@phnx-labs/agents-cli 1.20.34 → 1.20.36

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 (291) hide show
  1. package/CHANGELOG.md +113 -0
  2. package/LICENSE +185 -21
  3. package/README.md +13 -5
  4. package/dist/commands/audit.d.ts +14 -0
  5. package/dist/commands/audit.js +68 -0
  6. package/dist/commands/browser.js +82 -8
  7. package/dist/commands/check.d.ts +15 -0
  8. package/dist/commands/check.js +84 -0
  9. package/dist/commands/cloud.js +143 -3
  10. package/dist/commands/computer-actions.d.ts +15 -0
  11. package/dist/commands/computer-actions.js +120 -22
  12. package/dist/commands/computer.js +81 -0
  13. package/dist/commands/cost.js +17 -12
  14. package/dist/commands/daemon.js +4 -1
  15. package/dist/commands/doctor.d.ts +1 -0
  16. package/dist/commands/doctor.js +54 -97
  17. package/dist/commands/events.d.ts +16 -0
  18. package/dist/commands/events.js +173 -0
  19. package/dist/commands/exec.d.ts +19 -0
  20. package/dist/commands/exec.js +283 -12
  21. package/dist/commands/hosts.js +37 -29
  22. package/dist/commands/inspect.d.ts +2 -0
  23. package/dist/commands/inspect.js +62 -16
  24. package/dist/commands/lock.d.ts +12 -0
  25. package/dist/commands/lock.js +70 -0
  26. package/dist/commands/logs.d.ts +17 -0
  27. package/dist/commands/logs.js +139 -0
  28. package/dist/commands/message.d.ts +15 -0
  29. package/dist/commands/message.js +56 -0
  30. package/dist/commands/models.d.ts +3 -0
  31. package/dist/commands/models.js +27 -8
  32. package/dist/commands/permissions.js +9 -2
  33. package/dist/commands/repo.d.ts +34 -0
  34. package/dist/commands/repo.js +243 -65
  35. package/dist/commands/resource-view.d.ts +20 -0
  36. package/dist/commands/resource-view.js +90 -28
  37. package/dist/commands/routines.js +101 -5
  38. package/dist/commands/secrets-migrate.js +106 -57
  39. package/dist/commands/secrets.d.ts +31 -18
  40. package/dist/commands/secrets.js +196 -91
  41. package/dist/commands/serve.d.ts +10 -0
  42. package/dist/commands/serve.js +37 -0
  43. package/dist/commands/sessions-inject.d.ts +14 -0
  44. package/dist/commands/sessions-inject.js +111 -0
  45. package/dist/commands/sessions-picker.d.ts +2 -0
  46. package/dist/commands/sessions-picker.js +24 -3
  47. package/dist/commands/sessions-resume.d.ts +2 -0
  48. package/dist/commands/sessions-resume.js +221 -0
  49. package/dist/commands/sessions-tail.d.ts +10 -0
  50. package/dist/commands/sessions-tail.js +11 -0
  51. package/dist/commands/sessions.d.ts +143 -1
  52. package/dist/commands/sessions.js +628 -80
  53. package/dist/commands/setup.js +4 -2
  54. package/dist/commands/sync.d.ts +3 -1
  55. package/dist/commands/sync.js +156 -4
  56. package/dist/commands/teams.js +217 -0
  57. package/dist/commands/versions.js +2 -4
  58. package/dist/commands/view.d.ts +3 -0
  59. package/dist/commands/view.js +19 -8
  60. package/dist/commands/wallet.d.ts +6 -0
  61. package/dist/commands/wallet.js +22 -5
  62. package/dist/commands/watchdog.d.ts +18 -0
  63. package/dist/commands/watchdog.js +238 -0
  64. package/dist/index.js +82 -32
  65. package/dist/lib/agents.js +30 -9
  66. package/dist/lib/audit/log.d.ts +92 -0
  67. package/dist/lib/audit/log.js +177 -0
  68. package/dist/lib/auto-pull.js +2 -1
  69. package/dist/lib/browser/cdp.js +5 -1
  70. package/dist/lib/browser/chrome.d.ts +10 -0
  71. package/dist/lib/browser/chrome.js +18 -7
  72. package/dist/lib/browser/drivers/ssh.d.ts +8 -0
  73. package/dist/lib/browser/drivers/ssh.js +77 -16
  74. package/dist/lib/browser/har.d.ts +84 -0
  75. package/dist/lib/browser/har.js +77 -0
  76. package/dist/lib/browser/ipc.d.ts +3 -0
  77. package/dist/lib/browser/ipc.js +37 -12
  78. package/dist/lib/browser/profiles.d.ts +1 -1
  79. package/dist/lib/browser/profiles.js +8 -10
  80. package/dist/lib/browser/refs.d.ts +65 -0
  81. package/dist/lib/browser/refs.js +73 -1
  82. package/dist/lib/browser/runtime-state.js +1 -0
  83. package/dist/lib/browser/service.d.ts +38 -2
  84. package/dist/lib/browser/service.js +183 -23
  85. package/dist/lib/browser/types.d.ts +14 -1
  86. package/dist/lib/budget/live-cloud.d.ts +42 -0
  87. package/dist/lib/budget/live-cloud.js +79 -0
  88. package/dist/lib/budget/live-team.d.ts +31 -0
  89. package/dist/lib/budget/live-team.js +115 -0
  90. package/dist/lib/cloud/codex.js +4 -0
  91. package/dist/lib/cloud/rush.d.ts +12 -1
  92. package/dist/lib/cloud/rush.js +13 -3
  93. package/dist/lib/cloud/types.d.ts +9 -0
  94. package/dist/lib/computer/dispatch.d.ts +8 -0
  95. package/dist/lib/computer/dispatch.js +125 -0
  96. package/dist/lib/computer/loop.d.ts +62 -0
  97. package/dist/lib/computer/loop.js +98 -0
  98. package/dist/lib/computer/model.d.ts +44 -0
  99. package/dist/lib/computer/model.js +157 -0
  100. package/dist/lib/concurrency.d.ts +19 -0
  101. package/dist/lib/concurrency.js +33 -0
  102. package/dist/lib/daemon.d.ts +92 -0
  103. package/dist/lib/daemon.js +222 -18
  104. package/dist/lib/devices/connect.d.ts +3 -2
  105. package/dist/lib/devices/connect.js +5 -3
  106. package/dist/lib/devices/registry.d.ts +7 -0
  107. package/dist/lib/devices/registry.js +24 -0
  108. package/dist/lib/devices/tailscale.js +1 -1
  109. package/dist/lib/drift.d.ts +52 -0
  110. package/dist/lib/drift.js +112 -0
  111. package/dist/lib/events.d.ts +10 -3
  112. package/dist/lib/events.js +101 -24
  113. package/dist/lib/exec.d.ts +17 -0
  114. package/dist/lib/exec.js +100 -12
  115. package/dist/lib/git.d.ts +27 -0
  116. package/dist/lib/git.js +56 -1
  117. package/dist/lib/hooks/cache.d.ts +6 -0
  118. package/dist/lib/hooks/cache.js +54 -12
  119. package/dist/lib/hooks.d.ts +27 -0
  120. package/dist/lib/hooks.js +135 -10
  121. package/dist/lib/hosts/dispatch.d.ts +15 -0
  122. package/dist/lib/hosts/dispatch.js +45 -13
  123. package/dist/lib/hosts/logs.d.ts +16 -0
  124. package/dist/lib/hosts/logs.js +74 -0
  125. package/dist/lib/hosts/option.js +1 -1
  126. package/dist/lib/hosts/passthrough.js +3 -1
  127. package/dist/lib/hosts/progress.d.ts +66 -0
  128. package/dist/lib/hosts/progress.js +125 -17
  129. package/dist/lib/hosts/ready.d.ts +51 -7
  130. package/dist/lib/hosts/ready.js +98 -25
  131. package/dist/lib/hosts/reconcile.d.ts +53 -0
  132. package/dist/lib/hosts/reconcile.js +81 -0
  133. package/dist/lib/hosts/registry.d.ts +19 -2
  134. package/dist/lib/hosts/registry.js +58 -2
  135. package/dist/lib/hosts/remote-cmd.d.ts +62 -1
  136. package/dist/lib/hosts/remote-cmd.js +70 -1
  137. package/dist/lib/hosts/remote-os.d.ts +17 -0
  138. package/dist/lib/hosts/remote-os.js +30 -0
  139. package/dist/lib/hosts/session-index.d.ts +34 -0
  140. package/dist/lib/hosts/session-index.js +56 -0
  141. package/dist/lib/hosts/tasks.d.ts +22 -0
  142. package/dist/lib/hosts/tasks.js +29 -0
  143. package/dist/lib/lock.d.ts +93 -0
  144. package/dist/lib/lock.js +207 -0
  145. package/dist/lib/loop.js +16 -1
  146. package/dist/lib/machine-id.d.ts +21 -0
  147. package/dist/lib/machine-id.js +26 -0
  148. package/dist/lib/mailbox-target.d.ts +36 -0
  149. package/dist/lib/mailbox-target.js +45 -0
  150. package/dist/lib/mailbox.d.ts +47 -0
  151. package/dist/lib/mailbox.js +194 -0
  152. package/dist/lib/mcp.d.ts +5 -0
  153. package/dist/lib/mcp.js +24 -8
  154. package/dist/lib/migrate.d.ts +19 -0
  155. package/dist/lib/migrate.js +134 -26
  156. package/dist/lib/overdue.js +3 -0
  157. package/dist/lib/permissions.d.ts +4 -0
  158. package/dist/lib/permissions.js +35 -0
  159. package/dist/lib/picker.d.ts +26 -0
  160. package/dist/lib/picker.js +127 -0
  161. package/dist/lib/platform/exec.d.ts +46 -0
  162. package/dist/lib/platform/exec.js +74 -0
  163. package/dist/lib/platform/process.d.ts +31 -0
  164. package/dist/lib/platform/process.js +34 -1
  165. package/dist/lib/platform/winpath.js +2 -0
  166. package/dist/lib/plugin-marketplace.d.ts +30 -0
  167. package/dist/lib/plugin-marketplace.js +215 -2
  168. package/dist/lib/plugins.d.ts +5 -0
  169. package/dist/lib/plugins.js +61 -10
  170. package/dist/lib/profiles.d.ts +25 -0
  171. package/dist/lib/profiles.js +22 -6
  172. package/dist/lib/pty-client.js +2 -1
  173. package/dist/lib/rotate.d.ts +61 -0
  174. package/dist/lib/rotate.js +52 -0
  175. package/dist/lib/routines.d.ts +40 -2
  176. package/dist/lib/routines.js +66 -8
  177. package/dist/lib/runner.d.ts +11 -2
  178. package/dist/lib/runner.js +49 -7
  179. package/dist/lib/scheduler.js +6 -1
  180. package/dist/lib/secrets/bundles.d.ts +60 -4
  181. package/dist/lib/secrets/bundles.js +131 -12
  182. package/dist/lib/secrets/filestore.d.ts +3 -0
  183. package/dist/lib/secrets/filestore.js +42 -16
  184. package/dist/lib/secrets/index.d.ts +43 -2
  185. package/dist/lib/secrets/index.js +102 -3
  186. package/dist/lib/secrets/mcp.d.ts +93 -0
  187. package/dist/lib/secrets/mcp.js +205 -0
  188. package/dist/lib/secrets/remote.js +12 -5
  189. package/dist/lib/secrets/sync.js +83 -4
  190. package/dist/lib/secrets/windows.js +14 -3
  191. package/dist/lib/serve/data.d.ts +81 -0
  192. package/dist/lib/serve/data.js +91 -0
  193. package/dist/lib/serve/page.d.ts +7 -0
  194. package/dist/lib/serve/page.js +140 -0
  195. package/dist/lib/serve/server.d.ts +46 -0
  196. package/dist/lib/serve/server.js +115 -0
  197. package/dist/lib/session/active.d.ts +61 -0
  198. package/dist/lib/session/active.js +196 -17
  199. package/dist/lib/session/discover.d.ts +37 -0
  200. package/dist/lib/session/discover.js +204 -27
  201. package/dist/lib/session/inject.d.ts +18 -0
  202. package/dist/lib/session/inject.js +21 -0
  203. package/dist/lib/session/parse.d.ts +6 -0
  204. package/dist/lib/session/parse.js +286 -2
  205. package/dist/lib/session/pid-registry.d.ts +22 -0
  206. package/dist/lib/session/pid-registry.js +104 -0
  207. package/dist/lib/session/provenance.d.ts +14 -2
  208. package/dist/lib/session/provenance.js +39 -8
  209. package/dist/lib/session/remote-active.d.ts +26 -0
  210. package/dist/lib/session/remote-active.js +153 -0
  211. package/dist/lib/session/remote-list.d.ts +51 -0
  212. package/dist/lib/session/remote-list.js +213 -0
  213. package/dist/lib/session/remote.d.ts +7 -1
  214. package/dist/lib/session/remote.js +18 -8
  215. package/dist/lib/session/render.js +1 -1
  216. package/dist/lib/session/sync/config.d.ts +1 -7
  217. package/dist/lib/session/sync/config.js +4 -11
  218. package/dist/lib/session/types.d.ts +18 -1
  219. package/dist/lib/session/types.js +1 -1
  220. package/dist/lib/shims.d.ts +44 -6
  221. package/dist/lib/shims.js +143 -57
  222. package/dist/lib/ssh-exec.d.ts +26 -3
  223. package/dist/lib/ssh-exec.js +47 -3
  224. package/dist/lib/ssh-tunnel.d.ts +24 -5
  225. package/dist/lib/ssh-tunnel.js +62 -63
  226. package/dist/lib/staleness/writers/hooks.js +1 -1
  227. package/dist/lib/startup/command-registry.d.ts +8 -0
  228. package/dist/lib/startup/command-registry.js +17 -1
  229. package/dist/lib/state.d.ts +13 -0
  230. package/dist/lib/state.js +103 -9
  231. package/dist/lib/sync-umbrella.d.ts +14 -7
  232. package/dist/lib/sync-umbrella.js +17 -9
  233. package/dist/lib/teams/forEach.d.ts +110 -0
  234. package/dist/lib/teams/forEach.js +186 -0
  235. package/dist/lib/teams/index.d.ts +1 -0
  236. package/dist/lib/teams/index.js +1 -0
  237. package/dist/lib/teams/pr-watch.d.ts +226 -0
  238. package/dist/lib/teams/pr-watch.js +371 -0
  239. package/dist/lib/teams/registry.js +25 -9
  240. package/dist/lib/teams/supervisor.d.ts +14 -1
  241. package/dist/lib/teams/supervisor.js +19 -0
  242. package/dist/lib/teams/worktree.d.ts +9 -0
  243. package/dist/lib/teams/worktree.js +32 -0
  244. package/dist/lib/terminal/backends/ghostty.d.ts +6 -0
  245. package/dist/lib/terminal/backends/ghostty.js +69 -0
  246. package/dist/lib/terminal/backends/index.d.ts +19 -0
  247. package/dist/lib/terminal/backends/index.js +31 -0
  248. package/dist/lib/terminal/backends/iterm.d.ts +6 -0
  249. package/dist/lib/terminal/backends/iterm.js +62 -0
  250. package/dist/lib/terminal/backends/tmux.d.ts +14 -0
  251. package/dist/lib/terminal/backends/tmux.js +23 -0
  252. package/dist/lib/terminal/backends/vscodium-agent.d.ts +31 -0
  253. package/dist/lib/terminal/backends/vscodium-agent.js +72 -0
  254. package/dist/lib/terminal/engine.d.ts +39 -0
  255. package/dist/lib/terminal/engine.js +54 -0
  256. package/dist/lib/terminal/index.d.ts +17 -0
  257. package/dist/lib/terminal/index.js +8 -0
  258. package/dist/lib/terminal/inject.d.ts +204 -0
  259. package/dist/lib/terminal/inject.js +247 -0
  260. package/dist/lib/terminal/policy.d.ts +11 -0
  261. package/dist/lib/terminal/policy.js +11 -0
  262. package/dist/lib/terminal/quote.d.ts +11 -0
  263. package/dist/lib/terminal/quote.js +13 -0
  264. package/dist/lib/terminal/resolve.d.ts +64 -0
  265. package/dist/lib/terminal/resolve.js +90 -0
  266. package/dist/lib/terminal/shell.d.ts +6 -0
  267. package/dist/lib/terminal/shell.js +23 -0
  268. package/dist/lib/terminal/transport.d.ts +15 -0
  269. package/dist/lib/terminal/transport.js +40 -0
  270. package/dist/lib/terminal/types.d.ts +59 -0
  271. package/dist/lib/terminal/types.js +13 -0
  272. package/dist/lib/triggers/webhook.d.ts +85 -0
  273. package/dist/lib/triggers/webhook.js +141 -0
  274. package/dist/lib/types.d.ts +7 -0
  275. package/dist/lib/versions.d.ts +30 -3
  276. package/dist/lib/versions.js +129 -18
  277. package/dist/lib/watchdog/index.d.ts +3 -0
  278. package/dist/lib/watchdog/index.js +5 -0
  279. package/dist/lib/watchdog/read.d.ts +35 -0
  280. package/dist/lib/watchdog/read.js +149 -0
  281. package/dist/lib/watchdog/runner.d.ts +127 -0
  282. package/dist/lib/watchdog/runner.js +322 -0
  283. package/dist/lib/watchdog/watchdog.d.ts +40 -0
  284. package/dist/lib/watchdog/watchdog.js +166 -0
  285. package/dist/lib/watchdog/watchdogTail.d.ts +5 -0
  286. package/dist/lib/watchdog/watchdogTail.js +154 -0
  287. package/dist/lib/whats-new.d.ts +9 -0
  288. package/dist/lib/whats-new.js +35 -0
  289. package/dist/lib/workflows.d.ts +166 -0
  290. package/dist/lib/workflows.js +193 -0
  291. package/package.json +5 -4
@@ -4,106 +4,50 @@ import { checkAllClis } from '../lib/teams/agents.js';
4
4
  import { AGENTS, ALL_AGENT_IDS, resolveAgentName, formatAgentError } from '../lib/agents.js';
5
5
  import { getGlobalDefault, getVersionHomePath, isVersionInstalled, listInstalledVersions, parseAgentSpec, } from '../lib/versions.js';
6
6
  import { loadManifest, isStale } from '../lib/staleness/index.js';
7
- import { diffVersionCommands, iterCommandsCapableVersions } from '../lib/commands.js';
8
- import { diffVersionSkills, iterSkillsCapableVersions } from '../lib/skills.js';
9
- import { iterHooksCapableVersions, listUnmanagedHooksInVersionHome } from '../lib/hooks.js';
10
7
  import { diffVersionResources, DOCTOR_ALL_KINDS, } from '../lib/doctor-diff.js';
8
+ import { checkSyncStatus, countOrphans } from '../lib/drift.js';
11
9
  import { unifiedDiff, colorizeUnifiedDiff } from '../lib/diff-text.js';
12
10
  import { listCliStatus } from '../lib/cli-resources.js';
13
11
  import { setHelpSections } from '../lib/help.js';
14
12
  import { heal, healChangedAnything } from '../lib/heal.js';
15
13
  import { blocksLocalScripts, getEffectiveExecutionPolicy } from '../lib/platform/winpath.js';
14
+ import { terminalWidth, truncateToWidth, stringWidth, padToWidth } from '../lib/session/width.js';
16
15
  import * as fs from 'fs';
17
16
  const AGENT_NAMES = Object.fromEntries(ALL_AGENT_IDS.map((id) => [id, AGENTS[id].name]));
18
17
  // ─── overview mode (no target) ────────────────────────────────────────────────
19
- // Lines naming exactly what's out of sync for a version, plugins prioritized:
20
- // each divergent plugin gets its own line with specifics (stale mirror version,
21
- // invalid manifest, or the bundled skills/commands missing from the mirror —
22
- // the system-repo plugin content that matters most). Other kinds collapse to
23
- // compact counts so the readout stays scannable.
24
- function divergenceLines(report) {
25
- const lines = [];
26
- for (const p of report.kinds.plugins) {
27
- if (p.status === 'missing')
28
- lines.push(`plugin ${p.name} — not installed`);
29
- else if (p.status === 'diff')
30
- lines.push(`plugin ${p.name} — ${p.detail ?? 'mirror drifted'}`);
31
- }
32
- const counts = [];
33
- for (const kind of ['commands', 'skills', 'hooks', 'rules', 'mcp', 'permissions', 'subagents']) {
34
- const rows = report.kinds[kind];
35
- const miss = rows.filter((r) => r.status === 'missing').length;
36
- const dif = rows.filter((r) => r.status === 'diff').length;
37
- const bits = [];
38
- if (miss)
39
- bits.push(`${miss} missing`);
40
- if (dif)
41
- bits.push(`${dif} drifted`);
42
- if (bits.length)
43
- counts.push(`${kind} ${bits.join('/')}`);
44
- }
45
- if (counts.length)
46
- lines.push(counts.join(' · '));
47
- return lines;
18
+ function collapseWhitespace(s) {
19
+ return s.replace(/\s+/g, ' ').trim();
48
20
  }
49
- function checkSyncStatus(cwd) {
50
- const rows = [];
51
- // Every installed version, not just the default — a stale NON-default version
52
- // (e.g. one you launched from yesterday) is exactly the rot that silently
53
- // serves outdated/invalid resources and that `--fix` now heals. Hiding it here
54
- // is why that class of bug went unnoticed.
55
- for (const agent of ALL_AGENT_IDS) {
56
- const def = getGlobalDefault(agent);
57
- for (const version of listInstalledVersions(agent)) {
58
- const manifest = loadManifest(agent, version);
59
- const status = !manifest
60
- ? 'never-synced'
61
- : isStale(manifest, agent, version, cwd) ? 'stale' : 'fresh';
62
- const row = { agent, version, status, isDefault: version === def };
63
- if (status === 'stale') {
64
- // Resolve the specifics against non-project layers (the global home is
65
- // never reconciled against per-cwd project resources).
66
- const report = diffVersionResources(agent, version, { cwd, excludeProject: true });
67
- const lines = divergenceLines(report);
68
- if (lines.length)
69
- row.divergence = lines;
70
- }
71
- rows.push(row);
21
+ export function wrapLine(prefix, text, width = terminalWidth()) {
22
+ const words = collapseWhitespace(text).split(' ').filter(Boolean);
23
+ if (words.length === 0)
24
+ return [prefix.trimEnd()];
25
+ const continuation = ' '.repeat(stringWidth(prefix));
26
+ const lines = [];
27
+ let linePrefix = prefix;
28
+ let line = prefix;
29
+ let hasWord = false;
30
+ for (const word of words) {
31
+ const room = Math.max(1, width - stringWidth(linePrefix));
32
+ const piece = stringWidth(word) > room ? truncateToWidth(word, room) : word;
33
+ const candidate = hasWord ? `${line} ${piece}` : `${line}${piece}`;
34
+ if (hasWord && stringWidth(candidate) > width) {
35
+ lines.push(line);
36
+ linePrefix = continuation;
37
+ line = continuation + piece;
38
+ hasWord = true;
39
+ }
40
+ else {
41
+ line = candidate;
42
+ hasWord = true;
72
43
  }
73
44
  }
74
- return rows;
45
+ lines.push(line);
46
+ return lines;
75
47
  }
76
- function countOrphans() {
77
- const byKey = new Map();
78
- const ensure = (agent, version) => {
79
- const key = `${agent}@${version}`;
80
- let row = byKey.get(key);
81
- if (!row) {
82
- row = { agent, version, commands: 0, skills: 0, hooks: 0 };
83
- byKey.set(key, row);
84
- }
85
- return row;
86
- };
87
- for (const { agent, version } of iterCommandsCapableVersions()) {
88
- const diff = diffVersionCommands(agent, version);
89
- if (diff.orphans.length > 0)
90
- ensure(agent, version).commands = diff.orphans.length;
91
- }
92
- for (const { agent, version } of iterSkillsCapableVersions()) {
93
- const diff = diffVersionSkills(agent, version);
94
- if (diff.orphans.length > 0)
95
- ensure(agent, version).skills = diff.orphans.length;
96
- }
97
- // Orphan hooks are scripts in the version home that no agents.yaml/hooks.yaml
98
- // entry registers — so the registrar never wires them to an event and they
99
- // never fire. (Distinct from the source-diff `diffVersionHooks().orphans`,
100
- // which false-flags valid system-sourced registered hooks.)
101
- for (const { agent, version } of iterHooksCapableVersions()) {
102
- const dead = listUnmanagedHooksInVersionHome(agent, version);
103
- if (dead.length > 0)
104
- ensure(agent, version).hooks = dead.length;
105
- }
106
- return Array.from(byKey.values()).filter((r) => r.commands + r.skills + r.hooks > 0);
48
+ function printWrappedLine(prefix, text) {
49
+ for (const line of wrapLine(prefix, text))
50
+ console.log(chalk.gray(line));
107
51
  }
108
52
  function renderOverviewText(clis, syncRows, orphanRows, hostClis) {
109
53
  console.log(chalk.bold('Agent CLIs'));
@@ -130,7 +74,7 @@ function renderOverviewText(clis, syncRows, orphanRows, hostClis) {
130
74
  }
131
75
  }
132
76
  if (hidden.length > 0) {
133
- console.log(chalk.gray(` +${hidden.length} more supported (${hidden.join(', ')}) — \`agents add <name>\` to manage`));
77
+ printWrappedLine(' ', `+${hidden.length} more supported (${hidden.join(', ')}) — \`agents add <name>\` to manage`);
134
78
  }
135
79
  console.log();
136
80
  console.log(chalk.bold('Sync status (installed versions)'));
@@ -162,7 +106,7 @@ function renderOverviewText(clis, syncRows, orphanRows, hostClis) {
162
106
  // Version homes are reconciled only by management commands, so point at one
163
107
  // rather than promising an auto-sync that never happens.
164
108
  if (anyOutOfSync) {
165
- console.log(chalk.gray(' Reconcile with `agents doctor <agent>@<version> --fix` or `agents sync <agent>@<version>` (not applied on launch).'));
109
+ printWrappedLine(' ', 'Reconcile with `agents doctor <agent>@<version> --fix` or `agents sync <agent>@<version>` (not applied on launch).');
166
110
  }
167
111
  }
168
112
  console.log();
@@ -199,10 +143,17 @@ function renderOverviewText(clis, syncRows, orphanRows, hostClis) {
199
143
  const label = manifest.name.padEnd(nameWidth);
200
144
  const src = chalk.gray(`[${manifest.source}]`);
201
145
  if (installed) {
202
- console.log(` ${chalk.green('ready')} ${label} ${src} ${chalk.gray(manifest.description || '')}`);
146
+ const prefix = ` ${chalk.green('ready')} ${label} ${src}`;
147
+ const desc = manifest.description
148
+ ? ` ${truncateToWidth(collapseWhitespace(manifest.description), Math.max(1, terminalWidth() - stringWidth(prefix) - 2))}`
149
+ : '';
150
+ console.log(prefix + chalk.gray(desc));
203
151
  }
204
152
  else {
205
- console.log(` ${chalk.red('miss ')} ${label} ${src} ${chalk.gray(`not installed — run \`agents cli install ${manifest.name}\``)}`);
153
+ const prefix = ` ${chalk.red('miss ')} ${label} ${src}`;
154
+ const msg = `not installed — run \`agents cli install ${manifest.name}\``;
155
+ const budget = Math.max(1, terminalWidth() - stringWidth(prefix) - 2);
156
+ console.log(prefix + chalk.gray(` ${truncateToWidth(msg, budget)}`));
206
157
  }
207
158
  }
208
159
  }
@@ -357,8 +308,12 @@ function renderKindSection(kind, rows, layers, options) {
357
308
  }
358
309
  for (const r of visible) {
359
310
  const src = sourceLabel(r, layers);
360
- const detail = r.detail ? chalk.gray(` ${r.detail}`) : '';
361
- console.log(` ${statusLabel(r.status)} ${r.name.padEnd(28)} ${src}${detail}`);
311
+ const name = padToWidth(truncateToWidth(r.name, 28), 28);
312
+ const prefix = ` ${statusLabel(r.status)} ${name} ${src}`;
313
+ const detail = r.detail
314
+ ? chalk.gray(` ${truncateToWidth(collapseWhitespace(r.detail), Math.max(1, terminalWidth() - stringWidth(prefix) - 2))}`)
315
+ : '';
316
+ console.log(prefix + detail);
362
317
  if (options.showDiff && r.status === 'diff' && r.sourcePath && r.homePath) {
363
318
  const expected = readExpectedForDiff(kind, r);
364
319
  const actual = safeRead(r.homePath);
@@ -395,8 +350,10 @@ function readExpectedForDiff(kind, row) {
395
350
  function renderTargetText(report, options) {
396
351
  const label = `${AGENT_NAMES[report.agent] || report.agent}@${report.version}`;
397
352
  console.log(chalk.bold(label));
398
- console.log(chalk.gray(` home: ${report.home}`));
399
- console.log(chalk.gray(` cwd: ${report.cwd}`));
353
+ const homePrefix = ' home: ';
354
+ const cwdPrefix = ' cwd: ';
355
+ console.log(chalk.gray(homePrefix + truncateToWidth(report.home, Math.max(1, terminalWidth() - stringWidth(homePrefix)))));
356
+ console.log(chalk.gray(cwdPrefix + truncateToWidth(report.cwd, Math.max(1, terminalWidth() - stringWidth(cwdPrefix)))));
400
357
  const layerStr = [
401
358
  report.layers.project ? `project=${report.layers.project}` : null,
402
359
  `user=${report.layers.user}`,
@@ -405,7 +362,7 @@ function renderTargetText(report, options) {
405
362
  ? `extras=[${report.layers.extras.map((e) => e.alias).join(',')}]`
406
363
  : null,
407
364
  ].filter(Boolean).join(' ');
408
- console.log(chalk.gray(` layers: ${layerStr}`));
365
+ printWrappedLine(' layers: ', layerStr);
409
366
  // Staleness manifest verdict — single-line summary from the staleness
410
367
  // library, sitting alongside the detailed per-resource diff below.
411
368
  const manifest = loadManifest(report.agent, report.version);
@@ -446,7 +403,7 @@ function renderTargetText(report, options) {
446
403
  }
447
404
  else {
448
405
  console.log(` Verdict: ${verdictParts.join(', ')}.`);
449
- console.log(chalk.gray(` Run \`agents doctor ${report.agent}@${report.version} --fix\` to heal, or \`agents prune cleanup\` to drop extras.`));
406
+ printWrappedLine(' ', `Run \`agents doctor ${report.agent}@${report.version} --fix\` to heal, or \`agents prune cleanup\` to drop extras.`);
450
407
  }
451
408
  }
452
409
  // ─── fix / heal mode ───────────────────────────────────────────────────────────
@@ -0,0 +1,16 @@
1
+ /**
2
+ * `agents events` — read the structured audit/event log.
3
+ *
4
+ * The event log (`~/.agents/.cache/logs/events-YYYY-MM-DD.jsonl`) records every
5
+ * `agents <module> <cmd>` invocation plus richer typed events (secrets access,
6
+ * version installs, ...), each stamped with who ran it and from where (OS user,
7
+ * local vs SSH, remote client IP). This command reads it back — the audit trail
8
+ * for "who accessed a secret / created a team / started an agent, and from which
9
+ * host?".
10
+ *
11
+ * Filter by `--module` (top-level group, e.g. teams), `--command` (path prefix,
12
+ * e.g. "teams create"), `--event` (typed event), `--agent`, and `--since`.
13
+ * `--follow` tails today's log live.
14
+ */
15
+ import type { Command } from 'commander';
16
+ export declare function registerEventsCommand(program: Command): void;
@@ -0,0 +1,173 @@
1
+ /**
2
+ * `agents events` — read the structured audit/event log.
3
+ *
4
+ * The event log (`~/.agents/.cache/logs/events-YYYY-MM-DD.jsonl`) records every
5
+ * `agents <module> <cmd>` invocation plus richer typed events (secrets access,
6
+ * version installs, ...), each stamped with who ran it and from where (OS user,
7
+ * local vs SSH, remote client IP). This command reads it back — the audit trail
8
+ * for "who accessed a secret / created a team / started an agent, and from which
9
+ * host?".
10
+ *
11
+ * Filter by `--module` (top-level group, e.g. teams), `--command` (path prefix,
12
+ * e.g. "teams create"), `--event` (typed event), `--agent`, and `--since`.
13
+ * `--follow` tails today's log live.
14
+ */
15
+ import chalk from 'chalk';
16
+ import * as fs from 'fs';
17
+ import { query, getLogsPath } from '../lib/events.js';
18
+ /** Parse `--since`: relative offsets (30s/5m/2h/7d/4w) or an ISO/absolute date. */
19
+ function parseSince(s) {
20
+ const m = s.match(/^(\d+)([smhdw])$/);
21
+ if (m) {
22
+ const n = parseInt(m[1], 10);
23
+ const unitMs = {
24
+ s: 1000, m: 60_000, h: 3_600_000, d: 86_400_000, w: 604_800_000,
25
+ };
26
+ return new Date(Date.now() - n * unitMs[m[2]]);
27
+ }
28
+ const ms = Date.parse(s);
29
+ if (isNaN(ms))
30
+ throw new Error(`Invalid --since value: ${s} (use e.g. 2h, 7d, or an ISO date)`);
31
+ return new Date(ms);
32
+ }
33
+ /** How the run reached this host — 'local' or 'ssh 203.0.113.7'. */
34
+ function originLabel(r) {
35
+ if (r.transport === 'ssh') {
36
+ return chalk.yellow(`ssh${r.sshClientIp ? ' ' + r.sshClientIp : ''}`);
37
+ }
38
+ return chalk.gray('local');
39
+ }
40
+ /** The most useful one-line detail for a record, by event family. */
41
+ function detailFor(r) {
42
+ if (r.command)
43
+ return r.command;
44
+ const bits = [];
45
+ if (typeof r.team === 'string')
46
+ bits.push(`team=${r.team}`);
47
+ if (typeof r.bundle === 'string')
48
+ bits.push(`bundle=${r.bundle}`);
49
+ if (typeof r.skill === 'string')
50
+ bits.push(`skill=${r.skill}`);
51
+ if (typeof r.version === 'string')
52
+ bits.push(`v=${r.version}`);
53
+ if (typeof r.profile === 'string')
54
+ bits.push(`profile=${r.profile}`);
55
+ if (typeof r.error === 'string')
56
+ bits.push(chalk.red(r.error));
57
+ return bits.join(' ');
58
+ }
59
+ function renderRow(r) {
60
+ const time = chalk.gray(r.ts.slice(0, 19).replace('T', ' '));
61
+ const user = `${r.osUser ?? '?'}@${r.hostname}`;
62
+ const ev = r.event.startsWith('error') ? chalk.red(r.event) : chalk.cyan(r.event);
63
+ const agent = r.agent ? chalk.gray(` ${r.agent}`) : '';
64
+ return `${time} ${originLabel(r).padEnd(24)} ${user.padEnd(22)} ${ev.padEnd(26)}${agent} ${detailFor(r)}`;
65
+ }
66
+ export function registerEventsCommand(program) {
67
+ program
68
+ .command('events')
69
+ .description('Read the structured audit/event log (who ran what, from where)')
70
+ .option('--module <name>', 'Only events from this command group (e.g. teams, secrets)')
71
+ .option('--command <path>', 'Only this command path — prefix match (e.g. "teams create")')
72
+ .option('--event <type>', 'Only this typed event (repeatable, e.g. secrets.get)', collect, [])
73
+ .option('--agent <name>', 'Only events tagged with this agent')
74
+ .option('--since <time>', 'Only events newer than this (e.g. 2h, 7d, or ISO date)')
75
+ .option('--limit <n>', 'Max records to show (default 50)', '50')
76
+ .option('--json', 'Output raw records as JSON')
77
+ .option('-f, --follow', "Tail today's log live")
78
+ .addHelpText('after', `
79
+ Examples:
80
+ agents events Recent activity across everything
81
+ agents events --module teams Team lifecycle (create / add / disband)
82
+ agents events --module secrets Every secret accessed or revealed
83
+ agents events --command "teams create" Just team creations
84
+ agents events --event secrets.get --since 7d --json
85
+ agents events -f Live tail`)
86
+ .action(async (options) => {
87
+ if (options.follow) {
88
+ await followLog();
89
+ return;
90
+ }
91
+ const limit = Math.max(1, parseInt(options.limit ?? '50', 10) || 50);
92
+ let startDate;
93
+ try {
94
+ startDate = options.since ? parseSince(options.since) : undefined;
95
+ }
96
+ catch (err) {
97
+ console.error(chalk.red(err.message));
98
+ process.exit(2);
99
+ }
100
+ const records = query({
101
+ startDate,
102
+ eventTypes: options.event && options.event.length ? options.event : undefined,
103
+ agent: options.agent,
104
+ command: options.command,
105
+ module: options.module,
106
+ limit,
107
+ });
108
+ if (options.json) {
109
+ console.log(JSON.stringify(records, null, 2));
110
+ return;
111
+ }
112
+ if (records.length === 0) {
113
+ console.log(chalk.gray('No matching events.'));
114
+ return;
115
+ }
116
+ // query() returns newest-first; print oldest-first so a tail reads naturally.
117
+ for (const r of records.slice().reverse())
118
+ console.log(renderRow(r));
119
+ console.log(chalk.gray(`\n${records.length} event(s). Log: ${getLogsPath()}`));
120
+ });
121
+ }
122
+ /** commander repeatable-option collector. */
123
+ function collect(value, previous) {
124
+ return previous.concat([value]);
125
+ }
126
+ /** Tail today's event file, printing new lines as they land. */
127
+ async function followLog() {
128
+ const today = new Date();
129
+ const file = `${getLogsPath()}/events-${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, '0')}-${String(today.getDate()).padStart(2, '0')}.jsonl`;
130
+ let offset = 0;
131
+ try {
132
+ offset = fs.statSync(file).size;
133
+ }
134
+ catch {
135
+ // File may not exist yet — start at 0 and pick it up on first write.
136
+ }
137
+ console.log(chalk.gray(`Tailing ${file} — Ctrl-C to stop`));
138
+ const drain = () => {
139
+ let size = 0;
140
+ try {
141
+ size = fs.statSync(file).size;
142
+ }
143
+ catch {
144
+ return;
145
+ }
146
+ if (size <= offset) {
147
+ if (size < offset)
148
+ offset = 0; // rotated/truncated
149
+ return;
150
+ }
151
+ const fd = fs.openSync(file, 'r');
152
+ try {
153
+ const buf = Buffer.alloc(size - offset);
154
+ fs.readSync(fd, buf, 0, buf.length, offset);
155
+ offset = size;
156
+ for (const line of buf.toString('utf-8').split('\n').filter(Boolean)) {
157
+ try {
158
+ console.log(renderRow(JSON.parse(line)));
159
+ }
160
+ catch {
161
+ // Skip malformed lines.
162
+ }
163
+ }
164
+ }
165
+ finally {
166
+ fs.closeSync(fd);
167
+ }
168
+ };
169
+ // Poll — simpler and more portable than fs.watch across platforms/editors.
170
+ await new Promise(() => {
171
+ setInterval(drain, 500);
172
+ });
173
+ }
@@ -6,6 +6,7 @@
6
6
  * injection, and multi-agent fallback chains for rate-limit resilience.
7
7
  */
8
8
  import { type Command } from 'commander';
9
+ import type { ExecEffort } from '../lib/exec.js';
9
10
  /**
10
11
  * Build the LoopConfig the driver consumes from CLI flags and/or a workflow's
11
12
  * `loop:` frontmatter block (issue #332). Returns undefined when neither source
@@ -26,5 +27,23 @@ export declare function buildLoopConfig(flags: {
26
27
  }, workflowLoop?: import('../lib/workflows.js').LoopConfigRaw): import('../lib/loop.js').LoopConfig | undefined;
27
28
  /** Map a loop stop reason to a process exit code. condition-met/max are clean exits. */
28
29
  export declare function loopExitCode(stoppedBy: import('../lib/loop.js').LoopStoppedBy): number;
30
+ /**
31
+ * Drive a workflow's declarative `for_each:` fan-out end-to-end (issue #343).
32
+ *
33
+ * Runs the producer, expands one stage teammate per produced item (respecting
34
+ * `max_items` / `DEFAULT_FOR_EACH_CAP`, surfacing any truncation — never a
35
+ * silent cap), stages them into a fresh team via the existing `runForEach`
36
+ * bridge, then drives the teams supervisor until the DAG drains. When a verify
37
+ * panel is declared, tallies each item's `keep_if` gate from the skeptics'
38
+ * terminal status and logs which items survived.
39
+ *
40
+ * Reuses the teams substrate wholesale — no new orchestration engine. Returns
41
+ * the process exit code (0 on drain, 1 on producer failure / non-drain).
42
+ */
43
+ export declare function runWorkflowForEach(spec: import('../lib/workflows.js').ForEachSpec, opts: {
44
+ workflowName: string;
45
+ cwd: string;
46
+ effort?: ExecEffort;
47
+ }): Promise<number>;
29
48
  /** Register the `agents run <agent> [prompt]` command. */
30
49
  export declare function registerRunCommand(program: Command): void;