sneakoscope 4.8.7 → 5.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +51 -726
- package/config/bench-baseline.json +7 -0
- package/crates/sks-core/Cargo.lock +1 -1
- package/crates/sks-core/Cargo.toml +1 -1
- package/crates/sks-core/src/main.rs +1 -1
- package/dist/bin/install.js +35 -0
- package/dist/bin/sks.js +1 -1
- package/dist/cli/cli-theme.js +51 -0
- package/dist/cli/command-registry.js +15 -4
- package/dist/cli/help-fast.js +18 -8
- package/dist/cli/insane-search-command.js +36 -8
- package/dist/cli/install-helpers.js +32 -0
- package/dist/commands/codex-lb.js +2 -0
- package/dist/commands/doctor.js +94 -9
- package/dist/commands/proof.js +6 -3
- package/dist/config/skills-manifest.json +82 -54
- package/dist/core/agents/agent-conflict-graph.js +5 -0
- package/dist/core/agents/agent-lease.js +5 -0
- package/dist/core/agents/agent-ledger-schemas.js +1 -0
- package/dist/core/agents/agent-lifecycle.js +5 -3
- package/dist/core/agents/agent-orchestrator.js +268 -62
- package/dist/core/agents/agent-output-validator.js +14 -3
- package/dist/core/agents/agent-patch-queue-store.js +95 -2
- package/dist/core/agents/agent-patch-queue.js +6 -3
- package/dist/core/agents/agent-patch-schema.js +13 -0
- package/dist/core/agents/agent-proof-evidence.js +6 -1
- package/dist/core/agents/agent-runner-fake.js +40 -0
- package/dist/core/agents/agent-worker-pipeline.js +36 -2
- package/dist/core/agents/codex-exec-worker-adapter.js +2 -0
- package/dist/core/agents/native-cli-worker.js +0 -1
- package/dist/core/agents/native-worker-backend-router.js +58 -1
- package/dist/core/codex-app/sks-menubar.js +477 -132
- package/dist/core/codex-app.js +1 -0
- package/dist/core/codex-control/codex-sdk-config-policy.js +2 -1
- package/dist/core/codex-control/codex-sdk-env-policy.js +1 -1
- package/dist/core/codex-control/schemas/agent-worker-result.schema.js +12 -3
- package/dist/core/codex-hooks/codex-hook-managed-install.js +5 -0
- package/dist/core/codex-hooks/codex-hook-state-writer.js +70 -11
- package/dist/core/codex-hooks/codex-hook-trust-doctor.js +2 -2
- package/dist/core/codex-lb/codex-lb-env.js +20 -1
- package/dist/core/commands/basic-cli.js +18 -1
- package/dist/core/commands/check-command.js +37 -5
- package/dist/core/commands/computer-use-command.js +62 -7
- package/dist/core/commands/db-command.js +31 -5
- package/dist/core/commands/fast-mode-command.js +3 -0
- package/dist/core/commands/gate-result-contract.js +43 -0
- package/dist/core/commands/gates-command.js +6 -1
- package/dist/core/commands/gc-command.js +29 -2
- package/dist/core/commands/goal-command.js +9 -2
- package/dist/core/commands/gx-command.js +79 -7
- package/dist/core/commands/image-ux-review-command.js +188 -13
- package/dist/core/commands/mad-db-command.js +85 -176
- package/dist/core/commands/mad-sks-command.js +230 -29
- package/dist/core/commands/menubar-command.js +24 -2
- package/dist/core/commands/naruto-command.js +64 -10
- package/dist/core/commands/plan-command.js +76 -0
- package/dist/core/commands/ppt-command.js +159 -24
- package/dist/core/commands/qa-loop-command.js +6 -2
- package/dist/core/commands/release-command.js +55 -2
- package/dist/core/commands/research-command.js +1 -1
- package/dist/core/commands/review-command.js +217 -0
- package/dist/core/commands/route-success-helpers.js +59 -0
- package/dist/core/commands/run-command.js +19 -7
- package/dist/core/commands/seo-command.js +49 -1
- package/dist/core/commands/ui-command.js +161 -0
- package/dist/core/commands/uninstall-command.js +15 -1
- package/dist/core/db-safety.js +2 -2
- package/dist/core/doctor/doctor-dirty-planner.js +51 -7
- package/dist/core/doctor/doctor-transaction.js +8 -0
- package/dist/core/doctor/doctor-zellij-repair.js +1 -0
- package/dist/core/doctor/imagegen-repair.js +161 -0
- package/dist/core/feature-fixture-runner.js +2 -2
- package/dist/core/feature-fixtures.js +58 -37
- package/dist/core/feature-registry.js +102 -2
- package/dist/core/fsx.js +39 -6
- package/dist/core/image-ux-review/imagegen-adapter.js +48 -11
- package/dist/core/image-ux-review.js +16 -0
- package/dist/core/imagegen/imagegen-capability.js +11 -5
- package/dist/core/imagegen/require-imagegen.js +57 -0
- package/dist/core/init/skills.js +10 -5
- package/dist/core/mad-db/mad-db-coordinator.js +94 -18
- package/dist/core/mad-db/mad-db-policy.js +12 -10
- package/dist/core/mad-sks/executors/executor-base.js +8 -2
- package/dist/core/mad-sks/executors/index.js +4 -0
- package/dist/core/mad-sks/executors/sql-plane-executor.js +194 -0
- package/dist/core/naruto/naruto-active-pool.js +15 -4
- package/dist/core/naruto/naruto-real-worker-child.js +11 -1
- package/dist/core/naruto/naruto-role-policy.js +3 -0
- package/dist/core/naruto/naruto-task-hints.js +10 -0
- package/dist/core/naruto/naruto-work-graph.js +8 -2
- package/dist/core/naruto/naruto-work-item.js +6 -0
- package/dist/core/naruto/solution-tournament.js +101 -0
- package/dist/core/permission-gates.js +30 -0
- package/dist/core/pipeline-internals/runtime-core.js +11 -3
- package/dist/core/pipeline-internals/runtime-gates.js +27 -0
- package/dist/core/ppt-review/index.js +6 -1
- package/dist/core/ppt-review/slide-imagegen-review.js +75 -10
- package/dist/core/ppt.js +70 -2
- package/dist/core/proof/auto-finalize.js +70 -11
- package/dist/core/proof/proof-schema.js +2 -0
- package/dist/core/proof/route-adapter.js +5 -1
- package/dist/core/proof/route-finalizer.js +8 -5
- package/dist/core/proof/selftest-proof-fixtures.js +18 -5
- package/dist/core/proof/validation.js +2 -0
- package/dist/core/provider/model-router.js +53 -0
- package/dist/core/release/release-gate-node.js +3 -0
- package/dist/core/release/release-gate-resource-governor.js +1 -0
- package/dist/core/routes/constants.js +1 -1
- package/dist/core/routes.js +65 -18
- package/dist/core/safety/mutation-guard.js +5 -1
- package/dist/core/stop-gate/gate-evaluator.js +102 -0
- package/dist/core/stop-gate/stop-gate-check.js +16 -1
- package/dist/core/stop-gate/stop-gate-writer.js +4 -0
- package/dist/core/triwiki/agents-md-projector.js +184 -0
- package/dist/core/triwiki-wrongness/wrongness-schema.js +3 -1
- package/dist/core/trust-kernel/trust-kernel-schema.js +1 -0
- package/dist/core/trust-kernel/trust-report.js +1 -1
- package/dist/core/trust-kernel/trust-status.js +2 -0
- package/dist/core/ui/dashboard-html.js +111 -0
- package/dist/core/update/update-migration-state.js +386 -15
- package/dist/core/update-check.js +178 -81
- package/dist/core/verification/diff-quality.js +100 -0
- package/dist/core/verification/impact-scan.js +164 -0
- package/dist/core/verification/machine-feedback.js +146 -0
- package/dist/core/verification/mistake-rule-compiler.js +195 -0
- package/dist/core/version.js +1 -1
- package/dist/core/zellij/zellij-self-heal.js +9 -6
- package/dist/core/zellij/zellij-slot-telemetry.js +1 -1
- package/dist/scripts/check-feature-quality.js +2 -2
- package/dist/scripts/cli-output-consistency-check.js +57 -0
- package/dist/scripts/coding-bench-check.js +136 -0
- package/dist/scripts/doctor-imagegen-repair-check.js +62 -0
- package/dist/scripts/ensure-bin-executable.js +11 -3
- package/dist/scripts/harness-benchmark-check.js +104 -0
- package/dist/scripts/legacy-update-e2e-check.js +228 -0
- package/dist/scripts/mad-db-command-check.js +11 -8
- package/dist/scripts/mad-db-route-identity-check.js +8 -6
- package/dist/scripts/mad-db-safety-conflict-matrix-check.js +31 -8
- package/dist/scripts/mad-db-skill-policy-snapshot-check.js +4 -5
- package/dist/scripts/naruto-real-active-pool-runtime-check.js +26 -1
- package/dist/scripts/ppt-real-imagegen-wiring-check.js +5 -1
- package/dist/scripts/proof-root-cause-policy-check.js +2 -0
- package/dist/scripts/release-dag-full-coverage-check.js +13 -4
- package/dist/scripts/release-gate-dag-runner.js +14 -0
- package/dist/scripts/release-gate-existence-audit.js +2 -1
- package/dist/scripts/release-gate-planner.js +2 -1
- package/dist/scripts/release-gate-script-parity-check.js +45 -17
- package/dist/scripts/release-metadata-1-19-check.js +2 -1
- package/dist/scripts/seo-geo-feature-fixture-quality-check.js +1 -1
- package/dist/scripts/sks-1-11-gate-lib.js +8 -6
- package/dist/scripts/sks-menubar-install-check.js +57 -20
- package/dist/scripts/ux-review-real-loop-fixture-check.js +9 -4
- package/dist/scripts/ux-review-run-wires-imagegen-check.js +4 -0
- package/dist/scripts/zellij-slot-telemetry-runtime-check.js +1 -0
- package/docs/assets/sneakoscope-architecture-pipeline.jpg +0 -0
- package/docs/demo.tape +28 -0
- package/package.json +31 -24
- package/schemas/codex/completion-proof.schema.json +3 -2
- package/schemas/release/release-gate-node.schema.json +2 -1
- package/dist/scripts/agent-backfill-route-blackbox.js +0 -5
- package/dist/scripts/agent-dynamic-pool-route-blackbox.js +0 -5
- package/dist/scripts/agent-parallel-write-blackbox.js +0 -56
- package/dist/scripts/agent-patch-swarm-route-blackbox.js +0 -10
- package/dist/scripts/agent-route-blackbox-lib.js +0 -132
- package/dist/scripts/blackbox-command-import-smoke.js +0 -143
- package/dist/scripts/blackbox-global-shim.js +0 -77
- package/dist/scripts/blackbox-matrix.js +0 -70
- package/dist/scripts/blackbox-npx-one-shot.js +0 -69
- package/dist/scripts/blackbox-pack-install.js +0 -174
- package/dist/scripts/brand-neutrality-zero-leakage-blackbox.js +0 -4
- package/dist/scripts/build-once-runner-blackbox.js +0 -34
- package/dist/scripts/codex-0140-integration-blackbox.js +0 -13
- package/dist/scripts/codex-agent-type-blackbox.js +0 -4
- package/dist/scripts/codex-app-harness-blackbox.js +0 -4
- package/dist/scripts/codex-app-skill-agent-blackbox.js +0 -4
- package/dist/scripts/codex-hook-approval-blackbox.js +0 -4
- package/dist/scripts/codex-init-deep-directory-local-blackbox.js +0 -4
- package/dist/scripts/codex-native-feature-broker-blackbox.js +0 -4
- package/dist/scripts/codex-native-pattern-analysis-blackbox.js +0 -4
- package/dist/scripts/codex-native-read-repair-split-blackbox.js +0 -55
- package/dist/scripts/codex-native-reference-cache-blackbox.js +0 -41
- package/dist/scripts/core-skill-integrity-blackbox.js +0 -32
- package/dist/scripts/dfix-fast-blackbox-check.js +0 -37
- package/dist/scripts/dfix-parallel-write-blackbox.js +0 -48
- package/dist/scripts/dfix-patch-swarm-route-blackbox.js +0 -10
- package/dist/scripts/doctor-dirty-repair-blackbox.js +0 -22
- package/dist/scripts/doctor-dirty-semantic-blackbox.js +0 -8
- package/dist/scripts/doctor-native-capability-repair-blackbox.js +0 -39
- package/dist/scripts/doctor-transaction-engine-blackbox.js +0 -28
- package/dist/scripts/doctor-zellij-fix-blackbox.js +0 -4
- package/dist/scripts/doctor-zellij-no-homebrew-blackbox.js +0 -4
- package/dist/scripts/doctor-zellij-upgrade-blackbox.js +0 -4
- package/dist/scripts/gate-pack-runner-blackbox.js +0 -27
- package/dist/scripts/gate-pack-v2-blackbox.js +0 -18
- package/dist/scripts/geo-cli-blackbox-check.js +0 -18
- package/dist/scripts/loop-collision-blackbox.js +0 -3
- package/dist/scripts/loop-concurrency-oversubscription-blackbox.js +0 -3
- package/dist/scripts/loop-fixture-production-misuse-blackbox.js +0 -3
- package/dist/scripts/loop-kill-interrupt-real-blackbox.js +0 -3
- package/dist/scripts/loop-merge-strategy-blackbox.js +0 -3
- package/dist/scripts/loop-mesh-production-e2e-blackbox.js +0 -3
- package/dist/scripts/loop-side-effect-blackbox.js +0 -3
- package/dist/scripts/mad-db-operation-lifecycle-blackbox.js +0 -29
- package/dist/scripts/mad-sks-actual-executor-blackbox.js +0 -5
- package/dist/scripts/mad-zellij-headless-fallback-blackbox.js +0 -4
- package/dist/scripts/mad-zellij-self-heal-blackbox.js +0 -4
- package/dist/scripts/naruto-loop-mesh-blackbox.js +0 -3
- package/dist/scripts/naruto-real-parallelism-blackbox.js +0 -307
- package/dist/scripts/naruto-worktree-coding-blackbox.js +0 -29
- package/dist/scripts/parallel-runtime-real-blackbox.js +0 -44
- package/dist/scripts/pipeline-codex-native-doctor-mad-routing-real-blackbox.js +0 -77
- package/dist/scripts/pipeline-codex-native-e2e-blackbox.js +0 -13
- package/dist/scripts/pipeline-codex-native-image-routing-real-blackbox.js +0 -50
- package/dist/scripts/pipeline-codex-native-loop-routing-real-blackbox.js +0 -74
- package/dist/scripts/pipeline-codex-native-qa-routing-real-blackbox.js +0 -51
- package/dist/scripts/pipeline-codex-native-research-routing-real-blackbox.js +0 -45
- package/dist/scripts/pipeline-execution-profile-routing-blackbox.js +0 -4
- package/dist/scripts/postinstall-global-doctor-blackbox.js +0 -12
- package/dist/scripts/ppt-full-e2e-blackbox-check.js +0 -109
- package/dist/scripts/ppt-imagegen-blackbox-check.js +0 -46
- package/dist/scripts/qa-backfill-route-blackbox.js +0 -5
- package/dist/scripts/qa-patch-swarm-route-blackbox.js +0 -10
- package/dist/scripts/release-full-parallelism-blackbox.js +0 -41
- package/dist/scripts/release-triwiki-first-runner-blackbox.js +0 -48
- package/dist/scripts/release-wiring-3110-blackbox.js +0 -27
- package/dist/scripts/release-wiring-3112-blackbox.js +0 -17
- package/dist/scripts/release-wiring-3113-blackbox.js +0 -17
- package/dist/scripts/research-backfill-route-blackbox.js +0 -5
- package/dist/scripts/research-final-reviewer-blackbox.js +0 -70
- package/dist/scripts/research-stage-cycle-runtime-blackbox.js +0 -40
- package/dist/scripts/research-synthesis-writer-blackbox.js +0 -24
- package/dist/scripts/route-blackbox-realism-check.js +0 -21
- package/dist/scripts/scheduler-resource-claim-blackbox.js +0 -24
- package/dist/scripts/seo-cli-blackbox-check.js +0 -18
- package/dist/scripts/sks-3110-all-feature-regression-blackbox.js +0 -116
- package/dist/scripts/sks-3112-all-feature-regression-blackbox.js +0 -29
- package/dist/scripts/sks-3113-all-feature-regression-blackbox.js +0 -17
- package/dist/scripts/sks-400-all-feature-regression-blackbox.js +0 -21
- package/dist/scripts/sks-400-extreme-parallel-blackbox.js +0 -8
- package/dist/scripts/sks-400-five-minute-blackbox.js +0 -9
- package/dist/scripts/sks-400-legacy-purge-blackbox.js +0 -8
- package/dist/scripts/sks-401-all-feature-regression-blackbox.js +0 -46
- package/dist/scripts/sks-401-five-minute-actual-blackbox.js +0 -23
- package/dist/scripts/sks-402-all-feature-regression-blackbox.js +0 -9
- package/dist/scripts/sks-402-five-minute-real-blackbox.js +0 -22
- package/dist/scripts/sksd-warm-cache-blackbox.js +0 -12
- package/dist/scripts/team-backfill-route-blackbox.js +0 -5
- package/dist/scripts/team-parallel-write-blackbox.js +0 -55
- package/dist/scripts/team-patch-swarm-route-blackbox.js +0 -10
- package/dist/scripts/triwiki-affected-graph-blackbox.js +0 -28
- package/dist/scripts/triwiki-proof-bank-blackbox.js +0 -30
- package/dist/scripts/triwiki-proof-bank-lock-blackbox.js +0 -7
- package/dist/scripts/ux-patch-swarm-route-blackbox.js +0 -10
- package/dist/scripts/ux-review-imagegen-blackbox-check.js +0 -67
- package/dist/scripts/zellij-initial-main-only-blackbox.js +0 -28
- package/dist/scripts/zellij-pane-lock-concurrency-blackbox.js +0 -80
- package/dist/scripts/zellij-pane-lock-open-worker-integration-blackbox.js +0 -137
- package/dist/scripts/zellij-self-heal-typed-blackbox.js +0 -4
- package/dist/scripts/zellij-slot-telemetry-real-blackbox.js +0 -20
- package/dist/scripts/zellij-stacked-fallback-integration-blackbox.js +0 -81
- package/dist/scripts/zellij-worker-pane-real-ui-blackbox.js +0 -202
|
@@ -2,6 +2,7 @@ import fs from 'node:fs/promises';
|
|
|
2
2
|
import { existsSync } from 'node:fs';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { spawnSync } from 'node:child_process';
|
|
5
|
+
import { COMMANDS } from '../cli/command-registry.js';
|
|
5
6
|
import { COMMAND_CATALOG, DOLLAR_COMMAND_ALIASES, DOLLAR_COMMANDS, ROUTES } from './routes.js';
|
|
6
7
|
import { FEATURE_QUALITY_LEVELS, fixtureForFeature, fixtureSummary, validateFeatureFixtures } from './feature-fixtures.js';
|
|
7
8
|
import { runFeatureFixture, writeFeatureFixtureReports } from './feature-fixture-runner.js';
|
|
@@ -51,6 +52,8 @@ export async function buildFeatureRegistry({ root = packageRoot(), generatedAt =
|
|
|
51
52
|
}
|
|
52
53
|
features.push(nativeAgentIntakeFeature());
|
|
53
54
|
features.push(agentProofEvidenceFeature());
|
|
55
|
+
features.push(doctorImagegenRepairFeature());
|
|
56
|
+
features.push(...imagegenWiringFeatures());
|
|
54
57
|
for (const skillName of skillNames) {
|
|
55
58
|
if (!skillCoveredByRoute(skillName))
|
|
56
59
|
features.push(skillFeature(skillName));
|
|
@@ -102,7 +105,8 @@ export function validateFeatureRegistry(registry = {}) {
|
|
|
102
105
|
const blockers = [
|
|
103
106
|
...Object.entries(unmapped).flatMap(([kind, values]) => values.map((value) => `${kind}:${value}`)),
|
|
104
107
|
...duplicateFeatureIds.map((id) => `duplicate_feature_id:${id}`),
|
|
105
|
-
...routeMentionsWithoutRoute.map((mention) => `doc_route_mention_without_route:${mention}`)
|
|
108
|
+
...routeMentionsWithoutRoute.map((mention) => `doc_route_mention_without_route:${mention}`),
|
|
109
|
+
...routeGateConsistencyBlockers()
|
|
106
110
|
];
|
|
107
111
|
return {
|
|
108
112
|
ok: blockers.length === 0,
|
|
@@ -118,6 +122,7 @@ export function validateFeatureRegistry(registry = {}) {
|
|
|
118
122
|
unmapped,
|
|
119
123
|
duplicate_feature_ids: duplicateFeatureIds,
|
|
120
124
|
doc_route_mentions_without_route: routeMentionsWithoutRoute,
|
|
125
|
+
route_gate_consistency_blockers: routeGateConsistencyBlockers(),
|
|
121
126
|
blockers,
|
|
122
127
|
nonblocking_known_gaps: [
|
|
123
128
|
'feature fixtures remain progressive',
|
|
@@ -127,6 +132,41 @@ export function validateFeatureRegistry(registry = {}) {
|
|
|
127
132
|
feature_quality_summary: featureQualitySummary(features)
|
|
128
133
|
};
|
|
129
134
|
}
|
|
135
|
+
export function routeGateConsistencyBlockers() {
|
|
136
|
+
const blockers = [];
|
|
137
|
+
for (const route of ROUTES) {
|
|
138
|
+
const cliName = routeCliCommandName(route);
|
|
139
|
+
if (!cliName)
|
|
140
|
+
continue;
|
|
141
|
+
const entry = COMMANDS[cliName];
|
|
142
|
+
if (!entry?.ownsGates)
|
|
143
|
+
continue;
|
|
144
|
+
const routeGates = stopGateFiles(route.stopGate);
|
|
145
|
+
const owned = new Set((entry.ownedGateFiles || []).map((file) => String(file)));
|
|
146
|
+
if (!routeGates.length && owned.size > 0)
|
|
147
|
+
blockers.push(`route_gate_mismatch:${route.id}:routes_none_registry_${[...owned].join('|')}`);
|
|
148
|
+
for (const gate of routeGates) {
|
|
149
|
+
if (!owned.has(gate))
|
|
150
|
+
blockers.push(`route_gate_mismatch:${route.id}:${gate}_not_owned_by_${cliName}`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return blockers;
|
|
154
|
+
}
|
|
155
|
+
function routeCliCommandName(route) {
|
|
156
|
+
const command = String(route.command || '').replace(/^\$/, '').toLowerCase();
|
|
157
|
+
if (Object.hasOwn(COMMANDS, command))
|
|
158
|
+
return command;
|
|
159
|
+
const alias = (route.dollarAliases || [])
|
|
160
|
+
.map((value) => String(value || '').replace(/^\$/, '').toLowerCase())
|
|
161
|
+
.find((value) => Object.hasOwn(COMMANDS, value));
|
|
162
|
+
return alias || null;
|
|
163
|
+
}
|
|
164
|
+
function stopGateFiles(stopGate) {
|
|
165
|
+
const text = String(stopGate || '');
|
|
166
|
+
if (!text || text === 'none' || text === 'honest_mode' || text === 'plan-only')
|
|
167
|
+
return [];
|
|
168
|
+
return text.split('|').map((part) => part.trim()).filter((part) => part.endsWith('.json'));
|
|
169
|
+
}
|
|
130
170
|
export async function writeFeatureInventoryDocs({ root = packageRoot(), outFile = path.join(root, 'docs', 'feature-inventory.md') } = {}) {
|
|
131
171
|
const registry = await buildFeatureRegistry({ root });
|
|
132
172
|
const markdown = renderFeatureInventoryMarkdown(registry);
|
|
@@ -674,6 +714,66 @@ function agentProofEvidenceFeature() {
|
|
|
674
714
|
}
|
|
675
715
|
});
|
|
676
716
|
}
|
|
717
|
+
function doctorImagegenRepairFeature() {
|
|
718
|
+
return baseFeature({
|
|
719
|
+
id: 'doctor:imagegen-repair',
|
|
720
|
+
commands: ['sks doctor --json', 'sks doctor --fix --json'],
|
|
721
|
+
aliases: ['repair.imagegen', 'imagegen_repair'],
|
|
722
|
+
category: 'safety',
|
|
723
|
+
maturity: 'beta',
|
|
724
|
+
intent: 'Doctor repair path that detects Codex App imagegen, attempts repair when requested, and reports imagegen_repair evidence without claiming success unless re-detection passes.',
|
|
725
|
+
voxel_triwiki_integration: 'policy voxel required for visual/image routes that depend on Codex App imagegen',
|
|
726
|
+
completion_proof_integration: 'doctor report imagegen_repair is consumed by imagegen route blockers before visual route proof',
|
|
727
|
+
known_gaps: ['live Codex App feature enablement remains environment-dependent and reports manual actions when unavailable'],
|
|
728
|
+
source_refs: {
|
|
729
|
+
cli_command_names: ['doctor'],
|
|
730
|
+
handler_keys: ['doctor'],
|
|
731
|
+
dollar_commands: [],
|
|
732
|
+
app_skill_aliases: [],
|
|
733
|
+
skills: ['imagegen']
|
|
734
|
+
}
|
|
735
|
+
});
|
|
736
|
+
}
|
|
737
|
+
function imagegenWiringFeatures() {
|
|
738
|
+
return [
|
|
739
|
+
baseFeature({
|
|
740
|
+
id: 'ux-review:run-wires-imagegen',
|
|
741
|
+
commands: ['npm run ux-review:run-wires-imagegen', 'sks ux-review run --image <screenshot> --generate-callouts --json'],
|
|
742
|
+
aliases: ['$Image-UX-Review', '$UX-Review'],
|
|
743
|
+
category: 'visual-memory',
|
|
744
|
+
maturity: 'beta',
|
|
745
|
+
intent: 'Image UX route start gate, shared gpt-image-2 adapter, callout extraction, and Codex App evidence validation wiring.',
|
|
746
|
+
voxel_triwiki_integration: 'image/source/bbox voxel required',
|
|
747
|
+
completion_proof_integration: 'image-ux-review-gate and Completion Proof must separate real Codex image evidence from mock/API fallback evidence',
|
|
748
|
+
known_gaps: ['live Codex App image generation remains environment-dependent'],
|
|
749
|
+
source_refs: {
|
|
750
|
+
cli_command_names: ['image-ux-review'],
|
|
751
|
+
handler_keys: ['image-ux-review', 'ux-review'],
|
|
752
|
+
dollar_commands: ['$Image-UX-Review', '$UX-Review'],
|
|
753
|
+
app_skill_aliases: ['$image-ux-review', '$ux-review'],
|
|
754
|
+
skills: ['image-ux-review', 'ux-review', 'imagegen']
|
|
755
|
+
}
|
|
756
|
+
}),
|
|
757
|
+
baseFeature({
|
|
758
|
+
id: 'ppt:real-imagegen-wiring',
|
|
759
|
+
commands: ['npm run ppt:real-imagegen-wiring', 'sks ppt review --deck <pptx> --json'],
|
|
760
|
+
aliases: ['$PPT'],
|
|
761
|
+
category: 'visual-memory',
|
|
762
|
+
maturity: 'beta',
|
|
763
|
+
intent: 'PPT slide callout review path reuses the shared gpt-image-2 adapter and records imagegen_evidence in PPT gates.',
|
|
764
|
+
voxel_triwiki_integration: 'image/source/bbox voxel required',
|
|
765
|
+
completion_proof_integration: 'ppt-imagegen-review-gate and ppt-gate must include Codex App imagegen evidence classes and hashes',
|
|
766
|
+
known_gaps: ['live deck export and live Codex App image generation remain environment-dependent'],
|
|
767
|
+
source_refs: {
|
|
768
|
+
cli_command_names: ['ppt'],
|
|
769
|
+
handler_keys: ['ppt'],
|
|
770
|
+
dollar_commands: ['$PPT'],
|
|
771
|
+
app_skill_aliases: ['$ppt'],
|
|
772
|
+
skills: ['ppt', 'imagegen']
|
|
773
|
+
}
|
|
774
|
+
})
|
|
775
|
+
];
|
|
776
|
+
}
|
|
677
777
|
function skillFeature(skillName) {
|
|
678
778
|
return baseFeature({
|
|
679
779
|
id: `skill-${slug(skillName)}`,
|
|
@@ -876,7 +976,7 @@ function routeKnownGaps(command) {
|
|
|
876
976
|
if (command === '$MAD-SKS')
|
|
877
977
|
return ['permission closed by owning gate'];
|
|
878
978
|
if (command === '$MAD-DB')
|
|
879
|
-
return ['
|
|
979
|
+
return ['deprecated alias; SQL-plane execution is merged into $MAD-SKS and must still read back postconditions and close the mission-local write profile'];
|
|
880
980
|
return [];
|
|
881
981
|
}
|
|
882
982
|
function checkRow(id, ok, blockers = []) {
|
package/dist/core/fsx.js
CHANGED
|
@@ -5,12 +5,42 @@ import os from 'node:os';
|
|
|
5
5
|
import crypto from 'node:crypto';
|
|
6
6
|
import { spawn } from 'node:child_process';
|
|
7
7
|
import { fileURLToPath } from 'node:url';
|
|
8
|
-
export const PACKAGE_VERSION = '
|
|
8
|
+
export const PACKAGE_VERSION = '5.3.0';
|
|
9
9
|
export const DEFAULT_PROCESS_TAIL_BYTES = 256 * 1024;
|
|
10
10
|
export const DEFAULT_PROCESS_TIMEOUT_MS = 30 * 60 * 1000;
|
|
11
11
|
export function nowIso() {
|
|
12
12
|
return new Date().toISOString();
|
|
13
13
|
}
|
|
14
|
+
export function lastLine(chunk) {
|
|
15
|
+
const lines = String(chunk || '').split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
16
|
+
return lines[lines.length - 1] || '';
|
|
17
|
+
}
|
|
18
|
+
export function throttleLines(fn, ms = 500) {
|
|
19
|
+
let lastAt = 0;
|
|
20
|
+
let pending = null;
|
|
21
|
+
let timer = null;
|
|
22
|
+
const flush = () => {
|
|
23
|
+
timer = null;
|
|
24
|
+
if (!pending)
|
|
25
|
+
return;
|
|
26
|
+
lastAt = Date.now();
|
|
27
|
+
const line = pending;
|
|
28
|
+
pending = null;
|
|
29
|
+
fn(line);
|
|
30
|
+
};
|
|
31
|
+
return (chunk) => {
|
|
32
|
+
const line = lastLine(chunk);
|
|
33
|
+
if (!line)
|
|
34
|
+
return;
|
|
35
|
+
pending = line;
|
|
36
|
+
const now = Date.now();
|
|
37
|
+
const wait = Math.max(0, ms - (now - lastAt));
|
|
38
|
+
if (wait === 0)
|
|
39
|
+
flush();
|
|
40
|
+
else if (!timer)
|
|
41
|
+
timer = setTimeout(flush, wait);
|
|
42
|
+
};
|
|
43
|
+
}
|
|
14
44
|
export function sha256(input) {
|
|
15
45
|
return crypto.createHash('sha256').update(input).digest('hex');
|
|
16
46
|
}
|
|
@@ -109,18 +139,21 @@ export async function writeReceiptRotated(p, data, opts = {}) {
|
|
|
109
139
|
const rotated = prior
|
|
110
140
|
.filter((entry) => entry.isFile() && entry.name.startsWith(`${base}.`) && entry.name.endsWith('.json'))
|
|
111
141
|
.map((entry) => path.join(path.dirname(p), entry.name));
|
|
142
|
+
const rotatedFiles = new Set(rotated);
|
|
112
143
|
const existing = await fsp.stat(p).catch(() => null);
|
|
113
144
|
if (existing) {
|
|
114
145
|
const stamp = new Date(existing.mtimeMs).toISOString().replace(/[:.]/g, '-');
|
|
115
|
-
|
|
146
|
+
const rotatedPath = path.join(path.dirname(p), `${base}.${stamp}.json`);
|
|
147
|
+
await fsp.rename(p, rotatedPath).catch(() => undefined);
|
|
148
|
+
rotatedFiles.add(rotatedPath);
|
|
116
149
|
}
|
|
117
150
|
await writeJsonAtomic(p, data);
|
|
118
|
-
const rows = await Promise.all(
|
|
119
|
-
rows
|
|
151
|
+
const rows = await Promise.all([...rotatedFiles].map(async (file) => ({ file, stat: await fsp.stat(file).catch(() => null) })));
|
|
152
|
+
const removable = rows
|
|
120
153
|
.filter((row) => Boolean(row.stat))
|
|
121
154
|
.sort((a, b) => b.stat.mtimeMs - a.stat.mtimeMs)
|
|
122
|
-
.slice(keep)
|
|
123
|
-
|
|
155
|
+
.slice(keep);
|
|
156
|
+
await Promise.all(removable.map((row) => fsp.rm(row.file, { force: true }).catch(() => undefined)));
|
|
124
157
|
}
|
|
125
158
|
export async function writeBinaryAtomic(p, data) {
|
|
126
159
|
await ensureDir(path.dirname(p));
|
|
@@ -107,6 +107,7 @@ export function createCodexAppImagegenAdapter(opts = {}) {
|
|
|
107
107
|
schema: 'sks.image-ux-gpt-image-2-response.v1',
|
|
108
108
|
created_at: nowIso(),
|
|
109
109
|
provider: 'codex_app_imagegen',
|
|
110
|
+
evidence_class: 'codex_app_imagegen',
|
|
110
111
|
model: 'gpt-image-2',
|
|
111
112
|
ok: false,
|
|
112
113
|
status: 'blocked',
|
|
@@ -131,11 +132,13 @@ export function createCodexAppImagegenAdapter(opts = {}) {
|
|
|
131
132
|
schema: 'sks.image-ux-gpt-image-2-response.v1',
|
|
132
133
|
created_at: nowIso(),
|
|
133
134
|
provider: 'codex_app_imagegen',
|
|
135
|
+
evidence_class: 'codex_app_imagegen',
|
|
134
136
|
model: 'gpt-image-2',
|
|
135
137
|
ok: true,
|
|
136
138
|
status: 'generated',
|
|
137
139
|
output_image_path: dest,
|
|
138
140
|
output_image_sha256: meta.sha256,
|
|
141
|
+
output_sha256: meta.sha256,
|
|
139
142
|
output_id: meta.output_id,
|
|
140
143
|
output_source: outputSource,
|
|
141
144
|
image_artifact_path_contract: imageContract?.artifact_path || null,
|
|
@@ -161,6 +164,7 @@ export function createCodexAppImagegenAdapter(opts = {}) {
|
|
|
161
164
|
schema: 'sks.image-ux-gpt-image-2-response.v1',
|
|
162
165
|
created_at: nowIso(),
|
|
163
166
|
provider: 'codex_app_imagegen',
|
|
167
|
+
evidence_class: 'codex_app_imagegen',
|
|
164
168
|
model: 'gpt-image-2',
|
|
165
169
|
ok: false,
|
|
166
170
|
status: 'blocked',
|
|
@@ -196,6 +200,22 @@ export function createFakeImagegenAdapter(opts = {}) {
|
|
|
196
200
|
await ensureDir(input.output_dir);
|
|
197
201
|
const requestArtifact = path.join(input.output_dir, 'image-ux-gpt-image-2-request.json');
|
|
198
202
|
const responseArtifact = path.join(input.output_dir, 'image-ux-gpt-image-2-response.json');
|
|
203
|
+
if (!imagegenMockContext(opts)) {
|
|
204
|
+
await writeJsonAtomic(responseArtifact, {
|
|
205
|
+
schema: 'sks.image-ux-gpt-image-2-response.v1',
|
|
206
|
+
created_at: nowIso(),
|
|
207
|
+
provider: 'fake_imagegen_adapter',
|
|
208
|
+
fake_adapter: true,
|
|
209
|
+
execution_class: 'mock_fixture',
|
|
210
|
+
evidence_class: 'mock_fixture',
|
|
211
|
+
model: 'gpt-image-2',
|
|
212
|
+
ok: false,
|
|
213
|
+
status: 'blocked',
|
|
214
|
+
blocker: 'fake_imagegen_requires_test_or_mock_context',
|
|
215
|
+
local_only: true
|
|
216
|
+
});
|
|
217
|
+
return { ok: false, status: 'blocked', generated_image_path: null, output_id: null, blocker: 'fake_imagegen_requires_test_or_mock_context', provider: 'fake_imagegen_adapter', request_artifact: null, response_artifact: responseArtifact, latency_ms: Date.now() - started };
|
|
218
|
+
}
|
|
199
219
|
const validation = await validateGptImage2Request({
|
|
200
220
|
provider: 'fake_imagegen_adapter',
|
|
201
221
|
endpoint: 'local hermetic fixture',
|
|
@@ -227,6 +247,9 @@ export function createFakeImagegenAdapter(opts = {}) {
|
|
|
227
247
|
schema: 'sks.image-ux-gpt-image-2-response.v1',
|
|
228
248
|
created_at: nowIso(),
|
|
229
249
|
provider: 'fake_imagegen_adapter',
|
|
250
|
+
fake_adapter: true,
|
|
251
|
+
execution_class: 'mock_fixture',
|
|
252
|
+
evidence_class: 'mock_fixture',
|
|
230
253
|
model: 'gpt-image-2',
|
|
231
254
|
ok: false,
|
|
232
255
|
status: 'blocked',
|
|
@@ -251,16 +274,20 @@ export function createFakeImagegenAdapter(opts = {}) {
|
|
|
251
274
|
schema: 'sks.image-ux-gpt-image-2-response.v1',
|
|
252
275
|
created_at: nowIso(),
|
|
253
276
|
provider: 'fake_imagegen_adapter',
|
|
277
|
+
fake_adapter: true,
|
|
278
|
+
execution_class: 'mock_fixture',
|
|
279
|
+
evidence_class: 'mock_fixture',
|
|
254
280
|
model: 'gpt-image-2',
|
|
255
281
|
ok: true,
|
|
256
282
|
status: 'generated',
|
|
257
283
|
output_image_path: out,
|
|
258
284
|
output_image_sha256: meta.sha256,
|
|
285
|
+
output_sha256: meta.sha256,
|
|
259
286
|
output_id: meta.output_id,
|
|
287
|
+
output_source: 'mock_fixture',
|
|
260
288
|
image_artifact_path_contract: imageContract?.artifact_path || null,
|
|
261
289
|
dimensions: { width: meta.width, height: meta.height, format: meta.format },
|
|
262
290
|
latency_ms: Date.now() - started,
|
|
263
|
-
fake_adapter: true,
|
|
264
291
|
source: 'mock_like_fixture',
|
|
265
292
|
real_generated: false,
|
|
266
293
|
mock: true,
|
|
@@ -320,6 +347,7 @@ export function createOpenAIImagesApiAdapter(opts = {}) {
|
|
|
320
347
|
schema: 'sks.image-ux-gpt-image-2-response.v1',
|
|
321
348
|
created_at: nowIso(),
|
|
322
349
|
provider: 'openai_images_api',
|
|
350
|
+
evidence_class: 'non_codex_api_fallback',
|
|
323
351
|
model: 'gpt-image-2',
|
|
324
352
|
ok: false,
|
|
325
353
|
status: 'blocked',
|
|
@@ -334,6 +362,7 @@ export function createOpenAIImagesApiAdapter(opts = {}) {
|
|
|
334
362
|
schema: 'sks.image-ux-gpt-image-2-response.v1',
|
|
335
363
|
created_at: nowIso(),
|
|
336
364
|
provider: 'openai_images_api',
|
|
365
|
+
evidence_class: 'non_codex_api_fallback',
|
|
337
366
|
model: 'gpt-image-2',
|
|
338
367
|
ok: false,
|
|
339
368
|
status: 'blocked',
|
|
@@ -397,6 +426,7 @@ export function createOpenAIImagesApiAdapter(opts = {}) {
|
|
|
397
426
|
schema: 'sks.image-ux-gpt-image-2-response.v1',
|
|
398
427
|
created_at: nowIso(),
|
|
399
428
|
provider: 'openai_responses_image_generation',
|
|
429
|
+
evidence_class: 'non_codex_api_fallback',
|
|
400
430
|
model: 'gpt-image-2',
|
|
401
431
|
responses_model: responsesImagegenModel(opts),
|
|
402
432
|
auth_source: auth.auth_source,
|
|
@@ -404,6 +434,7 @@ export function createOpenAIImagesApiAdapter(opts = {}) {
|
|
|
404
434
|
status: 'generated',
|
|
405
435
|
output_image_path: out,
|
|
406
436
|
output_image_sha256: meta.sha256,
|
|
437
|
+
output_sha256: meta.sha256,
|
|
407
438
|
output_id: meta.output_id,
|
|
408
439
|
image_artifact_path_contract: imageContract?.artifact_path || null,
|
|
409
440
|
dimensions: { width: meta.width, height: meta.height, format: meta.format },
|
|
@@ -454,12 +485,14 @@ export function createOpenAIImagesApiAdapter(opts = {}) {
|
|
|
454
485
|
schema: 'sks.image-ux-gpt-image-2-response.v1',
|
|
455
486
|
created_at: nowIso(),
|
|
456
487
|
provider: 'openai_images_api',
|
|
488
|
+
evidence_class: 'non_codex_api_fallback',
|
|
457
489
|
model: 'gpt-image-2',
|
|
458
490
|
auth_source: auth.auth_source,
|
|
459
491
|
ok: true,
|
|
460
492
|
status: 'generated',
|
|
461
493
|
output_image_path: out,
|
|
462
494
|
output_image_sha256: meta.sha256,
|
|
495
|
+
output_sha256: meta.sha256,
|
|
463
496
|
output_id: meta.output_id,
|
|
464
497
|
image_artifact_path_contract: imageContract?.artifact_path || null,
|
|
465
498
|
dimensions: { width: meta.width, height: meta.height, format: meta.format },
|
|
@@ -511,24 +544,17 @@ async function resolveImageArtifactRoot(input) {
|
|
|
511
544
|
return projectRoot(input.output_dir || process.cwd()).catch(() => cwdRoot);
|
|
512
545
|
}
|
|
513
546
|
export async function generateGptImage2CalloutReview(input, opts = {}) {
|
|
514
|
-
if (opts.fake === true || process.env.SKS_TEST_FAKE_IMAGEGEN === '1') {
|
|
515
|
-
return createFakeImagegenAdapter(opts.fakeAdapter || {}).generateCalloutReview(input);
|
|
547
|
+
if ((opts.fake === true || process.env.SKS_TEST_FAKE_IMAGEGEN === '1') && imagegenMockContext(opts)) {
|
|
548
|
+
return createFakeImagegenAdapter({ ...(opts.fakeAdapter || {}), mockContext: true }).generateCalloutReview(input);
|
|
516
549
|
}
|
|
517
550
|
const capability = await detectImagegenCapability(opts.capability || {}).catch(() => null);
|
|
518
|
-
// Auto-enable the OpenAI direct-key API fallback whenever an OPENAI_API_KEY is
|
|
519
|
-
// available, so a missing/failed Codex App $imagegen surface still produces a
|
|
520
|
-
// real image instead of a hard block. Explicit opt-out wins: pass
|
|
521
|
-
// allowApiFallback:false or SKS_IMAGEGEN_ALLOW_API_FALLBACK=0.
|
|
522
|
-
const openAiKeyPresent = Boolean(opts.openai?.apiKey || process.env.OPENAI_API_KEY);
|
|
523
|
-
const explicitDisableApiFallback = opts.allowApiFallback === false || process.env.SKS_IMAGEGEN_ALLOW_API_FALLBACK === '0';
|
|
524
551
|
// codex-lb imagegen is a direct API fallback, not Codex App imagegen evidence.
|
|
525
552
|
// It must be explicitly enabled by the caller or environment.
|
|
526
553
|
const explicitDisableCodexLbFallback = opts.allowCodexLbApiFallback === false || process.env.SKS_IMAGEGEN_ALLOW_CODEX_LB_API_FALLBACK === '0';
|
|
527
554
|
const allowCodexLbApiFallback = !explicitDisableCodexLbFallback && (opts.allowCodexLbApiFallback === true
|
|
528
555
|
|| process.env.SKS_IMAGEGEN_ALLOW_CODEX_LB_API_FALLBACK === '1');
|
|
529
|
-
const allowApiFallback =
|
|
556
|
+
const allowApiFallback = (opts.allowApiFallback === true
|
|
530
557
|
|| process.env.SKS_IMAGEGEN_ALLOW_API_FALLBACK === '1'
|
|
531
|
-
|| openAiKeyPresent
|
|
532
558
|
|| allowCodexLbApiFallback);
|
|
533
559
|
const openaiOptions = {
|
|
534
560
|
...(opts.openai || {}),
|
|
@@ -544,6 +570,13 @@ export async function generateGptImage2CalloutReview(input, opts = {}) {
|
|
|
544
570
|
return codexResult;
|
|
545
571
|
return createOpenAIImagesApiAdapter(openaiOptions).generateCalloutReview(input);
|
|
546
572
|
}
|
|
573
|
+
function imagegenMockContext(opts = {}) {
|
|
574
|
+
return opts.mockContext === true
|
|
575
|
+
|| opts.testContext === true
|
|
576
|
+
|| process.env.NODE_ENV === 'test'
|
|
577
|
+
|| process.env.SKS_SELFTEST_MOCK === '1'
|
|
578
|
+
|| process.env.SKS_MOCK === '1';
|
|
579
|
+
}
|
|
547
580
|
export function imagegenCapabilityBlocker(surface = 'Codex App $imagegen') {
|
|
548
581
|
return {
|
|
549
582
|
schema: 'sks.image-ux-imagegen-blocker.v1',
|
|
@@ -705,6 +738,9 @@ export async function generatedImageMetadata(root, imagePath, opts = {}) {
|
|
|
705
738
|
source_screen_id: opts.source_screen_id || null,
|
|
706
739
|
provider_model: 'gpt-image-2',
|
|
707
740
|
provider_surface: opts.provider_surface || 'codex_app_imagegen',
|
|
741
|
+
evidence_class: opts.evidence_class || (opts.mock ? 'mock_fixture' : 'codex_app_imagegen'),
|
|
742
|
+
output_source: opts.output_source || (opts.mock ? 'mock_fixture' : 'manual_attach'),
|
|
743
|
+
output_sha256: opts.output_sha256 || await sha256File(absolute),
|
|
708
744
|
requested_fidelity: 'high_fidelity_automatic',
|
|
709
745
|
image_input_fidelity_note: 'high_fidelity_automatic',
|
|
710
746
|
privacy: 'local-only',
|
|
@@ -729,6 +765,7 @@ function redactedImagegenResponse(payload, ok, latencyMs, provider = 'openai_ima
|
|
|
729
765
|
schema: 'sks.image-ux-gpt-image-2-response.v1',
|
|
730
766
|
created_at: nowIso(),
|
|
731
767
|
provider,
|
|
768
|
+
evidence_class: provider === 'codex_app_imagegen' ? 'codex_app_imagegen' : 'non_codex_api_fallback',
|
|
732
769
|
model: 'gpt-image-2',
|
|
733
770
|
ok,
|
|
734
771
|
status: ok ? 'generated' : 'blocked',
|
|
@@ -790,11 +790,14 @@ function buildImagegenResponseArtifact(generatedReviewLedger = {}) {
|
|
|
790
790
|
schema: 'sks.image-ux-gpt-image-2-response.v1',
|
|
791
791
|
created_at: nowIso(),
|
|
792
792
|
provider: image?.provider_surface || generatedReviewLedger.provider?.preferred_surface || 'none',
|
|
793
|
+
evidence_class: image?.evidence_class || (image?.mock ? 'mock_fixture' : image?.real_generated ? 'codex_app_imagegen' : null),
|
|
793
794
|
model: 'gpt-image-2',
|
|
794
795
|
ok: generatedReviewLedger.passed === true,
|
|
795
796
|
status: generatedReviewLedger.passed === true ? 'generated' : 'blocked_or_pending',
|
|
796
797
|
output_image_path: image?.path || null,
|
|
797
798
|
output_image_sha256: image?.sha256 || null,
|
|
799
|
+
output_sha256: image?.output_sha256 || image?.sha256 || null,
|
|
800
|
+
output_source: image?.output_source || (image?.mock ? 'mock_fixture' : image?.real_generated ? 'manual_attach' : null),
|
|
798
801
|
output_id: image?.output_id || null,
|
|
799
802
|
dimensions: image ? { width: image.width || null, height: image.height || null, format: image.format || null } : null,
|
|
800
803
|
latency_ms: image?.latency_ms || null,
|
|
@@ -863,6 +866,19 @@ function generatedImageEvidenceBlockers(image = {}, evidence = {}) {
|
|
|
863
866
|
if (image.real_generated !== true || image.mock === true || image.source === 'mock_fixture')
|
|
864
867
|
return [];
|
|
865
868
|
const blockers = [];
|
|
869
|
+
const evidenceClass = String(image.evidence_class || '');
|
|
870
|
+
const outputSource = String(image.output_source || '');
|
|
871
|
+
const outputSha = String(image.output_sha256 || image.output_image_sha256 || '');
|
|
872
|
+
if (!evidenceClass)
|
|
873
|
+
blockers.push('generated_review_image_evidence_class_missing');
|
|
874
|
+
else if (evidenceClass !== 'codex_app_imagegen')
|
|
875
|
+
blockers.push(`generated_review_image_evidence_class_not_codex_app:${evidenceClass}`);
|
|
876
|
+
if (outputSource && !['manual_attach', 'auto_discovered_generated_images'].includes(outputSource))
|
|
877
|
+
blockers.push(`generated_review_image_output_source_invalid:${outputSource}`);
|
|
878
|
+
if (!outputSha)
|
|
879
|
+
blockers.push('generated_review_image_output_sha256_missing');
|
|
880
|
+
else if (evidence.sha256 && outputSha !== evidence.sha256)
|
|
881
|
+
blockers.push('generated_review_image_output_sha256_mismatch');
|
|
866
882
|
if (!image.path)
|
|
867
883
|
blockers.push('generated_review_image_missing');
|
|
868
884
|
if (!evidence.sha256)
|
|
@@ -18,8 +18,13 @@ export async function detectImagegenCapability(opts = {}) {
|
|
|
18
18
|
}).catch(() => null);
|
|
19
19
|
const apiFallbackAvailable = openaiApiKeyPresent;
|
|
20
20
|
const fakeAdapterEnabled = opts.fake === true || env.SKS_TEST_FAKE_IMAGEGEN === '1';
|
|
21
|
-
const
|
|
22
|
-
|
|
21
|
+
const fakeAdapterAcceptedForRoute = fakeAdapterEnabled && (opts.mockContext === true
|
|
22
|
+
|| opts.testContext === true
|
|
23
|
+
|| env.NODE_ENV === 'test'
|
|
24
|
+
|| env.SKS_SELFTEST_MOCK === '1'
|
|
25
|
+
|| env.SKS_MOCK === '1');
|
|
26
|
+
const realGenerationAvailable = codexAppBuiltInAvailable;
|
|
27
|
+
const routeGenerationAvailable = codexAppBuiltInAvailable || fakeAdapterAcceptedForRoute;
|
|
23
28
|
const coreReady = codexAppBuiltInAvailable;
|
|
24
29
|
const coreBlockers = coreReady ? [] : ['codex_app_builtin_imagegen_capability_missing'];
|
|
25
30
|
const routeGenerationBlockers = routeGenerationAvailable ? [] : ['imagegen_capability_missing'];
|
|
@@ -68,16 +73,17 @@ export async function detectImagegenCapability(opts = {}) {
|
|
|
68
73
|
},
|
|
69
74
|
fake_adapter: {
|
|
70
75
|
available: fakeAdapterEnabled,
|
|
76
|
+
accepted_for_route_readiness: fakeAdapterAcceptedForRoute,
|
|
71
77
|
env: 'SKS_TEST_FAKE_IMAGEGEN=1',
|
|
72
78
|
source: 'mock_like_fixture',
|
|
73
79
|
real_generation_claim_allowed: false
|
|
74
80
|
},
|
|
75
|
-
supports_reference_image: codexAppBuiltInAvailable ||
|
|
81
|
+
supports_reference_image: codexAppBuiltInAvailable || fakeAdapterAcceptedForRoute,
|
|
76
82
|
gpt_image_2_input_fidelity_automatic: true,
|
|
77
83
|
input_fidelity_must_be_omitted: true,
|
|
78
84
|
supported_workflows: {
|
|
79
|
-
ux_review_callouts: codexAppBuiltInAvailable ||
|
|
80
|
-
ppt_slide_callouts: codexAppBuiltInAvailable ||
|
|
85
|
+
ux_review_callouts: codexAppBuiltInAvailable || fakeAdapterAcceptedForRoute,
|
|
86
|
+
ppt_slide_callouts: codexAppBuiltInAvailable || fakeAdapterAcceptedForRoute,
|
|
81
87
|
structured_extraction_required_after_generation: true,
|
|
82
88
|
full_verification_requires_codex_app_output: true
|
|
83
89
|
},
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { detectImagegenCapability } from './imagegen-capability.js';
|
|
2
|
+
import { repairCodexImagegen } from '../doctor/imagegen-repair.js';
|
|
3
|
+
export async function requireCodexImagegen(root, opts = {}) {
|
|
4
|
+
const capability = await detectImagegenCapability({
|
|
5
|
+
codexBin: opts.codexBin || undefined,
|
|
6
|
+
timeoutMs: opts.timeoutMs || 5000
|
|
7
|
+
}).catch((err) => ({
|
|
8
|
+
ok: false,
|
|
9
|
+
core_ready: false,
|
|
10
|
+
blockers: [err instanceof Error ? err.message : String(err)]
|
|
11
|
+
}));
|
|
12
|
+
if (capability.core_ready === true) {
|
|
13
|
+
return { ok: true, capability, repair: null, blocker: null, blockers: [] };
|
|
14
|
+
}
|
|
15
|
+
const repair = opts.autoRepair === true
|
|
16
|
+
? await repairCodexImagegen({
|
|
17
|
+
root,
|
|
18
|
+
apply: opts.applyRepair === true,
|
|
19
|
+
codexBin: opts.codexBin || null,
|
|
20
|
+
timeoutMs: opts.timeoutMs || 5000
|
|
21
|
+
}).catch((err) => ({
|
|
22
|
+
ok: false,
|
|
23
|
+
recovered: false,
|
|
24
|
+
blockers: [err instanceof Error ? err.message : String(err)]
|
|
25
|
+
}))
|
|
26
|
+
: null;
|
|
27
|
+
const finalCapability = repair
|
|
28
|
+
? repair.after || capability
|
|
29
|
+
: capability;
|
|
30
|
+
const ok = finalCapability.core_ready === true || repair?.recovered === true;
|
|
31
|
+
const blockers = ok ? [] : [
|
|
32
|
+
...new Set([
|
|
33
|
+
...((finalCapability?.core_blockers || []).map(String)),
|
|
34
|
+
...((finalCapability?.blockers || []).map(String)),
|
|
35
|
+
...((repair?.blockers || []).map(String)),
|
|
36
|
+
'codex_imagegen_unavailable'
|
|
37
|
+
])
|
|
38
|
+
];
|
|
39
|
+
return {
|
|
40
|
+
ok,
|
|
41
|
+
capability: finalCapability,
|
|
42
|
+
repair,
|
|
43
|
+
blocker: ok ? null : {
|
|
44
|
+
schema: 'sks.codex-imagegen-required-blocker.v1',
|
|
45
|
+
blocker: 'codex_imagegen_unavailable',
|
|
46
|
+
status: 'blocked',
|
|
47
|
+
blockers,
|
|
48
|
+
next_actions: repair?.manual_actions || [
|
|
49
|
+
'Install/update Codex CLI: npm i -g @openai/codex@latest',
|
|
50
|
+
'Open Codex App settings and enable image_generation / $imagegen.',
|
|
51
|
+
'Verify with: codex features list --json'
|
|
52
|
+
]
|
|
53
|
+
},
|
|
54
|
+
blockers
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=require-imagegen.js.map
|