@iloom/cli 0.4.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/README.md +24 -0
  2. package/dist/{ClaudeContextManager-DK77227F.js → ClaudeContextManager-DQFKIMEP.js} +5 -5
  3. package/dist/{ClaudeService-W3SA7HVG.js → ClaudeService-CJS32WG2.js} +4 -4
  4. package/dist/{LoomLauncher-S3YGJRJQ.js → LoomLauncher-4UG2E4CD.js} +19 -24
  5. package/dist/LoomLauncher-4UG2E4CD.js.map +1 -0
  6. package/dist/MetadataManager-WXUVXKUS.js +10 -0
  7. package/dist/PRManager-7DSIMCAD.js +16 -0
  8. package/dist/{PromptTemplateManager-2TDZAUC6.js → PromptTemplateManager-72FEOGT6.js} +2 -2
  9. package/dist/README.md +24 -0
  10. package/dist/{SettingsManager-FJFU6JJD.js → SettingsManager-XPR4TEQL.js} +2 -2
  11. package/dist/agents/iloom-issue-analyze-and-plan.md +41 -7
  12. package/dist/agents/iloom-issue-analyzer.md +38 -8
  13. package/dist/agents/iloom-issue-complexity-evaluator.md +45 -15
  14. package/dist/agents/iloom-issue-enhancer.md +60 -18
  15. package/dist/agents/iloom-issue-implementer.md +29 -7
  16. package/dist/agents/iloom-issue-planner.md +36 -7
  17. package/dist/agents/iloom-issue-reviewer.md +30 -7
  18. package/dist/{chunk-JC5HXN75.js → chunk-3CMGCRB5.js} +2 -2
  19. package/dist/{chunk-G6CIIJLT.js → chunk-4YTILIIH.js} +7 -8
  20. package/dist/chunk-4YTILIIH.js.map +1 -0
  21. package/dist/{chunk-55TB3FSG.js → chunk-AS2IRKLU.js} +2 -2
  22. package/dist/{chunk-POI7KLBH.js → chunk-CDQEK2WD.js} +5 -5
  23. package/dist/{chunk-74VMN2KC.js → chunk-DKQ4SUII.js} +16 -1
  24. package/dist/chunk-DKQ4SUII.js.map +1 -0
  25. package/dist/{chunk-BIIQHEXJ.js → chunk-GVRO4PWE.js} +12 -8
  26. package/dist/chunk-GVRO4PWE.js.map +1 -0
  27. package/dist/{chunk-TMZAVPGF.js → chunk-HABINPX2.js} +71 -15
  28. package/dist/{chunk-TMZAVPGF.js.map → chunk-HABINPX2.js.map} +1 -1
  29. package/dist/{chunk-2W2FBL5G.js → chunk-LN4H3A6A.js} +66 -7
  30. package/dist/chunk-LN4H3A6A.js.map +1 -0
  31. package/dist/{chunk-VWNS6DH5.js → chunk-OOU3DKNT.js} +13 -7
  32. package/dist/chunk-OOU3DKNT.js.map +1 -0
  33. package/dist/chunk-P2ZQ5LKB.js +347 -0
  34. package/dist/chunk-P2ZQ5LKB.js.map +1 -0
  35. package/dist/{chunk-HD5SUKI2.js → chunk-RFUOIUQF.js} +49 -6
  36. package/dist/{chunk-HD5SUKI2.js.map → chunk-RFUOIUQF.js.map} +1 -1
  37. package/dist/{chunk-OF7BNW4D.js → chunk-RJKMF6BC.js} +30 -4
  38. package/dist/chunk-RJKMF6BC.js.map +1 -0
  39. package/dist/{chunk-O7WHXLCB.js → chunk-RNZMHJK7.js} +18 -4
  40. package/dist/chunk-RNZMHJK7.js.map +1 -0
  41. package/dist/{chunk-UPUAQYAW.js → chunk-S65T4O6I.js} +2 -2
  42. package/dist/{chunk-IARWMDAX.js → chunk-T5IIUG4Z.js} +98 -16
  43. package/dist/chunk-T5IIUG4Z.js.map +1 -0
  44. package/dist/{chunk-IJ7IGJT3.js → chunk-YZTDGPFB.js} +18 -1
  45. package/dist/chunk-YZTDGPFB.js.map +1 -0
  46. package/dist/{cleanup-KDLVTT7M.js → cleanup-MIDJVSIU.js} +14 -14
  47. package/dist/cli.js +228 -354
  48. package/dist/cli.js.map +1 -1
  49. package/dist/{contribute-HY372S6F.js → contribute-RS3DO3WP.js} +4 -4
  50. package/dist/{dev-server-JCJGQ3PV.js → dev-server-ASH7HJVI.js} +30 -16
  51. package/dist/dev-server-ASH7HJVI.js.map +1 -0
  52. package/dist/{feedback-7PVBQNLJ.js → feedback-RVIGHBJG.js} +5 -4
  53. package/dist/{feedback-7PVBQNLJ.js.map → feedback-RVIGHBJG.js.map} +1 -1
  54. package/dist/{git-4BVOOOOV.js → git-OQAPUPLP.js} +16 -6
  55. package/dist/git-OQAPUPLP.js.map +1 -0
  56. package/dist/{ignite-3B264M7K.js → ignite-XJALWFAT.js} +57 -22
  57. package/dist/ignite-XJALWFAT.js.map +1 -0
  58. package/dist/index.d.ts +58 -7
  59. package/dist/index.js +104 -7
  60. package/dist/index.js.map +1 -1
  61. package/dist/{init-LBA6NUK2.js → init-F6PFMSU5.js} +7 -7
  62. package/dist/init-F6PFMSU5.js.map +1 -0
  63. package/dist/mcp/recap-server.js +264 -0
  64. package/dist/mcp/recap-server.js.map +1 -0
  65. package/dist/{open-OGCV32Z4.js → open-KW4NTLXH.js} +16 -17
  66. package/dist/{open-OGCV32Z4.js.map → open-KW4NTLXH.js.map} +1 -1
  67. package/dist/{projects-P55273AB.js → projects-QEAEBAT2.js} +2 -2
  68. package/dist/prompts/init-prompt.txt +31 -72
  69. package/dist/prompts/issue-prompt.txt +115 -15
  70. package/dist/prompts/pr-prompt.txt +49 -1
  71. package/dist/prompts/regular-prompt.txt +80 -20
  72. package/dist/{rebase-4T5FQHNH.js → rebase-WZHHE5LU.js} +6 -6
  73. package/dist/recap-33NPZ3ZO.js +117 -0
  74. package/dist/recap-33NPZ3ZO.js.map +1 -0
  75. package/dist/{run-HNOP6WE2.js → run-HRYQ7TR7.js} +16 -17
  76. package/dist/{run-HNOP6WE2.js.map → run-HRYQ7TR7.js.map} +1 -1
  77. package/dist/schema/settings.schema.json +13 -2
  78. package/dist/{shell-DE3HKJSM.js → shell-JMU5XTHW.js} +6 -6
  79. package/dist/{summary-GDT7DTRI.js → summary-4SSGGH7N.js} +17 -9
  80. package/dist/summary-4SSGGH7N.js.map +1 -0
  81. package/dist/{test-git-YMAE57UP.js → test-git-6SAIRBUD.js} +4 -4
  82. package/dist/{test-prefix-YCKL6CMT.js → test-prefix-RLVRK5ZD.js} +4 -4
  83. package/package.json +1 -1
  84. package/dist/LoomLauncher-S3YGJRJQ.js.map +0 -1
  85. package/dist/chunk-2W2FBL5G.js.map +0 -1
  86. package/dist/chunk-74VMN2KC.js.map +0 -1
  87. package/dist/chunk-BIIQHEXJ.js.map +0 -1
  88. package/dist/chunk-G6CIIJLT.js.map +0 -1
  89. package/dist/chunk-IARWMDAX.js.map +0 -1
  90. package/dist/chunk-IJ7IGJT3.js.map +0 -1
  91. package/dist/chunk-O7WHXLCB.js.map +0 -1
  92. package/dist/chunk-OF7BNW4D.js.map +0 -1
  93. package/dist/chunk-QRBOPFAA.js +0 -48
  94. package/dist/chunk-QRBOPFAA.js.map +0 -1
  95. package/dist/chunk-VWNS6DH5.js.map +0 -1
  96. package/dist/dev-server-JCJGQ3PV.js.map +0 -1
  97. package/dist/ignite-3B264M7K.js.map +0 -1
  98. package/dist/summary-GDT7DTRI.js.map +0 -1
  99. /package/dist/{ClaudeContextManager-DK77227F.js.map → ClaudeContextManager-DQFKIMEP.js.map} +0 -0
  100. /package/dist/{ClaudeService-W3SA7HVG.js.map → ClaudeService-CJS32WG2.js.map} +0 -0
  101. /package/dist/{PromptTemplateManager-2TDZAUC6.js.map → MetadataManager-WXUVXKUS.js.map} +0 -0
  102. /package/dist/{SettingsManager-FJFU6JJD.js.map → PRManager-7DSIMCAD.js.map} +0 -0
  103. /package/dist/{git-4BVOOOOV.js.map → PromptTemplateManager-72FEOGT6.js.map} +0 -0
  104. /package/dist/{init-LBA6NUK2.js.map → SettingsManager-XPR4TEQL.js.map} +0 -0
  105. /package/dist/{chunk-JC5HXN75.js.map → chunk-3CMGCRB5.js.map} +0 -0
  106. /package/dist/{chunk-55TB3FSG.js.map → chunk-AS2IRKLU.js.map} +0 -0
  107. /package/dist/{chunk-POI7KLBH.js.map → chunk-CDQEK2WD.js.map} +0 -0
  108. /package/dist/{chunk-UPUAQYAW.js.map → chunk-S65T4O6I.js.map} +0 -0
  109. /package/dist/{cleanup-KDLVTT7M.js.map → cleanup-MIDJVSIU.js.map} +0 -0
  110. /package/dist/{contribute-HY372S6F.js.map → contribute-RS3DO3WP.js.map} +0 -0
  111. /package/dist/{projects-P55273AB.js.map → projects-QEAEBAT2.js.map} +0 -0
  112. /package/dist/{rebase-4T5FQHNH.js.map → rebase-WZHHE5LU.js.map} +0 -0
  113. /package/dist/{shell-DE3HKJSM.js.map → shell-JMU5XTHW.js.map} +0 -0
  114. /package/dist/{test-git-YMAE57UP.js.map → test-git-6SAIRBUD.js.map} +0 -0
  115. /package/dist/{test-prefix-YCKL6CMT.js.map → test-prefix-RLVRK5ZD.js.map} +0 -0
package/dist/cli.js CHANGED
@@ -1,98 +1,102 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  SessionSummaryService
4
- } from "./chunk-TMZAVPGF.js";
4
+ } from "./chunk-HABINPX2.js";
5
+ import {
6
+ FirstRunManager,
7
+ IssueTrackerFactory,
8
+ generateIssueManagementMcpConfig
9
+ } from "./chunk-RFUOIUQF.js";
10
+ import "./chunk-QHA67Q7A.js";
5
11
  import {
6
12
  CLIIsolationManager,
7
13
  DatabaseManager,
8
14
  EnvironmentManager,
9
15
  LoomManager,
10
16
  ResourceCleanup
11
- } from "./chunk-IARWMDAX.js";
17
+ } from "./chunk-T5IIUG4Z.js";
18
+ import {
19
+ detectPackageManager,
20
+ installDependencies,
21
+ runScript
22
+ } from "./chunk-VBFDVGAE.js";
23
+ import {
24
+ ProcessManager
25
+ } from "./chunk-VU3QMIP2.js";
26
+ import {
27
+ IdentifierParser
28
+ } from "./chunk-AS2IRKLU.js";
29
+ import {
30
+ createNeonProviderFromSettings
31
+ } from "./chunk-UNXRACJ7.js";
12
32
  import {
13
33
  InitCommand,
14
34
  ShellCompletion
15
- } from "./chunk-G6CIIJLT.js";
35
+ } from "./chunk-4YTILIIH.js";
16
36
  import "./chunk-UYWAESOT.js";
17
37
  import {
18
38
  IssueEnhancementService,
19
39
  capitalizeFirstLetter
20
40
  } from "./chunk-VTXCGKV5.js";
21
41
  import {
22
- MergeManager
23
- } from "./chunk-BIIQHEXJ.js";
42
+ AgentManager
43
+ } from "./chunk-RNZMHJK7.js";
24
44
  import {
25
- FirstRunManager,
26
- IssueTrackerFactory,
27
- generateIssueManagementMcpConfig
28
- } from "./chunk-HD5SUKI2.js";
29
- import "./chunk-QHA67Q7A.js";
45
+ ProjectCapabilityDetector
46
+ } from "./chunk-EBISESAP.js";
30
47
  import {
31
- AgentManager
32
- } from "./chunk-O7WHXLCB.js";
48
+ hasScript,
49
+ readPackageJson
50
+ } from "./chunk-2ZPFJQ3B.js";
33
51
  import {
34
- IdentifierParser
35
- } from "./chunk-55TB3FSG.js";
52
+ MergeManager
53
+ } from "./chunk-GVRO4PWE.js";
36
54
  import {
37
- ProcessManager
38
- } from "./chunk-VU3QMIP2.js";
55
+ GitWorktreeManager
56
+ } from "./chunk-3CMGCRB5.js";
57
+ import {
58
+ PRManager
59
+ } from "./chunk-P2ZQ5LKB.js";
39
60
  import {
40
61
  openBrowser
41
62
  } from "./chunk-YETJNRQM.js";
42
63
  import {
43
- GitWorktreeManager
44
- } from "./chunk-JC5HXN75.js";
45
- import {
46
- detectPackageManager,
47
- installDependencies,
48
- runScript
49
- } from "./chunk-VBFDVGAE.js";
64
+ getConfiguredRepoFromSettings,
65
+ hasMultipleRemotes
66
+ } from "./chunk-PSFVTBM7.js";
50
67
  import {
51
68
  ClaudeContextManager
52
- } from "./chunk-UPUAQYAW.js";
53
- import "./chunk-POI7KLBH.js";
69
+ } from "./chunk-S65T4O6I.js";
70
+ import "./chunk-CDQEK2WD.js";
71
+ import "./chunk-DKQ4SUII.js";
54
72
  import {
55
73
  extractSettingsOverrides
56
74
  } from "./chunk-GYCR2LOU.js";
57
75
  import {
58
76
  DefaultBranchNamingService
59
77
  } from "./chunk-QIUJPPJQ.js";
60
- import {
61
- ProjectCapabilityDetector
62
- } from "./chunk-EBISESAP.js";
63
- import {
64
- hasScript,
65
- readPackageJson
66
- } from "./chunk-2ZPFJQ3B.js";
67
- import {
68
- createNeonProviderFromSettings
69
- } from "./chunk-UNXRACJ7.js";
70
- import {
71
- getConfiguredRepoFromSettings,
72
- getEffectivePRTargetRemote,
73
- hasMultipleRemotes,
74
- parseGitRemotes
75
- } from "./chunk-PSFVTBM7.js";
76
78
  import {
77
79
  executeGitCommand,
78
80
  extractIssueNumber,
79
81
  findMainWorktreePathWithSettings,
82
+ findPlaceholderCommitSha,
80
83
  getMergeTargetBranch,
81
84
  getRepoRoot,
82
- pushBranchToRemote
83
- } from "./chunk-2W2FBL5G.js";
84
- import {
85
- MetadataManager
86
- } from "./chunk-IJ7IGJT3.js";
85
+ isPlaceholderCommit,
86
+ pushBranchToRemote,
87
+ removePlaceholderCommitFromHead,
88
+ removePlaceholderCommitFromHistory
89
+ } from "./chunk-LN4H3A6A.js";
87
90
  import {
88
91
  SettingsManager
89
- } from "./chunk-VWNS6DH5.js";
92
+ } from "./chunk-OOU3DKNT.js";
93
+ import {
94
+ MetadataManager
95
+ } from "./chunk-YZTDGPFB.js";
90
96
  import {
91
97
  GitHubService
92
98
  } from "./chunk-OEGECBFS.js";
93
- import {
94
- executeGhCommand
95
- } from "./chunk-KO2FOMHL.js";
99
+ import "./chunk-KO2FOMHL.js";
96
100
  import {
97
101
  promptCommitAction,
98
102
  promptConfirmation,
@@ -111,7 +115,6 @@ import {
111
115
  getLogger,
112
116
  withLogger
113
117
  } from "./chunk-6UIGZD2N.js";
114
- import "./chunk-74VMN2KC.js";
115
118
  import {
116
119
  createStderrLogger,
117
120
  logger
@@ -1664,267 +1667,6 @@ Run '${runCommand}' to see detailed errors.`
1664
1667
  }
1665
1668
  };
1666
1669
 
1667
- // src/lib/PRManager.ts
1668
- var PRManager = class {
1669
- constructor(settings) {
1670
- this.settings = settings;
1671
- }
1672
- /**
1673
- * Check if a PR already exists for the given branch
1674
- * @param branchName - Branch to check
1675
- * @param cwd - Working directory
1676
- * @returns Existing PR info or null if none found
1677
- */
1678
- async checkForExistingPR(branchName, cwd) {
1679
- try {
1680
- const prList = await executeGhCommand(
1681
- ["pr", "list", "--head", branchName, "--state", "open", "--json", "number,url"],
1682
- cwd ? { cwd } : void 0
1683
- );
1684
- if (prList.length > 0) {
1685
- return prList[0] ?? null;
1686
- }
1687
- return null;
1688
- } catch (error) {
1689
- getLogger().debug("Error checking for existing PR", { error });
1690
- return null;
1691
- }
1692
- }
1693
- /**
1694
- * Generate PR body using Claude if available, otherwise use simple template
1695
- * @param issueNumber - Issue number to include in body
1696
- * @param worktreePath - Path to worktree for context
1697
- * @returns PR body markdown
1698
- */
1699
- async generatePRBody(issueNumber, worktreePath) {
1700
- const hasClaudeCli = await detectClaudeCli();
1701
- if (hasClaudeCli) {
1702
- try {
1703
- const prompt = this.buildPRBodyPrompt(issueNumber);
1704
- const body2 = await launchClaude(prompt, {
1705
- headless: true,
1706
- addDir: worktreePath,
1707
- timeout: 3e4
1708
- });
1709
- if (body2 && typeof body2 === "string" && body2.trim()) {
1710
- const sanitized = this.sanitizeClaudeOutput(body2);
1711
- if (sanitized) {
1712
- return sanitized;
1713
- }
1714
- }
1715
- } catch (error) {
1716
- getLogger().debug("Claude PR body generation failed, using template", { error });
1717
- }
1718
- }
1719
- let body = "This PR contains changes from the iloom workflow.\n\n";
1720
- if (issueNumber) {
1721
- body += `Fixes #${issueNumber}`;
1722
- }
1723
- return body;
1724
- }
1725
- /**
1726
- * Build structured XML prompt for PR body generation
1727
- * Uses XML format for clear task definition and output expectations
1728
- */
1729
- buildPRBodyPrompt(issueNumber) {
1730
- const issueContext = issueNumber ? `
1731
- <IssueContext>
1732
- This PR is associated with GitHub issue #${issueNumber}.
1733
- Include "Fixes #${issueNumber}" at the end of the body on its own line.
1734
- </IssueContext>` : "";
1735
- return `<Task>
1736
- You are a software engineer writing a pull request body for this repository.
1737
- Examine the changes in the git repository and generate a concise, professional PR description.
1738
- </Task>
1739
-
1740
- <Requirements>
1741
- <Format>Write 2-3 sentences summarizing what was changed and why.${issueNumber ? `
1742
-
1743
- End with "Fixes #${issueNumber}" on its own line.` : ""}</Format>
1744
- <Tone>Professional and concise</Tone>
1745
- <Focus>Summarize the changes and their purpose</Focus>
1746
- <NoMeta>CRITICAL: Do NOT include ANY explanatory text, analysis, or meta-commentary. Output ONLY the raw PR body text.</NoMeta>
1747
- <Examples>
1748
- Good: "Add user authentication with JWT tokens to secure the API endpoints. This includes login and registration endpoints with proper password hashing.
1749
-
1750
- Fixes #42"
1751
- Good: "Fix navigation bug in sidebar menu that caused incorrect highlighting on nested routes."
1752
- Bad: "Here's the PR body:
1753
-
1754
- ---
1755
-
1756
- Add user authentication..."
1757
- Bad: "Based on the changes, I'll write: Fix navigation bug..."
1758
- </Examples>
1759
- ${issueContext}
1760
- </Requirements>
1761
-
1762
- <Output>
1763
- IMPORTANT: Your entire response will be used directly as the GitHub pull request body.
1764
- Do not include any explanatory text, headers, or separators before or after the body.
1765
- Start your response immediately with the PR body text.
1766
- </Output>`;
1767
- }
1768
- /**
1769
- * Sanitize Claude output to remove meta-commentary and clean formatting
1770
- * Handles cases where Claude includes explanatory text despite instructions
1771
- */
1772
- sanitizeClaudeOutput(rawOutput) {
1773
- let cleaned = rawOutput.trim();
1774
- const metaPatterns = [
1775
- /^.*?based on.*?changes.*?:/i,
1776
- /^.*?looking at.*?files.*?:/i,
1777
- /^.*?examining.*?:/i,
1778
- /^.*?analyzing.*?:/i,
1779
- /^.*?i'll.*?generate.*?:/i,
1780
- /^.*?let me.*?:/i,
1781
- /^.*?here.*?is.*?(?:the\s+)?(?:pr|pull request).*?body.*?:/i,
1782
- /^.*?here's.*?(?:the\s+)?(?:pr|pull request).*?body.*?:/i
1783
- ];
1784
- for (const pattern of metaPatterns) {
1785
- cleaned = cleaned.replace(pattern, "").trim();
1786
- }
1787
- cleaned = cleaned.replace(/^[-=]{3,}\s*/m, "").trim();
1788
- if (cleaned.includes(":")) {
1789
- const colonIndex = cleaned.indexOf(":");
1790
- const beforeColon = cleaned.substring(0, colonIndex).trim().toLowerCase();
1791
- const metaIndicators = [
1792
- "here is the pr body",
1793
- "here is the pull request body",
1794
- "pr body",
1795
- "pull request body",
1796
- "here is",
1797
- "here's",
1798
- "the body should be",
1799
- "i suggest",
1800
- "my suggestion"
1801
- ];
1802
- const isMetaCommentary = metaIndicators.some((indicator) => beforeColon.includes(indicator));
1803
- if (isMetaCommentary) {
1804
- const afterColon = cleaned.substring(colonIndex + 1).trim();
1805
- const afterSeparator = afterColon.replace(/^[-=]{3,}\s*/m, "").trim();
1806
- if (afterSeparator && afterSeparator.length > 10) {
1807
- cleaned = afterSeparator;
1808
- }
1809
- }
1810
- }
1811
- if (cleaned.startsWith('"') && cleaned.endsWith('"') || cleaned.startsWith("'") && cleaned.endsWith("'")) {
1812
- cleaned = cleaned.slice(1, -1).trim();
1813
- }
1814
- return cleaned;
1815
- }
1816
- /**
1817
- * Create a GitHub PR for the branch
1818
- * @param branchName - Branch to create PR from (used as --head)
1819
- * @param title - PR title
1820
- * @param body - PR body
1821
- * @param baseBranch - Base branch to target (usually main/master)
1822
- * @param cwd - Working directory
1823
- * @returns PR URL
1824
- */
1825
- async createPR(branchName, title, body, baseBranch, cwd) {
1826
- try {
1827
- const targetRemote = await getEffectivePRTargetRemote(this.settings, cwd);
1828
- let headValue = branchName;
1829
- if (targetRemote !== "origin") {
1830
- const remotes = await parseGitRemotes(cwd);
1831
- const originRemote = remotes.find((r) => r.name === "origin");
1832
- if (originRemote) {
1833
- headValue = `${originRemote.owner}:${branchName}`;
1834
- getLogger().debug(`Fork workflow detected, using head: ${headValue}`);
1835
- }
1836
- }
1837
- const args = ["pr", "create", "--head", headValue, "--title", title, "--body", body, "--base", baseBranch];
1838
- if (targetRemote !== "origin") {
1839
- const repo = await getConfiguredRepoFromSettings(this.settings, cwd);
1840
- args.push("--repo", repo);
1841
- }
1842
- const result = await executeGhCommand(args, cwd ? { cwd } : void 0);
1843
- const url = typeof result === "string" ? result.trim() : String(result).trim();
1844
- if (!url.includes("github.com") || !url.includes("/pull/")) {
1845
- throw new Error(`Unexpected response from gh pr create: ${url}`);
1846
- }
1847
- return url;
1848
- } catch (error) {
1849
- const errorMessage = error instanceof Error ? error.message : String(error);
1850
- if (errorMessage.includes("Head sha can't be blank") || errorMessage.includes("No commits between")) {
1851
- throw new Error(
1852
- `Failed to create pull request: ${errorMessage}
1853
-
1854
- This error typically occurs when:
1855
- - The branch was not fully pushed to the remote
1856
- - There's a race condition between push and PR creation
1857
- - The branch has no commits ahead of the base branch
1858
-
1859
- Try running: git push -u origin ${branchName}
1860
- Then retry: il finish`
1861
- );
1862
- }
1863
- throw new Error(`Failed to create pull request: ${errorMessage}`);
1864
- }
1865
- }
1866
- /**
1867
- * Open PR URL in browser
1868
- * @param url - PR URL to open
1869
- */
1870
- async openPRInBrowser(url) {
1871
- try {
1872
- await openBrowser(url);
1873
- getLogger().debug("Opened PR in browser", { url });
1874
- } catch (error) {
1875
- getLogger().warn("Failed to open PR in browser", { error });
1876
- }
1877
- }
1878
- /**
1879
- * Complete PR workflow: check for existing, create if needed, optionally open in browser
1880
- * @param branchName - Branch to create PR from
1881
- * @param title - PR title
1882
- * @param issueNumber - Optional issue number for body generation
1883
- * @param baseBranch - Base branch to target
1884
- * @param worktreePath - Path to worktree
1885
- * @param openInBrowser - Whether to open PR in browser
1886
- * @returns PR creation result
1887
- */
1888
- async createOrOpenPR(branchName, title, issueNumber, baseBranch, worktreePath, openInBrowser) {
1889
- const existingPR = await this.checkForExistingPR(branchName, worktreePath);
1890
- if (existingPR) {
1891
- getLogger().info(`Pull request already exists: ${existingPR.url}`);
1892
- if (openInBrowser) {
1893
- await this.openPRInBrowser(existingPR.url);
1894
- }
1895
- return {
1896
- url: existingPR.url,
1897
- number: existingPR.number,
1898
- wasExisting: true
1899
- };
1900
- }
1901
- const body = await this.generatePRBody(issueNumber, worktreePath);
1902
- getLogger().info("Creating pull request...");
1903
- const url = await this.createPR(branchName, title, body, baseBranch, worktreePath);
1904
- const prNumber = this.extractPRNumberFromUrl(url);
1905
- if (openInBrowser) {
1906
- await this.openPRInBrowser(url);
1907
- }
1908
- return {
1909
- url,
1910
- number: prNumber,
1911
- wasExisting: false
1912
- };
1913
- }
1914
- /**
1915
- * Extract PR number from GitHub PR URL
1916
- * @param url - PR URL (e.g., https://github.com/owner/repo/pull/123)
1917
- * @returns PR number
1918
- */
1919
- extractPRNumberFromUrl(url) {
1920
- const match = url.match(/\/pull\/(\d+)/);
1921
- if (match == null ? void 0 : match[1]) {
1922
- return parseInt(match[1], 10);
1923
- }
1924
- throw new Error(`Could not extract PR number from URL: ${url}`);
1925
- }
1926
- };
1927
-
1928
1670
  // src/commands/finish.ts
1929
1671
  import path3 from "path";
1930
1672
  var FinishCommand = class {
@@ -2302,10 +2044,22 @@ var FinishCommand = class {
2302
2044
  }
2303
2045
  /**
2304
2046
  * Execute workflow for issues and branches (merge into main)
2305
- * This is the traditional workflow: validatecommitrebase → merge → cleanup
2047
+ * This is the workflow: rebasevalidatecommit → merge → cleanup
2306
2048
  */
2307
2049
  async executeIssueWorkflow(parsed, options, worktree, result) {
2308
- var _a, _b;
2050
+ var _a, _b, _c;
2051
+ getLogger().info("Rebasing branch on main...");
2052
+ const mergeOptions = {
2053
+ dryRun: options.dryRun ?? false,
2054
+ force: options.force ?? false
2055
+ };
2056
+ await this.mergeManager.rebaseOnMain(worktree.path, mergeOptions);
2057
+ getLogger().success("Branch rebased successfully");
2058
+ result.operations.push({
2059
+ type: "rebase",
2060
+ message: "Branch rebased on main",
2061
+ success: true
2062
+ });
2309
2063
  if (!options.dryRun) {
2310
2064
  getLogger().info("Running pre-merge validations...");
2311
2065
  await this.validationRunner.runValidations(worktree.path, {
@@ -2380,18 +2134,92 @@ var FinishCommand = class {
2380
2134
  await this.executeGitHubPRWorkflow(parsed, options, worktree, settings, result);
2381
2135
  return;
2382
2136
  }
2383
- getLogger().info("Rebasing branch on main...");
2384
- const mergeOptions = {
2385
- dryRun: options.dryRun ?? false,
2386
- force: options.force ?? false
2387
- };
2388
- await this.mergeManager.rebaseOnMain(worktree.path, mergeOptions);
2389
- getLogger().success("Branch rebased successfully");
2390
- result.operations.push({
2391
- type: "rebase",
2392
- message: "Branch rebased on main",
2393
- success: true
2394
- });
2137
+ if (mergeBehavior.mode === "github-draft-pr") {
2138
+ if (!this.issueTracker.supportsPullRequests) {
2139
+ throw new Error(
2140
+ `The 'github-draft-pr' merge mode requires a GitHub-compatible issue tracker. Your provider (${this.issueTracker.providerName}) does not support pull requests.`
2141
+ );
2142
+ }
2143
+ const { MetadataManager: MetadataManager2 } = await import("./MetadataManager-WXUVXKUS.js");
2144
+ const metadataManager = new MetadataManager2();
2145
+ const metadata = await metadataManager.readMetadata(worktree.path);
2146
+ getLogger().debug(`Draft PR mode: worktree=${worktree.path}, draftPrNumber=${(metadata == null ? void 0 : metadata.draftPrNumber) ?? "none"}`);
2147
+ if (!(metadata == null ? void 0 : metadata.draftPrNumber)) {
2148
+ getLogger().warn("No draft PR found in metadata, creating new PR...");
2149
+ await this.executeGitHubPRWorkflow(parsed, options, worktree, settings, result);
2150
+ return;
2151
+ }
2152
+ const isHeadPlaceholder = await isPlaceholderCommit(worktree.path);
2153
+ const placeholderSha = await findPlaceholderCommitSha(worktree.path);
2154
+ getLogger().debug(`Placeholder detection: isHead=${isHeadPlaceholder}, sha=${placeholderSha ?? "none"}`);
2155
+ if (isHeadPlaceholder) {
2156
+ const commitCount = await executeGitCommand(
2157
+ ["rev-list", "--count", "HEAD"],
2158
+ { cwd: worktree.path }
2159
+ );
2160
+ if (parseInt(commitCount.trim(), 10) <= 1) {
2161
+ throw new Error(
2162
+ "Cannot finish draft PR: no changes have been committed.\nPlease make at least one commit before finishing."
2163
+ );
2164
+ }
2165
+ if (!options.dryRun) {
2166
+ getLogger().info("Removing placeholder commit from HEAD...");
2167
+ await removePlaceholderCommitFromHead(worktree.path);
2168
+ } else {
2169
+ getLogger().info("[DRY RUN] Would remove placeholder commit from HEAD");
2170
+ }
2171
+ } else if (placeholderSha) {
2172
+ const commitsAfterPlaceholder = await executeGitCommand(
2173
+ ["rev-list", "--count", `${placeholderSha}..HEAD`],
2174
+ { cwd: worktree.path }
2175
+ );
2176
+ if (parseInt(commitsAfterPlaceholder.trim(), 10) === 0) {
2177
+ throw new Error(
2178
+ "Cannot finish draft PR: no changes have been committed after the placeholder.\nPlease make at least one commit before finishing."
2179
+ );
2180
+ }
2181
+ if (!options.dryRun) {
2182
+ getLogger().info("Removing placeholder commit from history...");
2183
+ await removePlaceholderCommitFromHistory(worktree.path, placeholderSha);
2184
+ } else {
2185
+ getLogger().info("[DRY RUN] Would remove placeholder commit from history");
2186
+ }
2187
+ }
2188
+ const needsForceWithLease = isHeadPlaceholder || placeholderSha;
2189
+ if (!options.dryRun) {
2190
+ getLogger().info("Pushing final commits to remote...");
2191
+ if (needsForceWithLease) {
2192
+ await executeGitCommand(["push", "--force-with-lease", "origin", worktree.branch], { cwd: worktree.path });
2193
+ } else {
2194
+ await pushBranchToRemote(worktree.branch, worktree.path, { dryRun: false });
2195
+ }
2196
+ } else {
2197
+ if (needsForceWithLease) {
2198
+ getLogger().info("[DRY RUN] Would force push final commits to remote (history rewritten)");
2199
+ } else {
2200
+ getLogger().info("[DRY RUN] Would push final commits to remote");
2201
+ }
2202
+ }
2203
+ const prManager = new PRManager(settings);
2204
+ if (!options.dryRun) {
2205
+ await prManager.markPRReady(metadata.draftPrNumber, worktree.path);
2206
+ getLogger().success(`PR #${metadata.draftPrNumber} marked as ready for review`);
2207
+ } else {
2208
+ getLogger().info(`[DRY RUN] Would mark PR #${metadata.draftPrNumber} as ready for review`);
2209
+ }
2210
+ const prUrl = (_c = metadata.prUrls) == null ? void 0 : _c[String(metadata.draftPrNumber)];
2211
+ if (prUrl) {
2212
+ result.prUrl = prUrl;
2213
+ }
2214
+ result.operations.push({
2215
+ type: "pr-ready",
2216
+ message: `PR #${metadata.draftPrNumber} marked as ready for review`,
2217
+ success: true
2218
+ });
2219
+ await this.generateSessionSummaryIfConfigured(parsed, worktree, options, metadata.draftPrNumber);
2220
+ await this.handlePRCleanupPrompt(parsed, options, worktree, result);
2221
+ return;
2222
+ }
2395
2223
  getLogger().info("Performing fast-forward merge...");
2396
2224
  await this.mergeManager.performFastForwardMerge(worktree.branch, worktree.path, mergeOptions);
2397
2225
  getLogger().success("Fast-forward merge completed successfully");
@@ -2555,7 +2383,7 @@ var FinishCommand = class {
2555
2383
  });
2556
2384
  }
2557
2385
  finishResult.prUrl = prResult.url;
2558
- await this.generateSessionSummaryIfConfigured(parsed, worktree, options);
2386
+ await this.generateSessionSummaryIfConfigured(parsed, worktree, options, prResult.number);
2559
2387
  await this.handlePRCleanupPrompt(parsed, options, worktree, finishResult);
2560
2388
  }
2561
2389
  }
@@ -2578,8 +2406,8 @@ var FinishCommand = class {
2578
2406
  getLogger().info("");
2579
2407
  const shouldCleanup = await promptConfirmation(
2580
2408
  "Clean up worktree now?",
2581
- false
2582
- // Default to keeping worktree (safer option)
2409
+ true
2410
+ // Default to keeping worktree - won't delete if unmerged changes
2583
2411
  );
2584
2412
  if (shouldCleanup) {
2585
2413
  await this.performWorktreeCleanup(parsed, options, worktree, finishResult);
@@ -2720,8 +2548,13 @@ var FinishCommand = class {
2720
2548
  * This ensures the finish workflow continues even if summary generation fails
2721
2549
  *
2722
2550
  * In dry-run mode: generates summary and shows preview, but doesn't post
2551
+ *
2552
+ * @param parsed - The parsed input identifying the issue/PR being finished
2553
+ * @param worktree - The worktree being finished
2554
+ * @param options - Finish options (including dryRun flag)
2555
+ * @param prNumber - Optional PR number - when provided, summary is posted to the PR instead of the issue
2723
2556
  */
2724
- async generateSessionSummaryIfConfigured(parsed, worktree, options) {
2557
+ async generateSessionSummaryIfConfigured(parsed, worktree, options, prNumber) {
2725
2558
  if (parsed.type === "branch") {
2726
2559
  return;
2727
2560
  }
@@ -2752,7 +2585,8 @@ var FinishCommand = class {
2752
2585
  worktreePath: worktree.path,
2753
2586
  issueNumber: parsed.number ?? 0,
2754
2587
  branchName: worktree.branch,
2755
- loomType: parsed.type
2588
+ loomType: parsed.type,
2589
+ ...prNumber !== void 0 && { prNumber }
2756
2590
  });
2757
2591
  }
2758
2592
  /**
@@ -2992,7 +2826,9 @@ function formatLoomForJson(worktree, mainWorktreePath, metadata) {
2992
2826
  created_at: (metadata == null ? void 0 : metadata.created_at) ?? null,
2993
2827
  issueTracker: (metadata == null ? void 0 : metadata.issueTracker) ?? null,
2994
2828
  colorHex: (metadata == null ? void 0 : metadata.colorHex) ?? null,
2995
- projectPath: (metadata == null ? void 0 : metadata.projectPath) ?? null
2829
+ projectPath: (metadata == null ? void 0 : metadata.projectPath) ?? null,
2830
+ issueUrls: (metadata == null ? void 0 : metadata.issueUrls) ?? {},
2831
+ prUrls: (metadata == null ? void 0 : metadata.prUrls) ?? {}
2996
2832
  };
2997
2833
  }
2998
2834
  function formatLoomsForJson(worktrees, mainWorktreePath, metadata) {
@@ -3040,6 +2876,7 @@ async function validateSettingsForCommand(command) {
3040
2876
  if (bypassCommands.includes(commandName)) {
3041
2877
  return;
3042
2878
  }
2879
+ const warnOnlyCommands = ["list", "projects"];
3043
2880
  try {
3044
2881
  const settingsManager = new SettingsManager();
3045
2882
  const settings = await settingsManager.loadSettings();
@@ -3049,6 +2886,10 @@ async function validateSettingsForCommand(command) {
3049
2886
  return;
3050
2887
  }
3051
2888
  } catch (error) {
2889
+ if (warnOnlyCommands.includes(commandName)) {
2890
+ logger.warn(`Configuration warning: ${error instanceof Error ? error.message : "Unknown error"}`);
2891
+ return;
2892
+ }
3052
2893
  logger.error(`Configuration error: ${error instanceof Error ? error.message : "Unknown error"}`);
3053
2894
  logger.info("Please fix your .iloom/settings.json file and try again.");
3054
2895
  process.exit(1);
@@ -3118,14 +2959,14 @@ async function autoLaunchInitForMultipleRemotes() {
3118
2959
  await waitForKeypress2("Press any key to start configuration...");
3119
2960
  logger.info("");
3120
2961
  try {
3121
- const { InitCommand: InitCommand2 } = await import("./init-LBA6NUK2.js");
2962
+ const { InitCommand: InitCommand2 } = await import("./init-F6PFMSU5.js");
3122
2963
  const initCommand = new InitCommand2();
3123
2964
  const customInitialMessage = "Help me configure which git remote iloom should use for GitHub operations. I have multiple remotes and need to select the correct one.";
3124
2965
  await initCommand.execute(customInitialMessage);
3125
2966
  logger.info("");
3126
2967
  logger.info("Configuration complete! Continuing with your original command...");
3127
2968
  logger.info("");
3128
- const { SettingsManager: SettingsManager2 } = await import("./SettingsManager-FJFU6JJD.js");
2969
+ const { SettingsManager: SettingsManager2 } = await import("./SettingsManager-XPR4TEQL.js");
3129
2970
  const settingsManager = new SettingsManager2();
3130
2971
  const settings = await settingsManager.loadSettings();
3131
2972
  const { hasMultipleRemotes: hasMultipleRemotes2 } = await import("./remote-73TZ2ADI.js");
@@ -3219,7 +3060,7 @@ program.command("add-issue").alias("a").description("Create and enhance GitHub i
3219
3060
  });
3220
3061
  program.command("feedback").alias("f").description("Submit feedback/bug report to iloom-cli repository").argument("<description>", "Natural language description of feedback (>50 chars, >2 spaces)").option("--body <text>", "Body text for feedback (added after diagnostics)").action(async (description, options) => {
3221
3062
  try {
3222
- const { FeedbackCommand } = await import("./feedback-7PVBQNLJ.js");
3063
+ const { FeedbackCommand } = await import("./feedback-RVIGHBJG.js");
3223
3064
  const command = new FeedbackCommand();
3224
3065
  const feedbackOptions = {};
3225
3066
  if (options.body !== void 0) {
@@ -3299,7 +3140,7 @@ program.command("finish").alias("dn").description("Merge work and cleanup worksp
3299
3140
  });
3300
3141
  program.command("rebase").description("Rebase current branch on main with Claude-assisted conflict resolution").option("-f, --force", "Skip confirmation prompts").option("-n, --dry-run", "Preview actions without executing").action(async (options) => {
3301
3142
  try {
3302
- const { RebaseCommand } = await import("./rebase-4T5FQHNH.js");
3143
+ const { RebaseCommand } = await import("./rebase-WZHHE5LU.js");
3303
3144
  const command = new RebaseCommand();
3304
3145
  await command.execute(options);
3305
3146
  } catch (error) {
@@ -3311,7 +3152,7 @@ program.command("spin").alias("ignite").description("Launch Claude with auto-det
3311
3152
  new Option("--one-shot <mode>", "One-shot automation mode").choices(["default", "noReview", "bypassPermissions"]).default("default")
3312
3153
  ).action(async (options) => {
3313
3154
  try {
3314
- const { IgniteCommand } = await import("./ignite-3B264M7K.js");
3155
+ const { IgniteCommand } = await import("./ignite-XJALWFAT.js");
3315
3156
  const command = new IgniteCommand();
3316
3157
  await command.execute(options.oneShot ?? "default");
3317
3158
  } catch (error) {
@@ -3322,7 +3163,7 @@ program.command("spin").alias("ignite").description("Launch Claude with auto-det
3322
3163
  program.command("open").description("Open workspace in browser or run CLI tool").argument("[identifier]", "Issue number, PR number, or branch name (auto-detected if omitted)").allowUnknownOption().action(async (identifier, _options, command) => {
3323
3164
  try {
3324
3165
  const args = (command == null ? void 0 : command.args) ? command.args.slice(identifier ? 1 : 0) : [];
3325
- const { OpenCommand } = await import("./open-OGCV32Z4.js");
3166
+ const { OpenCommand } = await import("./open-KW4NTLXH.js");
3326
3167
  const cmd = new OpenCommand();
3327
3168
  const input = identifier ? { identifier, args } : { args };
3328
3169
  await cmd.execute(input);
@@ -3334,7 +3175,7 @@ program.command("open").description("Open workspace in browser or run CLI tool")
3334
3175
  program.command("run").description("Run CLI tool or open workspace in browser").argument("[identifier]", "Issue number, PR number, or branch name (auto-detected if omitted)").allowUnknownOption().action(async (identifier, _options, command) => {
3335
3176
  try {
3336
3177
  const args = (command == null ? void 0 : command.args) ? command.args.slice(identifier ? 1 : 0) : [];
3337
- const { RunCommand } = await import("./run-HNOP6WE2.js");
3178
+ const { RunCommand } = await import("./run-HRYQ7TR7.js");
3338
3179
  const cmd = new RunCommand();
3339
3180
  const input = identifier ? { identifier, args } : { args };
3340
3181
  await cmd.execute(input);
@@ -3345,7 +3186,7 @@ program.command("run").description("Run CLI tool or open workspace in browser").
3345
3186
  });
3346
3187
  program.command("dev-server").alias("dev").description("Start dev server for workspace (foreground)").argument("[identifier]", "Issue number, PR number, or branch name (auto-detected if omitted)").option("--json", "Output as JSON").action(async (identifier, options) => {
3347
3188
  try {
3348
- const { DevServerCommand } = await import("./dev-server-JCJGQ3PV.js");
3189
+ const { DevServerCommand } = await import("./dev-server-ASH7HJVI.js");
3349
3190
  const cmd = new DevServerCommand();
3350
3191
  await cmd.execute({ identifier, json: options == null ? void 0 : options.json });
3351
3192
  } catch (error) {
@@ -3355,7 +3196,7 @@ program.command("dev-server").alias("dev").description("Start dev server for wor
3355
3196
  });
3356
3197
  program.command("shell").alias("terminal").description("Open interactive shell with workspace environment").argument("[identifier]", "Issue number, PR number, or branch name (auto-detected if omitted)").action(async (identifier) => {
3357
3198
  try {
3358
- const { ShellCommand } = await import("./shell-DE3HKJSM.js");
3199
+ const { ShellCommand } = await import("./shell-JMU5XTHW.js");
3359
3200
  const cmd = new ShellCommand();
3360
3201
  await cmd.execute({ identifier });
3361
3202
  } catch (error) {
@@ -3366,7 +3207,7 @@ program.command("shell").alias("terminal").description("Open interactive shell w
3366
3207
  program.command("cleanup").alias("remove").alias("clean").description("Remove workspaces").argument("[identifier]", "Branch name or issue number to cleanup (auto-detected)").option("-l, --list", "List all worktrees").option("-a, --all", "Remove all worktrees (interactive confirmation)").option("-i, --issue <number>", "Cleanup by issue number", parseInt).option("-f, --force", "Skip confirmations and force removal").option("--dry-run", "Show what would be done without doing it").option("--json", "Output result as JSON").action(async (identifier, options) => {
3367
3208
  const executeAction = async () => {
3368
3209
  try {
3369
- const { CleanupCommand } = await import("./cleanup-KDLVTT7M.js");
3210
+ const { CleanupCommand } = await import("./cleanup-MIDJVSIU.js");
3370
3211
  const command = new CleanupCommand();
3371
3212
  const input = {
3372
3213
  options: options ?? {}
@@ -3406,7 +3247,11 @@ program.command("list").description("Show active workspaces").option("--json", "
3406
3247
  metadata.set(worktree.path, loomMetadata);
3407
3248
  }
3408
3249
  if (options.json) {
3409
- const mainWorktreePath = await findMainWorktreePathWithSettings();
3250
+ let mainWorktreePath;
3251
+ try {
3252
+ mainWorktreePath = await findMainWorktreePathWithSettings();
3253
+ } catch {
3254
+ }
3410
3255
  console.log(JSON.stringify(formatLoomsForJson(worktrees, mainWorktreePath, metadata), null, 2));
3411
3256
  return;
3412
3257
  }
@@ -3440,7 +3285,7 @@ program.command("list").description("Show active workspaces").option("--json", "
3440
3285
  });
3441
3286
  program.command("projects").description("List configured iloom projects").option("--json", "Output as JSON (default behavior)").action(async (options) => {
3442
3287
  try {
3443
- const { ProjectsCommand } = await import("./projects-P55273AB.js");
3288
+ const { ProjectsCommand } = await import("./projects-QEAEBAT2.js");
3444
3289
  const command = new ProjectsCommand();
3445
3290
  const result = await command.execute(options);
3446
3291
  console.log(JSON.stringify(result, null, 2));
@@ -3449,9 +3294,9 @@ program.command("projects").description("List configured iloom projects").option
3449
3294
  process.exit(1);
3450
3295
  }
3451
3296
  });
3452
- program.command("init").alias("config").description("Initialize iloom configuration and setup shell autocomplete").argument("[prompt]", 'Custom initial message to send to Claude (defaults to "Help me configure iloom settings.")').action(async (prompt) => {
3297
+ program.command("init").alias("config").description("Initialize iloom configuration").argument("[prompt]", 'Custom initial message to send to Claude (defaults to "Help me configure iloom settings.")').action(async (prompt) => {
3453
3298
  try {
3454
- const { InitCommand: InitCommand2 } = await import("./init-LBA6NUK2.js");
3299
+ const { InitCommand: InitCommand2 } = await import("./init-F6PFMSU5.js");
3455
3300
  const command = new InitCommand2();
3456
3301
  const trimmedPrompt = prompt == null ? void 0 : prompt.trim();
3457
3302
  const customPrompt = trimmedPrompt && trimmedPrompt.length > 0 ? trimmedPrompt : void 0;
@@ -3463,7 +3308,7 @@ program.command("init").alias("config").description("Initialize iloom configurat
3463
3308
  });
3464
3309
  program.command("contribute").description("Set up local development environment for contributing to iloom").action(async () => {
3465
3310
  try {
3466
- const { ContributeCommand } = await import("./contribute-HY372S6F.js");
3311
+ const { ContributeCommand } = await import("./contribute-RS3DO3WP.js");
3467
3312
  const command = new ContributeCommand();
3468
3313
  await command.execute();
3469
3314
  } catch (error) {
@@ -3543,9 +3388,9 @@ program.command("test-github").description("Test GitHub integration (Issue #3)")
3543
3388
  program.command("test-claude").description("Test Claude integration (Issue #10)").option("--detect", "Test Claude CLI detection").option("--version", "Get Claude CLI version").option("--branch <title>", "Test branch name generation with given title").option("--issue <number>", "Issue number for branch generation", "123").option("--launch <prompt>", "Launch Claude with a prompt (headless)").option("--interactive", "Launch Claude interactively (requires --launch)").option("--template <name>", "Test template loading").action(async (options) => {
3544
3389
  try {
3545
3390
  const { detectClaudeCli: detectClaudeCli2, getClaudeVersion, generateBranchName, launchClaude: launchClaude2 } = await import("./claude-ACVXNB6N.js");
3546
- const { PromptTemplateManager } = await import("./PromptTemplateManager-2TDZAUC6.js");
3547
- const { ClaudeService } = await import("./ClaudeService-W3SA7HVG.js");
3548
- const { ClaudeContextManager: ClaudeContextManager2 } = await import("./ClaudeContextManager-DK77227F.js");
3391
+ const { PromptTemplateManager } = await import("./PromptTemplateManager-72FEOGT6.js");
3392
+ const { ClaudeService } = await import("./ClaudeService-CJS32WG2.js");
3393
+ const { ClaudeContextManager: ClaudeContextManager2 } = await import("./ClaudeContextManager-DQFKIMEP.js");
3549
3394
  logger.info("Testing Claude Integration\n");
3550
3395
  if (options.detect) {
3551
3396
  logger.info("Detecting Claude CLI...");
@@ -3693,7 +3538,7 @@ program.command("test-webserver").description("Test if a web server is running o
3693
3538
  });
3694
3539
  program.command("test-git").description("Test Git integration - findMainWorktreePath() function (reads .iloom/settings.json)").action(async () => {
3695
3540
  try {
3696
- const { TestGitCommand } = await import("./test-git-YMAE57UP.js");
3541
+ const { TestGitCommand } = await import("./test-git-6SAIRBUD.js");
3697
3542
  const command = new TestGitCommand();
3698
3543
  await command.execute();
3699
3544
  } catch (error) {
@@ -3719,7 +3564,7 @@ program.command("test-tabs").description("Test iTerm2 dual tab functionality - o
3719
3564
  });
3720
3565
  program.command("test-prefix").description("Test worktree prefix configuration - preview worktree paths (reads .iloom/settings.json)").action(async () => {
3721
3566
  try {
3722
- const { TestPrefixCommand } = await import("./test-prefix-YCKL6CMT.js");
3567
+ const { TestPrefixCommand } = await import("./test-prefix-RLVRK5ZD.js");
3723
3568
  const command = new TestPrefixCommand();
3724
3569
  await command.execute();
3725
3570
  } catch (error) {
@@ -3733,7 +3578,7 @@ program.command("test-prefix").description("Test worktree prefix configuration -
3733
3578
  program.command("summary").description("Generate Claude session summary for a loom").argument("[identifier]", "Issue number, PR number (pr/123), or branch name (auto-detected if omitted)").option("--with-comment", "Post summary as a comment to the issue/PR").option("--json", "Output result as JSON").action(async (identifier, options) => {
3734
3579
  const executeAction = async () => {
3735
3580
  try {
3736
- const { SummaryCommand } = await import("./summary-GDT7DTRI.js");
3581
+ const { SummaryCommand } = await import("./summary-4SSGGH7N.js");
3737
3582
  const command = new SummaryCommand();
3738
3583
  const result = await command.execute({ identifier, options });
3739
3584
  if (options.json && result) {
@@ -3759,10 +3604,39 @@ program.command("summary").description("Generate Claude session summary for a lo
3759
3604
  await executeAction();
3760
3605
  }
3761
3606
  });
3607
+ program.command("recap").description("Get recap for a loom (defaults to current directory)").argument("[identifier]", "Issue number, PR number (pr/123), or branch name (auto-detected if omitted)").option("--json", "Output as JSON with filePath for file watching").action(async (identifier, options) => {
3608
+ const executeAction = async () => {
3609
+ try {
3610
+ const { RecapCommand } = await import("./recap-33NPZ3ZO.js");
3611
+ const command = new RecapCommand();
3612
+ const result = await command.execute({ identifier, json: options.json });
3613
+ if (options.json && result) {
3614
+ console.log(JSON.stringify(result, null, 2));
3615
+ }
3616
+ process.exit(0);
3617
+ } catch (error) {
3618
+ if (options.json) {
3619
+ console.log(JSON.stringify({ error: error instanceof Error ? error.message : "Unknown error" }, null, 2));
3620
+ } else {
3621
+ logger.error(`Recap failed: ${error instanceof Error ? error.message : "Unknown error"}`);
3622
+ if (error instanceof Error && error.stack) {
3623
+ logger.debug(error.stack);
3624
+ }
3625
+ }
3626
+ process.exit(1);
3627
+ }
3628
+ };
3629
+ if (options.json) {
3630
+ const jsonLogger = createStderrLogger();
3631
+ await withLogger(jsonLogger, executeAction);
3632
+ } else {
3633
+ await executeAction();
3634
+ }
3635
+ });
3762
3636
  program.command("test-neon").description("Test Neon integration and debug configuration").action(async () => {
3763
3637
  var _a;
3764
3638
  try {
3765
- const { SettingsManager: SettingsManager2 } = await import("./SettingsManager-FJFU6JJD.js");
3639
+ const { SettingsManager: SettingsManager2 } = await import("./SettingsManager-XPR4TEQL.js");
3766
3640
  const { createNeonProviderFromSettings: createNeonProviderFromSettings2 } = await import("./neon-helpers-L5CXQ5CT.js");
3767
3641
  logger.info("Testing Neon Integration\n");
3768
3642
  logger.info("1. Settings Configuration:");