docs: verify Factory Droid hook contract

This commit is contained in:
ZacharyZhang-NY committed 2026-07-19 10:31:33 -04:00
1 parent 8da7dbb524
commit 9cbcba21f5
3 files changed
+75 -1

No files matched your search

+1
View File
@@ -28,6 +28,7 @@ This repository publishes the open-source server, console, integration catalog,
- Write Auggie hooks only to `~/.augment/settings.json`; keep system and workspace settings read-only. Generate `.cmd` wrappers on Windows and `.sh` wrappers on Unix because Auggie dispatches supported script paths, and express hook timeouts in milliseconds. - Write Auggie hooks only to `~/.augment/settings.json`; keep system and workspace settings read-only. Generate `.cmd` wrappers on Windows and `.sh` wrappers on Unix because Auggie dispatches supported script paths, and express hook timeouts in milliseconds.
- Validate Auggie matcher syntax during installation with Node.js `new RegExp`; keep status and uninstall independent from the JavaScript validator so recovery remains available offline. - Validate Auggie matcher syntax during installation with Node.js `new RegExp`; keep status and uninstall independent from the JavaScript validator so recovery remains available offline.
- Write Cline file hooks to `$CLINE_DIR/hooks` with `~/.cline/hooks` as the default; keep Documents and workspace hook roots read-only. Use supported event filenames, preserve official hook input byte-for-byte, use `process.execPath` in Node and Go wrappers, and resolve Python runtimes from absolute shebangs. Translate guard exit code `2` into JSON stdout with `cancel: true`. Treat hook errors, timeouts, and invalid control JSON as fail-open. - Write Cline file hooks to `$CLINE_DIR/hooks` with `~/.cline/hooks` as the default; keep Documents and workspace hook roots read-only. Use supported event filenames, preserve official hook input byte-for-byte, use `process.execPath` in Node and Go wrappers, and resolve Python runtimes from absolute shebangs. Translate guard exit code `2` into JSON stdout with `cancel: true`. Treat hook errors, timeouts, and invalid control JSON as fail-open.
- Preserve Factory Droid's scope-root `hooks.json` precedence, legacy nested hook source, and per-event `settings.json` fallback. Edit only effective user sources; keep project and organization sources read-only.
## Mirror Workflow ## Mirror Workflow
+29 -1
View File
@@ -169,7 +169,9 @@
"config_format": "json", "config_format": "json",
"config_paths": [ "config_paths": [
"~/.factory/hooks.json", "~/.factory/hooks.json",
".factory/hooks.json" "~/.factory/settings.json",
".factory/hooks.json",
".factory/settings.json"
], ],
"events": { "events": {
"before_tool": "PreToolUse", "before_tool": "PreToolUse",
@@ -186,7 +188,33 @@
}, },
"adapters": { "node": false, "python": false, "go": false }, "adapters": { "node": false, "python": false, "go": false },
"delivery_state": "planned", "delivery_state": "planned",
"source_url": "https://docs.factory.ai/reference/hooks-reference",
"contract_variants": [
{
"id": "nestedhooks",
"release_channel": "legacy",
"activation": "An existing nested hooks file remains active until Droid saves and archives it",
"config_format": "json",
"config_paths": [
"~/.factory/hooks/hooks.json",
".factory/hooks/hooks.json"
],
"events": {
"before_tool": "PreToolUse",
"after_tool": "PostToolUse"
},
"event_fields": {
"name": "tool_name",
"input": "tool_input",
"session": "session_id"
},
"blocking": {
"mechanism": "exit_code_2",
"failure_mode": "fail_open"
},
"source_url": "https://docs.factory.ai/reference/hooks-reference" "source_url": "https://docs.factory.ai/reference/hooks-reference"
}
]
}, },
{ {
"id": "gemini", "id": "gemini",
+45
View File
@@ -214,6 +214,51 @@ test('high-drift providers retain their verified hook contracts', async () => {
'~/.codex/hooks.json', '~/.codex/hooks.json',
'.codex/hooks.json', '.codex/hooks.json',
]); ]);
assert.deepEqual(providers.get('droid').config_paths, [
'~/.factory/hooks.json',
'~/.factory/settings.json',
'.factory/hooks.json',
'.factory/settings.json',
]);
assert.deepEqual(providers.get('droid').events, {
before_tool: 'PreToolUse',
after_tool: 'PostToolUse',
});
assert.deepEqual(providers.get('droid').event_fields, {
name: 'tool_name',
input: 'tool_input',
session: 'session_id',
});
assert.deepEqual(providers.get('droid').blocking, {
mechanism: 'exit_code_2',
failure_mode: 'fail_open',
});
assert.deepEqual(providers.get('droid').contract_variants, [
{
id: 'nestedhooks',
release_channel: 'legacy',
activation: 'An existing nested hooks file remains active until Droid saves and archives it',
config_format: 'json',
config_paths: [
'~/.factory/hooks/hooks.json',
'.factory/hooks/hooks.json',
],
events: {
before_tool: 'PreToolUse',
after_tool: 'PostToolUse',
},
event_fields: {
name: 'tool_name',
input: 'tool_input',
session: 'session_id',
},
blocking: {
mechanism: 'exit_code_2',
failure_mode: 'fail_open',
},
source_url: 'https://docs.factory.ai/reference/hooks-reference',
},
]);
assert.equal(providers.get('cline').integration_mode, 'command_hooks'); assert.equal(providers.get('cline').integration_mode, 'command_hooks');
assert.equal(providers.get('cline').config_format, 'script'); assert.equal(providers.get('cline').config_format, 'script');
assert.deepEqual(providers.get('cline').config_paths, [ assert.deepEqual(providers.get('cline').config_paths, [