@owlmeans/viable-sdk 0.1.18-rc.1
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 +128 -0
- package/build/api/index.d.ts +2 -0
- package/build/api/index.d.ts.map +1 -0
- package/build/api/index.js +2 -0
- package/build/api/index.js.map +1 -0
- package/build/api/remote.d.ts +14 -0
- package/build/api/remote.d.ts.map +1 -0
- package/build/api/remote.js +123 -0
- package/build/api/remote.js.map +1 -0
- package/build/consts.d.ts +47 -0
- package/build/consts.d.ts.map +1 -0
- package/build/consts.js +47 -0
- package/build/consts.js.map +1 -0
- package/build/context/index.d.ts +22 -0
- package/build/context/index.d.ts.map +1 -0
- package/build/context/index.js +92 -0
- package/build/context/index.js.map +1 -0
- package/build/errors.d.ts +21 -0
- package/build/errors.d.ts.map +1 -0
- package/build/errors.js +36 -0
- package/build/errors.js.map +1 -0
- package/build/executor/boot-check.d.ts +73 -0
- package/build/executor/boot-check.d.ts.map +1 -0
- package/build/executor/boot-check.js +155 -0
- package/build/executor/boot-check.js.map +1 -0
- package/build/executor/env.d.ts +25 -0
- package/build/executor/env.d.ts.map +1 -0
- package/build/executor/env.js +77 -0
- package/build/executor/env.js.map +1 -0
- package/build/executor/errors.d.ts +69 -0
- package/build/executor/errors.d.ts.map +1 -0
- package/build/executor/errors.js +80 -0
- package/build/executor/errors.js.map +1 -0
- package/build/executor/files.d.ts +124 -0
- package/build/executor/files.d.ts.map +1 -0
- package/build/executor/files.js +529 -0
- package/build/executor/files.js.map +1 -0
- package/build/executor/git.d.ts +52 -0
- package/build/executor/git.d.ts.map +1 -0
- package/build/executor/git.js +353 -0
- package/build/executor/git.js.map +1 -0
- package/build/executor/health.d.ts +92 -0
- package/build/executor/health.d.ts.map +1 -0
- package/build/executor/health.js +98 -0
- package/build/executor/health.js.map +1 -0
- package/build/executor/index.d.ts +39 -0
- package/build/executor/index.d.ts.map +1 -0
- package/build/executor/index.js +173 -0
- package/build/executor/index.js.map +1 -0
- package/build/executor/integrity.d.ts +17 -0
- package/build/executor/integrity.d.ts.map +1 -0
- package/build/executor/integrity.js +59 -0
- package/build/executor/integrity.js.map +1 -0
- package/build/executor/layout.d.ts +61 -0
- package/build/executor/layout.d.ts.map +1 -0
- package/build/executor/layout.js +98 -0
- package/build/executor/layout.js.map +1 -0
- package/build/executor/shell.d.ts +89 -0
- package/build/executor/shell.d.ts.map +1 -0
- package/build/executor/shell.js +280 -0
- package/build/executor/shell.js.map +1 -0
- package/build/executor/spawn.d.ts +111 -0
- package/build/executor/spawn.d.ts.map +1 -0
- package/build/executor/spawn.js +314 -0
- package/build/executor/spawn.js.map +1 -0
- package/build/harness/index.d.ts +28 -0
- package/build/harness/index.d.ts.map +1 -0
- package/build/harness/index.js +83 -0
- package/build/harness/index.js.map +1 -0
- package/build/harness/templates.d.ts +30 -0
- package/build/harness/templates.d.ts.map +1 -0
- package/build/harness/templates.js +162 -0
- package/build/harness/templates.js.map +1 -0
- package/build/index.d.ts +13 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +12 -0
- package/build/index.js.map +1 -0
- package/build/project/env.d.ts +108 -0
- package/build/project/env.d.ts.map +1 -0
- package/build/project/env.js +233 -0
- package/build/project/env.js.map +1 -0
- package/build/project/marker.d.ts +34 -0
- package/build/project/marker.d.ts.map +1 -0
- package/build/project/marker.js +54 -0
- package/build/project/marker.js.map +1 -0
- package/build/project/setup.d.ts +62 -0
- package/build/project/setup.d.ts.map +1 -0
- package/build/project/setup.js +190 -0
- package/build/project/setup.js.map +1 -0
- package/build/run/index.d.ts +75 -0
- package/build/run/index.d.ts.map +1 -0
- package/build/run/index.js +150 -0
- package/build/run/index.js.map +1 -0
- package/build/run/serve.d.ts +18 -0
- package/build/run/serve.d.ts.map +1 -0
- package/build/run/serve.js +148 -0
- package/build/run/serve.js.map +1 -0
- package/build/run/state.d.ts +75 -0
- package/build/run/state.d.ts.map +1 -0
- package/build/run/state.js +136 -0
- package/build/run/state.js.map +1 -0
- package/build/session/index.d.ts +17 -0
- package/build/session/index.d.ts.map +1 -0
- package/build/session/index.js +226 -0
- package/build/session/index.js.map +1 -0
- package/build/session/questions.d.ts +16 -0
- package/build/session/questions.d.ts.map +1 -0
- package/build/session/questions.js +17 -0
- package/build/session/questions.js.map +1 -0
- package/build/session/queue.d.ts +54 -0
- package/build/session/queue.d.ts.map +1 -0
- package/build/session/queue.js +102 -0
- package/build/session/queue.js.map +1 -0
- package/build/session/tasks.d.ts +15 -0
- package/build/session/tasks.d.ts.map +1 -0
- package/build/session/tasks.js +16 -0
- package/build/session/tasks.js.map +1 -0
- package/build/task/driver.d.ts +30 -0
- package/build/task/driver.d.ts.map +1 -0
- package/build/task/driver.js +120 -0
- package/build/task/driver.js.map +1 -0
- package/build/task/envelope.d.ts +35 -0
- package/build/task/envelope.d.ts.map +1 -0
- package/build/task/envelope.js +230 -0
- package/build/task/envelope.js.map +1 -0
- package/build/task/index.d.ts +4 -0
- package/build/task/index.d.ts.map +1 -0
- package/build/task/index.js +4 -0
- package/build/task/index.js.map +1 -0
- package/build/task/inquiry.d.ts +53 -0
- package/build/task/inquiry.d.ts.map +1 -0
- package/build/task/inquiry.js +232 -0
- package/build/task/inquiry.js.map +1 -0
- package/build/tools/catalogue.d.ts +17 -0
- package/build/tools/catalogue.d.ts.map +1 -0
- package/build/tools/catalogue.js +1169 -0
- package/build/tools/catalogue.js.map +1 -0
- package/build/tools/index.d.ts +7 -0
- package/build/tools/index.d.ts.map +1 -0
- package/build/tools/index.js +7 -0
- package/build/tools/index.js.map +1 -0
- package/build/tools/jobs.d.ts +12 -0
- package/build/tools/jobs.d.ts.map +1 -0
- package/build/tools/jobs.js +60 -0
- package/build/tools/jobs.js.map +1 -0
- package/build/tools/mcp.d.ts +43 -0
- package/build/tools/mcp.d.ts.map +1 -0
- package/build/tools/mcp.js +131 -0
- package/build/tools/mcp.js.map +1 -0
- package/build/tools/platform.d.ts +77 -0
- package/build/tools/platform.d.ts.map +1 -0
- package/build/tools/platform.js +316 -0
- package/build/tools/platform.js.map +1 -0
- package/build/tools/refusal.d.ts +66 -0
- package/build/tools/refusal.d.ts.map +1 -0
- package/build/tools/refusal.js +377 -0
- package/build/tools/refusal.js.map +1 -0
- package/build/tools/types.d.ts +83 -0
- package/build/tools/types.d.ts.map +1 -0
- package/build/tools/types.js +38 -0
- package/build/tools/types.js.map +1 -0
- package/build/types.d.ts +174 -0
- package/build/types.d.ts.map +1 -0
- package/build/types.js +2 -0
- package/build/types.js.map +1 -0
- package/package.json +105 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { TARGET_API_PORT, TARGET_WEB_PORT, TARGET_WORKER_PORT } from '@owlmeans/viable-common';
|
|
2
|
+
/**
|
|
3
|
+
* What a local run is, written down.
|
|
4
|
+
*
|
|
5
|
+
* A separate module from the run itself, and the separation is load-bearing: `DbSync` has to
|
|
6
|
+
* bounce the api child, `DbSync` lives in the shell commands, and the shell commands are reached
|
|
7
|
+
* through the executor the run is built on. Everything that touches a child process therefore
|
|
8
|
+
* lives here, below both of them, instead of making the three import each other in a circle.
|
|
9
|
+
*
|
|
10
|
+
* The record is a file rather than memory because the processes outlive the call that started
|
|
11
|
+
* them and, on a restarted connector, outlive the process that started them too.
|
|
12
|
+
*/
|
|
13
|
+
export interface LocalProcessRecord {
|
|
14
|
+
pid: number;
|
|
15
|
+
port: number;
|
|
16
|
+
/**
|
|
17
|
+
* The id this instance answers `/api/healtz` with.
|
|
18
|
+
*
|
|
19
|
+
* Port ownership is a restart's only proof: the child is a shell wrapping `bun`, so a signal
|
|
20
|
+
* the shell dies from and `bun` survives leaves an orphan holding the port while the exit
|
|
21
|
+
* handler says "gone". A replacement then loses the bind and exits — and since a failed
|
|
22
|
+
* `listen` announces nothing on its own, everything keeps reporting healthy while the older
|
|
23
|
+
* build is what is being served.
|
|
24
|
+
*/
|
|
25
|
+
bootId?: string;
|
|
26
|
+
}
|
|
27
|
+
export interface LocalRunRecord {
|
|
28
|
+
dir: string;
|
|
29
|
+
startedAt: string;
|
|
30
|
+
api?: LocalProcessRecord;
|
|
31
|
+
worker?: LocalProcessRecord;
|
|
32
|
+
/** The process serving the built browser app — this connector itself, not a child. */
|
|
33
|
+
web?: LocalProcessRecord;
|
|
34
|
+
}
|
|
35
|
+
export declare const readRun: (dir: string) => Promise<LocalRunRecord | null>;
|
|
36
|
+
export declare const writeRun: (dir: string, record: LocalRunRecord) => Promise<void>;
|
|
37
|
+
export declare const clearRun: (dir: string) => Promise<void>;
|
|
38
|
+
/** Whether the api recorded here is still a live process. */
|
|
39
|
+
export declare const apiRunning: (record: LocalRunRecord | null) => boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Start the target's HTTP server as a detached child.
|
|
42
|
+
*
|
|
43
|
+
* Detached so the whole group can be signalled later — the child is a shell wrapping `bun`, and a
|
|
44
|
+
* signal aimed at the shell alone leaves `bun` holding the port.
|
|
45
|
+
*/
|
|
46
|
+
export declare const startApi: (dir: string, env?: Record<string, string>) => Promise<LocalProcessRecord>;
|
|
47
|
+
/**
|
|
48
|
+
* Start the target's queue worker, when this tree has one.
|
|
49
|
+
*
|
|
50
|
+
* The SAME `dist/index.js` as the api, out of the same package tree — the argv marker is the only
|
|
51
|
+
* thing separating the two processes, which is why nothing may reclaim a port without excluding
|
|
52
|
+
* the other's marker. Most generated applications declare no queues, and their absence is not a
|
|
53
|
+
* degraded state.
|
|
54
|
+
*/
|
|
55
|
+
export declare const startWorker: (dir: string) => Promise<LocalProcessRecord | null>;
|
|
56
|
+
/**
|
|
57
|
+
* Stop a recorded process and wait for its port to actually free.
|
|
58
|
+
*
|
|
59
|
+
* The port and not the pid is what a replacement needs, so that is what is waited on.
|
|
60
|
+
*/
|
|
61
|
+
export declare const stopProcess: (record: LocalProcessRecord | undefined) => Promise<void>;
|
|
62
|
+
/**
|
|
63
|
+
* Bounce the api child so it reconciles the target's tables against its code.
|
|
64
|
+
*
|
|
65
|
+
* What `DbSync` means for a target that owns its own structure: every `@owlmeans/postgres`
|
|
66
|
+
* resource creates and updates its table while the context initializes, so there is nothing to
|
|
67
|
+
* generate and no migration file to apply — the sync IS the restart. A tree with no run in front
|
|
68
|
+
* of it answers `null`: there is no process to bounce, and reporting that as a failure would send
|
|
69
|
+
* a caller after a repair that does not apply.
|
|
70
|
+
*/
|
|
71
|
+
export declare const restartApi: (dir: string) => Promise<string | null>;
|
|
72
|
+
/** Whether anything is answering on the api's port right now. */
|
|
73
|
+
export declare const apiListening: (port?: number) => Promise<boolean>;
|
|
74
|
+
export { TARGET_API_PORT, TARGET_WEB_PORT, TARGET_WORKER_PORT };
|
|
75
|
+
//# sourceMappingURL=state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../src/run/state.ts"],"names":[],"mappings":"AAKA,OAAO,EACoD,eAAe,EAAE,eAAe,EAEzF,kBAAkB,EACnB,MAAM,yBAAyB,CAAA;AAOhC;;;;;;;;;;GAUG;AAEH,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,MAAM,CAAA;IACZ;;;;;;;;OAQG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAA;IACX,SAAS,EAAE,MAAM,CAAA;IACjB,GAAG,CAAC,EAAE,kBAAkB,CAAA;IACxB,MAAM,CAAC,EAAE,kBAAkB,CAAA;IAC3B,sFAAsF;IACtF,GAAG,CAAC,EAAE,kBAAkB,CAAA;CACzB;AAID,eAAO,MAAM,OAAO,QAAe,MAAM,KAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAWxE,CAAA;AAED,eAAO,MAAM,QAAQ,QAAe,MAAM,UAAU,cAAc,KAAG,OAAO,CAAC,IAAI,CAGhF,CAAA;AAED,eAAO,MAAM,QAAQ,QAAe,MAAM,KAAG,OAAO,CAAC,IAAI,CAExD,CAAA;AAED,6DAA6D;AAC7D,eAAO,MAAM,UAAU,WAAY,cAAc,GAAG,IAAI,KAAG,OACf,CAAA;AAE5C;;;;;GAKG;AACH,eAAO,MAAM,QAAQ,QACd,MAAM,QAAO,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KACvC,OAAO,CAAC,kBAAkB,CA0B5B,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,WAAW,QAAe,MAAM,KAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAyBhF,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,WAAW,WAAkB,kBAAkB,GAAG,SAAS,KAAG,OAAO,CAAC,IAAI,CAUtF,CAAA;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,UAAU,QAAe,MAAM,KAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAYnE,CAAA;AAED,iEAAiE;AACjE,eAAO,MAAM,YAAY,UACjB,MAAM,KACX,OAAO,CAAC,OAAO,CAA+B,CAAA;AAEjD,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,kBAAkB,EAAE,CAAA"}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import { spawn } from 'node:child_process';
|
|
3
|
+
import { randomUUID } from 'node:crypto';
|
|
4
|
+
import p from 'node:path';
|
|
5
|
+
import { CONNECT_MARKER_DIR, CONNECT_RUN_FILE, TARGET_API_MARKER, TARGET_API_PORT, TARGET_WEB_PORT, TARGET_WORKER_MARKER, TARGET_WORKER_PORT } from '@owlmeans/viable-common';
|
|
6
|
+
import { backendEnv } from '../executor/env.js';
|
|
7
|
+
import { apiPath, hasWorker, workerPath } from '../executor/layout.js';
|
|
8
|
+
import { integrityRefusal } from '../executor/integrity.js';
|
|
9
|
+
import { isAlive, probeListening, reclaimPort, signalGroup, waitForPortFree } from '../executor/spawn.js';
|
|
10
|
+
const runFile = (dir) => p.join(dir, CONNECT_RUN_FILE);
|
|
11
|
+
export const readRun = async (dir) => {
|
|
12
|
+
const content = await fs.readFile(runFile(dir), 'utf-8').catch(() => null);
|
|
13
|
+
if (content == null)
|
|
14
|
+
return null;
|
|
15
|
+
try {
|
|
16
|
+
const parsed = JSON.parse(content);
|
|
17
|
+
return typeof parsed === 'object' && parsed !== null ? parsed : null;
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
export const writeRun = async (dir, record) => {
|
|
24
|
+
await fs.ensureDir(p.join(dir, CONNECT_MARKER_DIR));
|
|
25
|
+
await fs.writeFile(runFile(dir), `${JSON.stringify(record, null, 2)}\n`);
|
|
26
|
+
};
|
|
27
|
+
export const clearRun = async (dir) => {
|
|
28
|
+
await fs.rm(runFile(dir), { force: true }).catch(() => undefined);
|
|
29
|
+
};
|
|
30
|
+
/** Whether the api recorded here is still a live process. */
|
|
31
|
+
export const apiRunning = (record) => record != null && isAlive(record.api?.pid);
|
|
32
|
+
/**
|
|
33
|
+
* Start the target's HTTP server as a detached child.
|
|
34
|
+
*
|
|
35
|
+
* Detached so the whole group can be signalled later — the child is a shell wrapping `bun`, and a
|
|
36
|
+
* signal aimed at the shell alone leaves `bun` holding the port.
|
|
37
|
+
*/
|
|
38
|
+
export const startApi = async (dir, env = {}) => {
|
|
39
|
+
const bootId = randomUUID();
|
|
40
|
+
const cwd = apiPath(dir);
|
|
41
|
+
// A run killed without a stop leaves this child alive — detaching it is what keeps it
|
|
42
|
+
// running after the tool that started it exits. What survives holds the port, and the
|
|
43
|
+
// replacement then loses the bind and exits without announcing it.
|
|
44
|
+
if (!await waitForPortFree(TARGET_API_PORT, 2_000)) {
|
|
45
|
+
await reclaimPort(TARGET_API_PORT, TARGET_API_MARKER);
|
|
46
|
+
}
|
|
47
|
+
const child = spawn('bun', ['dist/index.js', TARGET_API_MARKER], {
|
|
48
|
+
cwd,
|
|
49
|
+
detached: true,
|
|
50
|
+
shell: true,
|
|
51
|
+
stdio: 'ignore',
|
|
52
|
+
env: {
|
|
53
|
+
...process.env,
|
|
54
|
+
...await backendEnv(dir),
|
|
55
|
+
BACKEND_PORT: `${TARGET_API_PORT}`,
|
|
56
|
+
BACKEND_BOOT_ID: bootId,
|
|
57
|
+
...env,
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
child.unref();
|
|
61
|
+
return { pid: child.pid ?? -1, port: TARGET_API_PORT, bootId };
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* Start the target's queue worker, when this tree has one.
|
|
65
|
+
*
|
|
66
|
+
* The SAME `dist/index.js` as the api, out of the same package tree — the argv marker is the only
|
|
67
|
+
* thing separating the two processes, which is why nothing may reclaim a port without excluding
|
|
68
|
+
* the other's marker. Most generated applications declare no queues, and their absence is not a
|
|
69
|
+
* degraded state.
|
|
70
|
+
*/
|
|
71
|
+
export const startWorker = async (dir) => {
|
|
72
|
+
if (!hasWorker(dir))
|
|
73
|
+
return null;
|
|
74
|
+
const cwd = workerPath(dir);
|
|
75
|
+
if (cwd == null)
|
|
76
|
+
return null;
|
|
77
|
+
const bootId = randomUUID();
|
|
78
|
+
const child = spawn('bun', ['dist/index.js', TARGET_WORKER_MARKER], {
|
|
79
|
+
cwd,
|
|
80
|
+
detached: true,
|
|
81
|
+
shell: true,
|
|
82
|
+
stdio: 'ignore',
|
|
83
|
+
env: {
|
|
84
|
+
...process.env,
|
|
85
|
+
...await backendEnv(dir),
|
|
86
|
+
// The target reads one "port I bind" variable and the worker binds its health port with it;
|
|
87
|
+
// `WORKER_PORT` travels beside it so a worker that grew its own variable finds it.
|
|
88
|
+
BACKEND_PORT: `${TARGET_WORKER_PORT}`,
|
|
89
|
+
WORKER_PORT: `${TARGET_WORKER_PORT}`,
|
|
90
|
+
BACKEND_BOOT_ID: bootId,
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
child.unref();
|
|
94
|
+
return { pid: child.pid ?? -1, port: TARGET_WORKER_PORT, bootId };
|
|
95
|
+
};
|
|
96
|
+
/**
|
|
97
|
+
* Stop a recorded process and wait for its port to actually free.
|
|
98
|
+
*
|
|
99
|
+
* The port and not the pid is what a replacement needs, so that is what is waited on.
|
|
100
|
+
*/
|
|
101
|
+
export const stopProcess = async (record) => {
|
|
102
|
+
if (record == null)
|
|
103
|
+
return;
|
|
104
|
+
if (isAlive(record.pid)) {
|
|
105
|
+
signalGroup(record.pid, 'SIGTERM');
|
|
106
|
+
if (!await waitForPortFree(record.port, 5_000)) {
|
|
107
|
+
signalGroup(record.pid, 'SIGKILL');
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
await waitForPortFree(record.port, 5_000);
|
|
111
|
+
};
|
|
112
|
+
/**
|
|
113
|
+
* Bounce the api child so it reconciles the target's tables against its code.
|
|
114
|
+
*
|
|
115
|
+
* What `DbSync` means for a target that owns its own structure: every `@owlmeans/postgres`
|
|
116
|
+
* resource creates and updates its table while the context initializes, so there is nothing to
|
|
117
|
+
* generate and no migration file to apply — the sync IS the restart. A tree with no run in front
|
|
118
|
+
* of it answers `null`: there is no process to bounce, and reporting that as a failure would send
|
|
119
|
+
* a caller after a repair that does not apply.
|
|
120
|
+
*/
|
|
121
|
+
export const restartApi = async (dir) => {
|
|
122
|
+
const record = await readRun(dir);
|
|
123
|
+
if (record == null || record.api == null)
|
|
124
|
+
return null;
|
|
125
|
+
const refused = await integrityRefusal(dir, 'Refused to restart');
|
|
126
|
+
if (refused != null)
|
|
127
|
+
return refused;
|
|
128
|
+
await stopProcess(record.api);
|
|
129
|
+
const api = await startApi(dir);
|
|
130
|
+
await writeRun(dir, { ...record, api });
|
|
131
|
+
return null;
|
|
132
|
+
};
|
|
133
|
+
/** Whether anything is answering on the api's port right now. */
|
|
134
|
+
export const apiListening = async (port = TARGET_API_PORT) => await probeListening(port);
|
|
135
|
+
export { TARGET_API_PORT, TARGET_WEB_PORT, TARGET_WORKER_PORT };
|
|
136
|
+
//# sourceMappingURL=state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/run/state.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ConnectSessionStatus } from '@owlmeans/viable-common';
|
|
2
|
+
import type { ConnectorApi, LocalExecutor, OpenSessionArgs, SessionRuntime } from '../types.js';
|
|
3
|
+
export interface SessionOptions {
|
|
4
|
+
api: ConnectorApi;
|
|
5
|
+
open: OpenSessionArgs;
|
|
6
|
+
/** Absent for a cloud target: the platform's own pod executes its commands. */
|
|
7
|
+
executor?: LocalExecutor;
|
|
8
|
+
/** Which deployment this is, recorded in the project's marker so a later connector finds it. */
|
|
9
|
+
apiUrl?: string;
|
|
10
|
+
log?: (line: string) => void;
|
|
11
|
+
}
|
|
12
|
+
export declare const openSession: (opts: SessionOptions) => Promise<SessionRuntime>;
|
|
13
|
+
export { ConnectSessionStatus };
|
|
14
|
+
export * from './queue.js';
|
|
15
|
+
export * from './tasks.js';
|
|
16
|
+
export * from './questions.js';
|
|
17
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/session/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAC8B,oBAAoB,EACxD,MAAM,yBAAyB,CAAA;AAMhC,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,eAAe,EAAE,cAAc,EAAgB,MAAM,aAAa,CAAA;AAM7G,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,YAAY,CAAA;IACjB,IAAI,EAAE,eAAe,CAAA;IACrB,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,aAAa,CAAA;IACxB,gGAAgG;IAChG,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;CAC7B;AAgDD,eAAO,MAAM,WAAW,SAAgB,cAAc,KAAG,OAAO,CAAC,cAAc,CA6L9E,CAAA;AAED,OAAO,EAAE,oBAAoB,EAAE,CAAA;AAC/B,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA;AAC1B,cAAc,gBAAgB,CAAA"}
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import { ConnectOpErrorKind, ConnectOpKind, ConnectSessionStatus } from '@owlmeans/viable-common';
|
|
2
|
+
import { PULL_WAIT_MS } from '../consts.js';
|
|
3
|
+
import { writeEnv } from '../project/env.js';
|
|
4
|
+
import { readMarker, writeMarker } from '../project/marker.js';
|
|
5
|
+
import { QuestionQueue } from './questions.js';
|
|
6
|
+
import { TaskQueue } from './tasks.js';
|
|
7
|
+
/**
|
|
8
|
+
* One attached connector, running.
|
|
9
|
+
*
|
|
10
|
+
* The loop is deliberately simple and deliberately serial: pull operations, answer them one at a
|
|
11
|
+
* time, put model tasks aside for the parent agent to drain. Serial because the thing on the other
|
|
12
|
+
* end of a local operation is a filesystem the platform believes it is the only writer of — two
|
|
13
|
+
* concurrent template writes into the same tree is not a throughput problem, it is a corrupted
|
|
14
|
+
* tree.
|
|
15
|
+
*
|
|
16
|
+
* Results are remembered by operation id. A connector that reconnects is handed everything still
|
|
17
|
+
* outstanding, including whatever it had already answered when the connection dropped, and
|
|
18
|
+
* re-executing a build or a model task because an acknowledgement was lost is exactly the cost
|
|
19
|
+
* this avoids.
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* Record which project a directory belongs to.
|
|
23
|
+
*
|
|
24
|
+
* Attaching a connector to a project IS the moment the directory becomes that project's, so it is
|
|
25
|
+
* the moment to say so on disk. Without it `attach_project` cannot find a project by its directory
|
|
26
|
+
* and a connector started here tomorrow has to be told again which project this is — the marker is
|
|
27
|
+
* read at startup for exactly that. It holds no secret and is meant to be committed.
|
|
28
|
+
*
|
|
29
|
+
* Best-effort: a session that works is worth more than a note about it, and the platform is the
|
|
30
|
+
* authority on what this project is either way.
|
|
31
|
+
*/
|
|
32
|
+
const recordMarker = async (opts, projectId) => {
|
|
33
|
+
const dir = opts.open.projectDir;
|
|
34
|
+
if (dir == null)
|
|
35
|
+
return;
|
|
36
|
+
try {
|
|
37
|
+
const existing = await readMarker(dir);
|
|
38
|
+
if (existing?.projectId === projectId)
|
|
39
|
+
return;
|
|
40
|
+
const status = await opts.api.project.status(projectId);
|
|
41
|
+
await writeMarker(dir, {
|
|
42
|
+
version: 1,
|
|
43
|
+
apiUrl: opts.apiUrl ?? '',
|
|
44
|
+
projectId,
|
|
45
|
+
slug: status.slot?.slug ?? status.project.alias,
|
|
46
|
+
createdAt: new Date().toISOString(),
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
catch (e) {
|
|
50
|
+
(opts.log ?? (() => undefined))(`could not record the project marker: ${e.message}`);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
export const openSession = async (opts) => {
|
|
54
|
+
const log = opts.log ?? (() => undefined);
|
|
55
|
+
const session = await opts.api.openSession(opts.open);
|
|
56
|
+
if (session.projectId != null)
|
|
57
|
+
await recordMarker(opts, session.projectId);
|
|
58
|
+
const tasks = new TaskQueue();
|
|
59
|
+
const questions = new QuestionQueue();
|
|
60
|
+
const answered = new Map();
|
|
61
|
+
const stats = {
|
|
62
|
+
opsDone: 0,
|
|
63
|
+
opsFailed: 0,
|
|
64
|
+
tasksDelivered: 0,
|
|
65
|
+
tasksSubmitted: 0,
|
|
66
|
+
questionsDelivered: 0,
|
|
67
|
+
questionsAnswered: 0,
|
|
68
|
+
lastActivityAt: Date.now(),
|
|
69
|
+
transport: 'pull',
|
|
70
|
+
};
|
|
71
|
+
let closed = false;
|
|
72
|
+
const submit = async (result) => {
|
|
73
|
+
answered.set(result.opId, result);
|
|
74
|
+
stats.lastActivityAt = Date.now();
|
|
75
|
+
try {
|
|
76
|
+
await opts.api.submitOp(session.id, result);
|
|
77
|
+
}
|
|
78
|
+
catch (e) {
|
|
79
|
+
// A lost acknowledgement is not a lost answer: the operation stays in the platform's store
|
|
80
|
+
// and is redelivered, and the cached result answers it without doing the work again.
|
|
81
|
+
log(`submit failed for ${result.opId}: ${e.message}`);
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
const perform = async (op) => {
|
|
85
|
+
const cached = answered.get(op.id);
|
|
86
|
+
if (cached != null) {
|
|
87
|
+
await submit(cached);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
if (op.kind === ConnectOpKind.ModelTask) {
|
|
91
|
+
// Not executed here at all — it is the parent agent's to run, in its own clean subagent.
|
|
92
|
+
// What this loop owes it is delivery and nothing else.
|
|
93
|
+
if (tasks.push(op.payload, op.id)) {
|
|
94
|
+
stats.tasksDelivered += 1;
|
|
95
|
+
stats.lastActivityAt = Date.now();
|
|
96
|
+
}
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
if (op.kind === ConnectOpKind.Inquiry) {
|
|
100
|
+
// Executed by nobody: it is a decision about the user's own project, and a connector that
|
|
101
|
+
// answered one itself would build a whole application on a guess nobody made. Queued for
|
|
102
|
+
// the parent agent to put to a person, exactly as a model task is queued for its subagent.
|
|
103
|
+
if (questions.push(op.payload, op.id)) {
|
|
104
|
+
stats.questionsDelivered += 1;
|
|
105
|
+
stats.lastActivityAt = Date.now();
|
|
106
|
+
}
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
try {
|
|
110
|
+
const value = op.kind === ConnectOpKind.Configure
|
|
111
|
+
? await writeEnv(requireExecutor().dir, op.payload)
|
|
112
|
+
: await requireExecutor().execute(op.payload);
|
|
113
|
+
stats.opsDone += 1;
|
|
114
|
+
await submit({ opId: op.id, sessionId: session.id, ok: true, value });
|
|
115
|
+
}
|
|
116
|
+
catch (e) {
|
|
117
|
+
stats.opsFailed += 1;
|
|
118
|
+
const error = e;
|
|
119
|
+
log(`operation ${op.id} failed: ${error.message}`);
|
|
120
|
+
await submit({
|
|
121
|
+
opId: op.id,
|
|
122
|
+
sessionId: session.id,
|
|
123
|
+
ok: false,
|
|
124
|
+
error: {
|
|
125
|
+
type: error.name,
|
|
126
|
+
message: error.message,
|
|
127
|
+
// A local failure is the connector's own — it ran and could not do the thing. Saying
|
|
128
|
+
// `Unavailable` here would tell the platform to give up on a run that is fine.
|
|
129
|
+
kind: ConnectOpErrorKind.Refused,
|
|
130
|
+
},
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
const requireExecutor = () => {
|
|
135
|
+
if (opts.executor == null) {
|
|
136
|
+
throw new Error('this session executes nothing locally — its target is a platform slot');
|
|
137
|
+
}
|
|
138
|
+
return opts.executor;
|
|
139
|
+
};
|
|
140
|
+
/**
|
|
141
|
+
* The pull loop.
|
|
142
|
+
*
|
|
143
|
+
* A long poll rather than a socket, as the first transport: it works through every proxy, needs
|
|
144
|
+
* no reconnection logic, and is the only option the URL-configured host has at all. The socket
|
|
145
|
+
* is an optimisation over it, not a replacement for it.
|
|
146
|
+
*/
|
|
147
|
+
const loop = async () => {
|
|
148
|
+
while (!closed) {
|
|
149
|
+
try {
|
|
150
|
+
const ops = await opts.api.pullOps(session.id, Math.floor(PULL_WAIT_MS / 1000));
|
|
151
|
+
stats.lastActivityAt = Date.now();
|
|
152
|
+
for (const op of ops) {
|
|
153
|
+
if (closed)
|
|
154
|
+
break;
|
|
155
|
+
await perform(op);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
catch (e) {
|
|
159
|
+
if (closed)
|
|
160
|
+
break;
|
|
161
|
+
log(`pull failed: ${e.message}`);
|
|
162
|
+
await new Promise(resolve => setTimeout(resolve, 2_000));
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
void loop();
|
|
167
|
+
return {
|
|
168
|
+
session,
|
|
169
|
+
stats,
|
|
170
|
+
nextTask: async (waitMs) => {
|
|
171
|
+
const task = await tasks.take(waitMs);
|
|
172
|
+
if (task != null)
|
|
173
|
+
stats.lastActivityAt = Date.now();
|
|
174
|
+
return task;
|
|
175
|
+
},
|
|
176
|
+
submitTask: async (result) => {
|
|
177
|
+
const opId = tasks.opIdOf(result.taskId);
|
|
178
|
+
if (opId == null) {
|
|
179
|
+
log(`no operation is waiting for task ${result.taskId}`);
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
tasks.settle(result.taskId);
|
|
183
|
+
stats.tasksSubmitted += 1;
|
|
184
|
+
await submit({ opId, sessionId: session.id, ok: true, value: result });
|
|
185
|
+
},
|
|
186
|
+
taskById: taskId => tasks.outstandingById(taskId),
|
|
187
|
+
outstandingTasks: () => tasks.outstandingTasks(),
|
|
188
|
+
pendingTasks: () => tasks.size(),
|
|
189
|
+
nextQuestion: async (waitMs) => {
|
|
190
|
+
const question = await questions.take(waitMs);
|
|
191
|
+
if (question != null)
|
|
192
|
+
stats.lastActivityAt = Date.now();
|
|
193
|
+
return question;
|
|
194
|
+
},
|
|
195
|
+
answerQuestion: async (answer) => {
|
|
196
|
+
const opId = questions.opIdOf(answer.inquiryId);
|
|
197
|
+
if (opId == null) {
|
|
198
|
+
// The question outlived its operation — the run parked and stopped waiting on this
|
|
199
|
+
// session. The answer is not lost: it is sent by id through `connect.inquiry.answer`,
|
|
200
|
+
// which is the caller's fallback and the reason this reports rather than throws.
|
|
201
|
+
log(`no operation is waiting for question ${answer.inquiryId}`);
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
questions.settle(answer.inquiryId);
|
|
205
|
+
stats.questionsAnswered += 1;
|
|
206
|
+
await submit({ opId, sessionId: session.id, ok: true, value: answer });
|
|
207
|
+
},
|
|
208
|
+
questionById: inquiryId => questions.outstandingById(inquiryId),
|
|
209
|
+
outstandingQuestions: () => questions.outstandingQuestions(),
|
|
210
|
+
pendingQuestions: () => questions.size(),
|
|
211
|
+
close: async () => {
|
|
212
|
+
closed = true;
|
|
213
|
+
try {
|
|
214
|
+
await opts.api.closeSession(session.id);
|
|
215
|
+
}
|
|
216
|
+
catch (e) {
|
|
217
|
+
log(`close failed: ${e.message}`);
|
|
218
|
+
}
|
|
219
|
+
},
|
|
220
|
+
};
|
|
221
|
+
};
|
|
222
|
+
export { ConnectSessionStatus };
|
|
223
|
+
export * from './queue.js';
|
|
224
|
+
export * from './tasks.js';
|
|
225
|
+
export * from './questions.js';
|
|
226
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/session/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { InquiryPayload } from '@owlmeans/viable-common';
|
|
2
|
+
import { OpQueue } from './queue.js';
|
|
3
|
+
/**
|
|
4
|
+
* Questions waiting for the person the parent agent is working for.
|
|
5
|
+
*
|
|
6
|
+
* The same queue as the model tasks, and deliberately a SEPARATE one: a question outranks a task
|
|
7
|
+
* because a person is slower than a subagent, and a parent draining one list would hand a question
|
|
8
|
+
* to a subagent — which is precisely the outcome the whole primitive exists to prevent. Nothing
|
|
9
|
+
* here executes anything: a question is delivered, and its answer comes back through the tool the
|
|
10
|
+
* parent calls after asking.
|
|
11
|
+
*/
|
|
12
|
+
export declare class QuestionQueue extends OpQueue<InquiryPayload> {
|
|
13
|
+
/** Put to the parent and still unanswered, oldest first. */
|
|
14
|
+
outstandingQuestions(): InquiryPayload[];
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=questions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"questions.d.ts","sourceRoot":"","sources":["../../src/session/questions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA;AAE7D,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAEpC;;;;;;;;GAQG;AACH,qBAAa,aAAc,SAAQ,OAAO,CAAC,cAAc,CAAC;IACxD,4DAA4D;IAC5D,oBAAoB,IAAI,cAAc,EAAE,CAEvC;CACF"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { OpQueue } from './queue.js';
|
|
2
|
+
/**
|
|
3
|
+
* Questions waiting for the person the parent agent is working for.
|
|
4
|
+
*
|
|
5
|
+
* The same queue as the model tasks, and deliberately a SEPARATE one: a question outranks a task
|
|
6
|
+
* because a person is slower than a subagent, and a parent draining one list would hand a question
|
|
7
|
+
* to a subagent — which is precisely the outcome the whole primitive exists to prevent. Nothing
|
|
8
|
+
* here executes anything: a question is delivered, and its answer comes back through the tool the
|
|
9
|
+
* parent calls after asking.
|
|
10
|
+
*/
|
|
11
|
+
export class QuestionQueue extends OpQueue {
|
|
12
|
+
/** Put to the parent and still unanswered, oldest first. */
|
|
13
|
+
outstandingQuestions() {
|
|
14
|
+
return this.outstanding();
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=questions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"questions.js","sourceRoot":"","sources":["../../src/session/questions.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAEpC;;;;;;;;GAQG;AACH,MAAM,OAAO,aAAc,SAAQ,OAAuB;IACxD,4DAA4D;IAC5D,oBAAoB;QAClB,OAAO,IAAI,CAAC,WAAW,EAAE,CAAA;IAC3B,CAAC;CACF"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Operations waiting for the parent agent — the model calls it performs, and the questions it
|
|
3
|
+
* puts to a person.
|
|
4
|
+
*
|
|
5
|
+
* A queue rather than a callback because of who drains it: the parent agent asks for work when it
|
|
6
|
+
* is ready, through a tool call, and may take minutes to answer. Nothing here pushes — the whole
|
|
7
|
+
* point of the local-LLM mode is that the platform waits on somebody else's schedule, and a
|
|
8
|
+
* question waits on a slower schedule still.
|
|
9
|
+
*
|
|
10
|
+
* Generic over the payload rather than copied per kind: both of them are handed out once, both are
|
|
11
|
+
* redelivered by the platform until they are answered, and both route their answer back on an
|
|
12
|
+
* operation id. A second copy of these rules is a second place for the redelivery guard to be
|
|
13
|
+
* forgotten, and the symptom of forgetting it is real model calls paid for and thrown away.
|
|
14
|
+
*
|
|
15
|
+
* The operation id is kept beside each item and never shown to the parent. It is what an answer is
|
|
16
|
+
* routed back on, and a parent that could name one could answer an operation it was never given.
|
|
17
|
+
*/
|
|
18
|
+
export declare class OpQueue<T extends {
|
|
19
|
+
id: string;
|
|
20
|
+
}> {
|
|
21
|
+
private readonly queue;
|
|
22
|
+
private readonly ops;
|
|
23
|
+
/**
|
|
24
|
+
* Every item this session has ever been handed.
|
|
25
|
+
*
|
|
26
|
+
* The platform redelivers an operation on every poll until it is answered — that is what makes a
|
|
27
|
+
* connector restart cost a round trip instead of a run. A model task takes a parent agent tens of
|
|
28
|
+
* seconds to answer, so without this the queue grew one copy per poll for the whole time it was
|
|
29
|
+
* being answered, and the parent then ran the same task over and over: real model calls, paid
|
|
30
|
+
* for, thrown away. Kept after settling too, so a redelivery that raced the platform's deletion
|
|
31
|
+
* is ignored rather than answered a second time.
|
|
32
|
+
*/
|
|
33
|
+
private readonly seen;
|
|
34
|
+
/**
|
|
35
|
+
* Handed out and not yet answered. An answer is checked against the item that asked for it.
|
|
36
|
+
*
|
|
37
|
+
* Named `held` rather than `outstanding` so the public reading of it can carry that name: the
|
|
38
|
+
* two subclasses expose it as `outstandingTasks()` / `outstandingQuestions()`, and a field and
|
|
39
|
+
* a method cannot share one name.
|
|
40
|
+
*/
|
|
41
|
+
private readonly held;
|
|
42
|
+
private readonly waiting;
|
|
43
|
+
/** @returns whether the item was accepted — `false` for a redelivery of one already handed over. */
|
|
44
|
+
push(item: T, opId: string): boolean;
|
|
45
|
+
/** The next item, or null once `waitMs` elapses. Never rejects: nothing to do is not a failure. */
|
|
46
|
+
take(waitMs: number): Promise<T | null>;
|
|
47
|
+
opIdOf(id: string): string | null;
|
|
48
|
+
outstandingById(id: string): T | null;
|
|
49
|
+
/** Handed out and still unanswered, oldest first. */
|
|
50
|
+
outstanding(): T[];
|
|
51
|
+
settle(id: string): void;
|
|
52
|
+
size(): number;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=queue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queue.d.ts","sourceRoot":"","sources":["../../src/session/queue.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,OAAO,CAAC,CAAC,SAAS;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE;IAC3C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAU;IAChC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAA4B;IAChD;;;;;;;;;OASG;IACH,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAoB;IACzC;;;;;;OAMG;IACH,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAuB;IAC5C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAwB;IAEhD,oGAAoG;IACpG,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAgBnC;IAED,mGAAmG;IAC7F,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAuB5C;IAED,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAEhC;IAED,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI,CAEpC;IAED,qDAAqD;IACrD,WAAW,IAAI,CAAC,EAAE,CAEjB;IAED,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAGvB;IAED,IAAI,IAAI,MAAM,CAEb;CACF"}
|