sneakoscope 8.1.2 → 8.2.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 +96 -58
- package/crates/sks-core/Cargo.lock +1 -1
- package/crates/sks-core/Cargo.toml +1 -1
- package/dist/bin/fast-inline.js +5 -51
- package/dist/cli/command-manifest-lite.js +2 -1
- package/dist/cli/command-registry.js +2 -1
- package/dist/cli/global-mode-router.js +1 -1
- package/dist/cli/install-helpers-codex-lb-config.js +112 -914
- package/dist/cli/install-helpers-codex-lb-shared.js +3 -44
- package/dist/cli/install-helpers-install-support.js +4 -20
- package/dist/cli/install-helpers.js +36 -2716
- package/dist/cli/router.js +9 -9
- package/dist/commands/bridge-command-output.js +111 -0
- package/dist/commands/bridge.js +320 -0
- package/dist/commands/codex-app.js +39 -123
- package/dist/commands/doctor-helpers.js +380 -0
- package/dist/commands/doctor-profile.js +3 -0
- package/dist/commands/doctor.js +114 -873
- package/dist/commands/mad-sks.js +0 -4
- package/dist/config/skills-manifest.json +1 -1
- package/dist/core/agents/agent-effort-policy.js +11 -21
- package/dist/core/agents/agent-recursion-guard.js +26 -0
- package/dist/core/agents/agent-runner-codex-exec.js +7 -9
- package/dist/core/architecture-hardening/contracts/contracts.js +225 -161
- package/dist/core/architecture-hardening/state/state-service.js +49 -13
- package/dist/core/auto-review.js +15 -9
- package/dist/core/codex/codex-config-guard.js +8 -0
- package/dist/core/codex-adapter.js +8 -10
- package/dist/core/codex-app/codex-app-fast-ui-repair.js +7 -29
- package/dist/core/codex-app/codex-app-launcher.js +10 -12
- package/dist/core/codex-app/codex-app-restart.js +10 -12
- package/dist/core/codex-app/menubar/constants.js +2 -5
- package/dist/core/codex-app/menubar/global-install.js +3 -2
- package/dist/core/codex-app/menubar/installer/result.js +23 -0
- package/dist/core/codex-app/menubar/installer/runtime.js +28 -0
- package/dist/core/codex-app/menubar/installer.js +5 -96
- package/dist/core/codex-app/menubar/migration.js +1 -42
- package/dist/core/codex-app/openrouter-provider.js +0 -78
- package/dist/core/codex-app.js +97 -360
- package/dist/core/codex-control/codex-app-server-runtime-env.js +8 -28
- package/dist/core/codex-control/codex-current-image-path-real-probe.js +2 -3
- package/dist/core/codex-control/codex-current-web-search-probe.js +2 -3
- package/dist/core/codex-control/codex-sdk-adapter.js +5 -48
- package/dist/core/codex-control/codex-task-runner.js +16 -60
- package/dist/core/codex-control/desktop-bridge-launch-guard.js +227 -0
- package/dist/core/codex-exec-output-schema.js +11 -13
- package/dist/core/codex-lb/bridge-contracts.js +2 -0
- package/dist/core/codex-lb/bridge-runtime-validation/capability.js +104 -0
- package/dist/core/codex-lb/bridge-runtime-validation/catalog.js +52 -0
- package/dist/core/codex-lb/bridge-runtime-validation/shared.js +109 -0
- package/dist/core/codex-lb/bridge-runtime-validation/status.js +250 -0
- package/dist/core/codex-lb/bridge-runtime-validation.js +106 -0
- package/dist/core/codex-lb/capability-runner.js +505 -201
- package/dist/core/codex-lb/codex-lb-env.js +179 -12
- package/dist/core/codex-lb/combined-catalog/builder.js +86 -0
- package/dist/core/codex-lb/combined-catalog/contracts.js +5 -0
- package/dist/core/codex-lb/combined-catalog/normalize.js +170 -0
- package/dist/core/codex-lb/combined-catalog/persistence.js +207 -0
- package/dist/core/codex-lb/combined-catalog/shared.js +12 -0
- package/dist/core/codex-lb/combined-catalog/storage.js +171 -0
- package/dist/core/codex-lb/combined-catalog.js +12 -0
- package/dist/core/codex-lb/desktop-bridge/client.js +4 -1
- package/dist/core/codex-lb/desktop-bridge/header-policy.js +48 -63
- package/dist/core/codex-lb/desktop-bridge/http-forward.js +115 -83
- package/dist/core/codex-lb/desktop-bridge/launchd.js +20 -13
- package/dist/core/codex-lb/desktop-bridge/location-rewrite.js +4 -1
- package/dist/core/codex-lb/desktop-bridge/security.js +381 -267
- package/dist/core/codex-lb/desktop-bridge/server.js +148 -19
- package/dist/core/codex-lb/desktop-bridge/state.js +56 -70
- package/dist/core/codex-lb/desktop-bridge/types.js +6 -1
- package/dist/core/codex-lb/desktop-bridge/websocket-forward.js +281 -106
- package/dist/core/codex-lb/desktop-bridge-migration/historical-config.js +245 -0
- package/dist/core/codex-lb/desktop-bridge-migration/historical-toml.js +56 -0
- package/dist/core/codex-lb/desktop-bridge-migration/metadata.js +73 -0
- package/dist/core/codex-lb/desktop-bridge-migration/receipt.js +52 -0
- package/dist/core/codex-lb/desktop-bridge-migration/retired-runtime-cleanup.js +106 -0
- package/dist/core/codex-lb/desktop-bridge-migration/types.js +1 -0
- package/dist/core/codex-lb/desktop-bridge-migration.js +238 -0
- package/dist/core/codex-lb/desktop-controller-v3/catalog.js +257 -0
- package/dist/core/codex-lb/desktop-controller-v3/diagnostics.js +62 -0
- package/dist/core/codex-lb/desktop-controller-v3/lifecycle-commands.js +203 -0
- package/dist/core/codex-lb/desktop-controller-v3/live-probes.js +293 -0
- package/dist/core/codex-lb/desktop-controller-v3/preflight-probes.js +144 -0
- package/dist/core/codex-lb/desktop-controller-v3/provider-commands.js +182 -0
- package/dist/core/codex-lb/desktop-controller-v3/shared.js +279 -0
- package/dist/core/codex-lb/desktop-controller-v3/status.js +269 -0
- package/dist/core/codex-lb/desktop-controller-v3/types.js +1 -0
- package/dist/core/codex-lb/desktop-controller-v3/verification.js +89 -0
- package/dist/core/codex-lb/desktop-controller-v3.js +67 -0
- package/dist/core/codex-lb/desktop-controller.js +2 -1730
- package/dist/core/codex-lb/desktop-service.js +462 -627
- package/dist/core/codex-lb/migration-receipt.js +560 -118
- package/dist/core/codex-lb/probes/auxiliary-surfaces-probe.js +37 -53
- package/dist/core/codex-lb/probes/bridge-probe.js +125 -64
- package/dist/core/codex-lb/probes/catalog-probe.js +36 -136
- package/dist/core/codex-lb/probes/computer-use-probe.js +63 -39
- package/dist/core/codex-lb/probes/image-generation-probe.js +98 -41
- package/dist/core/codex-lb/probes/probe-evidence.js +32 -33
- package/dist/core/codex-lb/probes/voice-realtime-probe.js +69 -43
- package/dist/core/codex-lb/provider-credentials/configuration.js +127 -0
- package/dist/core/codex-lb/provider-credentials/locks.js +11 -0
- package/dist/core/codex-lb/provider-credentials/private-snapshot.js +28 -0
- package/dist/core/codex-lb/provider-credentials/removal.js +33 -0
- package/dist/core/codex-lb/provider-credentials/resolution.js +59 -0
- package/dist/core/codex-lb/provider-credentials/runtime.js +55 -0
- package/dist/core/codex-lb/provider-credentials/types.js +1 -0
- package/dist/core/codex-lb/provider-credentials/validation-store.js +137 -0
- package/dist/core/codex-lb/provider-credentials.js +5 -0
- package/dist/core/codex-lb/provider-registry.js +323 -0
- package/dist/core/codex-lb/provider-route-policy.js +118 -0
- package/dist/core/codex-lb/request-route-resolver.js +172 -0
- package/dist/core/codex-lb/route-index.js +148 -0
- package/dist/core/codex-lb/trusted-deep-evidence.js +158 -286
- package/dist/core/commands/basic-cli.js +1 -1
- package/dist/core/commands/check-command.js +3 -10
- package/dist/core/commands/gate-result-contract.js +10 -14
- package/dist/core/commands/intent-normalization/normalizer.js +1 -1
- package/dist/core/commands/mad-sks-command.js +2 -6
- package/dist/core/commands/release-command.js +11 -1
- package/dist/core/commands/telegram-command.js +46 -6
- package/dist/core/doctor/doctor-readiness-matrix.js +9 -7
- package/dist/core/doctor/skill-legacy-surface.js +5 -5
- package/dist/core/evidence/v2/evidence-key.js +30 -3
- package/dist/core/feature-fixtures.js +8 -1
- package/dist/core/feature-registry.js +3 -2
- package/dist/core/hooks-runtime/stop-finalization.js +11 -1
- package/dist/core/hooks-runtime/subagent-context.js +15 -1
- package/dist/core/hooks-runtime/subagent-skill-availability-contract.js +1 -1
- package/dist/core/hooks-runtime/tool-output-quarantine.js +1 -1
- package/dist/core/hooks-runtime.js +73 -87
- package/dist/core/image-ux-review/imagegen-adapter.js +108 -94
- package/dist/core/image-ux-review/real-callout-extractor.js +144 -14
- package/dist/core/imagegen/desktop-bridge-imagegen-target.js +77 -0
- package/dist/core/imagegen/imagegen-capability.js +43 -151
- package/dist/core/init/skills/filesystem.js +89 -0
- package/dist/core/init/skills/inventory.js +97 -0
- package/dist/core/init/skills/manifest.js +151 -0
- package/dist/core/init/skills.js +5 -325
- package/dist/core/init.js +0 -63
- package/dist/core/install/installed-package-smoke.js +1 -1
- package/dist/core/managed-assets/managed-assets-manifest.js +0 -1
- package/dist/core/policy/latest-version-guidance.js +15 -2
- package/dist/core/preflight/parallel-preflight-engine.js +27 -51
- package/dist/core/provider/provider-badge.js +9 -4
- package/dist/core/provider/provider-context.js +57 -107
- package/dist/core/providers/openrouter/openrouter-account.js +3 -1
- package/dist/core/providers/openrouter/openrouter-secret-store.js +91 -22
- package/dist/core/release/desktop-bridge-release-evidence.js +457 -0
- package/dist/core/release/gate-manifest.js +0 -1
- package/dist/core/release/main-push-guard.js +13 -0
- package/dist/core/release/main-push-receipt.js +11 -0
- package/dist/core/release/physical-release-gates.js +664 -61
- package/dist/core/release/publish-preflight.js +3 -3
- package/dist/core/release/release-gate-batch-runner.js +19 -6
- package/dist/core/release/release-gate-dag.js +33 -6
- package/dist/core/release/release-gate-node.js +1 -3
- package/dist/core/release/release-gate-output-contract.js +55 -0
- package/dist/core/release/release-pack-contract.js +1 -1
- package/dist/core/release/release-pack-receipt.js +209 -8
- package/dist/core/release/release-real-contract.js +1 -1
- package/dist/core/release/stage-publish.js +106 -28
- package/dist/core/retention/temp-lease.js +204 -0
- package/dist/core/retention.js +18 -195
- package/dist/core/routes.js +1 -2
- package/dist/core/safety/intent-contract/intent-contract.js +3 -3
- package/dist/core/subagents/naruto-host-credentials.js +6 -1
- package/dist/core/subagents/official-subagent-config.js +27 -9
- package/dist/core/subagents/official-subagent-runner.js +14 -31
- package/dist/core/subagents/wave-lifecycle.js +36 -8
- package/dist/core/subagents/wave-parent-guidance.js +2 -1
- package/dist/core/telegram/doctor.js +2 -2
- package/dist/core/telegram/liveness.js +10 -4
- package/dist/core/triwiki/context-graph/compiler/index.js +18 -18
- package/dist/core/update/update-migration-state/fast-mode-config.js +172 -0
- package/dist/core/update/update-migration-state/session-state-split.js +247 -0
- package/dist/core/update/update-migration-state/simple-stages.js +46 -0
- package/dist/core/update/update-migration-state.js +4 -481
- package/dist/core/version.js +1 -1
- package/dist/native/sks-menubar/Sources/OperationCoordinator.swift +28 -4
- package/dist/native/sks-menubar/Sources/OperationModels.swift +112 -2
- package/dist/native/sks-menubar/Sources/ProviderRouteExplanation.swift +21 -0
- package/dist/native/sks-menubar/Sources/ProvidersBridgeCatalog.swift +140 -0
- package/dist/native/sks-menubar/Sources/ProvidersOpenRouter.swift +107 -470
- package/dist/native/sks-menubar/Sources/ProvidersReliability.swift +27 -197
- package/dist/native/sks-menubar/Sources/ProvidersRoutingTruth.swift +335 -269
- package/dist/native/sks-menubar/Sources/ProvidersViewController.swift +233 -437
- package/dist/native/sks-menubar/Sources/RemoteCodingViewController.swift +16 -7
- package/dist/native/sks-menubar/Sources/SecureProcessEnvelope.swift +39 -9
- package/dist/native/sks-menubar/Sources/TelegramSupport.swift +56 -0
- package/dist/scripts/canonical-test-runner.js +7 -1
- package/dist/scripts/check-runtime-schemas.js +7 -2
- package/dist/scripts/codex-sdk-real-smoke-check.js +3 -1
- package/dist/scripts/desktop-bridge-capabilities-check.js +123 -0
- package/dist/scripts/{codex-lb-desktop-bridge-latency-check.js → desktop-bridge-latency-check.js} +61 -16
- package/dist/scripts/desktop-bridge-real-evidence-check.js +64 -0
- package/dist/scripts/{codex-lb-desktop-bridge-check.js → desktop-bridge-transport-check.js} +92 -155
- package/dist/scripts/desktop-bridge-transport-client.js +116 -0
- package/dist/scripts/desktop-bridge-unification-check.js +276 -0
- package/dist/scripts/doctor-fixes-codex-app-fast-ui-check.js +12 -8
- package/dist/scripts/gate-policy-audit-check.js +52 -2
- package/dist/scripts/provider-badge-context-check.js +55 -12
- package/dist/scripts/publish-preflight.js +1 -2
- package/dist/scripts/release-affected-selector-check.js +1 -2
- package/dist/scripts/release-aggressive-resource-governor-check.js +1 -1
- package/dist/scripts/release-cache-glob-hashing-check.js +1 -0
- package/dist/scripts/release-cache-version-neutral-fixture-check.js +1 -0
- package/dist/scripts/release-full-parallelism-blackbox.js +1 -1
- package/dist/scripts/release-gate-batch-runner-check.js +9 -0
- package/dist/scripts/release-gate-dag-runner-check.js +6 -0
- package/dist/scripts/release-gate-dag-runner.js +4 -2
- package/dist/scripts/release-metadata-check.js +16 -3
- package/dist/scripts/release-pack-receipt.js +29 -6
- package/dist/scripts/release-physical-gates-check.js +39 -0
- package/dist/scripts/release-real-check.js +7 -5
- package/package.json +6 -8
- package/release-gates.v2.json +156 -157
- package/runtime-required-scripts.json +11 -11
- package/schemas/codex/desktop-bridge-status-v3.schema.json +286 -0
- package/schemas/codex/desktop-capabilities-v3.schema.json +198 -0
- package/schemas/release/release-gate-node.schema.json +2 -3
- package/dist/cli/codex-lb-setup-warning-output.js +0 -17
- package/dist/cli/install-helpers-codex-lb-chain.js +0 -529
- package/dist/commands/codex-lb.js +0 -1232
- package/dist/core/architecture-hardening/migration/migration.js +0 -111
- package/dist/core/codex-app/auxiliary-oauth-policy.js +0 -36
- package/dist/core/codex-app/catalog-compat/catalog-service.js +0 -104
- package/dist/core/codex-app/child-policy/child-policy.js +0 -35
- package/dist/core/codex-app/desktop-routing-snapshot.js +0 -233
- package/dist/core/codex-app/glm-model-profile.js +0 -1
- package/dist/core/codex-app/glm-profile-installer.js +0 -191
- package/dist/core/codex-app/glm-profile-schema.js +0 -42
- package/dist/core/codex-app/multi-provider-router.js +0 -391
- package/dist/core/codex-app/openrouter-activate.js +0 -405
- package/dist/core/codex-app/openrouter-model-catalog.js +0 -217
- package/dist/core/codex-app/provider-child-policy.js +0 -64
- package/dist/core/codex-app/provider-mode.js +0 -91
- package/dist/core/codex-app/provider-session-policy.js +0 -85
- package/dist/core/codex-app/session-policy/session-pinning.js +0 -68
- package/dist/core/codex-control/codex-lb-launch-recovery.js +0 -319
- package/dist/core/codex-lb/codex-lb-setup.js +0 -293
- package/dist/core/codex-lb/codex-lb-tool-catalog.js +0 -456
- package/dist/core/codex-lb/codex-lb-tool-output-recovery.js +0 -290
- package/dist/core/codex-lb/desktop-center-credentials.js +0 -1083
- package/dist/core/codex-lb/desktop-mode.js +0 -32
- package/dist/core/codex-lb/desktop-real-evidence.js +0 -168
- package/dist/core/codex-lb/legacy-migration.js +0 -576
- package/dist/core/codex-lb/native-openai-transport/transport.js +0 -68
- package/dist/core/codex-lb/provider-routing/provider-router.js +0 -58
- package/dist/core/codex-lb/routing-truth.js +0 -327
- package/dist/core/imagegen/codex-lb-imagegen-target.js +0 -92
- package/dist/native/sks-menubar/Sources/ProvidersConnectTest.swift +0 -118
- package/dist/native/sks-menubar/Sources/ProvidersFastMode.swift +0 -17
- package/dist/native/sks-menubar/Sources/ProvidersMultiProvider.swift +0 -331
- package/dist/native/sks-menubar/Sources/ProvidersRoleModels.swift +0 -260
- package/dist/scripts/codex-lb-catalog-passthrough-check.js +0 -120
- package/dist/scripts/codex-lb-desktop-auth-invariant-check.js +0 -169
- package/dist/scripts/codex-lb-desktop-capabilities-check.js +0 -287
- package/dist/scripts/codex-lb-desktop-real-evidence-check.js +0 -123
- package/dist/scripts/codex-lb-fast-mode-truth-check.js +0 -114
- package/dist/scripts/codex-lb-fast-ui-preservation-check.js +0 -152
- package/dist/scripts/codex-lb-gpt56-fast-profile-check.js +0 -231
|
@@ -1,11 +1,13 @@
|
|
|
1
|
+
import fsp from 'node:fs/promises';
|
|
1
2
|
import path from 'node:path';
|
|
2
|
-
import { codexSchemaPath, runCodexExecResumeWithOutputSchema, structuredOutputBlocker } from '../codex-exec-output-schema.js';
|
|
3
|
+
import { codexSchemaPath, runCodexExecResumeWithOutputSchema, structuredOutputBlocker, validateStructuredOutput } from '../codex-exec-output-schema.js';
|
|
3
4
|
import { readJson } from '../fsx.js';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
5
|
+
import { strictJsonSchemaFormat } from '../structured-output-adapter.js';
|
|
6
|
+
import { parseResponsesSsePayload } from '../responses-stream.js';
|
|
7
|
+
import { DESKTOP_BRIDGE_IMAGEGEN_RECOVERY_GUIDANCE, resolveDesktopBridgeImagegenTarget } from '../imagegen/desktop-bridge-imagegen-target.js';
|
|
6
8
|
import { generatedImageMetadata } from './imagegen-adapter.js';
|
|
7
9
|
import { buildIssueLedgerFromGeneratedCallouts } from './callout-extraction.js';
|
|
8
|
-
export async function extractRealCallouts(input) {
|
|
10
|
+
export async function extractRealCallouts(input, opts = {}) {
|
|
9
11
|
const schemaPath = await codexSchemaPath('image-ux-issue-ledger');
|
|
10
12
|
const jsonSchema = await readJson(schemaPath);
|
|
11
13
|
const prompt = input.prompt || buildRealCalloutExtractionPrompt(input);
|
|
@@ -74,16 +76,39 @@ export async function extractRealCallouts(input) {
|
|
|
74
76
|
});
|
|
75
77
|
}
|
|
76
78
|
else {
|
|
77
|
-
const
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
...(
|
|
86
|
-
|
|
79
|
+
const suppliedTarget = opts.desktopBridgeTarget
|
|
80
|
+
? fixtureDesktopBridgeTarget(opts.desktopBridgeTarget)
|
|
81
|
+
: null;
|
|
82
|
+
const target = suppliedTarget || await resolveDesktopBridgeImagegenTarget({
|
|
83
|
+
explicitModel: input.model
|
|
84
|
+
|| process.env.OPENAI_STRUCTURED_OUTPUT_MODEL
|
|
85
|
+
|| process.env.SKS_IMAGEGEN_RESPONSES_MODEL
|
|
86
|
+
|| null,
|
|
87
|
+
...(opts.home ? { home: opts.home } : {}),
|
|
88
|
+
...(opts.env ? { env: opts.env } : {}),
|
|
89
|
+
...(opts.desktopBridgeStatus !== undefined ? { desktopBridgeStatus: opts.desktopBridgeStatus } : {}),
|
|
90
|
+
...(opts.desktopBridgeStatusImpl ? { desktopBridgeStatusImpl: opts.desktopBridgeStatusImpl } : {})
|
|
91
|
+
}).catch(() => null);
|
|
92
|
+
if (!target || target.blocker || !target.endpoint || !target.model) {
|
|
93
|
+
const reason = target?.blocker || 'desktop_bridge_status_unavailable';
|
|
94
|
+
providerResult = {
|
|
95
|
+
ok: false,
|
|
96
|
+
status: 'blocked',
|
|
97
|
+
provider: 'desktop_bridge_structured_extractor',
|
|
98
|
+
parsed_json: null,
|
|
99
|
+
blocker: structuredOutputBlocker(reason, DESKTOP_BRIDGE_IMAGEGEN_RECOVERY_GUIDANCE),
|
|
100
|
+
fixture: target?.status_source === 'injected_fixture'
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
providerResult = await runDesktopBridgeStructuredOutput({
|
|
105
|
+
target,
|
|
106
|
+
prompt,
|
|
107
|
+
schemaName: 'image_ux_issue_ledger',
|
|
108
|
+
jsonSchema,
|
|
109
|
+
imagePath: path.resolve(input.root, input.generatedImagePath)
|
|
110
|
+
});
|
|
111
|
+
}
|
|
87
112
|
}
|
|
88
113
|
if (!providerResult.ok || !providerResult.parsed_json) {
|
|
89
114
|
return {
|
|
@@ -95,6 +120,7 @@ export async function extractRealCallouts(input) {
|
|
|
95
120
|
generated_image_sha256: generated.sha256,
|
|
96
121
|
parsed_json_present: false,
|
|
97
122
|
validation_status: 'blocked',
|
|
123
|
+
...(providerResult.fixture ? { fake_adapter: true, source: 'mock_fixture' } : {}),
|
|
98
124
|
issue_ledger: buildIssueLedgerFromGeneratedCallouts({
|
|
99
125
|
schema: 'sks.image-ux-generated-review-ledger.v2',
|
|
100
126
|
generated_review_images: [{ ...generated, callout_extraction_status: 'pending', callouts: [] }],
|
|
@@ -123,9 +149,113 @@ export async function extractRealCallouts(input) {
|
|
|
123
149
|
parsed_json_present: true,
|
|
124
150
|
validation_status: ledger.validation.ok ? 'valid' : 'blocked',
|
|
125
151
|
issue_ledger: ledger,
|
|
152
|
+
...(providerResult.fixture ? { fake_adapter: true, source: 'mock_fixture' } : {}),
|
|
126
153
|
blocker: ledger.issues.length ? null : structuredOutputBlocker('callout_extraction_schema_failed', 'Generated image did not yield visible callouts.')
|
|
127
154
|
};
|
|
128
155
|
}
|
|
156
|
+
async function runDesktopBridgeStructuredOutput(request) {
|
|
157
|
+
const imageBytes = await fsp.readFile(request.imagePath);
|
|
158
|
+
const imageUrl = `data:${mimeForPath(request.imagePath)};base64,${imageBytes.toString('base64')}`;
|
|
159
|
+
const fixture = request.target.status_source === 'injected_fixture'
|
|
160
|
+
|| request.target.live_evidence_allowed !== true;
|
|
161
|
+
try {
|
|
162
|
+
const response = await fetch(request.target.endpoint, {
|
|
163
|
+
method: 'POST',
|
|
164
|
+
headers: {
|
|
165
|
+
'content-type': 'application/json',
|
|
166
|
+
'x-sks-model': request.target.model
|
|
167
|
+
},
|
|
168
|
+
body: JSON.stringify({
|
|
169
|
+
model: request.target.model,
|
|
170
|
+
input: [{
|
|
171
|
+
role: 'user',
|
|
172
|
+
content: [
|
|
173
|
+
{ type: 'input_text', text: request.prompt },
|
|
174
|
+
{ type: 'input_image', image_url: imageUrl }
|
|
175
|
+
]
|
|
176
|
+
}],
|
|
177
|
+
text: { format: strictJsonSchemaFormat(request.schemaName, request.jsonSchema) }
|
|
178
|
+
})
|
|
179
|
+
});
|
|
180
|
+
const text = await response.text();
|
|
181
|
+
if (!response.ok) {
|
|
182
|
+
return bridgeStructuredOutputBlocked('desktop_bridge_structured_output_api_error', text, fixture);
|
|
183
|
+
}
|
|
184
|
+
const payload = parseStructuredOutputBody(text);
|
|
185
|
+
if (!payload)
|
|
186
|
+
return bridgeStructuredOutputBlocked('json_parse_failed', 'Desktop Bridge returned no readable JSON.', fixture);
|
|
187
|
+
const parsed = payload.output_parsed || parseStructuredOutputPayload(payload);
|
|
188
|
+
if (!parsed || typeof parsed !== 'object') {
|
|
189
|
+
return bridgeStructuredOutputBlocked('json_parse_failed', 'Desktop Bridge output did not contain parsed JSON.', fixture);
|
|
190
|
+
}
|
|
191
|
+
const validation = validateStructuredOutput(parsed, strictJsonSchemaFormat(request.schemaName, request.jsonSchema).schema);
|
|
192
|
+
return {
|
|
193
|
+
ok: validation.ok,
|
|
194
|
+
status: validation.ok ? 'parsed' : 'blocked',
|
|
195
|
+
provider: fixture ? 'desktop_bridge_fixture_structured_extractor' : 'desktop_bridge_structured_extractor',
|
|
196
|
+
parsed_json: validation.ok ? parsed : null,
|
|
197
|
+
blocker: validation.ok
|
|
198
|
+
? null
|
|
199
|
+
: structuredOutputBlocker('schema_validation_failed', validation.issues.join(', ')),
|
|
200
|
+
fixture
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
catch (error) {
|
|
204
|
+
return bridgeStructuredOutputBlocked('desktop_bridge_structured_output_api_error', error instanceof Error ? error.message : String(error), fixture);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
function bridgeStructuredOutputBlocked(reason, detail, fixture) {
|
|
208
|
+
return {
|
|
209
|
+
ok: false,
|
|
210
|
+
status: 'blocked',
|
|
211
|
+
provider: fixture ? 'desktop_bridge_fixture_structured_extractor' : 'desktop_bridge_structured_extractor',
|
|
212
|
+
parsed_json: null,
|
|
213
|
+
blocker: structuredOutputBlocker(reason, String(detail || '').slice(0, 2000)),
|
|
214
|
+
fixture
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
function fixtureDesktopBridgeTarget(value) {
|
|
218
|
+
if (!value || typeof value !== 'object')
|
|
219
|
+
return null;
|
|
220
|
+
return {
|
|
221
|
+
...value,
|
|
222
|
+
status_source: 'injected_fixture',
|
|
223
|
+
live_evidence_allowed: false
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
function parseStructuredOutputBody(text) {
|
|
227
|
+
try {
|
|
228
|
+
return JSON.parse(text);
|
|
229
|
+
}
|
|
230
|
+
catch {
|
|
231
|
+
return parseResponsesSsePayload(text);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
function parseStructuredOutputPayload(payload) {
|
|
235
|
+
const output = Array.isArray(payload.output) ? payload.output : [];
|
|
236
|
+
for (const item of output) {
|
|
237
|
+
const content = Array.isArray(item?.content) ? item.content : [];
|
|
238
|
+
for (const part of content) {
|
|
239
|
+
if (part?.parsed)
|
|
240
|
+
return part.parsed;
|
|
241
|
+
if (typeof part?.text === 'string') {
|
|
242
|
+
try {
|
|
243
|
+
return JSON.parse(part.text);
|
|
244
|
+
}
|
|
245
|
+
catch { }
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
return null;
|
|
250
|
+
}
|
|
251
|
+
function mimeForPath(file) {
|
|
252
|
+
const ext = path.extname(file).toLowerCase();
|
|
253
|
+
if (ext === '.jpg' || ext === '.jpeg')
|
|
254
|
+
return 'image/jpeg';
|
|
255
|
+
if (ext === '.webp')
|
|
256
|
+
return 'image/webp';
|
|
257
|
+
return 'image/png';
|
|
258
|
+
}
|
|
129
259
|
export function buildRealCalloutExtractionPrompt(input) {
|
|
130
260
|
const source = input.sourceScreenshot || {};
|
|
131
261
|
return [
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { desktopBridgeStatusV3 } from '../codex-lb/desktop-controller-v3.js';
|
|
2
|
+
export const DESKTOP_BRIDGE_IMAGEGEN_TARGET_SCHEMA = 'sks.desktop-bridge-imagegen-target.v1';
|
|
3
|
+
export const DESKTOP_BRIDGE_IMAGEGEN_RECOVERY_GUIDANCE = 'Run `sks bridge status --json` to inspect Desktop Bridge provider readiness.';
|
|
4
|
+
export async function resolveDesktopBridgeImagegenTarget(opts = {}) {
|
|
5
|
+
const env = opts.env || process.env;
|
|
6
|
+
const injected = opts.desktopBridgeStatus !== undefined || opts.desktopBridgeStatusImpl !== undefined;
|
|
7
|
+
const status = opts.desktopBridgeStatus !== undefined
|
|
8
|
+
? opts.desktopBridgeStatus
|
|
9
|
+
: await (opts.desktopBridgeStatusImpl || desktopBridgeStatusV3)({
|
|
10
|
+
...(opts.home ? { home: opts.home } : {}),
|
|
11
|
+
env
|
|
12
|
+
}).catch(() => null);
|
|
13
|
+
const model = String(opts.explicitModel ?? env.SKS_IMAGEGEN_RESPONSES_MODEL ?? '').trim() || null;
|
|
14
|
+
const selected = status?.schema === 'sks.desktop-bridge-status.v3'
|
|
15
|
+
&& status.management?.managed === true;
|
|
16
|
+
const loopbackOrigin = verifiedLoopbackOrigin(status);
|
|
17
|
+
const policy = status?.routing?.policy || null;
|
|
18
|
+
const route = model && policy?.fallback === 'none'
|
|
19
|
+
? policy.model_routes?.[model] || null
|
|
20
|
+
: null;
|
|
21
|
+
const provider = route ? status?.providers?.[route.provider_id] || null : null;
|
|
22
|
+
const providerImagegen = provider?.capabilities?.capabilities?.image_generation || null;
|
|
23
|
+
const blocker = !status || status.schema !== 'sks.desktop-bridge-status.v3'
|
|
24
|
+
? 'desktop_bridge_status_unavailable'
|
|
25
|
+
: !selected
|
|
26
|
+
? 'desktop_bridge_not_managed'
|
|
27
|
+
: status.service?.running !== true || status.service?.state !== 'ready'
|
|
28
|
+
? 'desktop_bridge_not_running'
|
|
29
|
+
: !loopbackOrigin
|
|
30
|
+
? 'desktop_bridge_loopback_unverified'
|
|
31
|
+
: status.readiness?.bridge_ready !== true || status.catalog_sync?.state !== 'verified'
|
|
32
|
+
? status.readiness?.blockers?.[0] || status.catalog_sync?.blockers?.[0] || 'desktop_bridge_state_unverified'
|
|
33
|
+
: !model
|
|
34
|
+
? 'desktop_bridge_imagegen_model_missing'
|
|
35
|
+
: !policy || policy.fallback !== 'none' || !route
|
|
36
|
+
? 'catalog_model_route_missing'
|
|
37
|
+
: provider?.enabled !== true
|
|
38
|
+
? 'bridge_route_provider_disabled'
|
|
39
|
+
: provider.credential?.state !== 'ready'
|
|
40
|
+
? provider.credential?.blockers?.[0] || 'bridge_route_provider_credential_unverified'
|
|
41
|
+
: providerImagegen?.state !== 'verified'
|
|
42
|
+
? providerImagegen?.blockers?.[0] || 'bridge_route_imagegen_capability_unverified'
|
|
43
|
+
: null;
|
|
44
|
+
const bridgeVerified = blocker === null;
|
|
45
|
+
return {
|
|
46
|
+
schema: DESKTOP_BRIDGE_IMAGEGEN_TARGET_SCHEMA,
|
|
47
|
+
selected,
|
|
48
|
+
bridge_verified: bridgeVerified,
|
|
49
|
+
endpoint: bridgeVerified ? `${loopbackOrigin}/backend-api/codex/responses` : null,
|
|
50
|
+
model,
|
|
51
|
+
model_source: model ? 'explicit' : null,
|
|
52
|
+
route: route || null,
|
|
53
|
+
provider_id: route?.provider_id || null,
|
|
54
|
+
status_source: injected ? 'injected_fixture' : 'runtime',
|
|
55
|
+
live_evidence_allowed: bridgeVerified && !injected,
|
|
56
|
+
blocker,
|
|
57
|
+
setup_guidance: DESKTOP_BRIDGE_IMAGEGEN_RECOVERY_GUIDANCE
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function verifiedLoopbackOrigin(status) {
|
|
61
|
+
const raw = String(status?.service?.loopback_origin || '').trim();
|
|
62
|
+
if (!raw)
|
|
63
|
+
return null;
|
|
64
|
+
try {
|
|
65
|
+
const parsed = new URL(raw);
|
|
66
|
+
const loopback = parsed.hostname === '127.0.0.1'
|
|
67
|
+
|| parsed.hostname === '::1'
|
|
68
|
+
|| parsed.hostname === '[::1]';
|
|
69
|
+
if (parsed.protocol !== 'http:' || !loopback || parsed.username || parsed.password
|
|
70
|
+
|| parsed.pathname !== '/' || parsed.search || parsed.hash || !parsed.port)
|
|
71
|
+
return null;
|
|
72
|
+
return parsed.origin;
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -1,11 +1,7 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import { loadCodexLbEnv, parseShellEnvValue } from '../codex-lb/codex-lb-env.js';
|
|
4
|
-
import { CODEX_LB_ROUTING_TRUTH_RECEIPT, codexLbRoutingTruthIsActive, readCodexLbRoutingTruthReceipt } from '../codex-lb/routing-truth.js';
|
|
5
|
-
import { nowIso, readText, runProcess, which } from '../fsx.js';
|
|
1
|
+
import { desktopBridgeStatusV3 } from '../codex-lb/desktop-controller-v3.js';
|
|
2
|
+
import { nowIso, runProcess, which } from '../fsx.js';
|
|
6
3
|
import { redactSecrets, redactString } from '../secret-redaction.js';
|
|
7
4
|
import { evaluateImagegenAuthReadiness } from './imagegen-auth-readiness.js';
|
|
8
|
-
import { escapeRegExp } from '../text/regex.js';
|
|
9
5
|
export async function detectImagegenCapability(opts = {}) {
|
|
10
6
|
const codexBin = opts.codexBin || await which('codex').catch(() => null);
|
|
11
7
|
const codexApp = await detectCodexAppImagegen(codexBin, opts);
|
|
@@ -97,130 +93,57 @@ export async function detectImagegenCapability(opts = {}) {
|
|
|
97
93
|
};
|
|
98
94
|
}
|
|
99
95
|
async function detectCodexLbImagegenAuth(opts = {}, env = process.env) {
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
const configText = typeof opts.configText === 'string'
|
|
104
|
-
? opts.configText
|
|
105
|
-
: await readText(configPath, '').catch(() => '');
|
|
106
|
-
const block = tomlTableBlock(configText, 'model_providers.codex-lb');
|
|
107
|
-
const selected = opts.codexLbSelected === true || topLevelTomlString(configText, 'model_provider') === 'codex-lb';
|
|
108
|
-
const providerConfigured = Boolean(block);
|
|
109
|
-
const requiresOpenAiAuth = tomlBoolean(block, 'requires_openai_auth');
|
|
110
|
-
const bearerEnvKey = tomlString(block, 'env_key');
|
|
111
|
-
const gatewayHeaderEnvKey = tomlEnvHttpHeader(block, 'X-Codex-LB-API-Key');
|
|
112
|
-
const envKey = bearerEnvKey || gatewayHeaderEnvKey;
|
|
113
|
-
const cliContract = providerConfigured
|
|
114
|
-
&& tomlString(block, 'name') === 'codex-lb'
|
|
115
|
-
&& tomlString(block, 'wire_api') === 'responses'
|
|
116
|
-
&& bearerEnvKey === 'CODEX_LB_API_KEY'
|
|
117
|
-
&& !gatewayHeaderEnvKey
|
|
118
|
-
&& requiresOpenAiAuth === false;
|
|
119
|
-
const baseUrl = tomlString(block, 'base_url') || String(env.CODEX_LB_BASE_URL || '').trim();
|
|
120
|
-
const envPath = opts.codexLbEnvPath || path.join(codexHome, 'sks-codex-lb.env');
|
|
121
|
-
const injectedEnvText = typeof opts.codexLbEnvText === 'string' ? opts.codexLbEnvText : null;
|
|
122
|
-
const keyFromInjectedFile = injectedEnvText !== null && envKey ? parseShellEnvValue(injectedEnvText, envKey) : '';
|
|
123
|
-
const loaded = injectedEnvText === null
|
|
124
|
-
? await loadCodexLbEnv({
|
|
125
|
-
home,
|
|
126
|
-
processEnv: {},
|
|
127
|
-
envPath,
|
|
128
|
-
metadataPath: path.join(codexHome, 'sks-codex-lb.json')
|
|
129
|
-
}).catch(() => null)
|
|
130
|
-
: null;
|
|
131
|
-
const apiKeyPresent = Boolean(opts.codexLbApiKey || keyFromInjectedFile || loaded?.secret_api_key);
|
|
132
|
-
const apiKeySource = opts.codexLbApiKey
|
|
133
|
-
? 'option'
|
|
134
|
-
: keyFromInjectedFile ? 'env-file' : loaded?.api_key?.source || null;
|
|
135
|
-
const blocker = codexLbAuthBlocker({
|
|
136
|
-
selected,
|
|
137
|
-
providerConfigured,
|
|
138
|
-
requiresOpenAiAuth,
|
|
139
|
-
envKey,
|
|
140
|
-
baseUrl,
|
|
141
|
-
apiKeyPresent,
|
|
142
|
-
cliContract
|
|
143
|
-
});
|
|
144
|
-
const routingTruthReceiptPath = opts.codexLbRoutingTruthReceiptPath
|
|
145
|
-
|| path.join(codexHome, CODEX_LB_ROUTING_TRUTH_RECEIPT);
|
|
146
|
-
const routingTruth = await readCodexLbRoutingTruthReceipt({
|
|
147
|
-
receiptPath: routingTruthReceiptPath
|
|
96
|
+
const status = opts.desktopBridgeStatus || await (opts.desktopBridgeStatusImpl || desktopBridgeStatusV3)({
|
|
97
|
+
home: opts.home || env.HOME,
|
|
98
|
+
env
|
|
148
99
|
}).catch(() => null);
|
|
149
|
-
const
|
|
150
|
-
const
|
|
151
|
-
const
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
const
|
|
155
|
-
|
|
100
|
+
const provider = status?.providers?.['codex-lb'] || null;
|
|
101
|
+
const policy = status?.routing?.policy || null;
|
|
102
|
+
const modelRoutes = Object.values(policy?.model_routes || {});
|
|
103
|
+
const selected = provider?.enabled === true && (policy?.default_provider_id === 'codex-lb'
|
|
104
|
+
|| modelRoutes.some((route) => route?.provider_id === 'codex-lb'));
|
|
105
|
+
const credentialReady = provider?.credential?.state === 'ready';
|
|
106
|
+
const endpointConfigured = provider?.endpoint?.configured === true;
|
|
107
|
+
const capabilityEvidence = provider?.capabilities?.capabilities?.image_generation || null;
|
|
108
|
+
const capabilityReady = capabilityEvidence?.state === 'verified';
|
|
109
|
+
const blocker = !status
|
|
110
|
+
? 'desktop_bridge_status_unavailable'
|
|
111
|
+
: !provider
|
|
112
|
+
? 'codex_lb_provider_status_missing'
|
|
113
|
+
: !provider.enabled
|
|
114
|
+
? 'codex_lb_provider_disabled'
|
|
115
|
+
: !credentialReady
|
|
116
|
+
? provider.credential?.blockers?.[0] || `codex_lb_credential_${provider.credential?.state || 'unknown'}`
|
|
117
|
+
: !endpointConfigured
|
|
118
|
+
? 'codex_lb_endpoint_missing'
|
|
119
|
+
: !selected
|
|
120
|
+
? 'codex_lb_route_inactive'
|
|
121
|
+
: !capabilityReady
|
|
122
|
+
? capabilityEvidence?.blockers?.[0] || `codex_lb_imagegen_capability_${capabilityEvidence?.state || 'unverified'}`
|
|
123
|
+
: null;
|
|
156
124
|
return {
|
|
157
125
|
available: blocker === null,
|
|
158
126
|
selected,
|
|
159
|
-
cli_contract:
|
|
160
|
-
provider_configured:
|
|
161
|
-
requires_openai_auth:
|
|
162
|
-
openai_auth_disabled:
|
|
163
|
-
env_key:
|
|
164
|
-
base_url:
|
|
165
|
-
env_path:
|
|
127
|
+
cli_contract: provider?.endpoint?.auth_transport === 'authorization-bearer',
|
|
128
|
+
provider_configured: Boolean(provider),
|
|
129
|
+
requires_openai_auth: null,
|
|
130
|
+
openai_auth_disabled: null,
|
|
131
|
+
env_key: null,
|
|
132
|
+
base_url: provider?.endpoint?.origin_redacted || null,
|
|
133
|
+
env_path: null,
|
|
166
134
|
api_key: {
|
|
167
|
-
present:
|
|
168
|
-
source:
|
|
135
|
+
present: credentialReady,
|
|
136
|
+
source: provider?.credential?.source || null,
|
|
169
137
|
redacted: true
|
|
170
138
|
},
|
|
171
|
-
routing_active:
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
configuredHost,
|
|
177
|
-
routingTruth,
|
|
178
|
-
expectedAuthTransport: routingAuthTransport,
|
|
179
|
-
routingTruthContextMatches,
|
|
180
|
-
routingActive
|
|
181
|
-
}),
|
|
139
|
+
routing_active: selected,
|
|
140
|
+
routing_blocker: selected ? null : 'codex_lb_route_inactive',
|
|
141
|
+
capability_evidence: capabilityEvidence,
|
|
142
|
+
provider_capability_summary: provider?.capabilities || null,
|
|
143
|
+
bridge_status_checked_at: status?.checked_at || null,
|
|
182
144
|
blocker
|
|
183
145
|
};
|
|
184
146
|
}
|
|
185
|
-
function codexLbRoutingBlocker(state) {
|
|
186
|
-
if (!state.selected)
|
|
187
|
-
return 'codex_lb_not_selected';
|
|
188
|
-
if (!state.routingTruth)
|
|
189
|
-
return 'codex_lb_routing_truth_receipt_missing';
|
|
190
|
-
if (state.routingTruth.selected !== true)
|
|
191
|
-
return 'codex_lb_routing_truth_selection_mismatch';
|
|
192
|
-
if (state.routingTruth.configured_host !== state.configuredHost)
|
|
193
|
-
return 'codex_lb_routing_truth_host_mismatch';
|
|
194
|
-
if (state.routingTruth.auth_transport !== state.expectedAuthTransport)
|
|
195
|
-
return 'codex_lb_routing_truth_auth_transport_mismatch';
|
|
196
|
-
if (!state.routingTruthContextMatches || !state.routingActive) {
|
|
197
|
-
return state.routingTruth.blockers?.[0] || 'codex_lb_routing_truth_unverified';
|
|
198
|
-
}
|
|
199
|
-
return null;
|
|
200
|
-
}
|
|
201
|
-
function codexLbAuthBlocker(state) {
|
|
202
|
-
if (!state.selected && !state.cliContract)
|
|
203
|
-
return 'codex_lb_not_selected';
|
|
204
|
-
if (!state.providerConfigured)
|
|
205
|
-
return 'codex_lb_provider_missing';
|
|
206
|
-
if (state.cliContract) {
|
|
207
|
-
if (!state.apiKeyPresent)
|
|
208
|
-
return 'codex_lb_api_key_missing';
|
|
209
|
-
if (!state.baseUrl)
|
|
210
|
-
return 'codex_lb_base_url_missing';
|
|
211
|
-
return null;
|
|
212
|
-
}
|
|
213
|
-
if (state.requiresOpenAiAuth !== true) {
|
|
214
|
-
return state.requiresOpenAiAuth === false ? 'codex_lb_legacy_openai_auth_disabled' : 'codex_lb_requires_openai_auth_missing';
|
|
215
|
-
}
|
|
216
|
-
if (state.envKey !== 'CODEX_LB_API_KEY')
|
|
217
|
-
return 'codex_lb_env_key_missing_or_unsupported';
|
|
218
|
-
if (!state.baseUrl)
|
|
219
|
-
return 'codex_lb_base_url_missing';
|
|
220
|
-
if (!state.apiKeyPresent)
|
|
221
|
-
return 'codex_lb_api_key_missing';
|
|
222
|
-
return null;
|
|
223
|
-
}
|
|
224
147
|
async function detectCodexAppImagegen(codexBin, opts = {}) {
|
|
225
148
|
if (opts.codexAppAvailable === true || process.env.SKS_CODEX_APP_IMAGEGEN_AVAILABLE === '1') {
|
|
226
149
|
return { available: true, detector: 'env_or_option', blocker: null, raw: null };
|
|
@@ -323,34 +246,3 @@ function boolish(value) {
|
|
|
323
246
|
return false;
|
|
324
247
|
return null;
|
|
325
248
|
}
|
|
326
|
-
function publicUrlHost(value) {
|
|
327
|
-
try {
|
|
328
|
-
return typeof value === 'string' && value ? new URL(value).host : null;
|
|
329
|
-
}
|
|
330
|
-
catch {
|
|
331
|
-
return null;
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
function topLevelTomlString(text = '', key = '') {
|
|
335
|
-
const topLevel = String(text || '').split(/\n\s*\[/)[0] || '';
|
|
336
|
-
return tomlString(topLevel, key);
|
|
337
|
-
}
|
|
338
|
-
function tomlTableBlock(text = '', table = '') {
|
|
339
|
-
const re = new RegExp(`(^|\\n)\\[${escapeRegExp(table)}\\]([\\s\\S]*?)(?=\\n\\[[^\\]]+\\]|\\s*$)`);
|
|
340
|
-
return String(text || '').match(re)?.[2] || '';
|
|
341
|
-
}
|
|
342
|
-
function tomlString(text = '', key = '') {
|
|
343
|
-
const re = new RegExp(`(^|\\n)\\s*${escapeRegExp(key)}\\s*=\\s*"([^"]*)"\\s*(?:#.*)?(?=\\n|$)`);
|
|
344
|
-
return String(text || '').match(re)?.[2] || '';
|
|
345
|
-
}
|
|
346
|
-
function tomlEnvHttpHeader(text = '', header = '') {
|
|
347
|
-
const inline = String(text || '').match(/(?:^|\n)\s*env_http_headers\s*=\s*\{([^}]*)\}/)?.[1] || '';
|
|
348
|
-
return inline.match(new RegExp(`"${escapeRegExp(header)}"\\s*=\\s*"([^"]+)"`))?.[1] || '';
|
|
349
|
-
}
|
|
350
|
-
function tomlBoolean(text = '', key = '') {
|
|
351
|
-
const re = new RegExp(`(^|\\n)\\s*${escapeRegExp(key)}\\s*=\\s*(true|false)\\s*(?:#.*)?(?=\\n|$)`, 'i');
|
|
352
|
-
const raw = String(text || '').match(re)?.[2];
|
|
353
|
-
if (!raw)
|
|
354
|
-
return null;
|
|
355
|
-
return raw.toLowerCase() === 'true';
|
|
356
|
-
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import fsp from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { inspectConfinedPath } from '../../managed-path-safety.js';
|
|
4
|
+
import { sha256 } from '../../fsx.js';
|
|
5
|
+
import { SKS_SKILL_MANIFEST_FILE, canonicalSkillNameFromValue } from './inventory.js';
|
|
6
|
+
export async function listSkillDirs(targetDir, opts = {}) {
|
|
7
|
+
const boundary = rootFromSkillsDir(targetDir);
|
|
8
|
+
let rootInspection;
|
|
9
|
+
try {
|
|
10
|
+
rootInspection = await inspectConfinedPath(boundary, targetDir);
|
|
11
|
+
}
|
|
12
|
+
catch (error) {
|
|
13
|
+
if (nodeErrorCode(error) === 'ENOENT')
|
|
14
|
+
return [];
|
|
15
|
+
throw error;
|
|
16
|
+
}
|
|
17
|
+
if (!rootInspection.exists)
|
|
18
|
+
return [];
|
|
19
|
+
if (rootInspection.leafSymlink || !rootInspection.stat?.isDirectory()) {
|
|
20
|
+
throw new Error(`skill_target_not_safe_directory:${targetDir}`);
|
|
21
|
+
}
|
|
22
|
+
const rows = await fsp.readdir(targetDir, { withFileTypes: true });
|
|
23
|
+
const out = [];
|
|
24
|
+
for (const row of rows) {
|
|
25
|
+
const dir = path.join(targetDir, row.name);
|
|
26
|
+
const directoryCanonical = canonicalSkillNameFromValue(row.name);
|
|
27
|
+
if (row.isSymbolicLink() || !row.isDirectory()) {
|
|
28
|
+
if (opts.includeUnsafeEntries) {
|
|
29
|
+
out.push({
|
|
30
|
+
name: row.name,
|
|
31
|
+
dir,
|
|
32
|
+
skillMdPath: null,
|
|
33
|
+
text: '',
|
|
34
|
+
canonical: directoryCanonical,
|
|
35
|
+
declaredCanonical: '',
|
|
36
|
+
directoryCanonical,
|
|
37
|
+
hash: '',
|
|
38
|
+
unsafeEntry: row.isSymbolicLink() ? 'symlink' : 'non-directory'
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
const skillMdPath = path.join(dir, 'SKILL.md');
|
|
44
|
+
const inspected = await inspectConfinedPath(boundary, skillMdPath);
|
|
45
|
+
if (!inspected.exists || inspected.leafSymlink || !inspected.stat?.isFile()) {
|
|
46
|
+
if (opts.includeUnsafeEntries) {
|
|
47
|
+
out.push({
|
|
48
|
+
name: row.name,
|
|
49
|
+
dir,
|
|
50
|
+
skillMdPath,
|
|
51
|
+
text: '',
|
|
52
|
+
canonical: directoryCanonical,
|
|
53
|
+
declaredCanonical: '',
|
|
54
|
+
directoryCanonical,
|
|
55
|
+
hash: '',
|
|
56
|
+
unsafeEntry: inspected.leafSymlink ? 'skill-file-symlink' : 'missing-or-non-file-skill'
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
const text = await fsp.readFile(skillMdPath, 'utf8');
|
|
62
|
+
const displayName = /^name:\s*(.+)\s*$/m.exec(text)?.[1] || row.name;
|
|
63
|
+
const declaredCanonical = canonicalSkillNameFromValue(displayName);
|
|
64
|
+
out.push({
|
|
65
|
+
name: row.name,
|
|
66
|
+
dir,
|
|
67
|
+
skillMdPath,
|
|
68
|
+
text,
|
|
69
|
+
canonical: declaredCanonical,
|
|
70
|
+
declaredCanonical,
|
|
71
|
+
directoryCanonical,
|
|
72
|
+
hash: sha256(text)
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
return out;
|
|
76
|
+
}
|
|
77
|
+
export function rootFromSkillsDir(targetDir) {
|
|
78
|
+
const normalized = path.resolve(targetDir);
|
|
79
|
+
if (path.basename(normalized) === 'skills' && path.basename(path.dirname(normalized)) === '.agents') {
|
|
80
|
+
return path.dirname(path.dirname(normalized));
|
|
81
|
+
}
|
|
82
|
+
return path.dirname(path.dirname(normalized));
|
|
83
|
+
}
|
|
84
|
+
export async function pruneProjectGeneratedManifest(targetDir) {
|
|
85
|
+
await fsp.rm(path.join(targetDir, SKS_SKILL_MANIFEST_FILE), { force: true }).catch(() => undefined);
|
|
86
|
+
}
|
|
87
|
+
function nodeErrorCode(error) {
|
|
88
|
+
return String(error?.code || '');
|
|
89
|
+
}
|