@phnx-labs/agents-cli 1.20.78 → 1.20.82

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 (176) hide show
  1. package/CHANGELOG.md +487 -0
  2. package/README.md +25 -25
  3. package/dist/bin/agents +0 -0
  4. package/dist/commands/activity.d.ts +9 -0
  5. package/dist/commands/activity.js +153 -24
  6. package/dist/commands/apply.js +11 -4
  7. package/dist/commands/cli.js +1 -1
  8. package/dist/commands/commands.d.ts +1 -1
  9. package/dist/commands/commands.js +7 -6
  10. package/dist/commands/defaults.js +3 -11
  11. package/dist/commands/doctor.d.ts +65 -0
  12. package/dist/commands/doctor.js +575 -31
  13. package/dist/commands/events.js +1 -1
  14. package/dist/commands/exec.js +24 -5
  15. package/dist/commands/feed.d.ts +4 -0
  16. package/dist/commands/feed.js +87 -11
  17. package/dist/commands/harness.js +2 -2
  18. package/dist/commands/hooks.js +1 -1
  19. package/dist/commands/import.js +8 -4
  20. package/dist/commands/logs.js +6 -0
  21. package/dist/commands/models.js +1 -1
  22. package/dist/commands/packages.js +6 -6
  23. package/dist/commands/permissions.js +1 -1
  24. package/dist/commands/profiles.js +1 -1
  25. package/dist/commands/pull.d.ts +1 -1
  26. package/dist/commands/pull.js +4 -4
  27. package/dist/commands/repo.d.ts +78 -0
  28. package/dist/commands/repo.js +187 -11
  29. package/dist/commands/routines.js +12 -2
  30. package/dist/commands/rules.js +13 -12
  31. package/dist/commands/secrets.d.ts +3 -1
  32. package/dist/commands/secrets.js +100 -32
  33. package/dist/commands/sessions-inject.d.ts +7 -4
  34. package/dist/commands/sessions-inject.js +18 -18
  35. package/dist/commands/sessions-picker.js +32 -3
  36. package/dist/commands/sessions-resume.d.ts +16 -0
  37. package/dist/commands/sessions-resume.js +14 -13
  38. package/dist/commands/sessions.d.ts +31 -0
  39. package/dist/commands/sessions.js +141 -16
  40. package/dist/commands/set.d.ts +15 -0
  41. package/dist/commands/set.js +79 -0
  42. package/dist/commands/setup-fleet.d.ts +21 -0
  43. package/dist/commands/setup-fleet.js +201 -0
  44. package/dist/commands/setup-secrets.d.ts +20 -0
  45. package/dist/commands/setup-secrets.js +223 -0
  46. package/dist/commands/setup.js +17 -3
  47. package/dist/commands/skills.js +1 -1
  48. package/dist/commands/sync.js +7 -2
  49. package/dist/commands/teams-picker.js +0 -1
  50. package/dist/commands/teams.d.ts +33 -1
  51. package/dist/commands/teams.js +208 -44
  52. package/dist/commands/versions.js +10 -5
  53. package/dist/commands/view.d.ts +1 -0
  54. package/dist/commands/view.js +11 -0
  55. package/dist/index.js +5 -8
  56. package/dist/lib/acp/harnesses.js +0 -7
  57. package/dist/lib/activity.d.ts +156 -0
  58. package/dist/lib/activity.js +282 -0
  59. package/dist/lib/agents.d.ts +9 -2
  60. package/dist/lib/agents.js +72 -63
  61. package/dist/lib/browser/service.js +3 -0
  62. package/dist/lib/browser/types.d.ts +7 -0
  63. package/dist/lib/capabilities.js +6 -2
  64. package/dist/lib/crabbox/lease.js +2 -2
  65. package/dist/lib/crabbox/setup-copy.d.ts +4 -4
  66. package/dist/lib/crabbox/setup-copy.js +4 -4
  67. package/dist/lib/daemon.d.ts +18 -0
  68. package/dist/lib/daemon.js +47 -6
  69. package/dist/lib/devices/fleet.d.ts +1 -1
  70. package/dist/lib/devices/fleet.js +1 -1
  71. package/dist/lib/doctor-diff.d.ts +20 -0
  72. package/dist/lib/doctor-diff.js +6 -1
  73. package/dist/lib/drift.d.ts +31 -11
  74. package/dist/lib/drift.js +58 -7
  75. package/dist/lib/events.d.ts +8 -1
  76. package/dist/lib/events.js +10 -1
  77. package/dist/lib/exec.js +35 -8
  78. package/dist/lib/feed-post.d.ts +28 -1
  79. package/dist/lib/feed-post.js +110 -2
  80. package/dist/lib/fleet/apply.js +8 -1
  81. package/dist/lib/fleet/auth-sync.d.ts +18 -1
  82. package/dist/lib/fleet/auth-sync.js +25 -11
  83. package/dist/lib/fleet/remote-login.js +5 -0
  84. package/dist/lib/git.d.ts +14 -14
  85. package/dist/lib/git.js +41 -44
  86. package/dist/lib/hooks.d.ts +42 -0
  87. package/dist/lib/hooks.js +137 -93
  88. package/dist/lib/hosts/dispatch.d.ts +28 -1
  89. package/dist/lib/hosts/dispatch.js +33 -5
  90. package/dist/lib/hosts/option.js +2 -2
  91. package/dist/lib/hosts/passthrough.d.ts +22 -1
  92. package/dist/lib/hosts/passthrough.js +238 -13
  93. package/dist/lib/hosts/run-target.d.ts +2 -0
  94. package/dist/lib/hosts/run-target.js +1 -0
  95. package/dist/lib/hq/floor.d.ts +1 -1
  96. package/dist/lib/hq/floor.js +6 -1
  97. package/dist/lib/mcp.js +3 -71
  98. package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
  99. package/dist/lib/menubar/notify-desktop.d.ts +15 -0
  100. package/dist/lib/menubar/notify-desktop.js +41 -5
  101. package/dist/lib/merged-resources.d.ts +11 -0
  102. package/dist/{commands/resources.js → lib/merged-resources.js} +11 -19
  103. package/dist/lib/permissions.d.ts +0 -32
  104. package/dist/lib/permissions.js +4 -157
  105. package/dist/lib/picker.js +1 -1
  106. package/dist/lib/platform/process.d.ts +16 -5
  107. package/dist/lib/platform/process.js +54 -0
  108. package/dist/lib/plugins.d.ts +0 -8
  109. package/dist/lib/plugins.js +4 -110
  110. package/dist/lib/project-resources.js +4 -1
  111. package/dist/lib/refresh.d.ts +5 -3
  112. package/dist/lib/refresh.js +7 -5
  113. package/dist/lib/resources/commands.js +4 -1
  114. package/dist/lib/resources/mcp.js +0 -4
  115. package/dist/lib/resources/permissions.d.ts +1 -1
  116. package/dist/lib/resources/permissions.js +1 -5
  117. package/dist/lib/resources/rules.js +4 -1
  118. package/dist/lib/resources/skills.js +4 -1
  119. package/dist/lib/resources/subagents.js +4 -0
  120. package/dist/lib/resources/types.d.ts +1 -1
  121. package/dist/lib/routines.d.ts +20 -0
  122. package/dist/lib/routines.js +6 -0
  123. package/dist/lib/run-defaults.d.ts +1 -0
  124. package/dist/lib/run-defaults.js +9 -0
  125. package/dist/lib/runner.d.ts +0 -12
  126. package/dist/lib/runner.js +49 -10
  127. package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
  128. package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
  129. package/dist/lib/secrets/agent.d.ts +16 -0
  130. package/dist/lib/secrets/agent.js +105 -3
  131. package/dist/lib/secrets/audit.d.ts +46 -0
  132. package/dist/lib/secrets/audit.js +56 -0
  133. package/dist/lib/secrets/bundles.d.ts +11 -8
  134. package/dist/lib/secrets/bundles.js +31 -23
  135. package/dist/lib/secrets/index.d.ts +2 -1
  136. package/dist/lib/secrets/index.js +8 -2
  137. package/dist/lib/secrets/remote.d.ts +75 -2
  138. package/dist/lib/secrets/remote.js +139 -5
  139. package/dist/lib/secrets/sync.js +3 -3
  140. package/dist/lib/session/active.d.ts +110 -26
  141. package/dist/lib/session/active.js +161 -50
  142. package/dist/lib/session/actor-sidecar.d.ts +23 -0
  143. package/dist/lib/session/actor-sidecar.js +101 -0
  144. package/dist/lib/session/db.d.ts +4 -1
  145. package/dist/lib/session/db.js +65 -8
  146. package/dist/lib/session/discover.d.ts +4 -0
  147. package/dist/lib/session/discover.js +13 -0
  148. package/dist/lib/session/hook-sessions.d.ts +9 -0
  149. package/dist/lib/session/hook-sessions.js +57 -8
  150. package/dist/lib/session/pid-registry.d.ts +13 -0
  151. package/dist/lib/session/render.d.ts +2 -0
  152. package/dist/lib/session/render.js +1 -1
  153. package/dist/lib/session/types.d.ts +16 -0
  154. package/dist/lib/staleness/detectors/commands.js +2 -2
  155. package/dist/lib/staleness/detectors/permissions.js +1 -45
  156. package/dist/lib/staleness/writers/commands.js +4 -5
  157. package/dist/lib/staleness/writers/hooks.js +1 -1
  158. package/dist/lib/startup/command-registry.d.ts +1 -2
  159. package/dist/lib/startup/command-registry.js +2 -4
  160. package/dist/lib/subagents-registry.js +5 -12
  161. package/dist/lib/subagents.d.ts +0 -10
  162. package/dist/lib/subagents.js +0 -12
  163. package/dist/lib/teams/agents.d.ts +0 -2
  164. package/dist/lib/teams/agents.js +10 -27
  165. package/dist/lib/teams/index.d.ts +1 -1
  166. package/dist/lib/teams/index.js +1 -1
  167. package/dist/lib/types.d.ts +17 -9
  168. package/dist/lib/usage.d.ts +28 -5
  169. package/dist/lib/usage.js +271 -8
  170. package/dist/lib/versions.js +7 -1
  171. package/dist/lib/watchdog/watchdog.d.ts +1 -1
  172. package/dist/lib/watchdog/watchdog.js +25 -13
  173. package/package.json +1 -2
  174. package/dist/commands/check.d.ts +0 -15
  175. package/dist/commands/check.js +0 -180
  176. package/dist/commands/resources.d.ts +0 -5
@@ -12,7 +12,7 @@ import { shareRuntimeEnv } from '../lib/share/config.js';
12
12
  import { runSupervisor } from '../lib/teams/supervisor.js';
13
13
  import { debug } from '../lib/teams/debug.js';
14
14
  import { runPrWatch, DEFAULT_MAX_WAVES, } from '../lib/teams/pr-watch.js';
15
- import { handleSpawn, handleStatus, handleStop, handleTasks, toTaskStatusSummary, } from '../lib/teams/api.js';
15
+ import { handleSpawn, handleStatus, handleStop, toTaskStatusSummary, } from '../lib/teams/api.js';
16
16
  import { createTeam, ensureTeam, getTeam, loadTeams, removeTeam, teamExists, } from '../lib/teams/registry.js';
17
17
  import { setHelpSections } from '../lib/help.js';
18
18
  import { createWorktree, isGitRepo, hasUncommittedChanges, removeWorktree, } from '../lib/teams/worktree.js';
@@ -46,7 +46,7 @@ const AGENT_NAMES = {
46
46
  kimi: 'Kimi',
47
47
  droid: 'Droid',
48
48
  };
49
- const VALID_AGENTS = Object.keys(AGENT_NAMES);
49
+ const VALID_AGENTS = ['claude', 'codex', 'cursor', 'opencode', 'grok', 'antigravity', 'kimi', 'droid'];
50
50
  // 'full' kept as historical alias for 'skip'; normalized to 'skip' downstream.
51
51
  const VALID_MODES = ['plan', 'edit', 'auto', 'skip', 'full'];
52
52
  const VALID_EFFORTS = ['low', 'medium', 'high', 'xhigh', 'max', 'auto'];
@@ -77,6 +77,75 @@ function formatTimestamp(iso) {
77
77
  minute: '2-digit',
78
78
  });
79
79
  }
80
+ function normalizeTeamListStatus(status) {
81
+ if (Object.values(AgentStatus).includes(status)) {
82
+ return status;
83
+ }
84
+ return AgentStatus.RUNNING;
85
+ }
86
+ function parseTimestamp(value) {
87
+ if (!value)
88
+ return null;
89
+ const date = new Date(value);
90
+ return Number.isNaN(date.getTime()) ? null : date;
91
+ }
92
+ function durationFromSnapshot(agent) {
93
+ const startedAt = parseTimestamp(agent.started_at);
94
+ if (!startedAt)
95
+ return null;
96
+ const completedAt = parseTimestamp(agent.completed_at);
97
+ let seconds;
98
+ if (completedAt) {
99
+ seconds = (completedAt.getTime() - startedAt.getTime()) / 1000;
100
+ }
101
+ else if (normalizeTeamListStatus(agent.status) === AgentStatus.RUNNING) {
102
+ seconds = (Date.now() - startedAt.getTime()) / 1000;
103
+ }
104
+ else {
105
+ return null;
106
+ }
107
+ if (seconds < 60)
108
+ return `${Math.max(0, Math.floor(seconds))} seconds`;
109
+ return `${Math.max(0, seconds / 60).toFixed(1)} minutes`;
110
+ }
111
+ function snapshotActivityTime(agent) {
112
+ const status = normalizeTeamListStatus(agent.status);
113
+ if (status === AgentStatus.RUNNING)
114
+ return new Date();
115
+ return parseTimestamp(agent.completed_at) || parseTimestamp(agent.started_at) || new Date(0);
116
+ }
117
+ function snapshotToStatusDetail(agent) {
118
+ return {
119
+ agent_id: agent.agent_id,
120
+ agent_type: agent.agent_type,
121
+ status: normalizeTeamListStatus(agent.status),
122
+ prompt: agent.prompt,
123
+ started_at: parseTimestamp(agent.started_at)?.toISOString() || new Date(0).toISOString(),
124
+ completed_at: parseTimestamp(agent.completed_at)?.toISOString() || null,
125
+ duration: durationFromSnapshot(agent),
126
+ files_created: [],
127
+ files_modified: [],
128
+ files_read: [],
129
+ files_deleted: [],
130
+ bash_commands: [],
131
+ recent_tool_calls: [],
132
+ last_messages: [],
133
+ tool_count: 0,
134
+ has_errors: false,
135
+ cursor: snapshotActivityTime(agent).toISOString(),
136
+ mode: agent.mode ?? undefined,
137
+ cloud_session_id: agent.cloud_session_id,
138
+ cloud_provider: agent.cloud_provider,
139
+ pr_url: agent.pr_url,
140
+ version: agent.version,
141
+ remote_session_id: agent.remote_session_id,
142
+ session_label: null,
143
+ name: agent.name,
144
+ after: agent.after,
145
+ task_type: agent.task_type,
146
+ host: agent.host,
147
+ };
148
+ }
80
149
  function fullName(type, version) {
81
150
  const name = AGENT_NAMES[type];
82
151
  return version ? `${name} ${version}` : name;
@@ -714,23 +783,132 @@ function mergeTeams(registry, tasks) {
714
783
  }
715
784
  return Array.from(byName.values()).sort((a, b) => new Date(b.modified_at).getTime() - new Date(a.modified_at).getTime());
716
785
  }
717
- // Build the same enriched rows the `list` picker uses. Shared between `list`
718
- // (interactive default) and the picker fallback for `status` / `start`.
719
- async function loadTeamRows(mgr) {
720
- const [tasks, registry] = await Promise.all([handleTasks(mgr, 1000), loadTeams()]);
721
- const merged = mergeTeams(registry, tasks.tasks);
722
- const rows = await Promise.all(merged.map(async (team) => {
723
- let agents = [];
786
+ function buildTasksFromSnapshots(agents) {
787
+ const byTeam = new Map();
788
+ for (const agent of agents) {
789
+ const teamAgents = byTeam.get(agent.task_name) || [];
790
+ teamAgents.push(agent);
791
+ byTeam.set(agent.task_name, teamAgents);
792
+ }
793
+ const tasks = [];
794
+ for (const [taskName, teamAgents] of byTeam) {
795
+ let pending = 0;
796
+ let running = 0;
797
+ let completed = 0;
798
+ let failed = 0;
799
+ let stopped = 0;
800
+ let earliestStart = null;
801
+ let latestActivity = null;
802
+ let workspaceDir = null;
803
+ for (const agent of teamAgents) {
804
+ const status = normalizeTeamListStatus(agent.status);
805
+ if (status === AgentStatus.PENDING)
806
+ pending++;
807
+ else if (status === AgentStatus.RUNNING)
808
+ running++;
809
+ else if (status === AgentStatus.COMPLETED)
810
+ completed++;
811
+ else if (status === AgentStatus.FAILED)
812
+ failed++;
813
+ else if (status === AgentStatus.STOPPED)
814
+ stopped++;
815
+ const startedAt = parseTimestamp(agent.started_at);
816
+ if (startedAt && (!earliestStart || startedAt < earliestStart)) {
817
+ earliestStart = startedAt;
818
+ }
819
+ const activity = snapshotActivityTime(agent);
820
+ if (!latestActivity || activity > latestActivity) {
821
+ latestActivity = activity;
822
+ }
823
+ if (!workspaceDir && agent.workspace_dir) {
824
+ workspaceDir = agent.workspace_dir;
825
+ }
826
+ }
827
+ const fallback = new Date(0);
828
+ tasks.push({
829
+ task_name: taskName,
830
+ agent_count: teamAgents.length,
831
+ pending,
832
+ running,
833
+ completed,
834
+ failed,
835
+ stopped,
836
+ workspace_dir: workspaceDir,
837
+ created_at: (earliestStart || fallback).toISOString(),
838
+ modified_at: (latestActivity || earliestStart || fallback).toISOString(),
839
+ });
840
+ }
841
+ return tasks.sort((a, b) => new Date(b.modified_at).getTime() - new Date(a.modified_at).getTime());
842
+ }
843
+ export function buildTeamRowsFromSnapshots(registry, agents) {
844
+ const byTeam = new Map();
845
+ for (const agent of agents) {
846
+ const details = byTeam.get(agent.task_name) || [];
847
+ details.push(snapshotToStatusDetail(agent));
848
+ byTeam.set(agent.task_name, details);
849
+ }
850
+ const teams = mergeTeams(registry, buildTasksFromSnapshots(agents));
851
+ return {
852
+ teams,
853
+ rows: teams.map((team) => ({
854
+ team,
855
+ agents: byTeam.get(team.task_name) || [],
856
+ description: registry[team.task_name]?.description,
857
+ })),
858
+ names: teams.map((team) => team.task_name),
859
+ };
860
+ }
861
+ function snapshotFromMeta(meta) {
862
+ if (!meta || typeof meta !== 'object')
863
+ return null;
864
+ const agentId = typeof meta.agent_id === 'string' ? meta.agent_id : '';
865
+ const taskName = typeof meta.task_name === 'string' ? meta.task_name : '';
866
+ const agentType = typeof meta.agent_type === 'string' ? meta.agent_type : '';
867
+ if (!agentId || !taskName || !agentType)
868
+ return null;
869
+ return {
870
+ agent_id: agentId,
871
+ task_name: taskName,
872
+ agent_type: agentType,
873
+ status: normalizeTeamListStatus(meta.status),
874
+ prompt: typeof meta.prompt === 'string' ? meta.prompt : '',
875
+ started_at: parseTimestamp(meta.started_at)?.toISOString() || new Date(0).toISOString(),
876
+ completed_at: parseTimestamp(meta.completed_at)?.toISOString() || null,
877
+ workspace_dir: typeof meta.workspace_dir === 'string' ? meta.workspace_dir : null,
878
+ version: typeof meta.version === 'string' ? meta.version : null,
879
+ remote_session_id: typeof meta.remote_session_id === 'string' ? meta.remote_session_id : null,
880
+ name: typeof meta.name === 'string' ? meta.name : null,
881
+ after: Array.isArray(meta.after) ? meta.after.filter((name) => typeof name === 'string') : [],
882
+ task_type: typeof meta.task_type === 'string' && VALID_TASK_TYPES.includes(meta.task_type)
883
+ ? meta.task_type
884
+ : null,
885
+ host: typeof meta.host_name === 'string' ? meta.host_name : null,
886
+ mode: typeof meta.mode === 'string' ? meta.mode : null,
887
+ cloud_session_id: typeof meta.cloud_session_id === 'string' ? meta.cloud_session_id : null,
888
+ cloud_provider: typeof meta.cloud_provider === 'string' ? meta.cloud_provider : null,
889
+ pr_url: typeof meta.pr_url === 'string' ? meta.pr_url : null,
890
+ };
891
+ }
892
+ async function loadTeamAgentSnapshots() {
893
+ const agentsDir = await getAgentsDir();
894
+ const entries = await fs.readdir(agentsDir).catch(() => []);
895
+ const snapshots = await Promise.all(entries.map(async (entry) => {
896
+ const metaPath = path.join(agentsDir, entry, 'meta.json');
724
897
  try {
725
- const res = await handleStatus(mgr, team.task_name, 'all');
726
- agents = res.agents;
898
+ const raw = await fs.readFile(metaPath, 'utf-8');
899
+ return snapshotFromMeta(JSON.parse(raw));
727
900
  }
728
901
  catch {
729
- // Empty teams (no live agents) throw in some code paths.
902
+ return null;
730
903
  }
731
- return { team, agents, description: registry[team.task_name]?.description };
732
904
  }));
733
- return { rows, names: merged.map((t) => t.task_name) };
905
+ return snapshots.filter((snapshot) => snapshot !== null);
906
+ }
907
+ // Build cached rows for the `list` picker. Shared between `list` and picker
908
+ // fallbacks for `status` / `start`; full status stays lazy until a team is picked.
909
+ async function loadTeamRows(_mgr) {
910
+ const [registry, agents] = await Promise.all([loadTeams(), loadTeamAgentSnapshots()]);
911
+ return buildTeamRowsFromSnapshots(registry, agents);
734
912
  }
735
913
  // Picker fallback for `teams logs` when the teammate ref is omitted. Shows a
736
914
  // flat list of every teammate with their team context; Enter picks one.
@@ -900,25 +1078,23 @@ export function registerTeamsCommands(program) {
900
1078
  .option('-n, --limit <n>', 'Show at most this many teams (default: 20)', '20')
901
1079
  .option('--json', 'Output machine-readable JSON instead of formatted table')
902
1080
  .action(async (query, opts) => {
903
- const mgr = mkManager();
904
1081
  const limit = Math.max(1, parseInt(opts.limit, 10) || 20);
905
- const [tasks, registry, everyAgent] = await Promise.all([
906
- handleTasks(mgr, 1000),
1082
+ const [registry, everyAgent] = await Promise.all([
907
1083
  loadTeams(),
908
- mgr.listAll(),
1084
+ loadTeamAgentSnapshots(),
909
1085
  ]);
910
1086
  // Group agents by team so we can filter on agent-type / version.
911
1087
  const byTeam = new Map();
912
1088
  for (const a of everyAgent) {
913
- const arr = byTeam.get(a.taskName) || [];
914
- arr.push({ agent_type: a.agentType, version: a.version });
915
- byTeam.set(a.taskName, arr);
1089
+ const arr = byTeam.get(a.task_name) || [];
1090
+ arr.push(a);
1091
+ byTeam.set(a.task_name, arr);
916
1092
  }
917
- let merged = mergeTeams(registry, tasks.tasks);
1093
+ let rows = buildTeamRowsFromSnapshots(registry, everyAgent).rows;
918
1094
  // --- query: substring match on team name ---
919
1095
  if (query) {
920
1096
  const q = query.toLowerCase();
921
- merged = merged.filter((t) => t.task_name.toLowerCase().includes(q));
1097
+ rows = rows.filter((row) => row.team.task_name.toLowerCase().includes(q));
922
1098
  }
923
1099
  // --- --agent: filter teams containing a matching teammate ---
924
1100
  if (opts.agent) {
@@ -926,8 +1102,8 @@ export function registerTeamsCommands(program) {
926
1102
  const wantVersion = VALID_AGENTS.includes(wantType)
927
1103
  ? resolveVersionAliasLoose(wantType, rawVersion)
928
1104
  : rawVersion;
929
- merged = merged.filter((t) => {
930
- const teammates = byTeam.get(t.task_name) || [];
1105
+ rows = rows.filter((row) => {
1106
+ const teammates = byTeam.get(row.team.task_name) || [];
931
1107
  return teammates.some((m) => m.agent_type === wantType && (!wantVersion || m.version === wantVersion));
932
1108
  });
933
1109
  }
@@ -938,27 +1114,27 @@ export function registerTeamsCommands(program) {
938
1114
  if (!validStatuses.includes(want)) {
939
1115
  die(`Invalid --status '${opts.status}'. Use one of: ${validStatuses.join(', ')}`);
940
1116
  }
941
- merged = merged.filter((t) => classifyTeamStatus(t) === want);
1117
+ rows = rows.filter((row) => classifyTeamStatus(row.team) === want);
942
1118
  }
943
1119
  // --- --since / --until: filter by activity window ---
944
1120
  if (opts.since) {
945
1121
  const cutoff = parseTimeFilter(opts.since);
946
1122
  if (!cutoff)
947
1123
  die(`Could not parse --since '${opts.since}'`);
948
- merged = merged.filter((t) => new Date(t.modified_at).getTime() >= cutoff);
1124
+ rows = rows.filter((row) => new Date(row.team.modified_at).getTime() >= cutoff);
949
1125
  }
950
1126
  if (opts.until) {
951
1127
  const cutoff = parseTimeFilter(opts.until);
952
1128
  if (!cutoff)
953
1129
  die(`Could not parse --until '${opts.until}'`);
954
- merged = merged.filter((t) => new Date(t.modified_at).getTime() <= cutoff);
1130
+ rows = rows.filter((row) => new Date(row.team.modified_at).getTime() <= cutoff);
955
1131
  }
956
- merged = merged.slice(0, limit);
1132
+ rows = rows.slice(0, limit);
957
1133
  if (isJsonMode(opts)) {
958
- console.log(JSON.stringify({ teams: merged }, null, 2));
1134
+ console.log(JSON.stringify({ teams: rows.map((row) => row.team) }, null, 2));
959
1135
  return;
960
1136
  }
961
- if (merged.length === 0) {
1137
+ if (rows.length === 0) {
962
1138
  if (query || opts.agent || opts.status || opts.since || opts.until) {
963
1139
  console.log(chalk.gray('No teams match those filters.'));
964
1140
  }
@@ -968,24 +1144,12 @@ export function registerTeamsCommands(program) {
968
1144
  }
969
1145
  return;
970
1146
  }
971
- // Enrich teams with teammate details for the picker's preview pane.
972
- const rows = await Promise.all(merged.map(async (team) => {
973
- let agents = [];
974
- try {
975
- const res = await handleStatus(mgr, team.task_name, 'all');
976
- agents = res.agents;
977
- }
978
- catch {
979
- // Empty teams (no live agents) throw in some code paths — preview
980
- // will just show "no teammates yet".
981
- }
982
- return { team, agents, description: registry[team.task_name]?.description };
983
- }));
984
1147
  if (isInteractiveTerminal()) {
985
1148
  try {
986
1149
  const picked = await teamPicker(rows, query);
987
1150
  if (picked) {
988
1151
  // Fall through to the status subcommand's action for the picked team.
1152
+ const mgr = mkManager();
989
1153
  const result = await handleStatus(mgr, picked.team, 'all');
990
1154
  await printTeamStatus(picked.team, result);
991
1155
  }
@@ -4,7 +4,7 @@ import ora from 'ora';
4
4
  import * as fs from 'fs';
5
5
  import * as path from 'path';
6
6
  import { select, confirm, checkbox } from '@inquirer/prompts';
7
- import { AGENTS, ALL_AGENT_IDS, accountOrgBadge, getAccountEmail, getAccountInfo, agentLabel, warnAgentDeprecated, isSelfUpdatingAgent, } from '../lib/agents.js';
7
+ import { AGENTS, MANAGED_AGENT_IDS, accountOrgBadge, getAccountEmail, getAccountInfo, agentLabel, warnAgentDeprecated, isAgentHardDeprecated, hardDeprecationError, isSelfUpdatingAgent, } from '../lib/agents.js';
8
8
  import { formatUsageSummary, getUsageInfoForIdentity, getUsageInfoByIdentity, getUsageLookupKey, } from '../lib/usage.js';
9
9
  import { viewAction } from './view.js';
10
10
  import { resolveConfiguredModel, formatAgentIdentity } from '../lib/models.js';
@@ -128,7 +128,7 @@ async function versionPruneAction(specs, options, commandName) {
128
128
  const parsed = parseAgentSpec(spec);
129
129
  if (!parsed) {
130
130
  console.log(chalk.red(`Invalid agent: ${spec}`));
131
- console.log(chalk.gray(`Format: <agent>[@version]. Available: ${ALL_AGENT_IDS.join(', ')}`));
131
+ console.log(chalk.gray(`Format: <agent>[@version]. Available: ${MANAGED_AGENT_IDS.join(', ')}`));
132
132
  continue;
133
133
  }
134
134
  const { agent, version } = parsed;
@@ -333,11 +333,16 @@ export function registerVersionsCommands(program) {
333
333
  const parsed = parseAgentSpec(spec);
334
334
  if (!parsed) {
335
335
  console.log(chalk.red(`Invalid agent: ${spec}`));
336
- console.log(chalk.gray(`Format: <agent>[@version]. Available: ${ALL_AGENT_IDS.join(', ')}`));
336
+ console.log(chalk.gray(`Format: <agent>[@version]. Available: ${MANAGED_AGENT_IDS.join(', ')}`));
337
337
  continue;
338
338
  }
339
339
  const { agent, version } = parsed;
340
340
  const agentConfig = AGENTS[agent];
341
+ if (isAgentHardDeprecated(agent)) {
342
+ console.error(chalk.red(hardDeprecationError(agent)));
343
+ process.exitCode = 1;
344
+ continue;
345
+ }
341
346
  warnAgentDeprecated(agent);
342
347
  // Isolation relies on a config-dir env var to redirect the copy away
343
348
  // from the user's real ~/.<agent>. Agents without one isolate only by
@@ -631,7 +636,7 @@ export function registerVersionsCommands(program) {
631
636
  const parsed = parseAgentSpec(agentArg);
632
637
  if (!parsed) {
633
638
  console.log(chalk.red(`Invalid agent: ${agentArg}`));
634
- console.log(chalk.gray(`Format: <agent>[@version]. Available: ${ALL_AGENT_IDS.join(', ')}`));
639
+ console.log(chalk.gray(`Format: <agent>[@version]. Available: ${MANAGED_AGENT_IDS.join(', ')}`));
635
640
  return;
636
641
  }
637
642
  agent = parsed.agent;
@@ -641,7 +646,7 @@ export function registerVersionsCommands(program) {
641
646
  const agentLower = agentArg.toLowerCase();
642
647
  if (!AGENTS[agentLower]) {
643
648
  console.log(chalk.red(`Invalid agent: ${agentArg}`));
644
- console.log(chalk.gray(`Available: ${ALL_AGENT_IDS.join(', ')}`));
649
+ console.log(chalk.gray(`Available: ${MANAGED_AGENT_IDS.join(', ')}`));
645
650
  return;
646
651
  }
647
652
  agent = agentLower;
@@ -129,6 +129,7 @@ export declare function viewAction(agentArg?: string, options?: {
129
129
  detailed?: boolean;
130
130
  refresh?: boolean;
131
131
  live?: boolean;
132
+ merged?: boolean;
132
133
  } & ViewSectionFilter): Promise<void>;
133
134
  /** Register the `agents view` command. */
134
135
  export declare function registerViewCommand(program: Command): void;
@@ -13,6 +13,7 @@ import { readManifest } from '../lib/manifest.js';
13
13
  import { listInstalledVersions, listInstalledVersionDirs, getGlobalDefault, getVersionHomePath, getVersionDir, getAvailableResources, getActuallySyncedResources, getNewResources, getProjectOnlyResources, hasNewResources, promptNewResourceSelection, syncResourcesToVersion, removeVersion, printTrashFooter, reconcileStaleLatestForAgent, isGlobalBinaryAgent, getLiveVersion, isVersionIsolated, getIsolatedDefault, } from '../lib/versions.js';
14
14
  import { ensureVersionedAliasCurrent, removeShim, } from '../lib/shims.js';
15
15
  import { getAgentResources } from '../lib/resources.js';
16
+ import { renderMergedResources } from '../lib/merged-resources.js';
16
17
  import { resolveVersionFilter, AgentSpecError } from '../lib/agent-spec/index.js';
17
18
  import { listCliStatus } from '../lib/cli-resources.js';
18
19
  import { isCapable } from '../lib/capabilities.js';
@@ -1468,6 +1469,12 @@ export async function pruneDuplicates(filterAgentId, yes, dryRun) {
1468
1469
  * Exported for use by deprecated aliases.
1469
1470
  */
1470
1471
  export async function viewAction(agentArg, options) {
1472
+ // --merged renders the cross-layer, first-wins resource surface (the former
1473
+ // `agents resources`), independent of the per-version detail view below.
1474
+ if (options?.merged) {
1475
+ renderMergedResources();
1476
+ return;
1477
+ }
1471
1478
  // --live is a shorter-to-type alias of --refresh; both force a live probe.
1472
1479
  const forceRefresh = options?.refresh === true || options?.live === true;
1473
1480
  // --resources / --detailed imply --json (they only shape structured output).
@@ -1595,6 +1602,7 @@ export function registerViewCommand(program) {
1595
1602
  .option('--hooks', 'Show only hooks in the detail view.')
1596
1603
  .option('--promptcuts', 'Show only promptcuts in the detail view.')
1597
1604
  .option('--cli', 'Show only host CLIs (declared in cli/, installed to PATH).')
1605
+ .option('--merged', 'Show the merged, first-wins resource surface across all layers (project, user, extras, system) in one table with the winning layer per row.')
1598
1606
  .addHelpText('after', `
1599
1607
  Examples:
1600
1608
  # Show all installed agents with versions, accounts, and usage
@@ -1625,6 +1633,9 @@ Examples:
1625
1633
  agents view claude@default --plugins --workflows
1626
1634
  agents view claude --commands # implicitly the default version
1627
1635
 
1636
+ # Merged, first-wins resource surface across all layers, with the winning layer
1637
+ agents view --merged
1638
+
1628
1639
  When to use:
1629
1640
  - Checking which agents are installed and what their default versions are
1630
1641
  - Seeing which account each version is logged into (useful for multi-account setups)
package/dist/index.js CHANGED
@@ -94,7 +94,7 @@ if (IS_DEV_BUILD) {
94
94
  // module on each invocation (which loaded the whole ~50-module tree before the
95
95
  // first byte of output), the registry maps a command name to a thunk that
96
96
  // imports only what that command needs. See src/lib/startup/command-registry.ts.
97
- import { COMMAND_LOADERS, LAZY_COMMAND_NAMES, loadView, loadInspect, loadResources, loadFeedback, loadCommands, loadHooks, loadSkills, loadRules, loadMemory, loadPermissions, loadMcp, loadCli, loadSubagents, loadPlugins, loadWorkflows, loadWorktree, loadVersions, loadImport, loadExport, loadPackages, loadRoutines, loadMonitors, loadRun, loadFork, loadDefaults, loadModels, loadPrune, loadTrash, loadRestore, loadDoctor, loadApply, loadCheck, loadStatus, loadProfiles, loadHarness, loadSecrets, loadLogin, loadWallet, loadHelper, loadMenubar, loadBeta, loadSync, loadLock, loadRefreshRules, loadDrive, loadFactory, loadUsage, loadCost, loadOutput, loadBudget, loadAlias, loadMine, loadPty, loadTmux, loadWatchdog, loadBrowser, loadComputer, loadHosts, loadLogs, loadEvents, loadAudit, loadWebhook, loadFunnel, loadSsh, loadPull, loadPush, loadRepo, loadSetup, loadUninstall, loadShare, loadSend, loadHq, loadFeed, loadActivity, loadMailboxes, } from './lib/startup/command-registry.js';
97
+ import { COMMAND_LOADERS, LAZY_COMMAND_NAMES, loadView, loadInspect, loadFeedback, loadCommands, loadHooks, loadSkills, loadRules, loadMemory, loadPermissions, loadMcp, loadCli, loadSubagents, loadPlugins, loadWorkflows, loadWorktree, loadVersions, loadImport, loadExport, loadPackages, loadRoutines, loadMonitors, loadRun, loadFork, loadDefaults, loadSet, loadModels, loadPrune, loadTrash, loadRestore, loadDoctor, loadApply, loadStatus, loadProfiles, loadHarness, loadSecrets, loadLogin, loadWallet, loadHelper, loadMenubar, loadBeta, loadSync, loadLock, loadRefreshRules, loadDrive, loadFactory, loadUsage, loadCost, loadOutput, loadBudget, loadAlias, loadMine, loadPty, loadTmux, loadWatchdog, loadBrowser, loadComputer, loadHosts, loadLogs, loadEvents, loadAudit, loadWebhook, loadFunnel, loadSsh, loadPull, loadPush, loadRepo, loadSetup, loadUninstall, loadShare, loadSend, loadHq, loadFeed, loadActivity, loadMailboxes, } from './lib/startup/command-registry.js';
98
98
  import { applyGlobalHelpConventions } from './lib/help.js';
99
99
  import { renderWhatsNew } from './lib/whats-new.js';
100
100
  import { getCliLaunch } from './lib/cli-entry.js';
@@ -215,7 +215,7 @@ program.helpInformation = function () {
215
215
  return brandRootHelp(`Usage: agents [command] [options]
216
216
 
217
217
  Install, configure, run, and dispatch AI coding agents from one place.
218
- Works with Claude, Codex, Gemini, Cursor, OpenCode, OpenClaw, and Droid.
218
+ Works with Claude, Codex, Antigravity, Cursor, OpenCode, OpenClaw, and Droid.
219
219
 
220
220
  Quick start:
221
221
  agents setup First-time setup (interactive)
@@ -231,9 +231,8 @@ Agent versions:
231
231
  use <agent>@<version> Set the default version
232
232
  prune cleanup [target] Remove orphan resources and older duplicate version installs
233
233
  trash Inspect and restore soft-deleted version directories
234
- view [agent[@version]] List versions, or inspect one in detail
234
+ view [agent[@version]] List versions, inspect one in detail, or --merged for the cross-layer resource surface
235
235
  inspect <target> Deep details for one agent+version, or a DotAgents repo (user|system|project|alias|path)
236
- resources Show merged DotAgents resources with their winning layer
237
236
 
238
237
  Agent configuration (synced across versions):
239
238
  rules Instructions given to agents (CLAUDE.md, etc.)
@@ -268,8 +267,7 @@ Credentials and profiles:
268
267
  secrets Keychain-backed env bundles; use 'secrets exec <bundle> -- <cmd>' to inject into a subprocess
269
268
 
270
269
  Diagnostics:
271
- doctor [agent[@version]] Diagnose CLI availability, sync status, and resource divergence
272
- check CI drift gate: exit non-zero when resources are out of sync
270
+ doctor [agent[@version]] Diagnose CLI availability, sync status, and resource divergence; --check for the CI drift gate
273
271
  usage [agent] Show rate-limit and quota usage per agent
274
272
 
275
273
  Config sync:
@@ -764,7 +762,6 @@ async function registerAllEagerCommands() {
764
762
  await reg(loadShare);
765
763
  await reg(loadSend);
766
764
  await reg(loadInspect);
767
- await reg(loadResources);
768
765
  await reg(loadFeedback);
769
766
  await reg(loadCommands);
770
767
  await reg(loadHooks);
@@ -788,13 +785,13 @@ async function registerAllEagerCommands() {
788
785
  await reg(loadRun);
789
786
  await reg(loadFork);
790
787
  await reg(loadDefaults);
788
+ await reg(loadSet);
791
789
  await reg(loadModels);
792
790
  await reg(loadPrune);
793
791
  await reg(loadTrash);
794
792
  await reg(loadRestore);
795
793
  await reg(loadDoctor);
796
794
  await reg(loadApply);
797
- await reg(loadCheck);
798
795
  await reg(loadStatus);
799
796
  registerExecAliasCommand(program);
800
797
  await reg(loadProfiles);
@@ -8,13 +8,6 @@
8
8
  * Sources: https://agentclientprotocol.com/get-started/agents + vendor docs.
9
9
  */
10
10
  export const ACP_HARNESSES = {
11
- gemini: {
12
- command: 'gemini',
13
- args: ['--experimental-acp'],
14
- installHint: 'npm i -g @google/gemini-cli',
15
- confidence: 'documented',
16
- source: 'https://agentclientprotocol.com/get-started/agents',
17
- },
18
11
  claude: {
19
12
  command: 'npx',
20
13
  args: ['-y', '@zed-industries/claude-agent-acp'],