@iloom/cli 0.3.2 → 0.3.4

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 (112) hide show
  1. package/README.md +3 -3
  2. package/dist/{BranchNamingService-JYO746H7.js → BranchNamingService-A77VI6AI.js} +2 -2
  3. package/dist/ClaudeContextManager-BN7RE5ZQ.js +15 -0
  4. package/dist/ClaudeService-DLYLJUPA.js +14 -0
  5. package/dist/{GitHubService-UAMH7DMF.js → GitHubService-FZHHBOFG.js} +3 -3
  6. package/dist/{LoomLauncher-FVZECY3C.js → LoomLauncher-ZV3ZZIBA.js} +23 -20
  7. package/dist/LoomLauncher-ZV3ZZIBA.js.map +1 -0
  8. package/dist/{PromptTemplateManager-A52RUAMS.js → PromptTemplateManager-6HH3PVXV.js} +2 -2
  9. package/dist/README.md +3 -3
  10. package/dist/{SettingsManager-MTVX57WR.js → SettingsManager-I2LRCW2A.js} +2 -2
  11. package/dist/{SettingsMigrationManager-AGIIIPDQ.js → SettingsMigrationManager-TJ7UWZG5.js} +3 -3
  12. package/dist/agents/iloom-issue-complexity-evaluator.md +18 -3
  13. package/dist/agents/iloom-issue-enhancer.md +1 -1
  14. package/dist/{chunk-OAP6SASD.js → chunk-2CXREBLZ.js} +2 -2
  15. package/dist/{chunk-KG343GSG.js → chunk-2IJEMXOB.js} +359 -99
  16. package/dist/chunk-2IJEMXOB.js.map +1 -0
  17. package/dist/{chunk-FOV7RRQ2.js → chunk-2MAIX45J.js} +4 -4
  18. package/dist/{chunk-5NTD4MCZ.js → chunk-5Q3NDNNV.js} +29 -5
  19. package/dist/chunk-5Q3NDNNV.js.map +1 -0
  20. package/dist/{chunk-GVICXJHW.js → chunk-5VK4NRSF.js} +2 -2
  21. package/dist/{chunk-C7ASXK6J.js → chunk-AKUJXDNW.js} +2 -2
  22. package/dist/{chunk-UCZ24SUE.js → chunk-CDZERT7Z.js} +21 -9
  23. package/dist/chunk-CDZERT7Z.js.map +1 -0
  24. package/dist/{chunk-JKXJ7BGL.js → chunk-CE26YH2U.js} +42 -3
  25. package/dist/chunk-CE26YH2U.js.map +1 -0
  26. package/dist/{chunk-ZZZWQGTS.js → chunk-CFFQ2Z7A.js} +74 -75
  27. package/dist/chunk-CFFQ2Z7A.js.map +1 -0
  28. package/dist/{chunk-FXMLNKLT.js → chunk-DLHA5VQ3.js} +174 -5
  29. package/dist/chunk-DLHA5VQ3.js.map +1 -0
  30. package/dist/{chunk-GOG3ZB7O.js → chunk-IFB4Z76W.js} +23 -4
  31. package/dist/chunk-IFB4Z76W.js.map +1 -0
  32. package/dist/{chunk-F4ENT6AC.js → chunk-M7JJCX53.js} +2 -2
  33. package/dist/{chunk-KLBYVHPK.js → chunk-OSCLCMDG.js} +2 -2
  34. package/dist/{chunk-ZLIHIUDQ.js → chunk-OYF4VIFI.js} +2 -2
  35. package/dist/{chunk-A2P7NZTB.js → chunk-PGPI5LR4.js} +4 -4
  36. package/dist/{chunk-WEN5C5DM.js → chunk-RIEO2WML.js} +4 -1
  37. package/dist/chunk-RIEO2WML.js.map +1 -0
  38. package/dist/{chunk-UERERX6M.js → chunk-SUOXY5WJ.js} +2 -2
  39. package/dist/{init-7IIM35LQ.js → chunk-UAN4A3YU.js} +343 -46
  40. package/dist/chunk-UAN4A3YU.js.map +1 -0
  41. package/dist/{claude-KIZYXTSG.js → claude-W52VKI6L.js} +2 -2
  42. package/dist/{cleanup-6WYUD5SN.js → cleanup-H4VXU3C3.js} +12 -12
  43. package/dist/cli.js +188 -91
  44. package/dist/cli.js.map +1 -1
  45. package/dist/{color-ZVALX37U.js → color-F7RU6B6Z.js} +10 -4
  46. package/dist/{contribute-7YJHZTO7.js → contribute-Y7IQV5QY.js} +4 -4
  47. package/dist/{feedback-752MGDPG.js → feedback-XTUCKJNT.js} +11 -9
  48. package/dist/{feedback-752MGDPG.js.map → feedback-XTUCKJNT.js.map} +1 -1
  49. package/dist/{git-TAFVDB3J.js → git-IYA53VIC.js} +7 -3
  50. package/dist/{ignite-OAMDUN27.js → ignite-T74RYXCA.js} +19 -71
  51. package/dist/ignite-T74RYXCA.js.map +1 -0
  52. package/dist/index.d.ts +52 -8
  53. package/dist/index.js +132 -84
  54. package/dist/index.js.map +1 -1
  55. package/dist/init-4FHTAM3F.js +19 -0
  56. package/dist/{neon-helpers-5HBYO2VP.js → neon-helpers-77PBPGJ5.js} +3 -3
  57. package/dist/{open-FCHKQ77R.js → open-UMXANW5S.js} +4 -4
  58. package/dist/{prompt-7INJ7YRU.js → prompt-QALMYTVC.js} +4 -2
  59. package/dist/prompt-QALMYTVC.js.map +1 -0
  60. package/dist/prompts/init-prompt.txt +82 -8
  61. package/dist/prompts/issue-prompt.txt +18 -11
  62. package/dist/prompts/regular-prompt.txt +373 -14
  63. package/dist/{rebase-Q7WXK566.js → rebase-VJ2VKR6R.js} +11 -11
  64. package/dist/rebase-VJ2VKR6R.js.map +1 -0
  65. package/dist/{run-SJPM6YRI.js → run-MJYY4PUT.js} +4 -4
  66. package/dist/schema/settings.schema.json +21 -3
  67. package/dist/{test-git-DEUE656D.js → test-git-IT5EWQ5C.js} +3 -3
  68. package/dist/{test-prefix-Y6Z6ZHSF.js → test-prefix-NPWDPUUH.js} +3 -3
  69. package/package.json +2 -1
  70. package/dist/ClaudeContextManager-5WPRJIIW.js +0 -15
  71. package/dist/ClaudeService-Z4KA7QOW.js +0 -14
  72. package/dist/LoomLauncher-FVZECY3C.js.map +0 -1
  73. package/dist/chunk-5NTD4MCZ.js.map +0 -1
  74. package/dist/chunk-FXMLNKLT.js.map +0 -1
  75. package/dist/chunk-GOG3ZB7O.js.map +0 -1
  76. package/dist/chunk-JKXJ7BGL.js.map +0 -1
  77. package/dist/chunk-KG343GSG.js.map +0 -1
  78. package/dist/chunk-PRE7KTM4.js +0 -302
  79. package/dist/chunk-PRE7KTM4.js.map +0 -1
  80. package/dist/chunk-UCZ24SUE.js.map +0 -1
  81. package/dist/chunk-WEN5C5DM.js.map +0 -1
  82. package/dist/chunk-ZZZWQGTS.js.map +0 -1
  83. package/dist/ignite-OAMDUN27.js.map +0 -1
  84. package/dist/init-7IIM35LQ.js.map +0 -1
  85. package/dist/rebase-Q7WXK566.js.map +0 -1
  86. /package/dist/{BranchNamingService-JYO746H7.js.map → BranchNamingService-A77VI6AI.js.map} +0 -0
  87. /package/dist/{ClaudeContextManager-5WPRJIIW.js.map → ClaudeContextManager-BN7RE5ZQ.js.map} +0 -0
  88. /package/dist/{ClaudeService-Z4KA7QOW.js.map → ClaudeService-DLYLJUPA.js.map} +0 -0
  89. /package/dist/{GitHubService-UAMH7DMF.js.map → GitHubService-FZHHBOFG.js.map} +0 -0
  90. /package/dist/{PromptTemplateManager-A52RUAMS.js.map → PromptTemplateManager-6HH3PVXV.js.map} +0 -0
  91. /package/dist/{SettingsManager-MTVX57WR.js.map → SettingsManager-I2LRCW2A.js.map} +0 -0
  92. /package/dist/{SettingsMigrationManager-AGIIIPDQ.js.map → SettingsMigrationManager-TJ7UWZG5.js.map} +0 -0
  93. /package/dist/{chunk-OAP6SASD.js.map → chunk-2CXREBLZ.js.map} +0 -0
  94. /package/dist/{chunk-FOV7RRQ2.js.map → chunk-2MAIX45J.js.map} +0 -0
  95. /package/dist/{chunk-GVICXJHW.js.map → chunk-5VK4NRSF.js.map} +0 -0
  96. /package/dist/{chunk-C7ASXK6J.js.map → chunk-AKUJXDNW.js.map} +0 -0
  97. /package/dist/{chunk-F4ENT6AC.js.map → chunk-M7JJCX53.js.map} +0 -0
  98. /package/dist/{chunk-KLBYVHPK.js.map → chunk-OSCLCMDG.js.map} +0 -0
  99. /package/dist/{chunk-ZLIHIUDQ.js.map → chunk-OYF4VIFI.js.map} +0 -0
  100. /package/dist/{chunk-A2P7NZTB.js.map → chunk-PGPI5LR4.js.map} +0 -0
  101. /package/dist/{chunk-UERERX6M.js.map → chunk-SUOXY5WJ.js.map} +0 -0
  102. /package/dist/{claude-KIZYXTSG.js.map → claude-W52VKI6L.js.map} +0 -0
  103. /package/dist/{cleanup-6WYUD5SN.js.map → cleanup-H4VXU3C3.js.map} +0 -0
  104. /package/dist/{color-ZVALX37U.js.map → color-F7RU6B6Z.js.map} +0 -0
  105. /package/dist/{contribute-7YJHZTO7.js.map → contribute-Y7IQV5QY.js.map} +0 -0
  106. /package/dist/{git-TAFVDB3J.js.map → git-IYA53VIC.js.map} +0 -0
  107. /package/dist/{neon-helpers-5HBYO2VP.js.map → init-4FHTAM3F.js.map} +0 -0
  108. /package/dist/{prompt-7INJ7YRU.js.map → neon-helpers-77PBPGJ5.js.map} +0 -0
  109. /package/dist/{open-FCHKQ77R.js.map → open-UMXANW5S.js.map} +0 -0
  110. /package/dist/{run-SJPM6YRI.js.map → run-MJYY4PUT.js.map} +0 -0
  111. /package/dist/{test-git-DEUE656D.js.map → test-git-IT5EWQ5C.js.map} +0 -0
  112. /package/dist/{test-prefix-Y6Z6ZHSF.js.map → test-prefix-NPWDPUUH.js.map} +0 -0
package/dist/cli.js CHANGED
@@ -4,8 +4,9 @@ import {
4
4
  DatabaseManager,
5
5
  EnvironmentManager,
6
6
  LoomManager,
7
+ MetadataManager,
7
8
  ResourceCleanup
8
- } from "./chunk-KG343GSG.js";
9
+ } from "./chunk-2IJEMXOB.js";
9
10
  import {
10
11
  IdentifierParser
11
12
  } from "./chunk-OXAM2WVC.js";
@@ -13,33 +14,37 @@ import {
13
14
  ProcessManager
14
15
  } from "./chunk-VU3QMIP2.js";
15
16
  import {
17
+ InitCommand,
16
18
  ShellCompletion
17
- } from "./chunk-PRE7KTM4.js";
19
+ } from "./chunk-UAN4A3YU.js";
18
20
  import {
19
21
  getConfiguredRepoFromSettings,
20
22
  getEffectivePRTargetRemote,
21
23
  hasMultipleRemotes,
22
24
  parseGitRemotes
23
25
  } from "./chunk-PA6Q6AWM.js";
26
+ import "./chunk-OSCLCMDG.js";
24
27
  import {
25
- IssueEnhancementService
26
- } from "./chunk-GOG3ZB7O.js";
28
+ IssueEnhancementService,
29
+ capitalizeFirstLetter
30
+ } from "./chunk-IFB4Z76W.js";
27
31
  import {
28
32
  openBrowser
29
33
  } from "./chunk-YETJNRQM.js";
30
34
  import {
31
35
  MergeManager
32
- } from "./chunk-FOV7RRQ2.js";
36
+ } from "./chunk-2MAIX45J.js";
33
37
  import {
38
+ FirstRunManager,
34
39
  IssueTrackerFactory,
35
40
  generateIssueManagementMcpConfig
36
- } from "./chunk-FXMLNKLT.js";
41
+ } from "./chunk-DLHA5VQ3.js";
37
42
  import {
38
43
  AgentManager
39
44
  } from "./chunk-OC4H6HJD.js";
40
45
  import {
41
46
  GitWorktreeManager
42
- } from "./chunk-OAP6SASD.js";
47
+ } from "./chunk-2CXREBLZ.js";
43
48
  import {
44
49
  detectPackageManager,
45
50
  installDependencies,
@@ -47,12 +52,12 @@ import {
47
52
  } from "./chunk-ZT3YZB4K.js";
48
53
  import {
49
54
  ClaudeContextManager
50
- } from "./chunk-C7ASXK6J.js";
51
- import "./chunk-A2P7NZTB.js";
52
- import "./chunk-WEN5C5DM.js";
55
+ } from "./chunk-AKUJXDNW.js";
56
+ import "./chunk-PGPI5LR4.js";
57
+ import "./chunk-RIEO2WML.js";
53
58
  import {
54
59
  DefaultBranchNamingService
55
- } from "./chunk-UERERX6M.js";
60
+ } from "./chunk-SUOXY5WJ.js";
56
61
  import {
57
62
  ProjectCapabilityDetector
58
63
  } from "./chunk-EBISESAP.js";
@@ -65,31 +70,33 @@ import {
65
70
  } from "./chunk-GYCR2LOU.js";
66
71
  import {
67
72
  createNeonProviderFromSettings
68
- } from "./chunk-GVICXJHW.js";
73
+ } from "./chunk-5VK4NRSF.js";
69
74
  import {
70
75
  executeGitCommand,
71
76
  extractIssueNumber,
72
77
  findMainWorktreePathWithSettings,
78
+ getRepoRoot,
73
79
  pushBranchToRemote
74
- } from "./chunk-5NTD4MCZ.js";
80
+ } from "./chunk-5Q3NDNNV.js";
75
81
  import {
76
82
  SettingsManager
77
- } from "./chunk-UCZ24SUE.js";
83
+ } from "./chunk-CDZERT7Z.js";
78
84
  import {
79
85
  GitHubService
80
- } from "./chunk-F4ENT6AC.js";
86
+ } from "./chunk-M7JJCX53.js";
81
87
  import {
82
88
  executeGhCommand
83
89
  } from "./chunk-3RUPPQRG.js";
84
90
  import {
91
+ promptCommitAction,
85
92
  promptConfirmation,
86
93
  waitForKeypress
87
- } from "./chunk-JKXJ7BGL.js";
88
- import "./chunk-ZZZWQGTS.js";
94
+ } from "./chunk-CE26YH2U.js";
95
+ import "./chunk-CFFQ2Z7A.js";
89
96
  import {
90
97
  detectClaudeCli,
91
98
  launchClaude
92
- } from "./chunk-ZLIHIUDQ.js";
99
+ } from "./chunk-OYF4VIFI.js";
93
100
  import "./chunk-RW54ZMBM.js";
94
101
  import {
95
102
  loadEnvIntoProcess
@@ -108,8 +115,25 @@ import path2 from "path";
108
115
  import { existsSync } from "fs";
109
116
  import { readFile } from "fs/promises";
110
117
  import path from "path";
118
+ async function getProjectRoot() {
119
+ const repoRoot = await getRepoRoot();
120
+ if (repoRoot) {
121
+ logger.debug(`getProjectRoot: Using git repo root: ${repoRoot}`);
122
+ return repoRoot;
123
+ }
124
+ const cwd = process.cwd();
125
+ logger.debug(`getProjectRoot: Not in git repo, using cwd: ${cwd}`);
126
+ return cwd;
127
+ }
111
128
  async function needsFirstRunSetup() {
112
- const iloomDir = path.join(process.cwd(), ".iloom");
129
+ const projectRoot = await getProjectRoot();
130
+ const firstRunManager = new FirstRunManager();
131
+ const { isConfigured } = await firstRunManager.fixupLegacyProject(projectRoot);
132
+ if (isConfigured) {
133
+ logger.debug("needsFirstRunSetup: Project is tracked as configured globally");
134
+ return false;
135
+ }
136
+ const iloomDir = path.join(projectRoot, ".iloom");
113
137
  if (!existsSync(iloomDir)) {
114
138
  return true;
115
139
  }
@@ -134,13 +158,17 @@ async function launchFirstRunSetup() {
134
158
  logger.info(
135
159
  "iloom will now launch an interactive configuration session with Claude."
136
160
  );
137
- const { waitForKeypress: waitForKeypress2 } = await import("./prompt-7INJ7YRU.js");
161
+ const { waitForKeypress: waitForKeypress2 } = await import("./prompt-QALMYTVC.js");
138
162
  await waitForKeypress2("Press any key to start configuration...");
139
- const { InitCommand } = await import("./init-7IIM35LQ.js");
140
163
  const initCommand = new InitCommand();
141
164
  await initCommand.execute(
142
165
  "Help me configure iloom settings for this project. This is my first time using iloom here. Note: Your iloom command will execute once we are done with configuration changes."
143
166
  );
167
+ const projectRoot = await getProjectRoot();
168
+ logger.debug(`Marking project as configured at root: ${projectRoot}`);
169
+ const firstRunManager = new FirstRunManager();
170
+ await firstRunManager.markProjectAsConfigured(projectRoot);
171
+ logger.debug(`Project marked as configured at root: ${projectRoot}`);
144
172
  logger.info("Configuration complete! Continuing with your original command...");
145
173
  }
146
174
 
@@ -222,7 +250,7 @@ var StartCommand = class {
222
250
  const parsed = await this.parseInput(input.identifier, repo);
223
251
  await this.validateInput(parsed, repo);
224
252
  if (parentLoom) {
225
- const { isInteractiveEnvironment, promptConfirmation: promptConfirmation2 } = await import("./prompt-7INJ7YRU.js");
253
+ const { isInteractiveEnvironment, promptConfirmation: promptConfirmation2 } = await import("./prompt-QALMYTVC.js");
226
254
  const parentDisplay = parentLoom.type === "issue" ? `issue #${parentLoom.identifier}` : parentLoom.type === "pr" ? `PR #${parentLoom.identifier}` : `branch ${parentLoom.identifier}`;
227
255
  if (input.options.childLoom === true) {
228
256
  logger.info(`Creating as child loom of ${parentDisplay} (--child-loom flag)`);
@@ -251,19 +279,20 @@ var StartCommand = class {
251
279
  }
252
280
  if (parsed.type === "description") {
253
281
  logger.info("Creating GitHub issue from description...");
254
- const body = input.options.body ?? "";
282
+ const title = capitalizeFirstLetter(parsed.originalInput);
283
+ const body = input.options.body ? capitalizeFirstLetter(input.options.body) : "";
255
284
  const result = await this.issueTracker.createIssue(
256
- parsed.originalInput,
257
- // Use description as title
285
+ title,
286
+ // Use capitalized description as title
258
287
  body
259
- // Use provided body or empty
288
+ // Use capitalized body or empty
260
289
  );
261
290
  logger.success(`Created issue #${result.number}: ${result.url}`);
262
291
  parsed.type = "issue";
263
292
  parsed.number = result.number;
264
293
  }
265
294
  if (input.options.oneShot === "bypassPermissions") {
266
- const { promptConfirmation: promptConfirmation2 } = await import("./prompt-7INJ7YRU.js");
295
+ const { promptConfirmation: promptConfirmation2 } = await import("./prompt-QALMYTVC.js");
267
296
  const confirmed = await promptConfirmation2(
268
297
  "\u26A0\uFE0F WARNING: bypassPermissions mode will allow Claude to execute all tool calls without confirmation. This can be dangerous. Do you want to proceed?"
269
298
  );
@@ -327,6 +356,7 @@ var StartCommand = class {
327
356
  * Parse input to determine type and extract relevant data
328
357
  */
329
358
  async parseInput(identifier, repo) {
359
+ const hasLeadingSpace = identifier.startsWith(" ");
330
360
  const trimmedIdentifier = identifier.trim();
331
361
  if (!trimmedIdentifier) {
332
362
  throw new Error("Missing required argument: identifier");
@@ -335,7 +365,7 @@ var StartCommand = class {
335
365
  if (trimmedIdentifier.length > 25 && spaceCount > 2) {
336
366
  return {
337
367
  type: "description",
338
- originalInput: trimmedIdentifier
368
+ originalInput: hasLeadingSpace ? " " + trimmedIdentifier : trimmedIdentifier
339
369
  };
340
370
  }
341
371
  const prPattern = /^pr[/-](\d+)$/i;
@@ -524,13 +554,17 @@ var AddIssueCommand = class {
524
554
  /**
525
555
  * Execute the add-issue command workflow:
526
556
  * 1. Validate description format
527
- * 2. Enhance description with Claude Code
557
+ * 2. Skip enhancement if body provided, otherwise enhance description with Claude Code
528
558
  * 3. Create GitHub issue
529
559
  * 4. Wait for keypress and open browser for review
530
560
  * 5. Return issue number
531
561
  */
532
562
  async execute(input) {
533
- const { description } = input;
563
+ const description = capitalizeFirstLetter(input.description);
564
+ const body = input.options.body ? capitalizeFirstLetter(input.options.body) : void 0;
565
+ if (process.env.FORCE_FIRST_TIME_SETUP === "true" || await needsFirstRunSetup()) {
566
+ await launchFirstRunSetup();
567
+ }
534
568
  const settings = await this.settingsManager.loadSettings();
535
569
  let repo;
536
570
  if (this.enhancementService.issueTracker.providerName === "github" && await hasMultipleRemotes()) {
@@ -540,10 +574,10 @@ var AddIssueCommand = class {
540
574
  if (!description || !this.enhancementService.validateDescription(description)) {
541
575
  throw new Error("Description is required and must be more than 30 characters with at least 3 words");
542
576
  }
543
- const enhancedDescription = await this.enhancementService.enhanceDescription(description);
577
+ const issueBody = body ?? await this.enhancementService.enhanceDescription(description);
544
578
  const result = await this.enhancementService.createEnhancedIssue(
545
579
  description,
546
- enhancedDescription,
580
+ issueBody,
547
581
  repo
548
582
  );
549
583
  await this.enhancementService.waitForReviewAndOpen(result.number);
@@ -570,6 +604,9 @@ var EnhanceCommand = class {
570
604
  async execute(input) {
571
605
  const { issueNumber, options } = input;
572
606
  const { author } = options;
607
+ if (process.env.FORCE_FIRST_TIME_SETUP === "true" || await needsFirstRunSetup()) {
608
+ await launchFirstRunSetup();
609
+ }
573
610
  const settings = await this.settingsManager.loadSettings();
574
611
  let repo;
575
612
  if (this.issueTracker.providerName === "github" && await hasMultipleRemotes()) {
@@ -1031,6 +1068,14 @@ Run '${runCommand}' to see detailed errors.`
1031
1068
  }
1032
1069
  };
1033
1070
 
1071
+ // src/types/index.ts
1072
+ var UserAbortedCommitError = class extends Error {
1073
+ constructor(message = "User aborted the commit") {
1074
+ super(message);
1075
+ this.name = "UserAbortedCommitError";
1076
+ }
1077
+ };
1078
+
1034
1079
  // src/lib/CommitManager.ts
1035
1080
  var CommitManager = class {
1036
1081
  /**
@@ -1089,19 +1134,34 @@ var CommitManager = class {
1089
1134
  }
1090
1135
  await executeGitCommand(commitArgs, { cwd: worktreePath });
1091
1136
  } else {
1092
- logger.info("Opening git editor for commit message review...");
1093
- const commitArgs = ["commit", "-e", "-m", message];
1094
- if (options.skipVerify) {
1095
- commitArgs.push("--no-verify");
1137
+ const action = await promptCommitAction(message);
1138
+ if (action === "abort") {
1139
+ throw new UserAbortedCommitError();
1140
+ }
1141
+ if (action === "accept") {
1142
+ const commitArgs = ["commit", "-m", message];
1143
+ if (options.skipVerify) {
1144
+ commitArgs.push("--no-verify");
1145
+ }
1146
+ await executeGitCommand(commitArgs, { cwd: worktreePath });
1147
+ } else {
1148
+ logger.info("Opening git editor for commit message review...");
1149
+ const commitArgs = ["commit", "-e", "-m", message];
1150
+ if (options.skipVerify) {
1151
+ commitArgs.push("--no-verify");
1152
+ }
1153
+ await executeGitCommand(commitArgs, {
1154
+ cwd: worktreePath,
1155
+ stdio: "inherit",
1156
+ timeout: 3e5
1157
+ // 5 minutes for interactive editing
1158
+ });
1096
1159
  }
1097
- await executeGitCommand(commitArgs, {
1098
- cwd: worktreePath,
1099
- stdio: "inherit",
1100
- timeout: 3e5
1101
- // 5 minutes for interactive editing
1102
- });
1103
1160
  }
1104
1161
  } catch (error) {
1162
+ if (error instanceof UserAbortedCommitError) {
1163
+ throw error;
1164
+ }
1105
1165
  if (error instanceof Error && error.message.includes("nothing to commit")) {
1106
1166
  logger.info("No changes to commit");
1107
1167
  return;
@@ -1721,7 +1781,7 @@ var FinishCommand = class {
1721
1781
  const neonProvider = createNeonProviderFromSettings(settings);
1722
1782
  const databaseManager = new DatabaseManager(neonProvider, environmentManager, databaseUrlEnvVarName);
1723
1783
  const cliIsolationManager = new CLIIsolationManager();
1724
- const { DefaultBranchNamingService: DefaultBranchNamingService2 } = await import("./BranchNamingService-JYO746H7.js");
1784
+ const { DefaultBranchNamingService: DefaultBranchNamingService2 } = await import("./BranchNamingService-A77VI6AI.js");
1725
1785
  this.loomManager ??= new LoomManager(
1726
1786
  this.gitWorktreeManager,
1727
1787
  this.issueTracker,
@@ -2075,8 +2135,16 @@ var FinishCommand = class {
2075
2135
  if (parsed.type === "issue" && parsed.number) {
2076
2136
  commitOptions.issueNumber = parsed.number;
2077
2137
  }
2078
- await this.commitManager.commitChanges(worktree.path, commitOptions);
2079
- logger.success("Changes committed successfully");
2138
+ try {
2139
+ await this.commitManager.commitChanges(worktree.path, commitOptions);
2140
+ logger.success("Changes committed successfully");
2141
+ } catch (error) {
2142
+ if (error instanceof UserAbortedCommitError) {
2143
+ logger.info("Commit aborted by user");
2144
+ return;
2145
+ }
2146
+ throw error;
2147
+ }
2080
2148
  }
2081
2149
  } else {
2082
2150
  logger.debug("No uncommitted changes found");
@@ -2145,12 +2213,20 @@ var FinishCommand = class {
2145
2213
  logger.info("Committing uncommitted changes...");
2146
2214
  const settings = await this.settingsManager.loadSettings(worktree.path);
2147
2215
  const skipVerify = ((_b = (_a = settings.workflows) == null ? void 0 : _a.pr) == null ? void 0 : _b.noVerify) ?? false;
2148
- await this.commitManager.commitChanges(worktree.path, {
2149
- dryRun: false,
2150
- skipVerify
2151
- // Do NOT pass issueNumber for PRs - no "Fixes #" trailer needed
2152
- });
2153
- logger.success("Changes committed");
2216
+ try {
2217
+ await this.commitManager.commitChanges(worktree.path, {
2218
+ dryRun: false,
2219
+ skipVerify
2220
+ // Do NOT pass issueNumber for PRs - no "Fixes #" trailer needed
2221
+ });
2222
+ logger.success("Changes committed");
2223
+ } catch (error) {
2224
+ if (error instanceof UserAbortedCommitError) {
2225
+ logger.info("Commit aborted by user");
2226
+ return;
2227
+ }
2228
+ throw error;
2229
+ }
2154
2230
  }
2155
2231
  } else {
2156
2232
  logger.debug("No uncommitted changes found");
@@ -2502,28 +2578,39 @@ function extractIssueNumbers(branch) {
2502
2578
  }
2503
2579
  return [issueNumber];
2504
2580
  }
2505
- function formatLoomForJson(worktree, mainWorktreePath) {
2506
- const loomType = determineLoomType(worktree);
2507
- let issueNumbers = [];
2508
- let prNumbers = [];
2509
- if (loomType === "pr") {
2510
- prNumbers = extractPRNumbers(worktree.path);
2511
- } else if (loomType === "issue") {
2512
- issueNumbers = extractIssueNumbers(worktree.branch);
2581
+ function formatLoomForJson(worktree, mainWorktreePath, metadata) {
2582
+ const loomType = (metadata == null ? void 0 : metadata.issueType) ?? determineLoomType(worktree);
2583
+ let issueNumbers;
2584
+ let prNumbers;
2585
+ if (metadata) {
2586
+ issueNumbers = metadata.issue_numbers;
2587
+ prNumbers = metadata.pr_numbers;
2588
+ } else {
2589
+ issueNumbers = [];
2590
+ prNumbers = [];
2591
+ if (loomType === "pr") {
2592
+ prNumbers = extractPRNumbers(worktree.path);
2593
+ } else if (loomType === "issue") {
2594
+ issueNumbers = extractIssueNumbers(worktree.branch);
2595
+ }
2513
2596
  }
2514
2597
  const isMainWorktree = mainWorktreePath ? worktree.path === mainWorktreePath : false;
2515
2598
  return {
2516
2599
  name: worktree.branch || worktree.path,
2517
2600
  worktreePath: worktree.bare ? null : worktree.path,
2518
- branch: worktree.branch || null,
2601
+ branch: ((metadata == null ? void 0 : metadata.branchName) ?? worktree.branch) || null,
2519
2602
  type: loomType,
2520
2603
  issue_numbers: issueNumbers,
2521
2604
  pr_numbers: prNumbers,
2522
- isMainWorktree
2605
+ isMainWorktree,
2606
+ description: (metadata == null ? void 0 : metadata.description) ?? null,
2607
+ created_at: (metadata == null ? void 0 : metadata.created_at) ?? null,
2608
+ issueTracker: (metadata == null ? void 0 : metadata.issueTracker) ?? null,
2609
+ colorHex: (metadata == null ? void 0 : metadata.colorHex) ?? null
2523
2610
  };
2524
2611
  }
2525
- function formatLoomsForJson(worktrees, mainWorktreePath) {
2526
- return worktrees.map((wt) => formatLoomForJson(wt, mainWorktreePath));
2612
+ function formatLoomsForJson(worktrees, mainWorktreePath, metadata) {
2613
+ return worktrees.map((wt) => formatLoomForJson(wt, mainWorktreePath, metadata == null ? void 0 : metadata.get(wt.path)));
2527
2614
  }
2528
2615
 
2529
2616
  // src/cli.ts
@@ -2551,7 +2638,7 @@ program.name("iloom").description(packageJson.description).version(packageJson.v
2551
2638
  } catch {
2552
2639
  }
2553
2640
  try {
2554
- const { SettingsMigrationManager } = await import("./SettingsMigrationManager-AGIIIPDQ.js");
2641
+ const { SettingsMigrationManager } = await import("./SettingsMigrationManager-TJ7UWZG5.js");
2555
2642
  const migrationManager = new SettingsMigrationManager();
2556
2643
  await migrationManager.migrateSettingsIfNeeded();
2557
2644
  } catch (error) {
@@ -2641,18 +2728,18 @@ async function autoLaunchInitForMultipleRemotes() {
2641
2728
  logger.info("iloom will now launch an interactive configuration session with Claude");
2642
2729
  logger.info("to help you select which remote to use for GitHub operations.");
2643
2730
  logger.info("");
2644
- const { waitForKeypress: waitForKeypress2 } = await import("./prompt-7INJ7YRU.js");
2731
+ const { waitForKeypress: waitForKeypress2 } = await import("./prompt-QALMYTVC.js");
2645
2732
  await waitForKeypress2("Press any key to start configuration...");
2646
2733
  logger.info("");
2647
2734
  try {
2648
- const { InitCommand } = await import("./init-7IIM35LQ.js");
2649
- const initCommand = new InitCommand();
2735
+ const { InitCommand: InitCommand2 } = await import("./init-4FHTAM3F.js");
2736
+ const initCommand = new InitCommand2();
2650
2737
  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.";
2651
2738
  await initCommand.execute(customInitialMessage);
2652
2739
  logger.info("");
2653
2740
  logger.info("Configuration complete! Continuing with your original command...");
2654
2741
  logger.info("");
2655
- const { SettingsManager: SettingsManager2 } = await import("./SettingsManager-MTVX57WR.js");
2742
+ const { SettingsManager: SettingsManager2 } = await import("./SettingsManager-I2LRCW2A.js");
2656
2743
  const settingsManager = new SettingsManager2();
2657
2744
  const settings = await settingsManager.loadSettings();
2658
2745
  const { hasMultipleRemotes: hasMultipleRemotes2 } = await import("./remote-VUNCQZ6J.js");
@@ -2677,7 +2764,7 @@ program.command("start").alias("new").alias("create").alias("up").description("C
2677
2764
  try {
2678
2765
  let finalIdentifier = identifier;
2679
2766
  if (!finalIdentifier) {
2680
- const { promptInput } = await import("./prompt-7INJ7YRU.js");
2767
+ const { promptInput } = await import("./prompt-QALMYTVC.js");
2681
2768
  finalIdentifier = await promptInput("Enter issue number, PR number (pr/123), or branch name");
2682
2769
  if (!(finalIdentifier == null ? void 0 : finalIdentifier.trim())) {
2683
2770
  logger.error("Identifier is required");
@@ -2694,7 +2781,7 @@ program.command("start").alias("new").alias("create").alias("up").description("C
2694
2781
  process.exit(1);
2695
2782
  }
2696
2783
  });
2697
- program.command("add-issue").alias("a").description("Create and enhance GitHub issue without starting workspace").argument("<description>", "Natural language description of the issue (>50 chars, >2 spaces)").action(async (description) => {
2784
+ program.command("add-issue").alias("a").description("Create and enhance GitHub issue without starting workspace").argument("<description>", "Natural language description of the issue (>50 chars, >2 spaces)").option("--body <text>", "Body text for issue (skips AI enhancement)").action(async (description, options) => {
2698
2785
  try {
2699
2786
  const settingsManager = new SettingsManager();
2700
2787
  const settings = await settingsManager.loadSettings();
@@ -2703,7 +2790,7 @@ program.command("add-issue").alias("a").description("Create and enhance GitHub i
2703
2790
  const command = new AddIssueCommand(enhancementService, settingsManager);
2704
2791
  const issueNumber = await command.execute({
2705
2792
  description,
2706
- options: {}
2793
+ options: options.body ? { body: options.body } : {}
2707
2794
  });
2708
2795
  logger.success(`Issue #${issueNumber} created successfully`);
2709
2796
  process.exit(0);
@@ -2714,7 +2801,7 @@ program.command("add-issue").alias("a").description("Create and enhance GitHub i
2714
2801
  });
2715
2802
  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) => {
2716
2803
  try {
2717
- const { FeedbackCommand } = await import("./feedback-752MGDPG.js");
2804
+ const { FeedbackCommand } = await import("./feedback-XTUCKJNT.js");
2718
2805
  const command = new FeedbackCommand();
2719
2806
  const feedbackOptions = {};
2720
2807
  if (options.body !== void 0) {
@@ -2765,7 +2852,7 @@ program.command("finish").alias("dn").description("Merge work and cleanup worksp
2765
2852
  });
2766
2853
  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) => {
2767
2854
  try {
2768
- const { RebaseCommand } = await import("./rebase-Q7WXK566.js");
2855
+ const { RebaseCommand } = await import("./rebase-VJ2VKR6R.js");
2769
2856
  const command = new RebaseCommand();
2770
2857
  await command.execute(options);
2771
2858
  } catch (error) {
@@ -2777,7 +2864,7 @@ program.command("spin").alias("ignite").description("Launch Claude with auto-det
2777
2864
  new Option("--one-shot <mode>", "One-shot automation mode").choices(["default", "noReview", "bypassPermissions"]).default("default")
2778
2865
  ).action(async (options) => {
2779
2866
  try {
2780
- const { IgniteCommand } = await import("./ignite-OAMDUN27.js");
2867
+ const { IgniteCommand } = await import("./ignite-T74RYXCA.js");
2781
2868
  const command = new IgniteCommand();
2782
2869
  await command.execute(options.oneShot ?? "default");
2783
2870
  } catch (error) {
@@ -2788,7 +2875,7 @@ program.command("spin").alias("ignite").description("Launch Claude with auto-det
2788
2875
  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) => {
2789
2876
  try {
2790
2877
  const args = (command == null ? void 0 : command.args) ? command.args.slice(identifier ? 1 : 0) : [];
2791
- const { OpenCommand } = await import("./open-FCHKQ77R.js");
2878
+ const { OpenCommand } = await import("./open-UMXANW5S.js");
2792
2879
  const cmd = new OpenCommand();
2793
2880
  const input = identifier ? { identifier, args } : { args };
2794
2881
  await cmd.execute(input);
@@ -2800,7 +2887,7 @@ program.command("open").description("Open workspace in browser or run CLI tool")
2800
2887
  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) => {
2801
2888
  try {
2802
2889
  const args = (command == null ? void 0 : command.args) ? command.args.slice(identifier ? 1 : 0) : [];
2803
- const { RunCommand } = await import("./run-SJPM6YRI.js");
2890
+ const { RunCommand } = await import("./run-MJYY4PUT.js");
2804
2891
  const cmd = new RunCommand();
2805
2892
  const input = identifier ? { identifier, args } : { args };
2806
2893
  await cmd.execute(input);
@@ -2811,7 +2898,7 @@ program.command("run").description("Run CLI tool or open workspace in browser").
2811
2898
  });
2812
2899
  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").action(async (identifier, options) => {
2813
2900
  try {
2814
- const { CleanupCommand } = await import("./cleanup-6WYUD5SN.js");
2901
+ const { CleanupCommand } = await import("./cleanup-H4VXU3C3.js");
2815
2902
  const command = new CleanupCommand();
2816
2903
  const input = {
2817
2904
  options: options ?? {}
@@ -2828,10 +2915,16 @@ program.command("cleanup").alias("remove").alias("clean").description("Remove wo
2828
2915
  program.command("list").description("Show active workspaces").option("--json", "Output as JSON").action(async (options) => {
2829
2916
  try {
2830
2917
  const manager = new GitWorktreeManager();
2918
+ const metadataManager = new MetadataManager();
2831
2919
  const worktrees = await manager.listWorktrees({ porcelain: true });
2920
+ const metadata = /* @__PURE__ */ new Map();
2921
+ for (const worktree of worktrees) {
2922
+ const loomMetadata = await metadataManager.readMetadata(worktree.path);
2923
+ metadata.set(worktree.path, loomMetadata);
2924
+ }
2832
2925
  if (options.json) {
2833
2926
  const mainWorktreePath = await findMainWorktreePathWithSettings();
2834
- console.log(JSON.stringify(formatLoomsForJson(worktrees, mainWorktreePath), null, 2));
2927
+ console.log(JSON.stringify(formatLoomsForJson(worktrees, mainWorktreePath, metadata), null, 2));
2835
2928
  return;
2836
2929
  }
2837
2930
  if (worktrees.length === 0) {
@@ -2841,7 +2934,11 @@ program.command("list").description("Show active workspaces").option("--json", "
2841
2934
  logger.info("Active workspaces:");
2842
2935
  for (const worktree of worktrees) {
2843
2936
  const formatted = manager.formatWorktree(worktree);
2937
+ const loomMetadata = metadata.get(worktree.path);
2844
2938
  logger.info(` ${formatted.title}`);
2939
+ if (loomMetadata == null ? void 0 : loomMetadata.description) {
2940
+ logger.info(` Description: ${loomMetadata.description}`);
2941
+ }
2845
2942
  logger.info(` Path: ${formatted.path}`);
2846
2943
  logger.info(` Commit: ${formatted.commit}`);
2847
2944
  }
@@ -2860,8 +2957,8 @@ program.command("list").description("Show active workspaces").option("--json", "
2860
2957
  });
2861
2958
  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) => {
2862
2959
  try {
2863
- const { InitCommand } = await import("./init-7IIM35LQ.js");
2864
- const command = new InitCommand();
2960
+ const { InitCommand: InitCommand2 } = await import("./init-4FHTAM3F.js");
2961
+ const command = new InitCommand2();
2865
2962
  const trimmedPrompt = prompt == null ? void 0 : prompt.trim();
2866
2963
  const customPrompt = trimmedPrompt && trimmedPrompt.length > 0 ? trimmedPrompt : void 0;
2867
2964
  await command.execute(customPrompt);
@@ -2872,7 +2969,7 @@ program.command("init").alias("config").description("Initialize iloom configurat
2872
2969
  });
2873
2970
  program.command("contribute").description("Set up local development environment for contributing to iloom").action(async () => {
2874
2971
  try {
2875
- const { ContributeCommand } = await import("./contribute-7YJHZTO7.js");
2972
+ const { ContributeCommand } = await import("./contribute-Y7IQV5QY.js");
2876
2973
  const command = new ContributeCommand();
2877
2974
  await command.execute();
2878
2975
  } catch (error) {
@@ -2892,8 +2989,8 @@ program.command("update").description("Update iloom-cli to the latest version").
2892
2989
  });
2893
2990
  program.command("test-github").description("Test GitHub integration (Issue #3)").argument("<identifier>", "Issue number or PR number").option("--no-claude", "Skip Claude for branch name generation").action(async (identifier, options) => {
2894
2991
  try {
2895
- const { GitHubService: GitHubService2 } = await import("./GitHubService-UAMH7DMF.js");
2896
- const { DefaultBranchNamingService: DefaultBranchNamingService2 } = await import("./BranchNamingService-JYO746H7.js");
2992
+ const { GitHubService: GitHubService2 } = await import("./GitHubService-FZHHBOFG.js");
2993
+ const { DefaultBranchNamingService: DefaultBranchNamingService2 } = await import("./BranchNamingService-A77VI6AI.js");
2897
2994
  logger.info("Testing GitHub Integration\n");
2898
2995
  const service = new GitHubService2();
2899
2996
  const branchNaming = new DefaultBranchNamingService2({ useClaude: options.claude !== false });
@@ -2951,10 +3048,10 @@ program.command("test-github").description("Test GitHub integration (Issue #3)")
2951
3048
  });
2952
3049
  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) => {
2953
3050
  try {
2954
- const { detectClaudeCli: detectClaudeCli2, getClaudeVersion, generateBranchName, launchClaude: launchClaude2 } = await import("./claude-KIZYXTSG.js");
2955
- const { PromptTemplateManager } = await import("./PromptTemplateManager-A52RUAMS.js");
2956
- const { ClaudeService } = await import("./ClaudeService-Z4KA7QOW.js");
2957
- const { ClaudeContextManager: ClaudeContextManager2 } = await import("./ClaudeContextManager-5WPRJIIW.js");
3051
+ const { detectClaudeCli: detectClaudeCli2, getClaudeVersion, generateBranchName, launchClaude: launchClaude2 } = await import("./claude-W52VKI6L.js");
3052
+ const { PromptTemplateManager } = await import("./PromptTemplateManager-6HH3PVXV.js");
3053
+ const { ClaudeService } = await import("./ClaudeService-DLYLJUPA.js");
3054
+ const { ClaudeContextManager: ClaudeContextManager2 } = await import("./ClaudeContextManager-BN7RE5ZQ.js");
2958
3055
  logger.info("Testing Claude Integration\n");
2959
3056
  if (options.detect) {
2960
3057
  logger.info("Detecting Claude CLI...");
@@ -3102,7 +3199,7 @@ program.command("test-webserver").description("Test if a web server is running o
3102
3199
  });
3103
3200
  program.command("test-git").description("Test Git integration - findMainWorktreePath() function (reads .iloom/settings.json)").action(async () => {
3104
3201
  try {
3105
- const { TestGitCommand } = await import("./test-git-DEUE656D.js");
3202
+ const { TestGitCommand } = await import("./test-git-IT5EWQ5C.js");
3106
3203
  const command = new TestGitCommand();
3107
3204
  await command.execute();
3108
3205
  } catch (error) {
@@ -3128,7 +3225,7 @@ program.command("test-tabs").description("Test iTerm2 dual tab functionality - o
3128
3225
  });
3129
3226
  program.command("test-prefix").description("Test worktree prefix configuration - preview worktree paths (reads .iloom/settings.json)").action(async () => {
3130
3227
  try {
3131
- const { TestPrefixCommand } = await import("./test-prefix-Y6Z6ZHSF.js");
3228
+ const { TestPrefixCommand } = await import("./test-prefix-NPWDPUUH.js");
3132
3229
  const command = new TestPrefixCommand();
3133
3230
  await command.execute();
3134
3231
  } catch (error) {
@@ -3142,8 +3239,8 @@ program.command("test-prefix").description("Test worktree prefix configuration -
3142
3239
  program.command("test-neon").description("Test Neon integration and debug configuration").action(async () => {
3143
3240
  var _a;
3144
3241
  try {
3145
- const { SettingsManager: SettingsManager2 } = await import("./SettingsManager-MTVX57WR.js");
3146
- const { createNeonProviderFromSettings: createNeonProviderFromSettings2 } = await import("./neon-helpers-5HBYO2VP.js");
3242
+ const { SettingsManager: SettingsManager2 } = await import("./SettingsManager-I2LRCW2A.js");
3243
+ const { createNeonProviderFromSettings: createNeonProviderFromSettings2 } = await import("./neon-helpers-77PBPGJ5.js");
3147
3244
  logger.info("Testing Neon Integration\n");
3148
3245
  logger.info("1. Settings Configuration:");
3149
3246
  const settingsManager = new SettingsManager2();