sneakoscope 8.6.6 → 9.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (200) hide show
  1. package/README.md +1 -1
  2. package/config/skills-hash-ledger.v1.json +0 -14
  3. package/crates/sks-core/Cargo.lock +1 -1
  4. package/crates/sks-core/Cargo.toml +1 -1
  5. package/dist/cli/command-manifest-lite.js +0 -1
  6. package/dist/cli/command-registry.js +0 -1
  7. package/dist/commands/doctor.js +11 -20
  8. package/dist/config/skills-manifest.json +1 -19
  9. package/dist/core/agents/agent-janitor.js +7 -0
  10. package/dist/core/agents/agent-orchestrator.js +5 -13
  11. package/dist/core/agents/agent-output-validator.js +1 -2
  12. package/dist/core/agents/agent-patch-schema.js +1 -2
  13. package/dist/core/agents/agent-proof-evidence.js +14 -19
  14. package/dist/core/agents/agent-recursion-guard.js +19 -5
  15. package/dist/core/agents/agent-schema.js +1 -1
  16. package/dist/core/agents/native-cli-worker-runtime.js +83 -60
  17. package/dist/core/agents/native-cli-worker.js +1 -1
  18. package/dist/core/agents/native-worker-backend-router.js +9 -64
  19. package/dist/core/align/align-context-index.js +68 -0
  20. package/dist/core/align/align-route.js +2 -0
  21. package/dist/core/align/code-navigation-align.js +42 -42
  22. package/dist/core/codex-control/codex-control-proof.js +0 -1
  23. package/dist/core/codex-control/codex-task-runner.js +2 -118
  24. package/dist/core/codex-control/gpt-final-arbiter.js +11 -20
  25. package/dist/core/codex-control/gpt-final-gate.js +31 -0
  26. package/dist/core/codex-control/gpt-final-proof-pack.js +8 -9
  27. package/dist/core/codex-control/model-call-concurrency.js +0 -2
  28. package/dist/core/codex-lb/combined-catalog/contracts.js +1 -0
  29. package/dist/core/codex-lb/desktop-bridge/http-forward.js +76 -7
  30. package/dist/core/codex-lb/desktop-bridge/server.js +2 -1
  31. package/dist/core/codex-lb/desktop-controller-v3/catalog.js +2 -1
  32. package/dist/core/codex-lb/desktop-controller-v3/status.js +12 -3
  33. package/dist/core/commands/intent-normalization/normalizer.js +0 -2
  34. package/dist/core/commands/run-command.js +1 -30
  35. package/dist/core/commands/search-command.js +4 -1
  36. package/dist/core/commands/triwiki-atlas-command.js +4 -4
  37. package/dist/core/commands/triwiki-graph-command.js +2 -2
  38. package/dist/core/commands/wiki-command.js +2 -2
  39. package/dist/core/doctor/doctor-dirty-planner.js +4 -0
  40. package/dist/core/doctor/doctor-readiness-matrix.js +0 -34
  41. package/dist/core/feature-fixtures.js +0 -10
  42. package/dist/core/fsx.js +1 -1
  43. package/dist/core/git-simple.js +2 -136
  44. package/dist/core/hooks-runtime/context-graph-freshness-preflight.js +2 -2
  45. package/dist/core/hooks-runtime/official-subagent-lifecycle.js +8 -1
  46. package/dist/core/init/skills.js +0 -2
  47. package/dist/core/init.js +4 -0
  48. package/dist/core/install/installed-package-smoke.js +1 -0
  49. package/dist/core/loops/loop-gpt-final-arbiter.js +1 -2
  50. package/dist/core/loops/loop-planner.js +1 -1
  51. package/dist/core/naruto/context-graph-advisor-pairs.js +29 -0
  52. package/dist/core/naruto/context-graph-advisor-scope.js +77 -139
  53. package/dist/core/naruto/context-graph-advisor.js +0 -0
  54. package/dist/core/naruto/hardware-capacity-probe.js +0 -1
  55. package/dist/core/naruto/naruto-concurrency-governor.js +4 -8
  56. package/dist/core/naruto/naruto-verification-dag.js +0 -1
  57. package/dist/core/pipeline/finalize-pipeline-result.js +1 -4
  58. package/dist/core/pipeline/gpt-final-required.js +4 -10
  59. package/dist/core/qa-loop/qa-loop-budget-policy.js +0 -1
  60. package/dist/core/release/gate-affected-globs.js +93 -0
  61. package/dist/core/release/gate-manifest.js +2 -88
  62. package/dist/core/release/release-gate-batch-runner.js +1 -1
  63. package/dist/core/release/release-gate-node.js +0 -1
  64. package/dist/core/release/release-gate-resource-governor.js +0 -1
  65. package/dist/core/research/research-claim-synthesizer.js +0 -2
  66. package/dist/core/research/research-falsification-runner.js +0 -2
  67. package/dist/core/research/research-stage-runner.js +2 -7
  68. package/dist/core/research/research-super-search.js +0 -2
  69. package/dist/core/research/research-synthesis-writer.js +0 -2
  70. package/dist/core/router/capability-card.js +0 -13
  71. package/dist/core/router/route-cache.js +0 -2
  72. package/dist/core/router/ultra-router.js +1 -1
  73. package/dist/core/routes/dollar-manifest-lite.js +0 -4
  74. package/dist/core/routes.js +0 -19
  75. package/dist/core/runtime/task-profile.js +3 -0
  76. package/dist/core/runtime/verification-budget.js +25 -0
  77. package/dist/core/search/context-projection.js +130 -0
  78. package/dist/core/search/context.js +0 -0
  79. package/dist/core/skills/skill-agent-metadata.js +0 -2
  80. package/dist/core/subagents/official-subagent-preparation.js +12 -3
  81. package/dist/core/subagents/official-subagent-runner.js +7 -0
  82. package/dist/core/subagents/triwiki-attention.js +2 -1
  83. package/dist/core/triwiki/context-graph/compiler/cache-key.js +11 -2
  84. package/dist/core/triwiki/context-graph/compiler/fragment-manifest-schema.js +163 -0
  85. package/dist/core/triwiki/context-graph/compiler/fragment-manifest-store.js +41 -0
  86. package/dist/core/triwiki/context-graph/compiler/fragment-manifest.js +108 -0
  87. package/dist/core/triwiki/context-graph/compiler/fragment-merge.js +195 -0
  88. package/dist/core/triwiki/context-graph/compiler/fragment-plan.js +137 -0
  89. package/dist/core/triwiki/context-graph/compiler/fragment-store.js +82 -0
  90. package/dist/core/triwiki/context-graph/compiler/incremental-build.js +161 -0
  91. package/dist/core/triwiki/context-graph/compiler/incremental-extract.js +94 -0
  92. package/dist/core/triwiki/context-graph/compiler/k-way-merge.js +92 -0
  93. package/dist/core/triwiki/context-graph/compiler/publish-index.js +98 -0
  94. package/dist/core/triwiki/context-graph/compiler/source-fragment.js +74 -0
  95. package/dist/core/triwiki/context-graph/contracts.js +2 -0
  96. package/dist/core/triwiki/context-graph/extractors/evidence/claims.js +4 -1
  97. package/dist/core/triwiki/context-graph/extractors/evidence/redaction.js +53 -0
  98. package/dist/core/triwiki/context-graph/projections/anchors.js +23 -21
  99. package/dist/core/triwiki/context-graph/projections/attention.js +30 -36
  100. package/dist/core/triwiki/context-graph/projections/code-pack-entry.js +92 -0
  101. package/dist/core/triwiki/context-graph/projections/code-pack-workspace.js +35 -44
  102. package/dist/core/triwiki/context-graph/projections/code-pack.js +21 -101
  103. package/dist/core/triwiki/context-graph/projections/graph-facts.js +103 -0
  104. package/dist/core/triwiki/context-graph/projections/index.js +3 -0
  105. package/dist/core/triwiki/context-graph/projections/module-view.js +46 -89
  106. package/dist/core/triwiki/context-graph/projections/node-summary.js +18 -32
  107. package/dist/core/triwiki/context-graph/projections/projection-candidate.js +47 -0
  108. package/dist/core/triwiki/context-graph/query/cache.js +191 -0
  109. package/dist/core/triwiki/context-graph/query/changed-path-seeds.js +29 -0
  110. package/dist/core/triwiki/context-graph/query/hydrate-chain.js +105 -0
  111. package/dist/core/triwiki/context-graph/query/hydrate-verify.js +83 -0
  112. package/dist/core/triwiki/context-graph/query/hydrate.js +0 -0
  113. package/dist/core/triwiki/context-graph/query/index.js +6 -0
  114. package/dist/core/triwiki/context-graph/query/kernel-candidates.js +128 -0
  115. package/dist/core/triwiki/context-graph/query/kernel-frontier.js +141 -0
  116. package/dist/core/triwiki/context-graph/query/kernel-fuse.js +240 -0
  117. package/dist/core/triwiki/context-graph/query/kernel-lanes.js +149 -0
  118. package/dist/core/triwiki/context-graph/query/kernel-plan.js +178 -0
  119. package/dist/core/triwiki/context-graph/query/kernel-safety.js +94 -0
  120. package/dist/core/triwiki/context-graph/query/kernel-select.js +154 -0
  121. package/dist/core/triwiki/context-graph/query/kernel-traverse.js +194 -0
  122. package/dist/core/triwiki/context-graph/query/kernel-types.js +63 -0
  123. package/dist/core/triwiki/context-graph/query/kernel.js +69 -0
  124. package/dist/core/triwiki/context-graph/query/name-anchors.js +20 -0
  125. package/dist/core/triwiki/context-graph/query/ranking-config.js +56 -0
  126. package/dist/core/triwiki/context-graph/query/walk.js +136 -0
  127. package/dist/core/triwiki/context-graph/query/workspace.js +110 -0
  128. package/dist/core/triwiki/context-graph/runtime-index/format-contract.js +111 -0
  129. package/dist/core/triwiki/context-graph/runtime-index/format-header.js +148 -0
  130. package/dist/core/triwiki/context-graph/runtime-index/format-primitives.js +57 -0
  131. package/dist/core/triwiki/context-graph/runtime-index/format-sections.js +57 -0
  132. package/dist/core/triwiki/context-graph/runtime-index/format.js +4 -0
  133. package/dist/core/triwiki/context-graph/runtime-index/lexicon-bm25.js +80 -0
  134. package/dist/core/triwiki/context-graph/runtime-index/lexicon-builder.js +194 -0
  135. package/dist/core/triwiki/context-graph/runtime-index/lexicon-contract.js +72 -0
  136. package/dist/core/triwiki/context-graph/runtime-index/lexicon-text.js +124 -0
  137. package/dist/core/triwiki/context-graph/runtime-index/lexicon-tokenizer.js +237 -0
  138. package/dist/core/triwiki/context-graph/runtime-index/lexicon.js +5 -0
  139. package/dist/core/triwiki/context-graph/runtime-index/reader-cursor.js +132 -0
  140. package/dist/core/triwiki/context-graph/runtime-index/reader-errors.js +39 -0
  141. package/dist/core/triwiki/context-graph/runtime-index/reader-hydrate.js +129 -0
  142. package/dist/core/triwiki/context-graph/runtime-index/reader-layout.js +104 -0
  143. package/dist/core/triwiki/context-graph/runtime-index/reader-lookup.js +90 -0
  144. package/dist/core/triwiki/context-graph/runtime-index/reader-names.js +57 -0
  145. package/dist/core/triwiki/context-graph/runtime-index/reader-types.js +2 -0
  146. package/dist/core/triwiki/context-graph/runtime-index/reader-validate.js +198 -0
  147. package/dist/core/triwiki/context-graph/runtime-index/reader.js +146 -0
  148. package/dist/core/triwiki/context-graph/runtime-index/writer-assemble.js +49 -0
  149. package/dist/core/triwiki/context-graph/runtime-index/writer-contract.js +112 -0
  150. package/dist/core/triwiki/context-graph/runtime-index/writer-lexical.js +139 -0
  151. package/dist/core/triwiki/context-graph/runtime-index/writer-tables.js +158 -0
  152. package/dist/core/triwiki/context-graph/runtime-index/writer-types.js +1 -0
  153. package/dist/core/triwiki/context-graph/runtime-index/writer.js +217 -0
  154. package/dist/core/triwiki/context-graph/store/generation-commit.js +171 -0
  155. package/dist/core/triwiki/context-graph/store/generation-errors.js +60 -0
  156. package/dist/core/triwiki/context-graph/store/generation-io.js +45 -0
  157. package/dist/core/triwiki/context-graph/store/generation-layout.js +42 -0
  158. package/dist/core/triwiki/context-graph/store/generation-pointer.js +131 -0
  159. package/dist/core/triwiki/context-graph/store/generation-recovery.js +89 -0
  160. package/dist/core/triwiki/context-graph/store/generation-resolve.js +24 -0
  161. package/dist/core/triwiki/context-graph/store/generation-retention.js +57 -0
  162. package/dist/core/triwiki/context-graph/store/generation-store.js +9 -0
  163. package/dist/core/triwiki/context-graph/store/generation-verify.js +48 -0
  164. package/dist/core/triwiki/context-graph/store/index-freshness.js +107 -0
  165. package/dist/core/triwiki/context-graph/store/operation-journal-recovery.js +37 -0
  166. package/dist/core/triwiki/context-graph/store/operation-journal-schema.js +225 -0
  167. package/dist/core/triwiki/context-graph/store/operation-journal.js +32 -0
  168. package/dist/core/triwiki/context-graph/store/snapshot-store.js +16 -8
  169. package/dist/core/verification/context-graph-affected.js +139 -98
  170. package/dist/core/verification/machine-feedback.js +19 -3
  171. package/dist/core/verification/verification-worker-pool.js +3 -1
  172. package/dist/core/version.js +1 -1
  173. package/dist/scripts/architecture-map-check.js +1 -1
  174. package/dist/scripts/context-graph-v2-check.js +327 -0
  175. package/dist/scripts/gate-policy-audit-check.js +2 -2
  176. package/dist/scripts/{local-collab-all-pipelines-final-gpt-check.js → gpt-final-all-pipelines-check.js} +5 -6
  177. package/dist/scripts/qa-loop-budget-policy-check.js +1 -1
  178. package/package.json +2 -2
  179. package/release-gates.v2.json +131 -3
  180. package/schemas/codex/agent-result.schema.json +1 -6
  181. package/schemas/naruto/naruto-concurrency-governor.schema.json +0 -1
  182. package/schemas/release/release-gate-node.schema.json +1 -1
  183. package/dist/core/agents/agent-runner-ollama.js +0 -416
  184. package/dist/core/agents/ollama-worker-config.js +0 -266
  185. package/dist/core/commands/local-model-command.js +0 -165
  186. package/dist/core/local-llm/local-collaboration-policy.js +0 -92
  187. package/dist/core/local-llm/local-llm-backpressure.js +0 -19
  188. package/dist/core/local-llm/local-llm-capability.js +0 -28
  189. package/dist/core/local-llm/local-llm-client.js +0 -99
  190. package/dist/core/local-llm/local-llm-context-cache.js +0 -20
  191. package/dist/core/local-llm/local-llm-control-adapter.js +0 -100
  192. package/dist/core/local-llm/local-llm-json-repair.js +0 -51
  193. package/dist/core/local-llm/local-llm-metrics.js +0 -41
  194. package/dist/core/local-llm/local-llm-ollama-client.js +0 -66
  195. package/dist/core/local-llm/local-llm-openai-compatible-client.js +0 -29
  196. package/dist/core/local-llm/local-llm-schema-enforcer.js +0 -14
  197. package/dist/core/local-llm/local-llm-smoke.js +0 -82
  198. package/dist/core/local-llm/local-worker-eligibility.js +0 -26
  199. package/schemas/local-llm/local-collaboration-policy.schema.json +0 -57
  200. package/schemas/local-llm/local-model-config.schema.json +0 -74
package/README.md CHANGED
@@ -22,7 +22,7 @@ Proof-first orchestration for Codex CLI, ChatGPT Desktop, AI coding agents, mult
22
22
  Sneakoscope Codex (`sks`) is an open-source trust layer for Codex CLI and ChatGPT Desktop. It coordinates bounded AI coding agents, records machine-verifiable evidence, preserves project memory, and blocks release claims that are not supported by current tests or artifacts. Search visibility outcomes are measured separately; SKS does not promise rankings or traffic.
23
23
  <!-- END SKS SEARCH VISIBILITY MARKETING -->
24
24
 
25
- This README documents package **SKS 8.6.6** — its own identity, read from `package.json` and subject to release-gate verification, not advice about what to install.
25
+ This README documents package **SKS 9.0.0** — its own identity, read from `package.json` and subject to release-gate verification, not advice about what to install.
26
26
 
27
27
  Use the official latest stable SKS and Codex CLI releases. The Codex compatibility SSOT is always the **current latest stable** host; capability probes measure what that host can actually do. Product docs do not crown a fixed `0.x.y` string as SSOT (release pins and schema directories are measured artifacts for the current package, not a permanent product version claim). Menu Bar / Center induce updates to the latest stable build. Run `sks update-check` for what is installed and read the capability report for what is supported. Install SSOT is npm `sneakoscope@latest`; PATH `sks` and Menu Bar stamped generation must match that version or gates fail. It resolves managed SKS skills from the authoritative global install, preserves a runnable Naruto child slot when `max_threads=2`, and keeps Menu Bar repair transactional so stamped generations remain verifiable. Naruto uses stable opt-in multi-agent V2 when the host exposes it (Codex official multi-agent wrap-only; SKS does not reimplement a parallel runtime). Local code search is mode-separated (`sks search files|text|structure|symbol|context`); `context` is answered by the compiled TriWiki Context Graph (`context-graph.json` is exhaustive authority; `context-pack.json` and managed `AGENTS.md` are bounded projections) — see [docs/architecture/context-graph.md](https://github.com/mandarange/Sneakoscope-Codex/blob/main/docs/architecture/context-graph.md) and [docs/PRODUCT-CONTRACT.md](https://github.com/mandarange/Sneakoscope-Codex/blob/main/docs/PRODUCT-CONTRACT.md). See [CHANGELOG.md](https://github.com/mandarange/Sneakoscope-Codex/blob/main/CHANGELOG.md).
28
28
 
@@ -389,20 +389,6 @@
389
389
  "16b2b813d202ca51d2ea4fe0da918eddf9494db7ab1356352d4188a5da3496b1"
390
390
  ]
391
391
  },
392
- {
393
- "canonical_name": "sks-with-local-llm-off",
394
- "trusted_sha256": [
395
- "4609c43a671c649b2574aebf035e0e8200b29bb893d176567e92f14d2f3aa92c",
396
- "86d3a860b438c91c2a5b4cc8ac9c8e7477008f9b689602ddcf14a9e3b759923d"
397
- ]
398
- },
399
- {
400
- "canonical_name": "sks-with-local-llm-on",
401
- "trusted_sha256": [
402
- "11da3f94d77b0f9fe76dee2e99d058cf1495fdc4eaf3e2fb6e43dae66f7d2cd3",
403
- "27e1ff08b95428d6b623d06358d5d114ff02673a5c97d8f180dd75859682cd6c"
404
- ]
405
- },
406
392
  {
407
393
  "canonical_name": "sks-work",
408
394
  "trusted_sha256": [
@@ -259,7 +259,7 @@ dependencies = [
259
259
 
260
260
  [[package]]
261
261
  name = "sks-core"
262
- version = "8.6.6"
262
+ version = "9.0.0"
263
263
  dependencies = [
264
264
  "globset",
265
265
  "grep-matcher",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "sks-core"
3
- version = "8.6.6"
3
+ version = "9.0.0"
4
4
  edition = "2021"
5
5
 
6
6
  [dependencies]
@@ -47,7 +47,6 @@ const COMMAND_MANIFEST_LITE_BASE = [
47
47
  { name: 'commit', summary: 'Create a simple git commit', maturity: 'stable' },
48
48
  { name: 'commit-and-push', summary: 'Create a simple git commit and push', maturity: 'stable' },
49
49
  { name: 'dfix', summary: 'Run DFix diagnose/plan/patch/verify loop', maturity: 'stable', mutatesRouteState: true },
50
- { name: 'with-local-llm', summary: 'Enable or inspect local Ollama worker backend', maturity: 'beta' },
51
50
  { name: 'naruto', summary: 'Run the $sks-naruto Codex official subagent workflow', maturity: 'labs', mutatesRouteState: true },
52
51
  { name: 'stop-gate', summary: 'Check canonical stop-gate resolution for a route/mission', maturity: 'beta', readonly: true, skipMigrationGate: true, allowedDuringActiveRoute: true, diagnostic: true },
53
52
  { name: 'route', summary: 'Inspect or close active route state', maturity: 'beta', skipMigrationGate: true, allowedDuringActiveRoute: true, diagnostic: true },
@@ -195,7 +195,6 @@ const COMMAND_DEFINITIONS = {
195
195
  commit: entry('stable', 'Create a simple git commit', 'dist/commands/commit.js', directCommand(() => import('../commands/commit.js'), 'dist/commands/commit.js')),
196
196
  'commit-and-push': entry('stable', 'Create a simple git commit and push', 'dist/commands/commit-and-push.js', directCommand(() => import('../commands/commit-and-push.js'), 'dist/commands/commit-and-push.js')),
197
197
  dfix: routeStateMutator(entry('stable', 'Run DFix diagnose/plan/patch/verify loop', 'dist/core/commands/dfix-command.js', commandArgsCommand(() => import('../core/commands/dfix-command.js'), 'dfixCommand', 'dist/core/commands/dfix-command.js')), ['dfix-gate.json']),
198
- 'with-local-llm': entry('beta', 'Enable or inspect local Ollama worker backend', 'dist/core/commands/local-model-command.js', argsCommand(() => import('../core/commands/local-model-command.js'), 'localModelCommand', 'dist/core/commands/local-model-command.js')),
199
198
  naruto: routeStateMutator(entry('labs', 'Run the $sks-naruto Codex official subagent workflow', 'dist/core/commands/naruto-command.js', argsCommand(() => import('../core/commands/naruto-command.js'), 'narutoCommand', 'dist/core/commands/naruto-command.js')), ['naruto-gate.json', 'stop-gate.json']),
200
199
  'stop-gate': readOnly(entry('beta', 'Check canonical stop-gate resolution for a route/mission', 'dist/core/commands/stop-gate-command.js', commandArgsCommand(() => import('../core/commands/stop-gate-command.js'), 'stopGateCommand', 'dist/core/commands/stop-gate-command.js'))),
201
200
  route: activeRouteDiagnostic(entry('beta', 'Inspect or close active route state', 'dist/core/commands/route-command.js', subcommand(() => import('../core/commands/route-command.js'), 'routeCommand', 'dist/core/commands/route-command.js', 'status'))),
@@ -15,7 +15,6 @@ import { inspectCodexConfigReadability } from '../core/codex/codex-config-readab
15
15
  import { inspectOAuthCallbackPortConflict, oauthCallbackDoctorGuidance } from '../core/codex/oauth-callback-port-diagnostic.js';
16
16
  import { inventoryCodexPermissionProfiles } from '../core/codex/codex-permission-profiles.js';
17
17
  import { resolveProviderContext } from '../core/provider/provider-context.js';
18
- import { readLocalModelConfig } from '../core/agents/ollama-worker-config.js';
19
18
  import { writeCodexCurrentAppCapabilityArtifacts } from '../core/codex-control/codex-current-app-capability.js';
20
19
  import { writeCodexPluginInventoryArtifacts, pluginAppTemplatePolicy } from '../core/codex-plugins/codex-plugin-json.js';
21
20
  import { writeMcpPluginInventoryArtifacts } from '../core/mcp/mcp-plugin-inventory.js';
@@ -444,7 +443,6 @@ async function runDoctorJsonFastPath(args = [], root) {
444
443
  doctor_fix_transaction: null,
445
444
  doctor_fix_postcheck: null,
446
445
  postcheck: null,
447
- local_model: null,
448
446
  agent_role_config: { schema: 'sks.agent-role-config-repair.v1', ok: true, apply: false, skipped: true, blockers: [] },
449
447
  codex_permission_profiles: { skipped: true, reason: 'doctor_json_fast_path_optional_diagnostics_skipped' },
450
448
  command_aliases: { schema: 'sks.command-alias-cleanup.v1', ok: true, skipped: true, reason: 'doctor_json_fast_path_no_write' },
@@ -669,7 +667,7 @@ async function runDoctor(args = [], root, doctorFix, deps = {}) {
669
667
  const codexApp = deepDiagnostics
670
668
  ? await codexAppIntegrationStatus({ codex }).catch((err) => ({ ok: false, error: err.message }))
671
669
  : { ok: false, skipped: true, warnings: ['codex_app_optional_diagnostic_skipped'] };
672
- const desktopBridge = await inspectDoctorDesktopBridgeStatus({
670
+ const desktopBridgeBeforeFix = await inspectDoctorDesktopBridgeStatus({
673
671
  processEnv: process.env
674
672
  }, { desktopBridgeStatusImpl: deps.desktopBridgeStatusImpl });
675
673
  const providerContext = deepDiagnostics
@@ -1034,11 +1032,12 @@ async function runDoctor(args = [], root, doctorFix, deps = {}) {
1034
1032
  rollback_evidence: 'combined_catalog_previous_generation_preserved'
1035
1033
  };
1036
1034
  try {
1035
+ const bridgeHome = path.resolve(process.env.HOME || os.homedir());
1037
1036
  const restarted = await restartStaleDesktopBridgeRuntime({
1038
- home: path.resolve(process.env.HOME || os.homedir()),
1037
+ home: bridgeHome,
1039
1038
  fix: doctorFix,
1040
1039
  });
1041
- const status = await desktopBridgeStatusV3({ home: root, env: process.env });
1040
+ const status = await desktopBridgeStatusV3({ home: bridgeHome, env: process.env });
1042
1041
  const blockers = (status?.readiness?.blockers || []).map(String);
1043
1042
  const stale = blockers.filter((blocker) => blocker.endsWith('_catalog_stale'));
1044
1043
  if (!status?.management?.managed || stale.length === 0) {
@@ -1053,9 +1052,9 @@ async function runDoctor(args = [], root, doctorFix, deps = {}) {
1053
1052
  const attempts = [];
1054
1053
  let syncedAndVerified = false;
1055
1054
  for (let attempt = 1; attempt <= CATALOG_REPAIR_MAX_ATTEMPTS; attempt += 1) {
1056
- const sync = await executeDesktopBridgeCommandV3({ operation: 'catalog.sync' }, { home: root, env: process.env });
1055
+ const sync = await executeDesktopBridgeCommandV3({ operation: 'catalog.sync' }, { home: bridgeHome, env: process.env });
1057
1056
  const commandOk = sync?.ok === true && sync?.execution?.ok === true;
1058
- const after = await desktopBridgeStatusV3({ home: root, env: process.env });
1057
+ const after = await desktopBridgeStatusV3({ home: bridgeHome, env: process.env });
1059
1058
  const stillStale = (after?.readiness?.blockers || [])
1060
1059
  .map(String).filter((blocker) => blocker.endsWith('_catalog_stale'));
1061
1060
  if (commandOk && stillStale.length === 0) {
@@ -1105,7 +1104,11 @@ async function runDoctor(args = [], root, doctorFix, deps = {}) {
1105
1104
  }))
1106
1105
  : null;
1107
1106
  const doctorFixPostcheck = doctorFix ? (await import('../core/doctor/doctor-repair-postcheck.js')).doctorRepairPostcheck(doctorFixTransaction) : null;
1108
- const localModel = await readLocalModelConfig().catch(() => null);
1107
+ const desktopBridge = doctorFixTransaction
1108
+ ? await inspectDoctorDesktopBridgeStatus({
1109
+ processEnv: process.env
1110
+ }, { desktopBridgeStatusImpl: deps.desktopBridgeStatusImpl })
1111
+ : desktopBridgeBeforeFix;
1109
1112
  const permissionProfiles = await inventoryCodexPermissionProfiles(root, { writeReport: true });
1110
1113
  const startupRoleRepair = startupConfigRepair?.role_repair;
1111
1114
  const agentRoleConfigRepair = doctorFix && startupRoleRepair
@@ -1368,7 +1371,6 @@ async function runDoctor(args = [], root, doctorFix, deps = {}) {
1368
1371
  require_legacy_global_hook_cleanup: requireLegacyGlobalHookCleanup,
1369
1372
  require_legacy_generation_convergence: doctorFix && !migrationReceiptOwnsReconcile,
1370
1373
  skills: skillsReconcile,
1371
- local_model: localModel,
1372
1374
  agent_role_config: agentRoleConfigRepair,
1373
1375
  repair: configRepair,
1374
1376
  codex_app_ui: codexAppUi,
@@ -1545,7 +1547,6 @@ async function runDoctor(args = [], root, doctorFix, deps = {}) {
1545
1547
  required_blockers: doctorFixPostcheck.required_blockers || [],
1546
1548
  optional_warnings: doctorFixPostcheck.optional_warnings || []
1547
1549
  } : null,
1548
- local_model: localModel,
1549
1550
  agent_role_config: agentRoleConfigRepair,
1550
1551
  official_subagent_config: officialSubagentConfig,
1551
1552
  codex_permission_profiles: permissionProfiles,
@@ -1803,16 +1804,6 @@ async function runDoctor(args = [], root, doctorFix, deps = {}) {
1803
1804
  if (!desktopBridge.ok)
1804
1805
  for (const action of desktopBridge.recovery_actions || [])
1805
1806
  console.log(` action: ${action}`);
1806
- if (localModel) {
1807
- console.log('Local LLM:');
1808
- console.log(` enabled: ${localModel.enabled ? 'yes' : 'no'}`);
1809
- console.log(` status: ${localModel.status}`);
1810
- console.log(` provider: ${localModel.provider}`);
1811
- console.log(` model: ${localModel.model}`);
1812
- console.log(` endpoint: ${localModel.base_url}`);
1813
- console.log(` last smoke: ${localModel.last_smoke?.ok ? `ok ${localModel.last_smoke.latency_ms || 0}ms ${localModel.last_smoke.tokens_per_second || 0} tok/s` : 'missing'}`);
1814
- console.log(' final arbiter: GPT required');
1815
- }
1816
1807
  console.log(`Permissions: config profile and permission profile are tracked separately (${permissionProfiles.codex_config_profile_field}, ${permissionProfiles.codex_permission_profile_field})`);
1817
1808
  console.log('Ready:');
1818
1809
  console.log(` cli_ready: ${ready.cli_ready ? 'yes' : 'no'}`);
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schema": "sks.skills-manifest.v1",
3
- "package_version": "8.6.6",
3
+ "package_version": "9.0.0",
4
4
  "skills": [
5
5
  {
6
6
  "canonical_name": "sks",
@@ -485,24 +485,6 @@
485
485
  ],
486
486
  "deprecated_aliases": []
487
487
  },
488
- {
489
- "canonical_name": "sks-with-local-llm-off",
490
- "type": "official",
491
- "content_sha256": "4609c43a671c649b2574aebf035e0e8200b29bb893d176567e92f14d2f3aa92c",
492
- "hash_history": [
493
- "86d3a860b438c91c2a5b4cc8ac9c8e7477008f9b689602ddcf14a9e3b759923d"
494
- ],
495
- "deprecated_aliases": []
496
- },
497
- {
498
- "canonical_name": "sks-with-local-llm-on",
499
- "type": "official",
500
- "content_sha256": "11da3f94d77b0f9fe76dee2e99d058cf1495fdc4eaf3e2fb6e43dae66f7d2cd3",
501
- "hash_history": [
502
- "27e1ff08b95428d6b623d06358d5d114ff02673a5c97d8f180dd75859682cd6c"
503
- ],
504
- "deprecated_aliases": []
505
- },
506
488
  {
507
489
  "canonical_name": "sks-work",
508
490
  "type": "official",
@@ -3,6 +3,7 @@ import path from 'node:path';
3
3
  import { exists, nowIso, readJson, writeJsonAtomic } from '../fsx.js';
4
4
  import { normalizeAgentSessionRows } from './agent-session-rows.js';
5
5
  import { resolveOwnedNamespacePath } from './agent-namespace-safety.js';
6
+ import { runAgentCleanupExecutor } from './agent-cleanup-executor.js';
6
7
  export async function runAgentJanitor(input) {
7
8
  const staleMs = input.staleMs ?? 30 * 60 * 1000;
8
9
  const agentRoot = path.join(input.missionDir, 'agents');
@@ -39,6 +40,11 @@ export async function runAgentJanitor(input) {
39
40
  const orphanTempDirs = await scopedExistingPaths(Array.isArray(namespace?.orphan_temp_dirs) ? namespace.orphan_temp_dirs : [], projectHash, namespace?.temp_dir ? [namespace.temp_dir] : []);
40
41
  const staleLocks = await scopedStaleLockPaths(namespace?.lock_dir ? [namespace.lock_dir] : [], projectHash, staleMs);
41
42
  const cleaned = [];
43
+ const reaped = input.reapOrphanProcesses
44
+ ? await runAgentCleanupExecutor({ missionDir: input.missionDir, missionId: input.missionId ?? null, action: 'cleanup', apply: true, staleMs })
45
+ .then((report) => (report?.actions || []).filter((row) => row?.kind === 'terminate_process' && row?.status === 'applied').length)
46
+ .catch(() => 0)
47
+ : 0;
42
48
  if (input.cleanup) {
43
49
  for (const dir of orphanGenerationDirs) {
44
50
  await fsp.rm(path.join(agentRoot, dir), { recursive: true, force: true }).catch(() => { });
@@ -69,6 +75,7 @@ export async function runAgentJanitor(input) {
69
75
  slot_generation_cleanup: cleaned.filter((entry) => entry.includes(`${path.sep}sessions${path.sep}`)),
70
76
  orphan_temp_dirs: orphanTempDirs,
71
77
  stale_locks: staleLocks,
78
+ reaped_orphan_processes: reaped,
72
79
  cleaned,
73
80
  blockers,
74
81
  };
@@ -43,7 +43,6 @@ import { createNativeCliWorkerRuntimeRecorder } from './native-cli-worker-runtim
43
43
  import { writeNativeCliWorkerRuntimeProof } from './native-cli-worker-runtime-proof.js';
44
44
  import { writeNoSubagentScalingPolicy } from './no-subagent-scaling-policy.js';
45
45
  import { writeOfficialSubagentHelperPolicy } from './official-subagent-helper-policy.js';
46
- import { resolveLocalCollaborationPolicy, localCollaborationParticipated } from '../local-llm/local-collaboration-policy.js';
47
46
  import { runFinalGptReviewStage } from '../pipeline/final-gpt-review-stage.js';
48
47
  import { selectFinalGptPatchSource } from '../pipeline/final-gpt-patch-stage.js';
49
48
  import { allocateWorkerWorktree, allocateWorkerWorktreesBatch } from '../git/git-worktree-manager.js';
@@ -217,7 +216,7 @@ export async function runNativeAgentOrchestrator(opts = {}) {
217
216
  partition = applyNarutoWorkGraphToPartition(partition, opts.narutoWorkGraph, roster, targetActiveSlots, prompt);
218
217
  augmentVerificationRollbackDagForNaruto(strategyCompiled.verification_rollback_dag, partition.slices);
219
218
  }
220
- await runAgentJanitor({ missionDir: dir, missionId, projectHash: namespace.root_hash });
219
+ const preSpawnSweep = await runAgentJanitor({ missionDir: dir, missionId, projectHash: namespace.root_hash, reapOrphanProcesses: true });
221
220
  const ledgerRoot = await initializeAgentCentralLedger(dir, { missionId, roster, partition, route, prompt, dynamicScheduler: true });
222
221
  const triwikiContext = await loadTriWikiRuntimeContext(root);
223
222
  await writeTriWikiContextArtifact(ledgerRoot, triwikiContext);
@@ -334,7 +333,6 @@ export async function runNativeAgentOrchestrator(opts = {}) {
334
333
  targetActiveSlots,
335
334
  backend,
336
335
  backendExplicit: opts.backendExplicit === true,
337
- noOllama: opts.noOllama === true,
338
336
  route,
339
337
  fastModePolicy,
340
338
  projectRoot: root
@@ -496,20 +494,16 @@ export async function runNativeAgentOrchestrator(opts = {}) {
496
494
  const officialSubagentHelperPolicy = await writeOfficialSubagentHelperPolicy(ledgerRoot, { nativeProof: nativeCliWorkerRuntimeProof });
497
495
  const noSubagentScalingPolicy = await writeNoSubagentScalingPolicy(ledgerRoot, { nativeProof: nativeCliWorkerRuntimeProof, officialSubagentHelperPolicy });
498
496
  const fastModePropagation = await writeFastModePropagationProof(ledgerRoot, { policy: fastModePolicy, backend, results });
499
- const localCollaborationPolicy = resolveLocalCollaborationPolicy();
500
- await writeJsonAtomic(path.join(ledgerRoot, 'local-collaboration-policy.json'), localCollaborationPolicy);
501
- const localParticipated = localCollaborationParticipated(results);
502
497
  const candidatePatchEnvelopes = results.flatMap((result) => Array.isArray(result.patch_envelopes) ? result.patch_envelopes : []);
503
498
  const worktreeParticipated = candidatePatchEnvelopes.some((envelope) => envelope?.source === 'git-worktree-diff' || envelope?.git_worktree?.worktree_path)
504
499
  || results.some((result) => result?.git_worktree_diff || result?.git_worktree_checkpoint);
505
- const gptFinalRequired = localParticipated || worktreeParticipated;
500
+ const gptFinalRequired = worktreeParticipated;
506
501
  const gptFinalArbiter = gptFinalRequired
507
502
  ? await runFinalGptReviewStage({
508
503
  schema: 'sks.gpt-final-arbiter-input.v1',
509
504
  route,
510
505
  mission_id: missionId,
511
- local_mode: localCollaborationPolicy.mode,
512
- local_outputs: results.map((result) => ({
506
+ candidate_outputs: results.map((result) => ({
513
507
  worker_id: result.agent_id,
514
508
  backend: result.backend_router_report?.selected_backend || result.backend || backend,
515
509
  status: result.status,
@@ -607,7 +601,6 @@ export async function runNativeAgentOrchestrator(opts = {}) {
607
601
  gitWorktreeRuntime,
608
602
  triwikiContext,
609
603
  selectedCoreSkill,
610
- localCollaborationPolicy,
611
604
  gptFinalArbiter,
612
605
  finalGptPatchStage
613
606
  });
@@ -624,7 +617,7 @@ export async function runNativeAgentOrchestrator(opts = {}) {
624
617
  backend,
625
618
  ledger_root: path.relative(root, ledgerRoot),
626
619
  roster,
627
- partition: { ok: partition.ok, slice_count: partition.slices.length, lease_count: partition.leases.length, blockers: partition.blockers },
620
+ partition: { ok: partition.ok, slice_count: partition.slices.length, lease_count: partition.leases.length, blockers: partition.blockers, pre_spawn_reaped: preSpawnSweep.reaped_orphan_processes },
628
621
  task_graph: partition.task_graph?.route_work_count_summary || null,
629
622
  requested_work_items: partition.task_graph?.desired_work_items || desiredWorkItemCount,
630
623
  actual_total_work_items: partition.task_graph?.total_work_items || partition.slices.length,
@@ -651,7 +644,6 @@ export async function runNativeAgentOrchestrator(opts = {}) {
651
644
  fast_mode_policy: fastModePolicy,
652
645
  fast_mode_propagation: fastModePropagation,
653
646
  git_worktree_runtime: gitWorktreeRuntime,
654
- local_collaboration_policy: localCollaborationPolicy,
655
647
  gpt_final_arbiter: gptFinalArbiter,
656
648
  final_gpt_patch_stage: finalGptPatchStage,
657
649
  patch_handoff: patchHandoff,
@@ -1089,7 +1081,7 @@ function sameTournamentGroupEntry(a, b) {
1089
1081
  function attachNarutoRuntimeProof(result, agent, slice) {
1090
1082
  const controlPlane = result?.codex_child_report || result?.codex_sdk_thread || result?.backend_router_report || null;
1091
1083
  const selectedBackend = String(result?.backend_router_report?.selected_backend || result?.backend || '');
1092
- const actualWorkerControlPlane = selectedBackend === 'codex-sdk' || selectedBackend === 'local-llm'
1084
+ const actualWorkerControlPlane = selectedBackend === 'codex-sdk'
1093
1085
  ? Boolean(controlPlane?.sdk_thread_id || controlPlane?.worker_result_path || result?.codex_child_report?.worker_result_path)
1094
1086
  : false;
1095
1087
  result.naruto_runtime = {
@@ -34,7 +34,7 @@ export const AGENT_RESULT_RUNTIME_SCHEMA = {
34
34
  task_slice_id: { type: 'string' },
35
35
  work_item_kind: { type: 'string' },
36
36
  status: { enum: ['done', 'blocked', 'failed'] },
37
- backend: { enum: ['fake', 'process', 'codex-sdk', 'python-codex-sdk', 'ollama', 'local-llm'] },
37
+ backend: { enum: ['fake', 'process', 'codex-sdk', 'python-codex-sdk'] },
38
38
  summary: { type: 'string' },
39
39
  findings: { type: 'array', items: { type: 'string' } },
40
40
  proposed_changes: { type: 'array', items: { type: 'string' } },
@@ -93,7 +93,6 @@ export const AGENT_RESULT_RUNTIME_SCHEMA = {
93
93
  worker_process_id: { type: 'number' },
94
94
  backend_child_process_id: { type: 'number' },
95
95
  backend_sdk_thread_id: { type: 'string' },
96
- backend_ollama_request_id: { type: 'string' },
97
96
  fast_mode: { type: 'boolean' },
98
97
  service_tier: { enum: ['fast', 'standard'] },
99
98
  lease_id: { type: 'string' },
@@ -17,7 +17,6 @@ export function normalizeAgentPatchEnvelope(input) {
17
17
  ...(hasFiniteNumber(input?.worker_process_id) ? { worker_process_id: Number(input.worker_process_id) } : {}),
18
18
  ...(hasFiniteNumber(input?.backend_child_process_id) ? { backend_child_process_id: Number(input.backend_child_process_id) } : {}),
19
19
  ...(input?.backend_sdk_thread_id ? { backend_sdk_thread_id: String(input.backend_sdk_thread_id) } : {}),
20
- ...(input?.backend_ollama_request_id ? { backend_ollama_request_id: String(input.backend_ollama_request_id) } : {}),
21
20
  ...(input?.fast_mode === undefined ? {} : { fast_mode: Boolean(input.fast_mode) }),
22
21
  ...(input?.service_tier === 'fast' || input?.service_tier === 'standard' ? { service_tier: input.service_tier } : {}),
23
22
  ...(input?.lease_id ? { lease_id: String(input.lease_id) } : {}),
@@ -57,7 +56,7 @@ export function validateAgentPatchEnvelope(envelope) {
57
56
  violations.push('operations_missing');
58
57
  if (envelope.source && !['fixture', 'model_authored', 'process_generated', 'git-worktree-diff'].includes(envelope.source))
59
58
  violations.push('source_invalid');
60
- if (envelope.source === 'model_authored' && !hasFiniteNumber(envelope.backend_child_process_id) && !envelope.backend_sdk_thread_id && !envelope.backend_ollama_request_id)
59
+ if (envelope.source === 'model_authored' && !hasFiniteNumber(envelope.backend_child_process_id) && !envelope.backend_sdk_thread_id)
61
60
  violations.push('model_authored_backend_proof_missing');
62
61
  if (envelope.source === 'fixture' && envelope.backend_child_process_id !== undefined)
63
62
  violations.push('fixture_backend_child_process_id_present');
@@ -7,7 +7,8 @@ import { assertAgentTerminalSessionsClosed } from './agent-terminal-session.js';
7
7
  import { assertAgentSessionGenerationsClosed } from './agent-session-generation.js';
8
8
  import { writeFakeRealProofPolicyReport } from '../proof/fake-real-proof-policy.js';
9
9
  import { buildRuntimeTruthMatrix, writeRuntimeTruthMatrix } from '../proof/runtime-truth-matrix.js';
10
- import { evaluateLocalCollaborationFinalGate, localCollaborationParticipated, resolveLocalCollaborationPolicy } from '../local-llm/local-collaboration-policy.js';
10
+ import { evaluateGptFinalGate } from '../codex-control/gpt-final-gate.js';
11
+ import { gptFinalRequiredForPipeline } from '../pipeline/gpt-final-required.js';
11
12
  export async function writeAgentProofEvidence(root, input) {
12
13
  const lifecycle = await assertAllAgentSessionsClosed(root);
13
14
  const terminal = await assertAgentTerminalSessionsClosed(root);
@@ -26,22 +27,18 @@ export async function writeAgentProofEvidence(root, input) {
26
27
  const patchRollbackProof = await readJson(path.join(root, 'agent-patch-rollback-proof.json'), null);
27
28
  const patchProof = await readJson(path.join(root, 'agent-patch-proof.json'), null);
28
29
  const patchHandoff = input.patchHandoff || await readJson(path.join(root, 'agent-patch-handoff-runtime.json'), null);
29
- const localCollaborationPolicy = input.localCollaborationPolicy || await readJson(path.join(root, 'local-collaboration-policy.json'), null) || resolveLocalCollaborationPolicy();
30
30
  const gptFinalArbiter = input.gptFinalArbiter || await readJson(path.join(root, 'gpt-final-arbiter', 'gpt-final-arbiter.json'), null);
31
31
  const narutoWorkGraph = await readJson(path.join(root, 'naruto-work-graph.json'), null);
32
32
  const narutoRoleDistribution = await readJson(path.join(root, 'naruto-role-distribution.json'), null);
33
33
  const narutoConcurrencyGovernor = await readJson(path.join(root, 'naruto-concurrency-governor.json'), null);
34
34
  const narutoActivePool = await readJson(path.join(root, 'naruto-active-pool.json'), null);
35
35
  const narutoVerificationDag = await readJson(path.join(root, 'naruto-verification-dag.json'), null);
36
- const localParticipated = localCollaborationParticipated(input.results || []) || Number(gptFinalArbiter?.local_outputs_count || 0) > 0;
36
+ const gptFinalRequired = gptFinalRequiredForPipeline({ candidateResults: input.results || [] }).gpt_final_required;
37
37
  const finalGptPatchStage = input.finalGptPatchStage || null;
38
- const localFinalGate = gptFinalArbiter?.final_gate || evaluateLocalCollaborationFinalGate({
39
- policy: localCollaborationPolicy,
40
- localParticipated,
38
+ const gptFinalGate = gptFinalArbiter?.final_gate || evaluateGptFinalGate({
39
+ required: gptFinalRequired,
41
40
  gptFinalStatus: gptFinalArbiter?.result?.status || null,
42
- gptFinalAvailable: Boolean(gptFinalArbiter),
43
- gptFinalBackend: gptFinalArbiter?.backend || null,
44
- applyPatches: parallelWritePolicy?.apply_patches === true
41
+ gptFinalAvailable: Boolean(gptFinalArbiter)
45
42
  });
46
43
  const nativeCliWorkerRuntimeProof = input.nativeCliWorkerRuntimeProof || await readJson(path.join(root, 'native-cli-worker-runtime-proof.json'), null);
47
44
  const noSubagentScalingPolicy = input.noSubagentScalingPolicy || await readJson(path.join(root, 'no-subagent-scaling-policy.json'), null);
@@ -173,9 +170,9 @@ export async function writeAgentProofEvidence(root, input) {
173
170
  ...(patchHandoff && !patchApplyOk ? ['patch_apply_not_ok'] : []),
174
171
  ...(patchHandoff && !patchVerificationOk ? ['patch_verification_not_ok'] : []),
175
172
  ...(patchHandoff && !patchRollbackOk ? ['patch_rollback_not_ok'] : []),
176
- ...(localParticipated && localFinalGate.ok !== true ? localFinalGate.blockers || ['gpt_final_arbiter_gate_not_ok'] : []),
177
- ...(localParticipated && gptFinalArbiter?.ok !== true ? gptFinalArbiter?.blockers || ['gpt_final_arbiter_not_ok'] : []),
178
- ...(localParticipated && finalGptPatchStage?.ok === false ? finalGptPatchStage.blockers || ['final_gpt_patch_stage_not_ok'] : []),
173
+ ...(gptFinalRequired && gptFinalGate.ok !== true ? gptFinalGate.blockers || ['gpt_final_arbiter_gate_not_ok'] : []),
174
+ ...(gptFinalRequired && gptFinalArbiter?.ok !== true ? gptFinalArbiter?.blockers || ['gpt_final_arbiter_not_ok'] : []),
175
+ ...(gptFinalRequired && finalGptPatchStage?.ok === false ? finalGptPatchStage.blockers || ['final_gpt_patch_stage_not_ok'] : []),
179
176
  ...(isNarutoRoute && !narutoWorkGraph ? ['naruto_work_graph_missing'] : []),
180
177
  ...(isNarutoRoute && narutoWorkGraph?.ok === false ? narutoWorkGraph.blockers || ['naruto_work_graph_not_ok'] : []),
181
178
  ...(isNarutoRoute && !narutoRoleDistribution ? ['naruto_role_distribution_missing'] : []),
@@ -236,15 +233,13 @@ export async function writeAgentProofEvidence(root, input) {
236
233
  parallel_write_apply_patches: parallelWritePolicy?.apply_patches === true,
237
234
  parallel_write_dry_run_patches: parallelWritePolicy?.dry_run_patches === true,
238
235
  parallel_write_max_write_agents: Number(parallelWritePolicy?.max_write_agents || 0),
239
- local_collaboration_policy: 'local-collaboration-policy.json',
240
- local_collaboration_mode: localCollaborationPolicy.mode || null,
241
- local_collaboration_participated: localParticipated,
242
236
  gpt_final_arbiter: gptFinalArbiter ? 'gpt-final-arbiter/gpt-final-arbiter.json' : null,
243
- gpt_final_status: gptFinalArbiter?.result?.status || (localParticipated ? 'missing' : 'not_required_no_local_outputs'),
237
+ gpt_final_required: gptFinalRequired,
238
+ gpt_final_status: gptFinalArbiter?.result?.status || (gptFinalRequired ? 'missing' : 'not_required_no_worktree_candidates'),
244
239
  gpt_final_backend: gptFinalArbiter?.backend || null,
245
- gpt_final_patch_source: finalGptPatchStage?.final_patch_source || (localParticipated ? 'blocked' : 'not_applicable'),
246
- gpt_final_gate_ok: localFinalGate.ok === true,
247
- gpt_final_gate: localFinalGate,
240
+ gpt_final_patch_source: finalGptPatchStage?.final_patch_source || (gptFinalRequired ? 'blocked' : 'not_applicable'),
241
+ gpt_final_gate_ok: gptFinalGate.ok === true,
242
+ gpt_final_gate: gptFinalGate,
248
243
  naruto_work_graph: narutoWorkGraph ? 'naruto-work-graph.json' : null,
249
244
  naruto_total_work_items: Number(narutoWorkGraph?.total_work_items || 0),
250
245
  naruto_mixed_work_kinds: narutoWorkGraph?.mixed_work_kinds || [],
@@ -86,8 +86,9 @@ export function agentWorkerHookRecursionDecision(state = {}, payload = {}, comma
86
86
  reason: `Agent command recursion guard blocked nested SKS route command in Codex PreToolUse hook: ${guard.violations.join(', ')}`
87
87
  };
88
88
  }
89
- export function agentWorkerHookContext(state = {}, payload = {}) {
90
- const env = {
89
+ export function agentWorkerHookContext(state = {}, payload = {}, env = process.env) {
90
+ const declared = {
91
+ ...(env || {}),
91
92
  ...(payload.env || {}),
92
93
  ...(payload.tool_input?.env || {}),
93
94
  ...(payload.toolInput?.env || {}),
@@ -95,11 +96,24 @@ export function agentWorkerHookContext(state = {}, payload = {}) {
95
96
  ...(payload.tool?.input?.env || {})
96
97
  };
97
98
  void state;
98
- return Boolean(String(env.SKS_AGENT_WORKER || '') === '1'
99
- || String(env.SKS_DISABLE_ROUTE_RECURSION || '') === '1'
99
+ return Boolean(String(declared.SKS_AGENT_WORKER || '') === '1'
100
+ || String(declared.SKS_DISABLE_ROUTE_RECURSION || '') === '1'
101
+ || agentGenerationDepth(declared) > 0
100
102
  || payload.agent_worker === true
101
103
  || payload.agentWorker === true);
102
104
  }
105
+ export function agentGenerationDepth(env = process.env) {
106
+ const raw = Number.parseInt(String(env[AGENT_GENERATION_DEPTH_ENV] || ''), 10);
107
+ return Number.isFinite(raw) && raw > 0 ? Math.min(raw, MAX_AGENT_GENERATION_DEPTH * 4) : 0;
108
+ }
109
+ export const AGENT_GENERATION_DEPTH_ENV = 'SKS_AGENT_GENERATION_DEPTH';
110
+ export const MAX_AGENT_GENERATION_DEPTH = 1;
111
+ export function nextAgentGenerationEnv(env = process.env) {
112
+ return { [AGENT_GENERATION_DEPTH_ENV]: String(agentGenerationDepth(env) + 1) };
113
+ }
114
+ export function agentGenerationDepthExceeded(env = process.env) {
115
+ return agentGenerationDepth(env) > MAX_AGENT_GENERATION_DEPTH;
116
+ }
103
117
  export function assertNoAgentRecursion(text) {
104
118
  const result = scanAgentTextForRecursion(text);
105
119
  if (!result.ok)
@@ -399,7 +413,7 @@ function transcriptGroupForChannel(channel) {
399
413
  function isWorkerExecutionSurface(rel, channel) {
400
414
  if (channel === 'stdout' || channel === 'stderr' || channel === 'agent_result')
401
415
  return true;
402
- return /(?:^|\/)agent-worker-pipeline\.(?:ts|mjs|js)$/.test(rel) || /(?:^|\/)agent-runner-(?:process|ollama)\.(?:ts|mjs|js)$/.test(rel);
416
+ return /(?:^|\/)agent-worker-pipeline\.(?:ts|mjs|js)$/.test(rel) || /(?:^|\/)agent-runner-process\.(?:ts|mjs|js)$/.test(rel);
403
417
  }
404
418
  function classifyNonRecursivePipelinePath(file) {
405
419
  const normalized = normalizePath(file);
@@ -12,7 +12,7 @@ export const OFFICIAL_SUBAGENT_EXECUTION_STAGE_ID = 'official_subagent_execution
12
12
  export const MAX_AGENT_COUNT = 20;
13
13
  export const DEFAULT_AGENT_CONCURRENCY = DEFAULT_NARUTO_MAX_THREADS;
14
14
  export const HARD_AGENT_CONCURRENCY = HARD_NARUTO_MAX_THREADS;
15
- export const AGENT_BACKENDS = ['fake', 'process', 'codex-sdk', 'ollama', 'local-llm'];
15
+ export const AGENT_BACKENDS = ['fake', 'process', 'codex-sdk'];
16
16
  export function normalizeAgentBackend(input) {
17
17
  const value = String(input || 'codex-sdk');
18
18
  return AGENT_BACKENDS.includes(value) ? value : null;