sneakoscope 10.3.4 → 10.3.5

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 (81) hide show
  1. package/README.md +203 -3
  2. package/config/skills-hash-ledger.v1.json +17 -1
  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 +3 -1
  6. package/dist/cli/command-registry.js +8 -0
  7. package/dist/cli/install-helpers.js +1 -2
  8. package/dist/commands/doctor.js +1 -2
  9. package/dist/commands/imagegen.js +154 -0
  10. package/dist/config/skills-manifest.json +35 -19
  11. package/dist/core/agents/native-worker-backend-router.js +13 -4
  12. package/dist/core/agents/official-subagent-helper-policy.js +1 -2
  13. package/dist/core/codex-app/menubar/constants.js +2 -0
  14. package/dist/core/codex-app.js +6 -6
  15. package/dist/core/codex-lb/desktop-bridge/imagegen-endpoint.js +95 -0
  16. package/dist/core/codex-lb/desktop-bridge/server.js +6 -1
  17. package/dist/core/codex-lb/desktop-bridge/types.js +1 -0
  18. package/dist/core/codex-native/core-skill-manifest.js +4 -5
  19. package/dist/core/codex-native/native-capability-repair-matrix.js +4 -5
  20. package/dist/core/commands/image-ux-review-command.js +6 -7
  21. package/dist/core/commands/ppt-command.js +3 -4
  22. package/dist/core/commands/qa-loop-command.js +28 -3
  23. package/dist/core/decisions/cli.js +1 -1
  24. package/dist/core/decisions/integration.js +51 -0
  25. package/dist/core/decisions/policy.js +27 -0
  26. package/dist/core/decisions/questions.js +44 -3
  27. package/dist/core/decisions/types.js +2 -0
  28. package/dist/core/doctor/doctor-readiness-matrix.js +1 -2
  29. package/dist/core/doctor/imagegen-repair.js +3 -4
  30. package/dist/core/feature-fixtures.js +1 -0
  31. package/dist/core/feature-registry.js +3 -3
  32. package/dist/core/hooks-runtime/hook-context.js +2 -2
  33. package/dist/core/hooks-runtime/hook-io.js +1 -2
  34. package/dist/core/hooks-runtime/jev-turn-plan.js +81 -0
  35. package/dist/core/hooks-runtime/managed-guidance-preflight.js +24 -4
  36. package/dist/core/hooks-runtime.js +29 -5
  37. package/dist/core/image-ux-review/imagegen-adapter.js +159 -316
  38. package/dist/core/image-ux-review.js +28 -20
  39. package/dist/core/imagegen/imagegen-auth-readiness.js +10 -8
  40. package/dist/core/imagegen/imagegen-capability.js +79 -14
  41. package/dist/core/imagegen/imagegen-config.js +45 -0
  42. package/dist/core/imagegen/imagegen-evidence.js +14 -2
  43. package/dist/core/imagegen/imagegen-generate.js +284 -0
  44. package/dist/core/imagegen/imagegen-jev.js +53 -0
  45. package/dist/core/imagegen/imagegen-model-policy.js +2 -5
  46. package/dist/core/imagegen/imagegen-request-validator.js +3 -3
  47. package/dist/core/imagegen/openrouter-images.js +288 -0
  48. package/dist/core/imagegen/require-imagegen.js +14 -7
  49. package/dist/core/init/skills.js +9 -10
  50. package/dist/core/lean-engineering-policy.js +2 -2
  51. package/dist/core/managed-assets/managed-assets-manifest.js +1 -2
  52. package/dist/core/pipeline-internals/runtime-core.js +4 -5
  53. package/dist/core/pipeline-internals/runtime-gates.js +5 -5
  54. package/dist/core/ppt-review/ppt-patch-handoff.js +1 -2
  55. package/dist/core/ppt-review/slide-imagegen-review.js +10 -11
  56. package/dist/core/ppt.js +50 -35
  57. package/dist/core/qa-loop/qa-loop-budget-policy.js +6 -2
  58. package/dist/core/qa-loop.js +8 -8
  59. package/dist/core/recallpulse.js +1 -2
  60. package/dist/core/research/research-synthesis-prompt.js +2 -3
  61. package/dist/core/routes/design-policy.js +1 -2
  62. package/dist/core/routes/dollar-manifest-lite.js +1 -2
  63. package/dist/core/routes/evidence.js +1 -1
  64. package/dist/core/routes/ppt-policy.js +1 -2
  65. package/dist/core/routes.js +16 -5
  66. package/dist/core/subagents/agent-catalog.js +1 -2
  67. package/dist/core/subagents/official-subagent-prompt.js +3 -3
  68. package/dist/core/triwiki-wrongness/wrongness-schema.js +3 -4
  69. package/dist/core/update/project-migration-fanout-runner.js +56 -0
  70. package/dist/core/update/sks-project-registry.js +223 -0
  71. package/dist/core/update/update-migration-state.js +7 -9
  72. package/dist/core/update/update-operation.js +3 -0
  73. package/dist/core/version.js +1 -1
  74. package/dist/native/sks-menubar/Sources/ControlCenterWindowController.swift +2 -0
  75. package/dist/native/sks-menubar/Sources/ImageGenerationModels.swift +341 -0
  76. package/dist/native/sks-menubar/Sources/ImageGenerationViewController.swift +330 -0
  77. package/dist/native/sks-menubar/Sources/SidebarItem.swift +2 -0
  78. package/dist/scripts/qa-loop-effort-escalation-check.js +4 -0
  79. package/package.json +1 -1
  80. package/dist/core/codex-app/openrouter-base-instructions.js +0 -1
  81. package/dist/core/research/research-prompt-contract.js +0 -23
package/README.md CHANGED
@@ -16,7 +16,7 @@
16
16
  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.
17
17
  <!-- END SKS SEARCH VISIBILITY MARKETING -->
18
18
 
19
- Current package: **SKS 10.3.4**. Install the latest stable release from npm.
19
+ Current package: **SKS 10.3.5**. Install the latest stable release from npm.
20
20
 
21
21
  [Quick start](#install-in-one-command) · [Commands](#everyday-commands) · [SKS Center](#sks-center-macos) · [Documentation](#documentation) · [Changelog](CHANGELOG.md)
22
22
 
@@ -104,6 +104,7 @@ home directory; set `SKS_POSTINSTALL_MENUBAR=1` to force the build in a script,
104
104
  | Connections | Connect Codex-LB or OpenRouter, choose authentication priority, and manage exposed models. |
105
105
  | Updates | Check and update SKS and Codex CLI, with operation progress and recovery details. |
106
106
  | MCP Servers | Manage server configuration, health checks, and authentication. |
107
+ | Image Generation | Keep Codex's default image generation, or route it through the Desktop Bridge to an OpenRouter image model you pick. |
107
108
  | Diagnostics | Inspect issues and run targeted checks. |
108
109
  | Settings | Configure lifecycle behavior, notifications, and advanced options. |
109
110
  | Remote Coding | Find the independent [Paseo companion](https://paseo.sh/docs) and its setup guidance. |
@@ -136,6 +137,204 @@ Enter credentials through the native connection dialog or the CLI's
136
137
  `--api-key-stdin` option. See the [provider guide](docs/codex-lb.md) for
137
138
  configuration, transport checks, and recovery commands.
138
139
 
140
+ ## Image generation
141
+
142
+ SKS image routes (image generation, UX-Review callouts, PPT assets, slide
143
+ reviews) follow one image mode. By default they use Codex's own image
144
+ generation. Turn on a custom image model on the **Image Generation** page to
145
+ send every SKS image through the Desktop Bridge to an OpenRouter image model
146
+ you pick. SKS pins no image model and records which model made each image.
147
+
148
+ ```sh
149
+ sks imagegen status --json
150
+ sks imagegen models --json
151
+ sks imagegen enable --model black-forest-labs/flux.2-klein-4b
152
+ sks imagegen generate --prompt "App icon, flat, blue" --out icon.png
153
+ sks imagegen disable
154
+ ```
155
+
156
+ See [Image generation](docs/image-generation.md) for both modes, evidence
157
+ sidecars, and the Jev choices.
158
+
159
+ ## Naruto workflow
160
+
161
+ The parent orchestrates: it decomposes the task, spawns a child for each
162
+ disjoint slice, waits, and owns integration and final verification. It does not
163
+ implement slices itself. The SKS PreToolUse hook denies parent source edits
164
+ until the first child starts and while children are still running. Children
165
+ receive bounded tasks and do not spawn children.
166
+
167
+ No model family is pinned. Every child runs the newest model of the tier its
168
+ work needs, read from the Codex models cache, so a new model family is used as
169
+ soon as Codex lists it:
170
+
171
+ | Work | Tier | Effort | Today |
172
+ | --- | --- | --- | --- |
173
+ | Tiny mechanical tasks | fast | low | `gpt-6-luna` |
174
+ | Instructed implementation | balanced | low | `gpt-6-sol` |
175
+ | Exploration, large-context reads, and direct tool operation | context | medium | `gpt-6-sol` |
176
+ | Planning, review, debugging, and focused judgment | deep | max | `gpt-6-astra` |
177
+
178
+ With Jev mode on, Jev picks the tier for every spawn, every gated parent edit,
179
+ the plan, and the context, so the parent spends no time on those choices. It
180
+ also picks the pipeline for each prompt; an explicit SKS `<div align="center">
181
+
182
+ <img src="docs/assets/sks-logo.svg" alt="Sneakoscope Codex logo" width="120" height="120" />
183
+
184
+ # Sneakoscope Codex
185
+
186
+ **Plan, build, and verify with Codex.**
187
+
188
+ [![npm version](https://img.shields.io/npm/v/sneakoscope?color=cb3837&logo=npm)](https://www.npmjs.com/package/sneakoscope)
189
+ [![node](https://img.shields.io/badge/node-%3E%3D20.11-339933?logo=node.js&logoColor=white)](#requirements)
190
+ [![license](https://img.shields.io/badge/license-MIT-blue)](LICENSE)
191
+
192
+ </div>
193
+
194
+ <!-- BEGIN SKS SEARCH VISIBILITY MARKETING -->
195
+ 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.
196
+ <!-- END SKS SEARCH VISIBILITY MARKETING -->
197
+
198
+ Current package: **SKS 10.3.5**. Install the latest stable release from npm.
199
+
200
+ [Quick start](#install-in-one-command) · [Commands](#everyday-commands) · [SKS Center](#sks-center-macos) · [Documentation](#documentation) · [Changelog](CHANGELOG.md)
201
+
202
+ ## Install in one command
203
+
204
+ ```sh
205
+ npm exec --yes --package=sneakoscope@latest -- sneakoscope install --yes
206
+ ```
207
+
208
+ The installer resolves the latest release, installs it globally, runs setup and
209
+ Doctor, and checks that `sks` on your PATH points to the installed version.
210
+
211
+ To set up a project, run this from its root, then open it in Codex:
212
+
213
+ ```sh
214
+ sks bootstrap --yes
215
+ ```
216
+
217
+ ## What SKS adds
218
+
219
+ | Capability | What you get |
220
+ | --- | --- |
221
+ | Focused execution | Answers and tiny edits stay lightweight; implementation work runs through official Codex subagents while the parent orchestrates and integrates. |
222
+ | Project context | TriWiki indexes repository code and supplies bounded context that can be checked against source. |
223
+ | Verification | Tests, diagnostics, and release evidence support completion claims. Security and data-integrity checks stay in place. |
224
+ | Native controls | SKS Center brings connections, updates, MCP servers, and diagnostics together on macOS. |
225
+ | Consistent setup | `sks update` installs the latest release, runs Doctor, and reconciles SKS-managed files and legacy assets. |
226
+
227
+ The default `essential` profile avoids repetitive completion rituals. `strict`
228
+ adds stronger completion requirements. See [Essential Trust](docs/essential-trust.md).
229
+
230
+ With Codex-LB connected, `sks agent-bridge async --prompt "Check SKS status while
231
+ explaining what the check covers" --tools status --json` runs native Astra Async
232
+ tool calling with selected read-only SKS tools, using WebSocket first and safe
233
+ HTTP fallback. See [Astra guidance](docs/astra-guidance.md)
234
+ for setup boundaries and reported execution evidence.
235
+
236
+ ## Everyday commands
237
+
238
+ SKS enables experimental Astra context management by default during setup and
239
+ repair. Turn it off in **SKS Center → Settings → Astra context management**, or
240
+ use `sks codex-app context-management off`. Updates preserve an explicit opt-out.
241
+ Start a new task after changing the setting. Availability depends on a supported
242
+ Codex client and eligible ChatGPT sign-in; API-key and custom-provider sessions
243
+ may not activate it. See [OpenAI's context management guidance](https://learn.chatgpt.com/docs/models#experimental-context-management).
244
+
245
+ Use these inside a Codex conversation:
246
+
247
+ | Command | Purpose |
248
+ | --- | --- |
249
+ | `$sks-plan "task"` | Create a plan without editing product code. |
250
+ | `$sks-work` | Execute the latest plan. |
251
+ | `$sks-naruto "task"` | Run an official subagent workflow. |
252
+ | `$sks-review` | Review the current changes. |
253
+ | `$sks-help` | Explore available SKS workflows. |
254
+
255
+ Use these in your terminal:
256
+
257
+ ```sh
258
+ sks --help
259
+ sks status --json
260
+ sks review --staged
261
+ sks doctor --json
262
+ sks update-check
263
+ sks update
264
+ ```
265
+
266
+ `sks update` runs setup reconciliation even when the package is already current.
267
+ It preserves user-authored configuration and cleans up recognized SKS-owned
268
+ legacy assets. If a check needs attention, follow its reported recovery action
269
+ in your terminal.
270
+
271
+ ## SKS Center (macOS)
272
+
273
+ Open **SKS Control Center** from the SKS menu bar.
274
+ The Menu Bar app (with the Control Center) is built from source on macOS when you run
275
+ `npm i -g sneakoscope` interactively in a terminal, and by `sks install`, `sks doctor --fix`,
276
+ `sks update`, or `sks menubar install`. Dependency, CI, and piped installs never touch your
277
+ home directory; set `SKS_POSTINSTALL_MENUBAR=1` to force the build in a script, or
278
+ `SKS_POSTINSTALL_NO_MENUBAR=1` to skip it.
279
+
280
+ | Page | Use it to |
281
+ | --- | --- |
282
+ | Overview | Check local health and find the next action. |
283
+ | Connections | Connect Codex-LB or OpenRouter, choose authentication priority, and manage exposed models. |
284
+ | Updates | Check and update SKS and Codex CLI, with operation progress and recovery details. |
285
+ | MCP Servers | Manage server configuration, health checks, and authentication. |
286
+ | Image Generation | Keep Codex's default image generation, or route it through the Desktop Bridge to an OpenRouter image model you pick. |
287
+ | Diagnostics | Inspect issues and run targeted checks. |
288
+ | Settings | Configure lifecycle behavior, notifications, and advanced options. |
289
+ | Remote Coding | Find the independent [Paseo companion](https://paseo.sh/docs) and its setup guidance. |
290
+
291
+ Connection controls appear first. Model catalogs, bridge diagnostics, and
292
+ advanced settings expand when you need them.
293
+
294
+ ## Desktop Bridge
295
+
296
+ One local bridge manages routing for independent **Codex-LB** and **OpenRouter**
297
+ profiles. ChatGPT sign-in remains owned by Codex. Provider choices and existing
298
+ session pins remain authoritative; unavailable routes are reported explicitly.
299
+
300
+ In **Connections**, turn on **Prefer Codex-LB** to use the saved Codex-LB
301
+ connection first for eligible models. The switch distinguishes a saved preference
302
+ from connection readiness: **on but unavailable** means setup needs attention.
303
+ Turning it off restores the configured official-model routing preference.
304
+
305
+ The same controls are available from the CLI:
306
+
307
+ ```sh
308
+ sks bridge auth-priority status --json
309
+ sks bridge auth-priority on --json
310
+ sks bridge auth-priority off --json
311
+ sks bridge status --json
312
+ sks bridge route explain gpt-6-astra --json
313
+ ```
314
+
315
+ Enter credentials through the native connection dialog or the CLI's
316
+ `--api-key-stdin` option. See the [provider guide](docs/codex-lb.md) for
317
+ configuration, transport checks, and recovery commands.
318
+
319
+ ## Image generation
320
+
321
+ SKS image routes (image generation, UX-Review callouts, PPT assets, slide
322
+ reviews) follow one image mode. By default they use Codex's own image
323
+ generation. Turn on a custom image model on the **Image Generation** page to
324
+ send every SKS image through the Desktop Bridge to an OpenRouter image model
325
+ you pick. SKS pins no image model and records which model made each image.
326
+
327
+ ```sh
328
+ sks imagegen status --json
329
+ sks imagegen models --json
330
+ sks imagegen enable --model black-forest-labs/flux.2-klein-4b
331
+ sks imagegen generate --prompt "App icon, flat, blue" --out icon.png
332
+ sks imagegen disable
333
+ ```
334
+
335
+ See [Image generation](docs/image-generation.md) for both modes, evidence
336
+ sidecars, and the Jev choices.
337
+
139
338
  ## Naruto workflow
140
339
 
141
340
  The parent orchestrates: it decomposes the task, spawns a child for each
@@ -156,8 +355,9 @@ soon as Codex lists it:
156
355
  | Planning, review, debugging, and focused judgment | deep | max | `gpt-6-astra` |
157
356
 
158
357
  With Jev mode on, Jev picks the tier for every spawn, every gated parent edit,
159
- the plan, and the context, so the parent spends no time on those choices. A
160
- stored role-model preference on a current model wins in both modes.
358
+ the plan, and the context, so the parent spends no time on those choices. It
359
+ command always
360
+ wins. A stored role-model preference on a current model wins in both modes.
161
361
 
162
362
  An active Codex task keeps the user's selected main model, effort, and service
163
363
  tier. Codex native `/goal` remains the persisted goal owner. Parallelism depends
@@ -14,6 +14,7 @@
14
14
  {
15
15
  "canonical_name": "sks-align",
16
16
  "trusted_sha256": [
17
+ "9eef36214be7e07a963eb36bb1df2c025cd0578b7419ddf4fd307081a2b62093",
17
18
  "b9db40d6e1dd2fc6e4665a2b30738d370da955cd4d6e86c88bd85059c7faa08c",
18
19
  "c485f39d4873adb9793672f7dcf4e956595ffb9dcbb032b3ffb0515b5857d31d",
19
20
  "e98e1b67e228bec5c37d00c0206a2e01d2da698a83c80b527105bf04a19c136a"
@@ -56,6 +57,7 @@
56
57
  {
57
58
  "canonical_name": "sks-commit",
58
59
  "trusted_sha256": [
60
+ "63cad87de9187f67e001949b0edcf39344626748f8f168bed257316dc1684d53",
59
61
  "aa2eeaa6be6d635170a8ecfc76353db95552f543cca107f239054c492409e3a9",
60
62
  "aea41328993b11e26e26ae94df6ed44312d1570ed39448531428b53ade9d7461",
61
63
  "943c6dcf822df086b320140e74404d4c7bcfd531264e25ada6624b5009f26207"
@@ -64,6 +66,7 @@
64
66
  {
65
67
  "canonical_name": "sks-commit-and-push",
66
68
  "trusted_sha256": [
69
+ "2307093e26513a26e71ac6cdfcf3fd1598979c6035525ee5d3de58820cb4adda",
67
70
  "acd6c7845c58d72234776e4608e1440583c62c38b513625d1272e4a413a40fb6",
68
71
  "8e4ff7a39440c82e6c67a67d5bb267c69f508cedb5d9d5a93261f4dcdf8e8a1a",
69
72
  "b005b4a7456b80b95768ad358fe5950bf517483c6de71aec14ee3d1c600cc074"
@@ -126,6 +129,7 @@
126
129
  {
127
130
  "canonical_name": "sks-design-artifact-expert",
128
131
  "trusted_sha256": [
132
+ "6881c1acff42b3cc760f089165a6ea753c774882bf0ec989b71f14936e894690",
129
133
  "6db9a7088e5f8d21dec9c8eed00abe665e1e89f19dcbb6d8472d77e4551cb556",
130
134
  "a09daba0a2e479a68ed81ec6fba8d70e54c8398ed86f3d1879f874b98480b97c",
131
135
  "4a28d166eaf0bc4477b566b056034f972a7034165e36d8186daa9947bf92e3cf"
@@ -134,6 +138,7 @@
134
138
  {
135
139
  "canonical_name": "sks-design-system-builder",
136
140
  "trusted_sha256": [
141
+ "9075bc17039da34ddd7d798009fdbcdedb8d03358a29c9a925d194bd76e9dcc4",
137
142
  "47654c9f74317abbd0a5a75f89cd2d563708e8234e8887cc7ab39bf49030abaa",
138
143
  "0a41e6ace960abaaf6abf5e7b1e53fd39f414e1e00b59fa725f2db9e3eb05b58",
139
144
  "c4f0007cad5774510bdc55e2815ce0911c220afa8d5dd4efc327ba1231c8f3da"
@@ -142,6 +147,7 @@
142
147
  {
143
148
  "canonical_name": "sks-design-ui-editor",
144
149
  "trusted_sha256": [
150
+ "c3bc8bbaac134f7d742cd5e4bed7dd61a99655c54a6bd42f669e6bdd033156fb",
145
151
  "2f9087664d8abe938a6dfbeaef5301ef00531e34a15506508e1d6d6b7132b894",
146
152
  "6c24e950a12dec52c625964069c7c21a0220a58e0f69f977d802f44fdb03a940",
147
153
  "83a806cc93a3c5342e0dccfc6a45983382d5bf74d1226c4e3288228db22b737a",
@@ -201,6 +207,7 @@
201
207
  {
202
208
  "canonical_name": "sks-goal",
203
209
  "trusted_sha256": [
210
+ "942c5e8db400cc1cd2b5ca9527124135fb4b8d9e8289338632d8929691aa54ed",
204
211
  "36c12285a339f9505fd88d6d9ea5691e451449f0bf8f55c21f51f0d715623235",
205
212
  "5ab1ac18fc265c375bae92ff23ddbd80c378484d6629c378f0e9270e660ded11",
206
213
  "867544877ac04df6e0232d6d425797e7fab2cceff9a7176a3c9e61f8c4a416d7",
@@ -277,6 +284,7 @@
277
284
  {
278
285
  "canonical_name": "sks-image-ux-review",
279
286
  "trusted_sha256": [
287
+ "643400c1682aaa4a84782e3740eb14efb0ddb905a84c086bd9a0f8afdabd5f02",
280
288
  "c7a5ea91adb0d45e652066cdb73f514cc7fcb47121cc13cce5e177f94630a42a",
281
289
  "54d4169dc7f362ac9fe2d090bd2612e41d30acbc3e883d6bd382929bdfb9459e",
282
290
  "9293346873b5fb25a9d93b630064a2c8ceede2bfdfa4c6ffe7fbb7f64da6595c"
@@ -285,6 +293,7 @@
285
293
  {
286
294
  "canonical_name": "sks-imagegen",
287
295
  "trusted_sha256": [
296
+ "0f3ba271f2977d1124b8236e25f5e05a3d03af234652e39601dc5054346e306c",
288
297
  "ebad63dae59ff70a4404148d09bffaca69e6c43e88d6e9f6f3d0dc4d5a4c65f6",
289
298
  "478e3d8f805eed55c3f3e6c2069142482a7dbd8fa5d9a59f03b136e0e1cb77d0",
290
299
  "a7f466ba1829a757f38432fbe8c3a672e22e91948537dafe8f8ce09561d2256e",
@@ -294,6 +303,7 @@
294
303
  {
295
304
  "canonical_name": "sks-imagegen-source-scout",
296
305
  "trusted_sha256": [
306
+ "84957463d326f0f7028fc47aabb3f1857c76f13534e3aed1c9fc1b075896dbd1",
297
307
  "b306134faf487b86e11a9736ea1ed60d2335eef858e58bedc80fd3dc4ff7137c",
298
308
  "440f361fb29afcbb6f6cdc88c6a7318953b4c8fd3181ef7c6d8187f091d18745",
299
309
  "95faf4358f1c6567ca6894bfb577629f14a23d623716be70325c0ff9a893d42e",
@@ -325,6 +335,7 @@
325
335
  {
326
336
  "canonical_name": "sks-naruto",
327
337
  "trusted_sha256": [
338
+ "c88999663811a50d096b7cbb696fbea5b8f72707bcbf4a232bb07fe3a10cb2a6",
328
339
  "b2eb207b2773ab1995ee6e113ba6f3b64de43389e76aef4a0f06d4845ff86223",
329
340
  "65e19a5d16f486b13541048c239e828f8039bfc6e38bafd7949d9c936fe4b5b2",
330
341
  "da43debf97f0b4a1583d8202a7306aca97ac97865accf9bca8f41d75c84a1cb9",
@@ -332,7 +343,6 @@
332
343
  "5df9c9678eb68fd79ceb998ae7a52dd54dc92336ad5169e8a01acca89f76bd60",
333
344
  "a1219f6dbad9c8c185953125ef0b8dccf081aa01efb8e8acaa543c6214ac049c",
334
345
  "d0d5968e78ac25e1d3e588735de1ddbcf149cfb3165edebca5dec1ed7c7a5c46",
335
- "34222c72e4e1ead3584907f4d905444b7de820283ee7348018f110d5e6b04461",
336
346
  "49b5e3dcc1b537b49c2cf09e5b875cb16acb05c622b22798e265e64dacd8ac90"
337
347
  ]
338
348
  },
@@ -347,6 +357,7 @@
347
357
  {
348
358
  "canonical_name": "sks-pipeline-runner",
349
359
  "trusted_sha256": [
360
+ "15159b6f6edea91be29612fe3cee2047d8ec47f4f7c95a33601198a9bfec3eda",
350
361
  "6f38d3387e4ab020291afe7f74713b135543e52707f5bfbffa6b3584542f45a5",
351
362
  "7749638f1e8393f3beb1f7b0c37195dd0463abdb6fd7da5d31b3d816ee91fa37",
352
363
  "fd06dfb27be41e5ffec3e3ec8c5362289f5919cf2afa9da5ab6b97e7baa4a0ac",
@@ -358,6 +369,7 @@
358
369
  {
359
370
  "canonical_name": "sks-plan",
360
371
  "trusted_sha256": [
372
+ "81b49b026cd6761a1b63029d8d39b830e0801a7f3d2f9a8609127769173ddd4e",
361
373
  "7795867b38a5f169924125850f137c31995cf28000f74284839530a68ace156a",
362
374
  "b6f3b09230e9809acf4e13df2de6af3c75a8534e8890d6560664ebfc2e4072f8"
363
375
  ]
@@ -365,6 +377,7 @@
365
377
  {
366
378
  "canonical_name": "sks-ppt",
367
379
  "trusted_sha256": [
380
+ "a25e537ff49b5bffdc093a5f772a8d218003ca1bb81e0aa304561684a9551b31",
368
381
  "fba3f438b9f22dae0813cd12bf310539a7d2b71c8cd9322eb840514e24884eaf",
369
382
  "c9a0d90e12560dd3f04959869051370e6baf46eda6eb63f708ea1661c5c9d041",
370
383
  "1d4de05afd42ee5739c0ed925af9e0ac4785fc746e659c60d3d908d465e6386c",
@@ -375,6 +388,7 @@
375
388
  {
376
389
  "canonical_name": "sks-prompt-pipeline",
377
390
  "trusted_sha256": [
391
+ "5e423981384fc3825c74327c4ca0fe09905a0dc81a533676c7e76ebb385348fc",
378
392
  "f82a103e7962e416961add515d7b3e65df89848dec1fbb9319bd49d7f1dac982",
379
393
  "93fd938dccd65d9b4d1dd140b60e1baedc627e7fcc54f9afd95eb2e44efd1143",
380
394
  "033bb114ec1fac3f8c312f698b1861ed4c2ce6f65c06f4f1a872c4b101b74b92",
@@ -393,6 +407,7 @@
393
407
  {
394
408
  "canonical_name": "sks-reasoning-router",
395
409
  "trusted_sha256": [
410
+ "b0f458caa1c3bd7bb7241a09b80fce5700aeb99b340e84c08a9b2b66bc875ba7",
396
411
  "41e14e8d5b93d743096664869ee68c41c86e911b0bbc165bdcd10e4a45faa4b6",
397
412
  "03d68436e568b3cee2bffc6ca58819019ca406f7b648ef4704e3465c7c83c114",
398
413
  "647f730520a1c7dc89c2642f5b8502624c65a861ae41aecf1fb137db40fd0611",
@@ -422,6 +437,7 @@
422
437
  {
423
438
  "canonical_name": "sks-research",
424
439
  "trusted_sha256": [
440
+ "b7280ca8a5ccf4304d25e97522d57968d20af6ec9f03f7d55a251ebcf8666236",
425
441
  "d61163446ebc429974aad8467653ddb5948739978600e9c27bff385fc53968ba",
426
442
  "8903022e98fa470cd764f7c8d1b28d4f996d6daf146260f20548acbe1276c55a",
427
443
  "2e96f95315d99b645d4171ba4648d9f9218ec3e98dcd6d363b5de522d2e1bfe3"
@@ -259,7 +259,7 @@ dependencies = [
259
259
 
260
260
  [[package]]
261
261
  name = "sks-core"
262
- version = "10.3.4"
262
+ version = "10.3.5"
263
263
  dependencies = [
264
264
  "globset",
265
265
  "grep-matcher",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "sks-core"
3
- version = "10.3.4"
3
+ version = "10.3.5"
4
4
  edition = "2021"
5
5
 
6
6
  [dependencies]
@@ -96,7 +96,8 @@ const COMMAND_MANIFEST_LITE_BASE = [
96
96
  { name: 'bench', summary: 'Run core trust-kernel benchmark budgets', maturity: 'beta' },
97
97
  { name: 'mcp-server', summary: 'Run a stdio MCP server exposing SKS commands as tools for MCP-capable agent hosts', maturity: 'beta', skipMigrationGate: true, allowedDuringActiveRoute: true },
98
98
  { name: 'agent-bridge', summary: 'Register SKS tools or run read-only tools with native Astra async calling', maturity: 'beta', readonly: true, diagnostic: true },
99
- { name: 'decision', summary: 'Manage optional Jev decisions through OpenRouter: status, enable, disable, probe, evaluate', maturity: 'labs', skipMigrationGate: true, allowedDuringActiveRoute: true }
99
+ { name: 'decision', summary: 'Manage optional Jev decisions through OpenRouter: status, enable, disable, probe, evaluate', maturity: 'labs', skipMigrationGate: true, allowedDuringActiveRoute: true },
100
+ { name: 'imagegen', summary: 'Generate images with the active SKS image mode (Codex default or a custom OpenRouter model): status, models, enable, disable, generate', maturity: 'beta', skipMigrationGate: true, allowedDuringActiveRoute: true }
100
101
  ];
101
102
  const SAFE_COMMAND_CONTRACT_LITE = {
102
103
  risk: 'R2',
@@ -109,6 +110,7 @@ const SAFE_COMMAND_CONTRACT_LITE = {
109
110
  const COMMAND_CONTRACT_OVERRIDES_LITE = {
110
111
  align: { latency: 'long', supportsJson: true, inputProfile: 'json-only' },
111
112
  decision: { risk: 'R2', latency: 'long', supportsJson: true, remoteAllowed: false, inputProfile: 'json-only' },
113
+ imagegen: { risk: 'R2', latency: 'long', supportsJson: true, remoteAllowed: false, inputProfile: 'json-only' },
112
114
  cleanup: { risk: 'R3', latency: 'long', supportsJson: true, remoteAllowed: false, inputProfile: 'json-only' },
113
115
  autoresearch: { latency: 'long' },
114
116
  bench: { latency: 'long' },
@@ -254,11 +254,19 @@ const COMMAND_DEFINITIONS = {
254
254
  activeRoutePolicy: 'always'
255
255
  })),
256
256
  packageRequiredFiles: ['dist/commands/decision.js']
257
+ },
258
+ imagegen: {
259
+ ...skipMigrationGate(entry('beta', 'Generate images with the active SKS image mode (Codex default or a custom OpenRouter model): status, models, enable, disable, generate', 'dist/commands/imagegen.js', directCommand(() => import('../commands/imagegen.js'), 'dist/commands/imagegen.js'), {
260
+ allowedDuringActiveRoute: true,
261
+ activeRoutePolicy: 'always'
262
+ })),
263
+ packageRequiredFiles: ['dist/commands/imagegen.js']
257
264
  }
258
265
  };
259
266
  const COMMANDS_WITH_LEGACY_CONTRACT_OVERRIDES = applyCommandContractOverrides(COMMAND_DEFINITIONS, {
260
267
  align: { latency: 'long', supportsJson: true, inputProfile: 'json-only' },
261
268
  decision: { risk: 'R2', latency: 'long', supportsJson: true, remoteAllowed: false, inputProfile: 'json-only' },
269
+ imagegen: { risk: 'R2', latency: 'long', supportsJson: true, remoteAllowed: false, inputProfile: 'json-only' },
262
270
  cleanup: { risk: 'R3', latency: 'long', supportsJson: true, remoteAllowed: false, inputProfile: 'json-only' },
263
271
  autoresearch: { latency: 'long' },
264
272
  bench: { latency: 'long' },
@@ -1,4 +1,3 @@
1
- import { IMAGEGEN_MODEL } from '../core/imagegen/imagegen-model-policy.js';
2
1
  import path from 'node:path';
3
2
  import fsp from 'node:fs/promises';
4
3
  import { stdin as input, stdout as output } from 'node:process';
@@ -70,7 +69,7 @@ export async function postinstall({ bootstrap }) {
70
69
  console.log('Configure providers explicitly with `sks bridge provider configure codex-lb ...` or `sks bridge provider configure openrouter ...`.');
71
70
  const imagegenRepair = await ensureCodexImagegenDuringInstall();
72
71
  if (imagegenRepair.status === 'ready')
73
- console.log(("Image generation provider capability ready (requested model: " + IMAGEGEN_MODEL + "; output not verified)."));
72
+ console.log('Image generation ready for the active SKS image mode (output not verified).');
74
73
  else if (imagegenRepair.status === 'recovered')
75
74
  console.log('Codex App Image Gen: recovered and re-detected. Start a new Codex/Work task; restart the desktop app only if the new task still lacks $imagegen.');
76
75
  else if (imagegenRepair.status === 'blocked')
@@ -1,4 +1,3 @@
1
- import { IMAGEGEN_MODEL } from '../core/imagegen/imagegen-model-policy.js';
2
1
  import os from 'node:os';
3
2
  import path from 'node:path';
4
3
  import { projectRoot, exists, formatBytes, nowIso, readText, writeJsonAtomic } from '../core/fsx.js';
@@ -1189,7 +1188,7 @@ async function runDoctor(args = [], root, doctorFix, deps = {}) {
1189
1188
  blockers: ['codex_imagegen_current_task_tool_manifest_unverified', 'codex_imagegen_real_output_unverified'],
1190
1189
  manual_actions: [
1191
1190
  'Start a fresh Codex/Work task so $imagegen is present in its tool manifest.',
1192
- ("Invoke $imagegen with " + IMAGEGEN_MODEL + " and bind the selected raster output path to route evidence.")
1191
+ 'Run `sks imagegen generate` (it follows the active SKS image mode) and bind the raster output path to route evidence.'
1193
1192
  ],
1194
1193
  communication_test: {
1195
1194
  level: 'flag_level',
@@ -0,0 +1,154 @@
1
+ import path from 'node:path';
2
+ import { flag, readOption } from '../cli/args.js';
3
+ import { printJson } from '../cli/output.js';
4
+ import { readDecisionConfig, jevEnabled } from '../core/decisions/config.js';
5
+ import { imagegenConfigPath, imagegenSelection, readImagegenConfig, writeImagegenConfig, isOpenRouterModelId } from '../core/imagegen/imagegen-config.js';
6
+ import { generateSksImage } from '../core/imagegen/imagegen-generate.js';
7
+ import { listOpenRouterImageModels } from '../core/imagegen/openrouter-images.js';
8
+ import { decideImagegenParameters } from '../core/imagegen/imagegen-jev.js';
9
+ import { resolveOpenRouterApiKey } from '../core/providers/openrouter/openrouter-secret-store.js';
10
+ export const IMAGEGEN_STATUS_SCHEMA = 'sks.imagegen-status.v1';
11
+ const USAGE = [
12
+ 'Usage: sks imagegen status|models|enable|disable|generate [options] [--json]',
13
+ ' status Show the active image mode (Codex default or custom OpenRouter model).',
14
+ ' models [--refresh] List OpenRouter models that output images.',
15
+ ' enable --model <id> Use this OpenRouter image model through the SKS Desktop Bridge.',
16
+ ' disable Go back to Codex default image generation.',
17
+ ' generate --prompt <text> --out <file> [--reference <file>]... [--aspect <ratio>] [--quality <q>]',
18
+ ' Make an image with the active mode and write evidence next to it.'
19
+ ].join('\n');
20
+ async function statusPayload(config, env, extra = {}) {
21
+ const selection = imagegenSelection(config);
22
+ const key = await resolveOpenRouterApiKey({ env }).catch(() => ({ key: null }));
23
+ const jev = await readDecisionConfig(env).then(jevEnabled).catch(() => false);
24
+ const warnings = [];
25
+ if (config.mode === 'openrouter' && !key.key)
26
+ warnings.push('openrouter_key_missing');
27
+ return {
28
+ schema: IMAGEGEN_STATUS_SCHEMA,
29
+ ok: true,
30
+ mode: config.mode,
31
+ custom_model_enabled: config.mode === 'openrouter',
32
+ openrouter_model: config.openrouter_model,
33
+ openrouter_key_present: Boolean(key.key),
34
+ effective: { provider: selection.mode, model: selection.model, label: selection.label },
35
+ jev_enabled: jev,
36
+ blockers: [],
37
+ warnings,
38
+ config_path: imagegenConfigPath(env),
39
+ ...extra
40
+ };
41
+ }
42
+ function print(payload, json) {
43
+ if (json) {
44
+ printJson(payload);
45
+ return;
46
+ }
47
+ if (payload.schema === IMAGEGEN_STATUS_SCHEMA) {
48
+ console.log(`Image generation: ${payload.effective?.label}`);
49
+ if (payload.custom_model_enabled && !payload.openrouter_key_present)
50
+ console.log('Warning: no OpenRouter key; add it in SKS Control Center (Connections, OpenRouter) or with `sks bridge provider configure openrouter --api-key-stdin`.');
51
+ for (const warning of payload.warnings || [])
52
+ if (warning !== 'openrouter_key_missing')
53
+ console.log(`Warning: ${warning}`);
54
+ for (const blocker of payload.blockers || [])
55
+ console.log(`Blocked: ${blocker}`);
56
+ return;
57
+ }
58
+ console.log(JSON.stringify(payload, null, 2));
59
+ }
60
+ function readAll(args, name) {
61
+ const out = [];
62
+ for (let i = 0; i < args.length; i++)
63
+ if (args[i] === name && args[i + 1])
64
+ out.push(args[i + 1]);
65
+ return out;
66
+ }
67
+ export async function run(_command, args = []) {
68
+ const env = process.env;
69
+ const json = flag(args, '--json');
70
+ const action = args.find((arg) => !arg.startsWith('-')) || 'status';
71
+ if (flag(args, '--help') || flag(args, '-h')) {
72
+ if (json)
73
+ printJson({ ok: true, command: 'imagegen', usage: USAGE, mutated: false });
74
+ else
75
+ console.log(USAGE);
76
+ return;
77
+ }
78
+ if (action === 'status') {
79
+ print(await statusPayload(await readImagegenConfig(env), env), json);
80
+ return;
81
+ }
82
+ if (action === 'models') {
83
+ const list = await listOpenRouterImageModels({ env, refresh: flag(args, '--refresh') });
84
+ const config = await readImagegenConfig(env);
85
+ const payload = { ...list, models: list.models.map((model) => ({ ...model, selected: model.id === config.openrouter_model })) };
86
+ if (json)
87
+ printJson(payload);
88
+ else
89
+ for (const model of payload.models)
90
+ console.log(`${model.selected ? '*' : ' '} ${model.id} ${model.name}`);
91
+ if (!list.ok)
92
+ process.exitCode = 1;
93
+ return;
94
+ }
95
+ if (action === 'enable') {
96
+ const model = String(readOption(args, '--model', '') || '').trim();
97
+ const before = await readImagegenConfig(env);
98
+ const fail = async (blocker) => {
99
+ print({ ...(await statusPayload(before, env)), ok: false, blockers: [blocker], changed: false }, json);
100
+ process.exitCode = 1;
101
+ };
102
+ if (!model)
103
+ return fail('imagegen_model_required');
104
+ if (!isOpenRouterModelId(model))
105
+ return fail('imagegen_model_not_image_capable');
106
+ const list = await listOpenRouterImageModels({ env });
107
+ if (!list.ok)
108
+ return fail(list.blockers[0] || 'openrouter_models_unavailable');
109
+ const row = list.models.find((candidate) => candidate.id === model);
110
+ if (!row)
111
+ return fail('imagegen_model_not_image_capable');
112
+ const next = await writeImagegenConfig({ mode: 'openrouter', openrouterModel: model }, env);
113
+ const payload = await statusPayload(next, env, { changed: before.mode !== next.mode || before.openrouter_model !== next.openrouter_model });
114
+ if (row.max_references === 0)
115
+ payload.warnings.push('imagegen_model_takes_no_reference_images');
116
+ print(payload, json);
117
+ return;
118
+ }
119
+ if (action === 'disable') {
120
+ const before = await readImagegenConfig(env);
121
+ const next = await writeImagegenConfig({ mode: 'codex' }, env);
122
+ print(await statusPayload(next, env, { changed: before.mode !== 'codex' }), json);
123
+ return;
124
+ }
125
+ if (action === 'generate') {
126
+ const prompt = String(readOption(args, '--prompt', '') || '').trim();
127
+ const out = String(readOption(args, '--out', '') || '').trim();
128
+ if (!prompt || !out) {
129
+ print({ schema: 'sks.imagegen-generate.v1', ok: false, blockers: [!prompt ? 'imagegen_prompt_required' : 'imagegen_out_required'], usage: USAGE }, json);
130
+ process.exitCode = 1;
131
+ return;
132
+ }
133
+ const references = readAll(args, '--reference').map((file) => path.resolve(file));
134
+ const explicitAspect = readOption(args, '--aspect', null);
135
+ const explicitQuality = readOption(args, '--quality', null);
136
+ const jev = explicitAspect && explicitQuality
137
+ ? null
138
+ : await decideImagegenParameters({ root: process.cwd(), prompt, hasReference: references.length > 0, ask: { aspect: !explicitAspect, quality: !explicitQuality }, env }).catch(() => null);
139
+ const result = await generateSksImage({
140
+ prompt,
141
+ outPath: path.resolve(out),
142
+ references,
143
+ aspectRatio: explicitAspect || jev?.aspectRatio || null,
144
+ quality: explicitQuality || jev?.quality || null,
145
+ env
146
+ });
147
+ print({ ...result, jev }, json);
148
+ if (!result.ok)
149
+ process.exitCode = 1;
150
+ return;
151
+ }
152
+ print({ ok: false, blockers: [`imagegen_unknown_action:${action}`], usage: USAGE }, json);
153
+ process.exitCode = 1;
154
+ }