@specific.dev/cli 0.1.127 → 0.1.129

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 (67) 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 +149 -35
  64. package/package.json +1 -1
  65. /package/dist/admin/_next/static/{tWkoycW-NhVqIuvprR9OV → wMHOi2gUxRLxCjfghptW7}/_buildManifest.js +0 -0
  66. /package/dist/admin/_next/static/{tWkoycW-NhVqIuvprR9OV → wMHOi2gUxRLxCjfghptW7}/_clientMiddlewareManifest.json +0 -0
  67. /package/dist/admin/_next/static/{tWkoycW-NhVqIuvprR9OV → wMHOi2gUxRLxCjfghptW7}/_ssgManifest.js +0 -0
package/dist/cli.js CHANGED
@@ -184188,9 +184188,9 @@ var NodeFsHandler = class {
184188
184188
  if (this.fsw.closed) {
184189
184189
  return;
184190
184190
  }
184191
- const dirname10 = sp.dirname(file);
184191
+ const dirname11 = sp.dirname(file);
184192
184192
  const basename6 = sp.basename(file);
184193
- const parent = this.fsw._getWatchedDir(dirname10);
184193
+ const parent = this.fsw._getWatchedDir(dirname11);
184194
184194
  let prevStats = stats;
184195
184195
  if (parent.has(basename6))
184196
184196
  return;
@@ -184217,7 +184217,7 @@ var NodeFsHandler = class {
184217
184217
  prevStats = newStats2;
184218
184218
  }
184219
184219
  } catch (error) {
184220
- this.fsw._remove(dirname10, basename6);
184220
+ this.fsw._remove(dirname11, basename6);
184221
184221
  }
184222
184222
  } else if (parent.has(basename6)) {
184223
184223
  const at = newStats.atimeMs;
@@ -185215,6 +185215,7 @@ import { spawn as spawn4 } from "child_process";
185215
185215
  import { randomUUID as randomUUID2 } from "crypto";
185216
185216
  import * as fs10 from "fs";
185217
185217
  import * as path11 from "path";
185218
+ import * as crypto3 from "crypto";
185218
185219
  import { spawnSync } from "child_process";
185219
185220
  import * as fs11 from "fs";
185220
185221
  import * as path12 from "path";
@@ -371210,6 +371211,32 @@ function getReshapeStatus(databaseUrl, reshapeBinaryPath, log) {
371210
371211
  return null;
371211
371212
  }
371212
371213
  }
371214
+ function hashMigrationFile(filePath) {
371215
+ const content = fs10.readFileSync(filePath);
371216
+ return crypto3.createHash("sha256").update(content).digest("hex");
371217
+ }
371218
+ function readPersistedState(stateFilePath) {
371219
+ if (!fs10.existsSync(stateFilePath)) return null;
371220
+ try {
371221
+ const parsed = JSON.parse(fs10.readFileSync(stateFilePath, "utf-8"));
371222
+ if (parsed?.version !== 1) return null;
371223
+ if (typeof parsed.startedMigration !== "string") return null;
371224
+ if (typeof parsed.fileHash !== "string") return null;
371225
+ return parsed;
371226
+ } catch {
371227
+ return null;
371228
+ }
371229
+ }
371230
+ function writePersistedState(stateFilePath, state) {
371231
+ fs10.mkdirSync(path11.dirname(stateFilePath), { recursive: true });
371232
+ fs10.writeFileSync(stateFilePath, JSON.stringify(state, null, 2));
371233
+ }
371234
+ function clearPersistedState(stateFilePath) {
371235
+ try {
371236
+ fs10.unlinkSync(stateFilePath);
371237
+ } catch {
371238
+ }
371239
+ }
371213
371240
  function makeReadOnly(filePath, log) {
371214
371241
  try {
371215
371242
  fs10.chmodSync(filePath, 292);
@@ -371220,7 +371247,15 @@ function makeReadOnly(filePath, log) {
371220
371247
  }
371221
371248
  }
371222
371249
  function createReshapeWatcher(options2) {
371223
- const { databaseUrl, migrationsDir, reshapeBinaryPath, onSearchPathChanged, onError, log } = options2;
371250
+ const {
371251
+ databaseUrl,
371252
+ migrationsDir,
371253
+ reshapeBinaryPath,
371254
+ stateFilePath,
371255
+ onSearchPathChanged,
371256
+ onError,
371257
+ log
371258
+ } = options2;
371224
371259
  let watcher = null;
371225
371260
  let currentMigrationFiles = [];
371226
371261
  let startedMigration = null;
@@ -371237,10 +371272,26 @@ function createReshapeWatcher(options2) {
371237
371272
  log(`Processing ${currentMigrationFiles.length} migration file(s)`);
371238
371273
  const lastMigration = currentMigrationFiles[currentMigrationFiles.length - 1];
371239
371274
  const lastMigrationName = getMigrationName(lastMigration);
371275
+ const lastMigrationPath = path11.join(migrationsDir, lastMigration);
371276
+ const currentHash = hashMigrationFile(lastMigrationPath);
371240
371277
  const status = getReshapeStatus(databaseUrl, reshapeBinaryPath, log);
371278
+ const persistedState = readPersistedState(stateFilePath);
371279
+ const priorCompletesDone = currentMigrationFiles.length === 1 || status?.latest_completed_migration === getMigrationName(currentMigrationFiles[currentMigrationFiles.length - 2]);
371280
+ const canReuse = status?.status === "in_progress" && status.in_progress_migrations.length === 1 && status.in_progress_migrations[0] === lastMigrationName && priorCompletesDone && persistedState?.startedMigration === lastMigration && persistedState?.fileHash === currentHash;
371281
+ if (canReuse) {
371282
+ log(
371283
+ `In-progress migration "${lastMigrationName}" matches on-disk file \u2014 reusing without abort (data preserved)`
371284
+ );
371285
+ startedMigration = lastMigration;
371286
+ const searchPath2 = getSchemaName(startedMigration);
371287
+ log(`Search path (schema name): ${searchPath2}`);
371288
+ log(`Reshape initialization complete`);
371289
+ return searchPath2;
371290
+ }
371241
371291
  if (status?.status === "in_progress") {
371242
- log(`Found in-progress migration(s), aborting before re-initialization...`);
371292
+ log(`In-progress migration differs from on-disk file, aborting before re-initialization...`);
371243
371293
  runReshape(["abort"], databaseUrl, migrationsDir, reshapeBinaryPath, log);
371294
+ clearPersistedState(stateFilePath);
371244
371295
  }
371245
371296
  if (currentMigrationFiles.length > 1) {
371246
371297
  const secondToLast = currentMigrationFiles[currentMigrationFiles.length - 2];
@@ -371276,6 +371327,11 @@ function createReshapeWatcher(options2) {
371276
371327
  return null;
371277
371328
  }
371278
371329
  startedMigration = lastMigration;
371330
+ writePersistedState(stateFilePath, {
371331
+ version: 1,
371332
+ startedMigration: lastMigration,
371333
+ fileHash: currentHash
371334
+ });
371279
371335
  log(`Migration "${lastMigrationName}" started successfully`);
371280
371336
  const searchPath = getSchemaName(startedMigration);
371281
371337
  log(`Search path (schema name): ${searchPath}`);
@@ -371321,6 +371377,11 @@ function createReshapeWatcher(options2) {
371321
371377
  onError(new Error(`Failed to restart migration: ${startResult.output}`));
371322
371378
  return;
371323
371379
  }
371380
+ writePersistedState(stateFilePath, {
371381
+ version: 1,
371382
+ startedMigration: filename,
371383
+ fileHash: hashMigrationFile(filePath)
371384
+ });
371324
371385
  log(`Migration restarted successfully`);
371325
371386
  log(`Note: Services do NOT need to restart (search_path unchanged)`);
371326
371387
  } else {
@@ -371370,6 +371431,11 @@ function createReshapeWatcher(options2) {
371370
371431
  const previousStarted = startedMigration;
371371
371432
  startedMigration = filename;
371372
371433
  currentMigrationFiles = newMigrationFiles;
371434
+ writePersistedState(stateFilePath, {
371435
+ version: 1,
371436
+ startedMigration: filename,
371437
+ fileHash: hashMigrationFile(filePath)
371438
+ });
371373
371439
  log(`New migration started successfully`);
371374
371440
  log(` Previous started migration: ${previousStarted || "(none)"}`);
371375
371441
  log(` New started migration: ${startedMigration}`);
@@ -371941,38 +372007,77 @@ var TunnelClientImpl = class extends EventEmitter2 {
371941
372007
  const remote = net7.connect({ host: this.tunnelHost, port: this.info.port });
371942
372008
  remote.setKeepAlive(true, 3e4);
371943
372009
  this.pool.add(remote);
372010
+ let active = false;
372011
+ let errored = false;
371944
372012
  remote.once("data", (firstChunk) => {
371945
372013
  this.pool.delete(remote);
372014
+ active = true;
371946
372015
  this.pipeToLocal(remote, firstChunk);
371947
372016
  });
371948
- let errored = false;
371949
372017
  remote.on("error", (err) => {
371950
372018
  errored = true;
371951
372019
  this.emit("error", err);
371952
372020
  });
371953
- remote.on("close", () => this.onIdleClose(remote, errored));
372021
+ remote.on("close", () => {
372022
+ if (this.closed)
372023
+ return;
372024
+ if (active) {
372025
+ this.fillPool();
372026
+ return;
372027
+ }
372028
+ this.pool.delete(remote);
372029
+ if (errored && this.pool.size === 0) {
372030
+ this.reconnect();
372031
+ } else {
372032
+ this.fillPool();
372033
+ }
372034
+ });
371954
372035
  }
371955
372036
  pipeToLocal(remote, firstChunk) {
372037
+ let buffered = firstChunk;
372038
+ const HEADER_END = Buffer.from("\r\n\r\n");
372039
+ const MAX_HEADER_BYTES = 64 * 1024;
372040
+ const flush = (end) => {
372041
+ const headers = buffered.subarray(0, end + HEADER_END.length);
372042
+ const body = buffered.subarray(end + HEADER_END.length);
372043
+ const rewritten = this.rewriteDevOriginHeaders(headers);
372044
+ const request2 = body.length > 0 ? Buffer.concat([rewritten, body]) : rewritten;
372045
+ this.openLocal(remote, request2);
372046
+ };
372047
+ const initial = buffered.indexOf(HEADER_END);
372048
+ if (initial !== -1) {
372049
+ flush(initial);
372050
+ return;
372051
+ }
372052
+ const onData = (chunk) => {
372053
+ buffered = Buffer.concat([buffered, chunk]);
372054
+ const end = buffered.indexOf(HEADER_END);
372055
+ if (end !== -1) {
372056
+ remote.off("data", onData);
372057
+ flush(end);
372058
+ } else if (buffered.length > MAX_HEADER_BYTES) {
372059
+ remote.off("data", onData);
372060
+ remote.destroy();
372061
+ }
372062
+ };
372063
+ remote.on("data", onData);
372064
+ }
372065
+ openLocal(remote, request2) {
371956
372066
  const local = net7.connect({ host: "127.0.0.1", port: this.localPort }, () => {
371957
- local.write(firstChunk);
372067
+ local.write(request2);
371958
372068
  remote.pipe(local);
371959
372069
  local.pipe(remote);
371960
372070
  });
371961
372071
  local.on("error", () => remote.destroy());
371962
- remote.on("close", () => {
371963
- if (!this.closed)
371964
- this.fillPool();
371965
- });
371966
372072
  }
371967
- onIdleClose(remote, errored) {
371968
- if (!this.pool.delete(remote) || this.closed)
371969
- return;
371970
- if (errored) {
371971
- if (this.pool.size === 0)
371972
- this.reconnect();
371973
- } else {
371974
- this.fillPool();
371975
- }
372073
+ rewriteDevOriginHeaders(headers) {
372074
+ const target = `localhost:${this.localPort}`;
372075
+ const text = headers.toString("latin1");
372076
+ let out = text.replace(/^Host:[^\r\n]*\r\n/im, `Host: ${target}\r
372077
+ `);
372078
+ out = out.replace(/^Origin:[^\r\n]*\r\n/im, `Origin: http://${target}\r
372079
+ `);
372080
+ return Buffer.from(out, "latin1");
371976
372081
  }
371977
372082
  async reconnect() {
371978
372083
  this.emit("close");
@@ -372657,10 +372762,19 @@ var DevEnvironment = class extends TypedEventEmitter {
372657
372762
  this.systemLog(
372658
372763
  `Initializing Reshape migrations for "${pg.name}" from ${migrationsDir}`
372659
372764
  );
372765
+ const reshapeStateFile = path14.join(
372766
+ this.projectDir,
372767
+ ".specific",
372768
+ "keys",
372769
+ this.instanceKey,
372770
+ "reshape",
372771
+ `${pg.name}.json`
372772
+ );
372660
372773
  const watcher = createReshapeWatcher({
372661
372774
  databaseUrl: resource.url,
372662
372775
  migrationsDir,
372663
372776
  reshapeBinaryPath: reshapeBin.executables["reshape"],
372777
+ stateFilePath: reshapeStateFile,
372664
372778
  onSearchPathChanged: async (newSearchPath) => {
372665
372779
  resource.reshapeSearchPath = newSearchPath ?? void 0;
372666
372780
  if (newSearchPath) {
@@ -373156,7 +373270,7 @@ function getDefaultKey() {
373156
373270
  // src/lib/analytics/index.ts
373157
373271
  import { PostHog } from "posthog-node";
373158
373272
  import * as os5 from "os";
373159
- import * as crypto3 from "crypto";
373273
+ import * as crypto4 from "crypto";
373160
373274
 
373161
373275
  // src/lib/project/config.ts
373162
373276
  import * as fs3 from "fs";
@@ -373629,7 +373743,7 @@ function isEnabled() {
373629
373743
  function getAnonymousId() {
373630
373744
  if (anonymousId) return anonymousId;
373631
373745
  const machineId = `${os5.hostname()}-${os5.userInfo().username}`;
373632
- anonymousId = crypto3.createHash("sha256").update(machineId).digest("hex").slice(0, 16);
373746
+ anonymousId = crypto4.createHash("sha256").update(machineId).digest("hex").slice(0, 16);
373633
373747
  return anonymousId;
373634
373748
  }
373635
373749
  function getProjectId() {
@@ -373675,7 +373789,7 @@ function trackEvent(event, properties) {
373675
373789
  event,
373676
373790
  properties: {
373677
373791
  ...properties,
373678
- cli_version: "0.1.127",
373792
+ cli_version: "0.1.129",
373679
373793
  platform: process.platform,
373680
373794
  node_version: process.version,
373681
373795
  project_id: getProjectId()
@@ -373993,9 +374107,9 @@ Valid agents: ${VALID_AGENT_IDS.join(", ")}`
373993
374107
  }
373994
374108
 
373995
374109
  // src/commands/docs.tsx
373996
- import { readFileSync as readFileSync10, existsSync as existsSync17 } from "fs";
374110
+ import { readFileSync as readFileSync11, existsSync as existsSync17 } from "fs";
373997
374111
  import { spawn as spawn6 } from "child_process";
373998
- import { join as join19, dirname as dirname8 } from "path";
374112
+ import { join as join19, dirname as dirname9 } from "path";
373999
374113
  import { fileURLToPath as fileURLToPath3 } from "url";
374000
374114
 
374001
374115
  // src/lib/beta/registry.ts
@@ -374007,7 +374121,7 @@ var BETA_REGISTRY = [
374007
374121
  ];
374008
374122
 
374009
374123
  // src/lib/beta/storage.ts
374010
- import { readFileSync as readFileSync9, writeFileSync as writeFileSync7, existsSync as existsSync16, mkdirSync as mkdirSync13 } from "fs";
374124
+ import { readFileSync as readFileSync10, writeFileSync as writeFileSync8, existsSync as existsSync16, mkdirSync as mkdirSync13 } from "fs";
374011
374125
  import { join as join18 } from "path";
374012
374126
  var BETAS_FILE = ".specific/betas.json";
374013
374127
  function loadEnabledBetas(projectDir = process.cwd()) {
@@ -374016,7 +374130,7 @@ function loadEnabledBetas(projectDir = process.cwd()) {
374016
374130
  return [];
374017
374131
  }
374018
374132
  try {
374019
- const content = readFileSync9(filePath, "utf-8");
374133
+ const content = readFileSync10(filePath, "utf-8");
374020
374134
  const data = JSON.parse(content);
374021
374135
  return data.enabled ?? [];
374022
374136
  } catch {
@@ -374040,14 +374154,14 @@ function saveBetas(enabled, projectDir) {
374040
374154
  mkdirSync13(specificDir, { recursive: true });
374041
374155
  }
374042
374156
  const data = { enabled };
374043
- writeFileSync7(
374157
+ writeFileSync8(
374044
374158
  join18(projectDir, BETAS_FILE),
374045
374159
  JSON.stringify(data, null, 2) + "\n"
374046
374160
  );
374047
374161
  }
374048
374162
 
374049
374163
  // src/commands/docs.tsx
374050
- var __dirname3 = dirname8(fileURLToPath3(import.meta.url));
374164
+ var __dirname3 = dirname9(fileURLToPath3(import.meta.url));
374051
374165
  var docsDir = join19(__dirname3, "docs");
374052
374166
  var _embeddedDocs = null;
374053
374167
  var RESHAPE_DOCS_PREFIX = "postgres/reshape/";
@@ -374121,15 +374235,15 @@ function resolveEmbeddedDoc(path27) {
374121
374235
  function resolveFilesystemDoc(path27) {
374122
374236
  if (!path27) {
374123
374237
  const indexPath2 = join19(docsDir, "index.md");
374124
- return existsSync17(indexPath2) ? readFileSync10(indexPath2, "utf-8") : null;
374238
+ return existsSync17(indexPath2) ? readFileSync11(indexPath2, "utf-8") : null;
374125
374239
  }
374126
374240
  const directPath = join19(docsDir, `${path27}.md`);
374127
374241
  if (existsSync17(directPath)) {
374128
- return readFileSync10(directPath, "utf-8");
374242
+ return readFileSync11(directPath, "utf-8");
374129
374243
  }
374130
374244
  const indexPath = join19(docsDir, path27, "index.md");
374131
374245
  if (existsSync17(indexPath)) {
374132
- return readFileSync10(indexPath, "utf-8");
374246
+ return readFileSync11(indexPath, "utf-8");
374133
374247
  }
374134
374248
  return null;
374135
374249
  }
@@ -377781,7 +377895,7 @@ function compareVersions(a, b) {
377781
377895
  return 0;
377782
377896
  }
377783
377897
  async function checkForUpdate() {
377784
- const currentVersion = "0.1.127";
377898
+ const currentVersion = "0.1.129";
377785
377899
  const response = await fetch(`${BINARIES_BASE_URL}/latest?t=${Date.now()}`);
377786
377900
  if (!response.ok) {
377787
377901
  throw new Error(`Failed to check for updates: HTTP ${response.status}`);
@@ -378051,7 +378165,7 @@ async function projectListCommand() {
378051
378165
  var program = new Command();
378052
378166
  var env = "production";
378053
378167
  var envLabel = env !== "production" ? `[${env.toUpperCase()}] ` : "";
378054
- program.name("specific").description(`${envLabel}Infrastructure-as-code for coding agents`).version("0.1.127").enablePositionalOptions();
378168
+ program.name("specific").description(`${envLabel}Infrastructure-as-code for coding agents`).version("0.1.129").enablePositionalOptions();
378055
378169
  program.command("init").description("Initialize project for use with a coding agent").option("--agent <name...>", "Agents to configure (cursor, claude, codex, other)").addHelpText("after", `
378056
378170
  Examples:
378057
378171
  $ specific init
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@specific.dev/cli",
3
- "version": "0.1.127",
3
+ "version": "0.1.129",
4
4
  "description": "CLI for Specific infrastructure-as-code",
5
5
  "type": "module",
6
6
  "main": "dist/cli.js",