@iloom/cli 0.4.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/dist/{BranchNamingService-TOM2KAUT.js → BranchNamingService-GCCWB3LK.js} +2 -2
  2. package/dist/{ClaudeContextManager-VEGJTS5E.js → ClaudeContextManager-DK77227F.js} +6 -6
  3. package/dist/{ClaudeService-ICSHJMQ5.js → ClaudeService-W3SA7HVG.js} +5 -5
  4. package/dist/{LoomLauncher-SJBZFZXE.js → LoomLauncher-S3YGJRJQ.js} +24 -11
  5. package/dist/LoomLauncher-S3YGJRJQ.js.map +1 -0
  6. package/dist/{chunk-TR5MC2U6.js → chunk-2W2FBL5G.js} +2 -2
  7. package/dist/{chunk-HVGQP44L.js → chunk-55TB3FSG.js} +2 -2
  8. package/dist/{chunk-LTNDJMTH.js → chunk-BIIQHEXJ.js} +4 -4
  9. package/dist/{chunk-KM3W7YQX.js → chunk-G6CIIJLT.js} +4 -4
  10. package/dist/{chunk-NFVFVYAP.js → chunk-IARWMDAX.js} +19 -12
  11. package/dist/chunk-IARWMDAX.js.map +1 -0
  12. package/dist/{chunk-MLS5FAV7.js → chunk-IJ7IGJT3.js} +4 -1
  13. package/dist/chunk-IJ7IGJT3.js.map +1 -0
  14. package/dist/{chunk-M5XUCTTJ.js → chunk-JC5HXN75.js} +2 -2
  15. package/dist/{chunk-ADDNFQJ4.js → chunk-POI7KLBH.js} +2 -2
  16. package/dist/{chunk-P2WZIDF3.js → chunk-QIUJPPJQ.js} +2 -2
  17. package/dist/{chunk-75B2HZZ5.js → chunk-RUC7OULH.js} +2 -2
  18. package/dist/{chunk-HHDSIE72.js → chunk-TMZAVPGF.js} +3 -3
  19. package/dist/{chunk-F4J6KEL6.js → chunk-UPUAQYAW.js} +2 -2
  20. package/dist/{chunk-JJUPY5MM.js → chunk-VAYGNQTE.js} +2 -2
  21. package/dist/{chunk-S44CHE3G.js → chunk-VTXCGKV5.js} +2 -2
  22. package/dist/{chunk-3NFBZRPR.js → chunk-Z5NXYJIG.js} +19 -1
  23. package/dist/chunk-Z5NXYJIG.js.map +1 -0
  24. package/dist/{claude-X7EBJRB2.js → claude-ACVXNB6N.js} +4 -4
  25. package/dist/{cleanup-7QVPYBJJ.js → cleanup-KDLVTT7M.js} +12 -12
  26. package/dist/cli.js +95 -48
  27. package/dist/cli.js.map +1 -1
  28. package/dist/{contribute-RZYCYUDX.js → contribute-HY372S6F.js} +3 -3
  29. package/dist/{dev-server-LOY7YWCP.js → dev-server-JCJGQ3PV.js} +9 -9
  30. package/dist/{feedback-562KPG5U.js → feedback-7PVBQNLJ.js} +5 -5
  31. package/dist/{git-OXJACVAU.js → git-4BVOOOOV.js} +3 -3
  32. package/dist/{ignite-VSIPGKKG.js → ignite-3B264M7K.js} +7 -7
  33. package/dist/index.d.ts +2 -0
  34. package/dist/index.js +3 -0
  35. package/dist/index.js.map +1 -1
  36. package/dist/{init-SCR2LQ4A.js → init-LBA6NUK2.js} +8 -8
  37. package/dist/{open-CX7HUE26.js → open-OGCV32Z4.js} +9 -9
  38. package/dist/{projects-6DTNDVLH.js → projects-P55273AB.js} +2 -2
  39. package/dist/{rebase-55URTXZC.js → rebase-4T5FQHNH.js} +8 -8
  40. package/dist/{run-DP2U2CA2.js → run-HNOP6WE2.js} +9 -9
  41. package/dist/shell-DE3HKJSM.js +240 -0
  42. package/dist/shell-DE3HKJSM.js.map +1 -0
  43. package/dist/{summary-J3CJSM7L.js → summary-GDT7DTRI.js} +8 -8
  44. package/dist/{test-git-QLAIBJLX.js → test-git-YMAE57UP.js} +3 -3
  45. package/dist/{test-prefix-6YM2ZOON.js → test-prefix-YCKL6CMT.js} +3 -3
  46. package/dist/{test-tabs-JGO3VOXJ.js → test-tabs-3SCJWRKT.js} +3 -3
  47. package/package.json +1 -1
  48. package/dist/LoomLauncher-SJBZFZXE.js.map +0 -1
  49. package/dist/chunk-3NFBZRPR.js.map +0 -1
  50. package/dist/chunk-MLS5FAV7.js.map +0 -1
  51. package/dist/chunk-NFVFVYAP.js.map +0 -1
  52. /package/dist/{BranchNamingService-TOM2KAUT.js.map → BranchNamingService-GCCWB3LK.js.map} +0 -0
  53. /package/dist/{ClaudeContextManager-VEGJTS5E.js.map → ClaudeContextManager-DK77227F.js.map} +0 -0
  54. /package/dist/{ClaudeService-ICSHJMQ5.js.map → ClaudeService-W3SA7HVG.js.map} +0 -0
  55. /package/dist/{chunk-TR5MC2U6.js.map → chunk-2W2FBL5G.js.map} +0 -0
  56. /package/dist/{chunk-HVGQP44L.js.map → chunk-55TB3FSG.js.map} +0 -0
  57. /package/dist/{chunk-LTNDJMTH.js.map → chunk-BIIQHEXJ.js.map} +0 -0
  58. /package/dist/{chunk-KM3W7YQX.js.map → chunk-G6CIIJLT.js.map} +0 -0
  59. /package/dist/{chunk-M5XUCTTJ.js.map → chunk-JC5HXN75.js.map} +0 -0
  60. /package/dist/{chunk-ADDNFQJ4.js.map → chunk-POI7KLBH.js.map} +0 -0
  61. /package/dist/{chunk-P2WZIDF3.js.map → chunk-QIUJPPJQ.js.map} +0 -0
  62. /package/dist/{chunk-75B2HZZ5.js.map → chunk-RUC7OULH.js.map} +0 -0
  63. /package/dist/{chunk-HHDSIE72.js.map → chunk-TMZAVPGF.js.map} +0 -0
  64. /package/dist/{chunk-F4J6KEL6.js.map → chunk-UPUAQYAW.js.map} +0 -0
  65. /package/dist/{chunk-JJUPY5MM.js.map → chunk-VAYGNQTE.js.map} +0 -0
  66. /package/dist/{chunk-S44CHE3G.js.map → chunk-VTXCGKV5.js.map} +0 -0
  67. /package/dist/{claude-X7EBJRB2.js.map → claude-ACVXNB6N.js.map} +0 -0
  68. /package/dist/{cleanup-7QVPYBJJ.js.map → cleanup-KDLVTT7M.js.map} +0 -0
  69. /package/dist/{contribute-RZYCYUDX.js.map → contribute-HY372S6F.js.map} +0 -0
  70. /package/dist/{dev-server-LOY7YWCP.js.map → dev-server-JCJGQ3PV.js.map} +0 -0
  71. /package/dist/{feedback-562KPG5U.js.map → feedback-7PVBQNLJ.js.map} +0 -0
  72. /package/dist/{git-OXJACVAU.js.map → git-4BVOOOOV.js.map} +0 -0
  73. /package/dist/{ignite-VSIPGKKG.js.map → ignite-3B264M7K.js.map} +0 -0
  74. /package/dist/{init-SCR2LQ4A.js.map → init-LBA6NUK2.js.map} +0 -0
  75. /package/dist/{open-CX7HUE26.js.map → open-OGCV32Z4.js.map} +0 -0
  76. /package/dist/{projects-6DTNDVLH.js.map → projects-P55273AB.js.map} +0 -0
  77. /package/dist/{rebase-55URTXZC.js.map → rebase-4T5FQHNH.js.map} +0 -0
  78. /package/dist/{run-DP2U2CA2.js.map → run-HNOP6WE2.js.map} +0 -0
  79. /package/dist/{summary-J3CJSM7L.js.map → summary-GDT7DTRI.js.map} +0 -0
  80. /package/dist/{test-git-QLAIBJLX.js.map → test-git-YMAE57UP.js.map} +0 -0
  81. /package/dist/{test-prefix-6YM2ZOON.js.map → test-prefix-YCKL6CMT.js.map} +0 -0
  82. /package/dist/{test-tabs-JGO3VOXJ.js.map → test-tabs-3SCJWRKT.js.map} +0 -0
@@ -117,6 +117,22 @@ function loadEnvIntoProcess(options) {
117
117
  }
118
118
  return returnValue;
119
119
  }
120
+ function isNoEnvFilesFoundError(error) {
121
+ return error.message.startsWith('no ".env*" files matching pattern');
122
+ }
123
+ function loadWorkspaceEnv(workspacePath) {
124
+ const nodeEnv = process.env.NODE_ENV ?? "development";
125
+ logger.debug("Loading workspace environment variables", {
126
+ workspacePath,
127
+ detectedNodeEnv: nodeEnv,
128
+ processNodeEnv: process.env.NODE_ENV ?? "not set"
129
+ });
130
+ return loadEnvIntoProcess({
131
+ path: workspacePath,
132
+ nodeEnv,
133
+ defaultNodeEnv: "development"
134
+ });
135
+ }
120
136
  var DOTENV_FLOW_NODE_ENV = process.env.DOTENV_FLOW_NODE_ENV ?? "development";
121
137
  function getDotenvFlowFiles() {
122
138
  return [
@@ -180,10 +196,12 @@ export {
180
196
  validateEnvVariable,
181
197
  extractPort,
182
198
  loadEnvIntoProcess,
199
+ isNoEnvFilesFoundError,
200
+ loadWorkspaceEnv,
183
201
  getDotenvFlowFiles,
184
202
  findEnvFileForDatabaseUrl,
185
203
  buildEnvSourceCommands,
186
204
  findEnvFileContainingVariable,
187
205
  hasVariableInAnyEnvFile
188
206
  };
189
- //# sourceMappingURL=chunk-3NFBZRPR.js.map
207
+ //# sourceMappingURL=chunk-Z5NXYJIG.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/env.ts"],"sourcesContent":["import path from 'path'\nimport dotenvFlow, { type DotenvFlowConfigOptions } from 'dotenv-flow'\nimport { logger } from './logger.js'\n\n/**\n * Parse .env file content into key-value map\n * Handles comments, empty lines, quoted/unquoted values, multiline values\n */\nexport function parseEnvFile(content: string): Map<string, string> {\n const envMap = new Map<string, string>()\n const lines = content.split('\\n')\n\n for (const line of lines) {\n const trimmedLine = line.trim()\n\n // Skip empty lines and comments\n if (!trimmedLine || trimmedLine.startsWith('#')) {\n continue\n }\n\n // Remove 'export ' prefix if present\n const cleanLine = trimmedLine.startsWith('export ')\n ? trimmedLine.substring(7)\n : trimmedLine\n\n // Find the first equals sign\n const equalsIndex = cleanLine.indexOf('=')\n if (equalsIndex === -1) {\n continue\n }\n\n const key = cleanLine.substring(0, equalsIndex).trim()\n let value = cleanLine.substring(equalsIndex + 1)\n\n // Handle quoted values\n if (\n (value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))\n ) {\n value = value.substring(1, value.length - 1)\n // Unescape quotes\n value = value.replace(/\\\\\"/g, '\"').replace(/\\\\'/g, \"'\")\n // Unescape newlines\n value = value.replace(/\\\\n/g, '\\n')\n }\n\n if (key) {\n envMap.set(key, value)\n }\n }\n\n return envMap\n}\n\n/**\n * Format environment variable as line for .env file\n * Always quotes values and escapes internal quotes\n */\nexport function formatEnvLine(key: string, value: string): string {\n // Escape quotes and newlines in the value\n const escapedValue = value\n .replace(/\"/g, '\\\\\"')\n .replace(/\\n/g, '\\\\n')\n .replace(/\\r/g, '\\\\r')\n\n return `${key}=\"${escapedValue}\"`\n}\n\n/**\n * Validate environment variable name and value\n */\nexport function validateEnvVariable(\n key: string,\n _value?: string\n): { valid: boolean; error?: string } {\n if (!key || key.length === 0) {\n return {\n valid: false,\n error: 'Environment variable key cannot be empty',\n }\n }\n\n if (!isValidEnvKey(key)) {\n return {\n valid: false,\n error: `Invalid environment variable name: ${key}. Must start with a letter or underscore and contain only letters, numbers, and underscores.`,\n }\n }\n\n // Values can be any string, including empty\n return { valid: true }\n}\n\n/**\n * Normalize line endings for cross-platform compatibility\n */\nexport function normalizeLineEndings(content: string): string {\n return content.replace(/\\r\\n/g, '\\n').replace(/\\r/g, '\\n')\n}\n\n/**\n * Extract port from .env file if present\n */\nexport function extractPort(envContent: Map<string, string>): number | null {\n const portValue = envContent.get('PORT')\n if (!portValue) {\n return null\n }\n\n const port = parseInt(portValue, 10)\n if (isNaN(port)) {\n return null\n }\n\n return port\n}\n\n/**\n * Check if environment variable key is valid\n */\nexport function isValidEnvKey(key: string): boolean {\n if (!key || key.length === 0) {\n return false\n }\n\n // Must start with letter or underscore, followed by letters, numbers, or underscores\n const validKeyRegex = /^[A-Za-z_][A-Za-z0-9_]*$/\n return validKeyRegex.test(key)\n}\n\n/**\n * Load environment variables using dotenv-flow\n * Supports environment-specific files (.env.development, .env.production, etc.)\n * and local overrides (.env.local, .env.development.local)\n */\nexport function loadEnvIntoProcess(options?: {\n path?: string\n nodeEnv?: string\n defaultNodeEnv?: string\n}): { parsed?: Record<string, string>; error?: Error } {\n logger.debug('Loading environment variables with dotenv-flow', {\n options: {\n path: options?.path ?? 'current working directory',\n nodeEnv: options?.nodeEnv ?? 'not specified',\n defaultNodeEnv: options?.defaultNodeEnv ?? 'development (default)'\n }\n })\n\n const configOptions: Partial<DotenvFlowConfigOptions> = {\n silent: true, // Don't throw errors if .env files are missing\n }\n\n // Only add defined values to avoid TypeScript strict type issues\n if (options?.path !== undefined) {\n configOptions.path = options.path\n logger.debug(`Using custom path: ${options.path}`)\n }\n if (options?.nodeEnv !== undefined) {\n configOptions.node_env = options.nodeEnv\n logger.debug(`Using NODE_ENV: ${options.nodeEnv}`)\n }\n if (options?.defaultNodeEnv !== undefined) {\n configOptions.default_node_env = options.defaultNodeEnv\n logger.debug(`Using default NODE_ENV: ${options.defaultNodeEnv}`)\n } else {\n configOptions.default_node_env = 'development'\n logger.debug('Using default NODE_ENV: development')\n }\n\n logger.debug('dotenv-flow config options:', configOptions)\n\n const result = dotenvFlow.config(configOptions)\n\n const returnValue: { parsed?: Record<string, string>; error?: Error } = {}\n\n if (result.parsed) {\n returnValue.parsed = result.parsed as Record<string, string>\n const variableCount = Object.keys(result.parsed).length\n logger.debug(`Successfully loaded ${variableCount} environment variables`)\n } else {\n logger.debug('No environment variables were parsed')\n }\n\n if (result.error) {\n returnValue.error = result.error\n logger.debug('dotenv-flow returned an error', {\n error: result.error.message,\n name: result.error.name\n })\n } else {\n logger.debug('dotenv-flow completed without errors')\n }\n\n return returnValue\n}\n\n/**\n * Check if an error from loadEnvIntoProcess indicates no .env files were found\n * This is a harmless condition that shouldn't be logged as a warning\n */\nexport function isNoEnvFilesFoundError(error: Error): boolean {\n return error.message.startsWith('no \".env*\" files matching pattern')\n}\n\n/**\n * Load environment variables for a specific workspace\n * Automatically determines environment based on NODE_ENV or defaults to development\n */\nexport function loadWorkspaceEnv(workspacePath: string): {\n parsed?: Record<string, string>\n error?: Error\n} {\n const nodeEnv = process.env.NODE_ENV ?? 'development'\n\n logger.debug('Loading workspace environment variables', {\n workspacePath,\n detectedNodeEnv: nodeEnv,\n processNodeEnv: process.env.NODE_ENV ?? 'not set'\n })\n\n return loadEnvIntoProcess({\n path: workspacePath,\n nodeEnv: nodeEnv,\n defaultNodeEnv: 'development'\n })\n}\n\n// CONSTANT: Always use 'development' per critical constraint, unless overridden\nconst DOTENV_FLOW_NODE_ENV = process.env.DOTENV_FLOW_NODE_ENV ?? 'development'\n\n/**\n * Get dotenv-flow files in precedence order (lowest to highest)\n * Always uses 'development' as NODE_ENV per constraint\n */\nexport function getDotenvFlowFiles(): string[] {\n return [\n '.env',\n '.env.local',\n `.env.${DOTENV_FLOW_NODE_ENV}`,\n `.env.${DOTENV_FLOW_NODE_ENV}.local`\n ]\n}\n\n/**\n * Map a file to its \"local\" equivalent for git-safe writes\n * .env -> .env.local\n * .env.{NODE_ENV} -> .env.{NODE_ENV}.local\n * Already local files return unchanged\n */\nexport function getLocalEquivalent(filename: string): string {\n // Already a .local file\n if (filename.endsWith('.local')) {\n return filename\n }\n return `${filename}.local`\n}\n\n/**\n * Find the appropriate env file to write a database URL variable to\n * Considers dotenv-flow precedence and git tracking status\n * Returns path relative to workspacePath\n *\n * Algorithm:\n * 1. Search files in reverse precedence order (highest first)\n * 2. Find first file containing the variable\n * 3. If tracked by git, return its .local equivalent\n * 4. If not tracked, return the file itself\n * 5. If not found anywhere, return '.env.local' (safe default)\n */\nexport async function findEnvFileForDatabaseUrl(\n workspacePath: string,\n variableName: string,\n isFileTracked: (filePath: string, cwd: string) => Promise<boolean>,\n fileExists: (filePath: string) => Promise<boolean>,\n getEnvVariable: (filePath: string, varName: string) => Promise<string | null>\n): Promise<string> {\n // Find the highest-precedence file containing the variable\n const file = await findEnvFileContainingVariable(workspacePath, variableName, fileExists, getEnvVariable)\n\n if (file === null) {\n // Variable not found anywhere - use safe default\n return '.env.local'\n }\n\n // Found the variable - check git tracking\n const isTracked = await isFileTracked(file, workspacePath)\n if (isTracked) {\n // Return .local equivalent for git safety\n return getLocalEquivalent(file)\n }\n\n return file\n}\n\n/**\n * Build shell source commands for all existing dotenv-flow files\n * Returns commands in precedence order (later overrides earlier)\n */\nexport async function buildEnvSourceCommands(\n workspacePath: string,\n fileExists: (filePath: string) => Promise<boolean>\n): Promise<string[]> {\n const files = getDotenvFlowFiles()\n const commands: string[] = []\n\n for (const file of files) {\n const fullPath = path.join(workspacePath, file)\n const exists = await fileExists(fullPath)\n if (exists) {\n commands.push(`source ${file}`)\n }\n }\n\n return commands\n}\n\n/**\n * Find the highest-precedence env file containing a variable\n * Searches all dotenv-flow files in reverse precedence order (highest first)\n * Returns the relative filename if found, null otherwise\n */\nexport async function findEnvFileContainingVariable(\n workspacePath: string,\n variableName: string,\n fileExists: (filePath: string) => Promise<boolean>,\n getEnvVariable: (filePath: string, varName: string) => Promise<string | null>\n): Promise<string | null> {\n const files = getDotenvFlowFiles().reverse() // highest precedence first\n\n for (const file of files) {\n const fullPath = path.join(workspacePath, file)\n\n // Skip if file doesn't exist\n if (!(await fileExists(fullPath))) {\n continue\n }\n\n // Check if file contains the variable\n const value = await getEnvVariable(fullPath, variableName)\n if (value !== null) {\n return file\n }\n }\n\n return null\n}\n\n/**\n * Check if a variable exists in any dotenv-flow file\n * Searches all dotenv-flow files (.env, .env.local, .env.{NODE_ENV}, .env.{NODE_ENV}.local)\n * Returns true if variable is found in any file, false otherwise\n */\nexport async function hasVariableInAnyEnvFile(\n workspacePath: string,\n variableName: string,\n fileExists: (filePath: string) => Promise<boolean>,\n getEnvVariable: (filePath: string, varName: string) => Promise<string | null>\n): Promise<boolean> {\n const file = await findEnvFileContainingVariable(workspacePath, variableName, fileExists, getEnvVariable)\n return file !== null\n}\n"],"mappings":"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","names":[]}
@@ -6,9 +6,9 @@ import {
6
6
  getClaudeVersion,
7
7
  launchClaude,
8
8
  launchClaudeInNewTerminalWindow
9
- } from "./chunk-75B2HZZ5.js";
10
- import "./chunk-JJUPY5MM.js";
11
- import "./chunk-3NFBZRPR.js";
9
+ } from "./chunk-RUC7OULH.js";
10
+ import "./chunk-VAYGNQTE.js";
11
+ import "./chunk-Z5NXYJIG.js";
12
12
  import "./chunk-6UIGZD2N.js";
13
13
  import "./chunk-UYVWLISQ.js";
14
14
  export {
@@ -19,4 +19,4 @@ export {
19
19
  launchClaude,
20
20
  launchClaudeInNewTerminalWindow
21
21
  };
22
- //# sourceMappingURL=claude-X7EBJRB2.js.map
22
+ //# sourceMappingURL=claude-ACVXNB6N.js.map
@@ -5,23 +5,23 @@ import {
5
5
  EnvironmentManager,
6
6
  LoomManager,
7
7
  ResourceCleanup
8
- } from "./chunk-NFVFVYAP.js";
8
+ } from "./chunk-IARWMDAX.js";
9
9
  import {
10
10
  IdentifierParser
11
- } from "./chunk-HVGQP44L.js";
11
+ } from "./chunk-55TB3FSG.js";
12
12
  import {
13
13
  ProcessManager
14
14
  } from "./chunk-VU3QMIP2.js";
15
15
  import {
16
16
  GitWorktreeManager
17
- } from "./chunk-M5XUCTTJ.js";
17
+ } from "./chunk-JC5HXN75.js";
18
18
  import "./chunk-VBFDVGAE.js";
19
19
  import "./chunk-2ZPFJQ3B.js";
20
20
  import {
21
21
  createNeonProviderFromSettings
22
22
  } from "./chunk-UNXRACJ7.js";
23
- import "./chunk-TR5MC2U6.js";
24
- import "./chunk-MLS5FAV7.js";
23
+ import "./chunk-2W2FBL5G.js";
24
+ import "./chunk-IJ7IGJT3.js";
25
25
  import {
26
26
  SettingsManager
27
27
  } from "./chunk-VWNS6DH5.js";
@@ -29,11 +29,11 @@ import {
29
29
  promptConfirmation
30
30
  } from "./chunk-SJ2GZ6RF.js";
31
31
  import "./chunk-WUQQNE63.js";
32
- import "./chunk-75B2HZZ5.js";
33
- import "./chunk-JJUPY5MM.js";
32
+ import "./chunk-RUC7OULH.js";
33
+ import "./chunk-VAYGNQTE.js";
34
34
  import {
35
35
  loadEnvIntoProcess
36
- } from "./chunk-3NFBZRPR.js";
36
+ } from "./chunk-Z5NXYJIG.js";
37
37
  import {
38
38
  getLogger
39
39
  } from "./chunk-6UIGZD2N.js";
@@ -78,9 +78,9 @@ var CleanupCommand = class {
78
78
  );
79
79
  if (!this.loomManager) {
80
80
  const { GitHubService } = await import("./GitHubService-RPM27GWD.js");
81
- const { ClaudeContextManager } = await import("./ClaudeContextManager-VEGJTS5E.js");
81
+ const { ClaudeContextManager } = await import("./ClaudeContextManager-DK77227F.js");
82
82
  const { ProjectCapabilityDetector } = await import("./ProjectCapabilityDetector-34LU7JJ4.js");
83
- const { DefaultBranchNamingService } = await import("./BranchNamingService-TOM2KAUT.js");
83
+ const { DefaultBranchNamingService } = await import("./BranchNamingService-GCCWB3LK.js");
84
84
  this.loomManager = new LoomManager(
85
85
  this.gitWorktreeManager,
86
86
  new GitHubService(),
@@ -280,7 +280,7 @@ var CleanupCommand = class {
280
280
  const { force, dryRun } = parsed.options;
281
281
  let parsedInput = await this.identifierParser.parseForPatternDetection(identifier);
282
282
  if (parsedInput.type === "branch" && parsedInput.branchName) {
283
- const { extractIssueNumber } = await import("./git-OXJACVAU.js");
283
+ const { extractIssueNumber } = await import("./git-4BVOOOOV.js");
284
284
  const extractedNumber = extractIssueNumber(parsedInput.branchName);
285
285
  if (extractedNumber !== null) {
286
286
  parsedInput = {
@@ -479,4 +479,4 @@ var CleanupCommand = class {
479
479
  export {
480
480
  CleanupCommand
481
481
  };
482
- //# sourceMappingURL=cleanup-7QVPYBJJ.js.map
482
+ //# sourceMappingURL=cleanup-KDLVTT7M.js.map
package/dist/cli.js CHANGED
@@ -1,26 +1,26 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  SessionSummaryService
4
- } from "./chunk-HHDSIE72.js";
4
+ } from "./chunk-TMZAVPGF.js";
5
5
  import {
6
6
  CLIIsolationManager,
7
7
  DatabaseManager,
8
8
  EnvironmentManager,
9
9
  LoomManager,
10
10
  ResourceCleanup
11
- } from "./chunk-NFVFVYAP.js";
11
+ } from "./chunk-IARWMDAX.js";
12
12
  import {
13
13
  InitCommand,
14
14
  ShellCompletion
15
- } from "./chunk-KM3W7YQX.js";
15
+ } from "./chunk-G6CIIJLT.js";
16
16
  import "./chunk-UYWAESOT.js";
17
17
  import {
18
18
  IssueEnhancementService,
19
19
  capitalizeFirstLetter
20
- } from "./chunk-S44CHE3G.js";
20
+ } from "./chunk-VTXCGKV5.js";
21
21
  import {
22
22
  MergeManager
23
- } from "./chunk-LTNDJMTH.js";
23
+ } from "./chunk-BIIQHEXJ.js";
24
24
  import {
25
25
  FirstRunManager,
26
26
  IssueTrackerFactory,
@@ -32,7 +32,7 @@ import {
32
32
  } from "./chunk-O7WHXLCB.js";
33
33
  import {
34
34
  IdentifierParser
35
- } from "./chunk-HVGQP44L.js";
35
+ } from "./chunk-55TB3FSG.js";
36
36
  import {
37
37
  ProcessManager
38
38
  } from "./chunk-VU3QMIP2.js";
@@ -41,7 +41,7 @@ import {
41
41
  } from "./chunk-YETJNRQM.js";
42
42
  import {
43
43
  GitWorktreeManager
44
- } from "./chunk-M5XUCTTJ.js";
44
+ } from "./chunk-JC5HXN75.js";
45
45
  import {
46
46
  detectPackageManager,
47
47
  installDependencies,
@@ -49,11 +49,14 @@ import {
49
49
  } from "./chunk-VBFDVGAE.js";
50
50
  import {
51
51
  ClaudeContextManager
52
- } from "./chunk-F4J6KEL6.js";
53
- import "./chunk-ADDNFQJ4.js";
52
+ } from "./chunk-UPUAQYAW.js";
53
+ import "./chunk-POI7KLBH.js";
54
+ import {
55
+ extractSettingsOverrides
56
+ } from "./chunk-GYCR2LOU.js";
54
57
  import {
55
58
  DefaultBranchNamingService
56
- } from "./chunk-P2WZIDF3.js";
59
+ } from "./chunk-QIUJPPJQ.js";
57
60
  import {
58
61
  ProjectCapabilityDetector
59
62
  } from "./chunk-EBISESAP.js";
@@ -61,9 +64,6 @@ import {
61
64
  hasScript,
62
65
  readPackageJson
63
66
  } from "./chunk-2ZPFJQ3B.js";
64
- import {
65
- extractSettingsOverrides
66
- } from "./chunk-GYCR2LOU.js";
67
67
  import {
68
68
  createNeonProviderFromSettings
69
69
  } from "./chunk-UNXRACJ7.js";
@@ -77,12 +77,13 @@ import {
77
77
  executeGitCommand,
78
78
  extractIssueNumber,
79
79
  findMainWorktreePathWithSettings,
80
+ getMergeTargetBranch,
80
81
  getRepoRoot,
81
82
  pushBranchToRemote
82
- } from "./chunk-TR5MC2U6.js";
83
+ } from "./chunk-2W2FBL5G.js";
83
84
  import {
84
85
  MetadataManager
85
- } from "./chunk-MLS5FAV7.js";
86
+ } from "./chunk-IJ7IGJT3.js";
86
87
  import {
87
88
  SettingsManager
88
89
  } from "./chunk-VWNS6DH5.js";
@@ -101,11 +102,11 @@ import "./chunk-WUQQNE63.js";
101
102
  import {
102
103
  detectClaudeCli,
103
104
  launchClaude
104
- } from "./chunk-75B2HZZ5.js";
105
- import "./chunk-JJUPY5MM.js";
105
+ } from "./chunk-RUC7OULH.js";
106
+ import "./chunk-VAYGNQTE.js";
106
107
  import {
107
108
  loadEnvIntoProcess
108
- } from "./chunk-3NFBZRPR.js";
109
+ } from "./chunk-Z5NXYJIG.js";
109
110
  import {
110
111
  getLogger,
111
112
  withLogger
@@ -1155,6 +1156,12 @@ import { execa } from "execa";
1155
1156
  function isRunningInVSCode() {
1156
1157
  return process.env.TERM_PROGRAM === "vscode";
1157
1158
  }
1159
+ function isRunningInCursor() {
1160
+ return !!process.env.CURSOR_TRACE_ID;
1161
+ }
1162
+ function isRunningInAntigravity() {
1163
+ return !!process.env.ANTIGRAVITY_CLI_ALIAS;
1164
+ }
1158
1165
  async function isVSCodeAvailable() {
1159
1166
  try {
1160
1167
  await execa("command", ["-v", "code"], {
@@ -1167,6 +1174,30 @@ async function isVSCodeAvailable() {
1167
1174
  return false;
1168
1175
  }
1169
1176
  }
1177
+ async function isCursorAvailable() {
1178
+ try {
1179
+ await execa("command", ["-v", "cursor"], {
1180
+ shell: true,
1181
+ timeout: 5e3
1182
+ });
1183
+ return true;
1184
+ } catch (error) {
1185
+ logger.debug("Cursor CLI not available", { error });
1186
+ return false;
1187
+ }
1188
+ }
1189
+ async function isAntigravityAvailable() {
1190
+ try {
1191
+ await execa("command", ["-v", "agy"], {
1192
+ shell: true,
1193
+ timeout: 5e3
1194
+ });
1195
+ return true;
1196
+ } catch (error) {
1197
+ logger.debug("Antigravity CLI not available", { error });
1198
+ return false;
1199
+ }
1200
+ }
1170
1201
 
1171
1202
  // src/types/index.ts
1172
1203
  var UserAbortedCommitError = class extends Error {
@@ -1251,8 +1282,12 @@ var CommitManager = class {
1251
1282
  await executeGitCommand(commitArgs, { cwd: worktreePath });
1252
1283
  } else {
1253
1284
  getLogger().info("Opening editor for commit message review...");
1254
- if (isRunningInVSCode() && await isVSCodeAvailable()) {
1255
- await this.commitWithVSCodeEditor(worktreePath, message, options);
1285
+ if (isRunningInAntigravity() && await isAntigravityAvailable()) {
1286
+ await this.commitWithExternalEditor(worktreePath, message, options, "agy", "Antigravity");
1287
+ } else if (isRunningInCursor() && await isCursorAvailable()) {
1288
+ await this.commitWithExternalEditor(worktreePath, message, options, "cursor", "Cursor");
1289
+ } else if (isRunningInVSCode() && await isVSCodeAvailable()) {
1290
+ await this.commitWithExternalEditor(worktreePath, message, options, "code", "VSCode");
1256
1291
  } else {
1257
1292
  const commitArgs = ["commit", "-e", "-m", message];
1258
1293
  if (options.skipVerify) {
@@ -1279,10 +1314,11 @@ var CommitManager = class {
1279
1314
  }
1280
1315
  }
1281
1316
  /**
1282
- * Commit with VSCode editor - handles file creation, editing, and commit ourselves
1283
- * to ensure the file opens in the current VSCode window (preserves IPC context)
1317
+ * Commit with external editor CLI (VSCode, Cursor, Antigravity, etc.)
1318
+ * Handles file creation, editing, and commit to ensure the file opens
1319
+ * in the current editor window (preserves IPC context)
1284
1320
  */
1285
- async commitWithVSCodeEditor(worktreePath, message, options) {
1321
+ async commitWithExternalEditor(worktreePath, message, options, cliCommand, editorName) {
1286
1322
  const commitMsgPath = join(worktreePath, ".COMMIT_EDITMSG");
1287
1323
  const initialContent = `${message}
1288
1324
 
@@ -1293,8 +1329,8 @@ var CommitManager = class {
1293
1329
  `;
1294
1330
  await writeFile(commitMsgPath, initialContent, "utf-8");
1295
1331
  try {
1296
- getLogger().debug(`Opening commit message in VSCode: ${commitMsgPath}`);
1297
- await execa2("code", ["--wait", commitMsgPath], {
1332
+ getLogger().debug(`Opening commit message in ${editorName}: ${commitMsgPath}`);
1333
+ await execa2(cliCommand, ["--wait", commitMsgPath], {
1298
1334
  cwd: worktreePath,
1299
1335
  stdio: "inherit"
1300
1336
  });
@@ -1929,7 +1965,7 @@ var FinishCommand = class {
1929
1965
  const neonProvider = createNeonProviderFromSettings(settings);
1930
1966
  const databaseManager = new DatabaseManager(neonProvider, environmentManager, databaseUrlEnvVarName);
1931
1967
  const cliIsolationManager = new CLIIsolationManager();
1932
- const { DefaultBranchNamingService: DefaultBranchNamingService2 } = await import("./BranchNamingService-TOM2KAUT.js");
1968
+ const { DefaultBranchNamingService: DefaultBranchNamingService2 } = await import("./BranchNamingService-GCCWB3LK.js");
1933
1969
  this.loomManager ??= new LoomManager(
1934
1970
  this.gitWorktreeManager,
1935
1971
  this.issueTracker,
@@ -2483,17 +2519,17 @@ var FinishCommand = class {
2483
2519
  getLogger().debug("Could not fetch issue title, using branch name", { error });
2484
2520
  }
2485
2521
  }
2522
+ const baseBranch = await getMergeTargetBranch(worktree.path);
2486
2523
  if (options.dryRun) {
2487
2524
  getLogger().info("[DRY RUN] Would create GitHub PR");
2488
2525
  getLogger().info(` Title: ${prTitle}`);
2489
- getLogger().info(` Base: ${settings.mainBranch ?? "main"}`);
2526
+ getLogger().info(` Base: ${baseBranch}`);
2490
2527
  finishResult.operations.push({
2491
2528
  type: "pr-creation",
2492
2529
  message: "Would create GitHub PR (dry-run)",
2493
2530
  success: true
2494
2531
  });
2495
2532
  } else {
2496
- const baseBranch = settings.mainBranch ?? "main";
2497
2533
  const openInBrowser = options.noBrowser !== true;
2498
2534
  const prResult = await prManager.createOrOpenPR(
2499
2535
  worktree.branch,
@@ -2955,7 +2991,8 @@ function formatLoomForJson(worktree, mainWorktreePath, metadata) {
2955
2991
  description: (metadata == null ? void 0 : metadata.description) ?? null,
2956
2992
  created_at: (metadata == null ? void 0 : metadata.created_at) ?? null,
2957
2993
  issueTracker: (metadata == null ? void 0 : metadata.issueTracker) ?? null,
2958
- colorHex: (metadata == null ? void 0 : metadata.colorHex) ?? null
2994
+ colorHex: (metadata == null ? void 0 : metadata.colorHex) ?? null,
2995
+ projectPath: (metadata == null ? void 0 : metadata.projectPath) ?? null
2959
2996
  };
2960
2997
  }
2961
2998
  function formatLoomsForJson(worktrees, mainWorktreePath, metadata) {
@@ -3081,7 +3118,7 @@ async function autoLaunchInitForMultipleRemotes() {
3081
3118
  await waitForKeypress2("Press any key to start configuration...");
3082
3119
  logger.info("");
3083
3120
  try {
3084
- const { InitCommand: InitCommand2 } = await import("./init-SCR2LQ4A.js");
3121
+ const { InitCommand: InitCommand2 } = await import("./init-LBA6NUK2.js");
3085
3122
  const initCommand = new InitCommand2();
3086
3123
  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.";
3087
3124
  await initCommand.execute(customInitialMessage);
@@ -3182,7 +3219,7 @@ program.command("add-issue").alias("a").description("Create and enhance GitHub i
3182
3219
  });
3183
3220
  program.command("feedback").alias("f").description("Submit feedback/bug report to iloom-cli repository").argument("<description>", "Natural language description of feedback (>50 chars, >2 spaces)").option("--body <text>", "Body text for feedback (added after diagnostics)").action(async (description, options) => {
3184
3221
  try {
3185
- const { FeedbackCommand } = await import("./feedback-562KPG5U.js");
3222
+ const { FeedbackCommand } = await import("./feedback-7PVBQNLJ.js");
3186
3223
  const command = new FeedbackCommand();
3187
3224
  const feedbackOptions = {};
3188
3225
  if (options.body !== void 0) {
@@ -3262,7 +3299,7 @@ program.command("finish").alias("dn").description("Merge work and cleanup worksp
3262
3299
  });
3263
3300
  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) => {
3264
3301
  try {
3265
- const { RebaseCommand } = await import("./rebase-55URTXZC.js");
3302
+ const { RebaseCommand } = await import("./rebase-4T5FQHNH.js");
3266
3303
  const command = new RebaseCommand();
3267
3304
  await command.execute(options);
3268
3305
  } catch (error) {
@@ -3274,7 +3311,7 @@ program.command("spin").alias("ignite").description("Launch Claude with auto-det
3274
3311
  new Option("--one-shot <mode>", "One-shot automation mode").choices(["default", "noReview", "bypassPermissions"]).default("default")
3275
3312
  ).action(async (options) => {
3276
3313
  try {
3277
- const { IgniteCommand } = await import("./ignite-VSIPGKKG.js");
3314
+ const { IgniteCommand } = await import("./ignite-3B264M7K.js");
3278
3315
  const command = new IgniteCommand();
3279
3316
  await command.execute(options.oneShot ?? "default");
3280
3317
  } catch (error) {
@@ -3285,7 +3322,7 @@ program.command("spin").alias("ignite").description("Launch Claude with auto-det
3285
3322
  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) => {
3286
3323
  try {
3287
3324
  const args = (command == null ? void 0 : command.args) ? command.args.slice(identifier ? 1 : 0) : [];
3288
- const { OpenCommand } = await import("./open-CX7HUE26.js");
3325
+ const { OpenCommand } = await import("./open-OGCV32Z4.js");
3289
3326
  const cmd = new OpenCommand();
3290
3327
  const input = identifier ? { identifier, args } : { args };
3291
3328
  await cmd.execute(input);
@@ -3297,7 +3334,7 @@ program.command("open").description("Open workspace in browser or run CLI tool")
3297
3334
  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) => {
3298
3335
  try {
3299
3336
  const args = (command == null ? void 0 : command.args) ? command.args.slice(identifier ? 1 : 0) : [];
3300
- const { RunCommand } = await import("./run-DP2U2CA2.js");
3337
+ const { RunCommand } = await import("./run-HNOP6WE2.js");
3301
3338
  const cmd = new RunCommand();
3302
3339
  const input = identifier ? { identifier, args } : { args };
3303
3340
  await cmd.execute(input);
@@ -3308,7 +3345,7 @@ program.command("run").description("Run CLI tool or open workspace in browser").
3308
3345
  });
3309
3346
  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) => {
3310
3347
  try {
3311
- const { DevServerCommand } = await import("./dev-server-LOY7YWCP.js");
3348
+ const { DevServerCommand } = await import("./dev-server-JCJGQ3PV.js");
3312
3349
  const cmd = new DevServerCommand();
3313
3350
  await cmd.execute({ identifier, json: options == null ? void 0 : options.json });
3314
3351
  } catch (error) {
@@ -3316,10 +3353,20 @@ program.command("dev-server").alias("dev").description("Start dev server for wor
3316
3353
  process.exit(1);
3317
3354
  }
3318
3355
  });
3356
+ program.command("shell").alias("terminal").description("Open interactive shell with workspace environment").argument("[identifier]", "Issue number, PR number, or branch name (auto-detected if omitted)").action(async (identifier) => {
3357
+ try {
3358
+ const { ShellCommand } = await import("./shell-DE3HKJSM.js");
3359
+ const cmd = new ShellCommand();
3360
+ await cmd.execute({ identifier });
3361
+ } catch (error) {
3362
+ logger.error(`Failed to open shell: ${error instanceof Error ? error.message : "Unknown error"}`);
3363
+ process.exit(1);
3364
+ }
3365
+ });
3319
3366
  program.command("cleanup").alias("remove").alias("clean").description("Remove workspaces").argument("[identifier]", "Branch name or issue number to cleanup (auto-detected)").option("-l, --list", "List all worktrees").option("-a, --all", "Remove all worktrees (interactive confirmation)").option("-i, --issue <number>", "Cleanup by issue number", parseInt).option("-f, --force", "Skip confirmations and force removal").option("--dry-run", "Show what would be done without doing it").option("--json", "Output result as JSON").action(async (identifier, options) => {
3320
3367
  const executeAction = async () => {
3321
3368
  try {
3322
- const { CleanupCommand } = await import("./cleanup-7QVPYBJJ.js");
3369
+ const { CleanupCommand } = await import("./cleanup-KDLVTT7M.js");
3323
3370
  const command = new CleanupCommand();
3324
3371
  const input = {
3325
3372
  options: options ?? {}
@@ -3393,7 +3440,7 @@ program.command("list").description("Show active workspaces").option("--json", "
3393
3440
  });
3394
3441
  program.command("projects").description("List configured iloom projects").option("--json", "Output as JSON (default behavior)").action(async (options) => {
3395
3442
  try {
3396
- const { ProjectsCommand } = await import("./projects-6DTNDVLH.js");
3443
+ const { ProjectsCommand } = await import("./projects-P55273AB.js");
3397
3444
  const command = new ProjectsCommand();
3398
3445
  const result = await command.execute(options);
3399
3446
  console.log(JSON.stringify(result, null, 2));
@@ -3404,7 +3451,7 @@ program.command("projects").description("List configured iloom projects").option
3404
3451
  });
3405
3452
  program.command("init").alias("config").description("Initialize iloom configuration and setup shell autocomplete").argument("[prompt]", 'Custom initial message to send to Claude (defaults to "Help me configure iloom settings.")').action(async (prompt) => {
3406
3453
  try {
3407
- const { InitCommand: InitCommand2 } = await import("./init-SCR2LQ4A.js");
3454
+ const { InitCommand: InitCommand2 } = await import("./init-LBA6NUK2.js");
3408
3455
  const command = new InitCommand2();
3409
3456
  const trimmedPrompt = prompt == null ? void 0 : prompt.trim();
3410
3457
  const customPrompt = trimmedPrompt && trimmedPrompt.length > 0 ? trimmedPrompt : void 0;
@@ -3416,7 +3463,7 @@ program.command("init").alias("config").description("Initialize iloom configurat
3416
3463
  });
3417
3464
  program.command("contribute").description("Set up local development environment for contributing to iloom").action(async () => {
3418
3465
  try {
3419
- const { ContributeCommand } = await import("./contribute-RZYCYUDX.js");
3466
+ const { ContributeCommand } = await import("./contribute-HY372S6F.js");
3420
3467
  const command = new ContributeCommand();
3421
3468
  await command.execute();
3422
3469
  } catch (error) {
@@ -3437,7 +3484,7 @@ program.command("update").description("Update iloom-cli to the latest version").
3437
3484
  program.command("test-github").description("Test GitHub integration (Issue #3)").argument("<identifier>", "Issue number or PR number").option("--no-claude", "Skip Claude for branch name generation").action(async (identifier, options) => {
3438
3485
  try {
3439
3486
  const { GitHubService: GitHubService2 } = await import("./GitHubService-RPM27GWD.js");
3440
- const { DefaultBranchNamingService: DefaultBranchNamingService2 } = await import("./BranchNamingService-TOM2KAUT.js");
3487
+ const { DefaultBranchNamingService: DefaultBranchNamingService2 } = await import("./BranchNamingService-GCCWB3LK.js");
3441
3488
  logger.info("Testing GitHub Integration\n");
3442
3489
  const service = new GitHubService2();
3443
3490
  const branchNaming = new DefaultBranchNamingService2({ useClaude: options.claude !== false });
@@ -3495,10 +3542,10 @@ program.command("test-github").description("Test GitHub integration (Issue #3)")
3495
3542
  });
3496
3543
  program.command("test-claude").description("Test Claude integration (Issue #10)").option("--detect", "Test Claude CLI detection").option("--version", "Get Claude CLI version").option("--branch <title>", "Test branch name generation with given title").option("--issue <number>", "Issue number for branch generation", "123").option("--launch <prompt>", "Launch Claude with a prompt (headless)").option("--interactive", "Launch Claude interactively (requires --launch)").option("--template <name>", "Test template loading").action(async (options) => {
3497
3544
  try {
3498
- const { detectClaudeCli: detectClaudeCli2, getClaudeVersion, generateBranchName, launchClaude: launchClaude2 } = await import("./claude-X7EBJRB2.js");
3545
+ const { detectClaudeCli: detectClaudeCli2, getClaudeVersion, generateBranchName, launchClaude: launchClaude2 } = await import("./claude-ACVXNB6N.js");
3499
3546
  const { PromptTemplateManager } = await import("./PromptTemplateManager-2TDZAUC6.js");
3500
- const { ClaudeService } = await import("./ClaudeService-ICSHJMQ5.js");
3501
- const { ClaudeContextManager: ClaudeContextManager2 } = await import("./ClaudeContextManager-VEGJTS5E.js");
3547
+ const { ClaudeService } = await import("./ClaudeService-W3SA7HVG.js");
3548
+ const { ClaudeContextManager: ClaudeContextManager2 } = await import("./ClaudeContextManager-DK77227F.js");
3502
3549
  logger.info("Testing Claude Integration\n");
3503
3550
  if (options.detect) {
3504
3551
  logger.info("Detecting Claude CLI...");
@@ -3646,7 +3693,7 @@ program.command("test-webserver").description("Test if a web server is running o
3646
3693
  });
3647
3694
  program.command("test-git").description("Test Git integration - findMainWorktreePath() function (reads .iloom/settings.json)").action(async () => {
3648
3695
  try {
3649
- const { TestGitCommand } = await import("./test-git-QLAIBJLX.js");
3696
+ const { TestGitCommand } = await import("./test-git-YMAE57UP.js");
3650
3697
  const command = new TestGitCommand();
3651
3698
  await command.execute();
3652
3699
  } catch (error) {
@@ -3659,7 +3706,7 @@ program.command("test-git").description("Test Git integration - findMainWorktree
3659
3706
  });
3660
3707
  program.command("test-tabs").description("Test iTerm2 dual tab functionality - opens two tabs with test commands").action(async () => {
3661
3708
  try {
3662
- const { TestTabsCommand } = await import("./test-tabs-JGO3VOXJ.js");
3709
+ const { TestTabsCommand } = await import("./test-tabs-3SCJWRKT.js");
3663
3710
  const command = new TestTabsCommand();
3664
3711
  await command.execute();
3665
3712
  } catch (error) {
@@ -3672,7 +3719,7 @@ program.command("test-tabs").description("Test iTerm2 dual tab functionality - o
3672
3719
  });
3673
3720
  program.command("test-prefix").description("Test worktree prefix configuration - preview worktree paths (reads .iloom/settings.json)").action(async () => {
3674
3721
  try {
3675
- const { TestPrefixCommand } = await import("./test-prefix-6YM2ZOON.js");
3722
+ const { TestPrefixCommand } = await import("./test-prefix-YCKL6CMT.js");
3676
3723
  const command = new TestPrefixCommand();
3677
3724
  await command.execute();
3678
3725
  } catch (error) {
@@ -3686,7 +3733,7 @@ program.command("test-prefix").description("Test worktree prefix configuration -
3686
3733
  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) => {
3687
3734
  const executeAction = async () => {
3688
3735
  try {
3689
- const { SummaryCommand } = await import("./summary-J3CJSM7L.js");
3736
+ const { SummaryCommand } = await import("./summary-GDT7DTRI.js");
3690
3737
  const command = new SummaryCommand();
3691
3738
  const result = await command.execute({ identifier, options });
3692
3739
  if (options.json && result) {