@promptbook/cli 0.112.0-97 → 0.112.0-98
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/apps/agents-server/README.md +3 -3
- package/apps/agents-server/src/app/admin/cli-access/CliAccessClient.tsx +99 -0
- package/apps/agents-server/src/app/admin/cli-access/page.tsx +14 -0
- package/apps/agents-server/src/app/admin/code-runners/CodeRunnersClient.tsx +76 -325
- package/apps/agents-server/src/app/admin/database/page.tsx +1 -2
- package/apps/agents-server/src/app/agents/[agentName]/chat/CanonicalAgentChatSurface.tsx +24 -0
- package/apps/agents-server/src/app/api/admin/cli-access/route.ts +137 -0
- package/apps/agents-server/src/app/api/admin/code-runners/authentication/route.ts +7 -64
- package/apps/agents-server/src/app/api/admin/servers/[serverId]/route.ts +3 -3
- package/apps/agents-server/src/app/api/admin/servers/route.ts +4 -4
- package/apps/agents-server/src/app/api/chat/export/pdf/route.ts +63 -0
- package/apps/agents-server/src/components/AdminTerminal/AdminTerminalCard.tsx +279 -0
- package/apps/agents-server/src/components/AdminTerminal/useAdminTerminalSession.ts +336 -0
- package/apps/agents-server/src/components/Header/buildHeaderSystemMenuItems.ts +4 -0
- package/apps/agents-server/src/database/$provideClientSql.ts +17 -4
- package/apps/agents-server/src/database/$provideDatabaseAdminExecutor.ts +24 -3
- package/apps/agents-server/src/database/$provideSupabaseForServer.ts +1 -11
- package/apps/agents-server/src/database/agentsServerDatabaseMode.ts +1 -20
- package/apps/agents-server/src/languages/ServerTranslationKeys.ts +1 -0
- package/apps/agents-server/src/languages/translations/czech.yaml +1 -0
- package/apps/agents-server/src/languages/translations/english.yaml +1 -0
- package/apps/agents-server/src/tools/$provideServer.ts +2 -2
- package/apps/agents-server/src/tools/BrowserConnectionProvider.ts +1 -1
- package/apps/agents-server/src/utils/chatExport/downloadChatPdfFromServer.ts +59 -0
- package/apps/agents-server/src/utils/chatExport/renderHtmlToPdfOnServer.ts +37 -0
- package/apps/agents-server/src/utils/codeRunnerAuthentication.ts +77 -237
- package/apps/agents-server/src/utils/createInteractiveTerminalEventStream.ts +84 -0
- package/apps/agents-server/src/utils/interactiveTerminalSession.ts +442 -0
- package/apps/agents-server/src/utils/serverCliAccess.ts +221 -0
- package/apps/agents-server/src/utils/serverRegistry.ts +4 -4
- package/apps/agents-server/src/utils/vpsConfiguration.ts +2 -0
- package/esm/apps/agents-server/src/database/agentsServerDatabaseMode.d.ts +1 -9
- package/esm/index.es.js +2 -2
- package/esm/src/book-components/Chat/Chat/ChatActionsBar.d.ts +2 -0
- package/esm/src/book-components/Chat/Chat/ChatProps.d.ts +6 -0
- package/esm/src/book-components/Chat/save/_common/ChatSaveFormatHandler.d.ts +35 -0
- package/esm/src/book-components/Chat/save/_common/createChatExportFilename.d.ts +11 -0
- package/esm/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/src/book-components/Chat/Chat/Chat.tsx +2 -0
- package/src/book-components/Chat/Chat/ChatActionsBar.tsx +17 -9
- package/src/book-components/Chat/Chat/ChatProps.tsx +7 -0
- package/src/book-components/Chat/save/_common/ChatSaveFormatHandler.ts +40 -0
- package/src/book-components/Chat/save/_common/createChatExportFilename.ts +20 -0
- package/src/cli/cli-commands/agents-server/ensureAgentsServerEnvFile.ts +1 -1
- package/src/other/templates/getTemplatesPipelineCollection.ts +721 -736
- package/src/version.ts +2 -2
- package/src/versions.txt +1 -0
- package/umd/apps/agents-server/src/database/agentsServerDatabaseMode.d.ts +1 -9
- package/umd/index.umd.js +2 -2
- package/umd/src/book-components/Chat/Chat/ChatActionsBar.d.ts +2 -0
- package/umd/src/book-components/Chat/Chat/ChatProps.d.ts +6 -0
- package/umd/src/book-components/Chat/save/_common/ChatSaveFormatHandler.d.ts +35 -0
- package/umd/src/book-components/Chat/save/_common/createChatExportFilename.d.ts +11 -0
- package/umd/src/version.d.ts +1 -1
- package/apps/agents-server/src/database/$providePostgresPool.ts +0 -27
- package/apps/agents-server/src/database/postgres/$provideLocalPostgresSupabase.ts +0 -1261
- package/src/conversion/validation/_importPipeline.ts +0 -88
- /package/esm/src/conversion/validation/{_importPipeline.d.ts → _importPipeline.test.d.ts} +0 -0
- /package/umd/src/conversion/validation/{_importPipeline.d.ts → _importPipeline.test.d.ts} +0 -0
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
import { spawn, type ChildProcessWithoutNullStreams } from 'child_process';
|
|
2
|
-
import { randomUUID } from 'crypto';
|
|
3
|
-
import { EventEmitter } from 'events';
|
|
4
|
-
import { spaceTrim } from 'spacetrim';
|
|
5
1
|
import { createVpsInstallerCommandEnvironment, resolveVpsInstallerScriptPath } from './vpsConfiguration';
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
2
|
+
import {
|
|
3
|
+
getInteractiveTerminalSession,
|
|
4
|
+
getLatestInteractiveTerminalSession,
|
|
5
|
+
startInteractiveTerminalSession,
|
|
6
|
+
stopInteractiveTerminalSession,
|
|
7
|
+
subscribeToInteractiveTerminalSession,
|
|
8
|
+
type InteractiveTerminalSessionSnapshot,
|
|
9
|
+
type InteractiveTerminalSessionSubscriber,
|
|
10
|
+
writeInteractiveTerminalSessionInput,
|
|
11
|
+
} from './interactiveTerminalSession';
|
|
9
12
|
|
|
10
13
|
/**
|
|
11
14
|
* Serializable snapshot of one interactive code-runner authentication session.
|
|
@@ -52,50 +55,6 @@ export type CodeRunnerAuthenticationSessionSnapshot = {
|
|
|
52
55
|
readonly signal: NodeJS.Signals | null;
|
|
53
56
|
};
|
|
54
57
|
|
|
55
|
-
/**
|
|
56
|
-
* Output event emitted while the authentication terminal is running.
|
|
57
|
-
*/
|
|
58
|
-
type CodeRunnerAuthenticationOutputEvent = {
|
|
59
|
-
readonly type: 'output';
|
|
60
|
-
readonly chunk: string;
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Exit event emitted when the authentication terminal finishes.
|
|
65
|
-
*/
|
|
66
|
-
type CodeRunnerAuthenticationExitEvent = {
|
|
67
|
-
readonly type: 'exit';
|
|
68
|
-
readonly snapshot: CodeRunnerAuthenticationSessionSnapshot;
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Internal mutable session state stored in-process.
|
|
73
|
-
*/
|
|
74
|
-
type CodeRunnerAuthenticationSession = {
|
|
75
|
-
readonly id: string;
|
|
76
|
-
readonly agent: string;
|
|
77
|
-
readonly process: ChildProcessWithoutNullStreams;
|
|
78
|
-
readonly events: EventEmitter<{
|
|
79
|
-
output: [CodeRunnerAuthenticationOutputEvent];
|
|
80
|
-
exit: [CodeRunnerAuthenticationExitEvent];
|
|
81
|
-
}>;
|
|
82
|
-
readonly startedAt: Date;
|
|
83
|
-
cleanupTimeout: NodeJS.Timeout | null;
|
|
84
|
-
output: string;
|
|
85
|
-
isRunning: boolean;
|
|
86
|
-
finishedAt: Date | null;
|
|
87
|
-
exitCode: number | null;
|
|
88
|
-
signal: NodeJS.Signals | null;
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Shared in-memory state reused across requests in the standalone server process.
|
|
93
|
-
*/
|
|
94
|
-
type CodeRunnerAuthenticationState = {
|
|
95
|
-
readonly sessionsById: Map<string, CodeRunnerAuthenticationSession>;
|
|
96
|
-
readonly latestSessionIdByAgent: Map<string, string>;
|
|
97
|
-
};
|
|
98
|
-
|
|
99
58
|
/**
|
|
100
59
|
* Browser stream callbacks used by one subscribed UI client.
|
|
101
60
|
*/
|
|
@@ -103,12 +62,12 @@ export type CodeRunnerAuthenticationSessionSubscriber = {
|
|
|
103
62
|
/**
|
|
104
63
|
* Called whenever new terminal output arrives.
|
|
105
64
|
*/
|
|
106
|
-
readonly onOutput: (event:
|
|
65
|
+
readonly onOutput: (event: Parameters<InteractiveTerminalSessionSubscriber['onOutput']>[0]) => void;
|
|
107
66
|
|
|
108
67
|
/**
|
|
109
68
|
* Called once the session exits.
|
|
110
69
|
*/
|
|
111
|
-
readonly onExit: (event:
|
|
70
|
+
readonly onExit: (event: { readonly type: 'exit'; readonly snapshot: CodeRunnerAuthenticationSessionSnapshot }) => void;
|
|
112
71
|
};
|
|
113
72
|
|
|
114
73
|
/**
|
|
@@ -120,64 +79,28 @@ export type CodeRunnerAuthenticationSessionSubscriber = {
|
|
|
120
79
|
export async function startCodeRunnerAuthenticationSession(
|
|
121
80
|
agent: string,
|
|
122
81
|
): Promise<CodeRunnerAuthenticationSessionSnapshot> {
|
|
123
|
-
const existingSession = getLatestCodeRunnerAuthenticationSession(agent);
|
|
124
|
-
if (existingSession?.isRunning) {
|
|
125
|
-
return existingSession;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
if (process.platform !== 'linux') {
|
|
129
|
-
throw new Error('Interactive code-runner authentication is available only on the Linux VPS runtime.');
|
|
130
|
-
}
|
|
131
|
-
|
|
132
82
|
const scriptPath = await resolveVpsInstallerScriptPath();
|
|
133
83
|
if (!scriptPath) {
|
|
134
84
|
throw new Error('The VPS installer script could not be found on this server.');
|
|
135
85
|
}
|
|
136
86
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
87
|
+
return toRequiredCodeRunnerAuthenticationSessionSnapshot(
|
|
88
|
+
startInteractiveTerminalSession({
|
|
89
|
+
sessionKey: buildCodeRunnerAuthenticationSessionKey(agent),
|
|
90
|
+
title: `${agent} authentication`,
|
|
91
|
+
command: 'bash',
|
|
92
|
+
arguments: [scriptPath, 'authenticate-runner'],
|
|
93
|
+
env: createVpsInstallerCommandEnvironment({
|
|
94
|
+
isNonInteractiveModeEnabled: false,
|
|
95
|
+
isProcessRestartEnabled: false,
|
|
96
|
+
}),
|
|
97
|
+
metadata: {
|
|
98
|
+
agent,
|
|
99
|
+
},
|
|
100
|
+
unavailableErrorMessage: 'Interactive code-runner authentication is available only on the Linux VPS runtime.',
|
|
142
101
|
}),
|
|
143
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
const session: CodeRunnerAuthenticationSession = {
|
|
147
|
-
id: sessionId,
|
|
148
102
|
agent,
|
|
149
|
-
|
|
150
|
-
events: new EventEmitter(),
|
|
151
|
-
startedAt: new Date(),
|
|
152
|
-
cleanupTimeout: null,
|
|
153
|
-
output: '',
|
|
154
|
-
isRunning: true,
|
|
155
|
-
finishedAt: null,
|
|
156
|
-
exitCode: null,
|
|
157
|
-
signal: null,
|
|
158
|
-
};
|
|
159
|
-
|
|
160
|
-
const state = getCodeRunnerAuthenticationState();
|
|
161
|
-
state.sessionsById.set(sessionId, session);
|
|
162
|
-
state.latestSessionIdByAgent.set(agent, sessionId);
|
|
163
|
-
|
|
164
|
-
childProcess.stdout.setEncoding('utf-8');
|
|
165
|
-
childProcess.stderr.setEncoding('utf-8');
|
|
166
|
-
childProcess.stdout.on('data', (chunk: string) => appendCodeRunnerAuthenticationOutput(session, chunk));
|
|
167
|
-
childProcess.stderr.on('data', (chunk: string) => appendCodeRunnerAuthenticationOutput(session, chunk));
|
|
168
|
-
childProcess.on('close', (exitCode, signal) => finalizeCodeRunnerAuthenticationSession(session, exitCode, signal));
|
|
169
|
-
childProcess.on('error', (error) => {
|
|
170
|
-
appendCodeRunnerAuthenticationOutput(
|
|
171
|
-
session,
|
|
172
|
-
spaceTrim(`
|
|
173
|
-
Failed to start the code-runner authentication process.
|
|
174
|
-
|
|
175
|
-
${error.message}
|
|
176
|
-
`) + '\n',
|
|
177
|
-
);
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
return createCodeRunnerAuthenticationSessionSnapshot(session);
|
|
103
|
+
);
|
|
181
104
|
}
|
|
182
105
|
|
|
183
106
|
/**
|
|
@@ -189,12 +112,10 @@ export async function startCodeRunnerAuthenticationSession(
|
|
|
189
112
|
export function getLatestCodeRunnerAuthenticationSession(
|
|
190
113
|
agent: string,
|
|
191
114
|
): CodeRunnerAuthenticationSessionSnapshot | null {
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
return getCodeRunnerAuthenticationSession(sessionId);
|
|
115
|
+
return toCodeRunnerAuthenticationSessionSnapshot(
|
|
116
|
+
getLatestInteractiveTerminalSession(buildCodeRunnerAuthenticationSessionKey(agent)),
|
|
117
|
+
agent,
|
|
118
|
+
);
|
|
198
119
|
}
|
|
199
120
|
|
|
200
121
|
/**
|
|
@@ -206,8 +127,7 @@ export function getLatestCodeRunnerAuthenticationSession(
|
|
|
206
127
|
export function getCodeRunnerAuthenticationSession(
|
|
207
128
|
sessionId: string,
|
|
208
129
|
): CodeRunnerAuthenticationSessionSnapshot | null {
|
|
209
|
-
|
|
210
|
-
return session ? createCodeRunnerAuthenticationSessionSnapshot(session) : null;
|
|
130
|
+
return toCodeRunnerAuthenticationSessionSnapshot(getInteractiveTerminalSession(sessionId));
|
|
211
131
|
}
|
|
212
132
|
|
|
213
133
|
/**
|
|
@@ -221,18 +141,14 @@ export function subscribeToCodeRunnerAuthenticationSession(
|
|
|
221
141
|
sessionId: string,
|
|
222
142
|
subscriber: CodeRunnerAuthenticationSessionSubscriber,
|
|
223
143
|
): (() => void) | null {
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
return () => {
|
|
233
|
-
session.events.off('output', subscriber.onOutput);
|
|
234
|
-
session.events.off('exit', subscriber.onExit);
|
|
235
|
-
};
|
|
144
|
+
return subscribeToInteractiveTerminalSession(sessionId, {
|
|
145
|
+
onOutput: subscriber.onOutput,
|
|
146
|
+
onExit: ({ snapshot }) =>
|
|
147
|
+
subscriber.onExit({
|
|
148
|
+
type: 'exit',
|
|
149
|
+
snapshot: toRequiredCodeRunnerAuthenticationSessionSnapshot(snapshot),
|
|
150
|
+
}),
|
|
151
|
+
});
|
|
236
152
|
}
|
|
237
153
|
|
|
238
154
|
/**
|
|
@@ -246,14 +162,7 @@ export function writeCodeRunnerAuthenticationSessionInput(
|
|
|
246
162
|
sessionId: string,
|
|
247
163
|
input: string,
|
|
248
164
|
): CodeRunnerAuthenticationSessionSnapshot {
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
if (!session.isRunning) {
|
|
252
|
-
throw new Error('The authentication session has already finished.');
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
session.process.stdin.write(input);
|
|
256
|
-
return createCodeRunnerAuthenticationSessionSnapshot(session);
|
|
165
|
+
return toRequiredCodeRunnerAuthenticationSessionSnapshot(writeInteractiveTerminalSessionInput(sessionId, input));
|
|
257
166
|
}
|
|
258
167
|
|
|
259
168
|
/**
|
|
@@ -265,130 +174,61 @@ export function writeCodeRunnerAuthenticationSessionInput(
|
|
|
265
174
|
export function stopCodeRunnerAuthenticationSession(
|
|
266
175
|
sessionId: string,
|
|
267
176
|
): CodeRunnerAuthenticationSessionSnapshot {
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
if (session.isRunning) {
|
|
271
|
-
session.process.kill('SIGTERM');
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
return createCodeRunnerAuthenticationSessionSnapshot(session);
|
|
177
|
+
return toRequiredCodeRunnerAuthenticationSessionSnapshot(stopInteractiveTerminalSession(sessionId));
|
|
275
178
|
}
|
|
276
179
|
|
|
277
180
|
/**
|
|
278
|
-
*
|
|
181
|
+
* Builds the stable logical session key for one runner authentication terminal.
|
|
279
182
|
*
|
|
280
|
-
* @
|
|
183
|
+
* @param agent - Runner identifier.
|
|
184
|
+
* @returns Stable session key.
|
|
281
185
|
*/
|
|
282
|
-
function
|
|
283
|
-
|
|
284
|
-
__promptbookCodeRunnerAuthenticationState?: CodeRunnerAuthenticationState;
|
|
285
|
-
};
|
|
286
|
-
|
|
287
|
-
if (!globalState.__promptbookCodeRunnerAuthenticationState) {
|
|
288
|
-
globalState.__promptbookCodeRunnerAuthenticationState = {
|
|
289
|
-
sessionsById: new Map(),
|
|
290
|
-
latestSessionIdByAgent: new Map(),
|
|
291
|
-
};
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
return globalState.__promptbookCodeRunnerAuthenticationState;
|
|
186
|
+
function buildCodeRunnerAuthenticationSessionKey(agent: string): string {
|
|
187
|
+
return `code-runner-authentication:${agent}`;
|
|
295
188
|
}
|
|
296
189
|
|
|
297
190
|
/**
|
|
298
|
-
*
|
|
191
|
+
* Converts one generic terminal snapshot into the runner-specific browser shape.
|
|
299
192
|
*
|
|
300
|
-
* @param session -
|
|
301
|
-
* @param
|
|
193
|
+
* @param session - Generic terminal snapshot.
|
|
194
|
+
* @param fallbackAgent - Agent name used when older sessions miss metadata.
|
|
195
|
+
* @returns Runner-specific snapshot or `null`.
|
|
302
196
|
*/
|
|
303
|
-
function
|
|
304
|
-
session:
|
|
305
|
-
|
|
306
|
-
):
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
return;
|
|
197
|
+
function toCodeRunnerAuthenticationSessionSnapshot(
|
|
198
|
+
session: InteractiveTerminalSessionSnapshot | null,
|
|
199
|
+
fallbackAgent = '',
|
|
200
|
+
): CodeRunnerAuthenticationSessionSnapshot | null {
|
|
201
|
+
if (!session) {
|
|
202
|
+
return null;
|
|
310
203
|
}
|
|
311
204
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
* @param output - Raw process output chunk.
|
|
323
|
-
* @returns UI-friendly terminal text.
|
|
324
|
-
*/
|
|
325
|
-
function normalizeCodeRunnerAuthenticationOutput(output: string): string {
|
|
326
|
-
return output.replace(/\r\n/gu, '\n').replace(/\r/gu, '\n');
|
|
205
|
+
return {
|
|
206
|
+
id: session.id,
|
|
207
|
+
agent: session.metadata.agent || fallbackAgent,
|
|
208
|
+
isRunning: session.isRunning,
|
|
209
|
+
output: session.output,
|
|
210
|
+
startedAt: session.startedAt,
|
|
211
|
+
finishedAt: session.finishedAt,
|
|
212
|
+
exitCode: session.exitCode,
|
|
213
|
+
signal: session.signal,
|
|
214
|
+
};
|
|
327
215
|
}
|
|
328
216
|
|
|
329
217
|
/**
|
|
330
|
-
*
|
|
218
|
+
* Converts one generic terminal snapshot into a required runner-specific snapshot.
|
|
331
219
|
*
|
|
332
|
-
* @param session -
|
|
333
|
-
* @
|
|
334
|
-
* @param signal - Process signal.
|
|
220
|
+
* @param session - Generic terminal snapshot.
|
|
221
|
+
* @returns Runner-specific snapshot.
|
|
335
222
|
*/
|
|
336
|
-
function
|
|
337
|
-
session:
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
session.isRunning = false;
|
|
342
|
-
session.finishedAt = new Date();
|
|
343
|
-
session.exitCode = exitCode;
|
|
344
|
-
session.signal = signal;
|
|
345
|
-
|
|
346
|
-
session.events.emit('exit', {
|
|
347
|
-
type: 'exit',
|
|
348
|
-
snapshot: createCodeRunnerAuthenticationSessionSnapshot(session),
|
|
349
|
-
});
|
|
350
|
-
|
|
351
|
-
if (session.cleanupTimeout) {
|
|
352
|
-
clearTimeout(session.cleanupTimeout);
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
session.cleanupTimeout = setTimeout(() => {
|
|
356
|
-
getCodeRunnerAuthenticationState().sessionsById.delete(session.id);
|
|
357
|
-
}, SESSION_RETENTION_MILLISECONDS);
|
|
358
|
-
}
|
|
223
|
+
function toRequiredCodeRunnerAuthenticationSessionSnapshot(
|
|
224
|
+
session: InteractiveTerminalSessionSnapshot | null,
|
|
225
|
+
fallbackAgent = '',
|
|
226
|
+
): CodeRunnerAuthenticationSessionSnapshot {
|
|
227
|
+
const mappedSession = toCodeRunnerAuthenticationSessionSnapshot(session, fallbackAgent);
|
|
359
228
|
|
|
360
|
-
|
|
361
|
-
* Reads one required mutable session and throws when missing.
|
|
362
|
-
*
|
|
363
|
-
* @param sessionId - Session identifier.
|
|
364
|
-
* @returns Mutable session state.
|
|
365
|
-
*/
|
|
366
|
-
function getRequiredCodeRunnerAuthenticationSession(sessionId: string): CodeRunnerAuthenticationSession {
|
|
367
|
-
const session = getCodeRunnerAuthenticationState().sessionsById.get(sessionId);
|
|
368
|
-
if (!session) {
|
|
229
|
+
if (!mappedSession) {
|
|
369
230
|
throw new Error('Authentication session was not found.');
|
|
370
231
|
}
|
|
371
232
|
|
|
372
|
-
return
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
/**
|
|
376
|
-
* Converts mutable session state into a browser-safe snapshot.
|
|
377
|
-
*
|
|
378
|
-
* @param session - Mutable in-memory session.
|
|
379
|
-
* @returns Serializable session snapshot.
|
|
380
|
-
*/
|
|
381
|
-
function createCodeRunnerAuthenticationSessionSnapshot(
|
|
382
|
-
session: CodeRunnerAuthenticationSession,
|
|
383
|
-
): CodeRunnerAuthenticationSessionSnapshot {
|
|
384
|
-
return {
|
|
385
|
-
id: session.id,
|
|
386
|
-
agent: session.agent,
|
|
387
|
-
isRunning: session.isRunning,
|
|
388
|
-
output: session.output,
|
|
389
|
-
startedAt: session.startedAt.toISOString(),
|
|
390
|
-
finishedAt: session.finishedAt ? session.finishedAt.toISOString() : null,
|
|
391
|
-
exitCode: session.exitCode,
|
|
392
|
-
signal: session.signal,
|
|
393
|
-
};
|
|
233
|
+
return mappedSession;
|
|
394
234
|
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import type { InteractiveTerminalSessionSubscriber } from './interactiveTerminalSession';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Minimal browser-safe terminal session shape needed by the shared SSE helper.
|
|
5
|
+
*/
|
|
6
|
+
type InteractiveTerminalEventStreamSession = {
|
|
7
|
+
readonly isRunning: boolean;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Generic subscriber shape used by one streamed browser terminal route.
|
|
12
|
+
*/
|
|
13
|
+
type InteractiveTerminalEventStreamSubscriber<TSession extends InteractiveTerminalEventStreamSession> = {
|
|
14
|
+
readonly onOutput: InteractiveTerminalSessionSubscriber['onOutput'];
|
|
15
|
+
readonly onExit: (event: { readonly type: 'exit'; readonly snapshot: TSession }) => void;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Creates one SSE response that replays buffered terminal output and then streams live events.
|
|
20
|
+
*
|
|
21
|
+
* @param request - Browser stream request.
|
|
22
|
+
* @param sessionId - Terminal session id.
|
|
23
|
+
* @param session - Existing session snapshot.
|
|
24
|
+
* @param subscribe - Subscription function for live terminal events.
|
|
25
|
+
* @returns Event stream response.
|
|
26
|
+
*/
|
|
27
|
+
export function createInteractiveTerminalEventStream<TSession extends InteractiveTerminalEventStreamSession>(
|
|
28
|
+
request: Request,
|
|
29
|
+
sessionId: string,
|
|
30
|
+
session: TSession,
|
|
31
|
+
subscribe: (
|
|
32
|
+
sessionId: string,
|
|
33
|
+
subscriber: InteractiveTerminalEventStreamSubscriber<TSession>,
|
|
34
|
+
) => (() => void) | null,
|
|
35
|
+
): Response {
|
|
36
|
+
const encoder = new TextEncoder();
|
|
37
|
+
|
|
38
|
+
return new Response(
|
|
39
|
+
new ReadableStream({
|
|
40
|
+
start(controller) {
|
|
41
|
+
const emitEvent = (event: string, payload: unknown) => {
|
|
42
|
+
controller.enqueue(encoder.encode(`event: ${event}\ndata: ${JSON.stringify(payload)}\n\n`));
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
emitEvent('snapshot', session);
|
|
46
|
+
|
|
47
|
+
if (!session.isRunning) {
|
|
48
|
+
controller.close();
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const unsubscribe = subscribe(sessionId, {
|
|
53
|
+
onOutput: ({ chunk }) => emitEvent('output', { chunk }),
|
|
54
|
+
onExit: ({ snapshot: nextSession }) => {
|
|
55
|
+
emitEvent('exit', nextSession);
|
|
56
|
+
unsubscribe?.();
|
|
57
|
+
controller.close();
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
if (!unsubscribe) {
|
|
62
|
+
controller.error(new Error('Terminal session was not found.'));
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
request.signal.addEventListener(
|
|
67
|
+
'abort',
|
|
68
|
+
() => {
|
|
69
|
+
unsubscribe();
|
|
70
|
+
controller.close();
|
|
71
|
+
},
|
|
72
|
+
{ once: true },
|
|
73
|
+
);
|
|
74
|
+
},
|
|
75
|
+
}),
|
|
76
|
+
{
|
|
77
|
+
headers: {
|
|
78
|
+
'Content-Type': 'text/event-stream',
|
|
79
|
+
'Cache-Control': 'no-cache, no-transform',
|
|
80
|
+
Connection: 'keep-alive',
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
);
|
|
84
|
+
}
|