@event4u/agent-config 9.29.0 → 9.30.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 (122) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/CHANGELOG.md +108 -7
  3. package/README.md +1 -0
  4. package/dist/agent-src/commands/analyze/inbox.md +22 -1
  5. package/dist/agent-src/commands/explain-run.md +31 -1
  6. package/dist/agent-src/commands/team/delegate.md +1 -0
  7. package/dist/agent-src/contexts/execution/orchestration-telemetry.md +4 -1
  8. package/dist/agent-src/contexts/execution/roadmap-process-loop.md +17 -0
  9. package/dist/agent-src/contexts/execution/subagent-response-contract.md +11 -1
  10. package/dist/agent-src/rules/preservation-guard.md +9 -0
  11. package/dist/agent-src/scripts/roadmap_gates.ts +312 -0
  12. package/dist/agent-src/scripts/update_roadmap_progress.ts +72 -4
  13. package/dist/agent-src/skills/subagent-orchestration/SKILL.md +10 -0
  14. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  15. package/dist/cli/registry.js +2 -0
  16. package/dist/cli/registry.js.map +1 -1
  17. package/dist/cli-delegate/{chunk-OJM3MBJM.js → chunk-BTJNRUX3.js} +21 -34
  18. package/dist/cli-delegate/{chunk-MMXA5GY7.js → chunk-DDUNNFYX.js} +14 -0
  19. package/dist/cli-delegate/{chunk-NZ5N2XQL.js → chunk-EQY4FLJB.js} +1 -1
  20. package/dist/cli-delegate/{chunk-RCIA67XN.js → chunk-IYTGIG2Y.js} +44 -1
  21. package/dist/cli-delegate/chunk-MMJL4TIX.js +18 -0
  22. package/dist/cli-delegate/chunk-O3CO5BFB.js +161 -0
  23. package/dist/cli-delegate/{chunk-REKCMYOU.js → chunk-PFBV6XRT.js} +36 -20
  24. package/dist/cli-delegate/chunk-RVGBH4XK.js +142 -0
  25. package/dist/cli-delegate/cmd_conformance.js +2798 -95
  26. package/dist/cli-delegate/cmd_doctor.js +2 -1
  27. package/dist/cli-delegate/cmd_export.js +2 -2
  28. package/dist/cli-delegate/cmd_handoff.js +86 -6
  29. package/dist/cli-delegate/cmd_prune.js +2 -2
  30. package/dist/cli-delegate/cmd_route_audit.js +2 -1
  31. package/dist/cli-delegate/cmd_session_recycle.js +177 -0
  32. package/dist/cli-delegate/cmd_settings_get.js +1 -1
  33. package/dist/cli-delegate/cmd_settings_migrate.js +2 -2
  34. package/dist/cli-delegate/cmd_settings_set.js +2 -2
  35. package/dist/cli-delegate/cmd_sync.js +2 -2
  36. package/dist/cli-delegate/cmd_uninstall.js +2 -2
  37. package/dist/cli-delegate/cmd_validate.js +2 -2
  38. package/dist/discovery/deprecation-report.md +1 -1
  39. package/dist/discovery/discovery-manifest.json +7 -7
  40. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  41. package/dist/discovery/discovery-manifest.summary.md +1 -1
  42. package/dist/discovery/orphan-report.md +1 -1
  43. package/dist/discovery/packs.json +2 -2
  44. package/dist/discovery/trust-report.md +1 -1
  45. package/dist/discovery/workspaces.json +2 -2
  46. package/dist/hooks/dispatch.js +1904 -575
  47. package/dist/install/install.mjs +14 -0
  48. package/dist/mcp/registry-manifest.json +2 -2
  49. package/dist/mcp/server.json +2 -2
  50. package/dist/mcp/server.mjs +3760 -726
  51. package/dist/server/schemas/settings.js +6 -0
  52. package/dist/server/schemas/settings.js.map +1 -1
  53. package/dist/ui/assets/index-B5qGYOJo.js +26 -0
  54. package/dist/ui/assets/index-B5qGYOJo.js.map +1 -0
  55. package/dist/ui/index.html +1 -1
  56. package/docs/contracts/settings-classes.md +21 -5
  57. package/package.json +1 -1
  58. package/src/agent-src/scripts/roadmap_gates.ts +312 -0
  59. package/src/agent-src/scripts/update_roadmap_progress.ts +72 -4
  60. package/src/config/agent-settings.template.yml +36 -0
  61. package/src/config/dispatch-economy-metrics.json +61 -0
  62. package/src/config/evaluator-budgets.json +4 -4
  63. package/src/config/hook-token-budget.json +91 -0
  64. package/src/config/recycle-threshold-budget.json +12 -0
  65. package/src/config/rule-enforcement-baseline.json +86 -0
  66. package/src/scripts/_cli/cmd_conformance.ts +17 -2
  67. package/src/scripts/_cli/cmd_session_recycle.ts +226 -0
  68. package/src/scripts/_dispatch.bash +23 -0
  69. package/src/scripts/_lib/judgment_ladder.ts +254 -2
  70. package/src/scripts/_lib/orchestration_record.ts +41 -10
  71. package/src/scripts/_lib/recycle_envelope_paths.ts +35 -0
  72. package/src/scripts/_lib/self_repair.ts +194 -0
  73. package/src/scripts/_lib/session_eol.ts +230 -0
  74. package/src/scripts/_lib/session_role.ts +42 -0
  75. package/src/scripts/_lib/subagent_capsule.ts +159 -0
  76. package/src/scripts/_lib/subagent_response.ts +75 -0
  77. package/src/scripts/ai_council/clients.ts +50 -1
  78. package/src/scripts/ask_transport.ts +221 -0
  79. package/src/scripts/bench_hook_injection.ts +234 -0
  80. package/src/scripts/check_adr_frontmatter.ts +84 -40
  81. package/src/scripts/check_branch_freshness.ts +1 -0
  82. package/src/scripts/check_corpus_staleness.ts +18 -4
  83. package/src/scripts/check_detector_corpus.ts +17 -0
  84. package/src/scripts/check_gitignore_freshness.ts +42 -8
  85. package/src/scripts/check_hook_bundle_freshness.ts +20 -0
  86. package/src/scripts/check_kernel_prefix_stability.ts +1 -0
  87. package/src/scripts/check_standing_rule_delivery.ts +73 -32
  88. package/src/scripts/check_static_layer_stability.ts +154 -0
  89. package/src/scripts/check_suppression_hygiene.ts +48 -0
  90. package/src/scripts/dispatch_economy_report.ts +448 -0
  91. package/src/scripts/dispatch_r2_reviewer.ts +15 -2
  92. package/src/scripts/explain_run.ts +206 -4
  93. package/src/scripts/generate_settings_reference.ts +1 -0
  94. package/src/scripts/handoff_context_hook.ts +112 -4
  95. package/src/scripts/hook_manifest.yaml +117 -10
  96. package/src/scripts/hooks/concern_registry.ts +8 -0
  97. package/src/scripts/hooks/delegation_nudge_hook.ts +40 -3
  98. package/src/scripts/hooks/dispatch_hook.ts +39 -2
  99. package/src/scripts/hooks/edit_shape_hook.ts +303 -0
  100. package/src/scripts/hooks/orchestration_record_hook.ts +19 -1
  101. package/src/scripts/hooks/reread_guard_hook.ts +314 -0
  102. package/src/scripts/hooks/rtk_wrap_hook.ts +133 -14
  103. package/src/scripts/hooks/session_eol_hook.ts +268 -0
  104. package/src/scripts/hooks/turn_end_gate_hook.ts +507 -0
  105. package/src/scripts/install-hooks.sh +1 -1
  106. package/src/scripts/language_mirror_hook.ts +89 -0
  107. package/src/scripts/lint_decision_impact.ts +14 -1
  108. package/src/scripts/lint_hook_manifest.ts +82 -0
  109. package/src/scripts/lint_readme_serial_comma.ts +1 -0
  110. package/src/scripts/lint_rule_enforcement_declaration.ts +347 -0
  111. package/src/scripts/measure_turn_end_gate.ts +194 -0
  112. package/src/scripts/orchestration_record.ts +4 -1
  113. package/src/scripts/rebuild_hook_bundle.ts +1 -0
  114. package/src/scripts/report_conformance_funnel.ts +284 -0
  115. package/src/scripts/report_imperative_density.ts +1 -0
  116. package/src/scripts/routing_doctor.ts +97 -0
  117. package/src/scripts/self_repair_cli.ts +51 -3
  118. package/src/scripts/session_eol_report.ts +261 -0
  119. package/src/server/schemas/settings.ts +14 -0
  120. package/src/templates/compact-instructions.md +40 -0
  121. package/dist/ui/assets/index-JDAF00bC.js +0 -26
  122. package/dist/ui/assets/index-JDAF00bC.js.map +0 -1
@@ -4374,6 +4374,9 @@ var settingsSchema = external_exports.object({
4374
4374
  judge_model: external_exports.string().default("").describe(
4375
4375
  "Override the model used for review / judge subagents that critique implementer output. Empty (default) = one tier above the implementer model \u2014 picks up nuance the implementer missed."
4376
4376
  ),
4377
+ model_ceiling: external_exports.string().default("").describe(
4378
+ "Session-wide model CEILING for subagents (spend cap). Empty (default) = no ceiling. When set, suite-owned CLI spawn wrappers export CLAUDE_CODE_SUBAGENT_MODEL to the sessions they launch. Class C: a human sets it; the agent never writes or infers one."
4379
+ ),
4377
4380
  max_parallel: external_exports.number().int().min(1).default(3).describe(
4378
4381
  "Hard cap on subagents running in parallel during /do-in-parallel, /do-competitively, and /judge runs. Raise for faster fan-out, lower if you hit rate limits or want lower token spend."
4379
4382
  ),
@@ -4540,6 +4543,17 @@ var settingsSchema = external_exports.object({
4540
4543
  enabled: external_exports.boolean().default(false).describe(
4541
4544
  "PreToolUse code-graph nudge (ADR-124 Phase 4). Default off. When on AND a native code-graph cache or a consumer-shipped graph.json/SCIP index is present, warns once per session (never blocks) as the agent is about to Grep/Glob or Read a source file \u2014 query the graph first for who-calls/where-used/impact questions (or rebuild if stale, build if absent). Source G\u2019s strict block-first-read mode is deliberately un-ported."
4542
4545
  )
4546
+ }).default({}),
4547
+ turn_end_gate: external_exports.object({
4548
+ enabled: external_exports.boolean().default(false).describe(
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
+ ),
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."
4553
+ ),
4554
+ language: external_exports.boolean().default(true).describe(
4555
+ "Detector B of the turn-end gate: refuse a turn whose user-visible prose is not in the pinned language, with fenced code, inline code, quoted tool output, tables, URLs, paths and identifiers excluded first (19 measured occurrences). Fires 18.0% of turns on the measured corpus, which is why the master switch is off by default. Inert while hooks.turn_end_gate.enabled is false."
4556
+ )
4543
4557
  }).default({})
4544
4558
  }),
4545
4559
  decision_engine: external_exports.object({
@@ -2,7 +2,7 @@ import { createRequire as __acCreateRequire } from 'node:module'; const require
2
2
  import {
3
3
  ZodFirstPartyTypeKind,
4
4
  settingsSchema
5
- } from "./chunk-MMXA5GY7.js";
5
+ } from "./chunk-DDUNNFYX.js";
6
6
  import {
7
7
  main
8
8
  } from "./chunk-MP3JT3IU.js";
@@ -41,6 +41,7 @@ import {
41
41
  ProjectRootError,
42
42
  ROOT_OVERRIDE_ENV,
43
43
  find_project_root_with_trace,
44
+ load_agent_settings,
44
45
  project_settings_path,
45
46
  resolve_project_root
46
47
  } from "./chunk-LCFJIQ4J.js";
@@ -186,7 +187,9 @@ __export(clients_exports, {
186
187
  _OpenAICompatibleClient: () => _OpenAICompatibleClient,
187
188
  _is_reasoning_model: () => _is_reasoning_model,
188
189
  _read_until_marker: () => _read_until_marker,
190
+ _resetModelCeilingMemo: () => _resetModelCeilingMemo,
189
191
  _setMonotonicSource: () => _setMonotonicSource,
192
+ _subagentModelCeiling: () => _subagentModelCeiling,
190
193
  _today_utc_iso: () => _today_utc_iso,
191
194
  assertCacheBreakpointOrder: () => assertCacheBreakpointOrder,
192
195
  load_anthropic_key: () => load_anthropic_key,
@@ -200,6 +203,9 @@ import { spawnSync } from "node:child_process";
200
203
  import * as fs4 from "node:fs";
201
204
  import * as path4 from "node:path";
202
205
 
206
+ // src/scripts/_lib/session_role.ts
207
+ var SESSION_ROLE_ENV = "AGENT_CONFIG_SESSION_ROLE";
208
+
203
209
  // src/scripts/ai_council/events_log.ts
204
210
  import * as crypto from "node:crypto";
205
211
  import * as fs3 from "node:fs";
@@ -405,6 +411,25 @@ function _pyJsonStringRaw(s) {
405
411
  }
406
412
 
407
413
  // src/scripts/ai_council/clients.ts
414
+ var _modelCeilingMemo = /* @__PURE__ */ new Map();
415
+ function _subagentModelCeiling(cwd = process.cwd()) {
416
+ const hit = _modelCeilingMemo.get(cwd);
417
+ if (hit !== void 0) return hit;
418
+ let ceiling;
419
+ try {
420
+ const settings = load_agent_settings({ cwd });
421
+ const sub = settings["subagents"] ?? {};
422
+ const v = typeof sub["model_ceiling"] === "string" ? sub["model_ceiling"].trim() : "";
423
+ ceiling = v.length > 0 ? v : null;
424
+ } catch {
425
+ ceiling = null;
426
+ }
427
+ _modelCeilingMemo.set(cwd, ceiling);
428
+ return ceiling;
429
+ }
430
+ function _resetModelCeilingMemo() {
431
+ _modelCeilingMemo.clear();
432
+ }
408
433
  var ANTHROPIC_KEY_FILENAME = "anthropic.key";
409
434
  var OPENAI_KEY_FILENAME = "openai.key";
410
435
  var ANTHROPIC_KEY_PATH = write_target(ANTHROPIC_KEY_FILENAME);
@@ -1150,7 +1175,25 @@ var CliClient = class extends ExternalAIClient {
1150
1175
  // (loader preload, git *_COMMAND, NODE_OPTIONS, …) so an
1151
1176
  // attacker-influenced parent env cannot RCE via the spawned CLI
1152
1177
  // or a `git` it invokes internally.
1153
- env: hardenedSpawnEnv()
1178
+ // Role marking (token-economy-dispatch Phase 2.2): a council
1179
+ // member CLI session is worker-class — it never talks to OUR
1180
+ // user, never dispatches sub-workers, never runs a council.
1181
+ // The spawned vendor CLI loads this repo's hook chains; the
1182
+ // marker lets the dispatcher run the thinner worker chain
1183
+ // (manifest `roles.worker.drop`; pre_tool_use guards are
1184
+ // structurally exempt). This is the ONE in-tree spawn point
1185
+ // that launches a separate CLI session today — Agent-tool
1186
+ // subagents share the host process env and cannot be marked
1187
+ // (probed live 2026-08-10; see _lib/session_role.ts).
1188
+ // The optional model ceiling (subagents.model_ceiling, class C)
1189
+ // rides the same spawn: a spend cap the human set per install.
1190
+ env: hardenedSpawnEnv({
1191
+ [SESSION_ROLE_ENV]: "worker",
1192
+ ...(() => {
1193
+ const ceiling = _subagentModelCeiling();
1194
+ return ceiling !== null ? { CLAUDE_CODE_SUBAGENT_MODEL: ceiling } : {};
1195
+ })()
1196
+ })
1154
1197
  };
1155
1198
  if (stdinPayload !== null) {
1156
1199
  spawnOpts.input = stdinPayload;
@@ -0,0 +1,18 @@
1
+ import { createRequire as __acCreateRequire } from 'node:module'; const require = globalThis.require ?? __acCreateRequire(import.meta.url);
2
+
3
+ // src/scripts/hooks/hook_stdin.ts
4
+ import * as fs from "node:fs";
5
+ var _override = null;
6
+ function readHookStdin() {
7
+ if (_override !== null) return _override;
8
+ try {
9
+ if (process.stdin.isTTY) return "";
10
+ return fs.readFileSync(0, "utf-8");
11
+ } catch {
12
+ return "";
13
+ }
14
+ }
15
+
16
+ export {
17
+ readHookStdin
18
+ };
@@ -0,0 +1,161 @@
1
+ import { createRequire as __acCreateRequire } from 'node:module'; const require = globalThis.require ?? __acCreateRequire(import.meta.url);
2
+
3
+ // src/scripts/hooks/state_io.ts
4
+ import fs from "node:fs";
5
+ import path from "node:path";
6
+ var LOCK_BASENAME = ".dispatcher.lock";
7
+ var REPLAY_ENV_VAR = "AGENT_CONFIG_REPLAY";
8
+ function is_replay_mode() {
9
+ return (process.env[REPLAY_ENV_VAR] ?? "").trim() === "1";
10
+ }
11
+ function _lock_path(state_dir) {
12
+ return path.join(state_dir, LOCK_BASENAME);
13
+ }
14
+ function _py_json_dumps(value, indent) {
15
+ const pad = " ".repeat(indent);
16
+ const escapeString = (s) => {
17
+ let out = '"';
18
+ for (const ch of s) {
19
+ const code = ch.codePointAt(0);
20
+ switch (ch) {
21
+ case '"':
22
+ out += '\\"';
23
+ break;
24
+ case "\\":
25
+ out += "\\\\";
26
+ break;
27
+ case "\n":
28
+ out += "\\n";
29
+ break;
30
+ case "\r":
31
+ out += "\\r";
32
+ break;
33
+ case " ":
34
+ out += "\\t";
35
+ break;
36
+ case "\b":
37
+ out += "\\b";
38
+ break;
39
+ case "\f":
40
+ out += "\\f";
41
+ break;
42
+ default:
43
+ if (code < 32 || code > 126) {
44
+ if (code > 65535) {
45
+ const c = code - 65536;
46
+ const hi = 55296 + (c >> 10);
47
+ const lo = 56320 + (c & 1023);
48
+ out += "\\u" + hi.toString(16).padStart(4, "0") + "\\u" + lo.toString(16).padStart(4, "0");
49
+ } else {
50
+ out += "\\u" + code.toString(16).padStart(4, "0");
51
+ }
52
+ } else {
53
+ out += ch;
54
+ }
55
+ }
56
+ }
57
+ return out + '"';
58
+ };
59
+ const render = (v, depth) => {
60
+ if (v === null || v === void 0) {
61
+ return "null";
62
+ }
63
+ if (typeof v === "boolean") {
64
+ return v ? "true" : "false";
65
+ }
66
+ if (typeof v === "number") {
67
+ if (!Number.isFinite(v)) {
68
+ if (Number.isNaN(v)) return "NaN";
69
+ return v > 0 ? "Infinity" : "-Infinity";
70
+ }
71
+ return String(v);
72
+ }
73
+ if (typeof v === "string") {
74
+ return escapeString(v);
75
+ }
76
+ const curPad = pad.repeat(depth + 1);
77
+ const closePad = pad.repeat(depth);
78
+ if (Array.isArray(v)) {
79
+ if (v.length === 0) {
80
+ return "[]";
81
+ }
82
+ const items = v.map((item) => curPad + render(item, depth + 1));
83
+ return "[\n" + items.join(",\n") + "\n" + closePad + "]";
84
+ }
85
+ if (typeof v === "object") {
86
+ const obj = v;
87
+ const keys = Object.keys(obj);
88
+ if (keys.length === 0) {
89
+ return "{}";
90
+ }
91
+ const items = keys.map(
92
+ (k) => curPad + escapeString(k) + ": " + render(obj[k], depth + 1)
93
+ );
94
+ return "{\n" + items.join(",\n") + "\n" + closePad + "}";
95
+ }
96
+ throw new TypeError(`Object of type ${typeof v} is not JSON serializable`);
97
+ };
98
+ return render(value, 0);
99
+ }
100
+ function atomic_write_json(target, payload, options = {}) {
101
+ if (is_replay_mode()) {
102
+ return;
103
+ }
104
+ const indent = options.indent ?? 2;
105
+ const targetPath = path.resolve(target);
106
+ const state_dir = path.dirname(targetPath);
107
+ fs.mkdirSync(state_dir, { recursive: true });
108
+ const body = _py_json_dumps(payload, indent) + "\n";
109
+ _atomic_write_text(targetPath, body);
110
+ }
111
+ function _acquire_lock(lock_path) {
112
+ const fd = fs.openSync(lock_path, "a", 420);
113
+ const held = lock_path + ".held";
114
+ const deadlineMs = 5e3;
115
+ const start = Date.now();
116
+ for (; ; ) {
117
+ try {
118
+ const heldFd = fs.openSync(held, "wx", 420);
119
+ fs.closeSync(heldFd);
120
+ return fd;
121
+ } catch (err) {
122
+ if (err.code !== "EEXIST") {
123
+ return fd;
124
+ }
125
+ if (Date.now() - start > deadlineMs) {
126
+ try {
127
+ fs.rmSync(held, { force: true });
128
+ } catch {
129
+ }
130
+ continue;
131
+ }
132
+ const sab = new Int32Array(new SharedArrayBuffer(4));
133
+ Atomics.wait(sab, 0, 0, 2);
134
+ }
135
+ }
136
+ }
137
+ function _release_lock(fd, lock_path) {
138
+ try {
139
+ fs.closeSync(fd);
140
+ } catch {
141
+ }
142
+ try {
143
+ fs.rmSync(lock_path + ".held", { force: true });
144
+ } catch {
145
+ }
146
+ }
147
+ function _atomic_write_text(target, text) {
148
+ const tmp = target + `.tmp.${process.pid}`;
149
+ const lock_path = _lock_path(path.dirname(target));
150
+ const fd = _acquire_lock(lock_path);
151
+ try {
152
+ fs.writeFileSync(tmp, text, { encoding: "utf-8" });
153
+ fs.renameSync(tmp, target);
154
+ } finally {
155
+ _release_lock(fd, lock_path);
156
+ }
157
+ }
158
+
159
+ export {
160
+ atomic_write_json
161
+ };
@@ -422,6 +422,11 @@ var binaryTag = defineScalarTag("tag:yaml.org,2002:binary", {
422
422
  });
423
423
  var YAML_DATE_REGEXP = /* @__PURE__ */ new RegExp("^([0-9][0-9][0-9][0-9])-([0-9][0-9])-([0-9][0-9])$");
424
424
  var YAML_TIMESTAMP_REGEXP = /* @__PURE__ */ new RegExp("^([0-9][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)(?:[Tt]|[ \\t]+)([0-9][0-9]?):([0-9][0-9]):([0-9][0-9])(?:\\.([0-9]*))?(?:[ \\t]*(Z|([-+])([0-9][0-9]?)(?::([0-9][0-9]))?))?$");
425
+ function makeUtcDate(year, month, day, hour = 0, minute = 0, second = 0, fraction = 0) {
426
+ const date = new Date(Date.UTC(year, month, day, hour, minute, second, fraction));
427
+ date.setUTCFullYear(year, month, day);
428
+ return date;
429
+ }
425
430
  function resolveYamlTimestamp(source) {
426
431
  let match = YAML_DATE_REGEXP.exec(source);
427
432
  if (match === null) match = YAML_TIMESTAMP_REGEXP.exec(source);
@@ -430,7 +435,7 @@ function resolveYamlTimestamp(source) {
430
435
  const month = +match[2] - 1;
431
436
  const day = +match[3];
432
437
  if (!match[4]) {
433
- const date2 = new Date(Date.UTC(year, month, day));
438
+ const date2 = makeUtcDate(year, month, day);
434
439
  if (date2.getUTCFullYear() !== year || date2.getUTCMonth() !== month || date2.getUTCDate() !== day) return NOT_RESOLVED;
435
440
  return date2;
436
441
  }
@@ -444,7 +449,7 @@ function resolveYamlTimestamp(source) {
444
449
  while (value.length < 3) value += "0";
445
450
  fraction = +value;
446
451
  }
447
- const date = new Date(Date.UTC(year, month, day, hour, minute, second, fraction));
452
+ const date = makeUtcDate(year, month, day, hour, minute, second, fraction);
448
453
  if (date.getUTCFullYear() !== year || date.getUTCMonth() !== month || date.getUTCDate() !== day) return NOT_RESOLVED;
449
454
  if (match[9]) {
450
455
  const offsetHour = +match[10];
@@ -542,7 +547,11 @@ var mapTag = defineMappingTag("tag:yaml.org,2002:map", {
542
547
  return Object.prototype.hasOwnProperty.call(container, String(key));
543
548
  },
544
549
  keys: (container) => Object.keys(container),
545
- get: (container, key) => container[String(key)]
550
+ get: (container, key) => {
551
+ const normalizedKey = String(key);
552
+ if (!Object.prototype.hasOwnProperty.call(container, normalizedKey)) return null;
553
+ return container[normalizedKey];
554
+ }
546
555
  });
547
556
  var setTag = defineMappingTag("tag:yaml.org,2002:set", {
548
557
  create: () => /* @__PURE__ */ new Set(),
@@ -563,9 +572,9 @@ var setTag = defineMappingTag("tag:yaml.org,2002:set", {
563
572
  });
564
573
  function createTagDefinitionMap() {
565
574
  return {
566
- scalar: {},
567
- sequence: {},
568
- mapping: {}
575
+ scalar: /* @__PURE__ */ Object.create(null),
576
+ sequence: /* @__PURE__ */ Object.create(null),
577
+ mapping: /* @__PURE__ */ Object.create(null)
569
578
  };
570
579
  }
571
580
  function createTagDefinitionListMap() {
@@ -735,7 +744,11 @@ var legacyMapTag = defineMappingTag("tag:yaml.org,2002:map", {
735
744
  return normalizedKey !== null && Object.prototype.hasOwnProperty.call(container, normalizedKey);
736
745
  },
737
746
  keys: (container) => Object.keys(container),
738
- get: (container, key) => container[String(key)]
747
+ get: (container, key) => {
748
+ const normalizedKey = String(key);
749
+ if (!Object.prototype.hasOwnProperty.call(container, normalizedKey)) return null;
750
+ return container[normalizedKey];
751
+ }
739
752
  });
740
753
  var DEFAULT_SNIPPET_OPTIONS = {
741
754
  maxLength: 79,
@@ -1071,10 +1084,10 @@ function getScalarValue(input, scalar) {
1071
1084
  return getPlainValue(input, valueStart, valueEnd);
1072
1085
  }
1073
1086
  }
1074
- var DEFAULT_TAG_HANDLERS = {
1087
+ var DEFAULT_TAG_HANDLERS = Object.assign(/* @__PURE__ */ Object.create(null), {
1075
1088
  "!": "!",
1076
1089
  "!!": "tag:yaml.org,2002:"
1077
- };
1090
+ });
1078
1091
  function tagPercentEncode(source) {
1079
1092
  return encodeURI(source).replace(/!/g, "%21");
1080
1093
  }
@@ -1327,6 +1340,10 @@ function constructFromEvents(events, options) {
1327
1340
  }
1328
1341
  case 6: {
1329
1342
  const frame = state.frames.pop();
1343
+ if (frame.kind === "mapping" && frame.hasKey) {
1344
+ state.position = frame.keyPosition;
1345
+ throwError$1(state, "incomplete mapping pair in event stream");
1346
+ }
1330
1347
  if (frame.kind === "document") state.documents.push(frame.value);
1331
1348
  else {
1332
1349
  const value = frame.tag.carrierIsResult ? frame.value : finalizeCollection(state, frame.position, frame.tag, frame.value);
@@ -1997,10 +2014,6 @@ function parseNode(state, parentIndent, nodeContext, allowToSeek, allowCompact,
1997
2014
  else if (state.lineIndent === parentIndent) indentStatus = 0;
1998
2015
  else indentStatus = -1;
1999
2016
  }
2000
- if (state.position === state.lineStart && testDocumentSeparator(state)) {
2001
- state.depth--;
2002
- return false;
2003
- }
2004
2017
  if (indentStatus === 1) while (true) {
2005
2018
  const ch = state.input.charCodeAt(state.position);
2006
2019
  const propertyState = snapshotState(state);
@@ -2549,14 +2562,14 @@ function chooseScalarStyle(state, string, layout, singleLineOnly, forceQuote, in
2549
2562
  if (char === CHAR_LINE_FEED) {
2550
2563
  hasLineBreak = true;
2551
2564
  if (shouldTrackWidth) {
2552
- hasFoldableLine = hasFoldableLine || i - previousLineBreak - 1 > lineWidth && string[previousLineBreak + 1] !== " ";
2565
+ hasFoldableLine = hasFoldableLine || i - previousLineBreak - 1 > lineWidth && !isMoreIndented(string[previousLineBreak + 1]);
2553
2566
  previousLineBreak = i;
2554
2567
  }
2555
2568
  } else if (!isPrintable(char)) return STYLE_DOUBLE;
2556
2569
  plain = plain && isPlainSafe(char, prevChar, inblock);
2557
2570
  prevChar = char;
2558
2571
  }
2559
- hasFoldableLine = hasFoldableLine || shouldTrackWidth && i - previousLineBreak - 1 > lineWidth && string[previousLineBreak + 1] !== " ";
2572
+ hasFoldableLine = hasFoldableLine || shouldTrackWidth && i - previousLineBreak - 1 > lineWidth && !isMoreIndented(string[previousLineBreak + 1]);
2560
2573
  }
2561
2574
  if (!hasLineBreak && !hasFoldableLine) {
2562
2575
  if (plain && !forceQuote) return STYLE_PLAIN;
@@ -2621,27 +2634,30 @@ function encodeFlowBreaks(string, indent) {
2621
2634
  function dropEndingNewline(string) {
2622
2635
  return string[string.length - 1] === "\n" ? string.slice(0, -1) : string;
2623
2636
  }
2637
+ function isMoreIndented(char) {
2638
+ return char === " " || char === " ";
2639
+ }
2624
2640
  function foldBlockScalar(string, width) {
2625
2641
  const lineRe = /(\n+)([^\n]*)/g;
2626
2642
  let nextLF = string.indexOf("\n");
2627
2643
  if (nextLF === -1) nextLF = string.length;
2628
2644
  lineRe.lastIndex = nextLF;
2629
2645
  let result = foldLine(string.slice(0, nextLF), width);
2630
- let prevMoreIndented = string[0] === "\n" || string[0] === " ";
2646
+ let prevMoreIndented = string[0] === "\n" || isMoreIndented(string[0]);
2631
2647
  let moreIndented;
2632
2648
  let match;
2633
2649
  while (match = lineRe.exec(string)) {
2634
2650
  const prefix = match[1];
2635
2651
  const line = match[2];
2636
- moreIndented = line[0] === " ";
2652
+ moreIndented = line !== "" && isMoreIndented(line[0]);
2637
2653
  result += prefix + (!prevMoreIndented && !moreIndented && line !== "" ? "\n" : "") + foldLine(line, width);
2638
2654
  prevMoreIndented = moreIndented;
2639
2655
  }
2640
2656
  return result;
2641
2657
  }
2642
2658
  function foldLine(line, width) {
2643
- if (line === "" || line[0] === " ") return line;
2644
- const breakRe = / [^ ]/g;
2659
+ if (line === "" || isMoreIndented(line[0])) return line;
2660
+ const breakRe = / [^ \t]/g;
2645
2661
  let match;
2646
2662
  let start = 0;
2647
2663
  let end;
@@ -2987,5 +3003,5 @@ export {
2987
3003
  /*! Bundled license information:
2988
3004
 
2989
3005
  js-yaml/dist/js-yaml.mjs:
2990
- (*! js-yaml 5.2.2 https://github.com/nodeca/js-yaml @license MIT *)
3006
+ (*! js-yaml 5.2.3 https://github.com/nodeca/js-yaml @license MIT *)
2991
3007
  */
@@ -0,0 +1,142 @@
1
+ import { createRequire as __acCreateRequire } from 'node:module'; const require = globalThis.require ?? __acCreateRequire(import.meta.url);
2
+
3
+ // src/scripts/_lib/recycle_envelope_paths.ts
4
+ import * as path from "node:path";
5
+ var RECYCLE_ENVELOPE_REL = path.join("agents", "runtime", "state", "recycle-envelope.json");
6
+ var RECYCLE_CONSUMED_REL = path.join(
7
+ "agents",
8
+ "runtime",
9
+ "state",
10
+ "recycle-envelope.consumed.json"
11
+ );
12
+ var RECYCLE_MAX_AGE_HOURS = 48;
13
+ var RECYCLE_ENVELOPE_MAX_BYTES = 6144;
14
+
15
+ // src/scripts/_lib/subagent_capsule.ts
16
+ var EPISTEMIC_STATES = ["verified", "assumed", "gap"];
17
+ var EPISTEMIC = new Set(EPISTEMIC_STATES);
18
+ var MAX_REF_CHARS = 200;
19
+ var MAX_LINE_CHARS = 240;
20
+ var MAX_ENTRIES = 40;
21
+ var CAPSULE_SCHEMA_VERSION = 2;
22
+ function isShortLine(value, max) {
23
+ return typeof value === "string" && value.length > 0 && value.length <= max && !value.includes("\n");
24
+ }
25
+ function checkList(errors, field, value, max, required) {
26
+ if (value === void 0) {
27
+ if (required) errors.push(`${field} is required`);
28
+ return;
29
+ }
30
+ if (!Array.isArray(value)) {
31
+ errors.push(`${field} must be an array`);
32
+ return;
33
+ }
34
+ if (value.length > MAX_ENTRIES) {
35
+ errors.push(`${field} carries ${value.length} entries (max ${MAX_ENTRIES}) \u2014 a capsule is a handoff, not a transcript`);
36
+ }
37
+ const bad = value.filter((x) => !isShortLine(x, max));
38
+ if (bad.length > 0) {
39
+ errors.push(
40
+ `${field} carries ${bad.length} entr${bad.length === 1 ? "y" : "ies"} that are not single lines of \u2264 ${max} chars (refs and short lines only, never bodies)`
41
+ );
42
+ }
43
+ }
44
+ var RECYCLE_ENVELOPE_KEYS = /* @__PURE__ */ new Set([
45
+ "capsule_version",
46
+ "variant",
47
+ "summary",
48
+ "task",
49
+ "workspace",
50
+ "written_at",
51
+ "acceptance_criteria",
52
+ "remaining",
53
+ "not_carried_forward",
54
+ "decisions",
55
+ "constraints",
56
+ "open_worker_envelopes",
57
+ "artifact_paths",
58
+ "assumptions"
59
+ ]);
60
+ function validateRecycleEnvelope(input) {
61
+ const errors = [];
62
+ if (typeof input !== "object" || input === null || Array.isArray(input)) {
63
+ return ["not an object"];
64
+ }
65
+ const e = input;
66
+ for (const key of Object.keys(e)) {
67
+ if (!RECYCLE_ENVELOPE_KEYS.has(key)) {
68
+ errors.push(
69
+ `unknown field "${key}" \u2014 a recycle envelope carries selection and pointers only; free-form additions (prose summaries included) are schema-invalid by construction`
70
+ );
71
+ }
72
+ }
73
+ if (e["capsule_version"] !== CAPSULE_SCHEMA_VERSION) {
74
+ errors.push(`capsule_version must be ${CAPSULE_SCHEMA_VERSION}`);
75
+ }
76
+ if (e["variant"] !== "main_session") {
77
+ errors.push("variant must be 'main_session'");
78
+ }
79
+ if (!isShortLine(e["summary"], MAX_LINE_CHARS)) {
80
+ errors.push(`summary must be a single line of 1\u2013${MAX_LINE_CHARS} chars`);
81
+ }
82
+ if (!isShortLine(e["task"], MAX_LINE_CHARS)) {
83
+ errors.push(`task must be a single line of 1\u2013${MAX_LINE_CHARS} chars`);
84
+ }
85
+ if (!isShortLine(e["workspace"], MAX_REF_CHARS)) {
86
+ errors.push(`workspace must be a path ref of \u2264 ${MAX_REF_CHARS} chars`);
87
+ }
88
+ const writtenAt = e["written_at"];
89
+ if (typeof writtenAt !== "string" || Number.isNaN(Date.parse(writtenAt))) {
90
+ errors.push("written_at must be a parseable ISO-8601 timestamp");
91
+ }
92
+ checkList(errors, "acceptance_criteria", e["acceptance_criteria"], MAX_LINE_CHARS, true);
93
+ if (Array.isArray(e["acceptance_criteria"]) && e["acceptance_criteria"].length === 0) {
94
+ errors.push('acceptance_criteria must carry at least one entry \u2014 the successor cannot know "done" without it');
95
+ }
96
+ checkList(errors, "remaining", e["remaining"], MAX_LINE_CHARS, true);
97
+ checkList(errors, "not_carried_forward", e["not_carried_forward"], MAX_LINE_CHARS, true);
98
+ checkList(errors, "decisions", e["decisions"], MAX_LINE_CHARS, false);
99
+ checkList(errors, "constraints", e["constraints"], MAX_LINE_CHARS, false);
100
+ checkList(errors, "open_worker_envelopes", e["open_worker_envelopes"], MAX_REF_CHARS, false);
101
+ checkList(errors, "artifact_paths", e["artifact_paths"], MAX_REF_CHARS, false);
102
+ const assumptions = e["assumptions"];
103
+ if (assumptions !== void 0) {
104
+ if (!Array.isArray(assumptions)) {
105
+ errors.push("assumptions must be an array");
106
+ } else {
107
+ if (assumptions.length > MAX_ENTRIES) {
108
+ errors.push(`assumptions carries ${assumptions.length} entries (max ${MAX_ENTRIES})`);
109
+ }
110
+ for (const [i, raw] of assumptions.entries()) {
111
+ errors.push(...validateAssumption(raw, `assumptions[${i}]`));
112
+ }
113
+ }
114
+ }
115
+ return errors;
116
+ }
117
+ function validateAssumption(input, label = "assumption") {
118
+ const errors = [];
119
+ if (typeof input !== "object" || input === null || Array.isArray(input)) {
120
+ return [`${label} is not an object`];
121
+ }
122
+ const a = input;
123
+ if (!isShortLine(a["statement"], MAX_LINE_CHARS)) {
124
+ errors.push(`${label}.statement must be a single line of 1\u2013${MAX_LINE_CHARS} chars`);
125
+ }
126
+ if (!isShortLine(a["basis"], MAX_REF_CHARS)) {
127
+ errors.push(`${label}.basis must be a ref token (file:line, id, path, command) of \u2264 ${MAX_REF_CHARS} chars`);
128
+ }
129
+ if (typeof a["epistemic_state"] !== "string" || !EPISTEMIC.has(a["epistemic_state"])) {
130
+ errors.push(`${label}.epistemic_state must be one of ${EPISTEMIC_STATES.join(" | ")}`);
131
+ }
132
+ return errors;
133
+ }
134
+
135
+ export {
136
+ RECYCLE_ENVELOPE_REL,
137
+ RECYCLE_CONSUMED_REL,
138
+ RECYCLE_MAX_AGE_HOURS,
139
+ RECYCLE_ENVELOPE_MAX_BYTES,
140
+ CAPSULE_SCHEMA_VERSION,
141
+ validateRecycleEnvelope
142
+ };