llm-relay 0.82.2 → 0.83.2
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/dist/config/routing-parser.js +22 -3
- package/dist/config/routing-parser.js.map +1 -1
- package/dist/config-types.d.ts +23 -0
- package/dist/config-types.js +1 -0
- package/dist/config-types.js.map +1 -1
- package/dist/dispatch.d.ts +2 -0
- package/dist/dispatch.js +4 -1
- package/dist/dispatch.js.map +1 -1
- package/dist/mcp/job-archive.d.ts +9 -0
- package/dist/mcp/job-archive.js +50 -12
- package/dist/mcp/job-archive.js.map +1 -1
- package/dist/mcp/job-journal.d.ts +35 -2
- package/dist/mcp/job-journal.js +68 -9
- package/dist/mcp/job-journal.js.map +1 -1
- package/dist/mcp/lane-runner.d.ts +98 -1
- package/dist/mcp/lane-runner.js +145 -2
- package/dist/mcp/lane-runner.js.map +1 -1
- package/dist/mcp/server.d.ts +105 -0
- package/dist/mcp/server.js +321 -66
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tree-delta.d.ts +40 -0
- package/dist/mcp/tree-delta.js +121 -0
- package/dist/mcp/tree-delta.js.map +1 -0
- package/dist/setup-claude.d.ts +5 -0
- package/dist/setup-claude.js +21 -7
- package/dist/setup-claude.js.map +1 -1
- package/package.json +1 -1
- package/scripts/install-skill.mjs +9 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"job-archive.js","sourceRoot":"","sources":["../../src/mcp/job-archive.ts"],"names":[],"mappings":"AA6BA,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjF,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAGtD,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC;AAGrC,MAAM,CAAC,MAAM,iBAAiB,GAAG,GAAG,CAAC;AAGrC,MAAM,CAAC,MAAM,yBAAyB,GAAG,GAAG,GAAG,IAAI,CAAC;AAoBpD,MAAM,UAAU,cAAc,CAAC,MAAyB,OAAO,CAAC,GAAG;IACjE,IAAI,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;QAClB,OAAO,cAAc,CAAC,OAAO,EAAE,CAAC,kBAAkB,EAAE,mBAAmB,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAC9F,CAAC;IACD,OAAO,cAAc,CAAC,OAAO,EAAE,CAAC,sBAAsB,CAAC,CAAC,CAAC;AAC3D,CAAC;
|
|
1
|
+
{"version":3,"file":"job-archive.js","sourceRoot":"","sources":["../../src/mcp/job-archive.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,6 +5,23 @@ export interface JournalRow {
|
|
|
5
5
|
spec?: string;
|
|
6
6
|
cwd: string;
|
|
7
7
|
startedAt: number;
|
|
8
|
+
/** The task's first line, cut short, so another process can list the job recognisably. */
|
|
9
|
+
label?: string;
|
|
10
|
+
/**
|
|
11
|
+
* The process and the journal instance that own the row. Absent on a row written before
|
|
12
|
+
* 2026-09-17, which is read exactly as before: an orphan.
|
|
13
|
+
*
|
|
14
|
+
* ⚠ Why both exist. Two hosts run their own `llm-relay mcp` process at the same time (Claude
|
|
15
|
+
* Desktop and Codex Desktop, measured), and both write this one file. Before the owner was
|
|
16
|
+
* recorded, the second process to start read the first one's LIVE jobs as orphans and reported
|
|
17
|
+
* them killed, and every write by either process erased the other's rows. The pid says whether
|
|
18
|
+
* the owner can still be running; the instance token tells two journals inside one process apart,
|
|
19
|
+
* which is how the suite simulates a restart without a second process.
|
|
20
|
+
*/
|
|
21
|
+
owner?: {
|
|
22
|
+
pid: number;
|
|
23
|
+
instance: string;
|
|
24
|
+
};
|
|
8
25
|
}
|
|
9
26
|
export interface JournalFile {
|
|
10
27
|
version: 1;
|
|
@@ -26,11 +43,27 @@ export interface JobJournal {
|
|
|
26
43
|
note(row: JournalRow): void;
|
|
27
44
|
/** Remove a job that reached a terminal state, or one that never started. */
|
|
28
45
|
clear(jobId: string): void;
|
|
29
|
-
/** Rows present at STARTUP — i.e. jobs a previous process died holding. */
|
|
46
|
+
/** Rows present at STARTUP whose owner is gone — i.e. jobs a previous process died holding. */
|
|
30
47
|
orphans(): JournalRow[];
|
|
48
|
+
/**
|
|
49
|
+
* The row for `jobId` if ANOTHER live process owns it right now, read from disk at call time.
|
|
50
|
+
* This is how one host's server answers for a job another host's server is still running.
|
|
51
|
+
*/
|
|
52
|
+
foreign(jobId: string): JournalRow | undefined;
|
|
53
|
+
/** Every row another live process owns now. */
|
|
54
|
+
foreignRows(): JournalRow[];
|
|
55
|
+
/** The highest `job-NNNN` sequence any row on disk carries, read at call time; 0 when none. */
|
|
56
|
+
maxSeqOnDisk(): number;
|
|
31
57
|
}
|
|
32
58
|
/** A journal that records nothing. The default under vitest, and for an embedder that declines one. */
|
|
33
59
|
export declare const nullJobJournal: JobJournal;
|
|
60
|
+
/** How a journal decides who owns a row. Injected so the suite can prove both branches. */
|
|
61
|
+
export interface JobJournalOptions {
|
|
62
|
+
/** This process's pid. */
|
|
63
|
+
pid?: number;
|
|
64
|
+
/** Does `pid` still name a running process? `process.kill(pid, 0)` by default. */
|
|
65
|
+
isAlive?: (pid: number) => boolean;
|
|
66
|
+
}
|
|
34
67
|
/**
|
|
35
68
|
* The real journal: a small JSON file rewritten on every change, read ONCE at construction.
|
|
36
69
|
*
|
|
@@ -43,4 +76,4 @@ export declare const nullJobJournal: JobJournal;
|
|
|
43
76
|
* the strength of an unparseable file would invent deaths, which is the same fail-safe direction
|
|
44
77
|
* `lane-manifest.ts` takes on a corrupt manifest.
|
|
45
78
|
*/
|
|
46
|
-
export declare function createJobJournal(path?: string): JobJournal;
|
|
79
|
+
export declare function createJobJournal(path?: string, options?: JobJournalOptions): JobJournal;
|
package/dist/mcp/job-journal.js
CHANGED
|
@@ -11,25 +11,55 @@ export const nullJobJournal = {
|
|
|
11
11
|
note: () => { },
|
|
12
12
|
clear: () => { },
|
|
13
13
|
orphans: () => [],
|
|
14
|
+
foreign: () => undefined,
|
|
15
|
+
foreignRows: () => [],
|
|
16
|
+
maxSeqOnDisk: () => 0,
|
|
14
17
|
};
|
|
15
|
-
|
|
18
|
+
function defaultIsAlive(pid) {
|
|
19
|
+
try {
|
|
20
|
+
process.kill(pid, 0);
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
catch (e) {
|
|
24
|
+
return e.code === "EPERM";
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
let instanceCounter = 0;
|
|
28
|
+
export function createJobJournal(path = jobJournalPath(), options = {}) {
|
|
29
|
+
const pid = options.pid ?? process.pid;
|
|
30
|
+
const isAlive = options.isAlive ?? defaultIsAlive;
|
|
31
|
+
instanceCounter += 1;
|
|
32
|
+
const instance = `${pid}-${Date.now().toString(36)}-${instanceCounter}`;
|
|
16
33
|
const rows = new Map();
|
|
17
34
|
let loaded = false;
|
|
18
35
|
let startupOrphans = [];
|
|
36
|
+
const readDisk = () => {
|
|
37
|
+
const parsed = safeReadJsonSync(path, {
|
|
38
|
+
validator: (v) => isRecord(v) && v["version"] === JOB_JOURNAL_VERSION && Array.isArray(v["jobs"]),
|
|
39
|
+
});
|
|
40
|
+
return parsed ? parsed.jobs.filter(isJournalRow) : null;
|
|
41
|
+
};
|
|
42
|
+
const ownedElsewhere = (row) => {
|
|
43
|
+
const owner = row.owner;
|
|
44
|
+
if (owner === undefined || owner.instance === instance)
|
|
45
|
+
return false;
|
|
46
|
+
if (owner.pid === pid)
|
|
47
|
+
return false;
|
|
48
|
+
return isAlive(owner.pid);
|
|
49
|
+
};
|
|
19
50
|
const readOnce = () => {
|
|
20
51
|
if (loaded)
|
|
21
52
|
return;
|
|
22
53
|
loaded = true;
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
});
|
|
26
|
-
if (!parsed)
|
|
54
|
+
const disk = readDisk();
|
|
55
|
+
if (!disk)
|
|
27
56
|
return;
|
|
28
|
-
startupOrphans =
|
|
57
|
+
startupOrphans = disk.filter((row) => row.owner?.instance !== instance && !ownedElsewhere(row));
|
|
29
58
|
};
|
|
30
59
|
const flush = () => {
|
|
31
60
|
try {
|
|
32
|
-
|
|
61
|
+
const others = (readDisk() ?? []).filter(ownedElsewhere);
|
|
62
|
+
atomicWriteJsonSync(path, { version: JOB_JOURNAL_VERSION, jobs: [...others, ...rows.values()] });
|
|
33
63
|
}
|
|
34
64
|
catch {
|
|
35
65
|
}
|
|
@@ -37,7 +67,7 @@ export function createJobJournal(path = jobJournalPath()) {
|
|
|
37
67
|
return {
|
|
38
68
|
note(row) {
|
|
39
69
|
readOnce();
|
|
40
|
-
rows.set(row.jobId, row);
|
|
70
|
+
rows.set(row.jobId, { ...row, owner: { pid, instance } });
|
|
41
71
|
flush();
|
|
42
72
|
},
|
|
43
73
|
clear(jobId) {
|
|
@@ -50,6 +80,26 @@ export function createJobJournal(path = jobJournalPath()) {
|
|
|
50
80
|
readOnce();
|
|
51
81
|
return startupOrphans;
|
|
52
82
|
},
|
|
83
|
+
foreign(jobId) {
|
|
84
|
+
readOnce();
|
|
85
|
+
if (rows.has(jobId))
|
|
86
|
+
return undefined;
|
|
87
|
+
return (readDisk() ?? []).find((row) => row.jobId === jobId && ownedElsewhere(row));
|
|
88
|
+
},
|
|
89
|
+
foreignRows() {
|
|
90
|
+
readOnce();
|
|
91
|
+
return (readDisk() ?? []).filter((row) => !rows.has(row.jobId) && ownedElsewhere(row));
|
|
92
|
+
},
|
|
93
|
+
maxSeqOnDisk() {
|
|
94
|
+
let max = 0;
|
|
95
|
+
for (const row of readDisk() ?? []) {
|
|
96
|
+
const m = /^job-(\d+)$/.exec(row.jobId);
|
|
97
|
+
const n = m ? Number(m[1]) : 0;
|
|
98
|
+
if (Number.isSafeInteger(n) && n > max)
|
|
99
|
+
max = n;
|
|
100
|
+
}
|
|
101
|
+
return max;
|
|
102
|
+
},
|
|
53
103
|
};
|
|
54
104
|
}
|
|
55
105
|
function isRecord(value) {
|
|
@@ -62,6 +112,15 @@ function isJournalRow(value) {
|
|
|
62
112
|
typeof value["laneId"] === "string" &&
|
|
63
113
|
typeof value["cwd"] === "string" &&
|
|
64
114
|
typeof value["startedAt"] === "number" &&
|
|
65
|
-
(value["spec"] === undefined || typeof value["spec"] === "string")
|
|
115
|
+
(value["spec"] === undefined || typeof value["spec"] === "string") &&
|
|
116
|
+
(value["label"] === undefined || typeof value["label"] === "string") &&
|
|
117
|
+
(value["owner"] === undefined || isOwner(value["owner"])));
|
|
118
|
+
}
|
|
119
|
+
function isOwner(value) {
|
|
120
|
+
return (isRecord(value) &&
|
|
121
|
+
typeof value["pid"] === "number" &&
|
|
122
|
+
Number.isSafeInteger(value["pid"]) &&
|
|
123
|
+
value["pid"] > 0 &&
|
|
124
|
+
typeof value["instance"] === "string");
|
|
66
125
|
}
|
|
67
126
|
//# sourceMappingURL=job-journal.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"job-journal.js","sourceRoot":"","sources":["../../src/mcp/job-journal.ts"],"names":[],"mappings":"AAoBA,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjF,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"job-journal.js","sourceRoot":"","sources":["../../src/mcp/job-journal.ts"],"names":[],"mappings":"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"}
|
|
@@ -212,6 +212,8 @@ export interface LaneJob {
|
|
|
212
212
|
* previous process, and its report is exactly what that process wrote (`job-archive.ts`).
|
|
213
213
|
*/
|
|
214
214
|
restored?: boolean;
|
|
215
|
+
/** The first line of the task, cut short (`taskLabel`), so a job can be recognised in a list. */
|
|
216
|
+
label?: string;
|
|
215
217
|
/**
|
|
216
218
|
* The read-only TOOL binding applied to the lane now running (`readonly-boundary.ts`
|
|
217
219
|
* `readOnlyInvoke`). Replaced per lane, like `expected`; absent for an ordinary dispatch.
|
|
@@ -220,6 +222,23 @@ export interface LaneJob {
|
|
|
220
222
|
laneId: string;
|
|
221
223
|
binding: string;
|
|
222
224
|
};
|
|
225
|
+
/**
|
|
226
|
+
* What the launcher changed before the lane now running started (`prepareLaneLaunch`): an
|
|
227
|
+
* environment value expanded or removed, or the working directory given to AGY. Names only, never
|
|
228
|
+
* a value. Replaced per lane, like `readOnly`; absent when the launcher changed nothing.
|
|
229
|
+
*/
|
|
230
|
+
launch?: string[];
|
|
231
|
+
/**
|
|
232
|
+
* What the job changed in its git working tree, rendered (`tree-delta.ts`): set once, when the job
|
|
233
|
+
* ends, for an agent-mode job whose cwd is in a git work tree. Report only.
|
|
234
|
+
*/
|
|
235
|
+
treeDelta?: string;
|
|
236
|
+
/**
|
|
237
|
+
* Each lane the walk kept past its attempt budget because it was still working, one line per lane,
|
|
238
|
+
* with the reason. Kept for the whole job — not replaced per lane — because the lane that was kept
|
|
239
|
+
* can still be stopped later, and the record of why it ran long must survive that.
|
|
240
|
+
*/
|
|
241
|
+
extended?: string[];
|
|
223
242
|
}
|
|
224
243
|
/**
|
|
225
244
|
* Output progress of the attempt now running. Byte counts and timestamps only — never the bytes.
|
|
@@ -288,6 +307,39 @@ export declare function isContentEmpty(text: string): boolean;
|
|
|
288
307
|
* literal token, rather than each spelling it out separately.
|
|
289
308
|
*/
|
|
290
309
|
export declare const EMPTY_OUTPUT_REASON = "empty-output: the lane's output has no usable content after stripping formatting";
|
|
310
|
+
/**
|
|
311
|
+
* Expand the `%NAME%` references a Windows environment value still holds (`docs/backlog.md`: a lane
|
|
312
|
+
* inherited `HOME=%USERPROFILE%` literally, and a child that honours `HOME` wrote into a directory
|
|
313
|
+
* named `%USERPROFILE%`). A reference expands from the SAME environment, looked up without case as
|
|
314
|
+
* Windows does, in one pass. A value that is ONE unresolved reference is removed, because the literal
|
|
315
|
+
* is never a usable value. An unresolved reference inside a longer value (a `PATH` entry) stays: removing
|
|
316
|
+
* the whole value would lose the parts that are real. Windows only — `%` has no meaning to a POSIX
|
|
317
|
+
* shell, and a POSIX value that holds one is data.
|
|
318
|
+
*
|
|
319
|
+
* Returns the notes `LaneJobStore.noteLaunch` records: variable and reference NAMES, never a value.
|
|
320
|
+
*/
|
|
321
|
+
export declare function expandEnvReferences(env: NodeJS.ProcessEnv, platform?: NodeJS.Platform): {
|
|
322
|
+
env: NodeJS.ProcessEnv;
|
|
323
|
+
notes: string[];
|
|
324
|
+
};
|
|
325
|
+
type LaneInvoke = {
|
|
326
|
+
command: string;
|
|
327
|
+
args: string[];
|
|
328
|
+
env?: Record<string, string | null>;
|
|
329
|
+
};
|
|
330
|
+
/**
|
|
331
|
+
* Give an AGY lane the caller's working directory (`docs/backlog.md`: AGY works in its own scratch
|
|
332
|
+
* directory whatever `cwd` its process gets, so a lane asked to edit a worktree saw none of its
|
|
333
|
+
* files). AGY reads a directory only through `--add-dir`, so the directory goes on the command line,
|
|
334
|
+
* and the task text names it. Null for every other lane.
|
|
335
|
+
*
|
|
336
|
+
* The prompt is the argument after AGY's own `-p`; a rung with no `-p` gets `--add-dir` alone. An
|
|
337
|
+
* `--add-dir` the rung already declares for the same directory is not repeated.
|
|
338
|
+
*/
|
|
339
|
+
export declare function agyWorkingDirInvoke<T extends LaneInvoke>(invoke: T, cwd: string): {
|
|
340
|
+
invoke: T;
|
|
341
|
+
note: string;
|
|
342
|
+
} | null;
|
|
291
343
|
export interface DispatchedQuotaReport {
|
|
292
344
|
laneId: string;
|
|
293
345
|
tier: string | undefined;
|
|
@@ -434,6 +486,16 @@ export declare function relayLoopbackUrl(config: {
|
|
|
434
486
|
port: number;
|
|
435
487
|
}, path: string): string;
|
|
436
488
|
export declare function readRelayAnnouncements(headers: Headers): RelayAnnouncements;
|
|
489
|
+
/** One line of `LaneJobStore.recent`. `elsewhere` marks a job another live process runs. */
|
|
490
|
+
export interface RecentJob {
|
|
491
|
+
id: string;
|
|
492
|
+
status: JobStatus;
|
|
493
|
+
laneId: string;
|
|
494
|
+
startedAt: number;
|
|
495
|
+
endedAt: number | undefined;
|
|
496
|
+
elsewhere: boolean;
|
|
497
|
+
label?: string;
|
|
498
|
+
}
|
|
437
499
|
/** Raise the counter to at least `seq`; never lowers it. */
|
|
438
500
|
export declare function seedJobCounter(seq: number): void;
|
|
439
501
|
/**
|
|
@@ -481,7 +543,7 @@ export declare class LaneJobStore {
|
|
|
481
543
|
* termination that never happened.
|
|
482
544
|
*/
|
|
483
545
|
private adoptOrphans;
|
|
484
|
-
create(laneId: string, spec: string | undefined, cwd: string, dispatchSource?: "daemon" | "fallback"): LaneJob;
|
|
546
|
+
create(laneId: string, spec: string | undefined, cwd: string, dispatchSource?: "daemon" | "fallback", label?: string): LaneJob;
|
|
485
547
|
/**
|
|
486
548
|
* Record the process-handle this dispatcher started for `id`, so the job can be REAPED when it
|
|
487
549
|
* reaches a terminal state and so what it owned is reportable afterwards.
|
|
@@ -534,6 +596,15 @@ export declare class LaneJobStore {
|
|
|
534
596
|
noteOutput(id: string, stream: "stdout" | "stderr", bytes: number, now: number): void;
|
|
535
597
|
/** Record the read-only tool binding the lane now running was given, so the reply can state it. */
|
|
536
598
|
noteReadOnly(id: string, laneId: string, binding: string): void;
|
|
599
|
+
/** Record what the launcher changed for the lane now running, so the reply can state it. */
|
|
600
|
+
/**
|
|
601
|
+
* Record the job's tree delta. Accepted on a TERMINAL job too — a cancellation ends the job before
|
|
602
|
+
* the second `git status` returns — and the archive row is then written again so it carries it.
|
|
603
|
+
*/
|
|
604
|
+
noteTreeDelta(id: string, text: string): void;
|
|
605
|
+
/** Record (or update) why the walk kept `laneId` past its budget. One line per lane. */
|
|
606
|
+
noteExtension(id: string, laneId: string, text: string): void;
|
|
607
|
+
noteLaunch(id: string, notes: readonly string[]): void;
|
|
537
608
|
/**
|
|
538
609
|
* Append one tried lane to the walk's record. Appended for EVERY attempt, the winner included,
|
|
539
610
|
* so the answer can say what it cost to get there — and so an abandoned lane leaves a trace,
|
|
@@ -584,7 +655,33 @@ export declare class LaneJobStore {
|
|
|
584
655
|
* `docs/reference.md` says so rather than implying a machine-wide guarantee this cannot make.
|
|
585
656
|
*/
|
|
586
657
|
inFlight(laneId: string, excludeJobId?: string): number;
|
|
658
|
+
/** A job THIS store holds. The walk reads this; it never needs another process's job. */
|
|
587
659
|
get(id: string): LaneJob | undefined;
|
|
660
|
+
/**
|
|
661
|
+
* A job for a CALLER: one this store holds, else one another `llm-relay mcp` process finished and
|
|
662
|
+
* archived after this store started (kept from then on, marked `restored`), else undefined.
|
|
663
|
+
*
|
|
664
|
+
* ⚠ Why a caller needs more than `get`. Claude Desktop and Codex Desktop each start their own
|
|
665
|
+
* server, and a session can poll through a different connection than the one that dispatched —
|
|
666
|
+
* observed 2026-09-16 as `unknown jobId` for a job that had finished. The archive is shared on
|
|
667
|
+
* disk, so the answer exists; it was read only once, at start.
|
|
668
|
+
*/
|
|
669
|
+
find(id: string): LaneJob | undefined;
|
|
670
|
+
/**
|
|
671
|
+
* The newest `limit` jobs this machine knows: this store's, every finished job on disk, and every
|
|
672
|
+
* job another live process is running. Newest start first.
|
|
673
|
+
*/
|
|
674
|
+
recent(limit: number): RecentJob[];
|
|
675
|
+
/**
|
|
676
|
+
* The journal row for a job another LIVE `llm-relay mcp` process is running now, or undefined.
|
|
677
|
+
* Nothing about it can be read here except that it runs; its answer reaches `find` once it ends.
|
|
678
|
+
*/
|
|
679
|
+
runningElsewhere(id: string): {
|
|
680
|
+
laneId: string;
|
|
681
|
+
spec?: string;
|
|
682
|
+
startedAt: number;
|
|
683
|
+
pid: number;
|
|
684
|
+
} | undefined;
|
|
588
685
|
list(): LaneJob[];
|
|
589
686
|
/**
|
|
590
687
|
* `relay` carries an answer-mode job's captured provenance headers — absent for every
|
package/dist/mcp/lane-runner.js
CHANGED
|
@@ -53,6 +53,62 @@ export function isContentEmpty(text) {
|
|
|
53
53
|
return text.replace(/[\s#*_\-|>`~=]/g, "").length === 0;
|
|
54
54
|
}
|
|
55
55
|
export const EMPTY_OUTPUT_REASON = "empty-output: the lane's output has no usable content after stripping formatting";
|
|
56
|
+
const ENV_REFERENCE = /%([A-Za-z_][A-Za-z0-9_()]*)%/g;
|
|
57
|
+
const WHOLE_ENV_REFERENCE = /^%[A-Za-z_][A-Za-z0-9_()]*%$/;
|
|
58
|
+
export function expandEnvReferences(env, platform = process.platform) {
|
|
59
|
+
if (platform !== "win32")
|
|
60
|
+
return { env, notes: [] };
|
|
61
|
+
const lookup = new Map();
|
|
62
|
+
for (const [name, value] of Object.entries(env)) {
|
|
63
|
+
if (typeof value === "string")
|
|
64
|
+
lookup.set(name.toUpperCase(), value);
|
|
65
|
+
}
|
|
66
|
+
const out = { ...env };
|
|
67
|
+
const notes = [];
|
|
68
|
+
for (const [name, value] of Object.entries(env)) {
|
|
69
|
+
if (typeof value !== "string" || !value.includes("%"))
|
|
70
|
+
continue;
|
|
71
|
+
if (WHOLE_ENV_REFERENCE.test(value) && !lookup.has(value.slice(1, -1).toUpperCase())) {
|
|
72
|
+
delete out[name];
|
|
73
|
+
notes.push(`${name} removed (${value} does not resolve)`);
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
const expanded = new Set();
|
|
77
|
+
const next = value.replace(ENV_REFERENCE, (token, ref) => {
|
|
78
|
+
const found = lookup.get(ref.toUpperCase());
|
|
79
|
+
if (found === undefined)
|
|
80
|
+
return token;
|
|
81
|
+
expanded.add(token);
|
|
82
|
+
return found;
|
|
83
|
+
});
|
|
84
|
+
if (expanded.size === 0)
|
|
85
|
+
continue;
|
|
86
|
+
out[name] = next;
|
|
87
|
+
notes.push(`${name} expanded from ${[...expanded].join(", ")}`);
|
|
88
|
+
}
|
|
89
|
+
return { env: out, notes };
|
|
90
|
+
}
|
|
91
|
+
export function agyWorkingDirInvoke(invoke, cwd) {
|
|
92
|
+
const rung = laneOfRung(invoke.command, invoke.args);
|
|
93
|
+
if (rung?.lane !== "agy")
|
|
94
|
+
return null;
|
|
95
|
+
const args = [...invoke.args];
|
|
96
|
+
const start = rung.binary === invoke.command ? 0 : args.indexOf(rung.binary) + 1;
|
|
97
|
+
const prompt = args.indexOf("-p", start);
|
|
98
|
+
if (prompt >= 0 && prompt + 1 < args.length) {
|
|
99
|
+
args[prompt + 1] = `Work in this directory: ${cwd}\n\n${args[prompt + 1]}`;
|
|
100
|
+
}
|
|
101
|
+
const target = samePathKey(cwd);
|
|
102
|
+
const declared = args.some((a, i) => (a === "--add-dir" && args[i + 1] !== undefined && samePathKey(args[i + 1]) === target) ||
|
|
103
|
+
(a.startsWith("--add-dir=") && samePathKey(a.slice("--add-dir=".length)) === target));
|
|
104
|
+
if (!declared)
|
|
105
|
+
args.push("--add-dir", cwd);
|
|
106
|
+
return { invoke: { ...invoke, args }, note: `agy works in ${cwd} (--add-dir)` };
|
|
107
|
+
}
|
|
108
|
+
function samePathKey(path) {
|
|
109
|
+
const resolved = resolvePath(path).replace(/\\/g, "/");
|
|
110
|
+
return process.platform === "win32" ? resolved.toLowerCase() : resolved;
|
|
111
|
+
}
|
|
56
112
|
export function classifyDispatchedResult(input) {
|
|
57
113
|
const { result } = input;
|
|
58
114
|
if (result.timedOut)
|
|
@@ -287,6 +343,20 @@ function readOwnedPids(handle) {
|
|
|
287
343
|
}
|
|
288
344
|
return raw.filter((pid) => Number.isSafeInteger(pid) && pid > 0);
|
|
289
345
|
}
|
|
346
|
+
function recentOf(job, elsewhere) {
|
|
347
|
+
return {
|
|
348
|
+
id: job.id,
|
|
349
|
+
status: job.status,
|
|
350
|
+
laneId: job.laneId,
|
|
351
|
+
startedAt: job.startedAt,
|
|
352
|
+
endedAt: job.endedAt,
|
|
353
|
+
elsewhere,
|
|
354
|
+
...(job.label === undefined ? {} : { label: job.label }),
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
function newestFirst(a, b) {
|
|
358
|
+
return b.startedAt - a.startedAt || (jobSeqOf(b.id) ?? 0) - (jobSeqOf(a.id) ?? 0);
|
|
359
|
+
}
|
|
290
360
|
let jobCounter = 0;
|
|
291
361
|
function nextJobId() {
|
|
292
362
|
jobCounter += 1;
|
|
@@ -361,7 +431,9 @@ export class LaneJobStore {
|
|
|
361
431
|
this.archive.record(killed);
|
|
362
432
|
}
|
|
363
433
|
}
|
|
364
|
-
create(laneId, spec, cwd, dispatchSource) {
|
|
434
|
+
create(laneId, spec, cwd, dispatchSource, label) {
|
|
435
|
+
seedJobCounter(this.archive.lastSeqOnDisk());
|
|
436
|
+
seedJobCounter(this.journal.maxSeqOnDisk());
|
|
365
437
|
const job = {
|
|
366
438
|
id: nextJobId(),
|
|
367
439
|
status: "running",
|
|
@@ -377,6 +449,7 @@ export class LaneJobStore {
|
|
|
377
449
|
error: undefined,
|
|
378
450
|
attempts: [],
|
|
379
451
|
...(dispatchSource !== undefined ? { dispatchSource } : {}),
|
|
452
|
+
...(label ? { label } : {}),
|
|
380
453
|
};
|
|
381
454
|
this.jobs.set(job.id, job);
|
|
382
455
|
const seq = jobSeqOf(job.id);
|
|
@@ -388,6 +461,7 @@ export class LaneJobStore {
|
|
|
388
461
|
...(job.spec === undefined ? {} : { spec: job.spec }),
|
|
389
462
|
cwd: job.cwd,
|
|
390
463
|
startedAt: job.startedAt,
|
|
464
|
+
...(job.label === undefined ? {} : { label: job.label }),
|
|
391
465
|
});
|
|
392
466
|
return job;
|
|
393
467
|
}
|
|
@@ -449,6 +523,7 @@ export class LaneJobStore {
|
|
|
449
523
|
job.expected = expected;
|
|
450
524
|
delete job.activity;
|
|
451
525
|
delete job.readOnly;
|
|
526
|
+
delete job.launch;
|
|
452
527
|
}
|
|
453
528
|
beginAttemptActivity(id, now) {
|
|
454
529
|
const job = this.jobs.get(id);
|
|
@@ -472,6 +547,27 @@ export class LaneJobStore {
|
|
|
472
547
|
return;
|
|
473
548
|
job.readOnly = { laneId, binding };
|
|
474
549
|
}
|
|
550
|
+
noteTreeDelta(id, text) {
|
|
551
|
+
const job = this.jobs.get(id);
|
|
552
|
+
if (!job)
|
|
553
|
+
return;
|
|
554
|
+
job.treeDelta = text;
|
|
555
|
+
if (job.status !== "running")
|
|
556
|
+
this.archive.record(job);
|
|
557
|
+
}
|
|
558
|
+
noteExtension(id, laneId, text) {
|
|
559
|
+
const job = this.jobs.get(id);
|
|
560
|
+
if (!job || job.status !== "running")
|
|
561
|
+
return;
|
|
562
|
+
const others = (job.extended ?? []).filter((line) => !line.startsWith(`${laneId} `));
|
|
563
|
+
job.extended = [...others, text];
|
|
564
|
+
}
|
|
565
|
+
noteLaunch(id, notes) {
|
|
566
|
+
const job = this.jobs.get(id);
|
|
567
|
+
if (!job || job.status !== "running" || notes.length === 0)
|
|
568
|
+
return;
|
|
569
|
+
job.launch = [...notes];
|
|
570
|
+
}
|
|
475
571
|
recordAttempt(id, attempt) {
|
|
476
572
|
this.jobs.get(id)?.attempts.push(attempt);
|
|
477
573
|
}
|
|
@@ -502,8 +598,55 @@ export class LaneJobStore {
|
|
|
502
598
|
get(id) {
|
|
503
599
|
return this.jobs.get(id);
|
|
504
600
|
}
|
|
601
|
+
find(id) {
|
|
602
|
+
const held = this.jobs.get(id);
|
|
603
|
+
if (held !== undefined)
|
|
604
|
+
return held;
|
|
605
|
+
const archived = this.archive.lookup(id);
|
|
606
|
+
if (archived === undefined)
|
|
607
|
+
return undefined;
|
|
608
|
+
const row = { ...archived, restored: true };
|
|
609
|
+
this.jobs.set(id, row);
|
|
610
|
+
return row;
|
|
611
|
+
}
|
|
612
|
+
recent(limit) {
|
|
613
|
+
const byId = new Map();
|
|
614
|
+
const add = (row) => {
|
|
615
|
+
if (!byId.has(row.id))
|
|
616
|
+
byId.set(row.id, row);
|
|
617
|
+
};
|
|
618
|
+
for (const job of this.jobs.values())
|
|
619
|
+
add(recentOf(job, false));
|
|
620
|
+
for (const job of this.archive.all())
|
|
621
|
+
add(recentOf(job, false));
|
|
622
|
+
for (const row of this.journal.foreignRows()) {
|
|
623
|
+
add({
|
|
624
|
+
id: row.jobId,
|
|
625
|
+
status: "running",
|
|
626
|
+
laneId: row.laneId,
|
|
627
|
+
startedAt: row.startedAt,
|
|
628
|
+
endedAt: undefined,
|
|
629
|
+
elsewhere: true,
|
|
630
|
+
...(row.label === undefined ? {} : { label: row.label }),
|
|
631
|
+
});
|
|
632
|
+
}
|
|
633
|
+
return [...byId.values()].sort(newestFirst).slice(0, Math.max(0, limit));
|
|
634
|
+
}
|
|
635
|
+
runningElsewhere(id) {
|
|
636
|
+
if (this.jobs.has(id))
|
|
637
|
+
return undefined;
|
|
638
|
+
const row = this.journal.foreign(id);
|
|
639
|
+
if (row?.owner === undefined)
|
|
640
|
+
return undefined;
|
|
641
|
+
return {
|
|
642
|
+
laneId: row.laneId,
|
|
643
|
+
...(row.spec === undefined ? {} : { spec: row.spec }),
|
|
644
|
+
startedAt: row.startedAt,
|
|
645
|
+
pid: row.owner.pid,
|
|
646
|
+
};
|
|
647
|
+
}
|
|
505
648
|
list() {
|
|
506
|
-
return [...this.jobs.values()].sort(
|
|
649
|
+
return [...this.jobs.values()].sort(newestFirst);
|
|
507
650
|
}
|
|
508
651
|
complete(id, run, semanticFailure, relay) {
|
|
509
652
|
const job = this.jobs.get(id);
|