@onesi/genesis 0.2.0 → 0.2.2

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.
package/dist/boxes.js ADDED
@@ -0,0 +1,338 @@
1
+ import { idempotencyHeaders } from './idempotency.js';
2
+ /** Boxes (mail, docs, files, sheets, slides, calendar, identity, MCP): one method per operation, grouped as the
3
+ * Boxes resource tree. Path parameters come first, then the body, then query options, then an optional
4
+ * idempotency key on the operations that take one. Operations that stream or download bytes return the raw Response;
5
+ * uploads take a FormData body. GET needs boxes:read, everything else boxes:write. Generated from the Boxes spec. */
6
+ export function boxesModule(client) {
7
+ return {
8
+ mail: {
9
+ addresses: {
10
+ create: (body) => client.request('boxes_mail_addresses_create', { body }),
11
+ list: () => client.request('boxes_mail_addresses_list'),
12
+ },
13
+ domains: {
14
+ addresses: {
15
+ create: (domainId, body) => client.request('boxes_mail_domains_addresses_create', { "domain_id": domainId, body }),
16
+ },
17
+ create: (body) => client.request('boxes_mail_domains_create', { body }),
18
+ list: () => client.request('boxes_mail_domains_list'),
19
+ verify: (domainId) => client.request('boxes_mail_domains_verify', { "domain_id": domainId }),
20
+ },
21
+ inbox: {
22
+ list: (q = {}) => client.request('boxes_mail_inbox_list', { ...q }),
23
+ },
24
+ mailboxes: {
25
+ list: () => client.request('boxes_mail_mailboxes_list'),
26
+ delegations: {
27
+ list: (mailboxId) => client.request('boxes_mail_mailboxes_delegations_list', { "mailbox_id": mailboxId }),
28
+ },
29
+ },
30
+ messages: {
31
+ get: (id) => client.request('boxes_mail_messages_get', { "id": id }),
32
+ delete: (id) => client.request('boxes_mail_messages_delete', { "id": id }),
33
+ update: (id, body) => client.request('boxes_mail_messages_update', { "id": id, body }),
34
+ attachments: {
35
+ list: (messageId) => client.request('boxes_mail_messages_attachments_list', { "messageId": messageId }),
36
+ },
37
+ delivery: {
38
+ get: (id) => client.request('boxes_mail_messages_delivery_get', { "id": id }),
39
+ },
40
+ },
41
+ send: (body, idempotencyKey) => client.request('boxes_mail_send', { body }, { headers: idempotencyHeaders('boxes_mail_send', idempotencyKey) }),
42
+ threads: {
43
+ get: (id) => client.request('boxes_mail_threads_get', { "id": id }),
44
+ list: (q = {}) => client.request('boxes_mail_threads_list', { ...q }),
45
+ },
46
+ agent: {
47
+ batchSend: (body, idempotencyKey) => client.request('boxes_mail_agent_batch_send', { body }, { headers: idempotencyHeaders('boxes_mail_agent_batch_send', idempotencyKey) }),
48
+ webhooks: {
49
+ create: (body) => client.request('boxes_mail_agent_webhooks_create', { body }),
50
+ list: () => client.request('boxes_mail_agent_webhooks_list'),
51
+ delete: (id) => client.request('boxes_mail_agent_webhooks_delete', { "id": id }),
52
+ },
53
+ activities: {
54
+ list: (q = {}) => client.request('boxes_mail_agent_activities_list', { ...q }),
55
+ },
56
+ state: {
57
+ list: (q = {}) => client.request('boxes_mail_agent_state_list', { ...q }),
58
+ update: (messageId, body) => client.request('boxes_mail_agent_state_update', { "messageId": messageId, body }),
59
+ },
60
+ },
61
+ attachments: {
62
+ content: {
63
+ get: (id) => client.raw('boxes_mail_attachments_content_get', { "id": id }),
64
+ },
65
+ get: (id) => client.request('boxes_mail_attachments_get', { "id": id }),
66
+ delete: (id) => client.request('boxes_mail_attachments_delete', { "id": id }),
67
+ upload: (body) => client.request('boxes_mail_attachments_upload', { body }),
68
+ },
69
+ search: (q) => client.request('boxes_mail_search', { ...q }),
70
+ stream: {
71
+ sse: () => client.raw('boxes_mail_stream_sse'),
72
+ },
73
+ batch: (body) => client.request('boxes_mail_batch', { body }),
74
+ delegations: {
75
+ revoke: (delegationId) => client.request('boxes_mail_delegations_revoke', { "delegation_id": delegationId }),
76
+ },
77
+ extraction: {
78
+ message: {
79
+ get: (messageId) => client.request('boxes_mail_extraction_message_get', { "message_id": messageId }),
80
+ },
81
+ thread: {
82
+ get: (threadId) => client.request('boxes_mail_extraction_thread_get', { "thread_id": threadId }),
83
+ },
84
+ },
85
+ folders: {
86
+ create: (body) => client.request('boxes_mail_folders_create', { body }),
87
+ list: () => client.request('boxes_mail_folders_list'),
88
+ },
89
+ governance: {
90
+ audit: {
91
+ list: (q = {}) => client.request('boxes_mail_governance_audit_list', { ...q }),
92
+ },
93
+ },
94
+ intelligence: {
95
+ thread: {
96
+ get: (threadId) => client.request('boxes_mail_intelligence_thread_get', { "thread_id": threadId }),
97
+ },
98
+ },
99
+ labels: {
100
+ create: (body) => client.request('boxes_mail_labels_create', { body }),
101
+ list: () => client.request('boxes_mail_labels_list'),
102
+ delete: (id) => client.request('boxes_mail_labels_delete', { "id": id }),
103
+ },
104
+ memory: {
105
+ events: {
106
+ submit: (body) => client.request('boxes_mail_memory_events_submit', { body }),
107
+ },
108
+ recall: (q) => client.request('boxes_mail_memory_recall', { ...q }),
109
+ search: (q) => client.request('boxes_mail_memory_search', { ...q }),
110
+ store: (body) => client.request('boxes_mail_memory_store', { body }),
111
+ },
112
+ personas: {
113
+ list: () => client.request('boxes_mail_personas_list'),
114
+ },
115
+ templates: {
116
+ list: () => client.request('boxes_mail_templates_list'),
117
+ },
118
+ },
119
+ files: {
120
+ list: (q = {}) => client.request('boxes_files_list', { ...q }),
121
+ search: (q) => client.request('boxes_files_search', { ...q }),
122
+ recent: {
123
+ list: (q = {}) => client.request('boxes_files_recent_list', { ...q }),
124
+ },
125
+ trash: {
126
+ list: (q = {}) => client.request('boxes_files_trash_list', { ...q }),
127
+ },
128
+ sharedWithMe: {
129
+ list: (q = {}) => client.request('boxes_files_shared_with_me_list', { ...q }),
130
+ },
131
+ upload: (body) => client.request('boxes_files_upload', { body }),
132
+ folders: {
133
+ create: (body) => client.request('boxes_files_folders_create', { body }),
134
+ },
135
+ get: (id) => client.request('boxes_files_get', { "id": id }),
136
+ update: (id, body) => client.request('boxes_files_update', { "id": id, body }),
137
+ delete: (id) => client.request('boxes_files_delete', { "id": id }),
138
+ download: (id) => client.raw('boxes_files_download', { "id": id }),
139
+ restore: (id) => client.request('boxes_files_restore', { "id": id }),
140
+ purge: (id) => client.request('boxes_files_purge', { "id": id }),
141
+ share: (id, body) => client.request('boxes_files_share', { "id": id, body }),
142
+ shares: {
143
+ list: (id) => client.request('boxes_files_shares_list', { "id": id }),
144
+ },
145
+ unshare: (id, shareId) => client.request('boxes_files_unshare', { "id": id, "share_id": shareId }),
146
+ },
147
+ docs: {
148
+ documents: {
149
+ list: (q = {}) => client.request('boxes_docs_documents_list', { ...q }),
150
+ create: (body) => client.request('boxes_docs_documents_create', { body }),
151
+ get: (id) => client.request('boxes_docs_documents_get', { "id": id }),
152
+ update: (id, body) => client.request('boxes_docs_documents_update', { "id": id, body }),
153
+ delete: (id) => client.request('boxes_docs_documents_delete', { "id": id }),
154
+ purge: (id) => client.request('boxes_docs_documents_purge', { "id": id }),
155
+ versions: {
156
+ list: (id, q = {}) => client.request('boxes_docs_documents_versions_list', { "id": id, ...q }),
157
+ },
158
+ share: (id, body) => client.request('boxes_docs_documents_share', { "id": id, body }),
159
+ shares: {
160
+ list: (id) => client.request('boxes_docs_documents_shares_list', { "id": id }),
161
+ },
162
+ unshare: (id, shareId) => client.request('boxes_docs_documents_unshare', { "id": id, "share_id": shareId }),
163
+ collaborators: {
164
+ list: (id) => client.request('boxes_docs_documents_collaborators_list', { "id": id }),
165
+ },
166
+ presence: {
167
+ update: (id, body) => client.request('boxes_docs_documents_presence_update', { "id": id, body }),
168
+ },
169
+ operations: {
170
+ list: (id, q = {}) => client.request('boxes_docs_documents_operations_list', { "id": id, ...q }),
171
+ apply: (id, body) => client.request('boxes_docs_documents_operations_apply', { "id": id, body }),
172
+ },
173
+ events: {
174
+ stream: (id, q = {}) => client.raw('boxes_docs_documents_events_stream', { "id": id, ...q }),
175
+ },
176
+ },
177
+ folders: {
178
+ create: (body) => client.request('boxes_docs_folders_create', { body }),
179
+ },
180
+ search: (q) => client.request('boxes_docs_search', { ...q }),
181
+ recent: {
182
+ list: (q = {}) => client.request('boxes_docs_recent_list', { ...q }),
183
+ },
184
+ trash: {
185
+ list: (q = {}) => client.request('boxes_docs_trash_list', { ...q }),
186
+ },
187
+ templates: {
188
+ list: (q = {}) => client.request('boxes_docs_templates_list', { ...q }),
189
+ },
190
+ sharedWithMe: {
191
+ list: (q = {}) => client.request('boxes_docs_shared_with_me_list', { ...q }),
192
+ },
193
+ mcp: {
194
+ action: (action, body) => client.request('boxes_docs_mcp_action', { "action": action, body }),
195
+ },
196
+ },
197
+ sheets: {
198
+ cells: {
199
+ batch: (id, tabId, body) => client.request('boxes_sheets_cells_batch', { "id": id, "tab_id": tabId, body }),
200
+ delete: (id, tabId, row, col) => client.request('boxes_sheets_cells_delete', { "id": id, "tab_id": tabId, "row": row, "col": col }),
201
+ get: (id, tabId, row, col) => client.request('boxes_sheets_cells_get', { "id": id, "tab_id": tabId, "row": row, "col": col }),
202
+ list: (id, tabId, q = {}) => client.request('boxes_sheets_cells_list', { "id": id, "tab_id": tabId, ...q }),
203
+ set: (id, tabId, body) => client.request('boxes_sheets_cells_set', { "id": id, "tab_id": tabId, body }),
204
+ query: (id, tabId, q) => client.request('boxes_sheets_cells_query', { "id": id, "tab_id": tabId, ...q }),
205
+ range: {
206
+ get: (id, tabId, q) => client.request('boxes_sheets_cells_range_get', { "id": id, "tab_id": tabId, ...q }),
207
+ },
208
+ },
209
+ search: (q) => client.request('boxes_sheets_search', { ...q }),
210
+ sharedWithMe: {
211
+ list: (q = {}) => client.request('boxes_sheets_shared_with_me_list', { ...q }),
212
+ },
213
+ spreadsheets: {
214
+ create: (body) => client.request('boxes_sheets_spreadsheets_create', { body }),
215
+ list: (q = {}) => client.request('boxes_sheets_spreadsheets_list', { ...q }),
216
+ delete: (id) => client.request('boxes_sheets_spreadsheets_delete', { "id": id }),
217
+ get: (id) => client.request('boxes_sheets_spreadsheets_get', { "id": id }),
218
+ update: (id, body) => client.request('boxes_sheets_spreadsheets_update', { "id": id, body }),
219
+ purge: (id) => client.request('boxes_sheets_spreadsheets_purge', { "id": id }),
220
+ share: (id, body) => client.request('boxes_sheets_spreadsheets_share', { "id": id, body }),
221
+ shares: {
222
+ list: (id) => client.request('boxes_sheets_spreadsheets_shares_list', { "id": id }),
223
+ },
224
+ unshare: (id, shareId) => client.request('boxes_sheets_spreadsheets_unshare', { "id": id, "share_id": shareId }),
225
+ },
226
+ tabs: {
227
+ create: (id, body) => client.request('boxes_sheets_tabs_create', { "id": id, body }),
228
+ list: (id) => client.request('boxes_sheets_tabs_list', { "id": id }),
229
+ delete: (id, tabId) => client.request('boxes_sheets_tabs_delete', { "id": id, "tab_id": tabId }),
230
+ get: (id, tabId) => client.request('boxes_sheets_tabs_get', { "id": id, "tab_id": tabId }),
231
+ update: (id, tabId, body) => client.request('boxes_sheets_tabs_update', { "id": id, "tab_id": tabId, body }),
232
+ },
233
+ },
234
+ slides: {
235
+ presentations: {
236
+ create: (body) => client.request('boxes_slides_presentations_create', { body }),
237
+ list: (q = {}) => client.request('boxes_slides_presentations_list', { ...q }),
238
+ delete: (id) => client.request('boxes_slides_presentations_delete', { "id": id }),
239
+ get: (id) => client.request('boxes_slides_presentations_get', { "id": id }),
240
+ update: (id, body) => client.request('boxes_slides_presentations_update', { "id": id, body }),
241
+ share: (id, body) => client.request('boxes_slides_presentations_share', { "id": id, body }),
242
+ sharedWithMe: {
243
+ list: (q = {}) => client.request('boxes_slides_presentations_shared_with_me_list', { ...q }),
244
+ },
245
+ shares: {
246
+ list: (id) => client.request('boxes_slides_presentations_shares_list', { "id": id }),
247
+ },
248
+ unshare: (id, shareId) => client.request('boxes_slides_presentations_unshare', { "id": id, "share_id": shareId }),
249
+ },
250
+ slides: {
251
+ create: (presentationId, body) => client.request('boxes_slides_slides_create', { "presentation_id": presentationId, body }),
252
+ list: (presentationId) => client.request('boxes_slides_slides_list', { "presentation_id": presentationId }),
253
+ delete: (presentationId, slideId) => client.request('boxes_slides_slides_delete', { "presentation_id": presentationId, "slide_id": slideId }),
254
+ get: (presentationId, slideId) => client.request('boxes_slides_slides_get', { "presentation_id": presentationId, "slide_id": slideId }),
255
+ update: (presentationId, slideId, body) => client.request('boxes_slides_slides_update', { "presentation_id": presentationId, "slide_id": slideId, body }),
256
+ reorder: (presentationId, slideId, body) => client.request('boxes_slides_slides_reorder', { "presentation_id": presentationId, "slide_id": slideId, body }),
257
+ },
258
+ templates: {
259
+ create: (body) => client.request('boxes_slides_templates_create', { body }),
260
+ list: (q = {}) => client.request('boxes_slides_templates_list', { ...q }),
261
+ delete: (id) => client.request('boxes_slides_templates_delete', { "id": id }),
262
+ get: (id) => client.request('boxes_slides_templates_get', { "id": id }),
263
+ update: (id, body) => client.request('boxes_slides_templates_update', { "id": id, body }),
264
+ },
265
+ },
266
+ calendar: {
267
+ availability: {
268
+ get: (q) => client.request('boxes_calendar_availability_get', { ...q }),
269
+ },
270
+ calendars: {
271
+ create: (body) => client.request('boxes_calendar_calendars_create', { body }),
272
+ list: () => client.request('boxes_calendar_calendars_list'),
273
+ delete: (id) => client.request('boxes_calendar_calendars_delete', { "id": id }),
274
+ get: (id) => client.request('boxes_calendar_calendars_get', { "id": id }),
275
+ update: (id, body) => client.request('boxes_calendar_calendars_update', { "id": id, body }),
276
+ },
277
+ events: {
278
+ attendees: {
279
+ list: (id) => client.request('boxes_calendar_events_attendees_list', { "id": id }),
280
+ },
281
+ create: (body) => client.request('boxes_calendar_events_create', { body }),
282
+ list: (q = {}) => client.request('boxes_calendar_events_list', { ...q }),
283
+ delete: (id) => client.request('boxes_calendar_events_delete', { "id": id }),
284
+ get: (id) => client.request('boxes_calendar_events_get', { "id": id }),
285
+ update: (id, body) => client.request('boxes_calendar_events_update', { "id": id, body }),
286
+ rsvp: (id, body) => client.request('boxes_calendar_events_rsvp', { "id": id, body }),
287
+ search: (q) => client.request('boxes_calendar_events_search', { ...q }),
288
+ },
289
+ schedulingLinks: {
290
+ book: (id, body) => client.request('boxes_calendar_scheduling_links_book', { "id": id, body }),
291
+ bySlug: {
292
+ get: (slug) => client.request('boxes_calendar_scheduling_links_by_slug_get', { "slug": slug }),
293
+ },
294
+ create: (body) => client.request('boxes_calendar_scheduling_links_create', { body }),
295
+ list: () => client.request('boxes_calendar_scheduling_links_list'),
296
+ delete: (id) => client.request('boxes_calendar_scheduling_links_delete', { "id": id }),
297
+ get: (id) => client.request('boxes_calendar_scheduling_links_get', { "id": id }),
298
+ update: (id, body) => client.request('boxes_calendar_scheduling_links_update', { "id": id, body }),
299
+ },
300
+ },
301
+ identity: {
302
+ me: {
303
+ get: () => client.request('boxes_identity_me_get'),
304
+ },
305
+ tenants: {
306
+ current: {
307
+ get: () => client.request('boxes_identity_tenants_current_get'),
308
+ },
309
+ },
310
+ users: {
311
+ get: (id) => client.request('boxes_identity_users_get', { "id": id }),
312
+ list: (q = {}) => client.request('boxes_identity_users_list', { ...q }),
313
+ },
314
+ workspaces: {
315
+ list: (q = {}) => client.request('boxes_identity_workspaces_list', { ...q }),
316
+ get: (id) => client.request('boxes_identity_workspaces_get', { "id": id }),
317
+ members: {
318
+ list: (id) => client.request('boxes_identity_workspaces_members_list', { "id": id }),
319
+ },
320
+ },
321
+ },
322
+ mcp: {
323
+ sessions: {
324
+ context: {
325
+ set: (sessionId, body) => client.request('boxes_mcp_sessions_context_set', { "session_id": sessionId, body }),
326
+ },
327
+ create: (body) => client.request('boxes_mcp_sessions_create', { body }),
328
+ list: () => client.request('boxes_mcp_sessions_list'),
329
+ delete: (sessionId) => client.request('boxes_mcp_sessions_delete', { "session_id": sessionId }),
330
+ get: (sessionId) => client.request('boxes_mcp_sessions_get', { "session_id": sessionId }),
331
+ },
332
+ tools: {
333
+ call: (body) => client.request('boxes_mcp_tools_call', { body }),
334
+ list: () => client.request('boxes_mcp_tools_list'),
335
+ },
336
+ },
337
+ };
338
+ }
package/dist/client.js CHANGED
@@ -97,7 +97,7 @@ export class GenesisClient {
97
97
  if (operationTable[operationId].rawResponse)
98
98
  return res;
99
99
  // DELETE /env answers 200 with an empty body.
100
- if (operationId === 'hives_delete_project_env') {
100
+ if (operationId === 'hives_delete_project_env' || operationId === 'hives_delete_project_env_key') {
101
101
  void res.body?.cancel().catch(() => { });
102
102
  return undefined;
103
103
  }
@@ -183,11 +183,13 @@ export class GenesisClient {
183
183
  input = { ...input, body: validateHivesEnvironment(input.body) };
184
184
  if (operationId === 'hives_delete_project_env')
185
185
  input = { ...input, body: validateHivesEnvironmentNames(input.body) };
186
+ if (operationId === 'hives_delete_project_env_key')
187
+ validateHivesEnvironmentNames([input.key]);
186
188
  const objectBody = isHivesObjectUpload(operationId) ? await hivesObjectBody(input.body) : undefined;
187
189
  const url = this.url(operationId, input);
188
190
  const headers = {
189
191
  accept: 'application/json',
190
- 'user-agent': this.opts.userAgent ?? '@onesi/genesis/0.2.0',
192
+ 'user-agent': this.opts.userAgent ?? '@onesi/genesis/0.2.2',
191
193
  ...this.opts.headers, ...init.headers,
192
194
  };
193
195
  if (op.service === 'blinds' && !['GET', 'HEAD', 'OPTIONS'].includes(op.method))
@@ -245,7 +247,7 @@ export class GenesisClient {
245
247
  body = JSON.stringify(input.body);
246
248
  }
247
249
  }
248
- const environmentOperation = op.service === 'hives' && /_project_env(?:ironment)?$/.test(operationId);
250
+ const environmentOperation = op.service === 'hives' && /_project_env(?:ironment|_key)?$/.test(operationId);
249
251
  const secretOperation = op.service === 'hives' && (/_secrets?$/.test(operationId) || environmentOperation);
250
252
  const functionOperation = op.service === 'hives' && (op.rawResponse || /_function(?:s|_async)?$/.test(operationId));
251
253
  let res;
@@ -291,7 +293,7 @@ export class GenesisClient {
291
293
  throw new GenesisError({ status: res.status, type: 'invalid_response', operationId,
292
294
  message: 'Hives operation status was not confirmed. Keep the original idempotency key and reconcile its operation.' });
293
295
  }
294
- if (op.rawResponse && res.ok)
296
+ if (op.rawResponse && op.service === 'hives' && res.ok)
295
297
  throw new GenesisError({ status: res.status, type: 'invalid_response', operationId,
296
298
  message: 'Hives did not confirm a completed guest execution. Keep the original invocation key and reconcile its operation.' });
297
299
  if (functionOperation && !res.ok) {
package/dist/errors.d.ts CHANGED
@@ -33,3 +33,9 @@ export declare function errorOutcome(body: unknown): string | undefined;
33
33
  /** Optional fields the gateway adds to an envelope; each must be a bounded string when present. */
34
34
  export declare const ENVELOPE_EXTRA_FIELDS: readonly string[];
35
35
  export declare const envelopeExtrasValid: (error: Record<string, unknown>) => boolean;
36
+ /**
37
+ * The service's error body as the CLI (`--json`) and MCP print it beside the envelope, redacted and bounded
38
+ * by `redactErrorBody` (see redact.ts). Undefined when the SDK kept no body: it deliberately drops bodies
39
+ * that may echo submitted secrets or guest data (Hives secret and function refusals).
40
+ */
41
+ export declare function errorBody(e: GenesisError): unknown;
package/dist/errors.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { authorizationCode, redactErrorBody } from './redact.js';
1
2
  /** Normalized error for every Genesis service (gateway `{error:{type,message}}`, IAM `{error,error_description}`, Relays `{error}`, Foundry/OpenAI shape). */
2
3
  export class GenesisError extends Error {
3
4
  status;
@@ -25,15 +26,41 @@ export class GenesisError extends Error {
25
26
  // An OAuth-style token (`{"error":"forbidden"}`) is the type; any other string is a message, and type stays a stable token.
26
27
  const type = typeof e === 'object' && e ? (e.type ?? e.code ?? 'error')
27
28
  : typeof e === 'string' && /^[a-z][a-z0-9_]{0,63}$/.test(e) ? e : statusType(res.status);
29
+ const code = backendCode(body);
28
30
  const message = (typeof e === 'object' && e?.message) || body?.error_description || body?.message ||
29
- (typeof e === 'string' && e) || (typeof body === 'string' && body) || `${res.status} ${res.statusText}`;
31
+ (typeof e === 'string' && e) || (typeof body === 'string' && body) || `${res.status} ${res.statusText}${code ? ` (${code})` : ''}`;
30
32
  return new GenesisError({
31
- status: res.status, type, message, code: typeof e === 'object' ? e?.code : undefined,
33
+ status: res.status, type, message, code,
32
34
  requestId: [typeof e === 'object' ? e?.request_id : undefined, body?.request_id, res.headers.get('x-request-id')].find((v) => typeof v === 'string' && v !== ''),
33
35
  operationId, body,
34
36
  });
35
37
  }
36
38
  }
39
+ const CODE_TOKEN = /^[A-Za-z][A-Za-z0-9_.:-]{0,63}$/;
40
+ /** A refusal code is one case (`release_not_proven_safe`, `HARNESS_NOT_ON_NODE`), never a mixed-case random string. */
41
+ const ONE_CASE = /^(?:[a-z][a-z0-9_.:-]*|[A-Z][A-Z0-9_.:-]*)$/;
42
+ /**
43
+ * The refusal code of an error body. The envelope's `error.code` wins, unless it is only the gateway's generic
44
+ * `UPSTREAM_<status>`; otherwise the backend's own top-level `code`, which the gateway keeps beside its envelope
45
+ * or passes through unwrapped (Hives `{"code":"release_not_proven_safe",...}` on a 409 release).
46
+ *
47
+ * Accepting a top-level `code` here is deliberate and differs from the Hives function/invocation error path
48
+ * (`hivesErrorDetail` in client.ts), which rejects it because there a top-level `code` belongs to an operation
49
+ * receipt. A top-level `code` can also be an OAuth authorization code echoed by an authorize/token answer, so
50
+ * it is not taken when the body looks like one (`redirect_uri`, `access_token`, `iss`...), beside any string
51
+ * `error`, when the value looks random, or when it is not a one-case code. `errorBody` redacts that `code` in an
52
+ * OAuth-shaped body, beside an OAuth error token (`{error: "invalid_grant", code}`) and when it looks random
53
+ * (16 or more letters and digits). Any other refused `code`, such as one beside a non-OAuth string `error`, is
54
+ * printed in the body but never reported as the error code.
55
+ */
56
+ function backendCode(body) {
57
+ if (!row(body))
58
+ return undefined;
59
+ const envelope = row(body.error) && typeof body.error.code === 'string' && body.error.code !== '' ? body.error.code : undefined;
60
+ const own = typeof body.code === 'string' && CODE_TOKEN.test(body.code) && ONE_CASE.test(body.code)
61
+ && typeof body.error !== 'string' && !authorizationCode(body) ? body.code : undefined;
62
+ return envelope !== undefined && !(own && /^UPSTREAM_\d{3}$/.test(envelope)) ? envelope : own;
63
+ }
37
64
  const statusType = (s) => s === 401 ? 'unauthorized' : s === 403 ? 'forbidden' : s === 404 ? 'not_found' : s === 429 ? 'rate_limited' : s >= 500 ? 'upstream_error' : 'error';
38
65
  /** The gateway catalog fields of an error, for JSON output: `code`, `required_scope` and `docs_url` when the gateway sent them. */
39
66
  export function errorCatalog(e) {
@@ -64,3 +91,11 @@ export function errorOutcome(body) {
64
91
  /** Optional fields the gateway adds to an envelope; each must be a bounded string when present. */
65
92
  export const ENVELOPE_EXTRA_FIELDS = ['type', 'message', 'docs_url', 'layer', 'reason', 'required_scope'];
66
93
  export const envelopeExtrasValid = (error) => ENVELOPE_EXTRA_FIELDS.every(name => error[name] === undefined || typeof error[name] === 'string' && error[name].length <= 2048);
94
+ /**
95
+ * The service's error body as the CLI (`--json`) and MCP print it beside the envelope, redacted and bounded
96
+ * by `redactErrorBody` (see redact.ts). Undefined when the SDK kept no body: it deliberately drops bodies
97
+ * that may echo submitted secrets or guest data (Hives secret and function refusals).
98
+ */
99
+ export function errorBody(e) {
100
+ return redactErrorBody(e.body);
101
+ }
package/dist/flocks.d.ts CHANGED
@@ -11,6 +11,7 @@ export interface WaitForJobOptions {
11
11
  onUpdate?: (job: FlocksJob) => void;
12
12
  }
13
13
  export type FlocksJob = OperationOutput<'flocks_getAccountJob'>;
14
+ export type FlocksRun = OperationOutput<'flocks_getRun'>;
14
15
  /** Org scope comes from the One account credential verified by the gateway. */
15
16
  export declare function flocksModule(client: GenesisClient): {
16
17
  readiness: {
@@ -35,6 +36,12 @@ export declare function flocksModule(client: GenesisClient): {
35
36
  accounts?: import("./index.js").components["schemas"]["Flocks.HeartbeatAccount"][];
36
37
  accounts_supported?: boolean;
37
38
  }[]>;
39
+ /** One node's presence (online, heartbeat age, harnesses) and a page of the runs recorded on it, newest first. */
40
+ activity: (id: string, query?: Omit<OperationInput<"flocks_getNodeActivity">, "id">) => Promise<{
41
+ node: import("./index.js").components["schemas"]["Flocks.NodePresence"];
42
+ items: import("./index.js").components["schemas"]["Flocks.Run"][];
43
+ next_cursor: string | null;
44
+ }>;
38
45
  rename: (id: string, nickname: string) => Promise<{
39
46
  id: string;
40
47
  name: string;
@@ -205,7 +212,34 @@ export declare function flocksModule(client: GenesisClient): {
205
212
  owner_subject?: string;
206
213
  created_at: number;
207
214
  updated_at: number;
215
+ inference_account_id: string | null;
216
+ account_owner_org: string | null;
217
+ grantee_org: string | null;
218
+ run_seconds: number | null;
208
219
  }>;
220
+ /** Starts a run of an agent (202 Run). `node_id` overrides the agent's pinned node for this run. */
221
+ create: (agent_id: string, body: OperationInput<"flocks_createRun">["body"], o?: {
222
+ signal?: AbortSignal;
223
+ }) => Promise<{
224
+ id: string;
225
+ agent_id: string;
226
+ harness: string;
227
+ node_id: string | null;
228
+ task: string;
229
+ state: "pending" | "running" | "completed" | "failed";
230
+ error_code: string | null;
231
+ owner_subject?: string;
232
+ created_at: number;
233
+ updated_at: number;
234
+ inference_account_id: string | null;
235
+ account_owner_org: string | null;
236
+ grantee_org: string | null;
237
+ run_seconds: number | null;
238
+ }>;
239
+ /** Polls a run until it is completed or failed. Rejects with a timeout error after `timeoutMs` (default 30 minutes). */
240
+ wait: (run_id: string, o?: WaitForJobOptions & {
241
+ onUpdate?: (run: FlocksRun) => void;
242
+ }) => Promise<FlocksRun>;
209
243
  };
210
244
  joinTokens: {
211
245
  exchange: (body: OperationInput<"flocks_exchangeJoinToken">["body"]) => Promise<{
@@ -262,6 +296,21 @@ export declare function flocksModule(client: GenesisClient): {
262
296
  updated_at: number;
263
297
  bound_instances?: number;
264
298
  }>;
299
+ /** Owner only: clears the recorded identity (the next verified switch on one of your own instances records it again). */
300
+ resetIdentity: (id: string, o?: FlocksWriteOptions) => Promise<{
301
+ id: string;
302
+ provider: string;
303
+ label: string;
304
+ auth_kind: "subscription_oauth" | "api_key";
305
+ identity: string | null;
306
+ status: "pending_login" | "active" | "needs_login" | "revoked" | "deleted";
307
+ owner_org: string;
308
+ granted: boolean;
309
+ created_by: string;
310
+ created_at: number;
311
+ updated_at: number;
312
+ bound_instances?: number;
313
+ }>;
265
314
  /** Signs the account out of every bound instance, then revokes the credential. Returns { account, job_id }. */
266
315
  delete: (id: string, o?: FlocksWriteOptions) => Promise<{
267
316
  account: import("./index.js").components["schemas"]["Flocks.Account"];
package/dist/flocks.js CHANGED
@@ -1,4 +1,14 @@
1
1
  import { GenesisError } from './errors.js';
2
+ /** Sleeps `ms`, rejecting early on abort; the abort listener is removed when the timer fires. */
3
+ function pause(ms, signal) {
4
+ return new Promise((resolve, reject) => {
5
+ const onAbort = () => { clearTimeout(t); reject(signal.reason ?? new Error('aborted')); };
6
+ const t = setTimeout(() => { signal?.removeEventListener('abort', onAbort); resolve(); }, ms);
7
+ if (signal?.aborted)
8
+ return onAbort();
9
+ signal?.addEventListener('abort', onAbort, { once: true });
10
+ });
11
+ }
2
12
  /** Org scope comes from the One account credential verified by the gateway. */
3
13
  export function flocksModule(client) {
4
14
  const nodePath = (id) => ({ id });
@@ -10,6 +20,8 @@ export function flocksModule(client) {
10
20
  },
11
21
  nodes: {
12
22
  list: () => client.request('flocks_listNodes'),
23
+ /** One node's presence (online, heartbeat age, harnesses) and a page of the runs recorded on it, newest first. */
24
+ activity: (id, query = {}) => client.request('flocks_getNodeActivity', { id, ...query }),
13
25
  rename: (id, nickname) => client.request('flocks_renameNode', { ...nodePath(id), body: { nickname } }),
14
26
  /** Set an instance nickname and/or labels (the label key `flock` groups instances). */
15
27
  update: (id, body) => client.request('flocks_renameNode', { ...nodePath(id), body }),
@@ -39,6 +51,21 @@ export function flocksModule(client) {
39
51
  runs: {
40
52
  list: (query = {}) => client.request('flocks_listRuns', query),
41
53
  get: (run_id) => client.request('flocks_getRun', { run_id }),
54
+ /** Starts a run of an agent (202 Run). `node_id` overrides the agent's pinned node for this run. */
55
+ create: (agent_id, body, o = {}) => client.request('flocks_createRun', { agent_id, body }, o.signal ? { signal: o.signal } : undefined),
56
+ /** Polls a run until it is completed or failed. Rejects with a timeout error after `timeoutMs` (default 30 minutes). */
57
+ wait: async (run_id, o = {}) => {
58
+ const interval = o.intervalMs ?? 2000, deadline = Date.now() + (o.timeoutMs ?? 1_800_000);
59
+ for (;;) {
60
+ const run = await client.request('flocks_getRun', { run_id }, o.signal ? { signal: o.signal } : undefined);
61
+ o.onUpdate?.(run);
62
+ if (run.state === 'completed' || run.state === 'failed')
63
+ return run;
64
+ if (Date.now() + interval > deadline)
65
+ throw new GenesisError({ status: 0, type: 'timeout', operationId: 'flocks_getRun', message: `Run ${run_id} was still ${run.state} after ${o.timeoutMs ?? 1_800_000} ms; poll runs.get again.` });
66
+ await pause(interval, o.signal);
67
+ }
68
+ },
42
69
  },
43
70
  joinTokens: {
44
71
  exchange: (body) => client.request('flocks_exchangeJoinToken', { body }),
@@ -53,6 +80,8 @@ export function flocksModule(client) {
53
80
  list: (query = {}) => client.request('flocks_listAccounts', query),
54
81
  create: (body, o) => write('flocks_createAccount', { body }, o),
55
82
  get: (id) => client.request('flocks_getAccount', { id }),
83
+ /** Owner only: clears the recorded identity (the next verified switch on one of your own instances records it again). */
84
+ resetIdentity: (id, o) => write('flocks_resetAccountIdentity', { id }, o),
56
85
  /** Signs the account out of every bound instance, then revokes the credential. Returns { account, job_id }. */
57
86
  delete: (id, o) => write('flocks_deleteAccount', { id }, o),
58
87
  /** Starts a login on one of your instances; the device url and code appear on the job item for you only. */
@@ -87,10 +116,7 @@ export function flocksModule(client) {
87
116
  return job;
88
117
  if (Date.now() + interval > deadline)
89
118
  throw new GenesisError({ status: 0, type: 'timeout', operationId: 'flocks_getAccountJob', message: `Job ${id} was still running after ${o.timeoutMs ?? 600_000} ms; poll jobs.get again.` });
90
- await new Promise((resolve, reject) => {
91
- const t = setTimeout(resolve, interval);
92
- o.signal?.addEventListener('abort', () => { clearTimeout(t); reject(o.signal.reason ?? new Error('aborted')); }, { once: true });
93
- });
119
+ await pause(interval, o.signal);
94
120
  }
95
121
  },
96
122
  },
package/dist/foundry.d.ts CHANGED
@@ -70,6 +70,11 @@ export declare function foundryModule(client: GenesisClient): {
70
70
  verificationKey: () => Promise<{
71
71
  [key: string]: unknown;
72
72
  }>;
73
+ /** Public: the current key plus the retired keys that still verify receipts signed before a rotation. */
74
+ verificationKeys: () => Promise<{
75
+ current: import("./index.js").components["schemas"]["Foundry.ReceiptVerificationKey"];
76
+ retired: import("./index.js").components["schemas"]["Foundry.ReceiptVerificationKey"][];
77
+ }>;
73
78
  };
74
79
  keys: {
75
80
  list: () => Promise<{
package/dist/foundry.js CHANGED
@@ -20,6 +20,8 @@ export function foundryModule(client) {
20
20
  get: (receipt_id) => client.request('foundry_getGenerationReceipt', { receipt_id }),
21
21
  byRequest: (request_id) => client.request('foundry_getGenerationReceiptByRequest', { request_id }),
22
22
  verificationKey: () => client.request('foundry_getReceiptVerificationKey'),
23
+ /** Public: the current key plus the retired keys that still verify receipts signed before a rotation. */
24
+ verificationKeys: () => client.request('foundry_listReceiptVerificationKeys'),
23
25
  },
24
26
  keys: {
25
27
  list: () => client.request('foundry_listApiKeys'),