@phnx-labs/agents-cli 1.20.72 → 1.20.74

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 (234) hide show
  1. package/CHANGELOG.md +395 -0
  2. package/README.md +40 -4
  3. package/dist/bin/agents +0 -0
  4. package/dist/commands/activity.d.ts +12 -0
  5. package/dist/commands/activity.js +68 -0
  6. package/dist/commands/apply.d.ts +13 -0
  7. package/dist/commands/apply.js +28 -3
  8. package/dist/commands/browser.js +1 -1
  9. package/dist/commands/cloud.js +21 -11
  10. package/dist/commands/doctor.js +21 -5
  11. package/dist/commands/events.d.ts +11 -10
  12. package/dist/commands/events.js +30 -21
  13. package/dist/commands/exec.d.ts +34 -0
  14. package/dist/commands/exec.js +337 -39
  15. package/dist/commands/export.d.ts +11 -0
  16. package/dist/commands/export.js +215 -0
  17. package/dist/commands/feed.d.ts +13 -0
  18. package/dist/commands/feed.js +130 -29
  19. package/dist/commands/hq.d.ts +2 -0
  20. package/dist/commands/hq.js +58 -0
  21. package/dist/commands/import.js +51 -3
  22. package/dist/commands/lease.d.ts +19 -0
  23. package/dist/commands/lease.js +138 -11
  24. package/dist/commands/login.d.ts +2 -0
  25. package/dist/commands/login.js +123 -0
  26. package/dist/commands/logs.js +1 -1
  27. package/dist/commands/mine.d.ts +27 -0
  28. package/dist/commands/mine.js +207 -0
  29. package/dist/commands/monitors.js +79 -49
  30. package/dist/commands/plugins.js +1 -0
  31. package/dist/commands/profiles.js +158 -0
  32. package/dist/commands/repo.js +2 -60
  33. package/dist/commands/resources.d.ts +5 -0
  34. package/dist/commands/resources.js +95 -0
  35. package/dist/commands/routines.d.ts +2 -0
  36. package/dist/commands/routines.js +139 -37
  37. package/dist/commands/secrets.js +234 -47
  38. package/dist/commands/send.d.ts +15 -0
  39. package/dist/commands/send.js +62 -0
  40. package/dist/commands/sessions-tail.d.ts +1 -0
  41. package/dist/commands/sessions-tail.js +20 -9
  42. package/dist/commands/sessions.js +18 -3
  43. package/dist/commands/setup-mine.d.ts +18 -0
  44. package/dist/commands/setup-mine.js +106 -0
  45. package/dist/commands/setup-share.js +2 -2
  46. package/dist/commands/setup.js +9 -2
  47. package/dist/commands/share.d.ts +8 -1
  48. package/dist/commands/share.js +122 -37
  49. package/dist/commands/ssh.d.ts +9 -0
  50. package/dist/commands/ssh.js +196 -26
  51. package/dist/commands/sync.js +1 -1
  52. package/dist/commands/teams.js +11 -2
  53. package/dist/commands/versions.js +36 -5
  54. package/dist/commands/view.js +75 -27
  55. package/dist/index.js +80 -10
  56. package/dist/lib/activity.d.ts +124 -0
  57. package/dist/lib/activity.js +542 -0
  58. package/dist/lib/agents.d.ts +35 -0
  59. package/dist/lib/agents.js +79 -6
  60. package/dist/lib/artifact-actions.d.ts +1 -1
  61. package/dist/lib/artifact-actions.js +1 -1
  62. package/dist/lib/ask-classifier.d.ts +2 -1
  63. package/dist/lib/ask-classifier.js +3 -3
  64. package/dist/lib/auth-health.d.ts +32 -4
  65. package/dist/lib/auth-health.js +40 -1
  66. package/dist/lib/auto-pull.js +8 -1
  67. package/dist/lib/brand.d.ts +40 -0
  68. package/dist/lib/brand.js +122 -0
  69. package/dist/lib/browser/drivers/ssh.js +4 -7
  70. package/dist/lib/browser/service.js +6 -8
  71. package/dist/lib/channels/providers/index.d.ts +2 -0
  72. package/dist/lib/channels/providers/index.js +20 -0
  73. package/dist/lib/channels/providers/mailbox.d.ts +2 -0
  74. package/dist/lib/channels/providers/mailbox.js +26 -0
  75. package/dist/lib/channels/providers/openclaw-telegram.d.ts +2 -0
  76. package/dist/lib/channels/providers/openclaw-telegram.js +34 -0
  77. package/dist/lib/channels/providers/rush.d.ts +6 -0
  78. package/dist/lib/channels/providers/rush.js +55 -0
  79. package/dist/lib/channels/registry.d.ts +42 -0
  80. package/dist/lib/channels/registry.js +20 -0
  81. package/dist/lib/channels/resolve.d.ts +11 -0
  82. package/dist/lib/channels/resolve.js +12 -0
  83. package/dist/lib/cli-resources.d.ts +18 -0
  84. package/dist/lib/cli-resources.js +53 -4
  85. package/dist/lib/cloud/codex.js +6 -3
  86. package/dist/lib/cloud/factory.d.ts +1 -0
  87. package/dist/lib/cloud/factory.js +10 -4
  88. package/dist/lib/cloud/rush.d.ts +3 -1
  89. package/dist/lib/cloud/rush.js +6 -1
  90. package/dist/lib/cloud/types.d.ts +2 -0
  91. package/dist/lib/codex-home.d.ts +35 -0
  92. package/dist/lib/codex-home.js +136 -0
  93. package/dist/lib/config-transfer.d.ts +16 -0
  94. package/dist/lib/config-transfer.js +56 -0
  95. package/dist/lib/crabbox/cli.d.ts +44 -0
  96. package/dist/lib/crabbox/cli.js +120 -20
  97. package/dist/lib/crabbox/lease.d.ts +52 -1
  98. package/dist/lib/crabbox/lease.js +117 -16
  99. package/dist/lib/crabbox/progress.d.ts +31 -0
  100. package/dist/lib/crabbox/progress.js +76 -0
  101. package/dist/lib/crabbox/runtimes.d.ts +4 -0
  102. package/dist/lib/crabbox/runtimes.js +33 -8
  103. package/dist/lib/crabbox/setup-copy.d.ts +87 -0
  104. package/dist/lib/crabbox/setup-copy.js +127 -0
  105. package/dist/lib/daemon.d.ts +5 -5
  106. package/dist/lib/daemon.js +9 -9
  107. package/dist/lib/drive-sync.js +6 -3
  108. package/dist/lib/event-stream.d.ts +36 -0
  109. package/dist/lib/event-stream.js +68 -0
  110. package/dist/lib/events.d.ts +1 -1
  111. package/dist/lib/exec.d.ts +11 -0
  112. package/dist/lib/exec.js +23 -2
  113. package/dist/lib/export.d.ts +72 -0
  114. package/dist/lib/export.js +269 -0
  115. package/dist/lib/feed-policy.d.ts +1 -1
  116. package/dist/lib/feed-policy.js +14 -9
  117. package/dist/lib/feed-ranking.d.ts +32 -0
  118. package/dist/lib/feed-ranking.js +224 -0
  119. package/dist/lib/feed.d.ts +35 -2
  120. package/dist/lib/feed.js +66 -3
  121. package/dist/lib/fleet/auth-sync.d.ts +53 -0
  122. package/dist/lib/fleet/auth-sync.js +92 -0
  123. package/dist/lib/fleet/remote-login.d.ts +187 -0
  124. package/dist/lib/fleet/remote-login.js +556 -0
  125. package/dist/lib/format.d.ts +30 -3
  126. package/dist/lib/format.js +34 -5
  127. package/dist/lib/fs-atomic.d.ts +7 -2
  128. package/dist/lib/fs-atomic.js +8 -12
  129. package/dist/lib/git.d.ts +16 -0
  130. package/dist/lib/git.js +79 -2
  131. package/dist/lib/heal.js +11 -3
  132. package/dist/lib/hosts/progress.d.ts +28 -10
  133. package/dist/lib/hosts/progress.js +79 -22
  134. package/dist/lib/hosts/remote-cmd.js +4 -0
  135. package/dist/lib/hq/floor.d.ts +87 -0
  136. package/dist/lib/hq/floor.js +226 -0
  137. package/dist/lib/import.d.ts +23 -0
  138. package/dist/lib/import.js +74 -2
  139. package/dist/lib/isolation-boundary-report.d.ts +10 -0
  140. package/dist/lib/isolation-boundary-report.js +35 -0
  141. package/dist/lib/menubar/install-menubar.js +14 -20
  142. package/dist/lib/notify.d.ts +1 -0
  143. package/dist/lib/notify.js +3 -3
  144. package/dist/lib/open-url.d.ts +2 -0
  145. package/dist/lib/open-url.js +19 -0
  146. package/dist/lib/openclaw-keychain.d.ts +56 -0
  147. package/dist/lib/openclaw-keychain.js +236 -0
  148. package/dist/lib/overdue.js +10 -0
  149. package/dist/lib/permissions.d.ts +44 -1
  150. package/dist/lib/permissions.js +284 -7
  151. package/dist/lib/project-launch.d.ts +6 -12
  152. package/dist/lib/project-launch.js +13 -228
  153. package/dist/lib/project-resources.d.ts +7 -0
  154. package/dist/lib/project-resources.js +306 -0
  155. package/dist/lib/pty-client.d.ts +27 -0
  156. package/dist/lib/pty-client.js +136 -10
  157. package/dist/lib/refresh.js +14 -10
  158. package/dist/lib/resource-profiles.d.ts +26 -0
  159. package/dist/lib/resource-profiles.js +157 -0
  160. package/dist/lib/resources/permissions.js +7 -1
  161. package/dist/lib/resources/types.d.ts +1 -1
  162. package/dist/lib/resources.d.ts +1 -1
  163. package/dist/lib/resources.js +32 -3
  164. package/dist/lib/routines.d.ts +11 -0
  165. package/dist/lib/routines.js +56 -15
  166. package/dist/lib/runner.d.ts +1 -0
  167. package/dist/lib/runner.js +66 -5
  168. package/dist/lib/secrets/bundles.d.ts +16 -3
  169. package/dist/lib/secrets/bundles.js +206 -37
  170. package/dist/lib/secrets/icloud-import.d.ts +2 -2
  171. package/dist/lib/secrets/icloud-import.js +9 -6
  172. package/dist/lib/secrets/mcp.js +1 -1
  173. package/dist/lib/secrets/vault-age-helper.d.ts +1 -0
  174. package/dist/lib/secrets/vault-age-helper.js +34 -0
  175. package/dist/lib/secrets/vault.d.ts +49 -0
  176. package/dist/lib/secrets/vault.js +397 -0
  177. package/dist/lib/self-heal/checks/path.js +3 -1
  178. package/dist/lib/self-heal/checks/shadowing.js +10 -2
  179. package/dist/lib/self-heal/checks/shims.js +19 -11
  180. package/dist/lib/session/cloud.d.ts +2 -2
  181. package/dist/lib/session/cloud.js +2 -2
  182. package/dist/lib/session/db.d.ts +4 -0
  183. package/dist/lib/session/db.js +44 -7
  184. package/dist/lib/session/discover.d.ts +2 -0
  185. package/dist/lib/session/discover.js +114 -3
  186. package/dist/lib/session/stream-render.d.ts +3 -0
  187. package/dist/lib/session/stream-render.js +130 -0
  188. package/dist/lib/session/types.d.ts +6 -0
  189. package/dist/lib/share/analytics.d.ts +13 -0
  190. package/dist/lib/share/analytics.js +45 -0
  191. package/dist/lib/share/config.d.ts +19 -5
  192. package/dist/lib/share/config.js +44 -8
  193. package/dist/lib/share/provision.d.ts +58 -6
  194. package/dist/lib/share/provision.js +97 -22
  195. package/dist/lib/share/publish.d.ts +36 -13
  196. package/dist/lib/share/publish.js +55 -8
  197. package/dist/lib/share/worker-template.js +83 -17
  198. package/dist/lib/shims.d.ts +35 -0
  199. package/dist/lib/shims.js +159 -13
  200. package/dist/lib/ssh-exec.d.ts +14 -0
  201. package/dist/lib/ssh-exec.js +57 -0
  202. package/dist/lib/staleness/detectors/hooks.js +25 -1
  203. package/dist/lib/staleness/detectors/permissions.js +66 -0
  204. package/dist/lib/staleness/detectors/workflows.js +20 -0
  205. package/dist/lib/staleness/writers/hooks.js +58 -4
  206. package/dist/lib/staleness/writers/permissions.js +2 -2
  207. package/dist/lib/staleness/writers/skills.js +1 -1
  208. package/dist/lib/staleness/writers/sources.d.ts +10 -1
  209. package/dist/lib/staleness/writers/sources.js +68 -1
  210. package/dist/lib/star-nudge.d.ts +45 -0
  211. package/dist/lib/star-nudge.js +91 -0
  212. package/dist/lib/startup/command-registry.d.ts +7 -1
  213. package/dist/lib/startup/command-registry.js +19 -3
  214. package/dist/lib/state.d.ts +2 -0
  215. package/dist/lib/state.js +17 -4
  216. package/dist/lib/subagents-registry.d.ts +2 -0
  217. package/dist/lib/subagents-registry.js +3 -0
  218. package/dist/lib/teams/parsers.js +214 -6
  219. package/dist/lib/teams/supervisor.d.ts +7 -0
  220. package/dist/lib/teams/supervisor.js +2 -1
  221. package/dist/lib/template.d.ts +1 -1
  222. package/dist/lib/template.js +1 -1
  223. package/dist/lib/triggers/webhook.js +36 -3
  224. package/dist/lib/types.d.ts +84 -0
  225. package/dist/lib/uninstall.js +1 -45
  226. package/dist/lib/version.d.ts +40 -0
  227. package/dist/lib/version.js +94 -16
  228. package/dist/lib/versions.d.ts +24 -0
  229. package/dist/lib/versions.js +269 -78
  230. package/dist/lib/workflows.d.ts +2 -0
  231. package/dist/lib/workflows.js +88 -0
  232. package/package.json +2 -1
  233. package/dist/commands/daemon.d.ts +0 -10
  234. package/dist/commands/daemon.js +0 -121
@@ -8,6 +8,7 @@
8
8
  */
9
9
  import { extractFileOpsFromBash } from './file_ops.js';
10
10
  const claudeToolUseMap = new Map();
11
+ const droidToolUseMap = new Map();
11
12
  /** Normalize a raw JSON event from any agent type into an array of unified event objects. */
12
13
  export function normalizeEvents(agentType, raw) {
13
14
  if (agentType === 'codex') {
@@ -34,12 +35,9 @@ export function normalizeEvents(agentType, raw) {
34
35
  else if (agentType === 'kimi') {
35
36
  return normalizeKimi(raw);
36
37
  }
37
- // droid (Factory AI) intentionally falls through to the generic normalizer
38
- // below: its `-o stream-json` JSONL event schema is not yet verified against
39
- // a live run (the documented `debug` format differs from stream-json). Events
40
- // still stream and render; structured tool/file categorization will be added
41
- // once a real `droid exec -o stream-json` sample is captured. Do NOT guess the
42
- // schema here — a wrong discriminator silently mislabels every event.
38
+ else if (agentType === 'droid') {
39
+ return normalizeDroid(raw);
40
+ }
43
41
  const timestamp = new Date().toISOString();
44
42
  return [{
45
43
  type: raw.type || 'unknown',
@@ -1078,6 +1076,216 @@ function normalizeKimi(raw) {
1078
1076
  timestamp: timestamp,
1079
1077
  }];
1080
1078
  }
1079
+ // --- Droid parsing ---
1080
+ // Droid's `droid exec -o stream-json` stream mirrors the Factory session JSONL
1081
+ // envelope: session_start records plus Anthropic-shaped message content blocks.
1082
+ // Tool blocks carry the actionable file path / command in `input`; result blocks
1083
+ // only carry `tool_use_id`, so keep a small id map just like normalizeClaude.
1084
+ function normalizeDroid(raw) {
1085
+ const timestamp = typeof raw?.timestamp === 'string' ? raw.timestamp : new Date().toISOString();
1086
+ if (!raw || typeof raw !== 'object') {
1087
+ return [{
1088
+ type: 'unknown',
1089
+ agent: 'droid',
1090
+ raw: raw,
1091
+ timestamp: timestamp,
1092
+ }];
1093
+ }
1094
+ const eventType = typeof raw.type === 'string' ? raw.type : 'unknown';
1095
+ if (eventType === 'session_start') {
1096
+ return [{
1097
+ type: 'init',
1098
+ agent: 'droid',
1099
+ session_id: typeof raw.id === 'string' ? raw.id : null,
1100
+ timestamp: timestamp,
1101
+ }];
1102
+ }
1103
+ if (eventType === 'result') {
1104
+ return [{
1105
+ type: 'result',
1106
+ agent: 'droid',
1107
+ status: raw.is_error === true ? 'error' : 'success',
1108
+ message: typeof raw.result === 'string' ? raw.result : undefined,
1109
+ timestamp: timestamp,
1110
+ }];
1111
+ }
1112
+ if (eventType !== 'message') {
1113
+ return [{
1114
+ type: eventType,
1115
+ agent: 'droid',
1116
+ raw: raw,
1117
+ timestamp: timestamp,
1118
+ }];
1119
+ }
1120
+ const message = raw.message || {};
1121
+ const role = message.role === 'user' ? 'user' : 'assistant';
1122
+ const blocks = message.content;
1123
+ if (typeof blocks === 'string') {
1124
+ const content = blocks.trim();
1125
+ if (!content)
1126
+ return [];
1127
+ return role === 'assistant'
1128
+ ? [{ type: 'message', agent: 'droid', content, complete: true, timestamp }]
1129
+ : [{ type: 'user_message', agent: 'droid', content, timestamp }];
1130
+ }
1131
+ if (!Array.isArray(blocks))
1132
+ return [];
1133
+ const events = [];
1134
+ for (const block of blocks) {
1135
+ if (!block || typeof block !== 'object')
1136
+ continue;
1137
+ if (block.type === 'text') {
1138
+ const text = typeof block.text === 'string' ? block.text.trim() : '';
1139
+ if (!text)
1140
+ continue;
1141
+ if (role === 'assistant') {
1142
+ events.push({
1143
+ type: 'message',
1144
+ agent: 'droid',
1145
+ content: text,
1146
+ complete: true,
1147
+ timestamp: timestamp,
1148
+ });
1149
+ }
1150
+ else if (!text.startsWith('<system-reminder>') && !text.startsWith('Hook execution:')) {
1151
+ events.push({
1152
+ type: 'user_message',
1153
+ agent: 'droid',
1154
+ content: text,
1155
+ timestamp: timestamp,
1156
+ });
1157
+ }
1158
+ continue;
1159
+ }
1160
+ if (block.type === 'thinking') {
1161
+ const thinking = typeof block.thinking === 'string' ? block.thinking.trim() : '';
1162
+ if (thinking) {
1163
+ events.push({
1164
+ type: 'thinking',
1165
+ agent: 'droid',
1166
+ content: thinking,
1167
+ timestamp: timestamp,
1168
+ });
1169
+ }
1170
+ continue;
1171
+ }
1172
+ if (block.type === 'tool_use') {
1173
+ events.push(...normalizeDroidToolUse(block, timestamp));
1174
+ continue;
1175
+ }
1176
+ if (block.type === 'tool_result') {
1177
+ const toolUseId = typeof block.tool_use_id === 'string' ? block.tool_use_id : null;
1178
+ const toolInfo = toolUseId ? droidToolUseMap.get(toolUseId) : undefined;
1179
+ if (toolUseId)
1180
+ droidToolUseMap.delete(toolUseId);
1181
+ const content = extractDroidToolResultContent(block.content);
1182
+ if (block.is_error === true) {
1183
+ events.push({
1184
+ type: 'error',
1185
+ agent: 'droid',
1186
+ tool: toolInfo?.tool,
1187
+ content: content || 'Tool execution failed',
1188
+ timestamp: timestamp,
1189
+ });
1190
+ }
1191
+ else {
1192
+ events.push({
1193
+ type: 'tool_result',
1194
+ agent: 'droid',
1195
+ tool: toolInfo?.tool,
1196
+ tool_call_id: toolUseId,
1197
+ success: true,
1198
+ content: content.length > 500 ? content.slice(0, 497) + '...' : content,
1199
+ timestamp: timestamp,
1200
+ });
1201
+ }
1202
+ }
1203
+ }
1204
+ return events;
1205
+ }
1206
+ function normalizeDroidToolUse(block, timestamp) {
1207
+ const toolName = typeof block.name === 'string' ? block.name : 'unknown';
1208
+ const toolInput = block.input && typeof block.input === 'object' ? block.input : {};
1209
+ if (typeof block.id === 'string') {
1210
+ droidToolUseMap.set(block.id, { tool: toolName, args: toolInput });
1211
+ }
1212
+ const filePath = toolInput.file_path || toolInput.path || '';
1213
+ const command = toolInput.command || '';
1214
+ if ((toolName === 'Execute' || toolName === 'Bash') && command) {
1215
+ const events = [{
1216
+ type: 'bash',
1217
+ agent: 'droid',
1218
+ tool: toolName,
1219
+ command: command,
1220
+ timestamp: timestamp,
1221
+ }];
1222
+ const [filesRead, filesWritten, filesDeleted] = extractFileOpsFromBash(command);
1223
+ for (const path of filesRead) {
1224
+ events.push({ type: 'file_read', agent: 'droid', tool: 'bash', path, command, timestamp });
1225
+ }
1226
+ for (const path of filesWritten) {
1227
+ events.push({ type: 'file_write', agent: 'droid', tool: 'bash', path, command, timestamp });
1228
+ }
1229
+ for (const path of filesDeleted) {
1230
+ events.push({ type: 'file_delete', agent: 'droid', tool: 'bash', path, command, timestamp });
1231
+ }
1232
+ return events;
1233
+ }
1234
+ if (toolName === 'Read' && filePath) {
1235
+ return [{
1236
+ type: 'file_read',
1237
+ agent: 'droid',
1238
+ tool: toolName,
1239
+ path: filePath,
1240
+ timestamp: timestamp,
1241
+ }];
1242
+ }
1243
+ if ((toolName === 'Create' || toolName === 'Write') && filePath) {
1244
+ return [{
1245
+ type: 'file_create',
1246
+ agent: 'droid',
1247
+ tool: toolName,
1248
+ path: filePath,
1249
+ timestamp: timestamp,
1250
+ }];
1251
+ }
1252
+ if ((toolName === 'Edit' || toolName === 'MultiEdit') && filePath) {
1253
+ return [{
1254
+ type: 'file_write',
1255
+ agent: 'droid',
1256
+ tool: toolName,
1257
+ path: filePath,
1258
+ timestamp: timestamp,
1259
+ }];
1260
+ }
1261
+ if ((toolName === 'Delete' || toolName === 'Remove') && filePath) {
1262
+ return [{
1263
+ type: 'file_delete',
1264
+ agent: 'droid',
1265
+ tool: toolName,
1266
+ path: filePath,
1267
+ timestamp: timestamp,
1268
+ }];
1269
+ }
1270
+ return [{
1271
+ type: 'tool_use',
1272
+ agent: 'droid',
1273
+ tool: toolName,
1274
+ args: toolInput,
1275
+ timestamp: timestamp,
1276
+ }];
1277
+ }
1278
+ function extractDroidToolResultContent(content) {
1279
+ if (typeof content === 'string')
1280
+ return content;
1281
+ if (Array.isArray(content)) {
1282
+ return content
1283
+ .filter((part) => part && typeof part === 'object' && part.type === 'text')
1284
+ .map((part) => typeof part.text === 'string' ? part.text : '')
1285
+ .join('\n');
1286
+ }
1287
+ return '';
1288
+ }
1081
1289
  // --- Antigravity parsing ---
1082
1290
  // Intentionally conservative. Antigravity's `agy` binary advertises an
1083
1291
  // `--output-format json` flag in its docs, but the released binary errors with
@@ -51,6 +51,13 @@ export interface SupervisorResult {
51
51
  waves: number;
52
52
  stoppedBy: 'drained' | 'max-waves' | 'signal' | 'callback' | 'budget';
53
53
  elapsed_ms: number;
54
+ /**
55
+ * Number of teammates in the `failed` state when the team drained. Only set
56
+ * for `stoppedBy === 'drained'`. A drained DAG means nothing is pending or
57
+ * running — NOT that everything succeeded — so callers that treat "drained"
58
+ * as success (e.g. a completion nudge) must check `failed === 0` first.
59
+ */
60
+ failed?: number;
54
61
  /** Set when `stoppedBy === 'budget'` — the breach that terminated the team. */
55
62
  budgetBreach?: BreachInfo;
56
63
  }
@@ -80,7 +80,8 @@ export async function runSupervisor(mgr, opts) {
80
80
  const afterCallback = await mgr.listByTask(team);
81
81
  const stillLive = afterCallback.some((a) => a.status === 'pending' || a.status === 'running');
82
82
  if (!stillLive) {
83
- return { waves: wave, stoppedBy: 'drained', elapsed_ms: Date.now() - startedAt };
83
+ const failed = afterCallback.filter((a) => a.status === 'failed').length;
84
+ return { waves: wave, stoppedBy: 'drained', failed, elapsed_ms: Date.now() - startedAt };
84
85
  }
85
86
  if (stopSignal) {
86
87
  return { waves: wave, stoppedBy: 'signal', elapsed_ms: Date.now() - startedAt };
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Template resolution utilities.
3
- * Ported from agents/halo/cli/pkg/template.
3
+ * Ported from the legacy agent CLI template helpers.
4
4
  *
5
5
  * Supports {{artifact.*}} and {{preflight.*}} placeholder patterns used in
6
6
  * artifact action input mappings.
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Template resolution utilities.
3
- * Ported from agents/halo/cli/pkg/template.
3
+ * Ported from the legacy agent CLI template helpers.
4
4
  *
5
5
  * Supports {{artifact.*}} and {{preflight.*}} placeholder patterns used in
6
6
  * artifact action input mappings.
@@ -77,18 +77,46 @@ function linearTeamKey(payload) {
77
77
  return typeof team?.key === 'string' ? team.key : null;
78
78
  }
79
79
  function linearLabels(payload) {
80
+ // Linear webhook bodies flatten list relations: an Issue event carries
81
+ // `data.labels` as a flat array of label objects (`[{ id, name, color }]`),
82
+ // NOT the `{ nodes: [...] }` connection shape returned by the GraphQL API.
83
+ // Reading `.nodes` here made every `--label` filter match nothing.
80
84
  const data = payload.data;
81
- const labels = data?.labels;
82
- const nodes = Array.isArray(labels?.nodes) ? labels.nodes : [];
83
- return nodes
85
+ const labels = Array.isArray(data?.labels) ? data?.labels : [];
86
+ return labels
84
87
  .map((n) => n.name)
85
88
  .filter((n) => typeof n === 'string' && n.length > 0);
86
89
  }
90
+ function githubAction(payload) {
91
+ return typeof payload.action === 'string' ? payload.action : null;
92
+ }
93
+ function githubLabels(payload) {
94
+ const names = new Set();
95
+ const add = (value) => {
96
+ if (typeof value === 'string' && value.length > 0)
97
+ names.add(value);
98
+ };
99
+ const deliveryLabel = payload.label;
100
+ add(deliveryLabel?.name);
101
+ const pr = payload.pull_request;
102
+ const prLabels = Array.isArray(pr?.labels) ? pr.labels : [];
103
+ for (const label of prLabels) {
104
+ add(label.name);
105
+ }
106
+ const issue = payload.issue;
107
+ const issueLabels = Array.isArray(issue?.labels) ? issue.labels : [];
108
+ for (const label of issueLabels) {
109
+ add(label.name);
110
+ }
111
+ return [...names];
112
+ }
87
113
  function githubTriggerMatches(trigger, webhook) {
88
114
  if (webhook.source !== 'github')
89
115
  return false;
90
116
  if (trigger.event !== webhook.event)
91
117
  return false;
118
+ if (trigger.action && githubAction(webhook.payload) !== trigger.action)
119
+ return false;
92
120
  if (trigger.repo) {
93
121
  const repo = webhookRepo(webhook.payload);
94
122
  if (!repo || repo.toLowerCase() !== trigger.repo.toLowerCase())
@@ -99,6 +127,11 @@ function githubTriggerMatches(trigger, webhook) {
99
127
  if (!branches.some((b) => b === trigger.branch))
100
128
  return false;
101
129
  }
130
+ if (trigger.label) {
131
+ const expected = trigger.label.toLowerCase();
132
+ if (!githubLabels(webhook.payload).some((name) => name.toLowerCase() === expected))
133
+ return false;
134
+ }
102
135
  return true;
103
136
  }
104
137
  function linearTriggerMatches(trigger, webhook) {
@@ -508,6 +508,29 @@ export interface VersionResources {
508
508
  permissions?: ResourcePattern[];
509
509
  mcp?: ResourcePattern[];
510
510
  }
511
+ /** Resource-kind selectors controlled by top-level resource profiles. */
512
+ export interface ResourceProfilePreset {
513
+ description?: string;
514
+ commands?: ResourcePattern[];
515
+ skills?: ResourcePattern[];
516
+ hooks?: ResourcePattern[];
517
+ subagents?: ResourcePattern[];
518
+ plugins?: ResourcePattern[];
519
+ workflows?: ResourcePattern[];
520
+ permissions?: ResourcePattern[];
521
+ mcp?: ResourcePattern[];
522
+ /** Rule preset name to compose while this profile is active. */
523
+ rules?: string;
524
+ /** Alias for rules, accepted so YAML can mirror VersionResources naming. */
525
+ rulesPreset?: string;
526
+ /** Secrets bundle names, or "*" for every bundle. */
527
+ secrets?: string[];
528
+ }
529
+ /** Top-level profiles/presets that switch the resolved resource view. */
530
+ export interface ResourceProfilesConfig {
531
+ active?: string;
532
+ presets?: Record<string, ResourceProfilePreset>;
533
+ }
511
534
  /** A userConfig field declared in a plugin manifest. */
512
535
  export interface PluginUserConfigField {
513
536
  key: string;
@@ -644,9 +667,42 @@ export interface ExtraRepoConfig {
644
667
  path?: string;
645
668
  enabled: boolean;
646
669
  }
670
+ /**
671
+ * A white-label brand — a personally-named CLI (e.g. `jack`) that IS agents-cli,
672
+ * minted by `agents setup mine` / `agents mine`. The brand's shim exports
673
+ * `AGENTS_BRAND=<name>`; the entrypoint reads it to present under this name and
674
+ * apply the customization below. Portable user config — rides `agents repo
675
+ * push/pull`. See lib/brand.ts.
676
+ */
677
+ export interface BrandConfig {
678
+ /** The brand name; also the binary name on PATH. */
679
+ name: string;
680
+ /** Built-in top-level commands this brand hides/disables (e.g. `["teams"]`). */
681
+ disabledCommands?: string[];
682
+ /**
683
+ * Resource-profile preset this brand pins (a key in `profiles.presets`). When
684
+ * the CLI runs under this brand, that preset becomes the active profile, so
685
+ * skills/plugins/mcp/hooks/etc. filter to the brand's curated set. Defaults to
686
+ * `mine-<name>`.
687
+ */
688
+ profile?: string;
689
+ /** False to keep the config but stop minting/using the brand. */
690
+ enabled: boolean;
691
+ }
647
692
  /** Top-level structure of ~/.agents/.system/agents.yaml -- the CLI's persistent state. */
648
693
  export interface Meta {
649
694
  agents?: Partial<Record<AgentId, string>>;
695
+ /**
696
+ * Per-agent preferred ISOLATED version — which copy a bare `agents run <agent>`
697
+ * resolves to when the agent has no global default.
698
+ *
699
+ * Kept separate from `agents` on purpose. An entry there is the global default,
700
+ * which owns the launcher, the bare shim and the real `~/.<agent>` config
701
+ * symlink, and arms the self-heal `shadowing` check. An isolated copy must never
702
+ * acquire any of that, so it cannot be recorded in the same place — the
703
+ * separation is what keeps `getGlobalDefault` incapable of returning one.
704
+ */
705
+ isolatedAgents?: Partial<Record<AgentId, string>>;
650
706
  run?: RunConfig;
651
707
  /**
652
708
  * `agents run --lease` config. `secretsBundle` names the keychain secrets bundle
@@ -682,6 +738,12 @@ export interface Meta {
682
738
  enabled?: BetaFeatureName[];
683
739
  };
684
740
  registries?: Record<RegistryType, Record<string, RegistryConfig>>;
741
+ /**
742
+ * Top-level resource profiles. Activating one filters the resolved resource
743
+ * set across commands, skills, hooks, rules, MCP, permissions, and secrets.
744
+ * Model-provider run profiles are separate YAML files under profiles/.
745
+ */
746
+ profiles?: ResourceProfilesConfig;
685
747
  versions?: Partial<Record<AgentId, Record<string, VersionResources>>>;
686
748
  source?: string;
687
749
  /**
@@ -696,6 +758,12 @@ export interface Meta {
696
758
  * via the `path` field.
697
759
  */
698
760
  extraRepos?: Record<string, ExtraRepoConfig>;
761
+ /**
762
+ * White-label brands keyed by name. Each mints a personally-named binary
763
+ * (e.g. `jack`) that runs agents-cli under that name with its own disabled
764
+ * commands + curated resource profile. See lib/brand.ts.
765
+ */
766
+ brands?: Record<string, BrandConfig>;
699
767
  /**
700
768
  * Keys like `skill.hermes` — registries seeded from SEEDED_REGISTRIES exactly
701
769
  * once. Tracked so a user `registry remove` won't silently re-seed.
@@ -746,6 +814,22 @@ export interface Meta {
746
814
  workerName?: string;
747
815
  bucketName?: string;
748
816
  domain?: string;
817
+ /** Cloudflare Web Analytics token injected into published HTML pages. */
818
+ analyticsToken?: string;
819
+ };
820
+ /**
821
+ * Owner/channel notification config for `agents send` / `agents notify`.
822
+ * `owner` is the default recipient for `agents notify` (channel + target).
823
+ * `transports` maps a user-facing channel name to the provider that actually
824
+ * delivers it — explicit, one provider per channel, no fallback. Omitted keys
825
+ * default to name-identity (channel `slack` -> provider `slack`).
826
+ */
827
+ notify?: {
828
+ owner?: {
829
+ channel: string;
830
+ to: string;
831
+ };
832
+ transports?: Record<string, string>;
749
833
  };
750
834
  }
751
835
  /** Persisted agent-host entry in agents.yaml (overlay or inline). */
@@ -20,6 +20,7 @@ import * as os from 'os';
20
20
  import * as path from 'path';
21
21
  import { AGENTS, ALL_AGENT_IDS } from './agents.js';
22
22
  import { getAgentConfigPath, getConfigSymlinkVersion, stripShimPathLines, releaseAdoptedLauncher, } from './shims.js';
23
+ import { moveDirCrossDevice, copyDirStrippingAgentsSymlinks } from './config-transfer.js';
23
24
  import { getUserAgentsDir, getBackupsDir, getHistoryDir, getShimsDir, getLegacySystemAgentsDir, } from './state.js';
24
25
  /** Home dir honoring the AGENTS_REAL_HOME test/override, mirroring shims.ts. */
25
26
  function realHome() {
@@ -60,51 +61,6 @@ function symlinkTarget(p) {
60
61
  function removeLink(p) {
61
62
  fs.unlinkSync(p);
62
63
  }
63
- /**
64
- * Move `source` onto `dest` across possibly-different volumes. `renameSync` is
65
- * atomic but throws EXDEV when `~/.agents` lives on a different filesystem than
66
- * `$HOME`; fall back to copy-then-remove so the restore still completes. The
67
- * source (a backup inside `~/.agents`) is removed only after the copy succeeds,
68
- * so a mid-copy failure never destroys the sole surviving copy.
69
- */
70
- function moveDirCrossDevice(source, dest) {
71
- try {
72
- fs.renameSync(source, dest);
73
- }
74
- catch (err) {
75
- if (err.code !== 'EXDEV')
76
- throw err;
77
- fs.cpSync(source, dest, { recursive: true });
78
- fs.rmSync(source, { recursive: true, force: true });
79
- }
80
- }
81
- /**
82
- * Copy `source` to `dest`, dropping any symlink whose target resolves back into
83
- * `~/.agents`. Adoption syncs managed resources (skills/commands) into the
84
- * version home as symlinks into `~/.agents`; copying them verbatim would leave
85
- * the restored config full of links that dangle the moment `~/.agents` is
86
- * disposed. Stripping them yields a clean, self-contained restore.
87
- */
88
- function copyDirStrippingAgentsSymlinks(source, dest, agentsDir) {
89
- const inside = agentsDir + path.sep;
90
- fs.cpSync(source, dest, {
91
- recursive: true,
92
- filter: (src) => {
93
- try {
94
- const st = fs.lstatSync(src);
95
- if (st.isSymbolicLink()) {
96
- const tgt = path.resolve(path.dirname(src), fs.readlinkSync(src));
97
- if (tgt === agentsDir || tgt.startsWith(inside))
98
- return false;
99
- }
100
- }
101
- catch {
102
- /* unreadable entry — let cpSync surface it on the real copy */
103
- }
104
- return true;
105
- },
106
- });
107
- }
108
64
  /** Classify one agent's config dir without mutating anything. */
109
65
  function planConfig(agent) {
110
66
  const realPath = getAgentConfigPath(agent);
@@ -1,8 +1,48 @@
1
+ /**
2
+ * Well-known locations of the `agents` launcher for PATH-less GUI/launchd
3
+ * processes (the menu-bar helper inherits no login PATH). Also the anchor for
4
+ * recovering the on-disk install layout when the CLI runs as a Bun single-file
5
+ * binary — see {@link resolveInstalledLayout}.
6
+ */
7
+ export declare function resolveAgentsBin(): string | null;
8
+ export interface InstallLayout {
9
+ /** The install's `dist/` directory (holds `index.js` + `lib/`). */
10
+ distDir: string;
11
+ /** The compiled CLI entry, `dist/index.js`. */
12
+ entryPath: string;
13
+ /** The shipping `package.json`, `dist/../package.json`. */
14
+ pkgJsonPath: string;
15
+ }
16
+ /**
17
+ * Pure derivation (no I/O) of an install's on-disk layout from the realpath of
18
+ * its `agents` launcher. A launcher lives at `<pkg>/dist/bin/agents`, so two
19
+ * levels up is `<pkg>/dist`. Exported for unit testing so the dirname chain the
20
+ * Bun-binary fallback depends on stays locked.
21
+ */
22
+ export declare function installLayoutFromBin(realBin: string): InstallLayout;
23
+ /**
24
+ * Resolve the on-disk install layout of the running CLI by following the
25
+ * `agents` launcher symlink.
26
+ *
27
+ * When the CLI runs as a Bun single-file executable, `import.meta.url` points
28
+ * inside the virtual bundle (`/$bunfs/…`), so sibling-relative resolution can't
29
+ * see the shipped `package.json`, `dist/index.js`, or `MenubarHelper.app` on
30
+ * disk. The launcher symlink points at the real files; walk up from it. Returns
31
+ * null when no launcher is found (dev/tsx runs, or a box without the helper) —
32
+ * callers keep their in-bundle resolution as the primary path and use this only
33
+ * as the fallback.
34
+ */
35
+ export declare function resolveInstalledLayout(): InstallLayout | null;
1
36
  /**
2
37
  * Resolve the CLI version from the shipping package.json. Used by the daemon
3
38
  * to answer `IPCAction: 'version'` and by the client to detect daemon drift —
4
39
  * a dev-build CLI talking to a launchd-managed registry daemon would silently
5
40
  * get stale behavior without this check.
41
+ *
42
+ * Primary read is relative to this module; when that fails (the Bun single-file
43
+ * binary can't read its own bundled package.json), fall back to the on-disk
44
+ * install found via the launcher symlink so callers like the menu bar don't see
45
+ * a bogus `unknown`.
6
46
  */
7
47
  export declare function getCliVersion(): string;
8
48
  /**