fanout-cli 0.7.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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 elberacasa
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,42 @@
1
+ # fanout-cli
2
+
3
+ Let Claude Code lead the other coding-agent CLIs you already pay for.
4
+
5
+ Fanout is a local daemon and a Claude Code plugin. Claude plans the work; the other agents you have installed and
6
+ signed in — Codex, and Claude itself when you opt in — do pieces of it in parallel, each in its own git worktree.
7
+ Nothing merges until it has been reviewed by someone who did not write it, passed your project's own checks, and
8
+ been approved by you.
9
+
10
+ ## See it without an account
11
+
12
+ ```sh
13
+ npx fanout-cli demo
14
+ ```
15
+
16
+ Three simulated agents run a real mission on a throwaway repository, in real worktrees, through the real gate. No
17
+ sign-in, no API key, no network. It prints a local URL — open it to watch.
18
+
19
+ ## Use it for real
20
+
21
+ ```sh
22
+ npm install -g fanout-cli
23
+ fanout seat # what is installed on this machine, and what is signed in
24
+ fanout demo # the offline walkthrough
25
+ fanout help # everything else
26
+ ```
27
+
28
+ Then add the plugin so Claude Code can drive it. See
29
+ [the repository](https://github.com/elberacasa/fanout) for the current instructions.
30
+
31
+ ## What it will not do
32
+
33
+ - **It never touches your credentials.** Each agent runs through its vendor's own documented non-interactive mode,
34
+ on your machine, under your account. Fanout does not read, copy, store, proxy or reuse a session token, and does
35
+ not work around anyone's rate limits.
36
+ - **It never merges unreviewed work.** Review, your project's checks, and your approval must all have judged the
37
+ same revision of the same diff. A bug fix additionally needs a test proven to fail on the old code.
38
+ - **It never commits on your branch without you.** Agents work in isolated worktrees and cannot reach your files,
39
+ your secrets, or anything git ignores.
40
+ - **It sends nothing anywhere.** Your code, your prompts and the ledger stay on your machine. There is no telemetry.
41
+
42
+ Requires Node 22.18 or newer. MIT licensed.
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env node
2
+ import { main } from "./main.js";
3
+ /* The thin edge of the CLI: everything testable lives in main.ts, which takes its output as an argument. */
4
+ const code = await main(process.argv.slice(2), {
5
+ out: (text) => process.stdout.write(text),
6
+ err: (text) => process.stderr.write(text),
7
+ });
8
+ process.exitCode = code;
9
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,4GAA4G;AAE5G,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;IAC7C,GAAG,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC;IACzC,GAAG,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC;CAC1C,CAAC,CAAC;AACH,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC"}
package/dist/demo.d.ts ADDED
@@ -0,0 +1,32 @@
1
+ import type { PlanLine } from "fanout-core";
2
+ import type { ScenarioInput } from "fanout-adapter-fake";
3
+ /** A small repository worth changing: three areas, one seeded bug, one commit. */
4
+ export declare function buildDemoRepo(root: string): string;
5
+ export declare const DEMO_GOAL = "Add CSV export and fix the December date bug";
6
+ /**
7
+ * Three lines that touch three different areas.
8
+ *
9
+ * One of them is marked `fixesBug`, which is the flag the merge gate holds to the fourth non-negotiable: that
10
+ * line cannot merge without a test proven to fail on the old code. The demo exists partly to show that refusal.
11
+ */
12
+ export declare function demoLines(): PlanLine[];
13
+ /**
14
+ * What each simulated agent does, second by second.
15
+ *
16
+ * `timeScale` is the only dishonesty about time and it is the useful kind: a real run takes minutes and nobody
17
+ * watches a demo for minutes. The phases, the tool calls and the files are what a real run of this shape does.
18
+ */
19
+ export declare function demoScenario(line: PlanLine): ScenarioInput;
20
+ /**
21
+ * The claim check the demo shows, written here rather than asked of anyone.
22
+ *
23
+ * Marked `simulated` all the way through to the screen. A real check needs a real second vendor and a
24
+ * subscription; inventing one and presenting it as read would be faking the single thing this product claims to
25
+ * do, which is worse than having no demo at all.
26
+ */
27
+ export declare function demoClaims(): {
28
+ claim: string;
29
+ verdict: "confirmed" | "refuted" | "unclear";
30
+ evidence: string;
31
+ }[];
32
+ //# sourceMappingURL=demo.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"demo.d.ts","sourceRoot":"","sources":["../src/demo.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAezD,kFAAkF;AAClF,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAoClD;AAED,eAAO,MAAM,SAAS,iDAAiD,CAAC;AAExE;;;;;GAKG;AACH,wBAAgB,SAAS,IAAI,QAAQ,EAAE,CA2CtC;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,QAAQ,GAAG,aAAa,CAoF1D;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,IAAI;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,WAAW,GAAG,SAAS,GAAG,SAAS,CAAC;IAC7C,QAAQ,EAAE,MAAM,CAAC;CAClB,EAAE,CAkBF"}
package/dist/demo.js ADDED
@@ -0,0 +1,207 @@
1
+ import { execFileSync } from "node:child_process";
2
+ import { mkdirSync, rmSync, writeFileSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ /*
5
+ * A whole mission, on a machine with no accounts on it.
6
+ *
7
+ * Everything here is the real thing except the thinking. Real git worktrees, the real safety gate, the real
8
+ * append-only ledger, real diffs collected from real files — driven by the `fake` seat, which is a genuine CLI
9
+ * speaking the genuine protocol and taking a script instead of a model. Nothing is stubbed out inside the daemon,
10
+ * because a demo that exercised a special path would be a demo of something nobody ships.
11
+ *
12
+ * It is honest about the one thing it cannot do. A cold reader's verdicts need a real second vendor; the demo's
13
+ * are written here, and every surface that shows them says `simulated` out loud. Faking the one claim the product
14
+ * makes would be the single most dishonest thing this repository could contain.
15
+ */
16
+ /** A small repository worth changing: three areas, one seeded bug, one commit. */
17
+ export function buildDemoRepo(root) {
18
+ rmSync(root, { recursive: true, force: true });
19
+ mkdirSync(join(root, "src", "api"), { recursive: true });
20
+ mkdirSync(join(root, "src", "ui"), { recursive: true });
21
+ mkdirSync(join(root, "docs"), { recursive: true });
22
+ writeFileSync(join(root, "src", "api", "orders.ts"), "export interface Order {\n id: string;\n total: number;\n}\n\n" +
23
+ "export function ordersFor(customer: string): Order[] {\n return [];\n}\n");
24
+ writeFileSync(join(root, "src", "api", "dates.ts"), "/** Formats a day. Off by one in December: the bug this demo fixes. */\n" +
25
+ "export function monthOf(date: Date): number {\n return date.getMonth();\n}\n");
26
+ writeFileSync(join(root, "src", "ui", "table.ts"), "export const columns = ['id', 'total'];\n");
27
+ writeFileSync(join(root, "docs", "orders.md"), "# Orders\n\nThe orders API.\n");
28
+ writeFileSync(join(root, "package.json"), `${JSON.stringify({ name: "demo-shop", private: true, scripts: { check: "echo ok" } }, null, 2)}\n`);
29
+ const git = (args) => {
30
+ execFileSync("git", args, {
31
+ cwd: root,
32
+ stdio: "ignore",
33
+ env: { PATH: process.env["PATH"] ?? "", HOME: process.env["HOME"] ?? "", GIT_CONFIG_NOSYSTEM: "1" },
34
+ });
35
+ };
36
+ git(["init", "--quiet", "-b", "main"]);
37
+ git(["config", "user.email", "demo@example.invalid"]);
38
+ git(["config", "user.name", "Fanout demo"]);
39
+ git(["add", "-A"]);
40
+ git(["commit", "--quiet", "-m", "the shop, before the crew arrives"]);
41
+ return root;
42
+ }
43
+ export const DEMO_GOAL = "Add CSV export and fix the December date bug";
44
+ /**
45
+ * Three lines that touch three different areas.
46
+ *
47
+ * One of them is marked `fixesBug`, which is the flag the merge gate holds to the fourth non-negotiable: that
48
+ * line cannot merge without a test proven to fail on the old code. The demo exists partly to show that refusal.
49
+ */
50
+ export function demoLines() {
51
+ return [
52
+ {
53
+ id: "api",
54
+ title: "CSV export endpoint",
55
+ role: "builder",
56
+ prompt: "Add GET /orders.csv, streaming rows and escaping quotes.",
57
+ seat: { id: "fake", model: "demo" },
58
+ // Narrowed to the file it writes. `src/api/**` swallowed the dates line's scope, and the safety gate
59
+ // refused the plan — on the product's own demo, which is the best argument for the check there is.
60
+ scope: { write: ["src/api/csv.ts"] },
61
+ dependsOn: [],
62
+ checks: ["npm run check"],
63
+ fixesBug: false,
64
+ },
65
+ {
66
+ id: "dates",
67
+ title: "Fix the December month bug",
68
+ role: "builder",
69
+ prompt: "monthOf() is off by one in December. Fix it and prove it with a test.",
70
+ seat: { id: "fake", model: "demo" },
71
+ scope: { write: ["src/api/dates.ts", "src/api/dates.test.ts"] },
72
+ dependsOn: [],
73
+ checks: ["npm run check"],
74
+ fixesBug: true,
75
+ },
76
+ {
77
+ id: "ui",
78
+ title: "Export button",
79
+ role: "builder",
80
+ /*
81
+ * The one line that asks for a seat this machine does not have. Nothing here fakes the consequence: the
82
+ * demo's crew really is the simulated seat alone, so the router really does move this line and really does
83
+ * say why — which is the behaviour worth showing, and the only honest way to show it offline.
84
+ */
85
+ prompt: "Add the export column and a button that hits the new endpoint.",
86
+ seat: { id: "codex", model: "gpt-5-codex" },
87
+ scope: { write: ["src/ui/**"] },
88
+ dependsOn: [],
89
+ checks: ["npm run check"],
90
+ fixesBug: false,
91
+ },
92
+ ];
93
+ }
94
+ /**
95
+ * What each simulated agent does, second by second.
96
+ *
97
+ * `timeScale` is the only dishonesty about time and it is the useful kind: a real run takes minutes and nobody
98
+ * watches a demo for minutes. The phases, the tool calls and the files are what a real run of this shape does.
99
+ */
100
+ export function demoScenario(line) {
101
+ const scenarios = {
102
+ api: {
103
+ steps: [
104
+ { phase: "reading", delayMs: 900 },
105
+ { tool: "read", summary: "src/api/orders.ts", delayMs: 700 },
106
+ { phase: "coding", delayMs: 600 },
107
+ {
108
+ tool: "edit",
109
+ summary: "add the csv writer",
110
+ delayMs: 1400,
111
+ write: {
112
+ "src/api/csv.ts": "import type { Order } from './orders.ts';\n\n" +
113
+ "/** One row per order. A quote inside a field is doubled, per RFC 4180. */\n" +
114
+ "export function toCsv(orders: Order[]): string {\n" +
115
+ " const rows = orders.map((order) => `${quote(order.id)},${order.total}`);\n" +
116
+ " return ['id,total', ...rows].join('\\n');\n}\n\n" +
117
+ "function quote(value: string): string {\n" +
118
+ " return value.includes(',') || value.includes('\"')\n" +
119
+ ' ? `"${value.split(\'"\').join(\'""\')}"`\n : value;\n}\n',
120
+ },
121
+ },
122
+ { phase: "testing", delayMs: 900 },
123
+ { tool: "shell", summary: "npm run check", delayMs: 1100 },
124
+ { usage: 3 },
125
+ { phase: "reporting", delayMs: 400 },
126
+ ],
127
+ report: "Added toCsv() with RFC 4180 quoting. Streaming is left for a follow-up.",
128
+ timeScale: 1,
129
+ },
130
+ dates: {
131
+ steps: [
132
+ { phase: "reading", delayMs: 800 },
133
+ { phase: "coding", delayMs: 900 },
134
+ {
135
+ tool: "edit",
136
+ summary: "months are zero-based",
137
+ delayMs: 1200,
138
+ write: {
139
+ "src/api/dates.ts": "/** Formats a day. getMonth() is zero-based, which is where December went wrong. */\n" +
140
+ "export function monthOf(date: Date): number {\n return date.getMonth() + 1;\n}\n",
141
+ "src/api/dates.test.ts": "import { monthOf } from './dates.ts';\n\n" +
142
+ "// Fails on the old code: it returned 11 for December.\n" +
143
+ "test('December is the twelfth month', () => {\n" +
144
+ " expect(monthOf(new Date('2026-12-01'))).toBe(12);\n});\n",
145
+ },
146
+ },
147
+ { phase: "testing", delayMs: 1000 },
148
+ { tool: "shell", summary: "npm run check", delayMs: 900 },
149
+ { usage: 2 },
150
+ { phase: "reporting", delayMs: 400 },
151
+ ],
152
+ report: "monthOf() was zero-based. Fixed, with a test that fails on the old code.",
153
+ timeScale: 1,
154
+ },
155
+ ui: {
156
+ steps: [
157
+ { phase: "reading", delayMs: 1000 },
158
+ { phase: "coding", delayMs: 1500 },
159
+ {
160
+ tool: "edit",
161
+ summary: "export column and button",
162
+ delayMs: 1600,
163
+ write: {
164
+ "src/ui/table.ts": "export const columns = ['id', 'total', 'export'];\n",
165
+ "src/ui/export-button.ts": "export function exportButton(): string {\n" +
166
+ " return '<button data-href=\"/orders.csv\">Export CSV</button>';\n}\n",
167
+ },
168
+ },
169
+ { usage: 4 },
170
+ { phase: "reporting", delayMs: 600 },
171
+ ],
172
+ report: "Added the column and the button.",
173
+ timeScale: 1,
174
+ },
175
+ };
176
+ const scenario = scenarios[line.id];
177
+ if (scenario === undefined)
178
+ throw new Error(`the demo has no script for line "${line.id}"`);
179
+ return scenario;
180
+ }
181
+ /**
182
+ * The claim check the demo shows, written here rather than asked of anyone.
183
+ *
184
+ * Marked `simulated` all the way through to the screen. A real check needs a real second vendor and a
185
+ * subscription; inventing one and presenting it as read would be faking the single thing this product claims to
186
+ * do, which is worse than having no demo at all.
187
+ */
188
+ export function demoClaims() {
189
+ return [
190
+ {
191
+ claim: "The December fix comes with a test that fails on the old code",
192
+ verdict: "confirmed",
193
+ evidence: "dates.test.ts expects 12; the old monthOf returned 11 · src/api/dates.ts:3",
194
+ },
195
+ {
196
+ claim: "Nothing outside the three declared scopes was touched",
197
+ verdict: "confirmed",
198
+ evidence: "every changed path falls inside a declared write scope",
199
+ },
200
+ {
201
+ claim: "toCsv escapes every field that needs it",
202
+ verdict: "refuted",
203
+ evidence: "a field containing a newline is not quoted · src/api/csv.ts:10",
204
+ },
205
+ ];
206
+ }
207
+ //# sourceMappingURL=demo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"demo.js","sourceRoot":"","sources":["../src/demo.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC3D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAIjC;;;;;;;;;;;GAWG;AAEH,kFAAkF;AAClF,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,MAAM,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAC/C,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACzD,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACxD,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAEnD,aAAa,CACX,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,WAAW,CAAC,EACrC,kEAAkE;QAChE,2EAA2E,CAC9E,CAAC;IACF,aAAa,CACX,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,CAAC,EACpC,0EAA0E;QACxE,+EAA+E,CAClF,CAAC;IACF,aAAa,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,CAAC,EAAE,2CAA2C,CAAC,CAAC;IAChG,aAAa,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,+BAA+B,CAAC,CAAC;IAChF,aAAa,CACX,IAAI,CAAC,IAAI,EAAE,cAAc,CAAC,EAC1B,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CACpG,CAAC;IAEF,MAAM,GAAG,GAAG,CAAC,IAAc,EAAQ,EAAE;QACnC,YAAY,CAAC,KAAK,EAAE,IAAI,EAAE;YACxB,GAAG,EAAE,IAAI;YACT,KAAK,EAAE,QAAQ;YACf,GAAG,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,mBAAmB,EAAE,GAAG,EAAE;SACpG,CAAC,CAAC;IACL,CAAC,CAAC;IACF,GAAG,CAAC,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;IACvC,GAAG,CAAC,CAAC,QAAQ,EAAE,YAAY,EAAE,sBAAsB,CAAC,CAAC,CAAC;IACtD,GAAG,CAAC,CAAC,QAAQ,EAAE,WAAW,EAAE,aAAa,CAAC,CAAC,CAAC;IAC5C,GAAG,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC;IACnB,GAAG,CAAC,CAAC,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,mCAAmC,CAAC,CAAC,CAAC;IACtE,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,CAAC,MAAM,SAAS,GAAG,8CAA8C,CAAC;AAExE;;;;;GAKG;AACH,MAAM,UAAU,SAAS;IACvB,OAAO;QACL;YACE,EAAE,EAAE,KAAK;YACT,KAAK,EAAE,qBAAqB;YAC5B,IAAI,EAAE,SAAS;YACf,MAAM,EAAE,0DAA0D;YAClE,IAAI,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE;YACnC,qGAAqG;YACrG,mGAAmG;YACnG,KAAK,EAAE,EAAE,KAAK,EAAE,CAAC,gBAAgB,CAAC,EAAE;YACpC,SAAS,EAAE,EAAE;YACb,MAAM,EAAE,CAAC,eAAe,CAAC;YACzB,QAAQ,EAAE,KAAK;SAChB;QACD;YACE,EAAE,EAAE,OAAO;YACX,KAAK,EAAE,4BAA4B;YACnC,IAAI,EAAE,SAAS;YACf,MAAM,EAAE,uEAAuE;YAC/E,IAAI,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE;YACnC,KAAK,EAAE,EAAE,KAAK,EAAE,CAAC,kBAAkB,EAAE,uBAAuB,CAAC,EAAE;YAC/D,SAAS,EAAE,EAAE;YACb,MAAM,EAAE,CAAC,eAAe,CAAC;YACzB,QAAQ,EAAE,IAAI;SACf;QACD;YACE,EAAE,EAAE,IAAI;YACR,KAAK,EAAE,eAAe;YACtB,IAAI,EAAE,SAAS;YACf;;;;eAIG;YACH,MAAM,EAAE,gEAAgE;YACxE,IAAI,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE;YAC3C,KAAK,EAAE,EAAE,KAAK,EAAE,CAAC,WAAW,CAAC,EAAE;YAC/B,SAAS,EAAE,EAAE;YACb,MAAM,EAAE,CAAC,eAAe,CAAC;YACzB,QAAQ,EAAE,KAAK;SAChB;KACF,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAAC,IAAc;IACzC,MAAM,SAAS,GAAkC;QAC/C,GAAG,EAAE;YACH,KAAK,EAAE;gBACL,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,EAAE;gBAClC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,mBAAmB,EAAE,OAAO,EAAE,GAAG,EAAE;gBAC5D,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,EAAE;gBACjC;oBACE,IAAI,EAAE,MAAM;oBACZ,OAAO,EAAE,oBAAoB;oBAC7B,OAAO,EAAE,IAAI;oBACb,KAAK,EAAE;wBACL,gBAAgB,EACd,+CAA+C;4BAC/C,8EAA8E;4BAC9E,oDAAoD;4BACpD,8EAA8E;4BAC9E,oDAAoD;4BACpD,2CAA2C;4BAC3C,wDAAwD;4BACxD,iEAAiE;qBACpE;iBACF;gBACD,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,EAAE;gBAClC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,OAAO,EAAE,IAAI,EAAE;gBAC1D,EAAE,KAAK,EAAE,CAAC,EAAE;gBACZ,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,GAAG,EAAE;aACrC;YACD,MAAM,EAAE,yEAAyE;YACjF,SAAS,EAAE,CAAC;SACb;QACD,KAAK,EAAE;YACL,KAAK,EAAE;gBACL,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,EAAE;gBAClC,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,EAAE;gBACjC;oBACE,IAAI,EAAE,MAAM;oBACZ,OAAO,EAAE,uBAAuB;oBAChC,OAAO,EAAE,IAAI;oBACb,KAAK,EAAE;wBACL,kBAAkB,EAChB,uFAAuF;4BACvF,mFAAmF;wBACrF,uBAAuB,EACrB,2CAA2C;4BAC3C,0DAA0D;4BAC1D,iDAAiD;4BACjD,4DAA4D;qBAC/D;iBACF;gBACD,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE;gBACnC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,OAAO,EAAE,GAAG,EAAE;gBACzD,EAAE,KAAK,EAAE,CAAC,EAAE;gBACZ,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,GAAG,EAAE;aACrC;YACD,MAAM,EAAE,0EAA0E;YAClF,SAAS,EAAE,CAAC;SACb;QACD,EAAE,EAAE;YACF,KAAK,EAAE;gBACL,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE;gBACnC,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE;gBAClC;oBACE,IAAI,EAAE,MAAM;oBACZ,OAAO,EAAE,0BAA0B;oBACnC,OAAO,EAAE,IAAI;oBACb,KAAK,EAAE;wBACL,iBAAiB,EAAE,qDAAqD;wBACxE,yBAAyB,EACvB,4CAA4C;4BAC5C,wEAAwE;qBAC3E;iBACF;gBACD,EAAE,KAAK,EAAE,CAAC,EAAE;gBACZ,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,GAAG,EAAE;aACrC;YACD,MAAM,EAAE,kCAAkC;YAC1C,SAAS,EAAE,CAAC;SACb;KACF,CAAC;IAEF,MAAM,QAAQ,GAAG,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACpC,IAAI,QAAQ,KAAK,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,oCAAoC,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;IAC5F,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,UAAU;IAKxB,OAAO;QACL;YACE,KAAK,EAAE,+DAA+D;YACtE,OAAO,EAAE,WAAW;YACpB,QAAQ,EAAE,4EAA4E;SACvF;QACD;YACE,KAAK,EAAE,uDAAuD;YAC9D,OAAO,EAAE,WAAW;YACpB,QAAQ,EAAE,wDAAwD;SACnE;QACD;YACE,KAAK,EAAE,yCAAyC;YAChD,OAAO,EAAE,SAAS;YAClB,QAAQ,EAAE,gEAAgE;SAC3E;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { type ProjectionState, type SeatInfo, type SeatPolicy } from "fanout-core";
2
+ export declare function crewTable(seats: readonly SeatInfo[], policy?: SeatPolicy): string;
3
+ export declare function missionLines(state: ProjectionState, now?: Date): string;
4
+ //# sourceMappingURL=format.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,eAAe,EACpB,KAAK,QAAQ,EACb,KAAK,UAAU,EAChB,MAAM,aAAa,CAAC;AAarB,wBAAgB,SAAS,CAAC,KAAK,EAAE,SAAS,QAAQ,EAAE,EAAE,MAAM,GAAE,UAAyB,GAAG,MAAM,CA+B/F;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,eAAe,EAAE,GAAG,GAAE,IAAiB,GAAG,MAAM,CA6BnF"}
package/dist/format.js ADDED
@@ -0,0 +1,64 @@
1
+ import { elapsedMs, EMPTY_POLICY, formatDuration, silentMs, stanceFor, } from "fanout-core";
2
+ /*
3
+ * How the crew reads in a terminal. The rule everywhere: say what is known, say plainly what is not, and never let
4
+ * an unknown look like a yes.
5
+ */
6
+ const SIGN_IN = {
7
+ yes: "signed in",
8
+ no: "not signed in",
9
+ unknown: "unknown",
10
+ };
11
+ export function crewTable(seats, policy = EMPTY_POLICY) {
12
+ if (seats.length === 0)
13
+ return "No agent CLIs found on this machine.\n";
14
+ const rows = seats.map((seat) => ({
15
+ name: seat.displayName,
16
+ version: seat.version ?? "not installed",
17
+ state: seat.supported ? SIGN_IN[seat.signedIn] : seat.version === null ? "—" : "unsupported version",
18
+ ready: stanceFor(seat, policy).usable,
19
+ // "normal" is what a seat is when nobody has said anything, and printing it down every row would bury the
20
+ // one or two the owner actually decided about.
21
+ posture: stanceFor(seat, policy).posture === "normal" ? "" : stanceFor(seat, policy).posture,
22
+ // Most CLIs do not report a tier. An empty column says that better than a word like "unknown" repeated
23
+ // down the table, and the source travels with the value so nobody has to wonder who said it.
24
+ plan: seat.plan === null ? "" : `${seat.plan.name} (${seat.plan.source})`,
25
+ }));
26
+ const width = {
27
+ name: Math.max(...rows.map((row) => row.name.length)),
28
+ version: Math.max(...rows.map((row) => row.version.length)),
29
+ state: Math.max(...rows.map((row) => row.state.length)),
30
+ plan: Math.max(...rows.map((row) => row.plan.length)),
31
+ };
32
+ const lines = rows.map((row) => (` ${row.ready ? "•" : " "} ${row.name.padEnd(width.name)} ${row.version.padEnd(width.version)} ` +
33
+ `${row.state.padEnd(width.state)} ${row.plan.padEnd(width.plan)} ${row.posture}`).trimEnd());
34
+ const ready = rows.filter((row) => row.ready).length;
35
+ return `Crew on this machine (${ready} ready)\n${lines.join("\n")}\n`;
36
+ }
37
+ export function missionLines(state, now = new Date()) {
38
+ const missions = Object.values(state.missions);
39
+ if (missions.length === 0)
40
+ return "No missions yet.\n";
41
+ const lines = missions.map((mission) => {
42
+ const runs = Object.values(mission.runs);
43
+ const running = runs.filter((run) => run.status === "running" || run.status === "queued").length;
44
+ const merged = runs.filter((run) => run.status === "merged").length;
45
+ const waiting = runs.filter((run) => run.status === "done" && run.review === null).length;
46
+ // A mission where every working run has gone silent is the one worth walking back to the terminal for.
47
+ const quiet = runs.filter((run) => (silentMs(run, now) ?? 0) >= 60_000).length;
48
+ const longest = runs.reduce((most, run) => Math.max(most, elapsedMs(run, now) ?? 0), 0);
49
+ const parts = [
50
+ `${runs.length} run${runs.length === 1 ? "" : "s"}`,
51
+ running > 0 ? `${running} running` : "",
52
+ waiting > 0 ? `${waiting} waiting for review` : "",
53
+ merged > 0 ? `${merged} merged` : "",
54
+ longest > 0 ? formatDuration(longest) : "",
55
+ quiet > 0 ? `${quiet} quiet` : "",
56
+ ].filter((part) => part !== "");
57
+ return ` ${mission.missionId.padEnd(16)} ${mission.status.padEnd(9)} ${parts.join(" · ")}`;
58
+ });
59
+ const anomalies = state.anomalies.length === 0
60
+ ? ""
61
+ : `\n ${state.anomalies.length} event(s) did not fit the story and were kept as anomalies.\n`;
62
+ return `Missions\n${lines.join("\n")}\n${anomalies}`;
63
+ }
64
+ //# sourceMappingURL=format.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.js","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"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"}
package/dist/home.d.ts ADDED
@@ -0,0 +1,9 @@
1
+ export interface FanoutHome {
2
+ root: string;
3
+ ledger: string;
4
+ token: string;
5
+ workspaces: string;
6
+ runs: string;
7
+ }
8
+ export declare function fanoutHome(env?: Readonly<Record<string, string | undefined>>): FanoutHome;
9
+ //# sourceMappingURL=home.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"home.d.ts","sourceRoot":"","sources":["../src/home.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,UAAU,CAAC,GAAG,GAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAe,GAAG,UAAU,CAStG"}
package/dist/home.js ADDED
@@ -0,0 +1,13 @@
1
+ import { homedir } from "node:os";
2
+ import { join } from "node:path";
3
+ export function fanoutHome(env = process.env) {
4
+ const root = env["FANOUT_HOME"] ?? join(env["HOME"] ?? homedir(), ".fanout");
5
+ return {
6
+ root,
7
+ ledger: join(root, "ledger.db"),
8
+ token: join(root, "token"),
9
+ workspaces: join(root, "workspaces"),
10
+ runs: join(root, "runs"),
11
+ };
12
+ }
13
+ //# sourceMappingURL=home.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"home.js","sourceRoot":"","sources":["../src/home.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAejC,MAAM,UAAU,UAAU,CAAC,MAAoD,OAAO,CAAC,GAAG;IACxF,MAAM,IAAI,GAAG,GAAG,CAAC,aAAa,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,OAAO,EAAE,EAAE,SAAS,CAAC,CAAC;IAC7E,OAAO;QACL,IAAI;QACJ,MAAM,EAAE,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC;QAC/B,KAAK,EAAE,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC;QAC1B,UAAU,EAAE,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC;QACpC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC;KACzB,CAAC;AACJ,CAAC"}
package/dist/main.d.ts ADDED
@@ -0,0 +1,21 @@
1
+ import { type AdapterManifest, type SeatAdapter, type SeatInfo } from "fanout-core";
2
+ import { type CommandResult, type RunLimits } from "fanout-daemon";
3
+ export declare const SEATS: readonly AdapterManifest[];
4
+ /** Every seat we can drive today. A plan naming anything else is dropped with the reason, never guessed at. */
5
+ export declare function adapters(): ReadonlyMap<string, SeatAdapter>;
6
+ /** What a run is allowed before the supervisor stops it. Generous: a real agent thinks for minutes. */
7
+ export declare const DEFAULT_LIMITS: RunLimits;
8
+ export interface Io {
9
+ out: (text: string) => void;
10
+ err: (text: string) => void;
11
+ /** Injected so tests never need the real CLIs installed. */
12
+ execute?: (binary: string, args: readonly string[]) => Promise<CommandResult>;
13
+ env?: Readonly<Record<string, string | undefined>>;
14
+ /** Resolves when the daemon should stop; without it, `daemon` runs until interrupted. */
15
+ until?: Promise<void>;
16
+ /** Where the command was run; tests point it at a temporary repository. */
17
+ cwd?: string;
18
+ }
19
+ export declare function main(argv: readonly string[], io: Io): Promise<number>;
20
+ export type { SeatInfo };
21
+ //# sourceMappingURL=main.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAKA,OAAO,EAOL,KAAK,eAAe,EAEpB,KAAK,WAAW,EAIhB,KAAK,QAAQ,EAEd,MAAM,aAAa,CAAC;AACrB,OAAO,EAeL,KAAK,aAAa,EAClB,KAAK,SAAS,EACf,MAAM,eAAe,CAAC;AAevB,eAAO,MAAM,KAAK,EAAE,SAAS,eAAe,EAA0B,CAAC;AAEvE,+GAA+G;AAC/G,wBAAgB,QAAQ,IAAI,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,CAM3D;AAED,uGAAuG;AACvG,eAAO,MAAM,cAAc,EAAE,SAM5B,CAAC;AAmBF,MAAM,WAAW,EAAE;IACjB,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5B,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5B,4DAA4D;IAC5D,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,KAAK,OAAO,CAAC,aAAa,CAAC,CAAC;IAC9E,GAAG,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;IACnD,yFAAyF;IACzF,KAAK,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB,2EAA2E;IAC3E,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,wBAAsB,IAAI,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAmC3E;AAkkBD,YAAY,EAAE,QAAQ,EAAE,CAAC"}