sneakoscope 2.0.5 → 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 (35) hide show
  1. package/README.md +7 -4
  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 +13 -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 +19 -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 +24 -2
  14. package/dist/core/agents/agent-worker-pipeline.js +9 -1
  15. package/dist/core/agents/native-worker-backend-router.js +19 -1
  16. package/dist/core/codex-app.js +124 -2
  17. package/dist/core/commands/naruto-command.js +9 -4
  18. package/dist/core/fsx.js +1 -1
  19. package/dist/core/hooks-runtime.js +2 -233
  20. package/dist/core/init.js +8 -8
  21. package/dist/core/naruto/naruto-active-pool.js +20 -4
  22. package/dist/core/pipeline-internals/runtime-core.js +1 -1
  23. package/dist/core/ppt.js +31 -8
  24. package/dist/core/product-design-app-server.js +410 -0
  25. package/dist/core/product-design-plugin.js +139 -0
  26. package/dist/core/routes.js +8 -8
  27. package/dist/core/version.js +1 -1
  28. package/dist/scripts/naruto-active-pool-check.js +13 -1
  29. package/dist/scripts/naruto-readonly-routing-check.js +116 -0
  30. package/dist/scripts/naruto-shadow-clone-swarm-check.js +7 -0
  31. package/dist/scripts/product-design-auto-install-check.js +119 -0
  32. package/dist/scripts/product-design-plugin-routing-check.js +101 -0
  33. package/dist/scripts/release-parallel-check.js +15 -1
  34. package/dist/scripts/release-provenance-check.js +21 -0
  35. package/package.json +5 -2
@@ -0,0 +1,410 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { EMPTY_CODEX_INFO, getCodexInfo } from './codex-adapter.js';
3
+ import { PRODUCT_DESIGN_PLUGIN, normalizeProductDesignPluginEvidence } from './product-design-plugin.js';
4
+ export const PRODUCT_DESIGN_AUTO_INSTALL_ENV = 'SKS_PRODUCT_DESIGN_AUTO_INSTALL';
5
+ export function productDesignAutoInstallRequested(opts = {}) {
6
+ const env = opts.env || process.env;
7
+ return opts.autoInstallProductDesign === true
8
+ || opts.installProductDesign === true
9
+ || opts.requireProductDesign === true
10
+ || opts.designRoute === true
11
+ || env?.[PRODUCT_DESIGN_AUTO_INSTALL_ENV] === '1'
12
+ || /^true$/i.test(String(env?.[PRODUCT_DESIGN_AUTO_INSTALL_ENV] || ''));
13
+ }
14
+ export async function ensureProductDesignPluginInstalled(opts = {}) {
15
+ const autoInstallProductDesign = productDesignAutoInstallRequested(opts);
16
+ const injectedRequest = opts.request || opts.appServerRequest;
17
+ if (injectedRequest) {
18
+ return ensureProductDesignPluginInstalledWithRequest(injectedRequest, {
19
+ ...opts,
20
+ autoInstallProductDesign
21
+ });
22
+ }
23
+ const codex = opts.codex || await getCodexInfo().catch(() => EMPTY_CODEX_INFO);
24
+ if (!codex.bin) {
25
+ return productDesignAppServerUnavailable('codex_cli_missing', 'Codex CLI missing.', {
26
+ autoInstallProductDesign
27
+ });
28
+ }
29
+ const client = new CodexAppServerJsonRpcClient({
30
+ command: codex.bin,
31
+ args: opts.appServerArgs || ['app-server', '--stdio'],
32
+ env: opts.env || process.env,
33
+ timeoutMs: opts.timeoutMs || 20000,
34
+ cwd: opts.cwd || process.cwd()
35
+ });
36
+ try {
37
+ await client.initialize();
38
+ const result = await ensureProductDesignPluginInstalledWithRequest((method, params) => client.request(method, params), {
39
+ ...opts,
40
+ autoInstallProductDesign
41
+ });
42
+ return {
43
+ ...result,
44
+ app_server_command: `${codex.bin} ${(opts.appServerArgs || ['app-server', '--stdio']).join(' ')}`
45
+ };
46
+ }
47
+ catch (err) {
48
+ return productDesignAppServerUnavailable('product_design_app_server_request_failed', err?.message || String(err), {
49
+ autoInstallProductDesign,
50
+ stderr: client.stderr.trim()
51
+ });
52
+ }
53
+ finally {
54
+ await client.close();
55
+ }
56
+ }
57
+ export async function ensureProductDesignPluginInstalledWithRequest(request, opts = {}) {
58
+ const autoInstallProductDesign = productDesignAutoInstallRequested(opts);
59
+ const calls = [];
60
+ const errors = [];
61
+ const call = async (method, params) => {
62
+ calls.push({ method, params });
63
+ try {
64
+ return { ok: true, result: await request(method, params) };
65
+ }
66
+ catch (err) {
67
+ const error = err?.message || String(err);
68
+ errors.push({ method, params, error });
69
+ return { ok: false, error };
70
+ }
71
+ };
72
+ const before = await readProductDesignFromAppServer(call);
73
+ if (before.evidence.ok) {
74
+ return productDesignEnsureReport({
75
+ ok: true,
76
+ status: 'ready',
77
+ autoInstallProductDesign,
78
+ installAttempted: false,
79
+ before,
80
+ after: before,
81
+ calls,
82
+ errors,
83
+ blockers: []
84
+ });
85
+ }
86
+ if (!autoInstallProductDesign) {
87
+ return productDesignEnsureReport({
88
+ ok: false,
89
+ status: 'install_not_requested',
90
+ autoInstallProductDesign,
91
+ installAttempted: false,
92
+ before,
93
+ after: before,
94
+ calls,
95
+ errors,
96
+ blockers: uniqueStrings([
97
+ ...before.evidence.blockers,
98
+ 'product_design_auto_install_not_requested'
99
+ ])
100
+ });
101
+ }
102
+ const install = await call('plugin/install', before.install_params || PRODUCT_DESIGN_PLUGIN.app_server.install_params);
103
+ const after = await readProductDesignFromAppServer(call, before.read_params || PRODUCT_DESIGN_PLUGIN.app_server.read_params);
104
+ let installedListEvidence = null;
105
+ if (!after.evidence.ok) {
106
+ const installedList = await call('plugin/installed', {});
107
+ const summary = installedList.ok ? findProductDesignPluginSummaryFromMarketplaces(installedList.result) : null;
108
+ if (summary) {
109
+ installedListEvidence = normalizeProductDesignPluginEvidence({
110
+ plugin: {
111
+ marketplaceName: summary.marketplaceName,
112
+ summary,
113
+ skills: []
114
+ }
115
+ });
116
+ }
117
+ }
118
+ const ok = after.evidence.ok;
119
+ return productDesignEnsureReport({
120
+ ok,
121
+ status: ok ? 'installed' : 'install_unverified',
122
+ autoInstallProductDesign,
123
+ installAttempted: true,
124
+ installResponse: summarizeProductDesignInstallResponse(install.result),
125
+ installError: install.ok ? null : install.error,
126
+ before,
127
+ after,
128
+ installedListEvidence,
129
+ calls,
130
+ errors,
131
+ blockers: ok ? [] : uniqueStrings([
132
+ ...after.evidence.blockers,
133
+ ...(installedListEvidence?.blockers || []),
134
+ ...(install.ok ? ['product_design_plugin_install_unverified'] : ['product_design_plugin_install_failed'])
135
+ ])
136
+ });
137
+ }
138
+ export async function readProductDesignFromAppServer(call, preferredReadParams = PRODUCT_DESIGN_PLUGIN.app_server.read_params) {
139
+ const direct = await call('plugin/read', preferredReadParams);
140
+ if (direct.ok) {
141
+ return {
142
+ read_source: 'plugin/read',
143
+ read_params: preferredReadParams,
144
+ install_params: preferredReadParams,
145
+ evidence: normalizeProductDesignPluginEvidence(direct.result)
146
+ };
147
+ }
148
+ const list = await call('plugin/list', PRODUCT_DESIGN_PLUGIN.app_server.list_params);
149
+ const summary = list.ok ? findProductDesignPluginSummaryFromMarketplaces(list.result) : null;
150
+ const discoveredReadParams = summary
151
+ ? productDesignAppServerReadParamsFromSummary(summary)
152
+ : PRODUCT_DESIGN_PLUGIN.app_server.read_params;
153
+ if (summary) {
154
+ const discoveredRead = await call('plugin/read', discoveredReadParams);
155
+ if (discoveredRead.ok) {
156
+ return {
157
+ read_source: 'plugin/list+plugin/read',
158
+ read_params: discoveredReadParams,
159
+ install_params: discoveredReadParams,
160
+ evidence: normalizeProductDesignPluginEvidence(discoveredRead.result)
161
+ };
162
+ }
163
+ }
164
+ const evidence = summary
165
+ ? normalizeProductDesignPluginEvidence({
166
+ plugin: {
167
+ marketplaceName: summary.marketplaceName,
168
+ summary,
169
+ skills: []
170
+ }
171
+ })
172
+ : normalizeProductDesignPluginEvidence({});
173
+ return {
174
+ read_source: summary ? 'plugin/list_summary' : 'plugin/read_failed',
175
+ read_params: discoveredReadParams,
176
+ install_params: discoveredReadParams,
177
+ evidence: {
178
+ ...evidence,
179
+ blockers: uniqueStrings([
180
+ ...evidence.blockers,
181
+ 'product_design_plugin_read_failed'
182
+ ])
183
+ }
184
+ };
185
+ }
186
+ export function findProductDesignPluginSummaryFromMarketplaces(input = {}) {
187
+ const marketplaces = Array.isArray(input?.marketplaces) ? input.marketplaces : [];
188
+ for (const marketplace of marketplaces) {
189
+ const plugins = Array.isArray(marketplace?.plugins) ? marketplace.plugins : [];
190
+ for (const plugin of plugins) {
191
+ const remotePluginId = String(plugin?.remotePluginId || plugin?.remote_plugin_id || '');
192
+ const id = String(plugin?.id || '');
193
+ const name = String(plugin?.name || '');
194
+ const displayName = String(plugin?.displayName || plugin?.display_name || plugin?.interface?.displayName || '');
195
+ const matches = id === PRODUCT_DESIGN_PLUGIN.id
196
+ || name === PRODUCT_DESIGN_PLUGIN.name
197
+ || displayName === PRODUCT_DESIGN_PLUGIN.display_name
198
+ || remotePluginId === PRODUCT_DESIGN_PLUGIN.remote_plugin_id;
199
+ if (matches) {
200
+ return {
201
+ ...plugin,
202
+ displayName,
203
+ marketplaceName: plugin?.marketplaceName || marketplace?.name || PRODUCT_DESIGN_PLUGIN.marketplace,
204
+ remotePluginId
205
+ };
206
+ }
207
+ }
208
+ }
209
+ return null;
210
+ }
211
+ export function productDesignAppServerReadParamsFromSummary(summary = {}) {
212
+ return {
213
+ remoteMarketplaceName: summary.marketplaceName || PRODUCT_DESIGN_PLUGIN.marketplace,
214
+ pluginName: summary.remotePluginId || summary.remote_plugin_id || PRODUCT_DESIGN_PLUGIN.remote_plugin_id
215
+ };
216
+ }
217
+ function productDesignEnsureReport(input) {
218
+ const remoteEvidence = input.after?.evidence || input.before?.evidence || normalizeProductDesignPluginEvidence({});
219
+ return {
220
+ schema: 'sks.product-design-app-server-ensure.v1',
221
+ ok: input.ok,
222
+ checked: true,
223
+ status: input.status,
224
+ auto_install_requested: input.autoInstallProductDesign === true,
225
+ install_attempted: input.installAttempted === true,
226
+ install_response: input.installResponse || null,
227
+ install_error: input.installError || null,
228
+ before_evidence: input.before?.evidence || null,
229
+ after_evidence: input.after?.evidence || null,
230
+ installed_list_evidence: input.installedListEvidence || null,
231
+ remote_evidence: remoteEvidence,
232
+ read_source: input.after?.read_source || input.before?.read_source || null,
233
+ read_params: input.after?.read_params || input.before?.read_params || PRODUCT_DESIGN_PLUGIN.app_server.read_params,
234
+ install_params: input.before?.install_params || PRODUCT_DESIGN_PLUGIN.app_server.install_params,
235
+ calls: input.calls || [],
236
+ errors: input.errors || [],
237
+ blockers: input.blockers || []
238
+ };
239
+ }
240
+ function productDesignAppServerUnavailable(reason, error, extra = {}) {
241
+ const evidence = normalizeProductDesignPluginEvidence({});
242
+ return {
243
+ schema: 'sks.product-design-app-server-ensure.v1',
244
+ ok: false,
245
+ checked: false,
246
+ status: 'app_server_unavailable',
247
+ auto_install_requested: extra.autoInstallProductDesign === true,
248
+ install_attempted: false,
249
+ install_response: null,
250
+ install_error: error,
251
+ before_evidence: evidence,
252
+ after_evidence: evidence,
253
+ installed_list_evidence: null,
254
+ remote_evidence: evidence,
255
+ read_source: null,
256
+ read_params: PRODUCT_DESIGN_PLUGIN.app_server.read_params,
257
+ install_params: PRODUCT_DESIGN_PLUGIN.app_server.install_params,
258
+ calls: [],
259
+ errors: [{ reason, error }],
260
+ stderr: extra.stderr || '',
261
+ blockers: uniqueStrings([
262
+ ...evidence.blockers,
263
+ reason
264
+ ])
265
+ };
266
+ }
267
+ function summarizeProductDesignInstallResponse(result = {}) {
268
+ if (!result)
269
+ return null;
270
+ return {
271
+ auth_policy: result.authPolicy || result.auth_policy || null,
272
+ apps_needing_auth: Array.isArray(result.appsNeedingAuth)
273
+ ? result.appsNeedingAuth.map((app) => ({
274
+ id: app?.id || null,
275
+ name: app?.name || app?.displayName || app?.display_name || null
276
+ }))
277
+ : []
278
+ };
279
+ }
280
+ function uniqueStrings(values = []) {
281
+ return Array.from(new Set(values.filter(Boolean).map((value) => String(value))));
282
+ }
283
+ class CodexAppServerJsonRpcClient {
284
+ command;
285
+ args;
286
+ env;
287
+ cwd;
288
+ timeoutMs;
289
+ child;
290
+ nextId;
291
+ pending;
292
+ stdoutBuffer;
293
+ stderr;
294
+ constructor(config = {}) {
295
+ this.command = config.command;
296
+ this.args = config.args || ['app-server', '--stdio'];
297
+ this.env = config.env || process.env;
298
+ this.cwd = config.cwd || process.cwd();
299
+ this.timeoutMs = Number(config.timeoutMs || 20000);
300
+ this.child = null;
301
+ this.nextId = 1;
302
+ this.pending = new Map();
303
+ this.stdoutBuffer = '';
304
+ this.stderr = '';
305
+ }
306
+ async initialize() {
307
+ this.start();
308
+ const result = await this.request('initialize', {
309
+ clientInfo: {
310
+ name: 'sneakoscope-product-design',
311
+ title: 'Sneakoscope Product Design Installer',
312
+ version: '1.0.0'
313
+ },
314
+ capabilities: {
315
+ experimentalApi: true,
316
+ requestAttestation: false,
317
+ optOutNotificationMethods: []
318
+ }
319
+ });
320
+ this.notify('notifications/initialized', {});
321
+ return result;
322
+ }
323
+ start() {
324
+ if (this.child)
325
+ return;
326
+ this.child = spawn(this.command, this.args, {
327
+ stdio: ['pipe', 'pipe', 'pipe'],
328
+ shell: false,
329
+ env: this.env,
330
+ cwd: this.cwd
331
+ });
332
+ this.child.stdout?.on('data', (chunk) => this.handleStdout(chunk));
333
+ this.child.stderr?.on('data', (chunk) => {
334
+ this.stderr += chunk.toString('utf8');
335
+ if (this.stderr.length > 64 * 1024)
336
+ this.stderr = this.stderr.slice(-64 * 1024);
337
+ });
338
+ this.child.on('error', (err) => this.rejectAll(err));
339
+ this.child.on('close', (code) => {
340
+ this.rejectAll(new Error(`Codex app-server exited before response (code ${code ?? 'signal'}). ${this.stderr.trim()}`.trim()));
341
+ });
342
+ }
343
+ request(method, params) {
344
+ this.start();
345
+ const id = this.nextId++;
346
+ const message = { jsonrpc: '2.0', id, method, params };
347
+ return new Promise((resolve, reject) => {
348
+ const timer = setTimeout(() => {
349
+ this.pending.delete(id);
350
+ reject(new Error(`Codex app-server request timed out: ${method}. ${this.stderr.trim()}`.trim()));
351
+ }, this.timeoutMs);
352
+ timer.unref?.();
353
+ this.pending.set(id, { resolve, reject, timer });
354
+ this.child?.stdin?.write(`${JSON.stringify(message)}\n`);
355
+ });
356
+ }
357
+ notify(method, params) {
358
+ this.start();
359
+ this.child?.stdin?.write(`${JSON.stringify({ jsonrpc: '2.0', method, params })}\n`);
360
+ }
361
+ handleStdout(chunk) {
362
+ this.stdoutBuffer += chunk.toString('utf8');
363
+ const lines = this.stdoutBuffer.split(/\r?\n/);
364
+ this.stdoutBuffer = lines.pop() || '';
365
+ for (const line of lines) {
366
+ if (!line.trim())
367
+ continue;
368
+ let message;
369
+ try {
370
+ message = JSON.parse(line);
371
+ }
372
+ catch {
373
+ continue;
374
+ }
375
+ if (message.id === undefined || !this.pending.has(message.id))
376
+ continue;
377
+ const pending = this.pending.get(message.id);
378
+ if (!pending)
379
+ continue;
380
+ this.pending.delete(message.id);
381
+ clearTimeout(pending.timer);
382
+ if (message.error)
383
+ pending.reject(new Error(message.error.message || JSON.stringify(message.error)));
384
+ else
385
+ pending.resolve(message.result);
386
+ }
387
+ }
388
+ rejectAll(err) {
389
+ for (const [id, pending] of this.pending.entries()) {
390
+ clearTimeout(pending.timer);
391
+ pending.reject(err);
392
+ this.pending.delete(id);
393
+ }
394
+ }
395
+ async close() {
396
+ if (!this.child)
397
+ return;
398
+ const child = this.child;
399
+ this.child = null;
400
+ try {
401
+ child.stdin?.end();
402
+ }
403
+ catch { }
404
+ try {
405
+ child.kill('SIGTERM');
406
+ }
407
+ catch { }
408
+ }
409
+ }
410
+ //# sourceMappingURL=product-design-app-server.js.map
@@ -0,0 +1,139 @@
1
+ export const PRODUCT_DESIGN_REQUIRED_SKILLS = Object.freeze([
2
+ 'audit',
3
+ 'design-qa',
4
+ 'get-context',
5
+ 'ideate',
6
+ 'image-to-code',
7
+ 'prototype',
8
+ 'research',
9
+ 'share',
10
+ 'url-to-code',
11
+ 'user-context'
12
+ ]);
13
+ export const PRODUCT_DESIGN_LEGACY_DESIGN_FALLBACK_SKILLS = Object.freeze([
14
+ 'design-artifact-expert',
15
+ 'design-ui-editor',
16
+ 'design-system-builder',
17
+ 'getdesign-reference'
18
+ ]);
19
+ export const PRODUCT_DESIGN_PLUGIN = Object.freeze({
20
+ id: 'product-design@openai-curated-remote',
21
+ name: 'product-design',
22
+ marketplace: 'openai-curated-remote',
23
+ marketplace_kind: 'vertical',
24
+ remote_plugin_id: 'Plugin_fa77aec24fc08191bc6e57f377126d76',
25
+ display_name: 'Product Design',
26
+ app_server: {
27
+ read_params: {
28
+ remoteMarketplaceName: 'openai-curated-remote',
29
+ pluginName: 'Plugin_fa77aec24fc08191bc6e57f377126d76'
30
+ },
31
+ install_params: {
32
+ remoteMarketplaceName: 'openai-curated-remote',
33
+ pluginName: 'Plugin_fa77aec24fc08191bc6e57f377126d76'
34
+ },
35
+ name_lookup_params: {
36
+ remoteMarketplaceName: 'openai-curated-remote',
37
+ pluginName: 'product-design'
38
+ },
39
+ list_params: {
40
+ marketplaceKinds: ['vertical']
41
+ }
42
+ }
43
+ });
44
+ export const PRODUCT_DESIGN_PIPELINE_STAGES = Object.freeze([
45
+ {
46
+ stage: 'context_intake',
47
+ skills: ['get-context', 'user-context'],
48
+ routes: ['Team', 'PPT', 'ImageUXReview'],
49
+ purpose: 'capture product/user/design context before local design.md fallback is hydrated'
50
+ },
51
+ {
52
+ stage: 'research_and_ideation',
53
+ skills: ['research', 'ideate'],
54
+ routes: ['Team', 'PPT'],
55
+ purpose: 'ground competitive, audience, and concept exploration before visual decisions'
56
+ },
57
+ {
58
+ stage: 'artifact_generation',
59
+ skills: ['prototype', 'image-to-code', 'url-to-code'],
60
+ routes: ['Team', 'PPT'],
61
+ purpose: 'turn sealed context, screenshots, images, or URLs into prototype/source direction'
62
+ },
63
+ {
64
+ stage: 'design_review',
65
+ skills: ['audit', 'design-qa'],
66
+ routes: ['Team', 'PPT', 'ImageUXReview', 'QALoop'],
67
+ purpose: 'audit hierarchy, accessibility, responsiveness, polish, and route-specific UX risk'
68
+ },
69
+ {
70
+ stage: 'delivery',
71
+ skills: ['share'],
72
+ routes: ['PPT', 'Team'],
73
+ purpose: 'package or hand off design artifacts when the Codex App plugin exposes sharing'
74
+ }
75
+ ]);
76
+ export function productDesignPluginPolicyText() {
77
+ const stages = PRODUCT_DESIGN_PIPELINE_STAGES
78
+ .map((entry) => `${entry.stage}=${entry.skills.join('+')}`)
79
+ .join('; ');
80
+ return `Product Design plugin policy: design-related routes must prefer the Codex App Product Design plugin (${PRODUCT_DESIGN_PLUGIN.id}) from the remote vertical marketplace ${PRODUCT_DESIGN_PLUGIN.marketplace}. Discovery must not rely only on \`codex plugin list\`, because vertical marketplace plugins can be omitted from the local/default catalog; when Product Design is not ready, first run the app-server Product Design ensure path: plugin/read with remote plugin id params ${JSON.stringify(PRODUCT_DESIGN_PLUGIN.app_server.read_params)}, plugin/list with ${JSON.stringify(PRODUCT_DESIGN_PLUGIN.app_server.list_params)} if the id must be rediscovered, and plugin/install with ${JSON.stringify(PRODUCT_DESIGN_PLUGIN.app_server.install_params)} before falling back to legacy design.md skills. Expected ready evidence is installed=true, enabled=true, displayName/name Product Design, remotePluginId ${PRODUCT_DESIGN_PLUGIN.remote_plugin_id}, and skills ${PRODUCT_DESIGN_REQUIRED_SKILLS.join(', ')}. Pipeline mapping: ${stages}. Legacy local design helpers (${PRODUCT_DESIGN_LEGACY_DESIGN_FALLBACK_SKILLS.join(', ')}) are compatibility fallback only when Product Design auto-install/ensure is unavailable or still fails, or when the route explicitly needs an existing project-local design.md; do not auto-create a heavy design.md as the first design step when Product Design is ready.`;
81
+ }
82
+ export function normalizeProductDesignPluginEvidence(input = {}) {
83
+ const detail = input?.plugin || input?.data?.plugin || input;
84
+ const summary = detail?.summary || detail;
85
+ const skills = Array.isArray(detail?.skills)
86
+ ? detail.skills.map((skill) => String(skill?.name || skill || '')).filter(Boolean)
87
+ : [];
88
+ const id = String(summary?.id || detail?.id || '');
89
+ const name = String(summary?.name || detail?.name || '');
90
+ const displayName = String(summary?.displayName || detail?.displayName || summary?.display_name || detail?.display_name || name || '');
91
+ const marketplaceName = String(detail?.marketplaceName || input?.marketplaceName || summary?.marketplaceName || '');
92
+ const remotePluginId = String(summary?.remotePluginId || detail?.remotePluginId || summary?.remote_plugin_id || detail?.remote_plugin_id || '');
93
+ const installed = summary?.installed === true || detail?.installed === true;
94
+ const enabled = summary?.enabled === true || detail?.enabled === true;
95
+ const missingSkills = PRODUCT_DESIGN_REQUIRED_SKILLS.filter((skill) => !skills.includes(skill));
96
+ const identityOk = id === PRODUCT_DESIGN_PLUGIN.id
97
+ || name === PRODUCT_DESIGN_PLUGIN.name
98
+ || displayName === PRODUCT_DESIGN_PLUGIN.display_name
99
+ || remotePluginId === PRODUCT_DESIGN_PLUGIN.remote_plugin_id;
100
+ const marketplaceOk = !marketplaceName || marketplaceName === PRODUCT_DESIGN_PLUGIN.marketplace;
101
+ const ok = Boolean(installed && enabled && identityOk && marketplaceOk && missingSkills.length === 0);
102
+ return {
103
+ schema: 'sks.product-design-plugin-evidence.v1',
104
+ ok,
105
+ id,
106
+ name,
107
+ display_name: displayName,
108
+ marketplace_name: marketplaceName,
109
+ remote_plugin_id: remotePluginId,
110
+ installed,
111
+ enabled,
112
+ skills,
113
+ missing_skills: missingSkills,
114
+ expected: PRODUCT_DESIGN_PLUGIN,
115
+ blockers: ok ? [] : [
116
+ ...(!installed ? ['product_design_not_installed'] : []),
117
+ ...(!enabled ? ['product_design_not_enabled'] : []),
118
+ ...(!identityOk ? ['product_design_identity_unverified'] : []),
119
+ ...(!marketplaceOk ? ['product_design_wrong_marketplace'] : []),
120
+ ...(missingSkills.length ? ['product_design_skills_missing'] : [])
121
+ ]
122
+ };
123
+ }
124
+ export function productDesignPluginVisibilityFromCodexPluginList(input = {}) {
125
+ const text = JSON.stringify(input || {});
126
+ const listed = text.includes(PRODUCT_DESIGN_PLUGIN.id)
127
+ || text.includes(PRODUCT_DESIGN_PLUGIN.name)
128
+ || text.includes(PRODUCT_DESIGN_PLUGIN.remote_plugin_id);
129
+ return {
130
+ schema: 'sks.product-design-plugin-list-visibility.v1',
131
+ listed,
132
+ detector: 'codex plugin list --json',
133
+ requires_remote_vertical_lookup: !listed,
134
+ remote_marketplace: PRODUCT_DESIGN_PLUGIN.marketplace,
135
+ app_server_read_params: PRODUCT_DESIGN_PLUGIN.app_server.read_params,
136
+ app_server_list_params: PRODUCT_DESIGN_PLUGIN.app_server.list_params
137
+ };
138
+ }
139
+ //# sourceMappingURL=product-design-plugin.js.map
@@ -1,3 +1,5 @@
1
+ import { PRODUCT_DESIGN_LEGACY_DESIGN_FALLBACK_SKILLS, PRODUCT_DESIGN_PLUGIN, PRODUCT_DESIGN_REQUIRED_SKILLS, productDesignPluginPolicyText } from './product-design-plugin.js';
2
+ export { productDesignPluginPolicyText };
1
3
  const REFLECTION_SKILL_NAME = 'reflection';
2
4
  export const SOLUTION_SCOUT_SKILL_NAME = 'solution-scout';
3
5
  export const SOLUTION_SCOUT_STAGE_ID = 'solution_scout';
@@ -119,7 +121,7 @@ export const DESIGN_SYSTEM_SSOT = {
119
121
  id: 'design-system-ssot',
120
122
  authority_file: 'design.md',
121
123
  builder_prompt: 'docs/Design-Sys-Prompt.md',
122
- rule: 'design.md is the single design decision authority. When it is missing, synthesize it from the builder prompt plus approved source inputs; external references must be fused into design.md or route artifacts and must not become parallel design authorities.'
124
+ rule: `Product Design plugin (${PRODUCT_DESIGN_PLUGIN.id}) is the primary design authority when available. design.md is a project-local cache/compatibility authority only when already present or when Product Design is unavailable; if fallback is needed, synthesize it from the builder prompt plus approved source inputs and fuse external references into design.md or route artifacts instead of keeping parallel authorities.`
123
125
  };
124
126
  export const AWESOME_DESIGN_MD_REFERENCE = {
125
127
  id: 'awesome-design-md',
@@ -135,6 +137,7 @@ export const PPT_PIPELINE_SKILL_ALLOWLIST = Object.freeze([
135
137
  REFLECTION_SKILL_NAME,
136
138
  'honest-mode'
137
139
  ]);
140
+ export const PRODUCT_DESIGN_PLUGIN_TOOL_ALLOWLIST = PRODUCT_DESIGN_REQUIRED_SKILLS;
138
141
  export const PPT_CONDITIONAL_SKILL_ALLOWLIST = Object.freeze([]);
139
142
  export const PPT_PIPELINE_MCP_ALLOWLIST = Object.freeze([
140
143
  {
@@ -146,13 +149,13 @@ export function pptPipelineAllowlistPolicyText() {
146
149
  const conditionalSkills = PPT_CONDITIONAL_SKILL_ALLOWLIST.length
147
150
  ? PPT_CONDITIONAL_SKILL_ALLOWLIST.map((entry) => `${entry.skill}=${entry.condition}`).join('; ')
148
151
  : 'none';
149
- return `PPT pipeline allowlist: during $PPT design/render work, ignore installed skills and MCPs that are not explicitly part of the $PPT pipeline. The purpose is to prevent AI-like generic presentation design: decorative gradients, nested cards, vague SaaS visuals, and style choices not grounded in the audience, source material, getdesign reference, or the project design SSOT. Required skills are ${PPT_PIPELINE_SKILL_ALLOWLIST.join(', ')}. The imagegen skill is required for $PPT so Codex App can invoke official built-in $imagegen/gpt-image-2 for every generated raster asset or generated visual-review image; do not route PPT imagery through direct API fallback. Do not use generic design skills such as design-artifact-expert, design-ui-editor, or design-system-builder for $PPT just because they are installed. $PPT design must use getdesign-reference plus the built-in PPT design implementation pipeline: ${DESIGN_SYSTEM_SSOT.authority_file} when present, ${DESIGN_SYSTEM_SSOT.builder_prompt} as the builder prompt when missing, and route-local ppt-style-tokens.json as the fused design projection. Conditional skills/MCPs are allowed only when their condition is sealed in the contract: ${conditionalSkills}; ${PPT_PIPELINE_MCP_ALLOWLIST.map((entry) => `${entry.mcp}=${entry.condition}`).join('; ')}. Fact, image, and review evidence are first-class artifacts: gather user-provided context and required web/Context7 evidence into ppt-fact-ledger.json, block unsupported critical claims, plan required image resources through ppt-image-asset-ledger.json, then run a bounded review loop recorded in ppt-review-policy.json, ppt-review-ledger.json, and ppt-iteration-report.json. Required raster asset or generated visual-review evidence must come from Codex App $imagegen/gpt-image-2; direct API fallback, placeholder files, and prose-only substitutes do not satisfy the route gate. The review loop caps full-deck passes at 2, slide retries at 2, requires P0/P1 issue count to be zero, targets score >= 0.88, and stops when improvement delta is below 0.03 or evidence is missing. For Codex App visual critique, invoke $imagegen/gpt-image-2 (${CODEX_APP_IMAGE_GENERATION_DOC_URL}) when required; never simulate missing gpt-image-2 output. If required image-review evidence is unavailable, record the blocker instead of passing the gate. ${CODEX_IMAGEGEN_REQUIRED_POLICY}`;
152
+ return `PPT pipeline allowlist: during $PPT design/render work, ignore installed skills and MCPs that are not explicitly part of the $PPT pipeline. The purpose is to prevent AI-like generic presentation design: decorative gradients, nested cards, vague SaaS visuals, and style choices not grounded in the audience, source material, Product Design plugin evidence, getdesign fallback reference, or the project design cache. Required SKS skills are ${PPT_PIPELINE_SKILL_ALLOWLIST.join(', ')}. Product Design plugin tools are allowed and preferred for design work: ${PRODUCT_DESIGN_PLUGIN_TOOL_ALLOWLIST.join(', ')}. Use ${PRODUCT_DESIGN_PLUGIN.id} first for get-context/user-context intake, research/ideate exploration, prototype/image-to-code/url-to-code artifact direction, audit/design-qa review, and share handoff when available. The imagegen skill is required for $PPT so Codex App can invoke official built-in $imagegen/gpt-image-2 for every generated raster asset or generated visual-review image; do not route PPT imagery through direct API fallback. Do not use generic design skills such as ${PRODUCT_DESIGN_LEGACY_DESIGN_FALLBACK_SKILLS.join(', ')} for $PPT just because they are installed. $PPT design must use Product Design plugin first; if unavailable, use getdesign-reference plus the built-in PPT design implementation pipeline: existing ${DESIGN_SYSTEM_SSOT.authority_file} when present, ${DESIGN_SYSTEM_SSOT.builder_prompt} as fallback builder prompt when missing, and route-local ppt-style-tokens.json as the fused design projection. Conditional skills/MCPs are allowed only when their condition is sealed in the contract: ${conditionalSkills}; ${PPT_PIPELINE_MCP_ALLOWLIST.map((entry) => `${entry.mcp}=${entry.condition}`).join('; ')}. Fact, image, and review evidence are first-class artifacts: gather user-provided context and required web/Context7 evidence into ppt-fact-ledger.json, block unsupported critical claims, plan required image resources through ppt-image-asset-ledger.json, then run a bounded review loop recorded in ppt-review-policy.json, ppt-review-ledger.json, and ppt-iteration-report.json. Required raster asset or generated visual-review evidence must come from Codex App $imagegen/gpt-image-2; direct API fallback, placeholder files, and prose-only substitutes do not satisfy the route gate. The review loop caps full-deck passes at 2, slide retries at 2, requires P0/P1 issue count to be zero, targets score >= 0.88, and stops when improvement delta is below 0.03 or evidence is missing. For Codex App visual critique, invoke $imagegen/gpt-image-2 (${CODEX_APP_IMAGE_GENERATION_DOC_URL}) when required; never simulate missing gpt-image-2 output. If required image-review evidence is unavailable, record the blocker instead of passing the gate. ${productDesignPluginPolicyText()} ${CODEX_IMAGEGEN_REQUIRED_POLICY}`;
150
153
  }
151
154
  export function getdesignReferencePolicyText() {
152
- return `Design SSOT policy: ${DESIGN_SYSTEM_SSOT.authority_file} is the single design decision authority. If it is missing, create or update it through ${DESIGN_SYSTEM_SSOT.builder_prompt}; getdesign.md (${GETDESIGN_REFERENCE.url}), its official docs, and curated DESIGN.md examples at ${AWESOME_DESIGN_MD_REFERENCE.url} are source inputs to fuse into that SSOT or into route-local style tokens, not parallel authorities. Prefer the official Codex skill when available (${GETDESIGN_REFERENCE.codex_skill_install}); otherwise use the generated getdesign-reference skill plus official Web/API/CLI/SDK docs and curated DESIGN.md examples as inputs. Do not claim an official getdesign MCP server is configured unless a current official MCP surface is actually available.`;
155
+ return `Design authority policy: ${PRODUCT_DESIGN_PLUGIN.id} is the first design surface for Codex App design routes. ${DESIGN_SYSTEM_SSOT.authority_file} is a project-local design cache/compatibility authority when already present or when Product Design is unavailable. If fallback creation is needed, create or update it through ${DESIGN_SYSTEM_SSOT.builder_prompt}; getdesign.md (${GETDESIGN_REFERENCE.url}), its official docs, and curated DESIGN.md examples at ${AWESOME_DESIGN_MD_REFERENCE.url} are source inputs to fuse into that fallback SSOT or into route-local style tokens, not parallel authorities. Prefer Product Design plugin tools for design context, ideation, prototype, audit, and QA; use the generated getdesign-reference skill only as fallback/source grounding. Do not claim an official getdesign MCP server is configured unless a current official MCP surface is actually available. ${productDesignPluginPolicyText()}`;
153
156
  }
154
157
  export function imageUxReviewPipelinePolicyText() {
155
- return `Image UX review pipeline: the core mechanism is not text-only screenshot critique. Capture or receive source UI screenshots; web/browser/webapp capture must pass the Codex Chrome Extension readiness gate first, while Computer Use is only for native Mac/non-web app surfaces. Then use Codex App imagegen/$imagegen with gpt-image-2 (${CODEX_APP_IMAGE_GENERATION_DOC_URL}) to create new annotated review images from those screenshots as reference inputs. The generated review image must visibly mark numbered callouts, P0/P1/P2/P3 labels, eye-flow, hierarchy, contrast, alignment, density, affordance problems, and a small corrected mini-comp or before/after strip when useful. Then analyze that generated review image with vision/OCR and convert the visible callouts into image-ux-issue-ledger.json rows. Missing generated review images block full Image UX verification, but the route may close as verified_partial/reference-only when source screenshots plus hashes, docs evidence, source Image Voxel anchors, and Honest Mode evidence exist and the gate records that no annotated image, callout extraction, or full UX review evidence exists. Never pass this route from a direct API fallback, hand-written text-only substitute, placeholder asset, or fabricated ledger. ${CODEX_WEB_VERIFICATION_POLICY} ${CODEX_IMAGEGEN_REQUIRED_POLICY}`;
158
+ return `Image UX review pipeline: the core mechanism is not text-only screenshot critique. Capture or receive source UI screenshots; web/browser/webapp capture must pass the Codex Chrome Extension readiness gate first, while Computer Use is only for native Mac/non-web app surfaces. Use Product Design plugin audit/design-qa when available to structure UX issue framing, but still require the imagegen visual evidence route. Then use Codex App imagegen/$imagegen with gpt-image-2 (${CODEX_APP_IMAGE_GENERATION_DOC_URL}) to create new annotated review images from those screenshots as reference inputs. The generated review image must visibly mark numbered callouts, P0/P1/P2/P3 labels, eye-flow, hierarchy, contrast, alignment, density, affordance problems, and a small corrected mini-comp or before/after strip when useful. Then analyze that generated review image with vision/OCR and convert the visible callouts into image-ux-issue-ledger.json rows. Missing generated review images block full Image UX verification, but the route may close as verified_partial/reference-only when source screenshots plus hashes, docs evidence, source Image Voxel anchors, and Honest Mode evidence exist and the gate records that no annotated image, callout extraction, or full UX review evidence exists. Never pass this route from a direct API fallback, hand-written text-only substitute, placeholder asset, or fabricated ledger. ${productDesignPluginPolicyText()} ${CODEX_WEB_VERIFICATION_POLICY} ${CODEX_IMAGEGEN_REQUIRED_POLICY}`;
156
159
  }
157
160
  export const RECOMMENDED_SKILLS = [
158
161
  'reasoning-router',
@@ -162,9 +165,6 @@ export const RECOMMENDED_SKILLS = [
162
165
  'seo-geo-optimizer',
163
166
  'autoresearch-loop',
164
167
  'performance-evaluator',
165
- 'design-artifact-expert',
166
- 'design-system-builder',
167
- 'design-ui-editor',
168
168
  'getdesign-reference',
169
169
  'imagegen',
170
170
  'imagegen-source-scout',
@@ -626,7 +626,7 @@ export const COMMAND_CATALOG = [
626
626
  { name: 'update', usage: 'sks update check|now [--version <version>] [--json] [--dry-run]', description: 'Check for SKS updates or install the requested package version through npm global mode.' },
627
627
  { name: 'deps', usage: 'sks deps check [--json] [--yes]', description: 'Check Node/npm, Codex CLI, and Zellij readiness; pass --yes to repair missing Codex CLI/Zellij tooling when supported.' },
628
628
  { name: 'codex', usage: 'sks codex compatibility|version|doctor|schema [--json]', description: 'Check Codex CLI rust-v0.136.0 compatibility, installed version, 0.136 capabilities, inherited 0.135/0.134/0.133 behavior, and vendored hook schema snapshot freshness.' },
629
- { name: 'codex-app', usage: 'sks codex-app [check|chrome-extension|pat status|remote-control]', description: 'Check Codex App install, Codex Chrome Extension web verification readiness, PAT-safe status, first-party MCP/plugin readiness, and Codex CLI 0.130.0+ remote-control availability.' },
629
+ { name: 'codex-app', usage: 'sks codex-app [check|product-design|product-design --check-only|ensure-product-design|chrome-extension|pat status|remote-control]', description: 'Check Codex App install, Product Design plugin auto-install readiness, Codex Chrome Extension web verification readiness, PAT-safe status, first-party MCP/plugin readiness, and Codex CLI 0.130.0+ remote-control availability.' },
630
630
  { name: 'hooks', usage: 'sks hooks explain|status|trust-report|replay|codex-validate|warning-check ... [--json]', description: 'Explain Codex hook events, validate vendored latest 10-event output schemas, replay fixtures, and enforce warning-zero SKS hook policies under the 0.134 compatibility matrix.' },
631
631
  { name: 'codex-lb', usage: 'sks codex-lb status|health|metrics|doctor|circuit|repair|setup ...', description: 'Configure, health-check, repair, and record circuit evidence for codex-lb provider auth without confusing ChatGPT OAuth and proxy keys.' },
632
632
  { name: 'auth', usage: 'sks auth status|health|repair|setup --host <domain> --api-key <key>', description: 'Shortcut for codex-lb provider auth status, health, repair, and setup commands.' },
@@ -1,2 +1,2 @@
1
- export const PACKAGE_VERSION = '2.0.5';
1
+ export const PACKAGE_VERSION = '2.0.6';
2
2
  //# sourceMappingURL=version.js.map
@@ -15,13 +15,25 @@ const governor = governorMod.decideNarutoConcurrency({
15
15
  const report = activePool.simulateNarutoActivePool({ graph, governor: { ...governor, safe_active_workers: 5 } });
16
16
  assertGate(report.ok === true, 'active pool must drain cleanly', report);
17
17
  assertGate(report.max_observed_active_workers <= 5, 'active pool must never exceed safe cap', report);
18
+ assertGate(report.max_observed_write_lease_conflicts === 0, 'active pool must never run overlapping write leases concurrently', report);
18
19
  assertGate(report.completed_count >= graph.total_work_items, 'active pool must complete all base work items', report);
19
20
  assertGate(report.refill_events >= 5, 'active pool must refill slots as work drains', report);
20
21
  assertGate(report.duplicate_execution_count === 0, 'active pool must not duplicate work without retry', report);
22
+ const sameLeaseGraph = workGraph.buildNarutoWorkGraph({
23
+ requestedClones: 10,
24
+ totalWorkItems: 10,
25
+ writeCapable: true,
26
+ targetPaths: ['src/shared-fixture.ts'],
27
+ maxActiveWorkers: 5
28
+ });
29
+ const sameLeaseReport = activePool.simulateNarutoActivePool({ graph: sameLeaseGraph, governor: { ...governor, safe_active_workers: 5 } });
30
+ assertGate(sameLeaseReport.ok === true, 'same-file work graph must drain without overlapping write leases', sameLeaseReport);
31
+ assertGate(sameLeaseReport.max_observed_write_lease_conflicts === 0, 'same-file write items must be serialized or interleaved with read-only work only', sameLeaseReport);
21
32
  emitGate('naruto:active-pool', {
22
33
  safe_active_workers: report.safe_active_workers,
23
34
  completed_count: report.completed_count,
24
35
  refill_events: report.refill_events,
25
- max_observed_active_workers: report.max_observed_active_workers
36
+ max_observed_active_workers: report.max_observed_active_workers,
37
+ same_lease_max_write_conflicts: sameLeaseReport.max_observed_write_lease_conflicts
26
38
  });
27
39
  //# sourceMappingURL=naruto-active-pool-check.js.map