@oxygen-agent/cli 1.1014.136 → 1.1014.619

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 (293) hide show
  1. package/README.md +1 -1
  2. package/dist/admin-primary-providers-render.js +27 -19
  3. package/dist/cli-output.d.ts +12 -0
  4. package/dist/cli-output.js +395 -0
  5. package/dist/cli-paths.d.ts +1 -0
  6. package/dist/cli-paths.js +3 -0
  7. package/dist/cli-profile-context.d.ts +3 -0
  8. package/dist/cli-profile-context.js +13 -0
  9. package/dist/command-manifest.d.ts +15 -0
  10. package/dist/command-manifest.js +23 -1
  11. package/dist/command-support.d.ts +438 -0
  12. package/dist/command-support.js +1610 -0
  13. package/dist/commands/action-column.d.ts +3 -0
  14. package/dist/commands/action-column.js +43 -0
  15. package/dist/commands/activation.d.ts +3 -0
  16. package/dist/commands/activation.js +24 -0
  17. package/dist/commands/admin.d.ts +3 -0
  18. package/dist/commands/admin.js +347 -0
  19. package/dist/commands/ads.d.ts +3 -0
  20. package/dist/commands/ads.js +62 -0
  21. package/dist/commands/agent.d.ts +3 -0
  22. package/dist/commands/agent.js +274 -0
  23. package/dist/commands/api-keys.d.ts +3 -0
  24. package/dist/commands/api-keys.js +77 -0
  25. package/dist/commands/approvals.d.ts +3 -0
  26. package/dist/commands/approvals.js +518 -0
  27. package/dist/commands/auth.d.ts +3 -0
  28. package/dist/commands/auth.js +230 -0
  29. package/dist/commands/billing.d.ts +3 -0
  30. package/dist/commands/billing.js +357 -0
  31. package/dist/commands/blueprints.d.ts +3 -0
  32. package/dist/commands/blueprints.js +312 -0
  33. package/dist/commands/budget.d.ts +3 -0
  34. package/dist/commands/budget.js +55 -0
  35. package/dist/commands/callables.d.ts +3 -0
  36. package/dist/commands/callables.js +111 -0
  37. package/dist/commands/capabilities.d.ts +3 -0
  38. package/dist/commands/capabilities.js +44 -0
  39. package/dist/commands/cells.d.ts +3 -0
  40. package/dist/commands/cells.js +94 -0
  41. package/dist/commands/columns.d.ts +3 -0
  42. package/dist/commands/columns.js +1628 -0
  43. package/dist/commands/commands.d.ts +3 -0
  44. package/dist/commands/commands.js +45 -0
  45. package/dist/commands/comments.d.ts +3 -0
  46. package/dist/commands/comments.js +188 -0
  47. package/dist/commands/companies.d.ts +3 -0
  48. package/dist/commands/companies.js +312 -0
  49. package/dist/commands/connections.d.ts +3 -0
  50. package/dist/commands/connections.js +39 -0
  51. package/dist/commands/context.d.ts +3 -0
  52. package/dist/commands/context.js +170 -0
  53. package/dist/commands/copilot.d.ts +3 -0
  54. package/dist/commands/copilot.js +565 -0
  55. package/dist/commands/crm.d.ts +3 -0
  56. package/dist/commands/crm.js +1672 -0
  57. package/dist/commands/custom-integrations.d.ts +3 -0
  58. package/dist/commands/custom-integrations.js +140 -0
  59. package/dist/commands/dashboards.d.ts +3 -0
  60. package/dist/commands/dashboards.js +240 -0
  61. package/dist/commands/db.d.ts +3 -0
  62. package/dist/commands/db.js +190 -0
  63. package/dist/commands/deliverability.d.ts +3 -0
  64. package/dist/commands/deliverability.js +90 -0
  65. package/dist/commands/directory.d.ts +3 -0
  66. package/dist/commands/directory.js +101 -0
  67. package/dist/commands/domains.d.ts +3 -0
  68. package/dist/commands/domains.js +604 -0
  69. package/dist/commands/egress.d.ts +3 -0
  70. package/dist/commands/egress.js +130 -0
  71. package/dist/commands/email.d.ts +3 -0
  72. package/dist/commands/email.js +49 -0
  73. package/dist/commands/engagement.d.ts +3 -0
  74. package/dist/commands/engagement.js +189 -0
  75. package/dist/commands/enrich-column.d.ts +3 -0
  76. package/dist/commands/enrich-column.js +149 -0
  77. package/dist/commands/enrichment.d.ts +3 -0
  78. package/dist/commands/enrichment.js +49 -0
  79. package/dist/commands/feedback.d.ts +3 -0
  80. package/dist/commands/feedback.js +96 -0
  81. package/dist/commands/feeds.d.ts +3 -0
  82. package/dist/commands/feeds.js +486 -0
  83. package/dist/commands/find.d.ts +3 -0
  84. package/dist/commands/find.js +159 -0
  85. package/dist/commands/followers.d.ts +3 -0
  86. package/dist/commands/followers.js +39 -0
  87. package/dist/commands/formulas.d.ts +3 -0
  88. package/dist/commands/formulas.js +43 -0
  89. package/dist/commands/home.d.ts +3 -0
  90. package/dist/commands/home.js +22 -0
  91. package/dist/commands/inbox.d.ts +3 -0
  92. package/dist/commands/inbox.js +779 -0
  93. package/dist/commands/integrations.d.ts +3 -0
  94. package/dist/commands/integrations.js +290 -0
  95. package/dist/commands/knowledge.d.ts +3 -0
  96. package/dist/commands/knowledge.js +874 -0
  97. package/dist/commands/lead-sourcing.d.ts +3 -0
  98. package/dist/commands/lead-sourcing.js +52 -0
  99. package/dist/commands/limits.d.ts +3 -0
  100. package/dist/commands/limits.js +54 -0
  101. package/dist/commands/linkedin.d.ts +3 -0
  102. package/dist/commands/linkedin.js +275 -0
  103. package/dist/commands/login.d.ts +3 -0
  104. package/dist/commands/login.js +347 -0
  105. package/dist/commands/logout.d.ts +3 -0
  106. package/dist/commands/logout.js +12 -0
  107. package/dist/commands/mailboxes.d.ts +3 -0
  108. package/dist/commands/mailboxes.js +1290 -0
  109. package/dist/commands/managed-inboxes.d.ts +3 -0
  110. package/dist/commands/managed-inboxes.js +361 -0
  111. package/dist/commands/messages.d.ts +3 -0
  112. package/dist/commands/messages.js +78 -0
  113. package/dist/commands/notetaker.d.ts +3 -0
  114. package/dist/commands/notetaker.js +79 -0
  115. package/dist/commands/observability.d.ts +3 -0
  116. package/dist/commands/observability.js +125 -0
  117. package/dist/commands/orgs.d.ts +3 -0
  118. package/dist/commands/orgs.js +237 -0
  119. package/dist/commands/people.d.ts +3 -0
  120. package/dist/commands/people.js +353 -0
  121. package/dist/commands/posts.d.ts +3 -0
  122. package/dist/commands/posts.js +139 -0
  123. package/dist/commands/profiles.d.ts +3 -0
  124. package/dist/commands/profiles.js +250 -0
  125. package/dist/commands/projects.d.ts +3 -0
  126. package/dist/commands/projects.js +94 -0
  127. package/dist/commands/prompts.d.ts +3 -0
  128. package/dist/commands/prompts.js +84 -0
  129. package/dist/commands/publishing.d.ts +3 -0
  130. package/dist/commands/publishing.js +1419 -0
  131. package/dist/commands/recipes.d.ts +3 -0
  132. package/dist/commands/recipes.js +120 -0
  133. package/dist/commands/reviews.d.ts +3 -0
  134. package/dist/commands/reviews.js +75 -0
  135. package/dist/commands/rows.d.ts +3 -0
  136. package/dist/commands/rows.js +27 -0
  137. package/dist/commands/runs.d.ts +3 -0
  138. package/dist/commands/runs.js +37 -0
  139. package/dist/commands/search.d.ts +3 -0
  140. package/dist/commands/search.js +182 -0
  141. package/dist/commands/senders.d.ts +3 -0
  142. package/dist/commands/senders.js +393 -0
  143. package/dist/commands/sequences.d.ts +3 -0
  144. package/dist/commands/sequences.js +2322 -0
  145. package/dist/commands/session.d.ts +3 -0
  146. package/dist/commands/session.js +109 -0
  147. package/dist/commands/signals.d.ts +3 -0
  148. package/dist/commands/signals.js +289 -0
  149. package/dist/commands/signup-leads.d.ts +3 -0
  150. package/dist/commands/signup-leads.js +46 -0
  151. package/dist/commands/skills.d.ts +3 -0
  152. package/dist/commands/skills.js +50 -0
  153. package/dist/commands/sourcing.d.ts +3 -0
  154. package/dist/commands/sourcing.js +27 -0
  155. package/dist/commands/status.d.ts +3 -0
  156. package/dist/commands/status.js +51 -0
  157. package/dist/commands/supabase.d.ts +3 -0
  158. package/dist/commands/supabase.js +128 -0
  159. package/dist/commands/support.d.ts +3 -0
  160. package/dist/commands/support.js +651 -0
  161. package/dist/commands/suppressions.d.ts +3 -0
  162. package/dist/commands/suppressions.js +577 -0
  163. package/dist/commands/table-ingestions.d.ts +3 -0
  164. package/dist/commands/table-ingestions.js +145 -0
  165. package/dist/commands/table-runs.d.ts +3 -0
  166. package/dist/commands/table-runs.js +277 -0
  167. package/dist/commands/tables.d.ts +3 -0
  168. package/dist/commands/tables.js +3505 -0
  169. package/dist/commands/tags.d.ts +3 -0
  170. package/dist/commands/tags.js +147 -0
  171. package/dist/commands/tools.d.ts +3 -0
  172. package/dist/commands/tools.js +246 -0
  173. package/dist/commands/update.d.ts +3 -0
  174. package/dist/commands/update.js +106 -0
  175. package/dist/commands/verify.d.ts +3 -0
  176. package/dist/commands/verify.js +27 -0
  177. package/dist/commands/viewers.d.ts +3 -0
  178. package/dist/commands/viewers.js +72 -0
  179. package/dist/commands/voice.d.ts +3 -0
  180. package/dist/commands/voice.js +351 -0
  181. package/dist/commands/whatsapp.d.ts +3 -0
  182. package/dist/commands/whatsapp.js +226 -0
  183. package/dist/commands/whoami.d.ts +3 -0
  184. package/dist/commands/whoami.js +110 -0
  185. package/dist/commands/worker.d.ts +3 -0
  186. package/dist/commands/worker.js +60 -0
  187. package/dist/commands/workflows.d.ts +3 -0
  188. package/dist/commands/workflows.js +1752 -0
  189. package/dist/commands/workspace.d.ts +3 -0
  190. package/dist/commands/workspace.js +94 -0
  191. package/dist/compact-list-flags.d.ts +7 -0
  192. package/dist/compact-list-flags.js +12 -0
  193. package/dist/crm-support-flags.js +14 -5
  194. package/dist/customer-operation-commands.js +8 -6
  195. package/dist/diagnostic-uploader.d.ts +3 -1
  196. package/dist/diagnostic-uploader.js +29 -8
  197. package/dist/help.d.ts +5 -0
  198. package/dist/help.js +22 -0
  199. package/dist/index.d.ts +98 -1
  200. package/dist/index.js +331 -30719
  201. package/dist/local-module-loader.d.ts +4 -0
  202. package/dist/local-module-loader.js +156 -0
  203. package/dist/visual-commands.js +9 -5
  204. package/node_modules/@oxygen/cli-ugc/dist/commands.js +2 -2
  205. package/node_modules/@oxygen/shared/dist/agent-session-schedule.d.ts +36 -0
  206. package/node_modules/@oxygen/shared/dist/agent-session-schedule.js +69 -0
  207. package/node_modules/@oxygen/shared/dist/agent-sessions.d.ts +14 -5
  208. package/node_modules/@oxygen/shared/dist/agent-sessions.js +14 -3
  209. package/node_modules/@oxygen/shared/dist/capability-discovery.js +175 -14
  210. package/node_modules/@oxygen/shared/dist/compact-list-result.d.ts +6 -0
  211. package/node_modules/@oxygen/shared/dist/compact-list-result.js +27 -0
  212. package/node_modules/@oxygen/shared/dist/contracts/agent-sessions.d.ts +12 -1
  213. package/node_modules/@oxygen/shared/dist/contracts/agent-sessions.js +5 -2
  214. package/node_modules/@oxygen/shared/dist/contracts/browser-operations.js +4 -2
  215. package/node_modules/@oxygen/shared/dist/contracts/compact-list-reads.d.ts +57 -0
  216. package/node_modules/@oxygen/shared/dist/contracts/compact-list-reads.js +23 -0
  217. package/node_modules/@oxygen/shared/dist/contracts/crm-support.d.ts +52 -0
  218. package/node_modules/@oxygen/shared/dist/contracts/crm-support.js +43 -2
  219. package/node_modules/@oxygen/shared/dist/contracts/customer-operations.js +20 -16
  220. package/node_modules/@oxygen/shared/dist/contracts/knowledge-content-reads.js +1 -1
  221. package/node_modules/@oxygen/shared/dist/contracts/knowledge-proposal-reads.d.ts +49 -0
  222. package/node_modules/@oxygen/shared/dist/contracts/knowledge-proposal-reads.js +14 -0
  223. package/node_modules/@oxygen/shared/dist/contracts/knowledge-sync.js +1 -1
  224. package/node_modules/@oxygen/shared/dist/contracts/limits-read.js +60 -7
  225. package/node_modules/@oxygen/shared/dist/contracts/operations.d.ts +9 -1
  226. package/node_modules/@oxygen/shared/dist/contracts/operations.js +13 -5
  227. package/node_modules/@oxygen/shared/dist/contracts/publishing-reads.js +1 -1
  228. package/node_modules/@oxygen/shared/dist/contracts/teammates.d.ts +16 -0
  229. package/node_modules/@oxygen/shared/dist/contracts/teammates.js +115 -0
  230. package/node_modules/@oxygen/shared/dist/cost-estimate-view.js +21 -3
  231. package/node_modules/@oxygen/shared/dist/cost-estimate.d.ts +31 -1
  232. package/node_modules/@oxygen/shared/dist/cost-estimate.js +56 -15
  233. package/node_modules/@oxygen/shared/dist/diagnostic-credentials.d.ts +2 -0
  234. package/node_modules/@oxygen/shared/dist/diagnostic-credentials.js +2 -0
  235. package/node_modules/@oxygen/shared/dist/diagnostic-lock.js +71 -44
  236. package/node_modules/@oxygen/shared/dist/diagnostic-spool.d.ts +18 -0
  237. package/node_modules/@oxygen/shared/dist/diagnostic-spool.js +348 -0
  238. package/node_modules/@oxygen/shared/dist/diagnostic-storage-failure.d.ts +10 -0
  239. package/node_modules/@oxygen/shared/dist/diagnostic-storage-failure.js +42 -0
  240. package/node_modules/@oxygen/shared/dist/diagnostic-storage.d.ts +1 -1
  241. package/node_modules/@oxygen/shared/dist/diagnostic-storage.js +59 -213
  242. package/node_modules/@oxygen/shared/dist/diagnostics.js +3 -2
  243. package/node_modules/@oxygen/shared/dist/email-dsn.d.ts +16 -5
  244. package/node_modules/@oxygen/shared/dist/email-dsn.js +97 -1
  245. package/node_modules/@oxygen/shared/dist/emailguard-placement-probe.js +5 -0
  246. package/node_modules/@oxygen/shared/dist/enrichment-intents.js +4 -5
  247. package/node_modules/@oxygen/shared/dist/file-import.d.ts +8 -0
  248. package/node_modules/@oxygen/shared/dist/file-import.js +21 -2
  249. package/node_modules/@oxygen/shared/dist/hosted-ai.d.ts +30 -0
  250. package/node_modules/@oxygen/shared/dist/hosted-ai.js +20 -0
  251. package/node_modules/@oxygen/shared/dist/knowledge-bootstrap.d.ts +6 -2
  252. package/node_modules/@oxygen/shared/dist/knowledge-seed-content.d.ts +17 -7
  253. package/node_modules/@oxygen/shared/dist/knowledge-seed-content.js +81 -17
  254. package/node_modules/@oxygen/shared/dist/langfuse.js +8 -4
  255. package/node_modules/@oxygen/shared/dist/mailbox-egress-ownership.d.ts +1 -1
  256. package/node_modules/@oxygen/shared/dist/mailbox-import.d.ts +6 -3
  257. package/node_modules/@oxygen/shared/dist/mailbox-import.js +9 -9
  258. package/node_modules/@oxygen/shared/dist/mcp-server-info.d.ts +8 -0
  259. package/node_modules/@oxygen/shared/dist/mcp-server-info.js +10 -0
  260. package/node_modules/@oxygen/shared/dist/object-storage.d.ts +10 -0
  261. package/node_modules/@oxygen/shared/dist/object-storage.js +14 -0
  262. package/node_modules/@oxygen/shared/dist/plan-limits-view.d.ts +5 -0
  263. package/node_modules/@oxygen/shared/dist/plan-limits-view.js +17 -1
  264. package/node_modules/@oxygen/shared/dist/pricing-sheet.d.ts +1 -1
  265. package/node_modules/@oxygen/shared/dist/pricing-sheet.js +1 -1
  266. package/node_modules/@oxygen/shared/dist/provider-selection.d.ts +15 -0
  267. package/node_modules/@oxygen/shared/dist/provider-selection.js +3 -0
  268. package/node_modules/@oxygen/shared/dist/repricing.d.ts +1 -1
  269. package/node_modules/@oxygen/shared/dist/repricing.js +2 -2
  270. package/node_modules/@oxygen/shared/dist/schedule-label.d.ts +6 -0
  271. package/node_modules/@oxygen/shared/dist/schedule-label.js +12 -0
  272. package/node_modules/@oxygen/shared/dist/sequence-failures.d.ts +1 -0
  273. package/node_modules/@oxygen/shared/dist/sequence-failures.js +20 -6
  274. package/node_modules/@oxygen/shared/dist/teammate-groups.d.ts +55 -0
  275. package/node_modules/@oxygen/shared/dist/teammate-groups.js +74 -0
  276. package/node_modules/@oxygen/shared/dist/teammate-messages.d.ts +52 -0
  277. package/node_modules/@oxygen/shared/dist/teammate-messages.js +88 -0
  278. package/node_modules/@oxygen/shared/dist/teammate-notes.d.ts +58 -0
  279. package/node_modules/@oxygen/shared/dist/teammate-notes.js +73 -0
  280. package/node_modules/@oxygen/shared/dist/teammate-routines.d.ts +95 -0
  281. package/node_modules/@oxygen/shared/dist/teammate-routines.js +266 -0
  282. package/node_modules/@oxygen/shared/dist/teammate-tasks.d.ts +56 -0
  283. package/node_modules/@oxygen/shared/dist/teammate-tasks.js +114 -0
  284. package/node_modules/@oxygen/shared/dist/teammates.d.ts +78 -0
  285. package/node_modules/@oxygen/shared/dist/teammates.js +140 -0
  286. package/node_modules/@oxygen/shared/dist/user-capability-routing.js +120 -0
  287. package/node_modules/@oxygen/shared/dist/version.generated.d.ts +1 -1
  288. package/node_modules/@oxygen/shared/dist/version.generated.js +1 -1
  289. package/node_modules/@oxygen/shared/dist/visual-render.d.ts +9 -1
  290. package/node_modules/@oxygen/shared/dist/visual-render.js +12 -5
  291. package/node_modules/@oxygen/shared/dist/warmup-metrics.d.ts +5 -0
  292. package/node_modules/@oxygen/shared/dist/warmup-metrics.js +44 -0
  293. package/package.json +1 -1
@@ -0,0 +1,3 @@
1
+ import { ExtractedCommandActionHandler } from "../command-support.js";
2
+ import { Command } from "commander";
3
+ export declare function registerTagsFamily(program: Command, handleAsyncAction: ExtractedCommandActionHandler): void;
@@ -0,0 +1,147 @@
1
+ import { splitCommaList } from "../command-support.js";
2
+ import { requestOxygen } from "../http-client.js";
3
+ import { readOption } from "../util.js";
4
+ import { OxygenError } from "@oxygen/shared/cli-result";
5
+ import { TAG_COLORS } from "@oxygen/shared/select-options";
6
+ import { TAG_KINDS_PROSE } from "@oxygen/shared/tags";
7
+ import { Command } from "commander";
8
+ /**
9
+ * Build the registry patch body. An omitted field keeps its stored value; an
10
+ * explicit null clears it — so a `--clear-*` flag must send null, and a flag the
11
+ * user did not pass must send nothing at all.
12
+ */
13
+ function tagRegistryBody(options) {
14
+ const body = {};
15
+ const description = readOption(options.description);
16
+ if (options.clearDescription)
17
+ body.description = null;
18
+ else if (description !== undefined)
19
+ body.description = description;
20
+ const color = readOption(options.color);
21
+ if (options.clearColor)
22
+ body.color = null;
23
+ else if (color !== undefined)
24
+ body.color = color;
25
+ if (options.pinned && options.unpinned) {
26
+ throw new OxygenError("invalid_request", "Pass either --pinned or --unpinned, not both.", {
27
+ exitCode: 1,
28
+ });
29
+ }
30
+ if (options.pinned)
31
+ body.pinned = true;
32
+ else if (options.unpinned)
33
+ body.pinned = false;
34
+ return body;
35
+ }
36
+ export function registerTagsFamily(program, handleAsyncAction) {
37
+ program
38
+ .command("tags")
39
+ .description(`Workspace tags: one vocabulary across ${TAG_KINDS_PROSE}. Tags normalize to lowercase (trimmed, deduped, max 50 per item; any characters — nothing is slugified, so "Q3 Outbound" becomes "q3 outbound"). ATTACH with a carrier's own tag command (e.g. \`oxygen inbox tag\`, \`oxygen tables tag\`) or use \`oxygen tags attach <kind> <ref> --tags <labels>\` for Signal types, saved Dashboards, runtime Agents, and saved Ads searches. Then \`tags get <tag>\` returns every carrier with deep-links. CURATE the vocabulary here: \`tags create\` declares a tag (with a description, color, and pin) before anything carries it, \`tags update\` re-annotates one, and \`tags rename\`/\`merge\`/\`delete\` reshape it everywhere at once. Tags are free, inert metadata: attaching or removing one costs 0 credits, makes no provider call, and changes no sending, routing, or warm-up behaviour.`)
40
+ .addCommand(new Command("list")
41
+ .description("List every workspace tag with per-primitive counts, most-used first.")
42
+ .option("--json", "Print a JSON envelope.")
43
+ .action(async (options) => {
44
+ await handleAsyncAction("tags list", options, () => requestOxygen("/api/cli/tags"));
45
+ }))
46
+ .addCommand(new Command("get")
47
+ .description(`Everything carrying one tag — ${TAG_KINDS_PROSE} — each with its deep-link. In the result, ad_search_collection means a saved Ads search.`)
48
+ .argument("<tag>", "The tag (case-insensitive).")
49
+ .option("--json", "Print a JSON envelope.")
50
+ .action(async (tag, options) => {
51
+ await handleAsyncAction("tags get", options, () =>
52
+ // Explicit receivers retain the existing reserved-label read hints;
53
+ // they are customer reads, not aliases of the normal footprint.
54
+ requestOxygen(tag === "bulk" ? "/api/cli/tags/bulk"
55
+ : tag === "rename" ? "/api/cli/tags/rename"
56
+ : `/api/cli/tags/${encodeURIComponent(tag)}`));
57
+ }))
58
+ .addCommand(new Command("rename")
59
+ .description("Rename one tag EVERYWHERE it appears (every primitive, archived rows included). Preview-first: without --apply, prints per-kind would-change counts and mutates nothing. Idempotent — safe to re-run after a partial failure.")
60
+ .argument("<from>", "The current tag (case-insensitive).")
61
+ .argument("<to>", "The new tag (normalized lowercase).")
62
+ .option("--apply", "Execute the rename. Without this flag, returns a preview of the counts only.")
63
+ .option("--json", "Print a JSON envelope.")
64
+ .action(async (from, to, options) => {
65
+ await handleAsyncAction("tags rename", options, () => requestOxygen("/api/cli/tags/rename", {
66
+ method: "POST",
67
+ body: { from, to, ...(options.apply ? { apply: true } : {}) },
68
+ }));
69
+ }))
70
+ .addCommand(new Command("create")
71
+ .description("Declare a tag before anything carries it, with an optional description, color, and pin. Idempotent: run it on a tag already in use to annotate it — carriers are never touched.")
72
+ .argument("<label>", "The tag (normalized to lowercase; spaces are kept, nothing is slugified).")
73
+ .option("--description <text>", "What this tag means in this workspace.")
74
+ .option("--color <color>", `Pill color. One of: ${TAG_COLORS.join(", ")}. Omit to derive it from the label.`)
75
+ .option("--pinned", "Pin it to the top of the tag list and the tag picker.")
76
+ .option("--json", "Print a JSON envelope.")
77
+ .action(async (label, options) => {
78
+ await handleAsyncAction("tags create", options, () => requestOxygen(`/api/cli/tags/${encodeURIComponent(label)}`, {
79
+ method: "POST",
80
+ body: tagRegistryBody(options),
81
+ }));
82
+ }))
83
+ .addCommand(new Command("update")
84
+ .description("Change a tag's description, color, or pin. Only the flags you pass change; use the --clear-* flags to remove a value. To change the LABEL use `tags rename`.")
85
+ .argument("<label>", "The tag (case-insensitive).")
86
+ .option("--description <text>", "Replace the description.")
87
+ .option("--clear-description", "Remove the description.")
88
+ .option("--color <color>", `Replace the color. One of: ${TAG_COLORS.join(", ")}.`)
89
+ .option("--clear-color", "Remove the color override and derive it from the label again.")
90
+ // NOT --no-pinned: Commander treats a declared --no-x as making x default
91
+ // to true, which would silently pin every tag created without a flag.
92
+ .option("--pinned", "Pin the tag.")
93
+ .option("--unpinned", "Unpin the tag.")
94
+ .option("--json", "Print a JSON envelope.")
95
+ .action(async (label, options) => {
96
+ await handleAsyncAction("tags update", options, () => requestOxygen(`/api/cli/tags/${encodeURIComponent(label)}`, {
97
+ method: "POST",
98
+ body: tagRegistryBody(options),
99
+ }));
100
+ }))
101
+ .addCommand(new Command("merge")
102
+ .description("Merge one or more tags into a single target, EVERYWHERE they appear (archived rows included). Preview-first: without --apply, prints per-kind and per-tag would-change counts and mutates nothing. Idempotent — safe to re-run after a partial failure.")
103
+ .argument("<from...>", "The tags to merge away (case-insensitive).")
104
+ .requiredOption("--into <tag>", "The surviving tag.")
105
+ .option("--apply", "Execute the merge. Without this flag, returns a preview of the counts only.")
106
+ .option("--json", "Print a JSON envelope.")
107
+ .action(async (from, options) => {
108
+ await handleAsyncAction("tags merge", options, () => requestOxygen("/api/cli/tags/bulk", {
109
+ method: "POST",
110
+ body: {
111
+ action: "merge",
112
+ tags: from,
113
+ into: readOption(options.into) ?? "",
114
+ ...(options.apply ? { apply: true } : {}),
115
+ },
116
+ }));
117
+ }))
118
+ .addCommand(new Command("delete")
119
+ .description("Delete one or more tags: strips them from EVERY carrier (archived and finished items included) and removes their declaration. IRREVERSIBLE. Preview-first: without --apply, prints per-kind and per-tag counts and mutates nothing. Counts can exceed what `tags list` shows, because the index hides archived items but the delete still cleans them.")
120
+ .argument("<tags...>", "The tags to delete (case-insensitive).")
121
+ .option("--apply", "Execute the delete. Without this flag, returns a preview of the counts only.")
122
+ .option("--json", "Print a JSON envelope.")
123
+ .action(async (tags, options) => {
124
+ await handleAsyncAction("tags delete", options, () => requestOxygen("/api/cli/tags/bulk", {
125
+ method: "POST",
126
+ body: { action: "delete", tags, ...(options.apply ? { apply: true } : {}) },
127
+ }));
128
+ }))
129
+ .addCommand(new Command("attach")
130
+ .description("Replace tags on a Signal type, saved Dashboard, runtime Agent, or saved Ads search. [] clears the item; no provider call is made.")
131
+ .argument("<kind>", "signal_type, dashboard, agent, or ad_search_collection")
132
+ .argument("<ref>", "Signal type key, dashboard id/slug, Agent slug, or saved Ads search id")
133
+ .requiredOption("--tags <labels>", "Comma-separated complete tag list; an empty string clears it.")
134
+ .option("--json", "Print a JSON envelope.")
135
+ .action(async (kind, ref, options) => {
136
+ const body = { tags: splitCommaList(options.tags) };
137
+ await handleAsyncAction("tags attach", options, () => {
138
+ switch (kind) {
139
+ case "signal_type": return requestOxygen(`/api/cli/signals/registry/${encodeURIComponent(ref)}/tags`, { method: "POST", body });
140
+ case "dashboard": return requestOxygen(`/api/cli/dashboards/${encodeURIComponent(ref)}/tags`, { method: "POST", body });
141
+ case "agent": return requestOxygen(`/api/cli/agent/${encodeURIComponent(ref)}/tags`, { method: "POST", body });
142
+ case "ad_search_collection": return requestOxygen(`/api/cli/ads/searches/${encodeURIComponent(ref)}/tags`, { method: "POST", body });
143
+ default: throw new Error("kind must be signal_type, dashboard, agent, or ad_search_collection");
144
+ }
145
+ });
146
+ }));
147
+ }
@@ -0,0 +1,3 @@
1
+ import { ExtractedCommandActionHandler } from "../command-support.js";
2
+ import { Command } from "commander";
3
+ export declare function registerToolsFamily(program: Command, handleAsyncAction: ExtractedCommandActionHandler): void;
@@ -0,0 +1,246 @@
1
+ import { asPayloadRecord } from "../cli-output.js";
2
+ import { parseJsonObject, readPositiveInt } from "../cli-values.js";
3
+ import { readCsvOption, readNonNegativeNumber } from "../command-support.js";
4
+ import { requestOxygen } from "../http-client.js";
5
+ import { createToolCatalogDetailCommand } from "../tool-catalog-detail-command.js";
6
+ import { addToolCatalogSearchWindowFlag, readToolCatalogSearchWindow } from "../tool-catalog-search-window.js";
7
+ import { readOption } from "../util.js";
8
+ import { Command } from "commander";
9
+ // A dry run's stdout envelope looks like a successful result — same shape, same
10
+ // `ok: true` — so in a terminal the only tell that nothing was fetched was
11
+ // `meta.mode` buried inside the payload. That is how a working provider key gets
12
+ // reported as broken: the preview comes back empty and reads as a failed live
13
+ // call. Mirror the server's preview banner on stderr, the same stdout/stderr
14
+ // split the credits receipt uses, so the machine-read envelope stays clean.
15
+ /**
16
+ * Say WHY a preview found nothing, before the preview itself.
17
+ *
18
+ * A dry run against a tool the workspace has no connection for comes back as a
19
+ * clean, successful-looking envelope whose refusal lives several levels down in
20
+ * `access.status`. Read top-down, that is indistinguishable from "this provider
21
+ * has nothing for you" — which is how a blind operator concluded a whole
22
+ * provider could never be reached. When the route states `would_execute: false`
23
+ * with a `blocked_by` list, put it on stderr in one line, next to the fix.
24
+ * Absent those fields nothing is printed, so every other tool run is unchanged.
25
+ */
26
+ function writeToolRunBlockedNotice(data) {
27
+ const payload = asPayloadRecord(data);
28
+ if (!payload || payload.would_execute !== false)
29
+ return;
30
+ const blockedBy = Array.isArray(payload.blocked_by)
31
+ ? payload.blocked_by.filter((entry) => typeof entry === "string")
32
+ : [];
33
+ if (blockedBy.length === 0)
34
+ return;
35
+ const nextAction = typeof payload.next_action === "string" ? payload.next_action : null;
36
+ process.stderr.write(`Blocked: ${blockedBy.join(", ")}${nextAction ? ` — ${nextAction}` : ""}\n`);
37
+ }
38
+ // `tools search` composes optional catalog sources (composio, custom HTTP,
39
+ // per-tool access checks) behind short timeouts; a timed-out source still
40
+ // yields a success envelope, but `partial_sources` names what's missing and
41
+ // `total_tools` can be silently understated (blind-eval finding: a cold cache
42
+ // reported 1,640 of 7,222 tools). Mirror it to stderr so the undercount is
43
+ // visible in a terminal without polluting the machine-read stdout envelope.
44
+ function writePartialSourcesWarning(data) {
45
+ if (!data || typeof data !== "object" || Array.isArray(data))
46
+ return;
47
+ const sources = data.partial_sources;
48
+ if (!Array.isArray(sources) || sources.length === 0)
49
+ return;
50
+ const names = sources.filter((source) => typeof source === "string").join(", ");
51
+ process.stderr.write(`warning: catalog sources incomplete (${names}) — totals may be understated; rerun in a few seconds for the complete catalog\n`);
52
+ }
53
+ // Distinct from a missing catalog source: the tool IS in the catalog, we just
54
+ // could not determine whether this org may run it. Reported separately so a
55
+ // flaky per-tool check never reads as "a whole vendor is missing".
56
+ function writeAccessCheckFailuresWarning(data) {
57
+ if (!data || typeof data !== "object" || Array.isArray(data))
58
+ return;
59
+ const failures = data.access_check_failures;
60
+ if (!Array.isArray(failures) || failures.length === 0)
61
+ return;
62
+ const names = failures.filter((entry) => typeof entry === "string");
63
+ const shown = names.slice(0, 3).join(", ");
64
+ const suffix = names.length > 3 ? ` and ${names.length - 3} more` : "";
65
+ process.stderr.write(`warning: availability unknown for ${names.length} tool(s) (${shown}${suffix}) — rerun 'oxygen tools check-access' for those ids\n`);
66
+ }
67
+ export function registerToolsFamily(program, handleAsyncAction) {
68
+ program
69
+ .command("tools")
70
+ .description("Find provider operations and OXYGEN columns. For one provider operation's effective price on this workspace's credential, use `tools get <tool_id> --view pricing --json`; for a request-specific quote at 0 credits and without a provider call, use `tools run <tool_id> --input-json '{}' --mode dry-run --json`. Use `tools search --for-table <table>` to price a table's enrichment columns per row.")
71
+ .addCommand(addToolCatalogSearchWindowFlag(new Command("search")
72
+ .description("Search provider operations and OXYGEN columns for 0 credits; the default list is bounded. Use `tools get <tool_id> --view pricing --json` for one workspace-effective fee, or `tools run <tool_id> --input-json '{}' --mode dry-run --json` for a 0-credit quote without a provider call. With --for-table, suggestions prices enrichments per row. If partial_sources appears, totals may be understated; rerun.")
73
+ .argument("[query]", "Search text, e.g. `web` for the Web Research Agent column and its modes (each priced in `modes`), or `email`.")
74
+ .option("--verbosity <verbosity>", "minimal, summary, or full. Defaults to minimal; hydrate one result with tools get.")
75
+ .option("--terse", "Alias for --verbosity minimal.")
76
+ .option("--all", "Return the complete matching catalog — with no query that is every provider operation (7,000+ rows). Explicit because the default is bounded to 10; with --for-table the table-scoped answer is `suggestions`, which --all does not change.")
77
+ .option("--only-runnable", "Only return tools runnable by the active organization.")
78
+ .option("--workflow-eligible", "Only return tools a hosted workflow step may call, each annotated with the canonical `workflow_effect` its manifest step must declare. This is a narrower set than the table-column catalog — use it when authoring a workflow manifest so lint cannot reject a tool at apply time.")
79
+ .option("--no-access-check", "Skip workspace availability checks for a fast catalog listing. Prices then show managed list estimates, not this workspace's effective credential fee; use tools get <tool_id> --view pricing for that. Pair with --terse for discovery sweeps.")
80
+ .option("--category <category>", "Filter by Oxygen tool category, such as company_search, people_search, research, or local.")
81
+ .option("--capability <tag>", "Filter by capability tag, such as mobile_phone.")
82
+ .option("--provider <provider>", "Filter to one exact provider id, such as blitzapi.")
83
+ .option("--limit <n>", "Maximum number of tools to return. Capped at 100.")
84
+ .option("--providers", "Also return a per-vendor summary (provider id, display name, tool count) alongside the tools.")
85
+ .option("--for-table <table>", "Table id or slug. Prices Oxygen's own column kinds, presets and waterfalls (native_columns) for that table's columns and lists deterministic suggestions first — what you can enrich here and what each costs per row, before adding anything. The envelope opens with `suggested` (each entry's price and exact add command), then `native_columns`; `tools` comes last and lists only provider operations a column can run, so leave --all off unless you want every one of them.")
86
+ .option("--favorites", "Only the catalog entries you favourited for this workspace (see tools favorite).")
87
+ .option("--table-runnable", "Only tools a table column can run.")
88
+ .option("--json", "Print a JSON envelope.")
89
+ .action(async (query, options) => {
90
+ await handleAsyncAction("tools search", options, async () => {
91
+ const params = new URLSearchParams();
92
+ params.set("query", query ?? "");
93
+ const window = readToolCatalogSearchWindow(options);
94
+ if (window.max_chars !== undefined)
95
+ params.set("max_chars", String(window.max_chars));
96
+ if (window.include_native !== undefined)
97
+ params.set("include_native", String(window.include_native));
98
+ const forTable = readOption(options.forTable);
99
+ if (forTable)
100
+ params.set("for_table", forTable);
101
+ if (options.favorites)
102
+ params.set("favorites", "true");
103
+ if (options.tableRunnable)
104
+ params.set("table_runnable", "true");
105
+ const verbosity = options.terse ? "minimal" : readOption(options.verbosity);
106
+ if (verbosity)
107
+ params.set("verbosity", verbosity);
108
+ if (options.all)
109
+ params.set("all", "true");
110
+ if (options.onlyRunnable)
111
+ params.set("only_runnable", "true");
112
+ if (options.workflowEligible)
113
+ params.set("workflow_eligible", "true");
114
+ if (options.accessCheck === false)
115
+ params.set("include_access", "false");
116
+ if (readOption(options.category))
117
+ params.set("category", readOption(options.category) ?? "");
118
+ if (readOption(options.capability))
119
+ params.set("capability", readOption(options.capability) ?? "");
120
+ if (readOption(options.provider))
121
+ params.set("provider", readOption(options.provider) ?? "");
122
+ if (options.providers)
123
+ params.set("include_providers", "true");
124
+ const limit = readPositiveInt(options.limit);
125
+ if (limit !== undefined)
126
+ params.set("limit", String(Math.min(limit, 100)));
127
+ const data = await requestOxygen(`/api/cli/tools/search?${params.toString()}`);
128
+ writePartialSourcesWarning(data);
129
+ writeAccessCheckFailuresWarning(data);
130
+ return data;
131
+ });
132
+ })))
133
+ .addCommand(createToolCatalogDetailCommand(handleAsyncAction))
134
+ .addCommand(new Command("favorite")
135
+ .description("Favourite one column-catalog entry for this workspace: a native column (find_email, preset:person_enrich, prompt:icp_fit_score_v1) or a vendor tool (tool:<tool_id>). Favourites lead every table's + Add column panel and `tools search --favorites`.")
136
+ .argument("<entry_id>", "Catalog entry id, e.g. find_email, preset:person_enrich, prompt:<key>, tool:<tool_id>.")
137
+ .option("--json", "Print a JSON envelope.")
138
+ .action(async (entryId, options) => {
139
+ await handleAsyncAction("tools favorite", options, () => requestOxygen("/api/cli/tools/favorites", {
140
+ method: "POST",
141
+ body: { entry_id: entryId, favorite: true },
142
+ }));
143
+ }))
144
+ .addCommand(new Command("unfavorite")
145
+ .description("Remove one column-catalog entry from your favourites for this workspace.")
146
+ .argument("<entry_id>", "Catalog entry id, as listed by tools favorites.")
147
+ .option("--json", "Print a JSON envelope.")
148
+ .action(async (entryId, options) => {
149
+ await handleAsyncAction("tools unfavorite", options, () => requestOxygen("/api/cli/tools/favorites", {
150
+ method: "POST",
151
+ body: { entry_id: entryId, favorite: false },
152
+ }));
153
+ }))
154
+ .addCommand(new Command("favorites")
155
+ .description("List your favourite column-catalog entries for this workspace, with each native entry's per-row price.")
156
+ .option("--json", "Print a JSON envelope.")
157
+ .action(async (options) => {
158
+ await handleAsyncAction("tools favorites", options, () => requestOxygen("/api/cli/tools/favorites"));
159
+ }))
160
+ .addCommand(new Command("enums")
161
+ .description("Provider enum catalogs for fields that accept normalized values.")
162
+ .addCommand(new Command("list")
163
+ .description("List enum catalogs for a provider (or all providers).")
164
+ .option("--provider <provider>", "Filter to a single provider, e.g. blitzapi.")
165
+ .option("--json", "Print a JSON envelope.")
166
+ .action(async (options) => {
167
+ await handleAsyncAction("tools enums list", options, () => {
168
+ const params = new URLSearchParams();
169
+ const provider = readOption(options.provider);
170
+ if (provider)
171
+ params.set("provider", provider);
172
+ const suffix = params.toString();
173
+ return requestOxygen(`/api/cli/tools/enums${suffix ? `?${suffix}` : ""}`);
174
+ });
175
+ }))
176
+ .addCommand(new Command("get")
177
+ .description("Fetch the accepted values for one provider enum catalog. Use this before drafting payloads with enumRef fields.")
178
+ .argument("<provider>", "Provider name, e.g. blitzapi.")
179
+ .argument("<enum_ref>", "Enum reference id, e.g. industry, employee_range, country_code.")
180
+ .option("-q, --query <query>", "Case-insensitive substring or token search across the catalog values.")
181
+ .option("--limit <limit>", "Maximum number of values to return. Defaults to 100. Maximum 1000.")
182
+ .option("--json", "Print a JSON envelope.")
183
+ .action(async (provider, enumRef, options) => {
184
+ await handleAsyncAction("tools enums get", options, () => {
185
+ const params = new URLSearchParams();
186
+ const query = readOption(options.query);
187
+ const limit = readOption(options.limit);
188
+ if (query)
189
+ params.set("q", query);
190
+ if (limit)
191
+ params.set("limit", limit);
192
+ const suffix = params.toString();
193
+ return requestOxygen(`/api/cli/tools/enums/${encodeURIComponent(provider)}/${encodeURIComponent(enumRef)}${suffix ? `?${suffix}` : ""}`);
194
+ });
195
+ })))
196
+ .addCommand(new Command("run")
197
+ .description("Preview or run one tool. `--mode dry-run` quotes the exact inputs at 0 credits without a provider call or data write; `--mode live` executes after any required approval and credit ceiling.")
198
+ .argument("<tool_id>", "Tool id.")
199
+ .requiredOption("--input-json <json>", "Tool input as a JSON object.")
200
+ .option("--mode <mode>", "Execution mode: live or dry-run. Dry-run costs 0 credits and makes no provider call or data write; mutating tools default to dry-run.")
201
+ .option("--credential-mode <mode>", "Credential mode: managed, user_api_key, or user_oauth.")
202
+ .option("--org <organization_id>", "Optional organization id. Must match the stored CLI token.")
203
+ .option("--org-id <organization_id>", "Optional organization id. Must match the stored CLI token.")
204
+ .option("--connection-id <connection_id>", "Specific integration connection id. Defaults to the org's active default connection.")
205
+ .option("--fields <paths>", "Comma-separated response projection paths for large tool outputs.")
206
+ .option("--return <mode>", "Legacy response shape: raw, compact, or summary. Defaults to raw.")
207
+ .option("--return-mode <mode>", "Response shape: raw, compact, or summary. Prefer summary for large search responses.")
208
+ .option("--oxygen-cursor <cursor>", "Short Oxygen cursor returned as oxygen_next_cursor by a previous tool run.")
209
+ .option("--max-credits <n>", "Credit ceiling for live paid tools; not needed for no-bill tools. 0 runs no-bill operations, which may call providers, and reuses a managed lookup's cached result for the exact same input for free (the dry run's preview.cache says whether one exists). A paid cache miss at 0 calls and charges nothing.")
210
+ .option("--approved", "Required for live paid tools and external writes after inspecting dry-run output.")
211
+ .option("--json", "Print a JSON envelope.")
212
+ .action(async (toolId, options) => {
213
+ // Zero is a real ceiling here, not a typo: /api/cli/tools/run only
214
+ // demands a positive max_credits for BILLED tools, so a documented
215
+ // no-bill operation is legitimately run with --max-credits 0. The
216
+ // positive-only reader rejected that locally, before the request.
217
+ //
218
+ // Non-negative NUMBER, not readPositiveNumberOrZero (a whole seat
219
+ // count): this command's own dry-run hint prints "--max-credits
220
+ // 24.94", so an integer reader would refuse the very command the CLI
221
+ // just told the operator to run.
222
+ const maxCredits = readNonNegativeNumber(options.maxCredits);
223
+ await handleAsyncAction("tools run", options, async () => {
224
+ const data = await requestOxygen("/api/cli/tools/run", {
225
+ method: "POST",
226
+ body: {
227
+ tool_id: toolId,
228
+ input: parseJsonObject(options.inputJson),
229
+ ...(readOption(options.mode) ? { mode: readOption(options.mode) } : {}),
230
+ ...(readOption(options.credentialMode) ? { credential_mode: readOption(options.credentialMode) } : {}),
231
+ ...(readOption(options.org) ? { org_id: readOption(options.org) } : {}),
232
+ ...(readOption(options.orgId) ? { org_id: readOption(options.orgId) } : {}),
233
+ ...(readOption(options.connectionId) ? { connection_id: readOption(options.connectionId) } : {}),
234
+ ...(readOption(options.fields) ? { fields: readCsvOption(options.fields) } : {}),
235
+ ...(readOption(options["return"]) ? { return: readOption(options["return"]) } : {}),
236
+ ...(readOption(options.returnMode) ? { return_mode: readOption(options.returnMode) } : {}),
237
+ ...(readOption(options.oxygenCursor) ? { oxygen_cursor: readOption(options.oxygenCursor) } : {}),
238
+ ...(maxCredits !== undefined ? { max_credits: maxCredits } : {}),
239
+ ...(options.approved ? { approved: true } : {}),
240
+ },
241
+ });
242
+ writeToolRunBlockedNotice(data);
243
+ return data;
244
+ });
245
+ }));
246
+ }
@@ -0,0 +1,3 @@
1
+ import { ExtractedCommandActionHandler } from "../command-support.js";
2
+ import { Command } from "commander";
3
+ export declare function registerUpdateFamily(program: Command, handleAsyncAction: ExtractedCommandActionHandler): void;
@@ -0,0 +1,106 @@
1
+ import { readAutoUpdateStatus, runBackgroundUpdate } from "../auto-update.js";
2
+ import { emitCliFailure, writeJson } from "../cli-output.js";
3
+ import { ansi, formatAutomaticSkillsInstallStatusLines } from "../command-support.js";
4
+ import { runAutomaticSkillsInstall } from "../skills.js";
5
+ import { updateCli } from "../update.js";
6
+ import { OxygenError, success } from "@oxygen/shared/cli-result";
7
+ import { Option } from "commander";
8
+ import { stdout as output } from "node:process";
9
+ async function handleUpdateAction(options) {
10
+ // The detached daily worker and the post-update skills refresh print nothing:
11
+ // their parent is gone, and the next run reports the outcome.
12
+ if (options.background) {
13
+ await runBackgroundUpdate().catch(() => undefined);
14
+ return;
15
+ }
16
+ if (options.refreshSkills) {
17
+ await runAutomaticSkillsInstall().catch(() => undefined);
18
+ return;
19
+ }
20
+ try {
21
+ const modes = [options.status, options.enableAuto, options.disableAuto].filter(Boolean).length;
22
+ if (modes > 1) {
23
+ throw new OxygenError("conflicting_flags", "Pass only one of --status, --enable-auto, or --disable-auto.", { exitCode: 2 });
24
+ }
25
+ if (modes === 1) {
26
+ const setting = options.enableAuto ? "on" : options.disableAuto ? "off" : undefined;
27
+ const status = await readAutoUpdateStatus(setting ? { setting, dryRun: options.dryRun === true } : {});
28
+ if (options.json) {
29
+ writeJson(success("update", status));
30
+ return;
31
+ }
32
+ process.stdout.write(formatAutoUpdateStatus(status));
33
+ return;
34
+ }
35
+ const result = await updateCli(options);
36
+ if (options.json) {
37
+ writeJson(success("update", result));
38
+ return;
39
+ }
40
+ process.stdout.write(formatUpdateSuccess(result));
41
+ }
42
+ catch (error) {
43
+ emitCliFailure("update", error);
44
+ }
45
+ }
46
+ function formatUpdateSuccess(result) {
47
+ const styles = ansi(output.isTTY === true && !process.env.NO_COLOR);
48
+ return [
49
+ "",
50
+ `${styles.green("[OK]")} ${styles.bold(result.dry_run ? "CLI update command ready" : "CLI update completed")}`,
51
+ "",
52
+ ` ${styles.dim("Current")} ${result.current_version}`,
53
+ ` ${styles.dim("Package")} ${result.package}`,
54
+ ` ${styles.dim("Command")} ${result.command}`,
55
+ "",
56
+ ...formatAutomaticSkillsInstallStatusLines(result.skills_install),
57
+ ].join("\n");
58
+ }
59
+ // skipcq: JS-C1002
60
+ function formatAutoUpdateStatus(status) {
61
+ const styles = ansi(output.isTTY === true && !process.env.NO_COLOR);
62
+ const auto = status.auto_update;
63
+ const latest = status.latest_version
64
+ ? `${status.latest_version}${status.update_available ? " (newer version available)" : " (up to date)"}`
65
+ : `unknown (${status.latest_error ?? "npm registry unreachable"})`;
66
+ const last = auto.last_result
67
+ ? `${auto.last_result.ok ? "updated" : "failed"} ${auto.last_result.from}${auto.last_result.to ? ` -> ${auto.last_result.to}` : ""} `
68
+ + `at ${auto.last_result.at}${auto.last_result.error ? ` (${auto.last_result.error})` : ""}`
69
+ : "none yet";
70
+ return [
71
+ "",
72
+ `${styles.bold(status.dry_run ? `Oxygen CLI updates (dry run: automatic updates would be turned ${auto.setting}; nothing saved)` : "Oxygen CLI updates")}`,
73
+ "",
74
+ ` ${styles.dim("Installed")} ${status.current_version}`,
75
+ ` ${styles.dim("Latest (npm)")} ${latest}`,
76
+ ` ${styles.dim("Automatic")} ${auto.active ? "on (checks daily; updates when the API requires it)" : auto.reason_text ?? "off"}`,
77
+ ` ${styles.dim("Last update")} ${last}`,
78
+ "",
79
+ auto.active
80
+ ? ` Turn off: ${auto.disable}`
81
+ : ` Next step: ${auto.next_step ?? "oxygen update"}`,
82
+ "",
83
+ ].join("\n");
84
+ }
85
+ export function registerUpdateFamily(program, handleAsyncAction) {
86
+ program
87
+ .command("update")
88
+ .description("Update the Oxygen CLI from npm, then refresh the Oxygen agent skills in the global skill folders of "
89
+ + "Codex, Claude Code and Cursor (OXYGEN_SKIP_SKILLS=1 skips that). The CLI also keeps itself current: "
90
+ + "once a day it installs a newer release in the background, and when the API says it is too old it "
91
+ + "updates and re-runs your command. Automatic updates need a global npm install (npm install -g "
92
+ + "@oxygen-agent/cli); they are off for npx and project-local installs, under CI, for development builds, "
93
+ + "and after --disable-auto or OXYGEN_NO_AUTO_UPDATE=1.")
94
+ .option("--status", "Show the installed and newest published version and whether automatic updates are on.")
95
+ .option("--enable-auto", "Turn automatic updates on for this computer.")
96
+ .option("--disable-auto", "Turn automatic updates off for this computer, e.g. on a build server that must stay pinned.")
97
+ .option("--package <npm_spec>", "Install this npm spec instead of the latest, e.g. @oxygen-agent/cli@1.1010.721. To pin a build server, "
98
+ + "install the version you want and turn automatic updates off.")
99
+ .option("--dry-run", "Print the update command without running it; with --enable-auto or --disable-auto, show the result without saving it.")
100
+ .option("--json", "Print a JSON envelope.")
101
+ .addOption(new Option("--background", "Run the daily automatic update check.").hideHelp())
102
+ .addOption(new Option("--refresh-skills", "Refresh product skills after an automatic update.").hideHelp())
103
+ .action(async (options) => {
104
+ await handleUpdateAction(options);
105
+ });
106
+ }
@@ -0,0 +1,3 @@
1
+ import { ExtractedCommandActionHandler } from "../command-support.js";
2
+ import { Command } from "commander";
3
+ export declare function registerVerifyFamily(program: Command, handleAsyncAction: ExtractedCommandActionHandler): void;
@@ -0,0 +1,27 @@
1
+ import { readPositiveNumber } from "../command-support.js";
2
+ import { requestOxygen } from "../http-client.js";
3
+ import { Command } from "commander";
4
+ export function registerVerifyFamily(program, handleAsyncAction) {
5
+ program
6
+ .command("verify")
7
+ .description("Check whether emails you already have are safe to send to. dry_run previews the provider chain for free; live spends and needs --max-credits.")
8
+ .addCommand(new Command("email")
9
+ .description("Verify one or more email addresses. MillionVerifier answers first; eligible catch-all (accept-all) addresses escalate to BounceBan when available. Returns valid / invalid / catch_all / unknown per address. If escalation cannot run, catch_all stays unconfirmed; escalation_unavailable_reason and next_action explain why. On the managed lane, Oxygen staff own dry provider balances, credential repair and hold release; workspace credits do not fix those blockers. A free preview reports an availability snapshot, not guaranteed live readiness. See https://oxygen-agent.com/docs/providers/email-verification and the oxygen-enrichment skill (`oxygen skills get oxygen-enrichment --file references/verification.md --json`).")
10
+ .argument("<emails...>", "One or more email addresses to verify.")
11
+ .option("--mode <mode>", "dry_run (default) previews the plan and spends nothing; live spends credits and returns the answer.")
12
+ .option("--approved", "Same as --mode live. Accepted because the global help footer names --approved as the way to authorize a credit-spending command.")
13
+ .option("--max-credits <credits>", "Spend ceiling for the whole run. Required for --mode live. The free dry_run returns estimate.recommended_max_credits, which covers the estimated maximum subject to live provider availability and eligibility; it is a ceiling, not a charge or a guaranteed verdict. Re-verifying the exact same address in this workspace replays MillionVerifier's first pass free for up to 30 days, so a repeat run can report credits_used 0 — catch-all escalation is never cached, and its reservation is released in full when that call returns no verdict.")
14
+ .option("--json", "Print a JSON envelope.")
15
+ .action(async (emails, options) => {
16
+ await handleAsyncAction("verify email", options, () => requestOxygen("/api/cli/verify/run", {
17
+ method: "POST",
18
+ body: {
19
+ emails,
20
+ mode: options.mode === "live" || options.approved === true ? "live" : "dry_run",
21
+ ...(readPositiveNumber(options.maxCredits) !== undefined
22
+ ? { max_credits: readPositiveNumber(options.maxCredits) }
23
+ : {}),
24
+ },
25
+ }));
26
+ }));
27
+ }
@@ -0,0 +1,3 @@
1
+ import { ExtractedCommandActionHandler } from "../command-support.js";
2
+ import { Command } from "commander";
3
+ export declare function registerViewersFamily(program: Command, handleAsyncAction: ExtractedCommandActionHandler): void;