@burdenoff/fe-libs 2026.1004.2 → 2026.1004.4
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/chrome/mobileTabBar/useVisibleNavItems.d.ts +9 -0
- package/dist/chrome/mobileTabBar/useVisibleNavItems.d.ts.map +1 -1
- package/dist/chrome/mobileTabBar/useVisibleNavItems.js +3 -1
- package/dist/shared/assistant/api.d.ts +6 -0
- package/dist/shared/assistant/api.d.ts.map +1 -1
- package/dist/shared/assistant/api.js +5 -3
- package/dist/shared/assistant/i18nManifest.d.ts +3 -0
- package/dist/shared/assistant/i18nManifest.d.ts.map +1 -1
- package/dist/shared/assistant/i18nManifest.js +3 -0
- package/dist/shared/assistant/index.d.ts +8 -0
- package/dist/shared/assistant/index.d.ts.map +1 -1
- package/dist/shared/assistant/localUiCommandCopy.d.ts +18 -0
- package/dist/shared/assistant/localUiCommandCopy.d.ts.map +1 -1
- package/dist/shared/assistant/localUiCommandCopy.js +22 -2
- package/dist/shared/assistant/localUiCommands.d.ts +63 -26
- package/dist/shared/assistant/localUiCommands.d.ts.map +1 -1
- package/dist/shared/assistant/localUiCommands.js +128 -59
- package/dist/shared/assistant/ui/AssistantChatArea.d.ts.map +1 -1
- package/dist/shared/assistant/ui/AssistantChatArea.js +884 -750
- package/dist/shared/assistant/ui/AssistantMarkdownRenderer.d.ts +3 -34
- package/dist/shared/assistant/ui/AssistantMarkdownRenderer.d.ts.map +1 -1
- package/dist/shared/assistant/ui/AssistantMarkdownRenderer.js +83 -119
- package/dist/shared/assistant/ui/composer/AssistantConnectSourceItem.js +2 -1
- package/dist/shared/assistant/ui/composer/connectSource.js +2 -1
- package/dist/shared/assistant/uiActions/assistantHref.d.ts +36 -0
- package/dist/shared/assistant/uiActions/assistantHref.d.ts.map +1 -0
- package/dist/shared/assistant/uiActions/assistantHref.js +46 -0
- package/dist/shared/assistant/uiActions/deixis.d.ts +29 -0
- package/dist/shared/assistant/uiActions/deixis.d.ts.map +1 -0
- package/dist/shared/assistant/uiActions/deixis.js +54 -0
- package/dist/shared/assistant/uiActions/entityRoutes.d.ts +49 -0
- package/dist/shared/assistant/uiActions/entityRoutes.d.ts.map +1 -0
- package/dist/shared/assistant/uiActions/entityRoutes.js +53 -0
- package/dist/shared/assistant/uiActions/inAppLinks.d.ts +28 -0
- package/dist/shared/assistant/uiActions/inAppLinks.d.ts.map +1 -0
- package/dist/shared/assistant/uiActions/inAppLinks.js +51 -0
- package/dist/shared/assistant/uiActions/linkContext.d.ts +52 -0
- package/dist/shared/assistant/uiActions/linkContext.d.ts.map +1 -0
- package/dist/shared/assistant/uiActions/linkContext.js +60 -0
- package/dist/shared/assistant/uiActions/recordNames.d.ts +73 -0
- package/dist/shared/assistant/uiActions/recordNames.d.ts.map +1 -0
- package/dist/shared/assistant/uiActions/recordNames.js +75 -0
- package/dist/shared/assistant/uiActions/resolveTarget.d.ts +43 -0
- package/dist/shared/assistant/uiActions/resolveTarget.d.ts.map +1 -0
- package/dist/shared/assistant/uiActions/resolveTarget.js +49 -0
- package/dist/shared/assistant/uiActions/uiCatalogue.d.ts +30 -0
- package/dist/shared/assistant/uiActions/uiCatalogue.d.ts.map +1 -0
- package/dist/shared/assistant/uiActions/uiCatalogue.js +22 -0
- package/dist/shared/components/assistantWidget/MessageContent.js +4 -3
- package/dist/shared/tours/TourPlayerProvider.d.ts +12 -0
- package/dist/shared/tours/TourPlayerProvider.d.ts.map +1 -1
- package/dist/shared/tours/TourPlayerProvider.js +1 -1
- package/dist/shared/tours/tourTrigger/MobileTourSheet.d.ts.map +1 -1
- package/dist/shared/tours/tourTrigger/MobileTourSheet.js +16 -15
- package/dist/shared-assistant.js +198 -190
- package/package.json +3 -1
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ★ BOFF-8060 (N1b, C4b-lite): product-declared ENTITY routes — pages of one
|
|
3
|
+
* record (`/bigconsole/dashboards/:id`) that no sidebar entry names, so
|
|
4
|
+
* "take me there" cannot find them in the navigation. A product declares the
|
|
5
|
+
* templates it owns; the matcher below is the only thing that ever treats a
|
|
6
|
+
* path as one.
|
|
7
|
+
*
|
|
8
|
+
* PURE: no React, no DOM. The default is NO routes, so every product behaves
|
|
9
|
+
* as before until it supplies some.
|
|
10
|
+
*
|
|
11
|
+
* ★★ WHY THE `exclude` LISTS EXIST. A template like `/healthybowl/crops/:id`
|
|
12
|
+
* also matches `/healthybowl/crops/fields`, which is a STATIC page of the
|
|
13
|
+
* router and not a crop. Every param lists the router's static siblings it must
|
|
14
|
+
* never swallow. A router guard test in each app renders every template and
|
|
15
|
+
* every static sibling to prove the two lists agree with the real router.
|
|
16
|
+
*/
|
|
17
|
+
export type EntityParamKind = "id" | "slug" | "int";
|
|
18
|
+
export interface EntityParam {
|
|
19
|
+
kind: EntityParamKind;
|
|
20
|
+
/** Static sibling segments of the router this param must never match (case-insensitive: the router is). */
|
|
21
|
+
exclude?: readonly string[];
|
|
22
|
+
}
|
|
23
|
+
export interface AssistantEntityRoute {
|
|
24
|
+
/** Stable id, e.g. `bigconsole-dashboard`. The resolved target is `entity:<id>`. */
|
|
25
|
+
id: string;
|
|
26
|
+
/** A path template: `/bigconsole/dashboards/:id`. A segment starting `:` is a param. */
|
|
27
|
+
pattern: string;
|
|
28
|
+
/** One entry per param in `pattern`. */
|
|
29
|
+
params: Readonly<Record<string, EntityParam>>;
|
|
30
|
+
/**
|
|
31
|
+
* The id of a navigation entry the person must be able to SEE (the whole
|
|
32
|
+
* visible tree, groups included) for this route to resolve. Absent: a
|
|
33
|
+
* product-declared static route, which resolves for everyone who reaches it.
|
|
34
|
+
*/
|
|
35
|
+
visibleWith?: string;
|
|
36
|
+
/** What the page is called in a sentence: `{ key: "entity.dashboard", fallback: "dashboard" }`. */
|
|
37
|
+
noun: {
|
|
38
|
+
key: string;
|
|
39
|
+
fallback: string;
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
export interface EntityMatch {
|
|
43
|
+
route: AssistantEntityRoute;
|
|
44
|
+
params: Record<string, string>;
|
|
45
|
+
}
|
|
46
|
+
export declare function matchEntityRoute(path: string, routes: readonly AssistantEntityRoute[]): EntityMatch | null;
|
|
47
|
+
/** Fill a template with params, or null when one is missing or invalid. Used by record adapters. */
|
|
48
|
+
export declare function fillEntityRoute(route: AssistantEntityRoute, params: Readonly<Record<string, string>>): string | null;
|
|
49
|
+
//# sourceMappingURL=entityRoutes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entityRoutes.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/uiActions/entityRoutes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,MAAM,eAAe,GAAG,IAAI,GAAG,MAAM,GAAG,KAAK,CAAC;AAEpD,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,eAAe,CAAC;IACtB,2GAA2G;IAC3G,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC7B;AAED,MAAM,WAAW,oBAAoB;IACnC,oFAAoF;IACpF,EAAE,EAAE,MAAM,CAAC;IACX,wFAAwF;IACxF,OAAO,EAAE,MAAM,CAAC;IAChB,wCAAwC;IACxC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;IAC9C;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mGAAmG;IACnG,IAAI,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;CACzC;AAoBD,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,oBAAoB,CAAC;IAC5B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAChC;AAeD,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,SAAS,oBAAoB,EAAE,GACtC,WAAW,GAAG,IAAI,CA8BpB;AAED,oGAAoG;AACpG,wBAAgB,eAAe,CAC7B,KAAK,EAAE,oBAAoB,EAC3B,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GACvC,MAAM,GAAG,IAAI,CAef"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
//#region src/shared/assistant/uiActions/entityRoutes.ts
|
|
2
|
+
var e = {
|
|
3
|
+
id: /^[A-Za-z0-9_-]{1,128}$/,
|
|
4
|
+
slug: /^[A-Za-z0-9_.-]{1,128}$/,
|
|
5
|
+
int: /^[0-9]{1,9}$/
|
|
6
|
+
};
|
|
7
|
+
function t(t, n) {
|
|
8
|
+
return !(!e[t].test(n) || t === "slug" && (n === "." || n === ".." || n.includes("..")));
|
|
9
|
+
}
|
|
10
|
+
function n(e) {
|
|
11
|
+
if (!e.startsWith("/") || e.startsWith("//") || e.includes("?") || e.includes("#") || /%(?:2f|5c|2e)/i.test(e) || e.includes("\\")) return null;
|
|
12
|
+
let t = (e.length > 1 && e.endsWith("/") ? e.slice(0, -1) : e).slice(1).split("/");
|
|
13
|
+
return t.some((e) => e === "") ? null : t;
|
|
14
|
+
}
|
|
15
|
+
function r(e, r) {
|
|
16
|
+
let i = n(e);
|
|
17
|
+
if (i === null) return null;
|
|
18
|
+
for (let e of r) {
|
|
19
|
+
let n = e.pattern.slice(1).split("/");
|
|
20
|
+
if (n.length !== i.length) continue;
|
|
21
|
+
let r = {}, a = !0;
|
|
22
|
+
for (let o = 0; o < n.length && a; o += 1) {
|
|
23
|
+
let s = n[o] ?? "", c = i[o] ?? "";
|
|
24
|
+
if (!s.startsWith(":")) {
|
|
25
|
+
a = s.toLowerCase() === c.toLowerCase();
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
let l = s.slice(1), u = e.params[l];
|
|
29
|
+
a = u !== void 0 && t(u.kind, c) && !(u.exclude ?? []).some((e) => e.toLowerCase() === c.toLowerCase()), a && (r[l] = c);
|
|
30
|
+
}
|
|
31
|
+
if (a) return {
|
|
32
|
+
route: e,
|
|
33
|
+
params: r
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
function i(e, t) {
|
|
39
|
+
let n = [];
|
|
40
|
+
for (let r of e.pattern.slice(1).split("/")) {
|
|
41
|
+
if (!r.startsWith(":")) {
|
|
42
|
+
n.push(r);
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
let e = t[r.slice(1)];
|
|
46
|
+
if (e === void 0) return null;
|
|
47
|
+
n.push(e);
|
|
48
|
+
}
|
|
49
|
+
let i = `/${n.join("/")}`;
|
|
50
|
+
return r(i, [e]) ? i : null;
|
|
51
|
+
}
|
|
52
|
+
//#endregion
|
|
53
|
+
export { i as fillEntityRoute, r as matchEntityRoute };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ★ BOFF-8060 (N1b, C3b-link): the in-app links of one assistant reply, in the
|
|
3
|
+
* order the person reads them. "Take me there" acts on exactly these.
|
|
4
|
+
*
|
|
5
|
+
* PURE: markdown text in, paths out — no React and no DOM. It parses with the
|
|
6
|
+
* parser react-markdown 10 uses (`remark-parse` + `remark-gfm`), and judges
|
|
7
|
+
* every href with the SAME functions the renderer judges it with
|
|
8
|
+
* (`assistantUrlTransform`, `classifyAssistantHref`, `assistantRoutePath`), so
|
|
9
|
+
* a link is "in-app" here exactly when the renderer draws it as an in-app
|
|
10
|
+
* anchor. A parity test renders a corpus through the real renderer and
|
|
11
|
+
* compares the two sets.
|
|
12
|
+
*
|
|
13
|
+
* What is NOT a link the person can click, and so is never acted on:
|
|
14
|
+
* - code (fenced or inline) and raw HTML — the renderer prints them as text;
|
|
15
|
+
* - an image (a picture is not a link; `` has no anchor);
|
|
16
|
+
* - a reference whose definition does not exist;
|
|
17
|
+
* - an href the policy blocks, or one that leaves the app (external, a
|
|
18
|
+
* protocol-relative `//host`, `/\host`).
|
|
19
|
+
*/
|
|
20
|
+
export interface InAppLink {
|
|
21
|
+
/** What the link says, at most `LINK_TEXT_MAX` characters (the path when it says nothing). */
|
|
22
|
+
text: string;
|
|
23
|
+
/** The router path: pathname + search + hash, never an absolute URL. */
|
|
24
|
+
path: string;
|
|
25
|
+
}
|
|
26
|
+
export declare const LINK_TEXT_MAX = 80;
|
|
27
|
+
export declare function extractInAppLinks(markdown: string): InAppLink[];
|
|
28
|
+
//# sourceMappingURL=inAppLinks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inAppLinks.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/uiActions/inAppLinks.ts"],"names":[],"mappings":"AAUA;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,WAAW,SAAS;IACxB,8FAA8F;IAC9F,IAAI,EAAE,MAAM,CAAC;IACb,wEAAwE;IACxE,IAAI,EAAE,MAAM,CAAC;CACd;AAED,eAAO,MAAM,aAAa,KAAK,CAAC;AA0DhC,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAAE,CA0B/D"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import e from "../../../node_modules/remark-parse/lib/index.js";
|
|
2
|
+
import { unified as t } from "../../../node_modules/unified/lib/index.js";
|
|
3
|
+
import n from "../../../node_modules/remark-gfm/lib/index.js";
|
|
4
|
+
import { assistantRoutePath as r, classifyAssistantHref as i, transformAssistantUrl as a } from "./assistantHref.js";
|
|
5
|
+
//#region src/shared/assistant/uiActions/inAppLinks.ts
|
|
6
|
+
var o = 80, s = t().use(e).use(n), c = (e) => e.trim().replace(/\s+/g, " ").toLowerCase(), l = new Set([
|
|
7
|
+
"code",
|
|
8
|
+
"inlineCode",
|
|
9
|
+
"html",
|
|
10
|
+
"image",
|
|
11
|
+
"imageReference",
|
|
12
|
+
"definition"
|
|
13
|
+
]);
|
|
14
|
+
function u(e) {
|
|
15
|
+
return e.type === "text" || e.type === "inlineCode" ? e.value ?? "" : e.type === "image" || e.type === "imageReference" ? e.alt ?? "" : (e.children ?? []).map(u).join("");
|
|
16
|
+
}
|
|
17
|
+
function d(e, t) {
|
|
18
|
+
if (e.type === "definition" && e.identifier !== void 0 && e.url !== void 0) {
|
|
19
|
+
let n = c(e.identifier);
|
|
20
|
+
t.has(n) || t.set(n, e.url);
|
|
21
|
+
}
|
|
22
|
+
for (let n of e.children ?? []) d(n, t);
|
|
23
|
+
}
|
|
24
|
+
function f(e) {
|
|
25
|
+
let t = a(e, "href", "a");
|
|
26
|
+
return i(t) === "internal" ? r(t) : null;
|
|
27
|
+
}
|
|
28
|
+
function p(e) {
|
|
29
|
+
if (!e.trim()) return [];
|
|
30
|
+
let t = s.parse(e), n = /* @__PURE__ */ new Map();
|
|
31
|
+
d(t, n);
|
|
32
|
+
let r = [], i = /* @__PURE__ */ new Set(), a = (e) => {
|
|
33
|
+
if (l.has(e.type)) return;
|
|
34
|
+
let t;
|
|
35
|
+
if (e.type === "link" ? t = e.url : e.type === "linkReference" && e.identifier !== void 0 && (t = n.get(c(e.identifier))), t !== void 0) {
|
|
36
|
+
let n = f(t);
|
|
37
|
+
if (n !== null && !i.has(n)) {
|
|
38
|
+
i.add(n);
|
|
39
|
+
let t = u(e).replace(/\s+/g, " ").trim();
|
|
40
|
+
r.push({
|
|
41
|
+
text: (t || n).slice(0, 80),
|
|
42
|
+
path: n
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
for (let t of e.children ?? []) a(t);
|
|
47
|
+
};
|
|
48
|
+
return a(t), r;
|
|
49
|
+
}
|
|
50
|
+
//#endregion
|
|
51
|
+
export { o as LINK_TEXT_MAX, p as extractInAppLinks };
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { LocalDestination } from '../localUiCommands';
|
|
2
|
+
import { ResolveContext, ResolvedLinks } from './resolveTarget';
|
|
3
|
+
/**
|
|
4
|
+
* ★ BOFF-8060 (N1b): what "take me there" and "the second one" act on, built
|
|
5
|
+
* LIVE at send time from the conversation — never from render state, never
|
|
6
|
+
* from a re-query of the registry for candidates.
|
|
7
|
+
*
|
|
8
|
+
* Both are limited to the NEWEST assistant message on the surface the command
|
|
9
|
+
* came from (chat thread for a typed command, that voice session's spoken
|
|
10
|
+
* turns for a spoken one) and only while no later person message exists there.
|
|
11
|
+
* A hidden reply from another conversation, an older reply and a reply of the
|
|
12
|
+
* other surface are never read.
|
|
13
|
+
*/
|
|
14
|
+
export interface SurfaceMessage {
|
|
15
|
+
id: string;
|
|
16
|
+
role: string;
|
|
17
|
+
metadata?: ({
|
|
18
|
+
voice?: boolean;
|
|
19
|
+
voiceSessionId?: string;
|
|
20
|
+
localAction?: unknown;
|
|
21
|
+
} & Record<string, unknown>) | undefined;
|
|
22
|
+
}
|
|
23
|
+
/** The newest assistant message on the surface, or null when a person message came after it. */
|
|
24
|
+
export declare function latestReplyOnSurface<T extends SurfaceMessage>(messages: readonly T[], voiceSessionId: string | undefined): T | null;
|
|
25
|
+
export declare function rememberPresentedList(messageId: string, candidates: readonly LocalDestination[]): void;
|
|
26
|
+
export declare const presentedListFor: (messageId: string) => LocalDestination[] | undefined;
|
|
27
|
+
/** @internal for tests */
|
|
28
|
+
export declare const clearPresentedLists: () => void;
|
|
29
|
+
export interface PendingChoice {
|
|
30
|
+
/** One entry per line shown; null where that line can no longer be opened. null overall: unreadable (an entity list after a reload). */
|
|
31
|
+
candidates: ReadonlyArray<LocalDestination | null> | null;
|
|
32
|
+
/**
|
|
33
|
+
* The ids the list's record carries, kept so a reply that merely points at an
|
|
34
|
+
* unreadable list can keep it pending (the next pick must not reach a model
|
|
35
|
+
* that never saw the list either).
|
|
36
|
+
*/
|
|
37
|
+
candidateIds: readonly string[];
|
|
38
|
+
}
|
|
39
|
+
export interface NavigationContext {
|
|
40
|
+
links: ResolvedLinks;
|
|
41
|
+
pendingChoice: PendingChoice | null;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* @param text what the person SEES of the message (`spokenTurnText`), never raw
|
|
45
|
+
* content: a link inside a tool-step description is not a link they saw.
|
|
46
|
+
*/
|
|
47
|
+
export declare function buildNavigationContext(input: {
|
|
48
|
+
reply: SurfaceMessage | null;
|
|
49
|
+
text: string;
|
|
50
|
+
resolve: ResolveContext;
|
|
51
|
+
}): NavigationContext | null;
|
|
52
|
+
//# sourceMappingURL=linkContext.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"linkContext.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/uiActions/linkContext.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE3D,OAAO,EAIL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,iBAAiB,CAAC;AAEzB;;;;;;;;;;GAUG;AACH,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EACL,CAAC;QACC,KAAK,CAAC,EAAE,OAAO,CAAC;QAChB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,WAAW,CAAC,EAAE,OAAO,CAAC;KACvB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAC5B,SAAS,CAAC;CACf;AAYD,gGAAgG;AAChG,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,cAAc,EAC3D,QAAQ,EAAE,SAAS,CAAC,EAAE,EACtB,cAAc,EAAE,MAAM,GAAG,SAAS,GACjC,CAAC,GAAG,IAAI,CAQV;AAaD,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,SAAS,gBAAgB,EAAE,GACtC,IAAI,CAWN;AAED,eAAO,MAAM,gBAAgB,GAC3B,WAAW,MAAM,KAChB,gBAAgB,EAAE,GAAG,SAAqC,CAAC;AAE9D,0BAA0B;AAC1B,eAAO,MAAM,mBAAmB,QAAO,IAAyB,CAAC;AAIjE,MAAM,WAAW,aAAa;IAC5B,wIAAwI;IACxI,UAAU,EAAE,aAAa,CAAC,gBAAgB,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;IAC1D;;;;OAIG;IACH,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;CACjC;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,aAAa,CAAC;IACrB,aAAa,EAAE,aAAa,GAAG,IAAI,CAAC;CACrC;AAiDD;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE;IAC5C,KAAK,EAAE,cAAc,GAAG,IAAI,CAAC;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,cAAc,CAAC;CACzB,GAAG,iBAAiB,GAAG,IAAI,CAI3B"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { isEntityTarget as e, resolveInAppLinks as t, resolveUiTarget as n } from "./resolveTarget.js";
|
|
2
|
+
import { extractInAppLinks as r } from "./inAppLinks.js";
|
|
3
|
+
//#region src/shared/assistant/uiActions/linkContext.ts
|
|
4
|
+
var i = (e, t) => {
|
|
5
|
+
let n = e.metadata?.voice === !0;
|
|
6
|
+
return t === void 0 ? !n : n && e.metadata?.voiceSessionId === t;
|
|
7
|
+
};
|
|
8
|
+
function a(e, t) {
|
|
9
|
+
for (let n = e.length - 1; n >= 0; --n) {
|
|
10
|
+
let r = e[n];
|
|
11
|
+
if (!(!r || !i(r, t))) {
|
|
12
|
+
if (r.role === "user") return null;
|
|
13
|
+
if (r.role === "assistant") return r;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
var o = 50, s = /* @__PURE__ */ new Map();
|
|
19
|
+
function c(e, t) {
|
|
20
|
+
for (s.delete(e), s.set(e, t.map((e) => ({ ...e }))); s.size > o;) {
|
|
21
|
+
let e = s.keys().next();
|
|
22
|
+
if (e.done) break;
|
|
23
|
+
s.delete(e.value);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
var l = (e) => s.get(e), u = () => s.clear(), d = null, f = (e) => {
|
|
27
|
+
if (d?.text === e) return d.links;
|
|
28
|
+
let t = r(e);
|
|
29
|
+
return d = {
|
|
30
|
+
text: e,
|
|
31
|
+
links: t
|
|
32
|
+
}, t;
|
|
33
|
+
};
|
|
34
|
+
function p(t, r) {
|
|
35
|
+
let i = t.metadata?.localAction;
|
|
36
|
+
if (typeof i != "object" || !i) return null;
|
|
37
|
+
let a = i;
|
|
38
|
+
if (a.kind !== "choose-destination") return null;
|
|
39
|
+
let o = l(t.id);
|
|
40
|
+
if (o) return {
|
|
41
|
+
candidates: o.map((t) => n(t.path, r, e(t) ? t.label : void 0)),
|
|
42
|
+
candidateIds: o.map((e) => e.id)
|
|
43
|
+
};
|
|
44
|
+
let s = Array.isArray(a.candidateIds) ? a.candidateIds : [], c = s.filter((e) => typeof e == "string"), u = s.map((e) => typeof e == "string" ? r.destinations.find((t) => t.id === e) ?? null : null);
|
|
45
|
+
return u.length === 0 || u.some((e) => e === null) ? {
|
|
46
|
+
candidates: null,
|
|
47
|
+
candidateIds: c
|
|
48
|
+
} : {
|
|
49
|
+
candidates: u,
|
|
50
|
+
candidateIds: c
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
function m(e) {
|
|
54
|
+
return e.reply ? {
|
|
55
|
+
links: t(f(e.text), e.resolve),
|
|
56
|
+
pendingChoice: p(e.reply, e.resolve)
|
|
57
|
+
} : null;
|
|
58
|
+
}
|
|
59
|
+
//#endregion
|
|
60
|
+
export { m as buildNavigationContext, u as clearPresentedLists, a as latestReplyOnSurface, l as presentedListFor, c as rememberPresentedList };
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { LocalDestination } from '../localUiCommands';
|
|
2
|
+
import { AssistantEntityRoute } from './entityRoutes';
|
|
3
|
+
/**
|
|
4
|
+
* ★ BOFF-8060 (N1b, named records): "open the Coffee Shop Sales dashboard".
|
|
5
|
+
*
|
|
6
|
+
* A PRODUCT ADAPTER knows how to look one kind of record up by name through the
|
|
7
|
+
* product's own (RBAC-filtered) API; this module is the PURE half — the grammar
|
|
8
|
+
* that recognises such a request and the plan that turns the adapters' answers
|
|
9
|
+
* into "open it", "which of these?" or "nothing found". Nothing here reaches
|
|
10
|
+
* the network.
|
|
11
|
+
*
|
|
12
|
+
* Rules that keep it safe:
|
|
13
|
+
* - an adapter can only produce a path by FILLING an entity route the product
|
|
14
|
+
* declared (`fillEntityRoute` re-validates it), never an arbitrary string;
|
|
15
|
+
* - the route's `visibleWith` navigation entry must be in the person's visible
|
|
16
|
+
* tree, or the adapter is not consulted at all;
|
|
17
|
+
* - no match is NOT an answer: the sentence goes to the model as before.
|
|
18
|
+
*/
|
|
19
|
+
export interface AssistantRecordMatch {
|
|
20
|
+
/** The route params that identify the record (`{ id: "…" }`). */
|
|
21
|
+
params: Readonly<Record<string, string>>;
|
|
22
|
+
/** The record's own name, as the person sees it in the app. */
|
|
23
|
+
name: string;
|
|
24
|
+
}
|
|
25
|
+
export interface AssistantRecordAdapter {
|
|
26
|
+
/** Stable id, e.g. `bigconsole-dashboard`. */
|
|
27
|
+
id: string;
|
|
28
|
+
/** What people call the kind, lower case, singular and plural: `["dashboard", "dashboards"]`. */
|
|
29
|
+
nouns: readonly string[];
|
|
30
|
+
/** The kind's name in a sentence (translated): `{ key: "entity.dashboard", fallback: "dashboard" }`. */
|
|
31
|
+
noun: {
|
|
32
|
+
key: string;
|
|
33
|
+
fallback: string;
|
|
34
|
+
};
|
|
35
|
+
/** The id of the `AssistantEntityRoute` a match opens. */
|
|
36
|
+
entityRouteId: string;
|
|
37
|
+
/**
|
|
38
|
+
* The records this person may open whose name fits `name`. Called only for a
|
|
39
|
+
* recognised request. A rejection counts as "none found"; it is aborted when
|
|
40
|
+
* the panel stops waiting.
|
|
41
|
+
*/
|
|
42
|
+
find: (name: string, signal: AbortSignal) => Promise<readonly AssistantRecordMatch[]>;
|
|
43
|
+
}
|
|
44
|
+
export interface RecordRequest {
|
|
45
|
+
/** The name as said, lower case. */
|
|
46
|
+
name: string;
|
|
47
|
+
/** Adapters named by the sentence's noun; empty: every adapter. */
|
|
48
|
+
adapterIds: string[];
|
|
49
|
+
}
|
|
50
|
+
export declare function parseRecordRequest(utterance: string, adapters: readonly Pick<AssistantRecordAdapter, "id" | "nouns">[]): RecordRequest | null;
|
|
51
|
+
export interface RecordAnswer {
|
|
52
|
+
adapter: Pick<AssistantRecordAdapter, "id">;
|
|
53
|
+
route: AssistantEntityRoute;
|
|
54
|
+
/** The kind's translated name. */
|
|
55
|
+
noun: string;
|
|
56
|
+
matches: readonly AssistantRecordMatch[];
|
|
57
|
+
}
|
|
58
|
+
export type RecordPlan = {
|
|
59
|
+
kind: "none";
|
|
60
|
+
} | {
|
|
61
|
+
kind: "open";
|
|
62
|
+
destination: LocalDestination;
|
|
63
|
+
} | {
|
|
64
|
+
kind: "choose";
|
|
65
|
+
/** `kinds`: the same name in different kinds of record; `records`: several of one kind. */
|
|
66
|
+
why: "kinds" | "records";
|
|
67
|
+
candidates: LocalDestination[];
|
|
68
|
+
/** The distinct kind names among the candidates, in order. */
|
|
69
|
+
nouns: string[];
|
|
70
|
+
};
|
|
71
|
+
export declare const RECORD_CHOICE_MAX = 4;
|
|
72
|
+
export declare function planRecordResolution(name: string, answers: readonly RecordAnswer[]): RecordPlan;
|
|
73
|
+
//# sourceMappingURL=recordNames.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recordNames.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/uiActions/recordNames.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAmB,KAAK,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAG5E;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,oBAAoB;IACnC,iEAAiE;IACjE,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACzC,+DAA+D;IAC/D,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,sBAAsB;IACrC,8CAA8C;IAC9C,EAAE,EAAE,MAAM,CAAC;IACX,iGAAiG;IACjG,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,wGAAwG;IACxG,IAAI,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IACxC,0DAA0D;IAC1D,aAAa,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,IAAI,EAAE,CACJ,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,WAAW,KAChB,OAAO,CAAC,SAAS,oBAAoB,EAAE,CAAC,CAAC;CAC/C;AAED,MAAM,WAAW,aAAa;IAC5B,oCAAoC;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,mEAAmE;IACnE,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AA4CD,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,SAAS,IAAI,CAAC,sBAAsB,EAAE,IAAI,GAAG,OAAO,CAAC,EAAE,GAChE,aAAa,GAAG,IAAI,CA6CtB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,IAAI,CAAC,sBAAsB,EAAE,IAAI,CAAC,CAAC;IAC5C,KAAK,EAAE,oBAAoB,CAAC;IAC5B,kCAAkC;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,SAAS,oBAAoB,EAAE,CAAC;CAC1C;AAED,MAAM,MAAM,UAAU,GAClB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,gBAAgB,CAAA;CAAE,GAC/C;IACE,IAAI,EAAE,QAAQ,CAAC;IACf,2FAA2F;IAC3F,GAAG,EAAE,OAAO,GAAG,SAAS,CAAC;IACzB,UAAU,EAAE,gBAAgB,EAAE,CAAC;IAC/B,8DAA8D;IAC9D,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB,CAAC;AAEN,eAAO,MAAM,iBAAiB,IAAI,CAAC;AAkBnC,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,SAAS,YAAY,EAAE,GAC/B,UAAU,CA8CZ"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { fillEntityRoute as e } from "./entityRoutes.js";
|
|
2
|
+
import { ENTITY_TARGET_PREFIX as t } from "./resolveTarget.js";
|
|
3
|
+
//#region src/shared/assistant/uiActions/recordNames.ts
|
|
4
|
+
var n = (e) => e.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), r = new Set(/* @__PURE__ */ "it.that.this.there.here.back.them.those.one.link.page.screen.list.tab.section.view.all.my.the.new.first.second.third.fourth.last.next.previous.settings".split(".")), i = /(?:^| )(?:page|screen|list|tab|section|view|settings|menu)$/, a = 60, o = "(?:open|go to|take me to|pull up|bring up|navigate to|switch to|show me)", s = "(?:open|go to|take me to|pull up|bring up|navigate to)";
|
|
5
|
+
function c(e, t) {
|
|
6
|
+
if (t.length === 0) return null;
|
|
7
|
+
let c = (e) => t.filter((t) => t.nouns.includes(e)).map((e) => e.id), l = [...new Set(t.flatMap((e) => e.nouns))].sort((e, t) => t.length - e.length), u = (e) => {
|
|
8
|
+
let t = e.trim();
|
|
9
|
+
return t.length >= 2 && t.length <= a && !r.has(t) && !i.test(t);
|
|
10
|
+
};
|
|
11
|
+
if (l.length > 0) {
|
|
12
|
+
let t = l.map((e) => n(e)).join("|"), r = RegExp(`^${o} (?:the |my )?(${t}) (?:(?:called|named) )?(.+)$`).exec(e);
|
|
13
|
+
if (r && u(r[2] ?? "")) {
|
|
14
|
+
let e = c(r[1] ?? "");
|
|
15
|
+
if (e.length > 0) return {
|
|
16
|
+
name: (r[2] ?? "").trim(),
|
|
17
|
+
adapterIds: e
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
let i = RegExp(`^${o} (?:the |my )?(.+?) (${t})$`).exec(e);
|
|
21
|
+
if (i && u(i[1] ?? "")) {
|
|
22
|
+
let e = c(i[2] ?? "");
|
|
23
|
+
if (e.length > 0) return {
|
|
24
|
+
name: (i[1] ?? "").trim(),
|
|
25
|
+
adapterIds: e
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
let d = RegExp(`^${s} (?:the |my )?(.+)$`).exec(e);
|
|
30
|
+
return d && u(d[1] ?? "") && (d[1] ?? "").length >= 3 ? {
|
|
31
|
+
name: (d[1] ?? "").trim(),
|
|
32
|
+
adapterIds: []
|
|
33
|
+
} : null;
|
|
34
|
+
}
|
|
35
|
+
var l = 4, u = (e) => e.normalize("NFKC").toLowerCase().replace(/[^\p{L}\p{N}\s]/gu, " ").replace(/\s+/g, " ").trim();
|
|
36
|
+
function d(e, t) {
|
|
37
|
+
let n = t.split(" ");
|
|
38
|
+
return e.split(" ").every((e) => n.some((t) => t.startsWith(e)));
|
|
39
|
+
}
|
|
40
|
+
function f(n, r) {
|
|
41
|
+
let i = u(n);
|
|
42
|
+
if (!i) return { kind: "none" };
|
|
43
|
+
let a = [];
|
|
44
|
+
for (let n of r) for (let r of n.matches) {
|
|
45
|
+
let o = e(n.route, r.params);
|
|
46
|
+
if (o === null) continue;
|
|
47
|
+
let s = u(r.name), c = s === i;
|
|
48
|
+
!c && !d(i, s) || a.some((e) => e.destination.path === o) || a.push({
|
|
49
|
+
adapterId: n.adapter.id,
|
|
50
|
+
noun: n.noun,
|
|
51
|
+
exact: c,
|
|
52
|
+
destination: {
|
|
53
|
+
id: `${t}${n.route.id}`,
|
|
54
|
+
label: r.name.trim().slice(0, 80) || n.noun,
|
|
55
|
+
path: o,
|
|
56
|
+
context: n.noun
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
let o = a.some((e) => e.exact) ? a.filter((e) => e.exact) : a, s = o[0];
|
|
61
|
+
if (!s) return { kind: "none" };
|
|
62
|
+
if (o.length === 1) return {
|
|
63
|
+
kind: "open",
|
|
64
|
+
destination: s.destination
|
|
65
|
+
};
|
|
66
|
+
let c = new Set(o.map((e) => e.adapterId)), l = o.slice(0, 4);
|
|
67
|
+
return {
|
|
68
|
+
kind: "choose",
|
|
69
|
+
why: c.size > 1 ? "kinds" : "records",
|
|
70
|
+
candidates: l.map((e) => e.destination),
|
|
71
|
+
nouns: [...new Set(l.map((e) => e.noun))]
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
//#endregion
|
|
75
|
+
export { l as RECORD_CHOICE_MAX, c as parseRecordRequest, f as planRecordResolution };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { LocalDestination } from '../localUiCommands';
|
|
2
|
+
import { AssistantEntityRoute } from './entityRoutes';
|
|
3
|
+
import { InAppLink } from './inAppLinks';
|
|
4
|
+
/**
|
|
5
|
+
* ★ BOFF-8060 (N1b): which of the in-app paths a reply linked the panel may
|
|
6
|
+
* take the person to. PURE.
|
|
7
|
+
*
|
|
8
|
+
* A path resolves only to a place the person is already offered:
|
|
9
|
+
* 1. a NAVIGATION destination — what the RBAC-filtered sidebar shows
|
|
10
|
+
* (`navDestinations`), matched by its target path or its own path;
|
|
11
|
+
* 2. a product-declared ENTITY route whose `visibleWith` navigation entry is in
|
|
12
|
+
* the person's visible tree — or a declared static route with no
|
|
13
|
+
* `visibleWith` (the product's reviewed decision).
|
|
14
|
+
* Anything else is "unresolved": the panel says it cannot open that link, and
|
|
15
|
+
* the person can still click it themselves.
|
|
16
|
+
*/
|
|
17
|
+
export interface ResolveContext {
|
|
18
|
+
destinations: readonly LocalDestination[];
|
|
19
|
+
entityRoutes?: readonly AssistantEntityRoute[] | undefined;
|
|
20
|
+
/** Every id in the person's visible navigation tree, groups and parents included. */
|
|
21
|
+
visibleNavIds: ReadonlySet<string>;
|
|
22
|
+
/** The translated noun of an entity route ("dashboard"); default: its English fallback. */
|
|
23
|
+
nounLabel?: ((noun: AssistantEntityRoute["noun"]) => string) | undefined;
|
|
24
|
+
}
|
|
25
|
+
/** The entity-target id prefix: `entity:<routeId>`. */
|
|
26
|
+
export declare const ENTITY_TARGET_PREFIX = "entity:";
|
|
27
|
+
export declare function isEntityTarget(target: Pick<LocalDestination, "id">): boolean;
|
|
28
|
+
/** Every `id` in a navigation tree (the VISIBLE one), children included. */
|
|
29
|
+
export declare function navEntryIds(entries: readonly {
|
|
30
|
+
id: string;
|
|
31
|
+
children?: readonly {
|
|
32
|
+
id: string;
|
|
33
|
+
}[] | undefined;
|
|
34
|
+
}[]): Set<string>;
|
|
35
|
+
export declare function resolveUiTarget(path: string, context: ResolveContext, linkText?: string): LocalDestination | null;
|
|
36
|
+
export interface ResolvedLinks {
|
|
37
|
+
/** In reply order, de-duplicated by path. */
|
|
38
|
+
targets: LocalDestination[];
|
|
39
|
+
/** How many in-app links the reply has that did NOT resolve. */
|
|
40
|
+
unresolved: number;
|
|
41
|
+
}
|
|
42
|
+
export declare function resolveInAppLinks(links: readonly InAppLink[], context: ResolveContext): ResolvedLinks;
|
|
43
|
+
//# sourceMappingURL=resolveTarget.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolveTarget.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/uiActions/resolveTarget.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,EAAoB,KAAK,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAC7E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE9C;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,cAAc;IAC7B,YAAY,EAAE,SAAS,gBAAgB,EAAE,CAAC;IAC1C,YAAY,CAAC,EAAE,SAAS,oBAAoB,EAAE,GAAG,SAAS,CAAC;IAC3D,qFAAqF;IACrF,aAAa,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACnC,2FAA2F;IAC3F,SAAS,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,oBAAoB,CAAC,MAAM,CAAC,KAAK,MAAM,CAAC,GAAG,SAAS,CAAC;CAC1E;AAKD,uDAAuD;AACvD,eAAO,MAAM,oBAAoB,YAAY,CAAC;AAE9C,wBAAgB,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,gBAAgB,EAAE,IAAI,CAAC,GAAG,OAAO,CAE5E;AAED,4EAA4E;AAC5E,wBAAgB,WAAW,CACzB,OAAO,EAAE,SAAS;IAChB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,CAAC,EAAE,SAAS;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,EAAE,GAAG,SAAS,CAAC;CAClD,EAAE,GACF,GAAG,CAAC,MAAM,CAAC,CAkBb;AAKD,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,cAAc,EACvB,QAAQ,CAAC,EAAE,MAAM,GAChB,gBAAgB,GAAG,IAAI,CAgCzB;AAED,MAAM,WAAW,aAAa;IAC5B,6CAA6C;IAC7C,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,gEAAgE;IAChE,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,SAAS,SAAS,EAAE,EAC3B,OAAO,EAAE,cAAc,GACtB,aAAa,CAUf"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { matchEntityRoute as e } from "./entityRoutes.js";
|
|
2
|
+
import { isCurrentPath as t } from "../localUiCommands.js";
|
|
3
|
+
//#region src/shared/assistant/uiActions/resolveTarget.ts
|
|
4
|
+
var n = /\[?REDACTED_[A-Z_]+\]?|%5BREDACTED_/i, r = "entity:";
|
|
5
|
+
function i(e) {
|
|
6
|
+
return e.id.startsWith(r);
|
|
7
|
+
}
|
|
8
|
+
function a(e) {
|
|
9
|
+
let t = /* @__PURE__ */ new Set(), n = (e) => {
|
|
10
|
+
for (let r of e) t.add(r.id), r.children?.length && n(r.children);
|
|
11
|
+
};
|
|
12
|
+
return n(e), t;
|
|
13
|
+
}
|
|
14
|
+
var o = (e) => e.split("#")[0]?.split("?")[0] ?? e;
|
|
15
|
+
function s(i, a, s) {
|
|
16
|
+
if (!i.startsWith("/") || i.startsWith("//") || n.test(i)) return null;
|
|
17
|
+
for (let e of a.destinations) {
|
|
18
|
+
if ([e.path, ...e.aliases ?? []].find((e) => t(e, i)) === void 0) continue;
|
|
19
|
+
let n = t(e.path, i);
|
|
20
|
+
return {
|
|
21
|
+
...e,
|
|
22
|
+
path: n ? i : e.path
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
let c = e(i, a.entityRoutes ?? []);
|
|
26
|
+
if (c === null) return null;
|
|
27
|
+
let { route: l } = c;
|
|
28
|
+
if (l.visibleWith !== void 0 && !a.visibleNavIds.has(l.visibleWith)) return null;
|
|
29
|
+
let u = a.nounLabel ? a.nounLabel(l.noun) : l.noun.fallback;
|
|
30
|
+
return {
|
|
31
|
+
id: `${r}${l.id}`,
|
|
32
|
+
label: (s ?? "").trim() || u,
|
|
33
|
+
path: o(i),
|
|
34
|
+
context: u
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function c(e, t) {
|
|
38
|
+
let n = [], r = 0;
|
|
39
|
+
for (let i of e) {
|
|
40
|
+
let e = s(i.path, t, i.text);
|
|
41
|
+
e === null ? r += 1 : n.some((t) => t.path === e.path) || n.push(e);
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
targets: n,
|
|
45
|
+
unresolved: r
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
//#endregion
|
|
49
|
+
export { r as ENTITY_TARGET_PREFIX, i as isEntityTarget, a as navEntryIds, c as resolveInAppLinks, s as resolveUiTarget };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { LocalDestination } from '../localUiCommands';
|
|
2
|
+
/**
|
|
3
|
+
* ★ BOFF-8060 (N1b, §4.9 — N2 plumbing, DORMANT): the pages this person may be
|
|
4
|
+
* sent to, offered to the model so a future (N2) rule can point at the right
|
|
5
|
+
* one. Nothing consumes it yet: a product must opt in
|
|
6
|
+
* (`LocalUiCommandOptions.uiCatalogue`), and an older sandbox ignores an
|
|
7
|
+
* unknown body key — the same precedent as `conversationId` and `writeReply`.
|
|
8
|
+
* The field stays labelled `source` until the N2 image is live.
|
|
9
|
+
*
|
|
10
|
+
* It is built ONLY from what the RBAC-filtered sidebar really shows: never
|
|
11
|
+
* from the optimistic list shown while permissions load, never when a
|
|
12
|
+
* permission fetch failed, and never from a simulated role's navigation.
|
|
13
|
+
*/
|
|
14
|
+
export interface AssistantUiCatalogueEntry {
|
|
15
|
+
id: string;
|
|
16
|
+
label: string;
|
|
17
|
+
context?: string;
|
|
18
|
+
path: string;
|
|
19
|
+
}
|
|
20
|
+
export interface AssistantUiCatalogue {
|
|
21
|
+
v: 1;
|
|
22
|
+
entries: AssistantUiCatalogueEntry[];
|
|
23
|
+
}
|
|
24
|
+
export declare const UI_CATALOGUE_MAX_ENTRIES = 120;
|
|
25
|
+
export declare const UI_CATALOGUE_MAX_BYTES: number;
|
|
26
|
+
export declare function buildUiCatalogue(destinations: readonly LocalDestination[], gate: {
|
|
27
|
+
permissionsSettled: boolean;
|
|
28
|
+
simulating: boolean;
|
|
29
|
+
}): AssistantUiCatalogue | null;
|
|
30
|
+
//# sourceMappingURL=uiCatalogue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"uiCatalogue.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/uiActions/uiCatalogue.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE3D;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,yBAAyB;IACxC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,oBAAoB;IACnC,CAAC,EAAE,CAAC,CAAC;IACL,OAAO,EAAE,yBAAyB,EAAE,CAAC;CACtC;AAED,eAAO,MAAM,wBAAwB,MAAM,CAAC;AAC5C,eAAO,MAAM,sBAAsB,QAAW,CAAC;AAK/C,wBAAgB,gBAAgB,CAC9B,YAAY,EAAE,SAAS,gBAAgB,EAAE,EACzC,IAAI,EAAE;IAAE,kBAAkB,EAAE,OAAO,CAAC;IAAC,UAAU,EAAE,OAAO,CAAA;CAAE,GACzD,oBAAoB,GAAG,IAAI,CAkB7B"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
//#region src/shared/assistant/uiActions/uiCatalogue.ts
|
|
2
|
+
var e = 120, t = 8 * 1024, n = (e) => new TextEncoder().encode(JSON.stringify(e)).length;
|
|
3
|
+
function r(e, t) {
|
|
4
|
+
if (!t.permissionsSettled || t.simulating) return null;
|
|
5
|
+
let r = [];
|
|
6
|
+
for (let t of e.slice(0, 120)) r.push({
|
|
7
|
+
id: t.id,
|
|
8
|
+
label: t.label,
|
|
9
|
+
...t.context ? { context: t.context } : {},
|
|
10
|
+
path: t.path
|
|
11
|
+
});
|
|
12
|
+
for (; r.length > 0 && n({
|
|
13
|
+
v: 1,
|
|
14
|
+
entries: r
|
|
15
|
+
}) > 8192;) r.pop();
|
|
16
|
+
return r.length > 0 ? {
|
|
17
|
+
v: 1,
|
|
18
|
+
entries: r
|
|
19
|
+
} : null;
|
|
20
|
+
}
|
|
21
|
+
//#endregion
|
|
22
|
+
export { t as UI_CATALOGUE_MAX_BYTES, e as UI_CATALOGUE_MAX_ENTRIES, r as buildUiCatalogue };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { assistantRoutePath as e,
|
|
1
|
+
import { assistantRoutePath as e, classifyAssistantHref as t } from "../../assistant/uiActions/assistantHref.js";
|
|
2
|
+
import { browserShouldHandle as n } from "../../assistant/ui/AssistantMarkdownRenderer.js";
|
|
2
3
|
import { Fragment as r } from "react";
|
|
3
4
|
import { Fragment as i, jsx as a } from "react/jsx-runtime";
|
|
4
5
|
//#region src/shared/components/assistantWidget/MessageContent.tsx
|
|
@@ -11,12 +12,12 @@ var c = ({ content: c, onNavigate: l }) => {
|
|
|
11
12
|
for (let i of c.matchAll(f)) {
|
|
12
13
|
let [o, f, p] = i, m = i.index ?? 0;
|
|
13
14
|
m > d && u.push(/* @__PURE__ */ a(r, { children: c.slice(d, m) }, `t${String(d)}`));
|
|
14
|
-
let h = p ?
|
|
15
|
+
let h = p ? t(p) : "blocked", g = h === "internal" ? e(p) : null, _ = h === "external" && s(p);
|
|
15
16
|
f && p && (g || _) ? u.push(/* @__PURE__ */ a("a", {
|
|
16
17
|
href: g ?? p,
|
|
17
18
|
"data-testid": "assistant-message-link",
|
|
18
19
|
...g ? { onClick: l ? (e) => {
|
|
19
|
-
|
|
20
|
+
n(e) || (e.preventDefault(), l(g));
|
|
20
21
|
} : void 0 } : {
|
|
21
22
|
target: "_blank",
|
|
22
23
|
rel: "noopener noreferrer"
|