@iloom/cli 0.3.1 → 0.3.3
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.
- package/README.md +8 -6
- package/dist/{BranchNamingService-OMWKUYMM.js → BranchNamingService-A77VI6AI.js} +2 -2
- package/dist/ClaudeContextManager-BN7RE5ZQ.js +15 -0
- package/dist/ClaudeService-DLYLJUPA.js +14 -0
- package/dist/{GitHubService-EBOETDIW.js → GitHubService-FZHHBOFG.js} +3 -3
- package/dist/{LoomLauncher-JF7JZMTZ.js → LoomLauncher-ZV3ZZIBA.js} +40 -26
- package/dist/LoomLauncher-ZV3ZZIBA.js.map +1 -0
- package/dist/{PromptTemplateManager-A52RUAMS.js → PromptTemplateManager-6HH3PVXV.js} +2 -2
- package/dist/README.md +8 -6
- package/dist/{SettingsManager-ZCWJ56WP.js → SettingsManager-I2LRCW2A.js} +2 -2
- package/dist/{SettingsMigrationManager-AGIIIPDQ.js → SettingsMigrationManager-TJ7UWZG5.js} +3 -3
- package/dist/agents/iloom-issue-complexity-evaluator.md +18 -3
- package/dist/agents/iloom-issue-enhancer.md +1 -1
- package/dist/{chunk-TSKY3JI7.js → chunk-2CXREBLZ.js} +2 -2
- package/dist/{chunk-HBYZH6GD.js → chunk-2IJEMXOB.js} +431 -128
- package/dist/chunk-2IJEMXOB.js.map +1 -0
- package/dist/{chunk-IXKLYTWO.js → chunk-2MAIX45J.js} +8 -8
- package/dist/{chunk-4BGK7T6X.js → chunk-5Q3NDNNV.js} +48 -8
- package/dist/chunk-5Q3NDNNV.js.map +1 -0
- package/dist/{chunk-JQFO7QQN.js → chunk-5VK4NRSF.js} +3 -3
- package/dist/{chunk-JQFO7QQN.js.map → chunk-5VK4NRSF.js.map} +1 -1
- package/dist/{chunk-XPKDPZ5D.js → chunk-AKUJXDNW.js} +2 -2
- package/dist/{chunk-O5OH5MRX.js → chunk-CDZERT7Z.js} +23 -11
- package/dist/chunk-CDZERT7Z.js.map +1 -0
- package/dist/{chunk-JKXJ7BGL.js → chunk-CE26YH2U.js} +42 -3
- package/dist/chunk-CE26YH2U.js.map +1 -0
- package/dist/{chunk-ZZZWQGTS.js → chunk-CFFQ2Z7A.js} +74 -75
- package/dist/chunk-CFFQ2Z7A.js.map +1 -0
- package/dist/{chunk-RO26VS3W.js → chunk-DLHA5VQ3.js} +174 -5
- package/dist/chunk-DLHA5VQ3.js.map +1 -0
- package/dist/{chunk-ZBQVSHVT.js → chunk-IFB4Z76W.js} +35 -10
- package/dist/chunk-IFB4Z76W.js.map +1 -0
- package/dist/{chunk-G2IEYOLQ.js → chunk-M7JJCX53.js} +17 -2
- package/dist/chunk-M7JJCX53.js.map +1 -0
- package/dist/{chunk-KLBYVHPK.js → chunk-OSCLCMDG.js} +2 -2
- package/dist/chunk-OXAM2WVC.js +68 -0
- package/dist/chunk-OXAM2WVC.js.map +1 -0
- package/dist/{chunk-ZWFBBPJI.js → chunk-OYF4VIFI.js} +5 -3
- package/dist/chunk-OYF4VIFI.js.map +1 -0
- package/dist/{chunk-U5QDY7ZD.js → chunk-PGPI5LR4.js} +8 -8
- package/dist/{chunk-WEN5C5DM.js → chunk-RIEO2WML.js} +4 -1
- package/dist/chunk-RIEO2WML.js.map +1 -0
- package/dist/{chunk-ZE74H5BR.js → chunk-RW54ZMBM.js} +26 -20
- package/dist/chunk-RW54ZMBM.js.map +1 -0
- package/dist/{chunk-INW24J2W.js → chunk-SUOXY5WJ.js} +2 -2
- package/dist/{init-L55Q73H4.js → chunk-UAN4A3YU.js} +345 -45
- package/dist/chunk-UAN4A3YU.js.map +1 -0
- package/dist/{chunk-IP7SMKIF.js → chunk-UJL4HI2R.js} +59 -60
- package/dist/chunk-UJL4HI2R.js.map +1 -0
- package/dist/{claude-LUZ35IMK.js → claude-W52VKI6L.js} +4 -2
- package/dist/{cleanup-3MONU4PU.js → cleanup-H4VXU3C3.js} +19 -17
- package/dist/{cleanup-3MONU4PU.js.map → cleanup-H4VXU3C3.js.map} +1 -1
- package/dist/cli.js +347 -114
- package/dist/cli.js.map +1 -1
- package/dist/{color-ZVALX37U.js → color-F7RU6B6Z.js} +10 -4
- package/dist/{contribute-UWJAGIG7.js → contribute-Y7IQV5QY.js} +4 -3
- package/dist/{contribute-UWJAGIG7.js.map → contribute-Y7IQV5QY.js.map} +1 -1
- package/dist/{feedback-W3BXTGIM.js → feedback-XTUCKJNT.js} +16 -12
- package/dist/{feedback-W3BXTGIM.js.map → feedback-XTUCKJNT.js.map} +1 -1
- package/dist/{git-34Z6QVDS.js → git-IYA53VIC.js} +9 -2
- package/dist/{ignite-KVJEFXNO.js → ignite-T74RYXCA.js} +25 -75
- package/dist/ignite-T74RYXCA.js.map +1 -0
- package/dist/index.d.ts +71 -14
- package/dist/index.js +407 -377
- package/dist/index.js.map +1 -1
- package/dist/init-4FHTAM3F.js +19 -0
- package/dist/mcp/issue-management-server.js +8 -1
- package/dist/mcp/issue-management-server.js.map +1 -1
- package/dist/{neon-helpers-WPUACUVC.js → neon-helpers-77PBPGJ5.js} +3 -3
- package/dist/{open-LNRZL3UU.js → open-UMXANW5S.js} +27 -14
- package/dist/open-UMXANW5S.js.map +1 -0
- package/dist/{prompt-7INJ7YRU.js → prompt-QALMYTVC.js} +4 -2
- package/dist/prompts/init-prompt.txt +89 -9
- package/dist/prompts/issue-prompt.txt +18 -11
- package/dist/{rebase-C4WNCVGM.js → rebase-VJ2VKR6R.js} +15 -13
- package/dist/rebase-VJ2VKR6R.js.map +1 -0
- package/dist/{run-IOGNIOYN.js → run-MJYY4PUT.js} +27 -14
- package/dist/run-MJYY4PUT.js.map +1 -0
- package/dist/schema/settings.schema.json +22 -4
- package/dist/{test-git-J7I5MFYH.js → test-git-IT5EWQ5C.js} +5 -5
- package/dist/{test-prefix-ZCONBCBX.js → test-prefix-NPWDPUUH.js} +5 -5
- package/dist/{test-tabs-RXDBZ6J7.js → test-tabs-PRMRSHKI.js} +3 -2
- package/dist/{test-tabs-RXDBZ6J7.js.map → test-tabs-PRMRSHKI.js.map} +1 -1
- package/package.json +2 -1
- package/dist/ClaudeContextManager-3VXA6UPR.js +0 -13
- package/dist/ClaudeService-6CPK43N4.js +0 -12
- package/dist/LoomLauncher-JF7JZMTZ.js.map +0 -1
- package/dist/chunk-4BGK7T6X.js.map +0 -1
- package/dist/chunk-4E4LD3QR.js +0 -302
- package/dist/chunk-4E4LD3QR.js.map +0 -1
- package/dist/chunk-G2IEYOLQ.js.map +0 -1
- package/dist/chunk-HBYZH6GD.js.map +0 -1
- package/dist/chunk-IP7SMKIF.js.map +0 -1
- package/dist/chunk-JKXJ7BGL.js.map +0 -1
- package/dist/chunk-O5OH5MRX.js.map +0 -1
- package/dist/chunk-RO26VS3W.js.map +0 -1
- package/dist/chunk-WEN5C5DM.js.map +0 -1
- package/dist/chunk-ZBQVSHVT.js.map +0 -1
- package/dist/chunk-ZE74H5BR.js.map +0 -1
- package/dist/chunk-ZWFBBPJI.js.map +0 -1
- package/dist/chunk-ZZZWQGTS.js.map +0 -1
- package/dist/ignite-KVJEFXNO.js.map +0 -1
- package/dist/init-L55Q73H4.js.map +0 -1
- package/dist/open-LNRZL3UU.js.map +0 -1
- package/dist/rebase-C4WNCVGM.js.map +0 -1
- package/dist/run-IOGNIOYN.js.map +0 -1
- package/dist/terminal-BIRBZ4AZ.js +0 -16
- /package/dist/{BranchNamingService-OMWKUYMM.js.map → BranchNamingService-A77VI6AI.js.map} +0 -0
- /package/dist/{ClaudeContextManager-3VXA6UPR.js.map → ClaudeContextManager-BN7RE5ZQ.js.map} +0 -0
- /package/dist/{ClaudeService-6CPK43N4.js.map → ClaudeService-DLYLJUPA.js.map} +0 -0
- /package/dist/{GitHubService-EBOETDIW.js.map → GitHubService-FZHHBOFG.js.map} +0 -0
- /package/dist/{PromptTemplateManager-A52RUAMS.js.map → PromptTemplateManager-6HH3PVXV.js.map} +0 -0
- /package/dist/{SettingsManager-ZCWJ56WP.js.map → SettingsManager-I2LRCW2A.js.map} +0 -0
- /package/dist/{SettingsMigrationManager-AGIIIPDQ.js.map → SettingsMigrationManager-TJ7UWZG5.js.map} +0 -0
- /package/dist/{chunk-TSKY3JI7.js.map → chunk-2CXREBLZ.js.map} +0 -0
- /package/dist/{chunk-IXKLYTWO.js.map → chunk-2MAIX45J.js.map} +0 -0
- /package/dist/{chunk-XPKDPZ5D.js.map → chunk-AKUJXDNW.js.map} +0 -0
- /package/dist/{chunk-KLBYVHPK.js.map → chunk-OSCLCMDG.js.map} +0 -0
- /package/dist/{chunk-U5QDY7ZD.js.map → chunk-PGPI5LR4.js.map} +0 -0
- /package/dist/{chunk-INW24J2W.js.map → chunk-SUOXY5WJ.js.map} +0 -0
- /package/dist/{claude-LUZ35IMK.js.map → claude-W52VKI6L.js.map} +0 -0
- /package/dist/{color-ZVALX37U.js.map → color-F7RU6B6Z.js.map} +0 -0
- /package/dist/{git-34Z6QVDS.js.map → git-IYA53VIC.js.map} +0 -0
- /package/dist/{neon-helpers-WPUACUVC.js.map → init-4FHTAM3F.js.map} +0 -0
- /package/dist/{prompt-7INJ7YRU.js.map → neon-helpers-77PBPGJ5.js.map} +0 -0
- /package/dist/{terminal-BIRBZ4AZ.js.map → prompt-QALMYTVC.js.map} +0 -0
- /package/dist/{test-git-J7I5MFYH.js.map → test-git-IT5EWQ5C.js.map} +0 -0
- /package/dist/{test-prefix-ZCONBCBX.js.map → test-prefix-NPWDPUUH.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -226,7 +226,7 @@ var init_SettingsManager = __esm({
|
|
|
226
226
|
IloomSettingsSchema = z.object({
|
|
227
227
|
mainBranch: z.string().min(1, "Settings 'mainBranch' cannot be empty").optional().describe("Name of the main/primary branch for the repository"),
|
|
228
228
|
sourceEnvOnStart: z.boolean().default(false).describe(
|
|
229
|
-
"Source .env
|
|
229
|
+
"Source all dotenv-flow files (.env, .env.local, .env.development, .env.development.local) when launching terminal processes (Claude, dev server, terminal). Files are sourced in precedence order so later files override earlier ones. NOTE TO AI AGENTS: Before making changes to settings files, YOU MUST OFFER to check .env file compatibility. WARNING: Unquoted values in .env files may break sourcing in bash/zsh shells. Before enabling, verify ALL your .env.* files do not contain unquoted special characters (e.g., database URLs with ?, &, or other shell metacharacters). Shell compatibility issues may cause processes to fail or behave unexpectedly."
|
|
230
230
|
),
|
|
231
231
|
worktreePrefix: z.string().optional().refine(
|
|
232
232
|
(val) => {
|
|
@@ -272,17 +272,23 @@ var init_SettingsManager = __esm({
|
|
|
272
272
|
remote: z.string().optional()
|
|
273
273
|
}).optional().describe("Merge behavior configuration: local (merge locally) or github-pr (create PR)"),
|
|
274
274
|
ide: z.object({
|
|
275
|
-
type: z.enum(["vscode", "cursor", "webstorm", "sublime", "intellij", "windsurf"]).default("vscode").describe(
|
|
276
|
-
"IDE to launch when starting a loom. Options: vscode (Visual Studio Code), cursor (Cursor AI editor), webstorm (JetBrains WebStorm), sublime (Sublime Text), intellij (JetBrains IntelliJ IDEA), windsurf (Windsurf editor)."
|
|
275
|
+
type: z.enum(["vscode", "cursor", "webstorm", "sublime", "intellij", "windsurf", "antigravity"]).default("vscode").describe(
|
|
276
|
+
"IDE to launch when starting a loom. Options: vscode (Visual Studio Code), cursor (Cursor AI editor), webstorm (JetBrains WebStorm), sublime (Sublime Text), intellij (JetBrains IntelliJ IDEA), windsurf (Windsurf editor), antigravity (Antigravity IDE)."
|
|
277
277
|
)
|
|
278
278
|
}).optional().describe(
|
|
279
|
-
"IDE configuration for workspace launches. Controls which editor opens when you start a loom. Supports VSCode, Cursor, WebStorm, Sublime Text, IntelliJ, and
|
|
280
|
-
)
|
|
279
|
+
"IDE configuration for workspace launches. Controls which editor opens when you start a loom. Supports VSCode, Cursor, WebStorm, Sublime Text, IntelliJ, Windsurf, and Antigravity. Note: Color synchronization (title bar colors) only works with VSCode-compatible editors (vscode, cursor, windsurf, antigravity)."
|
|
280
|
+
),
|
|
281
|
+
colors: z.object({
|
|
282
|
+
terminal: z.boolean().default(true).describe("Apply terminal background colors based on branch name (macOS only)"),
|
|
283
|
+
vscode: z.boolean().default(false).describe(
|
|
284
|
+
"Apply VSCode/Cursor title bar colors based on branch name. Note: This modifies .vscode/settings.json which may be in source control. Default is false for safety; enable via init or explicitly if .vscode is gitignored."
|
|
285
|
+
)
|
|
286
|
+
}).optional().describe("Color synchronization settings for workspace identification")
|
|
281
287
|
});
|
|
282
288
|
IloomSettingsSchemaNoDefaults = z.object({
|
|
283
289
|
mainBranch: z.string().min(1, "Settings 'mainBranch' cannot be empty").optional().describe("Name of the main/primary branch for the repository"),
|
|
284
290
|
sourceEnvOnStart: z.boolean().optional().describe(
|
|
285
|
-
"Source .env
|
|
291
|
+
"Source all dotenv-flow files (.env, .env.local, .env.development, .env.development.local) when launching terminal processes (Claude, dev server, terminal). Files are sourced in precedence order so later files override earlier ones. NOTE TO AI AGENTS: Before making changes to settings files, YOU MUST OFFER to check .env compatibility. WARNING: Unquoted values in .env files may break sourcing in bash/zsh shells. Before enabling, verify ALL your .env.* files do not contain unquoted special characters (e.g., database URLs with ?, &, or other shell metacharacters). Shell compatibility issues may cause processes to fail or behave unexpectedly."
|
|
286
292
|
),
|
|
287
293
|
worktreePrefix: z.string().optional().refine(
|
|
288
294
|
(val) => {
|
|
@@ -328,12 +334,18 @@ var init_SettingsManager = __esm({
|
|
|
328
334
|
remote: z.string().optional()
|
|
329
335
|
}).optional().describe("Merge behavior configuration: local (merge locally) or github-pr (create PR)"),
|
|
330
336
|
ide: z.object({
|
|
331
|
-
type: z.enum(["vscode", "cursor", "webstorm", "sublime", "intellij", "windsurf"]).optional().describe(
|
|
332
|
-
"IDE to launch when starting a loom. Options: vscode (Visual Studio Code), cursor (Cursor AI editor), webstorm (JetBrains WebStorm), sublime (Sublime Text), intellij (JetBrains IntelliJ IDEA), windsurf (Windsurf editor)."
|
|
337
|
+
type: z.enum(["vscode", "cursor", "webstorm", "sublime", "intellij", "windsurf", "antigravity"]).optional().describe(
|
|
338
|
+
"IDE to launch when starting a loom. Options: vscode (Visual Studio Code), cursor (Cursor AI editor), webstorm (JetBrains WebStorm), sublime (Sublime Text), intellij (JetBrains IntelliJ IDEA), windsurf (Windsurf editor), antigravity (Antigravity IDE)."
|
|
333
339
|
)
|
|
334
340
|
}).optional().describe(
|
|
335
|
-
"IDE configuration for workspace launches. Controls which editor opens when you start a loom. Supports VSCode, Cursor, WebStorm, Sublime Text, IntelliJ, and
|
|
336
|
-
)
|
|
341
|
+
"IDE configuration for workspace launches. Controls which editor opens when you start a loom. Supports VSCode, Cursor, WebStorm, Sublime Text, IntelliJ, Windsurf, and Antigravity. Note: Color synchronization (title bar colors) only works with VSCode-compatible editors (vscode, cursor, windsurf, antigravity)."
|
|
342
|
+
),
|
|
343
|
+
colors: z.object({
|
|
344
|
+
terminal: z.boolean().optional().describe("Apply terminal background colors based on branch name (macOS only)"),
|
|
345
|
+
vscode: z.boolean().optional().describe(
|
|
346
|
+
"Apply VSCode/Cursor title bar colors based on branch name. Note: This modifies .vscode/settings.json which may be in source control."
|
|
347
|
+
)
|
|
348
|
+
}).optional().describe("Color synchronization settings for workspace identification")
|
|
337
349
|
});
|
|
338
350
|
SettingsManager = class {
|
|
339
351
|
/**
|
|
@@ -433,8 +445,8 @@ Note: CLI overrides were applied. Check your --set arguments.`);
|
|
|
433
445
|
*/
|
|
434
446
|
formatAllZodErrors(error, settingsPath) {
|
|
435
447
|
const errorMessages = error.issues.map((issue) => {
|
|
436
|
-
const
|
|
437
|
-
return ` - ${
|
|
448
|
+
const path6 = issue.path.length > 0 ? issue.path.join(".") : "root";
|
|
449
|
+
return ` - ${path6}: ${issue.message}`;
|
|
438
450
|
});
|
|
439
451
|
return new Error(
|
|
440
452
|
`Settings validation failed at ${settingsPath}:
|
|
@@ -540,333 +552,55 @@ ${errorMessages.join("\n")}`
|
|
|
540
552
|
}
|
|
541
553
|
});
|
|
542
554
|
|
|
543
|
-
// src/utils/terminal.ts
|
|
544
|
-
var terminal_exports = {};
|
|
545
|
-
__export(terminal_exports, {
|
|
546
|
-
detectITerm2: () => detectITerm2,
|
|
547
|
-
detectPlatform: () => detectPlatform,
|
|
548
|
-
openDualTerminalWindow: () => openDualTerminalWindow,
|
|
549
|
-
openMultipleTerminalWindows: () => openMultipleTerminalWindows,
|
|
550
|
-
openTerminalWindow: () => openTerminalWindow
|
|
551
|
-
});
|
|
552
|
-
import { execa as execa3 } from "execa";
|
|
553
|
-
import { existsSync } from "fs";
|
|
554
|
-
function detectPlatform() {
|
|
555
|
-
const platform = process.platform;
|
|
556
|
-
if (platform === "darwin") return "darwin";
|
|
557
|
-
if (platform === "linux") return "linux";
|
|
558
|
-
if (platform === "win32") return "win32";
|
|
559
|
-
return "unsupported";
|
|
560
|
-
}
|
|
561
|
-
async function detectITerm2() {
|
|
562
|
-
const platform = detectPlatform();
|
|
563
|
-
if (platform !== "darwin") return false;
|
|
564
|
-
return existsSync("/Applications/iTerm.app");
|
|
565
|
-
}
|
|
566
|
-
async function openTerminalWindow(options) {
|
|
567
|
-
const platform = detectPlatform();
|
|
568
|
-
if (platform !== "darwin") {
|
|
569
|
-
throw new Error(
|
|
570
|
-
`Terminal window launching not yet supported on ${platform}. Currently only macOS is supported.`
|
|
571
|
-
);
|
|
572
|
-
}
|
|
573
|
-
const hasITerm2 = await detectITerm2();
|
|
574
|
-
const applescript = hasITerm2 ? buildITerm2SingleTabScript(options) : buildAppleScript(options);
|
|
575
|
-
try {
|
|
576
|
-
await execa3("osascript", ["-e", applescript]);
|
|
577
|
-
if (!hasITerm2) {
|
|
578
|
-
await execa3("osascript", ["-e", 'tell application "Terminal" to activate']);
|
|
579
|
-
}
|
|
580
|
-
} catch (error) {
|
|
581
|
-
throw new Error(
|
|
582
|
-
`Failed to open terminal window: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
583
|
-
);
|
|
584
|
-
}
|
|
585
|
-
}
|
|
586
|
-
function buildAppleScript(options) {
|
|
587
|
-
const {
|
|
588
|
-
workspacePath,
|
|
589
|
-
command,
|
|
590
|
-
backgroundColor,
|
|
591
|
-
port,
|
|
592
|
-
includeEnvSetup,
|
|
593
|
-
includePortExport
|
|
594
|
-
} = options;
|
|
595
|
-
const commands = [];
|
|
596
|
-
if (workspacePath) {
|
|
597
|
-
commands.push(`cd '${escapePathForAppleScript(workspacePath)}'`);
|
|
598
|
-
}
|
|
599
|
-
if (includeEnvSetup) {
|
|
600
|
-
commands.push("source .env");
|
|
601
|
-
}
|
|
602
|
-
if (includePortExport && port !== void 0) {
|
|
603
|
-
commands.push(`export PORT=${port}`);
|
|
604
|
-
}
|
|
605
|
-
if (command) {
|
|
606
|
-
commands.push(command);
|
|
607
|
-
}
|
|
608
|
-
const fullCommand = commands.join(" && ");
|
|
609
|
-
const historyFreeCommand = ` ${fullCommand}`;
|
|
610
|
-
let script = `tell application "Terminal"
|
|
611
|
-
`;
|
|
612
|
-
script += ` set newTab to do script "${escapeForAppleScript(historyFreeCommand)}"
|
|
613
|
-
`;
|
|
614
|
-
if (backgroundColor) {
|
|
615
|
-
const { r, g, b } = backgroundColor;
|
|
616
|
-
script += ` set background color of newTab to {${Math.round(r * 257)}, ${Math.round(g * 257)}, ${Math.round(b * 257)}}
|
|
617
|
-
`;
|
|
618
|
-
}
|
|
619
|
-
script += `end tell`;
|
|
620
|
-
return script;
|
|
621
|
-
}
|
|
622
|
-
function escapePathForAppleScript(path5) {
|
|
623
|
-
return path5.replace(/'/g, "'\\''");
|
|
624
|
-
}
|
|
625
|
-
function escapeForAppleScript(command) {
|
|
626
|
-
return command.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
627
|
-
}
|
|
628
|
-
function buildITerm2SingleTabScript(options) {
|
|
629
|
-
const command = buildCommandSequence(options);
|
|
630
|
-
let script = 'tell application id "com.googlecode.iterm2"\n';
|
|
631
|
-
script += " create window with default profile\n";
|
|
632
|
-
script += " set s1 to current session of current window\n\n";
|
|
633
|
-
if (options.backgroundColor) {
|
|
634
|
-
const { r, g, b } = options.backgroundColor;
|
|
635
|
-
script += ` set background color of s1 to {${Math.round(r * 257)}, ${Math.round(g * 257)}, ${Math.round(b * 257)}}
|
|
636
|
-
`;
|
|
637
|
-
}
|
|
638
|
-
script += ` tell s1 to write text "${escapeForAppleScript(command)}"
|
|
639
|
-
|
|
640
|
-
`;
|
|
641
|
-
if (options.title) {
|
|
642
|
-
script += ` set name of s1 to "${escapeForAppleScript(options.title)}"
|
|
643
|
-
|
|
644
|
-
`;
|
|
645
|
-
}
|
|
646
|
-
script += " activate\n";
|
|
647
|
-
script += "end tell";
|
|
648
|
-
return script;
|
|
649
|
-
}
|
|
650
|
-
function buildCommandSequence(options) {
|
|
651
|
-
const {
|
|
652
|
-
workspacePath,
|
|
653
|
-
command,
|
|
654
|
-
port,
|
|
655
|
-
includeEnvSetup,
|
|
656
|
-
includePortExport
|
|
657
|
-
} = options;
|
|
658
|
-
const commands = [];
|
|
659
|
-
if (workspacePath) {
|
|
660
|
-
commands.push(`cd '${escapePathForAppleScript(workspacePath)}'`);
|
|
661
|
-
}
|
|
662
|
-
if (includeEnvSetup) {
|
|
663
|
-
commands.push("source .env");
|
|
664
|
-
}
|
|
665
|
-
if (includePortExport && port !== void 0) {
|
|
666
|
-
commands.push(`export PORT=${port}`);
|
|
667
|
-
}
|
|
668
|
-
if (command) {
|
|
669
|
-
commands.push(command);
|
|
670
|
-
}
|
|
671
|
-
const fullCommand = commands.join(" && ");
|
|
672
|
-
return ` ${fullCommand}`;
|
|
673
|
-
}
|
|
674
|
-
function buildITerm2MultiTabScript(optionsArray) {
|
|
675
|
-
if (optionsArray.length < 2) {
|
|
676
|
-
throw new Error("buildITerm2MultiTabScript requires at least 2 terminal options");
|
|
677
|
-
}
|
|
678
|
-
let script = 'tell application id "com.googlecode.iterm2"\n';
|
|
679
|
-
script += " create window with default profile\n";
|
|
680
|
-
script += " set newWindow to current window\n";
|
|
681
|
-
const options1 = optionsArray[0];
|
|
682
|
-
if (!options1) {
|
|
683
|
-
throw new Error("First terminal option is undefined");
|
|
684
|
-
}
|
|
685
|
-
const command1 = buildCommandSequence(options1);
|
|
686
|
-
script += " set s1 to current session of newWindow\n\n";
|
|
687
|
-
if (options1.backgroundColor) {
|
|
688
|
-
const { r, g, b } = options1.backgroundColor;
|
|
689
|
-
script += ` set background color of s1 to {${Math.round(r * 257)}, ${Math.round(g * 257)}, ${Math.round(b * 257)}}
|
|
690
|
-
`;
|
|
691
|
-
}
|
|
692
|
-
script += ` tell s1 to write text "${escapeForAppleScript(command1)}"
|
|
693
|
-
|
|
694
|
-
`;
|
|
695
|
-
if (options1.title) {
|
|
696
|
-
script += ` set name of s1 to "${escapeForAppleScript(options1.title)}"
|
|
697
|
-
|
|
698
|
-
`;
|
|
699
|
-
}
|
|
700
|
-
for (let i = 1; i < optionsArray.length; i++) {
|
|
701
|
-
const options = optionsArray[i];
|
|
702
|
-
if (!options) {
|
|
703
|
-
throw new Error(`Terminal option at index ${i} is undefined`);
|
|
704
|
-
}
|
|
705
|
-
const command = buildCommandSequence(options);
|
|
706
|
-
const sessionVar = `s${i + 1}`;
|
|
707
|
-
script += " tell newWindow\n";
|
|
708
|
-
script += ` set newTab${i} to (create tab with default profile)
|
|
709
|
-
`;
|
|
710
|
-
script += " end tell\n";
|
|
711
|
-
script += ` set ${sessionVar} to current session of newTab${i}
|
|
712
|
-
|
|
713
|
-
`;
|
|
714
|
-
if (options.backgroundColor) {
|
|
715
|
-
const { r, g, b } = options.backgroundColor;
|
|
716
|
-
script += ` set background color of ${sessionVar} to {${Math.round(r * 257)}, ${Math.round(g * 257)}, ${Math.round(b * 257)}}
|
|
717
|
-
`;
|
|
718
|
-
}
|
|
719
|
-
script += ` tell ${sessionVar} to write text "${escapeForAppleScript(command)}"
|
|
720
|
-
|
|
721
|
-
`;
|
|
722
|
-
if (options.title) {
|
|
723
|
-
script += ` set name of ${sessionVar} to "${escapeForAppleScript(options.title)}"
|
|
724
|
-
|
|
725
|
-
`;
|
|
726
|
-
}
|
|
727
|
-
}
|
|
728
|
-
script += " activate\n";
|
|
729
|
-
script += "end tell";
|
|
730
|
-
return script;
|
|
731
|
-
}
|
|
732
|
-
async function openMultipleTerminalWindows(optionsArray) {
|
|
733
|
-
if (optionsArray.length < 2) {
|
|
734
|
-
throw new Error("openMultipleTerminalWindows requires at least 2 terminal options. Use openTerminalWindow for single terminal.");
|
|
735
|
-
}
|
|
736
|
-
const platform = detectPlatform();
|
|
737
|
-
if (platform !== "darwin") {
|
|
738
|
-
throw new Error(
|
|
739
|
-
`Terminal window launching not yet supported on ${platform}. Currently only macOS is supported.`
|
|
740
|
-
);
|
|
741
|
-
}
|
|
742
|
-
const hasITerm2 = await detectITerm2();
|
|
743
|
-
if (hasITerm2) {
|
|
744
|
-
const applescript = buildITerm2MultiTabScript(optionsArray);
|
|
745
|
-
try {
|
|
746
|
-
await execa3("osascript", ["-e", applescript]);
|
|
747
|
-
} catch (error) {
|
|
748
|
-
throw new Error(
|
|
749
|
-
`Failed to open iTerm2 window: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
750
|
-
);
|
|
751
|
-
}
|
|
752
|
-
} else {
|
|
753
|
-
for (let i = 0; i < optionsArray.length; i++) {
|
|
754
|
-
const options = optionsArray[i];
|
|
755
|
-
if (!options) {
|
|
756
|
-
throw new Error(`Terminal option at index ${i} is undefined`);
|
|
757
|
-
}
|
|
758
|
-
await openTerminalWindow(options);
|
|
759
|
-
if (i < optionsArray.length - 1) {
|
|
760
|
-
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
761
|
-
}
|
|
762
|
-
}
|
|
763
|
-
}
|
|
764
|
-
}
|
|
765
|
-
async function openDualTerminalWindow(options1, options2) {
|
|
766
|
-
await openMultipleTerminalWindows([options1, options2]);
|
|
767
|
-
}
|
|
768
|
-
var init_terminal = __esm({
|
|
769
|
-
"src/utils/terminal.ts"() {
|
|
770
|
-
"use strict";
|
|
771
|
-
}
|
|
772
|
-
});
|
|
773
|
-
|
|
774
555
|
// src/utils/color.ts
|
|
775
556
|
var color_exports = {};
|
|
776
557
|
__export(color_exports, {
|
|
558
|
+
MIN_COLOR_DISTANCE: () => MIN_COLOR_DISTANCE,
|
|
777
559
|
calculateForegroundColor: () => calculateForegroundColor,
|
|
560
|
+
colorDistance: () => colorDistance,
|
|
778
561
|
generateColorFromBranchName: () => generateColorFromBranchName,
|
|
779
562
|
getColorPalette: () => getColorPalette,
|
|
780
563
|
hexToRgb: () => hexToRgb,
|
|
781
564
|
lightenColor: () => lightenColor,
|
|
782
565
|
rgbToHex: () => rgbToHex,
|
|
783
|
-
saturateColor: () => saturateColor
|
|
566
|
+
saturateColor: () => saturateColor,
|
|
567
|
+
selectDistinctColor: () => selectDistinctColor
|
|
784
568
|
});
|
|
785
569
|
import { createHash as createHash2 } from "crypto";
|
|
786
570
|
function getColorPalette() {
|
|
787
571
|
return [
|
|
788
|
-
|
|
789
|
-
{ r: 220, g: 235, b: 248 },
|
|
572
|
+
{ r: 220, g: 235, b: 255 },
|
|
790
573
|
// 0: Soft blue
|
|
791
|
-
{ r:
|
|
574
|
+
{ r: 255, g: 220, b: 235 },
|
|
792
575
|
// 1: Soft pink
|
|
793
|
-
{ r: 220, g:
|
|
576
|
+
{ r: 220, g: 255, b: 235 },
|
|
794
577
|
// 2: Soft green
|
|
795
|
-
{ r:
|
|
578
|
+
{ r: 255, g: 245, b: 220 },
|
|
796
579
|
// 3: Soft cream
|
|
797
|
-
{ r:
|
|
580
|
+
{ r: 245, g: 220, b: 255 },
|
|
798
581
|
// 4: Soft lavender
|
|
799
|
-
{ r: 220, g:
|
|
582
|
+
{ r: 220, g: 245, b: 255 },
|
|
800
583
|
// 5: Soft cyan
|
|
801
584
|
{ r: 235, g: 235, b: 235 },
|
|
802
585
|
// 6: Soft grey
|
|
803
|
-
{ r:
|
|
804
|
-
// 7: Soft
|
|
805
|
-
{ r:
|
|
806
|
-
// 8: Soft
|
|
807
|
-
{ r:
|
|
808
|
-
// 9: Soft
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
// 15: Pale sage
|
|
822
|
-
{ r: 245, g: 250, b: 235 },
|
|
823
|
-
// 16: Pale lemon
|
|
824
|
-
{ r: 245, g: 235, b: 235 },
|
|
825
|
-
// 17: Pale blush
|
|
826
|
-
{ r: 235, g: 235, b: 250 },
|
|
827
|
-
// 18: Pale lavender blue
|
|
828
|
-
{ r: 250, g: 235, b: 235 },
|
|
829
|
-
// 19: Pale coral
|
|
830
|
-
{ r: 235, g: 250, b: 250 },
|
|
831
|
-
// 20: Pale aqua
|
|
832
|
-
{ r: 240, g: 248, b: 255 },
|
|
833
|
-
// 21: Alice blue
|
|
834
|
-
{ r: 255, g: 240, b: 248 },
|
|
835
|
-
// 22: Lavender blush
|
|
836
|
-
{ r: 240, g: 255, b: 248 },
|
|
837
|
-
// 23: Honeydew tint
|
|
838
|
-
{ r: 255, g: 248, b: 240 },
|
|
839
|
-
// 24: Antique white
|
|
840
|
-
{ r: 248, g: 240, b: 255 },
|
|
841
|
-
// 25: Magnolia
|
|
842
|
-
{ r: 240, g: 248, b: 240 },
|
|
843
|
-
// 26: Mint cream tint
|
|
844
|
-
{ r: 248, g: 255, b: 240 },
|
|
845
|
-
// 27: Ivory tint
|
|
846
|
-
{ r: 248, g: 240, b: 240 },
|
|
847
|
-
// 28: Misty rose tint
|
|
848
|
-
{ r: 240, g: 240, b: 255 },
|
|
849
|
-
// 29: Ghost white tint
|
|
850
|
-
{ r: 255, g: 245, b: 238 },
|
|
851
|
-
// 30: Seashell
|
|
852
|
-
{ r: 245, g: 255, b: 250 },
|
|
853
|
-
// 31: Azure mist
|
|
854
|
-
{ r: 250, g: 245, b: 255 },
|
|
855
|
-
// 32: Lilac mist
|
|
856
|
-
{ r: 255, g: 250, b: 245 },
|
|
857
|
-
// 33: Snow peach
|
|
858
|
-
{ r: 238, g: 245, b: 255 },
|
|
859
|
-
// 34: Powder blue
|
|
860
|
-
{ r: 255, g: 238, b: 245 },
|
|
861
|
-
// 35: Pink lace
|
|
862
|
-
{ r: 245, g: 255, b: 238 },
|
|
863
|
-
// 36: Pale lime
|
|
864
|
-
{ r: 238, g: 255, b: 245 },
|
|
865
|
-
// 37: Pale turquoise
|
|
866
|
-
{ r: 245, g: 238, b: 255 },
|
|
867
|
-
// 38: Pale violet
|
|
868
|
-
{ r: 255, g: 245, b: 255 }
|
|
869
|
-
// 39: Pale magenta
|
|
586
|
+
{ r: 255, g: 230, b: 230 },
|
|
587
|
+
// 7: Soft coral
|
|
588
|
+
{ r: 230, g: 255, b: 230 },
|
|
589
|
+
// 8: Soft mint
|
|
590
|
+
{ r: 255, g: 245, b: 230 },
|
|
591
|
+
// 9: Soft peach
|
|
592
|
+
{ r: 220, g: 255, b: 255 },
|
|
593
|
+
// 10: Soft aqua
|
|
594
|
+
{ r: 255, g: 220, b: 255 },
|
|
595
|
+
// 11: Soft magenta
|
|
596
|
+
{ r: 255, g: 255, b: 220 },
|
|
597
|
+
// 12: Soft yellow
|
|
598
|
+
{ r: 235, g: 220, b: 255 },
|
|
599
|
+
// 13: Soft violet
|
|
600
|
+
{ r: 220, g: 255, b: 245 },
|
|
601
|
+
// 14: Soft sea green
|
|
602
|
+
{ r: 255, g: 235, b: 220 }
|
|
603
|
+
// 15: Soft salmon
|
|
870
604
|
];
|
|
871
605
|
}
|
|
872
606
|
function rgbToHex(r, g, b) {
|
|
@@ -906,6 +640,51 @@ function generateColorFromBranchName(branchName) {
|
|
|
906
640
|
index
|
|
907
641
|
};
|
|
908
642
|
}
|
|
643
|
+
function colorDistance(a, b) {
|
|
644
|
+
return Math.sqrt(
|
|
645
|
+
Math.pow(a.r - b.r, 2) + Math.pow(a.g - b.g, 2) + Math.pow(a.b - b.b, 2)
|
|
646
|
+
);
|
|
647
|
+
}
|
|
648
|
+
function selectDistinctColor(branchName, usedHexColors) {
|
|
649
|
+
const palette = getColorPalette();
|
|
650
|
+
const hashBasedColor = generateColorFromBranchName(branchName);
|
|
651
|
+
if (usedHexColors.length === 0) {
|
|
652
|
+
return hashBasedColor;
|
|
653
|
+
}
|
|
654
|
+
const usedRgbColors = [];
|
|
655
|
+
for (const hex of usedHexColors) {
|
|
656
|
+
try {
|
|
657
|
+
usedRgbColors.push(hexToRgb(hex));
|
|
658
|
+
} catch {
|
|
659
|
+
logger_default.debug(`[selectDistinctColor] Skipping invalid hex color: ${hex}`);
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
if (usedRgbColors.length === 0) {
|
|
663
|
+
return hashBasedColor;
|
|
664
|
+
}
|
|
665
|
+
const isTooSimilar = usedRgbColors.some(
|
|
666
|
+
(usedRgb) => colorDistance(hashBasedColor.rgb, usedRgb) < MIN_COLOR_DISTANCE
|
|
667
|
+
);
|
|
668
|
+
if (!isTooSimilar) {
|
|
669
|
+
return hashBasedColor;
|
|
670
|
+
}
|
|
671
|
+
for (let i = 0; i < palette.length; i++) {
|
|
672
|
+
const candidateRgb = palette[i];
|
|
673
|
+
if (!candidateRgb) continue;
|
|
674
|
+
const isDistinct = usedRgbColors.every(
|
|
675
|
+
(usedRgb) => colorDistance(candidateRgb, usedRgb) >= MIN_COLOR_DISTANCE
|
|
676
|
+
);
|
|
677
|
+
if (isDistinct) {
|
|
678
|
+
return {
|
|
679
|
+
rgb: candidateRgb,
|
|
680
|
+
hex: rgbToHex(candidateRgb.r, candidateRgb.g, candidateRgb.b),
|
|
681
|
+
index: i
|
|
682
|
+
};
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
logger_default.debug(`[selectDistinctColor] No distinct color found, falling back to hash-based for ${branchName}`);
|
|
686
|
+
return hashBasedColor;
|
|
687
|
+
}
|
|
909
688
|
function lightenColor(rgb, amount) {
|
|
910
689
|
const clamp = (value) => Math.min(255, Math.max(0, Math.round(value)));
|
|
911
690
|
return {
|
|
@@ -934,10 +713,12 @@ function calculateForegroundColor(rgb) {
|
|
|
934
713
|
const luminance = 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
|
935
714
|
return luminance > 0.5 ? "#000000" : "#ffffff";
|
|
936
715
|
}
|
|
716
|
+
var MIN_COLOR_DISTANCE;
|
|
937
717
|
var init_color = __esm({
|
|
938
718
|
"src/utils/color.ts"() {
|
|
939
719
|
"use strict";
|
|
940
720
|
init_logger();
|
|
721
|
+
MIN_COLOR_DISTANCE = 20;
|
|
941
722
|
}
|
|
942
723
|
});
|
|
943
724
|
|
|
@@ -951,6 +732,7 @@ import path3 from "path";
|
|
|
951
732
|
import fs from "fs-extra";
|
|
952
733
|
|
|
953
734
|
// src/utils/git.ts
|
|
735
|
+
init_SettingsManager();
|
|
954
736
|
init_logger();
|
|
955
737
|
import path2 from "path";
|
|
956
738
|
import { execa } from "execa";
|
|
@@ -1097,7 +879,7 @@ function extractIssueNumber(branchName) {
|
|
|
1097
879
|
}
|
|
1098
880
|
return null;
|
|
1099
881
|
}
|
|
1100
|
-
function isWorktreePath(
|
|
882
|
+
function isWorktreePath(path6) {
|
|
1101
883
|
const worktreePatterns = [
|
|
1102
884
|
/\/worktrees?\//i,
|
|
1103
885
|
// Contains /worktree/ or /worktrees/
|
|
@@ -1112,7 +894,7 @@ function isWorktreePath(path5) {
|
|
|
1112
894
|
/\.worktree$/i
|
|
1113
895
|
// ends with .worktree
|
|
1114
896
|
];
|
|
1115
|
-
return worktreePatterns.some((pattern) => pattern.test(
|
|
897
|
+
return worktreePatterns.some((pattern) => pattern.test(path6));
|
|
1116
898
|
}
|
|
1117
899
|
function generateWorktreePath(branchName, rootDir = process.cwd(), options) {
|
|
1118
900
|
let sanitized = branchName.replace(/\//g, "-");
|
|
@@ -1154,31 +936,31 @@ function generateWorktreePath(branchName, rootDir = process.cwd(), options) {
|
|
|
1154
936
|
return path2.join(parentDir, `${prefix}${sanitized}`);
|
|
1155
937
|
}
|
|
1156
938
|
}
|
|
1157
|
-
async function isValidGitRepo(
|
|
939
|
+
async function isValidGitRepo(path6) {
|
|
1158
940
|
try {
|
|
1159
|
-
await executeGitCommand(["rev-parse", "--git-dir"], { cwd:
|
|
941
|
+
await executeGitCommand(["rev-parse", "--git-dir"], { cwd: path6 });
|
|
1160
942
|
return true;
|
|
1161
943
|
} catch {
|
|
1162
944
|
return false;
|
|
1163
945
|
}
|
|
1164
946
|
}
|
|
1165
|
-
async function getCurrentBranch(
|
|
947
|
+
async function getCurrentBranch(path6 = process.cwd()) {
|
|
1166
948
|
try {
|
|
1167
|
-
const result = await executeGitCommand(["branch", "--show-current"], { cwd:
|
|
949
|
+
const result = await executeGitCommand(["branch", "--show-current"], { cwd: path6 });
|
|
1168
950
|
return result.trim();
|
|
1169
951
|
} catch {
|
|
1170
952
|
return null;
|
|
1171
953
|
}
|
|
1172
954
|
}
|
|
1173
|
-
async function branchExists(branchName,
|
|
955
|
+
async function branchExists(branchName, path6 = process.cwd(), includeRemote = true) {
|
|
1174
956
|
try {
|
|
1175
|
-
const localResult = await executeGitCommand(["branch", "--list", branchName], { cwd:
|
|
957
|
+
const localResult = await executeGitCommand(["branch", "--list", branchName], { cwd: path6 });
|
|
1176
958
|
if (localResult.trim()) {
|
|
1177
959
|
return true;
|
|
1178
960
|
}
|
|
1179
961
|
if (includeRemote) {
|
|
1180
962
|
const remoteResult = await executeGitCommand(["branch", "-r", "--list", `*/${branchName}`], {
|
|
1181
|
-
cwd:
|
|
963
|
+
cwd: path6
|
|
1182
964
|
});
|
|
1183
965
|
if (remoteResult.trim()) {
|
|
1184
966
|
return true;
|
|
@@ -1189,17 +971,31 @@ async function branchExists(branchName, path5 = process.cwd(), includeRemote = t
|
|
|
1189
971
|
return false;
|
|
1190
972
|
}
|
|
1191
973
|
}
|
|
1192
|
-
async function
|
|
974
|
+
async function getWorktreeRoot(path6 = process.cwd()) {
|
|
1193
975
|
try {
|
|
1194
|
-
const result = await executeGitCommand(["rev-parse", "--show-toplevel"], { cwd:
|
|
976
|
+
const result = await executeGitCommand(["rev-parse", "--show-toplevel"], { cwd: path6 });
|
|
1195
977
|
return result.trim();
|
|
1196
978
|
} catch {
|
|
1197
979
|
return null;
|
|
1198
980
|
}
|
|
1199
981
|
}
|
|
1200
|
-
async function
|
|
982
|
+
async function getRepoRoot(path6 = process.cwd()) {
|
|
983
|
+
try {
|
|
984
|
+
const gitCommonDir = await executeGitCommand(
|
|
985
|
+
["rev-parse", "--path-format=absolute", "--git-common-dir"],
|
|
986
|
+
{ cwd: path6 }
|
|
987
|
+
);
|
|
988
|
+
const trimmedPath = gitCommonDir.trim();
|
|
989
|
+
const repoRoot = trimmedPath.replace(/\/\.git\/worktrees\/[^/]+$/, "").replace(/\/\.git$/, "");
|
|
990
|
+
return repoRoot;
|
|
991
|
+
} catch (error) {
|
|
992
|
+
logger.warn(`Failed to determine repo root from git-common-dir: ${path6}`, error instanceof Error ? error.message : String(error));
|
|
993
|
+
return null;
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
async function findMainWorktreePath(path6 = process.cwd(), options) {
|
|
1201
997
|
try {
|
|
1202
|
-
const output = await executeGitCommand(["worktree", "list", "--porcelain"], { cwd:
|
|
998
|
+
const output = await executeGitCommand(["worktree", "list", "--porcelain"], { cwd: path6 });
|
|
1203
999
|
const worktrees = parseWorktreeList(output, options == null ? void 0 : options.mainBranch);
|
|
1204
1000
|
if (worktrees.length === 0) {
|
|
1205
1001
|
throw new Error("No worktrees found in repository");
|
|
@@ -1229,33 +1025,30 @@ async function findMainWorktreePath(path5 = process.cwd(), options) {
|
|
|
1229
1025
|
throw new Error(`Failed to find main worktree: ${error instanceof Error ? error.message : String(error)}`);
|
|
1230
1026
|
}
|
|
1231
1027
|
}
|
|
1232
|
-
async function findMainWorktreePathWithSettings(
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
settingsManager = new SM();
|
|
1236
|
-
}
|
|
1237
|
-
const settings = await settingsManager.loadSettings(path5);
|
|
1028
|
+
async function findMainWorktreePathWithSettings(path6, settingsManager) {
|
|
1029
|
+
settingsManager ??= new SettingsManager();
|
|
1030
|
+
const settings = await settingsManager.loadSettings(path6);
|
|
1238
1031
|
const findOptions = settings.mainBranch ? { mainBranch: settings.mainBranch } : void 0;
|
|
1239
|
-
return findMainWorktreePath(
|
|
1032
|
+
return findMainWorktreePath(path6, findOptions);
|
|
1240
1033
|
}
|
|
1241
|
-
async function hasUncommittedChanges(
|
|
1034
|
+
async function hasUncommittedChanges(path6 = process.cwd()) {
|
|
1242
1035
|
try {
|
|
1243
|
-
const result = await executeGitCommand(["status", "--porcelain"], { cwd:
|
|
1036
|
+
const result = await executeGitCommand(["status", "--porcelain"], { cwd: path6 });
|
|
1244
1037
|
return result.trim().length > 0;
|
|
1245
1038
|
} catch {
|
|
1246
1039
|
return false;
|
|
1247
1040
|
}
|
|
1248
1041
|
}
|
|
1249
|
-
async function getDefaultBranch(
|
|
1042
|
+
async function getDefaultBranch(path6 = process.cwd()) {
|
|
1250
1043
|
try {
|
|
1251
1044
|
const remoteResult = await executeGitCommand(["symbolic-ref", "refs/remotes/origin/HEAD"], {
|
|
1252
|
-
cwd:
|
|
1045
|
+
cwd: path6
|
|
1253
1046
|
});
|
|
1254
1047
|
const match = remoteResult.match(/refs\/remotes\/origin\/(.+)/);
|
|
1255
1048
|
if (match) return match[1] ?? "main";
|
|
1256
1049
|
const commonDefaults = ["main", "master", "develop"];
|
|
1257
1050
|
for (const branch of commonDefaults) {
|
|
1258
|
-
if (await branchExists(branch,
|
|
1051
|
+
if (await branchExists(branch, path6)) {
|
|
1259
1052
|
return branch;
|
|
1260
1053
|
}
|
|
1261
1054
|
}
|
|
@@ -1264,13 +1057,13 @@ async function getDefaultBranch(path5 = process.cwd()) {
|
|
|
1264
1057
|
return "main";
|
|
1265
1058
|
}
|
|
1266
1059
|
}
|
|
1267
|
-
async function findAllBranchesForIssue(issueNumber,
|
|
1060
|
+
async function findAllBranchesForIssue(issueNumber, path6 = process.cwd(), settingsManager) {
|
|
1268
1061
|
if (!settingsManager) {
|
|
1269
1062
|
const { SettingsManager: SM } = await Promise.resolve().then(() => (init_SettingsManager(), SettingsManager_exports));
|
|
1270
1063
|
settingsManager = new SM();
|
|
1271
1064
|
}
|
|
1272
|
-
const protectedBranches = await settingsManager.getProtectedBranches(
|
|
1273
|
-
const output = await executeGitCommand(["branch", "-a"], { cwd:
|
|
1065
|
+
const protectedBranches = await settingsManager.getProtectedBranches(path6);
|
|
1066
|
+
const output = await executeGitCommand(["branch", "-a"], { cwd: path6 });
|
|
1274
1067
|
const branches = [];
|
|
1275
1068
|
const lines = output.split("\n").filter(Boolean);
|
|
1276
1069
|
for (const line of lines) {
|
|
@@ -1327,18 +1120,18 @@ async function findAllBranchesForIssue(issueNumber, path5 = process.cwd(), setti
|
|
|
1327
1120
|
}
|
|
1328
1121
|
return branches;
|
|
1329
1122
|
}
|
|
1330
|
-
async function isEmptyRepository(
|
|
1123
|
+
async function isEmptyRepository(path6 = process.cwd()) {
|
|
1331
1124
|
try {
|
|
1332
|
-
await executeGitCommand(["rev-parse", "--verify", "HEAD"], { cwd:
|
|
1125
|
+
await executeGitCommand(["rev-parse", "--verify", "HEAD"], { cwd: path6 });
|
|
1333
1126
|
return false;
|
|
1334
1127
|
} catch {
|
|
1335
1128
|
return true;
|
|
1336
1129
|
}
|
|
1337
1130
|
}
|
|
1338
|
-
async function ensureRepositoryHasCommits(
|
|
1339
|
-
const isEmpty = await isEmptyRepository(
|
|
1131
|
+
async function ensureRepositoryHasCommits(path6 = process.cwd()) {
|
|
1132
|
+
const isEmpty = await isEmptyRepository(path6);
|
|
1340
1133
|
if (isEmpty) {
|
|
1341
|
-
await executeGitCommand(["commit", "--no-verify", "--allow-empty", "-m", "Initial commit"], { cwd:
|
|
1134
|
+
await executeGitCommand(["commit", "--no-verify", "--allow-empty", "-m", "Initial commit"], { cwd: path6 });
|
|
1342
1135
|
}
|
|
1343
1136
|
}
|
|
1344
1137
|
async function pushBranchToRemote(branchName, worktreePath, options) {
|
|
@@ -1383,6 +1176,29 @@ async function pushBranchToRemote(branchName, worktreePath, options) {
|
|
|
1383
1176
|
throw new Error(`Failed to push to remote: ${errorMessage}`);
|
|
1384
1177
|
}
|
|
1385
1178
|
}
|
|
1179
|
+
async function isFileTrackedByGit(filePath, cwd = process.cwd()) {
|
|
1180
|
+
try {
|
|
1181
|
+
const result = await executeGitCommand(
|
|
1182
|
+
["ls-files", "--error-unmatch", filePath],
|
|
1183
|
+
{ cwd }
|
|
1184
|
+
);
|
|
1185
|
+
return result.trim().length > 0;
|
|
1186
|
+
} catch (error) {
|
|
1187
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1188
|
+
if (errorMessage.includes("pathspec") && errorMessage.includes("did not match")) {
|
|
1189
|
+
return false;
|
|
1190
|
+
}
|
|
1191
|
+
throw error;
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
async function isFileGitignored(filePath, cwd = process.cwd()) {
|
|
1195
|
+
try {
|
|
1196
|
+
await executeGitCommand(["check-ignore", "-q", filePath], { cwd });
|
|
1197
|
+
return true;
|
|
1198
|
+
} catch {
|
|
1199
|
+
return false;
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1386
1202
|
|
|
1387
1203
|
// src/lib/GitWorktreeManager.ts
|
|
1388
1204
|
var GitWorktreeManager = class {
|
|
@@ -1752,6 +1568,9 @@ var GitWorktreeManager = class {
|
|
|
1752
1568
|
}
|
|
1753
1569
|
};
|
|
1754
1570
|
|
|
1571
|
+
// src/lib/GitHubService.ts
|
|
1572
|
+
import { execSync } from "child_process";
|
|
1573
|
+
|
|
1755
1574
|
// src/types/github.ts
|
|
1756
1575
|
var GitHubError = class extends Error {
|
|
1757
1576
|
constructor(code, message, details) {
|
|
@@ -1991,6 +1810,18 @@ var GitHubService = class {
|
|
|
1991
1810
|
this.supportsPullRequests = true;
|
|
1992
1811
|
this.prompter = (options == null ? void 0 : options.prompter) ?? promptConfirmation;
|
|
1993
1812
|
}
|
|
1813
|
+
/**
|
|
1814
|
+
* Check if GitHub CLI (gh) is available on the system
|
|
1815
|
+
* @returns true if gh CLI is installed and accessible, false otherwise
|
|
1816
|
+
*/
|
|
1817
|
+
static isCliAvailable() {
|
|
1818
|
+
try {
|
|
1819
|
+
execSync("gh --version", { stdio: "ignore" });
|
|
1820
|
+
return true;
|
|
1821
|
+
} catch {
|
|
1822
|
+
return false;
|
|
1823
|
+
}
|
|
1824
|
+
}
|
|
1994
1825
|
// Input detection - IssueTracker interface implementation
|
|
1995
1826
|
async detectInputType(input, repo) {
|
|
1996
1827
|
const numberMatch = input.match(/^#?(\d+)$/);
|
|
@@ -2611,6 +2442,7 @@ import fs2 from "fs-extra";
|
|
|
2611
2442
|
|
|
2612
2443
|
// src/utils/env.ts
|
|
2613
2444
|
init_logger();
|
|
2445
|
+
import path4 from "path";
|
|
2614
2446
|
import dotenvFlow from "dotenv-flow";
|
|
2615
2447
|
function parseEnvFile(content) {
|
|
2616
2448
|
const envMap = /* @__PURE__ */ new Map();
|
|
@@ -2664,6 +2496,45 @@ function isValidEnvKey(key) {
|
|
|
2664
2496
|
const validKeyRegex = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
2665
2497
|
return validKeyRegex.test(key);
|
|
2666
2498
|
}
|
|
2499
|
+
var DOTENV_FLOW_NODE_ENV = process.env.DOTENV_FLOW_NODE_ENV ?? "development";
|
|
2500
|
+
function getDotenvFlowFiles() {
|
|
2501
|
+
return [
|
|
2502
|
+
".env",
|
|
2503
|
+
".env.local",
|
|
2504
|
+
`.env.${DOTENV_FLOW_NODE_ENV}`,
|
|
2505
|
+
`.env.${DOTENV_FLOW_NODE_ENV}.local`
|
|
2506
|
+
];
|
|
2507
|
+
}
|
|
2508
|
+
async function buildEnvSourceCommands(workspacePath, fileExists) {
|
|
2509
|
+
const files = getDotenvFlowFiles();
|
|
2510
|
+
const commands = [];
|
|
2511
|
+
for (const file of files) {
|
|
2512
|
+
const fullPath = path4.join(workspacePath, file);
|
|
2513
|
+
const exists = await fileExists(fullPath);
|
|
2514
|
+
if (exists) {
|
|
2515
|
+
commands.push(`source ${file}`);
|
|
2516
|
+
}
|
|
2517
|
+
}
|
|
2518
|
+
return commands;
|
|
2519
|
+
}
|
|
2520
|
+
async function findEnvFileContainingVariable(workspacePath, variableName, fileExists, getEnvVariable) {
|
|
2521
|
+
const files = getDotenvFlowFiles().reverse();
|
|
2522
|
+
for (const file of files) {
|
|
2523
|
+
const fullPath = path4.join(workspacePath, file);
|
|
2524
|
+
if (!await fileExists(fullPath)) {
|
|
2525
|
+
continue;
|
|
2526
|
+
}
|
|
2527
|
+
const value = await getEnvVariable(fullPath, variableName);
|
|
2528
|
+
if (value !== null) {
|
|
2529
|
+
return file;
|
|
2530
|
+
}
|
|
2531
|
+
}
|
|
2532
|
+
return null;
|
|
2533
|
+
}
|
|
2534
|
+
async function hasVariableInAnyEnvFile(workspacePath, variableName, fileExists, getEnvVariable) {
|
|
2535
|
+
const file = await findEnvFileContainingVariable(workspacePath, variableName, fileExists, getEnvVariable);
|
|
2536
|
+
return file !== null;
|
|
2537
|
+
}
|
|
2667
2538
|
|
|
2668
2539
|
// src/utils/port.ts
|
|
2669
2540
|
import { createHash } from "crypto";
|
|
@@ -2882,6 +2753,7 @@ var EnvironmentManager = class {
|
|
|
2882
2753
|
|
|
2883
2754
|
// src/lib/DatabaseManager.ts
|
|
2884
2755
|
init_logger();
|
|
2756
|
+
import fs3 from "fs-extra";
|
|
2885
2757
|
var logger3 = createLogger({ prefix: "\u{1F5C2}\uFE0F" });
|
|
2886
2758
|
var DatabaseManager = class {
|
|
2887
2759
|
constructor(provider, environment, databaseUrlEnvVarName = "DATABASE_URL") {
|
|
@@ -2904,17 +2776,17 @@ var DatabaseManager = class {
|
|
|
2904
2776
|
* Check if database branching should be used
|
|
2905
2777
|
* Requires BOTH conditions:
|
|
2906
2778
|
* 1. Database provider is properly configured (checked via provider.isConfigured())
|
|
2907
|
-
* 2.
|
|
2779
|
+
* 2. Any dotenv-flow file contains the configured database URL variable
|
|
2908
2780
|
*/
|
|
2909
|
-
async shouldUseDatabaseBranching(
|
|
2781
|
+
async shouldUseDatabaseBranching(workspacePath) {
|
|
2910
2782
|
if (!this.provider.isConfigured()) {
|
|
2911
2783
|
logger3.debug("Skipping database branching: Database provider not configured");
|
|
2912
2784
|
return false;
|
|
2913
2785
|
}
|
|
2914
|
-
const hasDatabaseUrl = await this.hasDatabaseUrlInEnv(
|
|
2786
|
+
const hasDatabaseUrl = await this.hasDatabaseUrlInEnv(workspacePath);
|
|
2915
2787
|
if (!hasDatabaseUrl) {
|
|
2916
2788
|
logger3.debug(
|
|
2917
|
-
"Skipping database branching: configured database URL variable not found in
|
|
2789
|
+
"Skipping database branching: configured database URL variable not found in any env file"
|
|
2918
2790
|
);
|
|
2919
2791
|
return false;
|
|
2920
2792
|
}
|
|
@@ -2925,12 +2797,12 @@ var DatabaseManager = class {
|
|
|
2925
2797
|
* Returns connection string if branch was created, null if skipped
|
|
2926
2798
|
*
|
|
2927
2799
|
* @param branchName - Name of the branch to create
|
|
2928
|
-
* @param
|
|
2800
|
+
* @param workspacePath - Path to workspace for configuration checks (checks all dotenv-flow files)
|
|
2929
2801
|
* @param cwd - Optional working directory to run commands from
|
|
2930
2802
|
* @param fromBranch - Optional parent branch to create from (for child looms)
|
|
2931
2803
|
*/
|
|
2932
|
-
async createBranchIfConfigured(branchName,
|
|
2933
|
-
if (!await this.shouldUseDatabaseBranching(
|
|
2804
|
+
async createBranchIfConfigured(branchName, workspacePath, cwd, fromBranch) {
|
|
2805
|
+
if (!await this.shouldUseDatabaseBranching(workspacePath)) {
|
|
2934
2806
|
return null;
|
|
2935
2807
|
}
|
|
2936
2808
|
if (!await this.provider.isCliAvailable()) {
|
|
@@ -3057,19 +2929,24 @@ var DatabaseManager = class {
|
|
|
3057
2929
|
return null;
|
|
3058
2930
|
}
|
|
3059
2931
|
/**
|
|
3060
|
-
* Check if
|
|
2932
|
+
* Check if any dotenv-flow file has the configured database URL variable
|
|
3061
2933
|
* CRITICAL: If user explicitly configured a custom variable name (not default),
|
|
3062
|
-
* throw an error if it's missing from
|
|
2934
|
+
* throw an error if it's missing from all env files
|
|
3063
2935
|
*/
|
|
3064
|
-
async hasDatabaseUrlInEnv(
|
|
2936
|
+
async hasDatabaseUrlInEnv(workspacePath) {
|
|
3065
2937
|
try {
|
|
3066
|
-
const envMap = await this.environment.readEnvFile(envFilePath);
|
|
3067
2938
|
if (this.databaseUrlEnvVarName !== "DATABASE_URL") {
|
|
3068
2939
|
logger3.debug(`Looking for custom database URL variable: ${this.databaseUrlEnvVarName}`);
|
|
3069
2940
|
} else {
|
|
3070
2941
|
logger3.debug("Looking for default database URL variable: DATABASE_URL");
|
|
3071
2942
|
}
|
|
3072
|
-
|
|
2943
|
+
const hasConfiguredVar = await hasVariableInAnyEnvFile(
|
|
2944
|
+
workspacePath,
|
|
2945
|
+
this.databaseUrlEnvVarName,
|
|
2946
|
+
async (p) => fs3.pathExists(p),
|
|
2947
|
+
async (p, v) => this.environment.getEnvVariable(p, v)
|
|
2948
|
+
);
|
|
2949
|
+
if (hasConfiguredVar) {
|
|
3073
2950
|
if (this.databaseUrlEnvVarName !== "DATABASE_URL") {
|
|
3074
2951
|
logger3.debug(`\u2705 Found custom database URL variable: ${this.databaseUrlEnvVarName}`);
|
|
3075
2952
|
} else {
|
|
@@ -3078,20 +2955,25 @@ var DatabaseManager = class {
|
|
|
3078
2955
|
return true;
|
|
3079
2956
|
}
|
|
3080
2957
|
if (this.databaseUrlEnvVarName !== "DATABASE_URL") {
|
|
3081
|
-
logger3.debug(`\u274C Custom database URL variable '${this.databaseUrlEnvVarName}' not found in
|
|
2958
|
+
logger3.debug(`\u274C Custom database URL variable '${this.databaseUrlEnvVarName}' not found in any env file`);
|
|
3082
2959
|
throw new Error(
|
|
3083
|
-
`Configured database URL environment variable '${this.databaseUrlEnvVarName}' not found in
|
|
2960
|
+
`Configured database URL environment variable '${this.databaseUrlEnvVarName}' not found in any dotenv-flow file. Please add it to an .env file or update your iloom configuration.`
|
|
3084
2961
|
);
|
|
3085
2962
|
}
|
|
3086
|
-
const hasDefaultVar =
|
|
2963
|
+
const hasDefaultVar = await hasVariableInAnyEnvFile(
|
|
2964
|
+
workspacePath,
|
|
2965
|
+
"DATABASE_URL",
|
|
2966
|
+
async (p) => fs3.pathExists(p),
|
|
2967
|
+
async (p, v) => this.environment.getEnvVariable(p, v)
|
|
2968
|
+
);
|
|
3087
2969
|
if (hasDefaultVar) {
|
|
3088
2970
|
logger3.debug("\u2705 Found fallback DATABASE_URL variable");
|
|
3089
2971
|
} else {
|
|
3090
|
-
logger3.debug("\u274C No DATABASE_URL variable found in
|
|
2972
|
+
logger3.debug("\u274C No DATABASE_URL variable found in any env file");
|
|
3091
2973
|
}
|
|
3092
2974
|
return hasDefaultVar;
|
|
3093
2975
|
} catch (error) {
|
|
3094
|
-
if (error instanceof Error && error.message.includes("not found in
|
|
2976
|
+
if (error instanceof Error && error.message.includes("not found in")) {
|
|
3095
2977
|
throw error;
|
|
3096
2978
|
}
|
|
3097
2979
|
return false;
|
|
@@ -3104,6 +2986,140 @@ init_logger();
|
|
|
3104
2986
|
import { execa as execa4 } from "execa";
|
|
3105
2987
|
import { existsSync as existsSync2 } from "fs";
|
|
3106
2988
|
import { join } from "path";
|
|
2989
|
+
|
|
2990
|
+
// src/utils/terminal.ts
|
|
2991
|
+
import { execa as execa3 } from "execa";
|
|
2992
|
+
import { existsSync } from "fs";
|
|
2993
|
+
function detectPlatform() {
|
|
2994
|
+
const platform = process.platform;
|
|
2995
|
+
if (platform === "darwin") return "darwin";
|
|
2996
|
+
if (platform === "linux") return "linux";
|
|
2997
|
+
if (platform === "win32") return "win32";
|
|
2998
|
+
return "unsupported";
|
|
2999
|
+
}
|
|
3000
|
+
async function detectITerm2() {
|
|
3001
|
+
const platform = detectPlatform();
|
|
3002
|
+
if (platform !== "darwin") return false;
|
|
3003
|
+
return existsSync("/Applications/iTerm.app");
|
|
3004
|
+
}
|
|
3005
|
+
async function openTerminalWindow(options) {
|
|
3006
|
+
const platform = detectPlatform();
|
|
3007
|
+
if (platform !== "darwin") {
|
|
3008
|
+
throw new Error(
|
|
3009
|
+
`Terminal window launching not yet supported on ${platform}. Currently only macOS is supported.`
|
|
3010
|
+
);
|
|
3011
|
+
}
|
|
3012
|
+
const hasITerm2 = await detectITerm2();
|
|
3013
|
+
const applescript = hasITerm2 ? await buildITerm2SingleTabScript(options) : await buildAppleScript(options);
|
|
3014
|
+
try {
|
|
3015
|
+
await execa3("osascript", ["-e", applescript]);
|
|
3016
|
+
if (!hasITerm2) {
|
|
3017
|
+
await execa3("osascript", ["-e", 'tell application "Terminal" to activate']);
|
|
3018
|
+
}
|
|
3019
|
+
} catch (error) {
|
|
3020
|
+
throw new Error(
|
|
3021
|
+
`Failed to open terminal window: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
3022
|
+
);
|
|
3023
|
+
}
|
|
3024
|
+
}
|
|
3025
|
+
async function buildAppleScript(options) {
|
|
3026
|
+
const {
|
|
3027
|
+
workspacePath,
|
|
3028
|
+
command,
|
|
3029
|
+
backgroundColor,
|
|
3030
|
+
port,
|
|
3031
|
+
includeEnvSetup,
|
|
3032
|
+
includePortExport
|
|
3033
|
+
} = options;
|
|
3034
|
+
const commands = [];
|
|
3035
|
+
if (workspacePath) {
|
|
3036
|
+
commands.push(`cd '${escapePathForAppleScript(workspacePath)}'`);
|
|
3037
|
+
}
|
|
3038
|
+
if (includeEnvSetup && workspacePath) {
|
|
3039
|
+
const sourceCommands = await buildEnvSourceCommands(
|
|
3040
|
+
workspacePath,
|
|
3041
|
+
async (p) => existsSync(p)
|
|
3042
|
+
);
|
|
3043
|
+
commands.push(...sourceCommands);
|
|
3044
|
+
}
|
|
3045
|
+
if (includePortExport && port !== void 0) {
|
|
3046
|
+
commands.push(`export PORT=${port}`);
|
|
3047
|
+
}
|
|
3048
|
+
if (command) {
|
|
3049
|
+
commands.push(command);
|
|
3050
|
+
}
|
|
3051
|
+
const fullCommand = commands.join(" && ");
|
|
3052
|
+
const historyFreeCommand = ` ${fullCommand}`;
|
|
3053
|
+
let script = `tell application "Terminal"
|
|
3054
|
+
`;
|
|
3055
|
+
script += ` set newTab to do script "${escapeForAppleScript(historyFreeCommand)}"
|
|
3056
|
+
`;
|
|
3057
|
+
if (backgroundColor) {
|
|
3058
|
+
const { r, g, b } = backgroundColor;
|
|
3059
|
+
script += ` set background color of newTab to {${Math.round(r * 257)}, ${Math.round(g * 257)}, ${Math.round(b * 257)}}
|
|
3060
|
+
`;
|
|
3061
|
+
}
|
|
3062
|
+
script += `end tell`;
|
|
3063
|
+
return script;
|
|
3064
|
+
}
|
|
3065
|
+
function escapePathForAppleScript(path6) {
|
|
3066
|
+
return path6.replace(/'/g, "'\\''");
|
|
3067
|
+
}
|
|
3068
|
+
function escapeForAppleScript(command) {
|
|
3069
|
+
return command.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
3070
|
+
}
|
|
3071
|
+
async function buildITerm2SingleTabScript(options) {
|
|
3072
|
+
const command = await buildCommandSequence(options);
|
|
3073
|
+
let script = 'tell application id "com.googlecode.iterm2"\n';
|
|
3074
|
+
script += " create window with default profile\n";
|
|
3075
|
+
script += " set s1 to current session of current window\n\n";
|
|
3076
|
+
if (options.backgroundColor) {
|
|
3077
|
+
const { r, g, b } = options.backgroundColor;
|
|
3078
|
+
script += ` set background color of s1 to {${Math.round(r * 257)}, ${Math.round(g * 257)}, ${Math.round(b * 257)}}
|
|
3079
|
+
`;
|
|
3080
|
+
}
|
|
3081
|
+
script += ` tell s1 to write text "${escapeForAppleScript(command)}"
|
|
3082
|
+
|
|
3083
|
+
`;
|
|
3084
|
+
if (options.title) {
|
|
3085
|
+
script += ` set name of s1 to "${escapeForAppleScript(options.title)}"
|
|
3086
|
+
|
|
3087
|
+
`;
|
|
3088
|
+
}
|
|
3089
|
+
script += " activate\n";
|
|
3090
|
+
script += "end tell";
|
|
3091
|
+
return script;
|
|
3092
|
+
}
|
|
3093
|
+
async function buildCommandSequence(options) {
|
|
3094
|
+
const {
|
|
3095
|
+
workspacePath,
|
|
3096
|
+
command,
|
|
3097
|
+
port,
|
|
3098
|
+
includeEnvSetup,
|
|
3099
|
+
includePortExport
|
|
3100
|
+
} = options;
|
|
3101
|
+
const commands = [];
|
|
3102
|
+
if (workspacePath) {
|
|
3103
|
+
commands.push(`cd '${escapePathForAppleScript(workspacePath)}'`);
|
|
3104
|
+
}
|
|
3105
|
+
if (includeEnvSetup && workspacePath) {
|
|
3106
|
+
const sourceCommands = await buildEnvSourceCommands(
|
|
3107
|
+
workspacePath,
|
|
3108
|
+
async (p) => existsSync(p)
|
|
3109
|
+
);
|
|
3110
|
+
commands.push(...sourceCommands);
|
|
3111
|
+
}
|
|
3112
|
+
if (includePortExport && port !== void 0) {
|
|
3113
|
+
commands.push(`export PORT=${port}`);
|
|
3114
|
+
}
|
|
3115
|
+
if (command) {
|
|
3116
|
+
commands.push(command);
|
|
3117
|
+
}
|
|
3118
|
+
const fullCommand = commands.join(" && ");
|
|
3119
|
+
return ` ${fullCommand}`;
|
|
3120
|
+
}
|
|
3121
|
+
|
|
3122
|
+
// src/utils/claude.ts
|
|
3107
3123
|
async function detectClaudeCli() {
|
|
3108
3124
|
try {
|
|
3109
3125
|
await execa4("command", ["-v", "claude"], {
|
|
@@ -3247,7 +3263,6 @@ async function launchClaudeInNewTerminalWindow(_prompt, options) {
|
|
|
3247
3263
|
if (!workspacePath) {
|
|
3248
3264
|
throw new Error("workspacePath is required for terminal window launch");
|
|
3249
3265
|
}
|
|
3250
|
-
const { openTerminalWindow: openTerminalWindow2 } = await Promise.resolve().then(() => (init_terminal(), terminal_exports));
|
|
3251
3266
|
const executable = executablePath ?? "iloom";
|
|
3252
3267
|
let launchCommand = `${executable} spin`;
|
|
3253
3268
|
if (oneShot !== "default") {
|
|
@@ -3271,7 +3286,7 @@ async function launchClaudeInNewTerminalWindow(_prompt, options) {
|
|
|
3271
3286
|
}
|
|
3272
3287
|
}
|
|
3273
3288
|
const hasEnvFile = existsSync2(join(workspacePath, ".env"));
|
|
3274
|
-
await
|
|
3289
|
+
await openTerminalWindow({
|
|
3275
3290
|
workspacePath,
|
|
3276
3291
|
command: launchCommand,
|
|
3277
3292
|
...backgroundColor && { backgroundColor },
|
|
@@ -3285,7 +3300,7 @@ async function launchClaudeInNewTerminalWindow(_prompt, options) {
|
|
|
3285
3300
|
init_logger();
|
|
3286
3301
|
import { readFile as readFile2 } from "fs/promises";
|
|
3287
3302
|
import { accessSync } from "fs";
|
|
3288
|
-
import
|
|
3303
|
+
import path5 from "path";
|
|
3289
3304
|
import { fileURLToPath } from "url";
|
|
3290
3305
|
var PromptTemplateManager = class {
|
|
3291
3306
|
constructor(templateDir) {
|
|
@@ -3294,17 +3309,17 @@ var PromptTemplateManager = class {
|
|
|
3294
3309
|
} else {
|
|
3295
3310
|
const currentFileUrl = import.meta.url;
|
|
3296
3311
|
const currentFilePath = fileURLToPath(currentFileUrl);
|
|
3297
|
-
const distDir =
|
|
3298
|
-
let templateDir2 =
|
|
3312
|
+
const distDir = path5.dirname(currentFilePath);
|
|
3313
|
+
let templateDir2 = path5.join(distDir, "prompts");
|
|
3299
3314
|
let currentDir = distDir;
|
|
3300
|
-
while (currentDir !==
|
|
3301
|
-
const candidatePath =
|
|
3315
|
+
while (currentDir !== path5.dirname(currentDir)) {
|
|
3316
|
+
const candidatePath = path5.join(currentDir, "prompts");
|
|
3302
3317
|
try {
|
|
3303
3318
|
accessSync(candidatePath);
|
|
3304
3319
|
templateDir2 = candidatePath;
|
|
3305
3320
|
break;
|
|
3306
3321
|
} catch {
|
|
3307
|
-
currentDir =
|
|
3322
|
+
currentDir = path5.dirname(currentDir);
|
|
3308
3323
|
}
|
|
3309
3324
|
}
|
|
3310
3325
|
this.templateDir = templateDir2;
|
|
@@ -3319,7 +3334,7 @@ var PromptTemplateManager = class {
|
|
|
3319
3334
|
* Load a template file by name
|
|
3320
3335
|
*/
|
|
3321
3336
|
async loadTemplate(templateName) {
|
|
3322
|
-
const templatePath =
|
|
3337
|
+
const templatePath = path5.join(this.templateDir, `${templateName}-prompt.txt`);
|
|
3323
3338
|
logger.debug("Loading template", {
|
|
3324
3339
|
templateName,
|
|
3325
3340
|
templateDir: this.templateDir,
|
|
@@ -3401,6 +3416,9 @@ var PromptTemplateManager = class {
|
|
|
3401
3416
|
if (variables.SETTINGS_SCHEMA_CONTENT !== void 0) {
|
|
3402
3417
|
result = result.replace(/SETTINGS_SCHEMA_CONTENT/g, variables.SETTINGS_SCHEMA_CONTENT);
|
|
3403
3418
|
}
|
|
3419
|
+
if (variables.VSCODE_SETTINGS_GITIGNORED !== void 0) {
|
|
3420
|
+
result = result.replace(/VSCODE_SETTINGS_GITIGNORED/g, variables.VSCODE_SETTINGS_GITIGNORED);
|
|
3421
|
+
}
|
|
3404
3422
|
return result;
|
|
3405
3423
|
}
|
|
3406
3424
|
/**
|
|
@@ -3646,6 +3664,14 @@ var ClaudeContextManager = class {
|
|
|
3646
3664
|
}
|
|
3647
3665
|
};
|
|
3648
3666
|
|
|
3667
|
+
// src/types/index.ts
|
|
3668
|
+
var UserAbortedCommitError = class extends Error {
|
|
3669
|
+
constructor(message = "User aborted the commit") {
|
|
3670
|
+
super(message);
|
|
3671
|
+
this.name = "UserAbortedCommitError";
|
|
3672
|
+
}
|
|
3673
|
+
};
|
|
3674
|
+
|
|
3649
3675
|
// src/utils/index.ts
|
|
3650
3676
|
init_logger();
|
|
3651
3677
|
|
|
@@ -3958,6 +3984,7 @@ export {
|
|
|
3958
3984
|
IssueTrackerFactory,
|
|
3959
3985
|
LinearMarkupConverter,
|
|
3960
3986
|
TableFormatter,
|
|
3987
|
+
UserAbortedCommitError,
|
|
3961
3988
|
WorkspaceManager,
|
|
3962
3989
|
branchExists,
|
|
3963
3990
|
createLogger,
|
|
@@ -3972,8 +3999,11 @@ export {
|
|
|
3972
3999
|
getCurrentBranch,
|
|
3973
4000
|
getDefaultBranch,
|
|
3974
4001
|
getRepoRoot,
|
|
4002
|
+
getWorktreeRoot,
|
|
3975
4003
|
hasUncommittedChanges,
|
|
3976
4004
|
isEmptyRepository,
|
|
4005
|
+
isFileGitignored,
|
|
4006
|
+
isFileTrackedByGit,
|
|
3977
4007
|
isPRBranch,
|
|
3978
4008
|
isValidGitRepo,
|
|
3979
4009
|
isWorktreePath,
|