@swmansion/argent 0.13.1-next.1 → 0.13.1-next.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli-cmds.mjs +1165 -209
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +4 -0
- package/dist/cli.js.map +1 -1
- package/dist/installer.mjs +441 -433
- package/dist/mcp-server.mjs +90 -89
- package/dist/preview-ui/index.html +746 -47
- package/dist/preview-ui/theme.css +1 -0
- package/dist/preview-window/main.cjs +4 -2
- package/dist/tool-server.cjs +1087 -753
- package/package.json +3 -2
- package/scripts/postinstall.cjs +22 -0
package/dist/cli-cmds.mjs
CHANGED
|
@@ -109,8 +109,8 @@ var require_picocolors = __commonJS({
|
|
|
109
109
|
var require_src = __commonJS({
|
|
110
110
|
"../../node_modules/sisteransi/src/index.js"(exports, module) {
|
|
111
111
|
"use strict";
|
|
112
|
-
var
|
|
113
|
-
var CSI2 = `${
|
|
112
|
+
var ESC3 = "\x1B";
|
|
113
|
+
var CSI2 = `${ESC3}[`;
|
|
114
114
|
var beep = "\x07";
|
|
115
115
|
var cursor3 = {
|
|
116
116
|
to(x, y) {
|
|
@@ -134,8 +134,8 @@ var require_src = __commonJS({
|
|
|
134
134
|
left: `${CSI2}G`,
|
|
135
135
|
hide: `${CSI2}?25l`,
|
|
136
136
|
show: `${CSI2}?25h`,
|
|
137
|
-
save: `${
|
|
138
|
-
restore: `${
|
|
137
|
+
save: `${ESC3}7`,
|
|
138
|
+
restore: `${ESC3}8`
|
|
139
139
|
};
|
|
140
140
|
var scroll = {
|
|
141
141
|
up: (count = 1) => `${CSI2}S`.repeat(count),
|
|
@@ -162,8 +162,8 @@ var require_src = __commonJS({
|
|
|
162
162
|
});
|
|
163
163
|
|
|
164
164
|
// ../argent-cli/src/run.ts
|
|
165
|
-
import * as
|
|
166
|
-
import * as
|
|
165
|
+
import * as fs7 from "node:fs";
|
|
166
|
+
import * as path9 from "node:path";
|
|
167
167
|
|
|
168
168
|
// ../argent-tools-client/src/launcher.ts
|
|
169
169
|
import * as net from "node:net";
|
|
@@ -617,8 +617,8 @@ function parseLinkTarget(input) {
|
|
|
617
617
|
const host = u3.hostname.startsWith("[") ? u3.hostname.slice(1, -1) : u3.hostname;
|
|
618
618
|
if (!host) throw new Error(`URL "${input}" is missing a host.`);
|
|
619
619
|
const port = u3.port ? Number(u3.port) : u3.protocol === "https:" ? 443 : 80;
|
|
620
|
-
const
|
|
621
|
-
const url = `${u3.protocol}//${u3.host}${
|
|
620
|
+
const path12 = u3.pathname === "/" ? "" : u3.pathname.replace(/\/+$/, "");
|
|
621
|
+
const url = `${u3.protocol}//${u3.host}${path12}`;
|
|
622
622
|
const token = u3.username ? decodeURIComponent(u3.username) : void 0;
|
|
623
623
|
return { url, host, port, ...token ? { token } : {} };
|
|
624
624
|
}
|
|
@@ -930,8 +930,8 @@ function createGetModuleFromFilename(basePath = process.argv[1] ? dirname2(proce
|
|
|
930
930
|
return decodedFile;
|
|
931
931
|
};
|
|
932
932
|
}
|
|
933
|
-
function normalizeWindowsPath(
|
|
934
|
-
return
|
|
933
|
+
function normalizeWindowsPath(path12) {
|
|
934
|
+
return path12.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
|
|
935
935
|
}
|
|
936
936
|
|
|
937
937
|
// ../../node_modules/@posthog/core/dist/featureFlagUtils.mjs
|
|
@@ -3483,9 +3483,9 @@ async function addSourceContext(frames) {
|
|
|
3483
3483
|
LRU_FILE_CONTENTS_CACHE.reduce();
|
|
3484
3484
|
return frames;
|
|
3485
3485
|
}
|
|
3486
|
-
function getContextLinesFromFile(
|
|
3486
|
+
function getContextLinesFromFile(path12, ranges, output) {
|
|
3487
3487
|
return new Promise((resolve3) => {
|
|
3488
|
-
const stream = createReadStream(
|
|
3488
|
+
const stream = createReadStream(path12);
|
|
3489
3489
|
const lineReaded = createInterface2({
|
|
3490
3490
|
input: stream
|
|
3491
3491
|
});
|
|
@@ -3500,7 +3500,7 @@ function getContextLinesFromFile(path10, ranges, output) {
|
|
|
3500
3500
|
let rangeStart = range[0];
|
|
3501
3501
|
let rangeEnd = range[1];
|
|
3502
3502
|
function onStreamError() {
|
|
3503
|
-
LRU_FILE_CONTENTS_FS_READ_FAILED.set(
|
|
3503
|
+
LRU_FILE_CONTENTS_FS_READ_FAILED.set(path12, 1);
|
|
3504
3504
|
lineReaded.close();
|
|
3505
3505
|
lineReaded.removeAllListeners();
|
|
3506
3506
|
destroyStreamAndResolve();
|
|
@@ -3561,8 +3561,8 @@ function clearLineContext(frame) {
|
|
|
3561
3561
|
delete frame.context_line;
|
|
3562
3562
|
delete frame.post_context;
|
|
3563
3563
|
}
|
|
3564
|
-
function shouldSkipContextLinesForFile(
|
|
3565
|
-
return
|
|
3564
|
+
function shouldSkipContextLinesForFile(path12) {
|
|
3565
|
+
return path12.startsWith("node:") || path12.endsWith(".min.js") || path12.endsWith(".min.cjs") || path12.endsWith(".min.mjs") || path12.startsWith("data:");
|
|
3566
3566
|
}
|
|
3567
3567
|
function shouldSkipContextLinesForFrame(frame) {
|
|
3568
3568
|
if (void 0 !== frame.lineno && frame.lineno > MAX_CONTEXTLINES_LINENO) return true;
|
|
@@ -6256,9 +6256,9 @@ function isReplitAgent(env) {
|
|
|
6256
6256
|
}
|
|
6257
6257
|
var DEVIN_MARKER_PATH = "/opt/.devin";
|
|
6258
6258
|
var JULES_MARKER_PATH = "/opt/environment_summary.sh";
|
|
6259
|
-
function safeExists(fileExists,
|
|
6259
|
+
function safeExists(fileExists, path12) {
|
|
6260
6260
|
try {
|
|
6261
|
-
return fileExists(
|
|
6261
|
+
return fileExists(path12);
|
|
6262
6262
|
} catch {
|
|
6263
6263
|
return false;
|
|
6264
6264
|
}
|
|
@@ -6712,108 +6712,137 @@ function getBaseProps(runtime) {
|
|
|
6712
6712
|
}
|
|
6713
6713
|
|
|
6714
6714
|
// ../telemetry/src/identity.ts
|
|
6715
|
-
import * as
|
|
6716
|
-
import * as
|
|
6717
|
-
import * as
|
|
6715
|
+
import * as crypto2 from "node:crypto";
|
|
6716
|
+
import * as fs4 from "node:fs";
|
|
6717
|
+
import * as path8 from "node:path";
|
|
6718
6718
|
|
|
6719
6719
|
// ../telemetry/src/paths.ts
|
|
6720
|
-
import * as
|
|
6720
|
+
import * as path7 from "node:path";
|
|
6721
|
+
|
|
6722
|
+
// ../configuration-core/src/flags.ts
|
|
6723
|
+
import * as fs2 from "node:fs";
|
|
6721
6724
|
import * as path4 from "node:path";
|
|
6722
|
-
|
|
6723
|
-
|
|
6724
|
-
|
|
6725
|
-
|
|
6726
|
-
|
|
6727
|
-
|
|
6728
|
-
|
|
6729
|
-
|
|
6730
|
-
|
|
6731
|
-
|
|
6732
|
-
|
|
6725
|
+
import { homedir as homedir3 } from "node:os";
|
|
6726
|
+
var FLAG_REGISTRY = [
|
|
6727
|
+
{
|
|
6728
|
+
name: "disable-auto-screenshot",
|
|
6729
|
+
description: "Disable the automatic screenshot captured after interaction tools."
|
|
6730
|
+
},
|
|
6731
|
+
{
|
|
6732
|
+
name: "argent-lens",
|
|
6733
|
+
description: "Argent Lens \u2014 the propose_variant / await_user_selection tools and the Electron preview window for staging UI design variants and letting a human pick among them. Off by default while the feature is in development."
|
|
6734
|
+
},
|
|
6735
|
+
{
|
|
6736
|
+
name: "artifacts-list-endpoint",
|
|
6737
|
+
description: "Expose GET /artifacts for remote artifact inventory consumers."
|
|
6738
|
+
}
|
|
6739
|
+
];
|
|
6740
|
+
function getFlagDefinition(name, registry = FLAG_REGISTRY) {
|
|
6741
|
+
return registry.find((def) => def.name === name);
|
|
6733
6742
|
}
|
|
6734
|
-
|
|
6735
|
-
|
|
6743
|
+
var PROJECT_MARKERS = [".argent", ".git", "package.json"];
|
|
6744
|
+
function resolveProjectRoot(startDir) {
|
|
6745
|
+
const initial = path4.resolve(startDir);
|
|
6746
|
+
let current = initial;
|
|
6747
|
+
while (true) {
|
|
6748
|
+
for (const marker of PROJECT_MARKERS) {
|
|
6749
|
+
if (fs2.existsSync(path4.join(current, marker))) return current;
|
|
6750
|
+
}
|
|
6751
|
+
const parent = path4.dirname(current);
|
|
6752
|
+
if (parent === current) return initial;
|
|
6753
|
+
current = parent;
|
|
6754
|
+
}
|
|
6736
6755
|
}
|
|
6737
|
-
function
|
|
6738
|
-
|
|
6756
|
+
function getFlagsPath(scope, options = {}) {
|
|
6757
|
+
const home = options.homeDir ?? homedir3();
|
|
6758
|
+
if (scope === "global") {
|
|
6759
|
+
return path4.join(home, ".argent", "flags.json");
|
|
6760
|
+
}
|
|
6761
|
+
const cwd = options.cwd ?? process.cwd();
|
|
6762
|
+
return path4.join(resolveProjectRoot(cwd), ".argent", "flags.json");
|
|
6739
6763
|
}
|
|
6740
|
-
|
|
6741
|
-
|
|
6742
|
-
|
|
6743
|
-
|
|
6744
|
-
|
|
6745
|
-
|
|
6746
|
-
const existing = tryReadId(finalPath);
|
|
6747
|
-
if (existing) {
|
|
6748
|
-
cached = { path: finalPath, id: existing };
|
|
6749
|
-
return existing;
|
|
6764
|
+
function readFlagsFile(filePath) {
|
|
6765
|
+
let raw;
|
|
6766
|
+
try {
|
|
6767
|
+
raw = fs2.readFileSync(filePath, "utf8");
|
|
6768
|
+
} catch {
|
|
6769
|
+
return {};
|
|
6750
6770
|
}
|
|
6751
|
-
|
|
6752
|
-
|
|
6753
|
-
|
|
6754
|
-
|
|
6755
|
-
|
|
6756
|
-
|
|
6757
|
-
|
|
6758
|
-
|
|
6759
|
-
|
|
6760
|
-
|
|
6761
|
-
|
|
6762
|
-
|
|
6763
|
-
|
|
6764
|
-
|
|
6771
|
+
let parsed;
|
|
6772
|
+
try {
|
|
6773
|
+
parsed = JSON.parse(raw);
|
|
6774
|
+
} catch {
|
|
6775
|
+
return {};
|
|
6776
|
+
}
|
|
6777
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return {};
|
|
6778
|
+
const flags2 = parsed.flags;
|
|
6779
|
+
if (!flags2 || typeof flags2 !== "object" || Array.isArray(flags2)) return {};
|
|
6780
|
+
const out = {};
|
|
6781
|
+
for (const [k, v] of Object.entries(flags2)) {
|
|
6782
|
+
if (typeof v === "boolean") out[k] = v;
|
|
6783
|
+
}
|
|
6784
|
+
return out;
|
|
6785
|
+
}
|
|
6786
|
+
function writeFlagsFile(filePath, flags2) {
|
|
6787
|
+
if (Object.keys(flags2).length === 0) {
|
|
6788
|
+
if (fs2.existsSync(filePath)) fs2.rmSync(filePath, { force: true });
|
|
6789
|
+
const parent = path4.dirname(filePath);
|
|
6765
6790
|
try {
|
|
6766
|
-
|
|
6767
|
-
fs2.
|
|
6768
|
-
fs2.fsyncSync(fd);
|
|
6769
|
-
} finally {
|
|
6770
|
-
fs2.closeSync(fd);
|
|
6771
|
-
}
|
|
6772
|
-
fs2.linkSync(tmpPath, finalPath);
|
|
6773
|
-
cached = { path: finalPath, id: uuid };
|
|
6774
|
-
return uuid;
|
|
6775
|
-
} catch (err) {
|
|
6776
|
-
if (err.code === "EEXIST") {
|
|
6777
|
-
const beatUs = tryReadId(finalPath);
|
|
6778
|
-
if (beatUs) {
|
|
6779
|
-
cached = { path: finalPath, id: beatUs };
|
|
6780
|
-
return beatUs;
|
|
6781
|
-
}
|
|
6782
|
-
continue;
|
|
6783
|
-
}
|
|
6784
|
-
throw err;
|
|
6785
|
-
} finally {
|
|
6786
|
-
try {
|
|
6787
|
-
fs2.unlinkSync(tmpPath);
|
|
6788
|
-
} catch {
|
|
6791
|
+
if (fs2.existsSync(parent) && fs2.readdirSync(parent).length === 0) {
|
|
6792
|
+
fs2.rmdirSync(parent);
|
|
6789
6793
|
}
|
|
6794
|
+
} catch {
|
|
6790
6795
|
}
|
|
6796
|
+
return;
|
|
6791
6797
|
}
|
|
6792
|
-
|
|
6798
|
+
fs2.mkdirSync(path4.dirname(filePath), { recursive: true });
|
|
6799
|
+
const tmp = `${filePath}.${process.pid}.tmp`;
|
|
6800
|
+
fs2.writeFileSync(tmp, JSON.stringify({ flags: flags2 }, null, 2) + "\n");
|
|
6801
|
+
fs2.renameSync(tmp, filePath);
|
|
6793
6802
|
}
|
|
6794
|
-
function
|
|
6795
|
-
return
|
|
6803
|
+
function readFlags(scope, options = {}) {
|
|
6804
|
+
return readFlagsFile(getFlagsPath(scope, options));
|
|
6796
6805
|
}
|
|
6797
|
-
function
|
|
6798
|
-
|
|
6799
|
-
|
|
6800
|
-
|
|
6801
|
-
|
|
6802
|
-
|
|
6803
|
-
|
|
6804
|
-
|
|
6805
|
-
|
|
6806
|
-
|
|
6807
|
-
|
|
6808
|
-
|
|
6809
|
-
return
|
|
6806
|
+
function setFlag(name, value, scope, options = {}) {
|
|
6807
|
+
const filePath = getFlagsPath(scope, options);
|
|
6808
|
+
const current = readFlagsFile(filePath);
|
|
6809
|
+
current[name] = value;
|
|
6810
|
+
writeFlagsFile(filePath, current);
|
|
6811
|
+
}
|
|
6812
|
+
function unsetFlag(name, scope, options = {}) {
|
|
6813
|
+
const filePath = getFlagsPath(scope, options);
|
|
6814
|
+
const current = readFlagsFile(filePath);
|
|
6815
|
+
if (!Object.hasOwn(current, name)) return false;
|
|
6816
|
+
delete current[name];
|
|
6817
|
+
writeFlagsFile(filePath, current);
|
|
6818
|
+
return true;
|
|
6819
|
+
}
|
|
6820
|
+
function isFlagEnabled(name, options = {}) {
|
|
6821
|
+
const projectFlags = readFlags("project", options);
|
|
6822
|
+
if (Object.hasOwn(projectFlags, name)) return projectFlags[name];
|
|
6823
|
+
const globalFlags = readFlags("global", options);
|
|
6824
|
+
if (Object.hasOwn(globalFlags, name)) return globalFlags[name];
|
|
6825
|
+
return false;
|
|
6810
6826
|
}
|
|
6811
6827
|
|
|
6812
|
-
// ../
|
|
6813
|
-
import * as
|
|
6828
|
+
// ../configuration-core/src/paths.ts
|
|
6829
|
+
import * as os from "node:os";
|
|
6830
|
+
import * as path5 from "node:path";
|
|
6831
|
+
function nonEmpty(value) {
|
|
6832
|
+
if (value == void 0) return null;
|
|
6833
|
+
const trimmed = value.trim();
|
|
6834
|
+
return trimmed === "" ? null : value;
|
|
6835
|
+
}
|
|
6836
|
+
function argentHomeDir() {
|
|
6837
|
+
const home = process.platform === "win32" ? nonEmpty(process.env.USERPROFILE) ?? os.homedir() : nonEmpty(process.env.HOME) ?? os.homedir();
|
|
6838
|
+
return path5.join(home, ".argent");
|
|
6839
|
+
}
|
|
6840
|
+
function configFilePath() {
|
|
6841
|
+
return path5.join(argentHomeDir(), "config.json");
|
|
6842
|
+
}
|
|
6814
6843
|
|
|
6815
|
-
// ../
|
|
6816
|
-
import * as
|
|
6844
|
+
// ../configuration-core/src/config.ts
|
|
6845
|
+
import * as crypto from "node:crypto";
|
|
6817
6846
|
import * as fs3 from "node:fs";
|
|
6818
6847
|
import * as path6 from "node:path";
|
|
6819
6848
|
function readConfigObject() {
|
|
@@ -6876,7 +6905,7 @@ function updateConfig(mutate) {
|
|
|
6876
6905
|
const next = readConfigObject();
|
|
6877
6906
|
mutate(next);
|
|
6878
6907
|
const finalPath = configFilePath();
|
|
6879
|
-
const tmpPath = path6.join(argentHomeDir(), `.config.tmp.${process.pid}.${
|
|
6908
|
+
const tmpPath = path6.join(argentHomeDir(), `.config.tmp.${process.pid}.${crypto.randomUUID()}`);
|
|
6880
6909
|
const fd = fs3.openSync(tmpPath, "wx", 384);
|
|
6881
6910
|
try {
|
|
6882
6911
|
fs3.writeSync(fd, JSON.stringify(next, null, 2) + "\n");
|
|
@@ -6897,14 +6926,116 @@ function updateConfig(mutate) {
|
|
|
6897
6926
|
if (lock) releaseConfigLock(lock);
|
|
6898
6927
|
}
|
|
6899
6928
|
}
|
|
6929
|
+
function readLensConfig() {
|
|
6930
|
+
const lens2 = readConfigObject().lens;
|
|
6931
|
+
return lens2 && typeof lens2 === "object" ? lens2 : {};
|
|
6932
|
+
}
|
|
6933
|
+
function getRememberedAgent() {
|
|
6934
|
+
const agent = readLensConfig().agent;
|
|
6935
|
+
return typeof agent === "string" && agent.trim() ? agent : null;
|
|
6936
|
+
}
|
|
6937
|
+
function setRememberedAgent(agentId) {
|
|
6938
|
+
updateConfig((config) => {
|
|
6939
|
+
const lens2 = config.lens && typeof config.lens === "object" ? config.lens : {};
|
|
6940
|
+
lens2.agent = agentId;
|
|
6941
|
+
config.lens = lens2;
|
|
6942
|
+
});
|
|
6943
|
+
}
|
|
6944
|
+
function clearRememberedAgent() {
|
|
6945
|
+
updateConfig((config) => {
|
|
6946
|
+
if (config.lens && typeof config.lens === "object") {
|
|
6947
|
+
delete config.lens.agent;
|
|
6948
|
+
}
|
|
6949
|
+
});
|
|
6950
|
+
}
|
|
6951
|
+
|
|
6952
|
+
// ../telemetry/src/paths.ts
|
|
6953
|
+
function identityFilePath() {
|
|
6954
|
+
return path7.join(argentHomeDir(), "telemetry-id");
|
|
6955
|
+
}
|
|
6956
|
+
function debugLogPath() {
|
|
6957
|
+
return path7.join(argentHomeDir(), "telemetry-debug.log");
|
|
6958
|
+
}
|
|
6959
|
+
|
|
6960
|
+
// ../telemetry/src/identity.ts
|
|
6961
|
+
var cached = null;
|
|
6962
|
+
function readOrCreateAnonId() {
|
|
6963
|
+
const finalPath = identityFilePath();
|
|
6964
|
+
if (cached && cached.path === finalPath) return cached.id;
|
|
6965
|
+
const existing = tryReadId(finalPath);
|
|
6966
|
+
if (existing) {
|
|
6967
|
+
cached = { path: finalPath, id: existing };
|
|
6968
|
+
return existing;
|
|
6969
|
+
}
|
|
6970
|
+
fs4.mkdirSync(argentHomeDir(), { recursive: true });
|
|
6971
|
+
const uuid = crypto2.randomUUID();
|
|
6972
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
6973
|
+
const tmpPath = path8.join(
|
|
6974
|
+
argentHomeDir(),
|
|
6975
|
+
`.telemetry-id.tmp.${process.pid}.${crypto2.randomUUID()}`
|
|
6976
|
+
);
|
|
6977
|
+
let fd;
|
|
6978
|
+
try {
|
|
6979
|
+
fd = fs4.openSync(tmpPath, "wx", 384);
|
|
6980
|
+
} catch (err) {
|
|
6981
|
+
if (err.code === "EEXIST") continue;
|
|
6982
|
+
throw err;
|
|
6983
|
+
}
|
|
6984
|
+
try {
|
|
6985
|
+
try {
|
|
6986
|
+
fs4.writeSync(fd, uuid);
|
|
6987
|
+
fs4.fsyncSync(fd);
|
|
6988
|
+
} finally {
|
|
6989
|
+
fs4.closeSync(fd);
|
|
6990
|
+
}
|
|
6991
|
+
fs4.linkSync(tmpPath, finalPath);
|
|
6992
|
+
cached = { path: finalPath, id: uuid };
|
|
6993
|
+
return uuid;
|
|
6994
|
+
} catch (err) {
|
|
6995
|
+
if (err.code === "EEXIST") {
|
|
6996
|
+
const beatUs = tryReadId(finalPath);
|
|
6997
|
+
if (beatUs) {
|
|
6998
|
+
cached = { path: finalPath, id: beatUs };
|
|
6999
|
+
return beatUs;
|
|
7000
|
+
}
|
|
7001
|
+
continue;
|
|
7002
|
+
}
|
|
7003
|
+
throw err;
|
|
7004
|
+
} finally {
|
|
7005
|
+
try {
|
|
7006
|
+
fs4.unlinkSync(tmpPath);
|
|
7007
|
+
} catch {
|
|
7008
|
+
}
|
|
7009
|
+
}
|
|
7010
|
+
}
|
|
7011
|
+
throw new Error("telemetry: failed to create anonymous identity after retries");
|
|
7012
|
+
}
|
|
7013
|
+
function peekAnonId() {
|
|
7014
|
+
return tryReadId(identityFilePath());
|
|
7015
|
+
}
|
|
7016
|
+
function tryReadId(filePath) {
|
|
7017
|
+
let raw;
|
|
7018
|
+
try {
|
|
7019
|
+
const stats = fs4.lstatSync(filePath);
|
|
7020
|
+
if (!stats.isFile()) return null;
|
|
7021
|
+
raw = fs4.readFileSync(filePath, "utf8");
|
|
7022
|
+
} catch (err) {
|
|
7023
|
+
if (err.code === "ENOENT") return null;
|
|
7024
|
+
return null;
|
|
7025
|
+
}
|
|
7026
|
+
const value = raw.trim();
|
|
7027
|
+
if (/^[0-9a-fA-F-]{32,128}$/.test(value)) return value;
|
|
7028
|
+
return null;
|
|
7029
|
+
}
|
|
6900
7030
|
|
|
6901
7031
|
// ../telemetry/src/consent.ts
|
|
7032
|
+
import * as fs5 from "node:fs";
|
|
6902
7033
|
var cache = { current: null };
|
|
6903
7034
|
var sessionOverride = null;
|
|
6904
7035
|
function readConfigOverride() {
|
|
6905
7036
|
let stats;
|
|
6906
7037
|
try {
|
|
6907
|
-
stats =
|
|
7038
|
+
stats = fs5.lstatSync(configFilePath());
|
|
6908
7039
|
} catch (err) {
|
|
6909
7040
|
if (err.code === "ENOENT") {
|
|
6910
7041
|
cache.current = { mtimeMs: null, fingerprint: null, enabledOverride: null };
|
|
@@ -6924,7 +7055,7 @@ function readConfigOverride() {
|
|
|
6924
7055
|
}
|
|
6925
7056
|
let parsedEnabled = null;
|
|
6926
7057
|
try {
|
|
6927
|
-
const raw =
|
|
7058
|
+
const raw = fs5.readFileSync(configFilePath(), "utf8");
|
|
6928
7059
|
const json = JSON.parse(raw);
|
|
6929
7060
|
if (json && typeof json === "object") {
|
|
6930
7061
|
const t2 = json.telemetry;
|
|
@@ -6985,7 +7116,7 @@ function writeConsentFlag(enabled) {
|
|
|
6985
7116
|
}
|
|
6986
7117
|
|
|
6987
7118
|
// ../telemetry/src/debug.ts
|
|
6988
|
-
import * as
|
|
7119
|
+
import * as fs6 from "node:fs";
|
|
6989
7120
|
function isDebugEnabled(env = process.env) {
|
|
6990
7121
|
const v = env.ARGENT_TELEMETRY_DEBUG;
|
|
6991
7122
|
if (!v) return false;
|
|
@@ -7012,8 +7143,8 @@ function emitDebugPayload(payload) {
|
|
|
7012
7143
|
} catch {
|
|
7013
7144
|
}
|
|
7014
7145
|
try {
|
|
7015
|
-
|
|
7016
|
-
|
|
7146
|
+
fs6.mkdirSync(argentHomeDir(), { recursive: true });
|
|
7147
|
+
fs6.appendFileSync(debugLogPath(), line + "\n");
|
|
7017
7148
|
} catch {
|
|
7018
7149
|
}
|
|
7019
7150
|
}
|
|
@@ -7382,8 +7513,8 @@ async function fetchImageToFile(result, outPath) {
|
|
|
7382
7513
|
const res = await fetch(url);
|
|
7383
7514
|
if (!res.ok) throw new Error(`Failed to download image: ${res.status} ${res.statusText}`);
|
|
7384
7515
|
const buf = Buffer.from(await res.arrayBuffer());
|
|
7385
|
-
|
|
7386
|
-
|
|
7516
|
+
fs7.mkdirSync(path9.dirname(path9.resolve(outPath)), { recursive: true });
|
|
7517
|
+
fs7.writeFileSync(outPath, buf);
|
|
7387
7518
|
}
|
|
7388
7519
|
function renderResult(result, outputHint, images, json) {
|
|
7389
7520
|
if (json) return JSON.stringify(result, null, 2);
|
|
@@ -7522,8 +7653,8 @@ Examples:
|
|
|
7522
7653
|
if (outPath && meta.outputHint === "image") {
|
|
7523
7654
|
try {
|
|
7524
7655
|
if (images.length > 0) {
|
|
7525
|
-
|
|
7526
|
-
|
|
7656
|
+
fs7.mkdirSync(path9.dirname(path9.resolve(outPath)), { recursive: true });
|
|
7657
|
+
fs7.writeFileSync(outPath, images[0].data);
|
|
7527
7658
|
} else if (result && typeof result === "object") {
|
|
7528
7659
|
await fetchImageToFile(result, outPath);
|
|
7529
7660
|
}
|
|
@@ -7623,16 +7754,16 @@ Options:
|
|
|
7623
7754
|
}
|
|
7624
7755
|
|
|
7625
7756
|
// ../argent-cli/src/server.ts
|
|
7626
|
-
import * as
|
|
7627
|
-
import * as
|
|
7628
|
-
import { homedir as
|
|
7757
|
+
import * as fs8 from "node:fs";
|
|
7758
|
+
import * as path10 from "node:path";
|
|
7759
|
+
import { homedir as homedir5, networkInterfaces } from "node:os";
|
|
7629
7760
|
import { spawn as spawn2 } from "node:child_process";
|
|
7630
|
-
var STATE_DIR2 =
|
|
7631
|
-
var STATE_FILE2 =
|
|
7632
|
-
var LOG_FILE2 =
|
|
7761
|
+
var STATE_DIR2 = path10.join(homedir5(), ".argent");
|
|
7762
|
+
var STATE_FILE2 = path10.join(STATE_DIR2, "tool-server.json");
|
|
7763
|
+
var LOG_FILE2 = path10.join(STATE_DIR2, "tool-server.log");
|
|
7633
7764
|
function readState2() {
|
|
7634
7765
|
try {
|
|
7635
|
-
return JSON.parse(
|
|
7766
|
+
return JSON.parse(fs8.readFileSync(STATE_FILE2, "utf8"));
|
|
7636
7767
|
} catch {
|
|
7637
7768
|
return null;
|
|
7638
7769
|
}
|
|
@@ -7682,12 +7813,12 @@ async function stopCmd() {
|
|
|
7682
7813
|
console.log(`tool-server stopped (pid ${state2.pid}).`);
|
|
7683
7814
|
}
|
|
7684
7815
|
function logsCmd(follow) {
|
|
7685
|
-
if (!
|
|
7816
|
+
if (!fs8.existsSync(LOG_FILE2)) {
|
|
7686
7817
|
console.log(`No log file at ${LOG_FILE2}`);
|
|
7687
7818
|
return;
|
|
7688
7819
|
}
|
|
7689
7820
|
if (!follow) {
|
|
7690
|
-
process.stdout.write(
|
|
7821
|
+
process.stdout.write(fs8.readFileSync(LOG_FILE2, "utf8"));
|
|
7691
7822
|
return;
|
|
7692
7823
|
}
|
|
7693
7824
|
const child = spawn2("tail", ["-f", LOG_FILE2], { stdio: "inherit" });
|
|
@@ -8029,116 +8160,940 @@ async function server(argv, options) {
|
|
|
8029
8160
|
}
|
|
8030
8161
|
}
|
|
8031
8162
|
|
|
8032
|
-
// ../argent-cli/src/
|
|
8033
|
-
|
|
8163
|
+
// ../argent-cli/src/lens.ts
|
|
8164
|
+
import * as fs9 from "node:fs";
|
|
8165
|
+
import * as os2 from "node:os";
|
|
8166
|
+
import * as path11 from "node:path";
|
|
8034
8167
|
|
|
8035
|
-
// ../
|
|
8036
|
-
import
|
|
8037
|
-
import
|
|
8038
|
-
|
|
8039
|
-
|
|
8168
|
+
// ../argent-cli/src/lens-terminal.ts
|
|
8169
|
+
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
8170
|
+
import { existsSync as existsSync5 } from "node:fs";
|
|
8171
|
+
var ITERM_PATHS = ["/Applications/iTerm.app", `${process.env.HOME ?? ""}/Applications/iTerm.app`];
|
|
8172
|
+
function isITermInstalled(existsSync7 = defaultExists) {
|
|
8173
|
+
return ITERM_PATHS.some((p) => p && existsSync7(p));
|
|
8174
|
+
}
|
|
8175
|
+
function defaultExists(p) {
|
|
8176
|
+
return existsSync5(p);
|
|
8177
|
+
}
|
|
8178
|
+
function resolveTerminal(preferred = "iterm", existsSync7 = defaultExists) {
|
|
8179
|
+
if (preferred === "iterm" && isITermInstalled(existsSync7)) return "iterm";
|
|
8180
|
+
return "terminal";
|
|
8181
|
+
}
|
|
8182
|
+
function escapeAppleScript(s) {
|
|
8183
|
+
return s.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
8184
|
+
}
|
|
8185
|
+
function shellQuote(s) {
|
|
8186
|
+
return "'" + s.replace(/'/g, "'\\''") + "'";
|
|
8187
|
+
}
|
|
8188
|
+
function flattenLine(s) {
|
|
8189
|
+
return s.replace(/\s*[\r\n]+\s*/g, " ").trim();
|
|
8190
|
+
}
|
|
8191
|
+
function buildSpawnScript(app, shellCommand) {
|
|
8192
|
+
const esc = escapeAppleScript(shellCommand);
|
|
8193
|
+
if (app === "iterm") {
|
|
8194
|
+
return [
|
|
8195
|
+
'tell application "iTerm"',
|
|
8196
|
+
" activate",
|
|
8197
|
+
" set w to (create window with default profile)",
|
|
8198
|
+
' set _sid to ""',
|
|
8199
|
+
' set _tty to ""',
|
|
8200
|
+
" tell current session of w",
|
|
8201
|
+
` write text "${esc}"`,
|
|
8202
|
+
" set _tty to tty",
|
|
8203
|
+
" set _sid to id",
|
|
8204
|
+
" end tell",
|
|
8205
|
+
" set _wid to (id of w) as string",
|
|
8206
|
+
"end tell",
|
|
8207
|
+
'return _wid & "|" & _sid & "|" & _tty'
|
|
8208
|
+
].join("\n");
|
|
8209
|
+
}
|
|
8210
|
+
return [
|
|
8211
|
+
'tell application "Terminal"',
|
|
8212
|
+
" activate",
|
|
8213
|
+
` set _tab to do script "${esc}"`,
|
|
8214
|
+
" set _tty to tty of _tab",
|
|
8215
|
+
" set _wid to (id of front window) as string",
|
|
8216
|
+
"end tell",
|
|
8217
|
+
'return _wid & "||" & _tty'
|
|
8218
|
+
].join("\n");
|
|
8219
|
+
}
|
|
8220
|
+
function buildWriteScript(session, text2) {
|
|
8221
|
+
const esc = escapeAppleScript(flattenLine(text2));
|
|
8222
|
+
if (session.app === "iterm") {
|
|
8223
|
+
return [
|
|
8224
|
+
'tell application "iTerm"',
|
|
8225
|
+
" set _found to false",
|
|
8226
|
+
" repeat with w in windows",
|
|
8227
|
+
" repeat with t in tabs of w",
|
|
8228
|
+
" repeat with s in sessions of t",
|
|
8229
|
+
` if (id of s) is "${session.sessionId}" then`,
|
|
8230
|
+
" tell s to write text (character id 27) newline no",
|
|
8231
|
+
" delay 0.15",
|
|
8232
|
+
` tell s to write text "${esc}"`,
|
|
8233
|
+
" delay 0.2",
|
|
8234
|
+
' tell s to write text ""',
|
|
8235
|
+
" set _found to true",
|
|
8236
|
+
" end if",
|
|
8237
|
+
" end repeat",
|
|
8238
|
+
" end repeat",
|
|
8239
|
+
" end repeat",
|
|
8240
|
+
' if not _found then error "session gone"',
|
|
8241
|
+
"end tell"
|
|
8242
|
+
].join("\n");
|
|
8243
|
+
}
|
|
8244
|
+
return [
|
|
8245
|
+
'tell application "Terminal"',
|
|
8246
|
+
" set _found to false",
|
|
8247
|
+
" repeat with w in windows",
|
|
8248
|
+
` if (id of w as string) is "${session.windowId}" then`,
|
|
8249
|
+
" do script (character id 27) in (selected tab of w)",
|
|
8250
|
+
" delay 0.15",
|
|
8251
|
+
` do script "${esc}" in (selected tab of w)`,
|
|
8252
|
+
" delay 0.2",
|
|
8253
|
+
' do script "" in (selected tab of w)',
|
|
8254
|
+
" set _found to true",
|
|
8255
|
+
" end if",
|
|
8256
|
+
" end repeat",
|
|
8257
|
+
' if not _found then error "window gone"',
|
|
8258
|
+
"end tell"
|
|
8259
|
+
].join("\n");
|
|
8260
|
+
}
|
|
8261
|
+
function buildReadScript(session) {
|
|
8262
|
+
if (session.app === "iterm") {
|
|
8263
|
+
return [
|
|
8264
|
+
'tell application "iTerm"',
|
|
8265
|
+
" repeat with w in windows",
|
|
8266
|
+
" repeat with t in tabs of w",
|
|
8267
|
+
" repeat with s in sessions of t",
|
|
8268
|
+
` if (id of s) is "${session.sessionId}" then return (text of s)`,
|
|
8269
|
+
" end repeat",
|
|
8270
|
+
" end repeat",
|
|
8271
|
+
" end repeat",
|
|
8272
|
+
' return ""',
|
|
8273
|
+
"end tell"
|
|
8274
|
+
].join("\n");
|
|
8275
|
+
}
|
|
8276
|
+
return [
|
|
8277
|
+
'tell application "Terminal"',
|
|
8278
|
+
" repeat with w in windows",
|
|
8279
|
+
` if (id of w as string) is "${session.windowId}" then return ((contents of selected tab of w) as text)`,
|
|
8280
|
+
" end repeat",
|
|
8281
|
+
' return ""',
|
|
8282
|
+
"end tell"
|
|
8283
|
+
].join("\n");
|
|
8284
|
+
}
|
|
8285
|
+
function buildEnterScript(session) {
|
|
8286
|
+
if (session.app === "iterm") {
|
|
8287
|
+
return [
|
|
8288
|
+
'tell application "iTerm"',
|
|
8289
|
+
" repeat with w in windows",
|
|
8290
|
+
" repeat with t in tabs of w",
|
|
8291
|
+
" repeat with s in sessions of t",
|
|
8292
|
+
` if (id of s) is "${session.sessionId}" then tell s to write text ""`,
|
|
8293
|
+
" end repeat",
|
|
8294
|
+
" end repeat",
|
|
8295
|
+
" end repeat",
|
|
8296
|
+
"end tell"
|
|
8297
|
+
].join("\n");
|
|
8298
|
+
}
|
|
8299
|
+
return [
|
|
8300
|
+
'tell application "Terminal"',
|
|
8301
|
+
" repeat with w in windows",
|
|
8302
|
+
` if (id of w as string) is "${session.windowId}" then do script "" in (selected tab of w)`,
|
|
8303
|
+
" end repeat",
|
|
8304
|
+
"end tell"
|
|
8305
|
+
].join("\n");
|
|
8306
|
+
}
|
|
8307
|
+
function parseCapture(out) {
|
|
8308
|
+
const parts = out.trim().split("|");
|
|
8309
|
+
return {
|
|
8310
|
+
windowId: parts[0]?.trim() ?? "",
|
|
8311
|
+
sessionId: parts[1]?.trim() ?? "",
|
|
8312
|
+
tty: parts[2]?.trim() ?? ""
|
|
8313
|
+
};
|
|
8314
|
+
}
|
|
8315
|
+
function shortTty(tty) {
|
|
8316
|
+
return tty.startsWith("/dev/") ? tty.slice(5) : tty;
|
|
8317
|
+
}
|
|
8318
|
+
function parseAliveTtys(psOutput) {
|
|
8319
|
+
const set = /* @__PURE__ */ new Set();
|
|
8320
|
+
for (const line of psOutput.split("\n")) {
|
|
8321
|
+
const t2 = line.trim();
|
|
8322
|
+
if (t2 && t2 !== "??") set.add(t2);
|
|
8323
|
+
}
|
|
8324
|
+
return set;
|
|
8325
|
+
}
|
|
8326
|
+
function runOsascript(script) {
|
|
8327
|
+
try {
|
|
8328
|
+
return execFileSync2("/usr/bin/osascript", ["-e", script], {
|
|
8329
|
+
encoding: "utf8",
|
|
8330
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
8331
|
+
});
|
|
8332
|
+
} catch (err) {
|
|
8333
|
+
const e = err;
|
|
8334
|
+
const stderr = (typeof e.stderr === "string" ? e.stderr : e.stderr?.toString()) ?? "";
|
|
8335
|
+
throw new Error(`osascript failed: ${stderr.trim() || e.message || "unknown error"}`, {
|
|
8336
|
+
cause: err
|
|
8337
|
+
});
|
|
8338
|
+
}
|
|
8339
|
+
}
|
|
8340
|
+
function spawnTerminalSession(command, app) {
|
|
8341
|
+
const out = runOsascript(buildSpawnScript(app, command));
|
|
8342
|
+
const { windowId, sessionId: sessionId2, tty } = parseCapture(out);
|
|
8343
|
+
return { app, windowId, sessionId: sessionId2, tty };
|
|
8344
|
+
}
|
|
8345
|
+
function writeToSession(session, text2) {
|
|
8346
|
+
try {
|
|
8347
|
+
runOsascript(buildWriteScript(session, text2));
|
|
8348
|
+
return true;
|
|
8349
|
+
} catch {
|
|
8350
|
+
return false;
|
|
8351
|
+
}
|
|
8352
|
+
}
|
|
8353
|
+
function readSessionText(session) {
|
|
8354
|
+
try {
|
|
8355
|
+
return runOsascript(buildReadScript(session));
|
|
8356
|
+
} catch {
|
|
8357
|
+
return null;
|
|
8358
|
+
}
|
|
8359
|
+
}
|
|
8360
|
+
function pressEnter(session) {
|
|
8361
|
+
try {
|
|
8362
|
+
runOsascript(buildEnterScript(session));
|
|
8363
|
+
return true;
|
|
8364
|
+
} catch {
|
|
8365
|
+
return false;
|
|
8366
|
+
}
|
|
8367
|
+
}
|
|
8368
|
+
function aliveTtys() {
|
|
8369
|
+
try {
|
|
8370
|
+
const out = execFileSync2("/bin/ps", ["-A", "-o", "tty="], { encoding: "utf8" });
|
|
8371
|
+
return parseAliveTtys(out);
|
|
8372
|
+
} catch {
|
|
8373
|
+
return /* @__PURE__ */ new Set();
|
|
8374
|
+
}
|
|
8375
|
+
}
|
|
8376
|
+
function isSessionAlive(session) {
|
|
8377
|
+
if (!session.tty) return false;
|
|
8378
|
+
return aliveTtys().has(shortTty(session.tty));
|
|
8379
|
+
}
|
|
8380
|
+
|
|
8381
|
+
// ../argent-cli/src/lens-pty.ts
|
|
8382
|
+
import { createRequire } from "node:module";
|
|
8383
|
+
var nodeRequire = createRequire(import.meta.url);
|
|
8384
|
+
function loadNodePty(req = nodeRequire) {
|
|
8385
|
+
try {
|
|
8386
|
+
const mod = req("node-pty");
|
|
8387
|
+
return mod && typeof mod.spawn === "function" ? mod : null;
|
|
8388
|
+
} catch {
|
|
8389
|
+
return null;
|
|
8390
|
+
}
|
|
8391
|
+
}
|
|
8392
|
+
var ESC = "\x1B";
|
|
8393
|
+
var ENTER = "\r";
|
|
8394
|
+
var BEAT_AFTER_ESC_MS = 150;
|
|
8395
|
+
var BEAT_AFTER_TEXT_MS = 200;
|
|
8396
|
+
var QUIET_BEFORE_INJECT_MS = 600;
|
|
8397
|
+
var MAX_QUIET_WAIT_MS = 3e3;
|
|
8398
|
+
var QUIET_POLL_MS = 100;
|
|
8399
|
+
function ptyInjectBeats(text2) {
|
|
8400
|
+
return [
|
|
8401
|
+
{ delayBeforeMs: 0, data: ESC },
|
|
8402
|
+
{ delayBeforeMs: BEAT_AFTER_ESC_MS, data: flattenLine(text2) },
|
|
8403
|
+
{ delayBeforeMs: BEAT_AFTER_TEXT_MS, data: ENTER }
|
|
8404
|
+
];
|
|
8405
|
+
}
|
|
8406
|
+
function sleep(ms) {
|
|
8407
|
+
return new Promise((resolve3) => setTimeout(resolve3, ms));
|
|
8408
|
+
}
|
|
8409
|
+
var DEFAULT_COLS = 80;
|
|
8410
|
+
var DEFAULT_ROWS = 24;
|
|
8411
|
+
function startPtyProxy(opts) {
|
|
8412
|
+
const stdin2 = opts.stdin ?? process.stdin;
|
|
8413
|
+
const stdout2 = opts.stdout ?? process.stdout;
|
|
8414
|
+
const signals = opts.signals ?? process;
|
|
8415
|
+
const cols = stdout2.columns ?? DEFAULT_COLS;
|
|
8416
|
+
const rows = stdout2.rows ?? DEFAULT_ROWS;
|
|
8417
|
+
const term = opts.pty.spawn("/bin/sh", ["-c", opts.command], {
|
|
8418
|
+
name: process.env.TERM || "xterm-256color",
|
|
8419
|
+
cols,
|
|
8420
|
+
rows,
|
|
8421
|
+
cwd: opts.cwd,
|
|
8422
|
+
env: opts.env ?? process.env
|
|
8423
|
+
});
|
|
8424
|
+
const observers = [];
|
|
8425
|
+
const exitCbs = [];
|
|
8426
|
+
const dataSub = term.onData((d) => {
|
|
8427
|
+
stdout2.write(d);
|
|
8428
|
+
for (const cb of observers) cb(d);
|
|
8429
|
+
});
|
|
8430
|
+
const wasRaw = Boolean(stdin2.isRaw);
|
|
8431
|
+
if (stdin2.isTTY && stdin2.setRawMode) stdin2.setRawMode(true);
|
|
8432
|
+
stdin2.resume();
|
|
8433
|
+
let lastUserInputAt = 0;
|
|
8434
|
+
const onStdin = (d) => {
|
|
8435
|
+
lastUserInputAt = Date.now();
|
|
8436
|
+
term.write(d.toString("utf8"));
|
|
8437
|
+
};
|
|
8438
|
+
stdin2.on("data", onStdin);
|
|
8439
|
+
const onResize = () => {
|
|
8440
|
+
if (stdout2.columns && stdout2.rows) term.resize(stdout2.columns, stdout2.rows);
|
|
8441
|
+
};
|
|
8442
|
+
signals.on("SIGWINCH", onResize);
|
|
8443
|
+
let disposed = false;
|
|
8444
|
+
const cleanup = () => {
|
|
8445
|
+
if (disposed) return;
|
|
8446
|
+
disposed = true;
|
|
8447
|
+
try {
|
|
8448
|
+
dataSub.dispose();
|
|
8449
|
+
} catch {
|
|
8450
|
+
}
|
|
8451
|
+
stdin2.off("data", onStdin);
|
|
8452
|
+
signals.off("SIGWINCH", onResize);
|
|
8453
|
+
if (stdin2.isTTY && stdin2.setRawMode) stdin2.setRawMode(wasRaw);
|
|
8454
|
+
stdin2.pause();
|
|
8455
|
+
};
|
|
8456
|
+
term.onExit(({ exitCode }) => {
|
|
8457
|
+
cleanup();
|
|
8458
|
+
for (const cb of exitCbs) cb(exitCode ?? 0);
|
|
8459
|
+
});
|
|
8460
|
+
const waitForTypingPause = async () => {
|
|
8461
|
+
const started = Date.now();
|
|
8462
|
+
while (!disposed && lastUserInputAt > 0 && Date.now() - lastUserInputAt < QUIET_BEFORE_INJECT_MS && Date.now() - started < MAX_QUIET_WAIT_MS) {
|
|
8463
|
+
await sleep(QUIET_POLL_MS);
|
|
8464
|
+
}
|
|
8465
|
+
};
|
|
8466
|
+
let queue = Promise.resolve();
|
|
8467
|
+
return {
|
|
8468
|
+
pid: term.pid,
|
|
8469
|
+
inject(text2) {
|
|
8470
|
+
if (disposed) return false;
|
|
8471
|
+
const beats = ptyInjectBeats(text2);
|
|
8472
|
+
queue = queue.then(async () => {
|
|
8473
|
+
await waitForTypingPause();
|
|
8474
|
+
for (const beat of beats) {
|
|
8475
|
+
if (beat.delayBeforeMs) await sleep(beat.delayBeforeMs);
|
|
8476
|
+
if (disposed) return;
|
|
8477
|
+
term.write(beat.data);
|
|
8478
|
+
}
|
|
8479
|
+
}).catch(() => {
|
|
8480
|
+
});
|
|
8481
|
+
return true;
|
|
8482
|
+
},
|
|
8483
|
+
write(data) {
|
|
8484
|
+
if (disposed) return false;
|
|
8485
|
+
try {
|
|
8486
|
+
term.write(data);
|
|
8487
|
+
return true;
|
|
8488
|
+
} catch {
|
|
8489
|
+
return false;
|
|
8490
|
+
}
|
|
8491
|
+
},
|
|
8492
|
+
onData(cb) {
|
|
8493
|
+
observers.push(cb);
|
|
8494
|
+
},
|
|
8495
|
+
onExit(cb) {
|
|
8496
|
+
exitCbs.push(cb);
|
|
8497
|
+
},
|
|
8498
|
+
dispose() {
|
|
8499
|
+
const wasDisposed = disposed;
|
|
8500
|
+
cleanup();
|
|
8501
|
+
if (!wasDisposed) {
|
|
8502
|
+
try {
|
|
8503
|
+
term.kill();
|
|
8504
|
+
} catch {
|
|
8505
|
+
}
|
|
8506
|
+
}
|
|
8507
|
+
}
|
|
8508
|
+
};
|
|
8509
|
+
}
|
|
8510
|
+
|
|
8511
|
+
// ../argent-cli/src/lens-stream.ts
|
|
8512
|
+
function parseSseBuffer(buffer) {
|
|
8513
|
+
const normalised = buffer.replace(/\r\n/g, "\n");
|
|
8514
|
+
const events = [];
|
|
8515
|
+
let rest = normalised;
|
|
8516
|
+
for (; ; ) {
|
|
8517
|
+
const sep3 = rest.indexOf("\n\n");
|
|
8518
|
+
if (sep3 === -1) break;
|
|
8519
|
+
const rawFrame = rest.slice(0, sep3);
|
|
8520
|
+
rest = rest.slice(sep3 + 2);
|
|
8521
|
+
let event = "message";
|
|
8522
|
+
const dataLines = [];
|
|
8523
|
+
for (const line of rawFrame.split("\n")) {
|
|
8524
|
+
if (line === "" || line.startsWith(":")) continue;
|
|
8525
|
+
const colon = line.indexOf(":");
|
|
8526
|
+
const field = colon === -1 ? line : line.slice(0, colon);
|
|
8527
|
+
let value = colon === -1 ? "" : line.slice(colon + 1);
|
|
8528
|
+
if (value.startsWith(" ")) value = value.slice(1);
|
|
8529
|
+
if (field === "event") event = value;
|
|
8530
|
+
else if (field === "data") dataLines.push(value);
|
|
8531
|
+
}
|
|
8532
|
+
if (dataLines.length > 0) events.push({ event, data: dataLines.join("\n") });
|
|
8533
|
+
}
|
|
8534
|
+
return { events, rest };
|
|
8535
|
+
}
|
|
8536
|
+
async function* lensEvents(baseUrl, signal) {
|
|
8537
|
+
const res = await fetch(`${baseUrl}/preview/lens-stream`, {
|
|
8538
|
+
signal,
|
|
8539
|
+
headers: { Accept: "text/event-stream" }
|
|
8540
|
+
});
|
|
8541
|
+
if (!res.ok || !res.body) {
|
|
8542
|
+
throw new Error(`lens-stream: HTTP ${res.status}`);
|
|
8543
|
+
}
|
|
8544
|
+
const reader = res.body.getReader();
|
|
8545
|
+
const decoder = new TextDecoder();
|
|
8546
|
+
let buf = "";
|
|
8547
|
+
try {
|
|
8548
|
+
for (; ; ) {
|
|
8549
|
+
const { value, done } = await reader.read();
|
|
8550
|
+
if (done) return;
|
|
8551
|
+
buf += decoder.decode(value, { stream: true });
|
|
8552
|
+
const { events, rest } = parseSseBuffer(buf);
|
|
8553
|
+
buf = rest;
|
|
8554
|
+
for (const ev of events) yield ev;
|
|
8555
|
+
}
|
|
8556
|
+
} finally {
|
|
8557
|
+
try {
|
|
8558
|
+
reader.releaseLock();
|
|
8559
|
+
} catch {
|
|
8560
|
+
}
|
|
8561
|
+
}
|
|
8562
|
+
}
|
|
8563
|
+
|
|
8564
|
+
// ../argent-cli/src/lens-agents.ts
|
|
8565
|
+
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
8566
|
+
var AGENTS = [
|
|
8040
8567
|
{
|
|
8041
|
-
|
|
8042
|
-
|
|
8568
|
+
id: "claude",
|
|
8569
|
+
displayName: "Claude Code",
|
|
8570
|
+
bin: "claude",
|
|
8571
|
+
launch: (cwd, seed) => `cd ${cwd} 2>/dev/null; claude "$(cat ${seed})"`
|
|
8043
8572
|
},
|
|
8044
8573
|
{
|
|
8045
|
-
|
|
8046
|
-
|
|
8574
|
+
id: "codex",
|
|
8575
|
+
displayName: "Codex CLI",
|
|
8576
|
+
bin: "codex",
|
|
8577
|
+
launch: (cwd, seed) => `cd ${cwd} 2>/dev/null; codex "$(cat ${seed})"`
|
|
8047
8578
|
},
|
|
8048
8579
|
{
|
|
8049
|
-
|
|
8050
|
-
|
|
8580
|
+
id: "gemini",
|
|
8581
|
+
displayName: "Gemini CLI",
|
|
8582
|
+
bin: "gemini",
|
|
8583
|
+
launch: (cwd, seed) => `cd ${cwd} 2>/dev/null; gemini -i "$(cat ${seed})"`
|
|
8584
|
+
},
|
|
8585
|
+
{
|
|
8586
|
+
id: "opencode",
|
|
8587
|
+
displayName: "OpenCode",
|
|
8588
|
+
bin: "opencode",
|
|
8589
|
+
launch: (cwd) => `cd ${cwd} 2>/dev/null; opencode`,
|
|
8590
|
+
injectSeed: true
|
|
8591
|
+
},
|
|
8592
|
+
{
|
|
8593
|
+
id: "cursor",
|
|
8594
|
+
displayName: "Cursor CLI",
|
|
8595
|
+
bin: "cursor-agent",
|
|
8596
|
+
launch: (cwd, seed) => `cd ${cwd} 2>/dev/null; cursor-agent "$(cat ${seed})"`
|
|
8051
8597
|
}
|
|
8052
8598
|
];
|
|
8053
|
-
function
|
|
8054
|
-
return
|
|
8599
|
+
function findAgentById(id) {
|
|
8600
|
+
return AGENTS.find((a2) => a2.id === id);
|
|
8055
8601
|
}
|
|
8056
|
-
|
|
8057
|
-
|
|
8058
|
-
|
|
8059
|
-
|
|
8060
|
-
|
|
8061
|
-
|
|
8062
|
-
|
|
8602
|
+
function agentIds() {
|
|
8603
|
+
return AGENTS.map((a2) => a2.id);
|
|
8604
|
+
}
|
|
8605
|
+
function defaultIsOnPath(bin) {
|
|
8606
|
+
try {
|
|
8607
|
+
execFileSync3(process.platform === "win32" ? "where" : "which", [bin], {
|
|
8608
|
+
stdio: ["ignore", "ignore", "ignore"]
|
|
8609
|
+
});
|
|
8610
|
+
return true;
|
|
8611
|
+
} catch {
|
|
8612
|
+
return false;
|
|
8613
|
+
}
|
|
8614
|
+
}
|
|
8615
|
+
function isAgentInstalled(agent, isOnPath = defaultIsOnPath) {
|
|
8616
|
+
return isOnPath(agent.bin);
|
|
8617
|
+
}
|
|
8618
|
+
function detectInstalledAgents(isOnPath = defaultIsOnPath) {
|
|
8619
|
+
return AGENTS.filter((a2) => isOnPath(a2.bin));
|
|
8620
|
+
}
|
|
8621
|
+
|
|
8622
|
+
// ../argent-cli/src/lens.ts
|
|
8623
|
+
var LIVENESS_POLL_MS = 1200;
|
|
8624
|
+
var SPAWN_GRACE_MS = 8e3;
|
|
8625
|
+
var DEATH_CONFIRMATIONS = 3;
|
|
8626
|
+
var SSE_RECONNECT_MS = 1e3;
|
|
8627
|
+
function sleep2(ms) {
|
|
8628
|
+
return new Promise((resolve3) => setTimeout(resolve3, ms));
|
|
8629
|
+
}
|
|
8630
|
+
var TRUST_PROMPT_RE = /trust this folder|do you trust|yes,? i trust|trust the files in this/i;
|
|
8631
|
+
async function dismissTrustPrompt(session) {
|
|
8632
|
+
const deadline = Date.now() + 12e3;
|
|
8633
|
+
while (Date.now() < deadline) {
|
|
8634
|
+
await sleep2(700);
|
|
8635
|
+
const text2 = readSessionText(session);
|
|
8636
|
+
if (text2 == null) {
|
|
8637
|
+
pressEnter(session);
|
|
8638
|
+
return;
|
|
8639
|
+
}
|
|
8640
|
+
if (TRUST_PROMPT_RE.test(text2)) {
|
|
8641
|
+
pressEnter(session);
|
|
8642
|
+
return;
|
|
8063
8643
|
}
|
|
8064
|
-
const parent = path9.dirname(current);
|
|
8065
|
-
if (parent === current) return initial;
|
|
8066
|
-
current = parent;
|
|
8067
8644
|
}
|
|
8068
8645
|
}
|
|
8069
|
-
function
|
|
8070
|
-
|
|
8071
|
-
|
|
8072
|
-
|
|
8646
|
+
function dismissTrustPromptViaPty(proxy) {
|
|
8647
|
+
let acc = "";
|
|
8648
|
+
let done = false;
|
|
8649
|
+
const deadline = Date.now() + 12e3;
|
|
8650
|
+
proxy.onData((chunk) => {
|
|
8651
|
+
if (done) return;
|
|
8652
|
+
if (Date.now() > deadline) {
|
|
8653
|
+
done = true;
|
|
8654
|
+
return;
|
|
8655
|
+
}
|
|
8656
|
+
acc += chunk;
|
|
8657
|
+
if (TRUST_PROMPT_RE.test(acc)) {
|
|
8658
|
+
done = true;
|
|
8659
|
+
proxy.write("\r");
|
|
8660
|
+
}
|
|
8661
|
+
});
|
|
8662
|
+
}
|
|
8663
|
+
async function injectSeedViaPty(proxy) {
|
|
8664
|
+
await sleep2(5e3);
|
|
8665
|
+
proxy.inject(buildSeedPrompt());
|
|
8666
|
+
}
|
|
8667
|
+
function isInteractiveTty() {
|
|
8668
|
+
return Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
8669
|
+
}
|
|
8670
|
+
var errMsg = (e) => e instanceof Error ? e.message : String(e);
|
|
8671
|
+
function planAgent(agentId) {
|
|
8672
|
+
if (agentId) {
|
|
8673
|
+
const want = findAgentById(agentId);
|
|
8674
|
+
if (!want) {
|
|
8675
|
+
process.stderr.write(
|
|
8676
|
+
`lens: unknown agent "${agentId}". Choose one of: ${agentIds().join(", ")}
|
|
8677
|
+
`
|
|
8678
|
+
);
|
|
8679
|
+
process.exit(2);
|
|
8680
|
+
}
|
|
8681
|
+
if (!isAgentInstalled(want)) {
|
|
8682
|
+
process.stderr.write(
|
|
8683
|
+
`lens: ${want.displayName} (${want.bin}) is not installed or not on PATH.
|
|
8684
|
+
`
|
|
8685
|
+
);
|
|
8686
|
+
process.exit(1);
|
|
8687
|
+
}
|
|
8688
|
+
return { agent: want };
|
|
8073
8689
|
}
|
|
8074
|
-
const
|
|
8075
|
-
|
|
8690
|
+
const installed = detectInstalledAgents();
|
|
8691
|
+
if (installed.length === 0) {
|
|
8692
|
+
process.stderr.write(
|
|
8693
|
+
`lens: no supported coding-agent CLI found on PATH.
|
|
8694
|
+
Install one of: ${AGENTS.map((a2) => a2.bin).join(", ")}, then re-run argent lens.
|
|
8695
|
+
`
|
|
8696
|
+
);
|
|
8697
|
+
process.exit(1);
|
|
8698
|
+
}
|
|
8699
|
+
const remembered = getRememberedAgent();
|
|
8700
|
+
if (remembered) {
|
|
8701
|
+
const found = installed.find((a2) => a2.id === remembered);
|
|
8702
|
+
if (found) return { agent: found };
|
|
8703
|
+
}
|
|
8704
|
+
if (installed.length === 1) return { agent: installed[0] };
|
|
8705
|
+
return { choose: installed };
|
|
8076
8706
|
}
|
|
8077
|
-
function
|
|
8078
|
-
|
|
8707
|
+
async function injectSeedAfterBoot(session) {
|
|
8708
|
+
await sleep2(5e3);
|
|
8709
|
+
writeToSession(session, buildSeedPrompt());
|
|
8710
|
+
}
|
|
8711
|
+
function buildSeedPrompt() {
|
|
8712
|
+
return [
|
|
8713
|
+
"You are running inside an Argent Lens CLI session. The user has the Argent Lens",
|
|
8714
|
+
"preview window open and bound to THIS terminal.",
|
|
8715
|
+
"",
|
|
8716
|
+
"Match your response to the request. If it has a single obvious outcome \u2014 moving or",
|
|
8717
|
+
"renaming something, tweaking one value, or anything with no meaningful design",
|
|
8718
|
+
"alternatives \u2014 just make the change directly and report what you did; do not",
|
|
8719
|
+
'manufacture variants. Only when the request is genuinely open-ended ("restyle",',
|
|
8720
|
+
'"redesign", "make it nicer", or anything with a real design space) should you stage',
|
|
8721
|
+
"variants with the `propose_variant` Argent tool \u2014 at least two per element so the",
|
|
8722
|
+
"user has a real choice.",
|
|
8723
|
+
"",
|
|
8724
|
+
"Either way, end your turn when you're done \u2014 you never block waiting for a pick in",
|
|
8725
|
+
"this session (feedback comes back to you as a message).",
|
|
8726
|
+
"",
|
|
8727
|
+
"The user reviews any staged variants in the Lens window; their feedback arrives here",
|
|
8728
|
+
'as a normal message prefixed "[Argent Lens]" (the variants they chose, comments, and',
|
|
8729
|
+
"change requests). Act on it the same way \u2014 direct edits for concrete fixes, fresh",
|
|
8730
|
+
"variants only where the design is still open.",
|
|
8731
|
+
"",
|
|
8732
|
+
"Wait for the user's first instruction."
|
|
8733
|
+
].join(" ");
|
|
8734
|
+
}
|
|
8735
|
+
function formatLensFeedback(o2) {
|
|
8736
|
+
const parts = [];
|
|
8737
|
+
const sel = (m) => `[${m.by}=${m.value}]`;
|
|
8738
|
+
const chosen = o2.selections.filter((s) => s.chosenVariant);
|
|
8739
|
+
if (chosen.length) {
|
|
8740
|
+
parts.push(
|
|
8741
|
+
"Chosen variants \u2014 " + chosen.map((s) => {
|
|
8742
|
+
const v = s.chosenVariant;
|
|
8743
|
+
const summary = v.summary ? ` (${v.summary})` : "";
|
|
8744
|
+
const where = v.filePath ? ` [src: ${v.filePath}]` : "";
|
|
8745
|
+
const note = s.comment ? ` (note: ${s.comment})` : "";
|
|
8746
|
+
return `"${s.element}" ${sel(s.match)} \u2192 "${v.name}"${summary}${where}${note}`;
|
|
8747
|
+
}).join("; ")
|
|
8748
|
+
);
|
|
8749
|
+
}
|
|
8750
|
+
const notedNoPick = o2.selections.filter((s) => !s.chosenVariant && s.comment);
|
|
8751
|
+
if (notedNoPick.length) {
|
|
8752
|
+
parts.push(
|
|
8753
|
+
"Element notes \u2014 " + notedNoPick.map((s) => `"${s.element}" ${sel(s.match)}: ${s.comment}`).join("; ")
|
|
8754
|
+
);
|
|
8755
|
+
}
|
|
8756
|
+
const touched = new Set([...chosen, ...notedNoPick].map((s) => s.element));
|
|
8757
|
+
const leftAsIs = o2.unselected.map((u3) => u3.element).filter((e) => !touched.has(e));
|
|
8758
|
+
if (leftAsIs.length) {
|
|
8759
|
+
parts.push("Left as-is (reviewed, no change) \u2014 " + leftAsIs.map((e) => `"${e}"`).join(", "));
|
|
8760
|
+
}
|
|
8761
|
+
if (o2.annotations.length) {
|
|
8762
|
+
parts.push(
|
|
8763
|
+
"Comments on the screen \u2014 " + o2.annotations.map((a2) => `"${a2.target}" ${sel(a2.match)}: ${a2.comment}`).join("; ")
|
|
8764
|
+
);
|
|
8765
|
+
}
|
|
8766
|
+
if (o2.globalComment) parts.push("Overall direction \u2014 " + o2.globalComment);
|
|
8767
|
+
const body = parts.length ? parts.join(". ") : "No specific picks were made; review the current variants in the preview window.";
|
|
8768
|
+
const chosenWithComment = chosen.filter((s) => s.comment);
|
|
8769
|
+
const hasDirection = chosenWithComment.length > 0 || notedNoPick.length > 0 || o2.annotations.length > 0 || Boolean(o2.globalComment);
|
|
8770
|
+
const applyChosen = chosen.length ? "Apply the chosen variants to their source files where given. " : "";
|
|
8771
|
+
const closing = hasDirection ? "Handle each request with the smallest change that satisfies it: for a single obvious outcome (a move, rename, or one-value tweak) just make the edit and report it; stage fresh propose_variant options (at least two per element) only where the direction is genuinely open-ended. Then end your turn." : "Nothing further is requested \u2014 make no other changes unless the user asks, and end your turn.";
|
|
8772
|
+
return flattenLine(
|
|
8773
|
+
`[Argent Lens] Feedback from the preview window (round ${o2.round}). ${body}. ` + applyChosen + closing
|
|
8774
|
+
);
|
|
8775
|
+
}
|
|
8776
|
+
function parseArgs(argv) {
|
|
8777
|
+
let terminal;
|
|
8778
|
+
let agent;
|
|
8779
|
+
let help = false;
|
|
8780
|
+
let forget2 = false;
|
|
8781
|
+
for (let i2 = 0; i2 < argv.length; i2++) {
|
|
8782
|
+
const tok = argv[i2];
|
|
8783
|
+
if (tok === "--help" || tok === "-h") help = true;
|
|
8784
|
+
else if (tok === "--forget") forget2 = true;
|
|
8785
|
+
else if (tok === "--terminal" || tok === "-t") {
|
|
8786
|
+
const v = argv[++i2];
|
|
8787
|
+
if (v === "iterm" || v === "terminal") terminal = v;
|
|
8788
|
+
else {
|
|
8789
|
+
process.stderr.write(`lens: --terminal expects "iterm" or "terminal", got "${v ?? ""}"
|
|
8790
|
+
`);
|
|
8791
|
+
process.exit(2);
|
|
8792
|
+
}
|
|
8793
|
+
} else if (tok === "--agent" || tok === "-a") {
|
|
8794
|
+
agent = argv[++i2];
|
|
8795
|
+
if (!agent) {
|
|
8796
|
+
process.stderr.write(`lens: --agent expects one of: ${agentIds().join(", ")}
|
|
8797
|
+
`);
|
|
8798
|
+
process.exit(2);
|
|
8799
|
+
}
|
|
8800
|
+
}
|
|
8801
|
+
}
|
|
8802
|
+
return { terminal, agent, help, forget: forget2 };
|
|
8803
|
+
}
|
|
8804
|
+
function printHelp() {
|
|
8805
|
+
process.stdout.write(
|
|
8806
|
+
`Usage: argent lens [--agent <id>] [--terminal iterm|terminal]
|
|
8807
|
+
|
|
8808
|
+
Open Argent Lens bound to a fresh coding-agent session.
|
|
8809
|
+
|
|
8810
|
+
Opens the Lens preview window and runs your agent IN THIS terminal (it takes
|
|
8811
|
+
over the current window). When you request changes in the preview window they
|
|
8812
|
+
are typed into that agent session as its next prompt. Pick the agent in the
|
|
8813
|
+
window when more than one is installed, or pass --agent. The window streams a
|
|
8814
|
+
running simulator, or offers an in-window picker to boot one. Lens ends when
|
|
8815
|
+
you close the agent.
|
|
8816
|
+
|
|
8817
|
+
If this terminal isn't iTerm or Terminal.app (e.g. tmux / VS Code), the agent
|
|
8818
|
+
opens in a new window instead.
|
|
8819
|
+
|
|
8820
|
+
Options:
|
|
8821
|
+
-a, --agent <id> Agent to bind: ${agentIds().join(", ")}
|
|
8822
|
+
-t, --terminal <app> Terminal for the new-window fallback (iterm preferred)
|
|
8823
|
+
--forget Forget the remembered agent, then exit
|
|
8824
|
+
-h, --help Show this help
|
|
8825
|
+
`
|
|
8826
|
+
);
|
|
8827
|
+
}
|
|
8828
|
+
async function lens(argv, options) {
|
|
8829
|
+
const { terminal: preferred, agent: agentId, help, forget: forget2 } = parseArgs(argv);
|
|
8830
|
+
if (help) {
|
|
8831
|
+
printHelp();
|
|
8832
|
+
return;
|
|
8833
|
+
}
|
|
8834
|
+
if (forget2) {
|
|
8835
|
+
const had = getRememberedAgent();
|
|
8836
|
+
clearRememberedAgent();
|
|
8837
|
+
process.stdout.write(
|
|
8838
|
+
had ? ` Forgot the remembered agent ("${had}"). The picker will show again next run.
|
|
8839
|
+
` : " No agent was remembered.\n"
|
|
8840
|
+
);
|
|
8841
|
+
return;
|
|
8842
|
+
}
|
|
8843
|
+
if (process.platform !== "darwin") {
|
|
8844
|
+
process.stderr.write(
|
|
8845
|
+
"argent lens is macOS-only \u2014 it drives Terminal/iTerm via osascript to run and\nfeed the agent session.\n"
|
|
8846
|
+
);
|
|
8847
|
+
process.exit(1);
|
|
8848
|
+
}
|
|
8849
|
+
if (!isFlagEnabled("argent-lens")) {
|
|
8850
|
+
process.stderr.write(
|
|
8851
|
+
"Argent Lens is behind a feature flag. Enable it first:\n\n argent enable argent-lens\n\n"
|
|
8852
|
+
);
|
|
8853
|
+
process.exit(1);
|
|
8854
|
+
}
|
|
8855
|
+
const plan = planAgent(agentId);
|
|
8856
|
+
const choices = "choose" in plan ? plan.choose : [];
|
|
8857
|
+
const client2 = createToolsClient({ paths: options.paths });
|
|
8858
|
+
let baseUrl;
|
|
8079
8859
|
try {
|
|
8080
|
-
|
|
8081
|
-
} catch {
|
|
8082
|
-
|
|
8860
|
+
baseUrl = (await client2.baseUrl()).url;
|
|
8861
|
+
} catch (err) {
|
|
8862
|
+
process.stderr.write(`lens: could not reach the tool-server: ${errMsg(err)}
|
|
8863
|
+
`);
|
|
8864
|
+
process.exit(1);
|
|
8083
8865
|
}
|
|
8084
|
-
|
|
8866
|
+
const previewUrl = `${baseUrl}/preview/`;
|
|
8085
8867
|
try {
|
|
8086
|
-
|
|
8087
|
-
|
|
8088
|
-
|
|
8868
|
+
const res = await fetch(`${baseUrl}/preview/cli-session`, {
|
|
8869
|
+
method: "POST",
|
|
8870
|
+
headers: { "Content-Type": "application/json" },
|
|
8871
|
+
body: JSON.stringify({
|
|
8872
|
+
active: true,
|
|
8873
|
+
agents: choices.map((a2) => ({ id: a2.id, name: a2.displayName }))
|
|
8874
|
+
})
|
|
8875
|
+
});
|
|
8876
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
8877
|
+
} catch (err) {
|
|
8878
|
+
process.stderr.write(`lens: failed to start the Lens session: ${errMsg(err)}
|
|
8879
|
+
`);
|
|
8880
|
+
process.exit(1);
|
|
8089
8881
|
}
|
|
8090
|
-
|
|
8091
|
-
|
|
8092
|
-
|
|
8093
|
-
|
|
8094
|
-
|
|
8095
|
-
|
|
8882
|
+
let agent = "agent" in plan ? plan.agent : void 0;
|
|
8883
|
+
if (!agent) {
|
|
8884
|
+
process.stdout.write(
|
|
8885
|
+
`
|
|
8886
|
+
Argent Lens window is open: ${previewUrl}
|
|
8887
|
+
Pick an agent in the window to start\u2026
|
|
8888
|
+
`
|
|
8889
|
+
);
|
|
8890
|
+
const picked = await awaitAgentChoiceViaStream(baseUrl);
|
|
8891
|
+
if (picked) {
|
|
8892
|
+
agent = findAgentById(picked.id);
|
|
8893
|
+
if (agent && picked.remember) setRememberedAgent(agent.id);
|
|
8894
|
+
}
|
|
8096
8895
|
}
|
|
8097
|
-
|
|
8098
|
-
|
|
8099
|
-
|
|
8100
|
-
|
|
8101
|
-
|
|
8102
|
-
|
|
8896
|
+
if (!agent) {
|
|
8897
|
+
process.stderr.write("lens: no agent was chosen \u2014 closing the Lens session.\n");
|
|
8898
|
+
await endSession(baseUrl);
|
|
8899
|
+
process.exit(1);
|
|
8900
|
+
}
|
|
8901
|
+
const seedFile = path11.join(os2.tmpdir(), `argent-lens-seed-${process.pid}-${Date.now()}.txt`);
|
|
8902
|
+
fs9.writeFileSync(seedFile, buildSeedPrompt(), "utf8");
|
|
8903
|
+
const launchCmd = agent.launch(shellQuote(process.cwd()), shellQuote(seedFile));
|
|
8904
|
+
const removeSeedFile = () => {
|
|
8103
8905
|
try {
|
|
8104
|
-
|
|
8105
|
-
fs8.rmdirSync(parent);
|
|
8106
|
-
}
|
|
8906
|
+
fs9.rmSync(seedFile, { force: true });
|
|
8107
8907
|
} catch {
|
|
8108
8908
|
}
|
|
8109
|
-
|
|
8909
|
+
};
|
|
8910
|
+
const ptyMod = isInteractiveTty() ? loadNodePty() : null;
|
|
8911
|
+
let inject;
|
|
8912
|
+
let registerDeath;
|
|
8913
|
+
let quiet = false;
|
|
8914
|
+
let killAgent = () => {
|
|
8915
|
+
};
|
|
8916
|
+
if (ptyMod) {
|
|
8917
|
+
let proxy;
|
|
8918
|
+
try {
|
|
8919
|
+
proxy = startPtyProxy({ pty: ptyMod, command: launchCmd, cwd: process.cwd() });
|
|
8920
|
+
} catch (err) {
|
|
8921
|
+
process.stderr.write(`lens: failed to start the agent PTY: ${errMsg(err)}
|
|
8922
|
+
`);
|
|
8923
|
+
removeSeedFile();
|
|
8924
|
+
await endSession(baseUrl);
|
|
8925
|
+
process.exit(1);
|
|
8926
|
+
}
|
|
8927
|
+
quiet = true;
|
|
8928
|
+
dismissTrustPromptViaPty(proxy);
|
|
8929
|
+
if (agent.injectSeed) void injectSeedViaPty(proxy);
|
|
8930
|
+
inject = (text2) => proxy.inject(text2);
|
|
8931
|
+
registerDeath = (onDeath) => proxy.onExit(() => onDeath());
|
|
8932
|
+
killAgent = () => proxy.dispose();
|
|
8933
|
+
} else {
|
|
8934
|
+
const term = resolveTerminal(preferred);
|
|
8935
|
+
let session;
|
|
8936
|
+
try {
|
|
8937
|
+
session = spawnTerminalSession(launchCmd, term);
|
|
8938
|
+
} catch (err) {
|
|
8939
|
+
process.stderr.write(`lens: failed to spawn the agent: ${errMsg(err)}
|
|
8940
|
+
`);
|
|
8941
|
+
removeSeedFile();
|
|
8942
|
+
await endSession(baseUrl);
|
|
8943
|
+
process.exit(1);
|
|
8944
|
+
}
|
|
8945
|
+
process.stdout.write(
|
|
8946
|
+
`
|
|
8947
|
+
Argent Lens is live.
|
|
8948
|
+
|
|
8949
|
+
\u2022 Agent: ${agent.displayName} (new window)
|
|
8950
|
+
\u2022 Preview window: ${previewUrl}
|
|
8951
|
+
|
|
8952
|
+
Ask the agent to redesign something; review the variants in the window and
|
|
8953
|
+
request changes \u2014 they're queued to the agent automatically. End it by
|
|
8954
|
+
closing the agent terminal.
|
|
8955
|
+
|
|
8956
|
+
`
|
|
8957
|
+
);
|
|
8958
|
+
void dismissTrustPrompt(session);
|
|
8959
|
+
if (agent.injectSeed) void injectSeedAfterBoot(session);
|
|
8960
|
+
inject = (text2) => writeToSession(session, text2);
|
|
8961
|
+
registerDeath = (onDeath) => pollSessionDeath(session, onDeath);
|
|
8962
|
+
}
|
|
8963
|
+
let tearingDown = false;
|
|
8964
|
+
const teardown = (code) => {
|
|
8965
|
+
if (tearingDown) return;
|
|
8966
|
+
tearingDown = true;
|
|
8967
|
+
killAgent();
|
|
8968
|
+
void endSession(baseUrl).finally(() => {
|
|
8969
|
+
removeSeedFile();
|
|
8970
|
+
process.exit(code);
|
|
8971
|
+
});
|
|
8972
|
+
};
|
|
8973
|
+
const onSignal = () => {
|
|
8974
|
+
teardown(0);
|
|
8975
|
+
};
|
|
8976
|
+
process.on("SIGINT", onSignal);
|
|
8977
|
+
process.on("SIGTERM", onSignal);
|
|
8978
|
+
await runRelaySession(baseUrl, inject, registerDeath, quiet);
|
|
8979
|
+
teardown(0);
|
|
8980
|
+
}
|
|
8981
|
+
var AGENT_CHOICE_MAX_RECONNECTS = 60;
|
|
8982
|
+
async function awaitAgentChoiceViaStream(baseUrl) {
|
|
8983
|
+
const ac = new AbortController();
|
|
8984
|
+
let reconnects = 0;
|
|
8985
|
+
try {
|
|
8986
|
+
while (!ac.signal.aborted && reconnects <= AGENT_CHOICE_MAX_RECONNECTS) {
|
|
8987
|
+
try {
|
|
8988
|
+
for await (const ev of lensEvents(baseUrl, ac.signal)) {
|
|
8989
|
+
reconnects = 0;
|
|
8990
|
+
if (ev.event === "session-end") return null;
|
|
8991
|
+
if (ev.event === "agent-choice") {
|
|
8992
|
+
try {
|
|
8993
|
+
const payload = JSON.parse(ev.data);
|
|
8994
|
+
if (payload && typeof payload.id === "string" && payload.id) {
|
|
8995
|
+
return { id: payload.id, remember: Boolean(payload.remember) };
|
|
8996
|
+
}
|
|
8997
|
+
} catch {
|
|
8998
|
+
}
|
|
8999
|
+
}
|
|
9000
|
+
}
|
|
9001
|
+
} catch {
|
|
9002
|
+
}
|
|
9003
|
+
reconnects++;
|
|
9004
|
+
if (ac.signal.aborted || reconnects > AGENT_CHOICE_MAX_RECONNECTS) break;
|
|
9005
|
+
await sleep2(SSE_RECONNECT_MS);
|
|
9006
|
+
}
|
|
9007
|
+
} finally {
|
|
9008
|
+
ac.abort();
|
|
8110
9009
|
}
|
|
8111
|
-
|
|
8112
|
-
const tmp = `${filePath}.${process.pid}.tmp`;
|
|
8113
|
-
fs8.writeFileSync(tmp, JSON.stringify({ flags: flags2 }, null, 2) + "\n");
|
|
8114
|
-
fs8.renameSync(tmp, filePath);
|
|
9010
|
+
return null;
|
|
8115
9011
|
}
|
|
8116
|
-
function
|
|
8117
|
-
|
|
9012
|
+
function pollSessionDeath(session, onDeath) {
|
|
9013
|
+
const spawnedAt = Date.now();
|
|
9014
|
+
let deathStreak = 0;
|
|
9015
|
+
const timer = setInterval(() => {
|
|
9016
|
+
if (Date.now() - spawnedAt <= SPAWN_GRACE_MS) return;
|
|
9017
|
+
if (!isSessionAlive(session)) {
|
|
9018
|
+
if (++deathStreak >= DEATH_CONFIRMATIONS) {
|
|
9019
|
+
clearInterval(timer);
|
|
9020
|
+
onDeath();
|
|
9021
|
+
}
|
|
9022
|
+
} else {
|
|
9023
|
+
deathStreak = 0;
|
|
9024
|
+
}
|
|
9025
|
+
}, LIVENESS_POLL_MS);
|
|
9026
|
+
timer.unref?.();
|
|
8118
9027
|
}
|
|
8119
|
-
function
|
|
8120
|
-
const
|
|
8121
|
-
|
|
8122
|
-
|
|
8123
|
-
|
|
9028
|
+
async function runRelaySession(baseUrl, inject, registerDeath, quiet) {
|
|
9029
|
+
const log2 = (s) => {
|
|
9030
|
+
if (!quiet) process.stdout.write(s);
|
|
9031
|
+
};
|
|
9032
|
+
const ac = new AbortController();
|
|
9033
|
+
let alive = true;
|
|
9034
|
+
const stop = () => {
|
|
9035
|
+
if (!alive) return;
|
|
9036
|
+
alive = false;
|
|
9037
|
+
ac.abort();
|
|
9038
|
+
};
|
|
9039
|
+
registerDeath(() => {
|
|
9040
|
+
log2("\n Agent exited.\n");
|
|
9041
|
+
stop();
|
|
9042
|
+
});
|
|
9043
|
+
let lastCompletedAt = 0;
|
|
9044
|
+
try {
|
|
9045
|
+
const seed = await fetchOutcomeOnce(baseUrl);
|
|
9046
|
+
if (seed) lastCompletedAt = seed.completedAt;
|
|
9047
|
+
} catch {
|
|
9048
|
+
}
|
|
9049
|
+
while (alive && !ac.signal.aborted) {
|
|
9050
|
+
try {
|
|
9051
|
+
for await (const ev of lensEvents(baseUrl, ac.signal)) {
|
|
9052
|
+
if (!alive) break;
|
|
9053
|
+
if (ev.event === "session-end") return;
|
|
9054
|
+
if (ev.event !== "outcome") continue;
|
|
9055
|
+
let outcome = null;
|
|
9056
|
+
try {
|
|
9057
|
+
outcome = JSON.parse(ev.data);
|
|
9058
|
+
} catch {
|
|
9059
|
+
continue;
|
|
9060
|
+
}
|
|
9061
|
+
if (outcome && outcome.status === "completed" && outcome.completedAt > lastCompletedAt) {
|
|
9062
|
+
lastCompletedAt = outcome.completedAt;
|
|
9063
|
+
const ok = inject(formatLensFeedback(outcome));
|
|
9064
|
+
if (ok) {
|
|
9065
|
+
const n2 = outcome.selections.filter((s) => s.chosenVariant).length;
|
|
9066
|
+
log2(` \u2192 relayed feedback to the agent (${n2} pick(s)).
|
|
9067
|
+
`);
|
|
9068
|
+
} else {
|
|
9069
|
+
log2(" ! could not reach the agent (it may have exited).\n");
|
|
9070
|
+
}
|
|
9071
|
+
}
|
|
9072
|
+
}
|
|
9073
|
+
} catch {
|
|
9074
|
+
}
|
|
9075
|
+
if (alive && !ac.signal.aborted) await sleep2(SSE_RECONNECT_MS);
|
|
9076
|
+
}
|
|
8124
9077
|
}
|
|
8125
|
-
function
|
|
8126
|
-
const
|
|
8127
|
-
|
|
8128
|
-
|
|
8129
|
-
|
|
8130
|
-
writeFlagsFile(filePath, current);
|
|
8131
|
-
return true;
|
|
9078
|
+
async function fetchOutcomeOnce(baseUrl) {
|
|
9079
|
+
const res = await fetch(`${baseUrl}/preview/outcome`, { cache: "no-store" });
|
|
9080
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
9081
|
+
const body = await res.json();
|
|
9082
|
+
return body.outcome && body.outcome.status === "completed" ? body.outcome : null;
|
|
8132
9083
|
}
|
|
8133
|
-
function
|
|
8134
|
-
|
|
8135
|
-
|
|
8136
|
-
|
|
8137
|
-
|
|
8138
|
-
|
|
9084
|
+
async function endSession(baseUrl) {
|
|
9085
|
+
try {
|
|
9086
|
+
await fetch(`${baseUrl}/preview/cli-session`, {
|
|
9087
|
+
method: "POST",
|
|
9088
|
+
headers: { "Content-Type": "application/json" },
|
|
9089
|
+
body: JSON.stringify({ active: false })
|
|
9090
|
+
});
|
|
9091
|
+
} catch {
|
|
9092
|
+
}
|
|
8139
9093
|
}
|
|
8140
9094
|
|
|
8141
9095
|
// ../argent-cli/src/flags.ts
|
|
9096
|
+
var import_picocolors = __toESM(require_picocolors(), 1);
|
|
8142
9097
|
function colorState(enabled) {
|
|
8143
9098
|
const label = (enabled ? "enabled" : "disabled").padEnd(8);
|
|
8144
9099
|
if (!process.stdout.isTTY) return label;
|
|
@@ -8468,7 +9423,7 @@ var fastStringWidth = (input, options = {}) => {
|
|
|
8468
9423
|
var dist_default2 = fastStringWidth;
|
|
8469
9424
|
|
|
8470
9425
|
// ../../node_modules/fast-wrap-ansi/lib/main.js
|
|
8471
|
-
var
|
|
9426
|
+
var ESC2 = "\x1B";
|
|
8472
9427
|
var CSI = "\x9B";
|
|
8473
9428
|
var END_CODE = 39;
|
|
8474
9429
|
var ANSI_ESCAPE_BELL = "\x07";
|
|
@@ -8502,8 +9457,8 @@ var getClosingCode = (openingCode) => {
|
|
|
8502
9457
|
return 0;
|
|
8503
9458
|
return void 0;
|
|
8504
9459
|
};
|
|
8505
|
-
var wrapAnsiCode = (code) => `${
|
|
8506
|
-
var wrapAnsiHyperlink = (url) => `${
|
|
9460
|
+
var wrapAnsiCode = (code) => `${ESC2}${ANSI_CSI}${code}${ANSI_SGR_TERMINATOR}`;
|
|
9461
|
+
var wrapAnsiHyperlink = (url) => `${ESC2}${ANSI_ESCAPE_LINK}${url}${ANSI_ESCAPE_BELL}`;
|
|
8507
9462
|
var wrapWord = (rows, word, columns) => {
|
|
8508
9463
|
const characters = word[Symbol.iterator]();
|
|
8509
9464
|
let isInsideEscape = false;
|
|
@@ -8522,7 +9477,7 @@ var wrapWord = (rows, word, columns) => {
|
|
|
8522
9477
|
rows.push(character);
|
|
8523
9478
|
visible = 0;
|
|
8524
9479
|
}
|
|
8525
|
-
if (character ===
|
|
9480
|
+
if (character === ESC2 || character === CSI) {
|
|
8526
9481
|
isInsideEscape = true;
|
|
8527
9482
|
isInsideLinkEscape = word.startsWith(ANSI_ESCAPE_LINK, rawCharacterIndex + 1);
|
|
8528
9483
|
}
|
|
@@ -8640,7 +9595,7 @@ var exec = (string, columns, options = {}) => {
|
|
|
8640
9595
|
} else {
|
|
8641
9596
|
inSurrogate = false;
|
|
8642
9597
|
}
|
|
8643
|
-
if (character ===
|
|
9598
|
+
if (character === ESC2 || character === CSI) {
|
|
8644
9599
|
GROUP_REGEX.lastIndex = i2 + 1;
|
|
8645
9600
|
const groupsResult = GROUP_REGEX.exec(preString);
|
|
8646
9601
|
const groups = groupsResult?.groups;
|
|
@@ -9052,8 +10007,8 @@ var n = class extends V {
|
|
|
9052
10007
|
import { styleText as styleText2, stripVTControlCharacters } from "node:util";
|
|
9053
10008
|
import process$1 from "node:process";
|
|
9054
10009
|
var import_sisteransi2 = __toESM(require_src(), 1);
|
|
9055
|
-
import { existsSync as
|
|
9056
|
-
import { dirname as dirname5, join as
|
|
10010
|
+
import { existsSync as existsSync6, lstatSync as lstatSync3, readdirSync as readdirSync2 } from "node:fs";
|
|
10011
|
+
import { dirname as dirname5, join as join11 } from "node:path";
|
|
9057
10012
|
function isUnicodeSupported() {
|
|
9058
10013
|
if (process$1.platform !== "win32") {
|
|
9059
10014
|
return process$1.env.TERM !== "linux";
|
|
@@ -10024,6 +10979,7 @@ export {
|
|
|
10024
10979
|
flags,
|
|
10025
10980
|
getFlagDefinition,
|
|
10026
10981
|
isFlagEnabled,
|
|
10982
|
+
lens,
|
|
10027
10983
|
link,
|
|
10028
10984
|
run,
|
|
10029
10985
|
server,
|