@myagentroam/node 0.11.36 → 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/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 +5 -5
- 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
package/dist/codex-app-server.js
CHANGED
|
@@ -1,471 +1 @@
|
|
|
1
|
-
|
|
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
|
-
}
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
const USER_AUTHORIZATION_CLOCK_SKEW_MS = 60 * 60 * 1_000;
|
|
2
|
+
export function validUserAuthorization(value, envelope, operation, nodeId, now = Date.now()) {
|
|
3
|
+
if (typeof value !== 'object' || value === null || nodeId === undefined)
|
|
4
|
+
return false;
|
|
5
|
+
const authorization = value;
|
|
6
|
+
const modelResourceCapability = operation === 'model.resource.read' &&
|
|
7
|
+
authorization.userId === 0 &&
|
|
8
|
+
authorization.sessionHash === 'model-resource';
|
|
9
|
+
return ((modelResourceCapability ||
|
|
10
|
+
(typeof authorization.userId === 'number' &&
|
|
11
|
+
Number.isSafeInteger(authorization.userId) &&
|
|
12
|
+
authorization.userId > 0 &&
|
|
13
|
+
typeof authorization.sessionHash === 'string' &&
|
|
14
|
+
/^[A-Za-z0-9_-]{43}$/.test(authorization.sessionHash))) &&
|
|
15
|
+
authorization.nodeId === nodeId &&
|
|
16
|
+
authorization.operation === operation &&
|
|
17
|
+
authorization.requestId === envelope.id &&
|
|
18
|
+
typeof authorization.issuedAt === 'number' &&
|
|
19
|
+
typeof authorization.expiresAt === 'number' &&
|
|
20
|
+
Number.isSafeInteger(authorization.issuedAt) &&
|
|
21
|
+
Number.isSafeInteger(authorization.expiresAt) &&
|
|
22
|
+
authorization.expiresAt >= authorization.issuedAt &&
|
|
23
|
+
authorization.issuedAt <= now + USER_AUTHORIZATION_CLOCK_SKEW_MS &&
|
|
24
|
+
authorization.expiresAt >= now - USER_AUTHORIZATION_CLOCK_SKEW_MS &&
|
|
25
|
+
authorization.expiresAt - authorization.issuedAt <= 15_000);
|
|
26
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createSocket } from 'node:dgram';
|
|
2
2
|
import { isIP } from 'node:net';
|
|
3
3
|
import { directDataControlFrameSchema, directNodeCommandSchema } from '@myagentroam/protocol';
|
|
4
|
-
import { TerminalDirectService } from '
|
|
4
|
+
import { TerminalDirectService } from '../service/terminal-direct-service.js';
|
|
5
5
|
import { IceUdpMuxListener as NativeIceUdpMuxListener } from 'node-datachannel';
|
|
6
6
|
import { RTCPeerConnection } from 'node-datachannel/polyfill';
|
|
7
7
|
const MAX_HOST_CANDIDATES = 32;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { nodeCapabilitiesSchema } from '@myagentroam/protocol';
|
|
2
|
+
export function validatedCapabilities(value) {
|
|
3
|
+
return nodeCapabilitiesSchema.parse(value);
|
|
4
|
+
}
|
|
5
|
+
export function nodeConnectEndpoint(serverUrl) {
|
|
6
|
+
const endpoint = new URL(serverUrl);
|
|
7
|
+
if (endpoint.protocol === 'http:')
|
|
8
|
+
endpoint.protocol = 'ws:';
|
|
9
|
+
if (endpoint.protocol === 'https:')
|
|
10
|
+
endpoint.protocol = 'wss:';
|
|
11
|
+
if (endpoint.protocol !== 'ws:' && endpoint.protocol !== 'wss:') {
|
|
12
|
+
throw new Error('SERVER_URL_INVALID');
|
|
13
|
+
}
|
|
14
|
+
endpoint.pathname = `${endpoint.pathname.replace(/\/$/, '')}/api/node/connect`;
|
|
15
|
+
endpoint.search = '';
|
|
16
|
+
endpoint.hash = '';
|
|
17
|
+
return endpoint.toString();
|
|
18
|
+
}
|
|
19
|
+
export function nodeTerminalConnectEndpoint(serverUrl) {
|
|
20
|
+
const endpoint = new URL(serverUrl);
|
|
21
|
+
if (endpoint.protocol === 'http:')
|
|
22
|
+
endpoint.protocol = 'ws:';
|
|
23
|
+
if (endpoint.protocol === 'https:')
|
|
24
|
+
endpoint.protocol = 'wss:';
|
|
25
|
+
if (endpoint.protocol !== 'ws:' && endpoint.protocol !== 'wss:') {
|
|
26
|
+
throw new Error('SERVER_URL_INVALID');
|
|
27
|
+
}
|
|
28
|
+
endpoint.pathname = `${endpoint.pathname.replace(/\/$/, '')}/api/node/terminal-connect`;
|
|
29
|
+
endpoint.search = '';
|
|
30
|
+
endpoint.hash = '';
|
|
31
|
+
return endpoint.toString();
|
|
32
|
+
}
|