@specific.dev/cli 0.1.42 → 0.1.44
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/dist/admin/404/index.html +1 -1
- package/dist/admin/404.html +1 -1
- package/dist/admin/__next.__PAGE__.txt +4 -4
- package/dist/admin/__next._full.txt +11 -11
- package/dist/admin/__next._head.txt +4 -4
- package/dist/admin/__next._index.txt +4 -4
- package/dist/admin/__next._tree.txt +2 -2
- package/dist/admin/_next/static/chunks/{b71388016463cab2.js → 522cc1cbb935d4c6.js} +1 -1
- package/dist/admin/_next/static/chunks/62190944d690fc4e.js +4 -0
- package/dist/admin/_next/static/chunks/938d410f2031f3b1.css +3 -0
- package/dist/admin/_next/static/chunks/979e895ce202c4a3.js +1 -0
- package/dist/admin/_next/static/chunks/99f58b3b47071cc8.js +5 -0
- package/dist/admin/_next/static/chunks/9f53491ced2668ee.js +1 -0
- package/dist/admin/_next/static/chunks/a308451471d4cb39.js +1 -0
- package/dist/admin/_next/static/chunks/a4ff1b18f2f45e23.js +2 -0
- package/dist/admin/_next/static/chunks/a5c8191596f07db5.js +2 -0
- package/dist/admin/_next/static/chunks/a6dad97d9634a72d.js.map +1 -1
- package/dist/admin/_next/static/chunks/{ff1a16fafef87110.js → b2b4aada246f4749.js} +1 -1
- package/dist/admin/_next/static/chunks/bf65cbe8dc67cf90.js +5 -0
- package/dist/admin/_next/static/chunks/{turbopack-22b7312525502d51.js → turbopack-9e3df33047c5ecb2.js} +2 -2
- package/dist/admin/_not-found/__next._full.txt +9 -9
- package/dist/admin/_not-found/__next._head.txt +4 -4
- package/dist/admin/_not-found/__next._index.txt +4 -4
- package/dist/admin/_not-found/__next._not-found.__PAGE__.txt +2 -2
- package/dist/admin/_not-found/__next._not-found.txt +3 -3
- package/dist/admin/_not-found/__next._tree.txt +2 -2
- package/dist/admin/_not-found/index.html +1 -1
- package/dist/admin/_not-found/index.txt +9 -9
- package/dist/admin/databases/__next._full.txt +11 -11
- package/dist/admin/databases/__next._head.txt +4 -4
- package/dist/admin/databases/__next._index.txt +4 -4
- package/dist/admin/databases/__next._tree.txt +2 -2
- package/dist/admin/databases/__next.databases.__PAGE__.txt +4 -4
- package/dist/admin/databases/__next.databases.txt +3 -3
- package/dist/admin/databases/index.html +1 -1
- package/dist/admin/databases/index.txt +11 -11
- package/dist/admin/index.html +1 -1
- package/dist/admin/index.txt +11 -11
- package/dist/cli.js +1522 -1360
- package/dist/docs/index.md +1 -0
- package/dist/docs/integrations/nextjs.md +18 -0
- package/dist/docs/integrations/temporal.md +89 -0
- package/dist/docs/migrations/supabase.md +18 -0
- package/dist/docs/secrets-config.md +52 -8
- package/dist/docs/services.md +4 -2
- package/package.json +12 -4
- package/dist/admin/_next/static/chunks/1a608619ba3183f8.js +0 -5
- package/dist/admin/_next/static/chunks/237926899f121e8a.js +0 -2
- package/dist/admin/_next/static/chunks/2ca8ab35893ba132.css +0 -3
- package/dist/admin/_next/static/chunks/42730c0491633b9d.js +0 -5
- package/dist/admin/_next/static/chunks/465f799faf41e6df.js +0 -1
- package/dist/admin/_next/static/chunks/806bdb8e4a6a9b95.js +0 -4
- package/dist/admin/_next/static/chunks/9054c84ba21a4c14.js +0 -2
- package/dist/admin/_next/static/chunks/d2be314c3ece3fbe.js +0 -1
- package/dist/admin/_next/static/chunks/dde2c8e6322d1671.js +0 -1
- /package/dist/admin/_next/static/{w-7TGbUFVs5LhUxmBNTTr → pbjYnqTudS-YVLwgwOgBz}/_buildManifest.js +0 -0
- /package/dist/admin/_next/static/{w-7TGbUFVs5LhUxmBNTTr → pbjYnqTudS-YVLwgwOgBz}/_clientMiddlewareManifest.json +0 -0
- /package/dist/admin/_next/static/{w-7TGbUFVs5LhUxmBNTTr → pbjYnqTudS-YVLwgwOgBz}/_ssgManifest.js +0 -0
package/dist/cli.js
CHANGED
|
@@ -11,9 +11,16 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
11
11
|
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
12
12
|
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
13
13
|
});
|
|
14
|
+
var __esm = (fn, res) => function __init() {
|
|
15
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
16
|
+
};
|
|
14
17
|
var __commonJS = (cb, mod) => function __require2() {
|
|
15
18
|
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
16
19
|
};
|
|
20
|
+
var __export = (target, all) => {
|
|
21
|
+
for (var name in all)
|
|
22
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
23
|
+
};
|
|
17
24
|
var __copyProps = (to, from, except, desc) => {
|
|
18
25
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
19
26
|
for (let key of __getOwnPropNames(from))
|
|
@@ -31,9 +38,715 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
31
38
|
mod
|
|
32
39
|
));
|
|
33
40
|
|
|
34
|
-
//
|
|
41
|
+
// node_modules/.pnpm/is-docker@3.0.0/node_modules/is-docker/index.js
|
|
42
|
+
import fs4 from "node:fs";
|
|
43
|
+
function hasDockerEnv() {
|
|
44
|
+
try {
|
|
45
|
+
fs4.statSync("/.dockerenv");
|
|
46
|
+
return true;
|
|
47
|
+
} catch {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function hasDockerCGroup() {
|
|
52
|
+
try {
|
|
53
|
+
return fs4.readFileSync("/proc/self/cgroup", "utf8").includes("docker");
|
|
54
|
+
} catch {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function isDocker() {
|
|
59
|
+
if (isDockerCached === void 0) {
|
|
60
|
+
isDockerCached = hasDockerEnv() || hasDockerCGroup();
|
|
61
|
+
}
|
|
62
|
+
return isDockerCached;
|
|
63
|
+
}
|
|
64
|
+
var isDockerCached;
|
|
65
|
+
var init_is_docker = __esm({
|
|
66
|
+
"node_modules/.pnpm/is-docker@3.0.0/node_modules/is-docker/index.js"() {
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// node_modules/.pnpm/is-inside-container@1.0.0/node_modules/is-inside-container/index.js
|
|
71
|
+
import fs5 from "node:fs";
|
|
72
|
+
function isInsideContainer() {
|
|
73
|
+
if (cachedResult === void 0) {
|
|
74
|
+
cachedResult = hasContainerEnv() || isDocker();
|
|
75
|
+
}
|
|
76
|
+
return cachedResult;
|
|
77
|
+
}
|
|
78
|
+
var cachedResult, hasContainerEnv;
|
|
79
|
+
var init_is_inside_container = __esm({
|
|
80
|
+
"node_modules/.pnpm/is-inside-container@1.0.0/node_modules/is-inside-container/index.js"() {
|
|
81
|
+
init_is_docker();
|
|
82
|
+
hasContainerEnv = () => {
|
|
83
|
+
try {
|
|
84
|
+
fs5.statSync("/run/.containerenv");
|
|
85
|
+
return true;
|
|
86
|
+
} catch {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
// node_modules/.pnpm/is-wsl@3.1.0/node_modules/is-wsl/index.js
|
|
94
|
+
import process2 from "node:process";
|
|
95
|
+
import os3 from "node:os";
|
|
96
|
+
import fs6 from "node:fs";
|
|
97
|
+
var isWsl, is_wsl_default;
|
|
98
|
+
var init_is_wsl = __esm({
|
|
99
|
+
"node_modules/.pnpm/is-wsl@3.1.0/node_modules/is-wsl/index.js"() {
|
|
100
|
+
init_is_inside_container();
|
|
101
|
+
isWsl = () => {
|
|
102
|
+
if (process2.platform !== "linux") {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
if (os3.release().toLowerCase().includes("microsoft")) {
|
|
106
|
+
if (isInsideContainer()) {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
try {
|
|
112
|
+
return fs6.readFileSync("/proc/version", "utf8").toLowerCase().includes("microsoft") ? !isInsideContainer() : false;
|
|
113
|
+
} catch {
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
is_wsl_default = process2.env.__IS_WSL_TEST__ ? isWsl : isWsl();
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
// node_modules/.pnpm/powershell-utils@0.1.0/node_modules/powershell-utils/index.js
|
|
122
|
+
import process3 from "node:process";
|
|
123
|
+
import { Buffer as Buffer2 } from "node:buffer";
|
|
124
|
+
import { promisify } from "node:util";
|
|
125
|
+
import childProcess from "node:child_process";
|
|
126
|
+
var execFile, powerShellPath, executePowerShell;
|
|
127
|
+
var init_powershell_utils = __esm({
|
|
128
|
+
"node_modules/.pnpm/powershell-utils@0.1.0/node_modules/powershell-utils/index.js"() {
|
|
129
|
+
execFile = promisify(childProcess.execFile);
|
|
130
|
+
powerShellPath = () => `${process3.env.SYSTEMROOT || process3.env.windir || String.raw`C:\Windows`}\\System32\\WindowsPowerShell\\v1.0\\powershell.exe`;
|
|
131
|
+
executePowerShell = async (command, options2 = {}) => {
|
|
132
|
+
const {
|
|
133
|
+
powerShellPath: psPath,
|
|
134
|
+
...execFileOptions
|
|
135
|
+
} = options2;
|
|
136
|
+
const encodedCommand = executePowerShell.encodeCommand(command);
|
|
137
|
+
return execFile(
|
|
138
|
+
psPath ?? powerShellPath(),
|
|
139
|
+
[
|
|
140
|
+
...executePowerShell.argumentsPrefix,
|
|
141
|
+
encodedCommand
|
|
142
|
+
],
|
|
143
|
+
{
|
|
144
|
+
encoding: "utf8",
|
|
145
|
+
...execFileOptions
|
|
146
|
+
}
|
|
147
|
+
);
|
|
148
|
+
};
|
|
149
|
+
executePowerShell.argumentsPrefix = [
|
|
150
|
+
"-NoProfile",
|
|
151
|
+
"-NonInteractive",
|
|
152
|
+
"-ExecutionPolicy",
|
|
153
|
+
"Bypass",
|
|
154
|
+
"-EncodedCommand"
|
|
155
|
+
];
|
|
156
|
+
executePowerShell.encodeCommand = (command) => Buffer2.from(command, "utf16le").toString("base64");
|
|
157
|
+
executePowerShell.escapeArgument = (value) => `'${String(value).replaceAll("'", "''")}'`;
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
// node_modules/.pnpm/wsl-utils@0.3.1/node_modules/wsl-utils/utilities.js
|
|
162
|
+
function parseMountPointFromConfig(content) {
|
|
163
|
+
for (const line of content.split("\n")) {
|
|
164
|
+
if (/^\s*#/.test(line)) {
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
const match = /^\s*root\s*=\s*(?<mountPoint>"[^"]*"|'[^']*'|[^#]*)/.exec(line);
|
|
168
|
+
if (!match) {
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
return match.groups.mountPoint.trim().replaceAll(/^["']|["']$/g, "");
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
var init_utilities = __esm({
|
|
175
|
+
"node_modules/.pnpm/wsl-utils@0.3.1/node_modules/wsl-utils/utilities.js"() {
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
// node_modules/.pnpm/wsl-utils@0.3.1/node_modules/wsl-utils/index.js
|
|
180
|
+
import { promisify as promisify2 } from "node:util";
|
|
181
|
+
import childProcess2 from "node:child_process";
|
|
182
|
+
import fs7, { constants as fsConstants } from "node:fs/promises";
|
|
183
|
+
var execFile2, wslDrivesMountPoint, powerShellPathFromWsl, powerShellPath2, canAccessPowerShellPromise, canAccessPowerShell, wslDefaultBrowser, convertWslPathToWindows;
|
|
184
|
+
var init_wsl_utils = __esm({
|
|
185
|
+
"node_modules/.pnpm/wsl-utils@0.3.1/node_modules/wsl-utils/index.js"() {
|
|
186
|
+
init_is_wsl();
|
|
187
|
+
init_powershell_utils();
|
|
188
|
+
init_utilities();
|
|
189
|
+
init_is_wsl();
|
|
190
|
+
execFile2 = promisify2(childProcess2.execFile);
|
|
191
|
+
wslDrivesMountPoint = /* @__PURE__ */ (() => {
|
|
192
|
+
const defaultMountPoint = "/mnt/";
|
|
193
|
+
let mountPoint;
|
|
194
|
+
return async function() {
|
|
195
|
+
if (mountPoint) {
|
|
196
|
+
return mountPoint;
|
|
197
|
+
}
|
|
198
|
+
const configFilePath = "/etc/wsl.conf";
|
|
199
|
+
let isConfigFileExists = false;
|
|
200
|
+
try {
|
|
201
|
+
await fs7.access(configFilePath, fsConstants.F_OK);
|
|
202
|
+
isConfigFileExists = true;
|
|
203
|
+
} catch {
|
|
204
|
+
}
|
|
205
|
+
if (!isConfigFileExists) {
|
|
206
|
+
return defaultMountPoint;
|
|
207
|
+
}
|
|
208
|
+
const configContent = await fs7.readFile(configFilePath, { encoding: "utf8" });
|
|
209
|
+
const parsedMountPoint = parseMountPointFromConfig(configContent);
|
|
210
|
+
if (parsedMountPoint === void 0) {
|
|
211
|
+
return defaultMountPoint;
|
|
212
|
+
}
|
|
213
|
+
mountPoint = parsedMountPoint;
|
|
214
|
+
mountPoint = mountPoint.endsWith("/") ? mountPoint : `${mountPoint}/`;
|
|
215
|
+
return mountPoint;
|
|
216
|
+
};
|
|
217
|
+
})();
|
|
218
|
+
powerShellPathFromWsl = async () => {
|
|
219
|
+
const mountPoint = await wslDrivesMountPoint();
|
|
220
|
+
return `${mountPoint}c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe`;
|
|
221
|
+
};
|
|
222
|
+
powerShellPath2 = is_wsl_default ? powerShellPathFromWsl : powerShellPath;
|
|
223
|
+
canAccessPowerShell = async () => {
|
|
224
|
+
canAccessPowerShellPromise ??= (async () => {
|
|
225
|
+
try {
|
|
226
|
+
const psPath = await powerShellPath2();
|
|
227
|
+
await fs7.access(psPath, fsConstants.X_OK);
|
|
228
|
+
return true;
|
|
229
|
+
} catch {
|
|
230
|
+
return false;
|
|
231
|
+
}
|
|
232
|
+
})();
|
|
233
|
+
return canAccessPowerShellPromise;
|
|
234
|
+
};
|
|
235
|
+
wslDefaultBrowser = async () => {
|
|
236
|
+
const psPath = await powerShellPath2();
|
|
237
|
+
const command = String.raw`(Get-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\http\UserChoice").ProgId`;
|
|
238
|
+
const { stdout } = await executePowerShell(command, { powerShellPath: psPath });
|
|
239
|
+
return stdout.trim();
|
|
240
|
+
};
|
|
241
|
+
convertWslPathToWindows = async (path22) => {
|
|
242
|
+
if (/^[a-z]+:\/\//i.test(path22)) {
|
|
243
|
+
return path22;
|
|
244
|
+
}
|
|
245
|
+
try {
|
|
246
|
+
const { stdout } = await execFile2("wslpath", ["-aw", path22], { encoding: "utf8" });
|
|
247
|
+
return stdout.trim();
|
|
248
|
+
} catch {
|
|
249
|
+
return path22;
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
// node_modules/.pnpm/define-lazy-prop@3.0.0/node_modules/define-lazy-prop/index.js
|
|
256
|
+
function defineLazyProperty(object, propertyName, valueGetter) {
|
|
257
|
+
const define = (value) => Object.defineProperty(object, propertyName, { value, enumerable: true, writable: true });
|
|
258
|
+
Object.defineProperty(object, propertyName, {
|
|
259
|
+
configurable: true,
|
|
260
|
+
enumerable: true,
|
|
261
|
+
get() {
|
|
262
|
+
const result = valueGetter();
|
|
263
|
+
define(result);
|
|
264
|
+
return result;
|
|
265
|
+
},
|
|
266
|
+
set(value) {
|
|
267
|
+
define(value);
|
|
268
|
+
}
|
|
269
|
+
});
|
|
270
|
+
return object;
|
|
271
|
+
}
|
|
272
|
+
var init_define_lazy_prop = __esm({
|
|
273
|
+
"node_modules/.pnpm/define-lazy-prop@3.0.0/node_modules/define-lazy-prop/index.js"() {
|
|
274
|
+
}
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
// node_modules/.pnpm/default-browser-id@5.0.1/node_modules/default-browser-id/index.js
|
|
278
|
+
import { promisify as promisify3 } from "node:util";
|
|
279
|
+
import process4 from "node:process";
|
|
280
|
+
import { execFile as execFile3 } from "node:child_process";
|
|
281
|
+
async function defaultBrowserId() {
|
|
282
|
+
if (process4.platform !== "darwin") {
|
|
283
|
+
throw new Error("macOS only");
|
|
284
|
+
}
|
|
285
|
+
const { stdout } = await execFileAsync("defaults", ["read", "com.apple.LaunchServices/com.apple.launchservices.secure", "LSHandlers"]);
|
|
286
|
+
const match = /LSHandlerRoleAll = "(?!-)(?<id>[^"]+?)";\s+?LSHandlerURLScheme = (?:http|https);/.exec(stdout);
|
|
287
|
+
const browserId = match?.groups.id ?? "com.apple.Safari";
|
|
288
|
+
if (browserId === "com.apple.safari") {
|
|
289
|
+
return "com.apple.Safari";
|
|
290
|
+
}
|
|
291
|
+
return browserId;
|
|
292
|
+
}
|
|
293
|
+
var execFileAsync;
|
|
294
|
+
var init_default_browser_id = __esm({
|
|
295
|
+
"node_modules/.pnpm/default-browser-id@5.0.1/node_modules/default-browser-id/index.js"() {
|
|
296
|
+
execFileAsync = promisify3(execFile3);
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
// node_modules/.pnpm/run-applescript@7.1.0/node_modules/run-applescript/index.js
|
|
301
|
+
import process5 from "node:process";
|
|
302
|
+
import { promisify as promisify4 } from "node:util";
|
|
303
|
+
import { execFile as execFile4, execFileSync } from "node:child_process";
|
|
304
|
+
async function runAppleScript(script, { humanReadableOutput = true, signal } = {}) {
|
|
305
|
+
if (process5.platform !== "darwin") {
|
|
306
|
+
throw new Error("macOS only");
|
|
307
|
+
}
|
|
308
|
+
const outputArguments = humanReadableOutput ? [] : ["-ss"];
|
|
309
|
+
const execOptions = {};
|
|
310
|
+
if (signal) {
|
|
311
|
+
execOptions.signal = signal;
|
|
312
|
+
}
|
|
313
|
+
const { stdout } = await execFileAsync2("osascript", ["-e", script, outputArguments], execOptions);
|
|
314
|
+
return stdout.trim();
|
|
315
|
+
}
|
|
316
|
+
var execFileAsync2;
|
|
317
|
+
var init_run_applescript = __esm({
|
|
318
|
+
"node_modules/.pnpm/run-applescript@7.1.0/node_modules/run-applescript/index.js"() {
|
|
319
|
+
execFileAsync2 = promisify4(execFile4);
|
|
320
|
+
}
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
// node_modules/.pnpm/bundle-name@4.1.0/node_modules/bundle-name/index.js
|
|
324
|
+
async function bundleName(bundleId) {
|
|
325
|
+
return runAppleScript(`tell application "Finder" to set app_path to application file id "${bundleId}" as string
|
|
326
|
+
tell application "System Events" to get value of property list item "CFBundleName" of property list file (app_path & ":Contents:Info.plist")`);
|
|
327
|
+
}
|
|
328
|
+
var init_bundle_name = __esm({
|
|
329
|
+
"node_modules/.pnpm/bundle-name@4.1.0/node_modules/bundle-name/index.js"() {
|
|
330
|
+
init_run_applescript();
|
|
331
|
+
}
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
// node_modules/.pnpm/default-browser@5.4.0/node_modules/default-browser/windows.js
|
|
335
|
+
import { promisify as promisify5 } from "node:util";
|
|
336
|
+
import { execFile as execFile5 } from "node:child_process";
|
|
337
|
+
async function defaultBrowser(_execFileAsync = execFileAsync3) {
|
|
338
|
+
const { stdout } = await _execFileAsync("reg", [
|
|
339
|
+
"QUERY",
|
|
340
|
+
" HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\http\\UserChoice",
|
|
341
|
+
"/v",
|
|
342
|
+
"ProgId"
|
|
343
|
+
]);
|
|
344
|
+
const match = /ProgId\s*REG_SZ\s*(?<id>\S+)/.exec(stdout);
|
|
345
|
+
if (!match) {
|
|
346
|
+
throw new UnknownBrowserError(`Cannot find Windows browser in stdout: ${JSON.stringify(stdout)}`);
|
|
347
|
+
}
|
|
348
|
+
const { id } = match.groups;
|
|
349
|
+
const browser = windowsBrowserProgIds[id];
|
|
350
|
+
if (!browser) {
|
|
351
|
+
throw new UnknownBrowserError(`Unknown browser ID: ${id}`);
|
|
352
|
+
}
|
|
353
|
+
return browser;
|
|
354
|
+
}
|
|
355
|
+
var execFileAsync3, windowsBrowserProgIds, _windowsBrowserProgIdMap, UnknownBrowserError;
|
|
356
|
+
var init_windows = __esm({
|
|
357
|
+
"node_modules/.pnpm/default-browser@5.4.0/node_modules/default-browser/windows.js"() {
|
|
358
|
+
execFileAsync3 = promisify5(execFile5);
|
|
359
|
+
windowsBrowserProgIds = {
|
|
360
|
+
MSEdgeHTM: { name: "Edge", id: "com.microsoft.edge" },
|
|
361
|
+
// The missing `L` is correct.
|
|
362
|
+
MSEdgeBHTML: { name: "Edge Beta", id: "com.microsoft.edge.beta" },
|
|
363
|
+
MSEdgeDHTML: { name: "Edge Dev", id: "com.microsoft.edge.dev" },
|
|
364
|
+
AppXq0fevzme2pys62n3e0fbqa7peapykr8v: { name: "Edge", id: "com.microsoft.edge.old" },
|
|
365
|
+
ChromeHTML: { name: "Chrome", id: "com.google.chrome" },
|
|
366
|
+
ChromeBHTML: { name: "Chrome Beta", id: "com.google.chrome.beta" },
|
|
367
|
+
ChromeDHTML: { name: "Chrome Dev", id: "com.google.chrome.dev" },
|
|
368
|
+
ChromiumHTM: { name: "Chromium", id: "org.chromium.Chromium" },
|
|
369
|
+
BraveHTML: { name: "Brave", id: "com.brave.Browser" },
|
|
370
|
+
BraveBHTML: { name: "Brave Beta", id: "com.brave.Browser.beta" },
|
|
371
|
+
BraveDHTML: { name: "Brave Dev", id: "com.brave.Browser.dev" },
|
|
372
|
+
BraveSSHTM: { name: "Brave Nightly", id: "com.brave.Browser.nightly" },
|
|
373
|
+
FirefoxURL: { name: "Firefox", id: "org.mozilla.firefox" },
|
|
374
|
+
OperaStable: { name: "Opera", id: "com.operasoftware.Opera" },
|
|
375
|
+
VivaldiHTM: { name: "Vivaldi", id: "com.vivaldi.Vivaldi" },
|
|
376
|
+
"IE.HTTP": { name: "Internet Explorer", id: "com.microsoft.ie" }
|
|
377
|
+
};
|
|
378
|
+
_windowsBrowserProgIdMap = new Map(Object.entries(windowsBrowserProgIds));
|
|
379
|
+
UnknownBrowserError = class extends Error {
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
// node_modules/.pnpm/default-browser@5.4.0/node_modules/default-browser/index.js
|
|
385
|
+
import { promisify as promisify6 } from "node:util";
|
|
386
|
+
import process6 from "node:process";
|
|
387
|
+
import { execFile as execFile6 } from "node:child_process";
|
|
388
|
+
async function defaultBrowser2() {
|
|
389
|
+
if (process6.platform === "darwin") {
|
|
390
|
+
const id = await defaultBrowserId();
|
|
391
|
+
const name = await bundleName(id);
|
|
392
|
+
return { name, id };
|
|
393
|
+
}
|
|
394
|
+
if (process6.platform === "linux") {
|
|
395
|
+
const { stdout } = await execFileAsync4("xdg-mime", ["query", "default", "x-scheme-handler/http"]);
|
|
396
|
+
const id = stdout.trim();
|
|
397
|
+
const name = titleize(id.replace(/.desktop$/, "").replace("-", " "));
|
|
398
|
+
return { name, id };
|
|
399
|
+
}
|
|
400
|
+
if (process6.platform === "win32") {
|
|
401
|
+
return defaultBrowser();
|
|
402
|
+
}
|
|
403
|
+
throw new Error("Only macOS, Linux, and Windows are supported");
|
|
404
|
+
}
|
|
405
|
+
var execFileAsync4, titleize;
|
|
406
|
+
var init_default_browser = __esm({
|
|
407
|
+
"node_modules/.pnpm/default-browser@5.4.0/node_modules/default-browser/index.js"() {
|
|
408
|
+
init_default_browser_id();
|
|
409
|
+
init_bundle_name();
|
|
410
|
+
init_windows();
|
|
411
|
+
init_windows();
|
|
412
|
+
execFileAsync4 = promisify6(execFile6);
|
|
413
|
+
titleize = (string) => string.toLowerCase().replaceAll(/(?:^|\s|-)\S/g, (x) => x.toUpperCase());
|
|
414
|
+
}
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
// node_modules/.pnpm/is-in-ssh@1.0.0/node_modules/is-in-ssh/index.js
|
|
418
|
+
import process7 from "node:process";
|
|
419
|
+
var isInSsh, is_in_ssh_default;
|
|
420
|
+
var init_is_in_ssh = __esm({
|
|
421
|
+
"node_modules/.pnpm/is-in-ssh@1.0.0/node_modules/is-in-ssh/index.js"() {
|
|
422
|
+
isInSsh = Boolean(process7.env.SSH_CONNECTION || process7.env.SSH_CLIENT || process7.env.SSH_TTY);
|
|
423
|
+
is_in_ssh_default = isInSsh;
|
|
424
|
+
}
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
// node_modules/.pnpm/open@11.0.0/node_modules/open/index.js
|
|
428
|
+
var open_exports = {};
|
|
429
|
+
__export(open_exports, {
|
|
430
|
+
apps: () => apps,
|
|
431
|
+
default: () => open_default,
|
|
432
|
+
openApp: () => openApp
|
|
433
|
+
});
|
|
434
|
+
import process8 from "node:process";
|
|
435
|
+
import path4 from "node:path";
|
|
436
|
+
import { fileURLToPath } from "node:url";
|
|
437
|
+
import childProcess3 from "node:child_process";
|
|
438
|
+
import fs8, { constants as fsConstants2 } from "node:fs/promises";
|
|
439
|
+
function detectArchBinary(binary) {
|
|
440
|
+
if (typeof binary === "string" || Array.isArray(binary)) {
|
|
441
|
+
return binary;
|
|
442
|
+
}
|
|
443
|
+
const { [arch]: archBinary } = binary;
|
|
444
|
+
if (!archBinary) {
|
|
445
|
+
throw new Error(`${arch} is not supported`);
|
|
446
|
+
}
|
|
447
|
+
return archBinary;
|
|
448
|
+
}
|
|
449
|
+
function detectPlatformBinary({ [platform2]: platformBinary }, { wsl } = {}) {
|
|
450
|
+
if (wsl && is_wsl_default) {
|
|
451
|
+
return detectArchBinary(wsl);
|
|
452
|
+
}
|
|
453
|
+
if (!platformBinary) {
|
|
454
|
+
throw new Error(`${platform2} is not supported`);
|
|
455
|
+
}
|
|
456
|
+
return detectArchBinary(platformBinary);
|
|
457
|
+
}
|
|
458
|
+
var fallbackAttemptSymbol, __dirname, localXdgOpenPath, platform2, arch, tryEachApp, baseOpen, open, openApp, apps, open_default;
|
|
459
|
+
var init_open = __esm({
|
|
460
|
+
"node_modules/.pnpm/open@11.0.0/node_modules/open/index.js"() {
|
|
461
|
+
init_wsl_utils();
|
|
462
|
+
init_powershell_utils();
|
|
463
|
+
init_define_lazy_prop();
|
|
464
|
+
init_default_browser();
|
|
465
|
+
init_is_inside_container();
|
|
466
|
+
init_is_in_ssh();
|
|
467
|
+
fallbackAttemptSymbol = Symbol("fallbackAttempt");
|
|
468
|
+
__dirname = import.meta.url ? path4.dirname(fileURLToPath(import.meta.url)) : "";
|
|
469
|
+
localXdgOpenPath = path4.join(__dirname, "xdg-open");
|
|
470
|
+
({ platform: platform2, arch } = process8);
|
|
471
|
+
tryEachApp = async (apps2, opener) => {
|
|
472
|
+
if (apps2.length === 0) {
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
475
|
+
const errors = [];
|
|
476
|
+
for (const app of apps2) {
|
|
477
|
+
try {
|
|
478
|
+
return await opener(app);
|
|
479
|
+
} catch (error) {
|
|
480
|
+
errors.push(error);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
throw new AggregateError(errors, "Failed to open in all supported apps");
|
|
484
|
+
};
|
|
485
|
+
baseOpen = async (options2) => {
|
|
486
|
+
options2 = {
|
|
487
|
+
wait: false,
|
|
488
|
+
background: false,
|
|
489
|
+
newInstance: false,
|
|
490
|
+
allowNonzeroExitCode: false,
|
|
491
|
+
...options2
|
|
492
|
+
};
|
|
493
|
+
const isFallbackAttempt = options2[fallbackAttemptSymbol] === true;
|
|
494
|
+
delete options2[fallbackAttemptSymbol];
|
|
495
|
+
if (Array.isArray(options2.app)) {
|
|
496
|
+
return tryEachApp(options2.app, (singleApp) => baseOpen({
|
|
497
|
+
...options2,
|
|
498
|
+
app: singleApp,
|
|
499
|
+
[fallbackAttemptSymbol]: true
|
|
500
|
+
}));
|
|
501
|
+
}
|
|
502
|
+
let { name: app, arguments: appArguments = [] } = options2.app ?? {};
|
|
503
|
+
appArguments = [...appArguments];
|
|
504
|
+
if (Array.isArray(app)) {
|
|
505
|
+
return tryEachApp(app, (appName) => baseOpen({
|
|
506
|
+
...options2,
|
|
507
|
+
app: {
|
|
508
|
+
name: appName,
|
|
509
|
+
arguments: appArguments
|
|
510
|
+
},
|
|
511
|
+
[fallbackAttemptSymbol]: true
|
|
512
|
+
}));
|
|
513
|
+
}
|
|
514
|
+
if (app === "browser" || app === "browserPrivate") {
|
|
515
|
+
const ids = {
|
|
516
|
+
"com.google.chrome": "chrome",
|
|
517
|
+
"google-chrome.desktop": "chrome",
|
|
518
|
+
"com.brave.browser": "brave",
|
|
519
|
+
"org.mozilla.firefox": "firefox",
|
|
520
|
+
"firefox.desktop": "firefox",
|
|
521
|
+
"com.microsoft.msedge": "edge",
|
|
522
|
+
"com.microsoft.edge": "edge",
|
|
523
|
+
"com.microsoft.edgemac": "edge",
|
|
524
|
+
"microsoft-edge.desktop": "edge",
|
|
525
|
+
"com.apple.safari": "safari"
|
|
526
|
+
};
|
|
527
|
+
const flags = {
|
|
528
|
+
chrome: "--incognito",
|
|
529
|
+
brave: "--incognito",
|
|
530
|
+
firefox: "--private-window",
|
|
531
|
+
edge: "--inPrivate"
|
|
532
|
+
// Safari doesn't support private mode via command line
|
|
533
|
+
};
|
|
534
|
+
let browser;
|
|
535
|
+
if (is_wsl_default) {
|
|
536
|
+
const progId = await wslDefaultBrowser();
|
|
537
|
+
const browserInfo = _windowsBrowserProgIdMap.get(progId);
|
|
538
|
+
browser = browserInfo ?? {};
|
|
539
|
+
} else {
|
|
540
|
+
browser = await defaultBrowser2();
|
|
541
|
+
}
|
|
542
|
+
if (browser.id in ids) {
|
|
543
|
+
const browserName = ids[browser.id.toLowerCase()];
|
|
544
|
+
if (app === "browserPrivate") {
|
|
545
|
+
if (browserName === "safari") {
|
|
546
|
+
throw new Error("Safari doesn't support opening in private mode via command line");
|
|
547
|
+
}
|
|
548
|
+
appArguments.push(flags[browserName]);
|
|
549
|
+
}
|
|
550
|
+
return baseOpen({
|
|
551
|
+
...options2,
|
|
552
|
+
app: {
|
|
553
|
+
name: apps[browserName],
|
|
554
|
+
arguments: appArguments
|
|
555
|
+
}
|
|
556
|
+
});
|
|
557
|
+
}
|
|
558
|
+
throw new Error(`${browser.name} is not supported as a default browser`);
|
|
559
|
+
}
|
|
560
|
+
let command;
|
|
561
|
+
const cliArguments = [];
|
|
562
|
+
const childProcessOptions = {};
|
|
563
|
+
let shouldUseWindowsInWsl = false;
|
|
564
|
+
if (is_wsl_default && !isInsideContainer() && !is_in_ssh_default && !app) {
|
|
565
|
+
shouldUseWindowsInWsl = await canAccessPowerShell();
|
|
566
|
+
}
|
|
567
|
+
if (platform2 === "darwin") {
|
|
568
|
+
command = "open";
|
|
569
|
+
if (options2.wait) {
|
|
570
|
+
cliArguments.push("--wait-apps");
|
|
571
|
+
}
|
|
572
|
+
if (options2.background) {
|
|
573
|
+
cliArguments.push("--background");
|
|
574
|
+
}
|
|
575
|
+
if (options2.newInstance) {
|
|
576
|
+
cliArguments.push("--new");
|
|
577
|
+
}
|
|
578
|
+
if (app) {
|
|
579
|
+
cliArguments.push("-a", app);
|
|
580
|
+
}
|
|
581
|
+
} else if (platform2 === "win32" || shouldUseWindowsInWsl) {
|
|
582
|
+
command = await powerShellPath2();
|
|
583
|
+
cliArguments.push(...executePowerShell.argumentsPrefix);
|
|
584
|
+
if (!is_wsl_default) {
|
|
585
|
+
childProcessOptions.windowsVerbatimArguments = true;
|
|
586
|
+
}
|
|
587
|
+
if (is_wsl_default && options2.target) {
|
|
588
|
+
options2.target = await convertWslPathToWindows(options2.target);
|
|
589
|
+
}
|
|
590
|
+
const encodedArguments = ["$ProgressPreference = 'SilentlyContinue';", "Start"];
|
|
591
|
+
if (options2.wait) {
|
|
592
|
+
encodedArguments.push("-Wait");
|
|
593
|
+
}
|
|
594
|
+
if (app) {
|
|
595
|
+
encodedArguments.push(executePowerShell.escapeArgument(app));
|
|
596
|
+
if (options2.target) {
|
|
597
|
+
appArguments.push(options2.target);
|
|
598
|
+
}
|
|
599
|
+
} else if (options2.target) {
|
|
600
|
+
encodedArguments.push(executePowerShell.escapeArgument(options2.target));
|
|
601
|
+
}
|
|
602
|
+
if (appArguments.length > 0) {
|
|
603
|
+
appArguments = appArguments.map((argument) => executePowerShell.escapeArgument(argument));
|
|
604
|
+
encodedArguments.push("-ArgumentList", appArguments.join(","));
|
|
605
|
+
}
|
|
606
|
+
options2.target = executePowerShell.encodeCommand(encodedArguments.join(" "));
|
|
607
|
+
if (!options2.wait) {
|
|
608
|
+
childProcessOptions.stdio = "ignore";
|
|
609
|
+
}
|
|
610
|
+
} else {
|
|
611
|
+
if (app) {
|
|
612
|
+
command = app;
|
|
613
|
+
} else {
|
|
614
|
+
const isBundled = !__dirname || __dirname === "/";
|
|
615
|
+
let exeLocalXdgOpen = false;
|
|
616
|
+
try {
|
|
617
|
+
await fs8.access(localXdgOpenPath, fsConstants2.X_OK);
|
|
618
|
+
exeLocalXdgOpen = true;
|
|
619
|
+
} catch {
|
|
620
|
+
}
|
|
621
|
+
const useSystemXdgOpen = process8.versions.electron ?? (platform2 === "android" || isBundled || !exeLocalXdgOpen);
|
|
622
|
+
command = useSystemXdgOpen ? "xdg-open" : localXdgOpenPath;
|
|
623
|
+
}
|
|
624
|
+
if (appArguments.length > 0) {
|
|
625
|
+
cliArguments.push(...appArguments);
|
|
626
|
+
}
|
|
627
|
+
if (!options2.wait) {
|
|
628
|
+
childProcessOptions.stdio = "ignore";
|
|
629
|
+
childProcessOptions.detached = true;
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
if (platform2 === "darwin" && appArguments.length > 0) {
|
|
633
|
+
cliArguments.push("--args", ...appArguments);
|
|
634
|
+
}
|
|
635
|
+
if (options2.target) {
|
|
636
|
+
cliArguments.push(options2.target);
|
|
637
|
+
}
|
|
638
|
+
const subprocess = childProcess3.spawn(command, cliArguments, childProcessOptions);
|
|
639
|
+
if (options2.wait) {
|
|
640
|
+
return new Promise((resolve7, reject) => {
|
|
641
|
+
subprocess.once("error", reject);
|
|
642
|
+
subprocess.once("close", (exitCode) => {
|
|
643
|
+
if (!options2.allowNonzeroExitCode && exitCode !== 0) {
|
|
644
|
+
reject(new Error(`Exited with code ${exitCode}`));
|
|
645
|
+
return;
|
|
646
|
+
}
|
|
647
|
+
resolve7(subprocess);
|
|
648
|
+
});
|
|
649
|
+
});
|
|
650
|
+
}
|
|
651
|
+
if (isFallbackAttempt) {
|
|
652
|
+
return new Promise((resolve7, reject) => {
|
|
653
|
+
subprocess.once("error", reject);
|
|
654
|
+
subprocess.once("spawn", () => {
|
|
655
|
+
subprocess.once("close", (exitCode) => {
|
|
656
|
+
subprocess.off("error", reject);
|
|
657
|
+
if (exitCode !== 0) {
|
|
658
|
+
reject(new Error(`Exited with code ${exitCode}`));
|
|
659
|
+
return;
|
|
660
|
+
}
|
|
661
|
+
subprocess.unref();
|
|
662
|
+
resolve7(subprocess);
|
|
663
|
+
});
|
|
664
|
+
});
|
|
665
|
+
});
|
|
666
|
+
}
|
|
667
|
+
subprocess.unref();
|
|
668
|
+
return new Promise((resolve7, reject) => {
|
|
669
|
+
subprocess.once("error", reject);
|
|
670
|
+
subprocess.once("spawn", () => {
|
|
671
|
+
subprocess.off("error", reject);
|
|
672
|
+
resolve7(subprocess);
|
|
673
|
+
});
|
|
674
|
+
});
|
|
675
|
+
};
|
|
676
|
+
open = (target, options2) => {
|
|
677
|
+
if (typeof target !== "string") {
|
|
678
|
+
throw new TypeError("Expected a `target`");
|
|
679
|
+
}
|
|
680
|
+
return baseOpen({
|
|
681
|
+
...options2,
|
|
682
|
+
target
|
|
683
|
+
});
|
|
684
|
+
};
|
|
685
|
+
openApp = (name, options2) => {
|
|
686
|
+
if (typeof name !== "string" && !Array.isArray(name)) {
|
|
687
|
+
throw new TypeError("Expected a valid `name`");
|
|
688
|
+
}
|
|
689
|
+
const { arguments: appArguments = [] } = options2 ?? {};
|
|
690
|
+
if (appArguments !== void 0 && appArguments !== null && !Array.isArray(appArguments)) {
|
|
691
|
+
throw new TypeError("Expected `appArguments` as Array type");
|
|
692
|
+
}
|
|
693
|
+
return baseOpen({
|
|
694
|
+
...options2,
|
|
695
|
+
app: {
|
|
696
|
+
name,
|
|
697
|
+
arguments: appArguments
|
|
698
|
+
}
|
|
699
|
+
});
|
|
700
|
+
};
|
|
701
|
+
apps = {
|
|
702
|
+
browser: "browser",
|
|
703
|
+
browserPrivate: "browserPrivate"
|
|
704
|
+
};
|
|
705
|
+
defineLazyProperty(apps, "chrome", () => detectPlatformBinary({
|
|
706
|
+
darwin: "google chrome",
|
|
707
|
+
win32: "chrome",
|
|
708
|
+
// `chromium-browser` is the older deb package name used by Ubuntu/Debian before snap.
|
|
709
|
+
linux: ["google-chrome", "google-chrome-stable", "chromium", "chromium-browser"]
|
|
710
|
+
}, {
|
|
711
|
+
wsl: {
|
|
712
|
+
ia32: "/mnt/c/Program Files (x86)/Google/Chrome/Application/chrome.exe",
|
|
713
|
+
x64: ["/mnt/c/Program Files/Google/Chrome/Application/chrome.exe", "/mnt/c/Program Files (x86)/Google/Chrome/Application/chrome.exe"]
|
|
714
|
+
}
|
|
715
|
+
}));
|
|
716
|
+
defineLazyProperty(apps, "brave", () => detectPlatformBinary({
|
|
717
|
+
darwin: "brave browser",
|
|
718
|
+
win32: "brave",
|
|
719
|
+
linux: ["brave-browser", "brave"]
|
|
720
|
+
}, {
|
|
721
|
+
wsl: {
|
|
722
|
+
ia32: "/mnt/c/Program Files (x86)/BraveSoftware/Brave-Browser/Application/brave.exe",
|
|
723
|
+
x64: ["/mnt/c/Program Files/BraveSoftware/Brave-Browser/Application/brave.exe", "/mnt/c/Program Files (x86)/BraveSoftware/Brave-Browser/Application/brave.exe"]
|
|
724
|
+
}
|
|
725
|
+
}));
|
|
726
|
+
defineLazyProperty(apps, "firefox", () => detectPlatformBinary({
|
|
727
|
+
darwin: "firefox",
|
|
728
|
+
win32: String.raw`C:\Program Files\Mozilla Firefox\firefox.exe`,
|
|
729
|
+
linux: "firefox"
|
|
730
|
+
}, {
|
|
731
|
+
wsl: "/mnt/c/Program Files/Mozilla Firefox/firefox.exe"
|
|
732
|
+
}));
|
|
733
|
+
defineLazyProperty(apps, "edge", () => detectPlatformBinary({
|
|
734
|
+
darwin: "microsoft edge",
|
|
735
|
+
win32: "msedge",
|
|
736
|
+
linux: ["microsoft-edge", "microsoft-edge-dev"]
|
|
737
|
+
}, {
|
|
738
|
+
wsl: "/mnt/c/Program Files (x86)/Microsoft/Edge/Application/msedge.exe"
|
|
739
|
+
}));
|
|
740
|
+
defineLazyProperty(apps, "safari", () => detectPlatformBinary({
|
|
741
|
+
darwin: "Safari"
|
|
742
|
+
}));
|
|
743
|
+
open_default = open;
|
|
744
|
+
}
|
|
745
|
+
});
|
|
746
|
+
|
|
747
|
+
// node_modules/.pnpm/hcl2-json-parser@1.0.1/node_modules/hcl2-json-parser/dist/index.js
|
|
35
748
|
var require_dist = __commonJS({
|
|
36
|
-
"
|
|
749
|
+
"node_modules/.pnpm/hcl2-json-parser@1.0.1/node_modules/hcl2-json-parser/dist/index.js"(exports, module) {
|
|
37
750
|
"use strict";
|
|
38
751
|
(function() {
|
|
39
752
|
var $goVersion = "go1.18.10";
|
|
@@ -41,8 +754,8 @@ var require_dist = __commonJS({
|
|
|
41
754
|
var $global, $module, $NaN = NaN;
|
|
42
755
|
if ("undefined" != typeof window ? $global = window : "undefined" != typeof self ? $global = self : "undefined" != typeof global ? ($global = global).require = __require : $global = this, void 0 === $global || void 0 === $global.Array) throw new Error("no global object found");
|
|
43
756
|
if ("undefined" != typeof module && ($module = module), !$global.fs && $global.require) try {
|
|
44
|
-
var
|
|
45
|
-
"object" == typeof
|
|
757
|
+
var fs24 = $global.require("fs");
|
|
758
|
+
"object" == typeof fs24 && null !== fs24 && 0 !== Object.keys(fs24).length && ($global.fs = fs24);
|
|
46
759
|
} catch (e) {
|
|
47
760
|
}
|
|
48
761
|
if (!$global.fs) {
|
|
@@ -182233,8 +182946,8 @@ var require_dist = __commonJS({
|
|
|
182233
182946
|
import { Command } from "commander";
|
|
182234
182947
|
|
|
182235
182948
|
// src/commands/init.tsx
|
|
182236
|
-
import React2, { useState
|
|
182237
|
-
import { render as render2, Text as Text2, Box as Box2, useInput, useApp
|
|
182949
|
+
import React2, { useState, useEffect } from "react";
|
|
182950
|
+
import { render as render2, Text as Text2, Box as Box2, useInput, useApp } from "ink";
|
|
182238
182951
|
import "ink-spinner";
|
|
182239
182952
|
import * as fs10 from "fs";
|
|
182240
182953
|
import * as path6 from "path";
|
|
@@ -182407,7 +183120,7 @@ function generateCertificate(domain, keys = []) {
|
|
|
182407
183120
|
|
|
182408
183121
|
// src/lib/analytics/index.ts
|
|
182409
183122
|
import { PostHog } from "posthog-node";
|
|
182410
|
-
import * as
|
|
183123
|
+
import * as os5 from "os";
|
|
182411
183124
|
import * as crypto from "crypto";
|
|
182412
183125
|
|
|
182413
183126
|
// src/lib/project/config.ts
|
|
@@ -182452,7 +183165,7 @@ function writeProjectId(projectId, projectDir = process.cwd()) {
|
|
|
182452
183165
|
// src/lib/auth/credentials.ts
|
|
182453
183166
|
import * as fs9 from "fs";
|
|
182454
183167
|
import * as path5 from "path";
|
|
182455
|
-
import * as
|
|
183168
|
+
import * as os4 from "os";
|
|
182456
183169
|
|
|
182457
183170
|
// src/lib/auth/errors.ts
|
|
182458
183171
|
var RefreshTokenExpiredError = class extends Error {
|
|
@@ -182525,642 +183238,22 @@ async function refreshAccessToken(refreshToken) {
|
|
|
182525
183238
|
}
|
|
182526
183239
|
|
|
182527
183240
|
// src/lib/auth/login.tsx
|
|
182528
|
-
import React
|
|
182529
|
-
import { render, Box, Text
|
|
183241
|
+
import React from "react";
|
|
183242
|
+
import { render, Box, Text } from "ink";
|
|
182530
183243
|
import Spinner from "ink-spinner";
|
|
182531
183244
|
|
|
182532
|
-
// ../../node_modules/open/index.js
|
|
182533
|
-
import process8 from "node:process";
|
|
182534
|
-
import path3 from "node:path";
|
|
182535
|
-
import { fileURLToPath } from "node:url";
|
|
182536
|
-
import childProcess3 from "node:child_process";
|
|
182537
|
-
import fs7, { constants as fsConstants2 } from "node:fs/promises";
|
|
182538
|
-
|
|
182539
|
-
// ../../node_modules/wsl-utils/index.js
|
|
182540
|
-
import { promisify as promisify2 } from "node:util";
|
|
182541
|
-
import childProcess2 from "node:child_process";
|
|
182542
|
-
import fs6, { constants as fsConstants } from "node:fs/promises";
|
|
182543
|
-
|
|
182544
|
-
// ../../node_modules/is-wsl/index.js
|
|
182545
|
-
import process2 from "node:process";
|
|
182546
|
-
import os2 from "node:os";
|
|
182547
|
-
import fs5 from "node:fs";
|
|
182548
|
-
|
|
182549
|
-
// ../../node_modules/is-inside-container/index.js
|
|
182550
|
-
import fs4 from "node:fs";
|
|
182551
|
-
|
|
182552
|
-
// ../../node_modules/is-docker/index.js
|
|
182553
|
-
import fs3 from "node:fs";
|
|
182554
|
-
var isDockerCached;
|
|
182555
|
-
function hasDockerEnv() {
|
|
182556
|
-
try {
|
|
182557
|
-
fs3.statSync("/.dockerenv");
|
|
182558
|
-
return true;
|
|
182559
|
-
} catch {
|
|
182560
|
-
return false;
|
|
182561
|
-
}
|
|
182562
|
-
}
|
|
182563
|
-
function hasDockerCGroup() {
|
|
182564
|
-
try {
|
|
182565
|
-
return fs3.readFileSync("/proc/self/cgroup", "utf8").includes("docker");
|
|
182566
|
-
} catch {
|
|
182567
|
-
return false;
|
|
182568
|
-
}
|
|
182569
|
-
}
|
|
182570
|
-
function isDocker() {
|
|
182571
|
-
if (isDockerCached === void 0) {
|
|
182572
|
-
isDockerCached = hasDockerEnv() || hasDockerCGroup();
|
|
182573
|
-
}
|
|
182574
|
-
return isDockerCached;
|
|
182575
|
-
}
|
|
182576
|
-
|
|
182577
|
-
// ../../node_modules/is-inside-container/index.js
|
|
182578
|
-
var cachedResult;
|
|
182579
|
-
var hasContainerEnv = () => {
|
|
182580
|
-
try {
|
|
182581
|
-
fs4.statSync("/run/.containerenv");
|
|
182582
|
-
return true;
|
|
182583
|
-
} catch {
|
|
182584
|
-
return false;
|
|
182585
|
-
}
|
|
182586
|
-
};
|
|
182587
|
-
function isInsideContainer() {
|
|
182588
|
-
if (cachedResult === void 0) {
|
|
182589
|
-
cachedResult = hasContainerEnv() || isDocker();
|
|
182590
|
-
}
|
|
182591
|
-
return cachedResult;
|
|
182592
|
-
}
|
|
182593
|
-
|
|
182594
|
-
// ../../node_modules/is-wsl/index.js
|
|
182595
|
-
var isWsl = () => {
|
|
182596
|
-
if (process2.platform !== "linux") {
|
|
182597
|
-
return false;
|
|
182598
|
-
}
|
|
182599
|
-
if (os2.release().toLowerCase().includes("microsoft")) {
|
|
182600
|
-
if (isInsideContainer()) {
|
|
182601
|
-
return false;
|
|
182602
|
-
}
|
|
182603
|
-
return true;
|
|
182604
|
-
}
|
|
182605
|
-
try {
|
|
182606
|
-
return fs5.readFileSync("/proc/version", "utf8").toLowerCase().includes("microsoft") ? !isInsideContainer() : false;
|
|
182607
|
-
} catch {
|
|
182608
|
-
return false;
|
|
182609
|
-
}
|
|
182610
|
-
};
|
|
182611
|
-
var is_wsl_default = process2.env.__IS_WSL_TEST__ ? isWsl : isWsl();
|
|
182612
|
-
|
|
182613
|
-
// ../../node_modules/powershell-utils/index.js
|
|
182614
|
-
import process3 from "node:process";
|
|
182615
|
-
import { Buffer as Buffer2 } from "node:buffer";
|
|
182616
|
-
import { promisify } from "node:util";
|
|
182617
|
-
import childProcess from "node:child_process";
|
|
182618
|
-
var execFile = promisify(childProcess.execFile);
|
|
182619
|
-
var powerShellPath = () => `${process3.env.SYSTEMROOT || process3.env.windir || String.raw`C:\Windows`}\\System32\\WindowsPowerShell\\v1.0\\powershell.exe`;
|
|
182620
|
-
var executePowerShell = async (command, options2 = {}) => {
|
|
182621
|
-
const {
|
|
182622
|
-
powerShellPath: psPath,
|
|
182623
|
-
...execFileOptions
|
|
182624
|
-
} = options2;
|
|
182625
|
-
const encodedCommand = executePowerShell.encodeCommand(command);
|
|
182626
|
-
return execFile(
|
|
182627
|
-
psPath ?? powerShellPath(),
|
|
182628
|
-
[
|
|
182629
|
-
...executePowerShell.argumentsPrefix,
|
|
182630
|
-
encodedCommand
|
|
182631
|
-
],
|
|
182632
|
-
{
|
|
182633
|
-
encoding: "utf8",
|
|
182634
|
-
...execFileOptions
|
|
182635
|
-
}
|
|
182636
|
-
);
|
|
182637
|
-
};
|
|
182638
|
-
executePowerShell.argumentsPrefix = [
|
|
182639
|
-
"-NoProfile",
|
|
182640
|
-
"-NonInteractive",
|
|
182641
|
-
"-ExecutionPolicy",
|
|
182642
|
-
"Bypass",
|
|
182643
|
-
"-EncodedCommand"
|
|
182644
|
-
];
|
|
182645
|
-
executePowerShell.encodeCommand = (command) => Buffer2.from(command, "utf16le").toString("base64");
|
|
182646
|
-
executePowerShell.escapeArgument = (value) => `'${String(value).replaceAll("'", "''")}'`;
|
|
182647
|
-
|
|
182648
|
-
// ../../node_modules/wsl-utils/utilities.js
|
|
182649
|
-
function parseMountPointFromConfig(content) {
|
|
182650
|
-
for (const line of content.split("\n")) {
|
|
182651
|
-
if (/^\s*#/.test(line)) {
|
|
182652
|
-
continue;
|
|
182653
|
-
}
|
|
182654
|
-
const match = /^\s*root\s*=\s*(?<mountPoint>"[^"]*"|'[^']*'|[^#]*)/.exec(line);
|
|
182655
|
-
if (!match) {
|
|
182656
|
-
continue;
|
|
182657
|
-
}
|
|
182658
|
-
return match.groups.mountPoint.trim().replaceAll(/^["']|["']$/g, "");
|
|
182659
|
-
}
|
|
182660
|
-
}
|
|
182661
|
-
|
|
182662
|
-
// ../../node_modules/wsl-utils/index.js
|
|
182663
|
-
var execFile2 = promisify2(childProcess2.execFile);
|
|
182664
|
-
var wslDrivesMountPoint = /* @__PURE__ */ (() => {
|
|
182665
|
-
const defaultMountPoint = "/mnt/";
|
|
182666
|
-
let mountPoint;
|
|
182667
|
-
return async function() {
|
|
182668
|
-
if (mountPoint) {
|
|
182669
|
-
return mountPoint;
|
|
182670
|
-
}
|
|
182671
|
-
const configFilePath = "/etc/wsl.conf";
|
|
182672
|
-
let isConfigFileExists = false;
|
|
182673
|
-
try {
|
|
182674
|
-
await fs6.access(configFilePath, fsConstants.F_OK);
|
|
182675
|
-
isConfigFileExists = true;
|
|
182676
|
-
} catch {
|
|
182677
|
-
}
|
|
182678
|
-
if (!isConfigFileExists) {
|
|
182679
|
-
return defaultMountPoint;
|
|
182680
|
-
}
|
|
182681
|
-
const configContent = await fs6.readFile(configFilePath, { encoding: "utf8" });
|
|
182682
|
-
const parsedMountPoint = parseMountPointFromConfig(configContent);
|
|
182683
|
-
if (parsedMountPoint === void 0) {
|
|
182684
|
-
return defaultMountPoint;
|
|
182685
|
-
}
|
|
182686
|
-
mountPoint = parsedMountPoint;
|
|
182687
|
-
mountPoint = mountPoint.endsWith("/") ? mountPoint : `${mountPoint}/`;
|
|
182688
|
-
return mountPoint;
|
|
182689
|
-
};
|
|
182690
|
-
})();
|
|
182691
|
-
var powerShellPathFromWsl = async () => {
|
|
182692
|
-
const mountPoint = await wslDrivesMountPoint();
|
|
182693
|
-
return `${mountPoint}c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe`;
|
|
182694
|
-
};
|
|
182695
|
-
var powerShellPath2 = is_wsl_default ? powerShellPathFromWsl : powerShellPath;
|
|
182696
|
-
var canAccessPowerShellPromise;
|
|
182697
|
-
var canAccessPowerShell = async () => {
|
|
182698
|
-
canAccessPowerShellPromise ??= (async () => {
|
|
182699
|
-
try {
|
|
182700
|
-
const psPath = await powerShellPath2();
|
|
182701
|
-
await fs6.access(psPath, fsConstants.X_OK);
|
|
182702
|
-
return true;
|
|
182703
|
-
} catch {
|
|
182704
|
-
return false;
|
|
182705
|
-
}
|
|
182706
|
-
})();
|
|
182707
|
-
return canAccessPowerShellPromise;
|
|
182708
|
-
};
|
|
182709
|
-
var wslDefaultBrowser = async () => {
|
|
182710
|
-
const psPath = await powerShellPath2();
|
|
182711
|
-
const command = String.raw`(Get-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\http\UserChoice").ProgId`;
|
|
182712
|
-
const { stdout } = await executePowerShell(command, { powerShellPath: psPath });
|
|
182713
|
-
return stdout.trim();
|
|
182714
|
-
};
|
|
182715
|
-
var convertWslPathToWindows = async (path22) => {
|
|
182716
|
-
if (/^[a-z]+:\/\//i.test(path22)) {
|
|
182717
|
-
return path22;
|
|
182718
|
-
}
|
|
182719
|
-
try {
|
|
182720
|
-
const { stdout } = await execFile2("wslpath", ["-aw", path22], { encoding: "utf8" });
|
|
182721
|
-
return stdout.trim();
|
|
182722
|
-
} catch {
|
|
182723
|
-
return path22;
|
|
182724
|
-
}
|
|
182725
|
-
};
|
|
182726
|
-
|
|
182727
|
-
// ../../node_modules/define-lazy-prop/index.js
|
|
182728
|
-
function defineLazyProperty(object, propertyName, valueGetter) {
|
|
182729
|
-
const define = (value) => Object.defineProperty(object, propertyName, { value, enumerable: true, writable: true });
|
|
182730
|
-
Object.defineProperty(object, propertyName, {
|
|
182731
|
-
configurable: true,
|
|
182732
|
-
enumerable: true,
|
|
182733
|
-
get() {
|
|
182734
|
-
const result = valueGetter();
|
|
182735
|
-
define(result);
|
|
182736
|
-
return result;
|
|
182737
|
-
},
|
|
182738
|
-
set(value) {
|
|
182739
|
-
define(value);
|
|
182740
|
-
}
|
|
182741
|
-
});
|
|
182742
|
-
return object;
|
|
182743
|
-
}
|
|
182744
|
-
|
|
182745
|
-
// ../../node_modules/default-browser/index.js
|
|
182746
|
-
import { promisify as promisify6 } from "node:util";
|
|
182747
|
-
import process6 from "node:process";
|
|
182748
|
-
import { execFile as execFile6 } from "node:child_process";
|
|
182749
|
-
|
|
182750
|
-
// ../../node_modules/default-browser-id/index.js
|
|
182751
|
-
import { promisify as promisify3 } from "node:util";
|
|
182752
|
-
import process4 from "node:process";
|
|
182753
|
-
import { execFile as execFile3 } from "node:child_process";
|
|
182754
|
-
var execFileAsync = promisify3(execFile3);
|
|
182755
|
-
async function defaultBrowserId() {
|
|
182756
|
-
if (process4.platform !== "darwin") {
|
|
182757
|
-
throw new Error("macOS only");
|
|
182758
|
-
}
|
|
182759
|
-
const { stdout } = await execFileAsync("defaults", ["read", "com.apple.LaunchServices/com.apple.launchservices.secure", "LSHandlers"]);
|
|
182760
|
-
const match = /LSHandlerRoleAll = "(?!-)(?<id>[^"]+?)";\s+?LSHandlerURLScheme = (?:http|https);/.exec(stdout);
|
|
182761
|
-
const browserId = match?.groups.id ?? "com.apple.Safari";
|
|
182762
|
-
if (browserId === "com.apple.safari") {
|
|
182763
|
-
return "com.apple.Safari";
|
|
182764
|
-
}
|
|
182765
|
-
return browserId;
|
|
182766
|
-
}
|
|
182767
|
-
|
|
182768
|
-
// ../../node_modules/run-applescript/index.js
|
|
182769
|
-
import process5 from "node:process";
|
|
182770
|
-
import { promisify as promisify4 } from "node:util";
|
|
182771
|
-
import { execFile as execFile4, execFileSync } from "node:child_process";
|
|
182772
|
-
var execFileAsync2 = promisify4(execFile4);
|
|
182773
|
-
async function runAppleScript(script, { humanReadableOutput = true, signal } = {}) {
|
|
182774
|
-
if (process5.platform !== "darwin") {
|
|
182775
|
-
throw new Error("macOS only");
|
|
182776
|
-
}
|
|
182777
|
-
const outputArguments = humanReadableOutput ? [] : ["-ss"];
|
|
182778
|
-
const execOptions = {};
|
|
182779
|
-
if (signal) {
|
|
182780
|
-
execOptions.signal = signal;
|
|
182781
|
-
}
|
|
182782
|
-
const { stdout } = await execFileAsync2("osascript", ["-e", script, outputArguments], execOptions);
|
|
182783
|
-
return stdout.trim();
|
|
182784
|
-
}
|
|
182785
|
-
|
|
182786
|
-
// ../../node_modules/bundle-name/index.js
|
|
182787
|
-
async function bundleName(bundleId) {
|
|
182788
|
-
return runAppleScript(`tell application "Finder" to set app_path to application file id "${bundleId}" as string
|
|
182789
|
-
tell application "System Events" to get value of property list item "CFBundleName" of property list file (app_path & ":Contents:Info.plist")`);
|
|
182790
|
-
}
|
|
182791
|
-
|
|
182792
|
-
// ../../node_modules/default-browser/windows.js
|
|
182793
|
-
import { promisify as promisify5 } from "node:util";
|
|
182794
|
-
import { execFile as execFile5 } from "node:child_process";
|
|
182795
|
-
var execFileAsync3 = promisify5(execFile5);
|
|
182796
|
-
var windowsBrowserProgIds = {
|
|
182797
|
-
MSEdgeHTM: { name: "Edge", id: "com.microsoft.edge" },
|
|
182798
|
-
// The missing `L` is correct.
|
|
182799
|
-
MSEdgeBHTML: { name: "Edge Beta", id: "com.microsoft.edge.beta" },
|
|
182800
|
-
MSEdgeDHTML: { name: "Edge Dev", id: "com.microsoft.edge.dev" },
|
|
182801
|
-
AppXq0fevzme2pys62n3e0fbqa7peapykr8v: { name: "Edge", id: "com.microsoft.edge.old" },
|
|
182802
|
-
ChromeHTML: { name: "Chrome", id: "com.google.chrome" },
|
|
182803
|
-
ChromeBHTML: { name: "Chrome Beta", id: "com.google.chrome.beta" },
|
|
182804
|
-
ChromeDHTML: { name: "Chrome Dev", id: "com.google.chrome.dev" },
|
|
182805
|
-
ChromiumHTM: { name: "Chromium", id: "org.chromium.Chromium" },
|
|
182806
|
-
BraveHTML: { name: "Brave", id: "com.brave.Browser" },
|
|
182807
|
-
BraveBHTML: { name: "Brave Beta", id: "com.brave.Browser.beta" },
|
|
182808
|
-
BraveDHTML: { name: "Brave Dev", id: "com.brave.Browser.dev" },
|
|
182809
|
-
BraveSSHTM: { name: "Brave Nightly", id: "com.brave.Browser.nightly" },
|
|
182810
|
-
FirefoxURL: { name: "Firefox", id: "org.mozilla.firefox" },
|
|
182811
|
-
OperaStable: { name: "Opera", id: "com.operasoftware.Opera" },
|
|
182812
|
-
VivaldiHTM: { name: "Vivaldi", id: "com.vivaldi.Vivaldi" },
|
|
182813
|
-
"IE.HTTP": { name: "Internet Explorer", id: "com.microsoft.ie" }
|
|
182814
|
-
};
|
|
182815
|
-
var _windowsBrowserProgIdMap = new Map(Object.entries(windowsBrowserProgIds));
|
|
182816
|
-
var UnknownBrowserError = class extends Error {
|
|
182817
|
-
};
|
|
182818
|
-
async function defaultBrowser(_execFileAsync = execFileAsync3) {
|
|
182819
|
-
const { stdout } = await _execFileAsync("reg", [
|
|
182820
|
-
"QUERY",
|
|
182821
|
-
" HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\http\\UserChoice",
|
|
182822
|
-
"/v",
|
|
182823
|
-
"ProgId"
|
|
182824
|
-
]);
|
|
182825
|
-
const match = /ProgId\s*REG_SZ\s*(?<id>\S+)/.exec(stdout);
|
|
182826
|
-
if (!match) {
|
|
182827
|
-
throw new UnknownBrowserError(`Cannot find Windows browser in stdout: ${JSON.stringify(stdout)}`);
|
|
182828
|
-
}
|
|
182829
|
-
const { id } = match.groups;
|
|
182830
|
-
const browser = windowsBrowserProgIds[id];
|
|
182831
|
-
if (!browser) {
|
|
182832
|
-
throw new UnknownBrowserError(`Unknown browser ID: ${id}`);
|
|
182833
|
-
}
|
|
182834
|
-
return browser;
|
|
182835
|
-
}
|
|
182836
|
-
|
|
182837
|
-
// ../../node_modules/default-browser/index.js
|
|
182838
|
-
var execFileAsync4 = promisify6(execFile6);
|
|
182839
|
-
var titleize = (string) => string.toLowerCase().replaceAll(/(?:^|\s|-)\S/g, (x) => x.toUpperCase());
|
|
182840
|
-
async function defaultBrowser2() {
|
|
182841
|
-
if (process6.platform === "darwin") {
|
|
182842
|
-
const id = await defaultBrowserId();
|
|
182843
|
-
const name = await bundleName(id);
|
|
182844
|
-
return { name, id };
|
|
182845
|
-
}
|
|
182846
|
-
if (process6.platform === "linux") {
|
|
182847
|
-
const { stdout } = await execFileAsync4("xdg-mime", ["query", "default", "x-scheme-handler/http"]);
|
|
182848
|
-
const id = stdout.trim();
|
|
182849
|
-
const name = titleize(id.replace(/.desktop$/, "").replace("-", " "));
|
|
182850
|
-
return { name, id };
|
|
182851
|
-
}
|
|
182852
|
-
if (process6.platform === "win32") {
|
|
182853
|
-
return defaultBrowser();
|
|
182854
|
-
}
|
|
182855
|
-
throw new Error("Only macOS, Linux, and Windows are supported");
|
|
182856
|
-
}
|
|
182857
|
-
|
|
182858
|
-
// ../../node_modules/is-in-ssh/index.js
|
|
182859
|
-
import process7 from "node:process";
|
|
182860
|
-
var isInSsh = Boolean(process7.env.SSH_CONNECTION || process7.env.SSH_CLIENT || process7.env.SSH_TTY);
|
|
182861
|
-
var is_in_ssh_default = isInSsh;
|
|
182862
|
-
|
|
182863
|
-
// ../../node_modules/open/index.js
|
|
182864
|
-
var fallbackAttemptSymbol = Symbol("fallbackAttempt");
|
|
182865
|
-
var __dirname = import.meta.url ? path3.dirname(fileURLToPath(import.meta.url)) : "";
|
|
182866
|
-
var localXdgOpenPath = path3.join(__dirname, "xdg-open");
|
|
182867
|
-
var { platform: platform2, arch } = process8;
|
|
182868
|
-
var tryEachApp = async (apps2, opener) => {
|
|
182869
|
-
if (apps2.length === 0) {
|
|
182870
|
-
return;
|
|
182871
|
-
}
|
|
182872
|
-
const errors = [];
|
|
182873
|
-
for (const app of apps2) {
|
|
182874
|
-
try {
|
|
182875
|
-
return await opener(app);
|
|
182876
|
-
} catch (error) {
|
|
182877
|
-
errors.push(error);
|
|
182878
|
-
}
|
|
182879
|
-
}
|
|
182880
|
-
throw new AggregateError(errors, "Failed to open in all supported apps");
|
|
182881
|
-
};
|
|
182882
|
-
var baseOpen = async (options2) => {
|
|
182883
|
-
options2 = {
|
|
182884
|
-
wait: false,
|
|
182885
|
-
background: false,
|
|
182886
|
-
newInstance: false,
|
|
182887
|
-
allowNonzeroExitCode: false,
|
|
182888
|
-
...options2
|
|
182889
|
-
};
|
|
182890
|
-
const isFallbackAttempt = options2[fallbackAttemptSymbol] === true;
|
|
182891
|
-
delete options2[fallbackAttemptSymbol];
|
|
182892
|
-
if (Array.isArray(options2.app)) {
|
|
182893
|
-
return tryEachApp(options2.app, (singleApp) => baseOpen({
|
|
182894
|
-
...options2,
|
|
182895
|
-
app: singleApp,
|
|
182896
|
-
[fallbackAttemptSymbol]: true
|
|
182897
|
-
}));
|
|
182898
|
-
}
|
|
182899
|
-
let { name: app, arguments: appArguments = [] } = options2.app ?? {};
|
|
182900
|
-
appArguments = [...appArguments];
|
|
182901
|
-
if (Array.isArray(app)) {
|
|
182902
|
-
return tryEachApp(app, (appName) => baseOpen({
|
|
182903
|
-
...options2,
|
|
182904
|
-
app: {
|
|
182905
|
-
name: appName,
|
|
182906
|
-
arguments: appArguments
|
|
182907
|
-
},
|
|
182908
|
-
[fallbackAttemptSymbol]: true
|
|
182909
|
-
}));
|
|
182910
|
-
}
|
|
182911
|
-
if (app === "browser" || app === "browserPrivate") {
|
|
182912
|
-
const ids = {
|
|
182913
|
-
"com.google.chrome": "chrome",
|
|
182914
|
-
"google-chrome.desktop": "chrome",
|
|
182915
|
-
"com.brave.browser": "brave",
|
|
182916
|
-
"org.mozilla.firefox": "firefox",
|
|
182917
|
-
"firefox.desktop": "firefox",
|
|
182918
|
-
"com.microsoft.msedge": "edge",
|
|
182919
|
-
"com.microsoft.edge": "edge",
|
|
182920
|
-
"com.microsoft.edgemac": "edge",
|
|
182921
|
-
"microsoft-edge.desktop": "edge",
|
|
182922
|
-
"com.apple.safari": "safari"
|
|
182923
|
-
};
|
|
182924
|
-
const flags = {
|
|
182925
|
-
chrome: "--incognito",
|
|
182926
|
-
brave: "--incognito",
|
|
182927
|
-
firefox: "--private-window",
|
|
182928
|
-
edge: "--inPrivate"
|
|
182929
|
-
// Safari doesn't support private mode via command line
|
|
182930
|
-
};
|
|
182931
|
-
let browser;
|
|
182932
|
-
if (is_wsl_default) {
|
|
182933
|
-
const progId = await wslDefaultBrowser();
|
|
182934
|
-
const browserInfo = _windowsBrowserProgIdMap.get(progId);
|
|
182935
|
-
browser = browserInfo ?? {};
|
|
182936
|
-
} else {
|
|
182937
|
-
browser = await defaultBrowser2();
|
|
182938
|
-
}
|
|
182939
|
-
if (browser.id in ids) {
|
|
182940
|
-
const browserName = ids[browser.id.toLowerCase()];
|
|
182941
|
-
if (app === "browserPrivate") {
|
|
182942
|
-
if (browserName === "safari") {
|
|
182943
|
-
throw new Error("Safari doesn't support opening in private mode via command line");
|
|
182944
|
-
}
|
|
182945
|
-
appArguments.push(flags[browserName]);
|
|
182946
|
-
}
|
|
182947
|
-
return baseOpen({
|
|
182948
|
-
...options2,
|
|
182949
|
-
app: {
|
|
182950
|
-
name: apps[browserName],
|
|
182951
|
-
arguments: appArguments
|
|
182952
|
-
}
|
|
182953
|
-
});
|
|
182954
|
-
}
|
|
182955
|
-
throw new Error(`${browser.name} is not supported as a default browser`);
|
|
182956
|
-
}
|
|
182957
|
-
let command;
|
|
182958
|
-
const cliArguments = [];
|
|
182959
|
-
const childProcessOptions = {};
|
|
182960
|
-
let shouldUseWindowsInWsl = false;
|
|
182961
|
-
if (is_wsl_default && !isInsideContainer() && !is_in_ssh_default && !app) {
|
|
182962
|
-
shouldUseWindowsInWsl = await canAccessPowerShell();
|
|
182963
|
-
}
|
|
182964
|
-
if (platform2 === "darwin") {
|
|
182965
|
-
command = "open";
|
|
182966
|
-
if (options2.wait) {
|
|
182967
|
-
cliArguments.push("--wait-apps");
|
|
182968
|
-
}
|
|
182969
|
-
if (options2.background) {
|
|
182970
|
-
cliArguments.push("--background");
|
|
182971
|
-
}
|
|
182972
|
-
if (options2.newInstance) {
|
|
182973
|
-
cliArguments.push("--new");
|
|
182974
|
-
}
|
|
182975
|
-
if (app) {
|
|
182976
|
-
cliArguments.push("-a", app);
|
|
182977
|
-
}
|
|
182978
|
-
} else if (platform2 === "win32" || shouldUseWindowsInWsl) {
|
|
182979
|
-
command = await powerShellPath2();
|
|
182980
|
-
cliArguments.push(...executePowerShell.argumentsPrefix);
|
|
182981
|
-
if (!is_wsl_default) {
|
|
182982
|
-
childProcessOptions.windowsVerbatimArguments = true;
|
|
182983
|
-
}
|
|
182984
|
-
if (is_wsl_default && options2.target) {
|
|
182985
|
-
options2.target = await convertWslPathToWindows(options2.target);
|
|
182986
|
-
}
|
|
182987
|
-
const encodedArguments = ["$ProgressPreference = 'SilentlyContinue';", "Start"];
|
|
182988
|
-
if (options2.wait) {
|
|
182989
|
-
encodedArguments.push("-Wait");
|
|
182990
|
-
}
|
|
182991
|
-
if (app) {
|
|
182992
|
-
encodedArguments.push(executePowerShell.escapeArgument(app));
|
|
182993
|
-
if (options2.target) {
|
|
182994
|
-
appArguments.push(options2.target);
|
|
182995
|
-
}
|
|
182996
|
-
} else if (options2.target) {
|
|
182997
|
-
encodedArguments.push(executePowerShell.escapeArgument(options2.target));
|
|
182998
|
-
}
|
|
182999
|
-
if (appArguments.length > 0) {
|
|
183000
|
-
appArguments = appArguments.map((argument) => executePowerShell.escapeArgument(argument));
|
|
183001
|
-
encodedArguments.push("-ArgumentList", appArguments.join(","));
|
|
183002
|
-
}
|
|
183003
|
-
options2.target = executePowerShell.encodeCommand(encodedArguments.join(" "));
|
|
183004
|
-
if (!options2.wait) {
|
|
183005
|
-
childProcessOptions.stdio = "ignore";
|
|
183006
|
-
}
|
|
183007
|
-
} else {
|
|
183008
|
-
if (app) {
|
|
183009
|
-
command = app;
|
|
183010
|
-
} else {
|
|
183011
|
-
const isBundled = !__dirname || __dirname === "/";
|
|
183012
|
-
let exeLocalXdgOpen = false;
|
|
183013
|
-
try {
|
|
183014
|
-
await fs7.access(localXdgOpenPath, fsConstants2.X_OK);
|
|
183015
|
-
exeLocalXdgOpen = true;
|
|
183016
|
-
} catch {
|
|
183017
|
-
}
|
|
183018
|
-
const useSystemXdgOpen = process8.versions.electron ?? (platform2 === "android" || isBundled || !exeLocalXdgOpen);
|
|
183019
|
-
command = useSystemXdgOpen ? "xdg-open" : localXdgOpenPath;
|
|
183020
|
-
}
|
|
183021
|
-
if (appArguments.length > 0) {
|
|
183022
|
-
cliArguments.push(...appArguments);
|
|
183023
|
-
}
|
|
183024
|
-
if (!options2.wait) {
|
|
183025
|
-
childProcessOptions.stdio = "ignore";
|
|
183026
|
-
childProcessOptions.detached = true;
|
|
183027
|
-
}
|
|
183028
|
-
}
|
|
183029
|
-
if (platform2 === "darwin" && appArguments.length > 0) {
|
|
183030
|
-
cliArguments.push("--args", ...appArguments);
|
|
183031
|
-
}
|
|
183032
|
-
if (options2.target) {
|
|
183033
|
-
cliArguments.push(options2.target);
|
|
183034
|
-
}
|
|
183035
|
-
const subprocess = childProcess3.spawn(command, cliArguments, childProcessOptions);
|
|
183036
|
-
if (options2.wait) {
|
|
183037
|
-
return new Promise((resolve7, reject) => {
|
|
183038
|
-
subprocess.once("error", reject);
|
|
183039
|
-
subprocess.once("close", (exitCode) => {
|
|
183040
|
-
if (!options2.allowNonzeroExitCode && exitCode !== 0) {
|
|
183041
|
-
reject(new Error(`Exited with code ${exitCode}`));
|
|
183042
|
-
return;
|
|
183043
|
-
}
|
|
183044
|
-
resolve7(subprocess);
|
|
183045
|
-
});
|
|
183046
|
-
});
|
|
183047
|
-
}
|
|
183048
|
-
if (isFallbackAttempt) {
|
|
183049
|
-
return new Promise((resolve7, reject) => {
|
|
183050
|
-
subprocess.once("error", reject);
|
|
183051
|
-
subprocess.once("spawn", () => {
|
|
183052
|
-
subprocess.once("close", (exitCode) => {
|
|
183053
|
-
subprocess.off("error", reject);
|
|
183054
|
-
if (exitCode !== 0) {
|
|
183055
|
-
reject(new Error(`Exited with code ${exitCode}`));
|
|
183056
|
-
return;
|
|
183057
|
-
}
|
|
183058
|
-
subprocess.unref();
|
|
183059
|
-
resolve7(subprocess);
|
|
183060
|
-
});
|
|
183061
|
-
});
|
|
183062
|
-
});
|
|
183063
|
-
}
|
|
183064
|
-
subprocess.unref();
|
|
183065
|
-
return new Promise((resolve7, reject) => {
|
|
183066
|
-
subprocess.once("error", reject);
|
|
183067
|
-
subprocess.once("spawn", () => {
|
|
183068
|
-
subprocess.off("error", reject);
|
|
183069
|
-
resolve7(subprocess);
|
|
183070
|
-
});
|
|
183071
|
-
});
|
|
183072
|
-
};
|
|
183073
|
-
var open = (target, options2) => {
|
|
183074
|
-
if (typeof target !== "string") {
|
|
183075
|
-
throw new TypeError("Expected a `target`");
|
|
183076
|
-
}
|
|
183077
|
-
return baseOpen({
|
|
183078
|
-
...options2,
|
|
183079
|
-
target
|
|
183080
|
-
});
|
|
183081
|
-
};
|
|
183082
|
-
function detectArchBinary(binary) {
|
|
183083
|
-
if (typeof binary === "string" || Array.isArray(binary)) {
|
|
183084
|
-
return binary;
|
|
183085
|
-
}
|
|
183086
|
-
const { [arch]: archBinary } = binary;
|
|
183087
|
-
if (!archBinary) {
|
|
183088
|
-
throw new Error(`${arch} is not supported`);
|
|
183089
|
-
}
|
|
183090
|
-
return archBinary;
|
|
183091
|
-
}
|
|
183092
|
-
function detectPlatformBinary({ [platform2]: platformBinary }, { wsl } = {}) {
|
|
183093
|
-
if (wsl && is_wsl_default) {
|
|
183094
|
-
return detectArchBinary(wsl);
|
|
183095
|
-
}
|
|
183096
|
-
if (!platformBinary) {
|
|
183097
|
-
throw new Error(`${platform2} is not supported`);
|
|
183098
|
-
}
|
|
183099
|
-
return detectArchBinary(platformBinary);
|
|
183100
|
-
}
|
|
183101
|
-
var apps = {
|
|
183102
|
-
browser: "browser",
|
|
183103
|
-
browserPrivate: "browserPrivate"
|
|
183104
|
-
};
|
|
183105
|
-
defineLazyProperty(apps, "chrome", () => detectPlatformBinary({
|
|
183106
|
-
darwin: "google chrome",
|
|
183107
|
-
win32: "chrome",
|
|
183108
|
-
// `chromium-browser` is the older deb package name used by Ubuntu/Debian before snap.
|
|
183109
|
-
linux: ["google-chrome", "google-chrome-stable", "chromium", "chromium-browser"]
|
|
183110
|
-
}, {
|
|
183111
|
-
wsl: {
|
|
183112
|
-
ia32: "/mnt/c/Program Files (x86)/Google/Chrome/Application/chrome.exe",
|
|
183113
|
-
x64: ["/mnt/c/Program Files/Google/Chrome/Application/chrome.exe", "/mnt/c/Program Files (x86)/Google/Chrome/Application/chrome.exe"]
|
|
183114
|
-
}
|
|
183115
|
-
}));
|
|
183116
|
-
defineLazyProperty(apps, "brave", () => detectPlatformBinary({
|
|
183117
|
-
darwin: "brave browser",
|
|
183118
|
-
win32: "brave",
|
|
183119
|
-
linux: ["brave-browser", "brave"]
|
|
183120
|
-
}, {
|
|
183121
|
-
wsl: {
|
|
183122
|
-
ia32: "/mnt/c/Program Files (x86)/BraveSoftware/Brave-Browser/Application/brave.exe",
|
|
183123
|
-
x64: ["/mnt/c/Program Files/BraveSoftware/Brave-Browser/Application/brave.exe", "/mnt/c/Program Files (x86)/BraveSoftware/Brave-Browser/Application/brave.exe"]
|
|
183124
|
-
}
|
|
183125
|
-
}));
|
|
183126
|
-
defineLazyProperty(apps, "firefox", () => detectPlatformBinary({
|
|
183127
|
-
darwin: "firefox",
|
|
183128
|
-
win32: String.raw`C:\Program Files\Mozilla Firefox\firefox.exe`,
|
|
183129
|
-
linux: "firefox"
|
|
183130
|
-
}, {
|
|
183131
|
-
wsl: "/mnt/c/Program Files/Mozilla Firefox/firefox.exe"
|
|
183132
|
-
}));
|
|
183133
|
-
defineLazyProperty(apps, "edge", () => detectPlatformBinary({
|
|
183134
|
-
darwin: "microsoft edge",
|
|
183135
|
-
win32: "msedge",
|
|
183136
|
-
linux: ["microsoft-edge", "microsoft-edge-dev"]
|
|
183137
|
-
}, {
|
|
183138
|
-
wsl: "/mnt/c/Program Files (x86)/Microsoft/Edge/Application/msedge.exe"
|
|
183139
|
-
}));
|
|
183140
|
-
defineLazyProperty(apps, "safari", () => detectPlatformBinary({
|
|
183141
|
-
darwin: "Safari"
|
|
183142
|
-
}));
|
|
183143
|
-
var open_default = open;
|
|
183144
|
-
|
|
183145
183245
|
// src/lib/dev/debug-logger.ts
|
|
183146
|
-
import * as
|
|
183147
|
-
import * as
|
|
183246
|
+
import * as fs3 from "fs";
|
|
183247
|
+
import * as os2 from "os";
|
|
183248
|
+
import * as path3 from "path";
|
|
183148
183249
|
var DEBUG_LOG_PATH = ".specific/debug.log";
|
|
183149
183250
|
var logStream = null;
|
|
183150
|
-
function getLogStream() {
|
|
183151
|
-
if (logStream) {
|
|
183152
|
-
return logStream;
|
|
183153
|
-
}
|
|
183154
|
-
const logPath = path4.join(process.cwd(), DEBUG_LOG_PATH);
|
|
183155
|
-
fs8.mkdirSync(path4.dirname(logPath), { recursive: true });
|
|
183156
|
-
logStream = fs8.createWriteStream(logPath, { flags: "a" });
|
|
183157
|
-
return logStream;
|
|
183158
|
-
}
|
|
183159
183251
|
function writeLog(source, message) {
|
|
183160
|
-
const
|
|
183252
|
+
const logPath = path3.join(os2.homedir(), DEBUG_LOG_PATH);
|
|
183253
|
+
fs3.mkdirSync(path3.dirname(logPath), { recursive: true });
|
|
183161
183254
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
183162
183255
|
const line = message.endsWith("\n") ? message : message + "\n";
|
|
183163
|
-
|
|
183256
|
+
fs3.appendFileSync(logPath, `[${timestamp}] [${source}] ${line}`);
|
|
183164
183257
|
}
|
|
183165
183258
|
function pipeProcess(source, proc) {
|
|
183166
183259
|
proc.stdout?.on("data", (data) => {
|
|
@@ -183471,127 +183564,169 @@ var ApiClient = class {
|
|
|
183471
183564
|
}
|
|
183472
183565
|
};
|
|
183473
183566
|
|
|
183567
|
+
// src/lib/auth/login-flow.ts
|
|
183568
|
+
function runLoginFlow(options2) {
|
|
183569
|
+
const { setState, isReauthentication } = options2;
|
|
183570
|
+
let cancelled = false;
|
|
183571
|
+
async function run() {
|
|
183572
|
+
try {
|
|
183573
|
+
setState({ phase: "initiating" });
|
|
183574
|
+
writeLog("auth", "Starting login flow");
|
|
183575
|
+
if (isReauthentication) {
|
|
183576
|
+
clearUserCredentials();
|
|
183577
|
+
}
|
|
183578
|
+
writeLog("auth", "Initiating device authorization with WorkOS");
|
|
183579
|
+
const deviceAuth = await initiateDeviceAuthorization();
|
|
183580
|
+
writeLog(
|
|
183581
|
+
"auth",
|
|
183582
|
+
`Device authorization received: user_code=${deviceAuth.user_code}`
|
|
183583
|
+
);
|
|
183584
|
+
if (cancelled) return;
|
|
183585
|
+
setState({
|
|
183586
|
+
phase: "waiting-for-browser",
|
|
183587
|
+
userCode: deviceAuth.user_code,
|
|
183588
|
+
verificationUri: deviceAuth.verification_uri_complete
|
|
183589
|
+
});
|
|
183590
|
+
const { default: open3 } = await Promise.resolve().then(() => (init_open(), open_exports));
|
|
183591
|
+
await open3(deviceAuth.verification_uri_complete);
|
|
183592
|
+
const token = await pollUntilToken(deviceAuth, () => cancelled);
|
|
183593
|
+
if (cancelled || !token) return;
|
|
183594
|
+
writeLog("auth", "Fetching user info from platform API...");
|
|
183595
|
+
const client2 = new ApiClient(token.access_token);
|
|
183596
|
+
const user = await client2.getMe();
|
|
183597
|
+
writeLog("auth", `User info received: id=${user.id}`);
|
|
183598
|
+
if (cancelled) return;
|
|
183599
|
+
writeLog("auth", "Writing credentials to disk...");
|
|
183600
|
+
writeUserCredentials({
|
|
183601
|
+
accessToken: token.access_token,
|
|
183602
|
+
refreshToken: token.refresh_token,
|
|
183603
|
+
expiresAt: Date.now() + token.expires_in * 1e3,
|
|
183604
|
+
userId: user.id
|
|
183605
|
+
});
|
|
183606
|
+
writeLog("auth", "Credentials written successfully");
|
|
183607
|
+
setState({ phase: "success", email: token.user.email });
|
|
183608
|
+
writeLog("auth", "Login flow completed successfully");
|
|
183609
|
+
} catch (err) {
|
|
183610
|
+
if (cancelled) return;
|
|
183611
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
183612
|
+
writeLog("auth", `Login error: ${message}`);
|
|
183613
|
+
setState({ phase: "error", message });
|
|
183614
|
+
}
|
|
183615
|
+
}
|
|
183616
|
+
run();
|
|
183617
|
+
return {
|
|
183618
|
+
cancel: () => {
|
|
183619
|
+
cancelled = true;
|
|
183620
|
+
}
|
|
183621
|
+
};
|
|
183622
|
+
}
|
|
183623
|
+
async function pollUntilToken(deviceAuth, isCancelled) {
|
|
183624
|
+
let interval = deviceAuth.interval * 1e3;
|
|
183625
|
+
const expiresAt = Date.now() + deviceAuth.expires_in * 1e3;
|
|
183626
|
+
while (!isCancelled() && Date.now() < expiresAt) {
|
|
183627
|
+
await sleep(interval);
|
|
183628
|
+
if (isCancelled()) return null;
|
|
183629
|
+
writeLog(
|
|
183630
|
+
"auth",
|
|
183631
|
+
`Polling for token (timeRemaining=${Math.round((expiresAt - Date.now()) / 1e3)}s)`
|
|
183632
|
+
);
|
|
183633
|
+
const response = await pollForToken(deviceAuth.device_code);
|
|
183634
|
+
writeLog(
|
|
183635
|
+
"auth",
|
|
183636
|
+
`Poll response: ${JSON.stringify(response).substring(0, 200)}`
|
|
183637
|
+
);
|
|
183638
|
+
if (!("error" in response)) {
|
|
183639
|
+
writeLog("auth", "Token received successfully from WorkOS");
|
|
183640
|
+
return response;
|
|
183641
|
+
}
|
|
183642
|
+
if (response.error === "slow_down") {
|
|
183643
|
+
interval += 1e3;
|
|
183644
|
+
writeLog("auth", `Slowing down, new interval: ${interval}ms`);
|
|
183645
|
+
} else if (response.error !== "authorization_pending") {
|
|
183646
|
+
throw new Error(`Authentication failed: ${response.error}`);
|
|
183647
|
+
}
|
|
183648
|
+
}
|
|
183649
|
+
if (!isCancelled()) {
|
|
183650
|
+
throw new Error("Authentication timed out. Please try again.");
|
|
183651
|
+
}
|
|
183652
|
+
return null;
|
|
183653
|
+
}
|
|
183654
|
+
function sleep(ms) {
|
|
183655
|
+
return new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
183656
|
+
}
|
|
183657
|
+
|
|
183474
183658
|
// src/lib/auth/login.tsx
|
|
183659
|
+
function LoginUI({
|
|
183660
|
+
state,
|
|
183661
|
+
isReauthentication
|
|
183662
|
+
}) {
|
|
183663
|
+
if (state.phase === "error") {
|
|
183664
|
+
return /* @__PURE__ */ React.createElement(Text, { color: "red" }, "Error: ", state.message);
|
|
183665
|
+
}
|
|
183666
|
+
if (state.phase === "success") {
|
|
183667
|
+
return /* @__PURE__ */ React.createElement(Text, { color: "green" }, isReauthentication ? "Re-authenticated" : "Logged in", " as ", state.email);
|
|
183668
|
+
}
|
|
183669
|
+
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", gap: 1 }, isReauthentication && /* @__PURE__ */ React.createElement(Text, { color: "yellow" }, "Session expired. Please log in again."), /* @__PURE__ */ React.createElement(Text, { bold: true }, "Log in to Specific"), state.phase === "waiting-for-browser" ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Box, { flexDirection: "column" }, /* @__PURE__ */ React.createElement(Text, null, "Your authentication code:", " ", /* @__PURE__ */ React.createElement(Text, { color: "cyan", bold: true }, state.userCode))), /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: "blue" }, /* @__PURE__ */ React.createElement(Spinner, { type: "dots" })), /* @__PURE__ */ React.createElement(Text, null, " Waiting for authentication in browser...")), /* @__PURE__ */ React.createElement(Text, { dimColor: true }, "If the browser didn't open, visit: ", state.verificationUri)) : /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: "blue" }, /* @__PURE__ */ React.createElement(Spinner, { type: "dots" })), /* @__PURE__ */ React.createElement(Text, null, " Initiating login...")));
|
|
183670
|
+
}
|
|
183475
183671
|
function performLogin(options2 = {}) {
|
|
183476
183672
|
return new Promise((resolve7) => {
|
|
183673
|
+
let currentState = { phase: "initiating" };
|
|
183674
|
+
let flowHandle;
|
|
183477
183675
|
const instance = render(
|
|
183478
183676
|
/* @__PURE__ */ React.createElement(
|
|
183479
|
-
|
|
183677
|
+
LoginUI,
|
|
183480
183678
|
{
|
|
183481
|
-
|
|
183482
|
-
|
|
183483
|
-
instance.unmount();
|
|
183484
|
-
resolve7(result);
|
|
183485
|
-
}
|
|
183679
|
+
state: currentState,
|
|
183680
|
+
isReauthentication: options2.isReauthentication
|
|
183486
183681
|
}
|
|
183487
183682
|
)
|
|
183488
183683
|
);
|
|
183489
|
-
|
|
183490
|
-
|
|
183491
|
-
|
|
183492
|
-
|
|
183493
|
-
|
|
183494
|
-
|
|
183495
|
-
|
|
183496
|
-
|
|
183497
|
-
|
|
183498
|
-
|
|
183499
|
-
|
|
183500
|
-
|
|
183501
|
-
|
|
183502
|
-
|
|
183503
|
-
|
|
183504
|
-
|
|
183505
|
-
|
|
183506
|
-
|
|
183507
|
-
|
|
183508
|
-
|
|
183509
|
-
setUserCode(deviceAuth.user_code);
|
|
183510
|
-
setVerificationUri(deviceAuth.verification_uri_complete);
|
|
183511
|
-
setPhase("waiting");
|
|
183512
|
-
await open_default(deviceAuth.verification_uri_complete);
|
|
183513
|
-
let pollInterval = deviceAuth.interval * 1e3;
|
|
183514
|
-
const expiresAt = Date.now() + deviceAuth.expires_in * 1e3;
|
|
183515
|
-
const poll = async () => {
|
|
183516
|
-
if (cancelled || Date.now() > expiresAt) {
|
|
183517
|
-
if (!cancelled && Date.now() > expiresAt) {
|
|
183518
|
-
setError("Authentication timed out. Please try again.");
|
|
183519
|
-
setPhase("error");
|
|
183520
|
-
}
|
|
183521
|
-
return;
|
|
183522
|
-
}
|
|
183523
|
-
try {
|
|
183524
|
-
const response = await pollForToken(deviceAuth.device_code);
|
|
183525
|
-
if (cancelled) return;
|
|
183526
|
-
if ("error" in response) {
|
|
183527
|
-
if (response.error === "authorization_pending") {
|
|
183528
|
-
pollTimeoutId = setTimeout(poll, pollInterval);
|
|
183529
|
-
} else if (response.error === "slow_down") {
|
|
183530
|
-
pollInterval += 1e3;
|
|
183531
|
-
pollTimeoutId = setTimeout(poll, pollInterval);
|
|
183532
|
-
} else {
|
|
183533
|
-
setError(`Authentication failed: ${response.error}`);
|
|
183534
|
-
setPhase("error");
|
|
183535
|
-
}
|
|
183536
|
-
} else {
|
|
183537
|
-
const successResponse = response;
|
|
183538
|
-
const expiresAt2 = Date.now() + successResponse.expires_in * 1e3;
|
|
183539
|
-
const client2 = new ApiClient(successResponse.access_token);
|
|
183540
|
-
const user = await client2.getMe();
|
|
183541
|
-
writeUserCredentials({
|
|
183542
|
-
accessToken: successResponse.access_token,
|
|
183543
|
-
refreshToken: successResponse.refresh_token,
|
|
183544
|
-
expiresAt: expiresAt2,
|
|
183545
|
-
userId: user.id
|
|
183546
|
-
});
|
|
183547
|
-
setUserEmail(successResponse.user.email);
|
|
183548
|
-
setPhase("success");
|
|
183684
|
+
const cleanup = () => {
|
|
183685
|
+
flowHandle?.cancel();
|
|
183686
|
+
instance.unmount();
|
|
183687
|
+
};
|
|
183688
|
+
const handleExit = () => {
|
|
183689
|
+
cleanup();
|
|
183690
|
+
process.exit(0);
|
|
183691
|
+
};
|
|
183692
|
+
process.on("SIGINT", handleExit);
|
|
183693
|
+
process.on("SIGTERM", handleExit);
|
|
183694
|
+
flowHandle = runLoginFlow({
|
|
183695
|
+
isReauthentication: options2.isReauthentication,
|
|
183696
|
+
setState: (newState) => {
|
|
183697
|
+
currentState = newState;
|
|
183698
|
+
instance.rerender(
|
|
183699
|
+
/* @__PURE__ */ React.createElement(
|
|
183700
|
+
LoginUI,
|
|
183701
|
+
{
|
|
183702
|
+
state: currentState,
|
|
183703
|
+
isReauthentication: options2.isReauthentication
|
|
183549
183704
|
}
|
|
183550
|
-
|
|
183551
|
-
|
|
183552
|
-
|
|
183553
|
-
|
|
183554
|
-
|
|
183555
|
-
|
|
183556
|
-
|
|
183557
|
-
|
|
183558
|
-
|
|
183559
|
-
|
|
183560
|
-
|
|
183705
|
+
)
|
|
183706
|
+
);
|
|
183707
|
+
if (newState.phase === "success") {
|
|
183708
|
+
setTimeout(() => {
|
|
183709
|
+
process.off("SIGINT", handleExit);
|
|
183710
|
+
process.off("SIGTERM", handleExit);
|
|
183711
|
+
instance.unmount();
|
|
183712
|
+
resolve7({ success: true, userEmail: newState.email });
|
|
183713
|
+
}, 100);
|
|
183714
|
+
} else if (newState.phase === "error") {
|
|
183715
|
+
setTimeout(() => {
|
|
183716
|
+
process.off("SIGINT", handleExit);
|
|
183717
|
+
process.off("SIGTERM", handleExit);
|
|
183718
|
+
instance.unmount();
|
|
183719
|
+
resolve7({ success: false, error: new Error(newState.message) });
|
|
183720
|
+
}, 100);
|
|
183721
|
+
}
|
|
183561
183722
|
}
|
|
183562
|
-
}
|
|
183563
|
-
|
|
183564
|
-
return () => {
|
|
183565
|
-
cancelled = true;
|
|
183566
|
-
if (pollTimeoutId) clearTimeout(pollTimeoutId);
|
|
183567
|
-
};
|
|
183568
|
-
}, [phase, isReauthentication]);
|
|
183569
|
-
useEffect(() => {
|
|
183570
|
-
if (phase === "success") {
|
|
183571
|
-
const timer = setTimeout(() => {
|
|
183572
|
-
onComplete({ success: true, userEmail });
|
|
183573
|
-
}, 100);
|
|
183574
|
-
return () => clearTimeout(timer);
|
|
183575
|
-
}
|
|
183576
|
-
if (phase === "error") {
|
|
183577
|
-
const timer = setTimeout(() => {
|
|
183578
|
-
onComplete({ success: false, error: new Error(error) });
|
|
183579
|
-
}, 100);
|
|
183580
|
-
return () => clearTimeout(timer);
|
|
183581
|
-
}
|
|
183582
|
-
}, [phase, userEmail, error, onComplete]);
|
|
183583
|
-
if (phase === "error") {
|
|
183584
|
-
return /* @__PURE__ */ React.createElement(Text, { color: "red" }, "Error: ", error);
|
|
183585
|
-
}
|
|
183586
|
-
if (phase === "success") {
|
|
183587
|
-
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column" }, /* @__PURE__ */ React.createElement(Text, { color: "green" }, isReauthentication ? "Re-authenticated" : "Logged in", " as ", userEmail), /* @__PURE__ */ React.createElement(Text, { dimColor: true }, "Credentials saved to ~/.specific/credentials.json"));
|
|
183588
|
-
}
|
|
183589
|
-
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", gap: 1 }, isReauthentication && /* @__PURE__ */ React.createElement(Text, { color: "yellow" }, "Session expired. Please log in again."), /* @__PURE__ */ React.createElement(Text, { bold: true }, "Log in to Specific"), userCode ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Box, { flexDirection: "column" }, /* @__PURE__ */ React.createElement(Text, null, "Your authentication code:", " ", /* @__PURE__ */ React.createElement(Text, { color: "cyan", bold: true }, userCode))), /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: "blue" }, /* @__PURE__ */ React.createElement(Spinner, { type: "dots" })), /* @__PURE__ */ React.createElement(Text, null, " Waiting for authentication in browser...")), /* @__PURE__ */ React.createElement(Text, { dimColor: true }, "If the browser didn't open, visit: ", verificationUri)) : /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: "blue" }, /* @__PURE__ */ React.createElement(Spinner, { type: "dots" })), /* @__PURE__ */ React.createElement(Text, null, " Initiating login...")));
|
|
183723
|
+
});
|
|
183724
|
+
});
|
|
183590
183725
|
}
|
|
183591
183726
|
|
|
183592
183727
|
// src/lib/auth/credentials.ts
|
|
183593
183728
|
function getUserCredentialsDir() {
|
|
183594
|
-
return path5.join(
|
|
183729
|
+
return path5.join(os4.homedir(), ".specific");
|
|
183595
183730
|
}
|
|
183596
183731
|
function getCredentialsPath() {
|
|
183597
183732
|
return path5.join(getUserCredentialsDir(), "credentials.json");
|
|
@@ -183675,7 +183810,7 @@ function isEnabled() {
|
|
|
183675
183810
|
}
|
|
183676
183811
|
function getAnonymousId() {
|
|
183677
183812
|
if (anonymousId) return anonymousId;
|
|
183678
|
-
const machineId = `${
|
|
183813
|
+
const machineId = `${os5.hostname()}-${os5.userInfo().username}`;
|
|
183679
183814
|
anonymousId = crypto.createHash("sha256").update(machineId).digest("hex").slice(0, 16);
|
|
183680
183815
|
return anonymousId;
|
|
183681
183816
|
}
|
|
@@ -183708,7 +183843,7 @@ function trackEvent(event, properties) {
|
|
|
183708
183843
|
event,
|
|
183709
183844
|
properties: {
|
|
183710
183845
|
...properties,
|
|
183711
|
-
cli_version: "0.1.
|
|
183846
|
+
cli_version: "0.1.44",
|
|
183712
183847
|
platform: process.platform,
|
|
183713
183848
|
node_version: process.version,
|
|
183714
183849
|
project_id: getProjectId(),
|
|
@@ -183776,7 +183911,7 @@ function appendOrCreateFile(filePath, content) {
|
|
|
183776
183911
|
}
|
|
183777
183912
|
function addToGitignore() {
|
|
183778
183913
|
const gitignorePath = path6.join(process.cwd(), ".gitignore");
|
|
183779
|
-
const entries = [".specific", "specific.
|
|
183914
|
+
const entries = [".specific", "specific.local"];
|
|
183780
183915
|
if (fs10.existsSync(gitignorePath)) {
|
|
183781
183916
|
const existing = fs10.readFileSync(gitignorePath, "utf-8");
|
|
183782
183917
|
const lines = existing.split("\n").map((l) => l.trim());
|
|
@@ -183889,8 +184024,8 @@ function configureAgents(checked) {
|
|
|
183889
184024
|
return { agents, git, showManualInstructions: !!checked["other"] };
|
|
183890
184025
|
}
|
|
183891
184026
|
function InitUI() {
|
|
183892
|
-
const { exit } =
|
|
183893
|
-
const [initialState] =
|
|
184027
|
+
const { exit } = useApp();
|
|
184028
|
+
const [initialState] = useState(() => {
|
|
183894
184029
|
const detected = detectExistingAgents();
|
|
183895
184030
|
const hasDetected = Object.keys(detected).length > 0;
|
|
183896
184031
|
return {
|
|
@@ -183899,19 +184034,19 @@ function InitUI() {
|
|
|
183899
184034
|
// Focus submit if any detected
|
|
183900
184035
|
};
|
|
183901
184036
|
});
|
|
183902
|
-
const [phase, setPhase] =
|
|
184037
|
+
const [phase, setPhase] = useState(
|
|
183903
184038
|
() => caFilesExist() ? "agents" : "installing-ca"
|
|
183904
184039
|
);
|
|
183905
|
-
const [caInstallPhase, setCaInstallPhase] =
|
|
183906
|
-
const [focusedIndex, setFocusedIndex] =
|
|
183907
|
-
const [checked, setChecked] =
|
|
184040
|
+
const [caInstallPhase, setCaInstallPhase] = useState(() => caFilesExist() ? "done" : "installing");
|
|
184041
|
+
const [focusedIndex, setFocusedIndex] = useState(initialState.focusedIndex);
|
|
184042
|
+
const [checked, setChecked] = useState(
|
|
183908
184043
|
initialState.detected
|
|
183909
184044
|
);
|
|
183910
|
-
const [result, setResult] =
|
|
183911
|
-
const [tlsResult, setTlsResult] =
|
|
184045
|
+
const [result, setResult] = useState(null);
|
|
184046
|
+
const [tlsResult, setTlsResult] = useState(
|
|
183912
184047
|
caFilesExist() ? { status: "success" } : null
|
|
183913
184048
|
);
|
|
183914
|
-
|
|
184049
|
+
useEffect(() => {
|
|
183915
184050
|
if (phase === "installing-ca" && caInstallPhase === "installing") {
|
|
183916
184051
|
installCA();
|
|
183917
184052
|
}
|
|
@@ -183956,7 +184091,7 @@ function InitUI() {
|
|
|
183956
184091
|
setPhase("done");
|
|
183957
184092
|
}
|
|
183958
184093
|
});
|
|
183959
|
-
|
|
184094
|
+
useEffect(() => {
|
|
183960
184095
|
if (phase === "done") {
|
|
183961
184096
|
const timer = setTimeout(() => {
|
|
183962
184097
|
exit();
|
|
@@ -184031,13 +184166,13 @@ function resolveDocPath(path22) {
|
|
|
184031
184166
|
}
|
|
184032
184167
|
|
|
184033
184168
|
// src/commands/check.tsx
|
|
184034
|
-
import React3, { useState as
|
|
184169
|
+
import React3, { useState as useState2, useEffect as useEffect2 } from "react";
|
|
184035
184170
|
import { render as render3, Text as Text3, Box as Box3 } from "ink";
|
|
184036
184171
|
import Spinner3 from "ink-spinner";
|
|
184037
184172
|
import * as fs11 from "fs";
|
|
184038
184173
|
import * as path7 from "path";
|
|
184039
184174
|
|
|
184040
|
-
//
|
|
184175
|
+
// node_modules/.pnpm/@specific+config@file+..+config/node_modules/@specific/config/dist/parser.js
|
|
184041
184176
|
var import_hcl2_json_parser = __toESM(require_dist(), 1);
|
|
184042
184177
|
var { parseToObject } = import_hcl2_json_parser.default;
|
|
184043
184178
|
function parseReference(value) {
|
|
@@ -184369,6 +184504,22 @@ function parseStorage(data) {
|
|
|
184369
184504
|
}
|
|
184370
184505
|
return result;
|
|
184371
184506
|
}
|
|
184507
|
+
function parseConfigDevBlock(dev) {
|
|
184508
|
+
if (!dev) {
|
|
184509
|
+
return void 0;
|
|
184510
|
+
}
|
|
184511
|
+
const devArray = Array.isArray(dev) ? dev : [dev];
|
|
184512
|
+
const devObj = devArray[0];
|
|
184513
|
+
if (!devObj || typeof devObj !== "object" || Array.isArray(devObj)) {
|
|
184514
|
+
return void 0;
|
|
184515
|
+
}
|
|
184516
|
+
const fieldObj = devObj;
|
|
184517
|
+
const result = {};
|
|
184518
|
+
if (fieldObj.default !== void 0) {
|
|
184519
|
+
result.default = String(fieldObj.default);
|
|
184520
|
+
}
|
|
184521
|
+
return Object.keys(result).length > 0 ? result : void 0;
|
|
184522
|
+
}
|
|
184372
184523
|
function parseConfigs(configData) {
|
|
184373
184524
|
if (!configData || typeof configData !== "object" || Array.isArray(configData)) {
|
|
184374
184525
|
return [];
|
|
@@ -184377,6 +184528,7 @@ function parseConfigs(configData) {
|
|
|
184377
184528
|
for (const [name, fieldsArray] of Object.entries(configData)) {
|
|
184378
184529
|
const fields = Array.isArray(fieldsArray) ? fieldsArray[0] : fieldsArray;
|
|
184379
184530
|
if (!fields || typeof fields !== "object" || Array.isArray(fields)) {
|
|
184531
|
+
configs.push({ name });
|
|
184380
184532
|
continue;
|
|
184381
184533
|
}
|
|
184382
184534
|
const fieldObj = fields;
|
|
@@ -184384,10 +184536,30 @@ function parseConfigs(configData) {
|
|
|
184384
184536
|
if (fieldObj.default) {
|
|
184385
184537
|
config.default = String(fieldObj.default);
|
|
184386
184538
|
}
|
|
184539
|
+
const dev = parseConfigDevBlock(fieldObj.dev);
|
|
184540
|
+
if (dev) {
|
|
184541
|
+
config.dev = dev;
|
|
184542
|
+
}
|
|
184387
184543
|
configs.push(config);
|
|
184388
184544
|
}
|
|
184389
184545
|
return configs;
|
|
184390
184546
|
}
|
|
184547
|
+
function parseSecretDevBlock(dev) {
|
|
184548
|
+
if (!dev) {
|
|
184549
|
+
return void 0;
|
|
184550
|
+
}
|
|
184551
|
+
const devArray = Array.isArray(dev) ? dev : [dev];
|
|
184552
|
+
const devObj = devArray[0];
|
|
184553
|
+
if (!devObj || typeof devObj !== "object" || Array.isArray(devObj)) {
|
|
184554
|
+
return void 0;
|
|
184555
|
+
}
|
|
184556
|
+
const fieldObj = devObj;
|
|
184557
|
+
const result = {};
|
|
184558
|
+
if (fieldObj.required !== void 0) {
|
|
184559
|
+
result.required = fieldObj.required === true;
|
|
184560
|
+
}
|
|
184561
|
+
return Object.keys(result).length > 0 ? result : void 0;
|
|
184562
|
+
}
|
|
184391
184563
|
function parseSecrets(secretData) {
|
|
184392
184564
|
if (!secretData || typeof secretData !== "object" || Array.isArray(secretData)) {
|
|
184393
184565
|
return [];
|
|
@@ -184404,6 +184576,10 @@ function parseSecrets(secretData) {
|
|
|
184404
184576
|
if (typeof fieldObj.length === "number") {
|
|
184405
184577
|
secret.length = fieldObj.length;
|
|
184406
184578
|
}
|
|
184579
|
+
const dev = parseSecretDevBlock(fieldObj.dev);
|
|
184580
|
+
if (dev) {
|
|
184581
|
+
secret.dev = dev;
|
|
184582
|
+
}
|
|
184407
184583
|
}
|
|
184408
184584
|
secrets.push(secret);
|
|
184409
184585
|
}
|
|
@@ -184517,8 +184693,8 @@ function validateEndpointReferences(config) {
|
|
|
184517
184693
|
|
|
184518
184694
|
// src/commands/check.tsx
|
|
184519
184695
|
function CheckUI() {
|
|
184520
|
-
const [state, setState] =
|
|
184521
|
-
|
|
184696
|
+
const [state, setState] = useState2({ status: "loading" });
|
|
184697
|
+
useEffect2(() => {
|
|
184522
184698
|
async function load() {
|
|
184523
184699
|
const configPath = path7.join(process.cwd(), "specific.hcl");
|
|
184524
184700
|
if (!fs11.existsSync(configPath)) {
|
|
@@ -184558,19 +184734,19 @@ function checkCommand() {
|
|
|
184558
184734
|
}
|
|
184559
184735
|
|
|
184560
184736
|
// src/commands/dev.tsx
|
|
184561
|
-
import
|
|
184562
|
-
import { render as render4, Text as
|
|
184737
|
+
import React6, { useState as useState5, useEffect as useEffect3, useRef } from "react";
|
|
184738
|
+
import { render as render4, Text as Text6, Box as Box6, useApp as useApp2, Static } from "ink";
|
|
184563
184739
|
import Spinner4 from "ink-spinner";
|
|
184564
184740
|
import * as fs19 from "fs";
|
|
184565
184741
|
import * as path16 from "path";
|
|
184566
184742
|
|
|
184567
|
-
// node_modules/chokidar/index.js
|
|
184743
|
+
// node_modules/.pnpm/chokidar@5.0.0/node_modules/chokidar/index.js
|
|
184568
184744
|
import { EventEmitter } from "node:events";
|
|
184569
184745
|
import { stat as statcb, Stats } from "node:fs";
|
|
184570
184746
|
import { readdir as readdir2, stat as stat3 } from "node:fs/promises";
|
|
184571
184747
|
import * as sp2 from "node:path";
|
|
184572
184748
|
|
|
184573
|
-
// node_modules/readdirp/index.js
|
|
184749
|
+
// node_modules/.pnpm/readdirp@5.0.0/node_modules/readdirp/index.js
|
|
184574
184750
|
import { lstat, readdir, realpath, stat } from "node:fs/promises";
|
|
184575
184751
|
import { join as pjoin, relative as prelative, resolve as presolve, sep as psep } from "node:path";
|
|
184576
184752
|
import { Readable } from "node:stream";
|
|
@@ -184803,7 +184979,7 @@ function readdirp(root, options2 = {}) {
|
|
|
184803
184979
|
return new ReaddirpStream(options2);
|
|
184804
184980
|
}
|
|
184805
184981
|
|
|
184806
|
-
// node_modules/chokidar/handler.js
|
|
184982
|
+
// node_modules/.pnpm/chokidar@5.0.0/node_modules/chokidar/handler.js
|
|
184807
184983
|
import { watch as fs_watch, unwatchFile, watchFile } from "node:fs";
|
|
184808
184984
|
import { realpath as fsrealpath, lstat as lstat2, open as open2, stat as stat2 } from "node:fs/promises";
|
|
184809
184985
|
import { type as osType } from "node:os";
|
|
@@ -185562,7 +185738,7 @@ var NodeFsHandler = class {
|
|
|
185562
185738
|
}
|
|
185563
185739
|
};
|
|
185564
185740
|
|
|
185565
|
-
// node_modules/chokidar/index.js
|
|
185741
|
+
// node_modules/.pnpm/chokidar@5.0.0/node_modules/chokidar/index.js
|
|
185566
185742
|
var SLASH = "/";
|
|
185567
185743
|
var SLASH_SLASH = "//";
|
|
185568
185744
|
var ONE_DOT = ".";
|
|
@@ -186384,7 +186560,7 @@ var StablePortAllocator = class {
|
|
|
186384
186560
|
import * as fs14 from "fs";
|
|
186385
186561
|
import * as path10 from "path";
|
|
186386
186562
|
import * as net from "net";
|
|
186387
|
-
import * as
|
|
186563
|
+
import * as os7 from "os";
|
|
186388
186564
|
import { spawn } from "child_process";
|
|
186389
186565
|
|
|
186390
186566
|
// src/lib/bin/types.ts
|
|
@@ -186424,15 +186600,15 @@ var ExtractionError = class extends Error {
|
|
|
186424
186600
|
// src/lib/bin/manager.ts
|
|
186425
186601
|
import * as fs13 from "fs";
|
|
186426
186602
|
import * as path9 from "path";
|
|
186427
|
-
import * as
|
|
186603
|
+
import * as os6 from "os";
|
|
186428
186604
|
import { createReadStream } from "fs";
|
|
186429
186605
|
import { createTarExtractor, extractTo } from "tar-vern";
|
|
186430
186606
|
function getBinBaseDir() {
|
|
186431
|
-
return path9.join(
|
|
186607
|
+
return path9.join(os6.homedir(), ".specific", "bin");
|
|
186432
186608
|
}
|
|
186433
186609
|
function getPlatformInfo() {
|
|
186434
|
-
const platform5 =
|
|
186435
|
-
const arch3 =
|
|
186610
|
+
const platform5 = os6.platform();
|
|
186611
|
+
const arch3 = os6.arch();
|
|
186436
186612
|
if (platform5 !== "darwin" && platform5 !== "linux") {
|
|
186437
186613
|
throw new Error(
|
|
186438
186614
|
`Unsupported platform: ${platform5}. Only macOS and Linux are supported.`
|
|
@@ -186700,7 +186876,7 @@ function getLibraryEnv(binary) {
|
|
|
186700
186876
|
if (!binary.libraryPath) {
|
|
186701
186877
|
return {};
|
|
186702
186878
|
}
|
|
186703
|
-
const platform5 =
|
|
186879
|
+
const platform5 = os7.platform();
|
|
186704
186880
|
if (platform5 === "darwin") {
|
|
186705
186881
|
return { DYLD_LIBRARY_PATH: binary.libraryPath };
|
|
186706
186882
|
} else if (platform5 === "linux") {
|
|
@@ -186879,7 +187055,7 @@ async function waitForTcpPort(host, port, timeoutMs = 3e4) {
|
|
|
186879
187055
|
if (isOpen) {
|
|
186880
187056
|
return;
|
|
186881
187057
|
}
|
|
186882
|
-
await
|
|
187058
|
+
await sleep2(100);
|
|
186883
187059
|
}
|
|
186884
187060
|
throw new Error(`Port ${port} did not become available within timeout`);
|
|
186885
187061
|
}
|
|
@@ -186920,140 +187096,114 @@ async function stopProcess(proc) {
|
|
|
186920
187096
|
}, 2e3);
|
|
186921
187097
|
});
|
|
186922
187098
|
}
|
|
186923
|
-
function
|
|
187099
|
+
function sleep2(ms) {
|
|
186924
187100
|
return new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
186925
187101
|
}
|
|
186926
187102
|
|
|
186927
187103
|
// src/lib/dev/service-runner.ts
|
|
186928
187104
|
import { spawn as spawn2 } from "child_process";
|
|
186929
187105
|
|
|
186930
|
-
// src/lib/
|
|
187106
|
+
// src/lib/local/parser.ts
|
|
186931
187107
|
var import_hcl2_json_parser2 = __toESM(require_dist(), 1);
|
|
186932
|
-
import { readFile, writeFile
|
|
187108
|
+
import { readFile, writeFile } from "fs/promises";
|
|
186933
187109
|
import { existsSync as existsSync10 } from "fs";
|
|
186934
|
-
import * as path11 from "path";
|
|
186935
|
-
import * as crypto2 from "crypto";
|
|
186936
187110
|
var { parseToObject: parseToObject2 } = import_hcl2_json_parser2.default;
|
|
186937
|
-
var
|
|
186938
|
-
var
|
|
186939
|
-
|
|
187111
|
+
var LOCAL_FILE = "specific.local";
|
|
187112
|
+
var HEADER_COMMENT = `# Local secrets and configuration
|
|
187113
|
+
# Do not commit this file
|
|
187114
|
+
|
|
187115
|
+
`;
|
|
187116
|
+
async function parseLocalFile(content) {
|
|
186940
187117
|
const secrets = /* @__PURE__ */ new Map();
|
|
187118
|
+
const configs = /* @__PURE__ */ new Map();
|
|
186941
187119
|
if (!content.trim()) {
|
|
186942
|
-
return secrets;
|
|
187120
|
+
return { secrets, configs };
|
|
186943
187121
|
}
|
|
186944
187122
|
const parsed = await parseToObject2(content);
|
|
186945
|
-
|
|
186946
|
-
|
|
186947
|
-
|
|
187123
|
+
if (parsed.secrets) {
|
|
187124
|
+
const secretsBlocks = Array.isArray(parsed.secrets) ? parsed.secrets : [parsed.secrets];
|
|
187125
|
+
for (const block of secretsBlocks) {
|
|
187126
|
+
if (block && typeof block === "object") {
|
|
187127
|
+
for (const [key, value] of Object.entries(block)) {
|
|
187128
|
+
if (typeof value === "string") {
|
|
187129
|
+
secrets.set(key, value);
|
|
187130
|
+
}
|
|
187131
|
+
}
|
|
187132
|
+
}
|
|
186948
187133
|
}
|
|
186949
187134
|
}
|
|
186950
|
-
|
|
186951
|
-
|
|
186952
|
-
|
|
186953
|
-
|
|
186954
|
-
|
|
186955
|
-
|
|
186956
|
-
|
|
186957
|
-
|
|
186958
|
-
}
|
|
186959
|
-
|
|
186960
|
-
|
|
186961
|
-
const bytes = crypto2.randomBytes(length);
|
|
186962
|
-
let result = "";
|
|
186963
|
-
for (let i = 0; i < length; i++) {
|
|
186964
|
-
result += chars[bytes[i] % chars.length];
|
|
187135
|
+
if (parsed.config) {
|
|
187136
|
+
const configBlocks = Array.isArray(parsed.config) ? parsed.config : [parsed.config];
|
|
187137
|
+
for (const block of configBlocks) {
|
|
187138
|
+
if (block && typeof block === "object") {
|
|
187139
|
+
for (const [key, value] of Object.entries(block)) {
|
|
187140
|
+
if (typeof value === "string") {
|
|
187141
|
+
configs.set(key, value);
|
|
187142
|
+
}
|
|
187143
|
+
}
|
|
187144
|
+
}
|
|
187145
|
+
}
|
|
186965
187146
|
}
|
|
186966
|
-
return
|
|
187147
|
+
return { secrets, configs };
|
|
186967
187148
|
}
|
|
186968
|
-
async function
|
|
186969
|
-
if (!existsSync10(
|
|
186970
|
-
return /* @__PURE__ */ new Map();
|
|
187149
|
+
async function loadLocal() {
|
|
187150
|
+
if (!existsSync10(LOCAL_FILE)) {
|
|
187151
|
+
return { secrets: /* @__PURE__ */ new Map(), configs: /* @__PURE__ */ new Map() };
|
|
186971
187152
|
}
|
|
186972
|
-
const content = await readFile(
|
|
186973
|
-
|
|
186974
|
-
return new Map(Object.entries(parsed));
|
|
187153
|
+
const content = await readFile(LOCAL_FILE, "utf-8");
|
|
187154
|
+
return await parseLocalFile(content);
|
|
186975
187155
|
}
|
|
186976
|
-
|
|
186977
|
-
|
|
186978
|
-
if (existsSync10(GENERATED_SECRETS_FILE)) {
|
|
186979
|
-
const content = await readFile(GENERATED_SECRETS_FILE, "utf-8");
|
|
186980
|
-
secrets = JSON.parse(content);
|
|
186981
|
-
}
|
|
186982
|
-
secrets[name] = value;
|
|
186983
|
-
const dir = path11.dirname(GENERATED_SECRETS_FILE);
|
|
186984
|
-
if (!existsSync10(dir)) {
|
|
186985
|
-
await mkdir(dir, { recursive: true });
|
|
186986
|
-
}
|
|
186987
|
-
await writeFile(GENERATED_SECRETS_FILE, JSON.stringify(secrets, null, 2) + "\n");
|
|
187156
|
+
function escapeHclValue(value) {
|
|
187157
|
+
return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
186988
187158
|
}
|
|
186989
|
-
|
|
186990
|
-
const
|
|
186991
|
-
const
|
|
186992
|
-
const
|
|
186993
|
-
|
|
186994
|
-
|
|
186995
|
-
|
|
186996
|
-
|
|
186997
|
-
|
|
186998
|
-
|
|
186999
|
-
|
|
187000
|
-
|
|
187001
|
-
|
|
187002
|
-
|
|
187003
|
-
|
|
187004
|
-
|
|
187005
|
-
|
|
187159
|
+
function updateBlockValue(content, blockName, key, value) {
|
|
187160
|
+
const escapedValue = escapeHclValue(value);
|
|
187161
|
+
const newLine = ` ${key} = "${escapedValue}"`;
|
|
187162
|
+
const blockRegex = new RegExp(`(${blockName}\\s*\\{)([^}]*)(\\})`, "s");
|
|
187163
|
+
const blockMatch = content.match(blockRegex);
|
|
187164
|
+
if (blockMatch) {
|
|
187165
|
+
const blockContent = blockMatch[2];
|
|
187166
|
+
const keyRegex = new RegExp(`^(\\s*)${key}\\s*=\\s*"[^"]*"\\s*$`, "m");
|
|
187167
|
+
const keyMatch = blockContent.match(keyRegex);
|
|
187168
|
+
if (keyMatch) {
|
|
187169
|
+
const updatedBlockContent = blockContent.replace(keyRegex, newLine);
|
|
187170
|
+
return content.replace(blockRegex, `$1${updatedBlockContent}$3`);
|
|
187171
|
+
} else {
|
|
187172
|
+
const trimmedContent = blockContent.trimEnd();
|
|
187173
|
+
const newBlockContent = trimmedContent ? `${trimmedContent}
|
|
187174
|
+
${newLine}
|
|
187175
|
+
` : `
|
|
187176
|
+
${newLine}
|
|
187177
|
+
`;
|
|
187178
|
+
return content.replace(blockRegex, `$1${newBlockContent}$3`);
|
|
187006
187179
|
}
|
|
187007
|
-
}
|
|
187008
|
-
|
|
187180
|
+
} else {
|
|
187181
|
+
const newBlock = `${blockName} {
|
|
187182
|
+
${newLine}
|
|
187009
187183
|
}
|
|
187010
|
-
|
|
187011
|
-
|
|
187012
|
-
var import_hcl2_json_parser3 = __toESM(require_dist(), 1);
|
|
187013
|
-
import { readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
|
|
187014
|
-
import { existsSync as existsSync11 } from "fs";
|
|
187015
|
-
var { parseToObject: parseToObject3 } = import_hcl2_json_parser3.default;
|
|
187016
|
-
var CONFIG_FILE = "specific.config";
|
|
187017
|
-
async function parseConfigFile(content) {
|
|
187018
|
-
const configs = /* @__PURE__ */ new Map();
|
|
187019
|
-
if (!content.trim()) {
|
|
187020
|
-
return configs;
|
|
187021
|
-
}
|
|
187022
|
-
const parsed = await parseToObject3(content);
|
|
187023
|
-
for (const [key, value] of Object.entries(parsed)) {
|
|
187024
|
-
if (typeof value === "string") {
|
|
187025
|
-
configs.set(key, value);
|
|
187026
|
-
}
|
|
187184
|
+
`;
|
|
187185
|
+
return content.trimEnd() + "\n\n" + newBlock;
|
|
187027
187186
|
}
|
|
187028
|
-
return configs;
|
|
187029
187187
|
}
|
|
187030
|
-
async function
|
|
187031
|
-
|
|
187032
|
-
|
|
187188
|
+
async function saveLocalSecret(name, value) {
|
|
187189
|
+
let content = "";
|
|
187190
|
+
if (existsSync10(LOCAL_FILE)) {
|
|
187191
|
+
content = await readFile(LOCAL_FILE, "utf-8");
|
|
187192
|
+
} else {
|
|
187193
|
+
content = HEADER_COMMENT;
|
|
187033
187194
|
}
|
|
187034
|
-
|
|
187035
|
-
|
|
187195
|
+
content = updateBlockValue(content, "secrets", name, value);
|
|
187196
|
+
await writeFile(LOCAL_FILE, content);
|
|
187036
187197
|
}
|
|
187037
|
-
async function
|
|
187038
|
-
|
|
187039
|
-
|
|
187040
|
-
|
|
187041
|
-
|
|
187042
|
-
|
|
187043
|
-
finalConfigs.set(configDef.name, userValue);
|
|
187044
|
-
continue;
|
|
187045
|
-
}
|
|
187046
|
-
const envOverride = environmentOverrides?.[configDef.name];
|
|
187047
|
-
if (envOverride !== void 0) {
|
|
187048
|
-
finalConfigs.set(configDef.name, envOverride);
|
|
187049
|
-
continue;
|
|
187050
|
-
}
|
|
187051
|
-
if (configDef.default !== void 0) {
|
|
187052
|
-
finalConfigs.set(configDef.name, configDef.default);
|
|
187053
|
-
continue;
|
|
187054
|
-
}
|
|
187198
|
+
async function saveLocalConfig(name, value) {
|
|
187199
|
+
let content = "";
|
|
187200
|
+
if (existsSync10(LOCAL_FILE)) {
|
|
187201
|
+
content = await readFile(LOCAL_FILE, "utf-8");
|
|
187202
|
+
} else {
|
|
187203
|
+
content = HEADER_COMMENT;
|
|
187055
187204
|
}
|
|
187056
|
-
|
|
187205
|
+
content = updateBlockValue(content, "config", name, value);
|
|
187206
|
+
await writeFile(LOCAL_FILE, content);
|
|
187057
187207
|
}
|
|
187058
187208
|
|
|
187059
187209
|
// src/lib/dev/env-resolver.ts
|
|
@@ -187062,9 +187212,12 @@ var MissingSecretError = class extends Error {
|
|
|
187062
187212
|
super(
|
|
187063
187213
|
`Missing secret '${secretName}'
|
|
187064
187214
|
|
|
187065
|
-
This secret is declared in specific.hcl but has no value in ${
|
|
187215
|
+
This secret is declared in specific.hcl but has no value in ${LOCAL_FILE}.
|
|
187066
187216
|
|
|
187067
|
-
|
|
187217
|
+
Add it to the secrets block in ${LOCAL_FILE}:
|
|
187218
|
+
secrets {
|
|
187219
|
+
${secretName} = "your-value"
|
|
187220
|
+
}`
|
|
187068
187221
|
);
|
|
187069
187222
|
this.secretName = secretName;
|
|
187070
187223
|
this.name = "MissingSecretError";
|
|
@@ -187075,9 +187228,12 @@ var MissingConfigError = class extends Error {
|
|
|
187075
187228
|
super(
|
|
187076
187229
|
`Missing config '${configName}'
|
|
187077
187230
|
|
|
187078
|
-
This config is declared in specific.hcl but has no default value, environment override, or value in ${
|
|
187231
|
+
This config is declared in specific.hcl but has no default value, environment override, or value in ${LOCAL_FILE}.
|
|
187079
187232
|
|
|
187080
|
-
|
|
187233
|
+
Add it to the config block in ${LOCAL_FILE}:
|
|
187234
|
+
config {
|
|
187235
|
+
${configName} = "your-value"
|
|
187236
|
+
}`
|
|
187081
187237
|
);
|
|
187082
187238
|
this.configName = configName;
|
|
187083
187239
|
this.name = "MissingConfigError";
|
|
@@ -187124,7 +187280,7 @@ function resolveEnvValue(value, resources, secrets, configs, servicePort, servic
|
|
|
187124
187280
|
}
|
|
187125
187281
|
switch (serviceRef.attribute) {
|
|
187126
187282
|
case "url":
|
|
187127
|
-
return `
|
|
187283
|
+
return `localhost:${endpoint.port}`;
|
|
187128
187284
|
case "host":
|
|
187129
187285
|
return "localhost";
|
|
187130
187286
|
case "port":
|
|
@@ -187341,7 +187497,7 @@ function startService(service, resources, secrets, configs, endpointPorts, servi
|
|
|
187341
187497
|
|
|
187342
187498
|
// src/lib/dev/instance-state.ts
|
|
187343
187499
|
import * as fs15 from "fs";
|
|
187344
|
-
import * as
|
|
187500
|
+
import * as path11 from "path";
|
|
187345
187501
|
var InstanceStateManager = class {
|
|
187346
187502
|
stateDir;
|
|
187347
187503
|
statePath;
|
|
@@ -187350,9 +187506,9 @@ var InstanceStateManager = class {
|
|
|
187350
187506
|
key;
|
|
187351
187507
|
constructor(projectRoot, key = "default") {
|
|
187352
187508
|
this.key = key;
|
|
187353
|
-
this.stateDir =
|
|
187354
|
-
this.statePath =
|
|
187355
|
-
this.lockPath =
|
|
187509
|
+
this.stateDir = path11.join(projectRoot, ".specific", "keys", key);
|
|
187510
|
+
this.statePath = path11.join(this.stateDir, "state.json");
|
|
187511
|
+
this.lockPath = path11.join(this.stateDir, "state.lock");
|
|
187356
187512
|
}
|
|
187357
187513
|
getKey() {
|
|
187358
187514
|
return this.key;
|
|
@@ -187554,11 +187710,11 @@ var InstanceStateManager = class {
|
|
|
187554
187710
|
import * as http from "http";
|
|
187555
187711
|
import * as https from "https";
|
|
187556
187712
|
import * as fs16 from "fs";
|
|
187557
|
-
import * as
|
|
187713
|
+
import * as path12 from "path";
|
|
187558
187714
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
187559
187715
|
import httpProxy from "http-proxy";
|
|
187560
|
-
var __dirname3 =
|
|
187561
|
-
var adminDir =
|
|
187716
|
+
var __dirname3 = path12.dirname(fileURLToPath3(import.meta.url));
|
|
187717
|
+
var adminDir = path12.join(__dirname3, "admin");
|
|
187562
187718
|
var HTTP_PORT = 80;
|
|
187563
187719
|
var HTTPS_PORT = 443;
|
|
187564
187720
|
var DOMAIN_SUFFIX = ".local.spcf.app";
|
|
@@ -187844,9 +188000,9 @@ function serveStaticFile(res, pathname) {
|
|
|
187844
188000
|
filePath = filePath + "index.html";
|
|
187845
188001
|
}
|
|
187846
188002
|
const relativePath = filePath.startsWith("/") ? filePath.slice(1) : filePath;
|
|
187847
|
-
const fullPath =
|
|
187848
|
-
const resolvedPath =
|
|
187849
|
-
const resolvedAdminDir =
|
|
188003
|
+
const fullPath = path12.join(adminDir, relativePath);
|
|
188004
|
+
const resolvedPath = path12.resolve(fullPath);
|
|
188005
|
+
const resolvedAdminDir = path12.resolve(adminDir);
|
|
187850
188006
|
if (!resolvedPath.startsWith(resolvedAdminDir)) {
|
|
187851
188007
|
res.writeHead(403, { "Content-Type": "text/html" });
|
|
187852
188008
|
res.end("<h1>Forbidden</h1>");
|
|
@@ -187857,11 +188013,11 @@ function serveStaticFile(res, pathname) {
|
|
|
187857
188013
|
if (fs16.existsSync(htmlPath)) {
|
|
187858
188014
|
return serveFile(res, htmlPath);
|
|
187859
188015
|
}
|
|
187860
|
-
const indexPath =
|
|
188016
|
+
const indexPath = path12.join(resolvedPath, "index.html");
|
|
187861
188017
|
if (fs16.existsSync(indexPath)) {
|
|
187862
188018
|
return serveFile(res, indexPath);
|
|
187863
188019
|
}
|
|
187864
|
-
const notFoundPath =
|
|
188020
|
+
const notFoundPath = path12.join(adminDir, "404.html");
|
|
187865
188021
|
if (fs16.existsSync(notFoundPath)) {
|
|
187866
188022
|
return serveFileContent(res, notFoundPath, "text/html", 404);
|
|
187867
188023
|
}
|
|
@@ -187872,7 +188028,7 @@ function serveStaticFile(res, pathname) {
|
|
|
187872
188028
|
serveFile(res, resolvedPath);
|
|
187873
188029
|
}
|
|
187874
188030
|
function serveFile(res, filePath) {
|
|
187875
|
-
const ext =
|
|
188031
|
+
const ext = path12.extname(filePath).toLowerCase();
|
|
187876
188032
|
const contentType = MIME_TYPES[ext] || "application/octet-stream";
|
|
187877
188033
|
serveFileContent(res, filePath, contentType, 200);
|
|
187878
188034
|
}
|
|
@@ -187935,6 +188091,101 @@ async function startAdminServer(getState) {
|
|
|
187935
188091
|
// src/lib/dev/electric-manager.ts
|
|
187936
188092
|
import * as net2 from "net";
|
|
187937
188093
|
import { spawn as spawn3 } from "child_process";
|
|
188094
|
+
|
|
188095
|
+
// src/lib/secrets/parser.ts
|
|
188096
|
+
import { readFile as readFile2, writeFile as writeFile2, mkdir } from "fs/promises";
|
|
188097
|
+
import { existsSync as existsSync13 } from "fs";
|
|
188098
|
+
import * as path13 from "path";
|
|
188099
|
+
import * as crypto2 from "crypto";
|
|
188100
|
+
var GENERATED_SECRETS_FILE = ".specific/generated-secrets.json";
|
|
188101
|
+
async function loadSecrets() {
|
|
188102
|
+
const { secrets } = await loadLocal();
|
|
188103
|
+
return secrets;
|
|
188104
|
+
}
|
|
188105
|
+
function generateRandomString(length = 64) {
|
|
188106
|
+
const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
|
188107
|
+
const bytes = crypto2.randomBytes(length);
|
|
188108
|
+
let result = "";
|
|
188109
|
+
for (let i = 0; i < length; i++) {
|
|
188110
|
+
result += chars[bytes[i] % chars.length];
|
|
188111
|
+
}
|
|
188112
|
+
return result;
|
|
188113
|
+
}
|
|
188114
|
+
async function loadGeneratedSecrets() {
|
|
188115
|
+
if (!existsSync13(GENERATED_SECRETS_FILE)) {
|
|
188116
|
+
return /* @__PURE__ */ new Map();
|
|
188117
|
+
}
|
|
188118
|
+
const content = await readFile2(GENERATED_SECRETS_FILE, "utf-8");
|
|
188119
|
+
const parsed = JSON.parse(content);
|
|
188120
|
+
return new Map(Object.entries(parsed));
|
|
188121
|
+
}
|
|
188122
|
+
async function saveGeneratedSecret(name, value) {
|
|
188123
|
+
let secrets = {};
|
|
188124
|
+
if (existsSync13(GENERATED_SECRETS_FILE)) {
|
|
188125
|
+
const content = await readFile2(GENERATED_SECRETS_FILE, "utf-8");
|
|
188126
|
+
secrets = JSON.parse(content);
|
|
188127
|
+
}
|
|
188128
|
+
secrets[name] = value;
|
|
188129
|
+
const dir = path13.dirname(GENERATED_SECRETS_FILE);
|
|
188130
|
+
if (!existsSync13(dir)) {
|
|
188131
|
+
await mkdir(dir, { recursive: true });
|
|
188132
|
+
}
|
|
188133
|
+
await writeFile2(GENERATED_SECRETS_FILE, JSON.stringify(secrets, null, 2) + "\n");
|
|
188134
|
+
}
|
|
188135
|
+
async function prepareSecrets(secretsConfig, isDevMode = false) {
|
|
188136
|
+
const userSecrets = await loadSecrets();
|
|
188137
|
+
const generatedSecrets = await loadGeneratedSecrets();
|
|
188138
|
+
const finalSecrets = /* @__PURE__ */ new Map();
|
|
188139
|
+
for (const secretDef of secretsConfig) {
|
|
188140
|
+
const userValue = userSecrets.get(secretDef.name);
|
|
188141
|
+
if (userValue !== void 0) {
|
|
188142
|
+
finalSecrets.set(secretDef.name, userValue);
|
|
188143
|
+
continue;
|
|
188144
|
+
}
|
|
188145
|
+
if (secretDef.generated) {
|
|
188146
|
+
let generatedValue = generatedSecrets.get(secretDef.name);
|
|
188147
|
+
if (generatedValue === void 0) {
|
|
188148
|
+
generatedValue = generateRandomString(secretDef.length ?? 64);
|
|
188149
|
+
await saveGeneratedSecret(secretDef.name, generatedValue);
|
|
188150
|
+
}
|
|
188151
|
+
finalSecrets.set(secretDef.name, generatedValue);
|
|
188152
|
+
continue;
|
|
188153
|
+
}
|
|
188154
|
+
if (isDevMode && secretDef.dev?.required === false) {
|
|
188155
|
+
finalSecrets.set(secretDef.name, "");
|
|
188156
|
+
continue;
|
|
188157
|
+
}
|
|
188158
|
+
}
|
|
188159
|
+
return finalSecrets;
|
|
188160
|
+
}
|
|
188161
|
+
async function saveSecret(name, value) {
|
|
188162
|
+
await saveLocalSecret(name, value);
|
|
188163
|
+
}
|
|
188164
|
+
function findUsedSecrets(services, isDevMode) {
|
|
188165
|
+
const used = /* @__PURE__ */ new Set();
|
|
188166
|
+
for (const service of services) {
|
|
188167
|
+
const mergedEnv = isDevMode ? { ...service.env, ...service.dev?.env } : service.env;
|
|
188168
|
+
for (const value of Object.values(mergedEnv ?? {})) {
|
|
188169
|
+
if (typeof value === "object" && value.type === "secret") {
|
|
188170
|
+
used.add(value.name);
|
|
188171
|
+
}
|
|
188172
|
+
}
|
|
188173
|
+
}
|
|
188174
|
+
return used;
|
|
188175
|
+
}
|
|
188176
|
+
function findMissingSecrets(secretsDef, preparedSecrets, usedSecrets) {
|
|
188177
|
+
const missing = [];
|
|
188178
|
+
for (const secret of secretsDef) {
|
|
188179
|
+
if (secret.generated) continue;
|
|
188180
|
+
if (usedSecrets && !usedSecrets.has(secret.name)) continue;
|
|
188181
|
+
if (!preparedSecrets.has(secret.name)) {
|
|
188182
|
+
missing.push(secret.name);
|
|
188183
|
+
}
|
|
188184
|
+
}
|
|
188185
|
+
return missing;
|
|
188186
|
+
}
|
|
188187
|
+
|
|
188188
|
+
// src/lib/dev/electric-manager.ts
|
|
187938
188189
|
async function startElectric(postgres, port, options2) {
|
|
187939
188190
|
if (postgres.type !== "postgres") {
|
|
187940
188191
|
throw new Error(
|
|
@@ -187983,7 +188234,7 @@ async function waitForTcpPort2(host, port, timeoutMs = 3e4) {
|
|
|
187983
188234
|
if (isOpen) {
|
|
187984
188235
|
return;
|
|
187985
188236
|
}
|
|
187986
|
-
await
|
|
188237
|
+
await sleep3(100);
|
|
187987
188238
|
}
|
|
187988
188239
|
throw new Error(`Electric port ${port} did not become available within timeout`);
|
|
187989
188240
|
}
|
|
@@ -188024,7 +188275,7 @@ async function stopProcess2(proc) {
|
|
|
188024
188275
|
}, 2e3);
|
|
188025
188276
|
});
|
|
188026
188277
|
}
|
|
188027
|
-
function
|
|
188278
|
+
function sleep3(ms) {
|
|
188028
188279
|
return new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
188029
188280
|
}
|
|
188030
188281
|
|
|
@@ -188102,7 +188353,7 @@ async function waitForTcpPort3(host, port, timeoutMs = 3e4) {
|
|
|
188102
188353
|
if (isOpen) {
|
|
188103
188354
|
return;
|
|
188104
188355
|
}
|
|
188105
|
-
await
|
|
188356
|
+
await sleep4(100);
|
|
188106
188357
|
}
|
|
188107
188358
|
throw new Error(
|
|
188108
188359
|
`Drizzle Gateway port ${port} did not become available within timeout`
|
|
@@ -188145,7 +188396,7 @@ async function stopProcess3(proc) {
|
|
|
188145
188396
|
}, 2e3);
|
|
188146
188397
|
});
|
|
188147
188398
|
}
|
|
188148
|
-
function
|
|
188399
|
+
function sleep4(ms) {
|
|
188149
188400
|
return new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
188150
188401
|
}
|
|
188151
188402
|
|
|
@@ -188340,7 +188591,7 @@ function watchConfigFile(configPath, debounceMs, onChange) {
|
|
|
188340
188591
|
// src/lib/dev/proxy-registry.ts
|
|
188341
188592
|
import * as fs18 from "fs";
|
|
188342
188593
|
import * as path15 from "path";
|
|
188343
|
-
import * as
|
|
188594
|
+
import * as os8 from "os";
|
|
188344
188595
|
var ProxyRegistryManager = class {
|
|
188345
188596
|
proxyDir;
|
|
188346
188597
|
ownerPath;
|
|
@@ -188349,7 +188600,7 @@ var ProxyRegistryManager = class {
|
|
|
188349
188600
|
isOwner = false;
|
|
188350
188601
|
registryWatcher = null;
|
|
188351
188602
|
constructor() {
|
|
188352
|
-
this.proxyDir = path15.join(
|
|
188603
|
+
this.proxyDir = path15.join(os8.homedir(), ".specific", "proxy");
|
|
188353
188604
|
this.ownerPath = path15.join(this.proxyDir, "owner.json");
|
|
188354
188605
|
this.registryPath = path15.join(this.proxyDir, "registry.json");
|
|
188355
188606
|
this.lockPath = path15.join(this.proxyDir, "registry.lock");
|
|
@@ -188659,11 +188910,111 @@ var ProxyRegistryManager = class {
|
|
|
188659
188910
|
}
|
|
188660
188911
|
};
|
|
188661
188912
|
|
|
188913
|
+
// src/lib/config/parser.ts
|
|
188914
|
+
async function loadConfigs() {
|
|
188915
|
+
const { configs } = await loadLocal();
|
|
188916
|
+
return configs;
|
|
188917
|
+
}
|
|
188918
|
+
async function saveConfig(name, value) {
|
|
188919
|
+
await saveLocalConfig(name, value);
|
|
188920
|
+
}
|
|
188921
|
+
async function prepareConfigs(configsDef, environmentOverrides, isDevMode = false) {
|
|
188922
|
+
const userConfigs = await loadConfigs();
|
|
188923
|
+
const finalConfigs = /* @__PURE__ */ new Map();
|
|
188924
|
+
for (const configDef of configsDef) {
|
|
188925
|
+
const userValue = userConfigs.get(configDef.name);
|
|
188926
|
+
if (userValue !== void 0) {
|
|
188927
|
+
finalConfigs.set(configDef.name, userValue);
|
|
188928
|
+
continue;
|
|
188929
|
+
}
|
|
188930
|
+
const envOverride = environmentOverrides?.[configDef.name];
|
|
188931
|
+
if (envOverride !== void 0) {
|
|
188932
|
+
finalConfigs.set(configDef.name, envOverride);
|
|
188933
|
+
continue;
|
|
188934
|
+
}
|
|
188935
|
+
const effectiveDefault = isDevMode && configDef.dev?.default !== void 0 ? configDef.dev.default : configDef.default;
|
|
188936
|
+
if (effectiveDefault !== void 0) {
|
|
188937
|
+
finalConfigs.set(configDef.name, effectiveDefault);
|
|
188938
|
+
continue;
|
|
188939
|
+
}
|
|
188940
|
+
}
|
|
188941
|
+
return finalConfigs;
|
|
188942
|
+
}
|
|
188943
|
+
function findUsedConfigs(services, isDevMode) {
|
|
188944
|
+
const used = /* @__PURE__ */ new Set();
|
|
188945
|
+
for (const service of services) {
|
|
188946
|
+
const mergedEnv = isDevMode ? { ...service.env, ...service.dev?.env } : service.env;
|
|
188947
|
+
for (const value of Object.values(mergedEnv ?? {})) {
|
|
188948
|
+
if (typeof value === "object" && value.type === "config") {
|
|
188949
|
+
used.add(value.name);
|
|
188950
|
+
}
|
|
188951
|
+
}
|
|
188952
|
+
}
|
|
188953
|
+
return used;
|
|
188954
|
+
}
|
|
188955
|
+
function findMissingConfigs(configsDef, preparedConfigs, usedConfigs) {
|
|
188956
|
+
const missing = [];
|
|
188957
|
+
for (const config of configsDef) {
|
|
188958
|
+
if (usedConfigs && !usedConfigs.has(config.name)) continue;
|
|
188959
|
+
if (!preparedConfigs.has(config.name)) {
|
|
188960
|
+
missing.push(config.name);
|
|
188961
|
+
}
|
|
188962
|
+
}
|
|
188963
|
+
return missing;
|
|
188964
|
+
}
|
|
188965
|
+
|
|
188966
|
+
// src/lib/ui/SecretInput.tsx
|
|
188967
|
+
import React4, { useState as useState3 } from "react";
|
|
188968
|
+
import { Box as Box4, Text as Text4, useInput as useInput2 } from "ink";
|
|
188969
|
+
function SecretInput({ secretName, onSubmit, onCancel }) {
|
|
188970
|
+
const [value, setValue] = useState3("");
|
|
188971
|
+
useInput2((input, key) => {
|
|
188972
|
+
if (key.return) {
|
|
188973
|
+
if (value.trim() !== "") {
|
|
188974
|
+
onSubmit(value);
|
|
188975
|
+
}
|
|
188976
|
+
} else if (key.escape) {
|
|
188977
|
+
onCancel();
|
|
188978
|
+
} else if (key.backspace || key.delete) {
|
|
188979
|
+
setValue((prev) => prev.slice(0, -1));
|
|
188980
|
+
} else if (!key.ctrl && !key.meta && input) {
|
|
188981
|
+
setValue((prev) => prev + input);
|
|
188982
|
+
}
|
|
188983
|
+
});
|
|
188984
|
+
return /* @__PURE__ */ React4.createElement(Box4, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React4.createElement(Text4, null, "Enter value for secret ", /* @__PURE__ */ React4.createElement(Text4, { color: "cyan" }, secretName), ":"), /* @__PURE__ */ React4.createElement(Box4, null, /* @__PURE__ */ React4.createElement(Text4, { color: "cyan" }, "> "), /* @__PURE__ */ React4.createElement(Text4, null, value.length > 0 ? "*".repeat(value.length) : ""), /* @__PURE__ */ React4.createElement(Text4, { color: "gray" }, "|")), /* @__PURE__ */ React4.createElement(Text4, { dimColor: true }, "(Press Enter to save, Esc to cancel)"));
|
|
188985
|
+
}
|
|
188986
|
+
|
|
188987
|
+
// src/lib/ui/ConfigInput.tsx
|
|
188988
|
+
import React5, { useState as useState4 } from "react";
|
|
188989
|
+
import { Box as Box5, Text as Text5, useInput as useInput3 } from "ink";
|
|
188990
|
+
function ConfigInput({ configName, onSubmit, onCancel }) {
|
|
188991
|
+
const [value, setValue] = useState4("");
|
|
188992
|
+
useInput3((input, key) => {
|
|
188993
|
+
if (key.return) {
|
|
188994
|
+
if (value.trim() !== "") {
|
|
188995
|
+
onSubmit(value);
|
|
188996
|
+
}
|
|
188997
|
+
} else if (key.escape) {
|
|
188998
|
+
onCancel();
|
|
188999
|
+
} else if (key.backspace || key.delete) {
|
|
189000
|
+
setValue((prev) => prev.slice(0, -1));
|
|
189001
|
+
} else if (!key.ctrl && !key.meta && input) {
|
|
189002
|
+
setValue((prev) => prev + input);
|
|
189003
|
+
}
|
|
189004
|
+
});
|
|
189005
|
+
return /* @__PURE__ */ React5.createElement(Box5, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React5.createElement(Text5, null, "Enter value for config ", /* @__PURE__ */ React5.createElement(Text5, { color: "cyan" }, configName), ":"), /* @__PURE__ */ React5.createElement(Box5, null, /* @__PURE__ */ React5.createElement(Text5, { color: "cyan" }, "> "), /* @__PURE__ */ React5.createElement(Text5, null, value), /* @__PURE__ */ React5.createElement(Text5, { color: "gray" }, "|")), /* @__PURE__ */ React5.createElement(Text5, { dimColor: true }, "(Press Enter to save, Esc to cancel)"));
|
|
189006
|
+
}
|
|
189007
|
+
|
|
189008
|
+
// src/lib/ui/interactive.ts
|
|
189009
|
+
function isInteractive() {
|
|
189010
|
+
return process.stdin.isTTY === true && process.stdout.isTTY === true;
|
|
189011
|
+
}
|
|
189012
|
+
|
|
188662
189013
|
// src/commands/dev.tsx
|
|
188663
189014
|
var COLORS = ["cyan", "yellow", "green", "magenta", "blue"];
|
|
188664
189015
|
function DevUI({ instanceKey }) {
|
|
188665
|
-
const { exit } =
|
|
188666
|
-
const [state, setState] =
|
|
189016
|
+
const { exit } = useApp2();
|
|
189017
|
+
const [state, setState] = useState5(() => {
|
|
188667
189018
|
const caExists = caFilesExist();
|
|
188668
189019
|
return {
|
|
188669
189020
|
status: caExists ? "loading" : "installing-ca",
|
|
@@ -188676,7 +189027,7 @@ function DevUI({ instanceKey }) {
|
|
|
188676
189027
|
isProxyOwner: false
|
|
188677
189028
|
};
|
|
188678
189029
|
});
|
|
188679
|
-
|
|
189030
|
+
useEffect3(() => {
|
|
188680
189031
|
if (state.status === "installing-ca" && state.caInstallPhase === "installing") {
|
|
188681
189032
|
installCA();
|
|
188682
189033
|
}
|
|
@@ -188709,8 +189060,8 @@ function DevUI({ instanceKey }) {
|
|
|
188709
189060
|
const adminServerRef = useRef(null);
|
|
188710
189061
|
const servicesRef = useRef([]);
|
|
188711
189062
|
const resourcesRef = useRef(/* @__PURE__ */ new Map());
|
|
188712
|
-
const [reloadTrigger, setReloadTrigger] =
|
|
188713
|
-
const [readyToStart, setReadyToStart] =
|
|
189063
|
+
const [reloadTrigger, setReloadTrigger] = useState5(0);
|
|
189064
|
+
const [readyToStart, setReadyToStart] = useState5(() => caFilesExist());
|
|
188714
189065
|
const shutdown2 = async () => {
|
|
188715
189066
|
if (shuttingDown.current) return;
|
|
188716
189067
|
shuttingDown.current = true;
|
|
@@ -188802,7 +189153,7 @@ function DevUI({ instanceKey }) {
|
|
|
188802
189153
|
}));
|
|
188803
189154
|
setReloadTrigger((t) => t + 1);
|
|
188804
189155
|
};
|
|
188805
|
-
|
|
189156
|
+
useEffect3(() => {
|
|
188806
189157
|
const handleSignal = () => {
|
|
188807
189158
|
if (shuttingDown.current) {
|
|
188808
189159
|
writeLog("system", "Force shutting down");
|
|
@@ -188831,13 +189182,13 @@ function DevUI({ instanceKey }) {
|
|
|
188831
189182
|
process.off("SIGTERM", handleSignal);
|
|
188832
189183
|
};
|
|
188833
189184
|
}, []);
|
|
188834
|
-
|
|
189185
|
+
useEffect3(() => {
|
|
188835
189186
|
if (state.status === "running" && !startTimeRef.current) {
|
|
188836
189187
|
startTimeRef.current = Date.now();
|
|
188837
189188
|
trackEvent("dev_started");
|
|
188838
189189
|
}
|
|
188839
189190
|
}, [state.status]);
|
|
188840
|
-
|
|
189191
|
+
useEffect3(() => {
|
|
188841
189192
|
if (state.status !== "running") return;
|
|
188842
189193
|
const configPath = path16.join(process.cwd(), "specific.hcl");
|
|
188843
189194
|
const watcher = watchConfigFile(configPath, 1e3, () => {
|
|
@@ -188872,7 +189223,66 @@ function DevUI({ instanceKey }) {
|
|
|
188872
189223
|
]
|
|
188873
189224
|
}));
|
|
188874
189225
|
};
|
|
188875
|
-
|
|
189226
|
+
const handleSecretSubmit = async (value) => {
|
|
189227
|
+
const currentSecret = state.missingSecrets?.[state.currentSecretIndex ?? 0];
|
|
189228
|
+
if (!currentSecret) return;
|
|
189229
|
+
await saveSecret(currentSecret, value);
|
|
189230
|
+
const nextIndex = (state.currentSecretIndex ?? 0) + 1;
|
|
189231
|
+
if (nextIndex < (state.missingSecrets?.length ?? 0)) {
|
|
189232
|
+
setState((s) => ({
|
|
189233
|
+
...s,
|
|
189234
|
+
currentSecretIndex: nextIndex
|
|
189235
|
+
}));
|
|
189236
|
+
} else if (state.missingConfigs && state.missingConfigs.length > 0) {
|
|
189237
|
+
setState((s) => ({
|
|
189238
|
+
...s,
|
|
189239
|
+
status: "awaiting-configs",
|
|
189240
|
+
missingSecrets: void 0,
|
|
189241
|
+
currentSecretIndex: void 0,
|
|
189242
|
+
currentConfigIndex: 0
|
|
189243
|
+
}));
|
|
189244
|
+
} else {
|
|
189245
|
+
setState((s) => ({
|
|
189246
|
+
...s,
|
|
189247
|
+
status: "loading",
|
|
189248
|
+
missingSecrets: void 0,
|
|
189249
|
+
currentSecretIndex: void 0
|
|
189250
|
+
}));
|
|
189251
|
+
setReloadTrigger((t) => t + 1);
|
|
189252
|
+
}
|
|
189253
|
+
};
|
|
189254
|
+
const handleConfigSubmit = async (value) => {
|
|
189255
|
+
const currentConfig = state.missingConfigs?.[state.currentConfigIndex ?? 0];
|
|
189256
|
+
if (!currentConfig) return;
|
|
189257
|
+
await saveConfig(currentConfig, value);
|
|
189258
|
+
const nextIndex = (state.currentConfigIndex ?? 0) + 1;
|
|
189259
|
+
if (nextIndex < (state.missingConfigs?.length ?? 0)) {
|
|
189260
|
+
setState((s) => ({
|
|
189261
|
+
...s,
|
|
189262
|
+
currentConfigIndex: nextIndex
|
|
189263
|
+
}));
|
|
189264
|
+
} else {
|
|
189265
|
+
setState((s) => ({
|
|
189266
|
+
...s,
|
|
189267
|
+
status: "loading",
|
|
189268
|
+
missingConfigs: void 0,
|
|
189269
|
+
currentConfigIndex: void 0
|
|
189270
|
+
}));
|
|
189271
|
+
setReloadTrigger((t) => t + 1);
|
|
189272
|
+
}
|
|
189273
|
+
};
|
|
189274
|
+
const handleInputCancel = () => {
|
|
189275
|
+
setState((s) => ({
|
|
189276
|
+
...s,
|
|
189277
|
+
status: "error",
|
|
189278
|
+
error: "Startup cancelled - required values not provided",
|
|
189279
|
+
missingSecrets: void 0,
|
|
189280
|
+
currentSecretIndex: void 0,
|
|
189281
|
+
missingConfigs: void 0,
|
|
189282
|
+
currentConfigIndex: void 0
|
|
189283
|
+
}));
|
|
189284
|
+
};
|
|
189285
|
+
useEffect3(() => {
|
|
188876
189286
|
if (!readyToStart) {
|
|
188877
189287
|
return;
|
|
188878
189288
|
}
|
|
@@ -189047,8 +189457,50 @@ function DevUI({ instanceKey }) {
|
|
|
189047
189457
|
}
|
|
189048
189458
|
}
|
|
189049
189459
|
if (cancelled) return;
|
|
189050
|
-
const secrets = await prepareSecrets(config2.secrets);
|
|
189051
|
-
const configs = await prepareConfigs(config2.configs);
|
|
189460
|
+
const secrets = await prepareSecrets(config2.secrets, true);
|
|
189461
|
+
const configs = await prepareConfigs(config2.configs, void 0, true);
|
|
189462
|
+
const usedSecrets = findUsedSecrets(config2.services, true);
|
|
189463
|
+
const usedConfigs = findUsedConfigs(config2.services, true);
|
|
189464
|
+
const missingSecrets = findMissingSecrets(config2.secrets, secrets, usedSecrets);
|
|
189465
|
+
const missingConfigs = findMissingConfigs(config2.configs, configs, usedConfigs);
|
|
189466
|
+
if (missingSecrets.length > 0 || missingConfigs.length > 0) {
|
|
189467
|
+
if (isInteractive()) {
|
|
189468
|
+
if (missingSecrets.length > 0) {
|
|
189469
|
+
setState((s) => ({
|
|
189470
|
+
...s,
|
|
189471
|
+
status: "awaiting-secrets",
|
|
189472
|
+
missingSecrets,
|
|
189473
|
+
currentSecretIndex: 0,
|
|
189474
|
+
missingConfigs: missingConfigs.length > 0 ? missingConfigs : void 0
|
|
189475
|
+
}));
|
|
189476
|
+
return;
|
|
189477
|
+
} else {
|
|
189478
|
+
setState((s) => ({
|
|
189479
|
+
...s,
|
|
189480
|
+
status: "awaiting-configs",
|
|
189481
|
+
missingConfigs,
|
|
189482
|
+
currentConfigIndex: 0
|
|
189483
|
+
}));
|
|
189484
|
+
return;
|
|
189485
|
+
}
|
|
189486
|
+
} else {
|
|
189487
|
+
const errorParts = [];
|
|
189488
|
+
if (missingSecrets.length > 0) {
|
|
189489
|
+
errorParts.push(`Missing secrets: ${missingSecrets.join(", ")}
|
|
189490
|
+
Add them to the secrets block in specific.local`);
|
|
189491
|
+
}
|
|
189492
|
+
if (missingConfigs.length > 0) {
|
|
189493
|
+
errorParts.push(`Missing configs: ${missingConfigs.join(", ")}
|
|
189494
|
+
Add them to the config block in specific.local`);
|
|
189495
|
+
}
|
|
189496
|
+
setState((s) => ({
|
|
189497
|
+
...s,
|
|
189498
|
+
status: "error",
|
|
189499
|
+
error: errorParts.join("\n\n")
|
|
189500
|
+
}));
|
|
189501
|
+
return;
|
|
189502
|
+
}
|
|
189503
|
+
}
|
|
189052
189504
|
const validationErrors = validateEndpointReferences(config2);
|
|
189053
189505
|
if (validationErrors.length > 0) {
|
|
189054
189506
|
for (const error of validationErrors) {
|
|
@@ -189334,33 +189786,57 @@ function DevUI({ instanceKey }) {
|
|
|
189334
189786
|
}, [reloadTrigger, readyToStart, instanceKey]);
|
|
189335
189787
|
if (state.status === "installing-ca") {
|
|
189336
189788
|
if (state.caInstallPhase === "installing") {
|
|
189337
|
-
return /* @__PURE__ */
|
|
189789
|
+
return /* @__PURE__ */ React6.createElement(Box6, { flexDirection: "column" }, /* @__PURE__ */ React6.createElement(Text6, { bold: true, color: "cyan" }, "TLS Certificate Setup"), /* @__PURE__ */ React6.createElement(Text6, null, " "), /* @__PURE__ */ React6.createElement(Text6, null, "Installing a local certificate authority (CA) to enable HTTPS"), /* @__PURE__ */ React6.createElement(Text6, null, "for local development. The CA is limited to Specific projects."), /* @__PURE__ */ React6.createElement(Text6, null, " "), /* @__PURE__ */ React6.createElement(Text6, null, "Your password is required to add the CA to your system's trust store."), /* @__PURE__ */ React6.createElement(Text6, null, " "));
|
|
189338
189790
|
}
|
|
189339
189791
|
if (state.caInstallPhase === "error") {
|
|
189340
|
-
return /* @__PURE__ */
|
|
189792
|
+
return /* @__PURE__ */ React6.createElement(Box6, { flexDirection: "column" }, /* @__PURE__ */ React6.createElement(Text6, { color: "red" }, "Failed to install CA: ", state.caError));
|
|
189341
189793
|
}
|
|
189342
189794
|
}
|
|
189343
189795
|
if (state.status === "loading") {
|
|
189344
|
-
return /* @__PURE__ */
|
|
189796
|
+
return /* @__PURE__ */ React6.createElement(Box6, null, /* @__PURE__ */ React6.createElement(Text6, { color: "blue" }, /* @__PURE__ */ React6.createElement(Spinner4, { type: "dots" })));
|
|
189797
|
+
}
|
|
189798
|
+
if (state.status === "awaiting-secrets" && state.missingSecrets && state.currentSecretIndex !== void 0) {
|
|
189799
|
+
const currentSecret = state.missingSecrets[state.currentSecretIndex];
|
|
189800
|
+
return /* @__PURE__ */ React6.createElement(Box6, { flexDirection: "column" }, /* @__PURE__ */ React6.createElement(Text6, null, /* @__PURE__ */ React6.createElement(Text6, { bold: true, color: "cyan" }, "Specific dev server")), /* @__PURE__ */ React6.createElement(Text6, null, " "), /* @__PURE__ */ React6.createElement(Text6, null, "Missing secrets (", state.currentSecretIndex + 1, "/", state.missingSecrets.length, "):"), /* @__PURE__ */ React6.createElement(
|
|
189801
|
+
SecretInput,
|
|
189802
|
+
{
|
|
189803
|
+
key: currentSecret,
|
|
189804
|
+
secretName: currentSecret,
|
|
189805
|
+
onSubmit: handleSecretSubmit,
|
|
189806
|
+
onCancel: handleInputCancel
|
|
189807
|
+
}
|
|
189808
|
+
));
|
|
189809
|
+
}
|
|
189810
|
+
if (state.status === "awaiting-configs" && state.missingConfigs && state.currentConfigIndex !== void 0) {
|
|
189811
|
+
const currentConfig = state.missingConfigs[state.currentConfigIndex];
|
|
189812
|
+
return /* @__PURE__ */ React6.createElement(Box6, { flexDirection: "column" }, /* @__PURE__ */ React6.createElement(Text6, null, /* @__PURE__ */ React6.createElement(Text6, { bold: true, color: "cyan" }, "Specific dev server")), /* @__PURE__ */ React6.createElement(Text6, null, " "), /* @__PURE__ */ React6.createElement(Text6, null, "Missing configs (", state.currentConfigIndex + 1, "/", state.missingConfigs.length, "):"), /* @__PURE__ */ React6.createElement(
|
|
189813
|
+
ConfigInput,
|
|
189814
|
+
{
|
|
189815
|
+
key: currentConfig,
|
|
189816
|
+
configName: currentConfig,
|
|
189817
|
+
onSubmit: handleConfigSubmit,
|
|
189818
|
+
onCancel: handleInputCancel
|
|
189819
|
+
}
|
|
189820
|
+
));
|
|
189345
189821
|
}
|
|
189346
189822
|
if (state.status === "waiting") {
|
|
189347
|
-
return /* @__PURE__ */
|
|
189823
|
+
return /* @__PURE__ */ React6.createElement(Box6, { flexDirection: "column" }, /* @__PURE__ */ React6.createElement(Text6, null, /* @__PURE__ */ React6.createElement(Text6, { color: "yellow" }, /* @__PURE__ */ React6.createElement(Spinner4, { type: "dots" })), /* @__PURE__ */ React6.createElement(Text6, null, " No specific.hcl in project yet. Go build something with your coding agent!")));
|
|
189348
189824
|
}
|
|
189349
189825
|
if (state.status === "error") {
|
|
189350
|
-
return /* @__PURE__ */
|
|
189826
|
+
return /* @__PURE__ */ React6.createElement(Box6, { flexDirection: "column" }, /* @__PURE__ */ React6.createElement(Text6, { color: "red" }, "Error: ", state.error));
|
|
189351
189827
|
}
|
|
189352
189828
|
if (state.status === "stopping") {
|
|
189353
|
-
return /* @__PURE__ */
|
|
189829
|
+
return /* @__PURE__ */ React6.createElement(Box6, null, /* @__PURE__ */ React6.createElement(Text6, { color: "yellow" }, /* @__PURE__ */ React6.createElement(Spinner4, { type: "dots" })), /* @__PURE__ */ React6.createElement(Text6, null, " Shutting down..."));
|
|
189354
189830
|
}
|
|
189355
189831
|
if (state.status === "reloading") {
|
|
189356
|
-
return /* @__PURE__ */
|
|
189832
|
+
return /* @__PURE__ */ React6.createElement(Box6, { flexDirection: "column" }, /* @__PURE__ */ React6.createElement(Text6, null, /* @__PURE__ */ React6.createElement(Text6, { bold: true, color: "cyan" }, "Specific dev server")), /* @__PURE__ */ React6.createElement(Text6, null, " "), /* @__PURE__ */ React6.createElement(Box6, null, /* @__PURE__ */ React6.createElement(Text6, { color: "yellow" }, /* @__PURE__ */ React6.createElement(Spinner4, { type: "dots" })), /* @__PURE__ */ React6.createElement(Text6, null, " Reloading (specific.hcl changed)...")));
|
|
189357
189833
|
}
|
|
189358
189834
|
const { config, resources, services, proxy, output } = state;
|
|
189359
189835
|
if (!config) {
|
|
189360
|
-
return /* @__PURE__ */
|
|
189836
|
+
return /* @__PURE__ */ React6.createElement(Box6, null, /* @__PURE__ */ React6.createElement(Text6, { color: "blue" }, /* @__PURE__ */ React6.createElement(Spinner4, { type: "dots" })));
|
|
189361
189837
|
}
|
|
189362
189838
|
if (state.status === "starting") {
|
|
189363
|
-
return /* @__PURE__ */
|
|
189839
|
+
return /* @__PURE__ */ React6.createElement(Box6, { flexDirection: "column" }, /* @__PURE__ */ React6.createElement(Text6, null, /* @__PURE__ */ React6.createElement(Text6, { bold: true, color: "cyan" }, "Specific dev server"), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " (Ctrl+C to stop)")), /* @__PURE__ */ React6.createElement(Text6, null, " "), (config.postgres.length > 0 || config.redis.length > 0 || config.storage.length > 0) && /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { bold: true }, "Resources:"), config.postgres.map((pg) => {
|
|
189364
189840
|
const instance = resources.get(pg.name);
|
|
189365
189841
|
const resStatus = state.resourceStatus.get(pg.name);
|
|
189366
189842
|
const isReady = !!instance;
|
|
@@ -189375,7 +189851,7 @@ function DevUI({ instanceKey }) {
|
|
|
189375
189851
|
} else if (resStatus?.status === "starting") {
|
|
189376
189852
|
statusText = " starting...";
|
|
189377
189853
|
}
|
|
189378
|
-
return /* @__PURE__ */
|
|
189854
|
+
return /* @__PURE__ */ React6.createElement(Text6, { key: pg.name }, /* @__PURE__ */ React6.createElement(Text6, { color: isReady ? "green" : "gray" }, " \u25CF "), /* @__PURE__ */ React6.createElement(Text6, null, pg.name, " (postgres)"), instance && /* @__PURE__ */ React6.createElement(Text6, null, " \u2192 localhost:", instance.port), !isReady && statusText && /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, statusText));
|
|
189379
189855
|
}), config.redis.map((redis) => {
|
|
189380
189856
|
const instance = resources.get(redis.name);
|
|
189381
189857
|
const resStatus = state.resourceStatus.get(redis.name);
|
|
@@ -189391,35 +189867,35 @@ function DevUI({ instanceKey }) {
|
|
|
189391
189867
|
} else if (resStatus?.status === "starting") {
|
|
189392
189868
|
statusText = " starting...";
|
|
189393
189869
|
}
|
|
189394
|
-
return /* @__PURE__ */
|
|
189870
|
+
return /* @__PURE__ */ React6.createElement(Text6, { key: redis.name }, /* @__PURE__ */ React6.createElement(Text6, { color: isReady ? "green" : "gray" }, " \u25CF "), /* @__PURE__ */ React6.createElement(Text6, null, redis.name, " (redis)"), instance && /* @__PURE__ */ React6.createElement(Text6, null, " \u2192 localhost:", instance.port), !isReady && statusText && /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, statusText));
|
|
189395
189871
|
}), config.storage.map((storage) => {
|
|
189396
189872
|
const instance = resources.get(storage.name);
|
|
189397
189873
|
const resStatus = state.resourceStatus.get(storage.name);
|
|
189398
189874
|
const isReady = !!instance;
|
|
189399
189875
|
const statusText = resStatus?.status === "starting" ? " starting..." : "";
|
|
189400
|
-
return /* @__PURE__ */
|
|
189401
|
-
}), /* @__PURE__ */
|
|
189876
|
+
return /* @__PURE__ */ React6.createElement(Text6, { key: storage.name }, /* @__PURE__ */ React6.createElement(Text6, { color: isReady ? "green" : "gray" }, " \u25CF "), /* @__PURE__ */ React6.createElement(Text6, null, storage.name, " (storage)"), instance && /* @__PURE__ */ React6.createElement(Text6, null, " \u2192 localhost:", instance.port), !isReady && statusText && /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, statusText));
|
|
189877
|
+
}), /* @__PURE__ */ React6.createElement(Text6, null, " ")), config.services.length > 0 && /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { bold: true }, "Services:"), config.services.map((svc) => {
|
|
189402
189878
|
const running = services.find((s) => s.name === svc.name);
|
|
189403
189879
|
const isReady = !!running;
|
|
189404
189880
|
const defaultPort = running?.ports.get("default");
|
|
189405
189881
|
const portInfo = defaultPort ? ` \u2192 localhost:${defaultPort}` : "";
|
|
189406
|
-
return /* @__PURE__ */
|
|
189407
|
-
}), /* @__PURE__ */
|
|
189882
|
+
return /* @__PURE__ */ React6.createElement(Text6, { key: svc.name }, /* @__PURE__ */ React6.createElement(Text6, { color: isReady ? "green" : "gray" }, " \u25CF "), /* @__PURE__ */ React6.createElement(Text6, null, svc.name, portInfo));
|
|
189883
|
+
}), /* @__PURE__ */ React6.createElement(Text6, null, " ")), /* @__PURE__ */ React6.createElement(Box6, null, /* @__PURE__ */ React6.createElement(Text6, { color: "blue" }, /* @__PURE__ */ React6.createElement(Spinner4, { type: "dots" })), /* @__PURE__ */ React6.createElement(Text6, null, " Starting...")));
|
|
189408
189884
|
}
|
|
189409
189885
|
const staticItems = [
|
|
189410
189886
|
{
|
|
189411
189887
|
key: "title",
|
|
189412
|
-
content: /* @__PURE__ */
|
|
189888
|
+
content: /* @__PURE__ */ React6.createElement(Text6, null, /* @__PURE__ */ React6.createElement(Text6, { bold: true, color: "cyan" }, "Specific dev server"), instanceKey !== "default" && /* @__PURE__ */ React6.createElement(Text6, { color: "yellow" }, " [", instanceKey, "]"), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " (Ctrl+C to stop)"))
|
|
189413
189889
|
},
|
|
189414
|
-
{ key: "space1", content: /* @__PURE__ */
|
|
189890
|
+
{ key: "space1", content: /* @__PURE__ */ React6.createElement(Text6, null, " ") },
|
|
189415
189891
|
// Show admin UI URL
|
|
189416
189892
|
{
|
|
189417
189893
|
key: "admin",
|
|
189418
|
-
content: /* @__PURE__ */
|
|
189894
|
+
content: /* @__PURE__ */ React6.createElement(Text6, null, /* @__PURE__ */ React6.createElement(Text6, { bold: true }, "Admin:"), /* @__PURE__ */ React6.createElement(Text6, null, " "), /* @__PURE__ */ React6.createElement(Text6, { bold: true }, "https://", instanceKey === "default" ? "" : `${instanceKey}.`, "local.spcf.app"))
|
|
189419
189895
|
},
|
|
189420
|
-
{ key: "admin-space", content: /* @__PURE__ */
|
|
189896
|
+
{ key: "admin-space", content: /* @__PURE__ */ React6.createElement(Text6, null, " ") },
|
|
189421
189897
|
...services.length > 0 ? [
|
|
189422
|
-
{ key: "svc-header", content: /* @__PURE__ */
|
|
189898
|
+
{ key: "svc-header", content: /* @__PURE__ */ React6.createElement(Text6, { bold: true }, "Services:") },
|
|
189423
189899
|
...services.flatMap((svc) => {
|
|
189424
189900
|
const serviceConfig = config.services.find((s) => s.name === svc.name);
|
|
189425
189901
|
const endpoints = serviceConfig?.endpoints || [];
|
|
@@ -189427,7 +189903,7 @@ function DevUI({ instanceKey }) {
|
|
|
189427
189903
|
const defaultPort = svc.ports.get("default");
|
|
189428
189904
|
return [{
|
|
189429
189905
|
key: `svc-${svc.name}`,
|
|
189430
|
-
content: /* @__PURE__ */
|
|
189906
|
+
content: /* @__PURE__ */ React6.createElement(Text6, null, /* @__PURE__ */ React6.createElement(Text6, { color: "green" }, " \u25CF "), /* @__PURE__ */ React6.createElement(Text6, null, svc.name), defaultPort && /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " (localhost:", defaultPort, ")"))
|
|
189431
189907
|
}];
|
|
189432
189908
|
}
|
|
189433
189909
|
return endpoints.map((endpoint) => {
|
|
@@ -189436,61 +189912,61 @@ function DevUI({ instanceKey }) {
|
|
|
189436
189912
|
const proxyName = endpoint.name === "default" ? svc.name : `${svc.name}-${endpoint.name}`;
|
|
189437
189913
|
return {
|
|
189438
189914
|
key: `svc-${svc.name}-${endpoint.name}`,
|
|
189439
|
-
content: /* @__PURE__ */
|
|
189915
|
+
content: /* @__PURE__ */ React6.createElement(Text6, null, /* @__PURE__ */ React6.createElement(Text6, { color: "green" }, " \u25CF "), /* @__PURE__ */ React6.createElement(Text6, null, displayName), port ? endpoint.public ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, null, " \u2192 "), /* @__PURE__ */ React6.createElement(Text6, { bold: true }, "https://", proxyName, instanceKey === "default" ? "" : `.${instanceKey}`, ".local.spcf.app"), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " (localhost:", port, ")")) : /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " (localhost:", port, ")") : null)
|
|
189440
189916
|
};
|
|
189441
189917
|
});
|
|
189442
189918
|
}),
|
|
189443
|
-
{ key: "space2", content: /* @__PURE__ */
|
|
189919
|
+
{ key: "space2", content: /* @__PURE__ */ React6.createElement(Text6, null, " ") }
|
|
189444
189920
|
] : [],
|
|
189445
189921
|
...config.postgres.length > 0 ? [
|
|
189446
|
-
{ key: "pg-header", content: /* @__PURE__ */
|
|
189922
|
+
{ key: "pg-header", content: /* @__PURE__ */ React6.createElement(Text6, { bold: true }, "Postgres:") },
|
|
189447
189923
|
...config.postgres.map((pg) => {
|
|
189448
189924
|
const instance = resources.get(pg.name);
|
|
189449
189925
|
return {
|
|
189450
189926
|
key: `pg-${pg.name}`,
|
|
189451
|
-
content: /* @__PURE__ */
|
|
189927
|
+
content: /* @__PURE__ */ React6.createElement(Text6, null, /* @__PURE__ */ React6.createElement(Text6, { color: "green" }, " \u25CF "), /* @__PURE__ */ React6.createElement(Text6, null, pg.name), instance && /* @__PURE__ */ React6.createElement(Text6, null, " \u2192 ", instance.url))
|
|
189452
189928
|
};
|
|
189453
189929
|
}),
|
|
189454
|
-
{ key: "pg-space", content: /* @__PURE__ */
|
|
189930
|
+
{ key: "pg-space", content: /* @__PURE__ */ React6.createElement(Text6, null, " ") }
|
|
189455
189931
|
] : [],
|
|
189456
189932
|
...config.redis.length > 0 ? [
|
|
189457
|
-
{ key: "redis-header", content: /* @__PURE__ */
|
|
189933
|
+
{ key: "redis-header", content: /* @__PURE__ */ React6.createElement(Text6, { bold: true }, "Redis:") },
|
|
189458
189934
|
...config.redis.map((redis) => {
|
|
189459
189935
|
const instance = resources.get(redis.name);
|
|
189460
189936
|
return {
|
|
189461
189937
|
key: `redis-${redis.name}`,
|
|
189462
|
-
content: /* @__PURE__ */
|
|
189938
|
+
content: /* @__PURE__ */ React6.createElement(Text6, null, /* @__PURE__ */ React6.createElement(Text6, { color: "green" }, " \u25CF "), /* @__PURE__ */ React6.createElement(Text6, null, redis.name), instance && /* @__PURE__ */ React6.createElement(Text6, null, " \u2192 localhost:", instance.port))
|
|
189463
189939
|
};
|
|
189464
189940
|
}),
|
|
189465
|
-
{ key: "redis-space", content: /* @__PURE__ */
|
|
189941
|
+
{ key: "redis-space", content: /* @__PURE__ */ React6.createElement(Text6, null, " ") }
|
|
189466
189942
|
] : [],
|
|
189467
189943
|
...config.storage.length > 0 ? [
|
|
189468
|
-
{ key: "storage-header", content: /* @__PURE__ */
|
|
189944
|
+
{ key: "storage-header", content: /* @__PURE__ */ React6.createElement(Text6, { bold: true }, "Storage:") },
|
|
189469
189945
|
...config.storage.map((storage) => {
|
|
189470
189946
|
const instance = resources.get(storage.name);
|
|
189471
189947
|
return {
|
|
189472
189948
|
key: `storage-${storage.name}`,
|
|
189473
|
-
content: /* @__PURE__ */
|
|
189949
|
+
content: /* @__PURE__ */ React6.createElement(Text6, null, /* @__PURE__ */ React6.createElement(Text6, { color: "green" }, " \u25CF "), /* @__PURE__ */ React6.createElement(Text6, null, storage.name), instance && /* @__PURE__ */ React6.createElement(Text6, null, " \u2192 localhost:", instance.port))
|
|
189474
189950
|
};
|
|
189475
189951
|
}),
|
|
189476
|
-
{ key: "storage-space", content: /* @__PURE__ */
|
|
189952
|
+
{ key: "storage-space", content: /* @__PURE__ */ React6.createElement(Text6, null, " ") }
|
|
189477
189953
|
] : [],
|
|
189478
|
-
{ key: "separator", content: /* @__PURE__ */
|
|
189954
|
+
{ key: "separator", content: /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, "\u2500".repeat(50)) },
|
|
189479
189955
|
...state.parseError ? [
|
|
189480
189956
|
{
|
|
189481
189957
|
key: "parse-error",
|
|
189482
|
-
content: /* @__PURE__ */
|
|
189958
|
+
content: /* @__PURE__ */ React6.createElement(Text6, { color: "red" }, "Warning: ", state.parseError)
|
|
189483
189959
|
}
|
|
189484
189960
|
] : [],
|
|
189485
189961
|
...output.map((line, i) => ({
|
|
189486
189962
|
key: `log-${i}`,
|
|
189487
|
-
content: /* @__PURE__ */
|
|
189963
|
+
content: /* @__PURE__ */ React6.createElement(Text6, null, /* @__PURE__ */ React6.createElement(Text6, { color: line.color }, "[", line.service, "]"), " ", line.text)
|
|
189488
189964
|
}))
|
|
189489
189965
|
];
|
|
189490
|
-
return /* @__PURE__ */
|
|
189966
|
+
return /* @__PURE__ */ React6.createElement(Box6, { flexDirection: "column" }, /* @__PURE__ */ React6.createElement(Static, { items: staticItems }, (item) => /* @__PURE__ */ React6.createElement(Box6, { key: item.key }, item.content)));
|
|
189491
189967
|
}
|
|
189492
189968
|
function devCommand(instanceKey) {
|
|
189493
|
-
render4(/* @__PURE__ */
|
|
189969
|
+
render4(/* @__PURE__ */ React6.createElement(DevUI, { instanceKey }));
|
|
189494
189970
|
}
|
|
189495
189971
|
|
|
189496
189972
|
// src/lib/dev/git-worktree.ts
|
|
@@ -189533,8 +190009,9 @@ function getDefaultKey() {
|
|
|
189533
190009
|
}
|
|
189534
190010
|
|
|
189535
190011
|
// src/commands/deploy.tsx
|
|
189536
|
-
|
|
189537
|
-
import
|
|
190012
|
+
init_open();
|
|
190013
|
+
import React7, { useState as useState6, useEffect as useEffect4, useCallback } from "react";
|
|
190014
|
+
import { render as render5, Text as Text7, Box as Box7, useApp as useApp3, useInput as useInput5 } from "ink";
|
|
189538
190015
|
import Spinner5 from "ink-spinner";
|
|
189539
190016
|
import * as fs21 from "fs";
|
|
189540
190017
|
import * as path19 from "path";
|
|
@@ -189542,7 +190019,7 @@ import * as path19 from "path";
|
|
|
189542
190019
|
// src/lib/deploy/build-tester.ts
|
|
189543
190020
|
import { spawn as spawn5 } from "child_process";
|
|
189544
190021
|
import { existsSync as existsSync17 } from "fs";
|
|
189545
|
-
import { join as join18
|
|
190022
|
+
import { join as join18 } from "path";
|
|
189546
190023
|
function getDependencyInstallCommand(build, projectDir) {
|
|
189547
190024
|
switch (build.base) {
|
|
189548
190025
|
case "node":
|
|
@@ -189631,12 +190108,12 @@ function runCommand2(command, projectDir, buildName) {
|
|
|
189631
190108
|
async function testBuild(build, projectDir) {
|
|
189632
190109
|
const startTime = Date.now();
|
|
189633
190110
|
const outputs = [];
|
|
189634
|
-
const
|
|
189635
|
-
writeLog("build-test", `Starting test for build "${build.name}" (base: ${build.base},
|
|
189636
|
-
const depsCommand = getDependencyInstallCommand(build,
|
|
190111
|
+
const workDir = projectDir;
|
|
190112
|
+
writeLog("build-test", `Starting test for build "${build.name}" (base: ${build.base}, workDir: ${workDir})`);
|
|
190113
|
+
const depsCommand = getDependencyInstallCommand(build, workDir);
|
|
189637
190114
|
if (depsCommand) {
|
|
189638
190115
|
writeLog("build-test", `[${build.name}] Installing dependencies...`);
|
|
189639
|
-
const depsResult = await runCommand2(depsCommand,
|
|
190116
|
+
const depsResult = await runCommand2(depsCommand, workDir, build.name);
|
|
189640
190117
|
outputs.push(`[${depsCommand}]
|
|
189641
190118
|
${depsResult.output}`);
|
|
189642
190119
|
if (!depsResult.success) {
|
|
@@ -189655,7 +190132,7 @@ ${depsResult.output}`);
|
|
|
189655
190132
|
}
|
|
189656
190133
|
if (build.command) {
|
|
189657
190134
|
writeLog("build-test", `[${build.name}] Running build command...`);
|
|
189658
|
-
const buildResult = await runCommand2(build.command,
|
|
190135
|
+
const buildResult = await runCommand2(build.command, workDir, build.name);
|
|
189659
190136
|
outputs.push(`[${build.command}]
|
|
189660
190137
|
${buildResult.output}`);
|
|
189661
190138
|
if (!buildResult.success) {
|
|
@@ -189857,57 +190334,23 @@ function PhaseIndicator({
|
|
|
189857
190334
|
const currentIndex = phases.indexOf(currentPhase);
|
|
189858
190335
|
if (currentPhase === "error") {
|
|
189859
190336
|
if (phaseIndex < currentIndex) {
|
|
189860
|
-
return /* @__PURE__ */
|
|
190337
|
+
return /* @__PURE__ */ React7.createElement(Text7, null, /* @__PURE__ */ React7.createElement(Text7, { color: "green" }, " ", "\u2713"), " ", label);
|
|
189861
190338
|
}
|
|
189862
190339
|
if (phaseIndex === currentIndex) {
|
|
189863
|
-
return /* @__PURE__ */
|
|
190340
|
+
return /* @__PURE__ */ React7.createElement(Text7, null, /* @__PURE__ */ React7.createElement(Text7, { color: "red" }, " ", "\u2717"), " ", label);
|
|
189864
190341
|
}
|
|
189865
|
-
return /* @__PURE__ */
|
|
190342
|
+
return /* @__PURE__ */ React7.createElement(Text7, null, /* @__PURE__ */ React7.createElement(Text7, { dimColor: true }, " ", "\u25CB"), " ", /* @__PURE__ */ React7.createElement(Text7, { dimColor: true }, label));
|
|
189866
190343
|
}
|
|
189867
190344
|
if (phaseIndex < currentIndex) {
|
|
189868
|
-
return /* @__PURE__ */
|
|
190345
|
+
return /* @__PURE__ */ React7.createElement(Text7, null, /* @__PURE__ */ React7.createElement(Text7, { color: "green" }, " ", "\u2713"), " ", label);
|
|
189869
190346
|
}
|
|
189870
190347
|
if (phaseIndex === currentIndex) {
|
|
189871
190348
|
if (showSpinner) {
|
|
189872
|
-
return /* @__PURE__ */
|
|
190349
|
+
return /* @__PURE__ */ React7.createElement(Text7, null, " ", /* @__PURE__ */ React7.createElement(Text7, { color: "blue" }, /* @__PURE__ */ React7.createElement(Spinner5, { type: "dots" })), " ", label);
|
|
189873
190350
|
}
|
|
189874
|
-
return /* @__PURE__ */
|
|
190351
|
+
return /* @__PURE__ */ React7.createElement(Text7, null, /* @__PURE__ */ React7.createElement(Text7, { color: "yellow" }, " ", "\u25CF"), " ", label);
|
|
189875
190352
|
}
|
|
189876
|
-
return /* @__PURE__ */
|
|
189877
|
-
}
|
|
189878
|
-
function SecretInput({ secretName, onSubmit, onCancel }) {
|
|
189879
|
-
const [value, setValue] = useState5("");
|
|
189880
|
-
useInput3((input, key) => {
|
|
189881
|
-
if (key.return) {
|
|
189882
|
-
if (value.trim() !== "") {
|
|
189883
|
-
onSubmit(value);
|
|
189884
|
-
}
|
|
189885
|
-
} else if (key.escape) {
|
|
189886
|
-
onCancel();
|
|
189887
|
-
} else if (key.backspace || key.delete) {
|
|
189888
|
-
setValue((prev) => prev.slice(0, -1));
|
|
189889
|
-
} else if (!key.ctrl && !key.meta && input) {
|
|
189890
|
-
setValue((prev) => prev + input);
|
|
189891
|
-
}
|
|
189892
|
-
});
|
|
189893
|
-
return /* @__PURE__ */ React5.createElement(Box5, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React5.createElement(Text5, null, "Enter value for ", /* @__PURE__ */ React5.createElement(Text5, { color: "cyan" }, secretName), ":"), /* @__PURE__ */ React5.createElement(Box5, null, /* @__PURE__ */ React5.createElement(Text5, { color: "cyan" }, "> "), /* @__PURE__ */ React5.createElement(Text5, null, value.length > 0 ? "*".repeat(value.length) : ""), /* @__PURE__ */ React5.createElement(Text5, { color: "gray" }, "|")), /* @__PURE__ */ React5.createElement(Text5, { dimColor: true }, "(Press Enter to save, Esc to cancel deployment)"));
|
|
189894
|
-
}
|
|
189895
|
-
function ConfigInput({ configName, onSubmit, onCancel }) {
|
|
189896
|
-
const [value, setValue] = useState5("");
|
|
189897
|
-
useInput3((input, key) => {
|
|
189898
|
-
if (key.return) {
|
|
189899
|
-
if (value.trim() !== "") {
|
|
189900
|
-
onSubmit(value);
|
|
189901
|
-
}
|
|
189902
|
-
} else if (key.escape) {
|
|
189903
|
-
onCancel();
|
|
189904
|
-
} else if (key.backspace || key.delete) {
|
|
189905
|
-
setValue((prev) => prev.slice(0, -1));
|
|
189906
|
-
} else if (!key.ctrl && !key.meta && input) {
|
|
189907
|
-
setValue((prev) => prev + input);
|
|
189908
|
-
}
|
|
189909
|
-
});
|
|
189910
|
-
return /* @__PURE__ */ React5.createElement(Box5, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React5.createElement(Text5, null, "Enter value for config ", /* @__PURE__ */ React5.createElement(Text5, { color: "cyan" }, configName), ":"), /* @__PURE__ */ React5.createElement(Box5, null, /* @__PURE__ */ React5.createElement(Text5, { color: "cyan" }, "> "), /* @__PURE__ */ React5.createElement(Text5, null, value), /* @__PURE__ */ React5.createElement(Text5, { color: "gray" }, "|")), /* @__PURE__ */ React5.createElement(Text5, { dimColor: true }, "(Press Enter to save, Esc to cancel deployment)"));
|
|
190353
|
+
return /* @__PURE__ */ React7.createElement(Text7, null, /* @__PURE__ */ React7.createElement(Text7, { dimColor: true }, " ", "\u25CB"), " ", /* @__PURE__ */ React7.createElement(Text7, { dimColor: true }, label));
|
|
189911
190354
|
}
|
|
189912
190355
|
function ProjectSelector({
|
|
189913
190356
|
projects,
|
|
@@ -189916,7 +190359,7 @@ function ProjectSelector({
|
|
|
189916
190359
|
onUp,
|
|
189917
190360
|
onDown
|
|
189918
190361
|
}) {
|
|
189919
|
-
|
|
190362
|
+
useInput5((input, key) => {
|
|
189920
190363
|
if (key.return) {
|
|
189921
190364
|
if (selectedIndex === 0) {
|
|
189922
190365
|
onSelect("new");
|
|
@@ -189933,11 +190376,11 @@ function ProjectSelector({
|
|
|
189933
190376
|
{ id: "new", name: "Create new project", isNew: true },
|
|
189934
190377
|
...projects.map((p) => ({ ...p, isNew: false }))
|
|
189935
190378
|
];
|
|
189936
|
-
return /* @__PURE__ */
|
|
190379
|
+
return /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column", gap: 1 }, /* @__PURE__ */ React7.createElement(Text7, { bold: true }, "Select a project to deploy:"), /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column" }, items.map((item, index) => /* @__PURE__ */ React7.createElement(Text7, { key: item.id }, index === selectedIndex ? /* @__PURE__ */ React7.createElement(Text7, { color: "cyan" }, "> ") : /* @__PURE__ */ React7.createElement(Text7, null, " "), item.isNew ? /* @__PURE__ */ React7.createElement(Text7, { color: "green" }, item.name) : /* @__PURE__ */ React7.createElement(Text7, null, item.name, " ", /* @__PURE__ */ React7.createElement(Text7, { dimColor: true }, "(", item.id, ")"))))), /* @__PURE__ */ React7.createElement(Text7, { dimColor: true }, "Use arrow keys to navigate, Enter to select"));
|
|
189937
190380
|
}
|
|
189938
190381
|
function NameInput({ onSubmit, onCancel }) {
|
|
189939
|
-
const [value, setValue] =
|
|
189940
|
-
|
|
190382
|
+
const [value, setValue] = useState6("");
|
|
190383
|
+
useInput5((input, key) => {
|
|
189941
190384
|
if (key.return) {
|
|
189942
190385
|
if (value.trim() !== "") {
|
|
189943
190386
|
onSubmit(value.trim());
|
|
@@ -189950,13 +190393,13 @@ function NameInput({ onSubmit, onCancel }) {
|
|
|
189950
190393
|
setValue((prev) => prev + input);
|
|
189951
190394
|
}
|
|
189952
190395
|
});
|
|
189953
|
-
return /* @__PURE__ */
|
|
190396
|
+
return /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column", gap: 1 }, /* @__PURE__ */ React7.createElement(Text7, { bold: true }, "Create new project"), /* @__PURE__ */ React7.createElement(Text7, null, "Enter project name:"), /* @__PURE__ */ React7.createElement(Box7, null, /* @__PURE__ */ React7.createElement(Text7, { color: "cyan" }, "> "), /* @__PURE__ */ React7.createElement(Text7, null, value), /* @__PURE__ */ React7.createElement(Text7, { color: "gray" }, "|")), /* @__PURE__ */ React7.createElement(Text7, { dimColor: true }, "Press Enter to create, Esc to go back"));
|
|
189954
190397
|
}
|
|
189955
190398
|
function DeployUI({ environment, config, skipBuildTest }) {
|
|
189956
|
-
const { exit } =
|
|
189957
|
-
const [state, setState] =
|
|
189958
|
-
const clientRef =
|
|
189959
|
-
|
|
190399
|
+
const { exit } = useApp3();
|
|
190400
|
+
const [state, setState] = useState6({ phase: "checking-auth" });
|
|
190401
|
+
const clientRef = React7.useRef(null);
|
|
190402
|
+
useEffect4(() => {
|
|
189960
190403
|
if (state.phase !== "checking-auth") return;
|
|
189961
190404
|
const projectDir = process.cwd();
|
|
189962
190405
|
if (hasProjectId(projectDir)) {
|
|
@@ -189977,7 +190420,7 @@ function DeployUI({ environment, config, skipBuildTest }) {
|
|
|
189977
190420
|
}
|
|
189978
190421
|
setState({ phase: "logging-in" });
|
|
189979
190422
|
}, [state.phase]);
|
|
189980
|
-
|
|
190423
|
+
useEffect4(() => {
|
|
189981
190424
|
if (state.phase !== "logging-in") return;
|
|
189982
190425
|
let cancelled = false;
|
|
189983
190426
|
async function startLogin() {
|
|
@@ -190042,7 +190485,7 @@ function DeployUI({ environment, config, skipBuildTest }) {
|
|
|
190042
190485
|
cancelled = true;
|
|
190043
190486
|
};
|
|
190044
190487
|
}, [state.phase]);
|
|
190045
|
-
|
|
190488
|
+
useEffect4(() => {
|
|
190046
190489
|
if (state.phase !== "loading-projects") return;
|
|
190047
190490
|
let cancelled = false;
|
|
190048
190491
|
async function loadProjects() {
|
|
@@ -190089,7 +190532,7 @@ function DeployUI({ environment, config, skipBuildTest }) {
|
|
|
190089
190532
|
const handleNameCancel = useCallback(() => {
|
|
190090
190533
|
setState((s) => ({ ...s, phase: "selecting-project" }));
|
|
190091
190534
|
}, []);
|
|
190092
|
-
|
|
190535
|
+
useEffect4(() => {
|
|
190093
190536
|
if (state.phase !== "creating-project" || !state.newProjectName) return;
|
|
190094
190537
|
let cancelled = false;
|
|
190095
190538
|
async function createProject() {
|
|
@@ -190174,7 +190617,7 @@ function DeployUI({ environment, config, skipBuildTest }) {
|
|
|
190174
190617
|
error: "Deployment cancelled - configs not provided"
|
|
190175
190618
|
}));
|
|
190176
190619
|
}, []);
|
|
190177
|
-
|
|
190620
|
+
useEffect4(() => {
|
|
190178
190621
|
const {
|
|
190179
190622
|
phase: phase2,
|
|
190180
190623
|
deployment: deployment2,
|
|
@@ -190216,7 +190659,7 @@ function DeployUI({ environment, config, skipBuildTest }) {
|
|
|
190216
190659
|
}
|
|
190217
190660
|
})();
|
|
190218
190661
|
}, [state]);
|
|
190219
|
-
|
|
190662
|
+
useEffect4(() => {
|
|
190220
190663
|
const {
|
|
190221
190664
|
phase: phase2,
|
|
190222
190665
|
deployment: deployment2,
|
|
@@ -190258,7 +190701,7 @@ function DeployUI({ environment, config, skipBuildTest }) {
|
|
|
190258
190701
|
}
|
|
190259
190702
|
})();
|
|
190260
190703
|
}, [state]);
|
|
190261
|
-
|
|
190704
|
+
useEffect4(() => {
|
|
190262
190705
|
if (state.phase !== "testing-builds" || !state.projectId) return;
|
|
190263
190706
|
let cancelled = false;
|
|
190264
190707
|
let pollInterval;
|
|
@@ -190448,7 +190891,7 @@ ${errorMsg}`
|
|
|
190448
190891
|
if (pollInterval) clearInterval(pollInterval);
|
|
190449
190892
|
};
|
|
190450
190893
|
}, [state.projectId, environment, config.builds, skipBuildTest]);
|
|
190451
|
-
|
|
190894
|
+
useEffect4(() => {
|
|
190452
190895
|
let pollInterval;
|
|
190453
190896
|
if ((state.phase === "building" || state.phase === "deploying") && state.deployment && state.missingSecrets === void 0 && state.secretValues === void 0 && state.missingConfigs === void 0 && state.configValues === void 0) {
|
|
190454
190897
|
const client2 = clientRef.current;
|
|
@@ -190471,6 +190914,22 @@ ${errorMsg}`
|
|
|
190471
190914
|
if (pollInterval) clearInterval(pollInterval);
|
|
190472
190915
|
return;
|
|
190473
190916
|
}
|
|
190917
|
+
if (status.state === "awaiting_configs") {
|
|
190918
|
+
if (pollInterval) clearInterval(pollInterval);
|
|
190919
|
+
pollInterval = void 0;
|
|
190920
|
+
const missingConfigs2 = status.missingConfigs || [];
|
|
190921
|
+
writeLog("deploy", `Awaiting configs: ${missingConfigs2.join(", ")}`);
|
|
190922
|
+
setState((s) => ({
|
|
190923
|
+
...s,
|
|
190924
|
+
phase: "awaiting-configs",
|
|
190925
|
+
deployment: status,
|
|
190926
|
+
missingConfigs: missingConfigs2,
|
|
190927
|
+
configValues: {},
|
|
190928
|
+
currentConfigIndex: 0,
|
|
190929
|
+
currentConfigInput: ""
|
|
190930
|
+
}));
|
|
190931
|
+
return;
|
|
190932
|
+
}
|
|
190474
190933
|
if (status.state === "deploying") {
|
|
190475
190934
|
setState((s) => ({ ...s, phase: "deploying", deployment: status }));
|
|
190476
190935
|
} else if (status.state === "building") {
|
|
@@ -190486,12 +190945,12 @@ ${errorMsg}`
|
|
|
190486
190945
|
};
|
|
190487
190946
|
}
|
|
190488
190947
|
}, [state.phase, state.missingSecrets, state.secretValues, state.missingConfigs, state.configValues]);
|
|
190489
|
-
|
|
190948
|
+
useEffect4(() => {
|
|
190490
190949
|
if (state.phase === "testing-builds") {
|
|
190491
190950
|
trackEvent("deploy_started", { environment });
|
|
190492
190951
|
}
|
|
190493
190952
|
}, [state.phase, environment]);
|
|
190494
|
-
|
|
190953
|
+
useEffect4(() => {
|
|
190495
190954
|
if (state.phase === "success") {
|
|
190496
190955
|
trackEvent("deploy_succeeded", { environment });
|
|
190497
190956
|
closeDebugLog();
|
|
@@ -190520,16 +190979,16 @@ ${errorMsg}`
|
|
|
190520
190979
|
verificationUri
|
|
190521
190980
|
} = state;
|
|
190522
190981
|
if (phase === "checking-auth") {
|
|
190523
|
-
return /* @__PURE__ */
|
|
190982
|
+
return /* @__PURE__ */ React7.createElement(Box7, null, /* @__PURE__ */ React7.createElement(Text7, { color: "blue" }, /* @__PURE__ */ React7.createElement(Spinner5, { type: "dots" })), /* @__PURE__ */ React7.createElement(Text7, null, " Checking authentication..."));
|
|
190524
190983
|
}
|
|
190525
190984
|
if (phase === "logging-in") {
|
|
190526
|
-
return /* @__PURE__ */
|
|
190985
|
+
return /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column", gap: 1 }, /* @__PURE__ */ React7.createElement(Text7, { bold: true }, "Log in to Specific"), userCode ? /* @__PURE__ */ React7.createElement(React7.Fragment, null, /* @__PURE__ */ React7.createElement(Text7, null, "Your authentication code:", " ", /* @__PURE__ */ React7.createElement(Text7, { color: "cyan", bold: true }, userCode)), /* @__PURE__ */ React7.createElement(Box7, null, /* @__PURE__ */ React7.createElement(Text7, { color: "blue" }, /* @__PURE__ */ React7.createElement(Spinner5, { type: "dots" })), /* @__PURE__ */ React7.createElement(Text7, null, " Waiting for authentication in browser...")), /* @__PURE__ */ React7.createElement(Text7, { dimColor: true }, "If the browser didn't open, visit: ", verificationUri)) : /* @__PURE__ */ React7.createElement(Box7, null, /* @__PURE__ */ React7.createElement(Text7, { color: "blue" }, /* @__PURE__ */ React7.createElement(Spinner5, { type: "dots" })), /* @__PURE__ */ React7.createElement(Text7, null, " Initiating login...")));
|
|
190527
190986
|
}
|
|
190528
190987
|
if (phase === "loading-projects") {
|
|
190529
|
-
return /* @__PURE__ */
|
|
190988
|
+
return /* @__PURE__ */ React7.createElement(Box7, null, /* @__PURE__ */ React7.createElement(Text7, { color: "blue" }, /* @__PURE__ */ React7.createElement(Spinner5, { type: "dots" })), /* @__PURE__ */ React7.createElement(Text7, null, " Loading projects..."));
|
|
190530
190989
|
}
|
|
190531
190990
|
if (phase === "selecting-project" && projects && selectedIndex !== void 0) {
|
|
190532
|
-
return /* @__PURE__ */
|
|
190991
|
+
return /* @__PURE__ */ React7.createElement(
|
|
190533
190992
|
ProjectSelector,
|
|
190534
190993
|
{
|
|
190535
190994
|
projects,
|
|
@@ -190550,57 +191009,57 @@ ${errorMsg}`
|
|
|
190550
191009
|
);
|
|
190551
191010
|
}
|
|
190552
191011
|
if (phase === "entering-name") {
|
|
190553
|
-
return /* @__PURE__ */
|
|
191012
|
+
return /* @__PURE__ */ React7.createElement(NameInput, { onSubmit: handleNameSubmit, onCancel: handleNameCancel });
|
|
190554
191013
|
}
|
|
190555
191014
|
if (phase === "creating-project") {
|
|
190556
|
-
return /* @__PURE__ */
|
|
191015
|
+
return /* @__PURE__ */ React7.createElement(Box7, null, /* @__PURE__ */ React7.createElement(Text7, { color: "blue" }, /* @__PURE__ */ React7.createElement(Spinner5, { type: "dots" })), /* @__PURE__ */ React7.createElement(Text7, null, " Creating project..."));
|
|
190557
191016
|
}
|
|
190558
191017
|
const currentSecret = missingSecrets && currentSecretIndex !== void 0 ? missingSecrets[currentSecretIndex] : void 0;
|
|
190559
191018
|
const currentConfig = missingConfigs && currentConfigIndex !== void 0 ? missingConfigs[currentConfigIndex] : void 0;
|
|
190560
191019
|
const displayPhase = phase === "awaiting-secrets" || phase === "awaiting-configs" ? "building" : phase;
|
|
190561
|
-
return /* @__PURE__ */
|
|
191020
|
+
return /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column", gap: 1 }, /* @__PURE__ */ React7.createElement(Text7, null, /* @__PURE__ */ React7.createElement(Text7, { bold: true, color: "cyan" }, "Deploying to ", environment), deployment && /* @__PURE__ */ React7.createElement(Text7, { dimColor: true }, " (", deployment.id, ")")), /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column" }, /* @__PURE__ */ React7.createElement(
|
|
190562
191021
|
PhaseIndicator,
|
|
190563
191022
|
{
|
|
190564
191023
|
phase: "testing-builds",
|
|
190565
191024
|
currentPhase: displayPhase,
|
|
190566
191025
|
label: "Testing builds locally"
|
|
190567
191026
|
}
|
|
190568
|
-
), /* @__PURE__ */
|
|
191027
|
+
), /* @__PURE__ */ React7.createElement(
|
|
190569
191028
|
PhaseIndicator,
|
|
190570
191029
|
{
|
|
190571
191030
|
phase: "creating-tarball",
|
|
190572
191031
|
currentPhase: displayPhase,
|
|
190573
191032
|
label: `Creating archive${tarballSize ? ` (${formatBytes(tarballSize)})` : ""}`
|
|
190574
191033
|
}
|
|
190575
|
-
), /* @__PURE__ */
|
|
191034
|
+
), /* @__PURE__ */ React7.createElement(
|
|
190576
191035
|
PhaseIndicator,
|
|
190577
191036
|
{
|
|
190578
191037
|
phase: "creating-deployment",
|
|
190579
191038
|
currentPhase: displayPhase,
|
|
190580
191039
|
label: "Creating deployment"
|
|
190581
191040
|
}
|
|
190582
|
-
), /* @__PURE__ */
|
|
191041
|
+
), /* @__PURE__ */ React7.createElement(
|
|
190583
191042
|
PhaseIndicator,
|
|
190584
191043
|
{
|
|
190585
191044
|
phase: "uploading",
|
|
190586
191045
|
currentPhase: displayPhase,
|
|
190587
191046
|
label: "Uploading"
|
|
190588
191047
|
}
|
|
190589
|
-
), /* @__PURE__ */
|
|
191048
|
+
), /* @__PURE__ */ React7.createElement(
|
|
190590
191049
|
PhaseIndicator,
|
|
190591
191050
|
{
|
|
190592
191051
|
phase: "building",
|
|
190593
191052
|
currentPhase: displayPhase,
|
|
190594
191053
|
label: "Building"
|
|
190595
191054
|
}
|
|
190596
|
-
), /* @__PURE__ */
|
|
191055
|
+
), /* @__PURE__ */ React7.createElement(
|
|
190597
191056
|
PhaseIndicator,
|
|
190598
191057
|
{
|
|
190599
191058
|
phase: "deploying",
|
|
190600
191059
|
currentPhase: displayPhase,
|
|
190601
191060
|
label: "Deploying"
|
|
190602
191061
|
}
|
|
190603
|
-
)), phase === "awaiting-secrets" && currentSecret && /* @__PURE__ */
|
|
191062
|
+
)), phase === "awaiting-secrets" && currentSecret && /* @__PURE__ */ React7.createElement(
|
|
190604
191063
|
SecretInput,
|
|
190605
191064
|
{
|
|
190606
191065
|
key: currentSecret,
|
|
@@ -190608,7 +191067,7 @@ ${errorMsg}`
|
|
|
190608
191067
|
onSubmit: handleSecretSubmit,
|
|
190609
191068
|
onCancel: handleSecretCancel
|
|
190610
191069
|
}
|
|
190611
|
-
), phase === "awaiting-configs" && currentConfig && /* @__PURE__ */
|
|
191070
|
+
), phase === "awaiting-configs" && currentConfig && /* @__PURE__ */ React7.createElement(
|
|
190612
191071
|
ConfigInput,
|
|
190613
191072
|
{
|
|
190614
191073
|
key: currentConfig,
|
|
@@ -190616,7 +191075,7 @@ ${errorMsg}`
|
|
|
190616
191075
|
onSubmit: handleConfigSubmit,
|
|
190617
191076
|
onCancel: handleConfigCancel
|
|
190618
191077
|
}
|
|
190619
|
-
), phase === "error" && /* @__PURE__ */
|
|
191078
|
+
), phase === "error" && /* @__PURE__ */ React7.createElement(Box7, { marginTop: 1 }, /* @__PURE__ */ React7.createElement(Text7, { color: "red" }, "Error: ", error)), phase === "success" && /* @__PURE__ */ React7.createElement(Box7, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React7.createElement(Text7, { color: "green" }, "Deployment successful!"), deployment?.publicUrls && Object.keys(deployment.publicUrls).length > 0 && /* @__PURE__ */ React7.createElement(Box7, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React7.createElement(Text7, { bold: true }, "Public URLs:"), Object.entries(deployment.publicUrls).map(([name, url]) => /* @__PURE__ */ React7.createElement(Text7, { key: name }, " ", name, ": ", /* @__PURE__ */ React7.createElement(Text7, { color: "cyan" }, url))))));
|
|
190620
191079
|
}
|
|
190621
191080
|
async function deployCommand(environment, options2) {
|
|
190622
191081
|
const configPath = path19.join(process.cwd(), "specific.hcl");
|
|
@@ -190637,7 +191096,7 @@ async function deployCommand(environment, options2) {
|
|
|
190637
191096
|
const env2 = environment || "prod";
|
|
190638
191097
|
const skipBuildTest = options2?.skipBuildTest ?? false;
|
|
190639
191098
|
render5(
|
|
190640
|
-
/* @__PURE__ */
|
|
191099
|
+
/* @__PURE__ */ React7.createElement(
|
|
190641
191100
|
DeployUI,
|
|
190642
191101
|
{
|
|
190643
191102
|
environment: env2,
|
|
@@ -190877,14 +191336,14 @@ async function psqlCommand(databaseName, instanceKey = "default") {
|
|
|
190877
191336
|
}
|
|
190878
191337
|
|
|
190879
191338
|
// src/commands/clean.tsx
|
|
190880
|
-
import
|
|
190881
|
-
import { render as render6, Text as
|
|
191339
|
+
import React8, { useState as useState7, useEffect as useEffect5 } from "react";
|
|
191340
|
+
import { render as render6, Text as Text8, Box as Box8 } from "ink";
|
|
190882
191341
|
import Spinner6 from "ink-spinner";
|
|
190883
191342
|
import * as fs23 from "fs";
|
|
190884
191343
|
import * as path21 from "path";
|
|
190885
191344
|
function CleanUI({ instanceKey }) {
|
|
190886
|
-
const [state, setState] =
|
|
190887
|
-
|
|
191345
|
+
const [state, setState] = useState7({ status: "checking" });
|
|
191346
|
+
useEffect5(() => {
|
|
190888
191347
|
async function clean() {
|
|
190889
191348
|
const projectRoot = process.cwd();
|
|
190890
191349
|
const specificDir = path21.join(projectRoot, ".specific");
|
|
@@ -190960,345 +191419,50 @@ function CleanUI({ instanceKey }) {
|
|
|
190960
191419
|
clean();
|
|
190961
191420
|
}, [instanceKey]);
|
|
190962
191421
|
if (state.status === "checking") {
|
|
190963
|
-
return /* @__PURE__ */
|
|
191422
|
+
return /* @__PURE__ */ React8.createElement(Box8, null, /* @__PURE__ */ React8.createElement(Text8, { color: "blue" }, /* @__PURE__ */ React8.createElement(Spinner6, { type: "dots" })), /* @__PURE__ */ React8.createElement(Text8, null, " Checking for running instances..."));
|
|
190964
191423
|
}
|
|
190965
191424
|
if (state.status === "cleaning") {
|
|
190966
|
-
return /* @__PURE__ */
|
|
191425
|
+
return /* @__PURE__ */ React8.createElement(Box8, null, /* @__PURE__ */ React8.createElement(Text8, { color: "blue" }, /* @__PURE__ */ React8.createElement(Spinner6, { type: "dots" })), /* @__PURE__ */ React8.createElement(Text8, null, " Removing .specific directory..."));
|
|
190967
191426
|
}
|
|
190968
191427
|
if (state.status === "error") {
|
|
190969
|
-
return /* @__PURE__ */
|
|
191428
|
+
return /* @__PURE__ */ React8.createElement(Text8, { color: "red" }, "Error: ", state.error);
|
|
190970
191429
|
}
|
|
190971
191430
|
if (state.status === "nothing") {
|
|
190972
191431
|
const target2 = instanceKey ? `key "${instanceKey}"` : ".specific directory";
|
|
190973
|
-
return /* @__PURE__ */
|
|
191432
|
+
return /* @__PURE__ */ React8.createElement(Text8, { color: "yellow" }, "Nothing to clean (", target2, " does not exist)");
|
|
190974
191433
|
}
|
|
190975
191434
|
const target = instanceKey ? `key "${instanceKey}"` : ".specific directory";
|
|
190976
|
-
return /* @__PURE__ */
|
|
191435
|
+
return /* @__PURE__ */ React8.createElement(Text8, { color: "green" }, "Cleaned ", target);
|
|
190977
191436
|
}
|
|
190978
191437
|
function cleanCommand(instanceKey) {
|
|
190979
191438
|
if (instanceKey) {
|
|
190980
|
-
render6(/* @__PURE__ */
|
|
190981
|
-
} else {
|
|
190982
|
-
render6(/* @__PURE__ */ React6.createElement(CleanUI, null));
|
|
190983
|
-
}
|
|
190984
|
-
}
|
|
190985
|
-
|
|
190986
|
-
// src/commands/secrets.tsx
|
|
190987
|
-
import React7, { useState as useState7, useEffect as useEffect7 } from "react";
|
|
190988
|
-
import { render as render7, Text as Text7, Box as Box7, useInput as useInput4, useApp as useApp5 } from "ink";
|
|
190989
|
-
import * as fs24 from "fs";
|
|
190990
|
-
var HEADER_COMMENT = "# Do not commit this file - it contains secrets\n";
|
|
190991
|
-
function SetSecretUI({ secretName }) {
|
|
190992
|
-
const { exit } = useApp5();
|
|
190993
|
-
const [value, setValue] = useState7("");
|
|
190994
|
-
const [done, setDone] = useState7(false);
|
|
190995
|
-
const [error, setError] = useState7(null);
|
|
190996
|
-
useInput4((input, key) => {
|
|
190997
|
-
if (done) return;
|
|
190998
|
-
if (key.return) {
|
|
190999
|
-
if (value.trim() === "") {
|
|
191000
|
-
setError("Secret value cannot be empty");
|
|
191001
|
-
return;
|
|
191002
|
-
}
|
|
191003
|
-
try {
|
|
191004
|
-
const escapedValue = value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
191005
|
-
const hclLine = `${secretName} = "${escapedValue}"`;
|
|
191006
|
-
let content = "";
|
|
191007
|
-
let hasHeader = false;
|
|
191008
|
-
if (fs24.existsSync(SECRETS_FILE)) {
|
|
191009
|
-
content = fs24.readFileSync(SECRETS_FILE, "utf-8");
|
|
191010
|
-
hasHeader = content.startsWith("#");
|
|
191011
|
-
const lines = content.split("\n");
|
|
191012
|
-
const newLines = [];
|
|
191013
|
-
let found = false;
|
|
191014
|
-
const pattern = new RegExp(`^${secretName}\\s*=\\s*"`);
|
|
191015
|
-
for (const line of lines) {
|
|
191016
|
-
if (pattern.test(line.trim())) {
|
|
191017
|
-
newLines.push(hclLine);
|
|
191018
|
-
found = true;
|
|
191019
|
-
} else {
|
|
191020
|
-
newLines.push(line);
|
|
191021
|
-
}
|
|
191022
|
-
}
|
|
191023
|
-
if (found) {
|
|
191024
|
-
fs24.writeFileSync(SECRETS_FILE, newLines.join("\n"));
|
|
191025
|
-
setDone(true);
|
|
191026
|
-
return;
|
|
191027
|
-
}
|
|
191028
|
-
}
|
|
191029
|
-
let newContent = "";
|
|
191030
|
-
if (!hasHeader && !content) {
|
|
191031
|
-
newContent = HEADER_COMMENT + "\n";
|
|
191032
|
-
} else if (content) {
|
|
191033
|
-
newContent = content.endsWith("\n") ? content : content + "\n";
|
|
191034
|
-
}
|
|
191035
|
-
newContent += `${hclLine}
|
|
191036
|
-
`;
|
|
191037
|
-
fs24.writeFileSync(SECRETS_FILE, newContent);
|
|
191038
|
-
setDone(true);
|
|
191039
|
-
} catch (err) {
|
|
191040
|
-
setError(err instanceof Error ? err.message : String(err));
|
|
191041
|
-
}
|
|
191042
|
-
} else if (key.backspace || key.delete) {
|
|
191043
|
-
setValue((prev) => prev.slice(0, -1));
|
|
191044
|
-
} else if (key.escape) {
|
|
191045
|
-
exit();
|
|
191046
|
-
} else if (!key.ctrl && !key.meta && input) {
|
|
191047
|
-
setValue((prev) => prev + input);
|
|
191048
|
-
}
|
|
191049
|
-
});
|
|
191050
|
-
useEffect7(() => {
|
|
191051
|
-
if (done) {
|
|
191052
|
-
const timer = setTimeout(() => exit(), 50);
|
|
191053
|
-
return () => clearTimeout(timer);
|
|
191054
|
-
}
|
|
191055
|
-
}, [done, exit]);
|
|
191056
|
-
if (error) {
|
|
191057
|
-
return /* @__PURE__ */ React7.createElement(Text7, { color: "red" }, "Error: ", error);
|
|
191058
|
-
}
|
|
191059
|
-
if (done) {
|
|
191060
|
-
return /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column" }, /* @__PURE__ */ React7.createElement(Text7, { color: "green" }, "Secret '", secretName, "' saved to ", SECRETS_FILE));
|
|
191061
|
-
}
|
|
191062
|
-
return /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column" }, /* @__PURE__ */ React7.createElement(Text7, null, "Enter value for secret '", secretName, "':"), /* @__PURE__ */ React7.createElement(Box7, null, /* @__PURE__ */ React7.createElement(Text7, { color: "cyan" }, "> "), /* @__PURE__ */ React7.createElement(Text7, null, value.length > 0 ? "*".repeat(value.length) : ""), /* @__PURE__ */ React7.createElement(Text7, { color: "gray" }, "|")), /* @__PURE__ */ React7.createElement(Text7, { dimColor: true }, "(Press Enter to save, Esc to cancel)"));
|
|
191063
|
-
}
|
|
191064
|
-
async function secretsSetCommand(secretName) {
|
|
191065
|
-
if (!secretName) {
|
|
191066
|
-
console.error("Error: Secret name required");
|
|
191067
|
-
console.error("Usage: specific secrets set <name>");
|
|
191068
|
-
process.exit(1);
|
|
191069
|
-
}
|
|
191070
|
-
render7(/* @__PURE__ */ React7.createElement(SetSecretUI, { secretName }));
|
|
191071
|
-
}
|
|
191072
|
-
async function secretsCommand(action, secretName) {
|
|
191073
|
-
if (!action) {
|
|
191074
|
-
console.error("Usage: specific secrets <command>");
|
|
191075
|
-
console.error("");
|
|
191076
|
-
console.error("Commands:");
|
|
191077
|
-
console.error(" set <name> Set a secret value");
|
|
191078
|
-
process.exit(1);
|
|
191079
|
-
}
|
|
191080
|
-
if (action === "set") {
|
|
191081
|
-
if (!secretName) {
|
|
191082
|
-
console.error("Error: Secret name required");
|
|
191083
|
-
console.error("Usage: specific secrets set <name>");
|
|
191084
|
-
process.exit(1);
|
|
191085
|
-
}
|
|
191086
|
-
await secretsSetCommand(secretName);
|
|
191439
|
+
render6(/* @__PURE__ */ React8.createElement(CleanUI, { instanceKey }));
|
|
191087
191440
|
} else {
|
|
191088
|
-
|
|
191089
|
-
console.error("Usage: specific secrets set <name>");
|
|
191090
|
-
process.exit(1);
|
|
191091
|
-
}
|
|
191092
|
-
}
|
|
191093
|
-
|
|
191094
|
-
// src/commands/config.tsx
|
|
191095
|
-
import React8, { useState as useState8, useEffect as useEffect8 } from "react";
|
|
191096
|
-
import { render as render8, Text as Text8, Box as Box8, useInput as useInput5, useApp as useApp6 } from "ink";
|
|
191097
|
-
import * as fs25 from "fs";
|
|
191098
|
-
var HEADER_COMMENT2 = "# Configuration values for this project\n# These values override defaults defined in specific.hcl\n";
|
|
191099
|
-
function SetConfigUI({ configName, initialValue }) {
|
|
191100
|
-
const { exit } = useApp6();
|
|
191101
|
-
const [value, setValue] = useState8(initialValue ?? "");
|
|
191102
|
-
const [done, setDone] = useState8(false);
|
|
191103
|
-
const [error, setError] = useState8(null);
|
|
191104
|
-
useInput5((input, key) => {
|
|
191105
|
-
if (done) return;
|
|
191106
|
-
if (key.return) {
|
|
191107
|
-
if (value.trim() === "") {
|
|
191108
|
-
setError("Config value cannot be empty");
|
|
191109
|
-
return;
|
|
191110
|
-
}
|
|
191111
|
-
try {
|
|
191112
|
-
const escapedValue = value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
191113
|
-
const hclLine = `${configName} = "${escapedValue}"`;
|
|
191114
|
-
let content = "";
|
|
191115
|
-
let hasHeader = false;
|
|
191116
|
-
if (fs25.existsSync(CONFIG_FILE)) {
|
|
191117
|
-
content = fs25.readFileSync(CONFIG_FILE, "utf-8");
|
|
191118
|
-
hasHeader = content.startsWith("#");
|
|
191119
|
-
const lines = content.split("\n");
|
|
191120
|
-
const newLines = [];
|
|
191121
|
-
let found = false;
|
|
191122
|
-
const pattern = new RegExp(`^${configName}\\s*=\\s*"`);
|
|
191123
|
-
for (const line of lines) {
|
|
191124
|
-
if (pattern.test(line.trim())) {
|
|
191125
|
-
newLines.push(hclLine);
|
|
191126
|
-
found = true;
|
|
191127
|
-
} else {
|
|
191128
|
-
newLines.push(line);
|
|
191129
|
-
}
|
|
191130
|
-
}
|
|
191131
|
-
if (found) {
|
|
191132
|
-
fs25.writeFileSync(CONFIG_FILE, newLines.join("\n"));
|
|
191133
|
-
setDone(true);
|
|
191134
|
-
return;
|
|
191135
|
-
}
|
|
191136
|
-
}
|
|
191137
|
-
let newContent = "";
|
|
191138
|
-
if (!hasHeader && !content) {
|
|
191139
|
-
newContent = HEADER_COMMENT2 + "\n";
|
|
191140
|
-
} else if (content) {
|
|
191141
|
-
newContent = content.endsWith("\n") ? content : content + "\n";
|
|
191142
|
-
}
|
|
191143
|
-
newContent += `${hclLine}
|
|
191144
|
-
`;
|
|
191145
|
-
fs25.writeFileSync(CONFIG_FILE, newContent);
|
|
191146
|
-
setDone(true);
|
|
191147
|
-
} catch (err) {
|
|
191148
|
-
setError(err instanceof Error ? err.message : String(err));
|
|
191149
|
-
}
|
|
191150
|
-
} else if (key.backspace || key.delete) {
|
|
191151
|
-
setValue((prev) => prev.slice(0, -1));
|
|
191152
|
-
} else if (key.escape) {
|
|
191153
|
-
exit();
|
|
191154
|
-
} else if (!key.ctrl && !key.meta && input) {
|
|
191155
|
-
setValue((prev) => prev + input);
|
|
191156
|
-
}
|
|
191157
|
-
});
|
|
191158
|
-
useEffect8(() => {
|
|
191159
|
-
if (done) {
|
|
191160
|
-
const timer = setTimeout(() => exit(), 50);
|
|
191161
|
-
return () => clearTimeout(timer);
|
|
191162
|
-
}
|
|
191163
|
-
}, [done, exit]);
|
|
191164
|
-
if (error) {
|
|
191165
|
-
return /* @__PURE__ */ React8.createElement(Text8, { color: "red" }, "Error: ", error);
|
|
191166
|
-
}
|
|
191167
|
-
if (done) {
|
|
191168
|
-
return /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column" }, /* @__PURE__ */ React8.createElement(Text8, { color: "green" }, "Config '", configName, "' saved to ", CONFIG_FILE));
|
|
191169
|
-
}
|
|
191170
|
-
return /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column" }, /* @__PURE__ */ React8.createElement(Text8, null, "Enter value for config '", configName, "':"), /* @__PURE__ */ React8.createElement(Box8, null, /* @__PURE__ */ React8.createElement(Text8, { color: "cyan" }, "> "), /* @__PURE__ */ React8.createElement(Text8, null, value), /* @__PURE__ */ React8.createElement(Text8, { color: "gray" }, "|")), /* @__PURE__ */ React8.createElement(Text8, { dimColor: true }, "(Press Enter to save, Esc to cancel)"));
|
|
191171
|
-
}
|
|
191172
|
-
async function configSetCommand(configName, configValue) {
|
|
191173
|
-
if (!configName) {
|
|
191174
|
-
console.error("Error: Config name required");
|
|
191175
|
-
console.error("Usage: specific config set <name> [value]");
|
|
191176
|
-
process.exit(1);
|
|
191177
|
-
}
|
|
191178
|
-
if (configValue !== void 0) {
|
|
191179
|
-
try {
|
|
191180
|
-
const escapedValue = configValue.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
191181
|
-
const hclLine = `${configName} = "${escapedValue}"`;
|
|
191182
|
-
let content = "";
|
|
191183
|
-
let hasHeader = false;
|
|
191184
|
-
if (fs25.existsSync(CONFIG_FILE)) {
|
|
191185
|
-
content = fs25.readFileSync(CONFIG_FILE, "utf-8");
|
|
191186
|
-
hasHeader = content.startsWith("#");
|
|
191187
|
-
const lines = content.split("\n");
|
|
191188
|
-
const newLines = [];
|
|
191189
|
-
let found = false;
|
|
191190
|
-
const pattern = new RegExp(`^${configName}\\s*=\\s*"`);
|
|
191191
|
-
for (const line of lines) {
|
|
191192
|
-
if (pattern.test(line.trim())) {
|
|
191193
|
-
newLines.push(hclLine);
|
|
191194
|
-
found = true;
|
|
191195
|
-
} else {
|
|
191196
|
-
newLines.push(line);
|
|
191197
|
-
}
|
|
191198
|
-
}
|
|
191199
|
-
if (found) {
|
|
191200
|
-
fs25.writeFileSync(CONFIG_FILE, newLines.join("\n"));
|
|
191201
|
-
console.log(`Config '${configName}' saved to ${CONFIG_FILE}`);
|
|
191202
|
-
return;
|
|
191203
|
-
}
|
|
191204
|
-
}
|
|
191205
|
-
let newContent = "";
|
|
191206
|
-
if (!hasHeader && !content) {
|
|
191207
|
-
newContent = HEADER_COMMENT2 + "\n";
|
|
191208
|
-
} else if (content) {
|
|
191209
|
-
newContent = content.endsWith("\n") ? content : content + "\n";
|
|
191210
|
-
}
|
|
191211
|
-
newContent += `${hclLine}
|
|
191212
|
-
`;
|
|
191213
|
-
fs25.writeFileSync(CONFIG_FILE, newContent);
|
|
191214
|
-
console.log(`Config '${configName}' saved to ${CONFIG_FILE}`);
|
|
191215
|
-
} catch (err) {
|
|
191216
|
-
console.error("Error:", err instanceof Error ? err.message : String(err));
|
|
191217
|
-
process.exit(1);
|
|
191218
|
-
}
|
|
191219
|
-
return;
|
|
191220
|
-
}
|
|
191221
|
-
render8(/* @__PURE__ */ React8.createElement(SetConfigUI, { configName }));
|
|
191222
|
-
}
|
|
191223
|
-
async function configCommand(action, configName, configValue) {
|
|
191224
|
-
if (!action) {
|
|
191225
|
-
console.error("Usage: specific config <command>");
|
|
191226
|
-
console.error("");
|
|
191227
|
-
console.error("Commands:");
|
|
191228
|
-
console.error(" set <name> [value] Set a config value");
|
|
191229
|
-
process.exit(1);
|
|
191230
|
-
}
|
|
191231
|
-
if (action === "set") {
|
|
191232
|
-
if (!configName) {
|
|
191233
|
-
console.error("Error: Config name required");
|
|
191234
|
-
console.error("Usage: specific config set <name> [value]");
|
|
191235
|
-
process.exit(1);
|
|
191236
|
-
}
|
|
191237
|
-
await configSetCommand(configName, configValue);
|
|
191238
|
-
} else {
|
|
191239
|
-
console.error(`Unknown command: ${action}`);
|
|
191240
|
-
console.error("Usage: specific config set <name> [value]");
|
|
191241
|
-
process.exit(1);
|
|
191441
|
+
render6(/* @__PURE__ */ React8.createElement(CleanUI, null));
|
|
191242
191442
|
}
|
|
191243
191443
|
}
|
|
191244
191444
|
|
|
191245
191445
|
// src/commands/login.tsx
|
|
191246
|
-
|
|
191247
|
-
|
|
191248
|
-
|
|
191249
|
-
|
|
191250
|
-
const { exit } = useApp7();
|
|
191251
|
-
useEffect9(() => {
|
|
191252
|
-
const timer = setTimeout(() => exit(), 100);
|
|
191253
|
-
return () => clearTimeout(timer);
|
|
191254
|
-
}, [exit]);
|
|
191255
|
-
return /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column" }, /* @__PURE__ */ React9.createElement(Text9, { color: "green" }, "Already logged in."), /* @__PURE__ */ React9.createElement(Text9, { dimColor: true }, "Credentials saved to ~/.specific/credentials.json"));
|
|
191256
|
-
}
|
|
191257
|
-
function CheckingUI() {
|
|
191258
|
-
return /* @__PURE__ */ React9.createElement(Box9, null, /* @__PURE__ */ React9.createElement(Text9, { color: "blue" }, /* @__PURE__ */ React9.createElement(Spinner7, { type: "dots" })), /* @__PURE__ */ React9.createElement(Text9, null, " Checking login status..."));
|
|
191259
|
-
}
|
|
191260
|
-
function LoginUI() {
|
|
191261
|
-
const { exit } = useApp7();
|
|
191262
|
-
const [checking, setChecking] = useState9(true);
|
|
191263
|
-
const [alreadyLoggedIn, setAlreadyLoggedIn] = useState9(false);
|
|
191264
|
-
useEffect9(() => {
|
|
191265
|
-
if (isLoggedIn()) {
|
|
191266
|
-
setAlreadyLoggedIn(true);
|
|
191267
|
-
}
|
|
191268
|
-
setChecking(false);
|
|
191269
|
-
}, []);
|
|
191270
|
-
useEffect9(() => {
|
|
191271
|
-
if (checking || alreadyLoggedIn) return;
|
|
191272
|
-
async function doLogin() {
|
|
191273
|
-
const result = await performLogin();
|
|
191274
|
-
if (!result.success) {
|
|
191275
|
-
process.exitCode = 1;
|
|
191276
|
-
}
|
|
191277
|
-
exit();
|
|
191278
|
-
}
|
|
191279
|
-
doLogin();
|
|
191280
|
-
}, [checking, alreadyLoggedIn, exit]);
|
|
191281
|
-
if (checking) {
|
|
191282
|
-
return /* @__PURE__ */ React9.createElement(CheckingUI, null);
|
|
191446
|
+
async function loginCommand() {
|
|
191447
|
+
if (isLoggedIn()) {
|
|
191448
|
+
console.log("Already logged in.");
|
|
191449
|
+
return;
|
|
191283
191450
|
}
|
|
191284
|
-
|
|
191285
|
-
|
|
191451
|
+
const result = await performLogin();
|
|
191452
|
+
if (!result.success) {
|
|
191453
|
+
process.exitCode = 1;
|
|
191286
191454
|
}
|
|
191287
|
-
return null;
|
|
191288
|
-
}
|
|
191289
|
-
function loginCommand() {
|
|
191290
|
-
render9(/* @__PURE__ */ React9.createElement(LoginUI, null));
|
|
191291
191455
|
}
|
|
191292
191456
|
|
|
191293
191457
|
// src/commands/logout.tsx
|
|
191294
|
-
import
|
|
191295
|
-
import { render as
|
|
191458
|
+
import React9, { useState as useState8, useEffect as useEffect6 } from "react";
|
|
191459
|
+
import { render as render7, Text as Text9, useApp as useApp4 } from "ink";
|
|
191296
191460
|
function LogoutUI() {
|
|
191297
|
-
const { exit } =
|
|
191298
|
-
const [state, setState] =
|
|
191461
|
+
const { exit } = useApp4();
|
|
191462
|
+
const [state, setState] = useState8({
|
|
191299
191463
|
phase: "checking"
|
|
191300
191464
|
});
|
|
191301
|
-
|
|
191465
|
+
useEffect6(() => {
|
|
191302
191466
|
if (state.phase !== "checking") return;
|
|
191303
191467
|
if (!isLoggedIn()) {
|
|
191304
191468
|
setState({ phase: "not-logged-in" });
|
|
@@ -191307,29 +191471,29 @@ function LogoutUI() {
|
|
|
191307
191471
|
clearUserCredentials();
|
|
191308
191472
|
setState({ phase: "done" });
|
|
191309
191473
|
}, [state.phase]);
|
|
191310
|
-
|
|
191474
|
+
useEffect6(() => {
|
|
191311
191475
|
if (state.phase === "done" || state.phase === "not-logged-in") {
|
|
191312
191476
|
const timer = setTimeout(() => exit(), 100);
|
|
191313
191477
|
return () => clearTimeout(timer);
|
|
191314
191478
|
}
|
|
191315
191479
|
}, [state.phase, exit]);
|
|
191316
191480
|
if (state.phase === "not-logged-in") {
|
|
191317
|
-
return /* @__PURE__ */
|
|
191481
|
+
return /* @__PURE__ */ React9.createElement(Text9, { dimColor: true }, "Not logged in.");
|
|
191318
191482
|
}
|
|
191319
191483
|
if (state.phase === "done") {
|
|
191320
|
-
return /* @__PURE__ */
|
|
191484
|
+
return /* @__PURE__ */ React9.createElement(Text9, { color: "green" }, "Logged out successfully.");
|
|
191321
191485
|
}
|
|
191322
|
-
return /* @__PURE__ */
|
|
191486
|
+
return /* @__PURE__ */ React9.createElement(Text9, null, "Logging out...");
|
|
191323
191487
|
}
|
|
191324
191488
|
function logoutCommand() {
|
|
191325
|
-
|
|
191489
|
+
render7(/* @__PURE__ */ React9.createElement(LogoutUI, null));
|
|
191326
191490
|
}
|
|
191327
191491
|
|
|
191328
191492
|
// src/cli.tsx
|
|
191329
191493
|
var program = new Command();
|
|
191330
191494
|
var env = "production";
|
|
191331
191495
|
var envLabel = env !== "production" ? `[${env.toUpperCase()}] ` : "";
|
|
191332
|
-
program.name("specific").description(`${envLabel}Infrastructure-as-code for coding agents`).version("0.1.
|
|
191496
|
+
program.name("specific").description(`${envLabel}Infrastructure-as-code for coding agents`).version("0.1.44").enablePositionalOptions();
|
|
191333
191497
|
program.command("init").description("Initialize project for use with a coding agent").action(initCommand);
|
|
191334
191498
|
program.command("docs [topic]").description("Fetch LLM-optimized documentation").action(docsCommand);
|
|
191335
191499
|
program.command("check").description("Validate specific.hcl configuration").action(checkCommand);
|
|
@@ -191352,8 +191516,6 @@ program.command("psql [database]").description("Connect to a running Postgres da
|
|
|
191352
191516
|
program.command("clean").description("Remove .specific directory for a clean slate").option("-k, --key <key>", "Clean only the specified dev environment key").action((options2) => {
|
|
191353
191517
|
cleanCommand(options2.key);
|
|
191354
191518
|
});
|
|
191355
|
-
program.command("secrets [action] [name]").description("Manage secrets").action(secretsCommand);
|
|
191356
|
-
program.command("config [action] [name] [value]").description("Manage configuration values").action(configCommand);
|
|
191357
191519
|
program.command("login").description("Log in to Specific").action(loginCommand);
|
|
191358
191520
|
program.command("logout").description("Log out of Specific").action(logoutCommand);
|
|
191359
191521
|
var commandName = process.argv[2] || "help";
|