sneakoscope 6.4.0 → 6.7.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 (187) hide show
  1. package/README.md +26 -34
  2. package/config/codex-releases/{rust-v0.144.1.json → rust-v0.144.5.json} +5 -5
  3. package/crates/sks-core/Cargo.lock +1 -1
  4. package/crates/sks-core/Cargo.toml +1 -1
  5. package/dist/bin/install.js +1 -1
  6. package/dist/cli/command-manifest-lite.js +2 -3
  7. package/dist/cli/command-registry.js +6 -4
  8. package/dist/cli/help-fast.js +0 -1
  9. package/dist/cli/router.js +24 -3
  10. package/dist/commands/zellij.js +18 -29
  11. package/dist/config/skills-manifest.json +62 -62
  12. package/dist/core/agent-bridge/agent-manifest.js +22 -1
  13. package/dist/core/agents/agent-codex-cockpit.js +1 -81
  14. package/dist/core/agents/agent-effort-policy.js +13 -7
  15. package/dist/core/agents/agent-orchestrator.js +0 -6
  16. package/dist/core/agents/agent-output-validator.js +2 -1
  17. package/dist/core/agents/agent-patch-queue-store.js +0 -8
  18. package/dist/core/agents/agent-proof-evidence.js +0 -6
  19. package/dist/core/agents/agent-worker-pipeline.js +12 -6
  20. package/dist/core/agents/native-cli-worker-runtime.js +1 -16
  21. package/dist/core/agents/native-worker-backend-router.js +1 -1
  22. package/dist/core/bench.js +1 -1
  23. package/dist/core/codex/official-goal-mode.js +4 -2
  24. package/dist/core/codex-app/codex-app-fast-ui-repair.js +11 -17
  25. package/dist/core/codex-app/codex-app-ui-state-snapshot.js +34 -6
  26. package/dist/core/codex-app/menubar/constants.js +0 -1
  27. package/dist/core/codex-app.js +1 -1
  28. package/dist/core/codex-compat/codex-release-manifest.js +5 -5
  29. package/dist/core/codex-control/codex-0139-image-path-real-probe.js +1 -1
  30. package/dist/core/codex-control/codex-0139-web-search-probe.js +1 -1
  31. package/dist/core/codex-control/codex-control-proof.js +1 -0
  32. package/dist/core/codex-control/codex-fake-sdk-adapter.js +1 -1
  33. package/dist/core/codex-control/codex-lb-launch-recovery.js +7 -3
  34. package/dist/core/codex-control/codex-sdk-adapter.js +8 -7
  35. package/dist/core/codex-control/codex-sdk-config-policy.js +4 -24
  36. package/dist/core/codex-control/codex-sdk-env-policy.js +396 -11
  37. package/dist/core/codex-control/codex-task-runner.js +112 -57
  38. package/dist/core/codex-control/gpt-final-arbiter.js +1 -2
  39. package/dist/core/codex-control/python-codex-sdk-adapter.js +38 -15
  40. package/dist/core/codex-lb/codex-lb-tool-catalog.js +3 -3
  41. package/dist/core/codex-native/core-skill-manifest.js +4 -7
  42. package/dist/core/codex-runtime/resolve-codex-runtime.js +199 -0
  43. package/dist/core/commands/agent-bridge-command.js +46 -15
  44. package/dist/core/commands/basic-cli.js +1 -1
  45. package/dist/core/commands/command-utils.js +2 -2
  46. package/dist/core/commands/eval-command.js +19 -2
  47. package/dist/core/commands/goal-command.js +37 -86
  48. package/dist/core/commands/mad-sks-command.js +0 -2
  49. package/dist/core/commands/naruto-command.js +236 -176
  50. package/dist/core/doctor/current-project-guidance.js +1 -1
  51. package/dist/core/doctor/doctor-dirty-planner.js +1 -1
  52. package/dist/core/doctor/retired-managed-residue-missions.js +26 -11
  53. package/dist/core/doctor/retired-managed-residue-private.js +1 -1
  54. package/dist/core/doctor/retired-managed-residue-runtime.js +12 -2
  55. package/dist/core/doctor/retired-managed-residue-state.js +7 -7
  56. package/dist/core/evaluation.js +83 -21
  57. package/dist/core/feature-fixtures.js +4 -7
  58. package/dist/core/feature-registry.js +0 -1
  59. package/dist/core/fsx.js +169 -14
  60. package/dist/core/goal-workflow.js +71 -140
  61. package/dist/core/hooks-runtime/hook-io.js +2 -2
  62. package/dist/core/hooks-runtime.js +228 -50
  63. package/dist/core/init/skills.js +7 -6
  64. package/dist/core/init.js +52 -33
  65. package/dist/core/install/installed-package-smoke.js +1 -1
  66. package/dist/core/lean-engineering-policy.js +25 -23
  67. package/dist/core/locks/file-lock.js +74 -21
  68. package/dist/core/managed-assets/managed-assets-manifest.js +1 -1
  69. package/dist/core/mcp-config/health-check.js +7 -2
  70. package/dist/core/mission.js +99 -3
  71. package/dist/core/ops/upgrade-migration-fixtures.js +30 -2
  72. package/dist/core/pipeline-internals/runtime-core.js +67 -95
  73. package/dist/core/pipeline-internals/runtime-gates.js +25 -6
  74. package/dist/core/proof/fake-real-proof-policy.js +32 -9
  75. package/dist/core/proof/route-proof-gate.js +49 -1
  76. package/dist/core/provider/model-router.js +2 -0
  77. package/dist/core/questions.js +31 -5
  78. package/dist/core/recallpulse.js +2 -2
  79. package/dist/core/release/canonical-test-proof.js +135 -0
  80. package/dist/core/release/release-closure-contract.js +1 -0
  81. package/dist/core/release/release-closure-validation.js +25 -12
  82. package/dist/core/release/release-closure.js +34 -5
  83. package/dist/core/release/release-gate-contract.js +4 -3
  84. package/dist/core/release/release-gate-dag.js +4 -2
  85. package/dist/core/release/release-pack-content-scanner.js +7 -6
  86. package/dist/core/release/release-pack-receipt.js +33 -12
  87. package/dist/core/release/release-real-contract.js +41 -2
  88. package/dist/core/retention.js +95 -16
  89. package/dist/core/routes/constants.js +1 -1
  90. package/dist/core/routes/dollar-manifest-lite.js +1 -1
  91. package/dist/core/routes.js +18 -20
  92. package/dist/core/safety/command-contract/contracts.js +33 -0
  93. package/dist/core/safety/command-contract/types.js +1 -1
  94. package/dist/core/safety/ssot-guard.js +1 -54
  95. package/dist/core/stop-gate/stop-gate-check.js +0 -14
  96. package/dist/core/stop-gate/stop-gate-writer.js +0 -4
  97. package/dist/core/strategy/adhd-orchestrating-gate.js +2 -2
  98. package/dist/core/subagents/agent-catalog.js +28 -5
  99. package/dist/core/subagents/model-policy.js +52 -11
  100. package/dist/core/subagents/naruto-help-contract.js +2 -1
  101. package/dist/core/subagents/naruto-proof-projection.js +449 -0
  102. package/dist/core/subagents/official-subagent-preparation.js +641 -51
  103. package/dist/core/subagents/official-subagent-prompt.js +16 -6
  104. package/dist/core/subagents/official-subagent-runner.js +132 -12
  105. package/dist/core/subagents/subagent-evidence.js +44 -8
  106. package/dist/core/subagents/wave-lifecycle.js +238 -0
  107. package/dist/core/update-check.js +13 -4
  108. package/dist/core/verification/machine-feedback.js +39 -19
  109. package/dist/core/version.js +1 -1
  110. package/dist/core/zellij/zellij-lane-renderer.js +19 -19
  111. package/dist/core/zellij/zellij-official-subagent-activity.js +2 -0
  112. package/dist/core/zellij/zellij-right-column-manager.js +6 -55
  113. package/dist/core/zellij/zellij-slot-column-anchor.js +4 -5
  114. package/dist/core/zellij/zellij-slot-pane-renderer.js +1 -1
  115. package/dist/core/zellij/zellij-ui-mode.js +0 -7
  116. package/dist/core/zellij/zellij-worker-pane-manager.js +3 -11
  117. package/dist/native/sks-menubar/Sources/AppDelegate.swift +0 -1
  118. package/dist/native/sks-menubar/Sources/NotificationCoordinator.swift +1 -3
  119. package/dist/native/sks-menubar/Sources/OverviewViewController.swift +194 -24
  120. package/dist/native/sks-menubar/Sources/ProcessClient.swift +49 -4
  121. package/dist/native/sks-menubar/Sources/ProvidersViewController.swift +38 -10
  122. package/dist/native/sks-menubar/Sources/StatusItemController.swift +73 -11
  123. package/dist/native/sks-menubar/Sources/UpdatesViewController.swift +27 -2
  124. package/dist/scripts/architecture-guard-check.js +1 -9
  125. package/dist/scripts/canonical-test-runner.js +51 -8
  126. package/dist/scripts/check-architecture.js +11 -1
  127. package/dist/scripts/cli-output-consistency-check.js +0 -2
  128. package/dist/scripts/codex-0144-app-server-v2-check.js +4 -4
  129. package/dist/scripts/codex-0144-binary-identity-check.js +10 -4
  130. package/dist/scripts/codex-0144-capability-check.js +5 -5
  131. package/dist/scripts/codex-0144-policy-check.js +4 -0
  132. package/dist/scripts/codex-control-all-pipelines-check.js +2 -1
  133. package/dist/scripts/codex-lb-gpt56-fast-profile-check.js +3 -3
  134. package/dist/scripts/codex-sdk-all-pipelines-check.js +2 -1
  135. package/dist/scripts/codex-sdk-real-smoke-check.js +20 -2
  136. package/dist/scripts/current-command-surface-check.js +5 -3
  137. package/dist/scripts/current-surface-update-e2e-check.js +2 -2
  138. package/dist/scripts/docs-truthfulness-check.js +8 -6
  139. package/dist/scripts/doctor-fixes-codex-app-fast-ui-check.js +3 -2
  140. package/dist/scripts/gate-policy-audit-check.js +7 -1
  141. package/dist/scripts/harness-benchmark-check.js +4 -4
  142. package/dist/scripts/hook-latency-quantum-check.js +2 -2
  143. package/dist/scripts/legacy-gate-purge-check.js +4 -2
  144. package/dist/scripts/loop-directive-check-lib.js +14 -13
  145. package/dist/scripts/naruto-codex-e2e-check.js +2 -2
  146. package/dist/scripts/naruto-ssot-gate-aliases-check.js +9 -0
  147. package/dist/scripts/naruto-ssot-pipeline-default-check.js +10 -0
  148. package/dist/scripts/naruto-ssot-route-normalization-check.js +8 -0
  149. package/dist/scripts/naruto-ssot-routing-check.js +12 -0
  150. package/dist/scripts/product-design-plugin-routing-check.js +4 -9
  151. package/dist/scripts/release-affected-selector-check.js +7 -1
  152. package/dist/scripts/release-check-stamp.js +151 -18
  153. package/dist/scripts/release-dynamic-presets-check.js +5 -2
  154. package/dist/scripts/release-metadata-1-19-check.js +4 -0
  155. package/dist/scripts/release-real-check.js +21 -3
  156. package/dist/scripts/sks-menubar-install-check.js +5 -5
  157. package/dist/scripts/upgrade-migration-matrix-check.js +278 -5
  158. package/dist/scripts/zellij-developer-controls-check.js +3 -5
  159. package/dist/scripts/zellij-initial-main-only-blackbox.js +3 -8
  160. package/dist/scripts/zellij-pane-lock-open-worker-integration-blackbox.js +1 -2
  161. package/dist/scripts/zellij-right-column-headless-overflow-check.js +1 -1
  162. package/dist/scripts/zellij-right-column-manager-check.js +3 -4
  163. package/dist/scripts/zellij-slot-only-ui-check.js +2 -2
  164. package/dist/scripts/zellij-stacked-fallback-integration-blackbox.js +1 -2
  165. package/docs/demo.tape +1 -1
  166. package/infra-harness-gates.json +0 -27
  167. package/package.json +11 -6
  168. package/release-gates.v2.json +150 -22
  169. package/schemas/codex/agent-result.schema.json +4 -0
  170. package/schemas/codex/app-server-0.144/codex_app_server_protocol.v2.schemas.json +1 -18812
  171. package/schemas/codex/codex-0139-real-probe-result.schema.json +2 -2
  172. package/schemas/zellij/zellij-right-column-state.schema.json +0 -1
  173. package/dist/core/commands/ui-command.js +0 -198
  174. package/dist/core/loops/goal-to-loop-compat.js +0 -22
  175. package/dist/core/naruto/naruto-allocation-policy.js +0 -98
  176. package/dist/core/naruto/naruto-finalizer.js +0 -22
  177. package/dist/core/naruto/naruto-gpt-final-pack.js +0 -50
  178. package/dist/core/naruto/naruto-real-worker-child.js +0 -209
  179. package/dist/core/naruto/naruto-real-worker-runtime.js +0 -178
  180. package/dist/core/naruto/naruto-rebalance-policy.js +0 -47
  181. package/dist/core/naruto/naruto-verification-pool.js +0 -17
  182. package/dist/core/ui/dashboard-html.js +0 -110
  183. package/dist/core/zellij/zellij-dashboard-pane.js +0 -70
  184. package/dist/core/zellij/zellij-dashboard-renderer.js +0 -59
  185. package/dist/core/zellij/zellij-naruto-dashboard.js +0 -44
  186. package/dist/scripts/zellij-dashboard-pane-check.js +0 -69
  187. package/dist/scripts/zellij-dashboard-watch.js +0 -40
@@ -1,15 +1,21 @@
1
1
  import path from 'node:path';
2
2
  import { ui as cliUi } from '../../cli/cli-theme.js';
3
- import { createMission, findLatestMission, getOrCreateSessionMission, loadStateForSession, loadMission, sessionStateKey, setCurrent } from '../mission.js';
3
+ import { createMission, findLatestMission, getOrCreateSessionMission, loadStateForSession, loadMission, sessionStateKey, setCurrent, updateCurrentIfMissionAndRun } from '../mission.js';
4
4
  import { closeWorkOrderLedgerForRouteResult, createAndWriteWorkOrderLedgerForPrompt } from '../work-order-ledger.js';
5
5
  import { appendJsonl, exists, nowIso, readJson, sksRoot, writeJsonAtomic } from '../fsx.js';
6
6
  import { SUBAGENT_EVENT_LOG_FILENAME, SUBAGENT_PARENT_SUMMARY_FILENAME, bindTrustworthySubagentParentSummaryToRun, persistOrReuseTrustworthySubagentParentSummary, readSubagentEvents, writeSubagentEvidence } from '../subagents/subagent-evidence.js';
7
7
  import { buildNarutoHelpResult } from '../subagents/naruto-help-contract.js';
8
+ import { buildNarutoProofProjection } from '../subagents/naruto-proof-projection.js';
8
9
  import { withFileLock } from '../locks/file-lock.js';
9
10
  import { codexAppSessionKey, detectCodexAppSession, runOfficialSubagentWorkflow } from '../subagents/official-subagent-runner.js';
10
- import { NARUTO_GATE_FILENAME, NARUTO_RESULT_SCHEMA, NARUTO_SUMMARY_FILENAME, SUBAGENT_PLAN_FILENAME, buildNarutoGateResult, buildNarutoSummary, prepareOfficialSubagentMission, writeNarutoGate } from '../subagents/official-subagent-preparation.js';
11
+ import { NARUTO_GATE_FILENAME, NARUTO_RESULT_SCHEMA, NARUTO_SUMMARY_FILENAME, SUBAGENT_PLAN_FILENAME, buildNarutoGateResult, buildNarutoSummary, officialSubagentPreparationInProgress, prepareOfficialSubagentMission, withOfficialSubagentLifecycleLock, withNarutoMissionRunAdmission, writeNarutoGate } from '../subagents/official-subagent-preparation.js';
11
12
  import { recordOfficialSubagentParentOutcomesTelemetry } from '../zellij/zellij-official-subagent-telemetry.js';
13
+ import { effectiveSubagentTarget, refreshSubagentWaveLifecycle } from '../subagents/wave-lifecycle.js';
12
14
  export { buildNarutoGateResult } from '../subagents/official-subagent-preparation.js';
15
+ let nextNarutoPreparationFailureInjectionForTest = null;
16
+ export function injectNextNarutoPreparationFailureForTest(value) {
17
+ nextNarutoPreparationFailureInjectionForTest = value;
18
+ }
13
19
  export async function narutoCommand(commandOrArgs = 'naruto', maybeArgs = []) {
14
20
  const args = Array.isArray(commandOrArgs) ? commandOrArgs.map(String) : maybeArgs.map(String);
15
21
  if (args.some((arg) => arg === '--glm' || arg.startsWith('--glm=')))
@@ -43,21 +49,30 @@ async function narutoRun(parsed) {
43
49
  staleMs: 120_000
44
50
  }, () => narutoRunTransaction(parsed, root, appSession, sessionKey));
45
51
  }
46
- return narutoRunTransaction(parsed, root, appSession, sessionKey);
47
- }
48
- async function narutoRunTransaction(parsed, root, appSession, sessionKey) {
52
+ if (appSession)
53
+ return narutoRunTransaction(parsed, root, true, null);
49
54
  const mission = await resolveRunMission(root, parsed, sessionKey);
50
- if (!mission) {
51
- return emit(parsed, {
52
- schema: NARUTO_RESULT_SCHEMA,
53
- ok: false,
54
- status: 'blocked',
55
- blockers: [`naruto_mission_not_found:${parsed.missionId}`]
56
- }, () => console.error(`Naruto mission not found: ${parsed.missionId}`), true);
57
- }
55
+ if (!mission)
56
+ return missingRunMission(parsed);
57
+ const admission = await withNarutoMissionRunAdmission({
58
+ missionId: mission.id,
59
+ missionDir: mission.dir,
60
+ prompt: parsed.prompt
61
+ }, (lease) => narutoRunTransaction(parsed, root, false, null, mission, lease));
62
+ if (admission.kind === 'executed')
63
+ return admission.value;
64
+ const response = admission.kind === 'reused'
65
+ ? { ...admission.response, artifacts: terminalNarutoArtifactLinks(admission.response) }
66
+ : admission.response;
67
+ return emit(parsed, response, () => renderRunResult(response), response.status === 'blocked');
68
+ }
69
+ async function narutoRunTransaction(parsed, root, appSession, sessionKey, resolvedMission, missionLease) {
70
+ const mission = resolvedMission || await resolveRunMission(root, parsed, sessionKey);
71
+ if (!mission)
72
+ return missingRunMission(parsed);
58
73
  const { id, dir } = mission;
59
74
  if (appSession && sessionKey) {
60
- const pending = await readPendingAppNarutoRun(root, { id, dir }, sessionKey);
75
+ const pending = await readPendingAppNarutoRun(root, { id, dir }, sessionKey, parsed.prompt);
61
76
  if (pending)
62
77
  return emit(parsed, pending, () => renderRunResult(pending));
63
78
  }
@@ -66,11 +81,9 @@ async function narutoRunTransaction(parsed, root, appSession, sessionKey) {
66
81
  route: 'Naruto',
67
82
  prompt: parsed.prompt
68
83
  });
69
- const preparation = await withFileLock({
70
- lockPath: path.join(dir, '.naruto-preparation.lock'),
71
- timeoutMs: 5_000,
72
- staleMs: 60_000
73
- }, () => prepareOfficialSubagentMission({
84
+ const preparationFailureInjection = nextNarutoPreparationFailureInjectionForTest;
85
+ nextNarutoPreparationFailureInjectionForTest = null;
86
+ const preparation = await prepareOfficialSubagentMission({
74
87
  root,
75
88
  dir,
76
89
  missionId: id,
@@ -82,31 +95,43 @@ async function narutoRunTransaction(parsed, root, appSession, sessionKey) {
82
95
  ...(parsed.maxThreads === undefined ? {} : { maxThreads: parsed.maxThreads }),
83
96
  mode: 'naruto',
84
97
  readOnly: parsed.readOnly,
85
- preparationOnly: true
86
- }));
98
+ preparationOnly: true,
99
+ ...(preparationFailureInjection ? { failureInjection: preparationFailureInjection } : {}),
100
+ statePatch: ({ budget: preparedBudget, workflowRunId: preparedRunId }) => ({
101
+ mission_id: id,
102
+ route: 'Naruto',
103
+ route_command: '$Naruto',
104
+ mode: 'NARUTO',
105
+ phase: 'NARUTO_DELEGATION_CONTEXT_READY',
106
+ questions_allowed: false,
107
+ implementation_allowed: true,
108
+ subagents_required: true,
109
+ subagents_verified: false,
110
+ subagents_spawned: false,
111
+ subagents_reported: false,
112
+ subagent_evidence_file: 'subagent-evidence.json',
113
+ parent_summary_present: false,
114
+ native_sessions_required: false,
115
+ native_sessions_verified: false,
116
+ agents_required: false,
117
+ requested_subagents: preparedBudget.requestedSubagents,
118
+ target_subagents: preparedBudget.requestedSubagents,
119
+ max_threads: preparedBudget.maxThreads,
120
+ max_depth: preparedBudget.maxDepth,
121
+ official_subagent_run_id: preparedRunId,
122
+ session_scope: sessionKey,
123
+ stop_gate: NARUTO_GATE_FILENAME,
124
+ naruto_gate_file: NARUTO_GATE_FILENAME,
125
+ naruto_gate_passed: false,
126
+ reflection_invalidation_required: false,
127
+ reflection_invalidated_at: null,
128
+ reflection_invalidation_reason: null,
129
+ reflection_invalidated_for_workflow_run_id: null,
130
+ reflection_invalidated_for_proof_digest: null,
131
+ prompt: parsed.prompt
132
+ })
133
+ });
87
134
  const { plan, evidence: preparationEvidence, budget, verification, delegationPrompt, workflowRunId, configBlockers } = preparation;
88
- await setCurrent(root, {
89
- mission_id: id,
90
- route: 'Naruto',
91
- route_command: '$Naruto',
92
- mode: 'NARUTO',
93
- phase: 'NARUTO_DELEGATION_CONTEXT_READY',
94
- questions_allowed: false,
95
- implementation_allowed: true,
96
- subagents_required: true,
97
- subagents_verified: false,
98
- native_sessions_required: false,
99
- native_sessions_verified: false,
100
- agents_required: false,
101
- requested_subagents: budget.requestedSubagents,
102
- max_threads: budget.maxThreads,
103
- max_depth: budget.maxDepth,
104
- official_subagent_run_id: workflowRunId,
105
- session_scope: sessionKey,
106
- stop_gate: NARUTO_GATE_FILENAME,
107
- naruto_gate_file: NARUTO_GATE_FILENAME,
108
- prompt: parsed.prompt
109
- }, { sessionKey });
110
135
  const run = await runOfficialSubagentWorkflow({
111
136
  root,
112
137
  prompt: delegationPrompt,
@@ -114,117 +139,149 @@ async function narutoRunTransaction(parsed, root, appSession, sessionKey) {
114
139
  maxThreads: budget.maxThreads,
115
140
  appSession,
116
141
  missionId: id,
117
- sessionKey
118
- });
119
- const completedPlan = await readJson(path.join(dir, SUBAGENT_PLAN_FILENAME), plan).catch(() => plan);
120
- const finalBudget = {
121
- ...budget,
122
- requestedSubagents: Number(completedPlan?.requested_subagents || budget.requestedSubagents),
123
- maxThreads: Number(completedPlan?.max_threads || budget.maxThreads),
124
- firstWave: Number(completedPlan?.first_wave ?? budget.firstWave),
125
- waveCount: Number(completedPlan?.wave_count ?? budget.waveCount),
126
- capacity: completedPlan?.capacity_controller || budget.capacity
127
- };
128
- const runBoundParentSummary = bindTrustworthySubagentParentSummaryToRun(run.parent_summary, workflowRunId);
129
- const effectiveParentSummary = await persistOrReuseTrustworthySubagentParentSummary(dir, runBoundParentSummary, {
130
- workflowStatus: run.status,
131
- runId: workflowRunId
132
- });
133
- const evidence = await writeSubagentEvidence(dir, {
134
- requestedSubagents: finalBudget.requestedSubagents,
135
- parentSummary: effectiveParentSummary,
136
- workflowStatus: run.status,
137
- preparationOnly: appSession,
138
- runId: workflowRunId,
139
- additionalBlockers: configBlockers
142
+ sessionKey,
143
+ ...(missionLease ? { onChildSpawn: missionLease.protectChildPid } : {})
140
144
  });
141
- if (!appSession) {
142
- const parentTelemetry = await recordOfficialSubagentParentOutcomesTelemetry({
143
- root,
144
- routeMissionId: id,
145
- parentSummary: effectiveParentSummary,
146
- plan: completedPlan
147
- }).catch(async (error) => {
148
- await appendJsonl(path.join(dir, 'zellij-telemetry-warnings.jsonl'), {
149
- ts: nowIso(),
150
- warning: 'official_subagent_parent_outcome_telemetry_failed',
151
- error: String(error?.message || error)
152
- }).catch(() => undefined);
145
+ const result = await withOfficialSubagentLifecycleLock(dir, async () => {
146
+ if (await officialSubagentPreparationInProgress(dir))
153
147
  return null;
148
+ const completedPlan = await readJson(path.join(dir, SUBAGENT_PLAN_FILENAME), plan).catch(() => plan);
149
+ if (String(completedPlan?.workflow_run_id || '').trim() !== workflowRunId)
150
+ return null;
151
+ const finalBudget = {
152
+ ...budget,
153
+ requestedSubagents: Number(completedPlan?.requested_subagents || budget.requestedSubagents),
154
+ maxThreads: Number(completedPlan?.max_threads || budget.maxThreads),
155
+ firstWave: Number(completedPlan?.first_wave ?? budget.firstWave),
156
+ waveCount: Number(completedPlan?.wave_count ?? budget.waveCount),
157
+ capacity: completedPlan?.capacity_controller || budget.capacity
158
+ };
159
+ const runBoundParentSummary = bindTrustworthySubagentParentSummaryToRun(run.parent_summary, workflowRunId);
160
+ const effectiveParentSummary = await persistOrReuseTrustworthySubagentParentSummary(dir, runBoundParentSummary, {
161
+ workflowStatus: run.status,
162
+ runId: workflowRunId
163
+ });
164
+ const waveLifecycle = await refreshSubagentWaveLifecycle(dir, {
165
+ plan: completedPlan
166
+ }).catch(() => completedPlan?.wave_lifecycle || null);
167
+ const countTarget = effectiveSubagentTarget(waveLifecycle ? { ...completedPlan, wave_lifecycle: waveLifecycle } : completedPlan, waveLifecycle?.cumulative_started || 0);
168
+ const evidence = await writeSubagentEvidence(dir, {
169
+ requestedSubagents: finalBudget.requestedSubagents,
170
+ countPolicy: countTarget.countPolicy,
171
+ targetSubagents: countTarget.targetSubagents,
172
+ parentSummary: effectiveParentSummary,
173
+ workflowStatus: run.status,
174
+ preparationOnly: appSession,
175
+ runId: workflowRunId,
176
+ additionalBlockers: configBlockers
154
177
  });
155
- if (parentTelemetry?.blocker) {
156
- await appendJsonl(path.join(dir, 'zellij-telemetry-warnings.jsonl'), {
157
- ts: nowIso(),
158
- warning: 'official_subagent_parent_outcome_telemetry_incomplete',
159
- blocker: parentTelemetry.blocker,
160
- failed_mission_ids: 'failed_mission_ids' in parentTelemetry ? parentTelemetry.failed_mission_ids : [],
161
- skipped_thread_ids: 'skipped_thread_ids' in parentTelemetry ? parentTelemetry.skipped_thread_ids : []
162
- }).catch(() => undefined);
178
+ if (!appSession) {
179
+ const parentTelemetry = await recordOfficialSubagentParentOutcomesTelemetry({
180
+ root,
181
+ routeMissionId: id,
182
+ parentSummary: effectiveParentSummary,
183
+ plan: completedPlan
184
+ }).catch(async (error) => {
185
+ await appendJsonl(path.join(dir, 'zellij-telemetry-warnings.jsonl'), {
186
+ ts: nowIso(),
187
+ warning: 'official_subagent_parent_outcome_telemetry_failed',
188
+ error: String(error?.message || error)
189
+ }).catch(() => undefined);
190
+ return null;
191
+ });
192
+ if (parentTelemetry?.blocker) {
193
+ await appendJsonl(path.join(dir, 'zellij-telemetry-warnings.jsonl'), {
194
+ ts: nowIso(),
195
+ warning: 'official_subagent_parent_outcome_telemetry_incomplete',
196
+ blocker: parentTelemetry.blocker,
197
+ failed_mission_ids: 'failed_mission_ids' in parentTelemetry ? parentTelemetry.failed_mission_ids : [],
198
+ skipped_thread_ids: 'skipped_thread_ids' in parentTelemetry ? parentTelemetry.skipped_thread_ids : []
199
+ }).catch(() => undefined);
200
+ }
163
201
  }
164
- }
165
- const candidatePassed = run.ok === true && evidence.ok === true && appSession === false;
166
- const blockers = uniqueStrings([
167
- ...(Array.isArray(evidence.blockers) ? evidence.blockers : []),
168
- ...configBlockers,
169
- ...(!appSession && run.ok !== true ? [`codex_parent_exit:${String(run.codex_exit_code ?? 'unknown')}`] : []),
170
- ...(appSession ? ['official_subagent_execution_pending_in_current_parent'] : [])
171
- ]);
172
- const gate = await writeNarutoGate(dir, {
173
- missionId: id,
174
- workflowRunId,
175
- evidence,
176
- passed: candidatePassed,
177
- blockers
178
- });
179
- const passed = gate.passed === true;
180
- const status = passed
181
- ? 'completed'
182
- : appSession
183
- ? 'delegation_context_ready'
184
- : run.ok === true
185
- ? 'incomplete'
186
- : 'blocked';
187
- const summary = buildNarutoSummary({
188
- missionId: id,
189
- workflowRunId,
190
- budget: finalBudget,
191
- evidence,
192
- verification,
193
- status,
194
- ok: passed,
195
- parentSummary: effectiveParentSummary,
196
- blockers: gate.blockers,
197
- appSession,
198
- sessionKey,
199
- suggestedAgents: Array.isArray(completedPlan?.suggested_agents) ? completedPlan.suggested_agents : []
202
+ const candidatePassed = run.ok === true && evidence.ok === true && appSession === false;
203
+ const blockers = uniqueStrings([
204
+ ...(Array.isArray(evidence.blockers) ? evidence.blockers : []),
205
+ ...configBlockers,
206
+ ...(Array.isArray(run.blockers) ? run.blockers : []),
207
+ ...(appSession ? ['official_subagent_execution_pending_in_current_parent'] : [])
208
+ ]);
209
+ const gate = await writeNarutoGate(dir, {
210
+ missionId: id,
211
+ workflowRunId,
212
+ evidence,
213
+ passed: candidatePassed,
214
+ blockers
215
+ });
216
+ const passed = gate.passed === true;
217
+ const status = passed
218
+ ? 'completed'
219
+ : appSession
220
+ ? 'delegation_context_ready'
221
+ : run.ok === true
222
+ ? 'incomplete'
223
+ : 'blocked';
224
+ const summary = buildNarutoSummary({
225
+ missionId: id,
226
+ workflowRunId,
227
+ budget: finalBudget,
228
+ evidence,
229
+ verification,
230
+ status,
231
+ ok: passed,
232
+ parentSummary: effectiveParentSummary,
233
+ blockers: gate.blockers,
234
+ appSession,
235
+ sessionKey,
236
+ suggestedAgents: Array.isArray(completedPlan?.suggested_agents) ? completedPlan.suggested_agents : [],
237
+ waveLifecycle
238
+ });
239
+ await writeJsonAtomic(path.join(dir, NARUTO_SUMMARY_FILENAME), summary);
240
+ await updateCurrentIfMissionAndRun(root, id, workflowRunId, {
241
+ mission_id: id,
242
+ official_subagent_run_id: workflowRunId,
243
+ session_scope: sessionKey,
244
+ phase: passed ? 'NARUTO_COMPLETE' : appSession ? 'NARUTO_DELEGATION_CONTEXT_READY' : 'NARUTO_BLOCKED',
245
+ subagents_verified: evidence.ok === true,
246
+ requested_subagents: finalBudget.requestedSubagents,
247
+ target_subagents: evidence.target_subagents,
248
+ max_threads: finalBudget.maxThreads,
249
+ naruto_gate_passed: passed,
250
+ route_closed: false
251
+ }, { sessionKey });
252
+ if (!appSession) {
253
+ await closeWorkOrderLedgerForRouteResult(dir, { ok: passed, blockers: gate.blockers });
254
+ if (!passed)
255
+ process.exitCode = 1;
256
+ }
257
+ return {
258
+ ...summary,
259
+ mission_id: id,
260
+ attached_to_pending_run: false,
261
+ additionalContext: appSession ? run.additionalContext : undefined,
262
+ artifacts: narutoArtifactLinks(evidence)
263
+ };
200
264
  });
201
- await writeJsonAtomic(path.join(dir, NARUTO_SUMMARY_FILENAME), summary);
202
- await setCurrent(root, {
203
- mission_id: id,
204
- official_subagent_run_id: workflowRunId,
205
- session_scope: sessionKey,
206
- phase: passed ? 'NARUTO_COMPLETE' : appSession ? 'NARUTO_DELEGATION_CONTEXT_READY' : 'NARUTO_BLOCKED',
207
- subagents_verified: evidence.ok === true,
208
- requested_subagents: finalBudget.requestedSubagents,
209
- max_threads: finalBudget.maxThreads,
210
- naruto_gate_passed: passed,
211
- route_closed: false
212
- }, { sessionKey });
213
- if (!appSession) {
214
- await closeWorkOrderLedgerForRouteResult(dir, { ok: passed, blockers: gate.blockers });
215
- if (!passed)
216
- process.exitCode = 1;
265
+ if (!result) {
266
+ const currentSummary = await readJson(path.join(dir, NARUTO_SUMMARY_FILENAME), null).catch(() => null);
267
+ const currentEvidence = await readJson(path.join(dir, 'subagent-evidence.json'), null).catch(() => null);
268
+ const staleResult = {
269
+ ...(currentSummary || {}),
270
+ schema: NARUTO_RESULT_SCHEMA,
271
+ ok: currentSummary?.ok === true,
272
+ completion_evidence: currentSummary?.completion_evidence === true,
273
+ mission_id: id,
274
+ attached_to_pending_run: true,
275
+ stale_run_discarded: workflowRunId,
276
+ artifacts: narutoArtifactLinks(currentEvidence)
277
+ };
278
+ return emit(parsed, staleResult, () => renderRunResult(staleResult));
217
279
  }
218
- const result = {
219
- ...summary,
220
- mission_id: id,
221
- attached_to_pending_run: false,
222
- additionalContext: appSession ? run.additionalContext : undefined,
223
- artifacts: narutoArtifactLinks(evidence)
224
- };
225
280
  return emit(parsed, result, () => renderRunResult(result));
226
281
  }
227
- async function readPendingAppNarutoRun(root, mission, sessionKey) {
282
+ async function readPendingAppNarutoRun(root, mission, sessionKey, prompt) {
283
+ if (await officialSubagentPreparationInProgress(mission.dir))
284
+ return null;
228
285
  const [plan, evidence, summary, gate, state] = await Promise.all([
229
286
  readJson(path.join(mission.dir, SUBAGENT_PLAN_FILENAME), null),
230
287
  readJson(path.join(mission.dir, 'subagent-evidence.json'), null),
@@ -238,6 +295,7 @@ async function readPendingAppNarutoRun(root, mission, sessionKey) {
238
295
  && plan?.schema === 'sks.subagent-plan.v1'
239
296
  && plan?.workflow === 'official_codex_subagent'
240
297
  && plan?.mission_id === mission.id
298
+ && String(plan?.goal || '').trim() === String(prompt || '').trim()
241
299
  && plan?.session_scope === sessionKey
242
300
  && evidence?.run_id === workflowRunId
243
301
  && evidence?.preparation_only === true
@@ -285,6 +343,16 @@ function narutoArtifactLinks(evidence) {
285
343
  gate: NARUTO_GATE_FILENAME
286
344
  };
287
345
  }
346
+ function terminalNarutoArtifactLinks(response) {
347
+ return {
348
+ plan: SUBAGENT_PLAN_FILENAME,
349
+ events: SUBAGENT_EVENT_LOG_FILENAME,
350
+ parent_summary: response.parent_summary_present === true ? SUBAGENT_PARENT_SUMMARY_FILENAME : null,
351
+ evidence: 'subagent-evidence.json',
352
+ summary: NARUTO_SUMMARY_FILENAME,
353
+ gate: NARUTO_GATE_FILENAME
354
+ };
355
+ }
288
356
  async function narutoStatus(parsed) {
289
357
  const resolved = await resolveReadMission(parsed);
290
358
  if (!resolved)
@@ -302,7 +370,10 @@ async function narutoStatus(parsed) {
302
370
  mission_id: resolved.id,
303
371
  status: summary?.status || evidence?.status || 'prepared',
304
372
  requested_subagents: plan?.requested_subagents ?? evidence?.requested_subagents ?? null,
373
+ count_policy: evidence?.count_policy ?? plan?.wave_lifecycle?.count_policy ?? null,
374
+ target_subagents: evidence?.target_subagents ?? plan?.wave_lifecycle?.target_subagents ?? null,
305
375
  max_threads: plan?.max_threads ?? null,
376
+ wave_lifecycle: plan?.wave_lifecycle ?? null,
306
377
  started_subagents: evidence?.started_threads ?? 0,
307
378
  completed_subagents: evidence?.completed_threads ?? 0,
308
379
  failed_subagents: evidence?.failed_threads ?? 0,
@@ -325,6 +396,8 @@ async function narutoSubagents(parsed) {
325
396
  action: 'subagents',
326
397
  mission_id: resolved.id,
327
398
  requested_subagents: evidence?.requested_subagents ?? null,
399
+ count_policy: evidence?.count_policy ?? null,
400
+ target_subagents: evidence?.target_subagents ?? null,
328
401
  started_subagents: evidence?.started_threads ?? 0,
329
402
  completed_subagents: evidence?.completed_threads ?? 0,
330
403
  failed_subagents: evidence?.failed_threads ?? 0,
@@ -339,25 +412,11 @@ async function narutoProof(parsed) {
339
412
  const resolved = await resolveReadMission(parsed);
340
413
  if (!resolved)
341
414
  return missingMission(parsed, 'proof');
342
- const [evidence, summary, gate] = await Promise.all([
343
- readJson(path.join(resolved.dir, 'subagent-evidence.json'), null),
344
- readJson(path.join(resolved.dir, NARUTO_SUMMARY_FILENAME), null),
345
- readJson(path.join(resolved.dir, NARUTO_GATE_FILENAME), null)
346
- ]);
347
- const result = {
348
- schema: NARUTO_RESULT_SCHEMA,
349
- ok: gate?.passed === true && evidence?.ok === true,
350
- action: 'proof',
351
- mission_id: resolved.id,
352
- workflow: 'official_codex_subagent',
353
- evidence,
354
- summary,
355
- gate
356
- };
415
+ const result = await buildNarutoProofProjection({ artifactDir: resolved.dir, missionId: resolved.id });
357
416
  return emit(parsed, result, () => {
358
- console.log(`Naruto proof ${resolved.id}: ${result.ok ? 'passed' : 'incomplete'}`);
359
- if (Array.isArray(gate?.blockers) && gate.blockers.length)
360
- console.log(`Blockers: ${gate.blockers.join(', ')}`);
417
+ console.log(`Naruto proof ${resolved.id}: ${result.status}`);
418
+ if (result.blockers?.length)
419
+ console.log(`Blockers: ${result.blockers.join(', ')}`);
361
420
  });
362
421
  }
363
422
  function narutoHelp(parsed) {
@@ -391,6 +450,7 @@ async function resolveRunMission(root, parsed, sessionKey = null) {
391
450
  mode: 'naruto',
392
451
  prompt: parsed.prompt,
393
452
  sessionKey,
453
+ syncRequestIntake: true,
394
454
  selectMissionId: (state) => {
395
455
  const route = String(state?.route || state?.route_command || state?.mode || '').replace(/^\$/, '').toUpperCase();
396
456
  const sessionMatches = state?._session_key === sessionStateKey(sessionKey);
@@ -502,19 +562,10 @@ export function parseNarutoArgs(args) {
502
562
  }
503
563
  function positionalValues(args) {
504
564
  const valueFlags = new Set([
505
- '--agents', '--max-threads', '--mission', '--mission-id',
506
- '--backend', '--concurrency', '--target-active-slots', '--work-items',
507
- '--write-mode', '--max-write-agents', '--service-tier', '--messages',
508
- '--parallelism', '--tournament', '--ollama-model', '--local-model-model',
509
- '--ollama-base-url', '--local-model-base-url', '--scheduler', '--scheduler-mode',
510
- '--pool', '--pool-size', '--model', '--parent-model', '--worker-model',
511
- '--expert-model', '--agent-model', '--clone-model', '--reasoning-effort', '--engine'
565
+ '--agents', '--max-threads', '--mission', '--mission-id'
512
566
  ]);
513
567
  const booleanFlags = new Set([
514
- '--json', '--readonly', '--read-only', '--real', '--mock', '--no-open-zellij',
515
- '--no-zellij', '--attach', '--smoke', '--apply-patches', '--dry-run-patches',
516
- '--dry-run-patch', '--ollama', '--local-model', '--no-ollama', '--no-local-model',
517
- '--parallel-write', '--fast', '--no-fast'
568
+ '--json', '--readonly', '--read-only'
518
569
  ]);
519
570
  const result = [];
520
571
  for (let index = 0; index < args.length; index += 1) {
@@ -637,6 +688,14 @@ function missingMission(parsed, action) {
637
688
  status: 'missing_mission'
638
689
  }, () => console.log('No Naruto mission found.'));
639
690
  }
691
+ function missingRunMission(parsed) {
692
+ return emit(parsed, {
693
+ schema: NARUTO_RESULT_SCHEMA,
694
+ ok: false,
695
+ status: 'blocked',
696
+ blockers: [`naruto_mission_not_found:${parsed.missionId}`]
697
+ }, () => console.error(`Naruto mission not found: ${parsed.missionId}`), true);
698
+ }
640
699
  function emit(parsed, result, human, failed = false) {
641
700
  if (failed)
642
701
  process.exitCode = 1;
@@ -648,7 +707,7 @@ function emit(parsed, result, human, failed = false) {
648
707
  }
649
708
  function renderRunResult(result) {
650
709
  console.log(`$sks-naruto ${result.status}: ${result.mission_id}`);
651
- console.log(`Official subagents: requested ${result.requested_subagents}, max threads ${result.max_threads}`);
710
+ console.log(`Official subagents: requested ${result.requested_subagents}, target ${result.target_subagents ?? result.requested_subagents}, policy ${result.count_policy || 'exact'}, max threads ${result.max_threads}`);
652
711
  console.log(`Started/completed/failed: ${result.started_subagents}/${result.completed_subagents}/${result.failed_subagents}`);
653
712
  if (result.status === 'delegation_context_ready')
654
713
  console.log('Continue in the current Codex parent and wait for every requested subagent before summarizing.');
@@ -657,6 +716,7 @@ function renderRunResult(result) {
657
716
  }
658
717
  function renderStatusResult(result) {
659
718
  console.log(`Naruto ${result.action || 'status'}: ${result.mission_id}`);
719
+ console.log(`Requested/target/policy: ${result.requested_subagents ?? 0}/${result.target_subagents ?? result.requested_subagents ?? 0}/${result.count_policy || 'exact'}`);
660
720
  console.log(`Started/completed/failed: ${result.started_subagents || 0}/${result.completed_subagents || 0}/${result.failed_subagents || 0}`);
661
721
  }
662
722
  function uniqueStrings(values) {
@@ -10,7 +10,7 @@ import { inspectConfinedPath, moveConfinedPath, removeManagedPathVerified, uniqu
10
10
  import { collectNestedProjectRoots } from './current-project-guidance-nested.js';
11
11
  export const CURRENT_PROJECT_GUIDANCE_SCHEMA = 'sks.current-project-guidance.v1';
12
12
  const AGENTS_MARKER = 'BEGIN Sneakoscope Codex GX MANAGED BLOCK';
13
- const RETIRED_COMMAND_NAMES = ['team', 'mad-db', 'tmux', 'xai', 'swarm', 'agent', 'ralph', 'db'];
13
+ const RETIRED_COMMAND_NAMES = ['team', 'mad-db', 'tmux', 'xai', 'swarm', 'agent', 'ralph', 'db', 'ui'];
14
14
  const RETIRED_DOLLAR_COMMAND_NAMES = ['Agent', 'Team', 'MAD-DB', 'Swarm', 'ShadowClone', 'Kagebunshin', 'Ralph'];
15
15
  const LEGACY_UNPREFIXED_DOLLAR_COMMAND_NAMES = Array.from(new Set([
16
16
  ...RETIRED_DOLLAR_COMMAND_NAMES,
@@ -123,7 +123,7 @@ function phaseInputFiles(id) {
123
123
  return ['src/core/codex-native', 'src/scripts/native-capability-postcheck-check.ts'];
124
124
  if (id.includes('secret'))
125
125
  return ['safety-mutation-allowlist.json', 'src/scripts/secret-preservation-check.ts'];
126
- return ['package.json', 'config/codex-releases/rust-v0.144.1.json'];
126
+ return ['package.json', 'config/codex-releases/rust-v0.144.5.json'];
127
127
  }
128
128
  function packageIdentity() {
129
129
  const root = packageRoot();
@@ -132,31 +132,46 @@ export async function reconcileMissionIndex(root, fix, quarantineRoot, counters)
132
132
  return;
133
133
  }
134
134
  const value = await readJson(file, null).catch(() => null);
135
- if (!value || !Array.isArray(value.missions))
135
+ const indexSchemaCurrent = value?.schema === 'sks.mission-index.v1';
136
+ const missionRows = Array.isArray(value?.missions) ? value.missions : [];
137
+ const retiredRows = missionRows.filter((row) => isRetiredMissionIdentity(row));
138
+ const retiredCount = retiredRows.length;
139
+ const malformedOrForeign = !value || !indexSchemaCurrent || !Array.isArray(value?.missions);
140
+ if (!malformedOrForeign && retiredCount === 0)
136
141
  return;
137
- const retiredCount = value.missions.filter((row) => isRetiredMissionIdentity(row)).length;
138
- if (retiredCount === 0)
139
- return;
140
- counters.detected += retiredCount;
142
+ const retiredMissionIds = retiredRows
143
+ .map((row) => String(row?.id || ''))
144
+ .filter(Boolean);
145
+ const detectedCount = Math.max(1, retiredCount);
146
+ counters.detected += detectedCount;
141
147
  if (!fix) {
142
- counters.remaining += retiredCount;
143
- if (value.schema !== 'sks.mission-index.v1')
148
+ counters.remaining += detectedCount;
149
+ if (malformedOrForeign)
144
150
  counters.preserved += 1;
145
151
  return;
146
152
  }
147
153
  try {
148
- if (value.schema !== 'sks.mission-index.v1') {
154
+ if (malformedOrForeign) {
149
155
  await quarantineUserPath(root, file, quarantineRoot);
150
156
  counters.preserved += 1;
151
157
  }
158
+ const verifiedRetiredMissionIds = [];
159
+ for (const missionId of retiredMissionIds) {
160
+ const mission = await readJson(path.join(root, '.sneakoscope', 'missions', missionId, 'mission.json'), null).catch(() => null);
161
+ if (mission && isRetiredMissionIdentity(mission))
162
+ verifiedRetiredMissionIds.push(missionId);
163
+ }
152
164
  const { refreshMissionIndex } = await import('../retention.js');
153
- await refreshMissionIndex(root);
154
- counters.removed += retiredCount;
165
+ const refreshed = await refreshMissionIndex(root, { excludeMissionIds: verifiedRetiredMissionIds });
166
+ if (refreshed.missions.some((row) => isRetiredMissionIdentity(row))) {
167
+ throw new Error('retired_mission_index_identity_survived');
168
+ }
169
+ counters.removed += detectedCount;
155
170
  counters.rewrittenState += 1;
156
171
  }
157
172
  catch {
158
173
  counters.errors += 1;
159
- counters.remaining += retiredCount;
174
+ counters.remaining += detectedCount;
160
175
  }
161
176
  }
162
177
  async function reconcileSksOwnedRetiredMission(root, missionRoot, missionRecord, fix, quarantineRoot, counters) {
@@ -1,7 +1,7 @@
1
1
  import path from 'node:path';
2
2
  import { inspectConfinedPath, moveConfinedPath, removeEmptyTreeVerified, uniqueConfinedPath, walkConfinedEntries } from '../managed-path-safety.js';
3
3
  /** Cleanup-only inventory. These names are never registered, listed, or redirected. */
4
- export const REMOVED_PUBLIC_COMMANDS = ['team', 'mad-db', 'tmux', 'xai', 'swarm', 'agent', 'ralph'];
4
+ export const REMOVED_PUBLIC_COMMANDS = ['team', 'mad-db', 'tmux', 'xai', 'swarm', 'agent', 'ralph', 'ui'];
5
5
  const RETIRED_COMMAND_TOMBSTONES = new Set(REMOVED_PUBLIC_COMMANDS);
6
6
  const RETIRED_MISSION_MODES = new Set([
7
7
  ...REMOVED_PUBLIC_COMMANDS,