@myagentroam/node 0.1.3 → 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.
- 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 +4 -16
- package/dist/claude-agent-sdk.js +18 -79
- package/dist/claude-channel.js +0 -1
- package/dist/codex-app-server.d.ts +5 -0
- package/dist/codex-app-server.js +26 -5
- package/dist/config.d.ts +3 -0
- package/dist/config.js +18 -2
- package/dist/connector/node-connector-options.d.ts +26 -0
- package/dist/connector/node-connector-options.js +1 -0
- package/dist/connector/node-operation-router.d.ts +9 -0
- package/dist/connector/node-operation-router.js +22 -0
- package/dist/connector.d.ts +62 -356
- package/dist/connector.js +714 -6176
- package/dist/control-outbound-scheduler.d.ts +26 -0
- package/dist/control-outbound-scheduler.js +121 -0
- package/dist/database.d.ts +4 -0
- package/dist/database.js +15 -10
- 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.d.ts +14 -0
- package/dist/native-jsonl-reader.js +97 -0
- package/dist/native-session-history.d.ts +41 -4
- package/dist/native-session-history.js +340 -159
- 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 +153 -0
- package/dist/runner/abstract-runner.js +154 -0
- package/dist/runner/claude/managed-run-controller.d.ts +52 -0
- package/dist/runner/claude/managed-run-controller.js +326 -0
- package/dist/runner/claude-code-runner.d.ts +70 -0
- package/dist/runner/claude-code-runner.js +286 -0
- package/dist/runner/codex/conversation-parser.d.ts +59 -0
- package/dist/runner/codex/conversation-parser.js +816 -0
- package/dist/runner/codex/managed-run-controller.d.ts +80 -0
- package/dist/runner/codex/managed-run-controller.js +388 -0
- package/dist/runner/codex-runner.d.ts +85 -0
- package/dist/runner/codex-runner.js +365 -0
- package/dist/runner/fake-test-runner.d.ts +26 -0
- package/dist/runner/fake-test-runner.js +47 -0
- 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 +19 -0
- package/dist/runner/runner-registry.js +75 -0
- 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.d.ts +2 -2
- package/dist/runner-usage.js +3 -6
- package/dist/runtime-state.js +26 -14
- package/dist/service/attachment-domain-state.d.ts +5 -0
- package/dist/service/attachment-domain-state.js +5 -0
- package/dist/service/conversation-history-service.d.ts +34 -0
- package/dist/service/conversation-history-service.js +158 -0
- package/dist/service/external-session-resume-service.d.ts +32 -0
- package/dist/service/external-session-resume-service.js +98 -0
- package/dist/service/fake-managed-run-service.d.ts +29 -0
- package/dist/service/fake-managed-run-service.js +62 -0
- package/dist/service/managed-runner-session-service.d.ts +12 -0
- package/dist/service/managed-runner-session-service.js +35 -0
- package/dist/service/native-session-projection-service.d.ts +51 -0
- package/dist/service/native-session-projection-service.js +271 -0
- package/dist/service/native-session-watch-service.d.ts +37 -0
- package/dist/service/native-session-watch-service.js +150 -0
- package/dist/service/node-connection-lifecycle-service.d.ts +37 -0
- package/dist/service/node-connection-lifecycle-service.js +85 -0
- package/dist/service/node-control-channel.d.ts +32 -0
- package/dist/service/node-control-channel.js +85 -0
- package/dist/service/node-control-message-service.d.ts +28 -0
- package/dist/service/node-control-message-service.js +104 -0
- package/dist/service/node-request-service.d.ts +14 -0
- package/dist/service/node-request-service.js +50 -0
- package/dist/service/node-run-event-bridge.d.ts +40 -0
- package/dist/service/node-run-event-bridge.js +83 -0
- package/dist/service/node-terminal-channel.d.ts +29 -0
- package/dist/service/node-terminal-channel.js +182 -0
- 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.d.ts +32 -0
- package/dist/service/node-workspace-coordinator.js +80 -0
- package/dist/service/run-attachment-service.d.ts +37 -0
- package/dist/service/run-attachment-service.js +160 -0
- package/dist/service/run-domain-state.d.ts +4 -0
- package/dist/service/run-domain-state.js +4 -0
- package/dist/service/run-event-service.d.ts +31 -0
- package/dist/service/run-event-service.js +102 -0
- package/dist/service/run-workbench-service.d.ts +27 -0
- package/dist/service/run-workbench-service.js +113 -0
- package/dist/service/runner-channel-message-service.d.ts +13 -0
- package/dist/service/runner-channel-message-service.js +20 -0
- package/dist/service/runner-interaction-service.d.ts +40 -0
- package/dist/service/runner-interaction-service.js +246 -0
- package/dist/service/runner-service.d.ts +44 -0
- package/dist/service/runner-service.js +68 -0
- package/dist/service/session-catalog-service.d.ts +45 -0
- package/dist/service/session-catalog-service.js +224 -0
- package/dist/service/session-command-service.d.ts +23 -0
- package/dist/service/session-command-service.js +69 -0
- package/dist/service/session-context-service.d.ts +34 -0
- package/dist/service/session-context-service.js +87 -0
- package/dist/service/session-domain-state.d.ts +8 -0
- package/dist/service/session-domain-state.js +8 -0
- package/dist/service/session-identity-service.d.ts +24 -0
- package/dist/service/session-identity-service.js +86 -0
- package/dist/service/session-lifecycle-service.d.ts +31 -0
- package/dist/service/session-lifecycle-service.js +242 -0
- package/dist/service/session-message-service.d.ts +33 -0
- package/dist/service/session-message-service.js +157 -0
- package/dist/service/session-presentation-service.d.ts +33 -0
- package/dist/service/session-presentation-service.js +36 -0
- package/dist/service/session-query-service.d.ts +31 -0
- package/dist/service/session-query-service.js +77 -0
- package/dist/service/terminal-relay-state.d.ts +6 -0
- package/dist/service/terminal-relay-state.js +3 -0
- package/dist/service/terminal-service.d.ts +12 -0
- package/dist/service/terminal-service.js +52 -0
- package/dist/service/workbench-event-service.d.ts +21 -0
- package/dist/service/workbench-event-service.js +53 -0
- package/dist/service/workbench-manifest-service.d.ts +89 -0
- package/dist/service/workbench-manifest-service.js +70 -0
- package/dist/service/workspace-change-service.d.ts +9 -0
- package/dist/service/workspace-change-service.js +86 -0
- 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.d.ts +75 -0
- package/dist/service/workspace-domain-state.js +40 -0
- package/dist/service/workspace-file-service.d.ts +17 -0
- package/dist/service/workspace-file-service.js +109 -0
- package/dist/service/workspace-queue-workbench-service.d.ts +55 -0
- package/dist/service/workspace-queue-workbench-service.js +226 -0
- package/dist/service/workspace-service.d.ts +15 -0
- package/dist/service/workspace-service.js +67 -0
- package/dist/service/workspace-session-service.d.ts +23 -0
- package/dist/service/workspace-session-service.js +139 -0
- package/dist/service/workspace-upload-service.d.ts +37 -0
- package/dist/service/workspace-upload-service.js +240 -0
- package/dist/service/workspace-watch-service.d.ts +18 -0
- package/dist/service/workspace-watch-service.js +120 -0
- package/dist/service/workspace-workbench-service.d.ts +47 -0
- package/dist/service/workspace-workbench-service.js +223 -0
- 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.d.ts +1 -0
- package/dist/terminal.js +1 -2
- package/dist/util/node-operation-parsers.d.ts +92 -0
- package/dist/util/node-operation-parsers.js +382 -0
- package/dist/util/runner-native-session-parsers.d.ts +72 -0
- package/dist/util/runner-native-session-parsers.js +381 -0
- package/dist/util/secret-environment.d.ts +1 -0
- package/dist/util/secret-environment.js +25 -0
- 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.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-session-history.js.map +0 -1
- package/dist/operational.js.map +0 -1
- package/dist/process-tree.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.js.map +0 -1
- package/dist/storage.js.map +0 -1
- package/dist/terminal.js.map +0 -1
- package/dist/workspace.js.map +0 -1
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import { validSessionEffort, validSessionOption, validSessionTitle } from '../util/node-operation-parsers.js';
|
|
2
|
+
import { isPlainRecord } from '../util/node-operation-parsers.js';
|
|
3
|
+
export class SessionLifecycleService {
|
|
4
|
+
options;
|
|
5
|
+
starts = new Map();
|
|
6
|
+
constructor(options) {
|
|
7
|
+
this.options = options;
|
|
8
|
+
}
|
|
9
|
+
operations() {
|
|
10
|
+
return {
|
|
11
|
+
'session.metadata.update': (data) => this.updateMetadata(record(data)),
|
|
12
|
+
'session.pin.move': (data) => this.movePin(record(data)),
|
|
13
|
+
'session.create': (data) => this.create(record(data)),
|
|
14
|
+
'session.start': (data) => this.start(record(data)),
|
|
15
|
+
'session.config.update': (data) => this.updateConfiguration(record(data))
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
clear() {
|
|
19
|
+
this.starts.clear();
|
|
20
|
+
}
|
|
21
|
+
async updateMetadata(input) {
|
|
22
|
+
if (typeof input.sessionId !== 'string' ||
|
|
23
|
+
(input.customTitle !== undefined &&
|
|
24
|
+
input.customTitle !== null &&
|
|
25
|
+
typeof input.customTitle !== 'string') ||
|
|
26
|
+
(input.pinned !== undefined && typeof input.pinned !== 'boolean'))
|
|
27
|
+
throw new Error('SESSION_INVALID');
|
|
28
|
+
if (input.customTitle === null || input.customTitle?.trim().length === 0)
|
|
29
|
+
throw new Error('SESSION_TITLE_REQUIRED');
|
|
30
|
+
if (input.customTitle !== undefined && input.customTitle.trim().length > 160)
|
|
31
|
+
throw new Error('SESSION_TITLE_INVALID');
|
|
32
|
+
const current = this.options.runtime.getAgentSession(input.sessionId) ??
|
|
33
|
+
(await this.options.projection.createMetadataProjection(input.sessionId));
|
|
34
|
+
if (current === undefined)
|
|
35
|
+
throw new Error('SESSION_NOT_FOUND');
|
|
36
|
+
const nativeCodexRename = this.options.runners.require(current.runner).usesRunnerTitleForRename() &&
|
|
37
|
+
current.externalSessionId !== null &&
|
|
38
|
+
input.customTitle !== undefined;
|
|
39
|
+
await this.options.projection.rename(current, {
|
|
40
|
+
...(input.customTitle === undefined ? {} : { title: input.customTitle }),
|
|
41
|
+
...(input.pinned === undefined ? {} : { pinned: input.pinned })
|
|
42
|
+
});
|
|
43
|
+
const metadataTitle = nativeCodexRename ? null : input.customTitle;
|
|
44
|
+
const updated = this.options.runtime.updateSessionMetadata({
|
|
45
|
+
sessionId: current.id,
|
|
46
|
+
...(metadataTitle === undefined ? {} : { customTitle: metadataTitle }),
|
|
47
|
+
...(input.pinned === undefined ? {} : { pinned: input.pinned })
|
|
48
|
+
});
|
|
49
|
+
return {
|
|
50
|
+
session: this.options.present(nativeCodexRename
|
|
51
|
+
? this.options.runtime.setRunnerTitleFromNative(updated.id, input.customTitle ?? '')
|
|
52
|
+
: updated)
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
movePin(input) {
|
|
56
|
+
if (typeof input.sessionId !== 'string' ||
|
|
57
|
+
(input.direction !== 'up' && input.direction !== 'down'))
|
|
58
|
+
throw new Error('SESSION_PIN_MOVE_INVALID');
|
|
59
|
+
this.options.database().movePinnedSession(input.sessionId, input.direction);
|
|
60
|
+
return { moved: true };
|
|
61
|
+
}
|
|
62
|
+
create(input) {
|
|
63
|
+
const runner = this.options.runners.product(input.runner);
|
|
64
|
+
if (typeof input.workspaceId !== 'string' ||
|
|
65
|
+
runner === undefined ||
|
|
66
|
+
typeof input.cwd !== 'string' ||
|
|
67
|
+
input.cwd.length === 0 ||
|
|
68
|
+
(input.externalSessionId !== undefined && typeof input.externalSessionId !== 'string') ||
|
|
69
|
+
!validSessionTitle(input.title) ||
|
|
70
|
+
!validSessionOption(input.model) ||
|
|
71
|
+
!validSessionEffort(input.effort) ||
|
|
72
|
+
!validSessionOption(input.access))
|
|
73
|
+
throw new Error('SESSION_INVALID');
|
|
74
|
+
const database = this.options.database();
|
|
75
|
+
const workspace = database.getWorkspace(input.workspaceId);
|
|
76
|
+
if (workspace === undefined)
|
|
77
|
+
throw new Error('WORKSPACE_NOT_FOUND');
|
|
78
|
+
const saved = database
|
|
79
|
+
.getRunnerDefaults()
|
|
80
|
+
.find((value) => value.runner === runner.name &&
|
|
81
|
+
this.options.runners.supportsConfiguration(value, workspace));
|
|
82
|
+
const fallback = runner.defaultConfiguration(workspace);
|
|
83
|
+
const configuration = {
|
|
84
|
+
runner: runner.name,
|
|
85
|
+
model: typeof input.model === 'string' ? input.model : (saved?.model ?? fallback.model),
|
|
86
|
+
effort: typeof input.effort === 'string' ? input.effort : (saved?.effort ?? fallback.effort),
|
|
87
|
+
access: typeof input.access === 'string' ? input.access : (saved?.access ?? fallback.access)
|
|
88
|
+
};
|
|
89
|
+
if (!this.options.runners.supportsConfiguration(configuration, workspace))
|
|
90
|
+
throw new Error('RUNNER_CONFIGURATION_UNSUPPORTED');
|
|
91
|
+
const session = this.options.runtime.createAgentSession({
|
|
92
|
+
workspaceId: input.workspaceId,
|
|
93
|
+
runner: runner.name,
|
|
94
|
+
cwd: input.cwd,
|
|
95
|
+
...(typeof input.externalSessionId === 'string'
|
|
96
|
+
? { externalSessionId: input.externalSessionId }
|
|
97
|
+
: {}),
|
|
98
|
+
model: configuration.model,
|
|
99
|
+
effort: configuration.effort,
|
|
100
|
+
access: configuration.access,
|
|
101
|
+
...(typeof input.title === 'string' ? { title: input.title } : {})
|
|
102
|
+
});
|
|
103
|
+
if (input.bootstrapOnly === true)
|
|
104
|
+
this.options.identity.markBootstrap(session.id);
|
|
105
|
+
database.saveRunnerDefaults(configuration);
|
|
106
|
+
if (input.bootstrapOnly !== true)
|
|
107
|
+
this.options.emitSession(session);
|
|
108
|
+
return { session: this.options.present(session) };
|
|
109
|
+
}
|
|
110
|
+
async updateConfiguration(input) {
|
|
111
|
+
if (typeof input.sessionId !== 'string' ||
|
|
112
|
+
typeof input.model !== 'string' ||
|
|
113
|
+
typeof input.effort !== 'string' ||
|
|
114
|
+
!validSessionEffort(input.effort) ||
|
|
115
|
+
typeof input.access !== 'string')
|
|
116
|
+
throw new Error('SESSION_INVALID');
|
|
117
|
+
const current = this.options.runtime.getAgentSession(input.sessionId) ??
|
|
118
|
+
(await this.options.projection.createMetadataProjection(input.sessionId));
|
|
119
|
+
if (current === undefined)
|
|
120
|
+
throw new Error('SESSION_NOT_FOUND');
|
|
121
|
+
const configuration = {
|
|
122
|
+
runner: current.runner,
|
|
123
|
+
model: input.model,
|
|
124
|
+
effort: input.effort,
|
|
125
|
+
access: input.access
|
|
126
|
+
};
|
|
127
|
+
const workspace = this.options.database().getWorkspace(current.workspaceId);
|
|
128
|
+
if (workspace === undefined ||
|
|
129
|
+
!this.options.runners.supportsConfiguration(configuration, workspace))
|
|
130
|
+
throw new Error('RUNNER_CONFIGURATION_UNSUPPORTED');
|
|
131
|
+
const session = this.options.runtime.updateAgentSessionConfiguration({
|
|
132
|
+
sessionId: current.id,
|
|
133
|
+
model: input.model,
|
|
134
|
+
effort: input.effort,
|
|
135
|
+
access: input.access
|
|
136
|
+
});
|
|
137
|
+
if (session.externalSessionId !== null)
|
|
138
|
+
this.options.database().saveNativeSessionMetadata({
|
|
139
|
+
runner: session.runner,
|
|
140
|
+
externalSessionId: session.externalSessionId,
|
|
141
|
+
workspaceId: session.workspaceId,
|
|
142
|
+
model: session.model,
|
|
143
|
+
effort: session.effort,
|
|
144
|
+
access: session.access
|
|
145
|
+
});
|
|
146
|
+
this.options.emitSession(session);
|
|
147
|
+
return { session: this.options.present(session) };
|
|
148
|
+
}
|
|
149
|
+
async start(input) {
|
|
150
|
+
if (typeof input.clientMessageId !== 'string' ||
|
|
151
|
+
input.clientMessageId.length === 0 ||
|
|
152
|
+
typeof input.content !== 'string' ||
|
|
153
|
+
input.content.length === 0)
|
|
154
|
+
throw new Error('MESSAGE_INVALID');
|
|
155
|
+
if (input.deferredCommands !== undefined &&
|
|
156
|
+
(!Array.isArray(input.deferredCommands) ||
|
|
157
|
+
input.deferredCommands.some((value) => !isPlainRecord(value) ||
|
|
158
|
+
typeof value.commandId !== 'string' ||
|
|
159
|
+
typeof value.input !== 'string')))
|
|
160
|
+
throw new Error('RUNNER_COMMAND_INVALID');
|
|
161
|
+
const startKey = `${input.workspaceId}\u0000${input.runner}\u0000${input.clientMessageId}`;
|
|
162
|
+
const existing = this.starts.get(startKey);
|
|
163
|
+
if (existing !== undefined)
|
|
164
|
+
return existing;
|
|
165
|
+
const start = this.startFresh(input);
|
|
166
|
+
this.starts.set(startKey, start);
|
|
167
|
+
try {
|
|
168
|
+
const result = await start;
|
|
169
|
+
while (this.starts.size > 512) {
|
|
170
|
+
const oldest = this.starts.keys().next().value;
|
|
171
|
+
if (oldest === undefined || oldest === startKey)
|
|
172
|
+
break;
|
|
173
|
+
this.starts.delete(oldest);
|
|
174
|
+
}
|
|
175
|
+
return result;
|
|
176
|
+
}
|
|
177
|
+
catch (error) {
|
|
178
|
+
this.starts.delete(startKey);
|
|
179
|
+
throw error;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
async startFresh(input) {
|
|
183
|
+
const created = (await this.options.execute('session.create', {
|
|
184
|
+
...input,
|
|
185
|
+
bootstrapOnly: true
|
|
186
|
+
}));
|
|
187
|
+
const bootstrapId = created.session.id;
|
|
188
|
+
const identity = this.options.identity.wait(bootstrapId);
|
|
189
|
+
try {
|
|
190
|
+
if (Array.isArray(input.deferredCommands))
|
|
191
|
+
for (const value of input.deferredCommands)
|
|
192
|
+
if (isPlainRecord(value))
|
|
193
|
+
await this.options.execute('session.command.execute', {
|
|
194
|
+
sessionId: bootstrapId,
|
|
195
|
+
commandId: value.commandId,
|
|
196
|
+
input: value.input,
|
|
197
|
+
...(input.secretEnvironment === undefined
|
|
198
|
+
? {}
|
|
199
|
+
: { secretEnvironment: input.secretEnvironment })
|
|
200
|
+
});
|
|
201
|
+
const interceptedId = this.options.interceptedSessionId(input.clientMessageId);
|
|
202
|
+
const messageSessionId = interceptedId ?? bootstrapId;
|
|
203
|
+
if (interceptedId !== undefined)
|
|
204
|
+
this.options.identity.promote(bootstrapId, interceptedId);
|
|
205
|
+
const message = (await this.options.execute('session.message', {
|
|
206
|
+
sessionId: messageSessionId,
|
|
207
|
+
clientMessageId: input.clientMessageId,
|
|
208
|
+
content: input.content,
|
|
209
|
+
...(input.secretEnvironment === undefined
|
|
210
|
+
? {}
|
|
211
|
+
: { secretEnvironment: input.secretEnvironment }),
|
|
212
|
+
...(input.attachmentIds === undefined ? {} : { attachmentIds: input.attachmentIds })
|
|
213
|
+
}));
|
|
214
|
+
const nativeSessionId = await identity;
|
|
215
|
+
const session = this.options.runtime.getAgentSession(nativeSessionId);
|
|
216
|
+
const run = this.options.runtime.getRun(message.run.id);
|
|
217
|
+
if (session === undefined || run === undefined)
|
|
218
|
+
throw new Error('SESSION_START_FAILED');
|
|
219
|
+
return {
|
|
220
|
+
session: this.options.present(session),
|
|
221
|
+
run,
|
|
222
|
+
delivery: message.delivery,
|
|
223
|
+
idempotent: message.idempotent
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
catch (error) {
|
|
227
|
+
this.options.identity.reject(bootstrapId, 'SESSION_START_FAILED');
|
|
228
|
+
const promotedSessionId = await identity.catch(() => undefined);
|
|
229
|
+
if (promotedSessionId !== undefined)
|
|
230
|
+
try {
|
|
231
|
+
this.options.runtime.removeAgentSession(promotedSessionId);
|
|
232
|
+
}
|
|
233
|
+
catch {
|
|
234
|
+
// A started Run owns the promoted Session and finishes normally.
|
|
235
|
+
}
|
|
236
|
+
throw error;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
function record(data) {
|
|
241
|
+
return data !== null && typeof data === 'object' ? data : {};
|
|
242
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { NodeOperationHandler } from '../connector/node-operation-router.js';
|
|
2
|
+
import type { NodeAgentSession } from '../database.js';
|
|
3
|
+
import type { NodeRuntimeState } from '../runtime-state.js';
|
|
4
|
+
import type { CommandStateStore } from '../runner-command-engine.js';
|
|
5
|
+
import type { RunnerRegistry } from '../runner/runner-registry.js';
|
|
6
|
+
import type { WorkspaceUploadService } from './workspace-upload-service.js';
|
|
7
|
+
import type { RunnerImageAttachment, RunAttachmentService } from './run-attachment-service.js';
|
|
8
|
+
import type { RunnerInteractionService } from './runner-interaction-service.js';
|
|
9
|
+
import type { WorkspaceQueueWorkbenchService } from './workspace-queue-workbench-service.js';
|
|
10
|
+
interface SessionMessageServiceOptions {
|
|
11
|
+
readonly runtime: NodeRuntimeState;
|
|
12
|
+
readonly uploads: WorkspaceUploadService;
|
|
13
|
+
readonly attachments: RunAttachmentService;
|
|
14
|
+
readonly commands: CommandStateStore;
|
|
15
|
+
readonly queue: WorkspaceQueueWorkbenchService<RunnerImageAttachment>;
|
|
16
|
+
readonly interaction: RunnerInteractionService;
|
|
17
|
+
readonly runners: RunnerRegistry;
|
|
18
|
+
readonly resolve: (sessionId: string) => Promise<NodeAgentSession>;
|
|
19
|
+
readonly present: (session: NodeAgentSession) => unknown;
|
|
20
|
+
readonly emitSession: (session: NodeAgentSession) => void;
|
|
21
|
+
readonly emitQueue: (workspaceId: string, sessionId: string) => void;
|
|
22
|
+
readonly channelToken: (sessionId: string) => string | undefined;
|
|
23
|
+
}
|
|
24
|
+
export declare class SessionMessageService {
|
|
25
|
+
private readonly options;
|
|
26
|
+
constructor(options: SessionMessageServiceOptions);
|
|
27
|
+
operations(): Readonly<Record<string, NodeOperationHandler>>;
|
|
28
|
+
private message;
|
|
29
|
+
private persistAttachments;
|
|
30
|
+
private channelMessage;
|
|
31
|
+
private channelToken;
|
|
32
|
+
}
|
|
33
|
+
export {};
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { isImageAttachment, isRunnerImageAttachment, parseComposerAttachmentIds, parseMessageAttachments, sessionTitleFromFirstMessage, withNonImageAttachmentPrompt } from '../util/node-operation-parsers.js';
|
|
2
|
+
import { parseSecretEnvironment } from '../util/secret-environment.js';
|
|
3
|
+
export class SessionMessageService {
|
|
4
|
+
options;
|
|
5
|
+
constructor(options) {
|
|
6
|
+
this.options = options;
|
|
7
|
+
}
|
|
8
|
+
operations() {
|
|
9
|
+
return {
|
|
10
|
+
'session.message': (data) => this.message(record(data)),
|
|
11
|
+
'session.channel.message': (data) => this.channelMessage(record(data)),
|
|
12
|
+
'session.channel.token': (data) => this.channelToken(record(data))
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
async message(input) {
|
|
16
|
+
if (typeof input.sessionId !== 'string' ||
|
|
17
|
+
typeof input.clientMessageId !== 'string' ||
|
|
18
|
+
input.clientMessageId.length === 0 ||
|
|
19
|
+
typeof input.content !== 'string' ||
|
|
20
|
+
input.content.length === 0)
|
|
21
|
+
throw new Error('MESSAGE_INVALID');
|
|
22
|
+
const inlineAttachments = parseMessageAttachments(input.attachments);
|
|
23
|
+
const secretEnvironment = parseSecretEnvironment(input.secretEnvironment);
|
|
24
|
+
const attachmentIds = parseComposerAttachmentIds(input.attachmentIds);
|
|
25
|
+
if (inlineAttachments.length > 0 && attachmentIds.length > 0)
|
|
26
|
+
throw new Error('MESSAGE_ATTACHMENTS_INVALID');
|
|
27
|
+
const session = this.options.runtime.setTemporaryTitleIfMissing((await this.options.resolve(input.sessionId)).id, sessionTitleFromFirstMessage(input.content));
|
|
28
|
+
this.options.emitSession(session);
|
|
29
|
+
const intent = input.deliveryIntent;
|
|
30
|
+
if (intent !== undefined &&
|
|
31
|
+
intent !== 'SEND' &&
|
|
32
|
+
intent !== 'QUEUE' &&
|
|
33
|
+
intent !== 'REPLACE_CURRENT')
|
|
34
|
+
throw new Error('MESSAGE_INVALID');
|
|
35
|
+
const existing = this.options.runtime.findMessageRun(session.id, input.clientMessageId);
|
|
36
|
+
if (existing !== undefined)
|
|
37
|
+
return {
|
|
38
|
+
session: this.options.present(session),
|
|
39
|
+
run: existing,
|
|
40
|
+
delivery: this.options.runtime.isQueuedRun(existing.id) ? 'QUEUED' : 'STARTED',
|
|
41
|
+
idempotent: true
|
|
42
|
+
};
|
|
43
|
+
const uploaded = await this.options.uploads.resolve(session.workspaceId, attachmentIds);
|
|
44
|
+
const attachments = attachmentIds.length === 0
|
|
45
|
+
? inlineAttachments
|
|
46
|
+
: uploaded.map((attachment) => attachment.attachment);
|
|
47
|
+
const imageAttachments = attachments.filter(isImageAttachment);
|
|
48
|
+
const runnerImageAttachments = attachments.filter(isRunnerImageAttachment);
|
|
49
|
+
const active = this.options.runtime
|
|
50
|
+
.listRunsForSession(session.id)
|
|
51
|
+
.find((run) => run.status === 'STARTING' || run.status === 'RUNNING');
|
|
52
|
+
const replaceCurrentRun = intent === 'REPLACE_CURRENT' ? active : undefined;
|
|
53
|
+
const queueWasPaused = this.options.runtime.sessionQueue(session.id).paused;
|
|
54
|
+
const queuedBeforeCreate = this.options.runtime.hasActiveSessionLease(session.id) || intent === 'QUEUE';
|
|
55
|
+
const created = this.options.runtime.createMessageRun({
|
|
56
|
+
sessionId: session.id,
|
|
57
|
+
clientMessageId: input.clientMessageId,
|
|
58
|
+
content: input.content,
|
|
59
|
+
...(attachments.length === 0 ? {} : { attachments })
|
|
60
|
+
});
|
|
61
|
+
if (!created.created)
|
|
62
|
+
return {
|
|
63
|
+
session: this.options.present(session),
|
|
64
|
+
run: created.run,
|
|
65
|
+
delivery: this.options.runtime.isQueuedRun(created.run.id) ? 'QUEUED' : 'STARTED',
|
|
66
|
+
idempotent: true
|
|
67
|
+
};
|
|
68
|
+
this.options.attachments.cache(created.run.id, imageAttachments);
|
|
69
|
+
let attachmentPaths;
|
|
70
|
+
try {
|
|
71
|
+
attachmentPaths = await this.persistAttachments(session, created.run.id, attachmentIds, attachments, uploaded);
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
this.options.runtime.deleteQueuedRun(created.run.id);
|
|
75
|
+
this.options.attachments.clear(created.run.id);
|
|
76
|
+
throw error;
|
|
77
|
+
}
|
|
78
|
+
const runnerInput = withNonImageAttachmentPrompt(input.content, attachmentPaths);
|
|
79
|
+
this.options.runtime.updateQueuedMessage(created.run.id, runnerInput);
|
|
80
|
+
const planActive = this.options.commands
|
|
81
|
+
.list(session.id)
|
|
82
|
+
.some((state) => state.commandId === 'plan');
|
|
83
|
+
this.options.queue.remember({
|
|
84
|
+
runId: created.run.id,
|
|
85
|
+
sessionId: created.run.sessionId,
|
|
86
|
+
workspaceId: created.run.workspaceId,
|
|
87
|
+
runner: created.run.runner,
|
|
88
|
+
input: this.options.runners
|
|
89
|
+
.require(created.run.runner)
|
|
90
|
+
.prepareMessageInput(runnerInput, planActive ? 'plan' : 'default'),
|
|
91
|
+
attachments: runnerImageAttachments,
|
|
92
|
+
attachmentPaths,
|
|
93
|
+
cwd: session.cwd,
|
|
94
|
+
externalSessionId: session.externalSessionId,
|
|
95
|
+
model: session.model,
|
|
96
|
+
effort: session.effort,
|
|
97
|
+
access: session.access,
|
|
98
|
+
collaborationMode: planActive ? 'plan' : 'default',
|
|
99
|
+
secretEnvironment,
|
|
100
|
+
...(this.options.runners.require(created.run.runner).serviceTier() === 'fast'
|
|
101
|
+
? { serviceTier: 'fast' }
|
|
102
|
+
: {})
|
|
103
|
+
});
|
|
104
|
+
if (queueWasPaused && active === undefined && intent !== 'QUEUE')
|
|
105
|
+
this.options.runtime.prioritizeQueuedRun(created.run.id);
|
|
106
|
+
if (!queueWasPaused || intent !== 'QUEUE')
|
|
107
|
+
this.options.runtime.resumeSessionQueue(session.id);
|
|
108
|
+
this.options.emitQueue(session.workspaceId, session.id);
|
|
109
|
+
if (replaceCurrentRun !== undefined)
|
|
110
|
+
this.options.queue.replace(created.run.id, replaceCurrentRun.id);
|
|
111
|
+
else if (intent !== 'QUEUE' || !queuedBeforeCreate)
|
|
112
|
+
this.options.queue.schedule(session.id);
|
|
113
|
+
return {
|
|
114
|
+
session: this.options.present(session),
|
|
115
|
+
run: created.run,
|
|
116
|
+
delivery: replaceCurrentRun !== undefined ? 'RESTARTING' : queuedBeforeCreate ? 'QUEUED' : 'STARTED',
|
|
117
|
+
idempotent: false
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
async persistAttachments(session, runId, attachmentIds, attachments, uploaded) {
|
|
121
|
+
return [
|
|
122
|
+
...uploaded
|
|
123
|
+
.filter(({ attachment }) => !isRunnerImageAttachment(attachment))
|
|
124
|
+
.map(({ path }) => path),
|
|
125
|
+
...(await this.options.attachments.persistFiles(session.cwd, runId, attachmentIds.length === 0
|
|
126
|
+
? attachments.filter((attachment) => !isRunnerImageAttachment(attachment))
|
|
127
|
+
: []))
|
|
128
|
+
];
|
|
129
|
+
}
|
|
130
|
+
channelMessage(input) {
|
|
131
|
+
if (typeof input.sessionId !== 'string' ||
|
|
132
|
+
typeof input.token !== 'string' ||
|
|
133
|
+
typeof input.clientMessageId !== 'string' ||
|
|
134
|
+
typeof input.content !== 'string' ||
|
|
135
|
+
input.content.length === 0)
|
|
136
|
+
throw new Error('MESSAGE_INVALID');
|
|
137
|
+
const session = this.options.runtime.getAgentSession(input.sessionId);
|
|
138
|
+
if (session === undefined || session.channelToken !== input.token)
|
|
139
|
+
throw new Error('SESSION_CHANNEL_UNAVAILABLE');
|
|
140
|
+
return {
|
|
141
|
+
delivery: this.options.interaction.deliverChannel(session.runner, input.sessionId, input.clientMessageId, 'admin', input.token, input.content)
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
channelToken(input) {
|
|
145
|
+
if (typeof input.sessionId !== 'string')
|
|
146
|
+
throw new Error('SESSION_INVALID');
|
|
147
|
+
const token = this.options.channelToken(input.sessionId);
|
|
148
|
+
if (token === undefined)
|
|
149
|
+
throw new Error('SESSION_CHANNEL_UNAVAILABLE');
|
|
150
|
+
return { token };
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
function record(value) {
|
|
154
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value))
|
|
155
|
+
return {};
|
|
156
|
+
return value;
|
|
157
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { NodeCapabilities, SessionActivityState, RunnerCommandState } from '@myagentroam/protocol';
|
|
2
|
+
import type { CodexSessionControl } from '../codex-app-server.js';
|
|
3
|
+
import type { NodeAgentSession, NodeDatabase } from '../database.js';
|
|
4
|
+
import type { NodeRuntimeState } from '../runtime-state.js';
|
|
5
|
+
import type { CommandStateStore } from '../runner-command-engine.js';
|
|
6
|
+
import type { RunnerRegistry } from '../runner/runner-registry.js';
|
|
7
|
+
export type PresentedSession = NodeAgentSession & {
|
|
8
|
+
readonly control: CodexSessionControl;
|
|
9
|
+
readonly activity: SessionActivityState;
|
|
10
|
+
readonly runtime: {
|
|
11
|
+
readonly level: CodexSessionControl['level'];
|
|
12
|
+
readonly capabilities: readonly string[];
|
|
13
|
+
readonly reasonCode: string | null;
|
|
14
|
+
};
|
|
15
|
+
readonly commandStates: readonly RunnerCommandState[];
|
|
16
|
+
};
|
|
17
|
+
interface SessionPresentationServiceOptions {
|
|
18
|
+
readonly database: () => NodeDatabase | undefined;
|
|
19
|
+
readonly runtime: NodeRuntimeState;
|
|
20
|
+
readonly commands: CommandStateStore;
|
|
21
|
+
readonly runners: RunnerRegistry;
|
|
22
|
+
readonly capabilities: () => NodeCapabilities;
|
|
23
|
+
readonly hasManagedActiveRun: (session: NodeAgentSession) => boolean;
|
|
24
|
+
readonly externalActivity: (sessionId: string) => SessionActivityState | undefined;
|
|
25
|
+
readonly projectionForNative: (session: NodeAgentSession) => NodeAgentSession | undefined;
|
|
26
|
+
}
|
|
27
|
+
export declare class SessionPresentationService {
|
|
28
|
+
private readonly options;
|
|
29
|
+
constructor(options: SessionPresentationServiceOptions);
|
|
30
|
+
present(session: NodeAgentSession): PresentedSession;
|
|
31
|
+
presentDiscovered(sessions: readonly NodeAgentSession[]): readonly PresentedSession[];
|
|
32
|
+
}
|
|
33
|
+
export {};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export class SessionPresentationService {
|
|
2
|
+
options;
|
|
3
|
+
constructor(options) {
|
|
4
|
+
this.options = options;
|
|
5
|
+
}
|
|
6
|
+
present(session) {
|
|
7
|
+
const database = this.options.database();
|
|
8
|
+
if (session.externalSessionId !== null && database !== undefined) {
|
|
9
|
+
const metadata = database.getNativeSessionMetadata(session.runner, session.externalSessionId, session.workspaceId);
|
|
10
|
+
if (metadata !== undefined)
|
|
11
|
+
session = { ...session, pinnedAt: metadata.pinnedAt, pinOrder: metadata.pinOrder };
|
|
12
|
+
}
|
|
13
|
+
const presentation = this.options.runners
|
|
14
|
+
.require(session.runner)
|
|
15
|
+
.presentSession(session, this.options.capabilities(), {
|
|
16
|
+
managedActive: this.options.hasManagedActiveRun(session),
|
|
17
|
+
externalActivity: this.options.externalActivity(session.id),
|
|
18
|
+
commandStates: this.options.commands.list(session.id)
|
|
19
|
+
});
|
|
20
|
+
return {
|
|
21
|
+
...session,
|
|
22
|
+
...presentation
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
presentDiscovered(sessions) {
|
|
26
|
+
return sessions.map((session) => {
|
|
27
|
+
const projected = this.options.projectionForNative(session);
|
|
28
|
+
if (projected === undefined)
|
|
29
|
+
return this.present(session);
|
|
30
|
+
const synchronized = session.runnerTitle === null
|
|
31
|
+
? projected
|
|
32
|
+
: this.options.runtime.setRunnerTitleFromNative(projected.id, session.runnerTitle);
|
|
33
|
+
return this.present({ ...synchronized, lastActivityAt: session.lastActivityAt });
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { NodeOperationHandler } from '../connector/node-operation-router.js';
|
|
2
|
+
import type { NodeAgentSession } from '../database.js';
|
|
3
|
+
import type { NodeRuntimeState } from '../runtime-state.js';
|
|
4
|
+
import type { RunnerRegistry } from '../runner/runner-registry.js';
|
|
5
|
+
import type { SessionContextService } from './session-context-service.js';
|
|
6
|
+
import type { RunnerName } from '@myagentroam/protocol';
|
|
7
|
+
export interface SessionQueryServiceOptions {
|
|
8
|
+
readonly runtime: NodeRuntimeState;
|
|
9
|
+
readonly runners: RunnerRegistry;
|
|
10
|
+
readonly resolve: (sessionId: string) => Promise<NodeAgentSession | undefined>;
|
|
11
|
+
readonly present: (session: NodeAgentSession) => unknown;
|
|
12
|
+
readonly history: (session: NodeAgentSession, input: {
|
|
13
|
+
readonly cursor?: string;
|
|
14
|
+
readonly limit?: number;
|
|
15
|
+
}) => Promise<unknown>;
|
|
16
|
+
readonly context: SessionContextService;
|
|
17
|
+
readonly discover: (runner: RunnerName, workspaceId?: string) => Promise<readonly NodeAgentSession[]>;
|
|
18
|
+
readonly workspaceIdForCwd: (cwd: string) => string | undefined;
|
|
19
|
+
}
|
|
20
|
+
export declare class SessionQueryService {
|
|
21
|
+
private readonly options;
|
|
22
|
+
constructor(options: SessionQueryServiceOptions);
|
|
23
|
+
operations(): Readonly<Record<string, NodeOperationHandler>>;
|
|
24
|
+
private get;
|
|
25
|
+
private runs;
|
|
26
|
+
private turns;
|
|
27
|
+
private events;
|
|
28
|
+
private readContext;
|
|
29
|
+
private discover;
|
|
30
|
+
private requireSession;
|
|
31
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { isPlainRecord } from '../runner/codex/conversation-parser.js';
|
|
2
|
+
export class SessionQueryService {
|
|
3
|
+
options;
|
|
4
|
+
constructor(options) {
|
|
5
|
+
this.options = options;
|
|
6
|
+
}
|
|
7
|
+
operations() {
|
|
8
|
+
return {
|
|
9
|
+
'session.get': (data) => this.get(record(data)),
|
|
10
|
+
'session.runs': (data) => this.runs(record(data)),
|
|
11
|
+
'session.turns.list': (data) => this.turns(record(data)),
|
|
12
|
+
'session.events.read': (data) => this.events(record(data)),
|
|
13
|
+
'session.context.read': (data) => this.readContext(record(data)),
|
|
14
|
+
'session.discover': (data) => this.discover(record(data))
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
async get(input) {
|
|
18
|
+
return { session: this.options.present(await this.requireSession(input.sessionId)) };
|
|
19
|
+
}
|
|
20
|
+
async runs(input) {
|
|
21
|
+
const session = await this.requireSession(input.sessionId);
|
|
22
|
+
return { runs: this.options.runtime.listRunsForSession(session.id) };
|
|
23
|
+
}
|
|
24
|
+
async turns(input) {
|
|
25
|
+
const page = pageInput(input);
|
|
26
|
+
return this.options.history(await this.requireSession(input.sessionId), page);
|
|
27
|
+
}
|
|
28
|
+
events(input) {
|
|
29
|
+
const page = pageInput(input);
|
|
30
|
+
if (typeof input.sessionId !== 'string')
|
|
31
|
+
throw new Error('SESSION_NOT_FOUND');
|
|
32
|
+
const session = this.options.runtime.getAgentSession(input.sessionId);
|
|
33
|
+
if (session === undefined)
|
|
34
|
+
throw new Error('SESSION_NOT_FOUND');
|
|
35
|
+
return this.options.runtime.listConversationItems({ sessionId: session.id, ...page });
|
|
36
|
+
}
|
|
37
|
+
async readContext(input) {
|
|
38
|
+
return this.options.context.read(await this.requireSession(input.sessionId));
|
|
39
|
+
}
|
|
40
|
+
async discover(input) {
|
|
41
|
+
const runner = this.options.runners.product(input.runner);
|
|
42
|
+
if (runner === undefined)
|
|
43
|
+
throw new Error('SESSION_INVALID');
|
|
44
|
+
const workspaceId = typeof input.workspaceId === 'string'
|
|
45
|
+
? input.workspaceId
|
|
46
|
+
: typeof input.cwd === 'string'
|
|
47
|
+
? this.options.workspaceIdForCwd(input.cwd)
|
|
48
|
+
: undefined;
|
|
49
|
+
if (runner.discoveryScope === 'WORKSPACE_REQUIRED' && workspaceId === undefined)
|
|
50
|
+
throw new Error('SESSION_INVALID');
|
|
51
|
+
const sessions = await this.options.discover(runner.name, workspaceId);
|
|
52
|
+
return { sessions: sessions.map((session) => this.options.present(session)) };
|
|
53
|
+
}
|
|
54
|
+
async requireSession(sessionId) {
|
|
55
|
+
if (typeof sessionId !== 'string')
|
|
56
|
+
throw new Error('SESSION_INVALID');
|
|
57
|
+
const session = this.options.runtime.getAgentSession(sessionId) ?? (await this.options.resolve(sessionId));
|
|
58
|
+
if (session === undefined)
|
|
59
|
+
throw new Error('SESSION_NOT_FOUND');
|
|
60
|
+
return session;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function pageInput(input) {
|
|
64
|
+
if ((input.cursor !== undefined && typeof input.cursor !== 'string') ||
|
|
65
|
+
(input.limit !== undefined &&
|
|
66
|
+
(!Number.isInteger(input.limit) ||
|
|
67
|
+
input.limit < 1 ||
|
|
68
|
+
input.limit > 500)))
|
|
69
|
+
throw new Error('EVENT_CURSOR_INVALID');
|
|
70
|
+
return {
|
|
71
|
+
...(typeof input.cursor === 'string' ? { cursor: input.cursor } : {}),
|
|
72
|
+
...(typeof input.limit === 'number' ? { limit: input.limit } : {})
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
function record(value) {
|
|
76
|
+
return isPlainRecord(value) ? value : {};
|
|
77
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { NodeDatabase } from '../database.js';
|
|
2
|
+
import type { NodeOperationHandler } from '../connector/node-operation-router.js';
|
|
3
|
+
import type { TerminalManager } from '../terminal.js';
|
|
4
|
+
export declare class TerminalService {
|
|
5
|
+
private readonly database;
|
|
6
|
+
private readonly terminalManager;
|
|
7
|
+
constructor(database: () => NodeDatabase, terminalManager: TerminalManager);
|
|
8
|
+
operations(): Readonly<Record<string, NodeOperationHandler>>;
|
|
9
|
+
private open;
|
|
10
|
+
private close;
|
|
11
|
+
private authorizeAttach;
|
|
12
|
+
}
|