@burdenoff/microfe-bigconsole 2026.711.1 → 2026.711.3

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.
@@ -51,13 +51,37 @@ function S(e) {
51
51
  function C(e) {
52
52
  return (e.parts ?? [] ?? []).filter((e) => e.type === "text" && typeof e.text == "string").map((e) => e.text?.trim() ?? "").filter(Boolean).join("\n") || (typeof e.content == "string" ? e.content.trim() : "");
53
53
  }
54
- function w(e) {
54
+ var w = {
55
+ bash: "Running a command",
56
+ webfetch: "Fetching a page",
57
+ "file.read": "Reading files",
58
+ "file.write": "Writing files",
59
+ "file.edit": "Editing files",
60
+ "file.find.text": "Searching the code",
61
+ "file.find.file": "Looking for files",
62
+ todowrite: "Planning the steps",
63
+ todoread: "Reviewing the plan"
64
+ };
65
+ function T(e) {
66
+ return typeof e == "object" && e ? e : void 0;
67
+ }
68
+ function E(e) {
69
+ let t = e.tool ?? "tool", n = T(e.state?.input), r = n?.description;
70
+ if (typeof r == "string" && r.trim()) return r.trim();
71
+ let i = n?.todos;
72
+ if (Array.isArray(i)) {
73
+ let e = T(i.find((e) => T(e)?.status === "in_progress") ?? i[0])?.content;
74
+ if (typeof e == "string" && e.trim()) return e.trim();
75
+ }
76
+ return w[t] ?? `Running ${t}`;
77
+ }
78
+ function D(e) {
55
79
  return (e.parts ?? []).filter((e) => e.type === "tool" && e.tool).map((e) => {
56
- let t = e.state?.status ?? "running", n = e.tool ?? "tool";
57
- return t === "completed" ? `Completed: ${n}` : t === "failed" ? `Failed: ${n}` : `Running: ${n}`;
80
+ let t = e.state?.status ?? "running", n = E(e);
81
+ return t === "completed" ? `✓ ${n}` : t === "failed" ? `⚠ ${n}` : `⏳ ${n}…`;
58
82
  });
59
83
  }
60
- function T(e, t, n, r) {
84
+ function O(e, t, n, r) {
61
85
  let i = e.filter((e) => b(e) === "assistant" && x(e) >= t).sort((e, t) => x(e) - x(t));
62
86
  i.length === 0 && e.length > 0 && console.log("[BigConsole-Assistant] buildProgress: no relevant messages", {
63
87
  totalMessages: e.length,
@@ -68,7 +92,7 @@ function T(e, t, n, r) {
68
92
  let a, o;
69
93
  if (i.length === 0) a = "Thinking…", o = n === a && r !== void 0 && Date.now() - r >= 15e3;
70
94
  else {
71
- let e = i[i.length - 1], t = C(e), s = w(e);
95
+ let e = i[i.length - 1], t = C(e), s = D(e);
72
96
  a = [t, ...s].filter(Boolean).join("\n\n") || "Thinking…";
73
97
  let c = !!S(e) && (!!t || s.length > 0), l = !c && n === a && r !== void 0 && Date.now() - r >= 15e3;
74
98
  o = c || l;
@@ -78,10 +102,10 @@ function T(e, t, n, r) {
78
102
  done: o
79
103
  };
80
104
  }
81
- function E(e) {
105
+ function k(e) {
82
106
  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]");
83
107
  }
84
- function D(e) {
108
+ function A(e) {
85
109
  let t = e instanceof Error ? e.message.toLowerCase() : String(e).toLowerCase();
86
110
  return t.includes("rate limit exceeded") || t.includes("unauthorized") || t.includes("k8s api error 401") ? !1 : [
87
111
  "sandbox not found",
@@ -102,13 +126,13 @@ function D(e) {
102
126
  "unexpected error"
103
127
  ].some((e) => t.includes(e));
104
128
  }
105
- function O() {
106
- let { getAccessToken: _, getWorkspaceToken: S, userId: C, workspaceId: w } = f(), [O, k] = u(() => [null, null], []), A = d(O), j = d(k), M = l((e) => {
107
- A.current = e, e ? sessionStorage.setItem("bc-assistant-sandbox-id", e) : sessionStorage.removeItem("bc-assistant-sandbox-id");
129
+ function j() {
130
+ let { getAccessToken: _, getWorkspaceToken: S, userId: C, workspaceId: w } = f(), [T, E] = u(() => [null, null], []), D = d(T), j = d(E), M = l((e) => {
131
+ D.current = e, e ? sessionStorage.setItem("bc-assistant-sandbox-id", e) : sessionStorage.removeItem("bc-assistant-sandbox-id");
108
132
  }, []), N = l((e) => {
109
133
  j.current = e, e ? sessionStorage.setItem("bc-assistant-session-id", e) : sessionStorage.removeItem("bc-assistant-session-id");
110
134
  }, []), P = l(async (n, i) => {
111
- let a = A.current;
135
+ let a = D.current;
112
136
  if (console.log("[BigConsole-Assistant] ensureRuntime start", {
113
137
  sandboxId: a,
114
138
  workspaceId: n
@@ -175,7 +199,7 @@ function O() {
175
199
  sessionId: d,
176
200
  promptLength: e.length
177
201
  }), await a(l, o, d, e, p, c(), s);
178
- let _ = Date.now() + m, v = Date.now(), y = "", S = Date.now(), C = T([], f);
202
+ let _ = Date.now() + m, v = Date.now(), y = "", S = Date.now(), C = O([], f);
179
203
  for (; Date.now() < _;) {
180
204
  if (r.aborted) throw Error("Cancelled");
181
205
  let e = await i(l, o, d, s, 50);
@@ -184,26 +208,26 @@ function O() {
184
208
  messageCount: e.length,
185
209
  firstFewRoles: e.slice(0, 3).map((e) => b(e)),
186
210
  firstFewTimestamps: e.slice(0, 3).map((e) => x(e))
187
- }), C = T(e, f, y, S), console.log("[BigConsole-Assistant] progress", {
211
+ }), C = O(e, f, y, S), console.log("[BigConsole-Assistant] progress", {
188
212
  contentPreview: C.content.slice(0, 100),
189
213
  done: C.done,
190
214
  lastContentChangeAt: Date.now() - S
191
- }), C.content !== y && (y = C.content, S = Date.now()), t(E(C.content)), C.done) {
215
+ }), C.content !== y && (y = C.content, S = Date.now()), t(k(C.content)), C.done) {
192
216
  console.log("[BigConsole-Assistant] progress.done=true, breaking poll loop");
193
217
  break;
194
218
  }
195
219
  Date.now() - v > g && (await n(l, o, 600, s).catch(() => void 0), v = Date.now()), await new Promise((e) => setTimeout(e, h));
196
220
  }
197
221
  if (!C.done) throw Error("The assistant timed out while responding. Please try again.");
198
- return { text: E(C.content) };
222
+ return { text: k(C.content) };
199
223
  } catch (e) {
200
224
  if (console.error("[BigConsole-Assistant] run error", {
201
225
  attempt: u,
202
226
  error: e instanceof Error ? e.message : String(e),
203
227
  stack: e instanceof Error ? e.stack : void 0,
204
- sandboxId: A.current,
228
+ sandboxId: D.current,
205
229
  sessionId: j.current
206
- }), u === 1 && D(e)) return M(null), N(null), l(2);
230
+ }), u === 1 && A(e)) return M(null), N(null), l(2);
207
231
  throw e;
208
232
  }
209
233
  };
@@ -220,6 +244,6 @@ function O() {
220
244
  return u(() => ({ sendPrompt: F }), [F]);
221
245
  }
222
246
  //#endregion
223
- export { O as useSandboxAssistantTransport };
247
+ export { j as useSandboxAssistantTransport };
224
248
 
225
249
  //# sourceMappingURL=createSandboxAssistantTransport.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"createSandboxAssistantTransport.js","names":[],"sources":["../../../src/bigconsole/assistant/createSandboxAssistantTransport.ts"],"sourcesContent":["/**\n * BigConsole adapter for the shared fe-libs AssistantWidget.\n *\n * The floating widget (fe-libs, Layer 1) is backend-agnostic — it calls an\n * injected `AssistantTransport`. This hook builds a transport that drives the\n * sandbox AI assistant (combined `assistant` mode = docs Q&A + api-calls): it\n * provisions/reuses a sandbox, opens a session, dispatches the prompt async,\n * then polls for the streamed answer. The agent introspects the GraphQL schema\n * and performs API calls on the user's behalf using their workspace token,\n * contextual to the current screen (via `gatherPageContext`).\n *\n * This is a faithful port of microfe-vibecontrols'\n * `services/createSandboxAssistantTransport.ts`; the only product-specific\n * difference lives in `assistantApi.createAssistantSandbox`\n * (`AI_ASSISTANT_PRODUCT=bigconsole`).\n */\n\nimport { useCallback, useMemo, useRef } from 'react';\nimport { useAuthToken } from '@burdenoff/fe-libs/shared/providers/shell';\nimport {\n createAssistantSandbox,\n createAssistantSession,\n extendAssistantSandboxTTL,\n findExistingSandbox,\n getAssistantMessages,\n sendAssistantPromptAsync,\n waitForAssistantServiceReady,\n waitForSandboxReady,\n} from './assistantApi';\nimport { gatherPageContext } from './pageContext';\nimport type { AssistantMode, AssistantRawMessage, AssistantSandboxAuthContext } from './types';\n\n/**\n * Locally-defined mirror of the fe-libs `AssistantTransport` contract.\n *\n * Intentionally NOT imported from `@burdenoff/fe-libs`: microfe's tsconfig maps\n * `@burdenoff/fe-libs/*` to fe-libs *source*, so vite-plugin-dts would rewrite a\n * cross-package type used in this hook's public signature to a broken\n * source-relative path in the emitted `.d.ts`. Structural typing makes this\n * shape assignable to fe-libs' `AssistantTransport` at the call site\n * (bigconsole-app's AppShell), which is where compatibility is enforced.\n */\ninterface AssistantSendArgs {\n prompt: string;\n onProgress: (partialText: string) => void;\n signal: AbortSignal;\n}\n\nexport interface AssistantTransport {\n sendPrompt: (args: AssistantSendArgs) => Promise<{ text: string }>;\n}\n\n// BigConsole still boots the manually-tagged ACA image\n// `alpha-delegated-auth-v11` for the assistant sandbox. The historical\n// platform notes show that this image line reliably supports `api-calls`, while\n// the combined `assistant` mode depends on newer image contracts that are not\n// yet guaranteed on this tag. Use `api-calls` here so the assistant can execute\n// workspace GraphQL operations end-to-end right now. Once the underlying image\n// line is rebuilt and verified for combined mode, this can be switched back.\nconst MODE: AssistantMode = 'api-calls';\nconst STREAM_BUDGET_MS = 180_000;\nconst POLL_INTERVAL_MS = 1500;\nconst TTL_EXTEND_INTERVAL_MS = 30_000;\n\n// ── Context helpers (mirror vibecontrols' resolution) ────────────────\n\nfunction getProfileContextValue(key: 'workspaceId' | 'organizationId'): string {\n try {\n const activeContextKey =\n key === 'workspaceId' ? 'burdenoff-active-context-workspace' : 'burdenoff-active-context-organization';\n const activeContextValue = localStorage.getItem(activeContextKey);\n if (activeContextValue) return activeContextValue;\n\n const activeProfileId = sessionStorage.getItem('bf-active-profile');\n if (!activeProfileId) return '';\n const raw = localStorage.getItem(`bf-p-${activeProfileId}-context`);\n if (!raw) return '';\n const context = JSON.parse(raw) as { workspaceId?: string; organizationId?: string };\n return context[key] ?? '';\n } catch {\n return '';\n }\n}\n\nfunction getWorkspaceId(fallback: string | null): string {\n const params = new URLSearchParams(window.location.search);\n return params.get('workspace') ?? getProfileContextValue('workspaceId') ?? fallback ?? '';\n}\n\nfunction getOrganizationId(): string {\n const params = new URLSearchParams(window.location.search);\n return params.get('org') ?? getProfileContextValue('organizationId');\n}\n\n// ── Message-progress helpers (pure; mirror vibecontrols) ─────────────\n\nfunction getMessageRole(message: AssistantRawMessage): string | undefined {\n // Check nested format first, then flat format\n return message.info?.role ?? message.role;\n}\n\nfunction getRawMessageCreatedAt(message: AssistantRawMessage): number {\n // Check nested format first (epoch ms), then flat format (ISO string or epoch ms)\n const nested = message.info?.time?.created;\n if (nested !== undefined) return nested;\n const flat = message.createdAt;\n if (flat === undefined) return 0;\n // If it's a string (ISO), parse it; otherwise treat as epoch ms\n if (typeof flat === 'string') {\n const parsed = Date.parse(flat);\n return isNaN(parsed) ? 0 : parsed;\n }\n return flat;\n}\n\nfunction getMessageCompleted(message: AssistantRawMessage): number | undefined {\n // Check nested format first, then flat format\n const nested = message.info?.time?.completed;\n if (nested !== undefined) return nested;\n const flat = message.completedAt;\n if (flat === undefined) return undefined;\n if (typeof flat === 'string') {\n const parsed = Date.parse(flat);\n return isNaN(parsed) ? undefined : parsed;\n }\n return flat;\n}\n\nfunction getAssistantText(message: AssistantRawMessage): string {\n // Check parts format first (nested), then flat content\n const parts = message.parts ?? [];\n const textFromParts = (parts ?? [])\n .filter((part) => part.type === 'text' && typeof part.text === 'string')\n .map((part) => part.text?.trim() ?? '')\n .filter(Boolean)\n .join('\\n');\n if (textFromParts) return textFromParts;\n // Fallback to flat content field\n return typeof message.content === 'string' ? message.content.trim() : '';\n}\n\nfunction getToolProgress(message: AssistantRawMessage): string[] {\n const parts = message.parts ?? [];\n return parts\n .filter((part) => part.type === 'tool' && part.tool)\n .map((part) => {\n const status = part.state?.status ?? 'running';\n const tool = part.tool ?? 'tool';\n if (status === 'completed') return `Completed: ${tool}`;\n if (status === 'failed') return `Failed: ${tool}`;\n return `Running: ${tool}`;\n });\n}\n\nfunction buildProgress(\n messages: AssistantRawMessage[],\n sinceMs: number,\n previousContent?: string,\n previousContentAtMs?: number\n): { content: string; done: boolean } {\n const relevant = messages\n .filter((message) => getMessageRole(message) === 'assistant' && getRawMessageCreatedAt(message) >= sinceMs)\n .sort((left, right) => getRawMessageCreatedAt(left) - getRawMessageCreatedAt(right));\n\n // Debug: log message filtering when no relevant messages found\n if (relevant.length === 0 && messages.length > 0) {\n console.log('[BigConsole-Assistant] buildProgress: no relevant messages', {\n totalMessages: messages.length,\n sinceMs,\n messageRoles: messages.map((m) => getMessageRole(m)),\n messageTimestamps: messages.map((m) => getRawMessageCreatedAt(m)),\n });\n }\n\n let content: string;\n let done: boolean;\n\n if (relevant.length === 0) {\n content = 'Thinking…';\n // Staleness fallback: if no messages have appeared after 15+ seconds of polling,\n // treat the response as complete even when messages get filtered out\n // (e.g., due to timestamp skew or role mismatch).\n done =\n previousContent === content && previousContentAtMs !== undefined && Date.now() - previousContentAtMs >= 15_000;\n } else {\n const latest = relevant[relevant.length - 1]!;\n const text = getAssistantText(latest);\n const toolProgress = getToolProgress(latest);\n content = [text, ...toolProgress].filter(Boolean).join('\\n\\n') || 'Thinking…';\n\n const officiallyDone = Boolean(getMessageCompleted(latest)) && (Boolean(text) || toolProgress.length > 0);\n\n // Staleness fallback: if content hasn't changed in 15 s, treat the build as\n // complete even when the assistant forgot to set `completed`.\n const staleDone =\n !officiallyDone &&\n previousContent === content &&\n previousContentAtMs !== undefined &&\n Date.now() - previousContentAtMs >= 15_000;\n\n done = officiallyDone || staleDone;\n }\n\n return { content, done };\n}\n\nfunction sanitize(response: string): string {\n return response\n .replace(/(Authorization\\s*:\\s*Bearer\\s+)[^\\s\\n]+/gi, '$1[REDACTED]')\n .replace(/(X-Workspace-Authorization\\s*:\\s*Bearer\\s+)[^\\s\\n]+/gi, '$1[REDACTED]')\n .replace(/\\beyJ[A-Za-z0-9_-]+\\.[A-Za-z0-9._-]+\\.[A-Za-z0-9._-]+\\b/g, '[REDACTED_JWT]')\n .replace(/\\bsk-ant-[A-Za-z0-9-]+\\b/g, '[REDACTED_API_KEY]');\n}\n\nfunction isRecoverable(error: unknown): boolean {\n const message = error instanceof Error ? error.message.toLowerCase() : String(error).toLowerCase();\n if (\n message.includes('rate limit exceeded') ||\n message.includes('unauthorized') ||\n message.includes('k8s api error 401')\n ) {\n return false;\n }\n return [\n 'sandbox not found',\n 'sandbox is not running',\n 'sandbox service not available yet',\n 'sandbox failed',\n 'sandbox startup timed out',\n 'assistant service did not become healthy',\n 'proxy error: 404',\n 'proxy error: 502',\n 'proxy error: 503',\n 'unable to connect',\n 'image pull',\n 'container failed',\n 'bootstrap failed',\n // Transient network errors from the browser fetch — gateway CORS preflight\n // failures, mid-stream resets, and Cloudflare 524s all surface as\n // \"Failed to fetch\" via TypeError. They're worth retrying on a clean\n // runtime since the underlying sandbox state is unaffected.\n 'failed to fetch',\n 'cf-proxy timeout',\n // Subgraph returned 500 with a generic message — gateway returns this as\n // a GraphQL error rather than an HTTP error. The actual underlying cause\n // (e.g., transient Prisma timeout) is recoverable, but a fresh sandbox\n // may be needed.\n 'unexpected error',\n ].some((fragment) => message.includes(fragment));\n}\n\n/**\n * Returns a memoized `AssistantTransport` wired to the BigConsole sandbox\n * assistant agent. The sandbox + session are cached in refs so follow-up turns\n * reuse the warm environment for the lifetime of the host shell.\n */\nexport function useSandboxAssistantTransport(): AssistantTransport {\n const { getAccessToken, getWorkspaceToken, userId, workspaceId: ctxWorkspaceId } = useAuthToken();\n\n // Do not hydrate sandbox/session ids from a previous page lifecycle. We want\n // a clean in-memory transport on each fresh page load, but we can still\n // opportunistically reuse an active backend sandbox discovered at runtime to\n // avoid quota/plan-limit failures.\n const [initialSandboxId, initialSessionId] = useMemo(() => [null, null] as const, []);\n\n const sandboxIdRef = useRef<string | null>(initialSandboxId);\n const sessionIdRef = useRef<string | null>(initialSessionId);\n\n const persistSandboxId = useCallback((id: string | null) => {\n sandboxIdRef.current = id;\n if (id) {\n sessionStorage.setItem('bc-assistant-sandbox-id', id);\n } else {\n sessionStorage.removeItem('bc-assistant-sandbox-id');\n }\n }, []);\n\n const persistSessionId = useCallback((id: string | null) => {\n sessionIdRef.current = id;\n if (id) {\n sessionStorage.setItem('bc-assistant-session-id', id);\n } else {\n sessionStorage.removeItem('bc-assistant-session-id');\n }\n }, []);\n\n const ensureRuntime = useCallback(\n async (\n workspaceId: string,\n authContext: AssistantSandboxAuthContext\n ): Promise<{ sandboxId: string; sessionId: string }> => {\n let sandboxId = sandboxIdRef.current;\n console.log('[BigConsole-Assistant] ensureRuntime start', { sandboxId, workspaceId });\n if (!sandboxId) {\n if (!getAccessToken()) {\n throw new Error('The assistant requires an authenticated session. Please sign in again.');\n }\n console.log('[BigConsole-Assistant] findExistingSandbox called');\n sandboxId = await findExistingSandbox(workspaceId, MODE, authContext);\n console.log('[BigConsole-Assistant] findExistingSandbox result', { sandboxId });\n\n if (sandboxId) {\n try {\n console.log('[BigConsole-Assistant] waitForSandboxReady called (reused)', { sandboxId });\n await waitForSandboxReady(sandboxId, workspaceId, authContext);\n console.log('[BigConsole-Assistant] waitForSandboxReady done (reused)', { sandboxId });\n console.log('[BigConsole-Assistant] waitForAssistantServiceReady called (reused)', { sandboxId });\n await waitForAssistantServiceReady(sandboxId, workspaceId, MODE, authContext);\n console.log('[BigConsole-Assistant] waitForAssistantServiceReady done (reused)', { sandboxId });\n } catch (error) {\n console.warn('[BigConsole-Assistant] existing sandbox unusable, falling back to fresh sandbox', {\n sandboxId,\n error: error instanceof Error ? error.message : String(error),\n });\n sandboxId = null;\n }\n }\n\n if (!sandboxId) {\n console.log('[BigConsole-Assistant] createAssistantSandbox called');\n sandboxId = await createAssistantSandbox(MODE, workspaceId, authContext);\n console.log('[BigConsole-Assistant] createAssistantSandbox result', { sandboxId });\n console.log('[BigConsole-Assistant] waitForSandboxReady called (fresh)', { sandboxId });\n await waitForSandboxReady(sandboxId, workspaceId, authContext);\n console.log('[BigConsole-Assistant] waitForSandboxReady done (fresh)', { sandboxId });\n console.log('[BigConsole-Assistant] waitForAssistantServiceReady called (fresh)', { sandboxId });\n await waitForAssistantServiceReady(sandboxId, workspaceId, MODE, authContext);\n console.log('[BigConsole-Assistant] waitForAssistantServiceReady done (fresh)', { sandboxId });\n }\n\n persistSandboxId(sandboxId);\n }\n\n let sessionId = sessionIdRef.current;\n console.log('[BigConsole-Assistant] session check', { sessionId, sandboxId });\n if (!sessionId) {\n console.log('[BigConsole-Assistant] createAssistantSession called', { sandboxId, workspaceId });\n const result = await createAssistantSession(sandboxId, workspaceId, MODE, authContext);\n sessionId = result.sessionId;\n persistSessionId(sessionId);\n }\n\n return { sandboxId, sessionId };\n },\n [getAccessToken]\n );\n\n const sendPrompt = useCallback(\n async ({ prompt, onProgress, signal }: AssistantSendArgs): Promise<{ text: string }> => {\n const workspaceId = getWorkspaceId(ctxWorkspaceId);\n console.log('[BigConsole-Assistant] sendPrompt called', {\n promptLength: prompt.length,\n workspaceId,\n hasCtxWorkspaceId: !!ctxWorkspaceId,\n authContextKeys: {\n hasAccessToken: !!getAccessToken(),\n hasWorkspaceToken: !!getWorkspaceToken(),\n hasUserId: !!userId,\n },\n locationSearch: window.location.search,\n });\n if (!workspaceId) {\n throw new Error('The assistant needs an active workspace. Open a workspace and try again.');\n }\n const authContext: AssistantSandboxAuthContext = {\n accessToken: getAccessToken(),\n workspaceToken: getWorkspaceToken(),\n userId,\n organizationId: getOrganizationId(),\n };\n console.log('[BigConsole-Assistant] authContext prepared', {\n hasAccessToken: !!authContext.accessToken,\n hasWorkspaceToken: !!authContext.workspaceToken,\n hasUserId: !!authContext.userId,\n hasOrgId: !!authContext.organizationId,\n });\n\n const run = async (attempt: 1 | 2): Promise<{ text: string }> => {\n try {\n console.log('[BigConsole-Assistant] run attempt', attempt);\n const { sandboxId, sessionId } = await ensureRuntime(workspaceId, authContext);\n console.log('[BigConsole-Assistant] ensureRuntime resolved', { sandboxId, sessionId });\n\n const startedAt = Date.now();\n console.log('[BigConsole-Assistant] calling sendAssistantPromptAsync', {\n sandboxId,\n workspaceId,\n sessionId,\n promptLength: prompt.length,\n });\n await sendAssistantPromptAsync(\n sandboxId,\n workspaceId,\n sessionId,\n prompt,\n MODE,\n gatherPageContext(),\n authContext\n );\n\n const timeoutAt = Date.now() + STREAM_BUDGET_MS;\n let lastTtlExtensionAt = Date.now();\n let lastContent = '';\n let lastContentChangeAt = Date.now();\n let progress = buildProgress([], startedAt);\n\n while (Date.now() < timeoutAt) {\n if (signal.aborted) throw new Error('Cancelled');\n\n const messages = await getAssistantMessages(sandboxId, workspaceId, sessionId, authContext, 50);\n console.log('[BigConsole-Assistant] poll', {\n elapsedMs: Date.now() - startedAt,\n messageCount: messages.length,\n firstFewRoles: messages.slice(0, 3).map((m) => getMessageRole(m)),\n firstFewTimestamps: messages.slice(0, 3).map((m) => getRawMessageCreatedAt(m)),\n });\n progress = buildProgress(messages, startedAt, lastContent, lastContentChangeAt);\n console.log('[BigConsole-Assistant] progress', {\n contentPreview: progress.content.slice(0, 100),\n done: progress.done,\n lastContentChangeAt: Date.now() - lastContentChangeAt,\n });\n if (progress.content !== lastContent) {\n lastContent = progress.content;\n lastContentChangeAt = Date.now();\n }\n onProgress(sanitize(progress.content));\n if (progress.done) {\n console.log('[BigConsole-Assistant] progress.done=true, breaking poll loop');\n break;\n }\n\n if (Date.now() - lastTtlExtensionAt > TTL_EXTEND_INTERVAL_MS) {\n await extendAssistantSandboxTTL(sandboxId, workspaceId, 600, authContext).catch(() => undefined);\n lastTtlExtensionAt = Date.now();\n }\n\n await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));\n }\n\n if (!progress.done) {\n throw new Error('The assistant timed out while responding. Please try again.');\n }\n\n return { text: sanitize(progress.content) };\n } catch (error) {\n console.error('[BigConsole-Assistant] run error', {\n attempt,\n error: error instanceof Error ? error.message : String(error),\n stack: error instanceof Error ? error.stack : undefined,\n sandboxId: sandboxIdRef.current,\n sessionId: sessionIdRef.current,\n });\n // A stale/expired sandbox or session is recoverable — drop the warm\n // refs and retry once from a clean runtime.\n if (attempt === 1 && isRecoverable(error)) {\n persistSandboxId(null);\n persistSessionId(null);\n return run(2);\n }\n throw error;\n }\n };\n\n return run(1);\n },\n [ctxWorkspaceId, ensureRuntime, getAccessToken, getWorkspaceToken, userId, persistSandboxId, persistSessionId]\n );\n\n return useMemo<AssistantTransport>(() => ({ sendPrompt }), [sendPrompt]);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"createSandboxAssistantTransport.js","names":[],"sources":["../../../src/bigconsole/assistant/createSandboxAssistantTransport.ts"],"sourcesContent":["/**\n * BigConsole adapter for the shared fe-libs AssistantWidget.\n *\n * The floating widget (fe-libs, Layer 1) is backend-agnostic — it calls an\n * injected `AssistantTransport`. This hook builds a transport that drives the\n * sandbox AI assistant (combined `assistant` mode = docs Q&A + api-calls): it\n * provisions/reuses a sandbox, opens a session, dispatches the prompt async,\n * then polls for the streamed answer. The agent introspects the GraphQL schema\n * and performs API calls on the user's behalf using their workspace token,\n * contextual to the current screen (via `gatherPageContext`).\n *\n * This is a faithful port of microfe-vibecontrols'\n * `services/createSandboxAssistantTransport.ts`; the only product-specific\n * difference lives in `assistantApi.createAssistantSandbox`\n * (`AI_ASSISTANT_PRODUCT=bigconsole`).\n */\n\nimport { useCallback, useMemo, useRef } from 'react';\nimport { useAuthToken } from '@burdenoff/fe-libs/shared/providers/shell';\nimport {\n createAssistantSandbox,\n createAssistantSession,\n extendAssistantSandboxTTL,\n findExistingSandbox,\n getAssistantMessages,\n sendAssistantPromptAsync,\n waitForAssistantServiceReady,\n waitForSandboxReady,\n} from './assistantApi';\nimport { gatherPageContext } from './pageContext';\nimport type {\n AssistantMode,\n AssistantRawMessage,\n AssistantRawMessagePart,\n AssistantSandboxAuthContext,\n} from './types';\n\n/**\n * Locally-defined mirror of the fe-libs `AssistantTransport` contract.\n *\n * Intentionally NOT imported from `@burdenoff/fe-libs`: microfe's tsconfig maps\n * `@burdenoff/fe-libs/*` to fe-libs *source*, so vite-plugin-dts would rewrite a\n * cross-package type used in this hook's public signature to a broken\n * source-relative path in the emitted `.d.ts`. Structural typing makes this\n * shape assignable to fe-libs' `AssistantTransport` at the call site\n * (bigconsole-app's AppShell), which is where compatibility is enforced.\n */\ninterface AssistantSendArgs {\n prompt: string;\n onProgress: (partialText: string) => void;\n signal: AbortSignal;\n}\n\nexport interface AssistantTransport {\n sendPrompt: (args: AssistantSendArgs) => Promise<{ text: string }>;\n}\n\n// BigConsole still boots the manually-tagged ACA image\n// `alpha-delegated-auth-v11` for the assistant sandbox. The historical\n// platform notes show that this image line reliably supports `api-calls`, while\n// the combined `assistant` mode depends on newer image contracts that are not\n// yet guaranteed on this tag. Use `api-calls` here so the assistant can execute\n// workspace GraphQL operations end-to-end right now. Once the underlying image\n// line is rebuilt and verified for combined mode, this can be switched back.\nconst MODE: AssistantMode = 'api-calls';\nconst STREAM_BUDGET_MS = 180_000;\nconst POLL_INTERVAL_MS = 1500;\nconst TTL_EXTEND_INTERVAL_MS = 30_000;\n\n// ── Context helpers (mirror vibecontrols' resolution) ────────────────\n\nfunction getProfileContextValue(key: 'workspaceId' | 'organizationId'): string {\n try {\n const activeContextKey =\n key === 'workspaceId' ? 'burdenoff-active-context-workspace' : 'burdenoff-active-context-organization';\n const activeContextValue = localStorage.getItem(activeContextKey);\n if (activeContextValue) return activeContextValue;\n\n const activeProfileId = sessionStorage.getItem('bf-active-profile');\n if (!activeProfileId) return '';\n const raw = localStorage.getItem(`bf-p-${activeProfileId}-context`);\n if (!raw) return '';\n const context = JSON.parse(raw) as { workspaceId?: string; organizationId?: string };\n return context[key] ?? '';\n } catch {\n return '';\n }\n}\n\nfunction getWorkspaceId(fallback: string | null): string {\n const params = new URLSearchParams(window.location.search);\n return params.get('workspace') ?? getProfileContextValue('workspaceId') ?? fallback ?? '';\n}\n\nfunction getOrganizationId(): string {\n const params = new URLSearchParams(window.location.search);\n return params.get('org') ?? getProfileContextValue('organizationId');\n}\n\n// ── Message-progress helpers (pure; mirror vibecontrols) ─────────────\n\nfunction getMessageRole(message: AssistantRawMessage): string | undefined {\n // Check nested format first, then flat format\n return message.info?.role ?? message.role;\n}\n\nfunction getRawMessageCreatedAt(message: AssistantRawMessage): number {\n // Check nested format first (epoch ms), then flat format (ISO string or epoch ms)\n const nested = message.info?.time?.created;\n if (nested !== undefined) return nested;\n const flat = message.createdAt;\n if (flat === undefined) return 0;\n // If it's a string (ISO), parse it; otherwise treat as epoch ms\n if (typeof flat === 'string') {\n const parsed = Date.parse(flat);\n return isNaN(parsed) ? 0 : parsed;\n }\n return flat;\n}\n\nfunction getMessageCompleted(message: AssistantRawMessage): number | undefined {\n // Check nested format first, then flat format\n const nested = message.info?.time?.completed;\n if (nested !== undefined) return nested;\n const flat = message.completedAt;\n if (flat === undefined) return undefined;\n if (typeof flat === 'string') {\n const parsed = Date.parse(flat);\n return isNaN(parsed) ? undefined : parsed;\n }\n return flat;\n}\n\nfunction getAssistantText(message: AssistantRawMessage): string {\n // Check parts format first (nested), then flat content\n const parts = message.parts ?? [];\n const textFromParts = (parts ?? [])\n .filter((part) => part.type === 'text' && typeof part.text === 'string')\n .map((part) => part.text?.trim() ?? '')\n .filter(Boolean)\n .join('\\n');\n if (textFromParts) return textFromParts;\n // Fallback to flat content field\n return typeof message.content === 'string' ? message.content.trim() : '';\n}\n\n// Friendly, human-readable labels for the agent's tools so the progress line\n// reads like \"Searching the schema…\" instead of \"Running: bash\". The agent sets\n// a `description` on every bash call (e.g. \"Search for sales-related types in\n// workspace schema\") and a todo list on todowrite — surface those directly.\nconst TOOL_LABELS: Record<string, string> = {\n bash: 'Running a command',\n webfetch: 'Fetching a page',\n 'file.read': 'Reading files',\n 'file.write': 'Writing files',\n 'file.edit': 'Editing files',\n 'file.find.text': 'Searching the code',\n 'file.find.file': 'Looking for files',\n todowrite: 'Planning the steps',\n todoread: 'Reviewing the plan',\n};\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n return typeof value === 'object' && value !== null ? (value as Record<string, unknown>) : undefined;\n}\n\n/** Best-effort human summary of what a single tool part is doing right now. */\nfunction describeToolPart(part: AssistantRawMessagePart): string {\n const tool = part.tool ?? 'tool';\n const input = asRecord(part.state?.input);\n\n // bash carries a plain-English `description` of the step — the best signal.\n const description = input?.description;\n if (typeof description === 'string' && description.trim()) return description.trim();\n\n // todowrite carries the todo list — surface the item being worked on.\n const todos = input?.todos;\n if (Array.isArray(todos)) {\n const active = todos.find((todo) => asRecord(todo)?.status === 'in_progress') ?? todos[0];\n const content = asRecord(active)?.content;\n if (typeof content === 'string' && content.trim()) return content.trim();\n }\n\n return TOOL_LABELS[tool] ?? `Running ${tool}`;\n}\n\nfunction getToolProgress(message: AssistantRawMessage): string[] {\n const parts = message.parts ?? [];\n return parts\n .filter((part) => part.type === 'tool' && part.tool)\n .map((part) => {\n const status = part.state?.status ?? 'running';\n const label = describeToolPart(part);\n if (status === 'completed') return `✓ ${label}`;\n if (status === 'failed') return `⚠ ${label}`;\n return `⏳ ${label}…`;\n });\n}\n\nfunction buildProgress(\n messages: AssistantRawMessage[],\n sinceMs: number,\n previousContent?: string,\n previousContentAtMs?: number\n): { content: string; done: boolean } {\n const relevant = messages\n .filter((message) => getMessageRole(message) === 'assistant' && getRawMessageCreatedAt(message) >= sinceMs)\n .sort((left, right) => getRawMessageCreatedAt(left) - getRawMessageCreatedAt(right));\n\n // Debug: log message filtering when no relevant messages found\n if (relevant.length === 0 && messages.length > 0) {\n console.log('[BigConsole-Assistant] buildProgress: no relevant messages', {\n totalMessages: messages.length,\n sinceMs,\n messageRoles: messages.map((m) => getMessageRole(m)),\n messageTimestamps: messages.map((m) => getRawMessageCreatedAt(m)),\n });\n }\n\n let content: string;\n let done: boolean;\n\n if (relevant.length === 0) {\n content = 'Thinking…';\n // Staleness fallback: if no messages have appeared after 15+ seconds of polling,\n // treat the response as complete even when messages get filtered out\n // (e.g., due to timestamp skew or role mismatch).\n done =\n previousContent === content && previousContentAtMs !== undefined && Date.now() - previousContentAtMs >= 15_000;\n } else {\n const latest = relevant[relevant.length - 1]!;\n const text = getAssistantText(latest);\n const toolProgress = getToolProgress(latest);\n content = [text, ...toolProgress].filter(Boolean).join('\\n\\n') || 'Thinking…';\n\n const officiallyDone = Boolean(getMessageCompleted(latest)) && (Boolean(text) || toolProgress.length > 0);\n\n // Staleness fallback: if content hasn't changed in 15 s, treat the build as\n // complete even when the assistant forgot to set `completed`.\n const staleDone =\n !officiallyDone &&\n previousContent === content &&\n previousContentAtMs !== undefined &&\n Date.now() - previousContentAtMs >= 15_000;\n\n done = officiallyDone || staleDone;\n }\n\n return { content, done };\n}\n\nfunction sanitize(response: string): string {\n return response\n .replace(/(Authorization\\s*:\\s*Bearer\\s+)[^\\s\\n]+/gi, '$1[REDACTED]')\n .replace(/(X-Workspace-Authorization\\s*:\\s*Bearer\\s+)[^\\s\\n]+/gi, '$1[REDACTED]')\n .replace(/\\beyJ[A-Za-z0-9_-]+\\.[A-Za-z0-9._-]+\\.[A-Za-z0-9._-]+\\b/g, '[REDACTED_JWT]')\n .replace(/\\bsk-ant-[A-Za-z0-9-]+\\b/g, '[REDACTED_API_KEY]');\n}\n\nfunction isRecoverable(error: unknown): boolean {\n const message = error instanceof Error ? error.message.toLowerCase() : String(error).toLowerCase();\n if (\n message.includes('rate limit exceeded') ||\n message.includes('unauthorized') ||\n message.includes('k8s api error 401')\n ) {\n return false;\n }\n return [\n 'sandbox not found',\n 'sandbox is not running',\n 'sandbox service not available yet',\n 'sandbox failed',\n 'sandbox startup timed out',\n 'assistant service did not become healthy',\n 'proxy error: 404',\n 'proxy error: 502',\n 'proxy error: 503',\n 'unable to connect',\n 'image pull',\n 'container failed',\n 'bootstrap failed',\n // Transient network errors from the browser fetch — gateway CORS preflight\n // failures, mid-stream resets, and Cloudflare 524s all surface as\n // \"Failed to fetch\" via TypeError. They're worth retrying on a clean\n // runtime since the underlying sandbox state is unaffected.\n 'failed to fetch',\n 'cf-proxy timeout',\n // Subgraph returned 500 with a generic message — gateway returns this as\n // a GraphQL error rather than an HTTP error. The actual underlying cause\n // (e.g., transient Prisma timeout) is recoverable, but a fresh sandbox\n // may be needed.\n 'unexpected error',\n ].some((fragment) => message.includes(fragment));\n}\n\n/**\n * Returns a memoized `AssistantTransport` wired to the BigConsole sandbox\n * assistant agent. The sandbox + session are cached in refs so follow-up turns\n * reuse the warm environment for the lifetime of the host shell.\n */\nexport function useSandboxAssistantTransport(): AssistantTransport {\n const { getAccessToken, getWorkspaceToken, userId, workspaceId: ctxWorkspaceId } = useAuthToken();\n\n // Do not hydrate sandbox/session ids from a previous page lifecycle. We want\n // a clean in-memory transport on each fresh page load, but we can still\n // opportunistically reuse an active backend sandbox discovered at runtime to\n // avoid quota/plan-limit failures.\n const [initialSandboxId, initialSessionId] = useMemo(() => [null, null] as const, []);\n\n const sandboxIdRef = useRef<string | null>(initialSandboxId);\n const sessionIdRef = useRef<string | null>(initialSessionId);\n\n const persistSandboxId = useCallback((id: string | null) => {\n sandboxIdRef.current = id;\n if (id) {\n sessionStorage.setItem('bc-assistant-sandbox-id', id);\n } else {\n sessionStorage.removeItem('bc-assistant-sandbox-id');\n }\n }, []);\n\n const persistSessionId = useCallback((id: string | null) => {\n sessionIdRef.current = id;\n if (id) {\n sessionStorage.setItem('bc-assistant-session-id', id);\n } else {\n sessionStorage.removeItem('bc-assistant-session-id');\n }\n }, []);\n\n const ensureRuntime = useCallback(\n async (\n workspaceId: string,\n authContext: AssistantSandboxAuthContext\n ): Promise<{ sandboxId: string; sessionId: string }> => {\n let sandboxId = sandboxIdRef.current;\n console.log('[BigConsole-Assistant] ensureRuntime start', { sandboxId, workspaceId });\n if (!sandboxId) {\n if (!getAccessToken()) {\n throw new Error('The assistant requires an authenticated session. Please sign in again.');\n }\n console.log('[BigConsole-Assistant] findExistingSandbox called');\n sandboxId = await findExistingSandbox(workspaceId, MODE, authContext);\n console.log('[BigConsole-Assistant] findExistingSandbox result', { sandboxId });\n\n if (sandboxId) {\n try {\n console.log('[BigConsole-Assistant] waitForSandboxReady called (reused)', { sandboxId });\n await waitForSandboxReady(sandboxId, workspaceId, authContext);\n console.log('[BigConsole-Assistant] waitForSandboxReady done (reused)', { sandboxId });\n console.log('[BigConsole-Assistant] waitForAssistantServiceReady called (reused)', { sandboxId });\n await waitForAssistantServiceReady(sandboxId, workspaceId, MODE, authContext);\n console.log('[BigConsole-Assistant] waitForAssistantServiceReady done (reused)', { sandboxId });\n } catch (error) {\n console.warn('[BigConsole-Assistant] existing sandbox unusable, falling back to fresh sandbox', {\n sandboxId,\n error: error instanceof Error ? error.message : String(error),\n });\n sandboxId = null;\n }\n }\n\n if (!sandboxId) {\n console.log('[BigConsole-Assistant] createAssistantSandbox called');\n sandboxId = await createAssistantSandbox(MODE, workspaceId, authContext);\n console.log('[BigConsole-Assistant] createAssistantSandbox result', { sandboxId });\n console.log('[BigConsole-Assistant] waitForSandboxReady called (fresh)', { sandboxId });\n await waitForSandboxReady(sandboxId, workspaceId, authContext);\n console.log('[BigConsole-Assistant] waitForSandboxReady done (fresh)', { sandboxId });\n console.log('[BigConsole-Assistant] waitForAssistantServiceReady called (fresh)', { sandboxId });\n await waitForAssistantServiceReady(sandboxId, workspaceId, MODE, authContext);\n console.log('[BigConsole-Assistant] waitForAssistantServiceReady done (fresh)', { sandboxId });\n }\n\n persistSandboxId(sandboxId);\n }\n\n let sessionId = sessionIdRef.current;\n console.log('[BigConsole-Assistant] session check', { sessionId, sandboxId });\n if (!sessionId) {\n console.log('[BigConsole-Assistant] createAssistantSession called', { sandboxId, workspaceId });\n const result = await createAssistantSession(sandboxId, workspaceId, MODE, authContext);\n sessionId = result.sessionId;\n persistSessionId(sessionId);\n }\n\n return { sandboxId, sessionId };\n },\n [getAccessToken]\n );\n\n const sendPrompt = useCallback(\n async ({ prompt, onProgress, signal }: AssistantSendArgs): Promise<{ text: string }> => {\n const workspaceId = getWorkspaceId(ctxWorkspaceId);\n console.log('[BigConsole-Assistant] sendPrompt called', {\n promptLength: prompt.length,\n workspaceId,\n hasCtxWorkspaceId: !!ctxWorkspaceId,\n authContextKeys: {\n hasAccessToken: !!getAccessToken(),\n hasWorkspaceToken: !!getWorkspaceToken(),\n hasUserId: !!userId,\n },\n locationSearch: window.location.search,\n });\n if (!workspaceId) {\n throw new Error('The assistant needs an active workspace. Open a workspace and try again.');\n }\n const authContext: AssistantSandboxAuthContext = {\n accessToken: getAccessToken(),\n workspaceToken: getWorkspaceToken(),\n userId,\n organizationId: getOrganizationId(),\n };\n console.log('[BigConsole-Assistant] authContext prepared', {\n hasAccessToken: !!authContext.accessToken,\n hasWorkspaceToken: !!authContext.workspaceToken,\n hasUserId: !!authContext.userId,\n hasOrgId: !!authContext.organizationId,\n });\n\n const run = async (attempt: 1 | 2): Promise<{ text: string }> => {\n try {\n console.log('[BigConsole-Assistant] run attempt', attempt);\n const { sandboxId, sessionId } = await ensureRuntime(workspaceId, authContext);\n console.log('[BigConsole-Assistant] ensureRuntime resolved', { sandboxId, sessionId });\n\n const startedAt = Date.now();\n console.log('[BigConsole-Assistant] calling sendAssistantPromptAsync', {\n sandboxId,\n workspaceId,\n sessionId,\n promptLength: prompt.length,\n });\n await sendAssistantPromptAsync(\n sandboxId,\n workspaceId,\n sessionId,\n prompt,\n MODE,\n gatherPageContext(),\n authContext\n );\n\n const timeoutAt = Date.now() + STREAM_BUDGET_MS;\n let lastTtlExtensionAt = Date.now();\n let lastContent = '';\n let lastContentChangeAt = Date.now();\n let progress = buildProgress([], startedAt);\n\n while (Date.now() < timeoutAt) {\n if (signal.aborted) throw new Error('Cancelled');\n\n const messages = await getAssistantMessages(sandboxId, workspaceId, sessionId, authContext, 50);\n console.log('[BigConsole-Assistant] poll', {\n elapsedMs: Date.now() - startedAt,\n messageCount: messages.length,\n firstFewRoles: messages.slice(0, 3).map((m) => getMessageRole(m)),\n firstFewTimestamps: messages.slice(0, 3).map((m) => getRawMessageCreatedAt(m)),\n });\n progress = buildProgress(messages, startedAt, lastContent, lastContentChangeAt);\n console.log('[BigConsole-Assistant] progress', {\n contentPreview: progress.content.slice(0, 100),\n done: progress.done,\n lastContentChangeAt: Date.now() - lastContentChangeAt,\n });\n if (progress.content !== lastContent) {\n lastContent = progress.content;\n lastContentChangeAt = Date.now();\n }\n onProgress(sanitize(progress.content));\n if (progress.done) {\n console.log('[BigConsole-Assistant] progress.done=true, breaking poll loop');\n break;\n }\n\n if (Date.now() - lastTtlExtensionAt > TTL_EXTEND_INTERVAL_MS) {\n await extendAssistantSandboxTTL(sandboxId, workspaceId, 600, authContext).catch(() => undefined);\n lastTtlExtensionAt = Date.now();\n }\n\n await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));\n }\n\n if (!progress.done) {\n throw new Error('The assistant timed out while responding. Please try again.');\n }\n\n return { text: sanitize(progress.content) };\n } catch (error) {\n console.error('[BigConsole-Assistant] run error', {\n attempt,\n error: error instanceof Error ? error.message : String(error),\n stack: error instanceof Error ? error.stack : undefined,\n sandboxId: sandboxIdRef.current,\n sessionId: sessionIdRef.current,\n });\n // A stale/expired sandbox or session is recoverable — drop the warm\n // refs and retry once from a clean runtime.\n if (attempt === 1 && isRecoverable(error)) {\n persistSandboxId(null);\n persistSessionId(null);\n return run(2);\n }\n throw error;\n }\n };\n\n return run(1);\n },\n [ctxWorkspaceId, ensureRuntime, getAccessToken, getWorkspaceToken, userId, persistSandboxId, persistSessionId]\n );\n\n return useMemo<AssistantTransport>(() => ({ sendPrompt }), [sendPrompt]);\n}\n"],"mappings":"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"}
@@ -26,17 +26,17 @@ import { calculatePositionFromDrop as ce, findNextAvailablePosition as le } from
26
26
  import { memo as u, useCallback as d, useEffect as ue, useMemo as de, useRef as f, useState as p } from "react";
27
27
  import { jsx as m, jsxs as h } from "react/jsx-runtime";
28
28
  //#region src/bigconsole/components/dashboard/DashboardCanvas.tsx
29
- var g = u(function({ dashboardId: u, pageId: g, title: _, onPaste: fe, onSave: pe, isSaving: me = !1, onExport: he, pages: v = [], activePageId: y, onPageChange: ge, onPagesReorder: b, onPageAdd: x, onPageRename: _e, onPageDuplicate: ve, onPageDelete: ye, showFilters: be = !0, showPageTabs: xe = !0, enableCrossFilter: Se = !0 }) {
30
- let S = f(null), C = f(null), [w, Ce] = p(1200), [we, T] = p(!1), [Te, E] = p(!1), [D, O] = p(!1), [k, A] = p(!1), [Ee, j] = p(null), [M, N] = p(null), [P, F] = p(null), [I, L] = p(null), R = t((e) => e.viewMode === "edit"), { workspaceId: z, apiGatewayUrl: B, authToken: V } = r(), { installedWidgets: H, loading: De } = c({
31
- workspaceId: z,
32
- apiGatewayUrl: B,
33
- authToken: V,
34
- enabled: R
35
- }), { definitions: Oe } = a({
36
- workspaceId: z,
37
- apiGatewayUrl: B,
38
- authToken: V,
39
- enabled: R
29
+ var g = u(function({ dashboardId: u, pageId: g, title: _, onPaste: fe, onSave: pe, isSaving: me = !1, onExport: he, pages: v = [], activePageId: ge, onPageChange: _e, onPagesReorder: y, onPageAdd: b, onPageRename: ve, onPageDuplicate: ye, onPageDelete: be, showFilters: xe = !0, showPageTabs: Se = !0, enableCrossFilter: Ce = !0 }) {
30
+ let x = f(null), S = f(null), [C, we] = p(1200), [Te, w] = p(!1), [Ee, T] = p(!1), [E, D] = p(!1), [O, k] = p(!1), [De, A] = p(null), [j, M] = p(null), [N, P] = p(null), [F, I] = p(null), L = t((e) => e.viewMode === "edit"), { workspaceId: R, apiGatewayUrl: z, authToken: B } = r(), { installedWidgets: V, loading: Oe } = c({
31
+ workspaceId: R,
32
+ apiGatewayUrl: z,
33
+ authToken: B,
34
+ enabled: L
35
+ }), { definitions: H } = a({
36
+ workspaceId: R,
37
+ apiGatewayUrl: z,
38
+ authToken: B,
39
+ enabled: L
40
40
  }), U = t((e) => e.zoomLevel), W = t((e) => e.setGlobalFilterValues), ke = d((e) => {
41
41
  W(e);
42
42
  }, [W]), { createWidget: G } = o(g, u, { skipFetch: !0 }), K = e((e) => e.widgets), q = de(() => {
@@ -45,7 +45,7 @@ var g = u(function({ dashboardId: u, pageId: g, title: _, onPaste: fe, onSave: p
45
45
  }, [K, g]), Ae = e((e) => e.selectedWidgetId), J = e((e) => e.selectWidget), Y = e((e) => e.addWidget), X = e((e) => e.updateWidgetPosition), je = e((e) => e.configPanelOpen), Me = e((e) => e.closeConfigPanel);
46
46
  ue(() => {
47
47
  let e = () => {
48
- S.current && Ce(S.current.offsetWidth);
48
+ x.current && we(x.current.offsetWidth);
49
49
  };
50
50
  return e(), window.addEventListener("resize", e), () => window.removeEventListener("resize", e);
51
51
  }, []);
@@ -61,11 +61,11 @@ var g = u(function({ dashboardId: u, pageId: g, title: _, onPaste: fe, onSave: p
61
61
  }, [X]), Pe = d((e) => {
62
62
  J(e);
63
63
  }, [J]), Z = d(async (e) => {
64
- let t = I || (e.type ? i(e.type) : null), n = {
64
+ let t = F || (e.type ? i(e.type) : null), n = {
65
65
  width: t?.defaultSize?.width ?? 4,
66
66
  height: t?.defaultSize?.height ?? 4
67
67
  }, r;
68
- if (M) r = M;
68
+ if (j) r = j;
69
69
  else {
70
70
  let { x: e, y: t } = le(q, n, { cols: 12 });
71
71
  r = {
@@ -92,7 +92,7 @@ var g = u(function({ dashboardId: u, pageId: g, title: _, onPaste: fe, onSave: p
92
92
  parserId: a.parserId
93
93
  });
94
94
  if (t) {
95
- J(t.id), T(!1), N(null), F(null), L(null);
95
+ J(t.id), w(!1), M(null), P(null), I(null);
96
96
  return;
97
97
  }
98
98
  }
@@ -118,7 +118,7 @@ var g = u(function({ dashboardId: u, pageId: g, title: _, onPaste: fe, onSave: p
118
118
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
119
119
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
120
120
  };
121
- Y(o), J(o.id), T(!1), N(null), F(null), L(null);
121
+ Y(o), J(o.id), w(!1), M(null), P(null), I(null);
122
122
  }, [
123
123
  u,
124
124
  g,
@@ -126,14 +126,14 @@ var g = u(function({ dashboardId: u, pageId: g, title: _, onPaste: fe, onSave: p
126
126
  Y,
127
127
  J,
128
128
  q,
129
- M,
130
- I
129
+ j,
130
+ F
131
131
  ]), Fe = d((e) => {
132
- A(!0), j(e);
132
+ k(!0), A(e);
133
133
  }, []), Ie = d(() => {
134
- A(!1), j(null);
134
+ k(!1), A(null);
135
135
  }, []), Le = d((e) => {
136
- e.preventDefault(), A(!1), j(null);
136
+ e.preventDefault(), k(!1), A(null);
137
137
  try {
138
138
  let t = e.dataTransfer.getData("application/json");
139
139
  if (!t) return;
@@ -145,22 +145,22 @@ var g = u(function({ dashboardId: u, pageId: g, title: _, onPaste: fe, onSave: p
145
145
  defaultConfig: n.defaultConfig,
146
146
  defaultSize: n.defaultSize || r.defaultSize
147
147
  });
148
- let o = S.current?.getBoundingClientRect();
148
+ let o = x.current?.getBoundingClientRect();
149
149
  if (!o) return;
150
150
  let s = {
151
151
  width: r.defaultSize.width,
152
152
  height: r.defaultSize.height
153
- }, { x: c, y: l } = ce(e.clientX, e.clientY, o, w, s, { cols: 12 });
154
- N({
153
+ }, { x: c, y: l } = ce(e.clientX, e.clientY, o, C, s, { cols: 12 });
154
+ M({
155
155
  x: c,
156
156
  y: l,
157
157
  width: s.width,
158
158
  height: s.height
159
- }), F(n.type), L(a), T(!0);
159
+ }), P(n.type), I(a), w(!0);
160
160
  } catch (e) {
161
161
  console.error("Failed to handle widget drop:", e);
162
162
  }
163
- }, [w]), Re = d((e) => {
163
+ }, [C]), Re = d((e) => {
164
164
  e.preventDefault(), e.dataTransfer.dropEffect = "copy";
165
165
  }, []), ze = d((e, t) => {
166
166
  let n = t || i(e);
@@ -168,11 +168,11 @@ var g = u(function({ dashboardId: u, pageId: g, title: _, onPaste: fe, onSave: p
168
168
  type: e,
169
169
  title: n.name,
170
170
  config: n.defaultConfig
171
- }), O(!1);
171
+ }), D(!1);
172
172
  }, [Z]), Be = d(() => {
173
- O((e) => !e);
173
+ D((e) => !e);
174
174
  }, []), { exportPNG: Q, exportPDF: $, isExporting: Ve } = s({
175
- containerRef: C,
175
+ containerRef: S,
176
176
  name: _ || "dashboard"
177
177
  });
178
178
  return /* @__PURE__ */ h("div", {
@@ -181,9 +181,9 @@ var g = u(function({ dashboardId: u, pageId: g, title: _, onPaste: fe, onSave: p
181
181
  /* @__PURE__ */ m(ee, {
182
182
  dashboardId: u,
183
183
  title: _,
184
- onAddWidget: () => T(!0),
184
+ onAddWidget: () => w(!0),
185
185
  onTogglePalette: Be,
186
- isPaletteOpen: D,
186
+ isPaletteOpen: E,
187
187
  onPaste: fe,
188
188
  onSave: pe,
189
189
  isSaving: me,
@@ -195,56 +195,56 @@ var g = u(function({ dashboardId: u, pageId: g, title: _, onPaste: fe, onSave: p
195
195
  $();
196
196
  }, [$]),
197
197
  isExportingImage: Ve,
198
- onShare: () => E(!0)
198
+ onShare: () => T(!0)
199
199
  }),
200
200
  /* @__PURE__ */ m(ne, {
201
201
  widgets: q,
202
- isEditMode: R
202
+ isEditMode: L
203
203
  }),
204
- be && /* @__PURE__ */ m(te, {
204
+ xe && /* @__PURE__ */ m(te, {
205
205
  dashboardId: u,
206
206
  onFilterChange: ke,
207
207
  collapsible: !0
208
208
  }),
209
- xe && (R || v.length > 0) && /* @__PURE__ */ m(re, {
209
+ Se && (L || v.length > 0) && /* @__PURE__ */ m(re, {
210
210
  pages: v,
211
- activePageId: y || v[0]?.id,
212
- editable: R,
213
- onPageSelect: ge || (() => {}),
214
- onPagesReorder: b ? (e) => {
215
- b(e.map((e) => v.find((t) => t.id === e)).filter(Boolean));
211
+ activePageId: ge || v[0]?.id,
212
+ editable: L,
213
+ onPageSelect: _e || (() => {}),
214
+ onPagesReorder: y ? (e) => {
215
+ y(e.map((e) => v.find((t) => t.id === e)).filter(Boolean));
216
216
  } : void 0,
217
- onPageCreate: x,
218
- onPageRename: _e,
219
- onPageDuplicate: ve,
220
- onPageDelete: ye
217
+ onPageCreate: b,
218
+ onPageRename: ve,
219
+ onPageDuplicate: ye,
220
+ onPageDelete: be
221
221
  }),
222
222
  /* @__PURE__ */ h("div", {
223
223
  className: "flex flex-1 min-w-0 overflow-hidden",
224
- children: [R && /* @__PURE__ */ m(ae, {
225
- isOpen: D,
226
- onClose: () => O(!1),
224
+ children: [L && /* @__PURE__ */ m(ae, {
225
+ isOpen: E,
226
+ onClose: () => D(!1),
227
227
  onWidgetSelect: ze,
228
228
  onDragStart: Fe,
229
229
  onDragEnd: Ie,
230
- installedWidgets: H,
231
- installedWidgetsLoading: De,
232
- definitions: Oe
230
+ installedWidgets: V,
231
+ installedWidgetsLoading: Oe,
232
+ definitions: H
233
233
  }), /* @__PURE__ */ h("div", {
234
- ref: S,
234
+ ref: x,
235
235
  className: "flex-1 min-w-0 overflow-auto bg-bg-sunken",
236
236
  onDrop: Le,
237
237
  onDragOver: Re,
238
238
  onClick: () => {
239
- R && J(null);
239
+ L && J(null);
240
240
  },
241
241
  style: {
242
242
  position: "relative",
243
- border: k ? "2px dashed var(--color-action-primary-bg)" : "none",
244
- backgroundColor: k ? "var(--color-bg-hover)" : void 0,
243
+ border: O ? "2px dashed var(--color-action-primary-bg)" : "none",
244
+ backgroundColor: O ? "var(--color-bg-hover)" : void 0,
245
245
  transition: "border-color 0.2s, background-color 0.2s"
246
246
  },
247
- children: [k && /* @__PURE__ */ m("div", {
247
+ children: [O && /* @__PURE__ */ m("div", {
248
248
  style: {
249
249
  position: "absolute",
250
250
  top: "50%",
@@ -266,24 +266,24 @@ var g = u(function({ dashboardId: u, pageId: g, title: _, onPaste: fe, onSave: p
266
266
  },
267
267
  children: [
268
268
  "Drop to add ",
269
- /* @__PURE__ */ m("strong", { children: Ee }),
269
+ /* @__PURE__ */ m("strong", { children: De }),
270
270
  " widget"
271
271
  ]
272
272
  })
273
273
  }), /* @__PURE__ */ m("div", {
274
- ref: C,
274
+ ref: S,
275
275
  className: "min-h-full origin-top-left transition-transform",
276
276
  style: {
277
277
  transform: `scale(${U / 100})`,
278
278
  width: `${100 / (U / 100)}%`
279
279
  },
280
280
  children: q.length > 0 ? /* @__PURE__ */ m(n, {
281
- enabled: Se,
281
+ enabled: Ce,
282
282
  onCrossFilter: (e) => {},
283
283
  children: /* @__PURE__ */ m(l, {
284
284
  widgets: q,
285
- isEditMode: R,
286
- width: w,
285
+ isEditMode: L,
286
+ width: C,
287
287
  onLayoutChange: Ne,
288
288
  onWidgetSelect: Pe,
289
289
  selectedWidgetId: Ae
@@ -314,9 +314,9 @@ var g = u(function({ dashboardId: u, pageId: g, title: _, onPaste: fe, onSave: p
314
314
  className: "text-sm text-text-secondary mb-4 text-center max-w-[300px]",
315
315
  children: "Add widgets to build your dashboard. Click the \"Add Widget\" button to get started."
316
316
  }),
317
- R && /* @__PURE__ */ h("button", {
317
+ L && /* @__PURE__ */ h("button", {
318
318
  type: "button",
319
- onClick: () => T(!0),
319
+ onClick: () => w(!0),
320
320
  className: "\n inline-flex items-center gap-2\n px-4 py-2\n text-sm font-medium\n text-action-primary-fg\n bg-action-primary-bg\n hover:bg-action-primary-bgHover\n rounded-md\n transition-colors\n ",
321
321
  children: [/* @__PURE__ */ m("svg", {
322
322
  className: "w-4 h-4",
@@ -341,21 +341,22 @@ var g = u(function({ dashboardId: u, pageId: g, title: _, onPaste: fe, onSave: p
341
341
  onClose: Me
342
342
  }),
343
343
  /* @__PURE__ */ m(oe, {
344
- isOpen: we,
344
+ isOpen: Te,
345
345
  onClose: () => {
346
- T(!1), N(null), F(null), L(null);
346
+ w(!1), M(null), P(null), I(null);
347
347
  },
348
348
  onSave: Z,
349
- preselectedType: P || void 0,
350
- preselectedDefinition: I || void 0,
349
+ preselectedType: N || void 0,
350
+ preselectedDefinition: F || void 0,
351
351
  dashboardId: u,
352
- installedWidgets: H
352
+ installedWidgets: V,
353
+ definitions: H
353
354
  }),
354
355
  /* @__PURE__ */ m(ie, {
355
356
  dashboardId: u,
356
357
  dashboardName: _ || "Dashboard",
357
- isOpen: Te,
358
- onClose: () => E(!1)
358
+ isOpen: Ee,
359
+ onClose: () => T(!1)
359
360
  })
360
361
  ]
361
362
  });