@burdenoff/fe-libs 2026.1007.5 → 2026.1008.1

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.
Files changed (119) hide show
  1. package/dist/shared/assistant/api.d.ts +11 -0
  2. package/dist/shared/assistant/api.d.ts.map +1 -1
  3. package/dist/shared/assistant/api.js +6 -2
  4. package/dist/shared/assistant/attachmentCommit.d.ts +175 -0
  5. package/dist/shared/assistant/attachmentCommit.d.ts.map +1 -0
  6. package/dist/shared/assistant/attachmentCommit.js +638 -0
  7. package/dist/shared/assistant/attachments.d.ts +39 -19
  8. package/dist/shared/assistant/attachments.d.ts.map +1 -1
  9. package/dist/shared/assistant/conversation.d.ts +14 -0
  10. package/dist/shared/assistant/conversation.d.ts.map +1 -1
  11. package/dist/shared/assistant/createSandboxAssistantTransport.d.ts +8 -1
  12. package/dist/shared/assistant/createSandboxAssistantTransport.d.ts.map +1 -1
  13. package/dist/shared/assistant/createSandboxAssistantTransport.js +70 -51
  14. package/dist/shared/assistant/history/historyEngine.js +280 -280
  15. package/dist/shared/assistant/history/historyMapping.d.ts.map +1 -1
  16. package/dist/shared/assistant/history/historyMapping.js +19 -12
  17. package/dist/shared/assistant/i18nManifest.d.ts +23 -2
  18. package/dist/shared/assistant/i18nManifest.d.ts.map +1 -1
  19. package/dist/shared/assistant/i18nManifest.js +26 -3
  20. package/dist/shared/assistant/index.d.ts +9 -0
  21. package/dist/shared/assistant/index.d.ts.map +1 -1
  22. package/dist/shared/assistant/localUiCommandCopy.d.ts +23 -0
  23. package/dist/shared/assistant/localUiCommandCopy.d.ts.map +1 -1
  24. package/dist/shared/assistant/localUiCommandCopy.js +60 -23
  25. package/dist/shared/assistant/localUiCommands.d.ts +29 -0
  26. package/dist/shared/assistant/localUiCommands.d.ts.map +1 -1
  27. package/dist/shared/assistant/localUiCommands.js +18 -7
  28. package/dist/shared/assistant/types.d.ts +19 -8
  29. package/dist/shared/assistant/types.d.ts.map +1 -1
  30. package/dist/shared/assistant/ui/AssistantChatArea.d.ts.map +1 -1
  31. package/dist/shared/assistant/ui/AssistantChatArea.js +1624 -1266
  32. package/dist/shared/assistant/ui/AssistantMarkdownRenderer.d.ts +18 -3
  33. package/dist/shared/assistant/ui/AssistantMarkdownRenderer.d.ts.map +1 -1
  34. package/dist/shared/assistant/ui/AssistantMarkdownRenderer.js +1 -1
  35. package/dist/shared/assistant/ui/AssistantMessageItem.d.ts +5 -0
  36. package/dist/shared/assistant/ui/AssistantMessageItem.d.ts.map +1 -1
  37. package/dist/shared/assistant/ui/AssistantMessageItem.js +89 -84
  38. package/dist/shared/assistant/ui/AssistantMessageList.d.ts +5 -0
  39. package/dist/shared/assistant/ui/AssistantMessageList.d.ts.map +1 -1
  40. package/dist/shared/assistant/ui/AssistantMessageList.js +26 -25
  41. package/dist/shared/assistant/ui/AssistantUiOfferLink.d.ts +45 -0
  42. package/dist/shared/assistant/ui/AssistantUiOfferLink.d.ts.map +1 -0
  43. package/dist/shared/assistant/ui/AssistantUiOfferLink.js +56 -0
  44. package/dist/shared/assistant/ui/assistantOverlayState.d.ts +9 -0
  45. package/dist/shared/assistant/ui/assistantOverlayState.d.ts.map +1 -1
  46. package/dist/shared/assistant/ui/assistantOverlayState.js +37 -28
  47. package/dist/shared/assistant/ui/composer/AssistantAttachmentChips.d.ts +8 -5
  48. package/dist/shared/assistant/ui/composer/AssistantAttachmentChips.d.ts.map +1 -1
  49. package/dist/shared/assistant/ui/composer/AssistantAttachmentChips.js +26 -9
  50. package/dist/shared/assistant/ui/composer/AssistantComposer.d.ts +3 -2
  51. package/dist/shared/assistant/ui/composer/AssistantComposer.d.ts.map +1 -1
  52. package/dist/shared/assistant/ui/composer/AssistantComposer.js +214 -125
  53. package/dist/shared/assistant/ui/composer/AssistantConnectSourceItem.d.ts.map +1 -1
  54. package/dist/shared/assistant/ui/composer/AssistantConnectSourceItem.js +1 -1
  55. package/dist/shared/assistant/ui/voice/AssistantVoiceSession.d.ts +15 -0
  56. package/dist/shared/assistant/ui/voice/AssistantVoiceSession.d.ts.map +1 -1
  57. package/dist/shared/assistant/ui/voice/AssistantVoiceSession.js +127 -118
  58. package/dist/shared/assistant/ui/voice/VoiceConversationView.d.ts +6 -1
  59. package/dist/shared/assistant/ui/voice/VoiceConversationView.d.ts.map +1 -1
  60. package/dist/shared/assistant/ui/voice/VoiceConversationView.js +7 -7
  61. package/dist/shared/assistant/ui/voice/VoiceTranscriptDrawer.d.ts +6 -1
  62. package/dist/shared/assistant/ui/voice/VoiceTranscriptDrawer.d.ts.map +1 -1
  63. package/dist/shared/assistant/ui/voice/VoiceTranscriptDrawer.js +15 -12
  64. package/dist/shared/assistant/uiActions/actOnResolve.d.ts +108 -0
  65. package/dist/shared/assistant/uiActions/actOnResolve.d.ts.map +1 -0
  66. package/dist/shared/assistant/uiActions/actOnResolve.js +51 -0
  67. package/dist/shared/assistant/uiActions/linkContext.d.ts +29 -0
  68. package/dist/shared/assistant/uiActions/linkContext.d.ts.map +1 -1
  69. package/dist/shared/assistant/uiActions/linkContext.js +37 -10
  70. package/dist/shared/assistant/uiActions/navIntent.d.ts +58 -0
  71. package/dist/shared/assistant/uiActions/navIntent.d.ts.map +1 -0
  72. package/dist/shared/assistant/uiActions/navIntent.js +79 -0
  73. package/dist/shared/assistant/uiActions/navigateAction.d.ts +6 -1
  74. package/dist/shared/assistant/uiActions/navigateAction.d.ts.map +1 -1
  75. package/dist/shared/assistant/uiActions/navigateAction.js +18 -14
  76. package/dist/shared/assistant/uiActions/navigationOutcome.d.ts +16 -2
  77. package/dist/shared/assistant/uiActions/navigationOutcome.d.ts.map +1 -1
  78. package/dist/shared/assistant/uiActions/navigationOutcome.js +6 -2
  79. package/dist/shared/assistant/uiActions/offerYesOnSurface.d.ts +39 -0
  80. package/dist/shared/assistant/uiActions/offerYesOnSurface.d.ts.map +1 -0
  81. package/dist/shared/assistant/uiActions/offerYesOnSurface.js +34 -0
  82. package/dist/shared/assistant/uiActions/uiCatalogue.d.ts +14 -0
  83. package/dist/shared/assistant/uiActions/uiCatalogue.d.ts.map +1 -1
  84. package/dist/shared/assistant/uiActions/uiCatalogue.js +23 -3
  85. package/dist/shared/assistant/uiActions/uiOffers.d.ts +249 -0
  86. package/dist/shared/assistant/uiActions/uiOffers.d.ts.map +1 -0
  87. package/dist/shared/assistant/uiActions/uiOffers.js +195 -0
  88. package/dist/shared/assistant/useAssistantAttachments.d.ts +20 -2
  89. package/dist/shared/assistant/useAssistantAttachments.d.ts.map +1 -1
  90. package/dist/shared/assistant/useAssistantAttachments.js +146 -202
  91. package/dist/shared/assistant/useAttachmentCommitter.d.ts +17 -0
  92. package/dist/shared/assistant/useAttachmentCommitter.d.ts.map +1 -0
  93. package/dist/shared/assistant/useAttachmentCommitter.js +41 -0
  94. package/dist/shared/assistant/voiceCommit.d.ts +36 -0
  95. package/dist/shared/assistant/voiceCommit.d.ts.map +1 -0
  96. package/dist/shared/assistant/voiceCommit.js +24 -0
  97. package/dist/shared/assistant/writeProposals.d.ts +6 -0
  98. package/dist/shared/assistant/writeProposals.d.ts.map +1 -1
  99. package/dist/shared/assistant/writeReplyBinder.d.ts +40 -0
  100. package/dist/shared/assistant/writeReplyBinder.d.ts.map +1 -1
  101. package/dist/shared/assistant/writeReplyBinder.js +100 -83
  102. package/dist/shared/assistant/writeReplySend.d.ts +14 -0
  103. package/dist/shared/assistant/writeReplySend.d.ts.map +1 -1
  104. package/dist/shared/assistant/writeReplySend.js +32 -29
  105. package/dist/shared/hooks/index.d.ts +2 -0
  106. package/dist/shared/hooks/index.d.ts.map +1 -1
  107. package/dist/shared/navigation/unsavedChanges.d.ts +83 -0
  108. package/dist/shared/navigation/unsavedChanges.d.ts.map +1 -0
  109. package/dist/shared/navigation/unsavedChanges.js +46 -0
  110. package/dist/shared-assistant.js +247 -238
  111. package/dist/shared-hooks.js +10 -9
  112. package/dist/shared.js +20 -19
  113. package/dist/storage/filesPort.d.ts +111 -0
  114. package/dist/storage/filesPort.d.ts.map +1 -0
  115. package/dist/storage/filesPort.js +262 -0
  116. package/dist/storage/index.d.ts +2 -0
  117. package/dist/storage/index.d.ts.map +1 -1
  118. package/dist/storage/index.js +9 -8
  119. package/package.json +1 -1
@@ -0,0 +1,34 @@
1
+ import { offerYesState as e } from "./uiOffers.js";
2
+ import { isTurnInFlight as t } from "../turnState.js";
3
+ import { latestReplyOnSurface as n } from "./linkContext.js";
4
+ //#region src/shared/assistant/uiActions/offerYesOnSurface.ts
5
+ function r(r, i) {
6
+ let a = n(i.messages, i.voiceSessionId);
7
+ if (!a) return {
8
+ state: "none",
9
+ reply: null
10
+ };
11
+ let { processing: o } = i;
12
+ if (o && o.messageId === a.id && t(o.status)) return {
13
+ state: "none",
14
+ reply: null
15
+ };
16
+ let s = e(r, {
17
+ registry: i.registry,
18
+ actorId: i.actorId,
19
+ conversationId: i.conversationId,
20
+ perfNow: i.perfNow,
21
+ newestReply: {
22
+ id: a.id,
23
+ text: i.displayedText(a)
24
+ },
25
+ productWriteApproval: i.productWriteApproval,
26
+ capabilitiesOf: i.capabilitiesOf
27
+ });
28
+ return {
29
+ state: s,
30
+ reply: s === "none" ? null : a
31
+ };
32
+ }
33
+ //#endregion
34
+ export { r as offerYesOnSurface };
@@ -23,8 +23,22 @@ export interface AssistantUiCatalogue {
23
23
  }
24
24
  export declare const UI_CATALOGUE_MAX_ENTRIES = 120;
25
25
  export declare const UI_CATALOGUE_MAX_BYTES: number;
26
+ /** The key of one sandbox session, as `uiCatalogueSent` and `markUiCatalogueSent` read it. */
27
+ export declare function uiCatalogueSessionKey(sandboxId: string, sessionId: string): string;
28
+ /** A catalogue was delivered to this sandbox session in this page. */
29
+ export declare function uiCatalogueSent(sessionKey: string): boolean;
30
+ /** Record a prompt that carried a catalogue as sent (the oldest key goes past the bound). */
31
+ export declare function markUiCatalogueSent(sessionKey: string): void;
32
+ /** Forget every session (a fresh page's state; the tests start from it). */
33
+ export declare function forgetSentUiCatalogues(): void;
26
34
  export declare function buildUiCatalogue(destinations: readonly LocalDestination[], gate: {
27
35
  permissionsSettled: boolean;
28
36
  simulating: boolean;
37
+ /**
38
+ * A catalogue was already sent to this sandbox session
39
+ * (`uiCatalogueSent`). Only then does a settled, real, EMPTY menu produce
40
+ * `{v:1, entries:[]}` — the replacement for the stale list (RV-1).
41
+ */
42
+ sentBefore?: boolean;
29
43
  }): AssistantUiCatalogue | null;
30
44
  //# sourceMappingURL=uiCatalogue.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"uiCatalogue.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/uiActions/uiCatalogue.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE3D;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,yBAAyB;IACxC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,oBAAoB;IACnC,CAAC,EAAE,CAAC,CAAC;IACL,OAAO,EAAE,yBAAyB,EAAE,CAAC;CACtC;AAED,eAAO,MAAM,wBAAwB,MAAM,CAAC;AAC5C,eAAO,MAAM,sBAAsB,QAAW,CAAC;AAK/C,wBAAgB,gBAAgB,CAC9B,YAAY,EAAE,SAAS,gBAAgB,EAAE,EACzC,IAAI,EAAE;IAAE,kBAAkB,EAAE,OAAO,CAAC;IAAC,UAAU,EAAE,OAAO,CAAA;CAAE,GACzD,oBAAoB,GAAG,IAAI,CAkB7B"}
1
+ {"version":3,"file":"uiCatalogue.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/uiActions/uiCatalogue.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE3D;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,yBAAyB;IACxC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,oBAAoB;IACnC,CAAC,EAAE,CAAC,CAAC;IACL,OAAO,EAAE,yBAAyB,EAAE,CAAC;CACtC;AAED,eAAO,MAAM,wBAAwB,MAAM,CAAC;AAC5C,eAAO,MAAM,sBAAsB,QAAW,CAAC;AAiB/C,8FAA8F;AAC9F,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAElF;AAED,sEAAsE;AACtE,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAE3D;AAED,6FAA6F;AAC7F,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAQ5D;AAED,4EAA4E;AAC5E,wBAAgB,sBAAsB,IAAI,IAAI,CAE7C;AAED,wBAAgB,gBAAgB,CAC9B,YAAY,EAAE,SAAS,gBAAgB,EAAE,EACzC,IAAI,EAAE;IACJ,kBAAkB,EAAE,OAAO,CAAC;IAC5B,UAAU,EAAE,OAAO,CAAC;IACpB;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,GACA,oBAAoB,GAAG,IAAI,CAoB7B"}
@@ -1,7 +1,27 @@
1
1
  //#region src/shared/assistant/uiActions/uiCatalogue.ts
2
- var e = 120, t = 8 * 1024, n = (e) => new TextEncoder().encode(JSON.stringify(e)).length;
3
- function r(e, t) {
2
+ var e = 120, t = 8 * 1024, n = (e) => new TextEncoder().encode(JSON.stringify(e)).length, r = /* @__PURE__ */ new Set(), i = 64;
3
+ function a(e, t) {
4
+ return `${e}\n${t}`;
5
+ }
6
+ function o(e) {
7
+ return r.has(e);
8
+ }
9
+ function s(e) {
10
+ for (r.delete(e), r.add(e); r.size > i;) {
11
+ let e = r.values().next().value;
12
+ if (e === void 0) break;
13
+ r.delete(e);
14
+ }
15
+ }
16
+ function c() {
17
+ r.clear();
18
+ }
19
+ function l(e, t) {
4
20
  if (!t.permissionsSettled || t.simulating) return null;
21
+ if (e.length === 0) return t.sentBefore === !0 ? {
22
+ v: 1,
23
+ entries: []
24
+ } : null;
5
25
  let r = [];
6
26
  for (let t of e.slice(0, 120)) r.push({
7
27
  id: t.id,
@@ -19,4 +39,4 @@ function r(e, t) {
19
39
  } : null;
20
40
  }
21
41
  //#endregion
22
- export { t as UI_CATALOGUE_MAX_BYTES, e as UI_CATALOGUE_MAX_ENTRIES, r as buildUiCatalogue };
42
+ export { t as UI_CATALOGUE_MAX_BYTES, e as UI_CATALOGUE_MAX_ENTRIES, l as buildUiCatalogue, c as forgetSentUiCatalogues, s as markUiCatalogueSent, o as uiCatalogueSent, a as uiCatalogueSessionKey };
@@ -0,0 +1,249 @@
1
+ import { LocalDestination } from '../localUiCommands';
2
+ import { AssistantMode, AssistantRawMessage } from '../types';
3
+ /**
4
+ * ★ BOFF-8060 (N3): the pages the model OFFERS, as the sandbox reports them on
5
+ * the turn poller's `/messages` reads (`uiOffers`, design §2.6 and §3).
6
+ *
7
+ * A pure module: no React, no DOM, no store, no network. The panel owns one
8
+ * `UiOfferSession` per page load (a `useRef`, never persisted), so a reloaded
9
+ * page or a reopened conversation holds no offer at all (C11).
10
+ *
11
+ * ★★ What the sandbox sends is ids only — no label, no path, no model text. The
12
+ * label and the path always come from the person's LIVE, RBAC-filtered
13
+ * registry (`resolveOffer`), re-checked when the link is drawn and again when
14
+ * it is accepted. An offer whose id is not in that registry is never shown.
15
+ *
16
+ * An offer is admitted only for a turn THIS page session sent: the panel
17
+ * records each turn at send time (`recordTurn`), binds the sandbox's own ids
18
+ * for it from the turn's messages (`observeMessages`), and an offer counts
19
+ * only when its `turnId` and `assistantMessageId` are among them. Offers for
20
+ * any other turn are never shown.
21
+ *
22
+ * Offers are navigation only. Nothing here sends, approves or writes.
23
+ */
24
+ /** The sandbox's offer view (design §2.6), strictly checked by `parseUiOffers`. */
25
+ export interface UiOfferView {
26
+ v: 1;
27
+ /** `uo_` + 32 lowercase hex. */
28
+ offerId: string;
29
+ /** A registry id (the N2 catalogue id). No label, no path. */
30
+ catalogueId: string;
31
+ /** The model asked a yes/no question about it. Never true in a write transport. */
32
+ ask: boolean;
33
+ /** The sandbox's user message id the reply answers. */
34
+ turnId: string;
35
+ /** The sandbox's assistant message id of the reply. */
36
+ assistantMessageId: string;
37
+ conversationId: string;
38
+ /** The sandbox's OWN transport (`AI_ASSISTANT_READONLY`), never the panel's guess. */
39
+ transport: UiOfferTransport;
40
+ /** Server clock, ms. */
41
+ mintedAt: number;
42
+ /** Server clock, ms; at most `mintedAt + UI_OFFER_LIFETIME_MS`. */
43
+ expiresAt: number;
44
+ state: UiOfferState;
45
+ }
46
+ export type UiOfferTransport = "read" | "write";
47
+ export type UiOfferState = "live" | "expired";
48
+ /** At most this many offers are read from one `/messages` answer (the server's own cap). */
49
+ export declare const UI_OFFER_MAX_PER_READ = 10;
50
+ /** An offer lives at most 10 minutes from its mint, on the server's clock. */
51
+ export declare const UI_OFFER_LIFETIME_MS = 600000;
52
+ /** The page session never holds more than this many offers; the oldest go first. */
53
+ export declare const UI_OFFER_SESSION_MAX = 50;
54
+ export declare const UI_OFFER_ID_PATTERN: RegExp;
55
+ /** The N2 catalogue id charset (ai-assistant `UI_CATALOGUE_ID_PATTERN`). */
56
+ export declare const UI_OFFER_CATALOGUE_ID_PATTERN: RegExp;
57
+ /** A sandbox message id (opencode `msg_…`). */
58
+ export declare const UI_OFFER_MESSAGE_ID_PATTERN: RegExp;
59
+ /**
60
+ * The panel's conversation id, as the prompt sends it (`api.ts`
61
+ * `PROMPT_CONVERSATION_ID_PATTERN`; a test holds the two equal). Copied, not
62
+ * imported, so this module stays free of the network layer.
63
+ */
64
+ export declare const UI_OFFER_CONVERSATION_ID_PATTERN: RegExp;
65
+ /**
66
+ * The `uiOffers` field of one `/messages` answer, with that answer's `now`.
67
+ *
68
+ * - Absent (an older image, or no offer): an empty list.
69
+ * - Not an array, or no usable server clock: null — nothing is admitted.
70
+ * - Each item is checked field by field and DROPPED on any failure; duplicates
71
+ * keep the first; at most `UI_OFFER_MAX_PER_READ` items are kept.
72
+ */
73
+ export declare function parseUiOffers(raw: unknown, serverNow: unknown): {
74
+ offers: UiOfferView[];
75
+ serverNow: number;
76
+ } | null;
77
+ /** What the person's sidebar shows them NOW, and whether that list is real. */
78
+ export interface UiOfferRegistry {
79
+ destinations: readonly LocalDestination[];
80
+ /** Permissions loaded without error (`useVisibleNavItems`). */
81
+ permissionsSettled: boolean;
82
+ /** A role simulation is running. */
83
+ simulating: boolean;
84
+ }
85
+ /** A resolved offer: the registry's own label and path, never the model's. */
86
+ export interface UiOfferTarget {
87
+ id: string;
88
+ label: string;
89
+ /** Where the sidebar takes the person (`navTargetPath`). */
90
+ path: string;
91
+ context?: string;
92
+ }
93
+ /**
94
+ * The page an offer names, from the LIVE registry — or null.
95
+ *
96
+ * The same gate as `buildUiCatalogue`: never from the optimistic list shown
97
+ * while permissions load, never when the fetch failed, never during a role
98
+ * simulation. Entity routes are never offer targets (catalogue ids are nav ids).
99
+ */
100
+ export declare function resolveOffer(offer: Pick<UiOfferView, "catalogueId">, registry: UiOfferRegistry): UiOfferTarget | null;
101
+ /** A turn THIS page session sent, recorded at send time. */
102
+ export interface UiOfferTurnStart {
103
+ /** The panel's own reply message id (the bubble the offer is drawn under). */
104
+ replyId: string;
105
+ conversationId: string;
106
+ sandboxId: string;
107
+ sessionId: string;
108
+ /** The mode the turn was SENT in (Auto conversations mix transports). */
109
+ mode: AssistantMode;
110
+ /** That mode's `writeCapable`, at send time. */
111
+ writeCapable: boolean;
112
+ /** The signed-in actor who sent it. */
113
+ actorId: string;
114
+ /** The turn's reply floor: only messages created after it are this turn's. */
115
+ floorMs: number;
116
+ }
117
+ /** An admitted offer, with the clock of the read that last carried it. */
118
+ export interface ClientUiOffer extends UiOfferView {
119
+ /** The server's clock the first time this page session saw it. */
120
+ firstSeenServerNow: number;
121
+ /** The server's clock at the last read that carried it… */
122
+ serverNowAtRead: number;
123
+ /** …and the client's monotonic clock at that read. */
124
+ perfAtRead: number;
125
+ /** Accepted once already: a second tap, "yes" or "take me there" does nothing. */
126
+ used: boolean;
127
+ }
128
+ /** Who is looking, where, and at what the sidebar shows — read live by the caller. */
129
+ export interface UiOfferLiveContext {
130
+ registry: UiOfferRegistry;
131
+ /** The signed-in actor now. */
132
+ actorId: string | null | undefined;
133
+ /** The conversation the reply is shown in. */
134
+ conversationId: string | null | undefined;
135
+ /** `performance.now()` (or any monotonic ms). */
136
+ perfNow: number;
137
+ }
138
+ /** A live offer, resolved. */
139
+ export interface LiveUiOffer {
140
+ offer: ClientUiOffer;
141
+ target: UiOfferTarget;
142
+ }
143
+ /** The offer's age (design §5.2): the server clock plus a monotonic delta. */
144
+ export declare function uiOfferAgeMs(offer: ClientUiOffer, perfNow: number): number;
145
+ /** Not expired by the server's word, by its own `expiresAt`, or by the 10-minute life. */
146
+ export declare function uiOfferInTime(offer: ClientUiOffer, perfNow: number): boolean;
147
+ /**
148
+ * The offers this page session has seen, keyed by offer id, and the turns it
149
+ * sent. One per panel, in a `useRef`; never persisted.
150
+ */
151
+ export declare class UiOfferSession {
152
+ private readonly turns;
153
+ private readonly offers;
154
+ /** Record a turn as it is sent. Only such turns can ever show an offer. */
155
+ recordTurn(start: UiOfferTurnStart): void;
156
+ /** The turn recorded for this reply, or undefined (a reopened conversation). */
157
+ turnFor(replyId: string): Readonly<UiOfferTurnStart> | undefined;
158
+ /**
159
+ * Bind the sandbox's own ids for this turn from a `/messages` read: user
160
+ * messages created after the floor, and the assistant messages that answer
161
+ * them (`parentID`). True when something new was learned.
162
+ */
163
+ observeMessages(replyId: string, messages: readonly AssistantRawMessage[]): boolean;
164
+ /**
165
+ * Take the offers of one `/messages` read for this turn. Only the turn's
166
+ * own conversation is kept; an offer seen before keeps its first sighting
167
+ * and whether it was used, and takes the newer state and clock. True when
168
+ * anything changed.
169
+ */
170
+ receive(replyId: string, raw: unknown, serverNow: unknown, perfNow: number): boolean;
171
+ private evict;
172
+ /** Every offer bound to this reply's turn, used or not, live or not. */
173
+ offersFor(replyId: string): ClientUiOffer[];
174
+ /**
175
+ * The offers that may be shown or accepted under this reply now (design
176
+ * §3.2 `liveOfferFor`): the turn was sent from this page session by the actor
177
+ * signed in now, into the conversation shown; the offer is live, unused, in
178
+ * time, and names a page the person's live registry holds.
179
+ */
180
+ liveOffersFor(replyId: string, context: UiOfferLiveContext): LiveUiOffer[];
181
+ /**
182
+ * Claim an offer for acceptance. Set BEFORE navigating, so a double tap or a
183
+ * double "yes" does nothing the second time. False when it was already used
184
+ * or is unknown.
185
+ */
186
+ markUsed(offerId: string): boolean;
187
+ /**
188
+ * ★ BOFF-8060 (N4): give back a claim whose navigation was REFUSED for
189
+ * unsaved changes. Nothing was routed, so the offer was not used: its "Open
190
+ * {page}" link comes back, for when the person has saved or discarded.
191
+ * False when it is unknown or was not claimed.
192
+ */
193
+ release(offerId: string): boolean;
194
+ /** One offer by id, or undefined. */
195
+ offer(offerId: string): ClientUiOffer | undefined;
196
+ /** The reply an offer is bound to in this page session, or undefined. */
197
+ replyIdOf(offerId: string): string | undefined;
198
+ /**
199
+ * Milliseconds until the next bound, unused, live offer runs out of time, or
200
+ * null when none will. The panel re-renders then, so an expired link goes.
201
+ */
202
+ nextExpiryInMs(perfNow: number): number | null;
203
+ }
204
+ /**
205
+ * Which hint goes under the link (design §4): "…or “yes”" only for an offer the
206
+ * model asked about in a read transport — the sandbox's own transport AND the
207
+ * mode the turn was sent in. Anything else gets the tap / "take me there" hint.
208
+ */
209
+ export declare function uiOfferHintKind(offer: Pick<UiOfferView, "ask" | "transport">, turn: Pick<UiOfferTurnStart, "writeCapable"> | undefined): "read" | "link";
210
+ /**
211
+ * Y5: the reply asked exactly ONE question, and it is the last sentence.
212
+ *
213
+ * Code (fenced and inline), markdown link targets, autolinks and bare URLs
214
+ * are removed first — a `?` in a URL or a snippet is not a question. `?`, `؟`,
215
+ * `?` and `¿` all count, so a reply that also asks something in another script
216
+ * is not "one question".
217
+ */
218
+ export declare function asksOneQuestionLast(text: string): boolean;
219
+ /** What the binder may do with a bare "yes" (design §6). */
220
+ export type UiOfferYesState = "acceptable" | "expired" | "none";
221
+ /** What `offerYesState` reads, all of it live at the decision point. */
222
+ export interface UiOfferYesInput extends UiOfferLiveContext {
223
+ /** The newest assistant reply on the surface the "yes" came from, with its displayed text; null when a person message came after it. */
224
+ newestReply: {
225
+ id: string;
226
+ text: string;
227
+ } | null;
228
+ /** The product's own write approval (`proposal-v1` or not). */
229
+ productWriteApproval: string | null | undefined;
230
+ /** The issuing sandbox's own `/health`, as recorded. */
231
+ capabilitiesOf: (sandboxId: string) => {
232
+ uiOffers?: boolean;
233
+ writeApprovalMode?: string;
234
+ } | null | undefined;
235
+ }
236
+ /**
237
+ * Whether a bare "yes" accepts an offer, for the 5a binder's precedence row
238
+ * (design §6, guards Y1–Y6; Y7 — a bare English affirm — is the binder's).
239
+ *
240
+ * `acceptable` only when ALL hold: the product and the issuing sandbox are
241
+ * proposal-v1 and the sandbox serves offers (Y1); the sandbox's transport is
242
+ * read AND the mode the turn was sent in cannot write (Y2); exactly one live
243
+ * offer under the newest reply on the surface (Y3); the model asked about it
244
+ * (Y4); the reply asked one question, last (Y5); in time, unused, resolvable
245
+ * (Y6). `expired` when the one offer that would otherwise qualify ran out of
246
+ * time. Everything else is `none`, and the binder keeps its 5a meaning.
247
+ */
248
+ export declare function offerYesState(session: UiOfferSession, input: UiOfferYesInput): UiOfferYesState;
249
+ //# sourceMappingURL=uiOffers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uiOffers.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/uiActions/uiOffers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,195 @@
1
+ //#region src/shared/assistant/uiActions/uiOffers.ts
2
+ var e = 10, t = 6e5, n = 50, r = /^uo_[0-9a-f]{32}$/, i = /^[A-Za-z0-9:_.-]{1,64}$/, a = /^[A-Za-z0-9_-]{1,128}$/, o = /^[A-Za-z0-9_-]{1,128}$/, s = new Set(["read", "write"]), c = new Set(["live", "expired"]), l = (e) => typeof e == "object" && !!e && !Array.isArray(e), u = (e, t) => typeof e == "string" && t.test(e), d = (e) => typeof e == "number" && Number.isFinite(e);
3
+ function f(e) {
4
+ if (!l(e) || e.v !== 1) return null;
5
+ let { offerId: t, catalogueId: n, ask: f, turnId: p, assistantMessageId: m, conversationId: h, transport: g, mintedAt: _, expiresAt: v, state: y } = e;
6
+ return !u(t, r) || !u(n, i) || typeof f != "boolean" || !u(p, a) || !u(m, a) || !u(h, o) || typeof g != "string" || !s.has(g) || typeof y != "string" || !c.has(y) || !d(_) || !d(v) || v < _ || v - _ > 6e5 || f && g !== "read" ? null : {
7
+ v: 1,
8
+ offerId: t,
9
+ catalogueId: n,
10
+ ask: f,
11
+ turnId: p,
12
+ assistantMessageId: m,
13
+ conversationId: h,
14
+ transport: g,
15
+ mintedAt: _,
16
+ expiresAt: v,
17
+ state: y
18
+ };
19
+ }
20
+ function p(e, t) {
21
+ if (!d(t)) return null;
22
+ if (e === void 0) return {
23
+ offers: [],
24
+ serverNow: t
25
+ };
26
+ if (!Array.isArray(e)) return null;
27
+ let n = [], r = /* @__PURE__ */ new Set();
28
+ for (let t of e) {
29
+ if (n.length >= 10) break;
30
+ let e = f(t);
31
+ !e || r.has(e.offerId) || (r.add(e.offerId), n.push(e));
32
+ }
33
+ return {
34
+ offers: n,
35
+ serverNow: t
36
+ };
37
+ }
38
+ function m(e, t) {
39
+ if (!t.permissionsSettled || t.simulating) return null;
40
+ let n = t.destinations.find((t) => t.id === e.catalogueId);
41
+ return n ? {
42
+ id: n.id,
43
+ label: n.label,
44
+ path: n.path,
45
+ ...n.context ? { context: n.context } : {}
46
+ } : null;
47
+ }
48
+ function h(e, t) {
49
+ return e.serverNowAtRead - e.mintedAt + Math.max(0, t - e.perfAtRead);
50
+ }
51
+ function g(e, t) {
52
+ if (e.state !== "live") return !1;
53
+ let n = h(e, t);
54
+ return n <= 6e5 && e.mintedAt + n < e.expiresAt;
55
+ }
56
+ function _(e, t) {
57
+ let n = e.info?.time?.created;
58
+ return typeof n == "number" && n > t;
59
+ }
60
+ var v = class {
61
+ turns = /* @__PURE__ */ new Map();
62
+ offers = /* @__PURE__ */ new Map();
63
+ recordTurn(e) {
64
+ this.turns.set(e.replyId, {
65
+ ...e,
66
+ serverTurns: /* @__PURE__ */ new Map()
67
+ });
68
+ }
69
+ turnFor(e) {
70
+ return this.turns.get(e);
71
+ }
72
+ observeMessages(e, t) {
73
+ let n = this.turns.get(e);
74
+ if (!n) return !1;
75
+ let r = !1;
76
+ for (let e of t) {
77
+ if (!_(e, n.floorMs)) continue;
78
+ let t = e.info?.id;
79
+ typeof t == "string" && e.info?.role === "user" && !n.serverTurns.has(t) && (n.serverTurns.set(t, /* @__PURE__ */ new Set()), r = !0);
80
+ }
81
+ for (let e of t) {
82
+ if (!_(e, n.floorMs)) continue;
83
+ let t = e.info?.id, i = e.info?.parentID;
84
+ if (e.info?.role !== "assistant" || typeof t != "string" || typeof i != "string") continue;
85
+ let a = n.serverTurns.get(i);
86
+ a && !a.has(t) && (a.add(t), r = !0);
87
+ }
88
+ return r;
89
+ }
90
+ receive(e, t, n, r) {
91
+ let i = this.turns.get(e);
92
+ if (!i) return !1;
93
+ let a = p(t, n);
94
+ if (!a) return !1;
95
+ let o = !1;
96
+ for (let e of a.offers) {
97
+ if (e.conversationId !== i.conversationId) continue;
98
+ let t = this.offers.get(e.offerId);
99
+ t && (t.turnId !== e.turnId || t.assistantMessageId !== e.assistantMessageId || t.catalogueId !== e.catalogueId || t.conversationId !== e.conversationId) || (this.offers.set(e.offerId, {
100
+ ...e,
101
+ state: t?.state === "expired" ? "expired" : e.state,
102
+ firstSeenServerNow: t?.firstSeenServerNow ?? a.serverNow,
103
+ serverNowAtRead: a.serverNow,
104
+ perfAtRead: r,
105
+ used: t?.used ?? !1
106
+ }), o = !0);
107
+ }
108
+ return this.evict(), o;
109
+ }
110
+ evict() {
111
+ if (this.offers.size <= 50) return;
112
+ let e = [...this.offers.values()].sort((e, t) => e.mintedAt - t.mintedAt);
113
+ for (let t of e.slice(0, this.offers.size - 50)) this.offers.delete(t.offerId);
114
+ }
115
+ offersFor(e) {
116
+ let t = this.turns.get(e);
117
+ return t ? [...this.offers.values()].filter((e) => e.conversationId === t.conversationId && t.serverTurns.get(e.turnId)?.has(e.assistantMessageId) === !0).sort((e, t) => e.mintedAt - t.mintedAt) : [];
118
+ }
119
+ liveOffersFor(e, t) {
120
+ let n = this.turns.get(e);
121
+ if (!n || !t.actorId || n.actorId !== t.actorId || !t.conversationId || n.conversationId !== t.conversationId) return [];
122
+ let r = [];
123
+ for (let n of this.offersFor(e)) {
124
+ if (n.used || !g(n, t.perfNow)) continue;
125
+ let e = m(n, t.registry);
126
+ e && r.push({
127
+ offer: n,
128
+ target: e
129
+ });
130
+ }
131
+ return r;
132
+ }
133
+ markUsed(e) {
134
+ let t = this.offers.get(e);
135
+ return !t || t.used ? !1 : (this.offers.set(e, {
136
+ ...t,
137
+ used: !0
138
+ }), !0);
139
+ }
140
+ release(e) {
141
+ let t = this.offers.get(e);
142
+ return !t || !t.used ? !1 : (this.offers.set(e, {
143
+ ...t,
144
+ used: !1
145
+ }), !0);
146
+ }
147
+ offer(e) {
148
+ return this.offers.get(e);
149
+ }
150
+ replyIdOf(e) {
151
+ let t = this.offers.get(e);
152
+ if (t) {
153
+ for (let [e, n] of this.turns) if (t.conversationId === n.conversationId && n.serverTurns.get(t.turnId)?.has(t.assistantMessageId) === !0) return e;
154
+ }
155
+ }
156
+ nextExpiryInMs(e) {
157
+ let n = null;
158
+ for (let r of this.turns.keys()) for (let i of this.offersFor(r)) {
159
+ if (i.used || !g(i, e)) continue;
160
+ let r = h(i, e), a = Math.min(t - r, i.expiresAt - (i.mintedAt + r));
161
+ n = n === null ? a : Math.min(n, a);
162
+ }
163
+ return n === null ? null : Math.max(0, n);
164
+ }
165
+ };
166
+ function y(e, t) {
167
+ return e.ask && e.transport === "read" && t?.writeCapable === !1 ? "read" : "link";
168
+ }
169
+ var b = /[?؟?¿]/g, x = /[\s*_)\]"'”’»]+$/u;
170
+ function S(e) {
171
+ let t = e.replace(/```[\s\S]*?```/g, " ").replace(/`[^`]*`/g, " ").replace(/!?\[([^\]]*)\]\([^)]*\)/g, "$1").replace(/<[a-z][a-z0-9+.-]*:[^>\s]*>/gi, " ").replace(/\b[a-z][a-z0-9+.-]*:\/\/\S+/gi, " ");
172
+ if ((t.match(b) ?? []).length !== 1) return !1;
173
+ let n = t.replace(x, "");
174
+ return /[?؟?]$/.test(n);
175
+ }
176
+ function C(e, t) {
177
+ let n = t.newestReply;
178
+ if (!n) return "none";
179
+ let r = e.turnFor(n.id);
180
+ if (!r || !t.actorId || r.actorId !== t.actorId || !t.conversationId || r.conversationId !== t.conversationId || t.productWriteApproval !== "proposal-v1") return "none";
181
+ let i = t.capabilitiesOf(r.sandboxId);
182
+ if (i?.uiOffers !== !0 || i.writeApprovalMode !== "proposal-v1" || r.writeCapable !== !1 || !S(n.text)) return "none";
183
+ let a = e.offersFor(n.id).filter((e) => !e.used), o = e.liveOffersFor(n.id, t), s = (e) => e.transport === "read" && e.ask;
184
+ if (o.length === 1) {
185
+ let e = o[0];
186
+ return e && a.length === 1 && s(e.offer) ? "acceptable" : "none";
187
+ }
188
+ if (o.length === 0 && a.length === 1) {
189
+ let e = a[0];
190
+ if (e && s(e) && !g(e, t.perfNow) && m(e, t.registry)) return "expired";
191
+ }
192
+ return "none";
193
+ }
194
+ //#endregion
195
+ export { i as UI_OFFER_CATALOGUE_ID_PATTERN, o as UI_OFFER_CONVERSATION_ID_PATTERN, r as UI_OFFER_ID_PATTERN, t as UI_OFFER_LIFETIME_MS, e as UI_OFFER_MAX_PER_READ, a as UI_OFFER_MESSAGE_ID_PATTERN, n as UI_OFFER_SESSION_MAX, v as UiOfferSession, S as asksOneQuestionLast, C as offerYesState, p as parseUiOffers, m as resolveOffer, h as uiOfferAgeMs, y as uiOfferHintKind, g as uiOfferInTime };
@@ -1,9 +1,10 @@
1
1
  import { AssistantAttachment, AttachmentRejection, AttachmentSendBlocker } from './attachments';
2
+ import { AttachmentCommitResult, CommitOptions } from './attachmentCommit';
2
3
  export interface UseAssistantAttachmentsResult {
3
4
  /** Files being read/downscaled — no chip of their own yet. See below. */
4
5
  preparingCount: number;
5
6
  attachments: AssistantAttachment[];
6
- /** True while any attachment is still being prepared or uploaded. */
7
+ /** True while any attachment is still being prepared or saved (Send's commit). */
7
8
  isBusy: boolean;
8
9
  /**
9
10
  * Why the current attachments block sending, or `null` when they do not.
@@ -15,12 +16,29 @@ export interface UseAssistantAttachmentsResult {
15
16
  /** Most recent rejection, for a transient inline message. */
16
17
  rejection: AttachmentRejection | null;
17
18
  addFiles: (files: FileList | File[] | null | undefined) => void;
19
+ /** Drop a draft attachment. Ignored while Send is saving that very chip. */
18
20
  remove: (id: string) => void;
19
- /** Re-upload a single failed attachment, reusing the bytes already prepared. */
21
+ /** Clear the reason a Send could not save this attachment, ready for the next Send. */
20
22
  retry: (id: string) => void;
23
+ /** Drop the whole draft; a commit in flight is cancelled and rolled back first. */
21
24
  clear: () => void;
22
25
  clearRejection: () => void;
23
26
  canAddMore: boolean;
27
+ /**
28
+ * Save the draft to Files and mint download URLs — the one step that touches the file library.
29
+ * Resolves with the attachments to send (see `AttachmentCommitResult`); on failure or cancel it
30
+ * has undone what it created and the draft is intact. Single flight: a second call while one is
31
+ * running returns the same promise.
32
+ */
33
+ commit: (options?: {
34
+ mode?: CommitOptions['mode'];
35
+ budgetMs?: number;
36
+ signal?: AbortSignal;
37
+ }) => Promise<AttachmentCommitResult>;
38
+ /** Stop the commit in flight (it rolls back and resolves `{ ok: false, cancelled: true }`). */
39
+ cancelCommit: () => void;
40
+ /** True from the moment `commit()` is called until it settles. */
41
+ isCommitting: boolean;
24
42
  }
25
43
  export interface UseAssistantAttachmentsOptions {
26
44
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"useAssistantAttachments.d.ts","sourceRoot":"","sources":["../../../src/shared/assistant/useAssistantAttachments.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAOH,OAAO,EAYL,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACxB,KAAK,qBAAqB,EAC3B,MAAM,eAAe,CAAC;AAsJvB,MAAM,WAAW,6BAA6B;IAC5C,yEAAyE;IACzE,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,mBAAmB,EAAE,CAAC;IACnC,qEAAqE;IACrE,MAAM,EAAE,OAAO,CAAC;IAChB;;;;;OAKG;IACH,WAAW,EAAE,qBAAqB,GAAG,IAAI,CAAC;IAC1C,6DAA6D;IAC7D,SAAS,EAAE,mBAAmB,GAAG,IAAI,CAAC;IACtC,QAAQ,EAAE,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI,EAAE,GAAG,IAAI,GAAG,SAAS,KAAK,IAAI,CAAC;IAChE,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7B,gFAAgF;IAChF,KAAK,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5B,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,8BAA8B;IAC7C;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,uBAAuB,CACrC,OAAO,GAAE,8BAAmC,GAC3C,6BAA6B,CAyQ/B"}
1
+ {"version":3,"file":"useAssistantAttachments.d.ts","sourceRoot":"","sources":["../../../src/shared/assistant/useAssistantAttachments.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAIH,OAAO,EAYL,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACxB,KAAK,qBAAqB,EAC3B,MAAM,eAAe,CAAC;AAEvB,OAAO,EAEL,KAAK,sBAAsB,EAE3B,KAAK,aAAa,EACnB,MAAM,oBAAoB,CAAC;AAkJ5B,MAAM,WAAW,6BAA6B;IAC5C,yEAAyE;IACzE,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,mBAAmB,EAAE,CAAC;IACnC,kFAAkF;IAClF,MAAM,EAAE,OAAO,CAAC;IAChB;;;;;OAKG;IACH,WAAW,EAAE,qBAAqB,GAAG,IAAI,CAAC;IAC1C,6DAA6D;IAC7D,SAAS,EAAE,mBAAmB,GAAG,IAAI,CAAC;IACtC,QAAQ,EAAE,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI,EAAE,GAAG,IAAI,GAAG,SAAS,KAAK,IAAI,CAAC;IAChE,4EAA4E;IAC5E,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7B,uFAAuF;IACvF,KAAK,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5B,mFAAmF;IACnF,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,UAAU,EAAE,OAAO,CAAC;IACpB;;;;;OAKG;IACH,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE;QACjB,IAAI,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;QAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,MAAM,CAAC,EAAE,WAAW,CAAC;KACtB,KAAK,OAAO,CAAC,sBAAsB,CAAC,CAAC;IACtC,+FAA+F;IAC/F,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,kEAAkE;IAClE,YAAY,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,8BAA8B;IAC7C;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,uBAAuB,CACrC,OAAO,GAAE,8BAAmC,GAC3C,6BAA6B,CAwN/B"}