@openagt/agent-runner 0.0.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/LICENSE +21 -0
- package/bin/agent-runner +11 -0
- package/dist/cli.d.ts +19 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +208 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +17 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +62 -0
- package/dist/config.js.map +1 -0
- package/dist/ended.d.ts +66 -0
- package/dist/ended.d.ts.map +1 -0
- package/dist/ended.js +114 -0
- package/dist/ended.js.map +1 -0
- package/dist/git-host.d.ts +31 -0
- package/dist/git-host.d.ts.map +1 -0
- package/dist/git-host.js +26 -0
- package/dist/git-host.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/init.d.ts +39 -0
- package/dist/init.d.ts.map +1 -0
- package/dist/init.js +104 -0
- package/dist/init.js.map +1 -0
- package/dist/live-card.d.ts +27 -0
- package/dist/live-card.d.ts.map +1 -0
- package/dist/live-card.js +56 -0
- package/dist/live-card.js.map +1 -0
- package/dist/names.d.ts +12 -0
- package/dist/names.d.ts.map +1 -0
- package/dist/names.js +12 -0
- package/dist/names.js.map +1 -0
- package/dist/parent.d.ts +47 -0
- package/dist/parent.d.ts.map +1 -0
- package/dist/parent.js +52 -0
- package/dist/parent.js.map +1 -0
- package/dist/records.d.ts +81 -0
- package/dist/records.d.ts.map +1 -0
- package/dist/records.js +89 -0
- package/dist/records.js.map +1 -0
- package/dist/run-lock.d.ts +29 -0
- package/dist/run-lock.d.ts.map +1 -0
- package/dist/run-lock.js +80 -0
- package/dist/run-lock.js.map +1 -0
- package/dist/run.d.ts +169 -0
- package/dist/run.d.ts.map +1 -0
- package/dist/run.js +462 -0
- package/dist/run.js.map +1 -0
- package/dist/runner.d.ts +148 -0
- package/dist/runner.d.ts.map +1 -0
- package/dist/runner.js +208 -0
- package/dist/runner.js.map +1 -0
- package/dist/sweep.d.ts +46 -0
- package/dist/sweep.d.ts.map +1 -0
- package/dist/sweep.js +83 -0
- package/dist/sweep.js.map +1 -0
- package/dist/test-repo.d.ts +18 -0
- package/dist/test-repo.d.ts.map +1 -0
- package/dist/test-repo.js +49 -0
- package/dist/test-repo.js.map +1 -0
- package/package.json +54 -0
package/dist/records.js
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { deleteRun, writeRun } from '@openagt/skill-logs';
|
|
2
|
+
/**
|
|
3
|
+
* A run in flight is a run record (#1774): the `logs` skill's card on the project's `agent-data`
|
|
4
|
+
* branch, written before the agent is spawned with `status: running` and this tool's own mark
|
|
5
|
+
* under `caller`, and written again when the run ends — same id, same file — with how it went.
|
|
6
|
+
* One file for the run's whole life, and every machine that shares the branch reads the same
|
|
7
|
+
* running cards (a scheduler counts them against its caps). No pid is held anywhere: a restart
|
|
8
|
+
* loses nothing.
|
|
9
|
+
*
|
|
10
|
+
* A running card from another machine is that machine's: only its own sweep, or a person, changes
|
|
11
|
+
* it. A machine that never comes back leaves its card running, on purpose: nothing here guesses that a run it cannot see is dead.
|
|
12
|
+
*/
|
|
13
|
+
/** How far a run takes its work when its agent finishes: a commit, its branch pushed, its pull request, or the request set to merge once its checks pass. */
|
|
14
|
+
export const PUBLISH_LEVELS = ['commit', 'branch', 'pr', 'merge'];
|
|
15
|
+
export function isPublish(value) {
|
|
16
|
+
return PUBLISH_LEVELS.includes(value);
|
|
17
|
+
}
|
|
18
|
+
/** The mark a card carries, or `undefined` for a run this tool did not start. */
|
|
19
|
+
export function runnerMark(card) {
|
|
20
|
+
const mark = card.caller?.['runner'];
|
|
21
|
+
if (!mark || typeof mark !== 'object')
|
|
22
|
+
return undefined;
|
|
23
|
+
const { host, pid, then, publish, parent, base, baseCommit } = mark;
|
|
24
|
+
if (typeof host !== 'string')
|
|
25
|
+
return undefined;
|
|
26
|
+
return { host, ...(typeof pid === 'number' ? { pid } : {}), ...lasting({ then, publish, parent, base, baseCommit }) };
|
|
27
|
+
}
|
|
28
|
+
/** What a mark keeps for the run's whole life, a resume included: its follow-up, its publish level, its parent, where it started. */
|
|
29
|
+
export function lasting(mark) {
|
|
30
|
+
return {
|
|
31
|
+
...(typeof mark.then === 'string' ? { then: mark.then } : {}),
|
|
32
|
+
...(isPublish(mark.publish) ? { publish: mark.publish } : {}),
|
|
33
|
+
...(typeof mark.parent === 'string' ? { parent: mark.parent } : {}),
|
|
34
|
+
...(typeof mark.base === 'string' ? { base: mark.base } : {}),
|
|
35
|
+
...(typeof mark.baseCommit === 'string' ? { baseCommit: mark.baseCommit } : {}),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/** The card a run starts with. */
|
|
39
|
+
export function markerCard(run) {
|
|
40
|
+
return {
|
|
41
|
+
id: run.id,
|
|
42
|
+
startedAt: run.startedAt,
|
|
43
|
+
status: 'running',
|
|
44
|
+
intent: run.prompt,
|
|
45
|
+
driver: run.driver,
|
|
46
|
+
...(run.model !== undefined ? { model: run.model } : {}),
|
|
47
|
+
// `host` as the run's live card has it too: a reader tells this machine's runs from another's by it.
|
|
48
|
+
caller: { runner: run.mark, host: run.mark.host, ...forReaders(run.mark) },
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* What a reader of the card finds beside `host`, outside this tool's mark: the run's parent, the
|
|
53
|
+
* branch it was started from when it was told one, and the commit its own work begins at, which
|
|
54
|
+
* its changes are measured from.
|
|
55
|
+
*/
|
|
56
|
+
export function forReaders(mark) {
|
|
57
|
+
return { ...(mark.parent !== undefined ? { parent: mark.parent } : {}), ...(mark.base !== undefined ? { base: mark.base } : {}), ...(mark.baseCommit !== undefined ? { baseCommit: mark.baseCommit } : {}) };
|
|
58
|
+
}
|
|
59
|
+
/** What the reclaim of a run's checkout is told: the commit its branch was made at, when its mark names one. */
|
|
60
|
+
export function startOf(card) {
|
|
61
|
+
const from = runnerMark(card)?.baseCommit;
|
|
62
|
+
return from !== undefined ? { from } : {};
|
|
63
|
+
}
|
|
64
|
+
/** Put the run's card on the branch before its agent exists. The outcome says whether it reached origin. */
|
|
65
|
+
export function writeMarker(repo, card, deps = {}) {
|
|
66
|
+
return writeRun(repo, card, [], deps);
|
|
67
|
+
}
|
|
68
|
+
/** Take a marker back: a scheduler lost a cap to another machine's marker, so this run never starts. */
|
|
69
|
+
export function withdrawMarker(repo, id, deps = {}) {
|
|
70
|
+
return deleteRun(repo, id, deps);
|
|
71
|
+
}
|
|
72
|
+
/** Record how a run went: its card and its diary, over the marker. */
|
|
73
|
+
export function recordRun(repo, card, diary, deps = {}) {
|
|
74
|
+
return writeRun(repo, card, diary, deps);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Record a run again without its branch when the reclaim deleted that branch: one that held
|
|
78
|
+
* nothing goes with its checkout, and the record must not name a branch that is gone. Written
|
|
79
|
+
* after the reclaim rather than reclaiming first, so the record never says `running` with no
|
|
80
|
+
* checkout behind it. Nothing is written when the branch stayed.
|
|
81
|
+
*/
|
|
82
|
+
export async function recordBranchGone(repo, card, diary, deleted, deps = {}) {
|
|
83
|
+
if (card.branch === undefined || !deleted?.includes(card.branch))
|
|
84
|
+
return undefined;
|
|
85
|
+
const branchless = { ...card };
|
|
86
|
+
delete branchless.branch;
|
|
87
|
+
return recordRun(repo, branchless, diary, deps);
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=records.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"records.js","sourceRoot":"","sources":["../src/records.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAkD,MAAM,qBAAqB,CAAA;AAEzG;;;;;;;;;;GAUG;AAEH,6JAA6J;AAC7J,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,CAAU,CAAA;AAG1E,MAAM,UAAU,SAAS,CAAC,KAAc;IACtC,OAAQ,cAAqC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;AAC/D,CAAC;AAoBD,iFAAiF;AACjF,MAAM,UAAU,UAAU,CAAC,IAAa;IACtC,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,CAAA;IACpC,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAA;IACvD,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,IAA+B,CAAA;IAC9F,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAA;IAC9C,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,OAAO,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,EAAE,CAAA;AACvH,CAAC;AAED,qIAAqI;AACrI,MAAM,UAAU,OAAO,CAAC,IAAmG;IACzH,OAAO;QACL,GAAG,CAAC,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7D,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7D,GAAG,CAAC,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACnE,GAAG,CAAC,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7D,GAAG,CAAC,OAAO,IAAI,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAChF,CAAA;AACH,CAAC;AAED,kCAAkC;AAClC,MAAM,UAAU,UAAU,CAAC,GAAwG;IACjI,OAAO;QACL,EAAE,EAAE,GAAG,CAAC,EAAE;QACV,SAAS,EAAE,GAAG,CAAC,SAAS;QACxB,MAAM,EAAE,SAAS;QACjB,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,GAAG,CAAC,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACxD,qGAAqG;QACrG,MAAM,EAAE,EAAE,MAAM,EAAE,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;KAC3E,CAAA;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,IAAwD;IACjF,OAAO,EAAE,GAAG,CAAC,IAAI,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,IAAI,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAA;AAC9M,CAAC;AAED,gHAAgH;AAChH,MAAM,UAAU,OAAO,CAAC,IAAa;IACnC,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,EAAE,UAAU,CAAA;IACzC,OAAO,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;AAC3C,CAAC;AAED,4GAA4G;AAC5G,MAAM,UAAU,WAAW,CAAC,IAAY,EAAE,IAAa,EAAE,IAAI,GAAa,EAAE;IAC1E,OAAO,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,CAAC,CAAA;AACvC,CAAC;AAED,wGAAwG;AACxG,MAAM,UAAU,cAAc,CAAC,IAAY,EAAE,EAAU,EAAE,IAAI,GAAa,EAAE;IAC1E,OAAO,SAAS,CAAC,IAAI,EAAE,EAAE,EAAE,IAAI,CAAC,CAAA;AAClC,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,SAAS,CAAC,IAAY,EAAE,IAAa,EAAE,KAA8B,EAAE,IAAI,GAAa,EAAE;IACxG,OAAO,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,CAAA;AAC1C,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,IAAY,EAAE,IAAa,EAAE,KAA8B,EAAE,OAAsC,EAAE,IAAI,GAAa,EAAE;IAC7J,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,OAAO,SAAS,CAAA;IAClF,MAAM,UAAU,GAAY,EAAE,GAAG,IAAI,EAAE,CAAA;IACvC,OAAO,UAAU,CAAC,MAAM,CAAA;IACxB,OAAO,SAAS,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,IAAI,CAAC,CAAA;AACjD,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One process per run at a time (#1774). A run's process holds its run's lock from before it
|
|
3
|
+
* touches the record until it has let the checkout go. A second process for the same run waits
|
|
4
|
+
* until the holder is gone: a resume that comes while the run still records and reclaims, or two
|
|
5
|
+
* resumes started together by two messages. The sweep leaves a run alone while its lock is held.
|
|
6
|
+
*
|
|
7
|
+
* The lock is a file under the tool's directory holding the pid of its holder. A pid that is not
|
|
8
|
+
* alive holds nothing, so a process that died leaves no lock that matters. Per machine, like the
|
|
9
|
+
* pid in it. Two waiters taking over a dead holder's lock in the same instant can both believe
|
|
10
|
+
* they hold it; a holder that dies is already the sweep's case.
|
|
11
|
+
*/
|
|
12
|
+
/** Whether `pid` is a live process on this host. A pid on another host is unknowable here. */
|
|
13
|
+
export declare function isPidAlive(pid: number): boolean;
|
|
14
|
+
export declare function runLockPath(repo: string, id: string): string;
|
|
15
|
+
/** Where a spawned run's stderr lands, so a run that dies before writing anything leaves a trace. */
|
|
16
|
+
export declare function runStderrPath(repo: string, id: string): string;
|
|
17
|
+
/** The live pid holding the run's lock, or `undefined` when none does. */
|
|
18
|
+
export declare function lockHolder(repo: string, id: string, isAlive: (pid: number) => boolean): Promise<number | undefined>;
|
|
19
|
+
/** Take the run's lock for `pid`, waiting while another live process holds it. A lock already naming `pid` is its own. */
|
|
20
|
+
export declare function acquireRunLock(repo: string, id: string, opts: {
|
|
21
|
+
pid: number;
|
|
22
|
+
isAlive: (pid: number) => boolean;
|
|
23
|
+
pollMs?: number;
|
|
24
|
+
}): Promise<void>;
|
|
25
|
+
/** Hand the lock `from` holds to the process `to`: a detached run's parent to the run's own process. */
|
|
26
|
+
export declare function handOverRunLock(repo: string, id: string, from: number, to: number): Promise<void>;
|
|
27
|
+
/** Let the lock go, when `pid` holds it. */
|
|
28
|
+
export declare function releaseRunLock(repo: string, id: string, pid: number): Promise<void>;
|
|
29
|
+
//# sourceMappingURL=run-lock.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-lock.d.ts","sourceRoot":"","sources":["../src/run-lock.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;GAUG;AAEH,8FAA8F;AAC9F,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAO/C;AAKD,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAE5D;AAED,qGAAqG;AACrG,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAE9D;AAQD,0EAA0E;AAC1E,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAGzH;AAED,0HAA0H;AAC1H,wBAAsB,cAAc,CAClC,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,EACV,IAAI,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GACxE,OAAO,CAAC,IAAI,CAAC,CAoBf;AAED,wGAAwG;AACxG,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEvG;AAED,4CAA4C;AAC5C,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEzF"}
|
package/dist/run-lock.js
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { mkdir, readFile, rm, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { dirname, join } from 'node:path';
|
|
3
|
+
import { excludeFromGit } from '@openagt/agent-data';
|
|
4
|
+
import { RUNNER_DIR, RUNS_DIR } from './names.js';
|
|
5
|
+
/**
|
|
6
|
+
* One process per run at a time (#1774). A run's process holds its run's lock from before it
|
|
7
|
+
* touches the record until it has let the checkout go. A second process for the same run waits
|
|
8
|
+
* until the holder is gone: a resume that comes while the run still records and reclaims, or two
|
|
9
|
+
* resumes started together by two messages. The sweep leaves a run alone while its lock is held.
|
|
10
|
+
*
|
|
11
|
+
* The lock is a file under the tool's directory holding the pid of its holder. A pid that is not
|
|
12
|
+
* alive holds nothing, so a process that died leaves no lock that matters. Per machine, like the
|
|
13
|
+
* pid in it. Two waiters taking over a dead holder's lock in the same instant can both believe
|
|
14
|
+
* they hold it; a holder that dies is already the sweep's case.
|
|
15
|
+
*/
|
|
16
|
+
/** Whether `pid` is a live process on this host. A pid on another host is unknowable here. */
|
|
17
|
+
export function isPidAlive(pid) {
|
|
18
|
+
try {
|
|
19
|
+
process.kill(pid, 0);
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
catch (err) {
|
|
23
|
+
return err.code === 'EPERM';
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/** How often a waiting process looks at the lock again. */
|
|
27
|
+
const POLL_MS = 500;
|
|
28
|
+
export function runLockPath(repo, id) {
|
|
29
|
+
return join(repo, RUNNER_DIR, RUNS_DIR, `${id}.lock`);
|
|
30
|
+
}
|
|
31
|
+
/** Where a spawned run's stderr lands, so a run that dies before writing anything leaves a trace. */
|
|
32
|
+
export function runStderrPath(repo, id) {
|
|
33
|
+
return join(repo, RUNNER_DIR, RUNS_DIR, `${id}.stderr`);
|
|
34
|
+
}
|
|
35
|
+
async function readHolder(repo, id) {
|
|
36
|
+
const raw = await readFile(runLockPath(repo, id), 'utf8').catch(() => undefined);
|
|
37
|
+
const pid = Number(raw?.trim());
|
|
38
|
+
return Number.isInteger(pid) && pid > 0 ? pid : undefined;
|
|
39
|
+
}
|
|
40
|
+
/** The live pid holding the run's lock, or `undefined` when none does. */
|
|
41
|
+
export async function lockHolder(repo, id, isAlive) {
|
|
42
|
+
const pid = await readHolder(repo, id);
|
|
43
|
+
return pid !== undefined && isAlive(pid) ? pid : undefined;
|
|
44
|
+
}
|
|
45
|
+
/** Take the run's lock for `pid`, waiting while another live process holds it. A lock already naming `pid` is its own. */
|
|
46
|
+
export async function acquireRunLock(repo, id, opts) {
|
|
47
|
+
const path = runLockPath(repo, id);
|
|
48
|
+
await mkdir(dirname(path), { recursive: true });
|
|
49
|
+
// Hidden from git: the tool's directory must not dirty the tree.
|
|
50
|
+
await excludeFromGit(repo, `/${RUNNER_DIR}`).catch(() => { });
|
|
51
|
+
for (;;) {
|
|
52
|
+
try {
|
|
53
|
+
await writeFile(path, `${opts.pid}\n`, { flag: 'wx' });
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
catch (err) {
|
|
57
|
+
if (err.code !== 'EEXIST')
|
|
58
|
+
throw err;
|
|
59
|
+
}
|
|
60
|
+
const holder = await readHolder(repo, id);
|
|
61
|
+
if (holder === opts.pid)
|
|
62
|
+
return;
|
|
63
|
+
if (holder === undefined || !opts.isAlive(holder)) {
|
|
64
|
+
await rm(path, { force: true });
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
await new Promise(resolve => setTimeout(resolve, opts.pollMs ?? POLL_MS));
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/** Hand the lock `from` holds to the process `to`: a detached run's parent to the run's own process. */
|
|
71
|
+
export async function handOverRunLock(repo, id, from, to) {
|
|
72
|
+
if ((await readHolder(repo, id)) === from)
|
|
73
|
+
await writeFile(runLockPath(repo, id), `${to}\n`);
|
|
74
|
+
}
|
|
75
|
+
/** Let the lock go, when `pid` holds it. */
|
|
76
|
+
export async function releaseRunLock(repo, id, pid) {
|
|
77
|
+
if ((await readHolder(repo, id)) === pid)
|
|
78
|
+
await rm(runLockPath(repo, id), { force: true });
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=run-lock.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-lock.js","sourceRoot":"","sources":["../src/run-lock.ts"],"names":[],"mappings":"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"}
|
package/dist/run.d.ts
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { type Driver } from '@openagt/agent-driver';
|
|
2
|
+
import { type GitRunner } from '@openagt/agent-data';
|
|
3
|
+
import { type LogsDeps, type RunStatus } from '@openagt/skill-logs';
|
|
4
|
+
import { type Publish } from './records.js';
|
|
5
|
+
import { type GitHost, type MergeOutcome } from './git-host.js';
|
|
6
|
+
import { type ParentDeps } from './parent.js';
|
|
7
|
+
/**
|
|
8
|
+
* One run (#1774): a checkout from the branches package, a session from agent-driver, the prompt
|
|
9
|
+
* once, and the agent's own loop to the end. No system prompt and no gates: the
|
|
10
|
+
* command's skill file is the whole instruction, and the agent publishes its own work, when asked
|
|
11
|
+
* to, through the skills in its checkout. How far it takes its work is the run's publish level
|
|
12
|
+
* (`run --publish <commit|branch|pr|merge>`), said in one sentence after the prompt: commit the work,
|
|
13
|
+
* and from there push the branch, open its pull request, or set it to merge once its checks pass.
|
|
14
|
+
* The sentence follows every message the agent is sent, a queued one too, and the record keeps it
|
|
15
|
+
* apart from the message. A run with no level gets its prompt as written, and its agent commits
|
|
16
|
+
* only when the prompt asks.
|
|
17
|
+
* This process records the run and reclaims the checkout when the
|
|
18
|
+
* agent stops; a run that dies is caught by the sweep, which a scheduler runs on every tick.
|
|
19
|
+
*
|
|
20
|
+
* The session keeps the run's live record itself, the card and the diary under `.the-framework/`
|
|
21
|
+
* in the checkout, in the run record's shape; this process adds its mark, the pid and the host,
|
|
22
|
+
* and copies the two files onto the branch unchanged when the run ends. What reaches the agent
|
|
23
|
+
* from outside comes through the session's inbox: a line waiting when a turn ends becomes the
|
|
24
|
+
* next turn; when the last turn ended on a question and nothing waited, the run ends `waiting`,
|
|
25
|
+
* keeps its checkout, and the answer resumes it (`resumeRun`): the same run, the same record,
|
|
26
|
+
* continued.
|
|
27
|
+
*
|
|
28
|
+
* SIGINT or SIGTERM to this process stops the run: the agent's whole process tree is ended
|
|
29
|
+
* through the driver, the run is recorded `stopped`, the checkout reclaimed. That is what a
|
|
30
|
+
* dashboard's Stop sends, the pid being on the live card; nothing else steers a run.
|
|
31
|
+
*
|
|
32
|
+
* One-shot: `agent-runner run <prompt>` runs on its own. A scheduler's tick spawns the same thing
|
|
33
|
+
* with the marker already written and the id chosen.
|
|
34
|
+
*
|
|
35
|
+
* A run may name a follow-up (`run --then <prompt>`): once it ends done with a pull request, a
|
|
36
|
+
* fresh agent, a run of its own with its own record, works on the same branch from the prompt,
|
|
37
|
+
* the first run's id after it. The first agent is told, in a line after its prompt, to publish its
|
|
38
|
+
* work without arming the pull request's merge, whatever level the run was given; the follow-up
|
|
39
|
+
* is given no level, its prompt says what it publishes; the follow-up ending done is when this
|
|
40
|
+
* process merges it, through the project's git host (`git-host.ts`). A follow-up that fails or is
|
|
41
|
+
* stopped leaves the request open, for a person.
|
|
42
|
+
*
|
|
43
|
+
* The pull request a run's branch has is read back the same way, through the git host the project
|
|
44
|
+
* declares; a project with no git host package records none.
|
|
45
|
+
*
|
|
46
|
+
* A run may be started for another run, its parent (`run --parent <id>`), and from a branch other
|
|
47
|
+
* than origin's default (`run --base <ref>`); both are on its record for its whole life. When it
|
|
48
|
+
* ends, however it ends, its parent is told (`parent.ts`).
|
|
49
|
+
*
|
|
50
|
+
* A run that makes its own branch writes down the commit the branch was made at, on its record
|
|
51
|
+
* for its whole life: the run's own work is what came after it, which is how it is still told
|
|
52
|
+
* apart once it is merged. A run given a branch that exists (a follow-up's) writes none: that
|
|
53
|
+
* branch's work began with another run.
|
|
54
|
+
*/
|
|
55
|
+
/** The detail a stopped run's record carries. */
|
|
56
|
+
export declare const STOPPED_DETAIL = "stopped by a signal to its process";
|
|
57
|
+
/** The sentence after a prompt that says how far to take the work, every level starting with the commit; how is the business of the skills in the checkout. */
|
|
58
|
+
export declare const PUBLISH_LINES: Readonly<Record<Publish, string>>;
|
|
59
|
+
/** The sentence when a follow-up is coming: the agent publishes its work, this process merges the request later. */
|
|
60
|
+
export declare const HOLD_MERGE_LINE = "When you finish, if you changed any file, commit your work, push your branch and open its pull request, but do not arm its merge: it is merged for you once a follow-up is done.";
|
|
61
|
+
/**
|
|
62
|
+
* The sentence a run adds after every prompt of its agent, the first and each message after it:
|
|
63
|
+
* that of its publish level, the hold sentence instead when the run names a follow-up, none for a
|
|
64
|
+
* run with neither. The session sends it after the prompt and writes it down apart from it, so a
|
|
65
|
+
* reader shows the person's words as the person wrote them.
|
|
66
|
+
*/
|
|
67
|
+
export declare function addedLine(publish: Publish | undefined, then: string | undefined): string | undefined;
|
|
68
|
+
/** Filesystem-safe, time-ordered id from an ISO start: the shape the dashboard sorts runs by. */
|
|
69
|
+
export declare function runIdFrom(startedAt: string): string;
|
|
70
|
+
export interface RunOptions {
|
|
71
|
+
/** What the agent is told, usually a slash command. */
|
|
72
|
+
prompt: string;
|
|
73
|
+
/** The run's id; minted from the start time when absent. */
|
|
74
|
+
id?: string;
|
|
75
|
+
/** Whether the run's marker is already on the branch: a scheduler's tick writes it before it spawns. A person's run marks itself. */
|
|
76
|
+
marked?: boolean;
|
|
77
|
+
/** The model the session starts on; the tool's own default when absent. */
|
|
78
|
+
model?: string;
|
|
79
|
+
driver: Driver;
|
|
80
|
+
/** The branch to work on, an existing one; a fresh `agent-<id>` when absent. */
|
|
81
|
+
branch?: string;
|
|
82
|
+
/** The pull request that branch already has: a follow-up's, so its end does not announce it as new. */
|
|
83
|
+
branchPr?: {
|
|
84
|
+
number: number;
|
|
85
|
+
url: string;
|
|
86
|
+
};
|
|
87
|
+
/** The follow-up's prompt: a fresh agent's once this run ends done with a pull request, this run's id after it. */
|
|
88
|
+
then?: string;
|
|
89
|
+
/** How far the agent publishes when it finishes; absent, only what the prompt itself asks. */
|
|
90
|
+
publish?: Publish;
|
|
91
|
+
/** The coding agent a follow-up run is on, given its id; this run's own when absent. */
|
|
92
|
+
nextDriver?: (id: string) => Driver;
|
|
93
|
+
/** The run this one is started for: told when this one ends. */
|
|
94
|
+
parent?: string;
|
|
95
|
+
/** The branch the run's fresh branch starts from; origin's default branch when absent. */
|
|
96
|
+
base?: string;
|
|
97
|
+
/** How an ended parent is continued, in its own process; absent, only a working parent is told. */
|
|
98
|
+
resume?: ParentDeps['resume'];
|
|
99
|
+
host?: string;
|
|
100
|
+
pid?: number;
|
|
101
|
+
/** Whether a pid is a live process here: what the run's lock asks of its holder. */
|
|
102
|
+
isAlive?: (pid: number) => boolean;
|
|
103
|
+
now?: () => Date;
|
|
104
|
+
git?: GitRunner;
|
|
105
|
+
/** The project's git host; the one the project declares when absent. */
|
|
106
|
+
gitHost?: GitHost;
|
|
107
|
+
logs?: LogsDeps;
|
|
108
|
+
log?: (line: string) => void;
|
|
109
|
+
}
|
|
110
|
+
export interface RunOutcome {
|
|
111
|
+
id: string;
|
|
112
|
+
status: Exclude<RunStatus, 'running'>;
|
|
113
|
+
branch?: string;
|
|
114
|
+
pr?: {
|
|
115
|
+
number: number;
|
|
116
|
+
url: string;
|
|
117
|
+
};
|
|
118
|
+
cost?: number;
|
|
119
|
+
/** Whether the checkout went once the remote had its branch, or stayed and why. */
|
|
120
|
+
checkout: {
|
|
121
|
+
reclaimed: true;
|
|
122
|
+
} | {
|
|
123
|
+
reclaimed: false;
|
|
124
|
+
reason: string;
|
|
125
|
+
};
|
|
126
|
+
detail?: string;
|
|
127
|
+
/** The follow-up run, when one ran, and how the merge of this run's pull request went when it ended done. */
|
|
128
|
+
then?: RunOutcome & {
|
|
129
|
+
merge?: MergeOutcome;
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
export declare function runCommand(repo: string, opts: RunOptions): Promise<RunOutcome>;
|
|
133
|
+
export interface ResumeOptions {
|
|
134
|
+
/** The run to continue: one that ended `waiting`, or any ended run whose session the driver can resume. */
|
|
135
|
+
id: string;
|
|
136
|
+
/** The user's words to the agent; or, with `answer`, absent. */
|
|
137
|
+
text?: string;
|
|
138
|
+
/** The chosen label or labels, answering the question the run's last turn asked. */
|
|
139
|
+
answer?: string;
|
|
140
|
+
driver: Driver;
|
|
141
|
+
/** The coding agent a follow-up run is on, given its id, when the run's record names a follow-up; this run's own when absent. */
|
|
142
|
+
nextDriver?: (id: string) => Driver;
|
|
143
|
+
/** How an ended parent is continued, in its own process; absent, only a working parent is told. */
|
|
144
|
+
resume?: ParentDeps['resume'];
|
|
145
|
+
model?: string;
|
|
146
|
+
host?: string;
|
|
147
|
+
pid?: number;
|
|
148
|
+
/** Whether a pid is a live process here: what the run's lock asks of its holder. */
|
|
149
|
+
isAlive?: (pid: number) => boolean;
|
|
150
|
+
now?: () => Date;
|
|
151
|
+
git?: GitRunner;
|
|
152
|
+
/** The project's git host; the one the project declares when absent. */
|
|
153
|
+
gitHost?: GitHost;
|
|
154
|
+
logs?: LogsDeps;
|
|
155
|
+
log?: (line: string) => void;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Continue an ended run: the same id, the same record, the same branch. The checkout is the one
|
|
159
|
+
* the run kept, or a new one attached to its branch; a branch that went with the checkout, for
|
|
160
|
+
* holding nothing, starts again from the base the record names, or origin's default branch. The session resumes by the id the
|
|
161
|
+
* record carries; the diary goes on from where it stopped. The prompt is the user's text, or the
|
|
162
|
+
* continuation of the question the run ended on with the given answer. The sentence of the publish
|
|
163
|
+
* level the record keeps is said again after it. A run whose work was landed, its branch gone
|
|
164
|
+
* with that, is no longer recorded as landed once it is on a branch made again: what it does from
|
|
165
|
+
* here is not. A follow-up the record names is still owed: the
|
|
166
|
+
* agent is told again not to arm the merge, and the follow-up runs once this ends done.
|
|
167
|
+
*/
|
|
168
|
+
export declare function resumeRun(repo: string, opts: ResumeOptions): Promise<RunOutcome>;
|
|
169
|
+
//# sourceMappingURL=run.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"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"}
|