backlot 0.4.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/LICENSE +202 -0
- package/README.md +106 -0
- package/dist/cli/client.d.ts +22 -0
- package/dist/cli/client.js +83 -0
- package/dist/cli/client.js.map +1 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +308 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/core/events.d.ts +10 -0
- package/dist/core/events.js +42 -0
- package/dist/core/events.js.map +1 -0
- package/dist/core/journal.d.ts +80 -0
- package/dist/core/journal.js +186 -0
- package/dist/core/journal.js.map +1 -0
- package/dist/core/manifest.d.ts +76 -0
- package/dist/core/manifest.js +46 -0
- package/dist/core/manifest.js.map +1 -0
- package/dist/core/paths.d.ts +17 -0
- package/dist/core/paths.js +32 -0
- package/dist/core/paths.js.map +1 -0
- package/dist/core/policy.d.ts +15 -0
- package/dist/core/policy.js +45 -0
- package/dist/core/policy.js.map +1 -0
- package/dist/core/ports.d.ts +3 -0
- package/dist/core/ports.js +22 -0
- package/dist/core/ports.js.map +1 -0
- package/dist/core/retention.d.ts +19 -0
- package/dist/core/retention.js +101 -0
- package/dist/core/retention.js.map +1 -0
- package/dist/core/sync.d.ts +15 -0
- package/dist/core/sync.js +150 -0
- package/dist/core/sync.js.map +1 -0
- package/dist/core/types.d.ts +82 -0
- package/dist/core/types.js +6 -0
- package/dist/core/types.js.map +1 -0
- package/dist/core/upkeep.d.ts +11 -0
- package/dist/core/upkeep.js +47 -0
- package/dist/core/upkeep.js.map +1 -0
- package/dist/core/util.d.ts +36 -0
- package/dist/core/util.js +100 -0
- package/dist/core/util.js.map +1 -0
- package/dist/daemon/engine.d.ts +284 -0
- package/dist/daemon/engine.js +858 -0
- package/dist/daemon/engine.js.map +1 -0
- package/dist/daemon/index.d.ts +2 -0
- package/dist/daemon/index.js +183 -0
- package/dist/daemon/index.js.map +1 -0
- package/dist/daemon/supervisor.d.ts +36 -0
- package/dist/daemon/supervisor.js +189 -0
- package/dist/daemon/supervisor.js.map +1 -0
- package/dist/drivers/datastore-sqlite.d.ts +27 -0
- package/dist/drivers/datastore-sqlite.js +83 -0
- package/dist/drivers/datastore-sqlite.js.map +1 -0
- package/dist/drivers/datastores.d.ts +22 -0
- package/dist/drivers/datastores.js +190 -0
- package/dist/drivers/datastores.js.map +1 -0
- package/dist/drivers/types.d.ts +71 -0
- package/dist/drivers/types.js +14 -0
- package/dist/drivers/types.js.map +1 -0
- package/dist/mcp/index.d.ts +2 -0
- package/dist/mcp/index.js +144 -0
- package/dist/mcp/index.js.map +1 -0
- package/package.json +57 -0
- package/schema/stack.schema.json +172 -0
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* backlot CLI. Contract: every verb accepts --json (stdout = data, stderr =
|
|
4
|
+
* human); exit codes are contractual — 0 ok, 1 work-error, 2 env-error,
|
|
5
|
+
* 3 infra-error, 64 usage. See docs/architecture.md §11.
|
|
6
|
+
*/
|
|
7
|
+
import { ensureDaemon, rpc } from './client.js';
|
|
8
|
+
const USAGE = `backlot — puts a working instance of a web application in front of you.
|
|
9
|
+
|
|
10
|
+
Usage:
|
|
11
|
+
backlot up [--watch] [--reset-data|--pristine] [--ttl <minutes>]
|
|
12
|
+
session lease: sync, upkeep, start services, print context
|
|
13
|
+
backlot run <check> [--pristine] [--pull] [--detach]
|
|
14
|
+
run lease: bind -> execute the check -> verdict -> release
|
|
15
|
+
--detach: submit-and-poll — returns a jobId immediately
|
|
16
|
+
backlot job <jobId> poll a detached run (pending|running|done + verdict)
|
|
17
|
+
backlot ctx the consumer context blob (URLs, logins, conn strings)
|
|
18
|
+
backlot sync project the worktree state into the current lease
|
|
19
|
+
backlot exec <cmd...> run a command inside the leased environment
|
|
20
|
+
backlot logs <service> [--lines N]
|
|
21
|
+
backlot reset-data restore the data template on the current lease
|
|
22
|
+
backlot token --role <r> mint an auth token via the stack's auth.token hook
|
|
23
|
+
backlot pull copy declared outputs back into the worktree
|
|
24
|
+
backlot release release the current lease (environment stays warm)
|
|
25
|
+
backlot status daemon, pool, and lease overview
|
|
26
|
+
backlot pool ls|recycle [--all]
|
|
27
|
+
backlot daemon stop stop the daemon (environments are recovered on next use)
|
|
28
|
+
|
|
29
|
+
Every verb accepts --json. Long verbs (up/run/sync/bind/reset-data) show live progress
|
|
30
|
+
on a terminal (stderr); force with --progress, silence with --quiet. stdout stays clean.
|
|
31
|
+
Exit codes: 0 ok · 1 work-error · 2 env-error · 3 infra-error · 64 usage.`;
|
|
32
|
+
const rawArgv = process.argv.slice(2);
|
|
33
|
+
const verb = rawArgv[0];
|
|
34
|
+
// Known flags and whether each takes a value. A proper single-pass parser so a
|
|
35
|
+
// flag's value is never mis-bound as a positional (and an inner command's own
|
|
36
|
+
// flags survive) — the F1 class of argv bugs. Everything after a lone `--`, and
|
|
37
|
+
// EVERYTHING for `exec`, is treated as a raw passthrough command.
|
|
38
|
+
const VALUE_FLAGS = new Set(['--holder', '--ttl', '--role', '--lines', '--ref', '--spec', '--preset']);
|
|
39
|
+
const BOOL_FLAGS = new Set(['--json', '--watch', '--reset-data', '--pristine', '--pull', '--detach', '--all', '--raw', '--progress', '--quiet']);
|
|
40
|
+
const flagVals = new Map();
|
|
41
|
+
const flags = new Set();
|
|
42
|
+
const positional = [];
|
|
43
|
+
let passthrough = null; // for `exec` / after `--`
|
|
44
|
+
{
|
|
45
|
+
const body = rawArgv.slice(1);
|
|
46
|
+
for (let i = 0; i < body.length; i++) {
|
|
47
|
+
const a = body[i];
|
|
48
|
+
// `exec` consumes the entire remainder verbatim (its own flags included),
|
|
49
|
+
// except a leading `--json` which is ours; `--` also opens passthrough.
|
|
50
|
+
if (verb === 'exec' && passthrough === null && a !== '--json' && !a.startsWith('--')) {
|
|
51
|
+
passthrough = body.slice(i);
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
if (a === '--') {
|
|
55
|
+
passthrough = body.slice(i + 1);
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
if (VALUE_FLAGS.has(a)) {
|
|
59
|
+
const v = body[i + 1];
|
|
60
|
+
if (v === undefined) {
|
|
61
|
+
console.error(`backlot: ${a} needs a value`);
|
|
62
|
+
process.exit(64);
|
|
63
|
+
}
|
|
64
|
+
flagVals.set(a, v);
|
|
65
|
+
i++;
|
|
66
|
+
}
|
|
67
|
+
else if (BOOL_FLAGS.has(a)) {
|
|
68
|
+
flags.add(a);
|
|
69
|
+
}
|
|
70
|
+
else if (a.startsWith('--')) {
|
|
71
|
+
console.error(`backlot: unknown flag '${a}'`);
|
|
72
|
+
process.exit(64);
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
positional.push(a);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
const json = flags.has('--json');
|
|
80
|
+
const flagValue = (name) => flagVals.get(name);
|
|
81
|
+
const out = (data) => console.log(json ? JSON.stringify(data, null, json ? 0 : 2) : humanize(data));
|
|
82
|
+
const errExit = (e) => {
|
|
83
|
+
const code = e.class === 'work-error' ? 1 : e.class === 'infra-error' ? 3 : 2;
|
|
84
|
+
if (json)
|
|
85
|
+
console.log(JSON.stringify({ ok: false, error: e }));
|
|
86
|
+
else {
|
|
87
|
+
console.error(`backlot: [${e.class ?? e.code ?? 'error'}] ${e.message}${e.source ? ` (${e.source})` : ''}`);
|
|
88
|
+
if (e.logExcerpt)
|
|
89
|
+
console.error(`--- log excerpt ---\n${e.logExcerpt}`);
|
|
90
|
+
}
|
|
91
|
+
process.exit(code);
|
|
92
|
+
};
|
|
93
|
+
function humanize(data) {
|
|
94
|
+
return JSON.stringify(data, null, 2);
|
|
95
|
+
}
|
|
96
|
+
// Progress -> stderr, shown for humans (a TTY) or on --progress; --quiet forces
|
|
97
|
+
// off. Never touches stdout, so the --json payload stays clean for agents.
|
|
98
|
+
const showProgress = flags.has('--progress') || (process.stderr.isTTY === true && !flags.has('--quiet') && !flags.has('--json'));
|
|
99
|
+
let lastProgressLen = 0;
|
|
100
|
+
const progress = showProgress
|
|
101
|
+
? (phase) => {
|
|
102
|
+
const line = ` ⋯ ${phase}`;
|
|
103
|
+
// Redraw in place on a TTY so the phase log stays a single moving line.
|
|
104
|
+
if (process.stderr.isTTY) {
|
|
105
|
+
process.stderr.write(`\r${line}${' '.repeat(Math.max(0, lastProgressLen - line.length))}`);
|
|
106
|
+
lastProgressLen = line.length;
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
process.stderr.write(line + '\n');
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
: undefined;
|
|
113
|
+
const endProgress = () => {
|
|
114
|
+
if (showProgress && process.stderr.isTTY && lastProgressLen)
|
|
115
|
+
process.stderr.write('\r' + ' '.repeat(lastProgressLen) + '\r');
|
|
116
|
+
};
|
|
117
|
+
/** --ttl is in MINUTES; accepts a bare number or an explicit `<n>m`. Returns ms or undefined if invalid. */
|
|
118
|
+
function parseTtlMinutes(v) {
|
|
119
|
+
const m = /^(\d+(?:\.\d+)?)m?$/.exec(v.trim());
|
|
120
|
+
if (!m)
|
|
121
|
+
return undefined;
|
|
122
|
+
const mins = Number(m[1]);
|
|
123
|
+
if (!Number.isFinite(mins) || mins <= 0)
|
|
124
|
+
return undefined;
|
|
125
|
+
return mins * 60_000;
|
|
126
|
+
}
|
|
127
|
+
function hygiene() {
|
|
128
|
+
if (flags.has('--pristine'))
|
|
129
|
+
return 'pristine';
|
|
130
|
+
if (flags.has('--reset-data'))
|
|
131
|
+
return 'reset-data';
|
|
132
|
+
return undefined;
|
|
133
|
+
}
|
|
134
|
+
async function main() {
|
|
135
|
+
if (!verb || verb === 'help' || verb === '--help' || verb === '-h') {
|
|
136
|
+
console.log(USAGE);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
const known = ['up', 'run', 'job', 'ctx', 'sync', 'bind', 'exec', 'logs', 'token', 'reset-data', 'pull', 'release', 'status', 'doctor', 'pool', 'daemon'];
|
|
140
|
+
if (!known.includes(verb)) {
|
|
141
|
+
console.error(`backlot: unknown verb '${verb}'\n\n${USAGE}`);
|
|
142
|
+
process.exit(64);
|
|
143
|
+
}
|
|
144
|
+
await ensureDaemon();
|
|
145
|
+
const cwd = process.cwd();
|
|
146
|
+
const holder = flagValue('--holder');
|
|
147
|
+
let res;
|
|
148
|
+
switch (verb) {
|
|
149
|
+
case 'up': {
|
|
150
|
+
const ttl = flagValue('--ttl');
|
|
151
|
+
let ttlMs;
|
|
152
|
+
if (ttl !== undefined) {
|
|
153
|
+
ttlMs = parseTtlMinutes(ttl);
|
|
154
|
+
if (ttlMs === undefined) {
|
|
155
|
+
console.error(`backlot: --ttl expects minutes (a positive number), got '${ttl}'`);
|
|
156
|
+
process.exit(64);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
res = await rpc('up', { cwd, holder, hygiene: hygiene(), watch: flags.has('--watch'), ttlMs }, progress);
|
|
160
|
+
endProgress();
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
case 'run': {
|
|
164
|
+
const check = positional[0];
|
|
165
|
+
if (!check) {
|
|
166
|
+
console.error(`backlot run: which check? (usage: backlot run <check>)`);
|
|
167
|
+
process.exit(64);
|
|
168
|
+
}
|
|
169
|
+
if (flags.has('--detach')) {
|
|
170
|
+
res = await rpc('run-detach', { cwd, holder, check, hygiene: hygiene() });
|
|
171
|
+
if (res.ok) {
|
|
172
|
+
out(res.data);
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
res = await rpc('run', { cwd, holder, check, hygiene: hygiene() }, progress);
|
|
178
|
+
endProgress();
|
|
179
|
+
if (res.ok && flags.has('--pull'))
|
|
180
|
+
await rpc('pull', { cwd, holder });
|
|
181
|
+
}
|
|
182
|
+
break;
|
|
183
|
+
}
|
|
184
|
+
case 'job': {
|
|
185
|
+
const jobId = positional[0];
|
|
186
|
+
if (!jobId) {
|
|
187
|
+
console.error('backlot job: which job? (usage: backlot job <jobId> | backlot job ls)');
|
|
188
|
+
process.exit(64);
|
|
189
|
+
}
|
|
190
|
+
res = jobId === 'ls' ? await rpc('job-ls', {}) : await rpc('job', { jobId });
|
|
191
|
+
break;
|
|
192
|
+
}
|
|
193
|
+
case 'ctx':
|
|
194
|
+
res = await rpc('ctx', { cwd, holder });
|
|
195
|
+
break;
|
|
196
|
+
case 'sync':
|
|
197
|
+
res = await rpc('sync', { cwd, holder }, progress);
|
|
198
|
+
endProgress();
|
|
199
|
+
break;
|
|
200
|
+
case 'bind': {
|
|
201
|
+
const ref = flagValue('--ref');
|
|
202
|
+
res = ref ? await rpc('bind-ref', { cwd, holder, ref }, progress) : await rpc('sync', { cwd, holder }, progress);
|
|
203
|
+
endProgress();
|
|
204
|
+
break;
|
|
205
|
+
}
|
|
206
|
+
case 'exec': {
|
|
207
|
+
// The whole passthrough is the command, verbatim — its own --flags intact.
|
|
208
|
+
const cmd = (passthrough ?? positional).join(' ');
|
|
209
|
+
if (!cmd) {
|
|
210
|
+
console.error('backlot exec: no command given');
|
|
211
|
+
process.exit(64);
|
|
212
|
+
}
|
|
213
|
+
res = await rpc('exec', { cwd, holder, cmd });
|
|
214
|
+
if (res.ok) {
|
|
215
|
+
const d = res.data;
|
|
216
|
+
if (json)
|
|
217
|
+
console.log(JSON.stringify({ ok: d.exitCode === 0, ...d }));
|
|
218
|
+
else {
|
|
219
|
+
if (d.stdout)
|
|
220
|
+
process.stdout.write(d.stdout);
|
|
221
|
+
if (d.stderr)
|
|
222
|
+
process.stderr.write(d.stderr);
|
|
223
|
+
}
|
|
224
|
+
process.exit(d.exitCode === 0 ? 0 : 1);
|
|
225
|
+
}
|
|
226
|
+
break;
|
|
227
|
+
}
|
|
228
|
+
case 'logs': {
|
|
229
|
+
const service = positional[0];
|
|
230
|
+
if (!service) {
|
|
231
|
+
console.error('backlot logs: which service?');
|
|
232
|
+
process.exit(64);
|
|
233
|
+
}
|
|
234
|
+
res = await rpc('logs', { cwd, holder, service, lines: Number(flagValue('--lines') ?? 40) });
|
|
235
|
+
if (res.ok && !json) {
|
|
236
|
+
console.log(res.data.lines);
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
break;
|
|
240
|
+
}
|
|
241
|
+
case 'reset-data':
|
|
242
|
+
res = await rpc('reset-data', { cwd, holder }, progress);
|
|
243
|
+
endProgress();
|
|
244
|
+
break;
|
|
245
|
+
case 'token':
|
|
246
|
+
res = await rpc('token', { cwd, holder, role: flagValue('--role') ?? 'admin' });
|
|
247
|
+
break;
|
|
248
|
+
case 'pull':
|
|
249
|
+
res = await rpc('pull', { cwd, holder });
|
|
250
|
+
break;
|
|
251
|
+
case 'release':
|
|
252
|
+
res = await rpc('release', { cwd, holder });
|
|
253
|
+
break;
|
|
254
|
+
case 'status':
|
|
255
|
+
res = await rpc('status', {});
|
|
256
|
+
break;
|
|
257
|
+
case 'doctor':
|
|
258
|
+
res = await rpc('doctor', {});
|
|
259
|
+
break;
|
|
260
|
+
case 'pool': {
|
|
261
|
+
const sub = positional[0] ?? 'ls';
|
|
262
|
+
if (sub === 'ls')
|
|
263
|
+
res = await rpc('status', {});
|
|
264
|
+
else if (sub === 'recycle')
|
|
265
|
+
res = await rpc('pool-recycle', { all: flags.has('--all') });
|
|
266
|
+
else if (sub === 'reconcile')
|
|
267
|
+
res = await rpc('pool-reconcile', {});
|
|
268
|
+
else if (sub === 'doctor')
|
|
269
|
+
res = await rpc('doctor', {});
|
|
270
|
+
else {
|
|
271
|
+
console.error(`backlot pool: unknown subcommand '${sub}' (ls | recycle | reconcile | doctor)`);
|
|
272
|
+
process.exit(64);
|
|
273
|
+
}
|
|
274
|
+
break;
|
|
275
|
+
}
|
|
276
|
+
case 'daemon': {
|
|
277
|
+
if (positional[0] !== 'stop') {
|
|
278
|
+
console.error('backlot daemon: only `stop` is supported');
|
|
279
|
+
process.exit(64);
|
|
280
|
+
}
|
|
281
|
+
res = await rpc('shutdown', {});
|
|
282
|
+
break;
|
|
283
|
+
}
|
|
284
|
+
default:
|
|
285
|
+
process.exit(64);
|
|
286
|
+
}
|
|
287
|
+
if (!res)
|
|
288
|
+
process.exit(0);
|
|
289
|
+
if (!res.ok) {
|
|
290
|
+
errExit(res.error);
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
if (verb === 'run') {
|
|
294
|
+
const v = res.data;
|
|
295
|
+
out(res.data);
|
|
296
|
+
process.exit(v.ok ? 0 : 1);
|
|
297
|
+
}
|
|
298
|
+
out(res.data);
|
|
299
|
+
}
|
|
300
|
+
main().catch((err) => {
|
|
301
|
+
const msg = String(err.message ?? err);
|
|
302
|
+
if (json)
|
|
303
|
+
console.log(JSON.stringify({ ok: false, error: { class: 'env-error', message: msg } }));
|
|
304
|
+
else
|
|
305
|
+
console.error(`backlot: ${msg}`);
|
|
306
|
+
process.exit(2);
|
|
307
|
+
});
|
|
308
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type EventLevel = 'info' | 'warn' | 'error';
|
|
2
|
+
export interface DaemonEvent {
|
|
3
|
+
at: number;
|
|
4
|
+
level: EventLevel;
|
|
5
|
+
kind: string;
|
|
6
|
+
envId?: string;
|
|
7
|
+
detail?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function logEvent(e: Omit<DaemonEvent, 'at'>): void;
|
|
10
|
+
export declare function recentEvents(limit?: number): DaemonEvent[];
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured daemon event log (task: observability). Failures used to vanish
|
|
3
|
+
* into swallowed catches; this makes them visible. Append-only JSONL under the
|
|
4
|
+
* state dir, size-capped in place, read back by `status`/`doctor`.
|
|
5
|
+
*/
|
|
6
|
+
import { appendFileSync, readFileSync, statSync, writeFileSync } from 'node:fs';
|
|
7
|
+
import { join } from 'node:path';
|
|
8
|
+
import { stateRoot } from './paths.js';
|
|
9
|
+
const logPath = () => join(stateRoot(), 'events.jsonl');
|
|
10
|
+
const CAP = 512 * 1024;
|
|
11
|
+
export function logEvent(e) {
|
|
12
|
+
const line = JSON.stringify({ at: Date.now(), ...e }) + '\n';
|
|
13
|
+
try {
|
|
14
|
+
const p = logPath();
|
|
15
|
+
try {
|
|
16
|
+
if (statSync(p).size > CAP) {
|
|
17
|
+
const kept = readFileSync(p, 'utf8').split('\n').slice(-500).join('\n');
|
|
18
|
+
writeFileSync(p, kept);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
/* no file yet */
|
|
23
|
+
}
|
|
24
|
+
appendFileSync(p, line);
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
/* logging must never throw into a caller */
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export function recentEvents(limit = 30) {
|
|
31
|
+
try {
|
|
32
|
+
return readFileSync(logPath(), 'utf8')
|
|
33
|
+
.split('\n')
|
|
34
|
+
.filter(Boolean)
|
|
35
|
+
.slice(-limit)
|
|
36
|
+
.map((l) => JSON.parse(l));
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return [];
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/core/events.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAChF,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAWvC,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,cAAc,CAAC,CAAC;AACxD,MAAM,GAAG,GAAG,GAAG,GAAG,IAAI,CAAC;AAEvB,MAAM,UAAU,QAAQ,CAAC,CAA0B;IACjD,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC;IAC7D,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,OAAO,EAAE,CAAC;QACpB,IAAI,CAAC;YACH,IAAI,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,GAAG,EAAE,CAAC;gBAC3B,MAAM,IAAI,GAAG,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACxE,aAAa,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;YACzB,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,iBAAiB;QACnB,CAAC;QACD,cAAc,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,4CAA4C;IAC9C,CAAC;AACH,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,KAAK,GAAG,EAAE;IACrC,IAAI,CAAC;QACH,OAAO,YAAY,CAAC,OAAO,EAAE,EAAE,MAAM,CAAC;aACnC,KAAK,CAAC,IAAI,CAAC;aACX,MAAM,CAAC,OAAO,CAAC;aACf,KAAK,CAAC,CAAC,KAAK,CAAC;aACb,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAgB,CAAC,CAAC;IAC9C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { EnvState, Hygiene, LeaseKind } from './types.js';
|
|
2
|
+
export interface EnvRow {
|
|
3
|
+
id: string;
|
|
4
|
+
stack: string;
|
|
5
|
+
stackRoot: string;
|
|
6
|
+
state: EnvState;
|
|
7
|
+
root: string;
|
|
8
|
+
ports: Record<string, number>;
|
|
9
|
+
datastoreNs: Record<string, string>;
|
|
10
|
+
fingerprints: Record<string, string>;
|
|
11
|
+
presets: Record<string, string>;
|
|
12
|
+
bindCount: number;
|
|
13
|
+
createdAt: number;
|
|
14
|
+
lastUsedAt: number;
|
|
15
|
+
servicePids: Record<string, number>;
|
|
16
|
+
/** Consecutive bind failures — >= 2 auto-escalates the next bind to pristine (decision 0007). */
|
|
17
|
+
failStreak: number;
|
|
18
|
+
}
|
|
19
|
+
export interface LeaseRow {
|
|
20
|
+
id: string;
|
|
21
|
+
envId: string;
|
|
22
|
+
kind: LeaseKind;
|
|
23
|
+
holder: string;
|
|
24
|
+
hygiene: Hygiene;
|
|
25
|
+
expiresAt: number;
|
|
26
|
+
}
|
|
27
|
+
export declare class Journal {
|
|
28
|
+
private db;
|
|
29
|
+
constructor(path?: string);
|
|
30
|
+
private rowToEnv;
|
|
31
|
+
saveEnv(e: EnvRow): void;
|
|
32
|
+
getEnv(id: string): EnvRow | undefined;
|
|
33
|
+
envsForStack(stack: string): EnvRow[];
|
|
34
|
+
allEnvs(): EnvRow[];
|
|
35
|
+
deleteEnv(id: string): void;
|
|
36
|
+
/**
|
|
37
|
+
* A per-stack env sequence that NEVER reuses a number, even after envs are
|
|
38
|
+
* reaped — so a recycled env's id can't collide with a live one. Monotonic
|
|
39
|
+
* in the journal, survives daemon restarts.
|
|
40
|
+
*/
|
|
41
|
+
nextEnvSeq(stack: string): number;
|
|
42
|
+
/** Update just the recorded service pids (auto-restart keeps recovery honest). */
|
|
43
|
+
updateServicePids(id: string, pids: Record<string, number>): void;
|
|
44
|
+
saveLease(l: LeaseRow): void;
|
|
45
|
+
private rowToLease;
|
|
46
|
+
leaseForHolder(holder: string, stack: string): LeaseRow | undefined;
|
|
47
|
+
leaseForEnv(envId: string): LeaseRow | undefined;
|
|
48
|
+
allLeases(): LeaseRow[];
|
|
49
|
+
deleteLease(id: string): void;
|
|
50
|
+
saveJob(job: {
|
|
51
|
+
id: string;
|
|
52
|
+
stackCwd: string;
|
|
53
|
+
check: string;
|
|
54
|
+
state: string;
|
|
55
|
+
verdict?: unknown;
|
|
56
|
+
finishedAt?: number;
|
|
57
|
+
}): void;
|
|
58
|
+
getJob(id: string): {
|
|
59
|
+
id: string;
|
|
60
|
+
check: string;
|
|
61
|
+
state: string;
|
|
62
|
+
verdict: unknown;
|
|
63
|
+
createdAt: number;
|
|
64
|
+
finishedAt: number | null;
|
|
65
|
+
} | undefined;
|
|
66
|
+
listJobs(limit?: number): Array<{
|
|
67
|
+
id: string;
|
|
68
|
+
check: string;
|
|
69
|
+
state: string;
|
|
70
|
+
ok: boolean | null;
|
|
71
|
+
createdAt: number;
|
|
72
|
+
finishedAt: number | null;
|
|
73
|
+
}>;
|
|
74
|
+
/** Recovery: a job left 'running'/'pending' by a dead daemon can never finish. */
|
|
75
|
+
failStaleJobs(): number;
|
|
76
|
+
/** Retention: done jobs finished before the cutoff leave the journal. */
|
|
77
|
+
pruneJobs(cutoffMs: number): number;
|
|
78
|
+
/** Shift every deadline by `ms` — the sleep pardon (decision 0009). */
|
|
79
|
+
pardon(ms: number): void;
|
|
80
|
+
}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The per-machine journal: disk is truth, daemon memory is a cache
|
|
3
|
+
* (decision 0009). node:sqlite — zero native deps.
|
|
4
|
+
*/
|
|
5
|
+
import { DatabaseSync } from 'node:sqlite';
|
|
6
|
+
import { journalPath } from './paths.js';
|
|
7
|
+
export class Journal {
|
|
8
|
+
db;
|
|
9
|
+
constructor(path = journalPath()) {
|
|
10
|
+
this.db = new DatabaseSync(path);
|
|
11
|
+
this.db.exec('PRAGMA journal_mode = WAL');
|
|
12
|
+
this.db.exec(`
|
|
13
|
+
CREATE TABLE IF NOT EXISTS envs (
|
|
14
|
+
id TEXT PRIMARY KEY, stack TEXT NOT NULL, stack_root TEXT NOT NULL,
|
|
15
|
+
state TEXT NOT NULL, root TEXT NOT NULL,
|
|
16
|
+
ports TEXT NOT NULL DEFAULT '{}', datastore_ns TEXT NOT NULL DEFAULT '{}',
|
|
17
|
+
fingerprints TEXT NOT NULL DEFAULT '{}', presets TEXT NOT NULL DEFAULT '{}',
|
|
18
|
+
bind_count INTEGER NOT NULL DEFAULT 0,
|
|
19
|
+
created_at INTEGER NOT NULL, last_used_at INTEGER NOT NULL,
|
|
20
|
+
service_pids TEXT NOT NULL DEFAULT '{}',
|
|
21
|
+
fail_streak INTEGER NOT NULL DEFAULT 0
|
|
22
|
+
);
|
|
23
|
+
CREATE TABLE IF NOT EXISTS leases (
|
|
24
|
+
id TEXT PRIMARY KEY, env_id TEXT NOT NULL, kind TEXT NOT NULL,
|
|
25
|
+
holder TEXT NOT NULL, hygiene TEXT NOT NULL, expires_at INTEGER NOT NULL
|
|
26
|
+
);
|
|
27
|
+
CREATE TABLE IF NOT EXISTS jobs (
|
|
28
|
+
id TEXT PRIMARY KEY, stack_cwd TEXT NOT NULL, check_name TEXT NOT NULL,
|
|
29
|
+
state TEXT NOT NULL, verdict TEXT, created_at INTEGER NOT NULL, finished_at INTEGER
|
|
30
|
+
);
|
|
31
|
+
CREATE TABLE IF NOT EXISTS counters (
|
|
32
|
+
stack TEXT PRIMARY KEY, next_env INTEGER NOT NULL DEFAULT 1
|
|
33
|
+
);
|
|
34
|
+
`);
|
|
35
|
+
// Migration for journals created before fail_streak existed.
|
|
36
|
+
try {
|
|
37
|
+
this.db.exec("ALTER TABLE envs ADD COLUMN fail_streak INTEGER NOT NULL DEFAULT 0");
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
/* column already exists */
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
rowToEnv(r) {
|
|
44
|
+
return {
|
|
45
|
+
id: r.id,
|
|
46
|
+
stack: r.stack,
|
|
47
|
+
stackRoot: r.stack_root,
|
|
48
|
+
state: r.state,
|
|
49
|
+
root: r.root,
|
|
50
|
+
ports: JSON.parse(r.ports),
|
|
51
|
+
datastoreNs: JSON.parse(r.datastore_ns),
|
|
52
|
+
fingerprints: JSON.parse(r.fingerprints),
|
|
53
|
+
presets: JSON.parse(r.presets),
|
|
54
|
+
bindCount: r.bind_count,
|
|
55
|
+
createdAt: r.created_at,
|
|
56
|
+
lastUsedAt: r.last_used_at,
|
|
57
|
+
servicePids: JSON.parse(r.service_pids),
|
|
58
|
+
failStreak: r.fail_streak ?? 0,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
saveEnv(e) {
|
|
62
|
+
this.db
|
|
63
|
+
.prepare(`INSERT INTO envs (id, stack, stack_root, state, root, ports, datastore_ns, fingerprints, presets, bind_count, created_at, last_used_at, service_pids, fail_streak)
|
|
64
|
+
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)
|
|
65
|
+
ON CONFLICT(id) DO UPDATE SET state=excluded.state, ports=excluded.ports,
|
|
66
|
+
datastore_ns=excluded.datastore_ns, fingerprints=excluded.fingerprints,
|
|
67
|
+
presets=excluded.presets, bind_count=excluded.bind_count,
|
|
68
|
+
last_used_at=excluded.last_used_at, service_pids=excluded.service_pids,
|
|
69
|
+
fail_streak=excluded.fail_streak`)
|
|
70
|
+
.run(e.id, e.stack, e.stackRoot, e.state, e.root, JSON.stringify(e.ports), JSON.stringify(e.datastoreNs), JSON.stringify(e.fingerprints), JSON.stringify(e.presets), e.bindCount, e.createdAt, e.lastUsedAt, JSON.stringify(e.servicePids), e.failStreak);
|
|
71
|
+
}
|
|
72
|
+
getEnv(id) {
|
|
73
|
+
const r = this.db.prepare('SELECT * FROM envs WHERE id = ?').get(id);
|
|
74
|
+
return r ? this.rowToEnv(r) : undefined;
|
|
75
|
+
}
|
|
76
|
+
envsForStack(stack) {
|
|
77
|
+
return this.db.prepare('SELECT * FROM envs WHERE stack = ? ORDER BY id').all(stack).map((r) => this.rowToEnv(r));
|
|
78
|
+
}
|
|
79
|
+
allEnvs() {
|
|
80
|
+
return this.db.prepare('SELECT * FROM envs ORDER BY id').all().map((r) => this.rowToEnv(r));
|
|
81
|
+
}
|
|
82
|
+
deleteEnv(id) {
|
|
83
|
+
this.db.prepare('DELETE FROM envs WHERE id = ?').run(id);
|
|
84
|
+
this.db.prepare('DELETE FROM leases WHERE env_id = ?').run(id);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* A per-stack env sequence that NEVER reuses a number, even after envs are
|
|
88
|
+
* reaped — so a recycled env's id can't collide with a live one. Monotonic
|
|
89
|
+
* in the journal, survives daemon restarts.
|
|
90
|
+
*/
|
|
91
|
+
nextEnvSeq(stack) {
|
|
92
|
+
this.db.prepare('INSERT INTO counters (stack, next_env) VALUES (?, 1) ON CONFLICT(stack) DO NOTHING').run(stack);
|
|
93
|
+
const row = this.db.prepare('SELECT next_env FROM counters WHERE stack = ?').get(stack);
|
|
94
|
+
const seq = row.next_env;
|
|
95
|
+
this.db.prepare('UPDATE counters SET next_env = next_env + 1 WHERE stack = ?').run(stack);
|
|
96
|
+
return seq;
|
|
97
|
+
}
|
|
98
|
+
/** Update just the recorded service pids (auto-restart keeps recovery honest). */
|
|
99
|
+
updateServicePids(id, pids) {
|
|
100
|
+
this.db.prepare('UPDATE envs SET service_pids = ? WHERE id = ?').run(JSON.stringify(pids), id);
|
|
101
|
+
}
|
|
102
|
+
saveLease(l) {
|
|
103
|
+
this.db
|
|
104
|
+
.prepare(`INSERT INTO leases (id, env_id, kind, holder, hygiene, expires_at) VALUES (?,?,?,?,?,?)
|
|
105
|
+
ON CONFLICT(id) DO UPDATE SET expires_at=excluded.expires_at, hygiene=excluded.hygiene`)
|
|
106
|
+
.run(l.id, l.envId, l.kind, l.holder, l.hygiene, l.expiresAt);
|
|
107
|
+
}
|
|
108
|
+
rowToLease(r) {
|
|
109
|
+
return {
|
|
110
|
+
id: r.id,
|
|
111
|
+
envId: r.env_id,
|
|
112
|
+
kind: r.kind,
|
|
113
|
+
holder: r.holder,
|
|
114
|
+
hygiene: r.hygiene,
|
|
115
|
+
expiresAt: r.expires_at,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
leaseForHolder(holder, stack) {
|
|
119
|
+
const r = this.db
|
|
120
|
+
.prepare(`SELECT l.* FROM leases l JOIN envs e ON e.id = l.env_id WHERE l.holder = ? AND e.stack = ?`)
|
|
121
|
+
.get(holder, stack);
|
|
122
|
+
return r ? this.rowToLease(r) : undefined;
|
|
123
|
+
}
|
|
124
|
+
leaseForEnv(envId) {
|
|
125
|
+
const r = this.db.prepare('SELECT * FROM leases WHERE env_id = ?').get(envId);
|
|
126
|
+
return r ? this.rowToLease(r) : undefined;
|
|
127
|
+
}
|
|
128
|
+
allLeases() {
|
|
129
|
+
return this.db.prepare('SELECT * FROM leases').all().map((r) => this.rowToLease(r));
|
|
130
|
+
}
|
|
131
|
+
deleteLease(id) {
|
|
132
|
+
this.db.prepare('DELETE FROM leases WHERE id = ?').run(id);
|
|
133
|
+
}
|
|
134
|
+
saveJob(job) {
|
|
135
|
+
this.db
|
|
136
|
+
.prepare(`INSERT INTO jobs (id, stack_cwd, check_name, state, verdict, created_at, finished_at) VALUES (?,?,?,?,?,?,?)
|
|
137
|
+
ON CONFLICT(id) DO UPDATE SET state=excluded.state, verdict=excluded.verdict, finished_at=excluded.finished_at`)
|
|
138
|
+
.run(job.id, job.stackCwd, job.check, job.state, job.verdict ? JSON.stringify(job.verdict) : null, Date.now(), job.finishedAt ?? null);
|
|
139
|
+
}
|
|
140
|
+
getJob(id) {
|
|
141
|
+
const r = this.db.prepare('SELECT * FROM jobs WHERE id = ?').get(id);
|
|
142
|
+
if (!r)
|
|
143
|
+
return undefined;
|
|
144
|
+
return {
|
|
145
|
+
id: r.id,
|
|
146
|
+
check: r.check_name,
|
|
147
|
+
state: r.state,
|
|
148
|
+
verdict: r.verdict ? JSON.parse(r.verdict) : null,
|
|
149
|
+
createdAt: r.created_at,
|
|
150
|
+
finishedAt: r.finished_at ?? null,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
listJobs(limit = 20) {
|
|
154
|
+
return this.db.prepare('SELECT * FROM jobs ORDER BY created_at DESC LIMIT ?').all(limit).map((r) => ({
|
|
155
|
+
id: r.id,
|
|
156
|
+
check: r.check_name,
|
|
157
|
+
state: r.state,
|
|
158
|
+
ok: r.verdict ? Boolean(JSON.parse(r.verdict).ok) : null,
|
|
159
|
+
createdAt: r.created_at,
|
|
160
|
+
finishedAt: r.finished_at ?? null,
|
|
161
|
+
}));
|
|
162
|
+
}
|
|
163
|
+
/** Recovery: a job left 'running'/'pending' by a dead daemon can never finish. */
|
|
164
|
+
failStaleJobs() {
|
|
165
|
+
const stale = this.db.prepare("SELECT id, check_name, stack_cwd FROM jobs WHERE state != 'done'").all();
|
|
166
|
+
for (const j of stale) {
|
|
167
|
+
this.saveJob({
|
|
168
|
+
id: j.id, stackCwd: j.stack_cwd, check: j.check_name, state: 'done',
|
|
169
|
+
verdict: { check: j.check_name, ok: false, exitCode: -1, failure: { class: 'env-error', message: 'daemon restarted while this run was in flight — result lost' } },
|
|
170
|
+
finishedAt: Date.now(),
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
return stale.length;
|
|
174
|
+
}
|
|
175
|
+
/** Retention: done jobs finished before the cutoff leave the journal. */
|
|
176
|
+
pruneJobs(cutoffMs) {
|
|
177
|
+
const res = this.db.prepare("DELETE FROM jobs WHERE state = 'done' AND finished_at IS NOT NULL AND finished_at < ?").run(cutoffMs);
|
|
178
|
+
return Number(res.changes ?? 0);
|
|
179
|
+
}
|
|
180
|
+
/** Shift every deadline by `ms` — the sleep pardon (decision 0009). */
|
|
181
|
+
pardon(ms) {
|
|
182
|
+
this.db.prepare('UPDATE leases SET expires_at = expires_at + ?').run(ms);
|
|
183
|
+
this.db.prepare('UPDATE envs SET last_used_at = last_used_at + ?').run(ms);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
//# sourceMappingURL=journal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"journal.js","sourceRoot":"","sources":["../../src/core/journal.ts"],"names":[],"mappings":"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"}
|