@iloom/cli 0.8.0 → 0.8.2

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 (71) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +4 -1
  3. package/dist/{PRManager-XLTVG6YG.js → PRManager-A63LT3NF.js} +4 -4
  4. package/dist/README.md +4 -1
  5. package/dist/agents/iloom-code-reviewer.md +16 -1
  6. package/dist/agents/iloom-framework-detector.md +1 -1
  7. package/dist/agents/iloom-issue-analyze-and-plan.md +1 -1
  8. package/dist/agents/iloom-issue-analyzer.md +1 -1
  9. package/dist/agents/iloom-issue-enhancer.md +1 -1
  10. package/dist/agents/iloom-issue-implementer.md +2 -2
  11. package/dist/agents/iloom-issue-planner.md +1 -1
  12. package/dist/{build-H4DK3DMQ.js → build-Z3WCIKPD.js} +3 -3
  13. package/dist/{chunk-A4UQY3M2.js → chunk-3FC3VNEX.js} +2 -2
  14. package/dist/{chunk-YAVVDZVF.js → chunk-44Y5IF7P.js} +4 -4
  15. package/dist/{chunk-ECP77QGE.js → chunk-A7XHHUEV.js} +4 -4
  16. package/dist/{chunk-RODL2HVY.js → chunk-FPNSFP6K.js} +6 -6
  17. package/dist/{chunk-WNXYC7J4.js → chunk-GWONJE3X.js} +6 -6
  18. package/dist/{chunk-BCQDYAOJ.js → chunk-O6LECMT6.js} +4 -4
  19. package/dist/{chunk-AZH27CPV.js → chunk-PBSHQVCT.js} +2 -2
  20. package/dist/{chunk-LFVRG6UU.js → chunk-RNBIISBZ.js} +4 -2
  21. package/dist/chunk-RNBIISBZ.js.map +1 -0
  22. package/dist/{chunk-QJX6ICWY.js → chunk-SC6X5EBG.js} +2 -2
  23. package/dist/{chunk-L4CN7YQT.js → chunk-UDZCTLD6.js} +2 -2
  24. package/dist/{cleanup-25PCP2EM.js → cleanup-NWNKWPUY.js} +3 -3
  25. package/dist/cli.js +269 -48
  26. package/dist/cli.js.map +1 -1
  27. package/dist/{commit-SS77KUNX.js → commit-534QIRHY.js} +3 -3
  28. package/dist/{compile-ZOAODFN2.js → compile-UANHMNTS.js} +3 -3
  29. package/dist/{dev-server-TYYJM3XA.js → dev-server-TO7RLYJI.js} +5 -5
  30. package/dist/{feedback-HZVLOTQJ.js → feedback-7ZZI6RC5.js} +2 -2
  31. package/dist/{ignite-CPXPZ4ZD.js → ignite-5SIGOW5V.js} +6 -6
  32. package/dist/{init-MZBIXQ7V.js → init-XXDIB2UJ.js} +4 -4
  33. package/dist/{lint-MDVUV3W2.js → lint-XPODLDVA.js} +3 -3
  34. package/dist/{open-2LPZ7XXW.js → open-M2SUR74Y.js} +5 -5
  35. package/dist/{plan-N3YDCOIV.js → plan-FB4AOJ2Q.js} +9 -9
  36. package/dist/prompts/init-prompt.txt +26 -2
  37. package/dist/{rebase-7YS3N274.js → rebase-4FNRBW3H.js} +3 -3
  38. package/dist/{run-XPGCMFFO.js → run-GZNHRJB2.js} +5 -5
  39. package/dist/{summary-5UWNLAI5.js → summary-Z4F7YFXE.js} +5 -5
  40. package/dist/{test-N2725YRI.js → test-LBSPYIJW.js} +3 -3
  41. package/dist/vscode-LH3VSQ2W.js +164 -0
  42. package/dist/vscode-LH3VSQ2W.js.map +1 -0
  43. package/dist/vscode-announcement-EQ2SKK3T.js +46 -0
  44. package/dist/vscode-announcement-EQ2SKK3T.js.map +1 -0
  45. package/package.json +2 -1
  46. package/dist/chunk-LFVRG6UU.js.map +0 -1
  47. /package/dist/{PRManager-XLTVG6YG.js.map → PRManager-A63LT3NF.js.map} +0 -0
  48. /package/dist/{build-H4DK3DMQ.js.map → build-Z3WCIKPD.js.map} +0 -0
  49. /package/dist/{chunk-A4UQY3M2.js.map → chunk-3FC3VNEX.js.map} +0 -0
  50. /package/dist/{chunk-YAVVDZVF.js.map → chunk-44Y5IF7P.js.map} +0 -0
  51. /package/dist/{chunk-ECP77QGE.js.map → chunk-A7XHHUEV.js.map} +0 -0
  52. /package/dist/{chunk-RODL2HVY.js.map → chunk-FPNSFP6K.js.map} +0 -0
  53. /package/dist/{chunk-WNXYC7J4.js.map → chunk-GWONJE3X.js.map} +0 -0
  54. /package/dist/{chunk-BCQDYAOJ.js.map → chunk-O6LECMT6.js.map} +0 -0
  55. /package/dist/{chunk-AZH27CPV.js.map → chunk-PBSHQVCT.js.map} +0 -0
  56. /package/dist/{chunk-QJX6ICWY.js.map → chunk-SC6X5EBG.js.map} +0 -0
  57. /package/dist/{chunk-L4CN7YQT.js.map → chunk-UDZCTLD6.js.map} +0 -0
  58. /package/dist/{cleanup-25PCP2EM.js.map → cleanup-NWNKWPUY.js.map} +0 -0
  59. /package/dist/{commit-SS77KUNX.js.map → commit-534QIRHY.js.map} +0 -0
  60. /package/dist/{compile-ZOAODFN2.js.map → compile-UANHMNTS.js.map} +0 -0
  61. /package/dist/{dev-server-TYYJM3XA.js.map → dev-server-TO7RLYJI.js.map} +0 -0
  62. /package/dist/{feedback-HZVLOTQJ.js.map → feedback-7ZZI6RC5.js.map} +0 -0
  63. /package/dist/{ignite-CPXPZ4ZD.js.map → ignite-5SIGOW5V.js.map} +0 -0
  64. /package/dist/{init-MZBIXQ7V.js.map → init-XXDIB2UJ.js.map} +0 -0
  65. /package/dist/{lint-MDVUV3W2.js.map → lint-XPODLDVA.js.map} +0 -0
  66. /package/dist/{open-2LPZ7XXW.js.map → open-M2SUR74Y.js.map} +0 -0
  67. /package/dist/{plan-N3YDCOIV.js.map → plan-FB4AOJ2Q.js.map} +0 -0
  68. /package/dist/{rebase-7YS3N274.js.map → rebase-4FNRBW3H.js.map} +0 -0
  69. /package/dist/{run-XPGCMFFO.js.map → run-GZNHRJB2.js.map} +0 -0
  70. /package/dist/{summary-5UWNLAI5.js.map → summary-Z4F7YFXE.js.map} +0 -0
  71. /package/dist/{test-N2725YRI.js.map → test-LBSPYIJW.js.map} +0 -0
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  SessionSummaryService
4
- } from "./chunk-AZH27CPV.js";
4
+ } from "./chunk-PBSHQVCT.js";
5
5
  import "./chunk-NXMDEL3F.js";
6
6
  import {
7
7
  CLIIsolationManager,
@@ -9,21 +9,29 @@ import {
9
9
  EnvironmentManager,
10
10
  LoomManager,
11
11
  ResourceCleanup
12
- } from "./chunk-WNXYC7J4.js";
12
+ } from "./chunk-GWONJE3X.js";
13
13
  import {
14
14
  launchFirstRunSetup,
15
15
  needsFirstRunSetup
16
- } from "./chunk-A4UQY3M2.js";
16
+ } from "./chunk-3FC3VNEX.js";
17
+ import {
18
+ CommitManager,
19
+ UserAbortedCommitError,
20
+ ValidationRunner
21
+ } from "./chunk-SSASIBDJ.js";
17
22
  import {
18
23
  BuildRunner,
19
24
  MergeManager
20
- } from "./chunk-ECP77QGE.js";
25
+ } from "./chunk-A7XHHUEV.js";
21
26
  import {
22
27
  IssueTrackerFactory
23
- } from "./chunk-QJX6ICWY.js";
28
+ } from "./chunk-SC6X5EBG.js";
24
29
  import {
25
30
  ProcessManager
26
31
  } from "./chunk-XHNACIHO.js";
32
+ import {
33
+ installDependencies
34
+ } from "./chunk-RD7I2Q2F.js";
27
35
  import "./chunk-52MVUK5V.js";
28
36
  import {
29
37
  IdentifierParser,
@@ -34,9 +42,12 @@ import {
34
42
  } from "./chunk-7ZEHSSUP.js";
35
43
  import {
36
44
  ShellCompletion
37
- } from "./chunk-RODL2HVY.js";
38
- import "./chunk-Q7POFB5Q.js";
45
+ } from "./chunk-FPNSFP6K.js";
46
+ import {
47
+ GitWorktreeManager
48
+ } from "./chunk-HSGZW3ID.js";
39
49
  import "./chunk-BYUMEDDD.js";
50
+ import "./chunk-Q7POFB5Q.js";
40
51
  import {
41
52
  IssueEnhancementService,
42
53
  capitalizeFirstLetter
@@ -45,31 +56,22 @@ import "./chunk-XJHQVOT6.js";
45
56
  import {
46
57
  ProjectCapabilityDetector
47
58
  } from "./chunk-7GLZVDPQ.js";
59
+ import "./chunk-XPKN3QWY.js";
48
60
  import {
49
61
  AgentManager
50
62
  } from "./chunk-4BSXZ5YZ.js";
51
63
  import {
52
- CommitManager,
53
- UserAbortedCommitError,
54
- ValidationRunner
55
- } from "./chunk-SSASIBDJ.js";
56
- import {
57
- installDependencies
58
- } from "./chunk-RD7I2Q2F.js";
64
+ PRManager
65
+ } from "./chunk-44Y5IF7P.js";
59
66
  import {
60
- GitWorktreeManager
61
- } from "./chunk-HSGZW3ID.js";
62
- import "./chunk-XPKN3QWY.js";
67
+ IssueManagementProviderFactory
68
+ } from "./chunk-UDZCTLD6.js";
63
69
  import {
64
- PRManager
65
- } from "./chunk-YAVVDZVF.js";
70
+ getLinearChildIssues
71
+ } from "./chunk-RNBIISBZ.js";
66
72
  import {
67
73
  openBrowser
68
74
  } from "./chunk-YETJNRQM.js";
69
- import {
70
- IssueManagementProviderFactory
71
- } from "./chunk-L4CN7YQT.js";
72
- import "./chunk-LFVRG6UU.js";
73
75
  import {
74
76
  getConfiguredRepoFromSettings,
75
77
  hasMultipleRemotes
@@ -112,7 +114,9 @@ import {
112
114
  import {
113
115
  GitHubService
114
116
  } from "./chunk-PVW6JE7E.js";
115
- import "./chunk-THS5L54H.js";
117
+ import {
118
+ getSubIssues
119
+ } from "./chunk-THS5L54H.js";
116
120
  import {
117
121
  promptConfirmation,
118
122
  waitForKeypress
@@ -351,7 +355,7 @@ var StartCommand = class {
351
355
  throw new Error("Missing required argument: identifier");
352
356
  }
353
357
  const spaceCount = (trimmedIdentifier.match(/ /g) ?? []).length;
354
- if (trimmedIdentifier.length > 25 && spaceCount >= 1) {
358
+ if (trimmedIdentifier.length > 15 && spaceCount >= 1) {
355
359
  return {
356
360
  type: "description",
357
361
  originalInput: hasLeadingSpace ? " " + trimmedIdentifier : trimmedIdentifier
@@ -1896,7 +1900,9 @@ function formatLoomForJson(worktree, mainWorktreePath, metadata) {
1896
1900
  projectPath: (metadata == null ? void 0 : metadata.projectPath) ?? null,
1897
1901
  issueUrls: (metadata == null ? void 0 : metadata.issueUrls) ?? {},
1898
1902
  prUrls: (metadata == null ? void 0 : metadata.prUrls) ?? {},
1899
- capabilities: (metadata == null ? void 0 : metadata.capabilities) ?? []
1903
+ capabilities: (metadata == null ? void 0 : metadata.capabilities) ?? [],
1904
+ isChildLoom: (metadata == null ? void 0 : metadata.parentLoom) != null,
1905
+ parentLoom: (metadata == null ? void 0 : metadata.parentLoom) ?? null
1900
1906
  };
1901
1907
  }
1902
1908
  function formatLoomsForJson(worktrees, mainWorktreePath, metadata) {
@@ -1923,10 +1929,114 @@ function formatFinishedLoomForJson(metadata) {
1923
1929
  prUrls: metadata.prUrls ?? {},
1924
1930
  capabilities: metadata.capabilities ?? [],
1925
1931
  status: metadata.status ?? "finished",
1926
- finishedAt: metadata.finishedAt ?? null
1932
+ finishedAt: metadata.finishedAt ?? null,
1933
+ isChildLoom: metadata.parentLoom != null,
1934
+ parentLoom: metadata.parentLoom ?? null
1927
1935
  };
1928
1936
  }
1929
1937
 
1938
+ // src/utils/list-children.ts
1939
+ async function fetchChildIssues(parentIssueNumber, settings, repo) {
1940
+ const providerName = IssueTrackerFactory.getProviderName(settings);
1941
+ logger.debug("Fetching child issues", { parentIssueNumber, provider: providerName, repo });
1942
+ const results = await Promise.allSettled([
1943
+ (async () => {
1944
+ if (providerName === "github") {
1945
+ const issueNum = parseInt(parentIssueNumber, 10);
1946
+ if (isNaN(issueNum)) {
1947
+ logger.warn(`Invalid GitHub issue number: ${parentIssueNumber}`);
1948
+ return [];
1949
+ }
1950
+ return getSubIssues(issueNum, repo);
1951
+ } else if (providerName === "linear") {
1952
+ return getLinearChildIssues(parentIssueNumber);
1953
+ } else {
1954
+ logger.warn(`Unsupported issue tracker provider: ${providerName}`);
1955
+ return [];
1956
+ }
1957
+ })()
1958
+ ]);
1959
+ const result = results[0];
1960
+ if (result.status === "fulfilled") {
1961
+ return result.value;
1962
+ } else {
1963
+ logger.warn(`Failed to fetch child issues for ${parentIssueNumber}`, { error: result.reason });
1964
+ return [];
1965
+ }
1966
+ }
1967
+ async function findChildLooms(parentBranchName, metadataManager) {
1968
+ logger.debug("Finding child looms", { parentBranchName });
1969
+ const allMetadata = await metadataManager.listAllMetadata();
1970
+ const childLooms = allMetadata.filter((metadata) => {
1971
+ if (!metadata.parentLoom) {
1972
+ return false;
1973
+ }
1974
+ return metadata.parentLoom.branchName === parentBranchName;
1975
+ });
1976
+ logger.debug(`Found ${childLooms.length} child looms for parent: ${parentBranchName}`);
1977
+ return childLooms;
1978
+ }
1979
+ function matchChildrenData(childIssues, childLooms) {
1980
+ const issueToLoomMap = /* @__PURE__ */ new Map();
1981
+ for (const loom of childLooms) {
1982
+ for (const issueNum of loom.issue_numbers) {
1983
+ issueToLoomMap.set(issueNum, loom);
1984
+ }
1985
+ }
1986
+ const childIssueIds = new Set(childIssues.map((issue) => issue.id));
1987
+ const matchedIssues = childIssues.map((issue) => {
1988
+ const matchingLoom = issueToLoomMap.get(issue.id);
1989
+ return {
1990
+ id: issue.id,
1991
+ title: issue.title,
1992
+ url: issue.url,
1993
+ state: issue.state,
1994
+ hasActiveLoom: matchingLoom != null,
1995
+ loomBranch: (matchingLoom == null ? void 0 : matchingLoom.branchName) ?? null
1996
+ };
1997
+ });
1998
+ const matchedLooms = childLooms.map((loom) => {
1999
+ const hasMatchingIssue = loom.issue_numbers.some((issueNum) => childIssueIds.has(issueNum));
2000
+ return {
2001
+ branch: loom.branchName ?? "",
2002
+ issueNumbers: loom.issue_numbers,
2003
+ hasMatchingIssue
2004
+ };
2005
+ });
2006
+ const summary = {
2007
+ totalIssues: matchedIssues.length,
2008
+ issuesWithLooms: matchedIssues.filter((issue) => issue.hasActiveLoom).length,
2009
+ totalLooms: matchedLooms.length,
2010
+ orphanLooms: matchedLooms.filter((loom) => !loom.hasMatchingIssue).length
2011
+ };
2012
+ return {
2013
+ issues: matchedIssues,
2014
+ looms: matchedLooms,
2015
+ summary
2016
+ };
2017
+ }
2018
+ async function assembleChildrenData(parentLoom, metadataManager, settings, repo) {
2019
+ if (!parentLoom.issue_numbers || parentLoom.issue_numbers.length === 0) {
2020
+ logger.debug("No issue_numbers on loom, skipping children fetch", {
2021
+ branch: parentLoom.branchName
2022
+ });
2023
+ return null;
2024
+ }
2025
+ if (!parentLoom.branchName) {
2026
+ logger.debug("No branchName on loom, skipping children fetch");
2027
+ return null;
2028
+ }
2029
+ const parentIssueNumber = parentLoom.issue_numbers[0];
2030
+ if (parentIssueNumber === void 0) {
2031
+ return null;
2032
+ }
2033
+ const [childIssues, childLooms] = await Promise.all([
2034
+ fetchChildIssues(parentIssueNumber, settings, repo),
2035
+ findChildLooms(parentLoom.branchName, metadataManager)
2036
+ ]);
2037
+ return matchChildrenData(childIssues, childLooms);
2038
+ }
2039
+
1930
2040
  // src/cli.ts
1931
2041
  import fs3 from "fs-extra";
1932
2042
 
@@ -2150,6 +2260,15 @@ program.name("iloom").description(packageJson.description).version(packageJson.v
2150
2260
  await validateSettingsForCommand(actionCommand);
2151
2261
  await validateGhCliForCommand(actionCommand);
2152
2262
  await validateIdeForStartCommand(actionCommand);
2263
+ }).hook("postAction", async (_thisCommand, actionCommand) => {
2264
+ try {
2265
+ const { showVSCodeAnnouncementIfNeeded } = await import("./vscode-announcement-EQ2SKK3T.js");
2266
+ const jsonMode = actionCommand.opts().json === true;
2267
+ if (!jsonMode) {
2268
+ await showVSCodeAnnouncementIfNeeded(actionCommand.name());
2269
+ }
2270
+ } catch {
2271
+ }
2153
2272
  });
2154
2273
  async function validateSettingsForCommand(command) {
2155
2274
  var _a, _b;
@@ -2276,7 +2395,7 @@ async function autoLaunchInitForMultipleRemotes() {
2276
2395
  await waitForKeypress2("Press any key to start configuration...");
2277
2396
  logger.info("");
2278
2397
  try {
2279
- const { InitCommand } = await import("./init-MZBIXQ7V.js");
2398
+ const { InitCommand } = await import("./init-XXDIB2UJ.js");
2280
2399
  const initCommand = new InitCommand();
2281
2400
  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.";
2282
2401
  await initCommand.execute(customInitialMessage);
@@ -2377,7 +2496,7 @@ program.command("add-issue").alias("a").description("Create and enhance GitHub i
2377
2496
  });
2378
2497
  program.command("feedback").alias("f").description("Submit feedback/bug report to iloom-cli repository").argument("<description>", "Feedback title (>30 chars, >2 spaces; or any non-empty text when --body provided)").option("--body <text>", "Body text for feedback (added after diagnostics)").action(async (description, options) => {
2379
2498
  try {
2380
- const { FeedbackCommand } = await import("./feedback-HZVLOTQJ.js");
2499
+ const { FeedbackCommand } = await import("./feedback-7ZZI6RC5.js");
2381
2500
  const command = new FeedbackCommand();
2382
2501
  const feedbackOptions = {};
2383
2502
  if (options.body !== void 0) {
@@ -2462,7 +2581,7 @@ program.command("finish").alias("dn").description("Merge work and cleanup worksp
2462
2581
  program.command("commit").alias("c").description("Commit all uncommitted files with issue reference").option("-m, --message <text>", "Custom commit message (skip Claude generation)").option("--fixes", 'Use "Fixes #N" trailer instead of "Refs #N" (closes issue)').option("--no-review", "Skip commit message review prompt").option("--json", "Output result as JSON (implies --no-review)").option("--wip-commit", "Quick WIP commit: skip validations and pre-commit hooks").action(async (options) => {
2463
2582
  const executeAction = async () => {
2464
2583
  try {
2465
- const { CommitCommand } = await import("./commit-SS77KUNX.js");
2584
+ const { CommitCommand } = await import("./commit-534QIRHY.js");
2466
2585
  const command = new CommitCommand();
2467
2586
  const noReview = options.review === false || options.json === true;
2468
2587
  const result = await command.execute({
@@ -2497,7 +2616,7 @@ program.command("commit").alias("c").description("Commit all uncommitted files w
2497
2616
  });
2498
2617
  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) => {
2499
2618
  try {
2500
- const { RebaseCommand } = await import("./rebase-7YS3N274.js");
2619
+ const { RebaseCommand } = await import("./rebase-4FNRBW3H.js");
2501
2620
  const command = new RebaseCommand();
2502
2621
  await command.execute(options);
2503
2622
  } catch (error) {
@@ -2509,7 +2628,7 @@ program.command("spin").alias("ignite").description("Launch Claude with auto-det
2509
2628
  new Option("--one-shot <mode>", "One-shot automation mode").choices(["default", "noReview", "bypassPermissions"])
2510
2629
  ).action(async (options) => {
2511
2630
  try {
2512
- const { IgniteCommand } = await import("./ignite-CPXPZ4ZD.js");
2631
+ const { IgniteCommand } = await import("./ignite-5SIGOW5V.js");
2513
2632
  const command = new IgniteCommand();
2514
2633
  await command.execute(options.oneShot);
2515
2634
  } catch (error) {
@@ -2520,7 +2639,7 @@ program.command("spin").alias("ignite").description("Launch Claude with auto-det
2520
2639
  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) => {
2521
2640
  try {
2522
2641
  const args = (command == null ? void 0 : command.args) ? command.args.slice(identifier ? 1 : 0) : [];
2523
- const { OpenCommand } = await import("./open-2LPZ7XXW.js");
2642
+ const { OpenCommand } = await import("./open-M2SUR74Y.js");
2524
2643
  const cmd = new OpenCommand();
2525
2644
  const input = identifier ? { identifier, args } : { args };
2526
2645
  await cmd.execute(input);
@@ -2532,7 +2651,7 @@ program.command("open").description("Open workspace in browser or run CLI tool")
2532
2651
  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) => {
2533
2652
  try {
2534
2653
  const args = (command == null ? void 0 : command.args) ? command.args.slice(identifier ? 1 : 0) : [];
2535
- const { RunCommand } = await import("./run-XPGCMFFO.js");
2654
+ const { RunCommand } = await import("./run-GZNHRJB2.js");
2536
2655
  const cmd = new RunCommand();
2537
2656
  const input = identifier ? { identifier, args } : { args };
2538
2657
  await cmd.execute(input);
@@ -2541,9 +2660,18 @@ program.command("run").description("Run CLI tool or open workspace in browser").
2541
2660
  process.exit(1);
2542
2661
  }
2543
2662
  });
2663
+ program.command("vscode").description("Install iloom VS Code extension and open workspace in VS Code").argument("[identifier]", "Issue number, PR number, or branch name (auto-detected if omitted)").option("--no-wait", "Skip keypress prompt and open immediately").action(async (identifier, options) => {
2664
+ try {
2665
+ const { VSCodeCommand } = await import("./vscode-LH3VSQ2W.js");
2666
+ const cmd = new VSCodeCommand();
2667
+ await cmd.execute({ identifier, wait: options == null ? void 0 : options.wait });
2668
+ } catch (error) {
2669
+ throw new Error(`Failed to open VS Code: ${error instanceof Error ? error.message : "Unknown error"}`);
2670
+ }
2671
+ });
2544
2672
  program.command("dev-server").alias("dev").description("Start dev server for workspace (foreground)").argument("[identifier]", "Issue number, PR number, or branch name (auto-detected if omitted)").option("--json", "Output as JSON").action(async (identifier, options) => {
2545
2673
  try {
2546
- const { DevServerCommand } = await import("./dev-server-TYYJM3XA.js");
2674
+ const { DevServerCommand } = await import("./dev-server-TO7RLYJI.js");
2547
2675
  const cmd = new DevServerCommand();
2548
2676
  await cmd.execute({ identifier, json: options == null ? void 0 : options.json });
2549
2677
  } catch (error) {
@@ -2563,7 +2691,7 @@ program.command("shell").alias("terminal").description("Open interactive shell w
2563
2691
  });
2564
2692
  program.command("build").description("Run the build script").argument("[identifier]", "Issue number, PR number, or branch name (auto-detected if omitted)").action(async (identifier) => {
2565
2693
  try {
2566
- const { BuildCommand } = await import("./build-H4DK3DMQ.js");
2694
+ const { BuildCommand } = await import("./build-Z3WCIKPD.js");
2567
2695
  const cmd = new BuildCommand();
2568
2696
  await cmd.execute(identifier ? { identifier } : {});
2569
2697
  } catch (error) {
@@ -2573,7 +2701,7 @@ program.command("build").description("Run the build script").argument("[identifi
2573
2701
  });
2574
2702
  program.command("lint").description("Run the lint script").argument("[identifier]", "Issue number, PR number, or branch name (auto-detected if omitted)").action(async (identifier) => {
2575
2703
  try {
2576
- const { LintCommand } = await import("./lint-MDVUV3W2.js");
2704
+ const { LintCommand } = await import("./lint-XPODLDVA.js");
2577
2705
  const cmd = new LintCommand();
2578
2706
  await cmd.execute(identifier ? { identifier } : {});
2579
2707
  } catch (error) {
@@ -2583,7 +2711,7 @@ program.command("lint").description("Run the lint script").argument("[identifier
2583
2711
  });
2584
2712
  program.command("test").description("Run the test script").argument("[identifier]", "Issue number, PR number, or branch name (auto-detected if omitted)").action(async (identifier) => {
2585
2713
  try {
2586
- const { TestCommand } = await import("./test-N2725YRI.js");
2714
+ const { TestCommand } = await import("./test-LBSPYIJW.js");
2587
2715
  const cmd = new TestCommand();
2588
2716
  await cmd.execute(identifier ? { identifier } : {});
2589
2717
  } catch (error) {
@@ -2593,7 +2721,7 @@ program.command("test").description("Run the test script").argument("[identifier
2593
2721
  });
2594
2722
  program.command("compile").alias("typecheck").description("Run the compile or typecheck script (prefers compile if both exist)").argument("[identifier]", "Issue number, PR number, or branch name (auto-detected if omitted)").action(async (identifier) => {
2595
2723
  try {
2596
- const { CompileCommand } = await import("./compile-ZOAODFN2.js");
2724
+ const { CompileCommand } = await import("./compile-UANHMNTS.js");
2597
2725
  const cmd = new CompileCommand();
2598
2726
  await cmd.execute(identifier ? { identifier } : {});
2599
2727
  } catch (error) {
@@ -2604,7 +2732,7 @@ program.command("compile").alias("typecheck").description("Run the compile or ty
2604
2732
  program.command("cleanup").alias("remove").alias("clean").description("Remove workspaces").argument("[identifier]", "Branch name or issue number to cleanup (auto-detected)").option("-l, --list", "List all worktrees").option("-a, --all", "Remove all worktrees (interactive confirmation)").option("-i, --issue <number>", "Cleanup by issue number", parseInt).option("-f, --force", "Skip confirmations and force removal").option("--dry-run", "Show what would be done without doing it").option("--json", "Output result as JSON").option("--defer <ms>", "Wait specified milliseconds before cleanup", parseInt).action(async (identifier, options) => {
2605
2733
  const executeAction = async () => {
2606
2734
  try {
2607
- const { CleanupCommand } = await import("./cleanup-25PCP2EM.js");
2735
+ const { CleanupCommand } = await import("./cleanup-NWNKWPUY.js");
2608
2736
  const command = new CleanupCommand();
2609
2737
  const input = {
2610
2738
  options: options ?? {}
@@ -2633,7 +2761,7 @@ program.command("cleanup").alias("remove").alias("clean").description("Remove wo
2633
2761
  await executeAction();
2634
2762
  }
2635
2763
  });
2636
- program.command("list").description("Show active workspaces").option("--json", "Output as JSON").option("--finished", "Show only finished looms (sorted by finish time, latest first)").option("--all", "Show both active and finished looms").option("--global", "Show looms from all projects (default: current project only)").action(async (options) => {
2764
+ program.command("list").description("Show active workspaces").option("--json", "Output as JSON").option("--finished", "Show only finished looms (sorted by finish time, latest first)").option("--all", "Show both active and finished looms").option("--global", "Show looms from all projects (default: current project only)").option("--children", "Fetch and display child issues and child looms for each parent loom").action(async (options) => {
2637
2765
  try {
2638
2766
  const manager = new GitWorktreeManager();
2639
2767
  const metadataManager = new MetadataManager();
@@ -2732,7 +2860,9 @@ program.command("list").description("Show active workspaces").option("--json", "
2732
2860
  issueUrls: loom.issueUrls ?? {},
2733
2861
  prUrls: loom.prUrls ?? {},
2734
2862
  status: "active",
2735
- finishedAt: null
2863
+ finishedAt: null,
2864
+ isChildLoom: loom.parentLoom != null,
2865
+ parentLoom: loom.parentLoom ?? null
2736
2866
  }));
2737
2867
  } else {
2738
2868
  activeJson = formatLoomsForJson(worktrees, mainWorktreePath, metadata).map((loom) => ({
@@ -2753,6 +2883,47 @@ program.command("list").description("Show active workspaces").option("--json", "
2753
2883
  (loom) => loom.projectPath == null || loom.projectPath === currentProjectPath
2754
2884
  );
2755
2885
  }
2886
+ if (options.children) {
2887
+ const settingsManager = new SettingsManager();
2888
+ const settings = await settingsManager.loadSettings();
2889
+ const activeChildrenResults = await Promise.allSettled(
2890
+ activeJson.map(async (loom) => {
2891
+ const index = activeJson.indexOf(loom);
2892
+ const loomMetadata = options.global ? globalActiveLooms.find((m) => m.branchName === loom.branch) : metadata.get(loom.worktreePath ?? "");
2893
+ if (!loomMetadata) {
2894
+ return { index, children: null };
2895
+ }
2896
+ const children = await assembleChildrenData(loomMetadata, metadataManager, settings);
2897
+ return { index, children };
2898
+ })
2899
+ );
2900
+ for (const result of activeChildrenResults) {
2901
+ if (result.status === "fulfilled" && result.value.children) {
2902
+ const loom = activeJson[result.value.index];
2903
+ if (loom) {
2904
+ loom.children = result.value.children;
2905
+ }
2906
+ }
2907
+ }
2908
+ const finishedChildrenResults = await Promise.allSettled(
2909
+ finishedJson.map(async (loom, index) => {
2910
+ const loomMetadata = finishedLooms.find((m) => m.branchName === loom.branch);
2911
+ if (!loomMetadata) {
2912
+ return { index, children: null };
2913
+ }
2914
+ const children = await assembleChildrenData(loomMetadata, metadataManager, settings);
2915
+ return { index, children };
2916
+ })
2917
+ );
2918
+ for (const result of finishedChildrenResults) {
2919
+ if (result.status === "fulfilled" && result.value.children) {
2920
+ const loom = finishedJson[result.value.index];
2921
+ if (loom) {
2922
+ loom.children = result.value.children;
2923
+ }
2924
+ }
2925
+ }
2926
+ }
2756
2927
  const allLooms = [...activeJson, ...finishedJson];
2757
2928
  console.log(JSON.stringify(allLooms, null, 2));
2758
2929
  return;
@@ -2769,11 +2940,20 @@ program.command("list").description("Show active workspaces").option("--json", "
2769
2940
  }
2770
2941
  return;
2771
2942
  }
2943
+ let textSettings = null;
2944
+ if (options.children) {
2945
+ const settingsManager = new SettingsManager();
2946
+ textSettings = await settingsManager.loadSettings();
2947
+ }
2772
2948
  if (showActive && hasActive) {
2773
2949
  logger.info("Active workspaces:");
2774
2950
  if (options.global) {
2775
2951
  for (const loom of filteredGlobalActiveLooms) {
2776
- logger.info(` ${loom.branchName ?? "unknown"}`);
2952
+ if (loom.parentLoom) {
2953
+ logger.info(` ${loom.branchName ?? "unknown"} (Child of: ${loom.parentLoom.branchName})`);
2954
+ } else {
2955
+ logger.info(` ${loom.branchName ?? "unknown"}`);
2956
+ }
2777
2957
  if (loom.description) {
2778
2958
  logger.info(` Description: ${loom.description}`);
2779
2959
  }
@@ -2783,17 +2963,43 @@ program.command("list").description("Show active workspaces").option("--json", "
2783
2963
  if (loom.projectPath) {
2784
2964
  logger.info(` Project: ${loom.projectPath}`);
2785
2965
  }
2966
+ if (options.children && textSettings) {
2967
+ const childrenData = await assembleChildrenData(loom, metadataManager, textSettings);
2968
+ if (childrenData && (childrenData.summary.totalIssues > 0 || childrenData.summary.totalLooms > 0)) {
2969
+ logger.info(` Child Issues: ${childrenData.summary.totalIssues} (${childrenData.summary.issuesWithLooms} with active looms)`);
2970
+ for (const issue of childrenData.issues) {
2971
+ if (!issue.hasActiveLoom) {
2972
+ logger.info(` [No loom] #${issue.id} - ${issue.title} (${issue.state})`);
2973
+ }
2974
+ }
2975
+ }
2976
+ }
2786
2977
  }
2787
2978
  } else {
2788
2979
  for (const worktree of filteredWorktrees) {
2789
2980
  const formatted = manager.formatWorktree(worktree);
2790
2981
  const loomMetadata = metadata.get(worktree.path);
2791
- logger.info(` ${formatted.title}`);
2982
+ if (loomMetadata == null ? void 0 : loomMetadata.parentLoom) {
2983
+ logger.info(` ${formatted.title} (Child of: ${loomMetadata.parentLoom.branchName})`);
2984
+ } else {
2985
+ logger.info(` ${formatted.title}`);
2986
+ }
2792
2987
  if (loomMetadata == null ? void 0 : loomMetadata.description) {
2793
2988
  logger.info(` Description: ${loomMetadata.description}`);
2794
2989
  }
2795
2990
  logger.info(` Path: ${formatted.path}`);
2796
2991
  logger.info(` Commit: ${formatted.commit}`);
2992
+ if (options.children && textSettings && loomMetadata) {
2993
+ const childrenData = await assembleChildrenData(loomMetadata, metadataManager, textSettings);
2994
+ if (childrenData && (childrenData.summary.totalIssues > 0 || childrenData.summary.totalLooms > 0)) {
2995
+ logger.info(` Child Issues: ${childrenData.summary.totalIssues} (${childrenData.summary.issuesWithLooms} with active looms)`);
2996
+ for (const issue of childrenData.issues) {
2997
+ if (!issue.hasActiveLoom) {
2998
+ logger.info(` [No loom] #${issue.id} - ${issue.title} (${issue.state})`);
2999
+ }
3000
+ }
3001
+ }
3002
+ }
2797
3003
  }
2798
3004
  }
2799
3005
  }
@@ -2803,13 +3009,28 @@ program.command("list").description("Show active workspaces").option("--json", "
2803
3009
  }
2804
3010
  logger.info("Finished looms:");
2805
3011
  for (const loom of filteredFinishedLooms) {
2806
- logger.info(` ${loom.branchName ?? "unknown"}`);
3012
+ if (loom.parentLoom) {
3013
+ logger.info(` ${loom.branchName ?? "unknown"} (Child of: ${loom.parentLoom.branchName})`);
3014
+ } else {
3015
+ logger.info(` ${loom.branchName ?? "unknown"}`);
3016
+ }
2807
3017
  if (loom.description) {
2808
3018
  logger.info(` Description: ${loom.description}`);
2809
3019
  }
2810
3020
  if (loom.finishedAt) {
2811
3021
  logger.info(` Finished: ${new Date(loom.finishedAt).toLocaleString()}`);
2812
3022
  }
3023
+ if (options.children && textSettings) {
3024
+ const childrenData = await assembleChildrenData(loom, metadataManager, textSettings);
3025
+ if (childrenData && (childrenData.summary.totalIssues > 0 || childrenData.summary.totalLooms > 0)) {
3026
+ logger.info(` Child Issues: ${childrenData.summary.totalIssues} (${childrenData.summary.issuesWithLooms} with active looms)`);
3027
+ for (const issue of childrenData.issues) {
3028
+ if (!issue.hasActiveLoom) {
3029
+ logger.info(` [No loom] #${issue.id} - ${issue.title} (${issue.state})`);
3030
+ }
3031
+ }
3032
+ }
3033
+ }
2813
3034
  }
2814
3035
  }
2815
3036
  } catch (error) {
@@ -2838,7 +3059,7 @@ program.command("projects").description("List configured iloom projects").option
2838
3059
  });
2839
3060
  program.command("init").alias("config").description("Initialize iloom configuration").argument("[prompt]", 'Custom initial message to send to Claude (defaults to "Help me configure iloom settings.")').action(async (prompt) => {
2840
3061
  try {
2841
- const { InitCommand } = await import("./init-MZBIXQ7V.js");
3062
+ const { InitCommand } = await import("./init-XXDIB2UJ.js");
2842
3063
  const command = new InitCommand();
2843
3064
  const trimmedPrompt = prompt == null ? void 0 : prompt.trim();
2844
3065
  const customPrompt = trimmedPrompt && trimmedPrompt.length > 0 ? trimmedPrompt : void 0;
@@ -2850,7 +3071,7 @@ program.command("init").alias("config").description("Initialize iloom configurat
2850
3071
  });
2851
3072
  program.command("plan").description("Launch interactive planning session with Architect persona").argument("[prompt]", "Initial planning prompt or topic").option("--model <model>", "Model to use (default: opus)").option("--yolo", "Enable autonomous mode - Claude proceeds without user interaction").option("--planner <provider>", "AI provider for planning: claude, gemini, codex (default: claude)").option("--reviewer <provider>", "AI provider for review: claude, gemini, codex, none (default: none)").action(async (prompt, options) => {
2852
3073
  try {
2853
- const { PlanCommand } = await import("./plan-N3YDCOIV.js");
3074
+ const { PlanCommand } = await import("./plan-FB4AOJ2Q.js");
2854
3075
  const command = new PlanCommand();
2855
3076
  await command.execute(prompt, options == null ? void 0 : options.model, options == null ? void 0 : options.yolo, options == null ? void 0 : options.planner, options == null ? void 0 : options.reviewer);
2856
3077
  } catch (error) {
@@ -3130,7 +3351,7 @@ program.command("test-prefix").description("Test worktree prefix configuration -
3130
3351
  program.command("summary").description("Generate Claude session summary for a loom").argument("[identifier]", "Issue number, PR number (pr/123), or branch name (auto-detected if omitted)").option("--with-comment", "Post summary as a comment to the issue/PR").option("--json", "Output result as JSON").action(async (identifier, options) => {
3131
3352
  const executeAction = async () => {
3132
3353
  try {
3133
- const { SummaryCommand } = await import("./summary-5UWNLAI5.js");
3354
+ const { SummaryCommand } = await import("./summary-Z4F7YFXE.js");
3134
3355
  const command = new SummaryCommand();
3135
3356
  const result = await command.execute({ identifier, options });
3136
3357
  if (options.json && result) {