@iloom/cli 0.1.17 → 0.1.19

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 (118) hide show
  1. package/README.md +51 -6
  2. package/dist/ClaudeContextManager-JKR4WGNU.js +13 -0
  3. package/dist/ClaudeService-55DQGB7T.js +12 -0
  4. package/dist/{GitHubService-F7Z3XJOS.js → GitHubService-LWP4GKGH.js} +3 -3
  5. package/dist/{LoomLauncher-MODG2SEM.js → LoomLauncher-UMMLPIZO.js} +7 -7
  6. package/dist/{PromptTemplateManager-7FINLRDE.js → PromptTemplateManager-WII75TKH.js} +2 -2
  7. package/dist/README.md +755 -0
  8. package/dist/{SettingsManager-VAZF26S2.js → SettingsManager-SKLUVE3K.js} +6 -2
  9. package/dist/{add-issue-22JBNOML.js → add-issue-X56V3XPB.js} +23 -8
  10. package/dist/add-issue-X56V3XPB.js.map +1 -0
  11. package/dist/{chunk-Y7SAGNUT.js → chunk-DEPYQRRB.js} +2 -2
  12. package/dist/{chunk-WKEWRSDB.js → chunk-ELFT36PV.js} +3 -3
  13. package/dist/chunk-FXV24OYZ.js +83 -0
  14. package/dist/chunk-FXV24OYZ.js.map +1 -0
  15. package/dist/{chunk-HPJJSYNS.js → chunk-H5LDRGVK.js} +6 -8
  16. package/dist/{chunk-HPJJSYNS.js.map → chunk-H5LDRGVK.js.map} +1 -1
  17. package/dist/{chunk-QEPVTTHD.js → chunk-IO4WFTL2.js} +17 -11
  18. package/dist/chunk-IO4WFTL2.js.map +1 -0
  19. package/dist/{chunk-KQDEK2ZW.js → chunk-JXQXSC45.js} +41 -9
  20. package/dist/chunk-JXQXSC45.js.map +1 -0
  21. package/dist/{chunk-JQ7VOSTC.js → chunk-KOCQAD2E.js} +3 -3
  22. package/dist/{chunk-YYSKGAZT.js → chunk-LAPY6NAE.js} +17 -8
  23. package/dist/chunk-LAPY6NAE.js.map +1 -0
  24. package/dist/{chunk-O2QWO64Z.js → chunk-PV3GAXQO.js} +56 -3
  25. package/dist/chunk-PV3GAXQO.js.map +1 -0
  26. package/dist/chunk-PVAVNJKS.js +188 -0
  27. package/dist/chunk-PVAVNJKS.js.map +1 -0
  28. package/dist/{chunk-CP2NU2JC.js → chunk-Q2KYPAH2.js} +7 -7
  29. package/dist/{chunk-CP2NU2JC.js.map → chunk-Q2KYPAH2.js.map} +1 -1
  30. package/dist/{chunk-W3DQTW63.js → chunk-USVVV3FP.js} +4 -4
  31. package/dist/{chunk-SSR5AVRJ.js → chunk-VCMMAFXQ.js} +21 -8
  32. package/dist/chunk-VCMMAFXQ.js.map +1 -0
  33. package/dist/chunk-VVH3ANF2.js +307 -0
  34. package/dist/chunk-VVH3ANF2.js.map +1 -0
  35. package/dist/{chunk-JBH2ZYYZ.js → chunk-VYQLLHZ7.js} +22 -3
  36. package/dist/chunk-VYQLLHZ7.js.map +1 -0
  37. package/dist/{chunk-SJUQ2NDR.js → chunk-ZMNQBJUI.js} +24 -19
  38. package/dist/chunk-ZMNQBJUI.js.map +1 -0
  39. package/dist/{chunk-T7QPXANZ.js → chunk-ZWXJBSUW.js} +17 -17
  40. package/dist/chunk-ZWXJBSUW.js.map +1 -0
  41. package/dist/{cleanup-3LUWPSM7.js → cleanup-ZHROIBSQ.js} +12 -16
  42. package/dist/cleanup-ZHROIBSQ.js.map +1 -0
  43. package/dist/cli.js +107 -49
  44. package/dist/cli.js.map +1 -1
  45. package/dist/contribute-3MQJ3XAQ.js +256 -0
  46. package/dist/contribute-3MQJ3XAQ.js.map +1 -0
  47. package/dist/{enhance-XJIQHVPD.js → enhance-VGWUX474.js} +18 -8
  48. package/dist/enhance-VGWUX474.js.map +1 -0
  49. package/dist/{feedback-23CLXKFT.js → feedback-ZOUCCHN4.js} +8 -8
  50. package/dist/{finish-3CQZIULO.js → finish-QJSK6Z7J.js} +36 -313
  51. package/dist/finish-QJSK6Z7J.js.map +1 -0
  52. package/dist/{git-LVRZ57GJ.js → git-OUYMVYJX.js} +2 -2
  53. package/dist/{ignite-WXEF2ID5.js → ignite-HICLZEYU.js} +124 -9
  54. package/dist/ignite-HICLZEYU.js.map +1 -0
  55. package/dist/index.d.ts +794 -712
  56. package/dist/index.js +169 -36
  57. package/dist/index.js.map +1 -1
  58. package/dist/init-UMKNHNV5.js +339 -0
  59. package/dist/init-UMKNHNV5.js.map +1 -0
  60. package/dist/mcp/github-comment-server.js +12 -9
  61. package/dist/mcp/github-comment-server.js.map +1 -1
  62. package/dist/neon-helpers-ZVIRPKCI.js +10 -0
  63. package/dist/{open-X6BTENPV.js → open-ETZUFSE4.js} +15 -17
  64. package/dist/{open-X6BTENPV.js.map → open-ETZUFSE4.js.map} +1 -1
  65. package/dist/prompts/init-prompt.txt +748 -0
  66. package/dist/prompts/issue-prompt.txt +141 -9
  67. package/dist/rebase-KBWFDZCN.js +95 -0
  68. package/dist/rebase-KBWFDZCN.js.map +1 -0
  69. package/dist/remote-GJEZWRCC.js +14 -0
  70. package/dist/{run-2JCPQAX3.js → run-4SVQ3WEU.js} +15 -17
  71. package/dist/{run-2JCPQAX3.js.map → run-4SVQ3WEU.js.map} +1 -1
  72. package/dist/schema/settings.schema.json +51 -1
  73. package/dist/{start-LWVRBJ6S.js → start-CT2ZEFP2.js} +54 -53
  74. package/dist/{start-LWVRBJ6S.js.map → start-CT2ZEFP2.js.map} +1 -1
  75. package/dist/{test-git-XPF4SZXJ.js → test-git-MKZATGZN.js} +3 -3
  76. package/dist/{test-prefix-XGFXFAYN.js → test-prefix-ZNLWDI3K.js} +3 -3
  77. package/dist/{update-DN3FSNKY.js → update-4TDDUR5K.js} +10 -4
  78. package/dist/{update-DN3FSNKY.js.map → update-4TDDUR5K.js.map} +1 -1
  79. package/package.json +3 -2
  80. package/dist/ClaudeContextManager-XOSXQ67R.js +0 -13
  81. package/dist/ClaudeService-YSZ6EXWP.js +0 -12
  82. package/dist/NeonProvider-PAGPUH7F.js +0 -12
  83. package/dist/add-issue-22JBNOML.js.map +0 -1
  84. package/dist/chunk-37DYYFVK.js +0 -29
  85. package/dist/chunk-37DYYFVK.js.map +0 -1
  86. package/dist/chunk-F3XBU2R7.js +0 -110
  87. package/dist/chunk-F3XBU2R7.js.map +0 -1
  88. package/dist/chunk-JBH2ZYYZ.js.map +0 -1
  89. package/dist/chunk-KQDEK2ZW.js.map +0 -1
  90. package/dist/chunk-O2QWO64Z.js.map +0 -1
  91. package/dist/chunk-QEPVTTHD.js.map +0 -1
  92. package/dist/chunk-SJUQ2NDR.js.map +0 -1
  93. package/dist/chunk-SSR5AVRJ.js.map +0 -1
  94. package/dist/chunk-T7QPXANZ.js.map +0 -1
  95. package/dist/chunk-YYSKGAZT.js.map +0 -1
  96. package/dist/cleanup-3LUWPSM7.js.map +0 -1
  97. package/dist/enhance-XJIQHVPD.js.map +0 -1
  98. package/dist/env-MDFL4ZXL.js +0 -23
  99. package/dist/finish-3CQZIULO.js.map +0 -1
  100. package/dist/ignite-WXEF2ID5.js.map +0 -1
  101. package/dist/init-RHACUR4E.js +0 -123
  102. package/dist/init-RHACUR4E.js.map +0 -1
  103. /package/dist/{ClaudeContextManager-XOSXQ67R.js.map → ClaudeContextManager-JKR4WGNU.js.map} +0 -0
  104. /package/dist/{ClaudeService-YSZ6EXWP.js.map → ClaudeService-55DQGB7T.js.map} +0 -0
  105. /package/dist/{GitHubService-F7Z3XJOS.js.map → GitHubService-LWP4GKGH.js.map} +0 -0
  106. /package/dist/{LoomLauncher-MODG2SEM.js.map → LoomLauncher-UMMLPIZO.js.map} +0 -0
  107. /package/dist/{NeonProvider-PAGPUH7F.js.map → PromptTemplateManager-WII75TKH.js.map} +0 -0
  108. /package/dist/{PromptTemplateManager-7FINLRDE.js.map → SettingsManager-SKLUVE3K.js.map} +0 -0
  109. /package/dist/{chunk-Y7SAGNUT.js.map → chunk-DEPYQRRB.js.map} +0 -0
  110. /package/dist/{chunk-WKEWRSDB.js.map → chunk-ELFT36PV.js.map} +0 -0
  111. /package/dist/{chunk-JQ7VOSTC.js.map → chunk-KOCQAD2E.js.map} +0 -0
  112. /package/dist/{chunk-W3DQTW63.js.map → chunk-USVVV3FP.js.map} +0 -0
  113. /package/dist/{feedback-23CLXKFT.js.map → feedback-ZOUCCHN4.js.map} +0 -0
  114. /package/dist/{SettingsManager-VAZF26S2.js.map → git-OUYMVYJX.js.map} +0 -0
  115. /package/dist/{env-MDFL4ZXL.js.map → neon-helpers-ZVIRPKCI.js.map} +0 -0
  116. /package/dist/{git-LVRZ57GJ.js.map → remote-GJEZWRCC.js.map} +0 -0
  117. /package/dist/{test-git-XPF4SZXJ.js.map → test-git-MKZATGZN.js.map} +0 -0
  118. /package/dist/{test-prefix-XGFXFAYN.js.map → test-prefix-ZNLWDI3K.js.map} +0 -0
package/dist/index.d.ts CHANGED
@@ -123,683 +123,6 @@ interface WorktreeCleanupOptions {
123
123
  dryRun?: boolean;
124
124
  }
125
125
 
126
- /**
127
- * Manages Git worktrees for the iloom CLI
128
- * Ports functionality from bash scripts into TypeScript
129
- */
130
- declare class GitWorktreeManager {
131
- private readonly _workingDirectory;
132
- constructor(workingDirectory?: string);
133
- /**
134
- * Get the working directory for git operations (main worktree path)
135
- */
136
- get workingDirectory(): string;
137
- /**
138
- * List all worktrees in the repository
139
- * Defaults to porcelain format for reliable machine parsing
140
- * Equivalent to: git worktree list --porcelain
141
- */
142
- listWorktrees(options?: WorktreeListOptions): Promise<GitWorktree[]>;
143
- /**
144
- * Find worktree for a specific branch
145
- * Ports: find_worktree_for_branch() from find-worktree-for-branch.sh
146
- */
147
- findWorktreeForBranch(branchName: string): Promise<GitWorktree | null>;
148
- /**
149
- * Check if a worktree is the main repository worktree
150
- * The main worktree is the first one listed by git worktree list (Git guarantee)
151
- * This cannot be determined by path comparison because --show-toplevel returns
152
- * the same value for all worktrees.
153
- */
154
- isMainWorktree(worktree: GitWorktree): Promise<boolean>;
155
- /**
156
- * Check if a worktree is a PR worktree based on naming patterns
157
- * Ports: is_pr_worktree() from worktree-utils.sh
158
- */
159
- isPRWorktree(worktree: GitWorktree): boolean;
160
- /**
161
- * Get PR number from worktree branch name
162
- * Ports: get_pr_number_from_worktree() from worktree-utils.sh
163
- */
164
- getPRNumberFromWorktree(worktree: GitWorktree): number | null;
165
- /**
166
- * Create a new worktree
167
- * Ports worktree creation logic from new-branch-workflow.sh
168
- * @returns The absolute path to the created worktree
169
- */
170
- createWorktree(options: WorktreeCreateOptions): Promise<string>;
171
- /**
172
- * Remove a worktree and optionally clean up associated files
173
- * Ports worktree removal logic from cleanup-worktree.sh
174
- * @returns A message describing what was done (for dry-run mode)
175
- */
176
- removeWorktree(worktreePath: string, options?: WorktreeCleanupOptions): Promise<string | void>;
177
- /**
178
- * Validate worktree state and integrity
179
- */
180
- validateWorktree(worktreePath: string): Promise<WorktreeValidation>;
181
- /**
182
- * Get detailed status information for a worktree
183
- */
184
- getWorktreeStatus(worktreePath: string): Promise<WorktreeStatus>;
185
- /**
186
- * Generate a suggested worktree path for a branch
187
- */
188
- generateWorktreePath(branchName: string, customRoot?: string, options?: {
189
- isPR?: boolean;
190
- prNumber?: number;
191
- prefix?: string;
192
- }): string;
193
- /**
194
- * Sanitize a branch name for use as a directory name
195
- * Replaces slashes with dashes and removes invalid filesystem characters
196
- * Ports logic from bash script line 593: ${BRANCH_NAME//\\//-}
197
- */
198
- sanitizeBranchName(branchName: string): string;
199
- /**
200
- * Check if repository is in a valid state for worktree operations
201
- */
202
- isRepoReady(): Promise<boolean>;
203
- /**
204
- * Get repository information
205
- */
206
- getRepoInfo(): Promise<{
207
- root: string | null;
208
- defaultBranch: string;
209
- currentBranch: string | null;
210
- }>;
211
- /**
212
- * Prune stale worktree entries (worktrees that no longer exist on disk)
213
- */
214
- pruneWorktrees(): Promise<void>;
215
- /**
216
- * Lock a worktree to prevent it from being pruned or moved
217
- */
218
- lockWorktree(worktreePath: string, reason?: string): Promise<void>;
219
- /**
220
- * Unlock a previously locked worktree
221
- */
222
- unlockWorktree(worktreePath: string): Promise<void>;
223
- /**
224
- * Find worktrees matching an identifier (branch name, path, or PR number)
225
- */
226
- findWorktreesByIdentifier(identifier: string): Promise<GitWorktree[]>;
227
- /**
228
- * Find worktree for a specific issue number using exact pattern matching
229
- * Matches: issue-{N} at start OR after /, -, _ (but NOT issue-{N}X where X is a digit)
230
- * Supports patterns like: issue-44, feat/issue-44-feature, feat-issue-44, bugfix_issue-44, etc.
231
- * Avoids false matches like: tissue-44, myissue-44
232
- * Ports: find_existing_worktree() from bash script lines 131-165
233
- */
234
- findWorktreeForIssue(issueNumber: number): Promise<GitWorktree | null>;
235
- /**
236
- * Find worktree for a specific PR by branch name
237
- * Ports: find_existing_worktree() for PR type from bash script lines 149-160
238
- */
239
- findWorktreeForPR(prNumber: number, branchName: string): Promise<GitWorktree | null>;
240
- /**
241
- * Remove multiple worktrees
242
- * Returns a summary of successes and failures
243
- * Automatically filters out the main worktree
244
- */
245
- removeWorktrees(worktrees: GitWorktree[], options?: WorktreeCleanupOptions): Promise<{
246
- successes: Array<{
247
- worktree: GitWorktree;
248
- }>;
249
- failures: Array<{
250
- worktree: GitWorktree;
251
- error: string;
252
- }>;
253
- skipped: Array<{
254
- worktree: GitWorktree;
255
- reason: string;
256
- }>;
257
- }>;
258
- /**
259
- * Format worktree information for display
260
- */
261
- formatWorktree(worktree: GitWorktree): {
262
- title: string;
263
- path: string;
264
- commit: string;
265
- };
266
- }
267
-
268
- interface EnvVariable {
269
- key: string;
270
- value: string;
271
- }
272
- interface EnvFileOptions {
273
- path: string;
274
- backup?: boolean;
275
- encoding?: BufferEncoding;
276
- }
277
- /**
278
- * @deprecated Use exception-based error handling instead
279
- */
280
- interface EnvOperationResult {
281
- success: boolean;
282
- backupPath?: string;
283
- error?: string;
284
- }
285
- interface PortAssignmentOptions {
286
- basePort?: number;
287
- issueNumber?: number;
288
- prNumber?: number;
289
- branchName?: string;
290
- }
291
-
292
- type ProjectCapability = 'cli' | 'web';
293
- type Capability = ProjectCapability;
294
- interface Loom {
295
- id: string;
296
- path: string;
297
- branch: string;
298
- type: 'issue' | 'pr' | 'branch';
299
- identifier: string | number;
300
- port: number;
301
- databaseBranch?: string;
302
- createdAt: Date;
303
- lastAccessed: Date;
304
- githubData?: {
305
- title?: string;
306
- body?: string;
307
- url?: string;
308
- state?: string;
309
- };
310
- capabilities?: ProjectCapability[];
311
- binEntries?: Record<string, string>;
312
- cliSymlinks?: string[];
313
- }
314
- interface CreateLoomInput {
315
- type: 'issue' | 'pr' | 'branch';
316
- identifier: string | number;
317
- originalInput: string;
318
- baseBranch?: string;
319
- options?: {
320
- skipDatabase?: boolean;
321
- skipColorSync?: boolean;
322
- enableClaude?: boolean;
323
- enableCode?: boolean;
324
- enableDevServer?: boolean;
325
- enableTerminal?: boolean;
326
- oneShot?: OneShotMode;
327
- setArguments?: string[];
328
- executablePath?: string;
329
- };
330
- }
331
- type LaunchMode = 'editor' | 'terminal' | 'both';
332
- interface LoomSummary {
333
- id: string;
334
- type: 'issue' | 'pr' | 'branch';
335
- identifier: string | number;
336
- title?: string;
337
- branch: string;
338
- port: number;
339
- status: 'active' | 'stale' | 'error';
340
- lastAccessed: string;
341
- }
342
-
343
- /**
344
- * Options for ResourceCleanup operations
345
- */
346
- interface ResourceCleanupOptions {
347
- /** Preview operations without executing */
348
- dryRun?: boolean;
349
- /** Skip confirmations and safety checks */
350
- force?: boolean;
351
- /** Delete the associated branch */
352
- deleteBranch?: boolean;
353
- /** Keep database branch instead of deleting */
354
- keepDatabase?: boolean;
355
- /** Prompt for confirmation before operations */
356
- interactive?: boolean;
357
- }
358
- /**
359
- * Result of a cleanup operation
360
- */
361
- interface CleanupResult {
362
- /** Identifier that was cleaned up */
363
- identifier: string;
364
- /** Actual branch name that was found (will differ from identifier) */
365
- branchName?: string;
366
- /** Overall success status */
367
- success: boolean;
368
- /** Individual operation results */
369
- operations: OperationResult[];
370
- /** Errors encountered during cleanup */
371
- errors: Error[];
372
- /** Whether rollback is required */
373
- rollbackRequired?: boolean;
374
- }
375
- /**
376
- * Result of an individual cleanup operation
377
- */
378
- interface OperationResult {
379
- /** Type of operation performed */
380
- type: 'dev-server' | 'worktree' | 'branch' | 'database' | 'cli-symlinks';
381
- /** Whether operation succeeded */
382
- success: boolean;
383
- /** Human-readable message */
384
- message: string;
385
- /** Error message if operation failed */
386
- error?: string;
387
- /** For database operations: whether branch was actually deleted (vs not found) */
388
- deleted?: boolean;
389
- }
390
- /**
391
- * Safety check result
392
- */
393
- interface SafetyCheck {
394
- /** Whether cleanup is safe to proceed */
395
- isSafe: boolean;
396
- /** Non-blocking warnings */
397
- warnings: string[];
398
- /** Blocking issues that prevent cleanup */
399
- blockers: string[];
400
- }
401
- /**
402
- * Options for branch deletion
403
- */
404
- interface BranchDeleteOptions {
405
- /** Force delete unmerged branch */
406
- force?: boolean;
407
- /** Also delete remote branch */
408
- remote?: boolean;
409
- /** Preview without executing */
410
- dryRun?: boolean;
411
- }
412
- /**
413
- * Target for batch cleanup - represents a branch that may or may not have a worktree
414
- */
415
- interface BranchCleanupTarget {
416
- /** Branch name */
417
- branchName: string;
418
- /** Whether this branch has an associated worktree */
419
- hasWorktree: boolean;
420
- /** Path to worktree if it exists */
421
- worktreePath?: string;
422
- }
423
- /**
424
- * Result of batch cleanup operation for an issue
425
- */
426
- interface BatchCleanupResult {
427
- /** Issue number that was cleaned up */
428
- issueNumber: number;
429
- /** Number of branches found matching the issue */
430
- targetsFound: number;
431
- /** Number of worktrees successfully removed */
432
- worktreesRemoved: number;
433
- /** Number of branches successfully deleted */
434
- branchesDeleted: number;
435
- /** Number of failed operations */
436
- failed: number;
437
- /** Individual cleanup results for each branch */
438
- results: CleanupResult[];
439
- }
440
-
441
- /**
442
- * Information about a running process
443
- */
444
- interface ProcessInfo {
445
- /** Process ID */
446
- pid: number;
447
- /** Process name (e.g., "node", "pnpm") */
448
- name: string;
449
- /** Full command line */
450
- command: string;
451
- /** Port the process is listening on */
452
- port: number;
453
- /** Whether this appears to be a dev server */
454
- isDevServer: boolean;
455
- }
456
-
457
- interface Workspace {
458
- id: string;
459
- path: string;
460
- branch: string;
461
- issueNumber?: number;
462
- prNumber?: number;
463
- port: number;
464
- databaseBranch?: string;
465
- createdAt: Date;
466
- lastAccessed: Date;
467
- }
468
- interface WorkspaceInput {
469
- identifier: string;
470
- type: 'issue' | 'pr' | 'branch';
471
- skipClaude?: boolean;
472
- }
473
- interface WorkspaceSummary {
474
- id: string;
475
- issueNumber?: number;
476
- prNumber?: number;
477
- title: string;
478
- branch: string;
479
- port: number;
480
- status: 'active' | 'stale' | 'error';
481
- lastAccessed: string;
482
- }
483
- interface Worktree {
484
- path: string;
485
- branch: string;
486
- commit: string;
487
- isPR: boolean;
488
- prNumber?: number;
489
- issueNumber?: number;
490
- port?: number;
491
- }
492
- interface GitStatus {
493
- hasUncommittedChanges: boolean;
494
- unstagedFiles: string[];
495
- stagedFiles: string[];
496
- currentBranch: string;
497
- isAheadOfRemote: boolean;
498
- isBehindRemote: boolean;
499
- }
500
- interface Issue {
501
- number: number;
502
- title: string;
503
- body: string;
504
- state: 'open' | 'closed';
505
- labels: string[];
506
- assignees: string[];
507
- url: string;
508
- }
509
- interface PullRequest {
510
- number: number;
511
- title: string;
512
- body: string;
513
- state: 'open' | 'closed' | 'merged';
514
- branch: string;
515
- baseBranch: string;
516
- url: string;
517
- isDraft: boolean;
518
- }
519
- /**
520
- * Result of database branch deletion operation
521
- * Distinguishes between successful deletion, branch not found, and errors
522
- */
523
- interface DatabaseDeletionResult {
524
- /** Overall operation succeeded (true even if branch didn't exist) */
525
- success: boolean;
526
- /** True only if a branch was actually deleted */
527
- deleted: boolean;
528
- /** True if branch didn't exist (not an error, just nothing to do) */
529
- notFound: boolean;
530
- /** Error message if operation failed */
531
- error?: string;
532
- /** User declined deletion (for preview databases) */
533
- userDeclined?: boolean;
534
- /** Name of the branch that was processed */
535
- branchName?: string;
536
- }
537
- interface DatabaseProvider {
538
- createBranch(name: string, fromBranch?: string, cwd?: string): Promise<string>;
539
- deleteBranch(name: string, isPreview?: boolean, cwd?: string): Promise<DatabaseDeletionResult>;
540
- getConnectionString(branch: string, cwd?: string): Promise<string>;
541
- listBranches(cwd?: string): Promise<string[]>;
542
- branchExists(name: string, cwd?: string): Promise<boolean>;
543
- findPreviewBranch(branchName: string, cwd?: string): Promise<string | null>;
544
- getBranchNameFromEndpoint(endpointId: string, cwd?: string): Promise<string | null>;
545
- sanitizeBranchName(branchName: string): string;
546
- isAuthenticated(cwd?: string): Promise<boolean>;
547
- isCliAvailable(): Promise<boolean>;
548
- isConfigured(): boolean;
549
- }
550
- interface Config {
551
- defaultPort: number;
552
- databaseProvider?: 'neon' | 'supabase' | 'planetscale';
553
- claudeModel?: 'opus' | 'sonnet' | 'haiku';
554
- skipClaude?: boolean;
555
- customWorkspaceRoot?: string;
556
- }
557
- type OneShotMode = 'default' | 'noReview' | 'bypassPermissions';
558
- interface StartOptions {
559
- claude?: boolean;
560
- code?: boolean;
561
- devServer?: boolean;
562
- terminal?: boolean;
563
- oneShot?: OneShotMode;
564
- }
565
- interface AddIssueOptions {
566
- }
567
- interface FeedbackOptions {
568
- }
569
- interface EnhanceOptions {
570
- noBrowser?: boolean;
571
- }
572
- interface FinishOptions {
573
- force?: boolean;
574
- dryRun?: boolean;
575
- pr?: number;
576
- skipBuild?: boolean;
577
- }
578
- /**
579
- * Options for the cleanup command
580
- * All flags are optional and can be combined (subject to validation)
581
- */
582
- interface CleanupOptions {
583
- /** List all worktrees without removing anything */
584
- list?: boolean;
585
- /** Remove all worktrees (interactive confirmation required unless --force) */
586
- all?: boolean;
587
- /** Cleanup by specific issue number */
588
- issue?: number;
589
- /** Skip confirmations and force removal */
590
- force?: boolean;
591
- /** Show what would be done without actually doing it */
592
- dryRun?: boolean;
593
- }
594
- interface ListOptions {
595
- json?: boolean;
596
- }
597
- interface MockOptions {
598
- scenario: 'empty' | 'existing' | 'conflicts' | 'error';
599
- data?: unknown;
600
- }
601
-
602
- interface RgbColor {
603
- r: number;
604
- g: number;
605
- b: number;
606
- }
607
- interface ColorData {
608
- rgb: RgbColor;
609
- hex: string;
610
- index: number;
611
- }
612
- type Platform = 'darwin' | 'linux' | 'win32' | 'unsupported';
613
- interface ValidationOptions {
614
- dryRun?: boolean;
615
- skipTypecheck?: boolean;
616
- skipLint?: boolean;
617
- skipTests?: boolean;
618
- }
619
- interface ValidationStepResult {
620
- step: 'typecheck' | 'lint' | 'test';
621
- passed: boolean;
622
- skipped: boolean;
623
- output?: string;
624
- error?: string;
625
- duration?: number;
626
- }
627
- interface ValidationResult {
628
- success: boolean;
629
- steps: ValidationStepResult[];
630
- totalDuration: number;
631
- }
632
- interface CommitOptions {
633
- dryRun?: boolean;
634
- issueNumber?: number;
635
- message?: string;
636
- noReview?: boolean;
637
- skipVerify?: boolean;
638
- }
639
- interface MergeOptions {
640
- dryRun?: boolean;
641
- force?: boolean;
642
- repoRoot?: string;
643
- }
644
- interface MergeResult {
645
- success: boolean;
646
- branchName: string;
647
- commitsMerged: number;
648
- rebaseCompleted: boolean;
649
- mergeCompleted: boolean;
650
- }
651
- interface UpdateCheckCache {
652
- lastCheck: number;
653
- latestVersion: string;
654
- }
655
- interface UpdateCheckResult {
656
- currentVersion: string;
657
- latestVersion: string;
658
- updateAvailable: boolean;
659
- }
660
- type InstallationMethod = 'global' | 'local' | 'linked' | 'unknown';
661
-
662
- interface GitHubInputDetection {
663
- type: 'issue' | 'pr' | 'unknown';
664
- number: number | null;
665
- rawInput: string;
666
- }
667
- interface BranchNameStrategy {
668
- generate(issueNumber: number, title: string): Promise<string>;
669
- }
670
- interface BranchGenerationOptions {
671
- issueNumber: number;
672
- title: string;
673
- strategy?: BranchNameStrategy;
674
- }
675
-
676
- declare class GitHubService {
677
- private defaultBranchNameStrategy;
678
- private prompter;
679
- constructor(options?: {
680
- branchNameStrategy?: BranchNameStrategy;
681
- useClaude?: boolean;
682
- claudeModel?: string;
683
- prompter?: (message: string) => Promise<boolean>;
684
- });
685
- detectInputType(input: string): Promise<GitHubInputDetection>;
686
- fetchIssue(issueNumber: number): Promise<Issue>;
687
- isValidIssue(issueNumber: number): Promise<Issue | false>;
688
- private fetchIssueInternal;
689
- validateIssueState(issue: Issue): Promise<void>;
690
- fetchPR(prNumber: number): Promise<PullRequest>;
691
- isValidPR(prNumber: number): Promise<PullRequest | false>;
692
- private fetchPRInternal;
693
- validatePRState(pr: PullRequest): Promise<void>;
694
- generateBranchName(options: BranchGenerationOptions): Promise<string>;
695
- createIssue(title: string, body: string, repository?: string, labels?: string[]): Promise<{
696
- number: number;
697
- url: string;
698
- }>;
699
- getIssueUrl(issueNumber: number, repo?: string): Promise<string>;
700
- moveIssueToInProgress(issueNumber: number): Promise<void>;
701
- private updateIssueStatusInProject;
702
- extractContext(entity: Issue | PullRequest): string;
703
- private mapGitHubIssueToIssue;
704
- private mapGitHubPRToPullRequest;
705
- private promptUserConfirmation;
706
- setDefaultBranchNameStrategy(strategy: BranchNameStrategy): void;
707
- getBranchNameStrategy(): BranchNameStrategy;
708
- }
709
-
710
- declare class EnvironmentManager {
711
- private readonly backupSuffix;
712
- /**
713
- * Set or update an environment variable in a .env file
714
- * Ports functionality from bash/utils/env-utils.sh:setEnvVar()
715
- * @returns The backup path if a backup was created
716
- */
717
- setEnvVar(filePath: string, key: string, value: string, backup?: boolean): Promise<string | void>;
718
- /**
719
- * Read and parse a .env file
720
- */
721
- readEnvFile(filePath: string): Promise<Map<string, string>>;
722
- /**
723
- * Generic file copy helper that only copies if source exists
724
- * Does not throw if source file doesn't exist - just logs and returns
725
- * @private
726
- */
727
- copyIfExists(source: string, destination: string): Promise<void>;
728
- /**
729
- * Calculate unique port for workspace
730
- * Implements:
731
- * - Issue/PR: 3000 + issue/PR number
732
- * - Branch: 3000 + deterministic hash offset (1-999)
733
- */
734
- calculatePort(options: PortAssignmentOptions): number;
735
- /**
736
- * Set port environment variable for workspace
737
- */
738
- setPortForWorkspace(envFilePath: string, issueNumber?: number, prNumber?: number, branchName?: string): Promise<number>;
739
- /**
740
- * Validate environment configuration
741
- */
742
- validateEnvFile(filePath: string): Promise<{
743
- valid: boolean;
744
- errors: string[];
745
- }>;
746
- /**
747
- * Create backup of existing file
748
- */
749
- private createBackup;
750
- }
751
-
752
- /**
753
- * Database Manager - orchestrates database operations with conditional execution
754
- * Ports functionality from bash scripts with guard conditions:
755
- * 1. Database provider must be properly configured (provider.isConfigured())
756
- * 2. The worktree's .env file must contain the configured database URL variable (default: DATABASE_URL)
757
- *
758
- * This ensures database branching only occurs for projects that actually use databases
759
- */
760
- declare class DatabaseManager {
761
- private provider;
762
- private environment;
763
- private databaseUrlEnvVarName;
764
- constructor(provider: DatabaseProvider, environment: EnvironmentManager, databaseUrlEnvVarName?: string);
765
- /**
766
- * Get the configured database URL environment variable name
767
- */
768
- getConfiguredVariableName(): string;
769
- /**
770
- * Check if database branching should be used
771
- * Requires BOTH conditions:
772
- * 1. Database provider is properly configured (checked via provider.isConfigured())
773
- * 2. .env file contains the configured database URL variable
774
- */
775
- shouldUseDatabaseBranching(envFilePath: string): Promise<boolean>;
776
- /**
777
- * Create database branch only if configured
778
- * Returns connection string if branch was created, null if skipped
779
- *
780
- * @param branchName - Name of the branch to create
781
- * @param envFilePath - Path to .env file for configuration checks
782
- * @param cwd - Optional working directory to run commands from
783
- */
784
- createBranchIfConfigured(branchName: string, envFilePath: string, cwd?: string): Promise<string | null>;
785
- /**
786
- * Delete database branch only if configured
787
- * Returns result object indicating what happened
788
- *
789
- * @param branchName - Name of the branch to delete
790
- * @param shouldCleanup - Boolean indicating if database cleanup should be performed (pre-fetched config)
791
- * @param isPreview - Whether this is a preview database branch
792
- * @param cwd - Optional working directory to run commands from (prevents issues with deleted directories)
793
- */
794
- deleteBranchIfConfigured(branchName: string, shouldCleanup: boolean, isPreview?: boolean, cwd?: string): Promise<DatabaseDeletionResult>;
795
- /**
796
- * Check if .env has the configured database URL variable
797
- * CRITICAL: If user explicitly configured a custom variable name (not default),
798
- * throw an error if it's missing from .env
799
- */
800
- private hasDatabaseUrlInEnv;
801
- }
802
-
803
126
  /**
804
127
  * Zod schema for iloom settings
805
128
  */
@@ -962,6 +285,45 @@ declare const IloomSettingsSchema: z.ZodObject<{
962
285
  databaseUrlEnvVarName?: string | undefined;
963
286
  } | undefined;
964
287
  }>>;
288
+ databaseProviders: z.ZodOptional<z.ZodObject<{
289
+ neon: z.ZodOptional<z.ZodObject<{
290
+ projectId: z.ZodString;
291
+ parentBranch: z.ZodString;
292
+ }, "strip", z.ZodTypeAny, {
293
+ projectId: string;
294
+ parentBranch: string;
295
+ }, {
296
+ projectId: string;
297
+ parentBranch: string;
298
+ }>>;
299
+ }, "strip", z.ZodTypeAny, {
300
+ neon?: {
301
+ projectId: string;
302
+ parentBranch: string;
303
+ } | undefined;
304
+ }, {
305
+ neon?: {
306
+ projectId: string;
307
+ parentBranch: string;
308
+ } | undefined;
309
+ }>>;
310
+ issueManagement: z.ZodOptional<z.ZodObject<{
311
+ github: z.ZodOptional<z.ZodObject<{
312
+ remote: z.ZodString;
313
+ }, "strip", z.ZodTypeAny, {
314
+ remote: string;
315
+ }, {
316
+ remote: string;
317
+ }>>;
318
+ }, "strip", z.ZodTypeAny, {
319
+ github?: {
320
+ remote: string;
321
+ } | undefined;
322
+ }, {
323
+ github?: {
324
+ remote: string;
325
+ } | undefined;
326
+ }>>;
965
327
  }, "strip", z.ZodTypeAny, {
966
328
  mainBranch?: string | undefined;
967
329
  worktreePrefix?: string | undefined;
@@ -1003,6 +365,17 @@ declare const IloomSettingsSchema: z.ZodObject<{
1003
365
  databaseUrlEnvVarName: string;
1004
366
  } | undefined;
1005
367
  } | undefined;
368
+ databaseProviders?: {
369
+ neon?: {
370
+ projectId: string;
371
+ parentBranch: string;
372
+ } | undefined;
373
+ } | undefined;
374
+ issueManagement?: {
375
+ github?: {
376
+ remote: string;
377
+ } | undefined;
378
+ } | undefined;
1006
379
  }, {
1007
380
  mainBranch?: string | undefined;
1008
381
  worktreePrefix?: string | undefined;
@@ -1044,62 +417,756 @@ declare const IloomSettingsSchema: z.ZodObject<{
1044
417
  databaseUrlEnvVarName?: string | undefined;
1045
418
  } | undefined;
1046
419
  } | undefined;
420
+ databaseProviders?: {
421
+ neon?: {
422
+ projectId: string;
423
+ parentBranch: string;
424
+ } | undefined;
425
+ } | undefined;
426
+ issueManagement?: {
427
+ github?: {
428
+ remote: string;
429
+ } | undefined;
430
+ } | undefined;
1047
431
  }>;
1048
432
  /**
1049
- * TypeScript type for iloom settings derived from Zod schema
433
+ * TypeScript type for iloom settings derived from Zod schema
434
+ */
435
+ type IloomSettings = z.infer<typeof IloomSettingsSchema>;
436
+ /**
437
+ * Manages project-level settings from .iloom/settings.json
438
+ */
439
+ declare class SettingsManager {
440
+ /**
441
+ * Load settings from <PROJECT_ROOT>/.iloom/settings.json and settings.local.json
442
+ * Merges settings.local.json over settings.json with priority
443
+ * CLI overrides have highest priority if provided
444
+ * Returns empty object if both files don't exist (not an error)
445
+ */
446
+ loadSettings(projectRoot?: string, cliOverrides?: Partial<IloomSettings>): Promise<IloomSettings>;
447
+ /**
448
+ * Log the final merged configuration for debugging
449
+ */
450
+ private logFinalConfiguration;
451
+ /**
452
+ * Load and parse a single settings file
453
+ * Returns empty object if file doesn't exist (not an error)
454
+ */
455
+ private loadSettingsFile;
456
+ /**
457
+ * Deep merge two settings objects with priority to override
458
+ * Uses deepmerge library with array replacement strategy
459
+ */
460
+ private mergeSettings;
461
+ /**
462
+ * Format all Zod validation errors into a single error message
463
+ */
464
+ private formatAllZodErrors;
465
+ /**
466
+ * Validate settings structure and model names using Zod schema
467
+ * This method is kept for testing purposes but uses Zod internally
468
+ * @internal - Only used in tests via bracket notation
469
+ */
470
+ private validateSettings;
471
+ /**
472
+ * Get project root (defaults to process.cwd())
473
+ */
474
+ private getProjectRoot;
475
+ /**
476
+ * Get effective protected branches list with mainBranch always included
477
+ *
478
+ * This method provides a single source of truth for protected branches logic:
479
+ * 1. Use configured protectedBranches if provided
480
+ * 2. Otherwise use defaults: [mainBranch, 'main', 'master', 'develop']
481
+ * 3. ALWAYS ensure mainBranch is included even if user configured custom list
482
+ *
483
+ * @param projectRoot - Optional project root directory (defaults to process.cwd())
484
+ * @returns Array of protected branch names with mainBranch guaranteed to be included
485
+ */
486
+ getProtectedBranches(projectRoot?: string): Promise<string[]>;
487
+ }
488
+
489
+ /**
490
+ * Manages Git worktrees for the iloom CLI
491
+ * Ports functionality from bash scripts into TypeScript
492
+ */
493
+ declare class GitWorktreeManager {
494
+ private readonly _workingDirectory;
495
+ constructor(workingDirectory?: string);
496
+ /**
497
+ * Get the working directory for git operations (main worktree path)
498
+ */
499
+ get workingDirectory(): string;
500
+ /**
501
+ * List all worktrees in the repository
502
+ * Defaults to porcelain format for reliable machine parsing
503
+ * Equivalent to: git worktree list --porcelain
504
+ */
505
+ listWorktrees(options?: WorktreeListOptions): Promise<GitWorktree[]>;
506
+ /**
507
+ * Find worktree for a specific branch
508
+ * Ports: find_worktree_for_branch() from find-worktree-for-branch.sh
509
+ */
510
+ findWorktreeForBranch(branchName: string): Promise<GitWorktree | null>;
511
+ /**
512
+ * Check if a worktree is the main repository worktree
513
+ * Uses findMainWorktreePathWithSettings to determine the main worktree based on settings.
514
+ *
515
+ * @param worktree - The worktree to check
516
+ * @param settingsManager - SettingsManager instance for loading settings
517
+ * @returns true if the worktree is the main worktree
518
+ */
519
+ isMainWorktree(worktree: GitWorktree, settingsManager: SettingsManager): Promise<boolean>;
520
+ /**
521
+ * Check if a worktree is a PR worktree based on naming patterns
522
+ * Ports: is_pr_worktree() from worktree-utils.sh
523
+ */
524
+ isPRWorktree(worktree: GitWorktree): boolean;
525
+ /**
526
+ * Get PR number from worktree branch name
527
+ * Ports: get_pr_number_from_worktree() from worktree-utils.sh
528
+ */
529
+ getPRNumberFromWorktree(worktree: GitWorktree): number | null;
530
+ /**
531
+ * Create a new worktree
532
+ * Ports worktree creation logic from new-branch-workflow.sh
533
+ * @returns The absolute path to the created worktree
534
+ */
535
+ createWorktree(options: WorktreeCreateOptions): Promise<string>;
536
+ /**
537
+ * Remove a worktree and optionally clean up associated files
538
+ * Ports worktree removal logic from cleanup-worktree.sh
539
+ * @returns A message describing what was done (for dry-run mode)
540
+ */
541
+ removeWorktree(worktreePath: string, options?: WorktreeCleanupOptions): Promise<string | void>;
542
+ /**
543
+ * Validate worktree state and integrity
544
+ */
545
+ validateWorktree(worktreePath: string): Promise<WorktreeValidation>;
546
+ /**
547
+ * Get detailed status information for a worktree
548
+ */
549
+ getWorktreeStatus(worktreePath: string): Promise<WorktreeStatus>;
550
+ /**
551
+ * Generate a suggested worktree path for a branch
552
+ */
553
+ generateWorktreePath(branchName: string, customRoot?: string, options?: {
554
+ isPR?: boolean;
555
+ prNumber?: number;
556
+ prefix?: string;
557
+ }): string;
558
+ /**
559
+ * Sanitize a branch name for use as a directory name
560
+ * Replaces slashes with dashes and removes invalid filesystem characters
561
+ * Ports logic from bash script line 593: ${BRANCH_NAME//\\//-}
562
+ */
563
+ sanitizeBranchName(branchName: string): string;
564
+ /**
565
+ * Check if repository is in a valid state for worktree operations
566
+ */
567
+ isRepoReady(): Promise<boolean>;
568
+ /**
569
+ * Get repository information
570
+ */
571
+ getRepoInfo(): Promise<{
572
+ root: string | null;
573
+ defaultBranch: string;
574
+ currentBranch: string | null;
575
+ }>;
576
+ /**
577
+ * Prune stale worktree entries (worktrees that no longer exist on disk)
578
+ */
579
+ pruneWorktrees(): Promise<void>;
580
+ /**
581
+ * Lock a worktree to prevent it from being pruned or moved
582
+ */
583
+ lockWorktree(worktreePath: string, reason?: string): Promise<void>;
584
+ /**
585
+ * Unlock a previously locked worktree
586
+ */
587
+ unlockWorktree(worktreePath: string): Promise<void>;
588
+ /**
589
+ * Find worktrees matching an identifier (branch name, path, or PR number)
590
+ */
591
+ findWorktreesByIdentifier(identifier: string): Promise<GitWorktree[]>;
592
+ /**
593
+ * Find worktree for a specific issue number using exact pattern matching
594
+ * Matches: issue-{N} at start OR after /, -, _ (but NOT issue-{N}X where X is a digit)
595
+ * Supports patterns like: issue-44, feat/issue-44-feature, feat-issue-44, bugfix_issue-44, etc.
596
+ * Avoids false matches like: tissue-44, myissue-44
597
+ * Ports: find_existing_worktree() from bash script lines 131-165
598
+ */
599
+ findWorktreeForIssue(issueNumber: number): Promise<GitWorktree | null>;
600
+ /**
601
+ * Find worktree for a specific PR by branch name
602
+ * Ports: find_existing_worktree() for PR type from bash script lines 149-160
603
+ */
604
+ findWorktreeForPR(prNumber: number, branchName: string): Promise<GitWorktree | null>;
605
+ /**
606
+ * Remove multiple worktrees
607
+ * Returns a summary of successes and failures
608
+ * Automatically filters out the main worktree
609
+ *
610
+ * @param worktrees - Array of worktrees to remove
611
+ * @param settingsManager - SettingsManager instance for determining main worktree
612
+ * @param options - Cleanup options
613
+ */
614
+ removeWorktrees(worktrees: GitWorktree[], settingsManager: SettingsManager, options?: WorktreeCleanupOptions): Promise<{
615
+ successes: Array<{
616
+ worktree: GitWorktree;
617
+ }>;
618
+ failures: Array<{
619
+ worktree: GitWorktree;
620
+ error: string;
621
+ }>;
622
+ skipped: Array<{
623
+ worktree: GitWorktree;
624
+ reason: string;
625
+ }>;
626
+ }>;
627
+ /**
628
+ * Format worktree information for display
629
+ */
630
+ formatWorktree(worktree: GitWorktree): {
631
+ title: string;
632
+ path: string;
633
+ commit: string;
634
+ };
635
+ }
636
+
637
+ interface EnvVariable {
638
+ key: string;
639
+ value: string;
640
+ }
641
+ interface EnvFileOptions {
642
+ path: string;
643
+ backup?: boolean;
644
+ encoding?: BufferEncoding;
645
+ }
646
+ /**
647
+ * @deprecated Use exception-based error handling instead
648
+ */
649
+ interface EnvOperationResult {
650
+ success: boolean;
651
+ backupPath?: string;
652
+ error?: string;
653
+ }
654
+ interface PortAssignmentOptions {
655
+ basePort?: number;
656
+ issueNumber?: number;
657
+ prNumber?: number;
658
+ branchName?: string;
659
+ }
660
+
661
+ type ProjectCapability = 'cli' | 'web';
662
+ type Capability = ProjectCapability;
663
+ interface Loom {
664
+ id: string;
665
+ path: string;
666
+ branch: string;
667
+ type: 'issue' | 'pr' | 'branch';
668
+ identifier: string | number;
669
+ port: number;
670
+ databaseBranch?: string;
671
+ createdAt: Date;
672
+ lastAccessed: Date;
673
+ githubData?: {
674
+ title?: string;
675
+ body?: string;
676
+ url?: string;
677
+ state?: string;
678
+ };
679
+ capabilities?: ProjectCapability[];
680
+ binEntries?: Record<string, string>;
681
+ cliSymlinks?: string[];
682
+ }
683
+ interface CreateLoomInput {
684
+ type: 'issue' | 'pr' | 'branch';
685
+ identifier: string | number;
686
+ originalInput: string;
687
+ baseBranch?: string;
688
+ options?: {
689
+ skipDatabase?: boolean;
690
+ skipColorSync?: boolean;
691
+ enableClaude?: boolean;
692
+ enableCode?: boolean;
693
+ enableDevServer?: boolean;
694
+ enableTerminal?: boolean;
695
+ oneShot?: OneShotMode;
696
+ setArguments?: string[];
697
+ executablePath?: string;
698
+ };
699
+ }
700
+ type LaunchMode = 'editor' | 'terminal' | 'both';
701
+ interface LoomSummary {
702
+ id: string;
703
+ type: 'issue' | 'pr' | 'branch';
704
+ identifier: string | number;
705
+ title?: string;
706
+ branch: string;
707
+ port: number;
708
+ status: 'active' | 'stale' | 'error';
709
+ lastAccessed: string;
710
+ }
711
+
712
+ /**
713
+ * Options for ResourceCleanup operations
1050
714
  */
1051
- type IloomSettings = z.infer<typeof IloomSettingsSchema>;
715
+ interface ResourceCleanupOptions {
716
+ /** Preview operations without executing */
717
+ dryRun?: boolean;
718
+ /** Skip confirmations and safety checks */
719
+ force?: boolean;
720
+ /** Delete the associated branch */
721
+ deleteBranch?: boolean;
722
+ /** Keep database branch instead of deleting */
723
+ keepDatabase?: boolean;
724
+ /** Prompt for confirmation before operations */
725
+ interactive?: boolean;
726
+ }
727
+ /**
728
+ * Result of a cleanup operation
729
+ */
730
+ interface CleanupResult {
731
+ /** Identifier that was cleaned up */
732
+ identifier: string;
733
+ /** Actual branch name that was found (will differ from identifier) */
734
+ branchName?: string;
735
+ /** Overall success status */
736
+ success: boolean;
737
+ /** Individual operation results */
738
+ operations: OperationResult[];
739
+ /** Errors encountered during cleanup */
740
+ errors: Error[];
741
+ /** Whether rollback is required */
742
+ rollbackRequired?: boolean;
743
+ }
744
+ /**
745
+ * Result of an individual cleanup operation
746
+ */
747
+ interface OperationResult {
748
+ /** Type of operation performed */
749
+ type: 'dev-server' | 'worktree' | 'branch' | 'database' | 'cli-symlinks';
750
+ /** Whether operation succeeded */
751
+ success: boolean;
752
+ /** Human-readable message */
753
+ message: string;
754
+ /** Error message if operation failed */
755
+ error?: string;
756
+ /** For database operations: whether branch was actually deleted (vs not found) */
757
+ deleted?: boolean;
758
+ }
759
+ /**
760
+ * Safety check result
761
+ */
762
+ interface SafetyCheck {
763
+ /** Whether cleanup is safe to proceed */
764
+ isSafe: boolean;
765
+ /** Non-blocking warnings */
766
+ warnings: string[];
767
+ /** Blocking issues that prevent cleanup */
768
+ blockers: string[];
769
+ }
770
+ /**
771
+ * Options for branch deletion
772
+ */
773
+ interface BranchDeleteOptions {
774
+ /** Force delete unmerged branch */
775
+ force?: boolean;
776
+ /** Also delete remote branch */
777
+ remote?: boolean;
778
+ /** Preview without executing */
779
+ dryRun?: boolean;
780
+ }
781
+ /**
782
+ * Target for batch cleanup - represents a branch that may or may not have a worktree
783
+ */
784
+ interface BranchCleanupTarget {
785
+ /** Branch name */
786
+ branchName: string;
787
+ /** Whether this branch has an associated worktree */
788
+ hasWorktree: boolean;
789
+ /** Path to worktree if it exists */
790
+ worktreePath?: string;
791
+ }
792
+ /**
793
+ * Result of batch cleanup operation for an issue
794
+ */
795
+ interface BatchCleanupResult {
796
+ /** Issue number that was cleaned up */
797
+ issueNumber: number;
798
+ /** Number of branches found matching the issue */
799
+ targetsFound: number;
800
+ /** Number of worktrees successfully removed */
801
+ worktreesRemoved: number;
802
+ /** Number of branches successfully deleted */
803
+ branchesDeleted: number;
804
+ /** Number of failed operations */
805
+ failed: number;
806
+ /** Individual cleanup results for each branch */
807
+ results: CleanupResult[];
808
+ }
809
+
810
+ /**
811
+ * Information about a running process
812
+ */
813
+ interface ProcessInfo {
814
+ /** Process ID */
815
+ pid: number;
816
+ /** Process name (e.g., "node", "pnpm") */
817
+ name: string;
818
+ /** Full command line */
819
+ command: string;
820
+ /** Port the process is listening on */
821
+ port: number;
822
+ /** Whether this appears to be a dev server */
823
+ isDevServer: boolean;
824
+ }
825
+
826
+ interface Workspace {
827
+ id: string;
828
+ path: string;
829
+ branch: string;
830
+ issueNumber?: number;
831
+ prNumber?: number;
832
+ port: number;
833
+ databaseBranch?: string;
834
+ createdAt: Date;
835
+ lastAccessed: Date;
836
+ }
837
+ interface WorkspaceInput {
838
+ identifier: string;
839
+ type: 'issue' | 'pr' | 'branch';
840
+ skipClaude?: boolean;
841
+ }
842
+ interface WorkspaceSummary {
843
+ id: string;
844
+ issueNumber?: number;
845
+ prNumber?: number;
846
+ title: string;
847
+ branch: string;
848
+ port: number;
849
+ status: 'active' | 'stale' | 'error';
850
+ lastAccessed: string;
851
+ }
852
+ interface Worktree {
853
+ path: string;
854
+ branch: string;
855
+ commit: string;
856
+ isPR: boolean;
857
+ prNumber?: number;
858
+ issueNumber?: number;
859
+ port?: number;
860
+ }
861
+ interface GitStatus {
862
+ hasUncommittedChanges: boolean;
863
+ unstagedFiles: string[];
864
+ stagedFiles: string[];
865
+ currentBranch: string;
866
+ isAheadOfRemote: boolean;
867
+ isBehindRemote: boolean;
868
+ }
869
+ interface Issue {
870
+ number: number;
871
+ title: string;
872
+ body: string;
873
+ state: 'open' | 'closed';
874
+ labels: string[];
875
+ assignees: string[];
876
+ url: string;
877
+ }
878
+ interface PullRequest {
879
+ number: number;
880
+ title: string;
881
+ body: string;
882
+ state: 'open' | 'closed' | 'merged';
883
+ branch: string;
884
+ baseBranch: string;
885
+ url: string;
886
+ isDraft: boolean;
887
+ }
888
+ /**
889
+ * Result of database branch deletion operation
890
+ * Distinguishes between successful deletion, branch not found, and errors
891
+ */
892
+ interface DatabaseDeletionResult {
893
+ /** Overall operation succeeded (true even if branch didn't exist) */
894
+ success: boolean;
895
+ /** True only if a branch was actually deleted */
896
+ deleted: boolean;
897
+ /** True if branch didn't exist (not an error, just nothing to do) */
898
+ notFound: boolean;
899
+ /** Error message if operation failed */
900
+ error?: string;
901
+ /** User declined deletion (for preview databases) */
902
+ userDeclined?: boolean;
903
+ /** Name of the branch that was processed */
904
+ branchName?: string;
905
+ }
906
+ interface DatabaseProvider {
907
+ createBranch(name: string, fromBranch?: string, cwd?: string): Promise<string>;
908
+ deleteBranch(name: string, isPreview?: boolean, cwd?: string): Promise<DatabaseDeletionResult>;
909
+ getConnectionString(branch: string, cwd?: string): Promise<string>;
910
+ listBranches(cwd?: string): Promise<string[]>;
911
+ branchExists(name: string, cwd?: string): Promise<boolean>;
912
+ findPreviewBranch(branchName: string, cwd?: string): Promise<string | null>;
913
+ getBranchNameFromEndpoint(endpointId: string, cwd?: string): Promise<string | null>;
914
+ sanitizeBranchName(branchName: string): string;
915
+ isAuthenticated(cwd?: string): Promise<boolean>;
916
+ isCliAvailable(): Promise<boolean>;
917
+ isConfigured(): boolean;
918
+ }
919
+ interface Config {
920
+ defaultPort: number;
921
+ databaseProvider?: 'neon' | 'supabase' | 'planetscale';
922
+ claudeModel?: 'opus' | 'sonnet' | 'haiku';
923
+ skipClaude?: boolean;
924
+ customWorkspaceRoot?: string;
925
+ }
926
+ type OneShotMode = 'default' | 'noReview' | 'bypassPermissions';
927
+ interface StartOptions {
928
+ claude?: boolean;
929
+ code?: boolean;
930
+ devServer?: boolean;
931
+ terminal?: boolean;
932
+ oneShot?: OneShotMode;
933
+ }
934
+ interface AddIssueOptions {
935
+ }
936
+ interface FeedbackOptions {
937
+ }
938
+ interface EnhanceOptions {
939
+ noBrowser?: boolean;
940
+ }
941
+ interface FinishOptions {
942
+ force?: boolean;
943
+ dryRun?: boolean;
944
+ pr?: number;
945
+ skipBuild?: boolean;
946
+ }
1052
947
  /**
1053
- * Manages project-level settings from .iloom/settings.json
948
+ * Options for the cleanup command
949
+ * All flags are optional and can be combined (subject to validation)
1054
950
  */
1055
- declare class SettingsManager {
951
+ interface CleanupOptions {
952
+ /** List all worktrees without removing anything */
953
+ list?: boolean;
954
+ /** Remove all worktrees (interactive confirmation required unless --force) */
955
+ all?: boolean;
956
+ /** Cleanup by specific issue number */
957
+ issue?: number;
958
+ /** Skip confirmations and force removal */
959
+ force?: boolean;
960
+ /** Show what would be done without actually doing it */
961
+ dryRun?: boolean;
962
+ }
963
+ interface ListOptions {
964
+ json?: boolean;
965
+ }
966
+ interface MockOptions {
967
+ scenario: 'empty' | 'existing' | 'conflicts' | 'error';
968
+ data?: unknown;
969
+ }
970
+
971
+ interface RgbColor {
972
+ r: number;
973
+ g: number;
974
+ b: number;
975
+ }
976
+ interface ColorData {
977
+ rgb: RgbColor;
978
+ hex: string;
979
+ index: number;
980
+ }
981
+ type Platform = 'darwin' | 'linux' | 'win32' | 'unsupported';
982
+ interface ValidationOptions {
983
+ dryRun?: boolean;
984
+ skipTypecheck?: boolean;
985
+ skipLint?: boolean;
986
+ skipTests?: boolean;
987
+ }
988
+ interface ValidationStepResult {
989
+ step: 'typecheck' | 'lint' | 'test';
990
+ passed: boolean;
991
+ skipped: boolean;
992
+ output?: string;
993
+ error?: string;
994
+ duration?: number;
995
+ }
996
+ interface ValidationResult {
997
+ success: boolean;
998
+ steps: ValidationStepResult[];
999
+ totalDuration: number;
1000
+ }
1001
+ interface CommitOptions {
1002
+ dryRun?: boolean;
1003
+ issueNumber?: number;
1004
+ message?: string;
1005
+ noReview?: boolean;
1006
+ skipVerify?: boolean;
1007
+ }
1008
+ interface MergeOptions {
1009
+ dryRun?: boolean;
1010
+ force?: boolean;
1011
+ repoRoot?: string;
1012
+ }
1013
+ interface MergeResult {
1014
+ success: boolean;
1015
+ branchName: string;
1016
+ commitsMerged: number;
1017
+ rebaseCompleted: boolean;
1018
+ mergeCompleted: boolean;
1019
+ }
1020
+ interface UpdateCheckCache {
1021
+ lastCheck: number;
1022
+ latestVersion: string;
1023
+ }
1024
+ interface UpdateCheckResult {
1025
+ currentVersion: string;
1026
+ latestVersion: string;
1027
+ updateAvailable: boolean;
1028
+ }
1029
+ type InstallationMethod = 'global' | 'local' | 'linked' | 'unknown';
1030
+
1031
+ interface GitHubInputDetection {
1032
+ type: 'issue' | 'pr' | 'unknown';
1033
+ number: number | null;
1034
+ rawInput: string;
1035
+ }
1036
+ interface BranchNameStrategy {
1037
+ generate(issueNumber: number, title: string): Promise<string>;
1038
+ }
1039
+ interface BranchGenerationOptions {
1040
+ issueNumber: number;
1041
+ title: string;
1042
+ strategy?: BranchNameStrategy;
1043
+ }
1044
+
1045
+ declare class GitHubService {
1046
+ private defaultBranchNameStrategy;
1047
+ private prompter;
1048
+ constructor(options?: {
1049
+ branchNameStrategy?: BranchNameStrategy;
1050
+ useClaude?: boolean;
1051
+ claudeModel?: string;
1052
+ prompter?: (message: string) => Promise<boolean>;
1053
+ });
1054
+ detectInputType(input: string, repo?: string): Promise<GitHubInputDetection>;
1055
+ fetchIssue(issueNumber: number, repo?: string): Promise<Issue>;
1056
+ isValidIssue(issueNumber: number, repo?: string): Promise<Issue | false>;
1057
+ private fetchIssueInternal;
1058
+ validateIssueState(issue: Issue): Promise<void>;
1059
+ fetchPR(prNumber: number, repo?: string): Promise<PullRequest>;
1060
+ isValidPR(prNumber: number, repo?: string): Promise<PullRequest | false>;
1061
+ private fetchPRInternal;
1062
+ validatePRState(pr: PullRequest): Promise<void>;
1063
+ generateBranchName(options: BranchGenerationOptions): Promise<string>;
1064
+ createIssue(title: string, body: string, repository?: string, labels?: string[]): Promise<{
1065
+ number: number;
1066
+ url: string;
1067
+ }>;
1068
+ getIssueUrl(issueNumber: number, repo?: string): Promise<string>;
1069
+ moveIssueToInProgress(issueNumber: number): Promise<void>;
1070
+ private updateIssueStatusInProject;
1071
+ extractContext(entity: Issue | PullRequest): string;
1072
+ private mapGitHubIssueToIssue;
1073
+ private mapGitHubPRToPullRequest;
1074
+ private promptUserConfirmation;
1075
+ setDefaultBranchNameStrategy(strategy: BranchNameStrategy): void;
1076
+ getBranchNameStrategy(): BranchNameStrategy;
1077
+ }
1078
+
1079
+ declare class EnvironmentManager {
1080
+ private readonly backupSuffix;
1056
1081
  /**
1057
- * Load settings from <PROJECT_ROOT>/.iloom/settings.json and settings.local.json
1058
- * Merges settings.local.json over settings.json with priority
1059
- * CLI overrides have highest priority if provided
1060
- * Returns empty object if both files don't exist (not an error)
1082
+ * Set or update an environment variable in a .env file
1083
+ * Ports functionality from bash/utils/env-utils.sh:setEnvVar()
1084
+ * @returns The backup path if a backup was created
1061
1085
  */
1062
- loadSettings(projectRoot?: string, cliOverrides?: Partial<IloomSettings>): Promise<IloomSettings>;
1086
+ setEnvVar(filePath: string, key: string, value: string, backup?: boolean): Promise<string | void>;
1063
1087
  /**
1064
- * Log the final merged configuration for debugging
1088
+ * Read and parse a .env file
1065
1089
  */
1066
- private logFinalConfiguration;
1090
+ readEnvFile(filePath: string): Promise<Map<string, string>>;
1067
1091
  /**
1068
- * Load and parse a single settings file
1069
- * Returns empty object if file doesn't exist (not an error)
1092
+ * Generic file copy helper that only copies if source exists
1093
+ * Does not throw if source file doesn't exist - just logs and returns
1094
+ * @private
1070
1095
  */
1071
- private loadSettingsFile;
1096
+ copyIfExists(source: string, destination: string): Promise<void>;
1072
1097
  /**
1073
- * Deep merge two settings objects with priority to override
1074
- * Uses deepmerge library with array replacement strategy
1098
+ * Calculate unique port for workspace
1099
+ * Implements:
1100
+ * - Issue/PR: 3000 + issue/PR number
1101
+ * - Branch: 3000 + deterministic hash offset (1-999)
1075
1102
  */
1076
- private mergeSettings;
1103
+ calculatePort(options: PortAssignmentOptions): number;
1077
1104
  /**
1078
- * Format all Zod validation errors into a single error message
1105
+ * Set port environment variable for workspace
1079
1106
  */
1080
- private formatAllZodErrors;
1107
+ setPortForWorkspace(envFilePath: string, issueNumber?: number, prNumber?: number, branchName?: string): Promise<number>;
1081
1108
  /**
1082
- * Validate settings structure and model names using Zod schema
1083
- * This method is kept for testing purposes but uses Zod internally
1084
- * @internal - Only used in tests via bracket notation
1109
+ * Validate environment configuration
1085
1110
  */
1086
- private validateSettings;
1111
+ validateEnvFile(filePath: string): Promise<{
1112
+ valid: boolean;
1113
+ errors: string[];
1114
+ }>;
1087
1115
  /**
1088
- * Get project root (defaults to process.cwd())
1116
+ * Create backup of existing file
1089
1117
  */
1090
- private getProjectRoot;
1118
+ private createBackup;
1119
+ }
1120
+
1121
+ /**
1122
+ * Database Manager - orchestrates database operations with conditional execution
1123
+ * Ports functionality from bash scripts with guard conditions:
1124
+ * 1. Database provider must be properly configured (provider.isConfigured())
1125
+ * 2. The worktree's .env file must contain the configured database URL variable (default: DATABASE_URL)
1126
+ *
1127
+ * This ensures database branching only occurs for projects that actually use databases
1128
+ */
1129
+ declare class DatabaseManager {
1130
+ private provider;
1131
+ private environment;
1132
+ private databaseUrlEnvVarName;
1133
+ constructor(provider: DatabaseProvider, environment: EnvironmentManager, databaseUrlEnvVarName?: string);
1091
1134
  /**
1092
- * Get effective protected branches list with mainBranch always included
1135
+ * Get the configured database URL environment variable name
1136
+ */
1137
+ getConfiguredVariableName(): string;
1138
+ /**
1139
+ * Check if database branching should be used
1140
+ * Requires BOTH conditions:
1141
+ * 1. Database provider is properly configured (checked via provider.isConfigured())
1142
+ * 2. .env file contains the configured database URL variable
1143
+ */
1144
+ shouldUseDatabaseBranching(envFilePath: string): Promise<boolean>;
1145
+ /**
1146
+ * Create database branch only if configured
1147
+ * Returns connection string if branch was created, null if skipped
1093
1148
  *
1094
- * This method provides a single source of truth for protected branches logic:
1095
- * 1. Use configured protectedBranches if provided
1096
- * 2. Otherwise use defaults: [mainBranch, 'main', 'master', 'develop']
1097
- * 3. ALWAYS ensure mainBranch is included even if user configured custom list
1149
+ * @param branchName - Name of the branch to create
1150
+ * @param envFilePath - Path to .env file for configuration checks
1151
+ * @param cwd - Optional working directory to run commands from
1152
+ */
1153
+ createBranchIfConfigured(branchName: string, envFilePath: string, cwd?: string): Promise<string | null>;
1154
+ /**
1155
+ * Delete database branch only if configured
1156
+ * Returns result object indicating what happened
1098
1157
  *
1099
- * @param projectRoot - Optional project root directory (defaults to process.cwd())
1100
- * @returns Array of protected branch names with mainBranch guaranteed to be included
1158
+ * @param branchName - Name of the branch to delete
1159
+ * @param shouldCleanup - Boolean indicating if database cleanup should be performed (pre-fetched config)
1160
+ * @param isPreview - Whether this is a preview database branch
1161
+ * @param cwd - Optional working directory to run commands from (prevents issues with deleted directories)
1101
1162
  */
1102
- getProtectedBranches(projectRoot?: string): Promise<string[]>;
1163
+ deleteBranchIfConfigured(branchName: string, shouldCleanup: boolean, isPreview?: boolean, cwd?: string): Promise<DatabaseDeletionResult>;
1164
+ /**
1165
+ * Check if .env has the configured database URL variable
1166
+ * CRITICAL: If user explicitly configured a custom variable name (not default),
1167
+ * throw an error if it's missing from .env
1168
+ */
1169
+ private hasDatabaseUrlInEnv;
1103
1170
  }
1104
1171
 
1105
1172
  interface TemplateVariables {
@@ -1110,6 +1177,21 @@ interface TemplateVariables {
1110
1177
  WORKSPACE_PATH?: string;
1111
1178
  PORT?: number;
1112
1179
  ONE_SHOT_MODE?: boolean;
1180
+ SETTINGS_SCHEMA?: string;
1181
+ SETTINGS_JSON?: string;
1182
+ SETTINGS_LOCAL_JSON?: string;
1183
+ SHELL_TYPE?: string;
1184
+ SHELL_CONFIG_PATH?: string;
1185
+ SHELL_CONFIG_CONTENT?: string;
1186
+ REMOTES_INFO?: string;
1187
+ MULTIPLE_REMOTES?: string;
1188
+ SINGLE_REMOTE?: string;
1189
+ SINGLE_REMOTE_NAME?: string;
1190
+ SINGLE_REMOTE_URL?: string;
1191
+ NO_REMOTES?: string;
1192
+ README_CONTENT?: string;
1193
+ SETTINGS_SCHEMA_CONTENT?: string;
1194
+ FIRST_TIME_USER?: boolean;
1113
1195
  }
1114
1196
  declare class PromptTemplateManager {
1115
1197
  private templateDir;
@@ -1117,7 +1199,7 @@ declare class PromptTemplateManager {
1117
1199
  /**
1118
1200
  * Load a template file by name
1119
1201
  */
1120
- loadTemplate(templateName: 'issue' | 'pr' | 'regular'): Promise<string>;
1202
+ loadTemplate(templateName: 'issue' | 'pr' | 'regular' | 'init'): Promise<string>;
1121
1203
  /**
1122
1204
  * Substitute variables in a template string
1123
1205
  */
@@ -1132,7 +1214,7 @@ declare class PromptTemplateManager {
1132
1214
  /**
1133
1215
  * Get a fully processed prompt for a workflow type
1134
1216
  */
1135
- getPrompt(type: 'issue' | 'pr' | 'regular', variables: TemplateVariables): Promise<string>;
1217
+ getPrompt(type: 'issue' | 'pr' | 'regular' | 'init', variables: TemplateVariables): Promise<string>;
1136
1218
  }
1137
1219
 
1138
1220
  interface ClaudeWorkflowOptions {