sneakoscope 2.0.4 → 2.0.6

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 (120) hide show
  1. package/README.md +18 -11
  2. package/crates/sks-core/Cargo.lock +1 -1
  3. package/crates/sks-core/Cargo.toml +1 -1
  4. package/crates/sks-core/src/main.rs +1 -1
  5. package/dist/.sks-build-stamp.json +4 -4
  6. package/dist/bin/sks.js +1 -1
  7. package/dist/build-manifest.json +78 -8
  8. package/dist/cli/install-helpers.js +23 -0
  9. package/dist/commands/codex-app.js +25 -3
  10. package/dist/commands/doctor.js +33 -4
  11. package/dist/commands/mad-sks.js +2 -2
  12. package/dist/core/agents/agent-orchestrator.js +22 -3
  13. package/dist/core/agents/agent-proof-evidence.js +59 -2
  14. package/dist/core/agents/agent-roster.js +35 -6
  15. package/dist/core/agents/agent-schema.js +1 -1
  16. package/dist/core/agents/agent-worker-pipeline.js +9 -1
  17. package/dist/core/agents/native-worker-backend-router.js +50 -10
  18. package/dist/core/agents/ollama-worker-config.js +164 -15
  19. package/dist/core/codex/codex-0-137-compat.js +119 -0
  20. package/dist/core/codex-app.js +124 -2
  21. package/dist/core/codex-control/codex-control-proof.js +4 -1
  22. package/dist/core/codex-control/codex-sdk-capability.js +1 -1
  23. package/dist/core/codex-control/codex-task-runner.js +329 -5
  24. package/dist/core/codex-control/python-codex-sdk-adapter.js +197 -0
  25. package/dist/core/codex-control/python-codex-sdk-event-translator.js +14 -0
  26. package/dist/core/commands/local-model-command.js +65 -19
  27. package/dist/core/commands/naruto-command.js +124 -8
  28. package/dist/core/commands/run-command.js +1 -1
  29. package/dist/core/doctor/doctor-readiness-matrix.js +21 -2
  30. package/dist/core/fsx.js +1 -1
  31. package/dist/core/hooks-runtime.js +2 -233
  32. package/dist/core/init.js +8 -8
  33. package/dist/core/local-llm/local-llm-backpressure.js +20 -0
  34. package/dist/core/local-llm/local-llm-capability.js +29 -0
  35. package/dist/core/local-llm/local-llm-client.js +100 -0
  36. package/dist/core/local-llm/local-llm-config.js +6 -1
  37. package/dist/core/local-llm/local-llm-context-cache.js +21 -0
  38. package/dist/core/local-llm/local-llm-control-adapter.js +101 -0
  39. package/dist/core/local-llm/local-llm-json-repair.js +52 -0
  40. package/dist/core/local-llm/local-llm-metrics.js +42 -0
  41. package/dist/core/local-llm/local-llm-ollama-client.js +67 -0
  42. package/dist/core/local-llm/local-llm-openai-compatible-client.js +30 -0
  43. package/dist/core/local-llm/local-llm-prompt-cache.js +12 -0
  44. package/dist/core/local-llm/local-llm-scheduler.js +29 -0
  45. package/dist/core/local-llm/local-llm-schema-enforcer.js +15 -0
  46. package/dist/core/local-llm/local-llm-smoke.js +83 -0
  47. package/dist/core/local-llm/local-llm-warmup.js +20 -0
  48. package/dist/core/local-llm/local-worker-eligibility.js +27 -0
  49. package/dist/core/naruto/hardware-capacity-probe.js +36 -0
  50. package/dist/core/naruto/naruto-active-pool.js +134 -0
  51. package/dist/core/naruto/naruto-backpressure.js +13 -0
  52. package/dist/core/naruto/naruto-concurrency-governor.js +65 -0
  53. package/dist/core/naruto/naruto-finalizer.js +18 -0
  54. package/dist/core/naruto/naruto-generation-scheduler.js +18 -0
  55. package/dist/core/naruto/naruto-gpt-final-pack.js +49 -0
  56. package/dist/core/naruto/naruto-parallel-patch-apply.js +95 -0
  57. package/dist/core/naruto/naruto-patch-transaction-batch.js +42 -0
  58. package/dist/core/naruto/naruto-role-policy.js +107 -0
  59. package/dist/core/naruto/naruto-verification-dag.js +42 -0
  60. package/dist/core/naruto/naruto-verification-pool.js +18 -0
  61. package/dist/core/naruto/naruto-work-graph.js +198 -0
  62. package/dist/core/naruto/naruto-work-item.js +40 -0
  63. package/dist/core/naruto/naruto-work-stealing.js +11 -0
  64. package/dist/core/naruto/resource-pressure-monitor.js +32 -0
  65. package/dist/core/pipeline/finalize-pipeline-result.js +58 -0
  66. package/dist/core/pipeline/gpt-final-required.js +12 -0
  67. package/dist/core/pipeline-internals/runtime-core.js +1 -1
  68. package/dist/core/ppt.js +31 -8
  69. package/dist/core/product-design-app-server.js +410 -0
  70. package/dist/core/product-design-plugin.js +139 -0
  71. package/dist/core/prompt/prompt-placeholder-guard.js +30 -0
  72. package/dist/core/router/capability-card.js +13 -0
  73. package/dist/core/router/route-cache.js +3 -0
  74. package/dist/core/router/ultra-router.js +2 -1
  75. package/dist/core/routes.js +12 -12
  76. package/dist/core/version.js +1 -1
  77. package/dist/core/zellij/zellij-lane-runtime.js +2 -2
  78. package/dist/core/zellij/zellij-naruto-dashboard.js +36 -0
  79. package/dist/core/zellij/zellij-worker-pane-manager.js +4 -4
  80. package/dist/scripts/blackbox-command-import-smoke.js +10 -1
  81. package/dist/scripts/check-package-boundary.js +12 -3
  82. package/dist/scripts/codex-0-137-compat-check.js +27 -0
  83. package/dist/scripts/codex-environment-scoped-approvals-check.js +10 -0
  84. package/dist/scripts/codex-plugin-list-json-check.js +8 -0
  85. package/dist/scripts/codex-thread-runtime-choice-check.js +10 -0
  86. package/dist/scripts/local-collab-all-pipelines-final-gpt-check.js +21 -0
  87. package/dist/scripts/local-llm-all-pipelines-check.js +11 -0
  88. package/dist/scripts/local-llm-cache-performance-check.js +10 -0
  89. package/dist/scripts/local-llm-capability-check.js +14 -0
  90. package/dist/scripts/local-llm-smoke-check.js +23 -0
  91. package/dist/scripts/local-llm-structured-output-check.js +11 -0
  92. package/dist/scripts/local-llm-throughput-check.js +10 -0
  93. package/dist/scripts/local-llm-tool-call-repair-check.js +10 -0
  94. package/dist/scripts/local-llm-warmup-check.js +11 -0
  95. package/dist/scripts/naruto-active-pool-check.js +39 -0
  96. package/dist/scripts/naruto-concurrency-governor-check.js +52 -0
  97. package/dist/scripts/naruto-gpt-final-pack-check.js +34 -0
  98. package/dist/scripts/naruto-parallel-patch-apply-check.js +41 -0
  99. package/dist/scripts/naruto-readonly-routing-check.js +116 -0
  100. package/dist/scripts/naruto-real-local-gpt-final-smoke.js +16 -0
  101. package/dist/scripts/naruto-role-distribution-check.js +23 -0
  102. package/dist/scripts/naruto-shadow-clone-swarm-check.js +13 -0
  103. package/dist/scripts/naruto-verification-pool-check.js +36 -0
  104. package/dist/scripts/naruto-work-graph-check.js +24 -0
  105. package/dist/scripts/naruto-zellij-massive-ui-check.js +23 -0
  106. package/dist/scripts/product-design-auto-install-check.js +119 -0
  107. package/dist/scripts/product-design-plugin-routing-check.js +101 -0
  108. package/dist/scripts/prompt-placeholder-guard-check.js +33 -0
  109. package/dist/scripts/python-codex-sdk-all-pipelines-check.js +47 -0
  110. package/dist/scripts/python-codex-sdk-capability-check.js +75 -0
  111. package/dist/scripts/python-codex-sdk-sandbox-policy-check.js +10 -0
  112. package/dist/scripts/python-codex-sdk-stream-bridge-check.js +12 -0
  113. package/dist/scripts/release-parallel-check.js +16 -2
  114. package/dist/scripts/release-provenance-check.js +21 -0
  115. package/dist/scripts/release-real-check.js +5 -0
  116. package/dist/scripts/zellij-worker-pane-manager-check.js +1 -1
  117. package/package.json +36 -4
  118. package/schemas/local-llm/local-model-config.schema.json +74 -0
  119. package/schemas/naruto/naruto-concurrency-governor.schema.json +21 -0
  120. package/schemas/naruto/naruto-work-graph.schema.json +22 -0
package/README.md CHANGED
@@ -16,10 +16,13 @@ Set up this agent project with Sneakoscope Codex. Use [[mandarange/Sneakoscope-C
16
16
 
17
17
  ## Current Release
18
18
 
19
- SKS **2.0.4** is a P0 Codex App Fast UI and MAD Zellij worker-pane closure patch on top of the 2.0 execution layer. `sks --mad` now relies on launch-time Fast/high overrides instead of user-level Codex config rewrites, safe Fast UI repair runs through `sks doctor --fix`, provider badges read env/auth/config.toml consistently, and interactive MAD worker panes attach to the real Zellij session as scheduler slots spawn.
19
+ SKS **2.0.6** wires Codex App Product Design into the design pipeline and hardens Naruto read-only routing on top of the 2.0 execution layer. Design routes can now discover, install, verify, and prefer the remote `product-design@openai-curated-remote` plugin, while read-only native worker runs keep write mode off and avoid treating pre-existing dirty files as generated patches.
20
20
 
21
21
  What changed:
22
22
 
23
+ - Product Design plugin readiness now checks both local and remote Codex App catalogs, auto-installs the remote plugin when needed, and records the installed/enabled skill surface.
24
+ - UI/design/PPT runtime routes prefer Product Design for research, ideation, audit, design QA, prototype, URL-to-code, image-to-code, share, and user-context steps.
25
+ - Naruto read-only runs force write mode off, propagate no-patch reasons through worker proof, and skip changed-file lease checks when no write-capable patch envelope exists.
23
26
  - `codex-sdk` is the default native agent backend for Team, QA, Research, Naruto, MAD-SKS, and direct agent runs, with every runtime task entering through `runCodexTask`.
24
27
  - Codex App UI snapshot, preservation, clobber guard, and doctor repair checks protect host-owned Fast UI/profile settings around `sks --mad`.
25
28
  - Provider context resolves `openai`, `codex-lb`, and `codex-app` with badge/fallback surfaces while avoiding private Codex App UI mutation.
@@ -78,7 +81,7 @@ Broader release checks still live behind `npm run release:check`. Detailed relea
78
81
  sks xai docs
79
82
  ```
80
83
 
81
- - **Quieter update prompts.** The "update available" choice is shown once per conversation and then stays quiet for a short window (default 8 min, `SKS_UPDATE_OFFER_THROTTLE_MS`) instead of repeating on every prompt. The check compares npm latest against source metadata, PATH `sks --version`, and the global npm package, so a completed `npm i -g sneakoscope` clears stale pending/accepted offers.
84
+ - **CLI-only SKS update notices.** Codex App hooks no longer stop normal work to ask for an SKS update. CLI launch surfaces such as `sks --mad` print a non-blocking latest-version notice, `sks update-check` / `sks update check` show the explicit status, and `sks doctor --fix` runs the guarded global SKS update path before repair.
82
85
 
83
86
  ## Retention And Cleanup
84
87
 
@@ -359,7 +362,7 @@ sks --mad --allow-package-install --allow-service-control --allow-network --yes
359
362
 
360
363
  This syncs existing codex-lb provider auth, creates/uses the `sks-mad-high` xhigh maintenance profile, opens the MAD-SKS permission gate for that Zellij run, starts a same-mission read-only native agent swarm, and launches a Codex CLI layout whose right-side lanes read that MAD ledger. Bare `sks --mad` grants target-project file and shell scope only; add explicit `--allow-*` flags for packages, services, network, Computer Use, browser use, generated assets, file permissions, DB writes, or other high-risk scopes. MAD-SKS is not a DB-only unlock: it is explicit user authorization to widen approved target-project scopes. Catastrophic database wipe/all-row/project-management safeguards remain active, and the pipeline contract still forbids unrequested fallback implementation code.
361
364
 
362
- Before launching, SKS checks npm for a newer `sneakoscope`; answer `y` to update or `n` to continue. Use `--yes` to approve missing dependency installs automatically. Tune MAD swarm startup with `--mad-agents <n>`, `--mad-swarm-work-items <n>`, and `--mad-swarm-backend <backend>`; `--no-mad-swarm` keeps only the cockpit UI if you need a temporary fallback.
365
+ Before launching, SKS checks npm for a newer `sneakoscope` and prints a non-blocking update notice when one is available; use `sks update now` or `sks doctor --fix` when you want SKS to update itself. Use `--yes` to approve missing dependency installs automatically. Tune MAD swarm startup with `--mad-agents <n>`, `--mad-swarm-work-items <n>`, and `--mad-swarm-backend <backend>`; `--no-mad-swarm` keeps only the cockpit UI if you need a temporary fallback.
363
366
 
364
367
  ### Team Missions
365
368
 
@@ -398,9 +401,9 @@ Manual fan-out syntax:
398
401
 
399
402
  Effort is assigned per agent. Simple read-only/docs slices can run low, ordinary tooling and lease mapping use medium, safety/DB/schema/release lanes use high, and frontier/forensic research can escalate to xhigh. If a lease conflict, schema failure, proof blocker, DB risk, or release risk appears, the parent can escalate that lane while keeping unrelated lanes cheaper and faster.
400
403
 
401
- ### Naruto Shadow Clone Swarm (`$Naruto`)
404
+ ### Naruto Massive Parallel Work Swarm (`$Naruto`)
402
405
 
403
- `$Naruto` (影分身 / Kage Bunshin no Jutsu) is a high-scale mode of the native agent kernel for broad fan-out work codebase-wide sweeps, parallel drafting, large audits. It lifts the standard 20-agent ceiling to **up to 100 clone sessions** (only for this route; every other route keeps the 20 cap).
406
+ `$Naruto` (影分身 / Kage Bunshin no Jutsu) is the hardware-safe massive parallel work mode of the native agent kernel. It is not limited to validation. A Naruto run builds a mixed work graph, keeps a safe active worker pool full, and assigns clones to implementation, modification, test generation, verification, research, documentation, conflict resolution, rollback planning, integration support, and GPT final review input work. It lifts the standard 20-agent ceiling to **up to 100 total clone generations** for this route while keeping active workers under the live hardware, lease, memory, terminal UI, file descriptor, local LLM, and remote API caps.
404
407
 
405
408
  ```sh
406
409
  sks naruto run "sweep the codebase for TODO comments and summarize"
@@ -411,9 +414,11 @@ sks naruto status
411
414
 
412
415
  Aliases: `$ShadowClone`, `$Kagebunshin`, and the CLI flag `sks --naruto`.
413
416
 
414
- - **System-aware concurrency:** `--clones N` is the total work fan-out, but `$Naruto` never spawns the whole count at once. Live concurrency is throttled to a host-safe number derived from CPU cores and free memory (heavier cap for real `codex-sdk` workers, tighter packing for in-process `fake`). So `--clones 100` on a small host still processes all 100 work units while only running a safe handful at a time; the run reports when it throttles. Override with `SKS_NARUTO_MAX_CONCURRENCY=<n>`.
417
+ - **Hardware-safe governor:** `--clones N` is the total work fan-out, but `$Naruto` never spawns the whole count at once. Live concurrency is throttled by current load, memory, file descriptors, Zellij pane budget, local LLM request budget, remote API budget, disk pressure, pending queue, and active lease conflicts.
418
+ - **Dynamic active pool:** completed workers are drained and replaced while runnable work remains, so the active pool does not sit empty between generations.
415
419
  - **Dynamic per-clone effort (like Team):** truly simple / no-tool work runs at `low`, any tool use lifts a clone to `medium` (never high/xhigh), and every clone runs in fast service tier.
416
- - **Safe parallel writes:** clones coordinate through the same lease-based patch-swarm (merge coordinator + conflict rebase + transaction journal) as Team.
420
+ - **Safe parallel writes:** write-capable clones produce patch envelopes for leased files. Non-overlapping envelopes can apply in parallel; overlapping envelopes serialize or route to conflict resolution. Local worker output remains a draft until the GPT final arbiter approves or modifies it.
421
+ - **Massive UI without pane overload:** Zellij shows visible active worker panes up to the UI cap and tracks the remaining active headless workers in the Naruto dashboard.
417
422
 
418
423
  See [docs/naruto.md](docs/naruto.md) for the full reference.
419
424
 
@@ -513,18 +518,20 @@ $DB inspect this migration for destructive risk
513
518
 
514
519
  ### Optional Local LLM Workers
515
520
 
516
- Local Ollama workers are off by default, so SKS stays GPT-only unless you explicitly enable them. Use the Codex App prompt commands:
521
+ Local model workers are off by default, so SKS stays GPT-only unless you explicitly enable them. Use the Codex App prompt commands:
517
522
 
518
523
  ```text
519
524
  $with-local-llm-on
520
525
  $with-local-llm-off
521
526
  ```
522
527
 
523
- When enabled, the local model can only help with policy-eligible simple code patch-envelope work or read-only collection. GPT/Codex still owns strategy, planning, design, review, verification, safety, and integration. Check or tune the machine-local setting from the terminal:
528
+ When enabled, SKS auto-detects an installed local model from a running MLX LM server, OpenAI-compatible local server, or Ollama. If no local model is available, activation stays blocked and reports that no local model was found. The local model can only help with policy-eligible simple code patch-envelope work or read-only collection. GPT/Codex still owns strategy, planning, design, review, verification, safety, and integration. Check or tune the machine-local setting from the terminal:
524
529
 
525
530
  ```sh
526
531
  sks with-local-llm status --json
527
- sks with-local-llm on --model rafw007/qwen36-a3b-claude-coder:q4_K_M
532
+ sks with-local-llm on
533
+ sks with-local-llm on --provider mlx-lm --model mlx-community/Qwen3.6-35B-A3B-4bit --base-url http://127.0.0.1:8080
534
+ sks with-local-llm on --provider ollama --model rafw007/qwen36-a3b-claude-coder:q4_K_M
528
535
  sks with-local-llm off
529
536
  ```
530
537
 
@@ -655,7 +662,7 @@ npm ls -g sneakoscope --depth=0
655
662
  sks doctor --fix
656
663
  ```
657
664
 
658
- Update prompts compare npm latest against the effective installed version from source metadata, PATH `sks --version`, and global npm package metadata. `sks update now` installs through npm global mode instead of mutating the current project's dependencies. If a global update succeeded but an old shim remains earlier on PATH, `sks doctor --fix` can remove duplicate global installs and refresh the managed setup.
665
+ CLI update checks compare npm latest against the effective installed version from source metadata, PATH `sks --version`, and global npm package metadata. Codex App hooks do not force update choices during ordinary work. `sks update now` installs through npm global mode instead of mutating the current project's dependencies, and `sks doctor --fix` runs that guarded global update path before setup/config repair. If a global update succeeded but an old shim remains earlier on PATH, `sks doctor --fix` can remove duplicate global installs and refresh the managed setup.
659
666
 
660
667
  ### Zellij is missing
661
668
 
@@ -76,7 +76,7 @@ dependencies = [
76
76
 
77
77
  [[package]]
78
78
  name = "sks-core"
79
- version = "2.0.4"
79
+ version = "2.0.6"
80
80
  dependencies = [
81
81
  "serde_json",
82
82
  ]
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "sks-core"
3
- version = "2.0.4"
3
+ version = "2.0.6"
4
4
  edition = "2021"
5
5
 
6
6
  [dependencies]
@@ -4,7 +4,7 @@ use std::io::{self, Read, Seek, SeekFrom};
4
4
  fn main() {
5
5
  let mut args = std::env::args().skip(1);
6
6
  match args.next().as_deref() {
7
- Some("--version") => println!("sks-rs 2.0.4"),
7
+ Some("--version") => println!("sks-rs 2.0.6"),
8
8
  Some("compact-info") => {
9
9
  let mut input = String::new();
10
10
  let _ = io::stdin().read_to_string(&mut input);
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schema": "sks.dist-build-stamp.v1",
3
3
  "package_name": "sneakoscope",
4
- "package_version": "2.0.4",
5
- "source_digest": "bd67ddf989e2e0b702453d422e2cf991e8ca397d3d4afc14fdfa06b4610452c9",
6
- "source_file_count": 1879,
7
- "built_at_source_time": 1780569940553
4
+ "package_version": "2.0.6",
5
+ "source_digest": "3947e39c47a565506e9ffd37568ae889bc7943f6dc342b5c357976b840770f94",
6
+ "source_file_count": 1953,
7
+ "built_at_source_time": 1780662014263
8
8
  }
package/dist/bin/sks.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- const FAST_PACKAGE_VERSION = '2.0.4';
2
+ const FAST_PACKAGE_VERSION = '2.0.6';
3
3
  const args = process.argv.slice(2);
4
4
  try {
5
5
  if (args[0] === '--agent' && args[1] === 'worker') {
@@ -1,16 +1,16 @@
1
1
  {
2
2
  "schema": "sks.dist-build.v2",
3
- "version": "2.0.4",
4
- "package_version": "2.0.4",
3
+ "version": "2.0.6",
4
+ "package_version": "2.0.6",
5
5
  "typescript": true,
6
6
  "mjs_runtime_files": 0,
7
- "compiled_file_count": 949,
8
- "compiled_js_count": 949,
7
+ "compiled_file_count": 1019,
8
+ "compiled_js_count": 1019,
9
9
  "compiled_dts_count": 0,
10
- "source_digest": "bd67ddf989e2e0b702453d422e2cf991e8ca397d3d4afc14fdfa06b4610452c9",
11
- "source_file_count": 1879,
12
- "source_files_hash": "c43d09b591370ad58937365d6bbfca2be0b60fcf04a43fdbb9a56d9288752814",
13
- "source_list_hash": "c43d09b591370ad58937365d6bbfca2be0b60fcf04a43fdbb9a56d9288752814",
10
+ "source_digest": "3947e39c47a565506e9ffd37568ae889bc7943f6dc342b5c357976b840770f94",
11
+ "source_file_count": 1953,
12
+ "source_files_hash": "5d6f0e4186fc37279e1cf6de0c6b3c7230123c4a588966f8fda2a9324eb75192",
13
+ "source_list_hash": "5d6f0e4186fc37279e1cf6de0c6b3c7230123c4a588966f8fda2a9324eb75192",
14
14
  "src_mjs_runtime_files": 0,
15
15
  "dist_stamp_schema": "sks.dist-build-stamp.v1",
16
16
  "files": [
@@ -216,6 +216,8 @@
216
216
  "core/codex-control/gpt-final-context-compressor.js",
217
217
  "core/codex-control/gpt-final-proof-pack.js",
218
218
  "core/codex-control/gpt-final-review-schema.js",
219
+ "core/codex-control/python-codex-sdk-adapter.js",
220
+ "core/codex-control/python-codex-sdk-event-translator.js",
219
221
  "core/codex-control/schemas/agent-worker-result.schema.js",
220
222
  "core/codex-exec-output-schema.js",
221
223
  "core/codex-hooks/codex-hook-actual-discovery.js",
@@ -237,6 +239,7 @@
237
239
  "core/codex/codex-0-134-compat.js",
238
240
  "core/codex/codex-0-135-compat.js",
239
241
  "core/codex/codex-0-136-compat.js",
242
+ "core/codex/codex-0-137-compat.js",
240
243
  "core/codex/codex-cli-syntax-builder.js",
241
244
  "core/codex/codex-config-eperm-repair.js",
242
245
  "core/codex/codex-config-readability.js",
@@ -362,7 +365,22 @@
362
365
  "core/json-schema-validator.js",
363
366
  "core/language-preference.js",
364
367
  "core/local-llm/local-collaboration-policy.js",
368
+ "core/local-llm/local-llm-backpressure.js",
369
+ "core/local-llm/local-llm-capability.js",
370
+ "core/local-llm/local-llm-client.js",
365
371
  "core/local-llm/local-llm-config.js",
372
+ "core/local-llm/local-llm-context-cache.js",
373
+ "core/local-llm/local-llm-control-adapter.js",
374
+ "core/local-llm/local-llm-json-repair.js",
375
+ "core/local-llm/local-llm-metrics.js",
376
+ "core/local-llm/local-llm-ollama-client.js",
377
+ "core/local-llm/local-llm-openai-compatible-client.js",
378
+ "core/local-llm/local-llm-prompt-cache.js",
379
+ "core/local-llm/local-llm-scheduler.js",
380
+ "core/local-llm/local-llm-schema-enforcer.js",
381
+ "core/local-llm/local-llm-smoke.js",
382
+ "core/local-llm/local-llm-warmup.js",
383
+ "core/local-llm/local-worker-eligibility.js",
366
384
  "core/loop-blocker.js",
367
385
  "core/mad-sks/audit-ledger.js",
368
386
  "core/mad-sks/authorization-manifest.js",
@@ -393,6 +411,22 @@
393
411
  "core/mission.js",
394
412
  "core/mistake-memory.js",
395
413
  "core/mistake-recall.js",
414
+ "core/naruto/hardware-capacity-probe.js",
415
+ "core/naruto/naruto-active-pool.js",
416
+ "core/naruto/naruto-backpressure.js",
417
+ "core/naruto/naruto-concurrency-governor.js",
418
+ "core/naruto/naruto-finalizer.js",
419
+ "core/naruto/naruto-generation-scheduler.js",
420
+ "core/naruto/naruto-gpt-final-pack.js",
421
+ "core/naruto/naruto-parallel-patch-apply.js",
422
+ "core/naruto/naruto-patch-transaction-batch.js",
423
+ "core/naruto/naruto-role-policy.js",
424
+ "core/naruto/naruto-verification-dag.js",
425
+ "core/naruto/naruto-verification-pool.js",
426
+ "core/naruto/naruto-work-graph.js",
427
+ "core/naruto/naruto-work-item.js",
428
+ "core/naruto/naruto-work-stealing.js",
429
+ "core/naruto/resource-pressure-monitor.js",
396
430
  "core/no-question-guard.js",
397
431
  "core/openclaw.js",
398
432
  "core/perf-bench.js",
@@ -406,6 +440,8 @@
406
440
  "core/pipeline/agent-stage-policy.js",
407
441
  "core/pipeline/final-gpt-patch-stage.js",
408
442
  "core/pipeline/final-gpt-review-stage.js",
443
+ "core/pipeline/finalize-pipeline-result.js",
444
+ "core/pipeline/gpt-final-required.js",
409
445
  "core/pipeline/pipeline-plan-writer.js",
410
446
  "core/pipeline/plan-schema.js",
411
447
  "core/pipeline/prompt-context-answer.js",
@@ -437,7 +473,10 @@
437
473
  "core/ppt-review/slide-issue-extraction.js",
438
474
  "core/ppt.js",
439
475
  "core/preflight/parallel-preflight-engine.js",
476
+ "core/product-design-app-server.js",
477
+ "core/product-design-plugin.js",
440
478
  "core/prompt-context-builder.js",
479
+ "core/prompt/prompt-placeholder-guard.js",
441
480
  "core/proof-field.js",
442
481
  "core/proof/auto-finalize.js",
443
482
  "core/proof/claim-ledger.js",
@@ -568,6 +607,7 @@
568
607
  "core/zellij/zellij-lane-runtime.js",
569
608
  "core/zellij/zellij-launcher.js",
570
609
  "core/zellij/zellij-layout-builder.js",
610
+ "core/zellij/zellij-naruto-dashboard.js",
571
611
  "core/zellij/zellij-pane-proof.js",
572
612
  "core/zellij/zellij-screen-proof.js",
573
613
  "core/zellij/zellij-worker-pane-manager.js",
@@ -679,6 +719,7 @@
679
719
  "scripts/codex-0-134-runner-truth-check.js",
680
720
  "scripts/codex-0-135-compat-check.js",
681
721
  "scripts/codex-0-136-compat-check.js",
722
+ "scripts/codex-0-137-compat-check.js",
682
723
  "scripts/codex-app-fast-ui-preservation-check.js",
683
724
  "scripts/codex-app-provider-badge-check.js",
684
725
  "scripts/codex-app-ui-clobber-guard-check.js",
@@ -696,6 +737,7 @@
696
737
  "scripts/codex-control-structured-output-check.js",
697
738
  "scripts/codex-control-thread-registry-check.js",
698
739
  "scripts/codex-control-tool-call-sequence-repair-check.js",
740
+ "scripts/codex-environment-scoped-approvals-check.js",
699
741
  "scripts/codex-exec-output-schema-actual-syntax-check.js",
700
742
  "scripts/codex-fast-mode-profile-propagation-check.js",
701
743
  "scripts/codex-history-search-check.js",
@@ -710,6 +752,7 @@
710
752
  "scripts/codex-managed-proxy-env-check.js",
711
753
  "scripts/codex-output-schema-fixture-check.js",
712
754
  "scripts/codex-permission-profiles-check.js",
755
+ "scripts/codex-plugin-list-json-check.js",
713
756
  "scripts/codex-profile-primary-check.js",
714
757
  "scripts/codex-project-config-policy-merge-regression.js",
715
758
  "scripts/codex-project-config-policy-splitter-check.js",
@@ -731,6 +774,7 @@
731
774
  "scripts/codex-sdk-thread-registry-check.js",
732
775
  "scripts/codex-sdk-ux-ppt-review-pipeline-check.js",
733
776
  "scripts/codex-sdk-zellij-pane-binding-check.js",
777
+ "scripts/codex-thread-runtime-choice-check.js",
734
778
  "scripts/codex-web-adapter-check.js",
735
779
  "scripts/computer-use-live-evidence-check.js",
736
780
  "scripts/computer-use-live-optional-check.js",
@@ -802,9 +846,18 @@
802
846
  "scripts/lib/real-codex-parallel-gate.js",
803
847
  "scripts/lib/real-codex-parallel-proof-fixture.js",
804
848
  "scripts/lib/valid-png-fixture.js",
849
+ "scripts/local-collab-all-pipelines-final-gpt-check.js",
805
850
  "scripts/local-collab-gpt-final-availability-check.js",
806
851
  "scripts/local-collab-no-local-only-final-check.js",
807
852
  "scripts/local-collab-policy-check.js",
853
+ "scripts/local-llm-all-pipelines-check.js",
854
+ "scripts/local-llm-cache-performance-check.js",
855
+ "scripts/local-llm-capability-check.js",
856
+ "scripts/local-llm-smoke-check.js",
857
+ "scripts/local-llm-structured-output-check.js",
858
+ "scripts/local-llm-throughput-check.js",
859
+ "scripts/local-llm-tool-call-repair-check.js",
860
+ "scripts/local-llm-warmup-check.js",
808
861
  "scripts/loop-blocker-check.js",
809
862
  "scripts/mad-preflight-blocks-unreadable-config-check.js",
810
863
  "scripts/mad-sks-actual-executor-blackbox.js",
@@ -831,7 +884,17 @@
831
884
  "scripts/mcp-tool-naming-parity-check.js",
832
885
  "scripts/memory-summary-rebuild-check.js",
833
886
  "scripts/mutation-callsite-coverage-check.js",
887
+ "scripts/naruto-active-pool-check.js",
888
+ "scripts/naruto-concurrency-governor-check.js",
889
+ "scripts/naruto-gpt-final-pack-check.js",
890
+ "scripts/naruto-parallel-patch-apply-check.js",
891
+ "scripts/naruto-readonly-routing-check.js",
892
+ "scripts/naruto-real-local-gpt-final-smoke.js",
893
+ "scripts/naruto-role-distribution-check.js",
834
894
  "scripts/naruto-shadow-clone-swarm-check.js",
895
+ "scripts/naruto-verification-pool-check.js",
896
+ "scripts/naruto-work-graph-check.js",
897
+ "scripts/naruto-zellij-massive-ui-check.js",
835
898
  "scripts/non-recursive-pipeline-check.js",
836
899
  "scripts/npm-publish-performance-check.js",
837
900
  "scripts/official-docs-compat-report.js",
@@ -856,8 +919,15 @@
856
919
  "scripts/prepublish-fast-check.js",
857
920
  "scripts/prepublish-release-check-or-fast.js",
858
921
  "scripts/priority-full-closure-check.js",
922
+ "scripts/product-design-auto-install-check.js",
923
+ "scripts/product-design-plugin-routing-check.js",
924
+ "scripts/prompt-placeholder-guard-check.js",
859
925
  "scripts/provider-badge-context-check.js",
860
926
  "scripts/provider-context-config-toml-check.js",
927
+ "scripts/python-codex-sdk-all-pipelines-check.js",
928
+ "scripts/python-codex-sdk-capability-check.js",
929
+ "scripts/python-codex-sdk-sandbox-policy-check.js",
930
+ "scripts/python-codex-sdk-stream-bridge-check.js",
861
931
  "scripts/python-tools-smoke-check.js",
862
932
  "scripts/qa-actual-route-backfill-check.js",
863
933
  "scripts/qa-backfill-route-blackbox.js",
@@ -13,6 +13,7 @@ import { context7ConfigToml, DOLLAR_SKILL_NAMES, GETDESIGN_REFERENCE, hasContext
13
13
  import { checkZellijCapability } from '../core/zellij/zellij-capability.js';
14
14
  import { reconcileCodexAppUpgradeProcesses } from '../core/codex-app.js';
15
15
  import { recordCodexLbHealthEvent } from '../core/codex-lb-circuit.js';
16
+ import { runSksUpdateCheck, runSksUpdateNow } from '../core/update-check.js';
16
17
  import { loadCodexLbEnv, writeCodexLbKeychain, codexLbMetadataPath } from '../core/codex-lb/codex-lb-env.js';
17
18
  import { buildCodexLbSetupPlan, codexLbPersistenceSummary, installCodexLbShellProfileSnippet, selectedCodexLbPersistenceModes } from '../core/codex-lb/codex-lb-setup.js';
18
19
  const DEFAULT_CODEX_APP_PLUGINS = [
@@ -2231,6 +2232,28 @@ export async function maybePromptCodexUpdateForLaunch(args = [], opts = {}) {
2231
2232
  return { status: 'skipped_by_user', latest: latest.version || null, current, command, bin: codex.bin || null };
2232
2233
  return installCodexLatest(command, latest.version, current);
2233
2234
  }
2235
+ export async function maybePromptSksUpdateForLaunch(args = [], opts = {}) {
2236
+ if (hasFlag(args, '--json') || hasFlag(args, '--skip-sks-update') || process.env.SKS_SKIP_SKS_UPDATE === '1')
2237
+ return { status: 'skipped' };
2238
+ const label = opts.label || 'SKS launch';
2239
+ const check = await runSksUpdateCheck({ timeoutMs: 5000 }).catch((err) => ({
2240
+ ok: false,
2241
+ update_available: false,
2242
+ latest: null,
2243
+ current: PACKAGE_VERSION,
2244
+ command: null,
2245
+ error: err?.message || String(err)
2246
+ }));
2247
+ if (!check.update_available) {
2248
+ return { status: check.error ? 'unavailable' : 'current', latest: check.latest || null, current: check.current || PACKAGE_VERSION, error: check.error || null };
2249
+ }
2250
+ const command = check.command || `sks update now --version ${check.latest}`;
2251
+ if (shouldAutoApproveInstall(args)) {
2252
+ return runSksUpdateNow({ version: check.latest, timeoutMs: 10 * 60 * 1000, maxOutputBytes: 128 * 1024 });
2253
+ }
2254
+ console.log(`SKS update available before ${label}: ${check.current} -> ${check.latest}. Run when ready: ${command}`);
2255
+ return { status: 'available', latest: check.latest || null, current: check.current || PACKAGE_VERSION, command };
2256
+ }
2234
2257
  export function shouldAutoApproveInstall(args = [], env = process.env) {
2235
2258
  if (hasFlag(args, '--from-postinstall') && env.SKS_POSTINSTALL_AUTO_INSTALL_CLI_TOOLS !== '1')
2236
2259
  return false;
@@ -1,11 +1,31 @@
1
1
  import { flag } from '../cli/args.js';
2
2
  import { printJson } from '../cli/output.js';
3
- import { codexAccessTokenStatus, codexAppIntegrationStatus, codexChromeExtensionStatus, formatCodexAppStatus } from '../core/codex-app.js';
3
+ import { codexAccessTokenStatus, codexAppIntegrationStatus, codexChromeExtensionStatus, codexProductDesignPluginStatus, formatCodexAppStatus, formatCodexProductDesignPluginStatus } from '../core/codex-app.js';
4
4
  import { codexAppRemoteControlCommand } from '../cli/codex-app-command.js';
5
5
  export async function run(_command, args = []) {
6
6
  const action = args[0] || 'check';
7
7
  if (action === 'remote-control' || action === 'remote')
8
8
  return codexAppRemoteControlCommand(args.slice(1));
9
+ if (action === 'product-design' || action === 'design-product' || action === 'ensure-product-design') {
10
+ const checkOnly = flag(args, '--check-only') || flag(args, '--no-install');
11
+ const status = await codexProductDesignPluginStatus({
12
+ autoInstallProductDesign: !checkOnly && (action === 'product-design'
13
+ || action === 'design-product'
14
+ || action === 'ensure-product-design'
15
+ || flag(args, '--install')
16
+ || flag(args, '--auto-install'))
17
+ });
18
+ if (flag(args, '--json')) {
19
+ printJson(status);
20
+ if (!status.ok)
21
+ process.exitCode = 1;
22
+ return;
23
+ }
24
+ console.log(formatCodexProductDesignPluginStatus(status));
25
+ if (!status.ok)
26
+ process.exitCode = 1;
27
+ return;
28
+ }
9
29
  if (action === 'chrome-extension' || action === 'chrome') {
10
30
  const status = await codexChromeExtensionStatus();
11
31
  if (flag(args, '--json')) {
@@ -32,7 +52,9 @@ export async function run(_command, args = []) {
32
52
  return;
33
53
  }
34
54
  if (action === 'check' || action === 'status') {
35
- const status = await codexAppIntegrationStatus();
55
+ const status = await codexAppIntegrationStatus({
56
+ autoInstallProductDesign: flag(args, '--install-product-design') || flag(args, '--auto-install-product-design')
57
+ });
36
58
  if (flag(args, '--json')) {
37
59
  printJson(status);
38
60
  if (!status.ok)
@@ -44,7 +66,7 @@ export async function run(_command, args = []) {
44
66
  process.exitCode = 1;
45
67
  return;
46
68
  }
47
- console.error('Usage: sks codex-app check|status|chrome-extension|pat status|remote-control [--json]');
69
+ console.error('Usage: sks codex-app check|status|product-design [--check-only]|ensure-product-design|chrome-extension|pat status|remote-control [--json]');
48
70
  process.exitCode = 1;
49
71
  }
50
72
  //# sourceMappingURL=codex-app.js.map
@@ -17,10 +17,24 @@ import { inventoryCodexPermissionProfiles } from '../core/codex/codex-permission
17
17
  import { appendMigrationEvents, hashConfigText } from '../core/migration/migration-transaction-journal.js';
18
18
  import { repairCodexAppFastUi } from '../core/codex-app/codex-app-fast-ui-repair.js';
19
19
  import { resolveProviderContext } from '../core/provider/provider-context.js';
20
+ import { readLocalModelConfig } from '../core/agents/ollama-worker-config.js';
21
+ import { runSksUpdateNow } from '../core/update-check.js';
20
22
  export async function run(_command, args = []) {
23
+ const doctorFix = flag(args, '--fix');
21
24
  let setupRepair = null;
25
+ const sksUpdate = doctorFix
26
+ ? await runSksUpdateNow({
27
+ timeoutMs: 10 * 60 * 1000,
28
+ maxOutputBytes: 128 * 1024
29
+ }).catch((err) => ({
30
+ schema: 'sks.update-now.v1',
31
+ ok: false,
32
+ status: 'failed',
33
+ error: err?.message || String(err)
34
+ }))
35
+ : null;
22
36
  let migrationPreFix = null;
23
- if (flag(args, '--fix')) {
37
+ if (doctorFix) {
24
38
  // Snapshot config content before ANY mutation so the migration journal can
25
39
  // record real before/after hashes for the whole --fix transaction.
26
40
  migrationPreFix = await captureCodexConfigSnapshot();
@@ -96,7 +110,6 @@ export async function run(_command, args = []) {
96
110
  model_provider: null
97
111
  }
98
112
  }));
99
- const doctorFix = flag(args, '--fix');
100
113
  const explicitCodexAppUiRepair = flag(args, '--repair-codex-app-ui') || flag(args, '--yes');
101
114
  const codexAppUiPlan = await repairCodexAppFastUi(root, {
102
115
  apply: false,
@@ -136,6 +149,7 @@ export async function run(_command, args = []) {
136
149
  }))
137
150
  : codexAppUiPlan;
138
151
  const zellij = await checkZellijCapability({ root, require: process.env.SKS_REQUIRE_ZELLIJ === '1' });
152
+ const localModel = await readLocalModelConfig().catch(() => null);
139
153
  const permissionProfiles = await inventoryCodexPermissionProfiles(root, { writeReport: true });
140
154
  const globalSksInstallCleanup = flag(args, '--fix') && !flag(args, '--local-only')
141
155
  ? await cleanDuplicateGlobalSksInstalls({ root, fix: true }).catch((err) => ({ schema: 'sks.global-sks-install-cleanup.v1', ok: false, fix: true, error: err?.message || String(err), blockers: ['global_sks_install_cleanup_exception'] }))
@@ -151,6 +165,7 @@ export async function run(_command, args = []) {
151
165
  codex_doctor: codexDoctor,
152
166
  require_codex_doctor: flag(args, '--fix') || flag(args, '--require-actual-codex'),
153
167
  zellij,
168
+ local_model: localModel,
154
169
  repair: configRepair,
155
170
  codex_app_ui: codexAppUi,
156
171
  require_codex_cli_config_load: flag(args, '--fix') || flag(args, '--require-actual-codex'),
@@ -162,7 +177,7 @@ export async function run(_command, args = []) {
162
177
  const zellijReadiness = buildZellijReadiness(root, zellij, ready);
163
178
  const result = {
164
179
  schema: 'sks.doctor-status.v1',
165
- ok: ready.ready,
180
+ ok: ready.ready && (!sksUpdate || sksUpdate.ok !== false),
166
181
  root,
167
182
  node: { ok: Number(process.versions.node.split('.')[0]) >= 20, version: process.version },
168
183
  codex,
@@ -175,6 +190,7 @@ export async function run(_command, args = []) {
175
190
  codex_doctor: codexDoctor,
176
191
  codex_doctor_diff: codexDoctorDiff,
177
192
  zellij,
193
+ local_model: localModel,
178
194
  zellij_readiness: zellijReadiness,
179
195
  codex_permission_profiles: permissionProfiles,
180
196
  imagegen: {
@@ -185,7 +201,7 @@ export async function run(_command, args = []) {
185
201
  ready,
186
202
  sneakoscope: { ok: await exists(`${root}/.sneakoscope`) },
187
203
  package: { bytes: pkgBytes, human: formatBytes(pkgBytes) },
188
- repair: { setup: setupRepair, codex_config: configRepair, migration_journal: migrationJournal, global_sks_installs: globalSksInstallCleanup }
204
+ repair: { sks_update: sksUpdate, setup: setupRepair, codex_config: configRepair, migration_journal: migrationJournal, global_sks_installs: globalSksInstallCleanup }
189
205
  };
190
206
  if (flag(args, '--json')) {
191
207
  printJson(result);
@@ -234,6 +250,16 @@ export async function run(_command, args = []) {
234
250
  }
235
251
  }
236
252
  console.log(`codex-lb: ${codexLb.ok ? 'ok' : `warning ${codexLb.circuit?.state || 'unknown'}`}`);
253
+ if (localModel) {
254
+ console.log('Local LLM:');
255
+ console.log(` enabled: ${localModel.enabled ? 'yes' : 'no'}`);
256
+ console.log(` status: ${localModel.status}`);
257
+ console.log(` provider: ${localModel.provider}`);
258
+ console.log(` model: ${localModel.model}`);
259
+ console.log(` endpoint: ${localModel.base_url}`);
260
+ 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'}`);
261
+ console.log(' final arbiter: GPT required');
262
+ }
237
263
  console.log(`Permissions: config profile and permission profile are tracked separately (${permissionProfiles.codex_config_profile_field}, ${permissionProfiles.codex_permission_profile_field})`);
238
264
  console.log('Ready:');
239
265
  console.log(` cli_ready: ${ready.cli_ready ? 'yes' : 'no'}`);
@@ -251,6 +277,9 @@ export async function run(_command, args = []) {
251
277
  if (migrationJournal?.journal_path) {
252
278
  console.log(`Migration journal: ${migrationJournal.journal_path} (${migrationJournal.event_count} events, ${migrationJournal.mutations_without_rollback} without rollback)`);
253
279
  }
280
+ if (sksUpdate) {
281
+ console.log(`SKS update: ${sksUpdate.status}${sksUpdate.latest ? ` latest ${sksUpdate.latest}` : ''}${sksUpdate.error ? ` (${sksUpdate.error})` : ''}`);
282
+ }
254
283
  if (globalSksInstallCleanup) {
255
284
  console.log(`Global SKS installs: kept ${globalSksInstallCleanup.kept?.length ?? 0}, removed ${globalSksInstallCleanup.removed?.filter((entry) => entry.ok).length ?? 0}, source repo exempt ${globalSksInstallCleanup.candidates?.filter((entry) => entry.source_repo_exempt).length ?? 0}`);
256
285
  }
@@ -1,9 +1,9 @@
1
1
  import { madHighCommand } from '../core/commands/mad-sks-command.js';
2
- import { ensureMadLaunchDependencies, formatMadLaunchDependencyAction, maybePromptCodexUpdateForLaunch, maybePromptCodexLbSetupForLaunch } from '../cli/install-helpers.js';
2
+ import { ensureMadLaunchDependencies, formatMadLaunchDependencyAction, maybePromptCodexUpdateForLaunch, maybePromptCodexLbSetupForLaunch, maybePromptSksUpdateForLaunch } from '../cli/install-helpers.js';
3
3
  import { PACKAGE_VERSION } from '../core/fsx.js';
4
4
  export async function run(_command, args = []) {
5
5
  return madHighCommand(['--mad-sks', ...args], {
6
- maybePromptSksUpdateForLaunch: async () => ({ status: 'skipped' }),
6
+ maybePromptSksUpdateForLaunch,
7
7
  maybePromptCodexUpdateForLaunch,
8
8
  ensureMadLaunchDependencies,
9
9
  printDepsInstallAction: (action) => console.error(formatMadLaunchDependencyAction(action)),
@@ -117,6 +117,7 @@ export async function runNativeAgentOrchestrator(opts = {}) {
117
117
  const strategyCompiled = compileStrategy({
118
118
  prompt,
119
119
  route,
120
+ ...(writeCapable ? {} : { writeTargets: [] }),
120
121
  agentCount: roster.agent_count,
121
122
  visualRequired
122
123
  });
@@ -235,12 +236,13 @@ export async function runNativeAgentOrchestrator(opts = {}) {
235
236
  rate_limit_delay_ms: backend === 'codex-sdk' ? 250 : 0,
236
237
  resource_pressure_warnings: roster.agent_count > roster.concurrency ? ['agents_exceed_concurrency_batches'] : []
237
238
  });
239
+ const effectiveWriteMode = writeCapable ? opts.writeMode || 'off' : 'off';
238
240
  const parallelWritePolicy = {
239
241
  schema: 'sks.agent-parallel-write-policy.v1',
240
242
  generated_at: nowIso(),
241
243
  route,
242
244
  route_command: routeCommand,
243
- write_mode: opts.writeMode || 'off',
245
+ write_mode: effectiveWriteMode,
244
246
  apply_patches: opts.applyPatches === true,
245
247
  dry_run_patches: opts.dryRunPatches === true,
246
248
  max_write_agents: Number(opts.maxWriteAgents || 0),
@@ -779,7 +781,7 @@ async function runAgentPatchSwarmRuntime(root, ledgerRoot, input) {
779
781
  await queueStore.persistSnapshot();
780
782
  const journalSummary = await queueStore.journal.writeSummary();
781
783
  const proof = buildAgentPatchProof({ ...proofInput, transactionJournal: journalSummary });
782
- const zeroPatchBlockers = input.writeCapable && input.parallelWritePolicy?.write_mode === 'parallel' && pendingEntries.length === 0 && input.parallelWritePolicy?.dry_run_patches !== true
784
+ const zeroPatchBlockers = input.writeCapable && input.parallelWritePolicy?.write_mode === 'parallel' && pendingEntries.length === 0 && input.dryRun !== true && input.parallelWritePolicy?.dry_run_patches !== true
783
785
  ? ['write_mode_parallel_zero_patch_envelopes']
784
786
  : [];
785
787
  const blockers = [
@@ -870,6 +872,8 @@ function normalizeVisualLaneCount(value, fallback, maxAgentCount) {
870
872
  return Math.max(1, Math.min(maxAgentCount, Math.floor(raw)));
871
873
  }
872
874
  function isWriteCapableRun(opts) {
875
+ if (opts.readonly === true)
876
+ return false;
873
877
  return opts.applyPatches === true || opts.dryRunPatches === true || (opts.writeMode !== undefined && opts.writeMode !== 'off');
874
878
  }
875
879
  function defaultRouteCommand(route) {
@@ -991,6 +995,7 @@ async function runAgentByBackend(backend, agent, slice, opts) {
991
995
  ...sdkWorkerResult,
992
996
  backend: 'codex-sdk',
993
997
  patch_envelopes: patchEnvelopes,
998
+ ...(patchEnvelopes.length ? {} : { no_patch_reason: buildDirectNoPatchReason(slice, opts) }),
994
999
  codex_child_report: sdkReport,
995
1000
  codex_sdk_thread: sdkReport,
996
1001
  model_authored_patch_envelopes: patchEnvelopes.length > 0,
@@ -1027,10 +1032,24 @@ function buildDirectSdkWorkerPrompt(slice) {
1027
1032
  '',
1028
1033
  write.length
1029
1034
  ? `Write-capable slice. Return JSON matching ${CODEX_AGENT_WORKER_RESULT_SCHEMA_ID}; include patch_envelopes for write_paths=${JSON.stringify(write)}. Each patch envelope must include schema, source "model_authored", agent_id, session_id, slot_id, generation_index, task_slice_id, lease_id, allowed_paths, operations, and rationale. Each operation must include op, path, search, replace, content, and diff; use empty strings for operation fields that do not apply.`
1030
- : `Read-only slice. Return JSON matching ${CODEX_AGENT_WORKER_RESULT_SCHEMA_ID}.`,
1035
+ : `Read-only slice. Return JSON matching ${CODEX_AGENT_WORKER_RESULT_SCHEMA_ID}; do not report pre-existing repository dirtiness as changed_files.`,
1031
1036
  'Required JSON fields: status, summary, findings, changed_files, patch_envelopes, verification, rollback_notes, blockers.'
1032
1037
  ].join('\n');
1033
1038
  }
1039
+ function buildDirectNoPatchReason(slice, opts) {
1040
+ const writePathCount = sdkWritePaths(slice, opts).length;
1041
+ return {
1042
+ schema: 'sks.native-cli-worker-no-patch-reason.v1',
1043
+ generated_at: nowIso(),
1044
+ ok: writePathCount === 0,
1045
+ reason: writePathCount ? 'write_capable_task_without_backend_patch_envelope' : 'read_only_or_no_write_paths',
1046
+ route_justification: writePathCount ? 'backend returned no patch envelopes for a write-capable task' : 'task has no write paths',
1047
+ read_only_or_noop_evidence: writePathCount === 0,
1048
+ task_slice_id: slice?.id || null,
1049
+ backend: 'codex-sdk',
1050
+ blockers: writePathCount ? ['write_capable_no_patch_envelope'] : []
1051
+ };
1052
+ }
1034
1053
  function sdkWritePaths(slice, opts) {
1035
1054
  return [
1036
1055
  ...(Array.isArray(slice?.write_paths) ? slice.write_paths : []),