sneakoscope 10.1.4 → 10.1.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 (79) hide show
  1. package/README.md +1 -1
  2. package/config/skills-hash-ledger.v1.json +8 -0
  3. package/crates/sks-core/Cargo.lock +1 -1
  4. package/crates/sks-core/Cargo.toml +1 -1
  5. package/dist/cli/install-helpers.js +2 -1
  6. package/dist/commands/doctor.js +2 -1
  7. package/dist/config/skills-manifest.json +19 -10
  8. package/dist/core/agents/agent-effort-policy.js +3 -3
  9. package/dist/core/agents/official-subagent-helper-policy.js +2 -1
  10. package/dist/core/bench.js +1 -1
  11. package/dist/core/codex-app.js +6 -5
  12. package/dist/core/codex-lb/desktop-bridge/http-forward.js +11 -6
  13. package/dist/core/codex-lb/desktop-bridge/rejection-log.js +3 -0
  14. package/dist/core/codex-lb/desktop-bridge/responses-websocket.js +2 -2
  15. package/dist/core/codex-lb/desktop-bridge/security.js +4 -0
  16. package/dist/core/codex-lb/desktop-bridge/server.js +10 -1
  17. package/dist/core/codex-lb/desktop-bridge/types.js +12 -0
  18. package/dist/core/codex-native/core-skill-manifest.js +4 -3
  19. package/dist/core/codex-native/native-capability-repair-matrix.js +5 -4
  20. package/dist/core/commands/image-ux-review-command.js +23 -27
  21. package/dist/core/commands/ppt-command.js +4 -3
  22. package/dist/core/commands/qa-loop-command.js +8 -8
  23. package/dist/core/doctor/doctor-readiness-matrix.js +2 -1
  24. package/dist/core/doctor/imagegen-repair.js +4 -3
  25. package/dist/core/evidence/evidence-router.js +3 -3
  26. package/dist/core/evidence/evidence-schema.js +1 -1
  27. package/dist/core/feature-fixtures.js +2 -2
  28. package/dist/core/feature-registry.js +3 -2
  29. package/dist/core/hooks-runtime/hook-io.js +2 -1
  30. package/dist/core/image-ux-review/callout-extraction.js +1 -1
  31. package/dist/core/image-ux-review/imagegen-adapter.js +63 -185
  32. package/dist/core/image-ux-review/recapture.js +1 -1
  33. package/dist/core/image-ux-review.js +46 -46
  34. package/dist/core/imagegen/imagegen-auth-readiness.js +6 -13
  35. package/dist/core/imagegen/imagegen-capability.js +22 -15
  36. package/dist/core/imagegen/imagegen-model-policy.js +22 -0
  37. package/dist/core/imagegen/{gpt-image-2-request-validator.js → imagegen-request-validator.js} +13 -12
  38. package/dist/core/imagegen/require-imagegen.js +4 -2
  39. package/dist/core/init/skills.js +6 -5
  40. package/dist/core/init.js +1 -1
  41. package/dist/core/managed-assets/managed-assets-manifest.js +9 -6
  42. package/dist/core/performance-budgets.json +1 -1
  43. package/dist/core/pipeline-internals/runtime-core.js +3 -2
  44. package/dist/core/pipeline-internals/runtime-gates.js +9 -8
  45. package/dist/core/ppt-review/index.js +1 -1
  46. package/dist/core/ppt-review/ppt-patch-handoff.js +2 -1
  47. package/dist/core/ppt-review/slide-imagegen-review.js +14 -9
  48. package/dist/core/ppt-review/slide-issue-extraction.js +2 -2
  49. package/dist/core/ppt.js +25 -22
  50. package/dist/core/qa-loop/qa-contract.js +5 -5
  51. package/dist/core/qa-loop.js +55 -54
  52. package/dist/core/recallpulse.js +2 -1
  53. package/dist/core/routes/design-policy.js +2 -1
  54. package/dist/core/routes/dollar-manifest-lite.js +2 -1
  55. package/dist/core/routes/evidence.js +5 -4
  56. package/dist/core/routes/ppt-policy.js +2 -1
  57. package/dist/core/routes.js +8 -7
  58. package/dist/core/stop-gate/gate-evaluator.js +3 -3
  59. package/dist/core/subagents/agent-catalog.js +2 -1
  60. package/dist/core/subagents/model-policy.js +1 -1
  61. package/dist/core/subagents/naruto-help-contract.js +2 -1
  62. package/dist/core/subagents/official-subagent-prompt.js +6 -6
  63. package/dist/core/subagents/role-model-preferences.js +14 -6
  64. package/dist/core/triwiki-wrongness/wrongness-schema.js +7 -6
  65. package/dist/core/trust-kernel/trust-report.js +6 -6
  66. package/dist/core/version.js +1 -1
  67. package/dist/core/wiki-image/callout-parser.js +1 -1
  68. package/dist/core/wiki-image/validation.js +2 -2
  69. package/dist/scripts/codex-native-agent-role-content-check.js +1 -1
  70. package/dist/scripts/imagegen-real-smoke-check.js +4 -5
  71. package/dist/scripts/ppt-real-imagegen-smoke-check.js +1 -1
  72. package/dist/scripts/ppt-real-imagegen-wiring-check.js +2 -2
  73. package/dist/scripts/search-visibility-gate-lib.js +0 -1
  74. package/dist/scripts/ux-review-imagegen-blackbox-check.js +3 -3
  75. package/dist/scripts/ux-review-real-imagegen-smoke-check.js +1 -1
  76. package/dist/scripts/ux-review-run-wires-imagegen-check.js +2 -2
  77. package/package.json +1 -1
  78. package/schemas/codex/image-ux-issue-ledger.schema.json +1 -1
  79. package/dist/core/image-ux-review/codex-app-generated-image-discovery.js +0 -100
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.1.4**. Install the latest stable release from npm.
19
+ Current package: **SKS 10.1.6**. 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
 
@@ -111,6 +111,7 @@
111
111
  {
112
112
  "canonical_name": "sks-design-artifact-expert",
113
113
  "trusted_sha256": [
114
+ "6db9a7088e5f8d21dec9c8eed00abe665e1e89f19dcbb6d8472d77e4551cb556",
114
115
  "a09daba0a2e479a68ed81ec6fba8d70e54c8398ed86f3d1879f874b98480b97c",
115
116
  "4a28d166eaf0bc4477b566b056034f972a7034165e36d8186daa9947bf92e3cf"
116
117
  ]
@@ -118,6 +119,7 @@
118
119
  {
119
120
  "canonical_name": "sks-design-system-builder",
120
121
  "trusted_sha256": [
122
+ "47654c9f74317abbd0a5a75f89cd2d563708e8234e8887cc7ab39bf49030abaa",
121
123
  "0a41e6ace960abaaf6abf5e7b1e53fd39f414e1e00b59fa725f2db9e3eb05b58",
122
124
  "c4f0007cad5774510bdc55e2815ce0911c220afa8d5dd4efc327ba1231c8f3da"
123
125
  ]
@@ -125,6 +127,7 @@
125
127
  {
126
128
  "canonical_name": "sks-design-ui-editor",
127
129
  "trusted_sha256": [
130
+ "6c24e950a12dec52c625964069c7c21a0220a58e0f69f977d802f44fdb03a940",
128
131
  "83a806cc93a3c5342e0dccfc6a45983382d5bf74d1226c4e3288228db22b737a",
129
132
  "1b65f0028a6dcb2f7eeab0b0df411a75546bc3aefa8a76067e1818da000c2249"
130
133
  ]
@@ -243,12 +246,14 @@
243
246
  {
244
247
  "canonical_name": "sks-image-ux-review",
245
248
  "trusted_sha256": [
249
+ "54d4169dc7f362ac9fe2d090bd2612e41d30acbc3e883d6bd382929bdfb9459e",
246
250
  "9293346873b5fb25a9d93b630064a2c8ceede2bfdfa4c6ffe7fbb7f64da6595c"
247
251
  ]
248
252
  },
249
253
  {
250
254
  "canonical_name": "sks-imagegen",
251
255
  "trusted_sha256": [
256
+ "478e3d8f805eed55c3f3e6c2069142482a7dbd8fa5d9a59f03b136e0e1cb77d0",
252
257
  "a7f466ba1829a757f38432fbe8c3a672e22e91948537dafe8f8ce09561d2256e",
253
258
  "7a1f9372b03975886233a623031f41e06fd782b1e7a3409517bb428d9c6b76dd"
254
259
  ]
@@ -256,6 +261,7 @@
256
261
  {
257
262
  "canonical_name": "sks-imagegen-source-scout",
258
263
  "trusted_sha256": [
264
+ "95faf4358f1c6567ca6894bfb577629f14a23d623716be70325c0ff9a893d42e",
259
265
  "95e71d4431a4c1f6911f0f76eaa1c2b475c52fd22d35c0a6c241e21e090507ad",
260
266
  "d648b571c674ed3be862bc0e8b2110f88c2bee54292bb009df0b0b2dbd6d400b"
261
267
  ]
@@ -282,6 +288,7 @@
282
288
  {
283
289
  "canonical_name": "sks-naruto",
284
290
  "trusted_sha256": [
291
+ "b981bea4183376c6c0204941ad6c2e78782e2cdea4f8d25cc85630c609faaf95",
285
292
  "5df9c9678eb68fd79ceb998ae7a52dd54dc92336ad5169e8a01acca89f76bd60",
286
293
  "a1219f6dbad9c8c185953125ef0b8dccf081aa01efb8e8acaa543c6214ac049c",
287
294
  "d0d5968e78ac25e1d3e588735de1ddbcf149cfb3165edebca5dec1ed7c7a5c46",
@@ -316,6 +323,7 @@
316
323
  {
317
324
  "canonical_name": "sks-ppt",
318
325
  "trusted_sha256": [
326
+ "c9a0d90e12560dd3f04959869051370e6baf46eda6eb63f708ea1661c5c9d041",
319
327
  "1d4de05afd42ee5739c0ed925af9e0ac4785fc746e659c60d3d908d465e6386c",
320
328
  "02e8a0758ec6d056ce9851a5a4505b1d32e302e730be3eb169a41392a5d6b2e2",
321
329
  "329fc6ee24bb04478b18fb6ccd3691cd7cbb50e1b77ca7b6136383d00b3b0bb4"
@@ -259,7 +259,7 @@ dependencies = [
259
259
 
260
260
  [[package]]
261
261
  name = "sks-core"
262
- version = "10.1.4"
262
+ version = "10.1.6"
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.1.4"
3
+ version = "10.1.6"
4
4
  edition = "2021"
5
5
 
6
6
  [dependencies]
@@ -1,3 +1,4 @@
1
+ import { IMAGEGEN_MODEL } from '../core/imagegen/imagegen-model-policy.js';
1
2
  import path from 'node:path';
2
3
  import fsp from 'node:fs/promises';
3
4
  import { stdin as input, stdout as output } from 'node:process';
@@ -60,7 +61,7 @@ export async function postinstall({ bootstrap }) {
60
61
  console.log('Configure providers explicitly with `sks bridge provider configure codex-lb ...` or `sks bridge provider configure openrouter ...`.');
61
62
  const imagegenRepair = await ensureCodexImagegenDuringInstall();
62
63
  if (imagegenRepair.status === 'ready')
63
- console.log('Codex App Image Gen: ready ($imagegen/gpt-image-2 detected).');
64
+ console.log(("Image generation provider capability ready (requested model: " + IMAGEGEN_MODEL + "; output not verified)."));
64
65
  else if (imagegenRepair.status === 'recovered')
65
66
  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.');
66
67
  else if (imagegenRepair.status === 'blocked')
@@ -1,3 +1,4 @@
1
+ import { IMAGEGEN_MODEL } from '../core/imagegen/imagegen-model-policy.js';
1
2
  import os from 'node:os';
2
3
  import path from 'node:path';
3
4
  import { projectRoot, exists, formatBytes, nowIso, readText, writeJsonAtomic } from '../core/fsx.js';
@@ -1188,7 +1189,7 @@ async function runDoctor(args = [], root, doctorFix, deps = {}) {
1188
1189
  blockers: ['codex_imagegen_current_task_tool_manifest_unverified', 'codex_imagegen_real_output_unverified'],
1189
1190
  manual_actions: [
1190
1191
  'Start a fresh Codex/Work task so $imagegen is present in its tool manifest.',
1191
- 'Invoke $imagegen with gpt-image-2 and bind the selected raster output path to route evidence.'
1192
+ ("Invoke $imagegen with " + IMAGEGEN_MODEL + " and bind the selected raster output path to route evidence.")
1192
1193
  ],
1193
1194
  communication_test: {
1194
1195
  level: 'flag_level',
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schema": "sks.skills-manifest.v1",
3
- "package_version": "10.1.4",
3
+ "package_version": "10.1.6",
4
4
  "skills": [
5
5
  {
6
6
  "canonical_name": "sks",
@@ -138,8 +138,9 @@
138
138
  {
139
139
  "canonical_name": "sks-design-artifact-expert",
140
140
  "type": "official",
141
- "content_sha256": "a09daba0a2e479a68ed81ec6fba8d70e54c8398ed86f3d1879f874b98480b97c",
141
+ "content_sha256": "6db9a7088e5f8d21dec9c8eed00abe665e1e89f19dcbb6d8472d77e4551cb556",
142
142
  "hash_history": [
143
+ "a09daba0a2e479a68ed81ec6fba8d70e54c8398ed86f3d1879f874b98480b97c",
143
144
  "4a28d166eaf0bc4477b566b056034f972a7034165e36d8186daa9947bf92e3cf"
144
145
  ],
145
146
  "deprecated_aliases": []
@@ -147,8 +148,9 @@
147
148
  {
148
149
  "canonical_name": "sks-design-system-builder",
149
150
  "type": "official",
150
- "content_sha256": "0a41e6ace960abaaf6abf5e7b1e53fd39f414e1e00b59fa725f2db9e3eb05b58",
151
+ "content_sha256": "47654c9f74317abbd0a5a75f89cd2d563708e8234e8887cc7ab39bf49030abaa",
151
152
  "hash_history": [
153
+ "0a41e6ace960abaaf6abf5e7b1e53fd39f414e1e00b59fa725f2db9e3eb05b58",
152
154
  "c4f0007cad5774510bdc55e2815ce0911c220afa8d5dd4efc327ba1231c8f3da"
153
155
  ],
154
156
  "deprecated_aliases": []
@@ -156,8 +158,9 @@
156
158
  {
157
159
  "canonical_name": "sks-design-ui-editor",
158
160
  "type": "official",
159
- "content_sha256": "83a806cc93a3c5342e0dccfc6a45983382d5bf74d1226c4e3288228db22b737a",
161
+ "content_sha256": "6c24e950a12dec52c625964069c7c21a0220a58e0f69f977d802f44fdb03a940",
160
162
  "hash_history": [
163
+ "83a806cc93a3c5342e0dccfc6a45983382d5bf74d1226c4e3288228db22b737a",
161
164
  "1b65f0028a6dcb2f7eeab0b0df411a75546bc3aefa8a76067e1818da000c2249"
162
165
  ],
163
166
  "deprecated_aliases": []
@@ -305,15 +308,18 @@
305
308
  {
306
309
  "canonical_name": "sks-image-ux-review",
307
310
  "type": "core",
308
- "content_sha256": "9293346873b5fb25a9d93b630064a2c8ceede2bfdfa4c6ffe7fbb7f64da6595c",
309
- "hash_history": [],
311
+ "content_sha256": "54d4169dc7f362ac9fe2d090bd2612e41d30acbc3e883d6bd382929bdfb9459e",
312
+ "hash_history": [
313
+ "9293346873b5fb25a9d93b630064a2c8ceede2bfdfa4c6ffe7fbb7f64da6595c"
314
+ ],
310
315
  "deprecated_aliases": []
311
316
  },
312
317
  {
313
318
  "canonical_name": "sks-imagegen",
314
319
  "type": "official",
315
- "content_sha256": "a7f466ba1829a757f38432fbe8c3a672e22e91948537dafe8f8ce09561d2256e",
320
+ "content_sha256": "478e3d8f805eed55c3f3e6c2069142482a7dbd8fa5d9a59f03b136e0e1cb77d0",
316
321
  "hash_history": [
322
+ "a7f466ba1829a757f38432fbe8c3a672e22e91948537dafe8f8ce09561d2256e",
317
323
  "7a1f9372b03975886233a623031f41e06fd782b1e7a3409517bb428d9c6b76dd"
318
324
  ],
319
325
  "deprecated_aliases": []
@@ -321,8 +327,9 @@
321
327
  {
322
328
  "canonical_name": "sks-imagegen-source-scout",
323
329
  "type": "official",
324
- "content_sha256": "95e71d4431a4c1f6911f0f76eaa1c2b475c52fd22d35c0a6c241e21e090507ad",
330
+ "content_sha256": "95faf4358f1c6567ca6894bfb577629f14a23d623716be70325c0ff9a893d42e",
325
331
  "hash_history": [
332
+ "95e71d4431a4c1f6911f0f76eaa1c2b475c52fd22d35c0a6c241e21e090507ad",
326
333
  "d648b571c674ed3be862bc0e8b2110f88c2bee54292bb009df0b0b2dbd6d400b"
327
334
  ],
328
335
  "deprecated_aliases": []
@@ -346,8 +353,9 @@
346
353
  {
347
354
  "canonical_name": "sks-naruto",
348
355
  "type": "core",
349
- "content_sha256": "5df9c9678eb68fd79ceb998ae7a52dd54dc92336ad5169e8a01acca89f76bd60",
356
+ "content_sha256": "b981bea4183376c6c0204941ad6c2e78782e2cdea4f8d25cc85630c609faaf95",
350
357
  "hash_history": [
358
+ "5df9c9678eb68fd79ceb998ae7a52dd54dc92336ad5169e8a01acca89f76bd60",
351
359
  "a1219f6dbad9c8c185953125ef0b8dccf081aa01efb8e8acaa543c6214ac049c",
352
360
  "d0d5968e78ac25e1d3e588735de1ddbcf149cfb3165edebca5dec1ed7c7a5c46",
353
361
  "34222c72e4e1ead3584907f4d905444b7de820283ee7348018f110d5e6b04461",
@@ -388,8 +396,9 @@
388
396
  {
389
397
  "canonical_name": "sks-ppt",
390
398
  "type": "official",
391
- "content_sha256": "1d4de05afd42ee5739c0ed925af9e0ac4785fc746e659c60d3d908d465e6386c",
399
+ "content_sha256": "c9a0d90e12560dd3f04959869051370e6baf46eda6eb63f708ea1661c5c9d041",
392
400
  "hash_history": [
401
+ "1d4de05afd42ee5739c0ed925af9e0ac4785fc746e659c60d3d908d465e6386c",
393
402
  "02e8a0758ec6d056ce9851a5a4505b1d32e302e730be3eb169a41392a5d6b2e2",
394
403
  "329fc6ee24bb04478b18fb6ccd3691cd7cbb50e1b77ca7b6136383d00b3b0bb4"
395
404
  ],
@@ -43,7 +43,7 @@ export function decideOfficialSubagentModel(input = {}) {
43
43
  'requested model/effort profile unavailable blocks instead of silently falling back'
44
44
  ],
45
45
  downshift_triggers: [
46
- 'ordinary UI, logic, backend, or native implementation selects Astra High',
46
+ 'instructed UI, logic, backend, or native implementation selects Astra Low',
47
47
  'long-context, Browser/Chrome, Computer Use, image-generation, or large search selects Astra Medium',
48
48
  'tiny short-context mechanical search/typing/rename work selects Astra Low'
49
49
  ]
@@ -97,7 +97,7 @@ export function decideOfficialSubagentModel(input = {}) {
97
97
  'requested model/effort profile unavailable blocks instead of silently falling back'
98
98
  ],
99
99
  downshift_triggers: [
100
- 'ordinary UI, logic, backend, or native implementation selects Astra High',
100
+ 'instructed UI, logic, backend, or native implementation selects Astra Low',
101
101
  'long-context, Browser/Chrome, Computer Use, or image-generation execution selects Astra Medium',
102
102
  'tiny short-context mechanical work selects Astra Low'
103
103
  ]
@@ -132,7 +132,7 @@ export function buildAgentEffortPolicy(roster = {}) {
132
132
  agent_count: roster.agent_count || decisions.length,
133
133
  concurrency: roster.concurrency || decisions.length,
134
134
  decisions,
135
- rule: 'All child agents use GPT-6 Astra: Low for tiny short-context mechanical work, Medium for reads and tool execution, High for ordinary implementation, and Max for focused judgment. The parent keeps its user-selected model.'
135
+ rule: 'All child agents use GPT-6 Astra: Low for tiny short-context mechanical work and instructed implementation, Medium for reads and tool execution, and Max for focused judgment. The parent keeps its user-selected model, reasoning effort, and service tier; explicit Astra effort preferences may override role defaults.'
136
136
  };
137
137
  }
138
138
  export function reasoningProfileName(effort) {
@@ -1,3 +1,4 @@
1
+ import { IMAGEGEN_MODEL } from '../imagegen/imagegen-model-policy.js';
1
2
  import path from 'node:path';
2
3
  import { nowIso, readJson, readText, writeJsonAtomic } from '../fsx.js';
3
4
  export const OFFICIAL_SUBAGENT_HELPER_POLICY_SCHEMA = 'sks.official-subagent-helper-policy.v1';
@@ -42,7 +43,7 @@ export async function writeOfficialSubagentHelperPolicy(root, input = {}) {
42
43
  built_in_agents_allowed: builtInAgentsAllowed,
43
44
  codex_app_capabilities_allowed: codexAppCapabilitiesAllowed,
44
45
  codex_builtin_imagegen_helper_allowed: true,
45
- preferred_image_generation_surface: 'Codex App $imagegen/gpt-image-2',
46
+ preferred_image_generation_surface: ("Selected image provider: " + IMAGEGEN_MODEL + ""),
46
47
  codex_app_builtin_evidence_class: 'codex_app_builtin',
47
48
  api_fallback_evidence_class: 'api_fallback',
48
49
  provider_surface_evidence_required: true,
@@ -69,7 +69,7 @@ export const TRUST_VALIDATE_BENCH_COMMAND = 'sks trust validate bench-fixture --
69
69
  export const CORE_BENCH_WARMUP_ITERATIONS = 1;
70
70
  export const UX_REVIEW_STAGED_LATENCY_BUDGETS = Object.freeze({
71
71
  source_screenshot_ingest: 500,
72
- gpt_image_2_generation: 120_000,
72
+ imagegen_generation: 120_000,
73
73
  callout_extraction: 120_000,
74
74
  fix_task_planning: 500,
75
75
  recapture_re_review: 120_000,
@@ -1,3 +1,4 @@
1
+ import { IMAGEGEN_MODEL, CODEX_BUILTIN_IMAGEGEN_MODEL } from './imagegen/imagegen-model-policy.js';
1
2
  import path from 'node:path';
2
3
  import os from 'node:os';
3
4
  import fsp from 'node:fs/promises';
@@ -483,7 +484,7 @@ function codexNativeSksMenuStatus() {
483
484
  export function codexAppGuidance({ appInstalled, codex, mcpList, featureList, requiredFeatureFlags = {}, requiredFeatureFlagsOk = true, defaultPlugins = { ok: true, missing_enabled: [] }, productDesignPlugin = null, pluginSkillShadows = { ok: true, blocking: [] }, fastModeConfig = { ok: true, blockers: [] }, providerModelUi = null, nativeSksMenu = null, gitActions = { ok: true, blockers: [] }, imageGenerationReady, inAppBrowserReady, browserUseFeatureReady, computerUseReady, browserUseReady, browserToolReady, computerUseMcpListed, browserUseMcpListed, chromeExtension, remoteControl }) {
484
485
  const lines = [];
485
486
  if (!appInstalled) {
486
- lines.push('Install and open Codex App for first-party MCP/plugin tools. Base Codex CLI flows remain available, but Codex Computer Use and imagegen/gpt-image-2 evidence will be unavailable until Codex App is ready.');
487
+ lines.push(("Install and open Codex App for first-party MCP/plugin tools. Base Codex CLI flows remain available, but Codex Computer Use requires the App; imagegen/" + IMAGEGEN_MODEL + " evidence will be unavailable until Codex App is ready."));
487
488
  lines.push(`Docs: ${CODEX_APP_DOCS_URL}`);
488
489
  }
489
490
  if (!codex?.bin)
@@ -571,10 +572,10 @@ export function codexAppGuidance({ appInstalled, codex, mcpList, featureList, re
571
572
  lines.push('Codex Chrome Extension is ready; SKS web/browser/webapp QA and UX review should use it before any other web surface.');
572
573
  }
573
574
  if (imageGenerationReady) {
574
- lines.push('Image generation is enabled; required raster assets and generated image-review evidence must invoke $imagegen/gpt-image-2 and record real output.');
575
+ lines.push(("The built-in image tool is enabled. Current-model image work requires a provider that explicitly selects " + IMAGEGEN_MODEL + " and record real output."));
575
576
  }
576
577
  else if (appInstalled || codex?.bin) {
577
- lines.push('Codex image_generation was not visible from `codex features list`. Required imagegen/gpt-image-2 evidence must stay blocked or unverified until $imagegen is available in Codex App.');
578
+ lines.push(("Codex image_generation was not visible from `codex features list`. Required imagegen/" + IMAGEGEN_MODEL + " evidence must stay blocked or unverified until $imagegen is available in Codex App."));
578
579
  lines.push('Run: sks doctor --fix to attempt Codex CLI/App image_generation repair, then rerun the blocked visual route.');
579
580
  }
580
581
  if (computerUseReady && !computerUseMcpListed) {
@@ -588,7 +589,7 @@ export function codexAppGuidance({ appInstalled, codex, mcpList, featureList, re
588
589
  lines.push('Browser Use plugin files are installed, but `codex mcp list` does not list a browser-use MCP server. Treat Browser Use as plugin-scoped, not as SKS browser verification evidence.');
589
590
  }
590
591
  if (!lines.length)
591
- lines.push('Codex App, Codex CLI, Chrome Extension, native Computer Use, Browser tooling, and image generation checks look ready. Web UI E2E uses the Chrome Extension path; native non-web visual evidence uses Computer Use; generated image evidence still requires $imagegen/gpt-image-2 output.');
592
+ lines.push(("Codex App, Codex CLI, Chrome Extension, native Computer Use, Browser tooling, and built-in image feature checks look configured. Web UI E2E uses the Chrome Extension path; native non-web visual evidence uses Computer Use; generated image evidence still requires $imagegen/" + IMAGEGEN_MODEL + " output."));
592
593
  return lines;
593
594
  }
594
595
  export function formatCodexAppStatus(status, { includeRaw = false } = {}) {
@@ -609,7 +610,7 @@ export function formatCodexAppStatus(status, { includeRaw = false } = {}) {
609
610
  `Chrome Ext: ${status.chrome_extension?.ok ? 'ok' : `setup ${(status.chrome_extension?.blockers || []).join(', ') || 'required'}`}`,
610
611
  `Computer Use:${status.mcp.has_computer_use ? status.mcp.computer_use_source === 'plugin_cache' ? ' installed (verify @Computer in thread)' : ' ok' : ' missing'}`,
611
612
  `Browser: ${status.features?.browser_tool_ready ? `ok (${status.features.browser_tool_source})` : status.mcp.has_browser_use ? status.mcp.browser_use_source === 'plugin_cache' ? 'installed (plugin scoped)' : 'ok' : 'missing'}`,
612
- `Image Gen: ${status.features?.image_generation ? 'ok ($imagegen/gpt-image-2)' : status.features?.checked ? 'missing' : 'not checked'}`,
613
+ `Image Gen: ${status.features?.image_generation ? (`enabled (${CODEX_BUILTIN_IMAGEGEN_MODEL}; ${IMAGEGEN_MODEL} provider unverified)`) : status.features?.checked ? 'missing' : 'not checked'}`,
613
614
  `Ready: ${status.ok ? 'yes' : 'no'}`,
614
615
  '',
615
616
  ...status.guidance.map((line) => `- ${line}`)
@@ -7,7 +7,7 @@ import { buildOfficialPassthroughHeaders, buildProviderUpstreamHeaders, rewriteR
7
7
  import { createDesktopBridgeRejectionLogger } from './rejection-log.js';
8
8
  import { ensureDesktopBridgeRemoteTarget, isUnreachableUpstreamError, refreshDesktopBridgeRemoteTarget, resolveAndBindDesktopBridgeRouteContext, resolveCodexSessionIdentity, resolveDesktopBridgeTarget, safeBridgeErrorCode, singleBridgeHeader } from './security.js';
9
9
  import { desktopBridgeListenOrigin } from './state.js';
10
- import { DesktopBridgeError } from './types.js';
10
+ import { DEFAULT_DESKTOP_BRIDGE_MAX_REQUEST_BODY_BYTES, DesktopBridgeError, DesktopBridgeRequestBodyTooLargeError } from './types.js';
11
11
  const MAX_UPSTREAM_ERROR_BODY_BYTES = 1024 * 1024;
12
12
  function decodeBridgeRequestBody(body, encoding, maximum) {
13
13
  const options = { maxOutputLength: maximum };
@@ -20,7 +20,9 @@ function decodeBridgeRequestBody(body, encoding, maximum) {
20
20
  try {
21
21
  return zlib.inflateSync(body, options);
22
22
  }
23
- catch {
23
+ catch (error) {
24
+ if (error.code === 'ERR_BUFFER_TOO_LARGE')
25
+ throw error;
24
26
  return zlib.inflateRawSync(body, options);
25
27
  }
26
28
  case 'br':
@@ -38,6 +40,9 @@ function decodeBridgeRequestBody(body, encoding, maximum) {
38
40
  catch (error) {
39
41
  if (error instanceof DesktopBridgeError)
40
42
  throw error;
43
+ if (error.code === 'ERR_BUFFER_TOO_LARGE') {
44
+ throw new DesktopBridgeRequestBodyTooLargeError(maximum, 'decoded');
45
+ }
41
46
  throw new DesktopBridgeError('bridge_responses_body_invalid_json');
42
47
  }
43
48
  }
@@ -48,14 +53,14 @@ function bodyCarriesModel(rawUrl) {
48
53
  async function readBoundedBody(req, maximum) {
49
54
  const declared = Number(req.headers['content-length'] || 0);
50
55
  if (Number.isFinite(declared) && declared > maximum)
51
- throw new DesktopBridgeError('bridge_request_body_too_large');
56
+ throw new DesktopBridgeRequestBodyTooLargeError(maximum, 'encoded', declared);
52
57
  const chunks = [];
53
58
  let total = 0;
54
- for await (const raw of req) {
59
+ for await (const raw of req.iterator({ destroyOnReturn: false })) {
55
60
  const chunk = Buffer.isBuffer(raw) ? raw : Buffer.from(raw);
56
61
  total += chunk.length;
57
62
  if (total > maximum)
58
- throw new DesktopBridgeError('bridge_request_body_too_large');
63
+ throw new DesktopBridgeRequestBodyTooLargeError(maximum, 'encoded', total);
59
64
  chunks.push(chunk);
60
65
  }
61
66
  return Buffer.concat(chunks);
@@ -79,7 +84,7 @@ export async function prepareDesktopBridgeRequest(req, config) {
79
84
  let payload = null;
80
85
  let contentEncodingStripped = false;
81
86
  if (bodyCarriesModel(req.url)) {
82
- const maximum = config.maxRequestBodyBytes ?? 16 * 1024 * 1024;
87
+ const maximum = config.maxRequestBodyBytes ?? DEFAULT_DESKTOP_BRIDGE_MAX_REQUEST_BODY_BYTES;
83
88
  body = await readBoundedBody(req, maximum);
84
89
  const encoding = String(req.headers['content-encoding'] || '').trim().toLowerCase();
85
90
  let decoded = body;
@@ -78,6 +78,9 @@ export function createDesktopBridgeRejectionLogger(options = {}) {
78
78
  ...(Number.isInteger(event.status) ? { status: event.status } : {}),
79
79
  ...(providerId ? { provider_id: providerId } : {}),
80
80
  ...(publicModel ? { public_model: publicModel } : {}),
81
+ ...(Number.isSafeInteger(event.max_request_body_bytes) && event.max_request_body_bytes > 0 ? { max_request_body_bytes: event.max_request_body_bytes } : {}),
82
+ ...(Number.isSafeInteger(event.request_body_bytes) && event.request_body_bytes >= 0 ? { request_body_bytes: event.request_body_bytes } : {}),
83
+ ...(event.request_body_stage === 'encoded' || event.request_body_stage === 'decoded' ? { request_body_stage: event.request_body_stage } : {}),
81
84
  });
82
85
  };
83
86
  }
@@ -5,7 +5,7 @@ import { BRIDGE_OFFICIAL_ROUTE_ID } from '../bridge-contracts.js';
5
5
  import { buildOfficialPassthroughWebSocketHeaders, buildProviderWebSocketHeaders } from './header-policy.js';
6
6
  import { createDesktopBridgeRejectionLogger } from './rejection-log.js';
7
7
  import { assertDesktopBridgeRouteContext, ensureDesktopBridgeRemoteTarget, isUnreachableUpstreamError, refreshDesktopBridgeRemoteTarget, resolveAndBindDesktopBridgeRouteContext, resolveCodexSessionIdentity, resolveDesktopBridgeTarget, safeBridgeErrorCode } from './security.js';
8
- import { DesktopBridgeError } from './types.js';
8
+ import { DEFAULT_DESKTOP_BRIDGE_MAX_REQUEST_BODY_BYTES, DesktopBridgeError } from './types.js';
9
9
  const MAX_PENDING_MESSAGES = 256;
10
10
  const CLOSE_GRACE_MS = 1_000;
11
11
  const INITIAL_CREATE_TIMEOUT_MS = 60 * 60_000;
@@ -19,7 +19,7 @@ function bytes(data) {
19
19
  }
20
20
  export function forwardResponsesWebSocket(req, socket, head, config) {
21
21
  const upgradeIdentity = resolveCodexSessionIdentity(req.headers);
22
- const maxBytes = config.maxRequestBodyBytes ?? 16 * 1024 * 1024;
22
+ const maxBytes = config.maxRequestBodyBytes ?? DEFAULT_DESKTOP_BRIDGE_MAX_REQUEST_BODY_BYTES;
23
23
  const server = new WebSocketServer({ noServer: true, clientTracking: false, perMessageDeflate: false, maxPayload: maxBytes });
24
24
  try {
25
25
  server.handleUpgrade(req, socket, head, (client) => {
@@ -569,6 +569,10 @@ export function validateDesktopBridgeConfig(config) {
569
569
  throw new DesktopBridgeError('bridge_connect_timeout_invalid');
570
570
  if (!Number.isFinite(config.idleTimeoutMs) || config.idleTimeoutMs < 1_000 || config.idleTimeoutMs > 86_400_000)
571
571
  throw new DesktopBridgeError('bridge_idle_timeout_invalid');
572
+ if (config.maxRequestBodyBytes !== undefined
573
+ && (!Number.isSafeInteger(config.maxRequestBodyBytes) || config.maxRequestBodyBytes < 1)) {
574
+ throw new DesktopBridgeError('bridge_request_body_limit_invalid');
575
+ }
572
576
  if (config.requestTimeoutMs !== undefined
573
577
  && (!Number.isFinite(config.requestTimeoutMs) || config.requestTimeoutMs < 1_000 || config.requestTimeoutMs > 120_000)) {
574
578
  throw new DesktopBridgeError('bridge_request_timeout_invalid');
@@ -5,7 +5,7 @@ import { destroyDesktopBridgeUpstreamAgents, forwardHttp, prepareDesktopBridgeRe
5
5
  import { createDesktopBridgeRejectionLogger } from './rejection-log.js';
6
6
  import { assertAllowedOrigin, assertAllowedPath, assertLoopbackPeer, assertLoopbackListenHost, assertWebSocketUpgrade, prepareDesktopBridgeConfig, safeBridgeErrorCode, validatePreparedDesktopBridgeConfig, } from './security.js';
7
7
  import { createDesktopBridgePublicState, desktopBridgeListenOrigin, desktopBridgeStatePath, refreshDesktopBridgeState, removeDesktopBridgeStateIfOwned, writeDesktopBridgeState, } from './state.js';
8
- import { DesktopBridgeError } from './types.js';
8
+ import { DesktopBridgeError, DesktopBridgeRequestBodyTooLargeError } from './types.js';
9
9
  import { PACKAGE_VERSION } from '../../version.js';
10
10
  import { DESKTOP_BRIDGE_CLIENT_PATH_PREFIX, DESKTOP_BRIDGE_DIAGNOSTIC_HEALTH_PATH, DESKTOP_BRIDGE_DIAGNOSTIC_PATH, DESKTOP_BRIDGE_DIAGNOSTIC_PROTOCOL } from './types.js';
11
11
  import { forwardWebSocket, safeEndUpgradeSocket } from './websocket-forward.js';
@@ -84,6 +84,8 @@ function handleDiagnosticWebSocket(req, socket, head) {
84
84
  consume();
85
85
  }
86
86
  function rejectionStatus(code) {
87
+ if (code === 'bridge_request_body_too_large')
88
+ return 413;
87
89
  if (code === 'bridge_path_not_allowed')
88
90
  return 404;
89
91
  if (code === 'bridge_request_capacity_exhausted')
@@ -95,6 +97,8 @@ function rejectionStatus(code) {
95
97
  return 400;
96
98
  }
97
99
  function rejectionStatusText(status) {
100
+ if (status === 413)
101
+ return 'Payload Too Large';
98
102
  if (status === 404)
99
103
  return 'Not Found';
100
104
  if (status === 403)
@@ -114,6 +118,11 @@ function writeBridgeRejection(res, error, req) {
114
118
  method: req?.method,
115
119
  url: req?.url,
116
120
  status: rejectionStatus(rejectedCode),
121
+ ...(error instanceof DesktopBridgeRequestBodyTooLargeError ? {
122
+ max_request_body_bytes: error.maximumBytes,
123
+ request_body_bytes: error.observedBytes,
124
+ request_body_stage: error.stage,
125
+ } : {}),
117
126
  });
118
127
  if (res.headersSent) {
119
128
  res.destroy(error instanceof Error ? error : undefined);
@@ -21,3 +21,15 @@ export class DesktopBridgeError extends Error {
21
21
  this.code = code;
22
22
  }
23
23
  }
24
+ export const DEFAULT_DESKTOP_BRIDGE_MAX_REQUEST_BODY_BYTES = 128 * 1024 * 1024;
25
+ export class DesktopBridgeRequestBodyTooLargeError extends DesktopBridgeError {
26
+ maximumBytes;
27
+ stage;
28
+ observedBytes;
29
+ constructor(maximumBytes, stage, observedBytes) {
30
+ super('bridge_request_body_too_large');
31
+ this.maximumBytes = maximumBytes;
32
+ this.stage = stage;
33
+ this.observedBytes = observedBytes;
34
+ }
35
+ }
@@ -1,3 +1,4 @@
1
+ import { IMAGEGEN_MODEL } from '../imagegen/imagegen-model-policy.js';
1
2
  import { PACKAGE_VERSION, nowIso, sha256 } from '../fsx.js';
2
3
  import { coreEngineeringDirectiveReference } from '../lean-engineering-policy.js';
3
4
  import { normalizeDollarSkillName, prefixKnownSksDollarReferences, sksPrefixedDollarCommand, sksPrefixedSkillName } from '../routes/dollar-prefix.js';
@@ -14,7 +15,7 @@ const CORE_SKILL_DEFINITIONS = [
14
15
  route: '$Naruto',
15
16
  purpose: 'run a Codex official subagent workflow with official agent threads while parent integration remains owner.',
16
17
  when: 'Use when the user explicitly invokes $Naruto or the selected route requires bounded parallel delegation.',
17
- workflow: 'Run sks naruto run "<task>" [--agents N] [--max-threads N] [--json] with Codex official subagent threads only. The parent owns decomposition, per-wave capacity, later root-owned waves, integration, and final verification. Automatic targets begin at 4/6/8/16 by task size: bounded, explicit parallel, large-scale, then mass mechanical or exploration fan-out on the Astra Low/Astra Medium lanes. After decomposition both lanes may expand to the SKS-owned 256-child ceiling when independent useful slices and real host capacity remain positive; max_threads defaults to a 256-child frame budget cap, never a target. A measured lower Codex host cap or explicit provider/API budget remains authoritative, and multi-wave scheduling reuses returned capacity. Use gpt-6-astra for every child, preserving parent settings and ignoring child-model overrides. Route tiny mechanical and mass shards to Astra Low, broad search and exploration shards to Astra Medium, implementation to Astra High, and judgment to Astra Max; max_depth=1 blocks nested delegation. Wait for every planned thread before final. In an active Codex App Naruto mission, commit the strict parent evidence with sks naruto parent-summary --mission <id> --stdin, then return localized Markdown without exposing the JSON.',
18
+ workflow: 'Run sks naruto run "<task>" [--agents N] [--max-threads N] [--json] with Codex official subagent threads only. The parent owns decomposition, per-wave capacity, later root-owned waves, integration, and final verification. Automatic targets begin at 4/6/8/16 by task size: bounded, explicit parallel, large-scale, then mass mechanical or exploration fan-out on the Astra Low/Astra Medium lanes. After decomposition both lanes may expand to the SKS-owned 256-child ceiling when independent useful slices and real host capacity remain positive; max_threads defaults to a 256-child frame budget cap, never a target. A measured lower Codex host cap or explicit provider/API budget remains authoritative, and multi-wave scheduling reuses returned capacity. Use gpt-6-astra for every child, preserving parent settings and ignoring child-model overrides. Route tiny mechanical and mass shards to Astra Low, broad search and exploration shards to Astra Medium, instructed ordinary coding execution to Astra Low, and planning, analysis, review, or other judgment to Astra Max. Keep the four task-class profiles and compatibility IDs; explicit Astra effort preferences, including High, remain supported; max_depth=1 blocks nested delegation. Wait for every planned thread before final. In an active Codex App Naruto mission, commit the strict parent evidence with sks naruto parent-summary --mission <id> --stdin, then return localized Markdown without exposing the JSON.',
18
19
  safety: 'Preserve user-authored content, inherit the parent permission mode, do not spawn nested subagents, do not inject the full pack or the full TriWiki context into every child, and do not fall back to another model, process runtime, custom scheduler, or worker pool. The historical Naruto process runtime is removed; stop with explicit blocker evidence when the official path is unavailable.',
19
20
  cli: 'sks naruto run "<task>" [--agents N] [--max-threads N] [--json]; sks naruto status|subagents|proof [--mission <id>] [--json]; sks naruto parent-summary --mission <id> --stdin [--json]',
20
21
  evidence: 'subagent-plan.json, subagent-events.jsonl, subagent-parent-summary.json, subagent-evidence.json, naruto-summary.json, and naruto-gate.json.',
@@ -60,10 +61,10 @@ const CORE_SKILL_DEFINITIONS = [
60
61
  route: '$Image-UX-Review',
61
62
  purpose: 'run one screenshot-to-generated-annotation-to-UX-report pipeline without duplicate picker skills.',
62
63
  when: 'Use for $Image-UX-Review, $UX-Review, $Visual-Review, or $UI-UX-Review requests; all aliases resolve to this one canonical skill.',
63
- workflow: 'Capture or attach the real source screenshot first; web/browser/webapp capture must pass the Codex Chrome Extension readiness gate first, while Computer Use is reserved for native Mac/non-web surfaces. Send the source image as the I2I reference to the selected Codex imagegen provider with gpt-image-2 and a senior Toss UI/UX designer prompt that visibly adds numbered P0/P1/P2/P3 callouts, hierarchy, contrast, alignment, density, affordance, eye-flow arrows, and a corrected mini-comp. Then analyze the generated annotated image pixels with vision/OCR, not the source screenshot, and write the issue ledger, extraction report, and UX/UI change report with the generated image path and sha256.',
64
+ workflow: ("Capture or attach the real source screenshot first; web/browser/webapp capture must pass the Codex Chrome Extension readiness gate first, while Computer Use is reserved for native Mac/non-web surfaces. Send the source image as the I2I reference to the selected Codex imagegen provider with " + IMAGEGEN_MODEL + " and a senior Toss UI/UX designer prompt that visibly adds numbered P0/P1/P2/P3 callouts, hierarchy, contrast, alignment, density, affordance, eye-flow arrows, and a corrected mini-comp. Then analyze the generated annotated image pixels with vision/OCR, not the source screenshot, and write the issue ledger, extraction report, and UX/UI change report with the generated image path and sha256."),
64
65
  safety: 'Do not substitute text-only critique, a source-screenshot-only report, placeholders, partial image frames, mock evidence, or an unrelated API provider for the selected real imagegen path. Apply fixes only when requested and recheck changed screens.',
65
66
  cli: 'sks ux-review run --image <path> [--fix] --json; legacy $sks-ux-review, $sks-visual-review, and $sks-ui-ux-review inputs route here internally.',
66
- evidence: 'image-ux-screen-inventory.json, image-ux-gpt-image-2-request.json, image-ux-gpt-image-2-response.json, image-ux-generated-review-ledger.json, image-ux-issue-ledger.json, image-ux-callout-extraction-report.json, image-ux-iteration-report.json, and image-ux-review-gate.json.',
67
+ evidence: 'image-ux-screen-inventory.json, image-ux-imagegen-request.json, image-ux-imagegen-response.json, image-ux-generated-review-ledger.json, image-ux-issue-ledger.json, image-ux-callout-extraction-report.json, image-ux-iteration-report.json, and image-ux-review-gate.json.',
67
68
  fallback: 'Block full verification if the real source screenshot, completed generated annotated image, generated-image callout extraction, or generated-image-based UX/UI report is unavailable.'
68
69
  },
69
70
  {
@@ -1,3 +1,4 @@
1
+ import { IMAGEGEN_MODEL } from '../imagegen/imagegen-model-policy.js';
1
2
  import fs from 'node:fs/promises';
2
3
  import path from 'node:path';
3
4
  import { ensureDir, nowIso, writeJsonAtomic } from '../fsx.js';
@@ -79,16 +80,16 @@ async function stateForCapability(root, id, imageCapability, nativeFeatureMatrix
79
80
  repair_actions: verified
80
81
  ? ['postcheck-imagegen-path-contract']
81
82
  : builtInConfigured
82
- ? ['Invoke Codex App $imagegen with gpt-image-2 in a fresh task and record the selected raster output path before retrying the image route.']
83
- : ['Sign in to Codex App, enable the built-in $imagegen / gpt-image-2 surface, then verify it with a real generated raster output before retrying the image route.'],
83
+ ? [("Use the selected model-capable image provider with " + IMAGEGEN_MODEL + " in a fresh task and record the selected raster output path before retrying the image route.")]
84
+ : [("Select a provider supporting " + IMAGEGEN_MODEL + " surface, then verify it with a real generated raster output before retrying the image route.")],
84
85
  after: null,
85
86
  artifact_path: path.join(reports, 'native-capability-repair-matrix.json'),
86
87
  core_blockers: [],
87
88
  route_blockers: verified ? {} : { 'route-image': [routeBlocker] },
88
89
  manual_actions: verified ? [] : [
89
90
  builtInConfigured
90
- ? 'Generate one real raster with Codex App $imagegen / gpt-image-2 and bind its output path to the route evidence.'
91
- : 'Sign in to Codex App and enable/use the built-in $imagegen / gpt-image-2 surface before image routes.'
91
+ ? ("Generate one real raster with the selected model-capable provider: " + IMAGEGEN_MODEL + " and bind its output path to the route evidence.")
92
+ : ("Select a provider supporting " + IMAGEGEN_MODEL + " surface before image routes.")
92
93
  ],
93
94
  blockers: [],
94
95
  warnings: verified ? [] : [