farming-code 2.2.8 → 2.2.12
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 +42 -28
- package/README.zh_cn.md +42 -28
- package/THIRD_PARTY_NOTICES.md +11 -2
- package/backend/acp-checkpoint-store.js +198 -0
- package/backend/acp-runtime.js +306 -83
- package/backend/acp-session-state.js +202 -6
- package/backend/acp-transcript.js +112 -0
- package/backend/agent-activity.js +6 -157
- package/backend/agent-manager.js +1592 -741
- package/backend/agent-provider-session.js +17 -242
- package/backend/agent-runtime-binding.js +219 -0
- package/backend/agent-session-history.js +66 -1
- package/backend/auth.js +79 -6
- package/backend/codex-models.js +81 -84
- package/backend/codex-session-archive.js +54 -0
- package/backend/codex-terminal-profile.js +500 -0
- package/backend/codex-transcript-sanitizer.js +12 -0
- package/backend/codex-transcript.js +230 -8
- package/backend/config-manager.js +35 -0
- package/backend/control-api.js +192 -17
- package/backend/executable-discovery.js +2 -0
- package/backend/farming-net-pass.js +285 -0
- package/backend/farming-net-registry.js +112 -0
- package/backend/farming-net-server.js +298 -0
- package/backend/farming-session-store.js +5 -13
- package/backend/git-worktree-info.js +181 -0
- package/backend/local-session-engine.js +411 -186
- package/backend/main-page-session.js +5 -2
- package/backend/native-pty-controller-generation.js +106 -0
- package/backend/native-pty-host-client.js +275 -7
- package/backend/native-pty-host-identity.js +86 -0
- package/backend/native-pty-host.js +813 -114
- package/backend/native-session-engine.js +100 -28
- package/backend/packaged-node-pty.js +22 -2
- package/backend/provider-adapters.js +253 -0
- package/backend/provider-session-service.js +241 -0
- package/backend/runtime-observation.js +81 -0
- package/backend/server.js +354 -84
- package/backend/session-engine-bridge.js +21 -2
- package/backend/session-engine-router.js +1 -1
- package/backend/session-engine.js +1 -1
- package/backend/session-stream-protocol.js +185 -0
- package/backend/storage-layout.js +55 -0
- package/backend/terminal-attach-checkpoint.js +74 -0
- package/backend/terminal-exit-quiescence.js +39 -0
- package/backend/terminal-reducer-flow-control.js +97 -0
- package/backend/terminal-screen-state.js +11 -2
- package/backend/terminal-screen-worker-pool.js +59 -6
- package/backend/terminal-screen-worker-thread.js +97 -57
- package/backend/terminal-screen-worker.js +133 -51
- package/backend/terminal-state-serialization.js +127 -0
- package/backend/terminal-status.js +23 -4
- package/backend/usage-monitor.js +176 -17
- package/backend/workspace-directory.js +232 -0
- package/backend/workspace-file-router.js +182 -76
- package/backend/workspace-file-service.js +319 -4
- package/backend/workspace-root-registry.js +164 -0
- package/dist/assets/App-DWsa7DXG.js +206 -0
- package/dist/assets/{FileEditorMarkdownPreview-elKWc8Im.js → FileEditorMarkdownPreview-UlVd0O4D.js} +92 -92
- package/dist/assets/FileEditorPane-Dxx4rKOg.js +2 -0
- package/dist/assets/IconGlyphs-AU22gPDY.js +1 -0
- package/dist/assets/ProjectFilesSection-DE7Nb9Jk.js +12 -0
- package/dist/assets/ReviewPage-CeDKDyZh.js +3 -0
- package/dist/assets/code-dark-DPiuyeSp.css +1 -0
- package/dist/assets/file-icons-Bw2qd5iT.js +1 -0
- package/dist/assets/{index-BrbljRqn.js → index-CUFPJoa5.js} +3 -3
- package/dist/assets/main-Bqtb5kuz.css +1 -0
- package/dist/assets/{monaco.contribution-CyLosfZI.js → monaco.contribution-BXz-lfFB.js} +2 -2
- package/dist/assets/{tsMode-DGZTlTj8.js → tsMode-B0oUTcXQ.js} +1 -1
- package/dist/assets/workspace-editor-model-BQol4qbA.js +1 -0
- package/dist/assets/workspace-editor-monaco-BICJESG0.js +4 -0
- package/dist/assets/workspace-editor-monaco-DRJ7IaXk.js +1 -0
- package/dist/assets/workspace-view-state-DvYG_9PH.js +7 -0
- package/dist/assets/workspace-working-copy-D8-s_Sgh.js +1 -0
- package/dist/farming-2/site.webmanifest +2 -0
- package/dist/index.html +1 -1
- package/frontend/farming-net/app.css +625 -0
- package/frontend/farming-net/app.js +268 -0
- package/frontend/farming-net/index.html +86 -0
- package/frontend/reading-anchor.js +198 -0
- package/frontend/session-bridge.js +12 -3
- package/frontend/session-modal-bridge.js +5 -12
- package/frontend/skins/crt/app.js +1978 -793
- package/frontend/skins/crt/index.html +313 -23
- package/frontend/skins/crt/styles/billing.css +294 -223
- package/frontend/skins/crt/styles/monochrome-green.css +7 -2
- package/frontend/terminal-replay.js +372 -0
- package/package.json +10 -3
- package/shared/browser-protocol.d.ts +5 -0
- package/shared/browser-protocol.js +130 -0
- package/dist/assets/App-8dYAM6ql.js +0 -124
- package/dist/assets/FileEditorPane-RWiFD2cq.js +0 -5
- package/dist/assets/IconGlyphs-DfL0EBnj.js +0 -1
- package/dist/assets/ProjectFilesSection-Q4PDsWmM.js +0 -12
- package/dist/assets/ReviewPage-BaXu1ZdX.js +0 -3
- package/dist/assets/code-dark-CDkOQAtK.css +0 -1
- package/dist/assets/file-icons-EFUGSSwf.js +0 -1
- package/dist/assets/main-D073SnW4.css +0 -1
- package/dist/assets/qoder-C9LmmOSf.svg +0 -1
- package/dist/assets/qoder-Cf9gl0Y5.svg +0 -1
- package/dist/assets/qoder-gHCinseV.svg +0 -1
- package/dist/assets/workspace-view-state-CTyDzk2D.js +0 -1
- package/dist/assets/zsh-CLpveKlF.svg +0 -1
- package/dist/assets/zsh-FxSpMPbz.svg +0 -1
- /package/dist/assets/{api-D1lyBYIQ.js → api-D8nyOEbz.js} +0 -0
- /package/dist/assets/{core-ZlAPicox.js → core-D0LFJkDt.js} +0 -0
- /package/dist/assets/{useWorkspaceMenuKeyboard-CneKAZUJ.js → useWorkspaceMenuKeyboard-Brws6Ar9.js} +0 -0
|
@@ -1,42 +1,10 @@
|
|
|
1
|
-
const path = require('path');
|
|
2
1
|
const { parseCommand } = require('./cli-agents');
|
|
3
|
-
const {
|
|
4
|
-
|
|
5
|
-
createTemporaryProviderSessionId,
|
|
6
|
-
isSafeProviderSessionId,
|
|
7
|
-
} = require('./provider-session-id');
|
|
8
|
-
|
|
9
|
-
const CODING_SESSION_PROVIDERS = new Set(['codex', 'claude', 'opencode', 'qoder']);
|
|
10
|
-
const CODEX_VALUE_OPTIONS = new Set([
|
|
11
|
-
'-a',
|
|
12
|
-
'-c',
|
|
13
|
-
'-C',
|
|
14
|
-
'-m',
|
|
15
|
-
'-s',
|
|
16
|
-
'--ask-for-approval',
|
|
17
|
-
'--cd',
|
|
18
|
-
'--config',
|
|
19
|
-
'--config-profile',
|
|
20
|
-
'--model',
|
|
21
|
-
'--profile',
|
|
22
|
-
'--sandbox',
|
|
23
|
-
]);
|
|
24
|
-
|
|
25
|
-
function normalizeProvider(provider) {
|
|
26
|
-
const value = String(provider || '').trim().toLowerCase();
|
|
27
|
-
return CODING_SESSION_PROVIDERS.has(value) ? value : '';
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function providerForProgram(program) {
|
|
31
|
-
const basename = path.basename(String(program || '').trim());
|
|
32
|
-
if (basename === 'qodercli') return 'qoder';
|
|
33
|
-
return normalizeProvider(basename);
|
|
34
|
-
}
|
|
2
|
+
const { getProviderAdapter, providerForProgram } = require('./provider-adapters');
|
|
3
|
+
const { isSafeProviderSessionId } = require('./provider-session-id');
|
|
35
4
|
|
|
36
5
|
function sessionFromExactResumeSource(source) {
|
|
37
|
-
const match = String(source || '').match(/^(
|
|
38
|
-
if (!match) return null;
|
|
39
|
-
if (!isSafeProviderSessionId(match[3])) return null;
|
|
6
|
+
const match = String(source || '').match(/^([a-z0-9_-]+)-history:(?:home:([A-Za-z0-9._-]+):)?([A-Za-z0-9._:-]+)$/);
|
|
7
|
+
if (!match || !getProviderAdapter(match[1]) || !isSafeProviderSessionId(match[3])) return null;
|
|
40
8
|
return {
|
|
41
9
|
provider: match[1],
|
|
42
10
|
providerHomeId: match[2] || 'default',
|
|
@@ -44,202 +12,30 @@ function sessionFromExactResumeSource(source) {
|
|
|
44
12
|
};
|
|
45
13
|
}
|
|
46
14
|
|
|
47
|
-
function
|
|
48
|
-
if (!option || option.includes('=')) return false;
|
|
49
|
-
return valueOptions.has(option);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
function firstCodexSubcommand(args) {
|
|
53
|
-
for (let index = 0; index < args.length; index += 1) {
|
|
54
|
-
const arg = args[index];
|
|
55
|
-
if (!arg) continue;
|
|
56
|
-
if (arg.startsWith('-')) {
|
|
57
|
-
if (optionTakesValue(arg, CODEX_VALUE_OPTIONS)) index += 1;
|
|
58
|
-
continue;
|
|
59
|
-
}
|
|
60
|
-
return { value: arg, index };
|
|
61
|
-
}
|
|
62
|
-
return null;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
function codexSessionIdAfterSubcommand(args, subcommandIndex) {
|
|
66
|
-
const positional = [];
|
|
67
|
-
for (let index = subcommandIndex + 1; index < args.length; index += 1) {
|
|
68
|
-
const arg = args[index];
|
|
69
|
-
if (!arg) continue;
|
|
70
|
-
if (arg.startsWith('-')) {
|
|
71
|
-
if (optionTakesValue(arg, CODEX_VALUE_OPTIONS)) index += 1;
|
|
72
|
-
continue;
|
|
73
|
-
}
|
|
74
|
-
positional.push(arg);
|
|
75
|
-
}
|
|
76
|
-
const sessionId = positional.at(-1) || '';
|
|
77
|
-
return isSafeProviderSessionId(sessionId) ? sessionId : '';
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
function argValue(args, names) {
|
|
81
|
-
for (let index = 0; index < args.length; index += 1) {
|
|
82
|
-
const arg = args[index];
|
|
83
|
-
for (const name of names) {
|
|
84
|
-
if (arg === name) return args[index + 1] || '';
|
|
85
|
-
if (arg.startsWith(`${name}=`)) return arg.slice(name.length + 1);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
return '';
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
function hasArg(args, names) {
|
|
92
|
-
return args.some(arg => names.includes(arg) || names.some(name => arg.startsWith(`${name}=`)));
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
function codexProviderSessionPlan(rawArgs) {
|
|
96
|
-
const subcommand = firstCodexSubcommand(rawArgs);
|
|
97
|
-
if (subcommand && subcommand.value === 'resume') {
|
|
98
|
-
const sessionId = codexSessionIdAfterSubcommand(rawArgs, subcommand.index);
|
|
99
|
-
if (sessionId) {
|
|
100
|
-
return {
|
|
101
|
-
id: sessionId,
|
|
102
|
-
temporary: false,
|
|
103
|
-
source: 'resume',
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
if (subcommand && subcommand.value === 'fork') {
|
|
109
|
-
return {
|
|
110
|
-
id: createTemporaryProviderSessionId(),
|
|
111
|
-
temporary: true,
|
|
112
|
-
source: 'codex-fork-temporary',
|
|
113
|
-
forkedFromProviderSessionId: codexSessionIdAfterSubcommand(rawArgs, subcommand.index),
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
if (subcommand && subcommand.value) {
|
|
118
|
-
return null;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
return {
|
|
122
|
-
id: createTemporaryProviderSessionId(),
|
|
123
|
-
temporary: true,
|
|
124
|
-
source: 'codex-temporary',
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
function claudeProviderSessionPlan(rawArgs, launchArgs) {
|
|
129
|
-
const explicitSessionId = argValue(rawArgs, ['--session-id']);
|
|
130
|
-
const resumeSessionId = argValue(rawArgs, ['--resume']);
|
|
131
|
-
const isFork = hasArg(rawArgs, ['--fork-session']);
|
|
132
|
-
const isContinue = hasArg(rawArgs, ['--continue', '-c']);
|
|
133
|
-
|
|
134
|
-
if (explicitSessionId && isSafeProviderSessionId(explicitSessionId)) {
|
|
135
|
-
return {
|
|
136
|
-
id: explicitSessionId,
|
|
137
|
-
temporary: false,
|
|
138
|
-
source: 'launch-session-id',
|
|
139
|
-
forkedFromProviderSessionId: isFork && isSafeProviderSessionId(resumeSessionId) ? resumeSessionId : '',
|
|
140
|
-
};
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
if (resumeSessionId && isSafeProviderSessionId(resumeSessionId) && !isFork) {
|
|
144
|
-
return {
|
|
145
|
-
id: resumeSessionId,
|
|
146
|
-
temporary: false,
|
|
147
|
-
source: 'resume',
|
|
148
|
-
};
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
if (isContinue) {
|
|
152
|
-
return null;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
const sessionId = createProviderSessionId();
|
|
15
|
+
function emptyPlan(args) {
|
|
156
16
|
return {
|
|
157
|
-
|
|
17
|
+
provider: '',
|
|
18
|
+
id: '',
|
|
158
19
|
temporary: false,
|
|
159
|
-
source:
|
|
160
|
-
forkedFromProviderSessionId:
|
|
161
|
-
args
|
|
162
|
-
};
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
function qoderProviderSessionPlan(rawArgs, launchArgs) {
|
|
166
|
-
const explicitSessionId = argValue(rawArgs, ['--session-id']);
|
|
167
|
-
const resumeSessionId = argValue(rawArgs, ['--resume']);
|
|
168
|
-
const isFork = hasArg(rawArgs, ['--fork-session']);
|
|
169
|
-
const isContinue = hasArg(rawArgs, ['--continue']);
|
|
170
|
-
|
|
171
|
-
if (explicitSessionId && isSafeProviderSessionId(explicitSessionId)) {
|
|
172
|
-
return {
|
|
173
|
-
id: explicitSessionId,
|
|
174
|
-
temporary: false,
|
|
175
|
-
source: 'launch-session-id',
|
|
176
|
-
forkedFromProviderSessionId: isFork && isSafeProviderSessionId(resumeSessionId) ? resumeSessionId : '',
|
|
177
|
-
};
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
if (resumeSessionId && isSafeProviderSessionId(resumeSessionId) && !isFork) {
|
|
181
|
-
return {
|
|
182
|
-
id: resumeSessionId,
|
|
183
|
-
temporary: false,
|
|
184
|
-
source: 'resume',
|
|
185
|
-
};
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
if (isContinue) {
|
|
189
|
-
return null;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
const sessionId = createProviderSessionId();
|
|
193
|
-
return {
|
|
194
|
-
id: sessionId,
|
|
195
|
-
temporary: false,
|
|
196
|
-
source: isFork ? 'qoder-fork-session-id' : 'qoder-session-id',
|
|
197
|
-
forkedFromProviderSessionId: isFork && isSafeProviderSessionId(resumeSessionId) ? resumeSessionId : '',
|
|
198
|
-
args: ['--session-id', sessionId, ...launchArgs],
|
|
199
|
-
};
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
function openCodeProviderSessionPlan(rawArgs) {
|
|
203
|
-
const sessionId = argValue(rawArgs, ['--session', '-s']);
|
|
204
|
-
if (!sessionId || !isSafeProviderSessionId(sessionId)) return null;
|
|
205
|
-
if (hasArg(rawArgs, ['--fork'])) {
|
|
206
|
-
return {
|
|
207
|
-
id: createTemporaryProviderSessionId(),
|
|
208
|
-
temporary: true,
|
|
209
|
-
source: 'opencode-fork-temporary',
|
|
210
|
-
forkedFromProviderSessionId: sessionId,
|
|
211
|
-
};
|
|
212
|
-
}
|
|
213
|
-
return {
|
|
214
|
-
id: sessionId,
|
|
215
|
-
temporary: false,
|
|
216
|
-
source: 'resume',
|
|
20
|
+
source: '',
|
|
21
|
+
forkedFromProviderSessionId: '',
|
|
22
|
+
args,
|
|
217
23
|
};
|
|
218
24
|
}
|
|
219
25
|
|
|
220
26
|
function buildAgentProviderSessionPlan({ command, program, args, source } = {}) {
|
|
221
27
|
const sourceSession = sessionFromExactResumeSource(source);
|
|
222
28
|
const rawParts = parseCommand(command);
|
|
223
|
-
const
|
|
224
|
-
const provider = sourceSession ? sourceSession.provider : providerForProgram(rawProgram || program);
|
|
225
|
-
if (!provider) {
|
|
226
|
-
return {
|
|
227
|
-
provider: '',
|
|
228
|
-
id: '',
|
|
229
|
-
key: '',
|
|
230
|
-
temporary: false,
|
|
231
|
-
source: '',
|
|
232
|
-
forkedFromProviderSessionId: '',
|
|
233
|
-
args: Array.isArray(args) ? args : [],
|
|
234
|
-
};
|
|
235
|
-
}
|
|
236
|
-
|
|
29
|
+
const provider = sourceSession?.provider || providerForProgram(rawParts[0] || program);
|
|
237
30
|
const launchArgs = Array.isArray(args) ? args : [];
|
|
31
|
+
const adapter = getProviderAdapter(provider);
|
|
32
|
+
if (!adapter) return emptyPlan(launchArgs);
|
|
33
|
+
|
|
238
34
|
if (sourceSession) {
|
|
239
35
|
return {
|
|
240
36
|
provider,
|
|
241
37
|
id: sourceSession.sessionId,
|
|
242
|
-
providerHomeId: sourceSession.providerHomeId
|
|
38
|
+
providerHomeId: sourceSession.providerHomeId,
|
|
243
39
|
temporary: false,
|
|
244
40
|
source: 'resume-source',
|
|
245
41
|
forkedFromProviderSessionId: '',
|
|
@@ -247,29 +43,8 @@ function buildAgentProviderSessionPlan({ command, program, args, source } = {})
|
|
|
247
43
|
};
|
|
248
44
|
}
|
|
249
45
|
|
|
250
|
-
const
|
|
251
|
-
|
|
252
|
-
if (provider === 'codex') {
|
|
253
|
-
plan = codexProviderSessionPlan(rawArgs);
|
|
254
|
-
} else if (provider === 'claude') {
|
|
255
|
-
plan = claudeProviderSessionPlan(rawArgs, launchArgs);
|
|
256
|
-
} else if (provider === 'qoder') {
|
|
257
|
-
plan = qoderProviderSessionPlan(rawArgs, launchArgs);
|
|
258
|
-
} else if (provider === 'opencode') {
|
|
259
|
-
plan = openCodeProviderSessionPlan(rawArgs);
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
if (!plan || !plan.id) {
|
|
263
|
-
return {
|
|
264
|
-
provider: '',
|
|
265
|
-
id: '',
|
|
266
|
-
temporary: false,
|
|
267
|
-
source: '',
|
|
268
|
-
forkedFromProviderSessionId: '',
|
|
269
|
-
args: launchArgs,
|
|
270
|
-
};
|
|
271
|
-
}
|
|
272
|
-
|
|
46
|
+
const plan = adapter.planSession(rawParts.slice(1), launchArgs);
|
|
47
|
+
if (!plan?.id) return emptyPlan(launchArgs);
|
|
273
48
|
return {
|
|
274
49
|
provider,
|
|
275
50
|
id: plan.id,
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
const RUNTIME_KINDS = new Set(['terminal', 'acp', 'json', 'app-server']);
|
|
2
|
+
|
|
3
|
+
function terminalBinding() {
|
|
4
|
+
return { kind: 'terminal' };
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
function acpBinding(source = {}) {
|
|
8
|
+
return {
|
|
9
|
+
kind: 'acp',
|
|
10
|
+
state: source.state || source.acpState || '',
|
|
11
|
+
error: source.error || source.acpError || '',
|
|
12
|
+
stopReason: source.stopReason || source.acpStopReason || '',
|
|
13
|
+
pendingPermission: source.pendingPermission || source.acpPendingPermission || null,
|
|
14
|
+
pendingPermissions: source.pendingPermissions || source.acpPendingPermissions || [],
|
|
15
|
+
pendingElicitation: source.pendingElicitation || source.acpPendingElicitation || null,
|
|
16
|
+
pendingElicitations: source.pendingElicitations || source.acpPendingElicitations || [],
|
|
17
|
+
activeElicitations: source.activeElicitations || source.acpActiveElicitations || [],
|
|
18
|
+
sessionUpdatedAt: source.sessionUpdatedAt || source.acpSessionUpdatedAt || '',
|
|
19
|
+
sessionRevision: Number(source.sessionRevision ?? source.acpSessionRevision) || 0,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function jsonBinding(source = {}) {
|
|
24
|
+
return {
|
|
25
|
+
kind: 'json',
|
|
26
|
+
state: source.state || source.jsonCliState || '',
|
|
27
|
+
error: source.error || source.jsonCliError || '',
|
|
28
|
+
transcriptUpdatedAt: source.transcriptUpdatedAt || source.jsonCliTranscriptUpdatedAt || '',
|
|
29
|
+
events: source.events || source.jsonCliEvents || [],
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function appServerBinding(source = {}) {
|
|
34
|
+
return {
|
|
35
|
+
kind: 'app-server',
|
|
36
|
+
state: source.state || source.codexAppServerState || '',
|
|
37
|
+
endpoint: source.endpoint || source.codexAppServerEndpoint || '',
|
|
38
|
+
threadId: source.threadId || source.codexAppServerThreadId || '',
|
|
39
|
+
turnId: source.turnId || source.codexAppServerTurnId || '',
|
|
40
|
+
error: source.error || source.codexAppServerError || '',
|
|
41
|
+
pendingRequestId: source.pendingRequestId || source.codexAppServerPendingRequestId || '',
|
|
42
|
+
pendingRequestMethod: source.pendingRequestMethod || source.codexAppServerPendingRequestMethod || '',
|
|
43
|
+
pendingRequest: source.pendingRequest || source.codexAppServerPendingRequest || null,
|
|
44
|
+
notice: source.notice || source.codexAppServerNotice || null,
|
|
45
|
+
goal: source.goal || source.codexAppServerGoal || null,
|
|
46
|
+
observerDeferred: source.observerDeferred === true || source.codexCliObserverDeferred === true,
|
|
47
|
+
homePath: source.homePath || source.codexAppServerHomePath || '',
|
|
48
|
+
transcriptUpdatedAt: source.transcriptUpdatedAt || source.codexAppServerTranscriptUpdatedAt || '',
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function runtimeKind(agent) {
|
|
53
|
+
if (RUNTIME_KINDS.has(agent?.runtimeBinding?.kind)) return agent.runtimeBinding.kind;
|
|
54
|
+
if (agent?.agentRuntimeMode === 'acp') return 'acp';
|
|
55
|
+
if (agent?.agentRuntimeMode === 'json') return 'json';
|
|
56
|
+
return agent?.codexRuntimeMode === 'app-server' ? 'app-server' : 'terminal';
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function bindingFromLegacy(agent) {
|
|
60
|
+
if (RUNTIME_KINDS.has(agent?.runtimeBinding?.kind)) return agent.runtimeBinding;
|
|
61
|
+
switch (runtimeKind(agent)) {
|
|
62
|
+
case 'acp': return acpBinding(agent);
|
|
63
|
+
case 'json': return jsonBinding(agent);
|
|
64
|
+
case 'app-server': return appServerBinding(agent);
|
|
65
|
+
default: return terminalBinding();
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function runtimeBindingFor(kind, source = {}) {
|
|
70
|
+
switch (kind) {
|
|
71
|
+
case 'acp': return acpBinding(source);
|
|
72
|
+
case 'json': return jsonBinding(source);
|
|
73
|
+
case 'app-server': return appServerBinding(source);
|
|
74
|
+
default: return terminalBinding();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function runtimeBindingOf(agent, expectedKind) {
|
|
79
|
+
const binding = bindingFromLegacy(agent);
|
|
80
|
+
return !expectedKind || binding.kind === expectedKind ? binding : null;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function replaceRuntimeBinding(agent, kind, source = {}) {
|
|
84
|
+
const binding = runtimeBindingFor(kind, source);
|
|
85
|
+
agent.runtimeBinding = binding;
|
|
86
|
+
return binding;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const LEGACY_RUNTIME_FIELDS = [
|
|
90
|
+
'acpState', 'acpError', 'acpStopReason', 'acpPendingPermission', 'acpPendingPermissions',
|
|
91
|
+
'acpPendingElicitation', 'acpPendingElicitations', 'acpActiveElicitations',
|
|
92
|
+
'acpSessionUpdatedAt', 'acpSessionRevision', 'jsonCliState', 'jsonCliError',
|
|
93
|
+
'jsonCliTranscriptUpdatedAt', 'codexAppServerState', 'codexAppServerEndpoint',
|
|
94
|
+
'codexAppServerThreadId', 'codexAppServerTurnId', 'codexAppServerError',
|
|
95
|
+
'codexAppServerPendingRequestId', 'codexAppServerPendingRequestMethod',
|
|
96
|
+
'codexAppServerPendingRequest', 'codexAppServerNotice', 'codexAppServerGoal',
|
|
97
|
+
'codexCliObserverDeferred', 'codexAppServerHomePath', 'codexAppServerTranscriptUpdatedAt',
|
|
98
|
+
];
|
|
99
|
+
|
|
100
|
+
function installRuntimeBinding(agent) {
|
|
101
|
+
if (!agent || typeof agent !== 'object') return agent;
|
|
102
|
+
const jsonResumeEvents = Array.isArray(agent.runtimeBinding?.events)
|
|
103
|
+
? agent.runtimeBinding.events
|
|
104
|
+
: (Array.isArray(agent.jsonCliEvents) ? agent.jsonCliEvents : []);
|
|
105
|
+
const binding = bindingFromLegacy(agent);
|
|
106
|
+
agent.runtimeBinding = binding;
|
|
107
|
+
agent.runtimeResumeState = {
|
|
108
|
+
...(agent.runtimeResumeState || {}),
|
|
109
|
+
jsonEvents: jsonResumeEvents,
|
|
110
|
+
};
|
|
111
|
+
for (const name of ['agentRuntimeMode', 'codexRuntimeMode', 'jsonCliEvents', ...LEGACY_RUNTIME_FIELDS]) {
|
|
112
|
+
delete agent[name];
|
|
113
|
+
}
|
|
114
|
+
return agent;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
class RuntimeAgentMap extends Map {
|
|
118
|
+
set(key, agent) {
|
|
119
|
+
return super.set(key, installRuntimeBinding(agent));
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function publicRuntimeBinding(agent) {
|
|
124
|
+
const binding = RUNTIME_KINDS.has(agent?.runtimeBinding?.kind)
|
|
125
|
+
? agent.runtimeBinding
|
|
126
|
+
: bindingFromLegacy(agent);
|
|
127
|
+
if (binding.kind === 'terminal') return terminalBinding();
|
|
128
|
+
if (binding.kind === 'json') {
|
|
129
|
+
return {
|
|
130
|
+
kind: 'json',
|
|
131
|
+
state: binding.state,
|
|
132
|
+
error: binding.error,
|
|
133
|
+
transcriptUpdatedAt: binding.transcriptUpdatedAt,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
if (binding.kind === 'app-server') {
|
|
137
|
+
return {
|
|
138
|
+
kind: 'app-server',
|
|
139
|
+
state: binding.state,
|
|
140
|
+
endpoint: binding.endpoint,
|
|
141
|
+
threadId: binding.threadId,
|
|
142
|
+
turnId: binding.turnId,
|
|
143
|
+
error: binding.error,
|
|
144
|
+
pendingRequestId: binding.pendingRequestId,
|
|
145
|
+
pendingRequestMethod: binding.pendingRequestMethod,
|
|
146
|
+
pendingRequest: binding.pendingRequest,
|
|
147
|
+
notice: binding.notice,
|
|
148
|
+
goal: binding.goal,
|
|
149
|
+
observerDeferred: binding.observerDeferred,
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
return { ...binding };
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function runtimeState(agent) {
|
|
156
|
+
const binding = RUNTIME_KINDS.has(agent?.runtimeBinding?.kind)
|
|
157
|
+
? agent.runtimeBinding
|
|
158
|
+
: bindingFromLegacy(agent);
|
|
159
|
+
return binding.kind === 'terminal' ? '' : binding.state || '';
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function legacyRuntimeMetadata(agent) {
|
|
163
|
+
const binding = bindingFromLegacy(agent);
|
|
164
|
+
const metadata = {
|
|
165
|
+
codexRuntimeMode: binding.kind === 'app-server' ? 'app-server' : 'cli',
|
|
166
|
+
agentRuntimeMode: ['acp', 'json'].includes(binding.kind) ? binding.kind : 'terminal',
|
|
167
|
+
};
|
|
168
|
+
if (binding.kind === 'acp') {
|
|
169
|
+
return {
|
|
170
|
+
...metadata,
|
|
171
|
+
acpState: binding.state,
|
|
172
|
+
acpError: binding.error,
|
|
173
|
+
acpStopReason: binding.stopReason,
|
|
174
|
+
acpPendingPermission: binding.pendingPermission,
|
|
175
|
+
acpPendingPermissions: binding.pendingPermissions,
|
|
176
|
+
acpPendingElicitation: binding.pendingElicitation,
|
|
177
|
+
acpPendingElicitations: binding.pendingElicitations,
|
|
178
|
+
acpActiveElicitations: binding.activeElicitations,
|
|
179
|
+
acpSessionUpdatedAt: binding.sessionUpdatedAt,
|
|
180
|
+
acpSessionRevision: binding.sessionRevision,
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
if (binding.kind === 'json') {
|
|
184
|
+
return {
|
|
185
|
+
...metadata,
|
|
186
|
+
jsonCliState: binding.state,
|
|
187
|
+
jsonCliError: binding.error,
|
|
188
|
+
jsonCliTranscriptUpdatedAt: binding.transcriptUpdatedAt,
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
if (binding.kind === 'app-server') {
|
|
192
|
+
return {
|
|
193
|
+
...metadata,
|
|
194
|
+
codexAppServerHomePath: binding.homePath,
|
|
195
|
+
codexAppServerState: binding.state,
|
|
196
|
+
codexAppServerEndpoint: binding.endpoint,
|
|
197
|
+
codexAppServerThreadId: binding.threadId,
|
|
198
|
+
codexAppServerTurnId: binding.turnId,
|
|
199
|
+
codexAppServerError: binding.error,
|
|
200
|
+
codexAppServerPendingRequestId: binding.pendingRequestId,
|
|
201
|
+
codexAppServerPendingRequestMethod: binding.pendingRequestMethod,
|
|
202
|
+
codexAppServerPendingRequest: binding.pendingRequest,
|
|
203
|
+
codexCliObserverDeferred: binding.observerDeferred,
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
return metadata;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
module.exports = {
|
|
210
|
+
RuntimeAgentMap,
|
|
211
|
+
installRuntimeBinding,
|
|
212
|
+
legacyRuntimeMetadata,
|
|
213
|
+
publicRuntimeBinding,
|
|
214
|
+
replaceRuntimeBinding,
|
|
215
|
+
runtimeBindingFor,
|
|
216
|
+
runtimeBindingOf,
|
|
217
|
+
runtimeKind,
|
|
218
|
+
runtimeState,
|
|
219
|
+
};
|
|
@@ -25,6 +25,61 @@ function quoteCommandArg(value) {
|
|
|
25
25
|
return `'${String(value).replace(/'/g, `'\\''`)}'`;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
function tomlStringAssignment(line, key) {
|
|
29
|
+
const match = String(line || '').match(new RegExp(`^\\s*${key}\\s*=\\s*("(?:[^"\\\\]|\\\\.)*"|'[^']*')\\s*(?:#.*)?$`));
|
|
30
|
+
if (!match) return '';
|
|
31
|
+
const literal = match[1];
|
|
32
|
+
if (literal.startsWith('"')) {
|
|
33
|
+
try {
|
|
34
|
+
return JSON.parse(literal).trim();
|
|
35
|
+
} catch {
|
|
36
|
+
return '';
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return literal.slice(1, -1).trim();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function codexProfileNameForSection(section) {
|
|
43
|
+
const match = String(section || '').trim().match(/^profiles\.(?:"([^"]+)"|'([^']+)'|([A-Za-z0-9_-]+))$/);
|
|
44
|
+
return match ? (match[1] || match[2] || match[3] || '') : '';
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function resolveCodexResumeModelProvider(codexHome) {
|
|
48
|
+
const home = normalizePathValue(codexHome)
|
|
49
|
+
|| normalizePathValue(process.env.CODEX_HOME)
|
|
50
|
+
|| path.join(os.homedir(), '.codex');
|
|
51
|
+
let config = '';
|
|
52
|
+
try {
|
|
53
|
+
config = fs.readFileSync(path.join(home, 'config.toml'), 'utf8');
|
|
54
|
+
} catch {
|
|
55
|
+
return 'openai';
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
let section = '';
|
|
59
|
+
let activeProfile = '';
|
|
60
|
+
let topLevelProvider = '';
|
|
61
|
+
const profileProviders = new Map();
|
|
62
|
+
for (const line of config.split(/\r?\n/)) {
|
|
63
|
+
const sectionMatch = line.match(/^\s*\[([^\]]+)]\s*(?:#.*)?$/);
|
|
64
|
+
if (sectionMatch) {
|
|
65
|
+
section = sectionMatch[1].trim();
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
if (!section) {
|
|
69
|
+
activeProfile = tomlStringAssignment(line, 'profile') || activeProfile;
|
|
70
|
+
topLevelProvider = tomlStringAssignment(line, 'model_provider') || topLevelProvider;
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
const profileName = codexProfileNameForSection(section);
|
|
74
|
+
if (profileName) {
|
|
75
|
+
const provider = tomlStringAssignment(line, 'model_provider');
|
|
76
|
+
if (provider) profileProviders.set(profileName, provider);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return (activeProfile && profileProviders.get(activeProfile)) || topLevelProvider || 'openai';
|
|
81
|
+
}
|
|
82
|
+
|
|
28
83
|
function normalizePathValue(value) {
|
|
29
84
|
if (typeof value !== 'string') return '';
|
|
30
85
|
const trimmed = value.trim();
|
|
@@ -752,8 +807,17 @@ function buildAgentSessionResumeCommand(provider, sessionId, options = {}) {
|
|
|
752
807
|
|
|
753
808
|
if (normalizedProvider === 'codex') {
|
|
754
809
|
const cwd = normalizePathValue(options.cwd);
|
|
810
|
+
const modelProvider = String(
|
|
811
|
+
options.modelProvider
|
|
812
|
+
|| (Object.prototype.hasOwnProperty.call(options, 'providerHomePath')
|
|
813
|
+
? resolveCodexResumeModelProvider(options.providerHomePath)
|
|
814
|
+
: '')
|
|
815
|
+
).trim();
|
|
816
|
+
const providerArgs = modelProvider
|
|
817
|
+
? ` -c ${quoteCommandArg(`model_provider=${JSON.stringify(modelProvider)}`)}`
|
|
818
|
+
: '';
|
|
755
819
|
const cwdArgs = cwd ? ` -C ${quoteCommandArg(cwd)}` : '';
|
|
756
|
-
return `codex ${options.fork === true ? 'fork' : 'resume'}${cwdArgs} ${normalizedSessionId}`;
|
|
820
|
+
return `codex ${options.fork === true ? 'fork' : 'resume'}${providerArgs}${cwdArgs} ${normalizedSessionId}`;
|
|
757
821
|
}
|
|
758
822
|
|
|
759
823
|
if (normalizedProvider === 'claude') {
|
|
@@ -884,5 +948,6 @@ module.exports = {
|
|
|
884
948
|
listQoderSessions,
|
|
885
949
|
normalizeProvider,
|
|
886
950
|
paginateAgentSessions,
|
|
951
|
+
resolveCodexResumeModelProvider,
|
|
887
952
|
searchAgentSessions,
|
|
888
953
|
};
|