nstantpage-agent 0.5.34 → 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.
- package/dist/cli.bundle.js +1082 -161
- package/dist/cli.js +15 -1
- package/dist/commands/run.d.ts +13 -0
- package/dist/commands/run.js +82 -0
- package/dist/commands/service.js +5 -1
- package/dist/commands/start.js +9 -2
- package/dist/commands/update.d.ts +14 -0
- package/dist/commands/update.js +73 -0
- package/dist/fileManager.d.ts +11 -0
- package/dist/fileManager.js +44 -0
- package/dist/localServer.d.ts +3 -0
- package/dist/localServer.js +49 -1
- package/dist/packageInstaller.js +14 -1
- package/dist/statusServer.js +643 -2
- package/dist/tunnel.js +2 -1
- package/dist/version.d.ts +5 -0
- package/dist/version.js +34 -0
- package/package.json +3 -1
- package/scripts/postinstall.mjs +190 -0
package/dist/cli.bundle.js
CHANGED
|
@@ -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
|
|
976
|
-
var
|
|
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 =
|
|
1909
|
-
if (
|
|
1910
|
-
if (sourceExt.includes(
|
|
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) =>
|
|
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 =
|
|
1924
|
+
resolvedScriptPath = fs21.realpathSync(this._scriptPath);
|
|
1925
1925
|
} catch (err) {
|
|
1926
1926
|
resolvedScriptPath = this._scriptPath;
|
|
1927
1927
|
}
|
|
1928
|
-
executableDir =
|
|
1929
|
-
|
|
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 =
|
|
1936
|
+
const legacyName = path20.basename(
|
|
1937
1937
|
this._scriptPath,
|
|
1938
|
-
|
|
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(
|
|
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 =
|
|
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(
|
|
2804
|
-
if (
|
|
2805
|
-
this._executableDir =
|
|
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(
|
|
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
|
|
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,
|
|
3164
|
-
if (!isObject(object) || typeof
|
|
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(
|
|
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,
|
|
3188
|
-
if (!isObject(object) || typeof
|
|
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(
|
|
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,
|
|
3206
|
-
if (!isObject(object) || typeof
|
|
3205
|
+
function deleteProperty(object, path20) {
|
|
3206
|
+
if (!isObject(object) || typeof path20 !== "string") {
|
|
3207
3207
|
return false;
|
|
3208
3208
|
}
|
|
3209
|
-
const pathArray = getPathSegments(
|
|
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,
|
|
3224
|
-
if (!isObject(object) || typeof
|
|
3223
|
+
function hasProperty(object, path20) {
|
|
3224
|
+
if (!isObject(object) || typeof path20 !== "string") {
|
|
3225
3225
|
return false;
|
|
3226
3226
|
}
|
|
3227
|
-
const pathArray = getPathSegments(
|
|
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(
|
|
7010
|
-
let input =
|
|
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 [
|
|
7210
|
-
wsComponent.path =
|
|
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,
|
|
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,
|
|
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
|
|
19297
|
+
const fs21 = config.sslcert || config.sslkey || config.sslrootcert ? __require("fs") : null;
|
|
19298
19298
|
if (config.sslcert) {
|
|
19299
|
-
config.ssl.cert =
|
|
19299
|
+
config.ssl.cert = fs21.readFileSync(config.sslcert).toString();
|
|
19300
19300
|
}
|
|
19301
19301
|
if (config.sslkey) {
|
|
19302
|
-
config.ssl.key =
|
|
19302
|
+
config.ssl.key = fs21.readFileSync(config.sslkey).toString();
|
|
19303
19303
|
}
|
|
19304
19304
|
if (config.sslrootcert) {
|
|
19305
|
-
config.ssl.ca =
|
|
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
|
|
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 ?
|
|
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
|
|
21242
|
-
var
|
|
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
|
-
|
|
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 =
|
|
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
|
|
23993
|
-
import
|
|
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
|
|
24013
|
-
import
|
|
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";
|
|
@@ -24426,6 +24426,48 @@ var FileManager = class {
|
|
|
24426
24426
|
getProjectDir() {
|
|
24427
24427
|
return this.projectDir;
|
|
24428
24428
|
}
|
|
24429
|
+
/**
|
|
24430
|
+
* Build a recursive file tree of the project directory.
|
|
24431
|
+
* Returns a structure matching the backend's /api/projects/{id}/tree format.
|
|
24432
|
+
*/
|
|
24433
|
+
async getFileTree() {
|
|
24434
|
+
const root = {
|
|
24435
|
+
name: path8.basename(this.projectDir),
|
|
24436
|
+
path: "",
|
|
24437
|
+
isDirectory: true,
|
|
24438
|
+
children: []
|
|
24439
|
+
};
|
|
24440
|
+
if (existsSync(this.projectDir)) {
|
|
24441
|
+
root.children = await this.buildTree(this.projectDir, "");
|
|
24442
|
+
}
|
|
24443
|
+
return root;
|
|
24444
|
+
}
|
|
24445
|
+
async buildTree(dir, relativePath) {
|
|
24446
|
+
const SKIP_DIRS3 = /* @__PURE__ */ new Set(["node_modules", "dist", ".git", ".vite-cache", ".next", "__pycache__", ".turbo", ".cache"]);
|
|
24447
|
+
const entries = await fs10.readdir(dir, { withFileTypes: true });
|
|
24448
|
+
const result = [];
|
|
24449
|
+
const sorted = entries.sort((a, b) => {
|
|
24450
|
+
if (a.isDirectory() && !b.isDirectory())
|
|
24451
|
+
return -1;
|
|
24452
|
+
if (!a.isDirectory() && b.isDirectory())
|
|
24453
|
+
return 1;
|
|
24454
|
+
return a.name.localeCompare(b.name);
|
|
24455
|
+
});
|
|
24456
|
+
for (const entry of sorted) {
|
|
24457
|
+
if (entry.name.startsWith(".") && entry.name !== ".env")
|
|
24458
|
+
continue;
|
|
24459
|
+
const entryRelPath = relativePath ? `${relativePath}/${entry.name}` : entry.name;
|
|
24460
|
+
if (entry.isDirectory()) {
|
|
24461
|
+
if (SKIP_DIRS3.has(entry.name))
|
|
24462
|
+
continue;
|
|
24463
|
+
const children = await this.buildTree(path8.join(dir, entry.name), entryRelPath);
|
|
24464
|
+
result.push({ name: entry.name, path: entryRelPath, isDirectory: true, children });
|
|
24465
|
+
} else {
|
|
24466
|
+
result.push({ name: entry.name, path: entryRelPath, isDirectory: false, children: [] });
|
|
24467
|
+
}
|
|
24468
|
+
}
|
|
24469
|
+
return result;
|
|
24470
|
+
}
|
|
24429
24471
|
/**
|
|
24430
24472
|
* Check if a path exists.
|
|
24431
24473
|
*/
|
|
@@ -24774,7 +24816,16 @@ var PackageInstaller = class {
|
|
|
24774
24816
|
console.log(` [Installer] Installing project dependencies...`);
|
|
24775
24817
|
const pm = this.detectPackageManager();
|
|
24776
24818
|
const args = this.buildFastInstallArgs(pm);
|
|
24777
|
-
|
|
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
|
+
}
|
|
24778
24829
|
this.writeDepsHash();
|
|
24779
24830
|
console.log(` [Installer] Dependencies installed`);
|
|
24780
24831
|
} finally {
|
|
@@ -25694,11 +25745,40 @@ var AgentSync = class {
|
|
|
25694
25745
|
}
|
|
25695
25746
|
};
|
|
25696
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
|
+
|
|
25697
25777
|
// dist/localServer.js
|
|
25698
25778
|
var ptyModule = null;
|
|
25699
25779
|
try {
|
|
25700
|
-
const
|
|
25701
|
-
ptyModule =
|
|
25780
|
+
const _require2 = createRequire(import.meta.url);
|
|
25781
|
+
ptyModule = _require2("node-pty");
|
|
25702
25782
|
} catch {
|
|
25703
25783
|
}
|
|
25704
25784
|
var terminalSessions = /* @__PURE__ */ new Map();
|
|
@@ -25986,7 +26066,7 @@ Access-Control-Allow-Origin: *\r
|
|
|
25986
26066
|
res.end(JSON.stringify({ error: `Unknown endpoint: ${pathOnly}` }));
|
|
25987
26067
|
}
|
|
25988
26068
|
}
|
|
25989
|
-
getHandler(
|
|
26069
|
+
getHandler(path20) {
|
|
25990
26070
|
const handlers = {
|
|
25991
26071
|
"/live/sync": this.handleSync,
|
|
25992
26072
|
"/live/files": this.handleFiles,
|
|
@@ -26033,12 +26113,15 @@ Access-Control-Allow-Origin: *\r
|
|
|
26033
26113
|
"/live/push-to-backend": this.handlePushToBackend,
|
|
26034
26114
|
"/live/pull-from-backend": this.handlePullFromBackend,
|
|
26035
26115
|
"/live/disk-file": this.handleDiskFile,
|
|
26116
|
+
"/live/tree": this.handleTree,
|
|
26117
|
+
"/live/file-content": this.handleFileContent,
|
|
26118
|
+
"/live/save-file": this.handleSaveFile,
|
|
26036
26119
|
"/health": this.handleHealth
|
|
26037
26120
|
};
|
|
26038
|
-
if (handlers[
|
|
26039
|
-
return handlers[
|
|
26121
|
+
if (handlers[path20])
|
|
26122
|
+
return handlers[path20];
|
|
26040
26123
|
for (const [route, handler] of Object.entries(handlers)) {
|
|
26041
|
-
if (
|
|
26124
|
+
if (path20.startsWith(route + "/"))
|
|
26042
26125
|
return handler;
|
|
26043
26126
|
}
|
|
26044
26127
|
return null;
|
|
@@ -26260,7 +26343,7 @@ Access-Control-Allow-Origin: *\r
|
|
|
26260
26343
|
const label = parsed.label || `Terminal ${sessionCounter}`;
|
|
26261
26344
|
let shell = null;
|
|
26262
26345
|
let ptyProcess = null;
|
|
26263
|
-
const spawnCwd =
|
|
26346
|
+
const spawnCwd = fs15.existsSync(this.options.projectDir) ? this.options.projectDir : process.cwd();
|
|
26264
26347
|
if (ptyModule) {
|
|
26265
26348
|
try {
|
|
26266
26349
|
ptyProcess = ptyModule.spawn(shellCmd, [], {
|
|
@@ -26422,7 +26505,7 @@ Access-Control-Allow-Origin: *\r
|
|
|
26422
26505
|
connected: true,
|
|
26423
26506
|
projectId: this.options.projectId,
|
|
26424
26507
|
agent: {
|
|
26425
|
-
version:
|
|
26508
|
+
version: getPackageVersion(),
|
|
26426
26509
|
hostname: os7.hostname(),
|
|
26427
26510
|
platform: `${os7.platform()} ${os7.arch()}`
|
|
26428
26511
|
}
|
|
@@ -26684,7 +26767,7 @@ Access-Control-Allow-Origin: *\r
|
|
|
26684
26767
|
const projectDir = this.options.projectDir;
|
|
26685
26768
|
console.log(` [LocalServer] Running production build for project ${this.options.projectId}...`);
|
|
26686
26769
|
try {
|
|
26687
|
-
const hasBuildScript =
|
|
26770
|
+
const hasBuildScript = fs15.existsSync(path14.join(projectDir, "script", "build.ts"));
|
|
26688
26771
|
const buildCmd = hasBuildScript ? "npx tsx script/build.ts" : "npx vite build";
|
|
26689
26772
|
const buildResult = await new Promise((resolve) => {
|
|
26690
26773
|
const proc = spawn4("sh", ["-c", buildCmd], {
|
|
@@ -26708,32 +26791,32 @@ Access-Control-Allow-Origin: *\r
|
|
|
26708
26791
|
this.json(res, { success: false, error: errorMsg });
|
|
26709
26792
|
return;
|
|
26710
26793
|
}
|
|
26711
|
-
const distDir =
|
|
26712
|
-
if (!
|
|
26794
|
+
const distDir = path14.join(projectDir, "dist");
|
|
26795
|
+
if (!fs15.existsSync(distDir)) {
|
|
26713
26796
|
this.json(res, { success: false, error: "dist/ not found after build" });
|
|
26714
26797
|
return;
|
|
26715
26798
|
}
|
|
26716
26799
|
const files = {};
|
|
26717
26800
|
const collectFiles = (dir, prefix) => {
|
|
26718
|
-
const entries =
|
|
26801
|
+
const entries = fs15.readdirSync(dir, { withFileTypes: true });
|
|
26719
26802
|
for (const entry of entries) {
|
|
26720
|
-
const fullPath =
|
|
26803
|
+
const fullPath = path14.join(dir, entry.name);
|
|
26721
26804
|
const relPath = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
26722
26805
|
if (entry.isDirectory()) {
|
|
26723
26806
|
collectFiles(fullPath, relPath);
|
|
26724
26807
|
} else {
|
|
26725
|
-
const ext =
|
|
26808
|
+
const ext = path14.extname(entry.name).toLowerCase();
|
|
26726
26809
|
const isBinary = [".png", ".jpg", ".jpeg", ".gif", ".webp", ".ico", ".woff", ".woff2", ".ttf", ".eot", ".mp3", ".mp4", ".ogg", ".wav"].includes(ext);
|
|
26727
26810
|
if (isBinary) {
|
|
26728
|
-
files[relPath] = "base64:" +
|
|
26811
|
+
files[relPath] = "base64:" + fs15.readFileSync(fullPath).toString("base64");
|
|
26729
26812
|
} else {
|
|
26730
|
-
files[relPath] =
|
|
26813
|
+
files[relPath] = fs15.readFileSync(fullPath, "utf-8");
|
|
26731
26814
|
}
|
|
26732
26815
|
}
|
|
26733
26816
|
}
|
|
26734
26817
|
};
|
|
26735
26818
|
collectFiles(distDir, "");
|
|
26736
|
-
const hasBackend =
|
|
26819
|
+
const hasBackend = fs15.existsSync(path14.join(projectDir, "server", "index.ts")) || fs15.existsSync(path14.join(projectDir, "server", "index.js"));
|
|
26737
26820
|
console.log(` [LocalServer] Build completed: ${Object.keys(files).length} files (backend=${hasBackend})`);
|
|
26738
26821
|
this.json(res, {
|
|
26739
26822
|
success: true,
|
|
@@ -26834,6 +26917,47 @@ Access-Control-Allow-Origin: *\r
|
|
|
26834
26917
|
this.json(res, { success: false, error: error.message }, 500);
|
|
26835
26918
|
}
|
|
26836
26919
|
}
|
|
26920
|
+
// ─── /live/tree ──────────────────────────────────────────────
|
|
26921
|
+
async handleTree(_req, res) {
|
|
26922
|
+
try {
|
|
26923
|
+
const tree = await this.fileManager.getFileTree();
|
|
26924
|
+
this.json(res, tree);
|
|
26925
|
+
} catch (error) {
|
|
26926
|
+
this.json(res, { error: error.message }, 500);
|
|
26927
|
+
}
|
|
26928
|
+
}
|
|
26929
|
+
// ─── /live/file-content ──────────────────────────────────────
|
|
26930
|
+
async handleFileContent(_req, res, _body, url) {
|
|
26931
|
+
const filePath = url.searchParams.get("path");
|
|
26932
|
+
if (!filePath) {
|
|
26933
|
+
this.json(res, { error: "Missing path parameter" }, 400);
|
|
26934
|
+
return;
|
|
26935
|
+
}
|
|
26936
|
+
try {
|
|
26937
|
+
const content = await this.fileManager.readFile(filePath);
|
|
26938
|
+
if (content === null) {
|
|
26939
|
+
this.json(res, { error: "File not found" }, 404);
|
|
26940
|
+
return;
|
|
26941
|
+
}
|
|
26942
|
+
this.json(res, { content });
|
|
26943
|
+
} catch (error) {
|
|
26944
|
+
this.json(res, { error: error.message }, 500);
|
|
26945
|
+
}
|
|
26946
|
+
}
|
|
26947
|
+
// ─── /live/save-file ────────────────────────────────────────
|
|
26948
|
+
async handleSaveFile(_req, res, body) {
|
|
26949
|
+
try {
|
|
26950
|
+
const { filePath, content } = JSON.parse(body);
|
|
26951
|
+
if (!filePath || content === void 0) {
|
|
26952
|
+
this.json(res, { error: "filePath and content required" }, 400);
|
|
26953
|
+
return;
|
|
26954
|
+
}
|
|
26955
|
+
await this.fileManager.writeFiles({ [filePath]: content });
|
|
26956
|
+
this.json(res, { success: true, message: "File saved" });
|
|
26957
|
+
} catch (error) {
|
|
26958
|
+
this.json(res, { error: error.message }, 500);
|
|
26959
|
+
}
|
|
26960
|
+
}
|
|
26837
26961
|
// ─── /health ─────────────────────────────────────────────────
|
|
26838
26962
|
async handleHealth(_req, res) {
|
|
26839
26963
|
this.json(res, {
|
|
@@ -27118,7 +27242,7 @@ var TunnelClient = class {
|
|
|
27118
27242
|
this.emitStatus("connected");
|
|
27119
27243
|
this.send({
|
|
27120
27244
|
type: "agent-info",
|
|
27121
|
-
version:
|
|
27245
|
+
version: getPackageVersion(),
|
|
27122
27246
|
hostname: os8.hostname(),
|
|
27123
27247
|
platform: `${os8.platform()} ${os8.arch()}`,
|
|
27124
27248
|
deviceId: getDeviceId(),
|
|
@@ -27563,11 +27687,21 @@ var TunnelClient = class {
|
|
|
27563
27687
|
|
|
27564
27688
|
// dist/statusServer.js
|
|
27565
27689
|
import http5 from "http";
|
|
27566
|
-
import
|
|
27567
|
-
import
|
|
27690
|
+
import fs16 from "fs";
|
|
27691
|
+
import path15 from "path";
|
|
27568
27692
|
import os9 from "os";
|
|
27693
|
+
import { spawn as spawn5 } from "child_process";
|
|
27694
|
+
import { createRequire as createRequire2 } from "module";
|
|
27569
27695
|
var STATUS_PORT = 18999;
|
|
27570
|
-
var STATUS_FILE =
|
|
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;
|
|
27571
27705
|
var StatusServer = class {
|
|
27572
27706
|
server = null;
|
|
27573
27707
|
getStatus;
|
|
@@ -27582,7 +27716,8 @@ var StatusServer = class {
|
|
|
27582
27716
|
return new Promise((resolve, reject) => {
|
|
27583
27717
|
this.server = http5.createServer((req, res) => {
|
|
27584
27718
|
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
27585
|
-
res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
|
|
27719
|
+
res.setHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, OPTIONS");
|
|
27720
|
+
res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, x-project-id");
|
|
27586
27721
|
res.setHeader("Content-Type", "application/json");
|
|
27587
27722
|
if (req.method === "OPTIONS") {
|
|
27588
27723
|
res.writeHead(204);
|
|
@@ -27642,9 +27777,549 @@ var StatusServer = class {
|
|
|
27642
27777
|
});
|
|
27643
27778
|
return;
|
|
27644
27779
|
}
|
|
27780
|
+
const parsedUrl = new URL(req.url || "/", `http://localhost:${STATUS_PORT}`);
|
|
27781
|
+
if (req.method === "GET" && url === "/browse/tree") {
|
|
27782
|
+
const dir = parsedUrl.searchParams.get("dir");
|
|
27783
|
+
if (!dir || !fs16.existsSync(dir)) {
|
|
27784
|
+
res.writeHead(400);
|
|
27785
|
+
res.end(JSON.stringify({ error: "Missing or invalid dir parameter" }));
|
|
27786
|
+
return;
|
|
27787
|
+
}
|
|
27788
|
+
try {
|
|
27789
|
+
const tree = buildFileTree(dir, path15.basename(dir));
|
|
27790
|
+
res.writeHead(200);
|
|
27791
|
+
res.end(JSON.stringify(tree));
|
|
27792
|
+
} catch (err) {
|
|
27793
|
+
res.writeHead(500);
|
|
27794
|
+
res.end(JSON.stringify({ error: err.message }));
|
|
27795
|
+
}
|
|
27796
|
+
return;
|
|
27797
|
+
}
|
|
27798
|
+
if (req.method === "GET" && url === "/browse/file") {
|
|
27799
|
+
const dir = parsedUrl.searchParams.get("dir");
|
|
27800
|
+
const filePath = parsedUrl.searchParams.get("path");
|
|
27801
|
+
if (!dir || !filePath) {
|
|
27802
|
+
res.writeHead(400);
|
|
27803
|
+
res.end(JSON.stringify({ error: "dir and path parameters required" }));
|
|
27804
|
+
return;
|
|
27805
|
+
}
|
|
27806
|
+
const fullPath = path15.resolve(dir, filePath);
|
|
27807
|
+
if (!fullPath.startsWith(path15.resolve(dir))) {
|
|
27808
|
+
res.writeHead(403);
|
|
27809
|
+
res.end(JSON.stringify({ error: "Path traversal not allowed" }));
|
|
27810
|
+
return;
|
|
27811
|
+
}
|
|
27812
|
+
try {
|
|
27813
|
+
if (!fs16.existsSync(fullPath)) {
|
|
27814
|
+
res.writeHead(404);
|
|
27815
|
+
res.end(JSON.stringify({ error: "File not found" }));
|
|
27816
|
+
return;
|
|
27817
|
+
}
|
|
27818
|
+
const content = fs16.readFileSync(fullPath, "utf-8");
|
|
27819
|
+
res.writeHead(200);
|
|
27820
|
+
res.end(JSON.stringify({ content }));
|
|
27821
|
+
} catch (err) {
|
|
27822
|
+
res.writeHead(500);
|
|
27823
|
+
res.end(JSON.stringify({ error: err.message }));
|
|
27824
|
+
}
|
|
27825
|
+
return;
|
|
27826
|
+
}
|
|
27827
|
+
if (req.method === "POST" && url === "/browse/save") {
|
|
27828
|
+
let body = "";
|
|
27829
|
+
req.on("data", (chunk) => {
|
|
27830
|
+
body += chunk.toString();
|
|
27831
|
+
});
|
|
27832
|
+
req.on("end", () => {
|
|
27833
|
+
try {
|
|
27834
|
+
const { dir, filePath, content } = JSON.parse(body);
|
|
27835
|
+
if (!dir || !filePath || content === void 0) {
|
|
27836
|
+
res.writeHead(400);
|
|
27837
|
+
res.end(JSON.stringify({ error: "dir, filePath, and content required" }));
|
|
27838
|
+
return;
|
|
27839
|
+
}
|
|
27840
|
+
const fullPath = path15.resolve(dir, filePath);
|
|
27841
|
+
if (!fullPath.startsWith(path15.resolve(dir))) {
|
|
27842
|
+
res.writeHead(403);
|
|
27843
|
+
res.end(JSON.stringify({ error: "Path traversal not allowed" }));
|
|
27844
|
+
return;
|
|
27845
|
+
}
|
|
27846
|
+
const parentDir = path15.dirname(fullPath);
|
|
27847
|
+
if (!fs16.existsSync(parentDir))
|
|
27848
|
+
fs16.mkdirSync(parentDir, { recursive: true });
|
|
27849
|
+
fs16.writeFileSync(fullPath, content, "utf-8");
|
|
27850
|
+
res.writeHead(200);
|
|
27851
|
+
res.end(JSON.stringify({ success: true }));
|
|
27852
|
+
} catch (err) {
|
|
27853
|
+
res.writeHead(500);
|
|
27854
|
+
res.end(JSON.stringify({ error: err.message }));
|
|
27855
|
+
}
|
|
27856
|
+
});
|
|
27857
|
+
return;
|
|
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
|
+
}
|
|
27645
28255
|
res.writeHead(404);
|
|
27646
28256
|
res.end(JSON.stringify({ error: "Not found" }));
|
|
27647
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
|
+
});
|
|
27648
28323
|
this.server.on("error", (err) => {
|
|
27649
28324
|
if (err.code === "EADDRINUSE") {
|
|
27650
28325
|
console.log(` [Status] Port ${STATUS_PORT} in use \u2014 status server skipped`);
|
|
@@ -27653,7 +28328,7 @@ var StatusServer = class {
|
|
|
27653
28328
|
}
|
|
27654
28329
|
reject(err);
|
|
27655
28330
|
});
|
|
27656
|
-
this.server.listen(STATUS_PORT,
|
|
28331
|
+
this.server.listen(STATUS_PORT, () => {
|
|
27657
28332
|
this.writeStatusFile();
|
|
27658
28333
|
resolve();
|
|
27659
28334
|
});
|
|
@@ -27665,25 +28340,134 @@ var StatusServer = class {
|
|
|
27665
28340
|
this.server = null;
|
|
27666
28341
|
}
|
|
27667
28342
|
try {
|
|
27668
|
-
if (
|
|
27669
|
-
|
|
28343
|
+
if (fs16.existsSync(STATUS_FILE))
|
|
28344
|
+
fs16.unlinkSync(STATUS_FILE);
|
|
27670
28345
|
} catch {
|
|
27671
28346
|
}
|
|
27672
28347
|
}
|
|
27673
28348
|
writeStatusFile() {
|
|
27674
|
-
const dir =
|
|
27675
|
-
if (!
|
|
27676
|
-
|
|
27677
|
-
|
|
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({
|
|
27678
28353
|
port: STATUS_PORT,
|
|
27679
28354
|
pid: process.pid,
|
|
27680
28355
|
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
27681
28356
|
}, null, 2), "utf-8");
|
|
27682
28357
|
}
|
|
27683
28358
|
};
|
|
28359
|
+
var SKIP_DIRS2 = /* @__PURE__ */ new Set([
|
|
28360
|
+
"node_modules",
|
|
28361
|
+
"dist",
|
|
28362
|
+
".git",
|
|
28363
|
+
".vite-cache",
|
|
28364
|
+
".next",
|
|
28365
|
+
"__pycache__",
|
|
28366
|
+
".turbo",
|
|
28367
|
+
".cache",
|
|
28368
|
+
"build",
|
|
28369
|
+
".svelte-kit"
|
|
28370
|
+
]);
|
|
28371
|
+
function buildFileTree(dirPath, name, relativePath = "") {
|
|
28372
|
+
const node = { name, path: relativePath, isDirectory: true, children: [] };
|
|
28373
|
+
let entries;
|
|
28374
|
+
try {
|
|
28375
|
+
entries = fs16.readdirSync(dirPath, { withFileTypes: true });
|
|
28376
|
+
} catch {
|
|
28377
|
+
return node;
|
|
28378
|
+
}
|
|
28379
|
+
const dirs = [];
|
|
28380
|
+
const files = [];
|
|
28381
|
+
for (const entry of entries) {
|
|
28382
|
+
if (entry.name.startsWith(".") && entry.name !== ".env")
|
|
28383
|
+
continue;
|
|
28384
|
+
const childRelative = relativePath ? `${relativePath}/${entry.name}` : entry.name;
|
|
28385
|
+
if (entry.isDirectory()) {
|
|
28386
|
+
if (SKIP_DIRS2.has(entry.name))
|
|
28387
|
+
continue;
|
|
28388
|
+
dirs.push(buildFileTree(path15.join(dirPath, entry.name), entry.name, childRelative));
|
|
28389
|
+
} else {
|
|
28390
|
+
files.push({ name: entry.name, path: childRelative, isDirectory: false, children: [] });
|
|
28391
|
+
}
|
|
28392
|
+
}
|
|
28393
|
+
dirs.sort((a, b) => a.name.localeCompare(b.name));
|
|
28394
|
+
files.sort((a, b) => a.name.localeCompare(b.name));
|
|
28395
|
+
node.children = [...dirs, ...files];
|
|
28396
|
+
return node;
|
|
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
|
+
}
|
|
27684
28468
|
|
|
27685
28469
|
// dist/commands/start.js
|
|
27686
|
-
var VERSION =
|
|
28470
|
+
var VERSION = getPackageVersion();
|
|
27687
28471
|
function resolveBackendUrl(options) {
|
|
27688
28472
|
if (options.backend)
|
|
27689
28473
|
return options.backend.replace(/\/$/, "");
|
|
@@ -27692,10 +28476,10 @@ function resolveBackendUrl(options) {
|
|
|
27692
28476
|
}
|
|
27693
28477
|
function resolveProjectDir(directory, projectId, customDir) {
|
|
27694
28478
|
if (customDir)
|
|
27695
|
-
return
|
|
28479
|
+
return path16.resolve(customDir);
|
|
27696
28480
|
if (directory !== ".")
|
|
27697
|
-
return
|
|
27698
|
-
const defaultBase =
|
|
28481
|
+
return path16.resolve(directory);
|
|
28482
|
+
const defaultBase = path16.join(os10.homedir(), ".nstantpage", "projects", projectId);
|
|
27699
28483
|
return defaultBase;
|
|
27700
28484
|
}
|
|
27701
28485
|
async function fetchProjectFiles(backendUrl, projectId, projectDir, token) {
|
|
@@ -27715,20 +28499,20 @@ async function fetchProjectFiles(backendUrl, projectId, projectDir, token) {
|
|
|
27715
28499
|
if (!data.files || data.files.length === 0) {
|
|
27716
28500
|
throw new Error("No files returned from backend. Is the project ID correct?");
|
|
27717
28501
|
}
|
|
27718
|
-
const versionFile =
|
|
27719
|
-
const existingVersion =
|
|
28502
|
+
const versionFile = path16.join(projectDir, ".nstantpage-version");
|
|
28503
|
+
const existingVersion = fs17.existsSync(versionFile) ? fs17.readFileSync(versionFile, "utf-8").trim() : null;
|
|
27720
28504
|
if (existingVersion === String(data.versionId)) {
|
|
27721
28505
|
console.log(source_default.gray(` Files up-to-date (version ${data.version})`));
|
|
27722
28506
|
return { fileCount: data.files.length, isNew: false, versionId: String(data.versionId) };
|
|
27723
28507
|
}
|
|
27724
28508
|
const dirsToCreate = /* @__PURE__ */ new Set();
|
|
27725
28509
|
for (const file of data.files) {
|
|
27726
|
-
const filePath =
|
|
27727
|
-
dirsToCreate.add(
|
|
28510
|
+
const filePath = path16.join(projectDir, file.path);
|
|
28511
|
+
dirsToCreate.add(path16.dirname(filePath));
|
|
27728
28512
|
}
|
|
27729
28513
|
for (const dir of dirsToCreate) {
|
|
27730
|
-
if (!
|
|
27731
|
-
|
|
28514
|
+
if (!fs17.existsSync(dir)) {
|
|
28515
|
+
fs17.mkdirSync(dir, { recursive: true });
|
|
27732
28516
|
}
|
|
27733
28517
|
}
|
|
27734
28518
|
const BATCH_SIZE = 50;
|
|
@@ -27736,12 +28520,12 @@ async function fetchProjectFiles(backendUrl, projectId, projectDir, token) {
|
|
|
27736
28520
|
for (let i = 0; i < data.files.length; i += BATCH_SIZE) {
|
|
27737
28521
|
const batch = data.files.slice(i, i + BATCH_SIZE);
|
|
27738
28522
|
await Promise.all(batch.map(async (file) => {
|
|
27739
|
-
const filePath =
|
|
27740
|
-
await
|
|
28523
|
+
const filePath = path16.join(projectDir, file.path);
|
|
28524
|
+
await fs17.promises.writeFile(filePath, file.content, "utf-8");
|
|
27741
28525
|
}));
|
|
27742
28526
|
written += batch.length;
|
|
27743
28527
|
}
|
|
27744
|
-
|
|
28528
|
+
fs17.writeFileSync(versionFile, String(data.versionId), "utf-8");
|
|
27745
28529
|
console.log(source_default.green(` \u2713 ${written} files downloaded (version ${data.version})`));
|
|
27746
28530
|
return { fileCount: written, isNew: true, versionId: String(data.versionId) };
|
|
27747
28531
|
}
|
|
@@ -27786,6 +28570,11 @@ function cleanupPreviousAgent(projectId, apiPort, devPort) {
|
|
|
27786
28570
|
killPort(apiPort);
|
|
27787
28571
|
if (devPort !== oldDevPort)
|
|
27788
28572
|
killPort(devPort);
|
|
28573
|
+
const backendPort = devPort + 1001;
|
|
28574
|
+
killPort(backendPort);
|
|
28575
|
+
const oldBackendPort = oldDevPort ? oldDevPort + 1001 : 0;
|
|
28576
|
+
if (oldBackendPort && oldBackendPort !== backendPort)
|
|
28577
|
+
killPort(oldBackendPort);
|
|
27789
28578
|
clearProjectConfig(projectId);
|
|
27790
28579
|
}
|
|
27791
28580
|
async function startCommand(directory, options) {
|
|
@@ -27840,8 +28629,8 @@ async function startCommand(directory, options) {
|
|
|
27840
28629
|
apiPort = allocated.apiPort;
|
|
27841
28630
|
}
|
|
27842
28631
|
const projectDir = resolveProjectDir(directory, projectId, options.dir);
|
|
27843
|
-
if (!
|
|
27844
|
-
|
|
28632
|
+
if (!fs17.existsSync(projectDir)) {
|
|
28633
|
+
fs17.mkdirSync(projectDir, { recursive: true });
|
|
27845
28634
|
}
|
|
27846
28635
|
conf.set("projectId", projectId);
|
|
27847
28636
|
cleanupPreviousAgent(projectId, apiPort, devPort);
|
|
@@ -27863,7 +28652,7 @@ async function startCommand(directory, options) {
|
|
|
27863
28652
|
const { fileCount, isNew, versionId } = await fetchProjectFiles(backendUrl, projectId, projectDir, token);
|
|
27864
28653
|
fetchedVersionId = versionId;
|
|
27865
28654
|
if (!installer.areDependenciesInstalled()) {
|
|
27866
|
-
if (
|
|
28655
|
+
if (fs17.existsSync(path16.join(projectDir, "package.json"))) {
|
|
27867
28656
|
console.log(source_default.gray(" Installing dependencies..."));
|
|
27868
28657
|
try {
|
|
27869
28658
|
await installer.ensureDependencies();
|
|
@@ -27879,16 +28668,16 @@ async function startCommand(directory, options) {
|
|
|
27879
28668
|
} catch (err) {
|
|
27880
28669
|
console.log(source_default.yellow(` \u26A0 Could not fetch project files: ${err.message}`));
|
|
27881
28670
|
console.log(source_default.gray(" Continuing with existing local files (if any)..."));
|
|
27882
|
-
if (!
|
|
28671
|
+
if (!fs17.existsSync(path16.join(projectDir, "package.json"))) {
|
|
27883
28672
|
console.log(source_default.red(`
|
|
27884
28673
|
\u2717 No package.json found and cannot fetch files from backend.`));
|
|
27885
28674
|
console.log(source_default.gray(" Check your project ID and authentication."));
|
|
27886
28675
|
process.exit(1);
|
|
27887
28676
|
}
|
|
27888
28677
|
}
|
|
27889
|
-
const localConfigPath =
|
|
27890
|
-
if (!
|
|
27891
|
-
|
|
28678
|
+
const localConfigPath = path16.join(projectDir, ".nstantpage.json");
|
|
28679
|
+
if (!fs17.existsSync(localConfigPath)) {
|
|
28680
|
+
fs17.writeFileSync(localConfigPath, JSON.stringify({ projectId }, null, 2), "utf-8");
|
|
27892
28681
|
}
|
|
27893
28682
|
let databaseUrl = null;
|
|
27894
28683
|
try {
|
|
@@ -28112,9 +28901,9 @@ async function startStandbyMode(token, options, backendUrl, deviceId) {
|
|
|
28112
28901
|
await existing.localServer.stop();
|
|
28113
28902
|
activeProjects.delete(pid);
|
|
28114
28903
|
const projectDir = resolveProjectDir(".", pid);
|
|
28115
|
-
if (
|
|
28904
|
+
if (fs17.existsSync(projectDir)) {
|
|
28116
28905
|
console.log(source_default.gray(` Wiping project directory: ${projectDir}`));
|
|
28117
|
-
|
|
28906
|
+
fs17.rmSync(projectDir, { recursive: true, force: true });
|
|
28118
28907
|
}
|
|
28119
28908
|
} else if (activeProjects.has(pid)) {
|
|
28120
28909
|
console.log(source_default.yellow(` Project ${pid} is already running`));
|
|
@@ -28277,8 +29066,8 @@ async function startAdditionalProject(projectId, opts) {
|
|
|
28277
29066
|
try {
|
|
28278
29067
|
const allocated = allocatePortsForProject(projectId);
|
|
28279
29068
|
const projectDir = resolveProjectDir(".", projectId);
|
|
28280
|
-
if (!
|
|
28281
|
-
|
|
29069
|
+
if (!fs17.existsSync(projectDir))
|
|
29070
|
+
fs17.mkdirSync(projectDir, { recursive: true });
|
|
28282
29071
|
cleanupPreviousAgent(projectId, allocated.apiPort, allocated.devPort);
|
|
28283
29072
|
await new Promise((r) => setTimeout(r, 50));
|
|
28284
29073
|
progress("fetching-files", "Fetching project files...");
|
|
@@ -28351,7 +29140,7 @@ async function startAdditionalProject(projectId, opts) {
|
|
|
28351
29140
|
localServer.markSynced(fetchedVersionId);
|
|
28352
29141
|
}
|
|
28353
29142
|
const installer = new PackageInstaller({ projectDir });
|
|
28354
|
-
const needsInstall = !installer.areDependenciesInstalled() &&
|
|
29143
|
+
const needsInstall = !installer.areDependenciesInstalled() && fs17.existsSync(path16.join(projectDir, "package.json"));
|
|
28355
29144
|
if (needsInstall) {
|
|
28356
29145
|
const installStart = Date.now();
|
|
28357
29146
|
console.log(source_default.gray(` Installing dependencies...`));
|
|
@@ -28462,13 +29251,13 @@ async function statusCommand() {
|
|
|
28462
29251
|
|
|
28463
29252
|
// dist/commands/service.js
|
|
28464
29253
|
init_config();
|
|
28465
|
-
import
|
|
28466
|
-
import
|
|
29254
|
+
import fs18 from "fs";
|
|
29255
|
+
import path17 from "path";
|
|
28467
29256
|
import os11 from "os";
|
|
28468
29257
|
import { execSync as execSync3 } from "child_process";
|
|
28469
|
-
import { fileURLToPath as
|
|
28470
|
-
var
|
|
28471
|
-
var
|
|
29258
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
29259
|
+
var __filename_esm2 = fileURLToPath3(import.meta.url);
|
|
29260
|
+
var __dirname_esm2 = path17.dirname(__filename_esm2);
|
|
28472
29261
|
var PLIST_LABEL = "com.nstantpage.agent";
|
|
28473
29262
|
var SYSTEMD_SERVICE = "nstantpage-agent";
|
|
28474
29263
|
var WIN_TASK_NAME = "NstantpageAgent";
|
|
@@ -28495,8 +29284,8 @@ async function serviceStopCommand() {
|
|
|
28495
29284
|
const platform2 = os11.platform();
|
|
28496
29285
|
let stopped = false;
|
|
28497
29286
|
if (platform2 === "darwin") {
|
|
28498
|
-
const plistPath =
|
|
28499
|
-
if (
|
|
29287
|
+
const plistPath = path17.join(os11.homedir(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
|
|
29288
|
+
if (fs18.existsSync(plistPath)) {
|
|
28500
29289
|
try {
|
|
28501
29290
|
execSync3(`launchctl unload "${plistPath}" 2>/dev/null`, { encoding: "utf-8" });
|
|
28502
29291
|
console.log(source_default.green(" \u2713 Background service stopped"));
|
|
@@ -28557,7 +29346,7 @@ async function serviceInstallCommand(options = {}) {
|
|
|
28557
29346
|
return;
|
|
28558
29347
|
}
|
|
28559
29348
|
if (electronAppPath === null) {
|
|
28560
|
-
console.log(source_default.gray(
|
|
29349
|
+
console.log(source_default.gray(' Tip: Run "nstantpage update --desktop" to download the desktop app with tray icon.'));
|
|
28561
29350
|
}
|
|
28562
29351
|
if (platform2 === "darwin") {
|
|
28563
29352
|
await installLaunchd(gateway, token);
|
|
@@ -28624,12 +29413,12 @@ async function serviceStatusCommand() {
|
|
|
28624
29413
|
} else {
|
|
28625
29414
|
console.log(source_default.gray(" Service status not available on this platform"));
|
|
28626
29415
|
}
|
|
28627
|
-
const logPath =
|
|
28628
|
-
if (
|
|
28629
|
-
const stats =
|
|
29416
|
+
const logPath = path17.join(os11.homedir(), ".nstantpage", "agent.log");
|
|
29417
|
+
if (fs18.existsSync(logPath)) {
|
|
29418
|
+
const stats = fs18.statSync(logPath);
|
|
28630
29419
|
console.log(source_default.gray(` Log file: ${logPath} (${(stats.size / 1024).toFixed(1)}KB)`));
|
|
28631
29420
|
try {
|
|
28632
|
-
const content =
|
|
29421
|
+
const content = fs18.readFileSync(logPath, "utf-8");
|
|
28633
29422
|
const lines = content.trim().split("\n").slice(-5);
|
|
28634
29423
|
if (lines.length > 0) {
|
|
28635
29424
|
console.log(source_default.gray(" Last log lines:"));
|
|
@@ -28643,35 +29432,39 @@ function findElectronApp() {
|
|
|
28643
29432
|
const platform2 = os11.platform();
|
|
28644
29433
|
if (platform2 === "darwin") {
|
|
28645
29434
|
const candidates = [
|
|
29435
|
+
// Downloaded by postinstall (npm i -g nstantpage-agent)
|
|
29436
|
+
path17.join(os11.homedir(), ".nstantpage", "desktop", "nstantpage.app"),
|
|
28646
29437
|
"/Applications/nstantpage.app",
|
|
28647
|
-
|
|
29438
|
+
path17.join(os11.homedir(), "Applications", "nstantpage.app"),
|
|
28648
29439
|
// Dev build location (from electron-builder --dir)
|
|
28649
|
-
|
|
28650
|
-
|
|
29440
|
+
path17.join(__dirname_esm2, "..", "..", "tray", "dist", "mac-arm64", "nstantpage.app"),
|
|
29441
|
+
path17.join(__dirname_esm2, "..", "..", "tray", "dist", "mac", "nstantpage.app")
|
|
28651
29442
|
];
|
|
28652
29443
|
for (const p of candidates) {
|
|
28653
|
-
if (
|
|
29444
|
+
if (fs18.existsSync(p))
|
|
28654
29445
|
return p;
|
|
28655
29446
|
}
|
|
28656
29447
|
} else if (platform2 === "win32") {
|
|
28657
29448
|
const candidates = [
|
|
28658
|
-
|
|
28659
|
-
|
|
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")
|
|
28660
29453
|
];
|
|
28661
29454
|
for (const p of candidates) {
|
|
28662
|
-
if (
|
|
29455
|
+
if (fs18.existsSync(p))
|
|
28663
29456
|
return p;
|
|
28664
29457
|
}
|
|
28665
29458
|
}
|
|
28666
29459
|
return null;
|
|
28667
29460
|
}
|
|
28668
29461
|
async function installElectronLaunchd(appPath) {
|
|
28669
|
-
const plistDir =
|
|
28670
|
-
const plistPath =
|
|
28671
|
-
const logPath =
|
|
28672
|
-
const errPath =
|
|
28673
|
-
|
|
28674
|
-
|
|
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 });
|
|
28675
29468
|
const plist = `<?xml version="1.0" encoding="UTF-8"?>
|
|
28676
29469
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
28677
29470
|
<plist version="1.0">
|
|
@@ -28706,7 +29499,7 @@ async function installElectronLaunchd(appPath) {
|
|
|
28706
29499
|
<integer>10</integer>
|
|
28707
29500
|
</dict>
|
|
28708
29501
|
</plist>`;
|
|
28709
|
-
|
|
29502
|
+
fs18.writeFileSync(plistPath, plist, "utf-8");
|
|
28710
29503
|
try {
|
|
28711
29504
|
execSync3(`launchctl unload "${plistPath}" 2>/dev/null`, { encoding: "utf-8" });
|
|
28712
29505
|
} catch {
|
|
@@ -28723,8 +29516,8 @@ async function installElectronLaunchd(appPath) {
|
|
|
28723
29516
|
console.log(source_default.blue(" Right-click the tray icon for options. Open nstantpage.com to connect projects.\n"));
|
|
28724
29517
|
}
|
|
28725
29518
|
async function installElectronWindowsTask(appPath) {
|
|
28726
|
-
const logPath =
|
|
28727
|
-
|
|
29519
|
+
const logPath = path17.join(os11.homedir(), ".nstantpage", "agent.log");
|
|
29520
|
+
fs18.mkdirSync(path17.dirname(logPath), { recursive: true });
|
|
28728
29521
|
try {
|
|
28729
29522
|
execSync3(`schtasks /delete /tn "${WIN_TASK_NAME}" /f 2>nul`, { encoding: "utf-8" });
|
|
28730
29523
|
} catch {
|
|
@@ -28753,8 +29546,8 @@ function getAgentBinPath() {
|
|
|
28753
29546
|
}
|
|
28754
29547
|
try {
|
|
28755
29548
|
const npmRoot = execSync3("npm root -g", { encoding: "utf-8" }).trim();
|
|
28756
|
-
const bin =
|
|
28757
|
-
if (
|
|
29549
|
+
const bin = path17.join(npmRoot, ".bin", "nstantpage");
|
|
29550
|
+
if (fs18.existsSync(bin))
|
|
28758
29551
|
return bin;
|
|
28759
29552
|
} catch {
|
|
28760
29553
|
}
|
|
@@ -28770,12 +29563,12 @@ function getNodePath() {
|
|
|
28770
29563
|
async function installLaunchd(gateway, token) {
|
|
28771
29564
|
const binPath = getAgentBinPath();
|
|
28772
29565
|
const nodePath = getNodePath();
|
|
28773
|
-
const plistDir =
|
|
28774
|
-
const plistPath =
|
|
28775
|
-
const logPath =
|
|
28776
|
-
const errPath =
|
|
28777
|
-
|
|
28778
|
-
|
|
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 });
|
|
28779
29572
|
const plist = `<?xml version="1.0" encoding="UTF-8"?>
|
|
28780
29573
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
28781
29574
|
<plist version="1.0">
|
|
@@ -28815,7 +29608,7 @@ async function installLaunchd(gateway, token) {
|
|
|
28815
29608
|
<integer>-5</integer>
|
|
28816
29609
|
</dict>
|
|
28817
29610
|
</plist>`;
|
|
28818
|
-
|
|
29611
|
+
fs18.writeFileSync(plistPath, plist, "utf-8");
|
|
28819
29612
|
try {
|
|
28820
29613
|
execSync3(`launchctl unload "${plistPath}" 2>/dev/null`, { encoding: "utf-8" });
|
|
28821
29614
|
} catch {
|
|
@@ -28831,8 +29624,8 @@ async function installLaunchd(gateway, token) {
|
|
|
28831
29624
|
console.log(source_default.blue(' Open any project on nstantpage.com and click "Connect" to use it.\n'));
|
|
28832
29625
|
}
|
|
28833
29626
|
async function uninstallLaunchd() {
|
|
28834
|
-
const plistPath =
|
|
28835
|
-
if (!
|
|
29627
|
+
const plistPath = path17.join(os11.homedir(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
|
|
29628
|
+
if (!fs18.existsSync(plistPath)) {
|
|
28836
29629
|
console.log(source_default.yellow(" \u26A0 Service is not installed"));
|
|
28837
29630
|
return;
|
|
28838
29631
|
}
|
|
@@ -28840,15 +29633,15 @@ async function uninstallLaunchd() {
|
|
|
28840
29633
|
execSync3(`launchctl unload "${plistPath}" 2>/dev/null`, { encoding: "utf-8" });
|
|
28841
29634
|
} catch {
|
|
28842
29635
|
}
|
|
28843
|
-
|
|
29636
|
+
fs18.unlinkSync(plistPath);
|
|
28844
29637
|
console.log(source_default.green(" \u2713 Agent service uninstalled (launchd)"));
|
|
28845
29638
|
console.log(source_default.gray(" The agent will no longer start automatically."));
|
|
28846
29639
|
}
|
|
28847
29640
|
async function installSystemd(gateway, token) {
|
|
28848
29641
|
const binPath = getAgentBinPath();
|
|
28849
|
-
const serviceDir =
|
|
28850
|
-
const servicePath =
|
|
28851
|
-
|
|
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 });
|
|
28852
29645
|
const unit = `[Unit]
|
|
28853
29646
|
Description=nstantpage Local Development Agent
|
|
28854
29647
|
After=network-online.target
|
|
@@ -28865,7 +29658,7 @@ Environment=HOME=${os11.homedir()}
|
|
|
28865
29658
|
[Install]
|
|
28866
29659
|
WantedBy=default.target
|
|
28867
29660
|
`;
|
|
28868
|
-
|
|
29661
|
+
fs18.writeFileSync(servicePath, unit, "utf-8");
|
|
28869
29662
|
try {
|
|
28870
29663
|
execSync3("systemctl --user daemon-reload", { encoding: "utf-8" });
|
|
28871
29664
|
execSync3(`systemctl --user enable ${SYSTEMD_SERVICE}`, { encoding: "utf-8" });
|
|
@@ -28884,8 +29677,8 @@ WantedBy=default.target
|
|
|
28884
29677
|
console.log(source_default.blue(' Open any project on nstantpage.com and click "Connect" to use it.\n'));
|
|
28885
29678
|
}
|
|
28886
29679
|
async function uninstallSystemd() {
|
|
28887
|
-
const servicePath =
|
|
28888
|
-
if (!
|
|
29680
|
+
const servicePath = path17.join(os11.homedir(), ".config", "systemd", "user", `${SYSTEMD_SERVICE}.service`);
|
|
29681
|
+
if (!fs18.existsSync(servicePath)) {
|
|
28889
29682
|
console.log(source_default.yellow(" \u26A0 Service is not installed"));
|
|
28890
29683
|
return;
|
|
28891
29684
|
}
|
|
@@ -28894,7 +29687,7 @@ async function uninstallSystemd() {
|
|
|
28894
29687
|
execSync3(`systemctl --user disable ${SYSTEMD_SERVICE} 2>/dev/null`, { encoding: "utf-8" });
|
|
28895
29688
|
} catch {
|
|
28896
29689
|
}
|
|
28897
|
-
|
|
29690
|
+
fs18.unlinkSync(servicePath);
|
|
28898
29691
|
try {
|
|
28899
29692
|
execSync3("systemctl --user daemon-reload", { encoding: "utf-8" });
|
|
28900
29693
|
} catch {
|
|
@@ -28905,14 +29698,14 @@ async function uninstallSystemd() {
|
|
|
28905
29698
|
async function installWindowsTask(gateway, token) {
|
|
28906
29699
|
const binPath = getAgentBinPath();
|
|
28907
29700
|
const nodePath = getNodePath();
|
|
28908
|
-
const logPath =
|
|
28909
|
-
|
|
28910
|
-
const batchDir =
|
|
28911
|
-
const batchPath =
|
|
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");
|
|
28912
29705
|
const batchContent = `@echo off\r
|
|
28913
29706
|
"${nodePath}" "${binPath}" start --gateway ${gateway} --token ${token} >> "${logPath}" 2>&1\r
|
|
28914
29707
|
`;
|
|
28915
|
-
|
|
29708
|
+
fs18.writeFileSync(batchPath, batchContent, "utf-8");
|
|
28916
29709
|
try {
|
|
28917
29710
|
execSync3(`schtasks /delete /tn "${WIN_TASK_NAME}" /f 2>nul`, { encoding: "utf-8" });
|
|
28918
29711
|
} catch {
|
|
@@ -28942,21 +29735,148 @@ async function uninstallWindowsTask() {
|
|
|
28942
29735
|
} catch {
|
|
28943
29736
|
console.log(source_default.yellow(" \u26A0 Task is not installed or could not be removed"));
|
|
28944
29737
|
}
|
|
28945
|
-
const batchPath =
|
|
29738
|
+
const batchPath = path17.join(os11.homedir(), ".nstantpage", "agent-service.cmd");
|
|
28946
29739
|
try {
|
|
28947
|
-
if (
|
|
28948
|
-
|
|
29740
|
+
if (fs18.existsSync(batchPath))
|
|
29741
|
+
fs18.unlinkSync(batchPath);
|
|
28949
29742
|
} catch {
|
|
28950
29743
|
}
|
|
28951
29744
|
console.log(source_default.gray(" The agent will no longer start automatically."));
|
|
28952
29745
|
}
|
|
28953
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
|
+
|
|
28954
29873
|
// dist/cli.js
|
|
28955
29874
|
var program2 = new Command();
|
|
28956
|
-
program2.name("nstantpage").description("Local development agent for nstantpage.com \u2014 run projects on your machine, preview in the cloud").version(
|
|
29875
|
+
program2.name("nstantpage").description("Local development agent for nstantpage.com \u2014 run projects on your machine, preview in the cloud").version(getPackageVersion());
|
|
28957
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);
|
|
28958
29877
|
program2.command("logout").description("Sign out and clear stored credentials").action(logoutCommand);
|
|
28959
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);
|
|
28960
29880
|
program2.command("stop").description("Stop the running agent").action(async () => {
|
|
28961
29881
|
console.log(source_default.yellow("Stopping agent..."));
|
|
28962
29882
|
const { getConfig: getConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
@@ -28982,4 +29902,5 @@ service.command("stop").description("Stop the running agent").action(serviceStop
|
|
|
28982
29902
|
service.command("install").description("Install as a background service (auto-starts on boot)").option("--gateway <url>", "Gateway URL", "wss://webprev.live").action(serviceInstallCommand);
|
|
28983
29903
|
service.command("uninstall").description("Remove the background service").action(serviceUninstallCommand);
|
|
28984
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);
|
|
28985
29906
|
program2.parse();
|