instar 1.3.31 → 1.3.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +8 -37
- package/dist/commands/init.js.map +1 -1
- package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
- package/dist/core/PostUpdateMigrator.js +18 -0
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/dist/core/instarSettingsHooks.d.ts +95 -0
- package/dist/core/instarSettingsHooks.d.ts.map +1 -0
- package/dist/core/instarSettingsHooks.js +136 -0
- package/dist/core/instarSettingsHooks.js.map +1 -0
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +18 -18
- package/upgrades/1.3.32.md +28 -0
- package/upgrades/side-effects/existing-agent-pretooluse-hook-parity.md +39 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* instarSettingsHooks.ts — the single source of truth for the instar
|
|
3
|
+
* PreToolUse hook ENTRIES written into `.claude/settings.json`.
|
|
4
|
+
*
|
|
5
|
+
* Why this module exists (the dark-guardrail migration gap, 2026-05-27):
|
|
6
|
+
* `init.ts` wired a full set of PreToolUse Bash hooks for NEW agents, but the
|
|
7
|
+
* existing-agent path (`PostUpdateMigrator.migrateSettings`) only ever ensured
|
|
8
|
+
* two of them (slopcheck-guard + the MCP gate). So four guardrails —
|
|
9
|
+
* grounding-before-messaging, deferral-detector (the false-blocker pre-filter),
|
|
10
|
+
* external-communication-guard, post-action-reflection — shipped to disk on
|
|
11
|
+
* every existing agent but were never switched on in settings. They looked
|
|
12
|
+
* installed and did nothing. Root cause: the "what hooks does an agent get"
|
|
13
|
+
* list lived in two places that drifted.
|
|
14
|
+
*
|
|
15
|
+
* Both the new-agent path (init.ts) and the existing-agent path
|
|
16
|
+
* (PostUpdateMigrator.ensureInstarPreToolUseBashHooks) now import these
|
|
17
|
+
* constants, so the two can never drift again — add a hook here and both
|
|
18
|
+
* paths get it. An anti-drift unit test locks the canonical filename set.
|
|
19
|
+
*
|
|
20
|
+
* NOTE: the objects here are written verbatim into settings.json, so their
|
|
21
|
+
* shape (type/command/blocking/timeout) must stay byte-stable. Presence
|
|
22
|
+
* detection during migration derives the script filename from the command
|
|
23
|
+
* via `instarHookFilename()` — never add a `filename` field to these objects,
|
|
24
|
+
* or new agents' settings would gain a stray key.
|
|
25
|
+
*
|
|
26
|
+
* Scope: the Claude-Code `Bash` and `mcp__.*` PreToolUse matchers only.
|
|
27
|
+
* slopcheck-guard keeps its own dedicated ensure-block in migrateSettings
|
|
28
|
+
* (it is intentionally NOT in this set — it is added by that block for both
|
|
29
|
+
* new and existing agents). Codex hooks (installCodexHooks.ts, `.*` matcher)
|
|
30
|
+
* are a separate path and are not governed by this module.
|
|
31
|
+
*/
|
|
32
|
+
export interface InstarSettingsHookEntry {
|
|
33
|
+
type: 'command';
|
|
34
|
+
command: string;
|
|
35
|
+
blocking?: boolean;
|
|
36
|
+
timeout?: number;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* The canonical instar PreToolUse `Bash`-matcher hook entries, in canonical
|
|
40
|
+
* order. Mirrors (and is consumed by) init.ts's former `instarBashHooks`.
|
|
41
|
+
*/
|
|
42
|
+
export declare const INSTAR_BASH_PRETOOLUSE_HOOKS: ReadonlyArray<InstarSettingsHookEntry>;
|
|
43
|
+
/**
|
|
44
|
+
* The canonical instar PreToolUse `mcp__.*`-matcher hook entries.
|
|
45
|
+
* Mirrors (and is consumed by) init.ts's former `instarMcpHooks`.
|
|
46
|
+
*/
|
|
47
|
+
export declare const INSTAR_MCP_PRETOOLUSE_HOOKS: ReadonlyArray<InstarSettingsHookEntry>;
|
|
48
|
+
/**
|
|
49
|
+
* The canonical script filenames for the Bash set, in order. Used by the
|
|
50
|
+
* anti-drift test and as the documented contract. Derived once from the
|
|
51
|
+
* command strings so it can never silently disagree with the entries above.
|
|
52
|
+
*/
|
|
53
|
+
export declare const INSTAR_BASH_PRETOOLUSE_FILENAMES: ReadonlyArray<string>;
|
|
54
|
+
/**
|
|
55
|
+
* Extract the instar hook script filename from a settings hook command, e.g.
|
|
56
|
+
* `node ${CLAUDE_PROJECT_DIR}/.instar/hooks/instar/deferral-detector.js` ->
|
|
57
|
+
* `deferral-detector.js`. Returns null if the command does not reference an
|
|
58
|
+
* instar hook script. Used for idempotent presence detection during migration
|
|
59
|
+
* (substring/filename match is robust to ${CLAUDE_PROJECT_DIR} vs absolute
|
|
60
|
+
* path variations, unlike an exact-command compare).
|
|
61
|
+
*/
|
|
62
|
+
export declare function instarHookFilename(command: string): string | null;
|
|
63
|
+
/** Minimal structural shape of a settings PreToolUse matcher entry. */
|
|
64
|
+
export interface SettingsMatcherEntry {
|
|
65
|
+
matcher?: string;
|
|
66
|
+
hooks?: Array<{
|
|
67
|
+
command?: string;
|
|
68
|
+
type?: string;
|
|
69
|
+
blocking?: boolean;
|
|
70
|
+
timeout?: number;
|
|
71
|
+
}>;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Idempotently ensure every canonical instar Bash PreToolUse hook is present
|
|
75
|
+
* in an existing agent's settings. Mirrors init.ts (both consume
|
|
76
|
+
* INSTAR_BASH_PRETOOLUSE_HOOKS), closing the dark-guardrail migration gap.
|
|
77
|
+
*
|
|
78
|
+
* Behavior:
|
|
79
|
+
* - Finds the `Bash` matcher (creates one if absent).
|
|
80
|
+
* - For each canonical hook, adds it ONLY IF no existing hook command already
|
|
81
|
+
* references that script filename (filename/substring match — robust to
|
|
82
|
+
* ${CLAUDE_PROJECT_DIR} vs absolute path; prevents duplicates).
|
|
83
|
+
* - APPENDS missing hooks in canonical order; never reorders or removes
|
|
84
|
+
* existing entries (hand-curated settings are preserved).
|
|
85
|
+
* - Pushes fresh copies of the canonical entries (never the shared objects).
|
|
86
|
+
*
|
|
87
|
+
* Returns the list of filenames that were added (empty array == no-op, so the
|
|
88
|
+
* caller can decide whether to flag the settings file as patched). Safe to run
|
|
89
|
+
* repeatedly: once every hook is present, every subsequent call returns [].
|
|
90
|
+
*
|
|
91
|
+
* Does NOT touch slopcheck-guard (its own dedicated ensure-block owns it) or
|
|
92
|
+
* any non-Bash matcher.
|
|
93
|
+
*/
|
|
94
|
+
export declare function ensureInstarBashPreToolUseHooks(preToolUse: SettingsMatcherEntry[]): string[];
|
|
95
|
+
//# sourceMappingURL=instarSettingsHooks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instarSettingsHooks.d.ts","sourceRoot":"","sources":["../../src/core/instarSettingsHooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAID;;;GAGG;AACH,eAAO,MAAM,4BAA4B,EAAE,aAAa,CAAC,uBAAuB,CA0B/E,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,2BAA2B,EAAE,aAAa,CAAC,uBAAuB,CAO9E,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,gCAAgC,EAAE,aAAa,CAAC,MAAM,CACW,CAAC;AAE/E;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGjE;AAED,uEAAuE;AACvE,MAAM,WAAW,oBAAoB;IACnC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,KAAK,CAAC;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC1F;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,+BAA+B,CAAC,UAAU,EAAE,oBAAoB,EAAE,GAAG,MAAM,EAAE,CAmB5F"}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* instarSettingsHooks.ts — the single source of truth for the instar
|
|
3
|
+
* PreToolUse hook ENTRIES written into `.claude/settings.json`.
|
|
4
|
+
*
|
|
5
|
+
* Why this module exists (the dark-guardrail migration gap, 2026-05-27):
|
|
6
|
+
* `init.ts` wired a full set of PreToolUse Bash hooks for NEW agents, but the
|
|
7
|
+
* existing-agent path (`PostUpdateMigrator.migrateSettings`) only ever ensured
|
|
8
|
+
* two of them (slopcheck-guard + the MCP gate). So four guardrails —
|
|
9
|
+
* grounding-before-messaging, deferral-detector (the false-blocker pre-filter),
|
|
10
|
+
* external-communication-guard, post-action-reflection — shipped to disk on
|
|
11
|
+
* every existing agent but were never switched on in settings. They looked
|
|
12
|
+
* installed and did nothing. Root cause: the "what hooks does an agent get"
|
|
13
|
+
* list lived in two places that drifted.
|
|
14
|
+
*
|
|
15
|
+
* Both the new-agent path (init.ts) and the existing-agent path
|
|
16
|
+
* (PostUpdateMigrator.ensureInstarPreToolUseBashHooks) now import these
|
|
17
|
+
* constants, so the two can never drift again — add a hook here and both
|
|
18
|
+
* paths get it. An anti-drift unit test locks the canonical filename set.
|
|
19
|
+
*
|
|
20
|
+
* NOTE: the objects here are written verbatim into settings.json, so their
|
|
21
|
+
* shape (type/command/blocking/timeout) must stay byte-stable. Presence
|
|
22
|
+
* detection during migration derives the script filename from the command
|
|
23
|
+
* via `instarHookFilename()` — never add a `filename` field to these objects,
|
|
24
|
+
* or new agents' settings would gain a stray key.
|
|
25
|
+
*
|
|
26
|
+
* Scope: the Claude-Code `Bash` and `mcp__.*` PreToolUse matchers only.
|
|
27
|
+
* slopcheck-guard keeps its own dedicated ensure-block in migrateSettings
|
|
28
|
+
* (it is intentionally NOT in this set — it is added by that block for both
|
|
29
|
+
* new and existing agents). Codex hooks (installCodexHooks.ts, `.*` matcher)
|
|
30
|
+
* are a separate path and are not governed by this module.
|
|
31
|
+
*/
|
|
32
|
+
const PD = '${CLAUDE_PROJECT_DIR}';
|
|
33
|
+
/**
|
|
34
|
+
* The canonical instar PreToolUse `Bash`-matcher hook entries, in canonical
|
|
35
|
+
* order. Mirrors (and is consumed by) init.ts's former `instarBashHooks`.
|
|
36
|
+
*/
|
|
37
|
+
export const INSTAR_BASH_PRETOOLUSE_HOOKS = [
|
|
38
|
+
{
|
|
39
|
+
type: 'command',
|
|
40
|
+
command: `bash ${PD}/.instar/hooks/instar/dangerous-command-guard.sh "$TOOL_INPUT"`,
|
|
41
|
+
blocking: true,
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
type: 'command',
|
|
45
|
+
command: `bash ${PD}/.instar/hooks/instar/grounding-before-messaging.sh "$TOOL_INPUT"`,
|
|
46
|
+
blocking: false,
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
type: 'command',
|
|
50
|
+
command: `node ${PD}/.instar/hooks/instar/deferral-detector.js`,
|
|
51
|
+
timeout: 5000,
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
type: 'command',
|
|
55
|
+
command: `node ${PD}/.instar/hooks/instar/external-communication-guard.js`,
|
|
56
|
+
timeout: 5000,
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
type: 'command',
|
|
60
|
+
command: `node ${PD}/.instar/hooks/instar/post-action-reflection.js`,
|
|
61
|
+
timeout: 5000,
|
|
62
|
+
},
|
|
63
|
+
];
|
|
64
|
+
/**
|
|
65
|
+
* The canonical instar PreToolUse `mcp__.*`-matcher hook entries.
|
|
66
|
+
* Mirrors (and is consumed by) init.ts's former `instarMcpHooks`.
|
|
67
|
+
*/
|
|
68
|
+
export const INSTAR_MCP_PRETOOLUSE_HOOKS = [
|
|
69
|
+
{
|
|
70
|
+
type: 'command',
|
|
71
|
+
command: `node ${PD}/.instar/hooks/instar/external-operation-gate.js`,
|
|
72
|
+
blocking: true,
|
|
73
|
+
timeout: 5000,
|
|
74
|
+
},
|
|
75
|
+
];
|
|
76
|
+
/**
|
|
77
|
+
* The canonical script filenames for the Bash set, in order. Used by the
|
|
78
|
+
* anti-drift test and as the documented contract. Derived once from the
|
|
79
|
+
* command strings so it can never silently disagree with the entries above.
|
|
80
|
+
*/
|
|
81
|
+
export const INSTAR_BASH_PRETOOLUSE_FILENAMES = INSTAR_BASH_PRETOOLUSE_HOOKS.map((h) => instarHookFilename(h.command) ?? '');
|
|
82
|
+
/**
|
|
83
|
+
* Extract the instar hook script filename from a settings hook command, e.g.
|
|
84
|
+
* `node ${CLAUDE_PROJECT_DIR}/.instar/hooks/instar/deferral-detector.js` ->
|
|
85
|
+
* `deferral-detector.js`. Returns null if the command does not reference an
|
|
86
|
+
* instar hook script. Used for idempotent presence detection during migration
|
|
87
|
+
* (substring/filename match is robust to ${CLAUDE_PROJECT_DIR} vs absolute
|
|
88
|
+
* path variations, unlike an exact-command compare).
|
|
89
|
+
*/
|
|
90
|
+
export function instarHookFilename(command) {
|
|
91
|
+
const m = command.match(/\/\.instar\/hooks\/instar\/([\w.-]+\.(?:sh|js|mjs|cjs))/);
|
|
92
|
+
return m ? m[1] : null;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Idempotently ensure every canonical instar Bash PreToolUse hook is present
|
|
96
|
+
* in an existing agent's settings. Mirrors init.ts (both consume
|
|
97
|
+
* INSTAR_BASH_PRETOOLUSE_HOOKS), closing the dark-guardrail migration gap.
|
|
98
|
+
*
|
|
99
|
+
* Behavior:
|
|
100
|
+
* - Finds the `Bash` matcher (creates one if absent).
|
|
101
|
+
* - For each canonical hook, adds it ONLY IF no existing hook command already
|
|
102
|
+
* references that script filename (filename/substring match — robust to
|
|
103
|
+
* ${CLAUDE_PROJECT_DIR} vs absolute path; prevents duplicates).
|
|
104
|
+
* - APPENDS missing hooks in canonical order; never reorders or removes
|
|
105
|
+
* existing entries (hand-curated settings are preserved).
|
|
106
|
+
* - Pushes fresh copies of the canonical entries (never the shared objects).
|
|
107
|
+
*
|
|
108
|
+
* Returns the list of filenames that were added (empty array == no-op, so the
|
|
109
|
+
* caller can decide whether to flag the settings file as patched). Safe to run
|
|
110
|
+
* repeatedly: once every hook is present, every subsequent call returns [].
|
|
111
|
+
*
|
|
112
|
+
* Does NOT touch slopcheck-guard (its own dedicated ensure-block owns it) or
|
|
113
|
+
* any non-Bash matcher.
|
|
114
|
+
*/
|
|
115
|
+
export function ensureInstarBashPreToolUseHooks(preToolUse) {
|
|
116
|
+
const added = [];
|
|
117
|
+
let bashEntry = preToolUse.find((e) => e.matcher === 'Bash');
|
|
118
|
+
if (!bashEntry) {
|
|
119
|
+
bashEntry = { matcher: 'Bash', hooks: [] };
|
|
120
|
+
preToolUse.push(bashEntry);
|
|
121
|
+
}
|
|
122
|
+
if (!bashEntry.hooks)
|
|
123
|
+
bashEntry.hooks = [];
|
|
124
|
+
for (const canonical of INSTAR_BASH_PRETOOLUSE_HOOKS) {
|
|
125
|
+
const fname = instarHookFilename(canonical.command);
|
|
126
|
+
if (!fname)
|
|
127
|
+
continue;
|
|
128
|
+
const present = bashEntry.hooks.some((h) => typeof h.command === 'string' && h.command.includes(fname));
|
|
129
|
+
if (!present) {
|
|
130
|
+
bashEntry.hooks.push({ ...canonical });
|
|
131
|
+
added.push(fname);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return added;
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=instarSettingsHooks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instarSettingsHooks.js","sourceRoot":"","sources":["../../src/core/instarSettingsHooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AASH,MAAM,EAAE,GAAG,uBAAuB,CAAC;AAEnC;;;GAGG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAA2C;IAClF;QACE,IAAI,EAAE,SAAS;QACf,OAAO,EAAE,QAAQ,EAAE,gEAAgE;QACnF,QAAQ,EAAE,IAAI;KACf;IACD;QACE,IAAI,EAAE,SAAS;QACf,OAAO,EAAE,QAAQ,EAAE,mEAAmE;QACtF,QAAQ,EAAE,KAAK;KAChB;IACD;QACE,IAAI,EAAE,SAAS;QACf,OAAO,EAAE,QAAQ,EAAE,4CAA4C;QAC/D,OAAO,EAAE,IAAI;KACd;IACD;QACE,IAAI,EAAE,SAAS;QACf,OAAO,EAAE,QAAQ,EAAE,uDAAuD;QAC1E,OAAO,EAAE,IAAI;KACd;IACD;QACE,IAAI,EAAE,SAAS;QACf,OAAO,EAAE,QAAQ,EAAE,iDAAiD;QACpE,OAAO,EAAE,IAAI;KACd;CACF,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAA2C;IACjF;QACE,IAAI,EAAE,SAAS;QACf,OAAO,EAAE,QAAQ,EAAE,kDAAkD;QACrE,QAAQ,EAAE,IAAI;QACd,OAAO,EAAE,IAAI;KACd;CACF,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,gCAAgC,GAC3C,4BAA4B,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;AAE/E;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAAe;IAChD,MAAM,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,yDAAyD,CAAC,CAAC;IACnF,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACzB,CAAC;AAQD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,+BAA+B,CAAC,UAAkC;IAChF,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,SAAS,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,MAAM,CAAC,CAAC;IAC7D,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,SAAS,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;QAC3C,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC7B,CAAC;IACD,IAAI,CAAC,SAAS,CAAC,KAAK;QAAE,SAAS,CAAC,KAAK,GAAG,EAAE,CAAC;IAE3C,KAAK,MAAM,SAAS,IAAI,4BAA4B,EAAE,CAAC;QACrD,MAAM,KAAK,GAAG,kBAAkB,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QACpD,IAAI,CAAC,KAAK;YAAE,SAAS;QACrB,MAAM,OAAO,GAAG,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,OAAO,KAAK,QAAQ,IAAI,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;QACxG,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,SAAS,EAAE,CAAC,CAAC;YACvC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACpB,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "./builtin-manifest.schema.json",
|
|
3
3
|
"schemaVersion": 1,
|
|
4
|
-
"generatedAt": "2026-05-27T22:
|
|
5
|
-
"instarVersion": "1.3.
|
|
4
|
+
"generatedAt": "2026-05-27T22:28:16.266Z",
|
|
5
|
+
"instarVersion": "1.3.32",
|
|
6
6
|
"entryCount": 192,
|
|
7
7
|
"entries": {
|
|
8
8
|
"hook:session-start": {
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"domain": "identity",
|
|
12
12
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
13
13
|
"installedPath": ".instar/hooks/instar/session-start.sh",
|
|
14
|
-
"contentHash": "
|
|
14
|
+
"contentHash": "7df6ffd4a8d6e5e8c98e888bed89fffec63347268d0a26819b8de60ab32cd347",
|
|
15
15
|
"since": "2025-01-01"
|
|
16
16
|
},
|
|
17
17
|
"hook:dangerous-command-guard": {
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"domain": "safety",
|
|
21
21
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
22
22
|
"installedPath": ".instar/hooks/instar/dangerous-command-guard.sh",
|
|
23
|
-
"contentHash": "
|
|
23
|
+
"contentHash": "7df6ffd4a8d6e5e8c98e888bed89fffec63347268d0a26819b8de60ab32cd347",
|
|
24
24
|
"since": "2025-01-01"
|
|
25
25
|
},
|
|
26
26
|
"hook:grounding-before-messaging": {
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"domain": "safety",
|
|
30
30
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
31
31
|
"installedPath": ".instar/hooks/instar/grounding-before-messaging.sh",
|
|
32
|
-
"contentHash": "
|
|
32
|
+
"contentHash": "7df6ffd4a8d6e5e8c98e888bed89fffec63347268d0a26819b8de60ab32cd347",
|
|
33
33
|
"since": "2025-01-01"
|
|
34
34
|
},
|
|
35
35
|
"hook:compaction-recovery": {
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"domain": "identity",
|
|
39
39
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
40
40
|
"installedPath": ".instar/hooks/instar/compaction-recovery.sh",
|
|
41
|
-
"contentHash": "
|
|
41
|
+
"contentHash": "7df6ffd4a8d6e5e8c98e888bed89fffec63347268d0a26819b8de60ab32cd347",
|
|
42
42
|
"since": "2025-01-01"
|
|
43
43
|
},
|
|
44
44
|
"hook:external-operation-gate": {
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"domain": "safety",
|
|
48
48
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
49
49
|
"installedPath": ".instar/hooks/instar/external-operation-gate.js",
|
|
50
|
-
"contentHash": "
|
|
50
|
+
"contentHash": "7df6ffd4a8d6e5e8c98e888bed89fffec63347268d0a26819b8de60ab32cd347",
|
|
51
51
|
"since": "2025-01-01"
|
|
52
52
|
},
|
|
53
53
|
"hook:deferral-detector": {
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"domain": "safety",
|
|
57
57
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
58
58
|
"installedPath": ".instar/hooks/instar/deferral-detector.js",
|
|
59
|
-
"contentHash": "
|
|
59
|
+
"contentHash": "7df6ffd4a8d6e5e8c98e888bed89fffec63347268d0a26819b8de60ab32cd347",
|
|
60
60
|
"since": "2025-01-01"
|
|
61
61
|
},
|
|
62
62
|
"hook:post-action-reflection": {
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
"domain": "evolution",
|
|
66
66
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
67
67
|
"installedPath": ".instar/hooks/instar/post-action-reflection.js",
|
|
68
|
-
"contentHash": "
|
|
68
|
+
"contentHash": "7df6ffd4a8d6e5e8c98e888bed89fffec63347268d0a26819b8de60ab32cd347",
|
|
69
69
|
"since": "2025-01-01"
|
|
70
70
|
},
|
|
71
71
|
"hook:external-communication-guard": {
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
"domain": "safety",
|
|
75
75
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
76
76
|
"installedPath": ".instar/hooks/instar/external-communication-guard.js",
|
|
77
|
-
"contentHash": "
|
|
77
|
+
"contentHash": "7df6ffd4a8d6e5e8c98e888bed89fffec63347268d0a26819b8de60ab32cd347",
|
|
78
78
|
"since": "2025-01-01"
|
|
79
79
|
},
|
|
80
80
|
"hook:scope-coherence-collector": {
|
|
@@ -83,7 +83,7 @@
|
|
|
83
83
|
"domain": "coherence",
|
|
84
84
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
85
85
|
"installedPath": ".instar/hooks/instar/scope-coherence-collector.js",
|
|
86
|
-
"contentHash": "
|
|
86
|
+
"contentHash": "7df6ffd4a8d6e5e8c98e888bed89fffec63347268d0a26819b8de60ab32cd347",
|
|
87
87
|
"since": "2025-01-01"
|
|
88
88
|
},
|
|
89
89
|
"hook:scope-coherence-checkpoint": {
|
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
"domain": "coherence",
|
|
93
93
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
94
94
|
"installedPath": ".instar/hooks/instar/scope-coherence-checkpoint.js",
|
|
95
|
-
"contentHash": "
|
|
95
|
+
"contentHash": "7df6ffd4a8d6e5e8c98e888bed89fffec63347268d0a26819b8de60ab32cd347",
|
|
96
96
|
"since": "2025-01-01"
|
|
97
97
|
},
|
|
98
98
|
"hook:free-text-guard": {
|
|
@@ -101,7 +101,7 @@
|
|
|
101
101
|
"domain": "safety",
|
|
102
102
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
103
103
|
"installedPath": ".instar/hooks/instar/free-text-guard.sh",
|
|
104
|
-
"contentHash": "
|
|
104
|
+
"contentHash": "7df6ffd4a8d6e5e8c98e888bed89fffec63347268d0a26819b8de60ab32cd347",
|
|
105
105
|
"since": "2025-01-01"
|
|
106
106
|
},
|
|
107
107
|
"hook:claim-intercept": {
|
|
@@ -110,7 +110,7 @@
|
|
|
110
110
|
"domain": "coherence",
|
|
111
111
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
112
112
|
"installedPath": ".instar/hooks/instar/claim-intercept.js",
|
|
113
|
-
"contentHash": "
|
|
113
|
+
"contentHash": "7df6ffd4a8d6e5e8c98e888bed89fffec63347268d0a26819b8de60ab32cd347",
|
|
114
114
|
"since": "2025-01-01"
|
|
115
115
|
},
|
|
116
116
|
"hook:claim-intercept-response": {
|
|
@@ -119,7 +119,7 @@
|
|
|
119
119
|
"domain": "coherence",
|
|
120
120
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
121
121
|
"installedPath": ".instar/hooks/instar/claim-intercept-response.js",
|
|
122
|
-
"contentHash": "
|
|
122
|
+
"contentHash": "7df6ffd4a8d6e5e8c98e888bed89fffec63347268d0a26819b8de60ab32cd347",
|
|
123
123
|
"since": "2025-01-01"
|
|
124
124
|
},
|
|
125
125
|
"hook:stop-gate-router": {
|
|
@@ -128,7 +128,7 @@
|
|
|
128
128
|
"domain": "safety",
|
|
129
129
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
130
130
|
"installedPath": ".instar/hooks/instar/stop-gate-router.js",
|
|
131
|
-
"contentHash": "
|
|
131
|
+
"contentHash": "7df6ffd4a8d6e5e8c98e888bed89fffec63347268d0a26819b8de60ab32cd347",
|
|
132
132
|
"since": "2025-01-01"
|
|
133
133
|
},
|
|
134
134
|
"hook:auto-approve-permissions": {
|
|
@@ -137,7 +137,7 @@
|
|
|
137
137
|
"domain": "safety",
|
|
138
138
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
139
139
|
"installedPath": ".instar/hooks/instar/auto-approve-permissions.js",
|
|
140
|
-
"contentHash": "
|
|
140
|
+
"contentHash": "7df6ffd4a8d6e5e8c98e888bed89fffec63347268d0a26819b8de60ab32cd347",
|
|
141
141
|
"since": "2025-01-01"
|
|
142
142
|
},
|
|
143
143
|
"job:health-check": {
|
|
@@ -1481,7 +1481,7 @@
|
|
|
1481
1481
|
"type": "subsystem",
|
|
1482
1482
|
"domain": "updates",
|
|
1483
1483
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
1484
|
-
"contentHash": "
|
|
1484
|
+
"contentHash": "7df6ffd4a8d6e5e8c98e888bed89fffec63347268d0a26819b8de60ab32cd347",
|
|
1485
1485
|
"since": "2025-01-01"
|
|
1486
1486
|
},
|
|
1487
1487
|
"subsystem:scheduler": {
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- bump: patch -->
|
|
4
|
+
|
|
5
|
+
## What Changed
|
|
6
|
+
|
|
7
|
+
Closes a fleet-wide "dark guardrail" migration gap. `instar init` wires a full set of PreToolUse `Bash` guardrail hooks for new agents, but the existing-agent update path (`PostUpdateMigrator.migrateSettings`) only ever switched on two of them. So four guardrails — `deferral-detector.js` (the false-blocker / anti-deferral pre-filter), `grounding-before-messaging.sh`, `external-communication-guard.js`, and `post-action-reflection.js` — were copied to disk on every existing agent but never wired into `.claude/settings.json`, leaving them installed-but-inert. Same failure class as the 2026-05-27 silent-stall incident.
|
|
8
|
+
|
|
9
|
+
This release introduces a single source of truth for the canonical instar PreToolUse hook set (`src/core/instarSettingsHooks.ts`), consumed by BOTH the new-agent path (`init.ts`) and the existing-agent path, so the two can never drift again. `migrateSettings` now idempotently ensures every canonical Bash guardrail is present (appends only the missing ones; never reorders or removes; leaves custom hooks alone).
|
|
10
|
+
|
|
11
|
+
## What to Tell Your User
|
|
12
|
+
|
|
13
|
+
- Four guardrail hooks that were quietly switched off on existing agents — including the "false blocker" catcher that stops the agent handing a doable task back to you — come on at this update. New agents already had them; no action needed.
|
|
14
|
+
|
|
15
|
+
## Summary of New Capabilities
|
|
16
|
+
|
|
17
|
+
| Capability | How to Use |
|
|
18
|
+
|-----------|-----------|
|
|
19
|
+
| Existing agents get the full instar PreToolUse guardrail set on update | Automatic on update; no action needed |
|
|
20
|
+
| Anti-drift: new-agent + existing-agent hook lists share one constant | Adding a hook to `INSTAR_BASH_PRETOOLUSE_HOOKS` wires both paths; a unit test locks the set |
|
|
21
|
+
|
|
22
|
+
## Evidence
|
|
23
|
+
|
|
24
|
+
- New module + tests: `src/core/instarSettingsHooks.ts`, `tests/unit/instar-settings-hooks.test.ts` (16), `tests/unit/PostUpdateMigrator-pretooluse-parity.test.ts` (3, real migrateSettings).
|
|
25
|
+
- Spec: `docs/specs/EXISTING-AGENT-PRETOOLUSE-HOOK-PARITY-SPEC.md` (approved)
|
|
26
|
+
- ELI16: `docs/specs/EXISTING-AGENT-PRETOOLUSE-HOOK-PARITY-SPEC.eli16.md`
|
|
27
|
+
- Side-effects review: `upgrades/side-effects/existing-agent-pretooluse-hook-parity.md`
|
|
28
|
+
- Context: Task 3 of the 2026-05-27 silent-stalls postmortem.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Side-Effects Review — Existing-Agent PreToolUse Hook Parity
|
|
2
|
+
|
|
3
|
+
**Spec:** docs/specs/EXISTING-AGENT-PRETOOLUSE-HOOK-PARITY-SPEC.md (approved: true, internal-adversarial review 2026-05-27)
|
|
4
|
+
|
|
5
|
+
Closes the dark-guardrail migration gap: `init.ts` wired a full instar Bash PreToolUse hook set for NEW agents, but `PostUpdateMigrator.migrateSettings` only ensured slopcheck-guard + the MCP gate for EXISTING agents — so `deferral-detector.js` (the false-blocker pre-filter; this is Task 3 of the silent-stalls postmortem), `grounding-before-messaging.sh`, `external-communication-guard.js`, and `post-action-reflection.js` shipped to disk on every existing agent but were never switched on in settings. Same failure class as the 2026-05-27 silent-stall incident (looks installed, does nothing).
|
|
6
|
+
|
|
7
|
+
## What changed
|
|
8
|
+
- `src/core/instarSettingsHooks.ts` — NEW. Single source of truth for the canonical instar `Bash` and `mcp__.*` PreToolUse hook ENTRIES (`INSTAR_BASH_PRETOOLUSE_HOOKS`, `INSTAR_MCP_PRETOOLUSE_HOOKS`), a `instarHookFilename()` helper, and the idempotent `ensureInstarBashPreToolUseHooks()`.
|
|
9
|
+
- `src/commands/init.ts` — refactored the inline `instarBashHooks` / `instarMcpHooks` literals to consume the shared constants (fresh copies via `.map(h => ({...h}))`). Behavior-preserving: byte-identical settings output for new agents (verified by the existing `hook-installation.test.ts`, all green).
|
|
10
|
+
- `src/core/PostUpdateMigrator.ts` — `migrateSettings` now calls `ensureInstarBashPreToolUseHooks(preToolUse)` before the slopcheck block; appends only missing canonical hooks, idempotently, reporting each as a `dark-guardrail wiring` upgrade.
|
|
11
|
+
- Tests: `tests/unit/instar-settings-hooks.test.ts` (16) + `tests/unit/PostUpdateMigrator-pretooluse-parity.test.ts` (3).
|
|
12
|
+
|
|
13
|
+
## Over-block / under-block
|
|
14
|
+
- UNDER: a custom hook with the same script filename would be treated as "present" and not re-added. Acceptable — that's the intent (don't duplicate). Custom hooks under `.claude/hooks/custom/` have different filenames, so they're never matched/displaced.
|
|
15
|
+
- OVER: none. The function only APPENDS missing canonical hooks; it never reorders or removes existing entries, and it touches only the `Bash` matcher. Slopcheck-guard and all non-Bash matchers are untouched.
|
|
16
|
+
|
|
17
|
+
## Signal vs authority
|
|
18
|
+
N/A for blocking — this wires guardrail hooks into settings. Within the false-blocker design, `deferral-detector` is the SIGNAL (non-blocking checklist injection); `MessagingToneGate` B17 is the AUTHORITY (already live). This change lights up the signal layer on existing agents; it adds no new blocking authority.
|
|
19
|
+
|
|
20
|
+
## Idempotency / migration parity
|
|
21
|
+
- IS a migration-parity fix. New-agent path (init.ts) and existing-agent path (migrateSettings) now consume the SAME constant — drift is impossible by construction; an anti-drift unit test locks the canonical filename set.
|
|
22
|
+
- `ensureInstarBashPreToolUseHooks` is idempotent (filename-substring presence check, robust to `${CLAUDE_PROJECT_DIR}` vs absolute path); re-runs are no-ops (verified).
|
|
23
|
+
- No config or CLAUDE.md change. No new hook scripts (all four already ship + are ESM-safe).
|
|
24
|
+
|
|
25
|
+
## Interactions
|
|
26
|
+
- Runs before the existing slopcheck ensure-block; since it creates the `Bash` matcher when absent, slopcheck's "no Bash matcher" branch becomes a no-op while its "add slopcheck" branch still fires. Both end states verified together in the parity test.
|
|
27
|
+
- Codex hooks (`installCodexHooks.ts`, `.*` matcher) are a separate path, intentionally not governed by this module.
|
|
28
|
+
|
|
29
|
+
## Rollback
|
|
30
|
+
Revert the migrator call + the init refactor + delete the shared module (3 files) and the 2 test files. Worst case: existing agents return to the dark-guardrail state.
|
|
31
|
+
|
|
32
|
+
## Tests
|
|
33
|
+
- `tests/unit/instar-settings-hooks.test.ts` (16) — anti-drift contract, filename extraction, add/idempotent/preserve/no-matcher/no-dup/fresh-copy, init-imports-the-constant.
|
|
34
|
+
- `tests/unit/PostUpdateMigrator-pretooluse-parity.test.ts` (3) — real `migrateSettings` against a stale agent home: wires the four, idempotent, reports each.
|
|
35
|
+
- Regression-safety: `hook-installation.test.ts`, `installCodexHooks.test.ts`, `codexHookContractCanary.test.ts`, `autonomous-skill-deployment.test.ts`, `capabilities-discoverability.test.ts` all green post-refactor.
|
|
36
|
+
|
|
37
|
+
## NOT in this commit (tracked)
|
|
38
|
+
- Notify-on-stop (Task 2 — separate PR/spec).
|
|
39
|
+
- Self-propagation harness (Task 4).
|