@golba98/codexa 1.0.1 → 1.0.3
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 +391 -94
- package/package.json +14 -8
- package/src/app.tsx +196 -63
- package/src/commands/handler.ts +9 -4
- package/src/config/buildInfo.ts +3 -0
- package/src/config/launchArgs.ts +10 -0
- package/src/config/layeredConfig.ts +0 -0
- package/src/config/persistence.ts +51 -0
- package/src/config/runtimeConfig.ts +4 -0
- package/src/config/settings.ts +6 -13
- package/src/config/toml-serialize.ts +0 -0
- package/src/config/trustStore.ts +0 -0
- package/src/config/updateCheckCache.ts +63 -0
- package/src/core/attachments.ts +0 -0
- package/src/core/auth/codexAuth.ts +0 -0
- package/src/core/channel.ts +23 -0
- package/src/core/cleanupFastFail.ts +0 -0
- package/src/core/clipboard.ts +0 -0
- package/src/core/codex.ts +0 -0
- package/src/core/codexExecArgs.ts +0 -0
- package/src/core/codexLaunch.ts +0 -0
- package/src/core/codexPrompt.ts +0 -0
- package/src/core/executables/claudeExecutable.ts +0 -0
- package/src/core/executables/codexExecutable.ts +1 -0
- package/src/core/executables/executableResolver.ts +61 -43
- package/src/core/executables/geminiExecutable.ts +0 -0
- package/src/core/githubDiagnostics.ts +0 -0
- package/src/core/hollowResponseFormat.ts +0 -0
- package/src/core/inputDebug.ts +0 -0
- package/src/core/launchContext.ts +33 -33
- package/src/core/models/codexCapabilities.ts +0 -0
- package/src/core/models/codexModelCapabilities.ts +0 -0
- package/src/core/models/modelSpecs.ts +0 -0
- package/src/core/perf/profiler.ts +0 -0
- package/src/core/perf/renderDebug.ts +0 -0
- package/src/core/planStorage.ts +0 -0
- package/src/core/process/CommandRunner.ts +0 -0
- package/src/core/process/processValidation.ts +9 -5
- package/src/core/projectInstructions.ts +0 -0
- package/src/core/providerLauncher/launcher.ts +59 -42
- package/src/core/providerLauncher/registry.ts +0 -0
- package/src/core/providerLauncher/types.ts +0 -0
- package/src/core/providerLauncher/workspaceConfig.ts +0 -0
- package/src/core/providerRuntime/anthropic.ts +0 -0
- package/src/core/providerRuntime/capabilityProfile.ts +0 -0
- package/src/core/providerRuntime/claudeCodeDiscovery.ts +0 -0
- package/src/core/providerRuntime/contextMetadata.ts +0 -0
- package/src/core/providerRuntime/gemini.ts +0 -0
- package/src/core/providerRuntime/lmstudio.ts +0 -0
- package/src/core/providerRuntime/local.ts +0 -0
- package/src/core/providerRuntime/models.ts +0 -0
- package/src/core/providerRuntime/reasoning.ts +0 -0
- package/src/core/providerRuntime/registry.ts +0 -0
- package/src/core/providerRuntime/types.ts +0 -0
- package/src/core/providers/codexJsonStream.ts +0 -0
- package/src/core/providers/codexSubprocess.ts +0 -0
- package/src/core/providers/codexTranscript.ts +0 -0
- package/src/core/providers/openaiNative.ts +0 -0
- package/src/core/providers/registry.ts +0 -0
- package/src/core/providers/types.ts +0 -0
- package/src/core/terminal/startupClear.ts +20 -0
- package/src/core/terminal/terminalCapabilities.ts +0 -0
- package/src/core/terminal/terminalControl.ts +0 -0
- package/src/core/terminal/terminalSanitize.ts +0 -0
- package/src/core/terminal/terminalSelection.ts +0 -0
- package/src/core/terminal/terminalTitle.ts +0 -0
- package/src/core/updateCheck.ts +188 -0
- package/src/core/workspaceActivity.ts +0 -0
- package/src/core/workspaceGuard.ts +0 -0
- package/src/core/workspaceRoot.ts +0 -0
- package/src/exec.ts +0 -0
- package/src/headless/execArgs.ts +1 -0
- package/src/headless/execRunner.ts +0 -0
- package/src/index.tsx +13 -9
- package/src/session/appSession.ts +0 -0
- package/src/session/chatLifecycle.ts +0 -0
- package/src/session/liveRenderScheduler.ts +0 -0
- package/src/session/planFlow.ts +0 -0
- package/src/session/planTranscript.ts +0 -0
- package/src/session/promptRunSchedule.ts +0 -0
- package/src/session/types.ts +2 -1
- package/src/test/runtimeTestUtils.ts +0 -0
- package/src/types/react-dom.d.ts +0 -0
- package/src/ui/ActionRequiredBlock.tsx +5 -5
- package/src/ui/ActivityBars.tsx +3 -3
- package/src/ui/ActivityIndicator.tsx +6 -6
- package/src/ui/AgentBlock.tsx +6 -6
- package/src/ui/AnimatedStatusText.tsx +1 -1
- package/src/ui/AppShell.tsx +13 -5
- package/src/ui/AttachmentImportPanel.tsx +8 -8
- package/src/ui/AuthPanel.tsx +20 -20
- package/src/ui/BackendPicker.tsx +0 -0
- package/src/ui/BottomComposer.tsx +117 -78
- package/src/ui/DashCard.tsx +3 -3
- package/src/ui/Markdown.tsx +17 -17
- package/src/ui/ModePicker.tsx +0 -0
- package/src/ui/ModelPicker.tsx +0 -0
- package/src/ui/ModelPickerScreen.tsx +10 -10
- package/src/ui/ModelReasoningPicker.tsx +14 -14
- package/src/ui/Panel.tsx +3 -3
- package/src/ui/PermissionsPanel.tsx +0 -0
- package/src/ui/PlanActionPicker.tsx +6 -6
- package/src/ui/PlanReviewPanel.tsx +8 -8
- package/src/ui/ProviderPicker.tsx +18 -18
- package/src/ui/ReasoningPicker.tsx +0 -0
- package/src/ui/RunFooter.tsx +3 -3
- package/src/ui/SelectionPanel.tsx +4 -4
- package/src/ui/SettingsPanel.tsx +8 -8
- package/src/ui/Spinner.tsx +1 -1
- package/src/ui/StaticIntroItem.tsx +0 -0
- package/src/ui/StaticTranscriptItem.tsx +0 -0
- package/src/ui/TextEntryPanel.tsx +10 -10
- package/src/ui/ThemePicker.tsx +0 -0
- package/src/ui/ThinkingBlock.tsx +8 -8
- package/src/ui/Timeline.tsx +21 -17
- package/src/ui/TopHeader.tsx +421 -257
- package/src/ui/TurnGroup.tsx +31 -31
- package/src/ui/UpdateAvailableCard.tsx +41 -0
- package/src/ui/UpdatePromptPanel.tsx +203 -0
- package/src/ui/busyStatusAnimation.ts +0 -0
- package/src/ui/commandNormalize.ts +0 -0
- package/src/ui/diffRenderer.ts +0 -0
- package/src/ui/focus.ts +3 -0
- package/src/ui/inputBuffer.ts +0 -0
- package/src/ui/layout.ts +1 -1
- package/src/ui/logoVariants.ts +107 -0
- package/src/ui/modeDisplay.ts +12 -12
- package/src/ui/outputPipeline.ts +0 -0
- package/src/ui/progressEntries.ts +0 -0
- package/src/ui/runActivityView.ts +0 -0
- package/src/ui/runtimeDisplay.ts +100 -0
- package/src/ui/slashCommands.ts +0 -0
- package/src/ui/terminalAnswerFormat.ts +0 -0
- package/src/ui/textLayout.ts +0 -0
- package/src/ui/theme.tsx +274 -395
- package/src/ui/themeFlow.ts +0 -0
- package/src/ui/timelineMeasure.ts +29 -19
- package/src/ui/useThrottledValue.ts +0 -0
- package/scripts/audit-codexa-capabilities.mjs +0 -466
- package/scripts/smoke-terminal-bench.mjs +0 -35
- package/src/appRenderStability.test.ts +0 -131
- package/src/commands/handler.test.ts +0 -643
- package/src/config/launchArgs.test.ts +0 -158
- package/src/config/layeredConfig.test.ts +0 -143
- package/src/config/persistence.test.ts +0 -110
- package/src/config/runtimeConfig.test.ts +0 -218
- package/src/config/settings.test.ts +0 -155
- package/src/config/trustStore.test.ts +0 -29
- package/src/core/attachments.test.ts +0 -155
- package/src/core/auth/codexAuth.test.ts +0 -68
- package/src/core/cleanupFastFail.test.ts +0 -76
- package/src/core/codexExecArgs.test.ts +0 -195
- package/src/core/codexLaunch.test.ts +0 -205
- package/src/core/codexPrompt.test.ts +0 -252
- package/src/core/executables/codexExecutable.test.ts +0 -212
- package/src/core/executables/executableResolver.test.ts +0 -129
- package/src/core/executables/geminiExecutable.test.ts +0 -116
- package/src/core/executables/pathSanityScan.test.ts +0 -47
- package/src/core/githubDiagnostics.test.ts +0 -92
- package/src/core/hollowResponseFormat.test.ts +0 -58
- package/src/core/launchContext.test.ts +0 -157
- package/src/core/models/codexCapabilities.test.ts +0 -45
- package/src/core/models/codexModelCapabilities.test.ts +0 -246
- package/src/core/models/modelSpecs.test.ts +0 -283
- package/src/core/perf/renderDebug.test.ts +0 -230
- package/src/core/planStorage.test.ts +0 -143
- package/src/core/process/CommandRunner.test.ts +0 -105
- package/src/core/projectInstructions.test.ts +0 -50
- package/src/core/providerLauncher/launcher.test.ts +0 -238
- package/src/core/providerLauncher/registry.test.ts +0 -324
- package/src/core/providerLauncher/workspaceConfig.test.ts +0 -638
- package/src/core/providerRuntime/anthropic.test.ts +0 -1120
- package/src/core/providerRuntime/capabilityProfile.test.ts +0 -311
- package/src/core/providerRuntime/contextMetadata.test.ts +0 -468
- package/src/core/providerRuntime/gemini.test.ts +0 -437
- package/src/core/providerRuntime/lmstudio.test.ts +0 -168
- package/src/core/providerRuntime/local.test.ts +0 -787
- package/src/core/providerRuntime/registry.test.ts +0 -233
- package/src/core/providers/codexJsonStream.test.ts +0 -148
- package/src/core/providers/codexSubprocess.test.ts +0 -68
- package/src/core/providers/codexTranscript.test.ts +0 -284
- package/src/core/terminal/terminalCapabilities.test.ts +0 -93
- package/src/core/terminal/terminalControl.test.ts +0 -75
- package/src/core/terminal/terminalSanitize.test.ts +0 -22
- package/src/core/terminal/terminalSelection.test.ts +0 -42
- package/src/core/terminal/terminalTitle.test.ts +0 -328
- package/src/core/workspaceActivity.test.ts +0 -163
- package/src/core/workspaceGuard.test.ts +0 -151
- package/src/core/workspaceRoot.test.ts +0 -23
- package/src/exec.test.ts +0 -13
- package/src/headless/execArgs.test.ts +0 -147
- package/src/headless/execRunner.test.ts +0 -434
- package/src/index.test.tsx +0 -618
- package/src/session/appSession.test.ts +0 -897
- package/src/session/chatLifecycle.test.ts +0 -64
- package/src/session/liveRenderScheduler.test.ts +0 -201
- package/src/session/planFlow.test.ts +0 -103
- package/src/session/planTranscript.test.ts +0 -65
- package/src/session/promptRunSchedule.test.ts +0 -36
- package/src/ui/ActivityIndicator.test.tsx +0 -58
- package/src/ui/AgentBlock.test.ts +0 -6
- package/src/ui/AnimatedStatusText.test.ts +0 -16
- package/src/ui/AppShell.test.tsx +0 -1739
- package/src/ui/AttachmentImportPanel.test.tsx +0 -204
- package/src/ui/BottomComposer.test.ts +0 -674
- package/src/ui/CodexLogo.tsx +0 -55
- package/src/ui/Markdown.test.ts +0 -157
- package/src/ui/ModelPickerProviderScope.test.tsx +0 -411
- package/src/ui/ModelPickerScreen.test.tsx +0 -99
- package/src/ui/ModelPickerState.test.tsx +0 -151
- package/src/ui/ModelReasoningPicker.test.tsx +0 -447
- package/src/ui/PlanReviewPanel.test.tsx +0 -267
- package/src/ui/PromptCardBorder.test.tsx +0 -161
- package/src/ui/ProviderPicker.test.tsx +0 -289
- package/src/ui/ProviderShortcut.test.tsx +0 -143
- package/src/ui/SettingsPanel.test.tsx +0 -233
- package/src/ui/Timeline.test.ts +0 -2067
- package/src/ui/TimelineNavigation.test.tsx +0 -201
- package/src/ui/TopHeader.test.tsx +0 -239
- package/src/ui/TurnGroup.test.tsx +0 -365
- package/src/ui/busyStatusAnimation.test.ts +0 -30
- package/src/ui/commandNormalize.test.ts +0 -142
- package/src/ui/diffRenderer.test.ts +0 -102
- package/src/ui/focusFlow.test.tsx +0 -1098
- package/src/ui/inputBuffer.test.ts +0 -151
- package/src/ui/layout.test.ts +0 -145
- package/src/ui/modeDisplay.test.ts +0 -42
- package/src/ui/runActivityView.test.ts +0 -89
- package/src/ui/runLifecycleView.test.tsx +0 -237
- package/src/ui/statusRenderIsolation.test.tsx +0 -654
- package/src/ui/terminalAnswerFormat.test.ts +0 -19
- package/src/ui/textLayout.test.ts +0 -18
- package/src/ui/themeFlow.test.ts +0 -53
- package/src/ui/timelineMeasureCache.test.ts +0 -986
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
import assert from "node:assert/strict";
|
|
2
|
-
import test from "node:test";
|
|
3
|
-
import {
|
|
4
|
-
DEFAULT_SHOW_BUSY_LOADER,
|
|
5
|
-
DEFAULT_TERMINAL_TITLE_MODE,
|
|
6
|
-
DEFAULT_WORKSPACE_DISPLAY_MODE,
|
|
7
|
-
DEFAULT_MODE,
|
|
8
|
-
USER_SETTING_DEFINITIONS,
|
|
9
|
-
formatBusyLoaderSettingValue,
|
|
10
|
-
formatModeLabel,
|
|
11
|
-
formatTerminalTitleModeLabel,
|
|
12
|
-
formatTerminalTitlePath,
|
|
13
|
-
formatWorkspaceDisplayModeLabel,
|
|
14
|
-
formatWorkspaceDisplayPath,
|
|
15
|
-
getCodexConfigFile,
|
|
16
|
-
getCodexHome,
|
|
17
|
-
getCodexaTrustStoreFile,
|
|
18
|
-
getNextMode,
|
|
19
|
-
normalizeReasoningForModel,
|
|
20
|
-
} from "./settings.js";
|
|
21
|
-
|
|
22
|
-
test("keeps supported reasoning levels for gpt-5.4-mini", () => {
|
|
23
|
-
assert.equal(normalizeReasoningForModel("gpt-5.4-mini", "high"), "high");
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
test("keeps reasoning unchanged for non-mini models", () => {
|
|
27
|
-
assert.equal(normalizeReasoningForModel("gpt-5.4", "low"), "low");
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
test("formats codex-style mode labels", () => {
|
|
32
|
-
assert.equal(formatModeLabel("suggest"), "Read-only");
|
|
33
|
-
assert.equal(formatModeLabel("auto-edit"), "Auto");
|
|
34
|
-
assert.equal(formatModeLabel("full-auto"), "Full Access");
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
test("cycles modes in the same order as Ctrl+Y", () => {
|
|
38
|
-
assert.equal(getNextMode("suggest"), "auto-edit");
|
|
39
|
-
assert.equal(getNextMode("auto-edit"), "full-auto");
|
|
40
|
-
assert.equal(getNextMode("full-auto"), "suggest");
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
test("defaults to full-auto mode", () => {
|
|
44
|
-
assert.equal(DEFAULT_MODE, "full-auto");
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
test("defaults workspace display mode and busy loader", () => {
|
|
48
|
-
assert.equal(DEFAULT_WORKSPACE_DISPLAY_MODE, "dir");
|
|
49
|
-
assert.equal(DEFAULT_TERMINAL_TITLE_MODE, "dir");
|
|
50
|
-
assert.equal(DEFAULT_SHOW_BUSY_LOADER, true);
|
|
51
|
-
assert.equal(formatWorkspaceDisplayModeLabel("dir"), "Dir");
|
|
52
|
-
assert.equal(formatWorkspaceDisplayModeLabel("name"), "Name");
|
|
53
|
-
assert.equal(formatWorkspaceDisplayModeLabel("simple"), "Simple");
|
|
54
|
-
assert.equal(formatTerminalTitleModeLabel("dir"), "Dir");
|
|
55
|
-
assert.equal(formatBusyLoaderSettingValue(true), "true");
|
|
56
|
-
assert.equal(formatBusyLoaderSettingValue(false), "false");
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
test("defines user settings through reusable schemas", () => {
|
|
60
|
-
assert.deepEqual(USER_SETTING_DEFINITIONS, [
|
|
61
|
-
{
|
|
62
|
-
key: "workspaceDisplayMode",
|
|
63
|
-
label: "Workspace display",
|
|
64
|
-
description: "Controls how the workspace label is displayed in the Codexa header.",
|
|
65
|
-
options: [
|
|
66
|
-
{ value: "dir", label: "Dir" },
|
|
67
|
-
{ value: "name", label: "Name" },
|
|
68
|
-
{ value: "simple", label: "Simple" },
|
|
69
|
-
],
|
|
70
|
-
},
|
|
71
|
-
{
|
|
72
|
-
key: "terminalTitleMode",
|
|
73
|
-
label: "Terminal title",
|
|
74
|
-
description: "Controls how the terminal tab/window title is displayed.",
|
|
75
|
-
options: [
|
|
76
|
-
{ value: "dir", label: "Dir" },
|
|
77
|
-
{ value: "name", label: "Name" },
|
|
78
|
-
{ value: "simple", label: "Simple" },
|
|
79
|
-
],
|
|
80
|
-
},
|
|
81
|
-
{
|
|
82
|
-
key: "showBusyLoader",
|
|
83
|
-
label: "Busy loader",
|
|
84
|
-
description: "Controls whether the footer shows a subtle loading animation while Codexa is busy.",
|
|
85
|
-
options: [
|
|
86
|
-
{ value: "true", label: "True" },
|
|
87
|
-
{ value: "false", label: "False" },
|
|
88
|
-
],
|
|
89
|
-
},
|
|
90
|
-
{
|
|
91
|
-
key: "terminalMouseMode",
|
|
92
|
-
label: "Mouse mode",
|
|
93
|
-
description:
|
|
94
|
-
"Selection (default): no mouse tracking — native drag-select and native wheel scroll work unmodified. "
|
|
95
|
-
+ "Scroll history via native terminal scrollback. "
|
|
96
|
-
+ "Wheel: enables SGR mouse tracking so the Codexa timeline captures wheel events for in-app scroll. "
|
|
97
|
-
+ "Native drag-select then requires Shift (Windows Terminal) or equivalent modifier. "
|
|
98
|
-
+ "Run /mouse to toggle for the current session.",
|
|
99
|
-
options: [
|
|
100
|
-
{ value: "selection", label: "Native selection" },
|
|
101
|
-
{ value: "wheel", label: "Wheel scroll" },
|
|
102
|
-
],
|
|
103
|
-
},
|
|
104
|
-
]);
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
test("formats workspace display paths without changing root semantics", () => {
|
|
108
|
-
assert.equal(formatWorkspaceDisplayPath("", "simple"), "");
|
|
109
|
-
assert.equal(
|
|
110
|
-
formatWorkspaceDisplayPath("C:\\Development\\1-JavaScript\\13-Custom CLI", "dir"),
|
|
111
|
-
"13-Custom CLI",
|
|
112
|
-
);
|
|
113
|
-
assert.equal(
|
|
114
|
-
formatWorkspaceDisplayPath("C:\\Development\\1-JavaScript\\13-Custom CLI", "name"),
|
|
115
|
-
"Codexa",
|
|
116
|
-
);
|
|
117
|
-
assert.equal(
|
|
118
|
-
formatWorkspaceDisplayPath("C:\\Development\\1-JavaScript\\13-Custom CLI", "simple"),
|
|
119
|
-
"13-Custom CLI",
|
|
120
|
-
);
|
|
121
|
-
assert.equal(formatWorkspaceDisplayPath("C:\\", "simple"), "C:\\");
|
|
122
|
-
assert.equal(formatWorkspaceDisplayPath("C:\\Workspace\\", "simple"), "Workspace");
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
test("formats terminal title labels with the same workspace semantics", () => {
|
|
126
|
-
assert.equal(
|
|
127
|
-
formatTerminalTitlePath("C:\\Development\\1-JavaScript\\13-Custom-CLI-Normal", "dir"),
|
|
128
|
-
"13-Custom-CLI-Normal",
|
|
129
|
-
);
|
|
130
|
-
assert.equal(
|
|
131
|
-
formatTerminalTitlePath("C:\\Development\\1-JavaScript\\13-Custom-CLI-Normal", "name"),
|
|
132
|
-
"Codexa",
|
|
133
|
-
);
|
|
134
|
-
assert.equal(
|
|
135
|
-
formatTerminalTitlePath("C:\\Development\\1-JavaScript\\13-Custom-CLI-Normal", "simple"),
|
|
136
|
-
"Codexa",
|
|
137
|
-
);
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
test("resolves CODEX_HOME-derived paths from the live environment", () => {
|
|
141
|
-
const previousCodexHome = process.env.CODEX_HOME;
|
|
142
|
-
process.env.CODEX_HOME = "C:\\Temp\\codex-home";
|
|
143
|
-
|
|
144
|
-
try {
|
|
145
|
-
assert.equal(getCodexHome(), "C:\\Temp\\codex-home");
|
|
146
|
-
assert.equal(getCodexConfigFile(), "C:\\Temp\\codex-home\\config.toml");
|
|
147
|
-
assert.equal(getCodexaTrustStoreFile(), "C:\\Temp\\codex-home\\codexa-trust.json");
|
|
148
|
-
} finally {
|
|
149
|
-
if (previousCodexHome === undefined) {
|
|
150
|
-
delete process.env.CODEX_HOME;
|
|
151
|
-
} else {
|
|
152
|
-
process.env.CODEX_HOME = previousCodexHome;
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
});
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import assert from "node:assert/strict";
|
|
2
|
-
import { mkdtempSync, rmSync } from "fs";
|
|
3
|
-
import { tmpdir } from "os";
|
|
4
|
-
import { join } from "path";
|
|
5
|
-
import test from "node:test";
|
|
6
|
-
|
|
7
|
-
test("persists trusted project roots", async () => {
|
|
8
|
-
const tempHome = mkdtempSync(join(tmpdir(), "codexa-trust-store-"));
|
|
9
|
-
const previousCodexHome = process.env.CODEX_HOME;
|
|
10
|
-
process.env.CODEX_HOME = tempHome;
|
|
11
|
-
|
|
12
|
-
try {
|
|
13
|
-
const module = await import(`./trustStore.js?trust=${Date.now()}`);
|
|
14
|
-
const projectRoot = "C:/Workspace/Repo";
|
|
15
|
-
|
|
16
|
-
assert.equal(module.isProjectTrusted(projectRoot), false);
|
|
17
|
-
module.setProjectTrust(projectRoot, true);
|
|
18
|
-
assert.equal(module.isProjectTrusted(projectRoot), true);
|
|
19
|
-
module.setProjectTrust(projectRoot, false);
|
|
20
|
-
assert.equal(module.isProjectTrusted(projectRoot), false);
|
|
21
|
-
} finally {
|
|
22
|
-
if (previousCodexHome === undefined) {
|
|
23
|
-
delete process.env.CODEX_HOME;
|
|
24
|
-
} else {
|
|
25
|
-
process.env.CODEX_HOME = previousCodexHome;
|
|
26
|
-
}
|
|
27
|
-
rmSync(tempHome, { recursive: true, force: true });
|
|
28
|
-
}
|
|
29
|
-
});
|
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
import assert from "node:assert/strict";
|
|
2
|
-
import test from "node:test";
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
import { mkdir, writeFile, rm } from "node:fs/promises";
|
|
5
|
-
import { tmpdir } from "node:os";
|
|
6
|
-
import {
|
|
7
|
-
isImageFile,
|
|
8
|
-
resolveAttachmentDestPath,
|
|
9
|
-
importExternalFile,
|
|
10
|
-
rewritePromptWithImportedPaths,
|
|
11
|
-
} from "./attachments.js";
|
|
12
|
-
|
|
13
|
-
// ─── isImageFile ─────────────────────────────────────────────────────────────
|
|
14
|
-
|
|
15
|
-
test("isImageFile returns true for .png", () => {
|
|
16
|
-
assert.equal(isImageFile("screenshot.png"), true);
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
test("isImageFile returns true for .jpg", () => {
|
|
20
|
-
assert.equal(isImageFile("photo.jpg"), true);
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
test("isImageFile returns true for .jpeg", () => {
|
|
24
|
-
assert.equal(isImageFile("image.jpeg"), true);
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
test("isImageFile returns true for uppercase extension", () => {
|
|
28
|
-
assert.equal(isImageFile("PHOTO.JPG"), true);
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
test("isImageFile returns true for .webp", () => {
|
|
32
|
-
assert.equal(isImageFile("img.webp"), true);
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
test("isImageFile returns false for .txt", () => {
|
|
36
|
-
assert.equal(isImageFile("document.txt"), false);
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
test("isImageFile returns false for .ts", () => {
|
|
40
|
-
assert.equal(isImageFile("component.ts"), false);
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
test("isImageFile returns false for no extension", () => {
|
|
44
|
-
assert.equal(isImageFile("noext"), false);
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
// ─── resolveAttachmentDestPath ────────────────────────────────────────────────
|
|
48
|
-
|
|
49
|
-
test("resolveAttachmentDestPath returns base filename when no collision", async () => {
|
|
50
|
-
const dir = path.join(tmpdir(), `codexa-attach-test-${Date.now()}`);
|
|
51
|
-
await mkdir(dir, { recursive: true });
|
|
52
|
-
try {
|
|
53
|
-
const dest = await resolveAttachmentDestPath("/some/path/file.png", dir);
|
|
54
|
-
assert.equal(path.basename(dest), "file.png");
|
|
55
|
-
assert.equal(path.dirname(dest), dir);
|
|
56
|
-
} finally {
|
|
57
|
-
await rm(dir, { recursive: true, force: true });
|
|
58
|
-
}
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
test("resolveAttachmentDestPath appends -1 on collision", async () => {
|
|
62
|
-
const dir = path.join(tmpdir(), `codexa-attach-test-${Date.now()}`);
|
|
63
|
-
await mkdir(dir, { recursive: true });
|
|
64
|
-
try {
|
|
65
|
-
// Create a file that would collide
|
|
66
|
-
await writeFile(path.join(dir, "file.png"), "existing");
|
|
67
|
-
const dest = await resolveAttachmentDestPath("/some/path/file.png", dir);
|
|
68
|
-
assert.equal(path.basename(dest), "file-1.png");
|
|
69
|
-
} finally {
|
|
70
|
-
await rm(dir, { recursive: true, force: true });
|
|
71
|
-
}
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
test("resolveAttachmentDestPath appends -2 on double collision", async () => {
|
|
75
|
-
const dir = path.join(tmpdir(), `codexa-attach-test-${Date.now()}`);
|
|
76
|
-
await mkdir(dir, { recursive: true });
|
|
77
|
-
try {
|
|
78
|
-
await writeFile(path.join(dir, "file.png"), "existing");
|
|
79
|
-
await writeFile(path.join(dir, "file-1.png"), "existing-1");
|
|
80
|
-
const dest = await resolveAttachmentDestPath("/some/path/file.png", dir);
|
|
81
|
-
assert.equal(path.basename(dest), "file-2.png");
|
|
82
|
-
} finally {
|
|
83
|
-
await rm(dir, { recursive: true, force: true });
|
|
84
|
-
}
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
// ─── importExternalFile ───────────────────────────────────────────────────────
|
|
88
|
-
|
|
89
|
-
test("importExternalFile creates attachments dir if missing and copies file", async () => {
|
|
90
|
-
const baseDir = path.join(tmpdir(), `codexa-import-test-${Date.now()}`);
|
|
91
|
-
const srcDir = path.join(baseDir, "src");
|
|
92
|
-
const destDir = path.join(baseDir, "attachments");
|
|
93
|
-
await mkdir(srcDir, { recursive: true });
|
|
94
|
-
const srcPath = path.join(srcDir, "test.png");
|
|
95
|
-
await writeFile(srcPath, "image-content");
|
|
96
|
-
try {
|
|
97
|
-
const destPath = await importExternalFile(srcPath, destDir);
|
|
98
|
-
assert.equal(path.basename(destPath), "test.png");
|
|
99
|
-
// Verify the file was copied
|
|
100
|
-
const { readFile } = await import("node:fs/promises");
|
|
101
|
-
const content = await readFile(destPath, "utf8");
|
|
102
|
-
assert.equal(content, "image-content");
|
|
103
|
-
} finally {
|
|
104
|
-
await rm(baseDir, { recursive: true, force: true });
|
|
105
|
-
}
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
// ─── rewritePromptWithImportedPaths ──────────────────────────────────────────
|
|
109
|
-
|
|
110
|
-
test("rewritePromptWithImportedPaths rewrites quoted path with spaces", () => {
|
|
111
|
-
const prompt = '"C:\\Users\\jorda\\OneDrive\\Screenshots\\Screenshot 2026.png" what is this?';
|
|
112
|
-
const result = rewritePromptWithImportedPaths(prompt, [{
|
|
113
|
-
rawPath: "C:\\Users\\jorda\\OneDrive\\Screenshots\\Screenshot 2026.png",
|
|
114
|
-
workspaceRelativePath: ".codexa/attachments/Screenshot 2026.png",
|
|
115
|
-
}]);
|
|
116
|
-
assert.equal(result, '".codexa/attachments/Screenshot 2026.png" what is this?');
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
test("rewritePromptWithImportedPaths rewrites unquoted path without spaces", () => {
|
|
120
|
-
const prompt = "Look at C:\\Users\\jorda\\file.png please";
|
|
121
|
-
const result = rewritePromptWithImportedPaths(prompt, [{
|
|
122
|
-
rawPath: "C:\\Users\\jorda\\file.png",
|
|
123
|
-
workspaceRelativePath: ".codexa/attachments/file.png",
|
|
124
|
-
}]);
|
|
125
|
-
assert.equal(result, "Look at .codexa/attachments/file.png please");
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
test("rewritePromptWithImportedPaths leaves non-matched text unchanged", () => {
|
|
129
|
-
const prompt = "hello world, no paths here";
|
|
130
|
-
const result = rewritePromptWithImportedPaths(prompt, [{
|
|
131
|
-
rawPath: "C:\\some\\other\\path.png",
|
|
132
|
-
workspaceRelativePath: ".codexa/attachments/path.png",
|
|
133
|
-
}]);
|
|
134
|
-
assert.equal(result, "hello world, no paths here");
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
test("rewritePromptWithImportedPaths does not double-quote already-quoted replacement path with spaces", () => {
|
|
138
|
-
const prompt = '"C:\\Users\\file with spaces.png" describe';
|
|
139
|
-
const result = rewritePromptWithImportedPaths(prompt, [{
|
|
140
|
-
rawPath: "C:\\Users\\file with spaces.png",
|
|
141
|
-
workspaceRelativePath: ".codexa/attachments/file with spaces.png",
|
|
142
|
-
}]);
|
|
143
|
-
// workspaceRelativePath has spaces → re-quoted; original was quoted → double-quoted match replaced
|
|
144
|
-
assert.equal(result, '".codexa/attachments/file with spaces.png" describe');
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
test("rewritePromptWithImportedPaths handles multiple replacements", () => {
|
|
148
|
-
// Paths without spaces get no quotes; the enclosing quotes from the original are consumed
|
|
149
|
-
const prompt = '"C:\\path\\a.png" and "C:\\path\\b.png" compare them';
|
|
150
|
-
const result = rewritePromptWithImportedPaths(prompt, [
|
|
151
|
-
{ rawPath: "C:\\path\\a.png", workspaceRelativePath: ".codexa/attachments/a.png" },
|
|
152
|
-
{ rawPath: "C:\\path\\b.png", workspaceRelativePath: ".codexa/attachments/b.png" },
|
|
153
|
-
]);
|
|
154
|
-
assert.equal(result, ".codexa/attachments/a.png and .codexa/attachments/b.png compare them");
|
|
155
|
-
});
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import assert from "node:assert/strict";
|
|
2
|
-
import test from "node:test";
|
|
3
|
-
import {
|
|
4
|
-
getRunGateDecision,
|
|
5
|
-
getAuthStateLabel,
|
|
6
|
-
inferAuthStateFromProbe,
|
|
7
|
-
isLikelyAuthFailure,
|
|
8
|
-
} from "./codexAuth.js";
|
|
9
|
-
|
|
10
|
-
test("infers authenticated from successful probe exit", () => {
|
|
11
|
-
const state = inferAuthStateFromProbe(0, "", "");
|
|
12
|
-
assert.equal(state, "authenticated");
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
test("infers unauthenticated from signed-out probe output", () => {
|
|
16
|
-
const state = inferAuthStateFromProbe(
|
|
17
|
-
1,
|
|
18
|
-
"No active session. Please login.",
|
|
19
|
-
"",
|
|
20
|
-
);
|
|
21
|
-
assert.equal(state, "unauthenticated");
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
test("infers unknown from ambiguous probe output", () => {
|
|
25
|
-
const state = inferAuthStateFromProbe(
|
|
26
|
-
2,
|
|
27
|
-
"Usage: codex login status [OPTIONS]",
|
|
28
|
-
"unexpected argument '--json'",
|
|
29
|
-
);
|
|
30
|
-
assert.equal(state, "unknown");
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
test("blocks runs when unauthenticated", () => {
|
|
34
|
-
const decision = getRunGateDecision("unauthenticated");
|
|
35
|
-
assert.equal(decision.allowRun, false);
|
|
36
|
-
assert.match(decision.blockMessage ?? "", /codex login/i);
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
test("warns but allows runs when auth state is unknown", () => {
|
|
40
|
-
const decision = getRunGateDecision("unknown");
|
|
41
|
-
assert.equal(decision.allowRun, true);
|
|
42
|
-
assert.match(decision.warningMessage ?? "", /unknown/i);
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
test("allows unchecked initial auth state without a warning", () => {
|
|
46
|
-
const decision = getRunGateDecision("unknown", { warnOnUnknown: false });
|
|
47
|
-
assert.equal(decision.allowRun, true);
|
|
48
|
-
assert.equal(decision.warningMessage, undefined);
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
test("allows runs when authenticated", () => {
|
|
52
|
-
const decision = getRunGateDecision("authenticated");
|
|
53
|
-
assert.equal(decision.allowRun, true);
|
|
54
|
-
assert.equal(decision.warningMessage, undefined);
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
test("detects runtime auth failure messages", () => {
|
|
58
|
-
const detected = isLikelyAuthFailure("Unauthorized (401): token expired. Run codex login.");
|
|
59
|
-
assert.equal(detected, true);
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
test("getAuthStateLabel returns Checking for checking state", () => {
|
|
63
|
-
assert.equal(getAuthStateLabel("checking"), "Checking");
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
test("getAuthStateLabel returns Unknown for unknown state", () => {
|
|
67
|
-
assert.equal(getAuthStateLabel("unknown"), "Unknown");
|
|
68
|
-
});
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import assert from "node:assert/strict";
|
|
2
|
-
import test from "node:test";
|
|
3
|
-
import type { RunToolActivity } from "../session/types.js";
|
|
4
|
-
import { getBlockedCleanupFailure } from "./cleanupFastFail.js";
|
|
5
|
-
|
|
6
|
-
function activity(overrides: Partial<RunToolActivity>): RunToolActivity {
|
|
7
|
-
return {
|
|
8
|
-
id: "tool-1",
|
|
9
|
-
command: "Remove-Item -Recurse __pycache__",
|
|
10
|
-
status: "failed",
|
|
11
|
-
startedAt: 1,
|
|
12
|
-
completedAt: 2,
|
|
13
|
-
...overrides,
|
|
14
|
-
};
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
test("reports access-denied Remove-Item cleanup failures", () => {
|
|
18
|
-
const result = getBlockedCleanupFailure(activity({
|
|
19
|
-
summary: "Access to the path 'C:\\repo\\__pycache__\\mod.pyc' is denied.",
|
|
20
|
-
}));
|
|
21
|
-
|
|
22
|
-
assert.match(result ?? "", /access denied/i);
|
|
23
|
-
assert.match(result ?? "", /C:\\repo\\__pycache__\\mod\.pyc/);
|
|
24
|
-
assert.match(result ?? "", /stopped/i);
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
test("reports generic POSIX and node locked delete failures", () => {
|
|
28
|
-
for (const summary of [
|
|
29
|
-
"rm: cannot remove 'tests/__pycache__/case.pyc': Permission denied",
|
|
30
|
-
"EPERM: operation not permitted, unlink 'tests/__pycache__/case.pyc'",
|
|
31
|
-
"EACCES: permission denied, rmdir 'tests/__pycache__'",
|
|
32
|
-
"EBUSY: resource busy or locked, unlink 'tests/__pycache__/case.pyc'",
|
|
33
|
-
"The process cannot access the file because it is being used by another process: 'tests/__pycache__/case.pyc'",
|
|
34
|
-
]) {
|
|
35
|
-
const result = getBlockedCleanupFailure(activity({
|
|
36
|
-
command: "rm -rf tests/__pycache__",
|
|
37
|
-
summary,
|
|
38
|
-
}));
|
|
39
|
-
|
|
40
|
-
assert.ok(result, `Expected blocked cleanup failure for: ${summary}`);
|
|
41
|
-
assert.match(result, /blocked|denied|locked|busy/i);
|
|
42
|
-
}
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
test("reports git and generic lock artifacts during delete failures", () => {
|
|
46
|
-
const gitLock = getBlockedCleanupFailure(activity({
|
|
47
|
-
command: "Remove-Item -LiteralPath .git\\config.lock",
|
|
48
|
-
summary: "Access to the path '.git\\config.lock' is denied.",
|
|
49
|
-
}));
|
|
50
|
-
const genericLock = getBlockedCleanupFailure(activity({
|
|
51
|
-
command: "del cache.lock",
|
|
52
|
-
summary: "EPERM: operation not permitted, unlink 'cache.lock'",
|
|
53
|
-
}));
|
|
54
|
-
|
|
55
|
-
assert.match(gitLock ?? "", /lock artifact/i);
|
|
56
|
-
assert.match(gitLock ?? "", /\.git\\config\.lock/i);
|
|
57
|
-
assert.match(genericLock ?? "", /lock artifact/i);
|
|
58
|
-
assert.match(genericLock ?? "", /cache\.lock/i);
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
test("ignores non-delete failures and non-failed activities", () => {
|
|
62
|
-
assert.equal(getBlockedCleanupFailure(activity({
|
|
63
|
-
command: "git status",
|
|
64
|
-
summary: "fatal: Unable to create '.git/config.lock': File exists.",
|
|
65
|
-
})), null);
|
|
66
|
-
|
|
67
|
-
assert.equal(getBlockedCleanupFailure(activity({
|
|
68
|
-
status: "completed",
|
|
69
|
-
summary: "Access to the path 'x.pyc' is denied.",
|
|
70
|
-
})), null);
|
|
71
|
-
|
|
72
|
-
assert.equal(getBlockedCleanupFailure(activity({
|
|
73
|
-
command: "rm -rf __pycache__",
|
|
74
|
-
summary: "No such file or directory",
|
|
75
|
-
})), null);
|
|
76
|
-
});
|
|
@@ -1,195 +0,0 @@
|
|
|
1
|
-
import assert from "node:assert/strict";
|
|
2
|
-
import test from "node:test";
|
|
3
|
-
import { resolveRuntimeConfig, normalizeRuntimeConfig } from "../config/runtimeConfig.js";
|
|
4
|
-
import { buildCodexExecArgs } from "./codexExecArgs.js";
|
|
5
|
-
import type { CodexCliCapabilities } from "./models/codexCapabilities.js";
|
|
6
|
-
|
|
7
|
-
const fullCapabilities: CodexCliCapabilities = {
|
|
8
|
-
askForApproval: true,
|
|
9
|
-
sandbox: true,
|
|
10
|
-
config: true,
|
|
11
|
-
fullAuto: true,
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
test("uses dedicated runtime policy flags when supported", () => {
|
|
15
|
-
const result = buildCodexExecArgs({
|
|
16
|
-
runtime: resolveRuntimeConfig(normalizeRuntimeConfig({
|
|
17
|
-
model: "gpt-5.4",
|
|
18
|
-
policy: {
|
|
19
|
-
approvalPolicy: "untrusted",
|
|
20
|
-
sandboxMode: "read-only",
|
|
21
|
-
},
|
|
22
|
-
})),
|
|
23
|
-
cwd: "C:/repo",
|
|
24
|
-
}, fullCapabilities);
|
|
25
|
-
|
|
26
|
-
assert.deepEqual(result, {
|
|
27
|
-
ok: true,
|
|
28
|
-
strategy: "direct-flags",
|
|
29
|
-
args: [
|
|
30
|
-
"exec",
|
|
31
|
-
"--experimental-json",
|
|
32
|
-
"--skip-git-repo-check",
|
|
33
|
-
"--cd",
|
|
34
|
-
"C:/repo",
|
|
35
|
-
"--model",
|
|
36
|
-
"gpt-5.4",
|
|
37
|
-
"--config",
|
|
38
|
-
"model_reasoning_effort=high",
|
|
39
|
-
"--ask-for-approval",
|
|
40
|
-
"untrusted",
|
|
41
|
-
"--sandbox",
|
|
42
|
-
"read-only",
|
|
43
|
-
"-",
|
|
44
|
-
],
|
|
45
|
-
});
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
test("falls back to config overrides when dedicated policy flags are unavailable", () => {
|
|
49
|
-
const result = buildCodexExecArgs({
|
|
50
|
-
runtime: resolveRuntimeConfig(normalizeRuntimeConfig({
|
|
51
|
-
model: "gpt-5.4-mini",
|
|
52
|
-
reasoningLevel: "medium",
|
|
53
|
-
policy: {
|
|
54
|
-
approvalPolicy: "on-request",
|
|
55
|
-
sandboxMode: "workspace-write",
|
|
56
|
-
},
|
|
57
|
-
})),
|
|
58
|
-
cwd: "C:/repo",
|
|
59
|
-
}, {
|
|
60
|
-
askForApproval: false,
|
|
61
|
-
sandbox: false,
|
|
62
|
-
config: true,
|
|
63
|
-
fullAuto: false,
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
assert.deepEqual(result, {
|
|
67
|
-
ok: true,
|
|
68
|
-
strategy: "config-overrides",
|
|
69
|
-
args: [
|
|
70
|
-
"exec",
|
|
71
|
-
"--experimental-json",
|
|
72
|
-
"--skip-git-repo-check",
|
|
73
|
-
"--cd",
|
|
74
|
-
"C:/repo",
|
|
75
|
-
"--model",
|
|
76
|
-
"gpt-5.4-mini",
|
|
77
|
-
"--config",
|
|
78
|
-
"model_reasoning_effort=medium",
|
|
79
|
-
"-c",
|
|
80
|
-
"approval_policy=on-request",
|
|
81
|
-
"-c",
|
|
82
|
-
"sandbox_mode=workspace-write",
|
|
83
|
-
"-",
|
|
84
|
-
],
|
|
85
|
-
});
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
test("fails clearly when the requested policy cannot be represented safely", () => {
|
|
89
|
-
const result = buildCodexExecArgs({
|
|
90
|
-
runtime: resolveRuntimeConfig(normalizeRuntimeConfig({
|
|
91
|
-
model: "gpt-5.4",
|
|
92
|
-
policy: {
|
|
93
|
-
approvalPolicy: "on-request",
|
|
94
|
-
sandboxMode: "workspace-write",
|
|
95
|
-
},
|
|
96
|
-
})),
|
|
97
|
-
cwd: "C:/repo",
|
|
98
|
-
}, {
|
|
99
|
-
askForApproval: false,
|
|
100
|
-
sandbox: false,
|
|
101
|
-
config: false,
|
|
102
|
-
fullAuto: false,
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
assert.equal(result.ok, false);
|
|
106
|
-
assert.equal(result.strategy, "fail");
|
|
107
|
-
assert.match(result.ok ? "" : result.error, /cannot safely apply the selected reasoning level/i);
|
|
108
|
-
assert.match(result.ok ? "" : result.error, /does not support --config/i);
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
test("uses mixed config and direct flags when only approval direct flag is unavailable", () => {
|
|
112
|
-
const result = buildCodexExecArgs({
|
|
113
|
-
runtime: resolveRuntimeConfig(normalizeRuntimeConfig({
|
|
114
|
-
model: "gpt-5.4",
|
|
115
|
-
reasoningLevel: "medium",
|
|
116
|
-
policy: {
|
|
117
|
-
approvalPolicy: "on-request",
|
|
118
|
-
sandboxMode: "workspace-write",
|
|
119
|
-
},
|
|
120
|
-
})),
|
|
121
|
-
cwd: "C:/repo",
|
|
122
|
-
}, {
|
|
123
|
-
askForApproval: false,
|
|
124
|
-
sandbox: true,
|
|
125
|
-
config: true,
|
|
126
|
-
fullAuto: true,
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
assert.deepEqual(result, {
|
|
130
|
-
ok: true,
|
|
131
|
-
strategy: "config-overrides",
|
|
132
|
-
args: [
|
|
133
|
-
"exec",
|
|
134
|
-
"--experimental-json",
|
|
135
|
-
"--skip-git-repo-check",
|
|
136
|
-
"--cd",
|
|
137
|
-
"C:/repo",
|
|
138
|
-
"--model",
|
|
139
|
-
"gpt-5.4",
|
|
140
|
-
"--config",
|
|
141
|
-
"model_reasoning_effort=medium",
|
|
142
|
-
"-c",
|
|
143
|
-
"approval_policy=on-request",
|
|
144
|
-
"--sandbox",
|
|
145
|
-
"workspace-write",
|
|
146
|
-
"-",
|
|
147
|
-
],
|
|
148
|
-
});
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
test("forwards network, writable roots, service tier, and personality as config overrides", () => {
|
|
152
|
-
const result = buildCodexExecArgs({
|
|
153
|
-
runtime: resolveRuntimeConfig(normalizeRuntimeConfig({
|
|
154
|
-
model: "gpt-5.4",
|
|
155
|
-
policy: {
|
|
156
|
-
approvalPolicy: "never",
|
|
157
|
-
sandboxMode: "workspace-write",
|
|
158
|
-
networkAccess: "enabled",
|
|
159
|
-
writableRoots: ["C:/repo/tmp", "C:/repo/cache"],
|
|
160
|
-
serviceTier: "fast",
|
|
161
|
-
personality: "pragmatic",
|
|
162
|
-
},
|
|
163
|
-
})),
|
|
164
|
-
cwd: "C:/repo",
|
|
165
|
-
}, fullCapabilities);
|
|
166
|
-
|
|
167
|
-
assert.deepEqual(result, {
|
|
168
|
-
ok: true,
|
|
169
|
-
strategy: "direct-flags",
|
|
170
|
-
args: [
|
|
171
|
-
"exec",
|
|
172
|
-
"--experimental-json",
|
|
173
|
-
"--skip-git-repo-check",
|
|
174
|
-
"--cd",
|
|
175
|
-
"C:/repo",
|
|
176
|
-
"--model",
|
|
177
|
-
"gpt-5.4",
|
|
178
|
-
"--config",
|
|
179
|
-
"model_reasoning_effort=high",
|
|
180
|
-
"--ask-for-approval",
|
|
181
|
-
"never",
|
|
182
|
-
"--sandbox",
|
|
183
|
-
"workspace-write",
|
|
184
|
-
"--config",
|
|
185
|
-
"sandbox_workspace_write.network_access=true",
|
|
186
|
-
"--config",
|
|
187
|
-
"sandbox_workspace_write.writable_roots=[\"C:\\\\repo\\\\tmp\",\"C:\\\\repo\\\\cache\"]",
|
|
188
|
-
"--config",
|
|
189
|
-
"service_tier=fast",
|
|
190
|
-
"--config",
|
|
191
|
-
"personality=pragmatic",
|
|
192
|
-
"-",
|
|
193
|
-
],
|
|
194
|
-
});
|
|
195
|
-
});
|