sneakoscope 6.1.0 → 6.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 +35 -11
- package/crates/sks-core/Cargo.lock +1 -1
- package/crates/sks-core/Cargo.toml +1 -1
- package/dist/bin/fast-inline.js +18 -9
- package/dist/bin/sks-dispatch.js +2 -2
- package/dist/cli/args.js +2 -0
- package/dist/cli/command-manifest-lite.js +2 -3
- package/dist/cli/command-registry.js +3 -4
- package/dist/cli/help-fast.js +1 -1
- package/dist/cli/install-helpers.js +116 -306
- package/dist/cli/install-tool-helpers.js +287 -0
- package/dist/cli/router.js +40 -4
- package/dist/commands/codex-lb.js +51 -20
- package/dist/commands/codex.js +39 -1
- package/dist/commands/doctor.js +242 -20
- package/dist/commands/tmux.js +5 -1
- package/dist/commands/zellij-monitor-pane.js +2 -0
- package/dist/commands/zellij-viewport-pane.js +3 -1
- package/dist/commands/zellij.js +1 -1
- package/dist/config/skills-manifest.json +59 -59
- package/dist/core/agent-bridge/agent-manifest.js +48 -0
- package/dist/core/agents/agent-command-surface.js +2 -1
- package/dist/core/agents/agent-effort-policy.js +38 -35
- package/dist/core/agents/agent-plan.js +100 -21
- package/dist/core/agents/agent-role-config.js +43 -46
- package/dist/core/agents/agent-runner-codex-exec.js +16 -3
- package/dist/core/agents/agent-schema.js +3 -2
- package/dist/core/agents/native-cli-session-swarm.js +1 -1
- package/dist/core/agents/zellij-right-lane-cockpit.js +2 -2
- package/dist/core/codex/agent-config-file-repair.js +94 -193
- package/dist/core/codex/codex-cli-update.js +723 -0
- package/dist/core/codex/codex-config-guard.js +185 -9
- package/dist/core/codex/codex-config-readability.js +21 -8
- package/dist/core/codex/codex-config-toml.js +14 -11
- package/dist/core/codex/codex-project-config-policy.js +3 -6
- package/dist/core/codex/codex-startup-config-postcheck.js +52 -42
- package/dist/core/codex-adapter.js +35 -22
- package/dist/core/codex-app/codex-agent-role-sync.js +13 -54
- package/dist/core/codex-app/codex-app-launcher.js +48 -17
- package/dist/core/codex-app/codex-app-restart.js +23 -2
- package/dist/core/codex-app/mcp-manager.js +679 -0
- package/dist/core/codex-app/sks-menubar.js +533 -8
- package/dist/core/codex-control/codex-0139-image-path-real-probe.js +15 -4
- package/dist/core/codex-control/codex-0139-web-search-probe.js +17 -6
- package/dist/core/codex-control/codex-lb-launch-recovery.js +293 -0
- package/dist/core/codex-control/codex-reliability-shield.js +89 -29
- package/dist/core/codex-control/codex-sdk-adapter.js +44 -8
- package/dist/core/codex-control/codex-task-runner.js +62 -9
- package/dist/core/codex-control/python-codex-sdk-adapter.js +30 -3
- package/dist/core/codex-exec-output-schema.js +35 -6
- package/dist/core/codex-lb/codex-lb-env.js +1 -1
- package/dist/core/codex-lb/codex-lb-tool-output-recovery.js +291 -0
- package/dist/core/codex-native/codex-native-feature-broker.js +9 -16
- package/dist/core/codex-native/codex-native-repair-transaction.js +1 -1
- package/dist/core/codex-native/core-skill-manifest.js +8 -4
- package/dist/core/codex-runtime/codex-desktop-config-policy.js +2 -3
- package/dist/core/commands/agent-bridge-command.js +23 -2
- package/dist/core/commands/agent-command.js +19 -5
- package/dist/core/commands/basic-cli.js +47 -6
- package/dist/core/commands/command-utils.js +1 -1
- package/dist/core/commands/mad-sks-command.js +76 -10
- package/dist/core/commands/menubar-command.js +94 -0
- package/dist/core/commands/naruto-command.js +645 -1156
- package/dist/core/commands/research-command.js +293 -231
- package/dist/core/commands/run-command.js +100 -23
- package/dist/core/commands/team-command.js +2 -3
- package/dist/core/commands/team-legacy-observe-command.js +94 -359
- package/dist/core/commands/wiki-command.js +11 -5
- package/dist/core/db-safety.js +2 -2
- package/dist/core/decision-lattice.js +6 -6
- package/dist/core/doctor/codex-startup-config-repair.js +8 -3
- package/dist/core/doctor/doctor-codex-startup-repair.js +6 -141
- package/dist/core/feature-fixture-executor.js +71 -7
- package/dist/core/feature-fixture-runner.js +53 -12
- package/dist/core/feature-fixtures.js +47 -14
- package/dist/core/feature-registry.js +28 -27
- package/dist/core/fsx.js +1 -0
- package/dist/core/harness-conflicts.js +18 -9
- package/dist/core/hooks-runtime/code-pack-freshness-preflight.js +14 -8
- package/dist/core/hooks-runtime/hook-io.js +8 -4
- package/dist/core/hooks-runtime/light-turn.js +70 -0
- package/dist/core/hooks-runtime/naruto-decision-gate.js +184 -0
- package/dist/core/hooks-runtime/payload-signals.js +270 -0
- package/dist/core/hooks-runtime/stop-repeat-guard.js +89 -0
- package/dist/core/hooks-runtime/team-digest.js +0 -1
- package/dist/core/hooks-runtime/tool-output-quarantine.js +93 -0
- package/dist/core/hooks-runtime.js +438 -354
- package/dist/core/init/skills.js +16 -30
- package/dist/core/init.js +144 -36
- package/dist/core/managed-assets/managed-assets-manifest.js +566 -10
- package/dist/core/mission.js +24 -1
- package/dist/core/pipeline-internals/runtime-core.js +570 -177
- package/dist/core/pipeline-internals/runtime-gates.js +174 -48
- package/dist/core/preflight/parallel-preflight-engine.js +66 -4
- package/dist/core/proof/route-adapter.js +1 -1
- package/dist/core/proof/route-proof-gate.js +7 -2
- package/dist/core/proof/selftest-proof-fixtures.js +3 -5
- package/dist/core/proof-field.js +1 -1
- package/dist/core/provider/model-router.js +42 -31
- package/dist/core/recallpulse/policy.js +12 -28
- package/dist/core/recallpulse.js +11 -6
- package/dist/core/release/npm-pack-proof.js +247 -0
- package/dist/core/release/package-dist-snapshot.js +151 -0
- package/dist/core/release/package-size-budget.js +4 -1
- package/dist/core/release/release-authorization-snapshot.js +115 -0
- package/dist/core/release/release-gate-affected-selector.js +14 -2
- package/dist/core/release/release-gate-cache-v2.js +30 -0
- package/dist/core/release/release-gate-contract.js +161 -0
- package/dist/core/release/release-gate-dag.js +1 -0
- package/dist/core/release/release-real-contract.js +90 -10
- package/dist/core/release-parallel-full-coverage.js +31 -143
- package/dist/core/research/claim-evidence-matrix.js +41 -6
- package/dist/core/research/experiment-plan.js +14 -10
- package/dist/core/research/falsification.js +9 -2
- package/dist/core/research/implementation-blueprint-densifier.js +82 -60
- package/dist/core/research/implementation-blueprint.js +32 -26
- package/dist/core/research/mock-result.js +122 -11
- package/dist/core/research/replication-pack.js +15 -8
- package/dist/core/research/research-adversarial-review.js +1068 -0
- package/dist/core/research/research-claim-builder.js +69 -17
- package/dist/core/research/research-claim-synthesizer.js +343 -0
- package/dist/core/research/research-cycle-runner.js +53 -3
- package/dist/core/research/research-falsification-runner.js +176 -0
- package/dist/core/research/research-final-reviewer.js +44 -125
- package/dist/core/research/research-plan-markdown.js +123 -0
- package/dist/core/research/research-realistic-report.js +14 -6
- package/dist/core/research/research-review-artifact-digest.js +66 -0
- package/dist/core/research/research-source-evidence.js +144 -0
- package/dist/core/research/research-source-layer-catalog.js +68 -0
- package/dist/core/research/research-source-ledger-merge.js +250 -12
- package/dist/core/research/research-source-shards.js +26 -70
- package/dist/core/research/research-stage-runner.js +237 -247
- package/dist/core/research/research-super-search.js +188 -0
- package/dist/core/research/research-synthesis-prompt.js +20 -1
- package/dist/core/research/research-synthesis-writer.js +86 -5
- package/dist/core/research/research-work-graph.js +25 -18
- package/dist/core/research/source-quality-report.js +21 -0
- package/dist/core/research.js +424 -390
- package/dist/core/retention.js +70 -2
- package/dist/core/routes/constants.js +1 -1
- package/dist/core/routes/dollar-manifest-lite.js +11 -11
- package/dist/core/routes.js +149 -69
- package/dist/core/runtime/task-profile.js +66 -0
- package/dist/core/runtime/verification-budget.js +12 -0
- package/dist/core/security/high-risk-contracts.js +6 -6
- package/dist/core/stop-gate/stop-gate-check.js +49 -12
- package/dist/core/subagents/agent-catalog.js +287 -0
- package/dist/core/subagents/model-policy.js +259 -0
- package/dist/core/subagents/naruto-help-contract.js +47 -0
- package/dist/core/subagents/official-subagent-config.js +488 -0
- package/dist/core/subagents/official-subagent-preparation.js +297 -0
- package/dist/core/subagents/official-subagent-prompt.js +159 -0
- package/dist/core/subagents/official-subagent-runner.js +129 -0
- package/dist/core/subagents/subagent-evidence.js +663 -0
- package/dist/core/subagents/terminology.js +16 -0
- package/dist/core/subagents/thread-budget.js +21 -0
- package/dist/core/subagents/triwiki-attention.js +168 -0
- package/dist/core/super-search/runtime-helpers.js +173 -19
- package/dist/core/super-search/runtime.js +140 -15
- package/dist/core/super-search/source-records.js +49 -8
- package/dist/core/team-review-policy.js +15 -0
- package/dist/core/triwiki/code-pack-head-freshness.js +291 -0
- package/dist/core/triwiki/triwiki-module-card.js +1 -1
- package/dist/core/triwiki-wrongness/wrongness-ledger.js +9 -2
- package/dist/core/version-manager.js +51 -1
- package/dist/core/version.js +1 -1
- package/dist/core/work-order-ledger.js +40 -1
- package/dist/core/zellij/zellij-fake-adapter.js +3 -1
- package/dist/core/zellij/zellij-launcher.js +49 -10
- package/dist/core/zellij/zellij-layout-builder.js +14 -5
- package/dist/core/zellij/zellij-official-subagent-activity.js +477 -0
- package/dist/core/zellij/zellij-official-subagent-telemetry.js +264 -0
- package/dist/core/zellij/zellij-pane-proof.js +9 -1
- package/dist/core/zellij/zellij-slot-pane-renderer.js +17 -5
- package/dist/core/zellij/zellij-slot-telemetry.js +15 -3
- package/dist/core/zellij/zellij-ui-mode.js +1 -1
- package/dist/core/zellij/zellij-update.js +14 -1
- package/dist/core/zellij/zellij-viewport-binder.js +3 -0
- package/dist/scripts/agent-role-config-repair-check.js +14 -16
- package/dist/scripts/architecture-guard-check.js +8 -1
- package/dist/scripts/canonical-test-runner.js +7 -1
- package/dist/scripts/check-route-modularity.js +0 -1
- package/dist/scripts/check-ts-contracts.js +1 -1
- package/dist/scripts/codex-control-all-pipelines-check.js +7 -3
- package/dist/scripts/codex-control-tool-output-continuity-audit-check.js +27 -0
- package/dist/scripts/codex-lb-fast-mode-truth-check.js +11 -1
- package/dist/scripts/codex-lb-fast-ui-preservation-check.js +9 -2
- package/dist/scripts/codex-lb-gpt56-fast-profile-check.js +13 -2
- package/dist/scripts/codex-native-agent-role-content-check.js +27 -7
- package/dist/scripts/codex-native-repair-transaction-check.js +3 -1
- package/dist/scripts/codex-sdk-all-pipelines-check.js +7 -4
- package/dist/scripts/codex-sdk-backend-router-check.js +2 -0
- package/dist/scripts/codex-sdk-research-pipeline-check.js +30 -8
- package/dist/scripts/db-route-materialization-check.js +33 -0
- package/dist/scripts/docs-truthfulness-check.js +3 -1
- package/dist/scripts/doctor-codex-startup-repair-check.js +12 -15
- package/dist/scripts/doctor-fix-production-blackbox.js +12 -2
- package/dist/scripts/doctor-startup-config-repair-blackbox.js +8 -2
- package/dist/scripts/doctor-startup-config-repair-check.js +12 -2
- package/dist/scripts/install-update-preserves-config-check.js +6 -1
- package/dist/scripts/lib/codex-sdk-gate-lib.js +4 -0
- package/dist/scripts/mad-sks-app-ui-no-mutation-check.js +0 -1
- package/dist/scripts/managed-role-manifest-parity-check.js +5 -4
- package/dist/scripts/naruto-codex-e2e-check.js +14 -7
- package/dist/scripts/naruto-shadow-clone-swarm-check.js +4 -201
- package/dist/scripts/npm-publish-performance-check.js +20 -12
- package/dist/scripts/official-subagent-workflow-check.js +145 -0
- package/dist/scripts/package-published-contract-check.js +6 -29
- package/dist/scripts/packlist-performance-check.js +18 -21
- package/dist/scripts/parallel-verification-engine-check.js +2 -2
- package/dist/scripts/prepublish-release-check-or-fast.js +23 -86
- package/dist/scripts/python-codex-sdk-all-pipelines-check.js +8 -0
- package/dist/scripts/release-affected-selector-check.js +74 -1
- package/dist/scripts/release-check-stamp.js +153 -248
- package/dist/scripts/release-dag-full-coverage-check.js +7 -15
- package/dist/scripts/release-dynamic-presets-check.js +2 -1
- package/dist/scripts/release-gate-dag-runner-check.js +0 -1
- package/dist/scripts/release-gate-dag-runner.js +12 -1
- package/dist/scripts/release-gate-existence-audit.js +1 -2
- package/dist/scripts/release-parallel-full-coverage-check.js +12 -6
- package/dist/scripts/release-parallel-speed-budget-check.js +18 -2
- package/dist/scripts/release-real-check.js +26 -4
- package/dist/scripts/release-registry-check.js +61 -16
- package/dist/scripts/research-blueprint-densifier-check.js +2 -2
- package/dist/scripts/research-real-cycle-no-legacy-final-md-check.js +11 -7
- package/dist/scripts/sizecheck.js +2 -2
- package/dist/scripts/sks-3-1-4-directive-check-lib.js +8 -2
- package/dist/scripts/sks-3-1-5-directive-check-lib.js +3 -2
- package/dist/scripts/sks-3-1-6-directive-check-lib.js +5 -3
- package/dist/scripts/sks-menubar-install-check.js +14 -1
- package/dist/scripts/super-search-provider-interface-check.js +31 -18
- package/dist/scripts/trust-fixture-check.js +32 -10
- package/dist/scripts/wrongness-fixture-check.js +1 -1
- package/dist/scripts/zellij-layout-valid-check.js +5 -5
- package/dist/scripts/zellij-spawn-on-demand-layout-check.js +3 -3
- package/docs/demo.tape +1 -1
- package/infra-harness-gates.json +1486 -0
- package/package.json +15 -10
- package/release-gates.v2.json +4060 -0
- package/runtime-required-scripts.json +9 -0
- package/dist/commands/db.js +0 -6
- package/dist/core/commands/db-command.js +0 -146
- package/dist/core/research/prompt.js +0 -15
- package/dist/scripts/codex-0139-feature-probes-check.js +0 -30
- package/dist/scripts/codex-0139-marketplace-source-check.js +0 -13
- package/dist/scripts/codex-control-tool-call-sequence-repair-check.js +0 -14
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
|
+
import fsp from 'node:fs/promises';
|
|
3
|
+
import { randomBytes } from 'node:crypto';
|
|
2
4
|
import { appendJsonl, ensureDir, nowIso, readText, sha256, writeTextAtomic } from '../fsx.js';
|
|
3
5
|
import { diffCodexAppUiSnapshots, snapshotCodexAppUiState } from '../codex-app/codex-app-ui-state-snapshot.js';
|
|
4
6
|
import { cleanupCodexConfigBackups, validateCodexConfigRoundTrip } from './codex-config-toml.js';
|
|
@@ -9,7 +11,7 @@ export async function writeCodexConfigGuarded(input) {
|
|
|
9
11
|
const root = path.resolve(input.root || process.cwd());
|
|
10
12
|
const cause = input.cause || 'codex-config';
|
|
11
13
|
const before = input.before === undefined ? String(await readText(configPath, '')) : String(input.before || '');
|
|
12
|
-
if (isUnmanagedProjectCodexConfig(root, configPath, before)) {
|
|
14
|
+
if (isUnmanagedProjectCodexConfig(root, configPath, before) && input.ownershipVerified !== true) {
|
|
13
15
|
const result = { ok: false, status: 'blocked_unmanaged_project_config', config_path: configPath, backup_path: null, changed: false };
|
|
14
16
|
await recordCodexConfigGuard(root, input.reportPath, {
|
|
15
17
|
cause,
|
|
@@ -38,10 +40,13 @@ export async function writeCodexConfigGuarded(input) {
|
|
|
38
40
|
return result;
|
|
39
41
|
}
|
|
40
42
|
const beforeSnapshot = await snapshotForConfig(root, configPath).catch(() => null);
|
|
41
|
-
|
|
43
|
+
const normalizeText = input.preserveTextFormatting === true
|
|
44
|
+
? (value) => String(value || '')
|
|
45
|
+
: ensureTrailingNewline;
|
|
46
|
+
let next = normalizeText(await input.mutate(before));
|
|
42
47
|
if (input.removeTopLevelModeLocks === true)
|
|
43
48
|
next = removeLegacyTopLevelCodexModeLocks(next);
|
|
44
|
-
const preserved = input.preserveFastUiKeys === false ? { text:
|
|
49
|
+
const preserved = input.preserveFastUiKeys === false ? { text: normalizeText(next), keys: [] } : mergeLostFastUiKeys(before, next);
|
|
45
50
|
next = preserved.text;
|
|
46
51
|
if (input.removeTopLevelModeLocks === true)
|
|
47
52
|
next = removeLegacyTopLevelCodexModeLocks(next);
|
|
@@ -63,8 +68,29 @@ export async function writeCodexConfigGuarded(input) {
|
|
|
63
68
|
});
|
|
64
69
|
return result;
|
|
65
70
|
}
|
|
66
|
-
|
|
67
|
-
|
|
71
|
+
const expectedBefore = normalizeText(before);
|
|
72
|
+
if (next === expectedBefore) {
|
|
73
|
+
if (input.verifyUnchangedBeforeWrite === true) {
|
|
74
|
+
const observed = await readConfigCommitSnapshot(configPath);
|
|
75
|
+
const expectedExists = input.expectedBeforeExists ?? true;
|
|
76
|
+
if (!configCommitSnapshotMatches(observed, expectedExists, before)) {
|
|
77
|
+
return recordConcurrentConfigChange({
|
|
78
|
+
root,
|
|
79
|
+
reportPath: input.reportPath,
|
|
80
|
+
cause,
|
|
81
|
+
configPath,
|
|
82
|
+
before,
|
|
83
|
+
expectedExists,
|
|
84
|
+
observed,
|
|
85
|
+
backupPath: null,
|
|
86
|
+
repairedKeys: preserved.keys,
|
|
87
|
+
forbiddenTopLevel
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
await writeTextAtomic(configPath, next, { mode: 0o600 });
|
|
93
|
+
}
|
|
68
94
|
const result = { ok: true, status: 'present', config_path: configPath, backup_path: null, changed: false, repaired_keys: preserved.keys, forbidden_top_level: forbiddenTopLevel };
|
|
69
95
|
if (preserved.keys.length || forbiddenTopLevel.length) {
|
|
70
96
|
await recordCodexConfigGuard(root, input.reportPath, {
|
|
@@ -79,9 +105,37 @@ export async function writeCodexConfigGuarded(input) {
|
|
|
79
105
|
}
|
|
80
106
|
return result;
|
|
81
107
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
108
|
+
let backupPath = null;
|
|
109
|
+
if (input.verifyUnchangedBeforeWrite === true) {
|
|
110
|
+
const expectedExists = input.expectedBeforeExists ?? true;
|
|
111
|
+
const commit = await commitCodexConfigIfUnchanged({
|
|
112
|
+
configPath,
|
|
113
|
+
before,
|
|
114
|
+
next,
|
|
115
|
+
expectedExists,
|
|
116
|
+
backupTag: input.backupTag || cause
|
|
117
|
+
});
|
|
118
|
+
if (!commit.ok) {
|
|
119
|
+
return recordConcurrentConfigChange({
|
|
120
|
+
root,
|
|
121
|
+
reportPath: input.reportPath,
|
|
122
|
+
cause,
|
|
123
|
+
configPath,
|
|
124
|
+
before,
|
|
125
|
+
expectedExists,
|
|
126
|
+
observed: commit.observed,
|
|
127
|
+
backupPath: commit.backupPath,
|
|
128
|
+
repairedKeys: preserved.keys,
|
|
129
|
+
forbiddenTopLevel
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
backupPath = commit.backupPath;
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
backupPath = before.trim() ? await backupCodexConfig(configPath, before, input.backupTag || cause) : null;
|
|
136
|
+
await ensureDir(path.dirname(configPath));
|
|
137
|
+
await writeTextAtomic(configPath, next, { mode: 0o600 });
|
|
138
|
+
}
|
|
85
139
|
const afterSnapshot = await snapshotForConfig(root, configPath).catch(() => null);
|
|
86
140
|
const diff = beforeSnapshot && afterSnapshot ? diffCodexAppUiSnapshots(beforeSnapshot, afterSnapshot) : null;
|
|
87
141
|
const result = {
|
|
@@ -115,6 +169,123 @@ export async function writeCodexConfigGuarded(input) {
|
|
|
115
169
|
});
|
|
116
170
|
return { ...result, report_path: reportPath };
|
|
117
171
|
}
|
|
172
|
+
function configCommitSnapshotMatches(observed, expectedExists, expectedText) {
|
|
173
|
+
return observed.ok
|
|
174
|
+
&& observed.exists === expectedExists
|
|
175
|
+
&& sha256(observed.text) === sha256(expectedText);
|
|
176
|
+
}
|
|
177
|
+
async function recordConcurrentConfigChange(input) {
|
|
178
|
+
const result = {
|
|
179
|
+
ok: false,
|
|
180
|
+
status: 'concurrent_change_detected',
|
|
181
|
+
config_path: input.configPath,
|
|
182
|
+
backup_path: input.backupPath,
|
|
183
|
+
changed: false,
|
|
184
|
+
repaired_keys: input.repairedKeys,
|
|
185
|
+
forbidden_top_level: input.forbiddenTopLevel
|
|
186
|
+
};
|
|
187
|
+
await recordCodexConfigGuard(input.root, input.reportPath, {
|
|
188
|
+
cause: input.cause,
|
|
189
|
+
config_path: input.configPath,
|
|
190
|
+
ok: false,
|
|
191
|
+
status: result.status,
|
|
192
|
+
expected_exists: input.expectedExists,
|
|
193
|
+
observed_exists: input.observed.exists,
|
|
194
|
+
expected_sha256: sha256(input.before),
|
|
195
|
+
observed_sha256: input.observed.ok ? sha256(input.observed.text) : null,
|
|
196
|
+
observed_status: input.observed.status,
|
|
197
|
+
backup_path: input.backupPath,
|
|
198
|
+
changed: false
|
|
199
|
+
});
|
|
200
|
+
return result;
|
|
201
|
+
}
|
|
202
|
+
async function commitCodexConfigIfUnchanged(input) {
|
|
203
|
+
await ensureDir(path.dirname(input.configPath));
|
|
204
|
+
const token = `${Date.now().toString(36)}-${process.pid}-${randomBytes(6).toString('hex')}`;
|
|
205
|
+
const candidatePath = `${input.configPath}.sks-commit-${token}.tmp`;
|
|
206
|
+
let backupPath = null;
|
|
207
|
+
try {
|
|
208
|
+
await writeTextAtomic(candidatePath, input.next, { mode: 0o600 });
|
|
209
|
+
const observed = await readConfigCommitSnapshot(input.configPath);
|
|
210
|
+
if (!configCommitSnapshotMatches(observed, input.expectedExists, input.before)) {
|
|
211
|
+
return { ok: false, backupPath, observed };
|
|
212
|
+
}
|
|
213
|
+
if (input.expectedExists) {
|
|
214
|
+
backupPath = `${input.configPath}.sks-${safeBackupTag(input.backupTag)}-${token}.bak`;
|
|
215
|
+
try {
|
|
216
|
+
await fsp.rename(input.configPath, backupPath);
|
|
217
|
+
}
|
|
218
|
+
catch {
|
|
219
|
+
return { ok: false, backupPath: null, observed: await readConfigCommitSnapshot(input.configPath) };
|
|
220
|
+
}
|
|
221
|
+
const claimed = await readConfigCommitSnapshot(backupPath);
|
|
222
|
+
if (!configCommitSnapshotMatches(claimed, true, input.before)) {
|
|
223
|
+
await restoreClaimedConfigIfAbsent(backupPath, input.configPath, claimed);
|
|
224
|
+
return { ok: false, backupPath, observed: claimed };
|
|
225
|
+
}
|
|
226
|
+
try {
|
|
227
|
+
await fsp.chmod(backupPath, 0o600);
|
|
228
|
+
const now = new Date();
|
|
229
|
+
await fsp.utimes(backupPath, now, now);
|
|
230
|
+
}
|
|
231
|
+
catch {
|
|
232
|
+
await restoreClaimedConfigIfAbsent(backupPath, input.configPath, claimed);
|
|
233
|
+
return { ok: false, backupPath, observed: await readConfigCommitSnapshot(input.configPath) };
|
|
234
|
+
}
|
|
235
|
+
const afterClaim = await readConfigCommitSnapshot(input.configPath);
|
|
236
|
+
if (!afterClaim.ok || afterClaim.exists) {
|
|
237
|
+
if (!afterClaim.exists)
|
|
238
|
+
await restoreClaimedConfigIfAbsent(backupPath, input.configPath, claimed);
|
|
239
|
+
return { ok: false, backupPath, observed: await readConfigCommitSnapshot(input.configPath) };
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
try {
|
|
243
|
+
await fsp.link(candidatePath, input.configPath);
|
|
244
|
+
}
|
|
245
|
+
catch {
|
|
246
|
+
if (backupPath) {
|
|
247
|
+
const claimed = await readConfigCommitSnapshot(backupPath);
|
|
248
|
+
await restoreClaimedConfigIfAbsent(backupPath, input.configPath, claimed);
|
|
249
|
+
}
|
|
250
|
+
return { ok: false, backupPath, observed: await readConfigCommitSnapshot(input.configPath) };
|
|
251
|
+
}
|
|
252
|
+
await fsp.chmod(input.configPath, 0o600).catch(() => undefined);
|
|
253
|
+
await cleanupCodexConfigBackups(input.configPath, { keepPerTag: 3, maxAgeMs: 30 * 24 * 60 * 60 * 1000 }).catch(() => undefined);
|
|
254
|
+
return { ok: true, backupPath };
|
|
255
|
+
}
|
|
256
|
+
finally {
|
|
257
|
+
await fsp.rm(candidatePath, { force: true }).catch(() => undefined);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
async function restoreClaimedConfigIfAbsent(backupPath, configPath, claimed) {
|
|
261
|
+
if (!claimed.ok || !claimed.exists || claimed.status !== 'regular')
|
|
262
|
+
return;
|
|
263
|
+
await fsp.link(backupPath, configPath).catch(() => undefined);
|
|
264
|
+
}
|
|
265
|
+
function safeBackupTag(value) {
|
|
266
|
+
return String(value || 'codex-config').replace(/[^A-Za-z0-9_.-]+/g, '-').replace(/^-+|-+$/g, '').slice(0, 96) || 'codex-config';
|
|
267
|
+
}
|
|
268
|
+
async function readConfigCommitSnapshot(configPath) {
|
|
269
|
+
let stat;
|
|
270
|
+
try {
|
|
271
|
+
stat = await fsp.lstat(configPath);
|
|
272
|
+
}
|
|
273
|
+
catch (error) {
|
|
274
|
+
if (error?.code === 'ENOENT')
|
|
275
|
+
return { ok: true, exists: false, text: '', status: 'missing' };
|
|
276
|
+
return { ok: false, exists: false, text: '', status: 'read_failed' };
|
|
277
|
+
}
|
|
278
|
+
if (stat.isSymbolicLink())
|
|
279
|
+
return { ok: false, exists: true, text: '', status: 'symlink' };
|
|
280
|
+
if (!stat.isFile())
|
|
281
|
+
return { ok: false, exists: true, text: '', status: 'non_regular' };
|
|
282
|
+
try {
|
|
283
|
+
return { ok: true, exists: true, text: await fsp.readFile(configPath, 'utf8'), status: 'regular' };
|
|
284
|
+
}
|
|
285
|
+
catch {
|
|
286
|
+
return { ok: false, exists: true, text: '', status: 'read_failed' };
|
|
287
|
+
}
|
|
288
|
+
}
|
|
118
289
|
export function extractTomlTable(text, tableName) {
|
|
119
290
|
const source = String(text || '');
|
|
120
291
|
const header = `[${tableName}]`;
|
|
@@ -146,7 +317,12 @@ export function isProjectCodexConfig(root, configPath) {
|
|
|
146
317
|
return path.resolve(configPath) === path.resolve(root, '.codex', 'config.toml');
|
|
147
318
|
}
|
|
148
319
|
export function hasSksManagedCodexConfigMarker(text) {
|
|
149
|
-
|
|
320
|
+
const source = String(text || '');
|
|
321
|
+
return /^\s*#\s*SKS-MANAGED-CODEX-CONFIG\b/im.test(source)
|
|
322
|
+
|| /(?:SKS managed|Sneakoscope|sneakoscope|sks_|agents\.native_agent|agents\.implementation_worker|multi_agent)/i.test(source)
|
|
323
|
+
|| /^\s*model_provider\s*=\s*["']codex-lb["']\s*(?:#.*)?$/mi.test(source)
|
|
324
|
+
|| /^\s*default_profile\s*=\s*["']sks-fast-high["']\s*(?:#.*)?$/mi.test(source)
|
|
325
|
+
|| /^\s*\[(?:user\.fast_mode|model_providers\.(?:"codex-lb"|codex-lb)|profiles\.(?:"sks-fast-high"|sks-fast-high))\]\s*(?:#.*)?$/mi.test(source);
|
|
150
326
|
}
|
|
151
327
|
export function isUnmanagedProjectCodexConfig(root, configPath, text) {
|
|
152
328
|
return isProjectCodexConfig(root, configPath)
|
|
@@ -50,16 +50,29 @@ export async function inspectCodexConfigReadability(rootInput = process.cwd(), o
|
|
|
50
50
|
}
|
|
51
51
|
add({ name: 'config_symlink', ok: !isSymlink || symlinkDetail.allowed === true, detail: symlinkDetail });
|
|
52
52
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
const readChecksPromise = Promise.all([
|
|
54
|
+
nodeReadCheck(configPath),
|
|
55
|
+
childReadCheck(configPath, root),
|
|
56
|
+
codexCliConfigLoadCheck(root, configPath, opts)
|
|
57
|
+
]);
|
|
58
|
+
// These are independent read-only metadata probes. Running them serially
|
|
59
|
+
// multiplied a single TCC/ACL timeout by three on the MAD launch path.
|
|
60
|
+
const macChecksPromise = process.platform === 'darwin'
|
|
61
|
+
? Promise.all([
|
|
62
|
+
commandCheck('macos_acl_ls_le', 'ls', ['-le', configPath], root),
|
|
63
|
+
commandCheck('macos_flags_ls_lO', 'ls', ['-lO', configPath], root),
|
|
64
|
+
commandCheck('macos_xattr', 'xattr', ['-l', configPath], root, { allowExitCodes: [0, 1] })
|
|
65
|
+
])
|
|
66
|
+
: Promise.resolve(null);
|
|
67
|
+
const [[nodeRead, childRead, codexLoad], macChecks] = await Promise.all([readChecksPromise, macChecksPromise]);
|
|
68
|
+
if (macChecks) {
|
|
69
|
+
const [acl, flags, xattrs] = macChecks;
|
|
70
|
+
add(acl);
|
|
56
71
|
if (/\bdeny\b.*\b(read|readattr|readextattr|readsecurity|search)\b/i.test(String(acl?.detail?.stdout || '')))
|
|
57
72
|
blockers.add('acl_denied');
|
|
58
|
-
const flags = await commandCheck('macos_flags_ls_lO', 'ls', ['-lO', configPath], root);
|
|
59
73
|
add(flags);
|
|
60
74
|
if (/\b(uchg|schg|restricted)\b/.test(String(flags.detail?.stdout || '')))
|
|
61
75
|
blockers.add('flags_locked');
|
|
62
|
-
const xattrs = await commandCheck('macos_xattr', 'xattr', ['-l', configPath], root, { allowExitCodes: [0, 1] });
|
|
63
76
|
add(xattrs);
|
|
64
77
|
add({ name: 'macos_quarantine_xattr', ok: !/com\.apple\.quarantine/.test(String(xattrs.detail?.stdout || '')), detail: { present: /com\.apple\.quarantine/.test(String(xattrs.detail?.stdout || '')) } });
|
|
65
78
|
if (/com\.apple\.quarantine/.test(String(xattrs.detail?.stdout || '')))
|
|
@@ -68,9 +81,9 @@ export async function inspectCodexConfigReadability(rootInput = process.cwd(), o
|
|
|
68
81
|
else {
|
|
69
82
|
add({ name: 'macos_metadata', ok: true, status: 'skipped_non_macos' });
|
|
70
83
|
}
|
|
71
|
-
add(
|
|
72
|
-
add(
|
|
73
|
-
add(
|
|
84
|
+
add(nodeRead);
|
|
85
|
+
add(childRead);
|
|
86
|
+
add(codexLoad);
|
|
74
87
|
}
|
|
75
88
|
else {
|
|
76
89
|
add({ name: 'config_file_checks', ok: true, status: 'skipped_config_missing', detail: { config_path: configPath } });
|
|
@@ -52,9 +52,8 @@ export async function cleanupCodexConfigBackups(configPath, opts = {}) {
|
|
|
52
52
|
const now = Date.now();
|
|
53
53
|
const groups = new Map();
|
|
54
54
|
for (const file of entries) {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
if (!/(?:^|[.-])(?:sks-|bak-|struct-bak-)|\.bak$/.test(file))
|
|
55
|
+
const tag = ownedBackupTag(base, file);
|
|
56
|
+
if (!tag)
|
|
58
57
|
continue;
|
|
59
58
|
const abs = path.join(dir, file);
|
|
60
59
|
let stat;
|
|
@@ -66,7 +65,6 @@ export async function cleanupCodexConfigBackups(configPath, opts = {}) {
|
|
|
66
65
|
}
|
|
67
66
|
if (!stat.isFile())
|
|
68
67
|
continue;
|
|
69
|
-
const tag = backupTag(base, file);
|
|
70
68
|
const group = groups.get(tag) || [];
|
|
71
69
|
group.push({ file, abs, mtimeMs: stat.mtimeMs });
|
|
72
70
|
groups.set(tag, group);
|
|
@@ -87,16 +85,21 @@ export async function cleanupCodexConfigBackups(configPath, opts = {}) {
|
|
|
87
85
|
}
|
|
88
86
|
return { cleaned: removed.length, files: removed };
|
|
89
87
|
}
|
|
90
|
-
function
|
|
88
|
+
function ownedBackupTag(base, file) {
|
|
89
|
+
if (!file.startsWith(`${base}.`))
|
|
90
|
+
return null;
|
|
91
91
|
const suffix = file.slice(`${base}.`.length);
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
return `sks-${
|
|
95
|
-
|
|
92
|
+
if (/^sks-[A-Za-z0-9_.-]+\.bak$/.test(suffix)) {
|
|
93
|
+
const group = suffix.match(/^sks-([^-]+)-/)?.[1] || suffix.slice('sks-'.length, -'.bak'.length);
|
|
94
|
+
return `sks-${group}`;
|
|
95
|
+
}
|
|
96
|
+
if (/^struct-bak-[A-Za-z0-9_.-]+$/.test(suffix))
|
|
96
97
|
return 'struct-bak';
|
|
97
|
-
if (
|
|
98
|
+
if (/^bak-[A-Za-z0-9_.-]+$/.test(suffix))
|
|
98
99
|
return 'bak';
|
|
99
|
-
|
|
100
|
+
if (/^codex-app-ui-repair-[A-Za-z0-9_.-]+\.bak$/.test(suffix))
|
|
101
|
+
return 'codex-app-ui-repair';
|
|
102
|
+
return null;
|
|
100
103
|
}
|
|
101
104
|
function messageOf(err) {
|
|
102
105
|
return err instanceof Error ? err.message : String(err);
|
|
@@ -2,7 +2,7 @@ import fsp from 'node:fs/promises';
|
|
|
2
2
|
import os from 'node:os';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { ensureDir, nowIso, readText, writeJsonAtomic } from '../fsx.js';
|
|
5
|
-
import { writeCodexConfigGuarded } from './codex-config-guard.js';
|
|
5
|
+
import { hasSksManagedCodexConfigMarker, writeCodexConfigGuarded } from './codex-config-guard.js';
|
|
6
6
|
import { cleanupCodexConfigBackups } from './codex-config-toml.js';
|
|
7
7
|
export const CODEX_PROJECT_CONFIG_POLICY_SCHEMA = 'sks.codex-project-config-policy.v1';
|
|
8
8
|
const MACHINE_LOCAL_TOP_LEVEL_KEYS = new Set([
|
|
@@ -95,7 +95,7 @@ export async function splitCodexProjectConfigPolicy(rootInput = process.cwd(), o
|
|
|
95
95
|
await writeJsonAtomic(reportPath, { ...report, report_path: reportPath });
|
|
96
96
|
return report;
|
|
97
97
|
}
|
|
98
|
-
if (opts.apply && isCodexConfigToml(configPath) && !
|
|
98
|
+
if (opts.apply && isCodexConfigToml(configPath) && !hasSksManagedCodexConfigMarker(String(original))) {
|
|
99
99
|
const report = {
|
|
100
100
|
schema: CODEX_PROJECT_CONFIG_POLICY_SCHEMA,
|
|
101
101
|
generated_at: nowIso(),
|
|
@@ -208,7 +208,7 @@ export async function repairCodexConfigStructure(configPathInput, opts = {}) {
|
|
|
208
208
|
if (original === null) {
|
|
209
209
|
return { config_path: configPath, ok: true, status: 'config_missing', changed: false, applied: false, hoisted_keys: [], backup_path: null };
|
|
210
210
|
}
|
|
211
|
-
if (opts.apply && isCodexConfigToml(configPath) && !
|
|
211
|
+
if (opts.apply && isCodexConfigToml(configPath) && !hasSksManagedCodexConfigMarker(String(original))) {
|
|
212
212
|
return {
|
|
213
213
|
config_path: configPath,
|
|
214
214
|
ok: false,
|
|
@@ -249,9 +249,6 @@ export async function repairCodexConfigStructure(configPathInput, opts = {}) {
|
|
|
249
249
|
function isCodexConfigToml(file) {
|
|
250
250
|
return path.basename(file) === 'config.toml' && path.basename(path.dirname(file)) === '.codex';
|
|
251
251
|
}
|
|
252
|
-
function hasSksManagedCodexMarker(text) {
|
|
253
|
-
return /(?:SKS managed|Sneakoscope|sneakoscope|sks_|agents\.native_agent|agents\.implementation_worker|multi_agent)/i.test(text);
|
|
254
|
-
}
|
|
255
252
|
function hoistMisplacedMachineLocalKeys(text) {
|
|
256
253
|
const blocks = tomlBlocks(text);
|
|
257
254
|
const preamble = [];
|
|
@@ -1,64 +1,64 @@
|
|
|
1
1
|
import fs from 'node:fs/promises';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { nowIso, writeJsonAtomic } from '../fsx.js';
|
|
4
|
-
import {
|
|
5
|
-
import { managedAgentRoleConfigForFile, managedAgentRoleConfigForRole } from '../agents/agent-role-config.js';
|
|
4
|
+
import { inspectOfficialSubagentToml, installOfficialSubagentAgentConfigs, readOfficialSubagentConfig } from '../subagents/official-subagent-config.js';
|
|
6
5
|
export async function postcheckCodexStartupConfig(input) {
|
|
7
6
|
const root = path.resolve(input.root);
|
|
8
7
|
const configPath = path.join(root, '.codex', 'config.toml');
|
|
9
8
|
const text = await fs.readFile(configPath, 'utf8').catch(() => '');
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
.
|
|
15
|
-
|
|
9
|
+
const configPresent = Boolean(text.trim());
|
|
10
|
+
const tomlValidation = inspectOfficialSubagentToml(text);
|
|
11
|
+
const officialConfig = await readOfficialSubagentConfig(root, {
|
|
12
|
+
...(input.home ? { home: input.home } : {}),
|
|
13
|
+
...(input.codexHome ? { codexHome: input.codexHome } : {}),
|
|
14
|
+
projectConfigPath: configPath
|
|
15
|
+
});
|
|
16
|
+
const rolePlan = await installOfficialSubagentAgentConfigs(root, { apply: false });
|
|
16
17
|
const tomlSmoke = tomlSyntaxSmoke(text);
|
|
17
18
|
const orphanChildTables = orphanMcpChildTables(text);
|
|
19
|
+
const blockers = [
|
|
20
|
+
...(!configPresent ? ['project_official_subagent_config_missing'] : []),
|
|
21
|
+
...(!tomlValidation.ok ? ['project_official_subagent_config_toml_parse_failed'] : []),
|
|
22
|
+
...officialConfig.blockers.map((item) => `official_subagent_config:${item}`),
|
|
23
|
+
...rolePlan.missing.map((file) => `missing_official_subagent_agent:${file}`),
|
|
24
|
+
...rolePlan.stale.map((file) => `stale_official_subagent_agent:${file}`),
|
|
25
|
+
...rolePlan.manual_blockers,
|
|
26
|
+
...tomlSmoke.blockers,
|
|
27
|
+
...orphanChildTables.map((table) => `orphan_mcp_child_table:${table}`)
|
|
28
|
+
];
|
|
18
29
|
const report = {
|
|
19
30
|
schema: 'sks.codex-startup-config-postcheck.v1',
|
|
20
31
|
generated_at: nowIso(),
|
|
21
|
-
ok:
|
|
32
|
+
ok: blockers.length === 0,
|
|
22
33
|
config_path: configPath,
|
|
23
|
-
missing_config_files:
|
|
24
|
-
relative_config_files:
|
|
25
|
-
unsupported_managed_role_fields:
|
|
34
|
+
missing_config_files: [],
|
|
35
|
+
relative_config_files: [],
|
|
36
|
+
unsupported_managed_role_fields: false,
|
|
37
|
+
official_subagent_config: {
|
|
38
|
+
max_threads: officialConfig.maxThreads,
|
|
39
|
+
max_depth: officialConfig.maxDepth,
|
|
40
|
+
job_max_runtime_seconds: officialConfig.jobMaxRuntimeSeconds,
|
|
41
|
+
interrupt_message: officialConfig.interruptMessage,
|
|
42
|
+
sources: officialConfig.sources,
|
|
43
|
+
warnings: officialConfig.warnings
|
|
44
|
+
},
|
|
45
|
+
official_subagent_agents: {
|
|
46
|
+
missing: rolePlan.missing,
|
|
47
|
+
stale: rolePlan.stale,
|
|
48
|
+
existing: rolePlan.existing,
|
|
49
|
+
preserved: rolePlan.preserved,
|
|
50
|
+
manual_blockers: rolePlan.manual_blockers
|
|
51
|
+
},
|
|
52
|
+
legacy_agent_tables_preserved: true,
|
|
26
53
|
toml_syntax_smoke_ok: tomlSmoke.ok,
|
|
27
54
|
orphan_mcp_child_tables: orphanChildTables,
|
|
28
|
-
blockers
|
|
29
|
-
...missing.map((file) => `missing_agent_config_file:${file}`),
|
|
30
|
-
...relativePaths.map((file) => `relative_agent_config_file:${file}`),
|
|
31
|
-
...(unsupportedRoleFields ? ['unsupported_message_role_prefix_field'] : []),
|
|
32
|
-
...tomlSmoke.blockers,
|
|
33
|
-
...orphanChildTables.map((table) => `orphan_mcp_child_table:${table}`)
|
|
34
|
-
]
|
|
55
|
+
blockers
|
|
35
56
|
};
|
|
36
|
-
if (input.reportPath !== null)
|
|
57
|
+
if (input.reportPath !== null) {
|
|
37
58
|
await writeJsonAtomic(input.reportPath || path.join(root, '.sneakoscope', 'reports', 'codex-startup-config-postcheck.json'), report).catch(() => undefined);
|
|
59
|
+
}
|
|
38
60
|
return report;
|
|
39
61
|
}
|
|
40
|
-
function managedAgentBlocks(text) {
|
|
41
|
-
const blocks = tomlBlocks(text);
|
|
42
|
-
return blocks.filter((block) => {
|
|
43
|
-
if (!block.header.startsWith('agents.'))
|
|
44
|
-
return false;
|
|
45
|
-
const role = block.header.slice('agents.'.length);
|
|
46
|
-
if (managedAgentRoleConfigForRole(role))
|
|
47
|
-
return true;
|
|
48
|
-
const configFile = block.text.match(/^\s*config_file\s*=\s*"([^"]+)"/m)?.[1] || '';
|
|
49
|
-
return Boolean(configFile && managedAgentRoleConfigForFile(configFile));
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
function tomlBlocks(text) {
|
|
53
|
-
const source = String(text || '');
|
|
54
|
-
const matches = [...source.matchAll(/(^|\n)\s*\[([^\]]+)\]\s*(?:#.*)?(?:\n|$)/g)];
|
|
55
|
-
return matches.map((match, index) => {
|
|
56
|
-
const start = Number(match.index || 0) + (match[1] ? 1 : 0);
|
|
57
|
-
const next = matches[index + 1];
|
|
58
|
-
const end = next ? Number(next.index || 0) + (next[1] ? 1 : 0) : source.length;
|
|
59
|
-
return { header: String(match[2] || '').trim(), text: source.slice(start, end) };
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
62
|
function tomlSyntaxSmoke(text) {
|
|
63
63
|
const blockers = [];
|
|
64
64
|
for (const [index, line] of String(text || '').split(/\r?\n/).entries()) {
|
|
@@ -80,4 +80,14 @@ function orphanMcpChildTables(text) {
|
|
|
80
80
|
return Boolean(match && !headers.has(`mcp_servers.${match[1]}`));
|
|
81
81
|
});
|
|
82
82
|
}
|
|
83
|
+
function tomlBlocks(text) {
|
|
84
|
+
const source = String(text || '');
|
|
85
|
+
const matches = [...source.matchAll(/(^|\n)\s*\[([^\]]+)\]\s*(?:#.*)?(?:\n|$)/g)];
|
|
86
|
+
return matches.map((match, index) => {
|
|
87
|
+
const start = Number(match.index || 0) + (match[1] ? 1 : 0);
|
|
88
|
+
const next = matches[index + 1];
|
|
89
|
+
const end = next ? Number(next.index || 0) + (next[1] ? 1 : 0) : source.length;
|
|
90
|
+
return { header: String(match[2] || '').trim(), text: source.slice(start, end) };
|
|
91
|
+
});
|
|
92
|
+
}
|
|
83
93
|
//# sourceMappingURL=codex-startup-config-postcheck.js.map
|
|
@@ -3,6 +3,7 @@ import { runProcess } from './fsx.js';
|
|
|
3
3
|
import { preserveCodexModelArgs } from './codex-model-guard.js';
|
|
4
4
|
import { managedProxyEnvForChild } from './codex/managed-proxy-env.js';
|
|
5
5
|
import { resolveCodexRuntime } from './codex-runtime/resolve-codex-runtime.js';
|
|
6
|
+
import { codexLbRecoveryBlockedProcessResult, withCodexLbCliLaunchRecovery } from './codex-control/codex-lb-launch-recovery.js';
|
|
6
7
|
export async function findCodexBinary() {
|
|
7
8
|
const resolved = await resolveCodexRuntime({
|
|
8
9
|
explicitPath: process.env.DCODEX_CODEX_BIN || null,
|
|
@@ -39,30 +40,42 @@ export function buildCodexExecArgs({ root, prompt, outputFile, json = true, prof
|
|
|
39
40
|
args.push(prompt);
|
|
40
41
|
return args;
|
|
41
42
|
}
|
|
42
|
-
export async function runCodexExec({ root, prompt, outputFile, json = true, profile = null, extraArgs = [], onStdout, onStderr, logDir = null, stdoutFile = null, stderrFile = null, maxBufferBytes = 256 * 1024, timeoutMs = null }) {
|
|
43
|
-
const bin = await findCodexBinary();
|
|
44
|
-
if (!bin) {
|
|
45
|
-
return {
|
|
46
|
-
code: 127,
|
|
47
|
-
stdout: '',
|
|
48
|
-
stderr: 'Codex CLI not found. Install @openai/codex or set SKS_CODEX_BIN.',
|
|
49
|
-
stdoutBytes: 0,
|
|
50
|
-
stderrBytes: 0,
|
|
51
|
-
truncated: false,
|
|
52
|
-
timedOut: false
|
|
53
|
-
};
|
|
54
|
-
}
|
|
43
|
+
export async function runCodexExec({ root, recoveryRoot = root, prompt, outputFile, json = true, profile = null, extraArgs = [], onStdout, onStderr, logDir = null, stdoutFile = null, stderrFile = null, maxBufferBytes = 256 * 1024, timeoutMs = null, env = process.env, codexBin = null, findCodexBinaryImpl = findCodexBinary, runProcessImpl = runProcess, recoveryFetch = undefined, recoveryTimeoutMs = undefined }) {
|
|
55
44
|
const args = buildCodexExecArgs({ root, prompt, outputFile, json, profile, extraArgs });
|
|
56
45
|
const effectiveTimeoutMs = Number(timeoutMs || process.env.SKS_CODEX_TIMEOUT_MS || process.env.DCODEX_CODEX_TIMEOUT_MS || 30 * 60 * 1000);
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
46
|
+
const recoveryArgs = args.slice(1, -1);
|
|
47
|
+
const guarded = await withCodexLbCliLaunchRecovery({
|
|
48
|
+
root: recoveryRoot,
|
|
49
|
+
env,
|
|
50
|
+
cliArgs: recoveryArgs,
|
|
51
|
+
...(typeof recoveryFetch === 'function' ? { fetchImpl: recoveryFetch } : {}),
|
|
52
|
+
...(recoveryTimeoutMs === undefined ? {} : { timeoutMs: recoveryTimeoutMs })
|
|
53
|
+
}, async () => {
|
|
54
|
+
const bin = codexBin || await findCodexBinaryImpl();
|
|
55
|
+
if (!bin) {
|
|
56
|
+
return {
|
|
57
|
+
code: 127,
|
|
58
|
+
stdout: '',
|
|
59
|
+
stderr: 'Codex CLI not found. Install @openai/codex or set SKS_CODEX_BIN.',
|
|
60
|
+
stdoutBytes: 0,
|
|
61
|
+
stderrBytes: 0,
|
|
62
|
+
truncated: false,
|
|
63
|
+
timedOut: false
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
return runProcessImpl(bin, args, {
|
|
67
|
+
cwd: root,
|
|
68
|
+
env: { ...env, ...managedProxyEnvForChild(env) },
|
|
69
|
+
onStdout,
|
|
70
|
+
onStderr,
|
|
71
|
+
timeoutMs: effectiveTimeoutMs,
|
|
72
|
+
maxOutputBytes: maxBufferBytes,
|
|
73
|
+
stdoutFile: stdoutFile || (logDir ? path.join(logDir, 'codex.stdout.log') : undefined),
|
|
74
|
+
stderrFile: stderrFile || (logDir ? path.join(logDir, 'codex.stderr.log') : undefined)
|
|
75
|
+
});
|
|
66
76
|
});
|
|
77
|
+
return guarded.launched
|
|
78
|
+
? guarded.value
|
|
79
|
+
: codexLbRecoveryBlockedProcessResult(guarded.toolOutputRecovery);
|
|
67
80
|
}
|
|
68
81
|
//# sourceMappingURL=codex-adapter.js.map
|