@specific.dev/cli 0.1.113 → 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 +206 -106
- package/package.json +1 -1
- /package/dist/admin/_next/static/{zFZhmJWhp-S4pZTnCndRF → 3wOysvI433uU7Czi4vdl0}/_buildManifest.js +0 -0
- /package/dist/admin/_next/static/{zFZhmJWhp-S4pZTnCndRF → 3wOysvI433uU7Czi4vdl0}/_clientMiddlewareManifest.json +0 -0
- /package/dist/admin/_next/static/{zFZhmJWhp-S4pZTnCndRF → 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);
|
|
@@ -371394,6 +371385,16 @@ async function startResources(options2) {
|
|
|
371394
371385
|
startedResources.push(instance);
|
|
371395
371386
|
callbacks.onResourceReady?.(instance.name, instance);
|
|
371396
371387
|
log(`Temporal namespace "${instance.name}" ready`);
|
|
371388
|
+
const dbState = {
|
|
371389
|
+
engine: "temporal",
|
|
371390
|
+
port: instance.port,
|
|
371391
|
+
host: instance.host,
|
|
371392
|
+
user: "",
|
|
371393
|
+
password: "",
|
|
371394
|
+
dbName: "",
|
|
371395
|
+
url: instance.url
|
|
371396
|
+
};
|
|
371397
|
+
await stateManager.registerDatabase(instance.name, dbState);
|
|
371397
371398
|
}
|
|
371398
371399
|
}
|
|
371399
371400
|
for (const mail of mailConfigs) {
|
|
@@ -373277,7 +373278,7 @@ function trackEvent(event, properties) {
|
|
|
373277
373278
|
event,
|
|
373278
373279
|
properties: {
|
|
373279
373280
|
...properties,
|
|
373280
|
-
cli_version: "0.1.
|
|
373281
|
+
cli_version: "0.1.115",
|
|
373281
373282
|
platform: process.platform,
|
|
373282
373283
|
node_version: process.version,
|
|
373283
373284
|
project_id: getProjectId()
|
|
@@ -374510,53 +374511,113 @@ function checkCommand() {
|
|
|
374510
374511
|
}
|
|
374511
374512
|
|
|
374512
374513
|
// src/commands/dev.tsx
|
|
374513
|
-
import React6, { useState as useState5, useEffect as
|
|
374514
|
+
import React6, { useState as useState5, useEffect as useEffect5, useRef as useRef3 } from "react";
|
|
374514
374515
|
import { render as render4, Text as Text6, Box as Box6, useApp as useApp2, Static } from "ink";
|
|
374515
374516
|
import Spinner3 from "ink-spinner";
|
|
374516
374517
|
import { Readable as Readable2 } from "stream";
|
|
374517
374518
|
|
|
374518
374519
|
// src/lib/ui/SecretInput.tsx
|
|
374519
|
-
import React4, { useState as useState3 } from "react";
|
|
374520
|
+
import React4, { useState as useState3, useRef, useCallback, useEffect as useEffect3 } from "react";
|
|
374520
374521
|
import { Box as Box4, Text as Text4, useInput as useInput2 } from "ink";
|
|
374522
|
+
var PASTE_DETECT_DELAY_MS = 100;
|
|
374521
374523
|
function SecretInput({ secretName, onSubmit, onCancel }) {
|
|
374522
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
|
+
}, []);
|
|
374523
374553
|
useInput2((input, key) => {
|
|
374524
374554
|
if (key.return) {
|
|
374525
|
-
|
|
374526
|
-
onSubmit(value);
|
|
374527
|
-
}
|
|
374555
|
+
scheduleSubmit();
|
|
374528
374556
|
} else if (key.escape) {
|
|
374529
374557
|
onCancel();
|
|
374530
374558
|
} else if (key.backspace || key.delete) {
|
|
374559
|
+
cancelSubmit();
|
|
374531
374560
|
setValue((prev) => prev.slice(0, -1));
|
|
374532
374561
|
} else if (!key.ctrl && !key.meta && input) {
|
|
374562
|
+
cancelSubmit();
|
|
374533
374563
|
setValue((prev) => prev + input);
|
|
374534
374564
|
}
|
|
374535
374565
|
});
|
|
374536
|
-
|
|
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)"));
|
|
374537
374568
|
}
|
|
374538
374569
|
|
|
374539
374570
|
// src/lib/ui/ConfigInput.tsx
|
|
374540
|
-
import React5, { useState as useState4 } from "react";
|
|
374571
|
+
import React5, { useState as useState4, useRef as useRef2, useCallback as useCallback2, useEffect as useEffect4 } from "react";
|
|
374541
374572
|
import { Box as Box5, Text as Text5, useInput as useInput3 } from "ink";
|
|
374573
|
+
var PASTE_DETECT_DELAY_MS2 = 100;
|
|
374542
374574
|
function ConfigInput({ configName, defaultValue, onSubmit, onCancel }) {
|
|
374543
374575
|
const [value, setValue] = useState4("");
|
|
374544
|
-
|
|
374545
|
-
|
|
374546
|
-
|
|
374547
|
-
|
|
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);
|
|
374548
374589
|
} else if (defaultValue !== void 0) {
|
|
374549
374590
|
onSubmit(defaultValue);
|
|
374550
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();
|
|
374551
374609
|
} else if (key.escape) {
|
|
374552
374610
|
onCancel();
|
|
374553
374611
|
} else if (key.backspace || key.delete) {
|
|
374612
|
+
cancelSubmit();
|
|
374554
374613
|
setValue((prev) => prev.slice(0, -1));
|
|
374555
374614
|
} else if (!key.ctrl && !key.meta && input) {
|
|
374615
|
+
cancelSubmit();
|
|
374556
374616
|
setValue((prev) => prev + input);
|
|
374557
374617
|
}
|
|
374558
374618
|
});
|
|
374559
|
-
|
|
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)"));
|
|
374560
374621
|
}
|
|
374561
374622
|
|
|
374562
374623
|
// src/commands/dev.tsx
|
|
@@ -374573,8 +374634,8 @@ function DevUI({ instanceKey, tunnelEnabled }) {
|
|
|
374573
374634
|
tunnelUrls: /* @__PURE__ */ new Map(),
|
|
374574
374635
|
tunnelStatus: /* @__PURE__ */ new Map()
|
|
374575
374636
|
});
|
|
374576
|
-
const devEnvRef =
|
|
374577
|
-
const startTimeRef =
|
|
374637
|
+
const devEnvRef = useRef3(null);
|
|
374638
|
+
const startTimeRef = useRef3(null);
|
|
374578
374639
|
const buildColorMap = (config2) => {
|
|
374579
374640
|
const colorMap = /* @__PURE__ */ new Map();
|
|
374580
374641
|
let colorIndex = 0;
|
|
@@ -374600,7 +374661,7 @@ function DevUI({ instanceKey, tunnelEnabled }) {
|
|
|
374600
374661
|
}
|
|
374601
374662
|
return colorMap;
|
|
374602
374663
|
};
|
|
374603
|
-
|
|
374664
|
+
useEffect5(() => {
|
|
374604
374665
|
const devEnv = new DevEnvironment({
|
|
374605
374666
|
projectDir: process.cwd(),
|
|
374606
374667
|
instanceKey,
|
|
@@ -374737,7 +374798,7 @@ function DevUI({ instanceKey, tunnelEnabled }) {
|
|
|
374737
374798
|
devEnvRef.current = null;
|
|
374738
374799
|
};
|
|
374739
374800
|
}, [instanceKey, tunnelEnabled]);
|
|
374740
|
-
|
|
374801
|
+
useEffect5(() => {
|
|
374741
374802
|
const handleSignal = () => {
|
|
374742
374803
|
const devEnv = devEnvRef.current;
|
|
374743
374804
|
if (!devEnv) return;
|
|
@@ -374768,7 +374829,7 @@ function DevUI({ instanceKey, tunnelEnabled }) {
|
|
|
374768
374829
|
process.off("unhandledRejection", handleCrash);
|
|
374769
374830
|
};
|
|
374770
374831
|
}, []);
|
|
374771
|
-
|
|
374832
|
+
useEffect5(() => {
|
|
374772
374833
|
if (state.status === "running" && !startTimeRef.current) {
|
|
374773
374834
|
startTimeRef.current = Date.now();
|
|
374774
374835
|
trackEvent("dev_started");
|
|
@@ -375064,11 +375125,29 @@ function devCommand(instanceKey, tunnelEnabled = false) {
|
|
|
375064
375125
|
|
|
375065
375126
|
// src/commands/deploy.tsx
|
|
375066
375127
|
init_open();
|
|
375067
|
-
import React7, { useState as useState6, useEffect as
|
|
375128
|
+
import React7, { useState as useState6, useEffect as useEffect6, useCallback as useCallback3 } from "react";
|
|
375068
375129
|
import { render as render5, Text as Text7, Box as Box7, useApp as useApp3, useInput as useInput4 } from "ink";
|
|
375069
375130
|
import Spinner4 from "ink-spinner";
|
|
375070
375131
|
import * as fs22 from "fs";
|
|
375071
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
|
+
}
|
|
375072
375151
|
function formatBytes(bytes) {
|
|
375073
375152
|
if (bytes < 1024) return `${bytes} B`;
|
|
375074
375153
|
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
@@ -375214,7 +375293,7 @@ function DeployUI({ environment, config }) {
|
|
|
375214
375293
|
const { exit } = useApp3();
|
|
375215
375294
|
const [state, setState] = useState6({ phase: "checking-auth" });
|
|
375216
375295
|
const clientRef = React7.useRef(null);
|
|
375217
|
-
|
|
375296
|
+
useEffect6(() => {
|
|
375218
375297
|
if (state.phase !== "checking-auth") return;
|
|
375219
375298
|
const projectDir = process.cwd();
|
|
375220
375299
|
if (hasProjectId(projectDir)) {
|
|
@@ -375235,7 +375314,7 @@ function DeployUI({ environment, config }) {
|
|
|
375235
375314
|
}
|
|
375236
375315
|
setState({ phase: "logging-in" });
|
|
375237
375316
|
}, [state.phase]);
|
|
375238
|
-
|
|
375317
|
+
useEffect6(() => {
|
|
375239
375318
|
if (state.phase !== "logging-in") return;
|
|
375240
375319
|
let cancelled = false;
|
|
375241
375320
|
async function startLogin() {
|
|
@@ -375296,7 +375375,7 @@ function DeployUI({ environment, config }) {
|
|
|
375296
375375
|
cancelled = true;
|
|
375297
375376
|
};
|
|
375298
375377
|
}, [state.phase]);
|
|
375299
|
-
|
|
375378
|
+
useEffect6(() => {
|
|
375300
375379
|
if (state.phase !== "loading-projects") return;
|
|
375301
375380
|
let cancelled = false;
|
|
375302
375381
|
async function loadProjects() {
|
|
@@ -375329,7 +375408,7 @@ function DeployUI({ environment, config }) {
|
|
|
375329
375408
|
cancelled = true;
|
|
375330
375409
|
};
|
|
375331
375410
|
}, [state.phase]);
|
|
375332
|
-
const handleProjectSelect =
|
|
375411
|
+
const handleProjectSelect = useCallback3(
|
|
375333
375412
|
(project) => {
|
|
375334
375413
|
if ("type" in project && project.type === "new") {
|
|
375335
375414
|
setState((s) => ({ ...s, phase: "entering-name", selectedOrganizationId: project.orgId }));
|
|
@@ -375344,13 +375423,13 @@ function DeployUI({ environment, config }) {
|
|
|
375344
375423
|
},
|
|
375345
375424
|
[]
|
|
375346
375425
|
);
|
|
375347
|
-
const handleNameSubmit =
|
|
375426
|
+
const handleNameSubmit = useCallback3((name) => {
|
|
375348
375427
|
setState((s) => ({ ...s, phase: "creating-project", newProjectName: name }));
|
|
375349
375428
|
}, []);
|
|
375350
|
-
const handleNameCancel =
|
|
375429
|
+
const handleNameCancel = useCallback3(() => {
|
|
375351
375430
|
setState((s) => ({ ...s, phase: "selecting-project" }));
|
|
375352
375431
|
}, []);
|
|
375353
|
-
|
|
375432
|
+
useEffect6(() => {
|
|
375354
375433
|
if (state.phase !== "creating-project" || !state.newProjectName) return;
|
|
375355
375434
|
let cancelled = false;
|
|
375356
375435
|
async function createProject() {
|
|
@@ -375377,7 +375456,7 @@ function DeployUI({ environment, config }) {
|
|
|
375377
375456
|
cancelled = true;
|
|
375378
375457
|
};
|
|
375379
375458
|
}, [state.phase, state.newProjectName]);
|
|
375380
|
-
const handleSecretSubmit =
|
|
375459
|
+
const handleSecretSubmit = useCallback3((value) => {
|
|
375381
375460
|
setState((s) => {
|
|
375382
375461
|
if (!s.missingSecrets || s.currentSecretIndex === void 0) return s;
|
|
375383
375462
|
const currentSecret2 = s.missingSecrets[s.currentSecretIndex];
|
|
@@ -375400,14 +375479,14 @@ function DeployUI({ environment, config }) {
|
|
|
375400
375479
|
};
|
|
375401
375480
|
});
|
|
375402
375481
|
}, []);
|
|
375403
|
-
const handleSecretCancel =
|
|
375482
|
+
const handleSecretCancel = useCallback3(() => {
|
|
375404
375483
|
setState((s) => ({
|
|
375405
375484
|
...s,
|
|
375406
375485
|
phase: "error",
|
|
375407
375486
|
error: "Deployment cancelled - secrets not provided"
|
|
375408
375487
|
}));
|
|
375409
375488
|
}, []);
|
|
375410
|
-
const handleConfigSubmit =
|
|
375489
|
+
const handleConfigSubmit = useCallback3((value) => {
|
|
375411
375490
|
setState((s) => {
|
|
375412
375491
|
if (!s.missingConfigs || s.currentConfigIndex === void 0) return s;
|
|
375413
375492
|
const currentConfig2 = s.missingConfigs[s.currentConfigIndex];
|
|
@@ -375430,14 +375509,14 @@ function DeployUI({ environment, config }) {
|
|
|
375430
375509
|
};
|
|
375431
375510
|
});
|
|
375432
375511
|
}, []);
|
|
375433
|
-
const handleConfigCancel =
|
|
375512
|
+
const handleConfigCancel = useCallback3(() => {
|
|
375434
375513
|
setState((s) => ({
|
|
375435
375514
|
...s,
|
|
375436
375515
|
phase: "error",
|
|
375437
375516
|
error: "Deployment cancelled - configs not provided"
|
|
375438
375517
|
}));
|
|
375439
375518
|
}, []);
|
|
375440
|
-
|
|
375519
|
+
useEffect6(() => {
|
|
375441
375520
|
const {
|
|
375442
375521
|
phase: phase2,
|
|
375443
375522
|
deployment: deployment2,
|
|
@@ -375479,7 +375558,7 @@ function DeployUI({ environment, config }) {
|
|
|
375479
375558
|
}
|
|
375480
375559
|
})();
|
|
375481
375560
|
}, [state]);
|
|
375482
|
-
|
|
375561
|
+
useEffect6(() => {
|
|
375483
375562
|
const {
|
|
375484
375563
|
phase: phase2,
|
|
375485
375564
|
deployment: deployment2,
|
|
@@ -375521,7 +375600,7 @@ function DeployUI({ environment, config }) {
|
|
|
375521
375600
|
}
|
|
375522
375601
|
})();
|
|
375523
375602
|
}, [state]);
|
|
375524
|
-
|
|
375603
|
+
useEffect6(() => {
|
|
375525
375604
|
if (state.phase !== "creating-tarball" || !state.projectId) return;
|
|
375526
375605
|
let cancelled = false;
|
|
375527
375606
|
async function runDeploy() {
|
|
@@ -375557,7 +375636,14 @@ function DeployUI({ environment, config }) {
|
|
|
375557
375636
|
let deployment2;
|
|
375558
375637
|
try {
|
|
375559
375638
|
writeLog("deploy", `Creating deployment for project ${state.projectId}`);
|
|
375560
|
-
|
|
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
|
+
});
|
|
375561
375647
|
writeLog("deploy", `Deployment created: ${deployment2.id}`);
|
|
375562
375648
|
} catch (err) {
|
|
375563
375649
|
const errorMsg = `Failed to create deployment: ${err instanceof Error ? err.message : String(err)}`;
|
|
@@ -375594,7 +375680,7 @@ function DeployUI({ environment, config }) {
|
|
|
375594
375680
|
cancelled = true;
|
|
375595
375681
|
};
|
|
375596
375682
|
}, [state.projectId, environment, config.builds]);
|
|
375597
|
-
|
|
375683
|
+
useEffect6(() => {
|
|
375598
375684
|
if (state.phase !== "pending" || !state.deployment) return;
|
|
375599
375685
|
let pollInterval;
|
|
375600
375686
|
let cancelled = false;
|
|
@@ -375703,7 +375789,7 @@ function DeployUI({ environment, config }) {
|
|
|
375703
375789
|
if (pollInterval) clearInterval(pollInterval);
|
|
375704
375790
|
};
|
|
375705
375791
|
}, [state.phase, state.deployment?.id]);
|
|
375706
|
-
|
|
375792
|
+
useEffect6(() => {
|
|
375707
375793
|
if (state.phase !== "starting" || !state.deployment) return;
|
|
375708
375794
|
let cancelled = false;
|
|
375709
375795
|
const client2 = clientRef.current;
|
|
@@ -375733,7 +375819,7 @@ function DeployUI({ environment, config }) {
|
|
|
375733
375819
|
cancelled = true;
|
|
375734
375820
|
};
|
|
375735
375821
|
}, [state.phase, state.deployment?.id]);
|
|
375736
|
-
|
|
375822
|
+
useEffect6(() => {
|
|
375737
375823
|
if (state.phase !== "queued" && state.phase !== "deploying" || !state.deployment) return;
|
|
375738
375824
|
let pollInterval;
|
|
375739
375825
|
let cancelled = false;
|
|
@@ -375786,12 +375872,12 @@ function DeployUI({ environment, config }) {
|
|
|
375786
375872
|
if (pollInterval) clearInterval(pollInterval);
|
|
375787
375873
|
};
|
|
375788
375874
|
}, [state.phase, state.deployment?.id]);
|
|
375789
|
-
|
|
375875
|
+
useEffect6(() => {
|
|
375790
375876
|
if (state.phase === "creating-tarball") {
|
|
375791
375877
|
trackEvent("deploy_started", { environment });
|
|
375792
375878
|
}
|
|
375793
375879
|
}, [state.phase, environment]);
|
|
375794
|
-
|
|
375880
|
+
useEffect6(() => {
|
|
375795
375881
|
if (state.phase === "success") {
|
|
375796
375882
|
trackEvent("deploy_succeeded", { environment });
|
|
375797
375883
|
closeDebugLog();
|
|
@@ -375998,7 +376084,14 @@ async function runDeployPipeline(options2) {
|
|
|
375998
376084
|
console.log("Creating deployment...");
|
|
375999
376085
|
let deployment;
|
|
376000
376086
|
try {
|
|
376001
|
-
|
|
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
|
+
});
|
|
376002
376095
|
} catch (err) {
|
|
376003
376096
|
console.error(`Error: Failed to create deployment: ${err instanceof Error ? err.message : String(err)}`);
|
|
376004
376097
|
process.exit(1);
|
|
@@ -376222,7 +376315,7 @@ async function execCommand(serviceName, command, instanceKey = "default") {
|
|
|
376222
376315
|
}
|
|
376223
376316
|
const required = findRequiredResources(service);
|
|
376224
376317
|
let resources = /* @__PURE__ */ new Map();
|
|
376225
|
-
const hasRequiredResources = required.postgres.length > 0 || required.redis.length > 0 || required.storage.length > 0;
|
|
376318
|
+
const hasRequiredResources = required.postgres.length > 0 || required.redis.length > 0 || required.storage.length > 0 || required.temporal.length > 0 || required.mail.length > 0;
|
|
376226
376319
|
stateManager = new InstanceStateManager(process.cwd(), instanceKey);
|
|
376227
376320
|
await stateManager.cleanStaleState();
|
|
376228
376321
|
const existingInstances = await stateManager.getExistingInstances();
|
|
@@ -376230,7 +376323,7 @@ async function execCommand(serviceName, command, instanceKey = "default") {
|
|
|
376230
376323
|
if (hasRequiredResources) {
|
|
376231
376324
|
if (existingInstances) {
|
|
376232
376325
|
spinner = startSpinner("Starting resources...");
|
|
376233
|
-
const allRequiredNames = [...required.postgres, ...required.redis, ...required.storage];
|
|
376326
|
+
const allRequiredNames = [...required.postgres, ...required.redis, ...required.storage, ...required.temporal, ...required.mail];
|
|
376234
376327
|
for (const name of allRequiredNames) {
|
|
376235
376328
|
const dbState = existingInstances.databases[name];
|
|
376236
376329
|
if (!dbState) {
|
|
@@ -376240,9 +376333,16 @@ async function execCommand(serviceName, command, instanceKey = "default") {
|
|
|
376240
376333
|
);
|
|
376241
376334
|
process.exit(1);
|
|
376242
376335
|
}
|
|
376336
|
+
const engineToType = {
|
|
376337
|
+
object_store: "storage",
|
|
376338
|
+
postgres: "postgres",
|
|
376339
|
+
redis: "redis",
|
|
376340
|
+
temporal: "temporal",
|
|
376341
|
+
mail: "mail"
|
|
376342
|
+
};
|
|
376243
376343
|
resources.set(name, {
|
|
376244
376344
|
name,
|
|
376245
|
-
type: dbState.engine
|
|
376345
|
+
type: engineToType[dbState.engine] ?? dbState.engine,
|
|
376246
376346
|
port: dbState.port,
|
|
376247
376347
|
host: dbState.host,
|
|
376248
376348
|
user: dbState.user,
|
|
@@ -376736,14 +376836,14 @@ async function reshapeCommand(action, databaseName, instanceKey = "default") {
|
|
|
376736
376836
|
}
|
|
376737
376837
|
|
|
376738
376838
|
// src/commands/clean.tsx
|
|
376739
|
-
import React8, { useState as useState7, useEffect as
|
|
376839
|
+
import React8, { useState as useState7, useEffect as useEffect7 } from "react";
|
|
376740
376840
|
import { render as render6, Text as Text8, Box as Box8 } from "ink";
|
|
376741
376841
|
import Spinner5 from "ink-spinner";
|
|
376742
376842
|
import * as fs26 from "fs";
|
|
376743
376843
|
import * as path24 from "path";
|
|
376744
376844
|
function CleanUI({ instanceKey }) {
|
|
376745
376845
|
const [state, setState] = useState7({ status: "checking" });
|
|
376746
|
-
|
|
376846
|
+
useEffect7(() => {
|
|
376747
376847
|
async function clean() {
|
|
376748
376848
|
const projectRoot = process.cwd();
|
|
376749
376849
|
const specificDir = path24.join(projectRoot, ".specific");
|
|
@@ -376871,14 +376971,14 @@ async function loginCommand(options2 = {}) {
|
|
|
376871
376971
|
}
|
|
376872
376972
|
|
|
376873
376973
|
// src/commands/logout.tsx
|
|
376874
|
-
import React9, { useState as useState8, useEffect as
|
|
376974
|
+
import React9, { useState as useState8, useEffect as useEffect8 } from "react";
|
|
376875
376975
|
import { render as render7, Text as Text9, useApp as useApp4 } from "ink";
|
|
376876
376976
|
function LogoutUI() {
|
|
376877
376977
|
const { exit } = useApp4();
|
|
376878
376978
|
const [state, setState] = useState8({
|
|
376879
376979
|
phase: "checking"
|
|
376880
376980
|
});
|
|
376881
|
-
|
|
376981
|
+
useEffect8(() => {
|
|
376882
376982
|
if (state.phase !== "checking") return;
|
|
376883
376983
|
if (!isLoggedIn()) {
|
|
376884
376984
|
setState({ phase: "not-logged-in" });
|
|
@@ -376887,7 +376987,7 @@ function LogoutUI() {
|
|
|
376887
376987
|
clearUserCredentials();
|
|
376888
376988
|
setState({ phase: "done" });
|
|
376889
376989
|
}, [state.phase]);
|
|
376890
|
-
|
|
376990
|
+
useEffect8(() => {
|
|
376891
376991
|
if (state.phase === "done" || state.phase === "not-logged-in") {
|
|
376892
376992
|
const timer = setTimeout(() => exit(), 100);
|
|
376893
376993
|
return () => clearTimeout(timer);
|
|
@@ -376906,7 +377006,7 @@ function logoutCommand() {
|
|
|
376906
377006
|
}
|
|
376907
377007
|
|
|
376908
377008
|
// src/commands/beta.tsx
|
|
376909
|
-
import React10, { useState as useState9, useEffect as
|
|
377009
|
+
import React10, { useState as useState9, useEffect as useEffect9 } from "react";
|
|
376910
377010
|
import { render as render8, Text as Text10, Box as Box9, useInput as useInput5, useApp as useApp5 } from "ink";
|
|
376911
377011
|
function BetaToggleUI() {
|
|
376912
377012
|
const { exit } = useApp5();
|
|
@@ -376944,7 +377044,7 @@ function BetaToggleUI() {
|
|
|
376944
377044
|
setSaved(true);
|
|
376945
377045
|
}
|
|
376946
377046
|
});
|
|
376947
|
-
|
|
377047
|
+
useEffect9(() => {
|
|
376948
377048
|
if (saved) {
|
|
376949
377049
|
const timer = setTimeout(() => exit(), 100);
|
|
376950
377050
|
return () => clearTimeout(timer);
|
|
@@ -376982,7 +377082,7 @@ function betaCommand() {
|
|
|
376982
377082
|
}
|
|
376983
377083
|
|
|
376984
377084
|
// src/commands/update.tsx
|
|
376985
|
-
import React11, { useState as useState10, useEffect as
|
|
377085
|
+
import React11, { useState as useState10, useEffect as useEffect10 } from "react";
|
|
376986
377086
|
import { render as render9, Text as Text11, Box as Box10, useApp as useApp6 } from "ink";
|
|
376987
377087
|
import Spinner6 from "ink-spinner";
|
|
376988
377088
|
|
|
@@ -377002,7 +377102,7 @@ function compareVersions(a, b) {
|
|
|
377002
377102
|
return 0;
|
|
377003
377103
|
}
|
|
377004
377104
|
async function checkForUpdate() {
|
|
377005
|
-
const currentVersion = "0.1.
|
|
377105
|
+
const currentVersion = "0.1.115";
|
|
377006
377106
|
const response = await fetch(`${BINARIES_BASE_URL}/latest?t=${Date.now()}`);
|
|
377007
377107
|
if (!response.ok) {
|
|
377008
377108
|
throw new Error(`Failed to check for updates: HTTP ${response.status}`);
|
|
@@ -377098,7 +377198,7 @@ function maybeStartBackgroundUpdate() {
|
|
|
377098
377198
|
function UpdateUI() {
|
|
377099
377199
|
const { exit } = useApp6();
|
|
377100
377200
|
const [state, setState] = useState10({ phase: "checking" });
|
|
377101
|
-
|
|
377201
|
+
useEffect10(() => {
|
|
377102
377202
|
if (state.phase !== "checking") return;
|
|
377103
377203
|
let cancelled = false;
|
|
377104
377204
|
async function check() {
|
|
@@ -377127,7 +377227,7 @@ function UpdateUI() {
|
|
|
377127
377227
|
cancelled = true;
|
|
377128
377228
|
};
|
|
377129
377229
|
}, [state.phase]);
|
|
377130
|
-
|
|
377230
|
+
useEffect10(() => {
|
|
377131
377231
|
if (state.phase !== "downloading" || !state.checkResult) return;
|
|
377132
377232
|
let cancelled = false;
|
|
377133
377233
|
async function download() {
|
|
@@ -377159,7 +377259,7 @@ function UpdateUI() {
|
|
|
377159
377259
|
cancelled = true;
|
|
377160
377260
|
};
|
|
377161
377261
|
}, [state.phase, state.checkResult]);
|
|
377162
|
-
|
|
377262
|
+
useEffect10(() => {
|
|
377163
377263
|
if (state.phase === "up-to-date" || state.phase === "success" || state.phase === "error" || state.phase === "permission-error") {
|
|
377164
377264
|
const timer = setTimeout(() => exit(), 100);
|
|
377165
377265
|
return () => clearTimeout(timer);
|
|
@@ -377270,7 +377370,7 @@ async function projectListCommand() {
|
|
|
377270
377370
|
var program = new Command();
|
|
377271
377371
|
var env = "production";
|
|
377272
377372
|
var envLabel = env !== "production" ? `[${env.toUpperCase()}] ` : "";
|
|
377273
|
-
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();
|
|
377274
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", `
|
|
377275
377375
|
Examples:
|
|
377276
377376
|
$ specific init
|