pure-point-guard 0.3.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -95,7 +95,7 @@ var init_errors = __esm({
95
95
  constructor(names) {
96
96
  const list = names.map((n) => ` ${n}`).join("\n");
97
97
  super(
98
- `${names.length} worktree(s) have completed work that hasn't been merged or PR'd:
98
+ `${names.length} worktree(s) have unmerged work that hasn't been PR'd:
99
99
  ${list}
100
100
 
101
101
  Use --force to reset anyway, or create PRs first with: ppg pr <worktree-id>`,
@@ -163,7 +163,7 @@ function success(message) {
163
163
  function warn(message) {
164
164
  console.log(`${YELLOW}\u26A0${RESET} ${message}`);
165
165
  }
166
- var RESET, BOLD, DIM, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, GRAY, STATUS_COLORS;
166
+ var RESET, BOLD, DIM, RED, GREEN, YELLOW, BLUE, CYAN, GRAY, STATUS_COLORS;
167
167
  var init_output = __esm({
168
168
  "src/lib/output.ts"() {
169
169
  "use strict";
@@ -174,20 +174,17 @@ var init_output = __esm({
174
174
  GREEN = "\x1B[32m";
175
175
  YELLOW = "\x1B[33m";
176
176
  BLUE = "\x1B[34m";
177
- MAGENTA = "\x1B[35m";
178
177
  CYAN = "\x1B[36m";
179
178
  GRAY = "\x1B[90m";
180
179
  STATUS_COLORS = {
181
- spawning: YELLOW,
182
180
  running: GREEN,
183
- waiting: CYAN,
184
- completed: BLUE,
185
- failed: RED,
186
- killed: MAGENTA,
187
- lost: RED + BOLD,
181
+ idle: CYAN,
182
+ exited: BLUE,
183
+ gone: GRAY,
188
184
  active: GREEN,
189
185
  merging: YELLOW,
190
186
  merged: BLUE,
187
+ failed: RED,
191
188
  cleaned: GRAY
192
189
  };
193
190
  }
@@ -325,29 +322,17 @@ var init_config = __esm({
325
322
  claude: {
326
323
  name: "claude",
327
324
  command: "claude --dangerously-skip-permissions",
328
- interactive: true,
329
- resultInstructions: [
330
- "When you have completed the task:",
331
- "",
332
- "1. Stage and commit all your changes with a descriptive commit message",
333
- "2. Push your branch: git push -u origin {{BRANCH}}",
334
- "3. Create a pull request: gh pr create --head {{BRANCH}} --base main --fill",
335
- "4. Write your results to {{RESULT_FILE}} in this format:",
336
- "",
337
- "# Result: {{AGENT_ID}}",
338
- "",
339
- "## PR",
340
- "<the PR URL from step 3>",
341
- "",
342
- "## Summary",
343
- "<what you accomplished>",
344
- "",
345
- "## Changes",
346
- "<list of files changed>",
347
- "",
348
- "## Notes",
349
- "<any important observations>"
350
- ].join("\n")
325
+ interactive: true
326
+ },
327
+ codex: {
328
+ name: "codex",
329
+ command: "codex --yolo",
330
+ interactive: true
331
+ },
332
+ opencode: {
333
+ name: "opencode",
334
+ command: "opencode --yolo",
335
+ interactive: true
351
336
  }
352
337
  },
353
338
  envFiles: [".env", ".env.local"],
@@ -977,11 +962,19 @@ var init_init = __esm({
977
962
 
978
963
  You are operating on the master branch of a ppg-managed project.
979
964
 
980
- ## Critical Rule
981
- **NEVER make code changes directly on the master branch.** Use \`ppg spawn\` to create worktrees.
965
+ ## When to Use ppg
966
+ Use \`ppg spawn\` whenever you want work to appear in the **ppg dashboard** \u2014 parallel tasks, code reviews,
967
+ batch issue work, multi-agent swarms. Agents spawned through ppg run in tmux panes the user can monitor,
968
+ interact with, and manage. Available agent types: \`claude\` (default), \`codex\`, \`opencode\` via \`--agent\`.
969
+
970
+ Direct edits, quick commands, and research are fine to do yourself \u2014 not everything needs an agent.
971
+ Never run \`claude\`, \`codex\`, or \`opencode\` directly as bash commands \u2014 they won't appear in the dashboard.
982
972
 
983
973
  ## Quick Reference
984
974
  - \`ppg spawn --name <name> --prompt "<task>" --json\` \u2014 Spawn worktree + agent
975
+ - \`ppg spawn --name <name> --agent codex --prompt "<task>" --json\` \u2014 Use Codex agent
976
+ - \`ppg spawn --name <name> --agent opencode --prompt "<task>" --json\` \u2014 Use OpenCode agent
977
+ - \`ppg spawn --worktree <id> --agent codex --prompt "review --base main" --json\` \u2014 Codex review
985
978
  - \`ppg status --json\` \u2014 Check statuses
986
979
  - \`ppg aggregate --all --json\` \u2014 Collect results (includes PR URLs)
987
980
  - \`ppg kill --agent <id> --json\` \u2014 Kill agent
@@ -1046,6 +1039,11 @@ async function createWorktree(repoRoot, id, options) {
1046
1039
  await execa3("git", args, { ...execaEnv, cwd: repoRoot });
1047
1040
  return wtPath;
1048
1041
  }
1042
+ async function adoptWorktree(repoRoot, id, branch) {
1043
+ const wtPath = worktreePath(repoRoot, id);
1044
+ await execa3("git", ["worktree", "add", wtPath, branch], { ...execaEnv, cwd: repoRoot });
1045
+ return wtPath;
1046
+ }
1049
1047
  async function removeWorktree(repoRoot, wtPath, options) {
1050
1048
  const args = ["worktree", "remove", wtPath];
1051
1049
  if (options?.force) {
@@ -1169,31 +1167,12 @@ async function spawnAgent(options) {
1169
1167
  agentId: agentId2,
1170
1168
  agentConfig,
1171
1169
  prompt,
1172
- worktreePath: worktreePath2,
1173
1170
  tmuxTarget,
1174
- projectRoot,
1175
- branch
1171
+ projectRoot
1176
1172
  } = options;
1177
- const resFile = resultFile(projectRoot, agentId2);
1178
- let fullPrompt = prompt;
1179
- if (agentConfig.resultInstructions && !options.skipResultInstructions) {
1180
- const ctx = {
1181
- WORKTREE_PATH: worktreePath2,
1182
- BRANCH: branch,
1183
- AGENT_ID: agentId2,
1184
- RESULT_FILE: resFile,
1185
- PROJECT_ROOT: projectRoot
1186
- };
1187
- const instructions = renderTemplate(agentConfig.resultInstructions, ctx);
1188
- fullPrompt += `
1189
-
1190
- ---
1191
-
1192
- ${instructions}`;
1193
- }
1194
1173
  const pFile = agentPromptFile(projectRoot, agentId2);
1195
1174
  await fs6.mkdir(agentPromptsDir(projectRoot), { recursive: true });
1196
- await fs6.writeFile(pFile, fullPrompt, "utf-8");
1175
+ await fs6.writeFile(pFile, prompt, "utf-8");
1197
1176
  const command = buildAgentCommand(agentConfig, pFile, options.sessionId);
1198
1177
  await sendKeys(tmuxTarget, command);
1199
1178
  return {
@@ -1204,7 +1183,6 @@ ${instructions}`;
1204
1183
  tmuxTarget,
1205
1184
  prompt: prompt.slice(0, 500),
1206
1185
  // Truncate for manifest storage
1207
- resultFile: resFile,
1208
1186
  startedAt: (/* @__PURE__ */ new Date()).toISOString(),
1209
1187
  ...options.sessionId ? { sessionId: options.sessionId } : {}
1210
1188
  };
@@ -1219,32 +1197,16 @@ function buildAgentCommand(agentConfig, promptFilePath, sessionId2) {
1219
1197
  }
1220
1198
  return `${envPrefix} ${command}${sessionFlag} ${catExpr}`;
1221
1199
  }
1222
- async function checkAgentStatus(agent, projectRoot, paneMap) {
1223
- if (["completed", "failed", "killed", "lost"].includes(agent.status)) {
1224
- return { status: agent.status, exitCode: agent.exitCode };
1225
- }
1226
- const hasResult = await fileExists(agent.resultFile);
1227
- if (hasResult) {
1228
- return { status: "completed" };
1229
- }
1200
+ async function checkAgentStatus(agent, _projectRoot, paneMap) {
1230
1201
  const paneInfo = paneMap ? paneMap.get(agent.tmuxTarget) ?? null : await getPaneInfo(agent.tmuxTarget);
1231
1202
  if (!paneInfo) {
1232
- return { status: "lost" };
1203
+ return { status: "gone" };
1233
1204
  }
1234
1205
  if (paneInfo.isDead) {
1235
- const exitCode = paneInfo.deadStatus;
1236
- const hasResultNow = await fileExists(agent.resultFile);
1237
- if (hasResultNow || exitCode === 0) {
1238
- return { status: "completed", exitCode: exitCode ?? 0 };
1239
- }
1240
- return { status: "failed", exitCode };
1206
+ return { status: "exited", exitCode: paneInfo.deadStatus };
1241
1207
  }
1242
1208
  if (SHELL_COMMANDS.has(paneInfo.currentCommand)) {
1243
- const hasResultNow = await fileExists(agent.resultFile);
1244
- if (hasResultNow) {
1245
- return { status: "completed", exitCode: 0 };
1246
- }
1247
- return { status: "failed", exitCode: void 0 };
1209
+ return { status: "idle" };
1248
1210
  }
1249
1211
  return { status: "running" };
1250
1212
  }
@@ -1260,27 +1222,18 @@ async function refreshAllAgentStatuses(manifest, projectRoot) {
1260
1222
  }
1261
1223
  }
1262
1224
  const results = await Promise.all(checks.map((c) => c.promise));
1263
- const now = (/* @__PURE__ */ new Date()).toISOString();
1264
1225
  for (let i = 0; i < checks.length; i++) {
1265
1226
  const { agent } = checks[i];
1266
1227
  const { status, exitCode } = results[i];
1267
- if (status !== agent.status) {
1268
- agent.status = status;
1269
- if (exitCode !== void 0) agent.exitCode = exitCode;
1270
- if (["completed", "failed", "lost"].includes(status) && !agent.completedAt) {
1271
- agent.completedAt = now;
1272
- }
1273
- }
1228
+ agent.status = status;
1229
+ if (exitCode !== void 0) agent.exitCode = exitCode;
1274
1230
  }
1275
1231
  const wtChecks = Object.values(manifest.worktrees).filter((wt) => wt.status === "active").map(async (wt) => {
1276
1232
  const exists = await fileExists(wt.path);
1277
1233
  if (!exists) {
1278
1234
  wt.status = "cleaned";
1279
1235
  for (const agent of Object.values(wt.agents)) {
1280
- if (!["completed", "failed", "killed"].includes(agent.status)) {
1281
- agent.status = "lost";
1282
- if (!agent.completedAt) agent.completedAt = now;
1283
- }
1236
+ agent.status = "gone";
1284
1237
  }
1285
1238
  }
1286
1239
  });
@@ -1356,7 +1309,6 @@ var init_agent = __esm({
1356
1309
  init_tmux();
1357
1310
  init_manifest();
1358
1311
  init_errors();
1359
- init_template();
1360
1312
  init_tmux();
1361
1313
  SHELL_COMMANDS = /* @__PURE__ */ new Set(["bash", "zsh", "sh", "fish", "dash", "tcsh", "csh"]);
1362
1314
  }
@@ -1478,6 +1430,12 @@ async function spawnCommand(options) {
1478
1430
  const count = options.count ?? 1;
1479
1431
  const userVars = parseVars(options.var ?? []);
1480
1432
  const promptText = await resolvePrompt(options, projectRoot);
1433
+ if (options.branch && options.worktree) {
1434
+ throw new PpgError("--branch and --worktree are mutually exclusive", "INVALID_ARGS");
1435
+ }
1436
+ if (options.branch && options.base) {
1437
+ throw new PpgError("--branch and --base are mutually exclusive (--base is for new branches)", "INVALID_ARGS");
1438
+ }
1481
1439
  if (options.worktree) {
1482
1440
  await spawnIntoExistingWorktree(
1483
1441
  projectRoot,
@@ -1489,6 +1447,17 @@ async function spawnCommand(options) {
1489
1447
  options,
1490
1448
  userVars
1491
1449
  );
1450
+ } else if (options.branch) {
1451
+ await spawnOnExistingBranch(
1452
+ projectRoot,
1453
+ config,
1454
+ agentConfig,
1455
+ options.branch,
1456
+ promptText,
1457
+ count,
1458
+ options,
1459
+ userVars
1460
+ );
1492
1461
  } else {
1493
1462
  await spawnNewWorktree(
1494
1463
  projectRoot,
@@ -1558,7 +1527,6 @@ async function spawnNewWorktree(projectRoot, config, agentConfig, promptText, co
1558
1527
  WORKTREE_PATH: wtPath,
1559
1528
  BRANCH: branchName,
1560
1529
  AGENT_ID: aId,
1561
- RESULT_FILE: resultFile(projectRoot, aId),
1562
1530
  PROJECT_ROOT: projectRoot,
1563
1531
  TASK_NAME: name,
1564
1532
  PROMPT: promptText
@@ -1611,6 +1579,102 @@ async function spawnNewWorktree(projectRoot, config, agentConfig, promptText, co
1611
1579
  info(`Attach: ppg attach ${wtId}`);
1612
1580
  }
1613
1581
  }
1582
+ async function spawnOnExistingBranch(projectRoot, config, agentConfig, branch, promptText, count, options, userVars) {
1583
+ const baseBranch = await getCurrentBranch(projectRoot);
1584
+ const wtId = worktreeId();
1585
+ const derivedName = branch.startsWith("ppg/") ? branch.slice(4) : branch;
1586
+ const name = options.name ? normalizeName(options.name, wtId) : normalizeName(derivedName, wtId);
1587
+ info(`Creating worktree ${wtId} from existing branch ${branch}`);
1588
+ const wtPath = await adoptWorktree(projectRoot, wtId, branch);
1589
+ await setupWorktreeEnv(projectRoot, wtPath, config);
1590
+ const manifest = await readManifest(projectRoot);
1591
+ const sessionName = manifest.sessionName;
1592
+ await ensureSession(sessionName);
1593
+ const windowTarget = await createWindow(sessionName, name, wtPath);
1594
+ const worktreeEntry = {
1595
+ id: wtId,
1596
+ name,
1597
+ path: wtPath,
1598
+ branch,
1599
+ baseBranch,
1600
+ status: "active",
1601
+ tmuxWindow: windowTarget,
1602
+ agents: {},
1603
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
1604
+ };
1605
+ await updateManifest(projectRoot, (m) => {
1606
+ m.worktrees[wtId] = worktreeEntry;
1607
+ return m;
1608
+ });
1609
+ const agents = [];
1610
+ for (let i = 0; i < count; i++) {
1611
+ const aId = agentId();
1612
+ let target;
1613
+ if (i === 0) {
1614
+ target = windowTarget;
1615
+ } else if (options.split) {
1616
+ const direction = i % 2 === 1 ? "horizontal" : "vertical";
1617
+ const pane = await splitPane(windowTarget, direction, wtPath);
1618
+ target = pane.target;
1619
+ } else {
1620
+ target = await createWindow(sessionName, `${name}-${i}`, wtPath);
1621
+ }
1622
+ const ctx = {
1623
+ WORKTREE_PATH: wtPath,
1624
+ BRANCH: branch,
1625
+ AGENT_ID: aId,
1626
+ PROJECT_ROOT: projectRoot,
1627
+ TASK_NAME: name,
1628
+ PROMPT: promptText
1629
+ };
1630
+ Object.assign(ctx, userVars);
1631
+ const renderedPrompt = renderTemplate(promptText, ctx);
1632
+ const agentEntry = await spawnAgent({
1633
+ agentId: aId,
1634
+ agentConfig,
1635
+ prompt: renderedPrompt,
1636
+ worktreePath: wtPath,
1637
+ tmuxTarget: target,
1638
+ projectRoot,
1639
+ branch,
1640
+ sessionId: sessionId()
1641
+ });
1642
+ agents.push(agentEntry);
1643
+ await updateManifest(projectRoot, (m) => {
1644
+ if (m.worktrees[wtId]) {
1645
+ m.worktrees[wtId].agents[agentEntry.id] = agentEntry;
1646
+ }
1647
+ return m;
1648
+ });
1649
+ }
1650
+ if (options.open === true) {
1651
+ openTerminalWindow(sessionName, windowTarget, name).catch(() => {
1652
+ });
1653
+ }
1654
+ if (options.json) {
1655
+ output({
1656
+ success: true,
1657
+ worktree: {
1658
+ id: wtId,
1659
+ name,
1660
+ branch,
1661
+ path: wtPath,
1662
+ tmuxWindow: windowTarget
1663
+ },
1664
+ agents: agents.map((a) => ({
1665
+ id: a.id,
1666
+ tmuxTarget: a.tmuxTarget,
1667
+ sessionId: a.sessionId
1668
+ }))
1669
+ }, true);
1670
+ } else {
1671
+ success(`Spawned worktree ${wtId} from branch ${branch} with ${agents.length} agent(s)`);
1672
+ for (const a of agents) {
1673
+ info(` Agent ${a.id} \u2192 ${a.tmuxTarget}`);
1674
+ }
1675
+ info(`Attach: ppg attach ${wtId}`);
1676
+ }
1677
+ }
1614
1678
  async function spawnIntoExistingWorktree(projectRoot, config, agentConfig, worktreeRef, promptText, count, options, userVars) {
1615
1679
  const manifest = await readManifest(projectRoot);
1616
1680
  const wt = resolveWorktree(manifest, worktreeRef);
@@ -1637,7 +1701,6 @@ async function spawnIntoExistingWorktree(projectRoot, config, agentConfig, workt
1637
1701
  WORKTREE_PATH: wt.path,
1638
1702
  BRANCH: wt.branch,
1639
1703
  AGENT_ID: aId,
1640
- RESULT_FILE: resultFile(projectRoot, aId),
1641
1704
  PROJECT_ROOT: projectRoot,
1642
1705
  TASK_NAME: wt.name,
1643
1706
  PROMPT: promptText
@@ -1713,6 +1776,7 @@ var init_spawn = __esm({
1713
1776
  // src/commands/status.ts
1714
1777
  var status_exports = {};
1715
1778
  __export(status_exports, {
1779
+ computeLifecycle: () => computeLifecycle,
1716
1780
  statusCommand: () => statusCommand
1717
1781
  });
1718
1782
  async function statusCommand(worktreeFilter, options) {
@@ -1731,7 +1795,7 @@ async function statusCommand(worktreeFilter, options) {
1731
1795
  if (options?.json) {
1732
1796
  output({
1733
1797
  session: manifest.sessionName,
1734
- worktrees: Object.fromEntries(worktrees.map((wt) => [wt.id, wt]))
1798
+ worktrees: Object.fromEntries(worktrees.map((wt) => [wt.id, { ...wt, lifecycle: computeLifecycle(wt) }]))
1735
1799
  }, true);
1736
1800
  return;
1737
1801
  }
@@ -1770,12 +1834,6 @@ async function statusCommand(worktreeFilter, options) {
1770
1834
  }
1771
1835
  function printWorktreeStatus(wt) {
1772
1836
  const agents = Object.values(wt.agents);
1773
- const statusCounts = {
1774
- running: agents.filter((a) => a.status === "running").length,
1775
- completed: agents.filter((a) => a.status === "completed").length,
1776
- failed: agents.filter((a) => a.status === "failed").length,
1777
- lost: agents.filter((a) => a.status === "lost").length
1778
- };
1779
1837
  console.log(
1780
1838
  `
1781
1839
  ${wt.name} (${wt.id}) [${formatStatus(wt.status)}] branch:${wt.branch}`
@@ -1799,6 +1857,14 @@ ${wt.name} (${wt.id}) [${formatStatus(wt.status)}] branch:${wt.branch}`
1799
1857
  const table = formatTable(agents, columns);
1800
1858
  console.log(table.split("\n").map((l) => ` ${l}`).join("\n"));
1801
1859
  }
1860
+ function computeLifecycle(wt) {
1861
+ if (wt.status === "merged") return "merged";
1862
+ if (wt.status === "cleaned") return "cleaned";
1863
+ const agents = Object.values(wt.agents);
1864
+ if (agents.some((a) => a.status === "running")) return "busy";
1865
+ if (wt.prUrl) return "shipped";
1866
+ return "idle";
1867
+ }
1802
1868
  function formatTime(iso) {
1803
1869
  if (!iso) return "\u2014";
1804
1870
  const d = new Date(iso);
@@ -1999,7 +2065,7 @@ async function killSingleAgent(projectRoot, agentId2, options, selfPaneId, paneM
1999
2065
  const found = findAgent(manifest, agentId2);
2000
2066
  if (!found) throw new AgentNotFoundError(agentId2);
2001
2067
  const { agent } = found;
2002
- const isTerminal = ["completed", "failed", "killed", "lost"].includes(agent.status);
2068
+ const isTerminal = agent.status !== "running";
2003
2069
  if (selfPaneId && paneMap) {
2004
2070
  const { skipped } = excludeSelf([agent], selfPaneId, paneMap);
2005
2071
  if (skipped.length > 0) {
@@ -2042,8 +2108,7 @@ async function killSingleAgent(projectRoot, agentId2, options, selfPaneId, paneM
2042
2108
  await updateManifest(projectRoot, (m) => {
2043
2109
  const f = findAgent(m, agentId2);
2044
2110
  if (f) {
2045
- f.agent.status = "killed";
2046
- f.agent.completedAt = (/* @__PURE__ */ new Date()).toISOString();
2111
+ f.agent.status = "gone";
2047
2112
  }
2048
2113
  return m;
2049
2114
  });
@@ -2058,7 +2123,7 @@ async function killWorktreeAgents(projectRoot, worktreeRef, options, selfPaneId,
2058
2123
  const manifest = await readManifest(projectRoot);
2059
2124
  const wt = resolveWorktree(manifest, worktreeRef);
2060
2125
  if (!wt) throw new WorktreeNotFoundError(worktreeRef);
2061
- let toKill = Object.values(wt.agents).filter((a) => ["running", "spawning", "waiting"].includes(a.status));
2126
+ let toKill = Object.values(wt.agents).filter((a) => a.status === "running");
2062
2127
  const skippedIds = [];
2063
2128
  if (selfPaneId && paneMap) {
2064
2129
  const { safe, skipped } = excludeSelf(toKill, selfPaneId, paneMap);
@@ -2076,8 +2141,7 @@ async function killWorktreeAgents(projectRoot, worktreeRef, options, selfPaneId,
2076
2141
  if (mWt) {
2077
2142
  for (const agent of Object.values(mWt.agents)) {
2078
2143
  if (killedIds.includes(agent.id)) {
2079
- agent.status = "killed";
2080
- agent.completedAt = (/* @__PURE__ */ new Date()).toISOString();
2144
+ agent.status = "gone";
2081
2145
  }
2082
2146
  }
2083
2147
  }
@@ -2127,7 +2191,7 @@ async function killAllAgents(projectRoot, options, selfPaneId, paneMap) {
2127
2191
  let toKill = [];
2128
2192
  for (const wt of Object.values(manifest.worktrees)) {
2129
2193
  for (const agent of Object.values(wt.agents)) {
2130
- if (["running", "spawning", "waiting"].includes(agent.status)) {
2194
+ if (agent.status === "running") {
2131
2195
  toKill.push(agent);
2132
2196
  }
2133
2197
  }
@@ -2149,8 +2213,7 @@ async function killAllAgents(projectRoot, options, selfPaneId, paneMap) {
2149
2213
  for (const wt of Object.values(m.worktrees)) {
2150
2214
  for (const agent of Object.values(wt.agents)) {
2151
2215
  if (killedIds.includes(agent.id)) {
2152
- agent.status = "killed";
2153
- agent.completedAt = (/* @__PURE__ */ new Date()).toISOString();
2216
+ agent.status = "gone";
2154
2217
  }
2155
2218
  }
2156
2219
  }
@@ -2396,13 +2459,12 @@ async function aggregateCommand(worktreeId2, options) {
2396
2459
  worktrees = [wt];
2397
2460
  } else {
2398
2461
  worktrees = Object.values(manifest.worktrees).filter(
2399
- (wt) => Object.values(wt.agents).some((a) => a.status === "completed")
2462
+ (wt) => Object.values(wt.agents).some((a) => a.status !== "running")
2400
2463
  );
2401
2464
  }
2402
2465
  const results = [];
2403
2466
  for (const wt of worktrees) {
2404
2467
  for (const agent of Object.values(wt.agents)) {
2405
- if (agent.status !== "completed" && agent.status !== "failed") continue;
2406
2468
  const result = await collectAgentResult(agent, projectRoot);
2407
2469
  results.push({
2408
2470
  agentId: agent.id,
@@ -2418,7 +2480,7 @@ async function aggregateCommand(worktreeId2, options) {
2418
2480
  if (options?.json) {
2419
2481
  output({ results: [] }, true);
2420
2482
  } else {
2421
- console.log("No completed agent results to aggregate.");
2483
+ console.log("No agent results to aggregate.");
2422
2484
  }
2423
2485
  return;
2424
2486
  }
@@ -2447,20 +2509,18 @@ async function aggregateCommand(worktreeId2, options) {
2447
2509
  }
2448
2510
  }
2449
2511
  async function collectAgentResult(agent, projectRoot) {
2450
- try {
2451
- const content = await fs9.readFile(agent.resultFile, "utf-8");
2452
- return content;
2453
- } catch {
2454
- }
2455
2512
  try {
2456
2513
  const paneContent = await capturePane(agent.tmuxTarget, 500);
2457
- return `*[No result file \u2014 pane capture fallback]*
2458
-
2459
- \`\`\`
2514
+ return `\`\`\`
2460
2515
  ${paneContent}
2461
2516
  \`\`\``;
2462
2517
  } catch {
2463
- return "*[No result file and pane not available]*";
2518
+ }
2519
+ try {
2520
+ const content = await fs9.readFile(resultFile(projectRoot, agent.id), "utf-8");
2521
+ return content;
2522
+ } catch {
2523
+ return "*[Pane not available and no legacy result file]*";
2464
2524
  }
2465
2525
  }
2466
2526
  var init_aggregate = __esm({
@@ -2470,6 +2530,7 @@ var init_aggregate = __esm({
2470
2530
  init_agent();
2471
2531
  init_worktree();
2472
2532
  init_tmux();
2533
+ init_paths();
2473
2534
  init_errors();
2474
2535
  init_output();
2475
2536
  }
@@ -2490,7 +2551,7 @@ async function mergeCommand(worktreeId2, options) {
2490
2551
  const wt = resolveWorktree(manifest, worktreeId2);
2491
2552
  if (!wt) throw new WorktreeNotFoundError(worktreeId2);
2492
2553
  const agents = Object.values(wt.agents);
2493
- const incomplete = agents.filter((a) => !["completed", "failed", "killed"].includes(a.status));
2554
+ const incomplete = agents.filter((a) => a.status === "running");
2494
2555
  if (incomplete.length > 0 && !options.force) {
2495
2556
  const ids = incomplete.map((a) => a.id).join(", ");
2496
2557
  throw new PpgError(
@@ -2753,7 +2814,6 @@ async function spawnSwarmAgent(opts) {
2753
2814
  WORKTREE_PATH: wtPath,
2754
2815
  BRANCH: branchName,
2755
2816
  AGENT_ID: aId,
2756
- RESULT_FILE: resultFile(projectRoot, aId),
2757
2817
  PROJECT_ROOT: projectRoot,
2758
2818
  TASK_NAME: taskName,
2759
2819
  ...swarmAgent.vars ?? {},
@@ -3213,7 +3273,7 @@ async function restartCommand(agentRef, options) {
3213
3273
  const found = findAgent(manifest, agentRef);
3214
3274
  if (!found) throw new AgentNotFoundError(agentRef);
3215
3275
  const { worktree: wt, agent: oldAgent } = found;
3216
- if (["running", "spawning", "waiting"].includes(oldAgent.status)) {
3276
+ if (oldAgent.status === "running") {
3217
3277
  info(`Killing existing agent ${oldAgent.id}`);
3218
3278
  await killAgent(oldAgent);
3219
3279
  }
@@ -3239,7 +3299,6 @@ async function restartCommand(agentRef, options) {
3239
3299
  WORKTREE_PATH: wt.path,
3240
3300
  BRANCH: wt.branch,
3241
3301
  AGENT_ID: newAgentId,
3242
- RESULT_FILE: resultFile(projectRoot, newAgentId),
3243
3302
  PROJECT_ROOT: projectRoot,
3244
3303
  TASK_NAME: wt.name,
3245
3304
  PROMPT: promptText
@@ -3254,16 +3313,14 @@ async function restartCommand(agentRef, options) {
3254
3313
  tmuxTarget: windowTarget,
3255
3314
  projectRoot,
3256
3315
  branch: wt.branch,
3257
- sessionId: newSessionId,
3258
- skipResultInstructions: !options.prompt
3316
+ sessionId: newSessionId
3259
3317
  });
3260
3318
  await updateManifest(projectRoot, (m) => {
3261
3319
  const mWt = m.worktrees[wt.id];
3262
3320
  if (mWt) {
3263
3321
  const mOldAgent = mWt.agents[oldAgent.id];
3264
- if (mOldAgent && !["completed", "failed", "killed", "lost"].includes(mOldAgent.status)) {
3265
- mOldAgent.status = "killed";
3266
- mOldAgent.completedAt = (/* @__PURE__ */ new Date()).toISOString();
3322
+ if (mOldAgent && mOldAgent.status === "running") {
3323
+ mOldAgent.status = "gone";
3267
3324
  }
3268
3325
  mWt.agents[newAgentId] = agentEntry;
3269
3326
  }
@@ -3366,7 +3423,6 @@ __export(pr_exports, {
3366
3423
  prCommand: () => prCommand,
3367
3424
  truncateBody: () => truncateBody
3368
3425
  });
3369
- import fs15 from "fs/promises";
3370
3426
  import { execa as execa8 } from "execa";
3371
3427
  async function prCommand(worktreeRef, options) {
3372
3428
  const projectRoot = await getRepoRoot();
@@ -3441,16 +3497,11 @@ async function prCommand(worktreeRef, options) {
3441
3497
  }
3442
3498
  }
3443
3499
  async function buildBodyFromResults(agents) {
3444
- const reads = agents.map(async (agent) => {
3445
- try {
3446
- return await fs15.readFile(agent.resultFile, "utf-8");
3447
- } catch {
3448
- return null;
3449
- }
3450
- });
3451
- const contents = (await Promise.all(reads)).filter((c) => c !== null);
3452
- if (contents.length === 0) return "";
3453
- return truncateBody(contents.join("\n\n---\n\n"));
3500
+ if (agents.length === 0) return "";
3501
+ const sections = agents.map((a) => `## Agent: ${a.id}
3502
+
3503
+ ${a.prompt}`);
3504
+ return truncateBody(sections.join("\n\n---\n\n"));
3454
3505
  }
3455
3506
  function truncateBody(body) {
3456
3507
  if (body.length <= MAX_BODY_LENGTH) return body;
@@ -3480,7 +3531,7 @@ function findAtRiskWorktrees(worktrees) {
3480
3531
  return worktrees.filter((wt) => {
3481
3532
  if (wt.status === "merged" || wt.status === "cleaned") return false;
3482
3533
  if (wt.prUrl) return false;
3483
- return Object.values(wt.agents).some((a) => a.status === "completed");
3534
+ return Object.values(wt.agents).some((a) => a.status === "idle" || a.status === "exited");
3484
3535
  });
3485
3536
  }
3486
3537
  async function resetCommand(options) {
@@ -3517,7 +3568,7 @@ async function resetCommand(options) {
3517
3568
  const allAgents = [];
3518
3569
  for (const wt of worktrees) {
3519
3570
  for (const agent of Object.values(wt.agents)) {
3520
- if (["running", "spawning", "waiting"].includes(agent.status)) {
3571
+ if (agent.status === "running") {
3521
3572
  allAgents.push(agent);
3522
3573
  }
3523
3574
  }
@@ -3539,12 +3590,10 @@ async function resetCommand(options) {
3539
3590
  }
3540
3591
  if (killedIds.length > 0) {
3541
3592
  await updateManifest(projectRoot, (m) => {
3542
- const now = (/* @__PURE__ */ new Date()).toISOString();
3543
3593
  for (const wt of Object.values(m.worktrees)) {
3544
3594
  for (const agent of Object.values(wt.agents)) {
3545
3595
  if (killedIds.includes(agent.id)) {
3546
- agent.status = "killed";
3547
- agent.completedAt = now;
3596
+ agent.status = "gone";
3548
3597
  }
3549
3598
  }
3550
3599
  }
@@ -3847,9 +3896,9 @@ async function waitCommand(worktreeRef, options) {
3847
3896
  }
3848
3897
  const manifest = await refreshAndGet(projectRoot);
3849
3898
  const agents = collectAgents(manifest, worktreeRef, options.all);
3850
- const allTerminal = agents.every((a) => TERMINAL_STATUSES.includes(a.status));
3851
- if (allTerminal) {
3852
- const anyFailed = agents.some((a) => ["failed", "lost"].includes(a.status));
3899
+ const allDone = agents.every((a) => a.status !== "running");
3900
+ if (allDone) {
3901
+ const anyFailed = agents.some((a) => a.status === "exited" && a.exitCode !== void 0 && a.exitCode !== 0);
3853
3902
  if (options.json) {
3854
3903
  output({
3855
3904
  timedOut: false,
@@ -3892,11 +3941,9 @@ function formatAgent(a) {
3892
3941
  status: a.status,
3893
3942
  agentType: a.agentType,
3894
3943
  exitCode: a.exitCode,
3895
- startedAt: a.startedAt,
3896
- completedAt: a.completedAt
3944
+ startedAt: a.startedAt
3897
3945
  };
3898
3946
  }
3899
- var TERMINAL_STATUSES;
3900
3947
  var init_wait = __esm({
3901
3948
  "src/commands/wait.ts"() {
3902
3949
  "use strict";
@@ -3905,7 +3952,6 @@ var init_wait = __esm({
3905
3952
  init_worktree();
3906
3953
  init_errors();
3907
3954
  init_output();
3908
- TERMINAL_STATUSES = ["completed", "failed", "killed", "lost"];
3909
3955
  }
3910
3956
  });
3911
3957
 
@@ -3915,18 +3961,34 @@ __export(worktree_exports, {
3915
3961
  worktreeCreateCommand: () => worktreeCreateCommand
3916
3962
  });
3917
3963
  async function worktreeCreateCommand(options) {
3964
+ if (options.branch && options.base) {
3965
+ throw new PpgError("--branch and --base are mutually exclusive (--base is for new branches)", "INVALID_ARGS");
3966
+ }
3918
3967
  const projectRoot = await getRepoRoot();
3919
3968
  const config = await loadConfig(projectRoot);
3920
3969
  await requireManifest(projectRoot);
3921
- const baseBranch = options.base ?? await getCurrentBranch(projectRoot);
3922
3970
  const wtId = worktreeId();
3923
- const name = options.name ? normalizeName(options.name, wtId) : wtId;
3924
- const branchName = `ppg/${name}`;
3925
- info(`Creating worktree ${wtId} on branch ${branchName}`);
3926
- const wtPath = await createWorktree(projectRoot, wtId, {
3927
- branch: branchName,
3928
- base: baseBranch
3929
- });
3971
+ let name;
3972
+ let branchName;
3973
+ let baseBranch;
3974
+ let wtPath;
3975
+ if (options.branch) {
3976
+ branchName = options.branch;
3977
+ const derivedName = branchName.startsWith("ppg/") ? branchName.slice(4) : branchName;
3978
+ name = options.name ? normalizeName(options.name, wtId) : normalizeName(derivedName, wtId);
3979
+ baseBranch = await getCurrentBranch(projectRoot);
3980
+ info(`Creating worktree ${wtId} from existing branch ${branchName}`);
3981
+ wtPath = await adoptWorktree(projectRoot, wtId, branchName);
3982
+ } else {
3983
+ baseBranch = options.base ?? await getCurrentBranch(projectRoot);
3984
+ name = options.name ? normalizeName(options.name, wtId) : wtId;
3985
+ branchName = `ppg/${name}`;
3986
+ info(`Creating worktree ${wtId} on branch ${branchName}`);
3987
+ wtPath = await createWorktree(projectRoot, wtId, {
3988
+ branch: branchName,
3989
+ base: baseBranch
3990
+ });
3991
+ }
3930
3992
  await setupWorktreeEnv(projectRoot, wtPath, config);
3931
3993
  const worktreeEntry = {
3932
3994
  id: wtId,
@@ -3968,6 +4030,7 @@ var init_worktree2 = __esm({
3968
4030
  init_worktree();
3969
4031
  init_env2();
3970
4032
  init_id();
4033
+ init_errors();
3971
4034
  init_output();
3972
4035
  init_name();
3973
4036
  }
@@ -4162,14 +4225,14 @@ var init_install_dashboard = __esm({
4162
4225
  });
4163
4226
 
4164
4227
  // src/core/schedule.ts
4165
- import fs16 from "fs/promises";
4228
+ import fs15 from "fs/promises";
4166
4229
  import YAML3 from "yaml";
4167
4230
  import { CronExpressionParser } from "cron-parser";
4168
4231
  async function loadSchedules(projectRoot) {
4169
4232
  const filePath = schedulesPath(projectRoot);
4170
4233
  let raw;
4171
4234
  try {
4172
- raw = await fs16.readFile(filePath, "utf-8");
4235
+ raw = await fs15.readFile(filePath, "utf-8");
4173
4236
  } catch (err) {
4174
4237
  if (err.code === "ENOENT") {
4175
4238
  throw new PpgError("No schedules file found. Create .ppg/schedules.yaml first.", "INVALID_ARGS");
@@ -4254,16 +4317,16 @@ var init_schedule = __esm({
4254
4317
  });
4255
4318
 
4256
4319
  // src/core/cron.ts
4257
- import fs17 from "fs/promises";
4320
+ import fs16 from "fs/promises";
4258
4321
  import { createReadStream } from "fs";
4259
4322
  import path11 from "path";
4260
4323
  import readline from "readline";
4261
4324
  import { execa as execa11 } from "execa";
4262
4325
  async function runCronDaemon(projectRoot) {
4263
4326
  const pidPath = cronPidPath(projectRoot);
4264
- await fs17.mkdir(path11.dirname(pidPath), { recursive: true });
4265
- await fs17.writeFile(pidPath, String(process.pid), "utf-8");
4266
- await fs17.mkdir(logsDir(projectRoot), { recursive: true });
4327
+ await fs16.mkdir(path11.dirname(pidPath), { recursive: true });
4328
+ await fs16.writeFile(pidPath, String(process.pid), "utf-8");
4329
+ await fs16.mkdir(logsDir(projectRoot), { recursive: true });
4267
4330
  await logCron(projectRoot, "Cron daemon starting");
4268
4331
  let states = await loadScheduleStates(projectRoot);
4269
4332
  let lastConfigMtime = await getFileMtime(schedulesPath(projectRoot));
@@ -4274,7 +4337,7 @@ async function runCronDaemon(projectRoot) {
4274
4337
  const cleanup = async () => {
4275
4338
  await logCron(projectRoot, "Cron daemon stopping");
4276
4339
  try {
4277
- await fs17.unlink(pidPath);
4340
+ await fs16.unlink(pidPath);
4278
4341
  } catch {
4279
4342
  }
4280
4343
  process.exit(0);
@@ -4318,7 +4381,7 @@ async function loadScheduleStates(projectRoot) {
4318
4381
  }
4319
4382
  async function getFileMtime(filePath) {
4320
4383
  try {
4321
- const stat = await fs17.stat(filePath);
4384
+ const stat = await fs16.stat(filePath);
4322
4385
  return stat.mtimeMs;
4323
4386
  } catch {
4324
4387
  return 0;
@@ -4373,10 +4436,10 @@ async function logCron(projectRoot, message) {
4373
4436
  `;
4374
4437
  process.stdout.write(line);
4375
4438
  try {
4376
- await fs17.appendFile(logPath, line, "utf-8");
4439
+ await fs16.appendFile(logPath, line, "utf-8");
4377
4440
  } catch {
4378
- await fs17.mkdir(logsDir(projectRoot), { recursive: true });
4379
- await fs17.appendFile(logPath, line, "utf-8");
4441
+ await fs16.mkdir(logsDir(projectRoot), { recursive: true });
4442
+ await fs16.appendFile(logPath, line, "utf-8");
4380
4443
  }
4381
4444
  }
4382
4445
  async function isCronRunning(projectRoot) {
@@ -4386,7 +4449,7 @@ async function getCronPid(projectRoot) {
4386
4449
  const pidPath = cronPidPath(projectRoot);
4387
4450
  let raw;
4388
4451
  try {
4389
- raw = await fs17.readFile(pidPath, "utf-8");
4452
+ raw = await fs16.readFile(pidPath, "utf-8");
4390
4453
  } catch {
4391
4454
  return null;
4392
4455
  }
@@ -4405,14 +4468,14 @@ async function getCronPid(projectRoot) {
4405
4468
  }
4406
4469
  async function cleanupPidFile(pidPath) {
4407
4470
  try {
4408
- await fs17.unlink(pidPath);
4471
+ await fs16.unlink(pidPath);
4409
4472
  } catch {
4410
4473
  }
4411
4474
  }
4412
4475
  async function readCronLog(projectRoot, lines = 20) {
4413
4476
  const logPath = cronLogPath(projectRoot);
4414
4477
  try {
4415
- await fs17.access(logPath);
4478
+ await fs16.access(logPath);
4416
4479
  } catch {
4417
4480
  return [];
4418
4481
  }
@@ -4449,7 +4512,7 @@ __export(cron_exports, {
4449
4512
  cronStatusCommand: () => cronStatusCommand,
4450
4513
  cronStopCommand: () => cronStopCommand
4451
4514
  });
4452
- import fs18 from "fs/promises";
4515
+ import fs17 from "fs/promises";
4453
4516
  async function cronStartCommand(options) {
4454
4517
  const projectRoot = await getRepoRoot();
4455
4518
  await requireInit(projectRoot);
@@ -4500,7 +4563,7 @@ async function cronStopCommand(options) {
4500
4563
  } catch {
4501
4564
  }
4502
4565
  try {
4503
- await fs18.unlink(cronPidPath(projectRoot));
4566
+ await fs17.unlink(cronPidPath(projectRoot));
4504
4567
  } catch {
4505
4568
  }
4506
4569
  try {
@@ -4586,7 +4649,7 @@ async function cronDaemonCommand() {
4586
4649
  }
4587
4650
  async function requireInit(projectRoot) {
4588
4651
  try {
4589
- await fs18.access(manifestPath(projectRoot));
4652
+ await fs17.access(manifestPath(projectRoot));
4590
4653
  } catch {
4591
4654
  throw new NotInitializedError(projectRoot);
4592
4655
  }
@@ -4620,7 +4683,7 @@ program.command("init").description("Initialize Point Guard in the current git r
4620
4683
  const { initCommand: initCommand2 } = await Promise.resolve().then(() => (init_init(), init_exports));
4621
4684
  await initCommand2(options);
4622
4685
  });
4623
- program.command("spawn").description("Spawn a new worktree and agent(s), or add agents to an existing worktree").option("-n, --name <name>", "Name for the worktree/task").option("-a, --agent <type>", "Agent type to use (default: claude)").option("-p, --prompt <text>", "Prompt text for the agent").option("-f, --prompt-file <path>", "File containing the prompt").option("-t, --template <name>", "Template name from .ppg/templates/").option("--var <key=value...>", "Template variables", collectVars, []).option("-b, --base <branch>", "Base branch for the worktree").option("-w, --worktree <id>", "Add agent to existing worktree").option("-c, --count <n>", "Number of agents to spawn", parsePositiveInt("count"), 1).option("--split", "Put all agents in one window as split panes").option("--open", "Open a Terminal window for the spawned agents").option("--json", "Output as JSON").action(async (options) => {
4686
+ program.command("spawn").description("Spawn a new worktree and agent(s), or add agents to an existing worktree").option("-n, --name <name>", "Name for the worktree/task").option("-a, --agent <type>", "Agent type to use (default: claude)").option("-p, --prompt <text>", "Prompt text for the agent").option("-f, --prompt-file <path>", "File containing the prompt").option("-t, --template <name>", "Template name from .ppg/templates/").option("--var <key=value...>", "Template variables", collectVars, []).option("-b, --base <branch>", "Base branch for the worktree").option("--branch <name>", "Check out an existing branch into a new worktree").option("-w, --worktree <id>", "Add agent to existing worktree").option("-c, --count <n>", "Number of agents to spawn", parsePositiveInt("count"), 1).option("--split", "Put all agents in one window as split panes").option("--open", "Open a Terminal window for the spawned agents").option("--json", "Output as JSON").action(async (options) => {
4624
4687
  const { spawnCommand: spawnCommand2 } = await Promise.resolve().then(() => (init_spawn(), spawn_exports));
4625
4688
  await spawnCommand2(options);
4626
4689
  });
@@ -4640,11 +4703,11 @@ program.command("logs").description("View agent pane output").argument("<agent-i
4640
4703
  const { logsCommand: logsCommand2 } = await Promise.resolve().then(() => (init_logs(), logs_exports));
4641
4704
  await logsCommand2(agentId2, options);
4642
4705
  });
4643
- program.command("aggregate").description("Aggregate results from completed agents").argument("[worktree-id]", "Worktree ID to aggregate results from").option("--all", "Aggregate from all worktrees").option("-o, --output <file>", "Write output to file").option("--json", "Output as JSON").action(async (worktreeId2, options) => {
4706
+ program.command("aggregate").description("Aggregate results from agents (captures pane output)").argument("[worktree-id]", "Worktree ID to aggregate results from").option("--all", "Aggregate from all worktrees").option("-o, --output <file>", "Write output to file").option("--json", "Output as JSON").action(async (worktreeId2, options) => {
4644
4707
  const { aggregateCommand: aggregateCommand2 } = await Promise.resolve().then(() => (init_aggregate(), aggregate_exports));
4645
4708
  await aggregateCommand2(worktreeId2, options);
4646
4709
  });
4647
- program.command("merge").description("Merge a worktree branch back into base").argument("<worktree-id>", "Worktree ID to merge").option("-s, --strategy <strategy>", "Merge strategy: squash or no-ff", "squash").option("--no-cleanup", "Do not remove worktree after merge").option("--dry-run", "Show what would be done without doing it").option("--force", "Merge even if agents are not completed").option("--json", "Output as JSON").action(async (worktreeId2, options) => {
4710
+ program.command("merge").description("Merge a worktree branch back into base").argument("<worktree-id>", "Worktree ID to merge").option("-s, --strategy <strategy>", "Merge strategy: squash or no-ff", "squash").option("--no-cleanup", "Do not remove worktree after merge").option("--dry-run", "Show what would be done without doing it").option("--force", "Merge even if agents are still running").option("--json", "Output as JSON").action(async (worktreeId2, options) => {
4648
4711
  const { mergeCommand: mergeCommand2 } = await Promise.resolve().then(() => (init_merge(), merge_exports));
4649
4712
  await mergeCommand2(worktreeId2, options);
4650
4713
  });
@@ -4660,7 +4723,7 @@ program.command("list").description("List available templates, swarms, or prompt
4660
4723
  const { listCommand: listCommand2 } = await Promise.resolve().then(() => (init_list(), list_exports));
4661
4724
  await listCommand2(type, options);
4662
4725
  });
4663
- program.command("restart").description("Restart a failed/killed agent in the same worktree").argument("<agent-id>", "Agent ID to restart").option("-p, --prompt <text>", "Override the original prompt").option("-a, --agent <type>", "Override the agent type").option("--open", "Open a Terminal window for the restarted agent").option("--json", "Output as JSON").action(async (agentId2, options) => {
4726
+ program.command("restart").description("Restart an agent in the same worktree").argument("<agent-id>", "Agent ID to restart").option("-p, --prompt <text>", "Override the original prompt").option("-a, --agent <type>", "Override the agent type").option("--open", "Open a Terminal window for the restarted agent").option("--json", "Output as JSON").action(async (agentId2, options) => {
4664
4727
  const { restartCommand: restartCommand2 } = await Promise.resolve().then(() => (init_restart(), restart_exports));
4665
4728
  await restartCommand2(agentId2, options);
4666
4729
  });
@@ -4689,7 +4752,7 @@ program.command("wait").description("Wait for agents to reach terminal state").a
4689
4752
  await waitCommand2(worktreeId2, options);
4690
4753
  });
4691
4754
  var worktreeCmd = program.command("worktree").description("Manage worktrees");
4692
- worktreeCmd.command("create").description("Create a standalone worktree without spawning agents").option("-n, --name <name>", "Name for the worktree").option("-b, --base <branch>", "Base branch for the worktree").option("--json", "Output as JSON").action(async (options) => {
4755
+ worktreeCmd.command("create").description("Create a standalone worktree without spawning agents").option("-n, --name <name>", "Name for the worktree").option("-b, --base <branch>", "Base branch for the worktree").option("--branch <name>", "Check out an existing branch into a new worktree").option("--json", "Output as JSON").action(async (options) => {
4693
4756
  const { worktreeCreateCommand: worktreeCreateCommand2 } = await Promise.resolve().then(() => (init_worktree2(), worktree_exports));
4694
4757
  await worktreeCreateCommand2(options);
4695
4758
  });