@specific.dev/cli 0.1.101 → 0.1.102
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 +2 -2
- package/dist/admin/__next.!KGRlZmF1bHQp.txt +1 -1
- package/dist/admin/__next._full.txt +2 -2
- 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/_next/static/chunks/{1f8468aeb163fb80.js → 93d028b73685d80d.js} +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 +2 -2
- 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 +2 -2
- 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 +2 -2
- package/dist/admin/index.html +1 -1
- package/dist/admin/index.txt +2 -2
- 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 +315 -16
- package/package.json +1 -1
- /package/dist/admin/_next/static/{rjO2iSMpFz_HoesjH1XgE → t6Nv9BcBf3NfJnds5W8MU}/_buildManifest.js +0 -0
- /package/dist/admin/_next/static/{rjO2iSMpFz_HoesjH1XgE → t6Nv9BcBf3NfJnds5W8MU}/_clientMiddlewareManifest.json +0 -0
- /package/dist/admin/_next/static/{rjO2iSMpFz_HoesjH1XgE → t6Nv9BcBf3NfJnds5W8MU}/_ssgManifest.js +0 -0
package/dist/cli.js
CHANGED
|
@@ -373033,7 +373033,7 @@ function trackEvent(event, properties) {
|
|
|
373033
373033
|
event,
|
|
373034
373034
|
properties: {
|
|
373035
373035
|
...properties,
|
|
373036
|
-
cli_version: "0.1.
|
|
373036
|
+
cli_version: "0.1.102",
|
|
373037
373037
|
platform: process.platform,
|
|
373038
373038
|
node_version: process.version,
|
|
373039
373039
|
project_id: getProjectId()
|
|
@@ -375666,7 +375666,185 @@ function DeployUI({ environment, config }) {
|
|
|
375666
375666
|
}
|
|
375667
375667
|
), phase === "error" && /* @__PURE__ */ React7.createElement(Box7, { marginTop: 1, flexDirection: "column" }, deployment?.error ? /* @__PURE__ */ React7.createElement(StructuredError, { error: deployment.error }) : /* @__PURE__ */ React7.createElement(Text7, { color: "red", bold: true }, error), buildOutput && /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React7.createElement(Text7, { bold: true }, "Build output:"), /* @__PURE__ */ React7.createElement(Text7, null, buildOutput))), phase === "success" && /* @__PURE__ */ React7.createElement(Box7, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React7.createElement(Text7, { color: "green" }, "Deployment successful!"), deployment?.publicUrls && Object.keys(deployment.publicUrls).length > 0 && /* @__PURE__ */ React7.createElement(Box7, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React7.createElement(Text7, { bold: true }, "Public URLs:"), Object.entries(deployment.publicUrls).map(([name, url]) => /* @__PURE__ */ React7.createElement(Text7, { key: name }, " ", name, ": ", /* @__PURE__ */ React7.createElement(Text7, { color: "cyan" }, url))))));
|
|
375668
375668
|
}
|
|
375669
|
-
async function
|
|
375669
|
+
async function runDeployPipeline(options2) {
|
|
375670
|
+
const { config } = options2;
|
|
375671
|
+
const projectDir = process.cwd();
|
|
375672
|
+
let token;
|
|
375673
|
+
try {
|
|
375674
|
+
token = await getValidAccessToken();
|
|
375675
|
+
} catch {
|
|
375676
|
+
console.error("Error: Not logged in.\n Run 'specific login' first.");
|
|
375677
|
+
process.exit(1);
|
|
375678
|
+
}
|
|
375679
|
+
const client2 = new SpecificClient({ accessToken: token });
|
|
375680
|
+
let projectId = options2.projectId;
|
|
375681
|
+
if (!projectId) {
|
|
375682
|
+
if (hasProjectId(projectDir)) {
|
|
375683
|
+
projectId = readProjectId(projectDir);
|
|
375684
|
+
} else {
|
|
375685
|
+
console.error(
|
|
375686
|
+
"Error: No project linked.\n Create one first: specific project new <name> [--org <org-id>]\n Or pass one directly: specific deploy --project <project-id>"
|
|
375687
|
+
);
|
|
375688
|
+
process.exit(1);
|
|
375689
|
+
}
|
|
375690
|
+
} else if (!hasProjectId(projectDir)) {
|
|
375691
|
+
writeProjectId(projectId);
|
|
375692
|
+
}
|
|
375693
|
+
const parsedSecrets = {};
|
|
375694
|
+
if (options2.secrets) {
|
|
375695
|
+
for (const s of options2.secrets) {
|
|
375696
|
+
const eqIndex = s.indexOf("=");
|
|
375697
|
+
if (eqIndex > 0) {
|
|
375698
|
+
parsedSecrets[s.substring(0, eqIndex)] = s.substring(eqIndex + 1);
|
|
375699
|
+
}
|
|
375700
|
+
}
|
|
375701
|
+
}
|
|
375702
|
+
const parsedConfigs = {};
|
|
375703
|
+
if (options2.configs) {
|
|
375704
|
+
for (const c of options2.configs) {
|
|
375705
|
+
const eqIndex = c.indexOf("=");
|
|
375706
|
+
if (eqIndex > 0) {
|
|
375707
|
+
parsedConfigs[c.substring(0, eqIndex)] = c.substring(eqIndex + 1);
|
|
375708
|
+
}
|
|
375709
|
+
}
|
|
375710
|
+
}
|
|
375711
|
+
console.log("Creating archive...");
|
|
375712
|
+
let tarball;
|
|
375713
|
+
let appPath;
|
|
375714
|
+
try {
|
|
375715
|
+
const result = await createTarball(config, projectDir);
|
|
375716
|
+
tarball = result.tarball;
|
|
375717
|
+
appPath = result.appPath;
|
|
375718
|
+
} catch (err) {
|
|
375719
|
+
console.error(`Error: Failed to create archive: ${err instanceof Error ? err.message : String(err)}`);
|
|
375720
|
+
process.exit(1);
|
|
375721
|
+
}
|
|
375722
|
+
console.log("Creating deployment...");
|
|
375723
|
+
let deployment;
|
|
375724
|
+
try {
|
|
375725
|
+
deployment = await client2.createDeployment(projectId, "prod");
|
|
375726
|
+
} catch (err) {
|
|
375727
|
+
console.error(`Error: Failed to create deployment: ${err instanceof Error ? err.message : String(err)}`);
|
|
375728
|
+
process.exit(1);
|
|
375729
|
+
}
|
|
375730
|
+
console.log("Uploading...");
|
|
375731
|
+
try {
|
|
375732
|
+
deployment = await client2.uploadTarball(deployment.id, tarball, appPath);
|
|
375733
|
+
} catch (err) {
|
|
375734
|
+
console.error(`Error: Failed to upload: ${err instanceof Error ? err.message : String(err)}`);
|
|
375735
|
+
process.exit(1);
|
|
375736
|
+
}
|
|
375737
|
+
console.log("Waiting for build...");
|
|
375738
|
+
while (true) {
|
|
375739
|
+
await new Promise((resolve9) => setTimeout(resolve9, 2e3));
|
|
375740
|
+
const status = await client2.getDeployment(deployment.id);
|
|
375741
|
+
deployment = status;
|
|
375742
|
+
if (status.state === "failed") {
|
|
375743
|
+
console.error(`Error: Deployment failed: ${status.stateMessage || "Unknown error"}`);
|
|
375744
|
+
process.exit(1);
|
|
375745
|
+
}
|
|
375746
|
+
const failedBuild = getFailedBuild(status.pendingActions);
|
|
375747
|
+
if (failedBuild && failedBuild.type === "build_failed") {
|
|
375748
|
+
console.error(`Error: Build "${failedBuild.serviceName}" failed: ${failedBuild.error}`);
|
|
375749
|
+
if (failedBuild.output) {
|
|
375750
|
+
console.error(`
|
|
375751
|
+
Build output:
|
|
375752
|
+
${failedBuild.output}`);
|
|
375753
|
+
}
|
|
375754
|
+
process.exit(1);
|
|
375755
|
+
}
|
|
375756
|
+
const missingSecrets = getMissingSecrets(status.pendingActions);
|
|
375757
|
+
if (missingSecrets.length > 0) {
|
|
375758
|
+
const secretsToSubmit = {};
|
|
375759
|
+
const stillMissing = [];
|
|
375760
|
+
for (const name of missingSecrets) {
|
|
375761
|
+
if (parsedSecrets[name] !== void 0) {
|
|
375762
|
+
secretsToSubmit[name] = parsedSecrets[name];
|
|
375763
|
+
} else {
|
|
375764
|
+
stillMissing.push(name);
|
|
375765
|
+
}
|
|
375766
|
+
}
|
|
375767
|
+
if (stillMissing.length > 0) {
|
|
375768
|
+
console.error(
|
|
375769
|
+
`Error: Missing required secrets: ${stillMissing.join(", ")}
|
|
375770
|
+
${stillMissing.map((s) => `specific deploy --secret ${s}=<value>`).join(" ")}`
|
|
375771
|
+
);
|
|
375772
|
+
process.exit(1);
|
|
375773
|
+
}
|
|
375774
|
+
await client2.submitSecrets(deployment.id, secretsToSubmit);
|
|
375775
|
+
continue;
|
|
375776
|
+
}
|
|
375777
|
+
const missingConfigs = getMissingConfigs(status.pendingActions);
|
|
375778
|
+
if (missingConfigs.length > 0) {
|
|
375779
|
+
const configsToSubmit = {};
|
|
375780
|
+
const stillMissing = [];
|
|
375781
|
+
for (const name of missingConfigs) {
|
|
375782
|
+
if (parsedConfigs[name] !== void 0) {
|
|
375783
|
+
configsToSubmit[name] = parsedConfigs[name];
|
|
375784
|
+
} else {
|
|
375785
|
+
stillMissing.push(name);
|
|
375786
|
+
}
|
|
375787
|
+
}
|
|
375788
|
+
if (stillMissing.length > 0) {
|
|
375789
|
+
console.error(
|
|
375790
|
+
`Error: Missing required configs: ${stillMissing.join(", ")}
|
|
375791
|
+
${stillMissing.map((c) => `specific deploy --config ${c}=<value>`).join(" ")}`
|
|
375792
|
+
);
|
|
375793
|
+
process.exit(1);
|
|
375794
|
+
}
|
|
375795
|
+
await client2.submitConfigs(deployment.id, configsToSubmit);
|
|
375796
|
+
continue;
|
|
375797
|
+
}
|
|
375798
|
+
if (hasBuildsInProgress(status.pendingActions)) {
|
|
375799
|
+
continue;
|
|
375800
|
+
}
|
|
375801
|
+
if (!status.pendingActions || status.pendingActions.length === 0) {
|
|
375802
|
+
break;
|
|
375803
|
+
}
|
|
375804
|
+
}
|
|
375805
|
+
console.log("Starting deployment...");
|
|
375806
|
+
try {
|
|
375807
|
+
await client2.startDeployment(deployment.id);
|
|
375808
|
+
} catch (err) {
|
|
375809
|
+
console.error(`Error: Failed to start deployment: ${err instanceof Error ? err.message : String(err)}`);
|
|
375810
|
+
process.exit(1);
|
|
375811
|
+
}
|
|
375812
|
+
console.log("Deploying...");
|
|
375813
|
+
while (true) {
|
|
375814
|
+
await new Promise((resolve9) => setTimeout(resolve9, 2e3));
|
|
375815
|
+
const status = await client2.getDeployment(deployment.id);
|
|
375816
|
+
deployment = status;
|
|
375817
|
+
if (status.state === "failed") {
|
|
375818
|
+
if (status.error) {
|
|
375819
|
+
console.error(`Error: ${formatErrorCode(status.error.code)}: ${status.error.message}`);
|
|
375820
|
+
if (status.error.output) {
|
|
375821
|
+
console.error(`
|
|
375822
|
+
Output:
|
|
375823
|
+
${status.error.output}`);
|
|
375824
|
+
}
|
|
375825
|
+
} else {
|
|
375826
|
+
console.error(`Error: Deployment failed: ${status.stateMessage || "Unknown error"}`);
|
|
375827
|
+
}
|
|
375828
|
+
process.exit(1);
|
|
375829
|
+
}
|
|
375830
|
+
if (status.state === "active") {
|
|
375831
|
+
deployment = status;
|
|
375832
|
+
break;
|
|
375833
|
+
}
|
|
375834
|
+
}
|
|
375835
|
+
console.log("");
|
|
375836
|
+
console.log(`\u2713 Deployed successfully`);
|
|
375837
|
+
console.log("");
|
|
375838
|
+
console.log(` deployment: ${deployment.id}`);
|
|
375839
|
+
if (deployment.publicUrls && Object.keys(deployment.publicUrls).length > 0) {
|
|
375840
|
+
console.log("");
|
|
375841
|
+
console.log(" URLs:");
|
|
375842
|
+
for (const [name, url] of Object.entries(deployment.publicUrls)) {
|
|
375843
|
+
console.log(` ${name}: ${url}`);
|
|
375844
|
+
}
|
|
375845
|
+
}
|
|
375846
|
+
}
|
|
375847
|
+
async function deployCommand(options2) {
|
|
375670
375848
|
const configPath = path19.join(process.cwd(), "specific.hcl");
|
|
375671
375849
|
if (!fs21.existsSync(configPath)) {
|
|
375672
375850
|
console.error("Error: No specific.hcl found in current directory");
|
|
@@ -375680,12 +375858,21 @@ async function deployCommand(environment) {
|
|
|
375680
375858
|
console.error(formatConfigError(err, hcl, configPath));
|
|
375681
375859
|
process.exit(1);
|
|
375682
375860
|
}
|
|
375683
|
-
const
|
|
375861
|
+
const hasNonInteractiveFlags = options2.project || options2.secret?.length || options2.config?.length;
|
|
375862
|
+
if (!isInteractive() || hasNonInteractiveFlags) {
|
|
375863
|
+
await runDeployPipeline({
|
|
375864
|
+
config,
|
|
375865
|
+
projectId: options2.project,
|
|
375866
|
+
secrets: options2.secret,
|
|
375867
|
+
configs: options2.config
|
|
375868
|
+
});
|
|
375869
|
+
return;
|
|
375870
|
+
}
|
|
375684
375871
|
render5(
|
|
375685
375872
|
/* @__PURE__ */ React7.createElement(
|
|
375686
375873
|
DeployUI,
|
|
375687
375874
|
{
|
|
375688
|
-
environment:
|
|
375875
|
+
environment: "prod",
|
|
375689
375876
|
config
|
|
375690
375877
|
}
|
|
375691
375878
|
)
|
|
@@ -376525,7 +376712,7 @@ function compareVersions(a, b) {
|
|
|
376525
376712
|
return 0;
|
|
376526
376713
|
}
|
|
376527
376714
|
async function checkForUpdate() {
|
|
376528
|
-
const currentVersion = "0.1.
|
|
376715
|
+
const currentVersion = "0.1.102";
|
|
376529
376716
|
const response = await fetch(`${BINARIES_BASE_URL}/latest?t=${Date.now()}`);
|
|
376530
376717
|
if (!response.ok) {
|
|
376531
376718
|
throw new Error(`Failed to check for updates: HTTP ${response.status}`);
|
|
@@ -376720,38 +376907,150 @@ function updateCommand() {
|
|
|
376720
376907
|
render9(/* @__PURE__ */ React11.createElement(UpdateUI, null));
|
|
376721
376908
|
}
|
|
376722
376909
|
|
|
376910
|
+
// src/commands/project.tsx
|
|
376911
|
+
async function projectNewCommand(name, options2) {
|
|
376912
|
+
try {
|
|
376913
|
+
const token = await getValidAccessToken();
|
|
376914
|
+
const client2 = new SpecificClient({ accessToken: token });
|
|
376915
|
+
let orgId = options2.org;
|
|
376916
|
+
if (!orgId) {
|
|
376917
|
+
const organizations = await client2.listOrganizations();
|
|
376918
|
+
if (organizations.length === 0) {
|
|
376919
|
+
console.error(
|
|
376920
|
+
"You don't belong to any organizations. Please create one first."
|
|
376921
|
+
);
|
|
376922
|
+
process.exit(1);
|
|
376923
|
+
}
|
|
376924
|
+
if (organizations.length === 1) {
|
|
376925
|
+
orgId = organizations[0].id;
|
|
376926
|
+
} else {
|
|
376927
|
+
console.error(
|
|
376928
|
+
"You belong to multiple organizations. Please specify one with --org.\n"
|
|
376929
|
+
);
|
|
376930
|
+
console.error("Available organizations:");
|
|
376931
|
+
for (const org of organizations) {
|
|
376932
|
+
console.error(` ${org.name} (${org.id})`);
|
|
376933
|
+
}
|
|
376934
|
+
process.exit(1);
|
|
376935
|
+
}
|
|
376936
|
+
}
|
|
376937
|
+
const project = await client2.createProject(name, orgId);
|
|
376938
|
+
console.log(`Project created: ${project.id}`);
|
|
376939
|
+
} catch (error) {
|
|
376940
|
+
const message = error instanceof Error ? error.message : "Unknown error occurred";
|
|
376941
|
+
console.error(`Failed to create project: ${message}`);
|
|
376942
|
+
process.exit(1);
|
|
376943
|
+
}
|
|
376944
|
+
}
|
|
376945
|
+
async function projectListCommand() {
|
|
376946
|
+
try {
|
|
376947
|
+
const token = await getValidAccessToken();
|
|
376948
|
+
const client2 = new SpecificClient({ accessToken: token });
|
|
376949
|
+
const [projects, organizations] = await Promise.all([
|
|
376950
|
+
client2.listProjects(),
|
|
376951
|
+
client2.listOrganizations()
|
|
376952
|
+
]);
|
|
376953
|
+
if (projects.length === 0) {
|
|
376954
|
+
console.log("No projects found.");
|
|
376955
|
+
return;
|
|
376956
|
+
}
|
|
376957
|
+
const orgMap = new Map(organizations.map((org) => [org.id, org.name]));
|
|
376958
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
376959
|
+
for (const project of projects) {
|
|
376960
|
+
const orgName = orgMap.get(project.organizationId) ?? project.organizationId;
|
|
376961
|
+
if (!grouped.has(orgName)) {
|
|
376962
|
+
grouped.set(orgName, []);
|
|
376963
|
+
}
|
|
376964
|
+
grouped.get(orgName).push({ id: project.id, name: project.name });
|
|
376965
|
+
}
|
|
376966
|
+
for (const [orgName, orgProjects] of grouped) {
|
|
376967
|
+
console.log(`${orgName}:`);
|
|
376968
|
+
for (const project of orgProjects) {
|
|
376969
|
+
console.log(` ${project.name} (${project.id})`);
|
|
376970
|
+
}
|
|
376971
|
+
}
|
|
376972
|
+
} catch (error) {
|
|
376973
|
+
const message = error instanceof Error ? error.message : "Unknown error occurred";
|
|
376974
|
+
console.error(`Failed to list projects: ${message}`);
|
|
376975
|
+
process.exit(1);
|
|
376976
|
+
}
|
|
376977
|
+
}
|
|
376978
|
+
|
|
376723
376979
|
// src/cli-program.tsx
|
|
376724
376980
|
var program = new Command();
|
|
376725
376981
|
var env = "production";
|
|
376726
376982
|
var envLabel = env !== "production" ? `[${env.toUpperCase()}] ` : "";
|
|
376727
|
-
program.name("specific").description(`${envLabel}Infrastructure-as-code for coding agents`).version("0.1.
|
|
376728
|
-
program.command("init").description("Initialize project for use with a coding agent").option("--agent <name...>", "Agents to configure (cursor, claude, codex, other)").
|
|
376729
|
-
|
|
376730
|
-
|
|
376731
|
-
|
|
376983
|
+
program.name("specific").description(`${envLabel}Infrastructure-as-code for coding agents`).version("0.1.102").enablePositionalOptions();
|
|
376984
|
+
program.command("init").description("Initialize project for use with a coding agent").option("--agent <name...>", "Agents to configure (cursor, claude, codex, other)").addHelpText("after", `
|
|
376985
|
+
Examples:
|
|
376986
|
+
$ specific init
|
|
376987
|
+
$ specific init --agent claude cursor`).action((options2) => initCommand(options2));
|
|
376988
|
+
program.command("docs [topic]").description("Fetch LLM-optimized documentation").addHelpText("after", `
|
|
376989
|
+
Examples:
|
|
376990
|
+
$ specific docs
|
|
376991
|
+
$ specific docs services
|
|
376992
|
+
$ specific docs postgres/reshape`).action(docsCommand);
|
|
376993
|
+
program.command("check").description("Validate specific.hcl configuration").addHelpText("after", `
|
|
376994
|
+
Examples:
|
|
376995
|
+
$ specific check`).action(checkCommand);
|
|
376996
|
+
program.command("dev").description("Start local development environment").option("-k, --key <key>", "Namespace for isolated dev environment (auto-detected from git worktree if not specified)").option("--tunnel", "Expose public services via localtunnel URLs").addHelpText("after", `
|
|
376997
|
+
Examples:
|
|
376998
|
+
$ specific dev
|
|
376999
|
+
$ specific dev --tunnel
|
|
377000
|
+
$ specific dev --key feature-branch`).action((options2) => {
|
|
376732
377001
|
const key = options2.key ?? getDefaultKey();
|
|
376733
377002
|
devCommand(key, options2.tunnel ?? false);
|
|
376734
377003
|
});
|
|
376735
|
-
program.command("deploy
|
|
376736
|
-
|
|
377004
|
+
program.command("deploy").description("Deploy to Specific infrastructure").option("--project <id>", "Project ID to deploy to (overrides .projectid file)").option("--secret <key=value...>", "Secret values (repeatable)").option("--config <key=value...>", "Config values (repeatable)").addHelpText("after", `
|
|
377005
|
+
Examples:
|
|
377006
|
+
$ specific deploy
|
|
377007
|
+
$ specific deploy --project proj_123
|
|
377008
|
+
$ specific deploy --secret db_url=postgres://... --config domain=app.com`).action((options2) => {
|
|
377009
|
+
deployCommand(options2);
|
|
376737
377010
|
});
|
|
376738
|
-
program.command("exec <service> [args...]").description("Run a one-off command with service environment").option("-k, --key <key>", "Dev environment namespace (auto-detected from git worktree if not specified)").passThroughOptions().
|
|
377011
|
+
program.command("exec <service> [args...]").description("Run a one-off command with service environment").option("-k, --key <key>", "Dev environment namespace (auto-detected from git worktree if not specified)").passThroughOptions().addHelpText("after", `
|
|
377012
|
+
Examples:
|
|
377013
|
+
$ specific exec api -- npm run migrate
|
|
377014
|
+
$ specific exec worker -- python manage.py shell`).action(async (service, args, options2) => {
|
|
376739
377015
|
const filteredArgs = args[0] === "--" ? args.slice(1) : args;
|
|
376740
377016
|
const key = options2.key ?? getDefaultKey();
|
|
376741
377017
|
await execCommand(service, filteredArgs, key);
|
|
376742
377018
|
});
|
|
376743
|
-
program.command("psql [database] [args...]").description("Connect to a Postgres database").option("-k, --key <key>", "Dev environment namespace (auto-detected from git worktree if not specified)").passThroughOptions().
|
|
377019
|
+
program.command("psql [database] [args...]").description("Connect to a Postgres database").option("-k, --key <key>", "Dev environment namespace (auto-detected from git worktree if not specified)").passThroughOptions().addHelpText("after", `
|
|
377020
|
+
Examples:
|
|
377021
|
+
$ specific psql
|
|
377022
|
+
$ specific psql mydb
|
|
377023
|
+
$ specific psql mydb -- -c "SELECT 1"`).action((database, args, options2) => {
|
|
376744
377024
|
const filteredArgs = args[0] === "--" ? args.slice(1) : args;
|
|
376745
377025
|
const key = options2.key ?? getDefaultKey();
|
|
376746
377026
|
psqlCommand(database, key, filteredArgs);
|
|
376747
377027
|
});
|
|
376748
|
-
program.command("reshape <action> [database]").description("Run Reshape migrations (start|complete|status|abort)").option("-k, --key <key>", "Dev environment namespace (auto-detected from git worktree if not specified)").
|
|
377028
|
+
program.command("reshape <action> [database]").description("Run Reshape migrations (start|complete|status|abort)").option("-k, --key <key>", "Dev environment namespace (auto-detected from git worktree if not specified)").addHelpText("after", `
|
|
377029
|
+
Examples:
|
|
377030
|
+
$ specific reshape start
|
|
377031
|
+
$ specific reshape complete
|
|
377032
|
+
$ specific reshape status mydb`).action((action, database, options2) => {
|
|
376749
377033
|
const key = options2.key ?? getDefaultKey();
|
|
376750
377034
|
reshapeCommand(action, database, key);
|
|
376751
377035
|
});
|
|
376752
|
-
program.command("clean").description("Remove .specific directory for a clean slate").option("-k, --key <key>", "Clean only the specified dev environment key").
|
|
377036
|
+
program.command("clean").description("Remove .specific directory for a clean slate").option("-k, --key <key>", "Clean only the specified dev environment key").addHelpText("after", `
|
|
377037
|
+
Examples:
|
|
377038
|
+
$ specific clean
|
|
377039
|
+
$ specific clean --key feature-branch`).action((options2) => {
|
|
376753
377040
|
cleanCommand(options2.key);
|
|
376754
377041
|
});
|
|
377042
|
+
var projectCmd = program.command("project").description("Manage projects");
|
|
377043
|
+
projectCmd.command("new <name>").description("Create a new project").option("--org <id>", "Organization ID (required if you belong to multiple organizations)").addHelpText("after", `
|
|
377044
|
+
Examples:
|
|
377045
|
+
$ specific project new my-app
|
|
377046
|
+
$ specific project new my-app --org org_123`).action((name, options2) => {
|
|
377047
|
+
projectNewCommand(name, options2);
|
|
377048
|
+
});
|
|
377049
|
+
projectCmd.command("list").description("List all projects").addHelpText("after", `
|
|
377050
|
+
Examples:
|
|
377051
|
+
$ specific project list`).action(() => {
|
|
377052
|
+
projectListCommand();
|
|
377053
|
+
});
|
|
376755
377054
|
program.command("beta").description("Manage beta feature flags").action(betaCommand);
|
|
376756
377055
|
program.command("update").description("Update Specific CLI to the latest version").action(updateCommand);
|
|
376757
377056
|
program.command("login").description("Log in to Specific").action(loginCommand);
|
package/package.json
CHANGED
/package/dist/admin/_next/static/{rjO2iSMpFz_HoesjH1XgE → t6Nv9BcBf3NfJnds5W8MU}/_buildManifest.js
RENAMED
|
File without changes
|
|
File without changes
|
/package/dist/admin/_next/static/{rjO2iSMpFz_HoesjH1XgE → t6Nv9BcBf3NfJnds5W8MU}/_ssgManifest.js
RENAMED
|
File without changes
|