@burdenoff/microfe-vibecontrols 2026.830.1 → 2026.905.2
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/components/assistant/AIAssistantPanel.js +34 -67
- package/dist/components/assistant/AIAssistantPanel.js.map +1 -1
- package/dist/components/assistant/AssistantChatArea.js +11 -281
- package/dist/components/assistant/AssistantChatInput.js +4 -44
- package/dist/components/assistant/AssistantConversationList.js +6 -155
- package/dist/components/assistant/AssistantExportMenu.js +5 -52
- package/dist/components/assistant/AssistantMessageItem.js +9 -99
- package/dist/components/assistant/AssistantMessageList.js +4 -28
- package/dist/components/assistant/AssistantModeSelector.js +5 -60
- package/dist/components/assistant/AssistantWelcome.js +4 -42
- package/dist/components/assistant/index.js +1 -1
- package/dist/hooks/useAiCreditsQuota.js +8 -8
- package/dist/hooks/useWorkspaceWriteAccess.js +14 -0
- package/dist/hooks/useWorkspaceWriteAccess.js.map +1 -0
- package/dist/index.js +3 -3
- package/dist/pages/SessionsPage.js +6 -6
- package/dist/plugin.js +82 -64
- package/dist/plugin.js.map +1 -1
- package/dist/services/assistantApi.js +17 -48
- package/dist/services/assistantApi.js.map +1 -1
- package/dist/utils/assistantPrompt.js +34 -0
- package/dist/utils/assistantPrompt.js.map +1 -0
- package/dist/utils/pageContext.js +34 -15
- package/dist/utils/pageContext.js.map +1 -1
- package/package.json +2 -2
- package/dist/components/assistant/AssistantChatArea.js.map +0 -1
- package/dist/components/assistant/AssistantChatInput.js.map +0 -1
- package/dist/components/assistant/AssistantConversationList.js.map +0 -1
- package/dist/components/assistant/AssistantExportMenu.js.map +0 -1
- package/dist/components/assistant/AssistantMessageItem.js.map +0 -1
- package/dist/components/assistant/AssistantMessageList.js.map +0 -1
- package/dist/components/assistant/AssistantModeSelector.js.map +0 -1
- package/dist/components/assistant/AssistantWelcome.js.map +0 -1
- package/dist/hooks/useAssistantHeartbeat.js +0 -40
- package/dist/hooks/useAssistantHeartbeat.js.map +0 -1
- package/dist/hooks/useAssistantKeyboardShortcuts.js +0 -37
- package/dist/hooks/useAssistantKeyboardShortcuts.js.map +0 -1
- package/dist/services/assistantExportService.js +0 -44
- package/dist/services/assistantExportService.js.map +0 -1
|
@@ -1,73 +1,40 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { AiCreditsMeter as
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import { jsx as f, jsxs as p } from "react/jsx-runtime";
|
|
1
|
+
import { ASSISTANT_MODES as e } from "../../types/assistant.js";
|
|
2
|
+
import { PRODUCT as t, reportAssistantTokenUsage as n } from "../../services/assistantApi.js";
|
|
3
|
+
import { useWorkspaceWriteAccess as r } from "../../hooks/useWorkspaceWriteAccess.js";
|
|
4
|
+
import { describeCurrentPage as i, gatherPageContext as a } from "../../utils/pageContext.js";
|
|
5
|
+
import { buildPromptForMode as o } from "../../utils/assistantPrompt.js";
|
|
6
|
+
import { AiCreditsMeter as s } from "./AiCreditsMeter.js";
|
|
7
|
+
import { jsx as c, jsxs as l } from "react/jsx-runtime";
|
|
8
|
+
import { AIAssistantPanel as u } from "@burdenoff/fe-libs/shared/assistant/ui/AIAssistantPanel";
|
|
9
|
+
import { AssistantProductProvider as d } from "@burdenoff/fe-libs/shared/assistant/product";
|
|
10
|
+
import { getActorId as f, getWorkspaceId as p } from "@burdenoff/fe-libs/shared/assistant/context";
|
|
12
11
|
//#region src/components/assistant/AIAssistantPanel.tsx
|
|
13
|
-
var m =
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
/* @__PURE__ */
|
|
29
|
-
className: "flex
|
|
30
|
-
children:
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
"aria-label": g("vibecontrols.assistant.panel.toggleList", "Toggle conversation list"),
|
|
37
|
-
"data-testid": "toggle-conversation-list",
|
|
38
|
-
children: /* @__PURE__ */ f(u, { className: "size-3.5 text-text-secondary" })
|
|
39
|
-
}), /* @__PURE__ */ f("span", {
|
|
40
|
-
className: "text-xs font-semibold text-text-primary truncate",
|
|
41
|
-
children: C?.title ?? g("vibecontrols.assistant.panel.title", "AI Assistant")
|
|
42
|
-
})]
|
|
43
|
-
}), /* @__PURE__ */ p("div", {
|
|
44
|
-
className: "flex items-center gap-0.5 flex-shrink-0",
|
|
45
|
-
children: [
|
|
46
|
-
w && /* @__PURE__ */ f("button", {
|
|
47
|
-
type: "button",
|
|
48
|
-
onClick: () => y && S(y),
|
|
49
|
-
className: "p-1 hover:bg-bg-sunken rounded transition-colors",
|
|
50
|
-
"aria-label": g("vibecontrols.assistant.panel.clearConversation", "Clear conversation"),
|
|
51
|
-
children: /* @__PURE__ */ f(l, { className: "size-3.5 text-text-secondary" })
|
|
52
|
-
}),
|
|
53
|
-
/* @__PURE__ */ f(s, {}),
|
|
54
|
-
/* @__PURE__ */ f("button", {
|
|
55
|
-
type: "button",
|
|
56
|
-
onClick: m,
|
|
57
|
-
className: "p-1 hover:bg-bg-sunken rounded transition-colors md:hidden",
|
|
58
|
-
"aria-label": g("vibecontrols.assistant.panel.close", "Close assistant"),
|
|
59
|
-
children: /* @__PURE__ */ f(d, { className: "size-3.5 text-text-secondary" })
|
|
60
|
-
})
|
|
61
|
-
]
|
|
62
|
-
})]
|
|
63
|
-
}),
|
|
64
|
-
/* @__PURE__ */ f(a, {}),
|
|
65
|
-
b && /* @__PURE__ */ f(o, {}),
|
|
66
|
-
/* @__PURE__ */ f(i, {})
|
|
67
|
-
]
|
|
12
|
+
var m = {
|
|
13
|
+
attachments: "/VibeControls/AI Assistant/Attachments",
|
|
14
|
+
artifacts: "/VibeControls/AI Assistant/Artifacts"
|
|
15
|
+
}, h = (h) => {
|
|
16
|
+
let g = r(f(), p() || null);
|
|
17
|
+
return /* @__PURE__ */ c(d, {
|
|
18
|
+
product: t,
|
|
19
|
+
modes: e,
|
|
20
|
+
describeCurrentPage: i,
|
|
21
|
+
gatherPageContext: a,
|
|
22
|
+
buildPrompt: o,
|
|
23
|
+
reportTokenUsage: n,
|
|
24
|
+
storageFolders: m,
|
|
25
|
+
children: /* @__PURE__ */ l("div", {
|
|
26
|
+
className: "flex flex-col h-full w-full min-h-0",
|
|
27
|
+
children: [/* @__PURE__ */ c(s, {}), /* @__PURE__ */ c("div", {
|
|
28
|
+
className: "flex-1 min-h-0",
|
|
29
|
+
children: /* @__PURE__ */ c(u, {
|
|
30
|
+
...h,
|
|
31
|
+
writeAccess: g
|
|
32
|
+
})
|
|
33
|
+
})]
|
|
34
|
+
})
|
|
68
35
|
});
|
|
69
36
|
};
|
|
70
37
|
//#endregion
|
|
71
|
-
export {
|
|
38
|
+
export { h as AIAssistantPanel };
|
|
72
39
|
|
|
73
40
|
//# sourceMappingURL=AIAssistantPanel.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AIAssistantPanel.js","names":[],"sources":["../../../src/components/assistant/AIAssistantPanel.tsx"],"sourcesContent":["/**\n * AI
|
|
1
|
+
{"version":3,"file":"AIAssistantPanel.js","names":[],"sources":["../../../src/components/assistant/AIAssistantPanel.tsx"],"sourcesContent":["/**\n * VibeControls' AI assistant.\n *\n * ★★ Everything below this file is now shared. The panel, the orchestrator, the\n * transport, the voice session, the composer and every component in them live in\n * `fe-libs/shared/assistant` and answer to any product that mounts them. What is\n * left here is the things that are genuinely VibeControls', and nothing else:\n *\n * modes which use cases this product offers.\n * describeCurrentPage what to CALL the page the user is on.\n * gatherPageContext the same page, as structured context for the agent.\n * buildPrompt the confirm-before-mutate guardrail, the language\n * directive and the dictation instructions.\n * reportTokenUsage the charge, against VibeControls' OWN reporter.\n * storageFolders where this product's attachments and artifacts live.\n *\n * Plus `writeAccess`, which is a PROP rather than a seventh seam field: which\n * resource types prove \"this user can write here\" is a product answer, but the\n * product can simply compute it and hand it down. A capability a product can\n * work out for itself does not belong in an interface every product must\n * satisfy.\n *\n * ★ The provider wraps from OUTSIDE the shared panel rather than sitting inside\n * its tree: the panel calls `useAssistantProduct()` and `useAssistantTr()` in its\n * own body, so a provider nested in its JSX would be below the consumer and read\n * as null — which does not throw, it silently renders English with no modes.\n *\n * ★ `AiCreditsMeter` is composed AROUND the shared panel, not inside it. The\n * shared panel has no slot for it and should not grow one: a credits strip is a\n * VibeControls billing decision, not something every product wants above its\n * assistant. It listens to the `notifyAiCreditsUpdated` event the shared chat\n * area already dispatches, so it keeps working untouched.\n */\n\nimport type { FC } from 'react';\nimport {\n AIAssistantPanel as SharedAIAssistantPanel,\n type AIAssistantPanelProps as SharedProps,\n} from '@burdenoff/fe-libs/shared/assistant/ui/AIAssistantPanel';\nimport { AssistantProductProvider } from '@burdenoff/fe-libs/shared/assistant/product';\nimport { getActorId, getWorkspaceId } from '@burdenoff/fe-libs/shared/assistant/context';\nimport { ASSISTANT_MODES } from '@/types/assistant';\nimport { PRODUCT, reportAssistantTokenUsage } from '@/services/assistantApi';\nimport { useWorkspaceWriteAccess } from '@/hooks/useWorkspaceWriteAccess';\nimport { describeCurrentPage, gatherPageContext } from '@/utils/pageContext';\nimport { buildPromptForMode } from '@/utils/assistantPrompt';\nimport { AiCreditsMeter } from './AiCreditsMeter';\n\n/**\n * Where this product's assistant files live.\n *\n * ★★ These strings are LOAD-BEARING once users have saved anything. They are the\n * real folders in the workspace file library holding every attachment and\n * artifact. Changing them does not fail — it starts a second folder beside the\n * first and orphans everything in the original.\n *\n * ★ Note the capitalisation: `/VibeControls/…`, while the product id is\n * `vibecontrols`. That mismatch is exactly why fe-libs cannot derive this and\n * why it is supplied here.\n */\nconst STORAGE_FOLDERS = {\n attachments: '/VibeControls/AI Assistant/Attachments',\n artifacts: '/VibeControls/AI Assistant/Artifacts',\n} as const;\n\nexport type AIAssistantPanelProps = Omit<SharedProps, 'writeAccess'>;\n\nexport const AIAssistantPanel: FC<AIAssistantPanelProps> = (props) => {\n /**\n * ★ Advisory, never a gate — see `useWorkspaceWriteAccess`. Gating on it\n * would remove api-calls from the product entirely until RBAC rows are\n * seeded. It warns before the effort instead of after it, and self-corrects\n * with no code change the moment those rows exist.\n */\n const writeAccess = useWorkspaceWriteAccess(getActorId(), getWorkspaceId() || null);\n\n return (\n <AssistantProductProvider\n product={PRODUCT}\n modes={ASSISTANT_MODES}\n describeCurrentPage={describeCurrentPage}\n gatherPageContext={gatherPageContext}\n buildPrompt={buildPromptForMode}\n reportTokenUsage={reportAssistantTokenUsage}\n storageFolders={STORAGE_FOLDERS}\n >\n <div className=\"flex flex-col h-full w-full min-h-0\">\n <AiCreditsMeter />\n <div className=\"flex-1 min-h-0\">\n <SharedAIAssistantPanel {...props} writeAccess={writeAccess} />\n </div>\n </div>\n </AssistantProductProvider>\n );\n};\n"],"mappings":";;;;;;;;;;;AA4DA,IAAM,IAAkB;CACtB,aAAa;CACb,WAAW;CACZ,EAIY,KAA+C,MAAU;CAOpE,IAAM,IAAc,EAAwB,GAAY,EAAE,GAAgB,IAAI,KAAK;AAEnF,QACE,kBAAC,GAAD;EACE,SAAS;EACT,OAAO;EACc;EACF;EACnB,aAAa;EACb,kBAAkB;EAClB,gBAAgB;YAEhB,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,GAAD,EAAkB,CAAA,EAClB,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,GAAD;KAAwB,GAAI;KAAoB;KAAe,CAAA;IAC3D,CAAA,CACF;;EACmB,CAAA"}
|
|
@@ -1,281 +1,11 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
import
|
|
12
|
-
import { useGatewayClient as ie } from "@burdenoff/fe-libs/shared/graphql";
|
|
13
|
-
import { useAuthToken as ae } from "@burdenoff/fe-libs/shared/providers/shell";
|
|
14
|
-
import { jsx as x, jsxs as S } from "react/jsx-runtime";
|
|
15
|
-
//#region src/components/assistant/AssistantChatArea.tsx
|
|
16
|
-
var oe = {
|
|
17
|
-
assistant: 18e4,
|
|
18
|
-
general: 18e4,
|
|
19
|
-
"api-calls": 18e4,
|
|
20
|
-
"vibe-plugins": 6e5
|
|
21
|
-
}, C = 18e4;
|
|
22
|
-
function w() {
|
|
23
|
-
return `${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
24
|
-
}
|
|
25
|
-
function T(e) {
|
|
26
|
-
try {
|
|
27
|
-
let t = e === "workspaceId" ? "burdenoff-active-context-workspace" : "burdenoff-active-context-organization", n = localStorage.getItem(t);
|
|
28
|
-
if (n) return n;
|
|
29
|
-
let r = sessionStorage.getItem("bf-active-profile");
|
|
30
|
-
if (!r) return "";
|
|
31
|
-
let i = localStorage.getItem(`bf-p-${r}-context`);
|
|
32
|
-
return i ? JSON.parse(i)[e] ?? "" : "";
|
|
33
|
-
} catch {
|
|
34
|
-
return "";
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
function se() {
|
|
38
|
-
return new URLSearchParams(window.location.search).get("workspace") ?? T("workspaceId");
|
|
39
|
-
}
|
|
40
|
-
function ce() {
|
|
41
|
-
return new URLSearchParams(window.location.search).get("org") ?? T("organizationId");
|
|
42
|
-
}
|
|
43
|
-
function le(e) {
|
|
44
|
-
let t = e instanceof Error ? e.message.toLowerCase() : String(e).toLowerCase();
|
|
45
|
-
return t.includes("rate limit exceeded") || t.includes("unauthorized") || t.includes("k8s api error 401") ? !1 : [
|
|
46
|
-
"sandbox not found",
|
|
47
|
-
"sandbox is not running",
|
|
48
|
-
"sandbox service not available yet",
|
|
49
|
-
"sandbox failed",
|
|
50
|
-
"sandbox startup timed out",
|
|
51
|
-
"assistant service did not become healthy",
|
|
52
|
-
"proxy error: 404",
|
|
53
|
-
"proxy error: 502",
|
|
54
|
-
"proxy error: 503",
|
|
55
|
-
"session mode mismatch"
|
|
56
|
-
].some((e) => t.includes(e));
|
|
57
|
-
}
|
|
58
|
-
function E(e) {
|
|
59
|
-
return e.replace(/(Authorization\s*:\s*Bearer\s+)[^\s\n]+/gi, "$1[REDACTED]").replace(/(X-Workspace-Authorization\s*:\s*Bearer\s+)[^\s\n]+/gi, "$1[REDACTED]").replace(/\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9._-]+\.[A-Za-z0-9._-]+\b/g, "[REDACTED_JWT]").replace(/\bsk-ant-[A-Za-z0-9-]+\b/g, "[REDACTED_API_KEY]");
|
|
60
|
-
}
|
|
61
|
-
function D(e) {
|
|
62
|
-
return e.info?.time?.created ?? 0;
|
|
63
|
-
}
|
|
64
|
-
function O(e) {
|
|
65
|
-
return (e ?? []).filter((e) => e.type === "text" && typeof e.text == "string").map((e) => e.text?.trim() ?? "").filter(Boolean).join("\n");
|
|
66
|
-
}
|
|
67
|
-
function k(e) {
|
|
68
|
-
return (e ?? []).filter((e) => e.type === "tool" && e.tool).map((e) => {
|
|
69
|
-
let t = e.state?.status ?? "running", n = e.tool ?? "tool";
|
|
70
|
-
return t === "completed" ? `Completed: ${n}` : t === "failed" ? `Failed: ${n}` : `Running: ${n}`;
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
function A(e, t) {
|
|
74
|
-
let n = e.filter((e) => e.info?.role === "assistant" && D(e) >= t).sort((e, t) => D(e) - D(t));
|
|
75
|
-
if (n.length === 0) return {
|
|
76
|
-
content: "Thinking...",
|
|
77
|
-
done: !1
|
|
78
|
-
};
|
|
79
|
-
let r = n[n.length - 1], i = O(r.parts), a = k(r.parts);
|
|
80
|
-
return {
|
|
81
|
-
content: [i, ...a].filter(Boolean).join("\n\n") || "Thinking...",
|
|
82
|
-
done: !!r.info?.time?.completed && (!!i || a.length > 0),
|
|
83
|
-
tokens: r.info?.tokens,
|
|
84
|
-
model: r.info?.providerID && r.info?.modelID ? `${r.info.providerID}/${r.info.modelID}` : void 0
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
function ue(e) {
|
|
88
|
-
switch (e) {
|
|
89
|
-
case "provisioning": return "Starting assistant environment...";
|
|
90
|
-
case "connecting": return "Connecting to assistant...";
|
|
91
|
-
case "streaming": return "Thinking...";
|
|
92
|
-
default: return "";
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
var j = () => {
|
|
96
|
-
let T = e(), D = ie("workspace"), { getAccessToken: O, getWorkspaceToken: k, userId: j } = ae(), { conversations: M, activeConversationId: N, mode: P, processingByConversationId: F, setMode: I, setConversationMode: L, setActiveConversation: R, createConversation: z, addMessage: B, updateMessage: V, patchMessage: H, setConversationProcessing: U, clearConversationProcessing: de, setBackendSessionId: W, clearBackendSessionId: G, setSandbox: K, clearSandbox: q } = n(), J = M.find((e) => e.id === N)?.messages ?? [], Y = N ? F[N] : void 0, fe = Y?.messageId ?? null, pe = Y?.status === "provisioning" || Y?.status === "connecting" || Y?.status === "streaming", X = y((e, t, n, r) => {
|
|
97
|
-
U(e, n, t, null), r ? V(e, t, r) : V(e, t, ue(n));
|
|
98
|
-
}, [U, V]), Z = y(async (e, t, r, o, c) => {
|
|
99
|
-
let l = n.getState().sandboxesByMode[r]?.sandboxId ?? null;
|
|
100
|
-
if (!l) {
|
|
101
|
-
X(e, t, "provisioning", "Looking for existing environment...");
|
|
102
|
-
let n = await s(D, o, r, c);
|
|
103
|
-
if (n) l = n, K(r, l, "provisioning"), X(e, t, "provisioning", "Reusing assistant environment..."), await p(D, l, o, c, 3e5, (n) => X(e, t, "provisioning", n)), await f(D, l, o, c, 9e4, (n) => X(e, t, "connecting", n)), K(r, l, "running");
|
|
104
|
-
else {
|
|
105
|
-
if (r === "api-calls" && !O()) throw Error("API Calls mode requires an authenticated session. Please sign in again.");
|
|
106
|
-
X(e, t, "provisioning", "Starting assistant environment..."), K(r, null, "provisioning"), l = await i(D, r, o, c), K(r, l, "provisioning"), await p(D, l, o, c, 3e5, (n) => X(e, t, "provisioning", n)), await f(D, l, o, c, 9e4, (n) => X(e, t, "connecting", n)), K(r, l, "running");
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
let d = n.getState().conversations.find((t) => t.id === e)?.backendSessionId ?? null;
|
|
110
|
-
if (d) try {
|
|
111
|
-
let e = await u(D, l, o, d, c);
|
|
112
|
-
if (e.mode !== r) throw Error(`Session mode mismatch: expected ${r}, received ${e.mode}`);
|
|
113
|
-
} catch {
|
|
114
|
-
G(e), d = null;
|
|
115
|
-
}
|
|
116
|
-
return d || (X(e, t, "connecting", "Preparing session..."), d = (await a(D, l, o, r, c)).sessionId, W(e, d)), {
|
|
117
|
-
sandboxId: l,
|
|
118
|
-
sessionId: d
|
|
119
|
-
};
|
|
120
|
-
}, [
|
|
121
|
-
D,
|
|
122
|
-
G,
|
|
123
|
-
O,
|
|
124
|
-
W,
|
|
125
|
-
K,
|
|
126
|
-
X
|
|
127
|
-
]), Q = y(async (e) => {
|
|
128
|
-
if (N) {
|
|
129
|
-
let e = F[N]?.status;
|
|
130
|
-
if (e === "provisioning" || e === "connecting" || e === "streaming") return;
|
|
131
|
-
}
|
|
132
|
-
let i = n.getState().mode, a = N, s = a ? n.getState().conversations.find((e) => e.id === a) : void 0;
|
|
133
|
-
if (a ? s && s.mode !== i && (s.messages.length > 0 || s.backendSessionId) ? a = z(void 0, i) : s && s.mode !== i && L(a, i) : a = z(void 0, i), !a) return;
|
|
134
|
-
let u = se(), f = {
|
|
135
|
-
accessToken: O(),
|
|
136
|
-
workspaceToken: k(),
|
|
137
|
-
userId: j,
|
|
138
|
-
organizationId: ce()
|
|
139
|
-
}, p = {
|
|
140
|
-
id: w(),
|
|
141
|
-
role: "user",
|
|
142
|
-
content: e,
|
|
143
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
144
|
-
};
|
|
145
|
-
B(a, p);
|
|
146
|
-
let m = w();
|
|
147
|
-
B(a, {
|
|
148
|
-
id: m,
|
|
149
|
-
role: "assistant",
|
|
150
|
-
content: "",
|
|
151
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
152
|
-
});
|
|
153
|
-
let h = (e, t, n, r) => {
|
|
154
|
-
H(a, m, {
|
|
155
|
-
content: E(e),
|
|
156
|
-
metadata: t?.length || n || r ? {
|
|
157
|
-
artifacts: t,
|
|
158
|
-
mode: i,
|
|
159
|
-
sessionId: n,
|
|
160
|
-
sandboxId: r
|
|
161
|
-
} : void 0
|
|
162
|
-
});
|
|
163
|
-
}, g = async (n = 1) => {
|
|
164
|
-
try {
|
|
165
|
-
await r(D, u, f);
|
|
166
|
-
} catch (e) {
|
|
167
|
-
if (t(e)) {
|
|
168
|
-
v("ai-credits"), h("You've run out of AI credits for this billing cycle. Upgrade your plan to keep chatting."), U(a, "error", m, null);
|
|
169
|
-
return;
|
|
170
|
-
}
|
|
171
|
-
console.warn("[assistant] AI-credit pre-flight check failed with a non-quota error; proceeding — gateway @usage(checkQuota) still enforces the real budget downstream", e);
|
|
172
|
-
}
|
|
173
|
-
try {
|
|
174
|
-
let { sandboxId: t, sessionId: n } = await Z(a, m, i, u, f);
|
|
175
|
-
X(a, m, "streaming", "Thinking...");
|
|
176
|
-
let r = Date.now();
|
|
177
|
-
await ee(D, t, u, n, e, i, te(), f);
|
|
178
|
-
let s = A([], r), p = Date.now() + (oe[i] ?? C), g = Date.now();
|
|
179
|
-
for (; Date.now() < p && (s = A(await l(D, t, u, n, f, 50), r), H(a, m, { content: E(s.content) }), !s.done);) Date.now() - g > 3e4 && (await o(D, t, u, 600, f).catch(() => void 0), g = Date.now()), await new Promise((e) => setTimeout(e, 1500));
|
|
180
|
-
if (!s.done && i !== "vibe-plugins") throw Error("Assistant response timed out while streaming progress");
|
|
181
|
-
let _ = i === "vibe-plugins" ? await c(D, t, u, n, f).catch(() => []) : void 0;
|
|
182
|
-
if (s.done || (s = {
|
|
183
|
-
...s,
|
|
184
|
-
content: `${s.content}\n\n_Still building in the background — any artifacts below will finish shortly. Re-open this conversation to pick up the completed plugin._`
|
|
185
|
-
}), h(s.content, _, n, t), s.tokens) {
|
|
186
|
-
H(a, m, { tokens: s.tokens });
|
|
187
|
-
try {
|
|
188
|
-
await d(D, u, n, m, s.model, s.tokens, f), ne();
|
|
189
|
-
} catch {}
|
|
190
|
-
}
|
|
191
|
-
U(a, "complete", m, null);
|
|
192
|
-
} catch (e) {
|
|
193
|
-
if (n === 1 && le(e)) return G(a), q(i), g(2);
|
|
194
|
-
throw e;
|
|
195
|
-
}
|
|
196
|
-
};
|
|
197
|
-
try {
|
|
198
|
-
if (!u) throw Error("Assistant backend is unavailable without an active workspace context.");
|
|
199
|
-
await g();
|
|
200
|
-
} catch (e) {
|
|
201
|
-
if (t(e)) {
|
|
202
|
-
v("sandbox"), h("You've reached your sandbox limit on the current plan. Upgrade to start the AI assistant."), U(a, "error", m, null);
|
|
203
|
-
return;
|
|
204
|
-
}
|
|
205
|
-
let n = e instanceof Error ? e.message : "Something went wrong";
|
|
206
|
-
U(a, "error", m, n), V(a, m, `Sorry, an error occurred: ${n}. Please try again.`);
|
|
207
|
-
}
|
|
208
|
-
}, [
|
|
209
|
-
N,
|
|
210
|
-
B,
|
|
211
|
-
D,
|
|
212
|
-
G,
|
|
213
|
-
q,
|
|
214
|
-
M,
|
|
215
|
-
z,
|
|
216
|
-
Z,
|
|
217
|
-
O,
|
|
218
|
-
k,
|
|
219
|
-
H,
|
|
220
|
-
F,
|
|
221
|
-
W,
|
|
222
|
-
L,
|
|
223
|
-
U,
|
|
224
|
-
X,
|
|
225
|
-
V,
|
|
226
|
-
j
|
|
227
|
-
]), me = y((e) => {
|
|
228
|
-
Q(e);
|
|
229
|
-
}, [Q]), $ = re(Q);
|
|
230
|
-
b(() => {
|
|
231
|
-
$.current = Q;
|
|
232
|
-
}, [Q]), b(() => {
|
|
233
|
-
let e = n.getState().consumePendingPrompt();
|
|
234
|
-
return e && $.current(e), n.subscribe((e, t) => {
|
|
235
|
-
if (e.pendingPrompt && e.pendingPrompt !== t.pendingPrompt) {
|
|
236
|
-
let e = n.getState().consumePendingPrompt();
|
|
237
|
-
e && $.current(e);
|
|
238
|
-
}
|
|
239
|
-
});
|
|
240
|
-
}, []);
|
|
241
|
-
let he = y((e) => {
|
|
242
|
-
let t = N ? n.getState().conversations.find((e) => e.id === N) : void 0;
|
|
243
|
-
if (t && (t.messages.length > 0 || t.backendSessionId)) {
|
|
244
|
-
if (t.mode !== e) {
|
|
245
|
-
let t = n.getState().conversations.find((t) => t.mode === e && t.messages.length === 0 && !t.backendSessionId && !n.getState().processingByConversationId[t.id]);
|
|
246
|
-
t ? R(t.id) : z(void 0, e);
|
|
247
|
-
}
|
|
248
|
-
} else N && L(N, e);
|
|
249
|
-
I(e);
|
|
250
|
-
}, [
|
|
251
|
-
N,
|
|
252
|
-
z,
|
|
253
|
-
R,
|
|
254
|
-
L,
|
|
255
|
-
I
|
|
256
|
-
]);
|
|
257
|
-
return /* @__PURE__ */ S("div", {
|
|
258
|
-
className: "flex flex-col flex-1 overflow-hidden pt-3",
|
|
259
|
-
children: [J.length === 0 ? /* @__PURE__ */ x(_, {
|
|
260
|
-
mode: P,
|
|
261
|
-
onSuggestionClick: me
|
|
262
|
-
}) : /* @__PURE__ */ x(h, {
|
|
263
|
-
messages: J,
|
|
264
|
-
streamingMessageId: fe
|
|
265
|
-
}), /* @__PURE__ */ S("div", { children: [/* @__PURE__ */ x("div", {
|
|
266
|
-
className: "px-3 pb-1",
|
|
267
|
-
children: /* @__PURE__ */ x(g, {
|
|
268
|
-
mode: P,
|
|
269
|
-
onModeChange: he
|
|
270
|
-
})
|
|
271
|
-
}), /* @__PURE__ */ x(m, {
|
|
272
|
-
onSend: (e) => void Q(e),
|
|
273
|
-
disabled: pe,
|
|
274
|
-
placeholder: T("vibecontrols.assistant.chatArea.placeholder", `Ask about ${P.replace(/-/g, " ")}...`)
|
|
275
|
-
})] })]
|
|
276
|
-
});
|
|
277
|
-
};
|
|
278
|
-
//#endregion
|
|
279
|
-
export { j as AssistantChatArea };
|
|
280
|
-
|
|
281
|
-
//# sourceMappingURL=AssistantChatArea.js.map
|
|
1
|
+
import "../../shared/hooks/useTr.js";
|
|
2
|
+
import "../../services/assistantApi.js";
|
|
3
|
+
import "./AssistantChatInput.js";
|
|
4
|
+
import "./AssistantMessageList.js";
|
|
5
|
+
import "./AssistantModeSelector.js";
|
|
6
|
+
import "./AssistantWelcome.js";
|
|
7
|
+
import "../../store/assistantStore.js";
|
|
8
|
+
import "react";
|
|
9
|
+
import "@burdenoff/fe-libs/shared/graphql";
|
|
10
|
+
import "@burdenoff/fe-libs/shared/providers/shell";
|
|
11
|
+
import "react/jsx-runtime";
|
|
@@ -1,44 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
//#region src/components/assistant/AssistantChatInput.tsx
|
|
6
|
-
var o = ({ onSend: o, disabled: s = !1, placeholder: c = "Ask anything..." }) => {
|
|
7
|
-
let l = e(), u = n(null), d = t(() => {
|
|
8
|
-
let e = u.current;
|
|
9
|
-
if (!e) return;
|
|
10
|
-
let t = e.value.trim();
|
|
11
|
-
!t || s || (o(t), e.value = "", e.style.height = "auto");
|
|
12
|
-
}, [o, s]);
|
|
13
|
-
return /* @__PURE__ */ a("div", {
|
|
14
|
-
className: "flex items-end gap-2 px-3 py-2.5 border-t border-border-default bg-bg-surface",
|
|
15
|
-
children: [/* @__PURE__ */ i("textarea", {
|
|
16
|
-
ref: u,
|
|
17
|
-
onKeyDown: t((e) => {
|
|
18
|
-
e.key === "Enter" && !e.shiftKey && (e.preventDefault(), d());
|
|
19
|
-
}, [d]),
|
|
20
|
-
onInput: t(() => {
|
|
21
|
-
let e = u.current;
|
|
22
|
-
e && (e.style.height = "auto", e.style.height = `${Math.min(e.scrollHeight, 120)}px`);
|
|
23
|
-
}, []),
|
|
24
|
-
disabled: s,
|
|
25
|
-
placeholder: c,
|
|
26
|
-
rows: 1,
|
|
27
|
-
className: "flex-1 resize-none bg-bg-sunken border border-border-default rounded-lg px-3 py-2 text-xs text-text-primary placeholder:text-text-muted focus:outline-none focus:border-action-primary-bg disabled:opacity-50 leading-relaxed",
|
|
28
|
-
"aria-label": l("vibecontrols.assistant.chatInput.ariaLabel", "Message input"),
|
|
29
|
-
"data-testid": "assistant-input"
|
|
30
|
-
}), /* @__PURE__ */ i("button", {
|
|
31
|
-
type: "button",
|
|
32
|
-
onClick: d,
|
|
33
|
-
disabled: s,
|
|
34
|
-
className: "flex-shrink-0 p-2 bg-action-primary-bg text-action-primary-text rounded-lg hover:bg-action-primary-bg-hover transition-colors disabled:opacity-50",
|
|
35
|
-
"aria-label": l("vibecontrols.assistant.chatInput.send", "Send message"),
|
|
36
|
-
"data-testid": "assistant-send",
|
|
37
|
-
children: /* @__PURE__ */ i(r, { className: "size-3.5" })
|
|
38
|
-
})]
|
|
39
|
-
});
|
|
40
|
-
};
|
|
41
|
-
//#endregion
|
|
42
|
-
export { o as AssistantChatInput };
|
|
43
|
-
|
|
44
|
-
//# sourceMappingURL=AssistantChatInput.js.map
|
|
1
|
+
import "../../shared/hooks/useTr.js";
|
|
2
|
+
import "react";
|
|
3
|
+
import "lucide-react";
|
|
4
|
+
import "react/jsx-runtime";
|
|
@@ -1,155 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
//#region src/components/assistant/AssistantConversationList.tsx
|
|
8
|
-
var m = () => {
|
|
9
|
-
let m = e(), { conversations: h, activeConversationId: g, processingByConversationId: _, setActiveConversation: v, setMode: y, createConversation: b, deleteConversation: x, renameConversation: S, setConversationListOpen: C } = t(), [w, T] = i(null), [E, D] = i("");
|
|
10
|
-
r(() => {
|
|
11
|
-
g && C(!1);
|
|
12
|
-
}, [g, C]);
|
|
13
|
-
let O = () => {
|
|
14
|
-
b(), C(!1);
|
|
15
|
-
}, k = (e) => {
|
|
16
|
-
let t = h.find((t) => t.id === e);
|
|
17
|
-
v(e), t && y(t.mode), C(!1);
|
|
18
|
-
}, A = (e, t) => {
|
|
19
|
-
T(e), D(t);
|
|
20
|
-
}, j = () => {
|
|
21
|
-
w && E.trim() && S(w, E.trim()), T(null);
|
|
22
|
-
}, M = (e, t) => {
|
|
23
|
-
e.stopPropagation(), x(t);
|
|
24
|
-
};
|
|
25
|
-
return /* @__PURE__ */ p("div", {
|
|
26
|
-
className: "absolute inset-0 z-10 flex flex-col bg-bg-surface",
|
|
27
|
-
"data-testid": "conversation-list",
|
|
28
|
-
children: [/* @__PURE__ */ p("div", {
|
|
29
|
-
className: "flex items-center justify-between px-3 py-2 border-b border-border-default",
|
|
30
|
-
children: [/* @__PURE__ */ f("span", {
|
|
31
|
-
className: "text-xs font-semibold text-text-primary",
|
|
32
|
-
children: m("vibecontrols.assistant.conversations.title", "Conversations")
|
|
33
|
-
}), /* @__PURE__ */ p("div", {
|
|
34
|
-
className: "flex items-center gap-1",
|
|
35
|
-
children: [/* @__PURE__ */ f("button", {
|
|
36
|
-
type: "button",
|
|
37
|
-
onClick: O,
|
|
38
|
-
className: "p-1 hover:bg-bg-elevated rounded transition-colors",
|
|
39
|
-
"aria-label": m("vibecontrols.assistant.conversations.new", "New conversation"),
|
|
40
|
-
"data-testid": "new-conversation",
|
|
41
|
-
children: /* @__PURE__ */ f(c, { className: "size-3.5 text-text-secondary" })
|
|
42
|
-
}), /* @__PURE__ */ f("button", {
|
|
43
|
-
type: "button",
|
|
44
|
-
onClick: () => C(!1),
|
|
45
|
-
className: "p-1 hover:bg-bg-elevated rounded transition-colors",
|
|
46
|
-
"aria-label": "Close conversation list",
|
|
47
|
-
children: /* @__PURE__ */ f(u, { className: "size-3.5 text-text-secondary" })
|
|
48
|
-
})]
|
|
49
|
-
})]
|
|
50
|
-
}), /* @__PURE__ */ f("div", {
|
|
51
|
-
className: "flex-1 overflow-y-auto",
|
|
52
|
-
children: h.length === 0 ? /* @__PURE__ */ p("div", {
|
|
53
|
-
className: "flex flex-col items-center justify-center h-full text-center px-4",
|
|
54
|
-
children: [
|
|
55
|
-
/* @__PURE__ */ f(o, { className: "size-6 text-text-muted mb-2" }),
|
|
56
|
-
/* @__PURE__ */ f("p", {
|
|
57
|
-
className: "text-xs text-text-muted",
|
|
58
|
-
children: m("vibecontrols.assistant.conversations.empty", "No conversations yet")
|
|
59
|
-
}),
|
|
60
|
-
/* @__PURE__ */ f("button", {
|
|
61
|
-
type: "button",
|
|
62
|
-
onClick: O,
|
|
63
|
-
className: "mt-2 text-xs text-action-primary-bg hover:underline",
|
|
64
|
-
children: m("vibecontrols.assistant.conversations.startNew", "Start a new conversation")
|
|
65
|
-
})
|
|
66
|
-
]
|
|
67
|
-
}) : /* @__PURE__ */ f("div", {
|
|
68
|
-
className: "py-1",
|
|
69
|
-
children: h.map((e) => {
|
|
70
|
-
let t = e.id === g, r = e.id === w, i = n.find((t) => t.id === e.mode), o = e.messages[e.messages.length - 1], c = _[e.id];
|
|
71
|
-
return /* @__PURE__ */ f("div", {
|
|
72
|
-
role: "button",
|
|
73
|
-
tabIndex: 0,
|
|
74
|
-
onKeyDown: (t) => {
|
|
75
|
-
(t.key === "Enter" || t.key === " ") && (t.preventDefault(), !r && k(e.id));
|
|
76
|
-
},
|
|
77
|
-
onClick: () => !r && k(e.id),
|
|
78
|
-
className: `group px-3 py-2 cursor-pointer hover:bg-bg-elevated transition-colors ${t ? "bg-bg-elevated border-l-2 border-action-primary-bg" : ""}`,
|
|
79
|
-
children: r ? /* @__PURE__ */ p("div", {
|
|
80
|
-
className: "flex items-center gap-1",
|
|
81
|
-
children: [/* @__PURE__ */ f("input", {
|
|
82
|
-
"aria-label": "control",
|
|
83
|
-
value: E,
|
|
84
|
-
onChange: (e) => D(e.target.value),
|
|
85
|
-
onKeyDown: (e) => {
|
|
86
|
-
e.key === "Enter" && j(), e.key === "Escape" && T(null);
|
|
87
|
-
},
|
|
88
|
-
className: "flex-1 text-xs bg-bg-sunken border border-border-default rounded px-2 py-1 text-text-primary focus:outline-none focus:border-action-primary-bg",
|
|
89
|
-
onClick: (e) => e.stopPropagation()
|
|
90
|
-
}), /* @__PURE__ */ f("button", {
|
|
91
|
-
type: "button",
|
|
92
|
-
onClick: (e) => {
|
|
93
|
-
e.stopPropagation(), j();
|
|
94
|
-
},
|
|
95
|
-
className: "p-1 hover:bg-bg-sunken rounded",
|
|
96
|
-
children: /* @__PURE__ */ f(a, { className: "size-3 text-status-success-text" })
|
|
97
|
-
})]
|
|
98
|
-
}) : /* @__PURE__ */ p(d, { children: [
|
|
99
|
-
/* @__PURE__ */ p("div", {
|
|
100
|
-
className: "flex items-center justify-between",
|
|
101
|
-
children: [/* @__PURE__ */ f("span", {
|
|
102
|
-
className: "text-xs font-medium text-text-primary truncate flex-1",
|
|
103
|
-
children: e.title
|
|
104
|
-
}), /* @__PURE__ */ p("div", {
|
|
105
|
-
className: "hidden group-hover:flex items-center gap-0.5 ml-1",
|
|
106
|
-
children: [/* @__PURE__ */ f("button", {
|
|
107
|
-
type: "button",
|
|
108
|
-
onClick: (t) => {
|
|
109
|
-
t.stopPropagation(), A(e.id, e.title);
|
|
110
|
-
},
|
|
111
|
-
className: "p-0.5 hover:bg-bg-sunken rounded",
|
|
112
|
-
"aria-label": "Rename conversation",
|
|
113
|
-
children: /* @__PURE__ */ f(s, { className: "size-3 text-text-muted" })
|
|
114
|
-
}), /* @__PURE__ */ f("button", {
|
|
115
|
-
type: "button",
|
|
116
|
-
onClick: (t) => M(t, e.id),
|
|
117
|
-
className: "p-0.5 hover:bg-bg-sunken rounded",
|
|
118
|
-
"aria-label": "Delete conversation",
|
|
119
|
-
"data-testid": "delete-conversation",
|
|
120
|
-
children: /* @__PURE__ */ f(l, { className: "size-3 text-status-error-text" })
|
|
121
|
-
})]
|
|
122
|
-
})]
|
|
123
|
-
}),
|
|
124
|
-
/* @__PURE__ */ p("div", {
|
|
125
|
-
className: "flex items-center gap-1.5 mt-0.5",
|
|
126
|
-
children: [
|
|
127
|
-
/* @__PURE__ */ f("span", {
|
|
128
|
-
className: "text-[10px] text-text-muted px-1 py-0.5 bg-bg-sunken rounded",
|
|
129
|
-
children: i?.label ?? e.mode
|
|
130
|
-
}),
|
|
131
|
-
/* @__PURE__ */ p("span", {
|
|
132
|
-
className: "text-[10px] text-text-muted",
|
|
133
|
-
children: [e.messages.length, " msgs"]
|
|
134
|
-
}),
|
|
135
|
-
c && c.status !== "idle" && /* @__PURE__ */ f("span", {
|
|
136
|
-
className: "text-[10px] text-action-primary-bg px-1 py-0.5 bg-bg-sunken rounded",
|
|
137
|
-
children: c.status
|
|
138
|
-
})
|
|
139
|
-
]
|
|
140
|
-
}),
|
|
141
|
-
o && /* @__PURE__ */ f("p", {
|
|
142
|
-
className: "text-[10px] text-text-muted truncate mt-0.5",
|
|
143
|
-
children: o.content.slice(0, 60)
|
|
144
|
-
})
|
|
145
|
-
] })
|
|
146
|
-
}, e.id);
|
|
147
|
-
})
|
|
148
|
-
})
|
|
149
|
-
})]
|
|
150
|
-
});
|
|
151
|
-
};
|
|
152
|
-
//#endregion
|
|
153
|
-
export { m as AssistantConversationList };
|
|
154
|
-
|
|
155
|
-
//# sourceMappingURL=AssistantConversationList.js.map
|
|
1
|
+
import "../../shared/hooks/useTr.js";
|
|
2
|
+
import "../../types/assistant.js";
|
|
3
|
+
import "../../store/assistantStore.js";
|
|
4
|
+
import "react";
|
|
5
|
+
import "lucide-react";
|
|
6
|
+
import "react/jsx-runtime";
|