@matthugh1/conductor-cli 0.2.2 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/agent.js CHANGED
@@ -1,8 +1,4 @@
1
1
  #!/usr/bin/env node
2
- import {
3
- ensureDatabaseUrl,
4
- postToServer
5
- } from "./chunk-B2WDTKD7.js";
6
2
 
7
3
  // ../../src/cli/agent.ts
8
4
  import { resolve } from "path";
@@ -124,12 +120,10 @@ function writeErr(text) {
124
120
  process.stderr.write(text + "\n");
125
121
  }
126
122
  async function cmdCheck(projectRoot, jsonOutput) {
127
- const { query: dbQuery } = await import("./db-U6Y3QJDD.js");
128
- const projects = await dbQuery(
129
- "SELECT id FROM projects WHERE path = $1 LIMIT 1",
130
- [projectRoot]
131
- );
132
- if (projects.length === 0) {
123
+ const { createDaemonClient } = await import("./daemon-client-CTYOJMJP.js");
124
+ const client = createDaemonClient();
125
+ const project = await client.resolveProjectByPath(projectRoot);
126
+ if (!project) {
133
127
  if (jsonOutput) {
134
128
  writeOut(
135
129
  JSON.stringify({
@@ -144,8 +138,8 @@ async function cmdCheck(projectRoot, jsonOutput) {
144
138
  }
145
139
  return 1;
146
140
  }
147
- const { getEnvironmentHealthReport } = await import("./health-UFK7YCKQ.js");
148
- const report = await getEnvironmentHealthReport(projects[0].id);
141
+ const projectId = project.id;
142
+ const report = await runLocalHealthChecks(projectRoot);
149
143
  if (jsonOutput) {
150
144
  writeOut(JSON.stringify(report, null, 2));
151
145
  } else {
@@ -157,18 +151,15 @@ async function cmdCheck(projectRoot, jsonOutput) {
157
151
  }
158
152
  }
159
153
  try {
160
- const { saveHealthSnapshot } = await import("./health-snapshots-6MUVHE3G.js");
161
- await saveHealthSnapshot(projects[0].id, report);
154
+ await client.saveHealthSnapshot(projectId, report);
162
155
  } catch {
163
- const posted = await postToServer("/api/environment/health", { report }, projectRoot);
164
- if (!posted && !jsonOutput) {
156
+ if (!jsonOutput) {
165
157
  writeErr("\u26A0 Could not sync results to the dashboard.");
166
158
  }
167
159
  }
168
160
  try {
169
- const { getGitBranchInfo, formatGitBranchLine, getStatusSummary, getRecentCommits } = await import("./git-wrapper-DVJ46TMA.js");
170
- const { getHookStatus } = await import("./git-hooks-UZJ6AER4.js");
171
- const { saveGitStatusSnapshot } = await import("./git-snapshots-N3FBS7T3.js");
161
+ const { getGitBranchInfo, formatGitBranchLine, getStatusSummary, getRecentCommits, runGit } = await import("./git-wrapper-QRZYTYCZ.js");
162
+ const { getHookStatus } = await import("./git-hooks-RQ6WJQS4.js");
172
163
  const branchInfo = await getGitBranchInfo(projectRoot);
173
164
  const branchLine = formatGitBranchLine(branchInfo);
174
165
  const status = await getStatusSummary(projectRoot);
@@ -182,21 +173,20 @@ async function cmdCheck(projectRoot, jsonOutput) {
182
173
  hookStatus = await getHookStatus(projectRoot);
183
174
  } catch {
184
175
  }
185
- const worktreeRows = await dbQuery(
186
- "SELECT branch_name, worktree_path FROM worktrees WHERE project_id = $1 AND status = 'active'",
187
- [projects[0].id]
188
- );
189
176
  const worktreeCommits = {};
190
- const { runGit } = await import("./git-wrapper-DVJ46TMA.js");
191
- for (const wt of worktreeRows) {
192
- try {
193
- const out = await runGit(wt.worktree_path, ["log", "-1", "--format=%cI"]);
194
- const date = out.trim();
195
- if (date) worktreeCommits[wt.branch_name] = date;
196
- } catch {
177
+ try {
178
+ const worktrees = await client.listActiveWorktrees(projectId);
179
+ for (const wt of worktrees) {
180
+ try {
181
+ const out = await runGit(wt.worktreePath, ["log", "-1", "--format=%cI"]);
182
+ const date = out.trim();
183
+ if (date) worktreeCommits[wt.branchName] = date;
184
+ } catch {
185
+ }
197
186
  }
187
+ } catch {
198
188
  }
199
- await saveGitStatusSnapshot(projects[0].id, {
189
+ await client.saveGitStatusSnapshot(projectId, {
200
190
  branch: branchInfo.branchName,
201
191
  branchLine,
202
192
  status,
@@ -218,17 +208,16 @@ async function cmdCheck(projectRoot, jsonOutput) {
218
208
  }
219
209
  }
220
210
  try {
221
- const { getGitBranchInfo } = await import("./git-wrapper-DVJ46TMA.js");
222
- const { getBranchOverview } = await import("./branch-overview-DSSCUE5F.js");
223
- const { saveBranchOverviewSnapshot } = await import("./git-snapshots-N3FBS7T3.js");
211
+ const { getGitBranchInfo } = await import("./git-wrapper-QRZYTYCZ.js");
212
+ const { getBranchOverview } = await import("./branch-overview-RRHX3XGY.js");
224
213
  const branchInfo = await getGitBranchInfo(projectRoot);
225
214
  let currentBranch = branchInfo.branchName;
226
215
  if (currentBranch?.startsWith("detached (")) currentBranch = null;
227
216
  const overview = await getBranchOverview(projectRoot, {
228
- projectId: projects[0].id,
217
+ projectId: null,
229
218
  currentBranch
230
219
  });
231
- await saveBranchOverviewSnapshot(projects[0].id, overview);
220
+ await client.saveBranchOverviewSnapshot(projectId, overview);
232
221
  if (!jsonOutput) {
233
222
  writeOut(`Branches: ${overview.branches.length} found`);
234
223
  }
@@ -244,14 +233,73 @@ async function cmdCheck(projectRoot, jsonOutput) {
244
233
  if (hasWarn) return 2;
245
234
  return 0;
246
235
  }
236
+ async function runLocalHealthChecks(projectRoot) {
237
+ const { existsSync } = await import("fs");
238
+ const { readFile } = await import("fs/promises");
239
+ const { join } = await import("path");
240
+ const { runGit } = await import("./git-wrapper-QRZYTYCZ.js");
241
+ const start = performance.now();
242
+ const checks = [];
243
+ const gitStart = performance.now();
244
+ try {
245
+ const output = await runGit(projectRoot, ["--version"]);
246
+ const version = output.trim().replace("git version ", "");
247
+ checks.push({ name: "Git", status: "pass", message: `Git ${version} found`, durationMs: Math.round(performance.now() - gitStart) });
248
+ } catch {
249
+ checks.push({ name: "Git", status: "fail", message: "Git not found or not working", durationMs: Math.round(performance.now() - gitStart) });
250
+ }
251
+ const hookStart = performance.now();
252
+ const hookPath = join(projectRoot, ".git", "hooks", "post-commit");
253
+ const CONDUCTOR_HOOK_MARKER = "# Conductor narration hook";
254
+ if (!existsSync(hookPath)) {
255
+ checks.push({
256
+ name: "Hooks",
257
+ status: "warn",
258
+ message: "Hooks not installed",
259
+ fixAction: { label: "Install hooks", href: "/git" },
260
+ durationMs: Math.round(performance.now() - hookStart)
261
+ });
262
+ } else {
263
+ try {
264
+ const content = await readFile(hookPath, "utf-8");
265
+ if (content.includes(CONDUCTOR_HOOK_MARKER)) {
266
+ checks.push({ name: "Hooks", status: "pass", message: "Hooks installed", durationMs: Math.round(performance.now() - hookStart) });
267
+ } else {
268
+ checks.push({
269
+ name: "Hooks",
270
+ status: "warn",
271
+ message: "Hook file exists but is not a Conductor hook",
272
+ fixAction: { label: "Install hooks", href: "/git" },
273
+ durationMs: Math.round(performance.now() - hookStart)
274
+ });
275
+ }
276
+ } catch {
277
+ checks.push({ name: "Hooks", status: "warn", message: "Could not read hook file", durationMs: Math.round(performance.now() - hookStart) });
278
+ }
279
+ }
280
+ const apiStart = performance.now();
281
+ try {
282
+ const { createDaemonClient } = await import("./daemon-client-CTYOJMJP.js");
283
+ await createDaemonClient().resolveProjectByPath(projectRoot);
284
+ checks.push({ name: "API", status: "pass", message: "Conductor server reachable", durationMs: Math.round(performance.now() - apiStart) });
285
+ } catch {
286
+ checks.push({ name: "API", status: "warn", message: "Conductor server not reachable", durationMs: Math.round(performance.now() - apiStart) });
287
+ }
288
+ const hasFail = checks.some((c) => c.status === "fail");
289
+ const hasWarn = checks.some((c) => c.status === "warn");
290
+ const overall = hasFail ? "unhealthy" : hasWarn ? "degraded" : "healthy";
291
+ return {
292
+ checks,
293
+ overall,
294
+ checkedAt: (/* @__PURE__ */ new Date()).toISOString(),
295
+ totalDurationMs: Math.round(performance.now() - start)
296
+ };
297
+ }
247
298
  async function cmdScan(projectRoot, jsonOutput) {
248
- const { scanWorktrees } = await import("./worktree-manager-2ZUJEL3L.js");
249
- const { query: dbQuery } = await import("./db-U6Y3QJDD.js");
250
- const projects = await dbQuery(
251
- "SELECT id FROM projects WHERE path = $1 LIMIT 1",
252
- [projectRoot]
253
- );
254
- if (projects.length === 0) {
299
+ const { createDaemonClient } = await import("./daemon-client-CTYOJMJP.js");
300
+ const client = createDaemonClient();
301
+ const project = await client.resolveProjectByPath(projectRoot);
302
+ if (!project) {
255
303
  if (jsonOutput) {
256
304
  writeOut(
257
305
  JSON.stringify({
@@ -266,8 +314,7 @@ async function cmdScan(projectRoot, jsonOutput) {
266
314
  }
267
315
  return 1;
268
316
  }
269
- const projectId = projects[0].id;
270
- const result = await scanWorktrees(projectId, projectRoot);
317
+ const { scan: result } = await client.scanWorktreesViaApi(project.id);
271
318
  if (jsonOutput) {
272
319
  writeOut(JSON.stringify(result, null, 2));
273
320
  } else {
@@ -293,7 +340,7 @@ async function cmdScan(projectRoot, jsonOutput) {
293
340
  async function cmdInit(projectRoot, jsonOutput) {
294
341
  const { resolve: resolvePath, basename, join } = await import("path");
295
342
  const { realpath, mkdir, readFile, writeFile, access } = await import("fs/promises");
296
- const { getServerBaseUrl } = await import("./cli-config-2ZDXUUQN.js");
343
+ const { getServerBaseUrl } = await import("./cli-config-LEERSU5N.js");
297
344
  let root = resolvePath(projectRoot.trim());
298
345
  try {
299
346
  root = await realpath(root);
@@ -368,7 +415,7 @@ async function cmdInit(projectRoot, jsonOutput) {
368
415
  return 0;
369
416
  }
370
417
  async function cmdHooks(projectRoot, subcommand, jsonOutput) {
371
- const { getHookStatus, installHooks } = await import("./git-hooks-UZJ6AER4.js");
418
+ const { getHookStatus, installHooks } = await import("./git-hooks-RQ6WJQS4.js");
372
419
  if (subcommand === "install") {
373
420
  const result = await installHooks(projectRoot);
374
421
  if (jsonOutput) {
@@ -410,13 +457,11 @@ async function cmdHooks(projectRoot, subcommand, jsonOutput) {
410
457
  return 2;
411
458
  }
412
459
  async function cmdWatch(projectRoot, once, jsonOutput) {
413
- const { claimNextTask, executeTask, failStaleTasks } = await import("./cli-tasks-NM5D5PIZ.js");
414
- const { query: dbQuery } = await import("./db-U6Y3QJDD.js");
415
- const projects = await dbQuery(
416
- "SELECT id FROM projects WHERE path = $1 LIMIT 1",
417
- [projectRoot]
418
- );
419
- if (projects.length === 0) {
460
+ const { createDaemonClient } = await import("./daemon-client-CTYOJMJP.js");
461
+ const { runGit } = await import("./git-wrapper-QRZYTYCZ.js");
462
+ const client = createDaemonClient();
463
+ const project = await client.resolveProjectByPath(projectRoot);
464
+ if (!project) {
420
465
  if (jsonOutput) {
421
466
  writeOut(
422
467
  JSON.stringify({
@@ -431,13 +476,56 @@ async function cmdWatch(projectRoot, once, jsonOutput) {
431
476
  }
432
477
  return 1;
433
478
  }
434
- const projectId = projects[0].id;
435
- const staleCount = await failStaleTasks(projectId);
479
+ const projectId = project.id;
480
+ async function executeTaskViaApi(task) {
481
+ try {
482
+ switch (task.taskType) {
483
+ case "remove_worktree": {
484
+ const worktreeId = task.payload.worktreeId;
485
+ if (!worktreeId) {
486
+ const msg = "Missing worktreeId in task payload.";
487
+ await client.failCliTask(task.id, msg);
488
+ return msg;
489
+ }
490
+ await client.removeWorktreeViaApi(projectId, worktreeId);
491
+ await client.completeCliTask(task.id, { worktreeId });
492
+ return `Removed worktree ${worktreeId}`;
493
+ }
494
+ case "delete_branch": {
495
+ const branchName = task.payload.branchName;
496
+ if (!branchName) {
497
+ const msg = "Missing branchName in task payload.";
498
+ await client.failCliTask(task.id, msg);
499
+ return msg;
500
+ }
501
+ await runGit(projectRoot, ["branch", "-D", branchName]);
502
+ await client.logGitActivityViaApi({
503
+ projectRoot,
504
+ eventType: "branch_delete",
505
+ branch: branchName,
506
+ summary: `Deleted branch "${branchName}"`
507
+ });
508
+ await client.completeCliTask(task.id, { branchName });
509
+ return `Deleted branch "${branchName}"`;
510
+ }
511
+ default: {
512
+ const msg = `Unknown task type: ${task.taskType}`;
513
+ await client.failCliTask(task.id, msg);
514
+ return msg;
515
+ }
516
+ }
517
+ } catch (err) {
518
+ const msg = err instanceof Error ? err.message : String(err);
519
+ await client.failCliTask(task.id, msg);
520
+ return `Failed: ${msg}`;
521
+ }
522
+ }
523
+ const staleCount = await client.failStaleCliTasks(projectId);
436
524
  if (staleCount > 0 && !jsonOutput) {
437
525
  writeOut(`Auto-failed ${staleCount} stale task(s).`);
438
526
  }
439
527
  if (once) {
440
- const task = await claimNextTask(projectId);
528
+ const task = await client.claimNextCliTask(projectId);
441
529
  if (!task) {
442
530
  if (jsonOutput) {
443
531
  writeOut(JSON.stringify({ message: "No pending tasks." }));
@@ -446,7 +534,7 @@ async function cmdWatch(projectRoot, once, jsonOutput) {
446
534
  }
447
535
  return 0;
448
536
  }
449
- const summary = await executeTask(task);
537
+ const summary = await executeTaskViaApi(task);
450
538
  if (jsonOutput) {
451
539
  writeOut(JSON.stringify({ taskId: task.id, taskType: task.taskType, summary }));
452
540
  } else {
@@ -468,9 +556,9 @@ async function cmdWatch(projectRoot, once, jsonOutput) {
468
556
  process.on("SIGTERM", shutdown);
469
557
  while (running) {
470
558
  try {
471
- const task = await claimNextTask(projectId);
559
+ const task = await client.claimNextCliTask(projectId);
472
560
  if (task) {
473
- const summary = await executeTask(task);
561
+ const summary = await executeTaskViaApi(task);
474
562
  if (jsonOutput) {
475
563
  writeOut(
476
564
  JSON.stringify({ taskId: task.id, taskType: task.taskType, summary })
@@ -479,7 +567,7 @@ async function cmdWatch(projectRoot, once, jsonOutput) {
479
567
  writeOut(`[${task.taskType}] ${summary}`);
480
568
  }
481
569
  }
482
- await failStaleTasks(projectId);
570
+ await client.failStaleCliTasks(projectId);
483
571
  } catch (err) {
484
572
  const msg = err instanceof Error ? err.message : String(err);
485
573
  if (!jsonOutput) {
@@ -496,23 +584,21 @@ async function cmdRun(opts) {
496
584
  const { spawn } = await import("child_process");
497
585
  const { readFileSync, existsSync } = await import("fs");
498
586
  const { assembleAutonomousPrompt } = await import("./runner-prompt-MOOPKA5P.js");
499
- const { computeWorkQueue } = await import("./work-queue-U3JYHLX2.js");
500
- const { query: dbQuery } = await import("./db-U6Y3QJDD.js");
501
- let project = opts.projectName ?? opts.projectRoot;
502
- if (opts.projectName) {
503
- const rows = await dbQuery(
504
- "SELECT path FROM projects WHERE name = $1 LIMIT 1",
505
- [opts.projectName]
506
- );
507
- if (rows.length === 0) {
508
- writeErr(`Project "${opts.projectName}" not found in Conductor.`);
509
- return 1;
510
- }
511
- if (rows[0].path === null) {
512
- writeErr(`Project "${opts.projectName}" has no local path registered.`);
513
- return 1;
514
- }
515
- project = rows[0].path;
587
+ const { createDaemonClient } = await import("./daemon-client-CTYOJMJP.js");
588
+ const client = createDaemonClient();
589
+ let project;
590
+ let projectId;
591
+ try {
592
+ const resolved = await client.resolveProject({
593
+ name: opts.projectName,
594
+ path: opts.projectName ? void 0 : opts.projectRoot
595
+ });
596
+ project = resolved.path;
597
+ projectId = resolved.id;
598
+ } catch (err) {
599
+ const msg = err instanceof Error ? err.message : String(err);
600
+ writeErr(`Project not found: ${msg}`);
601
+ return 1;
516
602
  }
517
603
  function ts() {
518
604
  return (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", { hour12: false });
@@ -556,7 +642,7 @@ async function cmdRun(opts) {
556
642
  });
557
643
  }
558
644
  async function getNextItem(skipIds) {
559
- const queue = await computeWorkQueue(project, 50, { autonomous: true });
645
+ const queue = await client.pollWorkQueue(projectId, 50, { autonomous: true });
560
646
  for (const item of queue.queue) {
561
647
  if (item.type === "deliverable" && (item.tier === "ready" || item.tier === "active") && !skipIds.has(item.entityId)) {
562
648
  return item;
@@ -678,16 +764,6 @@ async function main() {
678
764
  writeOut(HELP_TEXT);
679
765
  process.exit(parsed.help ? 0 : 1);
680
766
  }
681
- const needsDb = parsed.command !== "daemon";
682
- if (needsDb) {
683
- const hasDb = await ensureDatabaseUrl();
684
- if (!hasDb) {
685
- writeErr(
686
- "Could not find a database connection. Make sure the MCP server is running (npm run mcp) and try again."
687
- );
688
- process.exit(1);
689
- }
690
- }
691
767
  try {
692
768
  let exitCode;
693
769
  switch (parsed.command) {
@@ -727,7 +803,7 @@ async function main() {
727
803
  });
728
804
  break;
729
805
  case "daemon": {
730
- const { cmdDaemon, cmdDaemonCancel } = await import("./daemon-GGOJDZDB.js");
806
+ const { cmdDaemon, cmdDaemonCancel } = await import("./daemon-ZJDZIP3R.js");
731
807
  if (parsed.subcommand === "cancel") {
732
808
  exitCode = await cmdDaemonCancel(
733
809
  parsed.projectRoot,
@@ -1,10 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
+ ConductorError,
3
4
  runGit
4
- } from "./chunk-FAZ7FCZQ.js";
5
- import {
6
- query
7
- } from "./chunk-PANC6BTV.js";
5
+ } from "./chunk-N2KKNG4C.js";
8
6
 
9
7
  // ../../src/core/branch-overview-match.ts
10
8
  function slugifyTitle(title) {
@@ -71,6 +69,114 @@ function resolveDeliverableLink(branchName, hints, sessionByBranch) {
71
69
  return null;
72
70
  }
73
71
 
72
+ // ../../src/core/db.ts
73
+ import { Pool } from "pg";
74
+ var pool = null;
75
+ function getDatabaseUrl() {
76
+ const url = process.env.DATABASE_URL;
77
+ if (!url) {
78
+ throw new ConductorError(
79
+ "DB_UNREACHABLE" /* DB_UNREACHABLE */,
80
+ "DATABASE_URL is not set. Set it to your Supabase (or other Postgres) connection string."
81
+ );
82
+ }
83
+ return url;
84
+ }
85
+ function getPool() {
86
+ if (pool) {
87
+ return pool;
88
+ }
89
+ const connectionString = getDatabaseUrl();
90
+ const isRemote = connectionString.includes("supabase.co");
91
+ pool = new Pool({
92
+ connectionString,
93
+ max: 10,
94
+ connectionTimeoutMillis: 5e3,
95
+ idleTimeoutMillis: 3e4,
96
+ ...isRemote ? { ssl: { rejectUnauthorized: false } } : {}
97
+ });
98
+ pool.on("error", () => {
99
+ console.error(
100
+ "Unexpected database error on an idle connection. Check that Postgres is running."
101
+ );
102
+ });
103
+ return pool;
104
+ }
105
+ var TRANSIENT_CODES = /* @__PURE__ */ new Set(["ECONNRESET", "ECONNREFUSED", "ETIMEDOUT"]);
106
+ function isTransientConnectionError(err) {
107
+ const code = getErrorCode(err);
108
+ if (code && TRANSIENT_CODES.has(code)) return true;
109
+ const msg = err instanceof Error ? err.message : String(err);
110
+ return msg.includes("ECONNRESET") || msg.includes("ECONNREFUSED") || msg.includes("ETIMEDOUT") || msg.includes("connection terminated unexpectedly");
111
+ }
112
+ async function query(sql, params) {
113
+ const p = getPool();
114
+ try {
115
+ const result = await p.query(sql, params);
116
+ return result.rows;
117
+ } catch (err) {
118
+ if (isTransientConnectionError(err)) {
119
+ await new Promise((r) => setTimeout(r, 1e3));
120
+ try {
121
+ const result = await p.query(sql, params);
122
+ return result.rows;
123
+ } catch (retryErr) {
124
+ throw mapDbError(retryErr);
125
+ }
126
+ }
127
+ throw mapDbError(err);
128
+ }
129
+ }
130
+ function getErrorCode(err) {
131
+ if (err !== null && typeof err === "object" && "code" in err) {
132
+ const code = err.code;
133
+ return typeof code === "string" ? code : void 0;
134
+ }
135
+ return void 0;
136
+ }
137
+ function getBestErrorMessage(err) {
138
+ if (err instanceof AggregateError && err.errors.length > 0) {
139
+ const first = err.errors[0];
140
+ if (first instanceof Error && first.message.trim().length > 0) {
141
+ return first.message;
142
+ }
143
+ }
144
+ if (err instanceof Error && err.message.trim().length > 0) {
145
+ return err.message;
146
+ }
147
+ return String(err);
148
+ }
149
+ function mapDbError(err) {
150
+ const code = getErrorCode(err);
151
+ const message = getBestErrorMessage(err);
152
+ if (code === "ECONNREFUSED" || code === "ECONNRESET" || code === "ETIMEDOUT" || message.includes("ECONNREFUSED") || message.includes("ECONNRESET") || message.includes("ETIMEDOUT") || message.includes("connect ECONNREFUSED") || message.includes("connection terminated unexpectedly")) {
153
+ return new ConductorError(
154
+ "DB_UNREACHABLE" /* DB_UNREACHABLE */,
155
+ "Could not reach the database. Postgres may not be running on this machine.",
156
+ true
157
+ );
158
+ }
159
+ if (message.includes("password") || message.includes("authentication") || message.includes("28P01")) {
160
+ return new ConductorError(
161
+ "DB_QUERY_FAILED" /* DB_QUERY_FAILED */,
162
+ "Could not sign in to the database. Check your username and password."
163
+ );
164
+ }
165
+ if (message.includes("does not exist") && message.includes("database")) {
166
+ return new ConductorError(
167
+ "DB_QUERY_FAILED" /* DB_QUERY_FAILED */,
168
+ "That database does not exist yet. Create it first, then try again."
169
+ );
170
+ }
171
+ if (message.trim().length > 0) {
172
+ return new ConductorError("DB_QUERY_FAILED" /* DB_QUERY_FAILED */, message);
173
+ }
174
+ return new ConductorError(
175
+ "DB_QUERY_FAILED" /* DB_QUERY_FAILED */,
176
+ "Something went wrong while talking to the database."
177
+ );
178
+ }
179
+
74
180
  // ../../src/core/branch-overview.ts
75
181
  var STALE_MS = 7 * 24 * 60 * 60 * 1e3;
76
182
  var MAX_COMMITS = 20;
@@ -596,11 +702,10 @@ async function getMergeStats(projectRoot, defaultBranch, featureBranch) {
596
702
  const files = await loadChangedFiles(projectRoot, defaultBranch, featureBranch);
597
703
  return { commitCount, fileCount: files.length };
598
704
  }
599
-
600
705
  export {
601
- isBranchFullyOnMain,
602
- getConflictBranchesForWorkQueue,
603
- getBranchOverview,
604
706
  assertCanQueueMerge,
605
- getMergeStats
707
+ getBranchOverview,
708
+ getConflictBranchesForWorkQueue,
709
+ getMergeStats,
710
+ isBranchFullyOnMain
606
711
  };
@@ -1,12 +1,23 @@
1
1
  #!/usr/bin/env node
2
- import {
3
- ConductorError
4
- } from "./chunk-4YEHSYVN.js";
5
2
 
6
3
  // ../../src/core/git-wrapper.ts
7
4
  import { execFile } from "child_process";
8
5
  import { randomBytes } from "crypto";
9
6
  import { promisify } from "util";
7
+
8
+ // ../../src/core/errors.ts
9
+ var ConductorError = class extends Error {
10
+ code;
11
+ retryable;
12
+ constructor(code, message, retryable = false) {
13
+ super(message);
14
+ this.name = "ConductorError";
15
+ this.code = code;
16
+ this.retryable = retryable;
17
+ }
18
+ };
19
+
20
+ // ../../src/core/git-wrapper.ts
10
21
  var execFileAsync = promisify(execFile);
11
22
  var MAX_BUFFER = 10 * 1024 * 1024;
12
23
  var READ_TIMEOUT_MS = 3e4;
@@ -520,6 +531,7 @@ async function executeNarrated(projectRoot, gitArgs) {
520
531
  }
521
532
 
522
533
  export {
534
+ ConductorError,
523
535
  runGit,
524
536
  getGitBranchInfo,
525
537
  formatGitBranchLine,
@@ -123,14 +123,13 @@ async function ensureDatabaseUrl() {
123
123
  }
124
124
  return false;
125
125
  }
126
-
127
126
  export {
128
- readConfig,
129
- writeConfig,
130
- readApiKey,
131
- readProjectId,
132
- getServerBaseUrl,
127
+ ensureDatabaseUrl,
133
128
  fetchConfigFromServer,
129
+ getServerBaseUrl,
134
130
  postToServer,
135
- ensureDatabaseUrl
131
+ readApiKey,
132
+ readConfig,
133
+ readProjectId,
134
+ writeConfig
136
135
  };
@@ -16,7 +16,7 @@ function log(msg) {
16
16
  async function cmdDaemonCancel(projectRoot, projectName, jsonOutput, apiUrl, apiKey) {
17
17
  const { existsSync, readFileSync, unlinkSync } = await import("fs");
18
18
  const { join } = await import("path");
19
- const { createDaemonClient } = await import("./daemon-client-BE64H437.js");
19
+ const { createDaemonClient } = await import("./daemon-client-CTYOJMJP.js");
20
20
  const resolvedUrl = apiUrl ?? process.env.CONDUCTOR_API_URL;
21
21
  const client = createDaemonClient(resolvedUrl, apiKey);
22
22
  let projectId;
@@ -66,13 +66,13 @@ async function cmdDaemonCancel(projectRoot, projectName, jsonOutput, apiUrl, api
66
66
  async function cmdDaemon(opts) {
67
67
  const { mkdirSync, writeFileSync, unlinkSync, existsSync, readFileSync } = await import("fs");
68
68
  const { join } = await import("path");
69
- const { createDaemonClient } = await import("./daemon-client-BE64H437.js");
69
+ const { createDaemonClient } = await import("./daemon-client-CTYOJMJP.js");
70
70
  const resolvedUrl = opts.apiUrl ?? process.env.CONDUCTOR_API_URL;
71
71
  const client = createDaemonClient(resolvedUrl, opts.apiKey);
72
72
  let projectPath;
73
73
  let projectId;
74
74
  try {
75
- const { readProjectId } = await import("./cli-config-2ZDXUUQN.js");
75
+ const { readProjectId } = await import("./cli-config-LEERSU5N.js");
76
76
  const configProjectId = readProjectId();
77
77
  if (configProjectId) {
78
78
  projectId = configProjectId;
@@ -137,7 +137,7 @@ async function cmdDaemon(opts) {
137
137
  process.on("SIGTERM", shutdown);
138
138
  let fileConfig = {};
139
139
  try {
140
- const { readConfig } = await import("./cli-config-2ZDXUUQN.js");
140
+ const { readConfig } = await import("./cli-config-LEERSU5N.js");
141
141
  const config = readConfig(projectPath);
142
142
  fileConfig = config.daemon ?? {};
143
143
  } catch {
@@ -393,22 +393,31 @@ async function cmdDaemon(opts) {
393
393
  }
394
394
  if (daemonConfig.useWorktree && task.initiativeId) {
395
395
  try {
396
- const {
397
- createWorktree,
398
- getWorktreeForInitiative
399
- } = await import("./worktree-manager-2ZUJEL3L.js");
400
- const existing = await getWorktreeForInitiative(projectId, task.initiativeId);
396
+ const existing = await client.getWorktreeForInitiative(projectId, task.initiativeId);
401
397
  if (existing) {
402
398
  worktreePath = existing.worktreePath;
403
399
  log(`Reusing existing worktree at ${worktreePath}`);
404
400
  } else {
405
- const wt = await createWorktree(
401
+ const { runGit } = await import("./git-wrapper-QRZYTYCZ.js");
402
+ const path = await import("path");
403
+ const slug = (initiativeTitle ?? "unknown").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 60);
404
+ const branchName = slug;
405
+ const parentDir = path.dirname(projectPath);
406
+ const projectDir = path.basename(projectPath);
407
+ const worktreeDir = path.join(parentDir, `${projectDir}--${slug}`);
408
+ try {
409
+ await runGit(projectPath, ["rev-parse", "--verify", branchName]);
410
+ } catch {
411
+ await runGit(projectPath, ["branch", branchName]);
412
+ }
413
+ await runGit(projectPath, ["worktree", "add", worktreeDir, branchName]);
414
+ await client.registerWorktree({
406
415
  projectId,
407
- projectPath,
408
- task.initiativeId,
409
- initiativeTitle ?? "unknown"
410
- );
411
- worktreePath = wt.worktreePath;
416
+ initiativeId: task.initiativeId,
417
+ branchName,
418
+ worktreePath: worktreeDir
419
+ });
420
+ worktreePath = worktreeDir;
412
421
  log(`Created worktree for "${initiativeTitle}" at ${worktreePath}`);
413
422
  }
414
423
  } catch (err) {