@phnx-labs/agents-cli 1.20.0 → 1.20.3
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/CHANGELOG.md +73 -0
- package/README.md +4 -4
- package/dist/commands/cli.js +3 -3
- package/dist/commands/cloud.js +1 -1
- package/dist/commands/commands.js +24 -7
- package/dist/commands/exec.js +36 -16
- package/dist/commands/feedback.d.ts +7 -0
- package/dist/commands/feedback.js +89 -0
- package/dist/commands/helper.d.ts +12 -0
- package/dist/commands/helper.js +87 -0
- package/dist/commands/hooks.js +86 -7
- package/dist/commands/mcp.js +166 -10
- package/dist/commands/packages.js +196 -27
- package/dist/commands/permissions.js +21 -6
- package/dist/commands/profiles.d.ts +8 -0
- package/dist/commands/profiles.js +117 -4
- package/dist/commands/pull.js +4 -4
- package/dist/commands/routines.js +6 -6
- package/dist/commands/rules.js +8 -4
- package/dist/commands/secrets-migrate.d.ts +24 -0
- package/dist/commands/secrets-migrate.js +198 -0
- package/dist/commands/secrets-sync.d.ts +11 -0
- package/dist/commands/secrets-sync.js +155 -0
- package/dist/commands/secrets.js +74 -39
- package/dist/commands/skills.js +22 -5
- package/dist/commands/subagents.js +69 -49
- package/dist/commands/teams.js +48 -10
- package/dist/commands/utils.d.ts +33 -0
- package/dist/commands/utils.js +139 -0
- package/dist/commands/versions.js +4 -4
- package/dist/commands/view.d.ts +6 -0
- package/dist/commands/view.js +164 -8
- package/dist/commands/workflows.js +29 -6
- package/dist/index.js +4 -0
- package/dist/lib/acp/client.js +6 -1
- package/dist/lib/agents.d.ts +4 -0
- package/dist/lib/agents.js +18 -14
- package/dist/lib/auto-pull-worker.js +18 -1
- package/dist/lib/browser/chrome.js +4 -0
- package/dist/lib/browser/drivers/ssh.js +1 -1
- package/dist/lib/browser/profiles.d.ts +3 -3
- package/dist/lib/browser/profiles.js +3 -3
- package/dist/lib/browser/service.js +19 -0
- package/dist/lib/browser/types.d.ts +4 -4
- package/dist/lib/cli-resources.d.ts +36 -8
- package/dist/lib/cli-resources.js +268 -46
- package/dist/lib/cloud/factory.d.ts +1 -1
- package/dist/lib/cloud/factory.js +1 -1
- package/dist/lib/events.d.ts +16 -2
- package/dist/lib/events.js +33 -2
- package/dist/lib/exec.d.ts +39 -11
- package/dist/lib/exec.js +90 -31
- package/dist/lib/help.js +11 -5
- package/dist/lib/hooks/cache.d.ts +38 -0
- package/dist/lib/hooks/cache.js +242 -0
- package/dist/lib/hooks/profile.d.ts +33 -0
- package/dist/lib/hooks/profile.js +129 -0
- package/dist/lib/hooks.d.ts +0 -10
- package/dist/lib/hooks.js +68 -15
- package/dist/lib/mcp.d.ts +15 -0
- package/dist/lib/mcp.js +40 -0
- package/dist/lib/permissions.d.ts +13 -0
- package/dist/lib/permissions.js +51 -1
- package/dist/lib/plugins.js +15 -1
- package/dist/lib/profiles-presets.d.ts +26 -0
- package/dist/lib/profiles-presets.js +187 -8
- package/dist/lib/profiles.d.ts +34 -0
- package/dist/lib/profiles.js +112 -1
- package/dist/lib/routines-format.d.ts +17 -5
- package/dist/lib/routines-format.js +37 -16
- package/dist/lib/routines.d.ts +1 -1
- package/dist/lib/routines.js +2 -2
- package/dist/lib/runner.js +64 -10
- package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
- package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
- package/dist/lib/secrets/Agents CLI.app/Contents/_CodeSignature/CodeResources +1 -9
- package/dist/lib/secrets/bundles.d.ts +18 -22
- package/dist/lib/secrets/bundles.js +75 -99
- package/dist/lib/secrets/index.d.ts +51 -27
- package/dist/lib/secrets/index.js +147 -156
- package/dist/lib/secrets/install-helper.d.ts +45 -0
- package/dist/lib/secrets/install-helper.js +165 -0
- package/dist/lib/secrets/linux.js +4 -4
- package/dist/lib/secrets/sync.d.ts +56 -0
- package/dist/lib/secrets/sync.js +180 -0
- package/dist/lib/session/render.js +4 -4
- package/dist/lib/session/types.d.ts +1 -1
- package/dist/lib/shims.d.ts +4 -1
- package/dist/lib/shims.js +5 -35
- package/dist/lib/state.d.ts +14 -1
- package/dist/lib/state.js +49 -5
- package/dist/lib/teams/agents.d.ts +5 -4
- package/dist/lib/teams/agents.js +47 -21
- package/dist/lib/teams/api.d.ts +2 -1
- package/dist/lib/teams/api.js +4 -3
- package/dist/lib/types.d.ts +57 -1
- package/dist/lib/types.js +2 -0
- package/dist/lib/usage.d.ts +27 -2
- package/dist/lib/usage.js +100 -17
- package/dist/lib/versions.d.ts +35 -1
- package/dist/lib/versions.js +267 -64
- package/package.json +9 -8
- package/scripts/install-helper.js +97 -0
- package/scripts/postinstall.js +16 -0
- package/dist/lib/secrets/Agents CLI.app/Contents/embedded.provisionprofile +0 -0
package/dist/index.js
CHANGED
|
@@ -59,6 +59,7 @@ import { registerPullCommand } from './commands/pull.js';
|
|
|
59
59
|
import { registerRepoCommands } from './commands/repo.js';
|
|
60
60
|
import { registerSetupCommand, runSetup } from './commands/setup.js';
|
|
61
61
|
import { registerStatusCommand } from './commands/status.js';
|
|
62
|
+
import { registerFeedbackCommand } from './commands/feedback.js';
|
|
62
63
|
import { registerViewCommand } from './commands/view.js';
|
|
63
64
|
import { registerCommandsCommands } from './commands/commands.js';
|
|
64
65
|
import { registerHooksCommands } from './commands/hooks.js';
|
|
@@ -89,6 +90,7 @@ import { registerBrowserCommand } from './commands/browser.js';
|
|
|
89
90
|
import { registerComputerCommand } from './commands/computer.js';
|
|
90
91
|
import { registerProfilesCommands } from './commands/profiles.js';
|
|
91
92
|
import { registerSecretsCommands } from './commands/secrets.js';
|
|
93
|
+
import { registerHelperCommand } from './commands/helper.js';
|
|
92
94
|
import { registerFactoryCommands } from './commands/factory.js';
|
|
93
95
|
import { registerUsageCommand } from './commands/usage.js';
|
|
94
96
|
import { registerAliasCommand } from './commands/alias.js';
|
|
@@ -509,6 +511,7 @@ async function maybeBootstrapShimIntegration(requestedCommand) {
|
|
|
509
511
|
// Register all commands
|
|
510
512
|
registerViewCommand(program);
|
|
511
513
|
registerStatusCommand(program);
|
|
514
|
+
registerFeedbackCommand(program);
|
|
512
515
|
registerCommandsCommands(program);
|
|
513
516
|
registerHooksCommands(program);
|
|
514
517
|
registerSkillsCommands(program);
|
|
@@ -565,6 +568,7 @@ program
|
|
|
565
568
|
});
|
|
566
569
|
registerProfilesCommands(program);
|
|
567
570
|
registerSecretsCommands(program);
|
|
571
|
+
registerHelperCommand(program);
|
|
568
572
|
registerBetaCommands(program);
|
|
569
573
|
registerSyncCommand(program);
|
|
570
574
|
registerRefreshRulesCommand(program);
|
package/dist/lib/acp/client.js
CHANGED
|
@@ -82,7 +82,12 @@ function buildClient(opts) {
|
|
|
82
82
|
return {};
|
|
83
83
|
},
|
|
84
84
|
async requestPermission(params) {
|
|
85
|
-
|
|
85
|
+
// `skip` (formerly `full`) and `auto` blanket-approve; in `auto` the
|
|
86
|
+
// upstream model has its own classifier so we just say "allow once" and
|
|
87
|
+
// let it decide. `edit` says allow_once. `plan` should never reach here
|
|
88
|
+
// (canWrite gates writes earlier), but if it does we cancel.
|
|
89
|
+
const skipAll = mode === 'skip';
|
|
90
|
+
const optionId = skipAll
|
|
86
91
|
? (params.options.find(o => o.kind === 'allow_always')?.optionId
|
|
87
92
|
?? params.options[0]?.optionId)
|
|
88
93
|
: params.options.find(o => o.kind === 'allow_once')?.optionId;
|
package/dist/lib/agents.d.ts
CHANGED
|
@@ -156,6 +156,10 @@ interface McpConfigEntry {
|
|
|
156
156
|
type?: string;
|
|
157
157
|
url?: string;
|
|
158
158
|
}
|
|
159
|
+
/**
|
|
160
|
+
* Get user-scoped MCP config path for an agent.
|
|
161
|
+
*/
|
|
162
|
+
export declare function getUserMcpConfigPath(agentId: AgentId): string;
|
|
159
163
|
/**
|
|
160
164
|
* Get MCP config path for a specific HOME directory (used for version-managed agents).
|
|
161
165
|
*/
|
package/dist/lib/agents.js
CHANGED
|
@@ -191,7 +191,7 @@ export const AGENTS = {
|
|
|
191
191
|
format: 'markdown',
|
|
192
192
|
variableSyntax: '$ARGUMENTS',
|
|
193
193
|
supportsHooks: true,
|
|
194
|
-
capabilities: { hooks: true, mcp: true, allowlist: true, skills: true, commands: true, plugins: true, rulesImports: true },
|
|
194
|
+
capabilities: { hooks: true, mcp: true, allowlist: true, skills: true, commands: true, plugins: true, modes: ['plan', 'edit', 'auto', 'skip'], rulesImports: true },
|
|
195
195
|
},
|
|
196
196
|
// codex hooks: gated to >= 0.116.0 (introduced [features] codex_hooks flag).
|
|
197
197
|
codex: {
|
|
@@ -210,7 +210,7 @@ export const AGENTS = {
|
|
|
210
210
|
format: 'markdown',
|
|
211
211
|
variableSyntax: '$ARGUMENTS',
|
|
212
212
|
supportsHooks: true,
|
|
213
|
-
capabilities: { hooks: { since: '0.116.0' }, mcp: true, allowlist: false, skills: true, commands: { until: '0.117.0' }, plugins: { since: '0.128.0' } },
|
|
213
|
+
capabilities: { hooks: { since: '0.116.0' }, mcp: true, allowlist: false, skills: true, commands: { until: '0.117.0' }, plugins: { since: '0.128.0' }, modes: ['plan', 'edit', 'skip'] },
|
|
214
214
|
},
|
|
215
215
|
gemini: {
|
|
216
216
|
id: 'gemini',
|
|
@@ -229,7 +229,7 @@ export const AGENTS = {
|
|
|
229
229
|
supportsHooks: true,
|
|
230
230
|
nativeAgentsSkillsDir: true,
|
|
231
231
|
// gemini hooks: shipped in v0.26.0 (Jan 2026); older binaries silently ignore the `hooks` key.
|
|
232
|
-
capabilities: { hooks: { since: '0.26.0' }, mcp: true, allowlist: false, skills: true, commands: true, plugins: false, rulesImports: true },
|
|
232
|
+
capabilities: { hooks: { since: '0.26.0' }, mcp: true, allowlist: false, skills: true, commands: true, plugins: false, modes: ['plan', 'edit', 'skip'], rulesImports: true },
|
|
233
233
|
},
|
|
234
234
|
cursor: {
|
|
235
235
|
id: 'cursor',
|
|
@@ -247,7 +247,7 @@ export const AGENTS = {
|
|
|
247
247
|
format: 'markdown',
|
|
248
248
|
variableSyntax: '$ARGUMENTS',
|
|
249
249
|
supportsHooks: false,
|
|
250
|
-
capabilities: { hooks: false, mcp: true, allowlist: false, skills: true, commands: true, plugins: false },
|
|
250
|
+
capabilities: { hooks: false, mcp: true, allowlist: false, skills: true, commands: true, plugins: false, modes: ['edit', 'skip'] },
|
|
251
251
|
},
|
|
252
252
|
opencode: {
|
|
253
253
|
id: 'opencode',
|
|
@@ -264,7 +264,7 @@ export const AGENTS = {
|
|
|
264
264
|
format: 'markdown',
|
|
265
265
|
variableSyntax: '$ARGUMENTS',
|
|
266
266
|
supportsHooks: false,
|
|
267
|
-
capabilities: { hooks: false, mcp: true, allowlist: false, skills: true, commands: true, plugins: false },
|
|
267
|
+
capabilities: { hooks: false, mcp: true, allowlist: false, skills: true, commands: true, plugins: false, modes: ['plan', 'edit'] },
|
|
268
268
|
},
|
|
269
269
|
openclaw: {
|
|
270
270
|
id: 'openclaw',
|
|
@@ -281,7 +281,7 @@ export const AGENTS = {
|
|
|
281
281
|
format: 'markdown',
|
|
282
282
|
variableSyntax: '{{ARGUMENTS}}',
|
|
283
283
|
supportsHooks: true,
|
|
284
|
-
capabilities: { hooks: true, mcp: true, allowlist: false, skills: true, commands: false, plugins: true },
|
|
284
|
+
capabilities: { hooks: true, mcp: true, allowlist: false, skills: true, commands: false, plugins: true, modes: ['plan', 'edit', 'skip'] },
|
|
285
285
|
},
|
|
286
286
|
copilot: {
|
|
287
287
|
id: 'copilot',
|
|
@@ -298,7 +298,7 @@ export const AGENTS = {
|
|
|
298
298
|
format: 'markdown',
|
|
299
299
|
variableSyntax: '$ARGUMENTS',
|
|
300
300
|
supportsHooks: false,
|
|
301
|
-
capabilities: { hooks: false, mcp: true, allowlist: false, skills: true, commands: true, plugins: false },
|
|
301
|
+
capabilities: { hooks: false, mcp: true, allowlist: false, skills: true, commands: true, plugins: false, modes: ['plan', 'edit', 'auto', 'skip'] },
|
|
302
302
|
},
|
|
303
303
|
amp: {
|
|
304
304
|
id: 'amp',
|
|
@@ -315,7 +315,7 @@ export const AGENTS = {
|
|
|
315
315
|
format: 'markdown',
|
|
316
316
|
variableSyntax: '$ARGUMENTS',
|
|
317
317
|
supportsHooks: false,
|
|
318
|
-
capabilities: { hooks: false, mcp: true, allowlist: false, skills: true, commands: true, plugins: false },
|
|
318
|
+
capabilities: { hooks: false, mcp: true, allowlist: false, skills: true, commands: true, plugins: false, modes: ['plan', 'edit'] },
|
|
319
319
|
},
|
|
320
320
|
kiro: {
|
|
321
321
|
id: 'kiro',
|
|
@@ -333,7 +333,7 @@ export const AGENTS = {
|
|
|
333
333
|
format: 'markdown',
|
|
334
334
|
variableSyntax: '$ARGUMENTS',
|
|
335
335
|
supportsHooks: false,
|
|
336
|
-
capabilities: { hooks: false, mcp: true, allowlist: false, skills: true, commands: true, plugins: false },
|
|
336
|
+
capabilities: { hooks: false, mcp: true, allowlist: false, skills: true, commands: true, plugins: false, modes: ['edit'] },
|
|
337
337
|
},
|
|
338
338
|
goose: {
|
|
339
339
|
id: 'goose',
|
|
@@ -351,7 +351,7 @@ export const AGENTS = {
|
|
|
351
351
|
format: 'markdown',
|
|
352
352
|
variableSyntax: '$ARGUMENTS',
|
|
353
353
|
supportsHooks: false,
|
|
354
|
-
capabilities: { hooks: false, mcp: true, allowlist: false, skills: false, commands: false, plugins: false },
|
|
354
|
+
capabilities: { hooks: false, mcp: true, allowlist: false, skills: false, commands: false, plugins: false, modes: ['edit'] },
|
|
355
355
|
},
|
|
356
356
|
roo: {
|
|
357
357
|
id: 'roo',
|
|
@@ -369,7 +369,7 @@ export const AGENTS = {
|
|
|
369
369
|
format: 'markdown',
|
|
370
370
|
variableSyntax: '$ARGUMENTS',
|
|
371
371
|
supportsHooks: false,
|
|
372
|
-
capabilities: { hooks: false, mcp: true, allowlist: false, skills: true, commands: true, plugins: false },
|
|
372
|
+
capabilities: { hooks: false, mcp: true, allowlist: false, skills: true, commands: true, plugins: false, modes: ['plan', 'edit'] },
|
|
373
373
|
},
|
|
374
374
|
// Google Antigravity CLI (`agy`) — official replacement for Gemini CLI as of IO 2026.
|
|
375
375
|
// configDir nests inside `~/.gemini/` since agy shares the parent dir with the Gemini
|
|
@@ -396,7 +396,7 @@ export const AGENTS = {
|
|
|
396
396
|
format: 'markdown',
|
|
397
397
|
variableSyntax: '{{args}}',
|
|
398
398
|
supportsHooks: true,
|
|
399
|
-
capabilities: { hooks: true, mcp: true, allowlist: true, skills: true, commands: true, plugins: true, rulesImports: false },
|
|
399
|
+
capabilities: { hooks: true, mcp: true, allowlist: true, skills: true, commands: true, plugins: true, modes: ['edit', 'skip'], rulesImports: false },
|
|
400
400
|
},
|
|
401
401
|
// xAI Grok Build CLI (`grok`) — early beta, SuperGrok Heavy. Auth via OAuth on
|
|
402
402
|
// first launch, or XAI_API_KEY env var for headless. MCP servers configured inline
|
|
@@ -410,7 +410,7 @@ export const AGENTS = {
|
|
|
410
410
|
color: 'cyanBright',
|
|
411
411
|
cliCommand: 'grok',
|
|
412
412
|
npmPackage: '',
|
|
413
|
-
installScript: 'curl -fsSL https://x.ai/cli/install.sh | bash
|
|
413
|
+
installScript: 'curl -fsSL https://x.ai/cli/install.sh | bash',
|
|
414
414
|
configDir: path.join(HOME, '.grok'),
|
|
415
415
|
commandsDir: '', // Grok primarily uses skills + slash commands from skills
|
|
416
416
|
commandsSubdir: '',
|
|
@@ -427,6 +427,7 @@ export const AGENTS = {
|
|
|
427
427
|
skills: true,
|
|
428
428
|
commands: false, // covered by skills
|
|
429
429
|
plugins: true,
|
|
430
|
+
modes: ['plan', 'edit', 'skip'],
|
|
430
431
|
rulesImports: true,
|
|
431
432
|
},
|
|
432
433
|
},
|
|
@@ -1197,7 +1198,7 @@ function parseMcpFromOpenCodeConfig(configPath) {
|
|
|
1197
1198
|
/**
|
|
1198
1199
|
* Get user-scoped MCP config path for an agent.
|
|
1199
1200
|
*/
|
|
1200
|
-
function getUserMcpConfigPath(agentId) {
|
|
1201
|
+
export function getUserMcpConfigPath(agentId) {
|
|
1201
1202
|
const agent = AGENTS[agentId];
|
|
1202
1203
|
switch (agentId) {
|
|
1203
1204
|
case 'claude':
|
|
@@ -1215,6 +1216,9 @@ function getUserMcpConfigPath(agentId) {
|
|
|
1215
1216
|
case 'openclaw':
|
|
1216
1217
|
// OpenClaw uses openclaw.json
|
|
1217
1218
|
return path.join(agent.configDir, 'openclaw.json');
|
|
1219
|
+
case 'copilot':
|
|
1220
|
+
// GitHub Copilot CLI uses mcp-config.json (matches versioned + project paths)
|
|
1221
|
+
return path.join(agent.configDir, 'mcp-config.json');
|
|
1218
1222
|
case 'antigravity':
|
|
1219
1223
|
// agy uses mcp_config.json inside its nested config dir (~/.gemini/antigravity-cli/)
|
|
1220
1224
|
return path.join(agent.configDir, 'mcp_config.json');
|
|
@@ -14,6 +14,15 @@ import { tryAutoPull, isGitRepo } from './git.js';
|
|
|
14
14
|
import { getSystemAgentsDir, getUserAgentsDir, getEnabledExtraRepos, getFetchCacheDir, } from './state.js';
|
|
15
15
|
import { lockFilePath, statusFilePath } from './auto-pull.js';
|
|
16
16
|
const LOCK_TTL_MS = 5 * 60 * 1000;
|
|
17
|
+
/**
|
|
18
|
+
* Background auto-pull of ~/.agents-system/ is off by default. When enabled it
|
|
19
|
+
* silently fast-forwards a tracked source tree that the CLI then reads as a
|
|
20
|
+
* source of skills, hooks, install manifests, and commands — anyone with push
|
|
21
|
+
* access to that upstream gets remote code execution on every user the next
|
|
22
|
+
* time they invoke a command that loads a system resource. Operators that
|
|
23
|
+
* really want the convenience can set AGENTS_AUTO_PULL=1.
|
|
24
|
+
*/
|
|
25
|
+
const ENABLE_AUTO_PULL = process.env.AGENTS_AUTO_PULL === '1';
|
|
17
26
|
function ensureFetchDir() {
|
|
18
27
|
const dir = getFetchCacheDir();
|
|
19
28
|
if (!fs.existsSync(dir)) {
|
|
@@ -84,7 +93,15 @@ async function processTarget(target) {
|
|
|
84
93
|
return;
|
|
85
94
|
try {
|
|
86
95
|
if (target.mode === 'pull') {
|
|
87
|
-
|
|
96
|
+
if (!ENABLE_AUTO_PULL) {
|
|
97
|
+
// Demote to a fetch + notify; the user still sees ahead/behind on the
|
|
98
|
+
// next foreground CLI invocation, but the source tree is never mutated
|
|
99
|
+
// by a detached worker.
|
|
100
|
+
await notifyRepo(target);
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
await tryAutoPull(target.dir);
|
|
104
|
+
}
|
|
88
105
|
}
|
|
89
106
|
else {
|
|
90
107
|
await notifyRepo(target);
|
|
@@ -139,6 +139,10 @@ isElectron = false) {
|
|
|
139
139
|
'--no-default-browser-check',
|
|
140
140
|
'--disable-features=DefaultBrowserSetting,ChromeWhatsNewUI',
|
|
141
141
|
'--disable-crash-reporter',
|
|
142
|
+
// Suppress navigator.webdriver = true, which Chromium sets whenever a
|
|
143
|
+
// remote-debugging transport is active. That property is the loudest
|
|
144
|
+
// signal Cloudflare Turnstile, hCaptcha, and similar checks read.
|
|
145
|
+
'--disable-blink-features=AutomationControlled',
|
|
142
146
|
...(options.headless ? ['--headless=new'] : []),
|
|
143
147
|
`--window-size=${viewport.width},${viewport.height}`,
|
|
144
148
|
...(viewport.x !== undefined && viewport.y !== undefined
|
|
@@ -180,7 +180,7 @@ async function ensureRemoteBrowser(user, host, browserType, port, customBinary)
|
|
|
180
180
|
const remoteCmd = [
|
|
181
181
|
shellQuote(browserPath),
|
|
182
182
|
`--remote-debugging-port=${port}`,
|
|
183
|
-
shellQuote(
|
|
183
|
+
shellQuote(`--remote-allow-origins=http://127.0.0.1:${port}`),
|
|
184
184
|
'--disable-background-timer-throttling',
|
|
185
185
|
`--user-data-dir=/tmp/agents-browser-${port}`,
|
|
186
186
|
'</dev/null >/dev/null 2>&1 &',
|
|
@@ -65,12 +65,12 @@ export declare function resolveEndpoint(profile: BrowserProfile, endpointName?:
|
|
|
65
65
|
* Returns undefined for endpoint shapes that don't carry a port (e.g. ws:// without one).
|
|
66
66
|
*
|
|
67
67
|
* Ports are scoped by host: a `cdp://127.0.0.1:9222` profile (local Chrome on
|
|
68
|
-
* this machine) and an `ssh://
|
|
69
|
-
* point at different physical ports — the host disambiguates them.
|
|
68
|
+
* this machine) and an `ssh://remote-host:9222` profile (Comet on a remote
|
|
69
|
+
* host) point at different physical ports — the host disambiguates them.
|
|
70
70
|
*
|
|
71
71
|
* Accepts both `scheme://host:port` and `scheme://host?port=N` shapes (the
|
|
72
72
|
* latter is the documented form in `types.ts` for `ssh://`). Without this,
|
|
73
|
-
* `ssh://
|
|
73
|
+
* `ssh://remote-host?port=18805` would silently fall back to 9222 and every
|
|
74
74
|
* `?port=`-style SSH profile would collide on creation.
|
|
75
75
|
*/
|
|
76
76
|
export declare function extractConfiguredEndpoint(profile: BrowserProfile): {
|
|
@@ -299,12 +299,12 @@ export function resolveEndpoint(profile, endpointName) {
|
|
|
299
299
|
* Returns undefined for endpoint shapes that don't carry a port (e.g. ws:// without one).
|
|
300
300
|
*
|
|
301
301
|
* Ports are scoped by host: a `cdp://127.0.0.1:9222` profile (local Chrome on
|
|
302
|
-
* this machine) and an `ssh://
|
|
303
|
-
* point at different physical ports — the host disambiguates them.
|
|
302
|
+
* this machine) and an `ssh://remote-host:9222` profile (Comet on a remote
|
|
303
|
+
* host) point at different physical ports — the host disambiguates them.
|
|
304
304
|
*
|
|
305
305
|
* Accepts both `scheme://host:port` and `scheme://host?port=N` shapes (the
|
|
306
306
|
* latter is the documented form in `types.ts` for `ssh://`). Without this,
|
|
307
|
-
* `ssh://
|
|
307
|
+
* `ssh://remote-host?port=18805` would silently fall back to 9222 and every
|
|
308
308
|
* `?port=`-style SSH profile would collide on creation.
|
|
309
309
|
*/
|
|
310
310
|
export function extractConfiguredEndpoint(profile) {
|
|
@@ -1701,6 +1701,25 @@ export class BrowserService {
|
|
|
1701
1701
|
targetId: tabId,
|
|
1702
1702
|
flatten: true,
|
|
1703
1703
|
}));
|
|
1704
|
+
// Inject a one-shot stealth shim before any page script runs. Chromium
|
|
1705
|
+
// unconditionally exposes navigator.webdriver = true when a remote-debug
|
|
1706
|
+
// transport is attached; Cloudflare Turnstile, hCaptcha, and similar bot
|
|
1707
|
+
// checks read that property first. For browsers agents-cli spawns the
|
|
1708
|
+
// --disable-blink-features=AutomationControlled launch flag already
|
|
1709
|
+
// covers this, but for attach-to-running profiles (the Comet / Arc /
|
|
1710
|
+
// Brave case where the user launched the browser themselves) the flag
|
|
1711
|
+
// is unavailable — Page.addScriptToEvaluateOnNewDocument is the only
|
|
1712
|
+
// lever. Non-page targets (workers, service workers) will reject these
|
|
1713
|
+
// calls; we swallow the error and keep going.
|
|
1714
|
+
try {
|
|
1715
|
+
await conn.cdp.send('Page.enable', {}, sessionId);
|
|
1716
|
+
await conn.cdp.send('Page.addScriptToEvaluateOnNewDocument', {
|
|
1717
|
+
source: "Object.defineProperty(navigator,'webdriver',{get:()=>undefined});",
|
|
1718
|
+
}, sessionId);
|
|
1719
|
+
}
|
|
1720
|
+
catch {
|
|
1721
|
+
// Target doesn't support Page domain — nothing to inject.
|
|
1722
|
+
}
|
|
1704
1723
|
conn.sessionCache.set(tabId, sessionId);
|
|
1705
1724
|
return sessionId;
|
|
1706
1725
|
}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
export type BrowserType = 'chrome' | 'comet' | 'chromium' | 'brave' | 'edge' | 'custom';
|
|
2
2
|
/**
|
|
3
3
|
* A single named endpoint preset within a profile. Lets one profile cover
|
|
4
|
-
* the local + remote variants of the same app (e.g.
|
|
5
|
-
*
|
|
4
|
+
* the local + remote variants of the same app (e.g. an Electron app on this
|
|
5
|
+
* Mac vs. on a remote host) instead of forcing two parallel profiles.
|
|
6
6
|
*
|
|
7
7
|
* Per-endpoint overrides take precedence over profile-level fields.
|
|
8
8
|
*/
|
|
9
9
|
export interface EndpointPreset {
|
|
10
10
|
/** CDP URL — `cdp://host:port` or `ssh://host?port=N` */
|
|
11
11
|
target: string;
|
|
12
|
-
/** Override the profile-level binary (e.g.
|
|
12
|
+
/** Override the profile-level binary (e.g. a remote host has no local binary). */
|
|
13
13
|
binary?: string;
|
|
14
14
|
/** Override the profile-level targetFilter (Electron app builds may diverge). */
|
|
15
15
|
targetFilter?: string;
|
|
@@ -43,7 +43,7 @@ export interface BrowserProfile {
|
|
|
43
43
|
};
|
|
44
44
|
/** Directory holding source-side JSONL logs (e.g. ~/.rush/logs). */
|
|
45
45
|
logDir?: string;
|
|
46
|
-
/** Optional SSH host where logDir lives, e.g. "user@
|
|
46
|
+
/** Optional SSH host where logDir lives, e.g. "user@remote-host". */
|
|
47
47
|
logHost?: string;
|
|
48
48
|
}
|
|
49
49
|
/** Parsed form of `BrowserProfile.targetFilter`. */
|
|
@@ -16,6 +16,21 @@ export interface BinarySpec {
|
|
|
16
16
|
extract?: string;
|
|
17
17
|
};
|
|
18
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* How to verify a CLI is installed. Structured so we can dispatch to spawnSync
|
|
21
|
+
* with an argv array — never through a shell.
|
|
22
|
+
*
|
|
23
|
+
* `which` — just check PATH for `cmd`.
|
|
24
|
+
* `version` — spawn `cmd` with `args` and require exit 0.
|
|
25
|
+
*/
|
|
26
|
+
export type CheckSpec = {
|
|
27
|
+
kind: 'which';
|
|
28
|
+
cmd: string;
|
|
29
|
+
} | {
|
|
30
|
+
kind: 'version';
|
|
31
|
+
cmd: string;
|
|
32
|
+
args: string[];
|
|
33
|
+
};
|
|
19
34
|
/** Parsed CLI manifest. */
|
|
20
35
|
export interface CliManifest {
|
|
21
36
|
/** Name as it appears on the command line (e.g. "higgsfield"). */
|
|
@@ -24,8 +39,8 @@ export interface CliManifest {
|
|
|
24
39
|
description?: string;
|
|
25
40
|
/** Project homepage; used in detail view + post-install messaging. */
|
|
26
41
|
homepage?: string;
|
|
27
|
-
/**
|
|
28
|
-
check:
|
|
42
|
+
/** Structured check spec; never a raw shell command. */
|
|
43
|
+
check: CheckSpec;
|
|
29
44
|
/** Install methods tried in order; first one whose tool is available is used. */
|
|
30
45
|
install: InstallMethod[];
|
|
31
46
|
/** Message printed after successful install — typically auth instructions. */
|
|
@@ -42,6 +57,13 @@ export interface CliManifestError {
|
|
|
42
57
|
/** Human-readable reason. */
|
|
43
58
|
reason: string;
|
|
44
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* Parse a `check:` field into a CheckSpec. Accepts either a structured object
|
|
62
|
+
* (`{ kind: 'which'|'version', cmd, args? }`) or a legacy whitespace-separated
|
|
63
|
+
* string. String form is split on whitespace and each token is validated against
|
|
64
|
+
* SAFE_CHECK_TOKEN — manifests cannot smuggle in shell metacharacters.
|
|
65
|
+
*/
|
|
66
|
+
export declare function parseCheckSpec(raw: unknown, defaultName: string): CheckSpec;
|
|
45
67
|
/**
|
|
46
68
|
* Parse a single CLI manifest from its YAML contents.
|
|
47
69
|
* Returns a manifest on success; throws on schema violations so callers can
|
|
@@ -63,13 +85,18 @@ export declare function listCliManifests(cwd?: string): {
|
|
|
63
85
|
/** Resolve a single CLI manifest by name. Returns null when not declared. */
|
|
64
86
|
export declare function resolveCliManifest(name: string, cwd?: string): CliManifest | null;
|
|
65
87
|
export declare function hasCommand(cmd: string): boolean;
|
|
66
|
-
/**
|
|
88
|
+
/**
|
|
89
|
+
* Run the manifest's check. Dispatches on CheckSpec.kind — never invokes a
|
|
90
|
+
* shell, never interpolates strings into a command line.
|
|
91
|
+
*/
|
|
67
92
|
export declare function isCliInstalled(manifest: CliManifest): boolean;
|
|
68
93
|
/**
|
|
69
94
|
* Pick the first install method whose required host tool is available.
|
|
70
95
|
* Returns null when none of the declared methods can run on this host.
|
|
71
96
|
*/
|
|
72
97
|
export declare function selectInstallMethod(manifest: CliManifest): InstallMethod | null;
|
|
98
|
+
/** Render a CheckSpec back to a human-readable command string (display only). */
|
|
99
|
+
export declare function describeCheck(check: CheckSpec): string;
|
|
73
100
|
/** Short description of a method for display. */
|
|
74
101
|
export declare function describeMethod(method: InstallMethod): string;
|
|
75
102
|
export interface InstallResult {
|
|
@@ -83,6 +110,12 @@ export interface InstallResult {
|
|
|
83
110
|
/** Set when the install runner threw or exited non-zero. */
|
|
84
111
|
error?: string;
|
|
85
112
|
}
|
|
113
|
+
/**
|
|
114
|
+
* Display-only rendering of how a method would be run, for `--dry-run` and
|
|
115
|
+
* status output. Not used by installCli — execution goes through runInstallMethod
|
|
116
|
+
* which dispatches to spawnSync with argv arrays.
|
|
117
|
+
*/
|
|
118
|
+
export declare function buildInstallCommand(method: InstallMethod): string;
|
|
86
119
|
/**
|
|
87
120
|
* Install a single CLI by running its first compatible method. Streams the
|
|
88
121
|
* underlying command's output to the parent terminal so users see brew/npm
|
|
@@ -91,11 +124,6 @@ export interface InstallResult {
|
|
|
91
124
|
export declare function installCli(manifest: CliManifest, opts?: {
|
|
92
125
|
dryRun?: boolean;
|
|
93
126
|
}): InstallResult;
|
|
94
|
-
/**
|
|
95
|
-
* Map a declarative method to a shell command. Centralized so tests and dry-run
|
|
96
|
-
* surface the exact string that would execute.
|
|
97
|
-
*/
|
|
98
|
-
export declare function buildInstallCommand(method: InstallMethod): string;
|
|
99
127
|
export interface CliStatus {
|
|
100
128
|
manifest: CliManifest;
|
|
101
129
|
installed: boolean;
|