@buoy-gg/ask-buoy 7.0.38 → 7.0.39
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/lib/commonjs/blocks/AskBlocks.js +338 -1
- package/lib/commonjs/blocks/AskBlocks.js.map +1 -0
- package/lib/commonjs/blocks/BlockRenderer.js +262 -1
- package/lib/commonjs/blocks/BlockRenderer.js.map +1 -0
- package/lib/commonjs/blocks/ChromePrototypes.js +514 -1
- package/lib/commonjs/blocks/ChromePrototypes.js.map +1 -0
- package/lib/commonjs/blocks/DataBlocks.js +781 -1
- package/lib/commonjs/blocks/DataBlocks.js.map +1 -0
- package/lib/commonjs/blocks/ExtraBlocks.js +1860 -1
- package/lib/commonjs/blocks/ExtraBlocks.js.map +1 -0
- package/lib/commonjs/blocks/MediaBlocks.js +156 -1
- package/lib/commonjs/blocks/MediaBlocks.js.map +1 -0
- package/lib/commonjs/blocks/ReceiptBlocks.js +586 -1
- package/lib/commonjs/blocks/ReceiptBlocks.js.map +1 -0
- package/lib/commonjs/blocks/blockText.js +60 -1
- package/lib/commonjs/blocks/blockText.js.map +1 -0
- package/lib/commonjs/blocks/blockText.test.js +53 -1
- package/lib/commonjs/blocks/blockText.test.js.map +1 -0
- package/lib/commonjs/blocks/context.js +42 -1
- package/lib/commonjs/blocks/context.js.map +1 -0
- package/lib/commonjs/blocks/icons.js +96 -1
- package/lib/commonjs/blocks/icons.js.map +1 -0
- package/lib/commonjs/blocks/index.js +95 -1
- package/lib/commonjs/blocks/index.js.map +1 -0
- package/lib/commonjs/blocks/listRow.test.js +55 -1
- package/lib/commonjs/blocks/listRow.test.js.map +1 -0
- package/lib/commonjs/blocks/pageState.js +34 -1
- package/lib/commonjs/blocks/pageState.js.map +1 -0
- package/lib/commonjs/blocks/pageState.test.js +57 -1
- package/lib/commonjs/blocks/pageState.test.js.map +1 -0
- package/lib/commonjs/blocks/primitives.js +457 -1
- package/lib/commonjs/blocks/primitives.js.map +1 -0
- package/lib/commonjs/blocks/primitivesIndex.js +62 -1
- package/lib/commonjs/blocks/primitivesIndex.js.map +1 -0
- package/lib/commonjs/components/ApprovalCard.js +297 -1
- package/lib/commonjs/components/ApprovalCard.js.map +1 -0
- package/lib/commonjs/components/AskBuoyHeader.js +196 -1
- package/lib/commonjs/components/AskBuoyHeader.js.map +1 -0
- package/lib/commonjs/components/AskBuoyIcon.js +19 -1
- package/lib/commonjs/components/AskBuoyIcon.js.map +1 -0
- package/lib/commonjs/components/AskBuoyModal.js +479 -1
- package/lib/commonjs/components/AskBuoyModal.js.map +1 -0
- package/lib/commonjs/components/AskBuoySettings.js +181 -1
- package/lib/commonjs/components/AskBuoySettings.js.map +1 -0
- package/lib/commonjs/components/ChangesBar.js +211 -1
- package/lib/commonjs/components/ChangesBar.js.map +1 -0
- package/lib/commonjs/components/Composer.js +255 -1
- package/lib/commonjs/components/Composer.js.map +1 -0
- package/lib/commonjs/components/EmptyState.js +161 -1
- package/lib/commonjs/components/EmptyState.js.map +1 -0
- package/lib/commonjs/components/KeyboardPad.js +80 -1
- package/lib/commonjs/components/KeyboardPad.js.map +1 -0
- package/lib/commonjs/components/Markdown.js +310 -1
- package/lib/commonjs/components/Markdown.js.map +1 -0
- package/lib/commonjs/components/MessageList.js +970 -1
- package/lib/commonjs/components/MessageList.js.map +1 -0
- package/lib/commonjs/components/QueuedMessages.js +145 -1
- package/lib/commonjs/components/QueuedMessages.js.map +1 -0
- package/lib/commonjs/components/ThinkingStrip.js +223 -1
- package/lib/commonjs/components/ThinkingStrip.js.map +1 -0
- package/lib/commonjs/components/TypingDots.js +63 -1
- package/lib/commonjs/components/TypingDots.js.map +1 -0
- package/lib/commonjs/components/markdownParse.js +131 -1
- package/lib/commonjs/components/markdownParse.js.map +1 -0
- package/lib/commonjs/components/markdownParse.test.js +99 -1
- package/lib/commonjs/components/markdownParse.test.js.map +1 -0
- package/lib/commonjs/components/useCopyAction.js +50 -1
- package/lib/commonjs/components/useCopyAction.js.map +1 -0
- package/lib/commonjs/index.js +252 -1
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/preset.js +91 -1
- package/lib/commonjs/preset.js.map +1 -0
- package/lib/commonjs/store/activityGroups.js +110 -1
- package/lib/commonjs/store/activityGroups.js.map +1 -0
- package/lib/commonjs/store/activityGroups.test.js +78 -1
- package/lib/commonjs/store/activityGroups.test.js.map +1 -0
- package/lib/commonjs/store/askBuoySettings.js +72 -1
- package/lib/commonjs/store/askBuoySettings.js.map +1 -0
- package/lib/commonjs/store/askBuoyStore.js +589 -1
- package/lib/commonjs/store/askBuoyStore.js.map +1 -0
- package/lib/commonjs/store/blockPlacement.js +64 -1
- package/lib/commonjs/store/blockPlacement.js.map +1 -0
- package/lib/commonjs/store/blockPlacement.test.js +123 -1
- package/lib/commonjs/store/blockPlacement.test.js.map +1 -0
- package/lib/commonjs/store/queue.test.js +150 -1
- package/lib/commonjs/store/queue.test.js.map +1 -0
- package/lib/commonjs/store/resetConversation.js +77 -1
- package/lib/commonjs/store/resetConversation.js.map +1 -0
- package/lib/commonjs/store/restorePending.test.js +63 -1
- package/lib/commonjs/store/restorePending.test.js.map +1 -0
- package/lib/commonjs/store/restoredIds.test.js +47 -1
- package/lib/commonjs/store/restoredIds.test.js.map +1 -0
- package/lib/commonjs/store/suggestions.js +54 -1
- package/lib/commonjs/store/suggestions.js.map +1 -0
- package/lib/commonjs/store/suggestions.test.js +58 -1
- package/lib/commonjs/store/suggestions.test.js.map +1 -0
- package/lib/commonjs/store/systemLine.test.js +77 -1
- package/lib/commonjs/store/systemLine.test.js.map +1 -0
- package/lib/commonjs/store/ticketPrompt.js +17 -1
- package/lib/commonjs/store/ticketPrompt.js.map +1 -0
- package/lib/commonjs/store/traceText.js +81 -1
- package/lib/commonjs/store/traceText.js.map +1 -0
- package/lib/commonjs/store/traceText.test.js +112 -1
- package/lib/commonjs/store/traceText.test.js.map +1 -0
- package/lib/commonjs/store/transcriptPersistence.js +297 -1
- package/lib/commonjs/store/transcriptPersistence.js.map +1 -0
- package/lib/commonjs/store/transcriptPersistence.test.js +333 -1
- package/lib/commonjs/store/transcriptPersistence.test.js.map +1 -0
- package/lib/commonjs/store/turnRendering.test.js +151 -1
- package/lib/commonjs/store/turnRendering.test.js.map +1 -0
- package/lib/commonjs/store/useAskBuoy.js +651 -1
- package/lib/commonjs/store/useAskBuoy.js.map +1 -0
- package/lib/commonjs/store/useAskBuoySettings.js +14 -1
- package/lib/commonjs/store/useAskBuoySettings.js.map +1 -0
- package/lib/commonjs/sync/askBuoySyncAdapter.js +153 -1
- package/lib/commonjs/sync/askBuoySyncAdapter.js.map +1 -0
- package/lib/commonjs/sync/askBuoySyncAdapter.test.js +141 -1
- package/lib/commonjs/sync/askBuoySyncAdapter.test.js.map +1 -0
- package/lib/commonjs/sync/wire.js +58 -1
- package/lib/commonjs/sync/wire.js.map +1 -0
- package/lib/commonjs/types.js +6 -1
- package/lib/commonjs/types.js.map +1 -0
- package/lib/module/blocks/AskBlocks.js +331 -1
- package/lib/module/blocks/AskBlocks.js.map +1 -0
- package/lib/module/blocks/BlockRenderer.js +257 -1
- package/lib/module/blocks/BlockRenderer.js.map +1 -0
- package/lib/module/blocks/ChromePrototypes.js +503 -1
- package/lib/module/blocks/ChromePrototypes.js.map +1 -0
- package/lib/module/blocks/DataBlocks.js +767 -1
- package/lib/module/blocks/DataBlocks.js.map +1 -0
- package/lib/module/blocks/ExtraBlocks.js +1833 -1
- package/lib/module/blocks/ExtraBlocks.js.map +1 -0
- package/lib/module/blocks/MediaBlocks.js +151 -1
- package/lib/module/blocks/MediaBlocks.js.map +1 -0
- package/lib/module/blocks/ReceiptBlocks.js +574 -1
- package/lib/module/blocks/ReceiptBlocks.js.map +1 -0
- package/lib/module/blocks/blockText.js +55 -1
- package/lib/module/blocks/blockText.js.map +1 -0
- package/lib/module/blocks/blockText.test.js +53 -1
- package/lib/module/blocks/blockText.test.js.map +1 -0
- package/lib/module/blocks/context.js +35 -1
- package/lib/module/blocks/context.js.map +1 -0
- package/lib/module/blocks/icons.js +91 -1
- package/lib/module/blocks/icons.js.map +1 -0
- package/lib/module/blocks/index.js +8 -1
- package/lib/module/blocks/index.js.map +1 -0
- package/lib/module/blocks/listRow.test.js +56 -1
- package/lib/module/blocks/listRow.test.js.map +1 -0
- package/lib/module/blocks/pageState.js +30 -1
- package/lib/module/blocks/pageState.js.map +1 -0
- package/lib/module/blocks/pageState.test.js +56 -1
- package/lib/module/blocks/pageState.test.js.map +1 -0
- package/lib/module/blocks/primitives.js +445 -1
- package/lib/module/blocks/primitives.js.map +1 -0
- package/lib/module/blocks/primitivesIndex.js +5 -1
- package/lib/module/blocks/primitivesIndex.js.map +1 -0
- package/lib/module/components/ApprovalCard.js +292 -1
- package/lib/module/components/ApprovalCard.js.map +1 -0
- package/lib/module/components/AskBuoyHeader.js +193 -1
- package/lib/module/components/AskBuoyHeader.js.map +1 -0
- package/lib/module/components/AskBuoyIcon.js +8 -1
- package/lib/module/components/AskBuoyIcon.js.map +1 -0
- package/lib/module/components/AskBuoyModal.js +474 -1
- package/lib/module/components/AskBuoyModal.js.map +1 -0
- package/lib/module/components/AskBuoySettings.js +176 -1
- package/lib/module/components/AskBuoySettings.js.map +1 -0
- package/lib/module/components/ChangesBar.js +206 -1
- package/lib/module/components/ChangesBar.js.map +1 -0
- package/lib/module/components/Composer.js +250 -1
- package/lib/module/components/Composer.js.map +1 -0
- package/lib/module/components/EmptyState.js +156 -1
- package/lib/module/components/EmptyState.js.map +1 -0
- package/lib/module/components/KeyboardPad.js +75 -1
- package/lib/module/components/KeyboardPad.js.map +1 -0
- package/lib/module/components/Markdown.js +305 -1
- package/lib/module/components/Markdown.js.map +1 -0
- package/lib/module/components/MessageList.js +964 -1
- package/lib/module/components/MessageList.js.map +1 -0
- package/lib/module/components/QueuedMessages.js +140 -1
- package/lib/module/components/QueuedMessages.js.map +1 -0
- package/lib/module/components/ThinkingStrip.js +218 -1
- package/lib/module/components/ThinkingStrip.js.map +1 -0
- package/lib/module/components/TypingDots.js +58 -1
- package/lib/module/components/TypingDots.js.map +1 -0
- package/lib/module/components/markdownParse.js +125 -1
- package/lib/module/components/markdownParse.js.map +1 -0
- package/lib/module/components/markdownParse.test.js +98 -1
- package/lib/module/components/markdownParse.test.js.map +1 -0
- package/lib/module/components/useCopyAction.js +46 -1
- package/lib/module/components/useCopyAction.js.map +1 -0
- package/lib/module/index.js +34 -1
- package/lib/module/index.js.map +1 -0
- package/lib/module/preset.js +74 -1
- package/lib/module/preset.js.map +1 -0
- package/lib/module/store/activityGroups.js +103 -1
- package/lib/module/store/activityGroups.js.map +1 -0
- package/lib/module/store/activityGroups.test.js +77 -1
- package/lib/module/store/activityGroups.test.js.map +1 -0
- package/lib/module/store/askBuoySettings.js +67 -1
- package/lib/module/store/askBuoySettings.js.map +1 -0
- package/lib/module/store/askBuoyStore.js +583 -1
- package/lib/module/store/askBuoyStore.js.map +1 -0
- package/lib/module/store/blockPlacement.js +59 -1
- package/lib/module/store/blockPlacement.js.map +1 -0
- package/lib/module/store/blockPlacement.test.js +122 -1
- package/lib/module/store/blockPlacement.test.js.map +1 -0
- package/lib/module/store/queue.test.js +149 -1
- package/lib/module/store/queue.test.js.map +1 -0
- package/lib/module/store/resetConversation.js +72 -1
- package/lib/module/store/resetConversation.js.map +1 -0
- package/lib/module/store/restorePending.test.js +62 -1
- package/lib/module/store/restorePending.test.js.map +1 -0
- package/lib/module/store/restoredIds.test.js +46 -1
- package/lib/module/store/restoredIds.test.js.map +1 -0
- package/lib/module/store/suggestions.js +49 -1
- package/lib/module/store/suggestions.js.map +1 -0
- package/lib/module/store/suggestions.test.js +57 -1
- package/lib/module/store/suggestions.test.js.map +1 -0
- package/lib/module/store/systemLine.test.js +76 -1
- package/lib/module/store/systemLine.test.js.map +1 -0
- package/lib/module/store/ticketPrompt.js +13 -1
- package/lib/module/store/ticketPrompt.js.map +1 -0
- package/lib/module/store/traceText.js +75 -1
- package/lib/module/store/traceText.js.map +1 -0
- package/lib/module/store/traceText.test.js +111 -1
- package/lib/module/store/traceText.test.js.map +1 -0
- package/lib/module/store/transcriptPersistence.js +287 -1
- package/lib/module/store/transcriptPersistence.js.map +1 -0
- package/lib/module/store/transcriptPersistence.test.js +332 -1
- package/lib/module/store/transcriptPersistence.test.js.map +1 -0
- package/lib/module/store/turnRendering.test.js +150 -1
- package/lib/module/store/turnRendering.test.js.map +1 -0
- package/lib/module/store/useAskBuoy.js +646 -1
- package/lib/module/store/useAskBuoy.js.map +1 -0
- package/lib/module/store/useAskBuoySettings.js +9 -1
- package/lib/module/store/useAskBuoySettings.js.map +1 -0
- package/lib/module/sync/askBuoySyncAdapter.js +148 -1
- package/lib/module/sync/askBuoySyncAdapter.js.map +1 -0
- package/lib/module/sync/askBuoySyncAdapter.test.js +140 -1
- package/lib/module/sync/askBuoySyncAdapter.test.js.map +1 -0
- package/lib/module/sync/wire.js +47 -1
- package/lib/module/sync/wire.js.map +1 -0
- package/lib/module/types.js +4 -1
- package/lib/module/types.js.map +1 -0
- package/lib/typescript/blocks/AskBlocks.d.ts.map +1 -0
- package/lib/typescript/blocks/BlockRenderer.d.ts.map +1 -0
- package/lib/typescript/blocks/ChromePrototypes.d.ts.map +1 -0
- package/lib/typescript/blocks/DataBlocks.d.ts.map +1 -0
- package/lib/typescript/blocks/ExtraBlocks.d.ts.map +1 -0
- package/lib/typescript/blocks/MediaBlocks.d.ts.map +1 -0
- package/lib/typescript/blocks/ReceiptBlocks.d.ts.map +1 -0
- package/lib/typescript/blocks/blockText.d.ts.map +1 -0
- package/lib/typescript/blocks/blockText.test.d.ts.map +1 -0
- package/lib/typescript/blocks/context.d.ts.map +1 -0
- package/lib/typescript/blocks/icons.d.ts.map +1 -0
- package/lib/typescript/blocks/index.d.ts.map +1 -0
- package/lib/typescript/blocks/listRow.test.d.ts.map +1 -0
- package/lib/typescript/blocks/pageState.d.ts.map +1 -0
- package/lib/typescript/blocks/pageState.test.d.ts.map +1 -0
- package/lib/typescript/blocks/primitives.d.ts.map +1 -0
- package/lib/typescript/blocks/primitivesIndex.d.ts.map +1 -0
- package/lib/typescript/components/ApprovalCard.d.ts.map +1 -0
- package/lib/typescript/components/AskBuoyHeader.d.ts.map +1 -0
- package/lib/typescript/components/AskBuoyIcon.d.ts.map +1 -0
- package/lib/typescript/components/AskBuoyModal.d.ts.map +1 -0
- package/lib/typescript/components/AskBuoySettings.d.ts.map +1 -0
- package/lib/typescript/components/ChangesBar.d.ts.map +1 -0
- package/lib/typescript/components/Composer.d.ts.map +1 -0
- package/lib/typescript/components/EmptyState.d.ts.map +1 -0
- package/lib/typescript/components/KeyboardPad.d.ts.map +1 -0
- package/lib/typescript/components/Markdown.d.ts.map +1 -0
- package/lib/typescript/components/MessageList.d.ts.map +1 -0
- package/lib/typescript/components/QueuedMessages.d.ts.map +1 -0
- package/lib/typescript/components/ThinkingStrip.d.ts.map +1 -0
- package/lib/typescript/components/TypingDots.d.ts.map +1 -0
- package/lib/typescript/components/markdownParse.d.ts.map +1 -0
- package/lib/typescript/components/markdownParse.test.d.ts.map +1 -0
- package/lib/typescript/components/useCopyAction.d.ts.map +1 -0
- package/lib/typescript/index.d.ts.map +1 -0
- package/lib/typescript/preset.d.ts.map +1 -0
- package/lib/typescript/store/activityGroups.d.ts.map +1 -0
- package/lib/typescript/store/activityGroups.test.d.ts.map +1 -0
- package/lib/typescript/store/askBuoySettings.d.ts.map +1 -0
- package/lib/typescript/store/askBuoyStore.d.ts.map +1 -0
- package/lib/typescript/store/blockPlacement.d.ts.map +1 -0
- package/lib/typescript/store/blockPlacement.test.d.ts.map +1 -0
- package/lib/typescript/store/queue.test.d.ts.map +1 -0
- package/lib/typescript/store/resetConversation.d.ts.map +1 -0
- package/lib/typescript/store/restorePending.test.d.ts.map +1 -0
- package/lib/typescript/store/restoredIds.test.d.ts.map +1 -0
- package/lib/typescript/store/suggestions.d.ts.map +1 -0
- package/lib/typescript/store/suggestions.test.d.ts.map +1 -0
- package/lib/typescript/store/systemLine.test.d.ts.map +1 -0
- package/lib/typescript/store/ticketPrompt.d.ts.map +1 -0
- package/lib/typescript/store/traceText.d.ts.map +1 -0
- package/lib/typescript/store/traceText.test.d.ts.map +1 -0
- package/lib/typescript/store/transcriptPersistence.d.ts.map +1 -0
- package/lib/typescript/store/transcriptPersistence.test.d.ts.map +1 -0
- package/lib/typescript/store/turnRendering.test.d.ts.map +1 -0
- package/lib/typescript/store/useAskBuoy.d.ts.map +1 -0
- package/lib/typescript/store/useAskBuoySettings.d.ts.map +1 -0
- package/lib/typescript/sync/askBuoySyncAdapter.d.ts.map +1 -0
- package/lib/typescript/sync/askBuoySyncAdapter.test.d.ts.map +1 -0
- package/lib/typescript/sync/wire.d.ts.map +1 -0
- package/lib/typescript/types.d.ts.map +1 -0
- package/package.json +8 -8
|
@@ -1 +1,125 @@
|
|
|
1
|
-
"use strict";
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The Markdown parser, kept apart from the renderer so it can be unit-tested
|
|
5
|
+
* without React Native.
|
|
6
|
+
*
|
|
7
|
+
* Just enough for a chat answer: paragraphs, `-`/`*`/`1.` lists, `#` headings,
|
|
8
|
+
* pipe tables, and fenced code. Anything it does not understand falls through
|
|
9
|
+
* as plain text, never as a blank.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const isTableRow = l => /^\s*\|.*\|\s*$/.test(l);
|
|
13
|
+
const isTableRule = l => /^\s*\|?\s*:?-{2,}:?\s*(\|\s*:?-{2,}:?\s*)*\|?\s*$/.test(l);
|
|
14
|
+
const splitRow = l => l.trim().replace(/^\|/, "").replace(/\|$/, "").split("|").map(c => c.trim());
|
|
15
|
+
const FENCE = /^\s*```\s*([\w+-]*)\s*$/;
|
|
16
|
+
export function parseBlocks(source) {
|
|
17
|
+
const blocks = [];
|
|
18
|
+
let para = [];
|
|
19
|
+
const flush = () => {
|
|
20
|
+
if (para.length) blocks.push({
|
|
21
|
+
kind: "p",
|
|
22
|
+
text: para.join(" ")
|
|
23
|
+
});
|
|
24
|
+
para = [];
|
|
25
|
+
};
|
|
26
|
+
const lines = source.split("\n");
|
|
27
|
+
for (let li = 0; li < lines.length; li++) {
|
|
28
|
+
const raw = lines[li];
|
|
29
|
+
const line = raw.replace(/\s+$/, "");
|
|
30
|
+
|
|
31
|
+
// A fence opens a block that keeps its newlines and indentation — the
|
|
32
|
+
// one place in a chat answer where whitespace IS the content (JSON, a
|
|
33
|
+
// stack trace, a repro). Fences used to be unknown to this parser, so the
|
|
34
|
+
// lines were joined into a paragraph with the backticks shown literally.
|
|
35
|
+
const fence = FENCE.exec(line);
|
|
36
|
+
if (fence) {
|
|
37
|
+
flush();
|
|
38
|
+
const body = [];
|
|
39
|
+
let j = li + 1;
|
|
40
|
+
let closed = false;
|
|
41
|
+
while (j < lines.length) {
|
|
42
|
+
if (/^\s*```\s*$/.test(lines[j])) {
|
|
43
|
+
closed = true;
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
body.push(lines[j]);
|
|
47
|
+
j++;
|
|
48
|
+
}
|
|
49
|
+
blocks.push({
|
|
50
|
+
kind: "code",
|
|
51
|
+
lang: fence[1] ?? "",
|
|
52
|
+
text: body.join("\n"),
|
|
53
|
+
closed
|
|
54
|
+
});
|
|
55
|
+
li = closed ? j : lines.length;
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
if (!line.trim()) {
|
|
59
|
+
flush();
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
// A pipe table: header row, a rule row, then body rows.
|
|
63
|
+
if (isTableRow(line) && lines[li + 1] && isTableRule(lines[li + 1])) {
|
|
64
|
+
flush();
|
|
65
|
+
const header = splitRow(line);
|
|
66
|
+
const rows = [];
|
|
67
|
+
let j = li + 2;
|
|
68
|
+
while (j < lines.length && isTableRow(lines[j])) {
|
|
69
|
+
rows.push(splitRow(lines[j]));
|
|
70
|
+
j++;
|
|
71
|
+
}
|
|
72
|
+
blocks.push({
|
|
73
|
+
kind: "table",
|
|
74
|
+
header,
|
|
75
|
+
rows
|
|
76
|
+
});
|
|
77
|
+
li = j - 1;
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
const heading = /^#{1,6}\s+(.*)$/.exec(line);
|
|
81
|
+
if (heading) {
|
|
82
|
+
flush();
|
|
83
|
+
blocks.push({
|
|
84
|
+
kind: "h",
|
|
85
|
+
text: heading[1]
|
|
86
|
+
});
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
const bullet = /^(\s*)([-*•]|\d+[.)])\s+(.*)$/.exec(line);
|
|
90
|
+
if (bullet) {
|
|
91
|
+
flush();
|
|
92
|
+
const depth = Math.min(2, Math.floor(bullet[1].length / 2));
|
|
93
|
+
const marker = /^\d/.test(bullet[2]) ? bullet[2].replace(")", ".") : "•";
|
|
94
|
+
blocks.push({
|
|
95
|
+
kind: "li",
|
|
96
|
+
text: bullet[3],
|
|
97
|
+
marker,
|
|
98
|
+
depth
|
|
99
|
+
});
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
para.push(line.trim());
|
|
103
|
+
}
|
|
104
|
+
flush();
|
|
105
|
+
return blocks;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/** The preview a table is cut to. Past this it says so and offers the rest. */
|
|
109
|
+
export const TABLE_PREVIEW_ROWS = 12;
|
|
110
|
+
export const TABLE_PREVIEW_COLS = 4;
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* What a table preview leaves out, in the user's words — or null when nothing.
|
|
114
|
+
*
|
|
115
|
+
* The renderer used to slice to 4 columns and 12 rows and say nothing, so a
|
|
116
|
+
* 30-line bag read as a 12-line bag and the bug report that followed was
|
|
117
|
+
* "the bag only has 12 items". Evidence that is cut must say it is cut.
|
|
118
|
+
*/
|
|
119
|
+
export function tableTruncation(header, rows) {
|
|
120
|
+
const parts = [];
|
|
121
|
+
if (rows.length > TABLE_PREVIEW_ROWS) parts.push(`${TABLE_PREVIEW_ROWS} of ${rows.length} rows`);
|
|
122
|
+
if (header.length > TABLE_PREVIEW_COLS) parts.push(`${TABLE_PREVIEW_COLS} of ${header.length} columns`);
|
|
123
|
+
return parts.length ? `Showing ${parts.join(" · ")}` : null;
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=markdownParse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["isTableRow","l","test","isTableRule","splitRow","trim","replace","split","map","c","FENCE","parseBlocks","source","blocks","para","flush","length","push","kind","text","join","lines","li","raw","line","fence","exec","body","j","closed","lang","header","rows","heading","bullet","depth","Math","min","floor","marker","TABLE_PREVIEW_ROWS","TABLE_PREVIEW_COLS","tableTruncation","parts"],"sourceRoot":"../../../src","sources":["components/markdownParse.ts"],"mappings":"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","ignoreList":[]}
|
|
@@ -1 +1,98 @@
|
|
|
1
|
-
"use strict";
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The two things the old parser got wrong, written down so they stay fixed:
|
|
5
|
+
* fenced code flattened into a paragraph with the backticks shown, and a table
|
|
6
|
+
* cut to 12 × 4 with nothing to say it had been.
|
|
7
|
+
*/
|
|
8
|
+
import { describe, expect, it } from "vitest";
|
|
9
|
+
import { parseBlocks, tableTruncation } from "./markdownParse";
|
|
10
|
+
describe("fenced code", () => {
|
|
11
|
+
it("keeps newlines and indentation", () => {
|
|
12
|
+
const src = 'Here:\n```json\n{\n "qty": 14\n}\n```\n— the qty changed.';
|
|
13
|
+
const blocks = parseBlocks(src);
|
|
14
|
+
expect(blocks.map(b => b.kind)).toEqual(["p", "code", "p"]);
|
|
15
|
+
const code = blocks[1];
|
|
16
|
+
expect(code.kind === "code" && code.text).toBe('{\n "qty": 14\n}');
|
|
17
|
+
expect(code.kind === "code" && code.lang).toBe("json");
|
|
18
|
+
expect(code.kind === "code" && code.closed).toBe(true);
|
|
19
|
+
});
|
|
20
|
+
it("renders an unclosed fence as code while the stream is still inside it", () => {
|
|
21
|
+
const blocks = parseBlocks("```\nline one\nline two");
|
|
22
|
+
expect(blocks).toHaveLength(1);
|
|
23
|
+
const code = blocks[0];
|
|
24
|
+
expect(code.kind).toBe("code");
|
|
25
|
+
expect(code.kind === "code" && code.closed).toBe(false);
|
|
26
|
+
expect(code.kind === "code" && code.text).toBe("line one\nline two");
|
|
27
|
+
});
|
|
28
|
+
it("does not treat fence contents as lists or tables", () => {
|
|
29
|
+
const blocks = parseBlocks("```\n- not a bullet\n| a | b |\n|---|---|\n```");
|
|
30
|
+
expect(blocks).toHaveLength(1);
|
|
31
|
+
expect(blocks[0].kind).toBe("code");
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
describe("tables", () => {
|
|
35
|
+
const table = (rows, cols) => {
|
|
36
|
+
const header = Array.from({
|
|
37
|
+
length: cols
|
|
38
|
+
}, (_, i) => `c${i}`);
|
|
39
|
+
const body = Array.from({
|
|
40
|
+
length: rows
|
|
41
|
+
}, (_, r) => header.map((_, c) => `r${r}c${c}`));
|
|
42
|
+
return {
|
|
43
|
+
header,
|
|
44
|
+
rows: body
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
it("says nothing about a table that fits", () => {
|
|
48
|
+
const t = table(12, 4);
|
|
49
|
+
expect(tableTruncation(t.header, t.rows)).toBeNull();
|
|
50
|
+
});
|
|
51
|
+
it("names the rows it cut", () => {
|
|
52
|
+
const t = table(30, 4);
|
|
53
|
+
expect(tableTruncation(t.header, t.rows)).toBe("Showing 12 of 30 rows");
|
|
54
|
+
});
|
|
55
|
+
it("names the columns it cut", () => {
|
|
56
|
+
const t = table(3, 6);
|
|
57
|
+
expect(tableTruncation(t.header, t.rows)).toBe("Showing 4 of 6 columns");
|
|
58
|
+
});
|
|
59
|
+
it("names both when both are cut", () => {
|
|
60
|
+
const t = table(30, 6);
|
|
61
|
+
expect(tableTruncation(t.header, t.rows)).toBe("Showing 12 of 30 rows · 4 of 6 columns");
|
|
62
|
+
});
|
|
63
|
+
it("still parses a pipe table from text", () => {
|
|
64
|
+
const blocks = parseBlocks("| Item | Qty |\n|---|---|\n| Charizard | 14 |\n| Blastoise | 2 |");
|
|
65
|
+
expect(blocks).toHaveLength(1);
|
|
66
|
+
const t = blocks[0];
|
|
67
|
+
expect(t.kind === "table" && t.header).toEqual(["Item", "Qty"]);
|
|
68
|
+
expect(t.kind === "table" && t.rows).toEqual([["Charizard", "14"], ["Blastoise", "2"]]);
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
describe("everything else still works", () => {
|
|
72
|
+
it("paragraphs, headings and lists", () => {
|
|
73
|
+
const blocks = parseBlocks("# Title\n\nSome prose\ncontinues.\n\n- one\n - nested\n1. first");
|
|
74
|
+
expect(blocks).toEqual([{
|
|
75
|
+
kind: "h",
|
|
76
|
+
text: "Title"
|
|
77
|
+
}, {
|
|
78
|
+
kind: "p",
|
|
79
|
+
text: "Some prose continues."
|
|
80
|
+
}, {
|
|
81
|
+
kind: "li",
|
|
82
|
+
text: "one",
|
|
83
|
+
marker: "•",
|
|
84
|
+
depth: 0
|
|
85
|
+
}, {
|
|
86
|
+
kind: "li",
|
|
87
|
+
text: "nested",
|
|
88
|
+
marker: "•",
|
|
89
|
+
depth: 1
|
|
90
|
+
}, {
|
|
91
|
+
kind: "li",
|
|
92
|
+
text: "first",
|
|
93
|
+
marker: "1.",
|
|
94
|
+
depth: 0
|
|
95
|
+
}]);
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
//# sourceMappingURL=markdownParse.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["describe","expect","it","parseBlocks","tableTruncation","src","blocks","map","b","kind","toEqual","code","text","toBe","lang","closed","toHaveLength","table","rows","cols","header","Array","from","length","_","i","body","r","c","t","toBeNull","marker","depth"],"sourceRoot":"../../../src","sources":["components/markdownParse.test.ts"],"mappings":"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","ignoreList":[]}
|
|
@@ -1 +1,46 @@
|
|
|
1
|
-
"use strict";
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Copy that reports what happened.
|
|
5
|
+
*
|
|
6
|
+
* Both clipboard libraries are OPTIONAL peers, so `copyToClipboard` resolves
|
|
7
|
+
* false in an app that installed neither — a copy button that silently does
|
|
8
|
+
* nothing is worse than no copy button, so that case falls through to the OS
|
|
9
|
+
* share sheet (which also offers Copy) instead of failing quietly.
|
|
10
|
+
*
|
|
11
|
+
* `getText` is read on PRESS, not on render: the whole-transcript callers
|
|
12
|
+
* would otherwise rebuild the transcript on every frame of a streaming answer
|
|
13
|
+
* just to have a string ready for a button nobody tapped.
|
|
14
|
+
*/
|
|
15
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
16
|
+
import { Share } from "react-native";
|
|
17
|
+
import { copyToClipboard } from "@buoy-gg/shared-ui";
|
|
18
|
+
|
|
19
|
+
/** Long enough to notice out of the corner of an eye, short enough not to linger. */
|
|
20
|
+
const COPIED_MS = 1500;
|
|
21
|
+
export function useCopyAction(getText) {
|
|
22
|
+
const [copied, setCopied] = useState(false);
|
|
23
|
+
const timer = useRef(null);
|
|
24
|
+
useEffect(() => () => {
|
|
25
|
+
if (timer.current) clearTimeout(timer.current);
|
|
26
|
+
}, []);
|
|
27
|
+
const copy = useCallback(() => {
|
|
28
|
+
const text = getText();
|
|
29
|
+
void copyToClipboard(text).then(ok => {
|
|
30
|
+
if (!ok) {
|
|
31
|
+
void Share.share({
|
|
32
|
+
message: text
|
|
33
|
+
}).catch(() => {});
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
setCopied(true);
|
|
37
|
+
if (timer.current) clearTimeout(timer.current);
|
|
38
|
+
timer.current = setTimeout(() => setCopied(false), COPIED_MS);
|
|
39
|
+
}).catch(() => {});
|
|
40
|
+
}, [getText]);
|
|
41
|
+
return {
|
|
42
|
+
copied,
|
|
43
|
+
copy
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=useCopyAction.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["useCallback","useEffect","useRef","useState","Share","copyToClipboard","COPIED_MS","useCopyAction","getText","copied","setCopied","timer","current","clearTimeout","copy","text","then","ok","share","message","catch","setTimeout"],"sourceRoot":"../../../src","sources":["components/useCopyAction.ts"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAASA,WAAW,EAAEC,SAAS,EAAEC,MAAM,EAAEC,QAAQ,QAAQ,OAAO;AAChE,SAASC,KAAK,QAAQ,cAAc;AACpC,SAASC,eAAe,QAAQ,oBAAoB;;AAEpD;AACA,MAAMC,SAAS,GAAG,IAAI;AAEtB,OAAO,SAASC,aAAaA,CAACC,OAAqB,EAAyC;EAC1F,MAAM,CAACC,MAAM,EAAEC,SAAS,CAAC,GAAGP,QAAQ,CAAC,KAAK,CAAC;EAC3C,MAAMQ,KAAK,GAAGT,MAAM,CAAuC,IAAI,CAAC;EAChED,SAAS,CACP,MAAM,MAAM;IACV,IAAIU,KAAK,CAACC,OAAO,EAAEC,YAAY,CAACF,KAAK,CAACC,OAAO,CAAC;EAChD,CAAC,EACD,EACF,CAAC;EAED,MAAME,IAAI,GAAGd,WAAW,CAAC,MAAM;IAC7B,MAAMe,IAAI,GAAGP,OAAO,CAAC,CAAC;IACtB,KAAKH,eAAe,CAACU,IAAI,CAAC,CACvBC,IAAI,CAAEC,EAAE,IAAK;MACZ,IAAI,CAACA,EAAE,EAAE;QACP,KAAKb,KAAK,CAACc,KAAK,CAAC;UAAEC,OAAO,EAAEJ;QAAK,CAAC,CAAC,CAACK,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;QACnD;MACF;MACAV,SAAS,CAAC,IAAI,CAAC;MACf,IAAIC,KAAK,CAACC,OAAO,EAAEC,YAAY,CAACF,KAAK,CAACC,OAAO,CAAC;MAC9CD,KAAK,CAACC,OAAO,GAAGS,UAAU,CAAC,MAAMX,SAAS,CAAC,KAAK,CAAC,EAAEJ,SAAS,CAAC;IAC/D,CAAC,CAAC,CACDc,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;EACpB,CAAC,EAAE,CAACZ,OAAO,CAAC,CAAC;EAEb,OAAO;IAAEC,MAAM;IAAEK;EAAK,CAAC;AACzB","ignoreList":[]}
|
package/lib/module/index.js
CHANGED
|
@@ -1 +1,34 @@
|
|
|
1
|
-
"use strict";
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @buoy-gg/ask-buoy — "Ask Buoy".
|
|
5
|
+
*
|
|
6
|
+
* A chat sheet that drives every other Buoy tool on behalf of someone who does
|
|
7
|
+
* not read code. The model runs on the company's own endpoint (see
|
|
8
|
+
* `AskBuoyConfig`), the tool calls go through the same `dispatchToolAction`
|
|
9
|
+
* seam a Scenario step uses, and anything it changes is listed in a bar with an
|
|
10
|
+
* Undo.
|
|
11
|
+
*/
|
|
12
|
+
export { AskBuoyModal } from "./components/AskBuoyModal";
|
|
13
|
+
export { askBuoyToolPreset, createAskBuoyTool, AskBuoyIcon, ASK_BUOY_ICON_COLOR } from "./preset";
|
|
14
|
+
export { askBuoySyncAdapter, ASK_BUOY_ADAPTER_VERSION } from "./sync/askBuoySyncAdapter";
|
|
15
|
+
export { askBuoyStore } from "./store/askBuoyStore";
|
|
16
|
+
export { useAskBuoy, useAskBuoyState } from "./store/useAskBuoy";
|
|
17
|
+
export { redactForWire } from "./sync/wire";
|
|
18
|
+
export { BlockRenderer, BlockHandlersProvider, useBlockHandlers } from "./blocks";
|
|
19
|
+
export { Card as BlockCard, ActionRow as BlockActionRow, ProvenanceBadge } from "./blocks";
|
|
20
|
+
export { MessageActions, ReasoningStrip, ElapsedRow, QueuedComposer, ReloadDivider, Timestamp, EditableUserBubble, LivePill } from "./blocks";
|
|
21
|
+
export { Markdown } from "./components/Markdown";
|
|
22
|
+
// The real transcript pieces, exported so the example app's "chat scenes" page
|
|
23
|
+
// can stage conversations in the actual sheet chrome.
|
|
24
|
+
export { MessageList } from "./components/MessageList";
|
|
25
|
+
export { AskBuoyHeader } from "./components/AskBuoyHeader";
|
|
26
|
+
export { AskBuoySettings } from "./components/AskBuoySettings";
|
|
27
|
+
export { ThinkingStrip } from "./components/ThinkingStrip";
|
|
28
|
+
export { askBuoySettings } from "./store/askBuoySettings";
|
|
29
|
+
export { useAskBuoySettings } from "./store/useAskBuoySettings";
|
|
30
|
+
export { traceEntries, traceToText, hasTrace } from "./store/traceText";
|
|
31
|
+
export { Composer } from "./components/Composer";
|
|
32
|
+
export { ChangesBar } from "./components/ChangesBar";
|
|
33
|
+
export { ApprovalCard } from "./components/ApprovalCard";
|
|
34
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["AskBuoyModal","askBuoyToolPreset","createAskBuoyTool","AskBuoyIcon","ASK_BUOY_ICON_COLOR","askBuoySyncAdapter","ASK_BUOY_ADAPTER_VERSION","askBuoyStore","useAskBuoy","useAskBuoyState","redactForWire","BlockRenderer","BlockHandlersProvider","useBlockHandlers","Card","BlockCard","ActionRow","BlockActionRow","ProvenanceBadge","MessageActions","ReasoningStrip","ElapsedRow","QueuedComposer","ReloadDivider","Timestamp","EditableUserBubble","LivePill","Markdown","MessageList","AskBuoyHeader","AskBuoySettings","ThinkingStrip","askBuoySettings","useAskBuoySettings","traceEntries","traceToText","hasTrace","Composer","ChangesBar","ApprovalCard"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAASA,YAAY,QAAgC,2BAA2B;AAChF,SACEC,iBAAiB,EACjBC,iBAAiB,EACjBC,WAAW,EACXC,mBAAmB,QAEd,UAAU;AACjB,SAASC,kBAAkB,EAAEC,wBAAwB,QAAQ,2BAA2B;AACxF,SAASC,YAAY,QAAQ,sBAAsB;AACnD,SAASC,UAAU,EAAEC,eAAe,QAAgC,oBAAoB;AAGxF,SAASC,aAAa,QAAQ,aAAa;AAE3C,SAASC,aAAa,EAAEC,qBAAqB,EAAEC,gBAAgB,QAA4B,UAAU;AACrG,SAASC,IAAI,IAAIC,SAAS,EAAEC,SAAS,IAAIC,cAAc,EAAEC,eAAe,QAAQ,UAAU;AAC1F,SACEC,cAAc,EAAEC,cAAc,EAAEC,UAAU,EAAEC,cAAc,EAAEC,aAAa,EAAEC,SAAS,EAAEC,kBAAkB,EAAEC,QAAQ,QAC7G,UAAU;AACjB,SAASC,QAAQ,QAAQ,uBAAuB;AAChD;AACA;AACA,SAASC,WAAW,QAAQ,0BAA0B;AACtD,SAASC,aAAa,QAAQ,4BAA4B;AAC1D,SAASC,eAAe,QAAQ,8BAA8B;AAC9D,SAASC,aAAa,QAAQ,4BAA4B;AAC1D,SAASC,eAAe,QAAsD,yBAAyB;AACvG,SAASC,kBAAkB,QAAQ,4BAA4B;AAC/D,SAASC,YAAY,EAAEC,WAAW,EAAEC,QAAQ,QAAyB,mBAAmB;AACxF,SAASC,QAAQ,QAAQ,uBAAuB;AAChD,SAASC,UAAU,QAAQ,yBAAyB;AACpD,SAASC,YAAY,QAAQ,2BAA2B","ignoreList":[]}
|
package/lib/module/preset.js
CHANGED
|
@@ -1 +1,74 @@
|
|
|
1
|
-
"use strict";
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The Ask Buoy tool preset.
|
|
5
|
+
*
|
|
6
|
+
* Manual chrome (`component` renders its own JsModal) rather than the
|
|
7
|
+
* declarative `modal` config, because ToolModalShell forwards neither a footer
|
|
8
|
+
* slot nor `initialHeight` — and a chat needs a sticky composer and more than
|
|
9
|
+
* the default 400pt of sheet.
|
|
10
|
+
*
|
|
11
|
+
* The config is closed over at creation time rather than read from a store, so
|
|
12
|
+
* the endpoint and headers come from the app's own code on every render and
|
|
13
|
+
* there is never a copy of them sitting anywhere Buoy persists.
|
|
14
|
+
*/
|
|
15
|
+
import { AskBuoyIcon, ASK_BUOY_ICON_COLOR } from "./components/AskBuoyIcon";
|
|
16
|
+
import { AskBuoyModal } from "./components/AskBuoyModal";
|
|
17
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
18
|
+
export { AskBuoyIcon, ASK_BUOY_ICON_COLOR };
|
|
19
|
+
export const askBuoyToolPreset = {
|
|
20
|
+
id: "ask-buoy",
|
|
21
|
+
name: "ASK BUOY",
|
|
22
|
+
description: "Ask about this app in plain English",
|
|
23
|
+
slot: "both",
|
|
24
|
+
// Set here rather than in floating-tools-core's `toolColors` map: that map
|
|
25
|
+
// is already missing half the shipped tools, so the web twin falls back to a
|
|
26
|
+
// generic accent for them. A color on the preset is the one place both
|
|
27
|
+
// native and web read.
|
|
28
|
+
color: ASK_BUOY_ICON_COLOR,
|
|
29
|
+
// The approved composition uses a 48pt optical size in the 32pt dial slot.
|
|
30
|
+
// Compact row/header uses keep their requested size.
|
|
31
|
+
icon: ({
|
|
32
|
+
size,
|
|
33
|
+
slot
|
|
34
|
+
}) => /*#__PURE__*/_jsx(AskBuoyIcon, {
|
|
35
|
+
size: slot === 'dial' ? size * 1.5 : size
|
|
36
|
+
}),
|
|
37
|
+
component: AskBuoyModal
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* `endpoint` and `model` are REQUIRED at the type level. This used to extend
|
|
42
|
+
* Partial<AskBuoyConfig> with a cast, so a missing endpoint type-checked and
|
|
43
|
+
* only surfaced as a runtime "not set up yet" — the wrong moment to learn it.
|
|
44
|
+
*/
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Wire Ask Buoy to your team's AI endpoint.
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* createAskBuoyTool({
|
|
51
|
+
* endpoint: "https://ai.acme.com/v1/messages",
|
|
52
|
+
* model: "claude-opus-5",
|
|
53
|
+
* headers: async () => ({ Authorization: `Bearer ${await auth.getToken()}` }),
|
|
54
|
+
* context: { notes: ["user.rewards.points = loyalty points"] },
|
|
55
|
+
* })
|
|
56
|
+
*/
|
|
57
|
+
export function createAskBuoyTool(config) {
|
|
58
|
+
const {
|
|
59
|
+
name,
|
|
60
|
+
description,
|
|
61
|
+
...rest
|
|
62
|
+
} = config;
|
|
63
|
+
const resolved = rest;
|
|
64
|
+
return {
|
|
65
|
+
...askBuoyToolPreset,
|
|
66
|
+
name: name ?? askBuoyToolPreset.name,
|
|
67
|
+
description: description ?? askBuoyToolPreset.description,
|
|
68
|
+
component: props => /*#__PURE__*/_jsx(AskBuoyModal, {
|
|
69
|
+
...props,
|
|
70
|
+
config: resolved
|
|
71
|
+
})
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=preset.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["AskBuoyIcon","ASK_BUOY_ICON_COLOR","AskBuoyModal","jsx","_jsx","askBuoyToolPreset","id","name","description","slot","color","icon","size","component","createAskBuoyTool","config","rest","resolved","props"],"sourceRoot":"../../src","sources":["preset.tsx"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAASA,WAAW,EAAEC,mBAAmB,QAAQ,0BAA0B;AAC3E,SAASC,YAAY,QAAgC,2BAA2B;AAAC,SAAAC,GAAA,IAAAC,IAAA;AAGjF,SAASJ,WAAW,EAAEC,mBAAmB;AAEzC,OAAO,MAAMI,iBAAiB,GAAG;EAC/BC,EAAE,EAAE,UAAU;EACdC,IAAI,EAAE,UAAU;EAChBC,WAAW,EAAE,qCAAqC;EAClDC,IAAI,EAAE,MAAe;EACrB;EACA;EACA;EACA;EACAC,KAAK,EAAET,mBAAmB;EAC1B;EACA;EACAU,IAAI,EAAEA,CAAC;IAAEC,IAAI;IAAEH;EAAsD,CAAC,kBACpEL,IAAA,CAACJ,WAAW;IAACY,IAAI,EAAEH,IAAI,KAAK,MAAM,GAAGG,IAAI,GAAG,GAAG,GAAGA;EAAK,CAAE,CAC1D;EACDC,SAAS,EAAEX;AACb,CAAC;;AAED;AACA;AACA;AACA;AACA;;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASY,iBAAiBA,CAACC,MAAyB,EAAE;EAC3D,MAAM;IAAER,IAAI;IAAEC,WAAW;IAAE,GAAGQ;EAAK,CAAC,GAAGD,MAAM;EAC7C,MAAME,QAAuB,GAAGD,IAAI;EACpC,OAAO;IACL,GAAGX,iBAAiB;IACpBE,IAAI,EAAEA,IAAI,IAAIF,iBAAiB,CAACE,IAAI;IACpCC,WAAW,EAAEA,WAAW,IAAIH,iBAAiB,CAACG,WAAW;IACzDK,SAAS,EAAGK,KAAwB,iBAClCd,IAAA,CAACF,YAAY;MAAA,GAAKgB,KAAK;MAAEH,MAAM,EAAEE;IAAS,CAAE;EAEhD,CAAC;AACH","ignoreList":[]}
|
|
@@ -1 +1,103 @@
|
|
|
1
|
-
"use strict";
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* How tool rows fold in the activity card.
|
|
5
|
+
*
|
|
6
|
+
* Consecutive SUCCESSFUL READS fold into one row — "Looked at Network, Storage
|
|
7
|
+
* · 3 reads" — and nothing else ever folds. The previous rule folded by count:
|
|
8
|
+
* past four steps the card became "Did 7 things · 1 failed" with every row but
|
|
9
|
+
* the failures hidden, including the one successful write, which is the row
|
|
10
|
+
* the user most needs to see. Codex's exec cell does the same thing for file
|
|
11
|
+
* reads ("Explored — Read a, b, c") and keeps every run visible.
|
|
12
|
+
*
|
|
13
|
+
* A group never crosses a write: a read after a mutation is a different
|
|
14
|
+
* observation from a read before it, and merging them would misreport order.
|
|
15
|
+
* Uses the engine's `effect` classification, never the action's name.
|
|
16
|
+
*/
|
|
17
|
+
import { toolTitle } from "@buoy-gg/agent-core";
|
|
18
|
+
const foldable = c => c.effect === "read" && c.status === "ok";
|
|
19
|
+
export function groupCalls(calls) {
|
|
20
|
+
const out = [];
|
|
21
|
+
let run = [];
|
|
22
|
+
const flush = () => {
|
|
23
|
+
if (run.length === 0) return;
|
|
24
|
+
if (run.length === 1) {
|
|
25
|
+
out.push({
|
|
26
|
+
kind: "call",
|
|
27
|
+
call: run[0]
|
|
28
|
+
});
|
|
29
|
+
} else {
|
|
30
|
+
const titles = [...new Set(run.map(c => toolTitle(c.toolId)))];
|
|
31
|
+
out.push({
|
|
32
|
+
kind: "reads",
|
|
33
|
+
id: run.map(c => c.id).join("+"),
|
|
34
|
+
calls: run,
|
|
35
|
+
label: `Looked at ${joinNatural(titles)}`,
|
|
36
|
+
count: run.length
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
run = [];
|
|
40
|
+
};
|
|
41
|
+
for (const call of calls) {
|
|
42
|
+
if (foldable(call)) {
|
|
43
|
+
run.push(call);
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
flush();
|
|
47
|
+
out.push({
|
|
48
|
+
kind: "call",
|
|
49
|
+
call
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
flush();
|
|
53
|
+
return out;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** "Network", "Network and Storage", "Network, Storage and Screen". */
|
|
57
|
+
function joinNatural(items) {
|
|
58
|
+
if (items.length <= 1) return items[0] ?? "";
|
|
59
|
+
if (items.length === 2) return `${items[0]} and ${items[1]}`;
|
|
60
|
+
return `${items.slice(0, -1).join(", ")} and ${items[items.length - 1]}`;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* "48s · 6 actions · 1 declined" — the line under a finished answer.
|
|
65
|
+
*
|
|
66
|
+
* "Actions" is tool calls, not provider rounds: rounds are an implementation
|
|
67
|
+
* detail nobody outside the engine can count. Failed, refused, declined and
|
|
68
|
+
* stopped are listed separately because they are different outcomes — a
|
|
69
|
+
* failed exploratory read the agent recovered from is not a failed task. No
|
|
70
|
+
* duration is invented when the message has no start time (a restored note).
|
|
71
|
+
*/
|
|
72
|
+
export function turnFooter(message) {
|
|
73
|
+
const parts = [];
|
|
74
|
+
if (message.startedAt !== undefined && message.endedAt !== undefined && message.endedAt >= message.startedAt) {
|
|
75
|
+
parts.push(formatElapsed(message.endedAt - message.startedAt));
|
|
76
|
+
}
|
|
77
|
+
const n = message.toolCalls.length;
|
|
78
|
+
if (n > 0) {
|
|
79
|
+
parts.push(`${n} action${n === 1 ? "" : "s"}`);
|
|
80
|
+
const count = s => message.toolCalls.filter(c => c.status === s).length;
|
|
81
|
+
const failed = count("failed");
|
|
82
|
+
const refused = count("refused");
|
|
83
|
+
const declined = count("declined");
|
|
84
|
+
const stopped = count("stopped");
|
|
85
|
+
if (failed) parts.push(`${failed} failed`);
|
|
86
|
+
if (refused) parts.push(`${refused} refused`);
|
|
87
|
+
if (declined) parts.push(`${declined} declined`);
|
|
88
|
+
if (stopped) parts.push(`${stopped} not run`);
|
|
89
|
+
}
|
|
90
|
+
return parts.length ? parts.join(" · ") : null;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** "4s", "1m 04s", "1h 02m". Compact, for a subtitle or a footer. */
|
|
94
|
+
export function formatElapsed(ms) {
|
|
95
|
+
const total = Math.max(0, Math.floor(ms / 1000));
|
|
96
|
+
if (total < 60) return `${total}s`;
|
|
97
|
+
const m = Math.floor(total / 60);
|
|
98
|
+
const s = total % 60;
|
|
99
|
+
if (m < 60) return `${m}m ${String(s).padStart(2, "0")}s`;
|
|
100
|
+
const h = Math.floor(m / 60);
|
|
101
|
+
return `${h}h ${String(m % 60).padStart(2, "0")}m`;
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=activityGroups.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["toolTitle","foldable","c","effect","status","groupCalls","calls","out","run","flush","length","push","kind","call","titles","Set","map","toolId","id","join","label","joinNatural","count","items","slice","turnFooter","message","parts","startedAt","undefined","endedAt","formatElapsed","n","toolCalls","s","filter","failed","refused","declined","stopped","ms","total","Math","max","floor","m","String","padStart","h"],"sourceRoot":"../../../src","sources":["store/activityGroups.ts"],"mappings":"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","ignoreList":[]}
|
|
@@ -1 +1,77 @@
|
|
|
1
|
-
"use strict";
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The fold rule: consecutive successful reads fold, nothing else ever does,
|
|
5
|
+
* and a group never crosses a write.
|
|
6
|
+
*/
|
|
7
|
+
import { describe, expect, it } from "vitest";
|
|
8
|
+
import { formatElapsed, groupCalls, turnFooter } from "./activityGroups";
|
|
9
|
+
const call = (id, toolId, effect, status = "ok") => ({
|
|
10
|
+
id,
|
|
11
|
+
toolId,
|
|
12
|
+
action: "x",
|
|
13
|
+
label: `${toolId} ${id}`,
|
|
14
|
+
status,
|
|
15
|
+
effect
|
|
16
|
+
});
|
|
17
|
+
describe("groupCalls", () => {
|
|
18
|
+
it("leaves a single read as an ordinary row", () => {
|
|
19
|
+
const items = groupCalls([call("a", "console", "read")]);
|
|
20
|
+
expect(items).toEqual([{
|
|
21
|
+
kind: "call",
|
|
22
|
+
call: expect.objectContaining({
|
|
23
|
+
id: "a"
|
|
24
|
+
})
|
|
25
|
+
}]);
|
|
26
|
+
});
|
|
27
|
+
it("folds consecutive successful reads and names the tools once each", () => {
|
|
28
|
+
const items = groupCalls([call("a", "network", "read"), call("b", "storage", "read"), call("c", "storage", "read")]);
|
|
29
|
+
expect(items).toHaveLength(1);
|
|
30
|
+
const g = items[0];
|
|
31
|
+
expect(g.kind).toBe("reads");
|
|
32
|
+
expect(g.kind === "reads" && g.count).toBe(3);
|
|
33
|
+
expect(g.kind === "reads" && g.label).toBe("Looked at Network and Storage");
|
|
34
|
+
});
|
|
35
|
+
it("never folds a write, and never folds reads across one", () => {
|
|
36
|
+
const items = groupCalls([call("a", "network", "read"), call("b", "storage", "read"), call("w", "zustand", "write"), call("c", "storage", "read"), call("d", "console", "read")]);
|
|
37
|
+
expect(items.map(i => i.kind === "reads" ? `reads:${i.count}` : `call:${i.call.id}`)).toEqual(["reads:2", "call:w", "reads:2"]);
|
|
38
|
+
});
|
|
39
|
+
it("keeps failed, refused, declined, stopped and running reads as their own rows", () => {
|
|
40
|
+
const items = groupCalls([call("a", "network", "read"), call("f", "storage", "read", "failed"), call("b", "storage", "read"), call("r", "storage", "read", "running")]);
|
|
41
|
+
expect(items.map(i => i.kind)).toEqual(["call", "call", "call", "call"]);
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
describe("turnFooter", () => {
|
|
45
|
+
it("reports duration and action count", () => {
|
|
46
|
+
expect(turnFooter({
|
|
47
|
+
startedAt: 1_000,
|
|
48
|
+
endedAt: 13_000,
|
|
49
|
+
toolCalls: [call("a", "network", "read"), call("b", "zustand", "write")]
|
|
50
|
+
})).toBe("12s · 2 actions");
|
|
51
|
+
});
|
|
52
|
+
it("separates the outcomes that were not plain successes", () => {
|
|
53
|
+
expect(turnFooter({
|
|
54
|
+
startedAt: 0,
|
|
55
|
+
endedAt: 48_000,
|
|
56
|
+
toolCalls: [call("a", "network", "read"), call("b", "storage", "write", "failed"), call("c", "storage", "destructive", "declined"), call("d", "storage", "write", "stopped")]
|
|
57
|
+
})).toBe("48s · 4 actions · 1 failed · 1 declined · 1 not run");
|
|
58
|
+
});
|
|
59
|
+
it("invents no duration for a note with no start time", () => {
|
|
60
|
+
expect(turnFooter({
|
|
61
|
+
endedAt: 5_000,
|
|
62
|
+
toolCalls: []
|
|
63
|
+
})).toBeNull();
|
|
64
|
+
expect(turnFooter({
|
|
65
|
+
endedAt: 5_000,
|
|
66
|
+
toolCalls: [call("a", "network", "read")]
|
|
67
|
+
})).toBe("1 action");
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
describe("formatElapsed", () => {
|
|
71
|
+
it("is compact", () => {
|
|
72
|
+
expect(formatElapsed(4_200)).toBe("4s");
|
|
73
|
+
expect(formatElapsed(64_000)).toBe("1m 04s");
|
|
74
|
+
expect(formatElapsed(3_720_000)).toBe("1h 02m");
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
//# sourceMappingURL=activityGroups.test.js.map
|