@swmansion/argent 0.10.0 → 0.11.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 +4 -1
- package/assets/argent.tracecfg.pbtxt +133 -0
- package/assets/queries/README.md +93 -0
- package/assets/queries/cpu-hotspots.sql +106 -0
- package/assets/queries/function-callers.sql +62 -0
- package/assets/queries/hang-folds-batched.sql +88 -0
- package/assets/queries/hang-main-thread-samples.sql +32 -0
- package/assets/queries/hang-state-breakdown.sql +44 -0
- package/assets/queries/memory-rss.sql +25 -0
- package/assets/queries/thread-breakdown.sql +34 -0
- package/assets/queries/trace-bounds.sql +6 -0
- package/assets/queries/ui-hangs.sql +59 -0
- package/assets/trace-processor/LICENSE +235 -0
- package/assets/trace-processor/SHA256SUMS +4 -0
- package/assets/trace-processor/engine.mjs +42423 -0
- package/assets/trace-processor/engine_bundle.node.js +11130 -0
- package/assets/trace-processor/trace_processor.wasm +0 -0
- package/{dist → bin}/argent-android-devtools-0.1.0.apk +0 -0
- package/bin/darwin/ax-service +0 -0
- package/dist/cli-cmds.mjs +868 -701
- package/dist/installer.mjs +9 -0
- package/dist/mcp-server.mjs +297 -79
- package/dist/tool-server.cjs +3270 -1413
- 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-native-profiler/SKILL.md +5 -5
- /package/{dist → assets}/Argent.tracetemplate +0 -0
- /package/{manifest.json → assets/manifest.json} +0 -0
package/dist/cli-cmds.mjs
CHANGED
|
@@ -25,62 +25,6 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
25
25
|
mod
|
|
26
26
|
));
|
|
27
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
28
|
// ../../node_modules/picocolors/picocolors.js
|
|
85
29
|
var require_picocolors = __commonJS({
|
|
86
30
|
"../../node_modules/picocolors/picocolors.js"(exports, module) {
|
|
@@ -153,6 +97,62 @@ var require_picocolors = __commonJS({
|
|
|
153
97
|
}
|
|
154
98
|
});
|
|
155
99
|
|
|
100
|
+
// ../../node_modules/sisteransi/src/index.js
|
|
101
|
+
var require_src = __commonJS({
|
|
102
|
+
"../../node_modules/sisteransi/src/index.js"(exports, module) {
|
|
103
|
+
"use strict";
|
|
104
|
+
var ESC2 = "\x1B";
|
|
105
|
+
var CSI2 = `${ESC2}[`;
|
|
106
|
+
var beep = "\x07";
|
|
107
|
+
var cursor = {
|
|
108
|
+
to(x3, y) {
|
|
109
|
+
if (!y) return `${CSI2}${x3 + 1}G`;
|
|
110
|
+
return `${CSI2}${y + 1};${x3 + 1}H`;
|
|
111
|
+
},
|
|
112
|
+
move(x3, y) {
|
|
113
|
+
let ret = "";
|
|
114
|
+
if (x3 < 0) ret += `${CSI2}${-x3}D`;
|
|
115
|
+
else if (x3 > 0) ret += `${CSI2}${x3}C`;
|
|
116
|
+
if (y < 0) ret += `${CSI2}${-y}A`;
|
|
117
|
+
else if (y > 0) ret += `${CSI2}${y}B`;
|
|
118
|
+
return ret;
|
|
119
|
+
},
|
|
120
|
+
up: (count = 1) => `${CSI2}${count}A`,
|
|
121
|
+
down: (count = 1) => `${CSI2}${count}B`,
|
|
122
|
+
forward: (count = 1) => `${CSI2}${count}C`,
|
|
123
|
+
backward: (count = 1) => `${CSI2}${count}D`,
|
|
124
|
+
nextLine: (count = 1) => `${CSI2}E`.repeat(count),
|
|
125
|
+
prevLine: (count = 1) => `${CSI2}F`.repeat(count),
|
|
126
|
+
left: `${CSI2}G`,
|
|
127
|
+
hide: `${CSI2}?25l`,
|
|
128
|
+
show: `${CSI2}?25h`,
|
|
129
|
+
save: `${ESC2}7`,
|
|
130
|
+
restore: `${ESC2}8`
|
|
131
|
+
};
|
|
132
|
+
var scroll = {
|
|
133
|
+
up: (count = 1) => `${CSI2}S`.repeat(count),
|
|
134
|
+
down: (count = 1) => `${CSI2}T`.repeat(count)
|
|
135
|
+
};
|
|
136
|
+
var erase = {
|
|
137
|
+
screen: `${CSI2}2J`,
|
|
138
|
+
up: (count = 1) => `${CSI2}1J`.repeat(count),
|
|
139
|
+
down: (count = 1) => `${CSI2}J`.repeat(count),
|
|
140
|
+
line: `${CSI2}2K`,
|
|
141
|
+
lineEnd: `${CSI2}K`,
|
|
142
|
+
lineStart: `${CSI2}1K`,
|
|
143
|
+
lines(count) {
|
|
144
|
+
let clear = "";
|
|
145
|
+
for (let i = 0; i < count; i++)
|
|
146
|
+
clear += this.line + (i < count - 1 ? cursor.up() : "");
|
|
147
|
+
if (count)
|
|
148
|
+
clear += cursor.left;
|
|
149
|
+
return clear;
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
module.exports = { cursor, scroll, erase, beep };
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
|
|
156
156
|
// ../argent-cli/src/run.ts
|
|
157
157
|
import * as fs2 from "node:fs";
|
|
158
158
|
import * as path3 from "node:path";
|
|
@@ -566,6 +566,138 @@ function createToolsClient(options = {}) {
|
|
|
566
566
|
return { fetchTools, fetchTool, callTool, baseUrl };
|
|
567
567
|
}
|
|
568
568
|
|
|
569
|
+
// ../argent-tools-client/src/artifacts.ts
|
|
570
|
+
import { mkdir as mkdir3, readFile as readFile3, rm, stat, writeFile as writeFile3 } from "node:fs/promises";
|
|
571
|
+
import { tmpdir } from "node:os";
|
|
572
|
+
import { basename, join as join3 } from "node:path";
|
|
573
|
+
import { createHash } from "node:crypto";
|
|
574
|
+
import { execFile } from "node:child_process";
|
|
575
|
+
import { promisify } from "node:util";
|
|
576
|
+
var execFileAsync = promisify(execFile);
|
|
577
|
+
var ARTIFACT_MARKER = "__argentArtifact";
|
|
578
|
+
function isArtifactHandle(value) {
|
|
579
|
+
return !!value && typeof value === "object" && value[ARTIFACT_MARKER] === true && typeof value.id === "string" && typeof value.filename === "string";
|
|
580
|
+
}
|
|
581
|
+
var SESSION_ID = null;
|
|
582
|
+
function sessionId() {
|
|
583
|
+
if (!SESSION_ID) {
|
|
584
|
+
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[-:T]/g, (m2) => m2 === "T" ? "-" : "").slice(0, 15);
|
|
585
|
+
SESSION_ID = `${stamp}-${process.pid}`;
|
|
586
|
+
}
|
|
587
|
+
return SESSION_ID;
|
|
588
|
+
}
|
|
589
|
+
function sanitizeSegment(segment) {
|
|
590
|
+
return segment.replace(/[^A-Za-z0-9._-]/g, "_");
|
|
591
|
+
}
|
|
592
|
+
function projectSlug() {
|
|
593
|
+
const cwd = process.cwd();
|
|
594
|
+
const hash = createHash("sha1").update(cwd).digest("hex").slice(0, 6);
|
|
595
|
+
const name = sanitizeSegment(basename(cwd)) || "root";
|
|
596
|
+
return `${name}-${hash}`;
|
|
597
|
+
}
|
|
598
|
+
function artifactsRoot() {
|
|
599
|
+
return process.env.ARGENT_ARTIFACTS_DIR ?? join3(tmpdir(), "argent-artifacts");
|
|
600
|
+
}
|
|
601
|
+
function artifactDir(deviceId) {
|
|
602
|
+
const parts = [artifactsRoot(), projectSlug(), sessionId()];
|
|
603
|
+
if (deviceId) parts.push(sanitizeSegment(deviceId));
|
|
604
|
+
return join3(...parts);
|
|
605
|
+
}
|
|
606
|
+
async function resolveLocalFile(handle) {
|
|
607
|
+
if (!handle.hostPath) return null;
|
|
608
|
+
try {
|
|
609
|
+
const st2 = await stat(handle.hostPath);
|
|
610
|
+
if (handle.archive) {
|
|
611
|
+
return st2.isDirectory() ? handle.hostPath : null;
|
|
612
|
+
}
|
|
613
|
+
if (!st2.isFile()) return null;
|
|
614
|
+
if (st2.size !== handle.size) return null;
|
|
615
|
+
if (handle.mtimeMs != null && Math.round(st2.mtimeMs) !== Math.round(handle.mtimeMs)) {
|
|
616
|
+
return null;
|
|
617
|
+
}
|
|
618
|
+
return handle.hostPath;
|
|
619
|
+
} catch {
|
|
620
|
+
return null;
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
async function downloadAndExtractArchive(handle, data, dir) {
|
|
624
|
+
const tarball = join3(dir, `${sanitizeSegment(handle.filename)}.tar.gz`);
|
|
625
|
+
try {
|
|
626
|
+
await writeFile3(tarball, data);
|
|
627
|
+
await execFileAsync("tar", ["-xzf", tarball, "-C", dir]);
|
|
628
|
+
return join3(dir, handle.filename);
|
|
629
|
+
} catch {
|
|
630
|
+
return null;
|
|
631
|
+
} finally {
|
|
632
|
+
await rm(tarball, { force: true }).catch(() => {
|
|
633
|
+
});
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
async function materializeArtifacts(result, ctx) {
|
|
637
|
+
const images = [];
|
|
638
|
+
const fetchFn = ctx.fetchImpl ?? fetch;
|
|
639
|
+
const authHeaders3 = ctx.authToken ? { Authorization: `Bearer ${ctx.authToken}` } : {};
|
|
640
|
+
const dir = artifactDir(ctx.deviceId);
|
|
641
|
+
let dirReady = false;
|
|
642
|
+
async function ensureDir() {
|
|
643
|
+
if (!dirReady) {
|
|
644
|
+
await mkdir3(dir, { recursive: true });
|
|
645
|
+
dirReady = true;
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
async function walk(value) {
|
|
649
|
+
if (isArtifactHandle(value)) {
|
|
650
|
+
const localPath = await resolveLocalFile(value);
|
|
651
|
+
if (localPath) {
|
|
652
|
+
if (value.mimeType.startsWith("image/")) {
|
|
653
|
+
images.push({ localPath, data: await readFile3(localPath), mimeType: value.mimeType });
|
|
654
|
+
}
|
|
655
|
+
return localPath;
|
|
656
|
+
}
|
|
657
|
+
try {
|
|
658
|
+
const res = await fetchFn(`${ctx.toolsUrl}/artifacts/${value.id}`, {
|
|
659
|
+
headers: authHeaders3
|
|
660
|
+
});
|
|
661
|
+
if (!res.ok) return null;
|
|
662
|
+
const data = Buffer.from(await res.arrayBuffer());
|
|
663
|
+
await ensureDir();
|
|
664
|
+
if (value.archive === "tar.gz") {
|
|
665
|
+
return await downloadAndExtractArchive(value, data, dir);
|
|
666
|
+
}
|
|
667
|
+
if (value.size > 0 && data.length !== value.size) return null;
|
|
668
|
+
const downloadedPath = join3(dir, sanitizeSegment(value.filename));
|
|
669
|
+
await writeFile3(downloadedPath, data);
|
|
670
|
+
if (value.mimeType.startsWith("image/")) {
|
|
671
|
+
images.push({ localPath: downloadedPath, data, mimeType: value.mimeType });
|
|
672
|
+
}
|
|
673
|
+
return downloadedPath;
|
|
674
|
+
} catch {
|
|
675
|
+
return null;
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
if (Array.isArray(value)) {
|
|
679
|
+
return Promise.all(value.map(walk));
|
|
680
|
+
}
|
|
681
|
+
if (value && typeof value === "object") {
|
|
682
|
+
const out = {};
|
|
683
|
+
for (const [k2, v2] of Object.entries(value)) {
|
|
684
|
+
out[k2] = await walk(v2);
|
|
685
|
+
}
|
|
686
|
+
return out;
|
|
687
|
+
}
|
|
688
|
+
return value;
|
|
689
|
+
}
|
|
690
|
+
const rewritten = await walk(result);
|
|
691
|
+
return { result: rewritten, images };
|
|
692
|
+
}
|
|
693
|
+
function getDeviceIdFromArgs(args) {
|
|
694
|
+
if (!args || typeof args !== "object") return void 0;
|
|
695
|
+
const rec = args;
|
|
696
|
+
if (typeof rec.udid === "string") return rec.udid;
|
|
697
|
+
if (typeof rec.device_id === "string") return rec.device_id;
|
|
698
|
+
return void 0;
|
|
699
|
+
}
|
|
700
|
+
|
|
569
701
|
// ../argent-cli/src/flag-parser.ts
|
|
570
702
|
var FlagParseException = class extends Error {
|
|
571
703
|
};
|
|
@@ -801,17 +933,19 @@ async function fetchImageToFile(result, outPath) {
|
|
|
801
933
|
fs2.mkdirSync(path3.dirname(path3.resolve(outPath)), { recursive: true });
|
|
802
934
|
fs2.writeFileSync(outPath, buf);
|
|
803
935
|
}
|
|
804
|
-
function renderResult(result, outputHint, json) {
|
|
936
|
+
function renderResult(result, outputHint, images, json) {
|
|
805
937
|
if (json) return JSON.stringify(result, null, 2);
|
|
806
|
-
if (outputHint === "image"
|
|
807
|
-
|
|
808
|
-
|
|
938
|
+
if (outputHint === "image") {
|
|
939
|
+
if (images.length > 0) return `Saved screenshot: ${images[0].localPath}`;
|
|
940
|
+
if (result && typeof result === "object" && "path" in result && typeof result.path === "string") {
|
|
941
|
+
return `Saved screenshot: ${result.path}`;
|
|
942
|
+
}
|
|
809
943
|
}
|
|
810
944
|
if (typeof result === "string") return result;
|
|
811
945
|
return JSON.stringify(result, null, 2);
|
|
812
946
|
}
|
|
813
947
|
async function run(argv, options) {
|
|
814
|
-
const { fetchTool, callTool } = createToolsClient({ paths: options.paths });
|
|
948
|
+
const { fetchTool, callTool, baseUrl } = createToolsClient({ paths: options.paths });
|
|
815
949
|
const [toolName, ...rest] = argv;
|
|
816
950
|
if (!toolName || toolName === "--help" || toolName === "-h") {
|
|
817
951
|
console.log(`Usage: argent run <tool> [flags]
|
|
@@ -873,24 +1007,37 @@ Examples:
|
|
|
873
1007
|
}
|
|
874
1008
|
let result;
|
|
875
1009
|
let note;
|
|
1010
|
+
let images = [];
|
|
876
1011
|
try {
|
|
877
1012
|
const resp = await callTool(toolName, payload);
|
|
878
|
-
|
|
1013
|
+
const { url, token } = await baseUrl();
|
|
1014
|
+
const materialized = await materializeArtifacts(resp.data, {
|
|
1015
|
+
toolsUrl: url,
|
|
1016
|
+
authToken: token,
|
|
1017
|
+
deviceId: getDeviceIdFromArgs(payload)
|
|
1018
|
+
});
|
|
1019
|
+
result = materialized.result;
|
|
1020
|
+
images = materialized.images;
|
|
879
1021
|
note = resp.note;
|
|
880
1022
|
} catch (err) {
|
|
881
1023
|
console.error(err instanceof Error ? err.message : String(err));
|
|
882
1024
|
process.exit(1);
|
|
883
1025
|
}
|
|
884
|
-
if (outPath && meta.outputHint === "image"
|
|
1026
|
+
if (outPath && meta.outputHint === "image") {
|
|
885
1027
|
try {
|
|
886
|
-
|
|
1028
|
+
if (images.length > 0) {
|
|
1029
|
+
fs2.mkdirSync(path3.dirname(path3.resolve(outPath)), { recursive: true });
|
|
1030
|
+
fs2.writeFileSync(outPath, images[0].data);
|
|
1031
|
+
} else if (result && typeof result === "object") {
|
|
1032
|
+
await fetchImageToFile(result, outPath);
|
|
1033
|
+
}
|
|
887
1034
|
} catch (err) {
|
|
888
1035
|
console.error(`Failed to save image: ${err instanceof Error ? err.message : err}`);
|
|
889
1036
|
process.exit(1);
|
|
890
1037
|
}
|
|
891
1038
|
}
|
|
892
1039
|
if (note) console.error(note);
|
|
893
|
-
console.log(renderResult(result, meta.outputHint, json));
|
|
1040
|
+
console.log(renderResult(result, meta.outputHint, images, json));
|
|
894
1041
|
if (outPath && meta.outputHint === "image" && !json) {
|
|
895
1042
|
console.log(`Wrote: ${outPath}`);
|
|
896
1043
|
}
|
|
@@ -1375,99 +1522,395 @@ async function server(argv, options) {
|
|
|
1375
1522
|
}
|
|
1376
1523
|
}
|
|
1377
1524
|
|
|
1378
|
-
//
|
|
1379
|
-
|
|
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
|
-
};
|
|
1525
|
+
// ../argent-cli/src/flags.ts
|
|
1526
|
+
var import_picocolors = __toESM(require_picocolors(), 1);
|
|
1402
1527
|
|
|
1403
|
-
//
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
var
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
const
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
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;
|
|
1528
|
+
// ../configuration-core/src/flags.ts
|
|
1529
|
+
import * as fs4 from "node:fs";
|
|
1530
|
+
import * as path5 from "node:path";
|
|
1531
|
+
import { homedir as homedir4 } from "node:os";
|
|
1532
|
+
var FLAG_REGISTRY = [
|
|
1533
|
+
{
|
|
1534
|
+
name: "disable-auto-screenshot",
|
|
1535
|
+
description: "Disable the automatic screenshot captured after interaction tools."
|
|
1536
|
+
}
|
|
1537
|
+
];
|
|
1538
|
+
function getFlagDefinition(name, registry = FLAG_REGISTRY) {
|
|
1539
|
+
return registry.find((def) => def.name === name);
|
|
1540
|
+
}
|
|
1541
|
+
var PROJECT_MARKERS = [".argent", ".git", "package.json"];
|
|
1542
|
+
function resolveProjectRoot(startDir) {
|
|
1543
|
+
const initial = path5.resolve(startDir);
|
|
1544
|
+
let current = initial;
|
|
1545
|
+
while (true) {
|
|
1546
|
+
for (const marker of PROJECT_MARKERS) {
|
|
1547
|
+
if (fs4.existsSync(path5.join(current, marker))) return current;
|
|
1469
1548
|
}
|
|
1470
|
-
|
|
1549
|
+
const parent = path5.dirname(current);
|
|
1550
|
+
if (parent === current) return initial;
|
|
1551
|
+
current = parent;
|
|
1552
|
+
}
|
|
1553
|
+
}
|
|
1554
|
+
function getFlagsPath(scope, options = {}) {
|
|
1555
|
+
const home = options.homeDir ?? homedir4();
|
|
1556
|
+
if (scope === "global") {
|
|
1557
|
+
return path5.join(home, ".argent", "flags.json");
|
|
1558
|
+
}
|
|
1559
|
+
const cwd = options.cwd ?? process.cwd();
|
|
1560
|
+
return path5.join(resolveProjectRoot(cwd), ".argent", "flags.json");
|
|
1561
|
+
}
|
|
1562
|
+
function readFlagsFile(filePath) {
|
|
1563
|
+
let raw;
|
|
1564
|
+
try {
|
|
1565
|
+
raw = fs4.readFileSync(filePath, "utf8");
|
|
1566
|
+
} catch {
|
|
1567
|
+
return {};
|
|
1568
|
+
}
|
|
1569
|
+
let parsed;
|
|
1570
|
+
try {
|
|
1571
|
+
parsed = JSON.parse(raw);
|
|
1572
|
+
} catch {
|
|
1573
|
+
return {};
|
|
1574
|
+
}
|
|
1575
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return {};
|
|
1576
|
+
const flags2 = parsed.flags;
|
|
1577
|
+
if (!flags2 || typeof flags2 !== "object" || Array.isArray(flags2)) return {};
|
|
1578
|
+
const out = {};
|
|
1579
|
+
for (const [k2, v2] of Object.entries(flags2)) {
|
|
1580
|
+
if (typeof v2 === "boolean") out[k2] = v2;
|
|
1581
|
+
}
|
|
1582
|
+
return out;
|
|
1583
|
+
}
|
|
1584
|
+
function writeFlagsFile(filePath, flags2) {
|
|
1585
|
+
if (Object.keys(flags2).length === 0) {
|
|
1586
|
+
if (fs4.existsSync(filePath)) fs4.rmSync(filePath, { force: true });
|
|
1587
|
+
const parent = path5.dirname(filePath);
|
|
1588
|
+
try {
|
|
1589
|
+
if (fs4.existsSync(parent) && fs4.readdirSync(parent).length === 0) {
|
|
1590
|
+
fs4.rmdirSync(parent);
|
|
1591
|
+
}
|
|
1592
|
+
} catch {
|
|
1593
|
+
}
|
|
1594
|
+
return;
|
|
1595
|
+
}
|
|
1596
|
+
fs4.mkdirSync(path5.dirname(filePath), { recursive: true });
|
|
1597
|
+
const tmp = `${filePath}.${process.pid}.tmp`;
|
|
1598
|
+
fs4.writeFileSync(tmp, JSON.stringify({ flags: flags2 }, null, 2) + "\n");
|
|
1599
|
+
fs4.renameSync(tmp, filePath);
|
|
1600
|
+
}
|
|
1601
|
+
function readFlags(scope, options = {}) {
|
|
1602
|
+
return readFlagsFile(getFlagsPath(scope, options));
|
|
1603
|
+
}
|
|
1604
|
+
function setFlag(name, value, scope, options = {}) {
|
|
1605
|
+
const filePath = getFlagsPath(scope, options);
|
|
1606
|
+
const current = readFlagsFile(filePath);
|
|
1607
|
+
current[name] = value;
|
|
1608
|
+
writeFlagsFile(filePath, current);
|
|
1609
|
+
}
|
|
1610
|
+
function unsetFlag(name, scope, options = {}) {
|
|
1611
|
+
const filePath = getFlagsPath(scope, options);
|
|
1612
|
+
const current = readFlagsFile(filePath);
|
|
1613
|
+
if (!Object.hasOwn(current, name)) return false;
|
|
1614
|
+
delete current[name];
|
|
1615
|
+
writeFlagsFile(filePath, current);
|
|
1616
|
+
return true;
|
|
1617
|
+
}
|
|
1618
|
+
function isFlagEnabled(name, options = {}) {
|
|
1619
|
+
const projectFlags = readFlags("project", options);
|
|
1620
|
+
if (Object.hasOwn(projectFlags, name)) return projectFlags[name];
|
|
1621
|
+
const globalFlags = readFlags("global", options);
|
|
1622
|
+
if (Object.hasOwn(globalFlags, name)) return globalFlags[name];
|
|
1623
|
+
return false;
|
|
1624
|
+
}
|
|
1625
|
+
|
|
1626
|
+
// ../argent-cli/src/flags.ts
|
|
1627
|
+
function colorState(enabled) {
|
|
1628
|
+
const label = (enabled ? "enabled" : "disabled").padEnd(8);
|
|
1629
|
+
if (!process.stdout.isTTY) return label;
|
|
1630
|
+
return enabled ? import_picocolors.default.green(label) : import_picocolors.default.red(label);
|
|
1631
|
+
}
|
|
1632
|
+
var FLAG_NAME_RE = /^[a-zA-Z][a-zA-Z0-9._-]*$/;
|
|
1633
|
+
function parseToggleArgs(argv, command) {
|
|
1634
|
+
let name = null;
|
|
1635
|
+
let scope = "global";
|
|
1636
|
+
let positionalOnly = false;
|
|
1637
|
+
for (let i = 0; i < argv.length; i++) {
|
|
1638
|
+
const tok = argv[i];
|
|
1639
|
+
if (positionalOnly) {
|
|
1640
|
+
if (name !== null) throw new Error(`Unexpected extra argument: "${tok}"`);
|
|
1641
|
+
name = tok;
|
|
1642
|
+
continue;
|
|
1643
|
+
}
|
|
1644
|
+
if (tok === "--") {
|
|
1645
|
+
positionalOnly = true;
|
|
1646
|
+
continue;
|
|
1647
|
+
}
|
|
1648
|
+
if (tok === "--scope") {
|
|
1649
|
+
const v2 = argv[i + 1];
|
|
1650
|
+
if (v2 === void 0) throw new Error("--scope requires a value (project|global)");
|
|
1651
|
+
scope = parseScope(v2);
|
|
1652
|
+
i += 1;
|
|
1653
|
+
continue;
|
|
1654
|
+
}
|
|
1655
|
+
if (tok.startsWith("--scope=")) {
|
|
1656
|
+
scope = parseScope(tok.slice("--scope=".length));
|
|
1657
|
+
continue;
|
|
1658
|
+
}
|
|
1659
|
+
if (tok.startsWith("--")) {
|
|
1660
|
+
throw new Error(`Unknown flag: ${tok}`);
|
|
1661
|
+
}
|
|
1662
|
+
if (name !== null) {
|
|
1663
|
+
throw new Error(`Unexpected extra argument: "${tok}"`);
|
|
1664
|
+
}
|
|
1665
|
+
name = tok;
|
|
1666
|
+
}
|
|
1667
|
+
if (name === null) {
|
|
1668
|
+
throw new Error(`Usage: argent ${command} <flag-name> [--scope project|global]`);
|
|
1669
|
+
}
|
|
1670
|
+
if (!FLAG_NAME_RE.test(name)) {
|
|
1671
|
+
throw new Error(
|
|
1672
|
+
`Invalid flag name "${name}". Must start with a letter and contain only letters, digits, ".", "_", or "-".`
|
|
1673
|
+
);
|
|
1674
|
+
}
|
|
1675
|
+
return { name, scope };
|
|
1676
|
+
}
|
|
1677
|
+
function parseScope(raw) {
|
|
1678
|
+
if (raw === "global" || raw === "project") return raw;
|
|
1679
|
+
throw new Error(`--scope must be "project" or "global", got "${raw}"`);
|
|
1680
|
+
}
|
|
1681
|
+
function formatAvailableFlags(registry) {
|
|
1682
|
+
if (registry.length === 0) {
|
|
1683
|
+
return "Available flags:\n (none defined)";
|
|
1684
|
+
}
|
|
1685
|
+
const maxName = registry.reduce((m2, def) => Math.max(m2, def.name.length), 0);
|
|
1686
|
+
const lines = registry.map((def) => ` ${def.name.padEnd(maxName)} ${def.description}`);
|
|
1687
|
+
return ["Available flags:", ...lines].join("\n");
|
|
1688
|
+
}
|
|
1689
|
+
function printToggleHelp(command, registry) {
|
|
1690
|
+
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.";
|
|
1691
|
+
console.log(`Usage: argent ${command} <flag-name> [--scope project|global]
|
|
1692
|
+
|
|
1693
|
+
${summary}
|
|
1694
|
+
|
|
1695
|
+
${formatAvailableFlags(registry)}
|
|
1696
|
+
|
|
1697
|
+
Storage:
|
|
1698
|
+
~/.argent/flags.json (global, default)
|
|
1699
|
+
<project-root>/.argent/flags.json (project, with --scope project)
|
|
1700
|
+
|
|
1701
|
+
Options:
|
|
1702
|
+
--scope <global|project> Where to write (default: global)
|
|
1703
|
+
--help, -h Show this help
|
|
1704
|
+
`);
|
|
1705
|
+
}
|
|
1706
|
+
function runToggle(argv, command, registry) {
|
|
1707
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
1708
|
+
printToggleHelp(command, registry);
|
|
1709
|
+
return;
|
|
1710
|
+
}
|
|
1711
|
+
let parsed;
|
|
1712
|
+
try {
|
|
1713
|
+
parsed = parseToggleArgs(argv, command);
|
|
1714
|
+
} catch (err) {
|
|
1715
|
+
console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
1716
|
+
process.exit(2);
|
|
1717
|
+
}
|
|
1718
|
+
if (command === "enable" && getFlagDefinition(parsed.name, registry) === void 0) {
|
|
1719
|
+
console.error(
|
|
1720
|
+
`Error: Unknown feature flag "${parsed.name}". Run \`argent flags\` to see available flags.`
|
|
1721
|
+
);
|
|
1722
|
+
process.exit(2);
|
|
1723
|
+
}
|
|
1724
|
+
const filePath = getFlagsPath(parsed.scope);
|
|
1725
|
+
try {
|
|
1726
|
+
if (command === "enable") {
|
|
1727
|
+
setFlag(parsed.name, true, parsed.scope);
|
|
1728
|
+
} else {
|
|
1729
|
+
unsetFlag(parsed.name, parsed.scope);
|
|
1730
|
+
}
|
|
1731
|
+
} catch (err) {
|
|
1732
|
+
console.error(`Failed to ${command} flag: ${err instanceof Error ? err.message : String(err)}`);
|
|
1733
|
+
process.exit(1);
|
|
1734
|
+
}
|
|
1735
|
+
if (command === "enable") {
|
|
1736
|
+
console.log(`Enabled flag "${parsed.name}" (${parsed.scope}). Stored at ${filePath}.`);
|
|
1737
|
+
} else {
|
|
1738
|
+
console.log(`Disabled flag "${parsed.name}" (${parsed.scope}).`);
|
|
1739
|
+
}
|
|
1740
|
+
}
|
|
1741
|
+
function enable(argv, registry = FLAG_REGISTRY) {
|
|
1742
|
+
runToggle(argv, "enable", registry);
|
|
1743
|
+
}
|
|
1744
|
+
function disable(argv, registry = FLAG_REGISTRY) {
|
|
1745
|
+
runToggle(argv, "disable", registry);
|
|
1746
|
+
}
|
|
1747
|
+
function flags(argv, registry = FLAG_REGISTRY) {
|
|
1748
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
1749
|
+
console.log(`Usage: argent flags [--json]
|
|
1750
|
+
|
|
1751
|
+
List the available feature flags and their current state. Flags are
|
|
1752
|
+
predefined; project-scoped values override global ones.
|
|
1753
|
+
|
|
1754
|
+
${formatAvailableFlags(registry)}
|
|
1755
|
+
|
|
1756
|
+
Options:
|
|
1757
|
+
--json Print machine-readable JSON
|
|
1758
|
+
`);
|
|
1759
|
+
return;
|
|
1760
|
+
}
|
|
1761
|
+
const json = argv.includes("--json");
|
|
1762
|
+
const projectFlags = readFlags("project");
|
|
1763
|
+
const globalFlags = readFlags("global");
|
|
1764
|
+
const effective = {};
|
|
1765
|
+
for (const [k2, v2] of Object.entries(globalFlags)) effective[k2] = { value: v2, scope: "global" };
|
|
1766
|
+
for (const [k2, v2] of Object.entries(projectFlags)) effective[k2] = { value: v2, scope: "project" };
|
|
1767
|
+
const registryView = registry.map((def) => {
|
|
1768
|
+
const eff = Object.hasOwn(effective, def.name) ? effective[def.name] : void 0;
|
|
1769
|
+
return {
|
|
1770
|
+
name: def.name,
|
|
1771
|
+
description: def.description,
|
|
1772
|
+
enabled: eff?.value ?? false,
|
|
1773
|
+
scope: eff?.scope ?? null
|
|
1774
|
+
};
|
|
1775
|
+
});
|
|
1776
|
+
const known = new Set(registry.map((def) => def.name));
|
|
1777
|
+
const unrecognized = Object.keys(effective).filter((name) => !known.has(name)).sort().map((name) => ({ name, enabled: effective[name].value, scope: effective[name].scope }));
|
|
1778
|
+
if (json) {
|
|
1779
|
+
console.log(
|
|
1780
|
+
JSON.stringify(
|
|
1781
|
+
{
|
|
1782
|
+
flags: registryView,
|
|
1783
|
+
unrecognized,
|
|
1784
|
+
global: globalFlags,
|
|
1785
|
+
project: projectFlags,
|
|
1786
|
+
effective,
|
|
1787
|
+
paths: {
|
|
1788
|
+
global: getFlagsPath("global"),
|
|
1789
|
+
project: getFlagsPath("project")
|
|
1790
|
+
}
|
|
1791
|
+
},
|
|
1792
|
+
null,
|
|
1793
|
+
2
|
|
1794
|
+
)
|
|
1795
|
+
);
|
|
1796
|
+
return;
|
|
1797
|
+
}
|
|
1798
|
+
if (registryView.length === 0) {
|
|
1799
|
+
console.log("No feature flags are defined.");
|
|
1800
|
+
} else {
|
|
1801
|
+
console.log("Feature flags (project overrides global):");
|
|
1802
|
+
const maxName = registryView.reduce((m2, f2) => Math.max(m2, f2.name.length), 0);
|
|
1803
|
+
for (const f2 of registryView) {
|
|
1804
|
+
const scopeLabel = f2.scope ? ` (${f2.scope})` : "";
|
|
1805
|
+
console.log(` ${f2.name.padEnd(maxName, " ")} ${colorState(f2.enabled)}${scopeLabel}`);
|
|
1806
|
+
console.log(` ${" ".repeat(maxName)} ${f2.description}`);
|
|
1807
|
+
}
|
|
1808
|
+
}
|
|
1809
|
+
if (unrecognized.length > 0) {
|
|
1810
|
+
console.log("\nStored but no longer recognized (safe to `argent disable`):");
|
|
1811
|
+
const maxName = unrecognized.reduce((m2, f2) => Math.max(m2, f2.name.length), 0);
|
|
1812
|
+
for (const f2 of unrecognized) {
|
|
1813
|
+
console.log(` ${f2.name.padEnd(maxName, " ")} ${colorState(f2.enabled)} (${f2.scope})`);
|
|
1814
|
+
}
|
|
1815
|
+
}
|
|
1816
|
+
console.log(`
|
|
1817
|
+
Global: ${getFlagsPath("global")}`);
|
|
1818
|
+
console.log(` Project: ${getFlagsPath("project")}`);
|
|
1819
|
+
}
|
|
1820
|
+
|
|
1821
|
+
// ../../node_modules/@clack/core/dist/index.mjs
|
|
1822
|
+
import { styleText as v } from "node:util";
|
|
1823
|
+
import { stdout as x, stdin as D } from "node:process";
|
|
1824
|
+
import * as b from "node:readline";
|
|
1825
|
+
import E from "node:readline";
|
|
1826
|
+
|
|
1827
|
+
// ../../node_modules/fast-string-truncated-width/dist/utils.js
|
|
1828
|
+
var getCodePointsLength = /* @__PURE__ */ (() => {
|
|
1829
|
+
const SURROGATE_PAIR_RE = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
|
|
1830
|
+
return (input) => {
|
|
1831
|
+
let surrogatePairsNr = 0;
|
|
1832
|
+
SURROGATE_PAIR_RE.lastIndex = 0;
|
|
1833
|
+
while (SURROGATE_PAIR_RE.test(input)) {
|
|
1834
|
+
surrogatePairsNr += 1;
|
|
1835
|
+
}
|
|
1836
|
+
return input.length - surrogatePairsNr;
|
|
1837
|
+
};
|
|
1838
|
+
})();
|
|
1839
|
+
var isFullWidth = (x3) => {
|
|
1840
|
+
return x3 === 12288 || x3 >= 65281 && x3 <= 65376 || x3 >= 65504 && x3 <= 65510;
|
|
1841
|
+
};
|
|
1842
|
+
var isWideNotCJKTNotEmoji = (x3) => {
|
|
1843
|
+
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;
|
|
1844
|
+
};
|
|
1845
|
+
|
|
1846
|
+
// ../../node_modules/fast-string-truncated-width/dist/index.js
|
|
1847
|
+
var ANSI_RE = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]|\u001b\]8;[^;]*;.*?(?:\u0007|\u001b\u005c)/y;
|
|
1848
|
+
var CONTROL_RE = /[\x00-\x08\x0A-\x1F\x7F-\x9F]{1,1000}/y;
|
|
1849
|
+
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;
|
|
1850
|
+
var TAB_RE = /\t{1,1000}/y;
|
|
1851
|
+
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");
|
|
1852
|
+
var LATIN_RE = /(?:[\x20-\x7E\xA0-\xFF](?!\uFE0F)){1,1000}/y;
|
|
1853
|
+
var MODIFIER_RE = new RegExp("\\p{M}+", "gu");
|
|
1854
|
+
var NO_TRUNCATION = { limit: Infinity, ellipsis: "" };
|
|
1855
|
+
var getStringTruncatedWidth = (input, truncationOptions = {}, widthOptions = {}) => {
|
|
1856
|
+
const LIMIT = truncationOptions.limit ?? Infinity;
|
|
1857
|
+
const ELLIPSIS = truncationOptions.ellipsis ?? "";
|
|
1858
|
+
const ELLIPSIS_WIDTH = truncationOptions?.ellipsisWidth ?? (ELLIPSIS ? getStringTruncatedWidth(ELLIPSIS, NO_TRUNCATION, widthOptions).width : 0);
|
|
1859
|
+
const ANSI_WIDTH = 0;
|
|
1860
|
+
const CONTROL_WIDTH = widthOptions.controlWidth ?? 0;
|
|
1861
|
+
const TAB_WIDTH = widthOptions.tabWidth ?? 8;
|
|
1862
|
+
const EMOJI_WIDTH = widthOptions.emojiWidth ?? 2;
|
|
1863
|
+
const FULL_WIDTH_WIDTH = 2;
|
|
1864
|
+
const REGULAR_WIDTH = widthOptions.regularWidth ?? 1;
|
|
1865
|
+
const WIDE_WIDTH = widthOptions.wideWidth ?? FULL_WIDTH_WIDTH;
|
|
1866
|
+
const PARSE_BLOCKS = [
|
|
1867
|
+
[LATIN_RE, REGULAR_WIDTH],
|
|
1868
|
+
[ANSI_RE, ANSI_WIDTH],
|
|
1869
|
+
[CONTROL_RE, CONTROL_WIDTH],
|
|
1870
|
+
[TAB_RE, TAB_WIDTH],
|
|
1871
|
+
[EMOJI_RE, EMOJI_WIDTH],
|
|
1872
|
+
[CJKT_WIDE_RE, WIDE_WIDTH]
|
|
1873
|
+
];
|
|
1874
|
+
let indexPrev = 0;
|
|
1875
|
+
let index = 0;
|
|
1876
|
+
let length = input.length;
|
|
1877
|
+
let lengthExtra = 0;
|
|
1878
|
+
let truncationEnabled = false;
|
|
1879
|
+
let truncationIndex = length;
|
|
1880
|
+
let truncationLimit = Math.max(0, LIMIT - ELLIPSIS_WIDTH);
|
|
1881
|
+
let unmatchedStart = 0;
|
|
1882
|
+
let unmatchedEnd = 0;
|
|
1883
|
+
let width = 0;
|
|
1884
|
+
let widthExtra = 0;
|
|
1885
|
+
outer: while (true) {
|
|
1886
|
+
if (unmatchedEnd > unmatchedStart || index >= length && index > indexPrev) {
|
|
1887
|
+
const unmatched = input.slice(unmatchedStart, unmatchedEnd) || input.slice(indexPrev, index);
|
|
1888
|
+
lengthExtra = 0;
|
|
1889
|
+
for (const char of unmatched.replaceAll(MODIFIER_RE, "")) {
|
|
1890
|
+
const codePoint = char.codePointAt(0) || 0;
|
|
1891
|
+
if (isFullWidth(codePoint)) {
|
|
1892
|
+
widthExtra = FULL_WIDTH_WIDTH;
|
|
1893
|
+
} else if (isWideNotCJKTNotEmoji(codePoint)) {
|
|
1894
|
+
widthExtra = WIDE_WIDTH;
|
|
1895
|
+
} else {
|
|
1896
|
+
widthExtra = REGULAR_WIDTH;
|
|
1897
|
+
}
|
|
1898
|
+
if (width + widthExtra > truncationLimit) {
|
|
1899
|
+
truncationIndex = Math.min(truncationIndex, Math.max(unmatchedStart, indexPrev) + lengthExtra);
|
|
1900
|
+
}
|
|
1901
|
+
if (width + widthExtra > LIMIT) {
|
|
1902
|
+
truncationEnabled = true;
|
|
1903
|
+
break outer;
|
|
1904
|
+
}
|
|
1905
|
+
lengthExtra += char.length;
|
|
1906
|
+
width += widthExtra;
|
|
1907
|
+
}
|
|
1908
|
+
unmatchedStart = unmatchedEnd = 0;
|
|
1909
|
+
}
|
|
1910
|
+
if (index >= length) {
|
|
1911
|
+
break outer;
|
|
1912
|
+
}
|
|
1913
|
+
for (let i = 0, l = PARSE_BLOCKS.length; i < l; i++) {
|
|
1471
1914
|
const [BLOCK_RE, BLOCK_WIDTH] = PARSE_BLOCKS[i];
|
|
1472
1915
|
BLOCK_RE.lastIndex = index;
|
|
1473
1916
|
if (BLOCK_RE.test(input)) {
|
|
@@ -2268,7 +2711,7 @@ ${c}
|
|
|
2268
2711
|
} }).prompt();
|
|
2269
2712
|
|
|
2270
2713
|
// ../argent-cli/src/link.ts
|
|
2271
|
-
var
|
|
2714
|
+
var import_picocolors2 = __toESM(require_picocolors(), 1);
|
|
2272
2715
|
var WILDCARD_HOSTS = /* @__PURE__ */ new Set(["0.0.0.0", "::", "::0", ""]);
|
|
2273
2716
|
function isLoopback2(host) {
|
|
2274
2717
|
return host === "127.0.0.1" || host === "localhost" || host === "::1";
|
|
@@ -2420,587 +2863,311 @@ Examples:
|
|
|
2420
2863
|
argent link --host 10.0.0.42 --port 3001 Confirms interactively, then saves.
|
|
2421
2864
|
argent link --host 10.0.0.42 --token ab12\u2026c2 --yes
|
|
2422
2865
|
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}
|
|
2866
|
+
argent link --host 10.0.0.42 --yes --no-verify
|
|
2867
|
+
Saves immediately, no health check.
|
|
2868
|
+
|
|
2869
|
+
Security:
|
|
2870
|
+
The token (if any) is stored 0600 and sent as a bearer header. An http:// link
|
|
2871
|
+
has no TLS \u2014 treat any non-loopback http link as trusted-network-only. Prefer
|
|
2872
|
+
an https:// tunnel/proxy when crossing untrusted networks.
|
|
2873
|
+
|
|
2874
|
+
Notes:
|
|
2875
|
+
- If ARGENT_TOOLS_URL is also set in your environment, it overrides the link.
|
|
2876
|
+
- To stop using the remote target, run \`argent unlink\`.
|
|
2877
|
+
- \`argent server start/stop/status\` manage the local tool-server lifecycle
|
|
2878
|
+
and are unaffected by linking.
|
|
2879
|
+
- Restart your editor (Claude / Cursor / VS Code) afterwards \u2014 a running
|
|
2880
|
+
\`argent mcp\` process caches the target at startup and won't pick up the
|
|
2881
|
+
new link until it's relaunched.
|
|
2693
2882
|
`);
|
|
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
2883
|
}
|
|
2884
|
+
function printUnlinkHelp() {
|
|
2885
|
+
console.log(`Usage: argent unlink [flags]
|
|
2729
2886
|
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2887
|
+
Remove the persisted remote tool-server link (~/.argent/link.json) and return
|
|
2888
|
+
to default local auto-spawn behaviour.
|
|
2889
|
+
|
|
2890
|
+
Flags:
|
|
2891
|
+
--yes, -y Skip the confirmation prompt.
|
|
2892
|
+
--help, -h Show this help.
|
|
2893
|
+
|
|
2894
|
+
Examples:
|
|
2895
|
+
argent unlink Confirms, then removes the link.
|
|
2896
|
+
argent unlink --yes Removes without confirmation. Safe in scripts.
|
|
2897
|
+
|
|
2898
|
+
Notes:
|
|
2899
|
+
- No-op (exit 0) if no link is currently set.
|
|
2900
|
+
- If ARGENT_TOOLS_URL is also set in your environment, it still takes
|
|
2901
|
+
precedence after unlinking \u2014 unset it manually for fully local behaviour.
|
|
2902
|
+
- This does not stop or start any tool-server process. Use
|
|
2903
|
+
\`argent server stop\` if you also want to terminate a running local server.
|
|
2904
|
+
- Restart your editor afterwards \u2014 a running \`argent mcp\` process won't
|
|
2905
|
+
revert to local auto-spawn until it's relaunched.
|
|
2906
|
+
`);
|
|
2742
2907
|
}
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
if (
|
|
2908
|
+
async function promptHost(existing, initial) {
|
|
2909
|
+
const hostInput = await Pe({
|
|
2910
|
+
message: "Remote host or IP to connect to",
|
|
2911
|
+
placeholder: existing?.host ?? "127.0.0.1",
|
|
2912
|
+
initialValue: initial ?? existing?.host,
|
|
2913
|
+
validate(value) {
|
|
2914
|
+
if (!value || !value.trim()) return "Host cannot be empty.";
|
|
2915
|
+
const trimmed = value.trim();
|
|
2916
|
+
if (WILDCARD_HOSTS.has(trimmed)) {
|
|
2917
|
+
return `${trimmed} is a bind address, not a connect address \u2014 use 127.0.0.1 or the actual reachable host.`;
|
|
2918
|
+
}
|
|
2750
2919
|
}
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2920
|
+
});
|
|
2921
|
+
if (q(hostInput)) {
|
|
2922
|
+
me("Link cancelled.");
|
|
2923
|
+
process.exit(0);
|
|
2754
2924
|
}
|
|
2925
|
+
return hostInput.trim();
|
|
2755
2926
|
}
|
|
2756
|
-
function
|
|
2757
|
-
const
|
|
2758
|
-
|
|
2759
|
-
|
|
2927
|
+
async function promptPort(existing, initial) {
|
|
2928
|
+
const defaultPort = initial ?? existing?.port ?? 3001;
|
|
2929
|
+
const portInput = await Pe({
|
|
2930
|
+
message: "Remote port",
|
|
2931
|
+
placeholder: String(defaultPort),
|
|
2932
|
+
initialValue: String(defaultPort),
|
|
2933
|
+
validate(value) {
|
|
2934
|
+
if (!value || !value.trim()) return "Port cannot be empty.";
|
|
2935
|
+
try {
|
|
2936
|
+
validateConnectPort(value.trim());
|
|
2937
|
+
} catch (err) {
|
|
2938
|
+
if (err instanceof StartFlagError) return err.message;
|
|
2939
|
+
throw err;
|
|
2940
|
+
}
|
|
2941
|
+
}
|
|
2942
|
+
});
|
|
2943
|
+
if (q(portInput)) {
|
|
2944
|
+
me("Link cancelled.");
|
|
2945
|
+
process.exit(0);
|
|
2760
2946
|
}
|
|
2761
|
-
|
|
2762
|
-
return path5.join(resolveProjectRoot(cwd), ".argent", "flags.json");
|
|
2947
|
+
return validateConnectPort(portInput.trim());
|
|
2763
2948
|
}
|
|
2764
|
-
function
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
raw = fs4.readFileSync(filePath, "utf8");
|
|
2768
|
-
} catch {
|
|
2769
|
-
return {};
|
|
2770
|
-
}
|
|
2771
|
-
let parsed;
|
|
2949
|
+
async function preflightHealth(url, token) {
|
|
2950
|
+
const controller = new AbortController();
|
|
2951
|
+
const timer = setTimeout(() => controller.abort(), 3e3);
|
|
2772
2952
|
try {
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
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 {
|
|
2953
|
+
const res = await fetch(`${url}/tools`, {
|
|
2954
|
+
signal: controller.signal,
|
|
2955
|
+
headers: token ? { Authorization: `Bearer ${token}` } : {}
|
|
2956
|
+
});
|
|
2957
|
+
if (!res.ok) {
|
|
2958
|
+
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" : "";
|
|
2959
|
+
return { ok: false, error: `${res.status} ${res.statusText}${hint}` };
|
|
2795
2960
|
}
|
|
2796
|
-
return;
|
|
2961
|
+
return { ok: true };
|
|
2962
|
+
} catch (err) {
|
|
2963
|
+
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
2964
|
+
} finally {
|
|
2965
|
+
clearTimeout(timer);
|
|
2797
2966
|
}
|
|
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
2967
|
}
|
|
2820
|
-
function
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
if (Object.hasOwn(globalFlags, name)) return globalFlags[name];
|
|
2825
|
-
return false;
|
|
2968
|
+
function printRestartHint() {
|
|
2969
|
+
console.log(
|
|
2970
|
+
import_picocolors2.default.dim("Restart your editor to apply the change to any running `argent mcp` session.")
|
|
2971
|
+
);
|
|
2826
2972
|
}
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
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}"`);
|
|
2973
|
+
function printSecurityCaveat(host, token, url) {
|
|
2974
|
+
if (isLoopback2(host)) return;
|
|
2975
|
+
const tls = url.startsWith("https://");
|
|
2976
|
+
if (tls) {
|
|
2977
|
+
if (!token) {
|
|
2978
|
+
process.stderr.write(
|
|
2979
|
+
import_picocolors2.default.yellow(
|
|
2980
|
+
`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.
|
|
2981
|
+
`
|
|
2982
|
+
)
|
|
2983
|
+
);
|
|
2859
2984
|
}
|
|
2860
|
-
|
|
2861
|
-
}
|
|
2862
|
-
if (
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2985
|
+
return;
|
|
2986
|
+
}
|
|
2987
|
+
if (token) {
|
|
2988
|
+
process.stderr.write(
|
|
2989
|
+
import_picocolors2.default.dim(
|
|
2990
|
+
`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.
|
|
2991
|
+
`
|
|
2992
|
+
)
|
|
2868
2993
|
);
|
|
2994
|
+
return;
|
|
2869
2995
|
}
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2996
|
+
process.stderr.write(
|
|
2997
|
+
import_picocolors2.default.yellow(
|
|
2998
|
+
`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).
|
|
2999
|
+
`
|
|
3000
|
+
)
|
|
3001
|
+
);
|
|
2875
3002
|
}
|
|
2876
|
-
function
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
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
|
|
3003
|
+
async function link(argv) {
|
|
3004
|
+
let flags2;
|
|
3005
|
+
try {
|
|
3006
|
+
flags2 = parseLinkFlags(argv);
|
|
3007
|
+
} catch (err) {
|
|
3008
|
+
if (err instanceof StartFlagError) {
|
|
3009
|
+
console.error(`Error: ${err.message}
|
|
2889
3010
|
`);
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
3011
|
+
printLinkHelp();
|
|
3012
|
+
process.exit(2);
|
|
3013
|
+
}
|
|
3014
|
+
throw err;
|
|
3015
|
+
}
|
|
3016
|
+
if (flags2.help) {
|
|
3017
|
+
printLinkHelp();
|
|
2894
3018
|
return;
|
|
2895
3019
|
}
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
} catch (err) {
|
|
2900
|
-
console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
3020
|
+
if (flags2.yes && flags2.host === null) {
|
|
3021
|
+
console.error("Error: --yes requires --host (port defaults to 3001).\n");
|
|
3022
|
+
printLinkHelp();
|
|
2901
3023
|
process.exit(2);
|
|
2902
3024
|
}
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
3025
|
+
const existing = await readLinkConfig();
|
|
3026
|
+
let host;
|
|
3027
|
+
if (flags2.host !== null) {
|
|
3028
|
+
host = flags2.host;
|
|
3029
|
+
} else {
|
|
3030
|
+
ge(import_picocolors2.default.bgCyan(import_picocolors2.default.black(" argent link ")));
|
|
3031
|
+
if (existing) {
|
|
3032
|
+
R2.info(`Current link: ${import_picocolors2.default.cyan(existing.url)} (${existing.createdAt})`);
|
|
3033
|
+
}
|
|
3034
|
+
host = await promptHost(existing);
|
|
2908
3035
|
}
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
3036
|
+
let port;
|
|
3037
|
+
if (flags2.port !== null) {
|
|
3038
|
+
port = flags2.port;
|
|
3039
|
+
} else if (flags2.yes) {
|
|
3040
|
+
port = 3001;
|
|
3041
|
+
} else {
|
|
3042
|
+
port = await promptPort(existing);
|
|
3043
|
+
}
|
|
3044
|
+
const token = flags2.token ?? (existing && existing.host === host && existing.port === port ? existing.token : void 0);
|
|
3045
|
+
let url = flags2.url ?? formatUrl(host, port);
|
|
3046
|
+
if (!flags2.yes && existing) {
|
|
3047
|
+
if (existing.url === url) {
|
|
3048
|
+
R2.info(`Already linked to ${import_picocolors2.default.cyan(url)}.`);
|
|
3049
|
+
ye("No changes.");
|
|
3050
|
+
return;
|
|
3051
|
+
}
|
|
3052
|
+
const overwrite = await ue({
|
|
3053
|
+
message: `Replace existing link ${import_picocolors2.default.dim(existing.url)} with ${import_picocolors2.default.cyan(url)}?`,
|
|
3054
|
+
initialValue: true
|
|
3055
|
+
});
|
|
3056
|
+
if (q(overwrite) || !overwrite) {
|
|
3057
|
+
me("Link cancelled.");
|
|
3058
|
+
process.exit(0);
|
|
2915
3059
|
}
|
|
2916
|
-
} catch (err) {
|
|
2917
|
-
console.error(`Failed to ${command} flag: ${err instanceof Error ? err.message : String(err)}`);
|
|
2918
|
-
process.exit(1);
|
|
2919
3060
|
}
|
|
2920
|
-
if (
|
|
2921
|
-
|
|
3061
|
+
if (!flags2.noVerify) {
|
|
3062
|
+
while (true) {
|
|
3063
|
+
const spinnerActive = !flags2.yes;
|
|
3064
|
+
let spinner = null;
|
|
3065
|
+
if (spinnerActive) {
|
|
3066
|
+
spinner = ft();
|
|
3067
|
+
spinner.start(`Verifying tool-server at ${url}...`);
|
|
3068
|
+
}
|
|
3069
|
+
const result = await preflightHealth(url, token);
|
|
3070
|
+
if (result.ok) {
|
|
3071
|
+
if (spinner) spinner.stop(import_picocolors2.default.green("Tool-server reachable."));
|
|
3072
|
+
break;
|
|
3073
|
+
}
|
|
3074
|
+
if (spinner) spinner.stop(import_picocolors2.default.red("Verification failed."));
|
|
3075
|
+
const detail = result.error ? ` (${result.error})` : "";
|
|
3076
|
+
if (flags2.yes) {
|
|
3077
|
+
console.error(
|
|
3078
|
+
`Error: pre-flight GET ${url}/tools failed${detail}. Make sure the remote tool-server is running, or pass --no-verify to skip.`
|
|
3079
|
+
);
|
|
3080
|
+
process.exit(1);
|
|
3081
|
+
}
|
|
3082
|
+
R2.error(`pre-flight GET ${url}/tools failed${detail}.`);
|
|
3083
|
+
const action = await xe({
|
|
3084
|
+
message: "How would you like to proceed?",
|
|
3085
|
+
options: [
|
|
3086
|
+
{ value: "retry", label: "Retry verification" },
|
|
3087
|
+
{ value: "modify", label: "Modify host and port, then retry" },
|
|
3088
|
+
{ value: "skip", label: "Skip verification and save anyway" },
|
|
3089
|
+
{ value: "cancel", label: "Cancel" }
|
|
3090
|
+
],
|
|
3091
|
+
initialValue: "retry"
|
|
3092
|
+
});
|
|
3093
|
+
if (q(action) || action === "cancel") {
|
|
3094
|
+
me("Link cancelled.");
|
|
3095
|
+
process.exit(0);
|
|
3096
|
+
}
|
|
3097
|
+
if (action === "skip") break;
|
|
3098
|
+
if (action === "modify") {
|
|
3099
|
+
host = await promptHost(existing, host);
|
|
3100
|
+
port = await promptPort(existing, port);
|
|
3101
|
+
url = formatUrl(host, port);
|
|
3102
|
+
}
|
|
3103
|
+
}
|
|
3104
|
+
}
|
|
3105
|
+
const cfg = {
|
|
3106
|
+
url,
|
|
3107
|
+
host,
|
|
3108
|
+
port,
|
|
3109
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3110
|
+
...token ? { token } : {}
|
|
3111
|
+
};
|
|
3112
|
+
await writeLinkConfig(cfg);
|
|
3113
|
+
if (existing && existing.url !== url) {
|
|
3114
|
+
console.log(`${import_picocolors2.default.green("\u2713")} Link updated: ${import_picocolors2.default.dim(existing.url)} \u2192 ${import_picocolors2.default.cyan(url)}`);
|
|
2922
3115
|
} else {
|
|
2923
|
-
console.log(
|
|
3116
|
+
console.log(`${import_picocolors2.default.green("\u2713")} Linked: ${import_picocolors2.default.cyan(url)}`);
|
|
2924
3117
|
}
|
|
3118
|
+
if (token) console.log(import_picocolors2.default.dim(" auth: token stored in ~/.argent/link.json (0600)"));
|
|
3119
|
+
printSecurityCaveat(host, token, url);
|
|
3120
|
+
if (process.env.ARGENT_TOOLS_URL) {
|
|
3121
|
+
console.log(
|
|
3122
|
+
import_picocolors2.default.yellow(
|
|
3123
|
+
`Note: ARGENT_TOOLS_URL=${process.env.ARGENT_TOOLS_URL} is set in your environment and takes precedence over the link.`
|
|
3124
|
+
)
|
|
3125
|
+
);
|
|
3126
|
+
}
|
|
3127
|
+
printRestartHint();
|
|
2925
3128
|
}
|
|
2926
|
-
function
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
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
|
|
3129
|
+
async function unlink3(argv) {
|
|
3130
|
+
let flags2;
|
|
3131
|
+
try {
|
|
3132
|
+
flags2 = parseUnlinkFlags(argv);
|
|
3133
|
+
} catch (err) {
|
|
3134
|
+
if (err instanceof StartFlagError) {
|
|
3135
|
+
console.error(`Error: ${err.message}
|
|
2941
3136
|
`);
|
|
3137
|
+
printUnlinkHelp();
|
|
3138
|
+
process.exit(2);
|
|
3139
|
+
}
|
|
3140
|
+
throw err;
|
|
3141
|
+
}
|
|
3142
|
+
if (flags2.help) {
|
|
3143
|
+
printUnlinkHelp();
|
|
2942
3144
|
return;
|
|
2943
3145
|
}
|
|
2944
|
-
const
|
|
2945
|
-
|
|
2946
|
-
|
|
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
|
-
);
|
|
3146
|
+
const existing = await readLinkConfig();
|
|
3147
|
+
if (!existing) {
|
|
3148
|
+
console.log("Not currently linked \u2014 already using local tool-server.");
|
|
2979
3149
|
return;
|
|
2980
3150
|
}
|
|
2981
|
-
if (
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
console.log(` ${f2.name.padEnd(maxName, " ")} ${stateLabel.padEnd(8)}${scopeLabel}`);
|
|
2990
|
-
console.log(` ${" ".repeat(maxName)} ${f2.description}`);
|
|
3151
|
+
if (!flags2.yes) {
|
|
3152
|
+
const confirmed = await ue({
|
|
3153
|
+
message: `Remove link to ${import_picocolors2.default.cyan(existing.url)}?`,
|
|
3154
|
+
initialValue: true
|
|
3155
|
+
});
|
|
3156
|
+
if (q(confirmed) || !confirmed) {
|
|
3157
|
+
me("Unlink cancelled.");
|
|
3158
|
+
process.exit(0);
|
|
2991
3159
|
}
|
|
2992
3160
|
}
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3161
|
+
await clearLinkConfig();
|
|
3162
|
+
console.log(`${import_picocolors2.default.green("\u2713")} Unlinked from ${import_picocolors2.default.dim(existing.url)}.`);
|
|
3163
|
+
if (process.env.ARGENT_TOOLS_URL) {
|
|
3164
|
+
console.log(
|
|
3165
|
+
import_picocolors2.default.yellow(
|
|
3166
|
+
`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.`
|
|
3167
|
+
)
|
|
3168
|
+
);
|
|
3000
3169
|
}
|
|
3001
|
-
|
|
3002
|
-
Global: ${getFlagsPath("global")}`);
|
|
3003
|
-
console.log(` Project: ${getFlagsPath("project")}`);
|
|
3170
|
+
printRestartHint();
|
|
3004
3171
|
}
|
|
3005
3172
|
export {
|
|
3006
3173
|
FLAG_REGISTRY,
|