@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.
- package/LICENSE +33 -0
- package/README.md +711 -0
- package/dist/ClaudeContextManager-XOSXQ67R.js +13 -0
- package/dist/ClaudeContextManager-XOSXQ67R.js.map +1 -0
- package/dist/ClaudeService-YSZ6EXWP.js +12 -0
- package/dist/ClaudeService-YSZ6EXWP.js.map +1 -0
- package/dist/GitHubService-F7Z3XJOS.js +11 -0
- package/dist/GitHubService-F7Z3XJOS.js.map +1 -0
- package/dist/LoomLauncher-MODG2SEM.js +263 -0
- package/dist/LoomLauncher-MODG2SEM.js.map +1 -0
- package/dist/NeonProvider-PAGPUH7F.js +12 -0
- package/dist/NeonProvider-PAGPUH7F.js.map +1 -0
- package/dist/PromptTemplateManager-7FINLRDE.js +9 -0
- package/dist/PromptTemplateManager-7FINLRDE.js.map +1 -0
- package/dist/SettingsManager-VAZF26S2.js +19 -0
- package/dist/SettingsManager-VAZF26S2.js.map +1 -0
- package/dist/SettingsMigrationManager-MTQIMI54.js +146 -0
- package/dist/SettingsMigrationManager-MTQIMI54.js.map +1 -0
- package/dist/add-issue-22JBNOML.js +54 -0
- package/dist/add-issue-22JBNOML.js.map +1 -0
- package/dist/agents/iloom-issue-analyze-and-plan.md +580 -0
- package/dist/agents/iloom-issue-analyzer.md +290 -0
- package/dist/agents/iloom-issue-complexity-evaluator.md +224 -0
- package/dist/agents/iloom-issue-enhancer.md +266 -0
- package/dist/agents/iloom-issue-implementer.md +262 -0
- package/dist/agents/iloom-issue-planner.md +358 -0
- package/dist/agents/iloom-issue-reviewer.md +63 -0
- package/dist/chunk-2ZPFJQ3B.js +63 -0
- package/dist/chunk-2ZPFJQ3B.js.map +1 -0
- package/dist/chunk-37DYYFVK.js +29 -0
- package/dist/chunk-37DYYFVK.js.map +1 -0
- package/dist/chunk-BLCTGFZN.js +121 -0
- package/dist/chunk-BLCTGFZN.js.map +1 -0
- package/dist/chunk-CP2NU2JC.js +545 -0
- package/dist/chunk-CP2NU2JC.js.map +1 -0
- package/dist/chunk-CWR2SANQ.js +39 -0
- package/dist/chunk-CWR2SANQ.js.map +1 -0
- package/dist/chunk-F3XBU2R7.js +110 -0
- package/dist/chunk-F3XBU2R7.js.map +1 -0
- package/dist/chunk-GEHQXLEI.js +130 -0
- package/dist/chunk-GEHQXLEI.js.map +1 -0
- package/dist/chunk-GYCR2LOU.js +143 -0
- package/dist/chunk-GYCR2LOU.js.map +1 -0
- package/dist/chunk-GZP4UGGM.js +48 -0
- package/dist/chunk-GZP4UGGM.js.map +1 -0
- package/dist/chunk-H4E4THUZ.js +55 -0
- package/dist/chunk-H4E4THUZ.js.map +1 -0
- package/dist/chunk-HPJJSYNS.js +644 -0
- package/dist/chunk-HPJJSYNS.js.map +1 -0
- package/dist/chunk-JBH2ZYYZ.js +220 -0
- package/dist/chunk-JBH2ZYYZ.js.map +1 -0
- package/dist/chunk-JNKJ7NJV.js +78 -0
- package/dist/chunk-JNKJ7NJV.js.map +1 -0
- package/dist/chunk-JQ7VOSTC.js +437 -0
- package/dist/chunk-JQ7VOSTC.js.map +1 -0
- package/dist/chunk-KQDEK2ZW.js +199 -0
- package/dist/chunk-KQDEK2ZW.js.map +1 -0
- package/dist/chunk-O2QWO64Z.js +179 -0
- package/dist/chunk-O2QWO64Z.js.map +1 -0
- package/dist/chunk-OC4H6HJD.js +248 -0
- package/dist/chunk-OC4H6HJD.js.map +1 -0
- package/dist/chunk-PR7FKQBG.js +120 -0
- package/dist/chunk-PR7FKQBG.js.map +1 -0
- package/dist/chunk-PXZBAC2M.js +250 -0
- package/dist/chunk-PXZBAC2M.js.map +1 -0
- package/dist/chunk-QEPVTTHD.js +383 -0
- package/dist/chunk-QEPVTTHD.js.map +1 -0
- package/dist/chunk-RSRO7564.js +203 -0
- package/dist/chunk-RSRO7564.js.map +1 -0
- package/dist/chunk-SJUQ2NDR.js +146 -0
- package/dist/chunk-SJUQ2NDR.js.map +1 -0
- package/dist/chunk-SPYPLHMK.js +177 -0
- package/dist/chunk-SPYPLHMK.js.map +1 -0
- package/dist/chunk-SSCQCCJ7.js +75 -0
- package/dist/chunk-SSCQCCJ7.js.map +1 -0
- package/dist/chunk-SSR5AVRJ.js +41 -0
- package/dist/chunk-SSR5AVRJ.js.map +1 -0
- package/dist/chunk-T7QPXANZ.js +315 -0
- package/dist/chunk-T7QPXANZ.js.map +1 -0
- package/dist/chunk-U3WU5OWO.js +203 -0
- package/dist/chunk-U3WU5OWO.js.map +1 -0
- package/dist/chunk-W3DQTW63.js +124 -0
- package/dist/chunk-W3DQTW63.js.map +1 -0
- package/dist/chunk-WKEWRSDB.js +151 -0
- package/dist/chunk-WKEWRSDB.js.map +1 -0
- package/dist/chunk-Y7SAGNUT.js +66 -0
- package/dist/chunk-Y7SAGNUT.js.map +1 -0
- package/dist/chunk-YETJNRQM.js +39 -0
- package/dist/chunk-YETJNRQM.js.map +1 -0
- package/dist/chunk-YYSKGAZT.js +384 -0
- package/dist/chunk-YYSKGAZT.js.map +1 -0
- package/dist/chunk-ZZZWQGTS.js +169 -0
- package/dist/chunk-ZZZWQGTS.js.map +1 -0
- package/dist/claude-7LUVDZZ4.js +17 -0
- package/dist/claude-7LUVDZZ4.js.map +1 -0
- package/dist/cleanup-3LUWPSM7.js +412 -0
- package/dist/cleanup-3LUWPSM7.js.map +1 -0
- package/dist/cli-overrides-XFZWY7CM.js +16 -0
- package/dist/cli-overrides-XFZWY7CM.js.map +1 -0
- package/dist/cli.js +603 -0
- package/dist/cli.js.map +1 -0
- package/dist/color-ZVALX37U.js +21 -0
- package/dist/color-ZVALX37U.js.map +1 -0
- package/dist/enhance-XJIQHVPD.js +166 -0
- package/dist/enhance-XJIQHVPD.js.map +1 -0
- package/dist/env-MDFL4ZXL.js +23 -0
- package/dist/env-MDFL4ZXL.js.map +1 -0
- package/dist/feedback-23CLXKFT.js +158 -0
- package/dist/feedback-23CLXKFT.js.map +1 -0
- package/dist/finish-CY4CIH6O.js +1608 -0
- package/dist/finish-CY4CIH6O.js.map +1 -0
- package/dist/git-LVRZ57GJ.js +43 -0
- package/dist/git-LVRZ57GJ.js.map +1 -0
- package/dist/ignite-WXEF2ID5.js +359 -0
- package/dist/ignite-WXEF2ID5.js.map +1 -0
- package/dist/index.d.ts +1341 -0
- package/dist/index.js +3058 -0
- package/dist/index.js.map +1 -0
- package/dist/init-RHACUR4E.js +123 -0
- package/dist/init-RHACUR4E.js.map +1 -0
- package/dist/installation-detector-VARGFFRZ.js +11 -0
- package/dist/installation-detector-VARGFFRZ.js.map +1 -0
- package/dist/logger-MKYH4UDV.js +12 -0
- package/dist/logger-MKYH4UDV.js.map +1 -0
- package/dist/mcp/chunk-6SDFJ42P.js +62 -0
- package/dist/mcp/chunk-6SDFJ42P.js.map +1 -0
- package/dist/mcp/claude-YHHHLSXH.js +249 -0
- package/dist/mcp/claude-YHHHLSXH.js.map +1 -0
- package/dist/mcp/color-QS5BFCNN.js +168 -0
- package/dist/mcp/color-QS5BFCNN.js.map +1 -0
- package/dist/mcp/github-comment-server.js +165 -0
- package/dist/mcp/github-comment-server.js.map +1 -0
- package/dist/mcp/terminal-SDCMDVD7.js +202 -0
- package/dist/mcp/terminal-SDCMDVD7.js.map +1 -0
- package/dist/open-X6BTENPV.js +278 -0
- package/dist/open-X6BTENPV.js.map +1 -0
- package/dist/prompt-ANTQWHUF.js +13 -0
- package/dist/prompt-ANTQWHUF.js.map +1 -0
- package/dist/prompts/issue-prompt.txt +230 -0
- package/dist/prompts/pr-prompt.txt +35 -0
- package/dist/prompts/regular-prompt.txt +14 -0
- package/dist/run-2JCPQAX3.js +278 -0
- package/dist/run-2JCPQAX3.js.map +1 -0
- package/dist/schema/settings.schema.json +221 -0
- package/dist/start-LWVRBJ6S.js +982 -0
- package/dist/start-LWVRBJ6S.js.map +1 -0
- package/dist/terminal-3D6TUAKJ.js +16 -0
- package/dist/terminal-3D6TUAKJ.js.map +1 -0
- package/dist/test-git-XPF4SZXJ.js +52 -0
- package/dist/test-git-XPF4SZXJ.js.map +1 -0
- package/dist/test-prefix-XGFXFAYN.js +68 -0
- package/dist/test-prefix-XGFXFAYN.js.map +1 -0
- package/dist/test-tabs-JRKY3QMM.js +69 -0
- package/dist/test-tabs-JRKY3QMM.js.map +1 -0
- package/dist/test-webserver-M2I3EV4J.js +62 -0
- package/dist/test-webserver-M2I3EV4J.js.map +1 -0
- package/dist/update-3ZT2XX2G.js +79 -0
- package/dist/update-3ZT2XX2G.js.map +1 -0
- package/dist/update-notifier-QSSEB5KC.js +11 -0
- package/dist/update-notifier-QSSEB5KC.js.map +1 -0
- package/package.json +113 -0
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
promptConfirmation
|
|
4
|
+
} from "./chunk-JNKJ7NJV.js";
|
|
5
|
+
import {
|
|
6
|
+
createLogger
|
|
7
|
+
} from "./chunk-GEHQXLEI.js";
|
|
8
|
+
|
|
9
|
+
// src/lib/providers/NeonProvider.ts
|
|
10
|
+
import { execa } from "execa";
|
|
11
|
+
var logger = createLogger({ prefix: "\u{1F5C2}\uFE0F" });
|
|
12
|
+
function validateNeonConfig(config) {
|
|
13
|
+
if (!config.projectId) {
|
|
14
|
+
return {
|
|
15
|
+
valid: false,
|
|
16
|
+
error: "NEON_PROJECT_ID is required"
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
if (!config.parentBranch) {
|
|
20
|
+
return {
|
|
21
|
+
valid: false,
|
|
22
|
+
error: "NEON_PARENT_BRANCH is required"
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
if (!/^[a-zA-Z0-9-]+$/.test(config.projectId)) {
|
|
26
|
+
return {
|
|
27
|
+
valid: false,
|
|
28
|
+
error: "NEON_PROJECT_ID contains invalid characters"
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
return { valid: true };
|
|
32
|
+
}
|
|
33
|
+
var NeonProvider = class {
|
|
34
|
+
constructor(config) {
|
|
35
|
+
this.config = config;
|
|
36
|
+
this._isConfigured = false;
|
|
37
|
+
logger.debug("NeonProvider initialized with config:", {
|
|
38
|
+
projectId: config.projectId,
|
|
39
|
+
parentBranch: config.parentBranch,
|
|
40
|
+
hasProjectId: !!config.projectId,
|
|
41
|
+
hasParentBranch: !!config.parentBranch
|
|
42
|
+
});
|
|
43
|
+
const validation = validateNeonConfig(config);
|
|
44
|
+
if (!validation.valid) {
|
|
45
|
+
logger.debug(`NeonProvider not configured: ${validation.error}`);
|
|
46
|
+
logger.debug("Neon database branching will not be used");
|
|
47
|
+
this._isConfigured = false;
|
|
48
|
+
} else {
|
|
49
|
+
this._isConfigured = true;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Check if provider is properly configured
|
|
54
|
+
* Returns true if NEON_PROJECT_ID and NEON_PARENT_BRANCH are set
|
|
55
|
+
*/
|
|
56
|
+
isConfigured() {
|
|
57
|
+
return this._isConfigured;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Execute a Neon CLI command and return stdout
|
|
61
|
+
* Throws an error if the command fails
|
|
62
|
+
*
|
|
63
|
+
* @param args - Command arguments to pass to neon CLI
|
|
64
|
+
* @param cwd - Optional working directory to run the command from (defaults to current directory)
|
|
65
|
+
*/
|
|
66
|
+
async executeNeonCommand(args, cwd) {
|
|
67
|
+
if (!this._isConfigured) {
|
|
68
|
+
throw new Error("NeonProvider is not configured. Check NEON_PROJECT_ID and NEON_PARENT_BRANCH environment variables.");
|
|
69
|
+
}
|
|
70
|
+
const command = `neon ${args.join(" ")}`;
|
|
71
|
+
logger.debug(`Executing Neon CLI command: ${command}`);
|
|
72
|
+
logger.debug(`Project ID being used: ${this.config.projectId}`);
|
|
73
|
+
if (cwd) {
|
|
74
|
+
logger.debug(`Working directory: ${cwd}`);
|
|
75
|
+
}
|
|
76
|
+
const result = await execa("neon", args, {
|
|
77
|
+
timeout: 3e4,
|
|
78
|
+
encoding: "utf8",
|
|
79
|
+
stdio: "pipe",
|
|
80
|
+
...cwd && { cwd }
|
|
81
|
+
});
|
|
82
|
+
return result.stdout;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Check if neon CLI is available
|
|
86
|
+
* Ports: check_neon_cli() from bash/utils/neon-utils.sh:18-23
|
|
87
|
+
*/
|
|
88
|
+
async isCliAvailable() {
|
|
89
|
+
try {
|
|
90
|
+
await execa("command", ["-v", "neon"], {
|
|
91
|
+
timeout: 5e3,
|
|
92
|
+
shell: true
|
|
93
|
+
});
|
|
94
|
+
return true;
|
|
95
|
+
} catch {
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Check if user is authenticated with Neon CLI
|
|
101
|
+
* Ports: check_neon_auth() from bash/utils/neon-utils.sh:25-36
|
|
102
|
+
*
|
|
103
|
+
* @param cwd - Optional working directory to run the command from (prevents issues with deleted directories)
|
|
104
|
+
* @throws Error if authentication check fails for reasons other than not being authenticated
|
|
105
|
+
*/
|
|
106
|
+
async isAuthenticated(cwd) {
|
|
107
|
+
var _a;
|
|
108
|
+
const cliAvailable = await this.isCliAvailable();
|
|
109
|
+
if (!cliAvailable) {
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
try {
|
|
113
|
+
await execa("neon", ["me"], {
|
|
114
|
+
timeout: 1e4,
|
|
115
|
+
stdio: "pipe",
|
|
116
|
+
...cwd && { cwd }
|
|
117
|
+
});
|
|
118
|
+
return true;
|
|
119
|
+
} catch (error) {
|
|
120
|
+
const execaError = error;
|
|
121
|
+
const stderr = ((_a = execaError.stderr) == null ? void 0 : _a.trim()) ?? "";
|
|
122
|
+
const isAuthError = stderr.toLowerCase().includes("not authenticated") || stderr.toLowerCase().includes("not logged in") || stderr.toLowerCase().includes("authentication required") || stderr.toLowerCase().includes("login required");
|
|
123
|
+
if (isAuthError) {
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
throw error;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Sanitize branch name for Neon (replace slashes with underscores)
|
|
131
|
+
* Ports: sanitize_neon_branch_name() from bash/utils/neon-utils.sh:11-15
|
|
132
|
+
*/
|
|
133
|
+
sanitizeBranchName(branchName) {
|
|
134
|
+
return branchName.replace(/\//g, "_");
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Extract endpoint ID from Neon connection string
|
|
138
|
+
* Pattern matches: ep-abc-123 or ep-abc-123-pooler
|
|
139
|
+
* Returns: ep-abc-123 (without -pooler suffix)
|
|
140
|
+
* Used by: get_neon_branch_name() from bash/utils/neon-utils.sh:294
|
|
141
|
+
*/
|
|
142
|
+
extractEndpointId(connectionString) {
|
|
143
|
+
const hostMatch = connectionString.match(/@(ep-[a-z0-9-]+)\./);
|
|
144
|
+
if (!(hostMatch == null ? void 0 : hostMatch[1])) {
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
const fullEndpoint = hostMatch[1];
|
|
148
|
+
return fullEndpoint.replace(/-pooler$/, "");
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* List all branches in the Neon project
|
|
152
|
+
* Ports: list_neon_branches() from bash/utils/neon-utils.sh:63-74
|
|
153
|
+
*
|
|
154
|
+
* @param cwd - Optional working directory to run commands from
|
|
155
|
+
*/
|
|
156
|
+
async listBranches(cwd) {
|
|
157
|
+
const output = await this.executeNeonCommand([
|
|
158
|
+
"branches",
|
|
159
|
+
"list",
|
|
160
|
+
"--project-id",
|
|
161
|
+
this.config.projectId,
|
|
162
|
+
"--output",
|
|
163
|
+
"json"
|
|
164
|
+
], cwd);
|
|
165
|
+
const branches = JSON.parse(output);
|
|
166
|
+
return branches.map((branch) => branch.name);
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Check if a branch exists
|
|
170
|
+
* Ports: check_neon_branch_exists() from bash/utils/neon-utils.sh:38-61
|
|
171
|
+
*
|
|
172
|
+
* @param name - Branch name to check
|
|
173
|
+
* @param cwd - Optional working directory to run commands from
|
|
174
|
+
*/
|
|
175
|
+
async branchExists(name, cwd) {
|
|
176
|
+
const branches = await this.listBranches(cwd);
|
|
177
|
+
return branches.includes(name);
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Get connection string for a specific branch
|
|
181
|
+
* Ports: get_neon_connection_string() from bash/utils/neon-utils.sh:76-90
|
|
182
|
+
*
|
|
183
|
+
* @param branch - Branch name to get connection string for
|
|
184
|
+
* @param cwd - Optional working directory to run commands from
|
|
185
|
+
*/
|
|
186
|
+
async getConnectionString(branch, cwd) {
|
|
187
|
+
const connectionString = await this.executeNeonCommand([
|
|
188
|
+
"connection-string",
|
|
189
|
+
"--branch",
|
|
190
|
+
branch,
|
|
191
|
+
"--project-id",
|
|
192
|
+
this.config.projectId
|
|
193
|
+
], cwd);
|
|
194
|
+
return connectionString.trim();
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Find Vercel preview database branch
|
|
198
|
+
* Checks for both patterns: preview/<branch> and preview_<sanitized-branch>
|
|
199
|
+
* Ports: find_preview_database_branch() from bash/utils/neon-utils.sh:92-124
|
|
200
|
+
*
|
|
201
|
+
* @param branchName - Branch name to find preview for
|
|
202
|
+
* @param cwd - Optional working directory to run commands from
|
|
203
|
+
*/
|
|
204
|
+
async findPreviewBranch(branchName, cwd) {
|
|
205
|
+
const slashPattern = `preview/${branchName}`;
|
|
206
|
+
if (await this.branchExists(slashPattern, cwd)) {
|
|
207
|
+
logger.info(`Found Vercel preview database: ${slashPattern}`);
|
|
208
|
+
return slashPattern;
|
|
209
|
+
}
|
|
210
|
+
const sanitized = this.sanitizeBranchName(branchName);
|
|
211
|
+
const underscorePattern = `preview_${sanitized}`;
|
|
212
|
+
if (await this.branchExists(underscorePattern, cwd)) {
|
|
213
|
+
logger.info(`Found Vercel preview database: ${underscorePattern}`);
|
|
214
|
+
return underscorePattern;
|
|
215
|
+
}
|
|
216
|
+
return null;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Create a new database branch
|
|
220
|
+
* ALWAYS checks for Vercel preview database first
|
|
221
|
+
* Returns connection string for the branch
|
|
222
|
+
* Ports: create_neon_database_branch() from bash/utils/neon-utils.sh:126-187
|
|
223
|
+
*
|
|
224
|
+
* @param name - Name for the new branch
|
|
225
|
+
* @param fromBranch - Parent branch to create from (defaults to config.parentBranch)
|
|
226
|
+
* @param cwd - Optional working directory to run commands from
|
|
227
|
+
*/
|
|
228
|
+
async createBranch(name, fromBranch, cwd) {
|
|
229
|
+
const previewBranch = await this.findPreviewBranch(name, cwd);
|
|
230
|
+
if (previewBranch) {
|
|
231
|
+
const connectionString2 = await this.getConnectionString(previewBranch, cwd);
|
|
232
|
+
logger.success(`Using existing Vercel preview database: ${previewBranch}`);
|
|
233
|
+
return connectionString2;
|
|
234
|
+
}
|
|
235
|
+
const sanitizedName = this.sanitizeBranchName(name);
|
|
236
|
+
const parentBranch = fromBranch ?? this.config.parentBranch;
|
|
237
|
+
logger.info("Creating Neon database branch...");
|
|
238
|
+
logger.info(` Source branch: ${parentBranch}`);
|
|
239
|
+
logger.info(` New branch: ${sanitizedName}`);
|
|
240
|
+
await this.executeNeonCommand([
|
|
241
|
+
"branches",
|
|
242
|
+
"create",
|
|
243
|
+
"--name",
|
|
244
|
+
sanitizedName,
|
|
245
|
+
"--parent",
|
|
246
|
+
parentBranch,
|
|
247
|
+
"--project-id",
|
|
248
|
+
this.config.projectId
|
|
249
|
+
], cwd);
|
|
250
|
+
logger.success("Database branch created successfully");
|
|
251
|
+
logger.info("Getting connection string for new database branch...");
|
|
252
|
+
const connectionString = await this.getConnectionString(sanitizedName, cwd);
|
|
253
|
+
return connectionString;
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Delete a database branch
|
|
257
|
+
* Includes preview database protection with user confirmation
|
|
258
|
+
* Ports: delete_neon_database_branch() from bash/utils/neon-utils.sh:204-259
|
|
259
|
+
*
|
|
260
|
+
* @param name - Name of the branch to delete
|
|
261
|
+
* @param isPreview - Whether this is a preview database branch
|
|
262
|
+
* @param cwd - Optional working directory to run commands from (prevents issues with deleted directories)
|
|
263
|
+
*/
|
|
264
|
+
async deleteBranch(name, isPreview = false, cwd) {
|
|
265
|
+
const sanitizedName = this.sanitizeBranchName(name);
|
|
266
|
+
if (isPreview) {
|
|
267
|
+
const previewBranch = await this.findPreviewBranch(name, cwd);
|
|
268
|
+
if (previewBranch) {
|
|
269
|
+
logger.warn(`Found Vercel preview database: ${previewBranch}`);
|
|
270
|
+
logger.warn("Preview databases are managed by Vercel and will be cleaned up automatically");
|
|
271
|
+
logger.warn("Manual deletion may interfere with Vercel's preview deployments");
|
|
272
|
+
const confirmed = await promptConfirmation(
|
|
273
|
+
"Delete preview database anyway?",
|
|
274
|
+
false
|
|
275
|
+
);
|
|
276
|
+
if (confirmed) {
|
|
277
|
+
try {
|
|
278
|
+
logger.info(`Deleting Vercel preview database: ${previewBranch}`);
|
|
279
|
+
await this.executeNeonCommand([
|
|
280
|
+
"branches",
|
|
281
|
+
"delete",
|
|
282
|
+
previewBranch,
|
|
283
|
+
"--project-id",
|
|
284
|
+
this.config.projectId
|
|
285
|
+
], cwd);
|
|
286
|
+
logger.success("Preview database deleted successfully");
|
|
287
|
+
return {
|
|
288
|
+
success: true,
|
|
289
|
+
deleted: true,
|
|
290
|
+
notFound: false,
|
|
291
|
+
branchName: previewBranch
|
|
292
|
+
};
|
|
293
|
+
} catch (error) {
|
|
294
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
295
|
+
logger.error(`Failed to delete preview database: ${errorMessage}`);
|
|
296
|
+
return {
|
|
297
|
+
success: false,
|
|
298
|
+
deleted: false,
|
|
299
|
+
notFound: false,
|
|
300
|
+
error: errorMessage,
|
|
301
|
+
branchName: previewBranch
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
} else {
|
|
305
|
+
logger.info("Skipping preview database deletion");
|
|
306
|
+
return {
|
|
307
|
+
success: true,
|
|
308
|
+
deleted: false,
|
|
309
|
+
notFound: false,
|
|
310
|
+
userDeclined: true,
|
|
311
|
+
branchName: previewBranch
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
logger.info(`Checking for Neon database branch: ${sanitizedName}`);
|
|
317
|
+
try {
|
|
318
|
+
const exists = await this.branchExists(sanitizedName, cwd);
|
|
319
|
+
if (!exists) {
|
|
320
|
+
logger.info(`No database branch found for '${name}'`);
|
|
321
|
+
return {
|
|
322
|
+
success: true,
|
|
323
|
+
deleted: false,
|
|
324
|
+
notFound: true,
|
|
325
|
+
branchName: sanitizedName
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
logger.info(`Deleting Neon database branch: ${sanitizedName}`);
|
|
329
|
+
await this.executeNeonCommand([
|
|
330
|
+
"branches",
|
|
331
|
+
"delete",
|
|
332
|
+
sanitizedName,
|
|
333
|
+
"--project-id",
|
|
334
|
+
this.config.projectId
|
|
335
|
+
], cwd);
|
|
336
|
+
logger.success("Database branch deleted successfully");
|
|
337
|
+
return {
|
|
338
|
+
success: true,
|
|
339
|
+
deleted: true,
|
|
340
|
+
notFound: false,
|
|
341
|
+
branchName: sanitizedName
|
|
342
|
+
};
|
|
343
|
+
} catch (error) {
|
|
344
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
345
|
+
logger.error(`Failed to delete database branch: ${errorMessage}`);
|
|
346
|
+
return {
|
|
347
|
+
success: false,
|
|
348
|
+
deleted: false,
|
|
349
|
+
notFound: false,
|
|
350
|
+
error: errorMessage,
|
|
351
|
+
branchName: sanitizedName
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* Get branch name from endpoint ID (reverse lookup)
|
|
357
|
+
* Searches all branches to find one with matching endpoint
|
|
358
|
+
* Ports: get_neon_branch_name() from bash/utils/neon-utils.sh:262-308
|
|
359
|
+
*
|
|
360
|
+
* @param endpointId - Endpoint ID to search for
|
|
361
|
+
* @param cwd - Optional working directory to run commands from
|
|
362
|
+
*/
|
|
363
|
+
async getBranchNameFromEndpoint(endpointId, cwd) {
|
|
364
|
+
const branches = await this.listBranches(cwd);
|
|
365
|
+
for (const branch of branches) {
|
|
366
|
+
try {
|
|
367
|
+
const connectionString = await this.getConnectionString(branch, cwd);
|
|
368
|
+
const branchEndpointId = this.extractEndpointId(connectionString);
|
|
369
|
+
if (branchEndpointId === endpointId) {
|
|
370
|
+
return branch;
|
|
371
|
+
}
|
|
372
|
+
} catch {
|
|
373
|
+
continue;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
return null;
|
|
377
|
+
}
|
|
378
|
+
};
|
|
379
|
+
|
|
380
|
+
export {
|
|
381
|
+
validateNeonConfig,
|
|
382
|
+
NeonProvider
|
|
383
|
+
};
|
|
384
|
+
//# sourceMappingURL=chunk-YYSKGAZT.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/providers/NeonProvider.ts"],"sourcesContent":["import { execa, type ExecaError } from 'execa'\nimport type { DatabaseProvider } from '../../types/index.js'\nimport { createLogger } from '../../utils/logger.js'\nimport { promptConfirmation } from '../../utils/prompt.js'\n\nconst logger = createLogger({ prefix: '🗂️' })\n\ninterface NeonBranch {\n name: string\n id: string\n [key: string]: unknown\n}\n\nexport interface NeonConfig {\n projectId: string\n parentBranch: string\n}\n\n/**\n * Validate Neon configuration\n * Checks that required configuration values are present\n */\nexport function validateNeonConfig(config: {\n projectId?: string\n parentBranch?: string\n}): { valid: boolean; error?: string } {\n if (!config.projectId) {\n return {\n valid: false,\n error: 'NEON_PROJECT_ID is required',\n }\n }\n\n if (!config.parentBranch) {\n return {\n valid: false,\n error: 'NEON_PARENT_BRANCH is required',\n }\n }\n\n // Basic validation for project ID format (should start with appropriate prefix)\n if (!/^[a-zA-Z0-9-]+$/.test(config.projectId)) {\n return {\n valid: false,\n error: 'NEON_PROJECT_ID contains invalid characters',\n }\n }\n\n return { valid: true }\n}\n\n/**\n * Neon database provider implementation\n * Ports functionality from bash/utils/neon-utils.sh\n */\nexport class NeonProvider implements DatabaseProvider {\n private _isConfigured: boolean = false\n\n constructor(private config: NeonConfig) {\n logger.debug('NeonProvider initialized with config:', {\n projectId: config.projectId,\n parentBranch: config.parentBranch,\n hasProjectId: !!config.projectId,\n hasParentBranch: !!config.parentBranch,\n })\n\n // Validate config but don't throw - just mark as not configured\n // This allows the provider to be instantiated even when Neon is not being used\n const validation = validateNeonConfig(config)\n if (!validation.valid) {\n logger.debug(`NeonProvider not configured: ${validation.error}`)\n logger.debug('Neon database branching will not be used')\n this._isConfigured = false\n } else {\n this._isConfigured = true\n }\n }\n\n /**\n * Check if provider is properly configured\n * Returns true if NEON_PROJECT_ID and NEON_PARENT_BRANCH are set\n */\n isConfigured(): boolean {\n return this._isConfigured\n }\n\n /**\n * Execute a Neon CLI command and return stdout\n * Throws an error if the command fails\n *\n * @param args - Command arguments to pass to neon CLI\n * @param cwd - Optional working directory to run the command from (defaults to current directory)\n */\n private async executeNeonCommand(args: string[], cwd?: string): Promise<string> {\n // Check if provider is properly configured\n if (!this._isConfigured) {\n throw new Error('NeonProvider is not configured. Check NEON_PROJECT_ID and NEON_PARENT_BRANCH environment variables.')\n }\n\n // Log the exact command being executed for debugging\n const command = `neon ${args.join(' ')}`\n logger.debug(`Executing Neon CLI command: ${command}`)\n logger.debug(`Project ID being used: ${this.config.projectId}`)\n if (cwd) {\n logger.debug(`Working directory: ${cwd}`)\n }\n\n const result = await execa('neon', args, {\n timeout: 30000,\n encoding: 'utf8',\n stdio: 'pipe',\n ...(cwd && { cwd }),\n })\n return result.stdout\n }\n\n /**\n * Check if neon CLI is available\n * Ports: check_neon_cli() from bash/utils/neon-utils.sh:18-23\n */\n async isCliAvailable(): Promise<boolean> {\n try {\n await execa('command', ['-v', 'neon'], {\n timeout: 5000,\n shell: true,\n })\n return true\n } catch {\n return false\n }\n }\n\n /**\n * Check if user is authenticated with Neon CLI\n * Ports: check_neon_auth() from bash/utils/neon-utils.sh:25-36\n *\n * @param cwd - Optional working directory to run the command from (prevents issues with deleted directories)\n * @throws Error if authentication check fails for reasons other than not being authenticated\n */\n async isAuthenticated(cwd?: string): Promise<boolean> {\n const cliAvailable = await this.isCliAvailable()\n if (!cliAvailable) {\n return false\n }\n\n try {\n await execa('neon', ['me'], {\n timeout: 10000,\n stdio: 'pipe',\n ...(cwd && { cwd }),\n })\n return true\n } catch (error) {\n const execaError = error as ExecaError\n const stderr = execaError.stderr?.trim() ?? ''\n\n // Check for authentication failure patterns (should return false, not throw)\n const isAuthError =\n stderr.toLowerCase().includes('not authenticated') ||\n stderr.toLowerCase().includes('not logged in') ||\n stderr.toLowerCase().includes('authentication required') ||\n stderr.toLowerCase().includes('login required')\n\n if (isAuthError) {\n return false\n }\n\n // For any other error, let it bubble up\n throw error\n }\n }\n\n /**\n * Sanitize branch name for Neon (replace slashes with underscores)\n * Ports: sanitize_neon_branch_name() from bash/utils/neon-utils.sh:11-15\n */\n sanitizeBranchName(branchName: string): string {\n return branchName.replace(/\\//g, '_')\n }\n\n /**\n * Extract endpoint ID from Neon connection string\n * Pattern matches: ep-abc-123 or ep-abc-123-pooler\n * Returns: ep-abc-123 (without -pooler suffix)\n * Used by: get_neon_branch_name() from bash/utils/neon-utils.sh:294\n */\n private extractEndpointId(connectionString: string): string | null {\n // First, extract the full host part between @ and first dot\n // Examples:\n // @ep-abc123.us-east-1.neon.tech -> ep-abc123\n // @ep-abc123-pooler.us-east-1.neon.tech -> ep-abc123-pooler\n const hostMatch = connectionString.match(/@(ep-[a-z0-9-]+)\\./)\n if (!hostMatch?.[1]) {\n return null\n }\n\n const fullEndpoint = hostMatch[1]\n // Remove -pooler suffix if present\n return fullEndpoint.replace(/-pooler$/, '')\n }\n\n /**\n * List all branches in the Neon project\n * Ports: list_neon_branches() from bash/utils/neon-utils.sh:63-74\n *\n * @param cwd - Optional working directory to run commands from\n */\n async listBranches(cwd?: string): Promise<string[]> {\n const output = await this.executeNeonCommand([\n 'branches',\n 'list',\n '--project-id',\n this.config.projectId,\n '--output',\n 'json',\n ], cwd)\n\n const branches: NeonBranch[] = JSON.parse(output)\n return branches.map(branch => branch.name)\n }\n\n /**\n * Check if a branch exists\n * Ports: check_neon_branch_exists() from bash/utils/neon-utils.sh:38-61\n *\n * @param name - Branch name to check\n * @param cwd - Optional working directory to run commands from\n */\n async branchExists(name: string, cwd?: string): Promise<boolean> {\n const branches = await this.listBranches(cwd)\n return branches.includes(name)\n }\n\n /**\n * Get connection string for a specific branch\n * Ports: get_neon_connection_string() from bash/utils/neon-utils.sh:76-90\n *\n * @param branch - Branch name to get connection string for\n * @param cwd - Optional working directory to run commands from\n */\n async getConnectionString(branch: string, cwd?: string): Promise<string> {\n const connectionString = await this.executeNeonCommand([\n 'connection-string',\n '--branch',\n branch,\n '--project-id',\n this.config.projectId,\n ], cwd)\n return connectionString.trim()\n }\n\n /**\n * Find Vercel preview database branch\n * Checks for both patterns: preview/<branch> and preview_<sanitized-branch>\n * Ports: find_preview_database_branch() from bash/utils/neon-utils.sh:92-124\n *\n * @param branchName - Branch name to find preview for\n * @param cwd - Optional working directory to run commands from\n */\n async findPreviewBranch(branchName: string, cwd?: string): Promise<string | null> {\n // Check for exact preview branch match with slash pattern\n const slashPattern = `preview/${branchName}`\n if (await this.branchExists(slashPattern, cwd)) {\n logger.info(`Found Vercel preview database: ${slashPattern}`)\n return slashPattern\n }\n\n // Check for underscore pattern variation\n const sanitized = this.sanitizeBranchName(branchName)\n const underscorePattern = `preview_${sanitized}`\n if (await this.branchExists(underscorePattern, cwd)) {\n logger.info(`Found Vercel preview database: ${underscorePattern}`)\n return underscorePattern\n }\n\n return null\n }\n\n /**\n * Create a new database branch\n * ALWAYS checks for Vercel preview database first\n * Returns connection string for the branch\n * Ports: create_neon_database_branch() from bash/utils/neon-utils.sh:126-187\n *\n * @param name - Name for the new branch\n * @param fromBranch - Parent branch to create from (defaults to config.parentBranch)\n * @param cwd - Optional working directory to run commands from\n */\n async createBranch(name: string, fromBranch?: string, cwd?: string): Promise<string> {\n // Always check for existing Vercel preview database first (lines 149-158)\n const previewBranch = await this.findPreviewBranch(name, cwd)\n if (previewBranch) {\n const connectionString = await this.getConnectionString(previewBranch, cwd)\n logger.success(`Using existing Vercel preview database: ${previewBranch}`)\n return connectionString\n }\n\n // Sanitize branch name for Neon (replace slashes with underscores)\n const sanitizedName = this.sanitizeBranchName(name)\n const parentBranch = fromBranch ?? this.config.parentBranch\n\n logger.info('Creating Neon database branch...')\n logger.info(` Source branch: ${parentBranch}`)\n logger.info(` New branch: ${sanitizedName}`)\n\n // Create the database branch\n await this.executeNeonCommand([\n 'branches',\n 'create',\n '--name',\n sanitizedName,\n '--parent',\n parentBranch,\n '--project-id',\n this.config.projectId,\n ], cwd)\n\n logger.success('Database branch created successfully')\n\n // Get the connection string for the new branch\n logger.info('Getting connection string for new database branch...')\n const connectionString = await this.getConnectionString(sanitizedName, cwd)\n\n return connectionString\n }\n\n /**\n * Delete a database branch\n * Includes preview database protection with user confirmation\n * Ports: delete_neon_database_branch() from bash/utils/neon-utils.sh:204-259\n *\n * @param name - Name of the branch to delete\n * @param isPreview - Whether this is a preview database branch\n * @param cwd - Optional working directory to run commands from (prevents issues with deleted directories)\n */\n async deleteBranch(name: string, isPreview: boolean = false, cwd?: string): Promise<import('../../types/index.js').DatabaseDeletionResult> {\n // Sanitize branch name for Neon\n const sanitizedName = this.sanitizeBranchName(name)\n\n // For preview contexts, check for preview databases first\n if (isPreview) {\n const previewBranch = await this.findPreviewBranch(name, cwd)\n if (previewBranch) {\n logger.warn(`Found Vercel preview database: ${previewBranch}`)\n logger.warn('Preview databases are managed by Vercel and will be cleaned up automatically')\n logger.warn('Manual deletion may interfere with Vercel\\'s preview deployments')\n\n const confirmed = await promptConfirmation(\n 'Delete preview database anyway?',\n false\n )\n\n if (confirmed) {\n // User confirmed - delete preview branch\n try {\n logger.info(`Deleting Vercel preview database: ${previewBranch}`)\n await this.executeNeonCommand([\n 'branches',\n 'delete',\n previewBranch,\n '--project-id',\n this.config.projectId,\n ], cwd)\n logger.success('Preview database deleted successfully')\n return {\n success: true,\n deleted: true,\n notFound: false,\n branchName: previewBranch\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error)\n logger.error(`Failed to delete preview database: ${errorMessage}`)\n return {\n success: false,\n deleted: false,\n notFound: false,\n error: errorMessage,\n branchName: previewBranch\n }\n }\n } else {\n // User declined deletion\n logger.info('Skipping preview database deletion')\n return {\n success: true,\n deleted: false,\n notFound: false,\n userDeclined: true,\n branchName: previewBranch\n }\n }\n }\n // If no preview database found, fall through to check regular branch\n }\n\n // Check for regular branch\n logger.info(`Checking for Neon database branch: ${sanitizedName}`)\n\n try {\n const exists = await this.branchExists(sanitizedName, cwd)\n\n if (!exists) {\n logger.info(`No database branch found for '${name}'`)\n return {\n success: true,\n deleted: false,\n notFound: true,\n branchName: sanitizedName\n }\n }\n\n // Branch exists - delete it\n logger.info(`Deleting Neon database branch: ${sanitizedName}`)\n await this.executeNeonCommand([\n 'branches',\n 'delete',\n sanitizedName,\n '--project-id',\n this.config.projectId,\n ], cwd)\n logger.success('Database branch deleted successfully')\n\n return {\n success: true,\n deleted: true,\n notFound: false,\n branchName: sanitizedName\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error)\n logger.error(`Failed to delete database branch: ${errorMessage}`)\n return {\n success: false,\n deleted: false,\n notFound: false,\n error: errorMessage,\n branchName: sanitizedName\n }\n }\n }\n\n /**\n * Get branch name from endpoint ID (reverse lookup)\n * Searches all branches to find one with matching endpoint\n * Ports: get_neon_branch_name() from bash/utils/neon-utils.sh:262-308\n *\n * @param endpointId - Endpoint ID to search for\n * @param cwd - Optional working directory to run commands from\n */\n async getBranchNameFromEndpoint(endpointId: string, cwd?: string): Promise<string | null> {\n const branches = await this.listBranches(cwd)\n\n for (const branch of branches) {\n try {\n const connectionString = await this.getConnectionString(branch, cwd)\n const branchEndpointId = this.extractEndpointId(connectionString)\n\n if (branchEndpointId === endpointId) {\n return branch\n }\n } catch {\n // Skip branches that fail to get connection string\n continue\n }\n }\n\n return null\n }\n}\n"],"mappings":";;;;;;;;;AAAA,SAAS,aAA8B;AAKvC,IAAM,SAAS,aAAa,EAAE,QAAQ,kBAAM,CAAC;AAiBtC,SAAS,mBAAmB,QAGI;AACrC,MAAI,CAAC,OAAO,WAAW;AACrB,WAAO;AAAA,MACL,OAAO;AAAA,MACP,OAAO;AAAA,IACT;AAAA,EACF;AAEA,MAAI,CAAC,OAAO,cAAc;AACxB,WAAO;AAAA,MACL,OAAO;AAAA,MACP,OAAO;AAAA,IACT;AAAA,EACF;AAGA,MAAI,CAAC,kBAAkB,KAAK,OAAO,SAAS,GAAG;AAC7C,WAAO;AAAA,MACL,OAAO;AAAA,MACP,OAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO,EAAE,OAAO,KAAK;AACvB;AAMO,IAAM,eAAN,MAA+C;AAAA,EAGpD,YAAoB,QAAoB;AAApB;AAFpB,SAAQ,gBAAyB;AAG/B,WAAO,MAAM,yCAAyC;AAAA,MACpD,WAAW,OAAO;AAAA,MAClB,cAAc,OAAO;AAAA,MACrB,cAAc,CAAC,CAAC,OAAO;AAAA,MACvB,iBAAiB,CAAC,CAAC,OAAO;AAAA,IAC5B,CAAC;AAID,UAAM,aAAa,mBAAmB,MAAM;AAC5C,QAAI,CAAC,WAAW,OAAO;AACrB,aAAO,MAAM,gCAAgC,WAAW,KAAK,EAAE;AAC/D,aAAO,MAAM,0CAA0C;AACvD,WAAK,gBAAgB;AAAA,IACvB,OAAO;AACL,WAAK,gBAAgB;AAAA,IACvB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,eAAwB;AACtB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAc,mBAAmB,MAAgB,KAA+B;AAE9E,QAAI,CAAC,KAAK,eAAe;AACvB,YAAM,IAAI,MAAM,qGAAqG;AAAA,IACvH;AAGA,UAAM,UAAU,QAAQ,KAAK,KAAK,GAAG,CAAC;AACtC,WAAO,MAAM,+BAA+B,OAAO,EAAE;AACrD,WAAO,MAAM,0BAA0B,KAAK,OAAO,SAAS,EAAE;AAC9D,QAAI,KAAK;AACP,aAAO,MAAM,sBAAsB,GAAG,EAAE;AAAA,IAC1C;AAEA,UAAM,SAAS,MAAM,MAAM,QAAQ,MAAM;AAAA,MACvC,SAAS;AAAA,MACT,UAAU;AAAA,MACV,OAAO;AAAA,MACP,GAAI,OAAO,EAAE,IAAI;AAAA,IACnB,CAAC;AACD,WAAO,OAAO;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,iBAAmC;AACvC,QAAI;AACF,YAAM,MAAM,WAAW,CAAC,MAAM,MAAM,GAAG;AAAA,QACrC,SAAS;AAAA,QACT,OAAO;AAAA,MACT,CAAC;AACD,aAAO;AAAA,IACT,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,gBAAgB,KAAgC;AA3IxD;AA4II,UAAM,eAAe,MAAM,KAAK,eAAe;AAC/C,QAAI,CAAC,cAAc;AACjB,aAAO;AAAA,IACT;AAEA,QAAI;AACF,YAAM,MAAM,QAAQ,CAAC,IAAI,GAAG;AAAA,QAC1B,SAAS;AAAA,QACT,OAAO;AAAA,QACP,GAAI,OAAO,EAAE,IAAI;AAAA,MACnB,CAAC;AACD,aAAO;AAAA,IACT,SAAS,OAAO;AACd,YAAM,aAAa;AACnB,YAAM,WAAS,gBAAW,WAAX,mBAAmB,WAAU;AAG5C,YAAM,cACJ,OAAO,YAAY,EAAE,SAAS,mBAAmB,KACjD,OAAO,YAAY,EAAE,SAAS,eAAe,KAC7C,OAAO,YAAY,EAAE,SAAS,yBAAyB,KACvD,OAAO,YAAY,EAAE,SAAS,gBAAgB;AAEhD,UAAI,aAAa;AACf,eAAO;AAAA,MACT;AAGA,YAAM;AAAA,IACR;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,mBAAmB,YAA4B;AAC7C,WAAO,WAAW,QAAQ,OAAO,GAAG;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQQ,kBAAkB,kBAAyC;AAKjE,UAAM,YAAY,iBAAiB,MAAM,oBAAoB;AAC7D,QAAI,EAAC,uCAAY,KAAI;AACnB,aAAO;AAAA,IACT;AAEA,UAAM,eAAe,UAAU,CAAC;AAEhC,WAAO,aAAa,QAAQ,YAAY,EAAE;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,aAAa,KAAiC;AAClD,UAAM,SAAS,MAAM,KAAK,mBAAmB;AAAA,MAC3C;AAAA,MACA;AAAA,MACA;AAAA,MACA,KAAK,OAAO;AAAA,MACZ;AAAA,MACA;AAAA,IACF,GAAG,GAAG;AAEN,UAAM,WAAyB,KAAK,MAAM,MAAM;AAChD,WAAO,SAAS,IAAI,YAAU,OAAO,IAAI;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,aAAa,MAAc,KAAgC;AAC/D,UAAM,WAAW,MAAM,KAAK,aAAa,GAAG;AAC5C,WAAO,SAAS,SAAS,IAAI;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,oBAAoB,QAAgB,KAA+B;AACvE,UAAM,mBAAmB,MAAM,KAAK,mBAAmB;AAAA,MACrD;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,KAAK,OAAO;AAAA,IACd,GAAG,GAAG;AACN,WAAO,iBAAiB,KAAK;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,kBAAkB,YAAoB,KAAsC;AAEhF,UAAM,eAAe,WAAW,UAAU;AAC1C,QAAI,MAAM,KAAK,aAAa,cAAc,GAAG,GAAG;AAC9C,aAAO,KAAK,kCAAkC,YAAY,EAAE;AAC5D,aAAO;AAAA,IACT;AAGA,UAAM,YAAY,KAAK,mBAAmB,UAAU;AACpD,UAAM,oBAAoB,WAAW,SAAS;AAC9C,QAAI,MAAM,KAAK,aAAa,mBAAmB,GAAG,GAAG;AACnD,aAAO,KAAK,kCAAkC,iBAAiB,EAAE;AACjE,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAM,aAAa,MAAc,YAAqB,KAA+B;AAEnF,UAAM,gBAAgB,MAAM,KAAK,kBAAkB,MAAM,GAAG;AAC5D,QAAI,eAAe;AACjB,YAAMA,oBAAmB,MAAM,KAAK,oBAAoB,eAAe,GAAG;AAC1E,aAAO,QAAQ,2CAA2C,aAAa,EAAE;AACzE,aAAOA;AAAA,IACT;AAGA,UAAM,gBAAgB,KAAK,mBAAmB,IAAI;AAClD,UAAM,eAAe,cAAc,KAAK,OAAO;AAE/C,WAAO,KAAK,kCAAkC;AAC9C,WAAO,KAAK,oBAAoB,YAAY,EAAE;AAC9C,WAAO,KAAK,iBAAiB,aAAa,EAAE;AAG5C,UAAM,KAAK,mBAAmB;AAAA,MAC5B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,KAAK,OAAO;AAAA,IACd,GAAG,GAAG;AAEN,WAAO,QAAQ,sCAAsC;AAGrD,WAAO,KAAK,sDAAsD;AAClE,UAAM,mBAAmB,MAAM,KAAK,oBAAoB,eAAe,GAAG;AAE1E,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,aAAa,MAAc,YAAqB,OAAO,KAA8E;AAEzI,UAAM,gBAAgB,KAAK,mBAAmB,IAAI;AAGlD,QAAI,WAAW;AACb,YAAM,gBAAgB,MAAM,KAAK,kBAAkB,MAAM,GAAG;AAC5D,UAAI,eAAe;AACjB,eAAO,KAAK,kCAAkC,aAAa,EAAE;AAC7D,eAAO,KAAK,8EAA8E;AAC1F,eAAO,KAAK,iEAAkE;AAE9E,cAAM,YAAY,MAAM;AAAA,UACtB;AAAA,UACA;AAAA,QACF;AAEA,YAAI,WAAW;AAEb,cAAI;AACF,mBAAO,KAAK,qCAAqC,aAAa,EAAE;AAChE,kBAAM,KAAK,mBAAmB;AAAA,cAC5B;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA,KAAK,OAAO;AAAA,YACd,GAAG,GAAG;AACN,mBAAO,QAAQ,uCAAuC;AACtD,mBAAO;AAAA,cACL,SAAS;AAAA,cACT,SAAS;AAAA,cACT,UAAU;AAAA,cACV,YAAY;AAAA,YACd;AAAA,UACF,SAAS,OAAO;AACd,kBAAM,eAAe,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAC1E,mBAAO,MAAM,sCAAsC,YAAY,EAAE;AACjE,mBAAO;AAAA,cACL,SAAS;AAAA,cACT,SAAS;AAAA,cACT,UAAU;AAAA,cACV,OAAO;AAAA,cACP,YAAY;AAAA,YACd;AAAA,UACF;AAAA,QACF,OAAO;AAEL,iBAAO,KAAK,oCAAoC;AAChD,iBAAO;AAAA,YACL,SAAS;AAAA,YACT,SAAS;AAAA,YACT,UAAU;AAAA,YACV,cAAc;AAAA,YACd,YAAY;AAAA,UACd;AAAA,QACF;AAAA,MACF;AAAA,IAEF;AAGA,WAAO,KAAK,sCAAsC,aAAa,EAAE;AAEjE,QAAI;AACF,YAAM,SAAS,MAAM,KAAK,aAAa,eAAe,GAAG;AAEzD,UAAI,CAAC,QAAQ;AACX,eAAO,KAAK,iCAAiC,IAAI,GAAG;AACpD,eAAO;AAAA,UACL,SAAS;AAAA,UACT,SAAS;AAAA,UACT,UAAU;AAAA,UACV,YAAY;AAAA,QACd;AAAA,MACF;AAGA,aAAO,KAAK,kCAAkC,aAAa,EAAE;AAC7D,YAAM,KAAK,mBAAmB;AAAA,QAC5B;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,KAAK,OAAO;AAAA,MACd,GAAG,GAAG;AACN,aAAO,QAAQ,sCAAsC;AAErD,aAAO;AAAA,QACL,SAAS;AAAA,QACT,SAAS;AAAA,QACT,UAAU;AAAA,QACV,YAAY;AAAA,MACd;AAAA,IACF,SAAS,OAAO;AACd,YAAM,eAAe,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAC1E,aAAO,MAAM,qCAAqC,YAAY,EAAE;AAChE,aAAO;AAAA,QACL,SAAS;AAAA,QACT,SAAS;AAAA,QACT,UAAU;AAAA,QACV,OAAO;AAAA,QACP,YAAY;AAAA,MACd;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,0BAA0B,YAAoB,KAAsC;AACxF,UAAM,WAAW,MAAM,KAAK,aAAa,GAAG;AAE5C,eAAW,UAAU,UAAU;AAC7B,UAAI;AACF,cAAM,mBAAmB,MAAM,KAAK,oBAAoB,QAAQ,GAAG;AACnE,cAAM,mBAAmB,KAAK,kBAAkB,gBAAgB;AAEhE,YAAI,qBAAqB,YAAY;AACnC,iBAAO;AAAA,QACT;AAAA,MACF,QAAQ;AAEN;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AACF;","names":["connectionString"]}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
logger_default
|
|
4
|
+
} from "./chunk-GEHQXLEI.js";
|
|
5
|
+
|
|
6
|
+
// src/utils/color.ts
|
|
7
|
+
import { createHash } from "crypto";
|
|
8
|
+
function getColorPalette() {
|
|
9
|
+
return [
|
|
10
|
+
// First 10 colors preserved for backward compatibility
|
|
11
|
+
{ r: 220, g: 235, b: 248 },
|
|
12
|
+
// 0: Soft blue
|
|
13
|
+
{ r: 248, g: 220, b: 235 },
|
|
14
|
+
// 1: Soft pink
|
|
15
|
+
{ r: 220, g: 248, b: 235 },
|
|
16
|
+
// 2: Soft green
|
|
17
|
+
{ r: 248, g: 240, b: 220 },
|
|
18
|
+
// 3: Soft cream
|
|
19
|
+
{ r: 240, g: 220, b: 248 },
|
|
20
|
+
// 4: Soft lavender
|
|
21
|
+
{ r: 220, g: 240, b: 248 },
|
|
22
|
+
// 5: Soft cyan
|
|
23
|
+
{ r: 235, g: 235, b: 235 },
|
|
24
|
+
// 6: Soft grey
|
|
25
|
+
{ r: 228, g: 238, b: 248 },
|
|
26
|
+
// 7: Soft ice blue
|
|
27
|
+
{ r: 248, g: 228, b: 238 },
|
|
28
|
+
// 8: Soft rose
|
|
29
|
+
{ r: 228, g: 248, b: 238 },
|
|
30
|
+
// 9: Soft mint
|
|
31
|
+
// 30 new colors (indices 10-39)
|
|
32
|
+
{ r: 235, g: 245, b: 250 },
|
|
33
|
+
// 10: Pale sky blue
|
|
34
|
+
{ r: 250, g: 235, b: 245 },
|
|
35
|
+
// 11: Pale orchid
|
|
36
|
+
{ r: 235, g: 250, b: 245 },
|
|
37
|
+
// 12: Pale seafoam
|
|
38
|
+
{ r: 250, g: 245, b: 235 },
|
|
39
|
+
// 13: Pale peach
|
|
40
|
+
{ r: 245, g: 235, b: 250 },
|
|
41
|
+
// 14: Pale periwinkle
|
|
42
|
+
{ r: 235, g: 245, b: 235 },
|
|
43
|
+
// 15: Pale sage
|
|
44
|
+
{ r: 245, g: 250, b: 235 },
|
|
45
|
+
// 16: Pale lemon
|
|
46
|
+
{ r: 245, g: 235, b: 235 },
|
|
47
|
+
// 17: Pale blush
|
|
48
|
+
{ r: 235, g: 235, b: 250 },
|
|
49
|
+
// 18: Pale lavender blue
|
|
50
|
+
{ r: 250, g: 235, b: 235 },
|
|
51
|
+
// 19: Pale coral
|
|
52
|
+
{ r: 235, g: 250, b: 250 },
|
|
53
|
+
// 20: Pale aqua
|
|
54
|
+
{ r: 240, g: 248, b: 255 },
|
|
55
|
+
// 21: Alice blue
|
|
56
|
+
{ r: 255, g: 240, b: 248 },
|
|
57
|
+
// 22: Lavender blush
|
|
58
|
+
{ r: 240, g: 255, b: 248 },
|
|
59
|
+
// 23: Honeydew tint
|
|
60
|
+
{ r: 255, g: 248, b: 240 },
|
|
61
|
+
// 24: Antique white
|
|
62
|
+
{ r: 248, g: 240, b: 255 },
|
|
63
|
+
// 25: Magnolia
|
|
64
|
+
{ r: 240, g: 248, b: 240 },
|
|
65
|
+
// 26: Mint cream tint
|
|
66
|
+
{ r: 248, g: 255, b: 240 },
|
|
67
|
+
// 27: Ivory tint
|
|
68
|
+
{ r: 248, g: 240, b: 240 },
|
|
69
|
+
// 28: Misty rose tint
|
|
70
|
+
{ r: 240, g: 240, b: 255 },
|
|
71
|
+
// 29: Ghost white tint
|
|
72
|
+
{ r: 255, g: 245, b: 238 },
|
|
73
|
+
// 30: Seashell
|
|
74
|
+
{ r: 245, g: 255, b: 250 },
|
|
75
|
+
// 31: Azure mist
|
|
76
|
+
{ r: 250, g: 245, b: 255 },
|
|
77
|
+
// 32: Lilac mist
|
|
78
|
+
{ r: 255, g: 250, b: 245 },
|
|
79
|
+
// 33: Snow peach
|
|
80
|
+
{ r: 238, g: 245, b: 255 },
|
|
81
|
+
// 34: Powder blue
|
|
82
|
+
{ r: 255, g: 238, b: 245 },
|
|
83
|
+
// 35: Pink lace
|
|
84
|
+
{ r: 245, g: 255, b: 238 },
|
|
85
|
+
// 36: Pale lime
|
|
86
|
+
{ r: 238, g: 255, b: 245 },
|
|
87
|
+
// 37: Pale turquoise
|
|
88
|
+
{ r: 245, g: 238, b: 255 },
|
|
89
|
+
// 38: Pale violet
|
|
90
|
+
{ r: 255, g: 245, b: 255 }
|
|
91
|
+
// 39: Pale magenta
|
|
92
|
+
];
|
|
93
|
+
}
|
|
94
|
+
function rgbToHex(r, g, b) {
|
|
95
|
+
if (r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255) {
|
|
96
|
+
throw new Error("RGB values must be between 0 and 255");
|
|
97
|
+
}
|
|
98
|
+
const rHex = r.toString(16).padStart(2, "0");
|
|
99
|
+
const gHex = g.toString(16).padStart(2, "0");
|
|
100
|
+
const bHex = b.toString(16).padStart(2, "0");
|
|
101
|
+
return `#${rHex}${gHex}${bHex}`;
|
|
102
|
+
}
|
|
103
|
+
function hexToRgb(hex) {
|
|
104
|
+
const cleanHex = hex.startsWith("#") ? hex.slice(1) : hex;
|
|
105
|
+
if (cleanHex.length !== 6 || !/^[0-9a-fA-F]{6}$/.test(cleanHex)) {
|
|
106
|
+
throw new Error("Invalid hex color format. Expected format: #RRGGBB or RRGGBB");
|
|
107
|
+
}
|
|
108
|
+
const r = parseInt(cleanHex.slice(0, 2), 16);
|
|
109
|
+
const g = parseInt(cleanHex.slice(2, 4), 16);
|
|
110
|
+
const b = parseInt(cleanHex.slice(4, 6), 16);
|
|
111
|
+
return { r, g, b };
|
|
112
|
+
}
|
|
113
|
+
function generateColorFromBranchName(branchName) {
|
|
114
|
+
const hash = createHash("sha256").update(branchName).digest("hex");
|
|
115
|
+
const hashPrefix = hash.slice(0, 8);
|
|
116
|
+
const palette = getColorPalette();
|
|
117
|
+
const hashAsInt = parseInt(hashPrefix, 16);
|
|
118
|
+
const index = hashAsInt % palette.length;
|
|
119
|
+
logger_default.debug(`[generateColorFromBranchName] Branch name: ${branchName}, Hash: ${hash}, Hash prefix: ${hashPrefix}, Hash as int: ${hashAsInt}, Index: ${index}`);
|
|
120
|
+
const rgb = palette[index];
|
|
121
|
+
if (!rgb) {
|
|
122
|
+
throw new Error(`Invalid color index: ${index}`);
|
|
123
|
+
}
|
|
124
|
+
const hex = rgbToHex(rgb.r, rgb.g, rgb.b);
|
|
125
|
+
return {
|
|
126
|
+
rgb,
|
|
127
|
+
hex,
|
|
128
|
+
index
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
function lightenColor(rgb, amount) {
|
|
132
|
+
const clamp = (value) => Math.min(255, Math.max(0, Math.round(value)));
|
|
133
|
+
return {
|
|
134
|
+
r: clamp(rgb.r + (255 - rgb.r) * amount),
|
|
135
|
+
g: clamp(rgb.g + (255 - rgb.g) * amount),
|
|
136
|
+
b: clamp(rgb.b + (255 - rgb.b) * amount)
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
function saturateColor(rgb, amount) {
|
|
140
|
+
const clamp = (value) => Math.min(255, Math.max(0, Math.round(value)));
|
|
141
|
+
const avg = (rgb.r + rgb.g + rgb.b) / 3;
|
|
142
|
+
return {
|
|
143
|
+
r: clamp(rgb.r + (rgb.r - avg) * amount),
|
|
144
|
+
g: clamp(rgb.g + (rgb.g - avg) * amount),
|
|
145
|
+
b: clamp(rgb.b + (rgb.b - avg) * amount)
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
function calculateForegroundColor(rgb) {
|
|
149
|
+
const toLinear = (channel) => {
|
|
150
|
+
const c = channel / 255;
|
|
151
|
+
return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
|
|
152
|
+
};
|
|
153
|
+
const r = toLinear(rgb.r);
|
|
154
|
+
const g = toLinear(rgb.g);
|
|
155
|
+
const b = toLinear(rgb.b);
|
|
156
|
+
const luminance = 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
|
157
|
+
return luminance > 0.5 ? "#000000" : "#ffffff";
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export {
|
|
161
|
+
getColorPalette,
|
|
162
|
+
rgbToHex,
|
|
163
|
+
hexToRgb,
|
|
164
|
+
generateColorFromBranchName,
|
|
165
|
+
lightenColor,
|
|
166
|
+
saturateColor,
|
|
167
|
+
calculateForegroundColor
|
|
168
|
+
};
|
|
169
|
+
//# sourceMappingURL=chunk-ZZZWQGTS.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/color.ts"],"sourcesContent":["import { createHash } from 'crypto'\nimport logger from './logger'\n\n/**\n * RGB color representation\n */\nexport interface RgbColor {\n\tr: number\n\tg: number\n\tb: number\n}\n\n/**\n * Complete color data with RGB, hex, and palette index\n */\nexport interface ColorData {\n\trgb: RgbColor\n\thex: string\n\tindex: number\n}\n\n/**\n * Get the predefined color palette (40 subtle, professional colors)\n * Matches the terminal color palette from bash/new-branch-workflow.sh\n *\n * @returns Array of 40 RGB colors\n */\nexport function getColorPalette(): RgbColor[] {\n\treturn [\n\t\t// First 10 colors preserved for backward compatibility\n\t\t{ r: 220, g: 235, b: 248 }, // 0: Soft blue\n\t\t{ r: 248, g: 220, b: 235 }, // 1: Soft pink\n\t\t{ r: 220, g: 248, b: 235 }, // 2: Soft green\n\t\t{ r: 248, g: 240, b: 220 }, // 3: Soft cream\n\t\t{ r: 240, g: 220, b: 248 }, // 4: Soft lavender\n\t\t{ r: 220, g: 240, b: 248 }, // 5: Soft cyan\n\t\t{ r: 235, g: 235, b: 235 }, // 6: Soft grey\n\t\t{ r: 228, g: 238, b: 248 }, // 7: Soft ice blue\n\t\t{ r: 248, g: 228, b: 238 }, // 8: Soft rose\n\t\t{ r: 228, g: 248, b: 238 }, // 9: Soft mint\n\t\t// 30 new colors (indices 10-39)\n\t\t{ r: 235, g: 245, b: 250 }, // 10: Pale sky blue\n\t\t{ r: 250, g: 235, b: 245 }, // 11: Pale orchid\n\t\t{ r: 235, g: 250, b: 245 }, // 12: Pale seafoam\n\t\t{ r: 250, g: 245, b: 235 }, // 13: Pale peach\n\t\t{ r: 245, g: 235, b: 250 }, // 14: Pale periwinkle\n\t\t{ r: 235, g: 245, b: 235 }, // 15: Pale sage\n\t\t{ r: 245, g: 250, b: 235 }, // 16: Pale lemon\n\t\t{ r: 245, g: 235, b: 235 }, // 17: Pale blush\n\t\t{ r: 235, g: 235, b: 250 }, // 18: Pale lavender blue\n\t\t{ r: 250, g: 235, b: 235 }, // 19: Pale coral\n\t\t{ r: 235, g: 250, b: 250 }, // 20: Pale aqua\n\t\t{ r: 240, g: 248, b: 255 }, // 21: Alice blue\n\t\t{ r: 255, g: 240, b: 248 }, // 22: Lavender blush\n\t\t{ r: 240, g: 255, b: 248 }, // 23: Honeydew tint\n\t\t{ r: 255, g: 248, b: 240 }, // 24: Antique white\n\t\t{ r: 248, g: 240, b: 255 }, // 25: Magnolia\n\t\t{ r: 240, g: 248, b: 240 }, // 26: Mint cream tint\n\t\t{ r: 248, g: 255, b: 240 }, // 27: Ivory tint\n\t\t{ r: 248, g: 240, b: 240 }, // 28: Misty rose tint\n\t\t{ r: 240, g: 240, b: 255 }, // 29: Ghost white tint\n\t\t{ r: 255, g: 245, b: 238 }, // 30: Seashell\n\t\t{ r: 245, g: 255, b: 250 }, // 31: Azure mist\n\t\t{ r: 250, g: 245, b: 255 }, // 32: Lilac mist\n\t\t{ r: 255, g: 250, b: 245 }, // 33: Snow peach\n\t\t{ r: 238, g: 245, b: 255 }, // 34: Powder blue\n\t\t{ r: 255, g: 238, b: 245 }, // 35: Pink lace\n\t\t{ r: 245, g: 255, b: 238 }, // 36: Pale lime\n\t\t{ r: 238, g: 255, b: 245 }, // 37: Pale turquoise\n\t\t{ r: 245, g: 238, b: 255 }, // 38: Pale violet\n\t\t{ r: 255, g: 245, b: 255 }, // 39: Pale magenta\n\t]\n}\n\n/**\n * Convert RGB values to hex color format\n *\n * @param r - Red value (0-255)\n * @param g - Green value (0-255)\n * @param b - Blue value (0-255)\n * @returns Hex color string (e.g., \"#dcebf8\")\n * @throws Error if RGB values are out of range\n */\nexport function rgbToHex(r: number, g: number, b: number): string {\n\t// Validate RGB values\n\tif (r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255) {\n\t\tthrow new Error('RGB values must be between 0 and 255')\n\t}\n\n\t// Convert to hex and pad with zeros\n\tconst rHex = r.toString(16).padStart(2, '0')\n\tconst gHex = g.toString(16).padStart(2, '0')\n\tconst bHex = b.toString(16).padStart(2, '0')\n\n\treturn `#${rHex}${gHex}${bHex}`\n}\n\n/**\n * Convert hex color format to RGB values\n *\n * @param hex - Hex color string (with or without # prefix)\n * @returns RGB color object\n * @throws Error if hex format is invalid\n */\nexport function hexToRgb(hex: string): RgbColor {\n\t// Remove # prefix if present\n\tconst cleanHex = hex.startsWith('#') ? hex.slice(1) : hex\n\n\t// Validate format (must be exactly 6 hex characters)\n\tif (cleanHex.length !== 6 || !/^[0-9a-fA-F]{6}$/.test(cleanHex)) {\n\t\tthrow new Error('Invalid hex color format. Expected format: #RRGGBB or RRGGBB')\n\t}\n\n\t// Parse hex values\n\tconst r = parseInt(cleanHex.slice(0, 2), 16)\n\tconst g = parseInt(cleanHex.slice(2, 4), 16)\n\tconst b = parseInt(cleanHex.slice(4, 6), 16)\n\n\treturn { r, g, b }\n}\n\n/**\n * Generate deterministic color from branch name using SHA256 hash\n * Matches the bash implementation in bash/new-branch-workflow.sh\n *\n * @param branchName - Branch name to generate color from\n * @returns ColorData with RGB, hex, and palette index\n */\nexport function generateColorFromBranchName(branchName: string): ColorData {\n\t// Generate SHA256 hash of branch name\n\tconst hash = createHash('sha256').update(branchName).digest('hex')\n\n\t// Take first 8 hex characters and convert to index (0-39)\n\t// Matches bash: local index=$(( 0x$hash % ${#colors[@]} ))\n\tconst hashPrefix = hash.slice(0, 8)\n\tconst palette = getColorPalette()\n\tconst hashAsInt = parseInt(hashPrefix, 16)\n\tconst index = hashAsInt % palette.length\n\tlogger.debug(`[generateColorFromBranchName] Branch name: ${branchName}, Hash: ${hash}, Hash prefix: ${hashPrefix}, Hash as int: ${hashAsInt}, Index: ${index}`)\n\n\t// Get color from palette\n\tconst rgb = palette[index]\n\n\t// This should never happen as index is always in range [0, palette.length)\n\tif (!rgb) {\n\t\tthrow new Error(`Invalid color index: ${index}`)\n\t}\n\n\t// Convert to hex format\n\tconst hex = rgbToHex(rgb.r, rgb.g, rgb.b)\n\n\treturn {\n\t\trgb,\n\t\thex,\n\t\tindex,\n\t}\n}\n\n/**\n * Lighten a color by a given amount\n * Useful for creating slightly lighter variants for hover states\n *\n * @param rgb - RGB color to lighten\n * @param amount - Amount to lighten (0-1, where 0.1 = 10% lighter)\n * @returns Lightened RGB color\n */\nexport function lightenColor(rgb: RgbColor, amount: number): RgbColor {\n\tconst clamp = (value: number): number => Math.min(255, Math.max(0, Math.round(value)))\n\n\treturn {\n\t\tr: clamp(rgb.r + (255 - rgb.r) * amount),\n\t\tg: clamp(rgb.g + (255 - rgb.g) * amount),\n\t\tb: clamp(rgb.b + (255 - rgb.b) * amount),\n\t}\n}\n\n/**\n * Saturate a color by pushing it away from grey towards its dominant hue\n * Makes subtle colors more vivid while maintaining their hue\n *\n * @param rgb - RGB color to saturate\n * @param amount - Amount to saturate (0-1, where 0.4 = 40% more saturated)\n * @returns Saturated RGB color\n */\nexport function saturateColor(rgb: RgbColor, amount: number): RgbColor {\n\tconst clamp = (value: number): number => Math.min(255, Math.max(0, Math.round(value)))\n\n\t// Calculate average (grey point)\n\tconst avg = (rgb.r + rgb.g + rgb.b) / 3\n\n\t// Push each channel away from grey\n\treturn {\n\t\tr: clamp(rgb.r + (rgb.r - avg) * amount),\n\t\tg: clamp(rgb.g + (rgb.g - avg) * amount),\n\t\tb: clamp(rgb.b + (rgb.b - avg) * amount),\n\t}\n}\n\n/**\n * Calculate appropriate foreground color (black or white) for a given background\n * Uses relative luminance formula from WCAG 2.0\n *\n * @param rgb - Background RGB color\n * @returns '#000000' for light backgrounds, '#ffffff' for dark backgrounds\n */\nexport function calculateForegroundColor(rgb: RgbColor): string {\n\t// Convert RGB to relative luminance (WCAG 2.0 formula)\n\tconst toLinear = (channel: number): number => {\n\t\tconst c = channel / 255\n\t\treturn c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4)\n\t}\n\n\tconst r = toLinear(rgb.r)\n\tconst g = toLinear(rgb.g)\n\tconst b = toLinear(rgb.b)\n\n\tconst luminance = 0.2126 * r + 0.7152 * g + 0.0722 * b\n\n\t// Use black text for light backgrounds (luminance > 0.5)\n\t// Use white text for dark backgrounds\n\treturn luminance > 0.5 ? '#000000' : '#ffffff'\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
detectClaudeCli,
|
|
4
|
+
generateBranchName,
|
|
5
|
+
getClaudeVersion,
|
|
6
|
+
launchClaude,
|
|
7
|
+
launchClaudeInNewTerminalWindow
|
|
8
|
+
} from "./chunk-PXZBAC2M.js";
|
|
9
|
+
import "./chunk-GEHQXLEI.js";
|
|
10
|
+
export {
|
|
11
|
+
detectClaudeCli,
|
|
12
|
+
generateBranchName,
|
|
13
|
+
getClaudeVersion,
|
|
14
|
+
launchClaude,
|
|
15
|
+
launchClaudeInNewTerminalWindow
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=claude-7LUVDZZ4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|