@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.
Files changed (142) hide show
  1. package/dist/application/execution-lifecycle.js +54 -0
  2. package/dist/application/node-lifecycle.js +104 -0
  3. package/dist/application/node-operation-admission.js +51 -0
  4. package/dist/application/node-operation-contracts.js +1 -0
  5. package/dist/application/runner-composition.js +22 -0
  6. package/dist/application/session-projection-composition.js +26 -0
  7. package/dist/application/workspace-application.js +61 -0
  8. package/dist/application/workspace-composition.js +21 -0
  9. package/dist/capabilities.js +2 -2
  10. package/dist/codex-app-server.js +1 -471
  11. package/dist/connection/authorization.js +26 -0
  12. package/dist/{service → connection}/direct-transfer-service.js +1 -1
  13. package/dist/connection/endpoints.js +32 -0
  14. package/dist/connector.js +144 -252
  15. package/dist/database.js +34 -14
  16. package/dist/git-askpass.js +1 -1
  17. package/dist/git-execution-helper.js +1 -1
  18. package/dist/hosting/hosted-conversation-file-identity.js +27 -0
  19. package/dist/hosting/hosted-conversation-file-operations.js +44 -0
  20. package/dist/hosting/hosted-conversation-node-service.js +974 -0
  21. package/dist/hosting/hosted-conversation-runs.js +599 -0
  22. package/dist/hosting/hosted-conversation-templates.js +280 -0
  23. package/dist/hosting/hosted-conversation-uploads.js +344 -0
  24. package/dist/hosting/hosted-conversation-watch.js +194 -0
  25. package/dist/hosting/runtime-contracts.js +1 -0
  26. package/dist/runner/abstract-runner.js +4 -13
  27. package/dist/{claude-agent-sdk.js → runner/claude/claude-agent-sdk.js} +2 -2
  28. package/dist/runner/claude/conversation-parser.js +2 -1
  29. package/dist/runner/claude/managed-run-controller.js +6 -7
  30. package/dist/runner/claude/message-parsers.js +2 -1
  31. package/dist/runner/claude/native-transcript.js +2 -1
  32. package/dist/runner/claude/tool-normalizer.js +1 -1
  33. package/dist/runner/claude-code-runner.js +2 -2
  34. package/dist/runner/codex/codex-app-server.js +471 -0
  35. package/dist/runner/codex/conversation-parser.js +4 -2
  36. package/dist/runner/codex/managed-run-controller.js +7 -9
  37. package/dist/runner/codex/native-transcript.js +1 -1
  38. package/dist/runner/codex/tool-normalizer.js +1 -1
  39. package/dist/runner/codex-runner.js +9 -27
  40. package/dist/runner/contracts.js +1 -0
  41. package/dist/runner/mar-agent/conversation-normalizer.js +2 -2
  42. package/dist/runner/mar-agent/history-projection.js +1 -1
  43. package/dist/runner/mar-agent/hosted-conversation-runtime.js +6 -10
  44. package/dist/runner/mar-agent/managed-run-controller.js +85 -61
  45. package/dist/runner/mar-agent-runner.js +1 -1
  46. package/dist/runner/normalization.js +42 -0
  47. package/dist/runner/opencode/conversation-parser.js +1 -1
  48. package/dist/runner/opencode/managed-run-controller.js +6 -7
  49. package/dist/{opencode-server.js → runner/opencode/opencode-server.js} +2 -2
  50. package/dist/runner/opencode/tool-normalizer.js +1 -1
  51. package/dist/runner/opencode-runner.js +4 -5
  52. package/dist/runner/runner-registry.js +4 -1
  53. package/dist/runtime-state.js +48 -372
  54. package/dist/service/computer-use-enablement-service.js +1 -1
  55. package/dist/service/continuous-run-coordinator.js +52 -7
  56. package/dist/service/conversation-history-service.js +4 -4
  57. package/dist/service/conversation-hosting-capability-service.js +1 -1
  58. package/dist/service/conversation-hosting-enablement-service.js +1 -1
  59. package/dist/service/conversation-hosting-lifecycle-service.js +3 -3
  60. package/dist/service/conversation-hosting-maintenance-service.js +1 -1
  61. package/dist/service/conversation-observation.js +1 -1
  62. package/dist/service/conversation-segment-service.js +1 -1
  63. package/dist/service/external-session-resume-service.js +47 -27
  64. package/dist/service/fake-managed-run-service.js +3 -7
  65. package/dist/service/git-operation-service.js +1 -1
  66. package/dist/service/goal-continuation-coordinator.js +14 -7
  67. package/dist/service/mar-agent-model-transport-test-service.js +1 -1
  68. package/dist/service/native-session-watch-service.js +1 -1
  69. package/dist/service/node-control-channel.js +1 -5
  70. package/dist/service/node-request-service.js +1 -1
  71. package/dist/service/node-terminal-channel.js +2 -1
  72. package/dist/service/node-workspace-coordinator.js +3 -2
  73. package/dist/service/notification-mcp-bridge.js +6 -2
  74. package/dist/service/recent-run-projection-service.js +1 -1
  75. package/dist/service/restart-session-restorer.js +1 -1
  76. package/dist/service/run-event-service.js +49 -42
  77. package/dist/service/run-workbench-service.js +3 -3
  78. package/dist/service/runner-interaction-service.js +6 -5
  79. package/dist/service/runner-service.js +1 -1
  80. package/dist/service/session-recent-activity.js +2 -1
  81. package/dist/service/skill-directory-service.js +1 -1
  82. package/dist/service/skill-install-service.js +2 -2
  83. package/dist/service/terminal-service.js +1 -1
  84. package/dist/service/workbench-event-projection.js +3 -2
  85. package/dist/service/workbench-event-service.js +1 -1
  86. package/dist/service/workspace-service.js +3 -2
  87. package/dist/session/attachments.js +110 -0
  88. package/dist/session/contracts.js +1 -0
  89. package/dist/{util → session}/conversation-identity.js +1 -1
  90. package/dist/session/input-validation.js +15 -0
  91. package/dist/{service → session}/native-session-projection-service.js +40 -11
  92. package/dist/session/pagination.js +77 -0
  93. package/dist/{util → session}/runner-native-session-parsers.js +2 -1
  94. package/dist/session/runtime/approvals.js +90 -0
  95. package/dist/session/runtime/conversation-projection.js +310 -0
  96. package/dist/session/runtime/type-guards.js +19 -0
  97. package/dist/{service → session}/session-catalog-service.js +5 -4
  98. package/dist/{service → session}/session-command-service.js +3 -3
  99. package/dist/{service → session}/session-identity-service.js +1 -1
  100. package/dist/{service → session}/session-lifecycle-service.js +18 -7
  101. package/dist/{service → session}/session-message-service.js +6 -5
  102. package/dist/{service → session}/session-presentation-service.js +1 -1
  103. package/dist/{service → session}/session-query-service.js +2 -2
  104. package/dist/{service → session}/session-schedule-service.js +2 -2
  105. package/dist/util/records.js +3 -0
  106. package/dist/workspace/contracts.js +1 -0
  107. package/dist/workspace/file-index.js +534 -0
  108. package/dist/workspace/files.js +466 -0
  109. package/dist/workspace/git.js +991 -0
  110. package/dist/workspace/path-access.js +184 -0
  111. package/dist/workspace/utf8.js +12 -0
  112. package/dist/{service → workspace}/workspace-change-service.js +45 -21
  113. package/dist/{service → workspace}/workspace-code-navigation-service.js +6 -6
  114. package/dist/{service → workspace}/workspace-file-manager-service.js +1 -1
  115. package/dist/{service → workspace}/workspace-file-service.js +16 -16
  116. package/dist/{service → workspace}/workspace-git-exclude-service.js +1 -1
  117. package/dist/{service → workspace}/workspace-queue-workbench-service.js +3 -2
  118. package/dist/{service → workspace}/workspace-session-service.js +45 -40
  119. package/dist/{service → workspace}/workspace-upload-service.js +28 -28
  120. package/dist/{service → workspace}/workspace-watch-service.js +29 -28
  121. package/dist/{service → workspace}/workspace-workbench-service.js +4 -3
  122. package/package.json +5 -5
  123. package/dist/service/hosted-conversation-node-service.js +0 -2252
  124. package/dist/service/run-domain-state.js +0 -4
  125. package/dist/service/session-domain-state.js +0 -9
  126. package/dist/service/workspace-domain-state.js +0 -41
  127. package/dist/util/node-operation-parsers.js +0 -320
  128. package/dist/workspace.js +0 -2168
  129. /package/dist/{connector → application}/node-connector-options.js +0 -0
  130. /package/dist/{util → connection}/node-operation-data.js +0 -0
  131. /package/dist/{connector → connection}/node-operation-router.js +0 -0
  132. /package/dist/{service → hosting}/hosted-conversation-sandbox-profile.js +0 -0
  133. /package/dist/{service → hosting}/hosted-conversation-store.js +0 -0
  134. /package/dist/{util → mcp}/secret-environment.js +0 -0
  135. /package/dist/{claude-channel.js → runner/claude/claude-channel.js} +0 -0
  136. /package/dist/{util → runner}/personal-instructions.js +0 -0
  137. /package/dist/{util → runner}/runner-error.js +0 -0
  138. /package/dist/{service/conversation-work-process.js → session/runtime/work-process.js} +0 -0
  139. /package/dist/{service → session}/session-context-service.js +0 -0
  140. /package/dist/{util → workspace}/git-credential-client.js +0 -0
  141. /package/dist/{service → workspace}/workspace-content-search-service.js +0 -0
  142. /package/dist/{service → workspace}/workspace-watch-snapshot-service.js +0 -0
@@ -1,471 +1 @@
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
- }
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 './terminal-direct-service.js';
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
+ }