@event4u/agent-config 14.5.0 → 14.6.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 (45) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/CHANGELOG.md +128 -0
  3. package/dist/agent-src/commands/analyze/decision.md +7 -0
  4. package/dist/agent-src/commands/optimize/project.md +10 -0
  5. package/dist/agent-src/commands/roadmap/process-full.md +45 -3
  6. package/dist/agent-src/contexts/execution/roadmap-process-loop.md +130 -1
  7. package/dist/agent-src/rules/decision-revisit-gate.md +108 -7
  8. package/dist/agent-src/skills/adr-create/SKILL.md +25 -3
  9. package/dist/agent-src/skills/decision-review/SKILL.md +18 -0
  10. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  11. package/dist/cli-delegate/{chunk-ZPSXJTLI.js → chunk-P6LQDIWK.js} +15 -1
  12. package/dist/cli-delegate/cmd_conformance.js +1 -1
  13. package/dist/cli-delegate/cmd_handoff.js +1 -1
  14. package/dist/cli-delegate/cmd_session_recycle.js +1 -1
  15. package/dist/discovery/deprecation-report.md +1 -1
  16. package/dist/discovery/discovery-manifest.json +8 -8
  17. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  18. package/dist/discovery/discovery-manifest.summary.md +1 -1
  19. package/dist/discovery/dormancy-report.md +1 -1
  20. package/dist/discovery/orphan-report.md +1 -1
  21. package/dist/discovery/packs.json +2 -2
  22. package/dist/discovery/trust-report.md +1 -1
  23. package/dist/discovery/workspaces.json +2 -2
  24. package/dist/hooks/dispatch.js +334 -77
  25. package/dist/mcp/registry-manifest.json +2 -2
  26. package/dist/mcp/server.json +2 -2
  27. package/dist/router.json +1 -1
  28. package/docs/guidelines/agent-infra/engineering-memory-data-format.md +49 -0
  29. package/package.json +1 -1
  30. package/src/config/estate-count-budget.json +29 -1
  31. package/src/config/pack-size-budget.json +3 -2
  32. package/src/scripts/_lib/layer_overlap_notice.ts +85 -0
  33. package/src/scripts/_lib/scope_guard.sh +62 -3
  34. package/src/scripts/_lib/subagent_capsule.ts +81 -1
  35. package/src/scripts/adr/regenerate_index.ts +13 -2
  36. package/src/scripts/adr_cite_check.ts +424 -0
  37. package/src/scripts/check_adr_frontmatter.ts +187 -1
  38. package/src/scripts/check_single_delivery.ts +473 -0
  39. package/src/scripts/hooks/run_continuation_hook.ts +884 -68
  40. package/src/scripts/install.sh +12 -2
  41. package/src/scripts/memory_consolidation.ts +189 -0
  42. package/src/scripts/memory_eviction.ts +384 -0
  43. package/src/scripts/report_layer_overlap.ts +72 -0
  44. package/src/scripts/report_memory_pointers.ts +622 -0
  45. package/src/scripts/session_register_hook.ts +104 -15
@@ -11921,9 +11921,9 @@ function user_global_settings_paths() {
11921
11921
  if (flat !== null) {
11922
11922
  paths.push(flat);
11923
11923
  }
11924
- const canonical = resolve_with_fallback(USER_GLOBAL_CANONICAL_RELATIVE);
11925
- if (canonical !== null) {
11926
- paths.push(canonical);
11924
+ const canonical2 = resolve_with_fallback(USER_GLOBAL_CANONICAL_RELATIVE);
11925
+ if (canonical2 !== null) {
11926
+ paths.push(canonical2);
11927
11927
  }
11928
11928
  if (paths.length === 0) {
11929
11929
  paths.push(DEFAULT_USER_GLOBAL_FILE());
@@ -18118,6 +18118,20 @@ var CAPSULE_SCHEMA_VERSION = 3;
18118
18118
  function isShortLine(value, max) {
18119
18119
  return typeof value === "string" && value.length > 0 && value.length <= max && !value.includes("\n");
18120
18120
  }
18121
+ function isPathRef(value) {
18122
+ return typeof value === "string" && value.length > 0 && !/\s/.test(value);
18123
+ }
18124
+ function checkPathRefList(errors, field, value, max, required) {
18125
+ checkList(errors, field, value, max, required);
18126
+ if (!Array.isArray(value)) return;
18127
+ if (value.some((x) => !isShortLine(x, max))) return;
18128
+ const bad = value.filter((x) => !isPathRef(x));
18129
+ if (bad.length === 0) return;
18130
+ const shown = bad.slice(0, 3).map((x) => JSON.stringify(String(x))).join(", ");
18131
+ errors.push(
18132
+ `${field} carries ${bad.length} entr${bad.length === 1 ? "y" : "ies"} that are prose, not path refs: ${shown}${bad.length > 3 ? ", \u2026" : ""} \u2014 write the path (src/generated/api.ts, ../other-worktree/) or drop the entry; a sentence naming a file cannot be compared against a write target, and being comparable is the whole reason this is a field rather than a line of prose`
18133
+ );
18134
+ }
18121
18135
  function checkList(errors, field, value, max, required) {
18122
18136
  if (value === void 0) {
18123
18137
  if (required) errors.push(`${field} is required`);
@@ -18307,7 +18321,7 @@ function validateRecycleEnvelope(input) {
18307
18321
  checkList(errors, "decisions", e["decisions"], MAX_LINE_CHARS, false);
18308
18322
  errors.push(...decisionTagErrors(e["decisions"]));
18309
18323
  checkList(errors, "constraints", e["constraints"], MAX_LINE_CHARS, false);
18310
- checkList(errors, "do_not_touch", e["do_not_touch"], MAX_REF_CHARS, false);
18324
+ checkPathRefList(errors, "do_not_touch", e["do_not_touch"], MAX_REF_CHARS, false);
18311
18325
  checkList(errors, "open_worker_envelopes", e["open_worker_envelopes"], MAX_REF_CHARS, false);
18312
18326
  checkList(errors, "artifact_paths", e["artifact_paths"], MAX_REF_CHARS, false);
18313
18327
  checkList(errors, "suggested_skills", e["suggested_skills"], MAX_REF_CHARS, false);
@@ -20861,11 +20875,11 @@ function refresh_precommit_hook(root) {
20861
20875
  if (!current.includes(_PRECOMMIT_MARKER)) {
20862
20876
  return null;
20863
20877
  }
20864
- const canonical = fs35.readFileSync(template, "utf-8");
20865
- if (current === canonical) {
20878
+ const canonical2 = fs35.readFileSync(template, "utf-8");
20879
+ if (current === canonical2) {
20866
20880
  return null;
20867
20881
  }
20868
- fs35.writeFileSync(target, canonical);
20882
+ fs35.writeFileSync(target, canonical2);
20869
20883
  fs35.chmodSync(target, 493);
20870
20884
  return target;
20871
20885
  } catch {
@@ -21453,15 +21467,15 @@ function _load_config_fail_open() {
21453
21467
  var _CODEX_PLUGIN_DATA_DIRNAME = `${CODEX_PLUGIN_ID}-${CODEX_MARKETPLACE_NAME}`;
21454
21468
  var UPSTREAM_GATE_JOB_TITLE = "Codex Stop Gate Review";
21455
21469
  function _workspace_state_segment(workspace_root) {
21456
- let canonical = workspace_root;
21470
+ let canonical2 = workspace_root;
21457
21471
  try {
21458
- canonical = fs37.realpathSync.native(workspace_root);
21472
+ canonical2 = fs37.realpathSync.native(workspace_root);
21459
21473
  } catch {
21460
- canonical = workspace_root;
21474
+ canonical2 = workspace_root;
21461
21475
  }
21462
21476
  const slug_source = path38.basename(workspace_root) || "workspace";
21463
21477
  const slug = slug_source.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "workspace";
21464
- const hash = crypto3.createHash("sha256").update(canonical).digest("hex").slice(0, 16);
21478
+ const hash = crypto3.createHash("sha256").update(canonical2).digest("hex").slice(0, 16);
21465
21479
  return `${slug}-${hash}`;
21466
21480
  }
21467
21481
  function upstream_state_dir_candidates(workspace_root) {
@@ -23913,7 +23927,7 @@ function claim_is_stale(workspace_root, slug, peer_worktree) {
23913
23927
  }
23914
23928
  const base = slug.trim().replace(/\.md$/, "");
23915
23929
  const rel = path52.normalize(path52.join("agents", "roadmaps", `${base}.md`));
23916
- const inside = rel.startsWith(`agents${path52.sep}roadmaps${path52.sep}`) && !rel.includes("..");
23930
+ const inside = path52.dirname(rel) === path52.join("agents", "roadmaps");
23917
23931
  if (!inside || path52.isAbsolute(base)) {
23918
23932
  return true;
23919
23933
  }
@@ -23932,18 +23946,40 @@ function claim_is_stale(workspace_root, slug, peer_worktree) {
23932
23946
  return true;
23933
23947
  }
23934
23948
  function session_checkout(workspace_root, payload_cwd) {
23949
+ const fallback = canonical(workspace_root);
23935
23950
  const cwd = String(payload_cwd ?? "").trim();
23936
- if (cwd === "") return workspace_root;
23951
+ if (cwd === "") return fallback;
23952
+ let start;
23937
23953
  try {
23938
- if (!fs52.statSync(cwd).isDirectory()) return workspace_root;
23954
+ if (!fs52.statSync(cwd).isDirectory()) return fallback;
23955
+ start = fs52.realpathSync(cwd);
23939
23956
  } catch {
23940
- return workspace_root;
23957
+ return fallback;
23941
23958
  }
23942
- if (git_dir(cwd) === null) return workspace_root;
23943
- const mine = git_common_dir(cwd);
23959
+ const root = nearest_checkout_root(start);
23960
+ if (root === null) return fallback;
23961
+ const mine = git_common_dir(root);
23944
23962
  const theirs = git_common_dir(workspace_root);
23945
- if (mine === null || theirs === null || mine !== theirs) return workspace_root;
23946
- return cwd;
23963
+ if (mine === null || theirs === null || mine !== theirs) return fallback;
23964
+ return root;
23965
+ }
23966
+ function canonical(p) {
23967
+ const abs = path52.resolve(p);
23968
+ try {
23969
+ return fs52.realpathSync(abs);
23970
+ } catch {
23971
+ return abs;
23972
+ }
23973
+ }
23974
+ function nearest_checkout_root(start) {
23975
+ let dir = start;
23976
+ for (let i = 0; i < 64; i++) {
23977
+ if (git_dir(dir) !== null) return dir;
23978
+ const up = path52.dirname(dir);
23979
+ if (up === dir) return null;
23980
+ dir = up;
23981
+ }
23982
+ return null;
23947
23983
  }
23948
23984
  function build_record(workspace_root, session_id, platform, started_at, now = /* @__PURE__ */ new Date()) {
23949
23985
  const rec = {
@@ -24028,8 +24064,8 @@ function foreign_sessions_block(workspace_root, session_id, now = /* @__PURE__ *
24028
24064
  );
24029
24065
  }
24030
24066
  if (branch_hit !== null) {
24031
- const peer_tree = path52.resolve(branch_hit.record.worktree ?? "");
24032
- const same_tree = peer_tree !== "" && peer_tree === path52.resolve(workspace_root);
24067
+ const peer_tree = canonical(branch_hit.record.worktree ?? "");
24068
+ const same_tree = (branch_hit.record.worktree ?? "") !== "" && peer_tree === canonical(workspace_root);
24033
24069
  if (same_tree) {
24034
24070
  parts.push(
24035
24071
  "",
@@ -25793,15 +25829,15 @@ function targets_kernel_rule(filePath) {
25793
25829
  if (segments.length === 0) {
25794
25830
  return null;
25795
25831
  }
25796
- const basename9 = segments[segments.length - 1];
25797
- if (!is_kernel_rule(basename9)) {
25832
+ const basename10 = segments[segments.length - 1];
25833
+ if (!is_kernel_rule(basename10)) {
25798
25834
  return null;
25799
25835
  }
25800
25836
  const dirSegments = segments.slice(0, -1);
25801
25837
  if (!dirSegments.includes("rules")) {
25802
25838
  return null;
25803
25839
  }
25804
- return basename9.replace(/\.md$/, "");
25840
+ return basename10.replace(/\.md$/, "");
25805
25841
  }
25806
25842
  var _MUTATOR_VERBS = /* @__PURE__ */ new Set([
25807
25843
  "sed",
@@ -26176,7 +26212,7 @@ import { fileURLToPath as fileURLToPath39, pathToFileURL as pathToFileURL32 } fr
26176
26212
  import { spawnSync as spawnSync5 } from "node:child_process";
26177
26213
  import { existsSync as existsSync11, statSync as statSync16, readFileSync as readFileSync27, writeFileSync as writeFileSync13, mkdirSync as mkdirSync15 } from "node:fs";
26178
26214
  import { homedir as homedir5 } from "node:os";
26179
- import { delimiter as delimiter2, join as join26, dirname as dirname16 } from "node:path";
26215
+ import { delimiter as delimiter2, join as join26, dirname as dirname17 } from "node:path";
26180
26216
  var TOKEN_KILLER_GAIN_SIGNATURE = /RTK Token Savings/;
26181
26217
  var PROBE_TIMEOUT_MS = 3e3;
26182
26218
  function resolveBinaryOnPath(name, pathEnv) {
@@ -26271,7 +26307,7 @@ function detectRtkCached(options = {}) {
26271
26307
  };
26272
26308
  if (detection.version !== void 0) entry.version = detection.version;
26273
26309
  try {
26274
- mkdirSync15(dirname16(file), { recursive: true });
26310
+ mkdirSync15(dirname17(file), { recursive: true });
26275
26311
  writeFileSync13(file, `${JSON.stringify(entry, null, 2)}
26276
26312
  `, "utf-8");
26277
26313
  } catch {
@@ -28063,14 +28099,14 @@ function int(flags, key) {
28063
28099
  return Number.isFinite(n) ? n : NaN;
28064
28100
  }
28065
28101
  function contentHashId(input) {
28066
- const canonical = JSON.stringify({
28102
+ const canonical2 = JSON.stringify({
28067
28103
  ts: input.ts,
28068
28104
  spawn_count: input.spawn_count,
28069
28105
  token_delta: input.token_delta,
28070
28106
  tier_chosen: input.tier_chosen ?? null,
28071
28107
  task_class: input.task_class ?? null
28072
28108
  });
28073
- return crypto7.createHash("sha256").update(canonical).digest("hex").slice(0, 26).toUpperCase();
28109
+ return crypto7.createHash("sha256").update(canonical2).digest("hex").slice(0, 26).toUpperCase();
28074
28110
  }
28075
28111
  function main41(argv = process.argv.slice(2)) {
28076
28112
  const flags = parseFlags(argv);
@@ -32017,6 +32053,8 @@ import * as path85 from "node:path";
32017
32053
  import { fileURLToPath as fileURLToPath56, pathToFileURL as pathToFileURL50 } from "node:url";
32018
32054
  var EXIT_ALLOW27 = 0;
32019
32055
  var EXIT_BLOCK5 = 1;
32056
+ var BLOCKED_BY_MARKER = /<!--\s*blocked-by:\s*\S[^>]*-->/;
32057
+ var LEDGER_TAIL_MAX_BYTES = 512 * 1024;
32020
32058
  var EVENTS_RELPATH = path85.join(
32021
32059
  "agents",
32022
32060
  "runtime",
@@ -32027,10 +32065,14 @@ var STATE_DIR_REL = path85.join("agents", "runtime", "state");
32027
32065
  var MAX_ITERATIONS = 25;
32028
32066
  var WALL_CLOCK_CAP_MS = 4 * 60 * 60 * 1e3;
32029
32067
  var STALL_WINDOW = 3;
32068
+ var ABSENT_CONFIRM_FIRES = 2;
32030
32069
  var DUPLICATE_WINDOW_MS = 60 * 1e3;
32031
- function isDuplicateFire(state, turnOrdinal, openCount, nowMs) {
32070
+ function isDuplicateFire(state, turnOrdinal, openCount, nowMs, roadmapSource) {
32032
32071
  if (state === null) return false;
32033
32072
  if (state.last_turn !== turnOrdinal) return false;
32073
+ if (state.history_source !== void 0 && roadmapSource !== void 0 && state.history_source !== roadmapSource) {
32074
+ return false;
32075
+ }
32034
32076
  if (state.history.length === 0 || state.history[state.history.length - 1] !== openCount) {
32035
32077
  return false;
32036
32078
  }
@@ -32072,7 +32114,7 @@ function scanOpenSteps(text) {
32072
32114
  }
32073
32115
  const full = step.join("\n");
32074
32116
  const body = m[1];
32075
- if (body.includes("blocked-by:")) {
32117
+ if (BLOCKED_BY_MARKER.test(body)) {
32076
32118
  blocked += 1;
32077
32119
  continue;
32078
32120
  }
@@ -32096,13 +32138,13 @@ function extractVerify(stepText) {
32096
32138
  if (backticked !== null) return backticked[1].trim() || null;
32097
32139
  return null;
32098
32140
  }
32099
- function ladder(state, openCount, nowMs, caps = {
32141
+ function ladder(state, openCount, nowMs, blockedCount, caps = {
32100
32142
  maxIterations: MAX_ITERATIONS,
32101
32143
  wallClockMs: WALL_CLOCK_CAP_MS,
32102
32144
  stallWindow: STALL_WINDOW
32103
32145
  }) {
32104
32146
  if (state.halted) return state.halted;
32105
- if (openCount === 0) return "complete";
32147
+ if (openCount === 0) return blockedCount > 0 ? "blocked" : "complete";
32106
32148
  if (state.iterations >= caps.maxIterations) return "halt-max-iterations";
32107
32149
  const started = Date.parse(state.started_at);
32108
32150
  if (Number.isFinite(started) && nowMs - started >= caps.wallClockMs) {
@@ -32114,10 +32156,57 @@ function ladder(state, openCount, nowMs, caps = {
32114
32156
  }
32115
32157
  return "engage";
32116
32158
  }
32117
- function stateRelPath(runId) {
32159
+ function stateRelPath(runId, slug) {
32160
+ const safeRun = runId.replace(/[^A-Za-z0-9_-]/g, "_");
32161
+ const safeSlug = slug.replace(/[^A-Za-z0-9_-]/g, "_");
32162
+ return path85.join(STATE_DIR_REL, `run-continuation-${safeRun}-${safeSlug}.json`);
32163
+ }
32164
+ function legacyStateRelPath(runId) {
32118
32165
  const safe = runId.replace(/[^A-Za-z0-9_-]/g, "_");
32119
32166
  return path85.join(STATE_DIR_REL, `run-continuation-${safe}.json`);
32120
32167
  }
32168
+ function readRunState(workspaceRoot2, runId, slug) {
32169
+ const keyedFile = path85.join(workspaceRoot2, stateRelPath(runId, slug));
32170
+ const keyed = readState4(keyedFile);
32171
+ if (keyed !== null) return { state: keyed, from: "keyed", keyedFile };
32172
+ if (fileExists(keyedFile)) {
32173
+ return { state: null, from: "keyed", keyedFile };
32174
+ }
32175
+ const legacy = readState4(path85.join(workspaceRoot2, legacyStateRelPath(runId)));
32176
+ if (legacy === null) return { state: null, from: "none", keyedFile };
32177
+ if (legacy.roadmap !== void 0 && legacy.roadmap !== slug) {
32178
+ return { state: null, from: "none", keyedFile };
32179
+ }
32180
+ return { state: legacy, from: "legacy", keyedFile };
32181
+ }
32182
+ function writeState3(file, state) {
32183
+ try {
32184
+ fs84.mkdirSync(path85.dirname(file), { recursive: true });
32185
+ fs84.writeFileSync(file, `${JSON.stringify(state)}
32186
+ `, "utf8");
32187
+ return true;
32188
+ } catch {
32189
+ return false;
32190
+ }
32191
+ }
32192
+ function clearRunState(workspaceRoot2, runId, keyedFile, adoptedLegacy) {
32193
+ try {
32194
+ fs84.rmSync(keyedFile, { force: true });
32195
+ } catch {
32196
+ }
32197
+ if (!adoptedLegacy) return;
32198
+ try {
32199
+ fs84.rmSync(path85.join(workspaceRoot2, legacyStateRelPath(runId)), { force: true });
32200
+ } catch {
32201
+ }
32202
+ }
32203
+ function fileExists(p) {
32204
+ try {
32205
+ return fs84.statSync(p).isFile();
32206
+ } catch {
32207
+ return false;
32208
+ }
32209
+ }
32121
32210
  function readState4(file) {
32122
32211
  try {
32123
32212
  const parsed = JSON.parse(fs84.readFileSync(file, "utf8"));
@@ -32138,6 +32227,18 @@ function readState4(file) {
32138
32227
  if (typeof o["last_engaged_at"] === "string") {
32139
32228
  rec.last_engaged_at = o["last_engaged_at"];
32140
32229
  }
32230
+ if (typeof o["history_source"] === "string") {
32231
+ rec.history_source = o["history_source"];
32232
+ }
32233
+ if (typeof o["roadmap"] === "string") {
32234
+ rec.roadmap = o["roadmap"];
32235
+ }
32236
+ if (typeof o["absent_fires"] === "number" && Number.isFinite(o["absent_fires"])) {
32237
+ rec.absent_fires = o["absent_fires"];
32238
+ }
32239
+ if (o["inert_reported"] === true) {
32240
+ rec.inert_reported = true;
32241
+ }
32141
32242
  const halted = o["halted"];
32142
32243
  if (typeof halted === "string" && HALT_ACTIONS.includes(halted)) {
32143
32244
  rec.halted = halted;
@@ -32147,14 +32248,93 @@ function readState4(file) {
32147
32248
  return null;
32148
32249
  }
32149
32250
  }
32150
- function provenance(workspaceRoot2, claimPath) {
32251
+ function normalizeDir(p) {
32252
+ const abs = path85.resolve(p);
32253
+ try {
32254
+ return fs84.realpathSync(abs);
32255
+ } catch {
32256
+ return abs;
32257
+ }
32258
+ }
32259
+ function normalizeFile(p) {
32260
+ const abs = path85.resolve(p);
32261
+ return path85.join(normalizeDir(path85.dirname(abs)), path85.basename(abs));
32262
+ }
32263
+ function provenance(workspaceRoot2, claimPath, sessionRoot, sessionCwd) {
32264
+ const reader = normalizeDir(workspaceRoot2);
32265
+ const writer = normalizeDir(sessionRoot);
32151
32266
  return {
32152
- workspace_root: workspaceRoot2,
32153
- git_dir: git_dir(workspaceRoot2) ?? "",
32154
- git_common_dir: git_common_dir(workspaceRoot2) ?? "",
32155
- claim_path: claimPath
32267
+ workspace_root: reader,
32268
+ session_root: writer,
32269
+ // Empty when the host sent no `cwd` at all, which is a different fact
32270
+ // from a `cwd` that failed resolution — the first says the host is
32271
+ // silent, the second says the session sat somewhere `session_checkout`
32272
+ // would not trust. Both are readable; neither is guessed.
32273
+ //
32274
+ // Trimmed with the SAME rule `session_checkout` applies to the same
32275
+ // string (round 3 finding 6). Without it a whitespace-padded value
32276
+ // validated fine there and was `path.resolve`d here against the reader's
32277
+ // cwd, fabricating a path that is neither `session_root` nor under it —
32278
+ // precisely the shape the docblock above says no healthy resolution
32279
+ // produces, so a healthy line read as degraded. A whitespace-only value
32280
+ // now reads as host silence, which is what it is.
32281
+ session_cwd: sessionCwd.trim() === "" ? "" : normalizeDir(sessionCwd.trim()),
32282
+ git_dir: git_dir(writer) ?? "",
32283
+ git_common_dir: git_common_dir(writer) ?? "",
32284
+ claim_path: normalizeFile(claimPath)
32156
32285
  };
32157
32286
  }
32287
+ function resolveRoadmap(sessionRoot, workspaceRoot2, slug) {
32288
+ const dirRel = path85.join("agents", "roadmaps");
32289
+ const stem = slug.trim().replace(/\.md$/, "");
32290
+ const rel = path85.join(dirRel, `${stem}.md`);
32291
+ const norm = path85.normalize(rel);
32292
+ if (path85.dirname(norm) !== dirRel) return null;
32293
+ if (sessionRoot !== workspaceRoot2 && isDirectory(path85.join(sessionRoot, dirRel))) {
32294
+ return path85.join(sessionRoot, norm);
32295
+ }
32296
+ return path85.join(normalizeDir(workspaceRoot2), norm);
32297
+ }
32298
+ function isDirectory(p) {
32299
+ try {
32300
+ return fs84.statSync(p).isDirectory();
32301
+ } catch {
32302
+ return false;
32303
+ }
32304
+ }
32305
+ function eventAlreadyLogged(workspaceRoot2, runId, slug, event) {
32306
+ try {
32307
+ const file = path85.join(workspaceRoot2, EVENTS_RELPATH);
32308
+ const size = fs84.statSync(file).size;
32309
+ const start = Math.max(0, size - LEDGER_TAIL_MAX_BYTES);
32310
+ const fd = fs84.openSync(file, "r");
32311
+ let text;
32312
+ try {
32313
+ const buf = Buffer.alloc(size - start);
32314
+ const read = fs84.readSync(fd, buf, 0, buf.length, start);
32315
+ text = buf.subarray(0, read).toString("utf8");
32316
+ } finally {
32317
+ fs84.closeSync(fd);
32318
+ }
32319
+ for (const line of text.split("\n")) {
32320
+ if (line === "") continue;
32321
+ let rec;
32322
+ try {
32323
+ rec = JSON.parse(line);
32324
+ } catch {
32325
+ continue;
32326
+ }
32327
+ if (rec === null || typeof rec !== "object") continue;
32328
+ const o = rec;
32329
+ if (o["event"] === event && o["run_id"] === runId && o["roadmap"] === slug) {
32330
+ return true;
32331
+ }
32332
+ }
32333
+ return false;
32334
+ } catch {
32335
+ return false;
32336
+ }
32337
+ }
32158
32338
  function appendEvent2(workspaceRoot2, record) {
32159
32339
  try {
32160
32340
  const file = path85.join(workspaceRoot2, EVENTS_RELPATH);
@@ -32191,12 +32371,57 @@ function main55() {
32191
32371
  const claim = resolve_claim(workspaceRoot2, sessionId2 || null);
32192
32372
  if (claim === null) return EXIT_ALLOW27;
32193
32373
  const slug = claim.slug;
32194
- const roots = provenance(workspaceRoot2, claim.path);
32195
- const roadmapPath2 = path85.join(workspaceRoot2, "agents", "roadmaps", `${slug}.md`);
32196
- let roadmapText;
32197
- try {
32198
- roadmapText = fs84.readFileSync(roadmapPath2, "utf8");
32199
- } catch {
32374
+ const sessionRoot = session_checkout(
32375
+ workspaceRoot2,
32376
+ str10(payload["cwd"])
32377
+ );
32378
+ const roadmapPath2 = resolveRoadmap(sessionRoot, workspaceRoot2, slug);
32379
+ const runId = deriveSessionKey(sessionId2 || "unknown-session");
32380
+ let roadmapFile = null;
32381
+ let roadmapText = null;
32382
+ if (roadmapPath2 !== null) {
32383
+ try {
32384
+ roadmapText = fs84.readFileSync(roadmapPath2, "utf8");
32385
+ roadmapFile = roadmapPath2;
32386
+ } catch {
32387
+ roadmapText = null;
32388
+ }
32389
+ }
32390
+ if (roadmapText === null || roadmapFile === null) {
32391
+ const runState = readRunState(workspaceRoot2, runId, slug);
32392
+ const driven = runState.state;
32393
+ if (driven === null && runState.from === "none") return EXIT_ALLOW27;
32394
+ if (driven?.halted !== void 0) return EXIT_ALLOW27;
32395
+ const absenceRoots = provenance(
32396
+ workspaceRoot2,
32397
+ claim.path,
32398
+ sessionRoot,
32399
+ str10(payload["cwd"])
32400
+ );
32401
+ absenceRoots["roadmap_path"] = roadmapPath2;
32402
+ const absentFires = (driven?.absent_fires ?? 0) + 1;
32403
+ const firstAbsence = driven === null ? !eventAlreadyLogged(workspaceRoot2, runId, slug, "halt-roadmap-absent") : absentFires === 1;
32404
+ if (firstAbsence) {
32405
+ appendEvent2(workspaceRoot2, {
32406
+ event: "halt-roadmap-absent",
32407
+ run_id: runId,
32408
+ roadmap: slug,
32409
+ // `null` when the state file exists but could not be parsed.
32410
+ // Reported as null rather than as 0, which would claim a fact the
32411
+ // file no longer carries.
32412
+ iterations: driven?.iterations ?? null,
32413
+ absent_fires: driven === null ? null : absentFires,
32414
+ at: (/* @__PURE__ */ new Date()).toISOString(),
32415
+ ...absenceRoots
32416
+ });
32417
+ }
32418
+ if (driven === null) return EXIT_ALLOW27;
32419
+ if (absentFires < ABSENT_CONFIRM_FIRES) {
32420
+ driven.absent_fires = absentFires;
32421
+ writeState3(runState.keyedFile, driven);
32422
+ return EXIT_ALLOW27;
32423
+ }
32424
+ clearRunState(workspaceRoot2, runId, runState.keyedFile, runState.from === "legacy");
32200
32425
  return EXIT_ALLOW27;
32201
32426
  }
32202
32427
  if (parseExecutionMode(roadmapText) !== "autonomous") return EXIT_ALLOW27;
@@ -32205,7 +32430,29 @@ function main55() {
32205
32430
  );
32206
32431
  if (!transcriptPath) return EXIT_ALLOW27;
32207
32432
  try {
32208
- if (fs84.statSync(transcriptPath).size > TRANSCRIPT_READ_MAX_BYTES) return EXIT_ALLOW27;
32433
+ if (fs84.statSync(transcriptPath).size > TRANSCRIPT_READ_MAX_BYTES) {
32434
+ const inert = readRunState(workspaceRoot2, runId, slug);
32435
+ if (inert.state !== null && inert.state.inert_reported !== true) {
32436
+ const inertRoots = provenance(
32437
+ workspaceRoot2,
32438
+ claim.path,
32439
+ sessionRoot,
32440
+ str10(payload["cwd"])
32441
+ );
32442
+ inertRoots["roadmap_path"] = roadmapFile;
32443
+ appendEvent2(workspaceRoot2, {
32444
+ event: "inert-transcript-over-cap",
32445
+ run_id: runId,
32446
+ roadmap: slug,
32447
+ iterations: inert.state.iterations,
32448
+ at: (/* @__PURE__ */ new Date()).toISOString(),
32449
+ ...inertRoots
32450
+ });
32451
+ inert.state.inert_reported = true;
32452
+ writeState3(inert.keyedFile, inert.state);
32453
+ }
32454
+ return EXIT_ALLOW27;
32455
+ }
32209
32456
  } catch {
32210
32457
  return EXIT_ALLOW27;
32211
32458
  }
@@ -32217,7 +32464,13 @@ function main55() {
32217
32464
  } catch {
32218
32465
  return EXIT_ALLOW27;
32219
32466
  }
32220
- const runId = deriveSessionKey(sessionId2 || "unknown-session");
32467
+ const roots = provenance(
32468
+ workspaceRoot2,
32469
+ claim.path,
32470
+ sessionRoot,
32471
+ str10(payload["cwd"])
32472
+ );
32473
+ roots["roadmap_path"] = roadmapFile;
32221
32474
  if (refusedThisTurn(workspaceRoot2, sessionId2, turnOrdinal)) {
32222
32475
  appendEvent2(workspaceRoot2, {
32223
32476
  event: "deferred-quality-gate",
@@ -32229,47 +32482,55 @@ function main55() {
32229
32482
  });
32230
32483
  return EXIT_ALLOW27;
32231
32484
  }
32232
- const stateFile4 = path85.join(workspaceRoot2, stateRelPath(runId));
32233
- const prev = readState4(stateFile4);
32485
+ const mainState = readRunState(workspaceRoot2, runId, slug);
32486
+ const stateFile4 = mainState.keyedFile;
32487
+ const prev = mainState.state;
32234
32488
  const state = prev ?? {
32235
32489
  started_at: (/* @__PURE__ */ new Date()).toISOString(),
32236
32490
  iterations: 0,
32237
32491
  last_turn: -1,
32238
- history: []
32492
+ history: [],
32493
+ roadmap: slug
32239
32494
  };
32495
+ state.roadmap = slug;
32496
+ delete state.absent_fires;
32240
32497
  const scan = scanOpenSteps(roadmapText);
32241
- if (isDuplicateFire(prev, turnOrdinal, scan.open, Date.now())) {
32498
+ if (isDuplicateFire(prev, turnOrdinal, scan.open, Date.now(), roadmapFile)) {
32242
32499
  process.stderr.write(_continuationText(slug, scan, state.iterations));
32243
32500
  return EXIT_BLOCK5;
32244
32501
  }
32245
- const action = ladder(state, scan.open, Date.now());
32502
+ if (state.history_source !== roadmapFile) {
32503
+ state.history = [];
32504
+ state.history_source = roadmapFile;
32505
+ }
32506
+ const action = ladder(state, scan.open, Date.now(), scan.blocked);
32246
32507
  if (action !== "engage") {
32247
- appendEvent2(workspaceRoot2, {
32248
- event: action,
32249
- run_id: runId,
32250
- roadmap: slug,
32251
- turn: turnOrdinal,
32252
- iterations: state.iterations,
32253
- open: scan.open,
32254
- blocked: scan.blocked,
32255
- at: (/* @__PURE__ */ new Date()).toISOString(),
32256
- ...roots
32257
- });
32508
+ const alreadyStamped = prev?.halted !== void 0;
32509
+ const alreadyBlocked = action === "blocked" && eventAlreadyLogged(workspaceRoot2, runId, slug, "blocked");
32510
+ if (!alreadyStamped && !alreadyBlocked) {
32511
+ appendEvent2(workspaceRoot2, {
32512
+ event: action,
32513
+ run_id: runId,
32514
+ roadmap: slug,
32515
+ turn: turnOrdinal,
32516
+ iterations: state.iterations,
32517
+ open: scan.open,
32518
+ blocked: scan.blocked,
32519
+ at: (/* @__PURE__ */ new Date()).toISOString(),
32520
+ ...roots
32521
+ });
32522
+ }
32258
32523
  if (action === "complete") {
32259
- try {
32260
- fs84.rmSync(stateFile4, { force: true });
32261
- } catch {
32262
- }
32524
+ clearRunState(workspaceRoot2, runId, stateFile4, mainState.from === "legacy");
32525
+ return EXIT_ALLOW27;
32526
+ }
32527
+ if (action === "blocked") {
32528
+ clearRunState(workspaceRoot2, runId, stateFile4, mainState.from === "legacy");
32263
32529
  return EXIT_ALLOW27;
32264
32530
  }
32265
32531
  if (!state.halted) {
32266
32532
  state.halted = action;
32267
- try {
32268
- fs84.mkdirSync(path85.dirname(stateFile4), { recursive: true });
32269
- fs84.writeFileSync(stateFile4, `${JSON.stringify(state)}
32270
- `, "utf8");
32271
- } catch {
32272
- }
32533
+ writeState3(stateFile4, state);
32273
32534
  }
32274
32535
  return EXIT_ALLOW27;
32275
32536
  }
@@ -32277,11 +32538,7 @@ function main55() {
32277
32538
  state.last_turn = turnOrdinal;
32278
32539
  state.history.push(scan.open);
32279
32540
  state.last_engaged_at = (/* @__PURE__ */ new Date()).toISOString();
32280
- try {
32281
- fs84.mkdirSync(path85.dirname(stateFile4), { recursive: true });
32282
- fs84.writeFileSync(stateFile4, `${JSON.stringify(state)}
32283
- `, "utf8");
32284
- } catch {
32541
+ if (!writeState3(stateFile4, state)) {
32285
32542
  return EXIT_ALLOW27;
32286
32543
  }
32287
32544
  appendEvent2(workspaceRoot2, {
@@ -3,13 +3,13 @@
3
3
  "artefact_count": 609,
4
4
  "scanner_version": "de0a22b4ac4c"
5
5
  },
6
- "generated_at": "2026-08-19",
6
+ "generated_at": "2026-08-20",
7
7
  "package": {
8
8
  "description": "Governed skills, rules and commands for AI coding tools (Claude Code, Cursor, Windsurf, Copilot) \u2014 every claim machine-checked, including \"zero runtime daemon\".",
9
9
  "homepage": "https://event4u-app.github.io/agent-config",
10
10
  "name": "@event4u/agent-config",
11
11
  "repository": "https://github.com/event4u-app/agent-config",
12
- "version": "14.5.0"
12
+ "version": "14.6.0"
13
13
  },
14
14
  "registries": [
15
15
  {
@@ -9,12 +9,12 @@
9
9
  "transport": {
10
10
  "type": "stdio"
11
11
  },
12
- "version": "14.5.0"
12
+ "version": "14.6.0"
13
13
  }
14
14
  ],
15
15
  "repository": {
16
16
  "source": "github",
17
17
  "url": "https://github.com/event4u-app/agent-config"
18
18
  },
19
- "version": "14.5.0"
19
+ "version": "14.6.0"
20
20
  }