@specific.dev/cli 0.1.124 → 0.1.126

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 +1 -1
  4. package/dist/admin/__next.!KGRlZmF1bHQp.txt +1 -1
  5. package/dist/admin/__next._full.txt +1 -1
  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/_not-found/__next._full.txt +1 -1
  10. package/dist/admin/_not-found/__next._head.txt +1 -1
  11. package/dist/admin/_not-found/__next._index.txt +1 -1
  12. package/dist/admin/_not-found/__next._not-found.__PAGE__.txt +1 -1
  13. package/dist/admin/_not-found/__next._not-found.txt +1 -1
  14. package/dist/admin/_not-found/__next._tree.txt +1 -1
  15. package/dist/admin/_not-found/index.html +1 -1
  16. package/dist/admin/_not-found/index.txt +1 -1
  17. package/dist/admin/databases/__next.!KGRlZmF1bHQp.databases.__PAGE__.txt +1 -1
  18. package/dist/admin/databases/__next.!KGRlZmF1bHQp.databases.txt +1 -1
  19. package/dist/admin/databases/__next.!KGRlZmF1bHQp.txt +1 -1
  20. package/dist/admin/databases/__next._full.txt +1 -1
  21. package/dist/admin/databases/__next._head.txt +1 -1
  22. package/dist/admin/databases/__next._index.txt +1 -1
  23. package/dist/admin/databases/__next._tree.txt +1 -1
  24. package/dist/admin/databases/index.html +1 -1
  25. package/dist/admin/databases/index.txt +1 -1
  26. package/dist/admin/fullscreen/__next._full.txt +1 -1
  27. package/dist/admin/fullscreen/__next._head.txt +1 -1
  28. package/dist/admin/fullscreen/__next._index.txt +1 -1
  29. package/dist/admin/fullscreen/__next._tree.txt +1 -1
  30. package/dist/admin/fullscreen/__next.fullscreen.__PAGE__.txt +1 -1
  31. package/dist/admin/fullscreen/__next.fullscreen.txt +1 -1
  32. package/dist/admin/fullscreen/databases/__next._full.txt +1 -1
  33. package/dist/admin/fullscreen/databases/__next._head.txt +1 -1
  34. package/dist/admin/fullscreen/databases/__next._index.txt +1 -1
  35. package/dist/admin/fullscreen/databases/__next._tree.txt +1 -1
  36. package/dist/admin/fullscreen/databases/__next.fullscreen.databases.__PAGE__.txt +1 -1
  37. package/dist/admin/fullscreen/databases/__next.fullscreen.databases.txt +1 -1
  38. package/dist/admin/fullscreen/databases/__next.fullscreen.txt +1 -1
  39. package/dist/admin/fullscreen/databases/index.html +1 -1
  40. package/dist/admin/fullscreen/databases/index.txt +1 -1
  41. package/dist/admin/fullscreen/index.html +1 -1
  42. package/dist/admin/fullscreen/index.txt +1 -1
  43. package/dist/admin/index.html +1 -1
  44. package/dist/admin/index.txt +1 -1
  45. package/dist/admin/mail/__next.!KGRlZmF1bHQp.mail.__PAGE__.txt +1 -1
  46. package/dist/admin/mail/__next.!KGRlZmF1bHQp.mail.txt +1 -1
  47. package/dist/admin/mail/__next.!KGRlZmF1bHQp.txt +1 -1
  48. package/dist/admin/mail/__next._full.txt +1 -1
  49. package/dist/admin/mail/__next._head.txt +1 -1
  50. package/dist/admin/mail/__next._index.txt +1 -1
  51. package/dist/admin/mail/__next._tree.txt +1 -1
  52. package/dist/admin/mail/index.html +1 -1
  53. package/dist/admin/mail/index.txt +1 -1
  54. package/dist/admin/workflows/__next.!KGRlZmF1bHQp.txt +1 -1
  55. package/dist/admin/workflows/__next.!KGRlZmF1bHQp.workflows.__PAGE__.txt +1 -1
  56. package/dist/admin/workflows/__next.!KGRlZmF1bHQp.workflows.txt +1 -1
  57. package/dist/admin/workflows/__next._full.txt +1 -1
  58. package/dist/admin/workflows/__next._head.txt +1 -1
  59. package/dist/admin/workflows/__next._index.txt +1 -1
  60. package/dist/admin/workflows/__next._tree.txt +1 -1
  61. package/dist/admin/workflows/index.html +1 -1
  62. package/dist/admin/workflows/index.txt +1 -1
  63. package/dist/cli.js +81 -15
  64. package/dist/docs/postgres.md +1 -0
  65. package/package.json +1 -1
  66. /package/dist/admin/_next/static/{mW_zIz1G5hK3GXQcXI7Kb → xkQQHpz09QHzHXw5WkFYT}/_buildManifest.js +0 -0
  67. /package/dist/admin/_next/static/{mW_zIz1G5hK3GXQcXI7Kb → xkQQHpz09QHzHXw5WkFYT}/_clientMiddlewareManifest.json +0 -0
  68. /package/dist/admin/_next/static/{mW_zIz1G5hK3GXQcXI7Kb → xkQQHpz09QHzHXw5WkFYT}/_ssgManifest.js +0 -0
package/dist/cli.js CHANGED
@@ -369882,31 +369882,59 @@ function resolveEnv(env2, resources, secrets, configs, servicePort, serviceEndpo
369882
369882
  }
369883
369883
  return resolved;
369884
369884
  }
369885
- function resolveEnvForExec(env2, resources, secrets, configs) {
369885
+ function resolveEnvForExec(env2, resources, secrets, configs, runningContext) {
369886
369886
  if (!env2) {
369887
369887
  return { env: {}, missingSecrets: [], missingConfigs: [] };
369888
369888
  }
369889
369889
  const resolved = {};
369890
369890
  const missingSecrets = [];
369891
369891
  const missingConfigs = [];
369892
+ const canResolveRef = (ref) => {
369893
+ if (!runningContext) return false;
369894
+ switch (ref.type) {
369895
+ case "port":
369896
+ return runningContext.servicePort !== void 0;
369897
+ case "endpoint":
369898
+ return runningContext.currentServicePorts !== void 0;
369899
+ case "service": {
369900
+ if (!runningContext.serviceEndpoints) return false;
369901
+ if (ref.attribute === "public_url" && !runningContext.publicUrls) return false;
369902
+ return true;
369903
+ }
369904
+ case "volume":
369905
+ return false;
369906
+ default:
369907
+ return true;
369908
+ }
369909
+ };
369910
+ const isSkippableType = (type) => type === "port" || type === "endpoint" || type === "service" || type === "volume";
369892
369911
  for (const [key, value] of Object.entries(env2)) {
369893
369912
  if (typeof value === "string") {
369894
369913
  resolved[key] = value;
369895
369914
  continue;
369896
369915
  }
369897
- if (value.type === "port" || value.type === "endpoint" || value.type === "service" || value.type === "volume") {
369916
+ if (isSkippableType(value.type) && !canResolveRef(value)) {
369898
369917
  continue;
369899
369918
  }
369900
369919
  if (value.type === "interpolated") {
369901
- const hasSkippableRef = value.parts.some(
369902
- (part) => part.type === "ref" && (part.ref.type === "port" || part.ref.type === "endpoint" || part.ref.type === "service" || part.ref.type === "volume")
369920
+ const hasUnresolvableRef = value.parts.some(
369921
+ (part) => part.type === "ref" && isSkippableType(part.ref.type) && !canResolveRef(part.ref)
369903
369922
  );
369904
- if (hasSkippableRef) {
369923
+ if (hasUnresolvableRef) {
369905
369924
  continue;
369906
369925
  }
369907
369926
  }
369908
369927
  try {
369909
- resolved[key] = resolveEnvValue(value, resources, secrets, configs);
369928
+ resolved[key] = resolveEnvValue(
369929
+ value,
369930
+ resources,
369931
+ secrets,
369932
+ configs,
369933
+ runningContext?.servicePort,
369934
+ runningContext?.serviceEndpoints,
369935
+ runningContext?.currentServicePorts,
369936
+ runningContext?.publicUrls
369937
+ );
369910
369938
  } catch (err) {
369911
369939
  if (err instanceof MissingSecretError) {
369912
369940
  missingSecrets.push({ name: err.secretName, envVar: key });
@@ -370200,6 +370228,19 @@ var InstanceStateManager = class {
370200
370228
  releaseLock();
370201
370229
  }
370202
370230
  }
370231
+ async setPublicUrls(publicUrls) {
370232
+ if (!this.ownsInstances) {
370233
+ throw new Error("Cannot set public URLs: not the owner");
370234
+ }
370235
+ const releaseLock = await this.acquireLock();
370236
+ try {
370237
+ const state = this.readState();
370238
+ state.publicUrls = publicUrls;
370239
+ this.writeStateAtomic(state);
370240
+ } finally {
370241
+ releaseLock();
370242
+ }
370243
+ }
370203
370244
  async releaseOwnership() {
370204
370245
  if (!this.ownsInstances) {
370205
370246
  return;
@@ -372524,6 +372565,7 @@ Add them to the config block in specific.local`
372524
372565
  publicUrls.set(svc.name, `localhost:${svc.port}`);
372525
372566
  }
372526
372567
  }
372568
+ await stateManager.setPublicUrls(Object.fromEntries(publicUrls));
372527
372569
  const runningServices = [];
372528
372570
  const resolveServiceCwd = (service) => {
372529
372571
  if (service.root)
@@ -373341,7 +373383,7 @@ function trackEvent(event, properties) {
373341
373383
  event,
373342
373384
  properties: {
373343
373385
  ...properties,
373344
- cli_version: "0.1.124",
373386
+ cli_version: "0.1.126",
373345
373387
  platform: process.platform,
373346
373388
  node_version: process.version,
373347
373389
  project_id: getProjectId()
@@ -376585,7 +376627,7 @@ function startSpinner(text) {
376585
376627
  }
376586
376628
  };
376587
376629
  }
376588
- async function execCommand(serviceName, command, instanceKey = "default") {
376630
+ async function execCommand(serviceName, command, instanceKey = "default", options2 = {}) {
376589
376631
  if (command.length === 0) {
376590
376632
  console.error(
376591
376633
  "Error: No command provided. Usage: specific exec <service> -- <command>"
@@ -376723,11 +376765,32 @@ async function execCommand(serviceName, command, instanceKey = "default") {
376723
376765
  }
376724
376766
  }
376725
376767
  }
376768
+ let runningContext;
376769
+ if (existingInstances) {
376770
+ const serviceEndpoints = /* @__PURE__ */ new Map();
376771
+ for (const [name, svcState] of Object.entries(existingInstances.services)) {
376772
+ if (svcState.port !== void 0) {
376773
+ serviceEndpoints.set(name, [
376774
+ { serviceName: name, endpointName: "default", port: svcState.port }
376775
+ ]);
376776
+ }
376777
+ }
376778
+ const selfPort = existingInstances.services[serviceName]?.port;
376779
+ runningContext = { serviceEndpoints };
376780
+ if (selfPort !== void 0) {
376781
+ runningContext.servicePort = selfPort;
376782
+ runningContext.currentServicePorts = /* @__PURE__ */ new Map([["default", selfPort]]);
376783
+ }
376784
+ if (existingInstances.publicUrls) {
376785
+ runningContext.publicUrls = new Map(Object.entries(existingInstances.publicUrls));
376786
+ }
376787
+ }
376788
+ const effectiveEnv = runningContext && service.dev?.env ? { ...service.env, ...service.dev.env } : service.env;
376726
376789
  let resolvedEnv;
376727
376790
  try {
376728
376791
  const secrets = await prepareSecrets(config.secrets);
376729
376792
  const configs = await prepareConfigs(config.configs);
376730
- const result = resolveEnvForExec(service.env, resources, secrets, configs);
376793
+ const result = resolveEnvForExec(effectiveEnv, resources, secrets, configs, runningContext);
376731
376794
  resolvedEnv = result.env;
376732
376795
  if (result.missingSecrets.length > 0 || result.missingConfigs.length > 0) {
376733
376796
  if (result.missingSecrets.length > 0) {
@@ -376762,7 +376825,9 @@ async function execCommand(serviceName, command, instanceKey = "default") {
376762
376825
  process.on("SIGINT", () => handleSignal("SIGINT"));
376763
376826
  process.on("SIGTERM", () => handleSignal("SIGTERM"));
376764
376827
  let effectiveCwd = process.cwd();
376765
- if (service.root) {
376828
+ if (options2.cwd) {
376829
+ effectiveCwd = path21.resolve(process.cwd(), options2.cwd);
376830
+ } else if (service.root) {
376766
376831
  effectiveCwd = path21.resolve(process.cwd(), service.root);
376767
376832
  } else if (service.build) {
376768
376833
  const build = config.builds.find((b) => b.name === service.build.name);
@@ -377422,7 +377487,7 @@ function compareVersions(a, b) {
377422
377487
  return 0;
377423
377488
  }
377424
377489
  async function checkForUpdate() {
377425
- const currentVersion = "0.1.124";
377490
+ const currentVersion = "0.1.126";
377426
377491
  const response = await fetch(`${BINARIES_BASE_URL}/latest?t=${Date.now()}`);
377427
377492
  if (!response.ok) {
377428
377493
  throw new Error(`Failed to check for updates: HTTP ${response.status}`);
@@ -377692,7 +377757,7 @@ async function projectListCommand() {
377692
377757
  var program = new Command();
377693
377758
  var env = "production";
377694
377759
  var envLabel = env !== "production" ? `[${env.toUpperCase()}] ` : "";
377695
- program.name("specific").description(`${envLabel}Infrastructure-as-code for coding agents`).version("0.1.124").enablePositionalOptions();
377760
+ program.name("specific").description(`${envLabel}Infrastructure-as-code for coding agents`).version("0.1.126").enablePositionalOptions();
377696
377761
  program.command("init").description("Initialize project for use with a coding agent").option("--agent <name...>", "Agents to configure (cursor, claude, codex, other)").addHelpText("after", `
377697
377762
  Examples:
377698
377763
  $ specific init
@@ -377722,13 +377787,14 @@ Examples:
377722
377787
  $ specific deploy --secret db_url=postgres://... --config domain=app.com`).action((options2) => {
377723
377788
  deployCommand(options2);
377724
377789
  });
377725
- 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", `
377790
+ 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)").option("--cwd <path>", "Override working directory (defaults to service.root or build.root)").passThroughOptions().addHelpText("after", `
377726
377791
  Examples:
377727
377792
  $ specific exec api -- npm run migrate
377728
- $ specific exec worker -- python manage.py shell`).action(async (service, args, options2) => {
377793
+ $ specific exec worker -- python manage.py shell
377794
+ $ specific exec --cwd . api -- npx expo start`).action(async (service, args, options2) => {
377729
377795
  const filteredArgs = args[0] === "--" ? args.slice(1) : args;
377730
377796
  const key = options2.key ?? getDefaultKey();
377731
- await execCommand(service, filteredArgs, key);
377797
+ await execCommand(service, filteredArgs, key, options2.cwd !== void 0 ? { cwd: options2.cwd } : {});
377732
377798
  });
377733
377799
  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", `
377734
377800
  Examples:
@@ -42,6 +42,7 @@ The following PostgreSQL extensions are available in both development and produc
42
42
 
43
43
  - **pgvector** (`vector`) - Vector similarity search. Enable with `CREATE EXTENSION vector;` in a migration. See https://github.com/pgvector/pgvector for full documentation.
44
44
  - **pg_search** (`pg_search`) - Full-text search with BM25 ranking, powered by ParadeDB. Enable with `CREATE EXTENSION pg_search;` in a migration. See https://docs.paradedb.com/documentation/getting-started/quickstart for full documentation.
45
+ - **PostGIS** (`postgis`) - Geospatial queries and indexing over geometry and geography types. Enable with `CREATE EXTENSION postgis;` in a migration. See https://postgis.net/documentation/ for full documentation.
45
46
 
46
47
  ## Querying the database
47
48
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@specific.dev/cli",
3
- "version": "0.1.124",
3
+ "version": "0.1.126",
4
4
  "description": "CLI for Specific infrastructure-as-code",
5
5
  "type": "module",
6
6
  "main": "dist/cli.js",