@swmansion/argent 0.9.0 → 0.10.0
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/README.md +49 -9
- package/bin/argent-simulator-server.cjs +56 -0
- package/bin/{ax-service → darwin/ax-service} +0 -0
- package/bin/{simulator-server → darwin/simulator-server} +0 -0
- package/bin/linux/simulator-server +0 -0
- package/dist/argent-android-devtools-0.1.0.apk +0 -0
- package/dist/cli-cmds.mjs +2364 -76
- package/dist/cli.d.ts +6 -0
- package/dist/cli.js +23 -2
- package/dist/cli.js.map +1 -1
- package/dist/installer.mjs +232 -107
- package/dist/mcp-server.mjs +163 -51
- package/dist/tool-server.cjs +1491 -946
- package/dylibs/libArgentInjectionBootstrap.dylib +0 -0
- package/dylibs/libKeyboardPatch.dylib +0 -0
- package/dylibs/libNativeDevtoolsIos.dylib +0 -0
- package/package.json +2 -2
- package/skills/argent-android-emulator-setup/SKILL.md +1 -1
package/dist/cli-cmds.mjs
CHANGED
|
@@ -1,8 +1,161 @@
|
|
|
1
1
|
import { createRequire as __createRequire } from 'node:module'; const require = __createRequire(import.meta.url);
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
9
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
+
mod
|
|
26
|
+
));
|
|
27
|
+
|
|
28
|
+
// ../../node_modules/sisteransi/src/index.js
|
|
29
|
+
var require_src = __commonJS({
|
|
30
|
+
"../../node_modules/sisteransi/src/index.js"(exports, module) {
|
|
31
|
+
"use strict";
|
|
32
|
+
var ESC2 = "\x1B";
|
|
33
|
+
var CSI2 = `${ESC2}[`;
|
|
34
|
+
var beep = "\x07";
|
|
35
|
+
var cursor = {
|
|
36
|
+
to(x3, y) {
|
|
37
|
+
if (!y) return `${CSI2}${x3 + 1}G`;
|
|
38
|
+
return `${CSI2}${y + 1};${x3 + 1}H`;
|
|
39
|
+
},
|
|
40
|
+
move(x3, y) {
|
|
41
|
+
let ret = "";
|
|
42
|
+
if (x3 < 0) ret += `${CSI2}${-x3}D`;
|
|
43
|
+
else if (x3 > 0) ret += `${CSI2}${x3}C`;
|
|
44
|
+
if (y < 0) ret += `${CSI2}${-y}A`;
|
|
45
|
+
else if (y > 0) ret += `${CSI2}${y}B`;
|
|
46
|
+
return ret;
|
|
47
|
+
},
|
|
48
|
+
up: (count = 1) => `${CSI2}${count}A`,
|
|
49
|
+
down: (count = 1) => `${CSI2}${count}B`,
|
|
50
|
+
forward: (count = 1) => `${CSI2}${count}C`,
|
|
51
|
+
backward: (count = 1) => `${CSI2}${count}D`,
|
|
52
|
+
nextLine: (count = 1) => `${CSI2}E`.repeat(count),
|
|
53
|
+
prevLine: (count = 1) => `${CSI2}F`.repeat(count),
|
|
54
|
+
left: `${CSI2}G`,
|
|
55
|
+
hide: `${CSI2}?25l`,
|
|
56
|
+
show: `${CSI2}?25h`,
|
|
57
|
+
save: `${ESC2}7`,
|
|
58
|
+
restore: `${ESC2}8`
|
|
59
|
+
};
|
|
60
|
+
var scroll = {
|
|
61
|
+
up: (count = 1) => `${CSI2}S`.repeat(count),
|
|
62
|
+
down: (count = 1) => `${CSI2}T`.repeat(count)
|
|
63
|
+
};
|
|
64
|
+
var erase = {
|
|
65
|
+
screen: `${CSI2}2J`,
|
|
66
|
+
up: (count = 1) => `${CSI2}1J`.repeat(count),
|
|
67
|
+
down: (count = 1) => `${CSI2}J`.repeat(count),
|
|
68
|
+
line: `${CSI2}2K`,
|
|
69
|
+
lineEnd: `${CSI2}K`,
|
|
70
|
+
lineStart: `${CSI2}1K`,
|
|
71
|
+
lines(count) {
|
|
72
|
+
let clear = "";
|
|
73
|
+
for (let i = 0; i < count; i++)
|
|
74
|
+
clear += this.line + (i < count - 1 ? cursor.up() : "");
|
|
75
|
+
if (count)
|
|
76
|
+
clear += cursor.left;
|
|
77
|
+
return clear;
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
module.exports = { cursor, scroll, erase, beep };
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// ../../node_modules/picocolors/picocolors.js
|
|
85
|
+
var require_picocolors = __commonJS({
|
|
86
|
+
"../../node_modules/picocolors/picocolors.js"(exports, module) {
|
|
87
|
+
var p2 = process || {};
|
|
88
|
+
var argv = p2.argv || [];
|
|
89
|
+
var env = p2.env || {};
|
|
90
|
+
var isColorSupported = !(!!env.NO_COLOR || argv.includes("--no-color")) && (!!env.FORCE_COLOR || argv.includes("--color") || p2.platform === "win32" || (p2.stdout || {}).isTTY && env.TERM !== "dumb" || !!env.CI);
|
|
91
|
+
var formatter = (open, close, replace = open) => (input) => {
|
|
92
|
+
let string = "" + input, index = string.indexOf(close, open.length);
|
|
93
|
+
return ~index ? open + replaceClose(string, close, replace, index) + close : open + string + close;
|
|
94
|
+
};
|
|
95
|
+
var replaceClose = (string, close, replace, index) => {
|
|
96
|
+
let result = "", cursor = 0;
|
|
97
|
+
do {
|
|
98
|
+
result += string.substring(cursor, index) + replace;
|
|
99
|
+
cursor = index + close.length;
|
|
100
|
+
index = string.indexOf(close, cursor);
|
|
101
|
+
} while (~index);
|
|
102
|
+
return result + string.substring(cursor);
|
|
103
|
+
};
|
|
104
|
+
var createColors = (enabled = isColorSupported) => {
|
|
105
|
+
let f2 = enabled ? formatter : () => String;
|
|
106
|
+
return {
|
|
107
|
+
isColorSupported: enabled,
|
|
108
|
+
reset: f2("\x1B[0m", "\x1B[0m"),
|
|
109
|
+
bold: f2("\x1B[1m", "\x1B[22m", "\x1B[22m\x1B[1m"),
|
|
110
|
+
dim: f2("\x1B[2m", "\x1B[22m", "\x1B[22m\x1B[2m"),
|
|
111
|
+
italic: f2("\x1B[3m", "\x1B[23m"),
|
|
112
|
+
underline: f2("\x1B[4m", "\x1B[24m"),
|
|
113
|
+
inverse: f2("\x1B[7m", "\x1B[27m"),
|
|
114
|
+
hidden: f2("\x1B[8m", "\x1B[28m"),
|
|
115
|
+
strikethrough: f2("\x1B[9m", "\x1B[29m"),
|
|
116
|
+
black: f2("\x1B[30m", "\x1B[39m"),
|
|
117
|
+
red: f2("\x1B[31m", "\x1B[39m"),
|
|
118
|
+
green: f2("\x1B[32m", "\x1B[39m"),
|
|
119
|
+
yellow: f2("\x1B[33m", "\x1B[39m"),
|
|
120
|
+
blue: f2("\x1B[34m", "\x1B[39m"),
|
|
121
|
+
magenta: f2("\x1B[35m", "\x1B[39m"),
|
|
122
|
+
cyan: f2("\x1B[36m", "\x1B[39m"),
|
|
123
|
+
white: f2("\x1B[37m", "\x1B[39m"),
|
|
124
|
+
gray: f2("\x1B[90m", "\x1B[39m"),
|
|
125
|
+
bgBlack: f2("\x1B[40m", "\x1B[49m"),
|
|
126
|
+
bgRed: f2("\x1B[41m", "\x1B[49m"),
|
|
127
|
+
bgGreen: f2("\x1B[42m", "\x1B[49m"),
|
|
128
|
+
bgYellow: f2("\x1B[43m", "\x1B[49m"),
|
|
129
|
+
bgBlue: f2("\x1B[44m", "\x1B[49m"),
|
|
130
|
+
bgMagenta: f2("\x1B[45m", "\x1B[49m"),
|
|
131
|
+
bgCyan: f2("\x1B[46m", "\x1B[49m"),
|
|
132
|
+
bgWhite: f2("\x1B[47m", "\x1B[49m"),
|
|
133
|
+
blackBright: f2("\x1B[90m", "\x1B[39m"),
|
|
134
|
+
redBright: f2("\x1B[91m", "\x1B[39m"),
|
|
135
|
+
greenBright: f2("\x1B[92m", "\x1B[39m"),
|
|
136
|
+
yellowBright: f2("\x1B[93m", "\x1B[39m"),
|
|
137
|
+
blueBright: f2("\x1B[94m", "\x1B[39m"),
|
|
138
|
+
magentaBright: f2("\x1B[95m", "\x1B[39m"),
|
|
139
|
+
cyanBright: f2("\x1B[96m", "\x1B[39m"),
|
|
140
|
+
whiteBright: f2("\x1B[97m", "\x1B[39m"),
|
|
141
|
+
bgBlackBright: f2("\x1B[100m", "\x1B[49m"),
|
|
142
|
+
bgRedBright: f2("\x1B[101m", "\x1B[49m"),
|
|
143
|
+
bgGreenBright: f2("\x1B[102m", "\x1B[49m"),
|
|
144
|
+
bgYellowBright: f2("\x1B[103m", "\x1B[49m"),
|
|
145
|
+
bgBlueBright: f2("\x1B[104m", "\x1B[49m"),
|
|
146
|
+
bgMagentaBright: f2("\x1B[105m", "\x1B[49m"),
|
|
147
|
+
bgCyanBright: f2("\x1B[106m", "\x1B[49m"),
|
|
148
|
+
bgWhiteBright: f2("\x1B[107m", "\x1B[49m")
|
|
149
|
+
};
|
|
150
|
+
};
|
|
151
|
+
module.exports = createColors();
|
|
152
|
+
module.exports.createColors = createColors;
|
|
153
|
+
}
|
|
154
|
+
});
|
|
2
155
|
|
|
3
156
|
// ../argent-cli/src/run.ts
|
|
4
157
|
import * as fs2 from "node:fs";
|
|
5
|
-
import * as
|
|
158
|
+
import * as path3 from "node:path";
|
|
6
159
|
|
|
7
160
|
// ../argent-tools-client/src/launcher.ts
|
|
8
161
|
import * as net from "node:net";
|
|
@@ -11,20 +164,36 @@ import * as path from "node:path";
|
|
|
11
164
|
import * as readline from "node:readline";
|
|
12
165
|
import { homedir } from "node:os";
|
|
13
166
|
import { spawn } from "node:child_process";
|
|
14
|
-
import {
|
|
167
|
+
import { randomBytes } from "node:crypto";
|
|
168
|
+
import { mkdir, writeFile, readFile, unlink, rename, chmod } from "node:fs/promises";
|
|
15
169
|
var STATE_DIR = path.join(homedir(), ".argent");
|
|
16
170
|
var STATE_FILE = path.join(STATE_DIR, "tool-server.json");
|
|
17
171
|
var LOG_FILE = path.join(STATE_DIR, "tool-server.log");
|
|
18
|
-
|
|
19
|
-
|
|
172
|
+
var AUTH_TOKEN_BYTES = 32;
|
|
173
|
+
var AUTH_TOKEN_ENV = "ARGENT_AUTH_TOKEN";
|
|
174
|
+
var AUTOSPAWN_IDLE_TIMEOUT_MINUTES = 30;
|
|
175
|
+
function buildToolsServerEnv(paths, port, baseEnv = process.env, options = {}) {
|
|
176
|
+
const env = {
|
|
20
177
|
...baseEnv,
|
|
21
|
-
|
|
178
|
+
ARGENT_PORT: String(port),
|
|
22
179
|
ARGENT_SIMULATOR_SERVER_DIR: paths.simulatorServerDir,
|
|
23
180
|
ARGENT_NATIVE_DEVTOOLS_DIR: paths.nativeDevtoolsDir
|
|
24
181
|
};
|
|
182
|
+
if (options.host !== void 0) env.ARGENT_HOST = options.host;
|
|
183
|
+
if (options.idleTimeoutMinutes !== void 0) {
|
|
184
|
+
env.ARGENT_IDLE_TIMEOUT_MINUTES = String(options.idleTimeoutMinutes);
|
|
185
|
+
}
|
|
186
|
+
if (options.token) env[AUTH_TOKEN_ENV] = options.token;
|
|
187
|
+
return env;
|
|
188
|
+
}
|
|
189
|
+
function generateToken() {
|
|
190
|
+
return randomBytes(AUTH_TOKEN_BYTES).toString("hex");
|
|
191
|
+
}
|
|
192
|
+
function generateAuthToken() {
|
|
193
|
+
return generateToken();
|
|
25
194
|
}
|
|
26
195
|
function findFreePort() {
|
|
27
|
-
return new Promise((
|
|
196
|
+
return new Promise((resolve3, reject) => {
|
|
28
197
|
const srv = net.createServer();
|
|
29
198
|
srv.listen(0, "127.0.0.1", () => {
|
|
30
199
|
const addr = srv.address();
|
|
@@ -35,7 +204,7 @@ function findFreePort() {
|
|
|
35
204
|
const port = addr.port;
|
|
36
205
|
srv.close((err) => {
|
|
37
206
|
if (err) reject(err);
|
|
38
|
-
else
|
|
207
|
+
else resolve3(port);
|
|
39
208
|
});
|
|
40
209
|
});
|
|
41
210
|
srv.on("error", reject);
|
|
@@ -49,12 +218,28 @@ function isProcessAlive(pid) {
|
|
|
49
218
|
return false;
|
|
50
219
|
}
|
|
51
220
|
}
|
|
52
|
-
|
|
221
|
+
function isToolsServerProcessAlive(pid) {
|
|
222
|
+
return isProcessAlive(pid);
|
|
223
|
+
}
|
|
224
|
+
function healthCheckHost(host) {
|
|
225
|
+
if (host === "0.0.0.0" || host === "") return "127.0.0.1";
|
|
226
|
+
if (host === "::" || host === "::0") return "::1";
|
|
227
|
+
return host;
|
|
228
|
+
}
|
|
229
|
+
function formatUrl(host, port) {
|
|
230
|
+
const h2 = host.includes(":") && !host.startsWith("[") ? `[${host}]` : host;
|
|
231
|
+
return `http://${h2}:${port}`;
|
|
232
|
+
}
|
|
233
|
+
function authHeaders(token) {
|
|
234
|
+
return token ? { Authorization: `Bearer ${token}` } : {};
|
|
235
|
+
}
|
|
236
|
+
async function isToolsServerHealthy(port, host = "127.0.0.1", timeoutMs = 2e3, token) {
|
|
53
237
|
const controller = new AbortController();
|
|
54
|
-
const timer = setTimeout(() => controller.abort(),
|
|
238
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
55
239
|
try {
|
|
56
|
-
const res = await fetch(
|
|
57
|
-
signal: controller.signal
|
|
240
|
+
const res = await fetch(`${formatUrl(healthCheckHost(host), port)}/tools`, {
|
|
241
|
+
signal: controller.signal,
|
|
242
|
+
headers: authHeaders(token)
|
|
58
243
|
});
|
|
59
244
|
return res.ok;
|
|
60
245
|
} catch {
|
|
@@ -63,8 +248,8 @@ async function isHealthy(port) {
|
|
|
63
248
|
clearTimeout(timer);
|
|
64
249
|
}
|
|
65
250
|
}
|
|
66
|
-
function spawnToolsServer(paths, port) {
|
|
67
|
-
return new Promise((
|
|
251
|
+
function spawnToolsServer(paths, port, options = {}) {
|
|
252
|
+
return new Promise((resolve3, reject) => {
|
|
68
253
|
let logFd;
|
|
69
254
|
try {
|
|
70
255
|
fs.mkdirSync(STATE_DIR, { recursive: true });
|
|
@@ -75,7 +260,7 @@ function spawnToolsServer(paths, port) {
|
|
|
75
260
|
const child = spawn("node", [paths.bundlePath, "start"], {
|
|
76
261
|
detached: true,
|
|
77
262
|
stdio: ["ignore", "pipe", logFd],
|
|
78
|
-
env: buildToolsServerEnv(paths, port)
|
|
263
|
+
env: buildToolsServerEnv(paths, port, process.env, options)
|
|
79
264
|
});
|
|
80
265
|
child.unref();
|
|
81
266
|
const pid = child.pid;
|
|
@@ -91,12 +276,12 @@ function spawnToolsServer(paths, port) {
|
|
|
91
276
|
};
|
|
92
277
|
const rl = readline.createInterface({ input: child.stdout });
|
|
93
278
|
rl.on("line", (line) => {
|
|
94
|
-
const match = line.match(/Tools server listening on http
|
|
279
|
+
const match = line.match(/Tools server listening on http:\/\/.+:(\d+)/);
|
|
95
280
|
if (match) {
|
|
96
281
|
const actualPort = parseInt(match[1], 10);
|
|
97
282
|
rl.close();
|
|
98
283
|
child.stdout?.resume();
|
|
99
|
-
settle(() =>
|
|
284
|
+
settle(() => resolve3({ port: actualPort, pid }));
|
|
100
285
|
}
|
|
101
286
|
});
|
|
102
287
|
child.on("error", (err) => {
|
|
@@ -114,7 +299,7 @@ function spawnToolsServer(paths, port) {
|
|
|
114
299
|
rl.on("close", () => clearTimeout(timer));
|
|
115
300
|
});
|
|
116
301
|
}
|
|
117
|
-
async function
|
|
302
|
+
async function readToolsServerState() {
|
|
118
303
|
try {
|
|
119
304
|
const raw = await readFile(STATE_FILE, "utf8");
|
|
120
305
|
return JSON.parse(raw);
|
|
@@ -122,22 +307,73 @@ async function readState() {
|
|
|
122
307
|
return null;
|
|
123
308
|
}
|
|
124
309
|
}
|
|
125
|
-
async function
|
|
310
|
+
async function writeToolsServerState(state) {
|
|
126
311
|
await mkdir(STATE_DIR, { recursive: true });
|
|
127
|
-
|
|
312
|
+
const tmp = `${STATE_FILE}.${process.pid}.tmp`;
|
|
313
|
+
try {
|
|
314
|
+
await writeFile(tmp, JSON.stringify(state, null, 2) + "\n", {
|
|
315
|
+
encoding: "utf8",
|
|
316
|
+
mode: 384
|
|
317
|
+
});
|
|
318
|
+
await chmod(tmp, 384);
|
|
319
|
+
await rename(tmp, STATE_FILE);
|
|
320
|
+
} catch (err) {
|
|
321
|
+
await unlink(tmp).catch(() => {
|
|
322
|
+
});
|
|
323
|
+
throw err;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
function writeToolsServerStateSync(state) {
|
|
327
|
+
fs.mkdirSync(STATE_DIR, { recursive: true });
|
|
328
|
+
fs.writeFileSync(STATE_FILE, JSON.stringify(state, null, 2) + "\n", {
|
|
329
|
+
encoding: "utf8",
|
|
330
|
+
mode: 384
|
|
331
|
+
});
|
|
332
|
+
fs.chmodSync(STATE_FILE, 384);
|
|
128
333
|
}
|
|
129
|
-
async function
|
|
334
|
+
async function clearToolsServerState() {
|
|
130
335
|
try {
|
|
131
336
|
await unlink(STATE_FILE);
|
|
132
337
|
} catch {
|
|
133
338
|
}
|
|
134
339
|
}
|
|
340
|
+
var readState = readToolsServerState;
|
|
341
|
+
var writeState = writeToolsServerState;
|
|
342
|
+
var clearState = clearToolsServerState;
|
|
343
|
+
var SIGTERM_GRACE_MS = 6e3;
|
|
344
|
+
var SIGKILL_GRACE_MS = 1e3;
|
|
345
|
+
var KILL_POLL_MS = 100;
|
|
346
|
+
async function waitForExit(pid, timeoutMs) {
|
|
347
|
+
const deadline = Date.now() + timeoutMs;
|
|
348
|
+
while (Date.now() < deadline) {
|
|
349
|
+
if (!isProcessAlive(pid)) return true;
|
|
350
|
+
await new Promise((r) => setTimeout(r, KILL_POLL_MS));
|
|
351
|
+
}
|
|
352
|
+
return !isProcessAlive(pid);
|
|
353
|
+
}
|
|
135
354
|
async function killToolServer() {
|
|
136
355
|
const state = await readState();
|
|
137
356
|
if (!state) return;
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
357
|
+
let exited = !isProcessAlive(state.pid);
|
|
358
|
+
if (!exited) {
|
|
359
|
+
try {
|
|
360
|
+
process.kill(state.pid, "SIGTERM");
|
|
361
|
+
} catch {
|
|
362
|
+
exited = true;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
if (!exited) {
|
|
366
|
+
exited = await waitForExit(state.pid, SIGTERM_GRACE_MS);
|
|
367
|
+
}
|
|
368
|
+
if (!exited) {
|
|
369
|
+
try {
|
|
370
|
+
process.kill(state.pid, "SIGKILL");
|
|
371
|
+
} catch {
|
|
372
|
+
exited = true;
|
|
373
|
+
}
|
|
374
|
+
if (!exited) {
|
|
375
|
+
await waitForExit(state.pid, SIGKILL_GRACE_MS);
|
|
376
|
+
}
|
|
141
377
|
}
|
|
142
378
|
await clearState();
|
|
143
379
|
}
|
|
@@ -146,29 +382,154 @@ async function ensureToolsServer(paths) {
|
|
|
146
382
|
if (state) {
|
|
147
383
|
const alive = isProcessAlive(state.pid);
|
|
148
384
|
if (alive) {
|
|
149
|
-
const
|
|
385
|
+
const host = state.host ?? "127.0.0.1";
|
|
386
|
+
const healthy = await isToolsServerHealthy(state.port, host, 2e3, state.token);
|
|
150
387
|
if (healthy) {
|
|
151
|
-
return
|
|
388
|
+
return {
|
|
389
|
+
url: formatUrl(healthCheckHost(host), state.port),
|
|
390
|
+
token: state.token ?? ""
|
|
391
|
+
};
|
|
152
392
|
}
|
|
153
393
|
}
|
|
154
394
|
await clearState();
|
|
155
395
|
}
|
|
396
|
+
const token = generateToken();
|
|
156
397
|
const port = await findFreePort();
|
|
157
|
-
const { port: actualPort, pid } = await spawnToolsServer(paths, port
|
|
398
|
+
const { port: actualPort, pid } = await spawnToolsServer(paths, port, {
|
|
399
|
+
token,
|
|
400
|
+
idleTimeoutMinutes: AUTOSPAWN_IDLE_TIMEOUT_MINUTES
|
|
401
|
+
});
|
|
158
402
|
await writeState({
|
|
159
403
|
port: actualPort,
|
|
160
404
|
pid,
|
|
161
405
|
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
162
|
-
bundlePath: paths.bundlePath
|
|
406
|
+
bundlePath: paths.bundlePath,
|
|
407
|
+
host: "127.0.0.1",
|
|
408
|
+
token
|
|
409
|
+
});
|
|
410
|
+
return { url: formatUrl("127.0.0.1", actualPort), token };
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// ../argent-tools-client/src/link-config.ts
|
|
414
|
+
import * as path2 from "node:path";
|
|
415
|
+
import { homedir as homedir2 } from "node:os";
|
|
416
|
+
import { mkdir as mkdir2, writeFile as writeFile2, readFile as readFile2, unlink as unlink2, chmod as chmod2 } from "node:fs/promises";
|
|
417
|
+
var LINK_DIR = path2.join(homedir2(), ".argent");
|
|
418
|
+
var LINK_FILE = path2.join(LINK_DIR, "link.json");
|
|
419
|
+
async function readLinkConfig() {
|
|
420
|
+
try {
|
|
421
|
+
const raw = await readFile2(LINK_FILE, "utf8");
|
|
422
|
+
const parsed = JSON.parse(raw);
|
|
423
|
+
if (!parsed || typeof parsed.url !== "string" || typeof parsed.host !== "string" || typeof parsed.port !== "number" || typeof parsed.createdAt !== "string") {
|
|
424
|
+
return null;
|
|
425
|
+
}
|
|
426
|
+
return {
|
|
427
|
+
url: parsed.url,
|
|
428
|
+
host: parsed.host,
|
|
429
|
+
port: parsed.port,
|
|
430
|
+
createdAt: parsed.createdAt,
|
|
431
|
+
...typeof parsed.token === "string" ? { token: parsed.token } : {}
|
|
432
|
+
};
|
|
433
|
+
} catch {
|
|
434
|
+
return null;
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
async function writeLinkConfig(cfg) {
|
|
438
|
+
await mkdir2(LINK_DIR, { recursive: true });
|
|
439
|
+
await writeFile2(LINK_FILE, JSON.stringify(cfg, null, 2) + "\n", {
|
|
440
|
+
encoding: "utf8",
|
|
441
|
+
mode: 384
|
|
163
442
|
});
|
|
164
|
-
|
|
443
|
+
await chmod2(LINK_FILE, 384);
|
|
444
|
+
}
|
|
445
|
+
async function clearLinkConfig() {
|
|
446
|
+
try {
|
|
447
|
+
await unlink2(LINK_FILE);
|
|
448
|
+
} catch {
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
async function getResolvedToolsUrl() {
|
|
452
|
+
const envUrl = process.env.ARGENT_TOOLS_URL;
|
|
453
|
+
if (envUrl) {
|
|
454
|
+
const link3 = await readLinkConfig();
|
|
455
|
+
const envToken = process.env[AUTH_TOKEN_ENV];
|
|
456
|
+
return {
|
|
457
|
+
url: envUrl,
|
|
458
|
+
source: "env",
|
|
459
|
+
...envToken ? { token: envToken } : {},
|
|
460
|
+
...link3 ? { shadowedLink: link3 } : {}
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
const link2 = await readLinkConfig();
|
|
464
|
+
if (link2) {
|
|
465
|
+
return { url: link2.url, source: "link", ...link2.token ? { token: link2.token } : {} };
|
|
466
|
+
}
|
|
467
|
+
return { url: null, source: "none" };
|
|
468
|
+
}
|
|
469
|
+
var LINK_URL_SCHEME = "argent:";
|
|
470
|
+
function formatLinkUrl(parts) {
|
|
471
|
+
const h2 = parts.host.includes(":") && !parts.host.startsWith("[") ? `[${parts.host}]` : parts.host;
|
|
472
|
+
const auth = parts.token ? `${encodeURIComponent(parts.token)}@` : "";
|
|
473
|
+
return `${LINK_URL_SCHEME}//${auth}${h2}:${parts.port}`;
|
|
474
|
+
}
|
|
475
|
+
function parseLinkUrl(input) {
|
|
476
|
+
if (!input.startsWith(`${LINK_URL_SCHEME}//`)) return null;
|
|
477
|
+
let u;
|
|
478
|
+
try {
|
|
479
|
+
u = new URL(input);
|
|
480
|
+
} catch {
|
|
481
|
+
throw new Error(
|
|
482
|
+
`Invalid connection string "${input}" \u2014 expected argent://[<token>@]<host>:<port>`
|
|
483
|
+
);
|
|
484
|
+
}
|
|
485
|
+
const host = u.hostname.startsWith("[") ? u.hostname.slice(1, -1) : u.hostname;
|
|
486
|
+
if (!host) throw new Error(`Connection string "${input}" is missing a host.`);
|
|
487
|
+
if (!u.port) throw new Error(`Connection string "${input}" is missing a port.`);
|
|
488
|
+
const port = Number(u.port);
|
|
489
|
+
const token = u.username ? decodeURIComponent(u.username) : void 0;
|
|
490
|
+
return { host, port, ...token ? { token } : {} };
|
|
491
|
+
}
|
|
492
|
+
function httpFromHostPort(host, port) {
|
|
493
|
+
const h2 = host.includes(":") && !host.startsWith("[") ? `[${host}]` : host;
|
|
494
|
+
return `http://${h2}:${port}`;
|
|
495
|
+
}
|
|
496
|
+
function parseLinkTarget(input) {
|
|
497
|
+
const argent = parseLinkUrl(input);
|
|
498
|
+
if (argent) {
|
|
499
|
+
return {
|
|
500
|
+
url: httpFromHostPort(argent.host, argent.port),
|
|
501
|
+
host: argent.host,
|
|
502
|
+
port: argent.port,
|
|
503
|
+
...argent.token ? { token: argent.token } : {}
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
if (!/^https?:\/\//i.test(input)) return null;
|
|
507
|
+
let u;
|
|
508
|
+
try {
|
|
509
|
+
u = new URL(input);
|
|
510
|
+
} catch {
|
|
511
|
+
throw new Error(`Invalid URL "${input}" \u2014 expected http(s)://<host>[:<port>][/path].`);
|
|
512
|
+
}
|
|
513
|
+
const host = u.hostname.startsWith("[") ? u.hostname.slice(1, -1) : u.hostname;
|
|
514
|
+
if (!host) throw new Error(`URL "${input}" is missing a host.`);
|
|
515
|
+
const port = u.port ? Number(u.port) : u.protocol === "https:" ? 443 : 80;
|
|
516
|
+
const path6 = u.pathname === "/" ? "" : u.pathname.replace(/\/+$/, "");
|
|
517
|
+
const url = `${u.protocol}//${u.host}${path6}`;
|
|
518
|
+
const token = u.username ? decodeURIComponent(u.username) : void 0;
|
|
519
|
+
return { url, host, port, ...token ? { token } : {} };
|
|
165
520
|
}
|
|
166
521
|
|
|
167
522
|
// ../argent-tools-client/src/tools-client.ts
|
|
523
|
+
function authHeaders2(token) {
|
|
524
|
+
return token ? { Authorization: `Bearer ${token}` } : {};
|
|
525
|
+
}
|
|
168
526
|
function createToolsClient(options = {}) {
|
|
169
527
|
let cached = null;
|
|
170
528
|
async function baseUrl() {
|
|
171
|
-
|
|
529
|
+
const resolved = await getResolvedToolsUrl();
|
|
530
|
+
if (resolved.url) {
|
|
531
|
+
return { url: resolved.url, token: resolved.token ?? "" };
|
|
532
|
+
}
|
|
172
533
|
if (cached) return cached;
|
|
173
534
|
if (!options.paths) {
|
|
174
535
|
throw new Error(
|
|
@@ -179,8 +540,8 @@ function createToolsClient(options = {}) {
|
|
|
179
540
|
return cached;
|
|
180
541
|
}
|
|
181
542
|
async function fetchTools() {
|
|
182
|
-
const url = await baseUrl();
|
|
183
|
-
const res = await fetch(`${url}/tools
|
|
543
|
+
const { url, token } = await baseUrl();
|
|
544
|
+
const res = await fetch(`${url}/tools`, { headers: authHeaders2(token) });
|
|
184
545
|
if (!res.ok) throw new Error(`GET /tools failed: ${res.status} ${res.statusText}`);
|
|
185
546
|
const json = await res.json();
|
|
186
547
|
return json.tools;
|
|
@@ -190,10 +551,10 @@ function createToolsClient(options = {}) {
|
|
|
190
551
|
return tools2.find((t) => t.name === name) ?? null;
|
|
191
552
|
}
|
|
192
553
|
async function callTool(name, args) {
|
|
193
|
-
const url = await baseUrl();
|
|
554
|
+
const { url, token } = await baseUrl();
|
|
194
555
|
const res = await fetch(`${url}/tools/${encodeURIComponent(name)}`, {
|
|
195
556
|
method: "POST",
|
|
196
|
-
headers: { "Content-Type": "application/json" },
|
|
557
|
+
headers: { "Content-Type": "application/json", ...authHeaders2(token) },
|
|
197
558
|
body: JSON.stringify(args ?? {})
|
|
198
559
|
});
|
|
199
560
|
const json = await res.json().catch(() => ({}));
|
|
@@ -259,7 +620,7 @@ function parseFlags(argv, schema) {
|
|
|
259
620
|
continue;
|
|
260
621
|
}
|
|
261
622
|
if (tok === "--") {
|
|
262
|
-
for (let
|
|
623
|
+
for (let j2 = i + 1; j2 < argv.length; j2++) positional.push(argv[j2]);
|
|
263
624
|
break;
|
|
264
625
|
}
|
|
265
626
|
if (!tok.startsWith("--")) {
|
|
@@ -366,7 +727,7 @@ function renderFlagName(name, prop) {
|
|
|
366
727
|
}
|
|
367
728
|
function renderType(prop) {
|
|
368
729
|
if (prop.enum && Array.isArray(prop.enum)) {
|
|
369
|
-
return `enum: ${prop.enum.map((
|
|
730
|
+
return `enum: ${prop.enum.map((v2) => JSON.stringify(v2)).join(" | ")}`;
|
|
370
731
|
}
|
|
371
732
|
if (prop.type === "array") {
|
|
372
733
|
const item = prop.items?.type ?? "any";
|
|
@@ -388,9 +749,9 @@ function splitOptions(argv) {
|
|
|
388
749
|
continue;
|
|
389
750
|
}
|
|
390
751
|
if (tok === "--out") {
|
|
391
|
-
const
|
|
392
|
-
if (!
|
|
393
|
-
outPath =
|
|
752
|
+
const v2 = argv[i + 1];
|
|
753
|
+
if (!v2) throw new FlagParseException("--out requires a path");
|
|
754
|
+
outPath = v2;
|
|
394
755
|
i += 1;
|
|
395
756
|
continue;
|
|
396
757
|
}
|
|
@@ -403,13 +764,13 @@ function splitOptions(argv) {
|
|
|
403
764
|
return { json, outPath, argvForFlags: rest };
|
|
404
765
|
}
|
|
405
766
|
async function readStdin() {
|
|
406
|
-
return new Promise((
|
|
767
|
+
return new Promise((resolve3, reject) => {
|
|
407
768
|
let data = "";
|
|
408
769
|
process.stdin.setEncoding("utf8");
|
|
409
770
|
process.stdin.on("data", (chunk) => {
|
|
410
771
|
data += chunk;
|
|
411
772
|
});
|
|
412
|
-
process.stdin.on("end", () =>
|
|
773
|
+
process.stdin.on("end", () => resolve3(data));
|
|
413
774
|
process.stdin.on("error", reject);
|
|
414
775
|
});
|
|
415
776
|
}
|
|
@@ -437,7 +798,7 @@ async function fetchImageToFile(result, outPath) {
|
|
|
437
798
|
const res = await fetch(url);
|
|
438
799
|
if (!res.ok) throw new Error(`Failed to download image: ${res.status} ${res.statusText}`);
|
|
439
800
|
const buf = Buffer.from(await res.arrayBuffer());
|
|
440
|
-
fs2.mkdirSync(
|
|
801
|
+
fs2.mkdirSync(path3.dirname(path3.resolve(outPath)), { recursive: true });
|
|
441
802
|
fs2.writeFileSync(outPath, buf);
|
|
442
803
|
}
|
|
443
804
|
function renderResult(result, outputHint, json) {
|
|
@@ -507,8 +868,8 @@ Examples:
|
|
|
507
868
|
process.exit(2);
|
|
508
869
|
}
|
|
509
870
|
}
|
|
510
|
-
for (const [
|
|
511
|
-
payload[
|
|
871
|
+
for (const [k2, v2] of Object.entries(parsed.args)) {
|
|
872
|
+
payload[k2] = v2;
|
|
512
873
|
}
|
|
513
874
|
let result;
|
|
514
875
|
let note;
|
|
@@ -554,8 +915,8 @@ async function tools(argv, options) {
|
|
|
554
915
|
console.log("(no tools registered)");
|
|
555
916
|
return;
|
|
556
917
|
}
|
|
557
|
-
const sorted = [...list].sort((a,
|
|
558
|
-
const maxName = sorted.reduce((
|
|
918
|
+
const sorted = [...list].sort((a, b2) => a.name.localeCompare(b2.name));
|
|
919
|
+
const maxName = sorted.reduce((m2, t) => Math.max(m2, t.name.length), 0);
|
|
559
920
|
for (const t of sorted) {
|
|
560
921
|
const summary = summarize(t.description);
|
|
561
922
|
console.log(` ${t.name.padEnd(maxName, " ")} ${summary}`);
|
|
@@ -614,12 +975,12 @@ Options:
|
|
|
614
975
|
|
|
615
976
|
// ../argent-cli/src/server.ts
|
|
616
977
|
import * as fs3 from "node:fs";
|
|
617
|
-
import * as
|
|
618
|
-
import { homedir as
|
|
978
|
+
import * as path4 from "node:path";
|
|
979
|
+
import { homedir as homedir3, networkInterfaces } from "node:os";
|
|
619
980
|
import { spawn as spawn2 } from "node:child_process";
|
|
620
|
-
var STATE_DIR2 =
|
|
621
|
-
var STATE_FILE2 =
|
|
622
|
-
var LOG_FILE2 =
|
|
981
|
+
var STATE_DIR2 = path4.join(homedir3(), ".argent");
|
|
982
|
+
var STATE_FILE2 = path4.join(STATE_DIR2, "tool-server.json");
|
|
983
|
+
var LOG_FILE2 = path4.join(STATE_DIR2, "tool-server.log");
|
|
623
984
|
function readState2() {
|
|
624
985
|
try {
|
|
625
986
|
return JSON.parse(fs3.readFileSync(STATE_FILE2, "utf8"));
|
|
@@ -627,26 +988,6 @@ function readState2() {
|
|
|
627
988
|
return null;
|
|
628
989
|
}
|
|
629
990
|
}
|
|
630
|
-
function isProcessAlive2(pid) {
|
|
631
|
-
try {
|
|
632
|
-
process.kill(pid, 0);
|
|
633
|
-
return true;
|
|
634
|
-
} catch {
|
|
635
|
-
return false;
|
|
636
|
-
}
|
|
637
|
-
}
|
|
638
|
-
async function isHealthy2(port, timeoutMs = 2e3) {
|
|
639
|
-
const controller = new AbortController();
|
|
640
|
-
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
641
|
-
try {
|
|
642
|
-
const res = await fetch(`http://127.0.0.1:${port}/tools`, { signal: controller.signal });
|
|
643
|
-
return res.ok;
|
|
644
|
-
} catch {
|
|
645
|
-
return false;
|
|
646
|
-
} finally {
|
|
647
|
-
clearTimeout(timer);
|
|
648
|
-
}
|
|
649
|
-
}
|
|
650
991
|
async function statusCmd(json) {
|
|
651
992
|
const state = readState2();
|
|
652
993
|
if (!state) {
|
|
@@ -657,14 +998,22 @@ async function statusCmd(json) {
|
|
|
657
998
|
}
|
|
658
999
|
return;
|
|
659
1000
|
}
|
|
660
|
-
const
|
|
661
|
-
const
|
|
1001
|
+
const host = state.host ?? "127.0.0.1";
|
|
1002
|
+
const alive = isToolsServerProcessAlive(state.pid);
|
|
1003
|
+
const healthy = alive ? await isToolsServerHealthy(state.port, host, 2e3, state.token) : false;
|
|
662
1004
|
if (json) {
|
|
663
|
-
|
|
1005
|
+
const { token, ...publicState } = state;
|
|
1006
|
+
console.log(
|
|
1007
|
+
JSON.stringify(
|
|
1008
|
+
{ running: alive && healthy, ...publicState, hasToken: !!token, alive, healthy },
|
|
1009
|
+
null,
|
|
1010
|
+
2
|
|
1011
|
+
)
|
|
1012
|
+
);
|
|
664
1013
|
return;
|
|
665
1014
|
}
|
|
666
1015
|
console.log(`tool-server:`);
|
|
667
|
-
console.log(` url:
|
|
1016
|
+
console.log(` url: ${formatUrl(host, state.port)}`);
|
|
668
1017
|
console.log(` pid: ${state.pid}`);
|
|
669
1018
|
console.log(` startedAt: ${state.startedAt}`);
|
|
670
1019
|
console.log(` process: ${alive ? "alive" : "dead"}`);
|
|
@@ -695,12 +1044,312 @@ function logsCmd(follow) {
|
|
|
695
1044
|
const child = spawn2("tail", ["-f", LOG_FILE2], { stdio: "inherit" });
|
|
696
1045
|
child.on("exit", (code) => process.exit(code ?? 0));
|
|
697
1046
|
}
|
|
698
|
-
|
|
1047
|
+
var StartFlagError = class extends Error {
|
|
1048
|
+
};
|
|
1049
|
+
function parseStartFlags(argv) {
|
|
1050
|
+
const flags2 = {
|
|
1051
|
+
port: null,
|
|
1052
|
+
host: "127.0.0.1",
|
|
1053
|
+
idleTimeoutMinutes: 0,
|
|
1054
|
+
detach: false,
|
|
1055
|
+
force: false,
|
|
1056
|
+
noAuth: false,
|
|
1057
|
+
help: false
|
|
1058
|
+
};
|
|
1059
|
+
for (let i = 0; i < argv.length; i++) {
|
|
1060
|
+
const tok = argv[i];
|
|
1061
|
+
const takeValue = (name) => {
|
|
1062
|
+
const v2 = argv[i + 1];
|
|
1063
|
+
if (v2 === void 0) throw new StartFlagError(`${name} requires a value`);
|
|
1064
|
+
i += 1;
|
|
1065
|
+
return v2;
|
|
1066
|
+
};
|
|
1067
|
+
if (tok === "--help" || tok === "-h") {
|
|
1068
|
+
flags2.help = true;
|
|
1069
|
+
continue;
|
|
1070
|
+
}
|
|
1071
|
+
if (tok === "--detach" || tok === "-d") {
|
|
1072
|
+
flags2.detach = true;
|
|
1073
|
+
continue;
|
|
1074
|
+
}
|
|
1075
|
+
if (tok === "--force") {
|
|
1076
|
+
flags2.force = true;
|
|
1077
|
+
continue;
|
|
1078
|
+
}
|
|
1079
|
+
if (tok === "--no-auth") {
|
|
1080
|
+
flags2.noAuth = true;
|
|
1081
|
+
continue;
|
|
1082
|
+
}
|
|
1083
|
+
if (tok === "--port" || tok === "-p") {
|
|
1084
|
+
flags2.port = parsePort(takeValue("--port"));
|
|
1085
|
+
continue;
|
|
1086
|
+
}
|
|
1087
|
+
if (tok.startsWith("--port=")) {
|
|
1088
|
+
flags2.port = parsePort(tok.slice("--port=".length));
|
|
1089
|
+
continue;
|
|
1090
|
+
}
|
|
1091
|
+
if (tok === "--host") {
|
|
1092
|
+
flags2.host = takeValue("--host");
|
|
1093
|
+
continue;
|
|
1094
|
+
}
|
|
1095
|
+
if (tok.startsWith("--host=")) {
|
|
1096
|
+
flags2.host = tok.slice("--host=".length);
|
|
1097
|
+
continue;
|
|
1098
|
+
}
|
|
1099
|
+
if (tok === "--idle-timeout") {
|
|
1100
|
+
flags2.idleTimeoutMinutes = parseIdle(takeValue("--idle-timeout"));
|
|
1101
|
+
continue;
|
|
1102
|
+
}
|
|
1103
|
+
if (tok.startsWith("--idle-timeout=")) {
|
|
1104
|
+
flags2.idleTimeoutMinutes = parseIdle(tok.slice("--idle-timeout=".length));
|
|
1105
|
+
continue;
|
|
1106
|
+
}
|
|
1107
|
+
throw new StartFlagError(`Unknown flag: ${tok}`);
|
|
1108
|
+
}
|
|
1109
|
+
return flags2;
|
|
1110
|
+
}
|
|
1111
|
+
var NON_NEGATIVE_INT = /^\d+$/;
|
|
1112
|
+
function parsePort(raw) {
|
|
1113
|
+
if (!NON_NEGATIVE_INT.test(raw) || Number(raw) > 65535) {
|
|
1114
|
+
throw new StartFlagError(`--port must be an integer 0..65535, got "${raw}"`);
|
|
1115
|
+
}
|
|
1116
|
+
return Number(raw);
|
|
1117
|
+
}
|
|
1118
|
+
function parseIdle(raw) {
|
|
1119
|
+
if (!NON_NEGATIVE_INT.test(raw)) {
|
|
1120
|
+
throw new StartFlagError(`--idle-timeout must be a non-negative integer, got "${raw}"`);
|
|
1121
|
+
}
|
|
1122
|
+
return Number(raw);
|
|
1123
|
+
}
|
|
1124
|
+
function printStartHelp() {
|
|
1125
|
+
console.log(`Usage: argent server start [flags]
|
|
1126
|
+
|
|
1127
|
+
Spawn a long-lived tool-server. Foreground by default so process supervisors
|
|
1128
|
+
(systemd, Docker, supervisord) can own the lifecycle.
|
|
1129
|
+
|
|
1130
|
+
Flags:
|
|
1131
|
+
--port, -p <n> Bind to port <n> (0 = pick a free port). Default: 3001
|
|
1132
|
+
--host <h> Bind address. Default: 127.0.0.1
|
|
1133
|
+
Use 0.0.0.0 to expose on every interface.
|
|
1134
|
+
--idle-timeout <m> Auto-shutdown after <m> idle minutes (0 disables).
|
|
1135
|
+
Default: 0 (never auto-shutdown).
|
|
1136
|
+
--detach, -d Run as a detached background process and return.
|
|
1137
|
+
--force If a tool-server is already running, kill it first.
|
|
1138
|
+
--no-auth Disable authentication (no token). Anyone who can
|
|
1139
|
+
reach the port can drive the server. Dev/trusted only.
|
|
1140
|
+
--help, -h Show this help.
|
|
1141
|
+
|
|
1142
|
+
Auth:
|
|
1143
|
+
By default the server mints a bearer token and prints a one-line connection
|
|
1144
|
+
string. Pair a client by pasting it into \`argent link\`:
|
|
1145
|
+
argent link argent://<token>@<host>:<port>
|
|
1146
|
+
Pass --no-auth to run without a token (unauthenticated).
|
|
1147
|
+
|
|
1148
|
+
Examples:
|
|
1149
|
+
argent server start
|
|
1150
|
+
argent server start --port 4000
|
|
1151
|
+
argent server start --host 0.0.0.0 --port 4000
|
|
1152
|
+
argent server start --detach
|
|
1153
|
+
argent server start --host 0.0.0.0 --no-auth
|
|
1154
|
+
`);
|
|
1155
|
+
}
|
|
1156
|
+
function isLoopback(host) {
|
|
1157
|
+
return host === "127.0.0.1" || host === "localhost" || host === "::1";
|
|
1158
|
+
}
|
|
1159
|
+
function isWildcard(host) {
|
|
1160
|
+
return host === "0.0.0.0" || host === "::" || host === "::0" || host === "";
|
|
1161
|
+
}
|
|
1162
|
+
function primaryLanIPv4() {
|
|
1163
|
+
const ifaces = networkInterfaces();
|
|
1164
|
+
for (const addrs of Object.values(ifaces)) {
|
|
1165
|
+
for (const ni of addrs ?? []) {
|
|
1166
|
+
if (ni.family === "IPv4" && !ni.internal) return ni.address;
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
return null;
|
|
1170
|
+
}
|
|
1171
|
+
function resolveConnectHost(bindHost) {
|
|
1172
|
+
if (isWildcard(bindHost)) return primaryLanIPv4() ?? "127.0.0.1";
|
|
1173
|
+
return bindHost;
|
|
1174
|
+
}
|
|
1175
|
+
function printConnectionInfo(bindHost, port, token) {
|
|
1176
|
+
const connectHost = resolveConnectHost(bindHost);
|
|
1177
|
+
console.log("");
|
|
1178
|
+
console.log(" Connect a client:");
|
|
1179
|
+
console.log(` argent link ${formatLinkUrl({ host: connectHost, port, token })}`);
|
|
1180
|
+
const flagsForm = token ? `argent link --host ${connectHost} --port ${port} --token ${token}` : `argent link --host ${connectHost} --port ${port}`;
|
|
1181
|
+
console.log(` (or: ${flagsForm})${token ? "" : " [unauthenticated]"}`);
|
|
1182
|
+
if (isWildcard(bindHost)) {
|
|
1183
|
+
console.log(
|
|
1184
|
+
` note: bound to ${bindHost}; ${connectHost} is a best guess \u2014 replace it with the address clients actually reach this machine on.`
|
|
1185
|
+
);
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
async function ensureNoExistingServer(force) {
|
|
1189
|
+
const state = await readToolsServerState();
|
|
1190
|
+
if (!state) return;
|
|
1191
|
+
const alive = isToolsServerProcessAlive(state.pid);
|
|
1192
|
+
const healthy = alive ? await isToolsServerHealthy(state.port, state.host ?? "127.0.0.1") : false;
|
|
1193
|
+
if (alive && healthy && !force) {
|
|
1194
|
+
const url = formatUrl(state.host ?? "127.0.0.1", state.port);
|
|
1195
|
+
throw new StartFlagError(
|
|
1196
|
+
`tool-server is already running at ${url} (pid ${state.pid}).
|
|
1197
|
+
Use \`argent server stop\` first, or pass \`--force\` to replace it.`
|
|
1198
|
+
);
|
|
1199
|
+
}
|
|
1200
|
+
if (alive && force) {
|
|
1201
|
+
await killToolServer();
|
|
1202
|
+
} else {
|
|
1203
|
+
await clearToolsServerState();
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
async function resolvePort(requested) {
|
|
1207
|
+
if (requested === null) return 3001;
|
|
1208
|
+
if (requested === 0) return findFreePort();
|
|
1209
|
+
return requested;
|
|
1210
|
+
}
|
|
1211
|
+
async function startCmd(argv, paths) {
|
|
1212
|
+
if (!paths) {
|
|
1213
|
+
console.error("argent server start: bundled runtime paths missing \u2014 this build is incomplete.");
|
|
1214
|
+
process.exit(1);
|
|
1215
|
+
}
|
|
1216
|
+
let flags2;
|
|
1217
|
+
try {
|
|
1218
|
+
flags2 = parseStartFlags(argv);
|
|
1219
|
+
} catch (err) {
|
|
1220
|
+
if (err instanceof StartFlagError) {
|
|
1221
|
+
console.error(`Error: ${err.message}
|
|
1222
|
+
`);
|
|
1223
|
+
printStartHelp();
|
|
1224
|
+
process.exit(2);
|
|
1225
|
+
}
|
|
1226
|
+
throw err;
|
|
1227
|
+
}
|
|
1228
|
+
if (flags2.help) {
|
|
1229
|
+
printStartHelp();
|
|
1230
|
+
return;
|
|
1231
|
+
}
|
|
1232
|
+
try {
|
|
1233
|
+
await ensureNoExistingServer(flags2.force);
|
|
1234
|
+
} catch (err) {
|
|
1235
|
+
if (err instanceof StartFlagError) {
|
|
1236
|
+
console.error(err.message);
|
|
1237
|
+
process.exit(1);
|
|
1238
|
+
}
|
|
1239
|
+
throw err;
|
|
1240
|
+
}
|
|
1241
|
+
const port = await resolvePort(flags2.port);
|
|
1242
|
+
const token = flags2.noAuth ? void 0 : generateAuthToken();
|
|
1243
|
+
if (!isLoopback(flags2.host)) {
|
|
1244
|
+
if (token) {
|
|
1245
|
+
process.stderr.write(
|
|
1246
|
+
`Note: tool-server will be reachable on ${flags2.host}:${port} over plain HTTP (bearer-token auth, no TLS). Keep it to a trusted network or VPN.
|
|
1247
|
+
`
|
|
1248
|
+
);
|
|
1249
|
+
} else {
|
|
1250
|
+
process.stderr.write(
|
|
1251
|
+
`WARNING: tool-server will be reachable on ${flags2.host}:${port} with NO auth (--no-auth) \u2014 anyone who can reach the port can drive it. Do not expose to untrusted networks.
|
|
1252
|
+
`
|
|
1253
|
+
);
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
if (flags2.detach) {
|
|
1257
|
+
await runDetached(paths, port, flags2.host, flags2.idleTimeoutMinutes, token);
|
|
1258
|
+
return;
|
|
1259
|
+
}
|
|
1260
|
+
await runForeground(paths, port, flags2.host, flags2.idleTimeoutMinutes, token);
|
|
1261
|
+
}
|
|
1262
|
+
async function runDetached(paths, port, host, idleTimeoutMinutes, token) {
|
|
1263
|
+
const { port: actualPort, pid } = await spawnToolsServer(paths, port, {
|
|
1264
|
+
host,
|
|
1265
|
+
idleTimeoutMinutes,
|
|
1266
|
+
token
|
|
1267
|
+
});
|
|
1268
|
+
await writeToolsServerState({
|
|
1269
|
+
port: actualPort,
|
|
1270
|
+
pid,
|
|
1271
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1272
|
+
bundlePath: paths.bundlePath,
|
|
1273
|
+
host,
|
|
1274
|
+
...token ? { token } : {}
|
|
1275
|
+
});
|
|
1276
|
+
const url = formatUrl(host, actualPort);
|
|
1277
|
+
console.log(`tool-server started: ${url} (pid ${pid})`);
|
|
1278
|
+
printConnectionInfo(host, actualPort, token);
|
|
1279
|
+
console.log("");
|
|
1280
|
+
console.log(` logs: ${LOG_FILE2}`);
|
|
1281
|
+
console.log(` status: argent server status`);
|
|
1282
|
+
console.log(` stop: argent server stop`);
|
|
1283
|
+
}
|
|
1284
|
+
async function runForeground(paths, port, host, idleTimeoutMinutes, token) {
|
|
1285
|
+
const env = buildToolsServerEnv(paths, port, process.env, {
|
|
1286
|
+
host,
|
|
1287
|
+
idleTimeoutMinutes,
|
|
1288
|
+
token
|
|
1289
|
+
});
|
|
1290
|
+
const child = spawn2("node", [paths.bundlePath, "start"], {
|
|
1291
|
+
stdio: "inherit",
|
|
1292
|
+
env
|
|
1293
|
+
});
|
|
1294
|
+
const forward = (signal) => () => {
|
|
1295
|
+
try {
|
|
1296
|
+
child.kill(signal);
|
|
1297
|
+
} catch {
|
|
1298
|
+
}
|
|
1299
|
+
};
|
|
1300
|
+
const onInt = forward("SIGINT");
|
|
1301
|
+
const onTerm = forward("SIGTERM");
|
|
1302
|
+
process.on("SIGINT", onInt);
|
|
1303
|
+
process.on("SIGTERM", onTerm);
|
|
1304
|
+
let stateWritten = false;
|
|
1305
|
+
const childPid = child.pid;
|
|
1306
|
+
if (childPid !== void 0) {
|
|
1307
|
+
try {
|
|
1308
|
+
writeToolsServerStateSync({
|
|
1309
|
+
port,
|
|
1310
|
+
pid: childPid,
|
|
1311
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1312
|
+
bundlePath: paths.bundlePath,
|
|
1313
|
+
host,
|
|
1314
|
+
...token ? { token } : {}
|
|
1315
|
+
});
|
|
1316
|
+
stateWritten = true;
|
|
1317
|
+
} catch {
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
printConnectionInfo(host, port, token);
|
|
1321
|
+
await new Promise(() => {
|
|
1322
|
+
const cleanup = () => {
|
|
1323
|
+
process.removeListener("SIGINT", onInt);
|
|
1324
|
+
process.removeListener("SIGTERM", onTerm);
|
|
1325
|
+
if (stateWritten) {
|
|
1326
|
+
clearToolsServerState().catch(() => {
|
|
1327
|
+
});
|
|
1328
|
+
}
|
|
1329
|
+
};
|
|
1330
|
+
child.on("error", (err) => {
|
|
1331
|
+
cleanup();
|
|
1332
|
+
console.error(`argent server start: failed to spawn tool-server: ${err.message}`);
|
|
1333
|
+
process.exit(1);
|
|
1334
|
+
});
|
|
1335
|
+
child.on("exit", (code, signal) => {
|
|
1336
|
+
cleanup();
|
|
1337
|
+
const exitCode = code ?? (signal ? 128 + (signalNumber(signal) ?? 0) : 0);
|
|
1338
|
+
process.exit(exitCode);
|
|
1339
|
+
});
|
|
1340
|
+
});
|
|
1341
|
+
}
|
|
1342
|
+
function signalNumber(signal) {
|
|
1343
|
+
const map = { SIGINT: 2, SIGTERM: 15, SIGHUP: 1, SIGKILL: 9 };
|
|
1344
|
+
return map[signal] ?? null;
|
|
1345
|
+
}
|
|
1346
|
+
async function server(argv, options) {
|
|
699
1347
|
const sub = argv[0];
|
|
700
1348
|
const json = argv.includes("--json");
|
|
701
1349
|
const follow = argv.includes("-f") || argv.includes("--follow");
|
|
702
1350
|
if (!sub || sub === "--help" || sub === "-h") {
|
|
703
1351
|
console.log(`Usage:
|
|
1352
|
+
argent server start [flags] Spawn a long-lived tool-server (see --help)
|
|
704
1353
|
argent server status [--json] Show tool-server pid, port, and health
|
|
705
1354
|
argent server stop Terminate the running tool-server
|
|
706
1355
|
argent server logs [-f] Print (or follow) the tool-server log
|
|
@@ -708,6 +1357,9 @@ async function server(argv) {
|
|
|
708
1357
|
return;
|
|
709
1358
|
}
|
|
710
1359
|
switch (sub) {
|
|
1360
|
+
case "start":
|
|
1361
|
+
await startCmd(argv.slice(1), options?.paths);
|
|
1362
|
+
return;
|
|
711
1363
|
case "status":
|
|
712
1364
|
await statusCmd(json);
|
|
713
1365
|
return;
|
|
@@ -722,8 +1374,1644 @@ async function server(argv) {
|
|
|
722
1374
|
process.exit(1);
|
|
723
1375
|
}
|
|
724
1376
|
}
|
|
1377
|
+
|
|
1378
|
+
// ../../node_modules/@clack/core/dist/index.mjs
|
|
1379
|
+
import { styleText as v } from "node:util";
|
|
1380
|
+
import { stdout as x, stdin as D } from "node:process";
|
|
1381
|
+
import * as b from "node:readline";
|
|
1382
|
+
import E from "node:readline";
|
|
1383
|
+
|
|
1384
|
+
// ../../node_modules/fast-string-truncated-width/dist/utils.js
|
|
1385
|
+
var getCodePointsLength = /* @__PURE__ */ (() => {
|
|
1386
|
+
const SURROGATE_PAIR_RE = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
|
|
1387
|
+
return (input) => {
|
|
1388
|
+
let surrogatePairsNr = 0;
|
|
1389
|
+
SURROGATE_PAIR_RE.lastIndex = 0;
|
|
1390
|
+
while (SURROGATE_PAIR_RE.test(input)) {
|
|
1391
|
+
surrogatePairsNr += 1;
|
|
1392
|
+
}
|
|
1393
|
+
return input.length - surrogatePairsNr;
|
|
1394
|
+
};
|
|
1395
|
+
})();
|
|
1396
|
+
var isFullWidth = (x3) => {
|
|
1397
|
+
return x3 === 12288 || x3 >= 65281 && x3 <= 65376 || x3 >= 65504 && x3 <= 65510;
|
|
1398
|
+
};
|
|
1399
|
+
var isWideNotCJKTNotEmoji = (x3) => {
|
|
1400
|
+
return x3 === 8987 || x3 === 9001 || x3 >= 12272 && x3 <= 12287 || x3 >= 12289 && x3 <= 12350 || x3 >= 12441 && x3 <= 12543 || x3 >= 12549 && x3 <= 12591 || x3 >= 12593 && x3 <= 12686 || x3 >= 12688 && x3 <= 12771 || x3 >= 12783 && x3 <= 12830 || x3 >= 12832 && x3 <= 12871 || x3 >= 12880 && x3 <= 19903 || x3 >= 65040 && x3 <= 65049 || x3 >= 65072 && x3 <= 65106 || x3 >= 65108 && x3 <= 65126 || x3 >= 65128 && x3 <= 65131 || x3 >= 127488 && x3 <= 127490 || x3 >= 127504 && x3 <= 127547 || x3 >= 127552 && x3 <= 127560 || x3 >= 131072 && x3 <= 196605 || x3 >= 196608 && x3 <= 262141;
|
|
1401
|
+
};
|
|
1402
|
+
|
|
1403
|
+
// ../../node_modules/fast-string-truncated-width/dist/index.js
|
|
1404
|
+
var ANSI_RE = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]|\u001b\]8;[^;]*;.*?(?:\u0007|\u001b\u005c)/y;
|
|
1405
|
+
var CONTROL_RE = /[\x00-\x08\x0A-\x1F\x7F-\x9F]{1,1000}/y;
|
|
1406
|
+
var CJKT_WIDE_RE = /(?:(?![\uFF61-\uFF9F\uFF00-\uFFEF])[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}\p{Script=Tangut}]){1,1000}/yu;
|
|
1407
|
+
var TAB_RE = /\t{1,1000}/y;
|
|
1408
|
+
var EMOJI_RE = new RegExp("[\\u{1F1E6}-\\u{1F1FF}]{2}|\\u{1F3F4}[\\u{E0061}-\\u{E007A}]{2}[\\u{E0030}-\\u{E0039}\\u{E0061}-\\u{E007A}]{1,3}\\u{E007F}|(?:\\p{Emoji}\\uFE0F\\u20E3?|\\p{Emoji_Modifier_Base}\\p{Emoji_Modifier}?|\\p{Emoji_Presentation})(?:\\u200D(?:\\p{Emoji_Modifier_Base}\\p{Emoji_Modifier}?|\\p{Emoji_Presentation}|\\p{Emoji}\\uFE0F\\u20E3?))*", "yu");
|
|
1409
|
+
var LATIN_RE = /(?:[\x20-\x7E\xA0-\xFF](?!\uFE0F)){1,1000}/y;
|
|
1410
|
+
var MODIFIER_RE = new RegExp("\\p{M}+", "gu");
|
|
1411
|
+
var NO_TRUNCATION = { limit: Infinity, ellipsis: "" };
|
|
1412
|
+
var getStringTruncatedWidth = (input, truncationOptions = {}, widthOptions = {}) => {
|
|
1413
|
+
const LIMIT = truncationOptions.limit ?? Infinity;
|
|
1414
|
+
const ELLIPSIS = truncationOptions.ellipsis ?? "";
|
|
1415
|
+
const ELLIPSIS_WIDTH = truncationOptions?.ellipsisWidth ?? (ELLIPSIS ? getStringTruncatedWidth(ELLIPSIS, NO_TRUNCATION, widthOptions).width : 0);
|
|
1416
|
+
const ANSI_WIDTH = 0;
|
|
1417
|
+
const CONTROL_WIDTH = widthOptions.controlWidth ?? 0;
|
|
1418
|
+
const TAB_WIDTH = widthOptions.tabWidth ?? 8;
|
|
1419
|
+
const EMOJI_WIDTH = widthOptions.emojiWidth ?? 2;
|
|
1420
|
+
const FULL_WIDTH_WIDTH = 2;
|
|
1421
|
+
const REGULAR_WIDTH = widthOptions.regularWidth ?? 1;
|
|
1422
|
+
const WIDE_WIDTH = widthOptions.wideWidth ?? FULL_WIDTH_WIDTH;
|
|
1423
|
+
const PARSE_BLOCKS = [
|
|
1424
|
+
[LATIN_RE, REGULAR_WIDTH],
|
|
1425
|
+
[ANSI_RE, ANSI_WIDTH],
|
|
1426
|
+
[CONTROL_RE, CONTROL_WIDTH],
|
|
1427
|
+
[TAB_RE, TAB_WIDTH],
|
|
1428
|
+
[EMOJI_RE, EMOJI_WIDTH],
|
|
1429
|
+
[CJKT_WIDE_RE, WIDE_WIDTH]
|
|
1430
|
+
];
|
|
1431
|
+
let indexPrev = 0;
|
|
1432
|
+
let index = 0;
|
|
1433
|
+
let length = input.length;
|
|
1434
|
+
let lengthExtra = 0;
|
|
1435
|
+
let truncationEnabled = false;
|
|
1436
|
+
let truncationIndex = length;
|
|
1437
|
+
let truncationLimit = Math.max(0, LIMIT - ELLIPSIS_WIDTH);
|
|
1438
|
+
let unmatchedStart = 0;
|
|
1439
|
+
let unmatchedEnd = 0;
|
|
1440
|
+
let width = 0;
|
|
1441
|
+
let widthExtra = 0;
|
|
1442
|
+
outer: while (true) {
|
|
1443
|
+
if (unmatchedEnd > unmatchedStart || index >= length && index > indexPrev) {
|
|
1444
|
+
const unmatched = input.slice(unmatchedStart, unmatchedEnd) || input.slice(indexPrev, index);
|
|
1445
|
+
lengthExtra = 0;
|
|
1446
|
+
for (const char of unmatched.replaceAll(MODIFIER_RE, "")) {
|
|
1447
|
+
const codePoint = char.codePointAt(0) || 0;
|
|
1448
|
+
if (isFullWidth(codePoint)) {
|
|
1449
|
+
widthExtra = FULL_WIDTH_WIDTH;
|
|
1450
|
+
} else if (isWideNotCJKTNotEmoji(codePoint)) {
|
|
1451
|
+
widthExtra = WIDE_WIDTH;
|
|
1452
|
+
} else {
|
|
1453
|
+
widthExtra = REGULAR_WIDTH;
|
|
1454
|
+
}
|
|
1455
|
+
if (width + widthExtra > truncationLimit) {
|
|
1456
|
+
truncationIndex = Math.min(truncationIndex, Math.max(unmatchedStart, indexPrev) + lengthExtra);
|
|
1457
|
+
}
|
|
1458
|
+
if (width + widthExtra > LIMIT) {
|
|
1459
|
+
truncationEnabled = true;
|
|
1460
|
+
break outer;
|
|
1461
|
+
}
|
|
1462
|
+
lengthExtra += char.length;
|
|
1463
|
+
width += widthExtra;
|
|
1464
|
+
}
|
|
1465
|
+
unmatchedStart = unmatchedEnd = 0;
|
|
1466
|
+
}
|
|
1467
|
+
if (index >= length) {
|
|
1468
|
+
break outer;
|
|
1469
|
+
}
|
|
1470
|
+
for (let i = 0, l = PARSE_BLOCKS.length; i < l; i++) {
|
|
1471
|
+
const [BLOCK_RE, BLOCK_WIDTH] = PARSE_BLOCKS[i];
|
|
1472
|
+
BLOCK_RE.lastIndex = index;
|
|
1473
|
+
if (BLOCK_RE.test(input)) {
|
|
1474
|
+
lengthExtra = BLOCK_RE === CJKT_WIDE_RE ? getCodePointsLength(input.slice(index, BLOCK_RE.lastIndex)) : BLOCK_RE === EMOJI_RE ? 1 : BLOCK_RE.lastIndex - index;
|
|
1475
|
+
widthExtra = lengthExtra * BLOCK_WIDTH;
|
|
1476
|
+
if (width + widthExtra > truncationLimit) {
|
|
1477
|
+
truncationIndex = Math.min(truncationIndex, index + Math.floor((truncationLimit - width) / BLOCK_WIDTH));
|
|
1478
|
+
}
|
|
1479
|
+
if (width + widthExtra > LIMIT) {
|
|
1480
|
+
truncationEnabled = true;
|
|
1481
|
+
break outer;
|
|
1482
|
+
}
|
|
1483
|
+
width += widthExtra;
|
|
1484
|
+
unmatchedStart = indexPrev;
|
|
1485
|
+
unmatchedEnd = index;
|
|
1486
|
+
index = indexPrev = BLOCK_RE.lastIndex;
|
|
1487
|
+
continue outer;
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
index += 1;
|
|
1491
|
+
}
|
|
1492
|
+
return {
|
|
1493
|
+
width: truncationEnabled ? truncationLimit : width,
|
|
1494
|
+
index: truncationEnabled ? truncationIndex : length,
|
|
1495
|
+
truncated: truncationEnabled,
|
|
1496
|
+
ellipsed: truncationEnabled && LIMIT >= ELLIPSIS_WIDTH
|
|
1497
|
+
};
|
|
1498
|
+
};
|
|
1499
|
+
var dist_default = getStringTruncatedWidth;
|
|
1500
|
+
|
|
1501
|
+
// ../../node_modules/fast-string-width/dist/index.js
|
|
1502
|
+
var NO_TRUNCATION2 = {
|
|
1503
|
+
limit: Infinity,
|
|
1504
|
+
ellipsis: "",
|
|
1505
|
+
ellipsisWidth: 0
|
|
1506
|
+
};
|
|
1507
|
+
var fastStringWidth = (input, options = {}) => {
|
|
1508
|
+
return dist_default(input, NO_TRUNCATION2, options).width;
|
|
1509
|
+
};
|
|
1510
|
+
var dist_default2 = fastStringWidth;
|
|
1511
|
+
|
|
1512
|
+
// ../../node_modules/fast-wrap-ansi/lib/main.js
|
|
1513
|
+
var ESC = "\x1B";
|
|
1514
|
+
var CSI = "\x9B";
|
|
1515
|
+
var END_CODE = 39;
|
|
1516
|
+
var ANSI_ESCAPE_BELL = "\x07";
|
|
1517
|
+
var ANSI_CSI = "[";
|
|
1518
|
+
var ANSI_OSC = "]";
|
|
1519
|
+
var ANSI_SGR_TERMINATOR = "m";
|
|
1520
|
+
var ANSI_ESCAPE_LINK = `${ANSI_OSC}8;;`;
|
|
1521
|
+
var GROUP_REGEX = new RegExp(`(?:\\${ANSI_CSI}(?<code>\\d+)m|\\${ANSI_ESCAPE_LINK}(?<uri>.*)${ANSI_ESCAPE_BELL})`, "y");
|
|
1522
|
+
var getClosingCode = (openingCode) => {
|
|
1523
|
+
if (openingCode >= 30 && openingCode <= 37)
|
|
1524
|
+
return 39;
|
|
1525
|
+
if (openingCode >= 90 && openingCode <= 97)
|
|
1526
|
+
return 39;
|
|
1527
|
+
if (openingCode >= 40 && openingCode <= 47)
|
|
1528
|
+
return 49;
|
|
1529
|
+
if (openingCode >= 100 && openingCode <= 107)
|
|
1530
|
+
return 49;
|
|
1531
|
+
if (openingCode === 1 || openingCode === 2)
|
|
1532
|
+
return 22;
|
|
1533
|
+
if (openingCode === 3)
|
|
1534
|
+
return 23;
|
|
1535
|
+
if (openingCode === 4)
|
|
1536
|
+
return 24;
|
|
1537
|
+
if (openingCode === 7)
|
|
1538
|
+
return 27;
|
|
1539
|
+
if (openingCode === 8)
|
|
1540
|
+
return 28;
|
|
1541
|
+
if (openingCode === 9)
|
|
1542
|
+
return 29;
|
|
1543
|
+
if (openingCode === 0)
|
|
1544
|
+
return 0;
|
|
1545
|
+
return void 0;
|
|
1546
|
+
};
|
|
1547
|
+
var wrapAnsiCode = (code) => `${ESC}${ANSI_CSI}${code}${ANSI_SGR_TERMINATOR}`;
|
|
1548
|
+
var wrapAnsiHyperlink = (url) => `${ESC}${ANSI_ESCAPE_LINK}${url}${ANSI_ESCAPE_BELL}`;
|
|
1549
|
+
var wrapWord = (rows, word, columns) => {
|
|
1550
|
+
const characters = word[Symbol.iterator]();
|
|
1551
|
+
let isInsideEscape = false;
|
|
1552
|
+
let isInsideLinkEscape = false;
|
|
1553
|
+
let lastRow = rows.at(-1);
|
|
1554
|
+
let visible = lastRow === void 0 ? 0 : dist_default2(lastRow);
|
|
1555
|
+
let currentCharacter = characters.next();
|
|
1556
|
+
let nextCharacter = characters.next();
|
|
1557
|
+
let rawCharacterIndex = 0;
|
|
1558
|
+
while (!currentCharacter.done) {
|
|
1559
|
+
const character = currentCharacter.value;
|
|
1560
|
+
const characterLength = dist_default2(character);
|
|
1561
|
+
if (visible + characterLength <= columns) {
|
|
1562
|
+
rows[rows.length - 1] += character;
|
|
1563
|
+
} else {
|
|
1564
|
+
rows.push(character);
|
|
1565
|
+
visible = 0;
|
|
1566
|
+
}
|
|
1567
|
+
if (character === ESC || character === CSI) {
|
|
1568
|
+
isInsideEscape = true;
|
|
1569
|
+
isInsideLinkEscape = word.startsWith(ANSI_ESCAPE_LINK, rawCharacterIndex + 1);
|
|
1570
|
+
}
|
|
1571
|
+
if (isInsideEscape) {
|
|
1572
|
+
if (isInsideLinkEscape) {
|
|
1573
|
+
if (character === ANSI_ESCAPE_BELL) {
|
|
1574
|
+
isInsideEscape = false;
|
|
1575
|
+
isInsideLinkEscape = false;
|
|
1576
|
+
}
|
|
1577
|
+
} else if (character === ANSI_SGR_TERMINATOR) {
|
|
1578
|
+
isInsideEscape = false;
|
|
1579
|
+
}
|
|
1580
|
+
} else {
|
|
1581
|
+
visible += characterLength;
|
|
1582
|
+
if (visible === columns && !nextCharacter.done) {
|
|
1583
|
+
rows.push("");
|
|
1584
|
+
visible = 0;
|
|
1585
|
+
}
|
|
1586
|
+
}
|
|
1587
|
+
currentCharacter = nextCharacter;
|
|
1588
|
+
nextCharacter = characters.next();
|
|
1589
|
+
rawCharacterIndex += character.length;
|
|
1590
|
+
}
|
|
1591
|
+
lastRow = rows.at(-1);
|
|
1592
|
+
if (!visible && lastRow !== void 0 && lastRow.length && rows.length > 1) {
|
|
1593
|
+
rows[rows.length - 2] += rows.pop();
|
|
1594
|
+
}
|
|
1595
|
+
};
|
|
1596
|
+
var stringVisibleTrimSpacesRight = (string) => {
|
|
1597
|
+
const words = string.split(" ");
|
|
1598
|
+
let last = words.length;
|
|
1599
|
+
while (last) {
|
|
1600
|
+
if (dist_default2(words[last - 1])) {
|
|
1601
|
+
break;
|
|
1602
|
+
}
|
|
1603
|
+
last--;
|
|
1604
|
+
}
|
|
1605
|
+
if (last === words.length) {
|
|
1606
|
+
return string;
|
|
1607
|
+
}
|
|
1608
|
+
return words.slice(0, last).join(" ") + words.slice(last).join("");
|
|
1609
|
+
};
|
|
1610
|
+
var exec = (string, columns, options = {}) => {
|
|
1611
|
+
if (options.trim !== false && string.trim() === "") {
|
|
1612
|
+
return "";
|
|
1613
|
+
}
|
|
1614
|
+
let returnValue = "";
|
|
1615
|
+
let escapeCode;
|
|
1616
|
+
let escapeUrl;
|
|
1617
|
+
const words = string.split(" ");
|
|
1618
|
+
let rows = [""];
|
|
1619
|
+
let rowLength = 0;
|
|
1620
|
+
for (let index = 0; index < words.length; index++) {
|
|
1621
|
+
const word = words[index];
|
|
1622
|
+
if (options.trim !== false) {
|
|
1623
|
+
const row = rows.at(-1) ?? "";
|
|
1624
|
+
const trimmed = row.trimStart();
|
|
1625
|
+
if (row.length !== trimmed.length) {
|
|
1626
|
+
rows[rows.length - 1] = trimmed;
|
|
1627
|
+
rowLength = dist_default2(trimmed);
|
|
1628
|
+
}
|
|
1629
|
+
}
|
|
1630
|
+
if (index !== 0) {
|
|
1631
|
+
if (rowLength >= columns && (options.wordWrap === false || options.trim === false)) {
|
|
1632
|
+
rows.push("");
|
|
1633
|
+
rowLength = 0;
|
|
1634
|
+
}
|
|
1635
|
+
if (rowLength || options.trim === false) {
|
|
1636
|
+
rows[rows.length - 1] += " ";
|
|
1637
|
+
rowLength++;
|
|
1638
|
+
}
|
|
1639
|
+
}
|
|
1640
|
+
const wordLength = dist_default2(word);
|
|
1641
|
+
if (options.hard && wordLength > columns) {
|
|
1642
|
+
const remainingColumns = columns - rowLength;
|
|
1643
|
+
const breaksStartingThisLine = 1 + Math.floor((wordLength - remainingColumns - 1) / columns);
|
|
1644
|
+
const breaksStartingNextLine = Math.floor((wordLength - 1) / columns);
|
|
1645
|
+
if (breaksStartingNextLine < breaksStartingThisLine) {
|
|
1646
|
+
rows.push("");
|
|
1647
|
+
}
|
|
1648
|
+
wrapWord(rows, word, columns);
|
|
1649
|
+
rowLength = dist_default2(rows.at(-1) ?? "");
|
|
1650
|
+
continue;
|
|
1651
|
+
}
|
|
1652
|
+
if (rowLength + wordLength > columns && rowLength && wordLength) {
|
|
1653
|
+
if (options.wordWrap === false && rowLength < columns) {
|
|
1654
|
+
wrapWord(rows, word, columns);
|
|
1655
|
+
rowLength = dist_default2(rows.at(-1) ?? "");
|
|
1656
|
+
continue;
|
|
1657
|
+
}
|
|
1658
|
+
rows.push("");
|
|
1659
|
+
rowLength = 0;
|
|
1660
|
+
}
|
|
1661
|
+
if (rowLength + wordLength > columns && options.wordWrap === false) {
|
|
1662
|
+
wrapWord(rows, word, columns);
|
|
1663
|
+
rowLength = dist_default2(rows.at(-1) ?? "");
|
|
1664
|
+
continue;
|
|
1665
|
+
}
|
|
1666
|
+
rows[rows.length - 1] += word;
|
|
1667
|
+
rowLength += wordLength;
|
|
1668
|
+
}
|
|
1669
|
+
if (options.trim !== false) {
|
|
1670
|
+
rows = rows.map((row) => stringVisibleTrimSpacesRight(row));
|
|
1671
|
+
}
|
|
1672
|
+
const preString = rows.join("\n");
|
|
1673
|
+
let inSurrogate = false;
|
|
1674
|
+
for (let i = 0; i < preString.length; i++) {
|
|
1675
|
+
const character = preString[i];
|
|
1676
|
+
returnValue += character;
|
|
1677
|
+
if (!inSurrogate) {
|
|
1678
|
+
inSurrogate = character >= "\uD800" && character <= "\uDBFF";
|
|
1679
|
+
if (inSurrogate) {
|
|
1680
|
+
continue;
|
|
1681
|
+
}
|
|
1682
|
+
} else {
|
|
1683
|
+
inSurrogate = false;
|
|
1684
|
+
}
|
|
1685
|
+
if (character === ESC || character === CSI) {
|
|
1686
|
+
GROUP_REGEX.lastIndex = i + 1;
|
|
1687
|
+
const groupsResult = GROUP_REGEX.exec(preString);
|
|
1688
|
+
const groups = groupsResult?.groups;
|
|
1689
|
+
if (groups?.code !== void 0) {
|
|
1690
|
+
const code = Number.parseFloat(groups.code);
|
|
1691
|
+
escapeCode = code === END_CODE ? void 0 : code;
|
|
1692
|
+
} else if (groups?.uri !== void 0) {
|
|
1693
|
+
escapeUrl = groups.uri.length === 0 ? void 0 : groups.uri;
|
|
1694
|
+
}
|
|
1695
|
+
}
|
|
1696
|
+
if (preString[i + 1] === "\n") {
|
|
1697
|
+
if (escapeUrl) {
|
|
1698
|
+
returnValue += wrapAnsiHyperlink("");
|
|
1699
|
+
}
|
|
1700
|
+
const closingCode = escapeCode ? getClosingCode(escapeCode) : void 0;
|
|
1701
|
+
if (escapeCode && closingCode) {
|
|
1702
|
+
returnValue += wrapAnsiCode(closingCode);
|
|
1703
|
+
}
|
|
1704
|
+
} else if (character === "\n") {
|
|
1705
|
+
if (escapeCode && getClosingCode(escapeCode)) {
|
|
1706
|
+
returnValue += wrapAnsiCode(escapeCode);
|
|
1707
|
+
}
|
|
1708
|
+
if (escapeUrl) {
|
|
1709
|
+
returnValue += wrapAnsiHyperlink(escapeUrl);
|
|
1710
|
+
}
|
|
1711
|
+
}
|
|
1712
|
+
}
|
|
1713
|
+
return returnValue;
|
|
1714
|
+
};
|
|
1715
|
+
var CRLF_OR_LF = /\r?\n/;
|
|
1716
|
+
function wrapAnsi(string, columns, options) {
|
|
1717
|
+
return String(string).normalize().split(CRLF_OR_LF).map((line) => exec(line, columns, options)).join("\n");
|
|
1718
|
+
}
|
|
1719
|
+
|
|
1720
|
+
// ../../node_modules/@clack/core/dist/index.mjs
|
|
1721
|
+
var import_sisteransi = __toESM(require_src(), 1);
|
|
1722
|
+
import { ReadStream as O } from "node:tty";
|
|
1723
|
+
function f(r, t, s) {
|
|
1724
|
+
if (!s.some((o) => !o.disabled)) return r;
|
|
1725
|
+
const e2 = r + t, i = Math.max(s.length - 1, 0), n = e2 < 0 ? i : e2 > i ? 0 : e2;
|
|
1726
|
+
return s[n].disabled ? f(n, t < 0 ? -1 : 1, s) : n;
|
|
1727
|
+
}
|
|
1728
|
+
var G = ["up", "down", "left", "right", "space", "enter", "cancel"];
|
|
1729
|
+
var K = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
|
|
1730
|
+
var h = { actions: new Set(G), aliases: /* @__PURE__ */ new Map([["k", "up"], ["j", "down"], ["h", "left"], ["l", "right"], ["", "cancel"], ["escape", "cancel"]]), messages: { cancel: "Canceled", error: "Something went wrong" }, withGuide: true, date: { monthNames: [...K], messages: { required: "Please enter a valid date", invalidMonth: "There are only 12 months in a year", invalidDay: (r, t) => `There are only ${r} days in ${t}`, afterMin: (r) => `Date must be on or after ${r.toISOString().slice(0, 10)}`, beforeMax: (r) => `Date must be on or before ${r.toISOString().slice(0, 10)}` } } };
|
|
1731
|
+
function C(r, t) {
|
|
1732
|
+
if (typeof r == "string") return h.aliases.get(r) === t;
|
|
1733
|
+
for (const s of r) if (s !== void 0 && C(s, t)) return true;
|
|
1734
|
+
return false;
|
|
1735
|
+
}
|
|
1736
|
+
function z(r, t) {
|
|
1737
|
+
if (r === t) return;
|
|
1738
|
+
const s = r.split(`
|
|
1739
|
+
`), e2 = t.split(`
|
|
1740
|
+
`), i = Math.max(s.length, e2.length), n = [];
|
|
1741
|
+
for (let o = 0; o < i; o++) s[o] !== e2[o] && n.push(o);
|
|
1742
|
+
return { lines: n, numLinesBefore: s.length, numLinesAfter: e2.length, numLines: i };
|
|
1743
|
+
}
|
|
1744
|
+
var Y = globalThis.process.platform.startsWith("win");
|
|
1745
|
+
var k = /* @__PURE__ */ Symbol("clack:cancel");
|
|
1746
|
+
function q(r) {
|
|
1747
|
+
return r === k;
|
|
1748
|
+
}
|
|
1749
|
+
function w(r, t) {
|
|
1750
|
+
const s = r;
|
|
1751
|
+
s.isTTY && s.setRawMode(t);
|
|
1752
|
+
}
|
|
1753
|
+
function R({ input: r = D, output: t = x, overwrite: s = true, hideCursor: e2 = true } = {}) {
|
|
1754
|
+
const i = b.createInterface({ input: r, output: t, prompt: "", tabSize: 1 });
|
|
1755
|
+
b.emitKeypressEvents(r, i), r instanceof O && r.isTTY && r.setRawMode(true);
|
|
1756
|
+
const n = (o, { name: u, sequence: a }) => {
|
|
1757
|
+
const l = String(o);
|
|
1758
|
+
if (C([l, u, a], "cancel")) {
|
|
1759
|
+
e2 && t.write(import_sisteransi.cursor.show), process.exit(0);
|
|
1760
|
+
return;
|
|
1761
|
+
}
|
|
1762
|
+
if (!s) return;
|
|
1763
|
+
const c = u === "return" ? 0 : -1, y = u === "return" ? -1 : 0;
|
|
1764
|
+
b.moveCursor(t, c, y, () => {
|
|
1765
|
+
b.clearLine(t, 1, () => {
|
|
1766
|
+
r.once("keypress", n);
|
|
1767
|
+
});
|
|
1768
|
+
});
|
|
1769
|
+
};
|
|
1770
|
+
return e2 && t.write(import_sisteransi.cursor.hide), r.once("keypress", n), () => {
|
|
1771
|
+
r.off("keypress", n), e2 && t.write(import_sisteransi.cursor.show), r instanceof O && r.isTTY && !Y && r.setRawMode(false), i.terminal = false, i.close();
|
|
1772
|
+
};
|
|
1773
|
+
}
|
|
1774
|
+
var A = (r) => "columns" in r && typeof r.columns == "number" ? r.columns : 80;
|
|
1775
|
+
var L = (r) => "rows" in r && typeof r.rows == "number" ? r.rows : 20;
|
|
1776
|
+
function W(r, t, s, e2 = s, i = s, n) {
|
|
1777
|
+
const o = A(r ?? x);
|
|
1778
|
+
return wrapAnsi(t, o - s.length, { hard: true, trim: false }).split(`
|
|
1779
|
+
`).map((u, a, l) => {
|
|
1780
|
+
const c = n ? n(u, a) : u;
|
|
1781
|
+
return a === 0 ? `${e2}${c}` : a === l.length - 1 ? `${i}${c}` : `${s}${c}`;
|
|
1782
|
+
}).join(`
|
|
1783
|
+
`);
|
|
1784
|
+
}
|
|
1785
|
+
var m = class {
|
|
1786
|
+
input;
|
|
1787
|
+
output;
|
|
1788
|
+
_abortSignal;
|
|
1789
|
+
rl;
|
|
1790
|
+
opts;
|
|
1791
|
+
_render;
|
|
1792
|
+
_track = false;
|
|
1793
|
+
_prevFrame = "";
|
|
1794
|
+
_subscribers = /* @__PURE__ */ new Map();
|
|
1795
|
+
_cursor = 0;
|
|
1796
|
+
state = "initial";
|
|
1797
|
+
error = "";
|
|
1798
|
+
value;
|
|
1799
|
+
userInput = "";
|
|
1800
|
+
constructor(t, s = true) {
|
|
1801
|
+
const { input: e2 = D, output: i = x, render: n, signal: o, ...u } = t;
|
|
1802
|
+
this.opts = u, this.onKeypress = this.onKeypress.bind(this), this.close = this.close.bind(this), this.render = this.render.bind(this), this._render = n.bind(this), this._track = s, this._abortSignal = o, this.input = e2, this.output = i;
|
|
1803
|
+
}
|
|
1804
|
+
unsubscribe() {
|
|
1805
|
+
this._subscribers.clear();
|
|
1806
|
+
}
|
|
1807
|
+
setSubscriber(t, s) {
|
|
1808
|
+
const e2 = this._subscribers.get(t) ?? [];
|
|
1809
|
+
e2.push(s), this._subscribers.set(t, e2);
|
|
1810
|
+
}
|
|
1811
|
+
on(t, s) {
|
|
1812
|
+
this.setSubscriber(t, { cb: s });
|
|
1813
|
+
}
|
|
1814
|
+
once(t, s) {
|
|
1815
|
+
this.setSubscriber(t, { cb: s, once: true });
|
|
1816
|
+
}
|
|
1817
|
+
emit(t, ...s) {
|
|
1818
|
+
const e2 = this._subscribers.get(t) ?? [], i = [];
|
|
1819
|
+
for (const n of e2) n.cb(...s), n.once && i.push(() => e2.splice(e2.indexOf(n), 1));
|
|
1820
|
+
for (const n of i) n();
|
|
1821
|
+
}
|
|
1822
|
+
prompt() {
|
|
1823
|
+
return new Promise((t) => {
|
|
1824
|
+
if (this._abortSignal) {
|
|
1825
|
+
if (this._abortSignal.aborted) return this.state = "cancel", this.close(), t(k);
|
|
1826
|
+
this._abortSignal.addEventListener("abort", () => {
|
|
1827
|
+
this.state = "cancel", this.close();
|
|
1828
|
+
}, { once: true });
|
|
1829
|
+
}
|
|
1830
|
+
this.rl = E.createInterface({ input: this.input, tabSize: 2, prompt: "", escapeCodeTimeout: 50, terminal: true }), this.rl.prompt(), this.opts.initialUserInput !== void 0 && this._setUserInput(this.opts.initialUserInput, true), this.input.on("keypress", this.onKeypress), w(this.input, true), this.output.on("resize", this.render), this.render(), this.once("submit", () => {
|
|
1831
|
+
this.output.write(import_sisteransi.cursor.show), this.output.off("resize", this.render), w(this.input, false), t(this.value);
|
|
1832
|
+
}), this.once("cancel", () => {
|
|
1833
|
+
this.output.write(import_sisteransi.cursor.show), this.output.off("resize", this.render), w(this.input, false), t(k);
|
|
1834
|
+
});
|
|
1835
|
+
});
|
|
1836
|
+
}
|
|
1837
|
+
_isActionKey(t, s) {
|
|
1838
|
+
return t === " ";
|
|
1839
|
+
}
|
|
1840
|
+
_shouldSubmit(t, s) {
|
|
1841
|
+
return true;
|
|
1842
|
+
}
|
|
1843
|
+
_setValue(t) {
|
|
1844
|
+
this.value = t, this.emit("value", this.value);
|
|
1845
|
+
}
|
|
1846
|
+
_setUserInput(t, s) {
|
|
1847
|
+
this.userInput = t ?? "", this.emit("userInput", this.userInput), s && this._track && this.rl && (this.rl.write(this.userInput), this._cursor = this.rl.cursor);
|
|
1848
|
+
}
|
|
1849
|
+
_clearUserInput() {
|
|
1850
|
+
this.rl?.write(null, { ctrl: true, name: "u" }), this._setUserInput("");
|
|
1851
|
+
}
|
|
1852
|
+
onKeypress(t, s) {
|
|
1853
|
+
if (this._track && s.name !== "return" && (s.name && this._isActionKey(t, s) && this.rl?.write(null, { ctrl: true, name: "h" }), this._cursor = this.rl?.cursor ?? 0, this._setUserInput(this.rl?.line)), this.state === "error" && (this.state = "active"), s?.name && (!this._track && h.aliases.has(s.name) && this.emit("cursor", h.aliases.get(s.name)), h.actions.has(s.name) && this.emit("cursor", s.name)), t && (t.toLowerCase() === "y" || t.toLowerCase() === "n") && this.emit("confirm", t.toLowerCase() === "y"), this.emit("key", t?.toLowerCase(), s), s?.name === "return" && this._shouldSubmit(t, s)) {
|
|
1854
|
+
if (this.opts.validate) {
|
|
1855
|
+
const e2 = this.opts.validate(this.value);
|
|
1856
|
+
e2 && (this.error = e2 instanceof Error ? e2.message : e2, this.state = "error", this.rl?.write(this.userInput));
|
|
1857
|
+
}
|
|
1858
|
+
this.state !== "error" && (this.state = "submit");
|
|
1859
|
+
}
|
|
1860
|
+
C([t, s?.name, s?.sequence], "cancel") && (this.state = "cancel"), (this.state === "submit" || this.state === "cancel") && this.emit("finalize"), this.render(), (this.state === "submit" || this.state === "cancel") && this.close();
|
|
1861
|
+
}
|
|
1862
|
+
close() {
|
|
1863
|
+
this.input.unpipe(), this.input.removeListener("keypress", this.onKeypress), this.output.write(`
|
|
1864
|
+
`), w(this.input, false), this.rl?.close(), this.rl = void 0, this.emit(`${this.state}`, this.value), this.unsubscribe();
|
|
1865
|
+
}
|
|
1866
|
+
restoreCursor() {
|
|
1867
|
+
const t = wrapAnsi(this._prevFrame, process.stdout.columns, { hard: true, trim: false }).split(`
|
|
1868
|
+
`).length - 1;
|
|
1869
|
+
this.output.write(import_sisteransi.cursor.move(-999, t * -1));
|
|
1870
|
+
}
|
|
1871
|
+
render() {
|
|
1872
|
+
const t = wrapAnsi(this._render(this) ?? "", process.stdout.columns, { hard: true, trim: false });
|
|
1873
|
+
if (t !== this._prevFrame) {
|
|
1874
|
+
if (this.state === "initial") this.output.write(import_sisteransi.cursor.hide);
|
|
1875
|
+
else {
|
|
1876
|
+
const s = z(this._prevFrame, t), e2 = L(this.output);
|
|
1877
|
+
if (this.restoreCursor(), s) {
|
|
1878
|
+
const i = Math.max(0, s.numLinesAfter - e2), n = Math.max(0, s.numLinesBefore - e2);
|
|
1879
|
+
let o = s.lines.find((u) => u >= i);
|
|
1880
|
+
if (o === void 0) {
|
|
1881
|
+
this._prevFrame = t;
|
|
1882
|
+
return;
|
|
1883
|
+
}
|
|
1884
|
+
if (s.lines.length === 1) {
|
|
1885
|
+
this.output.write(import_sisteransi.cursor.move(0, o - n)), this.output.write(import_sisteransi.erase.lines(1));
|
|
1886
|
+
const u = t.split(`
|
|
1887
|
+
`);
|
|
1888
|
+
this.output.write(u[o]), this._prevFrame = t, this.output.write(import_sisteransi.cursor.move(0, u.length - o - 1));
|
|
1889
|
+
return;
|
|
1890
|
+
} else if (s.lines.length > 1) {
|
|
1891
|
+
if (i < n) o = i;
|
|
1892
|
+
else {
|
|
1893
|
+
const a = o - n;
|
|
1894
|
+
a > 0 && this.output.write(import_sisteransi.cursor.move(0, a));
|
|
1895
|
+
}
|
|
1896
|
+
this.output.write(import_sisteransi.erase.down());
|
|
1897
|
+
const u = t.split(`
|
|
1898
|
+
`).slice(o);
|
|
1899
|
+
this.output.write(u.join(`
|
|
1900
|
+
`)), this._prevFrame = t;
|
|
1901
|
+
return;
|
|
1902
|
+
}
|
|
1903
|
+
}
|
|
1904
|
+
this.output.write(import_sisteransi.erase.down());
|
|
1905
|
+
}
|
|
1906
|
+
this.output.write(t), this.state === "initial" && (this.state = "active"), this._prevFrame = t;
|
|
1907
|
+
}
|
|
1908
|
+
}
|
|
1909
|
+
};
|
|
1910
|
+
var X = class extends m {
|
|
1911
|
+
get cursor() {
|
|
1912
|
+
return this.value ? 0 : 1;
|
|
1913
|
+
}
|
|
1914
|
+
get _value() {
|
|
1915
|
+
return this.cursor === 0;
|
|
1916
|
+
}
|
|
1917
|
+
constructor(t) {
|
|
1918
|
+
super(t, false), this.value = !!t.initialValue, this.on("userInput", () => {
|
|
1919
|
+
this.value = this._value;
|
|
1920
|
+
}), this.on("confirm", (s) => {
|
|
1921
|
+
this.output.write(import_sisteransi.cursor.move(0, -1)), this.value = s, this.state = "submit", this.close();
|
|
1922
|
+
}), this.on("cursor", () => {
|
|
1923
|
+
this.value = !this.value;
|
|
1924
|
+
});
|
|
1925
|
+
}
|
|
1926
|
+
};
|
|
1927
|
+
var ut = class extends m {
|
|
1928
|
+
options;
|
|
1929
|
+
cursor = 0;
|
|
1930
|
+
get _selectedValue() {
|
|
1931
|
+
return this.options[this.cursor];
|
|
1932
|
+
}
|
|
1933
|
+
changeValue() {
|
|
1934
|
+
this.value = this._selectedValue.value;
|
|
1935
|
+
}
|
|
1936
|
+
constructor(t) {
|
|
1937
|
+
super(t, false), this.options = t.options;
|
|
1938
|
+
const s = this.options.findIndex(({ value: i }) => i === t.initialValue), e2 = s === -1 ? 0 : s;
|
|
1939
|
+
this.cursor = this.options[e2].disabled ? f(e2, 1, this.options) : e2, this.changeValue(), this.on("cursor", (i) => {
|
|
1940
|
+
switch (i) {
|
|
1941
|
+
case "left":
|
|
1942
|
+
case "up":
|
|
1943
|
+
this.cursor = f(this.cursor, -1, this.options);
|
|
1944
|
+
break;
|
|
1945
|
+
case "down":
|
|
1946
|
+
case "right":
|
|
1947
|
+
this.cursor = f(this.cursor, 1, this.options);
|
|
1948
|
+
break;
|
|
1949
|
+
}
|
|
1950
|
+
this.changeValue();
|
|
1951
|
+
});
|
|
1952
|
+
}
|
|
1953
|
+
};
|
|
1954
|
+
var ht = class extends m {
|
|
1955
|
+
get userInputWithCursor() {
|
|
1956
|
+
if (this.state === "submit") return this.userInput;
|
|
1957
|
+
const t = this.userInput;
|
|
1958
|
+
if (this.cursor >= t.length) return `${this.userInput}\u2588`;
|
|
1959
|
+
const s = t.slice(0, this.cursor), [e2, ...i] = t.slice(this.cursor);
|
|
1960
|
+
return `${s}${v("inverse", e2)}${i.join("")}`;
|
|
1961
|
+
}
|
|
1962
|
+
get cursor() {
|
|
1963
|
+
return this._cursor;
|
|
1964
|
+
}
|
|
1965
|
+
constructor(t) {
|
|
1966
|
+
super({ ...t, initialUserInput: t.initialUserInput ?? t.initialValue }), this.on("userInput", (s) => {
|
|
1967
|
+
this._setValue(s);
|
|
1968
|
+
}), this.on("finalize", () => {
|
|
1969
|
+
this.value || (this.value = t.defaultValue), this.value === void 0 && (this.value = "");
|
|
1970
|
+
});
|
|
1971
|
+
}
|
|
1972
|
+
};
|
|
1973
|
+
|
|
1974
|
+
// ../../node_modules/@clack/prompts/dist/index.mjs
|
|
1975
|
+
import { styleText as e, stripVTControlCharacters as nt2 } from "node:util";
|
|
1976
|
+
import V2 from "node:process";
|
|
1977
|
+
var import_sisteransi2 = __toESM(require_src(), 1);
|
|
1978
|
+
import { existsSync as Qt, lstatSync as wt, readdirSync as Zt } from "node:fs";
|
|
1979
|
+
import { dirname as bt, join as te } from "node:path";
|
|
1980
|
+
function ee() {
|
|
1981
|
+
return V2.platform !== "win32" ? V2.env.TERM !== "linux" : !!V2.env.CI || !!V2.env.WT_SESSION || !!V2.env.TERMINUS_SUBLIME || V2.env.ConEmuTask === "{cmd::Cmder}" || V2.env.TERM_PROGRAM === "Terminus-Sublime" || V2.env.TERM_PROGRAM === "vscode" || V2.env.TERM === "xterm-256color" || V2.env.TERM === "alacritty" || V2.env.TERMINAL_EMULATOR === "JetBrains-JediTerm";
|
|
1982
|
+
}
|
|
1983
|
+
var tt = ee();
|
|
1984
|
+
var ot2 = () => process.env.CI === "true";
|
|
1985
|
+
var w2 = (t, i) => tt ? t : i;
|
|
1986
|
+
var Tt = w2("\u25C6", "*");
|
|
1987
|
+
var at2 = w2("\u25A0", "x");
|
|
1988
|
+
var ut2 = w2("\u25B2", "x");
|
|
1989
|
+
var H = w2("\u25C7", "o");
|
|
1990
|
+
var lt = w2("\u250C", "T");
|
|
1991
|
+
var $ = w2("\u2502", "|");
|
|
1992
|
+
var x2 = w2("\u2514", "\u2014");
|
|
1993
|
+
var _t = w2("\u2510", "T");
|
|
1994
|
+
var xt = w2("\u2518", "\u2014");
|
|
1995
|
+
var z2 = w2("\u25CF", ">");
|
|
1996
|
+
var U = w2("\u25CB", " ");
|
|
1997
|
+
var et2 = w2("\u25FB", "[\u2022]");
|
|
1998
|
+
var K2 = w2("\u25FC", "[+]");
|
|
1999
|
+
var Y2 = w2("\u25FB", "[ ]");
|
|
2000
|
+
var Et = w2("\u25AA", "\u2022");
|
|
2001
|
+
var st = w2("\u2500", "-");
|
|
2002
|
+
var ct = w2("\u256E", "+");
|
|
2003
|
+
var Gt = w2("\u251C", "+");
|
|
2004
|
+
var $t = w2("\u256F", "+");
|
|
2005
|
+
var dt = w2("\u2570", "+");
|
|
2006
|
+
var Mt = w2("\u256D", "+");
|
|
2007
|
+
var ht2 = w2("\u25CF", "\u2022");
|
|
2008
|
+
var pt = w2("\u25C6", "*");
|
|
2009
|
+
var mt = w2("\u25B2", "!");
|
|
2010
|
+
var gt = w2("\u25A0", "x");
|
|
2011
|
+
var P = (t) => {
|
|
2012
|
+
switch (t) {
|
|
2013
|
+
case "initial":
|
|
2014
|
+
case "active":
|
|
2015
|
+
return e("cyan", Tt);
|
|
2016
|
+
case "cancel":
|
|
2017
|
+
return e("red", at2);
|
|
2018
|
+
case "error":
|
|
2019
|
+
return e("yellow", ut2);
|
|
2020
|
+
case "submit":
|
|
2021
|
+
return e("green", H);
|
|
2022
|
+
}
|
|
2023
|
+
};
|
|
2024
|
+
var yt = (t) => {
|
|
2025
|
+
switch (t) {
|
|
2026
|
+
case "initial":
|
|
2027
|
+
case "active":
|
|
2028
|
+
return e("cyan", $);
|
|
2029
|
+
case "cancel":
|
|
2030
|
+
return e("red", $);
|
|
2031
|
+
case "error":
|
|
2032
|
+
return e("yellow", $);
|
|
2033
|
+
case "submit":
|
|
2034
|
+
return e("green", $);
|
|
2035
|
+
}
|
|
2036
|
+
};
|
|
2037
|
+
var Ot = (t, i, s, r, u, n = false) => {
|
|
2038
|
+
let a = i, c = 0;
|
|
2039
|
+
if (n) for (let o = r - 1; o >= s && (a -= t[o].length, c++, !(a <= u)); o--) ;
|
|
2040
|
+
else for (let o = s; o < r && (a -= t[o].length, c++, !(a <= u)); o++) ;
|
|
2041
|
+
return { lineCount: a, removals: c };
|
|
2042
|
+
};
|
|
2043
|
+
var F = ({ cursor: t, options: i, style: s, output: r = process.stdout, maxItems: u = Number.POSITIVE_INFINITY, columnPadding: n = 0, rowPadding: a = 4 }) => {
|
|
2044
|
+
const c = A(r) - n, o = L(r), l = e("dim", "..."), d = Math.max(o - a, 0), g = Math.max(Math.min(u, d), 5);
|
|
2045
|
+
let p2 = 0;
|
|
2046
|
+
t >= g - 3 && (p2 = Math.max(Math.min(t - g + 3, i.length - g), 0));
|
|
2047
|
+
let f2 = g < i.length && p2 > 0, h2 = g < i.length && p2 + g < i.length;
|
|
2048
|
+
const I = Math.min(p2 + g, i.length), m2 = [];
|
|
2049
|
+
let y = 0;
|
|
2050
|
+
f2 && y++, h2 && y++;
|
|
2051
|
+
const v2 = p2 + (f2 ? 1 : 0), C2 = I - (h2 ? 1 : 0);
|
|
2052
|
+
for (let b2 = v2; b2 < C2; b2++) {
|
|
2053
|
+
const G2 = wrapAnsi(s(i[b2], b2 === t), c, { hard: true, trim: false }).split(`
|
|
2054
|
+
`);
|
|
2055
|
+
m2.push(G2), y += G2.length;
|
|
2056
|
+
}
|
|
2057
|
+
if (y > d) {
|
|
2058
|
+
let b2 = 0, G2 = 0, M = y;
|
|
2059
|
+
const N = t - v2;
|
|
2060
|
+
let O2 = d;
|
|
2061
|
+
const j2 = () => Ot(m2, M, 0, N, O2), k2 = () => Ot(m2, M, N + 1, m2.length, O2, true);
|
|
2062
|
+
f2 ? ({ lineCount: M, removals: b2 } = j2(), M > O2 && (h2 || (O2 -= 1), { lineCount: M, removals: G2 } = k2())) : (h2 || (O2 -= 1), { lineCount: M, removals: G2 } = k2(), M > O2 && (O2 -= 1, { lineCount: M, removals: b2 } = j2())), b2 > 0 && (f2 = true, m2.splice(0, b2)), G2 > 0 && (h2 = true, m2.splice(m2.length - G2, G2));
|
|
2063
|
+
}
|
|
2064
|
+
const S = [];
|
|
2065
|
+
f2 && S.push(l);
|
|
2066
|
+
for (const b2 of m2) for (const G2 of b2) S.push(G2);
|
|
2067
|
+
return h2 && S.push(l), S;
|
|
2068
|
+
};
|
|
2069
|
+
var ue = (t) => {
|
|
2070
|
+
const i = t.active ?? "Yes", s = t.inactive ?? "No";
|
|
2071
|
+
return new X({ active: i, inactive: s, signal: t.signal, input: t.input, output: t.output, initialValue: t.initialValue ?? true, render() {
|
|
2072
|
+
const r = t.withGuide ?? h.withGuide, u = `${P(this.state)} `, n = r ? `${e("gray", $)} ` : "", a = W(t.output, t.message, n, u), c = `${r ? `${e("gray", $)}
|
|
2073
|
+
` : ""}${a}
|
|
2074
|
+
`, o = this.value ? i : s;
|
|
2075
|
+
switch (this.state) {
|
|
2076
|
+
case "submit": {
|
|
2077
|
+
const l = r ? `${e("gray", $)} ` : "";
|
|
2078
|
+
return `${c}${l}${e("dim", o)}`;
|
|
2079
|
+
}
|
|
2080
|
+
case "cancel": {
|
|
2081
|
+
const l = r ? `${e("gray", $)} ` : "";
|
|
2082
|
+
return `${c}${l}${e(["strikethrough", "dim"], o)}${r ? `
|
|
2083
|
+
${e("gray", $)}` : ""}`;
|
|
2084
|
+
}
|
|
2085
|
+
default: {
|
|
2086
|
+
const l = r ? `${e("cyan", $)} ` : "", d = r ? e("cyan", x2) : "";
|
|
2087
|
+
return `${c}${l}${this.value ? `${e("green", z2)} ${i}` : `${e("dim", U)} ${e("dim", i)}`}${t.vertical ? r ? `
|
|
2088
|
+
${e("cyan", $)} ` : `
|
|
2089
|
+
` : ` ${e("dim", "/")} `}${this.value ? `${e("dim", U)} ${e("dim", s)}` : `${e("green", z2)} ${s}`}
|
|
2090
|
+
${d}
|
|
2091
|
+
`;
|
|
2092
|
+
}
|
|
2093
|
+
}
|
|
2094
|
+
} }).prompt();
|
|
2095
|
+
};
|
|
2096
|
+
var R2 = { message: (t = [], { symbol: i = e("gray", $), secondarySymbol: s = e("gray", $), output: r = process.stdout, spacing: u = 1, withGuide: n } = {}) => {
|
|
2097
|
+
const a = [], c = n ?? h.withGuide, o = c ? s : "", l = c ? `${i} ` : "", d = c ? `${s} ` : "";
|
|
2098
|
+
for (let p2 = 0; p2 < u; p2++) a.push(o);
|
|
2099
|
+
const g = Array.isArray(t) ? t : t.split(`
|
|
2100
|
+
`);
|
|
2101
|
+
if (g.length > 0) {
|
|
2102
|
+
const [p2, ...f2] = g;
|
|
2103
|
+
p2.length > 0 ? a.push(`${l}${p2}`) : a.push(c ? i : "");
|
|
2104
|
+
for (const h2 of f2) h2.length > 0 ? a.push(`${d}${h2}`) : a.push(c ? s : "");
|
|
2105
|
+
}
|
|
2106
|
+
r.write(`${a.join(`
|
|
2107
|
+
`)}
|
|
2108
|
+
`);
|
|
2109
|
+
}, info: (t, i) => {
|
|
2110
|
+
R2.message(t, { ...i, symbol: e("blue", ht2) });
|
|
2111
|
+
}, success: (t, i) => {
|
|
2112
|
+
R2.message(t, { ...i, symbol: e("green", pt) });
|
|
2113
|
+
}, step: (t, i) => {
|
|
2114
|
+
R2.message(t, { ...i, symbol: e("green", H) });
|
|
2115
|
+
}, warn: (t, i) => {
|
|
2116
|
+
R2.message(t, { ...i, symbol: e("yellow", mt) });
|
|
2117
|
+
}, warning: (t, i) => {
|
|
2118
|
+
R2.warn(t, i);
|
|
2119
|
+
}, error: (t, i) => {
|
|
2120
|
+
R2.message(t, { ...i, symbol: e("red", gt) });
|
|
2121
|
+
} };
|
|
2122
|
+
var me = (t = "", i) => {
|
|
2123
|
+
const s = i?.output ?? process.stdout, r = i?.withGuide ?? h.withGuide ? `${e("gray", x2)} ` : "";
|
|
2124
|
+
s.write(`${r}${e("red", t)}
|
|
2125
|
+
|
|
2126
|
+
`);
|
|
2127
|
+
};
|
|
2128
|
+
var ge = (t = "", i) => {
|
|
2129
|
+
const s = i?.output ?? process.stdout, r = i?.withGuide ?? h.withGuide ? `${e("gray", lt)} ` : "";
|
|
2130
|
+
s.write(`${r}${t}
|
|
2131
|
+
`);
|
|
2132
|
+
};
|
|
2133
|
+
var ye = (t = "", i) => {
|
|
2134
|
+
const s = i?.output ?? process.stdout, r = i?.withGuide ?? h.withGuide ? `${e("gray", $)}
|
|
2135
|
+
${e("gray", x2)} ` : "";
|
|
2136
|
+
s.write(`${r}${t}
|
|
2137
|
+
|
|
2138
|
+
`);
|
|
2139
|
+
};
|
|
2140
|
+
var Te = (t) => e("magenta", t);
|
|
2141
|
+
var ft = ({ indicator: t = "dots", onCancel: i, output: s = process.stdout, cancelMessage: r, errorMessage: u, frames: n = tt ? ["\u25D2", "\u25D0", "\u25D3", "\u25D1"] : ["\u2022", "o", "O", "0"], delay: a = tt ? 80 : 120, signal: c, ...o } = {}) => {
|
|
2142
|
+
const l = ot2();
|
|
2143
|
+
let d, g, p2 = false, f2 = false, h2 = "", I, m2 = performance.now();
|
|
2144
|
+
const y = A(s), v2 = o?.styleFrame ?? Te, C2 = (_) => {
|
|
2145
|
+
const A2 = _ > 1 ? u ?? h.messages.error : r ?? h.messages.cancel;
|
|
2146
|
+
f2 = _ === 1, p2 && (W2(A2, _), f2 && typeof i == "function" && i());
|
|
2147
|
+
}, S = () => C2(2), b2 = () => C2(1), G2 = () => {
|
|
2148
|
+
process.on("uncaughtExceptionMonitor", S), process.on("unhandledRejection", S), process.on("SIGINT", b2), process.on("SIGTERM", b2), process.on("exit", C2), c && c.addEventListener("abort", b2);
|
|
2149
|
+
}, M = () => {
|
|
2150
|
+
process.removeListener("uncaughtExceptionMonitor", S), process.removeListener("unhandledRejection", S), process.removeListener("SIGINT", b2), process.removeListener("SIGTERM", b2), process.removeListener("exit", C2), c && c.removeEventListener("abort", b2);
|
|
2151
|
+
}, N = () => {
|
|
2152
|
+
if (I === void 0) return;
|
|
2153
|
+
l && s.write(`
|
|
2154
|
+
`);
|
|
2155
|
+
const _ = wrapAnsi(I, y, { hard: true, trim: false }).split(`
|
|
2156
|
+
`);
|
|
2157
|
+
_.length > 1 && s.write(import_sisteransi2.cursor.up(_.length - 1)), s.write(import_sisteransi2.cursor.to(0)), s.write(import_sisteransi2.erase.down());
|
|
2158
|
+
}, O2 = (_) => _.replace(/\.+$/, ""), j2 = (_) => {
|
|
2159
|
+
const A2 = (performance.now() - _) / 1e3, L2 = Math.floor(A2 / 60), D2 = Math.floor(A2 % 60);
|
|
2160
|
+
return L2 > 0 ? `[${L2}m ${D2}s]` : `[${D2}s]`;
|
|
2161
|
+
}, k2 = o.withGuide ?? h.withGuide, rt2 = (_ = "") => {
|
|
2162
|
+
p2 = true, d = R({ output: s }), h2 = O2(_), m2 = performance.now(), k2 && s.write(`${e("gray", $)}
|
|
2163
|
+
`);
|
|
2164
|
+
let A2 = 0, L2 = 0;
|
|
2165
|
+
G2(), g = setInterval(() => {
|
|
2166
|
+
if (l && h2 === I) return;
|
|
2167
|
+
N(), I = h2;
|
|
2168
|
+
const D2 = v2(n[A2]);
|
|
2169
|
+
let Z;
|
|
2170
|
+
if (l) Z = `${D2} ${h2}...`;
|
|
2171
|
+
else if (t === "timer") Z = `${D2} ${h2} ${j2(m2)}`;
|
|
2172
|
+
else {
|
|
2173
|
+
const kt = ".".repeat(Math.floor(L2)).slice(0, 3);
|
|
2174
|
+
Z = `${D2} ${h2}${kt}`;
|
|
2175
|
+
}
|
|
2176
|
+
const Bt = wrapAnsi(Z, y, { hard: true, trim: false });
|
|
2177
|
+
s.write(Bt), A2 = A2 + 1 < n.length ? A2 + 1 : 0, L2 = L2 < 4 ? L2 + 0.125 : 0;
|
|
2178
|
+
}, a);
|
|
2179
|
+
}, W2 = (_ = "", A2 = 0, L2 = false) => {
|
|
2180
|
+
if (!p2) return;
|
|
2181
|
+
p2 = false, clearInterval(g), N();
|
|
2182
|
+
const D2 = A2 === 0 ? e("green", H) : A2 === 1 ? e("red", at2) : e("red", ut2);
|
|
2183
|
+
h2 = _ ?? h2, L2 || (t === "timer" ? s.write(`${D2} ${h2} ${j2(m2)}
|
|
2184
|
+
`) : s.write(`${D2} ${h2}
|
|
2185
|
+
`)), M(), d();
|
|
2186
|
+
};
|
|
2187
|
+
return { start: rt2, stop: (_ = "") => W2(_, 0), message: (_ = "") => {
|
|
2188
|
+
h2 = O2(_ ?? h2);
|
|
2189
|
+
}, cancel: (_ = "") => W2(_, 1), error: (_ = "") => W2(_, 2), clear: () => W2("", 0, true), get isCancelled() {
|
|
2190
|
+
return f2;
|
|
2191
|
+
} };
|
|
2192
|
+
};
|
|
2193
|
+
var jt = { light: w2("\u2500", "-"), heavy: w2("\u2501", "="), block: w2("\u2588", "#") };
|
|
2194
|
+
var it2 = (t, i) => t.includes(`
|
|
2195
|
+
`) ? t.split(`
|
|
2196
|
+
`).map((s) => i(s)).join(`
|
|
2197
|
+
`) : i(t);
|
|
2198
|
+
var xe = (t) => {
|
|
2199
|
+
const i = (s, r) => {
|
|
2200
|
+
const u = s.label ?? String(s.value);
|
|
2201
|
+
switch (r) {
|
|
2202
|
+
case "disabled":
|
|
2203
|
+
return `${e("gray", U)} ${it2(u, (n) => e("gray", n))}${s.hint ? ` ${e("dim", `(${s.hint ?? "disabled"})`)}` : ""}`;
|
|
2204
|
+
case "selected":
|
|
2205
|
+
return `${it2(u, (n) => e("dim", n))}`;
|
|
2206
|
+
case "active":
|
|
2207
|
+
return `${e("green", z2)} ${u}${s.hint ? ` ${e("dim", `(${s.hint})`)}` : ""}`;
|
|
2208
|
+
case "cancelled":
|
|
2209
|
+
return `${it2(u, (n) => e(["strikethrough", "dim"], n))}`;
|
|
2210
|
+
default:
|
|
2211
|
+
return `${e("dim", U)} ${it2(u, (n) => e("dim", n))}`;
|
|
2212
|
+
}
|
|
2213
|
+
};
|
|
2214
|
+
return new ut({ options: t.options, signal: t.signal, input: t.input, output: t.output, initialValue: t.initialValue, render() {
|
|
2215
|
+
const s = t.withGuide ?? h.withGuide, r = `${P(this.state)} `, u = `${yt(this.state)} `, n = W(t.output, t.message, u, r), a = `${s ? `${e("gray", $)}
|
|
2216
|
+
` : ""}${n}
|
|
2217
|
+
`;
|
|
2218
|
+
switch (this.state) {
|
|
2219
|
+
case "submit": {
|
|
2220
|
+
const c = s ? `${e("gray", $)} ` : "", o = W(t.output, i(this.options[this.cursor], "selected"), c);
|
|
2221
|
+
return `${a}${o}`;
|
|
2222
|
+
}
|
|
2223
|
+
case "cancel": {
|
|
2224
|
+
const c = s ? `${e("gray", $)} ` : "", o = W(t.output, i(this.options[this.cursor], "cancelled"), c);
|
|
2225
|
+
return `${a}${o}${s ? `
|
|
2226
|
+
${e("gray", $)}` : ""}`;
|
|
2227
|
+
}
|
|
2228
|
+
default: {
|
|
2229
|
+
const c = s ? `${e("cyan", $)} ` : "", o = s ? e("cyan", x2) : "", l = a.split(`
|
|
2230
|
+
`).length, d = s ? 2 : 1;
|
|
2231
|
+
return `${a}${c}${F({ output: t.output, cursor: this.cursor, options: this.options, maxItems: t.maxItems, columnPadding: c.length, rowPadding: l + d, style: (g, p2) => i(g, g.disabled ? "disabled" : p2 ? "active" : "inactive") }).join(`
|
|
2232
|
+
${c}`)}
|
|
2233
|
+
${o}
|
|
2234
|
+
`;
|
|
2235
|
+
}
|
|
2236
|
+
}
|
|
2237
|
+
} }).prompt();
|
|
2238
|
+
};
|
|
2239
|
+
var Nt = `${e("gray", $)} `;
|
|
2240
|
+
var Pe = (t) => new ht({ validate: t.validate, placeholder: t.placeholder, defaultValue: t.defaultValue, initialValue: t.initialValue, output: t.output, signal: t.signal, input: t.input, render() {
|
|
2241
|
+
const i = t?.withGuide ?? h.withGuide, s = `${`${i ? `${e("gray", $)}
|
|
2242
|
+
` : ""}${P(this.state)} `}${t.message}
|
|
2243
|
+
`, r = t.placeholder ? e("inverse", t.placeholder[0]) + e("dim", t.placeholder.slice(1)) : e(["inverse", "hidden"], "_"), u = this.userInput ? this.userInputWithCursor : r, n = this.value ?? "";
|
|
2244
|
+
switch (this.state) {
|
|
2245
|
+
case "error": {
|
|
2246
|
+
const a = this.error ? ` ${e("yellow", this.error)}` : "", c = i ? `${e("yellow", $)} ` : "", o = i ? e("yellow", x2) : "";
|
|
2247
|
+
return `${s.trim()}
|
|
2248
|
+
${c}${u}
|
|
2249
|
+
${o}${a}
|
|
2250
|
+
`;
|
|
2251
|
+
}
|
|
2252
|
+
case "submit": {
|
|
2253
|
+
const a = n ? ` ${e("dim", n)}` : "", c = i ? e("gray", $) : "";
|
|
2254
|
+
return `${s}${c}${a}`;
|
|
2255
|
+
}
|
|
2256
|
+
case "cancel": {
|
|
2257
|
+
const a = n ? ` ${e(["strikethrough", "dim"], n)}` : "", c = i ? e("gray", $) : "";
|
|
2258
|
+
return `${s}${c}${a}${n.trim() ? `
|
|
2259
|
+
${c}` : ""}`;
|
|
2260
|
+
}
|
|
2261
|
+
default: {
|
|
2262
|
+
const a = i ? `${e("cyan", $)} ` : "", c = i ? e("cyan", x2) : "";
|
|
2263
|
+
return `${s}${a}${u}
|
|
2264
|
+
${c}
|
|
2265
|
+
`;
|
|
2266
|
+
}
|
|
2267
|
+
}
|
|
2268
|
+
} }).prompt();
|
|
2269
|
+
|
|
2270
|
+
// ../argent-cli/src/link.ts
|
|
2271
|
+
var import_picocolors = __toESM(require_picocolors(), 1);
|
|
2272
|
+
var WILDCARD_HOSTS = /* @__PURE__ */ new Set(["0.0.0.0", "::", "::0", ""]);
|
|
2273
|
+
function isLoopback2(host) {
|
|
2274
|
+
return host === "127.0.0.1" || host === "localhost" || host === "::1";
|
|
2275
|
+
}
|
|
2276
|
+
function validateHost(raw) {
|
|
2277
|
+
const trimmed = raw.trim();
|
|
2278
|
+
if (WILDCARD_HOSTS.has(trimmed)) {
|
|
2279
|
+
throw new StartFlagError(
|
|
2280
|
+
`--host ${trimmed === "" ? '""' : trimmed} is a bind address, not a connect address \u2014 use 127.0.0.1 or the actual reachable host.`
|
|
2281
|
+
);
|
|
2282
|
+
}
|
|
2283
|
+
return trimmed;
|
|
2284
|
+
}
|
|
2285
|
+
function validateConnectPort(raw) {
|
|
2286
|
+
const port = parsePort(raw);
|
|
2287
|
+
if (port === 0) {
|
|
2288
|
+
throw new StartFlagError(`--port must be 1..65535 for a connect target, got "${raw}"`);
|
|
2289
|
+
}
|
|
2290
|
+
return port;
|
|
2291
|
+
}
|
|
2292
|
+
function parseLinkFlags(argv) {
|
|
2293
|
+
const flags2 = {
|
|
2294
|
+
host: null,
|
|
2295
|
+
port: null,
|
|
2296
|
+
token: null,
|
|
2297
|
+
url: null,
|
|
2298
|
+
yes: false,
|
|
2299
|
+
noVerify: false,
|
|
2300
|
+
help: false
|
|
2301
|
+
};
|
|
2302
|
+
for (let i = 0; i < argv.length; i++) {
|
|
2303
|
+
const tok = argv[i];
|
|
2304
|
+
const takeValue = (name) => {
|
|
2305
|
+
const v2 = argv[i + 1];
|
|
2306
|
+
if (v2 === void 0) throw new StartFlagError(`${name} requires a value`);
|
|
2307
|
+
i += 1;
|
|
2308
|
+
return v2;
|
|
2309
|
+
};
|
|
2310
|
+
if (tok === "--help" || tok === "-h") {
|
|
2311
|
+
flags2.help = true;
|
|
2312
|
+
continue;
|
|
2313
|
+
}
|
|
2314
|
+
if (tok === "--yes" || tok === "-y") {
|
|
2315
|
+
flags2.yes = true;
|
|
2316
|
+
continue;
|
|
2317
|
+
}
|
|
2318
|
+
if (tok === "--no-verify") {
|
|
2319
|
+
flags2.noVerify = true;
|
|
2320
|
+
continue;
|
|
2321
|
+
}
|
|
2322
|
+
if (tok === "--host") {
|
|
2323
|
+
flags2.host = validateHost(takeValue("--host"));
|
|
2324
|
+
continue;
|
|
2325
|
+
}
|
|
2326
|
+
if (tok.startsWith("--host=")) {
|
|
2327
|
+
flags2.host = validateHost(tok.slice("--host=".length));
|
|
2328
|
+
continue;
|
|
2329
|
+
}
|
|
2330
|
+
if (tok === "--port" || tok === "-p") {
|
|
2331
|
+
flags2.port = validateConnectPort(takeValue("--port"));
|
|
2332
|
+
continue;
|
|
2333
|
+
}
|
|
2334
|
+
if (tok.startsWith("--port=")) {
|
|
2335
|
+
flags2.port = validateConnectPort(tok.slice("--port=".length));
|
|
2336
|
+
continue;
|
|
2337
|
+
}
|
|
2338
|
+
if (tok === "--token") {
|
|
2339
|
+
flags2.token = takeValue("--token");
|
|
2340
|
+
continue;
|
|
2341
|
+
}
|
|
2342
|
+
if (tok.startsWith("--token=")) {
|
|
2343
|
+
flags2.token = tok.slice("--token=".length);
|
|
2344
|
+
continue;
|
|
2345
|
+
}
|
|
2346
|
+
if (!tok.startsWith("-")) {
|
|
2347
|
+
const parsed = parseLinkTarget(tok);
|
|
2348
|
+
if (!parsed) {
|
|
2349
|
+
throw new StartFlagError(
|
|
2350
|
+
`Unrecognized argument "${tok}". Expected an argent://\u2026 pairing string, an http(s):// URL, or flags (see --help).`
|
|
2351
|
+
);
|
|
2352
|
+
}
|
|
2353
|
+
flags2.host = validateHost(parsed.host);
|
|
2354
|
+
flags2.port = validateConnectPort(String(parsed.port));
|
|
2355
|
+
flags2.url = parsed.url;
|
|
2356
|
+
if (parsed.token) flags2.token = parsed.token;
|
|
2357
|
+
continue;
|
|
2358
|
+
}
|
|
2359
|
+
throw new StartFlagError(`Unknown flag: ${tok}`);
|
|
2360
|
+
}
|
|
2361
|
+
return flags2;
|
|
2362
|
+
}
|
|
2363
|
+
function parseUnlinkFlags(argv) {
|
|
2364
|
+
const flags2 = { yes: false, help: false };
|
|
2365
|
+
for (const tok of argv) {
|
|
2366
|
+
if (tok === "--help" || tok === "-h") {
|
|
2367
|
+
flags2.help = true;
|
|
2368
|
+
continue;
|
|
2369
|
+
}
|
|
2370
|
+
if (tok === "--yes" || tok === "-y") {
|
|
2371
|
+
flags2.yes = true;
|
|
2372
|
+
continue;
|
|
2373
|
+
}
|
|
2374
|
+
throw new StartFlagError(`Unknown flag: ${tok}`);
|
|
2375
|
+
}
|
|
2376
|
+
return flags2;
|
|
2377
|
+
}
|
|
2378
|
+
function printLinkHelp() {
|
|
2379
|
+
console.log(`Usage: argent link [<target>] [flags]
|
|
2380
|
+
|
|
2381
|
+
Route argent client requests (argent tools / run / mcp) to a remote tool-server
|
|
2382
|
+
instead of auto-spawning a local one. The target is persisted to ~/.argent/link.json
|
|
2383
|
+
and survives shell restarts.
|
|
2384
|
+
|
|
2385
|
+
<target> may be:
|
|
2386
|
+
- argent://[<token>@]<host>:<port> the string \`argent server start\` prints
|
|
2387
|
+
- http(s)://<host>[:<port>][/path] a full URL \u2014 use this for a reverse proxy
|
|
2388
|
+
or tunnel (ngrok, cloudflared, nginx). The
|
|
2389
|
+
scheme and any path prefix are preserved;
|
|
2390
|
+
requests go to <url>/tools.
|
|
2391
|
+
|
|
2392
|
+
The easiest LAN path is to paste the connection string from \`argent server start\`:
|
|
2393
|
+
argent link argent://<token>@10.0.0.42:3001
|
|
2394
|
+
For a tunnel, point at its public URL and pass the server's token:
|
|
2395
|
+
argent link https://argent.example.com --token <token>
|
|
2396
|
+
|
|
2397
|
+
Resolution order for the tool-server URL:
|
|
2398
|
+
1. ARGENT_TOOLS_URL environment variable (highest precedence)
|
|
2399
|
+
2. ~/.argent/link.json (this command)
|
|
2400
|
+
3. Auto-spawn a local tool-server (default)
|
|
2401
|
+
|
|
2402
|
+
Flags:
|
|
2403
|
+
--host <h> Remote host or IP to connect to. Prompts interactively if
|
|
2404
|
+
omitted. Wildcards (0.0.0.0, ::) are bind addresses, not
|
|
2405
|
+
connect targets, and are rejected \u2014 use 127.0.0.1 or the
|
|
2406
|
+
actual reachable host.
|
|
2407
|
+
--port, -p <n> Remote port (1..65535). Defaults to 3001. Prompts if omitted.
|
|
2408
|
+
--token <t> Bearer token for a server that enforces auth. Usually
|
|
2409
|
+
supplied inside the argent:// string instead.
|
|
2410
|
+
--no-verify Skip the pre-flight GET /tools health check.
|
|
2411
|
+
--yes, -y Non-interactive. Requires --host (port defaults to 3001).
|
|
2412
|
+
Fails if --host is missing.
|
|
2413
|
+
--help, -h Show this help.
|
|
2414
|
+
|
|
2415
|
+
Examples:
|
|
2416
|
+
argent link argent://ab12\u2026c2@10.0.0.42:3001 Pair from a server-start string.
|
|
2417
|
+
argent link https://argent.example.com --token ab12\u2026c2
|
|
2418
|
+
Link through an HTTPS tunnel/proxy.
|
|
2419
|
+
argent link Interactive prompts for host and port.
|
|
2420
|
+
argent link --host 10.0.0.42 --port 3001 Confirms interactively, then saves.
|
|
2421
|
+
argent link --host 10.0.0.42 --token ab12\u2026c2 --yes
|
|
2422
|
+
Non-interactive, authenticated.
|
|
2423
|
+
argent link --host 10.0.0.42 --yes --no-verify
|
|
2424
|
+
Saves immediately, no health check.
|
|
2425
|
+
|
|
2426
|
+
Security:
|
|
2427
|
+
The token (if any) is stored 0600 and sent as a bearer header. An http:// link
|
|
2428
|
+
has no TLS \u2014 treat any non-loopback http link as trusted-network-only. Prefer
|
|
2429
|
+
an https:// tunnel/proxy when crossing untrusted networks.
|
|
2430
|
+
|
|
2431
|
+
Notes:
|
|
2432
|
+
- If ARGENT_TOOLS_URL is also set in your environment, it overrides the link.
|
|
2433
|
+
- To stop using the remote target, run \`argent unlink\`.
|
|
2434
|
+
- \`argent server start/stop/status\` manage the local tool-server lifecycle
|
|
2435
|
+
and are unaffected by linking.
|
|
2436
|
+
- Restart your editor (Claude / Cursor / VS Code) afterwards \u2014 a running
|
|
2437
|
+
\`argent mcp\` process caches the target at startup and won't pick up the
|
|
2438
|
+
new link until it's relaunched.
|
|
2439
|
+
`);
|
|
2440
|
+
}
|
|
2441
|
+
function printUnlinkHelp() {
|
|
2442
|
+
console.log(`Usage: argent unlink [flags]
|
|
2443
|
+
|
|
2444
|
+
Remove the persisted remote tool-server link (~/.argent/link.json) and return
|
|
2445
|
+
to default local auto-spawn behaviour.
|
|
2446
|
+
|
|
2447
|
+
Flags:
|
|
2448
|
+
--yes, -y Skip the confirmation prompt.
|
|
2449
|
+
--help, -h Show this help.
|
|
2450
|
+
|
|
2451
|
+
Examples:
|
|
2452
|
+
argent unlink Confirms, then removes the link.
|
|
2453
|
+
argent unlink --yes Removes without confirmation. Safe in scripts.
|
|
2454
|
+
|
|
2455
|
+
Notes:
|
|
2456
|
+
- No-op (exit 0) if no link is currently set.
|
|
2457
|
+
- If ARGENT_TOOLS_URL is also set in your environment, it still takes
|
|
2458
|
+
precedence after unlinking \u2014 unset it manually for fully local behaviour.
|
|
2459
|
+
- This does not stop or start any tool-server process. Use
|
|
2460
|
+
\`argent server stop\` if you also want to terminate a running local server.
|
|
2461
|
+
- Restart your editor afterwards \u2014 a running \`argent mcp\` process won't
|
|
2462
|
+
revert to local auto-spawn until it's relaunched.
|
|
2463
|
+
`);
|
|
2464
|
+
}
|
|
2465
|
+
async function promptHost(existing, initial) {
|
|
2466
|
+
const hostInput = await Pe({
|
|
2467
|
+
message: "Remote host or IP to connect to",
|
|
2468
|
+
placeholder: existing?.host ?? "127.0.0.1",
|
|
2469
|
+
initialValue: initial ?? existing?.host,
|
|
2470
|
+
validate(value) {
|
|
2471
|
+
if (!value || !value.trim()) return "Host cannot be empty.";
|
|
2472
|
+
const trimmed = value.trim();
|
|
2473
|
+
if (WILDCARD_HOSTS.has(trimmed)) {
|
|
2474
|
+
return `${trimmed} is a bind address, not a connect address \u2014 use 127.0.0.1 or the actual reachable host.`;
|
|
2475
|
+
}
|
|
2476
|
+
}
|
|
2477
|
+
});
|
|
2478
|
+
if (q(hostInput)) {
|
|
2479
|
+
me("Link cancelled.");
|
|
2480
|
+
process.exit(0);
|
|
2481
|
+
}
|
|
2482
|
+
return hostInput.trim();
|
|
2483
|
+
}
|
|
2484
|
+
async function promptPort(existing, initial) {
|
|
2485
|
+
const defaultPort = initial ?? existing?.port ?? 3001;
|
|
2486
|
+
const portInput = await Pe({
|
|
2487
|
+
message: "Remote port",
|
|
2488
|
+
placeholder: String(defaultPort),
|
|
2489
|
+
initialValue: String(defaultPort),
|
|
2490
|
+
validate(value) {
|
|
2491
|
+
if (!value || !value.trim()) return "Port cannot be empty.";
|
|
2492
|
+
try {
|
|
2493
|
+
validateConnectPort(value.trim());
|
|
2494
|
+
} catch (err) {
|
|
2495
|
+
if (err instanceof StartFlagError) return err.message;
|
|
2496
|
+
throw err;
|
|
2497
|
+
}
|
|
2498
|
+
}
|
|
2499
|
+
});
|
|
2500
|
+
if (q(portInput)) {
|
|
2501
|
+
me("Link cancelled.");
|
|
2502
|
+
process.exit(0);
|
|
2503
|
+
}
|
|
2504
|
+
return validateConnectPort(portInput.trim());
|
|
2505
|
+
}
|
|
2506
|
+
async function preflightHealth(url, token) {
|
|
2507
|
+
const controller = new AbortController();
|
|
2508
|
+
const timer = setTimeout(() => controller.abort(), 3e3);
|
|
2509
|
+
try {
|
|
2510
|
+
const res = await fetch(`${url}/tools`, {
|
|
2511
|
+
signal: controller.signal,
|
|
2512
|
+
headers: token ? { Authorization: `Bearer ${token}` } : {}
|
|
2513
|
+
});
|
|
2514
|
+
if (!res.ok) {
|
|
2515
|
+
const hint = res.status === 401 ? " \u2014 the server requires a token; pass --token or use the argent:// link from `server start`" : res.status === 403 ? " \u2014 the server refused this host (DNS-rebinding guard); reach it by its bind host or start it with --host" : "";
|
|
2516
|
+
return { ok: false, error: `${res.status} ${res.statusText}${hint}` };
|
|
2517
|
+
}
|
|
2518
|
+
return { ok: true };
|
|
2519
|
+
} catch (err) {
|
|
2520
|
+
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
2521
|
+
} finally {
|
|
2522
|
+
clearTimeout(timer);
|
|
2523
|
+
}
|
|
2524
|
+
}
|
|
2525
|
+
function printRestartHint() {
|
|
2526
|
+
console.log(
|
|
2527
|
+
import_picocolors.default.dim("Restart your editor to apply the change to any running `argent mcp` session.")
|
|
2528
|
+
);
|
|
2529
|
+
}
|
|
2530
|
+
function printSecurityCaveat(host, token, url) {
|
|
2531
|
+
if (isLoopback2(host)) return;
|
|
2532
|
+
const tls = url.startsWith("https://");
|
|
2533
|
+
if (tls) {
|
|
2534
|
+
if (!token) {
|
|
2535
|
+
process.stderr.write(
|
|
2536
|
+
import_picocolors.default.yellow(
|
|
2537
|
+
`WARNING: ${host} is reached over HTTPS but with NO token \u2014 anyone who can reach the URL can drive the server. Pair with a token.
|
|
2538
|
+
`
|
|
2539
|
+
)
|
|
2540
|
+
);
|
|
2541
|
+
}
|
|
2542
|
+
return;
|
|
2543
|
+
}
|
|
2544
|
+
if (token) {
|
|
2545
|
+
process.stderr.write(
|
|
2546
|
+
import_picocolors.default.dim(
|
|
2547
|
+
`Note: ${host} is reached over plain HTTP (bearer-token auth, no TLS). Keep this link to a trusted network or VPN, or front it with an https:// tunnel.
|
|
2548
|
+
`
|
|
2549
|
+
)
|
|
2550
|
+
);
|
|
2551
|
+
return;
|
|
2552
|
+
}
|
|
2553
|
+
process.stderr.write(
|
|
2554
|
+
import_picocolors.default.yellow(
|
|
2555
|
+
`WARNING: linked target ${host} is non-loopback and has NO token \u2014 tool calls travel over plain HTTP with no auth. Treat this link as trusted-network-only, or pair with a token (start the server without --no-auth).
|
|
2556
|
+
`
|
|
2557
|
+
)
|
|
2558
|
+
);
|
|
2559
|
+
}
|
|
2560
|
+
async function link(argv) {
|
|
2561
|
+
let flags2;
|
|
2562
|
+
try {
|
|
2563
|
+
flags2 = parseLinkFlags(argv);
|
|
2564
|
+
} catch (err) {
|
|
2565
|
+
if (err instanceof StartFlagError) {
|
|
2566
|
+
console.error(`Error: ${err.message}
|
|
2567
|
+
`);
|
|
2568
|
+
printLinkHelp();
|
|
2569
|
+
process.exit(2);
|
|
2570
|
+
}
|
|
2571
|
+
throw err;
|
|
2572
|
+
}
|
|
2573
|
+
if (flags2.help) {
|
|
2574
|
+
printLinkHelp();
|
|
2575
|
+
return;
|
|
2576
|
+
}
|
|
2577
|
+
if (flags2.yes && flags2.host === null) {
|
|
2578
|
+
console.error("Error: --yes requires --host (port defaults to 3001).\n");
|
|
2579
|
+
printLinkHelp();
|
|
2580
|
+
process.exit(2);
|
|
2581
|
+
}
|
|
2582
|
+
const existing = await readLinkConfig();
|
|
2583
|
+
let host;
|
|
2584
|
+
if (flags2.host !== null) {
|
|
2585
|
+
host = flags2.host;
|
|
2586
|
+
} else {
|
|
2587
|
+
ge(import_picocolors.default.bgCyan(import_picocolors.default.black(" argent link ")));
|
|
2588
|
+
if (existing) {
|
|
2589
|
+
R2.info(`Current link: ${import_picocolors.default.cyan(existing.url)} (${existing.createdAt})`);
|
|
2590
|
+
}
|
|
2591
|
+
host = await promptHost(existing);
|
|
2592
|
+
}
|
|
2593
|
+
let port;
|
|
2594
|
+
if (flags2.port !== null) {
|
|
2595
|
+
port = flags2.port;
|
|
2596
|
+
} else if (flags2.yes) {
|
|
2597
|
+
port = 3001;
|
|
2598
|
+
} else {
|
|
2599
|
+
port = await promptPort(existing);
|
|
2600
|
+
}
|
|
2601
|
+
const token = flags2.token ?? (existing && existing.host === host && existing.port === port ? existing.token : void 0);
|
|
2602
|
+
let url = flags2.url ?? formatUrl(host, port);
|
|
2603
|
+
if (!flags2.yes && existing) {
|
|
2604
|
+
if (existing.url === url) {
|
|
2605
|
+
R2.info(`Already linked to ${import_picocolors.default.cyan(url)}.`);
|
|
2606
|
+
ye("No changes.");
|
|
2607
|
+
return;
|
|
2608
|
+
}
|
|
2609
|
+
const overwrite = await ue({
|
|
2610
|
+
message: `Replace existing link ${import_picocolors.default.dim(existing.url)} with ${import_picocolors.default.cyan(url)}?`,
|
|
2611
|
+
initialValue: true
|
|
2612
|
+
});
|
|
2613
|
+
if (q(overwrite) || !overwrite) {
|
|
2614
|
+
me("Link cancelled.");
|
|
2615
|
+
process.exit(0);
|
|
2616
|
+
}
|
|
2617
|
+
}
|
|
2618
|
+
if (!flags2.noVerify) {
|
|
2619
|
+
while (true) {
|
|
2620
|
+
const spinnerActive = !flags2.yes;
|
|
2621
|
+
let spinner = null;
|
|
2622
|
+
if (spinnerActive) {
|
|
2623
|
+
spinner = ft();
|
|
2624
|
+
spinner.start(`Verifying tool-server at ${url}...`);
|
|
2625
|
+
}
|
|
2626
|
+
const result = await preflightHealth(url, token);
|
|
2627
|
+
if (result.ok) {
|
|
2628
|
+
if (spinner) spinner.stop(import_picocolors.default.green("Tool-server reachable."));
|
|
2629
|
+
break;
|
|
2630
|
+
}
|
|
2631
|
+
if (spinner) spinner.stop(import_picocolors.default.red("Verification failed."));
|
|
2632
|
+
const detail = result.error ? ` (${result.error})` : "";
|
|
2633
|
+
if (flags2.yes) {
|
|
2634
|
+
console.error(
|
|
2635
|
+
`Error: pre-flight GET ${url}/tools failed${detail}. Make sure the remote tool-server is running, or pass --no-verify to skip.`
|
|
2636
|
+
);
|
|
2637
|
+
process.exit(1);
|
|
2638
|
+
}
|
|
2639
|
+
R2.error(`pre-flight GET ${url}/tools failed${detail}.`);
|
|
2640
|
+
const action = await xe({
|
|
2641
|
+
message: "How would you like to proceed?",
|
|
2642
|
+
options: [
|
|
2643
|
+
{ value: "retry", label: "Retry verification" },
|
|
2644
|
+
{ value: "modify", label: "Modify host and port, then retry" },
|
|
2645
|
+
{ value: "skip", label: "Skip verification and save anyway" },
|
|
2646
|
+
{ value: "cancel", label: "Cancel" }
|
|
2647
|
+
],
|
|
2648
|
+
initialValue: "retry"
|
|
2649
|
+
});
|
|
2650
|
+
if (q(action) || action === "cancel") {
|
|
2651
|
+
me("Link cancelled.");
|
|
2652
|
+
process.exit(0);
|
|
2653
|
+
}
|
|
2654
|
+
if (action === "skip") break;
|
|
2655
|
+
if (action === "modify") {
|
|
2656
|
+
host = await promptHost(existing, host);
|
|
2657
|
+
port = await promptPort(existing, port);
|
|
2658
|
+
url = formatUrl(host, port);
|
|
2659
|
+
}
|
|
2660
|
+
}
|
|
2661
|
+
}
|
|
2662
|
+
const cfg = {
|
|
2663
|
+
url,
|
|
2664
|
+
host,
|
|
2665
|
+
port,
|
|
2666
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2667
|
+
...token ? { token } : {}
|
|
2668
|
+
};
|
|
2669
|
+
await writeLinkConfig(cfg);
|
|
2670
|
+
if (existing && existing.url !== url) {
|
|
2671
|
+
console.log(`${import_picocolors.default.green("\u2713")} Link updated: ${import_picocolors.default.dim(existing.url)} \u2192 ${import_picocolors.default.cyan(url)}`);
|
|
2672
|
+
} else {
|
|
2673
|
+
console.log(`${import_picocolors.default.green("\u2713")} Linked: ${import_picocolors.default.cyan(url)}`);
|
|
2674
|
+
}
|
|
2675
|
+
if (token) console.log(import_picocolors.default.dim(" auth: token stored in ~/.argent/link.json (0600)"));
|
|
2676
|
+
printSecurityCaveat(host, token, url);
|
|
2677
|
+
if (process.env.ARGENT_TOOLS_URL) {
|
|
2678
|
+
console.log(
|
|
2679
|
+
import_picocolors.default.yellow(
|
|
2680
|
+
`Note: ARGENT_TOOLS_URL=${process.env.ARGENT_TOOLS_URL} is set in your environment and takes precedence over the link.`
|
|
2681
|
+
)
|
|
2682
|
+
);
|
|
2683
|
+
}
|
|
2684
|
+
printRestartHint();
|
|
2685
|
+
}
|
|
2686
|
+
async function unlink3(argv) {
|
|
2687
|
+
let flags2;
|
|
2688
|
+
try {
|
|
2689
|
+
flags2 = parseUnlinkFlags(argv);
|
|
2690
|
+
} catch (err) {
|
|
2691
|
+
if (err instanceof StartFlagError) {
|
|
2692
|
+
console.error(`Error: ${err.message}
|
|
2693
|
+
`);
|
|
2694
|
+
printUnlinkHelp();
|
|
2695
|
+
process.exit(2);
|
|
2696
|
+
}
|
|
2697
|
+
throw err;
|
|
2698
|
+
}
|
|
2699
|
+
if (flags2.help) {
|
|
2700
|
+
printUnlinkHelp();
|
|
2701
|
+
return;
|
|
2702
|
+
}
|
|
2703
|
+
const existing = await readLinkConfig();
|
|
2704
|
+
if (!existing) {
|
|
2705
|
+
console.log("Not currently linked \u2014 already using local tool-server.");
|
|
2706
|
+
return;
|
|
2707
|
+
}
|
|
2708
|
+
if (!flags2.yes) {
|
|
2709
|
+
const confirmed = await ue({
|
|
2710
|
+
message: `Remove link to ${import_picocolors.default.cyan(existing.url)}?`,
|
|
2711
|
+
initialValue: true
|
|
2712
|
+
});
|
|
2713
|
+
if (q(confirmed) || !confirmed) {
|
|
2714
|
+
me("Unlink cancelled.");
|
|
2715
|
+
process.exit(0);
|
|
2716
|
+
}
|
|
2717
|
+
}
|
|
2718
|
+
await clearLinkConfig();
|
|
2719
|
+
console.log(`${import_picocolors.default.green("\u2713")} Unlinked from ${import_picocolors.default.dim(existing.url)}.`);
|
|
2720
|
+
if (process.env.ARGENT_TOOLS_URL) {
|
|
2721
|
+
console.log(
|
|
2722
|
+
import_picocolors.default.yellow(
|
|
2723
|
+
`The env var ARGENT_TOOLS_URL is also set in your shell (=${process.env.ARGENT_TOOLS_URL}) and takes precedence \u2014 unset it manually if you want fully local behaviour.`
|
|
2724
|
+
)
|
|
2725
|
+
);
|
|
2726
|
+
}
|
|
2727
|
+
printRestartHint();
|
|
2728
|
+
}
|
|
2729
|
+
|
|
2730
|
+
// ../argent-cli/src/flags.ts
|
|
2731
|
+
import * as fs4 from "node:fs";
|
|
2732
|
+
import * as path5 from "node:path";
|
|
2733
|
+
import { homedir as homedir4 } from "node:os";
|
|
2734
|
+
var FLAG_REGISTRY = [
|
|
2735
|
+
// {
|
|
2736
|
+
// name: "example-flag",
|
|
2737
|
+
// description: "One-line summary shown by `argent flags`.",
|
|
2738
|
+
// },
|
|
2739
|
+
];
|
|
2740
|
+
function getFlagDefinition(name, registry = FLAG_REGISTRY) {
|
|
2741
|
+
return registry.find((def) => def.name === name);
|
|
2742
|
+
}
|
|
2743
|
+
var PROJECT_MARKERS = [".argent", ".git", "package.json"];
|
|
2744
|
+
function resolveProjectRoot(startDir) {
|
|
2745
|
+
const initial = path5.resolve(startDir);
|
|
2746
|
+
let current = initial;
|
|
2747
|
+
while (true) {
|
|
2748
|
+
for (const marker of PROJECT_MARKERS) {
|
|
2749
|
+
if (fs4.existsSync(path5.join(current, marker))) return current;
|
|
2750
|
+
}
|
|
2751
|
+
const parent = path5.dirname(current);
|
|
2752
|
+
if (parent === current) return initial;
|
|
2753
|
+
current = parent;
|
|
2754
|
+
}
|
|
2755
|
+
}
|
|
2756
|
+
function getFlagsPath(scope, options = {}) {
|
|
2757
|
+
const home = options.homeDir ?? homedir4();
|
|
2758
|
+
if (scope === "global") {
|
|
2759
|
+
return path5.join(home, ".argent", "flags.json");
|
|
2760
|
+
}
|
|
2761
|
+
const cwd = options.cwd ?? process.cwd();
|
|
2762
|
+
return path5.join(resolveProjectRoot(cwd), ".argent", "flags.json");
|
|
2763
|
+
}
|
|
2764
|
+
function readFlagsFile(filePath) {
|
|
2765
|
+
let raw;
|
|
2766
|
+
try {
|
|
2767
|
+
raw = fs4.readFileSync(filePath, "utf8");
|
|
2768
|
+
} catch {
|
|
2769
|
+
return {};
|
|
2770
|
+
}
|
|
2771
|
+
let parsed;
|
|
2772
|
+
try {
|
|
2773
|
+
parsed = JSON.parse(raw);
|
|
2774
|
+
} catch {
|
|
2775
|
+
return {};
|
|
2776
|
+
}
|
|
2777
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return {};
|
|
2778
|
+
const flags2 = parsed.flags;
|
|
2779
|
+
if (!flags2 || typeof flags2 !== "object" || Array.isArray(flags2)) return {};
|
|
2780
|
+
const out = {};
|
|
2781
|
+
for (const [k2, v2] of Object.entries(flags2)) {
|
|
2782
|
+
if (typeof v2 === "boolean") out[k2] = v2;
|
|
2783
|
+
}
|
|
2784
|
+
return out;
|
|
2785
|
+
}
|
|
2786
|
+
function writeFlagsFile(filePath, flags2) {
|
|
2787
|
+
if (Object.keys(flags2).length === 0) {
|
|
2788
|
+
if (fs4.existsSync(filePath)) fs4.rmSync(filePath, { force: true });
|
|
2789
|
+
const parent = path5.dirname(filePath);
|
|
2790
|
+
try {
|
|
2791
|
+
if (fs4.existsSync(parent) && fs4.readdirSync(parent).length === 0) {
|
|
2792
|
+
fs4.rmdirSync(parent);
|
|
2793
|
+
}
|
|
2794
|
+
} catch {
|
|
2795
|
+
}
|
|
2796
|
+
return;
|
|
2797
|
+
}
|
|
2798
|
+
fs4.mkdirSync(path5.dirname(filePath), { recursive: true });
|
|
2799
|
+
const tmp = `${filePath}.${process.pid}.tmp`;
|
|
2800
|
+
fs4.writeFileSync(tmp, JSON.stringify({ flags: flags2 }, null, 2) + "\n");
|
|
2801
|
+
fs4.renameSync(tmp, filePath);
|
|
2802
|
+
}
|
|
2803
|
+
function readFlags(scope, options = {}) {
|
|
2804
|
+
return readFlagsFile(getFlagsPath(scope, options));
|
|
2805
|
+
}
|
|
2806
|
+
function setFlag(name, value, scope, options = {}) {
|
|
2807
|
+
const filePath = getFlagsPath(scope, options);
|
|
2808
|
+
const current = readFlagsFile(filePath);
|
|
2809
|
+
current[name] = value;
|
|
2810
|
+
writeFlagsFile(filePath, current);
|
|
2811
|
+
}
|
|
2812
|
+
function unsetFlag(name, scope, options = {}) {
|
|
2813
|
+
const filePath = getFlagsPath(scope, options);
|
|
2814
|
+
const current = readFlagsFile(filePath);
|
|
2815
|
+
if (!Object.hasOwn(current, name)) return false;
|
|
2816
|
+
delete current[name];
|
|
2817
|
+
writeFlagsFile(filePath, current);
|
|
2818
|
+
return true;
|
|
2819
|
+
}
|
|
2820
|
+
function isFlagEnabled(name, options = {}) {
|
|
2821
|
+
const projectFlags = readFlags("project", options);
|
|
2822
|
+
if (Object.hasOwn(projectFlags, name)) return projectFlags[name];
|
|
2823
|
+
const globalFlags = readFlags("global", options);
|
|
2824
|
+
if (Object.hasOwn(globalFlags, name)) return globalFlags[name];
|
|
2825
|
+
return false;
|
|
2826
|
+
}
|
|
2827
|
+
var FLAG_NAME_RE = /^[a-zA-Z][a-zA-Z0-9._-]*$/;
|
|
2828
|
+
function parseToggleArgs(argv, command) {
|
|
2829
|
+
let name = null;
|
|
2830
|
+
let scope = "global";
|
|
2831
|
+
let positionalOnly = false;
|
|
2832
|
+
for (let i = 0; i < argv.length; i++) {
|
|
2833
|
+
const tok = argv[i];
|
|
2834
|
+
if (positionalOnly) {
|
|
2835
|
+
if (name !== null) throw new Error(`Unexpected extra argument: "${tok}"`);
|
|
2836
|
+
name = tok;
|
|
2837
|
+
continue;
|
|
2838
|
+
}
|
|
2839
|
+
if (tok === "--") {
|
|
2840
|
+
positionalOnly = true;
|
|
2841
|
+
continue;
|
|
2842
|
+
}
|
|
2843
|
+
if (tok === "--scope") {
|
|
2844
|
+
const v2 = argv[i + 1];
|
|
2845
|
+
if (v2 === void 0) throw new Error("--scope requires a value (project|global)");
|
|
2846
|
+
scope = parseScope(v2);
|
|
2847
|
+
i += 1;
|
|
2848
|
+
continue;
|
|
2849
|
+
}
|
|
2850
|
+
if (tok.startsWith("--scope=")) {
|
|
2851
|
+
scope = parseScope(tok.slice("--scope=".length));
|
|
2852
|
+
continue;
|
|
2853
|
+
}
|
|
2854
|
+
if (tok.startsWith("--")) {
|
|
2855
|
+
throw new Error(`Unknown flag: ${tok}`);
|
|
2856
|
+
}
|
|
2857
|
+
if (name !== null) {
|
|
2858
|
+
throw new Error(`Unexpected extra argument: "${tok}"`);
|
|
2859
|
+
}
|
|
2860
|
+
name = tok;
|
|
2861
|
+
}
|
|
2862
|
+
if (name === null) {
|
|
2863
|
+
throw new Error(`Usage: argent ${command} <flag-name> [--scope project|global]`);
|
|
2864
|
+
}
|
|
2865
|
+
if (!FLAG_NAME_RE.test(name)) {
|
|
2866
|
+
throw new Error(
|
|
2867
|
+
`Invalid flag name "${name}". Must start with a letter and contain only letters, digits, ".", "_", or "-".`
|
|
2868
|
+
);
|
|
2869
|
+
}
|
|
2870
|
+
return { name, scope };
|
|
2871
|
+
}
|
|
2872
|
+
function parseScope(raw) {
|
|
2873
|
+
if (raw === "global" || raw === "project") return raw;
|
|
2874
|
+
throw new Error(`--scope must be "project" or "global", got "${raw}"`);
|
|
2875
|
+
}
|
|
2876
|
+
function printToggleHelp(command) {
|
|
2877
|
+
const summary = command === "enable" ? "Enable a predefined feature flag (see `argent flags`) at the chosen scope." : "Remove a feature flag entry at the chosen scope. Falls back to the global value if set; otherwise the flag is treated as off.";
|
|
2878
|
+
console.log(`Usage: argent ${command} <flag-name> [--scope project|global]
|
|
2879
|
+
|
|
2880
|
+
${summary}
|
|
2881
|
+
|
|
2882
|
+
Storage:
|
|
2883
|
+
~/.argent/flags.json (global, default)
|
|
2884
|
+
<project-root>/.argent/flags.json (project, with --scope project)
|
|
2885
|
+
|
|
2886
|
+
Options:
|
|
2887
|
+
--scope <global|project> Where to write (default: global)
|
|
2888
|
+
--help, -h Show this help
|
|
2889
|
+
`);
|
|
2890
|
+
}
|
|
2891
|
+
function runToggle(argv, command, registry) {
|
|
2892
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
2893
|
+
printToggleHelp(command);
|
|
2894
|
+
return;
|
|
2895
|
+
}
|
|
2896
|
+
let parsed;
|
|
2897
|
+
try {
|
|
2898
|
+
parsed = parseToggleArgs(argv, command);
|
|
2899
|
+
} catch (err) {
|
|
2900
|
+
console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
2901
|
+
process.exit(2);
|
|
2902
|
+
}
|
|
2903
|
+
if (command === "enable" && getFlagDefinition(parsed.name, registry) === void 0) {
|
|
2904
|
+
console.error(
|
|
2905
|
+
`Error: Unknown feature flag "${parsed.name}". Run \`argent flags\` to see available flags.`
|
|
2906
|
+
);
|
|
2907
|
+
process.exit(2);
|
|
2908
|
+
}
|
|
2909
|
+
const filePath = getFlagsPath(parsed.scope);
|
|
2910
|
+
try {
|
|
2911
|
+
if (command === "enable") {
|
|
2912
|
+
setFlag(parsed.name, true, parsed.scope);
|
|
2913
|
+
} else {
|
|
2914
|
+
unsetFlag(parsed.name, parsed.scope);
|
|
2915
|
+
}
|
|
2916
|
+
} catch (err) {
|
|
2917
|
+
console.error(`Failed to ${command} flag: ${err instanceof Error ? err.message : String(err)}`);
|
|
2918
|
+
process.exit(1);
|
|
2919
|
+
}
|
|
2920
|
+
if (command === "enable") {
|
|
2921
|
+
console.log(`Enabled flag "${parsed.name}" (${parsed.scope}). Stored at ${filePath}.`);
|
|
2922
|
+
} else {
|
|
2923
|
+
console.log(`Disabled flag "${parsed.name}" (${parsed.scope}).`);
|
|
2924
|
+
}
|
|
2925
|
+
}
|
|
2926
|
+
function enable(argv, registry = FLAG_REGISTRY) {
|
|
2927
|
+
runToggle(argv, "enable", registry);
|
|
2928
|
+
}
|
|
2929
|
+
function disable(argv, registry = FLAG_REGISTRY) {
|
|
2930
|
+
runToggle(argv, "disable", registry);
|
|
2931
|
+
}
|
|
2932
|
+
function flags(argv, registry = FLAG_REGISTRY) {
|
|
2933
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
2934
|
+
console.log(`Usage: argent flags [--json]
|
|
2935
|
+
|
|
2936
|
+
List the available feature flags and their current state. Flags are
|
|
2937
|
+
predefined; project-scoped values override global ones.
|
|
2938
|
+
|
|
2939
|
+
Options:
|
|
2940
|
+
--json Print machine-readable JSON
|
|
2941
|
+
`);
|
|
2942
|
+
return;
|
|
2943
|
+
}
|
|
2944
|
+
const json = argv.includes("--json");
|
|
2945
|
+
const projectFlags = readFlags("project");
|
|
2946
|
+
const globalFlags = readFlags("global");
|
|
2947
|
+
const effective = {};
|
|
2948
|
+
for (const [k2, v2] of Object.entries(globalFlags)) effective[k2] = { value: v2, scope: "global" };
|
|
2949
|
+
for (const [k2, v2] of Object.entries(projectFlags)) effective[k2] = { value: v2, scope: "project" };
|
|
2950
|
+
const registryView = registry.map((def) => {
|
|
2951
|
+
const eff = Object.hasOwn(effective, def.name) ? effective[def.name] : void 0;
|
|
2952
|
+
return {
|
|
2953
|
+
name: def.name,
|
|
2954
|
+
description: def.description,
|
|
2955
|
+
enabled: eff?.value ?? false,
|
|
2956
|
+
scope: eff?.scope ?? null
|
|
2957
|
+
};
|
|
2958
|
+
});
|
|
2959
|
+
const known = new Set(registry.map((def) => def.name));
|
|
2960
|
+
const unrecognized = Object.keys(effective).filter((name) => !known.has(name)).sort().map((name) => ({ name, enabled: effective[name].value, scope: effective[name].scope }));
|
|
2961
|
+
if (json) {
|
|
2962
|
+
console.log(
|
|
2963
|
+
JSON.stringify(
|
|
2964
|
+
{
|
|
2965
|
+
flags: registryView,
|
|
2966
|
+
unrecognized,
|
|
2967
|
+
global: globalFlags,
|
|
2968
|
+
project: projectFlags,
|
|
2969
|
+
effective,
|
|
2970
|
+
paths: {
|
|
2971
|
+
global: getFlagsPath("global"),
|
|
2972
|
+
project: getFlagsPath("project")
|
|
2973
|
+
}
|
|
2974
|
+
},
|
|
2975
|
+
null,
|
|
2976
|
+
2
|
|
2977
|
+
)
|
|
2978
|
+
);
|
|
2979
|
+
return;
|
|
2980
|
+
}
|
|
2981
|
+
if (registryView.length === 0) {
|
|
2982
|
+
console.log("No feature flags are defined.");
|
|
2983
|
+
} else {
|
|
2984
|
+
console.log("Feature flags (project overrides global):");
|
|
2985
|
+
const maxName = registryView.reduce((m2, f2) => Math.max(m2, f2.name.length), 0);
|
|
2986
|
+
for (const f2 of registryView) {
|
|
2987
|
+
const stateLabel = f2.enabled ? "enabled" : "disabled";
|
|
2988
|
+
const scopeLabel = f2.scope ? ` (${f2.scope})` : "";
|
|
2989
|
+
console.log(` ${f2.name.padEnd(maxName, " ")} ${stateLabel.padEnd(8)}${scopeLabel}`);
|
|
2990
|
+
console.log(` ${" ".repeat(maxName)} ${f2.description}`);
|
|
2991
|
+
}
|
|
2992
|
+
}
|
|
2993
|
+
if (unrecognized.length > 0) {
|
|
2994
|
+
console.log("\nStored but no longer recognized (safe to `argent disable`):");
|
|
2995
|
+
const maxName = unrecognized.reduce((m2, f2) => Math.max(m2, f2.name.length), 0);
|
|
2996
|
+
for (const f2 of unrecognized) {
|
|
2997
|
+
const stateLabel = f2.enabled ? "enabled" : "disabled";
|
|
2998
|
+
console.log(` ${f2.name.padEnd(maxName, " ")} ${stateLabel.padEnd(8)} (${f2.scope})`);
|
|
2999
|
+
}
|
|
3000
|
+
}
|
|
3001
|
+
console.log(`
|
|
3002
|
+
Global: ${getFlagsPath("global")}`);
|
|
3003
|
+
console.log(` Project: ${getFlagsPath("project")}`);
|
|
3004
|
+
}
|
|
725
3005
|
export {
|
|
3006
|
+
FLAG_REGISTRY,
|
|
3007
|
+
disable,
|
|
3008
|
+
enable,
|
|
3009
|
+
flags,
|
|
3010
|
+
getFlagDefinition,
|
|
3011
|
+
isFlagEnabled,
|
|
3012
|
+
link,
|
|
726
3013
|
run,
|
|
727
3014
|
server,
|
|
728
|
-
tools
|
|
3015
|
+
tools,
|
|
3016
|
+
unlink3 as unlink
|
|
729
3017
|
};
|