@myagentroam/node 0.1.4 → 0.1.6

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 (210) hide show
  1. package/README.md +9 -1
  2. package/dist/capabilities.d.ts +2 -0
  3. package/dist/capabilities.js +15 -4
  4. package/dist/claude-agent-sdk.d.ts +3 -1
  5. package/dist/claude-agent-sdk.js +9 -2
  6. package/dist/claude-channel.js +0 -1
  7. package/dist/codex-app-server.d.ts +1 -0
  8. package/dist/codex-app-server.js +8 -1
  9. package/dist/config.d.ts +3 -0
  10. package/dist/config.js +18 -2
  11. package/dist/connector/node-connector-options.d.ts +3 -0
  12. package/dist/connector/node-connector-options.js +0 -1
  13. package/dist/connector/node-operation-router.js +0 -1
  14. package/dist/connector.d.ts +3 -0
  15. package/dist/connector.js +109 -7
  16. package/dist/control-outbound-scheduler.js +0 -1
  17. package/dist/database.d.ts +4 -0
  18. package/dist/database.js +14 -9
  19. package/dist/event-buffer.js +0 -1
  20. package/dist/fake-runner.js +0 -1
  21. package/dist/health.js +0 -1
  22. package/dist/main.js +6 -1
  23. package/dist/migrations/v001.js +0 -1
  24. package/dist/migrations/v002.js +0 -1
  25. package/dist/migrations/v003.d.ts +4 -0
  26. package/dist/migrations/v003.js +44 -0
  27. package/dist/native-jsonl-reader.js +0 -1
  28. package/dist/native-session-history.d.ts +19 -1
  29. package/dist/native-session-history.js +65 -3
  30. package/dist/opencode-runtime.d.ts +33 -0
  31. package/dist/opencode-runtime.js +80 -0
  32. package/dist/opencode-server.d.ts +47 -0
  33. package/dist/opencode-server.js +250 -0
  34. package/dist/operational.js +10 -3
  35. package/dist/process-tree.js +0 -1
  36. package/dist/runner/abstract-runner.d.ts +7 -2
  37. package/dist/runner/abstract-runner.js +17 -2
  38. package/dist/runner/claude/managed-run-controller.js +20 -1
  39. package/dist/runner/claude-code-runner.d.ts +3 -1
  40. package/dist/runner/claude-code-runner.js +26 -8
  41. package/dist/runner/codex/conversation-parser.d.ts +1 -3
  42. package/dist/runner/codex/conversation-parser.js +174 -34
  43. package/dist/runner/codex/managed-run-controller.d.ts +2 -1
  44. package/dist/runner/codex/managed-run-controller.js +13 -4
  45. package/dist/runner/codex-runner.d.ts +4 -0
  46. package/dist/runner/codex-runner.js +27 -4
  47. package/dist/runner/fake-test-runner.js +0 -1
  48. package/dist/runner/opencode/conversation-parser.d.ts +27 -0
  49. package/dist/runner/opencode/conversation-parser.js +217 -0
  50. package/dist/runner/opencode/managed-run-controller.d.ts +76 -0
  51. package/dist/runner/opencode/managed-run-controller.js +451 -0
  52. package/dist/runner/opencode-runner.d.ts +60 -0
  53. package/dist/runner/opencode-runner.js +330 -0
  54. package/dist/runner/runner-registry.d.ts +3 -1
  55. package/dist/runner/runner-registry.js +12 -3
  56. package/dist/runner-command-engine.js +0 -1
  57. package/dist/runner-profiles.d.ts +4 -0
  58. package/dist/runner-profiles.js +76 -3
  59. package/dist/runner-usage.js +0 -1
  60. package/dist/runtime-state.js +20 -9
  61. package/dist/service/attachment-domain-state.js +0 -1
  62. package/dist/service/conversation-history-service.js +0 -1
  63. package/dist/service/external-session-resume-service.js +0 -1
  64. package/dist/service/fake-managed-run-service.js +0 -1
  65. package/dist/service/managed-runner-session-service.d.ts +3 -1
  66. package/dist/service/managed-runner-session-service.js +8 -4
  67. package/dist/service/native-session-projection-service.d.ts +2 -1
  68. package/dist/service/native-session-projection-service.js +8 -5
  69. package/dist/service/native-session-watch-service.js +0 -1
  70. package/dist/service/node-connection-lifecycle-service.js +3 -2
  71. package/dist/service/node-control-channel.d.ts +1 -1
  72. package/dist/service/node-control-channel.js +5 -4
  73. package/dist/service/node-control-message-service.js +0 -1
  74. package/dist/service/node-request-service.js +0 -1
  75. package/dist/service/node-run-event-bridge.d.ts +2 -0
  76. package/dist/service/node-run-event-bridge.js +4 -1
  77. package/dist/service/node-terminal-channel.js +16 -10
  78. package/dist/service/node-upgrade-coordinator.d.ts +29 -0
  79. package/dist/service/node-upgrade-coordinator.js +137 -0
  80. package/dist/service/node-workspace-coordinator.js +0 -1
  81. package/dist/service/run-attachment-service.js +0 -1
  82. package/dist/service/run-domain-state.js +0 -1
  83. package/dist/service/run-event-service.js +0 -1
  84. package/dist/service/run-workbench-service.js +0 -1
  85. package/dist/service/runner-channel-message-service.js +0 -1
  86. package/dist/service/runner-interaction-service.js +2 -1
  87. package/dist/service/runner-service.d.ts +5 -4
  88. package/dist/service/runner-service.js +19 -6
  89. package/dist/service/session-catalog-service.d.ts +16 -1
  90. package/dist/service/session-catalog-service.js +82 -3
  91. package/dist/service/session-command-service.js +0 -1
  92. package/dist/service/session-context-service.js +0 -1
  93. package/dist/service/session-domain-state.js +0 -1
  94. package/dist/service/session-identity-service.js +0 -1
  95. package/dist/service/session-lifecycle-service.js +13 -7
  96. package/dist/service/session-message-service.js +0 -1
  97. package/dist/service/session-presentation-service.js +0 -1
  98. package/dist/service/session-query-service.js +0 -1
  99. package/dist/service/terminal-relay-state.js +0 -1
  100. package/dist/service/terminal-service.js +0 -1
  101. package/dist/service/workbench-event-service.js +0 -1
  102. package/dist/service/workbench-manifest-service.d.ts +5 -4
  103. package/dist/service/workbench-manifest-service.js +3 -2
  104. package/dist/service/workspace-change-service.js +2 -2
  105. package/dist/service/workspace-content-search-service.d.ts +14 -0
  106. package/dist/service/workspace-content-search-service.js +477 -0
  107. package/dist/service/workspace-domain-state.js +0 -1
  108. package/dist/service/workspace-file-service.d.ts +3 -0
  109. package/dist/service/workspace-file-service.js +35 -3
  110. package/dist/service/workspace-queue-workbench-service.js +0 -1
  111. package/dist/service/workspace-service.js +23 -10
  112. package/dist/service/workspace-session-service.js +0 -1
  113. package/dist/service/workspace-upload-service.js +0 -1
  114. package/dist/service/workspace-watch-service.js +0 -1
  115. package/dist/service/workspace-workbench-service.d.ts +9 -0
  116. package/dist/service/workspace-workbench-service.js +69 -2
  117. package/dist/service.js +2 -3
  118. package/dist/storage.js +0 -1
  119. package/dist/supervisor.d.ts +1 -0
  120. package/dist/supervisor.js +154 -0
  121. package/dist/terminal.js +0 -1
  122. package/dist/util/node-operation-parsers.d.ts +1 -0
  123. package/dist/util/node-operation-parsers.js +3 -1
  124. package/dist/util/runner-native-session-parsers.js +117 -73
  125. package/dist/util/secret-environment.js +0 -1
  126. package/dist/workspace.d.ts +62 -2
  127. package/dist/workspace.js +539 -57
  128. package/package.json +3 -2
  129. package/dist/capabilities.js.map +0 -1
  130. package/dist/claude-agent-sdk.js.map +0 -1
  131. package/dist/claude-channel.js.map +0 -1
  132. package/dist/codex-app-server.js.map +0 -1
  133. package/dist/config.js.map +0 -1
  134. package/dist/connector/node-connector-options.js.map +0 -1
  135. package/dist/connector/node-operation-router.js.map +0 -1
  136. package/dist/connector.js.map +0 -1
  137. package/dist/control-outbound-scheduler.js.map +0 -1
  138. package/dist/database.js.map +0 -1
  139. package/dist/event-buffer.js.map +0 -1
  140. package/dist/fake-runner.js.map +0 -1
  141. package/dist/health.js.map +0 -1
  142. package/dist/main.js.map +0 -1
  143. package/dist/migrations/v001.js.map +0 -1
  144. package/dist/migrations/v002.js.map +0 -1
  145. package/dist/native-jsonl-reader.js.map +0 -1
  146. package/dist/native-session-history.js.map +0 -1
  147. package/dist/operational.js.map +0 -1
  148. package/dist/process-tree.js.map +0 -1
  149. package/dist/runner/abstract-runner.js.map +0 -1
  150. package/dist/runner/claude/managed-run-controller.js.map +0 -1
  151. package/dist/runner/claude-code-runner.js.map +0 -1
  152. package/dist/runner/codex/conversation-parser.js.map +0 -1
  153. package/dist/runner/codex/managed-run-controller.js.map +0 -1
  154. package/dist/runner/codex-runner.js.map +0 -1
  155. package/dist/runner/fake-test-runner.js.map +0 -1
  156. package/dist/runner/runner-registry.js.map +0 -1
  157. package/dist/runner-command-engine.js.map +0 -1
  158. package/dist/runner-profiles.js.map +0 -1
  159. package/dist/runner-usage.js.map +0 -1
  160. package/dist/runtime-state.js.map +0 -1
  161. package/dist/service/attachment-domain-state.js.map +0 -1
  162. package/dist/service/conversation-history-service.js.map +0 -1
  163. package/dist/service/external-session-resume-service.js.map +0 -1
  164. package/dist/service/fake-managed-run-service.js.map +0 -1
  165. package/dist/service/managed-runner-session-service.js.map +0 -1
  166. package/dist/service/native-session-projection-service.js.map +0 -1
  167. package/dist/service/native-session-watch-service.js.map +0 -1
  168. package/dist/service/node-connection-lifecycle-service.js.map +0 -1
  169. package/dist/service/node-control-channel.js.map +0 -1
  170. package/dist/service/node-control-message-service.js.map +0 -1
  171. package/dist/service/node-request-service.js.map +0 -1
  172. package/dist/service/node-run-event-bridge.js.map +0 -1
  173. package/dist/service/node-terminal-channel.js.map +0 -1
  174. package/dist/service/node-workspace-coordinator.js.map +0 -1
  175. package/dist/service/run-attachment-service.js.map +0 -1
  176. package/dist/service/run-domain-state.js.map +0 -1
  177. package/dist/service/run-event-service.js.map +0 -1
  178. package/dist/service/run-workbench-service.js.map +0 -1
  179. package/dist/service/runner-channel-message-service.js.map +0 -1
  180. package/dist/service/runner-interaction-service.js.map +0 -1
  181. package/dist/service/runner-service.js.map +0 -1
  182. package/dist/service/session-catalog-service.js.map +0 -1
  183. package/dist/service/session-command-service.js.map +0 -1
  184. package/dist/service/session-context-service.js.map +0 -1
  185. package/dist/service/session-domain-state.js.map +0 -1
  186. package/dist/service/session-identity-service.js.map +0 -1
  187. package/dist/service/session-lifecycle-service.js.map +0 -1
  188. package/dist/service/session-message-service.js.map +0 -1
  189. package/dist/service/session-presentation-service.js.map +0 -1
  190. package/dist/service/session-query-service.js.map +0 -1
  191. package/dist/service/terminal-relay-state.js.map +0 -1
  192. package/dist/service/terminal-service.js.map +0 -1
  193. package/dist/service/workbench-event-service.js.map +0 -1
  194. package/dist/service/workbench-manifest-service.js.map +0 -1
  195. package/dist/service/workspace-change-service.js.map +0 -1
  196. package/dist/service/workspace-domain-state.js.map +0 -1
  197. package/dist/service/workspace-file-service.js.map +0 -1
  198. package/dist/service/workspace-queue-workbench-service.js.map +0 -1
  199. package/dist/service/workspace-service.js.map +0 -1
  200. package/dist/service/workspace-session-service.js.map +0 -1
  201. package/dist/service/workspace-upload-service.js.map +0 -1
  202. package/dist/service/workspace-watch-service.js.map +0 -1
  203. package/dist/service/workspace-workbench-service.js.map +0 -1
  204. package/dist/service.js.map +0 -1
  205. package/dist/storage.js.map +0 -1
  206. package/dist/terminal.js.map +0 -1
  207. package/dist/util/node-operation-parsers.js.map +0 -1
  208. package/dist/util/runner-native-session-parsers.js.map +0 -1
  209. package/dist/util/secret-environment.js.map +0 -1
  210. package/dist/workspace.js.map +0 -1
@@ -1,4 +1,4 @@
1
- import type { RunnerDefaultConfiguration } from '@myagentroam/protocol';
1
+ import type { NodeCapabilities, RunnerDefaultConfiguration } from '@myagentroam/protocol';
2
2
  import type { CodexSessionControl } from '../codex-app-server.js';
3
3
  import type { NodeAgentSession, NodeDatabase } from '../database.js';
4
4
  import type { NodeRuntimeState } from '../runtime-state.js';
@@ -11,6 +11,7 @@ interface NativeSessionProjectionServiceOptions {
11
11
  readonly nodeId: () => string;
12
12
  readonly runtime: NodeRuntimeState;
13
13
  readonly runners: RunnerRegistry;
14
+ readonly capabilities: () => NodeCapabilities;
14
15
  readonly state: SessionDomainState<NodeAgentSession, unknown>;
15
16
  readonly commands: CommandStateStore;
16
17
  readonly present: (session: NodeAgentSession) => NodeAgentSession & {
@@ -10,7 +10,7 @@ export class NativeSessionProjectionService {
10
10
  if (workspaceId !== undefined && workspace === undefined)
11
11
  throw new Error('WORKSPACE_NOT_FOUND');
12
12
  const runner = this.options.runners.product(runnerName);
13
- if (runner === undefined)
13
+ if (runner === undefined || !runner.available(this.options.capabilities()))
14
14
  throw new Error('RUNNER_UNAVAILABLE');
15
15
  const sessions = await runner.discoverSessions({
16
16
  workspaces: database.listWorkspaces(),
@@ -27,6 +27,7 @@ export class NativeSessionProjectionService {
27
27
  async list() {
28
28
  const discovered = await Promise.all(this.options.runners
29
29
  .advertised()
30
+ .filter((runner) => runner.available(this.options.capabilities()))
30
31
  .map((runner) => this.discover(runner.name)));
31
32
  const sessions = deduplicateDirectSessions(discovered.flat());
32
33
  this.remember(sessions);
@@ -35,6 +36,7 @@ export class NativeSessionProjectionService {
35
36
  async discoverWorkspace(workspaceId) {
36
37
  const discovered = await Promise.all(this.options.runners
37
38
  .advertised()
39
+ .filter((runner) => runner.available(this.options.capabilities()))
38
40
  .map((runner) => this.discover(runner.name, workspaceId)));
39
41
  const sessions = deduplicateDirectSessions(discovered.flat());
40
42
  this.remember(sessions);
@@ -96,6 +98,7 @@ export class NativeSessionProjectionService {
96
98
  });
97
99
  }
98
100
  resumedConfiguration(session) {
101
+ const workspace = this.options.database()?.getWorkspace(session.workspaceId);
99
102
  const current = {
100
103
  runner: session.runner,
101
104
  model: session.model,
@@ -110,13 +113,14 @@ export class NativeSessionProjectionService {
110
113
  model: current.model,
111
114
  effort: current.effort,
112
115
  access: current.access
113
- }))
116
+ }, workspace))
114
117
  return current;
115
118
  const saved = this.options
116
119
  .database()
117
120
  ?.getRunnerDefaults()
118
- .find((value) => value.runner === session.runner && this.options.runners.supportsConfiguration(value));
119
- return saved ?? this.options.runners.require(session.runner).defaultConfiguration();
121
+ .find((value) => value.runner === session.runner &&
122
+ this.options.runners.supportsConfiguration(value, workspace));
123
+ return saved ?? this.options.runners.require(session.runner).defaultConfiguration(workspace);
120
124
  }
121
125
  ensureResumedConfiguration(session) {
122
126
  const configuration = this.resumedConfiguration(session);
@@ -265,4 +269,3 @@ export class NativeSessionProjectionService {
265
269
  return database;
266
270
  }
267
271
  }
268
- //# sourceMappingURL=native-session-projection-service.js.map
@@ -148,4 +148,3 @@ export class NativeSessionWatchService {
148
148
  }
149
149
  }
150
150
  }
151
- //# sourceMappingURL=native-session-watch-service.js.map
@@ -34,6 +34,7 @@ export class NodeConnectionLifecycleService {
34
34
  serverUrl: config.serverUrl,
35
35
  allowedRoots: config.allowedRoots,
36
36
  ...(config.databasePath === undefined ? {} : { databasePath: config.databasePath }),
37
+ ...(config.upgrade === undefined ? {} : { upgrade: config.upgrade }),
37
38
  nodeId,
38
39
  credential
39
40
  };
@@ -67,7 +68,8 @@ export class NodeConnectionLifecycleService {
67
68
  next = {
68
69
  ...this.options.capabilities(),
69
70
  codex: { available: false },
70
- claudeCode: { available: false }
71
+ claudeCode: { available: false },
72
+ openCode: { available: false }
71
73
  };
72
74
  }
73
75
  if (this.options.stopped() ||
@@ -81,4 +83,3 @@ export class NodeConnectionLifecycleService {
81
83
  }
82
84
  }
83
85
  }
84
- //# sourceMappingURL=node-connection-lifecycle-service.js.map
@@ -10,7 +10,7 @@ interface NodeControlChannelOptions {
10
10
  readonly onConnecting: (attempt: number) => void;
11
11
  readonly onReconnectScheduled: () => void;
12
12
  readonly onMessage: (raw: string) => void;
13
- readonly onClose: (code: number) => void;
13
+ readonly onClose: (code: number, reason: string) => void;
14
14
  }
15
15
  export declare class NodeControlChannel {
16
16
  private readonly options;
@@ -35,13 +35,15 @@ export class NodeControlChannel {
35
35
  socket.close(4000, 'NODE_CREDENTIAL_MISSING');
36
36
  });
37
37
  socket.on('message', (raw) => this.options.onMessage(raw.toString()));
38
- socket.once('close', (code) => {
38
+ socket.once('close', (code, reason) => {
39
39
  if (this.socket !== socket)
40
40
  return;
41
41
  this.socket = undefined;
42
42
  this.outbound.reset();
43
- this.options.onClose(code);
44
- this.scheduleReconnect();
43
+ const reasonText = reason.toString();
44
+ this.options.onClose(code, reasonText);
45
+ if (!(code === 4000 && reasonText === 'NODE_CONNECTION_REPLACED'))
46
+ this.scheduleReconnect();
45
47
  });
46
48
  socket.once('error', () => undefined);
47
49
  }
@@ -81,4 +83,3 @@ export class NodeControlChannel {
81
83
  }, this.options.reconnectDelay(this.attempts++));
82
84
  }
83
85
  }
84
- //# sourceMappingURL=node-control-channel.js.map
@@ -102,4 +102,3 @@ export class NodeControlMessageService {
102
102
  this.options.send('ack', { type: envelope.type }, envelope.id);
103
103
  }
104
104
  }
105
- //# sourceMappingURL=node-control-message-service.js.map
@@ -48,4 +48,3 @@ export class NodeRequestService {
48
48
  }
49
49
  }
50
50
  }
51
- //# sourceMappingURL=node-request-service.js.map
@@ -2,6 +2,7 @@ import type { NodeEnvelope, WorkbenchEventCategory } from '@myagentroam/protocol
2
2
  import type { FakeRunnerStatus } from '../fake-runner.js';
3
3
  import type { CodexRunner } from '../runner/codex-runner.js';
4
4
  import type { ClaudeCodeRunner } from '../runner/claude-code-runner.js';
5
+ import type { OpenCodeRunner } from '../runner/opencode-runner.js';
5
6
  import type { NodeRuntimeState } from '../runtime-state.js';
6
7
  import type { RunDomainState } from './run-domain-state.js';
7
8
  import type { RunEventService } from './run-event-service.js';
@@ -17,6 +18,7 @@ interface NodeRunEventBridgeOptions {
17
18
  readonly queues: WorkspaceQueueWorkbenchService<RunnerImageAttachment>;
18
19
  readonly codex: CodexRunner;
19
20
  readonly claude: ClaudeCodeRunner;
21
+ readonly openCode: OpenCodeRunner;
20
22
  readonly send: (type: string, payload: unknown, replyTo?: string) => void;
21
23
  }
22
24
  /** Bridges process-local Run state to normalized control and Workbench events. */
@@ -62,6 +62,10 @@ export class NodeRunEventBridge {
62
62
  marSessionId: nativeSessionId
63
63
  });
64
64
  }
65
+ for (const [runId, managed] of this.options.openCode.execution) {
66
+ if (managed.sessionId === sessionId)
67
+ this.options.openCode.execution.set(runId, { ...managed, sessionId: nativeSessionId });
68
+ }
65
69
  }
66
70
  reconcile(envelope) {
67
71
  const payload = envelope.payload;
@@ -77,4 +81,3 @@ export class NodeRunEventBridge {
77
81
  this.options.send('ack', { type: 'runs.reconcile' }, envelope.id);
78
82
  }
79
83
  }
80
- //# sourceMappingURL=node-run-event-bridge.js.map
@@ -120,18 +120,25 @@ export class NodeTerminalChannel {
120
120
  }
121
121
  const parsed = terminalDataFrameSchema.safeParse(message.frame);
122
122
  const attachment = this.state.attachments.get(message.ticket);
123
- if (!parsed.success ||
124
- attachment === undefined ||
125
- parsed.data.terminalId !== attachment.terminalId ||
126
- !['input', 'resize', 'close'].includes(parsed.data.type)) {
123
+ if (!parsed.success || !['input', 'resize', 'close'].includes(parsed.data.type)) {
127
124
  this.invalid();
128
125
  return;
129
126
  }
130
- void this.options.manager.acceptFrame(attachment.attachmentId, parsed.data).catch(() => this.sendFrame(message.ticket, {
131
- type: 'error',
132
- terminalId: attachment.terminalId,
133
- code: 'TERMINAL_FRAME_REJECTED'
134
- }));
127
+ if (attachment === undefined)
128
+ return;
129
+ if (parsed.data.terminalId !== attachment.terminalId) {
130
+ this.invalid();
131
+ return;
132
+ }
133
+ void this.options.manager.acceptFrame(attachment.attachmentId, parsed.data).catch(() => {
134
+ this.state.attachments.delete(message.ticket);
135
+ this.options.manager.detach(attachment.attachmentId);
136
+ this.sendFrame(message.ticket, {
137
+ type: 'error',
138
+ terminalId: attachment.terminalId,
139
+ code: 'TERMINAL_FRAME_REJECTED'
140
+ });
141
+ });
135
142
  return;
136
143
  }
137
144
  if (message.type === 'shutdown' && Object.keys(message).length === 1) {
@@ -173,4 +180,3 @@ export class NodeTerminalChannel {
173
180
  this.state.attachments.clear();
174
181
  }
175
182
  }
176
- //# sourceMappingURL=node-terminal-channel.js.map
@@ -0,0 +1,29 @@
1
+ import type { NodeUpgradeStatus } from '@myagentroam/protocol';
2
+ export declare class NodeUpgradeCoordinator {
3
+ private readonly requestPath;
4
+ private readonly activeRunCount;
5
+ private readonly onStatus;
6
+ private readonly onReady;
7
+ private readonly now;
8
+ private status;
9
+ private timer;
10
+ constructor(requestPath: () => string, activeRunCount: () => number, onStatus: (status: NodeUpgradeStatus) => void, onReady: () => void, now?: () => number);
11
+ snapshot(): NodeUpgradeStatus;
12
+ loadResult(resultPath: string): Promise<void>;
13
+ request(data: unknown): {
14
+ status: 'ACCEPTED' | 'ALREADY_PENDING';
15
+ targetVersion: string;
16
+ activeRunCount: number;
17
+ };
18
+ cancel(): {
19
+ cancelled: true;
20
+ };
21
+ blocks(operation: string): boolean;
22
+ pending(): boolean;
23
+ stop(): void;
24
+ private checkReady;
25
+ private checkReadySafely;
26
+ private update;
27
+ private clearTimer;
28
+ }
29
+ export declare function nodeUpgradeRequestPath(databasePath: string): string;
@@ -0,0 +1,137 @@
1
+ import { mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises';
2
+ import { dirname, resolve } from 'node:path';
3
+ const STABLE_VERSION = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/u;
4
+ export class NodeUpgradeCoordinator {
5
+ requestPath;
6
+ activeRunCount;
7
+ onStatus;
8
+ onReady;
9
+ now;
10
+ status = { state: 'IDLE', updatedAt: Date.now() };
11
+ timer;
12
+ constructor(requestPath, activeRunCount, onStatus, onReady, now = Date.now) {
13
+ this.requestPath = requestPath;
14
+ this.activeRunCount = activeRunCount;
15
+ this.onStatus = onStatus;
16
+ this.onReady = onReady;
17
+ this.now = now;
18
+ }
19
+ snapshot() {
20
+ return this.status;
21
+ }
22
+ async loadResult(resultPath) {
23
+ try {
24
+ const result = JSON.parse(await readFile(resultPath, 'utf8'));
25
+ if (result['state'] === 'FAILED' && typeof result['errorCode'] === 'string')
26
+ this.update({
27
+ state: 'FAILED',
28
+ errorCode: result['errorCode'],
29
+ updatedAt: typeof result['updatedAt'] === 'number' ? result['updatedAt'] : this.now()
30
+ });
31
+ }
32
+ catch {
33
+ // Missing or malformed historical result does not prevent Node startup.
34
+ }
35
+ }
36
+ request(data) {
37
+ const targetVersion = record(data).targetVersion;
38
+ if (typeof targetVersion !== 'string' || !STABLE_VERSION.test(targetVersion))
39
+ throw new Error('NODE_UPGRADE_VERSION_INVALID');
40
+ if (this.status.state !== 'IDLE' && this.status.state !== 'FAILED') {
41
+ if (this.status.targetVersion !== targetVersion)
42
+ throw new Error('NODE_UPGRADE_ALREADY_PENDING');
43
+ return { status: 'ALREADY_PENDING', targetVersion, activeRunCount: this.activeRunCount() };
44
+ }
45
+ this.update({
46
+ state: 'WAITING_FOR_RUNS',
47
+ targetVersion,
48
+ activeRunCount: this.activeRunCount(),
49
+ updatedAt: this.now()
50
+ });
51
+ this.timer = setInterval(() => void this.checkReadySafely(), 250);
52
+ void this.checkReadySafely();
53
+ return { status: 'ACCEPTED', targetVersion, activeRunCount: this.activeRunCount() };
54
+ }
55
+ cancel() {
56
+ if (this.status.state !== 'WAITING_FOR_RUNS')
57
+ throw new Error('NODE_UPGRADE_NOT_CANCELLABLE');
58
+ this.clearTimer();
59
+ this.update({ state: 'IDLE', updatedAt: this.now() });
60
+ return { cancelled: true };
61
+ }
62
+ blocks(operation) {
63
+ return (this.pending() &&
64
+ (operation === 'session.start' ||
65
+ operation === 'session.resume' ||
66
+ operation === 'session.message' ||
67
+ operation === 'session.command.execute' ||
68
+ operation === 'runner.command.execute' ||
69
+ operation === 'session.channel.message' ||
70
+ operation === 'workspace.queue.message.execute' ||
71
+ operation === 'terminal.open'));
72
+ }
73
+ pending() {
74
+ return this.status.state === 'WAITING_FOR_RUNS' || this.status.state === 'READY_TO_RESTART';
75
+ }
76
+ stop() {
77
+ this.clearTimer();
78
+ }
79
+ async checkReady() {
80
+ if (this.status.state !== 'WAITING_FOR_RUNS')
81
+ return;
82
+ const activeRunCount = this.activeRunCount();
83
+ if (activeRunCount > 0) {
84
+ if (this.status.activeRunCount !== activeRunCount)
85
+ this.update({ ...this.status, activeRunCount, updatedAt: this.now() });
86
+ return;
87
+ }
88
+ this.clearTimer();
89
+ const targetVersion = this.status.targetVersion;
90
+ this.update({
91
+ state: 'READY_TO_RESTART',
92
+ targetVersion,
93
+ activeRunCount: 0,
94
+ updatedAt: this.now()
95
+ });
96
+ const path = this.requestPath();
97
+ const temporary = `${path}.${process.pid}.tmp`;
98
+ await mkdir(dirname(path), { recursive: true, mode: 0o700 });
99
+ await writeFile(temporary, `${JSON.stringify({ schemaVersion: 1, targetVersion, createdAt: this.now() })}\n`, { mode: 0o600 });
100
+ await rename(temporary, path).catch(async (error) => {
101
+ await rm(temporary, { force: true });
102
+ throw error;
103
+ });
104
+ this.onReady();
105
+ }
106
+ async checkReadySafely() {
107
+ try {
108
+ await this.checkReady();
109
+ }
110
+ catch {
111
+ this.clearTimer();
112
+ this.update({
113
+ state: 'FAILED',
114
+ targetVersion: this.status.targetVersion,
115
+ errorCode: 'NODE_UPGRADE_REQUEST_WRITE_FAILED',
116
+ updatedAt: this.now()
117
+ });
118
+ }
119
+ }
120
+ update(status) {
121
+ this.status = status;
122
+ this.onStatus(status);
123
+ }
124
+ clearTimer() {
125
+ if (this.timer !== undefined)
126
+ clearInterval(this.timer);
127
+ this.timer = undefined;
128
+ }
129
+ }
130
+ export function nodeUpgradeRequestPath(databasePath) {
131
+ return resolve(dirname(databasePath), 'upgrade-request.json');
132
+ }
133
+ function record(value) {
134
+ if (value === null || typeof value !== 'object' || Array.isArray(value))
135
+ throw new Error('NODE_UPGRADE_REQUEST_INVALID');
136
+ return value;
137
+ }
@@ -78,4 +78,3 @@ export class NodeWorkspaceCoordinator {
78
78
  }
79
79
  }
80
80
  }
81
- //# sourceMappingURL=node-workspace-coordinator.js.map
@@ -158,4 +158,3 @@ export class RunAttachmentService {
158
158
  this.state.nativeHistoryImages.clear();
159
159
  }
160
160
  }
161
- //# sourceMappingURL=run-attachment-service.js.map
@@ -2,4 +2,3 @@ export class RunDomainState {
2
2
  active = new Set();
3
3
  interruptRequested = new Set();
4
4
  }
5
- //# sourceMappingURL=run-domain-state.js.map
@@ -100,4 +100,3 @@ export class RunEventService {
100
100
  }
101
101
  }
102
102
  }
103
- //# sourceMappingURL=run-event-service.js.map
@@ -111,4 +111,3 @@ export class RunWorkbenchService {
111
111
  function record(value) {
112
112
  return isPlainRecord(value) ? value : {};
113
113
  }
114
- //# sourceMappingURL=run-workbench-service.js.map
@@ -18,4 +18,3 @@ export class RunnerChannelMessageService {
18
18
  this.options.send('ack', { type: envelope.type, delivery }, envelope.id);
19
19
  }
20
20
  }
21
- //# sourceMappingURL=runner-channel-message-service.js.map
@@ -166,6 +166,8 @@ export class RunnerInteractionService {
166
166
  }
167
167
  }
168
168
  respondUserInput(runId, requestId, rawAnswers) {
169
+ if (this.options.runners.respondUserInput(runId, requestId, rawAnswers))
170
+ return;
169
171
  if (this.options.codex().execution.userInputs.has(requestId)) {
170
172
  this.respondCodexUserInput(runId, requestId, rawAnswers);
171
173
  return;
@@ -242,4 +244,3 @@ export class RunnerInteractionService {
242
244
  });
243
245
  }
244
246
  }
245
- //# sourceMappingURL=runner-interaction-service.js.map
@@ -11,7 +11,7 @@ export declare class RunnerService {
11
11
  constructor(database: () => NodeDatabase, capabilities: () => NodeCapabilities, runners: RunnerRegistry, usage: RunnerUsageReader);
12
12
  operations(): Readonly<Record<string, NodeOperationHandler>>;
13
13
  profiles(): readonly {
14
- runner: "codex" | "claude-code";
14
+ runner: "codex" | "claude-code" | "opencode";
15
15
  capabilities: string[];
16
16
  models: {
17
17
  id: string;
@@ -24,18 +24,19 @@ export declare class RunnerService {
24
24
  description: string;
25
25
  }[];
26
26
  commands: {
27
+ id: string;
27
28
  available: boolean;
28
- runner: "codex" | "claude-code";
29
+ runner: "codex" | "claude-code" | "opencode";
29
30
  reasonCode: string | null;
30
- id: string;
31
31
  label: string;
32
32
  description: string;
33
33
  inputHint: string;
34
- source: "CODEX_APP_SERVER" | "CLAUDE_AGENT_SDK";
34
+ source: "CODEX_APP_SERVER" | "CLAUDE_AGENT_SDK" | "OPENCODE_SERVER";
35
35
  interaction: "RUNNER_TEXT" | "IMMEDIATE_ACTION" | "TOGGLE" | "VALUE";
36
36
  stateLabel?: string | undefined;
37
37
  }[];
38
38
  }[];
39
+ private refreshProfiles;
39
40
  private usageStatuses;
40
41
  private readUsage;
41
42
  private listProfiles;
@@ -1,4 +1,5 @@
1
1
  import { runnerDefaultConfigurationSchema } from '@myagentroam/protocol';
2
+ import { parseSecretEnvironment } from '../util/secret-environment.js';
2
3
  export class RunnerService {
3
4
  database;
4
5
  capabilities;
@@ -14,30 +15,43 @@ export class RunnerService {
14
15
  return {
15
16
  'runner.usage.status': () => this.usageStatuses(),
16
17
  'runner.usage.read': (data) => this.readUsage(data),
17
- 'runner.profiles.list': () => this.listProfiles(),
18
+ 'runner.profiles.list': (data) => this.listProfiles(data),
18
19
  'runner.defaults.save': (data) => this.saveDefaults(data)
19
20
  };
20
21
  }
21
22
  profiles() {
22
23
  return this.runners.profiles(this.capabilities());
23
24
  }
25
+ refreshProfiles(workspaceId, environment = {}) {
26
+ const workspace = workspaceId === undefined ? undefined : this.database().getWorkspace(workspaceId);
27
+ if (workspaceId !== undefined && workspace === undefined)
28
+ throw new Error('WORKSPACE_NOT_FOUND');
29
+ return this.runners.refreshProfiles(this.capabilities(), workspace, environment);
30
+ }
24
31
  async usageStatuses() {
25
32
  return {
26
33
  statuses: await Promise.all(this.runners
27
34
  .advertised()
28
- .map((runner) => this.usage.status(runner.name)))
35
+ .flatMap((runner) => runner.name === 'codex' || runner.name === 'claude-code'
36
+ ? [this.usage.status(runner.name)]
37
+ : []))
29
38
  };
30
39
  }
31
40
  async readUsage(data) {
32
41
  const input = data;
33
42
  const runner = this.runners.product(input.runner);
34
- if (runner === undefined)
43
+ if (runner === undefined || runner.name === 'opencode')
35
44
  throw new Error('RUNNER_USAGE_INVALID');
36
45
  return { usage: await this.usage.read(runner.name) };
37
46
  }
38
- listProfiles() {
47
+ async listProfiles(data) {
48
+ const input = data;
49
+ const workspaceId = typeof input.workspaceId === 'string' && input.workspaceId.length > 0
50
+ ? input.workspaceId
51
+ : undefined;
52
+ const environment = parseSecretEnvironment(input.secretEnvironment);
39
53
  return {
40
- profiles: this.profiles(),
54
+ profiles: await this.refreshProfiles(workspaceId, environment),
41
55
  defaults: this.database()
42
56
  .getRunnerDefaults()
43
57
  .filter((value) => this.runners.supportsConfiguration(value))
@@ -52,4 +66,3 @@ export class RunnerService {
52
66
  return { defaults: this.database().saveRunnerDefaults(parsed.data) };
53
67
  }
54
68
  }
55
- //# sourceMappingURL=runner-service.js.map
@@ -1,12 +1,14 @@
1
1
  import type { NodeOperationHandler } from '../connector/node-operation-router.js';
2
- import type { NodeAgentSession, NodeDatabase } from '../database.js';
2
+ import type { NodeAgentSession, NodeConversationTurn, NodeDatabase } from '../database.js';
3
3
  import type { NodeRuntimeState } from '../runtime-state.js';
4
4
  import type { ExternalSessionResumeService } from './external-session-resume-service.js';
5
5
  import type { NativeSessionProjectionService } from './native-session-projection-service.js';
6
+ import type { RunnerRegistry } from '../runner/runner-registry.js';
6
7
  interface SessionCatalogServiceOptions {
7
8
  readonly database: () => NodeDatabase;
8
9
  readonly nodeId: () => string;
9
10
  readonly runtime: NodeRuntimeState;
11
+ readonly runners: RunnerRegistry;
10
12
  readonly projection: NativeSessionProjectionService;
11
13
  readonly resume: ExternalSessionResumeService;
12
14
  readonly cachedNative: () => readonly NodeAgentSession[];
@@ -17,14 +19,27 @@ interface SessionCatalogServiceOptions {
17
19
  readonly forget: (session: NodeAgentSession, nativeIds: ReadonlySet<string>) => void;
18
20
  readonly refreshActivity: (session: NodeAgentSession) => Promise<void>;
19
21
  readonly externalActivity: (sessionId: string) => unknown;
22
+ readonly history: (session: NodeAgentSession, input: {
23
+ readonly cursor?: string;
24
+ readonly limit?: number;
25
+ }) => Promise<{
26
+ readonly turns: readonly NodeConversationTurn[];
27
+ readonly nextCursor: string | null;
28
+ }>;
29
+ readonly emitSession: (session: NodeAgentSession) => void;
20
30
  }
21
31
  export declare class SessionCatalogService {
22
32
  private readonly options;
33
+ private rewindQueue;
23
34
  constructor(options: SessionCatalogServiceOptions);
24
35
  operations(): Readonly<Record<string, NodeOperationHandler>>;
25
36
  private list;
26
37
  private mergePersisted;
27
38
  private resume;
39
+ private enqueueRewind;
40
+ private rewind;
41
+ private findTurn;
28
42
  private remove;
29
43
  }
44
+ export declare function rewindTitle(sourceTitle: string, existingTitles?: readonly string[]): string;
30
45
  export {};