@swmansion/argent 0.15.1-next.7 → 0.15.1-next.9
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 +12 -3
- package/dist/cli-cmds.mjs +3 -1
- package/dist/installer.mjs +411 -33
- package/dist/mcp-server.mjs +3 -1
- package/dist/tool-server.cjs +75 -31
- package/package.json +1 -1
- package/rules/argent.md +2 -2
- package/skills/argent-metro-debugger/SKILL.md +8 -6
- package/skills/argent-metro-debugger/references/failure-scenarios.md +6 -6
- package/skills/argent-tv-interact/SKILL.md +11 -1
package/README.md
CHANGED
|
@@ -12,7 +12,9 @@
|
|
|
12
12
|
**[Argent](https://argent.swmansion.com)** is an **agentic toolkit** that gives your AI assistant direct access to iOS Simulators, Android emulators and physical devices, TVs (Apple TV, Android TV, Fire TV) and Electron/Chromium desktop and web apps. Ask it to tap a button, run a profiler or reproduce an issue manually - all from within your CLI, without switching context.
|
|
13
13
|
|
|
14
14
|
```bash
|
|
15
|
-
npx @swmansion/argent init
|
|
15
|
+
npx @swmansion/argent@latest init
|
|
16
|
+
# or, in a pnpm project (where npm's devEngines check may refuse to run npx):
|
|
17
|
+
pnpm dlx @swmansion/argent@latest init
|
|
16
18
|
```
|
|
17
19
|
|
|
18
20
|
## Supported platforms
|
|
@@ -98,7 +100,9 @@ Argent runs Android emulators on Linux but the default install can be slow if a
|
|
|
98
100
|
From your project root:
|
|
99
101
|
|
|
100
102
|
```bash
|
|
101
|
-
npx @swmansion/argent init
|
|
103
|
+
npx @swmansion/argent@latest init
|
|
104
|
+
# or, in a pnpm project (where npm's devEngines check may refuse to run npx):
|
|
105
|
+
pnpm dlx @swmansion/argent@latest init
|
|
102
106
|
```
|
|
103
107
|
|
|
104
108
|
This command triggers an installation wizard which:
|
|
@@ -121,9 +125,14 @@ teammate gets the same setup on `npm install` — no per-developer global instal
|
|
|
121
125
|
`argent init` — choose the local mode:
|
|
122
126
|
|
|
123
127
|
```bash
|
|
124
|
-
npx @swmansion/argent init --local
|
|
128
|
+
npx @swmansion/argent@latest init --local
|
|
129
|
+
# or, in a pnpm project:
|
|
130
|
+
pnpm dlx @swmansion/argent@latest init --local
|
|
125
131
|
```
|
|
126
132
|
|
|
133
|
+
> Note: in a freshly `pnpm init`-ed project, `npx` itself may refuse to run
|
|
134
|
+
> (npm's `devEngines` check) — use the `pnpm dlx` form there.
|
|
135
|
+
|
|
127
136
|
This adds `@swmansion/argent` to your project's `devDependencies` and writes MCP
|
|
128
137
|
configs that launch the project-local copy (`node node_modules/@swmansion/argent/dist/cli.js mcp`).
|
|
129
138
|
Commit `package.json` + your lockfile, the generated MCP config (`.mcp.json`,
|
package/dist/cli-cmds.mjs
CHANGED
|
@@ -6234,10 +6234,10 @@ var FAILURE_CODES = {
|
|
|
6234
6234
|
ANDROID_UIAUTOMATOR_PARSE_FAILED: "ANDROID_UIAUTOMATOR_PARSE_FAILED",
|
|
6235
6235
|
ANDROID_UIAUTOMATOR_CAPTURE_FAILED: "ANDROID_UIAUTOMATOR_CAPTURE_FAILED",
|
|
6236
6236
|
DEBUGGER_METRO_NOT_RUNNING: "DEBUGGER_METRO_NOT_RUNNING",
|
|
6237
|
-
DEBUGGER_METRO_PROJECT_ROOT_MISSING: "DEBUGGER_METRO_PROJECT_ROOT_MISSING",
|
|
6238
6237
|
DEBUGGER_METRO_NO_TARGETS: "DEBUGGER_METRO_NO_TARGETS",
|
|
6239
6238
|
DEBUGGER_CDP_RUNTIME_EXCEPTION: "DEBUGGER_CDP_RUNTIME_EXCEPTION",
|
|
6240
6239
|
DEBUGGER_CDP_BINDING_TIMEOUT: "DEBUGGER_CDP_BINDING_TIMEOUT",
|
|
6240
|
+
DEBUGGER_CDP_BINDING_UNAVAILABLE: "DEBUGGER_CDP_BINDING_UNAVAILABLE",
|
|
6241
6241
|
DEBUGGER_CDP_PROTOCOL_ERROR: "DEBUGGER_CDP_PROTOCOL_ERROR",
|
|
6242
6242
|
DEBUGGER_RELOAD_FAILED: "DEBUGGER_RELOAD_FAILED",
|
|
6243
6243
|
JS_RUNTIME_CONSOLE_SERVER_BIND_FAILED: "JS_RUNTIME_CONSOLE_SERVER_BIND_FAILED",
|
|
@@ -6557,6 +6557,8 @@ var ALLOWED = {
|
|
|
6557
6557
|
action: PACKAGE_ACTION,
|
|
6558
6558
|
is_success: bool,
|
|
6559
6559
|
duration_ms: DURATION_MS,
|
|
6560
|
+
retry_count: COUNT,
|
|
6561
|
+
last_attempt_duration_ms: DURATION_MS,
|
|
6560
6562
|
...FAILURE_SIGNAL
|
|
6561
6563
|
},
|
|
6562
6564
|
"installation:cli_update_start": {},
|
package/dist/installer.mjs
CHANGED
|
@@ -16141,10 +16141,10 @@ var FAILURE_CODES = {
|
|
|
16141
16141
|
ANDROID_UIAUTOMATOR_PARSE_FAILED: "ANDROID_UIAUTOMATOR_PARSE_FAILED",
|
|
16142
16142
|
ANDROID_UIAUTOMATOR_CAPTURE_FAILED: "ANDROID_UIAUTOMATOR_CAPTURE_FAILED",
|
|
16143
16143
|
DEBUGGER_METRO_NOT_RUNNING: "DEBUGGER_METRO_NOT_RUNNING",
|
|
16144
|
-
DEBUGGER_METRO_PROJECT_ROOT_MISSING: "DEBUGGER_METRO_PROJECT_ROOT_MISSING",
|
|
16145
16144
|
DEBUGGER_METRO_NO_TARGETS: "DEBUGGER_METRO_NO_TARGETS",
|
|
16146
16145
|
DEBUGGER_CDP_RUNTIME_EXCEPTION: "DEBUGGER_CDP_RUNTIME_EXCEPTION",
|
|
16147
16146
|
DEBUGGER_CDP_BINDING_TIMEOUT: "DEBUGGER_CDP_BINDING_TIMEOUT",
|
|
16147
|
+
DEBUGGER_CDP_BINDING_UNAVAILABLE: "DEBUGGER_CDP_BINDING_UNAVAILABLE",
|
|
16148
16148
|
DEBUGGER_CDP_PROTOCOL_ERROR: "DEBUGGER_CDP_PROTOCOL_ERROR",
|
|
16149
16149
|
DEBUGGER_RELOAD_FAILED: "DEBUGGER_RELOAD_FAILED",
|
|
16150
16150
|
JS_RUNTIME_CONSOLE_SERVER_BIND_FAILED: "JS_RUNTIME_CONSOLE_SERVER_BIND_FAILED",
|
|
@@ -16464,6 +16464,8 @@ var ALLOWED = {
|
|
|
16464
16464
|
action: PACKAGE_ACTION,
|
|
16465
16465
|
is_success: bool,
|
|
16466
16466
|
duration_ms: DURATION_MS,
|
|
16467
|
+
retry_count: COUNT,
|
|
16468
|
+
last_attempt_duration_ms: DURATION_MS,
|
|
16467
16469
|
...FAILURE_SIGNAL
|
|
16468
16470
|
},
|
|
16469
16471
|
"installation:cli_update_start": {},
|
|
@@ -20043,12 +20045,30 @@ function detectPackageManager() {
|
|
|
20043
20045
|
if (agent.startsWith("bun")) return "bun";
|
|
20044
20046
|
return "npm";
|
|
20045
20047
|
}
|
|
20048
|
+
function asKnownPm(name) {
|
|
20049
|
+
return name === "npm" || name === "yarn" || name === "pnpm" || name === "bun" ? name : null;
|
|
20050
|
+
}
|
|
20046
20051
|
function pmFromPackageManagerField(dir) {
|
|
20047
20052
|
try {
|
|
20048
20053
|
const pkg = JSON.parse(fs8.readFileSync(path8.join(dir, "package.json"), "utf8"));
|
|
20049
|
-
if (typeof pkg.packageManager
|
|
20050
|
-
|
|
20051
|
-
|
|
20054
|
+
if (typeof pkg.packageManager === "string") {
|
|
20055
|
+
return asKnownPm(pkg.packageManager.split("@")[0]);
|
|
20056
|
+
}
|
|
20057
|
+
return null;
|
|
20058
|
+
} catch {
|
|
20059
|
+
return null;
|
|
20060
|
+
}
|
|
20061
|
+
}
|
|
20062
|
+
function pmFromDevEngines(dir) {
|
|
20063
|
+
try {
|
|
20064
|
+
const pkg = JSON.parse(fs8.readFileSync(path8.join(dir, "package.json"), "utf8"));
|
|
20065
|
+
const devEnginesPm = pkg.devEngines?.packageManager;
|
|
20066
|
+
const names = /* @__PURE__ */ new Set();
|
|
20067
|
+
for (const entry of Array.isArray(devEnginesPm) ? devEnginesPm : [devEnginesPm]) {
|
|
20068
|
+
const name = asKnownPm(entry?.name);
|
|
20069
|
+
if (name) names.add(name);
|
|
20070
|
+
}
|
|
20071
|
+
return names.size === 1 ? [...names][0] : null;
|
|
20052
20072
|
} catch {
|
|
20053
20073
|
return null;
|
|
20054
20074
|
}
|
|
@@ -20061,10 +20081,13 @@ function pmFromLockfile(dir) {
|
|
|
20061
20081
|
if (has("package-lock.json") || has("npm-shrinkwrap.json")) return "npm";
|
|
20062
20082
|
return null;
|
|
20063
20083
|
}
|
|
20084
|
+
function pmFromWorkspaceMarker(dir) {
|
|
20085
|
+
return fs8.existsSync(path8.join(dir, "pnpm-workspace.yaml")) ? "pnpm" : null;
|
|
20086
|
+
}
|
|
20064
20087
|
function detectProjectPackageManager(projectRoot) {
|
|
20065
20088
|
let dir = path8.resolve(projectRoot);
|
|
20066
20089
|
for (; ; ) {
|
|
20067
|
-
const pm = pmFromPackageManagerField(dir) ?? pmFromLockfile(dir);
|
|
20090
|
+
const pm = pmFromPackageManagerField(dir) ?? pmFromLockfile(dir) ?? pmFromDevEngines(dir) ?? pmFromWorkspaceMarker(dir);
|
|
20068
20091
|
if (pm) return pm;
|
|
20069
20092
|
if (fs8.existsSync(path8.join(dir, ".git"))) break;
|
|
20070
20093
|
const parent = path8.dirname(dir);
|
|
@@ -20726,10 +20749,291 @@ function writeTomlOrRemove(filePath, data) {
|
|
|
20726
20749
|
}
|
|
20727
20750
|
writeToml(filePath, data);
|
|
20728
20751
|
}
|
|
20752
|
+
function dirHasEditorEvidence(dir, looksArgentOnly) {
|
|
20753
|
+
return dirExists(dir) && !looksArgentOnly(dir);
|
|
20754
|
+
}
|
|
20755
|
+
function fileHasEditorEvidence(filePath, looksArgentOnly) {
|
|
20756
|
+
return fs13.existsSync(filePath) && !looksArgentOnly(filePath);
|
|
20757
|
+
}
|
|
20758
|
+
function parseJsoncStrict(filePath) {
|
|
20759
|
+
let raw;
|
|
20760
|
+
try {
|
|
20761
|
+
raw = fs13.readFileSync(filePath, "utf8");
|
|
20762
|
+
} catch {
|
|
20763
|
+
return null;
|
|
20764
|
+
}
|
|
20765
|
+
if (raw.charCodeAt(0) === 65279) raw = raw.slice(1);
|
|
20766
|
+
const errors = [];
|
|
20767
|
+
const parsed = parse3(raw, errors, { allowTrailingComma: true });
|
|
20768
|
+
if (errors.length > 0 || parsed === null || typeof parsed !== "object" || Array.isArray(parsed))
|
|
20769
|
+
return null;
|
|
20770
|
+
return parsed;
|
|
20771
|
+
}
|
|
20772
|
+
function parseTomlStrict(filePath) {
|
|
20773
|
+
try {
|
|
20774
|
+
return parse(fs13.readFileSync(filePath, "utf8"));
|
|
20775
|
+
} catch {
|
|
20776
|
+
return null;
|
|
20777
|
+
}
|
|
20778
|
+
}
|
|
20779
|
+
function parseYamlStrict(filePath) {
|
|
20780
|
+
try {
|
|
20781
|
+
const parsed = (0, import_yaml2.parse)(fs13.readFileSync(filePath, "utf8"));
|
|
20782
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) return null;
|
|
20783
|
+
return parsed;
|
|
20784
|
+
} catch {
|
|
20785
|
+
return null;
|
|
20786
|
+
}
|
|
20787
|
+
}
|
|
20788
|
+
function jsonLooksArgentServerOnly(filePath, containerKey) {
|
|
20789
|
+
const config = parseJsoncStrict(filePath);
|
|
20790
|
+
if (config === null) return false;
|
|
20791
|
+
const keys = Object.keys(config);
|
|
20792
|
+
if (keys.length !== 1 || keys[0] !== containerKey) return false;
|
|
20793
|
+
const servers = config[containerKey] ?? {};
|
|
20794
|
+
const serverKeys = Object.keys(servers);
|
|
20795
|
+
return serverKeys.length === 1 && serverKeys[0] === MCP_SERVER_KEY;
|
|
20796
|
+
}
|
|
20797
|
+
var bundledManagedNamesCache = null;
|
|
20798
|
+
function bundledManagedNames(kind) {
|
|
20799
|
+
if (!bundledManagedNamesCache) bundledManagedNamesCache = /* @__PURE__ */ new Map();
|
|
20800
|
+
const cached2 = bundledManagedNamesCache.get(kind);
|
|
20801
|
+
if (cached2) return cached2;
|
|
20802
|
+
let names;
|
|
20803
|
+
try {
|
|
20804
|
+
names = new Set(fs13.readdirSync(kind === "rules" ? RULES_DIR : AGENTS_DIR));
|
|
20805
|
+
} catch {
|
|
20806
|
+
names = /* @__PURE__ */ new Set();
|
|
20807
|
+
}
|
|
20808
|
+
bundledManagedNamesCache.set(kind, names);
|
|
20809
|
+
return names;
|
|
20810
|
+
}
|
|
20811
|
+
function managedDirLooksArgentOnly(dir, kind) {
|
|
20812
|
+
let entries;
|
|
20813
|
+
try {
|
|
20814
|
+
entries = fs13.readdirSync(dir);
|
|
20815
|
+
} catch {
|
|
20816
|
+
return false;
|
|
20817
|
+
}
|
|
20818
|
+
if (entries.length === 0) return false;
|
|
20819
|
+
if (kind === "skills") return entries.every((name) => name.startsWith(ARGENT_SKILL_PREFIX));
|
|
20820
|
+
const bundled = bundledManagedNames(kind);
|
|
20821
|
+
return entries.every((name) => bundled.has(name));
|
|
20822
|
+
}
|
|
20823
|
+
function cursorDirLooksArgentOnly(dir) {
|
|
20824
|
+
let entries;
|
|
20825
|
+
try {
|
|
20826
|
+
entries = fs13.readdirSync(dir);
|
|
20827
|
+
} catch {
|
|
20828
|
+
return false;
|
|
20829
|
+
}
|
|
20830
|
+
if (entries.length === 0) return false;
|
|
20831
|
+
return entries.every((entry) => {
|
|
20832
|
+
const full = path13.join(dir, entry);
|
|
20833
|
+
if (entry === "mcp.json") {
|
|
20834
|
+
return jsonLooksArgentServerOnly(full, "mcpServers");
|
|
20835
|
+
}
|
|
20836
|
+
if (entry === "permissions.json") {
|
|
20837
|
+
const config = parseJsoncStrict(full);
|
|
20838
|
+
if (config === null) return false;
|
|
20839
|
+
const keys = Object.keys(config);
|
|
20840
|
+
if (keys.length !== 1 || keys[0] !== "mcpAllowlist") return false;
|
|
20841
|
+
const list = config.mcpAllowlist;
|
|
20842
|
+
return Array.isArray(list) && list.length > 0 && list.every((rule) => rule === CURSOR_ALLOWLIST_PATTERN);
|
|
20843
|
+
}
|
|
20844
|
+
if (entry === "rules" || entry === "agents" || entry === "skills") {
|
|
20845
|
+
return managedDirLooksArgentOnly(full, entry);
|
|
20846
|
+
}
|
|
20847
|
+
return false;
|
|
20848
|
+
});
|
|
20849
|
+
}
|
|
20850
|
+
function claudeSettingsLooksArgentOnly(filePath) {
|
|
20851
|
+
const config = parseJsoncStrict(filePath);
|
|
20852
|
+
if (config === null) return false;
|
|
20853
|
+
const keys = Object.keys(config);
|
|
20854
|
+
if (keys.length !== 1 || keys[0] !== "permissions") return false;
|
|
20855
|
+
const permissions = config.permissions;
|
|
20856
|
+
if (!isRecord(permissions)) return false;
|
|
20857
|
+
const permKeys = Object.keys(permissions);
|
|
20858
|
+
if (permKeys.length !== 1 || permKeys[0] !== "allow") return false;
|
|
20859
|
+
const allow = permissions.allow;
|
|
20860
|
+
return Array.isArray(allow) && allow.length > 0 && allow.every((rule) => rule === PERMISSION_RULE);
|
|
20861
|
+
}
|
|
20862
|
+
function claudeDirLooksArgentOnly(dir) {
|
|
20863
|
+
let entries;
|
|
20864
|
+
try {
|
|
20865
|
+
entries = fs13.readdirSync(dir);
|
|
20866
|
+
} catch {
|
|
20867
|
+
return false;
|
|
20868
|
+
}
|
|
20869
|
+
if (entries.length === 0) return false;
|
|
20870
|
+
return entries.every((entry) => {
|
|
20871
|
+
const full = path13.join(dir, entry);
|
|
20872
|
+
if (entry === "settings.json") return claudeSettingsLooksArgentOnly(full);
|
|
20873
|
+
if (entry === "rules" || entry === "agents" || entry === "skills") {
|
|
20874
|
+
return managedDirLooksArgentOnly(full, entry);
|
|
20875
|
+
}
|
|
20876
|
+
return false;
|
|
20877
|
+
});
|
|
20878
|
+
}
|
|
20879
|
+
function vscodeDirLooksArgentOnly(dir) {
|
|
20880
|
+
let entries;
|
|
20881
|
+
try {
|
|
20882
|
+
entries = fs13.readdirSync(dir);
|
|
20883
|
+
} catch {
|
|
20884
|
+
return false;
|
|
20885
|
+
}
|
|
20886
|
+
if (entries.length === 0) return false;
|
|
20887
|
+
return entries.every(
|
|
20888
|
+
(entry) => entry === "mcp.json" && jsonLooksArgentServerOnly(path13.join(dir, entry), "servers")
|
|
20889
|
+
);
|
|
20890
|
+
}
|
|
20891
|
+
function windsurfDirLooksArgentOnly(dir) {
|
|
20892
|
+
let entries;
|
|
20893
|
+
try {
|
|
20894
|
+
entries = fs13.readdirSync(dir);
|
|
20895
|
+
} catch {
|
|
20896
|
+
return false;
|
|
20897
|
+
}
|
|
20898
|
+
if (entries.length === 0) return false;
|
|
20899
|
+
return entries.every(
|
|
20900
|
+
(entry) => entry === "mcp_config.json" && jsonLooksArgentServerOnly(path13.join(dir, entry), "mcpServers")
|
|
20901
|
+
);
|
|
20902
|
+
}
|
|
20903
|
+
function zedSettingsLooksArgentOnly(filePath) {
|
|
20904
|
+
const config = parseJsoncStrict(filePath);
|
|
20905
|
+
if (config === null) return false;
|
|
20906
|
+
const keys = Object.keys(config);
|
|
20907
|
+
if (keys.length === 0) return false;
|
|
20908
|
+
return keys.every((key) => {
|
|
20909
|
+
if (key === "context_servers") {
|
|
20910
|
+
const servers = config.context_servers;
|
|
20911
|
+
if (!isRecord(servers)) return false;
|
|
20912
|
+
const serverKeys = Object.keys(servers);
|
|
20913
|
+
return serverKeys.length === 1 && serverKeys[0] === MCP_SERVER_KEY;
|
|
20914
|
+
}
|
|
20915
|
+
if (key === "agent") {
|
|
20916
|
+
const agent = config.agent;
|
|
20917
|
+
if (!isRecord(agent)) return false;
|
|
20918
|
+
const agentKeys = Object.keys(agent);
|
|
20919
|
+
if (agentKeys.length !== 1 || agentKeys[0] !== "tool_permissions") return false;
|
|
20920
|
+
const perms = agent.tool_permissions;
|
|
20921
|
+
if (!isRecord(perms)) return false;
|
|
20922
|
+
const permKeys = Object.keys(perms);
|
|
20923
|
+
return permKeys.length === 1 && permKeys[0] === "default" && (perms.default === "allow" || perms.default === "confirm");
|
|
20924
|
+
}
|
|
20925
|
+
return false;
|
|
20926
|
+
});
|
|
20927
|
+
}
|
|
20928
|
+
function zedDirLooksArgentOnly(dir) {
|
|
20929
|
+
let entries;
|
|
20930
|
+
try {
|
|
20931
|
+
entries = fs13.readdirSync(dir);
|
|
20932
|
+
} catch {
|
|
20933
|
+
return false;
|
|
20934
|
+
}
|
|
20935
|
+
if (entries.length === 0) return false;
|
|
20936
|
+
return entries.every(
|
|
20937
|
+
(entry) => entry === "settings.json" && zedSettingsLooksArgentOnly(path13.join(dir, entry))
|
|
20938
|
+
);
|
|
20939
|
+
}
|
|
20940
|
+
function geminiDirLooksArgentOnly(dir) {
|
|
20941
|
+
let entries;
|
|
20942
|
+
try {
|
|
20943
|
+
entries = fs13.readdirSync(dir);
|
|
20944
|
+
} catch {
|
|
20945
|
+
return false;
|
|
20946
|
+
}
|
|
20947
|
+
if (entries.length === 0) return false;
|
|
20948
|
+
return entries.every((entry) => {
|
|
20949
|
+
const full = path13.join(dir, entry);
|
|
20950
|
+
if (entry === "settings.json") return jsonLooksArgentServerOnly(full, "mcpServers");
|
|
20951
|
+
if (entry === "rules" || entry === "agents") return managedDirLooksArgentOnly(full, entry);
|
|
20952
|
+
return false;
|
|
20953
|
+
});
|
|
20954
|
+
}
|
|
20955
|
+
function hermesConfigLooksArgentOnly(filePath) {
|
|
20956
|
+
const config = parseYamlStrict(filePath);
|
|
20957
|
+
if (config === null) return false;
|
|
20958
|
+
const keys = Object.keys(config);
|
|
20959
|
+
if (keys.length !== 1 || keys[0] !== "mcp_servers") return false;
|
|
20960
|
+
const servers = config.mcp_servers;
|
|
20961
|
+
if (!isRecord(servers)) return false;
|
|
20962
|
+
const serverKeys = Object.keys(servers);
|
|
20963
|
+
return serverKeys.length === 1 && serverKeys[0] === MCP_SERVER_KEY;
|
|
20964
|
+
}
|
|
20965
|
+
function hermesDirLooksArgentOnly(dir) {
|
|
20966
|
+
let entries;
|
|
20967
|
+
try {
|
|
20968
|
+
entries = fs13.readdirSync(dir);
|
|
20969
|
+
} catch {
|
|
20970
|
+
return false;
|
|
20971
|
+
}
|
|
20972
|
+
if (entries.length === 0) return false;
|
|
20973
|
+
return entries.every(
|
|
20974
|
+
(entry) => entry === "config.yaml" && hermesConfigLooksArgentOnly(path13.join(dir, entry))
|
|
20975
|
+
);
|
|
20976
|
+
}
|
|
20977
|
+
function kiroDirLooksArgentOnly(dir) {
|
|
20978
|
+
let entries;
|
|
20979
|
+
try {
|
|
20980
|
+
entries = fs13.readdirSync(dir);
|
|
20981
|
+
} catch {
|
|
20982
|
+
return false;
|
|
20983
|
+
}
|
|
20984
|
+
if (entries.length === 0) return false;
|
|
20985
|
+
return entries.every((entry) => {
|
|
20986
|
+
if (entry !== "settings") return false;
|
|
20987
|
+
const settingsDir = path13.join(dir, entry);
|
|
20988
|
+
let settingsEntries;
|
|
20989
|
+
try {
|
|
20990
|
+
settingsEntries = fs13.readdirSync(settingsDir);
|
|
20991
|
+
} catch {
|
|
20992
|
+
return false;
|
|
20993
|
+
}
|
|
20994
|
+
if (settingsEntries.length === 0) return false;
|
|
20995
|
+
return settingsEntries.every(
|
|
20996
|
+
(name) => name === "mcp.json" && jsonLooksArgentServerOnly(path13.join(settingsDir, name), "mcpServers")
|
|
20997
|
+
);
|
|
20998
|
+
});
|
|
20999
|
+
}
|
|
21000
|
+
function codexDirLooksArgentOnly(dir) {
|
|
21001
|
+
let entries;
|
|
21002
|
+
try {
|
|
21003
|
+
entries = fs13.readdirSync(dir);
|
|
21004
|
+
} catch {
|
|
21005
|
+
return false;
|
|
21006
|
+
}
|
|
21007
|
+
if (entries.length === 0) return false;
|
|
21008
|
+
return entries.every((entry) => {
|
|
21009
|
+
const full = path13.join(dir, entry);
|
|
21010
|
+
if (entry === "config.toml") {
|
|
21011
|
+
const config = parseTomlStrict(full);
|
|
21012
|
+
if (config === null) return false;
|
|
21013
|
+
const configEntries = Object.entries(config);
|
|
21014
|
+
if (configEntries.length === 0) return false;
|
|
21015
|
+
return configEntries.every(([key, value]) => {
|
|
21016
|
+
if (key === "mcp_servers") {
|
|
21017
|
+
const servers = value ?? {};
|
|
21018
|
+
const serverKeys = Object.keys(servers);
|
|
21019
|
+
return serverKeys.length === 1 && serverKeys[0] === MCP_SERVER_KEY;
|
|
21020
|
+
}
|
|
21021
|
+
if (key === "developer_instructions") {
|
|
21022
|
+
return typeof value === "string" && removeArgentSection(value) === "";
|
|
21023
|
+
}
|
|
21024
|
+
return false;
|
|
21025
|
+
});
|
|
21026
|
+
}
|
|
21027
|
+
if (entry === "rules" || entry === "agents" || entry === "skills") {
|
|
21028
|
+
return managedDirLooksArgentOnly(full, entry);
|
|
21029
|
+
}
|
|
21030
|
+
return false;
|
|
21031
|
+
});
|
|
21032
|
+
}
|
|
20729
21033
|
var cursorAdapter = {
|
|
20730
21034
|
name: "Cursor",
|
|
20731
21035
|
detect() {
|
|
20732
|
-
return
|
|
21036
|
+
return dirHasEditorEvidence(path13.join(homedir4(), ".cursor"), cursorDirLooksArgentOnly) || dirHasEditorEvidence(path13.join(process.cwd(), ".cursor"), cursorDirLooksArgentOnly);
|
|
20733
21037
|
},
|
|
20734
21038
|
projectPath(root) {
|
|
20735
21039
|
return path13.join(root, ".cursor", "mcp.json");
|
|
@@ -20833,7 +21137,8 @@ function claudeDisabledListFinding(settingsPath, label, projectConfined) {
|
|
|
20833
21137
|
var claudeAdapter = {
|
|
20834
21138
|
name: "Claude Code",
|
|
20835
21139
|
detect() {
|
|
20836
|
-
|
|
21140
|
+
const mcpJsonArgentOnly = (p) => jsonLooksArgentServerOnly(p, "mcpServers");
|
|
21141
|
+
return fileHasEditorEvidence(path13.join(process.cwd(), ".mcp.json"), mcpJsonArgentOnly) || fileHasEditorEvidence(path13.join(homedir4(), ".claude.json"), mcpJsonArgentOnly) || dirHasEditorEvidence(path13.join(process.cwd(), ".claude"), claudeDirLooksArgentOnly) || dirHasEditorEvidence(path13.join(homedir4(), ".claude"), claudeDirLooksArgentOnly);
|
|
20837
21142
|
},
|
|
20838
21143
|
projectPath(root) {
|
|
20839
21144
|
return path13.join(root, ".mcp.json");
|
|
@@ -20941,7 +21246,7 @@ var claudeAdapter = {
|
|
|
20941
21246
|
var vscodeAdapter = {
|
|
20942
21247
|
name: "VS Code",
|
|
20943
21248
|
detect() {
|
|
20944
|
-
return
|
|
21249
|
+
return dirHasEditorEvidence(path13.join(process.cwd(), ".vscode"), vscodeDirLooksArgentOnly) || dirExists(path13.join(homedir4(), ".vscode"));
|
|
20945
21250
|
},
|
|
20946
21251
|
projectPath(root) {
|
|
20947
21252
|
return path13.join(root, ".vscode", "mcp.json");
|
|
@@ -21024,7 +21329,10 @@ function vscodeUserDirs() {
|
|
|
21024
21329
|
var windsurfAdapter = {
|
|
21025
21330
|
name: "Windsurf",
|
|
21026
21331
|
detect() {
|
|
21027
|
-
return
|
|
21332
|
+
return dirHasEditorEvidence(
|
|
21333
|
+
path13.join(homedir4(), ".codeium", "windsurf"),
|
|
21334
|
+
windsurfDirLooksArgentOnly
|
|
21335
|
+
);
|
|
21028
21336
|
},
|
|
21029
21337
|
projectPath() {
|
|
21030
21338
|
return null;
|
|
@@ -21084,7 +21392,7 @@ var windsurfAdapter = {
|
|
|
21084
21392
|
var zedAdapter = {
|
|
21085
21393
|
name: "Zed",
|
|
21086
21394
|
detect() {
|
|
21087
|
-
return
|
|
21395
|
+
return dirHasEditorEvidence(path13.join(homedir4(), ".config", "zed"), zedDirLooksArgentOnly);
|
|
21088
21396
|
},
|
|
21089
21397
|
projectPath(root) {
|
|
21090
21398
|
return path13.join(root, ".zed", "settings.json");
|
|
@@ -21142,7 +21450,7 @@ var zedAdapter = {
|
|
|
21142
21450
|
var geminiAdapter = {
|
|
21143
21451
|
name: "Gemini",
|
|
21144
21452
|
detect() {
|
|
21145
|
-
return
|
|
21453
|
+
return dirHasEditorEvidence(path13.join(homedir4(), ".gemini"), geminiDirLooksArgentOnly) || dirHasEditorEvidence(path13.join(process.cwd(), ".gemini"), geminiDirLooksArgentOnly);
|
|
21146
21454
|
},
|
|
21147
21455
|
projectPath(root) {
|
|
21148
21456
|
return path13.join(root, ".gemini", "settings.json");
|
|
@@ -21207,7 +21515,7 @@ var CODEX_FILENAME = ".codex";
|
|
|
21207
21515
|
var codexAdapter = {
|
|
21208
21516
|
name: "Codex",
|
|
21209
21517
|
detect() {
|
|
21210
|
-
return
|
|
21518
|
+
return dirHasEditorEvidence(path13.join(homedir4(), CODEX_FILENAME), codexDirLooksArgentOnly) || dirHasEditorEvidence(path13.join(process.cwd(), CODEX_FILENAME), codexDirLooksArgentOnly);
|
|
21211
21519
|
},
|
|
21212
21520
|
projectPath(root) {
|
|
21213
21521
|
return path13.join(root, CODEX_FILENAME, "config.toml");
|
|
@@ -21285,7 +21593,7 @@ var codexAdapter = {
|
|
|
21285
21593
|
var hermesAdapter = {
|
|
21286
21594
|
name: "Hermes",
|
|
21287
21595
|
detect() {
|
|
21288
|
-
return
|
|
21596
|
+
return dirHasEditorEvidence(path13.join(homedir4(), ".hermes"), hermesDirLooksArgentOnly);
|
|
21289
21597
|
},
|
|
21290
21598
|
projectPath() {
|
|
21291
21599
|
return null;
|
|
@@ -21409,7 +21717,7 @@ var KIRO_AUTO_APPROVE_ALL = ["*"];
|
|
|
21409
21717
|
var kiroAdapter = {
|
|
21410
21718
|
name: "Kiro",
|
|
21411
21719
|
detect() {
|
|
21412
|
-
return
|
|
21720
|
+
return dirHasEditorEvidence(path13.join(homedir4(), ".kiro"), kiroDirLooksArgentOnly) || dirHasEditorEvidence(path13.join(process.cwd(), ".kiro"), kiroDirLooksArgentOnly);
|
|
21413
21721
|
},
|
|
21414
21722
|
projectPath(root) {
|
|
21415
21723
|
return path13.join(root, ".kiro", "settings", "mcp.json");
|
|
@@ -21773,16 +22081,19 @@ async function resolveTelemetryConsent(opts) {
|
|
|
21773
22081
|
}
|
|
21774
22082
|
|
|
21775
22083
|
// ../argent-installer/src/init-args.ts
|
|
21776
|
-
function extractFlag(args, flag) {
|
|
21777
|
-
const idx = args.indexOf(flag);
|
|
21778
|
-
if (idx === -1 || idx + 1 >= args.length) return null;
|
|
21779
|
-
return args[idx + 1];
|
|
21780
|
-
}
|
|
21781
22084
|
function parseInitArgs(args) {
|
|
22085
|
+
let fromTar = null;
|
|
22086
|
+
for (let i2 = 0; i2 < args.length; i2++) {
|
|
22087
|
+
const arg = args[i2];
|
|
22088
|
+
if (arg === "--from" || arg.startsWith("--from=")) {
|
|
22089
|
+
const value = arg === "--from" ? i2 + 1 < args.length ? args[++i2] : "" : arg.slice(7);
|
|
22090
|
+
if (value !== "" && fromTar === null) fromTar = value;
|
|
22091
|
+
}
|
|
22092
|
+
}
|
|
21782
22093
|
return {
|
|
21783
22094
|
nonInteractive: args.includes("--yes") || args.includes("-y"),
|
|
21784
22095
|
noTelemetry: args.includes("--no-telemetry"),
|
|
21785
|
-
fromTar
|
|
22096
|
+
fromTar,
|
|
21786
22097
|
wantsLocal: args.includes("--local"),
|
|
21787
22098
|
wantsGlobal: args.includes("--global")
|
|
21788
22099
|
};
|
|
@@ -21875,12 +22186,13 @@ var InitTelemetry = class {
|
|
|
21875
22186
|
});
|
|
21876
22187
|
});
|
|
21877
22188
|
}
|
|
21878
|
-
async trackPackageAction(action, startedAt, isSuccess, failureSignal2) {
|
|
22189
|
+
async trackPackageAction(action, startedAt, isSuccess, failureSignal2, attemptInfo) {
|
|
21879
22190
|
track("installation:package_action", {
|
|
21880
22191
|
trigger: "init",
|
|
21881
22192
|
action,
|
|
21882
22193
|
is_success: isSuccess,
|
|
21883
22194
|
duration_ms: performance.now() - startedAt,
|
|
22195
|
+
...attemptInfo ?? {},
|
|
21884
22196
|
...failureSignal2 ?? {}
|
|
21885
22197
|
});
|
|
21886
22198
|
}
|
|
@@ -21930,6 +22242,16 @@ function execShellCommandSync(cmd, opts = {}) {
|
|
|
21930
22242
|
...opts.env ? { env: opts.env } : {}
|
|
21931
22243
|
});
|
|
21932
22244
|
}
|
|
22245
|
+
var ShellCommandError = class extends Error {
|
|
22246
|
+
constructor(message, exitCode, signal) {
|
|
22247
|
+
super(message);
|
|
22248
|
+
this.exitCode = exitCode;
|
|
22249
|
+
this.signal = signal;
|
|
22250
|
+
this.name = "ShellCommandError";
|
|
22251
|
+
}
|
|
22252
|
+
exitCode;
|
|
22253
|
+
signal;
|
|
22254
|
+
};
|
|
21933
22255
|
function runShellCommand(cmd, opts = {}) {
|
|
21934
22256
|
return new Promise((resolve10, reject) => {
|
|
21935
22257
|
const child = spawn2(cmd.bin, cmd.args, {
|
|
@@ -21941,9 +22263,16 @@ function runShellCommand(cmd, opts = {}) {
|
|
|
21941
22263
|
child.stderr?.on("data", (chunk) => {
|
|
21942
22264
|
stderr += chunk.toString();
|
|
21943
22265
|
});
|
|
21944
|
-
child.on("close", (code) => {
|
|
22266
|
+
child.on("close", (code, signal) => {
|
|
21945
22267
|
if (code === 0) resolve10();
|
|
21946
|
-
else
|
|
22268
|
+
else
|
|
22269
|
+
reject(
|
|
22270
|
+
new ShellCommandError(
|
|
22271
|
+
stderr.trim() || (signal !== null ? `Command terminated by signal ${signal}` : `Command exited with code ${code}`),
|
|
22272
|
+
code,
|
|
22273
|
+
signal
|
|
22274
|
+
)
|
|
22275
|
+
);
|
|
21947
22276
|
});
|
|
21948
22277
|
child.on("error", reject);
|
|
21949
22278
|
});
|
|
@@ -22104,17 +22433,52 @@ async function installLocally(opts) {
|
|
|
22104
22433
|
materializeOnly ? `Installing project dependencies to materialize ${PACKAGE_NAME} (${pm})...` : `Adding ${PACKAGE_NAME} to devDependencies (${pm})...`
|
|
22105
22434
|
);
|
|
22106
22435
|
const startedAt = performance.now();
|
|
22107
|
-
const
|
|
22436
|
+
const attempt = () => runTrustingDisk(
|
|
22108
22437
|
() => runShellCommand(cmd, { cwd: projectRoot }),
|
|
22109
22438
|
() => isLocallyInstalled(projectRoot) || isYarnPnp(projectRoot)
|
|
22110
22439
|
);
|
|
22440
|
+
let lastAttemptStartedAt = performance.now();
|
|
22441
|
+
let retryCount = 0;
|
|
22442
|
+
let { landed, exitError: installError } = await attempt();
|
|
22443
|
+
const isMissingBinaryError = (err) => err !== null && (err.code === "ENOENT" || process.platform === "win32" && err instanceof ShellCommandError && err.exitCode === 9009);
|
|
22444
|
+
const missingBinary = !landed && isMissingBinaryError(installError);
|
|
22445
|
+
const wasInterrupted = (err) => err instanceof ShellCommandError && (err.signal !== null || err.exitCode === null);
|
|
22446
|
+
const interrupted = !landed && wasInterrupted(installError);
|
|
22447
|
+
if (!landed && installError && !missingBinary && !interrupted) {
|
|
22448
|
+
spinner2.message(`${pm} failed \u2014 retrying once...`);
|
|
22449
|
+
retryCount = 1;
|
|
22450
|
+
lastAttemptStartedAt = performance.now();
|
|
22451
|
+
({ landed, exitError: installError } = await attempt());
|
|
22452
|
+
}
|
|
22453
|
+
const attemptTelemetry = () => ({
|
|
22454
|
+
retry_count: retryCount,
|
|
22455
|
+
last_attempt_duration_ms: performance.now() - lastAttemptStartedAt
|
|
22456
|
+
});
|
|
22111
22457
|
if (!landed) {
|
|
22112
|
-
spinner2.stop(import_picocolors3.default.red("Local install failed."));
|
|
22113
|
-
|
|
22114
|
-
|
|
22458
|
+
spinner2.stop(import_picocolors3.default.red(interrupted ? "Local install interrupted." : "Local install failed."));
|
|
22459
|
+
if (missingBinary) {
|
|
22460
|
+
log.error(
|
|
22461
|
+
`This project uses ${import_picocolors3.default.cyan(pm)}, but the ${import_picocolors3.default.cyan(pm)} command was not found on PATH.`
|
|
22462
|
+
);
|
|
22463
|
+
log.info(
|
|
22464
|
+
`Install ${import_picocolors3.default.cyan(pm)} first` + (pm === "pnpm" || pm === "yarn" ? ` (e.g. ${import_picocolors3.default.cyan(`corepack enable ${pm}`)}, or see the ${pm} install docs)` : "") + `, then re-run ${import_picocolors3.default.cyan("argent init --local")}.`
|
|
22465
|
+
);
|
|
22466
|
+
} else if (interrupted) {
|
|
22467
|
+
log.error(`The ${import_picocolors3.default.cyan(pm)} install was interrupted before it finished.`);
|
|
22468
|
+
log.info(`Re-run ${import_picocolors3.default.cyan("argent init --local")} to try again.`);
|
|
22469
|
+
} else {
|
|
22470
|
+
log.error(
|
|
22471
|
+
installError ? `${installError}` : `The install reported success but ${import_picocolors3.default.cyan(PACKAGE_NAME)} is not in node_modules.`
|
|
22472
|
+
);
|
|
22473
|
+
log.info(`Install manually with: ${import_picocolors3.default.cyan(`cd ${projectRoot} && ${cmdStr}`)}`);
|
|
22474
|
+
}
|
|
22475
|
+
await tel.trackPackageAction(
|
|
22476
|
+
"fresh_install",
|
|
22477
|
+
startedAt,
|
|
22478
|
+
false,
|
|
22479
|
+
INSTALL_LOCAL_PACKAGE_FAILED,
|
|
22480
|
+
attemptTelemetry()
|
|
22115
22481
|
);
|
|
22116
|
-
log.info(`Install manually with: ${import_picocolors3.default.cyan(`cd ${projectRoot} && ${cmdStr}`)}`);
|
|
22117
|
-
await tel.trackPackageAction("fresh_install", startedAt, false, INSTALL_LOCAL_PACKAGE_FAILED);
|
|
22118
22482
|
await tel.finalize(INSTALL_LOCAL_PACKAGE_FAILED);
|
|
22119
22483
|
process.exit(1);
|
|
22120
22484
|
}
|
|
@@ -22133,7 +22497,7 @@ async function installLocally(opts) {
|
|
|
22133
22497
|
);
|
|
22134
22498
|
}
|
|
22135
22499
|
}
|
|
22136
|
-
await tel.trackPackageAction("fresh_install", startedAt, true);
|
|
22500
|
+
await tel.trackPackageAction("fresh_install", startedAt, true, void 0, attemptTelemetry());
|
|
22137
22501
|
}
|
|
22138
22502
|
async function runGlobal(opts) {
|
|
22139
22503
|
const { fromTar, nonInteractive, tel } = opts;
|
|
@@ -22279,6 +22643,12 @@ async function runGlobal(opts) {
|
|
|
22279
22643
|
|
|
22280
22644
|
// ../argent-installer/src/init-adapters.ts
|
|
22281
22645
|
var import_picocolors4 = __toESM(require_picocolors(), 1);
|
|
22646
|
+
function previouslyConfiguredAdapters(eligible, installMode) {
|
|
22647
|
+
const wantedScope = installMode === "local" ? "project" : "global";
|
|
22648
|
+
const scopes = findConfiguredAdapterScopes(eligible, process.cwd());
|
|
22649
|
+
const configured = new Set(scopes.filter((s) => s.scope === wantedScope).map((s) => s.adapter));
|
|
22650
|
+
return eligible.filter((a3) => configured.has(a3));
|
|
22651
|
+
}
|
|
22282
22652
|
async function chooseAdapters(opts) {
|
|
22283
22653
|
let eligible = ALL_ADAPTERS;
|
|
22284
22654
|
if (opts.installMode === "local") {
|
|
@@ -22294,12 +22664,16 @@ async function chooseAdapters(opts) {
|
|
|
22294
22664
|
}
|
|
22295
22665
|
const detected = detectAdapters().filter((a3) => eligible.includes(a3));
|
|
22296
22666
|
const detectedNames = detected.map((a3) => a3.name);
|
|
22667
|
+
const previouslyConfigured = previouslyConfiguredAdapters(eligible, opts.installMode);
|
|
22668
|
+
const previouslyConfiguredNames = previouslyConfigured.map((a3) => a3.name);
|
|
22669
|
+
const preselected = [...detected, ...previouslyConfigured.filter((a3) => !detected.includes(a3))];
|
|
22297
22670
|
if (opts.nonInteractive) {
|
|
22298
|
-
return { selected:
|
|
22671
|
+
return { selected: preselected.length > 0 ? preselected : eligible, detected };
|
|
22299
22672
|
}
|
|
22300
22673
|
const choices = eligible.map((a3) => {
|
|
22301
22674
|
const parts = [];
|
|
22302
22675
|
if (detectedNames.includes(a3.name)) parts.push("detected");
|
|
22676
|
+
else if (previouslyConfiguredNames.includes(a3.name)) parts.push("already configured");
|
|
22303
22677
|
const hasProject = a3.projectPath(process.cwd()) != null;
|
|
22304
22678
|
const hasGlobal = a3.globalPath() != null;
|
|
22305
22679
|
if (!hasProject && hasGlobal) {
|
|
@@ -22317,7 +22691,7 @@ async function chooseAdapters(opts) {
|
|
|
22317
22691
|
const selected = await multiselect({
|
|
22318
22692
|
message: "Which editors should Argent be configured for?",
|
|
22319
22693
|
options: choices,
|
|
22320
|
-
initialValues:
|
|
22694
|
+
initialValues: preselected,
|
|
22321
22695
|
required: true
|
|
22322
22696
|
});
|
|
22323
22697
|
if (isCancel(selected)) throw new InitCancelled("editors");
|
|
@@ -22876,7 +23250,11 @@ async function init2(args) {
|
|
|
22876
23250
|
note(mcpLines.join("\n"), "MCP Configuration");
|
|
22877
23251
|
const staleCleanup = await cleanupStaleMcpConfigs({
|
|
22878
23252
|
writtenAdapters,
|
|
22879
|
-
|
|
23253
|
+
// Sweep EVERY adapter, not just the detected set: the sweep is fully
|
|
23254
|
+
// gated on an existing argent entry (getArgentEntry), and the stale
|
|
23255
|
+
// entries most worth pruning live in argent-only dirs (~/.cursor,
|
|
23256
|
+
// ~/.codex) that detection now deliberately ignores.
|
|
23257
|
+
detectedAdapters: ALL_ADAPTERS,
|
|
22880
23258
|
installMode: tel.installMode,
|
|
22881
23259
|
scope: normalizedScope,
|
|
22882
23260
|
effectiveRoot,
|
package/dist/mcp-server.mjs
CHANGED
|
@@ -17660,10 +17660,10 @@ var FAILURE_CODES = {
|
|
|
17660
17660
|
ANDROID_UIAUTOMATOR_PARSE_FAILED: "ANDROID_UIAUTOMATOR_PARSE_FAILED",
|
|
17661
17661
|
ANDROID_UIAUTOMATOR_CAPTURE_FAILED: "ANDROID_UIAUTOMATOR_CAPTURE_FAILED",
|
|
17662
17662
|
DEBUGGER_METRO_NOT_RUNNING: "DEBUGGER_METRO_NOT_RUNNING",
|
|
17663
|
-
DEBUGGER_METRO_PROJECT_ROOT_MISSING: "DEBUGGER_METRO_PROJECT_ROOT_MISSING",
|
|
17664
17663
|
DEBUGGER_METRO_NO_TARGETS: "DEBUGGER_METRO_NO_TARGETS",
|
|
17665
17664
|
DEBUGGER_CDP_RUNTIME_EXCEPTION: "DEBUGGER_CDP_RUNTIME_EXCEPTION",
|
|
17666
17665
|
DEBUGGER_CDP_BINDING_TIMEOUT: "DEBUGGER_CDP_BINDING_TIMEOUT",
|
|
17666
|
+
DEBUGGER_CDP_BINDING_UNAVAILABLE: "DEBUGGER_CDP_BINDING_UNAVAILABLE",
|
|
17667
17667
|
DEBUGGER_CDP_PROTOCOL_ERROR: "DEBUGGER_CDP_PROTOCOL_ERROR",
|
|
17668
17668
|
DEBUGGER_RELOAD_FAILED: "DEBUGGER_RELOAD_FAILED",
|
|
17669
17669
|
JS_RUNTIME_CONSOLE_SERVER_BIND_FAILED: "JS_RUNTIME_CONSOLE_SERVER_BIND_FAILED",
|
|
@@ -18004,6 +18004,8 @@ var ALLOWED = {
|
|
|
18004
18004
|
action: PACKAGE_ACTION,
|
|
18005
18005
|
is_success: bool,
|
|
18006
18006
|
duration_ms: DURATION_MS,
|
|
18007
|
+
retry_count: COUNT,
|
|
18008
|
+
last_attempt_duration_ms: DURATION_MS,
|
|
18007
18009
|
...FAILURE_SIGNAL
|
|
18008
18010
|
},
|
|
18009
18011
|
"installation:cli_update_start": {},
|
package/dist/tool-server.cjs
CHANGED
|
@@ -314,10 +314,10 @@ var init_failure_codes = __esm({
|
|
|
314
314
|
ANDROID_UIAUTOMATOR_PARSE_FAILED: "ANDROID_UIAUTOMATOR_PARSE_FAILED",
|
|
315
315
|
ANDROID_UIAUTOMATOR_CAPTURE_FAILED: "ANDROID_UIAUTOMATOR_CAPTURE_FAILED",
|
|
316
316
|
DEBUGGER_METRO_NOT_RUNNING: "DEBUGGER_METRO_NOT_RUNNING",
|
|
317
|
-
DEBUGGER_METRO_PROJECT_ROOT_MISSING: "DEBUGGER_METRO_PROJECT_ROOT_MISSING",
|
|
318
317
|
DEBUGGER_METRO_NO_TARGETS: "DEBUGGER_METRO_NO_TARGETS",
|
|
319
318
|
DEBUGGER_CDP_RUNTIME_EXCEPTION: "DEBUGGER_CDP_RUNTIME_EXCEPTION",
|
|
320
319
|
DEBUGGER_CDP_BINDING_TIMEOUT: "DEBUGGER_CDP_BINDING_TIMEOUT",
|
|
320
|
+
DEBUGGER_CDP_BINDING_UNAVAILABLE: "DEBUGGER_CDP_BINDING_UNAVAILABLE",
|
|
321
321
|
DEBUGGER_CDP_PROTOCOL_ERROR: "DEBUGGER_CDP_PROTOCOL_ERROR",
|
|
322
322
|
DEBUGGER_RELOAD_FAILED: "DEBUGGER_RELOAD_FAILED",
|
|
323
323
|
JS_RUNTIME_CONSOLE_SERVER_BIND_FAILED: "JS_RUNTIME_CONSOLE_SERVER_BIND_FAILED",
|
|
@@ -103836,6 +103836,8 @@ var ALLOWED = {
|
|
|
103836
103836
|
action: PACKAGE_ACTION,
|
|
103837
103837
|
is_success: bool,
|
|
103838
103838
|
duration_ms: DURATION_MS,
|
|
103839
|
+
retry_count: COUNT,
|
|
103840
|
+
last_attempt_duration_ms: DURATION_MS,
|
|
103839
103841
|
...FAILURE_SIGNAL2
|
|
103840
103842
|
},
|
|
103841
103843
|
"installation:cli_update_start": {},
|
|
@@ -114407,6 +114409,8 @@ var CDPClient = class {
|
|
|
114407
114409
|
nextId = 1;
|
|
114408
114410
|
pending = /* @__PURE__ */ new Map();
|
|
114409
114411
|
pendingBindings = /* @__PURE__ */ new Map();
|
|
114412
|
+
/** Set by addBinding when the runtime ACKs the command but installs nothing. */
|
|
114413
|
+
bindingUnavailable = false;
|
|
114410
114414
|
scripts = /* @__PURE__ */ new Map();
|
|
114411
114415
|
enabledDomains = /* @__PURE__ */ new Set();
|
|
114412
114416
|
wsUrl;
|
|
@@ -114539,6 +114543,8 @@ var CDPClient = class {
|
|
|
114539
114543
|
}
|
|
114540
114544
|
async addBinding(name) {
|
|
114541
114545
|
await this.send("Runtime.addBinding", { name });
|
|
114546
|
+
const probe3 = await this.evaluate(`typeof ${name}`).catch(() => void 0);
|
|
114547
|
+
this.bindingUnavailable = probe3 === "undefined";
|
|
114542
114548
|
}
|
|
114543
114549
|
/**
|
|
114544
114550
|
* Inject a script that will push a result via the binding using a unique requestId.
|
|
@@ -114547,6 +114553,19 @@ var CDPClient = class {
|
|
|
114547
114553
|
evaluateWithBinding(expression, requestId, options) {
|
|
114548
114554
|
const id = requestId ?? crypto3.randomUUID();
|
|
114549
114555
|
const timeout = options?.timeout ?? DEFAULT_TIMEOUT_MS2;
|
|
114556
|
+
if (this.bindingUnavailable) {
|
|
114557
|
+
return Promise.reject(
|
|
114558
|
+
new FailureError(
|
|
114559
|
+
"This JS runtime acknowledges Runtime.addBinding but never installs the binding (legacy Hermes, React Native <= 0.72), so it cannot deliver a result over the binding channel. Tools that read the React tree this way are unavailable here; use `describe` to read on-screen structure.",
|
|
114560
|
+
{
|
|
114561
|
+
error_code: FAILURE_CODES.DEBUGGER_CDP_BINDING_UNAVAILABLE,
|
|
114562
|
+
failure_stage: "debugger_cdp_binding",
|
|
114563
|
+
failure_area: "tool_server",
|
|
114564
|
+
error_kind: "unsupported"
|
|
114565
|
+
}
|
|
114566
|
+
)
|
|
114567
|
+
);
|
|
114568
|
+
}
|
|
114550
114569
|
return new Promise((resolve7, reject) => {
|
|
114551
114570
|
const timer = setTimeout(() => {
|
|
114552
114571
|
this.pendingBindings.delete(id);
|
|
@@ -121983,12 +122002,14 @@ init_src();
|
|
|
121983
122002
|
|
|
121984
122003
|
// ../tool-server/src/utils/debugger/discovery.ts
|
|
121985
122004
|
init_src();
|
|
122005
|
+
var DECOY_VM = "don't use";
|
|
121986
122006
|
async function discoverMetro(port) {
|
|
121987
|
-
|
|
121988
|
-
|
|
121989
|
-
|
|
122007
|
+
let statusRes;
|
|
122008
|
+
try {
|
|
122009
|
+
statusRes = await fetch(`http://localhost:${port}/status`);
|
|
122010
|
+
} catch (err) {
|
|
121990
122011
|
throw new FailureError(
|
|
121991
|
-
`Metro at port ${port} is not running (got: ${
|
|
122012
|
+
`Metro at port ${port} is not running (got: ${err instanceof Error ? err.message : String(err)})`,
|
|
121992
122013
|
{
|
|
121993
122014
|
error_code: FAILURE_CODES.DEBUGGER_METRO_NOT_RUNNING,
|
|
121994
122015
|
failure_stage: "debugger_discover_metro_status",
|
|
@@ -121997,21 +122018,25 @@ async function discoverMetro(port) {
|
|
|
121997
122018
|
}
|
|
121998
122019
|
);
|
|
121999
122020
|
}
|
|
122000
|
-
const
|
|
122001
|
-
if (!
|
|
122021
|
+
const statusText = await statusRes.text();
|
|
122022
|
+
if (!statusText.includes("packager-status:running")) {
|
|
122002
122023
|
throw new FailureError(
|
|
122003
|
-
`Metro at port ${port}
|
|
122024
|
+
`Metro at port ${port} is not running (got: ${statusText.slice(0, 100)})`,
|
|
122004
122025
|
{
|
|
122005
|
-
error_code: FAILURE_CODES.
|
|
122006
|
-
failure_stage: "
|
|
122026
|
+
error_code: FAILURE_CODES.DEBUGGER_METRO_NOT_RUNNING,
|
|
122027
|
+
failure_stage: "debugger_discover_metro_status",
|
|
122007
122028
|
failure_area: "tool_server",
|
|
122008
122029
|
error_kind: "network"
|
|
122009
122030
|
}
|
|
122010
122031
|
);
|
|
122011
122032
|
}
|
|
122033
|
+
const projectRoot = statusRes.headers.get("X-React-Native-Project-Root") ?? "";
|
|
122012
122034
|
const listRes = await fetch(`http://localhost:${port}/json/list`);
|
|
122013
|
-
const
|
|
122014
|
-
|
|
122035
|
+
const parsed = await listRes.json().catch(() => null);
|
|
122036
|
+
const targets = (Array.isArray(parsed) ? parsed : []).filter(
|
|
122037
|
+
(t) => t?.vm !== DECOY_VM
|
|
122038
|
+
);
|
|
122039
|
+
if (!targets.length) {
|
|
122015
122040
|
throw new FailureError(
|
|
122016
122041
|
`Metro at port ${port} has no CDP targets \u2014 is a React Native app connected?`,
|
|
122017
122042
|
{
|
|
@@ -122026,8 +122051,19 @@ async function discoverMetro(port) {
|
|
|
122026
122051
|
}
|
|
122027
122052
|
|
|
122028
122053
|
// ../tool-server/src/utils/debugger/target-selection.ts
|
|
122054
|
+
function deviceKey(target) {
|
|
122055
|
+
const logicalId = target.reactNative?.logicalDeviceId;
|
|
122056
|
+
if (logicalId) return logicalId;
|
|
122057
|
+
try {
|
|
122058
|
+
const device = new URL(target.webSocketDebuggerUrl).searchParams.get("device");
|
|
122059
|
+
if (device) return `device=${device}`;
|
|
122060
|
+
} catch {
|
|
122061
|
+
}
|
|
122062
|
+
return target.deviceName;
|
|
122063
|
+
}
|
|
122029
122064
|
function selectTarget(targets, port, options) {
|
|
122030
|
-
|
|
122065
|
+
const pool = targets;
|
|
122066
|
+
let candidates = pool;
|
|
122031
122067
|
if (typeof options?.deviceId === "string" && options.deviceId) {
|
|
122032
122068
|
const deviceId = options.deviceId;
|
|
122033
122069
|
const filtered = candidates.filter((t) => t.reactNative?.logicalDeviceId === deviceId);
|
|
@@ -122035,16 +122071,21 @@ function selectTarget(targets, port, options) {
|
|
|
122035
122071
|
candidates = filtered;
|
|
122036
122072
|
} else {
|
|
122037
122073
|
const distinctDevices = /* @__PURE__ */ new Map();
|
|
122038
|
-
for (const t of
|
|
122039
|
-
const
|
|
122040
|
-
if (
|
|
122041
|
-
distinctDevices.set(
|
|
122074
|
+
for (const t of pool) {
|
|
122075
|
+
const key = deviceKey(t);
|
|
122076
|
+
if (key && !distinctDevices.has(key)) {
|
|
122077
|
+
distinctDevices.set(key, {
|
|
122078
|
+
name: t.deviceName,
|
|
122079
|
+
logicalId: t.reactNative?.logicalDeviceId
|
|
122080
|
+
});
|
|
122042
122081
|
}
|
|
122043
122082
|
}
|
|
122044
122083
|
if (distinctDevices.size > 1) {
|
|
122045
|
-
const listed = [...distinctDevices.
|
|
122084
|
+
const listed = [...distinctDevices.values()].map(
|
|
122085
|
+
(d) => d.logicalId ? `${d.name ?? "unknown"} (${d.logicalId})` : `${d.name ?? "unknown"} (legacy inspector \u2014 no logicalDeviceId)`
|
|
122086
|
+
).join(", ");
|
|
122046
122087
|
throw new Error(
|
|
122047
|
-
`No debugger target matches device_id "${deviceId}". ${distinctDevices.size} devices are connected to Metro on port ${port}: ${listed}.
|
|
122088
|
+
`No debugger target matches device_id "${deviceId}". ${distinctDevices.size} devices are connected to Metro on port ${port}: ${listed}. Re-target with the logicalDeviceId in parentheses \u2014 that is what debugger-connect returns and what subsequent debugger-* calls must pass. A legacy-inspector device (RN 0.72 / Vega) reports none and cannot be singled out of a shared Metro: give it its own Metro port.`
|
|
122048
122089
|
);
|
|
122049
122090
|
}
|
|
122050
122091
|
}
|
|
@@ -122185,6 +122226,7 @@ function parseNode(line) {
|
|
|
122185
122226
|
// ../tool-server/src/utils/debugger/source-resolver.ts
|
|
122186
122227
|
var ALLOWED_SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([".js", ".jsx", ".ts", ".tsx", ".mjs", ".cjs"]);
|
|
122187
122228
|
function isInsideProject(absFile, projectRoot) {
|
|
122229
|
+
if (!projectRoot) return false;
|
|
122188
122230
|
const resolvedRoot = path17.resolve(projectRoot);
|
|
122189
122231
|
const resolvedFile = path17.resolve(absFile);
|
|
122190
122232
|
const rel = path17.relative(resolvedRoot, resolvedFile);
|
|
@@ -122227,7 +122269,7 @@ function createSourceResolver(port, projectRoot) {
|
|
|
122227
122269
|
const frame = data.stack?.[0];
|
|
122228
122270
|
if (!frame?.file) return null;
|
|
122229
122271
|
if (/^https?:\/\//.test(frame.file)) return null;
|
|
122230
|
-
const relFile = frame.file.replace(projectRoot + "/", "").replace(/^\/+/, "");
|
|
122272
|
+
const relFile = projectRoot ? frame.file.replace(projectRoot + "/", "").replace(/^\/+/, "") : frame.file;
|
|
122231
122273
|
return {
|
|
122232
122274
|
file: relFile,
|
|
122233
122275
|
line: frame.lineNumber ?? 0,
|
|
@@ -122246,6 +122288,7 @@ function createSourceResolver(port, projectRoot) {
|
|
|
122246
122288
|
},
|
|
122247
122289
|
symbolicate: symbolicateFrame,
|
|
122248
122290
|
async readSourceFragment(location, contextLines = 3) {
|
|
122291
|
+
if (!projectRoot) return null;
|
|
122249
122292
|
try {
|
|
122250
122293
|
const absPath = path17.isAbsolute(location.file) ? path17.resolve(location.file) : path17.resolve(projectRoot, location.file);
|
|
122251
122294
|
const realRoot = await fs18.realpath(projectRoot);
|
|
@@ -133797,7 +133840,8 @@ var DEBUGGER_TOOL_CAPABILITY = {
|
|
|
133797
133840
|
apple: { simulator: true, device: true },
|
|
133798
133841
|
appleRemote: { simulator: true },
|
|
133799
133842
|
android: { emulator: true, device: true, unknown: true },
|
|
133800
|
-
chromium: { app: true }
|
|
133843
|
+
chromium: { app: true },
|
|
133844
|
+
vega: { vvd: true }
|
|
133801
133845
|
};
|
|
133802
133846
|
var RN_ONLY_TOOL_CAPABILITY = {
|
|
133803
133847
|
apple: { simulator: true, device: true },
|
|
@@ -133816,14 +133860,14 @@ function debuggerServiceRef(params) {
|
|
|
133816
133860
|
var zodSchema29 = external_exports.object({
|
|
133817
133861
|
port: external_exports.coerce.number().default(8081).describe("Metro server port (ignored for Chromium \u2014 its CDP port is encoded in device_id)"),
|
|
133818
133862
|
device_id: external_exports.string().describe(
|
|
133819
|
-
"Device id: iOS simulator UDID, Android logicalDeviceId returned by Metro, or Chromium device id (chromium-cdp-<port>) from list-devices.
|
|
133863
|
+
"Device id: iOS simulator UDID, Android logicalDeviceId returned by Metro, Vega serial (amazon-...), or Chromium device id (chromium-cdp-<port>) from list-devices. When a logicalDeviceId is returned, forward it as device_id to all subsequent debugger-* calls to pin them to this device; when none is returned (Vega), keep passing the id you connected with."
|
|
133820
133864
|
)
|
|
133821
133865
|
});
|
|
133822
133866
|
var debuggerConnectTool = {
|
|
133823
133867
|
id: "debugger-connect",
|
|
133824
133868
|
description: `Connect to a JS runtime CDP debugger.
|
|
133825
|
-
iOS / Android: connects to Metro's CDP endpoint on the given port. Chromium: re-uses the page CDP session opened by boot-device \u2014 port is ignored.
|
|
133826
|
-
Returns connection info including port, projectRoot (empty on Chromium), deviceName, appName, logicalDeviceId, and isNewDebugger. If already connected, returns the existing connection.
|
|
133869
|
+
iOS / Android / Vega: connects to Metro's CDP endpoint on the given port. Chromium: re-uses the page CDP session opened by boot-device \u2014 port is ignored.
|
|
133870
|
+
Returns connection info including port, projectRoot (empty on Chromium and on legacy Metro, e.g. Vega), deviceName, appName, logicalDeviceId (absent on Vega), and isNewDebugger. If already connected, returns the existing connection.
|
|
133827
133871
|
Use when starting a debug session or before calling other debugger-* tools. Fails if the runtime is unreachable (Metro down, or Chromium CDP terminated).`,
|
|
133828
133872
|
zodSchema: zodSchema29,
|
|
133829
133873
|
capability: DEBUGGER_TOOL_CAPABILITY,
|
|
@@ -133849,13 +133893,13 @@ init_zod();
|
|
|
133849
133893
|
var zodSchema30 = external_exports.object({
|
|
133850
133894
|
port: external_exports.coerce.number().default(8081).describe("Metro server port (ignored for Chromium)"),
|
|
133851
133895
|
device_id: external_exports.string().describe(
|
|
133852
|
-
"Device id from debugger-connect (iOS simulator UDID, Android logicalDeviceId, or Chromium device id)."
|
|
133896
|
+
"Device id from debugger-connect (iOS simulator UDID, Android logicalDeviceId, Vega serial, or Chromium device id)."
|
|
133853
133897
|
)
|
|
133854
133898
|
});
|
|
133855
133899
|
var debuggerStatusTool = {
|
|
133856
133900
|
id: "debugger-status",
|
|
133857
133901
|
description: `Get JS runtime debugger connection status and diagnostic info.
|
|
133858
|
-
Use when you need to verify connectivity before using other debugger tools. Returns port, projectRoot (empty on Chromium), deviceName, appName, logicalDeviceId, connected flag, loadedScripts count, and sourceMapReady (always true \u2014 waits for pending source maps before returning; no-op on Chromium). Fails if the runtime is unreachable.`,
|
|
133902
|
+
Use when you need to verify connectivity before using other debugger tools. Returns port, projectRoot (empty on Chromium and on legacy Metro, e.g. Vega), deviceName, appName, logicalDeviceId (absent on Vega), isNewDebugger (false on the legacy inspector), connected flag, loadedScripts count, and sourceMapReady (always true \u2014 waits for pending source maps before returning; no-op on Chromium). Fails if the runtime is unreachable.`,
|
|
133859
133903
|
zodSchema: zodSchema30,
|
|
133860
133904
|
capability: DEBUGGER_TOOL_CAPABILITY,
|
|
133861
133905
|
services: (params) => ({
|
|
@@ -133884,13 +133928,13 @@ init_zod();
|
|
|
133884
133928
|
var zodSchema31 = external_exports.object({
|
|
133885
133929
|
port: external_exports.coerce.number().default(8081).describe("Metro server port (ignored for Chromium)"),
|
|
133886
133930
|
device_id: external_exports.string().describe(
|
|
133887
|
-
"Device id from debugger-connect (iOS simulator UDID, Android logicalDeviceId, or Chromium device id)."
|
|
133931
|
+
"Device id from debugger-connect (iOS simulator UDID, Android logicalDeviceId, Vega serial, or Chromium device id)."
|
|
133888
133932
|
),
|
|
133889
133933
|
expression: external_exports.string().describe("JavaScript expression to evaluate in the app runtime")
|
|
133890
133934
|
});
|
|
133891
133935
|
var debuggerEvaluateTool = {
|
|
133892
133936
|
id: "debugger-evaluate",
|
|
133893
|
-
description: `Execute arbitrary JavaScript in the app's JS runtime via CDP \u2014 Hermes on iOS / Android, V8 on Chromium.
|
|
133937
|
+
description: `Execute arbitrary JavaScript in the app's JS runtime via CDP \u2014 Hermes on iOS / Android / Vega, V8 on Chromium.
|
|
133894
133938
|
Returns the evaluation result as a JSON-serializable value, along with deviceName, appName, and logicalDeviceId for context. Use when you need to read app state, call app functions, or test logic at runtime. The result is serialized by value, so cyclic objects (many RN runtime values \u2014 fiber nodes, navigation refs, global \u2014 are cyclic) fail with a serialization error rather than returning silently. Fails if the expression throws or the runtime is not connected.`,
|
|
133895
133939
|
zodSchema: zodSchema31,
|
|
133896
133940
|
capability: DEBUGGER_TOOL_CAPABILITY,
|
|
@@ -135374,13 +135418,13 @@ init_zod();
|
|
|
135374
135418
|
var zodSchema35 = external_exports.object({
|
|
135375
135419
|
port: external_exports.coerce.number().default(8081).describe("Metro server port (ignored for Chromium)"),
|
|
135376
135420
|
device_id: external_exports.string().describe(
|
|
135377
|
-
"Device id from debugger-connect (iOS simulator UDID, Android logicalDeviceId, or Chromium device id)."
|
|
135421
|
+
"Device id from debugger-connect (iOS simulator UDID, Android logicalDeviceId, Vega serial, or Chromium device id)."
|
|
135378
135422
|
)
|
|
135379
135423
|
});
|
|
135380
135424
|
var debuggerLogRegistryTool = {
|
|
135381
135425
|
id: "debugger-log-registry",
|
|
135382
135426
|
description: `Get a summary of all console logs captured from the app's JS runtime.
|
|
135383
|
-
Returns the log file path, entry counts by level, and message clusters (grouped by similarity). Works against Hermes (iOS / Android) and V8 (Chromium).
|
|
135427
|
+
Returns the log file path, entry counts by level, and message clusters (grouped by similarity). Works against Hermes (iOS / Android / Vega) and V8 (Chromium).
|
|
135384
135428
|
Use when investigating warnings, errors, or unexpected output \u2014 call this first for an overview, then read the returned file for details. Returns empty stats if no log data has been captured yet.`,
|
|
135385
135429
|
zodSchema: zodSchema35,
|
|
135386
135430
|
capability: DEBUGGER_TOOL_CAPABILITY,
|
|
@@ -135472,7 +135516,7 @@ var networkLogsTool = {
|
|
|
135472
135516
|
description: `Retrieve captured network (HTTP) requests from the running app.
|
|
135473
135517
|
Returns a paginated list of requests with method, URL, status, resource type, size, and duration.
|
|
135474
135518
|
Each entry includes a requestId that can be passed to view-network-request-details for full details.
|
|
135475
|
-
On React Native (iOS/Android) interception is injected into the JS runtime \u2014 it captures fetch() calls. On Chromium it reads the browser's native CDP Network domain (the active tab; all request types).
|
|
135519
|
+
On React Native (iOS / Android / Vega) interception is injected into the JS runtime \u2014 it captures fetch() calls. On Chromium it reads the browser's native CDP Network domain (the active tab; all request types).
|
|
135476
135520
|
Use when inspecting outbound HTTP traffic or debugging API calls in the running app.
|
|
135477
135521
|
Fails if the app is not connected (RN) or the device is not reachable (Chromium).`,
|
|
135478
135522
|
zodSchema: zodSchema36,
|
package/package.json
CHANGED
package/rules/argent.md
CHANGED
|
@@ -32,7 +32,7 @@ If argent IS available, ignore the rest of this block and follow this rule norma
|
|
|
32
32
|
|
|
33
33
|
If argent is ABSENT, treat it as an expected state, not an error to retry. Do not call `mcp__argent__*` tools, do not run `argent` commands, and do not attempt any argent workflow. Tell the user once, and ask if you should continue without argent:
|
|
34
34
|
|
|
35
|
-
> Argent isn't installed in this environment. To enable the mobile/Chromium tooling this repo is configured for, run `npx @swmansion/argent init -y` (or `npm i -g @swmansion/argent && argent init -y`).
|
|
35
|
+
> Argent isn't installed in this environment. To enable the mobile/Chromium tooling this repo is configured for, run `npx @swmansion/argent@latest init -y` (or `npm i -g @swmansion/argent@latest && argent init -y`).
|
|
36
36
|
> </availability_check>
|
|
37
37
|
|
|
38
38
|
<tapping_rule>
|
|
@@ -119,7 +119,7 @@ Prompt keywords: permission, grant, deny, revoke, reset permission, privacy, cam
|
|
|
119
119
|
|
|
120
120
|
TV INTERACTION (APPLE TV / ANDROID TV / FIRE TV)
|
|
121
121
|
Skill: `argent-tv-interact`
|
|
122
|
-
When: Any TV target — a `list-devices` entry with `runtimeKind: "tv"` (Apple TV simulator or Android TV emulator) or `platform:"vega"` / `kind:"vvd"` (Amazon Fire TV / VVD), or the user mentions Apple TV / tvOS / Android TV / leanback / Vega / Fire TV. A TV UI is focus-driven, not touch-driven: drive it with `describe` (read focus) + `tv-remote` (D-pad presses) + `keyboard` (type); `gesture-*` tools do NOT apply. Covers booting the target, app lifecycle, focus navigation, typing, screenshots, and (Vega) VVD lifecycle + Fast Refresh.
|
|
122
|
+
When: Any TV target — a `list-devices` entry with `runtimeKind: "tv"` (Apple TV simulator or Android TV emulator) or `platform:"vega"` / `kind:"vvd"` (Amazon Fire TV / VVD), or the user mentions Apple TV / tvOS / Android TV / leanback / Vega / Fire TV. A TV UI is focus-driven, not touch-driven: drive it with `describe` (read focus) + `tv-remote` (D-pad presses) + `keyboard` (type); `gesture-*` tools do NOT apply. Covers booting the target, app lifecycle, focus navigation, typing, screenshots, and (Vega) VVD lifecycle + Fast Refresh + JS-runtime debugging (evaluate, console logs, network inspector).
|
|
123
123
|
Prompt keywords: apple tv, tvos, android tv, leanback, vega, fire tv, vvd, d-pad
|
|
124
124
|
|
|
125
125
|
SCREENSHOT DIFF & VISUAL REGRESSION
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: argent-metro-debugger
|
|
3
|
-
description: Debug a JS runtime via CDP using argent debugger tools. Primary path is React Native via Metro (iOS / Android); a subset of the tools (debugger-connect, debugger-status, debugger-evaluate, debugger-log-registry) also drive a Chromium (CDP) app's renderer (an Electron app, or any Chromium browser exposing CDP) through the same surface. Use when connecting to the runtime, inspecting React components, reading console logs, or evaluating JavaScript.
|
|
3
|
+
description: Debug a JS runtime via CDP using argent debugger tools. Primary path is React Native via Metro (iOS / Android / Vega); a subset of the tools (debugger-connect, debugger-status, debugger-evaluate, debugger-log-registry) also drive a Chromium (CDP) app's renderer (an Electron app, or any Chromium browser exposing CDP) through the same surface. Use when connecting to the runtime, inspecting React components, reading console logs, or evaluating JavaScript.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
## 1. Prerequisites
|
|
7
7
|
|
|
8
8
|
For **React Native (iOS / Android)**: requires **Metro dev server running** (default `localhost:8081`) and **a React Native app connected to Metro** (at least one CDP target). Verify via `debugger-status`.
|
|
9
9
|
|
|
10
|
+
For **Vega (Fire TV)**: requires a **Debug `.vpkg`** (a Release build never attaches) and **Metro reachable from the device** (`vega device start-port-forwarding --port 8081 --forward false`). Verify via `debugger-status`. `debugger-component-tree`, `debugger-inspect-element`, `debugger-reload-metro` and the `react-profiler-*` / `profiler-*` tools are unavailable there — see the `argent-tv-interact` skill.
|
|
11
|
+
|
|
10
12
|
For **Chromium (CDP)**: requires a Chromium/CDP app already available — an Electron app booted via `boot-device` with `electronAppPath`, or any Chromium browser exposing a CDP port (auto-discovered by `list-devices` on `9222` / `ARGENT_CHROMIUM_PORTS`). The debugger re-uses the page CDP session — `port` is ignored, `device_id` is the `chromium-cdp-<port>` value from `list-devices` / `boot-device`. Only `debugger-connect`, `debugger-status`, `debugger-evaluate`, `debugger-log-registry`, `view-network-logs`, and `view-network-request-details` work on Chromium (the latter two read the browser's native CDP Network recording for the active tab instead of the Metro-injected `fetch` interceptor); `debugger-component-tree`, `debugger-reload-metro`, `debugger-inspect-element`, and the `react-profiler-*` / `profiler-*` tools are RN-only and reject Chromium at the capability gate with `Tool 'X' is not supported on chromium app`.
|
|
11
13
|
|
|
12
14
|
### Android: reverse port for Metro
|
|
@@ -21,16 +23,16 @@ adb -s <serial> reverse tcp:8081 tcp:8081
|
|
|
21
23
|
|
|
22
24
|
## 2. Tool Overview
|
|
23
25
|
|
|
24
|
-
All tools accept `port` (default 8081) AND `device_id` (the iOS Simulator UDID
|
|
26
|
+
All tools accept `port` (default 8081) AND `device_id` (the iOS Simulator UDID, Android serial, or Vega serial — a.k.a. `logicalDeviceId`, the CDP-reported id that matches the device). Vega's legacy inspector reports no `logicalDeviceId`, so there keep passing the serial. Always make sure you target the correct app on the correct device.
|
|
25
27
|
|
|
26
28
|
One Metro port can serve multiple connected devices (e.g. two simulators on `localhost:8081`, or an iOS simulator alongside an Android emulator with `adb reverse` set up). `device_id` pins every debugger/network/profiler call to a specific device so sessions do not collide.
|
|
27
29
|
|
|
28
30
|
### Connect & diagnostics
|
|
29
31
|
|
|
30
|
-
| Tool | Purpose
|
|
31
|
-
| ------------------ |
|
|
32
|
-
| `debugger-connect` | Connect to the JS runtime's CDP (Metro on iOS / Android; the page CDP session on Chromium). Returns port, projectRoot (empty on Chromium), deviceName, appName, `logicalDeviceId
|
|
33
|
-
| `debugger-status` | Like connect + loadedScripts, enabledDomains, sourceMapReady (no-op on Chromium). **Use to diagnose.**
|
|
32
|
+
| Tool | Purpose |
|
|
33
|
+
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
34
|
+
| `debugger-connect` | Connect to the JS runtime's CDP (Metro on iOS / Android / Vega; the page CDP session on Chromium). Returns port, projectRoot (empty on Chromium and on legacy Metro, e.g. Vega), deviceName, appName, `logicalDeviceId` (absent on Vega), isNewDebugger, connected. When a `logicalDeviceId` comes back, use it as the `device_id` for every subsequent debugger call. |
|
|
35
|
+
| `debugger-status` | Like connect + loadedScripts, enabledDomains, sourceMapReady (no-op on Chromium). **Use to diagnose.** |
|
|
34
36
|
|
|
35
37
|
### Reload & recovery
|
|
36
38
|
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
When a debugger tool fails, use **`debugger-status`** first to diagnose. Then match the error or situation below and act as specified. Do not retry the same failing tool repeatedly without following the recovery steps.
|
|
4
4
|
|
|
5
|
-
| Scenario | Error or situation | What to do
|
|
6
|
-
| ---------------------------------- | ------------------------------------------------------------------------------------------ |
|
|
7
|
-
| **Metro not running** | Error contains: `Metro at port 8081 is not running (got: ...)` | **Start Metro yourself** unless the user asked you not to: scan the workspace configuration and run the appropriate command to start Metro in the background (by default `npx react-native start` or `npx expo start`). Wait for Metro to be ready, then retry `debugger-connect` or `debugger-status`. If you cannot determine the project root, ask the user. |
|
|
8
|
-
| **
|
|
9
|
-
| **App not connected** | Error contains: `Metro at port 8081 has no CDP targets — is a React Native app connected?` | 1) Confirm the app is running on the device. 2) Use `restart-app` with the app's device id and bundleId to relaunch so it connects to Metro. 3) Wait a few seconds for the bundle to load. 4) Retry `debugger-status`. Do **not** use `debugger-reload-metro` to fix this — it also requires at least one target.
|
|
10
|
-
| **Was connected, then tool fails** | Any debugger tool fails with a connection or disconnect error after it was working | The app may have crashed or been closed. Use `restart-app` to relaunch the app, then call `debugger-connect` again to pick up the fresh `logicalDeviceId` (may change for booted-fresh simulators), and use that new `device_id` on all subsequent calls.
|
|
5
|
+
| Scenario | Error or situation | What to do |
|
|
6
|
+
| ---------------------------------- | ------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
7
|
+
| **Metro not running** | Error contains: `Metro at port 8081 is not running (got: ...)` | **Start Metro yourself** unless the user asked you not to: scan the workspace configuration and run the appropriate command to start Metro in the background (by default `npx react-native start` or `npx expo start`). Wait for Metro to be ready, then retry `debugger-connect` or `debugger-status`. If you cannot determine the project root, ask the user. A non-Metro server occupying the port lands here too — the `got:` text shows what answered. |
|
|
8
|
+
| **No source locations** | `projectRoot` is `""` and source lookups report no file:line | Not a failure. Legacy Metro (RN 0.72 and older, e.g. Vega) sends no `X-React-Native-Project-Root` header, so paths cannot be resolved against a project root. `debugger-evaluate`, console logs and the network inspector work regardless — do not restart Metro to "fix" it. |
|
|
9
|
+
| **App not connected** | Error contains: `Metro at port 8081 has no CDP targets — is a React Native app connected?` | 1) Confirm the app is running on the device. 2) Use `restart-app` with the app's device id and bundleId to relaunch so it connects to Metro. 3) Wait a few seconds for the bundle to load. 4) Retry `debugger-status`. Do **not** use `debugger-reload-metro` to fix this — it also requires at least one target. |
|
|
10
|
+
| **Was connected, then tool fails** | Any debugger tool fails with a connection or disconnect error after it was working | The app may have crashed or been closed. Use `restart-app` to relaunch the app, then call `debugger-connect` again to pick up the fresh `logicalDeviceId` (may change for booted-fresh simulators), and use that new `device_id` on all subsequent calls. |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: argent-tv-interact
|
|
3
|
-
description: Control and inspect TV apps via argent — Apple TV (tvOS), Android TV (leanback), and Amazon Fire TV (Vega). Boot the target, read focus, navigate with the D-pad remote, type, and
|
|
3
|
+
description: Control and inspect TV apps via argent — Apple TV (tvOS), Android TV (leanback), and Amazon Fire TV (Vega). Boot the target, read focus, navigate with the D-pad remote, type, screenshot, and on Vega debug the JS runtime (evaluate, console logs, network inspector). Use when a task targets a TV (runtimeKind "tv", or platform "vega"), or mentions Apple TV / tvOS / Android TV / leanback / Vega / Fire TV / VVD.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Argent TV (Apple TV + Android TV + Fire TV)
|
|
@@ -58,3 +58,13 @@ Needs a Debug build + Metro running. argent only _connects_ to Metro — start M
|
|
|
58
58
|
|
|
59
59
|
- **Apple TV / Android TV:** use the dev-build deep-links above; `npm start` for Metro.
|
|
60
60
|
- **Vega:** build/install a Debug `.vpkg` (`vega device install-app -p <path>`), `npm start`, `vega device start-port-forwarding --port 8081 --forward false`, then `vega device launch-app -a <appId>`. Confirm `http://localhost:8081/json/list` shows a `Hermes React Native` target; `.tsx` edits then hot-reload.
|
|
61
|
+
|
|
62
|
+
## Debugging the JS runtime (Vega)
|
|
63
|
+
|
|
64
|
+
Once that same Debug build + Metro setup is in place, the JS-runtime tools work on a Vega VVD: `debugger-connect`, `debugger-status`, `debugger-evaluate`, `debugger-log-registry` (console logs), `view-network-logs`, and `view-network-request-details`. See the `argent-metro-debugger` skill.
|
|
65
|
+
|
|
66
|
+
Vega's React Native forks RN 0.72 and serves the legacy Hermes inspector, so three things differ from iOS / Android:
|
|
67
|
+
|
|
68
|
+
- `debugger-component-tree`, `debugger-inspect-element`, `debugger-reload-metro` and the `react-profiler-*` / `profiler-*` tools are **not supported**. Component-tree and inspect-element are hard-blocked: they need `Runtime.addBinding`, which this Hermes acknowledges but never installs. The rest are simply unverified on the legacy inspector. Use `describe` for on-screen structure; with both component tools gated off, component `file:line` tracing has no path on Vega.
|
|
69
|
+
- `debugger-status` reports `isNewDebugger: false`.
|
|
70
|
+
- `projectRoot` is empty (RN 0.72's Metro sends no project-root header), so lookups that resolve paths against the project root return no location.
|