@onesi/genesis-cli 0.1.13 → 0.2.1

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 (67) hide show
  1. package/README.md +29 -2
  2. package/dist/beacons.js +68 -0
  3. package/dist/dials.js +7 -4
  4. package/dist/fleets.js +30 -0
  5. package/dist/flocks.d.ts +7 -1
  6. package/dist/flocks.js +281 -4
  7. package/dist/henry.d.ts +5 -1
  8. package/dist/henry.js +60 -1
  9. package/dist/hives-coverage.d.ts +12 -0
  10. package/dist/hives-coverage.js +133 -0
  11. package/dist/hives-node-transport.js +4 -1
  12. package/dist/hives-operations.d.ts +1 -0
  13. package/dist/hives-operations.js +2 -0
  14. package/dist/hives-platform.d.ts +13 -0
  15. package/dist/hives-platform.js +133 -0
  16. package/dist/hives-resources.d.ts +1 -0
  17. package/dist/hives-resources.js +5 -3
  18. package/dist/iam-directory.d.ts +15 -0
  19. package/dist/iam-directory.js +71 -0
  20. package/dist/index.d.ts +2 -0
  21. package/dist/index.js +273 -30
  22. package/dist/minds.d.ts +1 -1
  23. package/dist/minds.js +37 -2
  24. package/dist/onboard/art.d.ts +50 -0
  25. package/dist/onboard/art.js +139 -0
  26. package/dist/onboard/brand.d.ts +56 -0
  27. package/dist/onboard/brand.js +134 -0
  28. package/dist/onboard/caps.d.ts +90 -0
  29. package/dist/onboard/caps.js +232 -0
  30. package/dist/onboard/encode.d.ts +23 -0
  31. package/dist/onboard/encode.js +235 -0
  32. package/dist/onboard/eye.d.ts +103 -0
  33. package/dist/onboard/eye.js +147 -0
  34. package/dist/onboard/index.d.ts +61 -0
  35. package/dist/onboard/index.js +562 -0
  36. package/dist/onboard/mcp.d.ts +35 -0
  37. package/dist/onboard/mcp.js +118 -0
  38. package/dist/onboard/raster.d.ts +43 -0
  39. package/dist/onboard/raster.js +253 -0
  40. package/dist/onboard/sound.d.ts +2 -0
  41. package/dist/onboard/sound.js +54 -0
  42. package/dist/onboard/state.d.ts +24 -0
  43. package/dist/onboard/state.js +48 -0
  44. package/dist/onboard/term.d.ts +69 -0
  45. package/dist/onboard/term.js +292 -0
  46. package/dist/onboard/ui.d.ts +97 -0
  47. package/dist/onboard/ui.js +615 -0
  48. package/dist/orgs.d.ts +16 -0
  49. package/dist/orgs.js +89 -0
  50. package/dist/output.d.ts +13 -1
  51. package/dist/output.js +21 -2
  52. package/dist/products.d.ts +6 -2
  53. package/dist/products.js +474 -13
  54. package/dist/relays-commands/certificates.d.ts +3 -0
  55. package/dist/relays-commands/certificates.js +20 -0
  56. package/dist/relays-commands/domains.d.ts +3 -0
  57. package/dist/relays-commands/domains.js +23 -0
  58. package/dist/relays-commands/index.d.ts +4 -0
  59. package/dist/relays-commands/index.js +10 -0
  60. package/dist/relays-commands/monitoring.d.ts +3 -0
  61. package/dist/relays-commands/monitoring.js +41 -0
  62. package/dist/relays-commands/telemetry.d.ts +3 -0
  63. package/dist/relays-commands/telemetry.js +28 -0
  64. package/dist/relays-commands/zones.d.ts +7 -0
  65. package/dist/relays-commands/zones.js +16 -0
  66. package/dist/runner.js +2 -0
  67. package/package.json +2 -2
package/dist/products.js CHANGED
@@ -1,16 +1,53 @@
1
- import { idempotencyHeaders, operationTable } from '@onesi/genesis';
1
+ import { idempotencyHeaders, ifMatchHeaders, mindsEngineCommands, operationTable } from '@onesi/genesis';
2
+ import { readFile, writeFile } from 'node:fs/promises';
3
+ import { basename } from 'node:path';
2
4
  import { readFunctionJson } from './function-input.js';
3
5
  /** Command words -> operation. Positional arguments are the operation's path parameters, query
4
6
  * parameters become options, a body comes from --body-file, and --idempotency-key carries the
5
7
  * Idempotency-Key header (required where the service requires it). */
6
8
  export const PRODUCT_COMMANDS = {
7
- rigs: { description: 'Rigs: your desktops (read-only; One account login with a selected project)', commands: { list: 'rigs_listRigs' } },
8
- panes: { description: 'Panes: your browsers (read-only; One account login with a selected project)', commands: { list: 'panes_listPanes' } },
9
- shells: { description: 'Shells: your sandboxes (read-only; One account login with a selected project)', commands: { list: 'shells_listShells' } },
10
- gears: { description: 'Gears: durable workflows, runs and signals', commands: {
9
+ rigs: { description: 'Rigs: your desktops (One account login or org API key with a selected project)', commands: { list: 'rigs_listRigs', get: 'rigs_getRig', create: 'rigs_createRig', delete: 'rigs_deleteRig', action: 'rigs_actOnRig', term: 'rigs_openRigTerm' } },
10
+ panes: { description: 'Panes: your browsers (One account login or org API key with a selected project)', commands: { list: 'panes_listPanes', get: 'panes_getPane', create: 'panes_createPane', delete: 'panes_deletePane', action: 'panes_actOnPane', term: 'panes_openPaneTerm', screenshot: 'panes_getPaneScreenshotData' } },
11
+ shells: { description: 'Shells: your sandboxes (One account login or org API key with a selected project)', commands: { list: 'shells_listShells', get: 'shells_getShell', create: 'shells_createShell', delete: 'shells_deleteShell', action: 'shells_actOnShell', term: 'shells_openShellTerm', exec: 'shells_execShell' } },
12
+ gateway: { description: 'Genesis gateway: status, the verified caller, usage, the error catalog and the served OpenAPI document (answered by the gateway itself)', commands: {
13
+ status: 'gateway_getStatus', whoami: 'gateway_whoami', usage: 'gateway_getUsage', errors: 'gateway_listErrors', openapi: 'gateway_getOpenApi',
14
+ } },
15
+ auth: { description: "Auth's public discovery documents, unchanged (no login needed; issuer stays https://auth.life.one)", commands: {
16
+ discovery: 'gateway_getAuthOpenIdConfiguration', jwks: 'gateway_getAuthJwks', lifeid: 'gateway_getAuthLifeId',
17
+ } },
18
+ orgs: { description: 'Your organization usage and billing reads, and Orgs: legal entities, seats, resolutions, documents, filings, formation rehearsals and the record', commands: {
19
+ usage: 'gateway_getOrgUsage', observations: 'gateway_getOrgUsageObservations', billing: 'gateway_getOrgBilling',
20
+ 'payment-methods': 'gateway_listOrgPaymentMethods', service: 'gateway_getOrgServiceBilling',
21
+ // Orgs (legal entities). `documents add` (--file upload), `documents content` (download to a path) and
22
+ // `formation request` (--dry-run) are hand-written in orgs.ts.
23
+ whoami: 'orgs_whoami', portals: 'orgs_list_portals',
24
+ 'entities list': 'orgs_list_entities', 'entities get': 'orgs_get_entity', 'entities create': 'orgs_create_entity',
25
+ 'entities update': 'orgs_update_entity', 'entities archive': 'orgs_archive_entity',
26
+ 'registered-agent set': 'orgs_set_registered_agent', 'registered-agent remove': 'orgs_remove_registered_agent',
27
+ 'seats list': 'orgs_list_seats', 'seats create': 'orgs_create_seat', 'seats get': 'orgs_get_seat', 'seats update': 'orgs_update_seat', 'seats end': 'orgs_end_seat',
28
+ 'resolutions list': 'orgs_list_resolutions', 'resolutions create': 'orgs_create_resolution', 'resolutions get': 'orgs_get_resolution', 'resolutions vote': 'orgs_vote',
29
+ 'documents list': 'orgs_list_documents', 'documents get': 'orgs_get_document', 'documents sign': 'orgs_sign_document',
30
+ 'filings list': 'orgs_list_filings', 'filings create': 'orgs_create_filing', 'filings get': 'orgs_get_filing', 'filings update': 'orgs_update_filing',
31
+ 'formation-jobs list': 'orgs_list_formation_jobs', 'formation-jobs get': 'orgs_get_formation_job',
32
+ 'formation-jobs steps': 'orgs_list_formation_steps', 'formation-jobs cancel': 'orgs_cancel_formation_job',
33
+ 'record list': 'orgs_get_record', 'record verify': 'orgs_verify_record',
34
+ } },
35
+ billing: { description: 'Your organization billing: account, contacts, tax IDs, quotas, Minds account, invoices, usage report and the service catalog (login session, or an org API key with genesis.billing.read / .manage / genesis.usage.read). Nothing here pays or charges.', commands: {
36
+ 'account get': 'gateway_getBillingAccount', 'account update': 'gateway_updateBillingAccount', 'account activity': 'gateway_listBillingActivity',
37
+ 'contacts list': 'gateway_listBillingContacts', 'contacts create': 'gateway_createBillingContact', 'contacts delete': 'gateway_deleteBillingContact',
38
+ 'tax-ids list': 'gateway_listBillingTaxIds', 'tax-ids create': 'gateway_createBillingTaxId', 'tax-ids delete': 'gateway_deleteBillingTaxId',
39
+ 'quotas get': 'gateway_getOrgQuotas', 'quotas requests list': 'gateway_listQuotaRequests', 'quotas requests create': 'gateway_createQuotaRequest',
40
+ 'minds-account': 'gateway_getMindsAccount', invoices: 'gateway_listOrgInvoices', 'usage-report': 'gateway_getOrgUsageReport', catalog: 'gateway_listBillingServices',
41
+ } },
42
+ gears: { description: 'Gears: durable workflows, runs, signals and run lifecycle', commands: {
11
43
  'workflows list': 'gears_listWorkflows', 'workflows get': 'gears_getWorkflow', 'workflows register': 'gears_registerWorkflow',
12
44
  'runs list': 'gears_listRuns', 'runs get': 'gears_getRun', 'runs history': 'gears_getRunHistory',
13
- 'runs start': 'gears_startRun', 'runs signal': 'gears_signalRun', records: 'gears_listOperationalRecords',
45
+ 'runs start': 'gears_startRun', 'runs signal': 'gears_signalRun',
46
+ 'runs cancel': 'gears_cancelRun', 'runs resume': 'gears_resumeRun', 'runs complete': 'gears_completeRun', 'runs fail': 'gears_failRun',
47
+ 'runs timers start': 'gears_startTimer', 'runs retries schedule': 'gears_scheduleRetry', 'runs retries execute': 'gears_executeRetry',
48
+ 'runs step-refs record': 'gears_recordStepRefs', 'runs children start': 'gears_startChildRun',
49
+ 'runs compensations register': 'gears_registerCompensation', 'runs compensations rollback': 'gears_rollbackCompensations',
50
+ runtime: 'gears_getRuntime', records: 'gears_listOperationalRecords',
14
51
  } },
15
52
  lanes: { description: 'Lanes: agent context, cache, ledger and routing (Sandbox; One account login)', commands: {
16
53
  'records get': 'lanes_getRecord', 'records write': 'lanes_writeRecord', 'records snapshot': 'lanes_snapshotRecords', 'records restore': 'lanes_restoreRecords',
@@ -22,6 +59,74 @@ export const PRODUCT_COMMANDS = {
22
59
  'promotions list': 'lanes_listPromotionCandidates', 'promotions propose': 'lanes_proposePromotion', 'promotions review': 'lanes_reviewPromotion',
23
60
  'operations records': 'lanes_listOperationalRecords', 'operations get': 'lanes_getOperation',
24
61
  } },
62
+ auto: { description: "Auto: your organization's operating structure: orgs, mandates, positions, authority checks, budgets, policies, cadences, continuity and credentials", commands: {
63
+ whoami: 'auto_whoami',
64
+ 'orgs list': 'auto_listOrgs', 'orgs get': 'auto_getOrg', 'orgs create': 'auto_createOrg', 'orgs update': 'auto_updateOrg', 'orgs archive': 'auto_archiveOrg',
65
+ 'mandates list': 'auto_listMandates', 'mandates get': 'auto_getMandate', 'mandates create': 'auto_createMandate',
66
+ 'mandates update': 'auto_updateMandate', 'mandates archive': 'auto_archiveMandate', 'mandates propose': 'auto_proposeAction',
67
+ 'decisions record': 'auto_recordDecision', 'ledger list': 'auto_getLedger', 'ledger verify': 'auto_verifyLedger',
68
+ 'approvals list': 'auto_listApprovals', 'approvals get': 'auto_getApproval', 'approvals decide': 'auto_decideApproval',
69
+ 'units list': 'auto_listUnits', 'units get': 'auto_getUnit', 'units create': 'auto_createUnit', 'units update': 'auto_updateUnit', 'units archive': 'auto_archiveUnit',
70
+ 'positions list': 'auto_listPositions', 'positions get': 'auto_getPosition', 'positions create': 'auto_createPosition',
71
+ 'positions update': 'auto_updatePosition', 'positions archive': 'auto_archivePosition',
72
+ 'positions appoint': 'auto_appointOccupant', 'positions vacate': 'auto_vacatePosition',
73
+ 'positions terms': 'auto_listPositionTerms', 'positions scorecard': 'auto_getPositionScorecard',
74
+ 'positions succession': 'auto_setPositionSuccession', 'positions acting start': 'auto_startActing', 'positions acting end': 'auto_endActing',
75
+ chart: 'auto_getOrgChart', continuity: 'auto_getOrgContinuity',
76
+ 'authority check': 'auto_checkAuthority', 'authority get': 'auto_getAuthorityCheck', 'authority release': 'auto_releaseAuthorityCheck',
77
+ 'authority verify': 'auto_verifyAuthorityToken',
78
+ 'credentials issue': 'auto_issuePositionCredential', 'credentials list': 'auto_listCredentials', 'credentials get': 'auto_getCredential',
79
+ 'credentials revoke': 'auto_revokeCredential', 'credentials status': 'auto_getCredentialStatus',
80
+ 'keys jwks': 'auto_getJwks', 'keys did': 'auto_getDidDocument',
81
+ 'budgets list': 'auto_listBudgets', 'budgets get': 'auto_getBudget', 'budgets create': 'auto_createBudget', 'budgets update': 'auto_updateBudget',
82
+ 'budgets archive': 'auto_archiveBudget',
83
+ 'policies list': 'auto_listPolicies', 'policies get': 'auto_getPolicy', 'policies create': 'auto_createPolicy', 'policies update': 'auto_updatePolicy',
84
+ 'policies archive': 'auto_archivePolicy',
85
+ 'cadences list': 'auto_listCadences', 'cadences due': 'auto_listDueCadences', 'cadences get': 'auto_getCadence', 'cadences create': 'auto_createCadence',
86
+ 'cadences update': 'auto_updateCadence', 'cadences archive': 'auto_archiveCadence',
87
+ 'cadences occurrences': 'auto_listCadenceOccurrences', 'cadences record': 'auto_recordCadenceOccurrence',
88
+ 'goals list': 'auto_listGoals', 'goals get': 'auto_getGoal', 'goals create': 'auto_createGoal', 'goals update': 'auto_updateGoal',
89
+ 'goals archive': 'auto_archiveGoal', 'goals measure': 'auto_recordGoalMeasurement', scorecard: 'auto_getOrgScorecard',
90
+ } },
91
+ scopes: { description: 'Scopes: the work graph (projects, tasks, dependencies, assignments to agents or people); agents run on Henry, Fleets or Flocks', commands: {
92
+ whoami: 'scopes_whoami', workload: 'scopes_getWorkload',
93
+ 'projects list': 'scopes_listProjects', 'projects get': 'scopes_getProject', 'projects create': 'scopes_createProject',
94
+ 'projects update': 'scopes_updateProject', 'projects archive': 'scopes_archiveProject', 'projects graph': 'scopes_getGraph',
95
+ 'projects ready': 'scopes_listReady', 'projects tasks': 'scopes_listProjectTasks', 'projects activity': 'scopes_getProjectActivity',
96
+ 'tasks list': 'scopes_listTasks', 'tasks get': 'scopes_getTask', 'tasks create': 'scopes_createTask', 'tasks update': 'scopes_updateTask',
97
+ 'tasks archive': 'scopes_archiveTask', 'tasks assign': 'scopes_assignTask', 'tasks unassign': 'scopes_unassignTask',
98
+ 'tasks assignments': 'scopes_listAssignments', 'tasks activity': 'scopes_getTaskActivity',
99
+ 'dependencies list': 'scopes_listDependencies', 'dependencies add': 'scopes_addDependency', 'dependencies remove': 'scopes_removeDependency',
100
+ 'comments list': 'scopes_listComments', 'comments add': 'scopes_addComment',
101
+ } },
102
+ garden: { description: 'Garden: your organization\'s own finance (books, accounts, journal, customers and vendors, invoices, payments, payouts, reports, audit trail; garden:read / garden:write / garden:manage)', commands: {
103
+ whoami: 'garden_whoami',
104
+ 'books list': 'garden_listBooks', 'books get': 'garden_getBooks', 'books create': 'garden_createBooks', 'books update': 'garden_updateBooks', 'books archive': 'garden_archiveBooks',
105
+ 'accounts list': 'garden_listAccounts', 'accounts get': 'garden_getAccount', 'accounts create': 'garden_createAccount', 'accounts update': 'garden_updateAccount',
106
+ 'journal list': 'garden_listJournalEntries', 'journal get': 'garden_getJournalEntry', 'journal create': 'garden_createJournalEntry', 'journal update': 'garden_updateJournalEntry',
107
+ 'journal discard': 'garden_discardJournalEntry', 'journal post': 'garden_postJournalEntry', 'journal reverse': 'garden_reverseJournalEntry',
108
+ 'counterparties list': 'garden_listCounterparties', 'counterparties get': 'garden_getCounterparty', 'counterparties create': 'garden_createCounterparty', 'counterparties update': 'garden_updateCounterparty',
109
+ 'invoices list': 'garden_listInvoices', 'invoices get': 'garden_getInvoice', 'invoices create': 'garden_createInvoice', 'invoices update': 'garden_updateInvoice',
110
+ 'invoices finalize': 'garden_finalizeInvoice', 'invoices void': 'garden_voidInvoice', 'invoices uncollectible': 'garden_markInvoiceUncollectible', 'invoices pay': 'garden_recordInvoicePayment',
111
+ 'payments list': 'garden_listPayments', 'payments get': 'garden_getPayment', 'payments create': 'garden_createPayment', 'payments authorize': 'garden_authorizePayment', 'payments cancel': 'garden_cancelPayment',
112
+ 'payouts list': 'garden_listPayouts', 'payouts get': 'garden_getPayout', 'payouts create': 'garden_createPayout', 'payouts authorize': 'garden_authorizePayout', 'payouts cancel': 'garden_cancelPayout',
113
+ 'reports trial-balance': 'garden_getTrialBalance', 'reports balance-sheet': 'garden_getBalanceSheet', 'reports income-statement': 'garden_getIncomeStatement', 'reports ar-aging': 'garden_getArAging',
114
+ 'events list': 'garden_listEvents', 'events verify': 'garden_verifyEvents',
115
+ } },
116
+ zaps: { description: 'Zaps: key-value stores for agents and apps (org API key with zaps:read / zaps:write; Sandbox)', commands: {
117
+ list: 'zaps_listZaps', get: 'zaps_getZap', create: 'zaps_createZap', delete: 'zaps_deleteZap', purposes: 'zaps_listZapPurposes',
118
+ command: 'zaps_zapCommand', 'kv command': 'zaps_command', 'kv pipeline': 'zaps_pipeline', stats: 'zaps_getStats', metrics: 'zaps_getMetrics',
119
+ 'audit search': 'zaps_searchAudit', 'audit stats': 'zaps_getAuditStats',
120
+ } },
121
+ brews: { description: 'Brews: agent recipes, the exchange, decisions and selections (Sandbox; org API key or One account login; scope comes from the selection)', commands: {
122
+ create: 'brews_createBrew', list: 'brews_listBrews', get: 'brews_getBrew', card: 'brews_getBrewCard', compile: 'brews_compileBrew',
123
+ run: 'brews_runBrew', eval: 'brews_evalBrew', 'bench run': 'brews_runBrewBench', 'tools call': 'brews_callTool',
124
+ 'exchange public': 'brews_listPublicExchange', 'exchange list': 'brews_listExchange', 'exchange get': 'brews_getExchangeListing',
125
+ 'exchange install': 'brews_installBrew',
126
+ 'decisions status': 'brews_getDecisionStatus', 'decisions create': 'brews_createDecision', 'decisions get': 'brews_getDecision',
127
+ 'decisions reconcile': 'brews_reconcileDecision',
128
+ 'selections create': 'brews_createSelection', 'selections get': 'brews_getSelection', 'selections recover': 'brews_recoverSelection',
129
+ } },
25
130
  flares: { description: 'Flares: agent notifications, conversations, commitments, presence, trust and choreography (Sandbox; One account login)', commands: {
26
131
  list: 'flares_listFlares', get: 'flares_getFlare', send: 'flares_sendFlare', 'send-batch': 'flares_sendFlareBatch',
27
132
  acknowledge: 'flares_acknowledgeFlare', act: 'flares_actOnFlare',
@@ -30,6 +135,7 @@ export const PRODUCT_COMMANDS = {
30
135
  'commitments list': 'flares_listCommitments', 'commitments get': 'flares_getCommitment', 'commitments create': 'flares_createCommitment',
31
136
  'commitments accept': 'flares_acceptCommitment', 'commitments start': 'flares_startCommitment', 'commitments progress': 'flares_reportCommitmentProgress',
32
137
  'commitments fulfill': 'flares_fulfillCommitment', 'commitments fail': 'flares_failCommitment',
138
+ 'presence list': 'flares_listPresence', 'trust list': 'flares_listTrust', 'activity list': 'flares_listActivity',
33
139
  'presence heartbeat': 'flares_presenceHeartbeat', 'presence get': 'flares_getPresence',
34
140
  'trust score': 'flares_getTrustScore', 'trust check': 'flares_checkTrust', 'trust endorsements': 'flares_listEndorsements',
35
141
  'trust endorse': 'flares_createEndorsement', 'trust revoke': 'flares_revokeEndorsement',
@@ -39,6 +145,257 @@ export const PRODUCT_COMMANDS = {
39
145
  'choreography executions complete-step': 'flares_completeChoreographyStep', 'choreography executions fail-step': 'flares_failChoreographyStep',
40
146
  'choreography executions cancel': 'flares_cancelChoreographyExecution',
41
147
  } },
148
+ // `traces runs create|list|get`, `traces search` and `traces usage` are hand-written in index.ts and keep working;
149
+ // every other admitted Traces route is listed here.
150
+ traces: { description: 'Traces: research and evidence (runs, sources, monitors, crawl, extract, verify)', commands: {
151
+ 'runs steps': 'traces_getRunSteps', 'runs stream': 'traces_streamRun', 'runs evidence': 'traces_getRunEvidence',
152
+ 'runs cancel': 'traces_cancelRun', 'runs pause': 'traces_pauseRun', 'runs resume': 'traces_resumeRun', 'runs retry': 'traces_retryRun',
153
+ 'sources create': 'traces_createSource', 'sources list': 'traces_listSources', 'sources get': 'traces_getSource', 'sources update': 'traces_updateSource',
154
+ 'sources delete': 'traces_deleteSource', 'sources check': 'traces_checkSource', 'sources health': 'traces_getSourceHealth',
155
+ 'monitors create': 'traces_createMonitor', 'monitors list': 'traces_listMonitors', 'monitors get': 'traces_getMonitor', 'monitors update': 'traces_updateMonitor',
156
+ 'monitors delete': 'traces_deleteMonitor', 'monitors check': 'traces_checkMonitor', 'monitors alerts': 'traces_listMonitorAlerts',
157
+ 'monitors acknowledge-alert': 'traces_acknowledgeMonitorAlert',
158
+ 'crawl create': 'traces_createCrawl', 'crawl get': 'traces_getCrawl', 'crawl cancel': 'traces_cancelCrawl',
159
+ 'batch-scrape create': 'traces_createBatchScrape', 'batch-scrape get': 'traces_getBatchScrape', 'batch-scrape cancel': 'traces_cancelBatchScrape',
160
+ extract: 'traces_extract', 'extract-structured': 'traces_extractStructured', scrape: 'traces_scrape', map: 'traces_map',
161
+ 'evidence list': 'traces_listEvidence', 'evidence get': 'traces_getEvidence', 'artifacts get': 'traces_getArtifact',
162
+ 'ingest create': 'traces_ingestEvidence', 'ingest status': 'traces_getIngestStatus', 'ingest evaluate': 'traces_evaluateIngestFallback',
163
+ verify: 'traces_verifyClaim', 'spans': 'traces_listSpans', 'verdicts list': 'traces_listVerdicts', 'verdicts get': 'traces_getVerdict',
164
+ 'coding resolve': 'traces_resolveLibrary', 'coding docs': 'traces_getLibraryDocs',
165
+ 'usage-summary': 'traces_getUsageSummary', health: 'traces_getHealth',
166
+ 'api-keys create': 'traces_createApiKey', 'api-keys list': 'traces_listApiKeys', 'api-keys get': 'traces_getApiKey',
167
+ 'api-keys rotate': 'traces_rotateApiKey', 'api-keys revoke': 'traces_revokeApiKey',
168
+ } },
169
+ // `foundry models`, `foundry chat` and `foundry billing …` are hand-written in index.ts and keep working.
170
+ foundry: { description: 'Foundry: models, inference, receipts, keys and the model registry (inference needs a login; the universal API, routing, tools and workloads need a Console login)', commands: {
171
+ messages: 'foundry_createMessage', responses: 'foundry_createResponse', embeddings: 'foundry_createEmbedding', rerank: 'foundry_createRerank',
172
+ 'images create': 'foundry_createImage', 'images models': 'foundry_listImageModels', transcribe: 'foundry_createAudioTranscription',
173
+ 'receipts get': 'foundry_getGenerationReceipt', 'receipts by-request': 'foundry_getGenerationReceiptByRequest', 'receipts verification-key': 'foundry_getReceiptVerificationKey',
174
+ 'receipts verification-keys': 'foundry_listReceiptVerificationKeys',
175
+ 'keys list': 'foundry_listApiKeys', 'keys create': 'foundry_createApiKey', 'keys delete': 'foundry_deleteApiKey', 'keys rotate': 'foundry_rotateApiKey', 'keys current': 'foundry_getCurrentApiKey',
176
+ 'reporting request-logs': 'foundry_listRequestLogs', 'reporting provider-credentials': 'foundry_getProviderCredentialSummary',
177
+ 'activity list': 'foundry_getActivity', 'activity export': 'foundry_exportActivity', 'analytics meta': 'foundry_getAnalyticsMeta', 'analytics query': 'foundry_queryAnalytics',
178
+ 'batches create': 'foundry_createBatch', 'batches get': 'foundry_getBatch',
179
+ infer: 'foundry_createInference', 'infer-stream': 'foundry_streamInference', classify: 'foundry_classifyText', detect: 'foundry_detectObjects',
180
+ segment: 'foundry_segmentImage', embed: 'foundry_embedTexts', 'transcribe-audio': 'foundry_transcribeAudio', speak: 'foundry_synthesizeSpeech',
181
+ 'generate-image': 'foundry_generateImage', predict: 'foundry_predictTabular', forecast: 'foundry_forecastSeries', recommend: 'foundry_recommendItems',
182
+ annotate: 'foundry_annotateText', summarize: 'foundry_summarizeText',
183
+ 'routing preview': 'foundry_previewRoute', 'routing explain': 'foundry_explainRoutingInvocation',
184
+ 'routing evals plan': 'foundry_planRoutingEval', 'routing evals dispatch-plan': 'foundry_dispatchRoutingEvalPlan',
185
+ 'routing evals aggregate-dispatch': 'foundry_aggregateRoutingEvalDispatch', 'routing evals aggregate-planned': 'foundry_aggregatePlannedRoutingEval',
186
+ 'routing evals aggregate': 'foundry_aggregateRoutingEval', 'routing evals claim-readiness': 'foundry_checkRoutingEvalClaimReadiness',
187
+ 'tools cost-estimate': 'foundry_estimateCost', 'tools compare': 'foundry_compareModels', 'tools benchmark': 'foundry_benchmarkModels',
188
+ 'workloads status': 'foundry_getWorkloadStatus', 'workloads terminate': 'foundry_terminateWorkload',
189
+ 'generation get': 'foundry_getGeneration', 'generation content': 'foundry_getGenerationContent', 'generation feedback': 'foundry_submitGenerationFeedback',
190
+ 'registry models': 'foundry_listRegistryModels', 'registry model': 'foundry_getRegistryModel', 'registry offers': 'foundry_listModelOffers',
191
+ 'registry dossier': 'foundry_getModelDossier', 'registry benchmarks': 'foundry_listModelBenchmarks', 'registry sources': 'foundry_listModelSources',
192
+ 'registry providers': 'foundry_listRegistryProviders', 'registry provider': 'foundry_getRegistryProvider', 'registry provider-dossier': 'foundry_getProviderDossier',
193
+ 'registry facets': 'foundry_listRegistryFacets', 'registry model-base': 'foundry_getCurrentModelBase', 'registry model-base-releases': 'foundry_listModelBaseReleases',
194
+ 'registry labs': 'foundry_listRegistryLabs', 'registry lab': 'foundry_getRegistryLab', 'registry compare': 'foundry_compareRegistryModels',
195
+ 'registry v2 models': 'foundry_listRegistryModelsV2', 'registry v2 model': 'foundry_getRegistryModelV2', 'registry v2 dossier': 'foundry_getModelDossierV2',
196
+ 'registry v2 providers': 'foundry_listRegistryProvidersV2', 'registry v2 provider': 'foundry_getProviderDossierV2', 'registry v2 facets': 'foundry_listRegistryFacetsV2',
197
+ 'registry v2 model-base': 'foundry_getCurrentModelBaseV2', 'registry v2 model-base-releases': 'foundry_listModelBaseReleasesV2',
198
+ 'registry v2 labs': 'foundry_listRegistryLabsV2', 'registry v2 lab': 'foundry_getRegistryLabV2', 'registry v2 compare': 'foundry_compareRegistryModelsV2',
199
+ 'registry v2 benchmarks': 'foundry_listRegistryBenchmarksV2', 'registry v2 sources': 'foundry_listRegistrySourcesV2', 'registry v2 provenance': 'foundry_listRegistryProvenanceV2',
200
+ } },
201
+ // IAM v4 (projects and workspaces are `genesis projects` / `genesis workspaces`). `agents enroll` is hand-written in index.ts:
202
+ // it sends only an enrollment key. Inviting, member role changes and removal stay with a person in the Console.
203
+ iam: { description: 'IAM: organizations, fleets, agents, roles, grants, capabilities and permission checks (One account login, or an org API key with iam:read / iam:write)', commands: {
204
+ 'orgs list': 'iam_listOrgs', 'orgs get': 'iam_getOrg', 'orgs update': 'iam_updateOrg', 'orgs members': 'iam_listMembers', 'orgs entitlements': 'iam_listEntitlements',
205
+ 'fleets list': 'iam_listFleets', 'fleets get': 'iam_getFleet', 'fleets create': 'iam_createFleet', 'fleets update': 'iam_updateFleet', 'fleets delete': 'iam_deleteFleet',
206
+ 'agents list': 'iam_listAgents', 'agents get': 'iam_getAgent', 'agents create': 'iam_createAgent', 'agents revoke': 'iam_deleteAgent',
207
+ 'agents suspend': 'iam_suspendAgent', 'agents resume': 'iam_resumeAgent', 'agents rotate': 'iam_rotateAgentKey',
208
+ 'agents acts list': 'iam_listAgentActs', 'agents acts issue': 'iam_issueAgentAct',
209
+ 'agents publication': 'iam_getAgentPublication', 'agents orbit-msgs-grant': 'iam_getOrbitMsgsProductGrant', 'agents public': 'iam_getPublicAgent',
210
+ 'agents for-mind': 'iam_listMindAgents', 'agents enrollment-grants': 'iam_listAgentEnrollmentGrants',
211
+ 'roles list': 'iam_listRoles', 'roles get': 'iam_getRole', 'roles create': 'iam_createRole', 'roles update': 'iam_updateRole', 'roles delete': 'iam_deleteRole',
212
+ 'grants list': 'iam_listGrants', 'grants get': 'iam_getGrant', 'grants create': 'iam_createGrant', 'grants update': 'iam_updateGrant', 'grants delete': 'iam_deleteGrant',
213
+ 'capabilities get': 'iam_getCapability', 'capabilities create': 'iam_createCapability', 'capabilities update': 'iam_updateCapability',
214
+ 'capabilities revoke': 'iam_deleteCapability', 'capabilities verify': 'iam_verifyCapability',
215
+ platforms: 'iam_listPlatforms', 'tenant-context': 'iam_getTenantContext',
216
+ 'check-permission': 'iam_checkPermission', 'require-permission': 'iam_requirePermission', 'check-entitlement': 'iam_checkEntitlement',
217
+ } },
218
+ taps: { description: 'Taps: ask a human to decide; respond and lineage need a One account login (Sandbox)', commands: {
219
+ create: 'taps_createTap', list: 'taps_listTaps', get: 'taps_getTap', cancel: 'taps_cancelTap',
220
+ respond: 'taps_respondToTap', events: 'taps_listTapEvents',
221
+ 'routing-rules list': 'taps_listRoutingRules', 'routing-rules create': 'taps_createRoutingRule',
222
+ 'routing-rules update': 'taps_updateRoutingRule', 'routing-rules delete': 'taps_deleteRoutingRule',
223
+ 'escalation-policies list': 'taps_listEscalationPolicies', 'escalation-policies create': 'taps_createEscalationPolicy',
224
+ 'escalation-policies update': 'taps_updateEscalationPolicy', 'escalation-policies delete': 'taps_deleteEscalationPolicy',
225
+ 'settings get': 'taps_getSettings', 'settings update': 'taps_updateSettings',
226
+ 'garden get': 'taps_getGardenIntegration', 'garden enable': 'taps_enableGardenIntegration',
227
+ 'lineage challenge': 'taps_createAgentLineageChallenge', 'lineage requests create': 'taps_createAgentLineageRequest',
228
+ 'lineage requests list': 'taps_listAgentLineageRequests', 'lineage requests get': 'taps_getAgentLineageRequest',
229
+ } },
230
+ // `genesis minds engine <family> <verb> <mind_id> [params]`: every Minds engine route, generated from the grant table.
231
+ minds: { description: 'Minds: your Sandbox Minds (One account login)', commands: mindsEngineCommands },
232
+ boxes: { description: 'Boxes: mail, docs, files, sheets, slides, calendar and identity (org API key; GET boxes:read, writes boxes:write)', commands: {
233
+ // boxes:begin
234
+ 'mail addresses create': 'boxes_mail_addresses_create',
235
+ 'mail addresses list': 'boxes_mail_addresses_list',
236
+ 'mail domains addresses create': 'boxes_mail_domains_addresses_create',
237
+ 'mail domains create': 'boxes_mail_domains_create',
238
+ 'mail domains list': 'boxes_mail_domains_list',
239
+ 'mail domains verify': 'boxes_mail_domains_verify',
240
+ 'mail inbox list': 'boxes_mail_inbox_list',
241
+ 'mail mailboxes list': 'boxes_mail_mailboxes_list',
242
+ 'mail messages get': 'boxes_mail_messages_get',
243
+ 'mail messages delete': 'boxes_mail_messages_delete',
244
+ 'mail messages update': 'boxes_mail_messages_update',
245
+ 'mail send': 'boxes_mail_send',
246
+ 'mail threads get': 'boxes_mail_threads_get',
247
+ 'mail threads list': 'boxes_mail_threads_list',
248
+ 'mail agent batch-send': 'boxes_mail_agent_batch_send',
249
+ 'mail agent webhooks create': 'boxes_mail_agent_webhooks_create',
250
+ 'mail agent webhooks list': 'boxes_mail_agent_webhooks_list',
251
+ 'mail agent webhooks delete': 'boxes_mail_agent_webhooks_delete',
252
+ 'mail agent activities list': 'boxes_mail_agent_activities_list',
253
+ 'mail agent state list': 'boxes_mail_agent_state_list',
254
+ 'mail agent state update': 'boxes_mail_agent_state_update',
255
+ 'mail attachments content get': 'boxes_mail_attachments_content_get',
256
+ 'mail attachments get': 'boxes_mail_attachments_get',
257
+ 'mail attachments delete': 'boxes_mail_attachments_delete',
258
+ 'mail attachments upload': 'boxes_mail_attachments_upload',
259
+ 'mail messages attachments list': 'boxes_mail_messages_attachments_list',
260
+ 'mail messages delivery get': 'boxes_mail_messages_delivery_get',
261
+ 'mail search': 'boxes_mail_search',
262
+ 'mail stream sse': 'boxes_mail_stream_sse',
263
+ 'mail batch': 'boxes_mail_batch',
264
+ 'mail delegations revoke': 'boxes_mail_delegations_revoke',
265
+ 'mail extraction message get': 'boxes_mail_extraction_message_get',
266
+ 'mail extraction thread get': 'boxes_mail_extraction_thread_get',
267
+ 'mail folders create': 'boxes_mail_folders_create',
268
+ 'mail folders list': 'boxes_mail_folders_list',
269
+ 'mail governance audit list': 'boxes_mail_governance_audit_list',
270
+ 'mail intelligence thread get': 'boxes_mail_intelligence_thread_get',
271
+ 'mail labels create': 'boxes_mail_labels_create',
272
+ 'mail labels list': 'boxes_mail_labels_list',
273
+ 'mail labels delete': 'boxes_mail_labels_delete',
274
+ 'mail mailboxes delegations list': 'boxes_mail_mailboxes_delegations_list',
275
+ 'mail memory events submit': 'boxes_mail_memory_events_submit',
276
+ 'mail memory recall': 'boxes_mail_memory_recall',
277
+ 'mail memory search': 'boxes_mail_memory_search',
278
+ 'mail memory store': 'boxes_mail_memory_store',
279
+ 'mail personas list': 'boxes_mail_personas_list',
280
+ 'mail templates list': 'boxes_mail_templates_list',
281
+ 'files list': 'boxes_files_list',
282
+ 'files search': 'boxes_files_search',
283
+ 'files recent list': 'boxes_files_recent_list',
284
+ 'files trash list': 'boxes_files_trash_list',
285
+ 'files shared-with-me list': 'boxes_files_shared_with_me_list',
286
+ 'files upload': 'boxes_files_upload',
287
+ 'files folders create': 'boxes_files_folders_create',
288
+ 'files get': 'boxes_files_get',
289
+ 'files update': 'boxes_files_update',
290
+ 'files delete': 'boxes_files_delete',
291
+ 'files download': 'boxes_files_download',
292
+ 'files restore': 'boxes_files_restore',
293
+ 'files purge': 'boxes_files_purge',
294
+ 'files share': 'boxes_files_share',
295
+ 'files shares list': 'boxes_files_shares_list',
296
+ 'files unshare': 'boxes_files_unshare',
297
+ 'docs documents list': 'boxes_docs_documents_list',
298
+ 'docs documents create': 'boxes_docs_documents_create',
299
+ 'docs folders create': 'boxes_docs_folders_create',
300
+ 'docs search': 'boxes_docs_search',
301
+ 'docs recent list': 'boxes_docs_recent_list',
302
+ 'docs trash list': 'boxes_docs_trash_list',
303
+ 'docs templates list': 'boxes_docs_templates_list',
304
+ 'docs shared-with-me list': 'boxes_docs_shared_with_me_list',
305
+ 'docs mcp action': 'boxes_docs_mcp_action',
306
+ 'docs documents get': 'boxes_docs_documents_get',
307
+ 'docs documents update': 'boxes_docs_documents_update',
308
+ 'docs documents delete': 'boxes_docs_documents_delete',
309
+ 'docs documents purge': 'boxes_docs_documents_purge',
310
+ 'docs documents versions list': 'boxes_docs_documents_versions_list',
311
+ 'docs documents share': 'boxes_docs_documents_share',
312
+ 'docs documents shares list': 'boxes_docs_documents_shares_list',
313
+ 'docs documents unshare': 'boxes_docs_documents_unshare',
314
+ 'docs documents collaborators list': 'boxes_docs_documents_collaborators_list',
315
+ 'docs documents presence update': 'boxes_docs_documents_presence_update',
316
+ 'docs documents operations list': 'boxes_docs_documents_operations_list',
317
+ 'docs documents operations apply': 'boxes_docs_documents_operations_apply',
318
+ 'docs documents events stream': 'boxes_docs_documents_events_stream',
319
+ 'sheets cells batch': 'boxes_sheets_cells_batch',
320
+ 'sheets cells delete': 'boxes_sheets_cells_delete',
321
+ 'sheets cells get': 'boxes_sheets_cells_get',
322
+ 'sheets cells list': 'boxes_sheets_cells_list',
323
+ 'sheets cells set': 'boxes_sheets_cells_set',
324
+ 'sheets cells query': 'boxes_sheets_cells_query',
325
+ 'sheets cells range get': 'boxes_sheets_cells_range_get',
326
+ 'sheets search': 'boxes_sheets_search',
327
+ 'sheets shared-with-me list': 'boxes_sheets_shared_with_me_list',
328
+ 'sheets spreadsheets create': 'boxes_sheets_spreadsheets_create',
329
+ 'sheets spreadsheets list': 'boxes_sheets_spreadsheets_list',
330
+ 'sheets spreadsheets delete': 'boxes_sheets_spreadsheets_delete',
331
+ 'sheets spreadsheets get': 'boxes_sheets_spreadsheets_get',
332
+ 'sheets spreadsheets update': 'boxes_sheets_spreadsheets_update',
333
+ 'sheets spreadsheets purge': 'boxes_sheets_spreadsheets_purge',
334
+ 'sheets spreadsheets share': 'boxes_sheets_spreadsheets_share',
335
+ 'sheets spreadsheets shares list': 'boxes_sheets_spreadsheets_shares_list',
336
+ 'sheets spreadsheets unshare': 'boxes_sheets_spreadsheets_unshare',
337
+ 'sheets tabs create': 'boxes_sheets_tabs_create',
338
+ 'sheets tabs list': 'boxes_sheets_tabs_list',
339
+ 'sheets tabs delete': 'boxes_sheets_tabs_delete',
340
+ 'sheets tabs get': 'boxes_sheets_tabs_get',
341
+ 'sheets tabs update': 'boxes_sheets_tabs_update',
342
+ 'slides presentations create': 'boxes_slides_presentations_create',
343
+ 'slides presentations list': 'boxes_slides_presentations_list',
344
+ 'slides presentations delete': 'boxes_slides_presentations_delete',
345
+ 'slides presentations get': 'boxes_slides_presentations_get',
346
+ 'slides presentations update': 'boxes_slides_presentations_update',
347
+ 'slides presentations share': 'boxes_slides_presentations_share',
348
+ 'slides presentations shared-with-me list': 'boxes_slides_presentations_shared_with_me_list',
349
+ 'slides presentations shares list': 'boxes_slides_presentations_shares_list',
350
+ 'slides presentations unshare': 'boxes_slides_presentations_unshare',
351
+ 'slides slides create': 'boxes_slides_slides_create',
352
+ 'slides slides list': 'boxes_slides_slides_list',
353
+ 'slides slides delete': 'boxes_slides_slides_delete',
354
+ 'slides slides get': 'boxes_slides_slides_get',
355
+ 'slides slides update': 'boxes_slides_slides_update',
356
+ 'slides slides reorder': 'boxes_slides_slides_reorder',
357
+ 'slides templates create': 'boxes_slides_templates_create',
358
+ 'slides templates list': 'boxes_slides_templates_list',
359
+ 'slides templates delete': 'boxes_slides_templates_delete',
360
+ 'slides templates get': 'boxes_slides_templates_get',
361
+ 'slides templates update': 'boxes_slides_templates_update',
362
+ 'calendar availability get': 'boxes_calendar_availability_get',
363
+ 'calendar calendars create': 'boxes_calendar_calendars_create',
364
+ 'calendar calendars list': 'boxes_calendar_calendars_list',
365
+ 'calendar calendars delete': 'boxes_calendar_calendars_delete',
366
+ 'calendar calendars get': 'boxes_calendar_calendars_get',
367
+ 'calendar calendars update': 'boxes_calendar_calendars_update',
368
+ 'calendar events attendees list': 'boxes_calendar_events_attendees_list',
369
+ 'calendar events create': 'boxes_calendar_events_create',
370
+ 'calendar events list': 'boxes_calendar_events_list',
371
+ 'calendar events delete': 'boxes_calendar_events_delete',
372
+ 'calendar events get': 'boxes_calendar_events_get',
373
+ 'calendar events update': 'boxes_calendar_events_update',
374
+ 'calendar events rsvp': 'boxes_calendar_events_rsvp',
375
+ 'calendar events search': 'boxes_calendar_events_search',
376
+ 'calendar scheduling-links book': 'boxes_calendar_scheduling_links_book',
377
+ 'calendar scheduling-links by-slug get': 'boxes_calendar_scheduling_links_by_slug_get',
378
+ 'calendar scheduling-links create': 'boxes_calendar_scheduling_links_create',
379
+ 'calendar scheduling-links list': 'boxes_calendar_scheduling_links_list',
380
+ 'calendar scheduling-links delete': 'boxes_calendar_scheduling_links_delete',
381
+ 'calendar scheduling-links get': 'boxes_calendar_scheduling_links_get',
382
+ 'calendar scheduling-links update': 'boxes_calendar_scheduling_links_update',
383
+ 'identity me get': 'boxes_identity_me_get',
384
+ 'identity tenants current get': 'boxes_identity_tenants_current_get',
385
+ 'identity users get': 'boxes_identity_users_get',
386
+ 'identity users list': 'boxes_identity_users_list',
387
+ 'identity workspaces list': 'boxes_identity_workspaces_list',
388
+ 'identity workspaces get': 'boxes_identity_workspaces_get',
389
+ 'identity workspaces members list': 'boxes_identity_workspaces_members_list',
390
+ 'mcp sessions context set': 'boxes_mcp_sessions_context_set',
391
+ 'mcp sessions create': 'boxes_mcp_sessions_create',
392
+ 'mcp sessions list': 'boxes_mcp_sessions_list',
393
+ 'mcp sessions delete': 'boxes_mcp_sessions_delete',
394
+ 'mcp sessions get': 'boxes_mcp_sessions_get',
395
+ 'mcp tools call': 'boxes_mcp_tools_call',
396
+ 'mcp tools list': 'boxes_mcp_tools_list',
397
+ // boxes:end
398
+ } },
42
399
  };
43
400
  const BODY_LIMIT = 1024 * 1024;
44
401
  const flag = (name) => name.replace(/_/g, '-').replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
@@ -46,7 +403,20 @@ const flag = (name) => name.replace(/_/g, '-').replace(/([a-z])([A-Z])/g, '$1-$2
46
403
  const key = (name) => flag(name).replace(/-([a-z])/g, (_, c) => c.toUpperCase());
47
404
  export function registerProducts(program, dependencies) {
48
405
  for (const [service, { description, commands }] of Object.entries(PRODUCT_COMMANDS)) {
49
- const root = program.command(service).description(description);
406
+ // A service with hand-written commands (Traces) keeps them: this adds the rest beside them.
407
+ const root = program.commands.find(c => c.name() === service) ?? program.command(service).description(description);
408
+ registerOperationCommands(root, commands, dependencies);
409
+ }
410
+ }
411
+ /** One generic command per operation under `root` (Relays adds its family routes beside its hand-written commands). */
412
+ /** Media types a raw answer may print to stdout without --out: text, JSON, NDJSON and XML (structured suffixes included). Parameters are ignored; a missing type is not printable. */
413
+ const PRINTABLE_MEDIA_TYPE = /^(?:text\/[a-z0-9!#$&^_.+-]+|application\/(?:json|x-ndjson|xml)|application\/[a-z0-9!#$&^_.-]+\+(?:json|xml))$/;
414
+ export function printableMediaType(contentType) {
415
+ const media = contentType?.split(';')[0].trim().toLowerCase();
416
+ return !!media && PRINTABLE_MEDIA_TYPE.test(media);
417
+ }
418
+ export function registerOperationCommands(root, commands, dependencies) {
419
+ {
50
420
  const groups = new Map();
51
421
  for (const [words, id] of Object.entries(commands)) {
52
422
  const op = operationTable[id];
@@ -55,19 +425,45 @@ export function registerProducts(program, dependencies) {
55
425
  for (let i = 0; i < parts.length - 1; i++) {
56
426
  const key = parts.slice(0, i + 1).join(' ');
57
427
  if (!groups.has(key))
58
- groups.set(key, parent.command(parts[i]));
428
+ groups.set(key, parent.commands.find(c => c.name() === parts[i]) ?? parent.command(parts[i]));
59
429
  parent = groups.get(key);
60
430
  }
61
431
  const bodyRequired = op.inputSchema.required.includes('body');
62
432
  const command = parent.command([parts.at(-1), ...op.pathParams.map(p => `<${p}>`)].join(' ')).description(`${op.summary} (${op.method} ${op.path})`);
63
- for (const q of op.queryParams)
64
- command.option(`--${flag(q)} <value>`);
65
- if (op.hasBody)
433
+ const props = (op.inputSchema.properties ?? {});
434
+ // An array query parameter (Foundry registry compare `model`) is a repeatable flag, sent as `?q=a&q=b`.
435
+ for (const q of op.queryParams) {
436
+ if (props[q]?.type === 'array')
437
+ command.option(`--${flag(q)} <value>`, 'repeat for each value', (v, prev = []) => [...prev, v]);
438
+ else
439
+ command.option(`--${flag(q)} <value>`);
440
+ }
441
+ // Boxes only: multipart uploads, and raw bytes or event streams read through a --duration window.
442
+ // Every other service keeps the plain path below (Foundry infer-stream is read to its end).
443
+ const boxes = op.service === 'boxes';
444
+ const multipart = boxes && op.requestContentType === 'multipart/form-data';
445
+ const boxesRaw = boxes && !!op.rawResponse;
446
+ if (multipart) {
447
+ command.option('--file <part=path>', 'File part, repeatable: part name and local path', (v, all = []) => [...all, v]);
448
+ command.option('--field <part=value>', 'Text part, repeatable', (v, all = []) => [...all, v]);
449
+ }
450
+ else if (op.hasBody)
66
451
  command[bodyRequired ? 'requiredOption' : 'option']('--body-file <path>', 'JSON request body, up to 1 MiB');
452
+ // Boxes raw answers use the generic --out below; event streams also take a --duration window.
453
+ if (boxesRaw) {
454
+ command.option('--duration <seconds>', 'For event streams: stop reading after this many seconds (default 10)');
455
+ }
456
+ if (op.ifMatch)
457
+ command.requiredOption('--if-match <version>', 'The version you read (the version field of the object you are changing, or its ETag); a stale one is refused');
67
458
  if (op.idempotencyKey === 'required')
68
459
  command.requiredOption('--idempotency-key <key>', 'Stable key; reuse it to replay instead of acting twice');
69
460
  else if (op.idempotencyKey)
70
- command.option('--idempotency-key <key>', 'Optional stable key; a retry with it returns the original result');
461
+ command.option('--idempotency-key <key>', op.service === 'auto'
462
+ ? 'Optional stable key, 8-128 characters of A-Z a-z 0-9 _ . : -; a repeat returns the first answer'
463
+ : 'Optional stable key; a retry with it returns the original result');
464
+ // A raw answer can be written to a file; a binary one (e.g. a Panes screenshot) must be.
465
+ if (op.rawResponse)
466
+ command.option('--out <path>', 'File to write the response bytes to (required for a binary answer)');
71
467
  command.action(async (...args) => {
72
468
  const options = args[op.pathParams.length];
73
469
  const input = Object.fromEntries(op.pathParams.map((p, i) => [p, args[i]]));
@@ -76,8 +472,73 @@ export function registerProducts(program, dependencies) {
76
472
  input[q] = options[key(q)];
77
473
  if (options.bodyFile)
78
474
  input.body = await readFunctionJson(options.bodyFile, BODY_LIMIT);
79
- const headers = idempotencyHeaders(id, options.idempotencyKey);
475
+ const headers = { ...idempotencyHeaders(id, options.idempotencyKey), ...(op.ifMatch ? ifMatchHeaders(id, options.ifMatch) : {}) };
476
+ const extra = options;
477
+ if (multipart) {
478
+ const form = new FormData();
479
+ const split = (entry) => { const at = entry.indexOf('='); if (at < 1)
480
+ throw new Error(`Expected part=value, got "${entry}"`); return [entry.slice(0, at), entry.slice(at + 1)]; };
481
+ for (const entry of extra.file ?? []) {
482
+ const [part, file] = split(entry);
483
+ form.append(part, new Blob([new Uint8Array(await readFile(file))]), basename(file));
484
+ }
485
+ for (const entry of extra.field ?? [])
486
+ form.append(...split(entry));
487
+ input.body = form;
488
+ }
489
+ if (boxesRaw) {
490
+ const stream = new AbortController();
491
+ const signal = dependencies.signal ? AbortSignal.any([dependencies.signal, stream.signal]) : stream.signal;
492
+ const response = await (await dependencies.client()).raw(id, input, { headers, signal });
493
+ if (!response.ok)
494
+ throw new Error(`HTTP ${response.status}: ${(await response.text()).slice(0, 500)}`);
495
+ const type = response.headers.get('content-type') ?? '';
496
+ const timer = type.startsWith('text/event-stream') ? setTimeout(() => stream.abort(), Math.max(1, Number.isFinite(Number(extra.duration)) ? Number(extra.duration) : 10) * 1000) : undefined;
497
+ const chunks = [];
498
+ try {
499
+ for await (const chunk of response.body ?? [])
500
+ chunks.push(chunk);
501
+ }
502
+ catch (e) {
503
+ if (!stream.signal.aborted)
504
+ throw e;
505
+ }
506
+ finally {
507
+ clearTimeout(timer);
508
+ }
509
+ const bytes = Buffer.concat(chunks);
510
+ if (extra.out) {
511
+ await writeFile(extra.out, bytes);
512
+ dependencies.emit({ ok: true, path: extra.out, bytes: bytes.length, contentType: type }, () => `wrote ${bytes.length} bytes to ${extra.out}`);
513
+ }
514
+ else if (/^(text\/|application\/json)/.test(type))
515
+ dependencies.emit(bytes.toString('utf8'), () => bytes.toString('utf8'));
516
+ else
517
+ throw new Error(`The response is ${type || 'binary'}; pass --out <path> to save it.`);
518
+ return;
519
+ }
80
520
  const result = await (await dependencies.client()).request(id, input, { headers, signal: dependencies.signal });
521
+ if (result instanceof Response) {
522
+ // With --out, a raw answer (e.g. a Panes screenshot) is written to the file as bytes.
523
+ if (options.out) {
524
+ if (!result.ok) {
525
+ void result.body?.cancel().catch(() => { });
526
+ throw new Error(`${id} answered ${result.status}`);
527
+ }
528
+ const bytes = Buffer.from(await result.arrayBuffer());
529
+ await writeFile(options.out, bytes);
530
+ const written = { ok: true, path: options.out, bytes: bytes.length, contentType: result.headers.get('content-type') };
531
+ return dependencies.emit(written, () => JSON.stringify(written, null, 2));
532
+ }
533
+ // Without it, only a declared text answer (an SSE stream such as foundry infer-stream) prints; anything else needs --out.
534
+ const type = result.headers.get('content-type');
535
+ if (!printableMediaType(type)) {
536
+ void result.body?.cancel().catch(() => { });
537
+ throw new Error(`${id} answered ${type || 'no content type'}; pass --out <path> to save it`);
538
+ }
539
+ const text = await result.text();
540
+ return dependencies.emit(text, () => text);
541
+ }
81
542
  dependencies.emit(result ?? { ok: true }, () => JSON.stringify(result ?? { ok: true }, null, 2));
82
543
  });
83
544
  }
@@ -0,0 +1,3 @@
1
+ import type { OperationId } from '@onesi/genesis';
2
+ /** `genesis relays ...` words for the certificates family (openapi/specs/relays/certificates.openapi.yaml). */
3
+ export declare const certificatesCommands: Readonly<Record<string, OperationId>>;
@@ -0,0 +1,20 @@
1
+ /** `genesis relays ...` words for the certificates family (openapi/specs/relays/certificates.openapi.yaml). */
2
+ export const certificatesCommands = {
3
+ 'certificates list': 'relays_listCertificates',
4
+ 'certificates create': 'relays_createCertificate',
5
+ 'certificates get': 'relays_getCertificate',
6
+ 'certificates update': 'relays_updateCertificate',
7
+ 'certificates delete': 'relays_deleteCertificate',
8
+ 'certificates renew': 'relays_renewCertificate',
9
+ 'certificates download': 'relays_downloadCertificate',
10
+ 'certificates history': 'relays_listCertificateHistory',
11
+ 'certificates events': 'relays_listCertificateEvents',
12
+ 'certificates total-tls list': 'relays_listTotalTlsZones',
13
+ 'certificates total-tls enable': 'relays_enableTotalTls',
14
+ 'certificates total-tls disable': 'relays_disableTotalTls',
15
+ 'certificates ct-monitors list': 'relays_listCtMonitors',
16
+ 'certificates ct-monitors create': 'relays_createCtMonitor',
17
+ 'certificates ct-monitors get': 'relays_getCtMonitor',
18
+ 'certificates ct-monitors update': 'relays_updateCtMonitor',
19
+ 'certificates ct-monitors delete': 'relays_deleteCtMonitor',
20
+ };
@@ -0,0 +1,3 @@
1
+ import type { OperationId } from '@onesi/genesis';
2
+ /** `genesis relays ...` words for the domains family (openapi/specs/relays/domains.openapi.yaml). */
3
+ export declare const domainsCommands: Readonly<Record<string, OperationId>>;