@specific.dev/cli 0.1.45 → 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 +9 -9
- package/dist/admin/__next._head.txt +1 -1
- package/dist/admin/__next._index.txt +8 -8
- package/dist/admin/__next._tree.txt +2 -2
- package/dist/admin/_next/static/chunks/64efcb432fae8c98.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/{b4fa9a08d6dc37c1.js → e13659c7ad8234ce.js} +1 -1
- package/dist/admin/_not-found/__next._full.txt +8 -8
- package/dist/admin/_not-found/__next._head.txt +1 -1
- package/dist/admin/_not-found/__next._index.txt +8 -8
- 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 +8 -8
- package/dist/admin/databases/__next._full.txt +9 -9
- package/dist/admin/databases/__next._head.txt +1 -1
- package/dist/admin/databases/__next._index.txt +8 -8
- package/dist/admin/databases/__next._tree.txt +2 -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 +9 -9
- package/dist/admin/index.html +1 -1
- package/dist/admin/index.txt +9 -9
- package/dist/cli.js +302 -159
- package/package.json +1 -1
- package/dist/admin/_next/static/chunks/0cb2c4291ba35581.css +0 -4
- package/dist/admin/_next/static/chunks/721087f8fbaa34b3.js +0 -1
- package/dist/admin/_next/static/chunks/db72df2e613a023e.js +0 -5
- package/dist/admin/_next/static/chunks/e3f73cf77dd1ede1.js +0 -1
- /package/dist/admin/_next/static/{WUdRH_Qksuvhq_ji1IkHb → uXSe8Dmoqn0jmhvY6Iln0}/_buildManifest.js +0 -0
- /package/dist/admin/_next/static/{WUdRH_Qksuvhq_ji1IkHb → uXSe8Dmoqn0jmhvY6Iln0}/_clientMiddlewareManifest.json +0 -0
- /package/dist/admin/_next/static/{WUdRH_Qksuvhq_ji1IkHb → 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
|
}
|
|
@@ -190285,16 +190318,19 @@ function findWidestContext(projectDir, contexts) {
|
|
|
190285
190318
|
if (contexts.length === 0) return ".";
|
|
190286
190319
|
const absolute = contexts.map((c) => path18.resolve(projectDir, c));
|
|
190287
190320
|
const segments = absolute.map((p) => p.split(path18.sep).filter(Boolean));
|
|
190321
|
+
const firstSegments = segments[0];
|
|
190322
|
+
if (!firstSegments) return ".";
|
|
190288
190323
|
const minLen = Math.min(...segments.map((s) => s.length));
|
|
190289
190324
|
let commonLength = 0;
|
|
190290
190325
|
for (let i = 0; i < minLen; i++) {
|
|
190291
|
-
|
|
190326
|
+
const firstSeg = firstSegments[i];
|
|
190327
|
+
if (firstSeg !== void 0 && segments.every((s) => s[i] === firstSeg)) {
|
|
190292
190328
|
commonLength = i + 1;
|
|
190293
190329
|
} else {
|
|
190294
190330
|
break;
|
|
190295
190331
|
}
|
|
190296
190332
|
}
|
|
190297
|
-
const ancestorSegments =
|
|
190333
|
+
const ancestorSegments = firstSegments.slice(0, commonLength);
|
|
190298
190334
|
const ancestor = path18.sep + ancestorSegments.join(path18.sep);
|
|
190299
190335
|
return path18.relative(projectDir, ancestor) || ".";
|
|
190300
190336
|
}
|
|
@@ -190328,7 +190364,7 @@ function PhaseIndicator({
|
|
|
190328
190364
|
"creating-tarball",
|
|
190329
190365
|
"creating-deployment",
|
|
190330
190366
|
"uploading",
|
|
190331
|
-
"
|
|
190367
|
+
"pending",
|
|
190332
190368
|
"deploying",
|
|
190333
190369
|
"success"
|
|
190334
190370
|
];
|
|
@@ -190366,7 +190402,10 @@ function ProjectSelector({
|
|
|
190366
190402
|
if (selectedIndex === 0) {
|
|
190367
190403
|
onSelect("new");
|
|
190368
190404
|
} else {
|
|
190369
|
-
|
|
190405
|
+
const project = projects[selectedIndex - 1];
|
|
190406
|
+
if (project) {
|
|
190407
|
+
onSelect(project);
|
|
190408
|
+
}
|
|
190370
190409
|
}
|
|
190371
190410
|
} else if (key.upArrow) {
|
|
190372
190411
|
onUp();
|
|
@@ -190397,6 +190436,30 @@ function NameInput({ onSubmit, onCancel }) {
|
|
|
190397
190436
|
});
|
|
190398
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"));
|
|
190399
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
|
+
}
|
|
190400
190463
|
function DeployUI({ environment, config, skipBuildTest }) {
|
|
190401
190464
|
const { exit } = useApp3();
|
|
190402
190465
|
const [state, setState] = useState6({ phase: "checking-auth" });
|
|
@@ -190565,6 +190628,7 @@ function DeployUI({ environment, config, skipBuildTest }) {
|
|
|
190565
190628
|
setState((s) => {
|
|
190566
190629
|
if (!s.missingSecrets || s.currentSecretIndex === void 0) return s;
|
|
190567
190630
|
const currentSecret2 = s.missingSecrets[s.currentSecretIndex];
|
|
190631
|
+
if (!currentSecret2) return s;
|
|
190568
190632
|
const newSecretValues = { ...s.secretValues, [currentSecret2]: value };
|
|
190569
190633
|
const nextIndex = s.currentSecretIndex + 1;
|
|
190570
190634
|
if (nextIndex < s.missingSecrets.length) {
|
|
@@ -190594,6 +190658,7 @@ function DeployUI({ environment, config, skipBuildTest }) {
|
|
|
190594
190658
|
setState((s) => {
|
|
190595
190659
|
if (!s.missingConfigs || s.currentConfigIndex === void 0) return s;
|
|
190596
190660
|
const currentConfig2 = s.missingConfigs[s.currentConfigIndex];
|
|
190661
|
+
if (!currentConfig2) return s;
|
|
190597
190662
|
const newConfigValues = { ...s.configValues, [currentConfig2]: value };
|
|
190598
190663
|
const nextIndex = s.currentConfigIndex + 1;
|
|
190599
190664
|
if (nextIndex < s.missingConfigs.length) {
|
|
@@ -190646,7 +190711,7 @@ function DeployUI({ environment, config, skipBuildTest }) {
|
|
|
190646
190711
|
writeLog("deploy", "Secrets submitted successfully");
|
|
190647
190712
|
setState((s) => ({
|
|
190648
190713
|
...s,
|
|
190649
|
-
phase: "
|
|
190714
|
+
phase: "pending",
|
|
190650
190715
|
missingSecrets: void 0,
|
|
190651
190716
|
secretValues: void 0
|
|
190652
190717
|
}));
|
|
@@ -190688,7 +190753,7 @@ function DeployUI({ environment, config, skipBuildTest }) {
|
|
|
190688
190753
|
writeLog("deploy", "Configs submitted successfully");
|
|
190689
190754
|
setState((s) => ({
|
|
190690
190755
|
...s,
|
|
190691
|
-
phase: "
|
|
190756
|
+
phase: "pending",
|
|
190692
190757
|
missingConfigs: void 0,
|
|
190693
190758
|
configValues: void 0
|
|
190694
190759
|
}));
|
|
@@ -190706,7 +190771,6 @@ function DeployUI({ environment, config, skipBuildTest }) {
|
|
|
190706
190771
|
useEffect4(() => {
|
|
190707
190772
|
if (state.phase !== "testing-builds" || !state.projectId) return;
|
|
190708
190773
|
let cancelled = false;
|
|
190709
|
-
let pollInterval;
|
|
190710
190774
|
async function runBuildTestsAndDeploy() {
|
|
190711
190775
|
const projectDir = process.cwd();
|
|
190712
190776
|
const builds = config.builds || [];
|
|
@@ -190805,148 +190869,205 @@ ${errorMsg}`
|
|
|
190805
190869
|
return;
|
|
190806
190870
|
}
|
|
190807
190871
|
if (cancelled) return;
|
|
190808
|
-
writeLog("deploy", "
|
|
190809
|
-
setState((s) => ({ ...s, phase: "
|
|
190810
|
-
let lastState;
|
|
190811
|
-
const pollForCompletion = async () => {
|
|
190812
|
-
try {
|
|
190813
|
-
const status = await client2.getDeployment(deployment2.id);
|
|
190814
|
-
if (cancelled) return;
|
|
190815
|
-
if (status.state !== lastState) {
|
|
190816
|
-
writeLog(
|
|
190817
|
-
"deploy",
|
|
190818
|
-
`Deployment state: ${status.state}${status.stateMessage ? ` - ${status.stateMessage}` : ""}`
|
|
190819
|
-
);
|
|
190820
|
-
lastState = status.state;
|
|
190821
|
-
}
|
|
190822
|
-
if (status.state === "failed") {
|
|
190823
|
-
writeLog(
|
|
190824
|
-
"deploy:error",
|
|
190825
|
-
`Deployment failed: ${status.stateMessage || "Unknown error"}`
|
|
190826
|
-
);
|
|
190827
|
-
setState((s) => ({
|
|
190828
|
-
...s,
|
|
190829
|
-
phase: "error",
|
|
190830
|
-
deployment: status,
|
|
190831
|
-
error: status.stateMessage || "Deployment failed"
|
|
190832
|
-
}));
|
|
190833
|
-
if (pollInterval) clearInterval(pollInterval);
|
|
190834
|
-
return;
|
|
190835
|
-
}
|
|
190836
|
-
if (status.state === "active") {
|
|
190837
|
-
writeLog("deploy", "Deployment successful");
|
|
190838
|
-
if (status.publicUrls) {
|
|
190839
|
-
for (const [name, url] of Object.entries(status.publicUrls)) {
|
|
190840
|
-
writeLog("deploy", `Public URL: ${name} -> ${url}`);
|
|
190841
|
-
}
|
|
190842
|
-
}
|
|
190843
|
-
setState((s) => ({ ...s, phase: "success", deployment: status }));
|
|
190844
|
-
if (pollInterval) clearInterval(pollInterval);
|
|
190845
|
-
return;
|
|
190846
|
-
}
|
|
190847
|
-
if (status.state === "awaiting_secrets") {
|
|
190848
|
-
if (pollInterval) clearInterval(pollInterval);
|
|
190849
|
-
pollInterval = void 0;
|
|
190850
|
-
const missingSecrets2 = status.missingSecrets || [];
|
|
190851
|
-
writeLog("deploy", `Awaiting secrets: ${missingSecrets2.join(", ")}`);
|
|
190852
|
-
setState((s) => ({
|
|
190853
|
-
...s,
|
|
190854
|
-
phase: "awaiting-secrets",
|
|
190855
|
-
deployment: status,
|
|
190856
|
-
missingSecrets: missingSecrets2,
|
|
190857
|
-
secretValues: {},
|
|
190858
|
-
currentSecretIndex: 0,
|
|
190859
|
-
currentSecretInput: ""
|
|
190860
|
-
}));
|
|
190861
|
-
return;
|
|
190862
|
-
}
|
|
190863
|
-
if (status.state === "awaiting_configs") {
|
|
190864
|
-
if (pollInterval) clearInterval(pollInterval);
|
|
190865
|
-
pollInterval = void 0;
|
|
190866
|
-
const missingConfigs2 = status.missingConfigs || [];
|
|
190867
|
-
writeLog("deploy", `Awaiting configs: ${missingConfigs2.join(", ")}`);
|
|
190868
|
-
setState((s) => ({
|
|
190869
|
-
...s,
|
|
190870
|
-
phase: "awaiting-configs",
|
|
190871
|
-
deployment: status,
|
|
190872
|
-
missingConfigs: missingConfigs2,
|
|
190873
|
-
configValues: {},
|
|
190874
|
-
currentConfigIndex: 0,
|
|
190875
|
-
currentConfigInput: ""
|
|
190876
|
-
}));
|
|
190877
|
-
return;
|
|
190878
|
-
}
|
|
190879
|
-
if (status.state === "deploying") {
|
|
190880
|
-
setState((s) => ({ ...s, phase: "deploying", deployment: status }));
|
|
190881
|
-
} else if (status.state === "building") {
|
|
190882
|
-
setState((s) => ({ ...s, phase: "building", deployment: status }));
|
|
190883
|
-
}
|
|
190884
|
-
} catch {
|
|
190885
|
-
}
|
|
190886
|
-
};
|
|
190887
|
-
pollInterval = setInterval(pollForCompletion, 2e3);
|
|
190888
|
-
pollForCompletion();
|
|
190872
|
+
writeLog("deploy", "Deployment in pending state, waiting for builds to complete");
|
|
190873
|
+
setState((s) => ({ ...s, phase: "pending", deployment: deployment2 }));
|
|
190889
190874
|
}
|
|
190890
190875
|
runBuildTestsAndDeploy();
|
|
190891
190876
|
return () => {
|
|
190892
190877
|
cancelled = true;
|
|
190893
|
-
if (pollInterval) clearInterval(pollInterval);
|
|
190894
190878
|
};
|
|
190895
190879
|
}, [state.projectId, environment, config.builds, skipBuildTest]);
|
|
190896
190880
|
useEffect4(() => {
|
|
190881
|
+
if (state.phase !== "pending" || !state.deployment) return;
|
|
190897
190882
|
let pollInterval;
|
|
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
|
-
|
|
190934
|
-
|
|
190935
|
-
if (
|
|
190936
|
-
|
|
190937
|
-
|
|
190938
|
-
|
|
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
|
+
}
|
|
190939
191051
|
}
|
|
190940
|
-
|
|
191052
|
+
setState((s) => ({ ...s, phase: "success", deployment: status }));
|
|
191053
|
+
return;
|
|
190941
191054
|
}
|
|
190942
|
-
|
|
190943
|
-
|
|
190944
|
-
|
|
190945
|
-
|
|
190946
|
-
|
|
190947
|
-
}
|
|
190948
|
-
|
|
190949
|
-
|
|
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]);
|
|
190950
191071
|
useEffect4(() => {
|
|
190951
191072
|
if (state.phase === "testing-builds") {
|
|
190952
191073
|
trackEvent("deploy_started", { environment });
|
|
@@ -190971,6 +191092,7 @@ ${errorMsg}`
|
|
|
190971
191092
|
deployment,
|
|
190972
191093
|
error,
|
|
190973
191094
|
tarballSize,
|
|
191095
|
+
pendingActions,
|
|
190974
191096
|
missingSecrets,
|
|
190975
191097
|
currentSecretIndex,
|
|
190976
191098
|
missingConfigs,
|
|
@@ -191018,7 +191140,28 @@ ${errorMsg}`
|
|
|
191018
191140
|
}
|
|
191019
191141
|
const currentSecret = missingSecrets && currentSecretIndex !== void 0 ? missingSecrets[currentSecretIndex] : void 0;
|
|
191020
191142
|
const currentConfig = missingConfigs && currentConfigIndex !== void 0 ? missingConfigs[currentConfigIndex] : void 0;
|
|
191021
|
-
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
|
+
};
|
|
191022
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(
|
|
191023
191166
|
PhaseIndicator,
|
|
191024
191167
|
{
|
|
@@ -191050,16 +191193,16 @@ ${errorMsg}`
|
|
|
191050
191193
|
), /* @__PURE__ */ React7.createElement(
|
|
191051
191194
|
PhaseIndicator,
|
|
191052
191195
|
{
|
|
191053
|
-
phase: "
|
|
191196
|
+
phase: "pending",
|
|
191054
191197
|
currentPhase: displayPhase,
|
|
191055
|
-
label:
|
|
191198
|
+
label: getPendingLabel()
|
|
191056
191199
|
}
|
|
191057
191200
|
), /* @__PURE__ */ React7.createElement(
|
|
191058
191201
|
PhaseIndicator,
|
|
191059
191202
|
{
|
|
191060
191203
|
phase: "deploying",
|
|
191061
191204
|
currentPhase: displayPhase,
|
|
191062
|
-
label: "Deploying"
|
|
191205
|
+
label: phase === "queued" ? "Waiting in queue" : "Deploying"
|
|
191063
191206
|
}
|
|
191064
191207
|
)), phase === "awaiting-secrets" && currentSecret && /* @__PURE__ */ React7.createElement(
|
|
191065
191208
|
SecretInput,
|
|
@@ -191495,7 +191638,7 @@ function logoutCommand() {
|
|
|
191495
191638
|
var program = new Command();
|
|
191496
191639
|
var env = "production";
|
|
191497
191640
|
var envLabel = env !== "production" ? `[${env.toUpperCase()}] ` : "";
|
|
191498
|
-
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();
|
|
191499
191642
|
program.command("init").description("Initialize project for use with a coding agent").action(initCommand);
|
|
191500
191643
|
program.command("docs [topic]").description("Fetch LLM-optimized documentation").action(docsCommand);
|
|
191501
191644
|
program.command("check").description("Validate specific.hcl configuration").action(checkCommand);
|