@event4u/agent-config 14.13.0 → 14.14.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 +116 -387
- package/dist/agent-src/commands/analyze/inbox.md +36 -0
- package/dist/agent-src/rules/code-comment-discipline.md +6 -0
- package/dist/agent-src/scripts/archive_completed_roadmaps.ts +6 -6
- package/dist/agent-src/scripts/guarded_baseline.ts +22 -7
- package/dist/agent-src/scripts/stubs_due.ts +118 -2
- package/dist/agent-src/scripts/update_roadmap_progress.ts +8 -8
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/cli-delegate/cmd_conformance.js +38 -1
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +4 -4
- 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 +1438 -711
- package/dist/mcp/registry-manifest.json +2 -2
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +112 -17
- package/docs/guidelines/agent-infra/guarded-baseline.md +1 -1
- package/docs/guidelines/code-clarity.md +18 -0
- package/package.json +1 -1
- package/src/agent-src/scripts/archive_completed_roadmaps.ts +6 -6
- package/src/agent-src/scripts/guarded_baseline.ts +22 -7
- package/src/agent-src/scripts/stubs_due.ts +118 -2
- package/src/agent-src/scripts/update_roadmap_progress.ts +8 -8
- package/src/config/estate-count-budget.json +20 -1
- package/src/config/gate-coverage.yml +150 -0
- package/src/config/gate-violation-baselines.json +8 -3
- package/src/config/preamble-payload-budget.json +19 -11
- package/src/config/rule-stub-ceilings.json +14 -7
- package/src/scripts/_dispatch.bash +0 -4
- package/src/scripts/_lib/activation_ladder.ts +47 -3
- package/src/scripts/_lib/activation_receipt_producer.ts +341 -0
- package/src/scripts/_lib/adr_frontmatter.ts +26 -0
- package/src/scripts/_lib/candidate_pair_delta.ts +349 -0
- package/src/scripts/_lib/carrier_status.ts +118 -0
- package/src/scripts/_lib/cascade_stage_enumeration.ts +92 -0
- package/src/scripts/_lib/corpus_manifest.ts +726 -0
- package/src/scripts/_lib/delivery_arm_experiment.ts +18 -2
- package/src/scripts/_lib/estate_carrier_cases.ts +72 -0
- package/src/scripts/_lib/evaluation_cascade.ts +452 -0
- package/src/scripts/_lib/evolution_roi.ts +562 -0
- package/src/scripts/_lib/harness_evolution_guards.ts +10 -0
- package/src/scripts/_lib/lexical_shortlist.ts +215 -0
- package/src/scripts/_lib/llm_candidate_proposer.ts +461 -0
- package/src/scripts/_lib/llm_proposer_transport.ts +153 -0
- package/src/scripts/_lib/pathology_archive.ts +393 -0
- package/src/scripts/_lib/promotion_capability.ts +315 -0
- package/src/scripts/_lib/promotion_evidence.ts +414 -0
- package/src/scripts/_lib/promotion_review.ts +294 -0
- package/src/scripts/_lib/prompt_shape.ts +92 -0
- package/src/scripts/_lib/release_highlights.ts +70 -1
- package/src/scripts/_lib/release_material.ts +125 -2
- package/src/scripts/_lib/routing_corpus.ts +307 -0
- package/src/scripts/_lib/routing_index_input.ts +104 -0
- package/src/scripts/_lib/rule_injection.ts +22 -1
- package/src/scripts/_lib/semantic_noop.ts +167 -0
- package/src/scripts/activation_receipt.ts +258 -0
- package/src/scripts/ai_council/cross_exam.ts +128 -0
- package/src/scripts/ai_council/explain_route.ts +157 -0
- package/src/scripts/ai_council/information_gain.ts +293 -0
- package/src/scripts/ai_council/leakage_corpus.ts +385 -0
- package/src/scripts/ai_council/leakage_patterns.ts +453 -0
- package/src/scripts/ai_council/minority_retention.ts +171 -0
- package/src/scripts/ai_council/recouncil_savings.ts +299 -0
- package/src/scripts/ai_council/replay_route.ts +223 -0
- package/src/scripts/ai_council/reviewer_assignment.ts +279 -0
- package/src/scripts/ai_council/routing_training_row.ts +197 -0
- package/src/scripts/ai_council/synthesis_strategy.ts +159 -0
- package/src/scripts/check_adr_frontmatter.ts +4 -9
- package/src/scripts/check_estate_count.ts +205 -24
- package/src/scripts/check_release_highlights.ts +96 -13
- package/src/scripts/check_roadmap_trackable.ts +17 -2
- package/src/scripts/corpus_manifest.ts +235 -0
- package/src/scripts/evolution_lab.ts +181 -8
- package/src/scripts/hook_manifest.json +1 -1
- package/src/scripts/hook_manifest.yaml +28 -6
- package/src/scripts/hooks/comment_discipline_hook.ts +146 -0
- package/src/scripts/hooks/concern_registry.ts +2 -0
- package/src/scripts/hooks/turn_end_gate_hook.ts +9 -1
- package/src/scripts/language_mirror_hook.ts +14 -2
- package/src/scripts/lint_carrier_integrity.ts +820 -0
- package/src/scripts/lint_code_comments.ts +643 -0
- package/src/scripts/lint_plan_risk_register.ts +39 -19
- package/src/scripts/lint_promotion_paths.ts +779 -0
- package/src/scripts/llm_propose.ts +256 -0
- package/src/scripts/measure_delivery_sets.ts +361 -0
- package/src/scripts/measure_routing_signal.ts +307 -0
- package/src/scripts/model_rule_injection.ts +19 -3
- package/src/scripts/probe_council_retention.ts +495 -0
- package/src/scripts/release.ts +21 -37
- package/src/scripts/release_drill.ts +143 -0
- package/src/scripts/release_env.ts +35 -0
- package/src/scripts/release_publication.ts +84 -0
|
@@ -833,6 +833,28 @@ concerns:
|
|
|
833
833
|
args: []
|
|
834
834
|
fail_closed: false
|
|
835
835
|
severity: blocking
|
|
836
|
+
# Comment-discipline advisory — the write-time half of
|
|
837
|
+
# `lint_code_comments`. Scans the TEXT JUST WRITTEN (Write ->
|
|
838
|
+
# tool_input.content, Edit -> tool_input.new_string), never the file on
|
|
839
|
+
# disk, so it is forward-only by construction: a pre-existing comment the
|
|
840
|
+
# edit did not touch cannot fire it and there is no baseline to keep. Three
|
|
841
|
+
# classes: `de-comment` (a non-English comment line), `report-comment` (a
|
|
842
|
+
# comment shaped like an analysis report — markdown table, box rule, `§`
|
|
843
|
+
# head, revisit-if) and `provenance-comment` (a roadmap or reference path
|
|
844
|
+
# explaining where the code came from). Reports `{decision:"warn", reason,
|
|
845
|
+
# additional_context}` at exit 2, the same verified delivery as
|
|
846
|
+
# `delegation-nudge`; never blocks, because the classifier is a line
|
|
847
|
+
# heuristic and the deterministic refusal belongs in the gate where a human
|
|
848
|
+
# reads the whole file. NOT once-per-session, unlike edit-shape: the
|
|
849
|
+
# measured failure was 41 files each carrying the defect, and a nudge that
|
|
850
|
+
# speaks once while forty more land is that incident. fail_closed: false.
|
|
851
|
+
comment-discipline:
|
|
852
|
+
script: src/scripts/hooks/comment_discipline_hook.ts
|
|
853
|
+
args: []
|
|
854
|
+
fail_closed: false
|
|
855
|
+
severity: advisory
|
|
856
|
+
tools: [Write, Edit]
|
|
857
|
+
needs_payload_bodies: [input]
|
|
836
858
|
# road-to-token-economy-cache Phase 5.1/5.2 — edit-shape advisory. Fires
|
|
837
859
|
# when a Write replaced an existing, git-tracked file of >= 50 lines while
|
|
838
860
|
# the effective diff (`git diff HEAD --numstat` added+deleted vs current
|
|
@@ -1145,7 +1167,7 @@ platforms:
|
|
|
1145
1167
|
session_end: [chat-history, memory-learn, session-register, roadmap-progress, telemetry-flush]
|
|
1146
1168
|
stop: [chat-history, hot-context, verify-before-complete, self-repair, session-register, roadmap-progress, design-pass-stop]
|
|
1147
1169
|
pre_tool_use: [block-no-verify, block-unauthorized-git, evidence-independence, block-kernel-rule-writes, block-config-weakening, block-speaking-inbox-dir, rtk-wrap, design-slop, ui-route-nudge, code-graph-nudge, ship-diff-volume, reread-guard]
|
|
1148
|
-
post_tool_use: [chat-history, roadmap-progress, context-hygiene, verify-before-complete, minimal-safe-diff, injection-scan, pr-url-reminder, orchestration-record, telemetry-usage, tool-result-bytes, edit-shape, design-pass]
|
|
1170
|
+
post_tool_use: [chat-history, roadmap-progress, context-hygiene, verify-before-complete, minimal-safe-diff, injection-scan, pr-url-reminder, orchestration-record, telemetry-usage, tool-result-bytes, edit-shape, comment-discipline, design-pass]
|
|
1149
1171
|
|
|
1150
1172
|
claude:
|
|
1151
1173
|
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]
|
|
@@ -1153,7 +1175,7 @@ platforms:
|
|
|
1153
1175
|
stop: [chat-history, hot-context, 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]
|
|
1154
1176
|
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]
|
|
1155
1177
|
pre_tool_use: [block-no-verify, block-unauthorized-git, evidence-independence, block-kernel-rule-writes, block-config-weakening, block-speaking-inbox-dir, rtk-wrap, design-slop, ui-route-nudge, code-graph-nudge, ship-diff-volume, reread-guard, spawn-guard-shadow, source-first-gate, rule-inject]
|
|
1156
|
-
post_tool_use: [chat-history, roadmap-progress, context-hygiene, verify-before-complete, minimal-safe-diff, injection-scan, pr-url-reminder, orchestration-record, telemetry-usage, tool-result-bytes, edit-shape, language-mirror, design-pass, journal-record]
|
|
1178
|
+
post_tool_use: [chat-history, roadmap-progress, context-hygiene, verify-before-complete, minimal-safe-diff, injection-scan, pr-url-reminder, orchestration-record, telemetry-usage, tool-result-bytes, edit-shape, comment-discipline, language-mirror, design-pass, journal-record]
|
|
1157
1179
|
# `language-mirror` — round-5 § 6.1. `pre_compact` sets a pin-lost marker;
|
|
1158
1180
|
# the `post_tool_use` entry above re-emits the pin exactly once while that
|
|
1159
1181
|
# marker is set, then clears it. One extra injection per compaction EVENT —
|
|
@@ -1207,7 +1229,7 @@ platforms:
|
|
|
1207
1229
|
stop: [chat-history, hot-context, verify-before-complete, self-repair, session-register, roadmap-progress, design-pass-stop]
|
|
1208
1230
|
user_prompt_submit: [chat-history, verify-before-complete, minimal-safe-diff, language-mirror, git-authorization, session-canary, self-repair, session-register]
|
|
1209
1231
|
pre_tool_use: [block-no-verify, block-unauthorized-git, evidence-independence, block-kernel-rule-writes, block-config-weakening, block-speaking-inbox-dir, rtk-wrap, design-slop, ui-route-nudge, code-graph-nudge, ship-diff-volume, reread-guard, spawn-guard-shadow, source-first-gate]
|
|
1210
|
-
post_tool_use: [chat-history, roadmap-progress, context-hygiene, verify-before-complete, minimal-safe-diff, injection-scan, pr-url-reminder, orchestration-record, telemetry-usage, tool-result-bytes, edit-shape, design-pass]
|
|
1232
|
+
post_tool_use: [chat-history, roadmap-progress, context-hygiene, verify-before-complete, minimal-safe-diff, injection-scan, pr-url-reminder, orchestration-record, telemetry-usage, tool-result-bytes, edit-shape, comment-discipline, design-pass]
|
|
1211
1233
|
# subagent-ledger IS bound here, unlike the two nudges above, and the
|
|
1212
1234
|
# difference is the delivery channel rather than the platform: the nudges
|
|
1213
1235
|
# depend on stdout reaching the model, which this trampoline discards by
|
|
@@ -1230,7 +1252,7 @@ platforms:
|
|
|
1230
1252
|
session_end: [chat-history, memory-learn, session-register, roadmap-progress, telemetry-flush]
|
|
1231
1253
|
stop: [chat-history, hot-context, verify-before-complete, self-repair, session-register, roadmap-progress, design-pass-stop]
|
|
1232
1254
|
user_prompt_submit: [chat-history, verify-before-complete, minimal-safe-diff, language-mirror, git-authorization, session-canary, self-repair, session-register]
|
|
1233
|
-
post_tool_use: [chat-history, roadmap-progress, context-hygiene, verify-before-complete, minimal-safe-diff, injection-scan, pr-url-reminder, orchestration-record, telemetry-usage, tool-result-bytes, edit-shape, design-pass]
|
|
1255
|
+
post_tool_use: [chat-history, roadmap-progress, context-hygiene, verify-before-complete, minimal-safe-diff, injection-scan, pr-url-reminder, orchestration-record, telemetry-usage, tool-result-bytes, edit-shape, comment-discipline, design-pass]
|
|
1234
1256
|
|
|
1235
1257
|
# Phase 7.6 — Cline. Hooks live under `.clinerules/hooks/<HookName>`
|
|
1236
1258
|
# (project, no file extension, must be executable per Cline docs) or
|
|
@@ -1245,7 +1267,7 @@ platforms:
|
|
|
1245
1267
|
session_end: [chat-history, memory-learn, session-register, roadmap-progress, telemetry-flush]
|
|
1246
1268
|
stop: [chat-history, hot-context, verify-before-complete, self-repair, session-register, roadmap-progress, design-pass-stop]
|
|
1247
1269
|
user_prompt_submit: [chat-history, verify-before-complete, minimal-safe-diff, language-mirror, git-authorization, session-canary, self-repair, session-register]
|
|
1248
|
-
post_tool_use: [chat-history, roadmap-progress, context-hygiene, verify-before-complete, minimal-safe-diff, injection-scan, pr-url-reminder, orchestration-record, telemetry-usage, tool-result-bytes, edit-shape, design-pass]
|
|
1270
|
+
post_tool_use: [chat-history, roadmap-progress, context-hygiene, verify-before-complete, minimal-safe-diff, injection-scan, pr-url-reminder, orchestration-record, telemetry-usage, tool-result-bytes, edit-shape, comment-discipline, design-pass]
|
|
1249
1271
|
|
|
1250
1272
|
# Phase 7.7 — Windsurf (Cascade). Hooks live at `.windsurf/hooks.json`
|
|
1251
1273
|
# (project) or `~/.codeium/windsurf/hooks.json` (user). Cascade has
|
|
@@ -1281,7 +1303,7 @@ platforms:
|
|
|
1281
1303
|
session_end: [chat-history, memory-learn, session-register, roadmap-progress, telemetry-flush]
|
|
1282
1304
|
stop: [chat-history, hot-context, verify-before-complete, self-repair, session-register, roadmap-progress, design-pass-stop]
|
|
1283
1305
|
user_prompt_submit: [chat-history, verify-before-complete, minimal-safe-diff, language-mirror, git-authorization, session-canary, self-repair, session-register]
|
|
1284
|
-
post_tool_use: [chat-history, roadmap-progress, context-hygiene, verify-before-complete, minimal-safe-diff, injection-scan, pr-url-reminder, orchestration-record, telemetry-usage, tool-result-bytes, edit-shape, design-pass]
|
|
1306
|
+
post_tool_use: [chat-history, roadmap-progress, context-hygiene, verify-before-complete, minimal-safe-diff, injection-scan, pr-url-reminder, orchestration-record, telemetry-usage, tool-result-bytes, edit-shape, comment-discipline, design-pass]
|
|
1285
1307
|
|
|
1286
1308
|
# Phase 7.9 — Copilot has no hook surface. Concerns route through
|
|
1287
1309
|
# rule-only fallback; the dispatcher silently no-ops on --platform copilot.
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Comment-discipline advisory — `post_tool_use` concern.
|
|
4
|
+
*
|
|
5
|
+
* The write-time half of `lint_code_comments`. The gate answers "may this
|
|
6
|
+
* land"; this answers "was it written that way in the first place", which is
|
|
7
|
+
* the question the maintainer actually asked after a run produced 509 German
|
|
8
|
+
* comment lines across 41 of 45 changed source files without anything
|
|
9
|
+
* objecting once.
|
|
10
|
+
*
|
|
11
|
+
* `code-comment-discipline` is `type: auto` with PROMPT keywords (`comment`,
|
|
12
|
+
* `refactor`, `implement`, …). A run that writes forty-five files while the
|
|
13
|
+
* user says "build the todo module" matches none of them, so the rule never
|
|
14
|
+
* loads — the activation gap `fix-what-you-see` names for itself, in the one
|
|
15
|
+
* place where the agent is producing the artefact the rule governs. A
|
|
16
|
+
* post-write concern fires on the TOOL EVENT and therefore does not depend on
|
|
17
|
+
* what the prompt happened to say.
|
|
18
|
+
*
|
|
19
|
+
* `Write` carries the new content in `tool_input.content`; `Edit` carries the
|
|
20
|
+
* replacement in `tool_input.new_string`. Scanning that text rather than the
|
|
21
|
+
* file on disk makes the concern forward-only by construction: a pre-existing
|
|
22
|
+
* comment the edit did not touch cannot fire it, so there is no baseline to
|
|
23
|
+
* maintain and no legacy tree to clean before turning it on.
|
|
24
|
+
*
|
|
25
|
+
* Same shape as `edit_shape_hook.ts` and `delegation_nudge_hook.ts`:
|
|
26
|
+
* `host_semantics.emitFor`'s `severity === "warn"` branch returns exit 0 with
|
|
27
|
+
* the text in `hookSpecificOutput.additionalContext`, unconditionally, so the
|
|
28
|
+
* byte handed to the host is always 0. Advisory is the right severity here
|
|
29
|
+
* and not a hedge — the classifier is a line heuristic, and a heuristic that
|
|
30
|
+
* can refuse a write would turn one false positive into a blocked session.
|
|
31
|
+
* The deterministic refusal lives in the gate, where a human can read the
|
|
32
|
+
* whole file before answering.
|
|
33
|
+
*
|
|
34
|
+
* `edit-shape` fires once per session because its advice is a habit
|
|
35
|
+
* correction that lands the first time. This one is per-write on purpose: the
|
|
36
|
+
* measured failure is forty-one files each carrying the defect, and a nudge
|
|
37
|
+
* that speaks once and then watches forty more land is the shape that
|
|
38
|
+
* produced the incident. The cost is bounded by naming at most
|
|
39
|
+
* `MAX_REPORTED` findings and no more than one line per write.
|
|
40
|
+
*
|
|
41
|
+
* ROBUSTNESS: malformed payload → exit 0 silently. This concern never blocks.
|
|
42
|
+
*/
|
|
43
|
+
import * as fs from 'node:fs';
|
|
44
|
+
import * as path from 'node:path';
|
|
45
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
46
|
+
|
|
47
|
+
import { isScannable, scanText, type CommentFinding } from '../lint_code_comments.js';
|
|
48
|
+
import { unwrap, type JsonObject, type JsonValue } from './envelope.js';
|
|
49
|
+
import { readHookStdin } from './hook_stdin.js';
|
|
50
|
+
|
|
51
|
+
const EXIT_ALLOW = 0;
|
|
52
|
+
const EXIT_WARN = 2;
|
|
53
|
+
|
|
54
|
+
/** Findings named in the advisory line. The rest are counted, never listed. */
|
|
55
|
+
export const MAX_REPORTED = 3;
|
|
56
|
+
|
|
57
|
+
function str(v: JsonValue | undefined): string {
|
|
58
|
+
return typeof v === 'string' ? v : '';
|
|
59
|
+
}
|
|
60
|
+
function isObject(v: unknown): v is JsonObject {
|
|
61
|
+
return typeof v === 'object' && v !== null && !Array.isArray(v);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** The written text, per tool. Empty string when the payload carries none. */
|
|
65
|
+
export function writtenText(toolName: string, toolInput: JsonObject): string {
|
|
66
|
+
if (toolName === 'Write') return str(toolInput['content'] as JsonValue | undefined);
|
|
67
|
+
if (toolName === 'Edit') {
|
|
68
|
+
return str(toolInput['new_string'] as JsonValue | undefined)
|
|
69
|
+
|| str(toolInput['newString'] as JsonValue | undefined);
|
|
70
|
+
}
|
|
71
|
+
return '';
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** One advisory line, naming what fired and where. */
|
|
75
|
+
export function buildAdvisoryLine(file: string, findings: readonly CommentFinding[]): string {
|
|
76
|
+
const counts = new Map<string, number>();
|
|
77
|
+
for (const f of findings) counts.set(f.cls, (counts.get(f.cls) ?? 0) + 1);
|
|
78
|
+
const summary = [...counts].map(([c, n]) => `${c} ×${n}`).join(' · ');
|
|
79
|
+
const named = findings.slice(0, MAX_REPORTED)
|
|
80
|
+
.map((f) => `line ${f.line} (${f.signal})`)
|
|
81
|
+
.join(', ');
|
|
82
|
+
const more = findings.length > MAX_REPORTED ? `, +${findings.length - MAX_REPORTED} more` : '';
|
|
83
|
+
return (
|
|
84
|
+
`comment-discipline: the text just written to ${file} carries ${summary} — ${named}${more}. `
|
|
85
|
+
+ 'A comment states a WHY or a constraint the code cannot show, in English; evidence for a '
|
|
86
|
+
+ 'roadmap step belongs in that roadmap, not in a second copy in the source. Rewrite or '
|
|
87
|
+
+ 'delete those lines now, before the next write — `lint_code_comments` refuses them at the gate.'
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function main(): number {
|
|
92
|
+
try {
|
|
93
|
+
const [envelope, payload] = unwrap(readHookStdin(), 'claude');
|
|
94
|
+
|
|
95
|
+
const event = str(envelope['event'] as JsonValue | undefined);
|
|
96
|
+
if (event !== '' && event !== 'post_tool_use') return EXIT_ALLOW;
|
|
97
|
+
|
|
98
|
+
const toolName = str(
|
|
99
|
+
(payload['tool_name'] ?? payload['toolName'] ?? payload['tool']) as JsonValue | undefined,
|
|
100
|
+
);
|
|
101
|
+
if (toolName !== 'Write' && toolName !== 'Edit') return EXIT_ALLOW;
|
|
102
|
+
|
|
103
|
+
const ti = payload['tool_input'] ?? payload['toolInput'] ?? payload['input'];
|
|
104
|
+
if (!isObject(ti)) return EXIT_ALLOW;
|
|
105
|
+
|
|
106
|
+
const filePath = str((ti['file_path'] ?? ti['path'] ?? ti['filePath']) as JsonValue | undefined);
|
|
107
|
+
if (!filePath || !isScannable(filePath)) return EXIT_ALLOW;
|
|
108
|
+
|
|
109
|
+
const text = writtenText(toolName, ti);
|
|
110
|
+
if (!text) return EXIT_ALLOW;
|
|
111
|
+
|
|
112
|
+
const workspaceRoot = str(envelope['workspace_root'] as JsonValue | undefined).trim() || process.cwd();
|
|
113
|
+
const abs = path.isAbsolute(filePath) ? filePath : path.resolve(workspaceRoot, filePath);
|
|
114
|
+
const rel = path.relative(workspaceRoot, abs);
|
|
115
|
+
const shown = rel.startsWith('..') ? path.basename(abs) : rel;
|
|
116
|
+
|
|
117
|
+
const findings = scanText(shown, text);
|
|
118
|
+
if (findings.length === 0) return EXIT_ALLOW;
|
|
119
|
+
|
|
120
|
+
process.stdout.write(
|
|
121
|
+
`${JSON.stringify({
|
|
122
|
+
decision: 'warn',
|
|
123
|
+
reason: `comment-discipline: ${findings.length} comment finding(s) in the text written to ${shown}`,
|
|
124
|
+
additional_context: buildAdvisoryLine(shown, findings),
|
|
125
|
+
})}\n`,
|
|
126
|
+
);
|
|
127
|
+
return EXIT_WARN;
|
|
128
|
+
} catch {
|
|
129
|
+
return EXIT_ALLOW;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
declare const __AGENT_CONFIG_BUNDLE__: boolean | undefined;
|
|
134
|
+
function _isCliEntry(): boolean {
|
|
135
|
+
if (typeof __AGENT_CONFIG_BUNDLE__ !== 'undefined' && __AGENT_CONFIG_BUNDLE__) return false;
|
|
136
|
+
if (process.argv[1] === undefined) return false;
|
|
137
|
+
const argvUrl = pathToFileURL(path.resolve(process.argv[1])).href;
|
|
138
|
+
if (import.meta.url === argvUrl) return true;
|
|
139
|
+
try {
|
|
140
|
+
return fs.realpathSync(fileURLToPath(import.meta.url)) === fs.realpathSync(path.resolve(process.argv[1]));
|
|
141
|
+
} catch {
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (_isCliEntry()) process.exit(main());
|
|
@@ -69,6 +69,7 @@ import { main as ruleInjectMain } from './rule_inject_hook.js';
|
|
|
69
69
|
import { main as endReviewNudgeMain } from './end_review_nudge_hook.js';
|
|
70
70
|
import { main as turnEndGateMain } from './turn_end_gate_hook.js';
|
|
71
71
|
import { main as editShapeMain } from './edit_shape_hook.js';
|
|
72
|
+
import { main as commentDisciplineMain } from './comment_discipline_hook.js';
|
|
72
73
|
import { main as rereadGuardMain } from './reread_guard_hook.js';
|
|
73
74
|
import { main as sessionEolMain } from './session_eol_hook.js';
|
|
74
75
|
import { main as subagentLedgerMain } from './subagent_ledger_hook.js';
|
|
@@ -129,6 +130,7 @@ export const CONCERN_REGISTRY: Readonly<Record<string, ConcernMain>> = {
|
|
|
129
130
|
'src/scripts/hooks/end_review_nudge_hook.ts': endReviewNudgeMain as ConcernMain,
|
|
130
131
|
'src/scripts/hooks/turn_end_gate_hook.ts': turnEndGateMain as ConcernMain,
|
|
131
132
|
'src/scripts/hooks/edit_shape_hook.ts': editShapeMain as ConcernMain,
|
|
133
|
+
'src/scripts/hooks/comment_discipline_hook.ts': commentDisciplineMain as ConcernMain,
|
|
132
134
|
'src/scripts/hooks/reread_guard_hook.ts': rereadGuardMain as ConcernMain,
|
|
133
135
|
'src/scripts/hooks/session_eol_hook.ts': sessionEolMain as ConcernMain,
|
|
134
136
|
'src/scripts/hooks/subagent_ledger_hook.ts': subagentLedgerMain as ConcernMain,
|
|
@@ -579,12 +579,20 @@ export function readLanguagePin(workspaceRoot: string, session_id: string): Verd
|
|
|
579
579
|
* WHAT IS ACTUALLY CLASSIFIED, stated accurately because R2 finding 9 caught
|
|
580
580
|
* this file claiming otherwise in three places. `visibleProse` strips code,
|
|
581
581
|
* quotes, tables, URLs and paths from the whole reply — but `classify` then
|
|
582
|
-
* applies `
|
|
582
|
+
* applies `stripInjectedRegions` (which removes balanced host wrapper regions
|
|
583
|
+
* such as `<launch-selected-element>`, plus the host's advisory sentence beside
|
|
584
|
+
* them), then `instructionText` (which drops output-shaped lines and their
|
|
583
585
|
* followers) and `humanAuthoredLead`, and RETURNS ON THE LEAD ALONE when the
|
|
584
586
|
* lead is determined. So in the common case the verdict comes from the reply's
|
|
585
587
|
* opening chunk, not from all of it, and indented prose is discarded before
|
|
586
588
|
* scoring.
|
|
587
589
|
*
|
|
590
|
+
* The region strip reaches this path too, and its effect here is small by
|
|
591
|
+
* construction: `visibleProse` has already removed fenced code, so a balanced
|
|
592
|
+
* bare-tag pair surviving into the scorer is prose the reply wrote around a tag
|
|
593
|
+
* rather than markup. Named rather than omitted, because enumerating the
|
|
594
|
+
* scoring surface accurately is this comment's entire job.
|
|
595
|
+
*
|
|
588
596
|
* That is deliberately left as-is rather than swapped for a full-text scorer:
|
|
589
597
|
* sharing one classifier with `language_mirror_hook` is what stops the pin and
|
|
590
598
|
* the detector disagreeing about what language a turn is in, and changing the
|
|
@@ -83,7 +83,11 @@ import {
|
|
|
83
83
|
session_state_file,
|
|
84
84
|
} from "./hooks/state_io.js";
|
|
85
85
|
import { readHookStdin } from "./hooks/hook_stdin.js";
|
|
86
|
-
import {
|
|
86
|
+
import {
|
|
87
|
+
humanAuthoredLead,
|
|
88
|
+
isSyntheticPrompt,
|
|
89
|
+
stripInjectedRegions,
|
|
90
|
+
} from "./_lib/prompt_shape.js";
|
|
87
91
|
|
|
88
92
|
const EXIT_ALLOW = 0;
|
|
89
93
|
// Severity is taken from the EXIT CODE, not from the `decision` field in the
|
|
@@ -296,9 +300,17 @@ export function instructionText(prompt: string): string {
|
|
|
296
300
|
* an English instruction over a German paste resolves to English by the same
|
|
297
301
|
* step. The fallback is what keeps it conservative: a prompt with no document
|
|
298
302
|
* marker classifies exactly as it did before.
|
|
303
|
+
*
|
|
304
|
+
* `stripInjectedRegions` runs FIRST, and the order is load-bearing rather than
|
|
305
|
+
* tidy. A host wrapper the user never typed — `<launch-selected-element>` — is
|
|
306
|
+
* a bare tag line, which `humanAuthoredLead` read as the END of the human lead;
|
|
307
|
+
* prepended, as the host prepends it, that returned an empty lead and handed the
|
|
308
|
+
* verdict to ~4 KB of injected markup. Stripping before `instructionText` also
|
|
309
|
+
* keeps the block's indented lines from arming that filter's paste state, which
|
|
310
|
+
* was deleting the user's own sentence outright.
|
|
299
311
|
*/
|
|
300
312
|
export function classify(prompt: string): Classification {
|
|
301
|
-
const text = instructionText(prompt);
|
|
313
|
+
const text = instructionText(stripInjectedRegions(prompt));
|
|
302
314
|
const lead = humanAuthoredLead(text);
|
|
303
315
|
const leadVerdict = _score(lead);
|
|
304
316
|
if (leadVerdict.language !== "und") {
|