@myagentroam/node 0.1.4 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -1
- package/dist/capabilities.d.ts +2 -0
- package/dist/capabilities.js +15 -4
- package/dist/claude-agent-sdk.d.ts +3 -1
- package/dist/claude-agent-sdk.js +9 -2
- package/dist/claude-channel.js +0 -1
- package/dist/codex-app-server.d.ts +1 -0
- package/dist/codex-app-server.js +8 -1
- package/dist/config.d.ts +3 -0
- package/dist/config.js +18 -2
- package/dist/connector/node-connector-options.d.ts +3 -0
- package/dist/connector/node-connector-options.js +0 -1
- package/dist/connector/node-operation-router.js +0 -1
- package/dist/connector.d.ts +3 -0
- package/dist/connector.js +109 -7
- package/dist/control-outbound-scheduler.js +0 -1
- package/dist/database.d.ts +4 -0
- package/dist/database.js +14 -9
- package/dist/event-buffer.js +0 -1
- package/dist/fake-runner.js +0 -1
- package/dist/health.js +0 -1
- package/dist/main.js +6 -1
- package/dist/migrations/v001.js +0 -1
- package/dist/migrations/v002.js +0 -1
- package/dist/migrations/v003.d.ts +4 -0
- package/dist/migrations/v003.js +44 -0
- package/dist/native-jsonl-reader.js +0 -1
- package/dist/native-session-history.d.ts +19 -1
- package/dist/native-session-history.js +65 -3
- package/dist/opencode-runtime.d.ts +33 -0
- package/dist/opencode-runtime.js +80 -0
- package/dist/opencode-server.d.ts +47 -0
- package/dist/opencode-server.js +250 -0
- package/dist/operational.js +10 -3
- package/dist/process-tree.js +0 -1
- package/dist/runner/abstract-runner.d.ts +7 -2
- package/dist/runner/abstract-runner.js +17 -2
- package/dist/runner/claude/managed-run-controller.js +20 -1
- package/dist/runner/claude-code-runner.d.ts +3 -1
- package/dist/runner/claude-code-runner.js +26 -8
- package/dist/runner/codex/conversation-parser.d.ts +1 -3
- package/dist/runner/codex/conversation-parser.js +174 -34
- package/dist/runner/codex/managed-run-controller.d.ts +2 -1
- package/dist/runner/codex/managed-run-controller.js +13 -4
- package/dist/runner/codex-runner.d.ts +4 -0
- package/dist/runner/codex-runner.js +27 -4
- package/dist/runner/fake-test-runner.js +0 -1
- package/dist/runner/opencode/conversation-parser.d.ts +27 -0
- package/dist/runner/opencode/conversation-parser.js +217 -0
- package/dist/runner/opencode/managed-run-controller.d.ts +76 -0
- package/dist/runner/opencode/managed-run-controller.js +451 -0
- package/dist/runner/opencode-runner.d.ts +60 -0
- package/dist/runner/opencode-runner.js +330 -0
- package/dist/runner/runner-registry.d.ts +3 -1
- package/dist/runner/runner-registry.js +12 -3
- package/dist/runner-command-engine.js +0 -1
- package/dist/runner-profiles.d.ts +4 -0
- package/dist/runner-profiles.js +76 -3
- package/dist/runner-usage.js +0 -1
- package/dist/runtime-state.js +20 -9
- package/dist/service/attachment-domain-state.js +0 -1
- package/dist/service/conversation-history-service.js +0 -1
- package/dist/service/external-session-resume-service.js +0 -1
- package/dist/service/fake-managed-run-service.js +0 -1
- package/dist/service/managed-runner-session-service.d.ts +3 -1
- package/dist/service/managed-runner-session-service.js +8 -4
- package/dist/service/native-session-projection-service.d.ts +2 -1
- package/dist/service/native-session-projection-service.js +8 -5
- package/dist/service/native-session-watch-service.js +0 -1
- package/dist/service/node-connection-lifecycle-service.js +3 -2
- package/dist/service/node-control-channel.d.ts +1 -1
- package/dist/service/node-control-channel.js +5 -4
- package/dist/service/node-control-message-service.js +0 -1
- package/dist/service/node-request-service.js +0 -1
- package/dist/service/node-run-event-bridge.d.ts +2 -0
- package/dist/service/node-run-event-bridge.js +4 -1
- package/dist/service/node-terminal-channel.js +16 -10
- package/dist/service/node-upgrade-coordinator.d.ts +29 -0
- package/dist/service/node-upgrade-coordinator.js +137 -0
- package/dist/service/node-workspace-coordinator.js +0 -1
- package/dist/service/run-attachment-service.js +0 -1
- package/dist/service/run-domain-state.js +0 -1
- package/dist/service/run-event-service.js +0 -1
- package/dist/service/run-workbench-service.js +0 -1
- package/dist/service/runner-channel-message-service.js +0 -1
- package/dist/service/runner-interaction-service.js +2 -1
- package/dist/service/runner-service.d.ts +5 -4
- package/dist/service/runner-service.js +19 -6
- package/dist/service/session-catalog-service.d.ts +16 -1
- package/dist/service/session-catalog-service.js +82 -3
- package/dist/service/session-command-service.js +0 -1
- package/dist/service/session-context-service.js +0 -1
- package/dist/service/session-domain-state.js +0 -1
- package/dist/service/session-identity-service.js +0 -1
- package/dist/service/session-lifecycle-service.js +13 -7
- package/dist/service/session-message-service.js +0 -1
- package/dist/service/session-presentation-service.js +0 -1
- package/dist/service/session-query-service.js +0 -1
- package/dist/service/terminal-relay-state.js +0 -1
- package/dist/service/terminal-service.js +0 -1
- package/dist/service/workbench-event-service.js +0 -1
- package/dist/service/workbench-manifest-service.d.ts +5 -4
- package/dist/service/workbench-manifest-service.js +3 -2
- package/dist/service/workspace-change-service.js +2 -2
- package/dist/service/workspace-content-search-service.d.ts +14 -0
- package/dist/service/workspace-content-search-service.js +477 -0
- package/dist/service/workspace-domain-state.js +0 -1
- package/dist/service/workspace-file-service.d.ts +3 -0
- package/dist/service/workspace-file-service.js +35 -3
- package/dist/service/workspace-queue-workbench-service.js +0 -1
- package/dist/service/workspace-service.js +23 -10
- package/dist/service/workspace-session-service.js +0 -1
- package/dist/service/workspace-upload-service.js +0 -1
- package/dist/service/workspace-watch-service.js +0 -1
- package/dist/service/workspace-workbench-service.d.ts +9 -0
- package/dist/service/workspace-workbench-service.js +69 -2
- package/dist/service.js +2 -3
- package/dist/storage.js +0 -1
- package/dist/supervisor.d.ts +1 -0
- package/dist/supervisor.js +154 -0
- package/dist/terminal.js +0 -1
- package/dist/util/node-operation-parsers.d.ts +1 -0
- package/dist/util/node-operation-parsers.js +3 -1
- package/dist/util/runner-native-session-parsers.js +117 -73
- package/dist/util/secret-environment.js +0 -1
- package/dist/workspace.d.ts +62 -2
- package/dist/workspace.js +539 -57
- package/package.json +3 -2
- package/dist/capabilities.js.map +0 -1
- package/dist/claude-agent-sdk.js.map +0 -1
- package/dist/claude-channel.js.map +0 -1
- package/dist/codex-app-server.js.map +0 -1
- package/dist/config.js.map +0 -1
- package/dist/connector/node-connector-options.js.map +0 -1
- package/dist/connector/node-operation-router.js.map +0 -1
- package/dist/connector.js.map +0 -1
- package/dist/control-outbound-scheduler.js.map +0 -1
- package/dist/database.js.map +0 -1
- package/dist/event-buffer.js.map +0 -1
- package/dist/fake-runner.js.map +0 -1
- package/dist/health.js.map +0 -1
- package/dist/main.js.map +0 -1
- package/dist/migrations/v001.js.map +0 -1
- package/dist/migrations/v002.js.map +0 -1
- package/dist/native-jsonl-reader.js.map +0 -1
- package/dist/native-session-history.js.map +0 -1
- package/dist/operational.js.map +0 -1
- package/dist/process-tree.js.map +0 -1
- package/dist/runner/abstract-runner.js.map +0 -1
- package/dist/runner/claude/managed-run-controller.js.map +0 -1
- package/dist/runner/claude-code-runner.js.map +0 -1
- package/dist/runner/codex/conversation-parser.js.map +0 -1
- package/dist/runner/codex/managed-run-controller.js.map +0 -1
- package/dist/runner/codex-runner.js.map +0 -1
- package/dist/runner/fake-test-runner.js.map +0 -1
- package/dist/runner/runner-registry.js.map +0 -1
- package/dist/runner-command-engine.js.map +0 -1
- package/dist/runner-profiles.js.map +0 -1
- package/dist/runner-usage.js.map +0 -1
- package/dist/runtime-state.js.map +0 -1
- package/dist/service/attachment-domain-state.js.map +0 -1
- package/dist/service/conversation-history-service.js.map +0 -1
- package/dist/service/external-session-resume-service.js.map +0 -1
- package/dist/service/fake-managed-run-service.js.map +0 -1
- package/dist/service/managed-runner-session-service.js.map +0 -1
- package/dist/service/native-session-projection-service.js.map +0 -1
- package/dist/service/native-session-watch-service.js.map +0 -1
- package/dist/service/node-connection-lifecycle-service.js.map +0 -1
- package/dist/service/node-control-channel.js.map +0 -1
- package/dist/service/node-control-message-service.js.map +0 -1
- package/dist/service/node-request-service.js.map +0 -1
- package/dist/service/node-run-event-bridge.js.map +0 -1
- package/dist/service/node-terminal-channel.js.map +0 -1
- package/dist/service/node-workspace-coordinator.js.map +0 -1
- package/dist/service/run-attachment-service.js.map +0 -1
- package/dist/service/run-domain-state.js.map +0 -1
- package/dist/service/run-event-service.js.map +0 -1
- package/dist/service/run-workbench-service.js.map +0 -1
- package/dist/service/runner-channel-message-service.js.map +0 -1
- package/dist/service/runner-interaction-service.js.map +0 -1
- package/dist/service/runner-service.js.map +0 -1
- package/dist/service/session-catalog-service.js.map +0 -1
- package/dist/service/session-command-service.js.map +0 -1
- package/dist/service/session-context-service.js.map +0 -1
- package/dist/service/session-domain-state.js.map +0 -1
- package/dist/service/session-identity-service.js.map +0 -1
- package/dist/service/session-lifecycle-service.js.map +0 -1
- package/dist/service/session-message-service.js.map +0 -1
- package/dist/service/session-presentation-service.js.map +0 -1
- package/dist/service/session-query-service.js.map +0 -1
- package/dist/service/terminal-relay-state.js.map +0 -1
- package/dist/service/terminal-service.js.map +0 -1
- package/dist/service/workbench-event-service.js.map +0 -1
- package/dist/service/workbench-manifest-service.js.map +0 -1
- package/dist/service/workspace-change-service.js.map +0 -1
- package/dist/service/workspace-domain-state.js.map +0 -1
- package/dist/service/workspace-file-service.js.map +0 -1
- package/dist/service/workspace-queue-workbench-service.js.map +0 -1
- package/dist/service/workspace-service.js.map +0 -1
- package/dist/service/workspace-session-service.js.map +0 -1
- package/dist/service/workspace-upload-service.js.map +0 -1
- package/dist/service/workspace-watch-service.js.map +0 -1
- package/dist/service/workspace-workbench-service.js.map +0 -1
- package/dist/service.js.map +0 -1
- package/dist/storage.js.map +0 -1
- package/dist/terminal.js.map +0 -1
- package/dist/util/node-operation-parsers.js.map +0 -1
- package/dist/util/runner-native-session-parsers.js.map +0 -1
- package/dist/util/secret-environment.js.map +0 -1
- 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 &&
|
|
119
|
-
|
|
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
|
|
@@ -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
|
-
|
|
44
|
-
this.
|
|
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
|
|
@@ -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
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
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
|
+
}
|
|
@@ -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
|
-
.
|
|
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.
|
|
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 {};
|