sneakoscope 7.0.2 → 7.0.3

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 (468) hide show
  1. package/README.md +7 -5
  2. package/crates/sks-core/Cargo.lock +1 -1
  3. package/crates/sks-core/Cargo.toml +1 -1
  4. package/dist/bin/sks-dispatch.js +0 -3
  5. package/dist/cli/command-registry.js +0 -2
  6. package/dist/cli/install-helpers-codex-lb-chain.js +24 -2
  7. package/dist/cli/install-helpers-codex-lb-config.js +0 -7
  8. package/dist/cli/install-helpers-codex-lb-selftest-chain.js +0 -3
  9. package/dist/cli/install-helpers-codex-lb-selftest.js +0 -17
  10. package/dist/cli/install-helpers.js +81 -96
  11. package/dist/cli/router.js +0 -22
  12. package/dist/commands/codex-lb.js +176 -22
  13. package/dist/commands/codex.js +3 -8
  14. package/dist/commands/doctor.js +4 -14
  15. package/dist/commands/perf.js +5 -1
  16. package/dist/commands/zellij-slot-column-anchor.js +0 -2
  17. package/dist/commands/zellij-slot-pane.js +0 -7
  18. package/dist/commands/zellij.js +0 -2
  19. package/dist/config/skills-manifest.json +52 -52
  20. package/dist/core/agent-bridge/agent-manifest.js +192 -1
  21. package/dist/core/agent-bridge/agent-mode.js +0 -5
  22. package/dist/core/agent-bridge/host-capability-policy.js +189 -0
  23. package/dist/core/agent-bridge/host-capability-runtime.js +1395 -0
  24. package/dist/core/agent-bridge/mcp-server.js +1 -11
  25. package/dist/core/agents/agent-effort-policy.js +0 -3
  26. package/dist/core/agents/agent-orchestrator.js +0 -4
  27. package/dist/core/agents/agent-proof-evidence.js +0 -2
  28. package/dist/core/agents/agent-runner-ollama.js +0 -3
  29. package/dist/core/agents/agent-scheduler.js +0 -5
  30. package/dist/core/agents/native-cli-worker-runtime.js +5 -17
  31. package/dist/core/agents/work-partition/repo-inventory.js +0 -2
  32. package/dist/core/auto-review.js +0 -13
  33. package/dist/core/bench.js +0 -14
  34. package/dist/core/code-structure.js +0 -3
  35. package/dist/core/codex/agent-config-file-repair.js +0 -8
  36. package/dist/core/codex/codex-cli-update.js +122 -20
  37. package/dist/core/codex/codex-config-eperm-repair.js +0 -4
  38. package/dist/core/codex/codex-config-guard.js +0 -3
  39. package/dist/core/codex/codex-config-readability.js +0 -13
  40. package/dist/core/codex/codex-project-config-policy.js +0 -33
  41. package/dist/core/codex/official-goal-mode.js +0 -2
  42. package/dist/core/codex-app/codex-app-fast-ui-repair.js +5 -7
  43. package/dist/core/codex-app/codex-app-ui-state-snapshot.js +44 -7
  44. package/dist/core/codex-app/sks-menubar.js +0 -1
  45. package/dist/core/codex-app.js +0 -9
  46. package/dist/core/codex-compat/codex-hook-output-builders.js +9 -1
  47. package/dist/core/codex-compat/codex-hook-output-normalizer.js +1 -1
  48. package/dist/core/codex-compat/codex-hook-semantic-validator.js +3 -2
  49. package/dist/core/codex-compat/codex-hook-warning-detector.js +10 -2
  50. package/dist/core/codex-control/codex-lb-launch-recovery.js +0 -3
  51. package/dist/core/codex-control/codex-reliability-shield.js +0 -8
  52. package/dist/core/codex-control/codex-sdk-adapter.js +0 -3
  53. package/dist/core/codex-control/codex-sdk-config-policy.js +0 -2
  54. package/dist/core/codex-control/codex-sdk-env-policy.js +61 -16
  55. package/dist/core/codex-control/codex-task-runner.js +0 -7
  56. package/dist/core/codex-control/codex-thread-registry.js +0 -4
  57. package/dist/core/codex-lb/codex-lb-env.js +118 -20
  58. package/dist/core/codex-lb/codex-lb-tool-catalog.js +0 -4
  59. package/dist/core/codex-lb/codex-lb-tool-output-recovery.js +1 -1
  60. package/dist/core/codex-model-guard.js +0 -14
  61. package/dist/core/codex-native/codex-native-feature-broker.js +67 -22
  62. package/dist/core/codex-native/codex-native-interop-policy.js +81 -9
  63. package/dist/core/codex-native/confined-report-writer.js +21 -0
  64. package/dist/core/codex-native/core-skill-integrity.js +169 -20
  65. package/dist/core/codex-native/project-skill-dedupe.js +55 -13
  66. package/dist/core/codex-native/skill-registry-ledger.js +137 -16
  67. package/dist/core/codex-native/sks-skill-paths.js +185 -0
  68. package/dist/core/codex-runtime/codex-desktop-config-policy.js +0 -2
  69. package/dist/core/commands/agent-bridge-command.js +28 -8
  70. package/dist/core/commands/basic-cli.js +67 -26
  71. package/dist/core/commands/bench-command.js +5 -1
  72. package/dist/core/commands/command-utils.js +0 -5
  73. package/dist/core/commands/image-ux-review-command.js +0 -9
  74. package/dist/core/commands/mad-sks-command.js +0 -38
  75. package/dist/core/commands/naruto-command.js +46 -12
  76. package/dist/core/commands/ppt-command.js +0 -9
  77. package/dist/core/commands/run-command.js +8 -2
  78. package/dist/core/commands/seo-command.js +0 -6
  79. package/dist/core/commands/wiki-command.js +0 -14
  80. package/dist/core/computer-use-live-evidence.js +0 -5
  81. package/dist/core/config/secret-preservation.js +0 -11
  82. package/dist/core/daemon/sksd-hook-daemon-entrypoint.js +0 -2
  83. package/dist/core/daemon/sksd-hook-daemon.js +1 -29
  84. package/dist/core/daemon/sksd-hook-dispatch.js +0 -17
  85. package/dist/core/db-safety.js +0 -7
  86. package/dist/core/doctor/browser-use-repair.js +0 -2
  87. package/dist/core/doctor/doctor-codex-startup-repair.js +0 -3
  88. package/dist/core/doctor/doctor-readiness-matrix.js +12 -0
  89. package/dist/core/doctor/doctor-skill-reconcile.js +32 -0
  90. package/dist/core/doctor/imagegen-repair.js +0 -2
  91. package/dist/core/doctor/mcp-transport-collision-repair.js +0 -3
  92. package/dist/core/doctor/retired-managed-residue-private.js +0 -1
  93. package/dist/core/doctor/supabase-mcp-repair.js +0 -11
  94. package/dist/core/feature-fixture-executor.js +0 -48
  95. package/dist/core/feature-fixtures.js +0 -5
  96. package/dist/core/fsx.js +11 -12
  97. package/dist/core/hooks-runtime/code-pack-freshness-preflight.js +0 -5
  98. package/dist/core/hooks-runtime/hook-context.js +202 -0
  99. package/dist/core/hooks-runtime/hook-io.js +1 -12
  100. package/dist/core/hooks-runtime/light-turn.js +0 -2
  101. package/dist/core/hooks-runtime/naruto-decision-gate.js +4 -1
  102. package/dist/core/hooks-runtime/naruto-terminal-finalization.js +91 -0
  103. package/dist/core/hooks-runtime/official-subagent-lifecycle.js +370 -0
  104. package/dist/core/hooks-runtime/standalone-parent-host-capability.js +98 -0
  105. package/dist/core/hooks-runtime/subagent-context.js +59 -0
  106. package/dist/core/hooks-runtime/subagent-skill-availability-contract.js +29 -0
  107. package/dist/core/hooks-runtime/subagent-skill-availability-evidence.js +195 -0
  108. package/dist/core/hooks-runtime/subagent-skill-availability-guards.js +316 -0
  109. package/dist/core/hooks-runtime/subagent-skill-availability.js +217 -0
  110. package/dist/core/hooks-runtime.js +259 -535
  111. package/dist/core/image-ux-review/codex-app-generated-image-discovery.js +0 -17
  112. package/dist/core/image-ux-review/imagegen-adapter.js +0 -14
  113. package/dist/core/imagegen/imagegen-auth-readiness.js +0 -9
  114. package/dist/core/imagegen/imagegen-capability.js +0 -3
  115. package/dist/core/init/managed-skill-install.js +42 -0
  116. package/dist/core/init/skills.js +247 -74
  117. package/dist/core/init.js +15 -40
  118. package/dist/core/lean-engineering-policy.js +0 -2
  119. package/dist/core/locks/file-lock.js +0 -21
  120. package/dist/core/loops/loop-planner.js +0 -6
  121. package/dist/core/loops/loop-runtime.js +0 -1
  122. package/dist/core/loops/loop-worker-runtime.js +0 -19
  123. package/dist/core/mad-sks/executors/db-write-executor.js +0 -4
  124. package/dist/core/mad-sks/executors/executor-base.js +0 -10
  125. package/dist/core/mad-sks/immutable-harness-guard.js +0 -5
  126. package/dist/core/mad-sks/sql-plane/coordinator.js +0 -5
  127. package/dist/core/mad-sks/sql-plane/ledger.js +0 -4
  128. package/dist/core/mad-sks/sql-plane/lock.js +0 -4
  129. package/dist/core/mad-sks/sql-plane/mcp-executor.js +0 -9
  130. package/dist/core/mad-sks/sql-plane/policy-resolver.js +0 -2
  131. package/dist/core/mad-sks/sql-plane/postconditions.js +0 -4
  132. package/dist/core/mad-sks/sql-plane/recovery.js +0 -2
  133. package/dist/core/mad-sks/sql-plane/runtime-profile.js +0 -8
  134. package/dist/core/managed-assets/managed-assets-manifest.js +1 -7
  135. package/dist/core/mcp-config/health-check.js +10 -3
  136. package/dist/core/migration/migration-transaction-journal.js +0 -8
  137. package/dist/core/mission.js +0 -2
  138. package/dist/core/naruto/naruto-active-pool.js +0 -2
  139. package/dist/core/naruto/naruto-concurrency-governor.js +0 -1
  140. package/dist/core/naruto/naruto-real-write-proof.js +0 -4
  141. package/dist/core/naruto/naruto-write-e2e.js +0 -1
  142. package/dist/core/perf/perf-budget.js +0 -5
  143. package/dist/core/permission-gates.js +0 -2
  144. package/dist/core/pipeline-internals/runtime-core.js +15 -5
  145. package/dist/core/pipeline-internals/runtime-gates.js +0 -12
  146. package/dist/core/preflight/parallel-preflight-engine.js +0 -11
  147. package/dist/core/proof/evidence-collector.js +0 -2
  148. package/dist/core/proof/route-finalizer.js +0 -1
  149. package/dist/core/proof/selftest-proof-fixtures.js +0 -5
  150. package/dist/core/providers/glm/bench/glm-benchmark-runner.js +0 -2
  151. package/dist/core/providers/glm/glm-request-cache.js +0 -3
  152. package/dist/core/providers/glm/naruto/glm-naruto-command.js +0 -1
  153. package/dist/core/providers/glm/naruto/glm-naruto-decomposer.js +0 -1
  154. package/dist/core/providers/glm/naruto/glm-naruto-orchestrator.js +0 -6
  155. package/dist/core/providers/glm/naruto/glm-naruto-trace.js +0 -1
  156. package/dist/core/providers/glm/naruto/glm-naruto-worker-pool.js +0 -1
  157. package/dist/core/providers/glm/naruto/glm-naruto-worktree.js +0 -1
  158. package/dist/core/providers/openrouter/openrouter-secret-store.js +0 -1
  159. package/dist/core/providers/openrouter/openrouter-stream.js +0 -2
  160. package/dist/core/questions.js +3 -3
  161. package/dist/core/release/gate-manifest.js +0 -5
  162. package/dist/core/release/package-size-budget.js +1 -1
  163. package/dist/core/release/release-gate-batch-runner.js +11 -2
  164. package/dist/core/release/release-gate-cache-v2.js +0 -4
  165. package/dist/core/release/release-gate-hermetic-env.js +0 -5
  166. package/dist/core/release-parallel-full-coverage.js +0 -2
  167. package/dist/core/remote/ssh-worker-client.js +0 -3
  168. package/dist/core/research/research-adversarial-review.js +6 -2
  169. package/dist/core/responses-retry-policy.js +0 -10
  170. package/dist/core/retention.js +0 -7
  171. package/dist/core/routes/constants.js +0 -3
  172. package/dist/core/routes.js +89 -15
  173. package/dist/core/safety/command-contract/contracts.js +2 -0
  174. package/dist/core/safety/mutation-guard.js +0 -25
  175. package/dist/core/safety/mutation-ledger.js +0 -9
  176. package/dist/core/safety/requested-scope-contract.js +0 -0
  177. package/dist/core/security/high-risk-contracts.js +0 -1
  178. package/dist/core/skills/core-skill-card.js +0 -0
  179. package/dist/core/skills/core-skill-deployment.js +0 -13
  180. package/dist/core/skills/core-skill-epoch.js +0 -11
  181. package/dist/core/skills/core-skill-meta-update.js +0 -6
  182. package/dist/core/skills/core-skill-patch-apply.js +0 -7
  183. package/dist/core/skills/core-skill-patch.js +0 -8
  184. package/dist/core/skills/core-skill-reflection.js +0 -16
  185. package/dist/core/skills/core-skill-runtime.js +0 -6
  186. package/dist/core/skills/core-skill-scorer.js +0 -7
  187. package/dist/core/skills/core-skill-trainer.js +0 -11
  188. package/dist/core/skills/core-skill-types.js +0 -9
  189. package/dist/core/skills/core-skill-validation.js +0 -5
  190. package/dist/core/skills/rejected-skill-patch-buffer.js +0 -2
  191. package/dist/core/stop-gate/stop-gate-check.js +0 -8
  192. package/dist/core/stop-gate/stop-gate-resolver.js +0 -7
  193. package/dist/core/stop-gate/stop-gate-writer.js +0 -5
  194. package/dist/core/subagents/model-policy.js +0 -7
  195. package/dist/core/subagents/naruto-help-contract.js +1 -1
  196. package/dist/core/subagents/naruto-proof-projection.js +580 -12
  197. package/dist/core/subagents/official-subagent-config.js +0 -8
  198. package/dist/core/subagents/official-subagent-preparation.js +6 -5
  199. package/dist/core/subagents/official-subagent-prompt.js +29 -0
  200. package/dist/core/subagents/official-subagent-runner.js +343 -37
  201. package/dist/core/subagents/subagent-evidence.js +378 -9
  202. package/dist/core/subagents/thread-budget.js +5 -2
  203. package/dist/core/subagents/triwiki-attention.js +0 -4
  204. package/dist/core/subagents/wave-parent-guidance.js +54 -9
  205. package/dist/core/telegram/runtime.js +0 -1
  206. package/dist/core/triwiki/code-index-scanner.js +0 -3
  207. package/dist/core/triwiki/code-pack-head-freshness.js +0 -10
  208. package/dist/core/triwiki/code-pack.js +0 -2
  209. package/dist/core/triwiki/triwiki-cache-key.js +0 -1
  210. package/dist/core/triwiki/triwiki-proof-bank.js +0 -1
  211. package/dist/core/triwiki-attention.js +0 -10
  212. package/dist/core/triwiki-provenance.js +0 -5
  213. package/dist/core/triwiki-runtime.js +0 -12
  214. package/dist/core/triwiki-wrongness/wrongness-ledger.js +0 -7
  215. package/dist/core/triwiki-wrongness/wrongness-schema.js +0 -3
  216. package/dist/core/trust-kernel/trust-report.js +0 -7
  217. package/dist/core/update/update-migration-state.js +21 -39
  218. package/dist/core/update-check.js +2 -14
  219. package/dist/core/version-manager.js +2 -0
  220. package/dist/core/version.js +1 -1
  221. package/dist/core/work-order-ledger.js +0 -17
  222. package/dist/core/zellij/zellij-clipboard-config.js +0 -18
  223. package/dist/core/zellij/zellij-lane-renderer.js +5 -46
  224. package/dist/core/zellij/zellij-lane-runtime.js +0 -1
  225. package/dist/core/zellij/zellij-launcher.js +0 -26
  226. package/dist/core/zellij/zellij-official-subagent-activity.js +0 -5
  227. package/dist/core/zellij/zellij-official-subagent-telemetry.js +0 -5
  228. package/dist/core/zellij/zellij-screen-proof.js +0 -7
  229. package/dist/core/zellij/zellij-slot-column-anchor.js +0 -1
  230. package/dist/core/zellij/zellij-slot-pane-renderer.js +0 -9
  231. package/dist/core/zellij/zellij-slot-telemetry.js +0 -12
  232. package/dist/core/zellij/zellij-ui-mode.js +0 -7
  233. package/dist/core/zellij/zellij-update.js +0 -29
  234. package/dist/core/zellij/zellij-worker-pane-manager.js +0 -39
  235. package/dist/native/sks-menubar/Sources/ProvidersViewController.swift +213 -27
  236. package/dist/native/sks-menubar/Sources/UpdatesViewController.swift +95 -12
  237. package/dist/scripts/agent-message-bus-reader-check.js +0 -1
  238. package/dist/scripts/all-feature-deep-completion-check.js +0 -1
  239. package/dist/scripts/appshots-thread-attachment-discovery-check.js +0 -1
  240. package/dist/scripts/architecture-guard-check.js +0 -1
  241. package/dist/scripts/build-dist.js +0 -1
  242. package/dist/scripts/build-once-runner-check.js +0 -1
  243. package/dist/scripts/canonical-test-runner.js +0 -2
  244. package/dist/scripts/certificate-sla-check.js +0 -1
  245. package/dist/scripts/changelog-check.js +0 -1
  246. package/dist/scripts/check-cli-entrypoint.js +0 -1
  247. package/dist/scripts/check-command-module-budget.js +0 -7
  248. package/dist/scripts/check-feature-quality.js +0 -1
  249. package/dist/scripts/check-legacy-free.js +0 -1
  250. package/dist/scripts/check-pipeline-runtime.js +0 -1
  251. package/dist/scripts/check-runtime-schemas.js +0 -1
  252. package/dist/scripts/codex-0-134-runner-truth-check.js +0 -1
  253. package/dist/scripts/codex-0-137-compat-check.js +0 -1
  254. package/dist/scripts/codex-0138-capability-artifact-check.js +0 -1
  255. package/dist/scripts/codex-0138-capability-check.js +0 -1
  256. package/dist/scripts/codex-0138-doctor-check.js +0 -1
  257. package/dist/scripts/codex-0138-feature-probes-check.js +0 -1
  258. package/dist/scripts/codex-0144-core-real-probes-check.js +0 -1
  259. package/dist/scripts/codex-app-handoff-check.js +0 -1
  260. package/dist/scripts/codex-app-handoff-launch-check.js +0 -1
  261. package/dist/scripts/codex-config-load-probe.js +0 -5
  262. package/dist/scripts/codex-control-all-pipelines-check.js +0 -1
  263. package/dist/scripts/codex-control-event-stream-ledger-check.js +0 -1
  264. package/dist/scripts/codex-control-tool-output-continuity-audit-check.js +0 -1
  265. package/dist/scripts/codex-permission-profiles-check.js +0 -1
  266. package/dist/scripts/codex-plugin-app-template-policy-check.js +0 -1
  267. package/dist/scripts/codex-project-config-policy-splitter-check.js +0 -1
  268. package/dist/scripts/codex-sdk-all-pipelines-check.js +0 -1
  269. package/dist/scripts/codex-sdk-backend-router-check.js +0 -1
  270. package/dist/scripts/codex-sdk-capability-check.js +0 -1
  271. package/dist/scripts/codex-sdk-event-stream-ledger-check.js +0 -1
  272. package/dist/scripts/codex-sdk-real-smoke-check.js +0 -1
  273. package/dist/scripts/concurrent-session-collision-check.js +9 -0
  274. package/dist/scripts/context7-evidence-dedupe-check.js +0 -1
  275. package/dist/scripts/core-skill-card-schema-check.js +0 -11
  276. package/dist/scripts/core-skill-deployment-snapshot-check.js +0 -10
  277. package/dist/scripts/core-skill-heldout-validation-check.js +0 -11
  278. package/dist/scripts/core-skill-no-inference-optimizer-check.js +0 -11
  279. package/dist/scripts/core-skill-patch-check.js +0 -11
  280. package/dist/scripts/core-skill-route-runtime-integration-check.js +0 -11
  281. package/dist/scripts/current-surface-update-e2e-check.js +0 -4
  282. package/dist/scripts/current-upgrade-matrix-check.js +0 -1
  283. package/dist/scripts/dfix-fixture-check.js +0 -1
  284. package/dist/scripts/dfix-patch-handoff-check.js +0 -1
  285. package/dist/scripts/dfix-verification-check.js +0 -1
  286. package/dist/scripts/dfix-verification-recommendation-check.js +0 -1
  287. package/dist/scripts/docs-truthfulness-check.js +3 -3
  288. package/dist/scripts/doctor-fastpath-check.js +0 -1
  289. package/dist/scripts/doctor-fix-proves-codex-read-check.js +0 -11
  290. package/dist/scripts/doctor-fixes-codex-app-fast-ui-check.js +0 -4
  291. package/dist/scripts/doctor-idempotence-check.js +0 -1
  292. package/dist/scripts/doctor-ops-semantics-check.js +0 -1
  293. package/dist/scripts/ensure-bin-executable.js +0 -1
  294. package/dist/scripts/evidence-flagship-coverage-check.js +0 -1
  295. package/dist/scripts/fast-codex-service-tier-proof-check.js +0 -1
  296. package/dist/scripts/fixtures/fake-codex-config-loader.js +0 -5
  297. package/dist/scripts/fsx-hotpath-check.js +0 -1
  298. package/dist/scripts/gate-policy-audit-check.js +1 -1
  299. package/dist/scripts/geo-claim-evidence-check.js +0 -1
  300. package/dist/scripts/geo-cli-blackbox-check.js +0 -1
  301. package/dist/scripts/geo-crawler-policy-check.js +0 -1
  302. package/dist/scripts/git-worktree-diff-envelope-check.js +0 -1
  303. package/dist/scripts/git-worktree-dirty-lock-check.js +0 -1
  304. package/dist/scripts/git-worktree-dirty-main-detection-check.js +0 -1
  305. package/dist/scripts/git-worktree-integration-primary-check.js +0 -1
  306. package/dist/scripts/git-worktree-manifest-append-check.js +0 -1
  307. package/dist/scripts/git-worktree-untracked-diff-check.js +0 -1
  308. package/dist/scripts/high-risk-contracts-check.js +0 -1
  309. package/dist/scripts/hook-latency-budget-check.js +0 -1
  310. package/dist/scripts/hook-latency-quantum-check.js +0 -1
  311. package/dist/scripts/image-artifact-path-contract-check.js +0 -1
  312. package/dist/scripts/imagegen-real-smoke-check.js +0 -1
  313. package/dist/scripts/import-graph-budget-check.js +0 -1
  314. package/dist/scripts/installed-package-smoke-check.js +0 -1
  315. package/dist/scripts/legacy-gate-purge-check.js +0 -1
  316. package/dist/scripts/lib/codex-sdk-gate-lib.js +0 -3
  317. package/dist/scripts/lib/ensure-dist-fresh.js +0 -1
  318. package/dist/scripts/lib/valid-png-fixture.js +0 -1
  319. package/dist/scripts/local-collab-all-pipelines-final-gpt-check.js +0 -1
  320. package/dist/scripts/loop-directive-check-lib.js +0 -1
  321. package/dist/scripts/loop-worker-fixture-child.js +0 -1
  322. package/dist/scripts/mad-preflight-blocks-unreadable-config-check.js +0 -10
  323. package/dist/scripts/mad-sks-sql-plane-lifecycle-hook-decision-check.js +0 -1
  324. package/dist/scripts/mad-sks-sql-plane-result-lifecycle-check.js +0 -1
  325. package/dist/scripts/mcp-plugin-inventory-check.js +0 -1
  326. package/dist/scripts/mcp-tool-naming-parity-check.js +0 -1
  327. package/dist/scripts/model-call-concurrency-check.js +0 -1
  328. package/dist/scripts/mutation-callsite-coverage-check.js +0 -5
  329. package/dist/scripts/naruto-codex-e2e-check.js +0 -1
  330. package/dist/scripts/naruto-worktree-coding-blackbox.js +0 -1
  331. package/dist/scripts/official-subagent-workflow-check.js +3 -1
  332. package/dist/scripts/ops-diagnostics-bundle-check.js +0 -1
  333. package/dist/scripts/packlist-performance-check.js +1 -3
  334. package/dist/scripts/perf-budget-check.js +0 -1
  335. package/dist/scripts/ppt-full-e2e-blackbox-check.js +0 -1
  336. package/dist/scripts/ppt-real-export-adapter-check.js +0 -1
  337. package/dist/scripts/ppt-real-imagegen-smoke-check.js +0 -1
  338. package/dist/scripts/ppt-real-imagegen-wiring-check.js +0 -1
  339. package/dist/scripts/ppt-reexport-rereview-check.js +0 -1
  340. package/dist/scripts/prepublish-fast-check.js +0 -23
  341. package/dist/scripts/prepublish-release-check-or-fast.js +0 -7
  342. package/dist/scripts/probe-memoization-check.js +0 -1
  343. package/dist/scripts/product-design-plugin-routing-check.js +0 -1
  344. package/dist/scripts/project-skill-dedupe-blackbox.js +36 -9
  345. package/dist/scripts/prompt-placeholder-guard-check.js +0 -1
  346. package/dist/scripts/python-codex-sdk-all-pipelines-check.js +0 -3
  347. package/dist/scripts/qa-loop-app-handoff-capability-check.js +0 -1
  348. package/dist/scripts/qa-loop-app-handoff-check.js +0 -1
  349. package/dist/scripts/qa-loop-app-handoff-cli-check.js +0 -1
  350. package/dist/scripts/qa-loop-app-handoff-confirmation-check.js +0 -1
  351. package/dist/scripts/qa-loop-app-handoff-gate-lifecycle-check.js +0 -1
  352. package/dist/scripts/qa-loop-app-handoff-launch-check.js +0 -1
  353. package/dist/scripts/qa-loop-app-handoff-status-lifecycle-check.js +0 -1
  354. package/dist/scripts/qa-loop-budget-policy-check.js +0 -1
  355. package/dist/scripts/qa-loop-effort-escalation-check.js +0 -1
  356. package/dist/scripts/qa-loop-image-path-exposure-check.js +0 -1
  357. package/dist/scripts/qa-loop-image-path-prompt-injection-check.js +0 -1
  358. package/dist/scripts/release-cache-glob-hashing-check.js +0 -1
  359. package/dist/scripts/release-cache-input-classifier-check.js +0 -1
  360. package/dist/scripts/release-cache-neutralization-report-check.js +0 -1
  361. package/dist/scripts/release-cache-version-neutral-fixture-check.js +0 -1
  362. package/dist/scripts/release-check-stamp.js +0 -4
  363. package/dist/scripts/release-dist-freshness-check.js +0 -1
  364. package/dist/scripts/release-full-parallelism-blackbox.js +3 -3
  365. package/dist/scripts/release-gate-batch-runner-check.js +22 -0
  366. package/dist/scripts/release-gate-budget-check.js +0 -6
  367. package/dist/scripts/release-gate-dag-runner-check.js +0 -1
  368. package/dist/scripts/release-latency-slo-check.js +0 -1
  369. package/dist/scripts/release-metadata-1-19-check.js +0 -1
  370. package/dist/scripts/release-metadata-check.js +0 -3
  371. package/dist/scripts/release-parallel-speed-budget-check.js +0 -5
  372. package/dist/scripts/release-proof-truth-check.js +0 -1
  373. package/dist/scripts/release-provenance-check.js +0 -1
  374. package/dist/scripts/release-real-check.js +0 -1
  375. package/dist/scripts/release-runtime-truth-matrix-check.js +0 -1
  376. package/dist/scripts/release-version-truth-check.js +0 -1
  377. package/dist/scripts/research-blueprint-densifier-check.js +0 -1
  378. package/dist/scripts/research-claim-builder-check.js +0 -1
  379. package/dist/scripts/research-complete-package-fixture-check.js +0 -1
  380. package/dist/scripts/research-final-reviewer-blackbox.js +0 -1
  381. package/dist/scripts/responses-retry-policy-centralized-check.js +0 -1
  382. package/dist/scripts/retention-apply-smoke-check.js +0 -1
  383. package/dist/scripts/retention-budget-check.js +0 -1
  384. package/dist/scripts/retention-dry-run-check.js +0 -1
  385. package/dist/scripts/rollback-recovery-smoke-check.js +0 -1
  386. package/dist/scripts/route-intent-regression-check.js +0 -1
  387. package/dist/scripts/runtime-current-terminal-check.js +0 -1
  388. package/dist/scripts/runtime-dist-parity-check.js +0 -1
  389. package/dist/scripts/runtime-no-src-mjs-check.js +0 -1
  390. package/dist/scripts/runtime-proof-summary-check.js +0 -1
  391. package/dist/scripts/runtime-ts-rust-boundary-check.js +0 -15
  392. package/dist/scripts/runtime-ts-source-of-truth-check.js +0 -1
  393. package/dist/scripts/scheduler-batch-dispatch-check.js +0 -1
  394. package/dist/scripts/scheduler-parallel-proof-consistency-check.js +0 -1
  395. package/dist/scripts/scheduler-utilization-integral-check.js +0 -1
  396. package/dist/scripts/search-visibility-gate-lib.js +0 -1
  397. package/dist/scripts/seo-audit-fixture-check.js +0 -1
  398. package/dist/scripts/seo-cli-blackbox-check.js +0 -1
  399. package/dist/scripts/seo-geo-geo-disambiguation-check.js +0 -1
  400. package/dist/scripts/seo-geo-route-identity-check.js +0 -1
  401. package/dist/scripts/seo-geo-skill-rich-content-check.js +0 -1
  402. package/dist/scripts/seo-marketing-truthfulness-check.js +0 -1
  403. package/dist/scripts/seo-metadata-sync-check.js +0 -1
  404. package/dist/scripts/seo-no-mutation-by-default-check.js +0 -1
  405. package/dist/scripts/shared-memory-fixture-check.js +0 -1
  406. package/dist/scripts/side-effect-runtime-report-check.js +0 -1
  407. package/dist/scripts/sizecheck.js +0 -1
  408. package/dist/scripts/sks-1-11-gate-lib.js +0 -1
  409. package/dist/scripts/sks-1-12-real-execution-check-lib.js +0 -1
  410. package/dist/scripts/sks-1-18-gate-lib.js +0 -1
  411. package/dist/scripts/sks-menubar-install-check.js +0 -3
  412. package/dist/scripts/sksd-daemon-check.js +0 -1
  413. package/dist/scripts/super-search-live-smoke-check.js +0 -1
  414. package/dist/scripts/super-search-local-http-smoke-check.js +0 -1
  415. package/dist/scripts/super-search-offline-contract-check.js +0 -1
  416. package/dist/scripts/super-search-provider-interface-check.js +0 -1
  417. package/dist/scripts/triwiki-cache-key-check.js +0 -1
  418. package/dist/scripts/triwiki-proof-bank-blackbox.js +0 -1
  419. package/dist/scripts/triwiki-proof-bank-check.js +0 -1
  420. package/dist/scripts/triwiki-proof-card-check.js +0 -1
  421. package/dist/scripts/trust-fixture-check.js +0 -1
  422. package/dist/scripts/ultra-router-auto-router-check.js +0 -1
  423. package/dist/scripts/update-fastpath-check.js +0 -1
  424. package/dist/scripts/upgrade-migration-matrix-check.js +0 -1
  425. package/dist/scripts/ux-review-extract-wires-real-extractor-check.js +0 -1
  426. package/dist/scripts/ux-review-imagegen-blackbox-check.js +0 -1
  427. package/dist/scripts/ux-review-patch-diff-recheck-check.js +0 -1
  428. package/dist/scripts/ux-review-real-imagegen-smoke-check.js +0 -1
  429. package/dist/scripts/ux-review-run-wires-imagegen-check.js +0 -1
  430. package/dist/scripts/write-build-manifest.js +0 -1
  431. package/dist/scripts/wrongness-fixture-check.js +0 -1
  432. package/dist/scripts/zellij-capability-check.js +0 -1
  433. package/dist/scripts/zellij-developer-controls-check.js +0 -1
  434. package/dist/scripts/zellij-doctor-readiness-check.js +0 -13
  435. package/dist/scripts/zellij-dynamic-pane-lifecycle-check.js +0 -1
  436. package/dist/scripts/zellij-fake-adapter-check.js +0 -1
  437. package/dist/scripts/zellij-initial-main-only-blackbox.js +0 -1
  438. package/dist/scripts/zellij-lane-renderer-check.js +0 -1
  439. package/dist/scripts/zellij-launch-command-truth-check.js +0 -12
  440. package/dist/scripts/zellij-layout-valid-check.js +0 -1
  441. package/dist/scripts/zellij-pane-creation-lock-metrics-check.js +0 -1
  442. package/dist/scripts/zellij-pane-lock-concurrency-blackbox.js +0 -1
  443. package/dist/scripts/zellij-pane-lock-does-not-block-worker-check.js +0 -1
  444. package/dist/scripts/zellij-pane-lock-open-worker-integration-blackbox.js +0 -1
  445. package/dist/scripts/zellij-pane-proof-check.js +0 -1
  446. package/dist/scripts/zellij-qa-app-handoff-status-check.js +0 -1
  447. package/dist/scripts/zellij-real-session-cleanup-check.js +0 -1
  448. package/dist/scripts/zellij-real-session-launch-check.js +0 -1
  449. package/dist/scripts/zellij-right-column-geometry-proof.js +0 -1
  450. package/dist/scripts/zellij-right-column-headless-overflow-check.js +0 -1
  451. package/dist/scripts/zellij-right-column-manager-check.js +0 -1
  452. package/dist/scripts/zellij-screen-proof-check.js +0 -1
  453. package/dist/scripts/zellij-slot-only-ui-check.js +0 -1
  454. package/dist/scripts/zellij-slot-pane-renderer-check.js +0 -1
  455. package/dist/scripts/zellij-slot-pane-stale-detection-check.js +0 -7
  456. package/dist/scripts/zellij-slot-telemetry-incremental-check.js +0 -1
  457. package/dist/scripts/zellij-slot-telemetry-live-flush-check.js +0 -1
  458. package/dist/scripts/zellij-slot-telemetry-performance-check.js +0 -1
  459. package/dist/scripts/zellij-stacked-capability-routing-check.js +0 -1
  460. package/dist/scripts/zellij-stacked-fallback-integration-blackbox.js +0 -1
  461. package/dist/scripts/zellij-stacked-version-matrix-check.js +0 -1
  462. package/dist/scripts/zellij-stacked-version-parser-check.js +0 -1
  463. package/dist/scripts/zellij-ui-design-check.js +0 -12
  464. package/dist/scripts/zellij-update-prompt-matrix-check.js +0 -1
  465. package/dist/scripts/zellij-update-prompt-mode-check.js +0 -1
  466. package/dist/scripts/zellij-update-prompt-safety-check.js +0 -1
  467. package/dist/scripts/zellij-worker-pane-real-ui-blackbox.js +0 -2
  468. package/package.json +1 -1
@@ -1,7 +1,7 @@
1
1
  import path from 'node:path';
2
- import { projectRoot, readJson, readText, writeJsonAtomic, appendJsonl, nowIso, runProcess, sha256, packageRoot, tmpdir } from './fsx.js';
2
+ import { projectRoot, readJson, writeJsonAtomic, appendJsonl, nowIso, runProcess, sha256, packageRoot, tmpdir } from './fsx.js';
3
3
  import { looksInteractiveCommand, interactiveCommandReason } from './no-question-guard.js';
4
- import { loadStateForSession, missionDir, setCurrent, updateCurrentIfMissionAndRun } from './mission.js';
4
+ import { loadStateForSession, missionDir, sessionStateKey, setCurrent, stateFileForSession } from './mission.js';
5
5
  import { checkDbOperation, dbBlockReason, handleMadSksUserConfirmation } from './db-safety.js';
6
6
  import { maybeRecordMadSksSqlPlaneToolResultFromToolUse } from './mad-sks/sql-plane/result-lifecycle.js';
7
7
  import { checkHarnessModification, harnessGuardBlockReason, isHarnessSourceProject } from './harness-guard.js';
@@ -10,46 +10,45 @@ import { classifyMadSksShellCommand } from './mad-sks/write-guard.js';
10
10
  import { activeRouteContext, evaluateStop, prepareRoute, promptPipelineContext as routePipelineContext, recordContext7Evidence, recordSubagentEvidence, routePrompt } from './pipeline.js';
11
11
  import { localizedFinalizationReason } from './language-preference.js';
12
12
  import { classifyToolError } from './evaluation.js';
13
- import { dollarCommand, routeRequiresSubagents, stripVisibleDecisionAnswerBlocks } from './routes.js';
13
+ import { dollarCommand, managedSkillNamesForPrompt, stripVisibleDecisionAnswerBlocks } from './routes.js';
14
14
  import { coreEngineeringDirectiveReferenceText } from './lean-engineering-policy.js';
15
15
  import { scanAgentTextForRecursion } from './agents/agent-recursion-guard.js';
16
16
  import { evaluateLoopContinuation } from './loops/loop-continuation-enforcer.js';
17
17
  import { diagnosticPromptAllowedDuringNoQuestions } from './routes/diagnostic-allowlist.js';
18
- import { closeWorkOrderLedgerForRouteResult } from './work-order-ledger.js';
19
- import { maybeFinalizeRoute } from './proof/auto-finalize.js';
20
- import { validateRouteCompletionProof } from './proof/route-proof-gate.js';
21
18
  import { maybeReconcileProjectSkillsPreflight } from './hooks-runtime/skill-reconcile-preflight.js';
22
19
  import { codePackFreshnessNote } from './hooks-runtime/code-pack-freshness-preflight.js';
23
20
  import { claimHookInvocation } from './hooks-runtime/hook-invocation-dedupe.js';
24
21
  import { armLightTurnStopBypass, clearLightTurnStopBypass, consumeLightTurnStopBypass, hasMatchingLightTurnStopBypass } from './hooks-runtime/light-turn.js';
25
22
  import { evaluateHookNarutoDecisionGate, looksLikeActiveContinuationPrompt } from './hooks-runtime/naruto-decision-gate.js';
23
+ import { ensureOfficialSubagentArtifactDirConfined, officialSubagentArtifactDir, recordAndRefreshSubagentEvidence, refreshOfficialSubagentCompletionArtifacts } from './hooks-runtime/official-subagent-lifecycle.js';
26
24
  import { finalizationRepeatDecision } from './hooks-runtime/stop-repeat-guard.js';
25
+ import { activeNarutoParentLaunchMissionId, claimStandaloneParentHostCapabilityRuntime } from './hooks-runtime/standalone-parent-host-capability.js';
27
26
  import { classifyTaskProfile } from './runtime/task-profile.js';
28
27
  import { resolveSubagentThreadBudget } from './subagents/thread-budget.js';
29
28
  import { readOfficialSubagentConfig } from './subagents/official-subagent-config.js';
30
29
  import { withFileLock } from './locks/file-lock.js';
31
- import { NARUTO_PARENT_EFFORT, NARUTO_PARENT_MODEL } from './subagents/model-policy.js';
32
- import { officialSubagentRolePlan } from './subagents/agent-catalog.js';
33
- import { recordOfficialSubagentParentOutcomesTelemetry, recordOfficialSubagentZellijTelemetry } from './zellij/zellij-official-subagent-telemetry.js';
34
- import { bindTrustworthySubagentParentSummaryToRun, normalizeSubagentEvent, normalizeSubagentParentSummary, persistOrReuseTrustworthySubagentParentSummary, readSubagentEvents, recordSubagentEvent, SUBAGENT_EVIDENCE_FILENAME, SUBAGENT_PARENT_SUMMARY_FILENAME, writeSubagentEvidence } from './subagents/subagent-evidence.js';
35
- import { officialSubagentPreparationInProgress, withOfficialSubagentLifecycleLock, writeNarutoGate } from './subagents/official-subagent-preparation.js';
36
- import { effectiveSubagentTarget, normalizeLegacySubagentCountFields, refreshSubagentWaveLifecycle, subagentCountContractBlockers } from './subagents/wave-lifecycle.js';
37
- import { buildWaveParentGuidance, renderWaveParentGuidance } from './subagents/wave-parent-guidance.js';
38
- import { managedOfficialSubagentRoleByName } from './managed-assets/managed-assets-manifest.js';
39
- import { SSOT_GUARD_ARTIFACT, validateSsotGuardArtifact } from './safety/ssot-guard.js';
30
+ import { buildBoundWaveParentGuidance, renderWaveParentGuidance } from './subagents/wave-parent-guidance.js';
31
+ import { renderAuthoritativeSksSkillContext, resolveAuthoritativeSksSkillSources } from './codex-native/sks-skill-paths.js';
32
+ import { authoritativeSksSkillResolutionBlockers, clearSubagentSkillAvailabilityGuards, persistSubagentSkillAvailabilityBlocker, renderSubagentSkillAvailabilityHandoff, subagentSkillAvailabilityPreToolBlockReason } from './hooks-runtime/subagent-skill-availability.js';
33
+ import { HOST_CAPABILITY_HOOK_EVIDENCE_FILENAME, HOST_CAPABILITY_HOOK_OBSERVATIONS_FILENAME, HOST_CAPABILITY_HOOK_RUNTIME_FILENAME, acasHostToolName, authorizeAndMergeHostCapabilityPreToolObservation, buildHostCapabilityEvidenceFromHookObservations, explicitlyDeniedHostCapabilityTool, mergeHostCapabilityPostToolObservation, requestHostCapabilities, resolveHostCapabilityHookRuntimeBinding, sanitizeHostCapabilityPostToolUse, sanitizeHostCapabilityPreToolUse } from './agent-bridge/host-capability-runtime.js';
40
34
  const LIGHT_ROUTE_STOP_ARTIFACT = 'light-route-stop.json';
41
35
  const CODEX_GIT_ACTION_STOP_ARTIFACT = 'codex-git-action-stop-bypass.json';
42
36
  const CODEX_GIT_ACTION_STOP_TTL_MS = 15 * 60 * 1000;
43
37
  const UPDATE_CHECK_HOOK_INVOCATION_POLICY = 'function-only:no-runSksUpdateCheck-call-in-hooks';
44
- // Update checks stay function-only in hooks: the policy marker above is checked
45
- // by release readiness so ordinary Codex hook flow cannot grow a hidden update
46
- // prompt path.
47
38
  import { loadHookPayload, normalizeHookResult, visibleHookMessage } from './hooks-runtime/hook-io.js';
48
- import { codexGitActionMetadataSignal, codexGitActionMetadataText, compactAnswerContext, conversationId, explicitConversationId, extractCommand, extractLastMessage, extractUserPrompt, hookTurnId, looksLikeCodexGitAction, looksLikeCodexGitActionStopCompletion, looksLikeCodexUiSettingsEvent, looksLikeMadSksConfirmationPrompt, observedParentModel, observedParentModelMismatch, toolFailed } from './hooks-runtime/payload-signals.js';
39
+ import { codexGitActionMetadataSignal, codexGitActionMetadataText, compactAnswerContext, conversationId, explicitConversationId, extractCommand, extractLastMessage, extractUserPrompt, hookTurnId, looksLikeCodexGitAction, looksLikeCodexGitActionStopCompletion, looksLikeCodexUiSettingsEvent, looksLikeMadSksConfirmationPrompt, observedParentModel, toolFailed } from './hooks-runtime/payload-signals.js';
49
40
  import { interruptedToolOutputRecoveryBlockReason, missingToolOutputCallId, missingToolOutputCallIdFromPayload, quarantineMissingToolOutput, readToolOutputQuarantine } from './hooks-runtime/tool-output-quarantine.js';
41
+ import { activeAuthoritativeSksSkillRefresh, activeGoalOverlayContext, attachAuthoritativeSksSkillContext, authoritativeSksSkillAdmission, hookActiveSkillContextRefresh, isBlockingClarificationAwaiting, looksLikeClarificationCancel, routeBypassesActiveContext, routeIsGitOnly, selectedSksSkillNamesForActiveState, shouldPrepareFreshRouteOnActivePrompt, standaloneParentManagedSkillNames } from './hooks-runtime/hook-context.js';
42
+ import { sealedSubagentRoutingContext, subagentRouteContext } from './hooks-runtime/subagent-context.js';
50
43
  export { loadHookPayload, normalizeHookResult };
44
+ export { refreshOfficialSubagentCompletionArtifacts };
51
45
  async function loadState(root, payload = {}) {
52
- return loadStateForSession(root, conversationId(payload));
46
+ const sessionKey = conversationId(payload);
47
+ if (!explicitConversationId(payload))
48
+ return loadStateForSession(root, sessionKey);
49
+ const hashed = sessionStateKey(sessionKey);
50
+ const sessionState = await readJson(stateFileForSession(root, sessionKey), null).catch(() => null);
51
+ return sessionState ? { ...sessionState, _session_key: sessionState._session_key || hashed } : {};
53
52
  }
54
53
  function isNoQuestionRunning(state) {
55
54
  return (state.mode === 'RESEARCH' && state.phase === 'RESEARCH_RUNNING_NO_QUESTIONS')
@@ -96,10 +95,6 @@ export async function evaluateHookPayload(name, payload = {}, opts = {}) {
96
95
  hook: name
97
96
  }).catch(() => null);
98
97
  }
99
- // Hook decisions use persisted session state. Codex hook payloads do not
100
- // define a trusted `state` field; accepting a partial/spoofed value can hide
101
- // an active mission or bypass route gates. Explicit opts.state remains for
102
- // internal replay and focused tests.
103
98
  const loadedState = opts.state || await loadState(root, payload);
104
99
  const state = { ...loadedState, _session_key: loadedState?._session_key || sessionKey };
105
100
  const noQuestion = isNoQuestionRunning(state);
@@ -114,7 +109,11 @@ export async function evaluateHookPayload(name, payload = {}, opts = {}) {
114
109
  });
115
110
  const withNarutoDecision = (result) => ({ ...result, sksNarutoDecision });
116
111
  if (name === 'user-prompt-submit') {
117
- return withNarutoDecision(await hookUserPrompt(root, state, payload, noQuestion, sessionKey));
112
+ const result = await hookUserPrompt(root, state, payload, noQuestion, sessionKey);
113
+ return withNarutoDecision(await attachAuthoritativeSksSkillContext(root, state, payload, result));
114
+ }
115
+ if (name === 'session-start' || name === 'pre-compact' || name === 'post-compact') {
116
+ return withNarutoDecision(await hookActiveSkillContextRefresh(root, state, name));
118
117
  }
119
118
  if (name === 'pre-tool')
120
119
  return withNarutoDecision(await hookPreTool(root, state, payload, noQuestion, sessionKey));
@@ -132,11 +131,18 @@ export async function evaluateHookPayload(name, payload = {}, opts = {}) {
132
131
  }
133
132
  async function hookSubagentStart(root, state, payload = {}, sessionKey = null) {
134
133
  const artifactDir = officialSubagentArtifactDir(root, state, sessionKey);
135
- await recordAndRefreshSubagentEvidence(root, artifactDir, state, payload, 'SubagentStart').catch(() => null);
134
+ const sessionArtifactDir = officialSubagentArtifactDir(root, {}, sessionKey);
135
+ const artifactDirBlockers = [];
136
+ const artifactDirSafe = await ensureOfficialSubagentArtifactDirConfined(root, artifactDir)
137
+ .then(() => true)
138
+ .catch(() => false);
139
+ if (!artifactDirSafe)
140
+ artifactDirBlockers.push('subagent_skill_availability_artifact_dir_unsafe');
141
+ await clearSubagentSkillAvailabilityGuards(root, payload, artifactDir).catch(() => null);
136
142
  const config = await readOfficialSubagentConfig(root);
137
143
  const budget = resolveSubagentThreadBudget({ configuredMaxThreads: config.maxThreads });
138
144
  const active = subagentRouteContext(state);
139
- const routingContext = await sealedSubagentRoutingContext(artifactDir, payload);
145
+ const routingContext = artifactDirSafe ? await sealedSubagentRoutingContext(artifactDir, payload) : '';
140
146
  const resourceGuard = [
141
147
  `SKS subagent policy: Codex [agents].max_threads is ${budget.maxThreads}.`,
142
148
  'Use max_depth=1. Subagents must not spawn subagents.',
@@ -144,180 +150,48 @@ async function hookSubagentStart(root, state, payload = {}, sessionKey = null) {
144
150
  'Parallel writes require disjoint paths; serialize overlapping paths.',
145
151
  'Finish only your assigned slice, return a concise result, then stop so the root parent can close this thread.'
146
152
  ].join(' ');
147
- const additionalContext = [coreEngineeringDirectiveReferenceText(), resourceGuard, routingContext, active].filter(Boolean).join('\n\n');
148
- return { continue: true, additionalContext };
149
- }
150
- async function sealedSubagentRoutingContext(artifactDir, payload = {}) {
151
- const plan = await readJson(path.join(artifactDir, 'subagent-plan.json'), null).catch(() => null);
152
- if (!plan || plan.workflow !== 'official_codex_subagent')
153
- return '';
154
- const agentName = extractSubagentAgentName(payload);
155
- const agents = plan.agents && typeof plan.agents === 'object' ? plan.agents : {};
156
- const planned = agentName && agents[agentName] ? agents[agentName] : null;
157
- const role = agentName ? managedOfficialSubagentRoleByName(agentName) : null;
158
- const model = String(planned?.routed_model || planned?.model || role?.model || '').trim();
159
- const effort = String(planned?.routed_model_reasoning_effort || planned?.model_reasoning_effort || role?.model_reasoning_effort || '').trim();
160
- if (!agentName && !model)
161
- return '';
162
- return [
163
- 'SKS sealed child routing:',
164
- agentName ? `- custom agent: ${agentName}` : null,
165
- model ? `- model: ${model}` : null,
166
- effort ? `- model_reasoning_effort: ${effort}` : null,
167
- '- keep this sealed profile; do not retarget model/effort or spawn nested agents'
168
- ].filter(Boolean).join('\n');
169
- }
170
- function extractSubagentAgentName(payload = {}) {
171
- const candidates = [
172
- payload.agent_type,
173
- payload.agentType,
174
- payload.subagent_type,
175
- payload.subagentType,
176
- payload.agent_name,
177
- payload.agentName,
178
- payload.agent,
179
- payload.role,
180
- payload.payload?.agent_type,
181
- payload.payload?.agentType,
182
- payload.payload?.subagent_type,
183
- payload.data?.agent_type,
184
- payload.input?.agent_type
153
+ const skillNames = selectedSksSkillNamesForActiveState(state);
154
+ const resolution = skillNames.length
155
+ ? await resolveAuthoritativeSksSkillSources({ root, skillNames }).catch(() => null)
156
+ : null;
157
+ const skillBlockers = [
158
+ ...artifactDirBlockers,
159
+ ...(skillNames.length ? authoritativeSksSkillResolutionBlockers(resolution) : [])
185
160
  ];
186
- for (const value of candidates) {
187
- const name = String(value || '').trim();
188
- if (name)
189
- return name;
161
+ try {
162
+ await persistSubagentSkillAvailabilityBlocker({
163
+ root,
164
+ artifactDir,
165
+ sessionArtifactDir,
166
+ state,
167
+ payload,
168
+ blockers: skillBlockers
169
+ });
190
170
  }
191
- return '';
192
- }
193
- function subagentRouteContext(state = {}) {
194
- if (!state?.route && !state?.mode)
195
- return '';
196
- const route = state.route_command || state.route || state.mode;
197
- const mission = state.mission_id ? ` for mission ${state.mission_id}` : '';
198
- const artifacts = state.mission_id
199
- ? ` Read only the route artifacts relevant to your assigned slice under .sneakoscope/missions/${state.mission_id}/.`
200
- : '';
201
- const databaseBoundary = String(state.mode || state.route || '').toUpperCase() === 'DB'
202
- ? ' Keep database inspection read-only unless the parent supplied a separately sealed mutation contract.'
203
- : '';
204
- return `You are a child thread on ${route}${mission}. Execute only the slice assigned by the parent.${artifacts} Do not spawn or delegate other agents, wait for sibling threads, integrate sibling results, close the parent route, or author the sks.subagent-parent-summary.v1 parent result. Return a concise slice result to the parent.${databaseBoundary}`;
171
+ catch (error) {
172
+ const blocker = error instanceof Error
173
+ && error.message === 'subagent_skill_availability_blocker_artifact_write_failed'
174
+ ? 'subagent_skill_availability_blocker_artifact_write_failed'
175
+ : 'subagent_skill_availability_guard_persistence_failed';
176
+ skillBlockers.push(blocker);
177
+ }
178
+ if (artifactDirSafe) {
179
+ await recordAndRefreshSubagentEvidence(root, state, payload, 'SubagentStart', sessionKey).catch(() => null);
180
+ }
181
+ const skillContext = skillBlockers.length
182
+ ? renderSubagentSkillAvailabilityHandoff(skillBlockers)
183
+ : resolution
184
+ ? renderAuthoritativeSksSkillContext(resolution)
185
+ : '';
186
+ const additionalContext = [coreEngineeringDirectiveReferenceText(), resourceGuard, routingContext, active, skillContext].filter(Boolean).join('\n\n');
187
+ return { continue: true, additionalContext, ...(skillBlockers.length ? { silent: true } : {}) };
205
188
  }
206
189
  async function hookSubagentStop(root, state, payload = {}, sessionKey = null) {
207
- const artifactDir = officialSubagentArtifactDir(root, state, sessionKey);
208
- await recordAndRefreshSubagentEvidence(root, artifactDir, state, payload, 'SubagentStop').catch(() => null);
209
- // SubagentStop is evidence collection only. It must never reuse the parent
210
- // Stop hook's route gate or block a child thread from returning its result.
190
+ await recordAndRefreshSubagentEvidence(root, state, payload, 'SubagentStop', sessionKey).catch(() => null);
191
+ await clearSubagentSkillAvailabilityGuards(root, payload, officialSubagentArtifactDir(root, state, sessionKey)).catch(() => null);
211
192
  return { continue: true, silent: true };
212
193
  }
213
- function officialSubagentArtifactDir(root, state = {}, sessionKey = null) {
214
- if (state?.mission_id)
215
- return missionDir(root, state.mission_id);
216
- return path.join(root, '.sneakoscope', 'state', 'subagents', sha256(String(sessionKey || 'default')).slice(0, 32));
217
- }
218
- async function recordAndRefreshSubagentEvidence(root, artifactDir, state, payload, eventName) {
219
- return withOfficialSubagentLifecycleLock(artifactDir, async () => {
220
- if (await officialSubagentPreparationInProgress(artifactDir))
221
- return null;
222
- const plan = await readJson(path.join(artifactDir, 'subagent-plan.json'), {});
223
- const workflowRunId = String(plan?.workflow_run_id || state?.official_subagent_run_id || '').trim();
224
- const stateRunId = String(state?.official_subagent_run_id || '').trim();
225
- if (!workflowRunId || (stateRunId && stateRunId !== workflowRunId))
226
- return null;
227
- const terminalGate = plan?.workflow === 'official_codex_subagent'
228
- ? await readJson(path.join(artifactDir, 'naruto-gate.json'), null).catch(() => null)
229
- : null;
230
- const terminalRunId = String(terminalGate?.workflow_run_id || '').trim();
231
- if (workflowRunId
232
- && terminalRunId === workflowRunId
233
- && terminalGate?.passed === true
234
- && terminalGate?.terminal === true) {
235
- return null;
236
- }
237
- const normalizedInputEvent = normalizeSubagentEvent(payload, eventName);
238
- const explicitRunId = normalizedInputEvent?.run_id || null;
239
- if (explicitRunId && explicitRunId !== workflowRunId)
240
- return null;
241
- let boundRunId = explicitRunId;
242
- if (!boundRunId && eventName === 'SubagentStop' && normalizedInputEvent?.thread_id) {
243
- const priorEvents = await readSubagentEvents(artifactDir);
244
- const matchingStartRuns = [...new Set(priorEvents
245
- .filter((row) => row.event_name === 'SubagentStart'
246
- && row.thread_id === normalizedInputEvent.thread_id
247
- && Boolean(row.run_id))
248
- .map((row) => row.run_id))];
249
- boundRunId = matchingStartRuns.length === 1
250
- ? matchingStartRuns[0] || null
251
- : null;
252
- if (!boundRunId)
253
- return null;
254
- }
255
- else if (!boundRunId) {
256
- boundRunId = workflowRunId || null;
257
- }
258
- const eventPayload = boundRunId && payload && typeof payload === 'object' && !Array.isArray(payload)
259
- ? { ...payload, workflow_run_id: boundRunId }
260
- : payload;
261
- const event = await recordSubagentEvent(artifactDir, eventPayload, eventName);
262
- if (!event)
263
- return null;
264
- const zellijTelemetry = await recordOfficialSubagentZellijTelemetry({
265
- root,
266
- routeMissionId: plan?.mission_id || state?.mission_id || null,
267
- event,
268
- payload: eventPayload,
269
- plan
270
- }).catch(async (error) => {
271
- await appendJsonl(path.join(artifactDir, 'zellij-telemetry-warnings.jsonl'), {
272
- ts: nowIso(),
273
- warning: 'official_subagent_zellij_telemetry_failed',
274
- event_name: eventName,
275
- thread_id: event.thread_id,
276
- error: String(error?.message || error)
277
- }).catch(() => null);
278
- return null;
279
- });
280
- if (zellijTelemetry?.blocker) {
281
- await appendJsonl(path.join(artifactDir, 'zellij-telemetry-warnings.jsonl'), {
282
- ts: nowIso(),
283
- warning: 'official_subagent_zellij_telemetry_incomplete',
284
- event_name: eventName,
285
- thread_id: event.thread_id,
286
- blocker: zellijTelemetry.blocker,
287
- failed_mission_ids: 'failed_mission_ids' in zellijTelemetry ? zellijTelemetry.failed_mission_ids : []
288
- }).catch(() => null);
289
- }
290
- const lifecycle = await refreshSubagentWaveLifecycle(artifactDir, { plan, event }).catch(() => null);
291
- const refreshedPlan = lifecycle ? { ...plan, wave_lifecycle: lifecycle } : plan;
292
- const existing = await readJson(path.join(artifactDir, SUBAGENT_EVIDENCE_FILENAME), {});
293
- const parentSummary = await readJson(path.join(artifactDir, SUBAGENT_PARENT_SUMMARY_FILENAME), null);
294
- const countTarget = effectiveSubagentTarget(refreshedPlan, lifecycle?.cumulative_started || 0);
295
- const requestedSubagents = countTarget.requestedSubagents
296
- || Number(state?.requested_subagents || existing?.requested_subagents || 0);
297
- if (!Number.isFinite(requestedSubagents) || requestedSubagents < 1)
298
- return event;
299
- const evidence = await writeSubagentEvidence(artifactDir, {
300
- requestedSubagents,
301
- countPolicy: countTarget.countPolicy,
302
- targetSubagents: countTarget.targetSubagents,
303
- parentSummary,
304
- parentSummaryPresent: parentSummary !== null,
305
- workflowStatus: 'running',
306
- preparationOnly: false,
307
- runId: workflowRunId || null,
308
- additionalBlockers: Array.isArray(plan?.config_blockers)
309
- ? [
310
- ...plan.config_blockers.map((item) => `official_subagent_config:${String(item)}`),
311
- ...subagentCountContractBlockers(refreshedPlan, lifecycle?.cumulative_started || 0)
312
- ]
313
- : subagentCountContractBlockers(refreshedPlan, lifecycle?.cumulative_started || 0)
314
- });
315
- return event;
316
- });
317
- }
318
194
  async function hookUserPrompt(root, state, payload, noQuestion, sessionKey = null) {
319
- // A receipt is scoped to exactly one submitted turn. Every later prompt,
320
- // including Codex App git/settings events, invalidates it before returning.
321
195
  await clearLightTurnStopBypass(root, { sessionKey }).catch(() => undefined);
322
196
  const submittedPrompt = stripVisibleDecisionAnswerBlocks(extractUserPrompt(payload));
323
197
  const explicitSession = explicitConversationId(payload);
@@ -346,6 +220,23 @@ async function hookUserPrompt(root, state, payload, noQuestion, sessionKey = nul
346
220
  }
347
221
  const parentLaunchMissionId = activeNarutoParentLaunchMissionId();
348
222
  if (parentLaunchMissionId) {
223
+ const parentSkillNames = await standaloneParentManagedSkillNames(root, parentLaunchMissionId, state);
224
+ const skillAdmission = await authoritativeSksSkillAdmission(root, parentSkillNames);
225
+ if (skillAdmission.blocked)
226
+ return skillAdmission.blocked;
227
+ const parentHostCapability = await claimStandaloneParentHostCapabilityRuntime({
228
+ root,
229
+ missionId: parentLaunchMissionId,
230
+ sessionScope: sessionKey,
231
+ explicitSession
232
+ });
233
+ if (parentHostCapability.blocker) {
234
+ return {
235
+ decision: 'block',
236
+ permissionDecision: 'deny',
237
+ reason: `SKS blocked the standalone Naruto parent before host tool execution: ${parentHostCapability.blocker}`
238
+ };
239
+ }
349
240
  const attachedState = {
350
241
  ...state,
351
242
  mission_id: parentLaunchMissionId,
@@ -353,8 +244,11 @@ async function hookUserPrompt(root, state, payload, noQuestion, sessionKey = nul
353
244
  route: 'Naruto',
354
245
  route_command: '$Naruto',
355
246
  route_closed: false,
247
+ required_skills: parentSkillNames,
356
248
  subagents_required: true,
357
- native_sessions_required: false
249
+ native_sessions_required: false,
250
+ official_subagent_run_id: parentHostCapability.workflowRunId || state?.official_subagent_run_id || null,
251
+ session_scope: sessionKey
358
252
  };
359
253
  await setCurrent(root, attachedState, { sessionKey, replace: true });
360
254
  const activeContext = await activeRouteContext(root, attachedState);
@@ -400,6 +294,9 @@ async function hookUserPrompt(root, state, payload, noQuestion, sessionKey = nul
400
294
  return { continue: true, silent: true, sksTaskProfile: taskProfile };
401
295
  }
402
296
  if (!explicitCommand && !clarificationPending && !madConfirmationPrompt && !activeContinuation && lightRoute?.id === 'Answer') {
297
+ const skillAdmission = await authoritativeSksSkillAdmission(root, lightRoute.requiredSkills || ['answer', 'honest-mode']);
298
+ if (skillAdmission.blocked)
299
+ return skillAdmission.blocked;
403
300
  const turnId = hookTurnId(payload);
404
301
  if (turnId) {
405
302
  await armLightTurnStopBypass(root, {
@@ -428,7 +325,6 @@ async function hookUserPrompt(root, state, payload, noQuestion, sessionKey = nul
428
325
  systemMessage: visibleHookMessage('user-prompt-submit', activeContext)
429
326
  };
430
327
  }
431
- await maybeReconcileProjectSkillsPreflight(root).catch(() => null);
432
328
  const updateContext = '';
433
329
  const command = dollarCommand(prompt);
434
330
  const route = routePrompt(prompt);
@@ -439,6 +335,10 @@ async function hookUserPrompt(root, state, payload, noQuestion, sessionKey = nul
439
335
  systemMessage: `SKS: ${route.command} git action bypassed pipeline route gates.`
440
336
  };
441
337
  }
338
+ const skillAdmission = await authoritativeSksSkillAdmission(root, managedSkillNamesForPrompt(route, prompt));
339
+ if (skillAdmission.blocked)
340
+ return skillAdmission.blocked;
341
+ await maybeReconcileProjectSkillsPreflight(root).catch(() => null);
442
342
  const bypassActiveRoute = routeBypassesActiveContext(route);
443
343
  const goalOverlay = activeGoalOverlayContext(state, route);
444
344
  const prepareFreshRoute = shouldPrepareFreshRouteOnActivePrompt(prompt, route, {
@@ -484,54 +384,28 @@ async function hookUserPrompt(root, state, payload, noQuestion, sessionKey = nul
484
384
  reason: 'SKS no-question/no-interruption mode is active. User prompt has been queued until the run completes.'
485
385
  };
486
386
  }
487
- function routeBypassesActiveContext(route = null) {
488
- return ['DFix', 'Answer', 'Commit', 'CommitAndPush', 'Wiki', 'ComputerUse'].includes(String(route?.id || ''));
489
- }
490
- function routeIsGitOnly(route = null) {
491
- return ['Commit', 'CommitAndPush'].includes(String(route?.id || ''));
492
- }
493
- function shouldPrepareFreshRouteOnActivePrompt(prompt, route = null, opts = {}) {
494
- if (!route || opts.command || opts.bypassActiveRoute || opts.goalOverlay)
495
- return false;
496
- if (looksLikeActiveContinuationPrompt(prompt))
497
- return false;
498
- return routeRequiresSubagents(route, prompt);
499
- }
500
- function isClarificationAwaiting(state = {}) {
501
- const phase = String(state.phase || '');
502
- const stopGate = String(state.stop_gate || '');
503
- const gateAwaiting = phase.includes('CLARIFICATION_AWAITING_ANSWERS') || stopGate === 'clarification-gate';
504
- if (!gateAwaiting)
505
- return false;
506
- if (!state?.mission_id)
507
- return false;
508
- if (state.ambiguity_gate_required !== true || state.ambiguity_gate_passed === true)
509
- return false;
510
- return Boolean(state.clarification_required || state.implementation_allowed === false);
511
- }
512
- function activeNarutoParentLaunchMissionId() {
513
- return process.env.SKS_NARUTO_PARENT_LAUNCH === '1'
514
- ? String(process.env.SKS_NARUTO_PARENT_MISSION_ID || '').trim()
515
- : '';
516
- }
517
- function isBlockingClarificationAwaiting(state = {}) {
518
- return isClarificationAwaiting(state);
519
- }
520
- function looksLikeClarificationCancel(prompt = '') {
521
- return /^(cancel|reset|restart|new mission|새로|취소|중단|리셋|다시 시작)\b/i.test(String(prompt || '').trim());
522
- }
523
- function activeGoalOverlayContext(state = {}, route = null) {
524
- if (state.mode !== 'GOAL' || !state.mission_id)
525
- return '';
526
- if (!route || route.id === 'Goal' || route.id === 'DFix' || route.id === 'Answer')
527
- return '';
528
- return [
529
- `Legacy SKS Goal state ${state.mission_id} is non-authoritative and must not be updated.`,
530
- `Do not let it hijack this new ${route.command || '$SKS'} prompt. The newly prepared route mission and gate are authoritative for this turn.`,
531
- 'Codex native Goal is the only persisted Goal owner; use native controls only when the user explicitly returns to Goal.'
532
- ].join('\n');
533
- }
534
387
  async function hookPreTool(root, state, payload, noQuestion, sessionKey = null) {
388
+ const skillAvailabilityBlock = await subagentSkillAvailabilityPreToolBlockReason(root, payload, officialSubagentArtifactDir(root, state, sessionKey), {
389
+ missionId: state?.mission_id,
390
+ workflowRunId: state?.official_subagent_run_id
391
+ }).catch((error) => {
392
+ const code = error instanceof Error && error.message === 'subagent_skill_availability_guard_invalid'
393
+ ? 'subagent_skill_availability_guard_invalid'
394
+ : 'subagent_skill_availability_guard_check_failed';
395
+ return `SKS blocked this child tool call because managed skill availability failed (${code}). Return the blocker to the root parent without using tools.`;
396
+ });
397
+ if (skillAvailabilityBlock) {
398
+ return { decision: 'block', permissionDecision: 'deny', reason: skillAvailabilityBlock };
399
+ }
400
+ const skillRefresh = await activeAuthoritativeSksSkillRefresh(root, state);
401
+ if (skillRefresh.blocked) {
402
+ return {
403
+ decision: 'block',
404
+ permissionDecision: 'deny',
405
+ reason: skillRefresh.blocked.reason,
406
+ systemMessage: skillRefresh.blocked.systemMessage
407
+ };
408
+ }
535
409
  if (needsMutationSafetyCheck(payload)) {
536
410
  const madSksImmutableDecision = await checkMadSksImmutableModification(root, state, payload);
537
411
  if (madSksImmutableDecision.action === 'block') {
@@ -555,12 +429,18 @@ async function hookPreTool(root, state, payload, noQuestion, sessionKey = null)
555
429
  return agentRecursionDecision;
556
430
  if (noQuestion && looksInteractiveCommand(command))
557
431
  return { decision: 'block', reason: interactiveCommandReason(command) };
432
+ const hostCapabilityDecision = await enforceHostCapabilityPreTool(root, state, payload, sessionKey);
433
+ if (hostCapabilityDecision && hostCapabilityDecision.continue !== true)
434
+ return hostCapabilityDecision;
558
435
  const waveGuidance = await parentWaveGuidanceContext(root, state, sessionKey).catch(() => '');
559
- if (waveGuidance) {
436
+ const additionalContext = [skillRefresh.context, waveGuidance].filter(Boolean).join('\n\n');
437
+ if (additionalContext) {
560
438
  return {
561
439
  continue: true,
562
- additionalContext: waveGuidance,
563
- systemMessage: visibleHookMessage('pre-tool', 'SKS Naruto wave lifecycle requires root-parent follow-up.')
440
+ additionalContext,
441
+ ...(waveGuidance
442
+ ? { systemMessage: visibleHookMessage('pre-tool', 'SKS Naruto wave lifecycle requires root-parent follow-up.') }
443
+ : { silent: true })
564
444
  };
565
445
  }
566
446
  return { continue: true };
@@ -573,15 +453,14 @@ async function parentWaveGuidanceContext(root, state = {}, sessionKey = null) {
573
453
  || state?.subagents_required === true;
574
454
  if (!isNaruto)
575
455
  return '';
576
- // Child worker hooks must not receive parent wave spawn instructions.
577
456
  if (agentWorkerHookContext(state, {}))
578
457
  return '';
579
458
  const artifactDir = officialSubagentArtifactDir(root, state, sessionKey);
580
459
  const plan = await readJson(path.join(artifactDir, 'subagent-plan.json'), null).catch(() => null);
581
- if (!plan || plan.workflow !== 'official_codex_subagent')
582
- return '';
583
- const lifecycle = plan.wave_lifecycle || null;
584
- const guidance = lifecycle?.parent_guidance || buildWaveParentGuidance(lifecycle);
460
+ const guidance = buildBoundWaveParentGuidance(plan, {
461
+ missionId: state?.mission_id,
462
+ workflowRunId: state?.official_subagent_run_id
463
+ });
585
464
  if (!guidance?.required)
586
465
  return '';
587
466
  return renderWaveParentGuidance(guidance);
@@ -615,6 +494,7 @@ function agentWorkerHookContext(state = {}, payload = {}) {
615
494
  async function hookPostTool(root, state, payload, noQuestion, sessionKey = null) {
616
495
  state = { ...state, _session_key: state?._session_key || sessionKey };
617
496
  await Promise.all([
497
+ recordHostCapabilityPostTool(root, state, payload, sessionKey).catch(() => null),
618
498
  recordMadSksSqlPlanePostToolLifecycle(root, state, payload).catch(() => null),
619
499
  recordContext7Evidence(root, state, payload).catch(() => null),
620
500
  recordSubagentEvidence(root, state, payload).catch(() => null),
@@ -630,6 +510,134 @@ async function hookPostTool(root, state, payload, noQuestion, sessionKey = null)
630
510
  }
631
511
  return { continue: true };
632
512
  }
513
+ async function enforceHostCapabilityPreTool(root, state = {}, payload = {}, sessionKey = null) {
514
+ const tool = acasHostToolName(payload.tool_name);
515
+ if (!tool)
516
+ return null;
517
+ if (explicitlyDeniedHostCapabilityTool(tool)) {
518
+ return {
519
+ decision: 'block',
520
+ permissionDecision: 'deny',
521
+ reason: `SKS denied acas-tools.${tool}; this tool is explicitly denied for model execution.`
522
+ };
523
+ }
524
+ const context = await loadHostCapabilityHookContext(root, state, payload, sessionKey);
525
+ if (!context) {
526
+ return {
527
+ decision: 'block',
528
+ permissionDecision: 'deny',
529
+ reason: 'SKS denied this acas-tools call because it has no valid task-scoped Naruto mission, run, and session context.'
530
+ };
531
+ }
532
+ if (!context.binding) {
533
+ return {
534
+ decision: 'block',
535
+ permissionDecision: 'deny',
536
+ reason: `SKS denied this acas-tools call because the current Naruto mission has no valid task-scoped host capability runtime: ${context.blocker}`
537
+ };
538
+ }
539
+ const observation = sanitizeHostCapabilityPreToolUse(context.binding.runtime, payload);
540
+ if (!observation) {
541
+ return {
542
+ decision: 'block',
543
+ permissionDecision: 'deny',
544
+ reason: 'SKS denied this acas-tools call because its official PreToolUse identity fields are invalid.'
545
+ };
546
+ }
547
+ let authorization = {
548
+ decision: observation.decision,
549
+ blocker: observation.blocker
550
+ };
551
+ try {
552
+ await withFileLock({
553
+ lockPath: path.join(context.dir, '.host-capability-hooks.lock'),
554
+ timeoutMs: 5_000,
555
+ staleMs: 60_000
556
+ }, async () => {
557
+ const current = await readJson(path.join(context.dir, HOST_CAPABILITY_HOOK_OBSERVATIONS_FILENAME), null).catch(() => null);
558
+ const result = authorizeAndMergeHostCapabilityPreToolObservation({
559
+ binding: context.binding,
560
+ current,
561
+ observation
562
+ });
563
+ authorization = result;
564
+ await writeJsonAtomic(path.join(context.dir, HOST_CAPABILITY_HOOK_OBSERVATIONS_FILENAME), result.observations);
565
+ });
566
+ }
567
+ catch {
568
+ return {
569
+ decision: 'block',
570
+ permissionDecision: 'deny',
571
+ reason: 'SKS denied this acas-tools call because its bounded PreToolUse evidence could not be persisted.'
572
+ };
573
+ }
574
+ if (authorization.decision === 'denied') {
575
+ return {
576
+ decision: 'block',
577
+ permissionDecision: 'deny',
578
+ reason: authorization.blocker
579
+ ? `SKS denied acas-tools.${observation.tool}; ${authorization.blocker}.`
580
+ : `SKS denied acas-tools.${observation.tool}; it is outside runtime.allowed_tool_names for this mission, run, and session.`
581
+ };
582
+ }
583
+ return { continue: true };
584
+ }
585
+ async function recordHostCapabilityPostTool(root, state = {}, payload = {}, sessionKey = null) {
586
+ if (!acasHostToolName(payload.tool_name))
587
+ return null;
588
+ const context = await loadHostCapabilityHookContext(root, state, payload, sessionKey);
589
+ if (!context?.binding)
590
+ return null;
591
+ const observation = sanitizeHostCapabilityPostToolUse(payload);
592
+ if (!observation)
593
+ return null;
594
+ return withFileLock({
595
+ lockPath: path.join(context.dir, '.host-capability-hooks.lock'),
596
+ timeoutMs: 5_000,
597
+ staleMs: 60_000
598
+ }, async () => {
599
+ const current = await readJson(path.join(context.dir, HOST_CAPABILITY_HOOK_OBSERVATIONS_FILENAME), null).catch(() => null);
600
+ const next = mergeHostCapabilityPostToolObservation({
601
+ binding: context.binding,
602
+ current,
603
+ observation
604
+ });
605
+ const evidence = buildHostCapabilityEvidenceFromHookObservations({
606
+ binding: context.binding,
607
+ observations: next
608
+ });
609
+ await Promise.all([
610
+ writeJsonAtomic(path.join(context.dir, HOST_CAPABILITY_HOOK_OBSERVATIONS_FILENAME), next),
611
+ writeJsonAtomic(path.join(context.dir, HOST_CAPABILITY_HOOK_EVIDENCE_FILENAME), evidence)
612
+ ]);
613
+ return evidence;
614
+ });
615
+ }
616
+ async function loadHostCapabilityHookContext(root, state = {}, payload = {}, sessionKey = null) {
617
+ const missionId = String(state?.mission_id || '').trim();
618
+ const workflowRunId = String(state?.official_subagent_run_id || '').trim();
619
+ const payloadSession = String(payload?.session_id || '').trim();
620
+ const expectedSession = String(state?.session_scope || sessionKey || '').trim();
621
+ const isNaruto = String(state?.mode || '').toUpperCase() === 'NARUTO'
622
+ || String(state?.route || state?.route_command || '').replace(/^\$/, '').toUpperCase() === 'NARUTO'
623
+ || state?.subagents_required === true;
624
+ if (!isNaruto || !missionId || !workflowRunId || !payloadSession || !expectedSession)
625
+ return null;
626
+ if (payloadSession !== expectedSession || (sessionKey && String(sessionKey) !== payloadSession))
627
+ return null;
628
+ const dir = missionDir(root, missionId);
629
+ const [raw, plan] = await Promise.all([
630
+ readJson(path.join(dir, HOST_CAPABILITY_HOOK_RUNTIME_FILENAME), null).catch(() => null),
631
+ readJson(path.join(dir, 'subagent-plan.json'), null).catch(() => null)
632
+ ]);
633
+ const request = requestHostCapabilities(plan?.goal || state?.prompt || '');
634
+ return { dir, ...resolveHostCapabilityHookRuntimeBinding(raw, {
635
+ missionId,
636
+ workflowRunId,
637
+ sessionScope: payloadSession,
638
+ request
639
+ }) };
640
+ }
633
641
  function needsMutationSafetyCheck(payload = {}) {
634
642
  const toolName = String(payload.tool_name || payload.toolName || payload.name || payload.tool?.name || '');
635
643
  const knownReadOnly = /^(Read|Grep|Glob|LS|TodoRead|WebFetch|WebSearch|BashOutput|NotebookRead|ListMcpResources|ReadMcpResource)$/i;
@@ -874,290 +882,6 @@ async function hookStop(root, state, payload, noQuestion, sessionKey = null) {
874
882
  reason: 'SKS no-question run is not done. Continue autonomously, fix failing checks, update the active gate file, and do not ask the user.'
875
883
  };
876
884
  }
877
- export async function refreshOfficialSubagentCompletionArtifacts(root, state = {}, parentSummary = '', sessionKey = null) {
878
- const id = state?.mission_id;
879
- if (!id)
880
- return null;
881
- const dir = missionDir(root, id);
882
- const snapshot = await withOfficialSubagentLifecycleLock(dir, () => refreshOfficialSubagentCompletionArtifactsLocked(root, state, parentSummary, sessionKey, dir));
883
- if (snapshot?.terminal?.passed === true) {
884
- await finalizeNarutoTerminalProof(root, state, sessionKey, dir, snapshot.terminal);
885
- }
886
- return snapshot?.evidence ?? snapshot;
887
- }
888
- async function refreshOfficialSubagentCompletionArtifactsLocked(root, state, parentSummary, sessionKey, dir) {
889
- if (await officialSubagentPreparationInProgress(dir))
890
- return null;
891
- const id = state?.mission_id;
892
- const plan = await readJson(path.join(dir, 'subagent-plan.json'), null).catch(() => null);
893
- if (plan?.workflow !== 'official_codex_subagent')
894
- return null;
895
- const workflowRunId = String(plan.workflow_run_id || state.official_subagent_run_id || '').trim();
896
- if (!workflowRunId || String(state.official_subagent_run_id || '').trim() !== workflowRunId)
897
- return null;
898
- const [existingGate, existingSummary, rawExistingEvidence, existingParentSummary] = await Promise.all([
899
- readJson(path.join(dir, 'naruto-gate.json'), null).catch(() => null),
900
- readJson(path.join(dir, 'naruto-summary.json'), null).catch(() => null),
901
- readJson(path.join(dir, SUBAGENT_EVIDENCE_FILENAME), null).catch(() => null),
902
- readJson(path.join(dir, SUBAGENT_PARENT_SUMMARY_FILENAME), null).catch(() => null)
903
- ]);
904
- const existingEvidence = normalizeLegacySubagentCountFields(rawExistingEvidence, plan);
905
- if (completeNarutoTerminalBundle({
906
- workflowRunId,
907
- gate: existingGate,
908
- summary: existingSummary,
909
- evidence: existingEvidence,
910
- parentSummary: existingParentSummary
911
- })) {
912
- return {
913
- evidence: existingEvidence,
914
- terminal: { passed: true, missionId: state.mission_id, workflowRunId, gate: existingGate }
915
- };
916
- }
917
- const events = await readSubagentEvents(dir);
918
- const lifecycle = await refreshSubagentWaveLifecycle(dir, { plan }).catch(() => plan.wave_lifecycle || null);
919
- const refreshedPlan = lifecycle ? { ...plan, wave_lifecycle: lifecycle } : plan;
920
- const countTarget = effectiveSubagentTarget(refreshedPlan, lifecycle?.cumulative_started || 0);
921
- const requestedSubagents = countTarget.requestedSubagents || Number(state.requested_subagents || 0);
922
- const runBoundParentSummary = bindTrustworthySubagentParentSummaryToRun(parentSummary, workflowRunId);
923
- const effectiveParentSummary = await persistOrReuseTrustworthySubagentParentSummary(dir, runBoundParentSummary, {
924
- workflowStatus: 'parent_completed',
925
- runId: workflowRunId || null
926
- });
927
- const structuredParentSummary = normalizeSubagentParentSummary(effectiveParentSummary);
928
- const evidence = await writeSubagentEvidence(dir, {
929
- requestedSubagents,
930
- countPolicy: countTarget.countPolicy,
931
- targetSubagents: countTarget.targetSubagents,
932
- events,
933
- parentSummary: effectiveParentSummary,
934
- workflowStatus: 'parent_completed',
935
- preparationOnly: false,
936
- runId: workflowRunId || null,
937
- additionalBlockers: Array.isArray(plan.config_blockers)
938
- ? [
939
- ...plan.config_blockers.map((item) => `official_subagent_config:${String(item)}`),
940
- ...subagentCountContractBlockers(refreshedPlan, lifecycle?.cumulative_started || 0)
941
- ]
942
- : subagentCountContractBlockers(refreshedPlan, lifecycle?.cumulative_started || 0)
943
- });
944
- if (structuredParentSummary.trustworthy) {
945
- const parentTelemetry = await recordOfficialSubagentParentOutcomesTelemetry({
946
- root,
947
- routeMissionId: id,
948
- parentSummary: structuredParentSummary.raw,
949
- plan: refreshedPlan
950
- }).catch(async (error) => {
951
- await appendJsonl(path.join(dir, 'zellij-telemetry-warnings.jsonl'), {
952
- ts: nowIso(),
953
- warning: 'official_subagent_parent_outcome_telemetry_failed',
954
- error: String(error?.message || error)
955
- }).catch(() => null);
956
- return null;
957
- });
958
- if (parentTelemetry?.blocker) {
959
- await appendJsonl(path.join(dir, 'zellij-telemetry-warnings.jsonl'), {
960
- ts: nowIso(),
961
- warning: 'official_subagent_parent_outcome_telemetry_incomplete',
962
- blocker: parentTelemetry.blocker,
963
- failed_mission_ids: 'failed_mission_ids' in parentTelemetry ? parentTelemetry.failed_mission_ids : [],
964
- skipped_thread_ids: 'skipped_thread_ids' in parentTelemetry ? parentTelemetry.skipped_thread_ids : []
965
- }).catch(() => null);
966
- }
967
- }
968
- const isNaruto = String(state?.mode || '').toUpperCase() === 'NARUTO'
969
- || String(state?.route || state?.route_command || '').replace(/^\$/, '').toUpperCase() === 'NARUTO';
970
- if (!isNaruto) {
971
- await updateCurrentIfMissionAndRun(root, id, workflowRunId, {
972
- subagents_spawned: evidence.started_threads > 0,
973
- subagents_reported: evidence.completed_threads > 0,
974
- subagents_verified: evidence.ok,
975
- subagent_evidence_file: SUBAGENT_EVIDENCE_FILENAME,
976
- parent_summary_present: evidence.parent_summary_present
977
- }, { sessionKey: sessionKey || state._session_key });
978
- return { evidence, terminal: null };
979
- }
980
- const previousGate = existingGate || {};
981
- const parentModel = plan.observed_parent_model || state.observed_parent_model || null;
982
- const parentModelMismatch = previousGate.parent_model_match === false || observedParentModelMismatch(parentModel, NARUTO_PARENT_MODEL);
983
- const blockers = [...new Set([
984
- ...evidence.blockers,
985
- ...(Array.isArray(previousGate.config_blockers) ? previousGate.config_blockers.map(String) : []),
986
- ...(Array.isArray(plan.config_blockers) ? plan.config_blockers.map((item) => `official_subagent_config:${String(item)}`) : []),
987
- ...(parentModelMismatch ? [`parent_model_mismatch:${String(parentModel || 'unknown')}`] : [])
988
- ])];
989
- const ssotValidation = validateSsotGuardArtifact(await readJson(path.join(dir, SSOT_GUARD_ARTIFACT), null).catch(() => null));
990
- blockers.push(...ssotValidation.issues.map((issue) => `${SSOT_GUARD_ARTIFACT}:${issue}`));
991
- const uniqueBlockers = [...new Set(blockers)];
992
- const passed = evidence.ok === true && ssotValidation.ok && uniqueBlockers.length === 0;
993
- const updatedAt = nowIso();
994
- const summary = {
995
- schema: 'sks.naruto-subagent-workflow.v1',
996
- ok: passed,
997
- completion_evidence: passed,
998
- workflow: 'official_codex_subagent',
999
- workflow_run_id: workflowRunId || null,
1000
- mission_id: id,
1001
- route: '$Naruto',
1002
- status: passed ? 'completed' : evidence.status,
1003
- parent: {
1004
- model: NARUTO_PARENT_MODEL,
1005
- model_reasoning_effort: NARUTO_PARENT_EFFORT,
1006
- observed_model: parentModel,
1007
- observed_model_match: parentModel ? !parentModelMismatch : null
1008
- },
1009
- requested_subagents: requestedSubagents,
1010
- count_policy: evidence.count_policy,
1011
- target_subagents: evidence.target_subagents,
1012
- wave_lifecycle: lifecycle,
1013
- max_threads: Number(plan.max_threads || state.subagent_max_threads || 0),
1014
- max_depth: 1,
1015
- started_subagents: evidence.started_threads,
1016
- completed_subagents: evidence.completed_threads,
1017
- failed_subagents: evidence.failed_threads,
1018
- agents: officialSubagentRolePlan(),
1019
- verification: {
1020
- budget: plan.verification?.budget || plan.verification_budget || 'affected',
1021
- checks: Array.isArray(plan.verification?.checks)
1022
- ? plan.verification.checks
1023
- : Array.isArray(plan.verification_checks)
1024
- ? plan.verification_checks
1025
- : []
1026
- },
1027
- parent_summary_present: evidence.parent_summary_present,
1028
- parent_summary: structuredParentSummary.summary,
1029
- parent_thread_outcomes: structuredParentSummary.raw?.thread_outcomes || [],
1030
- subagent_evidence: SUBAGENT_EVIDENCE_FILENAME,
1031
- blockers: uniqueBlockers,
1032
- updated_at: updatedAt
1033
- };
1034
- await writeJsonAtomic(path.join(dir, 'naruto-summary.json'), summary);
1035
- const gate = await writeNarutoGate(dir, {
1036
- missionId: id,
1037
- workflowRunId,
1038
- evidence,
1039
- passed,
1040
- blockers: uniqueBlockers,
1041
- configBlockers: [
1042
- ...(Array.isArray(previousGate.config_blockers) ? previousGate.config_blockers.map(String) : []),
1043
- ...(Array.isArray(plan.config_blockers) ? plan.config_blockers.map((item) => `official_subagent_config:${String(item)}`) : [])
1044
- ],
1045
- observedParentModel: parentModel,
1046
- parentModelMatch: parentModel ? !parentModelMismatch : null
1047
- });
1048
- await updateCurrentIfMissionAndRun(root, id, workflowRunId, {
1049
- subagents_spawned: evidence.started_threads > 0,
1050
- subagents_reported: evidence.completed_threads > 0,
1051
- subagents_verified: evidence.ok,
1052
- subagent_evidence_file: SUBAGENT_EVIDENCE_FILENAME,
1053
- parent_summary_present: evidence.parent_summary_present
1054
- }, { sessionKey: sessionKey || state._session_key });
1055
- return {
1056
- evidence,
1057
- terminal: passed ? { passed: true, missionId: id, workflowRunId, gate } : null
1058
- };
1059
- }
1060
- function completeNarutoTerminalBundle(input) {
1061
- const runId = String(input.workflowRunId || '').trim();
1062
- const parent = normalizeSubagentParentSummary(input.parentSummary);
1063
- return Boolean(runId
1064
- && input.gate?.workflow_run_id === runId
1065
- && input.gate?.passed === true
1066
- && input.gate?.terminal === true
1067
- && input.summary?.workflow_run_id === runId
1068
- && input.summary?.ok === true
1069
- && input.summary?.status === 'completed'
1070
- && input.evidence?.run_id === runId
1071
- && input.evidence?.ok === true
1072
- && input.evidence?.status === 'completed'
1073
- && parent.trustworthy
1074
- && parent.status === 'completed'
1075
- && parent.run_id === runId);
1076
- }
1077
- async function finalizeNarutoTerminalProof(root, state, sessionKey, dir, terminal) {
1078
- // Lock order is finalization -> lifecycle -> session state. Preparation starts
1079
- // at lifecycle -> session state and never acquires the finalization lock.
1080
- await withFileLock({
1081
- lockPath: path.join(dir, '.naruto-finalize.lock'),
1082
- timeoutMs: 5_000,
1083
- staleMs: 30_000
1084
- }, () => withOfficialSubagentLifecycleLock(dir, async () => {
1085
- if (await officialSubagentPreparationInProgress(dir))
1086
- return;
1087
- const [currentPlan, currentGate] = await Promise.all([
1088
- readJson(path.join(dir, 'subagent-plan.json'), null).catch(() => null),
1089
- readJson(path.join(dir, 'naruto-gate.json'), null).catch(() => null)
1090
- ]);
1091
- if (String(currentPlan?.workflow_run_id || '').trim() !== terminal.workflowRunId
1092
- || String(currentGate?.workflow_run_id || '').trim() !== terminal.workflowRunId
1093
- || currentGate?.passed !== true
1094
- || currentGate?.terminal !== true)
1095
- return;
1096
- let proofStatus = await currentNarutoProofStatus(root, terminal.missionId, terminal.workflowRunId, state);
1097
- if (!proofStatus.valid) {
1098
- const finalized = await maybeFinalizeRoute(root, {
1099
- missionId: terminal.missionId,
1100
- route: '$Naruto',
1101
- gateFile: 'naruto-gate.json',
1102
- gate: currentGate,
1103
- artifacts: [
1104
- 'subagent-plan.json',
1105
- 'subagent-events.jsonl',
1106
- SUBAGENT_PARENT_SUMMARY_FILENAME,
1107
- SUBAGENT_EVIDENCE_FILENAME,
1108
- 'naruto-summary.json',
1109
- 'naruto-gate.json'
1110
- ],
1111
- claims: [{ id: 'naruto-official-subagent-completion', status: 'supported', evidence: 'naruto-gate.json' }],
1112
- agents: true
1113
- });
1114
- if (finalized?.ok !== true) {
1115
- throw new Error(`naruto_terminal_proof_finalize_failed:${String(finalized?.validation?.issues?.join(',') || finalized?.status || 'unknown')}`);
1116
- }
1117
- proofStatus = await currentNarutoProofStatus(root, terminal.missionId, terminal.workflowRunId, state);
1118
- }
1119
- if (!proofStatus.valid)
1120
- throw new Error('naruto_terminal_proof_invalid_after_finalize');
1121
- await closeWorkOrderLedgerForRouteResult(dir, { ok: true });
1122
- await invalidateReflectionForNarutoProofOnce(root, state, sessionKey, terminal.workflowRunId, proofStatus.digest);
1123
- }));
1124
- }
1125
- async function currentNarutoProofStatus(root, missionId, workflowRunId, state) {
1126
- const validation = await validateRouteCompletionProof(root, {
1127
- missionId,
1128
- route: '$Naruto',
1129
- state: {
1130
- ...state,
1131
- mission_id: missionId,
1132
- subagents_required: true,
1133
- official_subagent_run_id: workflowRunId
1134
- }
1135
- }).catch(() => null);
1136
- const proofRunId = String(validation?.proof?.evidence?.route_gate?.workflow_run_id || '').trim();
1137
- const proofText = await readText(path.join(root, '.sneakoscope', 'missions', missionId, 'completion-proof.json'), '').catch(() => '');
1138
- return {
1139
- valid: validation?.ok === true && proofRunId === workflowRunId,
1140
- proof: validation?.proof || null,
1141
- digest: proofText ? `sha256:${sha256(proofText)}` : null
1142
- };
1143
- }
1144
- async function invalidateReflectionForNarutoProofOnce(root, state, sessionKey, workflowRunId, proofDigest) {
1145
- if (!workflowRunId || !proofDigest)
1146
- return;
1147
- const resolvedSessionKey = sessionKey || state?._session_key;
1148
- await updateCurrentIfMissionAndRun(root, state?.mission_id, workflowRunId, (current) => {
1149
- if (current?.reflection_invalidated_for_workflow_run_id === workflowRunId
1150
- && current?.reflection_invalidated_for_proof_digest === proofDigest)
1151
- return null;
1152
- return {
1153
- reflection_invalidation_required: true,
1154
- reflection_invalidated_at: nowIso(),
1155
- reflection_invalidation_reason: 'naruto_terminal_proof_committed',
1156
- reflection_invalidated_for_workflow_run_id: workflowRunId,
1157
- reflection_invalidated_for_proof_digest: proofDigest
1158
- };
1159
- }, { sessionKey: resolvedSessionKey });
1160
- }
1161
885
  async function consumeLightRouteStop(root, payload = {}) {
1162
886
  const file = path.join(root, '.sneakoscope', 'state', LIGHT_ROUTE_STOP_ARTIFACT);
1163
887
  const record = await readJson(file, null).catch(() => null);