@plannotator/ui 0.50.0 → 0.52.0
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/HANDOFF.md +295 -11
- package/README.md +8 -0
- package/components/AISettingsTab.tsx +32 -0
- package/components/AgentToolAnnouncementDialog.tsx +347 -0
- package/components/AgentsTab.tsx +9 -9
- package/components/AnnotationToolbar.tsx +2 -2
- package/components/AskSessionAnnouncementDialog.tsx +329 -0
- package/components/BlockRenderer.tsx +10 -1
- package/components/CommentPopover.tsx +36 -18
- package/components/CompletionOverlay.tsx +12 -5
- package/components/DecisionControl.tsx +2 -7
- package/components/DiagramBlock.tsx +46 -4
- package/components/DocBadges.tsx +12 -8
- package/components/FloatingQuickLabelPicker.tsx +2 -2
- package/components/PlanHeaderMenu.tsx +1 -1
- package/components/QuickLabelDropdown.tsx +9 -4
- package/components/ServerSessionReplacedBanner.tsx +29 -0
- package/components/Settings.tsx +76 -192
- package/components/TerminalToolsAnnouncementDialog.tsx +1 -1
- package/components/Viewer.tsx +30 -1
- package/components/ai/AIProviderBar.tsx +18 -1
- package/components/ai/DocumentAIChatPanel.tsx +4 -9
- package/components/ai/SessionAskNotice.tsx +33 -21
- package/components/blocks/QuestionBlock.tsx +99 -27
- package/components/blocks/QuestionContext.tsx +81 -0
- package/components/diagram/DiagramComposer.tsx +54 -3
- package/components/diagram/DiagramViewer.tsx +31 -2
- package/components/diagram/index.ts +1 -1
- package/components/html-viewer/HtmlViewer.tsx +13 -3
- package/components/html-viewer/bridge-script.asset.js +230 -14
- package/components/html-viewer/bridge-script.ts +230 -14
- package/components/html-viewer/useHtmlAnnotation.ts +36 -55
- package/components/settings/QuickLabelsTab.tsx +378 -0
- package/hooks/useAIChat.ts +83 -6
- package/hooks/useAIProviderActivation.ts +13 -0
- package/hooks/useAIProviderConfig.ts +3 -3
- package/hooks/useActiveSection.ts +3 -2
- package/hooks/useAgentToolSetting.ts +33 -0
- package/hooks/useAnnotationDraft.ts +53 -7
- package/hooks/useAnnotationHighlighter.ts +129 -5
- package/hooks/useExternalAnnotations.ts +21 -1
- package/hooks/useFirstRunAnnouncementWindow.ts +114 -0
- package/hooks/useLatchedTrue.ts +15 -0
- package/hooks/useLinkedDoc.ts +64 -4
- package/hooks/useModelCatalogs.ts +9 -2
- package/package.json +2 -2
- package/styles.css +1 -1
- package/themes/gruvbox.css +6 -0
- package/types.ts +19 -0
- package/utils/agentClosed.ts +33 -0
- package/utils/agentToolAnnouncement.ts +109 -0
- package/utils/agentToolSetting.ts +108 -0
- package/utils/aiProvider.ts +13 -40
- package/utils/annotationOwnsHighlight.ts +27 -0
- package/utils/annotationScope.ts +15 -0
- package/utils/askSessionAnnouncement.ts +107 -0
- package/utils/blockTargeting.ts +61 -2
- package/utils/diagramAskAI.ts +161 -0
- package/utils/parser.ts +382 -114
- package/utils/questionAnswers.ts +3 -1
- package/utils/quickLabels.ts +82 -2
- package/utils/serverSession.ts +85 -0
package/hooks/useLinkedDoc.ts
CHANGED
|
@@ -14,6 +14,7 @@ import type { ViewerHandle } from "../components/Viewer";
|
|
|
14
14
|
import type { SidebarTab } from "./useSidebar";
|
|
15
15
|
import type { SourceSaveCapability } from "@plannotator/core/source-save";
|
|
16
16
|
import type { VersionInfo } from "./usePlanDiff";
|
|
17
|
+
import { annotationOwnsHighlight } from "../utils/annotationOwnsHighlight";
|
|
17
18
|
|
|
18
19
|
export interface LinkedDocLoadData {
|
|
19
20
|
markdown?: string;
|
|
@@ -124,6 +125,29 @@ export interface CachedDocState {
|
|
|
124
125
|
versionInfo?: VersionInfo | null;
|
|
125
126
|
}
|
|
126
127
|
|
|
128
|
+
/**
|
|
129
|
+
* The session's documents split the way FEEDBACK must be: the root document
|
|
130
|
+
* (the plan, the annotated file, or the folder itself) once, and every other
|
|
131
|
+
* document once under its own path. `getDocAnnotations()` is NOT this split —
|
|
132
|
+
* it also carries the active document's live state, which the host exports
|
|
133
|
+
* from its own state too, so exporting both printed the open document twice.
|
|
134
|
+
*/
|
|
135
|
+
export interface FeedbackDocuments {
|
|
136
|
+
/**
|
|
137
|
+
* The root document's stashed state while a linked document is open. Null
|
|
138
|
+
* while the root itself is the active document: its annotations are then
|
|
139
|
+
* the host's live state, which the host exports itself.
|
|
140
|
+
*/
|
|
141
|
+
root: (CachedDocState & { renderAs: DocumentRenderAs }) | null;
|
|
142
|
+
/**
|
|
143
|
+
* Every document other than the root that carries state, keyed by path:
|
|
144
|
+
* the cached documents plus the active linked document's live state. The
|
|
145
|
+
* root's own annotations are never here; a copy of the root's path opened
|
|
146
|
+
* from the root itself is a separate annotation set and is listed by path.
|
|
147
|
+
*/
|
|
148
|
+
documents: Map<string, CachedDocState>;
|
|
149
|
+
}
|
|
150
|
+
|
|
127
151
|
export interface LinkedDocSessionState {
|
|
128
152
|
root: SavedPlanState;
|
|
129
153
|
docs: Map<string, CachedDocState>;
|
|
@@ -156,8 +180,12 @@ export interface UseLinkedDocReturn {
|
|
|
156
180
|
back: () => void;
|
|
157
181
|
/** Dismiss the current error */
|
|
158
182
|
dismissError: () => void;
|
|
159
|
-
/** All linked doc annotations including the active doc's live state (keyed by filepath)
|
|
183
|
+
/** All linked doc annotations including the active doc's live state (keyed by filepath).
|
|
184
|
+
* For counts and the cross-file panel; a feedback export reads getFeedbackDocuments(). */
|
|
160
185
|
getDocAnnotations: () => Map<string, CachedDocState>;
|
|
186
|
+
/** The root document and every other document, each exactly once — what a
|
|
187
|
+
* feedback export reads (see FeedbackDocuments). */
|
|
188
|
+
getFeedbackDocuments: () => FeedbackDocuments;
|
|
161
189
|
/**
|
|
162
190
|
* Replace the stored annotations of a document that is NOT the active one —
|
|
163
191
|
* a cached linked doc, or the stashed source document. This is what lets the
|
|
@@ -285,7 +313,7 @@ export function useLinkedDoc(options: UseLinkedDocOptions): UseLinkedDocReturn {
|
|
|
285
313
|
if (saved.annotations.length) {
|
|
286
314
|
setTimeout(() => {
|
|
287
315
|
viewerRef.current?.clearAllHighlights();
|
|
288
|
-
viewerRef.current?.applySharedAnnotations(saved.annotations);
|
|
316
|
+
viewerRef.current?.applySharedAnnotations(saved.annotations.filter(annotationOwnsHighlight));
|
|
289
317
|
}, HIGHLIGHT_REAPPLY_DELAY);
|
|
290
318
|
}
|
|
291
319
|
}, [
|
|
@@ -415,7 +443,7 @@ export function useLinkedDoc(options: UseLinkedDocOptions): UseLinkedDocReturn {
|
|
|
415
443
|
if (cached?.annotations.length) {
|
|
416
444
|
setTimeout(() => {
|
|
417
445
|
viewerRef.current?.clearAllHighlights();
|
|
418
|
-
viewerRef.current?.applySharedAnnotations(cached.annotations);
|
|
446
|
+
viewerRef.current?.applySharedAnnotations(cached.annotations.filter(annotationOwnsHighlight));
|
|
419
447
|
}, HIGHLIGHT_REAPPLY_DELAY);
|
|
420
448
|
}
|
|
421
449
|
}, [
|
|
@@ -562,7 +590,7 @@ export function useLinkedDoc(options: UseLinkedDocOptions): UseLinkedDocReturn {
|
|
|
562
590
|
if (state.root.annotations.length) {
|
|
563
591
|
setTimeout(() => {
|
|
564
592
|
viewerRef.current?.clearAllHighlights();
|
|
565
|
-
viewerRef.current?.applySharedAnnotations(state.root.annotations);
|
|
593
|
+
viewerRef.current?.applySharedAnnotations(state.root.annotations.filter(annotationOwnsHighlight));
|
|
566
594
|
}, HIGHLIGHT_REAPPLY_DELAY);
|
|
567
595
|
}
|
|
568
596
|
}, [
|
|
@@ -644,6 +672,37 @@ export function useLinkedDoc(options: UseLinkedDocOptions): UseLinkedDocReturn {
|
|
|
644
672
|
// identity of this callback is what tells memoized readers to recompute.
|
|
645
673
|
}, [linkedDoc, annotations, globalAttachments, sourceFilePath, sourceConverted, getDocumentMarkdown, storeRevision]);
|
|
646
674
|
|
|
675
|
+
const getFeedbackDocuments = useCallback((): FeedbackDocuments => {
|
|
676
|
+
const documents = new Map(docCache.current);
|
|
677
|
+
if (linkedDoc) {
|
|
678
|
+
documents.set(linkedDoc.filepath, {
|
|
679
|
+
annotations: [...annotations],
|
|
680
|
+
globalAttachments: [...globalAttachments],
|
|
681
|
+
markdown: getDocumentMarkdown?.(linkedDoc.filepath, linkedDoc.markdown) ?? linkedDoc.markdown,
|
|
682
|
+
isConverted: linkedDoc.isConverted,
|
|
683
|
+
});
|
|
684
|
+
}
|
|
685
|
+
// A cache entry under the root's own path is NOT the root: it is a copy
|
|
686
|
+
// the reviewer opened from the root itself (an HTML "Home" link, or
|
|
687
|
+
// index.html#intro from index.html — a backlink only routes through
|
|
688
|
+
// back() while a linked doc is open). Its comments are a separate set the
|
|
689
|
+
// counts include, so it is exported under its path, never dropped.
|
|
690
|
+
const saved = linkedDoc ? savedPlanState.current : null;
|
|
691
|
+
return {
|
|
692
|
+
root: saved
|
|
693
|
+
? {
|
|
694
|
+
annotations: [...saved.annotations],
|
|
695
|
+
globalAttachments: [...saved.globalAttachments],
|
|
696
|
+
markdown: saved.markdown,
|
|
697
|
+
isConverted: !!sourceConverted,
|
|
698
|
+
renderAs: saved.renderAs,
|
|
699
|
+
}
|
|
700
|
+
: null,
|
|
701
|
+
documents,
|
|
702
|
+
};
|
|
703
|
+
// storeRevision: same reason as getDocAnnotations above.
|
|
704
|
+
}, [linkedDoc, annotations, globalAttachments, sourceConverted, getDocumentMarkdown, storeRevision]);
|
|
705
|
+
|
|
647
706
|
return {
|
|
648
707
|
isActive: linkedDoc !== null,
|
|
649
708
|
filepath: linkedDoc?.filepath ?? null,
|
|
@@ -654,6 +713,7 @@ export function useLinkedDoc(options: UseLinkedDocOptions): UseLinkedDocReturn {
|
|
|
654
713
|
back,
|
|
655
714
|
dismissError,
|
|
656
715
|
getDocAnnotations,
|
|
716
|
+
getFeedbackDocuments,
|
|
657
717
|
updateStoredAnnotations,
|
|
658
718
|
snapshotSession,
|
|
659
719
|
restoreSession,
|
|
@@ -14,7 +14,10 @@ export { effortSelectOptions, modelSelectOptions } from '@plannotator/core/model
|
|
|
14
14
|
* Claude / Codex model catalogs for the agent launchers (review, Code Tour,
|
|
15
15
|
* Guided Review) — the SAME lists Ask AI shows. Each is the Ask AI provider's
|
|
16
16
|
* discovered list, fetched through `/api/ai/capabilities?activate=<id>` (which
|
|
17
|
-
* runs the provider's server-cached discovery).
|
|
17
|
+
* runs the provider's server-cached discovery). When a session bridge makes
|
|
18
|
+
* Ask AI bridge-only, the server reports these under `catalogProviders`
|
|
19
|
+
* instead of `providers`, so the launchers keep them while Ask AI cannot
|
|
20
|
+
* offer them. Nothing is fetched until a
|
|
18
21
|
* surface asks for one engine with `useModelCatalogs(...).load(engine)`, and
|
|
19
22
|
* only when that engine is installed, so opening a launcher spawns only the
|
|
20
23
|
* selected CLI. While a fetch is in flight the static fallback is shown with
|
|
@@ -67,7 +70,11 @@ function loadCatalogEntry(engine: CatalogEngine): Promise<LoadedCatalog> {
|
|
|
67
70
|
load = fetch(`/api/ai/capabilities?activate=${encodeURIComponent(id)}`)
|
|
68
71
|
.then((res) => (res.ok ? res.json() : null))
|
|
69
72
|
.then((data): LoadedCatalog => {
|
|
70
|
-
|
|
73
|
+
// A server whose Ask AI is a session bridge lists the SDK providers
|
|
74
|
+
// only under `catalogProviders` (never under `providers`, which Ask AI
|
|
75
|
+
// reads), so the launchers look in both.
|
|
76
|
+
const matches = (p: { id?: string; name?: string }) => p.id === id || p.name === id;
|
|
77
|
+
const provider = data?.providers?.find(matches) ?? data?.catalogProviders?.find(matches);
|
|
71
78
|
const models = provider?.models;
|
|
72
79
|
if (!Array.isArray(models) || models.length === 0) return failed();
|
|
73
80
|
// The server answers 200 with its static fallback when discovery
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plannotator/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.52.0",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
"@lezer/highlight": "^1.2.3",
|
|
78
78
|
"@pierre/diffs": "1.3.6",
|
|
79
79
|
"@plannotator/atomic-editor": "^0.9.0",
|
|
80
|
-
"@plannotator/core": "0.25.
|
|
80
|
+
"@plannotator/core": "0.25.12",
|
|
81
81
|
"@plannotator/markdown-editor": "^0.5.0",
|
|
82
82
|
"@plannotator/web-highlighter": "^0.8.1",
|
|
83
83
|
"@tanstack/react-table": "^8.21.3",
|