@myagentroam/node 0.11.35 → 0.11.37
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/dist/application/execution-lifecycle.js +54 -0
- package/dist/application/node-lifecycle.js +104 -0
- package/dist/application/node-operation-admission.js +51 -0
- package/dist/application/node-operation-contracts.js +1 -0
- package/dist/application/runner-composition.js +22 -0
- package/dist/application/session-projection-composition.js +26 -0
- package/dist/application/workspace-application.js +61 -0
- package/dist/application/workspace-composition.js +21 -0
- package/dist/capabilities.js +2 -2
- package/dist/codex-app-server.js +1 -471
- package/dist/connection/authorization.js +26 -0
- package/dist/{service → connection}/direct-transfer-service.js +1 -1
- package/dist/connection/endpoints.js +32 -0
- package/dist/connector.js +144 -252
- package/dist/database.js +34 -14
- package/dist/git-askpass.js +1 -1
- package/dist/git-execution-helper.js +1 -1
- package/dist/hosting/hosted-conversation-file-identity.js +27 -0
- package/dist/hosting/hosted-conversation-file-operations.js +44 -0
- package/dist/hosting/hosted-conversation-node-service.js +974 -0
- package/dist/hosting/hosted-conversation-runs.js +599 -0
- package/dist/hosting/hosted-conversation-templates.js +280 -0
- package/dist/hosting/hosted-conversation-uploads.js +344 -0
- package/dist/hosting/hosted-conversation-watch.js +194 -0
- package/dist/hosting/runtime-contracts.js +1 -0
- package/dist/marctl-guidance.js +1 -1
- package/dist/runner/abstract-runner.js +4 -13
- package/dist/{claude-agent-sdk.js → runner/claude/claude-agent-sdk.js} +2 -2
- package/dist/runner/claude/conversation-parser.js +2 -1
- package/dist/runner/claude/managed-run-controller.js +6 -7
- package/dist/runner/claude/message-parsers.js +2 -1
- package/dist/runner/claude/native-transcript.js +2 -1
- package/dist/runner/claude/tool-normalizer.js +1 -1
- package/dist/runner/claude-code-runner.js +2 -2
- package/dist/runner/codex/codex-app-server.js +471 -0
- package/dist/runner/codex/conversation-parser.js +4 -2
- package/dist/runner/codex/managed-run-controller.js +7 -9
- package/dist/runner/codex/native-transcript.js +1 -1
- package/dist/runner/codex/tool-normalizer.js +1 -1
- package/dist/runner/codex-runner.js +9 -27
- package/dist/runner/contracts.js +1 -0
- package/dist/runner/mar-agent/conversation-normalizer.js +2 -2
- package/dist/runner/mar-agent/history-projection.js +1 -1
- package/dist/runner/mar-agent/hosted-conversation-runtime.js +6 -10
- package/dist/runner/mar-agent/managed-run-controller.js +85 -61
- package/dist/runner/mar-agent-runner.js +1 -1
- package/dist/runner/normalization.js +42 -0
- package/dist/runner/opencode/conversation-parser.js +1 -1
- package/dist/runner/opencode/managed-run-controller.js +6 -7
- package/dist/{opencode-server.js → runner/opencode/opencode-server.js} +2 -2
- package/dist/runner/opencode/tool-normalizer.js +1 -1
- package/dist/runner/opencode-runner.js +4 -5
- package/dist/runner/runner-registry.js +4 -1
- package/dist/runtime-state.js +48 -372
- package/dist/service/computer-use-enablement-service.js +1 -1
- package/dist/service/continuous-run-coordinator.js +52 -7
- package/dist/service/conversation-history-service.js +4 -4
- package/dist/service/conversation-hosting-capability-service.js +1 -1
- package/dist/service/conversation-hosting-enablement-service.js +1 -1
- package/dist/service/conversation-hosting-lifecycle-service.js +3 -3
- package/dist/service/conversation-hosting-maintenance-service.js +1 -1
- package/dist/service/conversation-observation.js +1 -1
- package/dist/service/conversation-segment-service.js +1 -1
- package/dist/service/external-session-resume-service.js +47 -27
- package/dist/service/fake-managed-run-service.js +3 -7
- package/dist/service/git-operation-service.js +1 -1
- package/dist/service/goal-continuation-coordinator.js +14 -7
- package/dist/service/mar-agent-model-transport-test-service.js +1 -1
- package/dist/service/native-session-watch-service.js +1 -1
- package/dist/service/node-control-channel.js +1 -5
- package/dist/service/node-request-service.js +1 -1
- package/dist/service/node-terminal-channel.js +2 -1
- package/dist/service/node-workspace-coordinator.js +3 -2
- package/dist/service/notification-mcp-bridge.js +6 -2
- package/dist/service/recent-run-projection-service.js +1 -1
- package/dist/service/restart-session-restorer.js +1 -1
- package/dist/service/run-event-service.js +49 -42
- package/dist/service/run-workbench-service.js +3 -3
- package/dist/service/runner-interaction-service.js +6 -5
- package/dist/service/runner-service.js +1 -1
- package/dist/service/session-recent-activity.js +2 -1
- package/dist/service/skill-directory-service.js +1 -1
- package/dist/service/skill-install-service.js +2 -2
- package/dist/service/terminal-service.js +1 -1
- package/dist/service/workbench-event-projection.js +3 -2
- package/dist/service/workbench-event-service.js +1 -1
- package/dist/service/workspace-service.js +3 -2
- package/dist/session/attachments.js +110 -0
- package/dist/session/contracts.js +1 -0
- package/dist/{util → session}/conversation-identity.js +1 -1
- package/dist/session/input-validation.js +15 -0
- package/dist/{service → session}/native-session-projection-service.js +40 -11
- package/dist/session/pagination.js +77 -0
- package/dist/{util → session}/runner-native-session-parsers.js +2 -1
- package/dist/session/runtime/approvals.js +90 -0
- package/dist/session/runtime/conversation-projection.js +310 -0
- package/dist/session/runtime/type-guards.js +19 -0
- package/dist/{service → session}/session-catalog-service.js +5 -4
- package/dist/{service → session}/session-command-service.js +3 -3
- package/dist/{service → session}/session-identity-service.js +1 -1
- package/dist/{service → session}/session-lifecycle-service.js +18 -7
- package/dist/{service → session}/session-message-service.js +6 -5
- package/dist/{service → session}/session-presentation-service.js +1 -1
- package/dist/{service → session}/session-query-service.js +2 -2
- package/dist/{service → session}/session-schedule-service.js +2 -2
- package/dist/util/records.js +3 -0
- package/dist/workspace/contracts.js +1 -0
- package/dist/workspace/file-index.js +534 -0
- package/dist/workspace/files.js +466 -0
- package/dist/workspace/git.js +991 -0
- package/dist/workspace/path-access.js +184 -0
- package/dist/workspace/utf8.js +12 -0
- package/dist/{service → workspace}/workspace-change-service.js +45 -21
- package/dist/{service → workspace}/workspace-code-navigation-service.js +6 -6
- package/dist/{service → workspace}/workspace-file-manager-service.js +1 -1
- package/dist/{service → workspace}/workspace-file-service.js +16 -16
- package/dist/{service → workspace}/workspace-git-exclude-service.js +1 -1
- package/dist/{service → workspace}/workspace-queue-workbench-service.js +3 -2
- package/dist/{service → workspace}/workspace-session-service.js +45 -40
- package/dist/{service → workspace}/workspace-upload-service.js +28 -28
- package/dist/{service → workspace}/workspace-watch-service.js +29 -28
- package/dist/{service → workspace}/workspace-workbench-service.js +4 -3
- package/package.json +4 -4
- package/dist/service/hosted-conversation-node-service.js +0 -2252
- package/dist/service/run-domain-state.js +0 -4
- package/dist/service/session-domain-state.js +0 -9
- package/dist/service/workspace-domain-state.js +0 -41
- package/dist/util/node-operation-parsers.js +0 -320
- package/dist/workspace.js +0 -2168
- /package/dist/{connector → application}/node-connector-options.js +0 -0
- /package/dist/{util → connection}/node-operation-data.js +0 -0
- /package/dist/{connector → connection}/node-operation-router.js +0 -0
- /package/dist/{service → hosting}/hosted-conversation-sandbox-profile.js +0 -0
- /package/dist/{service → hosting}/hosted-conversation-store.js +0 -0
- /package/dist/{util → mcp}/secret-environment.js +0 -0
- /package/dist/{claude-channel.js → runner/claude/claude-channel.js} +0 -0
- /package/dist/{util → runner}/personal-instructions.js +0 -0
- /package/dist/{util → runner}/runner-error.js +0 -0
- /package/dist/{service/conversation-work-process.js → session/runtime/work-process.js} +0 -0
- /package/dist/{service → session}/session-context-service.js +0 -0
- /package/dist/{util → workspace}/git-credential-client.js +0 -0
- /package/dist/{service → workspace}/workspace-content-search-service.js +0 -0
- /package/dist/{service → workspace}/workspace-watch-snapshot-service.js +0 -0
|
@@ -0,0 +1,471 @@
|
|
|
1
|
+
import { spawn, spawnSync } from 'node:child_process';
|
|
2
|
+
import { createInterface } from 'node:readline';
|
|
3
|
+
import { minimalRunnerEnvironment, platformCliInvocation, runRunnerProbe } from '../../operational.js';
|
|
4
|
+
const REQUEST_TIMEOUT_MS = 15_000;
|
|
5
|
+
/**
|
|
6
|
+
* Maps the facts that the Node can establish to the unified session controls.
|
|
7
|
+
* Native-session activation is validated atomically with the first message.
|
|
8
|
+
*/
|
|
9
|
+
export function codexSessionControl(input) {
|
|
10
|
+
void [input.available, input.nativeThreadId, input.nativeControl];
|
|
11
|
+
if (input.activeTurn) {
|
|
12
|
+
return {
|
|
13
|
+
level: 'MANAGED',
|
|
14
|
+
capabilities: ['history.read', 'events.live', 'turn.steer', 'turn.interrupt']
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
return {
|
|
18
|
+
level: 'MANAGED',
|
|
19
|
+
capabilities: ['history.read', 'turn.start']
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export class CodexAppServerRpcError extends Error {
|
|
23
|
+
code;
|
|
24
|
+
rpcMessage;
|
|
25
|
+
data;
|
|
26
|
+
constructor(payload) {
|
|
27
|
+
const rpcMessage = typeof payload.message === 'string' ? payload.message : 'Codex App Server request failed';
|
|
28
|
+
super(`CODEX_APP_SERVER_RPC_ERROR:${JSON.stringify(payload)}`);
|
|
29
|
+
this.name = 'CodexAppServerRpcError';
|
|
30
|
+
this.code = payload.code;
|
|
31
|
+
this.rpcMessage = rpcMessage;
|
|
32
|
+
this.data = payload.data;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
export function isCodexRolloutMissingError(error) {
|
|
36
|
+
return (error instanceof CodexAppServerRpcError &&
|
|
37
|
+
error.code === -32600 &&
|
|
38
|
+
(/^no rollout found for thread id\b/i.test(error.rpcMessage) ||
|
|
39
|
+
/^thread not loaded:\s*/i.test(error.rpcMessage)));
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Local JSON-RPC client for a Node-supervised Codex App Server over stdio.
|
|
43
|
+
* The transport is not exposed to MAR Server or the browser.
|
|
44
|
+
*/
|
|
45
|
+
export class CodexAppServerClient {
|
|
46
|
+
options;
|
|
47
|
+
child;
|
|
48
|
+
transport;
|
|
49
|
+
nextId = 1;
|
|
50
|
+
pending = new Map();
|
|
51
|
+
pendingDrainWaiters = new Set();
|
|
52
|
+
notifications = new Set();
|
|
53
|
+
environment = {};
|
|
54
|
+
starting;
|
|
55
|
+
restarting;
|
|
56
|
+
lifecycleRevision = 0;
|
|
57
|
+
constructor(options = {}) {
|
|
58
|
+
this.options = options;
|
|
59
|
+
}
|
|
60
|
+
configureEnvironment(environment) {
|
|
61
|
+
if (this.child !== undefined)
|
|
62
|
+
throw new Error('CODEX_APP_SERVER_ALREADY_STARTED');
|
|
63
|
+
this.environment = { ...environment };
|
|
64
|
+
}
|
|
65
|
+
clearEnvironment() {
|
|
66
|
+
if (this.child !== undefined)
|
|
67
|
+
throw new Error('CODEX_APP_SERVER_ALREADY_STARTED');
|
|
68
|
+
this.environment = {};
|
|
69
|
+
}
|
|
70
|
+
start() {
|
|
71
|
+
if (this.restarting !== undefined)
|
|
72
|
+
return this.restarting;
|
|
73
|
+
if (this.starting !== undefined)
|
|
74
|
+
return this.starting;
|
|
75
|
+
if (this.child !== undefined)
|
|
76
|
+
return Promise.resolve();
|
|
77
|
+
const starting = this.startManaged();
|
|
78
|
+
this.starting = starting;
|
|
79
|
+
const clearStarting = () => {
|
|
80
|
+
if (this.starting === starting)
|
|
81
|
+
this.starting = undefined;
|
|
82
|
+
};
|
|
83
|
+
void starting.then(clearStarting, clearStarting);
|
|
84
|
+
return starting;
|
|
85
|
+
}
|
|
86
|
+
restart() {
|
|
87
|
+
if (this.restarting !== undefined)
|
|
88
|
+
return this.restarting;
|
|
89
|
+
const restarting = this.restartManaged(this.lifecycleRevision);
|
|
90
|
+
this.restarting = restarting;
|
|
91
|
+
const clearRestarting = () => {
|
|
92
|
+
if (this.restarting === restarting)
|
|
93
|
+
this.restarting = undefined;
|
|
94
|
+
};
|
|
95
|
+
void restarting.then(clearRestarting, clearRestarting);
|
|
96
|
+
return restarting;
|
|
97
|
+
}
|
|
98
|
+
async startManaged() {
|
|
99
|
+
const command = this.options.command ?? 'codex';
|
|
100
|
+
const args = this.options.args ?? ['app-server'];
|
|
101
|
+
const spawnProcess = this.options.spawnProcess ?? defaultSpawn;
|
|
102
|
+
const child = spawnProcess(command, args, {
|
|
103
|
+
...(this.options.cwd === undefined ? {} : { cwd: this.options.cwd }),
|
|
104
|
+
env: { ...minimalRunnerEnvironment(), ...this.environment }
|
|
105
|
+
});
|
|
106
|
+
this.child = child;
|
|
107
|
+
this.transport = stdioTransport(child);
|
|
108
|
+
const lines = createInterface({ input: child.stdout });
|
|
109
|
+
lines.on('line', (line) => this.handleLine(line));
|
|
110
|
+
const managedChild = child;
|
|
111
|
+
child.once('error', (error) => {
|
|
112
|
+
if (this.child !== managedChild)
|
|
113
|
+
return;
|
|
114
|
+
this.failAll(new Error(`CODEX_APP_SERVER_START_FAILED:${error.message}`));
|
|
115
|
+
});
|
|
116
|
+
child.once('exit', () => {
|
|
117
|
+
if (this.child !== managedChild)
|
|
118
|
+
return;
|
|
119
|
+
this.child = undefined;
|
|
120
|
+
this.failAll(new Error('CODEX_APP_SERVER_EXITED'));
|
|
121
|
+
});
|
|
122
|
+
await this.requestDirect('initialize', {
|
|
123
|
+
clientInfo: { name: 'codex_vscode', title: 'MyAgentRoam', version: '0.1.4' },
|
|
124
|
+
capabilities: { experimentalApi: true }
|
|
125
|
+
});
|
|
126
|
+
this.notify('initialized', {});
|
|
127
|
+
}
|
|
128
|
+
async restartManaged(lifecycleRevision) {
|
|
129
|
+
await Promise.resolve();
|
|
130
|
+
if (this.starting !== undefined)
|
|
131
|
+
await this.starting;
|
|
132
|
+
await this.waitForPendingRequests();
|
|
133
|
+
if (this.lifecycleRevision !== lifecycleRevision)
|
|
134
|
+
throw new Error('CODEX_APP_SERVER_STOPPED');
|
|
135
|
+
this.stopManaged();
|
|
136
|
+
await this.startManaged();
|
|
137
|
+
}
|
|
138
|
+
stop() {
|
|
139
|
+
this.lifecycleRevision += 1;
|
|
140
|
+
this.stopManaged();
|
|
141
|
+
}
|
|
142
|
+
async stopAndWait() {
|
|
143
|
+
const child = this.child;
|
|
144
|
+
if (child === undefined) {
|
|
145
|
+
this.stop();
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
const exited = new Promise((resolve, reject) => {
|
|
149
|
+
if (child.exitCode !== null || child.signalCode !== null)
|
|
150
|
+
resolve();
|
|
151
|
+
else {
|
|
152
|
+
let forcedTimeout;
|
|
153
|
+
const onExit = () => {
|
|
154
|
+
clearTimeout(timeout);
|
|
155
|
+
if (forcedTimeout !== undefined)
|
|
156
|
+
clearTimeout(forcedTimeout);
|
|
157
|
+
resolve();
|
|
158
|
+
};
|
|
159
|
+
const timeout = setTimeout(() => {
|
|
160
|
+
child.kill('SIGKILL');
|
|
161
|
+
forcedTimeout = setTimeout(() => {
|
|
162
|
+
child.off('exit', onExit);
|
|
163
|
+
reject(new Error('CODEX_APP_SERVER_STOP_TIMEOUT'));
|
|
164
|
+
}, 2_000);
|
|
165
|
+
}, 2_000);
|
|
166
|
+
child.once('exit', onExit);
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
this.stop();
|
|
170
|
+
await exited;
|
|
171
|
+
}
|
|
172
|
+
stopManaged() {
|
|
173
|
+
this.transport?.destroy();
|
|
174
|
+
this.transport = undefined;
|
|
175
|
+
this.child?.kill();
|
|
176
|
+
this.child = undefined;
|
|
177
|
+
this.failAll(new Error('CODEX_APP_SERVER_STOPPED'));
|
|
178
|
+
}
|
|
179
|
+
onNotification(listener) {
|
|
180
|
+
this.notifications.add(listener);
|
|
181
|
+
return () => this.notifications.delete(listener);
|
|
182
|
+
}
|
|
183
|
+
async request(method, params) {
|
|
184
|
+
if (this.restarting !== undefined)
|
|
185
|
+
await this.restarting;
|
|
186
|
+
else if (this.starting !== undefined)
|
|
187
|
+
await this.starting;
|
|
188
|
+
return this.requestDirect(method, params);
|
|
189
|
+
}
|
|
190
|
+
requestDirect(method, params) {
|
|
191
|
+
const transport = this.transport;
|
|
192
|
+
if (transport === undefined || !transport.writable)
|
|
193
|
+
throw new Error('CODEX_APP_SERVER_UNAVAILABLE');
|
|
194
|
+
const id = this.nextId++;
|
|
195
|
+
const timeoutMs = this.options.timeoutMs ?? REQUEST_TIMEOUT_MS;
|
|
196
|
+
const result = new Promise((resolve, reject) => {
|
|
197
|
+
const timer = setTimeout(() => {
|
|
198
|
+
this.pending.delete(id);
|
|
199
|
+
this.resolvePendingDrain();
|
|
200
|
+
reject(new Error('CODEX_APP_SERVER_TIMEOUT'));
|
|
201
|
+
}, timeoutMs);
|
|
202
|
+
this.pending.set(id, { resolve, reject, timer });
|
|
203
|
+
});
|
|
204
|
+
transport.write(`${JSON.stringify({ method, id, params })}\n`);
|
|
205
|
+
return result;
|
|
206
|
+
}
|
|
207
|
+
waitForPendingRequests() {
|
|
208
|
+
if (this.pending.size === 0)
|
|
209
|
+
return Promise.resolve();
|
|
210
|
+
return new Promise((resolve) => this.pendingDrainWaiters.add(resolve));
|
|
211
|
+
}
|
|
212
|
+
resolvePendingDrain() {
|
|
213
|
+
if (this.pending.size !== 0)
|
|
214
|
+
return;
|
|
215
|
+
for (const resolve of this.pendingDrainWaiters)
|
|
216
|
+
resolve();
|
|
217
|
+
this.pendingDrainWaiters.clear();
|
|
218
|
+
}
|
|
219
|
+
notify(method, params) {
|
|
220
|
+
const transport = this.transport;
|
|
221
|
+
if (transport === undefined || !transport.writable)
|
|
222
|
+
throw new Error('CODEX_APP_SERVER_UNAVAILABLE');
|
|
223
|
+
transport.write(`${JSON.stringify({ method, params })}\n`);
|
|
224
|
+
}
|
|
225
|
+
respond(requestId, result) {
|
|
226
|
+
const transport = this.transport;
|
|
227
|
+
if (transport === undefined || !transport.writable)
|
|
228
|
+
throw new Error('CODEX_APP_SERVER_UNAVAILABLE');
|
|
229
|
+
transport.write(`${JSON.stringify({ id: requestId, result })}\n`);
|
|
230
|
+
}
|
|
231
|
+
startThread(cwd, configuration = {}) {
|
|
232
|
+
return this.request('thread/start', {
|
|
233
|
+
cwd,
|
|
234
|
+
experimentalRawEvents: true,
|
|
235
|
+
...codexThreadConfiguration(cwd, configuration)
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
listThreads(params = {}) {
|
|
239
|
+
return this.request('thread/list', params);
|
|
240
|
+
}
|
|
241
|
+
readThread(threadId) {
|
|
242
|
+
return this.request('thread/read', { threadId, includeTurns: false });
|
|
243
|
+
}
|
|
244
|
+
listCollaborationModes() {
|
|
245
|
+
return this.request('collaborationMode/list', {});
|
|
246
|
+
}
|
|
247
|
+
listModels(params) {
|
|
248
|
+
return this.request('model/list', params);
|
|
249
|
+
}
|
|
250
|
+
forkThread(threadId, cwd, lastTurnId, configuration = {}) {
|
|
251
|
+
return this.request('thread/fork', {
|
|
252
|
+
threadId,
|
|
253
|
+
lastTurnId,
|
|
254
|
+
cwd,
|
|
255
|
+
...codexThreadConfiguration(cwd, configuration)
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
revertThread(threadId, beforeTurnId) {
|
|
259
|
+
return this.request('thread/revert', { threadId, beforeTurnId });
|
|
260
|
+
}
|
|
261
|
+
listThreadTurns(threadId, input) {
|
|
262
|
+
return this.request('thread/turns/list', {
|
|
263
|
+
threadId,
|
|
264
|
+
...input,
|
|
265
|
+
itemsView: 'full',
|
|
266
|
+
sortDirection: 'desc'
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
setThreadName(threadId, name) {
|
|
270
|
+
return this.request('thread/name/set', { threadId, name });
|
|
271
|
+
}
|
|
272
|
+
resumeThread(threadId, cwd, configuration = {}) {
|
|
273
|
+
return this.request('thread/resume', {
|
|
274
|
+
threadId,
|
|
275
|
+
cwd,
|
|
276
|
+
...codexThreadConfiguration(cwd, configuration)
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
startTurn(threadId, text, cwd, configuration = {}, attachments = []) {
|
|
280
|
+
return this.request('turn/start', {
|
|
281
|
+
threadId,
|
|
282
|
+
cwd,
|
|
283
|
+
input: [{ type: 'text', text }, ...attachments],
|
|
284
|
+
...codexTurnConfiguration(cwd, configuration)
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
steerTurn(threadId, expectedTurnId, text) {
|
|
288
|
+
return this.request('turn/steer', {
|
|
289
|
+
threadId,
|
|
290
|
+
expectedTurnId,
|
|
291
|
+
input: [{ type: 'text', text }]
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
interruptTurn(threadId, turnId) {
|
|
295
|
+
return this.request('turn/interrupt', { threadId, turnId });
|
|
296
|
+
}
|
|
297
|
+
handleLine(line) {
|
|
298
|
+
let message;
|
|
299
|
+
try {
|
|
300
|
+
message = JSON.parse(line);
|
|
301
|
+
}
|
|
302
|
+
catch {
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
if ((typeof message.id === 'number' || typeof message.id === 'string') &&
|
|
306
|
+
typeof message.method === 'string') {
|
|
307
|
+
for (const listener of this.notifications) {
|
|
308
|
+
listener({ method: message.method, params: message.params, requestId: message.id });
|
|
309
|
+
}
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
if (typeof message.id === 'number') {
|
|
313
|
+
const pending = this.pending.get(message.id);
|
|
314
|
+
if (pending === undefined)
|
|
315
|
+
return;
|
|
316
|
+
clearTimeout(pending.timer);
|
|
317
|
+
this.pending.delete(message.id);
|
|
318
|
+
this.resolvePendingDrain();
|
|
319
|
+
if (message.error !== undefined) {
|
|
320
|
+
pending.reject(new CodexAppServerRpcError(isRecord(message.error) ? message.error : { message: String(message.error) }));
|
|
321
|
+
}
|
|
322
|
+
else {
|
|
323
|
+
pending.resolve(message.result);
|
|
324
|
+
}
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
if (typeof message.method === 'string') {
|
|
328
|
+
for (const listener of this.notifications)
|
|
329
|
+
listener({ method: message.method, params: message.params });
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
failAll(error) {
|
|
333
|
+
for (const [id, pending] of this.pending) {
|
|
334
|
+
clearTimeout(pending.timer);
|
|
335
|
+
pending.reject(error);
|
|
336
|
+
this.pending.delete(id);
|
|
337
|
+
}
|
|
338
|
+
this.resolvePendingDrain();
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
function codexThreadConfiguration(cwd, configuration) {
|
|
342
|
+
return {
|
|
343
|
+
...modelOption(configuration.model),
|
|
344
|
+
...(configuration.developerInstructions === undefined
|
|
345
|
+
? {}
|
|
346
|
+
: { developerInstructions: configuration.developerInstructions }),
|
|
347
|
+
...(configuration.mcpServers === undefined
|
|
348
|
+
? {}
|
|
349
|
+
: {
|
|
350
|
+
config: {
|
|
351
|
+
mcp_servers: configuration.mcpServers
|
|
352
|
+
}
|
|
353
|
+
}),
|
|
354
|
+
...codexPermissionConfiguration(cwd, configuration.access, 'thread')
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
function codexTurnConfiguration(cwd, configuration) {
|
|
358
|
+
const effort = typeof configuration.effort === 'string' && configuration.effort.trim().length > 0
|
|
359
|
+
? configuration.effort
|
|
360
|
+
: null;
|
|
361
|
+
return {
|
|
362
|
+
...modelOption(configuration.model),
|
|
363
|
+
...(effort === null ? {} : { effort }),
|
|
364
|
+
...(configuration.serviceTier === 'fast' ? { serviceTier: 'fast' } : {}),
|
|
365
|
+
...(configuration.collaborationMode === undefined
|
|
366
|
+
? {}
|
|
367
|
+
: {
|
|
368
|
+
collaborationMode: {
|
|
369
|
+
mode: configuration.collaborationMode,
|
|
370
|
+
settings: {
|
|
371
|
+
model: configuration.model ?? 'gpt-5.6-sol',
|
|
372
|
+
reasoningEffort: effort
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}),
|
|
376
|
+
...codexPermissionConfiguration(cwd, configuration.access, 'turn')
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
function modelOption(model) {
|
|
380
|
+
return model === undefined || model === null ? {} : { model };
|
|
381
|
+
}
|
|
382
|
+
function codexPermissionConfiguration(cwd, access, phase) {
|
|
383
|
+
const sandbox = access === 'read-only'
|
|
384
|
+
? 'read-only'
|
|
385
|
+
: access === 'workspace-write' || access === 'on-request'
|
|
386
|
+
? 'workspace-write'
|
|
387
|
+
: access === 'full-access'
|
|
388
|
+
? 'danger-full-access'
|
|
389
|
+
: undefined;
|
|
390
|
+
const approvalPolicy = access === 'workspace-write' || access === 'full-access' ? 'never' : 'on-request';
|
|
391
|
+
if (phase === 'thread')
|
|
392
|
+
return {
|
|
393
|
+
...(sandbox === undefined ? {} : { sandbox }),
|
|
394
|
+
approvalPolicy
|
|
395
|
+
};
|
|
396
|
+
return {
|
|
397
|
+
...(sandbox === undefined
|
|
398
|
+
? {}
|
|
399
|
+
: {
|
|
400
|
+
sandboxPolicy: sandbox === 'read-only'
|
|
401
|
+
? { type: 'readOnly' }
|
|
402
|
+
: sandbox === 'danger-full-access'
|
|
403
|
+
? { type: 'dangerFullAccess' }
|
|
404
|
+
: { type: 'workspaceWrite', writableRoots: [cwd], networkAccess: true }
|
|
405
|
+
}),
|
|
406
|
+
approvalPolicy
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
export function probeCodex(command = 'codex') {
|
|
410
|
+
const invocation = platformCliInvocation(command, ['--version']);
|
|
411
|
+
const result = spawnSync(invocation.command, invocation.args, {
|
|
412
|
+
windowsHide: true,
|
|
413
|
+
env: minimalRunnerEnvironment(),
|
|
414
|
+
timeout: 3_000,
|
|
415
|
+
encoding: 'utf8'
|
|
416
|
+
});
|
|
417
|
+
if (result.status !== 0 || result.error !== undefined)
|
|
418
|
+
return { available: false, compatible: false };
|
|
419
|
+
const version = `${result.stdout}${result.stderr}`.trim().slice(0, 128);
|
|
420
|
+
return {
|
|
421
|
+
available: true,
|
|
422
|
+
...(version.length === 0 ? {} : { version }),
|
|
423
|
+
// The CLI version is metadata only. Actual compatibility is established
|
|
424
|
+
// by the App Server initialize handshake when the client starts.
|
|
425
|
+
compatible: true
|
|
426
|
+
};
|
|
427
|
+
}
|
|
428
|
+
export async function probeCodexAsync(command = 'codex') {
|
|
429
|
+
const invocation = platformCliInvocation(command, ['--version']);
|
|
430
|
+
const result = await runRunnerProbe(invocation.command, invocation.args, {
|
|
431
|
+
env: minimalRunnerEnvironment(),
|
|
432
|
+
timeoutMs: 3_000
|
|
433
|
+
});
|
|
434
|
+
if (result.status !== 0)
|
|
435
|
+
return { available: false, compatible: false };
|
|
436
|
+
const version = `${result.stdout}${result.stderr}`.trim().slice(0, 128);
|
|
437
|
+
return {
|
|
438
|
+
available: true,
|
|
439
|
+
...(version.length === 0 ? {} : { version }),
|
|
440
|
+
// Do not reject a newer CLI before its App Server has had a chance to
|
|
441
|
+
// negotiate the protocol it actually supports.
|
|
442
|
+
compatible: true
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
export function isSupportedCodexVersion(version) {
|
|
446
|
+
return version.trim().length > 0;
|
|
447
|
+
}
|
|
448
|
+
function defaultSpawn(command, args, options) {
|
|
449
|
+
const invocation = platformCliInvocation(command, args);
|
|
450
|
+
return spawn(invocation.command, invocation.args, {
|
|
451
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
452
|
+
shell: false,
|
|
453
|
+
windowsHide: true,
|
|
454
|
+
...(options.cwd === undefined ? {} : { cwd: options.cwd }),
|
|
455
|
+
...(options.env === undefined ? {} : { env: options.env })
|
|
456
|
+
});
|
|
457
|
+
}
|
|
458
|
+
function isRecord(value) {
|
|
459
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
460
|
+
}
|
|
461
|
+
function stdioTransport(child) {
|
|
462
|
+
return {
|
|
463
|
+
get writable() {
|
|
464
|
+
return child.stdin.writable;
|
|
465
|
+
},
|
|
466
|
+
write: (data) => child.stdin.write(data),
|
|
467
|
+
on: (event, listener) => child.stdout.on(event, listener),
|
|
468
|
+
once: (event, listener) => child.stdout.once(event, listener),
|
|
469
|
+
destroy: () => child.stdout.destroy()
|
|
470
|
+
};
|
|
471
|
+
}
|
|
@@ -127,7 +127,7 @@ export class CodexUsageNormalizer {
|
|
|
127
127
|
}
|
|
128
128
|
}
|
|
129
129
|
import { basename, extname } from 'node:path';
|
|
130
|
-
import { runnerErrorProjection } from '
|
|
130
|
+
import { runnerErrorProjection } from '../runner-error.js';
|
|
131
131
|
import { conversationImageAttachmentSchema } from '@myagentroam/protocol';
|
|
132
132
|
import { parseCodexComposerImageMarkers } from './composer-image-markers.js';
|
|
133
133
|
import { normalizeCodexTool } from './tool-normalizer.js';
|
|
@@ -1334,7 +1334,9 @@ export function isCodexImageBlock(value) {
|
|
|
1334
1334
|
return false;
|
|
1335
1335
|
return value.type === 'image' || value.type === 'input_image' || value.type === 'output_image';
|
|
1336
1336
|
}
|
|
1337
|
-
import { compactRunnerText, compactRunnerValue, boundedConversationItemId,
|
|
1337
|
+
import { compactRunnerText, compactRunnerValue, boundedConversationItemId, nativePageEnd } from '../normalization.js';
|
|
1338
|
+
import { isPlainRecord } from '../../util/records.js';
|
|
1339
|
+
import { isCanonicalBase64 } from '../../session/attachments.js';
|
|
1338
1340
|
export function extractId(result, key) {
|
|
1339
1341
|
if (typeof result === 'object' &&
|
|
1340
1342
|
result !== null &&
|
|
@@ -2,12 +2,13 @@ import { NODE_MCP } from '../../mcp/naming.js';
|
|
|
2
2
|
import { nodeExecutionEnvironment } from '../../node-execution-environment.js';
|
|
3
3
|
import { extractId } from './conversation-parser.js';
|
|
4
4
|
import { normalizeCodexApproval } from './tool-normalizer.js';
|
|
5
|
-
import { parseSecretEnvironment } from '../../
|
|
5
|
+
import { parseSecretEnvironment } from '../../mcp/secret-environment.js';
|
|
6
6
|
import { safeErrorCode } from '../../util/safe-error.js';
|
|
7
|
-
import { runnerErrorProjection } from '
|
|
7
|
+
import { runnerErrorProjection } from '../runner-error.js';
|
|
8
8
|
import { ResponseLatencyTracker } from '../../service/response-latency-tracker.js';
|
|
9
9
|
import { GenerationTimingTracker } from '../../service/generation-timing-tracker.js';
|
|
10
|
-
import { boundedConversationItemId, compactRunnerText
|
|
10
|
+
import { boundedConversationItemId, compactRunnerText } from '../normalization.js';
|
|
11
|
+
import { isPlainRecord } from '../../util/records.js';
|
|
11
12
|
import { codexImageAttachments, codexLiveConversationItem, codexSourceItemId, CodexUsageNormalizer, codexUserInputQuestions } from './conversation-parser.js';
|
|
12
13
|
export function resolveCodexNotificationRun(runs, input) {
|
|
13
14
|
const entries = [...runs.entries()];
|
|
@@ -107,7 +108,7 @@ export class CodexManagedRunController {
|
|
|
107
108
|
externalSessionId: threadId,
|
|
108
109
|
...(initiatedByUserId === undefined ? {} : { initiatedByUserId })
|
|
109
110
|
});
|
|
110
|
-
this.host.
|
|
111
|
+
this.host.executionAccepted(runId);
|
|
111
112
|
this.runner.execution.runs.set(runId, {
|
|
112
113
|
sessionId: session.id,
|
|
113
114
|
threadId,
|
|
@@ -131,7 +132,6 @@ export class CodexManagedRunController {
|
|
|
131
132
|
this.usage.delete(runId);
|
|
132
133
|
this.runner.execution.runs.delete(runId);
|
|
133
134
|
this.runner.releaseEnvironment(runId);
|
|
134
|
-
this.host.removeActive(runId);
|
|
135
135
|
throw error;
|
|
136
136
|
}
|
|
137
137
|
}
|
|
@@ -372,7 +372,6 @@ export class CodexManagedRunController {
|
|
|
372
372
|
this.runner.releaseEnvironment(runId);
|
|
373
373
|
else
|
|
374
374
|
void titleRefresh.finally(() => this.runner.releaseEnvironment(runId));
|
|
375
|
-
this.host.removeActive(runId);
|
|
376
375
|
this.finishing.delete(runId);
|
|
377
376
|
};
|
|
378
377
|
if (usage.hasRollout && turnId !== undefined) {
|
|
@@ -577,7 +576,7 @@ export class CodexManagedRunController {
|
|
|
577
576
|
typeof payload.input !== 'string' ||
|
|
578
577
|
typeof payload.cwd !== 'string' ||
|
|
579
578
|
this.host.intercepted() ||
|
|
580
|
-
this.host.
|
|
579
|
+
this.host.isExecutionActive(payload.runId))
|
|
581
580
|
return;
|
|
582
581
|
const { runId, sessionId, input, cwd } = payload;
|
|
583
582
|
let attachments;
|
|
@@ -619,7 +618,7 @@ export class CodexManagedRunController {
|
|
|
619
618
|
this.host.emit(runId, 'run.rejected', { code: safeErrorCode(error, 'SECRET_ENVIRONMENT_INVALID') }, 'FAILED');
|
|
620
619
|
return;
|
|
621
620
|
}
|
|
622
|
-
this.host.
|
|
621
|
+
this.host.executionAccepted(runId);
|
|
623
622
|
void this.run({
|
|
624
623
|
runId,
|
|
625
624
|
sessionId,
|
|
@@ -739,7 +738,6 @@ export class CodexManagedRunController {
|
|
|
739
738
|
this.usage.delete(runId);
|
|
740
739
|
this.runner.execution.runs.delete(runId);
|
|
741
740
|
this.runner.releaseEnvironment(runId);
|
|
742
|
-
this.host.removeActive(runId);
|
|
743
741
|
}
|
|
744
742
|
}
|
|
745
743
|
emitError(runId, error, fallbackCode) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { homedir } from 'node:os';
|
|
2
2
|
import { basename, join } from 'node:path';
|
|
3
3
|
import { forEachJsonlRecord } from '../../native-jsonl-reader.js';
|
|
4
|
-
import { compactRunnerValue as compactValue } from '
|
|
4
|
+
import { compactRunnerValue as compactValue } from '../normalization.js';
|
|
5
5
|
import { stripGoalStartPrompt, publicGoalHistoryText } from '../../service/goal-runtime.js';
|
|
6
6
|
import { parseCodexComposerImageMarkers } from './composer-image-markers.js';
|
|
7
7
|
import { codexTranscriptSourceItemId } from './conversation-parser.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { compactRunnerText } from '
|
|
1
|
+
import { compactRunnerText } from '../normalization.js';
|
|
2
2
|
export function normalizeCodexApproval(method) {
|
|
3
3
|
return method === 'item/commandExecution/requestApproval'
|
|
4
4
|
? { toolName: 'command_execution', reason: 'Command execution requires approval.' }
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { withMarctlGuide } from '../mcp/marctl-guide.js';
|
|
2
|
-
import { CodexAppServerClient, isCodexRolloutMissingError } from '
|
|
2
|
+
import { CodexAppServerClient, isCodexRolloutMissingError } from './codex/codex-app-server.js';
|
|
3
3
|
import { AbstractRunner } from './abstract-runner.js';
|
|
4
4
|
import { declaredRunnerProfiles } from '../runner-profiles.js';
|
|
5
5
|
import { homedir } from 'node:os';
|
|
@@ -7,12 +7,12 @@ import { resolve } from 'node:path';
|
|
|
7
7
|
import { discoverAllNativeSessions } from '../native-session-history.js';
|
|
8
8
|
import { readCodexNativeContextUsage } from './codex/native-context-usage.js';
|
|
9
9
|
import { codexThreadCwd, extractCodexThreads } from './codex/conversation-parser.js';
|
|
10
|
-
import { deduplicateDirectSessions, isWithinWorkspace, latestNativeActivity } from '../
|
|
10
|
+
import { deduplicateDirectSessions, isWithinWorkspace, latestNativeActivity } from '../session/runner-native-session-parsers.js';
|
|
11
11
|
import { codexThreadHistoryModes, codexPaginatedThread, codexPaginatedCursor, codexPaginatedConversationPage } from './codex/conversation-parser.js';
|
|
12
|
-
import { codexSessionControl } from '
|
|
12
|
+
import { codexSessionControl } from './codex/codex-app-server.js';
|
|
13
13
|
import { extractId } from './codex/conversation-parser.js';
|
|
14
14
|
import { nodeLog } from '../operational.js';
|
|
15
|
-
import { conversationClientMessageId } from '../
|
|
15
|
+
import { conversationClientMessageId } from '../session/conversation-identity.js';
|
|
16
16
|
const CODEX_MODEL_CACHE_MS = 10 * 60 * 1_000;
|
|
17
17
|
const CODEX_MODEL_FAILURE_RETRY_MS = 30 * 1_000;
|
|
18
18
|
const CODEX_MODEL_PAGE_SIZE = 100;
|
|
@@ -245,40 +245,22 @@ export class CodexRunner extends AbstractRunner {
|
|
|
245
245
|
usesRunnerTitleForRename() {
|
|
246
246
|
return true;
|
|
247
247
|
}
|
|
248
|
-
async renameNative(session, input
|
|
248
|
+
async renameNative(session, input) {
|
|
249
249
|
if (session.externalSessionId === null)
|
|
250
250
|
return;
|
|
251
251
|
if (input.title !== undefined) {
|
|
252
252
|
await this.start();
|
|
253
253
|
await this.setThreadName(session.externalSessionId, input.title ?? '');
|
|
254
254
|
}
|
|
255
|
-
database.saveNativeSessionMetadata({
|
|
256
|
-
runner: this.name,
|
|
257
|
-
externalSessionId: session.externalSessionId,
|
|
258
|
-
workspaceId: session.workspaceId,
|
|
259
|
-
...(input.title === undefined ? {} : { runnerTitle: input.title }),
|
|
260
|
-
...(input.title === undefined
|
|
261
|
-
? {}
|
|
262
|
-
: { runnerTitlePending: input.title !== null && input.title.trim().length > 0 }),
|
|
263
|
-
...(input.pinned === undefined ? {} : { pinned: input.pinned })
|
|
264
|
-
});
|
|
265
255
|
}
|
|
266
|
-
projectedRunnerTitle(metadata, input
|
|
256
|
+
projectedRunnerTitle(metadata, input) {
|
|
267
257
|
const cached = metadata?.runnerTitle ?? null;
|
|
268
258
|
if (input.titleOrigin !== 'OFFICIAL' || input.title === undefined)
|
|
269
|
-
return cached ?? input.title ?? null;
|
|
259
|
+
return { title: cached ?? input.title ?? null, clearPending: false };
|
|
270
260
|
if (metadata?.runnerTitlePending === true) {
|
|
271
|
-
|
|
272
|
-
database?.saveNativeSessionMetadata({
|
|
273
|
-
runner: this.name,
|
|
274
|
-
externalSessionId: input.externalSessionId,
|
|
275
|
-
workspaceId: input.workspaceId,
|
|
276
|
-
runnerTitle: cached,
|
|
277
|
-
runnerTitlePending: false
|
|
278
|
-
});
|
|
279
|
-
return cached ?? input.title;
|
|
261
|
+
return { title: cached ?? input.title, clearPending: input.title === cached };
|
|
280
262
|
}
|
|
281
|
-
return input.title;
|
|
263
|
+
return { title: input.title, clearPending: false };
|
|
282
264
|
}
|
|
283
265
|
async readConversationHistory(readers) {
|
|
284
266
|
const page = await readers.official();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -4,8 +4,8 @@ export function normalizeMarAgentUsage(usage) {
|
|
|
4
4
|
const { executionId: _executionId, ...record } = usage;
|
|
5
5
|
return { ...record, schemaVersion: 1, coverage: 'request' };
|
|
6
6
|
}
|
|
7
|
-
import { boundedConversationItemId, compactRunnerText, compactRunnerValue } from '
|
|
8
|
-
import { runnerErrorProjection } from '
|
|
7
|
+
import { boundedConversationItemId, compactRunnerText, compactRunnerValue } from '../normalization.js';
|
|
8
|
+
import { runnerErrorProjection } from '../runner-error.js';
|
|
9
9
|
import { toolPresentationSchema } from '@myagentroam/protocol';
|
|
10
10
|
export class MarAgentConversationNormalizer {
|
|
11
11
|
input(entry) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { MarAgentConversationNormalizer } from './conversation-normalizer.js';
|
|
2
2
|
import { publicGoalHistoryText } from '../../service/goal-runtime.js';
|
|
3
|
-
import { boundedConversationItemId } from '
|
|
3
|
+
import { boundedConversationItemId } from '../normalization.js';
|
|
4
4
|
export function projectMarAgentHistory(session, entries, options = {}) {
|
|
5
5
|
const turns = new Map();
|
|
6
6
|
const normalizer = new MarAgentConversationNormalizer();
|