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