@event4u/agent-config 15.0.0 → 16.0.0
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/.augment-plugin/marketplace.json +3 -3
- package/.augment-plugin/plugin.json +1 -1
- package/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +142 -348
- package/dist/agent-src/commands/roadmap/create.md +3 -2
- package/dist/agent-src/contexts/communication/rules-auto/user-interaction-mechanics.md +50 -0
- package/dist/agent-src/rules/user-interaction.md +31 -30
- package/dist/agent-src/skills/error-handling-patterns/SKILL.md +9 -0
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/cli-delegate/{chunk-HZ52BRGG.js → chunk-H32DGUJH.js} +14 -89
- package/dist/cli-delegate/chunk-NUHLI2RX.js +80 -0
- package/dist/cli-delegate/{chunk-TYSY33MD.js → chunk-QJWAUMJW.js} +12 -2
- package/dist/cli-delegate/{chunk-2KKXJW25.js → chunk-S3VFXMTM.js} +1 -1
- package/dist/cli-delegate/cmd_conformance.js +831 -272
- package/dist/cli-delegate/cmd_explain.js +4 -2
- package/dist/cli-delegate/cmd_handoff.js +2 -2
- package/dist/cli-delegate/cmd_packs_active.js +2 -1
- package/dist/cli-delegate/cmd_session_recycle.js +2 -2
- package/dist/cli-delegate/cmd_settings_set.js +13 -0
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +5 -5
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +1 -1
- package/dist/discovery/dormancy-report.md +1 -1
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +2 -2
- package/dist/discovery/trust-report.md +1 -1
- package/dist/discovery/workspaces.json +2 -2
- package/dist/hooks/dispatch.js +1274 -571
- package/dist/install/install.mjs +1 -0
- package/dist/mcp/registry-manifest.json +2 -2
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +1218 -632
- package/dist/scripts/_lib/installed_lock.js +1 -1
- package/dist/server/io/yamlIO.js +50 -0
- package/package.json +1 -1
- package/src/config/continuity-surface.json +7 -0
- package/src/config/gate-violation-baselines.json +3 -3
- package/src/config/host-injection-effect.json +1 -1
- package/src/config/preamble-payload-budget.json +12 -7
- package/src/config/preamble-payload-exceptions.json +28 -0
- package/src/scripts/_dispatch.bash +3 -1
- package/src/scripts/_lib/base_ref_payload.ts +315 -0
- package/src/scripts/_lib/dropped_decision.ts +142 -0
- package/src/scripts/_lib/installed_lock.ts +1 -1
- package/src/scripts/_lib/measured_payload_ceiling.ts +424 -0
- package/src/scripts/_lib/payload_catalogue_completeness.ts +211 -0
- package/src/scripts/_lib/release_findings_ingest.ts +324 -0
- package/src/scripts/_lib/release_tag_dispatch.ts +63 -0
- package/src/scripts/_lib/review_baseline.ts +254 -0
- package/src/scripts/_lib/review_skipped_record.ts +61 -1
- package/src/scripts/_lib/standing_bound_ratchet.ts +216 -103
- package/src/scripts/_lib/turn_end_refusals.ts +51 -4
- package/src/scripts/check_beta_review_markers.ts +35 -4
- package/src/scripts/check_finding_dispositions.ts +167 -16
- package/src/scripts/check_held_object_arrivals.ts +381 -0
- package/src/scripts/check_preamble_payload_budget.ts +399 -122
- package/src/scripts/check_release_published.ts +1 -1
- package/src/scripts/check_reply_consistency.ts +86 -17
- package/src/scripts/hook_manifest.json +1 -1
- package/src/scripts/hook_manifest.yaml +39 -3
- package/src/scripts/hooks/block_kernel_rule_writes.ts +12 -2
- package/src/scripts/hooks/concern_registry.ts +2 -0
- package/src/scripts/hooks/end_review_nudge_hook.ts +101 -21
- package/src/scripts/hooks/review_baseline_hook.ts +130 -0
- package/src/scripts/hooks/turn_end_gate_hook.ts +232 -14
- package/src/scripts/hooks_doctor.ts +4 -1
- package/src/scripts/install.ts +1 -1
- package/src/scripts/interruption_report.ts +8 -2
- package/src/scripts/janitor.ts +8 -1
- package/src/scripts/measure_turn_end_gate.ts +302 -5
- package/src/scripts/release.ts +52 -64
- package/src/scripts/release_drill.ts +193 -14
- package/src/scripts/release_env.ts +1 -1
- package/src/scripts/release_publication.ts +1 -1
- package/src/scripts/report_held_object_arrivals.ts +456 -0
- package/src/scripts/sync_agent_settings.ts +140 -18
- package/src/server/io/yamlIO.ts +48 -0
|
@@ -57,7 +57,7 @@ function _package_name(): string {
|
|
|
57
57
|
*
|
|
58
58
|
* This probe used to answer local-OR-remote, and that made the gate reply
|
|
59
59
|
* "tagged, therefore published" to the exact state it exists to detect. A tag
|
|
60
|
-
* created by `release.ts` step
|
|
60
|
+
* created by `release.ts` step 9 whose push then failed sits in the local
|
|
61
61
|
* repository while nothing has shipped: `publish-npm.yml` triggers on
|
|
62
62
|
* `push: tags:`, so a tag that never reached the remote published nothing.
|
|
63
63
|
* Measured 2026-08-20 on 14.6.0 — main carried `package.json` 14.6.0, the tag
|
|
@@ -82,6 +82,10 @@ function _strip_codespans(line: string): string {
|
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
/** Split on \n / \r\n / \r, dropping a single trailing empty element. */
|
|
85
|
+
export function splitAndMask(text: string): string[] {
|
|
86
|
+
return mask_fences(_splitlines(text));
|
|
87
|
+
}
|
|
88
|
+
|
|
85
89
|
function _splitlines(text: string): string[] {
|
|
86
90
|
if (text === '') return [];
|
|
87
91
|
const parts = text.split(/\r\n|\r|\n/);
|
|
@@ -143,6 +147,64 @@ export function find_option_blocks(text: string): OptionBlock[] {
|
|
|
143
147
|
return blocks;
|
|
144
148
|
}
|
|
145
149
|
|
|
150
|
+
/** A recommendation line found in a block's adjacency window. */
|
|
151
|
+
export interface RecommendationLine {
|
|
152
|
+
/** 1-based line of the recommendation. */
|
|
153
|
+
line: number;
|
|
154
|
+
/** The number it names. Not necessarily one of the block's options. */
|
|
155
|
+
num: number;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* The recommendation line(s) sitting in ONE block's adjacency window.
|
|
160
|
+
*
|
|
161
|
+
* Extracted from `check_reply` rather than copied, because it has a second
|
|
162
|
+
* caller: `turn_end_gate_hook`'s `pending-decision` detector needs the same
|
|
163
|
+
* question this answers — is this numbered block an ASK, or is it a narrative
|
|
164
|
+
* list? Iron Law 1 says the recommendation line IS the ask, so a block without
|
|
165
|
+
* one was never a decision put to the user.
|
|
166
|
+
*
|
|
167
|
+
* That distinction is not decoration. Replayed over this repository's own 592
|
|
168
|
+
* assistant turns, a detector keyed on the block alone fired 29 times and 8 of
|
|
169
|
+
* those blocks carried no recommendation line anywhere near them — plans,
|
|
170
|
+
* findings lists, ordinary enumerations. Requiring the line removes that whole
|
|
171
|
+
* class, and it removes it by applying the rule the gate already cites rather
|
|
172
|
+
* than by adding a heuristic beside it.
|
|
173
|
+
*
|
|
174
|
+
* Returns every recommendation in the window, not the first: `check_reply`
|
|
175
|
+
* treats two as its own finding, and a caller that only wanted existence can
|
|
176
|
+
* read `.length > 0`.
|
|
177
|
+
*/
|
|
178
|
+
export function recommendationsUnder(
|
|
179
|
+
text: string,
|
|
180
|
+
block: OptionBlock,
|
|
181
|
+
maskedLines?: readonly string[],
|
|
182
|
+
): RecommendationLine[] {
|
|
183
|
+
// `maskedLines` lets a caller with several blocks over one text mask once
|
|
184
|
+
// instead of once per block. It is the SAME array `check_reply` and
|
|
185
|
+
// `find_option_blocks` compute; passing anything else silently changes the
|
|
186
|
+
// line numbers this returns, which is why it is an optimisation parameter
|
|
187
|
+
// and not part of the contract.
|
|
188
|
+
const lines = maskedLines ?? mask_fences(_splitlines(text));
|
|
189
|
+
const recs: RecommendationLine[] = [];
|
|
190
|
+
let inspected = 0;
|
|
191
|
+
for (let idx = block.endLine; idx < lines.length && inspected < REC_ADJACENCY_WINDOW; idx++) {
|
|
192
|
+
const line = lines[idx]!;
|
|
193
|
+
if (line.trim() === '') {
|
|
194
|
+
continue; // blank lines do not consume the adjacency window
|
|
195
|
+
}
|
|
196
|
+
if (HEADING_RE.test(line) || OPTION_LINE_RE.test(line)) {
|
|
197
|
+
break; // a new heading or a new options block ends this block's window
|
|
198
|
+
}
|
|
199
|
+
inspected += 1;
|
|
200
|
+
const m = REC_LINE_RE.exec(line);
|
|
201
|
+
if (m) {
|
|
202
|
+
recs.push({ line: idx + 1, num: parseInt(m[1]!, 10) });
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return recs;
|
|
206
|
+
}
|
|
207
|
+
|
|
146
208
|
/**
|
|
147
209
|
* Core check — the exported function tests drive. Returns all findings for
|
|
148
210
|
* one reply draft; empty array = the draft is consistent.
|
|
@@ -166,22 +228,7 @@ export function check_reply(text: string): Finding[] {
|
|
|
166
228
|
// Per-block: exactly one adjacent recommendation line, number in range.
|
|
167
229
|
const blocks = find_option_blocks(text);
|
|
168
230
|
for (const block of blocks) {
|
|
169
|
-
const recs
|
|
170
|
-
let inspected = 0;
|
|
171
|
-
for (let idx = block.endLine; idx < lines.length && inspected < REC_ADJACENCY_WINDOW; idx++) {
|
|
172
|
-
const line = lines[idx]!;
|
|
173
|
-
if (line.trim() === '') {
|
|
174
|
-
continue; // blank lines do not consume the adjacency window
|
|
175
|
-
}
|
|
176
|
-
if (HEADING_RE.test(line) || OPTION_LINE_RE.test(line)) {
|
|
177
|
-
break; // a new heading or a new options block ends this block's window
|
|
178
|
-
}
|
|
179
|
-
inspected += 1;
|
|
180
|
-
const m = REC_LINE_RE.exec(line);
|
|
181
|
-
if (m) {
|
|
182
|
-
recs.push({ line: idx + 1, num: parseInt(m[1]!, 10) });
|
|
183
|
-
}
|
|
184
|
-
}
|
|
231
|
+
const recs = recommendationsUnder(text, block);
|
|
185
232
|
if (recs.length === 0) {
|
|
186
233
|
findings.push({
|
|
187
234
|
line: block.startLine,
|
|
@@ -421,7 +468,24 @@ export function main(argv: readonly string[] = process.argv.slice(2)): number {
|
|
|
421
468
|
return 2;
|
|
422
469
|
}
|
|
423
470
|
|
|
471
|
+
// Bundle-safety: never auto-run when inlined into an esbuild bundle, where
|
|
472
|
+
// every module shares the bundle's `import.meta.url`.
|
|
473
|
+
//
|
|
474
|
+
// This module is not a hook, and until `turn_end_gate_hook` began importing
|
|
475
|
+
// `find_option_blocks` / `recommendationsUnder` from it, it was never inside
|
|
476
|
+
// one. It is now pulled into `dist/hooks/dispatch.js`, where without this guard
|
|
477
|
+
// the `import.meta.url === argvUrl` comparison below is TRUE for every bundled
|
|
478
|
+
// module — so importing this file would call `process.exit(main())` and take the
|
|
479
|
+
// whole dispatch down at import time. The build banner's `.__direct__` argv
|
|
480
|
+
// rewrite also prevents it, and a comment in the gate says so; a guard the other
|
|
481
|
+
// bundled entries all carry is the load-bearing half, and depending on the
|
|
482
|
+
// banner alone is depending on something no test pins.
|
|
483
|
+
declare const __AGENT_CONFIG_BUNDLE__: boolean | undefined;
|
|
484
|
+
|
|
424
485
|
function _isCliEntry(): boolean {
|
|
486
|
+
if (typeof __AGENT_CONFIG_BUNDLE__ !== 'undefined' && __AGENT_CONFIG_BUNDLE__) {
|
|
487
|
+
return false;
|
|
488
|
+
}
|
|
425
489
|
if (process.argv[1] === undefined) {
|
|
426
490
|
return false;
|
|
427
491
|
}
|
|
@@ -442,7 +506,12 @@ function _isCliEntry(): boolean {
|
|
|
442
506
|
}
|
|
443
507
|
}
|
|
444
508
|
|
|
445
|
-
|
|
509
|
+
// The `|| process.argv[1] === _HERE` arm is the reason the bundle check lives in
|
|
510
|
+
// BOTH places: inside a bundle `_HERE` resolves to the bundle's own path and so
|
|
511
|
+
// does `process.argv[1]`, so this arm would be true and would route straight past
|
|
512
|
+
// a guard that only sat in `_isCliEntry`.
|
|
513
|
+
const _IN_BUNDLE = typeof __AGENT_CONFIG_BUNDLE__ !== 'undefined' && __AGENT_CONFIG_BUNDLE__;
|
|
514
|
+
if (!_IN_BUNDLE && (_isCliEntry() || process.argv[1] === _HERE)) {
|
|
446
515
|
process.exit(main());
|
|
447
516
|
}
|
|
448
517
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"fingerprint":"33e5cccd:90644","manifest":{"schema_version":1,"concerns":{"chat-history":{"script":"src/scripts/chat_history.ts","args":["hook-dispatch"],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["result"]},"hot-context":{"script":"src/scripts/hot_context_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"handoff-context":{"script":"src/scripts/handoff_context_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"roadmap-progress":{"script":"src/scripts/roadmap_progress_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"onboarding-gate":{"script":"src/scripts/onboarding_gate_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"context-hygiene":{"script":"src/scripts/context_hygiene_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"verify-before-complete":{"script":"src/scripts/before_complete_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input","result"]},"ship-diff-volume":{"script":"src/scripts/hooks/ship_diff_volume_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"minimal-safe-diff":{"script":"src/scripts/minimal_safe_diff_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"injection-scan":{"script":"src/scripts/injection_scan_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input","result"]},"block-no-verify":{"script":"src/scripts/hooks/block_no_verify.ts","args":[],"fail_closed":true,"severity":"blocking","needs_payload_bodies":["input"]},"block-kernel-rule-writes":{"script":"src/scripts/hooks/block_kernel_rule_writes.ts","args":[],"fail_closed":true,"severity":"blocking","needs_payload_bodies":["input"]},"one-question-per-ask":{"script":"src/scripts/hooks/one_question_per_ask_hook.ts","args":[],"fail_closed":false,"severity":"blocking","tools":["AskUserQuestion","AskQuestion","UserQuestion","ask_user_question","ask_question","user_question"],"needs_payload_bodies":["input"]},"block-speaking-inbox-dir":{"script":"src/scripts/hooks/block_speaking_inbox_dir.ts","args":[],"fail_closed":false,"severity":"blocking","needs_payload_bodies":["input"]},"block-config-weakening":{"script":"src/scripts/hooks/block_config_weakening.ts","args":[],"fail_closed":false,"severity":"blocking","needs_payload_bodies":["input"]},"rtk-wrap":{"script":"src/scripts/hooks/rtk_wrap_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"design-slop":{"script":"src/scripts/hooks/design_slop_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"design-pass":{"script":"src/scripts/hooks/design_pass_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"design-pass-stop":{"script":"src/scripts/hooks/design_pass_hook.ts","args":["--slot","stop"],"fail_closed":false,"severity":"advisory"},"ui-route-nudge":{"script":"src/scripts/hooks/ui_route_nudge_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"suggestion-capture":{"script":"src/scripts/hooks/suggestion_capture_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"chain-nudge":{"script":"src/scripts/hooks/chain_nudge_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"code-graph-context":{"script":"src/scripts/hooks/code_graph_context_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Grep","Glob","Read"],"needs_payload_bodies":["input"]},"memory-learn":{"script":"src/scripts/memory_learn_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"first-run-gate":{"script":"src/scripts/first_run_gate_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"profile-staleness":{"script":"src/scripts/profile_staleness_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"wrapper-freshness":{"script":"src/scripts/wrapper_freshness_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"surface-probe":{"script":"src/scripts/surface_probe_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"team-review-gate":{"script":"src/scripts/team_review_gate_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"pr-url-reminder":{"script":"src/scripts/pr_url_reminder_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input","result"]},"push-settle":{"script":"src/scripts/hooks/push_settle_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input","result"]},"language-mirror":{"script":"src/scripts/language_mirror_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"git-authorization":{"script":"src/scripts/git_authorization_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"evidence-independence":{"script":"src/scripts/hooks/evidence_independence.ts","args":[],"fail_closed":false,"severity":"blocking","needs_payload_bodies":["input"]},"session-canary":{"script":"src/scripts/session_canary_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"council-availability":{"script":"src/scripts/council_availability_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"telemetry-disclosure":{"script":"src/scripts/telemetry_disclosure_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"telemetry-flush":{"script":"src/scripts/hooks/telemetry_flush_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"self-repair":{"script":"src/scripts/self_repair_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"session-register":{"script":"src/scripts/session_register_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"orchestration-record":{"script":"src/scripts/hooks/orchestration_record_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Agent","Task"],"needs_payload_bodies":["input","result"]},"telemetry-usage":{"script":"src/scripts/hooks/telemetry_usage_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Skill"],"needs_payload_bodies":["input"]},"delegation-nudge":{"script":"src/scripts/hooks/delegation_nudge_hook.ts","args":[],"fail_closed":false,"severity":"advisory","nudge_rank":1},"skill-route":{"script":"src/scripts/hooks/skill_route_hook.ts","args":[],"fail_closed":false,"severity":"advisory","nudge_rank":2},"rule-inject":{"script":"src/scripts/hooks/rule_inject_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"end-review-nudge":{"script":"src/scripts/hooks/end_review_nudge_hook.ts","args":[],"fail_closed":false,"severity":"advisory","skip_on_refusal_retry":true},"turn-end-gate":{"script":"src/scripts/hooks/turn_end_gate_hook.ts","args":[],"fail_closed":false,"severity":"blocking"},"comment-discipline":{"script":"src/scripts/hooks/comment_discipline_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Write","Edit"],"needs_payload_bodies":["input"]},"edit-shape":{"script":"src/scripts/hooks/edit_shape_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Write"],"needs_payload_bodies":["input"]},"reread-guard":{"script":"src/scripts/hooks/reread_guard_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Read","Edit","Write"],"needs_payload_bodies":["input"]},"session-eol":{"script":"src/scripts/hooks/session_eol_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"run-continuation":{"script":"src/scripts/hooks/run_continuation_hook.ts","args":[],"fail_closed":false,"severity":"blocking"},"interruption-ledger":{"script":"src/scripts/hooks/interruption_ledger_hook.ts","args":[],"fail_closed":false,"severity":"advisory","skip_on_refusal_retry":true},"subagent-ledger":{"script":"src/scripts/hooks/subagent_ledger_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"tool-result-bytes":{"script":"src/scripts/hooks/tool_result_bytes_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"spawn-guard-shadow":{"script":"src/scripts/hooks/spawn_guard_shadow_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Agent","Task"]},"source-first-gate":{"script":"src/scripts/hooks/source_first_gate_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"journal-record":{"script":"src/scripts/hooks/journal_record_hook.ts","args":[],"fail_closed":false,"severity":"advisory"}},"roles":{"worker":{"drop":["delegation-nudge","skill-route","end-review-nudge","council-availability","team-review-gate","self-repair","session-eol","interruption-ledger"]}},"platforms":{"augment":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush"],"stop":["chat-history","verify-before-complete","self-repair","session-register","roadmap-progress","design-pass-stop"],"pre_tool_use":["block-no-verify","evidence-independence","block-kernel-rule-writes","block-config-weakening","block-speaking-inbox-dir","rtk-wrap","design-slop","ui-route-nudge","code-graph-context","chain-nudge","ship-diff-volume","reread-guard"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","push-settle","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","comment-discipline","design-pass"]},"claude":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register","journal-record"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush","journal-record"],"stop":["chat-history","verify-before-complete","team-review-gate","end-review-nudge","turn-end-gate","self-repair","session-register","session-eol","interruption-ledger","roadmap-progress","design-pass-stop","suggestion-capture","journal-record","run-continuation"],"user_prompt_submit":["chat-history","verify-before-complete","minimal-safe-diff","language-mirror","delegation-nudge","skill-route","git-authorization","session-canary","self-repair","session-register","rule-inject","suggestion-capture","journal-record"],"pre_tool_use":["block-no-verify","evidence-independence","block-kernel-rule-writes","block-config-weakening","block-speaking-inbox-dir","one-question-per-ask","rtk-wrap","design-slop","ui-route-nudge","code-graph-context","chain-nudge","ship-diff-volume","reread-guard","spawn-guard-shadow","source-first-gate"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","push-settle","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","comment-discipline","language-mirror","design-pass","journal-record"],"pre_compact":["language-mirror","rule-inject","journal-record"],"subagent_start":["subagent-ledger","journal-record"],"subagent_stop":["subagent-ledger","journal-record"]},"cowork":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush"],"stop":["chat-history","verify-before-complete","self-repair","session-register","roadmap-progress","design-pass-stop"],"user_prompt_submit":["chat-history","verify-before-complete","minimal-safe-diff","language-mirror","git-authorization","session-canary","self-repair","session-register"],"pre_tool_use":["block-no-verify","evidence-independence","block-kernel-rule-writes","block-config-weakening","block-speaking-inbox-dir","rtk-wrap","design-slop","ui-route-nudge","code-graph-context","chain-nudge","ship-diff-volume","reread-guard","spawn-guard-shadow","source-first-gate"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","push-settle","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","comment-discipline","design-pass"],"subagent_start":["subagent-ledger"],"subagent_stop":["subagent-ledger"]},"cursor":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush"],"stop":["chat-history","verify-before-complete","self-repair","session-register","roadmap-progress","design-pass-stop"],"user_prompt_submit":["chat-history","verify-before-complete","minimal-safe-diff","language-mirror","git-authorization","session-canary","self-repair","session-register"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","push-settle","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","comment-discipline","design-pass"]},"cline":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush"],"stop":["chat-history","verify-before-complete","self-repair","session-register","roadmap-progress","design-pass-stop"],"user_prompt_submit":["chat-history","verify-before-complete","minimal-safe-diff","language-mirror","git-authorization","session-canary","self-repair","session-register"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","push-settle","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","comment-discipline","design-pass"]},"windsurf":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","profile-staleness","wrapper-freshness","surface-probe","session-register"],"stop":["chat-history","verify-before-complete","self-repair","session-register","design-pass-stop"],"user_prompt_submit":["chat-history","verify-before-complete","language-mirror","git-authorization","session-canary","self-repair","session-register"]},"gemini":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush"],"stop":["chat-history","verify-before-complete","self-repair","session-register","roadmap-progress","design-pass-stop"],"user_prompt_submit":["chat-history","verify-before-complete","minimal-safe-diff","language-mirror","git-authorization","session-canary","self-repair","session-register"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","push-settle","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","comment-discipline","design-pass"]},"copilot":{"fallback_only":true}},"native_event_aliases":{"augment":{"SessionStart":"session_start","SessionEnd":"session_end","Stop":"stop","PostToolUse":"post_tool_use","PreToolUse":"pre_tool_use"},"claude":{"SessionStart":"session_start","SessionEnd":"session_end","Stop":"stop","UserPromptSubmit":"user_prompt_submit","PostToolUse":"post_tool_use","PreToolUse":"pre_tool_use","PreCompact":"pre_compact","SubagentStart":"subagent_start","SubagentStop":"subagent_stop"},"cowork":{"SessionStart":"session_start","SessionEnd":"session_end","Stop":"stop","UserPromptSubmit":"user_prompt_submit","PostToolUse":"post_tool_use","PreToolUse":"pre_tool_use","PreCompact":"pre_compact","SubagentStart":"subagent_start","SubagentStop":"subagent_stop"},"cursor":{"sessionStart":"session_start","sessionEnd":"session_end","stop":"stop","beforeSubmitPrompt":"user_prompt_submit","postToolUse":"post_tool_use","preToolUse":"pre_tool_use","preCompact":"pre_compact"},"cline":{"TaskStart":"session_start","TaskResume":"session_start","TaskComplete":"session_end","TaskCancel":"stop","UserPromptSubmit":"user_prompt_submit","PostToolUse":"post_tool_use","PreToolUse":"pre_tool_use","PreCompact":"pre_compact"},"windsurf":{"pre_user_prompt":"user_prompt_submit","post_cascade_response":"stop","post_setup_worktree":"session_start"},"gemini":{"SessionStart":"session_start","SessionEnd":"session_end","BeforeAgent":"user_prompt_submit","AfterAgent":"stop","BeforeTool":"pre_tool_use","AfterTool":"post_tool_use"}}}}
|
|
1
|
+
{"fingerprint":"98bf3b44:92876","manifest":{"schema_version":1,"concerns":{"chat-history":{"script":"src/scripts/chat_history.ts","args":["hook-dispatch"],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["result"]},"hot-context":{"script":"src/scripts/hot_context_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"handoff-context":{"script":"src/scripts/handoff_context_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"roadmap-progress":{"script":"src/scripts/roadmap_progress_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"onboarding-gate":{"script":"src/scripts/onboarding_gate_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"context-hygiene":{"script":"src/scripts/context_hygiene_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"verify-before-complete":{"script":"src/scripts/before_complete_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input","result"]},"ship-diff-volume":{"script":"src/scripts/hooks/ship_diff_volume_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"minimal-safe-diff":{"script":"src/scripts/minimal_safe_diff_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"injection-scan":{"script":"src/scripts/injection_scan_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input","result"]},"block-no-verify":{"script":"src/scripts/hooks/block_no_verify.ts","args":[],"fail_closed":true,"severity":"blocking","needs_payload_bodies":["input"]},"block-kernel-rule-writes":{"script":"src/scripts/hooks/block_kernel_rule_writes.ts","args":[],"fail_closed":true,"severity":"blocking","needs_payload_bodies":["input"]},"one-question-per-ask":{"script":"src/scripts/hooks/one_question_per_ask_hook.ts","args":[],"fail_closed":false,"severity":"blocking","tools":["AskUserQuestion","AskQuestion","UserQuestion","ask_user_question","ask_question","user_question"],"needs_payload_bodies":["input"]},"block-speaking-inbox-dir":{"script":"src/scripts/hooks/block_speaking_inbox_dir.ts","args":[],"fail_closed":false,"severity":"blocking","needs_payload_bodies":["input"]},"block-config-weakening":{"script":"src/scripts/hooks/block_config_weakening.ts","args":[],"fail_closed":false,"severity":"blocking","needs_payload_bodies":["input"]},"rtk-wrap":{"script":"src/scripts/hooks/rtk_wrap_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"design-slop":{"script":"src/scripts/hooks/design_slop_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"design-pass":{"script":"src/scripts/hooks/design_pass_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"design-pass-stop":{"script":"src/scripts/hooks/design_pass_hook.ts","args":["--slot","stop"],"fail_closed":false,"severity":"advisory"},"ui-route-nudge":{"script":"src/scripts/hooks/ui_route_nudge_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"suggestion-capture":{"script":"src/scripts/hooks/suggestion_capture_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"chain-nudge":{"script":"src/scripts/hooks/chain_nudge_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"code-graph-context":{"script":"src/scripts/hooks/code_graph_context_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Grep","Glob","Read"],"needs_payload_bodies":["input"]},"memory-learn":{"script":"src/scripts/memory_learn_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"first-run-gate":{"script":"src/scripts/first_run_gate_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"profile-staleness":{"script":"src/scripts/profile_staleness_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"wrapper-freshness":{"script":"src/scripts/wrapper_freshness_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"surface-probe":{"script":"src/scripts/surface_probe_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"team-review-gate":{"script":"src/scripts/team_review_gate_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"pr-url-reminder":{"script":"src/scripts/pr_url_reminder_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input","result"]},"push-settle":{"script":"src/scripts/hooks/push_settle_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input","result"]},"language-mirror":{"script":"src/scripts/language_mirror_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"git-authorization":{"script":"src/scripts/git_authorization_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"evidence-independence":{"script":"src/scripts/hooks/evidence_independence.ts","args":[],"fail_closed":false,"severity":"blocking","needs_payload_bodies":["input"]},"session-canary":{"script":"src/scripts/session_canary_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"council-availability":{"script":"src/scripts/council_availability_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"telemetry-disclosure":{"script":"src/scripts/telemetry_disclosure_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"telemetry-flush":{"script":"src/scripts/hooks/telemetry_flush_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"self-repair":{"script":"src/scripts/self_repair_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"session-register":{"script":"src/scripts/session_register_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"orchestration-record":{"script":"src/scripts/hooks/orchestration_record_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Agent","Task"],"needs_payload_bodies":["input","result"]},"telemetry-usage":{"script":"src/scripts/hooks/telemetry_usage_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Skill"],"needs_payload_bodies":["input"]},"delegation-nudge":{"script":"src/scripts/hooks/delegation_nudge_hook.ts","args":[],"fail_closed":false,"severity":"advisory","nudge_rank":1},"skill-route":{"script":"src/scripts/hooks/skill_route_hook.ts","args":[],"fail_closed":false,"severity":"advisory","nudge_rank":2},"rule-inject":{"script":"src/scripts/hooks/rule_inject_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"end-review-nudge":{"script":"src/scripts/hooks/end_review_nudge_hook.ts","args":[],"fail_closed":false,"severity":"advisory","skip_on_refusal_retry":true},"review-baseline":{"script":"src/scripts/hooks/review_baseline_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"turn-end-gate":{"script":"src/scripts/hooks/turn_end_gate_hook.ts","args":[],"fail_closed":false,"severity":"blocking"},"comment-discipline":{"script":"src/scripts/hooks/comment_discipline_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Write","Edit"],"needs_payload_bodies":["input"]},"edit-shape":{"script":"src/scripts/hooks/edit_shape_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Write"],"needs_payload_bodies":["input"]},"reread-guard":{"script":"src/scripts/hooks/reread_guard_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Read","Edit","Write"],"needs_payload_bodies":["input"]},"session-eol":{"script":"src/scripts/hooks/session_eol_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"run-continuation":{"script":"src/scripts/hooks/run_continuation_hook.ts","args":[],"fail_closed":false,"severity":"blocking"},"interruption-ledger":{"script":"src/scripts/hooks/interruption_ledger_hook.ts","args":[],"fail_closed":false,"severity":"advisory","skip_on_refusal_retry":true},"subagent-ledger":{"script":"src/scripts/hooks/subagent_ledger_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"tool-result-bytes":{"script":"src/scripts/hooks/tool_result_bytes_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"spawn-guard-shadow":{"script":"src/scripts/hooks/spawn_guard_shadow_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Agent","Task"]},"source-first-gate":{"script":"src/scripts/hooks/source_first_gate_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"journal-record":{"script":"src/scripts/hooks/journal_record_hook.ts","args":[],"fail_closed":false,"severity":"advisory"}},"roles":{"worker":{"drop":["delegation-nudge","skill-route","end-review-nudge","review-baseline","council-availability","team-review-gate","self-repair","session-eol","interruption-ledger"]}},"platforms":{"augment":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush"],"stop":["chat-history","verify-before-complete","self-repair","session-register","roadmap-progress","design-pass-stop"],"pre_tool_use":["block-no-verify","evidence-independence","block-kernel-rule-writes","block-config-weakening","block-speaking-inbox-dir","rtk-wrap","design-slop","ui-route-nudge","code-graph-context","chain-nudge","ship-diff-volume","reread-guard"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","push-settle","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","comment-discipline","design-pass"]},"claude":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register","review-baseline","journal-record"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush","journal-record"],"stop":["chat-history","verify-before-complete","team-review-gate","end-review-nudge","turn-end-gate","self-repair","session-register","session-eol","interruption-ledger","roadmap-progress","design-pass-stop","suggestion-capture","journal-record","run-continuation"],"user_prompt_submit":["chat-history","verify-before-complete","minimal-safe-diff","language-mirror","delegation-nudge","skill-route","git-authorization","session-canary","self-repair","session-register","rule-inject","suggestion-capture","journal-record"],"pre_tool_use":["block-no-verify","evidence-independence","block-kernel-rule-writes","block-config-weakening","block-speaking-inbox-dir","one-question-per-ask","rtk-wrap","design-slop","ui-route-nudge","code-graph-context","chain-nudge","ship-diff-volume","reread-guard","spawn-guard-shadow","source-first-gate"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","push-settle","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","comment-discipline","language-mirror","design-pass","journal-record"],"pre_compact":["language-mirror","rule-inject","journal-record"],"subagent_start":["subagent-ledger","journal-record"],"subagent_stop":["subagent-ledger","journal-record"]},"cowork":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush"],"stop":["chat-history","verify-before-complete","self-repair","session-register","roadmap-progress","design-pass-stop"],"user_prompt_submit":["chat-history","verify-before-complete","minimal-safe-diff","language-mirror","git-authorization","session-canary","self-repair","session-register"],"pre_tool_use":["block-no-verify","evidence-independence","block-kernel-rule-writes","block-config-weakening","block-speaking-inbox-dir","rtk-wrap","design-slop","ui-route-nudge","code-graph-context","chain-nudge","ship-diff-volume","reread-guard","spawn-guard-shadow","source-first-gate"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","push-settle","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","comment-discipline","design-pass"],"subagent_start":["subagent-ledger"],"subagent_stop":["subagent-ledger"]},"cursor":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush"],"stop":["chat-history","verify-before-complete","self-repair","session-register","roadmap-progress","design-pass-stop"],"user_prompt_submit":["chat-history","verify-before-complete","minimal-safe-diff","language-mirror","git-authorization","session-canary","self-repair","session-register"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","push-settle","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","comment-discipline","design-pass"]},"cline":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush"],"stop":["chat-history","verify-before-complete","self-repair","session-register","roadmap-progress","design-pass-stop"],"user_prompt_submit":["chat-history","verify-before-complete","minimal-safe-diff","language-mirror","git-authorization","session-canary","self-repair","session-register"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","push-settle","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","comment-discipline","design-pass"]},"windsurf":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","profile-staleness","wrapper-freshness","surface-probe","session-register"],"stop":["chat-history","verify-before-complete","self-repair","session-register","design-pass-stop"],"user_prompt_submit":["chat-history","verify-before-complete","language-mirror","git-authorization","session-canary","self-repair","session-register"]},"gemini":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush"],"stop":["chat-history","verify-before-complete","self-repair","session-register","roadmap-progress","design-pass-stop"],"user_prompt_submit":["chat-history","verify-before-complete","minimal-safe-diff","language-mirror","git-authorization","session-canary","self-repair","session-register"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","push-settle","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","comment-discipline","design-pass"]},"copilot":{"fallback_only":true}},"native_event_aliases":{"augment":{"SessionStart":"session_start","SessionEnd":"session_end","Stop":"stop","PostToolUse":"post_tool_use","PreToolUse":"pre_tool_use"},"claude":{"SessionStart":"session_start","SessionEnd":"session_end","Stop":"stop","UserPromptSubmit":"user_prompt_submit","PostToolUse":"post_tool_use","PreToolUse":"pre_tool_use","PreCompact":"pre_compact","SubagentStart":"subagent_start","SubagentStop":"subagent_stop"},"cowork":{"SessionStart":"session_start","SessionEnd":"session_end","Stop":"stop","UserPromptSubmit":"user_prompt_submit","PostToolUse":"post_tool_use","PreToolUse":"pre_tool_use","PreCompact":"pre_compact","SubagentStart":"subagent_start","SubagentStop":"subagent_stop"},"cursor":{"sessionStart":"session_start","sessionEnd":"session_end","stop":"stop","beforeSubmitPrompt":"user_prompt_submit","postToolUse":"post_tool_use","preToolUse":"pre_tool_use","preCompact":"pre_compact"},"cline":{"TaskStart":"session_start","TaskResume":"session_start","TaskComplete":"session_end","TaskCancel":"stop","UserPromptSubmit":"user_prompt_submit","PostToolUse":"post_tool_use","PreToolUse":"pre_tool_use","PreCompact":"pre_compact"},"windsurf":{"pre_user_prompt":"user_prompt_submit","post_cascade_response":"stop","post_setup_worktree":"session_start"},"gemini":{"SessionStart":"session_start","SessionEnd":"session_end","BeforeAgent":"user_prompt_submit","AfterAgent":"stop","BeforeTool":"pre_tool_use","AfterTool":"post_tool_use"}}}}
|
|
@@ -919,13 +919,49 @@ concerns:
|
|
|
919
919
|
# about it. The saving is the module load rather than a large read, which is
|
|
920
920
|
# the smaller of the two flags below it and is stated as such.
|
|
921
921
|
skip_on_refusal_retry: true
|
|
922
|
+
# road-to-a-question-that-survives-the-turn Phase 2 — the session baseline
|
|
923
|
+
# `end-review-nudge` subtracts. CAPTURE ONLY: one small JSON file per session
|
|
924
|
+
# under agents/runtime/state/review-baseline/ (gitignored), holding HEAD and
|
|
925
|
+
# the count of non-doc lines already dirty when the session began. It emits no
|
|
926
|
+
# context, never warns, and always exits 0.
|
|
927
|
+
#
|
|
928
|
+
# WHY. `end_review_nudge_hook`'s own header records that a dirty tree
|
|
929
|
+
# predating the session is charged to the session, and names the reason it was
|
|
930
|
+
# left: "no such baseline exists anywhere a `stop` concern can read it". That
|
|
931
|
+
# was true of a one-concern phase and stale by the time it mattered —
|
|
932
|
+
# session_start is bound on seven hosts here. Measured cost of leaving it: on
|
|
933
|
+
# an accumulator branch the nudge read 1,771 lines of two crashed sessions'
|
|
934
|
+
# uncommitted work and fired every turn.
|
|
935
|
+
#
|
|
936
|
+
# The counting function is IMPORTED from the nudge, so the baseline and the
|
|
937
|
+
# measurement cannot drift on what a non-doc mutated line is.
|
|
938
|
+
#
|
|
939
|
+
# BOUND ON `claude` ALONE, and narrowly on purpose. Seven hosts carry
|
|
940
|
+
# session_start, but `end-review-nudge` — the only reader — is bound on
|
|
941
|
+
# claude's stop slot and nowhere else (cowork refuses it explicitly). Binding
|
|
942
|
+
# the writer everywhere would spend ~91 ms of git per session start on six
|
|
943
|
+
# hosts to produce a file nothing opens. It is dropped for the `worker` role
|
|
944
|
+
# alongside its reader, for the same reason. Where the baseline is absent the
|
|
945
|
+
# nudge reads `absent` and degrades to exactly its previous behaviour,
|
|
946
|
+
# recorded in its telemetry row rather than inferred. fail_closed: false.
|
|
947
|
+
review-baseline:
|
|
948
|
+
script: src/scripts/hooks/review_baseline_hook.ts
|
|
949
|
+
args: []
|
|
950
|
+
fail_closed: false
|
|
951
|
+
severity: advisory
|
|
922
952
|
# road-to-conformance-round5 Phase 3 — the FIRST concern that can refuse a
|
|
923
953
|
# turn-END. Round 5 measured the reason: both blocking carriers reached zero
|
|
924
954
|
# violations, neither advisory carrier did, and 19 language violations
|
|
925
955
|
# survived a pin that had fired 26-35 seconds earlier. Refusal-capable
|
|
926
956
|
# intercepts enforce; context injection requests.
|
|
927
957
|
#
|
|
928
|
-
#
|
|
958
|
+
# FIVE detectors on one guard — promissory closing, language mismatch,
|
|
959
|
+
# unverified edit, unsettled completion claim, and a decision the turn asked
|
|
960
|
+
# and then dropped. This said "Two" and named the first pair, which was true
|
|
961
|
+
# of the concern on the day it was registered and of nothing since; the
|
|
962
|
+
# authority is `DetectorId` in the hook, and the demotion contract carries the
|
|
963
|
+
# per-detector bars. Original note, kept because its reason still holds:
|
|
964
|
+
# promissory closing (20 measured) and language
|
|
929
965
|
# mismatch (19 measured) — because building the unsafe part twice is how a
|
|
930
966
|
# second detector becomes a second outage.
|
|
931
967
|
#
|
|
@@ -1272,7 +1308,7 @@ roles:
|
|
|
1272
1308
|
# contacts, so a worker turn that ends in a question to its orchestrator
|
|
1273
1309
|
# would be recorded as a contact that never reached a human, inflating the
|
|
1274
1310
|
# exact baseline Phase 0 pre-registers.
|
|
1275
|
-
drop: [delegation-nudge, skill-route, end-review-nudge, council-availability, team-review-gate, self-repair, session-eol, interruption-ledger]
|
|
1311
|
+
drop: [delegation-nudge, skill-route, end-review-nudge, review-baseline, council-availability, team-review-gate, self-repair, session-eol, interruption-ledger]
|
|
1276
1312
|
|
|
1277
1313
|
platforms:
|
|
1278
1314
|
augment:
|
|
@@ -1283,7 +1319,7 @@ platforms:
|
|
|
1283
1319
|
post_tool_use: [chat-history, roadmap-progress, context-hygiene, verify-before-complete, minimal-safe-diff, injection-scan, pr-url-reminder, push-settle, orchestration-record, telemetry-usage, tool-result-bytes, edit-shape, comment-discipline, design-pass]
|
|
1284
1320
|
|
|
1285
1321
|
claude:
|
|
1286
|
-
session_start: [chat-history, hot-context, handoff-context, session-canary, council-availability, telemetry-disclosure, first-run-gate, onboarding-gate, verify-before-complete, minimal-safe-diff, profile-staleness, wrapper-freshness, surface-probe, session-register, journal-record]
|
|
1322
|
+
session_start: [chat-history, hot-context, handoff-context, session-canary, council-availability, telemetry-disclosure, first-run-gate, onboarding-gate, verify-before-complete, minimal-safe-diff, profile-staleness, wrapper-freshness, surface-probe, session-register, review-baseline, journal-record]
|
|
1287
1323
|
session_end: [chat-history, memory-learn, session-register, roadmap-progress, telemetry-flush, journal-record]
|
|
1288
1324
|
stop: [chat-history, verify-before-complete, team-review-gate, end-review-nudge, turn-end-gate, self-repair, session-register, session-eol, interruption-ledger, roadmap-progress, design-pass-stop, suggestion-capture, journal-record, run-continuation]
|
|
1289
1325
|
user_prompt_submit: [chat-history, verify-before-complete, minimal-safe-diff, language-mirror, delegation-nudge, skill-route, git-authorization, session-canary, self-repair, session-register, rule-inject, suggestion-capture, journal-record]
|
|
@@ -26,8 +26,18 @@
|
|
|
26
26
|
* exported pure functions, and reports via the same stderr-block-message +
|
|
27
27
|
* exit-code shape (0 allow · 1 block). `fail_closed: true` in the manifest —
|
|
28
28
|
* ADR-127 permits more than one blocking hook; this is the second (after
|
|
29
|
-
* block-no-verify).
|
|
30
|
-
*
|
|
29
|
+
* block-no-verify).
|
|
30
|
+
*
|
|
31
|
+
* Coverage is limited to edit-tool envelopes whose explicit target is a
|
|
32
|
+
* kernel rule, and to the literal shell-argument write shapes recognized by
|
|
33
|
+
* `check_envelope`. Indirect or dynamically resolved writes may not be
|
|
34
|
+
* detected; this guard is not a sandbox and does not provide complete write
|
|
35
|
+
* mediation. The human-owned exception registry named in the denial message
|
|
36
|
+
* is the only LEGITIMATE bypass; it is not the only reachable one.
|
|
37
|
+
*
|
|
38
|
+
* The boundary is stated as an abstraction, without an inventory of concrete
|
|
39
|
+
* evasion families. `check_envelope` is the authoritative inspection point
|
|
40
|
+
* for exact behaviour.
|
|
31
41
|
*
|
|
32
42
|
* Exit codes (docs/contracts/hook-architecture-v1.md):
|
|
33
43
|
* 0 — allow
|
|
@@ -69,6 +69,7 @@ import { main as delegationNudgeMain } from './delegation_nudge_hook.js';
|
|
|
69
69
|
import { main as skillRouteMain } from './skill_route_hook.js';
|
|
70
70
|
import { main as ruleInjectMain } from './rule_inject_hook.js';
|
|
71
71
|
import { main as endReviewNudgeMain } from './end_review_nudge_hook.js';
|
|
72
|
+
import { main as reviewBaselineMain } from './review_baseline_hook.js';
|
|
72
73
|
import { main as turnEndGateMain } from './turn_end_gate_hook.js';
|
|
73
74
|
import { main as editShapeMain } from './edit_shape_hook.js';
|
|
74
75
|
import { main as commentDisciplineMain } from './comment_discipline_hook.js';
|
|
@@ -132,6 +133,7 @@ export const CONCERN_REGISTRY: Readonly<Record<string, ConcernMain>> = {
|
|
|
132
133
|
'src/scripts/hooks/skill_route_hook.ts': skillRouteMain as ConcernMain,
|
|
133
134
|
'src/scripts/hooks/rule_inject_hook.ts': ruleInjectMain as ConcernMain,
|
|
134
135
|
'src/scripts/hooks/end_review_nudge_hook.ts': endReviewNudgeMain as ConcernMain,
|
|
136
|
+
'src/scripts/hooks/review_baseline_hook.ts': reviewBaselineMain as ConcernMain,
|
|
135
137
|
'src/scripts/hooks/turn_end_gate_hook.ts': turnEndGateMain as ConcernMain,
|
|
136
138
|
'src/scripts/hooks/edit_shape_hook.ts': editShapeMain as ConcernMain,
|
|
137
139
|
'src/scripts/hooks/comment_discipline_hook.ts': commentDisciplineMain as ConcernMain,
|
|
@@ -28,17 +28,26 @@
|
|
|
28
28
|
* (`git ls-files --others --exclude-standard`, each one READ from the
|
|
29
29
|
* filesystem rather than diffed in a subprocess — see "Untracked files" below;
|
|
30
30
|
* fixes a review finding, F6, that a brand-new file was previously invisible
|
|
31
|
-
* to this count entirely).
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
31
|
+
* to this count entirely).
|
|
32
|
+
*
|
|
33
|
+
* SINCE 2026-09-11 THIS READING IS BASELINE-CORRECTED ON `claude`, and this
|
|
34
|
+
* block used to say the opposite — that a session-start baseline was rejected
|
|
35
|
+
* "because no such baseline exists anywhere a `stop` concern can read it". That
|
|
36
|
+
* was true of a one-concern roadmap phase and stale by the time it mattered:
|
|
37
|
+
* `session_start` is bound on seven hosts, and `review-baseline` now records
|
|
38
|
+
* HEAD plus the already-dirty non-doc line count there. `_lib/review_baseline.ts`
|
|
39
|
+
* cites this paragraph as the defect it closes, so leaving the paragraph
|
|
40
|
+
* standing would have made the two files contradict each other.
|
|
41
|
+
*
|
|
42
|
+
* What the correction does and does not cover:
|
|
43
|
+
* - Uncommitted changes that PREDATE the session are SUBTRACTED where a
|
|
44
|
+
* baseline is readable and its HEAD and measure still match. Absent,
|
|
45
|
+
* unreadable, head-moved or mixed-measure → the unsubtracted count, with
|
|
46
|
+
* the reason carried in the `review_skipped` row.
|
|
47
|
+
* - The baseline is written once per session and never refreshed, so from a
|
|
48
|
+
* session's first commit onward `head-moved` holds and the pre-existing
|
|
49
|
+
* tree is charged again. Over-reporting is the safe direction; the limit is
|
|
50
|
+
* real and is stated in `review_baseline.ts` rather than implied away.
|
|
42
51
|
* - A session that DID commit mid-turn (one of `commit-policy`'s four
|
|
43
52
|
* exceptions) moves HEAD, so mutations already committed are invisible
|
|
44
53
|
* to this diff. Declared, not silently assumed away.
|
|
@@ -207,11 +216,20 @@
|
|
|
207
216
|
* exit-2 warn onto an unverified propagation path is exactly the
|
|
208
217
|
* speculative mapping `host_semantics.ts` exists to avoid.
|
|
209
218
|
*
|
|
210
|
-
* CONTRACT: never
|
|
211
|
-
*
|
|
212
|
-
*
|
|
213
|
-
*
|
|
214
|
-
*
|
|
219
|
+
* CONTRACT: never REFUSES a turn. The DISPATCHER-INTERNAL exit is 2 on a fire
|
|
220
|
+
* (never 1/BLOCK, never >=3), `fail_closed: false`; the HOST-FACING exit on
|
|
221
|
+
* `claude` is 0 either way, per the proof above. Doc-only diffs, a reviewer
|
|
222
|
+
* having run, or any unreadable/malformed input all resolve to silence
|
|
223
|
+
* (dispatcher-internal exit 0), not a crash.
|
|
224
|
+
*
|
|
225
|
+
* WHAT THE PROOF ABOVE DOES NOT COVER. Every term of it is an exit code, so it
|
|
226
|
+
* settles refusal and nothing else. Whether the `additionalContext` payload
|
|
227
|
+
* this concern emits at `stop` causes the host to run the agent AGAIN is a
|
|
228
|
+
* separate question, and this tree does not answer it — see
|
|
229
|
+
* `docs/contracts/hook-architecture-v1.md` under the exit-code table, which
|
|
230
|
+
* names the measurement that would. So do not read the proof above as
|
|
231
|
+
* establishing that this concern leaves the turn alone; it establishes only
|
|
232
|
+
* that the concern never refuses it.
|
|
215
233
|
*/
|
|
216
234
|
import { spawnSync } from 'node:child_process';
|
|
217
235
|
import * as crypto from 'node:crypto';
|
|
@@ -220,7 +238,18 @@ import * as os from 'node:os';
|
|
|
220
238
|
import * as path from 'node:path';
|
|
221
239
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
222
240
|
|
|
223
|
-
import {
|
|
241
|
+
import {
|
|
242
|
+
applyBaseline,
|
|
243
|
+
currentHeadSha,
|
|
244
|
+
readBaseline,
|
|
245
|
+
type BaselineFallback,
|
|
246
|
+
type BaselineOutcome,
|
|
247
|
+
} from '../_lib/review_baseline.js';
|
|
248
|
+
import {
|
|
249
|
+
buildReviewSkippedLine,
|
|
250
|
+
type BaselineApplication,
|
|
251
|
+
type MutationMeasure,
|
|
252
|
+
} from '../_lib/review_skipped_record.js';
|
|
224
253
|
import { unwrap, type JsonObject, type JsonValue } from './envelope.js';
|
|
225
254
|
import { readHookStdin } from './hook_stdin.js';
|
|
226
255
|
import { atomic_write_json, is_replay_mode } from './state_io.js';
|
|
@@ -606,6 +635,7 @@ export function appendReviewSkippedTelemetry(
|
|
|
606
635
|
workspaceRoot: string,
|
|
607
636
|
diffLines: number,
|
|
608
637
|
mutationMeasure: MutationMeasure,
|
|
638
|
+
baseline?: BaselineApplication,
|
|
609
639
|
): void {
|
|
610
640
|
if (is_replay_mode()) return;
|
|
611
641
|
const ts = new Date().toISOString();
|
|
@@ -614,6 +644,7 @@ export function appendReviewSkippedTelemetry(
|
|
|
614
644
|
mutation_measure: mutationMeasure,
|
|
615
645
|
ts,
|
|
616
646
|
id: crypto.randomUUID(),
|
|
647
|
+
baseline,
|
|
617
648
|
});
|
|
618
649
|
if (errors.length || line === null) return; // refused input — never write a broken line
|
|
619
650
|
try {
|
|
@@ -694,6 +725,23 @@ function _read_stdin(): string {
|
|
|
694
725
|
return readHookStdin();
|
|
695
726
|
}
|
|
696
727
|
|
|
728
|
+
/**
|
|
729
|
+
* The one place the two spellings meet.
|
|
730
|
+
*
|
|
731
|
+
* `BaselineFallback` is kebab-cased because it is a TypeScript union read only
|
|
732
|
+
* in this process; `BaselineApplication` is snake_cased because it is written
|
|
733
|
+
* into an audit line and every other enum in that stream is. A hand-written
|
|
734
|
+
* ternary translated them until a review pointed out that `head-moved` and
|
|
735
|
+
* `head_moved` differ by one character in a conditional nobody would re-read —
|
|
736
|
+
* an exhaustive record makes a new fallback a compile error instead.
|
|
737
|
+
*/
|
|
738
|
+
const FALLBACK_TO_TELEMETRY: Readonly<Record<BaselineFallback, BaselineApplication>> = {
|
|
739
|
+
absent: 'absent',
|
|
740
|
+
unreadable: 'unreadable',
|
|
741
|
+
'head-moved': 'head_moved',
|
|
742
|
+
'mixed-measure': 'mixed_measure',
|
|
743
|
+
};
|
|
744
|
+
|
|
697
745
|
export function main(): number {
|
|
698
746
|
const [envelope, payload] = unwrap(_read_stdin(), 'claude');
|
|
699
747
|
|
|
@@ -705,15 +753,43 @@ export function main(): number {
|
|
|
705
753
|
const workspace_root =
|
|
706
754
|
String(envelope['workspace_root'] ?? '').trim() || process.cwd();
|
|
707
755
|
|
|
708
|
-
let
|
|
756
|
+
let measuredLines: number;
|
|
709
757
|
let mutationMeasure: MutationMeasure;
|
|
710
758
|
try {
|
|
711
759
|
const measured = totalNonDocMutatedLinesWithMeasure(workspace_root);
|
|
712
|
-
|
|
760
|
+
measuredLines = measured.lines;
|
|
713
761
|
mutationMeasure = measured.measure;
|
|
714
762
|
} catch {
|
|
715
763
|
return 0; // fail-open — never block the agent loop
|
|
716
764
|
}
|
|
765
|
+
|
|
766
|
+
// The session key is derived HERE rather than after the threshold test,
|
|
767
|
+
// because the threshold is now taken on the SUBTRACTED count and the
|
|
768
|
+
// baseline is keyed on the session. That is a real reordering: one extra
|
|
769
|
+
// `sha256` of a string and one `readFileSync` of a ~100-byte JSON file now
|
|
770
|
+
// run on every stop, including the majority that end below threshold. The
|
|
771
|
+
// alternative — testing the unsubtracted count first as a cheap
|
|
772
|
+
// pre-filter — is wrong in the one direction that matters: on an
|
|
773
|
+
// accumulator branch EVERY turn clears the unsubtracted threshold, so the
|
|
774
|
+
// pre-filter would pass exactly when the subtraction is needed and save
|
|
775
|
+
// nothing.
|
|
776
|
+
const sessionKey = deriveSessionKey(envelope, payload);
|
|
777
|
+
const baselineOutcome: BaselineOutcome = applyBaseline(
|
|
778
|
+
measuredLines,
|
|
779
|
+
readBaseline(workspace_root, sessionKey),
|
|
780
|
+
// A THUNK, not a value: on the `absent` and `unreadable` branches the
|
|
781
|
+
// result is discarded, and those two are the steady state on every host
|
|
782
|
+
// without this nudge and on every session before its first baseline
|
|
783
|
+
// write. Passing the value eagerly spent an 11-14 ms `git rev-parse` on
|
|
784
|
+
// each of those stops for nothing.
|
|
785
|
+
() => currentHeadSha(workspace_root),
|
|
786
|
+
mutationMeasure,
|
|
787
|
+
);
|
|
788
|
+
const diffLines = baselineOutcome.lines;
|
|
789
|
+
const baselineApplication: BaselineApplication = baselineOutcome.applied
|
|
790
|
+
? 'applied'
|
|
791
|
+
: FALLBACK_TO_TELEMETRY[baselineOutcome.fallback];
|
|
792
|
+
|
|
717
793
|
if (diffLines <= MUTATION_LINE_THRESHOLD) {
|
|
718
794
|
return 0; // below threshold, or a doc-only diff — nothing to nudge
|
|
719
795
|
}
|
|
@@ -723,7 +799,6 @@ export function main(): number {
|
|
|
723
799
|
// JSON parse below. A session that already fired stops here, at a
|
|
724
800
|
// single `fs.existsSync` call, without re-reading a (potentially
|
|
725
801
|
// large) transcript file it already knows the answer for.
|
|
726
|
-
const sessionKey = deriveSessionKey(envelope, payload);
|
|
727
802
|
if (hasFiredThisSession(workspace_root, sessionKey)) {
|
|
728
803
|
return 0;
|
|
729
804
|
}
|
|
@@ -756,7 +831,12 @@ export function main(): number {
|
|
|
756
831
|
markFiredThisSession(workspace_root, sessionKey, new Date().toISOString());
|
|
757
832
|
|
|
758
833
|
try {
|
|
759
|
-
appendReviewSkippedTelemetry(
|
|
834
|
+
appendReviewSkippedTelemetry(
|
|
835
|
+
workspace_root,
|
|
836
|
+
diffLines,
|
|
837
|
+
mutationMeasure,
|
|
838
|
+
baselineApplication,
|
|
839
|
+
);
|
|
760
840
|
} catch {
|
|
761
841
|
// never let a telemetry failure block or fail the turn
|
|
762
842
|
}
|