@event4u/agent-config 14.4.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 (48) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/CHANGELOG.md +132 -291
  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 +419 -94
  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 +36 -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/bench_hook_injection.ts +18 -1
  38. package/src/scripts/check_adr_frontmatter.ts +187 -1
  39. package/src/scripts/check_single_delivery.ts +473 -0
  40. package/src/scripts/hooks/host_semantics.ts +28 -0
  41. package/src/scripts/hooks/injection_budget.ts +152 -16
  42. package/src/scripts/hooks/run_continuation_hook.ts +918 -46
  43. package/src/scripts/install.sh +12 -2
  44. package/src/scripts/memory_consolidation.ts +189 -0
  45. package/src/scripts/memory_eviction.ts +384 -0
  46. package/src/scripts/report_layer_overlap.ts +72 -0
  47. package/src/scripts/report_memory_pointers.ts +622 -0
  48. package/src/scripts/session_register_hook.ts +144 -21
@@ -7765,6 +7765,10 @@ function claudeAdditionalContext(event, text) {
7765
7765
  })}
7766
7766
  `;
7767
7767
  }
7768
+ function emissionCarriesReasons(platform, severity) {
7769
+ if (!VERIFIED_PLATFORMS.has(platform)) return false;
7770
+ return severity !== "allow";
7771
+ }
7768
7772
  function emitFor(platform, event, severity, reasons, legacyExit) {
7769
7773
  if (!VERIFIED_PLATFORMS.has(platform)) {
7770
7774
  return { exit: legacyExit, stdout: "", stderr: "" };
@@ -7790,6 +7794,13 @@ function emitFor(platform, event, severity, reasons, legacyExit) {
7790
7794
 
7791
7795
  // src/scripts/hooks/injection_budget.ts
7792
7796
  var TURN_START_EVENT = "user_prompt_submit";
7797
+ var RC_ALLOW = 0;
7798
+ var RC_WARN = 2;
7799
+ function _severityForRc(rc) {
7800
+ if (rc === RC_ALLOW) return "allow";
7801
+ if (rc === RC_WARN) return "warn";
7802
+ return "block";
7803
+ }
7793
7804
  function isExempt(c) {
7794
7805
  if (c.failClosed) return true;
7795
7806
  return c.severity.trim().toLowerCase() !== "advisory";
@@ -7870,13 +7881,43 @@ function shapeEmissions(candidates, opts) {
7870
7881
  ceilingCause
7871
7882
  };
7872
7883
  }
7873
- var TURN_SPEND_BASENAME = "injection-turn.json";
7874
- function turnSpendPath(workspaceRoot2) {
7875
- return path3.join(workspaceRoot2, "agents", "runtime", "state", TURN_SPEND_BASENAME);
7884
+ var TURN_SPEND_DIR_REL = path3.join("agents", "runtime", "state", "injection-turn");
7885
+ var TURN_SPEND_MAX_FILES = 64;
7886
+ function turnSpendKey(session) {
7887
+ const safe = session.replace(/[^A-Za-z0-9._-]/g, "_");
7888
+ let h = 2166136261;
7889
+ for (let i = 0; i < session.length; i += 1) {
7890
+ h ^= session.charCodeAt(i);
7891
+ h = Math.imul(h, 16777619) >>> 0;
7892
+ }
7893
+ const digest = h.toString(16).padStart(8, "0");
7894
+ return `${safe.slice(0, 96)}.${digest}`;
7895
+ }
7896
+ function turnSpendPath(workspaceRoot2, session) {
7897
+ return path3.join(workspaceRoot2, TURN_SPEND_DIR_REL, `${turnSpendKey(session)}.json`);
7898
+ }
7899
+ function _pruneTurnSpend(dir) {
7900
+ try {
7901
+ const entries = fs3.readdirSync(dir).filter((n) => n.endsWith(".json") || n.endsWith(".tmp")).map((n) => {
7902
+ const p = path3.join(dir, n);
7903
+ try {
7904
+ return { p, mtime: fs3.statSync(p).mtimeMs };
7905
+ } catch {
7906
+ return { p, mtime: 0 };
7907
+ }
7908
+ }).sort((a, b) => b.mtime - a.mtime);
7909
+ for (const stale of entries.slice(TURN_SPEND_MAX_FILES)) {
7910
+ try {
7911
+ fs3.unlinkSync(stale.p);
7912
+ } catch {
7913
+ }
7914
+ }
7915
+ } catch {
7916
+ }
7876
7917
  }
7877
7918
  function readTurnSpend(workspaceRoot2, session) {
7878
7919
  try {
7879
- const raw = fs3.readFileSync(turnSpendPath(workspaceRoot2), "utf-8");
7920
+ const raw = fs3.readFileSync(turnSpendPath(workspaceRoot2, session), "utf-8");
7880
7921
  const parsed = JSON.parse(raw);
7881
7922
  if (parsed.session !== session) return 0;
7882
7923
  return typeof parsed.bytes === "number" && Number.isFinite(parsed.bytes) && parsed.bytes >= 0 ? parsed.bytes : 0;
@@ -7889,9 +7930,13 @@ function recordTurnSpend(workspaceRoot2, session, bytes, opts = {}) {
7889
7930
  const previous = opts.reset === true ? 0 : readTurnSpend(workspaceRoot2, session);
7890
7931
  const entry = { session, bytes: previous + Math.max(0, bytes) };
7891
7932
  try {
7892
- const target = turnSpendPath(workspaceRoot2);
7893
- fs3.mkdirSync(path3.dirname(target), { recursive: true });
7894
- fs3.writeFileSync(target, JSON.stringify(entry) + "\n", { encoding: "utf-8" });
7933
+ const target = turnSpendPath(workspaceRoot2, session);
7934
+ const dir = path3.dirname(target);
7935
+ fs3.mkdirSync(dir, { recursive: true });
7936
+ const tmp = `${target}.${String(process.pid)}.tmp`;
7937
+ fs3.writeFileSync(tmp, JSON.stringify(entry) + "\n", { encoding: "utf-8" });
7938
+ fs3.renameSync(tmp, target);
7939
+ _pruneTurnSpend(dir);
7895
7940
  } catch {
7896
7941
  }
7897
7942
  }
@@ -7957,12 +8002,15 @@ function shapeAndRecord(ctx, messages, finalRc) {
7957
8002
  nudgeRank: typeof rank2 === "number" ? rank2 : null
7958
8003
  };
7959
8004
  });
7960
- if (!VERIFIED_PLATFORMS.has(ctx.platform)) {
7961
- return textOf(new Set(candidates.map((c) => c.concern)));
7962
- }
7963
8005
  const workspaceRoot2 = _workspaceRoot(ctx);
7964
8006
  const sessionKey = _sessionKey(ctx) ?? "";
7965
8007
  const cap = resolveVolumeCap(ctx);
8008
+ if (!emissionCarriesReasons(ctx.platform, _severityForRc(finalRc))) {
8009
+ if (cap !== null && ctx.event === TURN_START_EVENT) {
8010
+ recordTurnSpend(workspaceRoot2, sessionKey, 0, { reset: true });
8011
+ }
8012
+ return textOf(new Set(candidates.map((c) => c.concern)));
8013
+ }
7966
8014
  const turnStartsHere = ctx.event === TURN_START_EVENT;
7967
8015
  const spentBefore = cap === null || turnStartsHere ? 0 : readTurnSpend(workspaceRoot2, sessionKey);
7968
8016
  const shaped = shapeEmissions(candidates, { capBytes: cap, spentBytes: spentBefore });
@@ -11873,9 +11921,9 @@ function user_global_settings_paths() {
11873
11921
  if (flat !== null) {
11874
11922
  paths.push(flat);
11875
11923
  }
11876
- const canonical = resolve_with_fallback(USER_GLOBAL_CANONICAL_RELATIVE);
11877
- if (canonical !== null) {
11878
- paths.push(canonical);
11924
+ const canonical2 = resolve_with_fallback(USER_GLOBAL_CANONICAL_RELATIVE);
11925
+ if (canonical2 !== null) {
11926
+ paths.push(canonical2);
11879
11927
  }
11880
11928
  if (paths.length === 0) {
11881
11929
  paths.push(DEFAULT_USER_GLOBAL_FILE());
@@ -18070,6 +18118,20 @@ var CAPSULE_SCHEMA_VERSION = 3;
18070
18118
  function isShortLine(value, max) {
18071
18119
  return typeof value === "string" && value.length > 0 && value.length <= max && !value.includes("\n");
18072
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
+ }
18073
18135
  function checkList(errors, field, value, max, required) {
18074
18136
  if (value === void 0) {
18075
18137
  if (required) errors.push(`${field} is required`);
@@ -18259,7 +18321,7 @@ function validateRecycleEnvelope(input) {
18259
18321
  checkList(errors, "decisions", e["decisions"], MAX_LINE_CHARS, false);
18260
18322
  errors.push(...decisionTagErrors(e["decisions"]));
18261
18323
  checkList(errors, "constraints", e["constraints"], MAX_LINE_CHARS, false);
18262
- 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);
18263
18325
  checkList(errors, "open_worker_envelopes", e["open_worker_envelopes"], MAX_REF_CHARS, false);
18264
18326
  checkList(errors, "artifact_paths", e["artifact_paths"], MAX_REF_CHARS, false);
18265
18327
  checkList(errors, "suggested_skills", e["suggested_skills"], MAX_REF_CHARS, false);
@@ -20813,11 +20875,11 @@ function refresh_precommit_hook(root) {
20813
20875
  if (!current.includes(_PRECOMMIT_MARKER)) {
20814
20876
  return null;
20815
20877
  }
20816
- const canonical = fs35.readFileSync(template, "utf-8");
20817
- if (current === canonical) {
20878
+ const canonical2 = fs35.readFileSync(template, "utf-8");
20879
+ if (current === canonical2) {
20818
20880
  return null;
20819
20881
  }
20820
- fs35.writeFileSync(target, canonical);
20882
+ fs35.writeFileSync(target, canonical2);
20821
20883
  fs35.chmodSync(target, 493);
20822
20884
  return target;
20823
20885
  } catch {
@@ -21405,15 +21467,15 @@ function _load_config_fail_open() {
21405
21467
  var _CODEX_PLUGIN_DATA_DIRNAME = `${CODEX_PLUGIN_ID}-${CODEX_MARKETPLACE_NAME}`;
21406
21468
  var UPSTREAM_GATE_JOB_TITLE = "Codex Stop Gate Review";
21407
21469
  function _workspace_state_segment(workspace_root) {
21408
- let canonical = workspace_root;
21470
+ let canonical2 = workspace_root;
21409
21471
  try {
21410
- canonical = fs37.realpathSync.native(workspace_root);
21472
+ canonical2 = fs37.realpathSync.native(workspace_root);
21411
21473
  } catch {
21412
- canonical = workspace_root;
21474
+ canonical2 = workspace_root;
21413
21475
  }
21414
21476
  const slug_source = path38.basename(workspace_root) || "workspace";
21415
21477
  const slug = slug_source.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "workspace";
21416
- 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);
21417
21479
  return `${slug}-${hash}`;
21418
21480
  }
21419
21481
  function upstream_state_dir_candidates(workspace_root) {
@@ -21913,9 +21975,9 @@ function resolveAvailability(cwd, env) {
21913
21975
  return null;
21914
21976
  }
21915
21977
  const exists = fs41.existsSync(p);
21916
- const provenance = env[COUNCIL_CONFIG_ENV] ? "env-override" : "user-global";
21978
+ const provenance2 = env[COUNCIL_CONFIG_ENV] ? "env-override" : "user-global";
21917
21979
  if (!exists) {
21918
- return { configured: false, path: p, exists: false, provenance, membersEnabled: 0, memberNames: [] };
21980
+ return { configured: false, path: p, exists: false, provenance: provenance2, membersEnabled: 0, memberNames: [] };
21919
21981
  }
21920
21982
  try {
21921
21983
  const cfg = load_council_config(p);
@@ -21924,12 +21986,12 @@ function resolveAvailability(cwd, env) {
21924
21986
  configured: cfg.enabled && enabled4.length > 0,
21925
21987
  path: p,
21926
21988
  exists: true,
21927
- provenance,
21989
+ provenance: provenance2,
21928
21990
  membersEnabled: enabled4.length,
21929
21991
  memberNames: enabled4
21930
21992
  };
21931
21993
  } catch {
21932
- return { configured: false, path: p, exists: true, provenance, membersEnabled: 0, memberNames: [] };
21994
+ return { configured: false, path: p, exists: true, provenance: provenance2, membersEnabled: 0, memberNames: [] };
21933
21995
  }
21934
21996
  }
21935
21997
  function buildFact(a) {
@@ -23828,20 +23890,24 @@ function _read_claim_file(file) {
23828
23890
  return null;
23829
23891
  }
23830
23892
  }
23831
- function read_claimed_slug(workspace_root, session_id) {
23893
+ function resolve_claim(workspace_root, session_id) {
23832
23894
  const own = roadmap_claim_rel(session_id);
23833
23895
  if (own !== ROADMAP_CLAIM_REL) {
23834
23896
  for (const p of claim_read_paths(workspace_root, session_id)) {
23835
23897
  if (path52.basename(p) === path52.basename(ROADMAP_CLAIM_REL)) continue;
23836
23898
  const mine = _read_claim_file(p);
23837
- if (mine !== null) return mine.slug;
23899
+ if (mine !== null) return { slug: mine.slug, path: p };
23838
23900
  }
23839
23901
  }
23840
23902
  let legacy = null;
23903
+ let legacy_path = "";
23841
23904
  for (const p of claim_read_paths(workspace_root, session_id)) {
23842
23905
  if (path52.basename(p) !== path52.basename(ROADMAP_CLAIM_REL)) continue;
23843
23906
  legacy = _read_claim_file(p);
23844
- if (legacy !== null) break;
23907
+ if (legacy !== null) {
23908
+ legacy_path = p;
23909
+ break;
23910
+ }
23845
23911
  }
23846
23912
  if (legacy === null) {
23847
23913
  return null;
@@ -23850,7 +23916,10 @@ function read_claimed_slug(workspace_root, session_id) {
23850
23916
  if (id !== "") {
23851
23917
  return null;
23852
23918
  }
23853
- return legacy.slug;
23919
+ return { slug: legacy.slug, path: legacy_path };
23920
+ }
23921
+ function read_claimed_slug(workspace_root, session_id) {
23922
+ return resolve_claim(workspace_root, session_id)?.slug ?? null;
23854
23923
  }
23855
23924
  function claim_is_stale(workspace_root, slug, peer_worktree) {
23856
23925
  if (slug === null || slug.trim() === "") {
@@ -23858,7 +23927,7 @@ function claim_is_stale(workspace_root, slug, peer_worktree) {
23858
23927
  }
23859
23928
  const base = slug.trim().replace(/\.md$/, "");
23860
23929
  const rel = path52.normalize(path52.join("agents", "roadmaps", `${base}.md`));
23861
- const inside = rel.startsWith(`agents${path52.sep}roadmaps${path52.sep}`) && !rel.includes("..");
23930
+ const inside = path52.dirname(rel) === path52.join("agents", "roadmaps");
23862
23931
  if (!inside || path52.isAbsolute(base)) {
23863
23932
  return true;
23864
23933
  }
@@ -23877,18 +23946,40 @@ function claim_is_stale(workspace_root, slug, peer_worktree) {
23877
23946
  return true;
23878
23947
  }
23879
23948
  function session_checkout(workspace_root, payload_cwd) {
23949
+ const fallback = canonical(workspace_root);
23880
23950
  const cwd = String(payload_cwd ?? "").trim();
23881
- if (cwd === "") return workspace_root;
23951
+ if (cwd === "") return fallback;
23952
+ let start;
23882
23953
  try {
23883
- if (!fs52.statSync(cwd).isDirectory()) return workspace_root;
23954
+ if (!fs52.statSync(cwd).isDirectory()) return fallback;
23955
+ start = fs52.realpathSync(cwd);
23884
23956
  } catch {
23885
- return workspace_root;
23957
+ return fallback;
23886
23958
  }
23887
- if (git_dir(cwd) === null) return workspace_root;
23888
- 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);
23889
23962
  const theirs = git_common_dir(workspace_root);
23890
- if (mine === null || theirs === null || mine !== theirs) return workspace_root;
23891
- 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;
23892
23983
  }
23893
23984
  function build_record(workspace_root, session_id, platform, started_at, now = /* @__PURE__ */ new Date()) {
23894
23985
  const rec = {
@@ -23973,8 +24064,8 @@ function foreign_sessions_block(workspace_root, session_id, now = /* @__PURE__ *
23973
24064
  );
23974
24065
  }
23975
24066
  if (branch_hit !== null) {
23976
- const peer_tree = path52.resolve(branch_hit.record.worktree ?? "");
23977
- 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);
23978
24069
  if (same_tree) {
23979
24070
  parts.push(
23980
24071
  "",
@@ -25738,15 +25829,15 @@ function targets_kernel_rule(filePath) {
25738
25829
  if (segments.length === 0) {
25739
25830
  return null;
25740
25831
  }
25741
- const basename9 = segments[segments.length - 1];
25742
- if (!is_kernel_rule(basename9)) {
25832
+ const basename10 = segments[segments.length - 1];
25833
+ if (!is_kernel_rule(basename10)) {
25743
25834
  return null;
25744
25835
  }
25745
25836
  const dirSegments = segments.slice(0, -1);
25746
25837
  if (!dirSegments.includes("rules")) {
25747
25838
  return null;
25748
25839
  }
25749
- return basename9.replace(/\.md$/, "");
25840
+ return basename10.replace(/\.md$/, "");
25750
25841
  }
25751
25842
  var _MUTATOR_VERBS = /* @__PURE__ */ new Set([
25752
25843
  "sed",
@@ -26119,9 +26210,9 @@ import { fileURLToPath as fileURLToPath39, pathToFileURL as pathToFileURL32 } fr
26119
26210
 
26120
26211
  // src/install/rtkDetection.ts
26121
26212
  import { spawnSync as spawnSync5 } from "node:child_process";
26122
- import { existsSync as existsSync11, statSync as statSync15, readFileSync as readFileSync27, writeFileSync as writeFileSync13, mkdirSync as mkdirSync15 } from "node:fs";
26213
+ import { existsSync as existsSync11, statSync as statSync16, readFileSync as readFileSync27, writeFileSync as writeFileSync13, mkdirSync as mkdirSync15 } from "node:fs";
26123
26214
  import { homedir as homedir5 } from "node:os";
26124
- 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";
26125
26216
  var TOKEN_KILLER_GAIN_SIGNATURE = /RTK Token Savings/;
26126
26217
  var PROBE_TIMEOUT_MS = 3e3;
26127
26218
  function resolveBinaryOnPath(name, pathEnv) {
@@ -26190,7 +26281,7 @@ function detectRtkCached(options = {}) {
26190
26281
  if (binPath === null) return { present: false };
26191
26282
  let stat = null;
26192
26283
  try {
26193
- const st = statSync15(binPath);
26284
+ const st = statSync16(binPath);
26194
26285
  stat = { mtimeMs: st.mtimeMs, size: st.size };
26195
26286
  } catch {
26196
26287
  stat = null;
@@ -26216,7 +26307,7 @@ function detectRtkCached(options = {}) {
26216
26307
  };
26217
26308
  if (detection.version !== void 0) entry.version = detection.version;
26218
26309
  try {
26219
- mkdirSync15(dirname16(file), { recursive: true });
26310
+ mkdirSync15(dirname17(file), { recursive: true });
26220
26311
  writeFileSync13(file, `${JSON.stringify(entry, null, 2)}
26221
26312
  `, "utf-8");
26222
26313
  } catch {
@@ -28008,14 +28099,14 @@ function int(flags, key) {
28008
28099
  return Number.isFinite(n) ? n : NaN;
28009
28100
  }
28010
28101
  function contentHashId(input) {
28011
- const canonical = JSON.stringify({
28102
+ const canonical2 = JSON.stringify({
28012
28103
  ts: input.ts,
28013
28104
  spawn_count: input.spawn_count,
28014
28105
  token_delta: input.token_delta,
28015
28106
  tier_chosen: input.tier_chosen ?? null,
28016
28107
  task_class: input.task_class ?? null
28017
28108
  });
28018
- 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();
28019
28110
  }
28020
28111
  function main41(argv = process.argv.slice(2)) {
28021
28112
  const flags = parseFlags(argv);
@@ -31962,6 +32053,8 @@ import * as path85 from "node:path";
31962
32053
  import { fileURLToPath as fileURLToPath56, pathToFileURL as pathToFileURL50 } from "node:url";
31963
32054
  var EXIT_ALLOW27 = 0;
31964
32055
  var EXIT_BLOCK5 = 1;
32056
+ var BLOCKED_BY_MARKER = /<!--\s*blocked-by:\s*\S[^>]*-->/;
32057
+ var LEDGER_TAIL_MAX_BYTES = 512 * 1024;
31965
32058
  var EVENTS_RELPATH = path85.join(
31966
32059
  "agents",
31967
32060
  "runtime",
@@ -31972,10 +32065,14 @@ var STATE_DIR_REL = path85.join("agents", "runtime", "state");
31972
32065
  var MAX_ITERATIONS = 25;
31973
32066
  var WALL_CLOCK_CAP_MS = 4 * 60 * 60 * 1e3;
31974
32067
  var STALL_WINDOW = 3;
32068
+ var ABSENT_CONFIRM_FIRES = 2;
31975
32069
  var DUPLICATE_WINDOW_MS = 60 * 1e3;
31976
- function isDuplicateFire(state, turnOrdinal, openCount, nowMs) {
32070
+ function isDuplicateFire(state, turnOrdinal, openCount, nowMs, roadmapSource) {
31977
32071
  if (state === null) return false;
31978
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
+ }
31979
32076
  if (state.history.length === 0 || state.history[state.history.length - 1] !== openCount) {
31980
32077
  return false;
31981
32078
  }
@@ -32017,7 +32114,7 @@ function scanOpenSteps(text) {
32017
32114
  }
32018
32115
  const full = step.join("\n");
32019
32116
  const body = m[1];
32020
- if (body.includes("blocked-by:")) {
32117
+ if (BLOCKED_BY_MARKER.test(body)) {
32021
32118
  blocked += 1;
32022
32119
  continue;
32023
32120
  }
@@ -32041,13 +32138,13 @@ function extractVerify(stepText) {
32041
32138
  if (backticked !== null) return backticked[1].trim() || null;
32042
32139
  return null;
32043
32140
  }
32044
- function ladder(state, openCount, nowMs, caps = {
32141
+ function ladder(state, openCount, nowMs, blockedCount, caps = {
32045
32142
  maxIterations: MAX_ITERATIONS,
32046
32143
  wallClockMs: WALL_CLOCK_CAP_MS,
32047
32144
  stallWindow: STALL_WINDOW
32048
32145
  }) {
32049
32146
  if (state.halted) return state.halted;
32050
- if (openCount === 0) return "complete";
32147
+ if (openCount === 0) return blockedCount > 0 ? "blocked" : "complete";
32051
32148
  if (state.iterations >= caps.maxIterations) return "halt-max-iterations";
32052
32149
  const started = Date.parse(state.started_at);
32053
32150
  if (Number.isFinite(started) && nowMs - started >= caps.wallClockMs) {
@@ -32059,10 +32156,57 @@ function ladder(state, openCount, nowMs, caps = {
32059
32156
  }
32060
32157
  return "engage";
32061
32158
  }
32062
- 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) {
32063
32165
  const safe = runId.replace(/[^A-Za-z0-9_-]/g, "_");
32064
32166
  return path85.join(STATE_DIR_REL, `run-continuation-${safe}.json`);
32065
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
+ }
32066
32210
  function readState4(file) {
32067
32211
  try {
32068
32212
  const parsed = JSON.parse(fs84.readFileSync(file, "utf8"));
@@ -32083,6 +32227,18 @@ function readState4(file) {
32083
32227
  if (typeof o["last_engaged_at"] === "string") {
32084
32228
  rec.last_engaged_at = o["last_engaged_at"];
32085
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
+ }
32086
32242
  const halted = o["halted"];
32087
32243
  if (typeof halted === "string" && HALT_ACTIONS.includes(halted)) {
32088
32244
  rec.halted = halted;
@@ -32092,6 +32248,93 @@ function readState4(file) {
32092
32248
  return null;
32093
32249
  }
32094
32250
  }
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);
32266
+ return {
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)
32285
+ };
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
+ }
32095
32338
  function appendEvent2(workspaceRoot2, record) {
32096
32339
  try {
32097
32340
  const file = path85.join(workspaceRoot2, EVENTS_RELPATH);
@@ -32125,13 +32368,60 @@ function main55() {
32125
32368
  }
32126
32369
  const workspaceRoot2 = str10(envelope["workspace_root"]) || process.cwd();
32127
32370
  const sessionId2 = str10(payload["session_id"]) || str10(envelope["session_id"]);
32128
- const slug = read_claimed_slug(workspaceRoot2, sessionId2 || null);
32129
- if (slug === null) return EXIT_ALLOW27;
32130
- const roadmapPath2 = path85.join(workspaceRoot2, "agents", "roadmaps", `${slug}.md`);
32131
- let roadmapText;
32132
- try {
32133
- roadmapText = fs84.readFileSync(roadmapPath2, "utf8");
32134
- } catch {
32371
+ const claim = resolve_claim(workspaceRoot2, sessionId2 || null);
32372
+ if (claim === null) return EXIT_ALLOW27;
32373
+ const slug = claim.slug;
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");
32135
32425
  return EXIT_ALLOW27;
32136
32426
  }
32137
32427
  if (parseExecutionMode(roadmapText) !== "autonomous") return EXIT_ALLOW27;
@@ -32140,7 +32430,29 @@ function main55() {
32140
32430
  );
32141
32431
  if (!transcriptPath) return EXIT_ALLOW27;
32142
32432
  try {
32143
- 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
+ }
32144
32456
  } catch {
32145
32457
  return EXIT_ALLOW27;
32146
32458
  }
@@ -32152,57 +32464,73 @@ function main55() {
32152
32464
  } catch {
32153
32465
  return EXIT_ALLOW27;
32154
32466
  }
32155
- 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;
32156
32474
  if (refusedThisTurn(workspaceRoot2, sessionId2, turnOrdinal)) {
32157
32475
  appendEvent2(workspaceRoot2, {
32158
32476
  event: "deferred-quality-gate",
32159
32477
  run_id: runId,
32160
32478
  roadmap: slug,
32161
32479
  turn: turnOrdinal,
32162
- at: (/* @__PURE__ */ new Date()).toISOString()
32480
+ at: (/* @__PURE__ */ new Date()).toISOString(),
32481
+ ...roots
32163
32482
  });
32164
32483
  return EXIT_ALLOW27;
32165
32484
  }
32166
- const stateFile4 = path85.join(workspaceRoot2, stateRelPath(runId));
32167
- const prev = readState4(stateFile4);
32485
+ const mainState = readRunState(workspaceRoot2, runId, slug);
32486
+ const stateFile4 = mainState.keyedFile;
32487
+ const prev = mainState.state;
32168
32488
  const state = prev ?? {
32169
32489
  started_at: (/* @__PURE__ */ new Date()).toISOString(),
32170
32490
  iterations: 0,
32171
32491
  last_turn: -1,
32172
- history: []
32492
+ history: [],
32493
+ roadmap: slug
32173
32494
  };
32495
+ state.roadmap = slug;
32496
+ delete state.absent_fires;
32174
32497
  const scan = scanOpenSteps(roadmapText);
32175
- if (isDuplicateFire(prev, turnOrdinal, scan.open, Date.now())) {
32498
+ if (isDuplicateFire(prev, turnOrdinal, scan.open, Date.now(), roadmapFile)) {
32176
32499
  process.stderr.write(_continuationText(slug, scan, state.iterations));
32177
32500
  return EXIT_BLOCK5;
32178
32501
  }
32179
- 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);
32180
32507
  if (action !== "engage") {
32181
- appendEvent2(workspaceRoot2, {
32182
- event: action,
32183
- run_id: runId,
32184
- roadmap: slug,
32185
- turn: turnOrdinal,
32186
- iterations: state.iterations,
32187
- open: scan.open,
32188
- blocked: scan.blocked,
32189
- at: (/* @__PURE__ */ new Date()).toISOString()
32190
- });
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
+ }
32191
32523
  if (action === "complete") {
32192
- try {
32193
- fs84.rmSync(stateFile4, { force: true });
32194
- } catch {
32195
- }
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");
32196
32529
  return EXIT_ALLOW27;
32197
32530
  }
32198
32531
  if (!state.halted) {
32199
32532
  state.halted = action;
32200
- try {
32201
- fs84.mkdirSync(path85.dirname(stateFile4), { recursive: true });
32202
- fs84.writeFileSync(stateFile4, `${JSON.stringify(state)}
32203
- `, "utf8");
32204
- } catch {
32205
- }
32533
+ writeState3(stateFile4, state);
32206
32534
  }
32207
32535
  return EXIT_ALLOW27;
32208
32536
  }
@@ -32210,11 +32538,7 @@ function main55() {
32210
32538
  state.last_turn = turnOrdinal;
32211
32539
  state.history.push(scan.open);
32212
32540
  state.last_engaged_at = (/* @__PURE__ */ new Date()).toISOString();
32213
- try {
32214
- fs84.mkdirSync(path85.dirname(stateFile4), { recursive: true });
32215
- fs84.writeFileSync(stateFile4, `${JSON.stringify(state)}
32216
- `, "utf8");
32217
- } catch {
32541
+ if (!writeState3(stateFile4, state)) {
32218
32542
  return EXIT_ALLOW27;
32219
32543
  }
32220
32544
  appendEvent2(workspaceRoot2, {
@@ -32225,7 +32549,8 @@ function main55() {
32225
32549
  iteration: state.iterations,
32226
32550
  open: scan.open,
32227
32551
  blocked: scan.blocked,
32228
- at: (/* @__PURE__ */ new Date()).toISOString()
32552
+ at: (/* @__PURE__ */ new Date()).toISOString(),
32553
+ ...roots
32229
32554
  });
32230
32555
  process.stderr.write(_continuationText(slug, scan, state.iterations));
32231
32556
  return EXIT_BLOCK5;