@event4u/agent-config 9.27.0 → 9.29.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 (220) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/AGENTS.md +13 -12
  3. package/CHANGELOG.md +165 -0
  4. package/README.md +1 -1
  5. package/agents/templates/.ai-council.yml.example +55 -24
  6. package/dist/agent-src/commands/analyze/conformance.md +24 -0
  7. package/dist/agent-src/commands/cost/report.md +2 -2
  8. package/dist/agent-src/commands/team/adversarial.md +8 -7
  9. package/dist/agent-src/commands/team/delegate.md +13 -12
  10. package/dist/agent-src/commands/team/review.md +9 -8
  11. package/dist/agent-src/commands/team/status.md +9 -8
  12. package/dist/agent-src/commands/team.md +29 -19
  13. package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +88 -2
  14. package/dist/agent-src/contexts/execution/auto-orchestration-activation.md +29 -21
  15. package/dist/agent-src/contexts/execution/host-capability-manifest.md +26 -15
  16. package/dist/agent-src/contexts/execution/orchestration-telemetry.md +28 -3
  17. package/dist/agent-src/contexts/execution/subagent-response-contract.md +54 -0
  18. package/dist/agent-src/contexts/execution/subagent-routing.md +13 -11
  19. package/dist/agent-src/contexts/execution/subagent-spawn-contract.md +25 -0
  20. package/dist/agent-src/contexts/execution/subagent-steering.md +6 -3
  21. package/dist/agent-src/rules/artifact-engagement-recording.md +4 -1
  22. package/dist/agent-src/rules/autonomous-execution.md +1 -1
  23. package/dist/agent-src/rules/brand-source-of-truth.md +33 -6
  24. package/dist/agent-src/rules/context-hygiene.md +3 -1
  25. package/dist/agent-src/rules/council-availability.md +93 -0
  26. package/dist/agent-src/rules/cross-source-consistency.md +3 -0
  27. package/dist/agent-src/rules/delegation-policy.md +38 -10
  28. package/dist/agent-src/rules/design-fidelity.md +3 -0
  29. package/dist/agent-src/rules/evaluator-independence.md +2 -1
  30. package/dist/agent-src/rules/external-code-graph-interop.md +2 -1
  31. package/dist/agent-src/rules/finance-safety-floor.md +1 -1
  32. package/dist/agent-src/rules/git-history-discipline.md +1 -1
  33. package/dist/agent-src/rules/history-discipline.md +3 -1
  34. package/dist/agent-src/rules/legal-safety-floor.md +1 -1
  35. package/dist/agent-src/rules/no-pr-progress-comments.md +3 -1
  36. package/dist/agent-src/rules/onboarding-gate.md +3 -1
  37. package/dist/agent-src/rules/roadmap-ci-steps-policy.md +4 -1
  38. package/dist/agent-src/rules/role-mode-adherence.md +1 -1
  39. package/dist/agent-src/rules/scale-discipline.md +3 -1
  40. package/dist/agent-src/rules/self-repair-loop.md +103 -0
  41. package/dist/agent-src/rules/session-canary.md +2 -1
  42. package/dist/agent-src/rules/settings-ask-protocol.md +8 -7
  43. package/dist/agent-src/rules/strategy-safety-floor.md +1 -1
  44. package/dist/agent-src/rules/token-budget-discipline.md +4 -2
  45. package/dist/agent-src/rules/tool-safety.md +5 -1
  46. package/dist/agent-src/skills/adversarial-review/SKILL.md +1 -1
  47. package/dist/agent-src/skills/analysis-autonomous-mode/SKILL.md +1 -1
  48. package/dist/agent-src/skills/forensics-report/SKILL.md +114 -0
  49. package/dist/agent-src/skills/forensics-report/evals/triggers.json +17 -0
  50. package/dist/agent-src/skills/performance-analysis/SKILL.md +1 -1
  51. package/dist/agent-src/skills/persona-improvement/SKILL.md +1 -1
  52. package/dist/agent-src/skills/premortem/SKILL.md +30 -1
  53. package/dist/agent-src/skills/project-analyzer/SKILL.md +1 -1
  54. package/dist/agent-src/skills/reasoning-orchestrator/SKILL.md +2 -1
  55. package/dist/agent-src/skills/security-audit/SKILL.md +1 -1
  56. package/dist/agent-src/skills/sequential-thinking/SKILL.md +1 -1
  57. package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +1 -1
  58. package/dist/agent-src/skills/subagent-orchestration/SKILL.md +7 -5
  59. package/dist/agent-src/skills/subagent-orchestration/schemas/subagent-status.json +61 -3
  60. package/dist/agent-src/skills/test-case-discovery/SKILL.md +1 -1
  61. package/dist/agent-src/skills/universal-project-analysis/SKILL.md +1 -1
  62. package/dist/agent-src/templates/AGENTS.md +8 -12
  63. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  64. package/dist/agent-src/templates/roadmaps.md +23 -0
  65. package/dist/cli/registry.js +7 -0
  66. package/dist/cli/registry.js.map +1 -1
  67. package/dist/cli-delegate/chunk-66OVWGB5.js +270 -0
  68. package/dist/cli-delegate/{chunk-HJ6DAJHR.js → chunk-LCFJIQ4J.js} +89 -7
  69. package/dist/cli-delegate/{chunk-VSYT7OHO.js → chunk-LVRYBKTI.js} +31 -2
  70. package/dist/cli-delegate/{chunk-DVRS2KVR.js → chunk-MMXA5GY7.js} +10 -17
  71. package/dist/cli-delegate/{chunk-WR6GTRHJ.js → chunk-MP3JT3IU.js} +3 -3
  72. package/dist/cli-delegate/{chunk-3KJIMFTB.js → chunk-NZ5N2XQL.js} +467 -305
  73. package/dist/cli-delegate/{chunk-AIIUU73N.js → chunk-OJM3MBJM.js} +1 -1
  74. package/dist/cli-delegate/{chunk-BCPIOAGV.js → chunk-RCIA67XN.js} +117 -96
  75. package/dist/cli-delegate/chunk-REKCMYOU.js +2991 -0
  76. package/dist/cli-delegate/cmd_analyze_session.js +1 -1
  77. package/dist/cli-delegate/cmd_brand_status.js +134 -0
  78. package/dist/cli-delegate/cmd_conformance.js +10 -47
  79. package/dist/cli-delegate/cmd_converge.js +3 -3
  80. package/dist/cli-delegate/cmd_doctor.js +10 -6
  81. package/dist/cli-delegate/cmd_explain.js +80 -330
  82. package/dist/cli-delegate/cmd_export.js +6 -6
  83. package/dist/cli-delegate/cmd_fleet.js +3 -3
  84. package/dist/cli-delegate/cmd_handoff.js +3 -3
  85. package/dist/cli-delegate/cmd_mcp_available.js +433 -0
  86. package/dist/cli-delegate/cmd_migrate.js +3 -3
  87. package/dist/cli-delegate/cmd_packs_active.js +153 -0
  88. package/dist/cli-delegate/cmd_preflight.js +1 -1
  89. package/dist/cli-delegate/cmd_prune.js +6 -6
  90. package/dist/cli-delegate/cmd_route_audit.js +8 -8
  91. package/dist/cli-delegate/cmd_route_explain.js +4 -4
  92. package/dist/cli-delegate/cmd_settings_get.js +266 -0
  93. package/dist/cli-delegate/cmd_settings_migrate.js +6 -6
  94. package/dist/cli-delegate/cmd_settings_set.js +8 -2968
  95. package/dist/cli-delegate/cmd_sync.js +6 -6
  96. package/dist/cli-delegate/cmd_uninstall.js +6 -6
  97. package/dist/cli-delegate/cmd_update.js +4 -4
  98. package/dist/cli-delegate/cmd_upgrade.js +4 -4
  99. package/dist/cli-delegate/cmd_validate.js +6 -6
  100. package/dist/cli-delegate/cmd_versions.js +4 -4
  101. package/dist/discovery/deprecation-report.md +1 -1
  102. package/dist/discovery/discovery-manifest.json +164 -55
  103. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  104. package/dist/discovery/discovery-manifest.summary.md +4 -3
  105. package/dist/discovery/orphan-report.md +1 -1
  106. package/dist/discovery/packs.json +44 -5
  107. package/dist/discovery/trust-report.md +11 -11
  108. package/dist/discovery/workspaces.json +16 -6
  109. package/dist/hooks/dispatch.js +9341 -6131
  110. package/dist/install/install.mjs +739 -524
  111. package/dist/mcp/registry-manifest.json +3 -3
  112. package/dist/mcp/server.json +2 -2
  113. package/dist/mcp/server.mjs +777 -281
  114. package/dist/router.json +1 -1
  115. package/dist/scripts/_lib/agent_settings.js +134 -15
  116. package/dist/scripts/_lib/agent_settings.js.map +1 -1
  117. package/dist/scripts/condense.js +147 -2
  118. package/dist/scripts/condense.js.map +1 -1
  119. package/dist/server/schemas/settings.js +6 -7
  120. package/dist/server/schemas/settings.js.map +1 -1
  121. package/dist/shared/settingsCarveOut.js +0 -9
  122. package/dist/shared/settingsCarveOut.js.map +1 -1
  123. package/dist/shared/settingsClasses.js +11 -9
  124. package/dist/shared/settingsClasses.js.map +1 -1
  125. package/dist/ui/assets/{index-DmR0mbk4.js → index-JDAF00bC.js} +2 -2
  126. package/dist/ui/assets/{index-DmR0mbk4.js.map → index-JDAF00bC.js.map} +1 -1
  127. package/dist/ui/index.html +1 -1
  128. package/docs/contracts/settings-classes.md +68 -17
  129. package/docs/guidelines/agent-infra/memory-access.md +14 -3
  130. package/package.json +1 -1
  131. package/src/agent-src/templates/AGENTS.md +8 -12
  132. package/src/config/agent-settings.template.yml +52 -66
  133. package/src/config/budgets.yml +29 -0
  134. package/src/config/discovery/packs.yml +11 -0
  135. package/src/config/discovery/workspaces.yml +1 -1
  136. package/src/config/evaluator-budgets.json +4 -4
  137. package/src/config/gate-coverage.yml +26 -0
  138. package/src/config/gate-violation-baselines.json +3 -3
  139. package/src/scripts/_cli/cmd_brand_status.ts +174 -0
  140. package/src/scripts/_cli/cmd_conformance.ts +14 -42
  141. package/src/scripts/_cli/cmd_doctor.ts +65 -48
  142. package/src/scripts/_cli/cmd_mcp_available.ts +266 -0
  143. package/src/scripts/_cli/cmd_packs_active.ts +225 -0
  144. package/src/scripts/_cli/cmd_settings_get.ts +324 -0
  145. package/src/scripts/_dispatch.bash +57 -0
  146. package/src/scripts/_lib/agent_settings.ts +140 -16
  147. package/src/scripts/_lib/auto_dispatch.corpus.test.ts +1 -1
  148. package/src/scripts/_lib/auto_dispatch.ts +23 -18
  149. package/src/scripts/_lib/capsule_trigger.ts +124 -0
  150. package/src/scripts/_lib/carrier_divergence.ts +135 -0
  151. package/src/scripts/_lib/host_capability.ts +144 -4
  152. package/src/scripts/_lib/judgment_ladder.ts +382 -0
  153. package/src/scripts/_lib/orchestration_gate.ts +8 -0
  154. package/src/scripts/_lib/orchestration_record.ts +37 -0
  155. package/src/scripts/_lib/orchestration_savings.ts +1 -1
  156. package/src/scripts/_lib/prompt_shape.ts +88 -0
  157. package/src/scripts/_lib/review_skipped_record.ts +102 -0
  158. package/src/scripts/_lib/rule_layer_overlap.ts +254 -0
  159. package/src/scripts/_lib/self_repair.ts +489 -0
  160. package/src/scripts/_lib/self_repair_store.ts +128 -0
  161. package/src/scripts/_lib/subagent_capsule.ts +182 -0
  162. package/src/scripts/_lib/subagent_response.ts +19 -0
  163. package/src/scripts/_lib/subagent_spawn.ts +13 -0
  164. package/src/scripts/_lib/subagent_steering.ts +9 -4
  165. package/src/scripts/_lib/tier_budget_routing.ts +6 -1
  166. package/src/scripts/_lib/transcript_entry.ts +80 -0
  167. package/src/scripts/_lib/worker_budget.ts +37 -2
  168. package/src/scripts/ai_council/clients.ts +76 -54
  169. package/src/scripts/ai_council/config.ts +94 -6
  170. package/src/scripts/ai_council/handoff.ts +113 -0
  171. package/src/scripts/ai_council/modes.ts +19 -4
  172. package/src/scripts/ai_council/orchestrator.ts +105 -0
  173. package/src/scripts/ai_council/quorum.ts +84 -0
  174. package/src/scripts/ai_council/session.ts +44 -0
  175. package/src/scripts/ai_council/transport_resolver.ts +127 -1
  176. package/src/scripts/ai_team/availability.ts +110 -0
  177. package/src/scripts/ai_team/config.ts +34 -14
  178. package/src/scripts/ai_team/team_dispatch.ts +71 -29
  179. package/src/scripts/bench_critic_protocol.ts +396 -0
  180. package/src/scripts/check_branch_freshness.ts +255 -0
  181. package/src/scripts/check_council_config_location.ts +125 -1
  182. package/src/scripts/check_detector_corpus.ts +202 -0
  183. package/src/scripts/check_hook_bundle_freshness.ts +4 -1
  184. package/src/scripts/check_standing_rule_delivery.ts +314 -0
  185. package/src/scripts/condense.ts +162 -2
  186. package/src/scripts/config/profiles.ts +13 -3
  187. package/src/scripts/conformance_scan.ts +272 -24
  188. package/src/scripts/council_availability_hook.ts +188 -0
  189. package/src/scripts/council_cli.ts +527 -32
  190. package/src/scripts/forensics_report.ts +333 -0
  191. package/src/scripts/hook_manifest.yaml +107 -26
  192. package/src/scripts/hooks/block_no_verify.ts +39 -2
  193. package/src/scripts/hooks/block_unauthorized_git.ts +156 -7
  194. package/src/scripts/hooks/concern_registry.ts +10 -0
  195. package/src/scripts/hooks/delegation_nudge_hook.ts +484 -0
  196. package/src/scripts/hooks/end_review_nudge_hook.ts +726 -0
  197. package/src/scripts/hooks/orchestration_record_hook.ts +342 -0
  198. package/src/scripts/install.ts +151 -0
  199. package/src/scripts/language_mirror_hook.ts +30 -37
  200. package/src/scripts/lint_discovery_vocabulary.ts +2 -0
  201. package/src/scripts/lint_never_silent.ts +276 -0
  202. package/src/scripts/lint_no_activation_gates.ts +271 -0
  203. package/src/scripts/measure_scope_dedup.ts +19 -13
  204. package/src/scripts/onboarding_gate_hook.ts +40 -1
  205. package/src/scripts/orchestration_record.ts +12 -1
  206. package/src/scripts/preamble_byte_census.ts +9 -20
  207. package/src/scripts/rebuild_hook_bundle.ts +177 -0
  208. package/src/scripts/release.ts +74 -2
  209. package/src/scripts/report_carrier_divergence.ts +364 -0
  210. package/src/scripts/report_skill_activation.ts +257 -0
  211. package/src/scripts/report_skill_obligation_violations.ts +579 -0
  212. package/src/scripts/routing_doctor.ts +95 -39
  213. package/src/scripts/score_skill_selection.ts +19 -5
  214. package/src/scripts/self_repair_cli.ts +470 -0
  215. package/src/scripts/self_repair_hook.ts +241 -0
  216. package/src/scripts/team_events_spike.ts +271 -0
  217. package/src/scripts/team_review_gate_hook.ts +31 -9
  218. package/src/server/schemas/settings.ts +10 -17
  219. package/src/shared/settingsCarveOut.ts +0 -10
  220. package/src/shared/settingsClasses.ts +11 -9
@@ -129,6 +129,7 @@ __export(agent_settings_exports, {
129
129
  PROJECT_ROOT_ENV: () => PROJECT_ROOT_ENV,
130
130
  ProjectRootError: () => ProjectRootError,
131
131
  ROOT_OVERRIDE_ENV: () => ROOT_OVERRIDE_ENV,
132
+ USER_GLOBAL_CANONICAL_RELATIVE: () => USER_GLOBAL_CANONICAL_RELATIVE,
132
133
  USER_GLOBAL_FILENAME: () => USER_GLOBAL_FILENAME,
133
134
  canonical_settings_write_path: () => canonical_settings_write_path,
134
135
  enumerate_modules: () => enumerate_modules,
@@ -140,7 +141,8 @@ __export(agent_settings_exports, {
140
141
  load_agent_settings: () => load_agent_settings,
141
142
  logger: () => logger,
142
143
  project_settings_path: () => project_settings_path,
143
- resolve_project_root: () => resolve_project_root
144
+ resolve_project_root: () => resolve_project_root,
145
+ user_global_settings_paths: () => user_global_settings_paths
144
146
  });
145
147
  import { createRequire } from "node:module";
146
148
  import * as fs3 from "node:fs";
@@ -192,12 +194,20 @@ function canonical_settings_write_path(project_root) {
192
194
  function DEFAULT_USER_GLOBAL_FILE() {
193
195
  return write_target(USER_GLOBAL_FILENAME);
194
196
  }
195
- function _resolve_user_global_file() {
196
- const found = resolve_with_fallback(USER_GLOBAL_FILENAME);
197
- if (found !== null) {
198
- return found;
197
+ function user_global_settings_paths() {
198
+ const paths = [];
199
+ const flat = resolve_with_fallback(USER_GLOBAL_FILENAME);
200
+ if (flat !== null) {
201
+ paths.push(flat);
199
202
  }
200
- return DEFAULT_USER_GLOBAL_FILE();
203
+ const canonical = resolve_with_fallback(USER_GLOBAL_CANONICAL_RELATIVE);
204
+ if (canonical !== null) {
205
+ paths.push(canonical);
206
+ }
207
+ if (paths.length === 0) {
208
+ paths.push(DEFAULT_USER_GLOBAL_FILE());
209
+ }
210
+ return paths;
201
211
  }
202
212
  function _exists(p) {
203
213
  try {
@@ -442,7 +452,10 @@ function load_agent_settings(options = {}) {
442
452
  const user_global_path = options.user_global_path ?? null;
443
453
  const verbose = options.verbose ?? false;
444
454
  const cwd = options.cwd ?? null;
445
- const user_global_raw = _read_yaml(user_global_path ? user_global_path : _resolve_user_global_file()) ?? {};
455
+ const user_global_raw = {};
456
+ for (const p of user_global_path ? [user_global_path] : user_global_settings_paths()) {
457
+ _deep_merge(user_global_raw, _read_yaml(p) ?? {});
458
+ }
446
459
  const [user_global_filtered, ignored] = _filter_whitelist(user_global_raw, MERGEABLE_KEYS);
447
460
  if (verbose && ignored.length > 0) {
448
461
  logger.info(
@@ -459,8 +472,32 @@ function load_agent_settings(options = {}) {
459
472
  _deep_merge(merged, layer);
460
473
  }
461
474
  }
475
+ _warn_removed_always_on_keys(merged);
462
476
  return merged;
463
477
  }
478
+ function _readDottedSettingsPath(root, dotted) {
479
+ let node = root;
480
+ for (const part of dotted.split(".")) {
481
+ if (typeof node !== "object" || node === null || Array.isArray(node)) {
482
+ return void 0;
483
+ }
484
+ node = node[part];
485
+ }
486
+ return node;
487
+ }
488
+ function _warn_removed_always_on_keys(merged) {
489
+ for (const key of REMOVED_ALWAYS_ON_KEYS) {
490
+ if (_warnedRemovedAlwaysOnKeys.has(key)) {
491
+ continue;
492
+ }
493
+ if (_readDottedSettingsPath(merged, key) === void 0) {
494
+ continue;
495
+ }
496
+ _warnedRemovedAlwaysOnKeys.add(key);
497
+ process.stderr.write(`${key} was removed (always-on orchestration); ignored.
498
+ `);
499
+ }
500
+ }
464
501
  function get_modules_config(options = {}) {
465
502
  const project_root = options.project_root ?? null;
466
503
  const team_path = options.team_path ?? null;
@@ -595,12 +632,11 @@ function* iter_setting_overrides(options = {}) {
595
632
  const project_path = options.project_path ?? null;
596
633
  const user_global_path = options.user_global_path ?? null;
597
634
  const cwd = options.cwd ?? null;
598
- const user_global_path_resolved = user_global_path ? user_global_path : _resolve_user_global_file();
599
- const user_global_raw = _read_yaml(user_global_path_resolved) ?? {};
600
- const [user_global_filtered] = _filter_whitelist(user_global_raw, MERGEABLE_KEYS);
601
- if (Object.keys(user_global_filtered).length > 0) {
602
- for (const key of _leaf_paths(user_global_filtered)) {
603
- yield [key, _get_dotted(user_global_filtered, key), user_global_path_resolved];
635
+ for (const p of user_global_path ? [user_global_path] : user_global_settings_paths()) {
636
+ const raw = _read_yaml(p) ?? {};
637
+ const [filtered] = _filter_whitelist(raw, MERGEABLE_KEYS);
638
+ for (const key of _leaf_paths(filtered)) {
639
+ yield [key, _get_dotted(filtered, key), p];
604
640
  }
605
641
  }
606
642
  for (const p of _resolve_cascade_paths(cwd, project_path)) {
@@ -741,7 +777,7 @@ function _relative_to(child, root) {
741
777
  function _posix_join(a, b) {
742
778
  return `${a.split(path3.sep).join("/")}/${b}`;
743
779
  }
744
- var _require, Logger, logger, DEFAULT_PROJECT_FILE, LOCAL_PROJECT_FILE, LOCAL_PROJECT_SUBDIR, DEFAULT_TEAM_FILE, USER_GLOBAL_FILENAME, MERGEABLE_KEYS, _DEFAULTS, MODULES_DEFAULTS, ANCHOR_AGENT_SETTINGS, ANCHOR_AGENTS_DIR, ANCHOR_GIT, _AGENTS_DIR_MARKERS, _LEGACY_ANCHOR_ENV, ORIGIN_ROOT_FLAG, ORIGIN_EXPLICIT, ORIGIN_ENV, ORIGIN_CWD_FALLBACK, PROJECT_ROOT_ENV, ROOT_OVERRIDE_ENV, ProjectRootError;
780
+ var _require, Logger, logger, DEFAULT_PROJECT_FILE, LOCAL_PROJECT_FILE, LOCAL_PROJECT_SUBDIR, DEFAULT_TEAM_FILE, USER_GLOBAL_FILENAME, USER_GLOBAL_CANONICAL_RELATIVE, MERGEABLE_KEYS, _DEFAULTS, MODULES_DEFAULTS, ANCHOR_AGENT_SETTINGS, ANCHOR_AGENTS_DIR, ANCHOR_GIT, _AGENTS_DIR_MARKERS, _LEGACY_ANCHOR_ENV, ORIGIN_ROOT_FLAG, ORIGIN_EXPLICIT, ORIGIN_ENV, ORIGIN_CWD_FALLBACK, PROJECT_ROOT_ENV, ROOT_OVERRIDE_ENV, ProjectRootError, REMOVED_ALWAYS_ON_KEYS, _warnedRemovedAlwaysOnKeys;
745
781
  var init_agent_settings = __esm({
746
782
  "src/scripts/_lib/agent_settings.ts"() {
747
783
  "use strict";
@@ -763,12 +799,27 @@ var init_agent_settings = __esm({
763
799
  LOCAL_PROJECT_SUBDIR = ["agents", "settings"];
764
800
  DEFAULT_TEAM_FILE = ".agent-project-settings.yml";
765
801
  USER_GLOBAL_FILENAME = "agent-settings.yml";
802
+ USER_GLOBAL_CANONICAL_RELATIVE = "settings/.agent-settings.yml";
766
803
  MERGEABLE_KEYS = [
804
+ // `name`, `ide` and `personal.bot_icon` are the PRE-MIGRATION spellings.
805
+ // `install.ts` migrates `ide` → `personal.ide` and `pr_comment_bot_icon`
806
+ // into its `personal.` home, and this list was never moved with them — so
807
+ // the whitelist named keys the template does not have while the keys it
808
+ // does have were filtered out silently. A user setting either preference
809
+ // user-globally got no error, no warning, and no effect
810
+ // (road-to-capability-answerability 4.3, ADR-219).
811
+ //
812
+ // Both spellings are listed rather than replaced: a legacy file that still
813
+ // uses the old name keeps working, and nothing that resolved before
814
+ // resolves differently. `name` has no reader anywhere and no template key;
815
+ // it is kept only so this change stays purely additive.
767
816
  "name",
768
817
  "ide",
818
+ "personal.ide",
769
819
  "rule_loading_tier",
770
820
  "memory.cadence",
771
821
  "personal.bot_icon",
822
+ "personal.pr_comment_bot_icon",
772
823
  "personal.autonomy",
773
824
  "telegraph.speak_scope",
774
825
  // Knowledge-card global cross-project sharing is a USER-GLOBAL setting
@@ -816,6 +867,14 @@ var init_agent_settings = __esm({
816
867
  this.name = "ProjectRootError";
817
868
  }
818
869
  };
870
+ REMOVED_ALWAYS_ON_KEYS = [
871
+ "subagents.enabled",
872
+ "subagents.auto",
873
+ "subagents.host_capabilities",
874
+ "subagents.budget_routing",
875
+ "ai_team.enabled"
876
+ ];
877
+ _warnedRemovedAlwaysOnKeys = /* @__PURE__ */ new Set();
819
878
  }
820
879
  });
821
880
 
@@ -23814,8 +23873,19 @@ ${user_prompt}`;
23814
23873
  "429",
23815
23874
  "usage limit"
23816
23875
  ];
23817
- constructor(opts) {
23876
+ /**
23877
+ * `identity` carries the subclass constants (`name`, `default_binary`)
23878
+ * that construction validates against. They are passed explicitly rather
23879
+ * than read off `this.name` / `this.default_binary` because subclass
23880
+ * instance-field initializers (`override default_binary = 'claude'`,
23881
+ * declared in the subclass body) run only AFTER this `super()` call
23882
+ * returns — reading them here, before that happens, would always see the
23883
+ * base class's own field defaults (`''`), not the subclass override.
23884
+ */
23885
+ constructor(opts, identity) {
23818
23886
  super();
23887
+ this.name = identity.name;
23888
+ this.default_binary = identity.default_binary;
23819
23889
  this.model = opts.model;
23820
23890
  this.timeout_seconds = opts.timeout_seconds ?? DEFAULT_CLI_TIMEOUT_SECONDS;
23821
23891
  this.max_calls_per_day = opts.max_calls_per_day ?? null;
@@ -24020,18 +24090,19 @@ ${user_prompt}`;
24020
24090
  }
24021
24091
  };
24022
24092
  AnthropicCliClient = class extends CliClient {
24023
- name = "anthropic";
24024
- default_binary = "claude";
24025
24093
  subscription_label = "claude-pro";
24026
24094
  constructor(opts = {}) {
24027
- super({
24028
- model: opts.model ?? DEFAULT_ANTHROPIC_CLI_MODEL,
24029
- binary: opts.binary,
24030
- timeout_seconds: opts.timeout_seconds,
24031
- max_calls_per_day: opts.max_calls_per_day,
24032
- warn_at: opts.warn_at,
24033
- cli_calls_path: opts.cli_calls_path
24034
- });
24095
+ super(
24096
+ {
24097
+ model: opts.model ?? DEFAULT_ANTHROPIC_CLI_MODEL,
24098
+ binary: opts.binary,
24099
+ timeout_seconds: opts.timeout_seconds,
24100
+ max_calls_per_day: opts.max_calls_per_day,
24101
+ warn_at: opts.warn_at,
24102
+ cli_calls_path: opts.cli_calls_path
24103
+ },
24104
+ { name: "anthropic", default_binary: "claude" }
24105
+ );
24035
24106
  }
24036
24107
  _build_command(system_prompt, user_prompt, max_tokens) {
24037
24108
  void user_prompt;
@@ -24091,8 +24162,6 @@ ${user_prompt}`;
24091
24162
  }
24092
24163
  };
24093
24164
  OpenAICliClient = class extends CliClient {
24094
- name = "openai";
24095
- default_binary = "codex";
24096
24165
  subscription_label = "chatgpt-plus";
24097
24166
  static _AUTH_FAILURE_PATTERNS = [
24098
24167
  ...CliClient._AUTH_FAILURE_PATTERNS,
@@ -24101,14 +24170,17 @@ ${user_prompt}`;
24101
24170
  "401"
24102
24171
  ];
24103
24172
  constructor(opts = {}) {
24104
- super({
24105
- model: opts.model ?? DEFAULT_OPENAI_CLI_MODEL,
24106
- binary: opts.binary,
24107
- timeout_seconds: opts.timeout_seconds,
24108
- max_calls_per_day: opts.max_calls_per_day,
24109
- warn_at: opts.warn_at,
24110
- cli_calls_path: opts.cli_calls_path
24111
- });
24173
+ super(
24174
+ {
24175
+ model: opts.model ?? DEFAULT_OPENAI_CLI_MODEL,
24176
+ binary: opts.binary,
24177
+ timeout_seconds: opts.timeout_seconds,
24178
+ max_calls_per_day: opts.max_calls_per_day,
24179
+ warn_at: opts.warn_at,
24180
+ cli_calls_path: opts.cli_calls_path
24181
+ },
24182
+ { name: "openai", default_binary: "codex" }
24183
+ );
24112
24184
  }
24113
24185
  _build_command(system_prompt, user_prompt, max_tokens) {
24114
24186
  void max_tokens;
@@ -24197,8 +24269,6 @@ ${user_prompt}`;
24197
24269
  }
24198
24270
  };
24199
24271
  GeminiCliClient = class extends CliClient {
24200
- name = "gemini";
24201
- default_binary = "gemini";
24202
24272
  subscription_label = "gemini-pro";
24203
24273
  static _AUTH_FAILURE_PATTERNS = [
24204
24274
  ...CliClient._AUTH_FAILURE_PATTERNS,
@@ -24207,14 +24277,17 @@ ${user_prompt}`;
24207
24277
  "oauth"
24208
24278
  ];
24209
24279
  constructor(opts = {}) {
24210
- super({
24211
- model: opts.model ?? DEFAULT_GEMINI_CLI_MODEL,
24212
- binary: opts.binary,
24213
- timeout_seconds: opts.timeout_seconds,
24214
- max_calls_per_day: opts.max_calls_per_day,
24215
- warn_at: opts.warn_at,
24216
- cli_calls_path: opts.cli_calls_path
24217
- });
24280
+ super(
24281
+ {
24282
+ model: opts.model ?? DEFAULT_GEMINI_CLI_MODEL,
24283
+ binary: opts.binary,
24284
+ timeout_seconds: opts.timeout_seconds,
24285
+ max_calls_per_day: opts.max_calls_per_day,
24286
+ warn_at: opts.warn_at,
24287
+ cli_calls_path: opts.cli_calls_path
24288
+ },
24289
+ { name: "gemini", default_binary: "gemini" }
24290
+ );
24218
24291
  }
24219
24292
  _build_command(system_prompt, user_prompt, max_tokens) {
24220
24293
  void user_prompt;
@@ -24289,8 +24362,6 @@ ${user_prompt}`;
24289
24362
  }
24290
24363
  };
24291
24364
  XAICliClient = class extends CliClient {
24292
- name = "xai";
24293
- default_binary = "grok";
24294
24365
  billable = true;
24295
24366
  // community CLI consumes an API key — billable applies
24296
24367
  static _AUTH_FAILURE_PATTERNS = [
@@ -24300,14 +24371,17 @@ ${user_prompt}`;
24300
24371
  "unauthorized"
24301
24372
  ];
24302
24373
  constructor(opts = {}) {
24303
- super({
24304
- model: opts.model ?? DEFAULT_XAI_MODEL,
24305
- binary: opts.binary,
24306
- timeout_seconds: opts.timeout_seconds,
24307
- max_calls_per_day: opts.max_calls_per_day,
24308
- warn_at: opts.warn_at,
24309
- cli_calls_path: opts.cli_calls_path
24310
- });
24374
+ super(
24375
+ {
24376
+ model: opts.model ?? DEFAULT_XAI_MODEL,
24377
+ binary: opts.binary,
24378
+ timeout_seconds: opts.timeout_seconds,
24379
+ max_calls_per_day: opts.max_calls_per_day,
24380
+ warn_at: opts.warn_at,
24381
+ cli_calls_path: opts.cli_calls_path
24382
+ },
24383
+ { name: "xai", default_binary: "grok" }
24384
+ );
24311
24385
  }
24312
24386
  _build_command(system_prompt, user_prompt, max_tokens) {
24313
24387
  void system_prompt;
@@ -24333,8 +24407,6 @@ ${user_prompt}`;
24333
24407
  }
24334
24408
  };
24335
24409
  PerplexityCliClient = class extends CliClient {
24336
- name = "perplexity";
24337
- default_binary = "perplexity";
24338
24410
  billable = true;
24339
24411
  // community CLI consumes an API key — billable applies
24340
24412
  static _AUTH_FAILURE_PATTERNS = [
@@ -24344,14 +24416,17 @@ ${user_prompt}`;
24344
24416
  "unauthorized"
24345
24417
  ];
24346
24418
  constructor(opts = {}) {
24347
- super({
24348
- model: opts.model ?? DEFAULT_PERPLEXITY_MODEL,
24349
- binary: opts.binary,
24350
- timeout_seconds: opts.timeout_seconds,
24351
- max_calls_per_day: opts.max_calls_per_day,
24352
- warn_at: opts.warn_at,
24353
- cli_calls_path: opts.cli_calls_path
24354
- });
24419
+ super(
24420
+ {
24421
+ model: opts.model ?? DEFAULT_PERPLEXITY_MODEL,
24422
+ binary: opts.binary,
24423
+ timeout_seconds: opts.timeout_seconds,
24424
+ max_calls_per_day: opts.max_calls_per_day,
24425
+ warn_at: opts.warn_at,
24426
+ cli_calls_path: opts.cli_calls_path
24427
+ },
24428
+ { name: "perplexity", default_binary: "perplexity" }
24429
+ );
24355
24430
  }
24356
24431
  _build_command(system_prompt, user_prompt, max_tokens) {
24357
24432
  void system_prompt;
@@ -24804,6 +24879,7 @@ function _build_config(raw, source_path) {
24804
24879
  const cli_call_budget = _build_cli_call_budget(
24805
24880
  _asDict(_getOr(raw, "cli_call_budget", {}))
24806
24881
  );
24882
+ const quorum = _build_quorum(_get(raw, "quorum", "majority"));
24807
24883
  const necessity_classifier = _build_necessity_classifier(
24808
24884
  _asDict(_getOr(raw, "necessity_classifier", {}))
24809
24885
  );
@@ -24829,6 +24905,7 @@ function _build_config(raw, source_path) {
24829
24905
  "debate_gates"
24830
24906
  );
24831
24907
  const restate = _build_restate(_asDict(_getOr(raw, "restate", {})), "restate");
24908
+ const critic_protocol = _build_critic_protocol(_getOr(raw, "critic_protocol", "legacy"));
24832
24909
  const decision_resolution = _build_decision_resolution(
24833
24910
  _asDict(_getOr(raw, "decision_resolution", {}))
24834
24911
  );
@@ -24850,6 +24927,7 @@ function _build_config(raw, source_path) {
24850
24927
  advisors,
24851
24928
  consensus_scoring: consensus,
24852
24929
  cli_call_budget,
24930
+ quorum,
24853
24931
  necessity_classifier,
24854
24932
  model_downgrade,
24855
24933
  debate,
@@ -24858,6 +24936,7 @@ function _build_config(raw, source_path) {
24858
24936
  chairman,
24859
24937
  debate_gates,
24860
24938
  restate,
24939
+ critic_protocol,
24861
24940
  decision_resolution,
24862
24941
  routing,
24863
24942
  low_impact,
@@ -25059,6 +25138,15 @@ function _build_restate(d, scope) {
25059
25138
  }
25060
25139
  return { enabled: Boolean(enabled) };
25061
25140
  }
25141
+ function _build_critic_protocol(v) {
25142
+ if (v === void 0 || v === null) return "legacy";
25143
+ if (!(_isStr(v) && _VALID_CRITIC_PROTOCOLS.has(v))) {
25144
+ throw new CouncilConfigError(
25145
+ `\`critic_protocol\`=${_pyRepr6(v)} not in ${_sortedListRepr(_VALID_CRITIC_PROTOCOLS)}.`
25146
+ );
25147
+ }
25148
+ return v;
25149
+ }
25062
25150
  function _build_decision_resolution(d) {
25063
25151
  if (!_isDict(d)) {
25064
25152
  throw new CouncilConfigError("`decision_resolution` must be a mapping.");
@@ -25310,7 +25398,7 @@ function _build_defaults(d) {
25310
25398
  if (!_isDict(d)) {
25311
25399
  throw new CouncilConfigError("`defaults` must be a mapping.");
25312
25400
  }
25313
- const mode = _get(d, "mode", "api");
25401
+ const mode = _get(d, "mode", "auto");
25314
25402
  if (!(_isStr(mode) && _VALID_MODES.has(mode))) {
25315
25403
  throw new CouncilConfigError(
25316
25404
  `defaults.mode=${_pyRepr6(mode)} not in ${_sortedListRepr(_VALID_MODES)}.`
@@ -25471,7 +25559,7 @@ function _build_cost_budget(d) {
25471
25559
  }
25472
25560
  return cb;
25473
25561
  }
25474
- function _build_member(name, cfg, default_mode = "api") {
25562
+ function _build_member(name, cfg, default_mode = "auto") {
25475
25563
  if (!_VALID_PROVIDERS.has(name)) {
25476
25564
  throw new CouncilConfigError(
25477
25565
  `members.${name}: unknown provider; valid: ${_sortedListRepr(_VALID_PROVIDERS)}.`
@@ -25599,6 +25687,9 @@ function _build_cli_call_budget(d) {
25599
25687
  );
25600
25688
  }
25601
25689
  const caps = /* @__PURE__ */ new Map();
25690
+ for (const provider of _VALID_PROVIDERS) {
25691
+ caps.set(provider, _DEFAULT_CLI_CALLS_PER_DAY);
25692
+ }
25602
25693
  for (const [provider, value] of Object.entries(raw_caps)) {
25603
25694
  if (!_VALID_PROVIDERS.has(provider)) {
25604
25695
  throw new CouncilConfigError(
@@ -25626,6 +25717,17 @@ function _build_cli_call_budget(d) {
25626
25717
  }
25627
25718
  return { max_calls_per_day: caps, warn_at };
25628
25719
  }
25720
+ function _build_quorum(raw) {
25721
+ if (raw === "majority") {
25722
+ return "majority";
25723
+ }
25724
+ if (_isInt(raw) && !_isBool(raw) && raw >= 1) {
25725
+ return raw;
25726
+ }
25727
+ throw new CouncilConfigError(
25728
+ `\`quorum\`=${_pyRepr6(raw)} must be 'majority' or an integer >= 1 (got ${_pyTypeName(raw)}).`
25729
+ );
25730
+ }
25629
25731
  function _build_advisor(name, cfg) {
25630
25732
  if (!_isDict(cfg)) {
25631
25733
  throw new CouncilConfigError(`advisors.${name}: must be a mapping.`);
@@ -25746,7 +25848,7 @@ function _pyTruthy3(value) {
25746
25848
  }
25747
25849
  return Object.keys(value).length > 0;
25748
25850
  }
25749
- var import_yaml5, _VALID_PROVIDERS, _VALID_MODES, _RAW_KEY_PREFIXES, CouncilConfigError, _Float, _VALID_NECESSITY_MODES, _VALID_DISCLOSURE_MODES, _VALID_CHAIRMAN_MODES, COUNCIL_CONFIG_RELNAME, COUNCIL_CONFIG_USER_GLOBAL_REL, COUNCIL_CONFIG_ENV, _VALID_RESOLUTION_MODES, _IMPACT_CLASSES, _LOCKED_IMPACT_CLASSES, _DEFAULT_RESOLUTION_MODES, _VALID_MEMBER_MODES, _VALID_DISPATCH_MODES;
25851
+ var import_yaml5, _VALID_PROVIDERS, _VALID_MODES, _RAW_KEY_PREFIXES, CouncilConfigError, _Float, _VALID_NECESSITY_MODES, _VALID_DISCLOSURE_MODES, _VALID_CHAIRMAN_MODES, COUNCIL_CONFIG_RELNAME, COUNCIL_CONFIG_USER_GLOBAL_REL, COUNCIL_CONFIG_ENV, _VALID_CRITIC_PROTOCOLS, _VALID_RESOLUTION_MODES, _IMPACT_CLASSES, _LOCKED_IMPACT_CLASSES, _DEFAULT_RESOLUTION_MODES, _VALID_MEMBER_MODES, _VALID_DISPATCH_MODES, _DEFAULT_CLI_CALLS_PER_DAY;
25750
25852
  var init_config = __esm({
25751
25853
  "src/scripts/ai_council/config.ts"() {
25752
25854
  "use strict";
@@ -25796,6 +25898,7 @@ var init_config = __esm({
25796
25898
  COUNCIL_CONFIG_RELNAME = ".ai-council.yml";
25797
25899
  COUNCIL_CONFIG_USER_GLOBAL_REL = "settings/.ai-council.yml";
25798
25900
  COUNCIL_CONFIG_ENV = "AI_COUNCIL_CONFIG";
25901
+ _VALID_CRITIC_PROTOCOLS = /* @__PURE__ */ new Set(["legacy", "load_bearing"]);
25799
25902
  _VALID_RESOLUTION_MODES = /* @__PURE__ */ new Set([
25800
25903
  "agent",
25801
25904
  "council",
@@ -25821,6 +25924,7 @@ var init_config = __esm({
25821
25924
  };
25822
25925
  _VALID_MEMBER_MODES = /* @__PURE__ */ new Set(["cli", "api"]);
25823
25926
  _VALID_DISPATCH_MODES = /* @__PURE__ */ new Set(["full", "single"]);
25927
+ _DEFAULT_CLI_CALLS_PER_DAY = 50;
25824
25928
  }
25825
25929
  });
25826
25930
 
@@ -26132,6 +26236,112 @@ var init_environment_detector = __esm({
26132
26236
  }
26133
26237
  });
26134
26238
 
26239
+ // src/scripts/ai_council/modes.ts
26240
+ function _sortedValidModes() {
26241
+ return Array.from(VALID_MODES).sort();
26242
+ }
26243
+ function _normalise(value) {
26244
+ if (value === null || value === void 0) {
26245
+ return null;
26246
+ }
26247
+ if (typeof value !== "string") {
26248
+ return null;
26249
+ }
26250
+ const s = value.trim().toLowerCase();
26251
+ return s || null;
26252
+ }
26253
+ function _validate2(mode, source) {
26254
+ if (mode === null) {
26255
+ return null;
26256
+ }
26257
+ if (!VALID_MODES.has(mode)) {
26258
+ throw new InvalidModeError(
26259
+ `${source} requested mode=${_pyRepr7(mode)}; expected one of: ${_pyReprList2(_sortedValidModes())}`
26260
+ );
26261
+ }
26262
+ return mode;
26263
+ }
26264
+ function _pyRepr7(s) {
26265
+ return `'${s}'`;
26266
+ }
26267
+ function _pyReprList2(items) {
26268
+ return `[${items.map((i) => _pyRepr7(i)).join(", ")}]`;
26269
+ }
26270
+ function resolve_global_mode(aiBlock) {
26271
+ if (aiBlock === null || aiBlock === void 0) {
26272
+ return null;
26273
+ }
26274
+ const flat = _normalise(_settingsGet(aiBlock, "mode"));
26275
+ if (flat !== null) {
26276
+ return flat;
26277
+ }
26278
+ const defaults = _settingsGet(aiBlock, "defaults");
26279
+ if (defaults === null || defaults === void 0) {
26280
+ return null;
26281
+ }
26282
+ if (!(defaults instanceof Map) && typeof defaults !== "object") {
26283
+ return null;
26284
+ }
26285
+ if (Array.isArray(defaults)) {
26286
+ return null;
26287
+ }
26288
+ return _normalise(
26289
+ _settingsGet(defaults, "mode")
26290
+ );
26291
+ }
26292
+ function _settingsGet(settings, key) {
26293
+ if (settings === null || settings === void 0) {
26294
+ return void 0;
26295
+ }
26296
+ if (settings instanceof Map) {
26297
+ return settings.get(key);
26298
+ }
26299
+ return settings[key];
26300
+ }
26301
+ function resolve_mode(memberName, opts = {}) {
26302
+ const invocationMode = opts.invocationMode ?? null;
26303
+ const memberSettings = opts.memberSettings ?? null;
26304
+ const globalMode = opts.globalMode ?? null;
26305
+ const inv = _validate2(
26306
+ _normalise(invocationMode),
26307
+ `/council mode= for ${_pyRepr7(memberName)}`
26308
+ );
26309
+ if (inv !== null) {
26310
+ return inv;
26311
+ }
26312
+ let memberModeRaw = null;
26313
+ if (memberSettings !== null) {
26314
+ const v = _settingsGet(memberSettings, "mode");
26315
+ memberModeRaw = v === void 0 ? null : v;
26316
+ }
26317
+ const member = _validate2(
26318
+ _normalise(memberModeRaw),
26319
+ `ai_council.members.${memberName}.mode`
26320
+ );
26321
+ if (member !== null) {
26322
+ return member;
26323
+ }
26324
+ const glob2 = _validate2(_normalise(globalMode), "ai_council.mode");
26325
+ if (glob2 !== null) {
26326
+ return glob2;
26327
+ }
26328
+ return DEFAULT_MODE;
26329
+ }
26330
+ var VALID_MODES, DEFAULT_MODE, InvalidModeError;
26331
+ var init_modes = __esm({
26332
+ "src/scripts/ai_council/modes.ts"() {
26333
+ "use strict";
26334
+ VALID_MODES = /* @__PURE__ */ new Set(["api", "manual", "cli", "auto"]);
26335
+ DEFAULT_MODE = "manual";
26336
+ InvalidModeError = class extends Error {
26337
+ constructor(message) {
26338
+ super(message);
26339
+ this.name = "InvalidModeError";
26340
+ }
26341
+ };
26342
+ }
26343
+ });
26344
+
26135
26345
  // src/scripts/ai_council/transport_resolver.ts
26136
26346
  function hasSource(report2, provider, allowed) {
26137
26347
  return report2.auth.some((a) => a.provider === provider && allowed.has(a.source));
@@ -26166,7 +26376,8 @@ function resolveTransport(opts) {
26166
26376
  billing,
26167
26377
  authSource,
26168
26378
  makesProviderCall: false,
26169
- reason: null
26379
+ reason: null,
26380
+ absentReason: null
26170
26381
  };
26171
26382
  }
26172
26383
  if (mode === "api" || mode === "cli") {
@@ -26176,7 +26387,8 @@ function resolveTransport(opts) {
26176
26387
  billing,
26177
26388
  authSource,
26178
26389
  makesProviderCall: true,
26179
- reason: null
26390
+ reason: null,
26391
+ absentReason: null
26180
26392
  };
26181
26393
  }
26182
26394
  if (mode !== "auto") {
@@ -26196,7 +26408,8 @@ function resolveTransport(opts) {
26196
26408
  billing,
26197
26409
  authSource,
26198
26410
  makesProviderCall: true,
26199
- reason: null
26411
+ reason: null,
26412
+ absentReason: null
26200
26413
  };
26201
26414
  }
26202
26415
  const keyPresent = opts.apiKeyPresent ?? hasSource(report2, provider, KEY_AUTH_SOURCES);
@@ -26207,12 +26420,36 @@ function resolveTransport(opts) {
26207
26420
  billing,
26208
26421
  authSource,
26209
26422
  makesProviderCall: true,
26210
- reason: null
26423
+ reason: null,
26424
+ absentReason: null
26211
26425
  };
26212
26426
  }
26213
- return unavailable(provider, billing, autoUnavailableReason(provider, binary, cliAuthed));
26427
+ return unavailable(
26428
+ provider,
26429
+ billing,
26430
+ autoUnavailableReason(provider, binary, cliAuthed),
26431
+ classifyStaticAbsentReason(binary)
26432
+ );
26433
+ }
26434
+ function resolveMemberTransport(opts) {
26435
+ const configuredMode = resolve_mode(opts.provider, {
26436
+ invocationMode: opts.invocationMode ?? null,
26437
+ memberSettings: opts.memberSettings ?? null,
26438
+ globalMode: opts.globalMode ?? null
26439
+ });
26440
+ const resolved = resolveTransport({
26441
+ provider: opts.provider,
26442
+ mode: configuredMode,
26443
+ report: opts.report,
26444
+ binaryOverride: opts.binaryOverride ?? null,
26445
+ // `exactOptionalPropertyTypes` rejects an explicit `undefined` for an
26446
+ // optional-boolean field, so the key is omitted entirely rather than
26447
+ // forwarded as `apiKeyPresent: undefined`.
26448
+ ...opts.apiKeyPresent !== void 0 ? { apiKeyPresent: opts.apiKeyPresent } : {}
26449
+ });
26450
+ return { ...resolved, configuredMode };
26214
26451
  }
26215
- function unavailable(_provider, billing, reason) {
26452
+ function unavailable(_provider, billing, reason, absentReason = null) {
26216
26453
  return {
26217
26454
  available: false,
26218
26455
  transport: null,
@@ -26221,9 +26458,13 @@ function unavailable(_provider, billing, reason) {
26221
26458
  billing,
26222
26459
  authSource: null,
26223
26460
  makesProviderCall: false,
26224
- reason
26461
+ reason,
26462
+ absentReason
26225
26463
  };
26226
26464
  }
26465
+ function classifyStaticAbsentReason(binary) {
26466
+ return binary === null ? "no_binary" : "no_auth";
26467
+ }
26227
26468
  function autoUnavailableReason(provider, binary, cliAuthed) {
26228
26469
  const expected = PROVIDER_CLI_META[provider]?.[0] ?? provider;
26229
26470
  if (binary === null && !cliAuthed) {
@@ -26234,11 +26475,40 @@ function autoUnavailableReason(provider, binary, cliAuthed) {
26234
26475
  }
26235
26476
  return `no transport available: \`${expected}\` is on PATH but not authenticated and no key resolves \u2014 log in to the CLI, or add an api_key_ref`;
26236
26477
  }
26478
+ function classifyCliFailure(raw) {
26479
+ const s = raw.trim().toLowerCase();
26480
+ if (s === "binary_missing" || s === "file_not_found") return "binary_missing";
26481
+ if (s === "auth_expired" || s === "auth_rejected" || s === "unauthorized") {
26482
+ return "auth_rejected";
26483
+ }
26484
+ if (s === "cli_unsupported" || s === "unsupported" || s === "parse_failed") {
26485
+ return "cli_unsupported";
26486
+ }
26487
+ if (s === "timeout") return "timeout";
26488
+ if (s === "cli_quota_exhausted" || s === "quota_exhausted") return "quota_exhausted";
26489
+ if (/^exit_5\d\d$/.test(s) || s === "server_error" || s === "os") return "server_error";
26490
+ return "other";
26491
+ }
26492
+ function absentReasonFromCliFailure(failure) {
26493
+ switch (failure) {
26494
+ case "binary_missing":
26495
+ return "no_binary";
26496
+ case "auth_rejected":
26497
+ return "no_auth";
26498
+ case "timeout":
26499
+ return "timeout";
26500
+ case "quota_exhausted":
26501
+ return "quota";
26502
+ default:
26503
+ return null;
26504
+ }
26505
+ }
26237
26506
  var VALID_TRANSPORT_MODES, CLI_AUTH_SOURCES, KEY_AUTH_SOURCES;
26238
26507
  var init_transport_resolver = __esm({
26239
26508
  "src/scripts/ai_council/transport_resolver.ts"() {
26240
26509
  "use strict";
26241
26510
  init_environment_detector();
26511
+ init_modes();
26242
26512
  VALID_TRANSPORT_MODES = /* @__PURE__ */ new Set([
26243
26513
  "api",
26244
26514
  "manual",
@@ -26512,7 +26782,6 @@ var init_config2 = __esm({
26512
26782
  max_consecutive_blocks: 3
26513
26783
  });
26514
26784
  AI_TEAM_DEFAULTS = Object.freeze({
26515
- enabled: false,
26516
26785
  model: "auto",
26517
26786
  allow_delegate: false,
26518
26787
  max_calls_per_day: 50,
@@ -26925,8 +27194,10 @@ __export(cmd_doctor_exports, {
26925
27194
  _scan_foreign: () => _scan_foreign,
26926
27195
  _settings_layer_chain: () => _settings_layer_chain,
26927
27196
  _skipped_manifest_check: () => _skipped_manifest_check,
27197
+ _team_codex_binary_name: () => _team_codex_binary_name,
26928
27198
  _wizard_state_path: () => _wizard_state_path,
26929
- main: () => main15
27199
+ main: () => main15,
27200
+ shutilWhich: () => shutilWhich
26930
27201
  });
26931
27202
  import * as crypto6 from "node:crypto";
26932
27203
  import * as fs45 from "node:fs";
@@ -28343,6 +28614,13 @@ function osErrorStr2(exc) {
28343
28614
  }
28344
28615
  return String(exc);
28345
28616
  }
28617
+ function _effectiveMemberMode(member, cfg) {
28618
+ return member.mode ?? cfg.defaults.mode;
28619
+ }
28620
+ function _mayRunOverCli(member, cfg) {
28621
+ const mode = _effectiveMemberMode(member, cfg);
28622
+ return mode === "cli" || mode === "auto";
28623
+ }
28346
28624
  function _check_council_cli(project_root) {
28347
28625
  const { load_cli_call_counts: load_cli_call_counts2 } = clients_exports;
28348
28626
  const { load_council_config: load_council_config2, resolve_config_path: resolve_config_path2 } = config_exports;
@@ -28368,7 +28646,7 @@ function _check_council_cli(project_root) {
28368
28646
  }
28369
28647
  const cli_members = [];
28370
28648
  for (const [name, m] of cfg.members.entries()) {
28371
- if (m.enabled && m.mode === "cli" && name in _CLI_PROVIDER_META) {
28649
+ if (m.enabled && _mayRunOverCli(m, cfg) && name in _CLI_PROVIDER_META) {
28372
28650
  cli_members.push([name, m]);
28373
28651
  }
28374
28652
  }
@@ -28467,18 +28745,11 @@ function _team_codex_binary_name(project_root) {
28467
28745
  return default_bin;
28468
28746
  }
28469
28747
  const member = cfg.members.get("openai");
28470
- if (member && member.enabled && member.mode === "cli" && member.binary) {
28748
+ if (member && member.enabled && _mayRunOverCli(member, cfg) && member.binary) {
28471
28749
  return member.binary;
28472
28750
  }
28473
28751
  return default_bin;
28474
28752
  }
28475
- function _settings_flag(val) {
28476
- if (typeof val === "boolean") return val;
28477
- if (typeof val === "string") {
28478
- return ["true", "yes", "on", "1"].includes(val.trim().toLowerCase());
28479
- }
28480
- return false;
28481
- }
28482
28753
  function _jwt_exp(token) {
28483
28754
  if (typeof token !== "string") return null;
28484
28755
  const parts = token.split(".");
@@ -28642,31 +28913,14 @@ function _check_detection(project_root) {
28642
28913
  }
28643
28914
  function _check_team(project_root) {
28644
28915
  const ai_team = _read_ai_team_block(project_root);
28645
- const enabled = _settings_flag(ai_team["enabled"]);
28646
28916
  const gateRaw = ai_team["review_gate"];
28647
28917
  const gate = typeof gateRaw === "object" && gateRaw !== null && !Array.isArray(gateRaw) ? gateRaw : {};
28648
- const gate_managed = _settings_flag(gate["managed"]);
28649
- if (!enabled) {
28650
- if (gate_managed) {
28651
- return {
28652
- id: "team",
28653
- status: "warn",
28654
- message: "half-configured: ai_team.review_gate.managed is on but ai_team.enabled is false \u2014 the gate never runs",
28655
- remedy: "set `ai_team.enabled: true` in .agent-settings.yml, or remove `ai_team.review_gate.managed`"
28656
- };
28657
- }
28658
- return {
28659
- id: "team",
28660
- status: "ok",
28661
- message: "team mode not configured (default-off)",
28662
- remedy: "opt in via `ai_team.enabled: true` in .agent-settings.yml, then re-run `agent-config doctor --check team`"
28663
- };
28664
- }
28665
28918
  const remedies = [];
28666
28919
  const binary_name = _team_codex_binary_name(project_root);
28667
28920
  const binary_resolved = shutilWhich(binary_name);
28668
28921
  const binary_glyph = binary_resolved !== null ? "\u2705" : "\u274C";
28669
- if (binary_resolved === null) {
28922
+ const binary_missing = binary_resolved === null;
28923
+ if (binary_missing) {
28670
28924
  remedies.push("install the codex CLI: `npm install -g @openai/codex`");
28671
28925
  }
28672
28926
  const auth_path = path43.join(_codex_home(), "auth.json");
@@ -28707,6 +28961,14 @@ function _check_team(project_root) {
28707
28961
  const gate_str = gate_signal.gate_str;
28708
28962
  remedies.push(...gate_signal.remedies);
28709
28963
  const detail = `codex binary ${binary_glyph} (${binary_name}) \xB7 ${auth_str} \xB7 ${plugin_str} \xB7 ${gate_str}`;
28964
+ if (binary_missing && !authed) {
28965
+ return {
28966
+ id: "team",
28967
+ status: "ok",
28968
+ message: `team unavailable (default) \u2014 codex CLI not installed \xB7 ${detail}`,
28969
+ remedy: remedies.join("; ")
28970
+ };
28971
+ }
28710
28972
  if (remedies.length > 0) {
28711
28973
  return {
28712
28974
  id: "team",
@@ -28718,7 +28980,7 @@ function _check_team(project_root) {
28718
28980
  return {
28719
28981
  id: "team",
28720
28982
  status: "ok",
28721
- message: `team mode enabled \xB7 ${detail}`,
28983
+ message: `team available \xB7 ${detail}`,
28722
28984
  remedy: ""
28723
28985
  };
28724
28986
  }
@@ -29983,7 +30245,7 @@ function _check_host_manifest(projectRoot) {
29983
30245
  return {
29984
30246
  id: "host-manifest",
29985
30247
  status: "ok",
29986
- message: `no .agent-settings.yml \u2014 safe-default manifest applies (${detectedNote})`,
30248
+ message: `no .agent-settings.yml \u2014 host capability is always probe/registry-resolved (${detectedNote})`,
29987
30249
  remedy: ""
29988
30250
  };
29989
30251
  }
@@ -30004,44 +30266,14 @@ function _check_host_manifest(projectRoot) {
30004
30266
  return {
30005
30267
  id: "host-manifest",
30006
30268
  status: "ok",
30007
- message: `no host_capabilities override \u2014 safe-default manifest applies (${detectedNote})`,
30269
+ message: `no host_capabilities override \u2014 host capability is always probe/registry-resolved (${detectedNote})`,
30008
30270
  remedy: ""
30009
30271
  };
30010
30272
  }
30011
- if (typeof manifest !== "object" || Array.isArray(manifest)) {
30012
- return {
30013
- id: "host-manifest",
30014
- status: "fail",
30015
- message: "subagents.host_capabilities is not a mapping",
30016
- remedy: "use the four boolean fields from the host-capability manifest contract"
30017
- };
30018
- }
30019
- const problems = [];
30020
- for (const [key, value] of Object.entries(manifest)) {
30021
- if (!HOST_MANIFEST_KEYS.has(key)) {
30022
- problems.push(`unknown key '${key}'`);
30023
- continue;
30024
- }
30025
- if (key === "schema_version") {
30026
- if (value !== 1) problems.push(`schema_version must be 1 (got ${JSON.stringify(value)})`);
30027
- continue;
30028
- }
30029
- if (typeof value !== "boolean") {
30030
- problems.push(`'${key}' must be boolean (got ${JSON.stringify(value)})`);
30031
- }
30032
- }
30033
- if (problems.length > 0) {
30034
- return {
30035
- id: "host-manifest",
30036
- status: "fail",
30037
- message: `host_capabilities malformed: ${problems.slice(0, 4).join("; ")}`,
30038
- remedy: "only schema_version:1 + four boolean capability fields are valid"
30039
- };
30040
- }
30041
30273
  return {
30042
30274
  id: "host-manifest",
30043
30275
  status: "ok",
30044
- message: `host_capabilities override parses strictly (${detectedNote})`,
30276
+ message: `subagents.host_capabilities is deprecated and ignored \u2014 host capability is always probe/registry-resolved (${detectedNote})`,
30045
30277
  remedy: ""
30046
30278
  };
30047
30279
  }
@@ -30198,7 +30430,7 @@ function _isCliEntry16() {
30198
30430
  return false;
30199
30431
  }
30200
30432
  }
30201
- var YAML6, _HERE13, PACKAGE_ROOT2, CONFORMANCE_CHECK_IDS, THIN_STUB_MARKER, HOST_MANIFEST_KEYS, USAGE3;
30433
+ var YAML6, _HERE13, PACKAGE_ROOT2, CONFORMANCE_CHECK_IDS, THIN_STUB_MARKER, USAGE3;
30202
30434
  var init_cmd_conformance = __esm({
30203
30435
  "src/scripts/_cli/cmd_conformance.ts"() {
30204
30436
  "use strict";
@@ -30220,13 +30452,6 @@ var init_cmd_conformance = __esm({
30220
30452
  "host-manifest"
30221
30453
  ];
30222
30454
  THIN_STUB_MARKER = "Routed rule \u2014 load the body on trigger-match";
30223
- HOST_MANIFEST_KEYS = /* @__PURE__ */ new Set([
30224
- "schema_version",
30225
- "subagent_spawn",
30226
- "parallel_spawn",
30227
- "status_polling",
30228
- "separate_quota_pool"
30229
- ]);
30230
30455
  USAGE3 = "usage: agent-config conformance [-h] [--project PROJECT] [--json]\n [--skip-dispatcher]\n";
30231
30456
  if (_isCliEntry16() || process16.argv[1] === _HERE13) {
30232
30457
  try {
@@ -31496,12 +31721,12 @@ function _enforceSize(text, mode) {
31496
31721
  const n = _utf8Len(text);
31497
31722
  if (n > MAX_BUNDLE_BYTES) {
31498
31723
  throw new BundleTooLarge(
31499
- `Bundle for ${_pyRepr7(mode)} mode is ${n} bytes (> ${MAX_BUNDLE_BYTES} hard ceiling). Narrow the scope (smaller diff, fewer files, shorter prompt).`
31724
+ `Bundle for ${_pyRepr8(mode)} mode is ${n} bytes (> ${MAX_BUNDLE_BYTES} hard ceiling). Narrow the scope (smaller diff, fewer files, shorter prompt).`
31500
31725
  );
31501
31726
  }
31502
31727
  return text;
31503
31728
  }
31504
- function _pyRepr7(s) {
31729
+ function _pyRepr8(s) {
31505
31730
  const hasSingle = s.includes("'");
31506
31731
  const hasDouble = s.includes('"');
31507
31732
  const quote = hasSingle && !hasDouble ? '"' : "'";
@@ -31651,7 +31876,7 @@ function _pyReprStr2(s) {
31651
31876
  }
31652
31877
  return `${quote}${body}${quote}`;
31653
31878
  }
31654
- function _pyRepr8(value) {
31879
+ function _pyRepr9(value) {
31655
31880
  return value === null ? "None" : _pyReprStr2(value);
31656
31881
  }
31657
31882
  function _splitlines8(text) {
@@ -31683,7 +31908,7 @@ function synthesis_template(mode) {
31683
31908
  Object.keys(_INPUT_MODE_TO_SYNTHESIS_KEY)
31684
31909
  );
31685
31910
  throw new Error(
31686
- `Unknown synthesis mode ${_pyRepr8(mode)}. Expected one of: [${expected.map((m) => _pyReprStr2(m)).join(", ")}]`
31911
+ `Unknown synthesis mode ${_pyRepr9(mode)}. Expected one of: [${expected.map((m) => _pyReprStr2(m)).join(", ")}]`
31687
31912
  );
31688
31913
  }
31689
31914
  function _strip_host_identity(text) {
@@ -31733,7 +31958,7 @@ function system_prompt_for(mode, opts = {}) {
31733
31958
  if (!_hasKey(_MODE_TABLE, mode)) {
31734
31959
  const expected = Object.keys(_MODE_TABLE).sort();
31735
31960
  throw new Error(
31736
- `Unknown council mode ${_pyRepr8(mode)}. Expected one of: [${expected.map((m) => _pyReprStr2(m)).join(", ")}]`
31961
+ `Unknown council mode ${_pyRepr9(mode)}. Expected one of: [${expected.map((m) => _pyReprStr2(m)).join(", ")}]`
31737
31962
  );
31738
31963
  }
31739
31964
  const head = handoff_preamble(project, original_ask);
@@ -32413,109 +32638,30 @@ var init_solo_dispatch = __esm({
32413
32638
  }
32414
32639
  });
32415
32640
 
32416
- // src/scripts/ai_council/modes.ts
32417
- function _sortedValidModes() {
32418
- return Array.from(VALID_MODES).sort();
32419
- }
32420
- function _normalise(value) {
32421
- if (value === null || value === void 0) {
32422
- return null;
32423
- }
32424
- if (typeof value !== "string") {
32425
- return null;
32426
- }
32427
- const s = value.trim().toLowerCase();
32428
- return s || null;
32429
- }
32430
- function _validate2(mode, source) {
32431
- if (mode === null) {
32432
- return null;
32433
- }
32434
- if (!VALID_MODES.has(mode)) {
32435
- throw new InvalidModeError(
32436
- `${source} requested mode=${_pyRepr9(mode)}; expected one of: ${_pyReprList2(_sortedValidModes())}`
32641
+ // src/scripts/ai_council/quorum.ts
32642
+ function resolveQuorumThreshold(total, setting = "majority") {
32643
+ if (!Number.isInteger(total) || total < 0) {
32644
+ throw new RangeError(
32645
+ `resolveQuorumThreshold: total must be a non-negative integer (got ${total}).`
32437
32646
  );
32438
32647
  }
32439
- return mode;
32440
- }
32441
- function _pyRepr9(s) {
32442
- return `'${s}'`;
32443
- }
32444
- function _pyReprList2(items) {
32445
- return `[${items.map((i) => _pyRepr9(i)).join(", ")}]`;
32446
- }
32447
- function resolve_global_mode(aiBlock) {
32448
- if (aiBlock === null || aiBlock === void 0) {
32449
- return null;
32450
- }
32451
- const flat = _normalise(_settingsGet(aiBlock, "mode"));
32452
- if (flat !== null) {
32453
- return flat;
32454
- }
32455
- const defaults = _settingsGet(aiBlock, "defaults");
32456
- if (defaults === null || defaults === void 0) {
32457
- return null;
32458
- }
32459
- if (!(defaults instanceof Map) && typeof defaults !== "object") {
32460
- return null;
32648
+ if (total === 0) {
32649
+ return 0;
32461
32650
  }
32462
- if (Array.isArray(defaults)) {
32463
- return null;
32651
+ if (setting === "majority") {
32652
+ return Math.ceil(total / 2);
32464
32653
  }
32465
- return _normalise(
32466
- _settingsGet(defaults, "mode")
32467
- );
32654
+ return Math.min(Math.max(setting, 1), total);
32468
32655
  }
32469
- function _settingsGet(settings, key) {
32470
- if (settings === null || settings === void 0) {
32471
- return void 0;
32472
- }
32473
- if (settings instanceof Map) {
32474
- return settings.get(key);
32475
- }
32476
- return settings[key];
32656
+ function evaluateQuorum(total, present, setting = "majority") {
32657
+ const threshold = resolveQuorumThreshold(total, setting);
32658
+ const clampedPresent = Math.min(Math.max(present, 0), total);
32659
+ const status3 = clampedPresent >= threshold ? "concluded" : "inconclusive";
32660
+ return { status: status3, threshold, total, present: clampedPresent };
32477
32661
  }
32478
- function resolve_mode(memberName, opts = {}) {
32479
- const invocationMode = opts.invocationMode ?? null;
32480
- const memberSettings = opts.memberSettings ?? null;
32481
- const globalMode = opts.globalMode ?? null;
32482
- const inv = _validate2(
32483
- _normalise(invocationMode),
32484
- `/council mode= for ${_pyRepr9(memberName)}`
32485
- );
32486
- if (inv !== null) {
32487
- return inv;
32488
- }
32489
- let memberModeRaw = null;
32490
- if (memberSettings !== null) {
32491
- const v = _settingsGet(memberSettings, "mode");
32492
- memberModeRaw = v === void 0 ? null : v;
32493
- }
32494
- const member = _validate2(
32495
- _normalise(memberModeRaw),
32496
- `ai_council.members.${memberName}.mode`
32497
- );
32498
- if (member !== null) {
32499
- return member;
32500
- }
32501
- const glob2 = _validate2(_normalise(globalMode), "ai_council.mode");
32502
- if (glob2 !== null) {
32503
- return glob2;
32504
- }
32505
- return DEFAULT_MODE;
32506
- }
32507
- var VALID_MODES, DEFAULT_MODE, InvalidModeError;
32508
- var init_modes = __esm({
32509
- "src/scripts/ai_council/modes.ts"() {
32662
+ var init_quorum = __esm({
32663
+ "src/scripts/ai_council/quorum.ts"() {
32510
32664
  "use strict";
32511
- VALID_MODES = /* @__PURE__ */ new Set(["api", "manual", "cli", "auto"]);
32512
- DEFAULT_MODE = "manual";
32513
- InvalidModeError = class extends Error {
32514
- constructor(message) {
32515
- super(message);
32516
- this.name = "InvalidModeError";
32517
- }
32518
- };
32519
32665
  }
32520
32666
  });
32521
32667
 
@@ -34977,6 +35123,37 @@ One sentence, and the single strongest reason.`;
34977
35123
  }
34978
35124
  });
34979
35125
 
35126
+ // src/scripts/ai_council/handoff.ts
35127
+ function isEmptyHandoff(h) {
35128
+ return h.decision === null && h.rejected_alternatives === null && h.constraints === null;
35129
+ }
35130
+ function buildHandoffFromStanceTally(tally) {
35131
+ if (tally === null || tally.consensus === null) {
35132
+ return EMPTY_HANDOFF;
35133
+ }
35134
+ const winner = tally.consensus;
35135
+ const rejected = tally.options.filter((o) => o !== winner).map((o) => ({
35136
+ option: o.label,
35137
+ reason: `backed by ${o.backers.length} member(s), weight ${o.weight.toFixed(2)} of ${tally.threshold.toFixed(2)} needed to conclude`
35138
+ }));
35139
+ return {
35140
+ decision: winner.label,
35141
+ rejected_alternatives: rejected.length > 0 ? rejected : null,
35142
+ constraints: null
35143
+ };
35144
+ }
35145
+ var EMPTY_HANDOFF;
35146
+ var init_handoff = __esm({
35147
+ "src/scripts/ai_council/handoff.ts"() {
35148
+ "use strict";
35149
+ EMPTY_HANDOFF = {
35150
+ decision: null,
35151
+ rejected_alternatives: null,
35152
+ constraints: null
35153
+ };
35154
+ }
35155
+ });
35156
+
34980
35157
  // src/scripts/ai_council/orchestrator.ts
34981
35158
  var orchestrator_exports = {};
34982
35159
  __export(orchestrator_exports, {
@@ -35956,11 +36133,58 @@ ${body}`;
35956
36133
  blocks.push(`## Convergence / Divergence
35957
36134
 
35958
36135
  ${body}`);
36136
+ if (opts.handoff && !isEmptyHandoff(opts.handoff)) {
36137
+ blocks.push(_render_handoff(opts.handoff));
36138
+ }
35959
36139
  if (blind !== null) {
35960
36140
  blocks.push(render_deanonymization_block("### De-anonymization map", blind.label_to_source));
35961
36141
  }
36142
+ if (opts.quorum) {
36143
+ blocks.push(_render_quorum_line(opts.quorum));
36144
+ }
36145
+ const absent = opts.absent_members ?? [];
36146
+ if (absent.length > 0) {
36147
+ blocks.push(_render_absent_members(absent));
36148
+ }
35962
36149
  return blocks.join("\n\n---\n\n");
35963
36150
  }
36151
+ function _render_quorum_line(q) {
36152
+ const verdict = q.status === "concluded" ? "concluded" : "INCONCLUSIVE \u2014 release gate holds";
36153
+ return `**Quorum:** ${q.present}/${q.total} present, needed ${q.threshold} \u2014 ${verdict}.`;
36154
+ }
36155
+ function _render_absent_members(absent) {
36156
+ const lines = ["### Absent Members", ""];
36157
+ for (const a of absent) {
36158
+ const tag = a.reason !== null ? ` (${a.reason})` : "";
36159
+ lines.push(`- **${a.member}**${tag} \u2014 ${a.detail}`);
36160
+ }
36161
+ return lines.join("\n");
36162
+ }
36163
+ function _render_handoff(h) {
36164
+ const lines = ["### Handoff", ""];
36165
+ lines.push(`**Decision:** ${h.decision ?? "none recorded \u2014 no structured verdict this pass."}`);
36166
+ lines.push("");
36167
+ if (h.rejected_alternatives !== null && h.rejected_alternatives.length > 0) {
36168
+ lines.push("**Rejected alternatives:**");
36169
+ lines.push("");
36170
+ for (const alt of h.rejected_alternatives) {
36171
+ lines.push(`- **${alt.option}** \u2014 ${alt.reason}`);
36172
+ }
36173
+ } else {
36174
+ lines.push("**Rejected alternatives:** none recorded.");
36175
+ }
36176
+ lines.push("");
36177
+ if (h.constraints !== null && h.constraints.length > 0) {
36178
+ lines.push("**Constraints:**");
36179
+ lines.push("");
36180
+ for (const c of h.constraints) {
36181
+ lines.push(`- ${c}`);
36182
+ }
36183
+ } else {
36184
+ lines.push("**Constraints:** none recorded.");
36185
+ }
36186
+ return lines.join("\n");
36187
+ }
35964
36188
  function _render_peer_review(peer_review) {
35965
36189
  const lines = ["## Peer-Review (Karpathy)"];
35966
36190
  let label_idx = 0;
@@ -36085,6 +36309,7 @@ var init_orchestrator = __esm({
36085
36309
  init_debate_gates();
36086
36310
  init_stance_tally();
36087
36311
  init_blind_review();
36312
+ init_handoff();
36088
36313
  CostBudget = class {
36089
36314
  max_input_tokens;
36090
36315
  max_output_tokens;
@@ -37669,6 +37894,7 @@ __export(council_cli_exports, {
37669
37894
  CouncilDisabledError: () => CouncilDisabledError,
37670
37895
  _parse_model_overrides: () => _parse_model_overrides,
37671
37896
  _parse_siblings_overrides: () => _parse_siblings_overrides,
37897
+ _postRunQuorum: () => _postRunQuorum,
37672
37898
  _synthesize_ai_council_block: () => _synthesize_ai_council_block,
37673
37899
  build_members: () => build_members,
37674
37900
  build_question: () => build_question,
@@ -37679,6 +37905,7 @@ __export(council_cli_exports, {
37679
37905
  cmd_replay: () => cmd_replay,
37680
37906
  cmd_run: () => cmd_run,
37681
37907
  cmd_shadow_report: () => cmd_shadow_report,
37908
+ cmd_status: () => cmd_status,
37682
37909
  format_estimate_table: () => format_estimate_table,
37683
37910
  load_settings: () => load_settings,
37684
37911
  main: () => main17
@@ -37969,6 +38196,13 @@ function _synthesize_ai_council_block(cfg) {
37969
38196
  max_calls_per_day: _mapToObject(cfg.cli_call_budget.max_calls_per_day),
37970
38197
  warn_at: cfg.cli_call_budget.warn_at
37971
38198
  },
38199
+ // Phase 3.3 (road-to-always-on-orchestration): was validated by
38200
+ // `_build_config`/`_build_quorum` but never forwarded into the
38201
+ // synthesized block, so `build_members` always saw `undefined` and
38202
+ // silently fell back to `'majority'` regardless of the user's
38203
+ // configured `quorum: <k>`. Additive key — callers that never read
38204
+ // it observe no change.
38205
+ quorum: cfg.quorum,
37972
38206
  necessity_classifier: {
37973
38207
  enabled: cfg.necessity_classifier.enabled,
37974
38208
  mode: cfg.necessity_classifier.mode,
@@ -38007,15 +38241,63 @@ function _mapToObject(m) {
38007
38241
  }
38008
38242
  return out;
38009
38243
  }
38244
+ function _member_api_key_present(cfg) {
38245
+ const ref = cfg["api_key_ref"];
38246
+ if (typeof ref !== "string" || ref.trim() === "") {
38247
+ return void 0;
38248
+ }
38249
+ try {
38250
+ resolve_api_key(ref);
38251
+ return true;
38252
+ } catch {
38253
+ return false;
38254
+ }
38255
+ }
38256
+ function _quorum_setting_from(ai) {
38257
+ const raw = ai["quorum"];
38258
+ if (raw === "majority") {
38259
+ return "majority";
38260
+ }
38261
+ if (typeof raw === "number" && Number.isInteger(raw) && raw >= 1) {
38262
+ return raw;
38263
+ }
38264
+ return "majority";
38265
+ }
38266
+ function _postRunQuorum(members, responses, ai_cfg) {
38267
+ const absent = [];
38268
+ let present = 0;
38269
+ for (let i = 0; i < members.length; i++) {
38270
+ const m = members[i];
38271
+ const r = responses[i];
38272
+ if (r !== void 0 && !r.error) {
38273
+ present += 1;
38274
+ continue;
38275
+ }
38276
+ const raw = r?.error ?? "no response";
38277
+ const failure = classifyCliFailure(raw);
38278
+ absent.push({
38279
+ member: m.name,
38280
+ reason: absentReasonFromCliFailure(failure) ?? "unavailable",
38281
+ detail: raw
38282
+ });
38283
+ }
38284
+ return { quorum: evaluateQuorum(members.length, present, _quorum_setting_from(ai_cfg)), absent };
38285
+ }
38286
+ function _format_quorum_line(q) {
38287
+ const verdict = q.status === "concluded" ? "concluded" : "INCONCLUSIVE \u2014 release gate holds";
38288
+ return `council:quorum \xB7 ${q.present}/${q.total} present, needed ${q.threshold} \u2014 ${verdict}.`;
38289
+ }
38010
38290
  function build_members(settings, opts = {}) {
38011
38291
  const invocation_mode = opts.invocation_mode ?? null;
38012
38292
  const model_overrides = opts.model_overrides ?? null;
38013
38293
  const siblings_overrides = opts.siblings_overrides ?? null;
38014
38294
  const skipped = opts.skipped ?? null;
38295
+ const quorum_out = opts.quorum_out ?? null;
38296
+ const report2 = opts.environment_report ?? detectEnvironment();
38015
38297
  const ai = _isDict3(settings) ? settings["ai_council"] || {} : {};
38016
38298
  if (!_pyBool2(ai["enabled"])) {
38017
38299
  throw new CouncilDisabledError(
38018
- "ai_council.enabled is false in .agent-settings.yml \u2014 flip it on before invoking council:* commands."
38300
+ `enabled is false in the council config (${COUNCIL_CONFIG_USER_GLOBAL_REL} under the user-global agent-config root) \u2014 flip it on before invoking council:* commands. This config is NEVER project-local (ADR-104), so do not look for it, or create it, in the project tree. \`agent-config council:status\` prints the resolved path.`
38019
38301
  );
38020
38302
  }
38021
38303
  const members_cfg = ai["members"] || {};
@@ -38045,25 +38327,36 @@ function build_members(settings, opts = {}) {
38045
38327
  );
38046
38328
  }
38047
38329
  const members = [];
38330
+ let total_enabled = 0;
38331
+ let absent_count = 0;
38048
38332
  for (const name of Object.keys(members_cfg)) {
38049
38333
  const cfg = members_cfg[name] || {};
38050
38334
  if (!_pyBool2(cfg["enabled"])) {
38051
38335
  if (name in siblings) {
38052
38336
  throw new CouncilDisabledError(
38053
- `--siblings targets member ${_pyReprStr5(name)} but it is not enabled in .agent-settings.yml (ai_council.members.${name}.enabled).`
38337
+ `--siblings targets member ${_pyReprStr5(name)} but it is not enabled in the council config (members.${name}.enabled in ${COUNCIL_CONFIG_USER_GLOBAL_REL} under the user-global root).`
38054
38338
  );
38055
38339
  }
38056
38340
  continue;
38057
38341
  }
38058
- const mode = resolve_mode(name, {
38342
+ total_enabled += 1;
38343
+ const api_key_present = _member_api_key_present(cfg);
38344
+ const resolved = resolveMemberTransport({
38345
+ provider: name,
38346
+ report: report2,
38059
38347
  invocationMode: invocation_mode,
38060
38348
  memberSettings: cfg,
38061
- globalMode: global_mode ?? null
38349
+ globalMode: global_mode ?? null,
38350
+ binaryOverride: cfg["binary"] ?? null,
38351
+ // `exactOptionalPropertyTypes` rejects an explicit `undefined` —
38352
+ // see `resolveMemberTransport`'s own forwarding call for the
38353
+ // same pattern.
38354
+ ...api_key_present !== void 0 ? { apiKeyPresent: api_key_present } : {}
38062
38355
  });
38063
38356
  if (name in siblings) {
38064
- if (mode !== "api") {
38357
+ if (resolved.transport !== "api") {
38065
38358
  throw new CouncilDisabledError(
38066
- `--siblings requires mode=api for member ${_pyReprStr5(name)} (got ${_pyReprStr5(mode)}).`
38359
+ `--siblings requires mode=api for member ${_pyReprStr5(name)} (configured mode=${_pyReprStr5(resolved.configuredMode)}, resolved transport=${_pyReprStr5(resolved.transport ?? "none")}).`
38067
38360
  );
38068
38361
  }
38069
38362
  const api_key_ref = cfg["api_key_ref"] ?? null;
@@ -38080,19 +38373,49 @@ function build_members(settings, opts = {}) {
38080
38373
  }
38081
38374
  continue;
38082
38375
  }
38376
+ if (resolved.transport === null) {
38377
+ const detail = resolved.reason ?? `member ${name} has no available transport`;
38378
+ const entry = {
38379
+ member: name,
38380
+ reason: resolved.absentReason ?? "unavailable",
38381
+ detail
38382
+ };
38383
+ absent_count += 1;
38384
+ if (skipped !== null) {
38385
+ skipped.push(entry);
38386
+ }
38387
+ _stderr2(`[council] SKIP ${name}: ${detail}
38388
+ `);
38389
+ continue;
38390
+ }
38083
38391
  const model = overrides[name] || cfg["model"] || null;
38084
- if (mode === "api" && _API_PROVIDERS.has(name)) {
38085
- members.push(
38086
- _construct_api_member(name, model, {
38087
- api_key_ref: cfg["api_key_ref"] ?? null,
38088
- // Council opts in explicitly (client-default OFF); on unless
38089
- // the operator sets `prompt_cache: false`.
38090
- enable_prompt_cache: cfg["prompt_cache"] !== false,
38091
- // road-to-cache-economy Phase 4 — see the siblings branch above.
38092
- prompt_cache_ttl: cfg["prompt_cache_ttl"] ?? void 0
38093
- })
38094
- );
38095
- } else if (mode === "cli" && _CLI_PROVIDERS.has(name)) {
38392
+ if (resolved.transport === "api" && _API_PROVIDERS.has(name)) {
38393
+ try {
38394
+ members.push(
38395
+ _construct_api_member(name, model, {
38396
+ api_key_ref: cfg["api_key_ref"] ?? null,
38397
+ // Council opts in explicitly (client-default OFF); on unless
38398
+ // the operator sets `prompt_cache: false`.
38399
+ enable_prompt_cache: cfg["prompt_cache"] !== false,
38400
+ // road-to-cache-economy Phase 4 — see the siblings branch above.
38401
+ prompt_cache_ttl: cfg["prompt_cache_ttl"] ?? void 0
38402
+ })
38403
+ );
38404
+ } catch (exc) {
38405
+ if (!(exc instanceof CouncilDisabledError)) {
38406
+ throw exc;
38407
+ }
38408
+ const detail = exc.message;
38409
+ const entry = { member: name, reason: "no_auth", detail };
38410
+ absent_count += 1;
38411
+ if (skipped !== null) {
38412
+ skipped.push(entry);
38413
+ }
38414
+ _stderr2(`[council] SKIP ${name}: ${detail}
38415
+ `);
38416
+ continue;
38417
+ }
38418
+ } else if (resolved.transport === "cli" && _CLI_PROVIDERS.has(name)) {
38096
38419
  try {
38097
38420
  members.push(
38098
38421
  _construct_cli_member(name, model, {
@@ -38112,6 +38435,7 @@ function build_members(settings, opts = {}) {
38112
38435
  reason: "binary_missing",
38113
38436
  detail
38114
38437
  };
38438
+ absent_count += 1;
38115
38439
  if (skipped !== null) {
38116
38440
  skipped.push(entry);
38117
38441
  }
@@ -38119,22 +38443,22 @@ function build_members(settings, opts = {}) {
38119
38443
  `);
38120
38444
  continue;
38121
38445
  }
38122
- } else if (mode === "cli") {
38446
+ } else if (resolved.transport === "cli") {
38123
38447
  throw new CouncilDisabledError(
38124
38448
  `member ${_pyReprStr5(name)} resolves to mode=cli but no CLI client is wired (known: ${_pyReprStrList(_pySortedStr(_CLI_PROVIDERS))}).`
38125
38449
  );
38126
- } else if (mode === "manual") {
38450
+ } else if (resolved.transport === "manual") {
38127
38451
  members.push(new ManualClient({ name, model: model || "manual" }));
38128
- } else if (mode === "playwright") {
38129
- throw new CouncilDisabledError(
38130
- `member ${_pyReprStr5(name)} resolves to mode=playwright (Phase 2c, not wired).`
38131
- );
38132
38452
  } else {
38133
38453
  throw new CouncilDisabledError(
38134
- `member ${_pyReprStr5(name)} has no transport \u2014 mode=${mode}, name not in ${_pyReprStrList(_pySortedStr(_API_PROVIDERS))}.`
38454
+ `member ${_pyReprStr5(name)} has no transport \u2014 resolved=${_pyReprStr5(resolved.transport)}, configured mode=${_pyReprStr5(resolved.configuredMode)}, name not in ${_pyReprStrList(_pySortedStr(_API_PROVIDERS))}.`
38135
38455
  );
38136
38456
  }
38137
38457
  }
38458
+ if (quorum_out !== null) {
38459
+ const present = total_enabled - absent_count;
38460
+ quorum_out.result = evaluateQuorum(total_enabled, present, _quorum_setting_from(ai));
38461
+ }
38138
38462
  if (members.length === 0) {
38139
38463
  if (skipped && skipped.length > 0) {
38140
38464
  const names = skipped.map((s) => String(s["member"])).join(", ");
@@ -38143,7 +38467,7 @@ function build_members(settings, opts = {}) {
38143
38467
  );
38144
38468
  }
38145
38469
  throw new CouncilDisabledError(
38146
- "no council member has `enabled: true` \u2014 enable at least one in .agent-settings.yml under ai_council.members.*."
38470
+ `no council member has \`enabled: true\` \u2014 enable at least one under members.* in ${COUNCIL_CONFIG_USER_GLOBAL_REL} (user-global root; never the project tree, ADR-104). \`agent-config council:status\` prints the resolved path.`
38147
38471
  );
38148
38472
  }
38149
38473
  return members;
@@ -38571,6 +38895,59 @@ function _objToMap(o) {
38571
38895
  }
38572
38896
  return m;
38573
38897
  }
38898
+ function _deserialise_handoff(data) {
38899
+ if (!_isDict3(data)) {
38900
+ return null;
38901
+ }
38902
+ const d = data;
38903
+ const decision = typeof d["decision"] === "string" ? d["decision"] : null;
38904
+ const rawAlts = d["rejected_alternatives"];
38905
+ const alts = Array.isArray(rawAlts) ? rawAlts.filter(
38906
+ (a) => _isDict3(a) && typeof a["option"] === "string" && typeof a["reason"] === "string"
38907
+ ).map((a) => ({ option: a["option"], reason: a["reason"] })) : [];
38908
+ const rawConstraints = d["constraints"];
38909
+ const constraints = Array.isArray(rawConstraints) ? rawConstraints.filter((c) => typeof c === "string") : [];
38910
+ return {
38911
+ decision,
38912
+ rejected_alternatives: alts.length > 0 ? alts : null,
38913
+ constraints: constraints.length > 0 ? constraints : null
38914
+ };
38915
+ }
38916
+ function _deserialise_absent_members(data) {
38917
+ if (!Array.isArray(data)) {
38918
+ return null;
38919
+ }
38920
+ const out = [];
38921
+ for (const entry of data) {
38922
+ if (!_isDict3(entry)) {
38923
+ continue;
38924
+ }
38925
+ const d = entry;
38926
+ const member = d["member"];
38927
+ const detail = d["detail"];
38928
+ if (typeof member !== "string" || typeof detail !== "string") {
38929
+ continue;
38930
+ }
38931
+ const raw = d["reason"];
38932
+ const reason = typeof raw === "string" && _VALID_ABSENT_REASONS.has(raw) ? raw : null;
38933
+ out.push({ member, reason, detail });
38934
+ }
38935
+ return out.length > 0 ? out : null;
38936
+ }
38937
+ function _deserialise_quorum(data) {
38938
+ if (!_isDict3(data)) {
38939
+ return null;
38940
+ }
38941
+ const d = data;
38942
+ const status3 = d["status"];
38943
+ const threshold = d["threshold"];
38944
+ const total = d["total"];
38945
+ const present = d["present"];
38946
+ if (status3 !== "concluded" && status3 !== "inconclusive" || typeof threshold !== "number" || typeof total !== "number" || typeof present !== "number") {
38947
+ return null;
38948
+ }
38949
+ return { status: status3, threshold, total, present };
38950
+ }
38574
38951
  function _resolve_rounds(args, ai_cfg) {
38575
38952
  if (_getattr3(args, "rounds", null) !== null) {
38576
38953
  return _pyInt6(args.rounds);
@@ -38608,12 +38985,14 @@ function cmd_estimate(args, opts = {}) {
38608
38985
  const advisor_plans = _build_advisor_plans(ai_cfg, REPO_ROOT3);
38609
38986
  const explicit_overrides = _parse_model_overrides(_getattr3(args, "model", null));
38610
38987
  const skipped = [];
38988
+ const quorum_out = { result: null };
38611
38989
  if (members === null) {
38612
38990
  members = build_members(settings, {
38613
38991
  invocation_mode: args.mode_override,
38614
38992
  model_overrides: _advisor_model_overrides(advisor_plans, explicit_overrides),
38615
38993
  siblings_overrides: _parse_siblings_overrides(_getattr3(args, "siblings", null)),
38616
- skipped
38994
+ skipped,
38995
+ quorum_out
38617
38996
  });
38618
38997
  }
38619
38998
  if (table === null) {
@@ -38649,6 +39028,9 @@ function cmd_estimate(args, opts = {}) {
38649
39028
  if (skipped.length > 0) {
38650
39029
  _stdout2(format_install_hints(skipped) + "\n");
38651
39030
  }
39031
+ if (quorum_out.result !== null) {
39032
+ _stdout2(_format_quorum_line(quorum_out.result) + "\n");
39033
+ }
38652
39034
  _stdout2(
38653
39035
  format_estimate_table(billable, estimates, {
38654
39036
  consensus_delta_usd: extra_usd,
@@ -39027,6 +39409,75 @@ function _emit_shadow_slo_banner() {
39027
39409
  return;
39028
39410
  }
39029
39411
  }
39412
+ function cmd_status(args, opts = {}) {
39413
+ const env = opts.env ?? process.env;
39414
+ const override = env[COUNCIL_CONFIG_ENV];
39415
+ const path_ = resolve_config_path(REPO_ROOT3, { env });
39416
+ const exists3 = fs56.existsSync(String(path_));
39417
+ const provenance = override ? `${COUNCIL_CONFIG_ENV} override` : "user-global";
39418
+ let cfg = null;
39419
+ let parse_error = null;
39420
+ if (exists3) {
39421
+ try {
39422
+ cfg = load_council_config(path_);
39423
+ } catch (exc) {
39424
+ parse_error = exc instanceof Error ? exc.message : String(exc);
39425
+ }
39426
+ }
39427
+ const enabledMembers = cfg === null ? [] : [...cfg.members.entries()].filter(([, m]) => m.enabled);
39428
+ const configured = cfg !== null && cfg.enabled && enabledMembers.length > 0;
39429
+ if (_getattr3(args, "json", false)) {
39430
+ _stdout2(
39431
+ `${JSON.stringify({
39432
+ configured,
39433
+ path: String(path_),
39434
+ exists: exists3,
39435
+ provenance,
39436
+ enabled: cfg?.enabled ?? null,
39437
+ members_total: cfg === null ? null : cfg.members.size,
39438
+ members_enabled: cfg === null ? null : enabledMembers.length,
39439
+ member_names: enabledMembers.map(([n]) => n),
39440
+ parse_error,
39441
+ project_tree_consulted: false
39442
+ })}
39443
+ `
39444
+ );
39445
+ return 0;
39446
+ }
39447
+ _stdout2(`council:status \xB7 ${configured ? "CONFIGURED" : "NOT CONFIGURED"}
39448
+ `);
39449
+ _stdout2(` config path ${String(path_)}
39450
+ `);
39451
+ _stdout2(` resolved by ${provenance}
39452
+ `);
39453
+ _stdout2(` file exists ${exists3 ? "yes" : "no"}
39454
+ `);
39455
+ if (parse_error !== null) {
39456
+ _stdout2(` parse error ${parse_error}
39457
+ `);
39458
+ }
39459
+ if (cfg !== null) {
39460
+ _stdout2(` enabled ${cfg.enabled ? "yes" : "no"}
39461
+ `);
39462
+ _stdout2(` members ${enabledMembers.length} enabled of ${cfg.members.size}
39463
+ `);
39464
+ if (enabledMembers.length > 0) {
39465
+ _stdout2(` ${enabledMembers.map(([n]) => n).join(", ")}
39466
+ `);
39467
+ }
39468
+ }
39469
+ _stdout2("\n");
39470
+ _stdout2(" The project tree is NEVER consulted (ADR-104). No project file \u2014\n");
39471
+ _stdout2(" `.agent-settings.yml` included \u2014 indicates council availability in\n");
39472
+ _stdout2(" either direction. Do not infer it from one; run this instead.\n");
39473
+ if (!configured) {
39474
+ _stdout2(`
39475
+ To configure: write ${COUNCIL_CONFIG_USER_GLOBAL_REL} under the user-global
39476
+ `);
39477
+ _stdout2(" agent-config root, with `enabled: true` and at least one enabled member.\n");
39478
+ }
39479
+ return 0;
39480
+ }
39030
39481
  function _apply_solo_dispatch(members) {
39031
39482
  let cfg;
39032
39483
  try {
@@ -39087,12 +39538,14 @@ function cmd_run(args, opts = {}) {
39087
39538
  const advisor_plans = _build_advisor_plans(ai_cfg, REPO_ROOT3);
39088
39539
  const explicit_overrides = _parse_model_overrides(_getattr3(args, "model", null));
39089
39540
  const skipped = [];
39541
+ const quorum_out = { result: null };
39090
39542
  if (members === null) {
39091
39543
  members = build_members(settings, {
39092
39544
  invocation_mode: args.mode_override,
39093
39545
  model_overrides: _advisor_model_overrides(advisor_plans, explicit_overrides),
39094
39546
  siblings_overrides: _parse_siblings_overrides(_getattr3(args, "siblings", null)),
39095
- skipped
39547
+ skipped,
39548
+ quorum_out
39096
39549
  });
39097
39550
  }
39098
39551
  if (_getattr3(args, "single", false)) {
@@ -39152,6 +39605,9 @@ function cmd_run(args, opts = {}) {
39152
39605
  if (skipped.length > 0) {
39153
39606
  _stdout2(format_install_hints(skipped) + "\n");
39154
39607
  }
39608
+ if (quorum_out.result !== null) {
39609
+ _stdout2(_format_quorum_line(quorum_out.result) + "\n");
39610
+ }
39155
39611
  _stdout2(
39156
39612
  format_estimate_table(billable, estimates, {
39157
39613
  consensus_delta_usd: extra_usd,
@@ -39226,6 +39682,14 @@ function cmd_run(args, opts = {}) {
39226
39682
  stance_repairs.push(r);
39227
39683
  }
39228
39684
  });
39685
+ const post_run = _postRunQuorum(members, responses, ai_cfg);
39686
+ quorum_out.result = post_run.quorum;
39687
+ skipped.push(...post_run.absent);
39688
+ const handoff = buildHandoffFromStanceTally(
39689
+ stance_tally_on ? tally_stances(
39690
+ responses.filter((r) => !r.error).map((r) => ({ member: `${r.provider}:${r.model}`, text: r.text }))
39691
+ ) : null
39692
+ );
39229
39693
  const persona_labels = build_persona_labels(advisor_plans, billable);
39230
39694
  const peer_review = _maybe_run_peer_review(
39231
39695
  ai_cfg,
@@ -39300,6 +39764,13 @@ function cmd_run(args, opts = {}) {
39300
39764
  if (blind_review_map !== null) {
39301
39765
  payload["blind_review_map"] = _mapToObject(blind_review_map);
39302
39766
  }
39767
+ if (quorum_out.result !== null) {
39768
+ payload["quorum"] = quorum_out.result;
39769
+ }
39770
+ if (skipped.length > 0) {
39771
+ payload["absent_members"] = skipped;
39772
+ }
39773
+ payload["handoff"] = handoff;
39303
39774
  const out_path = _validate_council_output_path(args.output, {
39304
39775
  kind: "responses",
39305
39776
  subcommand: "run"
@@ -39653,7 +40124,10 @@ function cmd_render(args) {
39653
40124
  stance_tally: payload["stance_tally"] === true,
39654
40125
  chairman_fields: payload["chairman_fields"] === true,
39655
40126
  blind: _isDict3(blind_map_raw) ? { label_to_source: _objToMap(blind_map_raw) } : null,
39656
- chairman: _isDict3(payload["chairman"]) ? payload["chairman"] : null
40127
+ chairman: _isDict3(payload["chairman"]) ? payload["chairman"] : null,
40128
+ handoff: _deserialise_handoff(payload["handoff"]),
40129
+ absent_members: _deserialise_absent_members(payload["absent_members"]),
40130
+ quorum: _deserialise_quorum(payload["quorum"])
39657
40131
  });
39658
40132
  if (_getattr3(args, "output", null)) {
39659
40133
  const out_path = _validate_council_output_path(args.output, {
@@ -39862,7 +40336,8 @@ function _defaultArgs() {
39862
40336
  low_impact_stats: false,
39863
40337
  reset: null,
39864
40338
  log: null,
39865
- window_days: 7
40339
+ window_days: 7,
40340
+ json: false
39866
40341
  };
39867
40342
  }
39868
40343
  function _usageFor(cmd) {
@@ -39979,6 +40454,12 @@ function _specsFor(cmd) {
39979
40454
  ],
39980
40455
  requiredOpts: []
39981
40456
  };
40457
+ case "status":
40458
+ return {
40459
+ positionals: [],
40460
+ opts: [{ flag: "--json", takesValue: false, apply: (o) => o.json = true }],
40461
+ requiredOpts: []
40462
+ };
39982
40463
  default:
39983
40464
  return { positionals: [], opts: [], requiredOpts: [] };
39984
40465
  }
@@ -40152,6 +40633,9 @@ function main17(argv = null) {
40152
40633
  if (args.cmd === "shadow-report") {
40153
40634
  return cmd_shadow_report(args);
40154
40635
  }
40636
+ if (args.cmd === "status") {
40637
+ return cmd_status(args);
40638
+ }
40155
40639
  } catch (exc) {
40156
40640
  if (exc instanceof CouncilDisabledError) {
40157
40641
  _stderr2(`\u274C council:${args.cmd}: ${exc.message}
@@ -40183,12 +40667,13 @@ function _isCliEntry17() {
40183
40667
  return false;
40184
40668
  }
40185
40669
  }
40186
- var _ArgExit2, ArgumentTypeError, _PROG9, SCHEMA_VERSION8, _API_PROVIDERS, _CLI_PROVIDERS, _HERE15, REPO_ROOT3, SETTINGS_FILE2, AI_COUNCIL_FILE, COUNCIL_CANONICAL_DIRS, CouncilDisabledError, _CLI_FACTORY, ValueError4, FileNotFoundError3, _SUBCOMMANDS, _TOP_USAGE2;
40670
+ var _ArgExit2, ArgumentTypeError, _PROG9, SCHEMA_VERSION8, _API_PROVIDERS, _CLI_PROVIDERS, _HERE15, REPO_ROOT3, SETTINGS_FILE2, AI_COUNCIL_FILE, COUNCIL_CANONICAL_DIRS, CouncilDisabledError, _CLI_FACTORY, ValueError4, _VALID_ABSENT_REASONS, FileNotFoundError3, _SUBCOMMANDS, _TOP_USAGE2;
40187
40671
  var init_council_cli = __esm({
40188
40672
  "src/scripts/council_cli.ts"() {
40189
40673
  "use strict";
40190
40674
  init_agent_settings();
40191
40675
  init_agent_settings();
40676
+ init_environment_detector();
40192
40677
  init_bundler();
40193
40678
  init_chairman();
40194
40679
  init_text_similarity();
@@ -40199,6 +40684,9 @@ var init_council_cli = __esm({
40199
40684
  init_config();
40200
40685
  init_solo_dispatch();
40201
40686
  init_modes();
40687
+ init_transport_resolver();
40688
+ init_transport_resolver();
40689
+ init_quorum();
40202
40690
  init_events_log();
40203
40691
  init_necessity();
40204
40692
  init_orchestrator();
@@ -40209,6 +40697,8 @@ var init_council_cli = __esm({
40209
40697
  init_shadow_dispatch();
40210
40698
  init_low_impact();
40211
40699
  init_blind_review();
40700
+ init_stance_tally();
40701
+ init_handoff();
40212
40702
  _ArgExit2 = class extends Error {
40213
40703
  };
40214
40704
  ArgumentTypeError = class extends Error {
@@ -40249,11 +40739,17 @@ var init_council_cli = __esm({
40249
40739
  };
40250
40740
  ValueError4 = class extends Error {
40251
40741
  };
40742
+ _VALID_ABSENT_REASONS = /* @__PURE__ */ new Set([
40743
+ "no_binary",
40744
+ "no_auth",
40745
+ "timeout",
40746
+ "quota"
40747
+ ]);
40252
40748
  FileNotFoundError3 = class extends Error {
40253
40749
  };
40254
- _SUBCOMMANDS = ["estimate", "run", "debate", "render", "replay", "quota", "shadow-report"];
40750
+ _SUBCOMMANDS = ["estimate", "run", "debate", "render", "replay", "quota", "shadow-report", "status"];
40255
40751
  _TOP_USAGE2 = `usage: ${_PROG9} [-h]
40256
- {estimate,run,debate,render,replay,quota,shadow-report}
40752
+ {estimate,run,debate,render,replay,quota,shadow-report,status}
40257
40753
  ...
40258
40754
  `;
40259
40755
  if (_isCliEntry17()) {