@usenaive-sdk/blueprints 0.3.0 → 0.4.0

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/index.js CHANGED
@@ -8,6 +8,112 @@ function isId(prefix, value) {
8
8
  return SUFFIX_PATTERN.test(value.slice(head.length).toLowerCase());
9
9
  }
10
10
 
11
+ // ../core/src/errors.ts
12
+ var CODES = {
13
+ window_unavailable: ["invalid_request", 400],
14
+ validation_failed: ["invalid_request", 400],
15
+ unauthorized: ["authentication", 401],
16
+ forbidden: ["permission", 403],
17
+ not_found: ["not_found", 404],
18
+ budget_exceeded: ["quota", 402],
19
+ insufficient_credits: ["quota", 402],
20
+ /**
21
+ * The organization holds no active plan, so it may not be used. `402`, alongside the other two
22
+ * money codes, because the remedy is a payment — not `403`, which reads as "your credential is
23
+ * wrong" and would send a customer to rotate a perfectly good key. Distinct from
24
+ * `insufficient_credits`: that one means "fund the balance", this one means "start the plan".
25
+ */
26
+ subscription_required: ["quota", 402],
27
+ version_conflict: ["conflict", 409],
28
+ /**
29
+ * The name is taken by a resource another project owns, and the request did not ask to take it
30
+ * (ADR-0375). Nothing existing fits: `validation_failed` says the request is malformed and it is
31
+ * not, `forbidden` reads as "your credential is wrong" and sends a customer to rotate a good key,
32
+ * and `version_conflict` means optimistic concurrency.
33
+ */
34
+ name_conflict: ["conflict", 409],
35
+ /**
36
+ * A shared declaration moved underneath the applier: the install's `revision` is not the
37
+ * `expected_revision` the apply carried (`§29.6`). Not `version_conflict`, which is one
38
+ * immutable-versioned object's optimistic concurrency and whose remedy is to re-read that
39
+ * object — this one carries a set of drifted PATHS and its remedy is a merge, and a client that
40
+ * cannot tell them apart shows a config diff for a stale agent version.
41
+ */
42
+ revision_conflict: ["conflict", 409],
43
+ idempotency_conflict: ["conflict", 409],
44
+ /**
45
+ * A lifecycle action asked of an object whose status does not admit it (§43–§45): forming a
46
+ * company on an unverified verification, funding a `frozen` wallet, cancelling a card that is not
47
+ * `active`. Not `version_conflict` — nothing raced; the remedy is to read the status.
48
+ */
49
+ state_conflict: ["conflict", 409],
50
+ session_running: ["conflict", 409],
51
+ session_terminal: ["conflict", 409],
52
+ computer_unavailable: ["conflict", 409],
53
+ /**
54
+ * Two P2 additions (ADR-0118). Both mean "not an error — retry later", and no existing code
55
+ * carries that: `feature_not_configured` is permanent, `computer_unavailable` is about a
56
+ * sandbox, and `validation_failed` would tell a durable runtime to give up on something that
57
+ * will succeed once verification or carrier approval clears.
58
+ */
59
+ job_not_ready: ["conflict", 409],
60
+ compliance_pending: ["conflict", 409],
61
+ // core-gaps: contracts (`canonical-spec §32`, §37; ADR-0448)
62
+ /** `--app` omitted and the org has more than one fullstack app to resolve it to (§37.2). */
63
+ ambiguous_app: ["conflict", 409],
64
+ /** A saved browser login is held by a human-login flow for the next 15 minutes (§32.6). */
65
+ context_locked: ["conflict", 409],
66
+ rate_limited: ["rate_limit", 429],
67
+ feature_not_configured: ["not_implemented", 501],
68
+ internal_error: ["api_error", 500],
69
+ /**
70
+ * A configured upstream answered with a failure of its own — a 5xx, or a browser automation that
71
+ * did nothing (§32.5). Not `internal_error`: the remedy is a retry, and nothing of ours broke.
72
+ */
73
+ provider_error: ["api_error", 502]
74
+ };
75
+ var VettaError = class extends Error {
76
+ type;
77
+ code;
78
+ httpStatus;
79
+ param;
80
+ constructor(code, message3, param) {
81
+ super(message3);
82
+ this.name = "VettaError";
83
+ const [type, httpStatus] = CODES[code];
84
+ this.type = type;
85
+ this.code = code;
86
+ this.httpStatus = httpStatus;
87
+ this.param = param;
88
+ }
89
+ toEnvelope(requestId) {
90
+ return {
91
+ error: {
92
+ type: this.type,
93
+ code: this.code,
94
+ message: this.message,
95
+ request_id: requestId,
96
+ ...this.param === void 0 ? {} : { param: this.param }
97
+ }
98
+ };
99
+ }
100
+ };
101
+
102
+ // ../core/src/money.ts
103
+ var USD = 1e6;
104
+ function invalid(message3) {
105
+ throw new VettaError("validation_failed", message3);
106
+ }
107
+ function microUsd(value) {
108
+ if (!Number.isSafeInteger(value)) invalid(`micro-USD must be an integer within range, got ${value}`);
109
+ return value;
110
+ }
111
+ function decimalStringFromMicro(amount) {
112
+ const absolute = BigInt(Math.abs(amount));
113
+ const fraction = (absolute % BigInt(USD)).toString().padStart(6, "0").replace(/0+$/, "").padEnd(2, "0");
114
+ return `${amount < 0 ? "-" : ""}${absolute / BigInt(USD)}.${fraction}`;
115
+ }
116
+
11
117
  // ../core/src/session-token.ts
12
118
  var SESSION_TTL_SECONDS = 30 * 24 * 60 * 60;
13
119
  var encoder = new TextEncoder();
@@ -36,6 +142,8 @@ var AUDIT_ACTIONS_P1 = [
36
142
  "computer.paused",
37
143
  "computer.resumed",
38
144
  "computer.snapshot_created",
145
+ "computer.updated",
146
+ "browser.live_view_opened",
39
147
  "deployment.created",
40
148
  "deployment.updated",
41
149
  "deployment.deleted",
@@ -95,13 +203,60 @@ var AUDIT_ACTIONS_P3 = [
95
203
  "app.db_queried",
96
204
  /** A ticket was minted that lets one browser past an app's own operator gate (§29.7). */
97
205
  "app.entered",
98
- "blueprint.installed"
206
+ /** A link was minted that serves one file's bytes to anyone holding it, for seven days (§40). */
207
+ "file.linked",
208
+ "blueprint.installed",
209
+ /** An install's answers were rewritten — what a template's crew is told about the business (§31.8). */
210
+ "blueprint.context_updated",
211
+ /** The one creator-program effect inside a tenant: a new organization attributed to a creator (§42.6). */
212
+ "referral.attributed"
213
+ ];
214
+ var AUDIT_ACTIONS_PRIMITIVES = [
215
+ "legal_verification.started",
216
+ "legal_member.completed",
217
+ "legal_member.link_resent",
218
+ "legal_company.created",
219
+ "legal_company.submitted",
220
+ "wallet.created",
221
+ "wallet.policy_updated",
222
+ "wallet.frozen",
223
+ "wallet.unfrozen",
224
+ "wallet.funded",
225
+ "wallet.transferred",
226
+ "wallet.swept",
227
+ "wallet.paid",
228
+ "card.issued",
229
+ "card.retried",
230
+ "card.cancelled",
231
+ "card.refunded",
232
+ /** The one read that files: a credential left the vault for a caller (§45.3). */
233
+ "card.credentials_revealed"
234
+ ];
235
+ var AUDIT_ACTIONS_CORE_GAPS = [
236
+ "browser.context_saved",
237
+ "browser.context_granted",
238
+ "browser.context_revoked",
239
+ "browser.credential_stored",
240
+ // core-gaps: U2-browser-api — §32.8's session events, audit-only when no session drove them.
241
+ "browser.session_opened",
242
+ "browser.session_closed",
243
+ "file.imported",
244
+ "app.db_rest",
245
+ "app.db_migrated",
246
+ "app.bucket_created",
247
+ "app.bucket_deleted",
248
+ "app.storage_put",
249
+ "app.storage_get",
250
+ // core-gaps: U9-storage
251
+ "app.storage_deleted"
99
252
  ];
100
253
  var AUDIT_ACTIONS = [
101
254
  ...AUDIT_ACTIONS_SHIPPED,
102
255
  ...AUDIT_ACTIONS_P1,
103
256
  ...AUDIT_ACTIONS_P2,
104
- ...AUDIT_ACTIONS_P3
257
+ ...AUDIT_ACTIONS_P3,
258
+ ...AUDIT_ACTIONS_PRIMITIVES,
259
+ ...AUDIT_ACTIONS_CORE_GAPS
105
260
  ];
106
261
 
107
262
  // ../core/src/schema/common.ts
@@ -119,7 +274,7 @@ var JsonSchemaDocument = z.record(z.string(), z.unknown()).refine((schema) => sc
119
274
  var WindowSchema = z.enum(["immediate", "priority", "loose"]);
120
275
  var TOKEN_TIERS = ["input", "cache_write", "cache_read", "output", "reasoning"];
121
276
  var TokenTierSchema = z.enum(TOKEN_TIERS);
122
- var TOOL_TIERS = ["search", "media", "social"];
277
+ var TOOL_TIERS = ["search", "media", "social", "browser", "storage"];
123
278
  var LINE_ITEM_TIERS = [...TOKEN_TIERS, "computer", ...TOOL_TIERS];
124
279
  var LineItemTierSchema = z.enum(LINE_ITEM_TIERS);
125
280
  var TokenUsageSchema = z.object({
@@ -142,84 +297,333 @@ var HARNESS_IDS = ["pi", "claude_code", "vetta", "hermes"];
142
297
  var HarnessIdSchema = z2.enum(HARNESS_IDS);
143
298
 
144
299
  // ../core/src/schema/agent.ts
300
+ import { z as z5 } from "zod";
301
+
302
+ // ../core/src/schema/browser.ts
303
+ import { z as z4 } from "zod";
304
+
305
+ // ../core/src/schema/org.ts
145
306
  import { z as z3 } from "zod";
146
- var ToolPermissionSchema = z3.enum(["allow", "ask", "deny"]);
147
- var ToolConfigSchema = z3.object({
307
+ var OrganizationSchema = z3.object({
308
+ id: idOf("org"),
309
+ object: z3.literal("organization"),
310
+ name: z3.string(),
311
+ balance_micro_usd: MicroUsdField,
312
+ created_at: Timestamp
313
+ });
314
+ var RoleSchema = z3.enum(["owner", "admin", "member"]);
315
+ var MemberSchema = z3.object({
316
+ id: z3.string(),
317
+ object: z3.literal("member"),
318
+ email: z3.email(),
319
+ role: RoleSchema,
320
+ invited_by: z3.string().nullable(),
321
+ created_at: Timestamp
322
+ });
323
+ var SCOPES = [
324
+ "agents:read",
325
+ "agents:write",
326
+ "sessions:read",
327
+ "sessions:write",
328
+ /**
329
+ * THE MODEL DOOR AND NOTHING ELSE. `/v1/proxy/*` used to take `sessions:write`, which also opens
330
+ * session create and cancel — so a credential handed to a customer's micro-VM, if it leaked, could
331
+ * start sessions for the whole organization. This scope buys exactly one capability, so a sandbox
332
+ * token can be minted with it alone.
333
+ *
334
+ * The proxy routes accept EITHER this or `sessions:write`: narrowing an already-published route
335
+ * would break every key that reaches it today (§17).
336
+ */
337
+ "proxy:write",
338
+ "computers:write",
339
+ "files:read",
340
+ "files:write",
341
+ "billing:read",
342
+ "billing:write",
343
+ "webhooks:*",
344
+ "audit:read",
345
+ "admin"
346
+ ];
347
+ var ScopeSchema = z3.enum(SCOPES);
348
+ var ApiKeySchema = z3.object({
349
+ id: idOf("key"),
350
+ object: z3.literal("api_key"),
351
+ name: z3.string(),
352
+ prefix: z3.string(),
353
+ scopes: z3.array(ScopeSchema),
354
+ created_by: PrincipalSchema,
355
+ last_used_at: Timestamp.nullable(),
356
+ created_at: Timestamp
357
+ });
358
+ var LedgerEntrySchema = z3.object({
359
+ id: idOf("led"),
360
+ type: z3.enum(["debit", "credit"]),
361
+ amount_micro_usd: MicroUsdField,
362
+ balance_after_micro_usd: MicroUsdField,
363
+ actor: PrincipalSchema,
364
+ session_id: idOf("ses").nullable(),
365
+ agent_id: idOf("agt").nullable(),
366
+ deployment_id: idOf("dep").nullable(),
367
+ line_items: z3.array(z3.object({ tier: LineItemTierSchema, amount_micro_usd: MicroUsdField })),
368
+ created_at: Timestamp
369
+ });
370
+ var TopupSchema = z3.object({
371
+ id: z3.string(),
372
+ object: z3.literal("topup"),
373
+ amount_micro_usd: MicroUsdField.positive(),
374
+ status: z3.enum(["pending", "requires_action", "succeeded", "failed"]),
375
+ action_url: z3.url().nullable(),
376
+ balance_after_micro_usd: MicroUsdField.nullable(),
377
+ created_at: Timestamp
378
+ });
379
+ var WebhookEndpointSchema = z3.object({
380
+ id: idOf("whk"),
381
+ object: z3.literal("webhook_endpoint"),
382
+ url: z3.url(),
383
+ events: z3.array(z3.string()),
148
384
  enabled: z3.boolean(),
149
- permission: ToolPermissionSchema,
150
- config: z3.record(z3.string(), z3.unknown()).optional()
385
+ created_at: Timestamp
151
386
  });
152
- var ToolsetSchema = z3.object({
153
- default_config: z3.object({ permission: ToolPermissionSchema }),
154
- configs: z3.record(z3.string(), ToolConfigSchema)
387
+ var WebhookDeliverySchema = z3.object({
388
+ id: idOf("whd"),
389
+ event_id: idOf("evt"),
390
+ event_type: z3.string(),
391
+ status: z3.enum(["pending", "succeeded", "failed"]),
392
+ attempts: z3.number().int().nonnegative(),
393
+ response_status: z3.number().int().nullable(),
394
+ response_snippet: z3.string().nullable(),
395
+ delivered_at: Timestamp.nullable(),
396
+ next_retry_at: Timestamp.nullable()
397
+ });
398
+ var AuditEntrySchema = z3.object({
399
+ id: idOf("aud"),
400
+ object: z3.literal("audit_entry"),
401
+ actor: PrincipalSchema,
402
+ action: AuditActionSchema,
403
+ resource_type: z3.string(),
404
+ resource_id: z3.string(),
405
+ request_id: z3.string(),
406
+ metadata: Metadata,
407
+ created_at: Timestamp
408
+ });
409
+
410
+ // ../core/src/schema/browser.ts
411
+ var BROWSER_MAX_TIMEOUT_MINUTES = 360;
412
+ var BROWSER_REGIONS = ["us-west", "us-east", "eu-central", "ap-southeast"];
413
+ var BROWSER_OS = ["windows", "mac", "linux", "mobile", "tablet"];
414
+ var BrowserOptionsSchema = z4.object({
415
+ allowed_domains: z4.array(z4.string().min(1)).min(1),
416
+ timeout_minutes: z4.number().int().min(1).max(BROWSER_MAX_TIMEOUT_MINUTES).default(15),
417
+ region: z4.enum(BROWSER_REGIONS).default("us-west"),
418
+ keep_alive: z4.boolean().default(false),
419
+ viewport: z4.object({ width: z4.number().int().positive(), height: z4.number().int().positive() }).optional(),
420
+ os: z4.enum(BROWSER_OS).optional(),
421
+ block_ads: z4.boolean().default(false),
422
+ solve_captchas: z4.boolean().default(true),
423
+ stealth: z4.boolean().default(false),
424
+ allow_writes: z4.boolean().default(false),
425
+ allow_extract: z4.boolean().default(false),
426
+ context_name: z4.string().min(1).max(64).optional(),
427
+ persist_context: z4.boolean().default(false),
428
+ human_login: z4.boolean().default(false),
429
+ proxy: z4.boolean().default(false)
430
+ }).refine((options) => !(options.proxy && options.allowed_domains.includes("*")), {
431
+ error: "a proxied browser needs a bounded allow-list, not *",
432
+ path: ["proxy"]
433
+ });
434
+ var BrowserSessionStatusSchema = z4.enum(["creating", "active", "closed", "error"]);
435
+ var BrowserSessionSchema = z4.object({
436
+ id: idOf("brw"),
437
+ object: z4.literal("browser_session"),
438
+ computer_id: idOf("cmp").nullable(),
439
+ /** The agent session that opened it, if an agent did; a REST caller's browser carries `null`. */
440
+ session_id: idOf("ses").nullable(),
441
+ status: BrowserSessionStatusSchema,
442
+ allowed_domains: z4.array(z4.string()),
443
+ region: z4.enum(BROWSER_REGIONS),
444
+ context_id: idOf("bct").nullable(),
445
+ context_backed: z4.boolean(),
446
+ timeout_at: Timestamp,
447
+ opened_at: Timestamp,
448
+ closed_at: Timestamp.nullable(),
449
+ created_at: Timestamp
450
+ });
451
+ var BrowserLiveViewSchema = z4.object({
452
+ object: z4.literal("browser_live_view"),
453
+ url: z4.url(),
454
+ expires_at: Timestamp
155
455
  });
156
- var BudgetSchema = z3.object({
456
+ var BrowserContextSchema = z4.object({
457
+ id: idOf("bct"),
458
+ object: z4.literal("browser_context"),
459
+ identity_id: idOf("idn"),
460
+ name: z4.string(),
461
+ service: z4.string().nullable(),
462
+ created_at: Timestamp,
463
+ last_used_at: Timestamp.nullable()
464
+ });
465
+ var BrowserGranteeTypeSchema = z4.enum(["agent", "role"]);
466
+ var BrowserGrantSchema = z4.object({
467
+ id: idOf("bgr"),
468
+ object: z4.literal("browser_grant"),
469
+ context_id: idOf("bct"),
470
+ grantee_type: BrowserGranteeTypeSchema,
471
+ grantee_id: z4.union([idOf("agt"), RoleSchema]),
472
+ created_at: Timestamp
473
+ });
474
+ var SaveBrowserContextSchema = z4.object({
475
+ name: z4.string().min(1).max(64),
476
+ identity_id: idOf("idn"),
477
+ service: z4.string().min(1).optional()
478
+ });
479
+ var CreateBrowserGrantSchema = z4.object({
480
+ identity_id: idOf("idn"),
481
+ grantee_type: BrowserGranteeTypeSchema,
482
+ grantee_id: z4.union([idOf("agt"), RoleSchema])
483
+ });
484
+ var Selector = z4.string().min(1);
485
+ var Instruction = z4.string().min(1).max(4096);
486
+ var BrowserActionRequestSchema = z4.discriminatedUnion("action", [
487
+ z4.object({ action: z4.literal("goto"), url: z4.string().url() }),
488
+ z4.object({ action: z4.literal("click"), selector: Selector }),
489
+ z4.object({ action: z4.literal("type"), selector: Selector, text: z4.string() }),
490
+ z4.object({
491
+ action: z4.literal("extract"),
492
+ instruction: Instruction.optional(),
493
+ selector: Selector.optional(),
494
+ schema: z4.record(z4.string(), z4.unknown()).optional()
495
+ }),
496
+ z4.object({
497
+ action: z4.literal("act"),
498
+ instruction: Instruction,
499
+ variables: z4.record(z4.string(), z4.string()).optional()
500
+ }),
501
+ z4.object({ action: z4.literal("observe"), instruction: Instruction }),
502
+ z4.object({
503
+ action: z4.literal("links"),
504
+ contains: z4.string().optional(),
505
+ limit: z4.number().int().min(1).max(200).default(50)
506
+ }),
507
+ z4.object({ action: z4.literal("screenshot") })
508
+ ]);
509
+ var BROWSER_ACTIONS = BrowserActionRequestSchema.options.map(
510
+ (option) => option.shape.action.value
511
+ );
512
+ var BrowserActionResultSchema = z4.object({
513
+ object: z4.literal("browser_action"),
514
+ action: z4.enum(BROWSER_ACTIONS),
515
+ url: z4.string(),
516
+ text: z4.string().nullable(),
517
+ data: z4.unknown().nullable(),
518
+ links: z4.array(z4.object({ href: z4.string(), text: z4.string() })).nullable(),
519
+ elements: z4.array(z4.object({ selector: z4.string(), description: z4.string() })).nullable(),
520
+ file_id: idOf("fil").nullable(),
521
+ performed: z4.boolean()
522
+ });
523
+ var BrowserLoginSchema = z4.object({
524
+ service: z4.string().min(1),
525
+ url: z4.string().url(),
526
+ identity_id: idOf("idn")
527
+ });
528
+ var BrowserSignupSchema = BrowserLoginSchema.extend({ email: z4.string().email() });
529
+ var BrowserCredentialSchema = z4.object({
530
+ identity_id: idOf("idn"),
531
+ service: z4.string().min(1),
532
+ email: z4.string().email(),
533
+ password: z4.string().min(1),
534
+ username: z4.string().min(1).optional()
535
+ });
536
+ var LiveViewSchema = z4.object({ url: z4.string().url(), expires_at: Timestamp });
537
+
538
+ // ../core/src/schema/agent.ts
539
+ var ToolPermissionSchema = z5.enum(["allow", "ask", "deny"]);
540
+ var ToolConfigSchema = z5.object({
541
+ enabled: z5.boolean(),
542
+ permission: ToolPermissionSchema,
543
+ config: z5.record(z5.string(), z5.unknown()).optional()
544
+ });
545
+ var ToolsetSchema = z5.object({
546
+ default_config: z5.object({ permission: ToolPermissionSchema }),
547
+ configs: z5.record(z5.string(), ToolConfigSchema)
548
+ }).superRefine((tools, ctx) => {
549
+ const config = tools.configs["browser"]?.config;
550
+ if (config === void 0) return;
551
+ for (const issue of BrowserOptionsSchema.safeParse(config).error?.issues ?? []) {
552
+ ctx.addIssue({ code: "custom", message: issue.message, path: ["configs", "browser", "config", ...issue.path] });
553
+ }
554
+ });
555
+ var BudgetSchema = z5.object({
157
556
  cap_micro_usd: MicroUsdField.nonnegative(),
158
557
  max_task_micro_usd: MicroUsdField.nonnegative(),
159
- period: z3.enum(["day", "week", "month"])
558
+ period: z5.enum(["day", "week", "month"])
160
559
  });
161
- var SkillRefSchema = z3.string().regex(/^[a-z0-9][a-z0-9-]*(@\d+)?$/, {
162
- error: "expected `slug` or `slug@N`"
560
+ var SkillRefSchema = z5.string().regex(/^(naive\/)?[a-z0-9][a-z0-9-]*(@\d+)?$/, {
561
+ error: "expected `slug`, `slug@N`, `naive/slug` or `naive/slug@N`"
163
562
  });
164
- var McpServerSchema = z3.object({
165
- name: z3.string(),
166
- url: z3.url(),
167
- headers: z3.record(z3.string(), z3.string()).optional()
563
+ var McpServerSchema = z5.object({
564
+ name: z5.string(),
565
+ url: z5.url(),
566
+ headers: z5.record(z5.string(), z5.string()).optional()
168
567
  });
169
- var RosterEntrySchema = z3.union([
568
+ var RosterEntrySchema = z5.union([
170
569
  idOf("agt").transform((id) => ({ type: "agent", id })),
171
- z3.object({
172
- type: z3.literal("agent"),
570
+ z5.object({
571
+ type: z5.literal("agent"),
173
572
  id: idOf("agt"),
174
- version: z3.number().int().positive().optional()
573
+ version: z5.number().int().positive().optional()
175
574
  }),
176
- z3.object({ type: z3.literal("self") }),
177
- z3.object({ type: z3.literal("advisor"), model: z3.string().min(1) })
575
+ z5.object({ type: z5.literal("self") }),
576
+ z5.object({ type: z5.literal("advisor"), model: z5.string().min(1) })
178
577
  ]);
179
578
  var SINGLETON_ENTRIES = ["self", "advisor"];
180
- var MultiagentSchema = z3.object({
181
- type: z3.literal("coordinator"),
182
- agents: z3.array(RosterEntrySchema).min(1).max(20).refine(
579
+ var MultiagentSchema = z5.object({
580
+ type: z5.literal("coordinator"),
581
+ agents: z5.array(RosterEntrySchema).min(1).max(20).refine(
183
582
  (roster) => SINGLETON_ENTRIES.every((t) => roster.filter((e) => e.type === t).length <= 1),
184
583
  { error: "a roster carries at most one `self` and at most one `advisor` entry" }
185
584
  ),
186
- board: z3.boolean().optional()
585
+ board: z5.boolean().optional()
187
586
  });
188
- var MultiagentField = z3.union([z3.boolean(), MultiagentSchema, z3.null()]);
587
+ var MultiagentField = z5.union([z5.boolean(), MultiagentSchema, z5.null()]);
588
+ function normaliseMultiagent(value) {
589
+ if (value === true) return { type: "coordinator", agents: [], board: false };
590
+ if (value === false || value === null) return null;
591
+ return value;
592
+ }
189
593
  var agentConfigShape = {
190
- model: z3.string(),
594
+ model: z5.string(),
191
595
  window: WindowSchema,
192
- system: z3.string(),
596
+ system: z5.string(),
193
597
  tools: ToolsetSchema,
194
- mcp_servers: z3.array(McpServerSchema),
195
- skills: z3.array(SkillRefSchema),
598
+ mcp_servers: z5.array(McpServerSchema),
599
+ skills: z5.array(SkillRefSchema),
196
600
  multiagent: MultiagentField,
197
601
  budget: BudgetSchema,
198
602
  output_schema: JsonSchemaDocument.nullable(),
199
- structured_output_required: z3.boolean(),
200
- description: z3.string().nullable(),
603
+ structured_output_required: z5.boolean(),
604
+ description: z5.string().nullable(),
201
605
  metadata: Metadata
202
606
  };
203
- var AgentVersionSchema = z3.object({
204
- version: z3.number().int().positive(),
607
+ var AgentVersionSchema = z5.object({
608
+ version: z5.number().int().positive(),
205
609
  created_at: Timestamp,
206
610
  created_by: PrincipalSchema,
207
611
  ...agentConfigShape
208
612
  });
209
- var AgentSchema = z3.object({
613
+ var AgentSchema = z5.object({
210
614
  id: idOf("agt"),
211
- object: z3.literal("agent"),
212
- name: z3.string(),
615
+ object: z5.literal("agent"),
616
+ name: z5.string(),
213
617
  /** The agent loop this agent runs (§19). Chosen at create; the catalog lives in `harness.ts`. */
214
618
  harness: HarnessIdSchema,
215
- current_version: z3.number().int().positive(),
619
+ current_version: z5.number().int().positive(),
216
620
  created_at: Timestamp,
217
621
  ...agentConfigShape
218
622
  });
219
623
 
220
624
  // ../core/src/schema/session.ts
221
- import { z as z4 } from "zod";
222
- var SessionStatusSchema = z4.enum([
625
+ import { z as z6 } from "zod";
626
+ var SessionStatusSchema = z6.enum([
223
627
  "queued",
224
628
  "running",
225
629
  "idle",
@@ -227,7 +631,7 @@ var SessionStatusSchema = z4.enum([
227
631
  "failed",
228
632
  "cancelled"
229
633
  ]);
230
- var StopReasonSchema = z4.enum([
634
+ var StopReasonSchema = z6.enum([
231
635
  "end_turn",
232
636
  "awaiting_input",
233
637
  "awaiting_approval",
@@ -253,61 +657,61 @@ var StopReasonSchema = z4.enum([
253
657
  */
254
658
  "awaiting_answer"
255
659
  ]);
256
- var ThreadRoleSchema = z4.enum(["coordinator", "member"]);
257
- var MessageSchema = z4.object({
258
- role: z4.enum(["system", "user", "assistant", "tool"]),
259
- content: z4.string(),
260
- tool_call_id: z4.string().optional()
660
+ var ThreadRoleSchema = z6.enum(["coordinator", "member"]);
661
+ var MessageSchema = z6.object({
662
+ role: z6.enum(["system", "user", "assistant", "tool"]),
663
+ content: z6.string(),
664
+ tool_call_id: z6.string().optional()
261
665
  });
262
- var ToolResultSchema = z4.object({
263
- output: z4.unknown(),
264
- is_error: z4.boolean().optional(),
265
- content: z4.string().optional()
666
+ var ToolResultSchema = z6.object({
667
+ output: z6.unknown(),
668
+ is_error: z6.boolean().optional(),
669
+ content: z6.string().optional()
266
670
  });
267
671
  var QuestionFieldBase = {
268
- key: z4.string().min(1).max(64),
269
- label: z4.string().min(1).max(200),
270
- help: z4.string().max(500).optional()
672
+ key: z6.string().min(1).max(64),
673
+ label: z6.string().min(1).max(200),
674
+ help: z6.string().max(500).optional()
271
675
  };
272
- var QuestionFieldSchema = z4.discriminatedUnion("type", [
273
- z4.object({
676
+ var QuestionFieldSchema = z6.discriminatedUnion("type", [
677
+ z6.object({
274
678
  ...QuestionFieldBase,
275
- type: z4.literal("text"),
276
- placeholder: z4.string().max(200).optional()
679
+ type: z6.literal("text"),
680
+ placeholder: z6.string().max(200).optional()
277
681
  }),
278
- z4.object({
682
+ z6.object({
279
683
  ...QuestionFieldBase,
280
- type: z4.literal("choice"),
684
+ type: z6.literal("choice"),
281
685
  /**
282
686
  * Plain strings: the option is both the value and the label, because the answer is read back by
283
687
  * a model, which wants the words and not an id. Fewer than two is not a choice, and more than
284
688
  * twelve is a list — which belongs in the prompt.
285
689
  */
286
- options: z4.array(z4.string().min(1).max(200)).min(2).max(12),
287
- multiple: z4.boolean().default(false),
690
+ options: z6.array(z6.string().min(1).max(200)).min(2).max(12),
691
+ multiple: z6.boolean().default(false),
288
692
  /**
289
693
  * The free-text escape, and it defaults to **true** on purpose: the agent wrote the options and
290
694
  * the agent is the one that does not know the answer, so an operator must always be able to say
291
695
  * something it did not think of. A question that truly admits only its list opts out explicitly.
292
696
  */
293
- other: z4.boolean().default(true)
697
+ other: z6.boolean().default(true)
294
698
  })
295
699
  ]);
296
- var QuestionSchema = z4.object({
297
- prompt: z4.string().min(1).max(1e3),
298
- fields: z4.array(QuestionFieldSchema).min(1).max(3)
700
+ var QuestionSchema = z6.object({
701
+ prompt: z6.string().min(1).max(1e3),
702
+ fields: z6.array(QuestionFieldSchema).min(1).max(3)
299
703
  });
300
- var AnswersSchema = z4.record(
301
- z4.string().min(1).max(64),
302
- z4.union([z4.string().max(2e3), z4.array(z4.string().max(2e3)).min(1).max(12)])
704
+ var AnswersSchema = z6.record(
705
+ z6.string().min(1).max(64),
706
+ z6.union([z6.string().max(2e3), z6.array(z6.string().max(2e3)).min(1).max(12)])
303
707
  ).refine((answers) => Object.keys(answers).length <= 3, {
304
708
  message: "a question has at most 3 fields, so an answer has at most 3 keys"
305
709
  });
306
- var PendingActionSchema = z4.object({
307
- kind: z4.enum(["tool", "question"]).default("tool"),
308
- tool_call_id: z4.string(),
309
- name: z4.string(),
310
- args: z4.record(z4.string(), z4.unknown()),
710
+ var PendingActionSchema = z6.object({
711
+ kind: z6.enum(["tool", "question"]).default("tool"),
712
+ tool_call_id: z6.string(),
713
+ name: z6.string(),
714
+ args: z6.record(z6.string(), z6.unknown()),
311
715
  /**
312
716
  * Present iff `kind` is `"question"`, and it is the parse of `args` rather than a second source
313
717
  * of truth: `args` is what the model called and therefore what replays byte-identically, while
@@ -316,11 +720,11 @@ var PendingActionSchema = z4.object({
316
720
  */
317
721
  question: QuestionSchema.optional()
318
722
  });
319
- var SessionSchema = z4.object({
723
+ var SessionSchema = z6.object({
320
724
  id: idOf("ses"),
321
- object: z4.literal("session"),
725
+ object: z6.literal("session"),
322
726
  agent_id: idOf("agt"),
323
- agent_version: z4.number().int().positive(),
727
+ agent_version: z6.number().int().positive(),
324
728
  deployment_id: idOf("dep").nullable(),
325
729
  /**
326
730
  * The persona this session acts as (`canonical-spec §22`). Chosen per task from the personas the
@@ -349,38 +753,39 @@ var SessionSchema = z4.object({
349
753
  budget_micro_usd: MicroUsdField.nonnegative(),
350
754
  consumed_micro_usd: MicroUsdField.nonnegative(),
351
755
  token_usage: TokenUsageSchema,
352
- pending_actions: z4.array(PendingActionSchema),
756
+ pending_actions: z6.array(PendingActionSchema),
353
757
  output_schema: JsonSchemaDocument.nullable(),
354
- structured_output: z4.record(z4.string(), z4.unknown()).nullable(),
355
- last_seq: z4.number().int().nonnegative(),
758
+ structured_output: z6.record(z6.string(), z6.unknown()).nullable(),
759
+ last_seq: z6.number().int().nonnegative(),
356
760
  metadata: Metadata,
357
761
  started_at: Timestamp.nullable(),
358
762
  ended_at: Timestamp.nullable(),
359
763
  created_at: Timestamp
360
764
  });
361
- var SendMessageSchema = z4.object({
362
- message: z4.string(),
363
- interrupt: z4.boolean().optional(),
364
- idempotency_key: z4.string().optional()
765
+ var SendMessageSchema = z6.object({
766
+ message: z6.string(),
767
+ interrupt: z6.boolean().optional(),
768
+ idempotency_key: z6.string().optional()
365
769
  });
366
- var SendAcceptedSchema = z4.object({
367
- session_id: z4.string(),
770
+ var SendAcceptedSchema = z6.object({
771
+ session_id: z6.string(),
368
772
  status: SessionStatusSchema,
369
- accepted_seq: z4.number().int().nonnegative()
773
+ accepted_seq: z6.number().int().nonnegative()
370
774
  });
371
- var ToolConfirmationSchema = z4.object({
372
- tool_call_id: z4.string(),
373
- decision: z4.enum(["allow", "deny"]),
374
- reason: z4.string().optional()
775
+ var ToolConfirmationSchema = z6.object({
776
+ tool_call_id: z6.string(),
777
+ decision: z6.enum(["allow", "deny"]),
778
+ reason: z6.string().optional(),
779
+ scope: z6.enum(["call", "session"]).default("call")
375
780
  });
376
- var SessionAnswerSchema = z4.object({
377
- tool_call_id: z4.string(),
378
- answers: z4.record(z4.string(), z4.union([z4.string(), z4.array(z4.string())]))
781
+ var SessionAnswerSchema = z6.object({
782
+ tool_call_id: z6.string(),
783
+ answers: z6.record(z6.string(), z6.union([z6.string(), z6.array(z6.string())]))
379
784
  });
380
785
 
381
786
  // ../core/src/schema/event.ts
382
- import { z as z5 } from "zod";
383
- var EventTypeSchema = z5.enum([
787
+ import { z as z7 } from "zod";
788
+ var EventTypeSchema = z7.enum([
384
789
  "message.delta",
385
790
  "message.completed",
386
791
  "tool.started",
@@ -400,57 +805,81 @@ var EventTypeSchema = z5.enum([
400
805
  "thread.created",
401
806
  "thread.running",
402
807
  "thread.idle",
403
- "thread.terminated"
808
+ "thread.terminated",
809
+ // core-gaps: contracts (`canonical-spec §32.8`, §33.5, §36.3, §37.3, §38.3)
810
+ "browser.session.opened",
811
+ "browser.session.closed",
812
+ "browser.context.saved",
813
+ "browser.context.granted",
814
+ "browser.context.revoked",
815
+ "media.job.queued",
816
+ "media.job.completed",
817
+ "media.job.failed",
818
+ "file.imported",
819
+ "app.db.migrated",
820
+ "app.storage.bucket.created",
821
+ "app.storage.bucket.deleted",
822
+ // identity money (`canonical-spec §44.3`, §45.3). Every one of these is driven over REST, which
823
+ // has no session stream, so the org's webhook subscriptions are the only push a customer gets.
824
+ "wallet.created",
825
+ "wallet.policy.updated",
826
+ "wallet.transaction.confirmed",
827
+ "wallet.swept",
828
+ "card.issued",
829
+ "card.failed",
830
+ "card.cancelled",
831
+ "card.refunded",
832
+ "card.credentials_revealed"
404
833
  ]);
405
- var EventSchema = z5.object({
834
+ var EventSchema = z7.object({
406
835
  id: idOf("evt"),
407
- seq: z5.number().int().positive(),
836
+ seq: z7.number().int().positive(),
408
837
  type: EventTypeSchema,
409
838
  session_id: idOf("ses"),
410
- data: z5.record(z5.string(), z5.unknown()),
839
+ data: z7.record(z7.string(), z7.unknown()),
411
840
  created_at: Timestamp
412
841
  });
413
- var ThreadEventDataSchema = z5.looseObject({ thread_id: idOf("ses") });
414
- var SessionUsageDataSchema = z5.object({
842
+ var ThreadEventDataSchema = z7.looseObject({ thread_id: idOf("ses") });
843
+ var SessionUsageDataSchema = z7.object({
415
844
  token_usage: TokenUsageSchema,
416
845
  consumed_micro_usd: MicroUsdField.nonnegative(),
417
- active_seconds: z5.number().nonnegative(),
418
- tool_calls: z5.number().int().nonnegative()
846
+ active_seconds: z7.number().nonnegative(),
847
+ tool_calls: z7.number().int().nonnegative()
419
848
  });
420
849
 
421
850
  // ../core/src/schema/board.ts
422
- import { z as z6 } from "zod";
851
+ import { z as z8 } from "zod";
423
852
  var BOARD_STATUSES = ["todo", "doing", "blocked", "done"];
424
- var BoardStatusSchema = z6.enum(BOARD_STATUSES);
425
- var BoardCountsSchema = z6.object({
426
- todo: z6.number().int().nonnegative(),
427
- doing: z6.number().int().nonnegative(),
428
- blocked: z6.number().int().nonnegative(),
429
- done: z6.number().int().nonnegative()
430
- });
431
- var BoardSchema = z6.object({
853
+ var BoardStatusSchema = z8.enum(BOARD_STATUSES);
854
+ var BoardCountsSchema = z8.object({
855
+ todo: z8.number().int().nonnegative(),
856
+ doing: z8.number().int().nonnegative(),
857
+ blocked: z8.number().int().nonnegative(),
858
+ done: z8.number().int().nonnegative()
859
+ });
860
+ var BoardSchema = z8.object({
432
861
  id: idOf("brd"),
433
- object: z6.literal("board"),
862
+ object: z8.literal("board"),
434
863
  agent_id: idOf("agt"),
435
864
  cards: BoardCountsSchema,
436
865
  created_at: Timestamp
437
866
  });
438
- var BoardCardSchema = z6.object({
867
+ var BoardCardSchema = z8.object({
439
868
  id: idOf("crd"),
440
- object: z6.literal("board_card"),
869
+ object: z8.literal("board_card"),
441
870
  board_id: idOf("brd"),
442
- title: z6.string().min(1),
443
- body: z6.string(),
871
+ title: z8.string().min(1),
872
+ body: z8.string(),
444
873
  status: BoardStatusSchema,
445
- assignee: z6.string().nullable(),
874
+ assignee: z8.string().nullable(),
446
875
  /** The cards this one waits on. A `blocked` card with an empty list is stuck on the world. */
447
- blocked_by: z6.array(idOf("crd")),
876
+ blocked_by: z8.array(idOf("crd")),
448
877
  created_at: Timestamp,
449
878
  updated_at: Timestamp
450
879
  });
451
- var BoardCommentSchema = z6.object({
880
+ var BoardCommentSchema = z8.object({
452
881
  id: idOf("bcm"),
453
- object: z6.literal("board_comment"),
882
+ object: z8.literal("board_comment"),
454
883
  card_id: idOf("crd"),
455
884
  /**
456
885
  * Who wrote it, as an id the server derived — never a name the caller supplied. A member's
@@ -458,105 +887,221 @@ var BoardCommentSchema = z6.object({
458
887
  * `key_` principal. The prefix is what lets a reader tell an agent's comment from a person's,
459
888
  * which is the distinction a free-text author field could not make and could be used to forge.
460
889
  */
461
- author: z6.string(),
462
- body: z6.string(),
890
+ author: z8.string(),
891
+ body: z8.string(),
463
892
  created_at: Timestamp
464
893
  });
465
894
 
466
895
  // ../core/src/schema/identity.ts
467
- import { z as z7 } from "zod";
896
+ import { z as z9 } from "zod";
468
897
  var IDENTITY_NAME_MAX = 128;
469
898
  var IDENTITY_DESCRIPTION_MAX = 1024;
470
- var IdentitySchema = z7.object({
899
+ var IdentitySchema = z9.object({
471
900
  id: idOf("idn"),
472
- object: z7.literal("identity"),
901
+ object: z9.literal("identity"),
473
902
  /** Human-facing persona name. Surfaced to the model so it acts in character. */
474
- name: z7.string().min(1).max(IDENTITY_NAME_MAX),
903
+ name: z9.string().min(1).max(IDENTITY_NAME_MAX),
475
904
  /** What the persona is for. The model reads it to choose tone, scope and endpoint. */
476
- description: z7.string().max(IDENTITY_DESCRIPTION_MAX).nullable(),
905
+ description: z9.string().max(IDENTITY_DESCRIPTION_MAX).nullable(),
477
906
  /** Inbox addresses (`localpart@domain`) this identity owns. */
478
- emails: z7.array(z7.string()),
907
+ emails: z9.array(z9.string()),
479
908
  /** Provisioned numbers in E.164. */
480
- phones: z7.array(z7.string()),
909
+ phones: z9.array(z9.string()),
481
910
  /** Verified web domains reachable through this identity's inboxes. */
482
- domains: z7.array(z7.string()),
911
+ domains: z9.array(z9.string()),
483
912
  /** `conn_` ids of authorized third-party connections. */
484
- connections: z7.array(z7.string()),
913
+ connections: z9.array(z9.string()),
485
914
  metadata: Metadata,
486
915
  created_at: Timestamp,
487
916
  updated_at: Timestamp
488
917
  });
489
918
 
490
919
  // ../core/src/schema/resource.ts
491
- import { z as z8 } from "zod";
492
- var ComputerStatusSchema = z8.enum(["creating", "running", "paused", "failed", "destroyed"]);
493
- var VolumeSchema = z8.object({
920
+ import { z as z11 } from "zod";
921
+
922
+ // ../core/src/schema/files-library.ts
923
+ import { z as z10 } from "zod";
924
+ var FILE_KINDS = ["image", "video", "audio", "document", "other"];
925
+ var FileKindSchema = z10.enum(FILE_KINDS);
926
+ var FILE_SOURCE_TYPES = [
927
+ "upload",
928
+ "url_import",
929
+ "image_generation",
930
+ "video_generation",
931
+ "video_clipping",
932
+ "screenshot",
933
+ "speech_generation"
934
+ ];
935
+ var FileSourceTypeSchema = z10.enum(FILE_SOURCE_TYPES);
936
+ var FileSourceSchema = z10.object({
937
+ type: FileSourceTypeSchema,
938
+ job_id: z10.union([idOf("med"), idOf("clj")]).nullable(),
939
+ url: z10.string().url().nullable()
940
+ });
941
+ var FileTagsSchema = z10.array(z10.string().min(1).max(64)).max(32);
942
+ var FileLibraryFieldsSchema = z10.object({
943
+ title: z10.string().max(256).nullable().default(null),
944
+ description: z10.string().max(4096).nullable().default(null),
945
+ tags: FileTagsSchema.default([]),
946
+ kind: FileKindSchema.default("other"),
947
+ source: FileSourceSchema.nullable().default(null),
948
+ thumbnail_file_id: idOf("fil").nullable().default(null),
949
+ width: z10.number().int().positive().nullable().default(null),
950
+ height: z10.number().int().positive().nullable().default(null),
951
+ duration_seconds: z10.number().nonnegative().nullable().default(null)
952
+ });
953
+ var UpdateFileSchema = z10.object({
954
+ title: z10.string().max(256).nullable().optional(),
955
+ description: z10.string().max(4096).nullable().optional(),
956
+ tags: FileTagsSchema.optional()
957
+ });
958
+ var ImportFileSchema = z10.object({
959
+ url: z10.string().url().startsWith("http"),
960
+ title: z10.string().max(256).optional(),
961
+ description: z10.string().max(4096).optional(),
962
+ tags: FileTagsSchema.optional()
963
+ });
964
+
965
+ // ../core/src/schema/resource.ts
966
+ var ComputerStatusSchema = z11.enum(["creating", "running", "paused", "failed", "destroyed"]);
967
+ var VolumeSchema = z11.object({
494
968
  id: idOf("vol"),
495
- size_gb: z8.number().int().positive(),
496
- mount_path: z8.string()
969
+ size_gb: z11.number().int().positive(),
970
+ mount_path: z11.string()
497
971
  });
498
- var ComputerSchema = z8.object({
972
+ var ComputerSchema = z11.object({
499
973
  id: idOf("cmp"),
500
- object: z8.literal("computer"),
501
- name: z8.string(),
502
- vcpu: z8.number().int().positive(),
503
- memory_mb: z8.number().int().positive(),
504
- disk_gb: z8.number().int().positive(),
974
+ object: z11.literal("computer"),
975
+ name: z11.string(),
976
+ vcpu: z11.number().int().positive(),
977
+ memory_mb: z11.number().int().positive(),
978
+ disk_gb: z11.number().int().positive(),
505
979
  status: ComputerStatusSchema,
506
- browser: z8.object({ allowed_domains: z8.array(z8.string()) }).nullable(),
980
+ // core-gaps: U2-browser-api — the whole option object (§32.2); `{ allowed_domains }` still parses.
981
+ browser: BrowserOptionsSchema.nullable(),
507
982
  volume: VolumeSchema.nullable(),
508
983
  snapshot_id: idOf("snp").nullable(),
509
984
  created_at: Timestamp
510
985
  });
511
- var SnapshotSchema = z8.object({
986
+ var SnapshotSchema = z11.object({
512
987
  snapshot_id: idOf("snp"),
513
988
  computer_id: idOf("cmp"),
514
989
  created_at: Timestamp
515
990
  });
516
- var SkillSchema = z8.object({
991
+ var ComputerProbeSchema = z11.object({
992
+ sampled_at: Timestamp,
993
+ uptime_seconds: z11.number().int().nonnegative(),
994
+ processes: z11.number().int().nonnegative(),
995
+ load_1m: z11.number().nonnegative(),
996
+ memory_used_mb: z11.number().int().nonnegative(),
997
+ memory_total_mb: z11.number().int().positive(),
998
+ disk_used_gb: z11.number().nonnegative(),
999
+ disk_total_gb: z11.number().positive()
1000
+ });
1001
+ var ComputerInspectSchema = z11.object({
1002
+ object: z11.literal("computer_inspect"),
1003
+ id: idOf("cmp"),
1004
+ status: ComputerStatusSchema,
1005
+ last_active_at: Timestamp.nullable(),
1006
+ /** Where the provider's file API is rooted (§41.1); `null` when it does not say. */
1007
+ home: z11.string().min(1).nullable(),
1008
+ probe: ComputerProbeSchema.nullable()
1009
+ });
1010
+ var COMMAND_OUTPUT_CAP = 65536;
1011
+ var ComputerCommandSchema = z11.object({
1012
+ id: idOf("cmd"),
1013
+ object: z11.literal("computer_command"),
1014
+ computer_id: idOf("cmp"),
1015
+ command: z11.string(),
1016
+ exit_code: z11.number().int().nullable(),
1017
+ timed_out: z11.boolean(),
1018
+ duration_ms: z11.number().int().nonnegative(),
1019
+ stdout: z11.string().max(COMMAND_OUTPUT_CAP),
1020
+ stderr: z11.string().max(COMMAND_OUTPUT_CAP),
1021
+ truncated: z11.boolean(),
1022
+ actor: PrincipalSchema,
1023
+ created_at: Timestamp
1024
+ });
1025
+ var ExecStreamFrameSchema = z11.union([
1026
+ z11.object({ stdout: z11.string() }),
1027
+ z11.object({ stderr: z11.string() }),
1028
+ z11.object({
1029
+ exit: z11.object({
1030
+ exit_code: z11.number().int().nullable(),
1031
+ timed_out: z11.boolean(),
1032
+ duration_ms: z11.number().int().nonnegative(),
1033
+ command_id: idOf("cmd")
1034
+ })
1035
+ })
1036
+ ]);
1037
+ var FileEntryTypeSchema = z11.enum(["file", "directory", "symlink", "other"]);
1038
+ var FileEntrySchema = z11.object({
1039
+ name: z11.string().min(1),
1040
+ path: z11.string().min(1),
1041
+ type: FileEntryTypeSchema,
1042
+ size_bytes: z11.number().int().nonnegative(),
1043
+ /** POSIX `st_mode`. */
1044
+ mode: z11.number().int().nonnegative(),
1045
+ modified_at: Timestamp.nullable()
1046
+ });
1047
+ var ComputerUpdateSchema = z11.strictObject({ name: z11.string().min(1).max(200) });
1048
+ var SkillSchema = z11.object({
517
1049
  id: idOf("skl"),
518
- object: z8.literal("skill"),
519
- name: z8.string(),
520
- description: z8.string().nullable(),
521
- latest_version: z8.number().int().positive(),
1050
+ object: z11.literal("skill"),
1051
+ name: z11.string(),
1052
+ description: z11.string().nullable(),
1053
+ latest_version: z11.number().int().positive(),
522
1054
  created_at: Timestamp
523
1055
  });
524
- var ResolvedSkillRefSchema = z8.object({
1056
+ var ResolvedSkillRefSchema = z11.object({
525
1057
  /** The reference exactly as the agent version wrote it: `slug` or `slug@N`. */
526
- ref: z8.string().min(1),
527
- slug: z8.string().min(1),
528
- version: z8.number().int().positive(),
529
- description: z8.string(),
530
- storage_key: z8.string().min(1)
531
- });
532
- var SkillVersionSchema = z8.object({
533
- version: z8.number().int().positive(),
534
- sha256: z8.string().regex(/^[0-9a-f]{64}$/),
535
- size_bytes: z8.number().int().nonnegative(),
1058
+ ref: z11.string().min(1),
1059
+ slug: z11.string().min(1),
1060
+ version: z11.number().int().positive(),
1061
+ description: z11.string(),
1062
+ storage_key: z11.string().min(1)
1063
+ });
1064
+ var SkillVersionSchema = z11.object({
1065
+ version: z11.number().int().positive(),
1066
+ sha256: z11.string().regex(/^[0-9a-f]{64}$/),
1067
+ size_bytes: z11.number().int().nonnegative(),
536
1068
  created_at: Timestamp
537
1069
  });
538
- var FileSchema = z8.object({
1070
+ var SkillCatalogEntrySchema = z11.object({
1071
+ object: z11.literal("skill_catalog_entry"),
1072
+ slug: z11.string().regex(/^[a-z0-9][a-z0-9-]*$/),
1073
+ version: z11.number().int().positive(),
1074
+ name: z11.string().min(1),
1075
+ description: z11.string(),
1076
+ tags: z11.array(z11.string().min(1)),
1077
+ content_hash: z11.string().regex(/^[0-9a-f]{64}$/),
1078
+ published_at: Timestamp
1079
+ });
1080
+ var SkillCatalogVersionSchema = SkillCatalogEntrySchema.extend({ content: z11.string() });
1081
+ var FileSchema = z11.object({
539
1082
  id: idOf("fil"),
540
- object: z8.literal("file"),
541
- name: z8.string(),
542
- content_type: z8.string(),
543
- size_bytes: z8.number().int().nonnegative(),
544
- scope: z8.enum(["session", "published"]),
1083
+ object: z11.literal("file"),
1084
+ name: z11.string(),
1085
+ content_type: z11.string(),
1086
+ size_bytes: z11.number().int().nonnegative(),
1087
+ scope: z11.enum(["session", "published"]),
545
1088
  session_id: idOf("ses").nullable(),
546
- sha256: z8.string().regex(/^[0-9a-f]{64}$/),
547
- created_at: Timestamp
1089
+ sha256: z11.string().regex(/^[0-9a-f]{64}$/),
1090
+ created_at: Timestamp,
1091
+ // The asset-library fields (`canonical-spec §36.1`), all nullable or defaulted.
1092
+ ...FileLibraryFieldsSchema.shape
548
1093
  });
549
- var ScheduleStatusSchema = z8.enum(["scheduled", "paused", "unscheduled"]);
550
- var DeploymentSchema = z8.object({
1094
+ var ScheduleStatusSchema = z11.enum(["scheduled", "paused", "unscheduled"]);
1095
+ var DeploymentSchema = z11.object({
551
1096
  id: idOf("dep"),
552
- object: z8.literal("deployment"),
1097
+ object: z11.literal("deployment"),
553
1098
  agent_id: idOf("agt"),
554
1099
  /** A pin. `null` tracks the agent's `current_version` on every fire (§12). */
555
- agent_version: z8.number().int().positive().nullable(),
556
- cron: z8.string(),
1100
+ agent_version: z11.number().int().positive().nullable(),
1101
+ cron: z11.string(),
557
1102
  /** IANA zone the `cron` is read in. "0 9 * * 1" means 09:00 *here*, across DST (ADR-0074). */
558
- timezone: z8.string(),
559
- input_template: z8.string(),
1103
+ timezone: z11.string(),
1104
+ input_template: z11.string(),
560
1105
  budget_micro_usd: MicroUsdField.nonnegative(),
561
1106
  window: WindowSchema,
562
1107
  /**
@@ -566,189 +1111,84 @@ var DeploymentSchema = z8.object({
566
1111
  * those endpoints, and a signed delivery over cleartext is not a delivery. Until the push was
567
1112
  * wired this field went nowhere, so nothing can be relying on an `http://` value (ADR-0161).
568
1113
  */
569
- on_idle: z8.url().startsWith("https://", { error: "a webhook URL must be https" }).nullable(),
1114
+ on_idle: z11.url().startsWith("https://", { error: "a webhook URL must be https" }).nullable(),
570
1115
  /**
571
1116
  * The persona every fire speaks as, or `null` to run as nobody (§22). Written as an `idn_` id
572
1117
  * **or** the persona's name, the way a session names one, and always echoed as the id: a fire at
573
1118
  * 3am must not be silenced by someone renaming the persona at noon.
574
1119
  */
575
1120
  identity: idOf("idn").nullable(),
576
- enabled: z8.boolean(),
1121
+ enabled: z11.boolean(),
577
1122
  /** Derived per deploy, never stored — the row cannot know whether a clock is watching it. */
578
1123
  schedule_status: ScheduleStatusSchema,
579
1124
  /** The next fire, or `null` when nothing will fire it (`schedule_status` says which). */
580
1125
  next_run_at: Timestamp.nullable(),
581
1126
  created_at: Timestamp
582
1127
  });
583
- var DeploymentRunSchema = z8.object({
1128
+ var DeploymentRunSchema = z11.object({
584
1129
  id: idOf("run"),
585
1130
  session_id: idOf("ses"),
586
1131
  status: SessionStatusSchema,
587
1132
  started_at: Timestamp.nullable()
588
1133
  });
589
1134
 
590
- // ../core/src/schema/org.ts
591
- import { z as z9 } from "zod";
592
- var OrganizationSchema = z9.object({
593
- id: idOf("org"),
594
- object: z9.literal("organization"),
595
- name: z9.string(),
596
- balance_micro_usd: MicroUsdField,
597
- created_at: Timestamp
598
- });
599
- var RoleSchema = z9.enum(["owner", "admin", "member"]);
600
- var MemberSchema = z9.object({
601
- id: z9.string(),
602
- object: z9.literal("member"),
603
- email: z9.email(),
604
- role: RoleSchema,
605
- invited_by: z9.string().nullable(),
606
- created_at: Timestamp
607
- });
608
- var SCOPES = [
609
- "agents:read",
610
- "agents:write",
611
- "sessions:read",
612
- "sessions:write",
613
- /**
614
- * THE MODEL DOOR AND NOTHING ELSE. `/v1/proxy/*` used to take `sessions:write`, which also opens
615
- * session create and cancel — so a credential handed to a customer's micro-VM, if it leaked, could
616
- * start sessions for the whole organization. This scope buys exactly one capability, so a sandbox
617
- * token can be minted with it alone.
618
- *
619
- * The proxy routes accept EITHER this or `sessions:write`: narrowing an already-published route
620
- * would break every key that reaches it today (§17).
621
- */
622
- "proxy:write",
623
- "computers:write",
624
- "files:read",
625
- "files:write",
626
- "billing:read",
627
- "billing:write",
628
- "webhooks:*",
629
- "audit:read",
630
- "admin"
631
- ];
632
- var ScopeSchema = z9.enum(SCOPES);
633
- var ApiKeySchema = z9.object({
634
- id: idOf("key"),
635
- object: z9.literal("api_key"),
636
- name: z9.string(),
637
- prefix: z9.string(),
638
- scopes: z9.array(ScopeSchema),
639
- created_by: PrincipalSchema,
640
- last_used_at: Timestamp.nullable(),
641
- created_at: Timestamp
642
- });
643
- var LedgerEntrySchema = z9.object({
644
- id: idOf("led"),
645
- type: z9.enum(["debit", "credit"]),
646
- amount_micro_usd: MicroUsdField,
647
- balance_after_micro_usd: MicroUsdField,
648
- actor: PrincipalSchema,
649
- session_id: idOf("ses").nullable(),
650
- agent_id: idOf("agt").nullable(),
651
- deployment_id: idOf("dep").nullable(),
652
- line_items: z9.array(z9.object({ tier: LineItemTierSchema, amount_micro_usd: MicroUsdField })),
653
- created_at: Timestamp
654
- });
655
- var TopupSchema = z9.object({
656
- id: z9.string(),
657
- object: z9.literal("topup"),
658
- amount_micro_usd: MicroUsdField.positive(),
659
- status: z9.enum(["pending", "requires_action", "succeeded", "failed"]),
660
- action_url: z9.url().nullable(),
661
- balance_after_micro_usd: MicroUsdField.nullable(),
662
- created_at: Timestamp
663
- });
664
- var WebhookEndpointSchema = z9.object({
665
- id: idOf("whk"),
666
- object: z9.literal("webhook_endpoint"),
667
- url: z9.url(),
668
- events: z9.array(z9.string()),
669
- enabled: z9.boolean(),
670
- created_at: Timestamp
671
- });
672
- var WebhookDeliverySchema = z9.object({
673
- id: idOf("whd"),
674
- event_id: idOf("evt"),
675
- event_type: z9.string(),
676
- status: z9.enum(["pending", "succeeded", "failed"]),
677
- attempts: z9.number().int().nonnegative(),
678
- response_status: z9.number().int().nullable(),
679
- response_snippet: z9.string().nullable(),
680
- delivered_at: Timestamp.nullable(),
681
- next_retry_at: Timestamp.nullable()
682
- });
683
- var AuditEntrySchema = z9.object({
684
- id: idOf("aud"),
685
- object: z9.literal("audit_entry"),
686
- actor: PrincipalSchema,
687
- action: AuditActionSchema,
688
- resource_type: z9.string(),
689
- resource_id: z9.string(),
690
- request_id: z9.string(),
691
- metadata: Metadata,
692
- created_at: Timestamp
693
- });
694
-
695
1135
  // ../core/src/schema/comms.ts
696
- import { z as z10 } from "zod";
697
- var DomainKindSchema = z10.enum(["system", "external", "purchased"]);
698
- var DomainStatusSchema = z10.enum(["pending_dns", "active", "failed"]);
699
- var DomainDnsStatusSchema = z10.enum(["pending_verification", "provisioned", "failed"]);
700
- var DomainInboundStatusSchema = z10.enum(["pending", "verified", "failed"]);
701
- var DomainAppConnectStatusSchema = z10.enum(["pending", "connected", "failed"]);
702
- var DnsRecordSchema = z10.object({
703
- type: z10.enum(["TXT", "CNAME", "MX"]),
704
- host: z10.string(),
705
- value: z10.string(),
706
- priority: z10.number().int().nullable(),
1136
+ import { z as z12 } from "zod";
1137
+ var DomainKindSchema = z12.enum(["system", "external", "purchased"]);
1138
+ var DomainStatusSchema = z12.enum(["pending_dns", "active", "failed"]);
1139
+ var DomainDnsStatusSchema = z12.enum(["pending_verification", "provisioned", "failed"]);
1140
+ var DomainInboundStatusSchema = z12.enum(["pending", "verified", "failed"]);
1141
+ var DomainAppConnectStatusSchema = z12.enum(["pending", "connected", "failed"]);
1142
+ var DnsRecordSchema = z12.object({
1143
+ type: z12.enum(["TXT", "CNAME", "MX"]),
1144
+ host: z12.string(),
1145
+ value: z12.string(),
1146
+ priority: z12.number().int().nullable(),
707
1147
  /** Vetta owns this record: `_dmarc`, DKIM, inbound MX. The agent may read it, never write it. */
708
- managed: z10.boolean()
1148
+ managed: z12.boolean()
709
1149
  });
710
- var DomainSchema = z10.object({
1150
+ var DomainSchema = z12.object({
711
1151
  id: idOf("dom"),
712
- object: z10.literal("domain"),
1152
+ object: z12.literal("domain"),
713
1153
  /** A domain belongs to the **organization**, not to one identity: two identities share one. */
714
- name: z10.string(),
1154
+ name: z12.string(),
715
1155
  kind: DomainKindSchema,
716
1156
  status: DomainStatusSchema,
717
1157
  dns_status: DomainDnsStatusSchema,
718
1158
  inbound_status: DomainInboundStatusSchema,
719
1159
  app_connect_status: DomainAppConnectStatusSchema,
720
- records: z10.array(DnsRecordSchema),
1160
+ records: z12.array(DnsRecordSchema),
721
1161
  last_verified_at: Timestamp.nullable(),
722
1162
  created_at: Timestamp
723
1163
  });
724
- var EmailInboxSchema = z10.object({
1164
+ var EmailInboxSchema = z12.object({
725
1165
  id: idOf("eml"),
726
- object: z10.literal("email_inbox"),
1166
+ object: z12.literal("email_inbox"),
727
1167
  identity_id: idOf("idn"),
728
1168
  domain_id: idOf("dom"),
729
- address: z10.string(),
730
- localpart: z10.string(),
1169
+ address: z12.string(),
1170
+ localpart: z12.string(),
731
1171
  /** Inbound routing keys off this: mail to the address wakes exactly this agent. */
732
1172
  owning_agent_id: idOf("agt"),
733
- status: z10.enum(["active", "disabled"]),
1173
+ status: z12.enum(["active", "disabled"]),
734
1174
  created_at: Timestamp
735
1175
  });
736
- var PhoneTierSchema = z10.enum(["sole_prop", "standard"]);
737
- var BrandStatusSchema = z10.enum(["none", "pending_verification", "verified", "rejected"]);
738
- var CampaignStatusSchema = z10.enum(["none", "pending", "approved", "rejected"]);
739
- var PhoneNumberSchema = z10.object({
1176
+ var PhoneTierSchema = z12.enum(["sole_prop", "standard"]);
1177
+ var BrandStatusSchema = z12.enum(["none", "pending_verification", "verified", "rejected"]);
1178
+ var CampaignStatusSchema = z12.enum(["none", "pending", "approved", "rejected"]);
1179
+ var PhoneNumberSchema = z12.object({
740
1180
  id: idOf("pho"),
741
- object: z10.literal("phone_number"),
1181
+ object: z12.literal("phone_number"),
742
1182
  identity_id: idOf("idn"),
743
- e164: z10.string(),
744
- country: z10.string(),
745
- capabilities: z10.object({
1183
+ e164: z12.string(),
1184
+ country: z12.string(),
1185
+ capabilities: z12.object({
746
1186
  /** Live the moment the number is bought — inbound never waits on carrier registration. */
747
- sms_inbound: z10.boolean(),
1187
+ sms_inbound: z12.boolean(),
748
1188
  /** True **iff** `campaign_status === "approved"`. Nothing else may set it. */
749
- sms_outbound: z10.boolean(),
1189
+ sms_outbound: z12.boolean(),
750
1190
  /** Voice is not a P2 capability; the field exists so its absence is explicit. */
751
- voice: z10.literal(false)
1191
+ voice: z12.literal(false)
752
1192
  }),
753
1193
  tier: PhoneTierSchema,
754
1194
  brand_status: BrandStatusSchema,
@@ -756,80 +1196,85 @@ var PhoneNumberSchema = z10.object({
756
1196
  provisioned_at: Timestamp.nullable(),
757
1197
  created_at: Timestamp
758
1198
  });
759
- var InboundMessageSchema = z10.object({
1199
+ var InboundMessageSchema = z12.object({
760
1200
  id: idOf("inb"),
761
- object: z10.literal("inbound_message"),
762
- channel: z10.enum(["email", "sms"]),
1201
+ object: z12.literal("inbound_message"),
1202
+ channel: z12.enum(["email", "sms"]),
763
1203
  identity_id: idOf("idn"),
764
1204
  /** The `eml_`/`pho_` endpoint it arrived at — the persona is decided by *where*, not by *who*. */
765
- endpoint_id: z10.string(),
766
- from: z10.string(),
767
- to: z10.string(),
768
- subject: z10.string().nullable(),
769
- text: z10.string(),
1205
+ endpoint_id: z12.string(),
1206
+ from: z12.string(),
1207
+ to: z12.string(),
1208
+ subject: z12.string().nullable(),
1209
+ text: z12.string(),
770
1210
  /** SPF/DKIM/DMARC for mail, carrier origin for SMS. Kept for the audit of why it was accepted. */
771
- auth: z10.record(z10.string(), z10.string()),
1211
+ auth: z12.record(z12.string(), z12.string()),
772
1212
  /** The session this message woke. Null until the wake seam lands (see ADR-0120). */
773
1213
  session_id: idOf("ses").nullable(),
774
1214
  received_at: Timestamp
775
1215
  });
776
1216
 
777
1217
  // ../core/src/schema/app.ts
778
- import { z as z11 } from "zod";
779
- var AppTypeSchema = z11.enum(["frontend_only", "fullstack"]);
780
- var AppStatusSchema = z11.enum(["provisioning", "active", "error"]);
781
- var AppMcpPathSchema = z11.string().regex(/^\/\S*$/, "must be an absolute path beginning with /").max(128);
782
- var AppSchema = z11.object({
1218
+ import { z as z13 } from "zod";
1219
+ var AppTypeSchema = z13.enum(["frontend_only", "fullstack"]);
1220
+ var AppStatusSchema = z13.enum(["provisioning", "active", "error"]);
1221
+ var AppMcpPathSchema = z13.string().regex(/^\/\S*$/, "must be an absolute path beginning with /").max(128);
1222
+ var AppSchema = z13.object({
783
1223
  id: idOf("app"),
784
- object: z11.literal("app"),
785
- name: z11.string(),
786
- description: z11.string().nullable(),
1224
+ object: z13.literal("app"),
1225
+ name: z13.string(),
1226
+ description: z13.string().nullable(),
787
1227
  type: AppTypeSchema,
788
1228
  /**
789
1229
  * The customer's own project name that made this app, or `null` for one made outside a project
790
1230
  * (ADR-0375). Customer-visible, unlike the provider handles: it is the word the customer typed,
791
1231
  * and the refusal that guards a name quotes it.
792
1232
  */
793
- project: z11.string().nullable(),
1233
+ project: z13.string().nullable(),
794
1234
  status: AppStatusSchema,
795
1235
  /** The address the app answers on — platform hostname until a custom domain connects. */
796
- url: z11.string().nullable(),
1236
+ url: z13.string().nullable(),
797
1237
  /** White-label words when `status` is `error`; never the provider's. */
798
- error: z11.string().nullable(),
1238
+ error: z13.string().nullable(),
799
1239
  /** Where the app serves MCP, or `null`. The bearer token for it is a server column. */
800
1240
  mcp: AppMcpPathSchema.nullable(),
801
1241
  created_at: Timestamp
802
1242
  });
803
- var AppDeploymentStatusSchema = z11.enum(["queued", "building", "ready", "error"]);
804
- var AppDeploymentSchema = z11.object({
1243
+ var AppDeploymentStatusSchema = z13.enum(["queued", "building", "ready", "error"]);
1244
+ var AppDeploymentSchema = z13.object({
805
1245
  id: idOf("apd"),
806
- object: z11.literal("app_deployment"),
1246
+ object: z13.literal("app_deployment"),
807
1247
  app_id: idOf("app"),
808
1248
  status: AppDeploymentStatusSchema,
809
- url: z11.string().nullable(),
810
- error: z11.string().nullable(),
1249
+ url: z13.string().nullable(),
1250
+ error: z13.string().nullable(),
811
1251
  /** The client's opaque digest of the files, echoed verbatim so it can skip an unchanged deploy. */
812
- content_hash: z11.string().nullable(),
1252
+ content_hash: z13.string().nullable(),
813
1253
  created_at: Timestamp
814
1254
  });
815
- var AppSecretSchema = z11.object({
816
- object: z11.literal("app_secret"),
817
- name: z11.string(),
1255
+ var AppDeploymentFilesSchema = z13.object({
1256
+ object: z13.literal("app_deployment_files"),
1257
+ deployment_id: idOf("apd"),
1258
+ files: z13.record(z13.string().min(1), z13.string())
1259
+ });
1260
+ var AppSecretSchema = z13.object({
1261
+ object: z13.literal("app_secret"),
1262
+ name: z13.string(),
818
1263
  /** The client's opaque digest of the value, echoed verbatim so it can skip an unchanged write. */
819
- value_hash: z11.string().nullable(),
1264
+ value_hash: z13.string().nullable(),
820
1265
  created_at: Timestamp
821
1266
  });
822
- var AppEntrySchema = z11.object({
823
- object: z11.literal("app_entry"),
824
- url: z11.string(),
825
- ticket: z11.string()
1267
+ var AppEntrySchema = z13.object({
1268
+ object: z13.literal("app_entry"),
1269
+ url: z13.string(),
1270
+ ticket: z13.string()
826
1271
  });
827
- var AppDomainStatusSchema = z11.enum(["pending", "connected", "failed"]);
828
- var AppDomainSchema = z11.object({
829
- object: z11.literal("app_domain"),
1272
+ var AppDomainStatusSchema = z13.enum(["pending", "connected", "failed"]);
1273
+ var AppDomainSchema = z13.object({
1274
+ object: z13.literal("app_domain"),
830
1275
  app_id: idOf("app"),
831
1276
  domain_id: idOf("dom"),
832
- domain: z11.string(),
1277
+ domain: z13.string(),
833
1278
  status: AppDomainStatusSchema,
834
1279
  created_at: Timestamp
835
1280
  });
@@ -837,52 +1282,58 @@ var ENV_NAME = /^[A-Z_][A-Z0-9_]*$/;
837
1282
  var APP_NAME = /^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$/;
838
1283
 
839
1284
  // ../core/src/schema/install.ts
840
- import { z as z12 } from "zod";
841
- var BlueprintInstallSourceSchema = z12.enum(["studio", "cli"]);
842
- var ResourceActionSchema = z12.enum(["created", "updated", "unchanged", "deleted", "refused"]);
843
- var ResourceReportSchema = z12.object({
844
- name: z12.string().min(1),
1285
+ import { z as z14 } from "zod";
1286
+ var BlueprintInstallSourceSchema = z14.enum(["studio", "cli"]);
1287
+ var BlueprintInstallStatusSchema = z14.enum(["pending", "applied", "failed"]);
1288
+ var ResourceActionSchema = z14.enum(["created", "updated", "unchanged", "deleted", "refused"]);
1289
+ var ResourceReportSchema = z14.object({
1290
+ name: z14.string().min(1),
845
1291
  action: ResourceActionSchema,
846
1292
  /** The `agt_`/`app_`/`ses_`… the line resolved to. Absent on a refusal that never got an id. */
847
- id: z12.string().optional(),
1293
+ id: z14.string().optional(),
848
1294
  /** An app's hostname once its build went live; `null` while it has none. Apps only. */
849
- url: z12.string().nullable().optional(),
850
- reason: z12.string().optional()
851
- });
852
- var BlueprintReportSchema = z12.object({
853
- skills: z12.array(ResourceReportSchema),
854
- identities: z12.array(ResourceReportSchema),
855
- vaults: z12.array(ResourceReportSchema),
856
- apps: z12.array(ResourceReportSchema),
857
- agents: z12.array(ResourceReportSchema),
858
- schedules: z12.array(ResourceReportSchema),
859
- intake: z12.array(ResourceReportSchema),
860
- skipped: z12.array(z12.string())
861
- });
862
- var BlueprintInstallSchema = z12.object({
1295
+ url: z14.string().nullable().optional(),
1296
+ reason: z14.string().optional()
1297
+ });
1298
+ var BlueprintReportSchema = z14.object({
1299
+ skills: z14.array(ResourceReportSchema),
1300
+ identities: z14.array(ResourceReportSchema),
1301
+ vaults: z14.array(ResourceReportSchema),
1302
+ apps: z14.array(ResourceReportSchema),
1303
+ agents: z14.array(ResourceReportSchema),
1304
+ schedules: z14.array(ResourceReportSchema),
1305
+ intake: z14.array(ResourceReportSchema),
1306
+ skipped: z14.array(z14.string()),
1307
+ deselected: z14.array(z14.string()).default([])
1308
+ });
1309
+ var BlueprintSelectionSchema = z14.object({
1310
+ agents: z14.array(z14.string().min(1)),
1311
+ apps: z14.array(z14.string().min(1))
1312
+ });
1313
+ var BlueprintInstallSchema = z14.object({
863
1314
  id: idOf("bpi"),
864
- object: z12.literal("blueprint_install"),
1315
+ object: z14.literal("blueprint_install"),
865
1316
  /** The customer's own `defineProject({ name })` — the same word `app.project` stamps (§29.2). */
866
- project: z12.string().min(1),
1317
+ project: z14.string().min(1),
867
1318
  /** The pair the declaration resolved to; `null` for a declaration that names no blueprint. */
868
- blueprint: z12.string().nullable(),
869
- template: z12.string().nullable(),
1319
+ blueprint: z14.string().nullable(),
1320
+ template: z14.string().nullable(),
870
1321
  /**
871
1322
  * Applies, not versions of anything: 1 on the first apply, +1 on each one after, whichever writer
872
1323
  * made it. It is not an agent version and it never rolls back.
873
1324
  */
874
- revision: z12.number().int().positive(),
1325
+ revision: z14.number().int().positive(),
875
1326
  /**
876
1327
  * The blueprint artifact version this came from, or `null` when it was applied from a working
877
1328
  * tree — an operator editing a clone has no version to name.
878
1329
  */
879
- artifact_version: z12.string().nullable(),
1330
+ artifact_version: z14.string().nullable(),
880
1331
  /**
881
1332
  * The setup answers this project was configured with (§7.1 fields, keyed by their `key`), so a
882
1333
  * re-apply does not re-ask and both writers configure from the same answers. Configuration only:
883
1334
  * a secret is a vault credential (§23) or an app secret (§29.2), and neither is ever an answer.
884
1335
  */
885
- answers: z12.record(z12.string(), z12.unknown()),
1336
+ answers: z14.record(z14.string(), z14.unknown()),
886
1337
  /**
887
1338
  * NO `declaration` ON THE WIRE, and that is the reconciliation of §29.6 with §31.1.
888
1339
  *
@@ -909,95 +1360,147 @@ var BlueprintInstallSchema = z12.object({
909
1360
  * a person needs after the screen that showed it is gone.
910
1361
  */
911
1362
  report: BlueprintReportSchema.nullable(),
1363
+ status: BlueprintInstallStatusSchema,
1364
+ /** Why a `failed` run threw, in one sentence; `null` on every other row. Never a stack or a key. */
1365
+ failure: z14.string().nullable(),
1366
+ /**
1367
+ * The `selection` the apply carried, or `null` — every row written before §31.2 and every apply
1368
+ * that omitted it, both meaning "everything". Defaulted so those rows parse unchanged.
1369
+ */
1370
+ selection: BlueprintSelectionSchema.nullable().default(null),
1371
+ /** When the answers were last edited through `PATCH …/installs/{id}` (§31.8); `null` if never. */
1372
+ context_updated_at: Timestamp.nullable().default(null),
912
1373
  applied_at: Timestamp,
913
1374
  created_at: Timestamp
914
1375
  });
1376
+ var ProjectContextAnswerSchema = z14.object({
1377
+ key: z14.string().min(1),
1378
+ label: z14.string(),
1379
+ value: z14.union([z14.string(), z14.array(z14.string())])
1380
+ });
1381
+ var ProjectContextSchema = z14.object({
1382
+ object: z14.literal("project_context"),
1383
+ project: z14.string().min(1),
1384
+ blueprint: z14.string().nullable(),
1385
+ template: z14.string().nullable(),
1386
+ artifact_version: z14.string().nullable(),
1387
+ answers: z14.array(ProjectContextAnswerSchema),
1388
+ apps: z14.array(z14.object({ name: z14.string().min(1), url: z14.string().nullable() })),
1389
+ agents: z14.array(z14.object({ name: z14.string().min(1), role: z14.string().nullable() })),
1390
+ /** `context_updated_at` once the answers have been edited, `applied_at` until then. */
1391
+ updated_at: Timestamp
1392
+ });
915
1393
 
916
1394
  // ../core/src/schema/blueprint.ts
917
- import { z as z13 } from "zod";
918
- var BlueprintScheduleSchema = z13.object({
919
- agent: z13.string().min(1),
920
- cron: z13.string().min(1),
921
- timezone: z13.string().nullable(),
1395
+ import { z as z15 } from "zod";
1396
+ var BlueprintScheduleSchema = z15.object({
1397
+ agent: z15.string().min(1),
1398
+ cron: z15.string().min(1),
1399
+ timezone: z15.string().nullable(),
922
1400
  /** The message each fire opens its session with — the sentence worth printing. */
923
- input: z13.string().min(1),
1401
+ input: z15.string().min(1),
924
1402
  budget_micro_usd: MicroUsdField.nonnegative()
925
1403
  });
926
- var BlueprintCrewSchema = z13.object({
927
- name: z13.string().min(1),
928
- description: z13.string().nullable(),
929
- model: z13.string().min(1),
930
- briefed: z13.boolean()
931
- });
932
- var BlueprintAppSchema = z13.object({
933
- name: z13.string().min(1),
1404
+ var BlueprintBudgetSchema = BlueprintScheduleSchema.pick({ agent: true, cron: true, budget_micro_usd: true });
1405
+ var BlueprintCrewSchema = z15.object({
1406
+ name: z15.string().min(1),
1407
+ description: z15.string().nullable(),
1408
+ model: z15.string().min(1),
1409
+ briefed: z15.boolean(),
1410
+ intake: z15.string().nullable().optional(),
1411
+ /** What the first session may spend: the intake's own cap, else the agent's (§31.4). Set iff `briefed`. */
1412
+ intake_micro_usd: MicroUsdField.nonnegative().optional(),
1413
+ role: z15.string().min(1).optional(),
1414
+ skills: z15.array(SkillRefSchema).optional(),
1415
+ tools: z15.array(z15.string().min(1)).optional(),
1416
+ required: z15.boolean().optional()
1417
+ });
1418
+ var BlueprintAppSchema = z15.object({
1419
+ name: z15.string().min(1),
934
1420
  type: AppTypeSchema,
935
- description: z13.string().nullable()
936
- });
937
- var ContentHashSchema = z13.string().regex(/^[0-9a-f]{64}$/, "a lowercase sha-256 hex digest");
938
- var BlueprintTreeSchema = z13.object({
1421
+ description: z15.string().nullable(),
1422
+ mcp: z15.string().nullable().optional(),
1423
+ tools: z15.array(z15.string().min(1)).optional(),
1424
+ /** Whether an install may deselect it (§31.2). Optional: the rollout argument above. */
1425
+ required: z15.boolean().optional()
1426
+ });
1427
+ var ContentHashSchema = z15.string().regex(/^[0-9a-f]{64}$/, "a lowercase sha-256 hex digest");
1428
+ var BlueprintTreeSchema = z15.object({
939
1429
  /** `apps[].name` in the declaration — the same name §31.5 prints and the install ensures by. */
940
- app: z13.string().min(1),
1430
+ app: z15.string().min(1),
941
1431
  content_hash: ContentHashSchema
942
1432
  });
943
- var BlueprintArtifactSchema = z13.object({
1433
+ var BlueprintArtifactSchema = z15.object({
944
1434
  id: idOf("bpa"),
945
- object: z13.literal("blueprint_artifact"),
1435
+ object: z15.literal("blueprint_artifact"),
946
1436
  /** The machine — its repository, screens and `/api/*`. */
947
- blueprint: z13.string().min(1),
1437
+ blueprint: z15.string().min(1),
948
1438
  /** Which of that blueprint's templates provides the crew. */
949
- template: z13.string().min(1),
1439
+ template: z15.string().min(1),
950
1440
  /** The blueprint repository's own released version. Stored, never parsed (ADR-0401). */
951
- version: z13.string().min(1),
1441
+ version: z15.string().min(1),
952
1442
  /**
953
1443
  * The built trees, one per deployable app, ordered as the declaration orders its apps. Never
954
1444
  * empty: an artifact that built nothing is not an artifact, and the column behind it says so
955
1445
  * (migration 0040) exactly as the single `content_hash` it replaces was `not null`.
956
1446
  */
957
- trees: z13.array(BlueprintTreeSchema).min(1),
1447
+ trees: z15.array(BlueprintTreeSchema).min(1),
958
1448
  /**
959
1449
  * The setup questions, asked by the studio **before** provisioning. `QuestionField` (§7.1) is
960
1450
  * reused rather than restated: a setup question and a question a parked agent asks are the same
961
1451
  * object at different times, so one component renders both.
962
1452
  */
963
- questions: z13.array(QuestionFieldSchema),
964
- schedules: z13.array(BlueprintScheduleSchema),
1453
+ questions: z15.array(QuestionFieldSchema),
1454
+ schedules: z15.array(BlueprintScheduleSchema),
965
1455
  /** Who the crew is, and what it deploys — §31.5. Derived from `declaration`, never stored twice. */
966
- agents: z13.array(BlueprintCrewSchema),
967
- apps: z13.array(BlueprintAppSchema),
1456
+ agents: z15.array(BlueprintCrewSchema),
1457
+ apps: z15.array(BlueprintAppSchema),
1458
+ /**
1459
+ * The agents a template creates per client the operator signs — printed, never provisioned by an
1460
+ * apply (§31.1). Absent on rows published before WS12 v2, hence optional.
1461
+ */
1462
+ crew_per_client: z15.array(BlueprintCrewSchema).optional(),
1463
+ /**
1464
+ * The creator template a row was published from (§42.8), `null` on every first-party row.
1465
+ * `creator_name` is the public display name the landing page credits. The API sends all three
1466
+ * on every row; they are optional here only so an artifact typed before §42 still reads.
1467
+ */
1468
+ creator_template_id: idOf("ctp").nullish(),
1469
+ creator_template_version: z15.number().int().positive().nullish(),
1470
+ creator_name: z15.string().min(1).nullish(),
968
1471
  published_at: Timestamp
969
1472
  });
970
1473
 
971
1474
  // ../core/src/schema/vault.ts
972
- import { z as z14 } from "zod";
973
- var VaultCredentialKindSchema = z14.enum(["env_var", "static_bearer", "mcp_oauth"]);
974
- var VaultSchema = z14.object({
1475
+ import { z as z16 } from "zod";
1476
+ var VaultCredentialKindSchema = z16.enum(["env_var", "static_bearer", "mcp_oauth"]);
1477
+ var VaultSchema = z16.object({
975
1478
  id: idOf("vlt"),
976
- object: z14.literal("vault"),
1479
+ object: z16.literal("vault"),
977
1480
  identity_id: idOf("idn").nullable(),
978
- display_name: z14.string().min(1).max(128),
979
- credential_count: z14.number().int().nonnegative(),
1481
+ display_name: z16.string().min(1).max(128),
1482
+ credential_count: z16.number().int().nonnegative(),
980
1483
  created_at: Timestamp
981
1484
  });
982
- var VaultCredentialSchema = z14.object({
1485
+ var VaultCredentialSchema = z16.object({
983
1486
  id: idOf("vcr"),
984
- object: z14.literal("vault_credential"),
1487
+ object: z16.literal("vault_credential"),
985
1488
  vault_id: idOf("vlt"),
986
1489
  kind: VaultCredentialKindSchema,
987
1490
  /** For `env_var`, the environment variable name. For the MCP kinds, a display label. */
988
- key: z14.string().min(1).max(128),
1491
+ key: z16.string().min(1).max(128),
989
1492
  /** The exact destination host an `env_var` credential is bound to. Never a wildcard. */
990
- host: z14.string().nullable(),
1493
+ host: z16.string().nullable(),
991
1494
  /** The exact MCP server URL an `mcp_*` token is matched to. */
992
- mcp_server_url: z14.url().nullable(),
993
- placeholder_ref: z14.string(),
1495
+ mcp_server_url: z16.url().nullable(),
1496
+ placeholder_ref: z16.string(),
994
1497
  expires_at: Timestamp.nullable(),
995
1498
  last_injected_at: Timestamp.nullable(),
996
1499
  created_at: Timestamp
997
1500
  });
998
1501
 
999
1502
  // ../core/src/schema/social.ts
1000
- import { z as z15 } from "zod";
1503
+ import { z as z17 } from "zod";
1001
1504
  var SOCIAL_PLATFORMS = [
1002
1505
  "bluesky",
1003
1506
  "facebook",
@@ -1019,19 +1522,27 @@ var SOCIAL_TEXT_PLATFORMS = [
1019
1522
  "threads",
1020
1523
  "x"
1021
1524
  ];
1022
- var SocialPlatformSchema = z15.enum(SOCIAL_PLATFORMS);
1023
- var SocialTextPlatformSchema = z15.enum(SOCIAL_TEXT_PLATFORMS);
1024
- var SocialAccountSchema = z15.object({
1025
- id: z15.string().min(1),
1026
- object: z15.literal("social_account"),
1525
+ var SOCIAL_MEDIA_PLATFORMS = ["instagram", "tiktok", "youtube"];
1526
+ var SOCIAL_VISIBILITIES = ["public", "unlisted", "private"];
1527
+ var SOCIAL_VISIBILITY_PLATFORMS = ["mastodon", "youtube"];
1528
+ var SocialVisibilitySchema = z17.enum(SOCIAL_VISIBILITIES);
1529
+ var SOCIAL_VISIBILITY_RULE = `visibility is ${SOCIAL_VISIBILITIES.join(", ")} and only ${SOCIAL_VISIBILITY_PLATFORMS.join(" and ")} accept it; omit it and the post publishes at the account's own default, which on a video channel is normally public`;
1530
+ var SocialPlatformSchema = z17.enum(SOCIAL_PLATFORMS);
1531
+ var SocialTextPlatformSchema = z17.enum(SOCIAL_TEXT_PLATFORMS);
1532
+ var isText = (platform) => SOCIAL_TEXT_PLATFORMS.includes(platform);
1533
+ var isMedia = (platform) => SOCIAL_MEDIA_PLATFORMS.includes(platform);
1534
+ var SOCIAL_PLATFORM_RULE = `${SOCIAL_TEXT_PLATFORMS.join(", ")} take a text-only post; ${SOCIAL_MEDIA_PLATFORMS.join(", ")} may be named only when the post carries media_urls or file_ids; ${SOCIAL_PLATFORMS.filter((platform) => !isText(platform) && !isMedia(platform)).join(", ")} cannot be posted to`;
1535
+ var SocialAccountSchema = z17.object({
1536
+ id: z17.string().min(1),
1537
+ object: z17.literal("social_account"),
1027
1538
  identity_id: idOf("idn"),
1028
1539
  platform: SocialPlatformSchema,
1029
- username: z15.string().nullable(),
1030
- display_name: z15.string().nullable(),
1031
- avatar_url: z15.url().nullable(),
1540
+ username: z17.string().nullable(),
1541
+ display_name: z17.string().nullable(),
1542
+ avatar_url: z17.url().nullable(),
1032
1543
  connected_at: Timestamp.nullable()
1033
1544
  });
1034
- var SocialPostStatusSchema = z15.enum([
1545
+ var SocialPostStatusSchema = z17.enum([
1035
1546
  "draft",
1036
1547
  "scheduled",
1037
1548
  "processing",
@@ -1039,51 +1550,932 @@ var SocialPostStatusSchema = z15.enum([
1039
1550
  "failed",
1040
1551
  "deleted"
1041
1552
  ]);
1042
- var SocialPostSchema = z15.object({
1043
- id: z15.string().min(1),
1044
- object: z15.literal("social_post"),
1553
+ var SocialPostSchema = z17.object({
1554
+ id: z17.string().min(1),
1555
+ object: z17.literal("social_post"),
1045
1556
  identity_id: idOf("idn"),
1046
- title: z15.string(),
1047
- platforms: z15.array(SocialTextPlatformSchema),
1557
+ title: z17.string(),
1558
+ platforms: z17.array(SocialPlatformSchema),
1048
1559
  status: SocialPostStatusSchema,
1049
1560
  scheduled_at: Timestamp.nullable(),
1050
1561
  posted_at: Timestamp.nullable(),
1051
- error: z15.string().nullable()
1562
+ error: z17.string().nullable()
1052
1563
  });
1053
- var SocialUploadSchema = z15.object({
1054
- id: z15.string().min(1),
1055
- object: z15.literal("social_upload"),
1564
+ var SocialUploadSchema = z17.object({
1565
+ id: z17.string().min(1),
1566
+ object: z17.literal("social_upload"),
1056
1567
  identity_id: idOf("idn"),
1057
- type: z15.enum(["image", "video", "document"]),
1058
- url: z15.url().nullable()
1568
+ type: z17.enum(["image", "video", "document"]),
1569
+ url: z17.url().nullable()
1059
1570
  });
1060
- var SocialAnalyticsSchema = z15.object({
1061
- object: z15.literal("social_analytics"),
1571
+ var SocialAnalyticsSchema = z17.object({
1572
+ object: z17.literal("social_analytics"),
1062
1573
  identity_id: idOf("idn"),
1063
- resource_id: z15.string().min(1),
1574
+ resource_id: z17.string().min(1),
1064
1575
  platform: SocialPlatformSchema.nullable(),
1065
- data: z15.unknown()
1576
+ data: z17.unknown()
1066
1577
  });
1067
- var SocialCommentSchema = z15.object({
1068
- id: z15.string().min(1),
1069
- object: z15.literal("social_comment"),
1578
+ var SocialCommentSchema = z17.object({
1579
+ id: z17.string().min(1),
1580
+ object: z17.literal("social_comment"),
1070
1581
  identity_id: idOf("idn"),
1071
- post_id: z15.string().min(1),
1072
- platforms: z15.array(SocialPlatformSchema),
1582
+ post_id: z17.string().min(1),
1583
+ platforms: z17.array(SocialPlatformSchema),
1073
1584
  status: SocialPostStatusSchema,
1074
1585
  posted_at: Timestamp.nullable(),
1075
- data: z15.unknown()
1586
+ data: z17.unknown()
1587
+ });
1588
+
1589
+ // ../core/src/schema/media.ts
1590
+ import { z as z18 } from "zod";
1591
+ var MEDIA_JOB_KINDS = ["video", "clip", "transcription"];
1592
+ var MediaJobKindSchema = z18.enum(MEDIA_JOB_KINDS);
1593
+ var MediaJobStatusSchema = z18.enum(["queued", "processing", "completed", "failed"]);
1594
+ var PublicUrl = z18.string().url().startsWith("http");
1595
+ var Score = z18.number().int().min(0).max(100);
1596
+ var Seconds = z18.number().nonnegative();
1597
+ var VideoResultSchema = z18.object({
1598
+ files: z18.array(
1599
+ z18.object({
1600
+ file_id: idOf("fil"),
1601
+ content_type: z18.string(),
1602
+ width: z18.number().int().positive().nullable(),
1603
+ height: z18.number().int().positive().nullable(),
1604
+ duration_seconds: Seconds.nullable()
1605
+ })
1606
+ )
1607
+ });
1608
+ var ViralityScoreSchema = z18.object({
1609
+ total: Score,
1610
+ shareability: Score,
1611
+ hook_strength: Score,
1612
+ story_quality: Score,
1613
+ emotional_impact: Score
1614
+ });
1615
+ var ClipResultSchema = z18.object({
1616
+ clips: z18.array(
1617
+ z18.object({
1618
+ file_id: idOf("fil"),
1619
+ title: z18.string(),
1620
+ start_seconds: Seconds,
1621
+ end_seconds: Seconds,
1622
+ duration_seconds: Seconds,
1623
+ virality: ViralityScoreSchema
1624
+ })
1625
+ )
1626
+ });
1627
+ var TranscriptSchema = z18.object({
1628
+ text: z18.string(),
1629
+ language: z18.string().nullable(),
1630
+ duration_seconds: Seconds.nullable(),
1631
+ segments: z18.array(z18.object({ start_seconds: Seconds, end_seconds: Seconds, text: z18.string() }))
1632
+ });
1633
+ var MediaJobResultSchema = z18.union([VideoResultSchema, ClipResultSchema, TranscriptSchema]);
1634
+ var MediaJobSchema = z18.object({
1635
+ id: idOf("med"),
1636
+ object: z18.literal("media_job"),
1637
+ kind: MediaJobKindSchema,
1638
+ status: MediaJobStatusSchema,
1639
+ model: z18.string().nullable(),
1640
+ input: z18.record(z18.string(), z18.unknown()),
1641
+ result: MediaJobResultSchema.nullable(),
1642
+ error: z18.object({ code: z18.string(), message: z18.string() }).nullable(),
1643
+ cost_micro_usd: MicroUsdField.nullable(),
1644
+ session_id: idOf("ses").nullable(),
1645
+ created_at: Timestamp,
1646
+ completed_at: Timestamp.nullable()
1647
+ });
1648
+ var ImageRequestSchema = z18.object({
1649
+ model: z18.string().min(1).optional(),
1650
+ prompt: z18.string().min(1),
1651
+ image_urls: z18.array(PublicUrl).max(4).optional(),
1652
+ aspect_ratio: z18.string().optional(),
1653
+ seed: z18.number().int().optional(),
1654
+ n: z18.number().int().min(1).max(4).default(1)
1655
+ });
1656
+ var VideoRequestSchema = z18.object({
1657
+ model: z18.string().min(1),
1658
+ prompt: z18.string().min(1),
1659
+ image_urls: z18.array(PublicUrl).max(1).optional(),
1660
+ aspect_ratio: z18.string().optional(),
1661
+ seed: z18.number().int().optional(),
1662
+ seconds: z18.number().int().min(1).max(60).optional()
1663
+ });
1664
+ var ImageGenerationSchema = z18.object({
1665
+ object: z18.literal("image_generation"),
1666
+ model: z18.string(),
1667
+ files: z18.array(FileSchema),
1668
+ cost_micro_usd: MicroUsdField
1669
+ });
1670
+ var ClipLength = z18.number().int().min(5).max(180);
1671
+ var ClipRequestSchema = z18.object({
1672
+ video_url: PublicUrl,
1673
+ aspect_ratio: z18.enum(["9:16", "16:9"]).default("9:16"),
1674
+ remove_silence: z18.boolean().default(false),
1675
+ caption_preset: z18.enum(["none", "clean", "bold", "karaoke"]).default("none"),
1676
+ language: z18.string().min(2).optional(),
1677
+ min_seconds: ClipLength.default(15),
1678
+ max_seconds: ClipLength.default(60),
1679
+ title: z18.string().min(1).optional()
1680
+ });
1681
+ var AudioFormatSchema = z18.enum(["mp3", "wav", "ogg"]);
1682
+ var TranscriptionRequestSchema = z18.object({
1683
+ model: z18.string().min(1).optional(),
1684
+ file_id: idOf("fil").optional(),
1685
+ url: PublicUrl.optional(),
1686
+ language: z18.string().min(2).optional(),
1687
+ timestamps: z18.boolean().default(true)
1688
+ }).refine((request) => request.file_id === void 0 !== (request.url === void 0), {
1689
+ error: "exactly one of file_id or url",
1690
+ path: ["file_id"]
1691
+ });
1692
+ var SpeechRequestSchema = z18.object({
1693
+ model: z18.string().min(1).optional(),
1694
+ text: z18.string().min(1).max(4096),
1695
+ voice: z18.string().min(1).optional(),
1696
+ format: AudioFormatSchema.default("mp3"),
1697
+ speed: z18.number().min(0.5).max(2).optional()
1698
+ });
1699
+ var SpeechToSpeechRequestSchema = z18.object({
1700
+ model: z18.string().min(1).optional(),
1701
+ file_id: idOf("fil"),
1702
+ voice: z18.string().min(1).optional(),
1703
+ format: AudioFormatSchema.default("mp3")
1704
+ });
1705
+ var SpeechGenerationSchema = z18.object({
1706
+ object: z18.literal("speech_generation"),
1707
+ model: z18.string(),
1708
+ file: FileSchema,
1709
+ duration_seconds: Seconds.nullable(),
1710
+ cost_micro_usd: MicroUsdField
1711
+ });
1712
+
1713
+ // ../core/src/schema/app-data.ts
1714
+ import { z as z19 } from "zod";
1715
+ var DbTableSchema = z19.object({
1716
+ object: z19.literal("db_table"),
1717
+ name: z19.string(),
1718
+ schema: z19.string().default("public"),
1719
+ rows: z19.number().int().nonnegative().nullable(),
1720
+ size_bytes: z19.number().int().nonnegative().nullable()
1721
+ });
1722
+ var DbMigrationSchema = z19.object({
1723
+ id: idOf("dbm"),
1724
+ object: z19.literal("db_migration"),
1725
+ name: z19.string(),
1726
+ sha256: z19.string().regex(/^[0-9a-f]{64}$/),
1727
+ applied_at: Timestamp,
1728
+ statements: z19.number().int().nonnegative()
1729
+ });
1730
+ var ApplyDbMigrationSchema = z19.object({
1731
+ name: z19.string().min(1).max(128).regex(/^[a-z0-9][a-z0-9_-]*$/),
1732
+ sql: z19.string().min(1)
1733
+ });
1734
+ var DB_REST_METHODS = ["GET", "POST", "PATCH", "PUT", "DELETE", "HEAD"];
1735
+ var DbRestMethodSchema = z19.enum(DB_REST_METHODS);
1736
+ var BUCKET_NAME = /^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$/;
1737
+ var BucketSchema = z19.object({
1738
+ object: z19.literal("bucket"),
1739
+ name: z19.string().regex(BUCKET_NAME),
1740
+ public: z19.boolean(),
1741
+ created_at: Timestamp
1742
+ });
1743
+ var CreateBucketSchema = z19.object({
1744
+ name: z19.string().regex(BUCKET_NAME, { error: "3\u201363 lowercase letters, digits and hyphens" }),
1745
+ public: z19.boolean().default(false)
1746
+ });
1747
+ var StorageObjectSchema = z19.object({
1748
+ object: z19.literal("storage_object"),
1749
+ bucket: z19.string(),
1750
+ key: z19.string().min(1),
1751
+ size_bytes: z19.number().int().nonnegative(),
1752
+ content_type: z19.string(),
1753
+ etag: z19.string().nullable(),
1754
+ updated_at: Timestamp
1755
+ });
1756
+ var SignedUrlMethodSchema = z19.enum(["PUT", "GET"]);
1757
+ var SignedUrlSchema = z19.object({
1758
+ object: z19.literal("signed_url"),
1759
+ url: z19.string().url(),
1760
+ method: SignedUrlMethodSchema,
1761
+ expires_at: Timestamp
1762
+ });
1763
+ var CreateUploadUrlSchema = z19.object({
1764
+ content_type: z19.string().min(1),
1765
+ expires_seconds: z19.number().int().min(60).max(3600).default(900)
1766
+ });
1767
+
1768
+ // ../core/src/schema/stock-photo.ts
1769
+ import { z as z20 } from "zod";
1770
+ var STOCK_PHOTO_ORIENTATIONS = ["landscape", "portrait", "square"];
1771
+ var STOCK_PHOTO_SIZES = ["small", "medium", "large"];
1772
+ var StockPhotoQuerySchema = z20.object({
1773
+ query: z20.string().min(1).max(200),
1774
+ count: z20.coerce.number().int().min(1).max(30).default(10),
1775
+ orientation: z20.enum(STOCK_PHOTO_ORIENTATIONS).optional(),
1776
+ color: z20.string().min(1).max(32).optional(),
1777
+ size: z20.enum(STOCK_PHOTO_SIZES).optional()
1778
+ });
1779
+ var StockPhotoSchema = z20.object({
1780
+ object: z20.literal("stock_photo"),
1781
+ id: z20.string().min(1),
1782
+ width: z20.number().int().positive(),
1783
+ height: z20.number().int().positive(),
1784
+ url: z20.string().url(),
1785
+ preview_url: z20.string().url(),
1786
+ alt: z20.string().nullable(),
1787
+ photographer: z20.string().nullable(),
1788
+ attribution_url: z20.string().url().nullable(),
1789
+ dominant_color: z20.string().nullable()
1790
+ });
1791
+
1792
+ // ../core/src/schema/creator.ts
1793
+ import { z as z21 } from "zod";
1794
+ var CreatorCodeSchema = z21.string().regex(/^[a-z0-9]{3,24}$/, "3 to 24 lowercase letters or digits");
1795
+ var PayoutMethodSchema = z21.enum(["wise", "paypal"]);
1796
+ var PayoutDetailsSchema = z21.object({
1797
+ method: PayoutMethodSchema,
1798
+ account: z21.string().min(1).max(320)
1799
+ });
1800
+ var CreatorStatusSchema = z21.enum(["active", "suspended"]);
1801
+ var CreatorSchema = z21.object({
1802
+ id: idOf("crt"),
1803
+ object: z21.literal("creator"),
1804
+ email: z21.email(),
1805
+ display_name: z21.string().min(1).max(80),
1806
+ code: CreatorCodeSchema,
1807
+ status: CreatorStatusSchema,
1808
+ payout: PayoutDetailsSchema.nullable(),
1809
+ clicks: z21.number().int().nonnegative(),
1810
+ created_at: Timestamp,
1811
+ updated_at: Timestamp
1812
+ });
1813
+ var IdentityCreatorSchema = CreatorSchema.pick({
1814
+ id: true,
1815
+ status: true
1816
+ });
1817
+ var CreatorApplicationStatusSchema = z21.enum([
1818
+ "pending",
1819
+ "approved",
1820
+ "rejected"
1821
+ ]);
1822
+ var CreatorApplicationSchema = z21.object({
1823
+ id: idOf("cra"),
1824
+ object: z21.literal("creator_application"),
1825
+ email: z21.email(),
1826
+ display_name: z21.string().min(1).max(80),
1827
+ pitch: z21.string().min(1).max(2e3),
1828
+ links: z21.array(z21.url({ protocol: /^https$/ })).max(5),
1829
+ status: CreatorApplicationStatusSchema,
1830
+ note: z21.string().nullable(),
1831
+ creator_id: idOf("crt").nullable(),
1832
+ created_at: Timestamp,
1833
+ decided_at: Timestamp.nullable()
1834
+ });
1835
+ var ReferralStatusSchema = z21.enum(["pending", "active", "expired"]);
1836
+ var ReferralSchema = z21.object({
1837
+ id: idOf("crf"),
1838
+ object: z21.literal("referral"),
1839
+ creator_id: idOf("crt"),
1840
+ organization_id: idOf("org"),
1841
+ status: ReferralStatusSchema,
1842
+ attributed_at: Timestamp,
1843
+ first_paid_at: Timestamp.nullable(),
1844
+ commission_until: Timestamp.nullable()
1845
+ });
1846
+ var CommissionKindSchema = z21.enum(["referral", "template"]);
1847
+ var CommissionStatusSchema = z21.enum([
1848
+ "pending",
1849
+ "available",
1850
+ "claimed",
1851
+ "paid"
1852
+ ]);
1853
+ var CommissionSchema = z21.object({
1854
+ id: idOf("crc"),
1855
+ object: z21.literal("commission"),
1856
+ creator_id: idOf("crt"),
1857
+ kind: CommissionKindSchema,
1858
+ referral_id: idOf("crf").nullable(),
1859
+ install_id: idOf("bpi").nullable(),
1860
+ creator_template_id: idOf("ctp").nullable(),
1861
+ base_micro_usd: MicroUsdField.nonnegative(),
1862
+ amount_micro_usd: MicroUsdField.nonnegative(),
1863
+ status: CommissionStatusSchema,
1864
+ accrued_at: Timestamp,
1865
+ available_at: Timestamp,
1866
+ payout_id: idOf("crp").nullable()
1867
+ });
1868
+ var PayoutStatusSchema = z21.enum(["requested", "paid", "rejected"]);
1869
+ var PayoutSchema = z21.object({
1870
+ id: idOf("crp"),
1871
+ object: z21.literal("payout"),
1872
+ creator_id: idOf("crt"),
1873
+ amount_micro_usd: MicroUsdField.positive(),
1874
+ currency: z21.literal("USD"),
1875
+ method: PayoutMethodSchema,
1876
+ account: z21.string().min(1),
1877
+ status: PayoutStatusSchema,
1878
+ reference: z21.string().nullable(),
1879
+ note: z21.string().nullable(),
1880
+ requested_at: Timestamp,
1881
+ decided_at: Timestamp.nullable()
1882
+ });
1883
+ var CREATOR_PROGRAM = {
1884
+ referral_percent: 20,
1885
+ template_percent: 5,
1886
+ commission_months: 12,
1887
+ hold_days: 30,
1888
+ attribution_days: 30,
1889
+ minimum_payout_micro_usd: 2e7
1890
+ };
1891
+ var CreatorTemplateSlugSchema = z21.string().max(32).regex(
1892
+ /^[a-z0-9]+(-[a-z0-9]+)*$/,
1893
+ "lowercase letters, digits and single dashes"
1894
+ );
1895
+ var CreatorSkillSchema = z21.object({
1896
+ slug: z21.string().regex(/^[a-z0-9][a-z0-9-]*$/, "lowercase letters, digits and dashes"),
1897
+ body: z21.string().min(1).max(64 * 1024)
1898
+ });
1899
+ var CreatorDeclarationSchema = z21.object({
1900
+ agents: z21.array(z21.unknown()),
1901
+ questions: z21.array(z21.unknown()),
1902
+ skills: z21.array(CreatorSkillSchema).max(16)
1903
+ });
1904
+ var CreatorTemplateVersionStatusSchema = z21.enum([
1905
+ "in_review",
1906
+ "approved",
1907
+ "changes_requested"
1908
+ ]);
1909
+ var VersionNumber = z21.number().int().positive();
1910
+ var CreatorTemplateSchema = z21.object({
1911
+ id: idOf("ctp"),
1912
+ object: z21.literal("creator_template"),
1913
+ creator_id: idOf("crt"),
1914
+ blueprint: z21.string().min(1),
1915
+ base_template: z21.string().min(1),
1916
+ slug: CreatorTemplateSlugSchema,
1917
+ template: z21.string().min(1).max(64),
1918
+ name: z21.string().min(1).max(80),
1919
+ description: z21.string().max(2e3),
1920
+ declaration: CreatorDeclarationSchema,
1921
+ published_version: VersionNumber.nullable(),
1922
+ latest_version: z21.object({
1923
+ version: VersionNumber,
1924
+ status: CreatorTemplateVersionStatusSchema
1925
+ }).nullable(),
1926
+ created_at: Timestamp,
1927
+ updated_at: Timestamp
1928
+ });
1929
+ var CreatorTemplateVersionSchema = z21.object({
1930
+ object: z21.literal("creator_template_version"),
1931
+ template_id: idOf("ctp"),
1932
+ version: VersionNumber,
1933
+ declaration: CreatorDeclarationSchema,
1934
+ status: CreatorTemplateVersionStatusSchema,
1935
+ note: z21.string().nullable(),
1936
+ artifact_id: idOf("bpa").nullable(),
1937
+ submitted_at: Timestamp,
1938
+ decided_at: Timestamp.nullable()
1939
+ });
1940
+ var CreatorBalanceSchema = z21.object({
1941
+ object: z21.literal("creator_balance"),
1942
+ pending_micro_usd: MicroUsdField.nonnegative(),
1943
+ available_micro_usd: MicroUsdField.nonnegative(),
1944
+ claimed_micro_usd: MicroUsdField.nonnegative(),
1945
+ paid_micro_usd: MicroUsdField.nonnegative(),
1946
+ minimum_payout_micro_usd: z21.literal(CREATOR_PROGRAM.minimum_payout_micro_usd)
1947
+ });
1948
+ var ReferralClickSchema = z21.object({
1949
+ object: z21.literal("referral_click"),
1950
+ code: CreatorCodeSchema,
1951
+ creator: z21.object({ display_name: z21.string().min(1) }),
1952
+ expires_at: Timestamp
1953
+ });
1954
+ var Day = z21.iso.date();
1955
+ var CreatorAnalyticsSchema = z21.object({
1956
+ object: z21.literal("creator_analytics"),
1957
+ days: z21.number().int().min(1).max(90),
1958
+ from: Day,
1959
+ to: Day,
1960
+ clicks: z21.number().int().nonnegative(),
1961
+ referrals: z21.number().int().nonnegative(),
1962
+ installs: z21.number().int().nonnegative(),
1963
+ active_installs: z21.number().int().nonnegative(),
1964
+ usage_by_day: z21.array(
1965
+ z21.object({ day: Day, debit_micro_usd: MicroUsdField.nonnegative() })
1966
+ ),
1967
+ commission_micro_usd: z21.object({
1968
+ pending: MicroUsdField.nonnegative(),
1969
+ available: MicroUsdField.nonnegative(),
1970
+ claimed: MicroUsdField.nonnegative(),
1971
+ paid: MicroUsdField.nonnegative()
1972
+ }),
1973
+ commissions_by_template: z21.array(
1974
+ z21.object({
1975
+ creator_template_id: idOf("ctp"),
1976
+ amount_micro_usd: MicroUsdField.nonnegative()
1977
+ })
1978
+ ),
1979
+ /** Every install covered, newest first: the day it was created and the day its twelve months end. */
1980
+ install_windows: z21.array(z21.object({ install_id: idOf("bpi"), from: Day, until: Day }))
1981
+ });
1982
+
1983
+ // ../core/src/schema/legal.ts
1984
+ import { z as z22 } from "zod";
1985
+ var LEGAL_MEMBER_STATUSES = [
1986
+ "pending",
1987
+ "link_ready",
1988
+ "link_sent",
1989
+ "in_progress",
1990
+ "pending_review",
1991
+ "verified",
1992
+ "failed"
1993
+ ];
1994
+ var LegalMemberStatusSchema = z22.enum(LEGAL_MEMBER_STATUSES);
1995
+ var LEGAL_VERIFICATION_STATUSES = ["in_progress", "pending_review", "verified", "failed"];
1996
+ var LegalVerificationStatusSchema = z22.enum(LEGAL_VERIFICATION_STATUSES);
1997
+ var LEGAL_COMPANY_STATUSES = ["awaiting_payment", "paid", "submitted", "formed", "failed"];
1998
+ var LegalCompanyStatusSchema = z22.enum(LEGAL_COMPANY_STATUSES);
1999
+ var LEGAL_DOCUMENT_KINDS = ["articles", "ein_letter", "operating_agreement", "other"];
2000
+ var LegalDocumentKindSchema = z22.enum(LEGAL_DOCUMENT_KINDS);
2001
+ var LegalMemberRoleSchema = z22.enum(["primary", "secondary"]);
2002
+ var LegalEinStatusSchema = z22.enum(["none", "pending", "issued"]);
2003
+ var LegalRequiredActionKindSchema = z22.enum(["signature", "information", "payment", "other"]);
2004
+ var US_STATES = [
2005
+ "AL",
2006
+ "AK",
2007
+ "AZ",
2008
+ "AR",
2009
+ "CA",
2010
+ "CO",
2011
+ "CT",
2012
+ "DE",
2013
+ "DC",
2014
+ "FL",
2015
+ "GA",
2016
+ "HI",
2017
+ "ID",
2018
+ "IL",
2019
+ "IN",
2020
+ "IA",
2021
+ "KS",
2022
+ "KY",
2023
+ "LA",
2024
+ "ME",
2025
+ "MD",
2026
+ "MA",
2027
+ "MI",
2028
+ "MN",
2029
+ "MS",
2030
+ "MO",
2031
+ "MT",
2032
+ "NE",
2033
+ "NV",
2034
+ "NH",
2035
+ "NJ",
2036
+ "NM",
2037
+ "NY",
2038
+ "NC",
2039
+ "ND",
2040
+ "OH",
2041
+ "OK",
2042
+ "OR",
2043
+ "PA",
2044
+ "RI",
2045
+ "SC",
2046
+ "SD",
2047
+ "TN",
2048
+ "TX",
2049
+ "UT",
2050
+ "VT",
2051
+ "VA",
2052
+ "WA",
2053
+ "WV",
2054
+ "WI",
2055
+ "WY"
2056
+ ];
2057
+ var UsStateSchema = z22.enum(US_STATES);
2058
+ var LegalMemberInputSchema = z22.object({
2059
+ first_name: z22.string().min(1).max(128),
2060
+ last_name: z22.string().min(1).max(128),
2061
+ email: z22.string().min(1).max(320),
2062
+ role: LegalMemberRoleSchema,
2063
+ is_responsible_party: z22.boolean(),
2064
+ ownership_percent: z22.number().int()
2065
+ });
2066
+ var LegalMemberSchema = LegalMemberInputSchema.extend({
2067
+ id: idOf("lgm"),
2068
+ object: z22.literal("legal_member"),
2069
+ verification_id: idOf("lgv"),
2070
+ status: LegalMemberStatusSchema,
2071
+ link_url: z22.url().nullable(),
2072
+ link_expires_at: Timestamp.nullable(),
2073
+ completed_at: Timestamp.nullable()
2074
+ });
2075
+ var LegalVerificationSchema = z22.object({
2076
+ id: idOf("lgv"),
2077
+ object: z22.literal("legal_verification"),
2078
+ identity_id: idOf("idn"),
2079
+ status: LegalVerificationStatusSchema,
2080
+ members: z22.array(LegalMemberSchema),
2081
+ ready_for_formation: z22.boolean(),
2082
+ started_at: Timestamp,
2083
+ completed_at: Timestamp.nullable(),
2084
+ created_at: Timestamp,
2085
+ updated_at: Timestamp
2086
+ });
2087
+ var StartLegalVerificationSchema = z22.object({ members: z22.array(LegalMemberInputSchema) });
2088
+ var CompleteLegalMemberSchema = z22.object({ token: z22.string().min(1) });
2089
+ var LegalNameOptionSchema = z22.object({ name: z22.string().min(1).max(200), ending: z22.literal("LLC") });
2090
+ var LegalMailingAddressSchema = z22.object({
2091
+ line1: z22.string().min(1).max(200),
2092
+ line2: z22.string().max(200).nullable(),
2093
+ city: z22.string().min(1).max(100),
2094
+ state: UsStateSchema,
2095
+ postal_code: z22.string().min(1).max(16),
2096
+ country: z22.literal("US")
2097
+ });
2098
+ var LegalRequiredActionSchema = z22.object({
2099
+ kind: LegalRequiredActionKindSchema,
2100
+ description: z22.string(),
2101
+ url: z22.url().nullable()
2102
+ });
2103
+ var LEGAL_DESCRIPTION_MAX = 50;
2104
+ var CreateLegalCompanySchema = z22.object({
2105
+ verification_id: idOf("lgv"),
2106
+ state: UsStateSchema,
2107
+ name_options: z22.array(z22.string().min(1).max(200)).min(1).max(3),
2108
+ naics_code: z22.string().regex(/^\d{2,6}$/),
2109
+ description: z22.string().min(1).max(LEGAL_DESCRIPTION_MAX),
2110
+ mailing_address: LegalMailingAddressSchema
2111
+ });
2112
+ var LegalCompanySchema = CreateLegalCompanySchema.omit({ name_options: true }).extend({
2113
+ id: idOf("lgc"),
2114
+ object: z22.literal("legal_company"),
2115
+ identity_id: idOf("idn"),
2116
+ status: LegalCompanyStatusSchema,
2117
+ entity_type: z22.literal("llc"),
2118
+ name_options: z22.array(LegalNameOptionSchema),
2119
+ legal_name: z22.string().nullable(),
2120
+ ein_status: LegalEinStatusSchema,
2121
+ price_micro_usd: MicroUsdField,
2122
+ required_actions: z22.array(LegalRequiredActionSchema),
2123
+ failure_reason: z22.string().max(256).nullable(),
2124
+ submitted_at: Timestamp.nullable(),
2125
+ formed_at: Timestamp.nullable(),
2126
+ created_at: Timestamp,
2127
+ updated_at: Timestamp
2128
+ });
2129
+ var LegalDocumentSchema = z22.object({
2130
+ id: idOf("lgd"),
2131
+ object: z22.literal("legal_document"),
2132
+ company_id: idOf("lgc"),
2133
+ kind: LegalDocumentKindSchema,
2134
+ name: z22.string(),
2135
+ created_at: Timestamp
2136
+ });
2137
+ var LegalDocumentLinkSchema = z22.object({
2138
+ object: z22.literal("legal_document_link"),
2139
+ url: z22.url(),
2140
+ expires_at: Timestamp
2141
+ });
2142
+ var NaicsCodeSchema = z22.object({
2143
+ object: z22.literal("naics_code"),
2144
+ code: z22.string().regex(/^\d{2,6}$/),
2145
+ title: z22.string()
2146
+ });
2147
+ var LegalStateSchema = z22.object({
2148
+ object: z22.literal("legal_state"),
2149
+ code: UsStateSchema,
2150
+ name: z22.string(),
2151
+ formation_fee_micro_usd: MicroUsdField
2152
+ });
2153
+ var LegalWebhookEventSchema = z22.object({
2154
+ provider_session_ref: z22.string().min(1),
2155
+ status: z22.enum(["verified", "failed", "pending_review"]),
2156
+ metadata: Metadata
2157
+ });
2158
+ var LLC_ENDING = /\s*(?:,\s*)?(?:l\.?l\.?c\.?|limited\s+liability\s+company)\s*$/i;
2159
+ function canonicalName(raw) {
2160
+ const name = raw.replace(LLC_ENDING, "").trim();
2161
+ if (name.length === 0) throw new VettaError("validation_failed", "A company name is required", "name_options");
2162
+ return { name, ending: "LLC" };
2163
+ }
2164
+
2165
+ // ../core/src/schema/wallet.ts
2166
+ import { z as z23 } from "zod";
2167
+ var WALLET_NETWORKS = ["eip155:84532", "eip155:8453"];
2168
+ var WalletNetworkSchema = z23.enum(WALLET_NETWORKS);
2169
+ var DEFAULT_WALLET_NETWORK = "eip155:84532";
2170
+ var WalletSelectSchema = z23.object({ network: WalletNetworkSchema.optional() });
2171
+ var WALLET_STATUSES = ["active", "frozen", "swept"];
2172
+ var WalletStatusSchema = z23.enum(WALLET_STATUSES);
2173
+ var WALLET_TRANSACTION_KINDS = ["fund", "transfer", "pay", "sweep"];
2174
+ var WalletTransactionKindSchema = z23.enum(WALLET_TRANSACTION_KINDS);
2175
+ var WALLET_TRANSACTION_STATUSES = ["pending", "confirmed", "failed"];
2176
+ var WalletTransactionStatusSchema = z23.enum(WALLET_TRANSACTION_STATUSES);
2177
+ var WalletDirectionSchema = z23.enum(["in", "out"]);
2178
+ var WalletFundSourceSchema = z23.enum(["faucet", "treasury"]);
2179
+ var EvmAddressSchema = z23.string().regex(/^0x[0-9a-fA-F]{40}$/, "expected a 0x address");
2180
+ var TxHashSchema = z23.string().regex(/^0x[0-9a-fA-F]{64}$/, "expected a 0x transaction hash");
2181
+ var WalletPolicySchema = z23.object({
2182
+ per_tx_cap_micro_usd: MicroUsdField.nonnegative(),
2183
+ daily_cap_micro_usd: MicroUsdField.positive().nullable(),
2184
+ low_balance_micro_usd: MicroUsdField.nonnegative().nullable()
2185
+ });
2186
+ var WalletSchema = z23.object({
2187
+ id: idOf("wlt"),
2188
+ object: z23.literal("wallet"),
2189
+ identity_id: idOf("idn"),
2190
+ status: WalletStatusSchema,
2191
+ network: WalletNetworkSchema,
2192
+ address: EvmAddressSchema,
2193
+ asset: z23.literal("usdc"),
2194
+ balance_micro_usd: MicroUsdField,
2195
+ policy: WalletPolicySchema,
2196
+ spent_today_micro_usd: MicroUsdField,
2197
+ created_at: Timestamp,
2198
+ updated_at: Timestamp
2199
+ });
2200
+ var CreateWalletSchema = z23.object({
2201
+ network: WalletNetworkSchema.optional(),
2202
+ policy: WalletPolicySchema.partial().optional()
2203
+ });
2204
+ var UpdateWalletPolicySchema = WalletPolicySchema.partial();
2205
+ var FundWalletSchema = z23.object({
2206
+ amount_micro_usd: MicroUsdField.positive(),
2207
+ source: WalletFundSourceSchema
2208
+ });
2209
+ var TransferWalletSchema = z23.object({
2210
+ to: z23.union([EvmAddressSchema, idOf("idn")]),
2211
+ amount_micro_usd: MicroUsdField.positive(),
2212
+ purpose: z23.string().min(1).max(256)
2213
+ });
2214
+ var SweepWalletSchema = z23.object({ to: EvmAddressSchema.optional() });
2215
+ var WalletTransactionSchema = z23.object({
2216
+ id: idOf("wtx"),
2217
+ object: z23.literal("wallet_transaction"),
2218
+ wallet_id: idOf("wlt"),
2219
+ kind: WalletTransactionKindSchema,
2220
+ direction: WalletDirectionSchema,
2221
+ amount_micro_usd: MicroUsdField,
2222
+ counterparty: z23.string().nullable(),
2223
+ origin: z23.string().nullable(),
2224
+ purpose: z23.string().nullable(),
2225
+ tx_hash: TxHashSchema.nullable(),
2226
+ session_id: idOf("ses").nullable(),
2227
+ status: WalletTransactionStatusSchema,
2228
+ created_at: Timestamp
2229
+ });
2230
+ var ListWalletTransactionsSchema = z23.object({
2231
+ kind: WalletTransactionKindSchema.optional(),
2232
+ direction: WalletDirectionSchema.optional(),
2233
+ origin: z23.string().optional(),
2234
+ since: Timestamp.optional()
2235
+ });
2236
+ var HttpMethodSchema = z23.enum(["GET", "POST", "PUT", "PATCH", "DELETE"]);
2237
+ var WalletQuoteRequestSchema = z23.object({ url: z23.url(), method: HttpMethodSchema.optional() });
2238
+ var WalletQuoteSchema = z23.object({
2239
+ object: z23.literal("wallet_quote"),
2240
+ url: z23.url(),
2241
+ payable: z23.boolean(),
2242
+ network: WalletNetworkSchema.nullable(),
2243
+ asset: z23.literal("usdc").nullable(),
2244
+ amount_micro_usd: MicroUsdField.nullable(),
2245
+ pay_to: EvmAddressSchema.nullable(),
2246
+ description: z23.string().nullable(),
2247
+ max_timeout_seconds: z23.number().int().nullable()
2248
+ });
2249
+ var WalletPayRequestSchema = WalletQuoteRequestSchema.extend({
2250
+ max_amount_micro_usd: MicroUsdField.positive().optional()
2251
+ });
2252
+ var WALLET_RESPONSE_BODY_MAX = 64 * 1024;
2253
+ var WalletPaymentSchema = z23.object({
2254
+ object: z23.literal("wallet_payment"),
2255
+ paid: z23.boolean(),
2256
+ transaction_id: idOf("wtx").nullable(),
2257
+ amount_micro_usd: MicroUsdField.nullable(),
2258
+ response_status: z23.number().int(),
2259
+ response_body: z23.string().max(WALLET_RESPONSE_BODY_MAX)
2260
+ });
2261
+
2262
+ // ../core/src/schema/cards.ts
2263
+ import { z as z24 } from "zod";
2264
+ var CARD_STATUSES = ["pending_payment", "issuing", "active", "failed", "cancelled", "refunded"];
2265
+ var CardStatusSchema = z24.enum(CARD_STATUSES);
2266
+ var CARD_MIN_LOAD_MICRO_USD = 1e6;
2267
+ var CARD_MAX_LOAD_MICRO_USD = 15e7;
2268
+ var CARD_LOAD_GRANULARITY_MICRO_USD = 1e4;
2269
+ var CardSchema = z24.object({
2270
+ id: idOf("vcd"),
2271
+ object: z24.literal("card"),
2272
+ identity_id: idOf("idn"),
2273
+ kind: z24.literal("prepaid"),
2274
+ status: CardStatusSchema,
2275
+ label: z24.string().min(1).max(128),
2276
+ brand: z24.string().nullable(),
2277
+ last4: z24.string().regex(/^\d{4}$/).nullable(),
2278
+ load_micro_usd: MicroUsdField,
2279
+ spent_micro_usd: MicroUsdField,
2280
+ currency: z24.literal("usd"),
2281
+ expires_at: Timestamp.nullable(),
2282
+ failure_reason: z24.string().max(256).nullable(),
2283
+ created_at: Timestamp,
2284
+ updated_at: Timestamp
2285
+ });
2286
+ var IssueCardSchema = z24.object({
2287
+ label: CardSchema.shape.label,
2288
+ load_micro_usd: MicroUsdField.min(CARD_MIN_LOAD_MICRO_USD).max(CARD_MAX_LOAD_MICRO_USD).multipleOf(CARD_LOAD_GRANULARITY_MICRO_USD)
2289
+ });
2290
+ var CardQuoteRequestSchema = IssueCardSchema.pick({ load_micro_usd: true });
2291
+ var CardQuoteSchema = z24.object({
2292
+ object: z24.literal("card_quote"),
2293
+ load_micro_usd: MicroUsdField,
2294
+ price_micro_usd: MicroUsdField,
2295
+ brand: z24.string().nullable(),
2296
+ min_load_micro_usd: MicroUsdField,
2297
+ max_load_micro_usd: MicroUsdField
2298
+ });
2299
+ var CardCredentialsSchema = z24.object({
2300
+ object: z24.literal("card_credentials"),
2301
+ card_id: idOf("vcd"),
2302
+ number: z24.string().min(1),
2303
+ pin: z24.string().nullable(),
2304
+ cvv: z24.string().nullable(),
2305
+ expiry: z24.string().nullable(),
2306
+ url: z24.url().nullable(),
2307
+ instructions: z24.string().nullable(),
2308
+ revealed_at: Timestamp
2309
+ });
2310
+ var CardTransactionSchema = z24.object({
2311
+ id: idOf("vct"),
2312
+ object: z24.literal("card_transaction"),
2313
+ card_id: idOf("vcd"),
2314
+ amount_micro_usd: MicroUsdField,
2315
+ merchant: z24.string().nullable(),
2316
+ description: z24.string().nullable(),
2317
+ session_id: idOf("ses").nullable(),
2318
+ metadata: Metadata,
2319
+ created_at: Timestamp
2320
+ });
2321
+ var LogCardTransactionSchema = z24.object({
2322
+ amount_micro_usd: MicroUsdField.positive(),
2323
+ merchant: z24.string().max(256).optional(),
2324
+ description: z24.string().max(1024).optional(),
2325
+ metadata: Metadata.optional()
2326
+ });
2327
+ var ListCardsSchema = z24.object({ status: CardStatusSchema.optional() });
2328
+
2329
+ // src/define.ts
2330
+ import { z as z27 } from "zod";
2331
+
2332
+ // src/roster.ts
2333
+ import { z as z26 } from "zod";
2334
+
2335
+ // src/report.ts
2336
+ import { ApiError, send } from "@usenaive-sdk/vetta";
2337
+ import { z as z25 } from "zod";
2338
+ function message(error) {
2339
+ return error instanceof Error ? error.message : String(error);
2340
+ }
2341
+ async function line(name, work) {
2342
+ try {
2343
+ return await work();
2344
+ } catch (error) {
2345
+ return { name, action: "refused", reason: message(error) };
2346
+ }
2347
+ }
2348
+ var AT_ONCE = 6;
2349
+ async function eachInFlight(items, work) {
2350
+ const out = [];
2351
+ for (let at = 0; at < items.length; at += AT_ONCE) {
2352
+ out.push(...await Promise.all(items.slice(at, at + AT_ONCE).map(work)));
2353
+ }
2354
+ return out;
2355
+ }
2356
+ async function attempt(into, name, work) {
2357
+ const one = await line(name, work);
2358
+ into.push(one);
2359
+ return one;
2360
+ }
2361
+ var canonical = (value) => {
2362
+ if (Array.isArray(value)) return value.map(canonical);
2363
+ if (value === null || typeof value !== "object") return value;
2364
+ return Object.fromEntries(
2365
+ Object.keys(value).sort().map((key) => [key, canonical(value[key])])
2366
+ );
2367
+ };
2368
+ var changed = (declared, live) => declared !== void 0 && JSON.stringify(canonical(declared)) !== JSON.stringify(canonical(live));
2369
+ async function absent(work) {
2370
+ try {
2371
+ return await work;
2372
+ } catch (error) {
2373
+ if (error instanceof ApiError && error.status === 404) return null;
2374
+ throw error;
2375
+ }
2376
+ }
2377
+ var PageShape = z25.object({
2378
+ data: z25.array(z25.unknown()),
2379
+ has_more: z25.boolean(),
2380
+ next_cursor: z25.string().nullable()
1076
2381
  });
2382
+ function rowLabel(row) {
2383
+ const { object, id } = row ?? {};
2384
+ const words = [object, id].filter((one) => typeof one === "string");
2385
+ return words.length > 0 ? words.join(" ") : "a row";
2386
+ }
2387
+ var why = (error) => error.issues.map((issue) => `${issue.path.join(".") || "(root)"}: ${issue.message}`).join("; ");
2388
+ async function listAll(config, path, item, skipped, query = {}) {
2389
+ const rows = [];
2390
+ let after;
2391
+ for (; ; ) {
2392
+ const response = await send(config, { method: "GET", path, query: { ...query, limit: 100, after } }, "application/json");
2393
+ const text = await response.text();
2394
+ if (!response.ok) throw new Error(`could not list ${path} (HTTP ${response.status})`);
2395
+ const body = PageShape.parse(JSON.parse(text));
2396
+ for (const row of body.data) {
2397
+ const parsed = item.safeParse(row);
2398
+ if (parsed.success) rows.push(parsed.data);
2399
+ else skipped.push(`${rowLabel(row)} in ${path} could not be read and was skipped: ${why(parsed.error)}`);
2400
+ }
2401
+ if (!body.has_more || body.next_cursor === null) return rows;
2402
+ after = body.next_cursor;
2403
+ }
2404
+ }
2405
+ async function tombstone(name, current, remove, dryRun) {
2406
+ if (!current) return { name, action: "unchanged", reason: "already absent" };
2407
+ if (!dryRun) await remove(current.id);
2408
+ return { name, action: "deleted", id: current.id };
2409
+ }
1077
2410
 
1078
- // src/define.ts
1079
- import { z as z16 } from "zod";
2411
+ // src/roster.ts
2412
+ var NAME = z26.string().min(1);
2413
+ var RosterNameSchema = z26.union([
2414
+ NAME.transform((name) => ({ type: "agent", name })),
2415
+ z26.object({ type: z26.literal("agent"), name: NAME, version: z26.number().int().positive().optional() }),
2416
+ z26.object({ type: z26.literal("self") }),
2417
+ z26.object({ type: z26.literal("advisor"), model: z26.string().min(1) })
2418
+ ]);
2419
+ var DeclMultiagentField = z26.union([
2420
+ z26.boolean(),
2421
+ z26.object({ ...MultiagentSchema.shape, agents: z26.array(RosterNameSchema).min(1).max(20) }),
2422
+ z26.null()
2423
+ ]);
2424
+ var hasRoster = (value) => typeof value === "object" && value !== null;
2425
+ var rosterNames = (roster) => roster.agents.flatMap((entry) => entry.type === "agent" ? [entry.name] : []);
2426
+ var teamWithoutRoster = (value) => hasRoster(value) ? void 0 : value;
2427
+ function unpinned(desired, live) {
2428
+ return {
2429
+ ...live,
2430
+ agents: live.agents.map((entry, i) => {
2431
+ const want = desired.agents[i];
2432
+ const pinned = want !== void 0 && "version" in want && want.version !== void 0;
2433
+ return entry.type === "agent" && !pinned ? { type: "agent", id: entry.id } : entry;
2434
+ })
2435
+ };
2436
+ }
2437
+ async function patchRoster(client, decl, roster, existing, ids, dryRun, lines) {
2438
+ const line2 = lines.find((one) => one.name === decl.name);
2439
+ if (line2 === void 0 || line2.action === "refused") return;
2440
+ const updated = () => {
2441
+ if (line2.action === "unchanged") line2.action = "updated";
2442
+ };
2443
+ const missing = rosterNames(roster).find((name) => !ids.has(name));
2444
+ if (missing !== void 0) {
2445
+ if (dryRun && lines.some((one) => one.name === missing && one.action === "created")) return updated();
2446
+ line2.action = "refused";
2447
+ line2.reason = `multiagent roster needs agent "${missing}", which was not provisioned in this run`;
2448
+ return;
2449
+ }
2450
+ const desired = {
2451
+ ...roster,
2452
+ agents: roster.agents.map(
2453
+ (entry) => entry.type === "agent" ? { type: "agent", id: ids.get(entry.name), ..."version" in entry && entry.version !== void 0 ? { version: entry.version } : {} } : entry
2454
+ )
2455
+ };
2456
+ const current = existing.find((agent) => agent.name === decl.name);
2457
+ const live = current === void 0 ? null : normaliseMultiagent(current.multiagent);
2458
+ if (live !== null && !changed(desired, unpinned(desired, live))) return;
2459
+ if (!dryRun && line2.id !== void 0) {
2460
+ try {
2461
+ await client.agents.update(line2.id, { multiagent: desired });
2462
+ } catch (error) {
2463
+ line2.action = "refused";
2464
+ line2.reason = error instanceof Error ? error.message : String(error);
2465
+ return;
2466
+ }
2467
+ }
2468
+ updated();
2469
+ }
1080
2470
 
1081
2471
  // src/template.ts
1082
2472
  var BLUEPRINTS = {
1083
2473
  /** Clients, pipeline, deliverables, calendar. */
1084
2474
  agency: { templates: ["blank", "seo-geo"], default: "blank" },
1085
2475
  /** Post queue, accounts, calendar, analytics. */
1086
- media: { templates: ["faceless", "clipping"] }
2476
+ media: { templates: ["faceless", "clipping"] },
2477
+ /** Pages, posts, forms, analytics — a published site with a crew behind it (`usenaive/web-blueprint`). */
2478
+ web: { templates: ["publisher"], default: "publisher" }
1087
2479
  };
1088
2480
  var list = (names) => names.join(", ");
1089
2481
  function chooseTemplate(blueprint, template) {
@@ -1115,47 +2507,67 @@ function chooseTemplate(blueprint, template) {
1115
2507
  var BlueprintRefusal = class extends Error {
1116
2508
  name = "BlueprintRefusal";
1117
2509
  };
1118
- var EnvValueSchema = z16.union([
1119
- z16.string(),
1120
- z16.object({ from_env: z16.string().min(1) }),
1121
- z16.object({ generate: z16.literal(true) })
2510
+ var EnvValueSchema = z27.union([
2511
+ z27.string(),
2512
+ z27.object({ from_env: z27.string().min(1) }),
2513
+ z27.object({ generate: z27.literal(true) })
1122
2514
  ]);
1123
- var AppDeclSchema = z16.object({
2515
+ var AppDeclSchema = z27.object({
1124
2516
  /** Becomes a hostname, so the grammar is the platform's `APP_NAME` (a DNS label). */
1125
- name: z16.string().regex(APP_NAME, "a lowercase DNS label, 63 characters or fewer"),
2517
+ name: z27.string().regex(APP_NAME, "a lowercase DNS label, 63 characters or fewer"),
1126
2518
  type: AppTypeSchema,
1127
- description: z16.string().optional(),
2519
+ description: z27.string().optional(),
1128
2520
  /** A directory whose files are collected and shipped as the app's file-map deployment. */
1129
- deploy_dir: z16.string().min(1).optional(),
2521
+ deploy_dir: z27.string().min(1).optional(),
1130
2522
  /** The path the app itself serves MCP on (§29.5); `fullstack` only. Absent means none. */
1131
2523
  mcp: AppMcpPathSchema.optional(),
1132
2524
  /** Written as the app's write-only secrets (§29.2) on every apply; names follow the platform's `ENV_NAME`. */
1133
- env: z16.record(z16.string().regex(ENV_NAME), EnvValueSchema, { error: "keyed by environment variable name (A-Z, 0-9, _)" }).optional()
1134
- });
1135
- var ScheduleDeclSchema = z16.object({
1136
- cron: z16.string().min(1),
1137
- timezone: z16.string().min(1).optional(),
2525
+ env: z27.record(z27.string().regex(ENV_NAME), EnvValueSchema, { error: "keyed by environment variable name (A-Z, 0-9, _)" }).optional(),
2526
+ /** An install may not leave this app out of its `selection` (§31.2). Absent means it may. */
2527
+ required: z27.boolean().optional(),
2528
+ // core-gaps: U8-database
2529
+ /** SQL files applied in order to the app's database after it is provisioned (§37); `fullstack` only. */
2530
+ migrations: z27.array(z27.string().min(1)).optional(),
2531
+ // core-gaps: storage-stock
2532
+ /** Buckets the app's object store must hold (§38.2); `fullstack` only. `public` defaults to false. */
2533
+ buckets: z27.array(CreateBucketSchema).optional()
2534
+ });
2535
+ var ScheduleDeclSchema = z27.object({
2536
+ cron: z27.string().min(1),
2537
+ timezone: z27.string().min(1).optional(),
1138
2538
  /** The message every fire opens its session with (`input_template` on the wire). */
1139
- input: z16.string().min(1),
2539
+ input: z27.string().min(1),
1140
2540
  budget_micro_usd: MicroUsdField.nonnegative(),
1141
- identity: z16.string().min(1).optional(),
1142
- enabled: z16.boolean().optional()
2541
+ identity: z27.string().min(1).optional(),
2542
+ enabled: z27.boolean().optional()
1143
2543
  });
1144
- var AgentDeclSchema = z16.object({
1145
- name: z16.string().min(1),
1146
- model: z16.string().min(1),
2544
+ var ToolsDeclSchema = ToolsetSchema;
2545
+ var AgentDeclSchema = z27.object({
2546
+ name: z27.string().min(1),
2547
+ model: z27.string().min(1),
1147
2548
  budget: BudgetSchema,
1148
- description: z16.string().optional(),
1149
- system: z16.string().optional(),
1150
- tools: ToolsetSchema.optional(),
1151
- skills: z16.array(SkillRefSchema).optional(),
1152
- mcp_servers: z16.array(McpServerSchema).optional(),
2549
+ description: z27.string().optional(),
2550
+ /** Two or three words the studio prints beside the name (§31.5) — "Head of content", not a sentence. */
2551
+ role: z27.string().min(1).optional(),
2552
+ /** An install may not leave this agent out of its `selection` (§31.2). Absent means it may. */
2553
+ required: z27.boolean().optional(),
2554
+ system: z27.string().optional(),
2555
+ tools: ToolsDeclSchema.optional(),
2556
+ skills: z27.array(SkillRefSchema).optional(),
2557
+ mcp_servers: z27.array(McpServerSchema).optional(),
2558
+ /** The rest of the runtime's agent config (§31.6), each the core schema; absent means the route's default and never drift. */
2559
+ window: WindowSchema.optional(),
2560
+ /** A roster names crew members by declared *name*; `up` resolves them to `agt_` ids in a second pass (`roster.ts`). */
2561
+ multiagent: DeclMultiagentField.optional(),
2562
+ output_schema: JsonSchemaDocument.nullable().optional(),
2563
+ structured_output_required: z27.boolean().optional(),
2564
+ metadata: Metadata.optional(),
1153
2565
  /** Declared app *names*; `up` resolves them to `app_` ids in `tools.configs.apps` (§29.3). */
1154
- allowed_apps: z16.array(z16.string()).optional(),
2566
+ allowed_apps: z27.array(z27.string()).optional(),
1155
2567
  /** A declared identity *name*; `up` attaches it after the agent upsert (§22). */
1156
- identity: z16.string().min(1).optional(),
2568
+ identity: z27.string().min(1).optional(),
1157
2569
  /** The agent's deployments as a complete set: declared → owned, and the rest are pruned (ADR-0355). */
1158
- schedules: z16.array(ScheduleDeclSchema).optional(),
2570
+ schedules: z27.array(ScheduleDeclSchema).optional(),
1159
2571
  /**
1160
2572
  * The first thing this agent reads, once, on the apply that **creates** it (`canonical-spec
1161
2573
  * §31.4`). It is what turns a provisioned crew into a crew that has started working.
@@ -1168,43 +2580,58 @@ var AgentDeclSchema = z16.object({
1168
2580
  * repeatedly and unattended while an intake spends once, at an apply a person is watching. Absent
1169
2581
  * means the agent's own `budget` governs.
1170
2582
  */
1171
- intake: z16.object({ message: z16.string().min(1), budget_micro_usd: MicroUsdField.nonnegative().optional() }).optional()
2583
+ intake: z27.object({ message: z27.string().min(1), budget_micro_usd: MicroUsdField.nonnegative().optional() }).optional()
1172
2584
  });
1173
- var CredentialDeclSchema = z16.object({
2585
+ var CredentialDeclSchema = z27.object({
1174
2586
  kind: VaultCredentialKindSchema,
1175
- key: z16.string().min(1).max(128),
2587
+ key: z27.string().min(1).max(128),
1176
2588
  /** The one exact destination host an `env_var` is bound to. */
1177
- host: z16.string().min(1).optional(),
2589
+ host: z27.string().min(1).optional(),
1178
2590
  /** The MCP server URL a `static_bearer` / `mcp_oauth` token is matched to. */
1179
- mcp_server_url: z16.url().optional(),
1180
- value: z16.object({ from_env: z16.string().min(1) })
2591
+ mcp_server_url: z27.url().optional(),
2592
+ value: z27.object({ from_env: z27.string().min(1) })
1181
2593
  });
1182
- var VaultDeclSchema = z16.object({
2594
+ var VaultDeclSchema = z27.object({
1183
2595
  name: VaultSchema.shape.display_name,
1184
- identity: z16.string().min(1).optional(),
1185
- credentials: z16.array(CredentialDeclSchema)
2596
+ identity: z27.string().min(1).optional(),
2597
+ credentials: z27.array(CredentialDeclSchema)
1186
2598
  });
1187
- var SkillDeclSchema = z16.object({
1188
- slug: z16.string().regex(/^[a-z0-9][a-z0-9-]*$/, "lowercase letters, digits and dashes"),
1189
- file: z16.string().min(1)
2599
+ var SkillDeclSchema = z27.object({
2600
+ slug: z27.string().regex(/^[a-z0-9][a-z0-9-]*$/, "lowercase letters, digits and dashes"),
2601
+ file: z27.string().min(1)
1190
2602
  });
1191
- var IdentityDeclSchema = IdentitySchema.pick({ name: true, description: true }).partial({
2603
+ var LegalDeclSchema = CreateLegalCompanySchema.pick({
2604
+ state: true,
2605
+ name_options: true,
2606
+ naics_code: true,
1192
2607
  description: true
1193
- });
1194
- var RemovedSchema = z16.object({
1195
- apps: z16.array(z16.string().min(1)).default([]),
1196
- agents: z16.array(z16.string().min(1)).default([]),
1197
- skills: z16.array(z16.string().min(1)).default([]),
1198
- identities: z16.array(z16.string().min(1)).default([]),
1199
- vaults: z16.array(z16.string().min(1)).default([])
1200
- });
1201
- var KeptSchema = z16.object({ agents: z16.array(z16.string().min(1)).default([]) });
1202
- var ProjectSchema = z16.object({
1203
- name: z16.string().min(1),
2608
+ }).extend({ label: z27.string().min(1).max(128) });
2609
+ var WalletDeclSchema = CreateWalletSchema.or(
2610
+ z27.array(CreateWalletSchema).refine(
2611
+ (list2) => new Set(list2.map((w) => w.network ?? DEFAULT_WALLET_NETWORK)).size === list2.length,
2612
+ { message: "one wallet per network" }
2613
+ )
2614
+ );
2615
+ var CardDeclSchema = IssueCardSchema;
2616
+ var IdentityDeclSchema = IdentitySchema.pick({ name: true, description: true }).partial({ description: true }).extend({
2617
+ legal: z27.array(LegalDeclSchema).optional(),
2618
+ wallet: WalletDeclSchema.optional(),
2619
+ cards: z27.array(CardDeclSchema).optional()
2620
+ });
2621
+ var RemovedSchema = z27.object({
2622
+ apps: z27.array(z27.string().min(1)).default([]),
2623
+ agents: z27.array(z27.string().min(1)).default([]),
2624
+ skills: z27.array(z27.string().min(1)).default([]),
2625
+ identities: z27.array(z27.string().min(1)).default([]),
2626
+ vaults: z27.array(z27.string().min(1)).default([])
2627
+ });
2628
+ var KeptSchema = z27.object({ agents: z27.array(z27.string().min(1)).default([]) });
2629
+ var ProjectSchema = z27.object({
2630
+ name: z27.string().min(1),
1204
2631
  /** The machine this project runs: its repo, its screens, its `/api/*` (`template.ts`). */
1205
- blueprint: z16.string().min(1).optional(),
2632
+ blueprint: z27.string().min(1).optional(),
1206
2633
  /** Which of that blueprint's templates provides the crew; a blueprint with a default may omit it. */
1207
- template: z16.string().min(1).optional(),
2634
+ template: z27.string().min(1).optional(),
1208
2635
  /**
1209
2636
  * What a person is asked BEFORE the crew is provisioned (`canonical-spec §31.2`).
1210
2637
  *
@@ -1216,12 +2643,19 @@ var ProjectSchema = z16.object({
1216
2643
  *
1217
2644
  * **Configuration only.** A secret is a vault credential or an app secret; neither is an answer.
1218
2645
  */
1219
- questions: z16.array(QuestionFieldSchema).default([]),
1220
- skills: z16.array(SkillDeclSchema).default([]),
1221
- identities: z16.array(IdentityDeclSchema).default([]),
1222
- vaults: z16.array(VaultDeclSchema).default([]),
1223
- apps: z16.array(AppDeclSchema).default([]),
1224
- agents: z16.array(AgentDeclSchema).default([]),
2646
+ questions: z27.array(QuestionFieldSchema).default([]),
2647
+ skills: z27.array(SkillDeclSchema).default([]),
2648
+ identities: z27.array(IdentityDeclSchema).default([]),
2649
+ vaults: z27.array(VaultDeclSchema).default([]),
2650
+ apps: z27.array(AppDeclSchema).default([]),
2651
+ agents: z27.array(AgentDeclSchema).default([]),
2652
+ /**
2653
+ * The agents this template creates PER CLIENT the operator signs (`canonical-spec §31.1`) —
2654
+ * printed on the artifact so a person sees the whole company, never provisioned by an apply,
2655
+ * because the apply does not know the clients yet. Names only: a model and a budget are the
2656
+ * crew's business at the moment a client is signed, not the declaration's.
2657
+ */
2658
+ crew_per_client: z27.array(z27.object({ name: z27.string().min(1), role: z27.string().min(1).optional(), description: z27.string().optional() })).optional(),
1225
2659
  removed: RemovedSchema.default({ apps: [], agents: [], skills: [], identities: [], vaults: [] }),
1226
2660
  kept: KeptSchema.default({ agents: [] })
1227
2661
  });
@@ -1252,11 +2686,19 @@ function applyChoice(config) {
1252
2686
  function parseProject(input) {
1253
2687
  const parsed = ProjectSchema.safeParse(input);
1254
2688
  if (!parsed.success) {
1255
- const lines = parsed.error.issues.map((i) => `${i.path.join(".") || "config"}: ${i.message}`);
2689
+ const unwrap = (i) => {
2690
+ if (i.code !== "invalid_union") return [i];
2691
+ const branch = i.errors.find((b) => !b.some((e) => e.code === "invalid_type" && e.path.length === 0));
2692
+ return branch ? branch.map((e) => ({ ...e, path: [...i.path, ...e.path] })) : [i];
2693
+ };
2694
+ const lines = parsed.error.issues.flatMap(unwrap).map((i) => `${i.path.join(".") || "config"}: ${i.message}`);
1256
2695
  refuse(`invalid project config \u2014 ${lines.join("; ")}`);
1257
2696
  }
1258
2697
  const config = parsed.data;
1259
2698
  applyChoice(config);
2699
+ if (config.template !== void 0 && config.questions.length > 3) {
2700
+ refuse(`template "${config.template}" asks ${config.questions.length} questions, but a template asks at most 3 before anything is provisioned \u2014 a fourth belongs to the crew's first conversation`);
2701
+ }
1260
2702
  assertUniqueNames("app", [...config.apps.map((a) => a.name), ...config.removed.apps]);
1261
2703
  assertUniqueNames("agent", [...config.agents.map((a) => a.name), ...config.removed.agents, ...config.kept.agents]);
1262
2704
  assertUniqueNames("skill", [...config.skills.map((s) => s.slug), ...config.removed.skills]);
@@ -1267,6 +2709,13 @@ function parseProject(input) {
1267
2709
  if (app.type === "frontend_only" && app.mcp !== void 0) {
1268
2710
  refuse(`app "${app.name}": mcp is set, but a frontend_only app has no server to answer on it \u2014 declare type "fullstack" or drop mcp`);
1269
2711
  }
2712
+ if (app.type === "frontend_only" && app.migrations !== void 0) {
2713
+ refuse(`app "${app.name}": migrations are set, but a frontend_only app has no database \u2014 declare type "fullstack" or drop migrations`);
2714
+ }
2715
+ if (app.type === "frontend_only" && app.buckets !== void 0) {
2716
+ refuse(`app "${app.name}": buckets are set, but a frontend_only app has no object store \u2014 declare type "fullstack" or drop buckets`);
2717
+ }
2718
+ assertUniqueNames("bucket", (app.buckets ?? []).map((bucket) => bucket.name));
1270
2719
  }
1271
2720
  const identityNames = new Set(config.identities.map((i) => i.name));
1272
2721
  for (const vault of config.vaults) {
@@ -1287,7 +2736,16 @@ function parseProject(input) {
1287
2736
  seen.add(at);
1288
2737
  }
1289
2738
  }
2739
+ const agentNames = /* @__PURE__ */ new Set([...config.agents.map((a) => a.name), ...config.kept.agents]);
1290
2740
  for (const agent of config.agents) {
2741
+ const rostered = /* @__PURE__ */ new Set();
2742
+ for (const name of hasRoster(agent.multiagent) ? rosterNames(agent.multiagent) : []) {
2743
+ if (name === agent.name) refuse(`agent "${agent.name}": multiagent roster names itself \u2014 a coordinator delegates to a copy of itself with { type: "self" }`);
2744
+ if (config.removed.agents.includes(name)) refuse(`agent "${agent.name}": multiagent roster names "${name}", which this config removes \u2014 drop it from the roster or keep the agent`);
2745
+ if (!agentNames.has(name)) refuse(`agent "${agent.name}": multiagent roster names "${name}", but no agent with that name is declared in this project`);
2746
+ if (rostered.has(name)) refuse(`agent "${agent.name}": multiagent roster names "${name}" twice \u2014 a team names each member once`);
2747
+ rostered.add(name);
2748
+ }
1291
2749
  for (const name of agent.allowed_apps ?? []) {
1292
2750
  if (!appNames.has(name)) {
1293
2751
  refuse(`agent "${agent.name}": allowed_apps names "${name}", but no app with that name is declared in this project`);
@@ -1345,7 +2803,7 @@ function isMissingModule(error) {
1345
2803
  const code = error?.code;
1346
2804
  return code === "ERR_MODULE_NOT_FOUND" || code === "MODULE_NOT_FOUND";
1347
2805
  }
1348
- function message(error) {
2806
+ function message2(error) {
1349
2807
  return error instanceof Error ? error.message : String(error);
1350
2808
  }
1351
2809
  function validate(path, raw) {
@@ -1369,7 +2827,7 @@ async function loadConfig(dir) {
1369
2827
  try {
1370
2828
  return validate(path, JSON.parse(readFileSync(path, "utf8")));
1371
2829
  } catch (error) {
1372
- if (error instanceof SyntaxError) return { ok: false, reason: "invalid", message: message(error) };
2830
+ if (error instanceof SyntaxError) return { ok: false, reason: "invalid", message: message2(error) };
1373
2831
  throw error;
1374
2832
  }
1375
2833
  }
@@ -1378,14 +2836,14 @@ async function loadConfig(dir) {
1378
2836
  const { createJiti } = await import("jiti");
1379
2837
  importFile = createJiti(pathToFileURL(path).href).import;
1380
2838
  } catch (error) {
1381
- return { ok: false, reason: "unloadable", message: message(error) };
2839
+ return { ok: false, reason: "unloadable", message: message2(error) };
1382
2840
  }
1383
2841
  let raw;
1384
2842
  try {
1385
2843
  const mod = await importFile(path);
1386
2844
  raw = mod?.default ?? mod;
1387
2845
  } catch (error) {
1388
- return { ok: false, reason: isMissingModule(error) ? "unloadable" : "invalid", message: message(error) };
2846
+ return { ok: false, reason: isMissingModule(error) ? "unloadable" : "invalid", message: message2(error) };
1389
2847
  }
1390
2848
  if (raw === null || typeof raw !== "object") {
1391
2849
  return {
@@ -1441,76 +2899,28 @@ function contentHash(files) {
1441
2899
 
1442
2900
  // src/up.ts
1443
2901
  import { createHash as createHash3 } from "node:crypto";
1444
- import { readFileSync as readFileSync3 } from "node:fs";
1445
- import { resolve as resolve3 } from "node:path";
2902
+ import { readFileSync as readFileSync4 } from "node:fs";
2903
+ import { resolve as resolve4 } from "node:path";
1446
2904
 
1447
- // src/report.ts
1448
- import { ApiError, send } from "@usenaive-sdk/vetta";
1449
- import { z as z17 } from "zod";
1450
- function message2(error) {
1451
- return error instanceof Error ? error.message : String(error);
1452
- }
1453
- async function attempt(into, name, work) {
1454
- let line;
1455
- try {
1456
- line = await work();
1457
- } catch (error) {
1458
- line = { name, action: "refused", reason: message2(error) };
1459
- }
1460
- into.push(line);
1461
- return line;
1462
- }
1463
- var canonical = (value) => {
1464
- if (Array.isArray(value)) return value.map(canonical);
1465
- if (value === null || typeof value !== "object") return value;
1466
- return Object.fromEntries(
1467
- Object.keys(value).sort().map((key) => [key, canonical(value[key])])
1468
- );
1469
- };
1470
- var changed = (declared, live) => declared !== void 0 && JSON.stringify(canonical(declared)) !== JSON.stringify(canonical(live));
1471
- async function absent(work) {
1472
- try {
1473
- return await work;
1474
- } catch (error) {
1475
- if (error instanceof ApiError && error.status === 404) return null;
1476
- throw error;
1477
- }
1478
- }
1479
- var PageShape = z17.object({
1480
- data: z17.array(z17.unknown()),
1481
- has_more: z17.boolean(),
1482
- next_cursor: z17.string().nullable()
1483
- });
1484
- function rowLabel(row) {
1485
- const { object, id } = row ?? {};
1486
- const words = [object, id].filter((one) => typeof one === "string");
1487
- return words.length > 0 ? words.join(" ") : "a row";
1488
- }
1489
- var why = (error) => error.issues.map((issue) => `${issue.path.join(".") || "(root)"}: ${issue.message}`).join("; ");
1490
- async function listAll(config, path, item, skipped, query = {}) {
1491
- const rows = [];
1492
- let after;
1493
- for (; ; ) {
1494
- const response = await send(config, { method: "GET", path, query: { ...query, limit: 100, after } }, "application/json");
1495
- const text = await response.text();
1496
- if (!response.ok) throw new Error(`could not list ${path} (HTTP ${response.status})`);
1497
- const body = PageShape.parse(JSON.parse(text));
1498
- for (const row of body.data) {
1499
- const parsed = item.safeParse(row);
1500
- if (parsed.success) rows.push(parsed.data);
1501
- else skipped.push(`${rowLabel(row)} in ${path} could not be read and was skipped: ${why(parsed.error)}`);
1502
- }
1503
- if (!body.has_more || body.next_cursor === null) return rows;
1504
- after = body.next_cursor;
1505
- }
1506
- }
1507
- async function tombstone(name, current, remove, dryRun) {
1508
- if (!current) return { name, action: "unchanged", reason: "already absent" };
1509
- if (!dryRun) await remove(current.id);
1510
- return { name, action: "deleted", id: current.id };
2905
+ // src/agents.ts
2906
+ var PROJECT_CONTEXT_PREAMBLE = "Before anything else, read the project context with the `project_context` tool. The answers in it are the client's own \u2014 never invent, assume or restate them from memory; what the context does not say, you ask. Use the context's own words for the company, its offer and its audience.";
2907
+ function desiredMetadata(decl, of, current) {
2908
+ if (of.template === void 0) return decl.metadata;
2909
+ return {
2910
+ ...current?.metadata,
2911
+ ...decl.metadata,
2912
+ project: of.project,
2913
+ ...of.blueprint !== void 0 ? { blueprint: of.blueprint } : {},
2914
+ template: of.template,
2915
+ group: of.template
2916
+ };
1511
2917
  }
2918
+ function desiredSystem(decl, of) {
2919
+ if (of.template === void 0) return decl.system;
2920
+ return decl.system === void 0 ? PROJECT_CONTEXT_PREAMBLE : `${PROJECT_CONTEXT_PREAMBLE}
1512
2921
 
1513
- // src/agents.ts
2922
+ ${decl.system}`;
2923
+ }
1514
2924
  function desiredTools(decl, current, ids) {
1515
2925
  if (ids === void 0) return decl.tools;
1516
2926
  const base = decl.tools ?? current?.tools ?? { default_config: { permission: "allow" }, configs: {} };
@@ -1523,21 +2933,26 @@ function desiredTools(decl, current, ids) {
1523
2933
  }
1524
2934
  };
1525
2935
  }
1526
- async function createAgent(client, decl, tools, identityId) {
2936
+ async function createAgent(client, decl, tools, team, identityId, system, metadata) {
1527
2937
  const created = await client.agents.create({
1528
2938
  name: decl.name,
1529
2939
  model: decl.model,
1530
2940
  budget: decl.budget,
1531
2941
  ...decl.description !== void 0 ? { description: decl.description } : {},
1532
- ...decl.system !== void 0 ? { system: decl.system } : {},
2942
+ ...system !== void 0 ? { system } : {},
1533
2943
  ...decl.skills !== void 0 ? { skills: decl.skills } : {},
1534
2944
  ...decl.mcp_servers !== void 0 ? { mcp_servers: decl.mcp_servers } : {},
1535
- ...tools !== void 0 ? { tools } : {}
2945
+ ...tools !== void 0 ? { tools } : {},
2946
+ ...decl.window !== void 0 ? { window: decl.window } : {},
2947
+ ...team !== void 0 ? { multiagent: team } : {},
2948
+ ...decl.output_schema !== void 0 ? { output_schema: decl.output_schema } : {},
2949
+ ...decl.structured_output_required !== void 0 ? { structured_output_required: decl.structured_output_required } : {},
2950
+ ...metadata !== void 0 ? { metadata } : {}
1536
2951
  });
1537
2952
  if (identityId !== void 0) await client.identities.attach(created.id, identityId);
1538
2953
  return { name: decl.name, action: "created", id: created.id };
1539
2954
  }
1540
- async function upsertAgent(client, decl, existing, ids, dryRun, scoped) {
2955
+ async function upsertAgent(client, decl, existing, ids, dryRun, scoped, of) {
1541
2956
  const unresolved = (decl.allowed_apps ?? []).filter((name) => !ids.apps.has(name));
1542
2957
  const identityId = decl.identity === void 0 ? void 0 : ids.identities.get(decl.identity);
1543
2958
  const missing = unresolved.length > 0 ? `allowed_apps needs app "${unresolved[0]}"` : decl.identity !== void 0 && identityId === void 0 ? `identity needs "${decl.identity}"` : null;
@@ -1547,15 +2962,13 @@ async function upsertAgent(client, decl, existing, ids, dryRun, scoped) {
1547
2962
  const appIds = decl.allowed_apps !== void 0 ? decl.allowed_apps.flatMap((name) => ids.apps.get(name) ?? []) : scoped;
1548
2963
  const current = existing.find((agent) => agent.name === decl.name) ?? null;
1549
2964
  const tools = desiredTools(decl, current, appIds);
1550
- if (!current) return dryRun ? { name: decl.name, action: "created" } : createAgent(client, decl, tools, identityId);
1551
- const patch = {};
1552
- if (changed(decl.model, current.model)) patch.model = decl.model;
1553
- if (changed(decl.budget, current.budget)) patch.budget = decl.budget;
1554
- if (changed(decl.description, current.description)) patch.description = decl.description;
1555
- if (changed(decl.system, current.system)) patch.system = decl.system;
1556
- if (changed(decl.skills, current.skills)) patch.skills = decl.skills;
1557
- if (changed(decl.mcp_servers, current.mcp_servers)) patch.mcp_servers = decl.mcp_servers;
1558
- if (changed(tools, current.tools)) patch.tools = tools;
2965
+ const team = teamWithoutRoster(decl.multiagent);
2966
+ const system = desiredSystem(decl, of);
2967
+ const metadata = desiredMetadata(decl, of, current);
2968
+ if (!current) {
2969
+ return dryRun ? { name: decl.name, action: "created" } : createAgent(client, decl, tools, team, identityId, system, metadata);
2970
+ }
2971
+ const patch = drift(decl, current, tools, team, system, metadata);
1559
2972
  const held = identityId === void 0 ? [] : (await client.identities.held(current.id)).data;
1560
2973
  const grant = identityId === void 0 || held.some((one) => one.id === identityId) ? null : identityId;
1561
2974
  const drifted = Object.keys(patch).length > 0 || missing !== null || grant !== null;
@@ -1566,6 +2979,22 @@ async function upsertAgent(client, decl, existing, ids, dryRun, scoped) {
1566
2979
  }
1567
2980
  return { name: decl.name, action: "updated", id: current.id };
1568
2981
  }
2982
+ function drift(decl, current, tools, team, system, metadata) {
2983
+ const patch = {};
2984
+ if (changed(decl.model, current.model)) patch.model = decl.model;
2985
+ if (changed(decl.budget, current.budget)) patch.budget = decl.budget;
2986
+ if (changed(decl.description, current.description)) patch.description = decl.description;
2987
+ if (changed(system, current.system)) patch.system = system;
2988
+ if (changed(decl.skills, current.skills)) patch.skills = decl.skills;
2989
+ if (changed(decl.mcp_servers, current.mcp_servers)) patch.mcp_servers = decl.mcp_servers;
2990
+ if (changed(tools, current.tools)) patch.tools = tools;
2991
+ if (changed(decl.window, current.window)) patch.window = decl.window;
2992
+ if (team !== void 0 && changed(normaliseMultiagent(team), normaliseMultiagent(current.multiagent))) patch.multiagent = team;
2993
+ if (changed(decl.output_schema, current.output_schema)) patch.output_schema = decl.output_schema;
2994
+ if (changed(decl.structured_output_required, current.structured_output_required)) patch.structured_output_required = decl.structured_output_required;
2995
+ if (changed(metadata, current.metadata)) patch.metadata = metadata;
2996
+ return patch;
2997
+ }
1569
2998
  async function openIntake(client, agent, decl, dryRun) {
1570
2999
  if (dryRun || agent.id === void 0) return { name: agent.name, action: "created" };
1571
3000
  const started = await client.sessions.create({
@@ -1606,10 +3035,15 @@ async function upsertSchedule(client, agent, decl, current, identityIds, dryRun)
1606
3035
  }
1607
3036
  async function reconcileSchedules(client, agent, declared, live, identityIds, dryRun, into) {
1608
3037
  const rows = live.filter((row) => row.agent_id === agent.id);
1609
- for (const decl of declared) {
1610
- const current = rows.find((row) => row.cron === decl.cron);
1611
- await attempt(into, `${agent.name} @ ${decl.cron}`, () => upsertSchedule(client, agent, decl, current, identityIds, dryRun));
1612
- }
3038
+ into.push(
3039
+ ...await eachInFlight(
3040
+ declared,
3041
+ (decl) => line(
3042
+ `${agent.name} @ ${decl.cron}`,
3043
+ () => upsertSchedule(client, agent, decl, rows.find((row) => row.cron === decl.cron), identityIds, dryRun)
3044
+ )
3045
+ )
3046
+ );
1613
3047
  for (const row of rows.filter((row2) => !declared.some((decl) => decl.cron === row2.cron))) {
1614
3048
  const name = `${agent.name} @ ${row.cron}`;
1615
3049
  await attempt(into, name, () => tombstone(name, row, (id) => client.deployments.delete(id), dryRun));
@@ -1618,7 +3052,59 @@ async function reconcileSchedules(client, agent, declared, live, identityIds, dr
1618
3052
 
1619
3053
  // src/apps.ts
1620
3054
  import { createHash as createHash2, randomBytes } from "node:crypto";
1621
- import { resolve as resolve2 } from "node:path";
3055
+ import { resolve as resolve3 } from "node:path";
3056
+
3057
+ // src/buckets.ts
3058
+ async function applyBuckets(client, appId, buckets) {
3059
+ const live = new Set((await client.storage.buckets.list({ app: appId })).data.map((row) => row.name));
3060
+ const missing = buckets.filter((bucket) => !live.has(bucket.name));
3061
+ for (const bucket of missing) await client.storage.buckets.create(bucket.name, { app: appId, public: bucket.public });
3062
+ return { fresh: missing.length, note: `${buckets.length} bucket(s), ${missing.length} new` };
3063
+ }
3064
+
3065
+ // src/migrations.ts
3066
+ import { readFileSync as readFileSync3, readdirSync as readdirSync2 } from "node:fs";
3067
+ import { basename, dirname, extname, join as join3, resolve as resolve2 } from "node:path";
3068
+ function matcher(pattern) {
3069
+ const source = pattern.split("*").map((part) => part.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("[^/]*");
3070
+ const regex = new RegExp(`^${source}$`);
3071
+ return (name) => regex.test(name);
3072
+ }
3073
+ function migrationFiles(patterns, dir) {
3074
+ const seen = /* @__PURE__ */ new Set();
3075
+ const files = [];
3076
+ for (const pattern of patterns) {
3077
+ const full = resolve2(dir, pattern);
3078
+ const paths = pattern.includes("*") ? readdirSync2(dirname(full), { withFileTypes: true }).filter((entry) => entry.isFile() && matcher(basename(full))(entry.name)).map((entry) => join3(dirname(full), entry.name)).sort() : [full];
3079
+ if (paths.length === 0) throw new Error(`migrations "${pattern}" matches no file under ${dir}`);
3080
+ for (const path of paths) {
3081
+ const name = basename(path, extname(path));
3082
+ if (seen.has(name)) continue;
3083
+ seen.add(name);
3084
+ files.push({ name, sql: readFileSync3(path, "utf8") });
3085
+ }
3086
+ }
3087
+ return files;
3088
+ }
3089
+ function declaredMigrations(decl, opts) {
3090
+ if (decl.migrations === void 0) return [];
3091
+ if (opts.trees === void 0) return migrationFiles(decl.migrations, opts.dir);
3092
+ const published = opts.migrations?.[decl.name];
3093
+ if (published === void 0) {
3094
+ throw new Error(
3095
+ `app "${decl.name}" declares migrations, but this apply was handed no published SQL for it. Republish the artifact, or apply them with \`naive up\` from a clone.`
3096
+ );
3097
+ }
3098
+ return published;
3099
+ }
3100
+ async function applyMigrations(client, appId, files) {
3101
+ const applied2 = new Set((await client.database.migrations({ app: appId })).map((row) => row.name));
3102
+ for (const file of files) await client.database.migrate(file.name, file.sql, { app: appId });
3103
+ const fresh = files.filter((file) => !applied2.has(file.name)).length;
3104
+ return { fresh, note: `${files.length} migration(s), ${fresh} new` };
3105
+ }
3106
+
3107
+ // src/apps.ts
1622
3108
  async function findApp(client, name, skipped) {
1623
3109
  const rows = await listAll(client.config, "/v1/apps", AppSchema, skipped, { name });
1624
3110
  return rows.find((app) => app.name === name) ?? null;
@@ -1634,6 +3120,8 @@ var PLATFORM_ENV = {
1634
3120
  api_url: "NAIVE_API_URL",
1635
3121
  /** The identity the install runs as, when the declaration declares exactly one. */
1636
3122
  identity_id: "NAIVE_IDENTITY_ID",
3123
+ /** The install's `project` — the row the app's own context lookup lands on (§31.8). */
3124
+ project: "NAIVE_PROJECT",
1637
3125
  /** A scoped organization API key minted for the app that asks for it. */
1638
3126
  api_key: "NAIVE_API_KEY"
1639
3127
  };
@@ -1696,13 +3184,14 @@ function builtTree(decl, opts) {
1696
3184
  `app "${decl.name}" declares deploy_dir "${decl.deploy_dir}", but this apply was handed no built tree for it` + (failed === void 0 ? "" : `: ${failed}`)
1697
3185
  );
1698
3186
  }
1699
- const files = collectFiles(hosted?.[decl.name] ?? resolve2(opts.dir, decl.deploy_dir));
3187
+ const files = collectFiles(hosted?.[decl.name] ?? resolve3(opts.dir, decl.deploy_dir));
1700
3188
  return { files, hash: contentHash(files) };
1701
3189
  }
1702
3190
  async function writeApp(client, id, env, tree) {
1703
- for (const [name, value] of Object.entries(env)) {
1704
- await client.apps.setSecret(id, { name, value, value_hash: secretHash(name, value) });
1705
- }
3191
+ await eachInFlight(
3192
+ Object.entries(env),
3193
+ ([name, value]) => client.apps.setSecret(id, { name, value, value_hash: secretHash(name, value) })
3194
+ );
1706
3195
  if (!tree) return;
1707
3196
  await client.apps.deploy(id, tree.files, tree.hash);
1708
3197
  await settleDeploy(client, id);
@@ -1713,10 +3202,10 @@ async function settleDeploy(client, id) {
1713
3202
  for (let poll = 0; poll < SETTLE_TRIES; poll++) {
1714
3203
  const newest = (await client.apps.deployments(id, { limit: 1 })).data[0];
1715
3204
  if (newest === void 0 || newest.status === "ready" || newest.status === "error") return;
1716
- await new Promise((resolve4) => setTimeout(resolve4, SETTLE_MS));
3205
+ await new Promise((resolve5) => setTimeout(resolve5, SETTLE_MS));
1717
3206
  }
1718
3207
  }
1719
- async function createApp(client, decl, env, tree, opts, appIds) {
3208
+ async function createApp(client, decl, env, tree, migrations, opts, appIds) {
1720
3209
  const created = await ensureApp(client, {
1721
3210
  name: decl.name,
1722
3211
  type: decl.type,
@@ -1726,13 +3215,24 @@ async function createApp(client, decl, env, tree, opts, appIds) {
1726
3215
  });
1727
3216
  appIds.set(decl.name, created.id);
1728
3217
  await writeApp(client, created.id, env, tree);
1729
- return { name: decl.name, action: "created", id: created.id, url: (await client.apps.get(created.id)).url };
3218
+ const notes = [];
3219
+ if (migrations.length > 0) notes.push((await applyMigrations(client, created.id, migrations)).note);
3220
+ if (decl.buckets !== void 0) notes.push((await applyBuckets(client, created.id, decl.buckets)).note);
3221
+ return {
3222
+ name: decl.name,
3223
+ action: "created",
3224
+ id: created.id,
3225
+ url: (await client.apps.get(created.id)).url,
3226
+ ...notes.length > 0 ? { reason: notes.join("; ") } : {}
3227
+ };
1730
3228
  }
1731
3229
  async function upsertApp(client, decl, opts, appIds) {
1732
3230
  const declared = planEnv(decl, opts);
1733
3231
  const names = declared.map((one) => one.name);
1734
3232
  const note = (notes) => notes.length > 0 ? { reason: notes.join("; ") } : {};
1735
3233
  const mcpPlan = decl.mcp !== void 0 ? [`will set mcp ${decl.mcp}`] : [];
3234
+ const migrationPlan = decl.migrations !== void 0 ? [`will apply migrations ${decl.migrations.join(", ")}`] : [];
3235
+ const bucketPlan = decl.buckets !== void 0 ? [`will ensure buckets ${decl.buckets.map((one) => one.name).join(", ")}`] : [];
1736
3236
  const current = await findApp(client, decl.name, opts.skipped);
1737
3237
  if (!current) {
1738
3238
  const willSet = names.length > 0 ? [`will set ${names.join(", ")}`] : [];
@@ -1740,11 +3240,11 @@ async function upsertApp(client, decl, opts, appIds) {
1740
3240
  return {
1741
3241
  name: decl.name,
1742
3242
  action: "created",
1743
- ...note([...willSet, ...mcpPlan, ...decl.deploy_dir ? [`will deploy ${decl.deploy_dir}`] : []])
3243
+ ...note([...willSet, ...mcpPlan, ...decl.deploy_dir ? [`will deploy ${decl.deploy_dir}`] : [], ...migrationPlan, ...bucketPlan])
1744
3244
  };
1745
3245
  }
1746
3246
  const { values } = await materialize(declared, EMPTY, false);
1747
- return createApp(client, decl, values, builtTree(decl, opts), opts, appIds);
3247
+ return createApp(client, decl, values, builtTree(decl, opts), declaredMigrations(decl, opts), opts, appIds);
1748
3248
  }
1749
3249
  const owned = current.project === opts.project;
1750
3250
  if (!owned && !opts.adopt) {
@@ -1786,15 +3286,28 @@ async function upsertApp(client, decl, opts, appIds) {
1786
3286
  const tree = builtTree(decl, opts);
1787
3287
  const newest = tree ? (await client.apps.deployments(current.id, { limit: 1 })).data[0] : void 0;
1788
3288
  const stale = tree !== null && newest?.content_hash !== tree.hash;
1789
- const action = !owned || drifted || stale || staleNames.length > 0 ? "updated" : "unchanged";
3289
+ let action = !owned || drifted || stale || staleNames.length > 0 ? "updated" : "unchanged";
1790
3290
  const plan = opts.dryRun ? [
1791
3291
  ...staleNames.length > 0 ? [`will set ${staleNames.join(", ")}`] : [],
1792
3292
  ..."mcp" in patch ? patch.mcp === null ? ["will clear mcp"] : mcpPlan : [],
1793
- ...decl.deploy_dir ? [stale ? `will deploy ${decl.deploy_dir}` : `${decl.deploy_dir} unchanged`] : []
3293
+ ...decl.deploy_dir ? [stale ? `will deploy ${decl.deploy_dir}` : `${decl.deploy_dir} unchanged`] : [],
3294
+ ...migrationPlan,
3295
+ ...bucketPlan
1794
3296
  ] : [];
1795
3297
  if (!opts.dryRun) {
1796
3298
  if (drifted) await client.apps.update(current.id, { ...patch, project: opts.project });
1797
3299
  await writeApp(client, current.id, staleEnv, stale ? tree : null);
3300
+ const migrations = declaredMigrations(decl, opts);
3301
+ if (migrations.length > 0) {
3302
+ const { fresh, note: note2 } = await applyMigrations(client, current.id, migrations);
3303
+ if (fresh > 0) action = "updated";
3304
+ plan.push(note2);
3305
+ }
3306
+ if (decl.buckets !== void 0) {
3307
+ const { fresh, note: note2 } = await applyBuckets(client, current.id, decl.buckets);
3308
+ if (fresh > 0) action = "updated";
3309
+ plan.push(note2);
3310
+ }
1798
3311
  }
1799
3312
  return {
1800
3313
  name: decl.name,
@@ -1806,6 +3319,106 @@ async function upsertApp(client, decl, opts, appIds) {
1806
3319
  };
1807
3320
  }
1808
3321
 
3322
+ // src/reconcile-cards.ts
3323
+ var LIVE = /* @__PURE__ */ new Set(["pending_payment", "issuing", "active"]);
3324
+ var nameOf = (identity, decl) => `${identity} / card ${decl.label}`;
3325
+ async function upsertCard(client, identityId, decl, live, dryRun, name) {
3326
+ const current = live.find((card) => card.label === decl.label && LIVE.has(card.status));
3327
+ if (current) return { name, action: "unchanged", id: current.id };
3328
+ const spent = live.find((card) => card.label === decl.label);
3329
+ if (spent) {
3330
+ return { name, action: "refused", id: spent.id, reason: `a card labelled "${decl.label}" is ${spent.status}; issue a replacement by hand` };
3331
+ }
3332
+ if (dryRun) {
3333
+ const quote = await client.identities.cards.quote(identityId, { load_micro_usd: decl.load_micro_usd });
3334
+ const price = decimalStringFromMicro(microUsd(quote.price_micro_usd));
3335
+ return { name, action: "created", reason: `would debit ${price} USD of credits (${quote.price_micro_usd} micro-USD)` };
3336
+ }
3337
+ const issued = await client.identities.cards.issue(identityId, decl);
3338
+ return { name, action: "created", id: issued.id };
3339
+ }
3340
+ async function reconcileCards(client, identity, identityId, decls, dryRun, into, skipped) {
3341
+ if (decls.length === 0) return;
3342
+ if (identityId === void 0) {
3343
+ for (const decl of decls) {
3344
+ into.push(
3345
+ dryRun ? { name: nameOf(identity, decl), action: "created", reason: "quoted once the identity exists; issuing debits credits" } : { name: nameOf(identity, decl), action: "refused", reason: `identity "${identity}" was not provisioned in this run` }
3346
+ );
3347
+ }
3348
+ return;
3349
+ }
3350
+ const live = await listAll(client.config, `/v1/identities/${identityId}/cards`, CardSchema, skipped);
3351
+ for (const decl of decls) {
3352
+ const name = nameOf(identity, decl);
3353
+ await attempt(into, name, () => upsertCard(client, identityId, decl, live, dryRun, name));
3354
+ }
3355
+ }
3356
+
3357
+ // src/reconcile-legal.ts
3358
+ var FILE = "vetta identity legal form";
3359
+ var VERIFY = "vetta identity legal verify";
3360
+ function latest(cases) {
3361
+ return [...cases].sort((a, b) => b.created_at.localeCompare(a.created_at))[0];
3362
+ }
3363
+ function match(decl, companies) {
3364
+ const wanted = new Set(
3365
+ decl.name_options.map((raw) => canonicalName(raw).name)
3366
+ );
3367
+ return companies.find(
3368
+ (c) => c.state === decl.state && c.name_options.some((o) => wanted.has(o.name))
3369
+ );
3370
+ }
3371
+ function report(decl, company, verification) {
3372
+ const name = decl.label;
3373
+ if (company !== void 0) {
3374
+ const reason = company.status === "failed" ? `failed: ${company.failure_reason ?? "the filing was rejected"}` : company.status;
3375
+ return {
3376
+ name,
3377
+ action: company.status === "failed" ? "refused" : "unchanged",
3378
+ id: company.id,
3379
+ reason
3380
+ };
3381
+ }
3382
+ if (verification === void 0)
3383
+ return {
3384
+ name,
3385
+ action: "refused",
3386
+ reason: `no verification case \u2014 a person must start one with \`${VERIFY}\``
3387
+ };
3388
+ if (verification.status === "verified") {
3389
+ return {
3390
+ name,
3391
+ action: "refused",
3392
+ id: verification.id,
3393
+ reason: `verified; the fee is debited from credits, so a person files it with \`${FILE}\``
3394
+ };
3395
+ }
3396
+ return {
3397
+ name,
3398
+ action: "refused",
3399
+ id: verification.id,
3400
+ reason: `verification ${verification.status}; nothing to file yet`
3401
+ };
3402
+ }
3403
+ async function reportLegal(client, decls, identityId, skipped) {
3404
+ if (decls.length === 0) return [];
3405
+ if (identityId === void 0)
3406
+ return decls.map((decl) => report(decl, void 0, void 0));
3407
+ const base = `/v1/identities/${identityId}/legal`;
3408
+ const [companies, cases] = await Promise.all([
3409
+ listAll(client.config, `${base}/companies`, LegalCompanySchema, skipped),
3410
+ listAll(
3411
+ client.config,
3412
+ `${base}/verifications`,
3413
+ LegalVerificationSchema,
3414
+ skipped
3415
+ )
3416
+ ]);
3417
+ return decls.map(
3418
+ (decl) => report(decl, match(decl, companies), latest(cases))
3419
+ );
3420
+ }
3421
+
1809
3422
  // src/vaults.ts
1810
3423
  async function upsertVault(client, decl, existing, identityIds, dryRun) {
1811
3424
  const identityId = decl.identity === void 0 ? void 0 : identityIds.get(decl.identity);
@@ -1851,23 +3464,94 @@ async function upsertCredential(client, vault, decl, existing, dryRun, from) {
1851
3464
  return { name, action: "created", id: created.id };
1852
3465
  }
1853
3466
 
3467
+ // src/reconcile-wallet.ts
3468
+ var declaredPolicy = (decl, live) => Object.fromEntries(
3469
+ Object.entries(decl.policy ?? {}).filter(([key, value]) => value !== void 0 && changed(value, live[key]))
3470
+ );
3471
+ var walletName = (identity, decl) => decl.network === void 0 || decl.network === DEFAULT_WALLET_NETWORK ? `${identity} / wallet` : `${identity} / wallet ${decl.network}`;
3472
+ async function reconcileWallet(client, identity, decl, dryRun) {
3473
+ const name = walletName(identity.name, decl);
3474
+ const network = decl.network ?? DEFAULT_WALLET_NETWORK;
3475
+ if (identity.id === void 0) {
3476
+ if (dryRun) return { name, action: "created" };
3477
+ return { name, action: "refused", reason: `identity "${identity.name}" was not provisioned in this run` };
3478
+ }
3479
+ const current = await absent(client.identities.wallet.get(identity.id, { network }));
3480
+ if (!current) {
3481
+ if (dryRun) return { name, action: "created" };
3482
+ const created = await client.identities.wallet.create(identity.id, decl);
3483
+ return { name, action: "created", id: created.id };
3484
+ }
3485
+ const patch = declaredPolicy(decl, current.policy);
3486
+ if (Object.keys(patch).length === 0) return { name, action: "unchanged", id: current.id };
3487
+ if (current.status !== "active") {
3488
+ return { name, action: "refused", id: current.id, reason: `wallet is ${current.status}; unfreeze it on the platform before changing its policy` };
3489
+ }
3490
+ if (!dryRun) await client.identities.wallet.updatePolicy(identity.id, patch, { network });
3491
+ return { name, action: "updated", id: current.id };
3492
+ }
3493
+
1854
3494
  // src/up.ts
3495
+ var SERVING_TRIES = 90;
3496
+ var SERVING_MS = 2e3;
3497
+ async function awaitServing(addresses, probe) {
3498
+ await Promise.all(
3499
+ addresses.map(async (address) => {
3500
+ for (let poll = 0; poll < SERVING_TRIES; poll++) {
3501
+ try {
3502
+ const { status } = await probe(address, { method: "GET" });
3503
+ if (status < 500 && status !== 404) return;
3504
+ } catch {
3505
+ }
3506
+ await new Promise((resolve5) => setTimeout(resolve5, SERVING_MS));
3507
+ }
3508
+ })
3509
+ );
3510
+ }
3511
+ function selectCrew(config, select) {
3512
+ if (select === void 0) return { apps: config.apps, agents: config.agents, deselected: [] };
3513
+ const named = (kind, names) => names.map((name) => `${kind} "${name}"`);
3514
+ const unknown = [
3515
+ ...named("app", select.apps.filter((name) => !config.apps.some((decl) => decl.name === name))),
3516
+ ...named("agent", select.agents.filter((name) => !config.agents.some((decl) => decl.name === name)))
3517
+ ];
3518
+ if (unknown.length > 0) {
3519
+ throw new BlueprintRefusal(`selection names ${unknown.join(", ")}, which this declaration does not declare`);
3520
+ }
3521
+ const apps = config.apps.filter((decl) => select.apps.includes(decl.name));
3522
+ const agents = config.agents.filter((decl) => select.agents.includes(decl.name));
3523
+ const missing = [
3524
+ ...named("app", config.apps.filter((decl) => decl.required === true && !apps.includes(decl)).map((decl) => decl.name)),
3525
+ ...named("agent", config.agents.filter((decl) => decl.required === true && !agents.includes(decl)).map((decl) => decl.name))
3526
+ ];
3527
+ if (missing.length > 0) {
3528
+ throw new BlueprintRefusal(
3529
+ `selection leaves out ${missing.join(", ")}, which this template requires \u2014 ${missing.length === 1 ? "it" : "they"} cannot be deselected`
3530
+ );
3531
+ }
3532
+ const deselected = [
3533
+ ...config.apps.filter((decl) => !apps.includes(decl)).map((decl) => decl.name),
3534
+ ...config.agents.filter((decl) => !agents.includes(decl)).map((decl) => decl.name)
3535
+ ];
3536
+ return { apps, agents, deselected };
3537
+ }
1855
3538
  function identityEnv(config, ids) {
1856
3539
  if (config.identities.length !== 1) return {};
1857
3540
  const id = ids.get(config.identities[0].name);
1858
3541
  return id === void 0 ? {} : { [PLATFORM_ENV.identity_id]: id };
1859
3542
  }
1860
3543
  async function upsertSkill(client, decl, opts) {
1861
- if (opts.hosted) {
3544
+ const inline = opts.skills[decl.slug];
3545
+ if (opts.hosted && inline === void 0) {
1862
3546
  throw new Error(
1863
3547
  `skill "${decl.slug}" is declared as the file "${decl.file}", and a hosted apply has no checkout to read it from. Push it with \`naive up\` from a clone, or publish it as part of the blueprint.`
1864
3548
  );
1865
3549
  }
1866
- const content = readFileSync3(resolve3(opts.dir, decl.file), "utf8");
3550
+ const content = inline ?? readFileSync4(resolve4(opts.dir, decl.file), "utf8");
1867
3551
  const sha256 = createHash3("sha256").update(content).digest("hex");
1868
3552
  const current = await absent(client.skills.get(decl.slug));
1869
- const latest = current ? (await client.skills.listVersions(decl.slug, { limit: 1 })).data[0] : void 0;
1870
- const action = !current ? "created" : latest?.sha256 === sha256 ? "unchanged" : "updated";
3553
+ const latest2 = current ? (await client.skills.listVersions(decl.slug, { limit: 1 })).data[0] : void 0;
3554
+ const action = !current ? "created" : latest2?.sha256 === sha256 ? "unchanged" : "updated";
1871
3555
  if (action === "unchanged" || opts.dryRun) {
1872
3556
  return { name: decl.slug, action, ...current ? { id: current.id } : {} };
1873
3557
  }
@@ -1890,14 +3574,14 @@ async function upsertIdentity(client, decl, dryRun, identityIds) {
1890
3574
  if (drifted && !dryRun) await client.identities.update(current.id, { description: decl.description ?? null });
1891
3575
  return { name: decl.name, action: drifted ? "updated" : "unchanged", id: current.id };
1892
3576
  }
1893
- async function applyRemoved(client, removed, live, owner, report) {
1894
- const dryRun = report.dry_run;
3577
+ async function applyRemoved(client, removed, live, owner, report2) {
3578
+ const dryRun = report2.dry_run;
1895
3579
  for (const name of removed.agents) {
1896
3580
  const current = live.agents.find((agent) => agent.name === name);
1897
- await attempt(report.agents, name, () => tombstone(name, current, (id) => client.agents.delete(id), dryRun));
3581
+ await attempt(report2.agents, name, () => tombstone(name, current, (id) => client.agents.delete(id), dryRun));
1898
3582
  }
1899
3583
  for (const name of removed.apps) {
1900
- await attempt(report.apps, name, async () => {
3584
+ await attempt(report2.apps, name, async () => {
1901
3585
  const current = await findApp(client, name, owner.skipped);
1902
3586
  if (current !== null && current.project !== owner.project && !owner.adopt) {
1903
3587
  return { name, action: "refused", id: current.id, reason: ownershipRefusal(name, owner.project, current.project) };
@@ -1907,18 +3591,18 @@ async function applyRemoved(client, removed, live, owner, report) {
1907
3591
  }
1908
3592
  for (const slug of removed.skills) {
1909
3593
  await attempt(
1910
- report.skills,
3594
+ report2.skills,
1911
3595
  slug,
1912
3596
  async () => tombstone(slug, await absent(client.skills.get(slug)), (id) => client.skills.delete(id), dryRun)
1913
3597
  );
1914
3598
  }
1915
3599
  for (const name of removed.vaults) {
1916
3600
  const current = live.vaults.find((vault) => vault.display_name === name);
1917
- await attempt(report.vaults, name, () => tombstone(name, current, (id) => client.vaults.delete(id), dryRun));
3601
+ await attempt(report2.vaults, name, () => tombstone(name, current, (id) => client.vaults.delete(id), dryRun));
1918
3602
  }
1919
3603
  for (const name of removed.identities) {
1920
3604
  await attempt(
1921
- report.identities,
3605
+ report2.identities,
1922
3606
  name,
1923
3607
  async () => tombstone(name, await absent(client.identities.get(name)), (id) => client.identities.delete(id), dryRun)
1924
3608
  );
@@ -1935,81 +3619,134 @@ function reportKept(config, live, into) {
1935
3619
  if (current !== void 0) into.push({ name, action: "unchanged", id: current.id, reason: `not declared by ${by}; kept, never deleted` });
1936
3620
  }
1937
3621
  }
3622
+ function reaches(decl, app) {
3623
+ return Object.entries(decl.tools?.configs ?? {}).some(
3624
+ ([name, one]) => name.startsWith(`${app}.`) && one.enabled && one.permission !== "deny"
3625
+ );
3626
+ }
1938
3627
  async function up(config, client, opts = {}) {
1939
3628
  const dryRun = opts.dry_run ?? false;
1940
3629
  const dir = opts.dir ?? process.cwd();
1941
3630
  const ids = { apps: /* @__PURE__ */ new Map(), identities: /* @__PURE__ */ new Map() };
1942
- const report = { dry_run: dryRun, ...applied(config), skills: [], identities: [], vaults: [], apps: [], agents: [], schedules: [], intake: [], skipped: [] };
1943
- const owner = { project: config.name, adopt: opts.adopt ?? false, skipped: report.skipped };
3631
+ const taken = selectCrew(config, opts.select);
3632
+ const report2 = { dry_run: dryRun, ...applied(config), skills: [], identities: [], vaults: [], apps: [], agents: [], schedules: [], intake: [], skipped: [], deselected: taken.deselected };
3633
+ const owner = { project: config.name, adopt: opts.adopt ?? false, skipped: report2.skipped };
1944
3634
  const hosted = opts.trees !== void 0;
1945
3635
  for (const decl of config.skills) {
1946
- await attempt(report.skills, decl.slug, () => upsertSkill(client, decl, { dryRun, dir, hosted }));
3636
+ await attempt(report2.skills, decl.slug, () => upsertSkill(client, decl, { dryRun, dir, hosted, skills: opts.skills ?? {} }));
1947
3637
  }
1948
3638
  for (const decl of config.identities) {
1949
- await attempt(report.identities, decl.name, () => upsertIdentity(client, decl, dryRun, ids.identities));
3639
+ await attempt(report2.identities, decl.name, () => upsertIdentity(client, decl, dryRun, ids.identities));
3640
+ const identityId = ids.identities.get(decl.name);
3641
+ report2.identities.push(...await reportLegal(client, decl.legal ?? [], identityId, report2.skipped));
3642
+ for (const wallet of decl.wallet === void 0 ? [] : Array.isArray(decl.wallet) ? decl.wallet : [decl.wallet]) {
3643
+ await attempt(
3644
+ report2.identities,
3645
+ walletName(decl.name, wallet),
3646
+ () => reconcileWallet(client, { name: decl.name, id: identityId }, wallet, dryRun)
3647
+ );
3648
+ }
3649
+ await reconcileCards(client, decl.name, identityId, decl.cards ?? [], dryRun, report2.identities, report2.skipped);
1950
3650
  }
1951
- const vaults = config.vaults.length > 0 || config.removed.vaults.length > 0 ? await listAll(client.config, "/v1/vaults", VaultSchema, report.skipped) : [];
3651
+ const vaults = config.vaults.length > 0 || config.removed.vaults.length > 0 ? await listAll(client.config, "/v1/vaults", VaultSchema, report2.skipped) : [];
1952
3652
  for (const decl of config.vaults) {
1953
- const line = await attempt(report.vaults, decl.name, () => upsertVault(client, decl, vaults, ids.identities, dryRun));
1954
- const vaultId = line.action === "unchanged" ? line.id : void 0;
1955
- const rows = vaultId === void 0 ? [] : await listAll(client.config, `/v1/vaults/${vaultId}/credentials`, VaultCredentialSchema, report.skipped);
3653
+ const line2 = await attempt(report2.vaults, decl.name, () => upsertVault(client, decl, vaults, ids.identities, dryRun));
3654
+ const vaultId = line2.action === "unchanged" ? line2.id : void 0;
3655
+ const rows = vaultId === void 0 ? [] : await listAll(client.config, `/v1/vaults/${vaultId}/credentials`, VaultCredentialSchema, report2.skipped);
1956
3656
  for (const cred of decl.credentials) {
1957
3657
  await attempt(
1958
- report.vaults,
3658
+ report2.vaults,
1959
3659
  `${decl.name} / ${cred.key}`,
1960
- () => upsertCredential(client, line, cred, rows, dryRun, opts.env ?? process.env)
3660
+ () => upsertCredential(client, line2, cred, rows, dryRun, opts.env ?? process.env)
1961
3661
  );
1962
3662
  }
1963
3663
  }
1964
3664
  const platform = opts.platform && {
1965
3665
  ...opts.platform,
1966
- known: { ...opts.platform.known, ...identityEnv(config, ids.identities) }
3666
+ known: {
3667
+ ...opts.platform.known,
3668
+ [PLATFORM_ENV.project]: opts.project ?? config.name,
3669
+ ...identityEnv(config, ids.identities)
3670
+ }
1967
3671
  };
1968
- for (const decl of config.apps) {
1969
- await attempt(
1970
- report.apps,
1971
- decl.name,
1972
- () => upsertApp(
1973
- client,
1974
- decl,
1975
- { ...owner, dryRun, dir, trees: opts.trees, tree_errors: opts.tree_errors, env: opts.env ?? process.env, platform },
1976
- ids.apps
3672
+ report2.apps.push(
3673
+ ...await eachInFlight(
3674
+ taken.apps,
3675
+ (decl) => line(
3676
+ decl.name,
3677
+ () => upsertApp(
3678
+ client,
3679
+ decl,
3680
+ {
3681
+ ...owner,
3682
+ dryRun,
3683
+ dir,
3684
+ trees: opts.trees,
3685
+ tree_errors: opts.tree_errors,
3686
+ migrations: opts.migrations,
3687
+ env: opts.env ?? process.env,
3688
+ platform
3689
+ },
3690
+ ids.apps
3691
+ )
1977
3692
  )
1978
- );
1979
- }
1980
- const existing = config.agents.length > 0 || config.removed.agents.length > 0 || config.kept.agents.length > 0 ? await listAll(client.config, "/v1/agents", AgentSchema, report.skipped) : [];
1981
- const deployments = config.agents.some((decl) => decl.schedules !== void 0) ? await listAll(client.config, "/v1/deployments", DeploymentSchema, report.skipped) : [];
3693
+ )
3694
+ );
3695
+ const existing = taken.agents.length > 0 || config.removed.agents.length > 0 || config.kept.agents.length > 0 ? await listAll(client.config, "/v1/agents", AgentSchema, report2.skipped) : [];
3696
+ const deployments = taken.agents.some((decl) => decl.schedules !== void 0) ? await listAll(client.config, "/v1/deployments", DeploymentSchema, report2.skipped) : [];
1982
3697
  const scoped = config.apps.length > 0 ? [...ids.apps.values()] : void 0;
1983
- const briefed = [];
1984
- for (const decl of config.agents) {
1985
- const line = await attempt(
1986
- report.agents,
1987
- decl.name,
1988
- () => upsertAgent(client, decl, existing, ids, dryRun, scoped)
1989
- );
3698
+ const crew = await eachInFlight(taken.agents, async (decl) => {
3699
+ const agent = await line(decl.name, () => upsertAgent(client, decl, existing, ids, dryRun, scoped, { project: opts.project ?? config.name, ...applied(config) }));
3700
+ const schedules = [];
1990
3701
  if (decl.schedules !== void 0) {
1991
- await reconcileSchedules(client, line, decl.schedules, deployments, ids.identities, dryRun, report.schedules);
3702
+ await reconcileSchedules(client, agent, decl.schedules, deployments, ids.identities, dryRun, schedules);
1992
3703
  }
1993
- if (decl.intake !== void 0 && line.action === "created") briefed.push([line, decl.intake]);
3704
+ return { decl, agent, schedules };
3705
+ });
3706
+ const briefed = [];
3707
+ const unbuilt = dryRun ? [] : config.apps.map((decl) => decl.name).filter((name) => !ids.apps.has(name));
3708
+ for (const { decl, agent, schedules } of crew) {
3709
+ report2.agents.push(agent);
3710
+ report2.schedules.push(...schedules);
3711
+ if (decl.intake === void 0 || agent.action !== "created") continue;
3712
+ const needs = unbuilt.find((app) => reaches(decl, app));
3713
+ if (needs === void 0) briefed.push([agent, decl.intake]);
3714
+ else report2.intake.push({ name: decl.name, action: "refused", reason: `needs app "${needs}", which was not provisioned in this run` });
1994
3715
  }
1995
- reportKept(config, existing, report.agents);
1996
- await applyRemoved(client, config.removed, { agents: existing, vaults }, owner, report);
1997
- for (const [line, decl] of briefed) {
1998
- await attempt(report.intake, line.name, () => openIntake(client, line, decl, dryRun));
3716
+ const agentIds = new Map(existing.map((agent) => [agent.name, agent.id]));
3717
+ for (const line2 of report2.agents) if (line2.id !== void 0) agentIds.set(line2.name, line2.id);
3718
+ for (const decl of config.agents) {
3719
+ if (hasRoster(decl.multiagent)) await patchRoster(client, decl, decl.multiagent, existing, agentIds, dryRun, report2.agents);
3720
+ }
3721
+ reportKept(config, existing, report2.agents);
3722
+ await applyRemoved(client, config.removed, { agents: existing, vaults }, owner, report2);
3723
+ if (briefed.length > 0 && !dryRun) {
3724
+ const serving = taken.apps.flatMap((decl) => {
3725
+ const url = report2.apps.find((one) => one.name === decl.name)?.url;
3726
+ return decl.mcp !== void 0 && typeof url === "string" ? [url + decl.mcp] : [];
3727
+ });
3728
+ await awaitServing(serving, opts.probe ?? globalThis.fetch);
1999
3729
  }
2000
- return report;
3730
+ report2.intake.push(
3731
+ ...await eachInFlight(briefed, ([agent, decl]) => line(agent.name, () => openIntake(client, agent, decl, dryRun)))
3732
+ );
3733
+ return report2;
2001
3734
  }
2002
3735
  export {
2003
3736
  BLUEPRINTS,
2004
3737
  BlueprintRefusal,
2005
3738
  CONFIG_CANDIDATES,
2006
3739
  PLATFORM_ENV,
3740
+ PROJECT_CONTEXT_PREAMBLE,
2007
3741
  chooseTemplate,
2008
3742
  collectFiles,
2009
3743
  contentHash,
2010
3744
  defineProject,
3745
+ hasRoster,
2011
3746
  loadConfig,
3747
+ migrationFiles,
2012
3748
  parseProject,
3749
+ selectCrew,
2013
3750
  up
2014
3751
  };
2015
3752
  //# sourceMappingURL=index.js.map