@iloom/cli 0.1.14

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 (161) hide show
  1. package/LICENSE +33 -0
  2. package/README.md +711 -0
  3. package/dist/ClaudeContextManager-XOSXQ67R.js +13 -0
  4. package/dist/ClaudeContextManager-XOSXQ67R.js.map +1 -0
  5. package/dist/ClaudeService-YSZ6EXWP.js +12 -0
  6. package/dist/ClaudeService-YSZ6EXWP.js.map +1 -0
  7. package/dist/GitHubService-F7Z3XJOS.js +11 -0
  8. package/dist/GitHubService-F7Z3XJOS.js.map +1 -0
  9. package/dist/LoomLauncher-MODG2SEM.js +263 -0
  10. package/dist/LoomLauncher-MODG2SEM.js.map +1 -0
  11. package/dist/NeonProvider-PAGPUH7F.js +12 -0
  12. package/dist/NeonProvider-PAGPUH7F.js.map +1 -0
  13. package/dist/PromptTemplateManager-7FINLRDE.js +9 -0
  14. package/dist/PromptTemplateManager-7FINLRDE.js.map +1 -0
  15. package/dist/SettingsManager-VAZF26S2.js +19 -0
  16. package/dist/SettingsManager-VAZF26S2.js.map +1 -0
  17. package/dist/SettingsMigrationManager-MTQIMI54.js +146 -0
  18. package/dist/SettingsMigrationManager-MTQIMI54.js.map +1 -0
  19. package/dist/add-issue-22JBNOML.js +54 -0
  20. package/dist/add-issue-22JBNOML.js.map +1 -0
  21. package/dist/agents/iloom-issue-analyze-and-plan.md +580 -0
  22. package/dist/agents/iloom-issue-analyzer.md +290 -0
  23. package/dist/agents/iloom-issue-complexity-evaluator.md +224 -0
  24. package/dist/agents/iloom-issue-enhancer.md +266 -0
  25. package/dist/agents/iloom-issue-implementer.md +262 -0
  26. package/dist/agents/iloom-issue-planner.md +358 -0
  27. package/dist/agents/iloom-issue-reviewer.md +63 -0
  28. package/dist/chunk-2ZPFJQ3B.js +63 -0
  29. package/dist/chunk-2ZPFJQ3B.js.map +1 -0
  30. package/dist/chunk-37DYYFVK.js +29 -0
  31. package/dist/chunk-37DYYFVK.js.map +1 -0
  32. package/dist/chunk-BLCTGFZN.js +121 -0
  33. package/dist/chunk-BLCTGFZN.js.map +1 -0
  34. package/dist/chunk-CP2NU2JC.js +545 -0
  35. package/dist/chunk-CP2NU2JC.js.map +1 -0
  36. package/dist/chunk-CWR2SANQ.js +39 -0
  37. package/dist/chunk-CWR2SANQ.js.map +1 -0
  38. package/dist/chunk-F3XBU2R7.js +110 -0
  39. package/dist/chunk-F3XBU2R7.js.map +1 -0
  40. package/dist/chunk-GEHQXLEI.js +130 -0
  41. package/dist/chunk-GEHQXLEI.js.map +1 -0
  42. package/dist/chunk-GYCR2LOU.js +143 -0
  43. package/dist/chunk-GYCR2LOU.js.map +1 -0
  44. package/dist/chunk-GZP4UGGM.js +48 -0
  45. package/dist/chunk-GZP4UGGM.js.map +1 -0
  46. package/dist/chunk-H4E4THUZ.js +55 -0
  47. package/dist/chunk-H4E4THUZ.js.map +1 -0
  48. package/dist/chunk-HPJJSYNS.js +644 -0
  49. package/dist/chunk-HPJJSYNS.js.map +1 -0
  50. package/dist/chunk-JBH2ZYYZ.js +220 -0
  51. package/dist/chunk-JBH2ZYYZ.js.map +1 -0
  52. package/dist/chunk-JNKJ7NJV.js +78 -0
  53. package/dist/chunk-JNKJ7NJV.js.map +1 -0
  54. package/dist/chunk-JQ7VOSTC.js +437 -0
  55. package/dist/chunk-JQ7VOSTC.js.map +1 -0
  56. package/dist/chunk-KQDEK2ZW.js +199 -0
  57. package/dist/chunk-KQDEK2ZW.js.map +1 -0
  58. package/dist/chunk-O2QWO64Z.js +179 -0
  59. package/dist/chunk-O2QWO64Z.js.map +1 -0
  60. package/dist/chunk-OC4H6HJD.js +248 -0
  61. package/dist/chunk-OC4H6HJD.js.map +1 -0
  62. package/dist/chunk-PR7FKQBG.js +120 -0
  63. package/dist/chunk-PR7FKQBG.js.map +1 -0
  64. package/dist/chunk-PXZBAC2M.js +250 -0
  65. package/dist/chunk-PXZBAC2M.js.map +1 -0
  66. package/dist/chunk-QEPVTTHD.js +383 -0
  67. package/dist/chunk-QEPVTTHD.js.map +1 -0
  68. package/dist/chunk-RSRO7564.js +203 -0
  69. package/dist/chunk-RSRO7564.js.map +1 -0
  70. package/dist/chunk-SJUQ2NDR.js +146 -0
  71. package/dist/chunk-SJUQ2NDR.js.map +1 -0
  72. package/dist/chunk-SPYPLHMK.js +177 -0
  73. package/dist/chunk-SPYPLHMK.js.map +1 -0
  74. package/dist/chunk-SSCQCCJ7.js +75 -0
  75. package/dist/chunk-SSCQCCJ7.js.map +1 -0
  76. package/dist/chunk-SSR5AVRJ.js +41 -0
  77. package/dist/chunk-SSR5AVRJ.js.map +1 -0
  78. package/dist/chunk-T7QPXANZ.js +315 -0
  79. package/dist/chunk-T7QPXANZ.js.map +1 -0
  80. package/dist/chunk-U3WU5OWO.js +203 -0
  81. package/dist/chunk-U3WU5OWO.js.map +1 -0
  82. package/dist/chunk-W3DQTW63.js +124 -0
  83. package/dist/chunk-W3DQTW63.js.map +1 -0
  84. package/dist/chunk-WKEWRSDB.js +151 -0
  85. package/dist/chunk-WKEWRSDB.js.map +1 -0
  86. package/dist/chunk-Y7SAGNUT.js +66 -0
  87. package/dist/chunk-Y7SAGNUT.js.map +1 -0
  88. package/dist/chunk-YETJNRQM.js +39 -0
  89. package/dist/chunk-YETJNRQM.js.map +1 -0
  90. package/dist/chunk-YYSKGAZT.js +384 -0
  91. package/dist/chunk-YYSKGAZT.js.map +1 -0
  92. package/dist/chunk-ZZZWQGTS.js +169 -0
  93. package/dist/chunk-ZZZWQGTS.js.map +1 -0
  94. package/dist/claude-7LUVDZZ4.js +17 -0
  95. package/dist/claude-7LUVDZZ4.js.map +1 -0
  96. package/dist/cleanup-3LUWPSM7.js +412 -0
  97. package/dist/cleanup-3LUWPSM7.js.map +1 -0
  98. package/dist/cli-overrides-XFZWY7CM.js +16 -0
  99. package/dist/cli-overrides-XFZWY7CM.js.map +1 -0
  100. package/dist/cli.js +603 -0
  101. package/dist/cli.js.map +1 -0
  102. package/dist/color-ZVALX37U.js +21 -0
  103. package/dist/color-ZVALX37U.js.map +1 -0
  104. package/dist/enhance-XJIQHVPD.js +166 -0
  105. package/dist/enhance-XJIQHVPD.js.map +1 -0
  106. package/dist/env-MDFL4ZXL.js +23 -0
  107. package/dist/env-MDFL4ZXL.js.map +1 -0
  108. package/dist/feedback-23CLXKFT.js +158 -0
  109. package/dist/feedback-23CLXKFT.js.map +1 -0
  110. package/dist/finish-CY4CIH6O.js +1608 -0
  111. package/dist/finish-CY4CIH6O.js.map +1 -0
  112. package/dist/git-LVRZ57GJ.js +43 -0
  113. package/dist/git-LVRZ57GJ.js.map +1 -0
  114. package/dist/ignite-WXEF2ID5.js +359 -0
  115. package/dist/ignite-WXEF2ID5.js.map +1 -0
  116. package/dist/index.d.ts +1341 -0
  117. package/dist/index.js +3058 -0
  118. package/dist/index.js.map +1 -0
  119. package/dist/init-RHACUR4E.js +123 -0
  120. package/dist/init-RHACUR4E.js.map +1 -0
  121. package/dist/installation-detector-VARGFFRZ.js +11 -0
  122. package/dist/installation-detector-VARGFFRZ.js.map +1 -0
  123. package/dist/logger-MKYH4UDV.js +12 -0
  124. package/dist/logger-MKYH4UDV.js.map +1 -0
  125. package/dist/mcp/chunk-6SDFJ42P.js +62 -0
  126. package/dist/mcp/chunk-6SDFJ42P.js.map +1 -0
  127. package/dist/mcp/claude-YHHHLSXH.js +249 -0
  128. package/dist/mcp/claude-YHHHLSXH.js.map +1 -0
  129. package/dist/mcp/color-QS5BFCNN.js +168 -0
  130. package/dist/mcp/color-QS5BFCNN.js.map +1 -0
  131. package/dist/mcp/github-comment-server.js +165 -0
  132. package/dist/mcp/github-comment-server.js.map +1 -0
  133. package/dist/mcp/terminal-SDCMDVD7.js +202 -0
  134. package/dist/mcp/terminal-SDCMDVD7.js.map +1 -0
  135. package/dist/open-X6BTENPV.js +278 -0
  136. package/dist/open-X6BTENPV.js.map +1 -0
  137. package/dist/prompt-ANTQWHUF.js +13 -0
  138. package/dist/prompt-ANTQWHUF.js.map +1 -0
  139. package/dist/prompts/issue-prompt.txt +230 -0
  140. package/dist/prompts/pr-prompt.txt +35 -0
  141. package/dist/prompts/regular-prompt.txt +14 -0
  142. package/dist/run-2JCPQAX3.js +278 -0
  143. package/dist/run-2JCPQAX3.js.map +1 -0
  144. package/dist/schema/settings.schema.json +221 -0
  145. package/dist/start-LWVRBJ6S.js +982 -0
  146. package/dist/start-LWVRBJ6S.js.map +1 -0
  147. package/dist/terminal-3D6TUAKJ.js +16 -0
  148. package/dist/terminal-3D6TUAKJ.js.map +1 -0
  149. package/dist/test-git-XPF4SZXJ.js +52 -0
  150. package/dist/test-git-XPF4SZXJ.js.map +1 -0
  151. package/dist/test-prefix-XGFXFAYN.js +68 -0
  152. package/dist/test-prefix-XGFXFAYN.js.map +1 -0
  153. package/dist/test-tabs-JRKY3QMM.js +69 -0
  154. package/dist/test-tabs-JRKY3QMM.js.map +1 -0
  155. package/dist/test-webserver-M2I3EV4J.js +62 -0
  156. package/dist/test-webserver-M2I3EV4J.js.map +1 -0
  157. package/dist/update-3ZT2XX2G.js +79 -0
  158. package/dist/update-3ZT2XX2G.js.map +1 -0
  159. package/dist/update-notifier-QSSEB5KC.js +11 -0
  160. package/dist/update-notifier-QSSEB5KC.js.map +1 -0
  161. package/package.json +113 -0
@@ -0,0 +1,124 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ buildDevServerCommand
4
+ } from "./chunk-GZP4UGGM.js";
5
+ import {
6
+ ProcessManager
7
+ } from "./chunk-SPYPLHMK.js";
8
+ import {
9
+ logger
10
+ } from "./chunk-GEHQXLEI.js";
11
+
12
+ // src/lib/DevServerManager.ts
13
+ import { execa } from "execa";
14
+ import { setTimeout } from "timers/promises";
15
+ var DevServerManager = class {
16
+ constructor(processManager, options = {}) {
17
+ this.runningServers = /* @__PURE__ */ new Map();
18
+ this.processManager = processManager ?? new ProcessManager();
19
+ this.options = {
20
+ startupTimeout: options.startupTimeout ?? 3e4,
21
+ checkInterval: options.checkInterval ?? 1e3
22
+ };
23
+ }
24
+ /**
25
+ * Ensure dev server is running on the specified port
26
+ * If not running, start it and wait for it to be ready
27
+ *
28
+ * @param worktreePath - Path to the worktree
29
+ * @param port - Port the server should run on
30
+ * @returns true if server is ready, false if startup failed/timed out
31
+ */
32
+ async ensureServerRunning(worktreePath, port) {
33
+ logger.debug(`Checking if dev server is running on port ${port}...`);
34
+ const existingProcess = await this.processManager.detectDevServer(port);
35
+ if (existingProcess) {
36
+ logger.debug(
37
+ `Dev server already running on port ${port} (PID: ${existingProcess.pid})`
38
+ );
39
+ return true;
40
+ }
41
+ logger.info(`Dev server not running on port ${port}, starting...`);
42
+ try {
43
+ await this.startDevServer(worktreePath, port);
44
+ return true;
45
+ } catch (error) {
46
+ logger.error(
47
+ `Failed to start dev server: ${error instanceof Error ? error.message : "Unknown error"}`
48
+ );
49
+ return false;
50
+ }
51
+ }
52
+ /**
53
+ * Start dev server in background and wait for it to be ready
54
+ */
55
+ async startDevServer(worktreePath, port) {
56
+ const devCommand = await buildDevServerCommand(worktreePath);
57
+ logger.debug(`Starting dev server with command: ${devCommand}`);
58
+ const serverProcess = execa("sh", ["-c", devCommand], {
59
+ cwd: worktreePath,
60
+ env: {
61
+ ...process.env,
62
+ PORT: port.toString()
63
+ },
64
+ // Important: Don't inherit stdio - server runs in background
65
+ stdio: "ignore",
66
+ // Detach from parent process so it continues running
67
+ detached: true
68
+ });
69
+ this.runningServers.set(port, serverProcess);
70
+ serverProcess.unref();
71
+ logger.info(`Waiting for dev server to start on port ${port}...`);
72
+ const ready = await this.waitForServerReady(port);
73
+ if (!ready) {
74
+ throw new Error(
75
+ `Dev server failed to start within ${this.options.startupTimeout}ms timeout`
76
+ );
77
+ }
78
+ logger.success(`Dev server started successfully on port ${port}`);
79
+ }
80
+ /**
81
+ * Wait for server to be ready by polling the port
82
+ */
83
+ async waitForServerReady(port) {
84
+ const startTime = Date.now();
85
+ let attempts = 0;
86
+ while (Date.now() - startTime < this.options.startupTimeout) {
87
+ attempts++;
88
+ const processInfo = await this.processManager.detectDevServer(port);
89
+ if (processInfo) {
90
+ logger.debug(
91
+ `Server detected on port ${port} after ${attempts} attempts (${Date.now() - startTime}ms)`
92
+ );
93
+ return true;
94
+ }
95
+ await setTimeout(this.options.checkInterval);
96
+ }
97
+ logger.warn(
98
+ `Server did not start on port ${port} after ${this.options.startupTimeout}ms (${attempts} attempts)`
99
+ );
100
+ return false;
101
+ }
102
+ /**
103
+ * Clean up all running server processes
104
+ * This should be called when the manager is being disposed
105
+ */
106
+ async cleanup() {
107
+ for (const [port, serverProcess] of this.runningServers.entries()) {
108
+ try {
109
+ logger.debug(`Cleaning up server process on port ${port}`);
110
+ serverProcess.kill();
111
+ } catch (error) {
112
+ logger.warn(
113
+ `Failed to kill server process on port ${port}: ${error instanceof Error ? error.message : "Unknown error"}`
114
+ );
115
+ }
116
+ }
117
+ this.runningServers.clear();
118
+ }
119
+ };
120
+
121
+ export {
122
+ DevServerManager
123
+ };
124
+ //# sourceMappingURL=chunk-W3DQTW63.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/DevServerManager.ts"],"sourcesContent":["import { execa, type ExecaChildProcess } from 'execa'\nimport { setTimeout } from 'timers/promises'\nimport { ProcessManager } from './process/ProcessManager.js'\nimport { buildDevServerCommand } from '../utils/dev-server.js'\nimport { logger } from '../utils/logger.js'\n\nexport interface DevServerManagerOptions {\n\t/**\n\t * Maximum time to wait for server to start (in milliseconds)\n\t * Default: 30000 (30 seconds)\n\t */\n\tstartupTimeout?: number\n\n\t/**\n\t * Interval between port checks (in milliseconds)\n\t * Default: 1000 (1 second)\n\t */\n\tcheckInterval?: number\n}\n\n/**\n * DevServerManager handles auto-starting and monitoring dev servers\n * Used by open/run commands to ensure dev server is running before opening browser\n */\nexport class DevServerManager {\n\tprivate readonly processManager: ProcessManager\n\tprivate readonly options: Required<DevServerManagerOptions>\n\tprivate runningServers: Map<number, ExecaChildProcess> = new Map()\n\n\tconstructor(\n\t\tprocessManager?: ProcessManager,\n\t\toptions: DevServerManagerOptions = {}\n\t) {\n\t\tthis.processManager = processManager ?? new ProcessManager()\n\t\tthis.options = {\n\t\t\tstartupTimeout: options.startupTimeout ?? 30000,\n\t\t\tcheckInterval: options.checkInterval ?? 1000,\n\t\t}\n\t}\n\n\t/**\n\t * Ensure dev server is running on the specified port\n\t * If not running, start it and wait for it to be ready\n\t *\n\t * @param worktreePath - Path to the worktree\n\t * @param port - Port the server should run on\n\t * @returns true if server is ready, false if startup failed/timed out\n\t */\n\tasync ensureServerRunning(worktreePath: string, port: number): Promise<boolean> {\n\t\tlogger.debug(`Checking if dev server is running on port ${port}...`)\n\n\t\t// Check if already running\n\t\tconst existingProcess = await this.processManager.detectDevServer(port)\n\t\tif (existingProcess) {\n\t\t\tlogger.debug(\n\t\t\t\t`Dev server already running on port ${port} (PID: ${existingProcess.pid})`\n\t\t\t)\n\t\t\treturn true\n\t\t}\n\n\t\t// Not running - start it\n\t\tlogger.info(`Dev server not running on port ${port}, starting...`)\n\n\t\ttry {\n\t\t\tawait this.startDevServer(worktreePath, port)\n\t\t\treturn true\n\t\t} catch (error) {\n\t\t\tlogger.error(\n\t\t\t\t`Failed to start dev server: ${error instanceof Error ? error.message : 'Unknown error'}`\n\t\t\t)\n\t\t\treturn false\n\t\t}\n\t}\n\n\t/**\n\t * Start dev server in background and wait for it to be ready\n\t */\n\tprivate async startDevServer(worktreePath: string, port: number): Promise<void> {\n\t\t// Build dev server command\n\t\tconst devCommand = await buildDevServerCommand(worktreePath)\n\t\tlogger.debug(`Starting dev server with command: ${devCommand}`)\n\n\t\t// Start server in background\n\t\tconst serverProcess = execa('sh', ['-c', devCommand], {\n\t\t\tcwd: worktreePath,\n\t\t\tenv: {\n\t\t\t\t...process.env,\n\t\t\t\tPORT: port.toString(),\n\t\t\t},\n\t\t\t// Important: Don't inherit stdio - server runs in background\n\t\t\tstdio: 'ignore',\n\t\t\t// Detach from parent process so it continues running\n\t\t\tdetached: true,\n\t\t})\n\n\t\t// Store reference to prevent cleanup\n\t\tthis.runningServers.set(port, serverProcess)\n\n\t\t// Unref so parent can exit\n\t\tserverProcess.unref()\n\n\t\t// Wait for server to be ready\n\t\tlogger.info(`Waiting for dev server to start on port ${port}...`)\n\t\tconst ready = await this.waitForServerReady(port)\n\n\t\tif (!ready) {\n\t\t\tthrow new Error(\n\t\t\t\t`Dev server failed to start within ${this.options.startupTimeout}ms timeout`\n\t\t\t)\n\t\t}\n\n\t\tlogger.success(`Dev server started successfully on port ${port}`)\n\t}\n\n\t/**\n\t * Wait for server to be ready by polling the port\n\t */\n\tprivate async waitForServerReady(port: number): Promise<boolean> {\n\t\tconst startTime = Date.now()\n\t\tlet attempts = 0\n\n\t\twhile (Date.now() - startTime < this.options.startupTimeout) {\n\t\t\tattempts++\n\n\t\t\t// Check if server is listening\n\t\t\tconst processInfo = await this.processManager.detectDevServer(port)\n\n\t\t\tif (processInfo) {\n\t\t\t\tlogger.debug(\n\t\t\t\t\t`Server detected on port ${port} after ${attempts} attempts (${Date.now() - startTime}ms)`\n\t\t\t\t)\n\t\t\t\treturn true\n\t\t\t}\n\n\t\t\t// Wait before next check\n\t\t\tawait setTimeout(this.options.checkInterval)\n\t\t}\n\n\t\t// Timeout\n\t\tlogger.warn(\n\t\t\t`Server did not start on port ${port} after ${this.options.startupTimeout}ms (${attempts} attempts)`\n\t\t)\n\t\treturn false\n\t}\n\n\t/**\n\t * Clean up all running server processes\n\t * This should be called when the manager is being disposed\n\t */\n\tasync cleanup(): Promise<void> {\n\t\tfor (const [port, serverProcess] of this.runningServers.entries()) {\n\t\t\ttry {\n\t\t\t\tlogger.debug(`Cleaning up server process on port ${port}`)\n\t\t\t\tserverProcess.kill()\n\t\t\t} catch (error) {\n\t\t\t\tlogger.warn(\n\t\t\t\t\t`Failed to kill server process on port ${port}: ${error instanceof Error ? error.message : 'Unknown error'}`\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t\tthis.runningServers.clear()\n\t}\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,151 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ detectClaudeCli,
4
+ generateBranchName,
5
+ launchClaude,
6
+ launchClaudeInNewTerminalWindow
7
+ } from "./chunk-PXZBAC2M.js";
8
+ import {
9
+ PromptTemplateManager
10
+ } from "./chunk-F3XBU2R7.js";
11
+ import {
12
+ SettingsManager
13
+ } from "./chunk-JBH2ZYYZ.js";
14
+ import {
15
+ logger
16
+ } from "./chunk-GEHQXLEI.js";
17
+
18
+ // src/lib/ClaudeService.ts
19
+ var ClaudeService = class {
20
+ constructor(templateManager, settingsManager) {
21
+ this.templateManager = templateManager ?? new PromptTemplateManager();
22
+ this.settingsManager = settingsManager ?? new SettingsManager();
23
+ }
24
+ /**
25
+ * Check if Claude CLI is available
26
+ */
27
+ async isAvailable() {
28
+ return detectClaudeCli();
29
+ }
30
+ /**
31
+ * Get the appropriate model for a workflow type
32
+ */
33
+ getModelForWorkflow(type) {
34
+ if (type === "issue") {
35
+ return "claude-sonnet-4-20250514";
36
+ }
37
+ return void 0;
38
+ }
39
+ /**
40
+ * Get the appropriate permission mode for a workflow type
41
+ */
42
+ getPermissionModeForWorkflow(type) {
43
+ var _a;
44
+ if ((_a = this.settings) == null ? void 0 : _a.workflows) {
45
+ const workflowConfig = type === "issue" ? this.settings.workflows.issue : type === "pr" ? this.settings.workflows.pr : this.settings.workflows.regular;
46
+ if (workflowConfig == null ? void 0 : workflowConfig.permissionMode) {
47
+ return workflowConfig.permissionMode;
48
+ }
49
+ }
50
+ if (type === "issue") {
51
+ return "acceptEdits";
52
+ }
53
+ return "default";
54
+ }
55
+ /**
56
+ * Launch Claude for a specific workflow
57
+ */
58
+ async launchForWorkflow(options) {
59
+ const { type, issueNumber, prNumber, title, workspacePath, port, headless = false, branchName, oneShot = "default", setArguments, executablePath } = options;
60
+ try {
61
+ this.settings ??= await this.settingsManager.loadSettings();
62
+ const variables = {
63
+ WORKSPACE_PATH: workspacePath
64
+ };
65
+ if (issueNumber !== void 0) {
66
+ variables.ISSUE_NUMBER = issueNumber;
67
+ }
68
+ if (prNumber !== void 0) {
69
+ variables.PR_NUMBER = prNumber;
70
+ }
71
+ if (title !== void 0) {
72
+ if (type === "issue") {
73
+ variables.ISSUE_TITLE = title;
74
+ } else if (type === "pr") {
75
+ variables.PR_TITLE = title;
76
+ }
77
+ }
78
+ if (port !== void 0) {
79
+ variables.PORT = port;
80
+ }
81
+ const prompt = await this.templateManager.getPrompt(type, variables);
82
+ const model = this.getModelForWorkflow(type);
83
+ const permissionMode = this.getPermissionModeForWorkflow(type);
84
+ if (permissionMode === "bypassPermissions") {
85
+ logger.warn(
86
+ "\u26A0\uFE0F WARNING: Using bypassPermissions mode - Claude will execute all tool calls without confirmation. This can be dangerous. Use with caution."
87
+ );
88
+ }
89
+ const claudeOptions = {
90
+ addDir: workspacePath,
91
+ headless
92
+ };
93
+ if (model !== void 0) {
94
+ claudeOptions.model = model;
95
+ }
96
+ if (permissionMode !== void 0 && permissionMode !== "default") {
97
+ claudeOptions.permissionMode = permissionMode;
98
+ }
99
+ if (branchName !== void 0) {
100
+ claudeOptions.branchName = branchName;
101
+ }
102
+ if (port !== void 0) {
103
+ claudeOptions.port = port;
104
+ }
105
+ if (setArguments !== void 0) {
106
+ claudeOptions.setArguments = setArguments;
107
+ }
108
+ if (executablePath !== void 0) {
109
+ claudeOptions.executablePath = executablePath;
110
+ }
111
+ logger.debug("Launching Claude for workflow", {
112
+ type,
113
+ model,
114
+ permissionMode,
115
+ headless,
116
+ workspacePath
117
+ });
118
+ if (headless) {
119
+ return await launchClaude(prompt, claudeOptions);
120
+ } else {
121
+ if (!claudeOptions.addDir) {
122
+ throw new Error("workspacePath required for interactive workflow launch");
123
+ }
124
+ return await launchClaudeInNewTerminalWindow(prompt, {
125
+ ...claudeOptions,
126
+ workspacePath: claudeOptions.addDir,
127
+ oneShot
128
+ });
129
+ }
130
+ } catch (error) {
131
+ logger.error("Failed to launch Claude for workflow", { error, options });
132
+ throw error;
133
+ }
134
+ }
135
+ /**
136
+ * Generate branch name with Claude, with fallback on failure
137
+ */
138
+ async generateBranchNameWithFallback(issueTitle, issueNumber) {
139
+ try {
140
+ return await generateBranchName(issueTitle, issueNumber);
141
+ } catch (error) {
142
+ logger.warn("Claude branch name generation failed, using fallback", { error });
143
+ return `feat/issue-${issueNumber}`;
144
+ }
145
+ }
146
+ };
147
+
148
+ export {
149
+ ClaudeService
150
+ };
151
+ //# sourceMappingURL=chunk-WKEWRSDB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/ClaudeService.ts"],"sourcesContent":["import { detectClaudeCli, launchClaude, launchClaudeInNewTerminalWindow, ClaudeCliOptions, generateBranchName } from '../utils/claude.js'\nimport { PromptTemplateManager, TemplateVariables } from './PromptTemplateManager.js'\nimport { SettingsManager, IloomSettings } from './SettingsManager.js'\nimport { logger } from '../utils/logger.js'\n\nexport interface ClaudeWorkflowOptions {\n\ttype: 'issue' | 'pr' | 'regular'\n\tissueNumber?: number\n\tprNumber?: number\n\ttitle?: string\n\tworkspacePath: string\n\tport?: number\n\theadless?: boolean\n\tbranchName?: string\n\toneShot?: import('../types/index.js').OneShotMode\n\tsetArguments?: string[] // Raw --set arguments to forward\n\texecutablePath?: string // Executable path to use for spin command\n}\n\nexport class ClaudeService {\n\tprivate templateManager: PromptTemplateManager\n\tprivate settingsManager: SettingsManager\n\tprivate settings?: IloomSettings\n\n\tconstructor(templateManager?: PromptTemplateManager, settingsManager?: SettingsManager) {\n\t\tthis.templateManager = templateManager ?? new PromptTemplateManager()\n\t\tthis.settingsManager = settingsManager ?? new SettingsManager()\n\t}\n\n\t/**\n\t * Check if Claude CLI is available\n\t */\n\tasync isAvailable(): Promise<boolean> {\n\t\treturn detectClaudeCli()\n\t}\n\n\t/**\n\t * Get the appropriate model for a workflow type\n\t */\n\tprivate getModelForWorkflow(type: 'issue' | 'pr' | 'regular'): string | undefined {\n\t\t// Issue workflows use claude-sonnet-4-20250514\n\t\tif (type === 'issue') {\n\t\t\treturn 'claude-sonnet-4-20250514'\n\t\t}\n\t\t// For PR and regular workflows, use Claude's default model\n\t\treturn undefined\n\t}\n\n\t/**\n\t * Get the appropriate permission mode for a workflow type\n\t */\n\tprivate getPermissionModeForWorkflow(\n\t\ttype: 'issue' | 'pr' | 'regular'\n\t): ClaudeCliOptions['permissionMode'] {\n\t\t// Check settings for configured permission mode\n\t\tif (this.settings?.workflows) {\n\t\t\tconst workflowConfig =\n\t\t\t\ttype === 'issue'\n\t\t\t\t\t? this.settings.workflows.issue\n\t\t\t\t\t: type === 'pr'\n\t\t\t\t\t\t? this.settings.workflows.pr\n\t\t\t\t\t\t: this.settings.workflows.regular\n\n\t\t\tif (workflowConfig?.permissionMode) {\n\t\t\t\treturn workflowConfig.permissionMode\n\t\t\t}\n\t\t}\n\n\t\t// Fall back to current defaults\n\t\tif (type === 'issue') {\n\t\t\treturn 'acceptEdits'\n\t\t}\n\t\t// For PR and regular workflows, use default permissions\n\t\treturn 'default'\n\t}\n\n\t/**\n\t * Launch Claude for a specific workflow\n\t */\n\tasync launchForWorkflow(options: ClaudeWorkflowOptions): Promise<string | void> {\n\t\tconst { type, issueNumber, prNumber, title, workspacePath, port, headless = false, branchName, oneShot = 'default', setArguments, executablePath } = options\n\n\t\ttry {\n\t\t\t// Load settings if not already cached\n\t\t\t// Settings are pre-validated at CLI startup, so no error handling needed here\n\t\t\tthis.settings ??= await this.settingsManager.loadSettings()\n\n\t\t\t// Build template variables\n\t\t\tconst variables: TemplateVariables = {\n\t\t\t\tWORKSPACE_PATH: workspacePath,\n\t\t\t}\n\n\t\t\tif (issueNumber !== undefined) {\n\t\t\t\tvariables.ISSUE_NUMBER = issueNumber\n\t\t\t}\n\n\t\t\tif (prNumber !== undefined) {\n\t\t\t\tvariables.PR_NUMBER = prNumber\n\t\t\t}\n\n\t\t\tif (title !== undefined) {\n\t\t\t\tif (type === 'issue') {\n\t\t\t\t\tvariables.ISSUE_TITLE = title\n\t\t\t\t} else if (type === 'pr') {\n\t\t\t\t\tvariables.PR_TITLE = title\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (port !== undefined) {\n\t\t\t\tvariables.PORT = port\n\t\t\t}\n\n\t\t\t// Get the prompt from template manager\n\t\t\tconst prompt = await this.templateManager.getPrompt(type, variables)\n\n\t\t\t// Determine model and permission mode\n\t\t\tconst model = this.getModelForWorkflow(type)\n\t\t\tconst permissionMode = this.getPermissionModeForWorkflow(type)\n\n\t\t\t// Display warning if bypassPermissions mode is used\n\t\t\tif (permissionMode === 'bypassPermissions') {\n\t\t\t\tlogger.warn(\n\t\t\t\t\t'⚠️ WARNING: Using bypassPermissions mode - Claude will execute all tool calls without confirmation. ' +\n\t\t\t\t\t\t'This can be dangerous. Use with caution.'\n\t\t\t\t)\n\t\t\t}\n\n\t\t\t// Build Claude CLI options\n\t\t\tconst claudeOptions: ClaudeCliOptions = {\n\t\t\t\taddDir: workspacePath,\n\t\t\t\theadless,\n\t\t\t}\n\n\t\t\t// Add optional model if present\n\t\t\tif (model !== undefined) {\n\t\t\t\tclaudeOptions.model = model\n\t\t\t}\n\n\t\t\t// Add permission mode if not default\n\t\t\tif (permissionMode !== undefined && permissionMode !== 'default') {\n\t\t\t\tclaudeOptions.permissionMode = permissionMode\n\t\t\t}\n\n\t\t\t// Add optional branch name for terminal coloring\n\t\t\tif (branchName !== undefined) {\n\t\t\t\tclaudeOptions.branchName = branchName\n\t\t\t}\n\n\t\t\t// Add optional port for terminal window export\n\t\t\tif (port !== undefined) {\n\t\t\t\tclaudeOptions.port = port\n\t\t\t}\n\n\t\t\t// Add optional setArguments for forwarding\n\t\t\tif (setArguments !== undefined) {\n\t\t\t\tclaudeOptions.setArguments = setArguments\n\t\t\t}\n\n\t\t\t// Add optional executablePath for spin command\n\t\t\tif (executablePath !== undefined) {\n\t\t\t\tclaudeOptions.executablePath = executablePath\n\t\t\t}\n\n\t\t\tlogger.debug('Launching Claude for workflow', {\n\t\t\t\ttype,\n\t\t\t\tmodel,\n\t\t\t\tpermissionMode,\n\t\t\t\theadless,\n\t\t\t\tworkspacePath,\n\t\t\t})\n\n\t\t\t// Launch Claude\n\t\t\tif (headless) {\n\t\t\t\t// Headless mode: use simple launchClaude\n\t\t\t\treturn await launchClaude(prompt, claudeOptions)\n\t\t\t} else {\n\t\t\t\t// Interactive workflow mode: use terminal window launcher\n\t\t\t\t// This is the \"end of il start\" behavior\n\t\t\t\tif (!claudeOptions.addDir) {\n\t\t\t\t\tthrow new Error('workspacePath required for interactive workflow launch')\n\t\t\t\t}\n\n\t\t\t\treturn await launchClaudeInNewTerminalWindow(prompt, {\n\t\t\t\t\t...claudeOptions,\n\t\t\t\t\tworkspacePath: claudeOptions.addDir,\n\t\t\t\t\toneShot,\n\t\t\t\t})\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tlogger.error('Failed to launch Claude for workflow', { error, options })\n\t\t\tthrow error\n\t\t}\n\t}\n\n\t/**\n\t * Generate branch name with Claude, with fallback on failure\n\t */\n\tasync generateBranchNameWithFallback(issueTitle: string, issueNumber: number): Promise<string> {\n\t\ttry {\n\t\t\treturn await generateBranchName(issueTitle, issueNumber)\n\t\t} catch (error) {\n\t\t\tlogger.warn('Claude branch name generation failed, using fallback', { error })\n\t\t\treturn `feat/issue-${issueNumber}`\n\t\t}\n\t}\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ ClaudeService
4
+ } from "./chunk-WKEWRSDB.js";
5
+ import {
6
+ logger
7
+ } from "./chunk-GEHQXLEI.js";
8
+
9
+ // src/lib/ClaudeContextManager.ts
10
+ var ClaudeContextManager = class {
11
+ constructor(claudeService, _promptTemplateManager, settingsManager) {
12
+ this.claudeService = claudeService ?? new ClaudeService(void 0, settingsManager);
13
+ }
14
+ /**
15
+ * Prepare context for Claude launch
16
+ * Placeholder for future .claude-context.md generation (Issue #11)
17
+ */
18
+ async prepareContext(context) {
19
+ if (!context.workspacePath) {
20
+ throw new Error("Workspace path is required");
21
+ }
22
+ if (context.type === "issue" && typeof context.identifier !== "number") {
23
+ throw new Error("Issue identifier must be a number");
24
+ }
25
+ if (context.type === "pr" && typeof context.identifier !== "number") {
26
+ throw new Error("PR identifier must be a number");
27
+ }
28
+ logger.debug("Context prepared", { context });
29
+ }
30
+ /**
31
+ * Launch Claude with the prepared context
32
+ */
33
+ async launchWithContext(context, headless = false) {
34
+ await this.prepareContext(context);
35
+ const workflowOptions = {
36
+ type: context.type,
37
+ workspacePath: context.workspacePath,
38
+ ...context.port !== void 0 && { port: context.port },
39
+ headless,
40
+ oneShot: context.oneShot ?? "default"
41
+ };
42
+ if (context.title !== void 0) {
43
+ workflowOptions.title = context.title;
44
+ }
45
+ if (context.branchName !== void 0) {
46
+ workflowOptions.branchName = context.branchName;
47
+ }
48
+ if (context.setArguments !== void 0) {
49
+ workflowOptions.setArguments = context.setArguments;
50
+ }
51
+ if (context.executablePath !== void 0) {
52
+ workflowOptions.executablePath = context.executablePath;
53
+ }
54
+ if (context.type === "issue") {
55
+ workflowOptions.issueNumber = context.identifier;
56
+ } else if (context.type === "pr") {
57
+ workflowOptions.prNumber = context.identifier;
58
+ }
59
+ return this.claudeService.launchForWorkflow(workflowOptions);
60
+ }
61
+ };
62
+
63
+ export {
64
+ ClaudeContextManager
65
+ };
66
+ //# sourceMappingURL=chunk-Y7SAGNUT.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/ClaudeContextManager.ts"],"sourcesContent":["import { ClaudeService, ClaudeWorkflowOptions } from './ClaudeService.js'\nimport { PromptTemplateManager } from './PromptTemplateManager.js'\nimport { logger } from '../utils/logger.js'\n\nexport interface ClaudeContext {\n\ttype: 'issue' | 'pr' | 'regular'\n\tidentifier: number | string\n\ttitle?: string\n\tworkspacePath: string\n\tport?: number\n\tbranchName?: string\n\toneShot?: import('../types/index.js').OneShotMode\n\tsetArguments?: string[] // Raw --set arguments to forward\n\texecutablePath?: string // Executable path to use for spin command\n}\n\nexport class ClaudeContextManager {\n\tprivate claudeService: ClaudeService\n\n\tconstructor(claudeService?: ClaudeService, _promptTemplateManager?: PromptTemplateManager, settingsManager?: import('./SettingsManager.js').SettingsManager) {\n\t\tthis.claudeService = claudeService ?? new ClaudeService(undefined, settingsManager)\n\t\t// promptTemplateManager is accepted for dependency injection but not used yet\n\t\t// Will be used in Issue #11 for .claude-context.md generation\n\t}\n\n\t/**\n\t * Prepare context for Claude launch\n\t * Placeholder for future .claude-context.md generation (Issue #11)\n\t */\n\tasync prepareContext(context: ClaudeContext): Promise<void> {\n\t\t// Validate context object\n\t\tif (!context.workspacePath) {\n\t\t\tthrow new Error('Workspace path is required')\n\t\t}\n\n\t\tif (context.type === 'issue' && typeof context.identifier !== 'number') {\n\t\t\tthrow new Error('Issue identifier must be a number')\n\t\t}\n\n\t\tif (context.type === 'pr' && typeof context.identifier !== 'number') {\n\t\t\tthrow new Error('PR identifier must be a number')\n\t\t}\n\n\t\tlogger.debug('Context prepared', { context })\n\t\t// Future: Generate .claude-context.md file in workspace\n\t}\n\n\t/**\n\t * Launch Claude with the prepared context\n\t */\n\tasync launchWithContext(context: ClaudeContext, headless: boolean = false): Promise<string | void> {\n\t\t// Prepare context first\n\t\tawait this.prepareContext(context)\n\n\t\t// Convert ClaudeContext to ClaudeWorkflowOptions\n\t\tconst workflowOptions: ClaudeWorkflowOptions = {\n\t\t\ttype: context.type,\n\t\t\tworkspacePath: context.workspacePath,\n\t\t\t...(context.port !== undefined && { port: context.port }),\n\t\t\theadless,\n\t\t\toneShot: context.oneShot ?? 'default',\n\t\t}\n\n\t\t// Add optional title if present\n\t\tif (context.title !== undefined) {\n\t\t\tworkflowOptions.title = context.title\n\t\t}\n\n\t\t// Add optional branch name if present\n\t\tif (context.branchName !== undefined) {\n\t\t\tworkflowOptions.branchName = context.branchName\n\t\t}\n\n\t\t// Add optional setArguments if present\n\t\tif (context.setArguments !== undefined) {\n\t\t\tworkflowOptions.setArguments = context.setArguments\n\t\t}\n\n\t\t// Add optional executablePath if present\n\t\tif (context.executablePath !== undefined) {\n\t\t\tworkflowOptions.executablePath = context.executablePath\n\t\t}\n\n\t\t// Set issue or PR number based on type\n\t\tif (context.type === 'issue') {\n\t\t\tworkflowOptions.issueNumber = context.identifier as number\n\t\t} else if (context.type === 'pr') {\n\t\t\tworkflowOptions.prNumber = context.identifier as number\n\t\t}\n\n\t\t// Delegate to Claude service\n\t\treturn this.claudeService.launchForWorkflow(workflowOptions)\n\t}\n}\n"],"mappings":";;;;;;;;;AAgBO,IAAM,uBAAN,MAA2B;AAAA,EAGjC,YAAY,eAA+B,wBAAgD,iBAAkE;AAC5J,SAAK,gBAAgB,iBAAiB,IAAI,cAAc,QAAW,eAAe;AAAA,EAGnF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,eAAe,SAAuC;AAE3D,QAAI,CAAC,QAAQ,eAAe;AAC3B,YAAM,IAAI,MAAM,4BAA4B;AAAA,IAC7C;AAEA,QAAI,QAAQ,SAAS,WAAW,OAAO,QAAQ,eAAe,UAAU;AACvE,YAAM,IAAI,MAAM,mCAAmC;AAAA,IACpD;AAEA,QAAI,QAAQ,SAAS,QAAQ,OAAO,QAAQ,eAAe,UAAU;AACpE,YAAM,IAAI,MAAM,gCAAgC;AAAA,IACjD;AAEA,WAAO,MAAM,oBAAoB,EAAE,QAAQ,CAAC;AAAA,EAE7C;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,kBAAkB,SAAwB,WAAoB,OAA+B;AAElG,UAAM,KAAK,eAAe,OAAO;AAGjC,UAAM,kBAAyC;AAAA,MAC9C,MAAM,QAAQ;AAAA,MACd,eAAe,QAAQ;AAAA,MACvB,GAAI,QAAQ,SAAS,UAAa,EAAE,MAAM,QAAQ,KAAK;AAAA,MACvD;AAAA,MACA,SAAS,QAAQ,WAAW;AAAA,IAC7B;AAGA,QAAI,QAAQ,UAAU,QAAW;AAChC,sBAAgB,QAAQ,QAAQ;AAAA,IACjC;AAGA,QAAI,QAAQ,eAAe,QAAW;AACrC,sBAAgB,aAAa,QAAQ;AAAA,IACtC;AAGA,QAAI,QAAQ,iBAAiB,QAAW;AACvC,sBAAgB,eAAe,QAAQ;AAAA,IACxC;AAGA,QAAI,QAAQ,mBAAmB,QAAW;AACzC,sBAAgB,iBAAiB,QAAQ;AAAA,IAC1C;AAGA,QAAI,QAAQ,SAAS,SAAS;AAC7B,sBAAgB,cAAc,QAAQ;AAAA,IACvC,WAAW,QAAQ,SAAS,MAAM;AACjC,sBAAgB,WAAW,QAAQ;AAAA,IACpC;AAGA,WAAO,KAAK,cAAc,kBAAkB,eAAe;AAAA,EAC5D;AACD;","names":[]}
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/utils/browser.ts
4
+ import { execa } from "execa";
5
+ function detectPlatform() {
6
+ const platform = process.platform;
7
+ if (platform === "darwin" || platform === "linux" || platform === "win32") {
8
+ return platform;
9
+ }
10
+ throw new Error(
11
+ `Unsupported platform: ${platform}. Browser opening is only supported on macOS, Linux, and Windows.`
12
+ );
13
+ }
14
+ function getBrowserCommand(platform) {
15
+ switch (platform) {
16
+ case "darwin":
17
+ return { command: "open", args: (url) => [url] };
18
+ case "linux":
19
+ return { command: "xdg-open", args: (url) => [url] };
20
+ case "win32":
21
+ return { command: "cmd", args: (url) => ["/c", "start", url] };
22
+ }
23
+ }
24
+ async function openBrowser(url) {
25
+ try {
26
+ const platform = detectPlatform();
27
+ const { command, args } = getBrowserCommand(platform);
28
+ await execa(command, args(url));
29
+ } catch (error) {
30
+ throw new Error(
31
+ `Failed to open browser: ${error instanceof Error ? error.message : "Unknown error"}`
32
+ );
33
+ }
34
+ }
35
+
36
+ export {
37
+ openBrowser
38
+ };
39
+ //# sourceMappingURL=chunk-YETJNRQM.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/browser.ts"],"sourcesContent":["import { execa } from 'execa'\n\nexport type Platform = 'darwin' | 'linux' | 'win32'\n\n/**\n * Detect the current platform\n * @returns Platform type\n * @throws Error if platform is unsupported\n */\nexport function detectPlatform(): Platform {\n\tconst platform = process.platform\n\n\tif (platform === 'darwin' || platform === 'linux' || platform === 'win32') {\n\t\treturn platform\n\t}\n\n\tthrow new Error(\n\t\t`Unsupported platform: ${platform}. Browser opening is only supported on macOS, Linux, and Windows.`\n\t)\n}\n\n/**\n * Get the browser command for the given platform\n * @param platform - The platform type\n * @returns Command to open browser\n */\nfunction getBrowserCommand(platform: Platform): { command: string; args: (url: string) => string[] } {\n\tswitch (platform) {\n\t\tcase 'darwin':\n\t\t\treturn { command: 'open', args: (url) => [url] }\n\t\tcase 'linux':\n\t\t\treturn { command: 'xdg-open', args: (url) => [url] }\n\t\tcase 'win32':\n\t\t\treturn { command: 'cmd', args: (url) => ['/c', 'start', url] }\n\t}\n}\n\n/**\n * Open a URL in the default browser\n * @param url - The URL to open\n * @throws Error if browser fails to open\n */\nexport async function openBrowser(url: string): Promise<void> {\n\ttry {\n\t\tconst platform = detectPlatform()\n\t\tconst { command, args } = getBrowserCommand(platform)\n\t\tawait execa(command, args(url))\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`Failed to open browser: ${error instanceof Error ? error.message : 'Unknown error'}`\n\t\t)\n\t}\n}\n"],"mappings":";;;AAAA,SAAS,aAAa;AASf,SAAS,iBAA2B;AAC1C,QAAM,WAAW,QAAQ;AAEzB,MAAI,aAAa,YAAY,aAAa,WAAW,aAAa,SAAS;AAC1E,WAAO;AAAA,EACR;AAEA,QAAM,IAAI;AAAA,IACT,yBAAyB,QAAQ;AAAA,EAClC;AACD;AAOA,SAAS,kBAAkB,UAA0E;AACpG,UAAQ,UAAU;AAAA,IACjB,KAAK;AACJ,aAAO,EAAE,SAAS,QAAQ,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE;AAAA,IAChD,KAAK;AACJ,aAAO,EAAE,SAAS,YAAY,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE;AAAA,IACpD,KAAK;AACJ,aAAO,EAAE,SAAS,OAAO,MAAM,CAAC,QAAQ,CAAC,MAAM,SAAS,GAAG,EAAE;AAAA,EAC/D;AACD;AAOA,eAAsB,YAAY,KAA4B;AAC7D,MAAI;AACH,UAAM,WAAW,eAAe;AAChC,UAAM,EAAE,SAAS,KAAK,IAAI,kBAAkB,QAAQ;AACpD,UAAM,MAAM,SAAS,KAAK,GAAG,CAAC;AAAA,EAC/B,SAAS,OAAO;AACf,UAAM,IAAI;AAAA,MACT,2BAA2B,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,IACpF;AAAA,EACD;AACD;","names":[]}