@burdenoff/microfe-timecampus 2026.716.2 → 2026.719.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.
- package/dist/services/createSandboxAssistantTransport.d.ts +1 -1
- package/dist/services/createSandboxAssistantTransport.js +6 -4
- package/dist/services/createSandboxAssistantTransport.js.map +1 -1
- package/dist/utils/pageContext.d.ts +13 -5
- package/dist/utils/pageContext.d.ts.map +1 -1
- package/dist/utils/pageContext.js +61 -0
- package/dist/utils/pageContext.js.map +1 -0
- package/package.json +8 -3
|
@@ -16,7 +16,7 @@ export interface AssistantTransport {
|
|
|
16
16
|
sendPrompt: (args: AssistantSendArgs) => Promise<{
|
|
17
17
|
text: string;
|
|
18
18
|
}>;
|
|
19
|
-
prewarm?: (level?:
|
|
19
|
+
prewarm?: (level?: "probe" | "full") => void;
|
|
20
20
|
suspend?: () => void;
|
|
21
21
|
}
|
|
22
22
|
export declare function useSandboxAssistantTransport(): AssistantTransport;
|
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { gatherPageContext as e } from "../utils/pageContext.js";
|
|
2
|
+
import { useSandboxAssistantTransport as t } from "@burdenoff/fe-libs/shared/assistant";
|
|
2
3
|
//#region src/services/createSandboxAssistantTransport.ts
|
|
3
|
-
function
|
|
4
|
-
return
|
|
4
|
+
function n() {
|
|
5
|
+
return t({
|
|
5
6
|
product: "timecampus",
|
|
7
|
+
gatherPageContext: e,
|
|
6
8
|
enableCredits: !0
|
|
7
9
|
});
|
|
8
10
|
}
|
|
9
11
|
//#endregion
|
|
10
|
-
export {
|
|
12
|
+
export { n as useSandboxAssistantTransport };
|
|
11
13
|
|
|
12
14
|
//# 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 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
|
|
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\";\nimport { gatherPageContext } from \"../utils/pageContext\";\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 gatherPageContext,\n enableCredits: true,\n });\n}\n"],"mappings":";;;AAyBA,SAAgB,IAAmD;AACjE,QAAO,EAAmB;EACxB,SAAS;EACT;EACA,eAAe;EAChB,CAAC"}
|
|
@@ -1,11 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Page context gathering — captures the user's current browser context
|
|
3
3
|
* to be sent alongside every assistant prompt for better AI awareness.
|
|
4
|
+
*
|
|
5
|
+
* Only emit keys the agent's ALLOWED_CONTEXT_KEYS allow-list actually
|
|
6
|
+
* forwards (`~/products/wspace/sandbox/ai-assistant/src/context-loader.ts`):
|
|
7
|
+
* currentUrl, currentPage, entityType, entityId, entityName, pageTitle,
|
|
8
|
+
* pageType, activeTab, activeTool, selectedText, workspaceId, workspaceName,
|
|
9
|
+
* projectId, projectName (+ legacy per-product back-compat keys). `platform`
|
|
10
|
+
* and `version` are silently dropped server-side (the agent already knows
|
|
11
|
+
* the product from `AI_ASSISTANT_PRODUCT` at boot), and `userAgent` is sent
|
|
12
|
+
* over the wire but dropped agent-side — a needless fingerprinting leak for
|
|
13
|
+
* a privacy-first product. None of the five are emitted here.
|
|
4
14
|
*/
|
|
5
15
|
interface ConversationContextShape {
|
|
6
16
|
entityType?: string;
|
|
7
17
|
entityId?: string;
|
|
8
18
|
activeTab?: string;
|
|
19
|
+
projectId?: string;
|
|
9
20
|
metadata?: Record<string, unknown>;
|
|
10
21
|
}
|
|
11
22
|
export interface PageContext {
|
|
@@ -13,11 +24,8 @@ export interface PageContext {
|
|
|
13
24
|
currentPage: string;
|
|
14
25
|
entityType?: string;
|
|
15
26
|
entityId?: string;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
viewportSize: string;
|
|
19
|
-
userAgent: string;
|
|
20
|
-
timestamp: string;
|
|
27
|
+
activeTab?: string;
|
|
28
|
+
projectId?: string;
|
|
21
29
|
}
|
|
22
30
|
export declare function gatherPageContext(): PageContext;
|
|
23
31
|
export declare function resolveTimeCampusConversationContext(pathname: string, search: string): ConversationContextShape;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pageContext.d.ts","sourceRoot":"","sources":["../../src/utils/pageContext.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"pageContext.d.ts","sourceRoot":"","sources":["../../src/utils/pageContext.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,UAAU,wBAAwB;IAChC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,WAAW;IAG1B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IAGpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAGlB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,iBAAiB,IAAI,WAAW,CAiB/C;AAMD,wBAAgB,oCAAoC,CAClD,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,GACb,wBAAwB,CAoE1B"}
|
|
@@ -0,0 +1,61 @@
|
|
|
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
|
+
activeTab: r.activeTab,
|
|
10
|
+
projectId: r.projectId
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
function t(e, t) {
|
|
14
|
+
return t.match(e);
|
|
15
|
+
}
|
|
16
|
+
function n(e, n) {
|
|
17
|
+
let r = new URLSearchParams(n);
|
|
18
|
+
for (let [n, r] of [
|
|
19
|
+
[/^\/?timecampus\/time\/projects\/([^/]+)$/, "TIMECAMPUS_PROJECT"],
|
|
20
|
+
[/^\/?timecampus\/time\/tasks\/([^/]+)$/, "TIMECAMPUS_TASK"],
|
|
21
|
+
[/^\/?timecampus\/meetings\/([^/]+)$/, "TIMECAMPUS_MEETING"],
|
|
22
|
+
[/^\/?timecampus\/pomodoro\/sessions\/([^/]+)$/, "TIMECAMPUS_POMODORO_SESSION"],
|
|
23
|
+
[/^\/?timecampus\/lifetime\/goals\/([^/]+)$/, "TIMECAMPUS_LIFE_GOAL"],
|
|
24
|
+
[/^\/?timecampus\/resource-planning\/plans\/([^/]+)$/, "TIMECAMPUS_RESOURCE_PLAN"]
|
|
25
|
+
]) {
|
|
26
|
+
let i = t(n, e);
|
|
27
|
+
if (i) return {
|
|
28
|
+
entityType: r,
|
|
29
|
+
entityId: i[1],
|
|
30
|
+
metadata: { routePattern: n.source }
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
for (let [n, r] of [
|
|
34
|
+
[/^\/?timecampus\/timeline\/?$/, "TIMECAMPUS_TIMELINE"],
|
|
35
|
+
[/^\/?timecampus\/time\/entries\/?$/, "TIMECAMPUS_TIME_ENTRY"],
|
|
36
|
+
[/^\/?timecampus\/expense-tracking\/?$/, "TIMECAMPUS_EXPENSE"],
|
|
37
|
+
[/^\/?timecampus\/time-approval\/?$/, "TIMECAMPUS_APPROVAL"],
|
|
38
|
+
[/^\/?timecampus\/client-portal\/?$/, "TIMECAMPUS_CLIENT_PORTAL"],
|
|
39
|
+
[/^\/?timecampus\/application-usage\/?$/, "TIMECAMPUS_APP_USAGE"]
|
|
40
|
+
]) if (t(n, e)) return {
|
|
41
|
+
entityType: r,
|
|
42
|
+
metadata: { routePattern: n.source }
|
|
43
|
+
};
|
|
44
|
+
let i = r.get("tab") ?? (() => {
|
|
45
|
+
let t = e.split("/").filter(Boolean);
|
|
46
|
+
return t.length > 2 ? t[t.length - 1] : void 0;
|
|
47
|
+
})();
|
|
48
|
+
return {
|
|
49
|
+
activeTab: i ?? void 0,
|
|
50
|
+
projectId: r.get("projectId") ?? void 0,
|
|
51
|
+
metadata: {
|
|
52
|
+
...i ? { activeTab: i } : {},
|
|
53
|
+
...r.get("projectId") ? { projectId: r.get("projectId") } : {},
|
|
54
|
+
...r.get("date") ? { date: r.get("date") } : {}
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
//#endregion
|
|
59
|
+
export { e as gatherPageContext };
|
|
60
|
+
|
|
61
|
+
//# sourceMappingURL=pageContext.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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 * Only emit keys the agent's ALLOWED_CONTEXT_KEYS allow-list actually\n * forwards (`~/products/wspace/sandbox/ai-assistant/src/context-loader.ts`):\n * currentUrl, currentPage, entityType, entityId, entityName, pageTitle,\n * pageType, activeTab, activeTool, selectedText, workspaceId, workspaceName,\n * projectId, projectName (+ legacy per-product back-compat keys). `platform`\n * and `version` are silently dropped server-side (the agent already knows\n * the product from `AI_ASSISTANT_PRODUCT` at boot), and `userAgent` is sent\n * over the wire but dropped agent-side — a needless fingerprinting leak for\n * a privacy-first product. None of the five are emitted here.\n */\n\ninterface ConversationContextShape {\n entityType?: string;\n entityId?: string;\n activeTab?: string;\n projectId?: string;\n metadata?: Record<string, unknown>;\n}\n\nexport interface PageContext {\n // `currentUrl` (NOT `activeUrl`) — must match the agent's allowed-context-key\n // contract, otherwise the agent filters it out.\n currentUrl: string;\n currentPage: string;\n // The entity the user is currently looking at, resolved from the route. Lets\n // the assistant act on \"this / current / here\" without asking for an id.\n entityType?: string;\n entityId?: string;\n // Surfaced separately from `metadata` so the allow-listed `activeTab` /\n // `projectId` keys actually reach the agent instead of being discarded.\n activeTab?: string;\n projectId?: 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 activeTab: entity.activeTab,\n projectId: entity.projectId,\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 // Page-level matches: these TimeCampus modules are flat list/dashboard\n // pages with no per-entity detail route (confirmed against\n // TimeCampusRoutes.tsx), so there is no id to capture — but the assistant\n // still benefits from knowing which module the user is looking at, so it\n // can scope \"show me my expenses\" / \"approve this\" style prompts without\n // asking which module the user means.\n const pageLevelMatches: Array<[RegExp, string]> = [\n [/^\\/?timecampus\\/timeline\\/?$/, \"TIMECAMPUS_TIMELINE\"],\n [/^\\/?timecampus\\/time\\/entries\\/?$/, \"TIMECAMPUS_TIME_ENTRY\"],\n [/^\\/?timecampus\\/expense-tracking\\/?$/, \"TIMECAMPUS_EXPENSE\"],\n [/^\\/?timecampus\\/time-approval\\/?$/, \"TIMECAMPUS_APPROVAL\"],\n [/^\\/?timecampus\\/client-portal\\/?$/, \"TIMECAMPUS_CLIENT_PORTAL\"],\n [/^\\/?timecampus\\/application-usage\\/?$/, \"TIMECAMPUS_APP_USAGE\"],\n ];\n\n for (const [pattern, entityType] of pageLevelMatches) {\n if (matchPath(pattern, pathname)) {\n return { entityType, metadata: { routePattern: pattern.source } };\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 projectId: params.get(\"projectId\") ?? 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":";AAsCA,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,WAAW,EAAO;EAClB,WAAW,EAAO;EACnB;;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;;AAmBL,MAAK,IAAM,CAAC,GAAS,MAT6B;EAChD,CAAC,gCAAgC,sBAAsB;EACvD,CAAC,qCAAqC,wBAAwB;EAC9D,CAAC,wCAAwC,qBAAqB;EAC9D,CAAC,qCAAqC,sBAAsB;EAC5D,CAAC,qCAAqC,2BAA2B;EACjE,CAAC,yCAAyC,uBAAuB;EAClE,CAGC,KAAI,EAAU,GAAS,EAAS,CAC9B,QAAO;EAAE;EAAY,UAAU,EAAE,cAAc,EAAQ,QAAQ;EAAE;CAIrE,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,WAAW,EAAO,IAAI,YAAY,IAAI,KAAA;EACtC,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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@burdenoff/microfe-timecampus",
|
|
3
|
-
"version": "2026.
|
|
3
|
+
"version": "2026.719.1",
|
|
4
4
|
"description": "Burdenoff TimeCampus Microfrontend - AI-powered time management and productivity platform",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -31,7 +31,10 @@
|
|
|
31
31
|
"lint:sanity": "if [ \"${CI:-}\" = \"true\" ]; then bun run lint; else bun run lint -- --cache --cache-location .eslintcache; fi",
|
|
32
32
|
"format": "prettier --write \"src/**/*.{ts,tsx}\"",
|
|
33
33
|
"type:check": "tsc --noEmit",
|
|
34
|
-
"
|
|
34
|
+
"test": "vitest run",
|
|
35
|
+
"test:watch": "vitest",
|
|
36
|
+
"test:coverage": "vitest run --coverage",
|
|
37
|
+
"sanity": "bun run codegen && bun run lint:sanity && bun run format && bun run type:check && bun run test && bun run build && bun run build-storybook",
|
|
35
38
|
"storybook": "storybook dev -p 6006",
|
|
36
39
|
"build-storybook": "storybook build",
|
|
37
40
|
"test:storybook": "test-storybook",
|
|
@@ -80,6 +83,7 @@
|
|
|
80
83
|
"@types/react": "^19.0.2",
|
|
81
84
|
"@types/react-dom": "^19.0.2",
|
|
82
85
|
"@vitejs/plugin-react": "^4.3.4",
|
|
86
|
+
"@vitest/coverage-v8": "3.2.7",
|
|
83
87
|
"autoprefixer": "^10.4.20",
|
|
84
88
|
"eslint": "^9.18.0",
|
|
85
89
|
"eslint-plugin-react": "^7.37.5",
|
|
@@ -94,7 +98,8 @@
|
|
|
94
98
|
"typescript": "^5.9.0",
|
|
95
99
|
"typescript-eslint": "^8.56.0",
|
|
96
100
|
"vite": "8.0.8",
|
|
97
|
-
"vite-plugin-dts": "3.9.1"
|
|
101
|
+
"vite-plugin-dts": "3.9.1",
|
|
102
|
+
"vitest": "3.2.7"
|
|
98
103
|
},
|
|
99
104
|
"peerDependencies": {
|
|
100
105
|
"@apollo/client": "^4.0.11",
|