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