@specific.dev/cli 0.1.114 → 0.1.115
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.!KGRlZmF1bHQp.__PAGE__.txt +1 -1
- package/dist/admin/__next.!KGRlZmF1bHQp.txt +1 -1
- package/dist/admin/__next._full.txt +1 -1
- package/dist/admin/__next._head.txt +1 -1
- package/dist/admin/__next._index.txt +1 -1
- package/dist/admin/__next._tree.txt +1 -1
- package/dist/admin/_not-found/__next._full.txt +1 -1
- package/dist/admin/_not-found/__next._head.txt +1 -1
- package/dist/admin/_not-found/__next._index.txt +1 -1
- package/dist/admin/_not-found/__next._not-found.__PAGE__.txt +1 -1
- package/dist/admin/_not-found/__next._not-found.txt +1 -1
- package/dist/admin/_not-found/__next._tree.txt +1 -1
- package/dist/admin/_not-found/index.html +1 -1
- package/dist/admin/_not-found/index.txt +1 -1
- package/dist/admin/databases/__next.!KGRlZmF1bHQp.databases.__PAGE__.txt +1 -1
- package/dist/admin/databases/__next.!KGRlZmF1bHQp.databases.txt +1 -1
- package/dist/admin/databases/__next.!KGRlZmF1bHQp.txt +1 -1
- package/dist/admin/databases/__next._full.txt +1 -1
- package/dist/admin/databases/__next._head.txt +1 -1
- package/dist/admin/databases/__next._index.txt +1 -1
- package/dist/admin/databases/__next._tree.txt +1 -1
- package/dist/admin/databases/index.html +1 -1
- package/dist/admin/databases/index.txt +1 -1
- package/dist/admin/fullscreen/__next._full.txt +1 -1
- package/dist/admin/fullscreen/__next._head.txt +1 -1
- package/dist/admin/fullscreen/__next._index.txt +1 -1
- package/dist/admin/fullscreen/__next._tree.txt +1 -1
- package/dist/admin/fullscreen/__next.fullscreen.__PAGE__.txt +1 -1
- package/dist/admin/fullscreen/__next.fullscreen.txt +1 -1
- package/dist/admin/fullscreen/databases/__next._full.txt +1 -1
- package/dist/admin/fullscreen/databases/__next._head.txt +1 -1
- package/dist/admin/fullscreen/databases/__next._index.txt +1 -1
- package/dist/admin/fullscreen/databases/__next._tree.txt +1 -1
- package/dist/admin/fullscreen/databases/__next.fullscreen.databases.__PAGE__.txt +1 -1
- package/dist/admin/fullscreen/databases/__next.fullscreen.databases.txt +1 -1
- package/dist/admin/fullscreen/databases/__next.fullscreen.txt +1 -1
- package/dist/admin/fullscreen/databases/index.html +1 -1
- package/dist/admin/fullscreen/databases/index.txt +1 -1
- package/dist/admin/fullscreen/index.html +1 -1
- package/dist/admin/fullscreen/index.txt +1 -1
- package/dist/admin/index.html +1 -1
- package/dist/admin/index.txt +1 -1
- package/dist/admin/mail/__next.!KGRlZmF1bHQp.mail.__PAGE__.txt +1 -1
- package/dist/admin/mail/__next.!KGRlZmF1bHQp.mail.txt +1 -1
- package/dist/admin/mail/__next.!KGRlZmF1bHQp.txt +1 -1
- package/dist/admin/mail/__next._full.txt +1 -1
- package/dist/admin/mail/__next._head.txt +1 -1
- package/dist/admin/mail/__next._index.txt +1 -1
- package/dist/admin/mail/__next._tree.txt +1 -1
- package/dist/admin/mail/index.html +1 -1
- package/dist/admin/mail/index.txt +1 -1
- package/dist/admin/workflows/__next.!KGRlZmF1bHQp.txt +1 -1
- package/dist/admin/workflows/__next.!KGRlZmF1bHQp.workflows.__PAGE__.txt +1 -1
- package/dist/admin/workflows/__next.!KGRlZmF1bHQp.workflows.txt +1 -1
- package/dist/admin/workflows/__next._full.txt +1 -1
- package/dist/admin/workflows/__next._head.txt +1 -1
- package/dist/admin/workflows/__next._index.txt +1 -1
- package/dist/admin/workflows/__next._tree.txt +1 -1
- package/dist/admin/workflows/index.html +1 -1
- package/dist/admin/workflows/index.txt +1 -1
- package/dist/cli.js +186 -103
- package/package.json +1 -1
- /package/dist/admin/_next/static/{bgRGrZnID0BykUNK10yK_ → 3wOysvI433uU7Czi4vdl0}/_buildManifest.js +0 -0
- /package/dist/admin/_next/static/{bgRGrZnID0BykUNK10yK_ → 3wOysvI433uU7Czi4vdl0}/_clientMiddlewareManifest.json +0 -0
- /package/dist/admin/_next/static/{bgRGrZnID0BykUNK10yK_ → 3wOysvI433uU7Czi4vdl0}/_ssgManifest.js +0 -0
package/dist/cli.js
CHANGED
|
@@ -367514,8 +367514,14 @@ var ApiClient = class {
|
|
|
367514
367514
|
Authorization: `Bearer ${token}`
|
|
367515
367515
|
};
|
|
367516
367516
|
}
|
|
367517
|
-
async createDeployment(projectId, environment) {
|
|
367518
|
-
const requestBody = {
|
|
367517
|
+
async createDeployment(projectId, environment, options2) {
|
|
367518
|
+
const requestBody = {
|
|
367519
|
+
projectId,
|
|
367520
|
+
environment,
|
|
367521
|
+
...options2?.triggeredBy && { triggeredBy: options2.triggeredBy },
|
|
367522
|
+
...options2?.gitCommitSha && { gitCommitSha: options2.gitCommitSha },
|
|
367523
|
+
...options2?.gitBranch && { gitBranch: options2.gitBranch }
|
|
367524
|
+
};
|
|
367519
367525
|
writeLog("api", `POST ${this.baseUrl}/deployments`);
|
|
367520
367526
|
writeLog("api", `Request body: ${JSON.stringify(requestBody)}`);
|
|
367521
367527
|
const response = await fetch(`${this.baseUrl}/deployments`, {
|
|
@@ -367862,9 +367868,9 @@ var SpecificClient = class {
|
|
|
367862
367868
|
return await this.client.getMe();
|
|
367863
367869
|
}
|
|
367864
367870
|
// --- Deployments ---
|
|
367865
|
-
async createDeployment(projectId, environment) {
|
|
367871
|
+
async createDeployment(projectId, environment, options2) {
|
|
367866
367872
|
return toDeployment(
|
|
367867
|
-
await this.client.createDeployment(projectId, environment)
|
|
367873
|
+
await this.client.createDeployment(projectId, environment, options2)
|
|
367868
367874
|
);
|
|
367869
367875
|
}
|
|
367870
367876
|
async uploadTarball(deploymentId, tarball, appPath) {
|
|
@@ -369458,7 +369464,7 @@ async function parseLocalFile(content) {
|
|
|
369458
369464
|
if (block && typeof block === "object") {
|
|
369459
369465
|
for (const [key, value] of Object.entries(block)) {
|
|
369460
369466
|
if (typeof value === "string") {
|
|
369461
|
-
secrets.set(key, value);
|
|
369467
|
+
secrets.set(key, value.trimEnd());
|
|
369462
369468
|
}
|
|
369463
369469
|
}
|
|
369464
369470
|
}
|
|
@@ -369470,7 +369476,7 @@ async function parseLocalFile(content) {
|
|
|
369470
369476
|
if (block && typeof block === "object") {
|
|
369471
369477
|
for (const [key, value] of Object.entries(block)) {
|
|
369472
369478
|
if (typeof value === "string") {
|
|
369473
|
-
configs.set(key, value);
|
|
369479
|
+
configs.set(key, value.trimEnd());
|
|
369474
369480
|
}
|
|
369475
369481
|
}
|
|
369476
369482
|
}
|
|
@@ -369485,57 +369491,42 @@ async function loadLocal() {
|
|
|
369485
369491
|
const content = await readFile(LOCAL_FILE, "utf-8");
|
|
369486
369492
|
return await parseLocalFile(content);
|
|
369487
369493
|
}
|
|
369488
|
-
function
|
|
369489
|
-
|
|
369494
|
+
function formatHclValue(value) {
|
|
369495
|
+
if (value.includes("\n")) {
|
|
369496
|
+
return `<<-EOT
|
|
369497
|
+
${value}
|
|
369498
|
+
EOT`;
|
|
369499
|
+
}
|
|
369500
|
+
const escaped = value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
369501
|
+
return `"${escaped}"`;
|
|
369490
369502
|
}
|
|
369491
|
-
function
|
|
369492
|
-
const
|
|
369493
|
-
const
|
|
369494
|
-
|
|
369495
|
-
|
|
369496
|
-
|
|
369497
|
-
|
|
369498
|
-
const keyRegex = new RegExp(`^(\\s*)${key}\\s*=\\s*"[^"]*"\\s*$`, "m");
|
|
369499
|
-
const keyMatch = blockContent.match(keyRegex);
|
|
369500
|
-
if (keyMatch) {
|
|
369501
|
-
const updatedBlockContent = blockContent.replace(keyRegex, newLine);
|
|
369502
|
-
return content.replace(blockRegex, `$1${updatedBlockContent}$3`);
|
|
369503
|
-
} else {
|
|
369504
|
-
const trimmedContent = blockContent.trimEnd();
|
|
369505
|
-
const newBlockContent = trimmedContent ? `${trimmedContent}
|
|
369506
|
-
${newLine}
|
|
369507
|
-
` : `
|
|
369508
|
-
${newLine}
|
|
369509
|
-
`;
|
|
369510
|
-
return content.replace(blockRegex, `$1${newBlockContent}$3`);
|
|
369511
|
-
}
|
|
369512
|
-
} else {
|
|
369513
|
-
const newBlock = `${blockName} {
|
|
369514
|
-
${newLine}
|
|
369503
|
+
function serializeBlock(blockName, entries) {
|
|
369504
|
+
const lines = [`${blockName} {`];
|
|
369505
|
+
for (const [key, value] of entries) {
|
|
369506
|
+
lines.push(` ${key} = ${formatHclValue(value)}`);
|
|
369507
|
+
}
|
|
369508
|
+
lines.push("}");
|
|
369509
|
+
return lines.join("\n");
|
|
369515
369510
|
}
|
|
369516
|
-
|
|
369517
|
-
|
|
369511
|
+
function serializeLocalFile(secrets, configs) {
|
|
369512
|
+
const blocks = [];
|
|
369513
|
+
if (secrets.size > 0) {
|
|
369514
|
+
blocks.push(serializeBlock("secrets", secrets));
|
|
369515
|
+
}
|
|
369516
|
+
if (configs.size > 0) {
|
|
369517
|
+
blocks.push(serializeBlock("config", configs));
|
|
369518
369518
|
}
|
|
369519
|
+
return HEADER_COMMENT + blocks.join("\n\n") + "\n";
|
|
369519
369520
|
}
|
|
369520
369521
|
async function saveLocalSecret(name, value) {
|
|
369521
|
-
|
|
369522
|
-
|
|
369523
|
-
|
|
369524
|
-
} else {
|
|
369525
|
-
content = HEADER_COMMENT;
|
|
369526
|
-
}
|
|
369527
|
-
content = updateBlockValue(content, "secrets", name, value);
|
|
369528
|
-
await writeFile(LOCAL_FILE, content);
|
|
369522
|
+
const { secrets, configs } = existsSync5(LOCAL_FILE) ? await parseLocalFile(await readFile(LOCAL_FILE, "utf-8")) : { secrets: /* @__PURE__ */ new Map(), configs: /* @__PURE__ */ new Map() };
|
|
369523
|
+
secrets.set(name, value);
|
|
369524
|
+
await writeFile(LOCAL_FILE, serializeLocalFile(secrets, configs));
|
|
369529
369525
|
}
|
|
369530
369526
|
async function saveLocalConfig(name, value) {
|
|
369531
|
-
|
|
369532
|
-
|
|
369533
|
-
|
|
369534
|
-
} else {
|
|
369535
|
-
content = HEADER_COMMENT;
|
|
369536
|
-
}
|
|
369537
|
-
content = updateBlockValue(content, "config", name, value);
|
|
369538
|
-
await writeFile(LOCAL_FILE, content);
|
|
369527
|
+
const { secrets, configs } = existsSync5(LOCAL_FILE) ? await parseLocalFile(await readFile(LOCAL_FILE, "utf-8")) : { secrets: /* @__PURE__ */ new Map(), configs: /* @__PURE__ */ new Map() };
|
|
369528
|
+
configs.set(name, value);
|
|
369529
|
+
await writeFile(LOCAL_FILE, serializeLocalFile(secrets, configs));
|
|
369539
369530
|
}
|
|
369540
369531
|
function appendSearchPathToUrl(baseUrl, searchPath) {
|
|
369541
369532
|
const url = new URL(baseUrl);
|
|
@@ -373287,7 +373278,7 @@ function trackEvent(event, properties) {
|
|
|
373287
373278
|
event,
|
|
373288
373279
|
properties: {
|
|
373289
373280
|
...properties,
|
|
373290
|
-
cli_version: "0.1.
|
|
373281
|
+
cli_version: "0.1.115",
|
|
373291
373282
|
platform: process.platform,
|
|
373292
373283
|
node_version: process.version,
|
|
373293
373284
|
project_id: getProjectId()
|
|
@@ -374520,53 +374511,113 @@ function checkCommand() {
|
|
|
374520
374511
|
}
|
|
374521
374512
|
|
|
374522
374513
|
// src/commands/dev.tsx
|
|
374523
|
-
import React6, { useState as useState5, useEffect as
|
|
374514
|
+
import React6, { useState as useState5, useEffect as useEffect5, useRef as useRef3 } from "react";
|
|
374524
374515
|
import { render as render4, Text as Text6, Box as Box6, useApp as useApp2, Static } from "ink";
|
|
374525
374516
|
import Spinner3 from "ink-spinner";
|
|
374526
374517
|
import { Readable as Readable2 } from "stream";
|
|
374527
374518
|
|
|
374528
374519
|
// src/lib/ui/SecretInput.tsx
|
|
374529
|
-
import React4, { useState as useState3 } from "react";
|
|
374520
|
+
import React4, { useState as useState3, useRef, useCallback, useEffect as useEffect3 } from "react";
|
|
374530
374521
|
import { Box as Box4, Text as Text4, useInput as useInput2 } from "ink";
|
|
374522
|
+
var PASTE_DETECT_DELAY_MS = 100;
|
|
374531
374523
|
function SecretInput({ secretName, onSubmit, onCancel }) {
|
|
374532
374524
|
const [value, setValue] = useState3("");
|
|
374525
|
+
const valueRef = useRef("");
|
|
374526
|
+
const submitTimer = useRef(null);
|
|
374527
|
+
useEffect3(() => {
|
|
374528
|
+
valueRef.current = value;
|
|
374529
|
+
}, [value]);
|
|
374530
|
+
const scheduleSubmit = useCallback(() => {
|
|
374531
|
+
if (submitTimer.current) {
|
|
374532
|
+
clearTimeout(submitTimer.current);
|
|
374533
|
+
}
|
|
374534
|
+
submitTimer.current = setTimeout(() => {
|
|
374535
|
+
submitTimer.current = null;
|
|
374536
|
+
if (valueRef.current.trim() !== "") {
|
|
374537
|
+
onSubmit(valueRef.current);
|
|
374538
|
+
}
|
|
374539
|
+
}, PASTE_DETECT_DELAY_MS);
|
|
374540
|
+
}, [onSubmit]);
|
|
374541
|
+
const cancelSubmit = useCallback(() => {
|
|
374542
|
+
if (submitTimer.current) {
|
|
374543
|
+
clearTimeout(submitTimer.current);
|
|
374544
|
+
submitTimer.current = null;
|
|
374545
|
+
setValue((prev) => prev + "\n");
|
|
374546
|
+
}
|
|
374547
|
+
}, []);
|
|
374548
|
+
useEffect3(() => {
|
|
374549
|
+
return () => {
|
|
374550
|
+
if (submitTimer.current) clearTimeout(submitTimer.current);
|
|
374551
|
+
};
|
|
374552
|
+
}, []);
|
|
374533
374553
|
useInput2((input, key) => {
|
|
374534
374554
|
if (key.return) {
|
|
374535
|
-
|
|
374536
|
-
onSubmit(value);
|
|
374537
|
-
}
|
|
374555
|
+
scheduleSubmit();
|
|
374538
374556
|
} else if (key.escape) {
|
|
374539
374557
|
onCancel();
|
|
374540
374558
|
} else if (key.backspace || key.delete) {
|
|
374559
|
+
cancelSubmit();
|
|
374541
374560
|
setValue((prev) => prev.slice(0, -1));
|
|
374542
374561
|
} else if (!key.ctrl && !key.meta && input) {
|
|
374562
|
+
cancelSubmit();
|
|
374543
374563
|
setValue((prev) => prev + input);
|
|
374544
374564
|
}
|
|
374545
374565
|
});
|
|
374546
|
-
|
|
374566
|
+
const lineCount = value.split("\n").length;
|
|
374567
|
+
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 ? lineCount > 1 ? `[${lineCount} lines, ${value.length} chars]` : "*".repeat(value.length) : ""), /* @__PURE__ */ React4.createElement(Text4, { color: "gray" }, "|")), /* @__PURE__ */ React4.createElement(Text4, { dimColor: true }, "(Press Enter to save, Esc to cancel)"));
|
|
374547
374568
|
}
|
|
374548
374569
|
|
|
374549
374570
|
// src/lib/ui/ConfigInput.tsx
|
|
374550
|
-
import React5, { useState as useState4 } from "react";
|
|
374571
|
+
import React5, { useState as useState4, useRef as useRef2, useCallback as useCallback2, useEffect as useEffect4 } from "react";
|
|
374551
374572
|
import { Box as Box5, Text as Text5, useInput as useInput3 } from "ink";
|
|
374573
|
+
var PASTE_DETECT_DELAY_MS2 = 100;
|
|
374552
374574
|
function ConfigInput({ configName, defaultValue, onSubmit, onCancel }) {
|
|
374553
374575
|
const [value, setValue] = useState4("");
|
|
374554
|
-
|
|
374555
|
-
|
|
374556
|
-
|
|
374557
|
-
|
|
374576
|
+
const valueRef = useRef2("");
|
|
374577
|
+
const submitTimer = useRef2(null);
|
|
374578
|
+
useEffect4(() => {
|
|
374579
|
+
valueRef.current = value;
|
|
374580
|
+
}, [value]);
|
|
374581
|
+
const scheduleSubmit = useCallback2(() => {
|
|
374582
|
+
if (submitTimer.current) {
|
|
374583
|
+
clearTimeout(submitTimer.current);
|
|
374584
|
+
}
|
|
374585
|
+
submitTimer.current = setTimeout(() => {
|
|
374586
|
+
submitTimer.current = null;
|
|
374587
|
+
if (valueRef.current.trim() !== "") {
|
|
374588
|
+
onSubmit(valueRef.current);
|
|
374558
374589
|
} else if (defaultValue !== void 0) {
|
|
374559
374590
|
onSubmit(defaultValue);
|
|
374560
374591
|
}
|
|
374592
|
+
}, PASTE_DETECT_DELAY_MS2);
|
|
374593
|
+
}, [onSubmit, defaultValue]);
|
|
374594
|
+
const cancelSubmit = useCallback2(() => {
|
|
374595
|
+
if (submitTimer.current) {
|
|
374596
|
+
clearTimeout(submitTimer.current);
|
|
374597
|
+
submitTimer.current = null;
|
|
374598
|
+
setValue((prev) => prev + "\n");
|
|
374599
|
+
}
|
|
374600
|
+
}, []);
|
|
374601
|
+
useEffect4(() => {
|
|
374602
|
+
return () => {
|
|
374603
|
+
if (submitTimer.current) clearTimeout(submitTimer.current);
|
|
374604
|
+
};
|
|
374605
|
+
}, []);
|
|
374606
|
+
useInput3((input, key) => {
|
|
374607
|
+
if (key.return) {
|
|
374608
|
+
scheduleSubmit();
|
|
374561
374609
|
} else if (key.escape) {
|
|
374562
374610
|
onCancel();
|
|
374563
374611
|
} else if (key.backspace || key.delete) {
|
|
374612
|
+
cancelSubmit();
|
|
374564
374613
|
setValue((prev) => prev.slice(0, -1));
|
|
374565
374614
|
} else if (!key.ctrl && !key.meta && input) {
|
|
374615
|
+
cancelSubmit();
|
|
374566
374616
|
setValue((prev) => prev + input);
|
|
374567
374617
|
}
|
|
374568
374618
|
});
|
|
374569
|
-
|
|
374619
|
+
const lineCount = value.split("\n").length;
|
|
374620
|
+
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), defaultValue !== void 0 && /* @__PURE__ */ React5.createElement(Text5, { dimColor: true }, " (default: ", defaultValue, ")"), ":"), /* @__PURE__ */ React5.createElement(Box5, null, /* @__PURE__ */ React5.createElement(Text5, { color: "cyan" }, "> "), /* @__PURE__ */ React5.createElement(Text5, null, lineCount > 1 ? `[${lineCount} lines]` : value), /* @__PURE__ */ React5.createElement(Text5, { color: "gray" }, "|")), /* @__PURE__ */ React5.createElement(Text5, { dimColor: true }, defaultValue !== void 0 ? "(Press Enter to accept default, type to override, Esc to cancel)" : "(Press Enter to save, Esc to cancel)"));
|
|
374570
374621
|
}
|
|
374571
374622
|
|
|
374572
374623
|
// src/commands/dev.tsx
|
|
@@ -374583,8 +374634,8 @@ function DevUI({ instanceKey, tunnelEnabled }) {
|
|
|
374583
374634
|
tunnelUrls: /* @__PURE__ */ new Map(),
|
|
374584
374635
|
tunnelStatus: /* @__PURE__ */ new Map()
|
|
374585
374636
|
});
|
|
374586
|
-
const devEnvRef =
|
|
374587
|
-
const startTimeRef =
|
|
374637
|
+
const devEnvRef = useRef3(null);
|
|
374638
|
+
const startTimeRef = useRef3(null);
|
|
374588
374639
|
const buildColorMap = (config2) => {
|
|
374589
374640
|
const colorMap = /* @__PURE__ */ new Map();
|
|
374590
374641
|
let colorIndex = 0;
|
|
@@ -374610,7 +374661,7 @@ function DevUI({ instanceKey, tunnelEnabled }) {
|
|
|
374610
374661
|
}
|
|
374611
374662
|
return colorMap;
|
|
374612
374663
|
};
|
|
374613
|
-
|
|
374664
|
+
useEffect5(() => {
|
|
374614
374665
|
const devEnv = new DevEnvironment({
|
|
374615
374666
|
projectDir: process.cwd(),
|
|
374616
374667
|
instanceKey,
|
|
@@ -374747,7 +374798,7 @@ function DevUI({ instanceKey, tunnelEnabled }) {
|
|
|
374747
374798
|
devEnvRef.current = null;
|
|
374748
374799
|
};
|
|
374749
374800
|
}, [instanceKey, tunnelEnabled]);
|
|
374750
|
-
|
|
374801
|
+
useEffect5(() => {
|
|
374751
374802
|
const handleSignal = () => {
|
|
374752
374803
|
const devEnv = devEnvRef.current;
|
|
374753
374804
|
if (!devEnv) return;
|
|
@@ -374778,7 +374829,7 @@ function DevUI({ instanceKey, tunnelEnabled }) {
|
|
|
374778
374829
|
process.off("unhandledRejection", handleCrash);
|
|
374779
374830
|
};
|
|
374780
374831
|
}, []);
|
|
374781
|
-
|
|
374832
|
+
useEffect5(() => {
|
|
374782
374833
|
if (state.status === "running" && !startTimeRef.current) {
|
|
374783
374834
|
startTimeRef.current = Date.now();
|
|
374784
374835
|
trackEvent("dev_started");
|
|
@@ -375074,11 +375125,29 @@ function devCommand(instanceKey, tunnelEnabled = false) {
|
|
|
375074
375125
|
|
|
375075
375126
|
// src/commands/deploy.tsx
|
|
375076
375127
|
init_open();
|
|
375077
|
-
import React7, { useState as useState6, useEffect as
|
|
375128
|
+
import React7, { useState as useState6, useEffect as useEffect6, useCallback as useCallback3 } from "react";
|
|
375078
375129
|
import { render as render5, Text as Text7, Box as Box7, useApp as useApp3, useInput as useInput4 } from "ink";
|
|
375079
375130
|
import Spinner4 from "ink-spinner";
|
|
375080
375131
|
import * as fs22 from "fs";
|
|
375081
375132
|
import * as path20 from "path";
|
|
375133
|
+
import { execFileSync as execFileSync2 } from "child_process";
|
|
375134
|
+
function getGitInfo(cwd) {
|
|
375135
|
+
try {
|
|
375136
|
+
const commitSha = execFileSync2("git", ["rev-parse", "HEAD"], {
|
|
375137
|
+
cwd,
|
|
375138
|
+
encoding: "utf-8",
|
|
375139
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
375140
|
+
}).trim();
|
|
375141
|
+
const branch = execFileSync2(
|
|
375142
|
+
"git",
|
|
375143
|
+
["rev-parse", "--abbrev-ref", "HEAD"],
|
|
375144
|
+
{ cwd, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
375145
|
+
).trim();
|
|
375146
|
+
return { commitSha, branch };
|
|
375147
|
+
} catch {
|
|
375148
|
+
return null;
|
|
375149
|
+
}
|
|
375150
|
+
}
|
|
375082
375151
|
function formatBytes(bytes) {
|
|
375083
375152
|
if (bytes < 1024) return `${bytes} B`;
|
|
375084
375153
|
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
@@ -375224,7 +375293,7 @@ function DeployUI({ environment, config }) {
|
|
|
375224
375293
|
const { exit } = useApp3();
|
|
375225
375294
|
const [state, setState] = useState6({ phase: "checking-auth" });
|
|
375226
375295
|
const clientRef = React7.useRef(null);
|
|
375227
|
-
|
|
375296
|
+
useEffect6(() => {
|
|
375228
375297
|
if (state.phase !== "checking-auth") return;
|
|
375229
375298
|
const projectDir = process.cwd();
|
|
375230
375299
|
if (hasProjectId(projectDir)) {
|
|
@@ -375245,7 +375314,7 @@ function DeployUI({ environment, config }) {
|
|
|
375245
375314
|
}
|
|
375246
375315
|
setState({ phase: "logging-in" });
|
|
375247
375316
|
}, [state.phase]);
|
|
375248
|
-
|
|
375317
|
+
useEffect6(() => {
|
|
375249
375318
|
if (state.phase !== "logging-in") return;
|
|
375250
375319
|
let cancelled = false;
|
|
375251
375320
|
async function startLogin() {
|
|
@@ -375306,7 +375375,7 @@ function DeployUI({ environment, config }) {
|
|
|
375306
375375
|
cancelled = true;
|
|
375307
375376
|
};
|
|
375308
375377
|
}, [state.phase]);
|
|
375309
|
-
|
|
375378
|
+
useEffect6(() => {
|
|
375310
375379
|
if (state.phase !== "loading-projects") return;
|
|
375311
375380
|
let cancelled = false;
|
|
375312
375381
|
async function loadProjects() {
|
|
@@ -375339,7 +375408,7 @@ function DeployUI({ environment, config }) {
|
|
|
375339
375408
|
cancelled = true;
|
|
375340
375409
|
};
|
|
375341
375410
|
}, [state.phase]);
|
|
375342
|
-
const handleProjectSelect =
|
|
375411
|
+
const handleProjectSelect = useCallback3(
|
|
375343
375412
|
(project) => {
|
|
375344
375413
|
if ("type" in project && project.type === "new") {
|
|
375345
375414
|
setState((s) => ({ ...s, phase: "entering-name", selectedOrganizationId: project.orgId }));
|
|
@@ -375354,13 +375423,13 @@ function DeployUI({ environment, config }) {
|
|
|
375354
375423
|
},
|
|
375355
375424
|
[]
|
|
375356
375425
|
);
|
|
375357
|
-
const handleNameSubmit =
|
|
375426
|
+
const handleNameSubmit = useCallback3((name) => {
|
|
375358
375427
|
setState((s) => ({ ...s, phase: "creating-project", newProjectName: name }));
|
|
375359
375428
|
}, []);
|
|
375360
|
-
const handleNameCancel =
|
|
375429
|
+
const handleNameCancel = useCallback3(() => {
|
|
375361
375430
|
setState((s) => ({ ...s, phase: "selecting-project" }));
|
|
375362
375431
|
}, []);
|
|
375363
|
-
|
|
375432
|
+
useEffect6(() => {
|
|
375364
375433
|
if (state.phase !== "creating-project" || !state.newProjectName) return;
|
|
375365
375434
|
let cancelled = false;
|
|
375366
375435
|
async function createProject() {
|
|
@@ -375387,7 +375456,7 @@ function DeployUI({ environment, config }) {
|
|
|
375387
375456
|
cancelled = true;
|
|
375388
375457
|
};
|
|
375389
375458
|
}, [state.phase, state.newProjectName]);
|
|
375390
|
-
const handleSecretSubmit =
|
|
375459
|
+
const handleSecretSubmit = useCallback3((value) => {
|
|
375391
375460
|
setState((s) => {
|
|
375392
375461
|
if (!s.missingSecrets || s.currentSecretIndex === void 0) return s;
|
|
375393
375462
|
const currentSecret2 = s.missingSecrets[s.currentSecretIndex];
|
|
@@ -375410,14 +375479,14 @@ function DeployUI({ environment, config }) {
|
|
|
375410
375479
|
};
|
|
375411
375480
|
});
|
|
375412
375481
|
}, []);
|
|
375413
|
-
const handleSecretCancel =
|
|
375482
|
+
const handleSecretCancel = useCallback3(() => {
|
|
375414
375483
|
setState((s) => ({
|
|
375415
375484
|
...s,
|
|
375416
375485
|
phase: "error",
|
|
375417
375486
|
error: "Deployment cancelled - secrets not provided"
|
|
375418
375487
|
}));
|
|
375419
375488
|
}, []);
|
|
375420
|
-
const handleConfigSubmit =
|
|
375489
|
+
const handleConfigSubmit = useCallback3((value) => {
|
|
375421
375490
|
setState((s) => {
|
|
375422
375491
|
if (!s.missingConfigs || s.currentConfigIndex === void 0) return s;
|
|
375423
375492
|
const currentConfig2 = s.missingConfigs[s.currentConfigIndex];
|
|
@@ -375440,14 +375509,14 @@ function DeployUI({ environment, config }) {
|
|
|
375440
375509
|
};
|
|
375441
375510
|
});
|
|
375442
375511
|
}, []);
|
|
375443
|
-
const handleConfigCancel =
|
|
375512
|
+
const handleConfigCancel = useCallback3(() => {
|
|
375444
375513
|
setState((s) => ({
|
|
375445
375514
|
...s,
|
|
375446
375515
|
phase: "error",
|
|
375447
375516
|
error: "Deployment cancelled - configs not provided"
|
|
375448
375517
|
}));
|
|
375449
375518
|
}, []);
|
|
375450
|
-
|
|
375519
|
+
useEffect6(() => {
|
|
375451
375520
|
const {
|
|
375452
375521
|
phase: phase2,
|
|
375453
375522
|
deployment: deployment2,
|
|
@@ -375489,7 +375558,7 @@ function DeployUI({ environment, config }) {
|
|
|
375489
375558
|
}
|
|
375490
375559
|
})();
|
|
375491
375560
|
}, [state]);
|
|
375492
|
-
|
|
375561
|
+
useEffect6(() => {
|
|
375493
375562
|
const {
|
|
375494
375563
|
phase: phase2,
|
|
375495
375564
|
deployment: deployment2,
|
|
@@ -375531,7 +375600,7 @@ function DeployUI({ environment, config }) {
|
|
|
375531
375600
|
}
|
|
375532
375601
|
})();
|
|
375533
375602
|
}, [state]);
|
|
375534
|
-
|
|
375603
|
+
useEffect6(() => {
|
|
375535
375604
|
if (state.phase !== "creating-tarball" || !state.projectId) return;
|
|
375536
375605
|
let cancelled = false;
|
|
375537
375606
|
async function runDeploy() {
|
|
@@ -375567,7 +375636,14 @@ function DeployUI({ environment, config }) {
|
|
|
375567
375636
|
let deployment2;
|
|
375568
375637
|
try {
|
|
375569
375638
|
writeLog("deploy", `Creating deployment for project ${state.projectId}`);
|
|
375570
|
-
|
|
375639
|
+
const gitInfo = getGitInfo(projectDir);
|
|
375640
|
+
deployment2 = await client2.createDeployment(state.projectId, environment, {
|
|
375641
|
+
triggeredBy: "cli",
|
|
375642
|
+
...gitInfo && {
|
|
375643
|
+
gitCommitSha: gitInfo.commitSha,
|
|
375644
|
+
gitBranch: gitInfo.branch
|
|
375645
|
+
}
|
|
375646
|
+
});
|
|
375571
375647
|
writeLog("deploy", `Deployment created: ${deployment2.id}`);
|
|
375572
375648
|
} catch (err) {
|
|
375573
375649
|
const errorMsg = `Failed to create deployment: ${err instanceof Error ? err.message : String(err)}`;
|
|
@@ -375604,7 +375680,7 @@ function DeployUI({ environment, config }) {
|
|
|
375604
375680
|
cancelled = true;
|
|
375605
375681
|
};
|
|
375606
375682
|
}, [state.projectId, environment, config.builds]);
|
|
375607
|
-
|
|
375683
|
+
useEffect6(() => {
|
|
375608
375684
|
if (state.phase !== "pending" || !state.deployment) return;
|
|
375609
375685
|
let pollInterval;
|
|
375610
375686
|
let cancelled = false;
|
|
@@ -375713,7 +375789,7 @@ function DeployUI({ environment, config }) {
|
|
|
375713
375789
|
if (pollInterval) clearInterval(pollInterval);
|
|
375714
375790
|
};
|
|
375715
375791
|
}, [state.phase, state.deployment?.id]);
|
|
375716
|
-
|
|
375792
|
+
useEffect6(() => {
|
|
375717
375793
|
if (state.phase !== "starting" || !state.deployment) return;
|
|
375718
375794
|
let cancelled = false;
|
|
375719
375795
|
const client2 = clientRef.current;
|
|
@@ -375743,7 +375819,7 @@ function DeployUI({ environment, config }) {
|
|
|
375743
375819
|
cancelled = true;
|
|
375744
375820
|
};
|
|
375745
375821
|
}, [state.phase, state.deployment?.id]);
|
|
375746
|
-
|
|
375822
|
+
useEffect6(() => {
|
|
375747
375823
|
if (state.phase !== "queued" && state.phase !== "deploying" || !state.deployment) return;
|
|
375748
375824
|
let pollInterval;
|
|
375749
375825
|
let cancelled = false;
|
|
@@ -375796,12 +375872,12 @@ function DeployUI({ environment, config }) {
|
|
|
375796
375872
|
if (pollInterval) clearInterval(pollInterval);
|
|
375797
375873
|
};
|
|
375798
375874
|
}, [state.phase, state.deployment?.id]);
|
|
375799
|
-
|
|
375875
|
+
useEffect6(() => {
|
|
375800
375876
|
if (state.phase === "creating-tarball") {
|
|
375801
375877
|
trackEvent("deploy_started", { environment });
|
|
375802
375878
|
}
|
|
375803
375879
|
}, [state.phase, environment]);
|
|
375804
|
-
|
|
375880
|
+
useEffect6(() => {
|
|
375805
375881
|
if (state.phase === "success") {
|
|
375806
375882
|
trackEvent("deploy_succeeded", { environment });
|
|
375807
375883
|
closeDebugLog();
|
|
@@ -376008,7 +376084,14 @@ async function runDeployPipeline(options2) {
|
|
|
376008
376084
|
console.log("Creating deployment...");
|
|
376009
376085
|
let deployment;
|
|
376010
376086
|
try {
|
|
376011
|
-
|
|
376087
|
+
const gitInfo = getGitInfo(projectDir);
|
|
376088
|
+
deployment = await client2.createDeployment(projectId, "prod", {
|
|
376089
|
+
triggeredBy: "cli",
|
|
376090
|
+
...gitInfo && {
|
|
376091
|
+
gitCommitSha: gitInfo.commitSha,
|
|
376092
|
+
gitBranch: gitInfo.branch
|
|
376093
|
+
}
|
|
376094
|
+
});
|
|
376012
376095
|
} catch (err) {
|
|
376013
376096
|
console.error(`Error: Failed to create deployment: ${err instanceof Error ? err.message : String(err)}`);
|
|
376014
376097
|
process.exit(1);
|
|
@@ -376753,14 +376836,14 @@ async function reshapeCommand(action, databaseName, instanceKey = "default") {
|
|
|
376753
376836
|
}
|
|
376754
376837
|
|
|
376755
376838
|
// src/commands/clean.tsx
|
|
376756
|
-
import React8, { useState as useState7, useEffect as
|
|
376839
|
+
import React8, { useState as useState7, useEffect as useEffect7 } from "react";
|
|
376757
376840
|
import { render as render6, Text as Text8, Box as Box8 } from "ink";
|
|
376758
376841
|
import Spinner5 from "ink-spinner";
|
|
376759
376842
|
import * as fs26 from "fs";
|
|
376760
376843
|
import * as path24 from "path";
|
|
376761
376844
|
function CleanUI({ instanceKey }) {
|
|
376762
376845
|
const [state, setState] = useState7({ status: "checking" });
|
|
376763
|
-
|
|
376846
|
+
useEffect7(() => {
|
|
376764
376847
|
async function clean() {
|
|
376765
376848
|
const projectRoot = process.cwd();
|
|
376766
376849
|
const specificDir = path24.join(projectRoot, ".specific");
|
|
@@ -376888,14 +376971,14 @@ async function loginCommand(options2 = {}) {
|
|
|
376888
376971
|
}
|
|
376889
376972
|
|
|
376890
376973
|
// src/commands/logout.tsx
|
|
376891
|
-
import React9, { useState as useState8, useEffect as
|
|
376974
|
+
import React9, { useState as useState8, useEffect as useEffect8 } from "react";
|
|
376892
376975
|
import { render as render7, Text as Text9, useApp as useApp4 } from "ink";
|
|
376893
376976
|
function LogoutUI() {
|
|
376894
376977
|
const { exit } = useApp4();
|
|
376895
376978
|
const [state, setState] = useState8({
|
|
376896
376979
|
phase: "checking"
|
|
376897
376980
|
});
|
|
376898
|
-
|
|
376981
|
+
useEffect8(() => {
|
|
376899
376982
|
if (state.phase !== "checking") return;
|
|
376900
376983
|
if (!isLoggedIn()) {
|
|
376901
376984
|
setState({ phase: "not-logged-in" });
|
|
@@ -376904,7 +376987,7 @@ function LogoutUI() {
|
|
|
376904
376987
|
clearUserCredentials();
|
|
376905
376988
|
setState({ phase: "done" });
|
|
376906
376989
|
}, [state.phase]);
|
|
376907
|
-
|
|
376990
|
+
useEffect8(() => {
|
|
376908
376991
|
if (state.phase === "done" || state.phase === "not-logged-in") {
|
|
376909
376992
|
const timer = setTimeout(() => exit(), 100);
|
|
376910
376993
|
return () => clearTimeout(timer);
|
|
@@ -376923,7 +377006,7 @@ function logoutCommand() {
|
|
|
376923
377006
|
}
|
|
376924
377007
|
|
|
376925
377008
|
// src/commands/beta.tsx
|
|
376926
|
-
import React10, { useState as useState9, useEffect as
|
|
377009
|
+
import React10, { useState as useState9, useEffect as useEffect9 } from "react";
|
|
376927
377010
|
import { render as render8, Text as Text10, Box as Box9, useInput as useInput5, useApp as useApp5 } from "ink";
|
|
376928
377011
|
function BetaToggleUI() {
|
|
376929
377012
|
const { exit } = useApp5();
|
|
@@ -376961,7 +377044,7 @@ function BetaToggleUI() {
|
|
|
376961
377044
|
setSaved(true);
|
|
376962
377045
|
}
|
|
376963
377046
|
});
|
|
376964
|
-
|
|
377047
|
+
useEffect9(() => {
|
|
376965
377048
|
if (saved) {
|
|
376966
377049
|
const timer = setTimeout(() => exit(), 100);
|
|
376967
377050
|
return () => clearTimeout(timer);
|
|
@@ -376999,7 +377082,7 @@ function betaCommand() {
|
|
|
376999
377082
|
}
|
|
377000
377083
|
|
|
377001
377084
|
// src/commands/update.tsx
|
|
377002
|
-
import React11, { useState as useState10, useEffect as
|
|
377085
|
+
import React11, { useState as useState10, useEffect as useEffect10 } from "react";
|
|
377003
377086
|
import { render as render9, Text as Text11, Box as Box10, useApp as useApp6 } from "ink";
|
|
377004
377087
|
import Spinner6 from "ink-spinner";
|
|
377005
377088
|
|
|
@@ -377019,7 +377102,7 @@ function compareVersions(a, b) {
|
|
|
377019
377102
|
return 0;
|
|
377020
377103
|
}
|
|
377021
377104
|
async function checkForUpdate() {
|
|
377022
|
-
const currentVersion = "0.1.
|
|
377105
|
+
const currentVersion = "0.1.115";
|
|
377023
377106
|
const response = await fetch(`${BINARIES_BASE_URL}/latest?t=${Date.now()}`);
|
|
377024
377107
|
if (!response.ok) {
|
|
377025
377108
|
throw new Error(`Failed to check for updates: HTTP ${response.status}`);
|
|
@@ -377115,7 +377198,7 @@ function maybeStartBackgroundUpdate() {
|
|
|
377115
377198
|
function UpdateUI() {
|
|
377116
377199
|
const { exit } = useApp6();
|
|
377117
377200
|
const [state, setState] = useState10({ phase: "checking" });
|
|
377118
|
-
|
|
377201
|
+
useEffect10(() => {
|
|
377119
377202
|
if (state.phase !== "checking") return;
|
|
377120
377203
|
let cancelled = false;
|
|
377121
377204
|
async function check() {
|
|
@@ -377144,7 +377227,7 @@ function UpdateUI() {
|
|
|
377144
377227
|
cancelled = true;
|
|
377145
377228
|
};
|
|
377146
377229
|
}, [state.phase]);
|
|
377147
|
-
|
|
377230
|
+
useEffect10(() => {
|
|
377148
377231
|
if (state.phase !== "downloading" || !state.checkResult) return;
|
|
377149
377232
|
let cancelled = false;
|
|
377150
377233
|
async function download() {
|
|
@@ -377176,7 +377259,7 @@ function UpdateUI() {
|
|
|
377176
377259
|
cancelled = true;
|
|
377177
377260
|
};
|
|
377178
377261
|
}, [state.phase, state.checkResult]);
|
|
377179
|
-
|
|
377262
|
+
useEffect10(() => {
|
|
377180
377263
|
if (state.phase === "up-to-date" || state.phase === "success" || state.phase === "error" || state.phase === "permission-error") {
|
|
377181
377264
|
const timer = setTimeout(() => exit(), 100);
|
|
377182
377265
|
return () => clearTimeout(timer);
|
|
@@ -377287,7 +377370,7 @@ async function projectListCommand() {
|
|
|
377287
377370
|
var program = new Command();
|
|
377288
377371
|
var env = "production";
|
|
377289
377372
|
var envLabel = env !== "production" ? `[${env.toUpperCase()}] ` : "";
|
|
377290
|
-
program.name("specific").description(`${envLabel}Infrastructure-as-code for coding agents`).version("0.1.
|
|
377373
|
+
program.name("specific").description(`${envLabel}Infrastructure-as-code for coding agents`).version("0.1.115").enablePositionalOptions();
|
|
377291
377374
|
program.command("init").description("Initialize project for use with a coding agent").option("--agent <name...>", "Agents to configure (cursor, claude, codex, other)").addHelpText("after", `
|
|
377292
377375
|
Examples:
|
|
377293
377376
|
$ specific init
|
package/package.json
CHANGED
/package/dist/admin/_next/static/{bgRGrZnID0BykUNK10yK_ → 3wOysvI433uU7Czi4vdl0}/_buildManifest.js
RENAMED
|
File without changes
|
|
File without changes
|
/package/dist/admin/_next/static/{bgRGrZnID0BykUNK10yK_ → 3wOysvI433uU7Czi4vdl0}/_ssgManifest.js
RENAMED
|
File without changes
|