@bluewombat/slot-kit 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,99 @@
1
+ # Slot kit
2
+
3
+ What a slot needs to answer the Transformer that spawned it.
4
+
5
+ A slot is an opaque command. Implementer spawns a Builder and its Gates,
6
+ FeatureBreakdown spawns a Planner, and each one reads argv and writes **one JSON
7
+ line on stdout**. That is the whole contract, and nothing here is required to
8
+ meet it: a shell script that prints the right line is a Gate. This package is
9
+ the plumbing every slot written in Node would otherwise write again — and it is
10
+ what keeps the shipped slots from each growing their own version of it.
11
+
12
+ The behaviour a slot must have is specified where its caller is:
13
+ [Implementer](../../kernel/implementer/SPECS.md) for Builders and Gates,
14
+ [FeatureBreakdown](../../kernel/feature-breakdown/SPECS.md) for Planners.
15
+ Slots that use this kit: [`@bluewombat/slots`](../../plugins/slots/README.md).
16
+
17
+ ## Install
18
+
19
+ ```bash
20
+ npm install @bluewombat/slot-kit
21
+ ```
22
+
23
+ ## A Gate
24
+
25
+ ```js
26
+ #!/usr/bin/env node
27
+ import { GATE_FLAGS, emitVerdict, ownArgv } from "@bluewombat/slot-kit";
28
+
29
+ const globs = ownArgv(process.argv, GATE_FLAGS);
30
+ if (globs.length === 0) {
31
+ emitVerdict("fail-blocking", "This Gate needs at least one glob.");
32
+ process.exit(0);
33
+ }
34
+ emitVerdict("pass");
35
+ ```
36
+
37
+ `ownArgv` is the first thing a slot needs: it is spawned with its own options
38
+ first and the caller's flags appended, and it must not trip over the second set.
39
+
40
+ ## What it holds
41
+
42
+ | Area | Exports |
43
+ | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
44
+ | argv | `ownArgv`, `splitRunner`, `take`, `stageOf`, `GATE_FLAGS`, `BUILDER_FLAGS`, `PLANNER_FLAGS` |
45
+ | options | `parseOptions` — a spec of flags, with choices, fallbacks and repeatable ones |
46
+ | stdout | `emitVerdict`, `emitFailure`, `emitPlan`, `emitRefusal` |
47
+ | agent CLIs | `findExecutable`, `runAgent`, `readResult`, `finishRun`, `failureOf` |
48
+ | prompts | `renderPrompt`, `readTemplate`, `PROMPT_RULES` — fill is generic; each role owns its names |
49
+ | roles | `parseRole`, `loadPrompt`, `loadRules`, `fillPrompt`, `spawnFilled`, `transcriptArgs`, `ROLE_OPTIONS` — a role fills its template and hands it to the agent after `--` |
50
+ | transcript | `openTranscript`, `transcriptFor`, `TRANSCRIPT_PARTS` |
51
+ | plans | `checkPlan` |
52
+ | paths | `pathMatchesGlob` |
53
+
54
+ Each `emit*` takes an optional `write`, which is how they are tested without a
55
+ process. Everything else is a plain function over its arguments; `finishRun` is
56
+ the one exception, and ends the process on purpose.
57
+
58
+ ## The three roles
59
+
60
+ | Role | Spawned by | Answers |
61
+ | ------- | ---------------- | ----------------------------------------------------------------------------- |
62
+ | Planner | FeatureBreakdown | `{"subtasks":[…]}`, or `{"outcome":"refused",…}` for an unsplittable one |
63
+ | Builder | Implementer | Nothing on a pass — the workspace is the answer. `{"outcome":…}` on a failure |
64
+ | Gate | Implementer | `{"verdict":"pass"}`, or `fail-retryable` / `fail-blocking` with a `report` |
65
+
66
+ A verdict is not an exit code. A Gate that exits non-zero without a line on
67
+ stdout has not answered.
68
+
69
+ ## Stack
70
+
71
+ Repository stack — TypeScript, Node 24.20, Biome, `node:test`. See
72
+ [docs/DEVELOPMENT.md](../../../docs/DEVELOPMENT.md).
73
+
74
+ ## Commands (development)
75
+
76
+ | Task | Command |
77
+ | --------- | ---------------- |
78
+ | Lint | `npm run lint` |
79
+ | Format | `npm run format` |
80
+ | Typecheck | `npm run tsc` |
81
+ | Test | `npm test` |
82
+ | Build | `npm run build` |
83
+
84
+ ## Layout
85
+
86
+ ```
87
+ src/
88
+ index.ts the whole surface
89
+ argv.ts who each argv token belongs to
90
+ options.ts a slot's own flags
91
+ emit.ts the one line on stdout
92
+ agent.ts find, run, and read an agent CLI
93
+ finish.ts how a finished agent run classifies
94
+ prompt.ts generic fill, rules, agent prompt (already rendered)
95
+ role.ts parse a role, fill its template, spawn the agent after `--`
96
+ transcript.ts one file per turn, when a Project asks for one
97
+ plan.ts whether a Plan can be acted on
98
+ glob.ts path globs
99
+ ```
@@ -0,0 +1,70 @@
1
+ /**
2
+ * What every slot that drives an agent CLI needs, and nothing about any one of
3
+ * them. A Builder and a Planner answer different contracts; finding a binary,
4
+ * running it and reading its result is the same work twice.
5
+ */
6
+ /**
7
+ * First executable among `names`, looked up name by name so a precise name
8
+ * anywhere wins over a generic one early on PATH. PATH first, then the
9
+ * directories an installer is known to use.
10
+ */
11
+ export declare function findExecutable(names: readonly string[], extraDirs?: readonly string[]): string | undefined;
12
+ export type AgentRun = {
13
+ /** Absent when the CLI never started. */
14
+ code?: number | null | undefined;
15
+ signal?: NodeJS.Signals | null | undefined;
16
+ /** Set when the CLI never started. */
17
+ error?: Error | undefined;
18
+ stdout: string;
19
+ stderr: string;
20
+ /** Both streams in arrival order. */
21
+ output: string;
22
+ startedAt: Date;
23
+ endedAt: Date;
24
+ durationMs: number;
25
+ };
26
+ export type AgentInvocation = {
27
+ file: string;
28
+ args: readonly string[];
29
+ cwd: string;
30
+ };
31
+ /**
32
+ * Run the agent to completion, streaming its output to stderr as it comes so
33
+ * an operator can watch. stdout stays the contract channel of the slot.
34
+ *
35
+ * Resolves with `output` — both streams in arrival order, which is what a
36
+ * failure report should quote — `stdout` alone, which is what a structured
37
+ * `--output-format` has to be parsed from, and `stderr` alone, which is where
38
+ * an agent says what it did.
39
+ */
40
+ export declare function runAgent({ file, args, cwd }: AgentInvocation): Promise<AgentRun>;
41
+ /**
42
+ * What an agent CLI writes on stdout so the role that spawned it can classify
43
+ * the run. Dates and `Error` do not survive JSON, so they are strings here.
44
+ */
45
+ export type SerializedRun = {
46
+ name: string;
47
+ bin: string;
48
+ code: number | null;
49
+ signal: string | null;
50
+ error?: string;
51
+ stdout: string;
52
+ stderr: string;
53
+ output: string;
54
+ startedAt: string;
55
+ endedAt: string;
56
+ durationMs: number;
57
+ };
58
+ /** The JSON an agent CLI writes after a vendor run. */
59
+ export declare function serializeRun(run: AgentRun, about: {
60
+ name: string;
61
+ bin: string;
62
+ }): SerializedRun;
63
+ /**
64
+ * Rebuild the run an agent CLI serialized. `undefined` when the payload is not
65
+ * one — a pre-run refusal is `{ error }` with no `startedAt`.
66
+ */
67
+ export declare function deserializeRun(raw: Record<string, unknown>): AgentRun | undefined;
68
+ /** The CLI's own result object: the last line of stdout that is one. */
69
+ export declare function readResult(stdout: string): Record<string, unknown> | undefined;
70
+ //# sourceMappingURL=agent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AAEH;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,SAAS,GAAE,SAAS,MAAM,EAAO,GAChC,MAAM,GAAG,SAAS,CAgBpB;AAED,MAAM,MAAM,QAAQ,GAAG;IACrB,yCAAyC;IACzC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC;IAC3C,sCAAsC;IACtC,KAAK,CAAC,EAAE,KAAK,GAAG,SAAS,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,qCAAqC;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,IAAI,CAAC;IAChB,OAAO,EAAE,IAAI,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACxB,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF;;;;;;;;GAQG;AACH,wBAAgB,QAAQ,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,eAAe,GAAG,OAAO,CAAC,QAAQ,CAAC,CAqDhF;AAED;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,uDAAuD;AACvD,wBAAgB,YAAY,CAAC,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,aAAa,CAc/F;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,QAAQ,GAAG,SAAS,CAgBjF;AAED,wEAAwE;AACxE,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAiB9E"}
package/dist/agent.js ADDED
@@ -0,0 +1,147 @@
1
+ import { spawn } from "node:child_process";
2
+ import { accessSync, constants } from "node:fs";
3
+ import { delimiter, join } from "node:path";
4
+ /**
5
+ * What every slot that drives an agent CLI needs, and nothing about any one of
6
+ * them. A Builder and a Planner answer different contracts; finding a binary,
7
+ * running it and reading its result is the same work twice.
8
+ */
9
+ /**
10
+ * First executable among `names`, looked up name by name so a precise name
11
+ * anywhere wins over a generic one early on PATH. PATH first, then the
12
+ * directories an installer is known to use.
13
+ */
14
+ export function findExecutable(names, extraDirs = []) {
15
+ const dirs = [...(process.env.PATH ?? "").split(delimiter), ...extraDirs].filter((dir) => dir.length > 0);
16
+ for (const name of names) {
17
+ for (const dir of dirs) {
18
+ const candidate = join(dir, name);
19
+ try {
20
+ accessSync(candidate, constants.X_OK);
21
+ return candidate;
22
+ }
23
+ catch {
24
+ // try the next directory
25
+ }
26
+ }
27
+ }
28
+ return undefined;
29
+ }
30
+ /**
31
+ * Run the agent to completion, streaming its output to stderr as it comes so
32
+ * an operator can watch. stdout stays the contract channel of the slot.
33
+ *
34
+ * Resolves with `output` — both streams in arrival order, which is what a
35
+ * failure report should quote — `stdout` alone, which is what a structured
36
+ * `--output-format` has to be parsed from, and `stderr` alone, which is where
37
+ * an agent says what it did.
38
+ */
39
+ export function runAgent({ file, args, cwd }) {
40
+ return new Promise((resolve) => {
41
+ const startedAt = new Date();
42
+ const child = spawn(file, [...args], { cwd, stdio: ["ignore", "pipe", "pipe"] });
43
+ let stdout = "";
44
+ let stderr = "";
45
+ let output = "";
46
+ let settled = false;
47
+ const settle = (result) => {
48
+ if (settled) {
49
+ return;
50
+ }
51
+ settled = true;
52
+ process.off("SIGTERM", stop);
53
+ process.off("SIGINT", stop);
54
+ const endedAt = new Date();
55
+ resolve({
56
+ stdout,
57
+ output,
58
+ ...result,
59
+ stderr,
60
+ startedAt,
61
+ endedAt,
62
+ durationMs: endedAt.getTime() - startedAt.getTime(),
63
+ });
64
+ };
65
+ const stop = () => {
66
+ child.kill("SIGKILL");
67
+ };
68
+ process.on("SIGTERM", stop);
69
+ process.on("SIGINT", stop);
70
+ child.stdout?.setEncoding("utf8");
71
+ child.stderr?.setEncoding("utf8");
72
+ child.stdout?.on("data", (chunk) => {
73
+ stdout += chunk;
74
+ output += chunk;
75
+ process.stderr.write(chunk);
76
+ });
77
+ child.stderr?.on("data", (chunk) => {
78
+ stderr += chunk;
79
+ output += chunk;
80
+ process.stderr.write(chunk);
81
+ });
82
+ child.on("error", (error) => {
83
+ settle({ error, stdout, output });
84
+ });
85
+ child.on("exit", (code, signal) => {
86
+ settle({ code, signal, stdout, output });
87
+ });
88
+ });
89
+ }
90
+ /** The JSON an agent CLI writes after a vendor run. */
91
+ export function serializeRun(run, about) {
92
+ return {
93
+ name: about.name,
94
+ bin: about.bin,
95
+ code: run.code ?? null,
96
+ signal: run.signal ?? null,
97
+ ...(run.error === undefined ? {} : { error: run.error.message }),
98
+ stdout: run.stdout,
99
+ stderr: run.stderr,
100
+ output: run.output,
101
+ startedAt: run.startedAt.toISOString(),
102
+ endedAt: run.endedAt.toISOString(),
103
+ durationMs: run.durationMs,
104
+ };
105
+ }
106
+ /**
107
+ * Rebuild the run an agent CLI serialized. `undefined` when the payload is not
108
+ * one — a pre-run refusal is `{ error }` with no `startedAt`.
109
+ */
110
+ export function deserializeRun(raw) {
111
+ if (typeof raw.startedAt !== "string" || typeof raw.endedAt !== "string") {
112
+ return undefined;
113
+ }
114
+ const signal = raw.signal;
115
+ return {
116
+ code: typeof raw.code === "number" ? raw.code : null,
117
+ signal: typeof signal === "string" ? signal : null,
118
+ ...(typeof raw.error === "string" ? { error: new Error(raw.error) } : {}),
119
+ stdout: typeof raw.stdout === "string" ? raw.stdout : "",
120
+ stderr: typeof raw.stderr === "string" ? raw.stderr : "",
121
+ output: typeof raw.output === "string" ? raw.output : "",
122
+ startedAt: new Date(raw.startedAt),
123
+ endedAt: new Date(raw.endedAt),
124
+ durationMs: typeof raw.durationMs === "number" ? raw.durationMs : 0,
125
+ };
126
+ }
127
+ /** The CLI's own result object: the last line of stdout that is one. */
128
+ export function readResult(stdout) {
129
+ const lines = stdout.split("\n").filter((line) => line.trim().length > 0);
130
+ for (let i = lines.length - 1; i >= 0; i--) {
131
+ const line = lines[i];
132
+ if (line === undefined) {
133
+ continue;
134
+ }
135
+ try {
136
+ const parsed = JSON.parse(line);
137
+ if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
138
+ return parsed;
139
+ }
140
+ }
141
+ catch {
142
+ // not this line
143
+ }
144
+ }
145
+ return undefined;
146
+ }
147
+ //# sourceMappingURL=agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent.js","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"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"}
package/dist/argv.d.ts ADDED
@@ -0,0 +1,43 @@
1
+ /**
2
+ * A slot is spawned with two argv sections: its own options, written by the
3
+ * Project, then the flags the Transformer appends about the work at hand. The
4
+ * slot never chose the second set and must not trip over it, so it needs to
5
+ * know which tokens are whose.
6
+ */
7
+ /** Flags Implementer appends after a Gate's own argv. */
8
+ export declare const GATE_FLAGS: ReadonlySet<string>;
9
+ /** Flags Implementer appends after a Builder's own argv. */
10
+ export declare const BUILDER_FLAGS: ReadonlySet<string>;
11
+ /** Flags FeatureBreakdown appends after a Planner's own argv. */
12
+ export declare const PLANNER_FLAGS: ReadonlySet<string>;
13
+ export declare const PUBLISHER_FLAGS: ReadonlySet<string>;
14
+ export declare const REFRESHER_FLAGS: ReadonlySet<string>;
15
+ /** Flags Host appends after a Describer's own argv. */
16
+ export declare const MESSAGE_FLAGS: ReadonlySet<string>;
17
+ /**
18
+ * Argv tokens that belong to the slot, not to the Transformer that spawned it.
19
+ *
20
+ * `caller` is that Transformer's flag set — `GATE_FLAGS`, `BUILDER_FLAGS`,
21
+ * `PLANNER_FLAGS`, `PUBLISHER_FLAGS` or
22
+ * `REFRESHER_FLAGS`. Each of them takes a value, so a match consumes two tokens.
23
+ */
24
+ export declare function ownArgv(argv: readonly string[], caller: ReadonlySet<string>): string[];
25
+ /**
26
+ * The Project's `--` splits this slot's own flags from the agent command it
27
+ * hands the rendered prompt to.
28
+ *
29
+ * Absent, or with nothing after it, there is no agent to run: a role that
30
+ * builds a prompt has nowhere to send it.
31
+ */
32
+ export declare function splitRunner(tokens: readonly string[]): {
33
+ ok: true;
34
+ own: string[];
35
+ runner: string[];
36
+ } | {
37
+ ok: false;
38
+ };
39
+ /** The value after `flag`, or nothing when the flag is absent or last. */
40
+ export declare function take(argv: readonly string[], flag: string): string | undefined;
41
+ /** What a Gate is looking at, when it makes a difference to the answer. */
42
+ export declare function stageOf(argv: readonly string[]): string;
43
+ //# sourceMappingURL=argv.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"argv.d.ts","sourceRoot":"","sources":["../src/argv.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,yDAAyD;AACzD,eAAO,MAAM,UAAU,EAAE,WAAW,CAAC,MAAM,CAOzC,CAAC;AAEH,4DAA4D;AAC5D,eAAO,MAAM,aAAa,EAAE,WAAW,CAAC,MAAM,CAQ5C,CAAC;AAEH,iEAAiE;AACjE,eAAO,MAAM,aAAa,EAAE,WAAW,CAAC,MAAM,CAK5C,CAAC;AAEH,eAAO,MAAM,eAAe,EAAE,WAAW,CAAC,MAAM,CAA0C,CAAC;AAE3F,eAAO,MAAM,eAAe,EAAE,WAAW,CAAC,MAAM,CAAyB,CAAC;AAE1E,uDAAuD;AACvD,eAAO,MAAM,aAAa,EAAE,WAAW,CAAC,MAAM,CAK5C,CAAC;AAEH;;;;;;GAMG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,MAAM,EAAE,CActF;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,SAAS,MAAM,EAAE,GACxB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,GAAG,EAAE,MAAM,EAAE,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAA;CAAE,CAU/D;AAED,0EAA0E;AAC1E,wBAAgB,IAAI,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAG9E;AAED,2EAA2E;AAC3E,wBAAgB,OAAO,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAGvD"}
package/dist/argv.js ADDED
@@ -0,0 +1,92 @@
1
+ /**
2
+ * A slot is spawned with two argv sections: its own options, written by the
3
+ * Project, then the flags the Transformer appends about the work at hand. The
4
+ * slot never chose the second set and must not trip over it, so it needs to
5
+ * know which tokens are whose.
6
+ */
7
+ /** Flags Implementer appends after a Gate's own argv. */
8
+ export const GATE_FLAGS = new Set([
9
+ "--id",
10
+ "--attempt",
11
+ "--gate-id",
12
+ "--intention",
13
+ "--definition-of-done",
14
+ "--stage",
15
+ ]);
16
+ /** Flags Implementer appends after a Builder's own argv. */
17
+ export const BUILDER_FLAGS = new Set([
18
+ "--id",
19
+ "--attempt",
20
+ "--intention",
21
+ "--definition-of-done",
22
+ "--report",
23
+ "--report-from",
24
+ "--context",
25
+ ]);
26
+ /** Flags FeatureBreakdown appends after a Planner's own argv. */
27
+ export const PLANNER_FLAGS = new Set([
28
+ "--key",
29
+ "--intention",
30
+ "--max-units",
31
+ "--title",
32
+ ]);
33
+ export const PUBLISHER_FLAGS = new Set(["--id", "--ref", "--target"]);
34
+ export const REFRESHER_FLAGS = new Set(["--target"]);
35
+ /** Flags Host appends after a Describer's own argv. */
36
+ export const MESSAGE_FLAGS = new Set([
37
+ "--id",
38
+ "--title",
39
+ "--intention",
40
+ "--target",
41
+ ]);
42
+ /**
43
+ * Argv tokens that belong to the slot, not to the Transformer that spawned it.
44
+ *
45
+ * `caller` is that Transformer's flag set — `GATE_FLAGS`, `BUILDER_FLAGS`,
46
+ * `PLANNER_FLAGS`, `PUBLISHER_FLAGS` or
47
+ * `REFRESHER_FLAGS`. Each of them takes a value, so a match consumes two tokens.
48
+ */
49
+ export function ownArgv(argv, caller) {
50
+ const out = [];
51
+ for (let i = 2; i < argv.length; i++) {
52
+ const token = argv[i];
53
+ if (token === undefined) {
54
+ continue;
55
+ }
56
+ if (caller.has(token)) {
57
+ i += 1;
58
+ continue;
59
+ }
60
+ out.push(token);
61
+ }
62
+ return out;
63
+ }
64
+ /**
65
+ * The Project's `--` splits this slot's own flags from the agent command it
66
+ * hands the rendered prompt to.
67
+ *
68
+ * Absent, or with nothing after it, there is no agent to run: a role that
69
+ * builds a prompt has nowhere to send it.
70
+ */
71
+ export function splitRunner(tokens) {
72
+ const at = tokens.indexOf("--");
73
+ if (at < 0) {
74
+ return { ok: false };
75
+ }
76
+ const runner = tokens.slice(at + 1);
77
+ if (runner.length === 0) {
78
+ return { ok: false };
79
+ }
80
+ return { ok: true, own: tokens.slice(0, at), runner };
81
+ }
82
+ /** The value after `flag`, or nothing when the flag is absent or last. */
83
+ export function take(argv, flag) {
84
+ const index = argv.indexOf(flag);
85
+ return index < 0 ? undefined : argv[index + 1];
86
+ }
87
+ /** What a Gate is looking at, when it makes a difference to the answer. */
88
+ export function stageOf(argv) {
89
+ const at = argv.indexOf("--stage");
90
+ return at < 0 ? "unit" : (argv[at + 1] ?? "unit");
91
+ }
92
+ //# sourceMappingURL=argv.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"argv.js","sourceRoot":"","sources":["../src/argv.ts"],"names":[],"mappings":"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"}
package/dist/emit.d.ts ADDED
@@ -0,0 +1,61 @@
1
+ /**
2
+ * The one line a slot puts on stdout.
3
+ *
4
+ * stdout is the contract channel and carries nothing else: whatever a slot has
5
+ * to say to a watching operator goes to stderr. Each role answers a different
6
+ * shape, so each has its own function rather than one that takes a kind.
7
+ */
8
+ /** A Gate's answer on the work in front of it. */
9
+ export type Verdict = "pass" | "fail-retryable" | "fail-blocking";
10
+ /** A Builder's answer when its pass did not produce work. */
11
+ export type Failure = Exclude<Verdict, "pass">;
12
+ export type Write = (line: string) => void;
13
+ /** A Gate's verdict, with the report the next Attempt is given. */
14
+ export declare function emitVerdict(verdict: Verdict, report?: string, write?: Write): void;
15
+ /** A Builder's failure. A pass says nothing: the workspace is the answer. */
16
+ export declare function emitFailure(outcome: Failure, report: string, write?: Write): void;
17
+ /** A Plan on stdout, and nothing else on it. */
18
+ export declare function emitPlan(subtasks: unknown, write?: Write): void;
19
+ /**
20
+ * Where the work now is, for the Authority to read.
21
+ *
22
+ * The reference is opaque above this line: a branch name, a directory, a URL —
23
+ * whatever the Publisher put in front of the judge, named the way that judge
24
+ * asks for it.
25
+ */
26
+ export declare function emitPublication(ref: string, write?: Write): void;
27
+ /**
28
+ * The work could not be placed where the Authority reads.
29
+ *
30
+ * A refusal, not a crash: the Submission does not happen and the reason travels
31
+ * back. A Publisher that could not run at all exits non-zero and says why on
32
+ * stderr instead.
33
+ */
34
+ export declare function emitPublishRefusal(reason: string, write?: Write): void;
35
+ /**
36
+ * What a commit should say: a subject line, and the body under it when there
37
+ * is one. Host writes the subject as the first line and the body after a
38
+ * blank one; how a Project words either is the slot's, not Host's.
39
+ */
40
+ export declare function emitMessage(subject: string, body?: string, write?: Write): void;
41
+ /**
42
+ * The work line copy now holds what the Authority holds.
43
+ *
44
+ * Nothing to bring back is a success, not a special case: a Refresher that
45
+ * found the copy already up to date answers the same way.
46
+ */
47
+ export declare function emitRefreshed(write?: Write): void;
48
+ /**
49
+ * The copy could not be brought up to date.
50
+ *
51
+ * Work started on a copy that is behind is built on a version that no longer
52
+ * exists, so this refusal stops the pass rather than letting it run.
53
+ */
54
+ export declare function emitRefreshRefusal(reason: string, write?: Write): void;
55
+ /**
56
+ * The FeatureStandard cannot be split. This is a verdict on the intention, not
57
+ * a failure of the slot: a slot that could not answer must exit non-zero and
58
+ * say why on stderr, so the Breakdown is retried rather than the feature buried.
59
+ */
60
+ export declare function emitRefusal(reason: string, write?: Write): void;
61
+ //# sourceMappingURL=emit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emit.d.ts","sourceRoot":"","sources":["../src/emit.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,kDAAkD;AAClD,MAAM,MAAM,OAAO,GAAG,MAAM,GAAG,gBAAgB,GAAG,eAAe,CAAC;AAElE,6DAA6D;AAC7D,MAAM,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;AAE/C,MAAM,MAAM,KAAK,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;AAM3C,mEAAmE;AACnE,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAK,EAAE,KAAK,GAAE,KAAgB,GAAG,IAAI,CAExF;AAED,6EAA6E;AAC7E,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,GAAE,KAAgB,GAAG,IAAI,CAE3F;AAED,gDAAgD;AAChD,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,GAAE,KAAgB,GAAG,IAAI,CAEzE;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,GAAE,KAAgB,GAAG,IAAI,CAE1E;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,GAAE,KAAgB,GAAG,IAAI,CAEhF;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,GAAE,KAAgB,GAAG,IAAI,CAEzF;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,GAAE,KAAgB,GAAG,IAAI,CAE3D;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,GAAE,KAAgB,GAAG,IAAI,CAEhF;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,GAAE,KAAgB,GAAG,IAAI,CAEzE"}
package/dist/emit.js ADDED
@@ -0,0 +1,77 @@
1
+ /**
2
+ * The one line a slot puts on stdout.
3
+ *
4
+ * stdout is the contract channel and carries nothing else: whatever a slot has
5
+ * to say to a watching operator goes to stderr. Each role answers a different
6
+ * shape, so each has its own function rather than one that takes a kind.
7
+ */
8
+ const toStdout = (line) => {
9
+ process.stdout.write(line);
10
+ };
11
+ /** A Gate's verdict, with the report the next Attempt is given. */
12
+ export function emitVerdict(verdict, report = "", write = toStdout) {
13
+ write(`${JSON.stringify({ verdict, report })}\n`);
14
+ }
15
+ /** A Builder's failure. A pass says nothing: the workspace is the answer. */
16
+ export function emitFailure(outcome, report, write = toStdout) {
17
+ write(`${JSON.stringify({ outcome, report })}\n`);
18
+ }
19
+ /** A Plan on stdout, and nothing else on it. */
20
+ export function emitPlan(subtasks, write = toStdout) {
21
+ write(`${JSON.stringify({ subtasks })}\n`);
22
+ }
23
+ /**
24
+ * Where the work now is, for the Authority to read.
25
+ *
26
+ * The reference is opaque above this line: a branch name, a directory, a URL —
27
+ * whatever the Publisher put in front of the judge, named the way that judge
28
+ * asks for it.
29
+ */
30
+ export function emitPublication(ref, write = toStdout) {
31
+ write(`${JSON.stringify({ ref })}\n`);
32
+ }
33
+ /**
34
+ * The work could not be placed where the Authority reads.
35
+ *
36
+ * A refusal, not a crash: the Submission does not happen and the reason travels
37
+ * back. A Publisher that could not run at all exits non-zero and says why on
38
+ * stderr instead.
39
+ */
40
+ export function emitPublishRefusal(reason, write = toStdout) {
41
+ write(`${JSON.stringify({ outcome: "refused", reason })}\n`);
42
+ }
43
+ /**
44
+ * What a commit should say: a subject line, and the body under it when there
45
+ * is one. Host writes the subject as the first line and the body after a
46
+ * blank one; how a Project words either is the slot's, not Host's.
47
+ */
48
+ export function emitMessage(subject, body, write = toStdout) {
49
+ write(`${JSON.stringify(body === undefined ? { subject } : { subject, body })}\n`);
50
+ }
51
+ /**
52
+ * The work line copy now holds what the Authority holds.
53
+ *
54
+ * Nothing to bring back is a success, not a special case: a Refresher that
55
+ * found the copy already up to date answers the same way.
56
+ */
57
+ export function emitRefreshed(write = toStdout) {
58
+ write(`${JSON.stringify({ ok: true })}\n`);
59
+ }
60
+ /**
61
+ * The copy could not be brought up to date.
62
+ *
63
+ * Work started on a copy that is behind is built on a version that no longer
64
+ * exists, so this refusal stops the pass rather than letting it run.
65
+ */
66
+ export function emitRefreshRefusal(reason, write = toStdout) {
67
+ write(`${JSON.stringify({ outcome: "refused", reason })}\n`);
68
+ }
69
+ /**
70
+ * The FeatureStandard cannot be split. This is a verdict on the intention, not
71
+ * a failure of the slot: a slot that could not answer must exit non-zero and
72
+ * say why on stderr, so the Breakdown is retried rather than the feature buried.
73
+ */
74
+ export function emitRefusal(reason, write = toStdout) {
75
+ write(`${JSON.stringify({ outcome: "refused", code: "not-specifiable", reason })}\n`);
76
+ }
77
+ //# sourceMappingURL=emit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emit.js","sourceRoot":"","sources":["../src/emit.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAUH,MAAM,QAAQ,GAAU,CAAC,IAAI,EAAE,EAAE;IAC/B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AAC7B,CAAC,CAAC;AAEF,mEAAmE;AACnE,MAAM,UAAU,WAAW,CAAC,OAAgB,EAAE,MAAM,GAAG,EAAE,EAAE,QAAe,QAAQ;IAChF,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC;AACpD,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,WAAW,CAAC,OAAgB,EAAE,MAAc,EAAE,QAAe,QAAQ;IACnF,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC;AACpD,CAAC;AAED,gDAAgD;AAChD,MAAM,UAAU,QAAQ,CAAC,QAAiB,EAAE,QAAe,QAAQ;IACjE,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,CAAC,IAAI,CAAC,CAAC;AAC7C,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAAC,GAAW,EAAE,QAAe,QAAQ;IAClE,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;AACxC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAc,EAAE,QAAe,QAAQ;IACxE,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC;AAC/D,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,OAAe,EAAE,IAAa,EAAE,QAAe,QAAQ;IACjF,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC;AACrF,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,QAAe,QAAQ;IACnD,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC;AAC7C,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAc,EAAE,QAAe,QAAQ;IACxE,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC;AAC/D,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,MAAc,EAAE,QAAe,QAAQ;IACjE,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,iBAAiB,EAAE,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC;AACxF,CAAC"}
@@ -0,0 +1,26 @@
1
+ import type { AgentRun } from "./agent.js";
2
+ import type { Failure } from "./emit.js";
3
+ export type FinishedRun = {
4
+ run: AgentRun;
5
+ bin: string;
6
+ name: string;
7
+ };
8
+ /**
9
+ * How a finished run reads: what to answer, and the report to answer it with.
10
+ *
11
+ * Separate from `finishRun` because the classification is the part worth
12
+ * checking, and `finishRun` ends the process.
13
+ */
14
+ export declare function failureOf(run: AgentRun, bin: string, name: string): {
15
+ outcome: Failure;
16
+ report: string;
17
+ };
18
+ /**
19
+ * Answer the Builder contract for a finished run, then leave.
20
+ *
21
+ * Every agent Builder ends here so they classify the same way: exit 0 is a
22
+ * completed pass, and everything else is `fail-blocking` when the CLI itself is
23
+ * unusable, `fail-retryable` when the agent failed at the work.
24
+ */
25
+ export declare function finishRun({ run, bin, name }: FinishedRun): never;
26
+ //# sourceMappingURL=finish.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"finish.d.ts","sourceRoot":"","sources":["../src/finish.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAgBzC,MAAM,MAAM,WAAW,GAAG;IAAE,GAAG,EAAE,QAAQ,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvE;;;;;GAKG;AACH,wBAAgB,SAAS,CACvB,GAAG,EAAE,QAAQ,EACb,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,GACX;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAYtC;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,WAAW,GAAG,KAAK,CAOhE"}