@detergent-software/conductor 0.0.0-stage → 1.0.0-dev.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +31 -0
- package/README.md +131 -2
- package/build/claude.js +102 -0
- package/build/claude.js.map +1 -0
- package/build/cli.js +450 -0
- package/build/cli.js.map +1 -0
- package/build/client.js +64 -0
- package/build/client.js.map +1 -0
- package/build/conditions.js +198 -0
- package/build/conditions.js.map +1 -0
- package/build/config.js +74 -0
- package/build/config.js.map +1 -0
- package/build/daemon.js +127 -0
- package/build/daemon.js.map +1 -0
- package/build/errors.js +17 -0
- package/build/errors.js.map +1 -0
- package/build/jsonc.js +24 -0
- package/build/jsonc.js.map +1 -0
- package/build/lock.js +64 -0
- package/build/lock.js.map +1 -0
- package/build/log.js +43 -0
- package/build/log.js.map +1 -0
- package/build/manager.js +614 -0
- package/build/manager.js.map +1 -0
- package/build/paths.js +16 -0
- package/build/paths.js.map +1 -0
- package/build/profile.js +74 -0
- package/build/profile.js.map +1 -0
- package/build/registry.js +33 -0
- package/build/registry.js.map +1 -0
- package/build/resolve.js +28 -0
- package/build/resolve.js.map +1 -0
- package/build/run.js +52 -0
- package/build/run.js.map +1 -0
- package/build/server.js +227 -0
- package/build/server.js.map +1 -0
- package/build/spend.js +134 -0
- package/build/spend.js.map +1 -0
- package/build/startup.js +78 -0
- package/build/startup.js.map +1 -0
- package/build/store.js +528 -0
- package/build/store.js.map +1 -0
- package/build/tab.js +26 -0
- package/build/tab.js.map +1 -0
- package/build/token.js +58 -0
- package/build/token.js.map +1 -0
- package/build/upgrade.js +93 -0
- package/build/upgrade.js.map +1 -0
- package/build/wait.js +149 -0
- package/build/wait.js.map +1 -0
- package/build/watchers/ado.js +167 -0
- package/build/watchers/ado.js.map +1 -0
- package/build/watchers/github.js +82 -0
- package/build/watchers/github.js.map +1 -0
- package/build/watchers/health.js +42 -0
- package/build/watchers/health.js.map +1 -0
- package/build/watchers/index.js +226 -0
- package/build/watchers/index.js.map +1 -0
- package/build/watchers/linear-key.js +56 -0
- package/build/watchers/linear-key.js.map +1 -0
- package/build/watchers/linear.js +218 -0
- package/build/watchers/linear.js.map +1 -0
- package/build/watchers/npm.js +35 -0
- package/build/watchers/npm.js.map +1 -0
- package/build/watchers/source.js +94 -0
- package/build/watchers/source.js.map +1 -0
- package/build/worktrees.js +143 -0
- package/build/worktrees.js.map +1 -0
- package/package.json +56 -5
package/build/cli.js
ADDED
|
@@ -0,0 +1,450 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { spawn } from 'node:child_process';
|
|
3
|
+
import { mkdirSync, readFileSync, realpathSync } from 'node:fs';
|
|
4
|
+
import { resolve, sep } from 'node:path';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
import { parseArgs } from 'node:util';
|
|
7
|
+
import { z } from 'zod';
|
|
8
|
+
import { callApi, NotRunningError, ping, readEndpoint } from "./client.js";
|
|
9
|
+
import { startDaemon } from "./daemon.js";
|
|
10
|
+
import { ConductorError } from "./errors.js";
|
|
11
|
+
import { processAlive, readPid } from "./lock.js";
|
|
12
|
+
import { fleetWorkerSchema } from "./manager.js";
|
|
13
|
+
import { conductorPaths } from "./paths.js";
|
|
14
|
+
import { registerProject } from "./registry.js";
|
|
15
|
+
import { outputOf, run } from "./run.js";
|
|
16
|
+
import { installStartup, removeStartup, runStartup, startupRunsCli, TASK_NAME } from "./startup.js";
|
|
17
|
+
import { openStore, projectSchema, workerSchema } from "./store.js";
|
|
18
|
+
import { parseTag, upgrade } from "./upgrade.js";
|
|
19
|
+
import { waitCommand } from "./wait.js";
|
|
20
|
+
const USAGE = `Usage: conduct <command>
|
|
21
|
+
|
|
22
|
+
serve run the daemon in this process (one per machine)
|
|
23
|
+
stop stop the running daemon
|
|
24
|
+
status [--json] the daemon's pid, port, projects and workers
|
|
25
|
+
project add <path> register the project whose checkout holds .claude/conductor.json
|
|
26
|
+
project list [--json] the registered projects
|
|
27
|
+
launch <item> start a worker: its worktree, a background session, a tab
|
|
28
|
+
[--project <name>] [--probe] [--prompt <text>] [--conductor <name>]
|
|
29
|
+
retire <worker> [--force] stop a worker, remove its worktree and session; refuses unfinished work
|
|
30
|
+
attach <worker> wake a parked worker (no event text) and open it in a tab
|
|
31
|
+
wait <condition> wait for an outside event: in a worker's worktree with the daemon
|
|
32
|
+
running, register it and end the turn (the daemon resumes the session);
|
|
33
|
+
otherwise check it here and block (exit 0 when it holds, 2 at --timeout)
|
|
34
|
+
pr <n> merged|checks|comment [--repo <owner>/<repo>]
|
|
35
|
+
run <pipeline> <run id> [done]
|
|
36
|
+
npm <version> [--tag <dist-tag>] [--package <name>]
|
|
37
|
+
health <env> --version <x> | --commit <sha>
|
|
38
|
+
approval [<item>] an approve / revise: comment after the item's newest Plan note
|
|
39
|
+
item <item> <state> | item <item> label|note <value>
|
|
40
|
+
time <when> such as 2026-10-10T09:00 (local)
|
|
41
|
+
<full form> such as pr:ado:Emergent.AgenticToolkit#1850:merged
|
|
42
|
+
[--local] [--timeout <minutes, local only; 29>] [--worker <worker>] [--item <item>]
|
|
43
|
+
install-startup start the daemon at logon (Windows Task Scheduler)
|
|
44
|
+
install-startup --remove remove that logon task
|
|
45
|
+
upgrade [--tag dev|latest] stop the daemon, npm install the newest version on the tag (default:
|
|
46
|
+
the tag the installed version came from), start the daemon again
|
|
47
|
+
|
|
48
|
+
A <worker> is its item (ATK-309) or its name (probe-ATK-309).
|
|
49
|
+
Files live in ~/.conductor (CONDUCTOR_HOME overrides it).`;
|
|
50
|
+
const STOP_WAIT_MS = 10_000;
|
|
51
|
+
// A restarted daemon opens its store and binds the port; under the logon task node starts cold.
|
|
52
|
+
const START_WAIT_MS = 30_000;
|
|
53
|
+
const NPM_INSTALL_TIMEOUT_MS = 5 * 60_000;
|
|
54
|
+
// A launch makes a worktree (pnpm install) before the session starts.
|
|
55
|
+
const LAUNCH_WAIT_MS = 15 * 60_000;
|
|
56
|
+
// The daemon's worst cases, so the CLI never gives up on an operation that still runs: retire
|
|
57
|
+
// lists sessions (60 s), stops one (120 s + 30 s), removes the worktree (5 min), rms it (120 s);
|
|
58
|
+
// attach waits out the settle time (up to 5 min), resumes (120 s) and opens the tab (60 s).
|
|
59
|
+
const RETIRE_TIMEOUT_MS = 12 * 60_000;
|
|
60
|
+
const ATTACH_TIMEOUT_MS = 9 * 60_000;
|
|
61
|
+
const projectsBody = z.object({ projects: z.array(projectSchema) });
|
|
62
|
+
const addBody = z.object({ created: z.boolean(), project: projectSchema });
|
|
63
|
+
const errorBody = z.object({ details: z.array(z.string()).optional(), error: z.string() });
|
|
64
|
+
const fleetBody = z.object({ workers: z.array(fleetWorkerSchema) });
|
|
65
|
+
const workerBody = z.object({ worker: workerSchema });
|
|
66
|
+
const workerDetailBody = z.object({
|
|
67
|
+
events: z.array(z.object({ data: z.record(z.string(), z.unknown()), kind: z.string() })),
|
|
68
|
+
worker: workerSchema,
|
|
69
|
+
});
|
|
70
|
+
const retireBody = z.object({
|
|
71
|
+
outcome: z.enum(['partial', 'refused', 'retired']),
|
|
72
|
+
reason: z.string().optional(),
|
|
73
|
+
steps: z.array(z.object({ error: z.string().optional(), ok: z.boolean(), step: z.string() })).optional(),
|
|
74
|
+
work: z
|
|
75
|
+
.object({ dirty: z.array(z.string()).optional(), unknown: z.string().optional(), unpushed: z.number().optional() })
|
|
76
|
+
.optional(),
|
|
77
|
+
worker: workerSchema,
|
|
78
|
+
});
|
|
79
|
+
const attachBody = z.object({ resumed: z.boolean(), tab: z.string().nullable(), worker: workerSchema });
|
|
80
|
+
async function addProject(paths, path) {
|
|
81
|
+
const absolute = resolve(path);
|
|
82
|
+
let result;
|
|
83
|
+
try {
|
|
84
|
+
result = addBody.parse(await expectOk(callApi(paths, { body: { path: absolute }, method: 'POST', path: '/projects' })));
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
if (!(error instanceof NotRunningError))
|
|
88
|
+
throw error;
|
|
89
|
+
// No daemon: write the store directly. The daemon reads it when it starts.
|
|
90
|
+
result = withStore(paths, (store) => registerProject(store, absolute));
|
|
91
|
+
}
|
|
92
|
+
out(`${result.created ? 'registered' : 'updated'} ${projectLine(result.project).trim()}`);
|
|
93
|
+
}
|
|
94
|
+
async function attach(paths, ref) {
|
|
95
|
+
const worker = await findWorker(paths, ref);
|
|
96
|
+
const result = attachBody.parse(await expectOk(callApi(paths, { method: 'POST', path: `/workers/${worker.id}/attach`, timeoutMs: ATTACH_TIMEOUT_MS })));
|
|
97
|
+
out(`${result.resumed ? 'woke' : 'attached to'} ${worker.name} (session ${result.worker.handle ?? '?'})`);
|
|
98
|
+
if (result.tab)
|
|
99
|
+
out(`no tab (${result.tab}); open it yourself: claude attach ${result.worker.handle ?? worker.name}`);
|
|
100
|
+
}
|
|
101
|
+
// The pid of the daemon once it answers /health, for upgrade's restart.
|
|
102
|
+
async function awaitDaemon(paths) {
|
|
103
|
+
const deadline = Date.now() + START_WAIT_MS;
|
|
104
|
+
while (Date.now() < deadline) {
|
|
105
|
+
const pid = readPid(paths.pid);
|
|
106
|
+
if (pid !== null && (await ping(paths, pid)))
|
|
107
|
+
return pid;
|
|
108
|
+
await sleep(250);
|
|
109
|
+
}
|
|
110
|
+
throw new ConductorError(`the conductor did not answer within ${START_WAIT_MS / 1000} s`, [`see ${paths.log}`]);
|
|
111
|
+
}
|
|
112
|
+
async function expectOk(call) {
|
|
113
|
+
const { body, status } = await call;
|
|
114
|
+
if (status >= 200 && status < 300)
|
|
115
|
+
return body;
|
|
116
|
+
const error = errorBody.safeParse(body);
|
|
117
|
+
throw new ConductorError(error.success ? error.data.error : `the API answered ${status}`, error.data?.details ?? []);
|
|
118
|
+
}
|
|
119
|
+
// A worker in flight by item or name. A probe and a live worker can share an item, so a name match wins.
|
|
120
|
+
async function findWorker(paths, ref) {
|
|
121
|
+
const { workers } = fleetBody.parse(await expectOk(callApi(paths, { method: 'GET', path: '/fleet' })));
|
|
122
|
+
const byName = workers.filter((w) => w.name === ref);
|
|
123
|
+
const matches = byName.length > 0 ? byName : workers.filter((w) => w.item === ref);
|
|
124
|
+
if (matches.length === 1 && matches[0])
|
|
125
|
+
return matches[0];
|
|
126
|
+
if (matches.length === 0)
|
|
127
|
+
throw new ConductorError(`no worker "${ref}" in flight`, ['`conduct status` lists them']);
|
|
128
|
+
throw new ConductorError(`"${ref}" names several workers`, matches.map((w) => `${w.name} in ${w.project}`));
|
|
129
|
+
}
|
|
130
|
+
// 1234 → 1.2k, 3_400_000 → 3.4M.
|
|
131
|
+
function formatTokens(tokens) {
|
|
132
|
+
if (tokens >= 1_000_000)
|
|
133
|
+
return `${(tokens / 1_000_000).toFixed(1)}M`;
|
|
134
|
+
if (tokens >= 1_000)
|
|
135
|
+
return `${(tokens / 1_000).toFixed(1)}k`;
|
|
136
|
+
return String(tokens);
|
|
137
|
+
}
|
|
138
|
+
function install() {
|
|
139
|
+
const cliPath = realpathSync(fileURLToPath(import.meta.url));
|
|
140
|
+
installStartup({ cliPath, nodePath: process.execPath });
|
|
141
|
+
out(`registered the "${TASK_NAME}" logon task: ${process.execPath} ${cliPath} serve`);
|
|
142
|
+
if (cliPath.includes(`${sep}.claude${sep}worktrees${sep}`)) {
|
|
143
|
+
out('warning: that build is in a worktree, which goes away; run install-startup from the main checkout');
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
async function launch(paths, item, options) {
|
|
147
|
+
const { worker } = workerBody.parse(await expectOk(callApi(paths, { body: { item, ...options }, method: 'POST', path: '/workers' })));
|
|
148
|
+
out(`launching ${worker.name} in ${worker.project} (worker ${worker.id}): worktree, then session`);
|
|
149
|
+
const deadline = Date.now() + LAUNCH_WAIT_MS;
|
|
150
|
+
while (Date.now() < deadline) {
|
|
151
|
+
await sleep(2000);
|
|
152
|
+
const detail = workerDetailBody.parse(await expectOk(callApi(paths, { method: 'GET', path: `/workers/${worker.id}` })));
|
|
153
|
+
const { status } = detail.worker;
|
|
154
|
+
if (status === 'launching')
|
|
155
|
+
continue;
|
|
156
|
+
if (status === 'failed') {
|
|
157
|
+
const failure = detail.events.find((e) => e.kind === 'worker.launch-failed')?.data ?? {};
|
|
158
|
+
throw new ConductorError(`could not launch ${worker.name}`, [
|
|
159
|
+
`${String(failure.step ?? 'launch')}: ${String(failure.error ?? 'see the log')}`,
|
|
160
|
+
]);
|
|
161
|
+
}
|
|
162
|
+
out(`launched ${worker.name}: session ${detail.worker.handle ?? '?'}, worktree ${detail.worker.worktree ?? '?'}`);
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
throw new ConductorError(`${worker.name} is still launching after ${LAUNCH_WAIT_MS / 60_000} min`, [
|
|
166
|
+
'`conduct status` shows it; the daemon carries on',
|
|
167
|
+
]);
|
|
168
|
+
}
|
|
169
|
+
async function listProjects(paths, json) {
|
|
170
|
+
let projects;
|
|
171
|
+
try {
|
|
172
|
+
projects = projectsBody.parse(await expectOk(callApi(paths, { method: 'GET', path: '/projects' }))).projects;
|
|
173
|
+
}
|
|
174
|
+
catch (error) {
|
|
175
|
+
if (!(error instanceof NotRunningError))
|
|
176
|
+
throw error;
|
|
177
|
+
projects = withStore(paths, (store) => store.listProjects());
|
|
178
|
+
}
|
|
179
|
+
if (json)
|
|
180
|
+
return out(JSON.stringify(projects, null, 2));
|
|
181
|
+
if (projects.length === 0)
|
|
182
|
+
return out('no projects; add one with `conduct project add <path>`');
|
|
183
|
+
projects.forEach((p) => out(projectLine(p)));
|
|
184
|
+
}
|
|
185
|
+
async function main(argv) {
|
|
186
|
+
// `wait` has options of its own: its --version is a value, not this CLI's version.
|
|
187
|
+
if (argv[0] === 'wait')
|
|
188
|
+
return wait(argv.slice(1));
|
|
189
|
+
const { positionals, values } = parseArgs({
|
|
190
|
+
allowPositionals: true,
|
|
191
|
+
args: argv,
|
|
192
|
+
options: {
|
|
193
|
+
conductor: { type: 'string' },
|
|
194
|
+
force: { type: 'boolean' },
|
|
195
|
+
help: { short: 'h', type: 'boolean' },
|
|
196
|
+
json: { type: 'boolean' },
|
|
197
|
+
probe: { type: 'boolean' },
|
|
198
|
+
project: { type: 'string' },
|
|
199
|
+
prompt: { type: 'string' },
|
|
200
|
+
remove: { type: 'boolean' },
|
|
201
|
+
tag: { type: 'string' },
|
|
202
|
+
version: { short: 'v', type: 'boolean' },
|
|
203
|
+
},
|
|
204
|
+
});
|
|
205
|
+
const paths = conductorPaths();
|
|
206
|
+
const [command, sub, arg] = positionals;
|
|
207
|
+
if (values.version)
|
|
208
|
+
return out(version());
|
|
209
|
+
if (values.help || command === undefined || command === 'help')
|
|
210
|
+
return out(USAGE);
|
|
211
|
+
switch (command) {
|
|
212
|
+
case 'attach':
|
|
213
|
+
if (sub === undefined)
|
|
214
|
+
throw new ConductorError('usage: conduct attach <worker>');
|
|
215
|
+
return attach(paths, sub);
|
|
216
|
+
case 'install-startup':
|
|
217
|
+
return values.remove ? uninstall() : install();
|
|
218
|
+
case 'launch':
|
|
219
|
+
if (sub === undefined)
|
|
220
|
+
throw new ConductorError('usage: conduct launch <item> [--project <name>] [--probe]');
|
|
221
|
+
return launch(paths, sub, {
|
|
222
|
+
conductor: values.conductor,
|
|
223
|
+
probe: values.probe,
|
|
224
|
+
project: values.project,
|
|
225
|
+
prompt: values.prompt,
|
|
226
|
+
});
|
|
227
|
+
case 'project':
|
|
228
|
+
if (sub === 'add' && arg !== undefined)
|
|
229
|
+
return addProject(paths, arg);
|
|
230
|
+
if (sub === 'list')
|
|
231
|
+
return listProjects(paths, values.json === true);
|
|
232
|
+
throw new ConductorError('usage: conduct project add <path> | conduct project list');
|
|
233
|
+
case 'retire':
|
|
234
|
+
if (sub === undefined)
|
|
235
|
+
throw new ConductorError('usage: conduct retire <worker> [--force]');
|
|
236
|
+
return retire(paths, sub, values.force === true);
|
|
237
|
+
case 'serve':
|
|
238
|
+
return serve(paths);
|
|
239
|
+
case 'status':
|
|
240
|
+
return status(paths, values.json === true);
|
|
241
|
+
case 'stop':
|
|
242
|
+
await stopDaemon(paths);
|
|
243
|
+
return;
|
|
244
|
+
case 'upgrade':
|
|
245
|
+
return upgradeCommand(paths, values.tag);
|
|
246
|
+
default:
|
|
247
|
+
throw new ConductorError(`unknown command "${command}"`, ['run `conduct help` for the commands']);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
// npm is a .cmd shim on Windows, which starts through a shell alone. The only argument from input is
|
|
251
|
+
// the tag, which parseTag limits to dev or latest.
|
|
252
|
+
function npm(args, timeoutMs) {
|
|
253
|
+
return run('npm', args, { shell: process.platform === 'win32', timeoutMs });
|
|
254
|
+
}
|
|
255
|
+
function out(line) {
|
|
256
|
+
process.stdout.write(`${line}\n`);
|
|
257
|
+
}
|
|
258
|
+
function projectLine(p) {
|
|
259
|
+
const state = p.problem ? `${p.problem}; run \`conduct project add\` again` : p.enabled ? 'enabled' : 'disabled';
|
|
260
|
+
return ` ${p.name} ${p.root} (protocol ${p.protocol}, ${state})`;
|
|
261
|
+
}
|
|
262
|
+
async function retire(paths, ref, force) {
|
|
263
|
+
const worker = await findWorker(paths, ref);
|
|
264
|
+
const { body, status } = await callApi(paths, {
|
|
265
|
+
method: 'DELETE',
|
|
266
|
+
path: `/workers/${worker.id}${force ? '?force=true' : ''}`,
|
|
267
|
+
timeoutMs: RETIRE_TIMEOUT_MS,
|
|
268
|
+
});
|
|
269
|
+
const parsed = retireBody.safeParse(body);
|
|
270
|
+
if (!parsed.success) {
|
|
271
|
+
await expectOk(Promise.resolve({ body, status })); // a plain error answer
|
|
272
|
+
throw new ConductorError(`the API answered ${status} with an unexpected body`);
|
|
273
|
+
}
|
|
274
|
+
const result = parsed.data;
|
|
275
|
+
const steps = (result.steps ?? []).map((s) => `${s.step}: ${s.ok ? 'ok' : `failed (${s.error ?? '?'})`}`);
|
|
276
|
+
if (result.outcome === 'refused') {
|
|
277
|
+
const work = [
|
|
278
|
+
...(result.work?.unpushed ? [`${result.work.unpushed} unpushed commit(s)`] : []),
|
|
279
|
+
...(result.work?.dirty ? [`uncommitted: ${result.work.dirty.join(', ')}`] : []),
|
|
280
|
+
...(result.work?.unknown ? [`not checked: ${result.work.unknown}`] : []),
|
|
281
|
+
];
|
|
282
|
+
throw new ConductorError(`refused to retire ${worker.name}: ${result.reason ?? ''}`, work);
|
|
283
|
+
}
|
|
284
|
+
if (result.outcome === 'partial')
|
|
285
|
+
throw new ConductorError(`retired ${worker.name} only in part`, steps);
|
|
286
|
+
out(`retired ${worker.name}`);
|
|
287
|
+
steps.forEach((s) => out(` ${s}`));
|
|
288
|
+
}
|
|
289
|
+
async function serve(paths) {
|
|
290
|
+
const daemon = await startDaemon(paths, { version: version() });
|
|
291
|
+
out(`conductor listening on 127.0.0.1:${daemon.port} (pid ${process.pid}, home ${paths.home})`);
|
|
292
|
+
for (const signal of ['SIGINT', 'SIGTERM', 'SIGBREAK']) {
|
|
293
|
+
process.once(signal, () => void daemon.stop(signal));
|
|
294
|
+
}
|
|
295
|
+
// Under the logon task nobody sees stderr, so a crash goes to the log. The pid file it leaves
|
|
296
|
+
// names a dead process, which the next start replaces.
|
|
297
|
+
process.on('uncaughtException', (error) => {
|
|
298
|
+
daemon.log.log('error', 'uncaught exception', { error: error.stack ?? String(error) });
|
|
299
|
+
process.exit(1);
|
|
300
|
+
});
|
|
301
|
+
await daemon.closed;
|
|
302
|
+
}
|
|
303
|
+
function sleep(ms) {
|
|
304
|
+
return new Promise((done) => setTimeout(done, ms));
|
|
305
|
+
}
|
|
306
|
+
async function status(paths, json) {
|
|
307
|
+
let projects;
|
|
308
|
+
try {
|
|
309
|
+
projects = projectsBody.parse(await expectOk(callApi(paths, { method: 'GET', path: '/projects' }))).projects;
|
|
310
|
+
}
|
|
311
|
+
catch (error) {
|
|
312
|
+
if (!(json && error instanceof NotRunningError))
|
|
313
|
+
throw error;
|
|
314
|
+
// Scripts and the conductor mod read the answer, so "not running" is JSON too (exit 1).
|
|
315
|
+
out(JSON.stringify({ home: paths.home, running: false }, null, 2));
|
|
316
|
+
process.exitCode = 1;
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
const { workers } = fleetBody.parse(await expectOk(callApi(paths, { method: 'GET', path: '/fleet' })));
|
|
320
|
+
const pid = readPid(paths.pid);
|
|
321
|
+
const port = readEndpoint(paths)?.port ?? null;
|
|
322
|
+
if (json)
|
|
323
|
+
return out(JSON.stringify({ home: paths.home, pid, port, projects, running: true, workers }, null, 2));
|
|
324
|
+
out(`conductor running (pid ${pid ?? '?'}, port ${port ?? '?'}, home ${paths.home})`);
|
|
325
|
+
out(projects.length === 0 ? 'no projects; add one with `conduct project add <path>`' : 'projects:');
|
|
326
|
+
projects.forEach((p) => out(projectLine(p)));
|
|
327
|
+
out(workers.length === 0 ? 'no workers' : 'workers:');
|
|
328
|
+
workers.forEach((w) => out(workerLine(w)));
|
|
329
|
+
}
|
|
330
|
+
// True when it stopped a daemon, false when none ran.
|
|
331
|
+
async function stopDaemon(paths) {
|
|
332
|
+
const pid = readPid(paths.pid);
|
|
333
|
+
try {
|
|
334
|
+
await expectOk(callApi(paths, { method: 'POST', path: '/shutdown' }));
|
|
335
|
+
}
|
|
336
|
+
catch (error) {
|
|
337
|
+
if (!(error instanceof NotRunningError))
|
|
338
|
+
throw error;
|
|
339
|
+
out('the conductor is not running');
|
|
340
|
+
return false;
|
|
341
|
+
}
|
|
342
|
+
const deadline = Date.now() + STOP_WAIT_MS;
|
|
343
|
+
while (readEndpoint(paths) !== null && Date.now() < deadline)
|
|
344
|
+
await sleep(100);
|
|
345
|
+
if (readEndpoint(paths) !== null) {
|
|
346
|
+
throw new ConductorError(`the conductor (pid ${pid ?? '?'}) did not stop within ${STOP_WAIT_MS / 1000} s`);
|
|
347
|
+
}
|
|
348
|
+
// The port file goes before the process ends; a start (the logon task's especially) waits for it.
|
|
349
|
+
const exitDeadline = Date.now() + STOP_WAIT_MS;
|
|
350
|
+
while (pid !== null && processAlive(pid) && Date.now() < exitDeadline)
|
|
351
|
+
await sleep(100);
|
|
352
|
+
out(`stopped the conductor (pid ${pid ?? '?'})`);
|
|
353
|
+
return true;
|
|
354
|
+
}
|
|
355
|
+
function uninstall() {
|
|
356
|
+
out(removeStartup() ? `removed the "${TASK_NAME}" logon task` : `no "${TASK_NAME}" logon task to remove`);
|
|
357
|
+
}
|
|
358
|
+
async function upgradeCommand(paths, tag) {
|
|
359
|
+
const cliPath = realpathSync(fileURLToPath(import.meta.url));
|
|
360
|
+
await upgrade({ tag: parseTag(tag) }, {
|
|
361
|
+
awaitDaemon: () => awaitDaemon(paths),
|
|
362
|
+
cliPath,
|
|
363
|
+
installedVersion: version,
|
|
364
|
+
npmInstall: (spec) => npm(['install', '--global', spec], NPM_INSTALL_TIMEOUT_MS),
|
|
365
|
+
npmRoot: async () => {
|
|
366
|
+
const result = await npm(['root', '--global']);
|
|
367
|
+
if (result.code !== 0)
|
|
368
|
+
throw new ConductorError('could not ask npm for its global folder', [outputOf(result)]);
|
|
369
|
+
return realpathSync(result.stdout.trim());
|
|
370
|
+
},
|
|
371
|
+
npmView: async (spec) => {
|
|
372
|
+
const result = await npm(['view', spec, 'version']);
|
|
373
|
+
const found = result.stdout.trim();
|
|
374
|
+
if (result.code !== 0 || found === '')
|
|
375
|
+
throw new ConductorError(`npm has no ${spec}`, [outputOf(result)]);
|
|
376
|
+
return found;
|
|
377
|
+
},
|
|
378
|
+
out,
|
|
379
|
+
runTask: runStartup,
|
|
380
|
+
// A failed start shows as awaitDaemon's timeout. The daemon runs in its home, not in the
|
|
381
|
+
// caller's directory, which it would hold open (a worktree it may later remove, say).
|
|
382
|
+
serveDetached: () => spawn(process.execPath, [cliPath, 'serve'], { cwd: paths.home, detached: true, stdio: 'ignore', windowsHide: true })
|
|
383
|
+
.on('error', () => { })
|
|
384
|
+
.unref(),
|
|
385
|
+
stopDaemon: () => stopDaemon(paths),
|
|
386
|
+
// The logon task's daemon uses ~/.conductor, so it can't restart one kept in CONDUCTOR_HOME.
|
|
387
|
+
taskRunsCli: () => !process.env.CONDUCTOR_HOME && startupRunsCli(cliPath),
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
// Read from disk each time: upgrade asks again after npm has replaced the package.
|
|
391
|
+
function version() {
|
|
392
|
+
const file = fileURLToPath(new URL('../package.json', import.meta.url));
|
|
393
|
+
return z.object({ version: z.string() }).parse(JSON.parse(readFileSync(file, 'utf8'))).version;
|
|
394
|
+
}
|
|
395
|
+
async function wait(argv) {
|
|
396
|
+
const { positionals, values } = parseArgs({
|
|
397
|
+
allowPositionals: true,
|
|
398
|
+
args: argv,
|
|
399
|
+
options: {
|
|
400
|
+
commit: { type: 'string' },
|
|
401
|
+
item: { type: 'string' },
|
|
402
|
+
local: { type: 'boolean' },
|
|
403
|
+
package: { type: 'string' },
|
|
404
|
+
repo: { type: 'string' },
|
|
405
|
+
tag: { type: 'string' },
|
|
406
|
+
timeout: { type: 'string' },
|
|
407
|
+
version: { type: 'string' },
|
|
408
|
+
worker: { type: 'string' },
|
|
409
|
+
},
|
|
410
|
+
});
|
|
411
|
+
const timeout = values.timeout === undefined ? undefined : Number(values.timeout);
|
|
412
|
+
if (timeout !== undefined && !(timeout > 0))
|
|
413
|
+
throw new ConductorError('--timeout takes minutes, such as --timeout 25');
|
|
414
|
+
if (positionals.length === 0)
|
|
415
|
+
throw new ConductorError('usage: conduct wait <condition>', ['run `conduct help` for the conditions']);
|
|
416
|
+
process.exitCode = await waitCommand(conductorPaths(), positionals, { ...values, timeoutMinutes: timeout }, { cwd: process.cwd(), err: (line) => process.stderr.write(`${line}\n`), out });
|
|
417
|
+
}
|
|
418
|
+
function withStore(paths, use) {
|
|
419
|
+
mkdirSync(paths.home, { recursive: true });
|
|
420
|
+
const store = openStore(paths.db);
|
|
421
|
+
try {
|
|
422
|
+
return use(store);
|
|
423
|
+
}
|
|
424
|
+
finally {
|
|
425
|
+
store.close();
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
// One line per worker: name, project, status and session activity, its waits, then spend.
|
|
429
|
+
function workerLine(w) {
|
|
430
|
+
const activity = w.status === 'running' ? `running, ${w.activity}` : w.status;
|
|
431
|
+
const waits = w.waits.map((x) => (x.resolvedAt ? `${x.condition} (resolved)` : x.condition));
|
|
432
|
+
return [
|
|
433
|
+
` ${w.name} ${w.project} ${activity}`,
|
|
434
|
+
...(waits.length > 0 ? [`waits: ${waits.join(', ')}`] : []),
|
|
435
|
+
`spend ${formatTokens(w.spend.today)} today, ${formatTokens(w.spend.total)} total`,
|
|
436
|
+
].join(' · ');
|
|
437
|
+
}
|
|
438
|
+
main(process.argv.slice(2)).catch((error) => {
|
|
439
|
+
if (error instanceof ConductorError) {
|
|
440
|
+
process.stderr.write(`conduct: ${error.message}\n${error.details.map((d) => ` ${d}\n`).join('')}`);
|
|
441
|
+
}
|
|
442
|
+
else if (error instanceof Error && 'code' in error && typeof error.code === 'string' && error.code.startsWith('ERR_PARSE_ARGS')) {
|
|
443
|
+
process.stderr.write(`conduct: ${error.message}\n${USAGE}\n`);
|
|
444
|
+
}
|
|
445
|
+
else {
|
|
446
|
+
process.stderr.write(`conduct: ${error instanceof Error ? (error.stack ?? error.message) : String(error)}\n`);
|
|
447
|
+
}
|
|
448
|
+
process.exitCode = 1;
|
|
449
|
+
});
|
|
450
|
+
//# sourceMappingURL=cli.js.map
|
package/build/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/build/client.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { ConductorError, hasCode, isMissing } from "./errors.js";
|
|
4
|
+
import { readToken } from "./token.js";
|
|
5
|
+
export class NotRunningError extends ConductorError {
|
|
6
|
+
constructor() {
|
|
7
|
+
super('the conductor is not running', ['start it with `conduct serve`']);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
export async function callApi(paths, { body, method, path, timeoutMs = 5000, }) {
|
|
11
|
+
const endpoint = readEndpoint(paths);
|
|
12
|
+
if (!endpoint)
|
|
13
|
+
throw new NotRunningError();
|
|
14
|
+
let response;
|
|
15
|
+
try {
|
|
16
|
+
response = await fetch(`http://127.0.0.1:${endpoint.port}${path}`, {
|
|
17
|
+
body: body === undefined ? undefined : JSON.stringify(body),
|
|
18
|
+
headers: {
|
|
19
|
+
authorization: `Bearer ${endpoint.token}`,
|
|
20
|
+
...(body === undefined ? {} : { 'content-type': 'application/json' }),
|
|
21
|
+
},
|
|
22
|
+
method,
|
|
23
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
// Refused: a port file left by a daemon that crashed. Anything else (a timeout, a reset) means
|
|
28
|
+
// a daemon may still be there, so callers must not act as if none were.
|
|
29
|
+
if (error instanceof Error && hasCode(error.cause, 'ECONNREFUSED'))
|
|
30
|
+
throw new NotRunningError();
|
|
31
|
+
throw new ConductorError(`the conductor on port ${endpoint.port} did not answer ${method} ${path}`, [String(error)]);
|
|
32
|
+
}
|
|
33
|
+
const text = await response.text();
|
|
34
|
+
return { body: text ? JSON.parse(text) : null, status: response.status };
|
|
35
|
+
}
|
|
36
|
+
const health = z.object({ pid: z.number() });
|
|
37
|
+
// True when the daemon on the port file's port answers /health as the given pid. /health doesn't
|
|
38
|
+
// touch the store, so a daemon that is busy or has a broken project still counts as running.
|
|
39
|
+
export async function ping(paths, pid, timeoutMs = 3000) {
|
|
40
|
+
try {
|
|
41
|
+
const { body, status } = await callApi(paths, { method: 'GET', path: '/health', timeoutMs });
|
|
42
|
+
return status === 200 && health.safeParse(body).data?.pid === pid;
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
// Where a running daemon listens: the port file it writes after `listen`, plus the token. Null when
|
|
49
|
+
// either is missing, which means no daemon has started (or the last one stopped cleanly).
|
|
50
|
+
export function readEndpoint(paths) {
|
|
51
|
+
let text;
|
|
52
|
+
try {
|
|
53
|
+
text = readFileSync(paths.port, 'utf8').trim();
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
if (isMissing(error))
|
|
57
|
+
return null;
|
|
58
|
+
throw error;
|
|
59
|
+
}
|
|
60
|
+
const port = Number(text);
|
|
61
|
+
const token = readToken(paths.token);
|
|
62
|
+
return Number.isInteger(port) && port > 0 && token ? { port, token } : null;
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|