@specific.dev/cli 0.1.138 → 0.1.140

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.
Files changed (68) hide show
  1. package/dist/admin/404/index.html +1 -1
  2. package/dist/admin/404.html +1 -1
  3. package/dist/admin/__next.!KGRlZmF1bHQp.__PAGE__.txt +2 -2
  4. package/dist/admin/__next.!KGRlZmF1bHQp.txt +1 -1
  5. package/dist/admin/__next._full.txt +2 -2
  6. package/dist/admin/__next._head.txt +1 -1
  7. package/dist/admin/__next._index.txt +1 -1
  8. package/dist/admin/__next._tree.txt +1 -1
  9. package/dist/admin/_next/static/chunks/{9c4a1f968df31582.js → 2dac1d24dcd83b5f.js} +2 -2
  10. package/dist/admin/_not-found/__next._full.txt +1 -1
  11. package/dist/admin/_not-found/__next._head.txt +1 -1
  12. package/dist/admin/_not-found/__next._index.txt +1 -1
  13. package/dist/admin/_not-found/__next._not-found.__PAGE__.txt +1 -1
  14. package/dist/admin/_not-found/__next._not-found.txt +1 -1
  15. package/dist/admin/_not-found/__next._tree.txt +1 -1
  16. package/dist/admin/_not-found/index.html +1 -1
  17. package/dist/admin/_not-found/index.txt +1 -1
  18. package/dist/admin/databases/__next.!KGRlZmF1bHQp.databases.__PAGE__.txt +1 -1
  19. package/dist/admin/databases/__next.!KGRlZmF1bHQp.databases.txt +1 -1
  20. package/dist/admin/databases/__next.!KGRlZmF1bHQp.txt +1 -1
  21. package/dist/admin/databases/__next._full.txt +1 -1
  22. package/dist/admin/databases/__next._head.txt +1 -1
  23. package/dist/admin/databases/__next._index.txt +1 -1
  24. package/dist/admin/databases/__next._tree.txt +1 -1
  25. package/dist/admin/databases/index.html +1 -1
  26. package/dist/admin/databases/index.txt +1 -1
  27. package/dist/admin/fullscreen/__next._full.txt +2 -2
  28. package/dist/admin/fullscreen/__next._head.txt +1 -1
  29. package/dist/admin/fullscreen/__next._index.txt +1 -1
  30. package/dist/admin/fullscreen/__next._tree.txt +1 -1
  31. package/dist/admin/fullscreen/__next.fullscreen.__PAGE__.txt +2 -2
  32. package/dist/admin/fullscreen/__next.fullscreen.txt +1 -1
  33. package/dist/admin/fullscreen/databases/__next._full.txt +1 -1
  34. package/dist/admin/fullscreen/databases/__next._head.txt +1 -1
  35. package/dist/admin/fullscreen/databases/__next._index.txt +1 -1
  36. package/dist/admin/fullscreen/databases/__next._tree.txt +1 -1
  37. package/dist/admin/fullscreen/databases/__next.fullscreen.databases.__PAGE__.txt +1 -1
  38. package/dist/admin/fullscreen/databases/__next.fullscreen.databases.txt +1 -1
  39. package/dist/admin/fullscreen/databases/__next.fullscreen.txt +1 -1
  40. package/dist/admin/fullscreen/databases/index.html +1 -1
  41. package/dist/admin/fullscreen/databases/index.txt +1 -1
  42. package/dist/admin/fullscreen/index.html +1 -1
  43. package/dist/admin/fullscreen/index.txt +2 -2
  44. package/dist/admin/index.html +1 -1
  45. package/dist/admin/index.txt +2 -2
  46. package/dist/admin/mail/__next.!KGRlZmF1bHQp.mail.__PAGE__.txt +1 -1
  47. package/dist/admin/mail/__next.!KGRlZmF1bHQp.mail.txt +1 -1
  48. package/dist/admin/mail/__next.!KGRlZmF1bHQp.txt +1 -1
  49. package/dist/admin/mail/__next._full.txt +1 -1
  50. package/dist/admin/mail/__next._head.txt +1 -1
  51. package/dist/admin/mail/__next._index.txt +1 -1
  52. package/dist/admin/mail/__next._tree.txt +1 -1
  53. package/dist/admin/mail/index.html +1 -1
  54. package/dist/admin/mail/index.txt +1 -1
  55. package/dist/admin/workflows/__next.!KGRlZmF1bHQp.txt +1 -1
  56. package/dist/admin/workflows/__next.!KGRlZmF1bHQp.workflows.__PAGE__.txt +1 -1
  57. package/dist/admin/workflows/__next.!KGRlZmF1bHQp.workflows.txt +1 -1
  58. package/dist/admin/workflows/__next._full.txt +1 -1
  59. package/dist/admin/workflows/__next._head.txt +1 -1
  60. package/dist/admin/workflows/__next._index.txt +1 -1
  61. package/dist/admin/workflows/__next._tree.txt +1 -1
  62. package/dist/admin/workflows/index.html +1 -1
  63. package/dist/admin/workflows/index.txt +1 -1
  64. package/dist/cli.js +101 -42
  65. package/package.json +1 -1
  66. /package/dist/admin/_next/static/{pHCjR5T3AY4B3i9-nU0ND → dIbCgE-_TKsqFpoght8OM}/_buildManifest.js +0 -0
  67. /package/dist/admin/_next/static/{pHCjR5T3AY4B3i9-nU0ND → dIbCgE-_TKsqFpoght8OM}/_clientMiddlewareManifest.json +0 -0
  68. /package/dist/admin/_next/static/{pHCjR5T3AY4B3i9-nU0ND → dIbCgE-_TKsqFpoght8OM}/_ssgManifest.js +0 -0
package/dist/cli.js CHANGED
@@ -373282,6 +373282,11 @@ function writePreviewEnvironmentId(environmentId, projectDir = process.cwd()) {
373282
373282
  fs3.writeFileSync(path3.join(specificDir, "preview_environment_id"), environmentId + "\n");
373283
373283
  }
373284
373284
 
373285
+ // src/lib/project/environment.ts
373286
+ function findEnvironmentByNameOrId(environments, flag) {
373287
+ return environments.find((e) => e.id === flag) ?? environments.find((e) => e.name === flag);
373288
+ }
373289
+
373285
373290
  // src/lib/auth/credentials.ts
373286
373291
  import * as fs19 from "fs";
373287
373292
  import * as path17 from "path";
@@ -373563,6 +373568,50 @@ async function performDeviceCodeLogin(deviceCode) {
373563
373568
  }
373564
373569
  }
373565
373570
 
373571
+ // src/lib/auth/github-oidc.ts
373572
+ var AUDIENCE = "specific.dev";
373573
+ var REFRESH_BUFFER_MS = 60 * 1e3;
373574
+ var cached = null;
373575
+ function isGithubActions() {
373576
+ return process.env.GITHUB_ACTIONS === "true";
373577
+ }
373578
+ async function fetchGithubActionsIdToken() {
373579
+ const now = Date.now();
373580
+ if (cached && cached.expiresAt - REFRESH_BUFFER_MS > now) {
373581
+ return cached.token;
373582
+ }
373583
+ const url = process.env.ACTIONS_ID_TOKEN_REQUEST_URL;
373584
+ const requestToken = process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN;
373585
+ if (!url || !requestToken) {
373586
+ throw new Error(
373587
+ "GitHub Actions OIDC token is not available. Add 'permissions: id-token: write' to your workflow job."
373588
+ );
373589
+ }
373590
+ const separator = url.includes("?") ? "&" : "?";
373591
+ const requestUrl = `${url}${separator}audience=${encodeURIComponent(AUDIENCE)}`;
373592
+ const response = await fetch(requestUrl, {
373593
+ method: "GET",
373594
+ headers: {
373595
+ Authorization: `bearer ${requestToken}`,
373596
+ Accept: "application/json; api-version=2.0"
373597
+ }
373598
+ });
373599
+ if (!response.ok) {
373600
+ const body = await response.text().catch(() => "");
373601
+ throw new Error(
373602
+ `Failed to fetch GitHub Actions OIDC token: HTTP ${response.status} ${response.statusText}${body ? ` \u2014 ${body.slice(0, 200)}` : ""}`
373603
+ );
373604
+ }
373605
+ const json = await response.json();
373606
+ if (typeof json.value !== "string" || json.value.length === 0) {
373607
+ throw new Error("GitHub Actions OIDC token response did not include a 'value' field");
373608
+ }
373609
+ const token = json.value;
373610
+ const expiresAt = getTokenExpiresAt(token) ?? Date.now() + 5 * 60 * 1e3;
373611
+ cached = { token, expiresAt };
373612
+ return token;
373613
+ }
373614
+
373566
373615
  // src/lib/auth/credentials.ts
373567
373616
  function getUserCredentialsDir() {
373568
373617
  return path17.join(os4.homedir(), ".specific");
@@ -373617,6 +373666,9 @@ async function saveCredentialsFromToken(token) {
373617
373666
  });
373618
373667
  }
373619
373668
  async function getValidAccessToken() {
373669
+ if (isGithubActions()) {
373670
+ return await fetchGithubActionsIdToken();
373671
+ }
373620
373672
  const credentials = readUserCredentials();
373621
373673
  if (!credentials) {
373622
373674
  throw new Error("Not logged in. Run 'specific login' first.");
@@ -373721,7 +373773,7 @@ function trackEvent(event, properties) {
373721
373773
  event,
373722
373774
  properties: {
373723
373775
  ...properties,
373724
- cli_version: "0.1.138",
373776
+ cli_version: "0.1.140",
373725
373777
  platform: process.platform,
373726
373778
  node_version: process.version,
373727
373779
  project_id: getProjectId()
@@ -375951,12 +376003,12 @@ function DeployUI({ envFlag, preview, config }) {
375951
376003
  return;
375952
376004
  }
375953
376005
  if (envFlag) {
375954
- const match = environments.find((e) => e.name === envFlag);
376006
+ const match = findEnvironmentByNameOrId(environments, envFlag);
375955
376007
  if (!match) {
375956
376008
  setState((s) => ({
375957
376009
  ...s,
375958
376010
  phase: "error",
375959
- error: `Environment "${envFlag}" not found. Available: ${environments.map((e) => e.name).join(", ")}`
376011
+ error: `Environment "${envFlag}" not found (matched against name and ID). Available: ${environments.map((e) => e.name).join(", ")}`
375960
376012
  }));
375961
376013
  return;
375962
376014
  }
@@ -376672,8 +376724,9 @@ async function runDeployPipeline(options2) {
376672
376724
  let token;
376673
376725
  try {
376674
376726
  token = await getValidAccessToken();
376675
- } catch {
376676
- console.error("Error: Not logged in.\n Run 'specific login' first.");
376727
+ } catch (err) {
376728
+ const message = err instanceof Error ? err.message : String(err);
376729
+ console.error(`Error: ${message}`);
376677
376730
  process.exit(1);
376678
376731
  }
376679
376732
  const client2 = new SpecificClient({ accessToken: token });
@@ -376703,39 +376756,43 @@ async function runDeployPipeline(options2) {
376703
376756
  const preview = await client2.createPreviewEnvironment(projectId);
376704
376757
  writePreviewEnvironmentId(preview.id, projectDir);
376705
376758
  console.log(`Preview environment "${preview.name}" created (expires: ${new Date(preview.expiresAt).toLocaleString()})`);
376706
- options2.env = preview.name;
376759
+ options2.environment = preview.name;
376707
376760
  }
376761
+ const projects = await client2.listProjects();
376762
+ const project = projects.find((p) => p.id === projectId);
376763
+ const environments = project?.environments ?? [];
376708
376764
  let environmentName;
376709
- if (options2.env) {
376710
- environmentName = options2.env;
376765
+ if (options2.environment) {
376766
+ const match = findEnvironmentByNameOrId(environments, options2.environment);
376767
+ if (!match) {
376768
+ console.error(
376769
+ `Error: Environment "${options2.environment}" not found (matched against name and ID).
376770
+ Available: ${environments.map((e) => e.name).join(", ") || "(none)"}`
376771
+ );
376772
+ process.exit(1);
376773
+ }
376774
+ environmentName = match.name;
376775
+ writeEnvironmentId(match.id);
376711
376776
  } else if (hasEnvironmentId(projectDir)) {
376712
376777
  const savedEnvId = readEnvironmentId(projectDir);
376713
- const projects = await client2.listProjects();
376714
- const project = projects.find((p) => p.id === projectId);
376715
- const env2 = project?.environments.find((e) => e.id === savedEnvId);
376778
+ const env2 = environments.find((e) => e.id === savedEnvId);
376716
376779
  if (env2) {
376717
376780
  environmentName = env2.name;
376781
+ } else if (environments.length === 1) {
376782
+ environmentName = environments[0].name;
376783
+ writeEnvironmentId(environments[0].id);
376784
+ } else if (environments.length === 0) {
376785
+ console.error("Error: No environments found for this project");
376786
+ process.exit(1);
376718
376787
  } else {
376719
- const environments = project?.environments ?? [];
376720
- if (environments.length === 1) {
376721
- environmentName = environments[0].name;
376722
- writeEnvironmentId(environments[0].id);
376723
- } else if (environments.length === 0) {
376724
- console.error("Error: No environments found for this project");
376725
- process.exit(1);
376726
- } else {
376727
- console.error(
376728
- `Error: Multiple environments available. Specify one with --env.
376788
+ console.error(
376789
+ `Error: Multiple environments available. Specify one with --environment.
376729
376790
  Available: ${environments.map((e) => e.name).join(", ")}
376730
- Example: specific deploy --env ${environments[0].name}`
376731
- );
376732
- process.exit(1);
376733
- }
376791
+ Example: specific deploy --environment ${environments[0].name}`
376792
+ );
376793
+ process.exit(1);
376734
376794
  }
376735
376795
  } else {
376736
- const projects = await client2.listProjects();
376737
- const project = projects.find((p) => p.id === projectId);
376738
- const environments = project?.environments ?? [];
376739
376796
  if (environments.length === 1) {
376740
376797
  environmentName = environments[0].name;
376741
376798
  writeEnvironmentId(environments[0].id);
@@ -376744,9 +376801,9 @@ async function runDeployPipeline(options2) {
376744
376801
  process.exit(1);
376745
376802
  } else {
376746
376803
  console.error(
376747
- `Error: Multiple environments available. Specify one with --env.
376804
+ `Error: Multiple environments available. Specify one with --environment.
376748
376805
  Available: ${environments.map((e) => e.name).join(", ")}
376749
- Example: specific deploy --env ${environments[0].name}`
376806
+ Example: specific deploy --environment ${environments[0].name}`
376750
376807
  );
376751
376808
  process.exit(1);
376752
376809
  }
@@ -376931,7 +376988,7 @@ async function deployCommand(options2) {
376931
376988
  await runDeployPipeline({
376932
376989
  config,
376933
376990
  projectId: options2.project,
376934
- env: options2.env,
376991
+ environment: options2.environment,
376935
376992
  secrets: options2.secret,
376936
376993
  configs: options2.config,
376937
376994
  preview: options2.preview
@@ -376942,7 +376999,7 @@ async function deployCommand(options2) {
376942
376999
  /* @__PURE__ */ React7.createElement(
376943
377000
  DeployUI,
376944
377001
  {
376945
- envFlag: options2.env,
377002
+ envFlag: options2.environment,
376946
377003
  preview: options2.preview,
376947
377004
  config
376948
377005
  }
@@ -377827,7 +377884,7 @@ function compareVersions(a, b) {
377827
377884
  return 0;
377828
377885
  }
377829
377886
  async function checkForUpdate() {
377830
- const currentVersion = "0.1.138";
377887
+ const currentVersion = "0.1.140";
377831
377888
  const response = await fetch(`${BINARIES_BASE_URL}/latest?t=${Date.now()}`);
377832
377889
  if (!response.ok) {
377833
377890
  throw new Error(`Failed to check for updates: HTTP ${response.status}`);
@@ -378276,7 +378333,7 @@ async function queryCommand(sqlArg, options2) {
378276
378333
  const projectId = readProjectId();
378277
378334
  const token = await getValidAccessToken();
378278
378335
  const client2 = new SpecificClient({ accessToken: token });
378279
- const environmentId = await resolveEnvironment(client2, projectId, options2.env);
378336
+ const environmentId = await resolveEnvironment(client2, projectId, options2.environment);
378280
378337
  const result = await client2.runObservabilityQuery(environmentId, sql);
378281
378338
  process.stdout.write(renderTable(result));
378282
378339
  } catch (err) {
@@ -378306,11 +378363,11 @@ async function resolveEnvironment(client2, projectId, envFlag) {
378306
378363
  const status = await client2.getProjectStatus(projectId);
378307
378364
  const environments = status.environments;
378308
378365
  if (envFlag) {
378309
- const match = environments.find((e) => e.name === envFlag);
378366
+ const match = findEnvironmentByNameOrId(environments, envFlag);
378310
378367
  if (!match) {
378311
378368
  const available = environments.map((e) => e.name).join(", ") || "(none)";
378312
378369
  throw new Error(
378313
- `Environment "${envFlag}" not found. Available: ${available}`
378370
+ `Environment "${envFlag}" not found (matched against name and ID). Available: ${available}`
378314
378371
  );
378315
378372
  }
378316
378373
  return match.id;
@@ -378329,7 +378386,7 @@ async function resolveEnvironment(client2, projectId, envFlag) {
378329
378386
  }
378330
378387
  const names = environments.map((e) => e.name).join(", ");
378331
378388
  throw new Error(
378332
- `Project has multiple environments (${names}). Pass --env <name>.`
378389
+ `Project has multiple environments (${names}). Pass --environment <name|id>.`
378333
378390
  );
378334
378391
  }
378335
378392
  function friendlyErrorMessage(raw) {
@@ -378342,7 +378399,7 @@ function friendlyErrorMessage(raw) {
378342
378399
  var program = new Command();
378343
378400
  var env = "production";
378344
378401
  var envLabel = env !== "production" ? `[${env.toUpperCase()}] ` : "";
378345
- program.name("specific").description(`${envLabel}Infrastructure-as-code for coding agents`).version("0.1.138").enablePositionalOptions();
378402
+ program.name("specific").description(`${envLabel}Infrastructure-as-code for coding agents`).version("0.1.140").enablePositionalOptions();
378346
378403
  program.command("init").description("Initialize project for use with a coding agent").option("--agent <name...>", "Agents to configure (cursor, claude, codex, other)").addHelpText("after", `
378347
378404
  Examples:
378348
378405
  $ specific init
@@ -378363,10 +378420,11 @@ Examples:
378363
378420
  const key = options2.key ?? getDefaultKey();
378364
378421
  devCommand(key, options2.tunnel ?? false);
378365
378422
  });
378366
- program.command("deploy").description("Deploy to Specific infrastructure").option("--project <id>", "Project ID to deploy to (overrides .projectid file)").option("--env <name>", "Target environment (auto-selected if only one exists)").option("--secret <key=value...>", "Secret values (repeatable)").option("--config <key=value...>", "Config values (repeatable)").option("--preview", "Deploy to an ephemeral preview environment").addHelpText("after", `
378423
+ program.command("deploy").description("Deploy to Specific infrastructure").option("--project <id>", "Project ID to deploy to (overrides .projectid file)").option("-e, --environment <name|id>", "Target environment (auto-selected if only one exists)").option("--secret <key=value...>", "Secret values (repeatable)").option("--config <key=value...>", "Config values (repeatable)").option("--preview", "Deploy to an ephemeral preview environment").addHelpText("after", `
378367
378424
  Examples:
378368
378425
  $ specific deploy
378369
- $ specific deploy --env staging
378426
+ $ specific deploy --environment staging
378427
+ $ specific deploy -e env_0abc123
378370
378428
  $ specific deploy --project proj_123
378371
378429
  $ specific deploy --preview
378372
378430
  $ specific deploy --secret db_url=postgres://... --config domain=app.com`).action((options2) => {
@@ -378419,10 +378477,11 @@ Examples:
378419
378477
  program.command("status").description("Show project, environments, and deployment status").addHelpText("after", `
378420
378478
  Examples:
378421
378479
  $ specific status`).action(statusCommand);
378422
- program.command("query [sql]").description("Run a SQL query against your environment's observability data").option("--env <name>", "Target environment (defaults to the current one)").addHelpText("after", `
378480
+ program.command("query [sql]").description("Run a SQL query against your environment's observability data").option("-e, --environment <name|id>", "Target environment (defaults to the current one)").addHelpText("after", `
378423
378481
  Examples:
378424
378482
  $ specific query "SELECT count() FROM observability.logs"
378425
- $ specific query --env staging "SELECT * FROM observability.logs LIMIT 5"
378483
+ $ specific query --environment staging "SELECT * FROM observability.logs LIMIT 5"
378484
+ $ specific query -e env_0abc123 "SELECT * FROM observability.logs LIMIT 5"
378426
378485
  $ cat queries/p99.sql | specific query
378427
378486
  $ specific query - < queries/p99.sql`).action((sql, options2) => {
378428
378487
  queryCommand(sql, options2);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@specific.dev/cli",
3
- "version": "0.1.138",
3
+ "version": "0.1.140",
4
4
  "description": "CLI for Specific infrastructure-as-code",
5
5
  "type": "module",
6
6
  "main": "dist/cli.js",