@oxygen-agent/cli 1.1014.135 → 1.1014.618

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 (292) 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 +1669 -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 +3492 -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 +17 -14
  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.js +5 -2
  248. package/node_modules/@oxygen/shared/dist/hosted-ai.d.ts +30 -0
  249. package/node_modules/@oxygen/shared/dist/hosted-ai.js +20 -0
  250. package/node_modules/@oxygen/shared/dist/knowledge-bootstrap.d.ts +6 -2
  251. package/node_modules/@oxygen/shared/dist/knowledge-seed-content.d.ts +17 -7
  252. package/node_modules/@oxygen/shared/dist/knowledge-seed-content.js +81 -17
  253. package/node_modules/@oxygen/shared/dist/langfuse.js +8 -4
  254. package/node_modules/@oxygen/shared/dist/mailbox-egress-ownership.d.ts +1 -1
  255. package/node_modules/@oxygen/shared/dist/mailbox-import.d.ts +6 -3
  256. package/node_modules/@oxygen/shared/dist/mailbox-import.js +9 -9
  257. package/node_modules/@oxygen/shared/dist/mcp-server-info.d.ts +8 -0
  258. package/node_modules/@oxygen/shared/dist/mcp-server-info.js +10 -0
  259. package/node_modules/@oxygen/shared/dist/object-storage.d.ts +10 -0
  260. package/node_modules/@oxygen/shared/dist/object-storage.js +14 -0
  261. package/node_modules/@oxygen/shared/dist/plan-limits-view.d.ts +5 -0
  262. package/node_modules/@oxygen/shared/dist/plan-limits-view.js +17 -1
  263. package/node_modules/@oxygen/shared/dist/pricing-sheet.d.ts +1 -1
  264. package/node_modules/@oxygen/shared/dist/pricing-sheet.js +1 -1
  265. package/node_modules/@oxygen/shared/dist/provider-selection.d.ts +15 -0
  266. package/node_modules/@oxygen/shared/dist/provider-selection.js +3 -0
  267. package/node_modules/@oxygen/shared/dist/repricing.d.ts +1 -1
  268. package/node_modules/@oxygen/shared/dist/repricing.js +2 -2
  269. package/node_modules/@oxygen/shared/dist/schedule-label.d.ts +6 -0
  270. package/node_modules/@oxygen/shared/dist/schedule-label.js +12 -0
  271. package/node_modules/@oxygen/shared/dist/sequence-failures.d.ts +1 -0
  272. package/node_modules/@oxygen/shared/dist/sequence-failures.js +20 -6
  273. package/node_modules/@oxygen/shared/dist/teammate-groups.d.ts +55 -0
  274. package/node_modules/@oxygen/shared/dist/teammate-groups.js +74 -0
  275. package/node_modules/@oxygen/shared/dist/teammate-messages.d.ts +52 -0
  276. package/node_modules/@oxygen/shared/dist/teammate-messages.js +88 -0
  277. package/node_modules/@oxygen/shared/dist/teammate-notes.d.ts +58 -0
  278. package/node_modules/@oxygen/shared/dist/teammate-notes.js +73 -0
  279. package/node_modules/@oxygen/shared/dist/teammate-routines.d.ts +95 -0
  280. package/node_modules/@oxygen/shared/dist/teammate-routines.js +266 -0
  281. package/node_modules/@oxygen/shared/dist/teammate-tasks.d.ts +56 -0
  282. package/node_modules/@oxygen/shared/dist/teammate-tasks.js +114 -0
  283. package/node_modules/@oxygen/shared/dist/teammates.d.ts +78 -0
  284. package/node_modules/@oxygen/shared/dist/teammates.js +140 -0
  285. package/node_modules/@oxygen/shared/dist/user-capability-routing.js +120 -0
  286. package/node_modules/@oxygen/shared/dist/version.generated.d.ts +1 -1
  287. package/node_modules/@oxygen/shared/dist/version.generated.js +1 -1
  288. package/node_modules/@oxygen/shared/dist/visual-render.d.ts +9 -1
  289. package/node_modules/@oxygen/shared/dist/visual-render.js +12 -5
  290. package/node_modules/@oxygen/shared/dist/warmup-metrics.d.ts +5 -0
  291. package/node_modules/@oxygen/shared/dist/warmup-metrics.js +44 -0
  292. package/package.json +1 -1
@@ -0,0 +1,312 @@
1
+ import { addCompactListReadFlags, appendCompactListReadQuery } from "../compact-list-flags.js";
2
+ import { collectMultiple, isUuid, parseJsonValue, readCsvOption, splitCommaList } from "../command-support.js";
3
+ import { requestOxygen } from "../http-client.js";
4
+ import { readOption } from "../util.js";
5
+ import { Command } from "commander";
6
+ async function buildBlueprintRequestBody(// skipcq: JS-R1005
7
+ slug, options) {
8
+ const body = {};
9
+ if (slug?.trim())
10
+ body.slug = slug.trim();
11
+ const filePath = readOption(options.file);
12
+ if (filePath) {
13
+ const fs = await import("node:fs/promises");
14
+ const raw = await fs.readFile(filePath, "utf8");
15
+ body.envelope = parseJsonValue(raw, "--file");
16
+ }
17
+ const fromUrl = readOption(options.fromUrl);
18
+ if (fromUrl) {
19
+ const response = await fetch(fromUrl, { headers: { Accept: "application/json" } });
20
+ if (!response.ok) {
21
+ throw new Error(`Failed to fetch blueprint from URL (${response.status} ${response.statusText}).`);
22
+ }
23
+ const payload = await response.json();
24
+ body.envelope = payload.blueprint
25
+ ?? payload.envelope
26
+ ?? payload;
27
+ }
28
+ const inputJson = readOption(options.inputJson);
29
+ if (inputJson) {
30
+ body.inputs = parseJsonValue(inputJson, "--input-json");
31
+ }
32
+ const tableRefEntries = Array.isArray(options.tableRef) ? options.tableRef : [];
33
+ if (tableRefEntries.length > 0) {
34
+ const refs = {};
35
+ for (const entry of tableRefEntries) {
36
+ const [key, value] = entry.split("=");
37
+ if (key && value)
38
+ refs[key.trim()] = value.trim();
39
+ }
40
+ if (Object.keys(refs).length > 0)
41
+ body.table_refs = refs;
42
+ }
43
+ const workflowId = readOption(options.workflowId);
44
+ if (workflowId)
45
+ body.workflow_id = workflowId;
46
+ const workflowName = readOption(options.workflowName);
47
+ if (workflowName)
48
+ body.workflow_name = workflowName;
49
+ if (!body.slug && !body.envelope) {
50
+ throw new Error("Pass a blueprint slug, --file, or --from-url.");
51
+ }
52
+ return body;
53
+ }
54
+ export function registerBlueprintsFamily(program, handleAsyncAction) {
55
+ program
56
+ .command("blueprints")
57
+ .description("Scaffolding bundles: a workflow + tables + columns + prompts as shareable JSON. For workflow-specific operating steps, start with `oxygen recipes list <goal> --json`.")
58
+ .addCommand(addCompactListReadFlags(new Command("list")
59
+ .description("List Oxygen blueprints visible in this workspace (seeds + saved).")
60
+ .argument("[query]", "Search text.")
61
+ .option("--tag <tag>", "Filter by tag.")
62
+ .option("--include-seeds", "Include the shipped seed blueprints (default true).")
63
+ .option("--no-include-seeds", "Exclude shipped seed blueprints.")
64
+ .option("--json", "Print a JSON envelope.")
65
+ .action(async (query, options, command) => {
66
+ await handleAsyncAction("blueprints list", options, () => {
67
+ const params = new URLSearchParams();
68
+ if (query)
69
+ params.set("query", query);
70
+ const tag = readOption(options.tag);
71
+ if (tag)
72
+ params.set("tag", tag);
73
+ if (options.includeSeeds === false)
74
+ params.set("include_seeds", "false");
75
+ appendCompactListReadQuery(params, command, "blueprints");
76
+ const qs = params.toString() ? `?${params.toString()}` : "";
77
+ return requestOxygen(`/api/cli/blueprints${qs}`);
78
+ });
79
+ }), "blueprints"))
80
+ .addCommand(new Command("tag")
81
+ .description("Replace a saved blueprint's workspace tags (whole set; `--tags \"\"` clears). Works on already-saved blueprints — no re-export needed. See `oxygen tags list` for the vocabulary.")
82
+ .argument("<blueprint>", "Blueprint slug or id.")
83
+ .requiredOption("--tags <tags>", "Comma-separated workspace tags (replaces the whole set; empty clears).")
84
+ .option("--json", "Print a JSON envelope.")
85
+ .action(async (blueprint, options) => {
86
+ await handleAsyncAction("blueprints tag", options, () => requestOxygen("/api/cli/blueprints/tags", {
87
+ method: "POST",
88
+ body: { blueprint, tags: splitCommaList(options.tags) },
89
+ }));
90
+ }))
91
+ .addCommand(new Command("describe")
92
+ .description("Describe one blueprint (seed or saved) by slug. The workflow's compiled bundle is left out (its size and sha256 are listed) unless --include-bundle is passed.")
93
+ .argument("<slug>", "Blueprint slug.")
94
+ .option("--include-bundle", "Include each workflow's compiled bundle (often 300k+ characters).")
95
+ .option("--json", "Print a JSON envelope.")
96
+ .action(async (slug, options) => {
97
+ await handleAsyncAction("blueprints describe", options, () => requestOxygen("/api/cli/blueprints/get", {
98
+ method: "POST",
99
+ body: { slug, ...(options.includeBundle ? { include_bundle: true } : {}) },
100
+ }));
101
+ }))
102
+ .addCommand(new Command("export")
103
+ .description("Build a portable blueprint JSON from an existing workflow.")
104
+ .requiredOption("--workflow <id>", "Workflow id or slug to export.")
105
+ .option("--tables <ids>", "Comma-separated list of table ids/slugs to bundle.")
106
+ .option("--prompts <slugs>", "Comma-separated list of prompt template slugs to bundle.")
107
+ .option("--blueprint-id <slug>", "Override the output blueprint slug.")
108
+ .option("--blueprint-name <name>", "Override the output blueprint name.")
109
+ .option("--blueprint-summary <text>", "Override the output blueprint summary.")
110
+ .option("--blueprint-tags <tags>", "Comma-separated tags for the exported blueprint.")
111
+ .option("--out <path>", "Write the exported envelope to this file path.")
112
+ .option("--json", "Print a JSON envelope.")
113
+ .action(async (options) => {
114
+ await handleAsyncAction("blueprints export", options, async () => {
115
+ const body = { workflow_id: options.workflow };
116
+ const tables = readOption(options.tables);
117
+ if (tables)
118
+ body.table_ids = readCsvOption(tables);
119
+ const prompts = readOption(options.prompts);
120
+ if (prompts)
121
+ body.prompt_slugs = readCsvOption(prompts);
122
+ const blueprintId = readOption(options.blueprintId);
123
+ if (blueprintId)
124
+ body.blueprint_id = blueprintId;
125
+ const blueprintName = readOption(options.blueprintName);
126
+ if (blueprintName)
127
+ body.blueprint_name = blueprintName;
128
+ const blueprintSummary = readOption(options.blueprintSummary);
129
+ if (blueprintSummary)
130
+ body.blueprint_summary = blueprintSummary;
131
+ const blueprintTags = readOption(options.blueprintTags);
132
+ if (blueprintTags)
133
+ body.blueprint_tags = readCsvOption(blueprintTags);
134
+ const result = await requestOxygen("/api/cli/blueprints/export", {
135
+ method: "POST",
136
+ body,
137
+ });
138
+ const outPath = readOption(options.out);
139
+ if (outPath) {
140
+ const fs = await import("node:fs/promises");
141
+ const blueprint = result.blueprint;
142
+ await fs.writeFile(outPath, JSON.stringify(blueprint, null, 2), "utf8");
143
+ }
144
+ return result;
145
+ });
146
+ }))
147
+ .addCommand(new Command("preflight")
148
+ .description("Preflight a blueprint (slug, local file, or shared URL) against this workspace. Price-aware seeds return a current runtime descriptor upper bound, live/scheduled cap scope and remediation, a zero-spend contract, and an exact apply command.")
149
+ .argument("[slug]", "Blueprint slug (for stored or seed blueprints).")
150
+ .option("--file <path>", "Read a blueprint envelope from a local JSON file.")
151
+ .option("--from-url <url>", "Fetch a shared blueprint envelope from a public Oxygen share URL.")
152
+ .option("--input-json <json>", "Seed blueprint input (parameters) as JSON.")
153
+ .option("--table-ref <ref=id...>", "Reuse an existing table for a blueprint ref (repeatable).", collectMultiple, [])
154
+ .option("--workflow-id <id>", "Reapply to an existing non-default workflow by database UUID or manifest id/slug; preflight.next preserves the exact selector you supplied, including a database UUID. The shipped LinkedIn monitor reuses its active tables and apply publishes a new disabled revision. An unmatched value previews a separate workflow.")
155
+ .option("--json", "Print a JSON envelope.")
156
+ .action(async (slug, options) => {
157
+ await handleAsyncAction("blueprints preflight", options, async () => {
158
+ const body = await buildBlueprintRequestBody(slug, options);
159
+ return requestOxygen("/api/cli/blueprints/preflight", { method: "POST", body });
160
+ });
161
+ }))
162
+ .addCommand(new Command("apply")
163
+ .description("Apply a blueprint: 0 credits and no provider calls or external writes, but creates workspace tables, columns, prompts, and a disabled workflow. Reapplying the shipped LinkedIn monitor reuses its active installed tables. It does not enable or run the workflow.")
164
+ .argument("[slug]", "Blueprint slug (for stored or seed blueprints).")
165
+ .option("--file <path>", "Read a blueprint envelope from a local JSON file.")
166
+ .option("--from-url <url>", "Fetch a shared blueprint envelope from a public Oxygen share URL.")
167
+ .option("--input-json <json>", "Seed blueprint input (parameters) as JSON.")
168
+ .option("--table-ref <ref=id...>", "Reuse an existing table for a blueprint ref (repeatable).", collectMultiple, [])
169
+ .option("--workflow-id <id>", "Target an existing workflow by database UUID or manifest id/slug. The shipped LinkedIn monitor reuses its active tables and publishes a new disabled revision; an unmatched value creates a separate workflow.")
170
+ .option("--workflow-name <name>", "Override the resulting workflow name.")
171
+ .option("--json", "Print a JSON envelope.")
172
+ .action(async (slug, options) => {
173
+ await handleAsyncAction("blueprints apply", options, async () => {
174
+ const body = await buildBlueprintRequestBody(slug, options);
175
+ return requestOxygen("/api/cli/blueprints/apply", { method: "POST", body });
176
+ });
177
+ }))
178
+ .addCommand(new Command("save")
179
+ .description("Persist a blueprint envelope into this workspace's gallery.")
180
+ .option("--file <path>", "Read a blueprint envelope from a local JSON file.")
181
+ .option("--slug <slug>", "Override the stored blueprint slug.")
182
+ .option("--name <name>", "Override the stored blueprint name.")
183
+ .option("--summary <text>", "Override the stored blueprint summary.")
184
+ .option("--json", "Print a JSON envelope.")
185
+ .action(async (options) => {
186
+ await handleAsyncAction("blueprints save", options, async () => {
187
+ const filePath = readOption(options.file);
188
+ if (!filePath)
189
+ throw new Error("--file is required for blueprints save");
190
+ const fs = await import("node:fs/promises");
191
+ const raw = await fs.readFile(filePath, "utf8");
192
+ const envelope = parseJsonValue(raw, "--file");
193
+ const body = { envelope };
194
+ const slug = readOption(options.slug);
195
+ if (slug)
196
+ body.slug = slug;
197
+ const name = readOption(options.name);
198
+ if (name)
199
+ body.name = name;
200
+ const summary = readOption(options.summary);
201
+ if (summary)
202
+ body.summary = summary;
203
+ return requestOxygen("/api/cli/blueprints/save", { method: "POST", body });
204
+ });
205
+ }))
206
+ .addCommand(new Command("archive")
207
+ .description("Archive a saved blueprint (seed blueprints cannot be archived).")
208
+ .argument("<id_or_slug>", "Blueprint UUID or slug.")
209
+ .option("--json", "Print a JSON envelope.")
210
+ .action(async (idOrSlug, options) => {
211
+ await handleAsyncAction("blueprints archive", options, () => requestOxygen("/api/cli/blueprints/archive", {
212
+ method: "POST",
213
+ body: isUuid(idOrSlug)
214
+ ? { id: idOrSlug }
215
+ : { slug: idOrSlug },
216
+ }));
217
+ }))
218
+ .addCommand(new Command("share")
219
+ .description("Create a public share URL for a saved blueprint (oxygen-agent.com/b/<code>).")
220
+ .argument("<slug>", "Blueprint slug or id to share.")
221
+ .option("--expires-in-days <days>", "Optional expiry (default: no expiry).")
222
+ .option("--disabled", "Create the share in disabled state.")
223
+ .option("--json", "Print a JSON envelope.")
224
+ .action(async (slug, options) => {
225
+ await handleAsyncAction("blueprints share", options, () => {
226
+ const body = { slug };
227
+ const expiresInDays = readOption(options.expiresInDays);
228
+ if (expiresInDays)
229
+ body.expires_in_days = Number(expiresInDays);
230
+ if (options.disabled)
231
+ body.enabled = false;
232
+ return requestOxygen("/api/cli/blueprints/share", { method: "POST", body });
233
+ });
234
+ }))
235
+ .addCommand(new Command("shares")
236
+ .description("List existing share URLs for this workspace.")
237
+ .option("--json", "Print a JSON envelope.")
238
+ .action(async (options) => {
239
+ await handleAsyncAction("blueprints shares", options, () => requestOxygen("/api/cli/blueprints/share"));
240
+ }))
241
+ .addCommand(new Command("unshare")
242
+ .description("Revoke a public share URL by short code.")
243
+ .argument("<code>", "Share short code (the slug after /b/ in the URL).")
244
+ .option("--json", "Print a JSON envelope.")
245
+ .action(async (code, options) => {
246
+ await handleAsyncAction("blueprints unshare", options, () => requestOxygen("/api/cli/blueprints/share/revoke", {
247
+ method: "POST",
248
+ body: { short_code: code },
249
+ }));
250
+ }))
251
+ .addCommand(new Command("publish")
252
+ .description("List a blueprint on the public Oxygen marketplace. Auto-creates a share URL if none exists.")
253
+ .argument("<slug>", "Blueprint slug to publish.")
254
+ .option("--category <name>", "Optional free-text category (e.g. outbound, enrichment).")
255
+ .option("--kind <kind>", "Listing kind: community (default) or official (Oxygen-curated; gated).")
256
+ .option("--approved", "Acknowledge the publish-safety warnings (required if the preview is not clean).")
257
+ .option("--json", "Print a JSON envelope.")
258
+ .action(async (slug, options) => {
259
+ await handleAsyncAction("blueprints publish", options, () => {
260
+ const body = { slug };
261
+ const category = readOption(options.category);
262
+ if (category)
263
+ body.category = category;
264
+ const kind = readOption(options.kind);
265
+ if (kind)
266
+ body.kind = kind;
267
+ if (options.approved)
268
+ body.approved = true;
269
+ return requestOxygen("/api/cli/blueprints/publish", { method: "POST", body });
270
+ });
271
+ }))
272
+ .addCommand(new Command("unpublish")
273
+ .description("Remove a blueprint from the public marketplace. The share URL stays valid for direct visitors.")
274
+ .argument("<slug>", "Blueprint slug to unlist.")
275
+ .option("--json", "Print a JSON envelope.")
276
+ .action(async (slug, options) => {
277
+ await handleAsyncAction("blueprints unpublish", options, () => requestOxygen("/api/cli/blueprints/unpublish", {
278
+ method: "POST",
279
+ body: { slug },
280
+ }));
281
+ }))
282
+ .addCommand(new Command("marketplace")
283
+ .description("Browse the public Oxygen blueprint marketplace.")
284
+ .option("--category <name>", "Filter by listing category.")
285
+ .option("--kind <kind>", "Filter by listing kind: community or official.")
286
+ .option("--json", "Print a JSON envelope.")
287
+ .action(async (options) => {
288
+ await handleAsyncAction("blueprints marketplace", options, () => {
289
+ const params = new URLSearchParams();
290
+ const category = readOption(options.category);
291
+ if (category)
292
+ params.set("category", category);
293
+ const kind = readOption(options.kind);
294
+ if (kind)
295
+ params.set("kind", kind);
296
+ const qs = params.toString() ? `?${params.toString()}` : "";
297
+ return requestOxygen(`/api/blueprints/marketplace${qs}`, { requireAuth: false });
298
+ });
299
+ }))
300
+ .addHelpText("after", [
301
+ "",
302
+ "Safety:",
303
+ " list, describe, and preflight use 0 credits, make no provider calls, and do not change workspace state.",
304
+ " Price-aware preflights fetch runtime descriptor pricing, label upper bounds versus exact-shape dry runs,",
305
+ " and return the exact apply command that preserves the validated inputs.",
306
+ " export has the same workspace safety; --out only writes the named local file.",
307
+ " apply also uses 0 credits and makes no provider calls or external writes, but it creates workspace",
308
+ " tables, prompts, and a disabled workflow. Its response reports future per-run credit ceilings.",
309
+ " save, archive, tag, share, publish, and their inverse commands change workspace or publication state.",
310
+ "",
311
+ ].join("\n"));
312
+ }
@@ -0,0 +1,3 @@
1
+ import { ExtractedCommandActionHandler } from "../command-support.js";
2
+ import { Command } from "commander";
3
+ export declare function registerBudgetFamily(program: Command, handleAsyncAction: ExtractedCommandActionHandler): void;
@@ -0,0 +1,55 @@
1
+ import { readPositiveNumber } from "../command-support.js";
2
+ import { requestOxygen } from "../http-client.js";
3
+ import { readOption } from "../util.js";
4
+ import { formatPublicBudgetScopes } from "@oxygen/shared/budget-scopes";
5
+ import { Command } from "commander";
6
+ export function registerBudgetFamily(program, handleAsyncAction) {
7
+ program
8
+ .command("budget")
9
+ .description("Standing credit caps (org/table daily/monthly hard-blocks) beyond per-run max_credits.")
10
+ .addCommand(new Command("list")
11
+ .description("Read-only, 0 credits. List standing caps with each policy's current spend and remaining credits, plus plan defaults: the daily spend guard and per-run ceilings of one Agent run, trigger delivery or auto-run batch. Daily/monthly windows start at 00:00 UTC; spend counts reservations minus releases, including open holds. Scoped caps currently measure workspace-wide spend. Every spend default: `oxygen limits show`.")
12
+ .option("--scope <scope>", `Filter by scope: ${formatPublicBudgetScopes()}.`)
13
+ .option("--status <status>", "Filter by status. Defaults to all.")
14
+ .option("--json", "Print a JSON envelope.")
15
+ .action(async (options) => {
16
+ await handleAsyncAction("budget list", options, () => {
17
+ const params = new URLSearchParams();
18
+ if (readOption(options.scope))
19
+ params.set("scope", readOption(options.scope));
20
+ if (readOption(options.status))
21
+ params.set("status", readOption(options.status));
22
+ const suffix = params.toString() ? `?${params.toString()}` : "";
23
+ return requestOxygen(`/api/cli/budget${suffix}`);
24
+ });
25
+ }))
26
+ .addCommand(new Command("set")
27
+ .description("Set, raise, or lower a standing credit cap (idempotent per scope+window). Daily/monthly windows start at 00:00 UTC and count reservations minus releases; inspect current use with `oxygen budget list`.")
28
+ .requiredOption("--scope <scope>", formatPublicBudgetScopes())
29
+ .requiredOption("--window <window>", "per_run, daily, or monthly.")
30
+ .requiredOption("--max-credits <credits>", "Cap in Oxygen credits.")
31
+ .option("--scope-id <id>", "Table id/slug for --scope table (or other scope id). Omit for a scope-wide cap.")
32
+ .option("--action <action>", "warn or hard_block. Defaults to hard_block.")
33
+ .option("--json", "Print a JSON envelope.")
34
+ .action(async (options) => {
35
+ await handleAsyncAction("budget set", options, () => requestOxygen("/api/cli/budget", {
36
+ method: "POST",
37
+ body: {
38
+ scope: readOption(options.scope),
39
+ window: readOption(options.window),
40
+ max_credits: readPositiveNumber(options.maxCredits),
41
+ ...(readOption(options.scopeId) ? { scope_id: readOption(options.scopeId) } : {}),
42
+ ...(readOption(options.action) ? { action: readOption(options.action) } : {}),
43
+ },
44
+ }));
45
+ }))
46
+ .addCommand(new Command("delete")
47
+ .description("Delete a standing budget policy by id.")
48
+ .requiredOption("--id <id>", "Budget policy id.")
49
+ .option("--json", "Print a JSON envelope.")
50
+ .action(async (options) => {
51
+ await handleAsyncAction("budget delete", options, () => requestOxygen(`/api/cli/budget?id=${encodeURIComponent(readOption(options.id))}`, {
52
+ method: "DELETE",
53
+ }));
54
+ }));
55
+ }
@@ -0,0 +1,3 @@
1
+ import { ExtractedCommandActionHandler } from "../command-support.js";
2
+ import { Command } from "commander";
3
+ export declare function registerCallablesFamily(program: Command, handleAsyncAction: ExtractedCommandActionHandler): void;
@@ -0,0 +1,111 @@
1
+ import { parseJsonObject, readPositiveInt } from "../cli-values.js";
2
+ import { parseJsonArray, readPositiveNumber } from "../command-support.js";
3
+ import { requestOxygen } from "../http-client.js";
4
+ import { readOption } from "../util.js";
5
+ import { Command } from "commander";
6
+ export function registerCallablesFamily(program, handleAsyncAction) {
7
+ program
8
+ .command("callables")
9
+ .description("Publish and bind typed callable tables (reusable row-in/row-out table runs).")
10
+ .addCommand(new Command("publish")
11
+ .description("Publish an existing table as a versioned callable function.")
12
+ .argument("<table>", "Backing table id or slug.")
13
+ .requiredOption("--inputs-json <json>", "JSON array of inputs: [{column,key?,required?,description?}].")
14
+ .requiredOption("--actions-json <json>", "JSON array of executable backing-table column keys or ids.")
15
+ .requiredOption("--outputs-json <json>", "JSON array of outputs: [{column,key?,required?,description?}].")
16
+ .requiredOption("--max-credits-per-item <n>", "Default hard credit ceiling for one enrolled caller row.")
17
+ .option("--max-items <n>", "Default maximum source rows per invocation. Defaults to 100.")
18
+ .option("--slug <slug>", "Stable callable slug.")
19
+ .option("--name <name>", "Callable display name.")
20
+ .option("--description <text>", "What the callable does and when to use it.")
21
+ .option("--json", "Print a JSON envelope.")
22
+ .action(async (table, options) => {
23
+ await handleAsyncAction("callables publish", options, () => requestOxygen("/api/cli/callables", {
24
+ method: "POST",
25
+ body: {
26
+ table,
27
+ inputs: parseJsonArray(options.inputsJson),
28
+ action_columns: parseJsonArray(options.actionsJson),
29
+ outputs: parseJsonArray(options.outputsJson),
30
+ default_max_credits_per_item: readPositiveNumber(options.maxCreditsPerItem),
31
+ ...(readPositiveInt(options.maxItems) !== undefined
32
+ ? { default_max_items: readPositiveInt(options.maxItems) }
33
+ : {}),
34
+ ...(readOption(options.slug) ? { slug: readOption(options.slug) } : {}),
35
+ ...(readOption(options.name) ? { display_name: readOption(options.name) } : {}),
36
+ ...(readOption(options.description) ? { description: readOption(options.description) } : {}),
37
+ },
38
+ }));
39
+ }))
40
+ .addCommand(new Command("list")
41
+ .description("List published callable tables and their current credit posture.")
42
+ .option("--include-disabled", "Include disabled definitions.")
43
+ .option("--limit <n>", "Maximum definitions to return.")
44
+ .option("--json", "Print a JSON envelope.")
45
+ .action(async (options) => {
46
+ await handleAsyncAction("callables list", options, () => {
47
+ const params = new URLSearchParams();
48
+ if (options.includeDisabled)
49
+ params.set("include_disabled", "true");
50
+ if (readPositiveInt(options.limit) !== undefined)
51
+ params.set("limit", String(readPositiveInt(options.limit)));
52
+ const suffix = params.toString();
53
+ return requestOxygen(`/api/cli/callables${suffix ? `?${suffix}` : ""}`);
54
+ });
55
+ }))
56
+ .addCommand(new Command("describe")
57
+ .description("Describe a callable's typed input/output contract and pinned backing columns.")
58
+ .argument("<callable>", "Callable id, slug, backing table id, or backing table slug.")
59
+ .option("--include-disabled", "Allow a disabled callable.")
60
+ .option("--json", "Print a JSON envelope.")
61
+ .action(async (callable, options) => {
62
+ await handleAsyncAction("callables describe", options, () => {
63
+ const params = new URLSearchParams({ callable });
64
+ if (options.includeDisabled)
65
+ params.set("include_disabled", "true");
66
+ return requestOxygen(`/api/cli/callables?${params.toString()}`);
67
+ });
68
+ }))
69
+ .addCommand(new Command("bind")
70
+ .description("Add a callable-function column to a source table with explicit input and callback mappings.")
71
+ .argument("<table>", "Caller/source table id or slug.")
72
+ .argument("<callable>", "Callable id or slug.")
73
+ .requiredOption("--inputs-json <json>", "JSON object mapping callable input keys to source column keys.")
74
+ .requiredOption("--outputs-json <json>", "JSON object mapping callable output keys to callback target column keys.")
75
+ .option("--max-credits-per-item <n>", "Override the callable's default per-enrolled-row cap.")
76
+ .option("--overwrite-policy <policy>", "empty_only (default) or overwrite.")
77
+ .option("--key <key>", "Binding column key.")
78
+ .option("--label <label>", "Binding column label.")
79
+ .option("--json", "Print a JSON envelope.")
80
+ .action(async (table, callable, options) => {
81
+ await handleAsyncAction("callables bind", options, () => requestOxygen("/api/cli/callables/bind", {
82
+ method: "POST",
83
+ body: {
84
+ table,
85
+ callable,
86
+ input_mapping: parseJsonObject(options.inputsJson),
87
+ output_mapping: parseJsonObject(options.outputsJson),
88
+ ...(readPositiveNumber(options.maxCreditsPerItem) !== undefined
89
+ ? { max_credits_per_item: readPositiveNumber(options.maxCreditsPerItem) }
90
+ : {}),
91
+ ...(readOption(options.overwritePolicy) ? { overwrite_policy: readOption(options.overwritePolicy) } : {}),
92
+ ...(readOption(options.key) ? { key: readOption(options.key) } : {}),
93
+ ...(readOption(options.label) ? { label: readOption(options.label) } : {}),
94
+ },
95
+ }));
96
+ }))
97
+ .addCommand(new Command("enable")
98
+ .description("Enable a callable table.")
99
+ .argument("<callable>", "Callable id, slug, or backing table.")
100
+ .option("--json", "Print a JSON envelope.")
101
+ .action(async (callable, options) => {
102
+ await handleAsyncAction("callables enable", options, () => requestOxygen("/api/cli/callables/status", { method: "POST", body: { callable, status: "active" } }));
103
+ }))
104
+ .addCommand(new Command("disable")
105
+ .description("Disable new invocations without changing existing tables or in-flight runs.")
106
+ .argument("<callable>", "Callable id, slug, or backing table.")
107
+ .option("--json", "Print a JSON envelope.")
108
+ .action(async (callable, options) => {
109
+ await handleAsyncAction("callables disable", options, () => requestOxygen("/api/cli/callables/status", { method: "POST", body: { callable, status: "disabled" } }));
110
+ }));
111
+ }
@@ -0,0 +1,3 @@
1
+ import { ExtractedCommandActionHandler } from "../command-support.js";
2
+ import { Command } from "commander";
3
+ export declare function registerCapabilitiesFamily(program: Command, handleAsyncAction: ExtractedCommandActionHandler): void;
@@ -0,0 +1,44 @@
1
+ import { OXYGEN_CAPABILITY_ROUTES, getCapabilityRouteMatch, serializeCapabilityRoute } from "@oxygen/shared/capability-discovery";
2
+ import { OxygenError } from "@oxygen/shared/cli-result";
3
+ import { inferUserCapabilityRoute } from "@oxygen/shared/user-capability-routing";
4
+ import { capabilityDiscoveryRecovery } from "@oxygen/shared/user-capability-routing";
5
+ import { Command } from "commander";
6
+ export function registerCapabilitiesFamily(program, handleAsyncAction) {
7
+ program
8
+ .command("capabilities")
9
+ .description("Route an outcome to its owning OXYGEN layer and hosted primitive.")
10
+ .addCommand(new Command("search")
11
+ .description("Find the owning capability, boundary, gateways, and next hydration step.")
12
+ .argument("<query...>", "Natural-language GTM outcome.")
13
+ .option("--json", "Print a JSON envelope.")
14
+ .action(async (queryParts, options) => {
15
+ await handleAsyncAction("capabilities search", options, async () => {
16
+ const query = queryParts.join(" ");
17
+ const route = inferUserCapabilityRoute(query);
18
+ return {
19
+ query,
20
+ route: serializeCapabilityRoute(route),
21
+ hint: route
22
+ ? "Hydrate one exact CLI command with `oxygen commands get <exact-command> --json`, or one MCP tool with `oxygen_capabilities_schema`."
23
+ : capabilityDiscoveryRecovery(query, "cli"),
24
+ alternate_search_hint: `If this route does not fit the outcome, run \`oxygen skills search ${JSON.stringify(query)} --json\` for a narrower operational play.`,
25
+ };
26
+ });
27
+ }))
28
+ .addCommand(new Command("get")
29
+ .description("Hydrate one exact capability card by id.")
30
+ .argument("<capability-id>", "Capability id returned by capabilities search.")
31
+ .option("--json", "Print a JSON envelope.")
32
+ .action(async (capabilityId, options) => {
33
+ await handleAsyncAction("capabilities get", options, async () => {
34
+ const route = getCapabilityRouteMatch(capabilityId);
35
+ if (!route) {
36
+ throw new OxygenError("capability_not_found", `Unknown OXYGEN capability: ${capabilityId}`, {
37
+ details: { available_ids: OXYGEN_CAPABILITY_ROUTES.map((card) => card.id) },
38
+ exitCode: 2,
39
+ });
40
+ }
41
+ return serializeCapabilityRoute(route);
42
+ });
43
+ }));
44
+ }
@@ -0,0 +1,3 @@
1
+ import { ExtractedCommandActionHandler } from "../command-support.js";
2
+ import { Command } from "commander";
3
+ export declare function registerCellsFamily(program: Command, handleAsyncAction: ExtractedCommandActionHandler): void;
@@ -0,0 +1,94 @@
1
+ import { readPositiveInt } from "../cli-values.js";
2
+ import { requestOxygen } from "../http-client.js";
3
+ import { readOption } from "../util.js";
4
+ import { OxygenError } from "@oxygen/shared/cli-result";
5
+ import { Command } from "commander";
6
+ export function registerCellsFamily(program, handleAsyncAction) {
7
+ program
8
+ .command("cells")
9
+ .description("Workspace cell provenance commands.")
10
+ .addCommand(new Command("inspect")
11
+ .description("Inspect one cell's value, row context, and recent history.")
12
+ .argument("<table>", "Table id or slug.")
13
+ .argument("<row_id>", "Workspace row UUID.")
14
+ .argument("<column>", "Column id or key.")
15
+ .option("--history-limit <n>", "Maximum recent cell changes to include. Defaults to 10; cap 50.")
16
+ .option("--json", "Print a JSON envelope.")
17
+ .action(async (table, rowId, column, options) => {
18
+ await handleAsyncAction("cells inspect", options, () => {
19
+ const historyLimit = readPositiveInt(options.historyLimit);
20
+ return requestOxygen("/api/cli/tables/cells/inspect", {
21
+ method: "POST",
22
+ body: {
23
+ table,
24
+ row_id: rowId,
25
+ column,
26
+ ...(historyLimit ? { history_limit: historyLimit } : {}),
27
+ },
28
+ });
29
+ });
30
+ }))
31
+ .addCommand(new Command("resolve")
32
+ .description("Record what a human verified about a cell whose external write was dispatched but never confirmed. It records the outcome only; it never calls the provider again. Use not_applied when the write provably did not land (the cell becomes rerunnable) or applied when it did.")
33
+ .argument("<table>", "Table id or slug.")
34
+ .argument("<row_id>", "Workspace row UUID.")
35
+ .argument("<column>", "Column id or key.")
36
+ .requiredOption("--outcome <outcome>", "applied (the external write landed) or not_applied (it never did).")
37
+ .option("--note <text>", "Short note about how the destination was verified.")
38
+ .option("--value <json>", "JSON value read off the destination, recorded into the cell. Only valid with --outcome applied.")
39
+ .option("--json", "Print a JSON envelope.")
40
+ .action(async (table, rowId, column, options) => {
41
+ const outcome = readOption(options.outcome);
42
+ if (outcome !== "applied" && outcome !== "not_applied") {
43
+ throw new OxygenError("invalid_effect_resolution_outcome", "--outcome must be applied or not_applied.", { exitCode: 1 });
44
+ }
45
+ const rawValue = readOption(options.value);
46
+ if (rawValue !== null && outcome !== "applied") {
47
+ throw new OxygenError("invalid_effect_resolution_value", "--value is only valid with --outcome applied; a not-applied effect wrote nothing.", { exitCode: 1 });
48
+ }
49
+ // Parsed locally so a malformed --value fails with a clear message
50
+ // instead of being posted as a JSON string the server would then
51
+ // faithfully write into the cell.
52
+ let value;
53
+ if (rawValue !== null) {
54
+ try {
55
+ value = JSON.parse(rawValue);
56
+ }
57
+ catch {
58
+ throw new OxygenError("invalid_json", `--value must be valid JSON. Quote a string as '"text"'.`, { exitCode: 1 });
59
+ }
60
+ }
61
+ await handleAsyncAction("cells resolve", options, () => requestOxygen("/api/cli/tables/cells/resolve", {
62
+ method: "POST",
63
+ body: {
64
+ table,
65
+ row_id: rowId,
66
+ column,
67
+ outcome,
68
+ ...(readOption(options.note) ? { note: readOption(options.note) } : {}),
69
+ ...(rawValue !== null ? { value } : {}),
70
+ },
71
+ }));
72
+ }))
73
+ .addCommand(new Command("history")
74
+ .description("Show cell change history.")
75
+ .argument("<table>", "Table id or slug.")
76
+ .argument("<row_id>", "Workspace row UUID.")
77
+ .argument("<column>", "Column id or key.")
78
+ .option("--limit <n>", "Maximum changes to return. Defaults to 50.")
79
+ .option("--json", "Print a JSON envelope.")
80
+ .action(async (table, rowId, column, options) => {
81
+ await handleAsyncAction("cells history", options, () => {
82
+ const limit = readPositiveInt(options.limit);
83
+ return requestOxygen("/api/cli/tables/cells/history", {
84
+ method: "POST",
85
+ body: {
86
+ table,
87
+ row_id: rowId,
88
+ column,
89
+ ...(limit ? { limit } : {}),
90
+ },
91
+ });
92
+ });
93
+ }));
94
+ }
@@ -0,0 +1,3 @@
1
+ import { ExtractedCommandActionHandler } from "../command-support.js";
2
+ import { Command } from "commander";
3
+ export declare function registerColumnsFamily(program: Command, handleAsyncAction: ExtractedCommandActionHandler): void;