sneakoscope 6.0.2 → 6.1.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 (242) hide show
  1. package/README.md +5 -3
  2. package/config/codex-releases/{rust-v0.142.0.json → rust-v0.144.1.json} +6 -6
  3. package/crates/sks-core/Cargo.lock +1 -1
  4. package/crates/sks-core/Cargo.toml +1 -1
  5. package/dist/cli/install-helpers.js +255 -440
  6. package/dist/cli/router.js +53 -4
  7. package/dist/commands/codex-app.js +8 -3
  8. package/dist/commands/codex-lb.js +169 -40
  9. package/dist/commands/codex.js +6 -5
  10. package/dist/commands/doctor.js +60 -26
  11. package/dist/commands/versioning.js +7 -0
  12. package/dist/config/skills-manifest.json +57 -57
  13. package/dist/core/agents/agent-central-ledger.js +9 -0
  14. package/dist/core/agents/agent-cleanup-executor.js +334 -41
  15. package/dist/core/agents/agent-cleanup.js +20 -1
  16. package/dist/core/agents/agent-command-surface.js +2 -1
  17. package/dist/core/agents/agent-effort-policy.js +46 -33
  18. package/dist/core/agents/agent-janitor.js +9 -10
  19. package/dist/core/agents/agent-namespace-safety.js +56 -0
  20. package/dist/core/agents/agent-orchestrator.js +26 -4
  21. package/dist/core/agents/agent-output-validator.js +1 -1
  22. package/dist/core/agents/agent-proof-evidence.js +16 -2
  23. package/dist/core/agents/agent-role-config.js +3 -6
  24. package/dist/core/agents/agent-roster.js +2 -2
  25. package/dist/core/agents/agent-runner-codex-exec.js +2 -0
  26. package/dist/core/agents/agent-runner-process.js +1 -0
  27. package/dist/core/agents/fast-mode-policy.js +3 -5
  28. package/dist/core/agents/native-cli-session-swarm.js +18 -1
  29. package/dist/core/agents/native-worker-backend-router.js +180 -108
  30. package/dist/core/agents/parallel-write-fixture.js +15 -10
  31. package/dist/core/agents/runtime-proof-summary.js +21 -3
  32. package/dist/core/agents/work-partition/repo-inventory.js +68 -7
  33. package/dist/core/code-structure.js +5 -4
  34. package/dist/core/codex/codex-config-guard.js +31 -9
  35. package/dist/core/codex-app/codex-app-fast-ui-repair.js +51 -20
  36. package/dist/core/codex-app/codex-app-restart.js +38 -8
  37. package/dist/core/codex-app/codex-app-ui-state-snapshot.js +11 -3
  38. package/dist/core/codex-app/sks-menubar.js +100 -40
  39. package/dist/core/codex-app.js +60 -17
  40. package/dist/core/codex-compat/codex-hook-warning-detector.js +10 -1
  41. package/dist/core/codex-compat/codex-release-manifest.js +6 -6
  42. package/dist/core/codex-control/codex-0139-doctor-real-probe.js +7 -1
  43. package/dist/core/codex-control/codex-0139-image-path-real-probe.js +14 -8
  44. package/dist/core/codex-control/codex-0139-probe-runner.js +103 -28
  45. package/dist/core/codex-control/codex-0139-real-probe-summary.js +7 -3
  46. package/dist/core/codex-control/codex-0139-real-probes.js +21 -6
  47. package/dist/core/codex-control/codex-0139-sandbox-real-probe.js +39 -13
  48. package/dist/core/codex-control/codex-0139-web-search-probe.js +11 -8
  49. package/dist/core/codex-control/{codex-0142-capability.js → codex-0144-capability.js} +22 -22
  50. package/dist/core/codex-control/codex-0144-collab-agent-real-probe.js +63 -0
  51. package/dist/core/codex-control/codex-model-metadata.js +8 -4
  52. package/dist/core/codex-control/codex-multi-agent-event-normalizer.js +5 -1
  53. package/dist/core/codex-control/codex-reliability-shield.js +4 -1
  54. package/dist/core/codex-control/codex-sdk-adapter.js +53 -6
  55. package/dist/core/codex-control/codex-sdk-config-policy.js +2 -1
  56. package/dist/core/codex-control/codex-sdk-sandbox-policy.js +6 -3
  57. package/dist/core/codex-lb/codex-lb-env.js +107 -0
  58. package/dist/core/codex-lb/codex-lb-tool-catalog.js +478 -0
  59. package/dist/core/codex-native/codex-native-feature-broker.js +22 -22
  60. package/dist/core/codex-native/codex-native-feature-matrix.js +2 -2
  61. package/dist/core/codex-native/native-capability-postcheck.js +16 -8
  62. package/dist/core/codex-native/native-capability-repair-matrix.js +76 -27
  63. package/dist/core/codex-plugins/codex-plugin-json.js +67 -21
  64. package/dist/core/codex-plugins/codex-plugin-repair.js +118 -0
  65. package/dist/core/codex-runtime/codex-desktop-config-policy.js +306 -0
  66. package/dist/core/commands/agent-command.js +19 -0
  67. package/dist/core/commands/basic-cli.js +45 -24
  68. package/dist/core/commands/gc-command.js +27 -4
  69. package/dist/core/commands/image-ux-review-command.js +55 -24
  70. package/dist/core/commands/mad-sks-command.js +152 -132
  71. package/dist/core/commands/naruto-command.js +41 -10
  72. package/dist/core/commands/pipeline-command.js +1 -0
  73. package/dist/core/commands/wiki-command.js +179 -83
  74. package/dist/core/computer-use-live-evidence.js +166 -3
  75. package/dist/core/computer-use-status.js +5 -2
  76. package/dist/core/daemon/sksd-hook-daemon-entrypoint.js +2 -2
  77. package/dist/core/daemon/sksd-hook-daemon.js +171 -28
  78. package/dist/core/daemon/sksd-hook-dispatch.js +2 -2
  79. package/dist/core/dfix/verification-selector.js +6 -4
  80. package/dist/core/doctor/browser-use-repair.js +54 -13
  81. package/dist/core/doctor/codex-0139-doctor.js +3 -2
  82. package/dist/core/doctor/computer-use-repair.js +28 -39
  83. package/dist/core/doctor/doctor-codex-startup-repair.js +19 -9
  84. package/dist/core/doctor/doctor-context7-repair.js +1 -1
  85. package/dist/core/doctor/doctor-dirty-planner.js +1 -1
  86. package/dist/core/doctor/doctor-native-capability-repair.js +74 -3
  87. package/dist/core/doctor/imagegen-repair.js +47 -12
  88. package/dist/core/doctor/legacy-global-hook-cleanup.js +179 -0
  89. package/dist/core/feature-registry.js +25 -31
  90. package/dist/core/fsx.js +54 -6
  91. package/dist/core/harness-conflicts.js +1 -1
  92. package/dist/core/hooks-runtime/code-pack-freshness-preflight.js +5 -4
  93. package/dist/core/hooks-runtime/hook-invocation-dedupe.js +147 -0
  94. package/dist/core/hooks-runtime/hook-io.js +6 -0
  95. package/dist/core/hooks-runtime.js +17 -2
  96. package/dist/core/image/image-artifact-path-contract.js +8 -6
  97. package/dist/core/image/image-artifact-registry.js +5 -1
  98. package/dist/core/image-ux-review/imagegen-adapter.js +5 -2
  99. package/dist/core/imagegen/imagegen-capability.js +10 -13
  100. package/dist/core/imagegen/require-imagegen.js +37 -11
  101. package/dist/core/managed-assets/managed-assets-manifest.js +1 -5
  102. package/dist/core/naruto/naruto-work-graph.js +70 -4
  103. package/dist/core/naruto/naruto-write-e2e.js +3 -4
  104. package/dist/core/ops/reporting.js +3 -0
  105. package/dist/core/pipeline-internals/runtime-core.js +12 -7
  106. package/dist/core/pipeline-internals/runtime-gates.js +17 -1
  107. package/dist/core/ppt/style-tokens.js +1 -1
  108. package/dist/core/ppt-review/index.js +1 -1
  109. package/dist/core/ppt-review/slide-exporter.js +23 -17
  110. package/dist/core/ppt-review/slide-imagegen-review.js +1 -1
  111. package/dist/core/ppt-review/slide-issue-extraction.js +4 -2
  112. package/dist/core/product-design-plugin.js +2 -2
  113. package/dist/core/proof/route-finalizer.js +1 -1
  114. package/dist/core/proof-field.js +3 -3
  115. package/dist/core/provider/model-router.js +68 -3
  116. package/dist/core/release/gate-manifest.js +18 -12
  117. package/dist/core/release/gate-pack-manifest.js +1 -1
  118. package/dist/core/release/package-size-budget.js +2 -0
  119. package/dist/core/release/release-gate-affected-selector.js +1 -1
  120. package/dist/core/release/release-gate-dag.js +43 -3
  121. package/dist/core/release/release-gate-hermetic-env.js +28 -17
  122. package/dist/core/release/release-real-contract.js +416 -0
  123. package/dist/core/retention/retention-budget.js +25 -6
  124. package/dist/core/retention.js +980 -101
  125. package/dist/core/routes/constants.js +1 -1
  126. package/dist/core/routes/evidence.js +4 -4
  127. package/dist/core/routes/model-mode-router.js +3 -0
  128. package/dist/core/routes/ppt-policy.js +1 -1
  129. package/dist/core/routes.js +11 -12
  130. package/dist/core/secret-redaction.js +4 -0
  131. package/dist/core/triwiki/code-pack.js +8 -2
  132. package/dist/core/triwiki/triwiki-cache-key.js +108 -29
  133. package/dist/core/triwiki-attention.js +13 -6
  134. package/dist/core/triwiki-provenance.js +274 -0
  135. package/dist/core/triwiki-runtime.js +21 -7
  136. package/dist/core/triwiki-wrongness/wrongness-ledger.js +178 -59
  137. package/dist/core/triwiki-wrongness/wrongness-retrieval.js +11 -2
  138. package/dist/core/triwiki-wrongness/wrongness-trust-policy.js +2 -0
  139. package/dist/core/update/update-migration-state.js +1 -1
  140. package/dist/core/update/update-notice.js +23 -0
  141. package/dist/core/update-check.js +69 -25
  142. package/dist/core/version.js +1 -1
  143. package/dist/core/wiki-coordinate.js +128 -12
  144. package/dist/core/work-order-ledger.js +168 -9
  145. package/dist/core/zellij/zellij-command.js +12 -1
  146. package/dist/core/zellij/zellij-dashboard-pane.js +3 -3
  147. package/dist/core/zellij/zellij-launcher.js +15 -14
  148. package/dist/core/zellij/zellij-pane-proof.js +32 -6
  149. package/dist/core/zellij/zellij-worker-pane-manager.js +5 -3
  150. package/dist/scripts/agent-fast-mode-default-check.js +48 -29
  151. package/dist/scripts/agent-role-config-repair-check.js +25 -4
  152. package/dist/scripts/agent-wiki-context-proof-check.js +16 -2
  153. package/dist/scripts/all-feature-deep-completion-check.js +14 -4
  154. package/dist/scripts/build-dist.js +17 -5
  155. package/dist/scripts/canonical-test-runner.js +188 -0
  156. package/dist/scripts/check-command-module-budget.js +38 -16
  157. package/dist/scripts/check-legacy-free.js +1 -1
  158. package/dist/scripts/codex-0139-interrupt-agent-check.js +5 -1
  159. package/dist/scripts/{codex-0142-app-server-v2-check.js → codex-0144-app-server-v2-check.js} +11 -10
  160. package/dist/scripts/{codex-0142-binary-identity-check.js → codex-0144-binary-identity-check.js} +4 -4
  161. package/dist/scripts/codex-0144-capability-check.js +21 -0
  162. package/dist/scripts/{codex-0139-real-probes-check.js → codex-0144-core-real-probes-check.js} +19 -5
  163. package/dist/scripts/{codex-0142-doctor-wiring-check.js → codex-0144-doctor-wiring-check.js} +6 -6
  164. package/dist/scripts/{codex-0142-manifest-check.js → codex-0144-manifest-check.js} +11 -3
  165. package/dist/scripts/{codex-0142-policy-check.js → codex-0144-policy-check.js} +2 -2
  166. package/dist/scripts/{codex-0142-thread-store-check.js → codex-0144-thread-store-check.js} +3 -3
  167. package/dist/scripts/codex-app-provider-model-ui-check.js +57 -8
  168. package/dist/scripts/codex-app-ui-preservation-check.js +35 -4
  169. package/dist/scripts/codex-control-side-effect-scope-check.js +2 -2
  170. package/dist/scripts/codex-effort-auto-discovery-check.js +1 -1
  171. package/dist/scripts/codex-lb-fast-mode-truth-check.js +1 -0
  172. package/dist/scripts/{codex-lb-gpt55-fast-profile-check.js → codex-lb-gpt56-fast-profile-check.js} +56 -5
  173. package/dist/scripts/codex-model-metadata-check.js +1 -1
  174. package/dist/scripts/codex-sdk-sandbox-policy-check.js +5 -1
  175. package/dist/scripts/codex-sdk-version-compat-check.js +2 -1
  176. package/dist/scripts/dfix-fixture-check.js +1 -1
  177. package/dist/scripts/docs-truthfulness-check.js +1 -1
  178. package/dist/scripts/doctor-codex-startup-repair-check.js +35 -10
  179. package/dist/scripts/doctor-context7-repair-check.js +2 -1
  180. package/dist/scripts/doctor-fix-proves-codex-read-check.js +1 -1
  181. package/dist/scripts/doctor-fixes-codex-app-fast-ui-check.js +34 -7
  182. package/dist/scripts/doctor-imagegen-repair-check.js +14 -4
  183. package/dist/scripts/doctor-startup-config-repair-blackbox.js +1 -1
  184. package/dist/scripts/doctor-startup-config-repair-check.js +1 -1
  185. package/dist/scripts/gate-policy-audit-check.js +2 -2
  186. package/dist/scripts/install-update-preserves-config-check.js +1 -1
  187. package/dist/scripts/legacy-gate-inventory-check.js +7 -5
  188. package/dist/scripts/legacy-strong-inventory-check.js +7 -5
  189. package/dist/scripts/legacy-upgrade-matrix-check.js +5 -5
  190. package/dist/scripts/lib/native-cli-session-swarm-check-lib.js +175 -14
  191. package/dist/scripts/mad-sks-app-ui-no-mutation-check.js +166 -6
  192. package/dist/scripts/mutation-callsite-coverage-check.js +0 -11
  193. package/dist/scripts/naruto-shadow-clone-swarm-check.js +88 -50
  194. package/dist/scripts/npm-publish-performance-check.js +2 -1
  195. package/dist/scripts/package-published-contract-check.js +9 -0
  196. package/dist/scripts/packlist-performance-check.js +5 -2
  197. package/dist/scripts/postinstall-safe-side-effects-check.js +8 -3
  198. package/dist/scripts/ppt-no-mock-as-real-check.js +3 -1
  199. package/dist/scripts/product-design-plugin-routing-check.js +1 -1
  200. package/dist/scripts/release-check-stamp.js +182 -2
  201. package/dist/scripts/release-dag-full-coverage-check.js +7 -7
  202. package/dist/scripts/release-dynamic-presets-check.js +8 -0
  203. package/dist/scripts/release-gate-dag-runner-check.js +3 -2
  204. package/dist/scripts/release-gate-dag-runner.js +24 -11
  205. package/dist/scripts/release-gate-existence-audit.js +8 -9
  206. package/dist/scripts/release-gate-script-parity-check.js +1 -1
  207. package/dist/scripts/release-real-check.js +368 -157
  208. package/dist/scripts/release-runtime-truth-matrix-check.js +22 -0
  209. package/dist/scripts/route-proof-artifact-structure-check.js +1 -0
  210. package/dist/scripts/scheduler-batch-dispatch-check.js +1 -1
  211. package/dist/scripts/search-visibility-gate-lib.js +1 -1
  212. package/dist/scripts/seo-geo-route-identity-check.js +30 -4
  213. package/dist/scripts/sizecheck.js +7 -2
  214. package/dist/scripts/sks-1-11-gate-lib.js +53 -6
  215. package/dist/scripts/sks-menubar-install-check.js +7 -0
  216. package/dist/scripts/sks-uninstall-regression-check.js +1 -1
  217. package/dist/scripts/sksd-daemon-check.js +16 -6
  218. package/dist/scripts/update-default-command-check.js +4 -2
  219. package/dist/scripts/write-build-manifest.js +2 -1
  220. package/dist/scripts/zellij-layout-valid-check.js +31 -6
  221. package/dist/scripts/zellij-pane-proof-check.js +33 -2
  222. package/dist/scripts/zellij-real-session-cleanup-check.js +122 -2
  223. package/dist/scripts/zellij-real-session-launch-check.js +76 -5
  224. package/dist/scripts/zellij-slot-pane-renderer-check.js +4 -4
  225. package/package.json +27 -30
  226. package/schemas/codex/{app-server-0.142 → app-server-0.144}/codex_app_server_protocol.v2.schemas.json +1146 -781
  227. package/schemas/codex/codex-0139-real-probe-result.schema.json +39 -5
  228. package/schemas/codex/ppt-slide-issue-ledger.schema.json +2 -1
  229. package/dist/core/codex-control/codex-0139-multi-agent-real-probe.js +0 -107
  230. package/dist/scripts/agent-native-release-gate.js +0 -274
  231. package/dist/scripts/codex-0142-capability-check.js +0 -21
  232. package/dist/scripts/command-performance-scorecard-check.js +0 -204
  233. package/dist/scripts/config-managed-merge-callsite-coverage-check.js +0 -212
  234. package/dist/scripts/dollar-performance-scorecard-check.js +0 -257
  235. package/dist/scripts/gate-timing-check.js +0 -16
  236. package/dist/scripts/ops-maturity-scorecard-check.js +0 -12
  237. package/dist/scripts/performance-baseline-check.js +0 -12
  238. package/dist/scripts/performance-improvement-report-check.js +0 -58
  239. package/dist/scripts/release-parallel-check.js +0 -389
  240. package/dist/scripts/release-runner-efficiency-check.js +0 -15
  241. package/dist/scripts/retention-long-run-smoke-check.js +0 -299
  242. package/docs/assets/sneakoscope-architecture-pipeline.jpg +0 -0
@@ -1,5 +1,6 @@
1
1
  import { codexModelEffortCapability } from '../codex-control/codex-model-capabilities.js';
2
2
  import { GLM_52_OPENROUTER_MODEL } from '../providers/glm/glm-52-settings.js';
3
+ import { isNarutoGpt56Model, routeNarutoGpt56Model } from '../provider/model-router.js';
3
4
  const XHIGH_SIGNAL_RE = /(frontier|autoresearch|novelty|hypothesis|falsif|forensic|from-chat-img|image\s*work\s*order|새로운\s*연구|가설|포렌식)/i;
4
5
  const HIGH_SIGNAL_RE = /(database|supabase|sql|migration|security|permission|mad|release|publish|deploy|architecture|policy|schema|hook|rollback|db|보안|배포|마이그레이션|데이터베이스|권한|릴리즈)/i;
5
6
  const MEDIUM_SIGNAL_RE = /(tmux|terminal|cli|tool(?:\s|-)?call|router|routing|orchestrat|pipeline|multi[-\s]?session|multi[-\s]?agent|lease|ledger|proof|검증|파이프라인|오케스트레이션|병렬|에이전트)/i;
@@ -60,52 +61,47 @@ export function decideAgentEffort(input = {}) {
60
61
  ]
61
62
  };
62
63
  }
63
- // Any action-tool signal (write/run/search/mcp/db/etc.) lifts a clone to medium.
64
- // Passive reading alone does not count "really simple" no-tool work stays at low.
65
- const NARUTO_ACTION_TOOL_RE = /(write|edit|create|modif|delete|remove|run\b|exec|command|bash|shell|script|install|build|test|migrat|patch|apply|fetch|curl|http|mcp|sql|database|\bdb\b|deploy|commit|push|rename|refactor|generate|scaffold|작성|수정|생성|삭제|실행|명령|빌드|테스트|설치|배포|패치|커밋|마이그레이션)/i;
66
- // $Naruto shadow-clone effort policy: dynamic like team mode, but capped.
67
- // - truly simple / no tool use -> low
68
- // - any tool use (one is enough) -> medium
69
- // - NEVER escalates to high/xhigh
70
- // - ALWAYS fast service tier
64
+ // $Naruto workers use the codex-lb GPT-5.6 family only. Model and effort are
65
+ // selected by the actual work kind; the removed low/medium cap must never be
66
+ // reintroduced through tool-count or read-only heuristics.
71
67
  export function decideNarutoCloneEffort(input = {}) {
72
68
  const persona = input.persona || {};
73
69
  const prompt = String(input.prompt || '');
74
70
  const role = String(persona.role || '');
75
71
  const agentId = String(input.agentId || persona.id || 'naruto_clone');
76
- const readonly = input.readonly === true || persona.read_only === true;
77
- const allowedTools = Array.isArray(persona.allowed_tools) ? persona.allowed_tools : [];
78
- const writePolicy = String(persona.write_policy || '');
79
- // Tool use is driven by (a) write capability, (b) the persona's actual action tools, or
80
- // (c) the work prompt itself — NOT by incidental persona prose (role/risk_focus), so a
81
- // read-only analysis clone on a no-tool prompt stays at low. Passive Read/Grep ≠ tool use.
82
- const hasActionTool = allowedTools.some((tool) => /write|edit|create|bash|shell|command|exec|run|mcp|patch|apply|multiedit|notebook/i.test(String(tool)));
83
- const writes = !readonly || /write|edit|route-local|workspace|patch|integrat/i.test(writePolicy) || hasActionTool;
84
- const toolUse = writes || NARUTO_ACTION_TOOL_RE.test(prompt);
85
- const effort = toolUse ? 'medium' : 'low';
86
- const modelDecision = decideAgentWorkerModel({ effort, prompt, role, agentId, readonly, writePolicy: String(writePolicy || '') });
87
- const modelCapability = codexModelEffortCapability({ model: modelDecision.model, defaultEffort: modelDecision.model_reasoning_effort });
72
+ const taskText = [role, agentId, persona.naruto_role].join(' ');
73
+ const riskText = [prompt, persona.risk_focus, persona.write_policy].join(' ');
74
+ const routed = routeNarutoGpt56Model({ taskText, riskText });
75
+ const effort = routed.reasoning;
76
+ const modelCapability = codexModelEffortCapability({
77
+ model: routed.model,
78
+ advertisedEfforts: narutoAdvertisedEfforts(routed.model),
79
+ defaultEffort: effort
80
+ });
88
81
  return {
89
82
  schema: 'sks.agent-effort-decision.v1',
90
83
  policy_version: 1,
91
84
  agent_id: agentId,
92
85
  role,
93
- model: modelDecision.model,
86
+ model: routed.model,
94
87
  reasoning_effort: effort,
95
- model_reasoning_effort: modelDecision.model_reasoning_effort,
96
- model_tier: modelDecision.model_tier,
97
- model_profile: modelDecision.model_profile,
98
- model_selection_reason: modelDecision.reason,
88
+ model_reasoning_effort: effort,
89
+ model_tier: `${routed.model}-${effort}`,
90
+ model_profile: `sks-naruto-${safeProfileSegment(routed.model)}-${effort}-fast`,
91
+ model_selection_reason: narutoSelectionReason(routed.model, effort),
99
92
  model_effort_capability: modelCapability,
100
93
  reasoning_profile: reasoningProfileName(effort),
101
94
  service_tier: 'fast',
102
- reason: toolUse ? 'naruto_tool_use_medium' : 'naruto_simple_no_tool_low',
95
+ reason: narutoSelectionReason(routed.model, effort),
103
96
  dynamic: true,
104
97
  escalation_triggers: [
105
- 'any tool use (write/edit/run/search/build/mcp/db) lifts the clone from low to medium'
98
+ 'complex or high-risk Terra work escalates from xhigh to max',
99
+ 'complex E2E, browser, Computer Use, or forensic Luna verification escalates from xhigh to max',
100
+ 'refactoring, architecture, planning, strategy, and integration select Sol at max'
106
101
  ],
107
102
  downshift_triggers: [
108
- 'truly simple, no-tool, read-only reasoning stays at low'
103
+ 'ordinary coding stays on Terra xhigh',
104
+ 'ordinary E2E, browser, Computer Use, and GUI verification stays on Luna xhigh'
109
105
  ]
110
106
  };
111
107
  }
@@ -124,21 +120,26 @@ export function buildAgentEffortPolicy(roster = {}) {
124
120
  reason: agent.reasoning_reason,
125
121
  dynamic: true
126
122
  })) : [];
123
+ const narutoFamilyOnly = decisions.length > 0 && decisions.every((decision) => isNarutoGpt56Model(decision.model));
127
124
  return {
128
125
  schema: 'sks.agent-effort-policy.v1',
129
126
  policy_version: 1,
130
127
  dynamic: true,
131
128
  service_tier: 'fast',
132
- model_catalog_policy: 'codex_catalog_passthrough',
133
- model_constraint: null,
134
- model_tiers: ['codex-selected-low', 'codex-selected-medium', 'codex-selected-high', 'codex-selected-xhigh', 'glm-5.2-minimal', 'glm-5.2-low', 'glm-5.2-high', 'glm-5.2-xhigh'],
135
- allowed_efforts: codexModelEffortCapability().advertised_efforts,
129
+ model_catalog_policy: narutoFamilyOnly ? 'naruto_gpt_5_6_family_dynamic' : 'codex_catalog_passthrough',
130
+ model_constraint: narutoFamilyOnly ? ['gpt-5.6-luna', 'gpt-5.6-terra', 'gpt-5.6-sol'] : null,
131
+ model_tiers: narutoFamilyOnly
132
+ ? ['gpt-5.6-luna-xhigh', 'gpt-5.6-luna-max', 'gpt-5.6-terra-xhigh', 'gpt-5.6-terra-max', 'gpt-5.6-sol-max']
133
+ : ['codex-selected-low', 'codex-selected-medium', 'codex-selected-high', 'codex-selected-xhigh', 'glm-5.2-minimal', 'glm-5.2-low', 'glm-5.2-high', 'glm-5.2-xhigh'],
134
+ allowed_efforts: narutoFamilyOnly ? ['xhigh', 'max'] : codexModelEffortCapability().advertised_efforts,
136
135
  model_effort_capability: codexModelEffortCapability(),
137
136
  max_agents: roster.max_agents || 20,
138
137
  agent_count: roster.agent_count || decisions.length,
139
138
  concurrency: roster.concurrency || decisions.length,
140
139
  decisions,
141
- rule: 'Codex/OpenAI workers inherit the current Codex-selected model, including future catalog entries; SKS changes only advertised reasoning effort. Explicit non-Codex provider modes retain their provider model.'
140
+ rule: narutoFamilyOnly
141
+ ? 'Naruto workers use only GPT-5.6 Luna/Terra/Sol: Terra xhigh/max for coding, Sol max for refactoring/planning/strategy/integration, and Luna xhigh/max for E2E/browser/Computer Use/GUI verification.'
142
+ : 'Codex/OpenAI workers inherit the current Codex-selected model, including future catalog entries; SKS changes only advertised reasoning effort. Explicit non-Codex provider modes retain their provider model.'
142
143
  };
143
144
  }
144
145
  export function reasoningProfileName(effort) {
@@ -164,6 +165,18 @@ function effortReason(effort) {
164
165
  return 'simple_bounded_slice';
165
166
  return 'default_orchestration_slice';
166
167
  }
168
+ function narutoAdvertisedEfforts(model) {
169
+ return model === 'gpt-5.6-luna'
170
+ ? ['low', 'medium', 'high', 'xhigh', 'max']
171
+ : ['low', 'medium', 'high', 'xhigh', 'max', 'ultra'];
172
+ }
173
+ function narutoSelectionReason(model, effort) {
174
+ if (model === 'gpt-5.6-sol')
175
+ return `naruto_refactor_plan_strategy_sol_${effort}`;
176
+ if (model === 'gpt-5.6-luna')
177
+ return `naruto_e2e_browser_computer_use_luna_${effort}`;
178
+ return `naruto_coding_terra_${effort}`;
179
+ }
167
180
  export function decideAgentWorkerModel(input = {}) {
168
181
  const mainModel = String(input.mainModel || process.env.SKS_CODEX_MODEL || process.env.CODEX_MODEL || '').trim();
169
182
  const glmMain = isGlmWorkerMode(mainModel);
@@ -2,6 +2,7 @@ import fsp from 'node:fs/promises';
2
2
  import path from 'node:path';
3
3
  import { exists, nowIso, readJson, writeJsonAtomic } from '../fsx.js';
4
4
  import { normalizeAgentSessionRows } from './agent-session-rows.js';
5
+ import { resolveOwnedNamespacePath } from './agent-namespace-safety.js';
5
6
  export async function runAgentJanitor(input) {
6
7
  const staleMs = input.staleMs ?? 30 * 60 * 1000;
7
8
  const agentRoot = path.join(input.missionDir, 'agents');
@@ -39,7 +40,7 @@ export async function runAgentJanitor(input) {
39
40
  const staleZellijSessions = rawStaleZellijSessions.filter((id) => !activeGenerationSet.has(id));
40
41
  const skippedActiveGenerations = rawStaleZellijSessions.filter((id) => activeGenerationSet.has(id));
41
42
  const orphanGenerationDirs = await detectOrphanGenerationDirs(agentRoot, new Set(generationRows.map((row) => String(row.artifact_dir || ''))));
42
- const orphanTempDirs = await scopedExistingPaths(Array.isArray(namespace?.orphan_temp_dirs) ? namespace.orphan_temp_dirs : [], projectHash);
43
+ const orphanTempDirs = await scopedExistingPaths(Array.isArray(namespace?.orphan_temp_dirs) ? namespace.orphan_temp_dirs : [], projectHash, namespace?.temp_dir ? [namespace.temp_dir] : []);
43
44
  const staleLocks = await scopedStaleLockPaths(namespace?.lock_dir ? [namespace.lock_dir] : [], projectHash, staleMs);
44
45
  const cleaned = [];
45
46
  if (input.cleanup) {
@@ -103,15 +104,12 @@ async function detectOrphanGenerationDirs(agentRoot, knownGenerationDirs) {
103
104
  export async function writeAgentJanitorReport(missionDir, report) {
104
105
  await writeJsonAtomic(path.join(missionDir, 'agents', 'agent-janitor-report.json'), report);
105
106
  }
106
- async function scopedExistingPaths(paths, projectHash) {
107
+ async function scopedExistingPaths(paths, projectHash, anchors = []) {
107
108
  const out = [];
108
109
  for (const candidate of paths) {
109
- if (!candidate)
110
- continue;
111
- if (projectHash && !candidate.includes(projectHash))
112
- continue;
113
- if (await exists(candidate))
114
- out.push(candidate);
110
+ const owned = await resolveOwnedNamespacePath(candidate, String(projectHash || ''), anchors);
111
+ if (owned)
112
+ out.push(owned);
115
113
  }
116
114
  return out;
117
115
  }
@@ -119,9 +117,10 @@ async function scopedStaleLockPaths(paths, projectHash, staleMs) {
119
117
  const out = [];
120
118
  const now = Date.now();
121
119
  for (const dir of paths) {
122
- if (!dir || (projectHash && !dir.includes(projectHash)) || !(await exists(dir)))
120
+ const ownedDir = await resolveOwnedNamespacePath(dir, String(projectHash || ''));
121
+ if (!ownedDir)
123
122
  continue;
124
- for (const file of await listFiles(dir)) {
123
+ for (const file of await listFiles(ownedDir)) {
125
124
  const stat = await fsp.stat(file).catch(() => null);
126
125
  if (stat && now - stat.mtimeMs > staleMs)
127
126
  out.push(file);
@@ -0,0 +1,56 @@
1
+ import fsp from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ export function validProjectNamespaceHash(value) {
4
+ return /^[A-Za-z0-9_-]{4,64}$/.test(String(value || ''));
5
+ }
6
+ export function processReportMatchesProjectNamespace(report, projectHash) {
7
+ if (!validProjectNamespaceHash(projectHash) || !report || typeof report !== 'object')
8
+ return false;
9
+ if (String(report.project_hash || '') === projectHash)
10
+ return true;
11
+ if (String(report.root_hash || '') === projectHash)
12
+ return true;
13
+ const namespace = String(report.project_namespace || '');
14
+ return namespace === projectHash || namespace === `sks-${projectHash}` || namespace.startsWith(`sks-${projectHash}-`);
15
+ }
16
+ export async function resolveOwnedNamespacePath(candidate, projectHash, anchors = []) {
17
+ if (!validProjectNamespaceHash(projectHash))
18
+ return null;
19
+ const raw = String(candidate || '');
20
+ if (!raw || !path.isAbsolute(raw) || raw.includes('\0') || raw.split(/[\\/]+/).includes('..'))
21
+ return null;
22
+ const resolved = path.resolve(raw);
23
+ const stat = await fsp.lstat(resolved).catch(() => null);
24
+ if (!stat || stat.isSymbolicLink())
25
+ return null;
26
+ const real = await fsp.realpath(resolved).catch(() => null);
27
+ if (!real)
28
+ return null;
29
+ const validAnchors = [];
30
+ for (const value of anchors) {
31
+ const anchorRaw = String(value || '');
32
+ if (!anchorRaw || !path.isAbsolute(anchorRaw) || anchorRaw.split(/[\\/]+/).includes('..'))
33
+ continue;
34
+ const anchorResolved = path.resolve(anchorRaw);
35
+ const anchorStat = await fsp.lstat(anchorResolved).catch(() => null);
36
+ if (!anchorStat?.isDirectory() || anchorStat.isSymbolicLink())
37
+ continue;
38
+ const anchorReal = await fsp.realpath(anchorResolved).catch(() => null);
39
+ if (anchorReal)
40
+ validAnchors.push({ resolved: anchorResolved, real: anchorReal });
41
+ }
42
+ if (validAnchors.length) {
43
+ return validAnchors.some((anchor) => isWithin(anchor.resolved, resolved) && isWithin(anchor.real, real)) ? resolved : null;
44
+ }
45
+ return pathContainsHashToken(resolved, projectHash) && pathContainsHashToken(real, projectHash) ? resolved : null;
46
+ }
47
+ function pathContainsHashToken(value, projectHash) {
48
+ const escaped = projectHash.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
49
+ const token = new RegExp(`(^|[-_.])${escaped}($|[-_.])`);
50
+ return path.resolve(value).split(path.sep).filter(Boolean).some((segment) => token.test(segment));
51
+ }
52
+ function isWithin(parent, candidate) {
53
+ const rel = path.relative(path.resolve(parent), path.resolve(candidate));
54
+ return rel === '' || (!rel.startsWith('..') && !path.isAbsolute(rel));
55
+ }
56
+ //# sourceMappingURL=agent-namespace-safety.js.map
@@ -53,6 +53,7 @@ import { writeNativeCliSessionProof } from './native-cli-session-proof.js';
53
53
  import { writeNoSubagentScalingPolicy } from './no-subagent-scaling-policy.js';
54
54
  import { writeOfficialSubagentHelperPolicy } from './official-subagent-helper-policy.js';
55
55
  import { runCodexTask } from '../codex-control/codex-control-plane.js';
56
+ import { codexTimeoutClassForRoute } from '../codex-control/codex-reliability-shield.js';
56
57
  import { CODEX_AGENT_WORKER_RESULT_SCHEMA_ID, codexAgentWorkerResultSchema } from '../codex-control/schemas/agent-worker-result.schema.js';
57
58
  import { resolveLocalCollaborationPolicy, localCollaborationParticipated } from '../local-llm/local-collaboration-policy.js';
58
59
  import { runFinalGptReviewStage } from '../pipeline/final-gpt-review-stage.js';
@@ -72,7 +73,7 @@ import { APPROACHES, rank, scoreCandidate, summarizeTournament } from '../naruto
72
73
  export async function runNativeAgentOrchestrator(opts = {}) {
73
74
  const root = path.resolve(opts.root || process.cwd());
74
75
  const sessionKey = opts.sessionKey || null;
75
- const prompt = String(opts.prompt || 'Native agent run');
76
+ const prompt = await resolveAgentMissionPrompt(root, opts);
76
77
  const route = opts.route || '$Agent';
77
78
  const routeCommand = String(opts.routeCommand || defaultRouteCommand(route));
78
79
  const routeBlackboxKind = String(opts.routeBlackboxKind || defaultRouteBlackboxKind(route));
@@ -412,7 +413,7 @@ export async function runNativeAgentOrchestrator(opts = {}) {
412
413
  generationIndex: agent.generation_index,
413
414
  requireGeneration: true
414
415
  });
415
- const backendOpts = { ...opts, missionId, agentRoot: ledgerRoot, cwd: workerWorktree?.context.path || root, projectRoot: root, route, prompt, fastMode: fastModePolicy.fast_mode, serviceTier: fastModePolicy.service_tier, ...(workerWorktree ? { worktree: workerWorktree.context } : {}) };
416
+ const backendOpts = { ...opts, missionId, agentRoot: ledgerRoot, cwd: workerWorktree?.context.path || root, projectRoot: root, projectHash: namespace.root_hash, route, prompt, fastMode: fastModePolicy.fast_mode, serviceTier: fastModePolicy.service_tier, ...(workerWorktree ? { worktree: workerWorktree.context } : {}) };
416
417
  const result = opts.nativeCliSwarm === false
417
418
  ? await runAgentByBackend(backend, runtimeAgent, runtimeSlice, backendOpts)
418
419
  : await nativeCliSwarm.launchWorker({ agent: runtimeAgent, slice: runtimeSlice, opts: backendOpts });
@@ -684,6 +685,27 @@ export async function runNativeAgentOrchestrator(opts = {}) {
684
685
  proof
685
686
  };
686
687
  }
688
+ export async function resolveAgentMissionPrompt(root, opts) {
689
+ const direct = String(opts.prompt || '').trim();
690
+ if (opts.promptExplicit === true || (direct && direct !== 'Native agent run'))
691
+ return direct || 'Native agent run';
692
+ const missionId = String(opts.missionId || '').trim();
693
+ if (!missionId)
694
+ return direct || 'Native agent run';
695
+ const dir = missionDir(root, missionId);
696
+ const [intake, routeContext, mission] = await Promise.all([
697
+ readJson(path.join(dir, 'request-intake.json'), null),
698
+ readJson(path.join(dir, 'route-context.json'), null),
699
+ readJson(path.join(dir, 'mission.json'), null)
700
+ ]);
701
+ return String(intake?.transformed_prompt
702
+ || routeContext?.transformed_prompt
703
+ || routeContext?.task
704
+ || routeContext?.prompt
705
+ || mission?.prompt
706
+ || direct
707
+ || 'Native agent run').trim();
708
+ }
687
709
  function normalizeMissionHardTimeoutMs(opts = {}, route = '') {
688
710
  const raw = Number(opts.hardTimeoutMs || opts.agentHardTimeoutMs || process.env.SKS_AGENT_HARD_TIMEOUT_MS || 0);
689
711
  if (Number.isFinite(raw) && raw > 0)
@@ -1905,7 +1927,7 @@ function buildProvidedAgentRoster(input, opts = {}) {
1905
1927
  writePolicy: String(entry.write_policy || '')
1906
1928
  });
1907
1929
  const suppliedModelEffort = String(entry.model_reasoning_effort || '');
1908
- const modelReasoningEffort = suppliedModelEffort === 'low' || suppliedModelEffort === 'high'
1930
+ const modelReasoningEffort = ['none', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max', 'ultra'].includes(suppliedModelEffort)
1909
1931
  ? suppliedModelEffort
1910
1932
  : modelDecision.model_reasoning_effort;
1911
1933
  return {
@@ -1989,7 +2011,7 @@ async function runAgentByBackend(backend, agent, slice, opts) {
1989
2011
  zellijPaneId: null,
1990
2012
  reliabilityPolicy: {
1991
2013
  maxEmptyResultRetries: writePaths.length ? 1 : 2,
1992
- timeoutClass: writePaths.length ? 'standard' : 'short'
2014
+ timeoutClass: codexTimeoutClassForRoute(opts.route, writePaths.length ? 'standard' : 'short')
1993
2015
  }
1994
2016
  });
1995
2017
  const sdkWorkerResult = await readJson(sdkTask.workerResultPath, null);
@@ -34,7 +34,7 @@ export const AGENT_RESULT_RUNTIME_SCHEMA = {
34
34
  task_slice_id: { type: 'string' },
35
35
  work_item_kind: { type: 'string' },
36
36
  status: { enum: ['done', 'blocked', 'failed'] },
37
- backend: { enum: ['fake', 'process', 'codex-sdk', 'python-codex-sdk', 'zellij', 'ollama', 'local-llm'] },
37
+ backend: { enum: ['fake', 'process', 'codex-sdk', 'python-codex-sdk', 'codex-exec', 'zellij', 'tmux', 'ollama', 'local-llm'] },
38
38
  summary: { type: 'string' },
39
39
  findings: { type: 'array', items: { type: 'string' } },
40
40
  proposed_changes: { type: 'array', items: { type: 'string' } },
@@ -321,7 +321,7 @@ export async function writeAgentProofEvidence(root, input) {
321
321
  patch_conflict_count: patchConflictCount,
322
322
  serial_bottleneck_count: serialBottleneckCount,
323
323
  changed_files_by_agent: changedFilesByAgent(patchApplyRows, patchEntries),
324
- lease_compliance_by_patch: leaseComplianceByPatch(patchEntries, input.partition?.leases || []),
324
+ lease_compliance_by_patch: leaseComplianceByPatch(patchEntries, input.partition?.leases || [], patchProof),
325
325
  rollback_digest_count: patchApplyRows.filter((row) => row.rollback_digest).length,
326
326
  real_parallel_claim: input.realParallel === true && input.backend === 'codex-sdk',
327
327
  fake_backend_disclaimer: input.backend === 'fake' ? 'fixture only; no real parallel execution claim' : null,
@@ -459,7 +459,21 @@ function changedFilesByAgent(applyRows, queueEntries) {
459
459
  }
460
460
  return out;
461
461
  }
462
- function leaseComplianceByPatch(queueEntries, leases) {
462
+ export function leaseComplianceByPatch(queueEntries, leases, patchProof) {
463
+ if (Array.isArray(patchProof?.lease_compliance_by_patch)) {
464
+ const entriesById = new Map(queueEntries.map((entry) => [String(entry.id), entry]));
465
+ return patchProof.lease_compliance_by_patch.map((row) => {
466
+ const patchEntryId = String(row.patch_entry_id || row.entry_id || '');
467
+ const entry = entriesById.get(patchEntryId);
468
+ return {
469
+ patch_entry_id: patchEntryId,
470
+ agent_id: entry?.envelope?.agent_id || row.agent_id || null,
471
+ lease_id: row.lease_id || null,
472
+ ok: row.ok === true,
473
+ write_paths: Array.isArray(row.write_paths) ? row.write_paths.map(String) : []
474
+ };
475
+ });
476
+ }
463
477
  return queueEntries.map((entry) => {
464
478
  const leaseId = entry.envelope?.lease_id || entry.envelope?.lease_proof?.lease_id || null;
465
479
  const agentId = entry.envelope?.agent_id || null;
@@ -32,7 +32,7 @@ export async function repairAgentRoleConfigs(input) {
32
32
  let managedCopyFound = false;
33
33
  for (const foundPath of foundPaths) {
34
34
  const text = fs.readFileSync(foundPath, 'utf8');
35
- if (isValidRoleConfig(text, role)) {
35
+ if (isValidRoleConfig(text, content)) {
36
36
  managedCopyFound = true;
37
37
  existing.push(path.relative(root, foundPath) || foundPath);
38
38
  continue;
@@ -78,10 +78,7 @@ export async function repairAgentRoleConfigs(input) {
78
78
  await writeJsonAtomic(input.reportPath, report);
79
79
  return report;
80
80
  }
81
- function isValidRoleConfig(text, role) {
82
- return managedAgentRoleOwnsText(text, role)
83
- && text.includes('description = "')
84
- && text.includes('developer_instructions = """')
85
- && !/^\s*(?:model|model_reasoning_effort)\s*=/m.test(text);
81
+ function isValidRoleConfig(text, expected) {
82
+ return text === expected;
86
83
  }
87
84
  //# sourceMappingURL=agent-role-config.js.map
@@ -151,8 +151,8 @@ export function buildNarutoCloneRoster(opts = {}) {
151
151
  const cloneReadonly = readonly || !writeAllowed;
152
152
  const role = mapNarutoRoleToAgentRole(narutoRole);
153
153
  const allowedTools = writeAllowed ? ['read', 'search', 'edit', 'test'] : narutoRole === 'verifier' ? ['read', 'search', 'test'] : ['read', 'search'];
154
- // Dynamic per-clone effort like team mode, capped at low/medium and always fast.
155
- const effort = decideNarutoCloneEffort({ persona: { ...base, role, allowed_tools: allowedTools, read_only: cloneReadonly, write_policy: writeAllowed ? 'exclusive Naruto patch-envelope lease required' : 'read-only Naruto role' }, prompt: opts.prompt || '', agentId: id, readonly: cloneReadonly });
154
+ // Dynamic Naruto-only GPT-5.6 model/effort policy; there is no legacy low/medium cap.
155
+ const effort = decideNarutoCloneEffort({ persona: { ...base, role, naruto_role: narutoRole, allowed_tools: allowedTools, read_only: cloneReadonly, write_policy: writeAllowed ? 'exclusive Naruto patch-envelope lease required' : 'read-only Naruto role' }, prompt: opts.prompt || '', agentId: id, readonly: cloneReadonly });
156
156
  const persona = {
157
157
  ...base,
158
158
  id,
@@ -44,6 +44,7 @@ export async function runCodexExecAgent(agent, slice, opts = {}) {
44
44
  const command = buildCodexExecAgentArgs(agent, opts.prompt || slice?.description || '', opts);
45
45
  const proxyEnv = managedProxyEnvForChild({ ...process.env, ...(opts.env || {}) });
46
46
  const report = await writeCodexProcessReport(opts.agentRoot || opts.cwd || process.cwd(), agent, {
47
+ project_hash: opts.projectHash || agent.project_hash || agent.root_hash || null,
47
48
  command: [opts.codexBin || 'codex', ...command.args],
48
49
  profile: opts.profile || null,
49
50
  result_file: command.resultFile,
@@ -74,6 +75,7 @@ export async function runCodexExecAgent(agent, slice, opts = {}) {
74
75
  const proxyEnv = managedProxyEnvForChild({ ...process.env, ...(opts.env || {}) });
75
76
  const result = await runProcess(opts.codexBin || 'codex', command.args, { cwd: opts.cwd || process.cwd(), env: { ...(opts.env || {}), ...proxyEnv, ...fastModeEnv(fastPolicy), ...workerEnv }, timeoutMs: opts.timeoutMs || 30 * 60 * 1000, maxOutputBytes: 256 * 1024, stdoutFile, stderrFile });
76
77
  const report = await writeCodexProcessReport(opts.agentRoot || opts.cwd || process.cwd(), agent, {
78
+ project_hash: opts.projectHash || agent.project_hash || agent.root_hash || null,
77
79
  command: [opts.codexBin || 'codex', ...command.args],
78
80
  profile: opts.profile || null,
79
81
  result_file: command.resultFile,
@@ -48,6 +48,7 @@ export async function runProcessAgent(agent, slice, opts = {}) {
48
48
  }
49
49
  const result = await runProcess(opts.command[0], opts.command.slice(1), { cwd: opts.cwd || process.cwd(), env: { ...(opts.env || {}), ...fastModeEnv(fastPolicy) }, timeoutMs: opts.timeoutMs || 30000, maxOutputBytes: 128 * 1024 });
50
50
  const report = await writeAgentProcessReport(opts.agentRoot || opts.cwd || process.cwd(), agent, 'process', {
51
+ project_hash: opts.projectHash || agent.project_hash || agent.root_hash || null,
51
52
  command: opts.command,
52
53
  service_tier: fastPolicy.service_tier,
53
54
  fast_mode: fastPolicy.fast_mode,
@@ -18,17 +18,15 @@ export function resolveFastModePolicy(input = {}) {
18
18
  ? 'standard'
19
19
  : preference?.mode === 'standard'
20
20
  ? 'standard'
21
- : explicitFast || explicitTier === 'fast' || preference?.mode === 'fast'
22
- ? 'fast'
23
- : 'standard';
21
+ : 'fast';
24
22
  return {
25
23
  schema: FAST_MODE_POLICY_SCHEMA,
26
24
  generated_at: nowIso(),
27
25
  fast_mode: serviceTier === 'fast',
28
26
  service_tier: serviceTier,
29
27
  codex_desktop_service_tier: codexDesktopServiceTier(serviceTier),
30
- default_fast_mode: false,
31
- disabled_by: explicitNoFast ? 'no-fast' : explicitTier === 'standard' ? 'service-tier-standard' : preference?.mode === 'standard' ? 'preference-standard' : serviceTier === 'standard' ? 'default-standard' : 'none',
28
+ default_fast_mode: true,
29
+ disabled_by: explicitNoFast ? 'no-fast' : explicitTier === 'standard' ? 'service-tier-standard' : preference?.mode === 'standard' ? 'preference-standard' : 'none',
32
30
  explicit_fast: explicitFast,
33
31
  explicit_no_fast: explicitNoFast,
34
32
  explicit_service_tier: explicitTier,
@@ -13,6 +13,7 @@ import { appendZellijSlotTelemetry } from '../zellij/zellij-slot-telemetry.js';
13
13
  import { appendParallelRuntimeEvent } from './parallel-runtime-proof.js';
14
14
  import { appendAgentMessage } from './agent-message-bus.js';
15
15
  import { markLoopWorkerInterrupted, registerLoopActiveWorker } from '../loops/loop-interrupt-registry.js';
16
+ import { readCodexLbModelCatalog } from '../codex-lb/codex-lb-env.js';
16
17
  export const NATIVE_CLI_SESSION_SWARM_SCHEMA = 'sks.agent-native-cli-session-swarm.v1';
17
18
  export function createNativeCliSessionSwarmRecorder(root, input) {
18
19
  return new NativeCliSessionSwarmRecorder(root, input);
@@ -26,11 +27,26 @@ class NativeCliSessionSwarmRecorder {
26
27
  writeLock = Promise.resolve();
27
28
  nextPaneToken = -1;
28
29
  visibleZellijReservations = new Set();
30
+ narutoModelCatalog = null;
29
31
  constructor(root, input) {
30
32
  this.root = root;
31
33
  this.input = input;
32
34
  }
33
35
  async initialize() {
36
+ if (/\$?naruto/i.test(this.input.route) && (this.input.backend === 'codex-sdk' || this.input.backend === 'zellij')) {
37
+ this.narutoModelCatalog = await readCodexLbModelCatalog().catch(() => ({
38
+ schema: 'sks.codex-lb-model-catalog.v1',
39
+ ok: false,
40
+ status: 'blocked',
41
+ models: [],
42
+ model_efforts: {},
43
+ blockers: ['codex_lb_model_catalog_unavailable']
44
+ }));
45
+ if (this.narutoModelCatalog?.ok !== true) {
46
+ const blockers = Array.isArray(this.narutoModelCatalog?.blockers) ? this.narutoModelCatalog.blockers.join(',') : 'unavailable';
47
+ throw new Error(`naruto_model_catalog_preflight_failed:${blockers}`);
48
+ }
49
+ }
34
50
  await this.persist();
35
51
  }
36
52
  async launchWorker(ctx) {
@@ -72,7 +88,8 @@ class NativeCliSessionSwarmRecorder {
72
88
  source_intelligence_refs: ctx.agent.source_intelligence_refs || null,
73
89
  goal_mode_ref: ctx.agent.goal_mode_ref || null,
74
90
  strategy_refs: ctx.slice?.strategy_refs || null,
75
- recursion_guard_env: true
91
+ recursion_guard_env: true,
92
+ naruto_model_catalog: this.narutoModelCatalog
76
93
  };
77
94
  await writeJsonAtomic(path.join(this.root, intakeRel), intake);
78
95
  const cliPath = await resolveWorkerCliPath();