@event4u/agent-config 9.30.0 → 9.32.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/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +60 -292
- package/dist/agent-src/contexts/execution/host-capability-manifest.md +32 -1
- package/dist/agent-src/rules/delegation-policy.md +11 -1
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/scripts/work_engine/delivery_state.ts +6 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/_self_fix.ts +332 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/refine.ts +106 -1
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/test.ts +50 -15
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +49 -15
- package/dist/agent-src/templates/scripts/work_engine/state.ts +74 -0
- package/dist/agent-src/templates/scripts/work_engine/state_io.ts +6 -0
- package/dist/cli-delegate/chunk-2WELHO3P.js +582 -0
- package/dist/cli-delegate/{chunk-IYTGIG2Y.js → chunk-542DZR4P.js} +118 -148
- package/dist/cli-delegate/{chunk-66OVWGB5.js → chunk-AG47LAGQ.js} +1 -1
- package/dist/cli-delegate/{chunk-MP3JT3IU.js → chunk-DS6BLDMG.js} +1 -1
- package/dist/cli-delegate/{chunk-O3CO5BFB.js → chunk-EJITJBJX.js} +12 -1
- package/dist/cli-delegate/{chunk-EQY4FLJB.js → chunk-ITIQSGOQ.js} +3 -3
- package/dist/cli-delegate/{chunk-LCFJIQ4J.js → chunk-JEJABGKB.js} +110 -6
- package/dist/cli-delegate/chunk-PZWRPRWP.js +38 -0
- package/dist/cli-delegate/{chunk-BTJNRUX3.js → chunk-QEEB4LHO.js} +1 -1
- package/dist/cli-delegate/{chunk-DDUNNFYX.js → chunk-UVKNIJH2.js} +2 -2
- package/dist/cli-delegate/cmd_analyze_session.js +1 -1
- package/dist/cli-delegate/cmd_brand_status.js +1 -1
- package/dist/cli-delegate/cmd_conformance.js +154 -41
- package/dist/cli-delegate/cmd_doctor.js +4 -3
- package/dist/cli-delegate/cmd_explain.js +2 -2
- package/dist/cli-delegate/cmd_export.js +4 -4
- package/dist/cli-delegate/cmd_handoff.js +168 -59
- package/dist/cli-delegate/cmd_mcp_available.js +1 -1
- package/dist/cli-delegate/cmd_migrate.js +2 -2
- package/dist/cli-delegate/cmd_packs_active.js +2 -2
- package/dist/cli-delegate/cmd_prune.js +4 -4
- package/dist/cli-delegate/cmd_route_audit.js +2 -2
- package/dist/cli-delegate/cmd_route_explain.js +1 -1
- package/dist/cli-delegate/cmd_session_recycle.js +19 -4
- package/dist/cli-delegate/cmd_settings_get.js +2 -55
- package/dist/cli-delegate/cmd_settings_migrate.js +4 -4
- package/dist/cli-delegate/cmd_settings_set.js +1 -1
- package/dist/cli-delegate/cmd_sync.js +4 -4
- package/dist/cli-delegate/cmd_uninstall.js +4 -4
- package/dist/cli-delegate/cmd_update.js +1 -1
- package/dist/cli-delegate/cmd_upgrade.js +1 -1
- package/dist/cli-delegate/cmd_validate.js +4 -4
- package/dist/cli-delegate/cmd_versions.js +1 -1
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +3 -3
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +1 -1
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +2 -2
- package/dist/discovery/trust-report.md +1 -1
- package/dist/discovery/workspaces.json +2 -2
- package/dist/hooks/dispatch.js +1411 -810
- package/dist/install/install.mjs +121 -16
- package/dist/mcp/registry-manifest.json +1 -1
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +365 -143
- package/dist/scripts/_lib/agent_settings.js +111 -2
- package/dist/scripts/_lib/agent_settings.js.map +1 -1
- package/dist/server/schemas/settings.js +2 -2
- package/dist/server/schemas/settings.js.map +1 -1
- package/package.json +1 -1
- package/src/agent-src/templates/scripts/work_engine/delivery_state.ts +6 -0
- package/src/agent-src/templates/scripts/work_engine/directives/backend/_self_fix.ts +332 -0
- package/src/agent-src/templates/scripts/work_engine/directives/backend/refine.ts +106 -1
- package/src/agent-src/templates/scripts/work_engine/directives/backend/test.ts +50 -15
- package/src/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +49 -15
- package/src/agent-src/templates/scripts/work_engine/state.ts +74 -0
- package/src/agent-src/templates/scripts/work_engine/state_io.ts +6 -0
- package/src/config/pack-size-budget.json +3 -2
- package/src/scripts/_cli/cmd_session_recycle.ts +25 -0
- package/src/scripts/_cli/explain_last/inputs.ts +13 -0
- package/src/scripts/_cli/handoff_generate.ts +36 -1
- package/src/scripts/_cli/handoff_sessions.ts +140 -9
- package/src/scripts/_lib/agent_settings.ts +119 -2
- package/src/scripts/_lib/carrier_divergence.ts +120 -2
- package/src/scripts/_lib/envelope_grounding.ts +206 -0
- package/src/scripts/_lib/host_capability.ts +79 -0
- package/src/scripts/_lib/session_eol.ts +85 -0
- package/src/scripts/_lib/subagent_capsule.ts +256 -1
- package/src/scripts/check_secret_leak.test.ts +43 -0
- package/src/scripts/check_secret_leak.ts +12 -0
- package/src/scripts/handoff_context_hook.ts +66 -18
- package/src/scripts/hooks/session_eol_hook.ts +12 -12
- package/src/scripts/hooks/turn_end_gate_hook.ts +296 -88
- package/src/scripts/language_mirror_hook.ts +69 -16
- package/src/scripts/measure_turn_end_gate.ts +129 -51
- package/src/scripts/report_carrier_divergence.ts +143 -30
- package/src/scripts/report_conformance_funnel.ts +18 -4
- package/src/scripts/routing_doctor.ts +25 -2
- package/src/scripts/schemas/dod.schema.json +45 -0
- package/src/server/schemas/settings.ts +2 -2
- package/dist/cli-delegate/chunk-RVGBH4XK.js +0 -142
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createRequire as __acCreateRequire } from 'node:module'; const require = globalThis.require ?? __acCreateRequire(import.meta.url);
|
|
2
2
|
import {
|
|
3
3
|
resolve_project_root
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-JEJABGKB.js";
|
|
5
5
|
import {
|
|
6
6
|
resolvePackageRoot
|
|
7
7
|
} from "./chunk-MCJYCQPF.js";
|
|
@@ -108,6 +108,15 @@ function atomic_write_json(target, payload, options = {}) {
|
|
|
108
108
|
const body = _py_json_dumps(payload, indent) + "\n";
|
|
109
109
|
_atomic_write_text(targetPath, body);
|
|
110
110
|
}
|
|
111
|
+
function atomic_write_text(target, text) {
|
|
112
|
+
if (is_replay_mode()) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
const targetPath = path.resolve(target);
|
|
116
|
+
const state_dir = path.dirname(targetPath);
|
|
117
|
+
fs.mkdirSync(state_dir, { recursive: true });
|
|
118
|
+
_atomic_write_text(targetPath, text);
|
|
119
|
+
}
|
|
111
120
|
function _acquire_lock(lock_path) {
|
|
112
121
|
const fd = fs.openSync(lock_path, "a", 420);
|
|
113
122
|
const held = lock_path + ".held";
|
|
@@ -157,5 +166,7 @@ function _atomic_write_text(target, text) {
|
|
|
157
166
|
}
|
|
158
167
|
|
|
159
168
|
export {
|
|
160
|
-
|
|
169
|
+
is_replay_mode,
|
|
170
|
+
atomic_write_json,
|
|
171
|
+
atomic_write_text
|
|
161
172
|
};
|
|
@@ -2,10 +2,10 @@ import { createRequire as __acCreateRequire } from 'node:module'; const require
|
|
|
2
2
|
import {
|
|
3
3
|
ZodFirstPartyTypeKind,
|
|
4
4
|
settingsSchema
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-UVKNIJH2.js";
|
|
6
6
|
import {
|
|
7
7
|
main
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-DS6BLDMG.js";
|
|
9
9
|
import {
|
|
10
10
|
RULE_SOURCE_REL
|
|
11
11
|
} from "./chunk-BKO2AZ7Z.js";
|
|
@@ -48,7 +48,7 @@ import {
|
|
|
48
48
|
import {
|
|
49
49
|
find_project_root_with_anchor,
|
|
50
50
|
load_agent_settings
|
|
51
|
-
} from "./chunk-
|
|
51
|
+
} from "./chunk-JEJABGKB.js";
|
|
52
52
|
import {
|
|
53
53
|
event4u_root,
|
|
54
54
|
legacy_xdg_root,
|
|
@@ -4,11 +4,67 @@ import {
|
|
|
4
4
|
write_target
|
|
5
5
|
} from "./chunk-NDJLNC6Q.js";
|
|
6
6
|
|
|
7
|
+
// src/shared/settingsCarveOut.ts
|
|
8
|
+
var SETTINGS_CARVE_OUT = [
|
|
9
|
+
{
|
|
10
|
+
key: "projection.mode",
|
|
11
|
+
reader: "src/scripts/install.ts:3409 _resolve_scoped_projection",
|
|
12
|
+
absentResolvesTo: "legacy-all",
|
|
13
|
+
reason: "The template fallback applies only when NO global settings file exists. Once a file exists, an absent key means legacy-all by documented contract, so an existing install is never silently narrowed on upgrade."
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
key: "projection.rule_workspaces",
|
|
17
|
+
reader: "src/install/rule_scope.ts:96 ruleScopeFromSettings",
|
|
18
|
+
absentResolvesTo: "null \u2014 LEGACY_ALL, i.e. every rule ships including maintainer-only ones",
|
|
19
|
+
reason: "Same upgrade contract as projection.mode, and the failure is louder: an absent list widens the projection instead of narrowing it."
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
key: "discipline_profile",
|
|
23
|
+
reader: "work_engine/_lib/agent_settings.ts:1263",
|
|
24
|
+
absentResolvesTo: "essential, unconditionally",
|
|
25
|
+
reason: "The template ships `auto`, which resolves to `off` on any measured-null model, any non-Claude host, and any host exposing no model id. Absent skips that resolution entirely and loads the essential tier everywhere."
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
key: "chat_history.frequency",
|
|
29
|
+
reader: "src/scripts/chat_history.ts:1140",
|
|
30
|
+
absentResolvesTo: "per_phase",
|
|
31
|
+
reason: "Canonical substitution is `per_turn`. Absent gives coarser capture than the shipped default \u2014 an audit-thinning change, which the class contract's own test 8 (what can the attacker HIDE) names as the severe direction."
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
key: "profile.id",
|
|
35
|
+
reader: "src/scripts/config/profiles.ts:221 resolve_profile",
|
|
36
|
+
absentResolvesTo: "the id `developer`, but a DEGRADED profile \u2014 packs: [], personas: [], hints: []",
|
|
37
|
+
reason: "Exactly the projection.mode shape: the template default is honoured only when no settings file exists. With a file present the id resolves but its profile body does not load, so the install silently loses every pack and persona."
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
key: "quality.local_auto_run",
|
|
41
|
+
reader: "src/scripts/lint_roadmap_ci_steps.ts:106",
|
|
42
|
+
absentResolvesTo: "true \u2014 which DISABLES the CI-step gate",
|
|
43
|
+
reason: "Inverted polarity, and the most dangerous row in the set: the template ships `false`, which ARMS the gate. Omitting the key would disarm a quality gate for every fresh install while the reference page says it is on."
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
key: "onboarding.onboarded",
|
|
47
|
+
reader: "src/scripts/onboarding_gate_hook.ts:99",
|
|
48
|
+
absentResolvesTo: "gate skipped, as if onboarding had already completed",
|
|
49
|
+
reason: "Absent behaves like `onboarded: true`, not like the template default `false`. Omitting it would skip the onboarding gate on precisely the fresh installs the gate exists for."
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
key: "chat_history.enabled",
|
|
53
|
+
reader: "src/scripts/chat_history.ts:1025 _read_chat_history_enabled",
|
|
54
|
+
absentResolvesTo: "false",
|
|
55
|
+
reason: "The reader falls back to false while the template ships true. This one is privacy-shaped: fixing the reader would start recording history for every install whose file lacks the key. Writing it explicitly keeps the decision visible in the file the user can read."
|
|
56
|
+
}
|
|
57
|
+
];
|
|
58
|
+
function carveOutKeys() {
|
|
59
|
+
return SETTINGS_CARVE_OUT.map((c) => c.key);
|
|
60
|
+
}
|
|
61
|
+
|
|
7
62
|
// src/scripts/_lib/agent_settings.ts
|
|
8
63
|
import { createRequire } from "node:module";
|
|
9
64
|
import * as fs from "node:fs";
|
|
10
65
|
import * as os from "node:os";
|
|
11
66
|
import * as path from "node:path";
|
|
67
|
+
import { fileURLToPath } from "node:url";
|
|
12
68
|
var _require = createRequire(import.meta.url);
|
|
13
69
|
var Logger = class {
|
|
14
70
|
name = "scripts._lib.agent_settings";
|
|
@@ -117,7 +173,45 @@ var MERGEABLE_KEYS = [
|
|
|
117
173
|
"knowledge.global_sharing.freshness.hypothesis_after_days",
|
|
118
174
|
"knowledge.global_sharing.freshness.stale_after_days"
|
|
119
175
|
];
|
|
120
|
-
var
|
|
176
|
+
var TEMPLATE_RELATIVE = path.join("src", "config", "agent-settings.template.yml");
|
|
177
|
+
var _PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "..", "..");
|
|
178
|
+
function default_template_path() {
|
|
179
|
+
return path.join(_PACKAGE_ROOT, TEMPLATE_RELATIVE);
|
|
180
|
+
}
|
|
181
|
+
function _is_placeholder(value) {
|
|
182
|
+
return typeof value === "string" && /^__[A-Z0-9_]+__$/.test(value);
|
|
183
|
+
}
|
|
184
|
+
function _prune_template(tree, excluded, prefix = "") {
|
|
185
|
+
const out = {};
|
|
186
|
+
for (const [key, value] of Object.entries(tree)) {
|
|
187
|
+
const dotted = prefix === "" ? key : `${prefix}.${key}`;
|
|
188
|
+
if (excluded.has(dotted) || _is_placeholder(value)) {
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
if (_is_plain_dict(value)) {
|
|
192
|
+
const child = _prune_template(value, excluded, dotted);
|
|
193
|
+
if (Object.keys(child).length > 0) {
|
|
194
|
+
out[key] = child;
|
|
195
|
+
}
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
out[key] = value;
|
|
199
|
+
}
|
|
200
|
+
return out;
|
|
201
|
+
}
|
|
202
|
+
var _template_defaults_cache = null;
|
|
203
|
+
function template_defaults(template_path) {
|
|
204
|
+
const use_cache = template_path === void 0;
|
|
205
|
+
if (use_cache && _template_defaults_cache !== null) {
|
|
206
|
+
return _deepcopy(_template_defaults_cache);
|
|
207
|
+
}
|
|
208
|
+
const parsed = _read_yaml(template_path ?? default_template_path()) ?? {};
|
|
209
|
+
const pruned = _prune_template(parsed, new Set(carveOutKeys()));
|
|
210
|
+
if (use_cache) {
|
|
211
|
+
_template_defaults_cache = pruned;
|
|
212
|
+
}
|
|
213
|
+
return _deepcopy(pruned);
|
|
214
|
+
}
|
|
121
215
|
var ANCHOR_AGENT_SETTINGS = "agent-settings";
|
|
122
216
|
var ANCHOR_AGENTS_DIR = "agents-dir";
|
|
123
217
|
var ANCHOR_GIT = "git";
|
|
@@ -386,6 +480,7 @@ function load_agent_settings(options = {}) {
|
|
|
386
480
|
const user_global_path = options.user_global_path ?? null;
|
|
387
481
|
const verbose = options.verbose ?? false;
|
|
388
482
|
const cwd = options.cwd ?? null;
|
|
483
|
+
const template_path = options.template_path ?? null;
|
|
389
484
|
const user_global_raw = {};
|
|
390
485
|
for (const p of user_global_path ? [user_global_path] : user_global_settings_paths()) {
|
|
391
486
|
_deep_merge(user_global_raw, _read_yaml(p) ?? {});
|
|
@@ -398,7 +493,7 @@ function load_agent_settings(options = {}) {
|
|
|
398
493
|
);
|
|
399
494
|
}
|
|
400
495
|
const cascade = _resolve_cascade_paths(cwd, project_path);
|
|
401
|
-
const merged =
|
|
496
|
+
const merged = template_defaults(template_path ?? void 0);
|
|
402
497
|
_deep_merge(merged, user_global_filtered);
|
|
403
498
|
for (const p of cascade) {
|
|
404
499
|
const layer = _read_yaml(p) ?? {};
|
|
@@ -555,16 +650,25 @@ function _deep_merge(dst, src) {
|
|
|
555
650
|
}
|
|
556
651
|
}
|
|
557
652
|
}
|
|
558
|
-
function
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
653
|
+
function _deepcopy(value) {
|
|
654
|
+
if (Array.isArray(value)) {
|
|
655
|
+
return value.map((v) => _deepcopy(v));
|
|
656
|
+
}
|
|
657
|
+
if (_is_plain_dict(value)) {
|
|
658
|
+
const out = {};
|
|
659
|
+
for (const [k, v] of Object.entries(value)) {
|
|
660
|
+
out[k] = _deepcopy(v);
|
|
661
|
+
}
|
|
662
|
+
return out;
|
|
663
|
+
}
|
|
664
|
+
return value;
|
|
562
665
|
}
|
|
563
666
|
function _is_plain_dict(value) {
|
|
564
667
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
565
668
|
}
|
|
566
669
|
|
|
567
670
|
export {
|
|
671
|
+
SETTINGS_CARVE_OUT,
|
|
568
672
|
logger,
|
|
569
673
|
DEFAULT_PROJECT_FILE,
|
|
570
674
|
LOCAL_PROJECT_FILE,
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { createRequire as __acCreateRequire } from 'node:module'; const require = globalThis.require ?? __acCreateRequire(import.meta.url);
|
|
2
|
+
|
|
3
|
+
// src/scripts/_lib/git_common_dir.ts
|
|
4
|
+
import fs from "node:fs";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
function realpath_or_self(p) {
|
|
7
|
+
try {
|
|
8
|
+
return fs.realpathSync(p);
|
|
9
|
+
} catch {
|
|
10
|
+
return p;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
function git_common_dir(project_root) {
|
|
14
|
+
const dot_git = path.join(project_root, ".git");
|
|
15
|
+
try {
|
|
16
|
+
const st = fs.statSync(dot_git);
|
|
17
|
+
if (st.isDirectory()) {
|
|
18
|
+
return realpath_or_self(dot_git);
|
|
19
|
+
}
|
|
20
|
+
const m = fs.readFileSync(dot_git, "utf-8").match(/^gitdir:\s*(.+)\s*$/m);
|
|
21
|
+
if (m === null) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
const gitdir = path.resolve(project_root, m[1].trim());
|
|
25
|
+
const commondir_file = path.join(gitdir, "commondir");
|
|
26
|
+
if (fs.existsSync(commondir_file)) {
|
|
27
|
+
const common = path.resolve(gitdir, fs.readFileSync(commondir_file, "utf-8").trim());
|
|
28
|
+
return realpath_or_self(common);
|
|
29
|
+
}
|
|
30
|
+
return realpath_or_self(gitdir);
|
|
31
|
+
} catch {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export {
|
|
37
|
+
git_common_dir
|
|
38
|
+
};
|
|
@@ -4549,10 +4549,10 @@ var settingsSchema = external_exports.object({
|
|
|
4549
4549
|
"Stop-slot turn-end gate (road-to-conformance-round5 Phase 3). Default off, and it is the only concern that can REFUSE a turn-end rather than a tool call \u2014 so it soaks behind an explicit opt-in before it binds. Round 5 measured the reason: both blocking carriers reached zero violations, neither advisory carrier did, and 19 wrong-language replies survived a pin that had fired 26-35 seconds earlier. A refused turn continues in the SAME turn and is never refused twice."
|
|
4550
4550
|
),
|
|
4551
4551
|
promissory: external_exports.boolean().default(true).describe(
|
|
4552
|
-
"Detector A of the turn-end gate: refuse a turn whose closing paragraph promises work not yet performed while asking the user nothing (20 measured occurrences). Inert while hooks.turn_end_gate.enabled is false."
|
|
4552
|
+
"Detector A of the turn-end gate: refuse a turn whose closing paragraph promises work not yet performed while asking the user nothing (20 measured occurrences). No fire rate is quoted here on purpose: the measured rate moved twice while the instrument itself was being corrected, so a number in a shipped description would be a moving target. Re-derive it with `measure-turn-end-gate --store <transcript dir>` against your own corpus before arming the gate. Inert while hooks.turn_end_gate.enabled is false."
|
|
4553
4553
|
),
|
|
4554
4554
|
language: external_exports.boolean().default(true).describe(
|
|
4555
|
-
"Detector B of the turn-end gate: refuse a turn whose
|
|
4555
|
+
"Detector B of the turn-end gate: refuse a turn whose reply is not in the pinned language (19 measured occurrences). Fenced code, inline code, quoted tool output, tables, URLs and paths are stripped first, and the remainder is then scored LEAD-FIRST by the same classifier that sets the pin \u2014 so the verdict usually comes from the reply opening, not from all of it. Sharing that classifier is deliberate: it stops the pin and the detector disagreeing about a turn. Accepted opt-in spellings for the switches below include YAML true/false and yes/no/on/off. Inert while hooks.turn_end_gate.enabled is false."
|
|
4556
4556
|
)
|
|
4557
4557
|
}).default({})
|
|
4558
4558
|
}),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createRequire as __acCreateRequire } from 'node:module'; const require = globalThis.require ?? __acCreateRequire(import.meta.url);
|
|
2
2
|
import {
|
|
3
3
|
resolve_project_root
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-JEJABGKB.js";
|
|
5
5
|
import "./chunk-NDJLNC6Q.js";
|
|
6
6
|
import "./chunk-J55WI3RR.js";
|
|
7
7
|
|
|
@@ -14,12 +14,15 @@ import {
|
|
|
14
14
|
_run_checks,
|
|
15
15
|
_run_checks_no_manifest,
|
|
16
16
|
_scan_foreign
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-542DZR4P.js";
|
|
18
18
|
import "./chunk-FTAISGDQ.js";
|
|
19
19
|
import {
|
|
20
|
-
atomic_write_json
|
|
21
|
-
|
|
20
|
+
atomic_write_json,
|
|
21
|
+
atomic_write_text,
|
|
22
|
+
is_replay_mode
|
|
23
|
+
} from "./chunk-EJITJBJX.js";
|
|
22
24
|
import "./chunk-LVRYBKTI.js";
|
|
25
|
+
import "./chunk-PZWRPRWP.js";
|
|
23
26
|
import "./chunk-736JCWLM.js";
|
|
24
27
|
import {
|
|
25
28
|
atomicAppendLine,
|
|
@@ -28,7 +31,7 @@ import {
|
|
|
28
31
|
} from "./chunk-63WSP6YZ.js";
|
|
29
32
|
import "./chunk-GRRPEPRN.js";
|
|
30
33
|
import "./chunk-NXFWFAYV.js";
|
|
31
|
-
import "./chunk-
|
|
34
|
+
import "./chunk-JEJABGKB.js";
|
|
32
35
|
import "./chunk-NDJLNC6Q.js";
|
|
33
36
|
import {
|
|
34
37
|
detectToolPresence
|
|
@@ -140,6 +143,37 @@ function comparePair(a, b) {
|
|
|
140
143
|
}
|
|
141
144
|
return "body-diff";
|
|
142
145
|
}
|
|
146
|
+
function splitFrontmatter(text) {
|
|
147
|
+
if (!text.startsWith("---")) return { hadFrontmatter: false, frontmatter: "", body: text };
|
|
148
|
+
const end = text.indexOf("\n---", 3);
|
|
149
|
+
if (end === -1) return { hadFrontmatter: false, frontmatter: "", body: text };
|
|
150
|
+
const afterFence = text.indexOf("\n", end + 1);
|
|
151
|
+
return {
|
|
152
|
+
hadFrontmatter: true,
|
|
153
|
+
frontmatter: text.slice(3, end),
|
|
154
|
+
body: afterFence === -1 ? "" : text.slice(afterFence + 1)
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
function proseEqual(a, b) {
|
|
158
|
+
const sa = splitFrontmatter(a);
|
|
159
|
+
const sb = splitFrontmatter(b);
|
|
160
|
+
if (!sa.hadFrontmatter && !sb.hadFrontmatter) return false;
|
|
161
|
+
const leading = /^\n+/;
|
|
162
|
+
return sa.body.replace(leading, "") === sb.body.replace(leading, "");
|
|
163
|
+
}
|
|
164
|
+
function frontmatterPaths(text) {
|
|
165
|
+
const { hadFrontmatter, frontmatter } = splitFrontmatter(text);
|
|
166
|
+
if (!hadFrontmatter) return null;
|
|
167
|
+
const lines = frontmatter.split("\n");
|
|
168
|
+
const start = lines.findIndex((l) => /^paths:/.test(l));
|
|
169
|
+
if (start === -1) return null;
|
|
170
|
+
const block = [lines[start]];
|
|
171
|
+
for (const line of lines.slice(start + 1)) {
|
|
172
|
+
if (/^\s/.test(line) && line.trim() !== "") block.push(line);
|
|
173
|
+
else break;
|
|
174
|
+
}
|
|
175
|
+
return block.map((l) => l.trim()).join(" ");
|
|
176
|
+
}
|
|
143
177
|
function censusRuleDir(dir) {
|
|
144
178
|
let files = 0;
|
|
145
179
|
let chars = 0;
|
|
@@ -223,7 +257,11 @@ function humanAuthoredLead(text) {
|
|
|
223
257
|
var EXIT_ALLOW = 0;
|
|
224
258
|
var EXIT_WARN = 2;
|
|
225
259
|
var STATE_FILE = path2.join("agents", "state", "language-mirror.json");
|
|
226
|
-
var
|
|
260
|
+
var PIN_LOST_DIR = path2.join("agents", "state", "language-mirror.pin-lost");
|
|
261
|
+
function pinLostMarker(session_id) {
|
|
262
|
+
const safe = (session_id || "unknown-session").replace(/[^A-Za-z0-9._-]/g, "_");
|
|
263
|
+
return path2.join(PIN_LOST_DIR, `${safe}.marker`);
|
|
264
|
+
}
|
|
227
265
|
function _isObject2(v) {
|
|
228
266
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
229
267
|
}
|
|
@@ -362,35 +400,49 @@ function _extractPrompt(payload) {
|
|
|
362
400
|
}
|
|
363
401
|
return "";
|
|
364
402
|
}
|
|
365
|
-
function
|
|
403
|
+
function _sessionId(envelope) {
|
|
404
|
+
const v = envelope["session_id"];
|
|
405
|
+
return typeof v === "string" && v.trim() !== "" ? v : "unknown-session";
|
|
406
|
+
}
|
|
407
|
+
function _migrateLegacyMarker(consumer_root) {
|
|
408
|
+
const legacy = path2.join(consumer_root, PIN_LOST_DIR);
|
|
409
|
+
try {
|
|
410
|
+
if (fs2.statSync(legacy).isFile()) {
|
|
411
|
+
fs2.rmSync(legacy, { force: true });
|
|
412
|
+
}
|
|
413
|
+
} catch {
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
function _setPinLost(consumer_root, session_id) {
|
|
417
|
+
if (is_replay_mode()) return;
|
|
418
|
+
_migrateLegacyMarker(consumer_root);
|
|
366
419
|
try {
|
|
367
|
-
|
|
368
|
-
fs2.mkdirSync(path2.dirname(target), { recursive: true });
|
|
369
|
-
fs2.writeFileSync(target, (/* @__PURE__ */ new Date()).toISOString());
|
|
420
|
+
atomic_write_text(path2.join(consumer_root, pinLostMarker(session_id)), (/* @__PURE__ */ new Date()).toISOString());
|
|
370
421
|
} catch {
|
|
371
422
|
}
|
|
372
423
|
}
|
|
373
|
-
function _pinLost(consumer_root) {
|
|
424
|
+
function _pinLost(consumer_root, session_id) {
|
|
374
425
|
try {
|
|
375
|
-
return fs2.existsSync(path2.join(consumer_root,
|
|
426
|
+
return fs2.existsSync(path2.join(consumer_root, pinLostMarker(session_id)));
|
|
376
427
|
} catch {
|
|
377
428
|
return false;
|
|
378
429
|
}
|
|
379
430
|
}
|
|
380
|
-
function _clearPinLost(consumer_root) {
|
|
431
|
+
function _clearPinLost(consumer_root, session_id) {
|
|
432
|
+
if (is_replay_mode()) return;
|
|
381
433
|
try {
|
|
382
|
-
fs2.rmSync(path2.join(consumer_root,
|
|
434
|
+
fs2.rmSync(path2.join(consumer_root, pinLostMarker(session_id)), { force: true });
|
|
383
435
|
} catch {
|
|
384
436
|
}
|
|
385
437
|
}
|
|
386
|
-
function _reEmitAfterCompaction(consumer_root) {
|
|
387
|
-
if (!_pinLost(consumer_root)) {
|
|
438
|
+
function _reEmitAfterCompaction(consumer_root, session_id) {
|
|
439
|
+
if (!_pinLost(consumer_root, session_id)) {
|
|
388
440
|
return EXIT_ALLOW;
|
|
389
441
|
}
|
|
390
442
|
const previous = _loadState(path2.join(consumer_root, STATE_FILE));
|
|
391
443
|
const language = previous.language;
|
|
392
444
|
const source = previous.source === "system-locale" ? "system-locale" : "prompt";
|
|
393
|
-
_clearPinLost(consumer_root);
|
|
445
|
+
_clearPinLost(consumer_root, session_id);
|
|
394
446
|
if (language !== "de" && language !== "en") {
|
|
395
447
|
return EXIT_ALLOW;
|
|
396
448
|
}
|
|
@@ -419,11 +471,11 @@ function run(stdin_text, options) {
|
|
|
419
471
|
const payload = _isObject2(envelope["payload"]) ? envelope["payload"] : envelope;
|
|
420
472
|
const event = typeof envelope["event"] === "string" ? envelope["event"] : "";
|
|
421
473
|
if (event === "pre_compact") {
|
|
422
|
-
_setPinLost(options.consumer_root);
|
|
474
|
+
_setPinLost(options.consumer_root, _sessionId(envelope));
|
|
423
475
|
return EXIT_ALLOW;
|
|
424
476
|
}
|
|
425
477
|
if (event === "post_tool_use") {
|
|
426
|
-
return _reEmitAfterCompaction(options.consumer_root);
|
|
478
|
+
return _reEmitAfterCompaction(options.consumer_root, _sessionId(envelope));
|
|
427
479
|
}
|
|
428
480
|
const prompt = _extractPrompt(payload);
|
|
429
481
|
if (!prompt) {
|
|
@@ -1944,10 +1996,7 @@ function _ruleType(file) {
|
|
|
1944
1996
|
} catch {
|
|
1945
1997
|
return "";
|
|
1946
1998
|
}
|
|
1947
|
-
|
|
1948
|
-
const end = text.indexOf("\n---", 3);
|
|
1949
|
-
const fm = end === -1 ? text : text.slice(0, end);
|
|
1950
|
-
const m = /^type:\s*"?([a-z]+)"?/m.exec(fm);
|
|
1999
|
+
const m = /^type:\s*"?([a-z]+)"?/m.exec(splitFrontmatter(text).frontmatter);
|
|
1951
2000
|
return m === null ? "" : m[1];
|
|
1952
2001
|
}
|
|
1953
2002
|
function compareCarriers(projectDir, globalDir, sourceDir) {
|
|
@@ -1959,6 +2008,8 @@ function compareCarriers(projectDir, globalDir, sourceDir) {
|
|
|
1959
2008
|
shared: 0,
|
|
1960
2009
|
identical: [],
|
|
1961
2010
|
provenanceOnly: [],
|
|
2011
|
+
frontmatterOnly: [],
|
|
2012
|
+
pathsScopeDiff: [],
|
|
1962
2013
|
bodyDiff: [],
|
|
1963
2014
|
projectOnly: [],
|
|
1964
2015
|
globalOnly: [],
|
|
@@ -1983,11 +2034,12 @@ function compareCarriers(projectDir, globalDir, sourceDir) {
|
|
|
1983
2034
|
}
|
|
1984
2035
|
out.shared += 1;
|
|
1985
2036
|
let verdict;
|
|
2037
|
+
let projectCopy;
|
|
2038
|
+
let globalCopy;
|
|
1986
2039
|
try {
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
);
|
|
2040
|
+
projectCopy = fs8.readFileSync(path8.join(projectDir, rule));
|
|
2041
|
+
globalCopy = fs8.readFileSync(path8.join(globalDir, rule));
|
|
2042
|
+
verdict = comparePair(projectCopy, globalCopy);
|
|
1991
2043
|
} catch {
|
|
1992
2044
|
out.shared -= 1;
|
|
1993
2045
|
out.unreadable.push(rule);
|
|
@@ -1995,7 +2047,16 @@ function compareCarriers(projectDir, globalDir, sourceDir) {
|
|
|
1995
2047
|
}
|
|
1996
2048
|
if (verdict === "identical") out.identical.push(rule);
|
|
1997
2049
|
else if (verdict === "provenance-only") out.provenanceOnly.push(rule);
|
|
1998
|
-
else
|
|
2050
|
+
else {
|
|
2051
|
+
const projectText = projectCopy.toString("utf-8");
|
|
2052
|
+
const globalText = globalCopy.toString("utf-8");
|
|
2053
|
+
if (proseEqual(projectText, globalText)) {
|
|
2054
|
+
out.frontmatterOnly.push(rule);
|
|
2055
|
+
if (frontmatterPaths(projectText) !== frontmatterPaths(globalText)) {
|
|
2056
|
+
out.pathsScopeDiff.push(rule);
|
|
2057
|
+
}
|
|
2058
|
+
} else out.bodyDiff.push(rule);
|
|
2059
|
+
}
|
|
1999
2060
|
}
|
|
2000
2061
|
return out;
|
|
2001
2062
|
}
|
|
@@ -2023,7 +2084,9 @@ function render2(d) {
|
|
|
2023
2084
|
lines.push(` shared rule names ${d.shared}`);
|
|
2024
2085
|
lines.push(` byte-identical ${d.identical.length}`);
|
|
2025
2086
|
lines.push(` differ ONLY in the install stamp ${d.provenanceOnly.length}`);
|
|
2026
|
-
lines.push(` differ in
|
|
2087
|
+
lines.push(` differ ONLY in frontmatter ${d.frontmatterOnly.length}`);
|
|
2088
|
+
lines.push(` of which disagree on \`paths:\` ${d.pathsScopeDiff.length} \u2190 ACTIONABLE`);
|
|
2089
|
+
lines.push(` differ in PROSE ${d.bodyDiff.length}`);
|
|
2027
2090
|
if (d.unreadable.length > 0) {
|
|
2028
2091
|
lines.push(` unreadable on one side ${d.unreadable.length} (${d.unreadable.join(", ")})`);
|
|
2029
2092
|
lines.push(" Not counted as shared and NOT a body difference \u2014 a dangling entry is");
|
|
@@ -2033,15 +2096,43 @@ function render2(d) {
|
|
|
2033
2096
|
lines.push(` present at global scope only ${d.globalOnly.length}`);
|
|
2034
2097
|
lines.push("");
|
|
2035
2098
|
if (d.bodyDiff.length > 0) {
|
|
2036
|
-
lines.push("
|
|
2037
|
-
lines.push(" Both copies reach the model,
|
|
2038
|
-
lines.push("
|
|
2039
|
-
lines.push("
|
|
2040
|
-
lines.push("
|
|
2041
|
-
lines.push("
|
|
2099
|
+
lines.push(" PROSE DIVERGENCE \u2014 the two carriers deliver different governed text for");
|
|
2100
|
+
lines.push(" these rules. Both copies reach the model, and the host resolves NOTHING:");
|
|
2101
|
+
lines.push(" rules without a `paths` key load at launch with the same priority as");
|
|
2102
|
+
lines.push(" CLAUDE.md, with no precedence marker between the layers, so a claim one");
|
|
2103
|
+
lines.push(" copy retracts can be re-asserted by the other and which text binds is");
|
|
2104
|
+
lines.push(" UNDEFINED. Cited, not inferred \u2014 agents/evidence/analysis/");
|
|
2105
|
+
lines.push(" claude-code-rules-dir-contract.md (host 2.1.226, the host's own docs plus");
|
|
2106
|
+
lines.push(" a first-party observation). The project copy is the NEWER text, which is a");
|
|
2107
|
+
lines.push(" fact about recency and NOT a host precedence rule: close the divergence by");
|
|
2108
|
+
lines.push(" reinstalling the global copy, or decide which text binds \u2014 do not assume");
|
|
2109
|
+
lines.push(" the newer one already won.");
|
|
2042
2110
|
for (const r of d.bodyDiff) lines.push(` - ${r}`);
|
|
2043
2111
|
lines.push("");
|
|
2044
2112
|
}
|
|
2113
|
+
if (d.pathsScopeDiff.length > 0) {
|
|
2114
|
+
lines.push(` \`paths:\` SCOPE DISAGREEMENT (${String(d.pathsScopeDiff.length)}) \u2014 same prose, different load schedule.`);
|
|
2115
|
+
lines.push(" ACT ON THESE. `paths` is the one frontmatter key this host reads: with it, a");
|
|
2116
|
+
lines.push(" rule fires when a matching file is read and is NOT re-injected after");
|
|
2117
|
+
lines.push(" /compact; without it, the rule loads unconditionally at launch. So the copy");
|
|
2118
|
+
lines.push(" that lacks `paths` DEFEATS the other copy's scoping \u2014 the rule the project");
|
|
2119
|
+
lines.push(" layer meant to deliver conditionally is delivered always, and an obligation");
|
|
2120
|
+
lines.push(" a maintainer deliberately scoped is silently unscoped on any machine that");
|
|
2121
|
+
lines.push(" carries both. Identical prose does not make this inert.");
|
|
2122
|
+
for (const r of d.pathsScopeDiff) lines.push(` - ${r}`);
|
|
2123
|
+
lines.push("");
|
|
2124
|
+
}
|
|
2125
|
+
const inert = d.frontmatterOnly.length - d.pathsScopeDiff.length;
|
|
2126
|
+
if (inert > 0) {
|
|
2127
|
+
lines.push(` ${String(inert)} further pair(s) differ ONLY in frontmatter the host does not read \u2014`);
|
|
2128
|
+
lines.push(" prose byte-identical, `paths` in agreement, nothing to act on. Two writers,");
|
|
2129
|
+
lines.push(" two policies: `generate-tools` emits `paths` where a rule is path-scoped and");
|
|
2130
|
+
lines.push(" nothing otherwise; `install.ts` writes agent-config's own vocabulary plus its");
|
|
2131
|
+
lines.push(" ownership stamp, and none of those keys is one this host reads");
|
|
2132
|
+
lines.push(" (claude-code-rules-dir-contract.md). Reported as a count on purpose: naming");
|
|
2133
|
+
lines.push(" every pair would bury the two classes above, which are the actionable ones.");
|
|
2134
|
+
lines.push("");
|
|
2135
|
+
}
|
|
2045
2136
|
if (d.provenanceOnly.length > 0) {
|
|
2046
2137
|
lines.push(` ${String(d.provenanceOnly.length)} pair(s) differ only by the installer's package:/source_path: stamp.`);
|
|
2047
2138
|
lines.push(" Not a content difference and NOT a defect: install.ts stamps every installed");
|
|
@@ -2077,9 +2168,18 @@ function render2(d) {
|
|
|
2077
2168
|
}
|
|
2078
2169
|
if (d.bodyDiff.length === 0) {
|
|
2079
2170
|
lines.push("");
|
|
2080
|
-
lines.push(" No
|
|
2081
|
-
|
|
2082
|
-
|
|
2171
|
+
lines.push(" No prose divergence \u2014 no rule's governed text differs between the carriers.");
|
|
2172
|
+
if (d.pathsScopeDiff.length > 0) {
|
|
2173
|
+
lines.push(" NOT an all-clear: the `paths:` disagreements above are still open, and they");
|
|
2174
|
+
lines.push(" change when a rule loads rather than what it says.");
|
|
2175
|
+
}
|
|
2176
|
+
lines.push(" The condition is transient \u2014 it returns whenever the checkout moves ahead of");
|
|
2177
|
+
lines.push(" the installed release \u2014 so this is a reading of right now, not a property of");
|
|
2178
|
+
lines.push(" the repo. Re-run it, do not cite it. That holds doubly here: the reading also");
|
|
2179
|
+
lines.push(" depends on WHICH GENERATION of the emitter produced the project tree (a");
|
|
2180
|
+
lines.push(" frontmatter-carrying symlink tree and a frontmatter-less real-file tree");
|
|
2181
|
+
lines.push(" classify the same commit differently), so a number from another checkout is");
|
|
2182
|
+
lines.push(" not comparable to this one.");
|
|
2083
2183
|
}
|
|
2084
2184
|
return lines.join("\n");
|
|
2085
2185
|
}
|
|
@@ -2680,12 +2780,25 @@ function render5(r) {
|
|
|
2680
2780
|
lines.push(" substituted with dist/, which would answer a different question.");
|
|
2681
2781
|
} else {
|
|
2682
2782
|
lines.push(
|
|
2683
|
-
` Divergence: ${d.shared} shared \xB7 ${d.bodyDiff.length}
|
|
2783
|
+
` Divergence: ${d.shared} shared \xB7 ${d.bodyDiff.length} prose-diff \xB7 ${d.frontmatterOnly.length} frontmatter-only (${d.pathsScopeDiff.length} on \`paths:\`) \xB7 ${d.provenanceOnly.length} provenance-only \xB7 ${d.projectOnly.length} project-only \xB7 ${d.globalOnly.length} global-only` + (d.manualOnlyGlobal.length > 0 ? ` (${d.manualOnlyGlobal.length} by design, ADR-004 manual)` : "")
|
|
2684
2784
|
);
|
|
2685
2785
|
if (d.bodyDiff.length > 0) {
|
|
2686
|
-
lines.push(`
|
|
2687
|
-
lines.push("
|
|
2688
|
-
lines.push("
|
|
2786
|
+
lines.push(` PROSE DIVERGENCE \u2014 both copies reach the model: ${d.bodyDiff.join(", ")}`);
|
|
2787
|
+
lines.push(" The host resolves nothing: both layers load at launch at the same");
|
|
2788
|
+
lines.push(" priority with no precedence marker, so which text binds is UNDEFINED");
|
|
2789
|
+
lines.push(" (claude-code-rules-dir-contract.md). The project copy is merely the");
|
|
2790
|
+
lines.push(" newer one \u2014 recency, not precedence.");
|
|
2791
|
+
}
|
|
2792
|
+
if (d.pathsScopeDiff.length > 0) {
|
|
2793
|
+
lines.push(` \`paths:\` SCOPE DISAGREEMENT (${String(d.pathsScopeDiff.length)}) \u2014 same prose, different load`);
|
|
2794
|
+
lines.push(" schedule. `paths` is the one frontmatter key the host reads, so the copy");
|
|
2795
|
+
lines.push(" without it defeats the other copy's scoping: a deliberately scoped");
|
|
2796
|
+
lines.push(" obligation is delivered unconditionally. Act on these.");
|
|
2797
|
+
}
|
|
2798
|
+
const inertFm = d.frontmatterOnly.length - d.pathsScopeDiff.length;
|
|
2799
|
+
if (inertFm > 0) {
|
|
2800
|
+
lines.push(` ${String(inertFm)} further pair(s) differ only in frontmatter the host does not read \u2014`);
|
|
2801
|
+
lines.push(" prose byte-identical, `paths` in agreement, nothing to act on.");
|
|
2689
2802
|
}
|
|
2690
2803
|
if (d.unreadable.length > 0) {
|
|
2691
2804
|
lines.push(` Unreadable on one side (${d.unreadable.length}) \u2014 a broken install, not a disagreement.`);
|
|
@@ -66,15 +66,16 @@ import {
|
|
|
66
66
|
_wizard_state_path,
|
|
67
67
|
main,
|
|
68
68
|
shutilWhich
|
|
69
|
-
} from "./chunk-
|
|
69
|
+
} from "./chunk-542DZR4P.js";
|
|
70
70
|
import "./chunk-FTAISGDQ.js";
|
|
71
|
-
import "./chunk-
|
|
71
|
+
import "./chunk-EJITJBJX.js";
|
|
72
72
|
import "./chunk-LVRYBKTI.js";
|
|
73
|
+
import "./chunk-PZWRPRWP.js";
|
|
73
74
|
import "./chunk-736JCWLM.js";
|
|
74
75
|
import "./chunk-63WSP6YZ.js";
|
|
75
76
|
import "./chunk-GRRPEPRN.js";
|
|
76
77
|
import "./chunk-NXFWFAYV.js";
|
|
77
|
-
import "./chunk-
|
|
78
|
+
import "./chunk-JEJABGKB.js";
|
|
78
79
|
import "./chunk-NDJLNC6Q.js";
|
|
79
80
|
import "./chunk-OY53J6II.js";
|
|
80
81
|
import "./chunk-MCJYCQPF.js";
|