@stigmer/react 3.1.2 → 3.1.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/composer/SessionComposer.d.ts +37 -5
- package/composer/SessionComposer.d.ts.map +1 -1
- package/composer/SessionComposer.js +13 -5
- package/composer/SessionComposer.js.map +1 -1
- package/execution/ArtifactApplyButton.d.ts +25 -0
- package/execution/ArtifactApplyButton.d.ts.map +1 -0
- package/execution/ArtifactApplyButton.js +21 -0
- package/execution/ArtifactApplyButton.js.map +1 -0
- package/execution/ArtifactContentBody.d.ts +36 -0
- package/execution/ArtifactContentBody.d.ts.map +1 -0
- package/execution/ArtifactContentBody.js +62 -0
- package/execution/ArtifactContentBody.js.map +1 -0
- package/execution/ArtifactDocument.d.ts +48 -0
- package/execution/ArtifactDocument.d.ts.map +1 -0
- package/execution/ArtifactDocument.js +89 -0
- package/execution/ArtifactDocument.js.map +1 -0
- package/execution/ArtifactPreviewModal.d.ts +9 -9
- package/execution/ArtifactPreviewModal.d.ts.map +1 -1
- package/execution/ArtifactPreviewModal.js +18 -145
- package/execution/ArtifactPreviewModal.js.map +1 -1
- package/execution/ArtifactRow.d.ts +49 -0
- package/execution/ArtifactRow.d.ts.map +1 -0
- package/execution/ArtifactRow.js +56 -0
- package/execution/ArtifactRow.js.map +1 -0
- package/execution/ArtifactsWidget.d.ts +6 -9
- package/execution/ArtifactsWidget.d.ts.map +1 -1
- package/execution/ArtifactsWidget.js +15 -19
- package/execution/ArtifactsWidget.js.map +1 -1
- package/execution/FileChangeProgressBar.d.ts +47 -0
- package/execution/FileChangeProgressBar.d.ts.map +1 -0
- package/execution/FileChangeProgressBar.js +49 -0
- package/execution/FileChangeProgressBar.js.map +1 -0
- package/execution/FileChangesView.d.ts.map +1 -1
- package/execution/FileChangesView.js +19 -4
- package/execution/FileChangesView.js.map +1 -1
- package/execution/FileReviewAtoms.d.ts +27 -0
- package/execution/FileReviewAtoms.d.ts.map +1 -0
- package/execution/FileReviewAtoms.js +64 -0
- package/execution/FileReviewAtoms.js.map +1 -0
- package/execution/FileReviewCard.d.ts +2 -2
- package/execution/FileReviewCard.d.ts.map +1 -1
- package/execution/FileReviewCard.js +32 -62
- package/execution/FileReviewCard.js.map +1 -1
- package/execution/MessageEntry.d.ts +0 -9
- package/execution/MessageEntry.d.ts.map +1 -1
- package/execution/MessageEntry.js +1 -11
- package/execution/MessageEntry.js.map +1 -1
- package/execution/MessageThread.d.ts +3 -4
- package/execution/MessageThread.d.ts.map +1 -1
- package/execution/MessageThread.js +25 -11
- package/execution/MessageThread.js.map +1 -1
- package/execution/PlanArtifactCard.d.ts +16 -10
- package/execution/PlanArtifactCard.d.ts.map +1 -1
- package/execution/PlanArtifactCard.js +31 -7
- package/execution/PlanArtifactCard.js.map +1 -1
- package/execution/PlanCompletionCard.d.ts +4 -4
- package/execution/PlanCompletionCard.d.ts.map +1 -1
- package/execution/PlanCompletionCard.js +4 -4
- package/execution/PlanCompletionCard.js.map +1 -1
- package/execution/PlanStreamingCard.d.ts +7 -2
- package/execution/PlanStreamingCard.d.ts.map +1 -1
- package/execution/PlanStreamingCard.js +11 -6
- package/execution/PlanStreamingCard.js.map +1 -1
- package/execution/index.d.ts +12 -2
- package/execution/index.d.ts.map +1 -1
- package/execution/index.js +6 -1
- package/execution/index.js.map +1 -1
- package/execution/use-build-from-plan-hotkey.d.ts +1 -1
- package/execution/use-build-from-plan-hotkey.js +1 -1
- package/execution/useArtifactContent.d.ts +6 -1
- package/execution/useArtifactContent.d.ts.map +1 -1
- package/execution/useArtifactContent.js +7 -2
- package/execution/useArtifactContent.js.map +1 -1
- package/execution/useArtifactCopy.d.ts +51 -0
- package/execution/useArtifactCopy.d.ts.map +1 -0
- package/execution/useArtifactCopy.js +75 -0
- package/execution/useArtifactCopy.js.map +1 -0
- package/execution/useArtifactDownload.d.ts.map +1 -1
- package/execution/useArtifactDownload.js +17 -5
- package/execution/useArtifactDownload.js.map +1 -1
- package/execution/useArtifactInspection.d.ts +85 -0
- package/execution/useArtifactInspection.d.ts.map +1 -0
- package/execution/useArtifactInspection.js +143 -0
- package/execution/useArtifactInspection.js.map +1 -0
- package/execution/useCreateAgentExecution.d.ts +16 -3
- package/execution/useCreateAgentExecution.d.ts.map +1 -1
- package/execution/useCreateAgentExecution.js +1 -0
- package/execution/useCreateAgentExecution.js.map +1 -1
- package/index.d.ts +4 -4
- package/index.d.ts.map +1 -1
- package/index.js +3 -3
- package/index.js.map +1 -1
- package/internal/MermaidDiagram.d.ts +47 -0
- package/internal/MermaidDiagram.d.ts.map +1 -0
- package/internal/MermaidDiagram.js +118 -0
- package/internal/MermaidDiagram.js.map +1 -0
- package/internal/file-tree/FileTreeNode.d.ts.map +1 -1
- package/internal/file-tree/FileTreeNode.js +2 -2
- package/internal/file-tree/FileTreeNode.js.map +1 -1
- package/internal/markdown-components.d.ts.map +1 -1
- package/internal/markdown-components.js +34 -0
- package/internal/markdown-components.js.map +1 -1
- package/internal/mermaid-loader.d.ts +26 -0
- package/internal/mermaid-loader.d.ts.map +1 -0
- package/internal/mermaid-loader.js +34 -0
- package/internal/mermaid-loader.js.map +1 -0
- package/internal/mermaid-theme-css.d.ts +41 -0
- package/internal/mermaid-theme-css.d.ts.map +1 -0
- package/internal/mermaid-theme-css.js +179 -0
- package/internal/mermaid-theme-css.js.map +1 -0
- package/internal/slug.d.ts +9 -5
- package/internal/slug.d.ts.map +1 -1
- package/internal/slug.js +10 -6
- package/internal/slug.js.map +1 -1
- package/library/detect-plan-artifact.d.ts +27 -9
- package/library/detect-plan-artifact.d.ts.map +1 -1
- package/library/detect-plan-artifact.js +26 -6
- package/library/detect-plan-artifact.js.map +1 -1
- package/library/index.d.ts +1 -1
- package/library/index.d.ts.map +1 -1
- package/library/index.js +1 -1
- package/library/index.js.map +1 -1
- package/package.json +5 -4
- package/session/PlanEditor.js +1 -1
- package/session/PlanEditor.js.map +1 -1
- package/session/SessionViewer.d.ts.map +1 -1
- package/session/SessionViewer.js +122 -30
- package/session/SessionViewer.js.map +1 -1
- package/session/artifact-document.d.ts +13 -0
- package/session/artifact-document.d.ts.map +1 -0
- package/session/artifact-document.js +22 -0
- package/session/artifact-document.js.map +1 -0
- package/session/facets/ArtifactsTab.d.ts +30 -4
- package/session/facets/ArtifactsTab.d.ts.map +1 -1
- package/session/facets/ArtifactsTab.js +32 -10
- package/session/facets/ArtifactsTab.js.map +1 -1
- package/session/index.d.ts +2 -1
- package/session/index.d.ts.map +1 -1
- package/session/index.js +4 -1
- package/session/index.js.map +1 -1
- package/session/plan-document.d.ts +14 -2
- package/session/plan-document.d.ts.map +1 -1
- package/session/plan-document.js +14 -3
- package/session/plan-document.js.map +1 -1
- package/session/usePlanDraft.d.ts +1 -1
- package/session/useSessionArtifacts.d.ts +17 -0
- package/session/useSessionArtifacts.d.ts.map +1 -1
- package/session/useSessionArtifacts.js +16 -5
- package/session/useSessionArtifacts.js.map +1 -1
- package/session/useSessionConversation.d.ts +26 -3
- package/session/useSessionConversation.d.ts.map +1 -1
- package/session/useSessionConversation.js +51 -6
- package/session/useSessionConversation.js.map +1 -1
- package/session/useSessionPageFlow.d.ts.map +1 -1
- package/session/useSessionPageFlow.js +1 -0
- package/session/useSessionPageFlow.js.map +1 -1
- package/session/useSessionPanel.d.ts +20 -0
- package/session/useSessionPanel.d.ts.map +1 -1
- package/session/useSessionPanel.js +13 -0
- package/session/useSessionPanel.js.map +1 -1
- package/session/useSessionRailViews.d.ts +13 -1
- package/session/useSessionRailViews.d.ts.map +1 -1
- package/session/useSessionRailViews.js +5 -3
- package/session/useSessionRailViews.js.map +1 -1
- package/src/composer/SessionComposer.tsx +76 -7
- package/src/composer/__tests__/SessionComposer-editing.test.tsx +128 -0
- package/src/execution/ArtifactApplyButton.tsx +79 -0
- package/src/execution/ArtifactContentBody.tsx +255 -0
- package/src/execution/ArtifactDocument.tsx +344 -0
- package/src/execution/ArtifactPreviewModal.tsx +49 -415
- package/src/execution/ArtifactRow.tsx +165 -0
- package/src/execution/ArtifactsWidget.tsx +24 -33
- package/src/execution/FileChangeProgressBar.tsx +121 -0
- package/src/execution/FileChangesView.tsx +18 -4
- package/src/execution/FileReviewAtoms.tsx +89 -0
- package/src/execution/FileReviewCard.tsx +57 -90
- package/src/execution/MessageEntry.tsx +0 -62
- package/src/execution/MessageThread.tsx +29 -15
- package/src/execution/PlanArtifactCard.tsx +130 -52
- package/src/execution/PlanCompletionCard.tsx +5 -5
- package/src/execution/PlanStreamingCard.tsx +15 -11
- package/src/execution/__tests__/ArtifactContentBody.test.tsx +131 -0
- package/src/execution/__tests__/ArtifactDocument.test.tsx +100 -0
- package/src/execution/__tests__/ArtifactPreviewModal.test.tsx +6 -6
- package/src/execution/__tests__/ArtifactRow.test.tsx +139 -0
- package/src/execution/__tests__/ArtifactsWidget.test.tsx +78 -0
- package/src/execution/__tests__/FileChangeProgressBar.test.tsx +125 -0
- package/src/execution/__tests__/FileReviewCard.test.tsx +66 -7
- package/src/execution/__tests__/MessageThread.test.tsx +1 -1
- package/src/execution/__tests__/PlanArtifactCard.test.tsx +52 -18
- package/src/execution/__tests__/PlanCompletionCard.test.tsx +2 -2
- package/src/execution/__tests__/PlanStreamingCard.test.tsx +11 -4
- package/src/execution/__tests__/buildThreadItems-plan-completion.test.ts +104 -8
- package/src/execution/__tests__/message-entry.test.tsx +56 -39
- package/src/execution/__tests__/useArtifactCopy.test.tsx +90 -0
- package/src/execution/__tests__/useArtifactDownload.test.tsx +2 -0
- package/src/execution/__tests__/useArtifactInspection.test.tsx +151 -0
- package/src/execution/__tests__/useCreateAgentExecution.test.tsx +35 -0
- package/src/execution/index.ts +20 -2
- package/src/execution/use-build-from-plan-hotkey.ts +1 -1
- package/src/execution/useArtifactContent.ts +7 -0
- package/src/execution/useArtifactCopy.ts +109 -0
- package/src/execution/useArtifactDownload.ts +17 -5
- package/src/execution/useArtifactInspection.ts +252 -0
- package/src/execution/useCreateAgentExecution.ts +17 -3
- package/src/index.ts +17 -2
- package/src/internal/MermaidDiagram.tsx +164 -0
- package/src/internal/__tests__/a11y/mermaid-theme.a11y.test.tsx +122 -0
- package/src/internal/__tests__/markdown-components.test.tsx +93 -1
- package/src/internal/__tests__/mermaid-diagram.test.tsx +282 -0
- package/src/internal/file-tree/FileTreeNode.tsx +13 -2
- package/src/internal/markdown-components.tsx +36 -1
- package/src/internal/mermaid-loader.ts +44 -0
- package/src/internal/mermaid-theme-css.ts +178 -0
- package/src/internal/slug.ts +10 -6
- package/src/library/__tests__/detect-plan-artifact.test.ts +21 -0
- package/src/library/detect-plan-artifact.ts +32 -10
- package/src/library/index.ts +2 -0
- package/src/session/PlanEditor.tsx +1 -1
- package/src/session/SessionViewer.tsx +227 -51
- package/src/session/__tests__/PlanEditor.test.tsx +4 -4
- package/src/session/__tests__/PlanStreamingDocument.test.tsx +1 -1
- package/src/session/__tests__/SessionViewer-artifactTabs.test.tsx +210 -0
- package/src/session/__tests__/SessionViewer-editResubmit.test.tsx +233 -0
- package/src/session/__tests__/SessionViewer-fileReviewDock.test.tsx +57 -0
- package/src/session/__tests__/useSessionArtifacts.test.ts +57 -0
- package/src/session/__tests__/useSessionConversation.test.tsx +216 -1
- package/src/session/__tests__/useSessionPanel.test.ts +70 -1
- package/src/session/artifact-document.ts +23 -0
- package/src/session/facets/ArtifactsTab.tsx +66 -18
- package/src/session/facets/__tests__/ArtifactsTab.test.tsx +111 -47
- package/src/session/index.ts +5 -1
- package/src/session/plan-document.ts +14 -3
- package/src/session/usePlanDraft.ts +1 -1
- package/src/session/useSessionArtifacts.ts +16 -5
- package/src/session/useSessionConversation.ts +80 -10
- package/src/session/useSessionPageFlow.ts +1 -0
- package/src/session/useSessionPanel.ts +41 -0
- package/src/session/useSessionRailViews.tsx +21 -1
- package/src/workspace/EditorTabs.tsx +38 -9
- package/src/workspace/ExplorerTree.tsx +10 -4
- package/src/workspace/FileViewer.tsx +27 -6
- package/src/workspace/WorkspaceContentSearch.tsx +44 -20
- package/src/workspace/WorkspaceEditor.tsx +19 -16
- package/src/workspace/WorkspaceFileSearch.tsx +51 -28
- package/src/workspace/WorkspaceSurface.tsx +106 -48
- package/src/workspace/__tests__/EditorTabs.test.tsx +4 -2
- package/src/workspace/__tests__/ExplorerTree.test.tsx +52 -0
- package/src/workspace/__tests__/FileViewer.test.tsx +18 -0
- package/src/workspace/__tests__/WorkspaceContentSearch.test.tsx +38 -5
- package/src/workspace/__tests__/WorkspaceEditor-initialPanel.test.tsx +19 -0
- package/src/workspace/__tests__/WorkspaceFileSearch.test.tsx +27 -6
- package/src/workspace/__tests__/WorkspaceSurface.test.tsx +70 -0
- package/src/workspace/__tests__/a11y/harness.tsx +140 -0
- package/src/workspace/__tests__/a11y/mock-capabilities.ts +138 -0
- package/src/workspace/__tests__/a11y/workspace-editor.a11y.test.tsx +65 -0
- package/src/workspace/__tests__/a11y/workspace-explorer-search.a11y.test.tsx +112 -0
- package/src/workspace/__tests__/a11y/workspace-viewer-tabs.a11y.test.tsx +69 -0
- package/styles.css +1 -1
- package/workspace/EditorTabs.d.ts +21 -3
- package/workspace/EditorTabs.d.ts.map +1 -1
- package/workspace/EditorTabs.js +18 -6
- package/workspace/EditorTabs.js.map +1 -1
- package/workspace/ExplorerTree.js +8 -4
- package/workspace/ExplorerTree.js.map +1 -1
- package/workspace/FileViewer.d.ts.map +1 -1
- package/workspace/FileViewer.js +19 -8
- package/workspace/FileViewer.js.map +1 -1
- package/workspace/WorkspaceContentSearch.d.ts.map +1 -1
- package/workspace/WorkspaceContentSearch.js +23 -2
- package/workspace/WorkspaceContentSearch.js.map +1 -1
- package/workspace/WorkspaceEditor.d.ts.map +1 -1
- package/workspace/WorkspaceEditor.js +8 -10
- package/workspace/WorkspaceEditor.js.map +1 -1
- package/workspace/WorkspaceFileSearch.d.ts.map +1 -1
- package/workspace/WorkspaceFileSearch.js +23 -3
- package/workspace/WorkspaceFileSearch.js.map +1 -1
- package/workspace/WorkspaceSurface.d.ts.map +1 -1
- package/workspace/WorkspaceSurface.js +54 -18
- package/workspace/WorkspaceSurface.js.map +1 -1
- package/execution/ArtifactCard.d.ts +0 -81
- package/execution/ArtifactCard.d.ts.map +0 -1
- package/execution/ArtifactCard.js +0 -130
- package/execution/ArtifactCard.js.map +0 -1
- package/src/execution/ArtifactCard.tsx +0 -320
|
@@ -102,7 +102,15 @@ export function FileTreeNode({
|
|
|
102
102
|
);
|
|
103
103
|
|
|
104
104
|
return (
|
|
105
|
-
<li
|
|
105
|
+
<li
|
|
106
|
+
role="treeitem"
|
|
107
|
+
// Depth conveys tree nesting to assistive tech (indentation is visual
|
|
108
|
+
// only). aria-level is 1-based; `depth` is 0-based. aria-expanded stays on
|
|
109
|
+
// the treeitem (the <li>) — its child group is nested here, so this is the
|
|
110
|
+
// element a tree-aware screen reader reads expandability from.
|
|
111
|
+
aria-level={depth + 1}
|
|
112
|
+
aria-expanded={isFolder ? expanded : undefined}
|
|
113
|
+
>
|
|
106
114
|
<button
|
|
107
115
|
type="button"
|
|
108
116
|
onClick={handleClick}
|
|
@@ -123,7 +131,10 @@ export function FileTreeNode({
|
|
|
123
131
|
aria-current={isSelected ? "true" : undefined}
|
|
124
132
|
>
|
|
125
133
|
{isFolder && (
|
|
126
|
-
<span
|
|
134
|
+
<span
|
|
135
|
+
aria-hidden="true"
|
|
136
|
+
className="text-[10px] text-muted-foreground-subtle"
|
|
137
|
+
>
|
|
127
138
|
{expanded ? "▼" : "▶"}
|
|
128
139
|
</span>
|
|
129
140
|
)}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { isValidElement, type ComponentProps, type JSX, type ReactNode } from "react";
|
|
2
2
|
import type { Components } from "react-markdown";
|
|
3
3
|
import remarkGfm from "remark-gfm";
|
|
4
4
|
import { cn } from "@stigmer/theme";
|
|
5
5
|
import { highlightToReact } from "./code-highlight.js";
|
|
6
|
+
import { MermaidDiagram } from "./MermaidDiagram.js";
|
|
6
7
|
|
|
7
8
|
const LANGUAGE_CLASS_PREFIX = "language-";
|
|
9
|
+
const MERMAID_LANGUAGE_CLASS = "language-mermaid";
|
|
8
10
|
|
|
9
11
|
type MdProps<T extends keyof JSX.IntrinsicElements> = ComponentProps<T>;
|
|
10
12
|
|
|
@@ -119,6 +121,30 @@ export function extractLeadingH1(markdown: string): {
|
|
|
119
121
|
return { title: match[1], body: trimmed.slice(match[0].length) };
|
|
120
122
|
}
|
|
121
123
|
|
|
124
|
+
/**
|
|
125
|
+
* Returns the mermaid source when a `pre` element's children are a single
|
|
126
|
+
* fenced code block explicitly tagged `mermaid`, or `null` otherwise.
|
|
127
|
+
*
|
|
128
|
+
* Both renderers (Streamdown for chat, react-markdown for artifacts/skills)
|
|
129
|
+
* hand `pre` exactly one `<code>` child whose `className` carries the fence's
|
|
130
|
+
* info string as `language-*` and whose children are the raw source text.
|
|
131
|
+
* Anything that deviates from that shape — a different language, a missing
|
|
132
|
+
* tag, non-string children — is not a mermaid fence and keeps the ordinary
|
|
133
|
+
* code-block rendering. Only the explicit `mermaid` tag qualifies:
|
|
134
|
+
* inspecting fence bodies to guess diagram intent is the kind of fuzzy
|
|
135
|
+
* heuristic this codebase avoids.
|
|
136
|
+
*/
|
|
137
|
+
function extractMermaidSource(children: ReactNode): string | null {
|
|
138
|
+
if (!isValidElement(children)) return null;
|
|
139
|
+
const { className, children: code } = children.props as {
|
|
140
|
+
className?: unknown;
|
|
141
|
+
children?: unknown;
|
|
142
|
+
};
|
|
143
|
+
if (typeof className !== "string") return null;
|
|
144
|
+
if (!className.split(/\s+/).includes(MERMAID_LANGUAGE_CLASS)) return null;
|
|
145
|
+
return typeof code === "string" ? code : null;
|
|
146
|
+
}
|
|
147
|
+
|
|
122
148
|
/**
|
|
123
149
|
* Styled react-markdown component overrides for SDK markdown surfaces.
|
|
124
150
|
*
|
|
@@ -208,6 +234,15 @@ export const MARKDOWN_COMPONENTS: Components = {
|
|
|
208
234
|
},
|
|
209
235
|
|
|
210
236
|
pre({ children, ...props }: MdProps<"pre">) {
|
|
237
|
+
// A ```mermaid fence renders as a diagram, not a code block. The check
|
|
238
|
+
// lives here (not in the `code` override) because the diagram must
|
|
239
|
+
// replace the <pre> wrapper too — a block-level diagram container inside
|
|
240
|
+
// <pre> is invalid HTML and would inherit code-block chrome.
|
|
241
|
+
const mermaidSource = extractMermaidSource(children);
|
|
242
|
+
if (mermaidSource !== null) {
|
|
243
|
+
return <MermaidDiagram chart={mermaidSource} />;
|
|
244
|
+
}
|
|
245
|
+
|
|
211
246
|
return (
|
|
212
247
|
<pre
|
|
213
248
|
className="mb-3 last:mb-0 overflow-x-auto rounded-md bg-muted p-3"
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lazy loader for the `mermaid` library, isolated in its own module — the
|
|
3
|
+
* same seam pattern as `workflow/layout/elk-layout-engine.ts` — so
|
|
4
|
+
* {@link file://./MermaidDiagram.tsx} stays a pure presentation component and
|
|
5
|
+
* tests can mock the load outcome (resolve, reject) without touching module
|
|
6
|
+
* registries.
|
|
7
|
+
*
|
|
8
|
+
* `mermaid` is an optional peer dependency (DD-013): it is large, so it must
|
|
9
|
+
* never sit on the synchronous bundle path, and a host that has not installed
|
|
10
|
+
* it must degrade gracefully (the caller falls back to a code block).
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The mermaid API surface the SDK consumes, typed from the package itself so
|
|
15
|
+
* it stays in lockstep with the installed version.
|
|
16
|
+
*/
|
|
17
|
+
export type MermaidModule = typeof import("mermaid").default;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Holds the in-flight import promise so concurrent diagrams share one load.
|
|
21
|
+
* A failed import clears the cache: rejections are often transient (a
|
|
22
|
+
* chunk-load hiccup mid-deploy), and caching one would break every diagram
|
|
23
|
+
* for the rest of the session.
|
|
24
|
+
*/
|
|
25
|
+
let mermaidImport: Promise<MermaidModule> | null = null;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Dynamically imports `mermaid`, sharing one in-flight import across callers.
|
|
29
|
+
*
|
|
30
|
+
* @returns The mermaid default export.
|
|
31
|
+
* @throws If `mermaid` cannot be imported (not installed, or the async chunk
|
|
32
|
+
* failed to load). Callers treat this as "diagrams unavailable" and render
|
|
33
|
+
* the fenced source as a plain code block.
|
|
34
|
+
*/
|
|
35
|
+
export function loadMermaid(): Promise<MermaidModule> {
|
|
36
|
+
mermaidImport ??= import("mermaid").then(
|
|
37
|
+
(module) => module.default,
|
|
38
|
+
(error: unknown) => {
|
|
39
|
+
mermaidImport = null;
|
|
40
|
+
throw error;
|
|
41
|
+
},
|
|
42
|
+
);
|
|
43
|
+
return mermaidImport;
|
|
44
|
+
}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token-driven `themeCSS` for Mermaid diagram interiors.
|
|
3
|
+
*
|
|
4
|
+
* Mermaid's built-in `default`/`dark` themes color a diagram's SVG interior
|
|
5
|
+
* with a fixed palette that ignores the host's `--stgm-*` preset (Corporate,
|
|
6
|
+
* Fintech, ...). The obvious fix — feeding resolved tokens into Mermaid's
|
|
7
|
+
* `themeVariables` — is blocked: our tokens are authored in `oklch()`, and
|
|
8
|
+
* Mermaid's color engine (`khroma`) parses only hex/rgb/hsl/keyword, so it
|
|
9
|
+
* throws or NaNs on `oklch(...)`. (Mermaid also gates every `themeVariables`
|
|
10
|
+
* value through the allowlist `^[\d "#%(),.;A-Za-z]+$`, which excludes `-` and
|
|
11
|
+
* would blank any `var(--...)`.)
|
|
12
|
+
*
|
|
13
|
+
* Instead we hand Mermaid this CSS via `initialize({ themeCSS })`. Mermaid
|
|
14
|
+
* injects it into the diagram's own `<style>` block, scoped under the render
|
|
15
|
+
* id (`#stgm-mermaid-N`), *after* the theme palette it computes. Because every
|
|
16
|
+
* selector in that block is id-prefixed, our rules and the palette's rules sit
|
|
17
|
+
* at equal specificity, so ours win by source order — and `!important` makes
|
|
18
|
+
* that bulletproof against the few palette rules that are themselves important
|
|
19
|
+
* or inlined. Crucially, `themeCSS` never passes through khroma, so the
|
|
20
|
+
* `oklch()`-backed `var(--stgm-*)` references flow straight to the browser,
|
|
21
|
+
* which resolves them against the `.stgm` scope the SVG lives in. That is why
|
|
22
|
+
* interiors track the active preset *and* color mode live, with no JS color
|
|
23
|
+
* reading and no re-render on theme change.
|
|
24
|
+
*
|
|
25
|
+
* `initialize({ theme })` still selects the built-in `default`/`dark` theme as
|
|
26
|
+
* the base, so any element or diagram type we do not target here degrades to
|
|
27
|
+
* Mermaid's stock palette — never a blank or mis-colored diagram.
|
|
28
|
+
*
|
|
29
|
+
* Palette intent (subtle surfaces + brand accents — legibility over brand
|
|
30
|
+
* saturation): node/actor bodies sit on a muted surface with quiet
|
|
31
|
+
* token-colored borders and edges; labels use the standard foreground; the
|
|
32
|
+
* brand `--stgm-primary` is reserved for structural headers (subgraph/cluster
|
|
33
|
+
* titles, sequence loop/section titles, the sequence-number badge).
|
|
34
|
+
*
|
|
35
|
+
* Coverage is the two families agents emit overwhelmingly — flowchart and
|
|
36
|
+
* sequence — plus the shared marker/edge-label chrome. Both label render paths
|
|
37
|
+
* are handled: SVG `text`/`tspan` (via `fill`) and HTML labels inside
|
|
38
|
+
* `foreignObject` (via `color`).
|
|
39
|
+
*/
|
|
40
|
+
export const MERMAID_THEME_CSS = `
|
|
41
|
+
/* Shared: edge arrowheads / markers */
|
|
42
|
+
.marker {
|
|
43
|
+
fill: var(--stgm-border) !important;
|
|
44
|
+
stroke: var(--stgm-border) !important;
|
|
45
|
+
}
|
|
46
|
+
.marker.cross {
|
|
47
|
+
stroke: var(--stgm-border) !important;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/* Flowchart: node bodies */
|
|
51
|
+
.node rect,
|
|
52
|
+
.node circle,
|
|
53
|
+
.node ellipse,
|
|
54
|
+
.node polygon,
|
|
55
|
+
.node path {
|
|
56
|
+
fill: var(--stgm-muted) !important;
|
|
57
|
+
stroke: var(--stgm-border) !important;
|
|
58
|
+
}
|
|
59
|
+
.node .neo-node {
|
|
60
|
+
stroke: var(--stgm-border) !important;
|
|
61
|
+
}
|
|
62
|
+
.node .katex path {
|
|
63
|
+
fill: var(--stgm-foreground) !important;
|
|
64
|
+
stroke: var(--stgm-foreground) !important;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/* Flowchart: node labels (SVG text and HTML spans) */
|
|
68
|
+
.label {
|
|
69
|
+
color: var(--stgm-foreground) !important;
|
|
70
|
+
}
|
|
71
|
+
.label text,
|
|
72
|
+
.label span {
|
|
73
|
+
fill: var(--stgm-foreground) !important;
|
|
74
|
+
color: var(--stgm-foreground) !important;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/* Flowchart: edges */
|
|
78
|
+
.edgePath .path,
|
|
79
|
+
.flowchart-link {
|
|
80
|
+
stroke: var(--stgm-border) !important;
|
|
81
|
+
}
|
|
82
|
+
.arrowheadPath,
|
|
83
|
+
.root .anchor path {
|
|
84
|
+
fill: var(--stgm-border) !important;
|
|
85
|
+
stroke: var(--stgm-border) !important;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/* Flowchart: edge labels sit on the diagram surface for legibility */
|
|
89
|
+
.edgeLabel,
|
|
90
|
+
.edgeLabel p,
|
|
91
|
+
.edgeLabel rect,
|
|
92
|
+
.labelBkg {
|
|
93
|
+
background-color: var(--stgm-card) !important;
|
|
94
|
+
fill: var(--stgm-card) !important;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/* Flowchart: subgraph clusters — muted surface, brand-accent title */
|
|
98
|
+
.cluster rect {
|
|
99
|
+
fill: var(--stgm-muted-subtle) !important;
|
|
100
|
+
stroke: var(--stgm-border) !important;
|
|
101
|
+
}
|
|
102
|
+
.cluster-label text,
|
|
103
|
+
.cluster text {
|
|
104
|
+
fill: var(--stgm-primary) !important;
|
|
105
|
+
}
|
|
106
|
+
.cluster-label span,
|
|
107
|
+
.cluster span {
|
|
108
|
+
color: var(--stgm-primary) !important;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/* Sequence: actors and lifelines */
|
|
112
|
+
.actor {
|
|
113
|
+
fill: var(--stgm-muted) !important;
|
|
114
|
+
stroke: var(--stgm-border) !important;
|
|
115
|
+
}
|
|
116
|
+
text.actor > tspan {
|
|
117
|
+
fill: var(--stgm-foreground) !important;
|
|
118
|
+
}
|
|
119
|
+
.actor-line {
|
|
120
|
+
stroke: var(--stgm-border) !important;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/* Sequence: messages */
|
|
124
|
+
.messageLine0,
|
|
125
|
+
.messageLine1 {
|
|
126
|
+
stroke: var(--stgm-border) !important;
|
|
127
|
+
}
|
|
128
|
+
[id$="-arrowhead"] path,
|
|
129
|
+
[id$="-crosshead"] path {
|
|
130
|
+
fill: var(--stgm-border) !important;
|
|
131
|
+
stroke: var(--stgm-border) !important;
|
|
132
|
+
}
|
|
133
|
+
.messageText {
|
|
134
|
+
fill: var(--stgm-foreground) !important;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/* Sequence: number badge — brand accent with its paired foreground */
|
|
138
|
+
[id$="-sequencenumber"] {
|
|
139
|
+
fill: var(--stgm-primary) !important;
|
|
140
|
+
}
|
|
141
|
+
.sequenceNumber {
|
|
142
|
+
fill: var(--stgm-primary-foreground) !important;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/* Sequence: alt/opt/loop boxes and labels */
|
|
146
|
+
.labelBox {
|
|
147
|
+
fill: var(--stgm-muted-subtle) !important;
|
|
148
|
+
stroke: var(--stgm-border) !important;
|
|
149
|
+
}
|
|
150
|
+
.labelText,
|
|
151
|
+
.labelText > tspan {
|
|
152
|
+
fill: var(--stgm-foreground) !important;
|
|
153
|
+
}
|
|
154
|
+
.loopText,
|
|
155
|
+
.loopText > tspan,
|
|
156
|
+
.sectionTitle,
|
|
157
|
+
.sectionTitle > tspan {
|
|
158
|
+
fill: var(--stgm-primary) !important;
|
|
159
|
+
}
|
|
160
|
+
.loopLine {
|
|
161
|
+
stroke: var(--stgm-border) !important;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/* Sequence: notes and activations */
|
|
165
|
+
.note {
|
|
166
|
+
fill: var(--stgm-muted-subtle) !important;
|
|
167
|
+
stroke: var(--stgm-border) !important;
|
|
168
|
+
}
|
|
169
|
+
.noteText,
|
|
170
|
+
.noteText > tspan {
|
|
171
|
+
fill: var(--stgm-foreground) !important;
|
|
172
|
+
}
|
|
173
|
+
.activation0,
|
|
174
|
+
.activation1 {
|
|
175
|
+
fill: var(--stgm-muted) !important;
|
|
176
|
+
stroke: var(--stgm-border) !important;
|
|
177
|
+
}
|
|
178
|
+
`;
|
package/src/internal/slug.ts
CHANGED
|
@@ -7,23 +7,27 @@
|
|
|
7
7
|
*
|
|
8
8
|
* Rules (applied in order):
|
|
9
9
|
* 1. Convert to lowercase
|
|
10
|
-
* 2. Replace spaces with hyphens
|
|
10
|
+
* 2. Replace spaces and dots (namespace separators) with hyphens
|
|
11
11
|
* 3. Strip everything except `a-z`, `0-9`, and `-`
|
|
12
12
|
* 4. Collapse consecutive hyphens into one
|
|
13
13
|
* 5. Trim leading / trailing hyphens
|
|
14
14
|
*
|
|
15
|
+
* Dots are treated as namespace separators (e.g. `platform.sara` → `platform-sara`),
|
|
16
|
+
* matching the backend generators, so namespace-scoped names stay readable.
|
|
17
|
+
*
|
|
15
18
|
* @example
|
|
16
19
|
* ```ts
|
|
17
|
-
* generateSlug("My Cool Agent")
|
|
18
|
-
* generateSlug("Acme Corp!")
|
|
19
|
-
* generateSlug(" --hello-- ")
|
|
20
|
-
* generateSlug("")
|
|
20
|
+
* generateSlug("My Cool Agent") // "my-cool-agent"
|
|
21
|
+
* generateSlug("Acme Corp!") // "acme-corp"
|
|
22
|
+
* generateSlug(" --hello-- ") // "hello"
|
|
23
|
+
* generateSlug("platform.planton-arch") // "platform-planton-arch"
|
|
24
|
+
* generateSlug("") // ""
|
|
21
25
|
* ```
|
|
22
26
|
*/
|
|
23
27
|
export function generateSlug(name: string): string {
|
|
24
28
|
return name
|
|
25
29
|
.toLowerCase()
|
|
26
|
-
.replace(/ /g, "-")
|
|
30
|
+
.replace(/[ .]/g, "-")
|
|
27
31
|
.replace(/[^a-z0-9-]/g, "")
|
|
28
32
|
.replace(/-{2,}/g, "-")
|
|
29
33
|
.replace(/^-+|-+$/g, "");
|
|
@@ -9,6 +9,7 @@ import { ExecutionArtifactKind } from "@stigmer/protos/ai/stigmer/agentic/agente
|
|
|
9
9
|
import { ApiResourceMetadataSchema } from "@stigmer/protos/ai/stigmer/commons/apiresource/metadata_pb";
|
|
10
10
|
import {
|
|
11
11
|
isPlanArtifact,
|
|
12
|
+
isPlanArtifactName,
|
|
12
13
|
findPlanArtifact,
|
|
13
14
|
findLatestSessionPlan,
|
|
14
15
|
PLAN_ARTIFACT_NAME,
|
|
@@ -35,11 +36,31 @@ function executionWithId(id: string, ...artifacts: ReturnType<typeof artifact>[]
|
|
|
35
36
|
});
|
|
36
37
|
}
|
|
37
38
|
|
|
39
|
+
describe("isPlanArtifactName", () => {
|
|
40
|
+
it("accepts the legacy exact name and any *.plan.md", () => {
|
|
41
|
+
expect(isPlanArtifactName(PLAN_ARTIFACT_NAME)).toBe(true);
|
|
42
|
+
expect(isPlanArtifactName("feature_x.plan.md")).toBe(true);
|
|
43
|
+
// The runner's current shape: hyphenated slug + content-hash discriminator.
|
|
44
|
+
expect(isPlanArtifactName("fix-the-download-ux_a1b2c3d4.plan.md")).toBe(true);
|
|
45
|
+
expect(isPlanArtifactName("a1b2c3d4.plan.md")).toBe(true);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it("rejects non-plan filenames", () => {
|
|
49
|
+
expect(isPlanArtifactName("report.md")).toBe(false);
|
|
50
|
+
expect(isPlanArtifactName("plan.txt")).toBe(false);
|
|
51
|
+
expect(isPlanArtifactName("myplan.md")).toBe(false);
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
|
|
38
55
|
describe("isPlanArtifact", () => {
|
|
39
56
|
it("is true for a FILE artifact named plan.md", () => {
|
|
40
57
|
expect(isPlanArtifact(artifact({ name: PLAN_ARTIFACT_NAME }))).toBe(true);
|
|
41
58
|
});
|
|
42
59
|
|
|
60
|
+
it("is true for a FILE artifact named <slug>_<id>.plan.md", () => {
|
|
61
|
+
expect(isPlanArtifact(artifact({ name: "plan-card-ux-cleanup_a1b2c3d4.plan.md" }))).toBe(true);
|
|
62
|
+
});
|
|
63
|
+
|
|
43
64
|
it("is false for a directory named plan.md", () => {
|
|
44
65
|
expect(
|
|
45
66
|
isPlanArtifact(artifact({ name: "plan.md", kind: ExecutionArtifactKind.DIRECTORY })),
|
|
@@ -3,26 +3,48 @@ import type { ExecutionArtifact } from "@stigmer/protos/ai/stigmer/agentic/agent
|
|
|
3
3
|
import { ExecutionArtifactKind } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* The session's current plan: the published
|
|
7
|
-
* recent execution that produced one, plus the execution it belongs
|
|
8
|
-
* (artifact content RPCs are execution-scoped).
|
|
6
|
+
* The session's current plan: the published plan artifact (a `*.plan.md` FILE)
|
|
7
|
+
* of the most recent execution that produced one, plus the execution it belongs
|
|
8
|
+
* to (artifact content RPCs are execution-scoped).
|
|
9
9
|
*/
|
|
10
10
|
export interface SessionPlan {
|
|
11
11
|
/** ID of the execution that published the plan. */
|
|
12
12
|
readonly executionId: string;
|
|
13
|
-
/** The published
|
|
13
|
+
/** The published plan artifact (`*.plan.md`). */
|
|
14
14
|
readonly artifact: ExecutionArtifact;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
|
-
*
|
|
19
|
-
*
|
|
18
|
+
* Legacy plan filename. Detection-only: {@link isPlanArtifactName} still
|
|
19
|
+
* accepts this exact name so plans published before named artifacts existed
|
|
20
|
+
* keep working. The runner never freshly emits it (a titleless plan falls back
|
|
21
|
+
* to a bare `<id>.plan.md`). Kept in sync with the runner's
|
|
22
|
+
* `PLAN_ARTIFACT_NAME` (shared/plan-artifact.ts).
|
|
20
23
|
*/
|
|
21
24
|
export const PLAN_ARTIFACT_NAME = "plan.md";
|
|
22
25
|
|
|
23
26
|
/**
|
|
24
|
-
*
|
|
25
|
-
*
|
|
27
|
+
* Suffix every named plan artifact carries (`<slug>_<id>.plan.md`, or a bare
|
|
28
|
+
* `<id>.plan.md` when untitled). The runner derives the slug from the plan's
|
|
29
|
+
* title and the `<id>` from its content hash; detection keys on this suffix.
|
|
30
|
+
* Kept in sync with the runner's `PLAN_ARTIFACT_SUFFIX` (shared/plan-artifact.ts)
|
|
31
|
+
* — the runner and browser SDK have disjoint module graphs, so the constant is
|
|
32
|
+
* duplicated by design, mirroring {@link PLAN_ARTIFACT_NAME}.
|
|
33
|
+
*/
|
|
34
|
+
export const PLAN_ARTIFACT_SUFFIX = ".plan.md";
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Returns `true` when a filename is a plan's: the legacy exact `plan.md`, or
|
|
38
|
+
* any `*.plan.md`. Accepting the legacy name keeps plans published before named
|
|
39
|
+
* artifacts existed detectable.
|
|
40
|
+
*/
|
|
41
|
+
export function isPlanArtifactName(name: string): boolean {
|
|
42
|
+
return name === PLAN_ARTIFACT_NAME || name.endsWith(PLAN_ARTIFACT_SUFFIX);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Returns `true` when an artifact is the published plan: a FILE artifact whose
|
|
47
|
+
* name satisfies {@link isPlanArtifactName}.
|
|
26
48
|
*
|
|
27
49
|
* Detection is by convention — the same lightweight, content-free approach used
|
|
28
50
|
* for skill packages ({@link isSkillPackage}) — so the UI never needs an extra
|
|
@@ -32,7 +54,7 @@ export const PLAN_ARTIFACT_NAME = "plan.md";
|
|
|
32
54
|
export function isPlanArtifact(artifact: ExecutionArtifact): boolean {
|
|
33
55
|
return (
|
|
34
56
|
artifact.kind === ExecutionArtifactKind.FILE &&
|
|
35
|
-
artifact.name
|
|
57
|
+
isPlanArtifactName(artifact.name)
|
|
36
58
|
);
|
|
37
59
|
}
|
|
38
60
|
|
|
@@ -56,7 +78,7 @@ export function findPlanArtifact(
|
|
|
56
78
|
|
|
57
79
|
/**
|
|
58
80
|
* Finds the session's LATEST plan across all executions — the plan the panel's
|
|
59
|
-
* plan document tab edits and "Build
|
|
81
|
+
* plan document tab edits and the "Build" action implements. Executions are
|
|
60
82
|
* scanned newest-first (the array is chronological), mirroring the thread's
|
|
61
83
|
* latest-plan-owns-the-build-action rule so every surface agrees on which
|
|
62
84
|
* plan is current.
|
package/src/library/index.ts
CHANGED
|
@@ -26,9 +26,11 @@ export type { SkillPackageDetection } from "./detect-skill-package.js";
|
|
|
26
26
|
|
|
27
27
|
export {
|
|
28
28
|
isPlanArtifact,
|
|
29
|
+
isPlanArtifactName,
|
|
29
30
|
findPlanArtifact,
|
|
30
31
|
findLatestSessionPlan,
|
|
31
32
|
PLAN_ARTIFACT_NAME,
|
|
33
|
+
PLAN_ARTIFACT_SUFFIX,
|
|
32
34
|
} from "./detect-plan-artifact.js";
|
|
33
35
|
export type { SessionPlan } from "./detect-plan-artifact.js";
|
|
34
36
|
|