@phnx-labs/agents-cli 1.22.116 → 1.22.118

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.
Files changed (254) hide show
  1. package/CHANGELOG.md +247 -0
  2. package/dist/bootstrap.js +4 -11
  3. package/dist/commands/browser.d.ts +52 -70
  4. package/dist/commands/browser.js +192 -3562
  5. package/dist/commands/daemon.d.ts +39 -2
  6. package/dist/commands/daemon.js +72 -73
  7. package/dist/commands/events.js +1 -1
  8. package/dist/commands/exec.d.ts +18 -0
  9. package/dist/commands/exec.js +104 -12
  10. package/dist/commands/repo.js +13 -49
  11. package/dist/commands/route.js +5 -5
  12. package/dist/commands/routines.js +39 -12
  13. package/dist/commands/sessions-render.d.ts +1 -1
  14. package/dist/commands/sessions-render.js +0 -1
  15. package/dist/commands/sessions.test-fixture.d.ts +0 -1
  16. package/dist/commands/sessions.test-fixture.js +0 -37
  17. package/dist/commands/setup-browser.d.ts +17 -12
  18. package/dist/commands/setup-browser.js +52 -87
  19. package/dist/commands/setup-preferences.d.ts +0 -17
  20. package/dist/commands/setup-preferences.js +18 -49
  21. package/dist/commands/setup-term.d.ts +4 -3
  22. package/dist/commands/setup-term.js +5 -4
  23. package/dist/commands/setup.js +11 -11
  24. package/dist/commands/ssh.js +10 -1
  25. package/dist/commands/sync.js +6 -44
  26. package/dist/commands/teams.js +0 -1
  27. package/dist/commands/update.d.ts +19 -0
  28. package/dist/commands/update.js +34 -6
  29. package/dist/commands/view.d.ts +12 -1
  30. package/dist/commands/view.js +47 -2
  31. package/dist/index.js +107 -26
  32. package/dist/lib/account-capabilities.js +0 -2
  33. package/dist/lib/account-catalog.d.ts +38 -0
  34. package/dist/lib/account-catalog.js +110 -26
  35. package/dist/lib/account-provider-registry.js +1 -1
  36. package/dist/lib/account-registry.d.ts +1 -1
  37. package/dist/lib/account-registry.js +36 -2
  38. package/dist/lib/accounting/rotate.js +22 -8
  39. package/dist/lib/accounting/usage-ingest.d.ts +6 -1
  40. package/dist/lib/accounting/usage-ingest.js +115 -45
  41. package/dist/lib/accounting/usage-sync.d.ts +134 -31
  42. package/dist/lib/accounting/usage-sync.js +227 -66
  43. package/dist/lib/accounting/usage.d.ts +16 -3
  44. package/dist/lib/accounting/usage.js +26 -8
  45. package/dist/lib/accounts/slots.d.ts +8 -0
  46. package/dist/lib/accounts/slots.js +17 -0
  47. package/dist/lib/add-dir.js +0 -1
  48. package/dist/lib/agent-cli-commands.js +0 -1
  49. package/dist/lib/agent-spec/agents.d.ts +6 -7
  50. package/dist/lib/agent-spec/agents.js +6 -60
  51. package/dist/lib/auth-health.d.ts +69 -1
  52. package/dist/lib/auth-health.js +133 -4
  53. package/dist/lib/browser/context.d.ts +82 -0
  54. package/dist/lib/browser/context.js +88 -0
  55. package/dist/lib/browser/paths.d.ts +25 -0
  56. package/dist/lib/browser/paths.js +51 -0
  57. package/dist/lib/browser/record.d.ts +38 -0
  58. package/dist/lib/browser/record.js +57 -0
  59. package/dist/lib/browser/sessions-list.js +1 -2
  60. package/dist/lib/browser-client.d.ts +158 -0
  61. package/dist/lib/browser-client.js +234 -0
  62. package/dist/lib/channels/owner-sink.d.ts +1 -18
  63. package/dist/lib/channels/owner-sink.js +29 -82
  64. package/dist/lib/channels/providers/rush.d.ts +7 -7
  65. package/dist/lib/channels/providers/rush.js +127 -57
  66. package/dist/lib/claude-statusline.d.ts +1 -1
  67. package/dist/lib/claude-statusline.js +15 -3
  68. package/dist/lib/commands.js +1 -1
  69. package/dist/lib/crabbox/lease.js +1 -1
  70. package/dist/lib/crabbox/runtimes.js +1 -3
  71. package/dist/lib/daemon/account-state-daemon-service.js +1 -0
  72. package/dist/lib/daemon/auth-sync-service.d.ts +21 -18
  73. package/dist/lib/daemon/auth-sync-service.js +37 -43
  74. package/dist/lib/daemon/daemon.d.ts +25 -14
  75. package/dist/lib/daemon/daemon.js +92 -154
  76. package/dist/lib/daemon/runner.d.ts +2 -2
  77. package/dist/lib/daemon/runner.js +32 -9
  78. package/dist/lib/daemon/self-update-service.d.ts +35 -34
  79. package/dist/lib/daemon/self-update-service.js +40 -36
  80. package/dist/lib/daemon/service.d.ts +12 -8
  81. package/dist/lib/daemon/supervisor.d.ts +65 -54
  82. package/dist/lib/daemon/supervisor.js +136 -171
  83. package/dist/lib/daemon/testdata/process-view-start.js +5 -2
  84. package/dist/lib/daemon/usage-sync-service.d.ts +21 -30
  85. package/dist/lib/daemon/usage-sync-service.js +46 -78
  86. package/dist/lib/daemon-health.d.ts +22 -5
  87. package/dist/lib/daemon-health.js +47 -3
  88. package/dist/lib/daemon-services.d.ts +1 -1
  89. package/dist/lib/daemon-services.js +0 -10
  90. package/dist/lib/daemon-ticks.js +4 -2
  91. package/dist/lib/devices/doctor-findings.js +8 -11
  92. package/dist/lib/devices/harness-inventory.js +14 -5
  93. package/dist/lib/exec-account-home.js +5 -0
  94. package/dist/lib/exec.js +0 -11
  95. package/dist/lib/feed/events.js +0 -1
  96. package/dist/lib/feed/tool-activity.js +5 -2
  97. package/dist/lib/fleet-shared-state.d.ts +45 -0
  98. package/dist/lib/fleet-shared-state.js +78 -9
  99. package/dist/lib/fs-atomic.js +25 -0
  100. package/dist/lib/harness-auth-capabilities.js +0 -1
  101. package/dist/lib/helper-versions.js +1 -1
  102. package/dist/lib/hooks/cache.d.ts +7 -0
  103. package/dist/lib/hooks/cache.js +27 -2
  104. package/dist/lib/hooks/install.js +7 -1
  105. package/dist/lib/hosts/ready.d.ts +38 -8
  106. package/dist/lib/hosts/ready.js +62 -14
  107. package/dist/lib/hosts/remote-cmd.js +1 -0
  108. package/dist/lib/installations/active-check.d.ts +27 -0
  109. package/dist/lib/installations/active-check.js +61 -0
  110. package/dist/lib/installations/migrate.js +6 -3
  111. package/dist/lib/installations/shims.js +9 -7
  112. package/dist/lib/installations/update.js +21 -15
  113. package/dist/lib/installations/versions.js +12 -1
  114. package/dist/lib/manifest.js +1 -1
  115. package/dist/lib/models.js +0 -2
  116. package/dist/lib/open-url.js +28 -54
  117. package/dist/lib/placement.d.ts +2 -0
  118. package/dist/lib/placement.js +5 -0
  119. package/dist/lib/profiles.js +0 -2
  120. package/dist/lib/refresh.js +1 -1
  121. package/dist/lib/routine-readiness.d.ts +35 -0
  122. package/dist/lib/routine-readiness.js +74 -16
  123. package/dist/lib/rules/compile.js +6 -0
  124. package/dist/lib/sandbox.js +0 -2
  125. package/dist/lib/secrets-policy.d.ts +89 -11
  126. package/dist/lib/secrets-policy.js +175 -28
  127. package/dist/lib/session/db.d.ts +1 -1
  128. package/dist/lib/session/db.js +65 -18
  129. package/dist/lib/session/discover.js +1 -283
  130. package/dist/lib/session/mirror.d.ts +4 -3
  131. package/dist/lib/session/mirror.js +4 -3
  132. package/dist/lib/session/parse.d.ts +0 -2
  133. package/dist/lib/session/parse.js +1 -138
  134. package/dist/lib/session/throughput.d.ts +1 -3
  135. package/dist/lib/session/throughput.js +0 -20
  136. package/dist/lib/session/types.d.ts +2 -2
  137. package/dist/lib/session/types.js +2 -2
  138. package/dist/lib/sessions-client.d.ts +60 -1
  139. package/dist/lib/sessions-client.js +227 -4
  140. package/dist/lib/setup-tool-status.js +8 -12
  141. package/dist/lib/signin-badge.d.ts +3 -2
  142. package/dist/lib/signin-badge.js +6 -3
  143. package/dist/lib/smart-launch.js +4 -1
  144. package/dist/lib/staleness/detectors/commands.d.ts +1 -1
  145. package/dist/lib/staleness/detectors/hooks.d.ts +1 -1
  146. package/dist/lib/staleness/detectors/mcp.d.ts +1 -1
  147. package/dist/lib/staleness/detectors/permissions.d.ts +1 -1
  148. package/dist/lib/staleness/detectors/plugins.d.ts +1 -1
  149. package/dist/lib/staleness/detectors/rules.d.ts +1 -1
  150. package/dist/lib/staleness/detectors/skills.d.ts +1 -1
  151. package/dist/lib/staleness/detectors/subagents.d.ts +1 -1
  152. package/dist/lib/staleness/detectors/workflows.d.ts +1 -1
  153. package/dist/lib/staleness/writers/commands.d.ts +1 -1
  154. package/dist/lib/staleness/writers/hooks.d.ts +1 -1
  155. package/dist/lib/staleness/writers/mcp.d.ts +1 -1
  156. package/dist/lib/staleness/writers/permissions.d.ts +1 -1
  157. package/dist/lib/staleness/writers/plugins.d.ts +1 -1
  158. package/dist/lib/staleness/writers/rules.d.ts +1 -1
  159. package/dist/lib/staleness/writers/skills.d.ts +1 -1
  160. package/dist/lib/staleness/writers/sources.js +5 -0
  161. package/dist/lib/staleness/writers/subagents.d.ts +1 -1
  162. package/dist/lib/staleness/writers/workflows.d.ts +1 -1
  163. package/dist/lib/state.d.ts +6 -4
  164. package/dist/lib/state.js +7 -17
  165. package/dist/lib/teams/parsers.d.ts +1 -1
  166. package/dist/lib/teams/parsers.js +1 -136
  167. package/dist/lib/teams/placement-probe.js +50 -15
  168. package/dist/lib/teams/scheduler.d.ts +7 -0
  169. package/dist/lib/types.d.ts +10 -1
  170. package/dist/lib/types.js +1 -1
  171. package/dist/lib/view-types.d.ts +32 -0
  172. package/dist/lib/watchdog/read.js +0 -1
  173. package/dist/lib/watchdog/rotate.js +1 -2
  174. package/dist/lib/watchdog/runner.js +2 -2
  175. package/dist/lib/watchdog/watchdog.d.ts +1 -1
  176. package/dist/lib/watchdog/watchdogTail.js +0 -31
  177. package/package.json +1 -1
  178. package/scripts/postinstall.js +8 -8
  179. package/dist/browser.d.ts +0 -2
  180. package/dist/browser.js +0 -17
  181. package/dist/commands/browser-picker.d.ts +0 -18
  182. package/dist/commands/browser-picker.js +0 -97
  183. package/dist/lib/browser/arc-discovery.d.ts +0 -52
  184. package/dist/lib/browser/arc-discovery.js +0 -197
  185. package/dist/lib/browser/arc-dom.d.ts +0 -14
  186. package/dist/lib/browser/arc-dom.js +0 -121
  187. package/dist/lib/browser/caller-identity.d.ts +0 -40
  188. package/dist/lib/browser/caller-identity.js +0 -175
  189. package/dist/lib/browser/cdp.d.ts +0 -51
  190. package/dist/lib/browser/cdp.js +0 -254
  191. package/dist/lib/browser/chrome.d.ts +0 -141
  192. package/dist/lib/browser/chrome.js +0 -704
  193. package/dist/lib/browser/chromium-discovery.d.ts +0 -28
  194. package/dist/lib/browser/chromium-discovery.js +0 -96
  195. package/dist/lib/browser/devices.d.ts +0 -34
  196. package/dist/lib/browser/devices.js +0 -61
  197. package/dist/lib/browser/domain-skills.d.ts +0 -71
  198. package/dist/lib/browser/domain-skills.js +0 -195
  199. package/dist/lib/browser/drivers/arc.d.ts +0 -40
  200. package/dist/lib/browser/drivers/arc.js +0 -276
  201. package/dist/lib/browser/drivers/firefox.d.ts +0 -99
  202. package/dist/lib/browser/drivers/firefox.js +0 -377
  203. package/dist/lib/browser/drivers/local.d.ts +0 -55
  204. package/dist/lib/browser/drivers/local.js +0 -266
  205. package/dist/lib/browser/drivers/ssh.d.ts +0 -120
  206. package/dist/lib/browser/drivers/ssh.js +0 -467
  207. package/dist/lib/browser/editor.d.ts +0 -3
  208. package/dist/lib/browser/editor.js +0 -50
  209. package/dist/lib/browser/ffmpeg.d.ts +0 -12
  210. package/dist/lib/browser/ffmpeg.js +0 -184
  211. package/dist/lib/browser/firefox-discovery.d.ts +0 -69
  212. package/dist/lib/browser/firefox-discovery.js +0 -162
  213. package/dist/lib/browser/har.d.ts +0 -85
  214. package/dist/lib/browser/har.js +0 -77
  215. package/dist/lib/browser/hygiene.d.ts +0 -97
  216. package/dist/lib/browser/hygiene.js +0 -153
  217. package/dist/lib/browser/index.d.ts +0 -5
  218. package/dist/lib/browser/index.js +0 -5
  219. package/dist/lib/browser/input.d.ts +0 -7
  220. package/dist/lib/browser/input.js +0 -92
  221. package/dist/lib/browser/ipc.d.ts +0 -204
  222. package/dist/lib/browser/ipc.js +0 -1453
  223. package/dist/lib/browser/login-detection.d.ts +0 -87
  224. package/dist/lib/browser/login-detection.js +0 -274
  225. package/dist/lib/browser/profiles.d.ts +0 -422
  226. package/dist/lib/browser/profiles.js +0 -1157
  227. package/dist/lib/browser/refs.d.ts +0 -89
  228. package/dist/lib/browser/refs.js +0 -191
  229. package/dist/lib/browser/registry.d.ts +0 -70
  230. package/dist/lib/browser/registry.js +0 -252
  231. package/dist/lib/browser/remote-control.d.ts +0 -59
  232. package/dist/lib/browser/remote-control.js +0 -85
  233. package/dist/lib/browser/resolve-target.d.ts +0 -66
  234. package/dist/lib/browser/resolve-target.js +0 -264
  235. package/dist/lib/browser/runtime-state.d.ts +0 -291
  236. package/dist/lib/browser/runtime-state.js +0 -584
  237. package/dist/lib/browser/secret-ref.d.ts +0 -10
  238. package/dist/lib/browser/secret-ref.js +0 -14
  239. package/dist/lib/browser/service.d.ts +0 -812
  240. package/dist/lib/browser/service.js +0 -4693
  241. package/dist/lib/browser/stream.d.ts +0 -17
  242. package/dist/lib/browser/stream.js +0 -72
  243. package/dist/lib/browser/task-index.d.ts +0 -78
  244. package/dist/lib/browser/task-index.js +0 -199
  245. package/dist/lib/browser/types.d.ts +0 -647
  246. package/dist/lib/browser/types.js +0 -61
  247. package/dist/lib/browser/upload.d.ts +0 -29
  248. package/dist/lib/browser/upload.js +0 -298
  249. package/dist/lib/daemon/browser-ipc-service.d.ts +0 -20
  250. package/dist/lib/daemon/browser-ipc-service.js +0 -46
  251. package/dist/lib/daemon/browser-task-reap-service.d.ts +0 -14
  252. package/dist/lib/daemon/browser-task-reap-service.js +0 -26
  253. package/dist/lib/fleet-shared-repo-sync.d.ts +0 -55
  254. package/dist/lib/fleet-shared-repo-sync.js +0 -490
@@ -1,97 +0,0 @@
1
- /**
2
- * Interactive browser task picker with preview.
3
- *
4
- * Powers the fuzzy-searchable task list shown by `agents browser status` in a TTY.
5
- * Shows task name, profile, domains, and tab count; preview pane shows full tab list.
6
- */
7
- import chalk from 'chalk';
8
- import { truncate, humanDuration } from '../lib/format.js';
9
- import { itemPicker } from '../lib/picker.js';
10
- const DOT = chalk.gray(' · ');
11
- function formatAge(ms) {
12
- return humanDuration(Date.now() - ms) + ' ago';
13
- }
14
- /** Build the preview pane for a browser task. */
15
- function buildBrowserPreview(item) {
16
- const { task, profile } = item;
17
- const lines = [];
18
- // Line 1: Task name (ID: xxx)
19
- lines.push(chalk.bold.white(`Task: ${task.name}`) + chalk.gray(` (${task.id})`));
20
- // Line 2: Profile info
21
- const profileParts = [chalk.cyan(profile.name)];
22
- if (profile.port)
23
- profileParts.push(`port ${profile.port}`);
24
- if (profile.pid)
25
- profileParts.push(`pid ${profile.pid}`);
26
- lines.push(chalk.gray('Profile: ') + profileParts.join(DOT));
27
- // Line 3: Timing
28
- const started = formatAge(task.createdAt);
29
- const duration = humanDuration(Date.now() - task.createdAt);
30
- lines.push(chalk.gray('Started: ') + chalk.white(started) + DOT + chalk.gray('Duration: ') + chalk.white(duration));
31
- // Blank line
32
- lines.push('');
33
- // Tabs section
34
- if (task.tabs && task.tabs.length > 0) {
35
- lines.push(chalk.gray('Tabs:'));
36
- const termWidth = process.stdout.columns || 80;
37
- const urlMax = Math.max(30, termWidth - 16);
38
- for (const tab of task.tabs) {
39
- const marker = tab.current ? chalk.yellow('*') : ' ';
40
- const id = chalk.gray(tab.id);
41
- const url = truncate(tab.url, urlMax);
42
- lines.push(` ${id} ${marker} ${chalk.white(url)}`);
43
- }
44
- }
45
- else {
46
- lines.push(chalk.gray('No tabs open'));
47
- }
48
- return lines.join('\n');
49
- }
50
- /** Build the list label for a browser task. */
51
- function buildBrowserLabel(item, query) {
52
- const { task, profile } = item;
53
- const termWidth = process.stdout.columns || 80;
54
- // Format: name profile tabs domains age
55
- const name = task.name.padEnd(20);
56
- const profileName = profile.name.padEnd(12);
57
- const tabs = `${task.tabCount} tab${task.tabCount === 1 ? '' : 's'}`.padEnd(8);
58
- const age = formatAge(task.createdAt);
59
- // Domains - fill remaining space
60
- const fixedWidth = 20 + 12 + 8 + 10; // name + profile + tabs + age
61
- const domainsWidth = Math.max(10, termWidth - fixedWidth - 4);
62
- const domains = task.domains?.length
63
- ? truncate(task.domains.join(', '), domainsWidth)
64
- : chalk.gray('no sites');
65
- // Highlight query matches
66
- let label = `${name}${chalk.cyan(profileName)}${tabs}${domains.padEnd(domainsWidth)}${chalk.gray(age)}`;
67
- if (query) {
68
- const re = new RegExp(`(${query.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')})`, 'gi');
69
- label = label.replace(re, chalk.yellow.bold('$1'));
70
- }
71
- return label;
72
- }
73
- /** Show an interactive browser task picker. */
74
- export async function browserTaskPicker(config) {
75
- const picked = await itemPicker({
76
- message: config.message,
77
- items: config.tasks,
78
- filter: (query) => {
79
- if (!query)
80
- return config.tasks;
81
- const q = query.toLowerCase();
82
- return config.tasks.filter((t) => t.task.name.toLowerCase().includes(q) ||
83
- t.profile.name.toLowerCase().includes(q) ||
84
- t.task.domains?.some((d) => d.toLowerCase().includes(q)));
85
- },
86
- labelFor: buildBrowserLabel,
87
- buildPreview: buildBrowserPreview,
88
- shortIdFor: (t) => t.task.name,
89
- pageSize: config.pageSize ?? 10,
90
- initialSearch: config.initialSearch,
91
- emptyMessage: 'No browser tasks running.',
92
- enterHint: 'view tabs',
93
- });
94
- if (!picked)
95
- return null;
96
- return { task: picked.item, action: 'view' };
97
- }
@@ -1,52 +0,0 @@
1
- interface ArcSpace {
2
- /** Stable UUID used for every native operation. */
3
- id: string;
4
- /** Display-only title; empty when the Space is untitled. Never part of identity. */
5
- title: string;
6
- }
7
- interface ArcProfile {
8
- /** Arc's profile directory basename: the stable profile identity. */
9
- profileId: string;
10
- /** Display-only profile name from Local State. */
11
- displayName: string;
12
- spaces: ArcSpace[];
13
- }
14
- type ArcDiscoveryResult = {
15
- ok: true;
16
- profiles: ArcProfile[];
17
- userDataDir: string;
18
- } | {
19
- ok: false;
20
- kind: 'unsupported' | 'not-installed' | 'invalid';
21
- reason: string;
22
- };
23
- interface SidebarSpace {
24
- id: string;
25
- title: string;
26
- profileId: string;
27
- }
28
- export declare function parseLocalStateProfiles(localStatePath: string): Map<string, string> | {
29
- error: string;
30
- };
31
- export declare function parseSidebarSpaces(sidebarPath: string): SidebarSpace[] | {
32
- error: string;
33
- };
34
- export declare function discoverArcProfilesAt(arcDir: string): ArcDiscoveryResult;
35
- export declare function discoverArcProfiles(): ArcDiscoveryResult;
36
- /** One Arc Space, flattened with the Arc profile it belongs to. */
37
- interface ArcSpaceProfile {
38
- /** The agents-cli profile name: `arc-<space-title-slug>`. */
39
- name: string;
40
- profileId: string;
41
- profileName: string;
42
- spaceId: string;
43
- spaceTitle: string;
44
- }
45
- /**
46
- * Flatten discovery into one agents-cli profile per Space (the concept agents
47
- * already know), named `arc-<space-title>`. Two Spaces with the same title get
48
- * the first six characters of their stable Space id appended, so the names
49
- * stay distinct without inventing a second selector.
50
- */
51
- export declare function arcSpaceProfiles(result: ArcDiscoveryResult): ArcSpaceProfile[];
52
- export {};
@@ -1,197 +0,0 @@
1
- /** Read-only Arc profile/Space discovery from Arc's native metadata. */
2
- import * as fs from 'node:fs';
3
- import * as os from 'node:os';
4
- import * as path from 'node:path';
5
- function isRecord(value) {
6
- return !!value && typeof value === 'object' && !Array.isArray(value);
7
- }
8
- /**
9
- * Arc's application-support root on this Mac. Arc keeps its Chromium `Local
10
- * State` under `<root>/User Data/` and its own sidebar model (Spaces and their
11
- * profile bindings) at `<root>/StorableSidebar.json` — two different levels,
12
- * so discovery is rooted here rather than at the Chromium user-data dir.
13
- * `AGENTS_ARC_DIR` points tests and non-default installs at another root.
14
- */
15
- function arcSupportDir() {
16
- const override = process.env.AGENTS_ARC_DIR;
17
- if (override)
18
- return path.resolve(override);
19
- if (process.platform !== 'darwin')
20
- return undefined;
21
- return path.join(os.homedir(), 'Library', 'Application Support', 'Arc');
22
- }
23
- export function parseLocalStateProfiles(localStatePath) {
24
- let parsed;
25
- try {
26
- parsed = JSON.parse(fs.readFileSync(localStatePath, 'utf8'));
27
- }
28
- catch (error) {
29
- return {
30
- error: error instanceof SyntaxError
31
- ? 'Arc Local State is not valid JSON'
32
- : `Cannot read Arc Local State: ${error instanceof Error ? error.message : String(error)}`,
33
- };
34
- }
35
- if (!isRecord(parsed) || !isRecord(parsed.profile) || !isRecord(parsed.profile.info_cache)) {
36
- return { error: 'Arc Local State has no profile.info_cache map' };
37
- }
38
- const profiles = new Map();
39
- for (const [profileId, value] of Object.entries(parsed.profile.info_cache)) {
40
- if (profileId === '__ARC_SYSTEM_PROFILE')
41
- continue;
42
- if (!isRecord(value) || typeof value.name !== 'string' || value.name.trim() === '') {
43
- return { error: `Arc Local State profile ${JSON.stringify(profileId)} has no non-empty name` };
44
- }
45
- profiles.set(profileId, value.name);
46
- }
47
- return profiles;
48
- }
49
- function parseProfileId(value, spaceId) {
50
- if (!isRecord(value)) {
51
- return { error: `Arc Space ${JSON.stringify(spaceId)} has no profile mapping` };
52
- }
53
- if (value.default === true && value.custom === undefined)
54
- return 'Default';
55
- if (!isRecord(value.custom)) {
56
- return { error: `Arc Space ${JSON.stringify(spaceId)} has an unknown profile mapping` };
57
- }
58
- const entries = Object.values(value.custom);
59
- if (entries.length !== 1 || !isRecord(entries[0])) {
60
- return { error: `Arc Space ${JSON.stringify(spaceId)} has an ambiguous custom profile mapping` };
61
- }
62
- const profileId = entries[0].directoryBasename;
63
- if (typeof profileId !== 'string' || profileId.trim() === '') {
64
- return { error: `Arc Space ${JSON.stringify(spaceId)} has no custom profile id` };
65
- }
66
- return profileId;
67
- }
68
- function parseTitle(value, spaceId) {
69
- if (value === undefined || value === null)
70
- return '';
71
- if (typeof value === 'string')
72
- return value;
73
- return { error: `Arc Space ${JSON.stringify(spaceId)} has a non-text title` };
74
- }
75
- export function parseSidebarSpaces(sidebarPath) {
76
- let parsed;
77
- try {
78
- parsed = JSON.parse(fs.readFileSync(sidebarPath, 'utf8'));
79
- }
80
- catch (error) {
81
- return {
82
- error: error instanceof SyntaxError
83
- ? 'Arc StorableSidebar.json is not valid JSON'
84
- : `Cannot read Arc StorableSidebar.json: ${error instanceof Error ? error.message : String(error)}`,
85
- };
86
- }
87
- if (!isRecord(parsed) || parsed.version !== 1) {
88
- const version = isRecord(parsed) ? parsed.version : undefined;
89
- return { error: `Unsupported StorableSidebar version: ${String(version)}` };
90
- }
91
- if (!isRecord(parsed.sidebar) || !Array.isArray(parsed.sidebar.containers)) {
92
- return { error: 'StorableSidebar.json has no sidebar.containers array' };
93
- }
94
- const spaces = [];
95
- const ids = new Set();
96
- for (const container of parsed.sidebar.containers) {
97
- if (!isRecord(container) || container.spaces === undefined)
98
- continue;
99
- if (!Array.isArray(container.spaces) || container.spaces.length % 2 !== 0) {
100
- return { error: 'StorableSidebar.json contains a malformed alternating spaces array' };
101
- }
102
- for (let i = 0; i < container.spaces.length; i += 2) {
103
- const encodedId = container.spaces[i];
104
- const value = container.spaces[i + 1];
105
- if (typeof encodedId !== 'string' || !isRecord(value)) {
106
- return { error: `StorableSidebar.json contains a malformed Space at index ${i}` };
107
- }
108
- if (typeof value.id !== 'string' || value.id !== encodedId) {
109
- return { error: `Arc Space key ${JSON.stringify(encodedId)} does not match its stable id` };
110
- }
111
- // Identity is the stable id and the profile binding. The title is
112
- // display-only: Arc omits it for an untitled Space, which must still be
113
- // listed (as `arc-space`) instead of taking every other Space down.
114
- const title = parseTitle(value.title, encodedId);
115
- if (typeof title !== 'string')
116
- return title;
117
- if (ids.has(encodedId)) {
118
- return { error: `Arc Space ${JSON.stringify(encodedId)} appears more than once` };
119
- }
120
- const profileId = parseProfileId(value.profile, encodedId);
121
- if (typeof profileId !== 'string')
122
- return profileId;
123
- ids.add(encodedId);
124
- spaces.push({ id: encodedId, title, profileId });
125
- }
126
- }
127
- return spaces;
128
- }
129
- export function discoverArcProfilesAt(arcDir) {
130
- const userDataDir = path.join(arcDir, 'User Data');
131
- if (!fs.existsSync(userDataDir)) {
132
- return { ok: false, kind: 'not-installed', reason: `Arc user data directory not found: ${userDataDir}` };
133
- }
134
- const profileNames = parseLocalStateProfiles(path.join(userDataDir, 'Local State'));
135
- if ('error' in profileNames)
136
- return { ok: false, kind: 'invalid', reason: profileNames.error };
137
- if (profileNames.size === 0) {
138
- return { ok: false, kind: 'invalid', reason: 'No Arc profiles found in Local State' };
139
- }
140
- const spaces = parseSidebarSpaces(path.join(arcDir, 'StorableSidebar.json'));
141
- if ('error' in spaces)
142
- return { ok: false, kind: 'invalid', reason: spaces.error };
143
- const profiles = new Map();
144
- for (const [profileId, displayName] of profileNames) {
145
- profiles.set(profileId, { profileId, displayName, spaces: [] });
146
- }
147
- for (const space of spaces) {
148
- const profile = profiles.get(space.profileId);
149
- if (!profile) {
150
- return {
151
- ok: false,
152
- kind: 'invalid',
153
- reason: `Arc Space ${JSON.stringify(space.id)} maps to unknown profile ${JSON.stringify(space.profileId)}`,
154
- };
155
- }
156
- profile.spaces.push({ id: space.id, title: space.title });
157
- }
158
- return { ok: true, profiles: [...profiles.values()], userDataDir };
159
- }
160
- export function discoverArcProfiles() {
161
- const arcDir = arcSupportDir();
162
- if (!arcDir) {
163
- return { ok: false, kind: 'unsupported', reason: 'Arc is not supported on this platform' };
164
- }
165
- return discoverArcProfilesAt(arcDir);
166
- }
167
- function slugify(value) {
168
- return value.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '');
169
- }
170
- /**
171
- * Flatten discovery into one agents-cli profile per Space (the concept agents
172
- * already know), named `arc-<space-title>`. Two Spaces with the same title get
173
- * the first six characters of their stable Space id appended, so the names
174
- * stay distinct without inventing a second selector.
175
- */
176
- export function arcSpaceProfiles(result) {
177
- if (!result.ok)
178
- return [];
179
- const flat = [];
180
- for (const profile of result.profiles) {
181
- for (const space of profile.spaces) {
182
- flat.push({
183
- name: `arc-${slugify(space.title) || 'space'}`,
184
- profileId: profile.profileId,
185
- profileName: profile.displayName,
186
- spaceId: space.id,
187
- spaceTitle: space.title,
188
- });
189
- }
190
- }
191
- const counts = new Map();
192
- for (const entry of flat)
193
- counts.set(entry.name, (counts.get(entry.name) ?? 0) + 1);
194
- return flat.map((entry) => (counts.get(entry.name) ?? 0) > 1
195
- ? { ...entry, name: `${entry.name}-${slugify(entry.spaceId).slice(0, 6)}` }
196
- : entry);
197
- }
@@ -1,14 +0,0 @@
1
- import type { RefNode, RefOpts } from './refs.js';
2
- /** Build one synchronous expression that reads DOM-backed refs from native Arc. */
3
- export declare function arcRefsExpression(opts?: RefOpts): string;
4
- export declare function parseArcRefsResult(value: unknown, opts?: RefOpts): {
5
- refs: string;
6
- nodeMap: Map<number, RefNode>;
7
- opts: {
8
- interactive: boolean;
9
- limit: number;
10
- };
11
- };
12
- export declare function arcClickExpression(selector: string): string;
13
- export declare function arcFillExpression(selector: string, text: string, clear?: boolean): string;
14
- export declare function arcScrollExpression(deltaX: number, deltaY: number): string;
@@ -1,121 +0,0 @@
1
- import { truncate } from '../format.js';
2
- const INTERACTIVE_SELECTOR = [
3
- 'a[href]', 'button', 'input', 'select', 'textarea', '[contenteditable="true"]',
4
- '[role="button"]', '[role="link"]', '[role="textbox"]', '[role="checkbox"]',
5
- '[role="radio"]', '[role="combobox"]', '[role="listbox"]', '[role="option"]',
6
- '[role="menuitem"]', '[role="tab"]', '[role="slider"]', '[role="spinbutton"]',
7
- '[role="searchbox"]', '[role="switch"]', '[role="treeitem"]',
8
- ].join(',');
9
- /** Build one synchronous expression that reads DOM-backed refs from native Arc. */
10
- export function arcRefsExpression(opts = {}) {
11
- const interactive = opts.interactive ?? true;
12
- const limit = opts.limit ?? 500;
13
- return `(() => {
14
- const selectorFor = (el) => {
15
- if (el.id) return '#' + CSS.escape(el.id);
16
- const parts = [];
17
- for (let node = el; node && node.nodeType === 1 && node !== document.documentElement; node = node.parentElement) {
18
- let part = node.localName;
19
- if (!part) return '';
20
- const siblings = node.parentElement ? Array.from(node.parentElement.children).filter((s) => s.localName === node.localName) : [];
21
- if (siblings.length > 1) part += ':nth-of-type(' + (siblings.indexOf(node) + 1) + ')';
22
- parts.unshift(part);
23
- }
24
- return parts.join(' > ');
25
- };
26
- const roleFor = (el) => {
27
- const explicit = el.getAttribute('role');
28
- if (explicit) return explicit.toLowerCase();
29
- if (el.matches('button')) return 'button';
30
- if (el.matches('a[href]')) return 'link';
31
- if (el.matches('textarea,[contenteditable="true"]')) return 'textbox';
32
- if (el.matches('select')) return 'combobox';
33
- if (el.matches('input')) {
34
- const type = (el.getAttribute('type') || 'text').toLowerCase();
35
- if (type === 'checkbox') return 'checkbox';
36
- if (type === 'radio') return 'radio';
37
- if (type === 'range') return 'slider';
38
- if (type === 'number') return 'spinbutton';
39
- return 'textbox';
40
- }
41
- return el.localName || 'generic';
42
- };
43
- const nameFor = (el) => el.getAttribute('aria-label') || el.getAttribute('title') ||
44
- (el.labels && el.labels[0] && el.labels[0].innerText) || el.innerText || el.value || el.getAttribute('placeholder') || '';
45
- const attrsFor = (el) => ['disabled','checked','selected','expanded','required','readonly','invalid']
46
- .filter((name) => el[name] === true || el.getAttribute('aria-' + name) === 'true');
47
- const editorFor = (el) => {
48
- for (let node = el, i = 0; node && i < 6; node = node.parentElement, i++) {
49
- if (node.hasAttribute('data-lexical-editor')) return 'lexical';
50
- if (node.classList.contains('ProseMirror')) return 'prosemirror';
51
- if (node.hasAttribute('data-slate-editor')) return 'slate';
52
- if (Array.from(node.classList).some((c) => /^DraftEditor-/.test(c))) return 'draft';
53
- if (node.classList.contains('ql-editor')) return 'quill';
54
- if (node.classList.contains('ck-editor__editable')) return 'ckeditor5';
55
- if (node.tagName === 'TRIX-EDITOR') return 'trix';
56
- }
57
- return undefined;
58
- };
59
- const source = ${interactive ? `document.querySelectorAll(${JSON.stringify(INTERACTIVE_SELECTOR)})` : `document.querySelectorAll('body *')`};
60
- const rows = [];
61
- for (const el of source) {
62
- if (rows.length >= ${JSON.stringify(limit)}) break;
63
- const selector = selectorFor(el);
64
- if (!selector) continue;
65
- const row = { role: roleFor(el), name: String(nameFor(el)).trim(), attrs: attrsFor(el), selector };
66
- const editor = editorFor(el);
67
- if (editor) row.editor = editor;
68
- rows.push(row);
69
- }
70
- return JSON.stringify(rows);
71
- })()`;
72
- }
73
- export function parseArcRefsResult(value, opts = {}) {
74
- const parsed = typeof value === 'string' ? JSON.parse(value) : value;
75
- if (!Array.isArray(parsed))
76
- throw new Error('Arc returned an invalid DOM ref listing.');
77
- const nodeMap = new Map();
78
- const lines = [];
79
- const compact = opts.compact ?? false;
80
- parsed.forEach((raw, index) => {
81
- const row = raw;
82
- if (typeof row.role !== 'string' || typeof row.name !== 'string' ||
83
- typeof row.selector !== 'string' || !Array.isArray(row.attrs) ||
84
- !row.attrs.every((attr) => typeof attr === 'string')) {
85
- throw new Error('Arc returned an invalid DOM ref entry.');
86
- }
87
- const ref = index + 1;
88
- const node = { ref, role: row.role, name: row.name, attrs: row.attrs, selector: row.selector };
89
- if (typeof row.editor === 'string')
90
- node.editor = row.editor;
91
- nodeMap.set(ref, node);
92
- const name = row.name ? ` "${truncate(row.name, 50)}"` : '';
93
- const attrs = row.attrs.length ? ` [${row.attrs.join('] [')}]` : '';
94
- const editor = row.editor ? ` [editor=${row.editor}]` : '';
95
- lines.push(`${compact ? '' : '- '}${row.role}${name} [ref=${ref}]${attrs}${editor}`);
96
- });
97
- return { refs: lines.join('\n'), nodeMap, opts: { interactive: opts.interactive ?? true, limit: opts.limit ?? 500 } };
98
- }
99
- export function arcClickExpression(selector) {
100
- return `(() => { const el = document.querySelector(${JSON.stringify(selector)}); if (!el) throw new Error('DOM ref is missing'); el.click(); return true; })()`;
101
- }
102
- export function arcFillExpression(selector, text, clear = true) {
103
- return `(() => {
104
- const el = document.querySelector(${JSON.stringify(selector)});
105
- if (!el) throw new Error('DOM ref is missing');
106
- const next = ${JSON.stringify(text)};
107
- if (el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement) {
108
- const proto = el instanceof HTMLInputElement ? HTMLInputElement.prototype : HTMLTextAreaElement.prototype;
109
- const setter = Object.getOwnPropertyDescriptor(proto, 'value').set;
110
- setter.call(el, ${clear ? 'next' : 'el.value + next'});
111
- } else if (el.isContentEditable) {
112
- el.textContent = ${clear ? 'next' : '(el.textContent || "") + next'};
113
- } else throw new Error('DOM ref is not editable');
114
- el.dispatchEvent(new InputEvent('input', { bubbles: true, inputType: 'insertText', data: next }));
115
- el.dispatchEvent(new Event('change', { bubbles: true }));
116
- return true;
117
- })()`;
118
- }
119
- export function arcScrollExpression(deltaX, deltaY) {
120
- return `(() => { window.scrollBy(${JSON.stringify(deltaX)}, ${JSON.stringify(deltaY)}); return true; })()`;
121
- }
@@ -1,40 +0,0 @@
1
- export interface CallerIdentity {
2
- actor: string;
3
- launchId?: string;
4
- sessionId?: string;
5
- /** Agent pid when identity came from the process-table anchor. */
6
- agentPid?: number;
7
- }
8
- /**
9
- * Resolve caller identity once per CLI process for browser IPC stamping.
10
- *
11
- * Starts from `process.ppid` — the shell or harness that launched this
12
- * `agents browser` invocation — and walks up until a state file or known
13
- * agent comm is found.
14
- */
15
- export declare function resolveCallerIdentity(env?: NodeJS.ProcessEnv): CallerIdentity;
16
- /**
17
- * The env a `browser --device` dispatch forwards so the HUB resolves the SAME
18
- * caller identity the worker would stamp locally. Without it a forwarded verb
19
- * lands on the hub with BLANK identity, and the daemon's no-identity task bucket
20
- * matches any other no-identity task — so a cold verb could attach to (or a
21
- * `done`/`stop` could close) an unrelated agent's or a human's browser. This is
22
- * the same surface-parity fix the `run --device` path already carries via
23
- * `--env AGENT_LAUNCH_ID` (remote-session-id.ts). Absent fields are omitted so a
24
- * genuinely-unidentifiable caller forwards nothing rather than an empty string
25
- * that would read as a real (blank) identity on the far side.
26
- */
27
- export declare function callerIdentityEnv(caller: Pick<CallerIdentity, 'sessionId' | 'launchId'>): Record<string, string>;
28
- /**
29
- * True when a live task belongs to this caller. Match on sessionId or
30
- * launchId — either is enough. A task with no recorded identity never
31
- * matches a caller that has one (and vice versa for the no-identity case
32
- * handled separately by the resolver).
33
- */
34
- export declare function taskMatchesCaller(task: {
35
- sessionId?: string;
36
- launchId?: string;
37
- }, caller: {
38
- sessionId?: string;
39
- launchId?: string;
40
- }): boolean;