@event4u/agent-config 17.0.0 → 17.2.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 (164) 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 +157 -468
  5. package/README.md +4 -3
  6. package/dist/agent-src/commands/project/analyze.md +9 -6
  7. package/dist/agent-src/commands/project/map.md +58 -0
  8. package/dist/agent-src/commands/project.md +5 -3
  9. package/dist/agent-src/contexts/execution/host-capability-manifest.md +5 -3
  10. package/dist/agent-src/skills/code-intelligence/SKILL.md +6 -0
  11. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  12. package/dist/agent-src/templates/roadmaps.md +5 -1
  13. package/dist/cli/registry.js +1 -1
  14. package/dist/cli-delegate/{chunk-IROAQ77A.js → chunk-3PK3VZHB.js} +107 -9
  15. package/dist/cli-delegate/{chunk-2SFOOFJJ.js → chunk-BZJ4Y3CI.js} +1 -1
  16. package/dist/cli-delegate/{chunk-CAL76ADI.js → chunk-CMZEKSNN.js} +52 -10
  17. package/dist/cli-delegate/{chunk-ESUNQ5XR.js → chunk-E3CFULNX.js} +22 -4
  18. package/dist/cli-delegate/{chunk-GOMILC3O.js → chunk-QBHEI5N4.js} +4 -3
  19. package/dist/cli-delegate/{chunk-SIOMDAKL.js → chunk-VYZGJLCA.js} +29 -39
  20. package/dist/cli-delegate/chunk-W5JXMF2T.js +77 -0
  21. package/dist/cli-delegate/{chunk-4SHNERBL.js → chunk-XIAPY44N.js} +1 -1
  22. package/dist/cli-delegate/{chunk-JHMMWNJ2.js → chunk-YHAPONWV.js} +1 -1
  23. package/dist/cli-delegate/cmd_conformance.js +32 -47
  24. package/dist/cli-delegate/cmd_doctor.js +4 -4
  25. package/dist/cli-delegate/cmd_doctor_neighbours.js +2 -2
  26. package/dist/cli-delegate/cmd_explain.js +1 -1
  27. package/dist/cli-delegate/cmd_export.js +6 -6
  28. package/dist/cli-delegate/cmd_fleet.js +3 -3
  29. package/dist/cli-delegate/cmd_preflight.js +3 -3
  30. package/dist/cli-delegate/cmd_prune.js +6 -6
  31. package/dist/cli-delegate/cmd_settings_migrate.js +6 -6
  32. package/dist/cli-delegate/cmd_settings_set.js +1 -1
  33. package/dist/cli-delegate/cmd_sync.js +6 -6
  34. package/dist/cli-delegate/cmd_uninstall.js +6 -6
  35. package/dist/cli-delegate/cmd_update.js +9 -13
  36. package/dist/cli-delegate/cmd_validate.js +6 -6
  37. package/dist/discovery/deprecation-report.md +1 -1
  38. package/dist/discovery/discovery-manifest.json +41 -15
  39. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  40. package/dist/discovery/discovery-manifest.summary.md +3 -3
  41. package/dist/discovery/dormancy-report.md +1 -1
  42. package/dist/discovery/orphan-report.md +1 -1
  43. package/dist/discovery/packs.json +6 -5
  44. package/dist/discovery/trust-report.md +2 -2
  45. package/dist/discovery/workspaces.json +5 -4
  46. package/dist/hooks/dispatch.js +163 -148
  47. package/dist/hooks/dispatch.sha256 +1 -1
  48. package/dist/hooks/instructions_observer.chunk.cjs +301 -0
  49. package/dist/hooks/instructions_observer.chunk.cjs.sha256 +1 -0
  50. package/dist/install/claudeRuleRewrite.js +10 -3
  51. package/dist/install/conflict.js +24 -2
  52. package/dist/install/conflictTracker.js +14 -3
  53. package/dist/install/install.mjs +222 -117
  54. package/dist/install/installThinLayer.js +1 -0
  55. package/dist/install/loggedWrites.js +142 -0
  56. package/dist/install/paths.js +12 -2
  57. package/dist/install/preserve.js +25 -4
  58. package/dist/install/txlog.js +10 -6
  59. package/dist/mcp/registry-manifest.json +3 -3
  60. package/dist/mcp/server.json +2 -2
  61. package/dist/mcp/server.mjs +33595 -22916
  62. package/dist/scripts/_lib/egress_rules.js +4 -1
  63. package/dist/scripts/_lib/identifier_redaction.js +35 -2
  64. package/dist/scripts/ai_council/seat_policy.js +7 -1
  65. package/dist/server/schemas/settings.js +1 -1
  66. package/package.json +4 -1
  67. package/src/config/ci-local-parity.yml +1 -1
  68. package/src/config/continuity-surface.json +7 -0
  69. package/src/config/evaluator-budgets.json +4 -4
  70. package/src/config/gate-coverage.yml +27 -7
  71. package/src/config/gate-violation-baselines.json +9 -3
  72. package/src/config/gitignore-block.txt +6 -0
  73. package/src/config/hook-bundle-budget.json +19 -4
  74. package/src/config/hook-token-budget.json +1 -1
  75. package/src/config/packed-binary-manifest.json +27 -0
  76. package/src/config/production-entries.json +18 -0
  77. package/src/config/release-gate-locality.yml +0 -7
  78. package/src/config/skill-body-budget.json +7 -1
  79. package/src/install/claudeRuleRewrite.ts +10 -1
  80. package/src/install/conflict.ts +24 -1
  81. package/src/install/conflictTracker.ts +18 -2
  82. package/src/install/installThinLayer.ts +6 -0
  83. package/src/install/loggedWrites.ts +148 -0
  84. package/src/install/paths.ts +11 -2
  85. package/src/install/preserve.ts +40 -4
  86. package/src/install/txlog.ts +10 -6
  87. package/src/scripts/_cli/cmd_conformance.ts +3 -2
  88. package/src/scripts/_cli/cmd_update.ts +15 -17
  89. package/src/scripts/_lib/bench_ab_complexity.ts +14 -2
  90. package/src/scripts/_lib/collector_record.ts +1 -0
  91. package/src/scripts/_lib/council_settings_block.ts +9 -2
  92. package/src/scripts/_lib/egress_rules.ts +4 -1
  93. package/src/scripts/_lib/host_capability.ts +10 -5
  94. package/src/scripts/_lib/identifier_redaction.ts +38 -2
  95. package/src/scripts/_lib/price_freshness.ts +112 -0
  96. package/src/scripts/_lib/production_reach.ts +194 -0
  97. package/src/scripts/_lib/quota_parked.ts +17 -28
  98. package/src/scripts/_lib/release_findings_ingest.ts +13 -335
  99. package/src/scripts/_lib/runtime_journal.ts +7 -7
  100. package/src/scripts/_lib/tier_downshift_verdict.ts +81 -35
  101. package/src/scripts/ai_council/chairman.ts +5 -2
  102. package/src/scripts/ai_council/clients.ts +4 -3
  103. package/src/scripts/ai_council/free_hand_shadow.ts +24 -12
  104. package/src/scripts/ai_council/free_route_catalog.ts +142 -5
  105. package/src/scripts/ai_council/free_route_client.ts +4 -0
  106. package/src/scripts/ai_council/hand_payload.ts +115 -7
  107. package/src/scripts/ai_council/orchestrator.ts +7 -10
  108. package/src/scripts/ai_council/route_chooser.ts +1 -1
  109. package/src/scripts/ai_council/route_member.ts +66 -4
  110. package/src/scripts/ai_council/seat_policy.ts +8 -1
  111. package/src/scripts/ai_council/self_hosted_probe.ts +327 -0
  112. package/src/scripts/ai_council/status_surface.ts +2 -0
  113. package/src/scripts/ask_transport.ts +137 -15
  114. package/src/scripts/check_finding_dispositions.ts +25 -71
  115. package/src/scripts/check_release_pr_shape.ts +3 -3
  116. package/src/scripts/check_step_production_reach.ts +257 -0
  117. package/src/scripts/code_graph/build.ts +210 -10
  118. package/src/scripts/code_graph/cli.ts +168 -46
  119. package/src/scripts/code_graph/detect.ts +5 -4
  120. package/src/scripts/code_graph/docs_layer.ts +57 -0
  121. package/src/scripts/code_graph/extract.ts +58 -13
  122. package/src/scripts/code_graph/extract_more.ts +314 -0
  123. package/src/scripts/code_graph/laravel_overlay.ts +454 -0
  124. package/src/scripts/code_graph/map.ts +846 -0
  125. package/src/scripts/code_graph/map_model.ts +977 -0
  126. package/src/scripts/code_graph/map_verify.ts +140 -0
  127. package/src/scripts/code_graph/map_viewer/viewer.css +278 -0
  128. package/src/scripts/code_graph/map_viewer/viewer.js +756 -0
  129. package/src/scripts/code_graph/scip_reader.ts +201 -0
  130. package/src/scripts/code_graph/sqlite_store.ts +8 -1
  131. package/src/scripts/code_graph/types.ts +81 -15
  132. package/src/scripts/code_graph/validate.ts +16 -26
  133. package/src/scripts/code_graph/verbs.ts +7 -0
  134. package/src/scripts/council_cli.ts +10 -8
  135. package/src/scripts/hook_chunks.mjs +7 -0
  136. package/src/scripts/hook_manifest.json +1 -1
  137. package/src/scripts/hook_manifest.yaml +23 -0
  138. package/src/scripts/hooks/dispatch_hook.ts +4 -4
  139. package/src/scripts/hooks/instructions_observer_hook.ts +25 -6
  140. package/src/scripts/hooks/lazy_concern.ts +4 -0
  141. package/src/scripts/hooks/payload_stub.ts +27 -0
  142. package/src/scripts/hooks/spawn_guard_shadow_hook.ts +29 -70
  143. package/src/scripts/hooks/subagent_ledger_hook.ts +80 -0
  144. package/src/scripts/install-hooks.sh +5 -0
  145. package/src/scripts/install.ts +2 -2
  146. package/src/scripts/lint_agents_layout.ts +2 -0
  147. package/src/scripts/lint_decision_classes.ts +34 -0
  148. package/src/scripts/lint_hook_manifest.ts +25 -0
  149. package/src/scripts/lint_roadmap_blockers.ts +52 -3
  150. package/src/scripts/mcp_server/consumer_tool_catalog.json +53 -6
  151. package/src/scripts/mcp_server/graph_tools.ts +73 -1
  152. package/src/scripts/mcp_server/tools.ts +19 -36
  153. package/src/scripts/release.ts +5 -9
  154. package/src/scripts/release_drill.ts +11 -165
  155. package/src/scripts/release_publication.ts +0 -9
  156. package/src/scripts/report_production_reach.ts +35 -0
  157. package/src/scripts/worker_reuse_shadow_report.ts +399 -1
  158. package/src/server/schemas/settings.ts +1 -1
  159. package/src/vendor/grammars/README.md +10 -5
  160. package/src/vendor/grammars/tree-sitter-go.wasm +0 -0
  161. package/src/vendor/grammars/tree-sitter-java.wasm +0 -0
  162. package/src/vendor/grammars/tree-sitter-python.wasm +0 -0
  163. package/dist/cli-delegate/chunk-A4QJ6ENT.js +0 -50
  164. /package/dist/cli-delegate/{chunk-E6XNBVE4.js → chunk-KR5ZIFPO.js} +0 -0
@@ -0,0 +1,301 @@
1
+ #!/usr/bin/env tsx
2
+ const __acChunkMetaUrl = require('node:url').pathToFileURL(__filename).href; const __acChunkMeta = { url: __acChunkMetaUrl, dirname: __dirname, filename: __filename };
3
+ "use strict";
4
+ var __create = Object.create;
5
+ var __defProp = Object.defineProperty;
6
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
7
+ var __getOwnPropNames = Object.getOwnPropertyNames;
8
+ var __getProtoOf = Object.getPrototypeOf;
9
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
10
+ var __export = (target, all) => {
11
+ for (var name in all)
12
+ __defProp(target, name, { get: all[name], enumerable: true });
13
+ };
14
+ var __copyProps = (to, from, except, desc) => {
15
+ if (from && typeof from === "object" || typeof from === "function") {
16
+ for (let key of __getOwnPropNames(from))
17
+ if (!__hasOwnProp.call(to, key) && key !== except)
18
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
19
+ }
20
+ return to;
21
+ };
22
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
23
+ // If the importer is in node compatibility mode or this is not an ESM
24
+ // file that has been converted to a CommonJS file using a Babel-
25
+ // compatible transform (i.e. "__esModule" has not been set), then set
26
+ // "default" to the CommonJS "module.exports" for node compatibility.
27
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
28
+ mod
29
+ ));
30
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
31
+
32
+ // src/scripts/hooks/instructions_observer_hook.ts
33
+ var instructions_observer_hook_exports = {};
34
+ __export(instructions_observer_hook_exports, {
35
+ KEEP_SESSIONS: () => KEEP_SESSIONS,
36
+ KILL_SWITCH_ENV: () => KILL_SWITCH_ENV,
37
+ MAX_SESSION_BYTES: () => MAX_SESSION_BYTES,
38
+ arrivalsDir: () => arrivalsDir,
39
+ main: () => main,
40
+ processEnvelope: () => processEnvelope
41
+ });
42
+ module.exports = __toCommonJS(instructions_observer_hook_exports);
43
+ var fs2 = __toESM(require("node:fs"), 1);
44
+ var path2 = __toESM(require("node:path"), 1);
45
+ var import_node_url = require("node:url");
46
+
47
+ // src/scripts/_lib/user_global_paths.ts
48
+ var os = __toESM(require("node:os"), 1);
49
+ var path = __toESM(require("node:path"), 1);
50
+ var EVENT4U_HOME_ENV = "EVENT4U_CONFIG_HOME";
51
+ var DEFAULT_EVENT4U_ROOT_RELATIVE = path.join(".event4u", "agent-config");
52
+ var LEGACY_XDG_ROOT_RELATIVE = path.join(".config", "agent-config");
53
+ function expanduser(p) {
54
+ if (p === "~") {
55
+ return os.homedir();
56
+ }
57
+ if (p.startsWith("~/") || process.platform === "win32" && p.startsWith("~\\")) {
58
+ return path.join(os.homedir(), p.slice(2));
59
+ }
60
+ return p;
61
+ }
62
+ function event4u_root(env) {
63
+ const env_map = env ?? process.env;
64
+ const override = env_map[EVENT4U_HOME_ENV];
65
+ if (override) {
66
+ return expanduser(override);
67
+ }
68
+ return path.join(os.homedir(), DEFAULT_EVENT4U_ROOT_RELATIVE);
69
+ }
70
+
71
+ // src/scripts/_lib/instructions_loaded_event.ts
72
+ var ID_SHAPE_RE = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
73
+ var isSessionFile = (f) => f.endsWith(".jsonl") && ID_SHAPE_RE.test(f.slice(0, -6));
74
+ var idShaped = (v) => typeof v === "string" && ID_SHAPE_RE.test(v) ? v : null;
75
+ function captureInstructionsLoaded(payload, ts, home, env) {
76
+ const p = typeof payload === "object" && payload !== null && !Array.isArray(payload) ? payload : {};
77
+ const raw = String(p["file_path"] ?? "").replace(/\\/g, "/");
78
+ const norm = /^([A-Za-z]:)?\//.test(raw) && !/\/\.{0,2}\//.test(raw) ? raw : "";
79
+ const h = home.replace(/\\/g, "/").replace(/\/+$/, "");
80
+ return {
81
+ v: 2,
82
+ ts,
83
+ agent: idShaped(env["AI_AGENT"]),
84
+ launch: idShaped(env["CLAUDE_CODE_ENTRYPOINT"]),
85
+ session: idShaped(p["session_id"]),
86
+ name: idShaped(p["hook_event_name"]),
87
+ reason: idShaped(p["load_reason"]),
88
+ file: idShaped(norm.slice(norm.lastIndexOf("/") + 1)),
89
+ rules: norm.includes("/.claude/rules/"),
90
+ user: h !== "" && norm.startsWith(`${h}/.claude/`)
91
+ };
92
+ }
93
+
94
+ // src/scripts/hooks/state_io.ts
95
+ var REPLAY_ENV_VAR = "AGENT_CONFIG_REPLAY";
96
+ function is_replay_mode() {
97
+ return (process.env[REPLAY_ENV_VAR] ?? "").trim() === "1";
98
+ }
99
+
100
+ // src/scripts/hooks/hook_stdin.ts
101
+ var tty = __toESM(require("node:tty"), 1);
102
+
103
+ // src/scripts/_lib/stdin.ts
104
+ var fs = __toESM(require("node:fs"), 1);
105
+ var CHUNK = 64 * 1024;
106
+ var RETRY_SLEEP_MS = 5;
107
+ var MAX_RETRIES = 2e3;
108
+ function _sleepSync(ms) {
109
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
110
+ }
111
+ function readStdinText(fd = 0, opts = {}) {
112
+ const chunks = [];
113
+ const buf = Buffer.alloc(CHUNK);
114
+ let retries = 0;
115
+ let got_any = false;
116
+ const first_byte_deadline = opts.firstByteTimeoutMs === void 0 ? null : Date.now() + opts.firstByteTimeoutMs;
117
+ for (; ; ) {
118
+ let read;
119
+ try {
120
+ read = fs.readSync(fd, buf, 0, CHUNK, null);
121
+ retries = 0;
122
+ } catch (exc) {
123
+ const code = exc.code;
124
+ if (code === "EAGAIN") {
125
+ if (!got_any && first_byte_deadline !== null && Date.now() >= first_byte_deadline) {
126
+ return "";
127
+ }
128
+ retries += 1;
129
+ if (retries > MAX_RETRIES) {
130
+ throw new Error(
131
+ `readStdinText: stdin stayed unreadable across ${String(MAX_RETRIES)} retries (~${String(MAX_RETRIES * RETRY_SLEEP_MS / 1e3)}s). Refusing to report an empty read as empty input.`
132
+ );
133
+ }
134
+ _sleepSync(RETRY_SLEEP_MS);
135
+ continue;
136
+ }
137
+ if (code === "EOF") break;
138
+ throw exc;
139
+ }
140
+ if (read === 0) break;
141
+ got_any = true;
142
+ chunks.push(Buffer.from(buf.subarray(0, read)));
143
+ }
144
+ return Buffer.concat(chunks).toString("utf-8");
145
+ }
146
+
147
+ // src/scripts/hooks/hook_stdin.ts
148
+ var OVERRIDE_KEY = /* @__PURE__ */ Symbol.for("agent-config.hookStdinOverride");
149
+ function host() {
150
+ return globalThis;
151
+ }
152
+ var HOOK_FIRST_BYTE_TIMEOUT_MS = 25;
153
+ function readFd0ToEnd() {
154
+ void process.stdin;
155
+ return readStdinText(0, { firstByteTimeoutMs: HOOK_FIRST_BYTE_TIMEOUT_MS });
156
+ }
157
+ function readHookStdin() {
158
+ const override = host()[OVERRIDE_KEY];
159
+ if (override !== null && override !== void 0) return override;
160
+ try {
161
+ if (tty.isatty(0)) return "";
162
+ return readFd0ToEnd();
163
+ } catch {
164
+ return "";
165
+ }
166
+ }
167
+
168
+ // src/scripts/hooks/exit_codes.ts
169
+ var EXIT_ALLOW = 0;
170
+ var EXIT_BLOCK = 1;
171
+ var EXIT_WARN = 2;
172
+ var EXIT_ERROR = 3;
173
+ var EXIT_CODES = Object.freeze([
174
+ Object.freeze({
175
+ code: EXIT_ALLOW,
176
+ name: "allow",
177
+ meaning: "no objection; the dispatcher passes the call through",
178
+ owner: "every concern \u2014 the default verdict",
179
+ authorizedBy: "nothing; allowing needs no authority"
180
+ }),
181
+ Object.freeze({
182
+ code: EXIT_BLOCK,
183
+ name: "block",
184
+ meaning: "refuse the call; the dispatcher lowers this onto the host deny channel",
185
+ owner: "a concern declared `severity: blocking` in hook_manifest.yaml",
186
+ authorizedBy: "the manifest entry plus its row in the BLOCKING_ALLOWLIST of tests/hooks/concern_severity.test.ts \u2014 an advisory concern emitting this is downgraded to warn by dispatch_hook._is_advisory"
187
+ }),
188
+ Object.freeze({
189
+ code: EXIT_WARN,
190
+ name: "warn",
191
+ meaning: "advisory; the dispatcher exits 0 and surfaces the reason",
192
+ owner: "any concern",
193
+ authorizedBy: "nothing; warning is the ceiling for an advisory concern and is always available to a blocking one"
194
+ }),
195
+ Object.freeze({
196
+ code: EXIT_ERROR,
197
+ name: "error",
198
+ meaning: "the concern crashed, timed out, or could not decide \u2014 any rc >= 3. The dispatcher resolves it by the concern`s declared severity, never by the number itself",
199
+ owner: "no concern emits this on purpose; the runtime does",
200
+ authorizedBy: "hook_manifest.yaml `severity` alone \u2014 blocking refuses, anything else fails open; `fail_closed` is no longer read on this branch. See docs/contracts/hook-architecture-v1.md \xA7 Exit-code semantics"
201
+ })
202
+ ]);
203
+
204
+ // src/scripts/hooks/instructions_observer_hook.ts
205
+ var KILL_SWITCH_ENV = "AGENT_CONFIG_INSTRUCTIONS_OBSERVER";
206
+ var KEEP_SESSIONS = 50;
207
+ var MAX_SESSION_BYTES = 256 * 1024;
208
+ var C = fs2.constants;
209
+ var NOFOLLOW = C.O_NOFOLLOW ?? 0;
210
+ var APPEND_NOFOLLOW = C.O_WRONLY | C.O_APPEND | C.O_CREAT | C.O_NONBLOCK | NOFOLLOW;
211
+ var TRUNC_NOFOLLOW = C.O_WRONLY | C.O_TRUNC | C.O_CREAT | C.O_NONBLOCK | NOFOLLOW;
212
+ function writePrivate(file, text, flags, cap = Infinity) {
213
+ const fd = fs2.openSync(file, flags, 384);
214
+ try {
215
+ const st = fs2.fstatSync(fd);
216
+ if (!st.isFile() || (st.mode & 63) !== 0) throw new Error("EREFUSED");
217
+ if (st.size < cap && fs2.writeSync(fd, text) !== text.length) throw new Error("ESHORT");
218
+ } finally {
219
+ fs2.closeSync(fd);
220
+ }
221
+ }
222
+ function privateDir(dir) {
223
+ fs2.mkdirSync(dir, { recursive: true, mode: 448 });
224
+ const st = fs2.lstatSync(dir);
225
+ const uid = process.getuid?.();
226
+ if (!st.isDirectory() || (st.mode & 63) !== 0 || uid !== void 0 && st.uid !== uid) throw new Error("EREFUSED_DIR");
227
+ }
228
+ function arrivalsDir(env = process.env) {
229
+ return path2.join(event4u_root(env), "runtime", "arrivals");
230
+ }
231
+ function prune(dir) {
232
+ const files = [];
233
+ for (const f of fs2.readdirSync(dir)) {
234
+ if (!isSessionFile(f)) continue;
235
+ try {
236
+ const st = fs2.lstatSync(path2.join(dir, f));
237
+ if (st.isFile()) files.push({ f, t: st.mtimeMs });
238
+ } catch {
239
+ }
240
+ }
241
+ files.sort((a, b) => b.t - a.t || (a.f < b.f ? -1 : 1));
242
+ for (const { f } of files.slice(KEEP_SESSIONS)) fs2.rmSync(path2.join(dir, f), { force: true });
243
+ }
244
+ function processEnvelope(raw, env = process.env) {
245
+ let dir = "";
246
+ try {
247
+ if (env[KILL_SWITCH_ENV] === "off" || is_replay_mode()) return EXIT_ALLOW;
248
+ dir = arrivalsDir(env);
249
+ let parsed = null;
250
+ try {
251
+ parsed = JSON.parse(raw);
252
+ } catch {
253
+ }
254
+ const envelope = parsed ?? {};
255
+ const inner = envelope["payload"];
256
+ const cap = captureInstructionsLoaded(typeof inner === "object" && inner !== null ? inner : envelope, (/* @__PURE__ */ new Date()).toISOString(), env["HOME"] ?? "", env);
257
+ if (cap.session === null) return EXIT_ALLOW;
258
+ privateDir(dir);
259
+ writePrivate(path2.join(dir, `${cap.session}.jsonl`), `${JSON.stringify(cap)}
260
+ `, APPEND_NOFOLLOW, MAX_SESSION_BYTES);
261
+ prune(dir);
262
+ } catch (e) {
263
+ try {
264
+ const code = String(e.code ?? e.message);
265
+ if (dir) writePrivate(`${dir}.last-error`, `${(/* @__PURE__ */ new Date()).toISOString()} ${code}
266
+ `, TRUNC_NOFOLLOW);
267
+ } catch {
268
+ }
269
+ }
270
+ return EXIT_ALLOW;
271
+ }
272
+ function main() {
273
+ try {
274
+ return processEnvelope(readHookStdin());
275
+ } catch {
276
+ return EXIT_ALLOW;
277
+ }
278
+ }
279
+ function _isCliEntry() {
280
+ if (true) {
281
+ return false;
282
+ }
283
+ if (process.argv[1] === void 0) return false;
284
+ const argvUrl = (0, import_node_url.pathToFileURL)(path2.resolve(process.argv[1])).href;
285
+ if (__acChunkMetaUrl === argvUrl) return true;
286
+ try {
287
+ return fs2.realpathSync((0, import_node_url.fileURLToPath)(__acChunkMetaUrl)) === fs2.realpathSync(path2.resolve(process.argv[1]));
288
+ } catch {
289
+ return false;
290
+ }
291
+ }
292
+ if (_isCliEntry()) process.exit(main());
293
+ // Annotate the CommonJS export names for ESM import in node:
294
+ 0 && (module.exports = {
295
+ KEEP_SESSIONS,
296
+ KILL_SWITCH_ENV,
297
+ MAX_SESSION_BYTES,
298
+ arrivalsDir,
299
+ main,
300
+ processEnvelope
301
+ });
@@ -0,0 +1 @@
1
+ fd1fae855375fc9885203e448f92e2a0b9f74a14cf7f35bf255bcaff391736bb instructions_observer.chunk.cjs
@@ -46,6 +46,9 @@
46
46
  import * as fs from 'node:fs';
47
47
  import * as path from 'node:path';
48
48
  import { _claude_paths_plan } from './claudePathsPlan.js';
49
+ // Re-exported for `install.ts`, which sits past the source-size ceiling and so
50
+ // reaches it through the namespace it already imports instead of a new line.
51
+ export { onlyDeployed } from './loggedWrites.js';
49
52
  import { parseFrontmatter } from './ruleInScope.js';
50
53
  /**
51
54
  * Frontmatter keys the rewrite must carry across, and why each one.
@@ -109,8 +112,8 @@ export function _withPreservedKeys(rendered, original) {
109
112
  * extraction and never up through a baseline raise. So the caller gets one call
110
113
  * and a list of strings.
111
114
  */
112
- export function rewriteAndReport(rulesDir, quiet, info, warn, wrappers, preserved = new Set()) {
113
- const result = rewriteClaudeRules(rulesDir, preserved);
115
+ export function rewriteAndReport(rulesDir, quiet, info, warn, wrappers, preserved = new Set(), onWrite) {
116
+ const result = rewriteClaudeRules(rulesDir, preserved, onWrite);
114
117
  // The flat-command wrapper report rides along rather than sitting at the
115
118
  // call site: `install.ts` is thousands of lines past
116
119
  // `check_source_size_budget`'s ceiling, and this module is the one place
@@ -205,8 +208,11 @@ export function renderClaudeRule(sourceText) {
205
208
  * disappearing from the frontmatter.
206
209
  *
207
210
  * Returns counts rather than printing. The caller owns the reporting surface.
211
+ * `onWrite` receives each rewritten path, so the installer can log it: the
212
+ * transaction log is read back as proof the bytes on disk are ours, and a
213
+ * write it never saw would leave every rewritten rule unprovable.
208
214
  */
209
- export function rewriteClaudeRules(rulesDir, preserved = new Set()) {
215
+ export function rewriteClaudeRules(rulesDir, preserved = new Set(), onWrite) {
210
216
  const result = { rewritten: 0, scoped: [], dropped: [], failed: [] };
211
217
  let entries;
212
218
  try {
@@ -258,6 +264,7 @@ export function rewriteClaudeRules(rulesDir, preserved = new Set()) {
258
264
  });
259
265
  continue;
260
266
  }
267
+ onWrite?.(full);
261
268
  result.rewritten += 1;
262
269
  }
263
270
  const stem = name.slice(0, -3);
@@ -16,7 +16,8 @@
16
16
  */
17
17
  import { existsSync } from 'node:fs';
18
18
  import { sha256File } from './plan.js';
19
- import { isLedgerMigration } from './preserve.js';
19
+ import { loggedWriteDigests, wroteTheseBytes } from './loggedWrites.js';
20
+ import { isLedgerMigration, logProofApplies, sidecarPathFor } from './preserve.js';
20
21
  import { classifyOwnership, ledgerListedPaths, recordedHashesWithLedger, } from './recordedOwnership.js';
21
22
  /**
22
23
  * Decide what to do with a single planned target.
@@ -161,8 +162,10 @@ export const CONFLICT_BATCH_THRESHOLD = 5;
161
162
  *
162
163
  * `recorded` is injectable for tests; by default it is read from the
163
164
  * manifest at `plan.root`, with the user-scoped ownership ledger laid over it.
165
+ * `logged` likewise; by default it is the install transaction log, opened only
166
+ * for an entry `logProofApplies` to.
164
167
  */
165
- export function computeConflicts(plan, recordedOverride) {
168
+ export function computeConflicts(plan, recordedOverride, loggedOverride) {
166
169
  // Force returns before the manifest is read. As a default parameter the
167
170
  // map was built at call entry and discarded on the next line, so every
168
171
  // force-mode plan paid a read and a YAML parse for nothing.
@@ -173,6 +176,7 @@ export function computeConflicts(plan, recordedOverride) {
173
176
  // digests never reaches the branch that needs this, and an unconditional
174
177
  // read would charge every plan for an answer most of them discard.
175
178
  let ledgerFiles = null;
179
+ let logged;
176
180
  const ledgerLists = (p) => {
177
181
  ledgerFiles ??= ledgerListedPaths();
178
182
  return ledgerFiles.has(p);
@@ -197,6 +201,24 @@ export function computeConflicts(plan, recordedOverride) {
197
201
  const ownership = classifyOwnership(recorded.get(entry.path), onDisk);
198
202
  if (ownership === 'recorded-unchanged')
199
203
  continue;
204
+ // The writer's transaction-log proof, under the writer's own
205
+ // condition (`logProofApplies`): where it holds and the log records
206
+ // these bytes, the writer replaces the file, so the preview must
207
+ // not name it.
208
+ const recordedSha = recorded.get(entry.path);
209
+ const unproven = {
210
+ exists: true,
211
+ recordedSha256: recordedSha,
212
+ onDiskSha256: onDisk,
213
+ force: false,
214
+ ledgerListed: ledgerLists(entry.path),
215
+ recordedIsStaged: typeof recordedSha === 'string' && recordedSha === recorded.get(sidecarPathFor(entry.path)),
216
+ };
217
+ if (logProofApplies(unproven)) {
218
+ logged ??= loggedOverride ?? loggedWriteDigests();
219
+ if (wroteTheseBytes(entry.path, onDisk, logged))
220
+ continue;
221
+ }
200
222
  if (ownership === 'unknown' && plan.policy.knownPaths.has(entry.path))
201
223
  continue;
202
224
  // CANDIDACY, not the verdict, and it is computed BEFORE the
@@ -21,7 +21,8 @@ import * as fs from 'node:fs';
21
21
  import * as os from 'node:os';
22
22
  import * as path from 'node:path';
23
23
  import { mkdirp, pathExists, resolvePath, sha256OfFile } from './fsPrimitives.js';
24
- import { EXIT_COMPLETED_WITH_CONFLICTS, conflictSummaryMessage, decideDeployWrite, foreignSidecarMessage, isLedgerMigration, migrationPreservedMessage, preservedFileMessage, sidecarPathFor, } from './preserve.js';
24
+ import { EXIT_COMPLETED_WITH_CONFLICTS, conflictSummaryMessage, decideDeployWrite, foreignSidecarMessage, isLedgerMigration, logProofApplies, migrationPreservedMessage, preservedFileMessage, sidecarPathFor, } from './preserve.js';
25
+ import { loggedWriteDigests, wroteTheseBytes } from './loggedWrites.js';
25
26
  import { ledgerListedPaths, recordedHashesWithLedger } from './recordedOwnership.js';
26
27
  /**
27
28
  * Build a tracker bound to one installer's reporting surface.
@@ -37,6 +38,7 @@ export function createConflictTracker(host) {
37
38
  root: null,
38
39
  recorded: null,
39
40
  ledgerFiles: null,
41
+ logged: null,
40
42
  preserved: [],
41
43
  migrated: new Set(),
42
44
  staged: new Map(),
@@ -210,6 +212,7 @@ export function createConflictTracker(host) {
210
212
  conflictState.root = root;
211
213
  conflictState.recorded = null;
212
214
  conflictState.ledgerFiles = null;
215
+ conflictState.logged = null;
213
216
  conflictState.preserved = [];
214
217
  conflictState.migrated = new Set();
215
218
  conflictState.staged = new Map();
@@ -222,13 +225,21 @@ export function createConflictTracker(host) {
222
225
  */
223
226
  resolve(target, force, would) {
224
227
  const exists = pathExists(target);
225
- const base = {
228
+ const recordedSha256 = exists ? recordedHashFor(target) : undefined;
229
+ const unproven = {
226
230
  exists,
227
- recordedSha256: exists ? recordedHashFor(target) : undefined,
231
+ recordedSha256,
228
232
  onDiskSha256: exists ? sha256OfFile(target) : null,
229
233
  force,
230
234
  ledgerListed: exists && ledgerLists(target),
235
+ recordedIsStaged: typeof recordedSha256 === 'string' && recordedSha256 === recordedHashFor(sidecarPathFor(target)),
231
236
  };
237
+ // The log is opened only where the record alone would preserve
238
+ // without cause, and read once per run: this run's own appends
239
+ // cannot prove a file it has not reached yet.
240
+ const loggedWrite = logProofApplies(unproven) &&
241
+ wroteTheseBytes(target, unproven.onDiskSha256, (conflictState.logged ??= loggedWriteDigests()));
242
+ const base = { ...unproven, loggedWrite };
232
243
  // The packaged digest costs a temp write and a tag, so it is
233
244
  // computed only for the targets that can consume it. On a tree
234
245
  // where every ledger-listed path carries a digest — which is every