@telorun/runner-core 0.8.1 → 0.9.0
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 +33 -2
- package/dist/backend.d.ts +107 -23
- package/dist/backend.d.ts.map +1 -1
- package/dist/config.d.ts +27 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +12 -0
- package/dist/config.js.map +1 -1
- package/dist/contract.d.ts +199 -15
- package/dist/contract.d.ts.map +1 -1
- package/dist/contract.js +9 -0
- package/dist/contract.js.map +1 -1
- package/dist/debug/ports-resolved.d.ts +26 -0
- package/dist/debug/ports-resolved.d.ts.map +1 -0
- package/dist/debug/ports-resolved.js +42 -0
- package/dist/debug/ports-resolved.js.map +1 -0
- package/dist/debug/relay.d.ts.map +1 -1
- package/dist/debug/relay.js +34 -6
- package/dist/debug/relay.js.map +1 -1
- package/dist/debug/run-projection.d.ts +53 -0
- package/dist/debug/run-projection.d.ts.map +1 -0
- package/dist/debug/run-projection.js +115 -0
- package/dist/debug/run-projection.js.map +1 -0
- package/dist/index.d.ts +8 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/dist/routes/apps.d.ts +1 -1
- package/dist/routes/apps.d.ts.map +1 -1
- package/dist/routes/apps.js +14 -4
- package/dist/routes/apps.js.map +1 -1
- package/dist/routes/io.d.ts.map +1 -1
- package/dist/routes/io.js +42 -9
- package/dist/routes/io.js.map +1 -1
- package/dist/routes/session-start.d.ts +12 -12
- package/dist/routes/session-start.d.ts.map +1 -1
- package/dist/routes/session-start.js +86 -13
- package/dist/routes/session-start.js.map +1 -1
- package/dist/routes/sessions.d.ts +11 -1
- package/dist/routes/sessions.d.ts.map +1 -1
- package/dist/routes/sessions.js +429 -4
- package/dist/routes/sessions.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +21 -1
- package/dist/server.js.map +1 -1
- package/dist/session/byte-ring-buffer.d.ts +6 -1
- package/dist/session/byte-ring-buffer.d.ts.map +1 -1
- package/dist/session/byte-ring-buffer.js +2 -2
- package/dist/session/byte-ring-buffer.js.map +1 -1
- package/dist/session/registry.d.ts +144 -13
- package/dist/session/registry.d.ts.map +1 -1
- package/dist/session/registry.js +166 -25
- package/dist/session/registry.js.map +1 -1
- package/dist/session/watch-supervisor.d.ts +42 -0
- package/dist/session/watch-supervisor.d.ts.map +1 -0
- package/dist/session/watch-supervisor.js +99 -0
- package/dist/session/watch-supervisor.js.map +1 -0
- package/dist/session/workspace-app.d.ts +4 -0
- package/dist/session/workspace-app.d.ts.map +1 -0
- package/dist/session/workspace-app.js +26 -0
- package/dist/session/workspace-app.js.map +1 -0
- package/dist/session/workspace-client.d.ts +33 -0
- package/dist/session/workspace-client.d.ts.map +1 -0
- package/dist/session/workspace-client.js +62 -0
- package/dist/session/workspace-client.js.map +1 -0
- package/dist/session/workspace-marker.d.ts +25 -0
- package/dist/session/workspace-marker.d.ts.map +1 -0
- package/dist/session/workspace-marker.js +35 -0
- package/dist/session/workspace-marker.js.map +1 -0
- package/dist/sse/channel.d.ts.map +1 -1
- package/dist/sse/channel.js +4 -0
- package/dist/sse/channel.js.map +1 -1
- package/package.json +5 -4
- package/src/backend.ts +111 -22
- package/src/config.ts +59 -0
- package/src/contract.ts +197 -15
- package/src/debug/ports-resolved.test.ts +66 -0
- package/src/debug/ports-resolved.ts +43 -0
- package/src/debug/relay.ts +32 -4
- package/src/debug/run-projection.test.ts +155 -0
- package/src/debug/run-projection.ts +122 -0
- package/src/index.ts +20 -1
- package/src/routes/apps.ts +14 -5
- package/src/routes/io.ts +58 -12
- package/src/routes/session-start.ts +106 -27
- package/src/routes/sessions.ts +498 -7
- package/src/server.ts +22 -1
- package/src/session/byte-ring-buffer.ts +8 -2
- package/src/session/registry.ts +288 -28
- package/src/session/ring-buffer.test.ts +4 -3
- package/src/session/watch-lifetime.test.ts +203 -0
- package/src/session/watch-supervisor.ts +112 -0
- package/src/session/workspace-app.ts +27 -0
- package/src/session/workspace-client.ts +80 -0
- package/src/session/workspace-marker.test.ts +35 -0
- package/src/session/workspace-marker.ts +39 -0
- package/src/sse/channel.ts +5 -0
- package/workspace-app/telo.yaml +228 -0
package/dist/routes/io.js
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { isTerminal } from "../contract.js";
|
|
2
2
|
const RESIZE_THROTTLE_MS = 50;
|
|
3
3
|
const SEQ_PREFIX_BYTES = 4;
|
|
4
|
+
const STREAM_TAG_BYTES = 1;
|
|
5
|
+
/** Wire codes for the per-frame stream tag. A tag rather than a labelled merged
|
|
6
|
+
* stream: under `io: "streams"` the transport really did separate stdout from
|
|
7
|
+
* stderr, and under `tty` it really did not. */
|
|
8
|
+
const STREAM_CODES = { tty: 0, stdout: 1, stderr: 2 };
|
|
4
9
|
/** Upper bound on cols/rows accepted from the client. xterm + a fit addon
|
|
5
10
|
* produce values in the low thousands at extreme zoom; anything past this
|
|
6
11
|
* is either nonsense or a malicious client trying to feed
|
|
@@ -32,6 +37,19 @@ function handleIo(socket, req, deps) {
|
|
|
32
37
|
closeWith(socket, 4404, "session not found");
|
|
33
38
|
return;
|
|
34
39
|
}
|
|
40
|
+
// Resolve which app's terminal this attachment is for. An explicit name must
|
|
41
|
+
// exist; an omitted one is only defensible on a single-app session.
|
|
42
|
+
const requestedApp = req.query.app?.trim() || undefined;
|
|
43
|
+
const channel = requestedApp
|
|
44
|
+
? entry.apps.get(requestedApp)
|
|
45
|
+
: deps.registry.soleApp(entry);
|
|
46
|
+
if (!channel) {
|
|
47
|
+
closeWith(socket, 4404, requestedApp
|
|
48
|
+
? `session runs no app named '${requestedApp}'`
|
|
49
|
+
: `session runs ${entry.apps.size} apps — ?app= is required`);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const appName = channel.name;
|
|
35
53
|
const lastSeq = parseLastSeq(req.query.lastSeq);
|
|
36
54
|
// Subscribe BEFORE snapshotting the replay buffer. This is load-bearing:
|
|
37
55
|
// a `pushBytes` that fires between snapshot and subscribe would otherwise
|
|
@@ -41,7 +59,7 @@ function handleIo(socket, req, deps) {
|
|
|
41
59
|
// the handler switches to direct-send mode.
|
|
42
60
|
let mode = "deferred";
|
|
43
61
|
const liveQueue = [];
|
|
44
|
-
const unsubscribe = deps.registry.subscribeBytes(sessionId, (buffered) => {
|
|
62
|
+
const unsubscribe = deps.registry.subscribeBytes(sessionId, appName, (buffered) => {
|
|
45
63
|
if (socket.readyState !== socket.OPEN)
|
|
46
64
|
return;
|
|
47
65
|
if (mode === "deferred") {
|
|
@@ -51,7 +69,7 @@ function handleIo(socket, req, deps) {
|
|
|
51
69
|
sendBytesFrame(socket, buffered);
|
|
52
70
|
}
|
|
53
71
|
});
|
|
54
|
-
const { entries, hasGap } =
|
|
72
|
+
const { entries, hasGap } = channel.byteBuffer.replay(lastSeq);
|
|
55
73
|
// If the session is already terminal AND the byte buffer holds nothing
|
|
56
74
|
// newer than what the client already saw, there's no live channel to
|
|
57
75
|
// attach to — close 4410 so the client falls back to status-only display.
|
|
@@ -60,8 +78,9 @@ function handleIo(socket, req, deps) {
|
|
|
60
78
|
closeWith(socket, 4410, "session terminal, nothing to replay");
|
|
61
79
|
return;
|
|
62
80
|
}
|
|
63
|
-
// Confirm the resume point
|
|
64
|
-
|
|
81
|
+
// Confirm the resume point and which attachment this is, so a client knows
|
|
82
|
+
// whether to offer resize before it sends one.
|
|
83
|
+
sendJson(socket, { type: "seq", seq: lastSeq, app: appName, io: channel.io });
|
|
65
84
|
if (hasGap) {
|
|
66
85
|
sendJson(socket, { type: "gap", reason: "buffer_evicted" });
|
|
67
86
|
}
|
|
@@ -92,7 +111,7 @@ function handleIo(socket, req, deps) {
|
|
|
92
111
|
return;
|
|
93
112
|
// Session may have exited between schedule and flush; backends treat
|
|
94
113
|
// resize on a gone workload as a no-op.
|
|
95
|
-
entry.session?.resize(next.cols, next.rows);
|
|
114
|
+
entry.session?.resize(appName, next.cols, next.rows);
|
|
96
115
|
};
|
|
97
116
|
socket.on("message", (raw, isBinary) => {
|
|
98
117
|
if (isBinary) {
|
|
@@ -100,7 +119,7 @@ function handleIo(socket, req, deps) {
|
|
|
100
119
|
if (!session)
|
|
101
120
|
return;
|
|
102
121
|
const buf = raw instanceof Buffer ? raw : Buffer.from(raw);
|
|
103
|
-
session.writeStdin(buf);
|
|
122
|
+
session.writeStdin(appName, buf);
|
|
104
123
|
return;
|
|
105
124
|
}
|
|
106
125
|
const text = raw.toString();
|
|
@@ -112,6 +131,13 @@ function handleIo(socket, req, deps) {
|
|
|
112
131
|
return;
|
|
113
132
|
}
|
|
114
133
|
if (parsed.type === "resize") {
|
|
134
|
+
// A resize is meaningless with no PTY — rejected rather than silently
|
|
135
|
+
// dropped, so a client attached to a `streams` app learns it must not
|
|
136
|
+
// wire its terminal's resize through.
|
|
137
|
+
if (channel.io !== "tty") {
|
|
138
|
+
sendJson(socket, { type: "error", error: "resize_unsupported", io: channel.io });
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
115
141
|
const cols = clampDimension(parsed.cols);
|
|
116
142
|
const rows = clampDimension(parsed.rows);
|
|
117
143
|
if (cols === null || rows === null)
|
|
@@ -160,7 +186,11 @@ function handleIo(socket, req, deps) {
|
|
|
160
186
|
if (isTerminal(entry.status) && drainTimer === null) {
|
|
161
187
|
drainAndClose(Date.now() + TERMINAL_DRAIN_MAX_MS);
|
|
162
188
|
}
|
|
189
|
+
// A byte-channel attachment counts as a live client: a session whose terminal
|
|
190
|
+
// someone is watching is not idle, even with no SSE stream open.
|
|
191
|
+
const releaseSubscriber = deps.registry.addSubscriber(sessionId);
|
|
163
192
|
const cleanup = () => {
|
|
193
|
+
releaseSubscriber();
|
|
164
194
|
unsubscribe();
|
|
165
195
|
unsubscribeStatus();
|
|
166
196
|
if (resizeTimer)
|
|
@@ -171,15 +201,18 @@ function handleIo(socket, req, deps) {
|
|
|
171
201
|
socket.on("close", cleanup);
|
|
172
202
|
socket.on("error", cleanup);
|
|
173
203
|
}
|
|
174
|
-
/** Wire format for a binary frame: `[seq:4 BE][payload:N]`. The 4-byte
|
|
204
|
+
/** Wire format for a binary frame: `[seq:4 BE][stream:1][payload:N]`. The 4-byte
|
|
175
205
|
* prefix lets the client de-sync detect — it knows the authoritative seq
|
|
176
206
|
* for every byte received, instead of inferring from frame count. Replay
|
|
177
|
-
* duplicates and reconnect resumes both lean on this.
|
|
207
|
+
* duplicates and reconnect resumes both lean on this. The stream byte says
|
|
208
|
+
* which source produced the payload; it is `tty` under a terminal attach and
|
|
209
|
+
* never asserts a split the transport did not make. */
|
|
178
210
|
function sendBytesFrame(socket, buffered) {
|
|
179
211
|
if (socket.readyState !== socket.OPEN)
|
|
180
212
|
return;
|
|
181
|
-
const prefix = Buffer.alloc(SEQ_PREFIX_BYTES);
|
|
213
|
+
const prefix = Buffer.alloc(SEQ_PREFIX_BYTES + STREAM_TAG_BYTES);
|
|
182
214
|
prefix.writeUInt32BE(buffered.seq, 0);
|
|
215
|
+
prefix.writeUInt8(STREAM_CODES[buffered.stream] ?? 0, SEQ_PREFIX_BYTES);
|
|
183
216
|
try {
|
|
184
217
|
socket.send(Buffer.concat([prefix, buffered.bytes]));
|
|
185
218
|
}
|
package/dist/routes/io.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"io.js","sourceRoot":"","sources":["../../src/routes/io.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,
|
|
1
|
+
{"version":3,"file":"io.js","sourceRoot":"","sources":["../../src/routes/io.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
|
|
2
|
-
import type { RunnerBackend } from "../backend.js";
|
|
3
|
-
import { type
|
|
4
|
-
import { type SessionRegistry } from "../session/registry.js";
|
|
2
|
+
import type { RunnerBackend, WorkloadLaunch } from "../backend.js";
|
|
3
|
+
import { type RunnerTerms } from "../contract.js";
|
|
4
|
+
import { type SessionEntry, type SessionRegistry } from "../session/registry.js";
|
|
5
5
|
/** JSON Schema for the `ports` body field, shared by every session-creating
|
|
6
6
|
* route so bundle and app sessions validate port mappings identically. */
|
|
7
7
|
export declare const portsSchema: {
|
|
@@ -38,15 +38,7 @@ export interface WorkloadStartDeps {
|
|
|
38
38
|
* TELO_REGISTRY_URL when the request doesn't override it. */
|
|
39
39
|
defaultRegistryUrl?: string;
|
|
40
40
|
}
|
|
41
|
-
export
|
|
42
|
-
bundle: RunBundle;
|
|
43
|
-
entryRelativePath: string;
|
|
44
|
-
env: Record<string, string>;
|
|
45
|
-
ports: PortMapping[];
|
|
46
|
-
config: SessionConfig;
|
|
47
|
-
selfContained: boolean;
|
|
48
|
-
inspect: boolean;
|
|
49
|
-
}
|
|
41
|
+
export type WorkloadStartArgs = WorkloadLaunch;
|
|
50
42
|
/**
|
|
51
43
|
* The session-creation leaf shared by `POST /v1/sessions` (bundle sessions) and
|
|
52
44
|
* `POST /v1/apps/:name/sessions` (operator-predefined apps): registers the
|
|
@@ -56,4 +48,12 @@ export interface WorkloadStartArgs {
|
|
|
56
48
|
* collection (status, DELETE, events, io).
|
|
57
49
|
*/
|
|
58
50
|
export declare function startWorkloadSession(app: FastifyInstance, deps: WorkloadStartDeps, args: WorkloadStartArgs, reply: FastifyReply): Promise<void>;
|
|
51
|
+
/**
|
|
52
|
+
* Wire a backend workload to an EXISTING registry entry and start it in the
|
|
53
|
+
* background. Shared by session creation and by `resume`, which builds a fresh
|
|
54
|
+
* pod from the checkpoint under the same session id — the callback wiring is the
|
|
55
|
+
* contract's, so a second copy of it would be a second place run outcomes,
|
|
56
|
+
* output routing and the credential boundary could drift.
|
|
57
|
+
*/
|
|
58
|
+
export declare function launchWorkload(app: FastifyInstance, deps: WorkloadStartDeps, args: WorkloadStartArgs, entry: SessionEntry): void;
|
|
59
59
|
//# sourceMappingURL=session-start.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-start.d.ts","sourceRoot":"","sources":["../../src/routes/session-start.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAG7E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"session-start.d.ts","sourceRoot":"","sources":["../../src/routes/session-start.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAG7E,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEnE,OAAO,EAGL,KAAK,WAAW,EACjB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,eAAe,EACrB,MAAM,wBAAwB,CAAC;AAEhC;2EAC2E;AAC3E,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;CAUd,CAAC;AAEX;;;;;GAKG;AACH,wBAAgB,YAAY,CAC1B,GAAG,EAAE,cAAc,EACnB,KAAK,EAAE,YAAY,EACnB,KAAK,EAAE,WAAW,GAAG,SAAS,GAC7B,OAAO,CAST;AAED;gFACgF;AAChF,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,aAAa,CAAC;IACvB,QAAQ,EAAE,eAAe,CAAC;IAC1B;kEAC8D;IAC9D,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,MAAM,iBAAiB,GAAG,cAAc,CAAC;AAE/C;;;;;;;GAOG;AACH,wBAAsB,oBAAoB,CACxC,GAAG,EAAE,eAAe,EACpB,IAAI,EAAE,iBAAiB,EACvB,IAAI,EAAE,iBAAiB,EACvB,KAAK,EAAE,YAAY,GAClB,OAAO,CAAC,IAAI,CAAC,CAuDf;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,eAAe,EACpB,IAAI,EAAE,iBAAiB,EACvB,IAAI,EAAE,iBAAiB,EACvB,KAAK,EAAE,YAAY,GAClB,IAAI,CA0FN"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { isEventFrame } from "@telorun/debug-wire";
|
|
2
|
+
import { RunProjection } from "../debug/run-projection.js";
|
|
2
3
|
import { ACCEPTED_TERMS_HEADER, SessionStartError, } from "../contract.js";
|
|
3
4
|
import { generateSessionId } from "../session/session-id.js";
|
|
4
|
-
import { SessionLimitError } from "../session/registry.js";
|
|
5
|
+
import { SessionLimitError, } from "../session/registry.js";
|
|
5
6
|
/** JSON Schema for the `ports` body field, shared by every session-creating
|
|
6
7
|
* route so bundle and app sessions validate port mappings identically. */
|
|
7
8
|
export const portsSchema = {
|
|
@@ -44,7 +45,12 @@ export async function startWorkloadSession(app, deps, args, reply) {
|
|
|
44
45
|
const sessionId = generateSessionId();
|
|
45
46
|
let entry;
|
|
46
47
|
try {
|
|
47
|
-
entry = deps.registry.register({
|
|
48
|
+
entry = deps.registry.register({
|
|
49
|
+
sessionId,
|
|
50
|
+
mode: args.mode,
|
|
51
|
+
agent: args.agent?.name,
|
|
52
|
+
apps: args.apps.map((a) => ({ name: a.name, io: a.io, ports: a.ports })),
|
|
53
|
+
});
|
|
48
54
|
}
|
|
49
55
|
catch (err) {
|
|
50
56
|
if (err instanceof SessionLimitError) {
|
|
@@ -59,9 +65,9 @@ export async function startWorkloadSession(app, deps, args, reply) {
|
|
|
59
65
|
// whitespace from an editor input doesn't flow into the workload.
|
|
60
66
|
const configRegistryUrl = args.config.registryUrl?.trim() || undefined;
|
|
61
67
|
const registryUrl = configRegistryUrl ?? deps.defaultRegistryUrl;
|
|
62
|
-
const sessionEnv = registryUrl && !("TELO_REGISTRY_URL" in args.env)
|
|
68
|
+
const sessionEnv = withoutCacheOverride(registryUrl && !("TELO_REGISTRY_URL" in args.env)
|
|
63
69
|
? { ...args.env, TELO_REGISTRY_URL: registryUrl }
|
|
64
|
-
: args.env;
|
|
70
|
+
: args.env);
|
|
65
71
|
// Respond as soon as the session is registered — BEFORE the backend starts.
|
|
66
72
|
// `backend.start()` now spans the on-cluster image build and pod bring-up,
|
|
67
73
|
// which can take seconds-to-minutes; awaiting it here would hide the event
|
|
@@ -74,28 +80,79 @@ export async function startWorkloadSession(app, deps, args, reply) {
|
|
|
74
80
|
streamUrl: `/v1/sessions/${sessionId}/events`,
|
|
75
81
|
createdAt: entry.createdAt.toISOString(),
|
|
76
82
|
});
|
|
83
|
+
// Every app's first generation is attributed to the session coming up; a
|
|
84
|
+
// reload after that is a watch reload unless a route says otherwise.
|
|
85
|
+
const projection = new RunProjection(deps.registry, sessionId);
|
|
86
|
+
projection.expectAll("initial");
|
|
87
|
+
// Parked on the entry so the reload / resume routes can attribute the
|
|
88
|
+
// generation they are about to cause.
|
|
89
|
+
entry.attribution = projection;
|
|
90
|
+
const launch = { ...args, env: sessionEnv };
|
|
91
|
+
entry.launch = launch;
|
|
92
|
+
launchWorkload(app, deps, launch, entry);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Wire a backend workload to an EXISTING registry entry and start it in the
|
|
96
|
+
* background. Shared by session creation and by `resume`, which builds a fresh
|
|
97
|
+
* pod from the checkpoint under the same session id — the callback wiring is the
|
|
98
|
+
* contract's, so a second copy of it would be a second place run outcomes,
|
|
99
|
+
* output routing and the credential boundary could drift.
|
|
100
|
+
*/
|
|
101
|
+
export function launchWorkload(app, deps, args, entry) {
|
|
102
|
+
const sessionId = entry.sessionId;
|
|
103
|
+
const projection = entry.attribution;
|
|
77
104
|
deps.backend
|
|
78
105
|
.start({
|
|
79
106
|
sessionId,
|
|
80
107
|
bundle: args.bundle,
|
|
81
|
-
|
|
82
|
-
env: sessionEnv,
|
|
83
|
-
ports: args.ports,
|
|
108
|
+
env: args.env,
|
|
84
109
|
config: args.config,
|
|
85
110
|
selfContained: args.selfContained,
|
|
86
111
|
inspect: args.inspect,
|
|
112
|
+
mode: args.mode,
|
|
113
|
+
apps: args.apps,
|
|
114
|
+
agent: args.agent,
|
|
87
115
|
onStatus: (status) => deps.registry.emit(sessionId, { type: "status", status }),
|
|
88
|
-
onProgress: (phase, message, done) => deps.registry.emit(sessionId, { type: "progress", phase, message, done }),
|
|
89
|
-
onOutput: (chunk) => deps.registry.pushBytes(sessionId, chunk),
|
|
116
|
+
onProgress: (phase, message, done, app) => deps.registry.emit(sessionId, { type: "progress", app, phase, message, done }),
|
|
117
|
+
onOutput: (app, chunk, stream) => deps.registry.pushBytes(sessionId, app, chunk, stream),
|
|
90
118
|
// Relay only kernel *event* frames to the client. stdout/stderr already
|
|
91
119
|
// arrive over the byte channel (onOutput), so forwarding log frames would
|
|
92
120
|
// double the traffic and let log spam evict lifecycle events from the
|
|
93
121
|
// byte-capped replay buffer. The editor discards relayed logs anyway.
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
122
|
+
//
|
|
123
|
+
// The projection sees EVERY frame, including the ones not relayed — run
|
|
124
|
+
// outcomes are derived from lifecycle events, not from what a client
|
|
125
|
+
// happens to be shown.
|
|
126
|
+
onDebug: (appName, frame) => {
|
|
127
|
+
projection?.frame(appName, frame);
|
|
128
|
+
if (isEventFrame(frame)) {
|
|
129
|
+
deps.registry.emit(sessionId, { type: "debug", app: appName, frame });
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
// A watch session's app dying is a RUN outcome, not a session status: the
|
|
133
|
+
// rest of the session is still up, and the next edit starts the next
|
|
134
|
+
// generation. The projection owns generation identity, so the ending goes
|
|
135
|
+
// through it rather than being emitted directly.
|
|
136
|
+
onRunEnded: (appName, outcome) => projection?.endGeneration(appName, outcome) ??
|
|
137
|
+
deps.registry.finishGeneration(sessionId, appName, {
|
|
138
|
+
phase: "failed",
|
|
139
|
+
reason: outcome.reason ?? "workload ended",
|
|
140
|
+
}),
|
|
141
|
+
onReachability: (app, port, state) => deps.registry.emit(sessionId, { type: "reachability", app, port, state }),
|
|
142
|
+
onEndpoints: (appName, change) => {
|
|
143
|
+
// The registry's own channel is what `GET /v1/sessions/:id` reports, so
|
|
144
|
+
// the delta has to land there too — otherwise the session document keeps
|
|
145
|
+
// describing the port set the session STARTED with, forever.
|
|
146
|
+
const channel = entry.apps.get(appName);
|
|
147
|
+
if (channel) {
|
|
148
|
+
const removed = new Set((change.removed ?? []).map((e) => `${e.protocol}/${e.port}`));
|
|
149
|
+
channel.ports = [
|
|
150
|
+
...channel.ports.filter((p) => !removed.has(`${p.protocol}/${p.port}`)),
|
|
151
|
+
...(change.added ?? []).map((e) => ({ port: e.port, protocol: e.protocol })),
|
|
152
|
+
];
|
|
153
|
+
}
|
|
154
|
+
deps.registry.emit(sessionId, { type: "endpoints", app: appName, ...change });
|
|
97
155
|
},
|
|
98
|
-
onReachability: (port, state) => deps.registry.emit(sessionId, { type: "reachability", port, state }),
|
|
99
156
|
isUserStopped: () => entry.userStopped,
|
|
100
157
|
})
|
|
101
158
|
.then(async (session) => {
|
|
@@ -126,4 +183,20 @@ export async function startWorkloadSession(app, deps, args, reply) {
|
|
|
126
183
|
deps.registry.emit(sessionId, { type: "status", status: { kind: "failed", message } });
|
|
127
184
|
});
|
|
128
185
|
}
|
|
186
|
+
/**
|
|
187
|
+
* Drop a client-supplied `TELO_CACHE_DIR`.
|
|
188
|
+
*
|
|
189
|
+
* It OUTRANKS the `telo-workspace.yaml` marker the session seeds at its
|
|
190
|
+
* workspace root, so a client that sets it silently gives every app its own
|
|
191
|
+
* module cache — the exact thing the marker exists to prevent. Where a cache
|
|
192
|
+
* root is genuinely needed (the workspace container, whose manifest lives
|
|
193
|
+
* outside the workspace) the backend sets it itself.
|
|
194
|
+
*/
|
|
195
|
+
function withoutCacheOverride(env) {
|
|
196
|
+
if (!("TELO_CACHE_DIR" in env))
|
|
197
|
+
return env;
|
|
198
|
+
const rest = { ...env };
|
|
199
|
+
delete rest.TELO_CACHE_DIR;
|
|
200
|
+
return rest;
|
|
201
|
+
}
|
|
129
202
|
//# sourceMappingURL=session-start.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-start.js","sourceRoot":"","sources":["../../src/routes/session-start.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEnD,OAAO,EACL,qBAAqB,EACrB,iBAAiB,
|
|
1
|
+
{"version":3,"file":"session-start.js","sourceRoot":"","sources":["../../src/routes/session-start.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import type { FastifyPluginAsync } from "fastify";
|
|
2
2
|
import type { RunnerBackend } from "../backend.js";
|
|
3
|
-
import type {
|
|
3
|
+
import type { ResolvedRunnerApp, WatchSessionConfig } from "../config.js";
|
|
4
|
+
import { type RunnerTerms, type SessionConfig } from "../contract.js";
|
|
4
5
|
import type { SessionRegistry } from "../session/registry.js";
|
|
6
|
+
/** The part of the operator's watch settings this route enforces. A projection
|
|
7
|
+
* of `WatchSessionConfig` rather than a second shape, so the two cannot
|
|
8
|
+
* disagree about what a field means. */
|
|
9
|
+
export type WatchConfig = Pick<WatchSessionConfig, "enabled" | "maxSessions" | "reloadLimitPerMinute">;
|
|
5
10
|
export interface SessionsRouteDeps {
|
|
6
11
|
backend: RunnerBackend;
|
|
7
12
|
registry: SessionRegistry;
|
|
@@ -17,6 +22,11 @@ export interface SessionsRouteDeps {
|
|
|
17
22
|
* the source of truth, so this re-checks what `/v1/capabilities` advertises
|
|
18
23
|
* (e.g. an `image` allowlist) against a client that skipped the editor. */
|
|
19
24
|
validateConfig?: (config: SessionConfig) => string | undefined;
|
|
25
|
+
/** The operator catalog a session's `agent` is resolved against — the same
|
|
26
|
+
* catalog `POST /v1/apps/:name/sessions` uses, because a co-resident agent IS
|
|
27
|
+
* an operator-predefined application, just one sharing a pod. */
|
|
28
|
+
apps?: Record<string, ResolvedRunnerApp>;
|
|
29
|
+
watch: WatchConfig;
|
|
20
30
|
}
|
|
21
31
|
export declare function sessionsRoute(deps: SessionsRouteDeps): FastifyPluginAsync;
|
|
22
32
|
//# sourceMappingURL=sessions.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sessions.d.ts","sourceRoot":"","sources":["../../src/routes/sessions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAmB,kBAAkB,EAAgB,MAAM,SAAS,CAAC;AAEjF,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"sessions.d.ts","sourceRoot":"","sources":["../../src/routes/sessions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAmB,kBAAkB,EAAgB,MAAM,SAAS,CAAC;AAEjF,OAAO,KAAK,EAAkB,aAAa,EAAE,MAAM,eAAe,CAAC;AACnE,OAAO,KAAK,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAC1E,OAAO,EAIL,KAAK,WAAW,EAEhB,KAAK,aAAa,EAGnB,MAAM,gBAAgB,CAAC;AAExB,OAAO,KAAK,EAAgB,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAI5E;;yCAEyC;AACzC,MAAM,MAAM,WAAW,GAAG,IAAI,CAC5B,kBAAkB,EAClB,SAAS,GAAG,aAAa,GAAG,sBAAsB,CACnD,CAAC;AAEF,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,aAAa,CAAC;IACvB,QAAQ,EAAE,eAAe,CAAC;IAC1B,WAAW,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC;IAC5B;kEAC8D;IAC9D,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;gEAC4D;IAC5D,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB;;;gFAG4E;IAC5E,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,MAAM,GAAG,SAAS,CAAC;IAC/D;;sEAEkE;IAClE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;IACzC,KAAK,EAAE,WAAW,CAAC;CACpB;AA0FD,wBAAgB,aAAa,CAAC,IAAI,EAAE,iBAAiB,GAAG,kBAAkB,CAuRzE"}
|