Enable chat users to inspect and open referenced native structures inline. - Render clickable inline previews for native structure references across chat surfaces. - Route preview actions to their corresponding task, mission, goal, and other dashboard views. - Add regression coverage, dashboard documentation, and a CLI changeset. Files changed: ...fn-8291-chat-native-structure-inline-preview.md | 7 + docs/dashboard-guide.md | 5 +- packages/dashboard/app/App.tsx | 31 +++ .../app/components/StandardChatSurface.tsx | 226 ++++++++++++++++-- ...andardChatSurface.nativeStructureEmbed.test.tsx | 257 +++++++++++++++++++++ .../__tests__/nativeStructureChatRef.test.ts | 54 +++++ .../app/components/nativeStructureChatRef.ts | 58 +++++ .../app/components/nativeStructureNavigation.ts | 21 ++ 8 files changed, 635 insertions(+), 24 deletions(-) Fusion-Task-Id: FN-8291 Fusion-Task-Lineage: 9db2c0fa-494e-4779-93f3-3309eed8565a Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
55 lines
2.0 KiB
TypeScript
55 lines
2.0 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { nativeStructureChatRefMatcher, parseNativeStructureChatRef } from "../nativeStructureChatRef";
|
|
|
|
describe("parseNativeStructureChatRef", () => {
|
|
it.each([
|
|
"mission",
|
|
"milestone",
|
|
"roadmap-item",
|
|
"research-finding",
|
|
"eval-result",
|
|
"goal",
|
|
] as const)("parses the canonical %s form", (kind) => {
|
|
expect(parseNativeStructureChatRef(`fusion://${kind}/ID-001`)).toEqual({ kind, id: "ID-001" });
|
|
});
|
|
|
|
it.each([
|
|
"mission:M-001",
|
|
"fusion://unknown-kind/R-001",
|
|
"fusion://mission/",
|
|
"fusion://mission/M-001/extra",
|
|
"fusion://mission/M%2F001",
|
|
"fusion://mission/M%5C001",
|
|
"fusion://mission/%20",
|
|
"https://mission/M-001",
|
|
])("rejects malformed or unsupported reference %s", (value) => {
|
|
expect(parseNativeStructureChatRef(value)).toBeNull();
|
|
});
|
|
|
|
it("matches a bare canonical token within surrounding text without swallowing it", () => {
|
|
const source = "Read fusion://mission/M-001, then continue.";
|
|
const matches = Array.from(source.matchAll(nativeStructureChatRefMatcher));
|
|
|
|
expect(matches.map((match) => match[0])).toEqual(["fusion://mission/M-001,"]);
|
|
expect(source.slice(0, matches[0]!.index)).toBe("Read ");
|
|
expect(matches[0]![1]).toBe("fusion://mission/M-001");
|
|
expect(matches[0]![2]).toBe(",");
|
|
expect(source.slice((matches[0]!.index ?? 0) + matches[0]![0].length)).toBe(" then continue.");
|
|
});
|
|
|
|
it.each([
|
|
"fusion://mission/M-001?query",
|
|
"fusion://mission/M-001#fragment",
|
|
"fusion://mission/M-001/extra",
|
|
"fusion://mission/M-001%2Fextra",
|
|
])("does not match a valid prefix of malformed bare token %s", (value) => {
|
|
expect(Array.from(value.matchAll(nativeStructureChatRefMatcher))).toEqual([]);
|
|
});
|
|
|
|
it("keeps defined terminal prose punctuation outside the canonical token", () => {
|
|
const matches = Array.from("See fusion://mission/M.001.".matchAll(nativeStructureChatRefMatcher));
|
|
expect(matches[0]![1]).toBe("fusion://mission/M.001");
|
|
expect(matches[0]![2]).toBe(".");
|
|
});
|
|
});
|