@odla-ai/brand 0.2.1 → 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.cts CHANGED
@@ -1,7 +1,340 @@
1
- import { B as BrandDb, A as AssetAnalysis, S as Swatch, a as BrandBook, b as BrandOp, c as BrandEntityRef, d as SectionKind, e as SectionStatus, f as BrandProposal, g as AssetKind, h as BrandActor } from './index-bj73h3qo.cjs';
2
- export { i as ASSET_KINDS, j as BOOK_STATUSES, k as BRAND_CHART_TOKENS, l as BRAND_CHAT_TOKENS, m as BRAND_DERIVED_TOKENS, n as BRAND_EMITTED_TOKENS, o as BRAND_NS, p as BRAND_REQUIRED_TOKENS, q as BookStatus, r as BrandAsset, s as BrandAttrs, t as BrandFileRecord, u as BrandLookup, v as BrandPalette, w as BrandResult, x as BrandRow, y as BrandScalar, z as BrandSection, C as BrandStorage, D as BrandTokens, E as BrandTokensSnapshot, F as BrandUploadBody, G as CompileInput, H as CompiledBrandTokens, I as DARK_FLIP_L_MAX, J as DARK_FLIP_L_MIN, K as DEFAULT_ACCENT_SEED, L as ImagerySection, M as LogoSection, N as MapResult, P as PALETTE_SOURCES, O as PALETTE_STATUSES, Q as PROPOSAL_KINDS, R as PROPOSAL_STATUSES, T as PaletteSection, U as PaletteSource, V as PaletteStatus, W as ProposalKind, X as ProposalStatus, Y as RenderTokensCssOptions, Z as SECTION_KINDS, _ as SECTION_STATUSES, $ as SWATCH_ROLES, a0 as SwatchRole, a1 as TokenWarning, a2 as TypographySection, a3 as VoiceSection, a4 as compileBrandTokens, a5 as deriveDarkTokens, a6 as mapPaletteToTokens, a7 as renderTokensCss } from './index-bj73h3qo.cjs';
1
+ import { P as ProposalKind, a as ProposalStatus, A as AssetKind, b as AssetAnalysis, B as BookStatus, c as BrandTokensSnapshot, d as PaletteStatus, S as Swatch, e as PaletteSource, f as SectionKind, g as SectionStatus } from './index-CRl3IXHB.cjs';
2
+ export { h as ASSET_KINDS, i as BOOK_STATUSES, j as BRAND_CHART_TOKENS, k as BRAND_CHAT_TOKENS, l as BRAND_DERIVED_TOKENS, m as BRAND_EMITTED_TOKENS, n as BRAND_NS, o as BRAND_REQUIRED_TOKENS, p as BrandTokens, C as CompileInput, q as CompiledBrandTokens, D as DARK_FLIP_L_MAX, r as DARK_FLIP_L_MIN, s as DEFAULT_ACCENT_SEED, I as ImagerySection, L as LogoSection, M as MapResult, t as PALETTE_SOURCES, u as PALETTE_STATUSES, v as PROPOSAL_KINDS, w as PROPOSAL_STATUSES, x as PaletteSection, R as RenderTokensCssOptions, y as SECTION_KINDS, z as SECTION_STATUSES, E as SWATCH_ROLES, F as SwatchRole, T as TokenWarning, G as TypographySection, V as VoiceSection, H as compileBrandTokens, J as deriveDarkTokens, K as mapPaletteToTokens, N as renderTokensCss } from './index-CRl3IXHB.cjs';
3
3
  import { ToolHandler, Skill, ToolDef, Persona, Inference, AgentRunInput, ImageBlock, OracleContentBlock } from '@odla-ai/ai';
4
4
 
5
+ /** Immutable storage snapshot captured by the trusted semantic Brand bridge. */
6
+ interface BrandSourceAssetSnapshot {
7
+ assetId: string;
8
+ contentDigest: string;
9
+ objectEtag: string;
10
+ objectSize: number;
11
+ pathDigest: string;
12
+ contentType: string | null;
13
+ analysisRevision: number | null;
14
+ analysisDigest: string | null;
15
+ }
16
+ /** Required proposal provenance. Nulls keep the reviewed snapshot lossless. */
17
+ interface BrandProposalProvenance {
18
+ sourceAssetId: string | null;
19
+ sourceAsset: BrandSourceAssetSnapshot | null;
20
+ messageId: string | null;
21
+ turnId: string | null;
22
+ taintLabels: string[];
23
+ }
24
+ /** Agent output parked for explicit human resolution. */
25
+ interface BrandProposal {
26
+ id: string;
27
+ bookId: string;
28
+ kind: ProposalKind;
29
+ status: ProposalStatus;
30
+ payload: Record<string, unknown>;
31
+ rationale: string;
32
+ provenance: BrandProposalProvenance;
33
+ reviewDigest: string;
34
+ audience: string[];
35
+ createdBy: string;
36
+ createdAuthorityRef: string;
37
+ createdAt: number;
38
+ resolvedBy?: string;
39
+ resolvedAt?: number;
40
+ resolutionNote?: string;
41
+ approvedBy?: string;
42
+ appliedBy?: string;
43
+ resolutionReceiptId?: string;
44
+ resolutionActionDigest?: string;
45
+ }
46
+ /** Immutable proposal fields a human sends back when resolving it. */
47
+ interface BrandProposalReviewSnapshot {
48
+ id: string;
49
+ bookId: string;
50
+ kind: ProposalKind;
51
+ status: "open";
52
+ payload: Record<string, unknown>;
53
+ rationale: string;
54
+ provenance: BrandProposalProvenance;
55
+ reviewDigest: string;
56
+ audience: string[];
57
+ createdBy: string;
58
+ createdAuthorityRef: string;
59
+ createdAt: number;
60
+ }
61
+ /** Host receipt returned after consuming one central human-exact decision. */
62
+ interface BrandHumanAuthorityConsumption {
63
+ id: string;
64
+ grantId: string;
65
+ grantVersion: number;
66
+ useNumber: number;
67
+ actorPrincipalId: string;
68
+ actorKind: "human";
69
+ credentialId: string;
70
+ credentialKind: "clerk";
71
+ appId: string;
72
+ /** Exact Registry project lifetime authorized for this Brand decision. */
73
+ appIncarnation: string;
74
+ capability: "brand.proposal.resolve";
75
+ projectCapability: "brand.approve";
76
+ effect: "internal";
77
+ actionDigest: string;
78
+ resourceDigest: string;
79
+ constraintEvidence: Record<string, unknown>;
80
+ consumptionIdempotencyKey: string;
81
+ requestDigest: string;
82
+ consumedAt: number;
83
+ }
84
+ /** Live dependency revision and intended effect consumed by the decision. */
85
+ interface BrandDecisionBinding {
86
+ version: 1;
87
+ bookVersion: number;
88
+ activationRevision: number;
89
+ activePaletteId: string | null;
90
+ memberIdsDigest: string;
91
+ activePaletteDigest: string | null;
92
+ typographyDigest: string | null;
93
+ sourceAssetDigest: string | null;
94
+ effectDigest: string;
95
+ }
96
+ /** Durable projection of one centrally authorized decision. */
97
+ interface BrandApprovalReceipt {
98
+ version: 1;
99
+ id: string;
100
+ mutationKey: string;
101
+ bookId: string;
102
+ proposalId: string;
103
+ resolution: "accepted" | "rejected";
104
+ paletteId?: string;
105
+ resolutionNote?: string;
106
+ reviewedProposal: BrandProposalReviewSnapshot;
107
+ actionDigest: string;
108
+ decisionBinding: BrandDecisionBinding;
109
+ approvedBy: string;
110
+ approvedByKind: "human";
111
+ appliedBy: string;
112
+ appliedByKind: "human";
113
+ authorityRef: string;
114
+ authorityCapability: "brand.approve";
115
+ authorityConsumption: BrandHumanAuthorityConsumption;
116
+ createdAt: number;
117
+ receiptDigest: string;
118
+ }
119
+
120
+ /** Scalar values odla-db attrs and where-clauses accept. */
121
+ type BrandScalar = string | number | boolean | null;
122
+ /** Natural-key lookup ref for idempotent upserts (odla-db `Lookup` shape). */
123
+ interface BrandLookup {
124
+ ns: string;
125
+ attr: string;
126
+ value: BrandScalar;
127
+ }
128
+ /** How an op names its row: a raw entity id, or a natural-key lookup. */
129
+ type BrandEntityRef = string | BrandLookup;
130
+ /** Attr payload of one op. Typed `any` on purpose: the real odla-db
131
+ * `transact` constrains attrs to its own `Value` type, and `any` is the one
132
+ * shape assignable in both directions with no cast. */
133
+ type BrandAttrs = Record<string, any>;
134
+ /** One transact operation (update = attr-merge upsert; merge = deep-merge
135
+ * into a json attribute; retract = clear the named attributes, since a typed
136
+ * scalar can't store null). */
137
+ type BrandOp = {
138
+ t: "update";
139
+ ns: string;
140
+ id: BrandEntityRef;
141
+ attrs: BrandAttrs;
142
+ } | {
143
+ t: "merge";
144
+ ns: string;
145
+ id: BrandEntityRef;
146
+ attrs: BrandAttrs;
147
+ } | {
148
+ t: "retract";
149
+ ns: string;
150
+ id: BrandEntityRef;
151
+ attrs: string[];
152
+ } | {
153
+ t: "delete";
154
+ ns: string;
155
+ id: BrandEntityRef;
156
+ } | {
157
+ t: "link";
158
+ ns: string;
159
+ id: BrandEntityRef;
160
+ label: string;
161
+ target: BrandEntityRef;
162
+ } | {
163
+ t: "unlink";
164
+ ns: string;
165
+ id: BrandEntityRef;
166
+ label: string;
167
+ target: BrandEntityRef;
168
+ };
169
+ /** A row as odla-db returns it: hydrated id plus attrs. */
170
+ type BrandRow = {
171
+ id: string;
172
+ } & Record<string, unknown>;
173
+ /** Query result: namespace → rows. */
174
+ type BrandResult = Record<string, BrandRow[]>;
175
+ /** A brand book row: the auth roster (`memberIds`, including the bot agent
176
+ * id) plus the active palette and compiled-token cache. */
177
+ interface BrandBook {
178
+ id: string;
179
+ /** Monotonic worker-managed metadata revision. */
180
+ version: number;
181
+ slug: string;
182
+ name: string;
183
+ status: BookStatus;
184
+ ownerId: string;
185
+ /** Host authority that allowed this worker-created book. */
186
+ createdAuthorityRef: string;
187
+ rosterAuthorityRef?: string;
188
+ memberIds: string[];
189
+ channelId?: string;
190
+ activePaletteId?: string;
191
+ /** CAS counter advanced by every accepted palette activation. */
192
+ activationRevision: number;
193
+ tokens?: BrandTokensSnapshot;
194
+ summary?: string;
195
+ createdAt: number;
196
+ updatedAt: number;
197
+ }
198
+ /** A section row — one per (book, kind), upserted by its natural `key`. */
199
+ interface BrandSection {
200
+ id: string;
201
+ key: string;
202
+ bookId: string;
203
+ kind: SectionKind;
204
+ status: SectionStatus;
205
+ content: Record<string, unknown>;
206
+ audience: string[];
207
+ updatedBy: string;
208
+ updatedAt: number;
209
+ /** Present on approved sections and bound to the exact human decision. */
210
+ approvalReceiptId?: string;
211
+ approvalActionDigest?: string;
212
+ }
213
+ /** A palette row. Swatches are json ON the palette, not a namespace: the
214
+ * palette is the atomic proposal/approval unit and swatches are never
215
+ * queried across palettes. */
216
+ interface BrandPalette {
217
+ id: string;
218
+ bookId: string;
219
+ name: string;
220
+ status: PaletteStatus;
221
+ swatches: Swatch[];
222
+ seedHex?: string;
223
+ source: PaletteSource;
224
+ rationale?: string;
225
+ /** Accepted proposal whose exact reviewed payload materialized this row. */
226
+ proposalId: string;
227
+ approvalReceiptId: string;
228
+ approvalActionDigest: string;
229
+ audience: string[];
230
+ createdAt: number;
231
+ updatedAt: number;
232
+ }
233
+ /** An asset row mirroring one real uploaded file (worker-mediated; rules
234
+ * close the namespace). Delete is a tombstone (`deletedAt`), never a row
235
+ * delete, so analyses/proposals referencing it stay coherent. */
236
+ interface BrandAsset {
237
+ id: string;
238
+ bookId: string;
239
+ kind: AssetKind;
240
+ path: string;
241
+ storageObjectId: string;
242
+ contentDigest: string;
243
+ contentType: string;
244
+ size: number;
245
+ status: "live" | "deleting" | "deleted";
246
+ title?: string;
247
+ analysis?: AssetAnalysis;
248
+ analyzedAt?: number;
249
+ analysisRevision: number;
250
+ analysisDigest?: string;
251
+ analyzedBy?: string;
252
+ analyzedAuthorityRef?: string;
253
+ audience: string[];
254
+ uploadedBy: string;
255
+ uploadedAuthorityRef: string;
256
+ createdAt: number;
257
+ deletedAt?: number;
258
+ deletedBy?: string;
259
+ deletedAuthorityRef?: string;
260
+ }
261
+ /** What `db.storage.upload` resolves to (odla-db's file record shape). */
262
+ interface BrandFileRecord {
263
+ id: string;
264
+ path: string;
265
+ url: string;
266
+ size: number;
267
+ contentType: string;
268
+ }
269
+ /** Bodies `storage.upload` accepts — a practical subset of the platform's
270
+ * `BodyInit` (which has no ambient type under a DOM-less lib). The real
271
+ * @odla-ai/db client accepts a superset, so it still structurally satisfies
272
+ * {@link BrandStorage}. */
273
+ type BrandUploadBody = string | Blob | ArrayBuffer | Uint8Array | ReadableStream<Uint8Array>;
274
+ /** The injected file store — @odla-ai/db's `storage` API satisfies this. */
275
+ interface BrandStorage {
276
+ upload(path: string, data: BrandUploadBody, contentType?: string, opts?: {
277
+ private?: boolean;
278
+ }): Promise<BrandFileRecord>;
279
+ sign(path: string, ttlSeconds?: number): Promise<string>;
280
+ delete(path: string): Promise<void>;
281
+ }
282
+ /** One entity-state compare-and-swap condition, checked atomically with the
283
+ * transaction. Mirrors @odla-ai/db's structural guard contract. */
284
+ interface BrandTransactGuard {
285
+ ns: string;
286
+ id: string;
287
+ exists: boolean;
288
+ equals?: Record<string, unknown>;
289
+ }
290
+ /** Attribution, idempotency, and atomic preconditions for a brand write. */
291
+ interface BrandTransactOptions {
292
+ mutationId?: string;
293
+ guards?: BrandTransactGuard[];
294
+ asUser?: string;
295
+ asEmail?: string;
296
+ asPrincipalKind?: "human" | "agent" | "service";
297
+ }
298
+ /** The injected odla client (structural — a real @odla-ai/db `AdminDb`
299
+ * satisfies it). `transact` accepts flat op arrays; stable mutation ids give
300
+ * exactly-once application and guards bind reviewed state to its write. */
301
+ interface BrandDb {
302
+ query(q: Record<string, unknown>): Promise<Record<string, unknown[]>>;
303
+ transact(ops: unknown[], opts?: BrandTransactOptions): Promise<{
304
+ txId: number;
305
+ duplicate?: boolean;
306
+ }>;
307
+ storage: BrandStorage;
308
+ }
309
+ /** Who is acting: a human member or the book's bot agent. */
310
+ interface BrandActor {
311
+ id: string;
312
+ kind: "human" | "agent";
313
+ email?: string;
314
+ }
315
+
316
+ /** Canonical least-privilege runtime profile for a Brand collaborator agent. */
317
+ interface BrandAgentProfile {
318
+ version: 1;
319
+ projectCapabilities: readonly ["brand.read", "brand.edit"];
320
+ semanticOperations: readonly [
321
+ "brand.proposal.create",
322
+ "brand.asset.analysis.record",
323
+ "brand.asset.content.read"
324
+ ];
325
+ rawBrandWrites: false;
326
+ rawFileOperations: false;
327
+ approval: {
328
+ principalKind: "human";
329
+ projectCapability: "brand.approve";
330
+ capability: "brand.proposal.resolve";
331
+ exactAction: true;
332
+ };
333
+ }
334
+ /** Install-time contract: agents use semantic Brand operations; only a direct
335
+ * human may consume exact approval authority for a reviewed proposal. */
336
+ declare const BRAND_AGENT_PROFILE: BrandAgentProfile;
337
+
5
338
  /** Caller-fault error (bad hex, oversized payload, blocked transition…) — the
6
339
  * route layer maps it to a 400. `fields` carries per-field messages when the
7
340
  * failure came from input validation. */
@@ -13,6 +346,27 @@ declare class BrandInputError extends Error {
13
346
  declare class BrandNotFoundError extends Error {
14
347
  constructor(what: string);
15
348
  }
349
+ /** A once-valid central authority/resource is permanently unavailable. */
350
+ declare class BrandGoneError extends Error {
351
+ constructor(message?: string);
352
+ }
353
+ /** Authenticated principal lacks the required principal kind/capability. */
354
+ declare class BrandForbiddenError extends Error {
355
+ constructor(message?: string);
356
+ }
357
+ /** Reviewed state or an idempotent action no longer matches current state. */
358
+ declare class BrandConflictError extends Error {
359
+ constructor(message: string);
360
+ }
361
+ /**
362
+ * A proposal authority use was consumed, but the local guarded Brand write
363
+ * lost its compare-and-swap race. Clients must preserve the reviewed draft but
364
+ * rotate their idempotency key before a fresh human decision attempt.
365
+ */
366
+ declare class BrandReviewStateChangedError extends BrandConflictError {
367
+ readonly code = "brand_review_state_changed";
368
+ constructor(message?: string);
369
+ }
16
370
 
17
371
  /** What `fetchBytes` resolves to: raw bytes plus the served content type. */
18
372
  interface BrandFetchedBytes {
@@ -58,7 +412,7 @@ interface SerializedLinkEnd {
58
412
  has: "one" | "many";
59
413
  label: string;
60
414
  }
61
- /** A serialized schema link (unused by brand — audiences are denormalized). */
415
+ /** A serialized schema link used for current-book authorization. */
62
416
  interface SerializedLink {
63
417
  forward: SerializedLinkEnd;
64
418
  reverse: SerializedLinkEnd;
@@ -69,7 +423,7 @@ interface SerializedSchema {
69
423
  links: Record<string, SerializedLink>;
70
424
  }
71
425
  /**
72
- * The pre-serialized (wire-shape) odla-db schema for the five brand
426
+ * The pre-serialized (wire-shape) odla-db schema for the six brand
73
427
  * namespaces; POST it to `/app/:id/schema` as `{ schema: BRAND_SCHEMA }`.
74
428
  * Natural keys (`book.slug`, `section.key`) make provisioning and section
75
429
  * upserts idempotent; mirrored `id` attrs make rows addressable by
@@ -87,11 +441,11 @@ interface BrandRule {
87
441
  /** Namespace → rule set, as installed at `/app/:id/admin/rules`. */
88
442
  type BrandRules = Record<string, BrandRule>;
89
443
  /**
90
- * Default-deny CEL rules for the five brand namespaces; install at
444
+ * Default-deny CEL rules for the six brand namespaces; install at
91
445
  * `/app/:id/admin/rules`. Books gate on the `memberIds` roster (owner-only
92
- * writes); sections/palettes/proposals gate on their denormalized `audience`
93
- * and are never client-deletable (archive via `status` instead); assets are
94
- * fully worker-mediated. Use {@link brandRules} for a per-install copy.
446
+ * writes); child rows gate reads on current linked-book membership and all
447
+ * writes are worker-mediated. Use
448
+ * {@link brandRules} for a per-install copy.
95
449
  */
96
450
  declare const BRAND_RULES: BrandRules;
97
451
  /**
@@ -134,9 +488,8 @@ declare function assertSwatches(value: unknown): Swatch[];
134
488
  */
135
489
  declare function assertSectionContent(kind: string, content: unknown): Record<string, unknown>;
136
490
  /**
137
- * Sanitize an upload's file name for use in an R2 key: strips path
138
- * separators, control characters, and leading dots, then caps at 120
139
- * characters. Throws when nothing survives sanitizing.
491
+ * Validate an upload file name for an R2 key. Path/URL delimiters and control
492
+ * characters are rejected; leading dots are stripped and length is capped.
140
493
  */
141
494
  declare function safeFileName(name: unknown): string;
142
495
  /**
@@ -151,6 +504,75 @@ declare function assertAssetContentType(value: unknown): string;
151
504
  */
152
505
  declare function assertAnalysis(value: unknown): AssetAnalysis;
153
506
 
507
+ /** Stay materially below the server's whole-guards parser budget. */
508
+ declare function isBoundedBrandJson(root: unknown, limits?: {
509
+ maxDepth?: number;
510
+ maxNodes?: number;
511
+ maxBytes?: number;
512
+ }): boolean;
513
+ /** Deterministic JSON with recursively sorted object keys. */
514
+ declare function canonicalBrandJson(value: unknown): string;
515
+ /** `sha256:<hex>` over {@link canonicalBrandJson}. */
516
+ declare function brandJsonDigest(value: unknown): Promise<string>;
517
+
518
+ /** Stable local reference to one immutable central grant revision. */
519
+ declare function brandAuthorityRef(consumption: Pick<BrandHumanAuthorityConsumption, "grantId" | "grantVersion">): string;
520
+ /** Validate the exact direct-human central authority receipt shape. */
521
+ declare function isBrandHumanAuthorityConsumption(value: unknown): value is BrandHumanAuthorityConsumption;
522
+ /** Verify exact shape, cross-field bindings, and every local digest. This
523
+ * proves receipt self-consistency only; the host must authenticate the
524
+ * central consumption behind `authorityConsumption.id`. */
525
+ declare function verifyBrandApprovalReceipt(receipt: unknown): Promise<boolean>;
526
+
527
+ /** Brand resources that can be shared into a Discussion message. */
528
+ declare const BRAND_DISCUSSION_REFERENCE_KINDS: readonly ["brand:book", "brand:asset", "brand:palette", "brand:proposal", "brand:receipt"];
529
+ /** One Brand resource kind understood by the native Brand destination. */
530
+ type BrandDiscussionReferenceKind = (typeof BRAND_DISCUSSION_REFERENCE_KINDS)[number];
531
+ /** Canonical Brand destination target parsed from an `odla-ref` deep link. */
532
+ interface BrandDiscussionReferenceTarget {
533
+ kind: BrandDiscussionReferenceKind;
534
+ bookId: string;
535
+ resourceId?: string;
536
+ }
537
+ /** Bounded color projection shared with Discussion people and agents. */
538
+ interface BrandDiscussionSwatch {
539
+ /** Semantic role used by the Brand token compiler. */
540
+ role: string;
541
+ /** Normalized opaque sRGB color (`#rrggbb`). */
542
+ hex: string;
543
+ /** Optional product-authored color name. */
544
+ name?: string;
545
+ }
546
+ /** Product-owned projection returned to Discussion typeahead and exact lookup. */
547
+ interface BrandDiscussionReference {
548
+ /** Canonical Brand kind used in stored Discussion ref markup. */
549
+ kind: BrandDiscussionReferenceKind;
550
+ /** Opaque durable product id; never infer membership from its segments. */
551
+ id: string;
552
+ /** Product-authored primary display name. */
553
+ label: string;
554
+ /** Short product-authored secondary context for the picker. */
555
+ hint: string;
556
+ /** Bounded product-authored context safe to show an LLM or person. */
557
+ summary: string;
558
+ /** Current product status at inspection time. */
559
+ status: string;
560
+ /** Human-readable native surface the link opens. */
561
+ destination: string;
562
+ /** Same-origin native link; navigation is not mutation authority. */
563
+ href: string;
564
+ /** Present only for a validated Brand palette, capped by Brand's swatch limit. */
565
+ swatches?: BrandDiscussionSwatch[];
566
+ }
567
+ /** Durable ref id: a book id, or `bookId/resourceId` for a child resource. */
568
+ declare function brandDiscussionReferenceId(target: BrandDiscussionReferenceTarget): string;
569
+ /** Canonical value stored in the stable `odla-ref` query parameter. */
570
+ declare function formatBrandDiscussionReference(target: BrandDiscussionReferenceTarget): string;
571
+ /** Parse and validate a Brand `odla-ref`; malformed and cross-product refs fail closed. */
572
+ declare function parseBrandDiscussionReference(input: URL | string): BrandDiscussionReferenceTarget | null;
573
+ /** Build the native Brand deep link while preserving the deployed origin. */
574
+ declare function brandDiscussionReferenceHref(current: URL, target: BrandDiscussionReferenceTarget, basePath?: string): string;
575
+
154
576
  /** Input to {@link createBookOps}. `memberIds` is the full auth roster —
155
577
  * include the bot agent's id so it can pass the audience rules. */
156
578
  interface CreateBookInput {
@@ -158,6 +580,7 @@ interface CreateBookInput {
158
580
  slug: string;
159
581
  name: string;
160
582
  ownerId: string;
583
+ createdAuthorityRef: string;
161
584
  memberIds: string[];
162
585
  channelId?: string;
163
586
  now: number;
@@ -212,6 +635,8 @@ interface UpsertSectionInput {
212
635
  audience: string[];
213
636
  updatedBy: string;
214
637
  now: number;
638
+ approvalReceiptId?: string;
639
+ approvalActionDigest?: string;
215
640
  }
216
641
  /**
217
642
  * Ops to create-or-replace a book's section of one kind: a single `update`
@@ -220,6 +645,24 @@ interface UpsertSectionInput {
220
645
  * snapshot, and the author/timestamp.
221
646
  */
222
647
  declare function upsertSectionOps(input: UpsertSectionInput): BrandOp[];
648
+ /** Input for an agent-authored non-palette facet proposal. */
649
+ interface ProposeSectionInput {
650
+ id: string;
651
+ bookId: string;
652
+ kind: Exclude<SectionKind, "palette">;
653
+ content: Record<string, unknown>;
654
+ rationale: string;
655
+ audience: string[];
656
+ createdBy: string;
657
+ createdAuthorityRef: string;
658
+ sourceAsset?: BrandProposal["provenance"]["sourceAsset"];
659
+ messageId: string;
660
+ turnId: string;
661
+ taintLabels: string[];
662
+ now: number;
663
+ }
664
+ /** Validate a facet draft and park it as an immutable OPEN proposal. */
665
+ declare function proposeSectionOps(input: ProposeSectionInput): Promise<BrandOp[]>;
223
666
 
224
667
  /** Input to {@link proposePaletteOps}. `audience` is the book's roster
225
668
  * snapshot; `contrastReport` is stored verbatim in the payload for the
@@ -233,9 +676,12 @@ interface ProposePaletteInput {
233
676
  seedHex?: string;
234
677
  contrastReport?: unknown;
235
678
  createdBy: string;
679
+ createdAuthorityRef: string;
236
680
  audience: string[];
237
- sourceAssetId?: string;
238
- messageId?: string;
681
+ sourceAsset?: BrandProposal["provenance"]["sourceAsset"];
682
+ messageId: string;
683
+ turnId: string;
684
+ taintLabels: string[];
239
685
  now: number;
240
686
  }
241
687
  /**
@@ -243,13 +689,15 @@ interface ProposePaletteInput {
243
689
  * `kind: "palette"`, `status: "open"`, with the validated swatches (and
244
690
  * optional seed/contrast report) in `payload`.
245
691
  */
246
- declare function proposePaletteOps(input: ProposePaletteInput): BrandOp[];
692
+ declare function proposePaletteOps(input: ProposePaletteInput): Promise<BrandOp[]>;
247
693
  /** Input to {@link acceptProposalOps}: the proposal row as read back, the id
248
694
  * to mint the palette under, and who resolved it. */
249
695
  interface AcceptProposalInput {
250
696
  proposal: BrandProposal;
251
697
  paletteId: string;
252
698
  resolvedBy: string;
699
+ approvalReceiptId: string;
700
+ approvalActionDigest: string;
253
701
  now: number;
254
702
  resolutionNote?: string;
255
703
  }
@@ -279,16 +727,18 @@ interface RejectProposalInput {
279
727
  declare function rejectProposalOps(input: RejectProposalInput): BrandOp[];
280
728
 
281
729
  /** Input to {@link createAssetOps} — the storage upload's receipt fields
282
- * (`path`/`url`/`size`) plus the declared kind and the book's audience. */
730
+ * (`path`/`size`) plus the declared kind and the book's audience. */
283
731
  interface CreateAssetInput {
284
732
  id: string;
285
733
  bookId: string;
286
734
  kind: AssetKind;
287
735
  path: string;
288
- url: string;
736
+ storageObjectId: string;
737
+ contentDigest: string;
289
738
  contentType: string;
290
739
  size: number;
291
740
  uploadedBy: string;
741
+ uploadedAuthorityRef: string;
292
742
  audience: string[];
293
743
  title?: string;
294
744
  now: number;
@@ -304,12 +754,14 @@ declare function createAssetOps(input: CreateAssetInput): BrandOp[];
304
754
  * `deletedAt` in place. List reads exclude tombstoned rows; the row itself
305
755
  * stays for provenance.
306
756
  */
307
- declare function tombstoneAssetOps(assetId: BrandEntityRef, now: number): BrandOp[];
757
+ declare function beginAssetDeleteOps(assetId: BrandEntityRef, now: number, deletedBy: string, deletedAuthorityRef: string): BrandOp[];
758
+ /** Complete a previously authorized deletion after storage is tombstoned. */
759
+ declare function finishAssetDeleteOps(assetId: BrandEntityRef): BrandOp[];
308
760
  /**
309
761
  * Ops to record an agent's analysis of an asset: the validated + capped
310
762
  * analysis json plus `analyzedAt`. Replaces any prior analysis whole.
311
763
  */
312
- declare function recordAnalysisOps(assetId: BrandEntityRef, analysis: unknown, now: number): BrandOp[];
764
+ declare function recordAnalysisOps(assetId: BrandEntityRef, analysis: unknown, priorRevision: number, analyzedBy: string, analyzedAuthorityRef: string, now: number): Promise<BrandOp[]>;
313
765
 
314
766
  /** An sRGB color with channels as fractions in [0, 1]. */
315
767
  interface Rgb {
@@ -566,6 +1018,21 @@ interface DerivePaletteOptions {
566
1018
  */
567
1019
  declare function derivePalette(seedHex: string, opts?: DerivePaletteOptions): Swatch[];
568
1020
 
1021
+ /** Semantic Brand capability granted to one live agent principal. */
1022
+ type BrandCapability = "brand.read" | "brand.edit";
1023
+ /** Host-verified evidence that an agent currently holds one Brand capability. */
1024
+ interface BrandCapabilityAuthority {
1025
+ capability: BrandCapability;
1026
+ authorityRef: string;
1027
+ }
1028
+ /** Safe directory projection exposed to an agent for Brand attribution. */
1029
+ interface BrandPrincipalProjection {
1030
+ id: string;
1031
+ displayName: string;
1032
+ kind: "human" | "agent" | "service";
1033
+ managerDisplayName?: string;
1034
+ }
1035
+
569
1036
  /** The bot identity the skill writes as (`selfId` = the agent id carried in
570
1037
  * the book's `memberIds` roster and every audience snapshot). */
571
1038
  interface BrandSkillSelf {
@@ -573,6 +1040,32 @@ interface BrandSkillSelf {
573
1040
  kind: "bot";
574
1041
  displayName?: string;
575
1042
  }
1043
+ /** Server-enforced semantic bridge. Raw agent credentials must be denied all
1044
+ * Brand namespace writes and raw file operations. */
1045
+ interface BrandAgentBridge {
1046
+ createProposal(input: {
1047
+ jobId: string;
1048
+ bookId: string;
1049
+ mutationId: string;
1050
+ kind: ProposalKind;
1051
+ payload: Record<string, unknown>;
1052
+ rationale: string;
1053
+ sourceAssetId?: string;
1054
+ }): Promise<BrandProposal>;
1055
+ recordAssetAnalysis(input: {
1056
+ jobId: string;
1057
+ mutationId: string;
1058
+ bookId: string;
1059
+ assetId: string;
1060
+ analysis: AssetAnalysis;
1061
+ expectedAnalysisRevision: number;
1062
+ }): Promise<BrandAsset>;
1063
+ readAssetContent(input: {
1064
+ jobId: string;
1065
+ bookId: string;
1066
+ assetId: string;
1067
+ }): Promise<BrandFetchedBytes>;
1068
+ }
576
1069
  /** Options for {@link brandSkill}. */
577
1070
  interface BrandSkillOpts {
578
1071
  /** The injected odla client (a real @odla-ai/db AdminDb satisfies it). */
@@ -581,10 +1074,27 @@ interface BrandSkillOpts {
581
1074
  bookId: string;
582
1075
  /** The bot identity acting through these tools. */
583
1076
  self: BrandSkillSelf;
584
- /** Origin prefixed onto relative asset urls (`url` starting with `/`). */
585
- fileBaseUrl: string;
586
- /** Asset-byte fetcher override (default: global fetch via resolveDeps). */
587
- fetchBytes?: (url: string) => Promise<BrandFetchedBytes>;
1077
+ /** Host attestation for the rules-scoped credential behind `db`. */
1078
+ agentDbBinding: {
1079
+ principalId: string;
1080
+ credentialRef: string;
1081
+ };
1082
+ /** Active verified agent job; the bridge derives message/turn provenance. */
1083
+ agentJobId: string;
1084
+ agentBridge: BrandAgentBridge;
1085
+ /** Host verification against the live principal grant. Missing/denied hooks
1086
+ * fail closed; roster membership is visibility, not authority. */
1087
+ authorizeCapability: (input: {
1088
+ agentId: string;
1089
+ bookId: string;
1090
+ capability: BrandCapability;
1091
+ }) => Promise<BrandCapabilityAuthority | null> | BrandCapabilityAuthority | null;
1092
+ /** Bounded host directory projection for conversational display only. */
1093
+ resolvePrincipals: (input: {
1094
+ requesterAgentId: string;
1095
+ bookId: string;
1096
+ principalIds: string[];
1097
+ }) => Promise<BrandPrincipalProjection[]>;
588
1098
  /** False when the model cannot take image/document blocks inside a
589
1099
  * tool_result — view_asset then steers to the pre-turn attachment path. */
590
1100
  visionInToolResults?: boolean;
@@ -598,12 +1108,27 @@ interface BrandToolCtx {
598
1108
  db: BrandDb;
599
1109
  bookId: string;
600
1110
  self: BrandSkillSelf;
601
- fileBaseUrl: string;
602
- fetchBytes: (url: string) => Promise<BrandFetchedBytes>;
603
1111
  /** Whether image/document blocks may be returned inside tool results. */
604
1112
  visionInToolResults: boolean;
605
1113
  now: () => number;
606
1114
  newId: () => string;
1115
+ agentJobId: string;
1116
+ createProposal(input: {
1117
+ mutationId: string;
1118
+ kind: ProposalKind;
1119
+ payload: Record<string, unknown>;
1120
+ rationale: string;
1121
+ sourceAssetId?: string;
1122
+ }): Promise<BrandProposal>;
1123
+ recordAssetAnalysis(input: {
1124
+ mutationId: string;
1125
+ assetId: string;
1126
+ analysis: AssetAnalysis;
1127
+ expectedAnalysisRevision: number;
1128
+ }): Promise<BrandAsset>;
1129
+ readAssetContent(assetId: string): Promise<BrandFetchedBytes>;
1130
+ resolvePrincipals(ids: string[]): Promise<BrandPrincipalProjection[]>;
1131
+ authority(capability: BrandCapability): Promise<BrandCapabilityAuthority>;
607
1132
  /** Load the scoped book row; throws BrandNotFoundError when missing. */
608
1133
  loadBook(): Promise<BrandBook>;
609
1134
  /** Wrap a handler so Brand validation errors come back as actionable
@@ -638,17 +1163,13 @@ declare function base64FromBytes(bytes: Uint8Array): string;
638
1163
  */
639
1164
  declare function assetTools(ctx: BrandToolCtx): ToolDef[];
640
1165
 
641
- /**
642
- * The book tools: `update_section` (validated per-kind content, upserted by
643
- * natural key with the book's audience snapshot) and `compile_tokens`
644
- * (palette + typography → light/dark token cache on the book row).
645
- */
1166
+ /** `update_section` validates a draft and parks it as an OPEN proposal. */
646
1167
  declare function bookTools(ctx: BrandToolCtx): ToolDef[];
647
1168
 
648
1169
  /**
649
1170
  * The palette tools: `analyze_color`, `evaluate_contrast` (pure math),
650
1171
  * `propose_palette` (writes an OPEN proposal with an automatic contrast
651
- * report), and `resolve_proposal` (applies the human's explicit verdict).
1172
+ * report). Resolution is deliberately not an agent tool.
652
1173
  */
653
1174
  declare function paletteTools(ctx: BrandToolCtx): ToolDef[];
654
1175
 
@@ -699,15 +1220,76 @@ declare function supportsBrandVision(spec: BrandVisionSpec | null | undefined):
699
1220
  */
700
1221
  declare function readTools(ctx: BrandToolCtx): ToolDef[];
701
1222
 
1223
+ type BrandRouteCapability = "brand.edit" | "app.manage";
1224
+ type BrandRouteEffect = "internal" | "destructive";
1225
+ interface BrandRouteAuthority {
1226
+ authorityRef: string;
1227
+ actorPrincipalId: string;
1228
+ capability: BrandRouteCapability;
1229
+ effect: BrandRouteEffect;
1230
+ }
702
1231
  /** Everything {@link import("./index").createBrandRoutes} needs from the host worker. */
703
1232
  interface BrandRouteOpts {
704
1233
  /** The injected odla client (a real @odla-ai/db AdminDb satisfies it). */
705
1234
  db: BrandDb;
1235
+ /** Registry app that owns the book rows and central authority records. */
1236
+ appId: string;
706
1237
  /** Host-owned auth: resolve the request to an actor or null (→ 401). The
707
1238
  * tokens routes skip this only when `publicTokens` is true. */
708
1239
  authorize: (req: Request) => Promise<BrandActor | null> | BrandActor | null;
1240
+ /** Optional host-owned authority seam for read-only Discussion reference
1241
+ * lookup. Verify exact Brand product, brand.read capability, canonical
1242
+ * audience, principal, current app lifetime/environment, and agent grant
1243
+ * provenance here; when omitted, the ordinary request authorizer is used. */
1244
+ authorizeDiscussionReferences?: (req: Request) => Promise<BrandActor | null> | BrandActor | null;
1245
+ /** Live host verification for worker-mediated effects. The callback must
1246
+ * verify the direct human credential, current app owner/co-owner status,
1247
+ * exact capability/effect/resource, and return null on any uncertainty. */
1248
+ authorizeCapability: (input: {
1249
+ req: Request;
1250
+ actor: BrandActor;
1251
+ appId: string;
1252
+ bookId?: string;
1253
+ capability: BrandRouteCapability;
1254
+ effect: BrandRouteEffect;
1255
+ }) => Promise<BrandRouteAuthority | null> | BrandRouteAuthority | null;
1256
+ /** Consume or idempotently replay one registry `human_exact` authority use,
1257
+ * then reload and authenticate its immutable central receipt. Missing,
1258
+ * synthetic, cached, or unverifiable authority must return null. */
1259
+ consumeHumanExact: (input: {
1260
+ req: Request;
1261
+ actor: BrandActor;
1262
+ appId: string;
1263
+ capability: "brand.proposal.resolve";
1264
+ projectCapability: "brand.approve";
1265
+ effect: "internal";
1266
+ resource: {
1267
+ bookId: string;
1268
+ proposalId: string;
1269
+ };
1270
+ actionDigest: string;
1271
+ consumptionIdempotencyKey: string;
1272
+ }) => Promise<BrandHumanAuthorityConsumption | null> | BrandHumanAuthorityConsumption | null;
1273
+ /** Re-read the private object and authenticate the exact snapshot captured
1274
+ * by the agent bridge. This must verify path, ETag, size, and SHA-256 bytes;
1275
+ * returning false prevents authority consumption and the local effect. */
1276
+ verifySourceAssetSnapshot: (input: {
1277
+ req: Request;
1278
+ appId: string;
1279
+ bookId: string;
1280
+ assetId: string;
1281
+ path: string;
1282
+ snapshot: BrandSourceAssetSnapshot;
1283
+ }) => Promise<boolean> | boolean;
709
1284
  /** Mount point. Default "/api/brand". */
710
1285
  basePath?: string;
1286
+ /** Native UI mount used by returned Discussion deep links. Default "/". */
1287
+ discussionBasePath?: string;
1288
+ /**
1289
+ * Product-owned fetch used only for a short-lived URL minted from a linked
1290
+ * private Brand asset. Callers never provide this URL or receive it back.
1291
+ */
1292
+ fetchPrivateAsset?: typeof fetch;
711
1293
  /** Upload size cap in bytes (checked against `File.size`). Default 8 MiB. */
712
1294
  maxUploadBytes?: number;
713
1295
  /** Serve `GET /books/:id/tokens.css` and `tokens.json` without authorize —
@@ -721,12 +1303,21 @@ interface BrandRouteOpts {
721
1303
  /** Per-request context handed to the authorized route handlers. */
722
1304
  interface BrandRouteCtx {
723
1305
  db: BrandDb;
1306
+ appId: string;
724
1307
  actor: BrandActor;
1308
+ authorizeCapability: BrandRouteOpts["authorizeCapability"];
1309
+ consumeHumanExact: BrandRouteOpts["consumeHumanExact"];
1310
+ verifySourceAssetSnapshot: BrandRouteOpts["verifySourceAssetSnapshot"];
725
1311
  now: () => number;
726
1312
  newId: () => string;
727
1313
  maxUploadBytes: number;
1314
+ discussionBasePath: string;
1315
+ fetchPrivateAsset: typeof fetch;
728
1316
  }
729
1317
 
1318
+ /** Freeze the exact OPEN proposal fields a reviewer sees. */
1319
+ declare function proposalReviewSnapshot(proposal: BrandProposal): BrandProposalReviewSnapshot;
1320
+
730
1321
  /**
731
1322
  * Build the brand fetch handler. Returns `null` for requests outside
732
1323
  * `basePath` (default `/api/brand`) so the host worker falls through to its
@@ -737,11 +1328,13 @@ interface BrandRouteCtx {
737
1328
  */
738
1329
  declare function createBrandRoutes(options: BrandRouteOpts): (req: Request) => Promise<Response | null>;
739
1330
 
740
- /** The dispatch envelope odla-db's commit hook POSTs when a trigger fires —
741
- * the same wire shape chat-agent consumes (see the header provenance note). */
1331
+ /** Versioned, host-authenticated envelope for one Brand agent turn. */
742
1332
  interface BrandDispatchBody {
743
- v: number;
1333
+ v: 2;
744
1334
  appId: string;
1335
+ /** Exact Registry app lifetime admitted by the durable Server job. */
1336
+ appIncarnation: string;
1337
+ jobId: string;
745
1338
  trigger: {
746
1339
  id: string;
747
1340
  skill: string;
@@ -757,61 +1350,61 @@ interface BrandDispatchBody {
757
1350
  row: Record<string, unknown>;
758
1351
  };
759
1352
  }
760
- /**
761
- * Validate an untrusted dispatch body; null if malformed. SHAPE-only,
762
- * mirroring chat-agent's parseDispatch: it does NOT gate on `trigger.skill` —
763
- * routing on skill is the HOST's job (a worker serving several skills checks
764
- * `body.trigger.skill === "brand"` before calling {@link dispatchBrandTurn}),
765
- * so an absent skill parses as `""`, never silently defaulted to "brand".
766
- */
767
- declare function parseBrandDispatch(raw: unknown): BrandDispatchBody | null;
768
- /** The brand book bound to a chat channel (`brand_book.channelId`), or null
769
- * when the channel id is empty or no book claims it. */
770
- declare function bookForChannel(db: BrandDb, channelId: string): Promise<BrandBook | null>;
771
- /**
772
- * The agent-turn input for a dispatched message: a brand-flavored prompt
773
- * (mirrors chat-agent's `inputFor` tone, steering into the brand workflow),
774
- * and — when pre-turn `attachments` are supplied (the no-vision-in-tool-
775
- * results path) — an explicit block array with the images BEFORE the text.
776
- */
777
- declare function brandInputFor(body: BrandDispatchBody, attachments?: ImageBlock[]): string | OracleContentBlock[];
778
- /** Everything {@link dispatchBrandTurn} needs from the host worker. The
779
- * @odla-ai/ai pieces (`inference`, `runAgent`) are injected so this module
780
- * keeps the package's types-only relationship with the peer. */
1353
+ /** Trusted host seams required to run one capability-bound Brand agent turn. */
781
1354
  interface BrandDispatchDeps {
782
- /** The injected odla client (a real @odla-ai/db AdminDb satisfies it). */
1355
+ /** Service read client; never handed to agent tools. */
783
1356
  db: BrandDb;
784
- /** The @odla-ai/ai inference facade the turn runs on. */
1357
+ appId: string;
1358
+ /** Host-created runtime bound to this verified dispatch + exact agent. */
1359
+ agentRuntimeFor: (input: {
1360
+ appId: string;
1361
+ agentId: string;
1362
+ bookId: string;
1363
+ triggerId: string;
1364
+ eventId: string;
1365
+ jobId: string;
1366
+ }) => Promise<{
1367
+ db: BrandDb;
1368
+ credentialRef: string;
1369
+ jobId: string;
1370
+ bridge: BrandAgentBridge;
1371
+ }>;
1372
+ authorizeCapability: (input: {
1373
+ agentId: string;
1374
+ bookId: string;
1375
+ capability: "brand.read" | "brand.edit";
1376
+ }) => Promise<BrandCapabilityAuthority | null> | BrandCapabilityAuthority | null;
1377
+ resolvePrincipals: (input: {
1378
+ requesterAgentId: string;
1379
+ bookId: string;
1380
+ principalIds: string[];
1381
+ }) => Promise<BrandPrincipalProjection[]>;
785
1382
  inference: Inference;
786
- /** Canonical model id for the persona. */
787
1383
  model: string;
788
- /** The agent loop — pass @odla-ai/ai's `runAgent`. */
789
1384
  runAgent: (inference: Inference, persona: Persona, input: AgentRunInput) => Promise<{
790
1385
  finalText: string;
791
1386
  }>;
792
- /** Origin prefixed onto relative asset urls (skill + pre-turn attachments). */
793
- fileBaseUrl: string;
794
- /** Optional stable id factory for durable whole-turn retries. */
795
1387
  newId?: () => string;
796
- /** Optional chat-skill factory (e.g. wrapping @odla-ai/chat's chatSkill) so
797
- * the bot can reply in the triggering channel. */
798
1388
  chatSkillFor?: (channelId: string, self: BrandSkillSelf) => Skill;
799
- /** Model catalog slice (model id → capability spec) for the vision probe;
800
- * an absent catalog or unknown model fails safe to the pre-turn path. */
801
1389
  catalog?: Record<string, BrandVisionSpec>;
802
1390
  }
803
- /**
804
- * Run one brand-agent turn for a dispatched chat message: resolve the book
805
- * via the row's `channelId` (throws {@link BrandNotFoundError} when no book
806
- * claims the channel), probe `supportsBrandVision(catalog[model])`, build the
807
- * persona (brand skill + optional chat skill, bot identity from
808
- * `trigger.runAs`), and run the loop. When the model can NOT take blocks in
809
- * tool results, assets are attached PRE-TURN as URL image blocks v1 keeps
810
- * detection simple: only when the message row carries an `assetIds` array
811
- * (no body-text scraping), and only live image assets.
812
- */
1391
+
1392
+ /** Reload message attachment ids against the exact live linked Brand book. */
1393
+ declare function attachedBrandAssetIds(db: BrandDb, book: BrandBook, row: Record<string, unknown>): Promise<string[]>;
1394
+
1395
+ /** Strict-enough structural parse for the signed host dispatch envelope. */
1396
+ declare function parseBrandDispatch(raw: unknown): BrandDispatchBody | null;
1397
+ /** Channel ids are unique by schema, but ambiguity still fails closed if a
1398
+ * legacy/corrupt store returns more than one row. */
1399
+ declare function bookForChannel(db: BrandDb, channelId: string): Promise<BrandBook | null>;
1400
+ /** Assemble the conversational request. Attachments remain supported as a
1401
+ * pure helper, but secure dispatch does not pass signed/private URLs here. */
1402
+ declare function brandInputFor(body: BrandDispatchBody, attachments?: ImageBlock[], author?: BrandPrincipalProjection, attachedAssetIds?: readonly string[]): string | OracleContentBlock[];
1403
+ /** Preflight exact app/skill/channel/roster/live brand.read before the model
1404
+ * is invoked. Every tool revalidates its own read/edit capability as well. */
813
1405
  declare function dispatchBrandTurn(deps: BrandDispatchDeps, body: BrandDispatchBody): Promise<{
814
1406
  finalText: string;
1407
+ durableOutcome: boolean;
815
1408
  }>;
816
1409
 
817
1410
  /** The odla-db namespace chat messages live in.
@@ -903,6 +1496,8 @@ interface BrandIntegrationDescriptor {
903
1496
  rules: BrandRules;
904
1497
  /** Commit triggers to register at /app/:id/admin/triggers (per-bot; app-supplied). */
905
1498
  triggers: BrandTrigger[];
1499
+ /** Least-privilege agent capabilities and semantic-operation boundary. */
1500
+ agentProfile: BrandAgentProfile;
906
1501
  probes?: BrandIntegrationProbe[];
907
1502
  provision: IntegrationProvision;
908
1503
  }
@@ -935,4 +1530,4 @@ interface CreateBrandIntegrationOptions {
935
1530
  */
936
1531
  declare function createBrandIntegration(options?: CreateBrandIntegrationOptions): BrandIntegrationDescriptor;
937
1532
 
938
- export { ASSET_CONTENT_TYPES, type AcceptProposalInput, AssetAnalysis, AssetKind, type AttrType, type AudienceChildren, BRAND_INSTRUCTIONS, BRAND_RULES, BRAND_SCHEMA, BrandActor, BrandBook, type BrandBotTriggerOpts, BrandDb, type BrandDeps, type BrandDispatchBody, type BrandDispatchDeps, BrandEntityRef, type BrandFetchedBytes, BrandInputError, type BrandIntegrationDescriptor, type BrandIntegrationProbe, BrandNotFoundError, BrandOp, BrandProposal, type BrandRouteCtx, type BrandRouteOpts, type BrandRule, type BrandRules, type BrandSkillOpts, type BrandSkillSelf, type BrandToolCtx, type BrandTrigger, type BrandVisionCapabilities, type BrandVisionSpec, CHART_DELTA_MIN, CHAT_MESSAGE_NS, CSS_NAMED_COLORS, type ContrastKind, type CreateAssetInput, type CreateBookInput, type CreateBrandIntegrationOptions, type CreateBrandPersonaOpts, DEFAULT_BRAND_SYSTEM, type DeriveChartOptions, type DerivePaletteOptions, type Hsl, type IntegrationProvision, type IntegrationSecret, type IntegrationSetting, type LightnessDirection, MAX_SWATCHES, MAX_VIEW_BYTES, type NamedColor, type NearestNamedColor, type Oklab, type Oklch, PICK_TEXT_DEFAULT_CANDIDATES, type ProposePaletteInput, RAMP_L_MAX, RAMP_L_MIN, type RejectProposalInput, type ResolvedBrandDeps, type Rgb, SectionKind, SectionStatus, type SerializedAttr, type SerializedEntity, type SerializedLink, type SerializedLinkEnd, type SerializedSchema, Swatch, type UpsertSectionInput, acceptProposalOps, adjustLightnessUntil, analogous, assertAnalysis, assertAssetContentType, assertHex, assertSectionContent, assertSwatches, assetTools, audienceFanoutOps, base64FromBytes, bookForChannel, bookTools, brandBotTrigger, brandInputFor, brandIntegration, brandRules, brandSkill, capString, capStringArray, clamp01, clampToGamut, complementary, contrastRatio, createAssetOps, createBookOps, createBrandIntegration, createBrandPersona, createBrandRoutes, deltaEOK, deltaEOKLab, deriveChartColors, derivePalette, dispatchBrandTurn, hexToOklch, hslToRgb, inSrgbGamut, linearToSrgb, meetsAA, meetsAAA, monochrome, nearestNamedColor, normalizeHex, oklabToOklch, oklabToRgb, oklchToHex, oklchToOklab, paletteTools, parseBrandDispatch, parseHex, pickTextOn, proposePaletteOps, readTools, recordAnalysisOps, rejectProposalOps, relativeLuminance, resolveDeps, rgbToHsl, rgbToOklab, rotateHue, safeFileName, sectionKey, splitComplementary, srgbToLinear, supportsBrandVision, tetradic, tintShadeRamp, toHex, tombstoneAssetOps, triadic, updateBookOps, upsertSectionOps };
1533
+ export { ASSET_CONTENT_TYPES, type AcceptProposalInput, AssetAnalysis, AssetKind, type AttrType, type AudienceChildren, BRAND_AGENT_PROFILE, BRAND_DISCUSSION_REFERENCE_KINDS, BRAND_INSTRUCTIONS, BRAND_RULES, BRAND_SCHEMA, BookStatus, type BrandActor, type BrandAgentBridge, type BrandAgentProfile, type BrandApprovalReceipt, type BrandAsset, type BrandAttrs, type BrandBook, type BrandBotTriggerOpts, type BrandCapabilityAuthority, BrandConflictError, type BrandDb, type BrandDecisionBinding, type BrandDeps, type BrandDiscussionReference, type BrandDiscussionReferenceKind, type BrandDiscussionReferenceTarget, type BrandDiscussionSwatch, type BrandDispatchBody, type BrandDispatchDeps, type BrandEntityRef, type BrandFetchedBytes, type BrandFileRecord, BrandForbiddenError, BrandGoneError, type BrandHumanAuthorityConsumption, BrandInputError, type BrandIntegrationDescriptor, type BrandIntegrationProbe, type BrandLookup, BrandNotFoundError, type BrandOp, type BrandPalette, type BrandPrincipalProjection, type BrandProposal, type BrandProposalProvenance, type BrandProposalReviewSnapshot, type BrandResult, BrandReviewStateChangedError, type BrandRouteCtx, type BrandRouteOpts, type BrandRow, type BrandRule, type BrandRules, type BrandScalar, type BrandSection, type BrandSkillOpts, type BrandSkillSelf, type BrandSourceAssetSnapshot, type BrandStorage, BrandTokensSnapshot, type BrandToolCtx, type BrandTransactGuard, type BrandTransactOptions, type BrandTrigger, type BrandUploadBody, type BrandVisionCapabilities, type BrandVisionSpec, CHART_DELTA_MIN, CHAT_MESSAGE_NS, CSS_NAMED_COLORS, type ContrastKind, type CreateAssetInput, type CreateBookInput, type CreateBrandIntegrationOptions, type CreateBrandPersonaOpts, DEFAULT_BRAND_SYSTEM, type DeriveChartOptions, type DerivePaletteOptions, type Hsl, type IntegrationProvision, type IntegrationSecret, type IntegrationSetting, type LightnessDirection, MAX_SWATCHES, MAX_VIEW_BYTES, type NamedColor, type NearestNamedColor, type Oklab, type Oklch, PICK_TEXT_DEFAULT_CANDIDATES, PaletteSource, PaletteStatus, ProposalKind, ProposalStatus, type ProposePaletteInput, type ProposeSectionInput, RAMP_L_MAX, RAMP_L_MIN, type RejectProposalInput, type ResolvedBrandDeps, type Rgb, SectionKind, SectionStatus, type SerializedAttr, type SerializedEntity, type SerializedLink, type SerializedLinkEnd, type SerializedSchema, Swatch, type UpsertSectionInput, acceptProposalOps, adjustLightnessUntil, analogous, assertAnalysis, assertAssetContentType, assertHex, assertSectionContent, assertSwatches, assetTools, attachedBrandAssetIds, audienceFanoutOps, base64FromBytes, beginAssetDeleteOps, bookForChannel, bookTools, brandAuthorityRef, brandBotTrigger, brandDiscussionReferenceHref, brandDiscussionReferenceId, brandInputFor, brandIntegration, brandJsonDigest, brandRules, brandSkill, canonicalBrandJson, capString, capStringArray, clamp01, clampToGamut, complementary, contrastRatio, createAssetOps, createBookOps, createBrandIntegration, createBrandPersona, createBrandRoutes, deltaEOK, deltaEOKLab, deriveChartColors, derivePalette, dispatchBrandTurn, finishAssetDeleteOps, formatBrandDiscussionReference, hexToOklch, hslToRgb, inSrgbGamut, isBoundedBrandJson, isBrandHumanAuthorityConsumption, linearToSrgb, meetsAA, meetsAAA, monochrome, nearestNamedColor, normalizeHex, oklabToOklch, oklabToRgb, oklchToHex, oklchToOklab, paletteTools, parseBrandDiscussionReference, parseBrandDispatch, parseHex, pickTextOn, proposalReviewSnapshot, proposePaletteOps, proposeSectionOps, readTools, recordAnalysisOps, rejectProposalOps, relativeLuminance, resolveDeps, rgbToHsl, rgbToOklab, rotateHue, safeFileName, sectionKey, splitComplementary, srgbToLinear, supportsBrandVision, tetradic, tintShadeRamp, toHex, triadic, updateBookOps, upsertSectionOps, verifyBrandApprovalReceipt };