@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.
- package/.augment-plugin/marketplace.json +3 -3
- package/.augment-plugin/plugin.json +1 -1
- package/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +157 -468
- package/README.md +4 -3
- package/dist/agent-src/commands/project/analyze.md +9 -6
- package/dist/agent-src/commands/project/map.md +58 -0
- package/dist/agent-src/commands/project.md +5 -3
- package/dist/agent-src/contexts/execution/host-capability-manifest.md +5 -3
- package/dist/agent-src/skills/code-intelligence/SKILL.md +6 -0
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/roadmaps.md +5 -1
- package/dist/cli/registry.js +1 -1
- package/dist/cli-delegate/{chunk-IROAQ77A.js → chunk-3PK3VZHB.js} +107 -9
- package/dist/cli-delegate/{chunk-2SFOOFJJ.js → chunk-BZJ4Y3CI.js} +1 -1
- package/dist/cli-delegate/{chunk-CAL76ADI.js → chunk-CMZEKSNN.js} +52 -10
- package/dist/cli-delegate/{chunk-ESUNQ5XR.js → chunk-E3CFULNX.js} +22 -4
- package/dist/cli-delegate/{chunk-GOMILC3O.js → chunk-QBHEI5N4.js} +4 -3
- package/dist/cli-delegate/{chunk-SIOMDAKL.js → chunk-VYZGJLCA.js} +29 -39
- package/dist/cli-delegate/chunk-W5JXMF2T.js +77 -0
- package/dist/cli-delegate/{chunk-4SHNERBL.js → chunk-XIAPY44N.js} +1 -1
- package/dist/cli-delegate/{chunk-JHMMWNJ2.js → chunk-YHAPONWV.js} +1 -1
- package/dist/cli-delegate/cmd_conformance.js +32 -47
- package/dist/cli-delegate/cmd_doctor.js +4 -4
- package/dist/cli-delegate/cmd_doctor_neighbours.js +2 -2
- package/dist/cli-delegate/cmd_explain.js +1 -1
- package/dist/cli-delegate/cmd_export.js +6 -6
- package/dist/cli-delegate/cmd_fleet.js +3 -3
- package/dist/cli-delegate/cmd_preflight.js +3 -3
- package/dist/cli-delegate/cmd_prune.js +6 -6
- package/dist/cli-delegate/cmd_settings_migrate.js +6 -6
- package/dist/cli-delegate/cmd_settings_set.js +1 -1
- package/dist/cli-delegate/cmd_sync.js +6 -6
- package/dist/cli-delegate/cmd_uninstall.js +6 -6
- package/dist/cli-delegate/cmd_update.js +9 -13
- package/dist/cli-delegate/cmd_validate.js +6 -6
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +41 -15
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +3 -3
- package/dist/discovery/dormancy-report.md +1 -1
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +6 -5
- package/dist/discovery/trust-report.md +2 -2
- package/dist/discovery/workspaces.json +5 -4
- package/dist/hooks/dispatch.js +163 -148
- package/dist/hooks/dispatch.sha256 +1 -1
- package/dist/hooks/instructions_observer.chunk.cjs +301 -0
- package/dist/hooks/instructions_observer.chunk.cjs.sha256 +1 -0
- package/dist/install/claudeRuleRewrite.js +10 -3
- package/dist/install/conflict.js +24 -2
- package/dist/install/conflictTracker.js +14 -3
- package/dist/install/install.mjs +222 -117
- package/dist/install/installThinLayer.js +1 -0
- package/dist/install/loggedWrites.js +142 -0
- package/dist/install/paths.js +12 -2
- package/dist/install/preserve.js +25 -4
- package/dist/install/txlog.js +10 -6
- package/dist/mcp/registry-manifest.json +3 -3
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +33595 -22916
- package/dist/scripts/_lib/egress_rules.js +4 -1
- package/dist/scripts/_lib/identifier_redaction.js +35 -2
- package/dist/scripts/ai_council/seat_policy.js +7 -1
- package/dist/server/schemas/settings.js +1 -1
- package/package.json +4 -1
- package/src/config/ci-local-parity.yml +1 -1
- package/src/config/continuity-surface.json +7 -0
- package/src/config/evaluator-budgets.json +4 -4
- package/src/config/gate-coverage.yml +27 -7
- package/src/config/gate-violation-baselines.json +9 -3
- package/src/config/gitignore-block.txt +6 -0
- package/src/config/hook-bundle-budget.json +19 -4
- package/src/config/hook-token-budget.json +1 -1
- package/src/config/packed-binary-manifest.json +27 -0
- package/src/config/production-entries.json +18 -0
- package/src/config/release-gate-locality.yml +0 -7
- package/src/config/skill-body-budget.json +7 -1
- package/src/install/claudeRuleRewrite.ts +10 -1
- package/src/install/conflict.ts +24 -1
- package/src/install/conflictTracker.ts +18 -2
- package/src/install/installThinLayer.ts +6 -0
- package/src/install/loggedWrites.ts +148 -0
- package/src/install/paths.ts +11 -2
- package/src/install/preserve.ts +40 -4
- package/src/install/txlog.ts +10 -6
- package/src/scripts/_cli/cmd_conformance.ts +3 -2
- package/src/scripts/_cli/cmd_update.ts +15 -17
- package/src/scripts/_lib/bench_ab_complexity.ts +14 -2
- package/src/scripts/_lib/collector_record.ts +1 -0
- package/src/scripts/_lib/council_settings_block.ts +9 -2
- package/src/scripts/_lib/egress_rules.ts +4 -1
- package/src/scripts/_lib/host_capability.ts +10 -5
- package/src/scripts/_lib/identifier_redaction.ts +38 -2
- package/src/scripts/_lib/price_freshness.ts +112 -0
- package/src/scripts/_lib/production_reach.ts +194 -0
- package/src/scripts/_lib/quota_parked.ts +17 -28
- package/src/scripts/_lib/release_findings_ingest.ts +13 -335
- package/src/scripts/_lib/runtime_journal.ts +7 -7
- package/src/scripts/_lib/tier_downshift_verdict.ts +81 -35
- package/src/scripts/ai_council/chairman.ts +5 -2
- package/src/scripts/ai_council/clients.ts +4 -3
- package/src/scripts/ai_council/free_hand_shadow.ts +24 -12
- package/src/scripts/ai_council/free_route_catalog.ts +142 -5
- package/src/scripts/ai_council/free_route_client.ts +4 -0
- package/src/scripts/ai_council/hand_payload.ts +115 -7
- package/src/scripts/ai_council/orchestrator.ts +7 -10
- package/src/scripts/ai_council/route_chooser.ts +1 -1
- package/src/scripts/ai_council/route_member.ts +66 -4
- package/src/scripts/ai_council/seat_policy.ts +8 -1
- package/src/scripts/ai_council/self_hosted_probe.ts +327 -0
- package/src/scripts/ai_council/status_surface.ts +2 -0
- package/src/scripts/ask_transport.ts +137 -15
- package/src/scripts/check_finding_dispositions.ts +25 -71
- package/src/scripts/check_release_pr_shape.ts +3 -3
- package/src/scripts/check_step_production_reach.ts +257 -0
- package/src/scripts/code_graph/build.ts +210 -10
- package/src/scripts/code_graph/cli.ts +168 -46
- package/src/scripts/code_graph/detect.ts +5 -4
- package/src/scripts/code_graph/docs_layer.ts +57 -0
- package/src/scripts/code_graph/extract.ts +58 -13
- package/src/scripts/code_graph/extract_more.ts +314 -0
- package/src/scripts/code_graph/laravel_overlay.ts +454 -0
- package/src/scripts/code_graph/map.ts +846 -0
- package/src/scripts/code_graph/map_model.ts +977 -0
- package/src/scripts/code_graph/map_verify.ts +140 -0
- package/src/scripts/code_graph/map_viewer/viewer.css +278 -0
- package/src/scripts/code_graph/map_viewer/viewer.js +756 -0
- package/src/scripts/code_graph/scip_reader.ts +201 -0
- package/src/scripts/code_graph/sqlite_store.ts +8 -1
- package/src/scripts/code_graph/types.ts +81 -15
- package/src/scripts/code_graph/validate.ts +16 -26
- package/src/scripts/code_graph/verbs.ts +7 -0
- package/src/scripts/council_cli.ts +10 -8
- package/src/scripts/hook_chunks.mjs +7 -0
- package/src/scripts/hook_manifest.json +1 -1
- package/src/scripts/hook_manifest.yaml +23 -0
- package/src/scripts/hooks/dispatch_hook.ts +4 -4
- package/src/scripts/hooks/instructions_observer_hook.ts +25 -6
- package/src/scripts/hooks/lazy_concern.ts +4 -0
- package/src/scripts/hooks/payload_stub.ts +27 -0
- package/src/scripts/hooks/spawn_guard_shadow_hook.ts +29 -70
- package/src/scripts/hooks/subagent_ledger_hook.ts +80 -0
- package/src/scripts/install-hooks.sh +5 -0
- package/src/scripts/install.ts +2 -2
- package/src/scripts/lint_agents_layout.ts +2 -0
- package/src/scripts/lint_decision_classes.ts +34 -0
- package/src/scripts/lint_hook_manifest.ts +25 -0
- package/src/scripts/lint_roadmap_blockers.ts +52 -3
- package/src/scripts/mcp_server/consumer_tool_catalog.json +53 -6
- package/src/scripts/mcp_server/graph_tools.ts +73 -1
- package/src/scripts/mcp_server/tools.ts +19 -36
- package/src/scripts/release.ts +5 -9
- package/src/scripts/release_drill.ts +11 -165
- package/src/scripts/release_publication.ts +0 -9
- package/src/scripts/report_production_reach.ts +35 -0
- package/src/scripts/worker_reuse_shadow_report.ts +399 -1
- package/src/server/schemas/settings.ts +1 -1
- package/src/vendor/grammars/README.md +10 -5
- package/src/vendor/grammars/tree-sitter-go.wasm +0 -0
- package/src/vendor/grammars/tree-sitter-java.wasm +0 -0
- package/src/vendor/grammars/tree-sitter-python.wasm +0 -0
- package/dist/cli-delegate/chunk-A4QJ6ENT.js +0 -50
- /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);
|
package/dist/install/conflict.js
CHANGED
|
@@ -16,7 +16,8 @@
|
|
|
16
16
|
*/
|
|
17
17
|
import { existsSync } from 'node:fs';
|
|
18
18
|
import { sha256File } from './plan.js';
|
|
19
|
-
import {
|
|
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
|
|
228
|
+
const recordedSha256 = exists ? recordedHashFor(target) : undefined;
|
|
229
|
+
const unproven = {
|
|
226
230
|
exists,
|
|
227
|
-
recordedSha256
|
|
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
|