@event4u/agent-config 17.3.0 → 17.4.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.
Files changed (137) hide show
  1. package/.augment-plugin/marketplace.json +3 -3
  2. package/.augment-plugin/plugin.json +1 -1
  3. package/.claude-plugin/marketplace.json +1 -1
  4. package/CHANGELOG.md +164 -342
  5. package/CREDITS.md +2 -2
  6. package/README.md +1 -1
  7. package/dist/agent-src/skills/code-intelligence/SKILL.md +3 -0
  8. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  9. package/dist/cli/registry.js +2 -2
  10. package/dist/cli-delegate/{chunk-DHSSP7V3.js → chunk-5AYJGUA3.js} +0 -2
  11. package/dist/cli-delegate/chunk-DIFZBP4G.js +1336 -0
  12. package/dist/cli-delegate/{chunk-MT2WOOCY.js → chunk-WY5ZZPGL.js} +2 -2
  13. package/dist/cli-delegate/{chunk-ORJPBER2.js → chunk-X6LZ7W5A.js} +73 -10
  14. package/dist/cli-delegate/cmd_conformance.js +175 -183
  15. package/dist/cli-delegate/cmd_doctor.js +5 -5
  16. package/dist/cli-delegate/cmd_doctor_neighbours.js +3 -3
  17. package/dist/cli-delegate/cmd_explain.js +1 -1
  18. package/dist/cli-delegate/cmd_handoff.js +2 -2
  19. package/dist/cli-delegate/cmd_memory_get.js +1 -1
  20. package/dist/cli-delegate/cmd_route_audit.js +1 -1
  21. package/dist/cli-delegate/cmd_session_recycle.js +2 -2
  22. package/dist/cli-delegate/cmd_update.js +24 -13
  23. package/dist/cli-delegate/cmd_upgrade.js +2 -2
  24. package/dist/cli-delegate/dist-25AZAHOP.js +3240 -0
  25. package/dist/cli-delegate/dist-P7MFPMF3.js +411 -0
  26. package/dist/cli-delegate/dist-XAS5ZLQB.js +6 -0
  27. package/dist/cli-delegate/{upgrade_unattended-VVL6JLSX.js → upgrade_unattended-QCWOKTUN.js} +178 -163
  28. package/dist/discovery/deprecation-report.md +1 -1
  29. package/dist/discovery/discovery-manifest.json +3 -3
  30. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  31. package/dist/discovery/discovery-manifest.summary.md +1 -1
  32. package/dist/discovery/dormancy-report.md +1 -1
  33. package/dist/discovery/orphan-report.md +1 -1
  34. package/dist/discovery/packs.json +2 -2
  35. package/dist/discovery/trust-report.md +1 -1
  36. package/dist/discovery/workspaces.json +2 -2
  37. package/dist/hooks/code_graph_refresh.chunk.cjs +56 -27
  38. package/dist/hooks/code_graph_refresh.chunk.cjs.sha256 +1 -1
  39. package/dist/hooks/dispatch.js +982 -929
  40. package/dist/hooks/dispatch.sha256 +1 -1
  41. package/dist/hooks/egress_engine.chunk.cjs +56 -6
  42. package/dist/hooks/egress_engine.chunk.cjs.sha256 +1 -1
  43. package/dist/hooks/update_notice.chunk.cjs +914 -0
  44. package/dist/hooks/update_notice.chunk.cjs.sha256 +1 -0
  45. package/dist/mcp/registry-manifest.json +1 -1
  46. package/dist/mcp/server.json +2 -2
  47. package/dist/mcp/server.mjs +71259 -66437
  48. package/dist/scripts/condense.js +9 -6
  49. package/package.json +4 -1
  50. package/src/config/evaluator-budgets.json +9 -8
  51. package/src/config/gate-violation-baselines.json +2 -2
  52. package/src/config/hook-bundle-budget.json +31 -6
  53. package/src/config/packed-binary-manifest.json +9 -0
  54. package/src/config/sigstore/npm_keys.json +50 -0
  55. package/src/config/sigstore/trust-material.json +9 -0
  56. package/src/config/sigstore/trusted_root.json +126 -0
  57. package/src/config/skill-body-budget.json +7 -1
  58. package/src/scripts/_cli/cmd_update.ts +48 -20
  59. package/src/scripts/_cli/cmd_upgrade.ts +7 -1
  60. package/src/scripts/_cli/upgrade_unattended.ts +90 -76
  61. package/src/scripts/_dispatch.bash +3 -2
  62. package/src/scripts/_lib/confusables.ts +0 -19
  63. package/src/scripts/_lib/egress_normalize.ts +53 -23
  64. package/src/scripts/_lib/egress_text.ts +5 -3
  65. package/src/scripts/_lib/egress_token.ts +7 -5
  66. package/src/scripts/_lib/gate_collector_experimental.ts +633 -0
  67. package/src/scripts/_lib/git_common_dir.ts +10 -0
  68. package/src/scripts/_lib/graph_feeder_record.ts +3 -2
  69. package/src/scripts/_lib/install_reach_checks.ts +32 -2
  70. package/src/scripts/_lib/lineage_backfill.ts +136 -0
  71. package/src/scripts/_lib/lineage_ledger.ts +211 -0
  72. package/src/scripts/_lib/lineage_map.ts +55 -0
  73. package/src/scripts/_lib/lineage_query.ts +140 -0
  74. package/src/scripts/_lib/lineage_seed.ts +116 -0
  75. package/src/scripts/_lib/lineage_watch.ts +249 -0
  76. package/src/scripts/_lib/link_crypto.ts +8 -4
  77. package/src/scripts/_lib/production_reach.ts +3 -3
  78. package/src/scripts/_lib/project_registry.ts +227 -0
  79. package/src/scripts/_lib/provenance_verify.ts +14 -242
  80. package/src/scripts/_lib/sigstore_provenance.ts +177 -0
  81. package/src/scripts/_lib/source_id.ts +48 -0
  82. package/src/scripts/_lib/source_shape.ts +4 -0
  83. package/src/scripts/_lib/unattended_gates.ts +6 -1
  84. package/src/scripts/advisories.ts +26 -10
  85. package/src/scripts/ai_council/council_egress.ts +5 -6
  86. package/src/scripts/bench_graph_feeder_latency.ts +10 -3
  87. package/src/scripts/check_dependency_floors.ts +7 -0
  88. package/src/scripts/check_egress_mutations.ts +1 -0
  89. package/src/scripts/code_graph/build.ts +67 -3
  90. package/src/scripts/code_graph/cli.ts +131 -28
  91. package/src/scripts/code_graph/conventions_default.ts +20 -1
  92. package/src/scripts/code_graph/detect.ts +5 -5
  93. package/src/scripts/code_graph/estate_cli.ts +135 -0
  94. package/src/scripts/code_graph/estate_index.ts +394 -0
  95. package/src/scripts/code_graph/estate_manifests.ts +223 -0
  96. package/src/scripts/code_graph/estate_map.ts +141 -0
  97. package/src/scripts/code_graph/extract.ts +4 -1
  98. package/src/scripts/code_graph/extract_more.ts +137 -2
  99. package/src/scripts/code_graph/graph_budget.ts +158 -0
  100. package/src/scripts/code_graph/graph_home.ts +80 -0
  101. package/src/scripts/code_graph/lineage_cli.ts +315 -0
  102. package/src/scripts/code_graph/map.ts +22 -13
  103. package/src/scripts/code_graph/map_model.ts +67 -12
  104. package/src/scripts/code_graph/map_verify.ts +68 -5
  105. package/src/scripts/code_graph/map_viewer/viewer.css +12 -0
  106. package/src/scripts/code_graph/map_viewer/viewer.js +45 -15
  107. package/src/scripts/code_graph/project_ref.ts +25 -0
  108. package/src/scripts/code_graph/projects_cli.ts +254 -0
  109. package/src/scripts/code_graph/providers/catalog.ts +14 -5
  110. package/src/scripts/code_graph/providers/django.ts +52 -9
  111. package/src/scripts/code_graph/providers/index.ts +2 -0
  112. package/src/scripts/code_graph/providers/rails.ts +204 -0
  113. package/src/scripts/code_graph/providers/spring.ts +38 -1
  114. package/src/scripts/code_graph/query.ts +9 -9
  115. package/src/scripts/code_graph/refresh_lock.ts +12 -8
  116. package/src/scripts/code_graph/repo_identity.ts +169 -0
  117. package/src/scripts/code_graph/sqlite_store.ts +22 -25
  118. package/src/scripts/code_graph/types.ts +6 -2
  119. package/src/scripts/condense.ts +6 -6
  120. package/src/scripts/hook_chunks.mjs +7 -0
  121. package/src/scripts/hook_manifest.json +1 -1
  122. package/src/scripts/hook_manifest.yaml +20 -17
  123. package/src/scripts/hooks/code_graph_refresh_hook.ts +10 -7
  124. package/src/scripts/hooks/dispatch_hook.ts +6 -7
  125. package/src/scripts/hooks/host_semantics.ts +72 -0
  126. package/src/scripts/hooks/lazy_concern.ts +4 -0
  127. package/src/scripts/hooks/user_notice.ts +105 -0
  128. package/src/scripts/lint_harvest_provenance.ts +137 -11
  129. package/src/scripts/mcp_server/consumer_tool_catalog.json +69 -15
  130. package/src/scripts/mcp_server/graph_tools.ts +161 -41
  131. package/src/scripts/network_sources.ts +24 -6
  132. package/src/scripts/schemas/provenance-mechanism.schema.json +46 -0
  133. package/src/scripts/update_notice_hook.ts +75 -7
  134. package/src/vendor/grammars/README.md +7 -6
  135. package/src/vendor/grammars/tree-sitter-ruby.wasm +0 -0
  136. /package/dist/cli-delegate/{chunk-FKYZOWVD.js → chunk-QBAFP67O.js} +0 -0
  137. /package/dist/cli-delegate/{chunk-BMGUGSY6.js → chunk-TQG6UMPC.js} +0 -0
@@ -0,0 +1,169 @@
1
+ /**
2
+ * A repository's identity on this machine (ADR-299, council decision O2).
3
+ *
4
+ * `repoId` is 12 hex of an HMAC-SHA256, keyed by a random key created once
5
+ * under the user-global `runtime/projects/`, over the canonical origin URL —
6
+ * userinfo, tokens, query and fragment removed, host lower-cased, default port
7
+ * dropped, ssh / scp / https forms and a trailing `.git` collapsed. Without a
8
+ * remote the main checkout's realpath stands in. Keyed rather than a plain hash
9
+ * because a hosting URL is dictionary-guessable and may carry a token.
10
+ *
11
+ * A linked worktree keeps its parent's `repoId` and gets an `instance`, so its
12
+ * writable caches never collide with the main checkout's while estate queries
13
+ * still count one project. Two separate clones of one origin share `repoId` too,
14
+ * so `checkout` — keyed over the main checkout's realpath — is what keeps their
15
+ * writable homes apart.
16
+ *
17
+ * File-based like `_lib/git_common_dir.ts`: an inherited `GIT_DIR` would
18
+ * redirect a `git config` subprocess to the wrong repository.
19
+ */
20
+ import { createHmac, randomBytes } from 'node:crypto';
21
+ import * as fs from 'node:fs';
22
+ import * as path from 'node:path';
23
+
24
+ import { git_common_dir } from '../_lib/git_common_dir.js';
25
+ import { type EnvMap, event4u_root } from '../_lib/user_global_paths.js';
26
+
27
+ export interface RepoIdentity {
28
+ repoId: string;
29
+ /** Set for a linked worktree only. */
30
+ instance: string | null;
31
+ /** 8 hex over the main checkout's realpath: distinct per clone, shared by its worktrees. */
32
+ checkout: string;
33
+ source: 'origin' | 'realpath';
34
+ }
35
+
36
+ const DEFAULT_PORTS: Record<string, string> = { 'ssh:': '22', 'git+ssh:': '22', 'https:': '443', 'http:': '80', 'git:': '9418' };
37
+
38
+ export function projectsDir(env?: EnvMap | null): string {
39
+ return path.join(event4u_root(env), 'runtime', 'projects');
40
+ }
41
+
42
+ /** `dir` overrides the projects directory, for a caller (advisories) that carries its own. */
43
+ export function machineKeyPath(env?: EnvMap | null, dir: string = projectsDir(env)): string {
44
+ return path.join(dir, 'machine.key');
45
+ }
46
+
47
+ /**
48
+ * The machine key, created on first use. Published with a hard link so a
49
+ * concurrent first use either wins or reads the winner's complete key — never
50
+ * an empty file. A key that exists but is malformed throws: replacing it would
51
+ * silently re-key every repository on the machine.
52
+ */
53
+ export function machineKey(env?: EnvMap | null, dir?: string): Buffer {
54
+ const p = machineKeyPath(env, dir);
55
+ const read = (): Buffer => {
56
+ const hex = fs.readFileSync(p, 'utf-8').trim();
57
+ if (!/^[0-9a-f]{64}$/.test(hex)) throw new Error(`malformed machine key: ${p}`);
58
+ return Buffer.from(hex, 'hex');
59
+ };
60
+ if (fs.existsSync(p)) return read();
61
+ fs.mkdirSync(path.dirname(p), { recursive: true });
62
+ const tmp = `${p}.${process.pid}-${randomBytes(4).toString('hex')}.tmp`;
63
+ fs.writeFileSync(tmp, `${randomBytes(32).toString('hex')}\n`, { mode: 0o600 });
64
+ try {
65
+ fs.linkSync(tmp, p);
66
+ } catch (e) {
67
+ if ((e as NodeJS.ErrnoException).code !== 'EEXIST') throw e;
68
+ } finally {
69
+ fs.rmSync(tmp, { force: true });
70
+ }
71
+ return read();
72
+ }
73
+
74
+ function trimPath(p: string): string {
75
+ return p
76
+ .replace(/\/{2,}/g, '/')
77
+ .replace(/^\/+|\/+$/g, '')
78
+ .replace(/\.git$/i, '')
79
+ .replace(/\/+$/, '');
80
+ }
81
+
82
+ /**
83
+ * The credential-free form two spellings of one remote share. A relative local
84
+ * path resolves against `base`, the repository root, because the process cwd
85
+ * is wherever the CLI happened to be started.
86
+ */
87
+ export function canonicalOrigin(raw: string, base?: string): string {
88
+ const url = raw.trim();
89
+ const scp = /^(?:[^@/]+@)?([^:/]+):(?!\/\/)(.+)$/.exec(url);
90
+ if (!url.includes('://') && scp && !/^[a-zA-Z]:[\\/]/.test(url)) {
91
+ return `${(scp[1] as string).toLowerCase()}/${trimPath(scp[2] as string)}`;
92
+ }
93
+ try {
94
+ const u = new URL(url);
95
+ if (u.protocol === 'file:') return `file:${trimPath(decodeURIComponent(u.pathname))}`;
96
+ const port = u.port && u.port !== DEFAULT_PORTS[u.protocol] ? `:${u.port}` : '';
97
+ return `${u.hostname.toLowerCase()}${port}/${trimPath(decodeURIComponent(u.pathname))}`;
98
+ } catch {
99
+ return `file:${trimPath(base === undefined ? path.resolve(url) : path.resolve(base, url))}`;
100
+ }
101
+ }
102
+
103
+ /** The `origin` URL, else the first remote's, read from the common git config. */
104
+ export function remoteUrl(root: string): string | null {
105
+ const common = git_common_dir(root);
106
+ if (common === null) return null;
107
+ let text: string;
108
+ try {
109
+ text = fs.readFileSync(path.join(common, 'config'), 'utf-8');
110
+ } catch {
111
+ return null;
112
+ }
113
+ const urls = new Map<string, string>();
114
+ let remote: string | null = null;
115
+ for (const line of text.split(/\r?\n/)) {
116
+ const section = /^\s*\[\s*remote\s+"([^"]+)"\s*\]/.exec(line);
117
+ if (section) {
118
+ remote = section[1] as string;
119
+ continue;
120
+ }
121
+ if (/^\s*\[/.test(line)) {
122
+ remote = null;
123
+ continue;
124
+ }
125
+ const kv = /^\s*url\s*=\s*(.+?)\s*$/.exec(line);
126
+ if (remote !== null && kv && !urls.has(remote)) urls.set(remote, (kv[1] as string).replace(/^"|"$/g, ''));
127
+ }
128
+ return urls.get('origin') ?? urls.values().next().value ?? null;
129
+ }
130
+
131
+ function realpathOr(p: string): string {
132
+ try {
133
+ return fs.realpathSync(p);
134
+ } catch {
135
+ return path.resolve(p);
136
+ }
137
+ }
138
+
139
+ function hmac(key: Buffer, value: string): string {
140
+ return createHmac('sha256', key).update(value).digest('hex');
141
+ }
142
+
143
+ export function repoIdentity(root: string, env?: EnvMap | null, dir?: string): RepoIdentity {
144
+ const key = machineKey(env, dir);
145
+ const real = realpathOr(root);
146
+ const common = git_common_dir(real);
147
+ let linked = false;
148
+ try {
149
+ linked = !fs.statSync(path.join(real, '.git')).isDirectory();
150
+ } catch {
151
+ linked = false;
152
+ }
153
+ const origin = remoteUrl(real);
154
+ const main = common !== null && path.basename(common) === '.git' ? path.dirname(common) : real;
155
+ let source: RepoIdentity['source'] = 'origin';
156
+ let canonical: string;
157
+ if (origin !== null) {
158
+ canonical = `origin:${canonicalOrigin(origin, main)}`;
159
+ } else {
160
+ source = 'realpath';
161
+ canonical = `path:${main}`;
162
+ }
163
+ return {
164
+ repoId: hmac(key, canonical).slice(0, 12),
165
+ instance: linked ? hmac(key, `instance:${real}`).slice(0, 8) : null,
166
+ checkout: hmac(key, `checkout:${main}`).slice(0, 8),
167
+ source,
168
+ };
169
+ }
@@ -56,7 +56,7 @@ import type { CodeEdge, CodeGraph, CodeNode } from './types.js';
56
56
  * 4 → 5 (`road-to-graph-providers-for-every-stack` 2.1): `edges` gained
57
57
  * `provider_id`, the convention provider that drew a convention edge.
58
58
  */
59
- export const GRAPH_STORE_VERSION = 5;
59
+ export const GRAPH_STORE_VERSION = 6;
60
60
 
61
61
  /**
62
62
  * Edge count at or above which the indexed read path replaces the blob path.
@@ -81,11 +81,10 @@ export function sqliteTwinPath(jsonPath: string): string {
81
81
  * JSON path remains the source of truth either way.
82
82
  *
83
83
  * Storage model: nodes/edges land in real tables (queryable, and the FTS-free
84
- * structure the rollback triggers measure), while `meta.graph_json` carries
85
- * the byte-exact canonical serialization so the loader can guarantee
86
- * byte-identical answers without re-deriving key order.
84
+ * structure the rollback triggers measure). The JSON is the only full copy;
85
+ * the twin is a disposable, rebuildable projection of it.
87
86
  */
88
- export function emitSqliteTwin(graph: CodeGraph, serialized: string, jsonPath: string): boolean {
87
+ export function emitSqliteTwin(graph: CodeGraph, jsonPath: string): boolean {
89
88
  if (!isSqliteAvailableSync()) return false;
90
89
  const twin = sqliteTwinPath(jsonPath);
91
90
  const tmp = `${twin}.tmp-${process.pid}`;
@@ -120,7 +119,6 @@ export function emitSqliteTwin(graph: CodeGraph, serialized: string, jsonPath: s
120
119
  meta.run('source_checksum', graph.source_checksum);
121
120
  meta.run('json_size', String(stat.size));
122
121
  meta.run('json_mtime_ms', String(stat.mtimeMs));
123
- meta.run('graph_json', serialized);
124
122
  // Counts live in meta so a reader can pick its path from one row
125
123
  // instead of a COUNT(*) over the table it is deciding whether to
126
124
  // read at all.
@@ -176,39 +174,38 @@ export function emitSqliteTwin(graph: CodeGraph, serialized: string, jsonPath: s
176
174
  }
177
175
 
178
176
  /**
179
- * Load the canonical serialization from a FRESH SQLite twin, or null when the
180
- * twin is absent / stale (JSON changed since emission) / corrupt /
181
- * version-mismatched / unsupported runtime. Callers fall back to reading the
182
- * JSON — and best-effort re-emit the twin from it (zero-touch rebuild).
177
+ * Whether the twin beside `jsonPath` mirrors it: present, the current store
178
+ * version, and recorded against the JSON's present size and mtime. A corrupt
179
+ * twin is a non-event — it is dropped so the next load re-emits it.
180
+ *
181
+ * The twin used to carry the whole serialized graph a second time and this
182
+ * returned it; that blob was the same bytes as the JSON and doubled the twin
183
+ * (road-to-a-graph-that-follows-you D2). The JSON is the only full copy now.
183
184
  */
184
- export function loadSerializedFromTwin(jsonPath: string): string | null {
185
- if (!isSqliteAvailableSync()) return null;
185
+ export function twinIsCurrent(jsonPath: string): boolean {
186
+ if (!isSqliteAvailableSync()) return false;
186
187
  const twin = sqliteTwinPath(jsonPath);
187
- if (!fs.existsSync(twin)) return null;
188
+ if (!fs.existsSync(twin)) return false;
188
189
  let stat: fs.Stats;
189
190
  try {
190
191
  stat = fs.statSync(jsonPath);
191
192
  } catch {
192
- return null; // canonical JSON gone — the twin has no truth to mirror
193
+ return false; // canonical JSON gone — the twin has no truth to mirror
193
194
  }
194
195
  try {
195
196
  const { DatabaseSync } = loadSqliteSync('code_graph.sqlite_store');
196
197
  const db = new DatabaseSync(twin, { readOnly: true });
197
198
  try {
198
- if (readUserVersion(db) !== GRAPH_STORE_VERSION) return null;
199
+ if (readUserVersion(db) !== GRAPH_STORE_VERSION) return false;
199
200
  const rows = db.prepare('SELECT key, value FROM meta').all() as { key: string; value: string }[];
200
201
  const meta = new Map(rows.map((r) => [r.key, r.value]));
201
- if (meta.get('json_size') !== String(stat.size)) return null;
202
- if (meta.get('json_mtime_ms') !== String(stat.mtimeMs)) return null;
203
- const serialized = meta.get('graph_json');
204
- return serialized && serialized.length > 0 ? serialized : null;
202
+ return meta.get('json_size') === String(stat.size) && meta.get('json_mtime_ms') === String(stat.mtimeMs);
205
203
  } finally {
206
204
  db.close();
207
205
  }
208
206
  } catch {
209
- // Corrupt twin is a non-event: drop it so the next build re-emits.
210
207
  fs.rmSync(twin, { force: true });
211
- return null;
208
+ return false;
212
209
  }
213
210
  }
214
211
 
@@ -218,9 +215,9 @@ export function loadSerializedFromTwin(jsonPath: string): string | null {
218
215
  *
219
216
  * Every export it had took a PATH and returned the whole graph: the serialized
220
217
  * blob, or a pair of counts. So "the query path prefers SQLite" was true and
221
- * bought nothing — `loadSerializedFromTwin` hands back the entire
222
- * serialization, and the caller then parses it and builds a `Map` over every
223
- * node and every edge. The twin was a cheaper blob transport, never an index.
218
+ * bought nothing — the loader handed back the entire serialization, and the
219
+ * caller then parsed it and built a `Map` over every node and every edge. The
220
+ * twin was a cheaper blob transport, never an index.
224
221
  *
225
222
  * These reads take an id, a label, or a file, and touch only the rows that
226
223
  * answer. Statements are prepared once per handle because a BFS calls
@@ -315,7 +312,7 @@ function toEdge(r: EdgeRow): CodeEdge {
315
312
  /**
316
313
  * Open the twin for INDEXED reads, or null when it cannot serve them.
317
314
  *
318
- * Null on exactly the conditions `loadSerializedFromTwin` already refuses on —
315
+ * Null on exactly the conditions `twinIsCurrent` refuses on —
319
316
  * absent, stale against the JSON's size/mtime, corrupt, version-mismatched, no
320
317
  * `node:sqlite` — so the two paths agree about when the twin is trustworthy
321
318
  * and a caller never has to ask twice.
@@ -9,7 +9,7 @@
9
9
  */
10
10
 
11
11
  /** Launch set — the stacks this suite's consumers actually run. */
12
- export type Lang = 'php' | 'typescript' | 'javascript' | 'python' | 'go' | 'java' | 'csharp';
12
+ export type Lang = 'php' | 'typescript' | 'javascript' | 'python' | 'go' | 'java' | 'csharp' | 'ruby';
13
13
 
14
14
  /** Same scale as `discovery_graph.ts::EdgeConfidence` (reused, not forked). */
15
15
  export type EdgeConfidence = 'EXTRACTED' | 'INFERRED' | 'AMBIGUOUS';
@@ -104,6 +104,8 @@ export type ResolvedVia =
104
104
  | 'fs-route'
105
105
  /** Stated by a compiler-grade SCIP index the project ships (`scip_reader.ts`). */
106
106
  | 'compiler-index'
107
+ /** C#: the one type of that name in the namespaces the file can see (its own, their parents, its `using`s). */
108
+ | 'namespace-scope'
107
109
  | 'test-import'
108
110
  | 'name-lookup'
109
111
  | 'dynamic'
@@ -159,7 +161,7 @@ export type EdgeProvider =
159
161
  // One space-separated string per list: this module ships in the hook bundle,
160
162
  // where an array literal costs a line per entry. `Words` splits it in the type.
161
163
  const STATED_WORDS =
162
- 'same-file import-specifier path-alias psr4 route-table directive-scan schema-call orm-relation di-binding compiler-index test-import literal-path literal-dotted fs-route' as const;
164
+ 'same-file import-specifier path-alias psr4 route-table directive-scan schema-call orm-relation di-binding compiler-index namespace-scope test-import literal-path literal-dotted fs-route' as const;
163
165
  const GUESS_WORDS = 'name-lookup dynamic foreign' as const;
164
166
  type Words<S extends string> = S extends `${infer H} ${infer T}` ? H | Words<T> : S;
165
167
  /** Mechanisms in neither list; must be `never` (a test asserts it). */
@@ -362,6 +364,7 @@ export const EXT_LANG: Readonly<Record<string, Lang>> = {
362
364
  '.go': 'go',
363
365
  '.java': 'java',
364
366
  '.cs': 'csharp',
367
+ '.rb': 'ruby',
365
368
  '.vue': 'typescript',
366
369
  };
367
370
 
@@ -374,6 +377,7 @@ export const GRAMMAR_WASM: Readonly<Record<Lang, string>> = {
374
377
  go: 'tree-sitter-go.wasm',
375
378
  java: 'tree-sitter-java.wasm',
376
379
  csharp: 'tree-sitter-c_sharp.wasm',
380
+ ruby: 'tree-sitter-ruby.wasm',
377
381
  };
378
382
 
379
383
  /** The single ABI version the pinned grammar set is built against. */
@@ -2191,11 +2191,11 @@ export function generate_plugin_command_skills(): number {
2191
2191
  const pointer_dir = path.join(MODULE_STATE.PLUGIN_SKILLS_DIR, PLUGIN_POINTER_SLUG);
2192
2192
  _mkdirp(pointer_dir);
2193
2193
  const pointer_file = path.join(pointer_dir, 'SKILL.md');
2194
- if (_isSymlink(pointer_file)) {
2195
- fs.unlinkSync(pointer_file);
2196
- }
2197
- if (!_isFile(pointer_file) || fs.readFileSync(pointer_file, 'utf-8') !== PLUGIN_POINTER_SKILL_BODY) {
2198
- fs.writeFileSync(pointer_file, PLUGIN_POINTER_SKILL_BODY);
2194
+ for (const file of [pointer_file, path.join(MODULE_STATE.PROJECT_ROOT, '.github', 'plugin', 'skills', PLUGIN_POINTER_SLUG, 'SKILL.md')]) {
2195
+ if (_isSymlink(file)) {
2196
+ fs.unlinkSync(file);
2197
+ }
2198
+ if (!_isFile(file) || fs.readFileSync(file, 'utf-8') !== PLUGIN_POINTER_SKILL_BODY) { fs.mkdirSync(path.dirname(file), { recursive: true }); fs.writeFileSync(file, PLUGIN_POINTER_SKILL_BODY); }
2199
2199
  }
2200
2200
 
2201
2201
  // 2. Prune every other skill dir so the tree converges to shim shape
@@ -2226,7 +2226,7 @@ export function generate_plugin_command_skills(): number {
2226
2226
  }
2227
2227
  }
2228
2228
 
2229
- let msg = ' ✅ Plugin skills: bootstrap shim (1 pointer skill) in .claude-plugin/skills/';
2229
+ let msg = ' ✅ Plugin skills: bootstrap shim (1 pointer skill) in .claude-plugin/skills/ and .github/plugin/skills/';
2230
2230
  if (removed_dirs) {
2231
2231
  msg += ` (${removed_dirs} content entries pruned)`;
2232
2232
  }
@@ -49,6 +49,13 @@ export const HOOK_CHUNKS = Object.freeze([
49
49
  entry: 'src/scripts/hooks/code_graph_refresh_hook.ts',
50
50
  outfile: 'dist/hooks/code_graph_refresh.chunk.cjs',
51
51
  }),
52
+ // `yaml` external for the reason given at `chat_history`: the concern
53
+ // reads one user-global settings file with it.
54
+ Object.freeze({
55
+ entry: 'src/scripts/update_notice_hook.ts',
56
+ outfile: 'dist/hooks/update_notice.chunk.cjs',
57
+ external: Object.freeze(['yaml']),
58
+ }),
52
59
  ]);
53
60
 
54
61
  /**
@@ -1 +1 @@
1
- {"fingerprint":"99ce8f951850440231d5d39bd342b1f53d09db94ae71722605bfab2c4dcb5dd0:111523","body_fingerprint":"7da30ee3fc8e8c873a295d7035ba34df3eb3f07e5a47d7dc3983bae823c3395c:21398","manifest":{"schema_version":1,"concerns":{"chat-history":{"script":"src/scripts/chat_history.ts","args":["hook-dispatch"],"fail_closed":false,"severity":"advisory","effect":"telemetry","needs_payload_bodies":["result"]},"hot-context":{"script":"src/scripts/hot_context_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"memory"},"handoff-context":{"script":"src/scripts/handoff_context_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"context"},"roadmap-progress":{"script":"src/scripts/roadmap_progress_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"formatting","needs_payload_bodies":["input"]},"onboarding-gate":{"script":"src/scripts/onboarding_gate_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"notification"},"context-hygiene":{"script":"src/scripts/context_hygiene_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"telemetry"},"verify-before-complete":{"script":"src/scripts/before_complete_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"verification","needs_payload_bodies":["input","result"]},"ship-diff-volume":{"script":"src/scripts/hooks/ship_diff_volume_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"verification","needs_payload_bodies":["input"]},"minimal-safe-diff":{"script":"src/scripts/minimal_safe_diff_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"verification","needs_payload_bodies":["input"]},"injection-scan":{"script":"src/scripts/injection_scan_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"verification","needs_payload_bodies":["input","result"]},"block-no-verify":{"script":"src/scripts/hooks/block_no_verify.ts","args":[],"fail_closed":true,"severity":"blocking","effect":"permission","needs_payload_bodies":["input"]},"block-kernel-rule-writes":{"script":"src/scripts/hooks/block_kernel_rule_writes.ts","args":[],"fail_closed":true,"severity":"blocking","effect":"permission","needs_payload_bodies":["input"]},"block-plumbing-writes":{"script":"src/scripts/hooks/block_plumbing_writes.ts","args":[],"fail_closed":true,"severity":"blocking","effect":"permission","needs_payload_bodies":["input"]},"one-question-per-ask":{"script":"src/scripts/hooks/one_question_per_ask_hook.ts","args":[],"fail_closed":false,"severity":"blocking","effect":"permission","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","effect":"permission","needs_payload_bodies":["input"]},"block-credential-reads":{"script":"src/scripts/hooks/block_credential_reads.ts","args":[],"fail_closed":false,"severity":"blocking","effect":"permission","needs_payload_bodies":["input"]},"block-config-weakening":{"script":"src/scripts/hooks/block_config_weakening.ts","args":[],"fail_closed":false,"severity":"blocking","effect":"permission","needs_payload_bodies":["input"]},"rtk-wrap":{"script":"src/scripts/hooks/rtk_wrap_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"formatting","needs_payload_bodies":["input"]},"design-slop":{"script":"src/scripts/hooks/design_slop_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"verification","needs_payload_bodies":["input"]},"design-pass":{"script":"src/scripts/hooks/design_pass_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"notification","needs_payload_bodies":["input"]},"design-pass-stop":{"script":"src/scripts/hooks/design_pass_hook.ts","args":["--slot","stop"],"fail_closed":false,"severity":"advisory","effect":"notification"},"ui-route-nudge":{"script":"src/scripts/hooks/ui_route_nudge_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"notification","needs_payload_bodies":["input"]},"suggestion-capture":{"script":"src/scripts/hooks/suggestion_capture_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"telemetry"},"chain-nudge":{"script":"src/scripts/hooks/chain_nudge_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"notification","needs_payload_bodies":["input"]},"code-graph-context":{"script":"src/scripts/hooks/code_graph_context_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"context","tools":["Grep","Glob","Read","Bash"],"needs_payload_bodies":["input"]},"memory-learn":{"script":"src/scripts/memory_learn_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"memory"},"first-run-gate":{"script":"src/scripts/first_run_gate_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"notification"},"profile-staleness":{"script":"src/scripts/profile_staleness_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"notification"},"wrapper-freshness":{"script":"src/scripts/wrapper_freshness_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"notification"},"surface-probe":{"script":"src/scripts/surface_probe_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"telemetry"},"team-review-gate":{"script":"src/scripts/team_review_gate_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"verification"},"pr-url-reminder":{"script":"src/scripts/pr_url_reminder_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"notification","needs_payload_bodies":["input","result"]},"push-settle":{"script":"src/scripts/hooks/push_settle_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"verification","needs_payload_bodies":["input","result"]},"language-mirror":{"script":"src/scripts/language_mirror_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"context"},"git-authorization":{"script":"src/scripts/git_authorization_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"verification"},"evidence-independence":{"script":"src/scripts/hooks/evidence_independence.ts","args":[],"fail_closed":false,"severity":"blocking","effect":"permission","needs_payload_bodies":["input"]},"session-canary":{"script":"src/scripts/session_canary_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"context"},"council-availability":{"script":"src/scripts/council_availability_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"verification"},"telemetry-disclosure":{"script":"src/scripts/telemetry_disclosure_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"notification"},"telemetry-flush":{"script":"src/scripts/hooks/telemetry_flush_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"telemetry"},"self-repair":{"script":"src/scripts/self_repair_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"telemetry"},"session-register":{"script":"src/scripts/session_register_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"telemetry"},"orchestration-record":{"script":"src/scripts/hooks/orchestration_record_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"telemetry","tools":["Agent","Task"],"needs_payload_bodies":["input","result"]},"telemetry-usage":{"script":"src/scripts/hooks/telemetry_usage_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"telemetry","tools":["Skill"],"needs_payload_bodies":["input"]},"mcp-usage-observation":{"script":"src/scripts/hooks/mcp_usage_observation_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"telemetry"},"delegation-nudge":{"script":"src/scripts/hooks/delegation_nudge_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"notification","nudge_rank":1},"skill-route":{"script":"src/scripts/hooks/skill_route_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"context","nudge_rank":2},"rule-inject":{"script":"src/scripts/hooks/rule_inject_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"context","needs_payload_bodies":["input"]},"obligation-settle":{"script":"src/scripts/hooks/obligation_settle_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"verification"},"end-review-nudge":{"script":"src/scripts/hooks/end_review_nudge_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"notification","skip_on_refusal_retry":true},"review-baseline":{"script":"src/scripts/hooks/review_baseline_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"telemetry"},"turn-end-gate":{"script":"src/scripts/hooks/turn_end_gate_hook.ts","args":[],"fail_closed":false,"severity":"blocking","effect":"permission"},"comment-discipline":{"script":"src/scripts/hooks/comment_discipline_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"verification","tools":["Write","Edit"],"needs_payload_bodies":["input"]},"edit-shape":{"script":"src/scripts/hooks/edit_shape_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"verification","tools":["Write"],"needs_payload_bodies":["input"]},"reread-guard":{"script":"src/scripts/hooks/reread_guard_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"verification","tools":["Read","Edit","Write"],"needs_payload_bodies":["input"]},"memory-recall":{"script":"src/scripts/hooks/memory_recall_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"memory","tools":["Bash","Edit","Write","MultiEdit","str-replace-editor","save-file","launch-process"],"needs_payload_bodies":["input"]},"session-eol":{"script":"src/scripts/hooks/session_eol_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"notification"},"interruption-ledger":{"script":"src/scripts/hooks/interruption_ledger_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"telemetry","skip_on_refusal_retry":true},"instructions-observer":{"script":"src/scripts/hooks/instructions_observer_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"telemetry"},"code-graph-refresh":{"script":"src/scripts/hooks/code_graph_refresh_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"execution"},"subagent-ledger":{"script":"src/scripts/hooks/subagent_ledger_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"telemetry"},"tool-result-bytes":{"script":"src/scripts/hooks/tool_result_bytes_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"telemetry"},"spawn-guard-shadow":{"script":"src/scripts/hooks/spawn_guard_shadow_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"telemetry","tools":["Agent","Task","SendMessage"],"needs_payload_bodies":["input","result"],"payload_fields":["name","subagent_type","to","recipient_kind","agentId"]},"host-rate-marker":{"script":"src/scripts/hooks/host_rate_marker_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"telemetry"},"source-first-gate":{"script":"src/scripts/hooks/source_first_gate_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"telemetry","needs_payload_bodies":["input"]},"journal-record":{"script":"src/scripts/hooks/journal_record_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"telemetry"}},"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":{"ask":"text","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","code-graph-refresh"],"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-plumbing-writes","block-config-weakening","block-speaking-inbox-dir","block-credential-reads","rtk-wrap","design-slop","ui-route-nudge","code-graph-context","chain-nudge","ship-diff-volume","reread-guard","memory-recall"],"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","mcp-usage-observation","tool-result-bytes","edit-shape","comment-discipline","design-pass"]},"claude":{"ask":"native","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","rule-inject","code-graph-refresh"],"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","obligation-settle","turn-end-gate","self-repair","session-register","session-eol","interruption-ledger","roadmap-progress","design-pass-stop","suggestion-capture","journal-record"],"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-plumbing-writes","block-config-weakening","block-speaking-inbox-dir","block-credential-reads","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","memory-recall"],"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","mcp-usage-observation","tool-result-bytes","edit-shape","comment-discipline","language-mirror","design-pass","journal-record","spawn-guard-shadow"],"pre_compact":["language-mirror","rule-inject","journal-record"],"subagent_start":["subagent-ledger","journal-record"],"subagent_stop":["subagent-ledger","journal-record"],"agent_error":["host-rate-marker"],"instructions_loaded":["instructions-observer"]},"cowork":{"ask":"text","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","code-graph-refresh"],"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-plumbing-writes","block-config-weakening","block-speaking-inbox-dir","block-credential-reads","rtk-wrap","design-slop","ui-route-nudge","code-graph-context","chain-nudge","ship-diff-volume","reread-guard","spawn-guard-shadow","source-first-gate","memory-recall"],"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","mcp-usage-observation","tool-result-bytes","edit-shape","comment-discipline","design-pass","spawn-guard-shadow"],"subagent_start":["subagent-ledger"],"subagent_stop":["subagent-ledger"]},"cursor":{"ask":"text","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","code-graph-refresh"],"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","mcp-usage-observation","tool-result-bytes","edit-shape","comment-discipline","design-pass"]},"cline":{"ask":"text","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","code-graph-refresh"],"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","mcp-usage-observation","tool-result-bytes","edit-shape","comment-discipline","design-pass"]},"windsurf":{"ask":"text","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","code-graph-refresh"],"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":{"ask":"text","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","code-graph-refresh"],"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","mcp-usage-observation","tool-result-bytes","edit-shape","comment-discipline","design-pass"]},"copilot":{"ask":"text","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","PostToolUseFailure":"post_tool_use","PreToolUse":"pre_tool_use","PreCompact":"pre_compact","SubagentStart":"subagent_start","SubagentStop":"subagent_stop","InstructionsLoaded":"instructions_loaded","StopFailure":"agent_error"},"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":"a1ea34a86eaabc4536ff7758681c8a89249dec6925148e96721b677b4d9de34b:111522","body_fingerprint":"6729962557eee79c6c7cda21ee5d245da8d52a4c22fbce12bdba960996db322e:21553","manifest":{"schema_version":1,"concerns":{"chat-history":{"script":"src/scripts/chat_history.ts","args":["hook-dispatch"],"fail_closed":false,"severity":"advisory","effect":"telemetry","needs_payload_bodies":["result"]},"hot-context":{"script":"src/scripts/hot_context_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"memory"},"handoff-context":{"script":"src/scripts/handoff_context_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"context"},"roadmap-progress":{"script":"src/scripts/roadmap_progress_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"formatting","needs_payload_bodies":["input"]},"onboarding-gate":{"script":"src/scripts/onboarding_gate_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"notification"},"context-hygiene":{"script":"src/scripts/context_hygiene_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"telemetry"},"verify-before-complete":{"script":"src/scripts/before_complete_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"verification","needs_payload_bodies":["input","result"]},"ship-diff-volume":{"script":"src/scripts/hooks/ship_diff_volume_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"verification","needs_payload_bodies":["input"]},"minimal-safe-diff":{"script":"src/scripts/minimal_safe_diff_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"verification","needs_payload_bodies":["input"]},"injection-scan":{"script":"src/scripts/injection_scan_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"verification","needs_payload_bodies":["input","result"]},"block-no-verify":{"script":"src/scripts/hooks/block_no_verify.ts","args":[],"fail_closed":true,"severity":"blocking","effect":"permission","needs_payload_bodies":["input"]},"block-kernel-rule-writes":{"script":"src/scripts/hooks/block_kernel_rule_writes.ts","args":[],"fail_closed":true,"severity":"blocking","effect":"permission","needs_payload_bodies":["input"]},"block-plumbing-writes":{"script":"src/scripts/hooks/block_plumbing_writes.ts","args":[],"fail_closed":true,"severity":"blocking","effect":"permission","needs_payload_bodies":["input"]},"one-question-per-ask":{"script":"src/scripts/hooks/one_question_per_ask_hook.ts","args":[],"fail_closed":false,"severity":"blocking","effect":"permission","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","effect":"permission","needs_payload_bodies":["input"]},"block-credential-reads":{"script":"src/scripts/hooks/block_credential_reads.ts","args":[],"fail_closed":false,"severity":"blocking","effect":"permission","needs_payload_bodies":["input"]},"block-config-weakening":{"script":"src/scripts/hooks/block_config_weakening.ts","args":[],"fail_closed":false,"severity":"blocking","effect":"permission","needs_payload_bodies":["input"]},"rtk-wrap":{"script":"src/scripts/hooks/rtk_wrap_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"formatting","needs_payload_bodies":["input"]},"design-slop":{"script":"src/scripts/hooks/design_slop_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"verification","needs_payload_bodies":["input"]},"design-pass":{"script":"src/scripts/hooks/design_pass_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"notification","needs_payload_bodies":["input"]},"design-pass-stop":{"script":"src/scripts/hooks/design_pass_hook.ts","args":["--slot","stop"],"fail_closed":false,"severity":"advisory","effect":"notification"},"ui-route-nudge":{"script":"src/scripts/hooks/ui_route_nudge_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"notification","needs_payload_bodies":["input"]},"suggestion-capture":{"script":"src/scripts/hooks/suggestion_capture_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"telemetry"},"chain-nudge":{"script":"src/scripts/hooks/chain_nudge_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"notification","needs_payload_bodies":["input"]},"code-graph-context":{"script":"src/scripts/hooks/code_graph_context_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"context","tools":["Grep","Glob","Read","Bash"],"needs_payload_bodies":["input"]},"memory-learn":{"script":"src/scripts/memory_learn_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"memory"},"first-run-gate":{"script":"src/scripts/first_run_gate_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"notification"},"profile-staleness":{"script":"src/scripts/profile_staleness_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"notification"},"wrapper-freshness":{"script":"src/scripts/wrapper_freshness_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"notification"},"update-notice":{"script":"src/scripts/update_notice_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"notification"},"surface-probe":{"script":"src/scripts/surface_probe_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"telemetry"},"team-review-gate":{"script":"src/scripts/team_review_gate_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"verification"},"pr-url-reminder":{"script":"src/scripts/pr_url_reminder_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"notification","needs_payload_bodies":["input","result"]},"push-settle":{"script":"src/scripts/hooks/push_settle_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"verification","needs_payload_bodies":["input","result"]},"language-mirror":{"script":"src/scripts/language_mirror_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"context"},"git-authorization":{"script":"src/scripts/git_authorization_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"verification"},"evidence-independence":{"script":"src/scripts/hooks/evidence_independence.ts","args":[],"fail_closed":false,"severity":"blocking","effect":"permission","needs_payload_bodies":["input"]},"session-canary":{"script":"src/scripts/session_canary_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"context"},"council-availability":{"script":"src/scripts/council_availability_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"verification"},"telemetry-disclosure":{"script":"src/scripts/telemetry_disclosure_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"notification"},"telemetry-flush":{"script":"src/scripts/hooks/telemetry_flush_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"telemetry"},"self-repair":{"script":"src/scripts/self_repair_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"telemetry"},"session-register":{"script":"src/scripts/session_register_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"telemetry"},"orchestration-record":{"script":"src/scripts/hooks/orchestration_record_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"telemetry","tools":["Agent","Task"],"needs_payload_bodies":["input","result"]},"telemetry-usage":{"script":"src/scripts/hooks/telemetry_usage_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"telemetry","tools":["Skill"],"needs_payload_bodies":["input"]},"mcp-usage-observation":{"script":"src/scripts/hooks/mcp_usage_observation_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"telemetry"},"delegation-nudge":{"script":"src/scripts/hooks/delegation_nudge_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"notification","nudge_rank":1},"skill-route":{"script":"src/scripts/hooks/skill_route_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"context","nudge_rank":2},"rule-inject":{"script":"src/scripts/hooks/rule_inject_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"context","needs_payload_bodies":["input"]},"obligation-settle":{"script":"src/scripts/hooks/obligation_settle_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"verification"},"end-review-nudge":{"script":"src/scripts/hooks/end_review_nudge_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"notification","skip_on_refusal_retry":true},"review-baseline":{"script":"src/scripts/hooks/review_baseline_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"telemetry"},"turn-end-gate":{"script":"src/scripts/hooks/turn_end_gate_hook.ts","args":[],"fail_closed":false,"severity":"blocking","effect":"permission"},"comment-discipline":{"script":"src/scripts/hooks/comment_discipline_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"verification","tools":["Write","Edit"],"needs_payload_bodies":["input"]},"edit-shape":{"script":"src/scripts/hooks/edit_shape_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"verification","tools":["Write"],"needs_payload_bodies":["input"]},"reread-guard":{"script":"src/scripts/hooks/reread_guard_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"verification","tools":["Read","Edit","Write"],"needs_payload_bodies":["input"]},"memory-recall":{"script":"src/scripts/hooks/memory_recall_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"memory","tools":["Bash","Edit","Write","MultiEdit","str-replace-editor","save-file","launch-process"],"needs_payload_bodies":["input"]},"session-eol":{"script":"src/scripts/hooks/session_eol_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"notification"},"interruption-ledger":{"script":"src/scripts/hooks/interruption_ledger_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"telemetry","skip_on_refusal_retry":true},"instructions-observer":{"script":"src/scripts/hooks/instructions_observer_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"telemetry"},"code-graph-refresh":{"script":"src/scripts/hooks/code_graph_refresh_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"execution"},"subagent-ledger":{"script":"src/scripts/hooks/subagent_ledger_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"telemetry"},"tool-result-bytes":{"script":"src/scripts/hooks/tool_result_bytes_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"telemetry"},"spawn-guard-shadow":{"script":"src/scripts/hooks/spawn_guard_shadow_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"telemetry","tools":["Agent","Task","SendMessage"],"needs_payload_bodies":["input","result"],"payload_fields":["name","subagent_type","to","recipient_kind","agentId"]},"host-rate-marker":{"script":"src/scripts/hooks/host_rate_marker_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"telemetry"},"source-first-gate":{"script":"src/scripts/hooks/source_first_gate_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"telemetry","needs_payload_bodies":["input"]},"journal-record":{"script":"src/scripts/hooks/journal_record_hook.ts","args":[],"fail_closed":false,"severity":"advisory","effect":"telemetry"}},"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":{"ask":"text","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","code-graph-refresh"],"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-plumbing-writes","block-config-weakening","block-speaking-inbox-dir","block-credential-reads","rtk-wrap","design-slop","ui-route-nudge","code-graph-context","chain-nudge","ship-diff-volume","reread-guard","memory-recall"],"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","mcp-usage-observation","tool-result-bytes","edit-shape","comment-discipline","design-pass"]},"claude":{"ask":"native","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","update-notice","surface-probe","session-register","review-baseline","journal-record","rule-inject","code-graph-refresh"],"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","obligation-settle","turn-end-gate","self-repair","session-register","session-eol","interruption-ledger","roadmap-progress","design-pass-stop","suggestion-capture","journal-record"],"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-plumbing-writes","block-config-weakening","block-speaking-inbox-dir","block-credential-reads","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","memory-recall"],"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","mcp-usage-observation","tool-result-bytes","edit-shape","comment-discipline","language-mirror","design-pass","journal-record","spawn-guard-shadow"],"pre_compact":["language-mirror","rule-inject","journal-record"],"subagent_start":["subagent-ledger","journal-record"],"subagent_stop":["subagent-ledger","journal-record"],"agent_error":["host-rate-marker"],"instructions_loaded":["instructions-observer"]},"cowork":{"ask":"text","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","code-graph-refresh"],"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-plumbing-writes","block-config-weakening","block-speaking-inbox-dir","block-credential-reads","rtk-wrap","design-slop","ui-route-nudge","code-graph-context","chain-nudge","ship-diff-volume","reread-guard","spawn-guard-shadow","source-first-gate","memory-recall"],"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","mcp-usage-observation","tool-result-bytes","edit-shape","comment-discipline","design-pass","spawn-guard-shadow"],"subagent_start":["subagent-ledger"],"subagent_stop":["subagent-ledger"]},"cursor":{"ask":"text","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","code-graph-refresh"],"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","mcp-usage-observation","tool-result-bytes","edit-shape","comment-discipline","design-pass"]},"cline":{"ask":"text","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","code-graph-refresh"],"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","mcp-usage-observation","tool-result-bytes","edit-shape","comment-discipline","design-pass"]},"windsurf":{"ask":"text","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","code-graph-refresh"],"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":{"ask":"text","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","code-graph-refresh"],"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","mcp-usage-observation","tool-result-bytes","edit-shape","comment-discipline","design-pass"]},"copilot":{"ask":"text","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","PostToolUseFailure":"post_tool_use","PreToolUse":"pre_tool_use","PreCompact":"pre_compact","SubagentStart":"subagent_start","SubagentStop":"subagent_stop","InstructionsLoaded":"instructions_loaded","StopFailure":"agent_error"},"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"}}}}
@@ -630,22 +630,25 @@ concerns:
630
630
  fail_closed: false
631
631
  severity: advisory
632
632
  effect: notification
633
- # `update-notice` and `update-auto-invite` were registered here on
634
- # 2026-10-20 and REMOVED the same day on a council verdict: both seats
635
- # refused the change 2/2, convergent, no split
636
- # (agents/evidence/council/lazy-concern-authority-expansion-20261020.md).
637
- # The finding is not about the concerns' quality. `fail_closed: false` and
638
- # `severity: advisory` describe failure and classification, not side
639
- # effects, and `effect: notification` means the concern tells a human
640
- # something and changes nothing else — so a session_start concern that may
641
- # initiate `upgrade --unattended`, and a stop concern that may open a
642
- # question with the user, are each an expansion of what lifecycle hooks are
643
- # permitted to DECIDE. That the invoked command keeps all its own gates is
644
- # true and beside the point: the gates constrain HOW an install happens,
645
- # never WHO may start one. The ring-0 record is a rollout switch, not
646
- # consent, so it postpones the expansion rather than bounding it.
647
- # They return in their own change, declared as authority expansions and
648
- # ratified on their own merits.
633
+ # Tells the user, at session start, that their global install is behind or
634
+ # has just moved. It installs nothing and starts nothing: a 2026-10-20
635
+ # council refused it 2/2 while it could spawn `upgrade --unattended`
636
+ # (agents/evidence/council/lazy-concern-authority-expansion-20261020.md),
637
+ # and that capability was removed rather than the effect widened (D13).
638
+ # Its writes are its own bookkeeping — a day stamp and the last version it
639
+ # reported, user-global, read by no other module (a CI assertion).
640
+ # Bound on `claude` alone: its text goes out through the user channel
641
+ # (`hooks/user_notice.ts`, `systemMessage`), which is UI-only, and claude is
642
+ # the one host with a verified field of that kind. Every other host keeps
643
+ # the CLI banner. Day-throttled, file reads only, loaded from its own chunk.
644
+ # Kill switches: `AGENT_CONFIG_NO_UPDATE_CHECK=1`, `update.mode: off`.
645
+ # `update-auto-invite` (step 4.3) is not registered.
646
+ update-notice:
647
+ script: src/scripts/update_notice_hook.ts
648
+ args: []
649
+ fail_closed: false
650
+ severity: advisory
651
+ effect: notification
649
652
  # road-to-install-path-convergence Phase 4 — duplicate-surface probe.
650
653
  # Reads src/config/surface-matrix.yml, existence-checks declared duplicate
651
654
  # classes, nudges ONCE per day (state: agents/runtime/state/
@@ -1616,7 +1619,7 @@ platforms:
1616
1619
 
1617
1620
  claude:
1618
1621
  ask: native
1619
- 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, rule-inject, code-graph-refresh]
1622
+ 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, update-notice, surface-probe, session-register, review-baseline, journal-record, rule-inject, code-graph-refresh]
1620
1623
  # `rule-inject` is bound here for ONE source: `compact`
1621
1624
  # (road-to-a-rule-carrier-that-works-outside-the-repo step 1.6). The concern
1622
1625
  # returns before reading anything on `startup`, `resume`, `clear` and
@@ -42,12 +42,12 @@ import { fileURLToPath, pathToFileURL } from 'node:url';
42
42
 
43
43
  import { hardenedSpawnEnv } from '../_lib/spawn_env.js';
44
44
  import { usableCli } from '../code_graph/refresh_cli.js';
45
- import { AUTO_REFRESH_REL, LOCK_REL, isStale, recordRefresh } from '../code_graph/refresh_lock.js';
45
+ import { hasProjectHome, projectHome } from '../code_graph/graph_home.js';
46
+ import { isStale, recordRefreshIn } from '../code_graph/refresh_lock.js';
46
47
  import { EXIT_ALLOW } from './exit_codes.js';
47
48
  import { readHookStdin } from './hook_stdin.js';
48
49
  import { is_replay_mode } from './state_io.js';
49
50
 
50
- export const CACHE_REL = path.join('agents', 'runtime', 'state', 'code-graph-v1.json');
51
51
  export const REFRESH_ARGS = ['code-graph', 'refresh', '--single-flight', '--map', '--budget-seconds', '60'];
52
52
 
53
53
  export type RefreshOutcome =
@@ -109,15 +109,18 @@ export function refreshFor(cwd: string, spawnFn: typeof spawn = spawn): RefreshO
109
109
  if (process.platform === 'win32') return 'unsupported';
110
110
  if (is_replay_mode()) return 'replay';
111
111
  const root = repoRoot(cwd);
112
- if (root === null || !fs.existsSync(path.join(root, AUTO_REFRESH_REL))) return 'not-opted-in';
112
+ // `auto-refresh on` refuses a root without a project home (ADR-299).
113
+ if (root === null || !hasProjectHome(root)) return 'not-opted-in';
114
+ const home = projectHome(root);
115
+ if (!fs.existsSync(home.autoRefreshPath)) return 'not-opted-in';
113
116
  // A repository-committed opt-in is refused before anything is written into the tree.
114
- if (anyTracked(root, [AUTO_REFRESH_REL, CACHE_REL])) return 'tracked';
117
+ if (anyTracked(root, [home.autoRefreshPath, home.cachePath].map((p) => path.relative(root, p)))) return 'tracked';
115
118
  const done = (outcome: RefreshOutcome, detail?: string): RefreshOutcome => {
116
- recordRefresh(root, { by: 'session-start', outcome, detail });
119
+ recordRefreshIn(home.stateDir, { by: 'session-start', outcome, detail });
117
120
  return outcome;
118
121
  };
119
- if (!fs.existsSync(path.join(root, CACHE_REL))) return done('no-cache');
120
- const lock = path.join(root, LOCK_REL);
122
+ if (!fs.existsSync(home.cachePath)) return done('no-cache');
123
+ const lock = home.lockPath;
121
124
  if (fs.existsSync(lock) && !isStale(lock)) return done('locked');
122
125
  const verdict = usableCli(root);
123
126
  if ('reason' in verdict) return done(verdict.reason, (verdict as { cli?: string }).cli);