nstantpage-agent 0.6.0 → 0.6.1

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.
@@ -972,8 +972,8 @@ var require_command = __commonJS({
972
972
  "node_modules/commander/lib/command.js"(exports) {
973
973
  var EventEmitter = __require("node:events").EventEmitter;
974
974
  var childProcess2 = __require("node:child_process");
975
- var path17 = __require("node:path");
976
- var fs18 = __require("node:fs");
975
+ var path20 = __require("node:path");
976
+ var fs21 = __require("node:fs");
977
977
  var process15 = __require("node:process");
978
978
  var { Argument: Argument2, humanReadableArgName } = require_argument();
979
979
  var { CommanderError: CommanderError2 } = require_error();
@@ -1905,11 +1905,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
1905
1905
  let launchWithNode = false;
1906
1906
  const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
1907
1907
  function findFile(baseDir, baseName) {
1908
- const localBin = path17.resolve(baseDir, baseName);
1909
- if (fs18.existsSync(localBin)) return localBin;
1910
- if (sourceExt.includes(path17.extname(baseName))) return void 0;
1908
+ const localBin = path20.resolve(baseDir, baseName);
1909
+ if (fs21.existsSync(localBin)) return localBin;
1910
+ if (sourceExt.includes(path20.extname(baseName))) return void 0;
1911
1911
  const foundExt = sourceExt.find(
1912
- (ext) => fs18.existsSync(`${localBin}${ext}`)
1912
+ (ext) => fs21.existsSync(`${localBin}${ext}`)
1913
1913
  );
1914
1914
  if (foundExt) return `${localBin}${foundExt}`;
1915
1915
  return void 0;
@@ -1921,21 +1921,21 @@ Expecting one of '${allowedValues.join("', '")}'`);
1921
1921
  if (this._scriptPath) {
1922
1922
  let resolvedScriptPath;
1923
1923
  try {
1924
- resolvedScriptPath = fs18.realpathSync(this._scriptPath);
1924
+ resolvedScriptPath = fs21.realpathSync(this._scriptPath);
1925
1925
  } catch (err) {
1926
1926
  resolvedScriptPath = this._scriptPath;
1927
1927
  }
1928
- executableDir = path17.resolve(
1929
- path17.dirname(resolvedScriptPath),
1928
+ executableDir = path20.resolve(
1929
+ path20.dirname(resolvedScriptPath),
1930
1930
  executableDir
1931
1931
  );
1932
1932
  }
1933
1933
  if (executableDir) {
1934
1934
  let localFile = findFile(executableDir, executableFile);
1935
1935
  if (!localFile && !subcommand._executableFile && this._scriptPath) {
1936
- const legacyName = path17.basename(
1936
+ const legacyName = path20.basename(
1937
1937
  this._scriptPath,
1938
- path17.extname(this._scriptPath)
1938
+ path20.extname(this._scriptPath)
1939
1939
  );
1940
1940
  if (legacyName !== this._name) {
1941
1941
  localFile = findFile(
@@ -1946,7 +1946,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1946
1946
  }
1947
1947
  executableFile = localFile || executableFile;
1948
1948
  }
1949
- launchWithNode = sourceExt.includes(path17.extname(executableFile));
1949
+ launchWithNode = sourceExt.includes(path20.extname(executableFile));
1950
1950
  let proc;
1951
1951
  if (process15.platform !== "win32") {
1952
1952
  if (launchWithNode) {
@@ -2786,7 +2786,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
2786
2786
  * @return {Command}
2787
2787
  */
2788
2788
  nameFromFilename(filename) {
2789
- this._name = path17.basename(filename, path17.extname(filename));
2789
+ this._name = path20.basename(filename, path20.extname(filename));
2790
2790
  return this;
2791
2791
  }
2792
2792
  /**
@@ -2800,9 +2800,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
2800
2800
  * @param {string} [path]
2801
2801
  * @return {(string|null|Command)}
2802
2802
  */
2803
- executableDir(path18) {
2804
- if (path18 === void 0) return this._executableDir;
2805
- this._executableDir = path18;
2803
+ executableDir(path21) {
2804
+ if (path21 === void 0) return this._executableDir;
2805
+ this._executableDir = path21;
2806
2806
  return this;
2807
2807
  }
2808
2808
  /**
@@ -3033,12 +3033,12 @@ var require_commander = __commonJS({
3033
3033
  });
3034
3034
 
3035
3035
  // node_modules/dot-prop/index.js
3036
- function getPathSegments(path17) {
3036
+ function getPathSegments(path20) {
3037
3037
  const parts = [];
3038
3038
  let currentSegment = "";
3039
3039
  let currentPart = "start";
3040
3040
  let isIgnoring = false;
3041
- for (const character of path17) {
3041
+ for (const character of path20) {
3042
3042
  switch (character) {
3043
3043
  case "\\": {
3044
3044
  if (currentPart === "index") {
@@ -3160,11 +3160,11 @@ function assertNotStringIndex(object, key) {
3160
3160
  throw new Error("Cannot use string index");
3161
3161
  }
3162
3162
  }
3163
- function getProperty(object, path17, value) {
3164
- if (!isObject(object) || typeof path17 !== "string") {
3163
+ function getProperty(object, path20, value) {
3164
+ if (!isObject(object) || typeof path20 !== "string") {
3165
3165
  return value === void 0 ? object : value;
3166
3166
  }
3167
- const pathArray = getPathSegments(path17);
3167
+ const pathArray = getPathSegments(path20);
3168
3168
  if (pathArray.length === 0) {
3169
3169
  return value;
3170
3170
  }
@@ -3184,12 +3184,12 @@ function getProperty(object, path17, value) {
3184
3184
  }
3185
3185
  return object === void 0 ? value : object;
3186
3186
  }
3187
- function setProperty(object, path17, value) {
3188
- if (!isObject(object) || typeof path17 !== "string") {
3187
+ function setProperty(object, path20, value) {
3188
+ if (!isObject(object) || typeof path20 !== "string") {
3189
3189
  return object;
3190
3190
  }
3191
3191
  const root = object;
3192
- const pathArray = getPathSegments(path17);
3192
+ const pathArray = getPathSegments(path20);
3193
3193
  for (let index = 0; index < pathArray.length; index++) {
3194
3194
  const key = pathArray[index];
3195
3195
  assertNotStringIndex(object, key);
@@ -3202,11 +3202,11 @@ function setProperty(object, path17, value) {
3202
3202
  }
3203
3203
  return root;
3204
3204
  }
3205
- function deleteProperty(object, path17) {
3206
- if (!isObject(object) || typeof path17 !== "string") {
3205
+ function deleteProperty(object, path20) {
3206
+ if (!isObject(object) || typeof path20 !== "string") {
3207
3207
  return false;
3208
3208
  }
3209
- const pathArray = getPathSegments(path17);
3209
+ const pathArray = getPathSegments(path20);
3210
3210
  for (let index = 0; index < pathArray.length; index++) {
3211
3211
  const key = pathArray[index];
3212
3212
  assertNotStringIndex(object, key);
@@ -3220,11 +3220,11 @@ function deleteProperty(object, path17) {
3220
3220
  }
3221
3221
  }
3222
3222
  }
3223
- function hasProperty(object, path17) {
3224
- if (!isObject(object) || typeof path17 !== "string") {
3223
+ function hasProperty(object, path20) {
3224
+ if (!isObject(object) || typeof path20 !== "string") {
3225
3225
  return false;
3226
3226
  }
3227
- const pathArray = getPathSegments(path17);
3227
+ const pathArray = getPathSegments(path20);
3228
3228
  if (pathArray.length === 0) {
3229
3229
  return false;
3230
3230
  }
@@ -7006,8 +7006,8 @@ var require_utils = __commonJS({
7006
7006
  }
7007
7007
  return ind;
7008
7008
  }
7009
- function removeDotSegments(path17) {
7010
- let input = path17;
7009
+ function removeDotSegments(path20) {
7010
+ let input = path20;
7011
7011
  const output = [];
7012
7012
  let nextSlash = -1;
7013
7013
  let len = 0;
@@ -7206,8 +7206,8 @@ var require_schemes = __commonJS({
7206
7206
  wsComponent.secure = void 0;
7207
7207
  }
7208
7208
  if (wsComponent.resourceName) {
7209
- const [path17, query] = wsComponent.resourceName.split("?");
7210
- wsComponent.path = path17 && path17 !== "/" ? path17 : void 0;
7209
+ const [path20, query] = wsComponent.resourceName.split("?");
7210
+ wsComponent.path = path20 && path20 !== "/" ? path20 : void 0;
7211
7211
  wsComponent.query = query;
7212
7212
  wsComponent.resourceName = void 0;
7213
7213
  }
@@ -11393,12 +11393,12 @@ var require_dist = __commonJS({
11393
11393
  throw new Error(`Unknown format "${name}"`);
11394
11394
  return f;
11395
11395
  };
11396
- function addFormats(ajv, list, fs18, exportName) {
11396
+ function addFormats(ajv, list, fs21, exportName) {
11397
11397
  var _a;
11398
11398
  var _b;
11399
11399
  (_a = (_b = ajv.opts.code).formats) !== null && _a !== void 0 ? _a : _b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
11400
11400
  for (const f of list)
11401
- ajv.addFormat(f, fs18[f]);
11401
+ ajv.addFormat(f, fs21[f]);
11402
11402
  }
11403
11403
  module.exports = exports = formatsPlugin;
11404
11404
  Object.defineProperty(exports, "__esModule", { value: true });
@@ -19294,15 +19294,15 @@ var require_pg_connection_string = __commonJS({
19294
19294
  if (config.sslcert || config.sslkey || config.sslrootcert || config.sslmode) {
19295
19295
  config.ssl = {};
19296
19296
  }
19297
- const fs18 = config.sslcert || config.sslkey || config.sslrootcert ? __require("fs") : null;
19297
+ const fs21 = config.sslcert || config.sslkey || config.sslrootcert ? __require("fs") : null;
19298
19298
  if (config.sslcert) {
19299
- config.ssl.cert = fs18.readFileSync(config.sslcert).toString();
19299
+ config.ssl.cert = fs21.readFileSync(config.sslcert).toString();
19300
19300
  }
19301
19301
  if (config.sslkey) {
19302
- config.ssl.key = fs18.readFileSync(config.sslkey).toString();
19302
+ config.ssl.key = fs21.readFileSync(config.sslkey).toString();
19303
19303
  }
19304
19304
  if (config.sslrootcert) {
19305
- config.ssl.ca = fs18.readFileSync(config.sslrootcert).toString();
19305
+ config.ssl.ca = fs21.readFileSync(config.sslrootcert).toString();
19306
19306
  }
19307
19307
  if (options.useLibpqCompat && config.uselibpqcompat) {
19308
19308
  throw new Error("Both useLibpqCompat and uselibpqcompat are set. Please use only one of them.");
@@ -21067,7 +21067,7 @@ var require_split2 = __commonJS({
21067
21067
  var require_helper = __commonJS({
21068
21068
  "node_modules/pgpass/lib/helper.js"(exports, module) {
21069
21069
  "use strict";
21070
- var path17 = __require("path");
21070
+ var path20 = __require("path");
21071
21071
  var Stream = __require("stream").Stream;
21072
21072
  var split = require_split2();
21073
21073
  var util = __require("util");
@@ -21106,7 +21106,7 @@ var require_helper = __commonJS({
21106
21106
  };
21107
21107
  module.exports.getFileName = function(rawEnv) {
21108
21108
  var env3 = rawEnv || process.env;
21109
- var file = env3.PGPASSFILE || (isWin ? path17.join(env3.APPDATA || "./", "postgresql", "pgpass.conf") : path17.join(env3.HOME || "./", ".pgpass"));
21109
+ var file = env3.PGPASSFILE || (isWin ? path20.join(env3.APPDATA || "./", "postgresql", "pgpass.conf") : path20.join(env3.HOME || "./", ".pgpass"));
21110
21110
  return file;
21111
21111
  };
21112
21112
  module.exports.usePgPass = function(stats, fname) {
@@ -21238,16 +21238,16 @@ var require_helper = __commonJS({
21238
21238
  var require_lib = __commonJS({
21239
21239
  "node_modules/pgpass/lib/index.js"(exports, module) {
21240
21240
  "use strict";
21241
- var path17 = __require("path");
21242
- var fs18 = __require("fs");
21241
+ var path20 = __require("path");
21242
+ var fs21 = __require("fs");
21243
21243
  var helper = require_helper();
21244
21244
  module.exports = function(connInfo, cb) {
21245
21245
  var file = helper.getFileName();
21246
- fs18.stat(file, function(err, stat) {
21246
+ fs21.stat(file, function(err, stat) {
21247
21247
  if (err || !helper.usePgPass(stat, file)) {
21248
21248
  return cb(void 0);
21249
21249
  }
21250
- var st = fs18.createReadStream(file);
21250
+ var st = fs21.createReadStream(file);
21251
21251
  helper.getPassword(connInfo, st, cb);
21252
21252
  });
21253
21253
  };
@@ -23989,8 +23989,8 @@ async function logoutCommand() {
23989
23989
 
23990
23990
  // dist/commands/start.js
23991
23991
  init_config();
23992
- import path15 from "path";
23993
- import fs16 from "fs";
23992
+ import path16 from "path";
23993
+ import fs17 from "fs";
23994
23994
  import os10 from "os";
23995
23995
  import { execSync as execSync2 } from "child_process";
23996
23996
 
@@ -24009,8 +24009,8 @@ init_config();
24009
24009
 
24010
24010
  // dist/localServer.js
24011
24011
  import http3 from "http";
24012
- import fs14 from "fs";
24013
- import path13 from "path";
24012
+ import fs15 from "fs";
24013
+ import path14 from "path";
24014
24014
  import os7 from "os";
24015
24015
  import { createRequire } from "module";
24016
24016
  import { spawn as spawn4 } from "child_process";
@@ -24816,7 +24816,16 @@ var PackageInstaller = class {
24816
24816
  console.log(` [Installer] Installing project dependencies...`);
24817
24817
  const pm = this.detectPackageManager();
24818
24818
  const args = this.buildFastInstallArgs(pm);
24819
- await this.runCommand(pm, args, 3e5);
24819
+ try {
24820
+ await this.runCommand(pm, args, 3e5);
24821
+ } catch (err) {
24822
+ if (String(err.message || err).includes("ERR_PNPM_OUTDATED_LOCKFILE") || String(err.message || err).includes("frozen-lockfile")) {
24823
+ console.log(` [Installer] Lockfile outdated \u2014 retrying without frozen-lockfile...`);
24824
+ await this.runCommand(pm, ["install", "--no-frozen-lockfile"], 3e5);
24825
+ } else {
24826
+ throw err;
24827
+ }
24828
+ }
24820
24829
  this.writeDepsHash();
24821
24830
  console.log(` [Installer] Dependencies installed`);
24822
24831
  } finally {
@@ -25736,11 +25745,40 @@ var AgentSync = class {
25736
25745
  }
25737
25746
  };
25738
25747
 
25748
+ // dist/version.js
25749
+ import fs14 from "fs";
25750
+ import path13 from "path";
25751
+ import { fileURLToPath as fileURLToPath2 } from "url";
25752
+ var __filename_esm = fileURLToPath2(import.meta.url);
25753
+ var __dirname_esm = path13.dirname(__filename_esm);
25754
+ var _version = null;
25755
+ function getPackageVersion() {
25756
+ if (_version)
25757
+ return _version;
25758
+ let dir = __dirname_esm;
25759
+ for (let i = 0; i < 5; i++) {
25760
+ const pkgPath = path13.join(dir, "package.json");
25761
+ if (fs14.existsSync(pkgPath)) {
25762
+ try {
25763
+ const pkg = JSON.parse(fs14.readFileSync(pkgPath, "utf-8"));
25764
+ if (pkg.name === "nstantpage-agent") {
25765
+ _version = pkg.version;
25766
+ return _version;
25767
+ }
25768
+ } catch {
25769
+ }
25770
+ }
25771
+ dir = path13.dirname(dir);
25772
+ }
25773
+ _version = "0.0.0";
25774
+ return _version;
25775
+ }
25776
+
25739
25777
  // dist/localServer.js
25740
25778
  var ptyModule = null;
25741
25779
  try {
25742
- const _require = createRequire(import.meta.url);
25743
- ptyModule = _require("node-pty");
25780
+ const _require2 = createRequire(import.meta.url);
25781
+ ptyModule = _require2("node-pty");
25744
25782
  } catch {
25745
25783
  }
25746
25784
  var terminalSessions = /* @__PURE__ */ new Map();
@@ -26028,7 +26066,7 @@ Access-Control-Allow-Origin: *\r
26028
26066
  res.end(JSON.stringify({ error: `Unknown endpoint: ${pathOnly}` }));
26029
26067
  }
26030
26068
  }
26031
- getHandler(path17) {
26069
+ getHandler(path20) {
26032
26070
  const handlers = {
26033
26071
  "/live/sync": this.handleSync,
26034
26072
  "/live/files": this.handleFiles,
@@ -26080,10 +26118,10 @@ Access-Control-Allow-Origin: *\r
26080
26118
  "/live/save-file": this.handleSaveFile,
26081
26119
  "/health": this.handleHealth
26082
26120
  };
26083
- if (handlers[path17])
26084
- return handlers[path17];
26121
+ if (handlers[path20])
26122
+ return handlers[path20];
26085
26123
  for (const [route, handler] of Object.entries(handlers)) {
26086
- if (path17.startsWith(route + "/"))
26124
+ if (path20.startsWith(route + "/"))
26087
26125
  return handler;
26088
26126
  }
26089
26127
  return null;
@@ -26305,7 +26343,7 @@ Access-Control-Allow-Origin: *\r
26305
26343
  const label = parsed.label || `Terminal ${sessionCounter}`;
26306
26344
  let shell = null;
26307
26345
  let ptyProcess = null;
26308
- const spawnCwd = fs14.existsSync(this.options.projectDir) ? this.options.projectDir : process.cwd();
26346
+ const spawnCwd = fs15.existsSync(this.options.projectDir) ? this.options.projectDir : process.cwd();
26309
26347
  if (ptyModule) {
26310
26348
  try {
26311
26349
  ptyProcess = ptyModule.spawn(shellCmd, [], {
@@ -26467,7 +26505,7 @@ Access-Control-Allow-Origin: *\r
26467
26505
  connected: true,
26468
26506
  projectId: this.options.projectId,
26469
26507
  agent: {
26470
- version: "0.5.11",
26508
+ version: getPackageVersion(),
26471
26509
  hostname: os7.hostname(),
26472
26510
  platform: `${os7.platform()} ${os7.arch()}`
26473
26511
  }
@@ -26729,7 +26767,7 @@ Access-Control-Allow-Origin: *\r
26729
26767
  const projectDir = this.options.projectDir;
26730
26768
  console.log(` [LocalServer] Running production build for project ${this.options.projectId}...`);
26731
26769
  try {
26732
- const hasBuildScript = fs14.existsSync(path13.join(projectDir, "script", "build.ts"));
26770
+ const hasBuildScript = fs15.existsSync(path14.join(projectDir, "script", "build.ts"));
26733
26771
  const buildCmd = hasBuildScript ? "npx tsx script/build.ts" : "npx vite build";
26734
26772
  const buildResult = await new Promise((resolve) => {
26735
26773
  const proc = spawn4("sh", ["-c", buildCmd], {
@@ -26753,32 +26791,32 @@ Access-Control-Allow-Origin: *\r
26753
26791
  this.json(res, { success: false, error: errorMsg });
26754
26792
  return;
26755
26793
  }
26756
- const distDir = path13.join(projectDir, "dist");
26757
- if (!fs14.existsSync(distDir)) {
26794
+ const distDir = path14.join(projectDir, "dist");
26795
+ if (!fs15.existsSync(distDir)) {
26758
26796
  this.json(res, { success: false, error: "dist/ not found after build" });
26759
26797
  return;
26760
26798
  }
26761
26799
  const files = {};
26762
26800
  const collectFiles = (dir, prefix) => {
26763
- const entries = fs14.readdirSync(dir, { withFileTypes: true });
26801
+ const entries = fs15.readdirSync(dir, { withFileTypes: true });
26764
26802
  for (const entry of entries) {
26765
- const fullPath = path13.join(dir, entry.name);
26803
+ const fullPath = path14.join(dir, entry.name);
26766
26804
  const relPath = prefix ? `${prefix}/${entry.name}` : entry.name;
26767
26805
  if (entry.isDirectory()) {
26768
26806
  collectFiles(fullPath, relPath);
26769
26807
  } else {
26770
- const ext = path13.extname(entry.name).toLowerCase();
26808
+ const ext = path14.extname(entry.name).toLowerCase();
26771
26809
  const isBinary = [".png", ".jpg", ".jpeg", ".gif", ".webp", ".ico", ".woff", ".woff2", ".ttf", ".eot", ".mp3", ".mp4", ".ogg", ".wav"].includes(ext);
26772
26810
  if (isBinary) {
26773
- files[relPath] = "base64:" + fs14.readFileSync(fullPath).toString("base64");
26811
+ files[relPath] = "base64:" + fs15.readFileSync(fullPath).toString("base64");
26774
26812
  } else {
26775
- files[relPath] = fs14.readFileSync(fullPath, "utf-8");
26813
+ files[relPath] = fs15.readFileSync(fullPath, "utf-8");
26776
26814
  }
26777
26815
  }
26778
26816
  }
26779
26817
  };
26780
26818
  collectFiles(distDir, "");
26781
- const hasBackend = fs14.existsSync(path13.join(projectDir, "server", "index.ts")) || fs14.existsSync(path13.join(projectDir, "server", "index.js"));
26819
+ const hasBackend = fs15.existsSync(path14.join(projectDir, "server", "index.ts")) || fs15.existsSync(path14.join(projectDir, "server", "index.js"));
26782
26820
  console.log(` [LocalServer] Build completed: ${Object.keys(files).length} files (backend=${hasBackend})`);
26783
26821
  this.json(res, {
26784
26822
  success: true,
@@ -27204,7 +27242,7 @@ var TunnelClient = class {
27204
27242
  this.emitStatus("connected");
27205
27243
  this.send({
27206
27244
  type: "agent-info",
27207
- version: "0.5.11",
27245
+ version: getPackageVersion(),
27208
27246
  hostname: os8.hostname(),
27209
27247
  platform: `${os8.platform()} ${os8.arch()}`,
27210
27248
  deviceId: getDeviceId(),
@@ -27649,11 +27687,21 @@ var TunnelClient = class {
27649
27687
 
27650
27688
  // dist/statusServer.js
27651
27689
  import http5 from "http";
27652
- import fs15 from "fs";
27653
- import path14 from "path";
27690
+ import fs16 from "fs";
27691
+ import path15 from "path";
27654
27692
  import os9 from "os";
27693
+ import { spawn as spawn5 } from "child_process";
27694
+ import { createRequire as createRequire2 } from "module";
27655
27695
  var STATUS_PORT = 18999;
27656
- var STATUS_FILE = path14.join(os9.homedir(), ".nstantpage", "status.json");
27696
+ var STATUS_FILE = path15.join(os9.homedir(), ".nstantpage", "status.json");
27697
+ var _require = createRequire2(import.meta.url);
27698
+ var ptyModule2 = null;
27699
+ try {
27700
+ ptyModule2 = _require("node-pty");
27701
+ } catch {
27702
+ }
27703
+ var repoTerminalSessions = /* @__PURE__ */ new Map();
27704
+ var repoSessionCounter = 0;
27657
27705
  var StatusServer = class {
27658
27706
  server = null;
27659
27707
  getStatus;
@@ -27668,8 +27716,8 @@ var StatusServer = class {
27668
27716
  return new Promise((resolve, reject) => {
27669
27717
  this.server = http5.createServer((req, res) => {
27670
27718
  res.setHeader("Access-Control-Allow-Origin", "*");
27671
- res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
27672
- res.setHeader("Access-Control-Allow-Headers", "Content-Type");
27719
+ res.setHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, OPTIONS");
27720
+ res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, x-project-id");
27673
27721
  res.setHeader("Content-Type", "application/json");
27674
27722
  if (req.method === "OPTIONS") {
27675
27723
  res.writeHead(204);
@@ -27732,13 +27780,13 @@ var StatusServer = class {
27732
27780
  const parsedUrl = new URL(req.url || "/", `http://localhost:${STATUS_PORT}`);
27733
27781
  if (req.method === "GET" && url === "/browse/tree") {
27734
27782
  const dir = parsedUrl.searchParams.get("dir");
27735
- if (!dir || !fs15.existsSync(dir)) {
27783
+ if (!dir || !fs16.existsSync(dir)) {
27736
27784
  res.writeHead(400);
27737
27785
  res.end(JSON.stringify({ error: "Missing or invalid dir parameter" }));
27738
27786
  return;
27739
27787
  }
27740
27788
  try {
27741
- const tree = buildFileTree(dir, path14.basename(dir));
27789
+ const tree = buildFileTree(dir, path15.basename(dir));
27742
27790
  res.writeHead(200);
27743
27791
  res.end(JSON.stringify(tree));
27744
27792
  } catch (err) {
@@ -27755,19 +27803,19 @@ var StatusServer = class {
27755
27803
  res.end(JSON.stringify({ error: "dir and path parameters required" }));
27756
27804
  return;
27757
27805
  }
27758
- const fullPath = path14.resolve(dir, filePath);
27759
- if (!fullPath.startsWith(path14.resolve(dir))) {
27806
+ const fullPath = path15.resolve(dir, filePath);
27807
+ if (!fullPath.startsWith(path15.resolve(dir))) {
27760
27808
  res.writeHead(403);
27761
27809
  res.end(JSON.stringify({ error: "Path traversal not allowed" }));
27762
27810
  return;
27763
27811
  }
27764
27812
  try {
27765
- if (!fs15.existsSync(fullPath)) {
27813
+ if (!fs16.existsSync(fullPath)) {
27766
27814
  res.writeHead(404);
27767
27815
  res.end(JSON.stringify({ error: "File not found" }));
27768
27816
  return;
27769
27817
  }
27770
- const content = fs15.readFileSync(fullPath, "utf-8");
27818
+ const content = fs16.readFileSync(fullPath, "utf-8");
27771
27819
  res.writeHead(200);
27772
27820
  res.end(JSON.stringify({ content }));
27773
27821
  } catch (err) {
@@ -27789,16 +27837,16 @@ var StatusServer = class {
27789
27837
  res.end(JSON.stringify({ error: "dir, filePath, and content required" }));
27790
27838
  return;
27791
27839
  }
27792
- const fullPath = path14.resolve(dir, filePath);
27793
- if (!fullPath.startsWith(path14.resolve(dir))) {
27840
+ const fullPath = path15.resolve(dir, filePath);
27841
+ if (!fullPath.startsWith(path15.resolve(dir))) {
27794
27842
  res.writeHead(403);
27795
27843
  res.end(JSON.stringify({ error: "Path traversal not allowed" }));
27796
27844
  return;
27797
27845
  }
27798
- const parentDir = path14.dirname(fullPath);
27799
- if (!fs15.existsSync(parentDir))
27800
- fs15.mkdirSync(parentDir, { recursive: true });
27801
- fs15.writeFileSync(fullPath, content, "utf-8");
27846
+ const parentDir = path15.dirname(fullPath);
27847
+ if (!fs16.existsSync(parentDir))
27848
+ fs16.mkdirSync(parentDir, { recursive: true });
27849
+ fs16.writeFileSync(fullPath, content, "utf-8");
27802
27850
  res.writeHead(200);
27803
27851
  res.end(JSON.stringify({ success: true }));
27804
27852
  } catch (err) {
@@ -27808,9 +27856,470 @@ var StatusServer = class {
27808
27856
  });
27809
27857
  return;
27810
27858
  }
27859
+ if (req.method === "GET" && url === "/browse/list-files") {
27860
+ const dir = parsedUrl.searchParams.get("dir");
27861
+ if (!dir || !fs16.existsSync(dir)) {
27862
+ res.writeHead(400);
27863
+ res.end(JSON.stringify({ error: "Missing or invalid dir parameter" }));
27864
+ return;
27865
+ }
27866
+ try {
27867
+ const files = [];
27868
+ collectFilesRecursive(dir, dir, files);
27869
+ res.writeHead(200);
27870
+ res.end(JSON.stringify({ files }));
27871
+ } catch (err) {
27872
+ res.writeHead(500);
27873
+ res.end(JSON.stringify({ error: err.message }));
27874
+ }
27875
+ return;
27876
+ }
27877
+ if (req.method === "POST" && url === "/browse/search") {
27878
+ let body = "";
27879
+ req.on("data", (chunk) => {
27880
+ body += chunk.toString();
27881
+ });
27882
+ req.on("end", () => {
27883
+ try {
27884
+ const { dir, query, isRegex, filePattern } = JSON.parse(body);
27885
+ if (!dir || !query) {
27886
+ res.writeHead(400);
27887
+ res.end(JSON.stringify({ error: "dir and query required" }));
27888
+ return;
27889
+ }
27890
+ if (!fs16.existsSync(dir)) {
27891
+ res.writeHead(400);
27892
+ res.end(JSON.stringify({ error: "dir does not exist" }));
27893
+ return;
27894
+ }
27895
+ const files = [];
27896
+ collectFilesRecursive(dir, dir, files);
27897
+ const regex = isRegex ? new RegExp(query, "gi") : null;
27898
+ const results = [];
27899
+ const maxResults = 100;
27900
+ for (const f of files) {
27901
+ if (results.length >= maxResults)
27902
+ break;
27903
+ if (filePattern && !matchGlob(f.filePath, filePattern))
27904
+ continue;
27905
+ const fullPath = path15.resolve(dir, f.filePath);
27906
+ let content;
27907
+ try {
27908
+ content = fs16.readFileSync(fullPath, "utf-8");
27909
+ } catch {
27910
+ continue;
27911
+ }
27912
+ const lines = content.split("\n");
27913
+ for (let i = 0; i < lines.length && results.length < maxResults; i++) {
27914
+ const matched = regex ? regex.test(lines[i]) : lines[i].toLowerCase().includes(query.toLowerCase());
27915
+ if (regex)
27916
+ regex.lastIndex = 0;
27917
+ if (matched) {
27918
+ results.push({ filePath: f.filePath, line: i + 1, content: lines[i] });
27919
+ }
27920
+ }
27921
+ }
27922
+ res.writeHead(200);
27923
+ res.end(JSON.stringify({ results }));
27924
+ } catch (err) {
27925
+ res.writeHead(500);
27926
+ res.end(JSON.stringify({ error: err.message }));
27927
+ }
27928
+ });
27929
+ return;
27930
+ }
27931
+ if (req.method === "POST" && url === "/browse/delete") {
27932
+ let body = "";
27933
+ req.on("data", (chunk) => {
27934
+ body += chunk.toString();
27935
+ });
27936
+ req.on("end", () => {
27937
+ try {
27938
+ const { dir, filePath } = JSON.parse(body);
27939
+ if (!dir || !filePath) {
27940
+ res.writeHead(400);
27941
+ res.end(JSON.stringify({ error: "dir and filePath required" }));
27942
+ return;
27943
+ }
27944
+ const fullPath = path15.resolve(dir, filePath);
27945
+ if (!fullPath.startsWith(path15.resolve(dir))) {
27946
+ res.writeHead(403);
27947
+ res.end(JSON.stringify({ error: "Path traversal not allowed" }));
27948
+ return;
27949
+ }
27950
+ if (!fs16.existsSync(fullPath)) {
27951
+ res.writeHead(404);
27952
+ res.end(JSON.stringify({ error: "File not found" }));
27953
+ return;
27954
+ }
27955
+ fs16.unlinkSync(fullPath);
27956
+ res.writeHead(200);
27957
+ res.end(JSON.stringify({ success: true }));
27958
+ } catch (err) {
27959
+ res.writeHead(500);
27960
+ res.end(JSON.stringify({ error: err.message }));
27961
+ }
27962
+ });
27963
+ return;
27964
+ }
27965
+ if (url === "/live/container-status") {
27966
+ res.writeHead(200);
27967
+ res.end(JSON.stringify({ status: "idle", projectId: parsedUrl.searchParams.get("projectId") || "repo" }));
27968
+ return;
27969
+ }
27970
+ if (req.method === "POST" && url === "/live/terminal") {
27971
+ let body = "";
27972
+ req.on("data", (chunk) => {
27973
+ body += chunk.toString();
27974
+ });
27975
+ req.on("end", () => {
27976
+ try {
27977
+ const parsed = body ? JSON.parse(body) : {};
27978
+ const command = parsed.command || "";
27979
+ const cwd = parsed.cwd || os9.homedir();
27980
+ const timeoutSeconds = Math.min(parsed.timeoutSeconds || 120, 600);
27981
+ const projectId = parsed.projectId || "repo";
27982
+ if (!command) {
27983
+ res.writeHead(400);
27984
+ res.end(JSON.stringify({ success: false, error: "command is required" }));
27985
+ return;
27986
+ }
27987
+ const spawnCwd = fs16.existsSync(cwd) ? cwd : os9.homedir();
27988
+ const shellCmd = process.platform === "win32" ? "cmd.exe" : process.env.SHELL || "/bin/bash";
27989
+ const shellEnv = { ...process.env, TERM: "xterm-256color", COLORTERM: "truecolor", FORCE_COLOR: "3" };
27990
+ const aiSession = Array.from(repoTerminalSessions.values()).find((s) => s.projectId === projectId && s.isAiSession && !s.exited);
27991
+ let stdout = "";
27992
+ let stderr = "";
27993
+ let finished = false;
27994
+ const child = spawn5(shellCmd, ["-c", command], {
27995
+ cwd: spawnCwd,
27996
+ env: shellEnv,
27997
+ stdio: ["pipe", "pipe", "pipe"]
27998
+ });
27999
+ child.stdout?.on("data", (d) => {
28000
+ const str = d.toString();
28001
+ stdout += str;
28002
+ if (aiSession) {
28003
+ for (const listener of aiSession.dataListeners) {
28004
+ try {
28005
+ listener(`\x1B[90m$ ${command}\x1B[0m
28006
+ `);
28007
+ } catch {
28008
+ }
28009
+ }
28010
+ for (const listener of aiSession.dataListeners) {
28011
+ try {
28012
+ listener(str);
28013
+ } catch {
28014
+ }
28015
+ }
28016
+ }
28017
+ });
28018
+ child.stderr?.on("data", (d) => {
28019
+ const str = d.toString();
28020
+ stderr += str;
28021
+ if (aiSession) {
28022
+ for (const listener of aiSession.dataListeners) {
28023
+ try {
28024
+ listener(str);
28025
+ } catch {
28026
+ }
28027
+ }
28028
+ }
28029
+ });
28030
+ const timeout = setTimeout(() => {
28031
+ if (!finished) {
28032
+ finished = true;
28033
+ try {
28034
+ child.kill("SIGKILL");
28035
+ } catch {
28036
+ }
28037
+ res.writeHead(200);
28038
+ res.end(JSON.stringify({
28039
+ success: false,
28040
+ exitCode: 124,
28041
+ stdout: stdout.slice(-5e4),
28042
+ stderr: stderr.slice(-5e4),
28043
+ error: `Timeout after ${timeoutSeconds}s`
28044
+ }));
28045
+ }
28046
+ }, timeoutSeconds * 1e3);
28047
+ child.on("exit", (code) => {
28048
+ if (finished)
28049
+ return;
28050
+ finished = true;
28051
+ clearTimeout(timeout);
28052
+ res.writeHead(200);
28053
+ res.end(JSON.stringify({
28054
+ success: code === 0,
28055
+ exitCode: code ?? -1,
28056
+ stdout: stdout.slice(-5e4),
28057
+ stderr: stderr.slice(-5e4),
28058
+ error: null
28059
+ }));
28060
+ });
28061
+ child.on("error", (err) => {
28062
+ if (finished)
28063
+ return;
28064
+ finished = true;
28065
+ clearTimeout(timeout);
28066
+ res.writeHead(200);
28067
+ res.end(JSON.stringify({
28068
+ success: false,
28069
+ exitCode: -1,
28070
+ stdout: "",
28071
+ stderr: "",
28072
+ error: err.message
28073
+ }));
28074
+ });
28075
+ } catch (err) {
28076
+ res.writeHead(500);
28077
+ res.end(JSON.stringify({ error: err.message }));
28078
+ }
28079
+ });
28080
+ return;
28081
+ }
28082
+ if (url === "/live/terminal/sessions") {
28083
+ if (req.method === "GET") {
28084
+ const pid = parsedUrl.searchParams.get("projectId") || "repo";
28085
+ const sessions = Array.from(repoTerminalSessions.values()).filter((s) => s.projectId === pid).map((s) => ({
28086
+ id: s.id,
28087
+ projectId: s.projectId,
28088
+ isAiSession: s.isAiSession,
28089
+ label: s.label,
28090
+ createdAt: s.createdAt,
28091
+ lastActivity: s.lastActivity,
28092
+ exited: s.exited,
28093
+ exitCode: s.exitCode,
28094
+ cols: s.cols,
28095
+ rows: s.rows
28096
+ }));
28097
+ res.writeHead(200);
28098
+ res.end(JSON.stringify({ success: true, sessions }));
28099
+ return;
28100
+ }
28101
+ if (req.method === "POST") {
28102
+ let body = "";
28103
+ req.on("data", (chunk) => {
28104
+ body += chunk.toString();
28105
+ });
28106
+ req.on("end", () => {
28107
+ try {
28108
+ const parsed = body ? JSON.parse(body) : {};
28109
+ const projectId = parsed.projectId || "repo";
28110
+ const cwd = parsed.cwd || os9.homedir();
28111
+ const cols = parsed.cols || 120;
28112
+ const rows = parsed.rows || 30;
28113
+ repoSessionCounter++;
28114
+ const sessionId = `repo-${Date.now()}-${repoSessionCounter}`;
28115
+ const label = parsed.label || `Terminal ${repoSessionCounter}`;
28116
+ const shellCmd = process.platform === "win32" ? "cmd.exe" : process.env.SHELL || "/bin/bash";
28117
+ const shellEnv = { ...process.env, TERM: "xterm-256color", COLORTERM: "truecolor", FORCE_COLOR: "3", COLUMNS: String(cols), LINES: String(rows) };
28118
+ const spawnCwd = fs16.existsSync(cwd) ? cwd : os9.homedir();
28119
+ let shell = null;
28120
+ let ptyProcess = null;
28121
+ if (ptyModule2) {
28122
+ try {
28123
+ ptyProcess = ptyModule2.spawn(shellCmd, [], { name: "xterm-256color", cols, rows, cwd: spawnCwd, env: shellEnv });
28124
+ } catch {
28125
+ ptyProcess = null;
28126
+ }
28127
+ }
28128
+ if (!ptyProcess) {
28129
+ try {
28130
+ shell = spawn5(shellCmd, ["-i"], { cwd: spawnCwd, env: shellEnv, stdio: ["pipe", "pipe", "pipe"] });
28131
+ } catch {
28132
+ shell = spawn5(shellCmd, [], { cwd: spawnCwd, env: shellEnv, stdio: ["pipe", "pipe", "pipe"] });
28133
+ }
28134
+ }
28135
+ const session = {
28136
+ id: sessionId,
28137
+ projectId,
28138
+ cwd: spawnCwd,
28139
+ shell,
28140
+ ptyProcess,
28141
+ outputBuffer: [],
28142
+ createdAt: Date.now(),
28143
+ lastActivity: Date.now(),
28144
+ cols,
28145
+ rows,
28146
+ isAiSession: parsed.isAiSession || false,
28147
+ label,
28148
+ exited: false,
28149
+ exitCode: null,
28150
+ dataListeners: /* @__PURE__ */ new Set(),
28151
+ exitListeners: /* @__PURE__ */ new Set()
28152
+ };
28153
+ const pushOutput = (str) => {
28154
+ session.outputBuffer.push(str);
28155
+ session.lastActivity = Date.now();
28156
+ while (session.outputBuffer.length > 500)
28157
+ session.outputBuffer.shift();
28158
+ for (const listener of session.dataListeners) {
28159
+ try {
28160
+ listener(str);
28161
+ } catch {
28162
+ }
28163
+ }
28164
+ };
28165
+ const handleExit = (code) => {
28166
+ session.exited = true;
28167
+ session.exitCode = code;
28168
+ for (const listener of session.exitListeners) {
28169
+ try {
28170
+ listener(code);
28171
+ } catch {
28172
+ }
28173
+ }
28174
+ };
28175
+ if (ptyProcess) {
28176
+ ptyProcess.onData((data) => pushOutput(data));
28177
+ ptyProcess.onExit(({ exitCode }) => handleExit(exitCode));
28178
+ } else if (shell) {
28179
+ shell.stdout?.on("data", (d) => pushOutput(d.toString()));
28180
+ shell.stderr?.on("data", (d) => pushOutput(d.toString()));
28181
+ shell.on("exit", (code) => handleExit(code));
28182
+ }
28183
+ repoTerminalSessions.set(sessionId, session);
28184
+ res.writeHead(200);
28185
+ res.end(JSON.stringify({
28186
+ success: true,
28187
+ session: { id: sessionId, projectId, isAiSession: session.isAiSession, label, createdAt: session.createdAt, lastActivity: session.lastActivity, exited: false, exitCode: null, cols, rows }
28188
+ }));
28189
+ } catch (err) {
28190
+ res.writeHead(500);
28191
+ res.end(JSON.stringify({ error: err.message }));
28192
+ }
28193
+ });
28194
+ return;
28195
+ }
28196
+ }
28197
+ if (req.method === "DELETE" && url?.startsWith("/live/terminal/sessions/")) {
28198
+ const sessionId = url.split("/").pop();
28199
+ const session = repoTerminalSessions.get(sessionId);
28200
+ if (session) {
28201
+ if (session.ptyProcess) {
28202
+ try {
28203
+ session.ptyProcess.kill();
28204
+ } catch {
28205
+ }
28206
+ }
28207
+ if (session.shell) {
28208
+ try {
28209
+ session.shell.kill();
28210
+ } catch {
28211
+ }
28212
+ }
28213
+ repoTerminalSessions.delete(sessionId);
28214
+ }
28215
+ res.writeHead(200);
28216
+ res.end(JSON.stringify({ success: true }));
28217
+ return;
28218
+ }
28219
+ if (req.method === "POST" && url === "/live/terminal/destroy") {
28220
+ let body = "";
28221
+ req.on("data", (chunk) => {
28222
+ body += chunk.toString();
28223
+ });
28224
+ req.on("end", () => {
28225
+ try {
28226
+ const { sessionId } = JSON.parse(body);
28227
+ const session = repoTerminalSessions.get(sessionId);
28228
+ if (session) {
28229
+ if (session.ptyProcess) {
28230
+ try {
28231
+ session.ptyProcess.kill();
28232
+ } catch {
28233
+ }
28234
+ }
28235
+ if (session.shell) {
28236
+ try {
28237
+ session.shell.kill();
28238
+ } catch {
28239
+ }
28240
+ }
28241
+ repoTerminalSessions.delete(sessionId);
28242
+ }
28243
+ res.writeHead(200);
28244
+ res.end(JSON.stringify({ success: true }));
28245
+ } catch (err) {
28246
+ res.writeHead(500);
28247
+ res.end(JSON.stringify({ error: err.message }));
28248
+ }
28249
+ });
28250
+ return;
28251
+ }
28252
+ if (req.headers.upgrade && req.headers.upgrade.toLowerCase() === "websocket") {
28253
+ return;
28254
+ }
27811
28255
  res.writeHead(404);
27812
28256
  res.end(JSON.stringify({ error: "Not found" }));
27813
28257
  });
28258
+ const wss = new import_websocket_server.default({ noServer: true });
28259
+ this.server.on("upgrade", (req, socket, head) => {
28260
+ const urlMatch = req.url?.match(/^\/live\/terminal\/ws\/([^/]+)\/([^/?]+)/);
28261
+ if (!urlMatch) {
28262
+ socket.destroy();
28263
+ return;
28264
+ }
28265
+ const sessionId = urlMatch[2];
28266
+ const session = repoTerminalSessions.get(sessionId);
28267
+ if (!session) {
28268
+ socket.destroy();
28269
+ return;
28270
+ }
28271
+ wss.handleUpgrade(req, socket, head, (ws) => {
28272
+ if (session.outputBuffer.length > 0) {
28273
+ ws.send(JSON.stringify({ type: "scrollback", data: session.outputBuffer.join("") }));
28274
+ }
28275
+ ws.send(JSON.stringify({ type: "connected", sessionId: session.id, projectId: session.projectId }));
28276
+ const dataListener = (data) => {
28277
+ try {
28278
+ if (ws.readyState === import_websocket.default.OPEN)
28279
+ ws.send(JSON.stringify({ type: "output", data }));
28280
+ } catch {
28281
+ }
28282
+ };
28283
+ const exitListener = (code) => {
28284
+ try {
28285
+ if (ws.readyState === import_websocket.default.OPEN)
28286
+ ws.send(JSON.stringify({ type: "exit", exitCode: code }));
28287
+ } catch {
28288
+ }
28289
+ };
28290
+ session.dataListeners.add(dataListener);
28291
+ session.exitListeners.add(exitListener);
28292
+ ws.on("message", (raw) => {
28293
+ try {
28294
+ const msg = JSON.parse(typeof raw === "string" ? raw : raw.toString());
28295
+ if (msg.type === "input" && msg.data) {
28296
+ if (session.ptyProcess)
28297
+ session.ptyProcess.write(msg.data);
28298
+ else if (session.shell?.stdin)
28299
+ session.shell.stdin.write(msg.data);
28300
+ } else if (msg.type === "resize" && msg.cols && msg.rows) {
28301
+ session.cols = msg.cols;
28302
+ session.rows = msg.rows;
28303
+ if (session.ptyProcess) {
28304
+ try {
28305
+ session.ptyProcess.resize(msg.cols, msg.rows);
28306
+ } catch {
28307
+ }
28308
+ }
28309
+ }
28310
+ } catch {
28311
+ }
28312
+ });
28313
+ ws.on("close", () => {
28314
+ session.dataListeners.delete(dataListener);
28315
+ session.exitListeners.delete(exitListener);
28316
+ });
28317
+ ws.on("error", () => {
28318
+ session.dataListeners.delete(dataListener);
28319
+ session.exitListeners.delete(exitListener);
28320
+ });
28321
+ });
28322
+ });
27814
28323
  this.server.on("error", (err) => {
27815
28324
  if (err.code === "EADDRINUSE") {
27816
28325
  console.log(` [Status] Port ${STATUS_PORT} in use \u2014 status server skipped`);
@@ -27819,7 +28328,7 @@ var StatusServer = class {
27819
28328
  }
27820
28329
  reject(err);
27821
28330
  });
27822
- this.server.listen(STATUS_PORT, "127.0.0.1", () => {
28331
+ this.server.listen(STATUS_PORT, () => {
27823
28332
  this.writeStatusFile();
27824
28333
  resolve();
27825
28334
  });
@@ -27831,16 +28340,16 @@ var StatusServer = class {
27831
28340
  this.server = null;
27832
28341
  }
27833
28342
  try {
27834
- if (fs15.existsSync(STATUS_FILE))
27835
- fs15.unlinkSync(STATUS_FILE);
28343
+ if (fs16.existsSync(STATUS_FILE))
28344
+ fs16.unlinkSync(STATUS_FILE);
27836
28345
  } catch {
27837
28346
  }
27838
28347
  }
27839
28348
  writeStatusFile() {
27840
- const dir = path14.dirname(STATUS_FILE);
27841
- if (!fs15.existsSync(dir))
27842
- fs15.mkdirSync(dir, { recursive: true });
27843
- fs15.writeFileSync(STATUS_FILE, JSON.stringify({
28349
+ const dir = path15.dirname(STATUS_FILE);
28350
+ if (!fs16.existsSync(dir))
28351
+ fs16.mkdirSync(dir, { recursive: true });
28352
+ fs16.writeFileSync(STATUS_FILE, JSON.stringify({
27844
28353
  port: STATUS_PORT,
27845
28354
  pid: process.pid,
27846
28355
  startedAt: (/* @__PURE__ */ new Date()).toISOString()
@@ -27863,7 +28372,7 @@ function buildFileTree(dirPath, name, relativePath = "") {
27863
28372
  const node = { name, path: relativePath, isDirectory: true, children: [] };
27864
28373
  let entries;
27865
28374
  try {
27866
- entries = fs15.readdirSync(dirPath, { withFileTypes: true });
28375
+ entries = fs16.readdirSync(dirPath, { withFileTypes: true });
27867
28376
  } catch {
27868
28377
  return node;
27869
28378
  }
@@ -27876,7 +28385,7 @@ function buildFileTree(dirPath, name, relativePath = "") {
27876
28385
  if (entry.isDirectory()) {
27877
28386
  if (SKIP_DIRS2.has(entry.name))
27878
28387
  continue;
27879
- dirs.push(buildFileTree(path14.join(dirPath, entry.name), entry.name, childRelative));
28388
+ dirs.push(buildFileTree(path15.join(dirPath, entry.name), entry.name, childRelative));
27880
28389
  } else {
27881
28390
  files.push({ name: entry.name, path: childRelative, isDirectory: false, children: [] });
27882
28391
  }
@@ -27886,9 +28395,79 @@ function buildFileTree(dirPath, name, relativePath = "") {
27886
28395
  node.children = [...dirs, ...files];
27887
28396
  return node;
27888
28397
  }
28398
+ var BINARY_EXTENSIONS = /* @__PURE__ */ new Set([
28399
+ ".png",
28400
+ ".jpg",
28401
+ ".jpeg",
28402
+ ".gif",
28403
+ ".webp",
28404
+ ".ico",
28405
+ ".svg",
28406
+ ".bmp",
28407
+ ".woff",
28408
+ ".woff2",
28409
+ ".ttf",
28410
+ ".eot",
28411
+ ".otf",
28412
+ ".zip",
28413
+ ".tar",
28414
+ ".gz",
28415
+ ".rar",
28416
+ ".7z",
28417
+ ".pdf",
28418
+ ".doc",
28419
+ ".docx",
28420
+ ".xls",
28421
+ ".xlsx",
28422
+ ".mp3",
28423
+ ".mp4",
28424
+ ".wav",
28425
+ ".avi",
28426
+ ".mov",
28427
+ ".exe",
28428
+ ".dll",
28429
+ ".so",
28430
+ ".dylib",
28431
+ ".o"
28432
+ ]);
28433
+ function collectFilesRecursive(baseDir, currentDir, out) {
28434
+ let entries;
28435
+ try {
28436
+ entries = fs16.readdirSync(currentDir, { withFileTypes: true });
28437
+ } catch {
28438
+ return;
28439
+ }
28440
+ for (const entry of entries) {
28441
+ if (entry.name.startsWith(".") && entry.name !== ".env")
28442
+ continue;
28443
+ const fullPath = path15.join(currentDir, entry.name);
28444
+ const relativePath = path15.relative(baseDir, fullPath);
28445
+ if (entry.isDirectory()) {
28446
+ if (SKIP_DIRS2.has(entry.name))
28447
+ continue;
28448
+ collectFilesRecursive(baseDir, fullPath, out);
28449
+ } else {
28450
+ const ext = path15.extname(entry.name).toLowerCase();
28451
+ if (BINARY_EXTENSIONS.has(ext)) {
28452
+ out.push({ filePath: relativePath, totalLines: 0 });
28453
+ } else {
28454
+ try {
28455
+ const content = fs16.readFileSync(fullPath, "utf-8");
28456
+ out.push({ filePath: relativePath, totalLines: content.split("\n").length });
28457
+ } catch {
28458
+ out.push({ filePath: relativePath, totalLines: 0 });
28459
+ }
28460
+ }
28461
+ }
28462
+ }
28463
+ }
28464
+ function matchGlob(filePath, pattern) {
28465
+ const regexPattern = "^" + pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "<<<GLOBSTAR>>>").replace(/\*/g, "[^/]*").replace(/<<<GLOBSTAR>>>/g, ".*").replace(/\?/g, ".") + "$";
28466
+ return new RegExp(regexPattern, "i").test(filePath);
28467
+ }
27889
28468
 
27890
28469
  // dist/commands/start.js
27891
- var VERSION = "0.5.29";
28470
+ var VERSION = getPackageVersion();
27892
28471
  function resolveBackendUrl(options) {
27893
28472
  if (options.backend)
27894
28473
  return options.backend.replace(/\/$/, "");
@@ -27897,10 +28476,10 @@ function resolveBackendUrl(options) {
27897
28476
  }
27898
28477
  function resolveProjectDir(directory, projectId, customDir) {
27899
28478
  if (customDir)
27900
- return path15.resolve(customDir);
28479
+ return path16.resolve(customDir);
27901
28480
  if (directory !== ".")
27902
- return path15.resolve(directory);
27903
- const defaultBase = path15.join(os10.homedir(), ".nstantpage", "projects", projectId);
28481
+ return path16.resolve(directory);
28482
+ const defaultBase = path16.join(os10.homedir(), ".nstantpage", "projects", projectId);
27904
28483
  return defaultBase;
27905
28484
  }
27906
28485
  async function fetchProjectFiles(backendUrl, projectId, projectDir, token) {
@@ -27920,20 +28499,20 @@ async function fetchProjectFiles(backendUrl, projectId, projectDir, token) {
27920
28499
  if (!data.files || data.files.length === 0) {
27921
28500
  throw new Error("No files returned from backend. Is the project ID correct?");
27922
28501
  }
27923
- const versionFile = path15.join(projectDir, ".nstantpage-version");
27924
- const existingVersion = fs16.existsSync(versionFile) ? fs16.readFileSync(versionFile, "utf-8").trim() : null;
28502
+ const versionFile = path16.join(projectDir, ".nstantpage-version");
28503
+ const existingVersion = fs17.existsSync(versionFile) ? fs17.readFileSync(versionFile, "utf-8").trim() : null;
27925
28504
  if (existingVersion === String(data.versionId)) {
27926
28505
  console.log(source_default.gray(` Files up-to-date (version ${data.version})`));
27927
28506
  return { fileCount: data.files.length, isNew: false, versionId: String(data.versionId) };
27928
28507
  }
27929
28508
  const dirsToCreate = /* @__PURE__ */ new Set();
27930
28509
  for (const file of data.files) {
27931
- const filePath = path15.join(projectDir, file.path);
27932
- dirsToCreate.add(path15.dirname(filePath));
28510
+ const filePath = path16.join(projectDir, file.path);
28511
+ dirsToCreate.add(path16.dirname(filePath));
27933
28512
  }
27934
28513
  for (const dir of dirsToCreate) {
27935
- if (!fs16.existsSync(dir)) {
27936
- fs16.mkdirSync(dir, { recursive: true });
28514
+ if (!fs17.existsSync(dir)) {
28515
+ fs17.mkdirSync(dir, { recursive: true });
27937
28516
  }
27938
28517
  }
27939
28518
  const BATCH_SIZE = 50;
@@ -27941,12 +28520,12 @@ async function fetchProjectFiles(backendUrl, projectId, projectDir, token) {
27941
28520
  for (let i = 0; i < data.files.length; i += BATCH_SIZE) {
27942
28521
  const batch = data.files.slice(i, i + BATCH_SIZE);
27943
28522
  await Promise.all(batch.map(async (file) => {
27944
- const filePath = path15.join(projectDir, file.path);
27945
- await fs16.promises.writeFile(filePath, file.content, "utf-8");
28523
+ const filePath = path16.join(projectDir, file.path);
28524
+ await fs17.promises.writeFile(filePath, file.content, "utf-8");
27946
28525
  }));
27947
28526
  written += batch.length;
27948
28527
  }
27949
- fs16.writeFileSync(versionFile, String(data.versionId), "utf-8");
28528
+ fs17.writeFileSync(versionFile, String(data.versionId), "utf-8");
27950
28529
  console.log(source_default.green(` \u2713 ${written} files downloaded (version ${data.version})`));
27951
28530
  return { fileCount: written, isNew: true, versionId: String(data.versionId) };
27952
28531
  }
@@ -28050,8 +28629,8 @@ async function startCommand(directory, options) {
28050
28629
  apiPort = allocated.apiPort;
28051
28630
  }
28052
28631
  const projectDir = resolveProjectDir(directory, projectId, options.dir);
28053
- if (!fs16.existsSync(projectDir)) {
28054
- fs16.mkdirSync(projectDir, { recursive: true });
28632
+ if (!fs17.existsSync(projectDir)) {
28633
+ fs17.mkdirSync(projectDir, { recursive: true });
28055
28634
  }
28056
28635
  conf.set("projectId", projectId);
28057
28636
  cleanupPreviousAgent(projectId, apiPort, devPort);
@@ -28073,7 +28652,7 @@ async function startCommand(directory, options) {
28073
28652
  const { fileCount, isNew, versionId } = await fetchProjectFiles(backendUrl, projectId, projectDir, token);
28074
28653
  fetchedVersionId = versionId;
28075
28654
  if (!installer.areDependenciesInstalled()) {
28076
- if (fs16.existsSync(path15.join(projectDir, "package.json"))) {
28655
+ if (fs17.existsSync(path16.join(projectDir, "package.json"))) {
28077
28656
  console.log(source_default.gray(" Installing dependencies..."));
28078
28657
  try {
28079
28658
  await installer.ensureDependencies();
@@ -28089,16 +28668,16 @@ async function startCommand(directory, options) {
28089
28668
  } catch (err) {
28090
28669
  console.log(source_default.yellow(` \u26A0 Could not fetch project files: ${err.message}`));
28091
28670
  console.log(source_default.gray(" Continuing with existing local files (if any)..."));
28092
- if (!fs16.existsSync(path15.join(projectDir, "package.json"))) {
28671
+ if (!fs17.existsSync(path16.join(projectDir, "package.json"))) {
28093
28672
  console.log(source_default.red(`
28094
28673
  \u2717 No package.json found and cannot fetch files from backend.`));
28095
28674
  console.log(source_default.gray(" Check your project ID and authentication."));
28096
28675
  process.exit(1);
28097
28676
  }
28098
28677
  }
28099
- const localConfigPath = path15.join(projectDir, ".nstantpage.json");
28100
- if (!fs16.existsSync(localConfigPath)) {
28101
- fs16.writeFileSync(localConfigPath, JSON.stringify({ projectId }, null, 2), "utf-8");
28678
+ const localConfigPath = path16.join(projectDir, ".nstantpage.json");
28679
+ if (!fs17.existsSync(localConfigPath)) {
28680
+ fs17.writeFileSync(localConfigPath, JSON.stringify({ projectId }, null, 2), "utf-8");
28102
28681
  }
28103
28682
  let databaseUrl = null;
28104
28683
  try {
@@ -28322,9 +28901,9 @@ async function startStandbyMode(token, options, backendUrl, deviceId) {
28322
28901
  await existing.localServer.stop();
28323
28902
  activeProjects.delete(pid);
28324
28903
  const projectDir = resolveProjectDir(".", pid);
28325
- if (fs16.existsSync(projectDir)) {
28904
+ if (fs17.existsSync(projectDir)) {
28326
28905
  console.log(source_default.gray(` Wiping project directory: ${projectDir}`));
28327
- fs16.rmSync(projectDir, { recursive: true, force: true });
28906
+ fs17.rmSync(projectDir, { recursive: true, force: true });
28328
28907
  }
28329
28908
  } else if (activeProjects.has(pid)) {
28330
28909
  console.log(source_default.yellow(` Project ${pid} is already running`));
@@ -28487,8 +29066,8 @@ async function startAdditionalProject(projectId, opts) {
28487
29066
  try {
28488
29067
  const allocated = allocatePortsForProject(projectId);
28489
29068
  const projectDir = resolveProjectDir(".", projectId);
28490
- if (!fs16.existsSync(projectDir))
28491
- fs16.mkdirSync(projectDir, { recursive: true });
29069
+ if (!fs17.existsSync(projectDir))
29070
+ fs17.mkdirSync(projectDir, { recursive: true });
28492
29071
  cleanupPreviousAgent(projectId, allocated.apiPort, allocated.devPort);
28493
29072
  await new Promise((r) => setTimeout(r, 50));
28494
29073
  progress("fetching-files", "Fetching project files...");
@@ -28561,7 +29140,7 @@ async function startAdditionalProject(projectId, opts) {
28561
29140
  localServer.markSynced(fetchedVersionId);
28562
29141
  }
28563
29142
  const installer = new PackageInstaller({ projectDir });
28564
- const needsInstall = !installer.areDependenciesInstalled() && fs16.existsSync(path15.join(projectDir, "package.json"));
29143
+ const needsInstall = !installer.areDependenciesInstalled() && fs17.existsSync(path16.join(projectDir, "package.json"));
28565
29144
  if (needsInstall) {
28566
29145
  const installStart = Date.now();
28567
29146
  console.log(source_default.gray(` Installing dependencies...`));
@@ -28672,13 +29251,13 @@ async function statusCommand() {
28672
29251
 
28673
29252
  // dist/commands/service.js
28674
29253
  init_config();
28675
- import fs17 from "fs";
28676
- import path16 from "path";
29254
+ import fs18 from "fs";
29255
+ import path17 from "path";
28677
29256
  import os11 from "os";
28678
29257
  import { execSync as execSync3 } from "child_process";
28679
- import { fileURLToPath as fileURLToPath2 } from "url";
28680
- var __filename_esm = fileURLToPath2(import.meta.url);
28681
- var __dirname_esm = path16.dirname(__filename_esm);
29258
+ import { fileURLToPath as fileURLToPath3 } from "url";
29259
+ var __filename_esm2 = fileURLToPath3(import.meta.url);
29260
+ var __dirname_esm2 = path17.dirname(__filename_esm2);
28682
29261
  var PLIST_LABEL = "com.nstantpage.agent";
28683
29262
  var SYSTEMD_SERVICE = "nstantpage-agent";
28684
29263
  var WIN_TASK_NAME = "NstantpageAgent";
@@ -28705,8 +29284,8 @@ async function serviceStopCommand() {
28705
29284
  const platform2 = os11.platform();
28706
29285
  let stopped = false;
28707
29286
  if (platform2 === "darwin") {
28708
- const plistPath = path16.join(os11.homedir(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
28709
- if (fs17.existsSync(plistPath)) {
29287
+ const plistPath = path17.join(os11.homedir(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
29288
+ if (fs18.existsSync(plistPath)) {
28710
29289
  try {
28711
29290
  execSync3(`launchctl unload "${plistPath}" 2>/dev/null`, { encoding: "utf-8" });
28712
29291
  console.log(source_default.green(" \u2713 Background service stopped"));
@@ -28767,7 +29346,7 @@ async function serviceInstallCommand(options = {}) {
28767
29346
  return;
28768
29347
  }
28769
29348
  if (electronAppPath === null) {
28770
- console.log(source_default.gray(" Tip: Install the nstantpage desktop app for a system tray icon."));
29349
+ console.log(source_default.gray(' Tip: Run "nstantpage update --desktop" to download the desktop app with tray icon.'));
28771
29350
  }
28772
29351
  if (platform2 === "darwin") {
28773
29352
  await installLaunchd(gateway, token);
@@ -28834,12 +29413,12 @@ async function serviceStatusCommand() {
28834
29413
  } else {
28835
29414
  console.log(source_default.gray(" Service status not available on this platform"));
28836
29415
  }
28837
- const logPath = path16.join(os11.homedir(), ".nstantpage", "agent.log");
28838
- if (fs17.existsSync(logPath)) {
28839
- const stats = fs17.statSync(logPath);
29416
+ const logPath = path17.join(os11.homedir(), ".nstantpage", "agent.log");
29417
+ if (fs18.existsSync(logPath)) {
29418
+ const stats = fs18.statSync(logPath);
28840
29419
  console.log(source_default.gray(` Log file: ${logPath} (${(stats.size / 1024).toFixed(1)}KB)`));
28841
29420
  try {
28842
- const content = fs17.readFileSync(logPath, "utf-8");
29421
+ const content = fs18.readFileSync(logPath, "utf-8");
28843
29422
  const lines = content.trim().split("\n").slice(-5);
28844
29423
  if (lines.length > 0) {
28845
29424
  console.log(source_default.gray(" Last log lines:"));
@@ -28853,35 +29432,39 @@ function findElectronApp() {
28853
29432
  const platform2 = os11.platform();
28854
29433
  if (platform2 === "darwin") {
28855
29434
  const candidates = [
29435
+ // Downloaded by postinstall (npm i -g nstantpage-agent)
29436
+ path17.join(os11.homedir(), ".nstantpage", "desktop", "nstantpage.app"),
28856
29437
  "/Applications/nstantpage.app",
28857
- path16.join(os11.homedir(), "Applications", "nstantpage.app"),
29438
+ path17.join(os11.homedir(), "Applications", "nstantpage.app"),
28858
29439
  // Dev build location (from electron-builder --dir)
28859
- path16.join(__dirname_esm, "..", "..", "tray", "dist", "mac-arm64", "nstantpage.app"),
28860
- path16.join(__dirname_esm, "..", "..", "tray", "dist", "mac", "nstantpage.app")
29440
+ path17.join(__dirname_esm2, "..", "..", "tray", "dist", "mac-arm64", "nstantpage.app"),
29441
+ path17.join(__dirname_esm2, "..", "..", "tray", "dist", "mac", "nstantpage.app")
28861
29442
  ];
28862
29443
  for (const p of candidates) {
28863
- if (fs17.existsSync(p))
29444
+ if (fs18.existsSync(p))
28864
29445
  return p;
28865
29446
  }
28866
29447
  } else if (platform2 === "win32") {
28867
29448
  const candidates = [
28868
- path16.join(os11.homedir(), "AppData", "Local", "Programs", "nstantpage", "nstantpage.exe"),
28869
- path16.join("C:\\Program Files", "nstantpage", "nstantpage.exe")
29449
+ // Downloaded by postinstall (npm i -g nstantpage-agent)
29450
+ path17.join(os11.homedir(), ".nstantpage", "desktop", "nstantpage.exe"),
29451
+ path17.join(os11.homedir(), "AppData", "Local", "Programs", "nstantpage", "nstantpage.exe"),
29452
+ path17.join("C:\\Program Files", "nstantpage", "nstantpage.exe")
28870
29453
  ];
28871
29454
  for (const p of candidates) {
28872
- if (fs17.existsSync(p))
29455
+ if (fs18.existsSync(p))
28873
29456
  return p;
28874
29457
  }
28875
29458
  }
28876
29459
  return null;
28877
29460
  }
28878
29461
  async function installElectronLaunchd(appPath) {
28879
- const plistDir = path16.join(os11.homedir(), "Library", "LaunchAgents");
28880
- const plistPath = path16.join(plistDir, `${PLIST_LABEL}.plist`);
28881
- const logPath = path16.join(os11.homedir(), ".nstantpage", "agent.log");
28882
- const errPath = path16.join(os11.homedir(), ".nstantpage", "agent.err.log");
28883
- fs17.mkdirSync(plistDir, { recursive: true });
28884
- fs17.mkdirSync(path16.dirname(logPath), { recursive: true });
29462
+ const plistDir = path17.join(os11.homedir(), "Library", "LaunchAgents");
29463
+ const plistPath = path17.join(plistDir, `${PLIST_LABEL}.plist`);
29464
+ const logPath = path17.join(os11.homedir(), ".nstantpage", "agent.log");
29465
+ const errPath = path17.join(os11.homedir(), ".nstantpage", "agent.err.log");
29466
+ fs18.mkdirSync(plistDir, { recursive: true });
29467
+ fs18.mkdirSync(path17.dirname(logPath), { recursive: true });
28885
29468
  const plist = `<?xml version="1.0" encoding="UTF-8"?>
28886
29469
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
28887
29470
  <plist version="1.0">
@@ -28916,7 +29499,7 @@ async function installElectronLaunchd(appPath) {
28916
29499
  <integer>10</integer>
28917
29500
  </dict>
28918
29501
  </plist>`;
28919
- fs17.writeFileSync(plistPath, plist, "utf-8");
29502
+ fs18.writeFileSync(plistPath, plist, "utf-8");
28920
29503
  try {
28921
29504
  execSync3(`launchctl unload "${plistPath}" 2>/dev/null`, { encoding: "utf-8" });
28922
29505
  } catch {
@@ -28933,8 +29516,8 @@ async function installElectronLaunchd(appPath) {
28933
29516
  console.log(source_default.blue(" Right-click the tray icon for options. Open nstantpage.com to connect projects.\n"));
28934
29517
  }
28935
29518
  async function installElectronWindowsTask(appPath) {
28936
- const logPath = path16.join(os11.homedir(), ".nstantpage", "agent.log");
28937
- fs17.mkdirSync(path16.dirname(logPath), { recursive: true });
29519
+ const logPath = path17.join(os11.homedir(), ".nstantpage", "agent.log");
29520
+ fs18.mkdirSync(path17.dirname(logPath), { recursive: true });
28938
29521
  try {
28939
29522
  execSync3(`schtasks /delete /tn "${WIN_TASK_NAME}" /f 2>nul`, { encoding: "utf-8" });
28940
29523
  } catch {
@@ -28963,8 +29546,8 @@ function getAgentBinPath() {
28963
29546
  }
28964
29547
  try {
28965
29548
  const npmRoot = execSync3("npm root -g", { encoding: "utf-8" }).trim();
28966
- const bin = path16.join(npmRoot, ".bin", "nstantpage");
28967
- if (fs17.existsSync(bin))
29549
+ const bin = path17.join(npmRoot, ".bin", "nstantpage");
29550
+ if (fs18.existsSync(bin))
28968
29551
  return bin;
28969
29552
  } catch {
28970
29553
  }
@@ -28980,12 +29563,12 @@ function getNodePath() {
28980
29563
  async function installLaunchd(gateway, token) {
28981
29564
  const binPath = getAgentBinPath();
28982
29565
  const nodePath = getNodePath();
28983
- const plistDir = path16.join(os11.homedir(), "Library", "LaunchAgents");
28984
- const plistPath = path16.join(plistDir, `${PLIST_LABEL}.plist`);
28985
- const logPath = path16.join(os11.homedir(), ".nstantpage", "agent.log");
28986
- const errPath = path16.join(os11.homedir(), ".nstantpage", "agent.err.log");
28987
- fs17.mkdirSync(plistDir, { recursive: true });
28988
- fs17.mkdirSync(path16.dirname(logPath), { recursive: true });
29566
+ const plistDir = path17.join(os11.homedir(), "Library", "LaunchAgents");
29567
+ const plistPath = path17.join(plistDir, `${PLIST_LABEL}.plist`);
29568
+ const logPath = path17.join(os11.homedir(), ".nstantpage", "agent.log");
29569
+ const errPath = path17.join(os11.homedir(), ".nstantpage", "agent.err.log");
29570
+ fs18.mkdirSync(plistDir, { recursive: true });
29571
+ fs18.mkdirSync(path17.dirname(logPath), { recursive: true });
28989
29572
  const plist = `<?xml version="1.0" encoding="UTF-8"?>
28990
29573
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
28991
29574
  <plist version="1.0">
@@ -29025,7 +29608,7 @@ async function installLaunchd(gateway, token) {
29025
29608
  <integer>-5</integer>
29026
29609
  </dict>
29027
29610
  </plist>`;
29028
- fs17.writeFileSync(plistPath, plist, "utf-8");
29611
+ fs18.writeFileSync(plistPath, plist, "utf-8");
29029
29612
  try {
29030
29613
  execSync3(`launchctl unload "${plistPath}" 2>/dev/null`, { encoding: "utf-8" });
29031
29614
  } catch {
@@ -29041,8 +29624,8 @@ async function installLaunchd(gateway, token) {
29041
29624
  console.log(source_default.blue(' Open any project on nstantpage.com and click "Connect" to use it.\n'));
29042
29625
  }
29043
29626
  async function uninstallLaunchd() {
29044
- const plistPath = path16.join(os11.homedir(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
29045
- if (!fs17.existsSync(plistPath)) {
29627
+ const plistPath = path17.join(os11.homedir(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
29628
+ if (!fs18.existsSync(plistPath)) {
29046
29629
  console.log(source_default.yellow(" \u26A0 Service is not installed"));
29047
29630
  return;
29048
29631
  }
@@ -29050,15 +29633,15 @@ async function uninstallLaunchd() {
29050
29633
  execSync3(`launchctl unload "${plistPath}" 2>/dev/null`, { encoding: "utf-8" });
29051
29634
  } catch {
29052
29635
  }
29053
- fs17.unlinkSync(plistPath);
29636
+ fs18.unlinkSync(plistPath);
29054
29637
  console.log(source_default.green(" \u2713 Agent service uninstalled (launchd)"));
29055
29638
  console.log(source_default.gray(" The agent will no longer start automatically."));
29056
29639
  }
29057
29640
  async function installSystemd(gateway, token) {
29058
29641
  const binPath = getAgentBinPath();
29059
- const serviceDir = path16.join(os11.homedir(), ".config", "systemd", "user");
29060
- const servicePath = path16.join(serviceDir, `${SYSTEMD_SERVICE}.service`);
29061
- fs17.mkdirSync(serviceDir, { recursive: true });
29642
+ const serviceDir = path17.join(os11.homedir(), ".config", "systemd", "user");
29643
+ const servicePath = path17.join(serviceDir, `${SYSTEMD_SERVICE}.service`);
29644
+ fs18.mkdirSync(serviceDir, { recursive: true });
29062
29645
  const unit = `[Unit]
29063
29646
  Description=nstantpage Local Development Agent
29064
29647
  After=network-online.target
@@ -29075,7 +29658,7 @@ Environment=HOME=${os11.homedir()}
29075
29658
  [Install]
29076
29659
  WantedBy=default.target
29077
29660
  `;
29078
- fs17.writeFileSync(servicePath, unit, "utf-8");
29661
+ fs18.writeFileSync(servicePath, unit, "utf-8");
29079
29662
  try {
29080
29663
  execSync3("systemctl --user daemon-reload", { encoding: "utf-8" });
29081
29664
  execSync3(`systemctl --user enable ${SYSTEMD_SERVICE}`, { encoding: "utf-8" });
@@ -29094,8 +29677,8 @@ WantedBy=default.target
29094
29677
  console.log(source_default.blue(' Open any project on nstantpage.com and click "Connect" to use it.\n'));
29095
29678
  }
29096
29679
  async function uninstallSystemd() {
29097
- const servicePath = path16.join(os11.homedir(), ".config", "systemd", "user", `${SYSTEMD_SERVICE}.service`);
29098
- if (!fs17.existsSync(servicePath)) {
29680
+ const servicePath = path17.join(os11.homedir(), ".config", "systemd", "user", `${SYSTEMD_SERVICE}.service`);
29681
+ if (!fs18.existsSync(servicePath)) {
29099
29682
  console.log(source_default.yellow(" \u26A0 Service is not installed"));
29100
29683
  return;
29101
29684
  }
@@ -29104,7 +29687,7 @@ async function uninstallSystemd() {
29104
29687
  execSync3(`systemctl --user disable ${SYSTEMD_SERVICE} 2>/dev/null`, { encoding: "utf-8" });
29105
29688
  } catch {
29106
29689
  }
29107
- fs17.unlinkSync(servicePath);
29690
+ fs18.unlinkSync(servicePath);
29108
29691
  try {
29109
29692
  execSync3("systemctl --user daemon-reload", { encoding: "utf-8" });
29110
29693
  } catch {
@@ -29115,14 +29698,14 @@ async function uninstallSystemd() {
29115
29698
  async function installWindowsTask(gateway, token) {
29116
29699
  const binPath = getAgentBinPath();
29117
29700
  const nodePath = getNodePath();
29118
- const logPath = path16.join(os11.homedir(), ".nstantpage", "agent.log");
29119
- fs17.mkdirSync(path16.dirname(logPath), { recursive: true });
29120
- const batchDir = path16.join(os11.homedir(), ".nstantpage");
29121
- const batchPath = path16.join(batchDir, "agent-service.cmd");
29701
+ const logPath = path17.join(os11.homedir(), ".nstantpage", "agent.log");
29702
+ fs18.mkdirSync(path17.dirname(logPath), { recursive: true });
29703
+ const batchDir = path17.join(os11.homedir(), ".nstantpage");
29704
+ const batchPath = path17.join(batchDir, "agent-service.cmd");
29122
29705
  const batchContent = `@echo off\r
29123
29706
  "${nodePath}" "${binPath}" start --gateway ${gateway} --token ${token} >> "${logPath}" 2>&1\r
29124
29707
  `;
29125
- fs17.writeFileSync(batchPath, batchContent, "utf-8");
29708
+ fs18.writeFileSync(batchPath, batchContent, "utf-8");
29126
29709
  try {
29127
29710
  execSync3(`schtasks /delete /tn "${WIN_TASK_NAME}" /f 2>nul`, { encoding: "utf-8" });
29128
29711
  } catch {
@@ -29152,21 +29735,148 @@ async function uninstallWindowsTask() {
29152
29735
  } catch {
29153
29736
  console.log(source_default.yellow(" \u26A0 Task is not installed or could not be removed"));
29154
29737
  }
29155
- const batchPath = path16.join(os11.homedir(), ".nstantpage", "agent-service.cmd");
29738
+ const batchPath = path17.join(os11.homedir(), ".nstantpage", "agent-service.cmd");
29156
29739
  try {
29157
- if (fs17.existsSync(batchPath))
29158
- fs17.unlinkSync(batchPath);
29740
+ if (fs18.existsSync(batchPath))
29741
+ fs18.unlinkSync(batchPath);
29159
29742
  } catch {
29160
29743
  }
29161
29744
  console.log(source_default.gray(" The agent will no longer start automatically."));
29162
29745
  }
29163
29746
 
29747
+ // dist/commands/update.js
29748
+ import fs19 from "fs";
29749
+ import path18 from "path";
29750
+ import os12 from "os";
29751
+ import { execSync as execSync4 } from "child_process";
29752
+ var DESKTOP_DIR = path18.join(os12.homedir(), ".nstantpage", "desktop");
29753
+ var VERSION_FILE = path18.join(DESKTOP_DIR, ".version");
29754
+ async function updateCommand(options = {}) {
29755
+ const updateBoth = !options.cli && !options.desktop;
29756
+ const currentVersion = getPackageVersion();
29757
+ console.log(source_default.blue(`
29758
+ nstantpage v${currentVersion}
29759
+ `));
29760
+ if (updateBoth || options.cli) {
29761
+ await updateCli(currentVersion);
29762
+ }
29763
+ if (updateBoth || options.desktop) {
29764
+ await updateDesktop();
29765
+ }
29766
+ console.log("");
29767
+ }
29768
+ async function updateCli(currentVersion) {
29769
+ console.log(source_default.gray(" Checking npm for CLI updates..."));
29770
+ try {
29771
+ const latest = execSync4("npm view nstantpage-agent version 2>/dev/null", {
29772
+ encoding: "utf-8"
29773
+ }).trim();
29774
+ if (latest === currentVersion) {
29775
+ console.log(source_default.green(` \u2713 CLI is up to date (${currentVersion})`));
29776
+ return;
29777
+ }
29778
+ console.log(source_default.yellow(` Updating CLI: ${currentVersion} \u2192 ${latest}`));
29779
+ execSync4("npm install -g nstantpage-agent@latest", {
29780
+ stdio: "inherit"
29781
+ });
29782
+ console.log(source_default.green(` \u2713 CLI updated to ${latest}`));
29783
+ } catch (err) {
29784
+ console.log(source_default.red(` \u2717 CLI update failed: ${err.message}`));
29785
+ console.log(source_default.gray(" Try manually: npm install -g nstantpage-agent@latest"));
29786
+ }
29787
+ }
29788
+ async function updateDesktop() {
29789
+ console.log(source_default.gray(" Checking GitHub for desktop updates..."));
29790
+ try {
29791
+ const scriptPath = path18.join(path18.dirname(new URL(import.meta.url).pathname), "..", "..", "scripts", "postinstall.mjs");
29792
+ if (fs19.existsSync(scriptPath)) {
29793
+ execSync4(`node "${scriptPath}"`, { stdio: "inherit" });
29794
+ } else {
29795
+ const altPath = path18.join(path18.dirname(new URL(import.meta.url).pathname), "..", "scripts", "postinstall.mjs");
29796
+ if (fs19.existsSync(altPath)) {
29797
+ execSync4(`node "${altPath}"`, { stdio: "inherit" });
29798
+ } else {
29799
+ console.log(source_default.yellow(" \u26A0 Desktop updater script not found. Reinstall to fix: npm i -g nstantpage-agent"));
29800
+ }
29801
+ }
29802
+ } catch (err) {
29803
+ console.log(source_default.red(` \u2717 Desktop update failed: ${err.message}`));
29804
+ }
29805
+ }
29806
+
29807
+ // dist/commands/run.js
29808
+ import fs20 from "fs";
29809
+ import path19 from "path";
29810
+ import os13 from "os";
29811
+ import { execSync as execSync5 } from "child_process";
29812
+ function findElectronApp2() {
29813
+ const platform2 = os13.platform();
29814
+ if (platform2 === "darwin") {
29815
+ const candidates = [
29816
+ path19.join(os13.homedir(), ".nstantpage", "desktop", "nstantpage.app"),
29817
+ "/Applications/nstantpage.app",
29818
+ path19.join(os13.homedir(), "Applications", "nstantpage.app")
29819
+ ];
29820
+ for (const p of candidates) {
29821
+ if (fs20.existsSync(p))
29822
+ return p;
29823
+ }
29824
+ } else if (platform2 === "win32") {
29825
+ const candidates = [
29826
+ path19.join(os13.homedir(), ".nstantpage", "desktop", "nstantpage.exe"),
29827
+ path19.join(os13.homedir(), "AppData", "Local", "Programs", "nstantpage", "nstantpage.exe"),
29828
+ path19.join("C:\\Program Files", "nstantpage", "nstantpage.exe")
29829
+ ];
29830
+ for (const p of candidates) {
29831
+ if (fs20.existsSync(p))
29832
+ return p;
29833
+ }
29834
+ }
29835
+ return null;
29836
+ }
29837
+ async function runCommand(options = {}) {
29838
+ const appPath = findElectronApp2();
29839
+ if (!appPath) {
29840
+ console.log(source_default.red(" \u2717 Desktop app not found."));
29841
+ console.log(source_default.gray(' Run "nstantpage update --desktop" to download it.'));
29842
+ process.exit(1);
29843
+ }
29844
+ const platform2 = os13.platform();
29845
+ const extraArgs = [];
29846
+ if (options.local !== void 0 && options.local !== false) {
29847
+ const port = typeof options.local === "string" ? options.local : "5001";
29848
+ extraArgs.push(`--local-url=http://localhost:${port}`);
29849
+ }
29850
+ console.log(source_default.blue(`
29851
+ Opening nstantpage desktop app...`));
29852
+ if (extraArgs.length) {
29853
+ console.log(source_default.gray(` Args: ${extraArgs.join(" ")}`));
29854
+ }
29855
+ try {
29856
+ if (platform2 === "darwin") {
29857
+ const argsStr = extraArgs.length ? ` --args ${extraArgs.join(" ")}` : "";
29858
+ execSync5(`open -a "${appPath}"${argsStr}`, { stdio: "inherit" });
29859
+ } else if (platform2 === "win32") {
29860
+ const argsStr = extraArgs.join(" ");
29861
+ execSync5(`"${appPath}" ${argsStr}`, { stdio: "inherit" });
29862
+ } else {
29863
+ console.log(source_default.yellow(" \u26A0 Desktop app not supported on this platform yet."));
29864
+ process.exit(1);
29865
+ }
29866
+ console.log(source_default.green(" \u2713 App launched\n"));
29867
+ } catch (err) {
29868
+ console.log(source_default.red(` \u2717 Failed to launch: ${err.message}`));
29869
+ process.exit(1);
29870
+ }
29871
+ }
29872
+
29164
29873
  // dist/cli.js
29165
29874
  var program2 = new Command();
29166
- program2.name("nstantpage").description("Local development agent for nstantpage.com \u2014 run projects on your machine, preview in the cloud").version("0.5.29");
29875
+ program2.name("nstantpage").description("Local development agent for nstantpage.com \u2014 run projects on your machine, preview in the cloud").version(getPackageVersion());
29167
29876
  program2.command("login").description("Authenticate with nstantpage.com").option("--gateway <url>", "Gateway URL (auto-detects local vs production)").option("--force", "Re-authenticate even if already logged in").action(loginCommand);
29168
29877
  program2.command("logout").description("Sign out and clear stored credentials").action(logoutCommand);
29169
29878
  program2.command("start").description("Start the agent for a project (replaces cloud containers)").argument("[directory]", "Project directory (defaults to ~/.nstantpage/projects/<id>)", ".").option("-p, --port <port>", "Local dev server port", "3000").option("-a, --api-port <port>", "Local API server port (internal)", "18924").option("--project-id <id>", "Link to a specific project ID").option("--gateway <url>", "Gateway URL (default: from login)").option("--backend <url>", "Backend API URL (auto-detected from gateway)").option("--token <token>", "Auth token (skip login flow)").option("--dir <path>", "Project directory override").option("--no-dev", "Skip starting the dev server (start manually later)").action(startCommand);
29879
+ program2.command("run").description("Open the nstantpage desktop app").option("--local [port]", "Connect to local backend (default: 5001)").action(runCommand);
29170
29880
  program2.command("stop").description("Stop the running agent").action(async () => {
29171
29881
  console.log(source_default.yellow("Stopping agent..."));
29172
29882
  const { getConfig: getConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
@@ -29192,4 +29902,5 @@ service.command("stop").description("Stop the running agent").action(serviceStop
29192
29902
  service.command("install").description("Install as a background service (auto-starts on boot)").option("--gateway <url>", "Gateway URL", "wss://webprev.live").action(serviceInstallCommand);
29193
29903
  service.command("uninstall").description("Remove the background service").action(serviceUninstallCommand);
29194
29904
  service.command("status").description("Check if the background service is running").action(serviceStatusCommand);
29905
+ program2.command("update").description("Update CLI and desktop app to the latest version").option("--cli", "Update only the CLI package").option("--desktop", "Update only the desktop app").action(updateCommand);
29195
29906
  program2.parse();