@usenaive-sdk/blueprints 0.2.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 +519 -13
- package/dist/index.js +2525 -648
- 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",
|
|
@@ -93,13 +201,62 @@ var AUDIT_ACTIONS_P3 = [
|
|
|
93
201
|
"app.domain_connected",
|
|
94
202
|
"app.domain_disconnected",
|
|
95
203
|
"app.db_queried",
|
|
96
|
-
|
|
204
|
+
/** A ticket was minted that lets one browser past an app's own operator gate (§29.7). */
|
|
205
|
+
"app.entered",
|
|
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"
|
|
97
252
|
];
|
|
98
253
|
var AUDIT_ACTIONS = [
|
|
99
254
|
...AUDIT_ACTIONS_SHIPPED,
|
|
100
255
|
...AUDIT_ACTIONS_P1,
|
|
101
256
|
...AUDIT_ACTIONS_P2,
|
|
102
|
-
...AUDIT_ACTIONS_P3
|
|
257
|
+
...AUDIT_ACTIONS_P3,
|
|
258
|
+
...AUDIT_ACTIONS_PRIMITIVES,
|
|
259
|
+
...AUDIT_ACTIONS_CORE_GAPS
|
|
103
260
|
];
|
|
104
261
|
|
|
105
262
|
// ../core/src/schema/common.ts
|
|
@@ -117,7 +274,7 @@ var JsonSchemaDocument = z.record(z.string(), z.unknown()).refine((schema) => sc
|
|
|
117
274
|
var WindowSchema = z.enum(["immediate", "priority", "loose"]);
|
|
118
275
|
var TOKEN_TIERS = ["input", "cache_write", "cache_read", "output", "reasoning"];
|
|
119
276
|
var TokenTierSchema = z.enum(TOKEN_TIERS);
|
|
120
|
-
var TOOL_TIERS = ["search", "media", "social"];
|
|
277
|
+
var TOOL_TIERS = ["search", "media", "social", "browser", "storage"];
|
|
121
278
|
var LINE_ITEM_TIERS = [...TOKEN_TIERS, "computer", ...TOOL_TIERS];
|
|
122
279
|
var LineItemTierSchema = z.enum(LINE_ITEM_TIERS);
|
|
123
280
|
var TokenUsageSchema = z.object({
|
|
@@ -140,84 +297,333 @@ var HARNESS_IDS = ["pi", "claude_code", "vetta", "hermes"];
|
|
|
140
297
|
var HarnessIdSchema = z2.enum(HARNESS_IDS);
|
|
141
298
|
|
|
142
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
|
|
143
306
|
import { z as z3 } from "zod";
|
|
144
|
-
var
|
|
145
|
-
|
|
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()),
|
|
146
384
|
enabled: z3.boolean(),
|
|
147
|
-
|
|
148
|
-
config: z3.record(z3.string(), z3.unknown()).optional()
|
|
385
|
+
created_at: Timestamp
|
|
149
386
|
});
|
|
150
|
-
var
|
|
151
|
-
|
|
152
|
-
|
|
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()
|
|
153
397
|
});
|
|
154
|
-
var
|
|
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
|
|
455
|
+
});
|
|
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({
|
|
155
556
|
cap_micro_usd: MicroUsdField.nonnegative(),
|
|
156
557
|
max_task_micro_usd: MicroUsdField.nonnegative(),
|
|
157
|
-
period:
|
|
558
|
+
period: z5.enum(["day", "week", "month"])
|
|
158
559
|
});
|
|
159
|
-
var SkillRefSchema =
|
|
160
|
-
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`"
|
|
161
562
|
});
|
|
162
|
-
var McpServerSchema =
|
|
163
|
-
name:
|
|
164
|
-
url:
|
|
165
|
-
headers:
|
|
563
|
+
var McpServerSchema = z5.object({
|
|
564
|
+
name: z5.string(),
|
|
565
|
+
url: z5.url(),
|
|
566
|
+
headers: z5.record(z5.string(), z5.string()).optional()
|
|
166
567
|
});
|
|
167
|
-
var RosterEntrySchema =
|
|
568
|
+
var RosterEntrySchema = z5.union([
|
|
168
569
|
idOf("agt").transform((id) => ({ type: "agent", id })),
|
|
169
|
-
|
|
170
|
-
type:
|
|
570
|
+
z5.object({
|
|
571
|
+
type: z5.literal("agent"),
|
|
171
572
|
id: idOf("agt"),
|
|
172
|
-
version:
|
|
573
|
+
version: z5.number().int().positive().optional()
|
|
173
574
|
}),
|
|
174
|
-
|
|
175
|
-
|
|
575
|
+
z5.object({ type: z5.literal("self") }),
|
|
576
|
+
z5.object({ type: z5.literal("advisor"), model: z5.string().min(1) })
|
|
176
577
|
]);
|
|
177
578
|
var SINGLETON_ENTRIES = ["self", "advisor"];
|
|
178
|
-
var MultiagentSchema =
|
|
179
|
-
type:
|
|
180
|
-
agents:
|
|
579
|
+
var MultiagentSchema = z5.object({
|
|
580
|
+
type: z5.literal("coordinator"),
|
|
581
|
+
agents: z5.array(RosterEntrySchema).min(1).max(20).refine(
|
|
181
582
|
(roster) => SINGLETON_ENTRIES.every((t) => roster.filter((e) => e.type === t).length <= 1),
|
|
182
583
|
{ error: "a roster carries at most one `self` and at most one `advisor` entry" }
|
|
183
584
|
),
|
|
184
|
-
board:
|
|
585
|
+
board: z5.boolean().optional()
|
|
185
586
|
});
|
|
186
|
-
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
|
+
}
|
|
187
593
|
var agentConfigShape = {
|
|
188
|
-
model:
|
|
594
|
+
model: z5.string(),
|
|
189
595
|
window: WindowSchema,
|
|
190
|
-
system:
|
|
596
|
+
system: z5.string(),
|
|
191
597
|
tools: ToolsetSchema,
|
|
192
|
-
mcp_servers:
|
|
193
|
-
skills:
|
|
598
|
+
mcp_servers: z5.array(McpServerSchema),
|
|
599
|
+
skills: z5.array(SkillRefSchema),
|
|
194
600
|
multiagent: MultiagentField,
|
|
195
601
|
budget: BudgetSchema,
|
|
196
602
|
output_schema: JsonSchemaDocument.nullable(),
|
|
197
|
-
structured_output_required:
|
|
198
|
-
description:
|
|
603
|
+
structured_output_required: z5.boolean(),
|
|
604
|
+
description: z5.string().nullable(),
|
|
199
605
|
metadata: Metadata
|
|
200
606
|
};
|
|
201
|
-
var AgentVersionSchema =
|
|
202
|
-
version:
|
|
607
|
+
var AgentVersionSchema = z5.object({
|
|
608
|
+
version: z5.number().int().positive(),
|
|
203
609
|
created_at: Timestamp,
|
|
204
610
|
created_by: PrincipalSchema,
|
|
205
611
|
...agentConfigShape
|
|
206
612
|
});
|
|
207
|
-
var AgentSchema =
|
|
613
|
+
var AgentSchema = z5.object({
|
|
208
614
|
id: idOf("agt"),
|
|
209
|
-
object:
|
|
210
|
-
name:
|
|
615
|
+
object: z5.literal("agent"),
|
|
616
|
+
name: z5.string(),
|
|
211
617
|
/** The agent loop this agent runs (§19). Chosen at create; the catalog lives in `harness.ts`. */
|
|
212
618
|
harness: HarnessIdSchema,
|
|
213
|
-
current_version:
|
|
619
|
+
current_version: z5.number().int().positive(),
|
|
214
620
|
created_at: Timestamp,
|
|
215
621
|
...agentConfigShape
|
|
216
622
|
});
|
|
217
623
|
|
|
218
624
|
// ../core/src/schema/session.ts
|
|
219
|
-
import { z as
|
|
220
|
-
var SessionStatusSchema =
|
|
625
|
+
import { z as z6 } from "zod";
|
|
626
|
+
var SessionStatusSchema = z6.enum([
|
|
221
627
|
"queued",
|
|
222
628
|
"running",
|
|
223
629
|
"idle",
|
|
@@ -225,7 +631,7 @@ var SessionStatusSchema = z4.enum([
|
|
|
225
631
|
"failed",
|
|
226
632
|
"cancelled"
|
|
227
633
|
]);
|
|
228
|
-
var StopReasonSchema =
|
|
634
|
+
var StopReasonSchema = z6.enum([
|
|
229
635
|
"end_turn",
|
|
230
636
|
"awaiting_input",
|
|
231
637
|
"awaiting_approval",
|
|
@@ -251,61 +657,61 @@ var StopReasonSchema = z4.enum([
|
|
|
251
657
|
*/
|
|
252
658
|
"awaiting_answer"
|
|
253
659
|
]);
|
|
254
|
-
var ThreadRoleSchema =
|
|
255
|
-
var MessageSchema =
|
|
256
|
-
role:
|
|
257
|
-
content:
|
|
258
|
-
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()
|
|
259
665
|
});
|
|
260
|
-
var ToolResultSchema =
|
|
261
|
-
output:
|
|
262
|
-
is_error:
|
|
263
|
-
content:
|
|
666
|
+
var ToolResultSchema = z6.object({
|
|
667
|
+
output: z6.unknown(),
|
|
668
|
+
is_error: z6.boolean().optional(),
|
|
669
|
+
content: z6.string().optional()
|
|
264
670
|
});
|
|
265
671
|
var QuestionFieldBase = {
|
|
266
|
-
key:
|
|
267
|
-
label:
|
|
268
|
-
help:
|
|
672
|
+
key: z6.string().min(1).max(64),
|
|
673
|
+
label: z6.string().min(1).max(200),
|
|
674
|
+
help: z6.string().max(500).optional()
|
|
269
675
|
};
|
|
270
|
-
var QuestionFieldSchema =
|
|
271
|
-
|
|
676
|
+
var QuestionFieldSchema = z6.discriminatedUnion("type", [
|
|
677
|
+
z6.object({
|
|
272
678
|
...QuestionFieldBase,
|
|
273
|
-
type:
|
|
274
|
-
placeholder:
|
|
679
|
+
type: z6.literal("text"),
|
|
680
|
+
placeholder: z6.string().max(200).optional()
|
|
275
681
|
}),
|
|
276
|
-
|
|
682
|
+
z6.object({
|
|
277
683
|
...QuestionFieldBase,
|
|
278
|
-
type:
|
|
684
|
+
type: z6.literal("choice"),
|
|
279
685
|
/**
|
|
280
686
|
* Plain strings: the option is both the value and the label, because the answer is read back by
|
|
281
687
|
* a model, which wants the words and not an id. Fewer than two is not a choice, and more than
|
|
282
688
|
* twelve is a list — which belongs in the prompt.
|
|
283
689
|
*/
|
|
284
|
-
options:
|
|
285
|
-
multiple:
|
|
690
|
+
options: z6.array(z6.string().min(1).max(200)).min(2).max(12),
|
|
691
|
+
multiple: z6.boolean().default(false),
|
|
286
692
|
/**
|
|
287
693
|
* The free-text escape, and it defaults to **true** on purpose: the agent wrote the options and
|
|
288
694
|
* the agent is the one that does not know the answer, so an operator must always be able to say
|
|
289
695
|
* something it did not think of. A question that truly admits only its list opts out explicitly.
|
|
290
696
|
*/
|
|
291
|
-
other:
|
|
697
|
+
other: z6.boolean().default(true)
|
|
292
698
|
})
|
|
293
699
|
]);
|
|
294
|
-
var QuestionSchema =
|
|
295
|
-
prompt:
|
|
296
|
-
fields:
|
|
700
|
+
var QuestionSchema = z6.object({
|
|
701
|
+
prompt: z6.string().min(1).max(1e3),
|
|
702
|
+
fields: z6.array(QuestionFieldSchema).min(1).max(3)
|
|
297
703
|
});
|
|
298
|
-
var AnswersSchema =
|
|
299
|
-
|
|
300
|
-
|
|
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)])
|
|
301
707
|
).refine((answers) => Object.keys(answers).length <= 3, {
|
|
302
708
|
message: "a question has at most 3 fields, so an answer has at most 3 keys"
|
|
303
709
|
});
|
|
304
|
-
var PendingActionSchema =
|
|
305
|
-
kind:
|
|
306
|
-
tool_call_id:
|
|
307
|
-
name:
|
|
308
|
-
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()),
|
|
309
715
|
/**
|
|
310
716
|
* Present iff `kind` is `"question"`, and it is the parse of `args` rather than a second source
|
|
311
717
|
* of truth: `args` is what the model called and therefore what replays byte-identically, while
|
|
@@ -314,11 +720,11 @@ var PendingActionSchema = z4.object({
|
|
|
314
720
|
*/
|
|
315
721
|
question: QuestionSchema.optional()
|
|
316
722
|
});
|
|
317
|
-
var SessionSchema =
|
|
723
|
+
var SessionSchema = z6.object({
|
|
318
724
|
id: idOf("ses"),
|
|
319
|
-
object:
|
|
725
|
+
object: z6.literal("session"),
|
|
320
726
|
agent_id: idOf("agt"),
|
|
321
|
-
agent_version:
|
|
727
|
+
agent_version: z6.number().int().positive(),
|
|
322
728
|
deployment_id: idOf("dep").nullable(),
|
|
323
729
|
/**
|
|
324
730
|
* The persona this session acts as (`canonical-spec §22`). Chosen per task from the personas the
|
|
@@ -347,38 +753,39 @@ var SessionSchema = z4.object({
|
|
|
347
753
|
budget_micro_usd: MicroUsdField.nonnegative(),
|
|
348
754
|
consumed_micro_usd: MicroUsdField.nonnegative(),
|
|
349
755
|
token_usage: TokenUsageSchema,
|
|
350
|
-
pending_actions:
|
|
756
|
+
pending_actions: z6.array(PendingActionSchema),
|
|
351
757
|
output_schema: JsonSchemaDocument.nullable(),
|
|
352
|
-
structured_output:
|
|
353
|
-
last_seq:
|
|
758
|
+
structured_output: z6.record(z6.string(), z6.unknown()).nullable(),
|
|
759
|
+
last_seq: z6.number().int().nonnegative(),
|
|
354
760
|
metadata: Metadata,
|
|
355
761
|
started_at: Timestamp.nullable(),
|
|
356
762
|
ended_at: Timestamp.nullable(),
|
|
357
763
|
created_at: Timestamp
|
|
358
764
|
});
|
|
359
|
-
var SendMessageSchema =
|
|
360
|
-
message:
|
|
361
|
-
interrupt:
|
|
362
|
-
idempotency_key:
|
|
765
|
+
var SendMessageSchema = z6.object({
|
|
766
|
+
message: z6.string(),
|
|
767
|
+
interrupt: z6.boolean().optional(),
|
|
768
|
+
idempotency_key: z6.string().optional()
|
|
363
769
|
});
|
|
364
|
-
var SendAcceptedSchema =
|
|
365
|
-
session_id:
|
|
770
|
+
var SendAcceptedSchema = z6.object({
|
|
771
|
+
session_id: z6.string(),
|
|
366
772
|
status: SessionStatusSchema,
|
|
367
|
-
accepted_seq:
|
|
773
|
+
accepted_seq: z6.number().int().nonnegative()
|
|
368
774
|
});
|
|
369
|
-
var ToolConfirmationSchema =
|
|
370
|
-
tool_call_id:
|
|
371
|
-
decision:
|
|
372
|
-
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")
|
|
373
780
|
});
|
|
374
|
-
var SessionAnswerSchema =
|
|
375
|
-
tool_call_id:
|
|
376
|
-
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())]))
|
|
377
784
|
});
|
|
378
785
|
|
|
379
786
|
// ../core/src/schema/event.ts
|
|
380
|
-
import { z as
|
|
381
|
-
var EventTypeSchema =
|
|
787
|
+
import { z as z7 } from "zod";
|
|
788
|
+
var EventTypeSchema = z7.enum([
|
|
382
789
|
"message.delta",
|
|
383
790
|
"message.completed",
|
|
384
791
|
"tool.started",
|
|
@@ -398,57 +805,81 @@ var EventTypeSchema = z5.enum([
|
|
|
398
805
|
"thread.created",
|
|
399
806
|
"thread.running",
|
|
400
807
|
"thread.idle",
|
|
401
|
-
"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"
|
|
402
833
|
]);
|
|
403
|
-
var EventSchema =
|
|
834
|
+
var EventSchema = z7.object({
|
|
404
835
|
id: idOf("evt"),
|
|
405
|
-
seq:
|
|
836
|
+
seq: z7.number().int().positive(),
|
|
406
837
|
type: EventTypeSchema,
|
|
407
838
|
session_id: idOf("ses"),
|
|
408
|
-
data:
|
|
839
|
+
data: z7.record(z7.string(), z7.unknown()),
|
|
409
840
|
created_at: Timestamp
|
|
410
841
|
});
|
|
411
|
-
var ThreadEventDataSchema =
|
|
412
|
-
var SessionUsageDataSchema =
|
|
842
|
+
var ThreadEventDataSchema = z7.looseObject({ thread_id: idOf("ses") });
|
|
843
|
+
var SessionUsageDataSchema = z7.object({
|
|
413
844
|
token_usage: TokenUsageSchema,
|
|
414
845
|
consumed_micro_usd: MicroUsdField.nonnegative(),
|
|
415
|
-
active_seconds:
|
|
416
|
-
tool_calls:
|
|
846
|
+
active_seconds: z7.number().nonnegative(),
|
|
847
|
+
tool_calls: z7.number().int().nonnegative()
|
|
417
848
|
});
|
|
418
849
|
|
|
419
850
|
// ../core/src/schema/board.ts
|
|
420
|
-
import { z as
|
|
851
|
+
import { z as z8 } from "zod";
|
|
421
852
|
var BOARD_STATUSES = ["todo", "doing", "blocked", "done"];
|
|
422
|
-
var BoardStatusSchema =
|
|
423
|
-
var BoardCountsSchema =
|
|
424
|
-
todo:
|
|
425
|
-
doing:
|
|
426
|
-
blocked:
|
|
427
|
-
done:
|
|
428
|
-
});
|
|
429
|
-
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({
|
|
430
861
|
id: idOf("brd"),
|
|
431
|
-
object:
|
|
862
|
+
object: z8.literal("board"),
|
|
432
863
|
agent_id: idOf("agt"),
|
|
433
864
|
cards: BoardCountsSchema,
|
|
434
865
|
created_at: Timestamp
|
|
435
866
|
});
|
|
436
|
-
var BoardCardSchema =
|
|
867
|
+
var BoardCardSchema = z8.object({
|
|
437
868
|
id: idOf("crd"),
|
|
438
|
-
object:
|
|
869
|
+
object: z8.literal("board_card"),
|
|
439
870
|
board_id: idOf("brd"),
|
|
440
|
-
title:
|
|
441
|
-
body:
|
|
871
|
+
title: z8.string().min(1),
|
|
872
|
+
body: z8.string(),
|
|
442
873
|
status: BoardStatusSchema,
|
|
443
|
-
assignee:
|
|
874
|
+
assignee: z8.string().nullable(),
|
|
444
875
|
/** The cards this one waits on. A `blocked` card with an empty list is stuck on the world. */
|
|
445
|
-
blocked_by:
|
|
876
|
+
blocked_by: z8.array(idOf("crd")),
|
|
446
877
|
created_at: Timestamp,
|
|
447
878
|
updated_at: Timestamp
|
|
448
879
|
});
|
|
449
|
-
var BoardCommentSchema =
|
|
880
|
+
var BoardCommentSchema = z8.object({
|
|
450
881
|
id: idOf("bcm"),
|
|
451
|
-
object:
|
|
882
|
+
object: z8.literal("board_comment"),
|
|
452
883
|
card_id: idOf("crd"),
|
|
453
884
|
/**
|
|
454
885
|
* Who wrote it, as an id the server derived — never a name the caller supplied. A member's
|
|
@@ -456,105 +887,221 @@ var BoardCommentSchema = z6.object({
|
|
|
456
887
|
* `key_` principal. The prefix is what lets a reader tell an agent's comment from a person's,
|
|
457
888
|
* which is the distinction a free-text author field could not make and could be used to forge.
|
|
458
889
|
*/
|
|
459
|
-
author:
|
|
460
|
-
body:
|
|
890
|
+
author: z8.string(),
|
|
891
|
+
body: z8.string(),
|
|
461
892
|
created_at: Timestamp
|
|
462
893
|
});
|
|
463
894
|
|
|
464
895
|
// ../core/src/schema/identity.ts
|
|
465
|
-
import { z as
|
|
896
|
+
import { z as z9 } from "zod";
|
|
466
897
|
var IDENTITY_NAME_MAX = 128;
|
|
467
898
|
var IDENTITY_DESCRIPTION_MAX = 1024;
|
|
468
|
-
var IdentitySchema =
|
|
899
|
+
var IdentitySchema = z9.object({
|
|
469
900
|
id: idOf("idn"),
|
|
470
|
-
object:
|
|
901
|
+
object: z9.literal("identity"),
|
|
471
902
|
/** Human-facing persona name. Surfaced to the model so it acts in character. */
|
|
472
|
-
name:
|
|
903
|
+
name: z9.string().min(1).max(IDENTITY_NAME_MAX),
|
|
473
904
|
/** What the persona is for. The model reads it to choose tone, scope and endpoint. */
|
|
474
|
-
description:
|
|
905
|
+
description: z9.string().max(IDENTITY_DESCRIPTION_MAX).nullable(),
|
|
475
906
|
/** Inbox addresses (`localpart@domain`) this identity owns. */
|
|
476
|
-
emails:
|
|
907
|
+
emails: z9.array(z9.string()),
|
|
477
908
|
/** Provisioned numbers in E.164. */
|
|
478
|
-
phones:
|
|
909
|
+
phones: z9.array(z9.string()),
|
|
479
910
|
/** Verified web domains reachable through this identity's inboxes. */
|
|
480
|
-
domains:
|
|
911
|
+
domains: z9.array(z9.string()),
|
|
481
912
|
/** `conn_` ids of authorized third-party connections. */
|
|
482
|
-
connections:
|
|
913
|
+
connections: z9.array(z9.string()),
|
|
483
914
|
metadata: Metadata,
|
|
484
915
|
created_at: Timestamp,
|
|
485
916
|
updated_at: Timestamp
|
|
486
917
|
});
|
|
487
918
|
|
|
488
919
|
// ../core/src/schema/resource.ts
|
|
489
|
-
import { z as
|
|
490
|
-
|
|
491
|
-
|
|
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({
|
|
492
968
|
id: idOf("vol"),
|
|
493
|
-
size_gb:
|
|
494
|
-
mount_path:
|
|
969
|
+
size_gb: z11.number().int().positive(),
|
|
970
|
+
mount_path: z11.string()
|
|
495
971
|
});
|
|
496
|
-
var ComputerSchema =
|
|
972
|
+
var ComputerSchema = z11.object({
|
|
497
973
|
id: idOf("cmp"),
|
|
498
|
-
object:
|
|
499
|
-
name:
|
|
500
|
-
vcpu:
|
|
501
|
-
memory_mb:
|
|
502
|
-
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(),
|
|
503
979
|
status: ComputerStatusSchema,
|
|
504
|
-
|
|
980
|
+
// core-gaps: U2-browser-api — the whole option object (§32.2); `{ allowed_domains }` still parses.
|
|
981
|
+
browser: BrowserOptionsSchema.nullable(),
|
|
505
982
|
volume: VolumeSchema.nullable(),
|
|
506
983
|
snapshot_id: idOf("snp").nullable(),
|
|
507
984
|
created_at: Timestamp
|
|
508
985
|
});
|
|
509
|
-
var SnapshotSchema =
|
|
986
|
+
var SnapshotSchema = z11.object({
|
|
510
987
|
snapshot_id: idOf("snp"),
|
|
511
988
|
computer_id: idOf("cmp"),
|
|
512
989
|
created_at: Timestamp
|
|
513
990
|
});
|
|
514
|
-
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({
|
|
515
1049
|
id: idOf("skl"),
|
|
516
|
-
object:
|
|
517
|
-
name:
|
|
518
|
-
description:
|
|
519
|
-
latest_version:
|
|
1050
|
+
object: z11.literal("skill"),
|
|
1051
|
+
name: z11.string(),
|
|
1052
|
+
description: z11.string().nullable(),
|
|
1053
|
+
latest_version: z11.number().int().positive(),
|
|
520
1054
|
created_at: Timestamp
|
|
521
1055
|
});
|
|
522
|
-
var ResolvedSkillRefSchema =
|
|
1056
|
+
var ResolvedSkillRefSchema = z11.object({
|
|
523
1057
|
/** The reference exactly as the agent version wrote it: `slug` or `slug@N`. */
|
|
524
|
-
ref:
|
|
525
|
-
slug:
|
|
526
|
-
version:
|
|
527
|
-
description:
|
|
528
|
-
storage_key:
|
|
529
|
-
});
|
|
530
|
-
var SkillVersionSchema =
|
|
531
|
-
version:
|
|
532
|
-
sha256:
|
|
533
|
-
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(),
|
|
534
1068
|
created_at: Timestamp
|
|
535
1069
|
});
|
|
536
|
-
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({
|
|
537
1082
|
id: idOf("fil"),
|
|
538
|
-
object:
|
|
539
|
-
name:
|
|
540
|
-
content_type:
|
|
541
|
-
size_bytes:
|
|
542
|
-
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"]),
|
|
543
1088
|
session_id: idOf("ses").nullable(),
|
|
544
|
-
sha256:
|
|
545
|
-
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
|
|
546
1093
|
});
|
|
547
|
-
var ScheduleStatusSchema =
|
|
548
|
-
var DeploymentSchema =
|
|
1094
|
+
var ScheduleStatusSchema = z11.enum(["scheduled", "paused", "unscheduled"]);
|
|
1095
|
+
var DeploymentSchema = z11.object({
|
|
549
1096
|
id: idOf("dep"),
|
|
550
|
-
object:
|
|
1097
|
+
object: z11.literal("deployment"),
|
|
551
1098
|
agent_id: idOf("agt"),
|
|
552
1099
|
/** A pin. `null` tracks the agent's `current_version` on every fire (§12). */
|
|
553
|
-
agent_version:
|
|
554
|
-
cron:
|
|
1100
|
+
agent_version: z11.number().int().positive().nullable(),
|
|
1101
|
+
cron: z11.string(),
|
|
555
1102
|
/** IANA zone the `cron` is read in. "0 9 * * 1" means 09:00 *here*, across DST (ADR-0074). */
|
|
556
|
-
timezone:
|
|
557
|
-
input_template:
|
|
1103
|
+
timezone: z11.string(),
|
|
1104
|
+
input_template: z11.string(),
|
|
558
1105
|
budget_micro_usd: MicroUsdField.nonnegative(),
|
|
559
1106
|
window: WindowSchema,
|
|
560
1107
|
/**
|
|
@@ -564,189 +1111,84 @@ var DeploymentSchema = z8.object({
|
|
|
564
1111
|
* those endpoints, and a signed delivery over cleartext is not a delivery. Until the push was
|
|
565
1112
|
* wired this field went nowhere, so nothing can be relying on an `http://` value (ADR-0161).
|
|
566
1113
|
*/
|
|
567
|
-
on_idle:
|
|
1114
|
+
on_idle: z11.url().startsWith("https://", { error: "a webhook URL must be https" }).nullable(),
|
|
568
1115
|
/**
|
|
569
1116
|
* The persona every fire speaks as, or `null` to run as nobody (§22). Written as an `idn_` id
|
|
570
1117
|
* **or** the persona's name, the way a session names one, and always echoed as the id: a fire at
|
|
571
1118
|
* 3am must not be silenced by someone renaming the persona at noon.
|
|
572
1119
|
*/
|
|
573
1120
|
identity: idOf("idn").nullable(),
|
|
574
|
-
enabled:
|
|
1121
|
+
enabled: z11.boolean(),
|
|
575
1122
|
/** Derived per deploy, never stored — the row cannot know whether a clock is watching it. */
|
|
576
1123
|
schedule_status: ScheduleStatusSchema,
|
|
577
1124
|
/** The next fire, or `null` when nothing will fire it (`schedule_status` says which). */
|
|
578
1125
|
next_run_at: Timestamp.nullable(),
|
|
579
1126
|
created_at: Timestamp
|
|
580
1127
|
});
|
|
581
|
-
var DeploymentRunSchema =
|
|
1128
|
+
var DeploymentRunSchema = z11.object({
|
|
582
1129
|
id: idOf("run"),
|
|
583
1130
|
session_id: idOf("ses"),
|
|
584
1131
|
status: SessionStatusSchema,
|
|
585
1132
|
started_at: Timestamp.nullable()
|
|
586
1133
|
});
|
|
587
1134
|
|
|
588
|
-
// ../core/src/schema/org.ts
|
|
589
|
-
import { z as z9 } from "zod";
|
|
590
|
-
var OrganizationSchema = z9.object({
|
|
591
|
-
id: idOf("org"),
|
|
592
|
-
object: z9.literal("organization"),
|
|
593
|
-
name: z9.string(),
|
|
594
|
-
balance_micro_usd: MicroUsdField,
|
|
595
|
-
created_at: Timestamp
|
|
596
|
-
});
|
|
597
|
-
var RoleSchema = z9.enum(["owner", "admin", "member"]);
|
|
598
|
-
var MemberSchema = z9.object({
|
|
599
|
-
id: z9.string(),
|
|
600
|
-
object: z9.literal("member"),
|
|
601
|
-
email: z9.email(),
|
|
602
|
-
role: RoleSchema,
|
|
603
|
-
invited_by: z9.string().nullable(),
|
|
604
|
-
created_at: Timestamp
|
|
605
|
-
});
|
|
606
|
-
var SCOPES = [
|
|
607
|
-
"agents:read",
|
|
608
|
-
"agents:write",
|
|
609
|
-
"sessions:read",
|
|
610
|
-
"sessions:write",
|
|
611
|
-
/**
|
|
612
|
-
* THE MODEL DOOR AND NOTHING ELSE. `/v1/proxy/*` used to take `sessions:write`, which also opens
|
|
613
|
-
* session create and cancel — so a credential handed to a customer's micro-VM, if it leaked, could
|
|
614
|
-
* start sessions for the whole organization. This scope buys exactly one capability, so a sandbox
|
|
615
|
-
* token can be minted with it alone.
|
|
616
|
-
*
|
|
617
|
-
* The proxy routes accept EITHER this or `sessions:write`: narrowing an already-published route
|
|
618
|
-
* would break every key that reaches it today (§17).
|
|
619
|
-
*/
|
|
620
|
-
"proxy:write",
|
|
621
|
-
"computers:write",
|
|
622
|
-
"files:read",
|
|
623
|
-
"files:write",
|
|
624
|
-
"billing:read",
|
|
625
|
-
"billing:write",
|
|
626
|
-
"webhooks:*",
|
|
627
|
-
"audit:read",
|
|
628
|
-
"admin"
|
|
629
|
-
];
|
|
630
|
-
var ScopeSchema = z9.enum(SCOPES);
|
|
631
|
-
var ApiKeySchema = z9.object({
|
|
632
|
-
id: idOf("key"),
|
|
633
|
-
object: z9.literal("api_key"),
|
|
634
|
-
name: z9.string(),
|
|
635
|
-
prefix: z9.string(),
|
|
636
|
-
scopes: z9.array(ScopeSchema),
|
|
637
|
-
created_by: PrincipalSchema,
|
|
638
|
-
last_used_at: Timestamp.nullable(),
|
|
639
|
-
created_at: Timestamp
|
|
640
|
-
});
|
|
641
|
-
var LedgerEntrySchema = z9.object({
|
|
642
|
-
id: idOf("led"),
|
|
643
|
-
type: z9.enum(["debit", "credit"]),
|
|
644
|
-
amount_micro_usd: MicroUsdField,
|
|
645
|
-
balance_after_micro_usd: MicroUsdField,
|
|
646
|
-
actor: PrincipalSchema,
|
|
647
|
-
session_id: idOf("ses").nullable(),
|
|
648
|
-
agent_id: idOf("agt").nullable(),
|
|
649
|
-
deployment_id: idOf("dep").nullable(),
|
|
650
|
-
line_items: z9.array(z9.object({ tier: LineItemTierSchema, amount_micro_usd: MicroUsdField })),
|
|
651
|
-
created_at: Timestamp
|
|
652
|
-
});
|
|
653
|
-
var TopupSchema = z9.object({
|
|
654
|
-
id: z9.string(),
|
|
655
|
-
object: z9.literal("topup"),
|
|
656
|
-
amount_micro_usd: MicroUsdField.positive(),
|
|
657
|
-
status: z9.enum(["pending", "requires_action", "succeeded", "failed"]),
|
|
658
|
-
action_url: z9.url().nullable(),
|
|
659
|
-
balance_after_micro_usd: MicroUsdField.nullable(),
|
|
660
|
-
created_at: Timestamp
|
|
661
|
-
});
|
|
662
|
-
var WebhookEndpointSchema = z9.object({
|
|
663
|
-
id: idOf("whk"),
|
|
664
|
-
object: z9.literal("webhook_endpoint"),
|
|
665
|
-
url: z9.url(),
|
|
666
|
-
events: z9.array(z9.string()),
|
|
667
|
-
enabled: z9.boolean(),
|
|
668
|
-
created_at: Timestamp
|
|
669
|
-
});
|
|
670
|
-
var WebhookDeliverySchema = z9.object({
|
|
671
|
-
id: idOf("whd"),
|
|
672
|
-
event_id: idOf("evt"),
|
|
673
|
-
event_type: z9.string(),
|
|
674
|
-
status: z9.enum(["pending", "succeeded", "failed"]),
|
|
675
|
-
attempts: z9.number().int().nonnegative(),
|
|
676
|
-
response_status: z9.number().int().nullable(),
|
|
677
|
-
response_snippet: z9.string().nullable(),
|
|
678
|
-
delivered_at: Timestamp.nullable(),
|
|
679
|
-
next_retry_at: Timestamp.nullable()
|
|
680
|
-
});
|
|
681
|
-
var AuditEntrySchema = z9.object({
|
|
682
|
-
id: idOf("aud"),
|
|
683
|
-
object: z9.literal("audit_entry"),
|
|
684
|
-
actor: PrincipalSchema,
|
|
685
|
-
action: AuditActionSchema,
|
|
686
|
-
resource_type: z9.string(),
|
|
687
|
-
resource_id: z9.string(),
|
|
688
|
-
request_id: z9.string(),
|
|
689
|
-
metadata: Metadata,
|
|
690
|
-
created_at: Timestamp
|
|
691
|
-
});
|
|
692
|
-
|
|
693
1135
|
// ../core/src/schema/comms.ts
|
|
694
|
-
import { z as
|
|
695
|
-
var DomainKindSchema =
|
|
696
|
-
var DomainStatusSchema =
|
|
697
|
-
var DomainDnsStatusSchema =
|
|
698
|
-
var DomainInboundStatusSchema =
|
|
699
|
-
var DomainAppConnectStatusSchema =
|
|
700
|
-
var DnsRecordSchema =
|
|
701
|
-
type:
|
|
702
|
-
host:
|
|
703
|
-
value:
|
|
704
|
-
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(),
|
|
705
1147
|
/** Vetta owns this record: `_dmarc`, DKIM, inbound MX. The agent may read it, never write it. */
|
|
706
|
-
managed:
|
|
1148
|
+
managed: z12.boolean()
|
|
707
1149
|
});
|
|
708
|
-
var DomainSchema =
|
|
1150
|
+
var DomainSchema = z12.object({
|
|
709
1151
|
id: idOf("dom"),
|
|
710
|
-
object:
|
|
1152
|
+
object: z12.literal("domain"),
|
|
711
1153
|
/** A domain belongs to the **organization**, not to one identity: two identities share one. */
|
|
712
|
-
name:
|
|
1154
|
+
name: z12.string(),
|
|
713
1155
|
kind: DomainKindSchema,
|
|
714
1156
|
status: DomainStatusSchema,
|
|
715
1157
|
dns_status: DomainDnsStatusSchema,
|
|
716
1158
|
inbound_status: DomainInboundStatusSchema,
|
|
717
1159
|
app_connect_status: DomainAppConnectStatusSchema,
|
|
718
|
-
records:
|
|
1160
|
+
records: z12.array(DnsRecordSchema),
|
|
719
1161
|
last_verified_at: Timestamp.nullable(),
|
|
720
1162
|
created_at: Timestamp
|
|
721
1163
|
});
|
|
722
|
-
var EmailInboxSchema =
|
|
1164
|
+
var EmailInboxSchema = z12.object({
|
|
723
1165
|
id: idOf("eml"),
|
|
724
|
-
object:
|
|
1166
|
+
object: z12.literal("email_inbox"),
|
|
725
1167
|
identity_id: idOf("idn"),
|
|
726
1168
|
domain_id: idOf("dom"),
|
|
727
|
-
address:
|
|
728
|
-
localpart:
|
|
1169
|
+
address: z12.string(),
|
|
1170
|
+
localpart: z12.string(),
|
|
729
1171
|
/** Inbound routing keys off this: mail to the address wakes exactly this agent. */
|
|
730
1172
|
owning_agent_id: idOf("agt"),
|
|
731
|
-
status:
|
|
1173
|
+
status: z12.enum(["active", "disabled"]),
|
|
732
1174
|
created_at: Timestamp
|
|
733
1175
|
});
|
|
734
|
-
var PhoneTierSchema =
|
|
735
|
-
var BrandStatusSchema =
|
|
736
|
-
var CampaignStatusSchema =
|
|
737
|
-
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({
|
|
738
1180
|
id: idOf("pho"),
|
|
739
|
-
object:
|
|
1181
|
+
object: z12.literal("phone_number"),
|
|
740
1182
|
identity_id: idOf("idn"),
|
|
741
|
-
e164:
|
|
742
|
-
country:
|
|
743
|
-
capabilities:
|
|
1183
|
+
e164: z12.string(),
|
|
1184
|
+
country: z12.string(),
|
|
1185
|
+
capabilities: z12.object({
|
|
744
1186
|
/** Live the moment the number is bought — inbound never waits on carrier registration. */
|
|
745
|
-
sms_inbound:
|
|
1187
|
+
sms_inbound: z12.boolean(),
|
|
746
1188
|
/** True **iff** `campaign_status === "approved"`. Nothing else may set it. */
|
|
747
|
-
sms_outbound:
|
|
1189
|
+
sms_outbound: z12.boolean(),
|
|
748
1190
|
/** Voice is not a P2 capability; the field exists so its absence is explicit. */
|
|
749
|
-
voice:
|
|
1191
|
+
voice: z12.literal(false)
|
|
750
1192
|
}),
|
|
751
1193
|
tier: PhoneTierSchema,
|
|
752
1194
|
brand_status: BrandStatusSchema,
|
|
@@ -754,75 +1196,85 @@ var PhoneNumberSchema = z10.object({
|
|
|
754
1196
|
provisioned_at: Timestamp.nullable(),
|
|
755
1197
|
created_at: Timestamp
|
|
756
1198
|
});
|
|
757
|
-
var InboundMessageSchema =
|
|
1199
|
+
var InboundMessageSchema = z12.object({
|
|
758
1200
|
id: idOf("inb"),
|
|
759
|
-
object:
|
|
760
|
-
channel:
|
|
1201
|
+
object: z12.literal("inbound_message"),
|
|
1202
|
+
channel: z12.enum(["email", "sms"]),
|
|
761
1203
|
identity_id: idOf("idn"),
|
|
762
1204
|
/** The `eml_`/`pho_` endpoint it arrived at — the persona is decided by *where*, not by *who*. */
|
|
763
|
-
endpoint_id:
|
|
764
|
-
from:
|
|
765
|
-
to:
|
|
766
|
-
subject:
|
|
767
|
-
text:
|
|
1205
|
+
endpoint_id: z12.string(),
|
|
1206
|
+
from: z12.string(),
|
|
1207
|
+
to: z12.string(),
|
|
1208
|
+
subject: z12.string().nullable(),
|
|
1209
|
+
text: z12.string(),
|
|
768
1210
|
/** SPF/DKIM/DMARC for mail, carrier origin for SMS. Kept for the audit of why it was accepted. */
|
|
769
|
-
auth:
|
|
1211
|
+
auth: z12.record(z12.string(), z12.string()),
|
|
770
1212
|
/** The session this message woke. Null until the wake seam lands (see ADR-0120). */
|
|
771
1213
|
session_id: idOf("ses").nullable(),
|
|
772
1214
|
received_at: Timestamp
|
|
773
1215
|
});
|
|
774
1216
|
|
|
775
1217
|
// ../core/src/schema/app.ts
|
|
776
|
-
import { z as
|
|
777
|
-
var AppTypeSchema =
|
|
778
|
-
var AppStatusSchema =
|
|
779
|
-
var AppMcpPathSchema =
|
|
780
|
-
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({
|
|
781
1223
|
id: idOf("app"),
|
|
782
|
-
object:
|
|
783
|
-
name:
|
|
784
|
-
description:
|
|
1224
|
+
object: z13.literal("app"),
|
|
1225
|
+
name: z13.string(),
|
|
1226
|
+
description: z13.string().nullable(),
|
|
785
1227
|
type: AppTypeSchema,
|
|
786
1228
|
/**
|
|
787
1229
|
* The customer's own project name that made this app, or `null` for one made outside a project
|
|
788
1230
|
* (ADR-0375). Customer-visible, unlike the provider handles: it is the word the customer typed,
|
|
789
1231
|
* and the refusal that guards a name quotes it.
|
|
790
1232
|
*/
|
|
791
|
-
project:
|
|
1233
|
+
project: z13.string().nullable(),
|
|
792
1234
|
status: AppStatusSchema,
|
|
793
1235
|
/** The address the app answers on — platform hostname until a custom domain connects. */
|
|
794
|
-
url:
|
|
1236
|
+
url: z13.string().nullable(),
|
|
795
1237
|
/** White-label words when `status` is `error`; never the provider's. */
|
|
796
|
-
error:
|
|
1238
|
+
error: z13.string().nullable(),
|
|
797
1239
|
/** Where the app serves MCP, or `null`. The bearer token for it is a server column. */
|
|
798
1240
|
mcp: AppMcpPathSchema.nullable(),
|
|
799
1241
|
created_at: Timestamp
|
|
800
1242
|
});
|
|
801
|
-
var AppDeploymentStatusSchema =
|
|
802
|
-
var AppDeploymentSchema =
|
|
1243
|
+
var AppDeploymentStatusSchema = z13.enum(["queued", "building", "ready", "error"]);
|
|
1244
|
+
var AppDeploymentSchema = z13.object({
|
|
803
1245
|
id: idOf("apd"),
|
|
804
|
-
object:
|
|
1246
|
+
object: z13.literal("app_deployment"),
|
|
805
1247
|
app_id: idOf("app"),
|
|
806
1248
|
status: AppDeploymentStatusSchema,
|
|
807
|
-
url:
|
|
808
|
-
error:
|
|
1249
|
+
url: z13.string().nullable(),
|
|
1250
|
+
error: z13.string().nullable(),
|
|
809
1251
|
/** The client's opaque digest of the files, echoed verbatim so it can skip an unchanged deploy. */
|
|
810
|
-
content_hash:
|
|
1252
|
+
content_hash: z13.string().nullable(),
|
|
811
1253
|
created_at: Timestamp
|
|
812
1254
|
});
|
|
813
|
-
var
|
|
814
|
-
object:
|
|
815
|
-
|
|
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(),
|
|
816
1263
|
/** The client's opaque digest of the value, echoed verbatim so it can skip an unchanged write. */
|
|
817
|
-
value_hash:
|
|
1264
|
+
value_hash: z13.string().nullable(),
|
|
818
1265
|
created_at: Timestamp
|
|
819
1266
|
});
|
|
820
|
-
var
|
|
821
|
-
|
|
822
|
-
|
|
1267
|
+
var AppEntrySchema = z13.object({
|
|
1268
|
+
object: z13.literal("app_entry"),
|
|
1269
|
+
url: z13.string(),
|
|
1270
|
+
ticket: z13.string()
|
|
1271
|
+
});
|
|
1272
|
+
var AppDomainStatusSchema = z13.enum(["pending", "connected", "failed"]);
|
|
1273
|
+
var AppDomainSchema = z13.object({
|
|
1274
|
+
object: z13.literal("app_domain"),
|
|
823
1275
|
app_id: idOf("app"),
|
|
824
1276
|
domain_id: idOf("dom"),
|
|
825
|
-
domain:
|
|
1277
|
+
domain: z13.string(),
|
|
826
1278
|
status: AppDomainStatusSchema,
|
|
827
1279
|
created_at: Timestamp
|
|
828
1280
|
});
|
|
@@ -830,32 +1282,58 @@ var ENV_NAME = /^[A-Z_][A-Z0-9_]*$/;
|
|
|
830
1282
|
var APP_NAME = /^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$/;
|
|
831
1283
|
|
|
832
1284
|
// ../core/src/schema/install.ts
|
|
833
|
-
import { z as
|
|
834
|
-
var BlueprintInstallSourceSchema =
|
|
835
|
-
var
|
|
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),
|
|
1291
|
+
action: ResourceActionSchema,
|
|
1292
|
+
/** The `agt_`/`app_`/`ses_`… the line resolved to. Absent on a refusal that never got an id. */
|
|
1293
|
+
id: z14.string().optional(),
|
|
1294
|
+
/** An app's hostname once its build went live; `null` while it has none. Apps only. */
|
|
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({
|
|
836
1314
|
id: idOf("bpi"),
|
|
837
|
-
object:
|
|
1315
|
+
object: z14.literal("blueprint_install"),
|
|
838
1316
|
/** The customer's own `defineProject({ name })` — the same word `app.project` stamps (§29.2). */
|
|
839
|
-
project:
|
|
1317
|
+
project: z14.string().min(1),
|
|
840
1318
|
/** The pair the declaration resolved to; `null` for a declaration that names no blueprint. */
|
|
841
|
-
blueprint:
|
|
842
|
-
template:
|
|
1319
|
+
blueprint: z14.string().nullable(),
|
|
1320
|
+
template: z14.string().nullable(),
|
|
843
1321
|
/**
|
|
844
1322
|
* Applies, not versions of anything: 1 on the first apply, +1 on each one after, whichever writer
|
|
845
1323
|
* made it. It is not an agent version and it never rolls back.
|
|
846
1324
|
*/
|
|
847
|
-
revision:
|
|
1325
|
+
revision: z14.number().int().positive(),
|
|
848
1326
|
/**
|
|
849
1327
|
* The blueprint artifact version this came from, or `null` when it was applied from a working
|
|
850
1328
|
* tree — an operator editing a clone has no version to name.
|
|
851
1329
|
*/
|
|
852
|
-
artifact_version:
|
|
1330
|
+
artifact_version: z14.string().nullable(),
|
|
853
1331
|
/**
|
|
854
1332
|
* The setup answers this project was configured with (§7.1 fields, keyed by their `key`), so a
|
|
855
1333
|
* re-apply does not re-ask and both writers configure from the same answers. Configuration only:
|
|
856
1334
|
* a secret is a vault credential (§23) or an app secret (§29.2), and neither is ever an answer.
|
|
857
1335
|
*/
|
|
858
|
-
answers:
|
|
1336
|
+
answers: z14.record(z14.string(), z14.unknown()),
|
|
859
1337
|
/**
|
|
860
1338
|
* NO `declaration` ON THE WIRE, and that is the reconciliation of §29.6 with §31.1.
|
|
861
1339
|
*
|
|
@@ -869,85 +1347,160 @@ var BlueprintInstallSchema = z12.object({
|
|
|
869
1347
|
* has it, so nothing is lost by not saying it twice.
|
|
870
1348
|
*/
|
|
871
1349
|
source: BlueprintInstallSourceSchema,
|
|
1350
|
+
/**
|
|
1351
|
+
* WHAT THE APPLY DID, or `null` when it did nothing but record.
|
|
1352
|
+
*
|
|
1353
|
+
* An apply that sends its own `declaration` has already reconciled it — that is what `naive up`
|
|
1354
|
+
* is — so the row it writes is a record and this is `null`. An apply that names a **published**
|
|
1355
|
+
* pair has reconciled nothing: it was never given the bytes (§31.1), so the server reads them
|
|
1356
|
+
* from the catalog and runs the same engine over them, and this is what that run reported.
|
|
1357
|
+
*
|
|
1358
|
+
* It is stored rather than only returned because a refusal inside a successful apply — an app
|
|
1359
|
+
* whose `env` reads a variable no hosted run has, a session refused for credit — is the one fact
|
|
1360
|
+
* a person needs after the screen that showed it is gone.
|
|
1361
|
+
*/
|
|
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),
|
|
872
1373
|
applied_at: Timestamp,
|
|
873
1374
|
created_at: Timestamp
|
|
874
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
|
+
});
|
|
875
1393
|
|
|
876
1394
|
// ../core/src/schema/blueprint.ts
|
|
877
|
-
import { z as
|
|
878
|
-
var BlueprintScheduleSchema =
|
|
879
|
-
agent:
|
|
880
|
-
cron:
|
|
881
|
-
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(),
|
|
882
1400
|
/** The message each fire opens its session with — the sentence worth printing. */
|
|
883
|
-
input:
|
|
1401
|
+
input: z15.string().min(1),
|
|
884
1402
|
budget_micro_usd: MicroUsdField.nonnegative()
|
|
885
1403
|
});
|
|
886
|
-
var
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
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),
|
|
894
1420
|
type: AppTypeSchema,
|
|
895
|
-
description:
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
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({
|
|
1429
|
+
/** `apps[].name` in the declaration — the same name §31.5 prints and the install ensures by. */
|
|
1430
|
+
app: z15.string().min(1),
|
|
1431
|
+
content_hash: ContentHashSchema
|
|
1432
|
+
});
|
|
1433
|
+
var BlueprintArtifactSchema = z15.object({
|
|
899
1434
|
id: idOf("bpa"),
|
|
900
|
-
object:
|
|
1435
|
+
object: z15.literal("blueprint_artifact"),
|
|
901
1436
|
/** The machine — its repository, screens and `/api/*`. */
|
|
902
|
-
blueprint:
|
|
1437
|
+
blueprint: z15.string().min(1),
|
|
903
1438
|
/** Which of that blueprint's templates provides the crew. */
|
|
904
|
-
template:
|
|
1439
|
+
template: z15.string().min(1),
|
|
905
1440
|
/** The blueprint repository's own released version. Stored, never parsed (ADR-0401). */
|
|
906
|
-
version:
|
|
907
|
-
|
|
1441
|
+
version: z15.string().min(1),
|
|
1442
|
+
/**
|
|
1443
|
+
* The built trees, one per deployable app, ordered as the declaration orders its apps. Never
|
|
1444
|
+
* empty: an artifact that built nothing is not an artifact, and the column behind it says so
|
|
1445
|
+
* (migration 0040) exactly as the single `content_hash` it replaces was `not null`.
|
|
1446
|
+
*/
|
|
1447
|
+
trees: z15.array(BlueprintTreeSchema).min(1),
|
|
908
1448
|
/**
|
|
909
1449
|
* The setup questions, asked by the studio **before** provisioning. `QuestionField` (§7.1) is
|
|
910
1450
|
* reused rather than restated: a setup question and a question a parked agent asks are the same
|
|
911
1451
|
* object at different times, so one component renders both.
|
|
912
1452
|
*/
|
|
913
|
-
questions:
|
|
914
|
-
schedules:
|
|
1453
|
+
questions: z15.array(QuestionFieldSchema),
|
|
1454
|
+
schedules: z15.array(BlueprintScheduleSchema),
|
|
915
1455
|
/** Who the crew is, and what it deploys — §31.5. Derived from `declaration`, never stored twice. */
|
|
916
|
-
agents:
|
|
917
|
-
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(),
|
|
918
1471
|
published_at: Timestamp
|
|
919
1472
|
});
|
|
920
1473
|
|
|
921
1474
|
// ../core/src/schema/vault.ts
|
|
922
|
-
import { z as
|
|
923
|
-
var VaultCredentialKindSchema =
|
|
924
|
-
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({
|
|
925
1478
|
id: idOf("vlt"),
|
|
926
|
-
object:
|
|
1479
|
+
object: z16.literal("vault"),
|
|
927
1480
|
identity_id: idOf("idn").nullable(),
|
|
928
|
-
display_name:
|
|
929
|
-
credential_count:
|
|
1481
|
+
display_name: z16.string().min(1).max(128),
|
|
1482
|
+
credential_count: z16.number().int().nonnegative(),
|
|
930
1483
|
created_at: Timestamp
|
|
931
1484
|
});
|
|
932
|
-
var VaultCredentialSchema =
|
|
1485
|
+
var VaultCredentialSchema = z16.object({
|
|
933
1486
|
id: idOf("vcr"),
|
|
934
|
-
object:
|
|
1487
|
+
object: z16.literal("vault_credential"),
|
|
935
1488
|
vault_id: idOf("vlt"),
|
|
936
1489
|
kind: VaultCredentialKindSchema,
|
|
937
1490
|
/** For `env_var`, the environment variable name. For the MCP kinds, a display label. */
|
|
938
|
-
key:
|
|
1491
|
+
key: z16.string().min(1).max(128),
|
|
939
1492
|
/** The exact destination host an `env_var` credential is bound to. Never a wildcard. */
|
|
940
|
-
host:
|
|
1493
|
+
host: z16.string().nullable(),
|
|
941
1494
|
/** The exact MCP server URL an `mcp_*` token is matched to. */
|
|
942
|
-
mcp_server_url:
|
|
943
|
-
placeholder_ref:
|
|
1495
|
+
mcp_server_url: z16.url().nullable(),
|
|
1496
|
+
placeholder_ref: z16.string(),
|
|
944
1497
|
expires_at: Timestamp.nullable(),
|
|
945
1498
|
last_injected_at: Timestamp.nullable(),
|
|
946
1499
|
created_at: Timestamp
|
|
947
1500
|
});
|
|
948
1501
|
|
|
949
1502
|
// ../core/src/schema/social.ts
|
|
950
|
-
import { z as
|
|
1503
|
+
import { z as z17 } from "zod";
|
|
951
1504
|
var SOCIAL_PLATFORMS = [
|
|
952
1505
|
"bluesky",
|
|
953
1506
|
"facebook",
|
|
@@ -969,19 +1522,27 @@ var SOCIAL_TEXT_PLATFORMS = [
|
|
|
969
1522
|
"threads",
|
|
970
1523
|
"x"
|
|
971
1524
|
];
|
|
972
|
-
var
|
|
973
|
-
var
|
|
974
|
-
var
|
|
975
|
-
|
|
976
|
-
|
|
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"),
|
|
977
1538
|
identity_id: idOf("idn"),
|
|
978
1539
|
platform: SocialPlatformSchema,
|
|
979
|
-
username:
|
|
980
|
-
display_name:
|
|
981
|
-
avatar_url:
|
|
1540
|
+
username: z17.string().nullable(),
|
|
1541
|
+
display_name: z17.string().nullable(),
|
|
1542
|
+
avatar_url: z17.url().nullable(),
|
|
982
1543
|
connected_at: Timestamp.nullable()
|
|
983
1544
|
});
|
|
984
|
-
var SocialPostStatusSchema =
|
|
1545
|
+
var SocialPostStatusSchema = z17.enum([
|
|
985
1546
|
"draft",
|
|
986
1547
|
"scheduled",
|
|
987
1548
|
"processing",
|
|
@@ -989,51 +1550,932 @@ var SocialPostStatusSchema = z15.enum([
|
|
|
989
1550
|
"failed",
|
|
990
1551
|
"deleted"
|
|
991
1552
|
]);
|
|
992
|
-
var SocialPostSchema =
|
|
993
|
-
id:
|
|
994
|
-
object:
|
|
1553
|
+
var SocialPostSchema = z17.object({
|
|
1554
|
+
id: z17.string().min(1),
|
|
1555
|
+
object: z17.literal("social_post"),
|
|
995
1556
|
identity_id: idOf("idn"),
|
|
996
|
-
title:
|
|
997
|
-
platforms:
|
|
1557
|
+
title: z17.string(),
|
|
1558
|
+
platforms: z17.array(SocialPlatformSchema),
|
|
998
1559
|
status: SocialPostStatusSchema,
|
|
999
1560
|
scheduled_at: Timestamp.nullable(),
|
|
1000
1561
|
posted_at: Timestamp.nullable(),
|
|
1001
|
-
error:
|
|
1562
|
+
error: z17.string().nullable()
|
|
1002
1563
|
});
|
|
1003
|
-
var SocialUploadSchema =
|
|
1004
|
-
id:
|
|
1005
|
-
object:
|
|
1564
|
+
var SocialUploadSchema = z17.object({
|
|
1565
|
+
id: z17.string().min(1),
|
|
1566
|
+
object: z17.literal("social_upload"),
|
|
1006
1567
|
identity_id: idOf("idn"),
|
|
1007
|
-
type:
|
|
1008
|
-
url:
|
|
1568
|
+
type: z17.enum(["image", "video", "document"]),
|
|
1569
|
+
url: z17.url().nullable()
|
|
1009
1570
|
});
|
|
1010
|
-
var SocialAnalyticsSchema =
|
|
1011
|
-
object:
|
|
1571
|
+
var SocialAnalyticsSchema = z17.object({
|
|
1572
|
+
object: z17.literal("social_analytics"),
|
|
1012
1573
|
identity_id: idOf("idn"),
|
|
1013
|
-
resource_id:
|
|
1574
|
+
resource_id: z17.string().min(1),
|
|
1014
1575
|
platform: SocialPlatformSchema.nullable(),
|
|
1015
|
-
data:
|
|
1576
|
+
data: z17.unknown()
|
|
1016
1577
|
});
|
|
1017
|
-
var SocialCommentSchema =
|
|
1018
|
-
id:
|
|
1019
|
-
object:
|
|
1578
|
+
var SocialCommentSchema = z17.object({
|
|
1579
|
+
id: z17.string().min(1),
|
|
1580
|
+
object: z17.literal("social_comment"),
|
|
1020
1581
|
identity_id: idOf("idn"),
|
|
1021
|
-
post_id:
|
|
1022
|
-
platforms:
|
|
1582
|
+
post_id: z17.string().min(1),
|
|
1583
|
+
platforms: z17.array(SocialPlatformSchema),
|
|
1023
1584
|
status: SocialPostStatusSchema,
|
|
1024
1585
|
posted_at: Timestamp.nullable(),
|
|
1025
|
-
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()
|
|
1026
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
|
+
}
|
|
1027
2410
|
|
|
1028
|
-
// src/
|
|
1029
|
-
|
|
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
|
+
}
|
|
1030
2470
|
|
|
1031
2471
|
// src/template.ts
|
|
1032
2472
|
var BLUEPRINTS = {
|
|
1033
2473
|
/** Clients, pipeline, deliverables, calendar. */
|
|
1034
2474
|
agency: { templates: ["blank", "seo-geo"], default: "blank" },
|
|
1035
2475
|
/** Post queue, accounts, calendar, analytics. */
|
|
1036
|
-
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" }
|
|
1037
2479
|
};
|
|
1038
2480
|
var list = (names) => names.join(", ");
|
|
1039
2481
|
function chooseTemplate(blueprint, template) {
|
|
@@ -1065,43 +2507,67 @@ function chooseTemplate(blueprint, template) {
|
|
|
1065
2507
|
var BlueprintRefusal = class extends Error {
|
|
1066
2508
|
name = "BlueprintRefusal";
|
|
1067
2509
|
};
|
|
1068
|
-
var EnvValueSchema =
|
|
1069
|
-
|
|
2510
|
+
var EnvValueSchema = z27.union([
|
|
2511
|
+
z27.string(),
|
|
2512
|
+
z27.object({ from_env: z27.string().min(1) }),
|
|
2513
|
+
z27.object({ generate: z27.literal(true) })
|
|
2514
|
+
]);
|
|
2515
|
+
var AppDeclSchema = z27.object({
|
|
1070
2516
|
/** Becomes a hostname, so the grammar is the platform's `APP_NAME` (a DNS label). */
|
|
1071
|
-
name:
|
|
2517
|
+
name: z27.string().regex(APP_NAME, "a lowercase DNS label, 63 characters or fewer"),
|
|
1072
2518
|
type: AppTypeSchema,
|
|
1073
|
-
description:
|
|
2519
|
+
description: z27.string().optional(),
|
|
1074
2520
|
/** A directory whose files are collected and shipped as the app's file-map deployment. */
|
|
1075
|
-
deploy_dir:
|
|
2521
|
+
deploy_dir: z27.string().min(1).optional(),
|
|
1076
2522
|
/** The path the app itself serves MCP on (§29.5); `fullstack` only. Absent means none. */
|
|
1077
2523
|
mcp: AppMcpPathSchema.optional(),
|
|
1078
2524
|
/** Written as the app's write-only secrets (§29.2) on every apply; names follow the platform's `ENV_NAME`. */
|
|
1079
|
-
env:
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
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(),
|
|
1084
2538
|
/** The message every fire opens its session with (`input_template` on the wire). */
|
|
1085
|
-
input:
|
|
2539
|
+
input: z27.string().min(1),
|
|
1086
2540
|
budget_micro_usd: MicroUsdField.nonnegative(),
|
|
1087
|
-
identity:
|
|
1088
|
-
enabled:
|
|
2541
|
+
identity: z27.string().min(1).optional(),
|
|
2542
|
+
enabled: z27.boolean().optional()
|
|
1089
2543
|
});
|
|
1090
|
-
var
|
|
1091
|
-
|
|
1092
|
-
|
|
2544
|
+
var ToolsDeclSchema = ToolsetSchema;
|
|
2545
|
+
var AgentDeclSchema = z27.object({
|
|
2546
|
+
name: z27.string().min(1),
|
|
2547
|
+
model: z27.string().min(1),
|
|
1093
2548
|
budget: BudgetSchema,
|
|
1094
|
-
description:
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
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(),
|
|
1099
2565
|
/** Declared app *names*; `up` resolves them to `app_` ids in `tools.configs.apps` (§29.3). */
|
|
1100
|
-
allowed_apps:
|
|
2566
|
+
allowed_apps: z27.array(z27.string()).optional(),
|
|
1101
2567
|
/** A declared identity *name*; `up` attaches it after the agent upsert (§22). */
|
|
1102
|
-
identity:
|
|
2568
|
+
identity: z27.string().min(1).optional(),
|
|
1103
2569
|
/** The agent's deployments as a complete set: declared → owned, and the rest are pruned (ADR-0355). */
|
|
1104
|
-
schedules:
|
|
2570
|
+
schedules: z27.array(ScheduleDeclSchema).optional(),
|
|
1105
2571
|
/**
|
|
1106
2572
|
* The first thing this agent reads, once, on the apply that **creates** it (`canonical-spec
|
|
1107
2573
|
* §31.4`). It is what turns a provisioned crew into a crew that has started working.
|
|
@@ -1114,43 +2580,58 @@ var AgentDeclSchema = z16.object({
|
|
|
1114
2580
|
* repeatedly and unattended while an intake spends once, at an apply a person is watching. Absent
|
|
1115
2581
|
* means the agent's own `budget` governs.
|
|
1116
2582
|
*/
|
|
1117
|
-
intake:
|
|
2583
|
+
intake: z27.object({ message: z27.string().min(1), budget_micro_usd: MicroUsdField.nonnegative().optional() }).optional()
|
|
1118
2584
|
});
|
|
1119
|
-
var CredentialDeclSchema =
|
|
2585
|
+
var CredentialDeclSchema = z27.object({
|
|
1120
2586
|
kind: VaultCredentialKindSchema,
|
|
1121
|
-
key:
|
|
2587
|
+
key: z27.string().min(1).max(128),
|
|
1122
2588
|
/** The one exact destination host an `env_var` is bound to. */
|
|
1123
|
-
host:
|
|
2589
|
+
host: z27.string().min(1).optional(),
|
|
1124
2590
|
/** The MCP server URL a `static_bearer` / `mcp_oauth` token is matched to. */
|
|
1125
|
-
mcp_server_url:
|
|
1126
|
-
value:
|
|
2591
|
+
mcp_server_url: z27.url().optional(),
|
|
2592
|
+
value: z27.object({ from_env: z27.string().min(1) })
|
|
1127
2593
|
});
|
|
1128
|
-
var VaultDeclSchema =
|
|
2594
|
+
var VaultDeclSchema = z27.object({
|
|
1129
2595
|
name: VaultSchema.shape.display_name,
|
|
1130
|
-
identity:
|
|
1131
|
-
credentials:
|
|
2596
|
+
identity: z27.string().min(1).optional(),
|
|
2597
|
+
credentials: z27.array(CredentialDeclSchema)
|
|
1132
2598
|
});
|
|
1133
|
-
var SkillDeclSchema =
|
|
1134
|
-
slug:
|
|
1135
|
-
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)
|
|
1136
2602
|
});
|
|
1137
|
-
var
|
|
2603
|
+
var LegalDeclSchema = CreateLegalCompanySchema.pick({
|
|
2604
|
+
state: true,
|
|
2605
|
+
name_options: true,
|
|
2606
|
+
naics_code: true,
|
|
1138
2607
|
description: true
|
|
1139
|
-
});
|
|
1140
|
-
var
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
var
|
|
1148
|
-
|
|
1149
|
-
|
|
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),
|
|
1150
2631
|
/** The machine this project runs: its repo, its screens, its `/api/*` (`template.ts`). */
|
|
1151
|
-
blueprint:
|
|
2632
|
+
blueprint: z27.string().min(1).optional(),
|
|
1152
2633
|
/** Which of that blueprint's templates provides the crew; a blueprint with a default may omit it. */
|
|
1153
|
-
template:
|
|
2634
|
+
template: z27.string().min(1).optional(),
|
|
1154
2635
|
/**
|
|
1155
2636
|
* What a person is asked BEFORE the crew is provisioned (`canonical-spec §31.2`).
|
|
1156
2637
|
*
|
|
@@ -1162,12 +2643,19 @@ var ProjectSchema = z16.object({
|
|
|
1162
2643
|
*
|
|
1163
2644
|
* **Configuration only.** A secret is a vault credential or an app secret; neither is an answer.
|
|
1164
2645
|
*/
|
|
1165
|
-
questions:
|
|
1166
|
-
skills:
|
|
1167
|
-
identities:
|
|
1168
|
-
vaults:
|
|
1169
|
-
apps:
|
|
1170
|
-
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(),
|
|
1171
2659
|
removed: RemovedSchema.default({ apps: [], agents: [], skills: [], identities: [], vaults: [] }),
|
|
1172
2660
|
kept: KeptSchema.default({ agents: [] })
|
|
1173
2661
|
});
|
|
@@ -1198,11 +2686,19 @@ function applyChoice(config) {
|
|
|
1198
2686
|
function parseProject(input) {
|
|
1199
2687
|
const parsed = ProjectSchema.safeParse(input);
|
|
1200
2688
|
if (!parsed.success) {
|
|
1201
|
-
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}`);
|
|
1202
2695
|
refuse(`invalid project config \u2014 ${lines.join("; ")}`);
|
|
1203
2696
|
}
|
|
1204
2697
|
const config = parsed.data;
|
|
1205
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
|
+
}
|
|
1206
2702
|
assertUniqueNames("app", [...config.apps.map((a) => a.name), ...config.removed.apps]);
|
|
1207
2703
|
assertUniqueNames("agent", [...config.agents.map((a) => a.name), ...config.removed.agents, ...config.kept.agents]);
|
|
1208
2704
|
assertUniqueNames("skill", [...config.skills.map((s) => s.slug), ...config.removed.skills]);
|
|
@@ -1213,6 +2709,13 @@ function parseProject(input) {
|
|
|
1213
2709
|
if (app.type === "frontend_only" && app.mcp !== void 0) {
|
|
1214
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`);
|
|
1215
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));
|
|
1216
2719
|
}
|
|
1217
2720
|
const identityNames = new Set(config.identities.map((i) => i.name));
|
|
1218
2721
|
for (const vault of config.vaults) {
|
|
@@ -1233,7 +2736,16 @@ function parseProject(input) {
|
|
|
1233
2736
|
seen.add(at);
|
|
1234
2737
|
}
|
|
1235
2738
|
}
|
|
2739
|
+
const agentNames = /* @__PURE__ */ new Set([...config.agents.map((a) => a.name), ...config.kept.agents]);
|
|
1236
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
|
+
}
|
|
1237
2749
|
for (const name of agent.allowed_apps ?? []) {
|
|
1238
2750
|
if (!appNames.has(name)) {
|
|
1239
2751
|
refuse(`agent "${agent.name}": allowed_apps names "${name}", but no app with that name is declared in this project`);
|
|
@@ -1291,7 +2803,7 @@ function isMissingModule(error) {
|
|
|
1291
2803
|
const code = error?.code;
|
|
1292
2804
|
return code === "ERR_MODULE_NOT_FOUND" || code === "MODULE_NOT_FOUND";
|
|
1293
2805
|
}
|
|
1294
|
-
function
|
|
2806
|
+
function message2(error) {
|
|
1295
2807
|
return error instanceof Error ? error.message : String(error);
|
|
1296
2808
|
}
|
|
1297
2809
|
function validate(path, raw) {
|
|
@@ -1315,7 +2827,7 @@ async function loadConfig(dir) {
|
|
|
1315
2827
|
try {
|
|
1316
2828
|
return validate(path, JSON.parse(readFileSync(path, "utf8")));
|
|
1317
2829
|
} catch (error) {
|
|
1318
|
-
if (error instanceof SyntaxError) return { ok: false, reason: "invalid", message:
|
|
2830
|
+
if (error instanceof SyntaxError) return { ok: false, reason: "invalid", message: message2(error) };
|
|
1319
2831
|
throw error;
|
|
1320
2832
|
}
|
|
1321
2833
|
}
|
|
@@ -1324,14 +2836,14 @@ async function loadConfig(dir) {
|
|
|
1324
2836
|
const { createJiti } = await import("jiti");
|
|
1325
2837
|
importFile = createJiti(pathToFileURL(path).href).import;
|
|
1326
2838
|
} catch (error) {
|
|
1327
|
-
return { ok: false, reason: "unloadable", message:
|
|
2839
|
+
return { ok: false, reason: "unloadable", message: message2(error) };
|
|
1328
2840
|
}
|
|
1329
2841
|
let raw;
|
|
1330
2842
|
try {
|
|
1331
2843
|
const mod = await importFile(path);
|
|
1332
2844
|
raw = mod?.default ?? mod;
|
|
1333
2845
|
} catch (error) {
|
|
1334
|
-
return { ok: false, reason: isMissingModule(error) ? "unloadable" : "invalid", message:
|
|
2846
|
+
return { ok: false, reason: isMissingModule(error) ? "unloadable" : "invalid", message: message2(error) };
|
|
1335
2847
|
}
|
|
1336
2848
|
if (raw === null || typeof raw !== "object") {
|
|
1337
2849
|
return {
|
|
@@ -1387,78 +2899,30 @@ function contentHash(files) {
|
|
|
1387
2899
|
|
|
1388
2900
|
// src/up.ts
|
|
1389
2901
|
import { createHash as createHash3 } from "node:crypto";
|
|
1390
|
-
import { readFileSync as
|
|
1391
|
-
import { resolve as
|
|
2902
|
+
import { readFileSync as readFileSync4 } from "node:fs";
|
|
2903
|
+
import { resolve as resolve4 } from "node:path";
|
|
1392
2904
|
|
|
1393
|
-
// src/
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
return
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
}
|
|
1406
|
-
into.push(line);
|
|
1407
|
-
return line;
|
|
1408
|
-
}
|
|
1409
|
-
var canonical = (value) => {
|
|
1410
|
-
if (Array.isArray(value)) return value.map(canonical);
|
|
1411
|
-
if (value === null || typeof value !== "object") return value;
|
|
1412
|
-
return Object.fromEntries(
|
|
1413
|
-
Object.keys(value).sort().map((key) => [key, canonical(value[key])])
|
|
1414
|
-
);
|
|
1415
|
-
};
|
|
1416
|
-
var changed = (declared, live) => declared !== void 0 && JSON.stringify(canonical(declared)) !== JSON.stringify(canonical(live));
|
|
1417
|
-
async function absent(work) {
|
|
1418
|
-
try {
|
|
1419
|
-
return await work;
|
|
1420
|
-
} catch (error) {
|
|
1421
|
-
if (error instanceof ApiError && error.status === 404) return null;
|
|
1422
|
-
throw error;
|
|
1423
|
-
}
|
|
1424
|
-
}
|
|
1425
|
-
var PageShape = z17.object({
|
|
1426
|
-
data: z17.array(z17.unknown()),
|
|
1427
|
-
has_more: z17.boolean(),
|
|
1428
|
-
next_cursor: z17.string().nullable()
|
|
1429
|
-
});
|
|
1430
|
-
function rowLabel(row) {
|
|
1431
|
-
const { object, id } = row ?? {};
|
|
1432
|
-
const words = [object, id].filter((one) => typeof one === "string");
|
|
1433
|
-
return words.length > 0 ? words.join(" ") : "a row";
|
|
1434
|
-
}
|
|
1435
|
-
var why = (error) => error.issues.map((issue) => `${issue.path.join(".") || "(root)"}: ${issue.message}`).join("; ");
|
|
1436
|
-
async function listAll(config, path, item, skipped, query = {}) {
|
|
1437
|
-
const rows = [];
|
|
1438
|
-
let after;
|
|
1439
|
-
for (; ; ) {
|
|
1440
|
-
const response = await send(config, { method: "GET", path, query: { ...query, limit: 100, after } }, "application/json");
|
|
1441
|
-
const text = await response.text();
|
|
1442
|
-
if (!response.ok) throw new Error(`could not list ${path} (HTTP ${response.status})`);
|
|
1443
|
-
const body = PageShape.parse(JSON.parse(text));
|
|
1444
|
-
for (const row of body.data) {
|
|
1445
|
-
const parsed = item.safeParse(row);
|
|
1446
|
-
if (parsed.success) rows.push(parsed.data);
|
|
1447
|
-
else skipped.push(`${rowLabel(row)} in ${path} could not be read and was skipped: ${why(parsed.error)}`);
|
|
1448
|
-
}
|
|
1449
|
-
if (!body.has_more || body.next_cursor === null) return rows;
|
|
1450
|
-
after = body.next_cursor;
|
|
1451
|
-
}
|
|
1452
|
-
}
|
|
1453
|
-
async function tombstone(name, current, remove, dryRun) {
|
|
1454
|
-
if (!current) return { name, action: "unchanged", reason: "already absent" };
|
|
1455
|
-
if (!dryRun) await remove(current.id);
|
|
1456
|
-
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
|
+
};
|
|
1457
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}
|
|
1458
2921
|
|
|
1459
|
-
|
|
2922
|
+
${decl.system}`;
|
|
2923
|
+
}
|
|
1460
2924
|
function desiredTools(decl, current, ids) {
|
|
1461
|
-
if (
|
|
2925
|
+
if (ids === void 0) return decl.tools;
|
|
1462
2926
|
const base = decl.tools ?? current?.tools ?? { default_config: { permission: "allow" }, configs: {} };
|
|
1463
2927
|
const appsTool = base.configs["apps"] ?? { enabled: true, permission: base.default_config.permission };
|
|
1464
2928
|
return {
|
|
@@ -1469,39 +2933,42 @@ function desiredTools(decl, current, ids) {
|
|
|
1469
2933
|
}
|
|
1470
2934
|
};
|
|
1471
2935
|
}
|
|
1472
|
-
async function createAgent(client, decl, tools, identityId) {
|
|
2936
|
+
async function createAgent(client, decl, tools, team, identityId, system, metadata) {
|
|
1473
2937
|
const created = await client.agents.create({
|
|
1474
2938
|
name: decl.name,
|
|
1475
2939
|
model: decl.model,
|
|
1476
2940
|
budget: decl.budget,
|
|
1477
2941
|
...decl.description !== void 0 ? { description: decl.description } : {},
|
|
1478
|
-
...
|
|
2942
|
+
...system !== void 0 ? { system } : {},
|
|
1479
2943
|
...decl.skills !== void 0 ? { skills: decl.skills } : {},
|
|
1480
2944
|
...decl.mcp_servers !== void 0 ? { mcp_servers: decl.mcp_servers } : {},
|
|
1481
|
-
...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 } : {}
|
|
1482
2951
|
});
|
|
1483
2952
|
if (identityId !== void 0) await client.identities.attach(created.id, identityId);
|
|
1484
2953
|
return { name: decl.name, action: "created", id: created.id };
|
|
1485
2954
|
}
|
|
1486
|
-
async function upsertAgent(client, decl, existing, ids, dryRun) {
|
|
2955
|
+
async function upsertAgent(client, decl, existing, ids, dryRun, scoped, of) {
|
|
1487
2956
|
const unresolved = (decl.allowed_apps ?? []).filter((name) => !ids.apps.has(name));
|
|
1488
2957
|
const identityId = decl.identity === void 0 ? void 0 : ids.identities.get(decl.identity);
|
|
1489
2958
|
const missing = unresolved.length > 0 ? `allowed_apps needs app "${unresolved[0]}"` : decl.identity !== void 0 && identityId === void 0 ? `identity needs "${decl.identity}"` : null;
|
|
1490
2959
|
if (missing !== null && !dryRun) {
|
|
1491
2960
|
return { name: decl.name, action: "refused", reason: `${missing}, which was not provisioned in this run` };
|
|
1492
2961
|
}
|
|
1493
|
-
const appIds =
|
|
2962
|
+
const appIds = decl.allowed_apps !== void 0 ? decl.allowed_apps.flatMap((name) => ids.apps.get(name) ?? []) : scoped;
|
|
1494
2963
|
const current = existing.find((agent) => agent.name === decl.name) ?? null;
|
|
1495
2964
|
const tools = desiredTools(decl, current, appIds);
|
|
1496
|
-
|
|
1497
|
-
const
|
|
1498
|
-
|
|
1499
|
-
if (
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
if (changed(decl.mcp_servers, current.mcp_servers)) patch.mcp_servers = decl.mcp_servers;
|
|
1504
|
-
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);
|
|
1505
2972
|
const held = identityId === void 0 ? [] : (await client.identities.held(current.id)).data;
|
|
1506
2973
|
const grant = identityId === void 0 || held.some((one) => one.id === identityId) ? null : identityId;
|
|
1507
2974
|
const drifted = Object.keys(patch).length > 0 || missing !== null || grant !== null;
|
|
@@ -1512,6 +2979,22 @@ async function upsertAgent(client, decl, existing, ids, dryRun) {
|
|
|
1512
2979
|
}
|
|
1513
2980
|
return { name: decl.name, action: "updated", id: current.id };
|
|
1514
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
|
+
}
|
|
1515
2998
|
async function openIntake(client, agent, decl, dryRun) {
|
|
1516
2999
|
if (dryRun || agent.id === void 0) return { name: agent.name, action: "created" };
|
|
1517
3000
|
const started = await client.sessions.create({
|
|
@@ -1552,10 +3035,15 @@ async function upsertSchedule(client, agent, decl, current, identityIds, dryRun)
|
|
|
1552
3035
|
}
|
|
1553
3036
|
async function reconcileSchedules(client, agent, declared, live, identityIds, dryRun, into) {
|
|
1554
3037
|
const rows = live.filter((row) => row.agent_id === agent.id);
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
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
|
+
);
|
|
1559
3047
|
for (const row of rows.filter((row2) => !declared.some((decl) => decl.cron === row2.cron))) {
|
|
1560
3048
|
const name = `${agent.name} @ ${row.cron}`;
|
|
1561
3049
|
await attempt(into, name, () => tombstone(name, row, (id) => client.deployments.delete(id), dryRun));
|
|
@@ -1563,8 +3051,60 @@ async function reconcileSchedules(client, agent, declared, live, identityIds, dr
|
|
|
1563
3051
|
}
|
|
1564
3052
|
|
|
1565
3053
|
// src/apps.ts
|
|
1566
|
-
import { createHash as createHash2 } from "node:crypto";
|
|
1567
|
-
import { resolve as
|
|
3054
|
+
import { createHash as createHash2, randomBytes } from "node:crypto";
|
|
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
|
|
1568
3108
|
async function findApp(client, name, skipped) {
|
|
1569
3109
|
const rows = await listAll(client.config, "/v1/apps", AppSchema, skipped, { name });
|
|
1570
3110
|
return rows.find((app) => app.name === name) ?? null;
|
|
@@ -1575,31 +3115,83 @@ function ownershipRefusal(name, project, owner) {
|
|
|
1575
3115
|
return `app "${name}" is owned by ${held}; this project is "${project}". Rename the app in your config, or re-run \`naive up --adopt\` to ${verb} it.`;
|
|
1576
3116
|
}
|
|
1577
3117
|
var ensureApp = (client, body) => client.apps.create(body);
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
3118
|
+
var PLATFORM_ENV = {
|
|
3119
|
+
/** The base URL of the API this apply ran through. */
|
|
3120
|
+
api_url: "NAIVE_API_URL",
|
|
3121
|
+
/** The identity the install runs as, when the declaration declares exactly one. */
|
|
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",
|
|
3125
|
+
/** A scoped organization API key minted for the app that asks for it. */
|
|
3126
|
+
api_key: "NAIVE_API_KEY"
|
|
3127
|
+
};
|
|
3128
|
+
function planEnv(decl, opts) {
|
|
3129
|
+
if (decl.env === void 0) return [];
|
|
3130
|
+
const plan = /* @__PURE__ */ new Map();
|
|
3131
|
+
for (const [name, value] of Object.entries(decl.env)) {
|
|
1581
3132
|
if (typeof value === "string") {
|
|
1582
|
-
|
|
3133
|
+
plan.set(name, { name, value });
|
|
1583
3134
|
continue;
|
|
1584
3135
|
}
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
3136
|
+
if ("generate" in value) {
|
|
3137
|
+
plan.set(name, { name, invent: async () => generated() });
|
|
3138
|
+
continue;
|
|
3139
|
+
}
|
|
3140
|
+
const known = opts.platform?.known[value.from_env];
|
|
3141
|
+
const mint = opts.platform?.minted?.[value.from_env];
|
|
3142
|
+
if (known !== void 0) plan.set(name, { name, value: known });
|
|
3143
|
+
else if (mint !== void 0) plan.set(name, { name, invent: () => mint(decl.name) });
|
|
3144
|
+
else {
|
|
3145
|
+
const local = opts.env[value.from_env];
|
|
3146
|
+
if (local === void 0) throw new Error(`env ${name} reads local variable ${value.from_env}, which is not set`);
|
|
3147
|
+
plan.set(name, { name, value: local });
|
|
3148
|
+
}
|
|
3149
|
+
}
|
|
3150
|
+
for (const [name, value] of Object.entries(opts.platform?.known ?? {})) plan.set(name, { name, value });
|
|
3151
|
+
return [...plan.values()];
|
|
3152
|
+
}
|
|
3153
|
+
async function materialize(plan, held, dryRun) {
|
|
3154
|
+
const values = {};
|
|
3155
|
+
const unmade = [];
|
|
3156
|
+
for (const one of plan) {
|
|
3157
|
+
if (one.value !== void 0) values[one.name] = one.value;
|
|
3158
|
+
else if (held.has(one.name)) continue;
|
|
3159
|
+
else if (dryRun) unmade.push(one.name);
|
|
3160
|
+
else values[one.name] = await invent(one);
|
|
3161
|
+
}
|
|
3162
|
+
return { values, unmade };
|
|
3163
|
+
}
|
|
3164
|
+
async function invent(one) {
|
|
3165
|
+
try {
|
|
3166
|
+
return await one.invent();
|
|
3167
|
+
} catch (cause) {
|
|
3168
|
+
throw new Error(
|
|
3169
|
+
`env ${one.name} is provisioned by the platform, and could not be: ${cause instanceof Error ? cause.message : String(cause)}`
|
|
3170
|
+
);
|
|
1588
3171
|
}
|
|
1589
|
-
return env;
|
|
1590
3172
|
}
|
|
3173
|
+
var generated = () => randomBytes(32).toString("base64url");
|
|
3174
|
+
var EMPTY = /* @__PURE__ */ new Set();
|
|
1591
3175
|
function secretHash(name, value) {
|
|
1592
3176
|
return createHash2("sha256").update(`${name}\0`).update(value).digest("hex");
|
|
1593
3177
|
}
|
|
1594
|
-
function
|
|
3178
|
+
function builtTree(decl, opts) {
|
|
1595
3179
|
if (!decl.deploy_dir) return null;
|
|
1596
|
-
const
|
|
3180
|
+
const hosted = opts.trees;
|
|
3181
|
+
if (hosted !== void 0 && hosted[decl.name] === void 0) {
|
|
3182
|
+
const failed = opts.tree_errors?.[decl.name];
|
|
3183
|
+
throw new Error(
|
|
3184
|
+
`app "${decl.name}" declares deploy_dir "${decl.deploy_dir}", but this apply was handed no built tree for it` + (failed === void 0 ? "" : `: ${failed}`)
|
|
3185
|
+
);
|
|
3186
|
+
}
|
|
3187
|
+
const files = collectFiles(hosted?.[decl.name] ?? resolve3(opts.dir, decl.deploy_dir));
|
|
1597
3188
|
return { files, hash: contentHash(files) };
|
|
1598
3189
|
}
|
|
1599
3190
|
async function writeApp(client, id, env, tree) {
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
3191
|
+
await eachInFlight(
|
|
3192
|
+
Object.entries(env),
|
|
3193
|
+
([name, value]) => client.apps.setSecret(id, { name, value, value_hash: secretHash(name, value) })
|
|
3194
|
+
);
|
|
1603
3195
|
if (!tree) return;
|
|
1604
3196
|
await client.apps.deploy(id, tree.files, tree.hash);
|
|
1605
3197
|
await settleDeploy(client, id);
|
|
@@ -1610,10 +3202,10 @@ async function settleDeploy(client, id) {
|
|
|
1610
3202
|
for (let poll = 0; poll < SETTLE_TRIES; poll++) {
|
|
1611
3203
|
const newest = (await client.apps.deployments(id, { limit: 1 })).data[0];
|
|
1612
3204
|
if (newest === void 0 || newest.status === "ready" || newest.status === "error") return;
|
|
1613
|
-
await new Promise((
|
|
3205
|
+
await new Promise((resolve5) => setTimeout(resolve5, SETTLE_MS));
|
|
1614
3206
|
}
|
|
1615
3207
|
}
|
|
1616
|
-
async function createApp(client, decl, env, opts, appIds) {
|
|
3208
|
+
async function createApp(client, decl, env, tree, migrations, opts, appIds) {
|
|
1617
3209
|
const created = await ensureApp(client, {
|
|
1618
3210
|
name: decl.name,
|
|
1619
3211
|
type: decl.type,
|
|
@@ -1622,14 +3214,25 @@ async function createApp(client, decl, env, opts, appIds) {
|
|
|
1622
3214
|
...decl.mcp !== void 0 ? { mcp: decl.mcp } : {}
|
|
1623
3215
|
});
|
|
1624
3216
|
appIds.set(decl.name, created.id);
|
|
1625
|
-
await writeApp(client, created.id, env,
|
|
1626
|
-
|
|
3217
|
+
await writeApp(client, created.id, env, tree);
|
|
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
|
+
};
|
|
1627
3228
|
}
|
|
1628
3229
|
async function upsertApp(client, decl, opts, appIds) {
|
|
1629
|
-
const
|
|
1630
|
-
const names =
|
|
3230
|
+
const declared = planEnv(decl, opts);
|
|
3231
|
+
const names = declared.map((one) => one.name);
|
|
1631
3232
|
const note = (notes) => notes.length > 0 ? { reason: notes.join("; ") } : {};
|
|
1632
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(", ")}`] : [];
|
|
1633
3236
|
const current = await findApp(client, decl.name, opts.skipped);
|
|
1634
3237
|
if (!current) {
|
|
1635
3238
|
const willSet = names.length > 0 ? [`will set ${names.join(", ")}`] : [];
|
|
@@ -1637,10 +3240,11 @@ async function upsertApp(client, decl, opts, appIds) {
|
|
|
1637
3240
|
return {
|
|
1638
3241
|
name: decl.name,
|
|
1639
3242
|
action: "created",
|
|
1640
|
-
...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])
|
|
1641
3244
|
};
|
|
1642
3245
|
}
|
|
1643
|
-
|
|
3246
|
+
const { values } = await materialize(declared, EMPTY, false);
|
|
3247
|
+
return createApp(client, decl, values, builtTree(decl, opts), declaredMigrations(decl, opts), opts, appIds);
|
|
1644
3248
|
}
|
|
1645
3249
|
const owned = current.project === opts.project;
|
|
1646
3250
|
if (!owned && !opts.adopt) {
|
|
@@ -1665,30 +3269,45 @@ async function upsertApp(client, decl, opts, appIds) {
|
|
|
1665
3269
|
if (!owned && !opts.dryRun) {
|
|
1666
3270
|
await ensureApp(client, { name: decl.name, type: decl.type, project: opts.project, adopt: true });
|
|
1667
3271
|
}
|
|
1668
|
-
const live =
|
|
1669
|
-
const
|
|
3272
|
+
const live = declared.length === 0 ? [] : (await client.apps.secrets(current.id)).data;
|
|
3273
|
+
const managed = new Set(names);
|
|
3274
|
+
const unmanaged = live.map((secret) => secret.name).filter((name) => !managed.has(name));
|
|
1670
3275
|
const held = new Map(live.map((secret) => [secret.name, secret.value_hash]));
|
|
3276
|
+
const { values: env, unmade } = await materialize(declared, new Set(held.keys()), opts.dryRun);
|
|
1671
3277
|
const staleEnv = Object.fromEntries(
|
|
1672
3278
|
Object.entries(env).filter(([name, value]) => held.get(name) !== secretHash(name, value))
|
|
1673
3279
|
);
|
|
1674
|
-
const staleNames = Object.keys(staleEnv);
|
|
3280
|
+
const staleNames = [...Object.keys(staleEnv), ...unmade];
|
|
1675
3281
|
const patch = {
|
|
1676
3282
|
...decl.description !== void 0 && decl.description !== current.description ? { description: decl.description } : {},
|
|
1677
3283
|
...(decl.mcp ?? null) !== current.mcp ? { mcp: decl.mcp ?? null } : {}
|
|
1678
3284
|
};
|
|
1679
3285
|
const drifted = Object.keys(patch).length > 0;
|
|
1680
|
-
const tree =
|
|
3286
|
+
const tree = builtTree(decl, opts);
|
|
1681
3287
|
const newest = tree ? (await client.apps.deployments(current.id, { limit: 1 })).data[0] : void 0;
|
|
1682
3288
|
const stale = tree !== null && newest?.content_hash !== tree.hash;
|
|
1683
|
-
|
|
3289
|
+
let action = !owned || drifted || stale || staleNames.length > 0 ? "updated" : "unchanged";
|
|
1684
3290
|
const plan = opts.dryRun ? [
|
|
1685
3291
|
...staleNames.length > 0 ? [`will set ${staleNames.join(", ")}`] : [],
|
|
1686
3292
|
..."mcp" in patch ? patch.mcp === null ? ["will clear mcp"] : mcpPlan : [],
|
|
1687
|
-
...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
|
|
1688
3296
|
] : [];
|
|
1689
3297
|
if (!opts.dryRun) {
|
|
1690
3298
|
if (drifted) await client.apps.update(current.id, { ...patch, project: opts.project });
|
|
1691
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
|
+
}
|
|
1692
3311
|
}
|
|
1693
3312
|
return {
|
|
1694
3313
|
name: decl.name,
|
|
@@ -1700,6 +3319,106 @@ async function upsertApp(client, decl, opts, appIds) {
|
|
|
1700
3319
|
};
|
|
1701
3320
|
}
|
|
1702
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
|
+
|
|
1703
3422
|
// src/vaults.ts
|
|
1704
3423
|
async function upsertVault(client, decl, existing, identityIds, dryRun) {
|
|
1705
3424
|
const identityId = decl.identity === void 0 ? void 0 : identityIds.get(decl.identity);
|
|
@@ -1725,14 +3444,14 @@ async function upsertVault(client, decl, existing, identityIds, dryRun) {
|
|
|
1725
3444
|
}
|
|
1726
3445
|
return { name: decl.name, action: "unchanged", id: current.id };
|
|
1727
3446
|
}
|
|
1728
|
-
async function upsertCredential(client, vault, decl, existing, dryRun) {
|
|
3447
|
+
async function upsertCredential(client, vault, decl, existing, dryRun, from) {
|
|
1729
3448
|
const name = `${vault.name} / ${decl.key}`;
|
|
1730
3449
|
if (vault.action === "refused") throw new Error(`vault "${vault.name}" was not provisioned in this run`);
|
|
1731
3450
|
const current = existing.find(
|
|
1732
3451
|
(row) => row.kind === decl.kind && row.key === decl.key && row.host === (decl.host ?? null) && row.mcp_server_url === (decl.mcp_server_url ?? null)
|
|
1733
3452
|
);
|
|
1734
3453
|
if (current) return { name, action: "unchanged", id: current.id };
|
|
1735
|
-
const value =
|
|
3454
|
+
const value = from[decl.value.from_env];
|
|
1736
3455
|
if (value === void 0) throw new Error(`credential ${decl.key} reads local variable ${decl.value.from_env}, which is not set`);
|
|
1737
3456
|
if (dryRun || vault.id === void 0) return { name, action: "created" };
|
|
1738
3457
|
const created = await client.vaults.credentials.create(vault.id, {
|
|
@@ -1745,13 +3464,94 @@ async function upsertCredential(client, vault, decl, existing, dryRun) {
|
|
|
1745
3464
|
return { name, action: "created", id: created.id };
|
|
1746
3465
|
}
|
|
1747
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
|
+
|
|
1748
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
|
+
}
|
|
3538
|
+
function identityEnv(config, ids) {
|
|
3539
|
+
if (config.identities.length !== 1) return {};
|
|
3540
|
+
const id = ids.get(config.identities[0].name);
|
|
3541
|
+
return id === void 0 ? {} : { [PLATFORM_ENV.identity_id]: id };
|
|
3542
|
+
}
|
|
1749
3543
|
async function upsertSkill(client, decl, opts) {
|
|
1750
|
-
const
|
|
3544
|
+
const inline = opts.skills[decl.slug];
|
|
3545
|
+
if (opts.hosted && inline === void 0) {
|
|
3546
|
+
throw new Error(
|
|
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.`
|
|
3548
|
+
);
|
|
3549
|
+
}
|
|
3550
|
+
const content = inline ?? readFileSync4(resolve4(opts.dir, decl.file), "utf8");
|
|
1751
3551
|
const sha256 = createHash3("sha256").update(content).digest("hex");
|
|
1752
3552
|
const current = await absent(client.skills.get(decl.slug));
|
|
1753
|
-
const
|
|
1754
|
-
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";
|
|
1755
3555
|
if (action === "unchanged" || opts.dryRun) {
|
|
1756
3556
|
return { name: decl.slug, action, ...current ? { id: current.id } : {} };
|
|
1757
3557
|
}
|
|
@@ -1774,14 +3574,14 @@ async function upsertIdentity(client, decl, dryRun, identityIds) {
|
|
|
1774
3574
|
if (drifted && !dryRun) await client.identities.update(current.id, { description: decl.description ?? null });
|
|
1775
3575
|
return { name: decl.name, action: drifted ? "updated" : "unchanged", id: current.id };
|
|
1776
3576
|
}
|
|
1777
|
-
async function applyRemoved(client, removed, live, owner,
|
|
1778
|
-
const dryRun =
|
|
3577
|
+
async function applyRemoved(client, removed, live, owner, report2) {
|
|
3578
|
+
const dryRun = report2.dry_run;
|
|
1779
3579
|
for (const name of removed.agents) {
|
|
1780
3580
|
const current = live.agents.find((agent) => agent.name === name);
|
|
1781
|
-
await attempt(
|
|
3581
|
+
await attempt(report2.agents, name, () => tombstone(name, current, (id) => client.agents.delete(id), dryRun));
|
|
1782
3582
|
}
|
|
1783
3583
|
for (const name of removed.apps) {
|
|
1784
|
-
await attempt(
|
|
3584
|
+
await attempt(report2.apps, name, async () => {
|
|
1785
3585
|
const current = await findApp(client, name, owner.skipped);
|
|
1786
3586
|
if (current !== null && current.project !== owner.project && !owner.adopt) {
|
|
1787
3587
|
return { name, action: "refused", id: current.id, reason: ownershipRefusal(name, owner.project, current.project) };
|
|
@@ -1791,18 +3591,18 @@ async function applyRemoved(client, removed, live, owner, report) {
|
|
|
1791
3591
|
}
|
|
1792
3592
|
for (const slug of removed.skills) {
|
|
1793
3593
|
await attempt(
|
|
1794
|
-
|
|
3594
|
+
report2.skills,
|
|
1795
3595
|
slug,
|
|
1796
3596
|
async () => tombstone(slug, await absent(client.skills.get(slug)), (id) => client.skills.delete(id), dryRun)
|
|
1797
3597
|
);
|
|
1798
3598
|
}
|
|
1799
3599
|
for (const name of removed.vaults) {
|
|
1800
3600
|
const current = live.vaults.find((vault) => vault.display_name === name);
|
|
1801
|
-
await attempt(
|
|
3601
|
+
await attempt(report2.vaults, name, () => tombstone(name, current, (id) => client.vaults.delete(id), dryRun));
|
|
1802
3602
|
}
|
|
1803
3603
|
for (const name of removed.identities) {
|
|
1804
3604
|
await attempt(
|
|
1805
|
-
|
|
3605
|
+
report2.identities,
|
|
1806
3606
|
name,
|
|
1807
3607
|
async () => tombstone(name, await absent(client.identities.get(name)), (id) => client.identities.delete(id), dryRun)
|
|
1808
3608
|
);
|
|
@@ -1819,57 +3619,134 @@ function reportKept(config, live, into) {
|
|
|
1819
3619
|
if (current !== void 0) into.push({ name, action: "unchanged", id: current.id, reason: `not declared by ${by}; kept, never deleted` });
|
|
1820
3620
|
}
|
|
1821
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
|
+
}
|
|
1822
3627
|
async function up(config, client, opts = {}) {
|
|
1823
3628
|
const dryRun = opts.dry_run ?? false;
|
|
1824
3629
|
const dir = opts.dir ?? process.cwd();
|
|
1825
3630
|
const ids = { apps: /* @__PURE__ */ new Map(), identities: /* @__PURE__ */ new Map() };
|
|
1826
|
-
const
|
|
1827
|
-
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 };
|
|
3634
|
+
const hosted = opts.trees !== void 0;
|
|
1828
3635
|
for (const decl of config.skills) {
|
|
1829
|
-
await attempt(
|
|
3636
|
+
await attempt(report2.skills, decl.slug, () => upsertSkill(client, decl, { dryRun, dir, hosted, skills: opts.skills ?? {} }));
|
|
1830
3637
|
}
|
|
1831
3638
|
for (const decl of config.identities) {
|
|
1832
|
-
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);
|
|
1833
3650
|
}
|
|
1834
|
-
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) : [];
|
|
1835
3652
|
for (const decl of config.vaults) {
|
|
1836
|
-
const
|
|
1837
|
-
const vaultId =
|
|
1838
|
-
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);
|
|
1839
3656
|
for (const cred of decl.credentials) {
|
|
1840
|
-
await attempt(
|
|
3657
|
+
await attempt(
|
|
3658
|
+
report2.vaults,
|
|
3659
|
+
`${decl.name} / ${cred.key}`,
|
|
3660
|
+
() => upsertCredential(client, line2, cred, rows, dryRun, opts.env ?? process.env)
|
|
3661
|
+
);
|
|
1841
3662
|
}
|
|
1842
3663
|
}
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
3664
|
+
const platform = opts.platform && {
|
|
3665
|
+
...opts.platform,
|
|
3666
|
+
known: {
|
|
3667
|
+
...opts.platform.known,
|
|
3668
|
+
[PLATFORM_ENV.project]: opts.project ?? config.name,
|
|
3669
|
+
...identityEnv(config, ids.identities)
|
|
3670
|
+
}
|
|
3671
|
+
};
|
|
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
|
+
)
|
|
3692
|
+
)
|
|
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) : [];
|
|
3697
|
+
const scoped = config.apps.length > 0 ? [...ids.apps.values()] : void 0;
|
|
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 = [];
|
|
1851
3701
|
if (decl.schedules !== void 0) {
|
|
1852
|
-
await reconcileSchedules(client,
|
|
3702
|
+
await reconcileSchedules(client, agent, decl.schedules, deployments, ids.identities, dryRun, schedules);
|
|
1853
3703
|
}
|
|
1854
|
-
|
|
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` });
|
|
1855
3715
|
}
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
for (const
|
|
1859
|
-
|
|
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);
|
|
1860
3729
|
}
|
|
1861
|
-
|
|
3730
|
+
report2.intake.push(
|
|
3731
|
+
...await eachInFlight(briefed, ([agent, decl]) => line(agent.name, () => openIntake(client, agent, decl, dryRun)))
|
|
3732
|
+
);
|
|
3733
|
+
return report2;
|
|
1862
3734
|
}
|
|
1863
3735
|
export {
|
|
1864
3736
|
BLUEPRINTS,
|
|
1865
3737
|
BlueprintRefusal,
|
|
1866
3738
|
CONFIG_CANDIDATES,
|
|
3739
|
+
PLATFORM_ENV,
|
|
3740
|
+
PROJECT_CONTEXT_PREAMBLE,
|
|
1867
3741
|
chooseTemplate,
|
|
1868
3742
|
collectFiles,
|
|
1869
3743
|
contentHash,
|
|
1870
3744
|
defineProject,
|
|
3745
|
+
hasRoster,
|
|
1871
3746
|
loadConfig,
|
|
3747
|
+
migrationFiles,
|
|
1872
3748
|
parseProject,
|
|
3749
|
+
selectCrew,
|
|
1873
3750
|
up
|
|
1874
3751
|
};
|
|
1875
3752
|
//# sourceMappingURL=index.js.map
|