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
package/dist/core/retention.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import fs from 'node:fs/promises';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import os from 'node:os';
|
|
4
|
-
import {
|
|
5
|
-
import { exists, readJson, writeJsonAtomic, ensureDir, dirSize, fileSize, formatBytes, rmrf, nowIso, appendJsonlBounded, listFilesRecursive, managedSksTmpRoot, sha256, SKS_TEMP_LEASE_FILE } from './fsx.js';
|
|
4
|
+
import { exists, readJson, writeJsonAtomic, ensureDir, dirSize, fileSize, formatBytes, rmrf, nowIso, appendJsonlBounded, listFilesRecursive, managedSksTmpRoot, sha256 } from './fsx.js';
|
|
6
5
|
import { FROM_CHAT_IMG_TEMP_TRIWIKI_ARTIFACT, FROM_CHAT_IMG_TEMP_TRIWIKI_SESSIONS } from './routes.js';
|
|
6
|
+
import { activeTempEnvironmentKey, currentProcessOwns, inspectTempPath, liveTempLease, removeDeadCanonicalTestLease, sharedTempEntryMatchesProject } from './retention/temp-lease.js';
|
|
7
7
|
export const DEFAULT_RETENTION_POLICY = Object.freeze({
|
|
8
8
|
schema_version: 1,
|
|
9
9
|
max_missions: 30,
|
|
@@ -107,8 +107,6 @@ const FULL_RETENTION_SCAN_MAX_FILES = 1_000_000;
|
|
|
107
107
|
const FULL_RETENTION_SCAN_MAX_DEPTH = 80;
|
|
108
108
|
const MISSION_COMPACTION_SCAN_MAX_FILES = 100_000;
|
|
109
109
|
const MISSION_COMPACTION_SCAN_MAX_DEPTH = 20;
|
|
110
|
-
const TEMP_RETENTION_SCAN_MAX_ENTRIES = 100_000;
|
|
111
|
-
const TEMP_RETENTION_SCAN_MAX_DEPTH = 20;
|
|
112
110
|
export async function ensureRetentionPolicy(root) {
|
|
113
111
|
const p = path.join(root, '.sneakoscope', 'policy.json');
|
|
114
112
|
if (!(await exists(p)))
|
|
@@ -414,197 +412,6 @@ async function safeMissionDirectory(root, id) {
|
|
|
414
412
|
return null;
|
|
415
413
|
return candidate;
|
|
416
414
|
}
|
|
417
|
-
async function inspectTempPath(target) {
|
|
418
|
-
const rootStat = await fs.lstat(target).catch(() => null);
|
|
419
|
-
if (!rootStat || rootStat.isSymbolicLink()) {
|
|
420
|
-
return {
|
|
421
|
-
complete: false,
|
|
422
|
-
latestMtimeMs: 0,
|
|
423
|
-
bytes: 0,
|
|
424
|
-
blockers: [rootStat ? 'temp_path_is_symlink' : 'temp_path_missing_or_unreadable']
|
|
425
|
-
};
|
|
426
|
-
}
|
|
427
|
-
let latestMtimeMs = rootStat.mtimeMs;
|
|
428
|
-
let bytes = rootStat.isFile() ? rootStat.size : 0;
|
|
429
|
-
let entryCount = 0;
|
|
430
|
-
const blockers = [];
|
|
431
|
-
const stack = rootStat.isDirectory()
|
|
432
|
-
? [{ dir: target, depth: 0 }]
|
|
433
|
-
: [];
|
|
434
|
-
while (stack.length) {
|
|
435
|
-
const current = stack.pop();
|
|
436
|
-
let entries;
|
|
437
|
-
try {
|
|
438
|
-
entries = await fs.readdir(current.dir, { withFileTypes: true });
|
|
439
|
-
}
|
|
440
|
-
catch {
|
|
441
|
-
blockers.push('temp_path_readdir_failed');
|
|
442
|
-
continue;
|
|
443
|
-
}
|
|
444
|
-
for (const entry of entries) {
|
|
445
|
-
entryCount += 1;
|
|
446
|
-
if (entryCount > TEMP_RETENTION_SCAN_MAX_ENTRIES) {
|
|
447
|
-
blockers.push(`temp_path_max_entries_exceeded:${TEMP_RETENTION_SCAN_MAX_ENTRIES}`);
|
|
448
|
-
return { complete: false, latestMtimeMs, bytes, blockers: [...new Set(blockers)] };
|
|
449
|
-
}
|
|
450
|
-
const child = path.join(current.dir, entry.name);
|
|
451
|
-
const stat = await fs.lstat(child).catch(() => null);
|
|
452
|
-
if (!stat) {
|
|
453
|
-
blockers.push('temp_path_stat_failed');
|
|
454
|
-
continue;
|
|
455
|
-
}
|
|
456
|
-
latestMtimeMs = Math.max(latestMtimeMs, stat.mtimeMs);
|
|
457
|
-
if (stat.isSymbolicLink())
|
|
458
|
-
continue;
|
|
459
|
-
if (stat.isDirectory()) {
|
|
460
|
-
if (current.depth >= TEMP_RETENTION_SCAN_MAX_DEPTH) {
|
|
461
|
-
blockers.push(`temp_path_max_depth_exceeded:${TEMP_RETENTION_SCAN_MAX_DEPTH}`);
|
|
462
|
-
}
|
|
463
|
-
else {
|
|
464
|
-
stack.push({ dir: child, depth: current.depth + 1 });
|
|
465
|
-
}
|
|
466
|
-
continue;
|
|
467
|
-
}
|
|
468
|
-
if (stat.isFile())
|
|
469
|
-
bytes += stat.size;
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
return {
|
|
473
|
-
complete: blockers.length === 0,
|
|
474
|
-
latestMtimeMs,
|
|
475
|
-
bytes,
|
|
476
|
-
blockers: [...new Set(blockers)]
|
|
477
|
-
};
|
|
478
|
-
}
|
|
479
|
-
function currentProcessOwns(stat) {
|
|
480
|
-
if (typeof process.getuid !== 'function')
|
|
481
|
-
return true;
|
|
482
|
-
return stat.uid === process.getuid();
|
|
483
|
-
}
|
|
484
|
-
function sharedTempEntryMatchesProject(entryName, projectHash) {
|
|
485
|
-
return entryName === `sks-${projectHash}` || entryName.startsWith(`sks-${projectHash}-`);
|
|
486
|
-
}
|
|
487
|
-
function activeTempEnvironmentKey(target) {
|
|
488
|
-
const resolvedTarget = path.resolve(target);
|
|
489
|
-
for (const key of ['SKS_TMP_DIR', 'TMPDIR', 'TMP', 'TEMP']) {
|
|
490
|
-
const raw = process.env[key];
|
|
491
|
-
if (!raw)
|
|
492
|
-
continue;
|
|
493
|
-
const activePath = path.resolve(raw);
|
|
494
|
-
if (isWithin(resolvedTarget, activePath))
|
|
495
|
-
return key;
|
|
496
|
-
}
|
|
497
|
-
return null;
|
|
498
|
-
}
|
|
499
|
-
async function liveTempLease(target) {
|
|
500
|
-
const leasePath = path.join(target, SKS_TEMP_LEASE_FILE);
|
|
501
|
-
const stat = await fs.lstat(leasePath).catch(() => null);
|
|
502
|
-
if (!stat?.isFile() || stat.isSymbolicLink() || !currentProcessOwns(stat))
|
|
503
|
-
return null;
|
|
504
|
-
const lease = await readJson(leasePath, null).catch(() => null);
|
|
505
|
-
const pid = Number(lease?.pid);
|
|
506
|
-
if (lease?.schema !== 'sks.temp-lease.v1' || !processIdAlive(pid))
|
|
507
|
-
return null;
|
|
508
|
-
return {
|
|
509
|
-
path: leasePath,
|
|
510
|
-
pid,
|
|
511
|
-
kind: lease?.kind ? String(lease.kind) : null
|
|
512
|
-
};
|
|
513
|
-
}
|
|
514
|
-
async function removeDeadCanonicalTestLease(base, target, targetStat, dryRun, actions) {
|
|
515
|
-
if (!targetStat.isDirectory() || targetStat.isSymbolicLink() || !currentProcessOwns(targetStat))
|
|
516
|
-
return false;
|
|
517
|
-
const [realBase, realTarget] = await Promise.all([
|
|
518
|
-
fs.realpath(base).catch(() => null),
|
|
519
|
-
fs.realpath(target).catch(() => null)
|
|
520
|
-
]);
|
|
521
|
-
if (!realBase || !realTarget || path.dirname(realTarget) !== realBase || !isWithin(realBase, realTarget))
|
|
522
|
-
return false;
|
|
523
|
-
const leasePath = path.join(target, SKS_TEMP_LEASE_FILE);
|
|
524
|
-
const leaseLstat = await fs.lstat(leasePath).catch(() => null);
|
|
525
|
-
if (!leaseLstat?.isFile() || leaseLstat.isSymbolicLink() || !currentProcessOwns(leaseLstat) || leaseLstat.size > 4096)
|
|
526
|
-
return false;
|
|
527
|
-
const leaseHandle = await fs.open(leasePath, 'r').catch(() => null);
|
|
528
|
-
if (!leaseHandle)
|
|
529
|
-
return false;
|
|
530
|
-
let lease = null;
|
|
531
|
-
try {
|
|
532
|
-
const leaseStat = await leaseHandle.stat();
|
|
533
|
-
if (!leaseStat.isFile()
|
|
534
|
-
|| !currentProcessOwns(leaseStat)
|
|
535
|
-
|| leaseStat.dev !== leaseLstat.dev
|
|
536
|
-
|| leaseStat.ino !== leaseLstat.ino)
|
|
537
|
-
return false;
|
|
538
|
-
lease = JSON.parse(await leaseHandle.readFile({ encoding: 'utf8' }));
|
|
539
|
-
}
|
|
540
|
-
catch {
|
|
541
|
-
return false;
|
|
542
|
-
}
|
|
543
|
-
finally {
|
|
544
|
-
await leaseHandle.close().catch(() => undefined);
|
|
545
|
-
}
|
|
546
|
-
const leaseKeys = lease && typeof lease === 'object' && !Array.isArray(lease)
|
|
547
|
-
? Object.keys(lease).sort()
|
|
548
|
-
: [];
|
|
549
|
-
const pid = Number(lease?.pid);
|
|
550
|
-
if (lease?.schema !== 'sks.temp-lease.v1'
|
|
551
|
-
|| lease?.kind !== 'canonical-test-runner'
|
|
552
|
-
|| !Number.isSafeInteger(pid)
|
|
553
|
-
|| pid <= 0
|
|
554
|
-
|| typeof lease?.created_at !== 'string'
|
|
555
|
-
|| !Number.isFinite(Date.parse(lease.created_at))
|
|
556
|
-
|| leaseKeys.join(',') !== 'created_at,kind,pid,schema'
|
|
557
|
-
|| processIdAlive(pid))
|
|
558
|
-
return false;
|
|
559
|
-
const currentTargetStat = await fs.lstat(target).catch(() => null);
|
|
560
|
-
if (!currentTargetStat?.isDirectory()
|
|
561
|
-
|| currentTargetStat.isSymbolicLink()
|
|
562
|
-
|| !currentProcessOwns(currentTargetStat)
|
|
563
|
-
|| currentTargetStat.dev !== targetStat.dev
|
|
564
|
-
|| currentTargetStat.ino !== targetStat.ino)
|
|
565
|
-
return false;
|
|
566
|
-
const action = {
|
|
567
|
-
action: 'remove_sks_temp',
|
|
568
|
-
path: target,
|
|
569
|
-
reason: 'dead_canonical_test_lease',
|
|
570
|
-
lease_path: leasePath,
|
|
571
|
-
owner_pid: pid,
|
|
572
|
-
lease_kind: lease.kind
|
|
573
|
-
};
|
|
574
|
-
if (dryRun) {
|
|
575
|
-
actions.push(action);
|
|
576
|
-
return true;
|
|
577
|
-
}
|
|
578
|
-
const quarantine = path.join(realBase, `.sks-retention-quarantine-${process.pid}-${randomUUID()}`);
|
|
579
|
-
try {
|
|
580
|
-
await fs.rename(target, quarantine);
|
|
581
|
-
}
|
|
582
|
-
catch {
|
|
583
|
-
return false;
|
|
584
|
-
}
|
|
585
|
-
const quarantinedStat = await fs.lstat(quarantine).catch(() => null);
|
|
586
|
-
if (!quarantinedStat
|
|
587
|
-
|| quarantinedStat.dev !== targetStat.dev
|
|
588
|
-
|| quarantinedStat.ino !== targetStat.ino) {
|
|
589
|
-
if (!(await exists(target)))
|
|
590
|
-
await fs.rename(quarantine, target).catch(() => undefined);
|
|
591
|
-
return false;
|
|
592
|
-
}
|
|
593
|
-
await rmrf(quarantine);
|
|
594
|
-
actions.push(action);
|
|
595
|
-
return true;
|
|
596
|
-
}
|
|
597
|
-
function processIdAlive(pid) {
|
|
598
|
-
if (!Number.isSafeInteger(pid) || pid <= 0)
|
|
599
|
-
return false;
|
|
600
|
-
try {
|
|
601
|
-
process.kill(pid, 0);
|
|
602
|
-
return true;
|
|
603
|
-
}
|
|
604
|
-
catch (error) {
|
|
605
|
-
return error?.code === 'EPERM';
|
|
606
|
-
}
|
|
607
|
-
}
|
|
608
415
|
async function pruneTmp(root, policy, dryRun, actions) {
|
|
609
416
|
const tmp = path.join(root, '.sneakoscope', 'tmp');
|
|
610
417
|
if (!(await exists(tmp)))
|
|
@@ -1251,6 +1058,8 @@ export async function sweepSksTempDirs(root, opts = {}) {
|
|
|
1251
1058
|
const maxAgeMs = Math.max(0, Number(opts.maxAgeHours ?? 6)) * 60 * 60 * 1000;
|
|
1252
1059
|
const realRoot = await fs.realpath(path.resolve(root)).catch(() => path.resolve(root));
|
|
1253
1060
|
const projectHash = sha256(realRoot).slice(0, 12);
|
|
1061
|
+
const activeTempRoot = path.resolve(os.tmpdir());
|
|
1062
|
+
const activeTempRootLease = await liveTempLease(activeTempRoot);
|
|
1254
1063
|
const roots = [
|
|
1255
1064
|
{ base: path.join(os.tmpdir(), 'sks-gate'), external: true, shared: true },
|
|
1256
1065
|
{ base: managedSksTmpRoot(), external: true, shared: false, canonicalLeaseCleanup: true },
|
|
@@ -1264,6 +1073,20 @@ export async function sweepSksTempDirs(root, opts = {}) {
|
|
|
1264
1073
|
const base = rootSpec.base;
|
|
1265
1074
|
if (!(await exists(base)))
|
|
1266
1075
|
continue;
|
|
1076
|
+
if (rootSpec.external
|
|
1077
|
+
&& activeTempRootLease
|
|
1078
|
+
&& activeTempRootLease.kind === 'canonical-test-runner'
|
|
1079
|
+
&& isWithin(activeTempRoot, base)) {
|
|
1080
|
+
actions.push({
|
|
1081
|
+
action: 'skip_sks_temp_sweep',
|
|
1082
|
+
path: base,
|
|
1083
|
+
reason: 'active_parent_temp_lease',
|
|
1084
|
+
lease_path: activeTempRootLease.path,
|
|
1085
|
+
owner_pid: activeTempRootLease.pid,
|
|
1086
|
+
lease_kind: activeTempRootLease.kind
|
|
1087
|
+
});
|
|
1088
|
+
continue;
|
|
1089
|
+
}
|
|
1267
1090
|
if (!(await safeRetentionBase(root, base, { external: rootSpec.external }))) {
|
|
1268
1091
|
actions.push({ action: 'skip_unsafe_retention_root', path: base, reason: 'symlink_or_outside_managed_temp' });
|
|
1269
1092
|
continue;
|
package/dist/core/routes.js
CHANGED
|
@@ -661,10 +661,9 @@ export const COMMAND_CATALOG = [
|
|
|
661
661
|
{ name: 'uninstall', usage: 'sks uninstall [--dry-run] [--yes] [--keep-config] [--keep-data] [--purge-projects] [--json]', description: 'Remove SKS global skills, hooks, menu bar, state, temp files, and optional project residue while preserving user-owned content by default.' },
|
|
662
662
|
{ name: 'deps', usage: 'sks deps check [--json] [--yes]', description: 'Check Node/npm and Codex CLI readiness; pass --yes to repair missing Codex CLI tooling when supported.' },
|
|
663
663
|
{ name: 'codex', usage: 'sks codex compatibility|version|update-status [--refresh]|update|doctor|schema|current [--json]', description: 'Check Codex CLI compatibility/version/update status, run the official `codex update`, and inspect current manifest, capability, and hook-schema evidence.' },
|
|
664
|
-
{ name: 'codex-app', usage: 'sks codex-app [check|
|
|
664
|
+
{ name: 'codex-app', usage: 'sks codex-app [check|status|restart|product-design|chrome-extension|pat status|remote-control]', description: 'Check Codex App integration, Desktop Bridge readiness, Product Design plugin readiness, Codex Chrome Extension web verification readiness, PAT-safe status, first-party MCP/plugin readiness, and Codex CLI remote-control availability. Provider routing is managed only by sks bridge.' },
|
|
665
665
|
{ name: 'codex-native', usage: 'sks codex-native status|feature-broker|invocation-plan|init-deep [--json]', description: 'Inspect Codex Native feature broker readiness, invocation routing, pattern evidence, and managed memory setup.' },
|
|
666
666
|
{ name: 'hooks', usage: 'sks hooks explain|status|trust-report|replay|codex-validate|warning-check ... [--json]', description: 'Explain Codex hook events, validate current vendored event output schemas, replay fixtures, and enforce warning-zero SKS hook policies.' },
|
|
667
|
-
{ name: 'codex-lb', usage: 'sks codex-lb status|connect-test|health|metrics|doctor|circuit|repair|setup ...', description: 'Configure, run a one-request connection proof, health-check, repair, and record circuit evidence for codex-lb provider auth without confusing ChatGPT OAuth and proxy keys.' },
|
|
668
667
|
{ name: 'remote', usage: 'sks remote readiness|machines|worker ... [--json]', description: 'Inspect official Codex Remote readiness and the allowlisted proof-aware SSH stdio worker surface.' },
|
|
669
668
|
{ name: 'mad-sks', usage: 'sks mad-sks plan|run|apply|sql|apply-migration|status|close|rollback-apply ... | sks --mad [--high]', description: 'Open or inspect MAD-SKS scoped permission workflows, merged SQL-plane execution, and the native Codex permission launcher.' },
|
|
670
669
|
{ name: 'auto-review', usage: 'sks auto-review status|enable|start [--high] | sks --Auto-review --high', description: 'Enable Codex automatic approval review and launch the native Codex session with the auto-review profile.' },
|
|
@@ -18,7 +18,7 @@ export function buildIntentContract(input) {
|
|
|
18
18
|
canonical_command: normalizeCommand(input.canonicalCommand),
|
|
19
19
|
target_hashes: [...new Set(input.targetHashes)].sort(),
|
|
20
20
|
policy_version: safeIdentifier(input.policyVersion, 'intent_policy_version_invalid'),
|
|
21
|
-
|
|
21
|
+
runtime_snapshot: input.runtimeSnapshot,
|
|
22
22
|
evidence_state: input.evidenceState,
|
|
23
23
|
retry_budget: Math.max(0, Math.min(2, input.retryBudget ?? 0)),
|
|
24
24
|
risk,
|
|
@@ -34,8 +34,8 @@ export function decideIntentReplay(previous, current) {
|
|
|
34
34
|
const reasons = [];
|
|
35
35
|
if (previous.policy_version !== current.policy_version)
|
|
36
36
|
reasons.push('policy_version_changed');
|
|
37
|
-
if (previous.
|
|
38
|
-
reasons.push('
|
|
37
|
+
if (previous.runtime_snapshot !== current.runtime_snapshot)
|
|
38
|
+
reasons.push('runtime_snapshot_changed');
|
|
39
39
|
if (JSON.stringify(previous.target_hashes) !== JSON.stringify(current.target_hashes))
|
|
40
40
|
reasons.push('target_hash_changed');
|
|
41
41
|
if (previous.effect !== current.effect || previous.canonical_command !== current.canonical_command)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { LUNA_SUBAGENT_MODEL, SOL_SUBAGENT_MODEL, TERRA_SUBAGENT_MODEL } from './model-policy.js';
|
|
2
2
|
export const NARUTO_AUTH_MODES = ['managed', 'host'];
|
|
3
3
|
const IDENTIFIER_RE = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;
|
|
4
|
+
const RETIRED_DIRECT_MANAGED_PROVIDERS = new Set(['codex-lb', 'openrouter']);
|
|
4
5
|
export const NARUTO_EFFORT_TIERS = ['minimal', 'low', 'medium', 'high', 'max'];
|
|
5
6
|
function readFlagValue(args, name) {
|
|
6
7
|
const inline = args.find((arg) => arg.startsWith(`${name}=`));
|
|
@@ -55,6 +56,9 @@ export function resolveNarutoCredentialPolicy(input) {
|
|
|
55
56
|
else if (authMode === 'managed') {
|
|
56
57
|
blockers.push('naruto_model_provider_requires_host_auth_mode');
|
|
57
58
|
}
|
|
59
|
+
else if (RETIRED_DIRECT_MANAGED_PROVIDERS.has(providerRaw.value)) {
|
|
60
|
+
blockers.push('desktop_bridge_direct_provider_selection_retired');
|
|
61
|
+
}
|
|
58
62
|
else {
|
|
59
63
|
modelProvider = providerRaw.value;
|
|
60
64
|
sources.modelProvider = providerRaw.source;
|
|
@@ -149,8 +153,9 @@ function validateGpt56EffortPair(scope, model, effort, blockers) {
|
|
|
149
153
|
}
|
|
150
154
|
export function narutoCredentialConfigArgs(policy) {
|
|
151
155
|
const out = [];
|
|
152
|
-
if (policy.modelProvider)
|
|
156
|
+
if (policy.modelProvider && !RETIRED_DIRECT_MANAGED_PROVIDERS.has(policy.modelProvider)) {
|
|
153
157
|
out.push('-c', `model_provider="${policy.modelProvider}"`);
|
|
158
|
+
}
|
|
154
159
|
if (policy.forcedLoginMethod)
|
|
155
160
|
out.push('-c', `forced_login_method="${policy.forcedLoginMethod}"`);
|
|
156
161
|
return out;
|
|
@@ -124,9 +124,14 @@ export async function readOfficialSubagentConfig(root, opts = {}) {
|
|
|
124
124
|
const defaultSubagentModel = resolveLayeredValue(projectLayer.agents.default_subagent_model, globalLayer.agents.default_subagent_model, DEFAULT_OFFICIAL_SUBAGENT_MODEL, nonEmptyString);
|
|
125
125
|
const defaultSubagentReasoningEffort = resolveLayeredValue(projectLayer.agents.default_subagent_reasoning_effort, globalLayer.agents.default_subagent_reasoning_effort, DEFAULT_OFFICIAL_SUBAGENT_REASONING_EFFORT, nonEmptyString);
|
|
126
126
|
const multiAgentV2 = resolveMultiAgentV2Layer(projectLayer.features.multi_agent_v2, globalLayer.features.multi_agent_v2, effectiveMaxThreads);
|
|
127
|
+
const effectiveMultiAgentV2 = {
|
|
128
|
+
...multiAgentV2.value,
|
|
129
|
+
maxConcurrentThreadsPerSession: Math.min(multiAgentV2.value.maxConcurrentThreadsPerSession, HARD_NARUTO_MAX_THREADS + 1)
|
|
130
|
+
};
|
|
127
131
|
const depthCoerced = maxDepth.value > 1;
|
|
128
132
|
const warnings = [
|
|
129
133
|
...(depthCoerced ? [`official_subagent_max_depth_coerced_to_one:${maxDepth.value}:${maxDepth.source}`] : []),
|
|
134
|
+
...capacityNormalizationWarnings(maxThreads, multiAgentV2),
|
|
130
135
|
...(projectLayer.legacyWarnings),
|
|
131
136
|
...(globalLayer.legacyWarnings)
|
|
132
137
|
];
|
|
@@ -138,7 +143,7 @@ export async function readOfficialSubagentConfig(root, opts = {}) {
|
|
|
138
143
|
interruptMessage: interruptMessage.value,
|
|
139
144
|
defaultSubagentModel: defaultSubagentModel.value,
|
|
140
145
|
defaultSubagentReasoningEffort: defaultSubagentReasoningEffort.value,
|
|
141
|
-
multiAgentV2:
|
|
146
|
+
multiAgentV2: effectiveMultiAgentV2,
|
|
142
147
|
sources: {
|
|
143
148
|
enabled: enabled.source,
|
|
144
149
|
maxThreads: maxThreads.source,
|
|
@@ -159,11 +164,15 @@ export function officialSubagentConfigWarnings(text = '', inheritedText = '') {
|
|
|
159
164
|
const inherited = configLayer(inheritedText, 'global');
|
|
160
165
|
if (project.blockers.length || inherited.blockers.length)
|
|
161
166
|
return [];
|
|
167
|
+
const maxThreads = resolveLayeredValue(readAgentsMaxThreadsFromRecord(project.agents), readAgentsMaxThreadsFromRecord(inherited.agents), DEFAULT_OFFICIAL_SUBAGENT_MAX_THREADS, positiveInteger);
|
|
168
|
+
const effectiveMaxThreads = Math.min(maxThreads.value, HARD_NARUTO_MAX_THREADS);
|
|
169
|
+
const multiAgentV2 = resolveMultiAgentV2Layer(project.features.multi_agent_v2, inherited.features.multi_agent_v2, effectiveMaxThreads);
|
|
162
170
|
const maxDepth = resolveLayeredValue(project.agents.max_depth, inherited.agents.max_depth, DEFAULT_OFFICIAL_SUBAGENT_MAX_DEPTH, positiveInteger);
|
|
163
171
|
return [
|
|
164
172
|
...(maxDepth.value > 1
|
|
165
173
|
? [`official_subagent_max_depth_coerced_to_one:${maxDepth.value}:${maxDepth.source}`]
|
|
166
174
|
: []),
|
|
175
|
+
...capacityNormalizationWarnings(maxThreads, multiAgentV2),
|
|
167
176
|
...project.legacyWarnings,
|
|
168
177
|
...inherited.legacyWarnings
|
|
169
178
|
];
|
|
@@ -364,16 +373,8 @@ function configLayer(text, label) {
|
|
|
364
373
|
...(configuredMaxThreads !== undefined && positiveInteger(configuredMaxThreads) === null
|
|
365
374
|
? [`${label}_official_subagent_max_threads_invalid`]
|
|
366
375
|
: []),
|
|
367
|
-
...(positiveInteger(configuredMaxThreads) !== null
|
|
368
|
-
&& Number(configuredMaxThreads) > HARD_NARUTO_MAX_THREADS
|
|
369
|
-
? [`${label}_official_subagent_max_threads_exceeds_hard_cap:${configuredMaxThreads}:${HARD_NARUTO_MAX_THREADS}`]
|
|
370
|
-
: []),
|
|
371
376
|
...(configuredV2Threads !== undefined && positiveInteger(configuredV2Threads) === null
|
|
372
377
|
? [`${label}_official_subagent_multi_agent_v2_max_threads_invalid`]
|
|
373
|
-
: []),
|
|
374
|
-
...(positiveInteger(configuredV2Threads) !== null
|
|
375
|
-
&& Number(configuredV2Threads) > HARD_NARUTO_MAX_THREADS + 1
|
|
376
|
-
? [`${label}_official_subagent_multi_agent_v2_max_threads_exceeds_hard_cap:${configuredV2Threads}:${HARD_NARUTO_MAX_THREADS + 1}`]
|
|
377
378
|
: [])
|
|
378
379
|
],
|
|
379
380
|
legacyWarnings
|
|
@@ -393,6 +394,23 @@ function resolveMultiAgentV2Layer(projectValue, globalValue, maxThreads) {
|
|
|
393
394
|
return { value: global, source: 'global' };
|
|
394
395
|
return { value: fallback, source: 'default' };
|
|
395
396
|
}
|
|
397
|
+
function capacityNormalizationWarnings(maxThreads, multiAgentV2) {
|
|
398
|
+
return [
|
|
399
|
+
...(maxThreads.value > HARD_NARUTO_MAX_THREADS
|
|
400
|
+
? [
|
|
401
|
+
`official_subagent_max_threads_normalized:configured=${maxThreads.value}`
|
|
402
|
+
+ `:effective=${HARD_NARUTO_MAX_THREADS}:source=${maxThreads.source}`
|
|
403
|
+
]
|
|
404
|
+
: []),
|
|
405
|
+
...(multiAgentV2.value.maxConcurrentThreadsPerSession > HARD_NARUTO_MAX_THREADS + 1
|
|
406
|
+
? [
|
|
407
|
+
'official_subagent_multi_agent_v2_max_threads_normalized'
|
|
408
|
+
+ `:configured=${multiAgentV2.value.maxConcurrentThreadsPerSession}`
|
|
409
|
+
+ `:effective=${HARD_NARUTO_MAX_THREADS + 1}:source=${multiAgentV2.source}`
|
|
410
|
+
]
|
|
411
|
+
: [])
|
|
412
|
+
];
|
|
413
|
+
}
|
|
396
414
|
function normalizeMultiAgentV2(value, fallback) {
|
|
397
415
|
if (value === true) {
|
|
398
416
|
return { ...fallback, enabled: true };
|
|
@@ -3,7 +3,7 @@ import os from 'node:os';
|
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { randomId, runProcess, writeJsonAtomic } from '../fsx.js';
|
|
5
5
|
import { DEFAULT_SUBAGENT_EFFORT, DEFAULT_SUBAGENT_MODEL, NARUTO_PARENT_EFFORT, NARUTO_PARENT_MODEL } from './model-policy.js';
|
|
6
|
-
import {
|
|
6
|
+
import { inspectDesktopBridgeCliLaunchGuard, stripRetiredDirectProviderEnv } from '../codex-control/desktop-bridge-launch-guard.js';
|
|
7
7
|
import { prepareCodexAppServerRuntimeEnv } from '../codex-control/codex-app-server-runtime-env.js';
|
|
8
8
|
import { probeNarutoCodexCapability } from '../codex-compat/codex-capability-matrix.js';
|
|
9
9
|
import { resolveOfficialCodexPackageRuntime } from '../codex-runtime/resolve-codex-runtime.js';
|
|
@@ -359,27 +359,12 @@ export async function runOfficialSubagentWorkflow(input) {
|
|
|
359
359
|
hostCapabilityLaunchNonce = randomId(32);
|
|
360
360
|
hostCapabilityPendingDir = officialSubagentMissionDir(canonicalRoot, input.missionId);
|
|
361
361
|
}
|
|
362
|
-
const sourceEnv = { ...process.env, ...(input.env || {}) };
|
|
363
|
-
const
|
|
362
|
+
const sourceEnv = stripRetiredDirectProviderEnv({ ...process.env, ...(input.env || {}) });
|
|
363
|
+
const preparedRuntimeEnv = input.credentialPolicy?.authMode === 'managed'
|
|
364
364
|
? sourceEnv
|
|
365
365
|
: await (input.prepareCodexRuntimeEnvImpl || prepareCodexAppServerRuntimeEnv)({ env: sourceEnv });
|
|
366
|
-
const
|
|
367
|
-
const
|
|
368
|
-
? resolveNarutoCredentialPolicy({
|
|
369
|
-
args: ['--auth-mode=host', '--model-provider=codex-lb', '--provider-env-key=CODEX_LB_API_KEY'],
|
|
370
|
-
env: runtimeEnv,
|
|
371
|
-
defaultParentModel: NARUTO_PARENT_MODEL,
|
|
372
|
-
defaultParentEffort: NARUTO_PARENT_EFFORT,
|
|
373
|
-
defaultSubagentModel: DEFAULT_SUBAGENT_MODEL,
|
|
374
|
-
defaultSubagentEffort: DEFAULT_SUBAGENT_EFFORT
|
|
375
|
-
})
|
|
376
|
-
: defaultNarutoCredentialPolicy());
|
|
377
|
-
const credentialPolicy = codexLbCliSelected
|
|
378
|
-
&& resolvedCredentialPolicy.authMode === 'host'
|
|
379
|
-
&& resolvedCredentialPolicy.modelProvider === null
|
|
380
|
-
&& resolvedCredentialPolicy.providerEnvKey === null
|
|
381
|
-
? { ...resolvedCredentialPolicy, providerEnvKey: 'CODEX_LB_API_KEY' }
|
|
382
|
-
: resolvedCredentialPolicy;
|
|
366
|
+
const runtimeEnv = stripRetiredDirectProviderEnv(preparedRuntimeEnv);
|
|
367
|
+
const credentialPolicy = input.credentialPolicy ?? defaultNarutoCredentialPolicy();
|
|
383
368
|
const inheritedSecretValues = knownInheritedSecretValues(runtimeEnv);
|
|
384
369
|
const childEnv = buildOfficialSubagentChildEnv({
|
|
385
370
|
env: runtimeEnv,
|
|
@@ -492,27 +477,25 @@ export async function runOfficialSubagentWorkflow(input) {
|
|
|
492
477
|
hostCapabilityConfigArgs: hostCapabilityCodexConfigArgs(hostCapabilityRuntime),
|
|
493
478
|
credentialPolicy
|
|
494
479
|
});
|
|
495
|
-
const
|
|
480
|
+
const launchGuard = await inspectDesktopBridgeCliLaunchGuard({
|
|
496
481
|
root: input.root,
|
|
497
482
|
env: childEnv,
|
|
498
|
-
cliArgs: args.slice(0, -1)
|
|
499
|
-
...(input.recoveryFetch ? { fetchImpl: input.recoveryFetch } : {}),
|
|
500
|
-
...(input.recoveryTimeoutMs === undefined ? {} : { timeoutMs: input.recoveryTimeoutMs })
|
|
483
|
+
cliArgs: args.slice(0, -1)
|
|
501
484
|
});
|
|
502
|
-
if (!
|
|
485
|
+
if (!launchGuard.ok) {
|
|
503
486
|
return {
|
|
504
487
|
...base,
|
|
505
488
|
ok: false,
|
|
506
|
-
status: '
|
|
489
|
+
status: 'desktop_bridge_launch_guard_blocked',
|
|
507
490
|
prepared: false,
|
|
508
491
|
codex_exit_code: null,
|
|
509
492
|
parent_summary: null,
|
|
510
493
|
parent_summary_file: null,
|
|
511
494
|
host_capability_runtime: hostCapabilityRuntime,
|
|
512
495
|
host_capability_evidence: hostCapabilityCollector.finish(),
|
|
513
|
-
|
|
514
|
-
blockers:
|
|
515
|
-
operator_actions:
|
|
496
|
+
desktop_bridge_launch_guard: launchGuard,
|
|
497
|
+
blockers: launchGuard.blockers,
|
|
498
|
+
operator_actions: launchGuard.operator_actions,
|
|
516
499
|
completion_evidence: false
|
|
517
500
|
};
|
|
518
501
|
}
|
|
@@ -536,7 +519,7 @@ export async function runOfficialSubagentWorkflow(input) {
|
|
|
536
519
|
parent_summary_file: null,
|
|
537
520
|
host_capability_runtime: hostCapabilityRuntime,
|
|
538
521
|
host_capability_evidence: hostCapabilityCollector.finish(),
|
|
539
|
-
|
|
522
|
+
desktop_bridge_launch_guard: launchGuard,
|
|
540
523
|
blockers: ['host_capability_pending_runtime_write_failed'],
|
|
541
524
|
completion_evidence: false
|
|
542
525
|
};
|
|
@@ -611,7 +594,7 @@ export async function runOfficialSubagentWorkflow(input) {
|
|
|
611
594
|
oauth_callback_port_diagnostic: oauthCallbackPortDiagnostic,
|
|
612
595
|
host_capability_runtime: hostCapabilityRuntime,
|
|
613
596
|
host_capability_evidence: hostCapabilityEvidence,
|
|
614
|
-
|
|
597
|
+
desktop_bridge_launch_guard: launchGuard,
|
|
615
598
|
process: {
|
|
616
599
|
pid: processResult.pid || null,
|
|
617
600
|
timed_out: processResult.timedOut,
|
|
@@ -46,13 +46,16 @@ export function subagentCountContractBlockers(plan, observedStarts = 0) {
|
|
|
46
46
|
const waveCapacity = positiveCount(lifecycle?.wave_capacity)
|
|
47
47
|
|| positiveCount(plan?.first_wave)
|
|
48
48
|
|| positiveCount(plan?.capacity_controller?.selected_capacity);
|
|
49
|
-
const
|
|
49
|
+
const legacyObservedWavePeak = Array.isArray(lifecycle?.waves)
|
|
50
50
|
? lifecycle.waves.reduce((peak, wave) => {
|
|
51
51
|
if (!wave || typeof wave !== 'object' || !Array.isArray(wave.thread_ids))
|
|
52
52
|
return peak;
|
|
53
53
|
return Math.max(peak, new Set(wave.thread_ids.map(String).filter(Boolean)).size);
|
|
54
54
|
}, 0)
|
|
55
55
|
: 0;
|
|
56
|
+
const observedWavePeak = lifecycle?.peak_open_threads === undefined
|
|
57
|
+
? legacyObservedWavePeak
|
|
58
|
+
: normalizeCount(lifecycle.peak_open_threads);
|
|
56
59
|
const waveCapacityExceeded = waveCapacity > 0 && observedWavePeak > waveCapacity;
|
|
57
60
|
return [
|
|
58
61
|
...(exactTargetRejected ? ['subagent_target_change_rejected'] : []),
|
|
@@ -112,6 +115,7 @@ export function createSubagentWaveLifecycle(input) {
|
|
|
112
115
|
cumulative_completed: 0,
|
|
113
116
|
cumulative_failed: 0,
|
|
114
117
|
cumulative_settled: 0,
|
|
118
|
+
peak_open_threads: 0,
|
|
115
119
|
open_threads: 0,
|
|
116
120
|
remaining_to_start: targetSubagents,
|
|
117
121
|
post_wave_rescan_required: false,
|
|
@@ -152,12 +156,16 @@ export async function refreshSubagentWaveLifecycle(artifactDir, input = {}) {
|
|
|
152
156
|
const targetSubagents = countPolicy === 'exact' && existing
|
|
153
157
|
? requestedTargetSubagents
|
|
154
158
|
: Math.min(automaticSubagentTargetCap(plan), Math.max(requestedTargetSubagents, normalizeCount(existing?.target_subagents), startedCount));
|
|
159
|
+
const waveCapacity = positiveCount(plan.first_wave)
|
|
160
|
+
|| positiveCount(plan.capacity_controller?.selected_capacity)
|
|
161
|
+
|| positiveCount(existing?.wave_capacity)
|
|
162
|
+
|| positiveCount(plan.max_threads)
|
|
163
|
+
|| targetSubagents;
|
|
155
164
|
const next = projectLifecycle(existing || createSubagentWaveLifecycle({
|
|
156
165
|
workflowRunId,
|
|
157
166
|
targetSubagents,
|
|
158
167
|
countPolicy,
|
|
159
|
-
waveCapacity
|
|
160
|
-
|| positiveCount(plan.capacity_controller?.selected_capacity)
|
|
168
|
+
waveCapacity
|
|
161
169
|
}), {
|
|
162
170
|
workflowRunId,
|
|
163
171
|
requestedTargetSubagents,
|
|
@@ -165,8 +173,7 @@ export async function refreshSubagentWaveLifecycle(artifactDir, input = {}) {
|
|
|
165
173
|
countPolicy,
|
|
166
174
|
events,
|
|
167
175
|
evidence: input.evidence || null,
|
|
168
|
-
waveCapacity
|
|
169
|
-
|| positiveCount(plan.capacity_controller?.selected_capacity),
|
|
176
|
+
waveCapacity,
|
|
170
177
|
lastEvent: input.event?.event_name || null,
|
|
171
178
|
targetChangeRejected: existing?.target_change_rejected === true || (countPolicy === 'exact'
|
|
172
179
|
&& Boolean(existing)
|
|
@@ -230,14 +237,13 @@ function projectLifecycle(previous, input) {
|
|
|
230
237
|
const cumulativeSettled = [...stops].filter((threadId) => starts.includes(threadId)).length;
|
|
231
238
|
const completed = Math.max(0, cumulativeSettled - failed.size);
|
|
232
239
|
const openThreads = Math.max(0, starts.length - cumulativeSettled);
|
|
240
|
+
const peakOpenThreads = maxConcurrentOpenThreads(input.events);
|
|
233
241
|
const remainingToStart = Math.max(0, input.targetSubagents - starts.length);
|
|
234
242
|
const lastWave = waves.at(-1);
|
|
235
243
|
const postWaveRescanRequired = Boolean(lastWave?.status === 'settled'
|
|
236
244
|
&& openThreads === 0
|
|
237
245
|
&& remainingToStart > 0);
|
|
238
|
-
const recoveredCapacity =
|
|
239
|
-
? lastWave.thread_ids.length
|
|
240
|
-
: 0;
|
|
246
|
+
const recoveredCapacity = Math.min(cumulativeSettled, Math.max(0, input.waveCapacity - openThreads));
|
|
241
247
|
const parentGuidance = buildWaveParentGuidance({
|
|
242
248
|
remaining_to_start: remainingToStart,
|
|
243
249
|
open_threads: openThreads,
|
|
@@ -260,6 +266,7 @@ function projectLifecycle(previous, input) {
|
|
|
260
266
|
cumulative_completed: completed,
|
|
261
267
|
cumulative_failed: failed.size,
|
|
262
268
|
cumulative_settled: cumulativeSettled,
|
|
269
|
+
peak_open_threads: peakOpenThreads,
|
|
263
270
|
open_threads: openThreads,
|
|
264
271
|
remaining_to_start: remainingToStart,
|
|
265
272
|
post_wave_rescan_required: postWaveRescanRequired,
|
|
@@ -283,6 +290,27 @@ function normalizeLifecycle(value, workflowRunId) {
|
|
|
283
290
|
function uniqueThreadIds(events) {
|
|
284
291
|
return [...new Set(events.map((event) => event.thread_id || '').filter(Boolean))];
|
|
285
292
|
}
|
|
293
|
+
function maxConcurrentOpenThreads(events) {
|
|
294
|
+
const started = new Set();
|
|
295
|
+
const open = new Set();
|
|
296
|
+
let peak = 0;
|
|
297
|
+
for (const event of events) {
|
|
298
|
+
const threadId = event.thread_id;
|
|
299
|
+
if (!threadId)
|
|
300
|
+
continue;
|
|
301
|
+
if (event.event_name === 'SubagentStart') {
|
|
302
|
+
if (started.has(threadId))
|
|
303
|
+
continue;
|
|
304
|
+
started.add(threadId);
|
|
305
|
+
open.add(threadId);
|
|
306
|
+
peak = Math.max(peak, open.size);
|
|
307
|
+
continue;
|
|
308
|
+
}
|
|
309
|
+
if (started.has(threadId))
|
|
310
|
+
open.delete(threadId);
|
|
311
|
+
}
|
|
312
|
+
return peak;
|
|
313
|
+
}
|
|
286
314
|
function latestEventTime(events, name, threadIds) {
|
|
287
315
|
const allowed = new Set(threadIds);
|
|
288
316
|
return events
|
|
@@ -19,7 +19,8 @@ export function buildWaveParentGuidance(lifecycle) {
|
|
|
19
19
|
}
|
|
20
20
|
if (rescan || remaining > 0) {
|
|
21
21
|
actions.push(REFRESH_LIFECYCLE_ACTION);
|
|
22
|
-
const
|
|
22
|
+
const reusableSlots = Math.max(0, waveCapacity - openThreads);
|
|
23
|
+
const nextWaveLimit = Math.min(remaining, reusableSlots);
|
|
23
24
|
if (nextWaveLimit > 0) {
|
|
24
25
|
actions.push(`${SPAWN_NEXT_WAVE_ACTION}:${nextWaveLimit}`);
|
|
25
26
|
}
|
|
@@ -123,8 +123,8 @@ async function probeTelegramReceipt(receiptPath, now) {
|
|
|
123
123
|
token_configured: receipt.token_configured,
|
|
124
124
|
token_source: receipt.token_source ?? (receipt.token_configured ? 'unknown' : 'none'),
|
|
125
125
|
bot_identity_valid: receipt.bot_identity_valid,
|
|
126
|
-
getme_checked_at: receipt.getme_checked_at,
|
|
127
|
-
getme_latency_ms: receipt.getme_latency_ms,
|
|
126
|
+
getme_checked_at: receipt.getme_checked_at ?? null,
|
|
127
|
+
getme_latency_ms: receipt.getme_latency_ms ?? null,
|
|
128
128
|
getme_check_kind: 'receipt',
|
|
129
129
|
paired_chat_count: receipt.paired_chat_count,
|
|
130
130
|
audit_healthy: receipt.audit_healthy !== false,
|
|
@@ -89,8 +89,9 @@ function isTelegramLivenessReceipt(value) {
|
|
|
89
89
|
&& (row.token_source === undefined || ['env', 'user_secret_file', 'none', 'unknown'].includes(String(row.token_source)))
|
|
90
90
|
&& optionalPositiveSafeInteger(row.bot_id)
|
|
91
91
|
&& typeof row.bot_identity_valid === 'boolean'
|
|
92
|
-
&&
|
|
93
|
-
&& (row.getme_latency_ms ===
|
|
92
|
+
&& optionalNullableIso(row.getme_checked_at)
|
|
93
|
+
&& (row.getme_latency_ms === undefined || row.getme_latency_ms === null
|
|
94
|
+
|| (Number.isFinite(row.getme_latency_ms) && Number(row.getme_latency_ms) >= 0))
|
|
94
95
|
&& Number.isSafeInteger(row.paired_chat_count) && Number(row.paired_chat_count) >= 0
|
|
95
96
|
&& typeof row.started_at === 'string' && Number.isFinite(Date.parse(row.started_at))
|
|
96
97
|
&& typeof row.heartbeat_at === 'string' && Number.isFinite(Date.parse(row.heartbeat_at))
|
|
@@ -110,9 +111,14 @@ function isPollSnapshot(value) {
|
|
|
110
111
|
&& typeof row.running === 'boolean'
|
|
111
112
|
&& Number.isSafeInteger(row.offset) && Number(row.offset) >= 0
|
|
112
113
|
&& Number.isSafeInteger(row.consecutive_failures) && Number(row.consecutive_failures) >= 0
|
|
113
|
-
&&
|
|
114
|
-
&& (row.
|
|
114
|
+
&& optionalNullableIso(row.last_poll_at)
|
|
115
|
+
&& optionalNullableIso(row.last_success_at)
|
|
116
|
+
&& optionalNullableIso(row.last_update_at)
|
|
117
|
+
&& (row.last_error === undefined || row.last_error === null || typeof row.last_error === 'string');
|
|
115
118
|
}
|
|
116
119
|
function nullableIso(value) {
|
|
117
120
|
return value === null || (typeof value === 'string' && Number.isFinite(Date.parse(value)));
|
|
118
121
|
}
|
|
122
|
+
function optionalNullableIso(value) {
|
|
123
|
+
return value === undefined || nullableIso(value);
|
|
124
|
+
}
|