@event4u/agent-config 9.28.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 (209) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/AGENTS.md +6 -6
  3. package/CHANGELOG.md +172 -5
  4. package/README.md +2 -1
  5. package/agents/templates/.ai-council.yml.example +55 -24
  6. package/dist/agent-src/commands/analyze/inbox.md +22 -1
  7. package/dist/agent-src/commands/cost/report.md +2 -2
  8. package/dist/agent-src/commands/explain-run.md +31 -1
  9. package/dist/agent-src/commands/team/adversarial.md +8 -7
  10. package/dist/agent-src/commands/team/delegate.md +14 -12
  11. package/dist/agent-src/commands/team/review.md +9 -8
  12. package/dist/agent-src/commands/team/status.md +9 -8
  13. package/dist/agent-src/commands/team.md +29 -19
  14. package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +88 -2
  15. package/dist/agent-src/contexts/execution/auto-orchestration-activation.md +29 -21
  16. package/dist/agent-src/contexts/execution/host-capability-manifest.md +26 -15
  17. package/dist/agent-src/contexts/execution/orchestration-telemetry.md +22 -1
  18. package/dist/agent-src/contexts/execution/roadmap-process-loop.md +17 -0
  19. package/dist/agent-src/contexts/execution/subagent-response-contract.md +65 -1
  20. package/dist/agent-src/contexts/execution/subagent-routing.md +13 -11
  21. package/dist/agent-src/contexts/execution/subagent-spawn-contract.md +25 -0
  22. package/dist/agent-src/contexts/execution/subagent-steering.md +6 -3
  23. package/dist/agent-src/rules/delegation-policy.md +11 -7
  24. package/dist/agent-src/rules/preservation-guard.md +9 -0
  25. package/dist/agent-src/rules/settings-ask-protocol.md +8 -7
  26. package/dist/agent-src/rules/token-budget-discipline.md +1 -1
  27. package/dist/agent-src/scripts/roadmap_gates.ts +312 -0
  28. package/dist/agent-src/scripts/update_roadmap_progress.ts +72 -4
  29. package/dist/agent-src/skills/forensics-report/SKILL.md +114 -0
  30. package/dist/agent-src/skills/forensics-report/evals/triggers.json +17 -0
  31. package/dist/agent-src/skills/premortem/SKILL.md +30 -1
  32. package/dist/agent-src/skills/reasoning-orchestrator/SKILL.md +2 -1
  33. package/dist/agent-src/skills/subagent-orchestration/SKILL.md +17 -5
  34. package/dist/agent-src/skills/subagent-orchestration/schemas/subagent-status.json +61 -3
  35. package/dist/agent-src/skills/test-case-discovery/SKILL.md +1 -1
  36. package/dist/agent-src/templates/AGENTS.md +4 -4
  37. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  38. package/dist/agent-src/templates/roadmaps.md +23 -0
  39. package/dist/cli/registry.js +2 -0
  40. package/dist/cli/registry.js.map +1 -1
  41. package/dist/cli-delegate/{chunk-22GCIJ2O.js → chunk-66OVWGB5.js} +1 -1
  42. package/dist/cli-delegate/{chunk-7OMQCH4V.js → chunk-BTJNRUX3.js} +22 -35
  43. package/dist/cli-delegate/{chunk-DVRS2KVR.js → chunk-DDUNNFYX.js} +24 -17
  44. package/dist/cli-delegate/{chunk-PQSAQKHW.js → chunk-EQY4FLJB.js} +3 -3
  45. package/dist/cli-delegate/{chunk-2BE5I2MN.js → chunk-IYTGIG2Y.js} +155 -91
  46. package/dist/cli-delegate/{chunk-GB2FSUEE.js → chunk-LCFJIQ4J.js} +32 -0
  47. package/dist/cli-delegate/{chunk-VSYT7OHO.js → chunk-LVRYBKTI.js} +31 -2
  48. package/dist/cli-delegate/chunk-MMJL4TIX.js +18 -0
  49. package/dist/cli-delegate/{chunk-JXARCGVN.js → chunk-MP3JT3IU.js} +1 -1
  50. package/dist/cli-delegate/chunk-O3CO5BFB.js +161 -0
  51. package/dist/cli-delegate/{chunk-REKCMYOU.js → chunk-PFBV6XRT.js} +36 -20
  52. package/dist/cli-delegate/chunk-RVGBH4XK.js +142 -0
  53. package/dist/cli-delegate/cmd_analyze_session.js +1 -1
  54. package/dist/cli-delegate/cmd_brand_status.js +1 -1
  55. package/dist/cli-delegate/cmd_conformance.js +2803 -137
  56. package/dist/cli-delegate/cmd_doctor.js +10 -5
  57. package/dist/cli-delegate/cmd_explain.js +2 -2
  58. package/dist/cli-delegate/cmd_export.js +4 -4
  59. package/dist/cli-delegate/cmd_handoff.js +88 -8
  60. package/dist/cli-delegate/cmd_mcp_available.js +1 -1
  61. package/dist/cli-delegate/cmd_migrate.js +2 -2
  62. package/dist/cli-delegate/cmd_packs_active.js +2 -2
  63. package/dist/cli-delegate/cmd_prune.js +4 -4
  64. package/dist/cli-delegate/cmd_route_audit.js +3 -2
  65. package/dist/cli-delegate/cmd_route_explain.js +1 -1
  66. package/dist/cli-delegate/cmd_session_recycle.js +177 -0
  67. package/dist/cli-delegate/cmd_settings_get.js +2 -8
  68. package/dist/cli-delegate/cmd_settings_migrate.js +4 -4
  69. package/dist/cli-delegate/cmd_settings_set.js +2 -2
  70. package/dist/cli-delegate/cmd_sync.js +4 -4
  71. package/dist/cli-delegate/cmd_uninstall.js +4 -4
  72. package/dist/cli-delegate/cmd_update.js +1 -1
  73. package/dist/cli-delegate/cmd_upgrade.js +1 -1
  74. package/dist/cli-delegate/cmd_validate.js +4 -4
  75. package/dist/cli-delegate/cmd_versions.js +1 -1
  76. package/dist/discovery/deprecation-report.md +1 -1
  77. package/dist/discovery/discovery-manifest.json +72 -23
  78. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  79. package/dist/discovery/discovery-manifest.summary.md +3 -2
  80. package/dist/discovery/orphan-report.md +1 -1
  81. package/dist/discovery/packs.json +39 -2
  82. package/dist/discovery/trust-report.md +2 -2
  83. package/dist/discovery/workspaces.json +12 -4
  84. package/dist/hooks/dispatch.js +2278 -611
  85. package/dist/install/install.mjs +56 -17
  86. package/dist/mcp/registry-manifest.json +3 -3
  87. package/dist/mcp/server.json +2 -2
  88. package/dist/mcp/server.mjs +4122 -699
  89. package/dist/router.json +1 -1
  90. package/dist/scripts/_lib/agent_settings.js +54 -0
  91. package/dist/scripts/_lib/agent_settings.js.map +1 -1
  92. package/dist/scripts/condense.js +147 -2
  93. package/dist/scripts/condense.js.map +1 -1
  94. package/dist/server/schemas/settings.js +12 -7
  95. package/dist/server/schemas/settings.js.map +1 -1
  96. package/dist/shared/settingsCarveOut.js +0 -9
  97. package/dist/shared/settingsCarveOut.js.map +1 -1
  98. package/dist/shared/settingsClasses.js +11 -9
  99. package/dist/shared/settingsClasses.js.map +1 -1
  100. package/dist/ui/assets/index-B5qGYOJo.js +26 -0
  101. package/dist/ui/assets/index-B5qGYOJo.js.map +1 -0
  102. package/dist/ui/index.html +1 -1
  103. package/docs/contracts/settings-classes.md +58 -12
  104. package/package.json +1 -1
  105. package/src/agent-src/scripts/roadmap_gates.ts +312 -0
  106. package/src/agent-src/scripts/update_roadmap_progress.ts +72 -4
  107. package/src/agent-src/templates/AGENTS.md +4 -4
  108. package/src/config/agent-settings.template.yml +88 -66
  109. package/src/config/discovery/packs.yml +11 -0
  110. package/src/config/discovery/workspaces.yml +1 -1
  111. package/src/config/dispatch-economy-metrics.json +61 -0
  112. package/src/config/evaluator-budgets.json +4 -4
  113. package/src/config/gate-violation-baselines.json +3 -3
  114. package/src/config/hook-token-budget.json +91 -0
  115. package/src/config/recycle-threshold-budget.json +12 -0
  116. package/src/config/rule-enforcement-baseline.json +86 -0
  117. package/src/scripts/_cli/cmd_conformance.ts +31 -44
  118. package/src/scripts/_cli/cmd_doctor.ts +65 -48
  119. package/src/scripts/_cli/cmd_session_recycle.ts +226 -0
  120. package/src/scripts/_dispatch.bash +23 -0
  121. package/src/scripts/_lib/agent_settings.ts +58 -0
  122. package/src/scripts/_lib/auto_dispatch.corpus.test.ts +1 -1
  123. package/src/scripts/_lib/auto_dispatch.ts +23 -18
  124. package/src/scripts/_lib/capsule_trigger.ts +124 -0
  125. package/src/scripts/_lib/host_capability.ts +63 -6
  126. package/src/scripts/_lib/judgment_ladder.ts +634 -0
  127. package/src/scripts/_lib/orchestration_gate.ts +8 -0
  128. package/src/scripts/_lib/orchestration_record.ts +78 -10
  129. package/src/scripts/_lib/orchestration_savings.ts +1 -1
  130. package/src/scripts/_lib/recycle_envelope_paths.ts +35 -0
  131. package/src/scripts/_lib/self_repair.ts +354 -13
  132. package/src/scripts/_lib/self_repair_store.ts +28 -0
  133. package/src/scripts/_lib/session_eol.ts +230 -0
  134. package/src/scripts/_lib/session_role.ts +42 -0
  135. package/src/scripts/_lib/subagent_capsule.ts +341 -0
  136. package/src/scripts/_lib/subagent_response.ts +94 -0
  137. package/src/scripts/_lib/subagent_spawn.ts +13 -0
  138. package/src/scripts/_lib/subagent_steering.ts +9 -4
  139. package/src/scripts/_lib/tier_budget_routing.ts +6 -1
  140. package/src/scripts/_lib/worker_budget.ts +37 -2
  141. package/src/scripts/ai_council/clients.ts +126 -55
  142. package/src/scripts/ai_council/config.ts +94 -6
  143. package/src/scripts/ai_council/handoff.ts +113 -0
  144. package/src/scripts/ai_council/modes.ts +19 -4
  145. package/src/scripts/ai_council/orchestrator.ts +105 -0
  146. package/src/scripts/ai_council/quorum.ts +84 -0
  147. package/src/scripts/ai_council/session.ts +44 -0
  148. package/src/scripts/ai_council/transport_resolver.ts +127 -1
  149. package/src/scripts/ai_team/availability.ts +110 -0
  150. package/src/scripts/ai_team/config.ts +34 -14
  151. package/src/scripts/ai_team/team_dispatch.ts +71 -29
  152. package/src/scripts/ask_transport.ts +221 -0
  153. package/src/scripts/bench_critic_protocol.ts +396 -0
  154. package/src/scripts/bench_hook_injection.ts +234 -0
  155. package/src/scripts/check_adr_frontmatter.ts +84 -40
  156. package/src/scripts/check_branch_freshness.ts +1 -0
  157. package/src/scripts/check_corpus_staleness.ts +18 -4
  158. package/src/scripts/check_detector_corpus.ts +219 -0
  159. package/src/scripts/check_gitignore_freshness.ts +42 -8
  160. package/src/scripts/check_hook_bundle_freshness.ts +24 -1
  161. package/src/scripts/check_kernel_prefix_stability.ts +1 -0
  162. package/src/scripts/check_standing_rule_delivery.ts +73 -32
  163. package/src/scripts/check_static_layer_stability.ts +154 -0
  164. package/src/scripts/check_suppression_hygiene.ts +48 -0
  165. package/src/scripts/condense.ts +162 -2
  166. package/src/scripts/council_cli.ts +401 -25
  167. package/src/scripts/dispatch_economy_report.ts +448 -0
  168. package/src/scripts/dispatch_r2_reviewer.ts +15 -2
  169. package/src/scripts/explain_run.ts +206 -4
  170. package/src/scripts/forensics_report.ts +333 -0
  171. package/src/scripts/generate_settings_reference.ts +1 -0
  172. package/src/scripts/handoff_context_hook.ts +112 -4
  173. package/src/scripts/hook_manifest.yaml +117 -10
  174. package/src/scripts/hooks/concern_registry.ts +8 -0
  175. package/src/scripts/hooks/delegation_nudge_hook.ts +106 -35
  176. package/src/scripts/hooks/dispatch_hook.ts +39 -2
  177. package/src/scripts/hooks/edit_shape_hook.ts +303 -0
  178. package/src/scripts/hooks/orchestration_record_hook.ts +19 -1
  179. package/src/scripts/hooks/reread_guard_hook.ts +314 -0
  180. package/src/scripts/hooks/rtk_wrap_hook.ts +133 -14
  181. package/src/scripts/hooks/session_eol_hook.ts +268 -0
  182. package/src/scripts/hooks/turn_end_gate_hook.ts +507 -0
  183. package/src/scripts/install-hooks.sh +1 -1
  184. package/src/scripts/language_mirror_hook.ts +89 -0
  185. package/src/scripts/lint_decision_impact.ts +14 -1
  186. package/src/scripts/lint_discovery_vocabulary.ts +2 -0
  187. package/src/scripts/lint_hook_manifest.ts +82 -0
  188. package/src/scripts/lint_never_silent.ts +276 -0
  189. package/src/scripts/lint_no_activation_gates.ts +271 -0
  190. package/src/scripts/lint_readme_serial_comma.ts +1 -0
  191. package/src/scripts/lint_rule_enforcement_declaration.ts +347 -0
  192. package/src/scripts/measure_turn_end_gate.ts +194 -0
  193. package/src/scripts/orchestration_record.ts +12 -1
  194. package/src/scripts/rebuild_hook_bundle.ts +178 -0
  195. package/src/scripts/release.ts +74 -2
  196. package/src/scripts/report_conformance_funnel.ts +284 -0
  197. package/src/scripts/report_imperative_density.ts +1 -0
  198. package/src/scripts/routing_doctor.ts +118 -36
  199. package/src/scripts/score_skill_selection.ts +19 -5
  200. package/src/scripts/self_repair_cli.ts +337 -59
  201. package/src/scripts/session_eol_report.ts +261 -0
  202. package/src/scripts/team_events_spike.ts +271 -0
  203. package/src/scripts/team_review_gate_hook.ts +31 -9
  204. package/src/server/schemas/settings.ts +24 -17
  205. package/src/shared/settingsCarveOut.ts +0 -10
  206. package/src/shared/settingsClasses.ts +11 -9
  207. package/src/templates/compact-instructions.md +40 -0
  208. package/dist/ui/assets/index-DmR0mbk4.js +0 -26
  209. package/dist/ui/assets/index-DmR0mbk4.js.map +0 -1
@@ -762,9 +762,67 @@ export function load_agent_settings(
762
762
  _deep_merge(merged, layer);
763
763
  }
764
764
  }
765
+ _warn_removed_always_on_keys(merged);
765
766
  return merged;
766
767
  }
767
768
 
769
+ /**
770
+ * Settings keys deleted by the always-on-orchestration doctrine
771
+ * (road-to-always-on-orchestration Phase 1 for the `subagents.*` keys;
772
+ * Phase 1 Step 1.3 for `ai_team.enabled`). A leftover value from an older
773
+ * install is ignored — never applied by any reader — and surfaced with ONE
774
+ * deprecation line per key per process run (stderr; the exit code never
775
+ * changes).
776
+ *
777
+ * `ai_team.enabled` joined this list in Step 1.3: the `/team` family's
778
+ * availability is now a codex-CLI/auth FACT
779
+ * (`src/scripts/ai_team/availability.ts`), the same doctrine already
780
+ * applied to `subagents.*` below, not a settings flag. The `ai_team`
781
+ * config loader (`src/scripts/ai_team/config.ts`) separately accepts a
782
+ * leftover `enabled` key without failing closed, so this warning is the
783
+ * only surfaced signal of the deletion.
784
+ */
785
+ const REMOVED_ALWAYS_ON_KEYS: readonly string[] = [
786
+ 'subagents.enabled',
787
+ 'subagents.auto',
788
+ 'subagents.host_capabilities',
789
+ 'subagents.budget_routing',
790
+ 'ai_team.enabled',
791
+ ];
792
+
793
+ /** Keys already warned about in THIS process — the "once per run" dedupe. */
794
+ const _warnedRemovedAlwaysOnKeys = new Set<string>();
795
+
796
+ /** Read one dotted path out of a merged settings tree; `undefined` when absent. */
797
+ function _readDottedSettingsPath(root: SettingsDict, dotted: string): SettingsValue {
798
+ let node: SettingsValue = root;
799
+ for (const part of dotted.split('.')) {
800
+ if (typeof node !== 'object' || node === null || Array.isArray(node)) {
801
+ return undefined;
802
+ }
803
+ node = (node as SettingsDict)[part];
804
+ }
805
+ return node;
806
+ }
807
+
808
+ /**
809
+ * Warn once per process, on stderr, for every {@link REMOVED_ALWAYS_ON_KEYS}
810
+ * still present in a resolved settings tree. Never throws, never changes
811
+ * what the caller does with `merged` — a pure notification side effect.
812
+ */
813
+ function _warn_removed_always_on_keys(merged: SettingsDict): void {
814
+ for (const key of REMOVED_ALWAYS_ON_KEYS) {
815
+ if (_warnedRemovedAlwaysOnKeys.has(key)) {
816
+ continue;
817
+ }
818
+ if (_readDottedSettingsPath(merged, key) === undefined) {
819
+ continue;
820
+ }
821
+ _warnedRemovedAlwaysOnKeys.add(key);
822
+ process.stderr.write(`${key} was removed (always-on orchestration); ignored.\n`);
823
+ }
824
+ }
825
+
768
826
  /**
769
827
  * Return the merged `modules:` configuration with defaults applied.
770
828
  *
@@ -23,7 +23,7 @@ import {
23
23
  type TaskSignals,
24
24
  } from './auto_dispatch.js';
25
25
 
26
- const ON: ActivationInputs = { enabled: true, auto: 'on', subagent_spawn: true };
26
+ const ON: ActivationInputs = { halted: false, subagent_spawn: true };
27
27
 
28
28
  /** Corpus signals transcribed from each task's documented "Classification signal". */
29
29
  const CORPUS: Array<{
@@ -7,19 +7,24 @@
7
7
  * Decides whether a task is delegable to subagents and which
8
8
  * `subagent-orchestration` mode fits — with NO per-turn LLM meta-call.
9
9
  *
10
+ * Always-on orchestration (road-to-always-on-orchestration Phase 1): there is
11
+ * no more `subagents.enabled` / `subagents.auto` setting gating this. The
12
+ * layer activates on any host reporting a subagent primitive, unless the one
13
+ * audited incident switch (`emergency.orchestration_halt`) is set.
14
+ *
10
15
  * Contract highlights:
11
16
  * - A task is delegable only on an enumerated structural signal.
12
17
  * - Trivial tasks below the size floor never delegate.
13
- * - Ambiguity → `ask` (when `auto == 'ask'`) or in-session, never speculative
14
- * spawn.
15
- * - The activation gate (`enabled`, `auto != off`, `subagent_spawn`) runs
16
- * first; any failure short-circuits to in-session.
18
+ * - A matched signal always DISPATCHES (there is no more ask-before-dispatch
19
+ * mode); an AMBIGUOUS verdict (no enumerated signal matched) is always an
20
+ * `ask` VERDICT to the user, never a speculative spawn.
21
+ * - The activation gate (`halted`, `subagent_spawn`) runs first; any failure
22
+ * short-circuits to in-session.
17
23
  */
18
24
 
19
25
  /** Minimum task-size estimate (exclusive) below which a task never delegates. */
20
26
  export const SIZE_FLOOR = 1;
21
27
 
22
- export type AutoMode = 'off' | 'ask' | 'on';
23
28
  export type DispatchMode = 'do-in-steps' | 'do-in-parallel';
24
29
  export type DispatchAction = 'dispatch' | 'ask' | 'in-session';
25
30
 
@@ -35,10 +40,14 @@ export interface TaskSignals {
35
40
  size_estimate: number;
36
41
  }
37
42
 
38
- /** Activation inputs resolved from settings + the host-capability manifest. */
43
+ /**
44
+ * Activation inputs resolved from the emergency incident switch + the
45
+ * host-capability manifest. No `enabled`/`auto` fields — always-on
46
+ * orchestration carries no per-layer setting to resolve them from.
47
+ */
39
48
  export interface ActivationInputs {
40
- enabled: boolean;
41
- auto: AutoMode;
49
+ /** `emergency.orchestration_halt` — the one audited incident switch. */
50
+ halted: boolean;
42
51
  subagent_spawn: boolean;
43
52
  }
44
53
 
@@ -59,8 +68,7 @@ function inSession(reason: string): Classification {
59
68
  */
60
69
  export function classifyTask(signals: TaskSignals, activation: ActivationInputs): Classification {
61
70
  // ── Activation gate — any failure short-circuits to in-session ──
62
- if (!activation.enabled) return inSession('subagents.enabled is false');
63
- if (activation.auto === 'off') return inSession('subagents.auto is off');
71
+ if (activation.halted) return inSession('emergency.orchestration_halt is set');
64
72
  if (!activation.subagent_spawn) return inSession('host has no subagent_spawn primitive');
65
73
 
66
74
  // ── Size floor — trivial tasks never delegate ──
@@ -82,16 +90,13 @@ export function classifyTask(signals: TaskSignals, activation: ActivationInputs)
82
90
  }
83
91
 
84
92
  if (mode === null) {
85
- // No enumerated signal matched → ambiguous. Ask under `ask`, else in-session.
86
- if (activation.auto === 'ask') {
87
- return { delegable: false, action: 'ask', mode: null, reason: 'no delegable signal — borderline, ask' };
88
- }
89
- return inSession('no enumerated delegable signal matched');
93
+ // No enumerated signal matched → ambiguous. Always an `ask` VERDICT —
94
+ // there is no more setting under which this silently stays in-session.
95
+ return { delegable: false, action: 'ask', mode: null, reason: 'no delegable signal — borderline, ask' };
90
96
  }
91
97
 
92
- // Matched a signal. Dispatch under `on`, ask under `ask`.
93
- const action: DispatchAction = activation.auto === 'on' ? 'dispatch' : 'ask';
94
- return { delegable: true, action, mode, reason };
98
+ // Matched a signal → always dispatch (always-on: no ask-before-dispatch mode).
99
+ return { delegable: true, action: 'dispatch', mode, reason };
95
100
  }
96
101
 
97
102
  // ── Lookup-class routing (L0 — road-to-lean-agent-init) ──
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Capsule-emission triggers — the two arms Phase 1 compares in shadow
3
+ * (road-to-worker-generation-recycling).
4
+ *
5
+ * Pure, no-I/O. Two candidate answers to "when should a worker hand off?":
6
+ *
7
+ * - **watermark** — cumulative tokens reach `CAPSULE_WATERMARK_FRACTION` of
8
+ * the stop-loss budget (`worker_budget.ts`). Cheap, already instrumented,
9
+ * and indifferent to whether the worker is still learning anything.
10
+ * - **saturation** — novelty per step, by term frequency, falls below a
11
+ * threshold. The hypothesis it encodes: a worker near its budget should
12
+ * have stopped EARLIER, not summarised harder — a worker that has stopped
13
+ * surfacing new terms is done discovering regardless of its token count.
14
+ *
15
+ * Deliberately term-frequency only. Embeddings would add a model dependency,
16
+ * a similarity threshold nobody can defend, and a second thing to explain when
17
+ * the arm loses — and the arm has to be able to lose cheaply for the shadow
18
+ * comparison to mean anything.
19
+ *
20
+ * NOTHING ACTS ON THESE. Phase 1 logs the step at which each trigger WOULD have
21
+ * fired and the worker runs to stop-loss exactly as before, so the measurement
22
+ * is not confounded by the mechanism it is measuring.
23
+ */
24
+
25
+ import { CAPSULE_WATERMARK_FRACTION } from './worker_budget.js';
26
+
27
+ /** Trailing steps averaged before saturation can fire. */
28
+ export const SATURATION_WINDOW = 3;
29
+ /** Mean novelty below this over the window = saturated. */
30
+ export const SATURATION_THRESHOLD = 0.2;
31
+
32
+ /** One observed worker step. `terms` is whatever the step surfaced — paths, symbols, words. */
33
+ export interface StepObservation {
34
+ /** Tokens this step consumed (per-step, not cumulative). */
35
+ tokens: number;
36
+ /** Terms surfaced by this step. Normalised and deduped internally. */
37
+ terms: string[];
38
+ }
39
+
40
+ export interface TriggerComparison {
41
+ /** Steps observed. */
42
+ steps: number;
43
+ /** 1-based step at which the token watermark was crossed; null = never. */
44
+ watermark_step: number | null;
45
+ /** 1-based step at which novelty saturated; null = never. */
46
+ saturation_step: number | null;
47
+ /** Per-step novelty ratio (new terms / distinct terms in that step). */
48
+ novelty: number[];
49
+ /** Cumulative tokens after each step. */
50
+ cumulative_tokens: number[];
51
+ }
52
+
53
+ /** Lowercase, strip surrounding punctuation. No stemming — a stemmer is a second thing to defend. */
54
+ function normalise(term: string): string {
55
+ return term.toLowerCase().replace(/^[^a-z0-9]+|[^a-z0-9]+$/g, '');
56
+ }
57
+
58
+ function distinctTerms(terms: string[]): Set<string> {
59
+ const out = new Set<string>();
60
+ for (const raw of terms) {
61
+ if (typeof raw !== 'string') continue;
62
+ const t = normalise(raw);
63
+ if (t.length > 0) out.add(t);
64
+ }
65
+ return out;
66
+ }
67
+
68
+ /**
69
+ * Run both arms over an observed step sequence and report where each WOULD
70
+ * have fired. Both may be null (neither fired) — which is a publishable result,
71
+ * not a failure of the instrument.
72
+ */
73
+ export function compareTriggers(steps: StepObservation[], budget: number): TriggerComparison {
74
+ const watermark = Math.floor(budget * CAPSULE_WATERMARK_FRACTION);
75
+ const seen = new Set<string>();
76
+ const novelty: number[] = [];
77
+ const cumulative_tokens: number[] = [];
78
+ let cumulative = 0;
79
+ let watermark_step: number | null = null;
80
+ let saturation_step: number | null = null;
81
+
82
+ for (const [i, step] of steps.entries()) {
83
+ cumulative += Number.isFinite(step.tokens) ? step.tokens : 0;
84
+ cumulative_tokens.push(cumulative);
85
+ if (watermark_step === null && budget > 0 && cumulative >= watermark) {
86
+ watermark_step = i + 1;
87
+ }
88
+
89
+ const terms = distinctTerms(step.terms ?? []);
90
+ let fresh = 0;
91
+ for (const t of terms) {
92
+ if (!seen.has(t)) {
93
+ fresh += 1;
94
+ seen.add(t);
95
+ }
96
+ }
97
+ // A step that surfaced nothing is fully saturated by definition: it
98
+ // learned nothing. Scoring it as 1.0 ("all new") would let an idle
99
+ // worker look maximally productive.
100
+ novelty.push(terms.size === 0 ? 0 : fresh / terms.size);
101
+
102
+ if (saturation_step === null && novelty.length >= SATURATION_WINDOW) {
103
+ const window = novelty.slice(-SATURATION_WINDOW);
104
+ const mean = window.reduce((a, b) => a + b, 0) / window.length;
105
+ if (mean < SATURATION_THRESHOLD) saturation_step = i + 1;
106
+ }
107
+ }
108
+
109
+ return { steps: steps.length, watermark_step, saturation_step, novelty, cumulative_tokens };
110
+ }
111
+
112
+ /**
113
+ * Which arm fired first, for the paired comparison in `docs/CLAIMS.md`
114
+ * (`worker-capsule-trigger-arm`). `null` = neither fired; `'tie'` = same step.
115
+ */
116
+ export function earlierArm(c: TriggerComparison): 'watermark' | 'saturation' | 'tie' | null {
117
+ const w = c.watermark_step;
118
+ const s = c.saturation_step;
119
+ if (w === null && s === null) return null;
120
+ if (w === null) return 'saturation';
121
+ if (s === null) return 'watermark';
122
+ if (w === s) return 'tie';
123
+ return w < s ? 'watermark' : 'saturation';
124
+ }
@@ -1,9 +1,9 @@
1
1
  /**
2
2
  * Host-capability manifest normalizer + committed capability registry.
3
3
  *
4
- * Pure, no-I/O helper that takes a partial / unknown object (typically the
5
- * `subagents.host_capabilities` override from `.agent-settings.yml`, or the
6
- * agent's own host-knowledge object) and returns a fully-populated manifest.
4
+ * Pure, no-I/O helper that takes a partial / unknown object (an explicit
5
+ * caller-supplied override, or the agent's own host-knowledge object) and
6
+ * returns a fully-populated manifest.
7
7
  *
8
8
  * Contract — see `src/agent-src/contexts/execution/host-capability-manifest.md`:
9
9
  *
@@ -16,14 +16,23 @@
16
16
  * adds a resolution order in front of the safe default so a fresh install on
17
17
  * a KNOWN host does not ship delegation dead by default:
18
18
  *
19
- * explicit `subagents.host_capabilities` override (wins, whole-object,
20
- * unchanged semantics) → committed registry row for the detected host
21
- * (`HOST_CAPABILITY_REGISTRY`) → `SAFE_DEFAULT` (all false).
19
+ * explicit override (wins, whole-object, unchanged semantics) → committed
20
+ * registry row for the detected host (`HOST_CAPABILITY_REGISTRY`) →
21
+ * `SAFE_DEFAULT` (all false).
22
22
  *
23
23
  * The registry lists only OBSERVED capabilities for a host this repo has
24
24
  * actually measured (see the roadmap's transcript evidence) — never a
25
25
  * speculative entry for a host nobody has verified.
26
+ *
27
+ * `probeHostCapabilities` (road-to-always-on-orchestration Phase 1) is the
28
+ * production entry point as of this change: capability is a FACT about the
29
+ * host, never a settings decision, so the former `subagents.host_capabilities`
30
+ * settings override was deleted. `resolveHostCapabilities`'s `override`
31
+ * parameter stays for back-compat (tests, and any caller that genuinely has a
32
+ * host-knowledge object of its own) — no production caller passes a
33
+ * settings-derived value into it any more.
26
34
  */
35
+ import process from 'node:process';
27
36
 
28
37
  /** Resolved host-capability manifest. All booleans, `schema_version` fixed at 1. */
29
38
  export interface HostCapabilityManifest {
@@ -32,6 +41,27 @@ export interface HostCapabilityManifest {
32
41
  parallel_spawn: boolean;
33
42
  status_polling: boolean;
34
43
  separate_quota_pool: boolean;
44
+ /**
45
+ * Claude Code's experimental multi-instance Agent Teams primitive
46
+ * (`CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS`). Resolved ONLY by
47
+ * {@link probeHostCapabilities}'s live environment probe — the registry
48
+ * and `normalizeHostManifest` never infer it from a host id, because
49
+ * this repo has not observed the flag's shape on any host, only its
50
+ * documented existence.
51
+ */
52
+ agent_teams: boolean;
53
+ /**
54
+ * The host can kill a running worker and spawn a fresh one that continues
55
+ * the SAME task mid-flight — the primitive worker-generation recycling
56
+ * needs (road-to-worker-generation-recycling, `blocker: host-worker-respawn`).
57
+ *
58
+ * `false` on every host today, deliberately: like `status_polling` and
59
+ * `separate_quota_pool`, this field is set `true` only once the capability
60
+ * is OBSERVED on a host, never by inference from the fact that spawning and
61
+ * killing both exist separately. A host without it degrades to today's
62
+ * stop-loss behaviour — loudly, never silently.
63
+ */
64
+ worker_respawn: boolean;
35
65
  }
36
66
 
37
67
  /** Safe default — unknown host assumes no subagent primitive. */
@@ -41,6 +71,8 @@ const SAFE_DEFAULT: HostCapabilityManifest = {
41
71
  parallel_spawn: false,
42
72
  status_polling: false,
43
73
  separate_quota_pool: false,
74
+ agent_teams: false,
75
+ worker_respawn: false,
44
76
  };
45
77
 
46
78
  /** Coerce one field: only a strict boolean `true` survives; everything else is `false`. */
@@ -67,6 +99,8 @@ export function normalizeHostManifest(input: unknown): HostCapabilityManifest {
67
99
  parallel_spawn: asBool(src.parallel_spawn),
68
100
  status_polling: asBool(src.status_polling),
69
101
  separate_quota_pool: asBool(src.separate_quota_pool),
102
+ agent_teams: asBool(src.agent_teams),
103
+ worker_respawn: asBool(src.worker_respawn),
70
104
  };
71
105
  }
72
106
 
@@ -140,3 +174,26 @@ export function resolveHostCapabilities(
140
174
  }
141
175
  return { ...SAFE_DEFAULT, ...row, schema_version: 1 };
142
176
  }
177
+
178
+ /**
179
+ * Probe the effective host-capability manifest for `hostId` from OBSERVABLE
180
+ * FACTS ONLY (road-to-always-on-orchestration Phase 1) — the committed
181
+ * registry row for the host, merged with a live environment probe. This is
182
+ * the production entry point: capability is a fact about the host, never a
183
+ * settings decision, so there is no override parameter here (that stays on
184
+ * {@link resolveHostCapabilities} for back-compat callers only).
185
+ *
186
+ * The one probed fact today: `agent_teams` resolves `true` when
187
+ * `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS` is set (any non-empty value) in the
188
+ * process environment — the one host fact this repo can observe about Claude
189
+ * Code's documented-but-unshipped-by-default multi-instance Agent Teams
190
+ * primitive. A registry row can also carry `agent_teams: true` directly for a
191
+ * host where it is unconditionally available; the two sources OR together —
192
+ * a probe never turns a registry-granted capability back off.
193
+ */
194
+ export function probeHostCapabilities(hostId: string | null | undefined): HostCapabilityManifest {
195
+ const base = resolveHostCapabilities(hostId);
196
+ const flag = process.env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS;
197
+ const probedAgentTeams = typeof flag === 'string' && flag !== '';
198
+ return { ...base, agent_teams: base.agent_teams || probedAgentTeams };
199
+ }