sneakoscope 6.0.3 → 6.1.2

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 (378) hide show
  1. package/README.md +29 -12
  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/bin/fast-inline.js +18 -14
  6. package/dist/bin/sks-dispatch.js +2 -4
  7. package/dist/cli/args.js +2 -0
  8. package/dist/cli/command-manifest-lite.js +2 -3
  9. package/dist/cli/command-registry.js +3 -4
  10. package/dist/cli/help-fast.js +1 -1
  11. package/dist/cli/install-helpers.js +348 -763
  12. package/dist/cli/install-tool-helpers.js +287 -0
  13. package/dist/cli/router.js +91 -6
  14. package/dist/commands/codex-lb.js +188 -53
  15. package/dist/commands/codex.js +44 -5
  16. package/dist/commands/doctor.js +302 -46
  17. package/dist/commands/tmux.js +5 -1
  18. package/dist/commands/versioning.js +7 -0
  19. package/dist/commands/zellij-monitor-pane.js +2 -0
  20. package/dist/commands/zellij-viewport-pane.js +3 -1
  21. package/dist/commands/zellij.js +1 -1
  22. package/dist/config/skills-manifest.json +59 -59
  23. package/dist/core/agent-bridge/agent-manifest.js +48 -0
  24. package/dist/core/agents/agent-central-ledger.js +9 -0
  25. package/dist/core/agents/agent-cleanup-executor.js +334 -41
  26. package/dist/core/agents/agent-cleanup.js +20 -1
  27. package/dist/core/agents/agent-command-surface.js +3 -1
  28. package/dist/core/agents/agent-effort-policy.js +30 -38
  29. package/dist/core/agents/agent-janitor.js +9 -10
  30. package/dist/core/agents/agent-namespace-safety.js +56 -0
  31. package/dist/core/agents/agent-orchestrator.js +25 -3
  32. package/dist/core/agents/agent-output-validator.js +1 -1
  33. package/dist/core/agents/agent-plan.js +100 -21
  34. package/dist/core/agents/agent-role-config.js +43 -49
  35. package/dist/core/agents/agent-runner-codex-exec.js +18 -3
  36. package/dist/core/agents/agent-runner-process.js +1 -0
  37. package/dist/core/agents/agent-schema.js +3 -2
  38. package/dist/core/agents/fast-mode-policy.js +3 -5
  39. package/dist/core/agents/native-cli-session-swarm.js +1 -1
  40. package/dist/core/agents/native-worker-backend-router.js +2 -1
  41. package/dist/core/agents/work-partition/repo-inventory.js +68 -7
  42. package/dist/core/agents/zellij-right-lane-cockpit.js +2 -2
  43. package/dist/core/code-structure.js +5 -4
  44. package/dist/core/codex/agent-config-file-repair.js +94 -193
  45. package/dist/core/codex/codex-cli-update.js +723 -0
  46. package/dist/core/codex/codex-config-guard.js +38 -11
  47. package/dist/core/codex/codex-project-config-policy.js +3 -6
  48. package/dist/core/codex/codex-startup-config-postcheck.js +52 -42
  49. package/dist/core/codex-adapter.js +35 -22
  50. package/dist/core/codex-app/codex-agent-role-sync.js +13 -54
  51. package/dist/core/codex-app/codex-app-fast-ui-repair.js +51 -20
  52. package/dist/core/codex-app/codex-app-launcher.js +48 -17
  53. package/dist/core/codex-app/codex-app-restart.js +23 -2
  54. package/dist/core/codex-app/codex-app-ui-state-snapshot.js +11 -3
  55. package/dist/core/codex-app/sks-menubar.js +136 -5
  56. package/dist/core/codex-app.js +35 -14
  57. package/dist/core/codex-compat/codex-hook-warning-detector.js +10 -1
  58. package/dist/core/codex-compat/codex-release-manifest.js +6 -6
  59. package/dist/core/codex-control/codex-0139-doctor-real-probe.js +7 -1
  60. package/dist/core/codex-control/codex-0139-image-path-real-probe.js +29 -12
  61. package/dist/core/codex-control/codex-0139-probe-runner.js +103 -28
  62. package/dist/core/codex-control/codex-0139-real-probe-summary.js +7 -3
  63. package/dist/core/codex-control/codex-0139-real-probes.js +21 -6
  64. package/dist/core/codex-control/codex-0139-sandbox-real-probe.js +39 -13
  65. package/dist/core/codex-control/codex-0139-web-search-probe.js +28 -14
  66. package/dist/core/codex-control/{codex-0142-capability.js → codex-0144-capability.js} +22 -22
  67. package/dist/core/codex-control/codex-0144-collab-agent-real-probe.js +63 -0
  68. package/dist/core/codex-control/codex-lb-launch-recovery.js +278 -0
  69. package/dist/core/codex-control/codex-multi-agent-event-normalizer.js +5 -1
  70. package/dist/core/codex-control/codex-reliability-shield.js +93 -30
  71. package/dist/core/codex-control/codex-sdk-adapter.js +96 -13
  72. package/dist/core/codex-control/codex-sdk-config-policy.js +2 -1
  73. package/dist/core/codex-control/codex-sdk-sandbox-policy.js +6 -3
  74. package/dist/core/codex-control/codex-task-runner.js +62 -9
  75. package/dist/core/codex-control/python-codex-sdk-adapter.js +30 -3
  76. package/dist/core/codex-exec-output-schema.js +35 -6
  77. package/dist/core/codex-lb/codex-lb-env.js +30 -1
  78. package/dist/core/codex-lb/codex-lb-tool-catalog.js +478 -0
  79. package/dist/core/codex-lb/codex-lb-tool-output-recovery.js +291 -0
  80. package/dist/core/codex-native/codex-native-feature-broker.js +31 -38
  81. package/dist/core/codex-native/codex-native-feature-matrix.js +2 -2
  82. package/dist/core/codex-native/codex-native-repair-transaction.js +1 -1
  83. package/dist/core/codex-native/core-skill-manifest.js +8 -4
  84. package/dist/core/codex-native/native-capability-postcheck.js +16 -8
  85. package/dist/core/codex-native/native-capability-repair-matrix.js +76 -27
  86. package/dist/core/codex-plugins/codex-plugin-json.js +67 -21
  87. package/dist/core/codex-plugins/codex-plugin-repair.js +118 -0
  88. package/dist/core/codex-runtime/codex-desktop-config-policy.js +305 -0
  89. package/dist/core/commands/agent-bridge-command.js +23 -2
  90. package/dist/core/commands/agent-command.js +38 -5
  91. package/dist/core/commands/basic-cli.js +77 -30
  92. package/dist/core/commands/command-utils.js +1 -1
  93. package/dist/core/commands/gc-command.js +27 -4
  94. package/dist/core/commands/image-ux-review-command.js +55 -24
  95. package/dist/core/commands/mad-sks-command.js +182 -137
  96. package/dist/core/commands/naruto-command.js +643 -1153
  97. package/dist/core/commands/pipeline-command.js +1 -0
  98. package/dist/core/commands/research-command.js +293 -231
  99. package/dist/core/commands/run-command.js +100 -23
  100. package/dist/core/commands/team-command.js +2 -3
  101. package/dist/core/commands/team-legacy-observe-command.js +94 -359
  102. package/dist/core/commands/wiki-command.js +179 -83
  103. package/dist/core/computer-use-live-evidence.js +166 -3
  104. package/dist/core/computer-use-status.js +5 -2
  105. package/dist/core/daemon/sksd-hook-daemon-entrypoint.js +2 -2
  106. package/dist/core/daemon/sksd-hook-daemon.js +171 -28
  107. package/dist/core/daemon/sksd-hook-dispatch.js +2 -2
  108. package/dist/core/db-safety.js +2 -2
  109. package/dist/core/decision-lattice.js +6 -6
  110. package/dist/core/dfix/verification-selector.js +6 -4
  111. package/dist/core/doctor/browser-use-repair.js +54 -13
  112. package/dist/core/doctor/codex-0139-doctor.js +3 -2
  113. package/dist/core/doctor/codex-startup-config-repair.js +8 -3
  114. package/dist/core/doctor/computer-use-repair.js +28 -39
  115. package/dist/core/doctor/doctor-codex-startup-repair.js +24 -149
  116. package/dist/core/doctor/doctor-context7-repair.js +1 -1
  117. package/dist/core/doctor/doctor-dirty-planner.js +1 -1
  118. package/dist/core/doctor/doctor-native-capability-repair.js +74 -3
  119. package/dist/core/doctor/imagegen-repair.js +47 -12
  120. package/dist/core/doctor/legacy-global-hook-cleanup.js +179 -0
  121. package/dist/core/feature-fixture-executor.js +71 -7
  122. package/dist/core/feature-fixture-runner.js +53 -12
  123. package/dist/core/feature-fixtures.js +47 -14
  124. package/dist/core/feature-registry.js +53 -58
  125. package/dist/core/fsx.js +54 -6
  126. package/dist/core/harness-conflicts.js +19 -10
  127. package/dist/core/hooks-runtime/code-pack-freshness-preflight.js +5 -4
  128. package/dist/core/hooks-runtime/hook-invocation-dedupe.js +147 -0
  129. package/dist/core/hooks-runtime/hook-io.js +14 -4
  130. package/dist/core/hooks-runtime/light-turn.js +70 -0
  131. package/dist/core/hooks-runtime/payload-signals.js +270 -0
  132. package/dist/core/hooks-runtime/team-digest.js +0 -1
  133. package/dist/core/hooks-runtime/tool-output-quarantine.js +93 -0
  134. package/dist/core/hooks-runtime.js +418 -250
  135. package/dist/core/image/image-artifact-path-contract.js +8 -6
  136. package/dist/core/image/image-artifact-registry.js +5 -1
  137. package/dist/core/image-ux-review/imagegen-adapter.js +5 -2
  138. package/dist/core/imagegen/imagegen-capability.js +10 -13
  139. package/dist/core/imagegen/require-imagegen.js +37 -11
  140. package/dist/core/init/skills.js +16 -30
  141. package/dist/core/init.js +144 -36
  142. package/dist/core/managed-assets/managed-assets-manifest.js +417 -14
  143. package/dist/core/mission.js +24 -1
  144. package/dist/core/naruto/naruto-work-graph.js +70 -4
  145. package/dist/core/ops/reporting.js +3 -0
  146. package/dist/core/pipeline-internals/runtime-core.js +578 -180
  147. package/dist/core/pipeline-internals/runtime-gates.js +191 -49
  148. package/dist/core/ppt/style-tokens.js +1 -1
  149. package/dist/core/ppt-review/index.js +1 -1
  150. package/dist/core/ppt-review/slide-exporter.js +23 -17
  151. package/dist/core/ppt-review/slide-imagegen-review.js +1 -1
  152. package/dist/core/ppt-review/slide-issue-extraction.js +4 -2
  153. package/dist/core/preflight/parallel-preflight-engine.js +50 -1
  154. package/dist/core/product-design-plugin.js +2 -2
  155. package/dist/core/proof/route-finalizer.js +1 -1
  156. package/dist/core/proof/route-proof-gate.js +7 -2
  157. package/dist/core/proof-field.js +3 -3
  158. package/dist/core/provider/model-router.js +38 -32
  159. package/dist/core/recallpulse/policy.js +12 -28
  160. package/dist/core/recallpulse.js +11 -6
  161. package/dist/core/release/gate-manifest.js +18 -12
  162. package/dist/core/release/gate-pack-manifest.js +1 -1
  163. package/dist/core/release/npm-pack-proof.js +247 -0
  164. package/dist/core/release/package-dist-snapshot.js +151 -0
  165. package/dist/core/release/package-size-budget.js +5 -0
  166. package/dist/core/release/release-authorization-snapshot.js +115 -0
  167. package/dist/core/release/release-gate-affected-selector.js +15 -3
  168. package/dist/core/release/release-gate-cache-v2.js +30 -0
  169. package/dist/core/release/release-gate-contract.js +161 -0
  170. package/dist/core/release/release-gate-dag.js +44 -3
  171. package/dist/core/release/release-gate-hermetic-env.js +28 -17
  172. package/dist/core/release/release-real-contract.js +496 -0
  173. package/dist/core/release-parallel-full-coverage.js +31 -143
  174. package/dist/core/research/claim-evidence-matrix.js +41 -6
  175. package/dist/core/research/experiment-plan.js +14 -10
  176. package/dist/core/research/falsification.js +9 -2
  177. package/dist/core/research/implementation-blueprint-densifier.js +82 -60
  178. package/dist/core/research/implementation-blueprint.js +32 -26
  179. package/dist/core/research/mock-result.js +122 -11
  180. package/dist/core/research/replication-pack.js +15 -8
  181. package/dist/core/research/research-adversarial-review.js +1068 -0
  182. package/dist/core/research/research-claim-builder.js +69 -17
  183. package/dist/core/research/research-claim-synthesizer.js +343 -0
  184. package/dist/core/research/research-cycle-runner.js +53 -3
  185. package/dist/core/research/research-falsification-runner.js +176 -0
  186. package/dist/core/research/research-final-reviewer.js +44 -125
  187. package/dist/core/research/research-realistic-report.js +14 -6
  188. package/dist/core/research/research-review-artifact-digest.js +66 -0
  189. package/dist/core/research/research-source-evidence.js +144 -0
  190. package/dist/core/research/research-source-layer-catalog.js +68 -0
  191. package/dist/core/research/research-source-ledger-merge.js +250 -12
  192. package/dist/core/research/research-source-shards.js +26 -70
  193. package/dist/core/research/research-stage-runner.js +237 -247
  194. package/dist/core/research/research-super-search.js +184 -0
  195. package/dist/core/research/research-synthesis-prompt.js +20 -1
  196. package/dist/core/research/research-synthesis-writer.js +86 -5
  197. package/dist/core/research/research-work-graph.js +25 -18
  198. package/dist/core/research/source-quality-report.js +21 -0
  199. package/dist/core/research.js +429 -280
  200. package/dist/core/retention/retention-budget.js +25 -6
  201. package/dist/core/retention.js +980 -101
  202. package/dist/core/routes/constants.js +1 -1
  203. package/dist/core/routes/dollar-manifest-lite.js +11 -11
  204. package/dist/core/routes/evidence.js +4 -4
  205. package/dist/core/routes/ppt-policy.js +1 -1
  206. package/dist/core/routes.js +92 -64
  207. package/dist/core/runtime/task-profile.js +66 -0
  208. package/dist/core/runtime/verification-budget.js +12 -0
  209. package/dist/core/secret-redaction.js +4 -0
  210. package/dist/core/security/high-risk-contracts.js +6 -6
  211. package/dist/core/stop-gate/stop-gate-check.js +49 -12
  212. package/dist/core/subagents/agent-catalog.js +215 -0
  213. package/dist/core/subagents/model-policy.js +118 -0
  214. package/dist/core/subagents/naruto-help-contract.js +40 -0
  215. package/dist/core/subagents/official-subagent-config.js +488 -0
  216. package/dist/core/subagents/official-subagent-preparation.js +251 -0
  217. package/dist/core/subagents/official-subagent-prompt.js +137 -0
  218. package/dist/core/subagents/official-subagent-runner.js +129 -0
  219. package/dist/core/subagents/subagent-evidence.js +663 -0
  220. package/dist/core/subagents/terminology.js +16 -0
  221. package/dist/core/subagents/thread-budget.js +21 -0
  222. package/dist/core/subagents/triwiki-attention.js +65 -0
  223. package/dist/core/super-search/runtime-helpers.js +173 -19
  224. package/dist/core/super-search/runtime.js +140 -15
  225. package/dist/core/super-search/source-records.js +49 -8
  226. package/dist/core/team-review-policy.js +15 -0
  227. package/dist/core/triwiki/code-pack.js +8 -2
  228. package/dist/core/triwiki/triwiki-cache-key.js +108 -29
  229. package/dist/core/triwiki/triwiki-module-card.js +1 -1
  230. package/dist/core/triwiki-attention.js +13 -6
  231. package/dist/core/triwiki-provenance.js +274 -0
  232. package/dist/core/triwiki-runtime.js +21 -7
  233. package/dist/core/triwiki-wrongness/wrongness-ledger.js +187 -61
  234. package/dist/core/triwiki-wrongness/wrongness-retrieval.js +11 -2
  235. package/dist/core/triwiki-wrongness/wrongness-trust-policy.js +2 -0
  236. package/dist/core/update-check.js +23 -15
  237. package/dist/core/version-manager.js +51 -1
  238. package/dist/core/version.js +1 -1
  239. package/dist/core/wiki-coordinate.js +128 -12
  240. package/dist/core/work-order-ledger.js +208 -10
  241. package/dist/core/zellij/zellij-command.js +12 -1
  242. package/dist/core/zellij/zellij-dashboard-pane.js +3 -3
  243. package/dist/core/zellij/zellij-fake-adapter.js +3 -1
  244. package/dist/core/zellij/zellij-launcher.js +51 -21
  245. package/dist/core/zellij/zellij-layout-builder.js +14 -5
  246. package/dist/core/zellij/zellij-official-subagent-activity.js +477 -0
  247. package/dist/core/zellij/zellij-official-subagent-telemetry.js +264 -0
  248. package/dist/core/zellij/zellij-pane-proof.js +32 -6
  249. package/dist/core/zellij/zellij-slot-pane-renderer.js +17 -5
  250. package/dist/core/zellij/zellij-slot-telemetry.js +15 -3
  251. package/dist/core/zellij/zellij-ui-mode.js +1 -1
  252. package/dist/core/zellij/zellij-viewport-binder.js +3 -0
  253. package/dist/core/zellij/zellij-worker-pane-manager.js +5 -3
  254. package/dist/scripts/agent-fast-mode-default-check.js +48 -29
  255. package/dist/scripts/agent-role-config-repair-check.js +34 -15
  256. package/dist/scripts/agent-wiki-context-proof-check.js +16 -2
  257. package/dist/scripts/all-feature-deep-completion-check.js +14 -4
  258. package/dist/scripts/architecture-guard-check.js +8 -1
  259. package/dist/scripts/build-dist.js +17 -5
  260. package/dist/scripts/canonical-test-runner.js +188 -0
  261. package/dist/scripts/check-command-module-budget.js +38 -16
  262. package/dist/scripts/check-legacy-free.js +1 -1
  263. package/dist/scripts/check-route-modularity.js +0 -1
  264. package/dist/scripts/check-ts-contracts.js +1 -1
  265. package/dist/scripts/codex-0139-interrupt-agent-check.js +5 -1
  266. package/dist/scripts/{codex-0142-app-server-v2-check.js → codex-0144-app-server-v2-check.js} +11 -10
  267. package/dist/scripts/{codex-0142-binary-identity-check.js → codex-0144-binary-identity-check.js} +4 -4
  268. package/dist/scripts/codex-0144-capability-check.js +21 -0
  269. package/dist/scripts/{codex-0139-real-probes-check.js → codex-0144-core-real-probes-check.js} +19 -5
  270. package/dist/scripts/{codex-0142-doctor-wiring-check.js → codex-0144-doctor-wiring-check.js} +6 -6
  271. package/dist/scripts/{codex-0142-manifest-check.js → codex-0144-manifest-check.js} +11 -3
  272. package/dist/scripts/{codex-0142-policy-check.js → codex-0144-policy-check.js} +2 -2
  273. package/dist/scripts/{codex-0142-thread-store-check.js → codex-0144-thread-store-check.js} +3 -3
  274. package/dist/scripts/codex-app-provider-model-ui-check.js +53 -19
  275. package/dist/scripts/codex-app-ui-preservation-check.js +35 -4
  276. package/dist/scripts/codex-control-all-pipelines-check.js +7 -3
  277. package/dist/scripts/codex-control-side-effect-scope-check.js +2 -2
  278. package/dist/scripts/codex-control-tool-output-continuity-audit-check.js +27 -0
  279. package/dist/scripts/codex-effort-auto-discovery-check.js +1 -1
  280. package/dist/scripts/codex-lb-fast-mode-truth-check.js +1 -0
  281. package/dist/scripts/{codex-lb-gpt55-fast-profile-check.js → codex-lb-gpt56-fast-profile-check.js} +56 -5
  282. package/dist/scripts/codex-model-metadata-check.js +1 -1
  283. package/dist/scripts/codex-native-agent-role-content-check.js +15 -7
  284. package/dist/scripts/codex-native-repair-transaction-check.js +3 -1
  285. package/dist/scripts/codex-sdk-all-pipelines-check.js +7 -4
  286. package/dist/scripts/codex-sdk-research-pipeline-check.js +30 -8
  287. package/dist/scripts/codex-sdk-sandbox-policy-check.js +5 -1
  288. package/dist/scripts/codex-sdk-version-compat-check.js +2 -1
  289. package/dist/scripts/db-route-materialization-check.js +33 -0
  290. package/dist/scripts/dfix-fixture-check.js +1 -1
  291. package/dist/scripts/docs-truthfulness-check.js +4 -2
  292. package/dist/scripts/doctor-codex-startup-repair-check.js +47 -25
  293. package/dist/scripts/doctor-context7-repair-check.js +2 -1
  294. package/dist/scripts/doctor-fix-production-blackbox.js +12 -2
  295. package/dist/scripts/doctor-fixes-codex-app-fast-ui-check.js +34 -7
  296. package/dist/scripts/doctor-imagegen-repair-check.js +14 -4
  297. package/dist/scripts/doctor-startup-config-repair-blackbox.js +9 -3
  298. package/dist/scripts/doctor-startup-config-repair-check.js +13 -3
  299. package/dist/scripts/install-update-preserves-config-check.js +7 -2
  300. package/dist/scripts/legacy-gate-inventory-check.js +7 -5
  301. package/dist/scripts/legacy-strong-inventory-check.js +7 -5
  302. package/dist/scripts/legacy-upgrade-matrix-check.js +4 -4
  303. package/dist/scripts/lib/native-cli-session-swarm-check-lib.js +173 -13
  304. package/dist/scripts/mad-sks-app-ui-no-mutation-check.js +165 -6
  305. package/dist/scripts/managed-role-manifest-parity-check.js +5 -4
  306. package/dist/scripts/mutation-callsite-coverage-check.js +0 -11
  307. package/dist/scripts/naruto-codex-e2e-check.js +14 -7
  308. package/dist/scripts/naruto-shadow-clone-swarm-check.js +4 -201
  309. package/dist/scripts/npm-publish-performance-check.js +20 -12
  310. package/dist/scripts/official-subagent-workflow-check.js +145 -0
  311. package/dist/scripts/package-published-contract-check.js +6 -20
  312. package/dist/scripts/packlist-performance-check.js +17 -3
  313. package/dist/scripts/parallel-verification-engine-check.js +2 -2
  314. package/dist/scripts/postinstall-safe-side-effects-check.js +8 -3
  315. package/dist/scripts/ppt-no-mock-as-real-check.js +3 -1
  316. package/dist/scripts/prepublish-release-check-or-fast.js +23 -86
  317. package/dist/scripts/product-design-plugin-routing-check.js +1 -1
  318. package/dist/scripts/release-affected-selector-check.js +74 -1
  319. package/dist/scripts/release-check-stamp.js +324 -239
  320. package/dist/scripts/release-dag-full-coverage-check.js +7 -15
  321. package/dist/scripts/release-dynamic-presets-check.js +10 -1
  322. package/dist/scripts/release-gate-dag-runner-check.js +3 -3
  323. package/dist/scripts/release-gate-dag-runner.js +35 -11
  324. package/dist/scripts/release-gate-existence-audit.js +1 -2
  325. package/dist/scripts/release-gate-script-parity-check.js +1 -1
  326. package/dist/scripts/release-parallel-full-coverage-check.js +12 -6
  327. package/dist/scripts/release-parallel-speed-budget-check.js +18 -2
  328. package/dist/scripts/release-real-check.js +390 -157
  329. package/dist/scripts/release-registry-check.js +61 -16
  330. package/dist/scripts/release-runtime-truth-matrix-check.js +22 -0
  331. package/dist/scripts/research-blueprint-densifier-check.js +2 -2
  332. package/dist/scripts/research-real-cycle-no-legacy-final-md-check.js +11 -7
  333. package/dist/scripts/route-proof-artifact-structure-check.js +1 -0
  334. package/dist/scripts/search-visibility-gate-lib.js +1 -1
  335. package/dist/scripts/seo-geo-route-identity-check.js +30 -4
  336. package/dist/scripts/sizecheck.js +4 -4
  337. package/dist/scripts/sks-1-11-gate-lib.js +53 -6
  338. package/dist/scripts/sks-3-1-4-directive-check-lib.js +8 -2
  339. package/dist/scripts/sks-3-1-5-directive-check-lib.js +3 -2
  340. package/dist/scripts/sks-3-1-6-directive-check-lib.js +5 -3
  341. package/dist/scripts/sks-menubar-install-check.js +8 -0
  342. package/dist/scripts/sks-uninstall-regression-check.js +1 -1
  343. package/dist/scripts/sksd-daemon-check.js +16 -6
  344. package/dist/scripts/trust-fixture-check.js +32 -10
  345. package/dist/scripts/write-build-manifest.js +2 -1
  346. package/dist/scripts/wrongness-fixture-check.js +1 -1
  347. package/dist/scripts/zellij-layout-valid-check.js +36 -11
  348. package/dist/scripts/zellij-pane-proof-check.js +33 -2
  349. package/dist/scripts/zellij-real-session-cleanup-check.js +122 -2
  350. package/dist/scripts/zellij-real-session-launch-check.js +76 -5
  351. package/dist/scripts/zellij-slot-pane-renderer-check.js +4 -4
  352. package/dist/scripts/zellij-spawn-on-demand-layout-check.js +3 -3
  353. package/docs/demo.tape +1 -1
  354. package/infra-harness-gates.json +1486 -0
  355. package/package.json +32 -19
  356. package/release-gates.v2.json +4060 -0
  357. package/runtime-required-scripts.json +9 -0
  358. package/schemas/codex/{app-server-0.142 → app-server-0.144}/codex_app_server_protocol.v2.schemas.json +1146 -781
  359. package/schemas/codex/codex-0139-real-probe-result.schema.json +39 -5
  360. package/schemas/codex/ppt-slide-issue-ledger.schema.json +2 -1
  361. package/dist/commands/db.js +0 -6
  362. package/dist/core/codex-control/codex-0139-multi-agent-real-probe.js +0 -107
  363. package/dist/core/commands/db-command.js +0 -146
  364. package/dist/core/research/prompt.js +0 -15
  365. package/dist/scripts/agent-native-release-gate.js +0 -274
  366. package/dist/scripts/codex-0142-capability-check.js +0 -21
  367. package/dist/scripts/codex-control-tool-call-sequence-repair-check.js +0 -14
  368. package/dist/scripts/command-performance-scorecard-check.js +0 -204
  369. package/dist/scripts/config-managed-merge-callsite-coverage-check.js +0 -212
  370. package/dist/scripts/dollar-performance-scorecard-check.js +0 -257
  371. package/dist/scripts/gate-timing-check.js +0 -16
  372. package/dist/scripts/ops-maturity-scorecard-check.js +0 -12
  373. package/dist/scripts/performance-baseline-check.js +0 -12
  374. package/dist/scripts/performance-improvement-report-check.js +0 -58
  375. package/dist/scripts/release-parallel-check.js +0 -389
  376. package/dist/scripts/release-runner-efficiency-check.js +0 -15
  377. package/dist/scripts/retention-long-run-smoke-check.js +0 -299
  378. package/docs/assets/sneakoscope-architecture-pipeline.jpg +0 -0
@@ -3,10 +3,15 @@ import path from 'node:path';
3
3
  import { appendJsonl, exists, nowIso, packageRoot, readJson, writeJsonAtomic } from '../fsx.js';
4
4
  import { drainZellijLaneSupervisor } from './zellij-lane-supervisor.js';
5
5
  import { normalizeAgentSessionRows } from './agent-session-rows.js';
6
+ import { isAgentTerminalSessionStatus, writeAgentCleanupReport } from './agent-cleanup.js';
6
7
  import { closeZellijPaneById } from '../zellij/zellij-worker-pane-manager.js';
8
+ import { processReportMatchesProjectNamespace, resolveOwnedNamespacePath, validProjectNamespaceHash } from './agent-namespace-safety.js';
9
+ import { appendAgentLedgerEvent } from './agent-central-ledger.js';
10
+ import { closeAgentSession } from './agent-lifecycle.js';
11
+ import { closeAgentSessionGeneration } from './agent-session-generation.js';
12
+ import { closeAgentTerminalSession } from './agent-terminal-session.js';
7
13
  export const AGENT_CLEANUP_PROOF_SCHEMA = 'sks.agent-cleanup-proof.v2';
8
14
  export const AGENT_CLEANUP_ACTION_LEDGER_SCHEMA = 'sks.agent-cleanup-action-ledger.v1';
9
- const TERMINAL_STATUSES = new Set(['closed', 'completed', 'done', 'failed', 'blocked', 'killed', 'timed_out']);
10
15
  export async function runAgentCleanupExecutor(opts) {
11
16
  const agentRoot = path.join(opts.missionDir, 'agents');
12
17
  const action = opts.action || 'cleanup';
@@ -16,30 +21,61 @@ export async function runAgentCleanupExecutor(opts) {
16
21
  const namespace = await readJson(path.join(opts.missionDir, 'project-session-namespace.json'), null);
17
22
  const sessionsRaw = await readJson(path.join(agentRoot, 'agent-sessions.json'), { sessions: {} });
18
23
  const sessions = normalizeAgentSessionRows(sessionsRaw);
24
+ const sessionById = new Map(sessions.map((row) => [String(row.session_id || row.id || row.agent_id || ''), row]));
19
25
  const activeSessionIds = new Set(sessions
20
- .filter((row) => !TERMINAL_STATUSES.has(String(row.status || row.lifecycle_state || '')))
26
+ .filter((row) => !isAgentTerminalSessionStatus(row.status || row.lifecycle_state))
21
27
  .map((row) => String(row.session_id || row.id || row.agent_id || ''))
22
28
  .filter(Boolean));
23
29
  const now = Date.now();
24
- const staleMs = opts.staleMs ?? 30 * 60 * 1000;
30
+ const requestedStaleMs = Number(opts.staleMs ?? 30 * 60 * 1000);
31
+ const staleMs = Number.isFinite(requestedStaleMs) ? Math.max(0, requestedStaleMs) : 30 * 60 * 1000;
25
32
  const projectHash = String(namespace?.root_hash || '');
33
+ const namespaceAuthorized = validProjectNamespaceHash(projectHash);
26
34
  const actions = [];
27
35
  const graceMs = opts.graceMs ?? Number(process.env.SKS_CLEANUP_GRACE_MS || 750);
28
36
  const killEscalation = opts.killEscalation !== false && process.env.SKS_CLEANUP_KILL_ESCALATION !== '0';
29
- const processReports = await listNamedFiles(path.join(agentRoot, 'sessions'), 'agent-process-report.json');
37
+ const sessionFiles = await listFiles(path.join(agentRoot, 'sessions'));
38
+ for (const session of sessions) {
39
+ if (isAgentTerminalSessionStatus(session.status || session.lifecycle_state))
40
+ continue;
41
+ const staleAction = await reconcileStaleSession({
42
+ agentRoot,
43
+ session,
44
+ sessionFiles,
45
+ projectHash,
46
+ namespaceAuthorized,
47
+ missionId: opts.missionId || namespace?.mission_id || null,
48
+ now,
49
+ staleMs,
50
+ apply
51
+ });
52
+ if (!staleAction)
53
+ continue;
54
+ actions.push(staleAction);
55
+ if (staleAction.kind === 'terminalize_stale_session' && (staleAction.status === 'planned' || staleAction.status === 'applied')) {
56
+ activeSessionIds.delete(String(session.session_id || session.session_key || session.id || session.agent_id || ''));
57
+ }
58
+ }
59
+ const processReports = sessionFiles.filter((file) => path.basename(file) === 'agent-process-report.json');
30
60
  for (const file of processReports) {
31
61
  const report = await readJson(file, null);
32
62
  const pid = Number(report?.pid || 0);
33
63
  const sessionId = String(report?.session_id || '');
34
- const status = String(sessions.find((row) => String(row.session_id || '') === sessionId)?.status || '');
35
- const terminal = TERMINAL_STATUSES.has(status) || (report?.exit_code !== null && report?.exit_code !== undefined);
64
+ const status = String(sessionById.get(sessionId)?.status || '');
65
+ const terminal = isAgentTerminalSessionStatus(status);
36
66
  if (!pid || !processIsAlive(pid))
37
67
  continue;
68
+ // A non-null exit code proves the recorded process already exited. If the
69
+ // PID is alive now it has been reused and must never be killed.
70
+ if (report?.exit_code !== null && report?.exit_code !== undefined) {
71
+ actions.push({ kind: 'skip_foreign_namespace', target: String(pid), status: 'skipped', reason: 'recorded_process_already_exited_pid_reused' });
72
+ continue;
73
+ }
38
74
  if (activeSessionIds.has(sessionId) && !terminal) {
39
75
  actions.push({ kind: 'skip_active_session', target: sessionId || String(pid), status: 'skipped', reason: 'session_active' });
40
76
  continue;
41
77
  }
42
- if (!processReportInNamespace(report, projectHash)) {
78
+ if (!processReportMatchesProjectNamespace(report, projectHash)) {
43
79
  actions.push({ kind: 'skip_foreign_namespace', target: String(pid), status: 'skipped', reason: 'process_outside_project_namespace' });
44
80
  continue;
45
81
  }
@@ -52,7 +88,7 @@ export async function runAgentCleanupExecutor(opts) {
52
88
  }));
53
89
  }
54
90
  const seenZellijPaneIds = new Set();
55
- const zellijReports = await listNamedFiles(path.join(agentRoot, 'sessions'), 'agent-zellij-report.json');
91
+ const zellijReports = sessionFiles.filter((file) => path.basename(file) === 'agent-zellij-report.json');
56
92
  for (const file of zellijReports) {
57
93
  const report = await readJson(file, null);
58
94
  const paneId = String(report?.pane_id || '');
@@ -60,7 +96,7 @@ export async function runAgentCleanupExecutor(opts) {
60
96
  if (!paneId)
61
97
  continue;
62
98
  seenZellijPaneIds.add(paneId);
63
- if (!processReportInNamespace(report, projectHash)) {
99
+ if (!processReportMatchesProjectNamespace(report, projectHash)) {
64
100
  actions.push({ kind: 'skip_foreign_namespace', target: paneId, status: 'skipped', reason: 'zellij_pane_outside_project_namespace' });
65
101
  continue;
66
102
  }
@@ -80,7 +116,7 @@ export async function runAgentCleanupExecutor(opts) {
80
116
  }
81
117
  }));
82
118
  }
83
- const workerPaneReports = await listNamedFiles(path.join(agentRoot, 'sessions'), 'zellij-worker-pane.json');
119
+ const workerPaneReports = sessionFiles.filter((file) => path.basename(file) === 'zellij-worker-pane.json');
84
120
  for (const file of workerPaneReports) {
85
121
  const report = await readJson(file, null);
86
122
  const paneId = String(report?.pane_id || '');
@@ -90,11 +126,15 @@ export async function runAgentCleanupExecutor(opts) {
90
126
  if (!paneId || !sessionName || seenZellijPaneIds.has(paneId))
91
127
  continue;
92
128
  seenZellijPaneIds.add(paneId);
129
+ if (!namespaceAuthorized) {
130
+ actions.push({ kind: 'skip_foreign_namespace', target: paneId, status: 'skipped', reason: 'project_namespace_missing_or_invalid' });
131
+ continue;
132
+ }
93
133
  if (opts.missionId && report?.mission_id && String(report.mission_id) !== String(opts.missionId)) {
94
134
  actions.push({ kind: 'skip_foreign_namespace', target: paneId, status: 'skipped', reason: 'zellij_pane_wrong_mission' });
95
135
  continue;
96
136
  }
97
- const terminal = TERMINAL_STATUSES.has(status) || Boolean(report?.closed_at);
137
+ const terminal = isAgentTerminalSessionStatus(status) || Boolean(report?.closed_at);
98
138
  if (activeSessionIds.has(sessionId) && !terminal && opts.drain !== true) {
99
139
  actions.push({ kind: 'skip_active_session', target: sessionId || paneId, status: 'skipped', reason: 'managed_zellij_worker_active' });
100
140
  continue;
@@ -132,6 +172,10 @@ export async function runAgentCleanupExecutor(opts) {
132
172
  if (seenZellijPaneIds.has(paneId))
133
173
  continue;
134
174
  seenZellijPaneIds.add(paneId);
175
+ if (!namespaceAuthorized) {
176
+ actions.push({ kind: 'skip_foreign_namespace', target: paneId, status: 'skipped', reason: 'project_namespace_missing_or_invalid' });
177
+ continue;
178
+ }
135
179
  if ((visibleActive || headlessActive) && opts.drain !== true) {
136
180
  actions.push({ kind: 'skip_active_session', target: paneId, status: 'skipped', reason: 'zellij_right_column_anchor_active' });
137
181
  continue;
@@ -152,22 +196,21 @@ export async function runAgentCleanupExecutor(opts) {
152
196
  }
153
197
  }
154
198
  for (const dir of Array.isArray(namespace?.orphan_temp_dirs) ? namespace.orphan_temp_dirs.map(String) : []) {
155
- if (!namespaceOwnsPath(dir, projectHash)) {
199
+ const ownedDir = await resolveOwnedNamespacePath(dir, projectHash, namespace?.temp_dir ? [namespace.temp_dir] : []);
200
+ if (!ownedDir) {
156
201
  actions.push({ kind: 'skip_foreign_namespace', target: dir, status: 'skipped', reason: 'path_outside_project_namespace' });
157
202
  continue;
158
203
  }
159
- if (!(await exists(dir)))
160
- continue;
161
204
  actions.push(await applyAction({
162
205
  kind: 'remove_temp_dir',
163
- target: dir,
206
+ target: ownedDir,
164
207
  reason: 'orphan_temp_dir',
165
208
  apply,
166
- before: async () => ({ exists: await exists(dir) }),
167
- after: async () => ({ exists: await exists(dir) }),
209
+ before: async () => ({ exists: await exists(ownedDir) }),
210
+ after: async () => ({ exists: await exists(ownedDir) }),
168
211
  run: async () => {
169
- await fsp.rm(dir, { recursive: true, force: true });
170
- if (await exists(dir))
212
+ await fsp.rm(ownedDir, { recursive: true, force: true });
213
+ if (await exists(ownedDir))
171
214
  throw new Error('temp_dir_still_exists_after_remove');
172
215
  }
173
216
  }));
@@ -187,9 +230,10 @@ export async function runAgentCleanupExecutor(opts) {
187
230
  }
188
231
  }));
189
232
  }
190
- for (const transcript of await listNamedFiles(path.join(agentRoot, 'sessions'), 'agent-terminal-session.json')) {
233
+ for (const transcript of sessionFiles.filter((file) => path.basename(file) === 'agent-terminal-session.json')) {
191
234
  actions.push({ kind: 'archive_transcript_keep', target: transcript, status: 'skipped', reason: 'terminal_transcripts_are_preserved' });
192
235
  }
236
+ const sessionCleanup = await writeAgentCleanupReport(agentRoot);
193
237
  const proof = buildCleanupProof({
194
238
  generatedAt: nowIso(),
195
239
  missionId: opts.missionId || namespace?.mission_id || null,
@@ -198,7 +242,8 @@ export async function runAgentCleanupExecutor(opts) {
198
242
  apply,
199
243
  dryRun: !apply,
200
244
  actions,
201
- activeSessionIds: [...activeSessionIds]
245
+ activeSessionIds: [...activeSessionIds],
246
+ sessionCleanup
202
247
  });
203
248
  await writeJsonAtomic(path.join(agentRoot, 'agent-cleanup-proof.json'), proof);
204
249
  await writeJsonAtomic(path.join(agentRoot, 'agent-command-cleanup.json'), {
@@ -220,6 +265,257 @@ export async function runAgentCleanupExecutor(opts) {
220
265
  }
221
266
  return proof;
222
267
  }
268
+ const STALE_SESSION_REASON = 'stale_nonterminal_session_without_live_process';
269
+ const SESSION_PROCESS_REPORT_NAMES = new Set(['agent-process-report.json', 'worker-process-report.json']);
270
+ async function reconcileStaleSession(input) {
271
+ const initial = await assessStaleSession(input);
272
+ if (!initial.stale)
273
+ return null;
274
+ const sessionId = initial.session_id;
275
+ if (!sessionId || !initial.artifact_dir || !input.namespaceAuthorized) {
276
+ return {
277
+ kind: 'skip_foreign_namespace',
278
+ target: sessionId || 'unknown-session',
279
+ status: 'skipped',
280
+ reason: !input.namespaceAuthorized ? 'stale_session_project_namespace_missing_or_invalid' : 'stale_session_artifact_path_invalid',
281
+ before: initial.evidence
282
+ };
283
+ }
284
+ if (initial.foreign_process_reports.length > 0) {
285
+ return {
286
+ kind: 'skip_foreign_namespace',
287
+ target: sessionId,
288
+ status: 'skipped',
289
+ reason: 'stale_session_foreign_process_report',
290
+ before: initial.evidence
291
+ };
292
+ }
293
+ if (initial.live_pids.length > 0) {
294
+ return {
295
+ kind: 'skip_active_session',
296
+ target: sessionId,
297
+ status: 'skipped',
298
+ reason: 'stale_session_live_process',
299
+ before: initial.evidence
300
+ };
301
+ }
302
+ if (!input.apply) {
303
+ return {
304
+ kind: 'terminalize_stale_session',
305
+ target: sessionId,
306
+ status: 'planned',
307
+ reason: STALE_SESSION_REASON,
308
+ before: initial.evidence,
309
+ after: initial.evidence
310
+ };
311
+ }
312
+ const latestSession = await readLatestSessionRecord(input.agentRoot, input.session, initial.artifact_dir);
313
+ const latestFiles = await listFiles(path.join(input.agentRoot, 'sessions'));
314
+ const latest = await assessStaleSession({ ...input, session: latestSession, sessionFiles: latestFiles });
315
+ if (!latest.stale) {
316
+ return {
317
+ kind: 'skip_active_session',
318
+ target: sessionId,
319
+ status: 'skipped',
320
+ reason: 'stale_session_activity_refreshed_before_apply',
321
+ before: initial.evidence,
322
+ after: latest.evidence
323
+ };
324
+ }
325
+ if (latest.foreign_process_reports.length > 0) {
326
+ return {
327
+ kind: 'skip_foreign_namespace',
328
+ target: sessionId,
329
+ status: 'skipped',
330
+ reason: 'stale_session_foreign_process_report',
331
+ before: initial.evidence,
332
+ after: latest.evidence
333
+ };
334
+ }
335
+ if (latest.live_pids.length > 0) {
336
+ return {
337
+ kind: 'skip_active_session',
338
+ target: sessionId,
339
+ status: 'skipped',
340
+ reason: 'stale_session_live_process',
341
+ before: initial.evidence,
342
+ after: latest.evidence
343
+ };
344
+ }
345
+ try {
346
+ const after = await terminalizeStaleSession(input.agentRoot, latestSession, latest, input.missionId);
347
+ return {
348
+ kind: 'terminalize_stale_session',
349
+ target: sessionId,
350
+ status: 'applied',
351
+ reason: STALE_SESSION_REASON,
352
+ before: initial.evidence,
353
+ after
354
+ };
355
+ }
356
+ catch (err) {
357
+ return {
358
+ kind: 'terminalize_stale_session',
359
+ target: sessionId,
360
+ status: 'failed',
361
+ reason: STALE_SESSION_REASON,
362
+ before: initial.evidence,
363
+ error: err instanceof Error ? err.message : String(err)
364
+ };
365
+ }
366
+ }
367
+ async function assessStaleSession(input) {
368
+ const sessionId = String(input.session?.session_id || input.session?.session_key || input.session?.id || input.session?.agent_id || '');
369
+ const artifact = resolveSessionArtifactDir(input.agentRoot, input.session);
370
+ const activity = latestSessionActivity(input.session);
371
+ const ageMs = activity ? Math.max(0, input.now - activity.timestamp) : null;
372
+ const stale = ageMs !== null && ageMs > input.staleMs;
373
+ const reportFiles = input.sessionFiles.filter((file) => SESSION_PROCESS_REPORT_NAMES.has(path.basename(file)));
374
+ const reports = [];
375
+ for (const file of reportFiles) {
376
+ const row = await readJson(file, null).catch(() => null);
377
+ if (row && String(row.session_id || '') === sessionId)
378
+ reports.push({ file, row });
379
+ }
380
+ const foreignProcessReports = reports
381
+ .filter(({ row }) => !processReportMatchesProjectNamespace(row, input.projectHash))
382
+ .map(({ file }) => path.relative(input.agentRoot, file));
383
+ const pids = [...new Set([
384
+ Number(input.session?.pid || input.session?.process_id || input.session?.worker_pid || 0),
385
+ ...reports.flatMap(({ row }) => [Number(row?.pid || row?.process_id || row?.worker_pid || 0), ...(Array.isArray(row?.child_process_ids) ? row.child_process_ids.map(Number) : [])])
386
+ ].filter((pid) => Number.isSafeInteger(pid) && pid > 0))];
387
+ const livePids = pids.filter(processIsAlive);
388
+ const evidence = {
389
+ session_id: sessionId || null,
390
+ observed_status: String(input.session?.status || input.session?.lifecycle_state || ''),
391
+ last_activity_at: activity?.iso || null,
392
+ last_activity_source: activity?.source || null,
393
+ age_ms: ageMs,
394
+ stale_ms: input.staleMs,
395
+ stale,
396
+ process_report_count: reports.length,
397
+ process_reports: reports.map(({ file }) => path.relative(input.agentRoot, file)),
398
+ observed_pids: pids,
399
+ live_pids: livePids,
400
+ foreign_process_reports: foreignProcessReports,
401
+ artifact_dir: artifact?.relative || null,
402
+ checked_at: new Date(input.now).toISOString()
403
+ };
404
+ return {
405
+ stale,
406
+ session_id: sessionId,
407
+ artifact_dir: artifact,
408
+ foreign_process_reports: foreignProcessReports,
409
+ live_pids: livePids,
410
+ evidence
411
+ };
412
+ }
413
+ function latestSessionActivity(session) {
414
+ const candidates = [
415
+ ['heartbeat_at', session?.heartbeat_at],
416
+ ['last_heartbeat_at', session?.last_heartbeat_at],
417
+ ['updated_at', session?.updated_at],
418
+ ['opened_at', session?.opened_at]
419
+ ].map(([source, value]) => ({ source: String(source), iso: String(value || ''), timestamp: Date.parse(String(value || '')) }))
420
+ .filter((row) => Number.isFinite(row.timestamp))
421
+ .sort((a, b) => b.timestamp - a.timestamp);
422
+ return candidates[0] || null;
423
+ }
424
+ function resolveSessionArtifactDir(agentRoot, session) {
425
+ const slotId = String(session?.slot_id || session?.worker_slot_id || '');
426
+ const generationIndex = Number(session?.generation_index);
427
+ const raw = String(session?.session_artifact_dir || (slotId && Number.isFinite(generationIndex) ? path.join('sessions', slotId, `gen-${generationIndex}`) : ''));
428
+ if (!raw || path.isAbsolute(raw) || raw.split(/[\\/]+/).includes('..'))
429
+ return null;
430
+ const resolved = path.resolve(agentRoot, raw);
431
+ const relative = path.relative(path.resolve(agentRoot), resolved);
432
+ if (!relative || relative.startsWith('..') || path.isAbsolute(relative))
433
+ return null;
434
+ return { absolute: resolved, relative: relative.split(path.sep).join('/') };
435
+ }
436
+ async function readLatestSessionRecord(agentRoot, fallback, artifact) {
437
+ const sessionKey = String(fallback?.session_key || fallback?.session_id || fallback?.agent_id || 'session').replace(/[^A-Za-z0-9._-]+/g, '_');
438
+ const shard = await readJson(path.join(agentRoot, 'sessions', `${sessionKey}.json`), null).catch(() => null);
439
+ if (shard)
440
+ return shard;
441
+ const artifactRecord = await readJson(path.join(artifact.absolute, 'agent-session-record.json'), null).catch(() => null);
442
+ return artifactRecord || fallback;
443
+ }
444
+ async function terminalizeStaleSession(agentRoot, session, assessment, missionId) {
445
+ const artifact = assessment.artifact_dir;
446
+ if (!artifact)
447
+ throw new Error('stale_session_artifact_path_invalid');
448
+ const sessionId = String(session.session_id || session.session_key || session.agent_id || '');
449
+ if (!sessionId)
450
+ throw new Error('stale_session_id_missing');
451
+ const closedAt = nowIso();
452
+ const evidencePath = path.join(artifact.relative, 'agent-stale-session-terminalization.json');
453
+ const closeReportPath = path.join(artifact.relative, 'agent-terminal-close-report.json');
454
+ const transactionId = `stale-${Date.now()}-${sessionId.slice(0, 80)}`;
455
+ const evidence = {
456
+ schema: 'sks.agent-stale-session-terminalization.v1',
457
+ transaction_id: transactionId,
458
+ mission_id: missionId,
459
+ session_id: sessionId,
460
+ status: 'timed_out',
461
+ generation_status: 'blocked',
462
+ reason: STALE_SESSION_REASON,
463
+ applied_at: closedAt,
464
+ assessment: assessment.evidence
465
+ };
466
+ const sessionKey = String(session.session_key || sessionId).replace(/[^A-Za-z0-9._-]+/g, '_');
467
+ const reasonedSession = {
468
+ ...session,
469
+ session_key: sessionKey,
470
+ timed_out_at: closedAt,
471
+ cleanup_terminalized_at: closedAt,
472
+ terminal_reason: STALE_SESSION_REASON,
473
+ terminalization_evidence: evidencePath
474
+ };
475
+ const agent = {
476
+ ...reasonedSession,
477
+ id: String(session.agent_id || session.id || sessionId),
478
+ session_id: sessionId,
479
+ session_generation_id: String(session.session_key || sessionId),
480
+ session_artifact_dir: artifact.relative
481
+ };
482
+ await writeJsonAtomic(path.join(agentRoot, evidencePath), evidence);
483
+ await writeJsonAtomic(path.join(agentRoot, 'sessions', `${sessionKey}.json`), { ...reasonedSession, schema: 'sks.agent-session-record.v1' });
484
+ await writeJsonAtomic(path.join(artifact.absolute, 'agent-session-record.json'), { ...reasonedSession, schema: 'sks.agent-session-record.v1' });
485
+ const closeReport = await closeAgentTerminalSession(agentRoot, agent, {
486
+ exitCode: 124,
487
+ status: 'timed_out',
488
+ ...(session.slot_id ? { slotId: String(session.slot_id) } : {}),
489
+ ...(Number.isFinite(Number(session.generation_index)) ? { generationIndex: Number(session.generation_index) } : {}),
490
+ requireGeneration: Boolean(session.slot_id && Number.isFinite(Number(session.generation_index)))
491
+ });
492
+ const terminalPath = path.join(artifact.absolute, 'agent-terminal-session.json');
493
+ const terminalRecord = await readJson(terminalPath, null);
494
+ await writeJsonAtomic(terminalPath, { ...terminalRecord, close_status: 'timed_out', close_reason: STALE_SESSION_REASON, terminalization_evidence: evidencePath });
495
+ await writeJsonAtomic(path.join(agentRoot, closeReportPath), { ...closeReport, status: 'timed_out', reason: STALE_SESSION_REASON, terminalization_evidence: evidencePath });
496
+ const generation = await closeAgentSessionGeneration(agentRoot, sessionId, { status: 'blocked', terminalCloseReportPath: closeReportPath });
497
+ await appendAgentLedgerEvent(agentRoot, {
498
+ agent_id: agent.id,
499
+ session_id: sessionId,
500
+ event_type: 'stale_session_terminalized',
501
+ payload: evidence
502
+ });
503
+ // closeAgentSession atomically replaces the session shard and then the
504
+ // canonical aggregate, so registry state is the final commit point.
505
+ const canonical = await closeAgentSession(agentRoot, agent, 'timed_out');
506
+ return {
507
+ session_id: sessionId,
508
+ status: canonical.status,
509
+ generation_status: generation?.status || null,
510
+ closed_at: canonical.closed_at,
511
+ transaction_id: transactionId,
512
+ canonical_registry: 'agent-sessions.json',
513
+ session_record: path.join(artifact.relative, 'agent-session-record.json'),
514
+ terminal_record: path.join(artifact.relative, 'agent-terminal-session.json'),
515
+ terminal_close_report: closeReportPath,
516
+ evidence: evidencePath
517
+ };
518
+ }
223
519
  function buildCleanupProof(input) {
224
520
  const byKind = (kind, status) => input.actions.filter((row) => row.kind === kind && (!status || row.status === status));
225
521
  const failed = input.actions.filter((row) => row.status === 'failed');
@@ -234,6 +530,10 @@ function buildCleanupProof(input) {
234
530
  apply: input.apply,
235
531
  stale_processes_found: byKind('terminate_process').map((row) => row.target),
236
532
  stale_processes_killed: byKind('terminate_process', 'applied').map((row) => row.target),
533
+ stale_sessions_found: byKind('terminalize_stale_session').map((row) => row.target),
534
+ stale_sessions_terminalization_planned: byKind('terminalize_stale_session', 'planned').map((row) => row.target),
535
+ stale_sessions_terminalized: byKind('terminalize_stale_session', 'applied').map((row) => row.target),
536
+ stale_session_terminalization_failures: byKind('terminalize_stale_session', 'failed').map((row) => row.target),
237
537
  process_trees: byKind('terminate_process').map((row) => ({ target: row.target, tree: row.process_tree || [] })),
238
538
  process_tree_count: byKind('terminate_process').filter((row) => (row.process_tree || []).length > 0).length,
239
539
  sigterm_planned: input.actions.filter((row) => row.status === 'planned' && row.signal_sequence?.includes('SIGTERM')).map((row) => row.target),
@@ -255,6 +555,7 @@ function buildCleanupProof(input) {
255
555
  skipped_active_sessions: [...new Set([...input.activeSessionIds, ...byKind('skip_active_session').map((row) => row.target)])].filter(Boolean),
256
556
  skipped_foreign_namespace: byKind('skip_foreign_namespace').map((row) => row.target),
257
557
  terminal_transcripts_preserved: byKind('archive_transcript_keep').map((row) => row.target),
558
+ session_cleanup: input.sessionCleanup,
258
559
  action_count: input.actions.length,
259
560
  applied_count: input.actions.filter((row) => row.status === 'applied').length,
260
561
  failed_count: failed.length,
@@ -344,9 +645,10 @@ async function applyAction(input) {
344
645
  }
345
646
  async function staleLockFiles(lockDir, projectHash, now, staleMs) {
346
647
  const out = [];
347
- if (!lockDir || !namespaceOwnsPath(lockDir, projectHash) || !(await exists(lockDir)))
648
+ const ownedLockDir = await resolveOwnedNamespacePath(lockDir, projectHash);
649
+ if (!ownedLockDir)
348
650
  return out;
349
- for (const file of await listFiles(lockDir)) {
651
+ for (const file of await listFiles(ownedLockDir)) {
350
652
  const stat = await fsp.stat(file).catch(() => null);
351
653
  if (stat && now - stat.mtimeMs > staleMs)
352
654
  out.push(file);
@@ -369,22 +671,6 @@ async function listFiles(dir) {
369
671
  }
370
672
  return out;
371
673
  }
372
- function namespaceOwnsPath(candidate, projectHash) {
373
- return Boolean(candidate && (!projectHash || candidate.includes(projectHash)));
374
- }
375
- function processReportInNamespace(report, projectHash) {
376
- if (!projectHash)
377
- return true;
378
- const raw = JSON.stringify({
379
- project_hash: report?.project_hash,
380
- root_hash: report?.root_hash,
381
- project_namespace: report?.project_namespace,
382
- cwd: report?.cwd,
383
- stdout_log: report?.stdout_log,
384
- stderr_log: report?.stderr_log
385
- });
386
- return raw === '{}' || raw.includes(projectHash) || (!report?.project_hash && !report?.root_hash && !report?.project_namespace);
387
- }
388
674
  function processIsAlive(pid) {
389
675
  try {
390
676
  process.kill(pid, 0);
@@ -405,12 +691,19 @@ async function readProcessTree(rootPid) {
405
691
  return { pid: Number(match[1]), ppid: Number(match[2]), command: match[3] || '' };
406
692
  }).filter(Boolean);
407
693
  const byParent = new Map();
694
+ const byPid = new Map();
408
695
  for (const row of rows)
409
696
  byParent.set(row.ppid, [...(byParent.get(row.ppid) || []), row]);
697
+ for (const row of rows)
698
+ byPid.set(row.pid, row);
410
699
  const out = [];
700
+ const visited = new Set();
411
701
  const visit = (pid) => {
412
- const current = rows.find((row) => row.pid === pid);
413
- if (current && !out.some((row) => row.pid === current.pid))
702
+ if (visited.has(pid))
703
+ return;
704
+ visited.add(pid);
705
+ const current = byPid.get(pid);
706
+ if (current)
414
707
  out.push(current);
415
708
  for (const child of byParent.get(pid) || [])
416
709
  visit(child.pid);
@@ -1,10 +1,29 @@
1
1
  import path from 'node:path';
2
2
  import { nowIso, readJson, writeJsonAtomic } from '../fsx.js';
3
+ export const AGENT_TERMINAL_SESSION_STATUSES = new Set([
4
+ 'blocked',
5
+ 'cancelled',
6
+ 'canceled',
7
+ 'closed',
8
+ 'complete',
9
+ 'completed',
10
+ 'done',
11
+ 'exited',
12
+ 'failed',
13
+ 'killed',
14
+ 'stopped',
15
+ 'terminated',
16
+ 'timed_out',
17
+ 'timeout'
18
+ ]);
19
+ export function isAgentTerminalSessionStatus(value) {
20
+ return AGENT_TERMINAL_SESSION_STATUSES.has(String(value || '').toLowerCase());
21
+ }
3
22
  export async function writeAgentCleanupReport(root) {
4
23
  const sessions = await readJson(path.join(root, 'agent-sessions.json'), { sessions: {} });
5
24
  const rows = Object.values(sessions.sessions || {});
6
25
  const closed = rows.filter((session) => String(session.status) === 'closed');
7
- const terminal = rows.filter((session) => ['closed', 'blocked', 'failed', 'killed', 'timed_out'].includes(String(session.status)));
26
+ const terminal = rows.filter((session) => isAgentTerminalSessionStatus(session.status));
8
27
  const report = {
9
28
  schema: 'sks.agent-cleanup.v1',
10
29
  generated_at: nowIso(),
@@ -51,6 +51,7 @@ export function parseAgentCommandArgs(command, args = []) {
51
51
  const graceMs = Number(readOption(args, '--grace-ms', 750));
52
52
  const killEscalation = hasFlag(args, '--kill-escalation') || !hasFlag(args, '--no-kill-escalation');
53
53
  const codexApp = hasFlag(args, '--codex-app');
54
+ const legacyNativeRuntime = hasFlag(args, '--legacy-native-runtime');
54
55
  const positionals = positionalArgs(rest, new Set(['--agents', '--target-active-slots', '--work-items', '--minimum-work-items', '--max-queue-expansion', '--concurrency', '--backend', '--route', '--mission', '--mission-id', '--agent', '--lane', '--stale-ms', '--grace-ms', '--profile', '--write-mode', '--max-write-agents', '--patch-entry-id', '--patch-entry', '--service-tier', '--zellij-session-name', '--worker-placement', '--zellij-visible-pane-cap', '--intake', '--agent-root', '--artifact-dir', '--result-path', '--heartbeat-path', '--patch-envelope-path', '--ollama-model', '--local-model-model', '--ollama-base-url', '--local-model-base-url']));
55
56
  const missionDefault = action === 'run' || action === 'spawn' || action === 'plan' ? '' : 'latest';
56
57
  const positionalMission = action === 'run' || action === 'spawn' || action === 'plan' ? '' : (positionals[0] || '');
@@ -58,8 +59,9 @@ export function parseAgentCommandArgs(command, args = []) {
58
59
  const lane = String(readOption(args, '--agent', readOption(args, '--lane', '')));
59
60
  const patchEntryId = String(readOption(args, '--patch-entry-id', readOption(args, '--patch-entry', '')));
60
61
  const promptPositionals = positionalMission ? positionals.slice(1) : positionals;
62
+ const promptExplicit = promptPositionals.length > 0;
61
63
  const prompt = promptPositionals.join(' ').trim() || 'Native agent run';
62
- return { command, action, prompt, route, agents, targetActiveSlots, desiredWorkItemCount, minimumWorkItems, maxQueueExpansion, concurrency, backend, backendExplicit, mock, real, readonly, profile, writeMode, applyPatches, dryRunPatches, maxWriteAgents, fastMode, serviceTier, noFast, ollamaEnabled: useOllama && !noOllama, noOllama, ollamaModel, ollamaBaseUrl, zellijSessionName, zellijPaneWorker, workerPlacement, zellijVisiblePaneCap, apply, dryRun, drain, staleMs, graceMs, killEscalation, json, missionId, lane, codexApp, patchEntryId };
64
+ return { command, action, prompt, promptExplicit, route, agents, targetActiveSlots, desiredWorkItemCount, minimumWorkItems, maxQueueExpansion, concurrency, backend, backendExplicit, mock, real, readonly, profile, writeMode, applyPatches, dryRunPatches, maxWriteAgents, fastMode, serviceTier, noFast, ollamaEnabled: useOllama && !noOllama, noOllama, ollamaModel, ollamaBaseUrl, zellijSessionName, zellijPaneWorker, workerPlacement, zellijVisiblePaneCap, apply, dryRun, drain, staleMs, graceMs, killEscalation, json, missionId, lane, codexApp, patchEntryId, legacyNativeRuntime };
63
65
  }
64
66
  export function resolveZellijVisiblePaneCap(value = '', explicit = false) {
65
67
  const requested = Number(value);