@burdenoff/microfe-timecampus 2026.710.2 → 2026.713.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,11 @@
1
1
  /**
2
- * TimeCampus adapter for the shared fe-libs AssistantWidget.
2
+ * timecampus adapter for the shared fe-libs AssistantWidget transport.
3
3
  *
4
- * Reuses the sandbox `api-calls` agent so the widget can run operations on the
5
- * current screen via API on the user's behalf.
4
+ * The sandbox lifecycle + poll/stream loop now lives in
5
+ * `@burdenoff/fe-libs/shared/assistant` (one implementation for all products);
6
+ * this is a thin wrapper. The exported name/shape are unchanged so app-shell
7
+ * imports don't move. The public return type is a LOCALLY-declared structural
8
+ * mirror — never re-export fe-libs types (vite-plugin-dts path rewriting).
6
9
  */
7
10
  interface AssistantSendArgs {
8
11
  prompt: string;
@@ -13,6 +16,8 @@ export interface AssistantTransport {
13
16
  sendPrompt: (args: AssistantSendArgs) => Promise<{
14
17
  text: string;
15
18
  }>;
19
+ prewarm?: (level?: 'probe' | 'full') => void;
20
+ suspend?: () => void;
16
21
  }
17
22
  export declare function useSandboxAssistantTransport(): AssistantTransport;
18
23
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"createSandboxAssistantTransport.d.ts","sourceRoot":"","sources":["../../src/services/createSandboxAssistantTransport.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAoBH,UAAU,iBAAiB;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,MAAM,EAAE,WAAW,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,CAAC,IAAI,EAAE,iBAAiB,KAAK,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACpE;AAsID,wBAAgB,4BAA4B,IAAI,kBAAkB,CA6JjE"}
1
+ {"version":3,"file":"createSandboxAssistantTransport.d.ts","sourceRoot":"","sources":["../../src/services/createSandboxAssistantTransport.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,UAAU,iBAAiB;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,MAAM,EAAE,WAAW,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,CAAC,IAAI,EAAE,iBAAiB,KAAK,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACnE,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,KAAK,IAAI,CAAC;IAC7C,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,wBAAgB,4BAA4B,IAAI,kBAAkB,CAMjE"}
@@ -1,120 +1,12 @@
1
- import { createAssistantSandbox as e, createAssistantSession as t, extendAssistantSandboxTTL as n, findExistingSandbox as r, getAssistantMessages as i, sendAssistantPromptAsync as a, waitForAssistantServiceReady as o, waitForSandboxReady as s } from "./assistantApi.js";
2
- import { gatherPageContext as c } from "../utils/pageContext.js";
3
- import { useCallback as l, useMemo as u, useRef as d } from "react";
4
- import { useGatewayClient as f } from "@burdenoff/fe-libs/shared/graphql";
5
- import { useAuthToken as p } from "@burdenoff/fe-libs/shared/providers/shell";
1
+ import { useSandboxAssistantTransport as e } from "@burdenoff/fe-libs/shared/assistant";
6
2
  //#region src/services/createSandboxAssistantTransport.ts
7
- var m = "assistant", h = 18e4, g = 1500, _ = 3e4;
8
- function v(e) {
9
- try {
10
- let t = e === "workspaceId" ? "burdenoff-active-context-workspace" : "burdenoff-active-context-organization", n = localStorage.getItem(t);
11
- if (n) return n;
12
- let r = sessionStorage.getItem("bf-active-profile");
13
- if (!r) return "";
14
- let i = localStorage.getItem(`bf-p-${r}-context`);
15
- return i ? JSON.parse(i)[e] ?? "" : "";
16
- } catch {
17
- return "";
18
- }
19
- }
20
- function y() {
21
- return new URLSearchParams(window.location.search).get("workspace") ?? v("workspaceId");
22
- }
23
- function b() {
24
- return new URLSearchParams(window.location.search).get("org") ?? v("organizationId");
25
- }
26
- function x(e) {
27
- return e.info?.time?.created ?? 0;
28
- }
29
- function S(e) {
30
- return (e ?? []).filter((e) => e.type === "text" && typeof e.text == "string").map((e) => e.text?.trim() ?? "").filter(Boolean).join("\n");
31
- }
32
- function C(e) {
33
- return (e ?? []).filter((e) => e.type === "tool" && e.tool).map((e) => {
34
- let t = e.state?.status ?? "running", n = e.tool ?? "tool";
35
- return t === "completed" ? `Completed: ${n}` : t === "failed" ? `Failed: ${n}` : `Running: ${n}`;
3
+ function t() {
4
+ return e({
5
+ product: "timecampus",
6
+ enableCredits: !0
36
7
  });
37
8
  }
38
- function w(e, t) {
39
- let n = e.filter((e) => e.info?.role === "assistant" && x(e) >= t).sort((e, t) => x(e) - x(t));
40
- if (n.length === 0) return {
41
- content: "Thinking…",
42
- done: !1
43
- };
44
- let r = n[n.length - 1], i = S(r.parts), a = C(r.parts);
45
- return {
46
- content: [i, ...a].filter(Boolean).join("\n\n") || "Thinking…",
47
- done: !!r.info?.time?.completed && (!!i || a.length > 0)
48
- };
49
- }
50
- function T(e) {
51
- 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]");
52
- }
53
- function E(e) {
54
- let t = e instanceof Error ? e.message.toLowerCase() : String(e).toLowerCase();
55
- return t.includes("rate limit exceeded") || t.includes("unauthorized") || t.includes("k8s api error 401") ? !1 : [
56
- "sandbox not found",
57
- "sandbox is not running",
58
- "sandbox service not available yet",
59
- "sandbox failed",
60
- "sandbox startup timed out",
61
- "assistant service did not become healthy",
62
- "proxy error: 404",
63
- "proxy error: 502",
64
- "proxy error: 503"
65
- ].some((e) => t.includes(e));
66
- }
67
- function D() {
68
- let v = f("workspace"), { getAccessToken: x, getWorkspaceToken: S, userId: C } = p(), D = d(null), O = d(null), k = l(async (n, i) => {
69
- let a = D.current;
70
- if (!a) {
71
- if (a = await r(v, n, m, i), !a) {
72
- if (!x()) throw Error("API Calls mode requires an authenticated session. Please sign in again.");
73
- a = await e(v, m, n, i);
74
- }
75
- await s(v, a, n, i), await o(v, a, n, i), D.current = a;
76
- }
77
- let c = O.current;
78
- return c || (c = (await t(v, a, n, m, i)).sessionId, O.current = c), {
79
- sandboxId: a,
80
- sessionId: c
81
- };
82
- }, [v, x]), A = l(async ({ prompt: e, onProgress: t, signal: r }) => {
83
- let o = y();
84
- if (!o) throw Error("The assistant needs an active workspace. Open a workspace and try again.");
85
- let s = {
86
- accessToken: x(),
87
- workspaceToken: S(),
88
- userId: C,
89
- organizationId: b()
90
- }, l = async (u) => {
91
- try {
92
- let { sandboxId: l, sessionId: u } = await k(o, s), d = Date.now();
93
- await a(v, l, o, u, e, m, c(), s);
94
- let f = Date.now() + h, p = Date.now(), y = w([], d);
95
- for (; Date.now() < f;) {
96
- if (r.aborted) throw Error("Cancelled");
97
- if (y = w(await i(v, l, o, u, s, 50), d), t(T(y.content)), y.done) break;
98
- Date.now() - p > _ && (await n(v, l, o, 600, s).catch(() => void 0), p = Date.now()), await new Promise((e) => setTimeout(e, g));
99
- }
100
- if (!y.done) throw Error("The assistant timed out while responding. Please try again.");
101
- return { text: T(y.content) };
102
- } catch (e) {
103
- if (u === 1 && E(e)) return D.current = null, O.current = null, l(2);
104
- throw e;
105
- }
106
- };
107
- return l(1);
108
- }, [
109
- v,
110
- k,
111
- x,
112
- S,
113
- C
114
- ]);
115
- return u(() => ({ sendPrompt: A }), [A]);
116
- }
117
9
  //#endregion
118
- export { D as useSandboxAssistantTransport };
10
+ export { t as useSandboxAssistantTransport };
119
11
 
120
12
  //# sourceMappingURL=createSandboxAssistantTransport.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"createSandboxAssistantTransport.js","names":[],"sources":["../../src/services/createSandboxAssistantTransport.ts"],"sourcesContent":["/**\n * TimeCampus adapter for the shared fe-libs AssistantWidget.\n *\n * Reuses the sandbox `api-calls` agent so the widget can run operations on the\n * current screen via API on the user's behalf.\n */\n\nimport { useCallback, useMemo, useRef } from \"react\";\nimport { useGatewayClient } from \"@burdenoff/fe-libs/shared/graphql\";\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 type AssistantRawMessage,\n type AssistantSandboxAuthContext,\n} from \"./assistantApi\";\nimport { gatherPageContext } from \"@/utils/pageContext\";\nimport type { AssistantMode } from \"@/types/assistant\";\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\nconst MODE: AssistantMode = \"assistant\";\nconst STREAM_BUDGET_MS = 180_000;\nconst POLL_INTERVAL_MS = 1500;\nconst TTL_EXTEND_INTERVAL_MS = 30_000;\n\nfunction getProfileContextValue(key: \"workspaceId\" | \"organizationId\"): string {\n try {\n const activeContextKey =\n key === \"workspaceId\"\n ? \"burdenoff-active-context-workspace\"\n : \"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 {\n workspaceId?: string;\n organizationId?: string;\n };\n return context[key] ?? \"\";\n } catch {\n return \"\";\n }\n}\n\nfunction getWorkspaceId(): string {\n const params = new URLSearchParams(window.location.search);\n return params.get(\"workspace\") ?? getProfileContextValue(\"workspaceId\");\n}\n\nfunction getOrganizationId(): string {\n const params = new URLSearchParams(window.location.search);\n return params.get(\"org\") ?? getProfileContextValue(\"organizationId\");\n}\n\nfunction getRawMessageCreatedAt(message: AssistantRawMessage): number {\n return message.info?.time?.created ?? 0;\n}\n\nfunction getAssistantText(parts: AssistantRawMessage[\"parts\"]): string {\n return (parts ?? [])\n .filter((part) => part.type === \"text\" && typeof part.text === \"string\")\n .map((part) => part.text?.trim() ?? \"\")\n .filter(Boolean)\n .join(\"\\n\");\n}\n\nfunction getToolProgress(parts: AssistantRawMessage[\"parts\"]): string[] {\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): { content: string; done: boolean } {\n const relevant = messages\n .filter(\n (message) =>\n message.info?.role === \"assistant\" &&\n getRawMessageCreatedAt(message) >= sinceMs,\n )\n .sort(\n (left, right) =>\n getRawMessageCreatedAt(left) - getRawMessageCreatedAt(right),\n );\n\n if (relevant.length === 0) return { content: \"Thinking…\", done: false };\n\n const latest = relevant[relevant.length - 1]!;\n const text = getAssistantText(latest.parts);\n const toolProgress = getToolProgress(latest.parts);\n const content =\n [text, ...toolProgress].filter(Boolean).join(\"\\n\\n\") || \"Thinking…\";\n\n return {\n content,\n done:\n Boolean(latest.info?.time?.completed) &&\n (Boolean(text) || toolProgress.length > 0),\n };\n}\n\nfunction sanitize(response: string): string {\n return response\n .replace(/(Authorization\\s*:\\s*Bearer\\s+)[^\\s\\n]+/gi, \"$1[REDACTED]\")\n .replace(\n /(X-Workspace-Authorization\\s*:\\s*Bearer\\s+)[^\\s\\n]+/gi,\n \"$1[REDACTED]\",\n )\n .replace(\n /\\beyJ[A-Za-z0-9_-]+\\.[A-Za-z0-9._-]+\\.[A-Za-z0-9._-]+\\b/g,\n \"[REDACTED_JWT]\",\n )\n .replace(/\\bsk-ant-[A-Za-z0-9-]+\\b/g, \"[REDACTED_API_KEY]\");\n}\n\nfunction isRecoverable(error: unknown): boolean {\n const message =\n error instanceof Error\n ? error.message.toLowerCase()\n : 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 ].some((fragment) => message.includes(fragment));\n}\n\nexport function useSandboxAssistantTransport(): AssistantTransport {\n const apollo = useGatewayClient(\"workspace\");\n const { getAccessToken, getWorkspaceToken, userId } = useAuthToken();\n\n const sandboxIdRef = useRef<string | null>(null);\n const sessionIdRef = useRef<string | null>(null);\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 if (!sandboxId) {\n sandboxId = await findExistingSandbox(\n apollo,\n workspaceId,\n MODE,\n authContext,\n );\n if (!sandboxId) {\n if (!getAccessToken()) {\n throw new Error(\n \"API Calls mode requires an authenticated session. Please sign in again.\",\n );\n }\n sandboxId = await createAssistantSandbox(\n apollo,\n MODE,\n workspaceId,\n authContext,\n );\n }\n await waitForSandboxReady(apollo, sandboxId, workspaceId, authContext);\n await waitForAssistantServiceReady(\n apollo,\n sandboxId,\n workspaceId,\n authContext,\n );\n sandboxIdRef.current = sandboxId;\n }\n\n let sessionId = sessionIdRef.current;\n if (!sessionId) {\n const result = await createAssistantSession(\n apollo,\n sandboxId,\n workspaceId,\n MODE,\n authContext,\n );\n sessionId = result.sessionId;\n sessionIdRef.current = sessionId;\n }\n\n return { sandboxId, sessionId };\n },\n [apollo, getAccessToken],\n );\n\n const sendPrompt = useCallback(\n async ({\n prompt,\n onProgress,\n signal,\n }: AssistantSendArgs): Promise<{ text: string }> => {\n const workspaceId = getWorkspaceId();\n if (!workspaceId) {\n throw new Error(\n \"The assistant needs an active workspace. Open a workspace and try again.\",\n );\n }\n const authContext: AssistantSandboxAuthContext = {\n accessToken: getAccessToken(),\n workspaceToken: getWorkspaceToken(),\n userId,\n organizationId: getOrganizationId(),\n };\n\n const run = async (attempt: 1 | 2): Promise<{ text: string }> => {\n try {\n const { sandboxId, sessionId } = await ensureRuntime(\n workspaceId,\n authContext,\n );\n\n const startedAt = Date.now();\n await sendAssistantPromptAsync(\n apollo,\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 progress = buildProgress([], startedAt);\n\n while (Date.now() < timeoutAt) {\n if (signal.aborted) throw new Error(\"Cancelled\");\n\n const messages = await getAssistantMessages(\n apollo,\n sandboxId,\n workspaceId,\n sessionId,\n authContext,\n 50,\n );\n progress = buildProgress(messages, startedAt);\n onProgress(sanitize(progress.content));\n if (progress.done) break;\n\n if (Date.now() - lastTtlExtensionAt > TTL_EXTEND_INTERVAL_MS) {\n await extendAssistantSandboxTTL(\n apollo,\n sandboxId,\n workspaceId,\n 600,\n authContext,\n ).catch(() => undefined);\n lastTtlExtensionAt = Date.now();\n }\n\n await new Promise((resolve) =>\n setTimeout(resolve, POLL_INTERVAL_MS),\n );\n }\n\n if (!progress.done) {\n throw new Error(\n \"The assistant timed out while responding. Please try again.\",\n );\n }\n\n return { text: sanitize(progress.content) };\n } catch (error) {\n if (attempt === 1 && isRecoverable(error)) {\n sandboxIdRef.current = null;\n sessionIdRef.current = null;\n return run(2);\n }\n throw error;\n }\n };\n\n return run(1);\n },\n [apollo, ensureRuntime, getAccessToken, getWorkspaceToken, userId],\n );\n\n return useMemo<AssistantTransport>(() => ({ sendPrompt }), [sendPrompt]);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"createSandboxAssistantTransport.js","names":[],"sources":["../../src/services/createSandboxAssistantTransport.ts"],"sourcesContent":["/**\n * timecampus adapter for the shared fe-libs AssistantWidget transport.\n *\n * The sandbox lifecycle + poll/stream loop now lives in\n * `@burdenoff/fe-libs/shared/assistant` (one implementation for all products);\n * this is a thin wrapper. The exported name/shape are unchanged so app-shell\n * imports don't move. The public return type is a LOCALLY-declared structural\n * mirror — never re-export fe-libs types (vite-plugin-dts path rewriting).\n */\n\nimport { useSandboxAssistantTransport as useSharedTransport } from '@burdenoff/fe-libs/shared/assistant';\n\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 prewarm?: (level?: 'probe' | 'full') => void;\n suspend?: () => void;\n}\n\nexport function useSandboxAssistantTransport(): AssistantTransport {\n return useSharedTransport({\n product: 'timecampus',\n \n enableCredits: true,\n });\n}\n"],"mappings":";;AAyBA,SAAgB,IAAmD;AACjE,QAAO,EAAmB;EACxB,SAAS;EAET,eAAe;EAChB,CAAC"}
@@ -18,9 +18,9 @@ import { Check as pe, DollarSign as me, ExternalLink as he, MessageSquare as ge,
18
18
  import { gql as f } from "@apollo/client";
19
19
  import { useApolloClient as Ce } from "@apollo/client/react";
20
20
  import { Fragment as p, jsx as m, jsxs as h } from "react/jsx-runtime";
21
- import { useRegisterPageConversationContext as g } from "@burdenoff/fe-libs/shared/providers/shell";
22
21
  import { uploadBlobToFiles as we } from "@burdenoff/fe-libs/storage";
23
- import { ContextConversationWidget as _ } from "@burdenoff/fe-libs/shared";
22
+ import { ContextConversationWidget as g } from "@burdenoff/fe-libs/shared";
23
+ import { useRegisterPageConversationContext as _ } from "@burdenoff/fe-libs/shared/providers/shell";
24
24
  //#region src/timecampus/pages/expense-tracking/ExpenseTrackingPage.tsx
25
25
  var v = 25, y = [
26
26
  "Travel",
@@ -42,11 +42,11 @@ var v = 25, y = [
42
42
  }
43
43
  `, De = 604800;
44
44
  function Oe({ expense: e }) {
45
- return g({
45
+ return _({
46
46
  entityType: "TIMECAMPUS_EXPENSE",
47
47
  entityId: e.id,
48
48
  contextTitle: `Expense · ${e.description ?? e.id}`
49
- }), /* @__PURE__ */ m(_, { widgetKey: "expense-review" });
49
+ }), /* @__PURE__ */ m(g, { widgetKey: "expense-review" });
50
50
  }
51
51
  function x() {
52
52
  return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
@@ -16,16 +16,16 @@ import { useState as d } from "react";
16
16
  import { CheckCircle as f, Clock as p, MessageSquare as de, MessagesSquare as m, Undo2 as h, X as fe, XCircle as g } from "lucide-react";
17
17
  import { Fragment as _, jsx as v, jsxs as y } from "react/jsx-runtime";
18
18
  import { GlassCard as b } from "@burdenoff/fe-libs/ui";
19
- import { useRegisterPageConversationContext as x } from "@burdenoff/fe-libs/shared/providers/shell";
20
- import { ContextConversationWidget as S } from "@burdenoff/fe-libs/shared";
19
+ import { ContextConversationWidget as x } from "@burdenoff/fe-libs/shared";
20
+ import { useRegisterPageConversationContext as S } from "@burdenoff/fe-libs/shared/providers/shell";
21
21
  //#region src/timecampus/pages/time-approval/TimeApprovalPage.tsx
22
22
  var C = 25;
23
23
  function w({ request: e }) {
24
- return x({
24
+ return S({
25
25
  entityType: "TIMECAMPUS_APPROVAL_REQUEST",
26
26
  entityId: e.id,
27
27
  contextTitle: `Approval · ${e.period ?? e.id}`
28
- }), /* @__PURE__ */ v(S, { widgetKey: "approval-review" });
28
+ }), /* @__PURE__ */ v(x, { widgetKey: "approval-review" });
29
29
  }
30
30
  var T = "mt-1 w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-secondary";
31
31
  function E() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@burdenoff/microfe-timecampus",
3
- "version": "2026.710.2",
3
+ "version": "2026.713.1",
4
4
  "description": "Burdenoff TimeCampus Microfrontend - AI-powered time management and productivity platform",
5
5
  "type": "module",
6
6
  "files": [
@@ -44,7 +44,7 @@
44
44
  },
45
45
  "dependencies": {
46
46
  "@apollo/client": "^4.0.11",
47
- "@burdenoff/fe-libs": "2026.625.5",
47
+ "@burdenoff/fe-libs": "2026.713.6",
48
48
  "clsx": "^2.1.1",
49
49
  "date-fns": "^4.1.0",
50
50
  "graphql": "^16.12.0",
@@ -1,49 +0,0 @@
1
- import { ApolloClient } from '@apollo/client';
2
- import { AssistantMode } from '../types/assistant';
3
- import { PageContext } from '../utils/pageContext';
4
-
5
- export interface AssistantRawMessagePart {
6
- type?: string;
7
- text?: string;
8
- tool?: string;
9
- state?: {
10
- status?: string;
11
- input?: unknown;
12
- output?: unknown;
13
- raw?: unknown;
14
- };
15
- }
16
- export interface AssistantRawMessage {
17
- info?: {
18
- id?: string;
19
- role?: string;
20
- providerID?: string;
21
- modelID?: string;
22
- tokens?: {
23
- input: number;
24
- output: number;
25
- };
26
- time?: {
27
- created?: number;
28
- completed?: number;
29
- };
30
- };
31
- parts?: AssistantRawMessagePart[];
32
- }
33
- export interface AssistantSandboxAuthContext {
34
- accessToken?: string | null;
35
- workspaceToken?: string | null;
36
- userId?: string | null;
37
- organizationId?: string | null;
38
- }
39
- export declare function findExistingSandbox(_apollo: ApolloClient, workspaceId: string, mode: AssistantMode, authContext?: AssistantSandboxAuthContext): Promise<string | null>;
40
- export declare function createAssistantSandbox(_apollo: ApolloClient, mode: AssistantMode, workspaceId: string, authContext?: AssistantSandboxAuthContext): Promise<string>;
41
- export declare function waitForSandboxReady(_apollo: ApolloClient, sandboxId: string, workspaceId: string, authContext?: AssistantSandboxAuthContext, maxWaitMs?: number): Promise<void>;
42
- export declare function waitForAssistantServiceReady(apollo: ApolloClient, sandboxId: string, workspaceId: string, authContext?: AssistantSandboxAuthContext, maxWaitMs?: number): Promise<void>;
43
- export declare function createAssistantSession(apollo: ApolloClient, sandboxId: string, workspaceId: string, mode: AssistantMode, authContext?: AssistantSandboxAuthContext): Promise<{
44
- sessionId: string;
45
- }>;
46
- export declare function sendAssistantPromptAsync(apollo: ApolloClient, sandboxId: string, workspaceId: string, sessionId: string, prompt: string, mode: AssistantMode, pageContext?: PageContext, authContext?: AssistantSandboxAuthContext): Promise<void>;
47
- export declare function getAssistantMessages(apollo: ApolloClient, sandboxId: string, workspaceId: string, sessionId: string, authContext?: AssistantSandboxAuthContext, limit?: number): Promise<AssistantRawMessage[]>;
48
- export declare function extendAssistantSandboxTTL(_apollo: ApolloClient, sandboxId: string, workspaceId: string, additionalSeconds?: number, authContext?: AssistantSandboxAuthContext): Promise<void>;
49
- //# sourceMappingURL=assistantApi.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"assistantApi.d.ts","sourceRoot":"","sources":["../../src/services/assistantApi.ts"],"names":[],"mappings":"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"}
@@ -1,248 +0,0 @@
1
- import { gql as e } from "@apollo/client";
2
- import { print as t } from "graphql";
3
- //#region src/services/assistantApi.ts
4
- var n = "burdenoffregistry.azurecr.io", r = "alpha", i = "alpha-delegated-auth-v11", a = "sandbox-app-client-headers-v1", o = e`
5
- mutation CreateSandbox($input: CreateSandboxInput!) {
6
- createSandbox(input: $input) {
7
- id
8
- name
9
- status
10
- }
11
- }
12
- `, s = e`
13
- query GetSandbox($id: ID!, $context: ContextInput!) {
14
- getSandbox(id: $id, context: $context) {
15
- id
16
- status
17
- errorMessage
18
- }
19
- }
20
- `, c = e`
21
- query GetActiveSandboxes($context: ContextInput!) {
22
- getActiveSandboxes(context: $context) {
23
- id
24
- name
25
- status
26
- metadata
27
- template
28
- createdBy
29
- }
30
- }
31
- `, l = e`
32
- mutation ProxySandboxRequest($input: ProxySandboxRequestInput!) {
33
- proxySandboxRequest(input: $input) {
34
- status
35
- body
36
- }
37
- }
38
- `, u = e`
39
- mutation ExtendSandboxTtl(
40
- $id: ID!
41
- $additionalSeconds: Int!
42
- $context: ContextInput!
43
- ) {
44
- extendSandboxTTL(
45
- id: $id
46
- additionalSeconds: $additionalSeconds
47
- context: $context
48
- ) {
49
- id
50
- expiresAt
51
- }
52
- }
53
- `;
54
- function d(e) {
55
- return e === "assistant" || e === "api-calls" ? i : r;
56
- }
57
- function f(e) {
58
- return `${n}/wspace/ai-assistant-${e === "assistant" ? "api-calls" : e}:${d(e)}`;
59
- }
60
- function p(e) {
61
- return e === "general" ? {
62
- cpuRequest: "100m",
63
- cpuLimit: "500m",
64
- memoryRequest: "256Mi",
65
- memoryLimit: "1Gi"
66
- } : {
67
- cpuRequest: "150m",
68
- cpuLimit: "750m",
69
- memoryRequest: "384Mi",
70
- memoryLimit: "1536Mi"
71
- };
72
- }
73
- function m(e) {
74
- let t = e.metadata?.assistantMode;
75
- if (t === "assistant" || t === "general" || t === "api-calls") return t;
76
- let n = e.name ?? "";
77
- return n.startsWith("ai-assistant-api-calls-") ? "api-calls" : n.startsWith("ai-assistant-general-") ? "general" : n.startsWith("ai-assistant-assistant-") ? "assistant" : null;
78
- }
79
- function h(e, t) {
80
- let n = {};
81
- return t?.accessToken && (n.authorization = `Bearer ${t.accessToken}`), t?.workspaceToken && (n["x-workspace-authorization"] = `Bearer ${t.workspaceToken}`), e && (n["x-workspace-id"] = e), t?.userId && (n["x-actor-id"] = t.userId, n["x-actor-type"] = "user"), t?.organizationId && (n["x-org-id"] = t.organizationId), Object.keys(n).length > 0 ? { headers: n } : void 0;
82
- }
83
- function g(e, t) {
84
- return {
85
- workspaceId: e,
86
- ...t?.organizationId ? { custom: { organizationId: t.organizationId } } : {}
87
- };
88
- }
89
- async function _(e) {
90
- let n = await fetch("/workspaces/graphql", {
91
- method: "POST",
92
- headers: {
93
- "Content-Type": "application/json",
94
- ...h(e.workspaceId, e.authContext)?.headers ?? {}
95
- },
96
- body: JSON.stringify({
97
- query: t(e.document),
98
- variables: e.variables
99
- })
100
- }), r = await n.json().catch(() => null);
101
- if (!n.ok) {
102
- let e = r?.errors?.map((e) => e.message).join(", "), t = Error(e || `Sandbox GraphQL HTTP ${n.status}`);
103
- throw t.statusCode = n.status, t.result = r ?? void 0, t;
104
- }
105
- if (!r) throw Error("Sandbox GraphQL returned empty response");
106
- if (r.errors?.length) throw Error(r.errors.map((e) => e.message).join(", "));
107
- if (!r.data) throw Error("Sandbox GraphQL returned no data");
108
- return r.data;
109
- }
110
- async function v(e, t, n, r) {
111
- return ((await _({
112
- document: c,
113
- variables: { context: g(t, r) },
114
- workspaceId: t,
115
- authContext: r
116
- })).getActiveSandboxes ?? []).find((e) => (e.status === "RUNNING" || e.status === "PROVISIONING" || e.status === "PENDING") && e.template === "AI_BUILDER" && m(e) === n && (!r?.userId || e.createdBy === r.userId) && e.metadata?.authStrategy === a && e.metadata?.imageTag === d(n))?.id ?? null;
117
- }
118
- async function y(e, t, n, r) {
119
- let i = p(t), s = [
120
- {
121
- name: "AI_ASSISTANT_MODE",
122
- value: t
123
- },
124
- {
125
- name: "HOSTNAME",
126
- value: "0.0.0.0"
127
- },
128
- {
129
- name: "WORKSPACE_ID",
130
- value: n
131
- },
132
- {
133
- name: "AI_ASSISTANT_PRODUCT",
134
- value: "timecampus"
135
- }
136
- ], c = await _({
137
- document: o,
138
- variables: { input: {
139
- name: `ai-assistant-${t}-${Date.now()}`,
140
- description: `AI Assistant sandbox (${t} mode)`,
141
- template: "AI_BUILDER",
142
- mode: "DEPLOYMENT",
143
- containers: [{
144
- name: "ai-assistant",
145
- image: f(t),
146
- ports: [{
147
- containerPort: 8080,
148
- name: "http"
149
- }],
150
- env: s
151
- }],
152
- resources: i,
153
- ttlSeconds: 600,
154
- metadata: {
155
- assistantMode: t,
156
- assistantOwnerUserId: r?.userId ?? null,
157
- assistantOrganizationId: r?.organizationId ?? null,
158
- authStrategy: a,
159
- imageTag: d(t)
160
- },
161
- context: g(n, r)
162
- } },
163
- workspaceId: n,
164
- authContext: r
165
- });
166
- if (!c?.createSandbox?.id) throw Error("createSandbox returned empty response");
167
- return c.createSandbox.id;
168
- }
169
- async function b(e, t, n, r, i = 3e5) {
170
- let a = Date.now();
171
- for (; Date.now() - a < i;) {
172
- let e = await _({
173
- document: s,
174
- variables: {
175
- id: t,
176
- context: g(n, r)
177
- },
178
- workspaceId: n,
179
- authContext: r
180
- }), i = e?.getSandbox?.status, a = e?.getSandbox?.errorMessage;
181
- if (i === "RUNNING") return;
182
- if (i === "FAILED" || i === "STOPPED" || i === "EXPIRED") throw Error(a ? `Sandbox ${i.toLowerCase()}: ${a}` : `Sandbox ${i.toLowerCase()}`);
183
- await new Promise((e) => setTimeout(e, 2e3));
184
- }
185
- throw Error("Sandbox startup timed out");
186
- }
187
- async function x(e, t, n, r, i, a, o) {
188
- let s = (await _({
189
- document: l,
190
- variables: { input: {
191
- sandboxId: t,
192
- path: r,
193
- method: i,
194
- body: a,
195
- context: g(n, o)
196
- } },
197
- workspaceId: n,
198
- authContext: o
199
- })).proxySandboxRequest;
200
- if (!s || s.status >= 400) {
201
- let e = s?.body;
202
- throw Error(e?.error ?? `Proxy error: ${s?.status ?? "unknown"}`);
203
- }
204
- return s.body;
205
- }
206
- async function S(e, t, n, r, i = 9e4) {
207
- let a = Date.now();
208
- for (; Date.now() - a < i;) {
209
- try {
210
- await x(e, t, n, "/health", "GET", void 0, r);
211
- return;
212
- } catch (e) {
213
- let t = e instanceof Error ? e.message : String(e);
214
- if (!/proxy error: 502|proxy error: 503|proxy error: 404|service not available/i.test(t)) throw e;
215
- }
216
- await new Promise((e) => setTimeout(e, 2e3));
217
- }
218
- throw Error("Assistant service did not become healthy before timeout");
219
- }
220
- async function C(e, t, n, r, i) {
221
- return { sessionId: (await x(e, t, n, "/sessions", "POST", { mode: r }, i)).session.id };
222
- }
223
- async function w(e, t, n, r, i, a, o, s) {
224
- await x(e, t, n, `/sessions/${r}/prompt-async`, "POST", {
225
- mode: a,
226
- prompt: i,
227
- pageContext: o ?? void 0
228
- }, s);
229
- }
230
- async function T(e, t, n, r, i, a = 50) {
231
- return (await x(e, t, n, `/sessions/${r}/messages?limit=${a}`, "GET", void 0, i)).messages ?? [];
232
- }
233
- async function E(e, t, n, r = 600, i) {
234
- await _({
235
- document: u,
236
- variables: {
237
- id: t,
238
- additionalSeconds: r,
239
- context: g(n, i)
240
- },
241
- workspaceId: n,
242
- authContext: i
243
- });
244
- }
245
- //#endregion
246
- export { y as createAssistantSandbox, C as createAssistantSession, E as extendAssistantSandboxTTL, v as findExistingSandbox, T as getAssistantMessages, w as sendAssistantPromptAsync, S as waitForAssistantServiceReady, b as waitForSandboxReady };
247
-
248
- //# sourceMappingURL=assistantApi.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"assistantApi.js","names":[],"sources":["../../src/services/assistantApi.ts"],"sourcesContent":["/**\n * AI Assistant API service for TimeCampus.\n *\n * All requests go through the wspace-public-gateway (GraphQL Federation):\n * Frontend → wspace-public-gateway → wspace-sandbox-svc → ai-assistant pod\n */\n\nimport { gql } from \"@apollo/client\";\nimport type { ApolloClient } from \"@apollo/client\";\nimport { print } from \"graphql\";\nimport type { AssistantMode } from \"@/types/assistant\";\nimport type { PageContext } from \"@/utils/pageContext\";\n\nconst HARBOR_REGISTRY = \"burdenoffregistry.azurecr.io\";\nconst DEFAULT_IMAGE_TAG =\n import.meta.env.VITE_APP_ENV === \"prod\" ? \"prod\" : \"alpha\";\nconst API_CALLS_IMAGE_TAG =\n import.meta.env.VITE_APP_ENV === \"prod\" ? \"prod\" : \"alpha-delegated-auth-v11\";\nconst ASSISTANT_API_AUTH_STRATEGY = \"sandbox-app-client-headers-v1\";\n\nconst CreateSandboxDocument = gql`\n mutation CreateSandbox($input: CreateSandboxInput!) {\n createSandbox(input: $input) {\n id\n name\n status\n }\n }\n`;\n\nconst GetSandboxDocument = gql`\n query GetSandbox($id: ID!, $context: ContextInput!) {\n getSandbox(id: $id, context: $context) {\n id\n status\n errorMessage\n }\n }\n`;\n\nconst GetActiveSandboxesDocument = gql`\n query GetActiveSandboxes($context: ContextInput!) {\n getActiveSandboxes(context: $context) {\n id\n name\n status\n metadata\n template\n createdBy\n }\n }\n`;\n\nconst ProxySandboxRequestDocument = gql`\n mutation ProxySandboxRequest($input: ProxySandboxRequestInput!) {\n proxySandboxRequest(input: $input) {\n status\n body\n }\n }\n`;\n\nconst ExtendSandboxTtlDocument = gql`\n mutation ExtendSandboxTtl(\n $id: ID!\n $additionalSeconds: Int!\n $context: ContextInput!\n ) {\n extendSandboxTTL(\n id: $id\n additionalSeconds: $additionalSeconds\n context: $context\n ) {\n id\n expiresAt\n }\n }\n`;\n\nfunction getImageTagForMode(mode: AssistantMode): string {\n return mode === \"assistant\" || mode === \"api-calls\"\n ? API_CALLS_IMAGE_TAG\n : DEFAULT_IMAGE_TAG;\n}\n\nfunction getImageForMode(mode: AssistantMode): string {\n const imageMode = mode === \"assistant\" ? \"api-calls\" : mode;\n return `${HARBOR_REGISTRY}/wspace/ai-assistant-${imageMode}:${getImageTagForMode(mode)}`;\n}\n\nfunction getResourcesForMode(mode: AssistantMode): {\n cpuRequest: string;\n cpuLimit: string;\n memoryRequest: string;\n memoryLimit: string;\n} {\n return mode === \"general\"\n ? {\n cpuRequest: \"100m\",\n cpuLimit: \"500m\",\n memoryRequest: \"256Mi\",\n memoryLimit: \"1Gi\",\n }\n : {\n cpuRequest: \"150m\",\n cpuLimit: \"750m\",\n memoryRequest: \"384Mi\",\n memoryLimit: \"1536Mi\",\n };\n}\n\nfunction resolveSandboxAssistantMode(sandbox: {\n metadata: Record<string, unknown> | null;\n name?: string | null;\n}): AssistantMode | null {\n const metadataMode = sandbox.metadata?.assistantMode;\n if (\n metadataMode === \"assistant\" ||\n metadataMode === \"general\" ||\n metadataMode === \"api-calls\"\n ) {\n return metadataMode;\n }\n\n const name = sandbox.name ?? \"\";\n if (name.startsWith(\"ai-assistant-api-calls-\")) return \"api-calls\";\n if (name.startsWith(\"ai-assistant-general-\")) return \"general\";\n if (name.startsWith(\"ai-assistant-assistant-\")) return \"assistant\";\n return null;\n}\n\nexport interface AssistantRawMessagePart {\n type?: string;\n text?: string;\n tool?: string;\n state?: {\n status?: string;\n input?: unknown;\n output?: unknown;\n raw?: unknown;\n };\n}\n\nexport interface AssistantRawMessage {\n info?: {\n id?: string;\n role?: string;\n providerID?: string;\n modelID?: string;\n tokens?: { input: number; output: number };\n time?: {\n created?: number;\n completed?: number;\n };\n };\n parts?: AssistantRawMessagePart[];\n}\n\nexport interface AssistantSandboxAuthContext {\n accessToken?: string | null;\n workspaceToken?: string | null;\n userId?: string | null;\n organizationId?: string | null;\n}\n\ninterface GraphQLResponse<TData> {\n data?: TData;\n errors?: Array<{ message: string }>;\n}\n\nfunction getGatewayRequestContext(\n workspaceId: string,\n authContext?: AssistantSandboxAuthContext,\n): { headers?: Record<string, string> } | undefined {\n const headers: Record<string, string> = {};\n if (authContext?.accessToken)\n headers.authorization = `Bearer ${authContext.accessToken}`;\n if (authContext?.workspaceToken) {\n headers[\"x-workspace-authorization\"] =\n `Bearer ${authContext.workspaceToken}`;\n }\n if (workspaceId) headers[\"x-workspace-id\"] = workspaceId;\n if (authContext?.userId) {\n headers[\"x-actor-id\"] = authContext.userId;\n headers[\"x-actor-type\"] = \"user\";\n }\n if (authContext?.organizationId)\n headers[\"x-org-id\"] = authContext.organizationId;\n return Object.keys(headers).length > 0 ? { headers } : undefined;\n}\n\nfunction buildSandboxContextInput(\n workspaceId: string,\n authContext?: AssistantSandboxAuthContext,\n): Record<string, unknown> {\n return {\n workspaceId,\n ...(authContext?.organizationId\n ? { custom: { organizationId: authContext.organizationId } }\n : {}),\n };\n}\n\nasync function executeSandboxGraphQL<TData>(params: {\n document: ReturnType<typeof gql>;\n variables: Record<string, unknown>;\n workspaceId: string;\n authContext?: AssistantSandboxAuthContext;\n}): Promise<TData> {\n const response = await fetch(\"/workspaces/graphql\", {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n ...(getGatewayRequestContext(params.workspaceId, params.authContext)\n ?.headers ?? {}),\n },\n body: JSON.stringify({\n query: print(params.document),\n variables: params.variables,\n }),\n });\n\n const result = (await response\n .json()\n .catch(() => null)) as GraphQLResponse<TData> | null;\n\n if (!response.ok) {\n const messages = result?.errors?.map((error) => error.message).join(\", \");\n const httpError = new Error(\n messages || `Sandbox GraphQL HTTP ${response.status}`,\n ) as Error & {\n statusCode?: number;\n result?: unknown;\n };\n httpError.statusCode = response.status;\n httpError.result = result ?? undefined;\n throw httpError;\n }\n\n if (!result) throw new Error(\"Sandbox GraphQL returned empty response\");\n if (result.errors?.length)\n throw new Error(result.errors.map((error) => error.message).join(\", \"));\n if (!result.data) throw new Error(\"Sandbox GraphQL returned no data\");\n return result.data;\n}\n\nexport async function findExistingSandbox(\n _apollo: ApolloClient,\n workspaceId: string,\n mode: AssistantMode,\n authContext?: AssistantSandboxAuthContext,\n): Promise<string | null> {\n const data = await executeSandboxGraphQL<{\n getActiveSandboxes: Array<{\n id: string;\n name: string;\n status: string;\n metadata: Record<string, unknown> | null;\n template: string;\n createdBy: string;\n }>;\n }>({\n document: GetActiveSandboxesDocument,\n variables: { context: buildSandboxContextInput(workspaceId, authContext) },\n workspaceId,\n authContext,\n });\n const sandboxes = data.getActiveSandboxes ?? [];\n\n return (\n sandboxes.find(\n (s) =>\n (s.status === \"RUNNING\" ||\n s.status === \"PROVISIONING\" ||\n s.status === \"PENDING\") &&\n s.template === \"AI_BUILDER\" &&\n resolveSandboxAssistantMode(s) === mode &&\n (!authContext?.userId || s.createdBy === authContext.userId) &&\n s.metadata?.authStrategy === ASSISTANT_API_AUTH_STRATEGY &&\n s.metadata?.imageTag === getImageTagForMode(mode),\n )?.id ?? null\n );\n}\n\nexport async function createAssistantSandbox(\n _apollo: ApolloClient,\n mode: AssistantMode,\n workspaceId: string,\n authContext?: AssistantSandboxAuthContext,\n): Promise<string> {\n const resources = getResourcesForMode(mode);\n const env = [\n { name: \"AI_ASSISTANT_MODE\", value: mode },\n { name: \"HOSTNAME\", value: \"0.0.0.0\" },\n { name: \"WORKSPACE_ID\", value: workspaceId },\n { name: \"AI_ASSISTANT_PRODUCT\", value: \"timecampus\" },\n ];\n\n const data = await executeSandboxGraphQL<{ createSandbox: { id: string } }>({\n document: CreateSandboxDocument,\n variables: {\n input: {\n name: `ai-assistant-${mode}-${Date.now()}`,\n description: `AI Assistant sandbox (${mode} mode)`,\n template: \"AI_BUILDER\",\n mode: \"DEPLOYMENT\",\n containers: [\n {\n name: \"ai-assistant\",\n image: getImageForMode(mode),\n ports: [{ containerPort: 8080, name: \"http\" }],\n env,\n },\n ],\n resources,\n ttlSeconds: 600,\n metadata: {\n assistantMode: mode,\n assistantOwnerUserId: authContext?.userId ?? null,\n assistantOrganizationId: authContext?.organizationId ?? null,\n authStrategy: ASSISTANT_API_AUTH_STRATEGY,\n imageTag: getImageTagForMode(mode),\n },\n context: buildSandboxContextInput(workspaceId, authContext),\n },\n },\n workspaceId,\n authContext,\n });\n\n if (!data?.createSandbox?.id)\n throw new Error(\"createSandbox returned empty response\");\n return data.createSandbox.id;\n}\n\nexport async function waitForSandboxReady(\n _apollo: ApolloClient,\n sandboxId: string,\n workspaceId: string,\n authContext?: AssistantSandboxAuthContext,\n maxWaitMs = 300_000,\n): Promise<void> {\n const start = Date.now();\n while (Date.now() - start < maxWaitMs) {\n const data = await executeSandboxGraphQL<{\n getSandbox: { status?: string; errorMessage?: string } | null;\n }>({\n document: GetSandboxDocument,\n variables: {\n id: sandboxId,\n context: buildSandboxContextInput(workspaceId, authContext),\n },\n workspaceId,\n authContext,\n });\n const status = data?.getSandbox?.status;\n const errorMessage = data?.getSandbox?.errorMessage as string | undefined;\n if (status === \"RUNNING\") return;\n if (status === \"FAILED\" || status === \"STOPPED\" || status === \"EXPIRED\") {\n throw new Error(\n errorMessage\n ? `Sandbox ${status.toLowerCase()}: ${errorMessage}`\n : `Sandbox ${status.toLowerCase()}`,\n );\n }\n await new Promise((r) => setTimeout(r, 2000));\n }\n throw new Error(\"Sandbox startup timed out\");\n}\n\ninterface ProxyResponse {\n proxySandboxRequest: {\n status: number;\n body: Record<string, unknown>;\n };\n}\n\nasync function proxyToSandbox(\n _apollo: ApolloClient,\n sandboxId: string,\n workspaceId: string,\n path: string,\n method: string,\n body?: unknown,\n authContext?: AssistantSandboxAuthContext,\n): Promise<Record<string, unknown>> {\n const result = await executeSandboxGraphQL<ProxyResponse>({\n document: ProxySandboxRequestDocument,\n variables: {\n input: {\n sandboxId,\n path,\n method,\n body,\n context: buildSandboxContextInput(workspaceId, authContext),\n },\n },\n workspaceId,\n authContext,\n });\n\n const proxyResult = result.proxySandboxRequest;\n if (!proxyResult || proxyResult.status >= 400) {\n const errBody = proxyResult?.body as Record<string, unknown> | undefined;\n throw new Error(\n (errBody?.error as string) ??\n `Proxy error: ${proxyResult?.status ?? \"unknown\"}`,\n );\n }\n return proxyResult.body;\n}\n\nexport async function waitForAssistantServiceReady(\n apollo: ApolloClient,\n sandboxId: string,\n workspaceId: string,\n authContext?: AssistantSandboxAuthContext,\n maxWaitMs = 90_000,\n): Promise<void> {\n const startedAt = Date.now();\n while (Date.now() - startedAt < maxWaitMs) {\n try {\n await proxyToSandbox(\n apollo,\n sandboxId,\n workspaceId,\n \"/health\",\n \"GET\",\n undefined,\n authContext,\n );\n return;\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n if (\n !/proxy error: 502|proxy error: 503|proxy error: 404|service not available/i.test(\n message,\n )\n ) {\n throw error;\n }\n }\n await new Promise((resolve) => setTimeout(resolve, 2000));\n }\n throw new Error(\"Assistant service did not become healthy before timeout\");\n}\n\nexport async function createAssistantSession(\n apollo: ApolloClient,\n sandboxId: string,\n workspaceId: string,\n mode: AssistantMode,\n authContext?: AssistantSandboxAuthContext,\n): Promise<{ sessionId: string }> {\n const body = await proxyToSandbox(\n apollo,\n sandboxId,\n workspaceId,\n \"/sessions\",\n \"POST\",\n { mode },\n authContext,\n );\n const session = body.session as Record<string, unknown>;\n return { sessionId: session.id as string };\n}\n\nexport async function sendAssistantPromptAsync(\n apollo: ApolloClient,\n sandboxId: string,\n workspaceId: string,\n sessionId: string,\n prompt: string,\n mode: AssistantMode,\n pageContext?: PageContext,\n authContext?: AssistantSandboxAuthContext,\n): Promise<void> {\n await proxyToSandbox(\n apollo,\n sandboxId,\n workspaceId,\n `/sessions/${sessionId}/prompt-async`,\n \"POST\",\n { mode, prompt, pageContext: pageContext ?? undefined },\n authContext,\n );\n}\n\nexport async function getAssistantMessages(\n apollo: ApolloClient,\n sandboxId: string,\n workspaceId: string,\n sessionId: string,\n authContext?: AssistantSandboxAuthContext,\n limit = 50,\n): Promise<AssistantRawMessage[]> {\n const body = await proxyToSandbox(\n apollo,\n sandboxId,\n workspaceId,\n `/sessions/${sessionId}/messages?limit=${limit}`,\n \"GET\",\n undefined,\n authContext,\n );\n return (body.messages as AssistantRawMessage[] | undefined) ?? [];\n}\n\nexport async function extendAssistantSandboxTTL(\n _apollo: ApolloClient,\n sandboxId: string,\n workspaceId: string,\n additionalSeconds = 600,\n authContext?: AssistantSandboxAuthContext,\n): Promise<void> {\n await executeSandboxGraphQL<{ extendSandboxTTL: { id: string } }>({\n document: ExtendSandboxTtlDocument,\n variables: {\n id: sandboxId,\n additionalSeconds,\n context: buildSandboxContextInput(workspaceId, authContext),\n },\n workspaceId,\n authContext,\n });\n}\n"],"mappings":"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"}
@@ -1,52 +0,0 @@
1
- //#region src/utils/pageContext.ts
2
- function e() {
3
- let e = window.location.href, t = window.location.pathname.split("/").filter(Boolean).slice(0, 3).join("/") || "home", r = n(window.location.pathname, window.location.search);
4
- return {
5
- currentUrl: e,
6
- currentPage: t,
7
- entityType: r.entityType,
8
- entityId: r.entityId,
9
- platform: "timecampus",
10
- version: "0.0.0-dev",
11
- viewportSize: `${window.innerWidth}x${window.innerHeight}`,
12
- userAgent: navigator.userAgent,
13
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
14
- };
15
- }
16
- function t(e, t) {
17
- return t.match(e);
18
- }
19
- function n(e, n) {
20
- let r = new URLSearchParams(n);
21
- for (let [n, r] of [
22
- [/^\/?timecampus\/time\/projects\/([^/]+)$/, "TIMECAMPUS_PROJECT"],
23
- [/^\/?timecampus\/time\/tasks\/([^/]+)$/, "TIMECAMPUS_TASK"],
24
- [/^\/?timecampus\/meetings\/([^/]+)$/, "TIMECAMPUS_MEETING"],
25
- [/^\/?timecampus\/pomodoro\/sessions\/([^/]+)$/, "TIMECAMPUS_POMODORO_SESSION"],
26
- [/^\/?timecampus\/lifetime\/goals\/([^/]+)$/, "TIMECAMPUS_LIFE_GOAL"],
27
- [/^\/?timecampus\/resource-planning\/plans\/([^/]+)$/, "TIMECAMPUS_RESOURCE_PLAN"]
28
- ]) {
29
- let i = t(n, e);
30
- if (i) return {
31
- entityType: r,
32
- entityId: i[1],
33
- metadata: { routePattern: n.source }
34
- };
35
- }
36
- let i = r.get("tab") ?? (() => {
37
- let t = e.split("/").filter(Boolean);
38
- return t.length > 2 ? t[t.length - 1] : void 0;
39
- })();
40
- return {
41
- activeTab: i ?? void 0,
42
- metadata: {
43
- ...i ? { activeTab: i } : {},
44
- ...r.get("projectId") ? { projectId: r.get("projectId") } : {},
45
- ...r.get("date") ? { date: r.get("date") } : {}
46
- }
47
- };
48
- }
49
- //#endregion
50
- export { e as gatherPageContext };
51
-
52
- //# sourceMappingURL=pageContext.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"pageContext.js","names":[],"sources":["../../src/utils/pageContext.ts"],"sourcesContent":["/**\n * Page context gathering — captures the user's current browser context\n * to be sent alongside every assistant prompt for better AI awareness.\n */\n\ninterface ConversationContextShape {\n entityType?: string;\n entityId?: string;\n activeTab?: string;\n metadata?: Record<string, unknown>;\n}\n\nexport interface PageContext {\n currentUrl: string;\n currentPage: string;\n entityType?: string;\n entityId?: string;\n platform: string;\n version: string;\n viewportSize: string;\n userAgent: string;\n timestamp: string;\n}\n\nexport function gatherPageContext(): PageContext {\n const url = window.location.href;\n const pathSegments = window.location.pathname.split(\"/\").filter(Boolean);\n const currentPage = pathSegments.slice(0, 3).join(\"/\") || \"home\";\n const entity = resolveTimeCampusConversationContext(\n window.location.pathname,\n window.location.search,\n );\n\n return {\n currentUrl: url,\n currentPage,\n entityType: entity.entityType,\n entityId: entity.entityId,\n platform: \"timecampus\",\n version: import.meta.env.VITE_APP_VERSION ?? \"0.0.0-dev\",\n viewportSize: `${window.innerWidth}x${window.innerHeight}`,\n userAgent: navigator.userAgent,\n timestamp: new Date().toISOString(),\n };\n}\n\nfunction matchPath(pattern: RegExp, pathname: string): RegExpMatchArray | null {\n return pathname.match(pattern);\n}\n\nexport function resolveTimeCampusConversationContext(\n pathname: string,\n search: string,\n): ConversationContextShape {\n const params = new URLSearchParams(search);\n\n const directMatches: Array<[RegExp, string]> = [\n [/^\\/?timecampus\\/time\\/projects\\/([^/]+)$/, \"TIMECAMPUS_PROJECT\"],\n [/^\\/?timecampus\\/time\\/tasks\\/([^/]+)$/, \"TIMECAMPUS_TASK\"],\n [/^\\/?timecampus\\/meetings\\/([^/]+)$/, \"TIMECAMPUS_MEETING\"],\n [\n /^\\/?timecampus\\/pomodoro\\/sessions\\/([^/]+)$/,\n \"TIMECAMPUS_POMODORO_SESSION\",\n ],\n [/^\\/?timecampus\\/lifetime\\/goals\\/([^/]+)$/, \"TIMECAMPUS_LIFE_GOAL\"],\n [\n /^\\/?timecampus\\/resource-planning\\/plans\\/([^/]+)$/,\n \"TIMECAMPUS_RESOURCE_PLAN\",\n ],\n ];\n\n for (const [pattern, entityType] of directMatches) {\n const match = matchPath(pattern, pathname);\n if (match) {\n return {\n entityType,\n entityId: match[1],\n metadata: { routePattern: pattern.source },\n };\n }\n }\n\n const activeTab =\n params.get(\"tab\") ??\n (() => {\n const segments = pathname.split(\"/\").filter(Boolean);\n return segments.length > 2 ? segments[segments.length - 1] : undefined;\n })();\n\n return {\n activeTab: activeTab ?? undefined,\n metadata: {\n ...(activeTab ? { activeTab } : {}),\n ...(params.get(\"projectId\")\n ? { projectId: params.get(\"projectId\") }\n : {}),\n ...(params.get(\"date\") ? { date: params.get(\"date\") } : {}),\n },\n };\n}\n"],"mappings":";AAwBA,SAAgB,IAAiC;CAC/C,IAAM,IAAM,OAAO,SAAS,MAEtB,IADe,OAAO,SAAS,SAAS,MAAM,IAAI,CAAC,OAAO,QAAQ,CACvC,MAAM,GAAG,EAAE,CAAC,KAAK,IAAI,IAAI,QACpD,IAAS,EACb,OAAO,SAAS,UAChB,OAAO,SAAS,OACjB;AAED,QAAO;EACL,YAAY;EACZ;EACA,YAAY,EAAO;EACnB,UAAU,EAAO;EACjB,UAAU;EACV,SAA6C;EAC7C,cAAc,GAAG,OAAO,WAAW,GAAG,OAAO;EAC7C,WAAW,UAAU;EACrB,4BAAW,IAAI,MAAM,EAAC,aAAa;EACpC;;AAGH,SAAS,EAAU,GAAiB,GAA2C;AAC7E,QAAO,EAAS,MAAM,EAAQ;;AAGhC,SAAgB,EACd,GACA,GAC0B;CAC1B,IAAM,IAAS,IAAI,gBAAgB,EAAO;AAiB1C,MAAK,IAAM,CAAC,GAAS,MAf0B;EAC7C,CAAC,4CAA4C,qBAAqB;EAClE,CAAC,yCAAyC,kBAAkB;EAC5D,CAAC,sCAAsC,qBAAqB;EAC5D,CACE,gDACA,8BACD;EACD,CAAC,6CAA6C,uBAAuB;EACrE,CACE,sDACA,2BACD;EACF,EAEkD;EACjD,IAAM,IAAQ,EAAU,GAAS,EAAS;AAC1C,MAAI,EACF,QAAO;GACL;GACA,UAAU,EAAM;GAChB,UAAU,EAAE,cAAc,EAAQ,QAAQ;GAC3C;;CAIL,IAAM,IACJ,EAAO,IAAI,MAAM,WACV;EACL,IAAM,IAAW,EAAS,MAAM,IAAI,CAAC,OAAO,QAAQ;AACpD,SAAO,EAAS,SAAS,IAAI,EAAS,EAAS,SAAS,KAAK,KAAA;KAC3D;AAEN,QAAO;EACL,WAAW,KAAa,KAAA;EACxB,UAAU;GACR,GAAI,IAAY,EAAE,cAAW,GAAG,EAAE;GAClC,GAAI,EAAO,IAAI,YAAY,GACvB,EAAE,WAAW,EAAO,IAAI,YAAY,EAAE,GACtC,EAAE;GACN,GAAI,EAAO,IAAI,OAAO,GAAG,EAAE,MAAM,EAAO,IAAI,OAAO,EAAE,GAAG,EAAE;GAC3D;EACF"}