@specific.dev/cli 0.1.74 → 0.1.75
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/admin/404/index.html +1 -1
- package/dist/admin/404.html +1 -1
- package/dist/admin/__next.!KGRlZmF1bHQp.__PAGE__.txt +1 -1
- package/dist/admin/__next.!KGRlZmF1bHQp.txt +1 -1
- package/dist/admin/__next._full.txt +1 -1
- package/dist/admin/__next._head.txt +1 -1
- package/dist/admin/__next._index.txt +1 -1
- package/dist/admin/__next._tree.txt +1 -1
- package/dist/admin/_not-found/__next._full.txt +1 -1
- package/dist/admin/_not-found/__next._head.txt +1 -1
- package/dist/admin/_not-found/__next._index.txt +1 -1
- package/dist/admin/_not-found/__next._not-found.__PAGE__.txt +1 -1
- package/dist/admin/_not-found/__next._not-found.txt +1 -1
- package/dist/admin/_not-found/__next._tree.txt +1 -1
- package/dist/admin/_not-found/index.html +1 -1
- package/dist/admin/_not-found/index.txt +1 -1
- package/dist/admin/databases/__next.!KGRlZmF1bHQp.databases.__PAGE__.txt +1 -1
- package/dist/admin/databases/__next.!KGRlZmF1bHQp.databases.txt +1 -1
- package/dist/admin/databases/__next.!KGRlZmF1bHQp.txt +1 -1
- package/dist/admin/databases/__next._full.txt +1 -1
- package/dist/admin/databases/__next._head.txt +1 -1
- package/dist/admin/databases/__next._index.txt +1 -1
- package/dist/admin/databases/__next._tree.txt +1 -1
- package/dist/admin/databases/index.html +1 -1
- package/dist/admin/databases/index.txt +1 -1
- package/dist/admin/fullscreen/__next._full.txt +1 -1
- package/dist/admin/fullscreen/__next._head.txt +1 -1
- package/dist/admin/fullscreen/__next._index.txt +1 -1
- package/dist/admin/fullscreen/__next._tree.txt +1 -1
- package/dist/admin/fullscreen/__next.fullscreen.__PAGE__.txt +1 -1
- package/dist/admin/fullscreen/__next.fullscreen.txt +1 -1
- package/dist/admin/fullscreen/databases/__next._full.txt +1 -1
- package/dist/admin/fullscreen/databases/__next._head.txt +1 -1
- package/dist/admin/fullscreen/databases/__next._index.txt +1 -1
- package/dist/admin/fullscreen/databases/__next._tree.txt +1 -1
- package/dist/admin/fullscreen/databases/__next.fullscreen.databases.__PAGE__.txt +1 -1
- package/dist/admin/fullscreen/databases/__next.fullscreen.databases.txt +1 -1
- package/dist/admin/fullscreen/databases/__next.fullscreen.txt +1 -1
- package/dist/admin/fullscreen/databases/index.html +1 -1
- package/dist/admin/fullscreen/databases/index.txt +1 -1
- package/dist/admin/fullscreen/index.html +1 -1
- package/dist/admin/fullscreen/index.txt +1 -1
- package/dist/admin/index.html +1 -1
- package/dist/admin/index.txt +1 -1
- package/dist/admin/mail/__next.!KGRlZmF1bHQp.mail.__PAGE__.txt +1 -1
- package/dist/admin/mail/__next.!KGRlZmF1bHQp.mail.txt +1 -1
- package/dist/admin/mail/__next.!KGRlZmF1bHQp.txt +1 -1
- package/dist/admin/mail/__next._full.txt +1 -1
- package/dist/admin/mail/__next._head.txt +1 -1
- package/dist/admin/mail/__next._index.txt +1 -1
- package/dist/admin/mail/__next._tree.txt +1 -1
- package/dist/admin/mail/index.html +1 -1
- package/dist/admin/mail/index.txt +1 -1
- package/dist/admin/workflows/__next.!KGRlZmF1bHQp.txt +1 -1
- package/dist/admin/workflows/__next.!KGRlZmF1bHQp.workflows.__PAGE__.txt +1 -1
- package/dist/admin/workflows/__next.!KGRlZmF1bHQp.workflows.txt +1 -1
- package/dist/admin/workflows/__next._full.txt +1 -1
- package/dist/admin/workflows/__next._head.txt +1 -1
- package/dist/admin/workflows/__next._index.txt +1 -1
- package/dist/admin/workflows/__next._tree.txt +1 -1
- package/dist/admin/workflows/index.html +1 -1
- package/dist/admin/workflows/index.txt +1 -1
- package/dist/cli.js +102 -36
- package/dist/postinstall.js +1 -1
- package/package.json +1 -1
- /package/dist/admin/_next/static/{rlz8iRhM93pN2MuVf1ScD → ntsk0waJiBFcaeQ8sbm0K}/_buildManifest.js +0 -0
- /package/dist/admin/_next/static/{rlz8iRhM93pN2MuVf1ScD → ntsk0waJiBFcaeQ8sbm0K}/_clientMiddlewareManifest.json +0 -0
- /package/dist/admin/_next/static/{rlz8iRhM93pN2MuVf1ScD → ntsk0waJiBFcaeQ8sbm0K}/_ssgManifest.js +0 -0
package/dist/cli.js
CHANGED
|
@@ -183485,7 +183485,11 @@ function caInstalledInTrustStore() {
|
|
|
183485
183485
|
} else if (platform6 === "linux") {
|
|
183486
183486
|
const trustPaths = [
|
|
183487
183487
|
"/usr/local/share/ca-certificates/specific-local-ca.crt",
|
|
183488
|
-
|
|
183488
|
+
// Debian/Ubuntu
|
|
183489
|
+
"/etc/pki/ca-trust/source/anchors/specific-local-ca.crt",
|
|
183490
|
+
// RHEL/Fedora
|
|
183491
|
+
"/etc/ca-certificates/trust-source/anchors/specific-local-ca.crt"
|
|
183492
|
+
// Arch
|
|
183489
183493
|
];
|
|
183490
183494
|
for (const trustPath of trustPaths) {
|
|
183491
183495
|
if (fs.existsSync(trustPath)) {
|
|
@@ -183609,6 +183613,11 @@ function getCAInstallCommands(certPath) {
|
|
|
183609
183613
|
`cp "${certPath}" /etc/pki/ca-trust/source/anchors/specific-local-ca.crt`,
|
|
183610
183614
|
"update-ca-trust extract"
|
|
183611
183615
|
];
|
|
183616
|
+
} else if (fs.existsSync("/etc/ca-certificates/trust-source/anchors")) {
|
|
183617
|
+
return [
|
|
183618
|
+
`cp "${certPath}" /etc/ca-certificates/trust-source/anchors/specific-local-ca.crt`,
|
|
183619
|
+
"trust extract-compat"
|
|
183620
|
+
];
|
|
183612
183621
|
}
|
|
183613
183622
|
throw new Error("Could not detect Linux certificate trust mechanism");
|
|
183614
183623
|
}
|
|
@@ -184362,9 +184371,12 @@ var ApiClient = class {
|
|
|
184362
184371
|
}
|
|
184363
184372
|
return response.json();
|
|
184364
184373
|
}
|
|
184365
|
-
async createProject(name) {
|
|
184374
|
+
async createProject(name, organizationId) {
|
|
184366
184375
|
const url = `${this.baseUrl}/projects`;
|
|
184367
184376
|
const requestBody = { name };
|
|
184377
|
+
if (organizationId) {
|
|
184378
|
+
requestBody.organizationId = organizationId;
|
|
184379
|
+
}
|
|
184368
184380
|
writeLog("api", `POST ${url}`);
|
|
184369
184381
|
writeLog("api", `Request body: ${JSON.stringify(requestBody)}`);
|
|
184370
184382
|
const response = await fetch(url, {
|
|
@@ -184399,6 +184411,31 @@ var ApiClient = class {
|
|
|
184399
184411
|
}
|
|
184400
184412
|
return response.json();
|
|
184401
184413
|
}
|
|
184414
|
+
async listOrganizations() {
|
|
184415
|
+
const url = `${this.baseUrl}/user/organizations`;
|
|
184416
|
+
writeLog("api", `GET ${url}`);
|
|
184417
|
+
const response = await fetch(url, {
|
|
184418
|
+
headers: await this.authHeaders()
|
|
184419
|
+
});
|
|
184420
|
+
writeLog("api", `Response: ${response.status} ${response.statusText}`);
|
|
184421
|
+
if (!response.ok) {
|
|
184422
|
+
let errorBody;
|
|
184423
|
+
try {
|
|
184424
|
+
const error = await response.json();
|
|
184425
|
+
errorBody = JSON.stringify(error);
|
|
184426
|
+
writeLog("api:error", `API error: ${error.error} (${error.code})`);
|
|
184427
|
+
throw new Error(`Failed to list organizations: ${error.error} (${error.code})`);
|
|
184428
|
+
} catch (e) {
|
|
184429
|
+
if (e instanceof Error && e.message.startsWith("Failed to list organizations")) {
|
|
184430
|
+
throw e;
|
|
184431
|
+
}
|
|
184432
|
+
errorBody = await response.text();
|
|
184433
|
+
writeLog("api:error", `Failed to parse error response: ${errorBody}`);
|
|
184434
|
+
throw new Error(`Failed to list organizations: ${response.statusText}`);
|
|
184435
|
+
}
|
|
184436
|
+
}
|
|
184437
|
+
return response.json();
|
|
184438
|
+
}
|
|
184402
184439
|
async getMe(signal) {
|
|
184403
184440
|
const url = `${this.baseUrl}/users/me`;
|
|
184404
184441
|
writeLog("api", `GET ${url}`);
|
|
@@ -184587,7 +184624,7 @@ function trackEvent(event, properties) {
|
|
|
184587
184624
|
event,
|
|
184588
184625
|
properties: {
|
|
184589
184626
|
...properties,
|
|
184590
|
-
cli_version: "0.1.
|
|
184627
|
+
cli_version: "0.1.75",
|
|
184591
184628
|
platform: process.platform,
|
|
184592
184629
|
node_version: process.version,
|
|
184593
184630
|
project_id: getProjectId()
|
|
@@ -192866,22 +192903,35 @@ function PhaseIndicator({
|
|
|
192866
192903
|
}
|
|
192867
192904
|
return /* @__PURE__ */ React7.createElement(Text7, null, /* @__PURE__ */ React7.createElement(Text7, { dimColor: true }, " ", "\u25CB"), " ", /* @__PURE__ */ React7.createElement(Text7, { dimColor: true }, label));
|
|
192868
192905
|
}
|
|
192906
|
+
function buildSelectorItems(projects, organizations) {
|
|
192907
|
+
const items = [];
|
|
192908
|
+
for (const org of organizations) {
|
|
192909
|
+
items.push({ type: "header", orgName: org.name });
|
|
192910
|
+
items.push({ type: "new", orgId: org.id });
|
|
192911
|
+
const orgProjects = projects.filter((p) => p.organizationId === org.id);
|
|
192912
|
+
for (const project of orgProjects) {
|
|
192913
|
+
items.push({ type: "project", project });
|
|
192914
|
+
}
|
|
192915
|
+
}
|
|
192916
|
+
return items;
|
|
192917
|
+
}
|
|
192869
192918
|
function ProjectSelector({
|
|
192870
192919
|
projects,
|
|
192920
|
+
organizations,
|
|
192871
192921
|
selectedIndex,
|
|
192872
192922
|
onSelect,
|
|
192873
192923
|
onUp,
|
|
192874
192924
|
onDown
|
|
192875
192925
|
}) {
|
|
192926
|
+
const items = buildSelectorItems(projects, organizations);
|
|
192927
|
+
const selectableIndices = items.map((item, index) => item.type !== "header" ? index : -1).filter((i) => i >= 0);
|
|
192876
192928
|
useInput5((input, key) => {
|
|
192877
192929
|
if (key.return) {
|
|
192878
|
-
|
|
192879
|
-
|
|
192880
|
-
|
|
192881
|
-
|
|
192882
|
-
|
|
192883
|
-
onSelect(project);
|
|
192884
|
-
}
|
|
192930
|
+
const item = items[selectedIndex];
|
|
192931
|
+
if (item?.type === "new") {
|
|
192932
|
+
onSelect({ type: "new", orgId: item.orgId });
|
|
192933
|
+
} else if (item?.type === "project") {
|
|
192934
|
+
onSelect(item.project);
|
|
192885
192935
|
}
|
|
192886
192936
|
} else if (key.upArrow) {
|
|
192887
192937
|
onUp();
|
|
@@ -192889,11 +192939,16 @@ function ProjectSelector({
|
|
|
192889
192939
|
onDown();
|
|
192890
192940
|
}
|
|
192891
192941
|
});
|
|
192892
|
-
|
|
192893
|
-
|
|
192894
|
-
|
|
192895
|
-
|
|
192896
|
-
|
|
192942
|
+
return /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column", gap: 1 }, /* @__PURE__ */ React7.createElement(Text7, { bold: true }, "Select a project to deploy:"), /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column" }, items.map((item, index) => {
|
|
192943
|
+
if (item.type === "header") {
|
|
192944
|
+
return /* @__PURE__ */ React7.createElement(Text7, { key: `header-${item.orgName}` }, index > 0 ? "\n" : "", /* @__PURE__ */ React7.createElement(Text7, { bold: true }, item.orgName));
|
|
192945
|
+
}
|
|
192946
|
+
const isSelected = index === selectedIndex;
|
|
192947
|
+
if (item.type === "new") {
|
|
192948
|
+
return /* @__PURE__ */ React7.createElement(Text7, { key: `new-${item.orgId}` }, isSelected ? /* @__PURE__ */ React7.createElement(Text7, { color: "cyan" }, " ", "> ") : /* @__PURE__ */ React7.createElement(Text7, null, " "), /* @__PURE__ */ React7.createElement(Text7, { color: "green" }, "Create new project"));
|
|
192949
|
+
}
|
|
192950
|
+
return /* @__PURE__ */ React7.createElement(Text7, { key: item.project.id }, isSelected ? /* @__PURE__ */ React7.createElement(Text7, { color: "cyan" }, " ", "> ") : /* @__PURE__ */ React7.createElement(Text7, null, " "), /* @__PURE__ */ React7.createElement(Text7, null, item.project.name, " ", /* @__PURE__ */ React7.createElement(Text7, { dimColor: true }, "(", item.project.id, ")")));
|
|
192951
|
+
})), /* @__PURE__ */ React7.createElement(Text7, { dimColor: true }, "Use arrow keys to navigate, Enter to select"));
|
|
192897
192952
|
}
|
|
192898
192953
|
function NameInput({ onSubmit, onCancel }) {
|
|
192899
192954
|
const [value, setValue] = useState6("");
|
|
@@ -193040,12 +193095,18 @@ function DeployUI({ environment, config }) {
|
|
|
193040
193095
|
async function loadProjects() {
|
|
193041
193096
|
try {
|
|
193042
193097
|
const client2 = new ApiClient();
|
|
193043
|
-
const { projects: projects2 } = await
|
|
193098
|
+
const [{ projects: projects2 }, { organizations }] = await Promise.all([
|
|
193099
|
+
client2.listProjects(),
|
|
193100
|
+
client2.listOrganizations()
|
|
193101
|
+
]);
|
|
193044
193102
|
if (cancelled) return;
|
|
193103
|
+
const items = buildSelectorItems(projects2, organizations);
|
|
193104
|
+
const firstSelectable = items.findIndex((item) => item.type !== "header");
|
|
193045
193105
|
setState({
|
|
193046
193106
|
phase: "selecting-project",
|
|
193047
193107
|
projects: projects2,
|
|
193048
|
-
|
|
193108
|
+
organizations,
|
|
193109
|
+
selectedIndex: firstSelectable >= 0 ? firstSelectable : 0
|
|
193049
193110
|
});
|
|
193050
193111
|
} catch (err) {
|
|
193051
193112
|
if (cancelled) return;
|
|
@@ -193062,13 +193123,14 @@ function DeployUI({ environment, config }) {
|
|
|
193062
193123
|
}, [state.phase]);
|
|
193063
193124
|
const handleProjectSelect = useCallback(
|
|
193064
193125
|
(project) => {
|
|
193065
|
-
if (project === "new") {
|
|
193066
|
-
setState((s) => ({ ...s, phase: "entering-name" }));
|
|
193126
|
+
if ("type" in project && project.type === "new") {
|
|
193127
|
+
setState((s) => ({ ...s, phase: "entering-name", selectedOrganizationId: project.orgId }));
|
|
193067
193128
|
} else {
|
|
193068
|
-
|
|
193129
|
+
const proj = project;
|
|
193130
|
+
writeProjectId(proj.id);
|
|
193069
193131
|
setState({
|
|
193070
193132
|
phase: "creating-tarball",
|
|
193071
|
-
projectId:
|
|
193133
|
+
projectId: proj.id
|
|
193072
193134
|
});
|
|
193073
193135
|
}
|
|
193074
193136
|
},
|
|
@@ -193086,7 +193148,7 @@ function DeployUI({ environment, config }) {
|
|
|
193086
193148
|
async function createProject() {
|
|
193087
193149
|
try {
|
|
193088
193150
|
const client2 = new ApiClient();
|
|
193089
|
-
const project = await client2.createProject(state.newProjectName);
|
|
193151
|
+
const project = await client2.createProject(state.newProjectName, state.selectedOrganizationId);
|
|
193090
193152
|
if (cancelled) return;
|
|
193091
193153
|
writeProjectId(project.id);
|
|
193092
193154
|
setState({
|
|
@@ -193562,24 +193624,28 @@ function DeployUI({ environment, config }) {
|
|
|
193562
193624
|
if (phase === "loading-projects") {
|
|
193563
193625
|
return /* @__PURE__ */ React7.createElement(Box7, null, /* @__PURE__ */ React7.createElement(Text7, { color: "blue" }, /* @__PURE__ */ React7.createElement(Spinner5, { type: "dots" })), /* @__PURE__ */ React7.createElement(Text7, null, " Loading projects..."));
|
|
193564
193626
|
}
|
|
193565
|
-
if (phase === "selecting-project" && projects && selectedIndex !== void 0) {
|
|
193627
|
+
if (phase === "selecting-project" && projects && state.organizations && selectedIndex !== void 0) {
|
|
193628
|
+
const selectorItems = buildSelectorItems(projects, state.organizations);
|
|
193629
|
+
const selectableIndices = selectorItems.map((item, index) => item.type !== "header" ? index : -1).filter((i) => i >= 0);
|
|
193566
193630
|
return /* @__PURE__ */ React7.createElement(
|
|
193567
193631
|
ProjectSelector,
|
|
193568
193632
|
{
|
|
193569
193633
|
projects,
|
|
193634
|
+
organizations: state.organizations,
|
|
193570
193635
|
selectedIndex,
|
|
193571
193636
|
onSelect: handleProjectSelect,
|
|
193572
|
-
onUp: () => setState((s) =>
|
|
193573
|
-
|
|
193574
|
-
|
|
193575
|
-
|
|
193576
|
-
|
|
193577
|
-
|
|
193578
|
-
|
|
193579
|
-
|
|
193580
|
-
|
|
193581
|
-
)
|
|
193582
|
-
|
|
193637
|
+
onUp: () => setState((s) => {
|
|
193638
|
+
const idx = s.selectedIndex ?? 0;
|
|
193639
|
+
const currentPos = selectableIndices.indexOf(idx);
|
|
193640
|
+
const prevPos = Math.max(0, currentPos - 1);
|
|
193641
|
+
return { ...s, selectedIndex: selectableIndices[prevPos] ?? idx };
|
|
193642
|
+
}),
|
|
193643
|
+
onDown: () => setState((s) => {
|
|
193644
|
+
const idx = s.selectedIndex ?? 0;
|
|
193645
|
+
const currentPos = selectableIndices.indexOf(idx);
|
|
193646
|
+
const nextPos = Math.min(selectableIndices.length - 1, currentPos + 1);
|
|
193647
|
+
return { ...s, selectedIndex: selectableIndices[nextPos] ?? idx };
|
|
193648
|
+
})
|
|
193583
193649
|
}
|
|
193584
193650
|
);
|
|
193585
193651
|
}
|
|
@@ -194482,7 +194548,7 @@ function compareVersions(a, b) {
|
|
|
194482
194548
|
return 0;
|
|
194483
194549
|
}
|
|
194484
194550
|
async function checkForUpdate() {
|
|
194485
|
-
const currentVersion = "0.1.
|
|
194551
|
+
const currentVersion = "0.1.75";
|
|
194486
194552
|
const response = await fetch(`${BINARIES_BASE_URL}/latest?t=${Date.now()}`);
|
|
194487
194553
|
if (!response.ok) {
|
|
194488
194554
|
throw new Error(`Failed to check for updates: HTTP ${response.status}`);
|
|
@@ -194681,7 +194747,7 @@ function updateCommand() {
|
|
|
194681
194747
|
var program = new Command();
|
|
194682
194748
|
var env = "production";
|
|
194683
194749
|
var envLabel = env !== "production" ? `[${env.toUpperCase()}] ` : "";
|
|
194684
|
-
program.name("specific").description(`${envLabel}Infrastructure-as-code for coding agents`).version("0.1.
|
|
194750
|
+
program.name("specific").description(`${envLabel}Infrastructure-as-code for coding agents`).version("0.1.75").enablePositionalOptions();
|
|
194685
194751
|
program.command("init").description("Initialize project for use with a coding agent").option("--agent <name...>", "Agents to configure (cursor, claude, codex, other)").action((options2) => initCommand(options2));
|
|
194686
194752
|
program.command("docs [topic]").description("Fetch LLM-optimized documentation").action(docsCommand);
|
|
194687
194753
|
program.command("check").description("Validate specific.hcl configuration").action(checkCommand);
|
package/dist/postinstall.js
CHANGED
package/package.json
CHANGED
/package/dist/admin/_next/static/{rlz8iRhM93pN2MuVf1ScD → ntsk0waJiBFcaeQ8sbm0K}/_buildManifest.js
RENAMED
|
File without changes
|
|
File without changes
|
/package/dist/admin/_next/static/{rlz8iRhM93pN2MuVf1ScD → ntsk0waJiBFcaeQ8sbm0K}/_ssgManifest.js
RENAMED
|
File without changes
|