@specific.dev/cli 0.1.44 → 0.1.46
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 +2 -2
- package/dist/admin/__next._full.txt +24 -17
- package/dist/admin/__next._head.txt +1 -1
- package/dist/admin/__next._index.txt +10 -4
- package/dist/admin/__next._tree.txt +3 -2
- package/dist/admin/_next/static/chunks/63473a6cb811ed42.js +5 -0
- package/dist/admin/_next/static/chunks/64efcb432fae8c98.js +1 -0
- package/dist/admin/_next/static/chunks/65ce370ab86b6df6.js +1 -0
- package/dist/admin/_next/static/chunks/6877369fbd84f127.js +1 -0
- package/dist/admin/_next/static/chunks/951210b423dc9315.css +4 -0
- package/dist/admin/_next/static/chunks/ce9a5f692b87aaa9.js +5 -0
- package/dist/admin/_next/static/chunks/d2b1f8ba26497c0b.js +1 -0
- package/dist/admin/_next/static/chunks/{a5c8191596f07db5.js → e13659c7ad8234ce.js} +2 -2
- package/dist/admin/_next/static/chunks/turbopack-ebee0930f5a58b67.js +4 -0
- package/dist/admin/_next/static/media/1bffadaabf893a1e-s.7cd81963.woff2 +0 -0
- package/dist/admin/_next/static/media/2bbe8d2671613f1f-s.76dcb0b2.woff2 +0 -0
- package/dist/admin/_next/static/media/2c55a0e60120577a-s.2a48534a.woff2 +0 -0
- package/dist/admin/_next/static/media/5476f68d60460930-s.c995e352.woff2 +0 -0
- package/dist/admin/_next/static/media/83afe278b6a6bb3c-s.p.3a6ba036.woff2 +0 -0
- package/dist/admin/_next/static/media/9c72aa0f40e4eef8-s.18a48cbc.woff2 +0 -0
- package/dist/admin/_next/static/media/ad66f9afd8947f86-s.7a40eb73.woff2 +0 -0
- package/dist/admin/_next/static/media/icon.456b8582.svg +12 -0
- package/dist/admin/_not-found/__next._full.txt +19 -13
- package/dist/admin/_not-found/__next._head.txt +1 -1
- package/dist/admin/_not-found/__next._index.txt +10 -4
- 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 +2 -2
- package/dist/admin/_not-found/index.html +1 -1
- package/dist/admin/_not-found/index.txt +19 -13
- package/dist/admin/databases/__next._full.txt +24 -17
- package/dist/admin/databases/__next._head.txt +1 -1
- package/dist/admin/databases/__next._index.txt +10 -4
- package/dist/admin/databases/__next._tree.txt +3 -2
- package/dist/admin/databases/__next.databases.__PAGE__.txt +2 -2
- package/dist/admin/databases/__next.databases.txt +1 -1
- package/dist/admin/databases/index.html +1 -1
- package/dist/admin/databases/index.txt +24 -17
- package/dist/admin/icon.svg +12 -0
- package/dist/admin/index.html +1 -1
- package/dist/admin/index.txt +24 -17
- package/dist/cli.js +305 -160
- package/package.json +1 -1
- package/dist/admin/_next/static/chunks/522cc1cbb935d4c6.js +0 -1
- package/dist/admin/_next/static/chunks/62190944d690fc4e.js +0 -4
- package/dist/admin/_next/static/chunks/938d410f2031f3b1.css +0 -3
- package/dist/admin/_next/static/chunks/979e895ce202c4a3.js +0 -1
- package/dist/admin/_next/static/chunks/99f58b3b47071cc8.js +0 -5
- package/dist/admin/_next/static/chunks/a4ff1b18f2f45e23.js +0 -2
- package/dist/admin/_next/static/chunks/bf65cbe8dc67cf90.js +0 -5
- package/dist/admin/_next/static/chunks/turbopack-9e3df33047c5ecb2.js +0 -4
- /package/dist/admin/_next/static/{pbjYnqTudS-YVLwgwOgBz → uXSe8Dmoqn0jmhvY6Iln0}/_buildManifest.js +0 -0
- /package/dist/admin/_next/static/{pbjYnqTudS-YVLwgwOgBz → uXSe8Dmoqn0jmhvY6Iln0}/_clientMiddlewareManifest.json +0 -0
- /package/dist/admin/_next/static/{pbjYnqTudS-YVLwgwOgBz → uXSe8Dmoqn0jmhvY6Iln0}/_ssgManifest.js +0 -0
package/dist/cli.js
CHANGED
|
@@ -183398,6 +183398,36 @@ var ApiClient = class {
|
|
|
183398
183398
|
}
|
|
183399
183399
|
return response.json();
|
|
183400
183400
|
}
|
|
183401
|
+
async startDeployment(deploymentId) {
|
|
183402
|
+
const url = `${this.baseUrl}/deployments/${deploymentId}/start`;
|
|
183403
|
+
writeLog("api", `POST ${url}`);
|
|
183404
|
+
const response = await fetch(url, {
|
|
183405
|
+
method: "POST",
|
|
183406
|
+
headers: this.authHeaders()
|
|
183407
|
+
});
|
|
183408
|
+
writeLog("api", `Response: ${response.status} ${response.statusText}`);
|
|
183409
|
+
if (!response.ok) {
|
|
183410
|
+
let errorBody;
|
|
183411
|
+
try {
|
|
183412
|
+
const error = await response.json();
|
|
183413
|
+
errorBody = JSON.stringify(error);
|
|
183414
|
+
writeLog("api:error", `API error: ${error.error} (${error.code})`);
|
|
183415
|
+
writeLog("api:error", `Request was: POST ${url}`);
|
|
183416
|
+
writeLog("api:error", `Response body: ${errorBody}`);
|
|
183417
|
+
throw new Error(
|
|
183418
|
+
`Failed to start deployment: ${error.error} (${error.code})`
|
|
183419
|
+
);
|
|
183420
|
+
} catch (e) {
|
|
183421
|
+
if (e instanceof Error && e.message.startsWith("Failed to start")) {
|
|
183422
|
+
throw e;
|
|
183423
|
+
}
|
|
183424
|
+
errorBody = await response.text();
|
|
183425
|
+
writeLog("api:error", `Failed to parse error response: ${errorBody}`);
|
|
183426
|
+
throw new Error(`Failed to start deployment: ${response.statusText}`);
|
|
183427
|
+
}
|
|
183428
|
+
}
|
|
183429
|
+
return response.json();
|
|
183430
|
+
}
|
|
183401
183431
|
async submitSecrets(deploymentId, secrets) {
|
|
183402
183432
|
const secretKeys = Object.keys(secrets);
|
|
183403
183433
|
const url = `${this.baseUrl}/deployments/${deploymentId}/secrets`;
|
|
@@ -183539,7 +183569,7 @@ var ApiClient = class {
|
|
|
183539
183569
|
writeLog("api", `GET ${url}`);
|
|
183540
183570
|
const response = await fetch(url, {
|
|
183541
183571
|
headers: this.authHeaders(),
|
|
183542
|
-
signal
|
|
183572
|
+
...signal ? { signal } : {}
|
|
183543
183573
|
});
|
|
183544
183574
|
writeLog("api", `Response: ${response.status} ${response.statusText}`);
|
|
183545
183575
|
if (!response.ok) {
|
|
@@ -183843,7 +183873,7 @@ function trackEvent(event, properties) {
|
|
|
183843
183873
|
event,
|
|
183844
183874
|
properties: {
|
|
183845
183875
|
...properties,
|
|
183846
|
-
cli_version: "0.1.
|
|
183876
|
+
cli_version: "0.1.46",
|
|
183847
183877
|
platform: process.platform,
|
|
183848
183878
|
node_version: process.version,
|
|
183849
183879
|
project_id: getProjectId(),
|
|
@@ -186546,8 +186576,9 @@ var StablePortAllocator = class {
|
|
|
186546
186576
|
return port;
|
|
186547
186577
|
}
|
|
186548
186578
|
allocate(key) {
|
|
186549
|
-
|
|
186550
|
-
|
|
186579
|
+
const savedPort = this.savedPorts[key];
|
|
186580
|
+
if (savedPort !== void 0) {
|
|
186581
|
+
return savedPort;
|
|
186551
186582
|
}
|
|
186552
186583
|
const port = this.allocateRandom();
|
|
186553
186584
|
this.savedPorts[key] = port;
|
|
@@ -186614,10 +186645,11 @@ function getPlatformInfo() {
|
|
|
186614
186645
|
`Unsupported platform: ${platform5}. Only macOS and Linux are supported.`
|
|
186615
186646
|
);
|
|
186616
186647
|
}
|
|
186648
|
+
const archStr = arch3;
|
|
186617
186649
|
let mappedArch;
|
|
186618
|
-
if (
|
|
186650
|
+
if (archStr === "x64" || archStr === "x86_64") {
|
|
186619
186651
|
mappedArch = "x64";
|
|
186620
|
-
} else if (
|
|
186652
|
+
} else if (archStr === "arm64" || archStr === "aarch64") {
|
|
186621
186653
|
mappedArch = "arm64";
|
|
186622
186654
|
} else {
|
|
186623
186655
|
throw new Error(
|
|
@@ -187318,7 +187350,7 @@ function resolveEnvValue(value, resources, secrets, configs, servicePort, servic
|
|
|
187318
187350
|
}
|
|
187319
187351
|
return pg.syncSecret;
|
|
187320
187352
|
default:
|
|
187321
|
-
throw new Error(`Unknown postgres attribute: ${value.attribute}`);
|
|
187353
|
+
throw new Error(`Unknown postgres attribute: ${String(value.attribute)}`);
|
|
187322
187354
|
}
|
|
187323
187355
|
}
|
|
187324
187356
|
case "redis": {
|
|
@@ -187336,7 +187368,7 @@ function resolveEnvValue(value, resources, secrets, configs, servicePort, servic
|
|
|
187336
187368
|
case "password":
|
|
187337
187369
|
return redis.password;
|
|
187338
187370
|
default:
|
|
187339
|
-
throw new Error(`Unknown redis attribute: ${value.attribute}`);
|
|
187371
|
+
throw new Error(`Unknown redis attribute: ${String(value.attribute)}`);
|
|
187340
187372
|
}
|
|
187341
187373
|
}
|
|
187342
187374
|
case "storage": {
|
|
@@ -187366,7 +187398,7 @@ function resolveEnvValue(value, resources, secrets, configs, servicePort, servic
|
|
|
187366
187398
|
}
|
|
187367
187399
|
return storage.bucket;
|
|
187368
187400
|
default:
|
|
187369
|
-
throw new Error(`Unknown storage attribute: ${value.attribute}`);
|
|
187401
|
+
throw new Error(`Unknown storage attribute: ${String(value.attribute)}`);
|
|
187370
187402
|
}
|
|
187371
187403
|
}
|
|
187372
187404
|
case "config": {
|
|
@@ -187927,9 +187959,9 @@ function extractServiceAndKey(host) {
|
|
|
187927
187959
|
return null;
|
|
187928
187960
|
}
|
|
187929
187961
|
const parts = prefix.split(".");
|
|
187930
|
-
if (parts.length === 1) {
|
|
187962
|
+
if (parts.length === 1 && parts[0]) {
|
|
187931
187963
|
return { serviceName: parts[0], key: "default" };
|
|
187932
|
-
} else if (parts.length === 2) {
|
|
187964
|
+
} else if (parts.length === 2 && parts[0] && parts[1]) {
|
|
187933
187965
|
return { serviceName: parts[0], key: parts[1] };
|
|
187934
187966
|
}
|
|
187935
187967
|
return null;
|
|
@@ -187946,7 +187978,7 @@ function extractDrizzleGatewayKey(host) {
|
|
|
187946
187978
|
const parts = prefix.split(".");
|
|
187947
187979
|
if (parts.length === 1 && parts[0] === DRIZZLE_GATEWAY_PREFIX) {
|
|
187948
187980
|
return "default";
|
|
187949
|
-
} else if (parts.length === 2 && parts[0] === DRIZZLE_GATEWAY_PREFIX) {
|
|
187981
|
+
} else if (parts.length === 2 && parts[0] === DRIZZLE_GATEWAY_PREFIX && parts[1]) {
|
|
187950
187982
|
return parts[1];
|
|
187951
187983
|
}
|
|
187952
187984
|
return null;
|
|
@@ -187967,7 +187999,7 @@ function extractAdminKey(host) {
|
|
|
187967
187999
|
return null;
|
|
187968
188000
|
}
|
|
187969
188001
|
const parts = prefix.split(".");
|
|
187970
|
-
if (parts.length === 1) {
|
|
188002
|
+
if (parts.length === 1 && parts[0]) {
|
|
187971
188003
|
return parts[0];
|
|
187972
188004
|
}
|
|
187973
188005
|
return null;
|
|
@@ -189502,14 +189534,15 @@ Add them to the config block in specific.local`);
|
|
|
189502
189534
|
}
|
|
189503
189535
|
}
|
|
189504
189536
|
const validationErrors = validateEndpointReferences(config2);
|
|
189505
|
-
|
|
189537
|
+
const firstError = validationErrors[0];
|
|
189538
|
+
if (firstError) {
|
|
189506
189539
|
for (const error of validationErrors) {
|
|
189507
189540
|
writeLog("system:error", error.message);
|
|
189508
189541
|
}
|
|
189509
189542
|
setState((s) => ({
|
|
189510
189543
|
...s,
|
|
189511
189544
|
status: "error",
|
|
189512
|
-
error:
|
|
189545
|
+
error: firstError.message
|
|
189513
189546
|
}));
|
|
189514
189547
|
return;
|
|
189515
189548
|
}
|
|
@@ -189616,6 +189649,7 @@ Add them to the config block in specific.local`);
|
|
|
189616
189649
|
for (const s of services2) {
|
|
189617
189650
|
runningServicePorts.set(s.name, s.ports.get("default"));
|
|
189618
189651
|
}
|
|
189652
|
+
const projectId = hasProjectId() ? readProjectId() : void 0;
|
|
189619
189653
|
const getState = () => ({
|
|
189620
189654
|
status: "running",
|
|
189621
189655
|
services: config2.services.filter((svc) => runningServicePorts.has(svc.name) || svc.serve).map((svc) => ({
|
|
@@ -189630,7 +189664,8 @@ Add them to the config block in specific.local`);
|
|
|
189630
189664
|
port: r.port,
|
|
189631
189665
|
host: r.host,
|
|
189632
189666
|
syncEnabled: r.type === "postgres" && syncDatabases.has(name)
|
|
189633
|
-
}))
|
|
189667
|
+
})),
|
|
189668
|
+
projectId
|
|
189634
189669
|
});
|
|
189635
189670
|
const adminServer = await startAdminServer(getState);
|
|
189636
189671
|
adminServerRef.current = adminServer;
|
|
@@ -190283,16 +190318,19 @@ function findWidestContext(projectDir, contexts) {
|
|
|
190283
190318
|
if (contexts.length === 0) return ".";
|
|
190284
190319
|
const absolute = contexts.map((c) => path18.resolve(projectDir, c));
|
|
190285
190320
|
const segments = absolute.map((p) => p.split(path18.sep).filter(Boolean));
|
|
190321
|
+
const firstSegments = segments[0];
|
|
190322
|
+
if (!firstSegments) return ".";
|
|
190286
190323
|
const minLen = Math.min(...segments.map((s) => s.length));
|
|
190287
190324
|
let commonLength = 0;
|
|
190288
190325
|
for (let i = 0; i < minLen; i++) {
|
|
190289
|
-
|
|
190326
|
+
const firstSeg = firstSegments[i];
|
|
190327
|
+
if (firstSeg !== void 0 && segments.every((s) => s[i] === firstSeg)) {
|
|
190290
190328
|
commonLength = i + 1;
|
|
190291
190329
|
} else {
|
|
190292
190330
|
break;
|
|
190293
190331
|
}
|
|
190294
190332
|
}
|
|
190295
|
-
const ancestorSegments =
|
|
190333
|
+
const ancestorSegments = firstSegments.slice(0, commonLength);
|
|
190296
190334
|
const ancestor = path18.sep + ancestorSegments.join(path18.sep);
|
|
190297
190335
|
return path18.relative(projectDir, ancestor) || ".";
|
|
190298
190336
|
}
|
|
@@ -190326,7 +190364,7 @@ function PhaseIndicator({
|
|
|
190326
190364
|
"creating-tarball",
|
|
190327
190365
|
"creating-deployment",
|
|
190328
190366
|
"uploading",
|
|
190329
|
-
"
|
|
190367
|
+
"pending",
|
|
190330
190368
|
"deploying",
|
|
190331
190369
|
"success"
|
|
190332
190370
|
];
|
|
@@ -190364,7 +190402,10 @@ function ProjectSelector({
|
|
|
190364
190402
|
if (selectedIndex === 0) {
|
|
190365
190403
|
onSelect("new");
|
|
190366
190404
|
} else {
|
|
190367
|
-
|
|
190405
|
+
const project = projects[selectedIndex - 1];
|
|
190406
|
+
if (project) {
|
|
190407
|
+
onSelect(project);
|
|
190408
|
+
}
|
|
190368
190409
|
}
|
|
190369
190410
|
} else if (key.upArrow) {
|
|
190370
190411
|
onUp();
|
|
@@ -190395,6 +190436,30 @@ function NameInput({ onSubmit, onCancel }) {
|
|
|
190395
190436
|
});
|
|
190396
190437
|
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"));
|
|
190397
190438
|
}
|
|
190439
|
+
function getMissingSecrets(pendingActions) {
|
|
190440
|
+
if (!pendingActions) return [];
|
|
190441
|
+
const secretAction = pendingActions.find((a) => a.type === "missing_secrets");
|
|
190442
|
+
if (secretAction && secretAction.type === "missing_secrets") {
|
|
190443
|
+
return secretAction.secrets;
|
|
190444
|
+
}
|
|
190445
|
+
return [];
|
|
190446
|
+
}
|
|
190447
|
+
function getMissingConfigs(pendingActions) {
|
|
190448
|
+
if (!pendingActions) return [];
|
|
190449
|
+
const configAction = pendingActions.find((a) => a.type === "missing_configs");
|
|
190450
|
+
if (configAction && configAction.type === "missing_configs") {
|
|
190451
|
+
return configAction.configs;
|
|
190452
|
+
}
|
|
190453
|
+
return [];
|
|
190454
|
+
}
|
|
190455
|
+
function hasBuildsInProgress(pendingActions) {
|
|
190456
|
+
if (!pendingActions) return false;
|
|
190457
|
+
return pendingActions.some((a) => a.type === "build_in_progress");
|
|
190458
|
+
}
|
|
190459
|
+
function getFailedBuild(pendingActions) {
|
|
190460
|
+
if (!pendingActions) return void 0;
|
|
190461
|
+
return pendingActions.find((a) => a.type === "build_failed");
|
|
190462
|
+
}
|
|
190398
190463
|
function DeployUI({ environment, config, skipBuildTest }) {
|
|
190399
190464
|
const { exit } = useApp3();
|
|
190400
190465
|
const [state, setState] = useState6({ phase: "checking-auth" });
|
|
@@ -190563,6 +190628,7 @@ function DeployUI({ environment, config, skipBuildTest }) {
|
|
|
190563
190628
|
setState((s) => {
|
|
190564
190629
|
if (!s.missingSecrets || s.currentSecretIndex === void 0) return s;
|
|
190565
190630
|
const currentSecret2 = s.missingSecrets[s.currentSecretIndex];
|
|
190631
|
+
if (!currentSecret2) return s;
|
|
190566
190632
|
const newSecretValues = { ...s.secretValues, [currentSecret2]: value };
|
|
190567
190633
|
const nextIndex = s.currentSecretIndex + 1;
|
|
190568
190634
|
if (nextIndex < s.missingSecrets.length) {
|
|
@@ -190592,6 +190658,7 @@ function DeployUI({ environment, config, skipBuildTest }) {
|
|
|
190592
190658
|
setState((s) => {
|
|
190593
190659
|
if (!s.missingConfigs || s.currentConfigIndex === void 0) return s;
|
|
190594
190660
|
const currentConfig2 = s.missingConfigs[s.currentConfigIndex];
|
|
190661
|
+
if (!currentConfig2) return s;
|
|
190595
190662
|
const newConfigValues = { ...s.configValues, [currentConfig2]: value };
|
|
190596
190663
|
const nextIndex = s.currentConfigIndex + 1;
|
|
190597
190664
|
if (nextIndex < s.missingConfigs.length) {
|
|
@@ -190644,7 +190711,7 @@ function DeployUI({ environment, config, skipBuildTest }) {
|
|
|
190644
190711
|
writeLog("deploy", "Secrets submitted successfully");
|
|
190645
190712
|
setState((s) => ({
|
|
190646
190713
|
...s,
|
|
190647
|
-
phase: "
|
|
190714
|
+
phase: "pending",
|
|
190648
190715
|
missingSecrets: void 0,
|
|
190649
190716
|
secretValues: void 0
|
|
190650
190717
|
}));
|
|
@@ -190686,7 +190753,7 @@ function DeployUI({ environment, config, skipBuildTest }) {
|
|
|
190686
190753
|
writeLog("deploy", "Configs submitted successfully");
|
|
190687
190754
|
setState((s) => ({
|
|
190688
190755
|
...s,
|
|
190689
|
-
phase: "
|
|
190756
|
+
phase: "pending",
|
|
190690
190757
|
missingConfigs: void 0,
|
|
190691
190758
|
configValues: void 0
|
|
190692
190759
|
}));
|
|
@@ -190704,7 +190771,6 @@ function DeployUI({ environment, config, skipBuildTest }) {
|
|
|
190704
190771
|
useEffect4(() => {
|
|
190705
190772
|
if (state.phase !== "testing-builds" || !state.projectId) return;
|
|
190706
190773
|
let cancelled = false;
|
|
190707
|
-
let pollInterval;
|
|
190708
190774
|
async function runBuildTestsAndDeploy() {
|
|
190709
190775
|
const projectDir = process.cwd();
|
|
190710
190776
|
const builds = config.builds || [];
|
|
@@ -190803,148 +190869,205 @@ ${errorMsg}`
|
|
|
190803
190869
|
return;
|
|
190804
190870
|
}
|
|
190805
190871
|
if (cancelled) return;
|
|
190806
|
-
writeLog("deploy", "
|
|
190807
|
-
setState((s) => ({ ...s, phase: "
|
|
190808
|
-
let lastState;
|
|
190809
|
-
const pollForCompletion = async () => {
|
|
190810
|
-
try {
|
|
190811
|
-
const status = await client2.getDeployment(deployment2.id);
|
|
190812
|
-
if (cancelled) return;
|
|
190813
|
-
if (status.state !== lastState) {
|
|
190814
|
-
writeLog(
|
|
190815
|
-
"deploy",
|
|
190816
|
-
`Deployment state: ${status.state}${status.stateMessage ? ` - ${status.stateMessage}` : ""}`
|
|
190817
|
-
);
|
|
190818
|
-
lastState = status.state;
|
|
190819
|
-
}
|
|
190820
|
-
if (status.state === "failed") {
|
|
190821
|
-
writeLog(
|
|
190822
|
-
"deploy:error",
|
|
190823
|
-
`Deployment failed: ${status.stateMessage || "Unknown error"}`
|
|
190824
|
-
);
|
|
190825
|
-
setState((s) => ({
|
|
190826
|
-
...s,
|
|
190827
|
-
phase: "error",
|
|
190828
|
-
deployment: status,
|
|
190829
|
-
error: status.stateMessage || "Deployment failed"
|
|
190830
|
-
}));
|
|
190831
|
-
if (pollInterval) clearInterval(pollInterval);
|
|
190832
|
-
return;
|
|
190833
|
-
}
|
|
190834
|
-
if (status.state === "active") {
|
|
190835
|
-
writeLog("deploy", "Deployment successful");
|
|
190836
|
-
if (status.publicUrls) {
|
|
190837
|
-
for (const [name, url] of Object.entries(status.publicUrls)) {
|
|
190838
|
-
writeLog("deploy", `Public URL: ${name} -> ${url}`);
|
|
190839
|
-
}
|
|
190840
|
-
}
|
|
190841
|
-
setState((s) => ({ ...s, phase: "success", deployment: status }));
|
|
190842
|
-
if (pollInterval) clearInterval(pollInterval);
|
|
190843
|
-
return;
|
|
190844
|
-
}
|
|
190845
|
-
if (status.state === "awaiting_secrets") {
|
|
190846
|
-
if (pollInterval) clearInterval(pollInterval);
|
|
190847
|
-
pollInterval = void 0;
|
|
190848
|
-
const missingSecrets2 = status.missingSecrets || [];
|
|
190849
|
-
writeLog("deploy", `Awaiting secrets: ${missingSecrets2.join(", ")}`);
|
|
190850
|
-
setState((s) => ({
|
|
190851
|
-
...s,
|
|
190852
|
-
phase: "awaiting-secrets",
|
|
190853
|
-
deployment: status,
|
|
190854
|
-
missingSecrets: missingSecrets2,
|
|
190855
|
-
secretValues: {},
|
|
190856
|
-
currentSecretIndex: 0,
|
|
190857
|
-
currentSecretInput: ""
|
|
190858
|
-
}));
|
|
190859
|
-
return;
|
|
190860
|
-
}
|
|
190861
|
-
if (status.state === "awaiting_configs") {
|
|
190862
|
-
if (pollInterval) clearInterval(pollInterval);
|
|
190863
|
-
pollInterval = void 0;
|
|
190864
|
-
const missingConfigs2 = status.missingConfigs || [];
|
|
190865
|
-
writeLog("deploy", `Awaiting configs: ${missingConfigs2.join(", ")}`);
|
|
190866
|
-
setState((s) => ({
|
|
190867
|
-
...s,
|
|
190868
|
-
phase: "awaiting-configs",
|
|
190869
|
-
deployment: status,
|
|
190870
|
-
missingConfigs: missingConfigs2,
|
|
190871
|
-
configValues: {},
|
|
190872
|
-
currentConfigIndex: 0,
|
|
190873
|
-
currentConfigInput: ""
|
|
190874
|
-
}));
|
|
190875
|
-
return;
|
|
190876
|
-
}
|
|
190877
|
-
if (status.state === "deploying") {
|
|
190878
|
-
setState((s) => ({ ...s, phase: "deploying", deployment: status }));
|
|
190879
|
-
} else if (status.state === "building") {
|
|
190880
|
-
setState((s) => ({ ...s, phase: "building", deployment: status }));
|
|
190881
|
-
}
|
|
190882
|
-
} catch {
|
|
190883
|
-
}
|
|
190884
|
-
};
|
|
190885
|
-
pollInterval = setInterval(pollForCompletion, 2e3);
|
|
190886
|
-
pollForCompletion();
|
|
190872
|
+
writeLog("deploy", "Deployment in pending state, waiting for builds to complete");
|
|
190873
|
+
setState((s) => ({ ...s, phase: "pending", deployment: deployment2 }));
|
|
190887
190874
|
}
|
|
190888
190875
|
runBuildTestsAndDeploy();
|
|
190889
190876
|
return () => {
|
|
190890
190877
|
cancelled = true;
|
|
190891
|
-
if (pollInterval) clearInterval(pollInterval);
|
|
190892
190878
|
};
|
|
190893
190879
|
}, [state.projectId, environment, config.builds, skipBuildTest]);
|
|
190894
190880
|
useEffect4(() => {
|
|
190881
|
+
if (state.phase !== "pending" || !state.deployment) return;
|
|
190895
190882
|
let pollInterval;
|
|
190896
|
-
|
|
190897
|
-
|
|
190898
|
-
|
|
190899
|
-
|
|
190900
|
-
|
|
190901
|
-
|
|
190902
|
-
|
|
190903
|
-
|
|
190904
|
-
|
|
190905
|
-
|
|
190906
|
-
|
|
190907
|
-
|
|
190908
|
-
|
|
190909
|
-
|
|
190910
|
-
|
|
190911
|
-
|
|
190912
|
-
|
|
190913
|
-
|
|
190914
|
-
|
|
190915
|
-
|
|
190916
|
-
}
|
|
190917
|
-
|
|
190918
|
-
|
|
190919
|
-
|
|
190920
|
-
|
|
190921
|
-
|
|
190922
|
-
|
|
190923
|
-
|
|
190924
|
-
|
|
190925
|
-
|
|
190926
|
-
|
|
190927
|
-
|
|
190928
|
-
|
|
190929
|
-
|
|
190930
|
-
|
|
190931
|
-
|
|
190932
|
-
|
|
190933
|
-
if (
|
|
190934
|
-
|
|
190935
|
-
|
|
190936
|
-
|
|
190883
|
+
let cancelled = false;
|
|
190884
|
+
const client2 = clientRef.current;
|
|
190885
|
+
if (!client2) return;
|
|
190886
|
+
const pollForPendingActions = async () => {
|
|
190887
|
+
if (cancelled) return;
|
|
190888
|
+
try {
|
|
190889
|
+
const status = await client2.getDeployment(state.deployment.id);
|
|
190890
|
+
if (cancelled) return;
|
|
190891
|
+
writeLog(
|
|
190892
|
+
"deploy",
|
|
190893
|
+
`Deployment state: ${status.state}, pending actions: ${JSON.stringify(status.pendingActions || [])}`
|
|
190894
|
+
);
|
|
190895
|
+
if (status.state === "failed") {
|
|
190896
|
+
if (pollInterval) clearInterval(pollInterval);
|
|
190897
|
+
writeLog("deploy:error", `Deployment failed: ${status.stateMessage || "Unknown error"}`);
|
|
190898
|
+
setState((s) => ({
|
|
190899
|
+
...s,
|
|
190900
|
+
phase: "error",
|
|
190901
|
+
deployment: status,
|
|
190902
|
+
error: status.stateMessage || "Deployment failed"
|
|
190903
|
+
}));
|
|
190904
|
+
return;
|
|
190905
|
+
}
|
|
190906
|
+
const failedBuild = getFailedBuild(status.pendingActions);
|
|
190907
|
+
if (failedBuild && failedBuild.type === "build_failed") {
|
|
190908
|
+
if (pollInterval) clearInterval(pollInterval);
|
|
190909
|
+
writeLog("deploy:error", `Build failed: ${failedBuild.error}`);
|
|
190910
|
+
setState((s) => ({
|
|
190911
|
+
...s,
|
|
190912
|
+
phase: "error",
|
|
190913
|
+
deployment: status,
|
|
190914
|
+
error: `Build "${failedBuild.serviceName}" failed: ${failedBuild.error}`
|
|
190915
|
+
}));
|
|
190916
|
+
return;
|
|
190917
|
+
}
|
|
190918
|
+
const missingSecrets2 = getMissingSecrets(status.pendingActions);
|
|
190919
|
+
if (missingSecrets2.length > 0) {
|
|
190920
|
+
if (pollInterval) clearInterval(pollInterval);
|
|
190921
|
+
pollInterval = void 0;
|
|
190922
|
+
writeLog("deploy", `Awaiting secrets: ${missingSecrets2.join(", ")}`);
|
|
190923
|
+
setState((s) => ({
|
|
190924
|
+
...s,
|
|
190925
|
+
phase: "awaiting-secrets",
|
|
190926
|
+
deployment: status,
|
|
190927
|
+
pendingActions: status.pendingActions,
|
|
190928
|
+
missingSecrets: missingSecrets2,
|
|
190929
|
+
secretValues: {},
|
|
190930
|
+
currentSecretIndex: 0,
|
|
190931
|
+
currentSecretInput: ""
|
|
190932
|
+
}));
|
|
190933
|
+
return;
|
|
190934
|
+
}
|
|
190935
|
+
const missingConfigs2 = getMissingConfigs(status.pendingActions);
|
|
190936
|
+
if (missingConfigs2.length > 0) {
|
|
190937
|
+
if (pollInterval) clearInterval(pollInterval);
|
|
190938
|
+
pollInterval = void 0;
|
|
190939
|
+
writeLog("deploy", `Awaiting configs: ${missingConfigs2.join(", ")}`);
|
|
190940
|
+
setState((s) => ({
|
|
190941
|
+
...s,
|
|
190942
|
+
phase: "awaiting-configs",
|
|
190943
|
+
deployment: status,
|
|
190944
|
+
pendingActions: status.pendingActions,
|
|
190945
|
+
missingConfigs: missingConfigs2,
|
|
190946
|
+
configValues: {},
|
|
190947
|
+
currentConfigIndex: 0,
|
|
190948
|
+
currentConfigInput: ""
|
|
190949
|
+
}));
|
|
190950
|
+
return;
|
|
190951
|
+
}
|
|
190952
|
+
if (hasBuildsInProgress(status.pendingActions)) {
|
|
190953
|
+
setState((s) => ({
|
|
190954
|
+
...s,
|
|
190955
|
+
deployment: status,
|
|
190956
|
+
pendingActions: status.pendingActions
|
|
190957
|
+
}));
|
|
190958
|
+
return;
|
|
190959
|
+
}
|
|
190960
|
+
if (!status.pendingActions || status.pendingActions.length === 0) {
|
|
190961
|
+
if (pollInterval) clearInterval(pollInterval);
|
|
190962
|
+
pollInterval = void 0;
|
|
190963
|
+
writeLog("deploy", "All pending actions resolved, starting deployment");
|
|
190964
|
+
setState((s) => ({
|
|
190965
|
+
...s,
|
|
190966
|
+
phase: "starting",
|
|
190967
|
+
deployment: status,
|
|
190968
|
+
pendingActions: []
|
|
190969
|
+
}));
|
|
190970
|
+
return;
|
|
190971
|
+
}
|
|
190972
|
+
setState((s) => ({
|
|
190973
|
+
...s,
|
|
190974
|
+
deployment: status,
|
|
190975
|
+
pendingActions: status.pendingActions
|
|
190976
|
+
}));
|
|
190977
|
+
} catch (err) {
|
|
190978
|
+
writeLog("deploy", `Poll error: ${err instanceof Error ? err.message : String(err)}`);
|
|
190979
|
+
}
|
|
190980
|
+
};
|
|
190981
|
+
pollInterval = setInterval(pollForPendingActions, 2e3);
|
|
190982
|
+
pollForPendingActions();
|
|
190983
|
+
return () => {
|
|
190984
|
+
cancelled = true;
|
|
190985
|
+
if (pollInterval) clearInterval(pollInterval);
|
|
190986
|
+
};
|
|
190987
|
+
}, [state.phase, state.deployment?.id]);
|
|
190988
|
+
useEffect4(() => {
|
|
190989
|
+
if (state.phase !== "starting" || !state.deployment) return;
|
|
190990
|
+
let cancelled = false;
|
|
190991
|
+
const client2 = clientRef.current;
|
|
190992
|
+
if (!client2) return;
|
|
190993
|
+
(async () => {
|
|
190994
|
+
try {
|
|
190995
|
+
writeLog("deploy", "Calling /start endpoint");
|
|
190996
|
+
await client2.startDeployment(state.deployment.id);
|
|
190997
|
+
writeLog("deploy", "Deployment started successfully");
|
|
190998
|
+
if (cancelled) return;
|
|
190999
|
+
setState((s) => ({
|
|
191000
|
+
...s,
|
|
191001
|
+
phase: "queued"
|
|
191002
|
+
}));
|
|
191003
|
+
} catch (err) {
|
|
191004
|
+
if (cancelled) return;
|
|
191005
|
+
const errorMsg = `Failed to start deployment: ${err instanceof Error ? err.message : String(err)}`;
|
|
191006
|
+
writeLog("deploy:error", errorMsg);
|
|
191007
|
+
setState((s) => ({
|
|
191008
|
+
...s,
|
|
191009
|
+
phase: "error",
|
|
191010
|
+
error: errorMsg
|
|
191011
|
+
}));
|
|
191012
|
+
}
|
|
191013
|
+
})();
|
|
191014
|
+
return () => {
|
|
191015
|
+
cancelled = true;
|
|
191016
|
+
};
|
|
191017
|
+
}, [state.phase, state.deployment?.id]);
|
|
191018
|
+
useEffect4(() => {
|
|
191019
|
+
if (state.phase !== "queued" && state.phase !== "deploying" || !state.deployment) return;
|
|
191020
|
+
let pollInterval;
|
|
191021
|
+
let cancelled = false;
|
|
191022
|
+
const client2 = clientRef.current;
|
|
191023
|
+
if (!client2) return;
|
|
191024
|
+
const pollForCompletion = async () => {
|
|
191025
|
+
if (cancelled) return;
|
|
191026
|
+
try {
|
|
191027
|
+
const status = await client2.getDeployment(state.deployment.id);
|
|
191028
|
+
if (cancelled) return;
|
|
191029
|
+
writeLog(
|
|
191030
|
+
"deploy",
|
|
191031
|
+
`Deployment state: ${status.state}${status.stateMessage ? ` - ${status.stateMessage}` : ""}`
|
|
191032
|
+
);
|
|
191033
|
+
if (status.state === "failed") {
|
|
191034
|
+
if (pollInterval) clearInterval(pollInterval);
|
|
191035
|
+
writeLog("deploy:error", `Deployment failed: ${status.stateMessage || "Unknown error"}`);
|
|
191036
|
+
setState((s) => ({
|
|
191037
|
+
...s,
|
|
191038
|
+
phase: "error",
|
|
191039
|
+
deployment: status,
|
|
191040
|
+
error: status.stateMessage || "Deployment failed"
|
|
191041
|
+
}));
|
|
191042
|
+
return;
|
|
191043
|
+
}
|
|
191044
|
+
if (status.state === "active") {
|
|
191045
|
+
if (pollInterval) clearInterval(pollInterval);
|
|
191046
|
+
writeLog("deploy", "Deployment successful");
|
|
191047
|
+
if (status.publicUrls) {
|
|
191048
|
+
for (const [name, url] of Object.entries(status.publicUrls)) {
|
|
191049
|
+
writeLog("deploy", `Public URL: ${name} -> ${url}`);
|
|
191050
|
+
}
|
|
190937
191051
|
}
|
|
190938
|
-
|
|
191052
|
+
setState((s) => ({ ...s, phase: "success", deployment: status }));
|
|
191053
|
+
return;
|
|
190939
191054
|
}
|
|
190940
|
-
|
|
190941
|
-
|
|
190942
|
-
|
|
190943
|
-
|
|
190944
|
-
|
|
190945
|
-
}
|
|
190946
|
-
|
|
190947
|
-
|
|
191055
|
+
if (status.state === "deploying") {
|
|
191056
|
+
setState((s) => ({ ...s, phase: "deploying", deployment: status }));
|
|
191057
|
+
} else if (status.state === "queued") {
|
|
191058
|
+
setState((s) => ({ ...s, phase: "queued", deployment: status }));
|
|
191059
|
+
}
|
|
191060
|
+
} catch (err) {
|
|
191061
|
+
writeLog("deploy", `Poll error: ${err instanceof Error ? err.message : String(err)}`);
|
|
191062
|
+
}
|
|
191063
|
+
};
|
|
191064
|
+
pollInterval = setInterval(pollForCompletion, 2e3);
|
|
191065
|
+
pollForCompletion();
|
|
191066
|
+
return () => {
|
|
191067
|
+
cancelled = true;
|
|
191068
|
+
if (pollInterval) clearInterval(pollInterval);
|
|
191069
|
+
};
|
|
191070
|
+
}, [state.phase, state.deployment?.id]);
|
|
190948
191071
|
useEffect4(() => {
|
|
190949
191072
|
if (state.phase === "testing-builds") {
|
|
190950
191073
|
trackEvent("deploy_started", { environment });
|
|
@@ -190969,6 +191092,7 @@ ${errorMsg}`
|
|
|
190969
191092
|
deployment,
|
|
190970
191093
|
error,
|
|
190971
191094
|
tarballSize,
|
|
191095
|
+
pendingActions,
|
|
190972
191096
|
missingSecrets,
|
|
190973
191097
|
currentSecretIndex,
|
|
190974
191098
|
missingConfigs,
|
|
@@ -191016,7 +191140,28 @@ ${errorMsg}`
|
|
|
191016
191140
|
}
|
|
191017
191141
|
const currentSecret = missingSecrets && currentSecretIndex !== void 0 ? missingSecrets[currentSecretIndex] : void 0;
|
|
191018
191142
|
const currentConfig = missingConfigs && currentConfigIndex !== void 0 ? missingConfigs[currentConfigIndex] : void 0;
|
|
191019
|
-
const
|
|
191143
|
+
const getDisplayPhase = () => {
|
|
191144
|
+
if (phase === "awaiting-secrets" || phase === "awaiting-configs" || phase === "starting") {
|
|
191145
|
+
return "pending";
|
|
191146
|
+
}
|
|
191147
|
+
if (phase === "queued") {
|
|
191148
|
+
return "deploying";
|
|
191149
|
+
}
|
|
191150
|
+
return phase;
|
|
191151
|
+
};
|
|
191152
|
+
const displayPhase = getDisplayPhase();
|
|
191153
|
+
const getPendingLabel = () => {
|
|
191154
|
+
if (hasBuildsInProgress(pendingActions)) {
|
|
191155
|
+
return "Building images";
|
|
191156
|
+
}
|
|
191157
|
+
if (phase === "awaiting-secrets" || phase === "awaiting-configs") {
|
|
191158
|
+
return "Waiting for input";
|
|
191159
|
+
}
|
|
191160
|
+
if (phase === "starting") {
|
|
191161
|
+
return "Starting deployment";
|
|
191162
|
+
}
|
|
191163
|
+
return "Preparing";
|
|
191164
|
+
};
|
|
191020
191165
|
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(
|
|
191021
191166
|
PhaseIndicator,
|
|
191022
191167
|
{
|
|
@@ -191048,16 +191193,16 @@ ${errorMsg}`
|
|
|
191048
191193
|
), /* @__PURE__ */ React7.createElement(
|
|
191049
191194
|
PhaseIndicator,
|
|
191050
191195
|
{
|
|
191051
|
-
phase: "
|
|
191196
|
+
phase: "pending",
|
|
191052
191197
|
currentPhase: displayPhase,
|
|
191053
|
-
label:
|
|
191198
|
+
label: getPendingLabel()
|
|
191054
191199
|
}
|
|
191055
191200
|
), /* @__PURE__ */ React7.createElement(
|
|
191056
191201
|
PhaseIndicator,
|
|
191057
191202
|
{
|
|
191058
191203
|
phase: "deploying",
|
|
191059
191204
|
currentPhase: displayPhase,
|
|
191060
|
-
label: "Deploying"
|
|
191205
|
+
label: phase === "queued" ? "Waiting in queue" : "Deploying"
|
|
191061
191206
|
}
|
|
191062
191207
|
)), phase === "awaiting-secrets" && currentSecret && /* @__PURE__ */ React7.createElement(
|
|
191063
191208
|
SecretInput,
|
|
@@ -191493,7 +191638,7 @@ function logoutCommand() {
|
|
|
191493
191638
|
var program = new Command();
|
|
191494
191639
|
var env = "production";
|
|
191495
191640
|
var envLabel = env !== "production" ? `[${env.toUpperCase()}] ` : "";
|
|
191496
|
-
program.name("specific").description(`${envLabel}Infrastructure-as-code for coding agents`).version("0.1.
|
|
191641
|
+
program.name("specific").description(`${envLabel}Infrastructure-as-code for coding agents`).version("0.1.46").enablePositionalOptions();
|
|
191497
191642
|
program.command("init").description("Initialize project for use with a coding agent").action(initCommand);
|
|
191498
191643
|
program.command("docs [topic]").description("Fetch LLM-optimized documentation").action(docsCommand);
|
|
191499
191644
|
program.command("check").description("Validate specific.hcl configuration").action(checkCommand);
|