sneakoscope 7.3.0 → 7.6.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 +129 -10
- package/crates/sks-core/Cargo.lock +1 -1
- package/crates/sks-core/Cargo.toml +1 -1
- package/dist/cli/codex-app-command.js +1 -1
- package/dist/cli/command-manifest-lite.js +4 -1
- package/dist/cli/command-registry.js +2 -0
- package/dist/cli/install-helpers-codex-lb-chain.js +42 -0
- package/dist/cli/install-helpers-codex-lb-config.js +114 -9
- package/dist/cli/install-helpers-install-support.js +6 -16
- package/dist/cli/install-helpers.js +788 -600
- package/dist/cli/router.js +30 -2
- package/dist/commands/codex-app.js +37 -1
- package/dist/commands/codex-lb.js +491 -300
- package/dist/config/skills-manifest.json +57 -71
- package/dist/core/align/align-route.js +127 -0
- package/dist/core/codex-app/codex-app-fast-ui-repair.js +8 -4
- package/dist/core/codex-app/codex-app-restart.js +83 -0
- package/dist/core/codex-app/codex-app-ui-state-snapshot.js +8 -4
- package/dist/core/codex-app/desktop-routing-snapshot.js +1 -1
- package/dist/core/codex-app/menubar/constants.js +5 -0
- package/dist/core/codex-app/menubar/generation-transaction-journal.js +1 -3
- package/dist/core/codex-app/menubar/installer.js +18 -0
- package/dist/core/codex-app/multi-provider-router.js +22 -10
- package/dist/core/codex-app/openrouter-activate.js +26 -1
- package/dist/core/codex-app.js +118 -26
- package/dist/core/codex-control/codex-app-server-runtime-env.js +86 -0
- package/dist/core/codex-control/codex-app-server-v2-client.js +78 -8
- package/dist/core/codex-control/codex-task-runner.js +2 -2
- package/dist/core/codex-lb/capability-runner.js +204 -0
- package/dist/core/codex-lb/capability-types.js +1 -0
- package/dist/core/codex-lb/codex-lb-env.js +9 -13
- package/dist/core/codex-lb/codex-lb-setup.js +45 -8
- package/dist/core/codex-lb/codex-lb-tool-catalog.js +52 -74
- package/dist/core/codex-lb/codex-lb-tool-output-recovery.js +1 -1
- package/dist/core/codex-lb/desktop-auth-invariant.js +185 -0
- package/dist/core/codex-lb/desktop-bridge/client.js +34 -0
- package/dist/core/codex-lb/desktop-bridge/header-policy.js +106 -0
- package/dist/core/codex-lb/desktop-bridge/http-forward.js +101 -0
- package/dist/core/codex-lb/desktop-bridge/index.js +10 -0
- package/dist/core/codex-lb/desktop-bridge/launchd.js +81 -0
- package/dist/core/codex-lb/desktop-bridge/location-rewrite.js +27 -0
- package/dist/core/codex-lb/desktop-bridge/security.js +274 -0
- package/dist/core/codex-lb/desktop-bridge/server.js +179 -0
- package/dist/core/codex-lb/desktop-bridge/state.js +119 -0
- package/dist/core/codex-lb/desktop-bridge/types.js +16 -0
- package/dist/core/codex-lb/desktop-bridge/websocket-forward.js +151 -0
- package/dist/core/codex-lb/desktop-center-credentials.js +189 -0
- package/dist/core/codex-lb/desktop-controller.js +1410 -0
- package/dist/core/codex-lb/desktop-mode.js +32 -0
- package/dist/core/codex-lb/desktop-real-evidence.js +168 -0
- package/dist/core/codex-lb/desktop-service.js +613 -0
- package/dist/core/codex-lb/legacy-migration.js +575 -0
- package/dist/core/codex-lb/migration-receipt.js +246 -0
- package/dist/core/codex-lb/probes/auxiliary-surfaces-probe.js +60 -0
- package/dist/core/codex-lb/probes/bridge-probe.js +75 -0
- package/dist/core/codex-lb/probes/catalog-probe.js +128 -0
- package/dist/core/codex-lb/probes/computer-use-probe.js +50 -0
- package/dist/core/codex-lb/probes/image-generation-probe.js +47 -0
- package/dist/core/codex-lb/probes/probe-evidence.js +39 -0
- package/dist/core/codex-lb/probes/voice-realtime-probe.js +44 -0
- package/dist/core/codex-lb/trusted-deep-evidence.js +403 -0
- package/dist/core/codex-native/core-skill-manifest.js +22 -6
- package/dist/core/codex-runtime/codex-desktop-config-policy.js +2 -1
- package/dist/core/commands/align-command.js +220 -0
- package/dist/core/commands/image-ux-review-command.js +280 -68
- package/dist/core/commands/naruto-command.js +257 -8
- package/dist/core/commands/ppt-command.js +2 -2
- package/dist/core/commands/telegram-command.js +402 -34
- package/dist/core/commands/triwiki-command.js +11 -1
- package/dist/core/commands/triwiki-graph-command.js +160 -0
- package/dist/core/commands/wiki-command.js +100 -20
- package/dist/core/doctor/skill-legacy-surface.js +1 -3
- package/dist/core/errors/message.js +3 -0
- package/dist/core/evidence/evidence-freshness.js +14 -0
- package/dist/core/feature-fixtures.js +9 -1
- package/dist/core/feature-registry.js +5 -3
- package/dist/core/fsx.js +7 -3
- package/dist/core/hooks-runtime/codex-commit-hooks-selftest.js +82 -0
- package/dist/core/hooks-runtime/context-graph-freshness-preflight.js +113 -0
- package/dist/core/hooks-runtime/hook-context.js +15 -2
- package/dist/core/hooks-runtime/managed-skill-generation-heal.js +46 -0
- package/dist/core/hooks-runtime/naruto-terminal-finalization.js +1 -0
- package/dist/core/hooks-runtime/official-subagent-lifecycle.js +1 -1
- package/dist/core/hooks-runtime/tool-output-quarantine.js +1 -1
- package/dist/core/hooks-runtime.js +33 -89
- package/dist/core/image-ux-review/callout-extraction.js +6 -0
- package/dist/core/image-ux-review/imagegen-adapter.js +64 -23
- package/dist/core/image-ux-review/real-callout-extractor.js +1 -0
- package/dist/core/image-ux-review.js +230 -12
- package/dist/core/imagegen/codex-lb-imagegen-target.js +21 -7
- package/dist/core/imagegen/imagegen-capability.js +10 -4
- package/dist/core/imagegen/require-imagegen.js +29 -5
- package/dist/core/init/skills.js +25 -13
- package/dist/core/init.js +1 -1
- package/dist/core/install/installed-package-smoke.js +157 -4
- package/dist/core/managed-assets/managed-assets-manifest.js +2 -1
- package/dist/core/managed-path-safety.js +8 -10
- package/dist/core/mcp-config/backup.js +2 -4
- package/dist/core/mcp-config/config-reader.js +2 -4
- package/dist/core/mcp-config/scope.js +3 -5
- package/dist/core/naruto/context-graph-advisor-scope.js +242 -0
- package/dist/core/naruto/context-graph-advisor.js +0 -0
- package/dist/core/perf/release-latency-slo.js +12 -6
- package/dist/core/pipeline-internals/runtime-core.js +78 -0
- package/dist/core/pipeline-internals/runtime-gates.js +5 -2
- package/dist/core/policy/latest-version-guidance.js +113 -0
- package/dist/core/ppt.js +8 -8
- package/dist/core/preflight/parallel-preflight-engine.js +1 -1
- package/dist/core/proof/auto-finalize.js +98 -6
- package/dist/core/proof/route-proof-gate.js +12 -1
- package/dist/core/proof/route-proof-policy.js +8 -8
- package/dist/core/release/gate-manifest.js +32 -1
- package/dist/core/release/npm-stage-contract.js +21 -0
- package/dist/core/release/package-size-budget.js +2 -2
- package/dist/core/release/release-gate-contract.js +5 -0
- package/dist/core/release/release-proof-io.js +1 -3
- package/dist/core/release/release-real-contract.js +5 -4
- package/dist/core/release/release-stamp-proof.js +1 -3
- package/dist/core/release/stage-publish.js +27 -0
- package/dist/core/remote/audit-idempotency.js +50 -18
- package/dist/core/remote/codex-public-activity.js +283 -0
- package/dist/core/remote/index.js +1 -0
- package/dist/core/remote/ssh-worker-client.js +4 -1
- package/dist/core/remote/worker.js +206 -27
- package/dist/core/research/research-adversarial-review.js +1 -3
- package/dist/core/research/research-claim-synthesizer.js +1 -3
- package/dist/core/research/research-falsification-runner.js +1 -3
- package/dist/core/research/research-source-evidence.js +1 -3
- package/dist/core/responses-stream.js +65 -19
- package/dist/core/routes/constants.js +1 -1
- package/dist/core/routes/design-policy.js +7 -2
- package/dist/core/routes/dollar-manifest-lite.js +2 -4
- package/dist/core/routes/evidence.js +1 -1
- package/dist/core/routes.js +30 -10
- package/dist/core/safety/command-contract/contracts.js +2 -0
- package/dist/core/safety/command-contract/types.js +1 -1
- package/dist/core/search/context-graph-seeds.js +205 -0
- package/dist/core/search/context.js +0 -0
- package/dist/core/search/provider.js +2 -2
- package/dist/core/secret-redaction.js +6 -0
- package/dist/core/subagents/naruto-help-contract.js +2 -1
- package/dist/core/subagents/naruto-host-credentials.js +161 -0
- package/dist/core/subagents/official-subagent-preparation.js +4 -1
- package/dist/core/subagents/official-subagent-prompt.js +44 -2
- package/dist/core/subagents/official-subagent-runner.js +26 -8
- package/dist/core/subagents/triwiki-attention.js +135 -123
- package/dist/core/telegram/bot-api.js +85 -10
- package/dist/core/telegram/center-snapshot.js +718 -0
- package/dist/core/telegram/config.js +158 -31
- package/dist/core/telegram/hub.js +288 -33
- package/dist/core/telegram/index.js +2 -0
- package/dist/core/telegram/ingress-spool.js +419 -0
- package/dist/core/telegram/ledgers.js +188 -29
- package/dist/core/telegram/messages.js +26 -6
- package/dist/core/telegram/owner-lock.js +10 -7
- package/dist/core/telegram/runtime-projection.js +38 -3
- package/dist/core/telegram/runtime.js +298 -63
- package/dist/core/telegram/service.js +137 -8
- package/dist/core/telegram/setup.js +291 -73
- package/dist/core/text/strings.js +3 -0
- package/dist/core/triwiki/code-pack.js +12 -120
- package/dist/core/triwiki/context-graph/compiler/cache-key.js +277 -0
- package/dist/core/triwiki/context-graph/compiler/extract.js +104 -0
- package/dist/core/triwiki/context-graph/compiler/freshness.js +108 -0
- package/dist/core/triwiki/context-graph/compiler/index.js +237 -0
- package/dist/core/triwiki/context-graph/compiler/merge.js +0 -0
- package/dist/core/triwiki/context-graph/compiler/serialize.js +115 -0
- package/dist/core/triwiki/context-graph/contracts.js +236 -0
- package/dist/core/triwiki/context-graph/extractors/code/builders.js +150 -0
- package/dist/core/triwiki/context-graph/extractors/code/declarations.js +161 -0
- package/dist/core/triwiki/context-graph/extractors/code/index.js +265 -0
- package/dist/core/triwiki/context-graph/extractors/code/inventory.js +237 -0
- package/dist/core/triwiki/context-graph/extractors/code/module-graph.js +252 -0
- package/dist/core/triwiki/context-graph/extractors/code/modules.js +79 -0
- package/dist/core/triwiki/context-graph/extractors/code/references.js +184 -0
- package/dist/core/triwiki/context-graph/extractors/code/selection.js +100 -0
- package/dist/core/triwiki/context-graph/extractors/code/ts-config.js +161 -0
- package/dist/core/triwiki/context-graph/extractors/code/types.js +18 -0
- package/dist/core/triwiki/context-graph/extractors/evidence/claims.js +289 -0
- package/dist/core/triwiki/context-graph/extractors/evidence/index.js +54 -0
- package/dist/core/triwiki/context-graph/extractors/evidence/proof-index.js +213 -0
- package/dist/core/triwiki/context-graph/extractors/evidence/proofs.js +266 -0
- package/dist/core/triwiki/context-graph/extractors/evidence/redaction.js +177 -0
- package/dist/core/triwiki/context-graph/extractors/evidence/shared.js +0 -0
- package/dist/core/triwiki/context-graph/extractors/evidence/sources.js +154 -0
- package/dist/core/triwiki/context-graph/extractors/index.js +7 -0
- package/dist/core/triwiki/context-graph/extractors/topology/commands.js +207 -0
- package/dist/core/triwiki/context-graph/extractors/topology/gate-edges.js +201 -0
- package/dist/core/triwiki/context-graph/extractors/topology/gates.js +182 -0
- package/dist/core/triwiki/context-graph/extractors/topology/globs.js +124 -0
- package/dist/core/triwiki/context-graph/extractors/topology/index.js +92 -0
- package/dist/core/triwiki/context-graph/extractors/topology/routes.js +135 -0
- package/dist/core/triwiki/context-graph/extractors/topology/shared.js +215 -0
- package/dist/core/triwiki/context-graph/graph-index.js +143 -0
- package/dist/core/triwiki/context-graph/ids.js +0 -0
- package/dist/core/triwiki/context-graph/lint/index.js +0 -0
- package/dist/core/triwiki/context-graph/lint/rules.js +232 -0
- package/dist/core/triwiki/context-graph/lint/warnings.js +93 -0
- package/dist/core/triwiki/context-graph/paths.js +116 -0
- package/dist/core/triwiki/context-graph/profiles.js +78 -0
- package/dist/core/triwiki/context-graph/projections/anchors.js +91 -0
- package/dist/core/triwiki/context-graph/projections/attention.js +58 -0
- package/dist/core/triwiki/context-graph/projections/code-pack-workspace.js +62 -0
- package/dist/core/triwiki/context-graph/projections/code-pack.js +144 -0
- package/dist/core/triwiki/context-graph/projections/index.js +7 -0
- package/dist/core/triwiki/context-graph/projections/module-view.js +140 -0
- package/dist/core/triwiki/context-graph/projections/node-summary.js +118 -0
- package/dist/core/triwiki/context-graph/projections/pack-contract.js +6 -0
- package/dist/core/triwiki/context-graph/query/explain.js +0 -0
- package/dist/core/triwiki/context-graph/query/index.js +178 -0
- package/dist/core/triwiki/context-graph/query/load.js +116 -0
- package/dist/core/triwiki/context-graph/query/pack.js +117 -0
- package/dist/core/triwiki/context-graph/query/rank.js +142 -0
- package/dist/core/triwiki/context-graph/query/ranking-config.js +64 -0
- package/dist/core/triwiki/context-graph/query/seeds.js +241 -0
- package/dist/core/triwiki/context-graph/query/snapshot-cache.js +72 -0
- package/dist/core/triwiki/context-graph/query/traverse.js +154 -0
- package/dist/core/triwiki/context-graph/query-types.js +29 -0
- package/dist/core/triwiki/context-graph/store/compile-lock.js +21 -0
- package/dist/core/triwiki/context-graph/store/event-log.js +48 -0
- package/dist/core/triwiki/context-graph/store/fragment-cache.js +85 -0
- package/dist/core/triwiki/context-graph/store/graph-status.js +85 -0
- package/dist/core/triwiki/context-graph/store/snapshot-store.js +155 -0
- package/dist/core/triwiki/triwiki-proof-bank-index-repair.js +115 -0
- package/dist/core/triwiki/triwiki-proof-bank-index-store.js +290 -0
- package/dist/core/triwiki/triwiki-proof-bank-index.js +126 -0
- package/dist/core/triwiki/triwiki-proof-bank.js +7 -1
- package/dist/core/verification/context-graph-affected.js +271 -0
- package/dist/core/version.js +1 -1
- package/dist/native/sks-menubar/Sources/AlertFactory.swift +11 -3
- package/dist/native/sks-menubar/Sources/AppDelegate.swift +9 -0
- package/dist/native/sks-menubar/Sources/ControlCenterWindowController.swift +25 -3
- package/dist/native/sks-menubar/Sources/ControlKit.swift +19 -8
- package/dist/native/sks-menubar/Sources/DiagnosticsViewController.swift +1 -2
- package/dist/native/sks-menubar/Sources/MCPServersViewController.swift +45 -17
- package/dist/native/sks-menubar/Sources/OverviewSummary.swift +162 -0
- package/dist/native/sks-menubar/Sources/OverviewViewController.swift +136 -190
- package/dist/native/sks-menubar/Sources/ProcessClient.swift +107 -11
- package/dist/native/sks-menubar/Sources/ProvidersMultiProvider.swift +5 -1
- package/dist/native/sks-menubar/Sources/ProvidersOpenRouter.swift +16 -4
- package/dist/native/sks-menubar/Sources/ProvidersRoleModels.swift +4 -1
- package/dist/native/sks-menubar/Sources/ProvidersRoutingTruth.swift +131 -0
- package/dist/native/sks-menubar/Sources/ProvidersViewController.swift +288 -341
- package/dist/native/sks-menubar/Sources/RemoteTelegramCenterState.swift +447 -0
- package/dist/native/sks-menubar/Sources/RemoteTelegramRendering.swift +484 -0
- package/dist/native/sks-menubar/Sources/RemoteTelegramViewController.swift +364 -115
- package/dist/native/sks-menubar/Sources/SettingsViewController.swift +73 -12
- package/dist/native/sks-menubar/Sources/SidebarItem.swift +3 -3
- package/dist/native/sks-menubar/Sources/StatusItemController.swift +13 -13
- package/dist/native/sks-menubar/Sources/TelegramHubSupervisor.swift +469 -0
- package/dist/native/sks-menubar/Sources/UpdatesViewController.swift +1 -6
- package/dist/native/sks-menubar/Tests/AppRuntimeTestSupport.swift +12 -0
- package/dist/native/sks-menubar/Tests/NativeTelegramRegressionRunner.swift +55 -0
- package/dist/native/sks-menubar/Tests/ProcessClientTests.swift +33 -0
- package/dist/native/sks-menubar/Tests/ProvidersViewControllerTests.swift +142 -0
- package/dist/native/sks-menubar/Tests/RemoteTelegramCenterStateTests.swift +56 -0
- package/dist/native/sks-menubar/Tests/TelegramHubSupervisorTests.swift +55 -0
- package/dist/scripts/codex-lb-catalog-passthrough-check.js +120 -0
- package/dist/scripts/codex-lb-desktop-auth-invariant-check.js +169 -0
- package/dist/scripts/codex-lb-desktop-bridge-check.js +394 -0
- package/dist/scripts/codex-lb-desktop-bridge-latency-check.js +196 -0
- package/dist/scripts/codex-lb-desktop-capabilities-check.js +287 -0
- package/dist/scripts/codex-lb-desktop-real-evidence-check.js +123 -0
- package/dist/scripts/codex-lb-fast-mode-truth-check.js +10 -3
- package/dist/scripts/codex-lb-fast-ui-preservation-check.js +81 -40
- package/dist/scripts/codex-lb-gpt56-fast-profile-check.js +99 -37
- package/dist/scripts/context-graph-check.js +191 -0
- package/dist/scripts/doctor-fixes-codex-app-fast-ui-check.js +1 -1
- package/dist/scripts/gate-policy-audit-check.js +1 -1
- package/dist/scripts/helper-dedup-check.js +0 -2
- package/dist/scripts/installed-package-smoke-check.js +4 -1
- package/dist/scripts/latest-version-guidance-check.js +74 -0
- package/dist/scripts/release-metadata-check.js +21 -4
- package/dist/scripts/release-real-check.js +7 -0
- package/dist/scripts/ux-review-imagegen-blackbox-check.js +25 -1
- package/dist/scripts/ux-review-run-wires-imagegen-check.js +9 -1
- package/package.json +8 -3
- package/release-gates.v2.json +176 -1
- package/runtime-required-scripts.json +30 -0
- package/schemas/triwiki/context-graph.schema.json +119 -0
- package/dist/cli/install-helpers-codex-lb-selftest-chain.js +0 -112
- package/dist/cli/install-helpers-codex-lb-selftest.js +0 -481
- package/dist/core/triwiki/code-index-scanner.js +0 -309
|
@@ -6,13 +6,19 @@ export const CODEX_LB_IMAGEGEN_TARGET_SCHEMA = 'sks.codex-lb-imagegen-target.v1'
|
|
|
6
6
|
export async function resolveCodexLbImagegenTarget(opts = {}) {
|
|
7
7
|
const env = opts.env || process.env;
|
|
8
8
|
const home = opts.home || env.HOME || os.homedir();
|
|
9
|
+
const codexHome = opts.codexHome || env.CODEX_HOME || path.join(home, '.codex');
|
|
9
10
|
const configText = typeof opts.configText === 'string'
|
|
10
11
|
? opts.configText
|
|
11
|
-
: await readText(path.join(
|
|
12
|
+
: await readText(path.join(codexHome, 'config.toml'), '').catch(() => '');
|
|
12
13
|
const selected = topLevelTomlString(configText, 'model_provider') === 'codex-lb';
|
|
13
|
-
const loaded = await loadCodexLbEnv({
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
const loaded = await loadCodexLbEnv({
|
|
15
|
+
home,
|
|
16
|
+
processEnv: {},
|
|
17
|
+
envPath: path.join(codexHome, 'sks-codex-lb.env'),
|
|
18
|
+
metadataPath: path.join(codexHome, 'sks-codex-lb.json')
|
|
19
|
+
}).catch(() => null);
|
|
20
|
+
const catalogModels = await readCatalogModels(configText, home, codexHome);
|
|
21
|
+
const explicit = String(opts.explicitModel || env.SKS_IMAGEGEN_RESPONSES_MODEL || '').trim();
|
|
16
22
|
const configuredModel = topLevelTomlString(configText, 'model');
|
|
17
23
|
const { model, model_source } = explicit
|
|
18
24
|
? { model: explicit, model_source: 'explicit' }
|
|
@@ -46,16 +52,17 @@ function codexLbImagegenBlocker(state) {
|
|
|
46
52
|
return 'codex_lb_imagegen_model_unresolved';
|
|
47
53
|
return null;
|
|
48
54
|
}
|
|
49
|
-
async function readCatalogModels(configText, home) {
|
|
55
|
+
async function readCatalogModels(configText, home, codexHome) {
|
|
50
56
|
const configured = topLevelTomlString(configText, 'model_catalog_json');
|
|
51
57
|
const candidates = [
|
|
52
|
-
configured ?
|
|
53
|
-
path.join(
|
|
58
|
+
configured ? resolveCatalogPath(configured, home, codexHome) : '',
|
|
59
|
+
path.join(codexHome, 'sks-codex-lb-tool-catalog.json')
|
|
54
60
|
].filter(Boolean);
|
|
55
61
|
for (const file of candidates) {
|
|
56
62
|
const payload = await readJson(file, null).catch(() => null);
|
|
57
63
|
const rows = Array.isArray(payload?.models) ? payload.models : Array.isArray(payload?.data) ? payload.data : [];
|
|
58
64
|
const slugs = rows
|
|
65
|
+
.filter((row) => row?.supported_in_api !== false && !hiddenCatalogRow(row))
|
|
59
66
|
.map((row) => String(row?.slug || row?.id || row?.model || '').trim())
|
|
60
67
|
.filter(Boolean);
|
|
61
68
|
if (slugs.length)
|
|
@@ -63,6 +70,13 @@ async function readCatalogModels(configText, home) {
|
|
|
63
70
|
}
|
|
64
71
|
return [];
|
|
65
72
|
}
|
|
73
|
+
function resolveCatalogPath(configured, home, codexHome) {
|
|
74
|
+
const expanded = configured.replace(/^~(?=\/|$)/, home);
|
|
75
|
+
return path.isAbsolute(expanded) ? expanded : path.resolve(codexHome, expanded);
|
|
76
|
+
}
|
|
77
|
+
function hiddenCatalogRow(row) {
|
|
78
|
+
return ['hide', 'hidden', 'internal', 'none', 'unavailable'].includes(String(row?.visibility || '').trim().toLowerCase());
|
|
79
|
+
}
|
|
66
80
|
function topLevelTomlString(text, key) {
|
|
67
81
|
const topLevel = String(text || '').split(/\n\s*\[/)[0] || '';
|
|
68
82
|
const re = new RegExp(`(^|\\n)\\s*${key.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\s*=\\s*"([^"]*)"\\s*(?:#.*)?(?=\\n|$)`);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import os from 'node:os';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import {
|
|
3
|
+
import { loadCodexLbEnv, parseShellEnvValue } from '../codex-lb/codex-lb-env.js';
|
|
4
4
|
import { nowIso, readText, runProcess, which } from '../fsx.js';
|
|
5
5
|
import { redactSecrets, redactString } from '../secret-redaction.js';
|
|
6
6
|
import { evaluateImagegenAuthReadiness } from './imagegen-auth-readiness.js';
|
|
@@ -97,7 +97,8 @@ export async function detectImagegenCapability(opts = {}) {
|
|
|
97
97
|
}
|
|
98
98
|
async function detectCodexLbImagegenAuth(opts = {}, env = process.env) {
|
|
99
99
|
const home = opts.home || env.HOME || process.env.HOME || os.homedir();
|
|
100
|
-
const
|
|
100
|
+
const codexHome = opts.codexHome || env.CODEX_HOME || path.join(home, '.codex');
|
|
101
|
+
const configPath = opts.configPath || path.join(codexHome, 'config.toml');
|
|
101
102
|
const configText = typeof opts.configText === 'string'
|
|
102
103
|
? opts.configText
|
|
103
104
|
: await readText(configPath, '').catch(() => '');
|
|
@@ -107,11 +108,16 @@ async function detectCodexLbImagegenAuth(opts = {}, env = process.env) {
|
|
|
107
108
|
const requiresOpenAiAuth = tomlBoolean(block, 'requires_openai_auth');
|
|
108
109
|
const envKey = tomlString(block, 'env_key');
|
|
109
110
|
const baseUrl = tomlString(block, 'base_url') || String(env.CODEX_LB_BASE_URL || '').trim();
|
|
110
|
-
const envPath = opts.codexLbEnvPath ||
|
|
111
|
+
const envPath = opts.codexLbEnvPath || path.join(codexHome, 'sks-codex-lb.env');
|
|
111
112
|
const injectedEnvText = typeof opts.codexLbEnvText === 'string' ? opts.codexLbEnvText : null;
|
|
112
113
|
const keyFromInjectedFile = injectedEnvText !== null && envKey ? parseShellEnvValue(injectedEnvText, envKey) : '';
|
|
113
114
|
const loaded = injectedEnvText === null
|
|
114
|
-
? await loadCodexLbEnv({
|
|
115
|
+
? await loadCodexLbEnv({
|
|
116
|
+
home,
|
|
117
|
+
processEnv: {},
|
|
118
|
+
envPath,
|
|
119
|
+
metadataPath: path.join(codexHome, 'sks-codex-lb.json')
|
|
120
|
+
}).catch(() => null)
|
|
115
121
|
: null;
|
|
116
122
|
const apiKeyPresent = Boolean(opts.codexLbApiKey || keyFromInjectedFile || loaded?.secret_api_key);
|
|
117
123
|
const apiKeySource = opts.codexLbApiKey
|
|
@@ -1,15 +1,27 @@
|
|
|
1
1
|
import { detectImagegenCapability } from './imagegen-capability.js';
|
|
2
2
|
import { repairCodexImagegen } from '../doctor/imagegen-repair.js';
|
|
3
3
|
export async function requireCodexImagegen(root, opts = {}) {
|
|
4
|
-
const
|
|
5
|
-
codexBin: opts.codexBin || undefined,
|
|
4
|
+
const capabilityOpts = {
|
|
6
5
|
timeoutMs: opts.timeoutMs || 5000
|
|
7
|
-
}
|
|
6
|
+
};
|
|
7
|
+
if (opts.codexBin !== undefined && opts.codexBin !== null)
|
|
8
|
+
capabilityOpts.codexBin = opts.codexBin;
|
|
9
|
+
if (opts.home !== undefined)
|
|
10
|
+
capabilityOpts.home = opts.home;
|
|
11
|
+
if (opts.codexHome !== undefined)
|
|
12
|
+
capabilityOpts.codexHome = opts.codexHome;
|
|
13
|
+
if (opts.env !== undefined)
|
|
14
|
+
capabilityOpts.env = opts.env;
|
|
15
|
+
if (opts.configText !== undefined)
|
|
16
|
+
capabilityOpts.configText = opts.configText;
|
|
17
|
+
if (opts.codexLbEnvText !== undefined)
|
|
18
|
+
capabilityOpts.codexLbEnvText = opts.codexLbEnvText;
|
|
19
|
+
const capability = await detectImagegenCapability(capabilityOpts).catch((err) => ({
|
|
8
20
|
ok: false,
|
|
9
21
|
core_ready: false,
|
|
10
22
|
blockers: [err instanceof Error ? err.message : String(err)]
|
|
11
23
|
}));
|
|
12
|
-
const capabilityReadyBeforeRepair = capability
|
|
24
|
+
const capabilityReadyBeforeRepair = imagegenPreflightReady(capability);
|
|
13
25
|
const repair = opts.autoRepair === true && !capabilityReadyBeforeRepair
|
|
14
26
|
? await repairCodexImagegen({
|
|
15
27
|
root,
|
|
@@ -25,7 +37,10 @@ export async function requireCodexImagegen(root, opts = {}) {
|
|
|
25
37
|
const finalCapability = repair
|
|
26
38
|
? repair.after || capability
|
|
27
39
|
: capability;
|
|
28
|
-
const capabilityReady = finalCapability
|
|
40
|
+
const capabilityReady = imagegenPreflightReady(finalCapability) || repair?.capability_ready === true;
|
|
41
|
+
const preflightProvider = finalCapability.core_ready === true
|
|
42
|
+
? 'codex_app_builtin'
|
|
43
|
+
: codexLbImagegenReady(finalCapability) ? 'codex_lb' : null;
|
|
29
44
|
const currentTaskToolManifestVerified = repair?.current_task_tool_manifest_verified === true;
|
|
30
45
|
const generatedOutputVerified = finalCapability.real_output_verified_by_capability_check === true
|
|
31
46
|
|| repair?.real_generation_verified === true;
|
|
@@ -55,6 +70,7 @@ export async function requireCodexImagegen(root, opts = {}) {
|
|
|
55
70
|
preflight_ready: preflightReady,
|
|
56
71
|
preflight_only: true,
|
|
57
72
|
preflight_does_not_satisfy_generated_output_proof: true,
|
|
73
|
+
preflight_provider: preflightProvider,
|
|
58
74
|
capability_ready: capabilityReady,
|
|
59
75
|
route_ready: routeReady,
|
|
60
76
|
current_task_tool_manifest_verified: currentTaskToolManifestVerified,
|
|
@@ -80,3 +96,11 @@ export async function requireCodexImagegen(root, opts = {}) {
|
|
|
80
96
|
blockers
|
|
81
97
|
};
|
|
82
98
|
}
|
|
99
|
+
function imagegenPreflightReady(capability) {
|
|
100
|
+
return capability?.core_ready === true || codexLbImagegenReady(capability);
|
|
101
|
+
}
|
|
102
|
+
function codexLbImagegenReady(capability) {
|
|
103
|
+
return capability?.codex_lb?.selected === true
|
|
104
|
+
&& capability?.codex_lb?.available === true
|
|
105
|
+
&& capability?.codex_lb?.blocker == null;
|
|
106
|
+
}
|
package/dist/core/init/skills.js
CHANGED
|
@@ -12,7 +12,7 @@ import { reconcileRetiredAgentRoleResidue } from '../agents/agent-role-config.js
|
|
|
12
12
|
import { ensureConfinedDirectory, inspectConfinedPath, moveConfinedPath, publicPathError, removeConfinedDirectoryIfEmpty, removeManagedPathVerified, uniqueConfinedPath } from '../managed-path-safety.js';
|
|
13
13
|
import { collectNestedProjectRoots } from '../doctor/current-project-guidance-nested.js';
|
|
14
14
|
import { coreEngineeringDirectiveReferenceText, engineeringSanityPolicyText } from '../lean-engineering-policy.js';
|
|
15
|
-
import { AWESOME_DESIGN_MD_REFERENCE, CODEX_APP_IMAGE_GENERATION_DOC_URL, CODEX_COMPUTER_USE_ONLY_POLICY, CODEX_IMAGEGEN_EVIDENCE_SOURCE, CODEX_IMAGEGEN_REQUIRED_POLICY, CODEX_WEB_VERIFICATION_POLICY, DEFAULT_CODEX_APP_PLUGINS, DESIGN_SYSTEM_SSOT, DOLLAR_COMMANDS, DOLLAR_SKILL_NAMES, FROM_CHAT_IMG_CHECKLIST_ARTIFACT, FROM_CHAT_IMG_COVERAGE_ARTIFACT, FROM_CHAT_IMG_QA_LOOP_ARTIFACT, FROM_CHAT_IMG_TEMP_TRIWIKI_ARTIFACT, FROM_CHAT_IMG_TEMP_TRIWIKI_SESSIONS, GETDESIGN_REFERENCE, IMAGEGEN_SOCIAL_SOURCE_POLICY, LEGACY_DOLLAR_SKILL_NAMES, OPENAI_CHATGPT_IMAGES_2_DOC_URL, OPENAI_GPT_IMAGE_2_MODEL_DOC_URL, OPENAI_IMAGE_GENERATION_DOC_URL, PPT_CONDITIONAL_SKILL_ALLOWLIST, PPT_PIPELINE_MCP_ALLOWLIST, PPT_PIPELINE_SKILL_ALLOWLIST, RECOMMENDED_SKILLS, RESERVED_CODEX_PLUGIN_SKILL_NAMES, SOLUTION_SCOUT_SKILL_NAME, chatCaptureIntakeText, context7ConfigToml, getdesignReferencePolicyText,
|
|
15
|
+
import { AWESOME_DESIGN_MD_REFERENCE, CODEX_APP_IMAGE_GENERATION_DOC_URL, CODEX_COMPUTER_USE_ONLY_POLICY, CODEX_IMAGEGEN_EVIDENCE_SOURCE, CODEX_IMAGEGEN_REQUIRED_POLICY, CODEX_WEB_VERIFICATION_POLICY, DEFAULT_CODEX_APP_PLUGINS, DESIGN_SYSTEM_SSOT, DOLLAR_COMMANDS, DOLLAR_SKILL_NAMES, FROM_CHAT_IMG_CHECKLIST_ARTIFACT, FROM_CHAT_IMG_COVERAGE_ARTIFACT, FROM_CHAT_IMG_QA_LOOP_ARTIFACT, FROM_CHAT_IMG_TEMP_TRIWIKI_ARTIFACT, FROM_CHAT_IMG_TEMP_TRIWIKI_SESSIONS, GETDESIGN_REFERENCE, IMAGEGEN_SOCIAL_SOURCE_POLICY, LEGACY_DOLLAR_SKILL_NAMES, OPENAI_CHATGPT_IMAGES_2_DOC_URL, OPENAI_GPT_IMAGE_2_MODEL_DOC_URL, OPENAI_IMAGE_GENERATION_DOC_URL, PPT_CONDITIONAL_SKILL_ALLOWLIST, PPT_PIPELINE_MCP_ALLOWLIST, PPT_PIPELINE_SKILL_ALLOWLIST, RECOMMENDED_SKILLS, RESERVED_CODEX_PLUGIN_SKILL_NAMES, SOLUTION_SCOUT_SKILL_NAME, chatCaptureIntakeText, context7ConfigToml, getdesignReferencePolicyText, outcomeRubricPolicyText, pptPipelineAllowlistPolicyText, productDesignPluginPolicyText, speedLanePolicyText, stackCurrentDocsPolicyText, triwikiContextTrackingText, triwikiStagePolicyText } from '../routes.js';
|
|
16
16
|
import { prefixKnownSksDollarReferences, sksPrefixedSkillName } from '../routes/dollar-prefix.js';
|
|
17
17
|
import { escapeRegExp } from '../text/regex.js';
|
|
18
18
|
const SKS_SKILL_MANIFEST_FILE = '.sks-generated.json';
|
|
@@ -21,6 +21,12 @@ const GENERATED_PRUNE_POLICY = 'remove_previous_sks_generated_paths_absent_from_
|
|
|
21
21
|
const REFLECTION_MEMORY_PATH = '.sneakoscope/memory/q2_facts/post-route-reflection.md';
|
|
22
22
|
const MANAGED_SKILL_MARKER_RE = /BEGIN SKS (?:IMMUTABLE CORE|MANAGED) SKILL/;
|
|
23
23
|
const FORGE_SKILL_MARKER_RE = /BEGIN SKS FORGE SKILL/;
|
|
24
|
+
const RETIRED_PUBLIC_IMAGE_UX_REVIEW_SKILL_ALIASES = [
|
|
25
|
+
'sks-ux-review',
|
|
26
|
+
'sks-visual-review',
|
|
27
|
+
'sks-ui-ux-review'
|
|
28
|
+
];
|
|
29
|
+
const RETIRED_PUBLIC_IMAGE_UX_REVIEW_SKILL_ALIAS_SET = new Set(RETIRED_PUBLIC_IMAGE_UX_REVIEW_SKILL_ALIASES);
|
|
24
30
|
export const REMOVED_SKS_SKILL_NAMES = [
|
|
25
31
|
'old-workflow',
|
|
26
32
|
'team-legacy',
|
|
@@ -85,7 +91,6 @@ function reflectionInstructionText(commandPrefix = 'sks') {
|
|
|
85
91
|
async function installOfficialSkills(root) {
|
|
86
92
|
const quarantinedUserCollisions = [];
|
|
87
93
|
const quarantinedManifestCollisions = await prepareReservedSkillManifestsForWrite(root);
|
|
88
|
-
const imageUxReviewSkill = (name) => `---\nname: ${name}\ndescription: $Image-UX-Review/$UX-Review imagegen/gpt-image-2 annotated UI/UX review loop.\n---\n\nUse only for $Image-UX-Review, $UX-Review, $visual-review, or $ui-ux-review UI/UX review requests. ${imageUxReviewPipelinePolicyText()} Route start must check Codex App imagegen capability and run the SKS imagegen repair loop once; if $imagegen/gpt-image-2 is still unavailable, stop with codex_imagegen_unavailable instead of doing text-only review or direct API substitution. Core loop: capture or attach source UI screenshots, then invoke Codex App $imagegen with gpt-image-2 to create a new generated annotated review image from each source screenshot, then analyze the generated review image with vision/OCR into image-ux-issue-ledger.json, then apply only requested safe fixes and recheck changed screens. Text-only screenshot critique cannot satisfy full verification; missing generated annotated review images keep full image-ux-review-gate.json verification blocked, but may close verified_partial/reference-only when source screenshots plus hashes, docs evidence, source Image Voxel anchors, and Honest Mode evidence exist. For live web/browser/webapp capture use Codex Chrome Extension first and halt if it is not installed/enabled; use Codex Computer Use only for native Mac/non-web app screens. Required artifacts: image-ux-review-policy.json, image-ux-screen-inventory.json, image-ux-generated-review-ledger.json, image-ux-issue-ledger.json, image-ux-iteration-report.json, image-ux-review-gate.json. Finish with reflection and Honest Mode.\n`;
|
|
89
94
|
const canonicalMadSksSqlPlanePolicy = madSksSqlPlanePolicyText()
|
|
90
95
|
.replace(/^---[\s\S]*?---\s*/, '')
|
|
91
96
|
.trim();
|
|
@@ -96,8 +101,8 @@ async function installOfficialSkills(root) {
|
|
|
96
101
|
'plan': `---\nname: plan\ndescription: Plan scaffold only - writes a fixed-template .sneakoscope/plans/<slug>.md, never touches code. Not project-specific decision-complete planning. 예: $Plan "결제 모듈 리팩터"\n---\n\nUse when the user invokes $Plan or asks for a plan-only frontdoor. Produce a concrete plan artifact under .sneakoscope/plans/<slug>.md with goal, scope, files to inspect, implementation steps, acceptance checks, and rollback notes. Do not edit product/source files, generated harness files, package metadata, or docs beyond the plan artifact. Keep implementation_allowed=false and hand off execution to $Work only after the user or route explicitly moves from planning to work. Finish with what is planned, what remains unimplemented, and Honest Mode.\n`,
|
|
97
102
|
'work': `---\nname: work\ndescription: Execute the latest plan with evidence-gated completion. 예: $Work\n---\n\nUse when the user invokes $Work or asks to execute the latest SKS plan. Resolve the newest .sneakoscope/plans/*.md, route execution through Naruto evidence gates, keep leases and verification artifacts current, and do not claim completion without machine evidence or explicit blocker evidence. If no plan exists, block with a clear next action: run $Plan first or provide a task.\n`,
|
|
98
103
|
'review': `---\nname: review\ndescription: Parallel diff review with machine-evidence first findings. 예: $Review 또는 sks review --staged\n---\n\nUse when the user asks for $Review or sks review. Review the selected diff read-only unless --fix is explicitly supplied. Machine evidence such as TypeScript, lint, tests, conflict markers, or secret scans outranks LLM findings and must be tagged evidence: machine; judgment-only findings must be tagged evidence: llm. --fix may attempt at most one machine-evidence fix pass and must re-run verification once. Do not mutate code for LLM-only opinions.\n`,
|
|
99
|
-
'fast-mode': `---\nname: fast-mode\ndescription: Dollar-command route for $Fast-Mode, $Fast-On, and $Fast-Off global Codex Desktop Fast mode toggles.\n---\n\nUse when the user invokes $Fast-Mode, $Fast-On, $Fast-Off, or asks to turn SKS Fast mode on/off. Prefer \`sks fast-mode on|off|status|clear --json\`. By default on/off updates the global Codex Desktop config so GPT
|
|
100
|
-
'fast-on': `---\nname: fast-on\ndescription: Alias for $Fast-On global Codex Desktop GPT
|
|
104
|
+
'fast-mode': `---\nname: fast-mode\ndescription: Dollar-command route for $Fast-Mode, $Fast-On, and $Fast-Off global Codex Desktop Fast mode toggles.\n---\n\nUse when the user invokes $Fast-Mode, $Fast-On, $Fast-Off, or asks to turn SKS Fast mode on/off. Prefer \`sks fast-mode on|off|status|clear --json\`. By default on/off updates the global Codex Desktop config so GPT-5.6 Fast (official service_tier) persists and also keeps .sneakoscope/state/fast-mode.json in sync for SKS workers. Use \`--project\` only when the user explicitly wants project-local worker preference without touching global Codex config. Explicit runtime flags still win: \`--fast\`, \`--no-fast\`, and \`--service-tier standard|fast\` override the saved preference for that run. Finish with a short status and Honest Mode; do not start Naruto or broad implementation for a toggle-only request.\n`,
|
|
105
|
+
'fast-on': `---\nname: fast-on\ndescription: Alias for $Fast-On global Codex Desktop GPT-5.6 Fast enablement.\n---\n\nUse the same rules as fast-mode. Run or instruct \`sks fast-mode on --json\`, then report Global (desktop), Project (sks workers), state file, and the fact that explicit per-run flags still override the saved preference.\n`,
|
|
101
106
|
'fast-off': `---\nname: fast-off\ndescription: Alias for $Fast-Off global Codex Desktop Fast mode disablement.\n---\n\nUse the same rules as fast-mode. Run or instruct \`sks fast-mode off --json\`, then report Global (desktop), Project (sks workers), state file, and the fact that explicit per-run flags still override the saved preference.\n`,
|
|
102
107
|
'with-local-llm-on': `---\nname: with-local-llm-on\ndescription: Dollar-command route for $with-local-llm-on local Ollama worker enablement.\n---\n\nUse when the user invokes $with-local-llm-on or asks to enable the optional local Ollama worker backend. Prefer \`sks with-local-llm on --json\`. The command writes the machine-local config at \`~/.sneakoscope/local-model.json\`. Default off means SKS stays GPT-only until this command enables local workers. Enabled mode only lets policy-eligible simple code patch-envelope or read-only collection worker slices use Ollama; GPT/Codex still owns strategy, planning, design, review, verification, safety, and integration. \`--no-ollama\` and \`SKS_OLLAMA_WORKERS=0\` still force local workers off for a run. Finish with a short status and Honest Mode; do not start Naruto for a toggle-only request.\n`,
|
|
103
108
|
'with-local-llm-off': `---\nname: with-local-llm-off\ndescription: Dollar-command route for $with-local-llm-off local Ollama worker disablement.\n---\n\nUse when the user invokes $with-local-llm-off or asks to disable the optional local Ollama worker backend. Prefer \`sks with-local-llm off --json\`. The command writes the machine-local config at \`~/.sneakoscope/local-model.json\`. Disabled mode keeps SKS GPT-only by default. Strategy, planning, design, review, verification, safety, and integration remain GPT/Codex-owned regardless of this toggle. Finish with a short status and Honest Mode; do not start Naruto for a toggle-only request.\n`,
|
|
@@ -119,7 +124,7 @@ async function installOfficialSkills(root) {
|
|
|
119
124
|
'help': `---\nname: help\ndescription: Dollar-command route for $Help or $help explaining installed SKS commands and workflows.\n---\n\nUse when the user invokes $Help/$help or asks what commands exist. Prefer concise output from sks commands, sks usage <topic>, sks quickstart, sks aliases, and sks codex-app.\n`,
|
|
120
125
|
'prompt-pipeline': `---\nname: prompt-pipeline\ndescription: Default SKS prompt routing for execution requests; Answer and DFix remain lightweight.\n---\n\nClassify only the route and the constraints that change execution. Answer handles real information requests; DFix handles tiny copy/config/docs/labels/spacing/translation/mechanical edits; general code-changing work uses Naruto with Codex official subagents. Preserve the literal user request; TriWiki may enrich it but never replace an explicit requirement. ${coreEngineeringDirectiveReferenceText()} ${engineeringSanityPolicyText()} For code work, identify the requested outcome, actual code/data flow, exact write scope, acceptance criteria, and the smallest meaningful verification. Load route-specific Design, PPT, image, browser, research, DB, release, or Context7 rules only when that route or external contract requires them. Materialize pipeline-plan.json with route, scopes, verification, and blockers, then finish the requested work instead of stopping at the plan.\n`,
|
|
121
126
|
[SOLUTION_SCOUT_SKILL_NAME]: `---\nname: ${SOLUTION_SCOUT_SKILL_NAME}\ndescription: Optional source scout for fixes that materially depend on external precedent.\n---\n\nUse only when the user asks for similar cases or when a package, API, platform, or externally documented behavior makes outside precedent materially useful. Search with the concrete symptom and current stack, prefer primary sources, and keep the local code path authoritative. Do not add this step to ordinary local bugfixes. If external evidence is unavailable, record that gap instead of inventing a workaround.\n`,
|
|
122
|
-
'reasoning-router': `---\nname: reasoning-router\ndescription: Temporary SKS reasoning-effort routing for every command and pipeline route.\n---\n\
|
|
127
|
+
'reasoning-router': `---\nname: reasoning-router\ndescription: Temporary SKS reasoning-effort routing for every command and pipeline route on the GPT-5.6 family.\n---\n\nGPT-5.6 efforts: none/low/medium/high/xhigh/max. Route medium for simple copy/color/discovery/setup/mechanical edits; high for logic, safety, architecture, DB, orchestration, refactor, multi-file work; xhigh for research, AutoResearch, falsification, benchmarks, SEO/GEO, open-ended discovery, and From-Chat-IMG analysis; max only for hardest quality-first judgment. Prefer gpt-5.6-luna / terra / sol role defaults over legacy model aliases. Routing is temporary; return to default after the gate. Inspect with sks reasoning and sks pipeline status.\n`,
|
|
123
128
|
'pipeline-runner': `---\nname: pipeline-runner\ndescription: Execute SKS routes with bounded state, evidence, reflection, and Honest Mode.\n---\n\nEvery $ command selects a route. Use current.json, mission artifacts, and pipeline-plan.json as bounded execution state; load only the selected route skill. ${coreEngineeringDirectiveReferenceText()} ${engineeringSanityPolicyText()} Codex native /goal is the only persisted goal owner. Use official Codex subagents only when the route requires independent slices, keep parent-owned integration, use bounded TriWiki context, fetch current external docs only when relevant, record real blockers, refresh and validate evidence, run reflection for full routes, and finish with a completion summary plus Honest Mode.\n`,
|
|
124
129
|
'context7-docs': `---\nname: context7-docs\ndescription: Enforce Context7 MCP documentation evidence for SKS routes that depend on external libraries, frameworks, APIs, MCPs, package managers, DB SDKs, or generated docs.\n---\n\nWhen required, resolve-library-id, then query-docs for the resolved id. Legacy get-library-docs evidence is accepted. Prefer sks context7 tools/resolve/docs/evidence and finish only after both evidence stages exist. Check setup with sks context7 check.\n`,
|
|
125
130
|
'super-search': `---\nname: super-search\ndescription: Dollar-command route for $Super-Search provider-independent source intelligence.\n---\n\nUse when the user invokes $Super-Search or asks for Super-Search source intelligence, source acquisition, X-search-style collection, URL acquisition, source normalization, claim ledgers, or citation proof. Prefer \`sks super-search doctor --json\` for readiness and \`sks super-search run "<query>" --mode balanced --json\` for provider-independent source proof; use \`sks super-search x "<query>" --json\` for X-search intent and \`sks super-search fetch "<url>" --json\` for URL acquisition. Context7 is required only when the query depends on current package/API/framework/MCP/generated documentation behavior. Provider-specific credentials are optional and must not be required for route readiness. Evidence/artifacts remain under \`.sneakoscope/missions/<super-search-* or route mission>/super-search/\`: intent.json, axes.json, query-variants.json, provider-plan.json, source-ledger.json, lead-ledger.json, claim-ledger.json, attempt-ledger.json, synthesis.md, super-search-proof.json, super-search-gate.json, and super-search-result.json. Do not turn weak discovery into supported claims; finish with an Honest Mode summary of verified sources, blockers, and unverified external coverage.\n`,
|
|
@@ -136,10 +141,6 @@ async function installOfficialSkills(root) {
|
|
|
136
141
|
'gx-visual-validate': `---\nname: gx-visual-validate\ndescription: Validate render metadata against vgraph.json and beta.json.\n---\n\nRun sks gx validate and drift; fail stale or incomplete hashes, nodes, edges, invariants, or anchors.\n`,
|
|
137
142
|
'turbo-context-pack': `---\nname: turbo-context-pack\ndescription: Build ultra-low-token context packet with Q4 bits, Q3 tags, top-K claims, and minimal evidence.\n---\n\nDefault to Q4/Q3 plus TriWiki RGBA anchors and attention.use_first. Add Q2/Q1 only when needed or when attention.hydrate_first says source hydration is required. Keep id, hash, path, and coordinate tuple for hydration.\n`,
|
|
138
143
|
'performance-evaluator': `---\nname: performance-evaluator\ndescription: Evaluate SKS performance, evidence-backed token usage, serialized-size proxies, accuracy-proxy, context-compression, or workflow improvements.\n---\n\nUse sks eval run/compare before claims. Treat serialized_size_bytes as a deterministic non-token proxy. Claim token savings only when actual baseline and candidate token counts include an evidence source; otherwise report token savings as not measured. Report accuracy_delta/proxy, required_recall, support, and meaningful_improvement without substituting proxy size for token evidence.\n`,
|
|
139
|
-
'image-ux-review': imageUxReviewSkill('image-ux-review'),
|
|
140
|
-
'ux-review': imageUxReviewSkill('ux-review'),
|
|
141
|
-
'visual-review': imageUxReviewSkill('visual-review'),
|
|
142
|
-
'ui-ux-review': imageUxReviewSkill('ui-ux-review'),
|
|
143
144
|
'imagegen': `---\nname: imagegen\ndescription: Required bridge to Codex App built-in image generation for logos, image assets, raster visuals, and image edits.\n---\n\nUse for generated or edited image assets: logo, product image, illustration, sprite, mockup, texture, cutout, or bitmap. Prefer the official Codex App built-in image generation feature documented at ${CODEX_APP_IMAGE_GENERATION_DOC_URL}: ask naturally or invoke \`$imagegen\`. SKS route code checks capability before image-dependent routes, attempts doctor imagegen repair once, and reports codex_imagegen_unavailable if Codex App $imagegen still is not ready. For newest-model requests, make the prompt explicit: "Use ChatGPT Images 2.0 / GPT Image 2.0 with gpt-image-2." Useful official references are ${OPENAI_CHATGPT_IMAGES_2_DOC_URL}, ${OPENAI_GPT_IMAGE_2_MODEL_DOC_URL}, and ${OPENAI_IMAGE_GENERATION_DOC_URL}. Codex App image generation counts against Codex usage limits. Capability detection is not output proof; full SKS evidence requires a real selected raster output path or generated review image artifact. Direct OpenAI API fallback is non-Codex evidence and does not satisfy SKS route evidence unless a separate non-Codex API task is explicitly requested. ${IMAGEGEN_SOCIAL_SOURCE_POLICY} ${CODEX_IMAGEGEN_REQUIRED_POLICY} Do not substitute placeholder SVG/HTML/CSS for requested raster assets; follow design.md when relevant.\n`,
|
|
144
145
|
'imagegen-source-scout': `---\nname: imagegen-source-scout\ndescription: Source scout for current GPT Image 2.0/gpt-image-2 prompt guidance, official docs, and X/social workflow signals.\n---\n\nUse when the user asks for the latest imagegen docs, ChatGPT Images 2.0 / GPT Image 2.0 / gpt-image-2 behavior, X/social reactions, prompt examples, or community workflow hints before creating an image prompt or SKS imagegen policy. Source order: official OpenAI announcement (${OPENAI_CHATGPT_IMAGES_2_DOC_URL}), Codex App image generation docs (${CODEX_APP_IMAGE_GENERATION_DOC_URL}), gpt-image-2 model docs (${OPENAI_GPT_IMAGE_2_MODEL_DOC_URL}), OpenAI Image Generation API docs (${OPENAI_IMAGE_GENERATION_DOC_URL}), then public X/social/community search for prompt-quality heuristics only. ${IMAGEGEN_SOCIAL_SOURCE_POLICY} If social or web search is unavailable, record that social coverage is unverified and continue from official docs. Output a compact evidence split: official capability/evidence rules, prompt heuristics, social/workflow signals, and blockers. Do not generate images itself; pair this with the imagegen skill for actual raster output.\n`,
|
|
145
146
|
'getdesign-reference': `---\nname: getdesign-reference\ndescription: Use getdesign.md official design reference as an input to the design.md SSOT for UI/UX, presentation, and HTML/PDF systems.\n---\n\nUse when creating or improving design.md, UI/UX design systems, deck-like HTML artifacts, presentation PDFs, or brand-inspired visual systems. design.md is the only design decision SSOT; reference ${GETDESIGN_REFERENCE.url}, ${GETDESIGN_REFERENCE.docs_url}, and ${AWESOME_DESIGN_MD_REFERENCE.url} only as source inputs to synthesize or update that SSOT or a route-local style-token artifact. Prefer the official Codex skill if available with \`${GETDESIGN_REFERENCE.codex_skill_install}\`. If the skill CLI is unavailable, use this generated skill plus official docs/API/CLI/SDK references and curated DESIGN.md examples as inputs. Do not claim getdesign MCP is configured unless a current official MCP surface is actually installed.\n`,
|
|
@@ -907,7 +908,9 @@ function buildFallbackSkillsManifest() {
|
|
|
907
908
|
...RECOMMENDED_SKILLS.map((name) => canonicalSkillNameFromValue(name)),
|
|
908
909
|
...DOLLAR_COMMANDS.map((command) => canonicalSkillNameFromValue(String(command.command || '').replace(/^\$/, ''))),
|
|
909
910
|
...buildSksCoreSkillManifest().skills.map((skill) => skill.canonical_name)
|
|
910
|
-
].filter((name) => Boolean(name)
|
|
911
|
+
].filter((name) => Boolean(name)
|
|
912
|
+
&& !REMOVED_SKS_SKILL_NAME_SET.has(String(name))
|
|
913
|
+
&& !RETIRED_PUBLIC_IMAGE_UX_REVIEW_SKILL_ALIAS_SET.has(String(name))));
|
|
911
914
|
return {
|
|
912
915
|
schema: PACKAGED_SKILLS_MANIFEST_SCHEMA,
|
|
913
916
|
package_version: PACKAGE_VERSION,
|
|
@@ -1161,7 +1164,7 @@ function isGeneratedSksPluginCollisionSkill(text, name) {
|
|
|
1161
1164
|
return /Maximum-speed \$Computer-Use\/\$CU lane|Codex App pipeline activation:|Sneakoscope generated|Dollar-command route generated by SKS/i.test(s);
|
|
1162
1165
|
}
|
|
1163
1166
|
function enrichSkillContent(name, content) {
|
|
1164
|
-
if (!['sks', 'answer', 'wiki', 'qa-loop', 'ppt', 'image-ux-review', '
|
|
1167
|
+
if (!['sks', 'answer', 'wiki', 'qa-loop', 'ppt', 'image-ux-review', 'computer-use-fast', 'cu', 'goal', 'research', 'autoresearch', 'db', 'gx', 'reflection', 'prompt-pipeline', 'pipeline-runner', 'context7-docs', 'turbo-context-pack', 'hproof-evidence-bind'].includes(name))
|
|
1165
1168
|
return content;
|
|
1166
1169
|
const text = String(content || '').trimEnd();
|
|
1167
1170
|
const activation = pipelineActivationText(name);
|
|
@@ -1179,7 +1182,7 @@ Context tracking:
|
|
|
1179
1182
|
`;
|
|
1180
1183
|
}
|
|
1181
1184
|
function pipelineActivationText(name) {
|
|
1182
|
-
const stateful = new Set(['sks', 'qa-loop', 'ppt', 'image-ux-review', '
|
|
1185
|
+
const stateful = new Set(['sks', 'qa-loop', 'ppt', 'image-ux-review', 'computer-use-fast', 'cu', 'goal', 'research', 'autoresearch', 'db', 'gx', 'prompt-pipeline', 'pipeline-runner']);
|
|
1183
1186
|
if (!stateful.has(name))
|
|
1184
1187
|
return '';
|
|
1185
1188
|
return `Codex App pipeline activation:
|
|
@@ -1229,6 +1232,7 @@ async function removeGeneratedAgentSkillAliases(root, skillNames) {
|
|
|
1229
1232
|
const current = new Set(skillNames);
|
|
1230
1233
|
const obsolete = [
|
|
1231
1234
|
...SKS_SKILL_NAMES_TO_CLEAN_UP,
|
|
1235
|
+
...RETIRED_PUBLIC_IMAGE_UX_REVIEW_SKILL_ALIASES,
|
|
1232
1236
|
'qaloop',
|
|
1233
1237
|
'wiki-refresh',
|
|
1234
1238
|
'wikirefresh',
|
|
@@ -1242,7 +1246,7 @@ async function removeGeneratedAgentSkillAliases(root, skillNames) {
|
|
|
1242
1246
|
if (current.has(name))
|
|
1243
1247
|
continue;
|
|
1244
1248
|
const dir = path.join(root, '.agents', 'skills', name);
|
|
1245
|
-
const action = await cleanupGeneratedSkillResidue(root, dir, name, (text) => isGeneratedSksAgentSkill(text, name), 'generated-agent-skill-user-content-collision');
|
|
1249
|
+
const action = await cleanupGeneratedSkillResidue(root, dir, name, (text) => isGeneratedSksAgentSkill(text, name) || isRetiredGeneratedImageUxReviewAlias(text, name), 'generated-agent-skill-user-content-collision');
|
|
1246
1250
|
if (action === 'removed')
|
|
1247
1251
|
removed.push(path.relative(root, dir));
|
|
1248
1252
|
if (action === 'quarantined')
|
|
@@ -1282,6 +1286,14 @@ function isGeneratedSksAgentSkill(text, name) {
|
|
|
1282
1286
|
return false;
|
|
1283
1287
|
return /Sneakoscope generated|Fallback Codex App picker alias|Codex App picker alias for|Dollar-command route generated by SKS/i.test(s);
|
|
1284
1288
|
}
|
|
1289
|
+
function isRetiredGeneratedImageUxReviewAlias(text, name) {
|
|
1290
|
+
if (!RETIRED_PUBLIC_IMAGE_UX_REVIEW_SKILL_ALIAS_SET.has(String(name)))
|
|
1291
|
+
return false;
|
|
1292
|
+
const s = String(text || '');
|
|
1293
|
+
return MANAGED_SKILL_MARKER_RE.test(s)
|
|
1294
|
+
&& new RegExp(`^name:\\s*${escapeRegExp(name)}\\s*$`, 'm').test(s)
|
|
1295
|
+
&& /imagegen\/gpt-image-2 annotated UI\/UX review loop/i.test(s);
|
|
1296
|
+
}
|
|
1285
1297
|
function isGeneratedSksLegacySkill(text, name) {
|
|
1286
1298
|
if (typeof text !== 'string')
|
|
1287
1299
|
return false;
|
package/dist/core/init.js
CHANGED
|
@@ -695,7 +695,7 @@ export async function initProject(root, opts = {}) {
|
|
|
695
695
|
next = shouldSelectCodexLb
|
|
696
696
|
? upsertTopLevelTomlString(next, 'model_provider', 'codex-lb')
|
|
697
697
|
: removeTopLevelTomlKeyIfValue(next, 'model_provider', 'codex-lb');
|
|
698
|
-
next = upsertTomlTable(next, 'model_providers.codex-lb', `[model_providers.codex-lb]\nname = "
|
|
698
|
+
next = upsertTomlTable(next, 'model_providers.codex-lb', `[model_providers.codex-lb]\nname = "codex-lb"\nbase_url = "${baseUrl}"\nwire_api = "responses"\nenv_key = "CODEX_LB_API_KEY"\nsupports_websockets = true\nrequires_openai_auth = false`);
|
|
699
699
|
return `${next.trim()}\n`;
|
|
700
700
|
}
|
|
701
701
|
function parseCodexLbEnvKey(text = '') {
|
|
@@ -30,8 +30,31 @@ export async function runInstalledPackageSmoke(root, options = {}) {
|
|
|
30
30
|
const npmCache = path.join(tmp, 'npm-cache');
|
|
31
31
|
const installPrefix = path.join(tmp, 'prefix');
|
|
32
32
|
const packDestination = path.join(tmp, 'pack');
|
|
33
|
-
|
|
33
|
+
const globalRoot = path.join(tmp, 'global-sks');
|
|
34
|
+
const installCwd = path.join(tmp, 'install-cwd');
|
|
35
|
+
const runtimeTmp = path.join(tmp, 'runtime-tmp');
|
|
36
|
+
const stubBin = path.join(tmp, 'bin');
|
|
37
|
+
const launchctlLog = path.join(tmp, 'launchctl-calls.log');
|
|
38
|
+
const launchctlStub = path.join(stubBin, process.platform === 'win32' ? 'launchctl.cmd' : 'launchctl');
|
|
39
|
+
const npmUserConfig = path.join(tmp, 'npmrc');
|
|
40
|
+
const npmGlobalConfig = path.join(tmp, 'npm-globalrc');
|
|
41
|
+
await Promise.all([home, codexHome, npmCache, installPrefix, packDestination, globalRoot, installCwd, runtimeTmp, stubBin, path.join(home, '.tmp')]
|
|
34
42
|
.map((dir) => fs.mkdir(dir, { recursive: true })));
|
|
43
|
+
await Promise.all([
|
|
44
|
+
fs.writeFile(launchctlLog, ''),
|
|
45
|
+
fs.writeFile(launchctlStub, launchctlStubSource()),
|
|
46
|
+
fs.writeFile(npmUserConfig, ''),
|
|
47
|
+
fs.writeFile(npmGlobalConfig, '')
|
|
48
|
+
]);
|
|
49
|
+
await fs.chmod(launchctlStub, 0o700).catch(() => { });
|
|
50
|
+
const externalRoots = [
|
|
51
|
+
{ label: 'home', root: home },
|
|
52
|
+
{ label: 'codex-home', root: codexHome },
|
|
53
|
+
{ label: 'global-sks', root: globalRoot },
|
|
54
|
+
{ label: 'install-cwd', root: installCwd },
|
|
55
|
+
{ label: 'runtime-tmp', root: runtimeTmp }
|
|
56
|
+
];
|
|
57
|
+
const externalBeforeInstall = await snapshotTrees(externalRoots);
|
|
35
58
|
const blockers = [];
|
|
36
59
|
const commands = [];
|
|
37
60
|
let tarball = null;
|
|
@@ -40,6 +63,14 @@ export async function runInstalledPackageSmoke(root, options = {}) {
|
|
|
40
63
|
let packedVersion = null;
|
|
41
64
|
let expectedSha256 = normalizeSha256(options.expectedSha256);
|
|
42
65
|
let receiptPath = null;
|
|
66
|
+
let postinstallDefault = {
|
|
67
|
+
scripts_enabled: true,
|
|
68
|
+
external_snapshot_match: false,
|
|
69
|
+
external_findings: [],
|
|
70
|
+
launchctl_calls: [],
|
|
71
|
+
package_local_stamp_present: false,
|
|
72
|
+
opt_in_guidance_present: false
|
|
73
|
+
};
|
|
43
74
|
if (options.expectedSha256 && !expectedSha256)
|
|
44
75
|
blockers.push('expected_sha256_invalid');
|
|
45
76
|
if (options.receipt && !options.tarball)
|
|
@@ -85,12 +116,66 @@ export async function runInstalledPackageSmoke(root, options = {}) {
|
|
|
85
116
|
}
|
|
86
117
|
}
|
|
87
118
|
if (tarball && blockers.length === 0) {
|
|
88
|
-
const install = await runJsonCommand(
|
|
89
|
-
'npm', 'install', '--global', '--prefix', installPrefix, '--
|
|
90
|
-
], {
|
|
119
|
+
const install = await runJsonCommand(installCwd, [
|
|
120
|
+
'npm', 'install', '--global', '--prefix', installPrefix, '--foreground-scripts', '--no-audit', '--no-fund', tarball
|
|
121
|
+
], {
|
|
122
|
+
home,
|
|
123
|
+
codexHome,
|
|
124
|
+
npmCache,
|
|
125
|
+
env: {
|
|
126
|
+
HOME: home,
|
|
127
|
+
USERPROFILE: home,
|
|
128
|
+
CODEX_HOME: codexHome,
|
|
129
|
+
XDG_CONFIG_HOME: path.join(home, '.config'),
|
|
130
|
+
XDG_CACHE_HOME: path.join(home, '.cache'),
|
|
131
|
+
XDG_DATA_HOME: path.join(home, '.local', 'share'),
|
|
132
|
+
INIT_CWD: installCwd,
|
|
133
|
+
TMPDIR: runtimeTmp,
|
|
134
|
+
PATH: `${stubBin}${path.delimiter}${String(process.env.PATH || '')}`,
|
|
135
|
+
NODE_DISABLE_COMPILE_CACHE: '1',
|
|
136
|
+
NODE_COMPILE_CACHE: '',
|
|
137
|
+
SKS_GLOBAL_ROOT: globalRoot,
|
|
138
|
+
SKS_MENUBAR_LAUNCHCTL: launchctlStub,
|
|
139
|
+
SKS_INSTALLED_SMOKE_LAUNCHCTL_LOG: launchctlLog,
|
|
140
|
+
SKS_POSTINSTALL_BOOTSTRAP: '',
|
|
141
|
+
SKS_POSTINSTALL_NO_BOOTSTRAP: '',
|
|
142
|
+
SKS_POSTINSTALL_PROMPT: '',
|
|
143
|
+
npm_config_userconfig: npmUserConfig,
|
|
144
|
+
NPM_CONFIG_USERCONFIG: npmUserConfig,
|
|
145
|
+
npm_config_globalconfig: npmGlobalConfig,
|
|
146
|
+
NPM_CONFIG_GLOBALCONFIG: npmGlobalConfig,
|
|
147
|
+
npm_config_ignore_scripts: 'false',
|
|
148
|
+
NPM_CONFIG_IGNORE_SCRIPTS: 'false',
|
|
149
|
+
NO_UPDATE_NOTIFIER: '1'
|
|
150
|
+
}
|
|
151
|
+
});
|
|
91
152
|
commands.push(summarizeInstalledSmokeCommand(install.command, 'install'));
|
|
92
153
|
if (install.exit_code !== 0)
|
|
93
154
|
blockers.push('npm_install_tarball_failed');
|
|
155
|
+
const externalAfterInstall = await snapshotTrees(externalRoots);
|
|
156
|
+
const externalFindings = diffTreeSnapshots(externalBeforeInstall, externalAfterInstall);
|
|
157
|
+
const launchctlCalls = await nonEmptyLines(launchctlLog);
|
|
158
|
+
const packageLocalStamp = path.join(installedPackageRoot(installPrefix), 'dist', '.sks-build-stamp.json');
|
|
159
|
+
const packageLocalStampPresent = await regularFileExists(packageLocalStamp);
|
|
160
|
+
const installOutput = `${install.stdout}\n${install.command.stderr_tail}`;
|
|
161
|
+
const optInGuidancePresent = /Automatic bootstrap was not run/.test(installOutput)
|
|
162
|
+
&& /SKS_POSTINSTALL_BOOTSTRAP=1/.test(installOutput);
|
|
163
|
+
postinstallDefault = {
|
|
164
|
+
scripts_enabled: true,
|
|
165
|
+
external_snapshot_match: externalFindings.length === 0,
|
|
166
|
+
external_findings: externalFindings,
|
|
167
|
+
launchctl_calls: launchctlCalls,
|
|
168
|
+
package_local_stamp_present: packageLocalStampPresent,
|
|
169
|
+
opt_in_guidance_present: optInGuidancePresent
|
|
170
|
+
};
|
|
171
|
+
if (externalFindings.length)
|
|
172
|
+
blockers.push(...externalFindings.map((finding) => `postinstall_default_external_mutation:${finding}`));
|
|
173
|
+
if (launchctlCalls.length)
|
|
174
|
+
blockers.push('postinstall_default_launchctl_called');
|
|
175
|
+
if (!packageLocalStampPresent)
|
|
176
|
+
blockers.push('postinstall_package_local_stamp_missing');
|
|
177
|
+
if (!optInGuidancePresent)
|
|
178
|
+
blockers.push('postinstall_default_opt_in_guidance_missing');
|
|
94
179
|
}
|
|
95
180
|
const bin = process.platform === 'win32'
|
|
96
181
|
? path.join(installPrefix, 'sks.cmd')
|
|
@@ -187,6 +272,7 @@ export async function runInstalledPackageSmoke(root, options = {}) {
|
|
|
187
272
|
required_dollar_commands: [...INSTALLED_REQUIRED_DOLLAR_COMMANDS],
|
|
188
273
|
closure
|
|
189
274
|
},
|
|
275
|
+
postinstall_default: postinstallDefault,
|
|
190
276
|
forbidden_findings: forbiddenFindings,
|
|
191
277
|
blockers: [...new Set(blockers)]
|
|
192
278
|
};
|
|
@@ -253,6 +339,7 @@ async function runJsonCommand(cwd, argv, opts) {
|
|
|
253
339
|
env.npm_config_cache = opts.npmCache;
|
|
254
340
|
env.NPM_CONFIG_CACHE = opts.npmCache;
|
|
255
341
|
}
|
|
342
|
+
Object.assign(env, opts.env || {});
|
|
256
343
|
const res = await runProcess(command || 'node', args, {
|
|
257
344
|
cwd,
|
|
258
345
|
timeoutMs: 120_000,
|
|
@@ -275,6 +362,72 @@ async function runJsonCommand(cwd, argv, opts) {
|
|
|
275
362
|
}
|
|
276
363
|
};
|
|
277
364
|
}
|
|
365
|
+
async function snapshotTrees(roots) {
|
|
366
|
+
const snapshot = new Map();
|
|
367
|
+
for (const entry of roots)
|
|
368
|
+
await walkSnapshot(entry.root, entry.root, entry.label, snapshot);
|
|
369
|
+
return snapshot;
|
|
370
|
+
}
|
|
371
|
+
async function walkSnapshot(root, current, label, snapshot) {
|
|
372
|
+
const entries = await fs.readdir(current, { withFileTypes: true }).catch(() => []);
|
|
373
|
+
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
374
|
+
for (const entry of entries) {
|
|
375
|
+
const absolute = path.join(current, entry.name);
|
|
376
|
+
const relative = path.relative(root, absolute) || '.';
|
|
377
|
+
const key = `${label}:${relative}`;
|
|
378
|
+
const stat = await fs.lstat(absolute);
|
|
379
|
+
const mode = (stat.mode & 0o777).toString(8).padStart(3, '0');
|
|
380
|
+
if (entry.isDirectory()) {
|
|
381
|
+
snapshot.set(key, `directory:${mode}`);
|
|
382
|
+
await walkSnapshot(root, absolute, label, snapshot);
|
|
383
|
+
}
|
|
384
|
+
else if (entry.isFile()) {
|
|
385
|
+
const bytes = await fs.readFile(absolute);
|
|
386
|
+
snapshot.set(key, `file:${mode}:${bytes.length}:${crypto.createHash('sha256').update(bytes).digest('hex')}`);
|
|
387
|
+
}
|
|
388
|
+
else if (entry.isSymbolicLink()) {
|
|
389
|
+
snapshot.set(key, `symlink:${mode}:${await fs.readlink(absolute)}`);
|
|
390
|
+
}
|
|
391
|
+
else {
|
|
392
|
+
snapshot.set(key, `other:${mode}:${stat.size}`);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
function diffTreeSnapshots(before, after) {
|
|
397
|
+
const findings = [];
|
|
398
|
+
const keys = [...new Set([...before.keys(), ...after.keys()])].sort();
|
|
399
|
+
for (const key of keys) {
|
|
400
|
+
if (!before.has(key))
|
|
401
|
+
findings.push(`added:${key}`);
|
|
402
|
+
else if (!after.has(key))
|
|
403
|
+
findings.push(`removed:${key}`);
|
|
404
|
+
else if (before.get(key) !== after.get(key))
|
|
405
|
+
findings.push(`changed:${key}`);
|
|
406
|
+
}
|
|
407
|
+
return findings;
|
|
408
|
+
}
|
|
409
|
+
async function nonEmptyLines(file) {
|
|
410
|
+
const value = await fs.readFile(file, 'utf8').catch(() => '');
|
|
411
|
+
return value.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
412
|
+
}
|
|
413
|
+
async function regularFileExists(file) {
|
|
414
|
+
const stat = await fs.lstat(file).catch(() => null);
|
|
415
|
+
return Boolean(stat?.isFile() && !stat.isSymbolicLink());
|
|
416
|
+
}
|
|
417
|
+
function installedPackageRoot(prefix) {
|
|
418
|
+
return process.platform === 'win32'
|
|
419
|
+
? path.join(prefix, 'node_modules', 'sneakoscope')
|
|
420
|
+
: path.join(prefix, 'lib', 'node_modules', 'sneakoscope');
|
|
421
|
+
}
|
|
422
|
+
function launchctlStubSource() {
|
|
423
|
+
if (process.platform === 'win32') {
|
|
424
|
+
return '@echo %*>>\"%SKS_INSTALLED_SMOKE_LAUNCHCTL_LOG%\"\r\n@exit /b 0\r\n';
|
|
425
|
+
}
|
|
426
|
+
return `#!/bin/sh
|
|
427
|
+
printf '%s\n' "$*" >> "$SKS_INSTALLED_SMOKE_LAUNCHCTL_LOG"
|
|
428
|
+
exit 0
|
|
429
|
+
`;
|
|
430
|
+
}
|
|
278
431
|
export function validateInstalledPublicSurface(commandManifest, dollarManifest) {
|
|
279
432
|
const commands = Array.isArray(commandManifest?.commands)
|
|
280
433
|
? commandManifest.commands.map((row) => String(row?.name || '')) : [];
|
|
@@ -454,7 +454,8 @@ export const MANAGED_SKILLS = Object.freeze([
|
|
|
454
454
|
'dfix',
|
|
455
455
|
'image-ux-review',
|
|
456
456
|
'computer-use',
|
|
457
|
-
'init-deep'
|
|
457
|
+
'init-deep',
|
|
458
|
+
'align'
|
|
458
459
|
].map((id) => ({ id, required_for: ['codex-native-runtime'] })));
|
|
459
460
|
export const MANAGED_HOOKS = Object.freeze([
|
|
460
461
|
{ id: 'version-guard', required_for: ['managed-state-current'], risk: 'managed-write' },
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import fsp from 'node:fs/promises';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
+
import { errorCodeOf } from './errors/message.js';
|
|
3
4
|
export class ManagedPathSafetyError extends Error {
|
|
4
5
|
code;
|
|
5
6
|
target;
|
|
@@ -73,7 +74,7 @@ export async function ensureConfinedDirectory(boundary, directory) {
|
|
|
73
74
|
await fsp.mkdir(current);
|
|
74
75
|
}
|
|
75
76
|
catch (error) {
|
|
76
|
-
if (
|
|
77
|
+
if (errorCodeOf(error) !== 'EEXIST')
|
|
77
78
|
throw error;
|
|
78
79
|
}
|
|
79
80
|
stat = await lstatOrNull(current);
|
|
@@ -111,7 +112,7 @@ export async function walkConfinedEntries(boundary, root) {
|
|
|
111
112
|
children = await fsp.readdir(current, { withFileTypes: true, encoding: 'utf8' });
|
|
112
113
|
}
|
|
113
114
|
catch (error) {
|
|
114
|
-
errors.push(`${
|
|
115
|
+
errors.push(`${errorCodeOf(error) || 'managed_path_readdir_failed'}:${current}`);
|
|
115
116
|
return;
|
|
116
117
|
}
|
|
117
118
|
children.sort((left, right) => left.name.localeCompare(right.name));
|
|
@@ -222,7 +223,7 @@ export async function removeEmptyTreeVerified(boundary, root) {
|
|
|
222
223
|
children = await fsp.readdir(current, { withFileTypes: true, encoding: 'utf8' });
|
|
223
224
|
}
|
|
224
225
|
catch (error) {
|
|
225
|
-
errors.push(`${
|
|
226
|
+
errors.push(`${errorCodeOf(error) || 'managed_path_readdir_failed'}:${current}`);
|
|
226
227
|
remainingPaths.push(current);
|
|
227
228
|
return;
|
|
228
229
|
}
|
|
@@ -239,7 +240,7 @@ export async function removeEmptyTreeVerified(boundary, root) {
|
|
|
239
240
|
after = await fsp.readdir(current);
|
|
240
241
|
}
|
|
241
242
|
catch (error) {
|
|
242
|
-
errors.push(`${
|
|
243
|
+
errors.push(`${errorCodeOf(error) || 'managed_path_readdir_failed'}:${current}`);
|
|
243
244
|
remainingPaths.push(current);
|
|
244
245
|
return;
|
|
245
246
|
}
|
|
@@ -251,7 +252,7 @@ export async function removeEmptyTreeVerified(boundary, root) {
|
|
|
251
252
|
await fsp.rmdir(current);
|
|
252
253
|
}
|
|
253
254
|
catch (error) {
|
|
254
|
-
errors.push(`${
|
|
255
|
+
errors.push(`${errorCodeOf(error) || 'managed_path_rmdir_failed'}:${current}`);
|
|
255
256
|
remainingPaths.push(current);
|
|
256
257
|
return;
|
|
257
258
|
}
|
|
@@ -270,18 +271,15 @@ export async function lstatConfinedOrNull(boundary, target) {
|
|
|
270
271
|
export function publicPathError(error, fallback) {
|
|
271
272
|
if (error instanceof ManagedPathSafetyError)
|
|
272
273
|
return `${error.code}:${error.target}`;
|
|
273
|
-
return `${
|
|
274
|
+
return `${errorCodeOf(error) || 'managed_path_operation_failed'}:${fallback}`;
|
|
274
275
|
}
|
|
275
276
|
async function lstatOrNull(target) {
|
|
276
277
|
try {
|
|
277
278
|
return await fsp.lstat(target);
|
|
278
279
|
}
|
|
279
280
|
catch (error) {
|
|
280
|
-
if (
|
|
281
|
+
if (errorCodeOf(error) === 'ENOENT')
|
|
281
282
|
return null;
|
|
282
283
|
throw error;
|
|
283
284
|
}
|
|
284
285
|
}
|
|
285
|
-
function errorCode(error) {
|
|
286
|
-
return error && typeof error === 'object' && 'code' in error ? String(error.code) : '';
|
|
287
|
-
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import crypto from 'node:crypto';
|
|
2
2
|
import fsp from 'node:fs/promises';
|
|
3
3
|
import path from 'node:path';
|
|
4
|
+
import { errorCodeOf } from '../errors/message.js';
|
|
4
5
|
import { nowIso, sha256, writeTextAtomic } from '../fsx.js';
|
|
5
6
|
import { MCP_BACKUP_SCHEMA } from './types.js';
|
|
6
7
|
export async function createMcpBackup(ref, before, operation, server) {
|
|
@@ -86,7 +87,7 @@ async function assertSafeBackupDirectory(directory, codexHome) {
|
|
|
86
87
|
if (relative.startsWith('..') || path.isAbsolute(relative))
|
|
87
88
|
throw new Error('mcp_backup_path_escape');
|
|
88
89
|
for (const candidate of [path.join(codexHome, 'backups'), directory]) {
|
|
89
|
-
const stat = await fsp.lstat(candidate).catch((error) =>
|
|
90
|
+
const stat = await fsp.lstat(candidate).catch((error) => errorCodeOf(error) === 'ENOENT' ? null : Promise.reject(error));
|
|
90
91
|
if (stat?.isSymbolicLink() || (stat && !stat.isDirectory()))
|
|
91
92
|
throw new Error('mcp_backup_directory_invalid');
|
|
92
93
|
if (stat) {
|
|
@@ -97,6 +98,3 @@ async function assertSafeBackupDirectory(directory, codexHome) {
|
|
|
97
98
|
}
|
|
98
99
|
}
|
|
99
100
|
}
|
|
100
|
-
function errorCode(error) {
|
|
101
|
-
return error && typeof error === 'object' && 'code' in error ? String(error.code) : '';
|
|
102
|
-
}
|