@agent-native/core 0.42.0 → 0.44.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/README.md +17 -56
- package/dist/chat-threads/store.d.ts.map +1 -1
- package/dist/chat-threads/store.js +71 -10
- package/dist/chat-threads/store.js.map +1 -1
- package/dist/cli/pr-visual-recap-workflow.d.ts +1 -1
- package/dist/cli/pr-visual-recap-workflow.d.ts.map +1 -1
- package/dist/cli/pr-visual-recap-workflow.js +1 -1
- package/dist/cli/pr-visual-recap-workflow.js.map +1 -1
- package/dist/cli/recap.d.ts.map +1 -1
- package/dist/cli/recap.js +13 -13
- package/dist/cli/recap.js.map +1 -1
- package/dist/cli/skills.d.ts +2 -6
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +21 -79
- package/dist/cli/skills.js.map +1 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +76 -18
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/blocks/index.d.ts +9 -0
- package/dist/client/blocks/index.d.ts.map +1 -1
- package/dist/client/blocks/index.js +9 -0
- package/dist/client/blocks/index.js.map +1 -1
- package/dist/client/blocks/library/AnnotatedCodeBlock.d.ts.map +1 -1
- package/dist/client/blocks/library/AnnotatedCodeBlock.js +3 -3
- package/dist/client/blocks/library/AnnotatedCodeBlock.js.map +1 -1
- package/dist/client/blocks/library/ApiEndpointBlock.d.ts.map +1 -1
- package/dist/client/blocks/library/ApiEndpointBlock.js +1 -1
- package/dist/client/blocks/library/ApiEndpointBlock.js.map +1 -1
- package/dist/client/blocks/library/DiffBlock.d.ts.map +1 -1
- package/dist/client/blocks/library/DiffBlock.js +128 -19
- package/dist/client/blocks/library/DiffBlock.js.map +1 -1
- package/dist/client/blocks/library/FileTreeBlock.d.ts.map +1 -1
- package/dist/client/blocks/library/FileTreeBlock.js +31 -4
- package/dist/client/blocks/library/FileTreeBlock.js.map +1 -1
- package/dist/client/blocks/library/JsonExplorerBlock.js +1 -1
- package/dist/client/blocks/library/JsonExplorerBlock.js.map +1 -1
- package/dist/client/blocks/library/MermaidBlock.js +1 -1
- package/dist/client/blocks/library/MermaidBlock.js.map +1 -1
- package/dist/client/blocks/library/callout.config.d.ts +29 -0
- package/dist/client/blocks/library/callout.config.d.ts.map +1 -0
- package/dist/client/blocks/library/callout.config.js +33 -0
- package/dist/client/blocks/library/callout.config.js.map +1 -0
- package/dist/client/blocks/library/callout.d.ts +20 -0
- package/dist/client/blocks/library/callout.d.ts.map +1 -0
- package/dist/client/blocks/library/callout.js +61 -0
- package/dist/client/blocks/library/callout.js.map +1 -0
- package/dist/client/blocks/library/checklist.d.ts.map +1 -1
- package/dist/client/blocks/library/checklist.js +3 -3
- package/dist/client/blocks/library/checklist.js.map +1 -1
- package/dist/client/blocks/library/code-tabs.js +1 -1
- package/dist/client/blocks/library/code-tabs.js.map +1 -1
- package/dist/client/blocks/library/diagram.config.d.ts +64 -0
- package/dist/client/blocks/library/diagram.config.d.ts.map +1 -0
- package/dist/client/blocks/library/diagram.config.js +111 -0
- package/dist/client/blocks/library/diagram.config.js.map +1 -0
- package/dist/client/blocks/library/diagram.d.ts +16 -0
- package/dist/client/blocks/library/diagram.d.ts.map +1 -0
- package/dist/client/blocks/library/diagram.js +261 -0
- package/dist/client/blocks/library/diagram.js.map +1 -0
- package/dist/client/blocks/library/question-form.config.d.ts +69 -0
- package/dist/client/blocks/library/question-form.config.d.ts.map +1 -0
- package/dist/client/blocks/library/question-form.config.js +58 -0
- package/dist/client/blocks/library/question-form.config.js.map +1 -0
- package/dist/client/blocks/library/question-form.d.ts +20 -0
- package/dist/client/blocks/library/question-form.d.ts.map +1 -0
- package/dist/client/blocks/library/question-form.js +286 -0
- package/dist/client/blocks/library/question-form.js.map +1 -0
- package/dist/client/blocks/library/sanitize-html.d.ts +5 -0
- package/dist/client/blocks/library/sanitize-html.d.ts.map +1 -0
- package/dist/client/blocks/library/sanitize-html.js +240 -0
- package/dist/client/blocks/library/sanitize-html.js.map +1 -0
- package/dist/client/blocks/library/server-specs.d.ts.map +1 -1
- package/dist/client/blocks/library/server-specs.js +49 -0
- package/dist/client/blocks/library/server-specs.js.map +1 -1
- package/dist/client/blocks/library/specs.d.ts.map +1 -1
- package/dist/client/blocks/library/specs.js +9 -0
- package/dist/client/blocks/library/specs.js.map +1 -1
- package/dist/client/blocks/library/tabs.d.ts.map +1 -1
- package/dist/client/blocks/library/tabs.js +12 -12
- package/dist/client/blocks/library/tabs.js.map +1 -1
- package/dist/client/blocks/library/wireframe-kit.d.ts +260 -0
- package/dist/client/blocks/library/wireframe-kit.d.ts.map +1 -0
- package/dist/client/blocks/library/wireframe-kit.js +920 -0
- package/dist/client/blocks/library/wireframe-kit.js.map +1 -0
- package/dist/client/blocks/library/wireframe.config.d.ts +123 -0
- package/dist/client/blocks/library/wireframe.config.d.ts.map +1 -0
- package/dist/client/blocks/library/wireframe.config.js +311 -0
- package/dist/client/blocks/library/wireframe.config.js.map +1 -0
- package/dist/client/blocks/library/wireframe.d.ts +15 -0
- package/dist/client/blocks/library/wireframe.d.ts.map +1 -0
- package/dist/client/blocks/library/wireframe.js +206 -0
- package/dist/client/blocks/library/wireframe.js.map +1 -0
- package/dist/client/blocks/mdx.d.ts.map +1 -1
- package/dist/client/blocks/mdx.js +11 -0
- package/dist/client/blocks/mdx.js.map +1 -1
- package/dist/client/blocks/registry.d.ts +9 -0
- package/dist/client/blocks/registry.d.ts.map +1 -1
- package/dist/client/blocks/registry.js +12 -5
- package/dist/client/blocks/registry.js.map +1 -1
- package/dist/client/blocks/server.d.ts +1 -0
- package/dist/client/blocks/server.d.ts.map +1 -1
- package/dist/client/blocks/server.js +1 -0
- package/dist/client/blocks/server.js.map +1 -1
- package/dist/client/blocks/types.d.ts +8 -0
- package/dist/client/blocks/types.d.ts.map +1 -1
- package/dist/client/blocks/types.js.map +1 -1
- package/dist/client/rich-markdown-editor/DragHandle.d.ts.map +1 -1
- package/dist/client/rich-markdown-editor/DragHandle.js +112 -84
- package/dist/client/rich-markdown-editor/DragHandle.js.map +1 -1
- package/dist/client/rich-markdown-editor/RegistryBlockNode.d.ts.map +1 -1
- package/dist/client/rich-markdown-editor/RegistryBlockNode.js +1 -1
- package/dist/client/rich-markdown-editor/RegistryBlockNode.js.map +1 -1
- package/dist/client/rich-markdown-editor/SharedRichEditor.d.ts +9 -1
- package/dist/client/rich-markdown-editor/SharedRichEditor.d.ts.map +1 -1
- package/dist/client/rich-markdown-editor/SharedRichEditor.js +3 -1
- package/dist/client/rich-markdown-editor/SharedRichEditor.js.map +1 -1
- package/dist/client/rich-markdown-editor/extensions.d.ts +13 -1
- package/dist/client/rich-markdown-editor/extensions.d.ts.map +1 -1
- package/dist/client/rich-markdown-editor/extensions.js +4 -2
- package/dist/client/rich-markdown-editor/extensions.js.map +1 -1
- package/dist/client/rich-markdown-editor/useCollabReconcile.d.ts.map +1 -1
- package/dist/client/rich-markdown-editor/useCollabReconcile.js +11 -1
- package/dist/client/rich-markdown-editor/useCollabReconcile.js.map +1 -1
- package/dist/server/poll.d.ts.map +1 -1
- package/dist/server/poll.js +30 -14
- package/dist/server/poll.js.map +1 -1
- package/dist/styles/agent-native.css +1 -0
- package/dist/styles/blocks.css +1388 -0
- package/dist/templates/default/.agents/skills/storing-data/SKILL.md +2 -0
- package/dist/templates/workspace-core/.agents/skills/performance/SKILL.md +141 -0
- package/dist/templates/workspace-core/.agents/skills/storing-data/SKILL.md +2 -0
- package/docs/content/plan-plugin.md +8 -8
- package/docs/content/pr-visual-recap.md +2 -2
- package/docs/content/template-plan.md +94 -17
- package/package.json +2 -1
- package/src/templates/default/.agents/skills/storing-data/SKILL.md +2 -0
- package/src/templates/workspace-core/.agents/skills/performance/SKILL.md +141 -0
- package/src/templates/workspace-core/.agents/skills/storing-data/SKILL.md +2 -0
- package/docs/content/visual-plans.md +0 -82
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useMemo, useState } from "react";
|
|
2
|
+
import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, } from "react";
|
|
3
3
|
import { IconChevronRight, IconColumns, IconDotsVertical, IconFileDiff, IconList, IconPlus, IconTrash, } from "@tabler/icons-react";
|
|
4
4
|
import { common, createLowlight } from "lowlight";
|
|
5
5
|
import { cn } from "../../utils.js";
|
|
6
|
-
import { AnnotationGutterMarker,
|
|
6
|
+
import { AnnotationGutterMarker, buildLineMarkerMap, hasRailAnnotations, rangeLabel, resolveAnnotations, } from "./annotation-rail.js";
|
|
7
7
|
import { DevInput, DevLabel, DevTextarea, DevSelect } from "./dev-doc-ui.js";
|
|
8
8
|
/**
|
|
9
9
|
* Split text into lines, each KEEPING its trailing newline (so the change
|
|
@@ -372,10 +372,42 @@ const SIGN = {
|
|
|
372
372
|
removed: "−",
|
|
373
373
|
context: " ",
|
|
374
374
|
};
|
|
375
|
-
const LINE_NO_CLASS = "select-none px-2 py-0 text-right font-mono
|
|
376
|
-
const DIFF_LINE_CLASS = "block min-w-max flex-1 whitespace-pre px-2 py-0 font-mono
|
|
375
|
+
const LINE_NO_CLASS = "select-none px-2 py-0 text-right font-mono [font-size:var(--plan-code-size)] leading-5 text-muted-foreground tabular-nums";
|
|
376
|
+
const DIFF_LINE_CLASS = "block min-w-max flex-1 whitespace-pre px-2 py-0 font-mono [font-size:var(--plan-code-size)] leading-5 text-foreground";
|
|
377
377
|
const DEFAULT_VISIBLE_DIFF_LINES = 15;
|
|
378
378
|
const MAX_DIFF_LCS_CELLS = 1_000_000;
|
|
379
|
+
/**
|
|
380
|
+
* Below this rendered container width (px) a diff drops side-by-side `split`
|
|
381
|
+
* mode and falls back to `unified`: split's two line-number gutters double the
|
|
382
|
+
* width the code needs, exactly where space is tightest (e.g. a diff nested in a
|
|
383
|
+
* vertical-tabs content column). Measured from the block's own box, not the
|
|
384
|
+
* viewport, so the fallback fires by available width at any nesting depth.
|
|
385
|
+
*/
|
|
386
|
+
const SPLIT_MIN_WIDTH = 560;
|
|
387
|
+
/**
|
|
388
|
+
* Observe the rendered inline width of an element. Returns a ref to attach plus
|
|
389
|
+
* the measured content-box width (null until the first ResizeObserver tick).
|
|
390
|
+
* Lets the diff pick an effective mode from the width it was actually handed — a
|
|
391
|
+
* measurement CSS container queries can't drive, since switching split↔unified
|
|
392
|
+
* is a structural (DOM) change, not a style toggle.
|
|
393
|
+
*/
|
|
394
|
+
function useContainerWidth() {
|
|
395
|
+
const ref = useRef(null);
|
|
396
|
+
const [width, setWidth] = useState(null);
|
|
397
|
+
useEffect(() => {
|
|
398
|
+
const el = ref.current;
|
|
399
|
+
if (!el || typeof ResizeObserver === "undefined")
|
|
400
|
+
return;
|
|
401
|
+
const observer = new ResizeObserver((entries) => {
|
|
402
|
+
const entry = entries[0];
|
|
403
|
+
if (entry)
|
|
404
|
+
setWidth(entry.contentRect.width);
|
|
405
|
+
});
|
|
406
|
+
observer.observe(el);
|
|
407
|
+
return () => observer.disconnect();
|
|
408
|
+
}, []);
|
|
409
|
+
return [ref, width];
|
|
410
|
+
}
|
|
379
411
|
function splitDiffFilename(filename) {
|
|
380
412
|
const value = filename?.trim() || "diff";
|
|
381
413
|
const segments = value.split("/").filter(Boolean);
|
|
@@ -393,6 +425,7 @@ function DiffRead({ data, blockId, title, summary, ctx, }) {
|
|
|
393
425
|
const [expanded, setExpanded] = useState(() => new Set());
|
|
394
426
|
const [showAllRows, setShowAllRows] = useState(false);
|
|
395
427
|
const [activeIndex, setActiveIndex] = useState(null);
|
|
428
|
+
const [containerRef, containerWidth] = useContainerWidth();
|
|
396
429
|
const rows = useMemo(() => buildRows(diffLines(data.before, data.after)), [data.before, data.after]);
|
|
397
430
|
const language = useMemo(() => resolveDiffLanguage(data), [data.filename, data.language]);
|
|
398
431
|
const fileParts = useMemo(() => splitDiffFilename(data.filename), [data.filename]);
|
|
@@ -407,6 +440,56 @@ function DiffRead({ data, blockId, title, summary, ctx, }) {
|
|
|
407
440
|
? beforeLineCount
|
|
408
441
|
: afterLineCount), [data.annotations, beforeLineCount, afterLineCount]);
|
|
409
442
|
const hasAnnotations = hasRailAnnotations(resolved);
|
|
443
|
+
// Effective render mode. The right-margin popover works in both unified and
|
|
444
|
+
// split, so annotations no longer force a mode; only a container narrower than
|
|
445
|
+
// SPLIT_MIN_WIDTH falls back to unified so split's doubled gutters never crush
|
|
446
|
+
// the code. `canSplit` also gates the mode toggle (hidden when unavailable).
|
|
447
|
+
const narrow = containerWidth != null && containerWidth < SPLIT_MIN_WIDTH;
|
|
448
|
+
const canSplit = !narrow;
|
|
449
|
+
const effectiveMode = canSplit ? mode : "unified";
|
|
450
|
+
// Annotation popover (diff): a marked line shows its note as a hover popover
|
|
451
|
+
// pinned in the diff's right margin and aligned to that line — no inline notes
|
|
452
|
+
// and no permanent side rail, so the code keeps its full width. A short
|
|
453
|
+
// hover-intent delay lets the pointer travel from the line into the popover.
|
|
454
|
+
const clearTimer = useRef(null);
|
|
455
|
+
const handleActiveChange = useCallback((index) => {
|
|
456
|
+
if (clearTimer.current) {
|
|
457
|
+
clearTimeout(clearTimer.current);
|
|
458
|
+
clearTimer.current = null;
|
|
459
|
+
}
|
|
460
|
+
if (index == null) {
|
|
461
|
+
clearTimer.current = setTimeout(() => setActiveIndex(null), 120);
|
|
462
|
+
}
|
|
463
|
+
else {
|
|
464
|
+
setActiveIndex(index);
|
|
465
|
+
}
|
|
466
|
+
}, []);
|
|
467
|
+
useEffect(() => () => {
|
|
468
|
+
if (clearTimer.current)
|
|
469
|
+
clearTimeout(clearTimer.current);
|
|
470
|
+
}, []);
|
|
471
|
+
const activeAnnotation = activeIndex == null
|
|
472
|
+
? null
|
|
473
|
+
: (resolved.find((r) => r.index === activeIndex && r.range) ?? null);
|
|
474
|
+
// Vertical center of the active marker's anchor row within the section, so the
|
|
475
|
+
// popover sits beside that line. Rows are in page flow (no inner vertical
|
|
476
|
+
// scroll), so a DOM measure on activeIndex change is stable.
|
|
477
|
+
const [popoverTop, setPopoverTop] = useState(null);
|
|
478
|
+
useLayoutEffect(() => {
|
|
479
|
+
const host = containerRef.current;
|
|
480
|
+
if (activeIndex == null || !host) {
|
|
481
|
+
setPopoverTop(null);
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
const rowEl = host.querySelector(`[data-annot-row="${activeIndex}"]`);
|
|
485
|
+
if (!rowEl) {
|
|
486
|
+
setPopoverTop(null);
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
const hostRect = host.getBoundingClientRect();
|
|
490
|
+
const rowRect = rowEl.getBoundingClientRect();
|
|
491
|
+
setPopoverTop(rowRect.top - hostRect.top + rowRect.height / 2);
|
|
492
|
+
}, [activeIndex, containerRef]);
|
|
410
493
|
// Side-scoped line → markers maps so a row only lights from its own side.
|
|
411
494
|
const beforeMarkers = useMemo(() => buildLineMarkerMap(resolved.filter((r) => annotationSide(r.annotation) === "before")), [resolved]);
|
|
412
495
|
const afterMarkers = useMemo(() => buildLineMarkerMap(resolved.filter((r) => annotationSide(r.annotation) !== "before")), [resolved]);
|
|
@@ -435,7 +518,7 @@ function DiffRead({ data, blockId, title, summary, ctx, }) {
|
|
|
435
518
|
const added = rows.filter((r) => r.kind === "added").length;
|
|
436
519
|
const removed = rows.filter((r) => r.kind === "removed").length;
|
|
437
520
|
const unchanged = data.before === data.after;
|
|
438
|
-
const totalVisibleLineCount =
|
|
521
|
+
const totalVisibleLineCount = effectiveMode === "split" ? splitLineCount : rows.length;
|
|
439
522
|
const shouldLimitRows = totalVisibleLineCount > DEFAULT_VISIBLE_DIFF_LINES;
|
|
440
523
|
// Never truncate away an annotated row: extend the window past the last one.
|
|
441
524
|
const effectiveRowLimit = useMemo(() => {
|
|
@@ -453,7 +536,7 @@ function DiffRead({ data, blockId, title, summary, ctx, }) {
|
|
|
453
536
|
return limit;
|
|
454
537
|
}, [showAllRows, shouldLimitRows, hasAnnotations, rows, markersForRow]);
|
|
455
538
|
const rowLimit = effectiveRowLimit;
|
|
456
|
-
const displayedRows =
|
|
539
|
+
const displayedRows = effectiveMode === "unified" && rowLimit ? rows.slice(0, rowLimit) : rows;
|
|
457
540
|
const toggleRun = (index) => setExpanded((prev) => {
|
|
458
541
|
const next = new Set(prev);
|
|
459
542
|
if (next.has(index))
|
|
@@ -462,10 +545,9 @@ function DiffRead({ data, blockId, title, summary, ctx, }) {
|
|
|
462
545
|
next.add(index);
|
|
463
546
|
return next;
|
|
464
547
|
});
|
|
465
|
-
return (_jsxs("section", { className: "plan-block group/diff-block", "data-block-id": blockId, children: [title && _jsx("div", { className: "plan-block-label", children: title }), summary && (_jsx("p", { className: "mb-3 text-sm leading-relaxed text-plan-muted", children: summary })), _jsxs("div", { className: cn(
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
: `Show all ${totalVisibleLineCount} lines`] }))] }), hasAnnotations && (_jsx(AnnotationNoteRail, { items: resolved, activeIndex: activeIndex, onActiveChange: setActiveIndex, ctx: ctx, showMarker: true }))] })] }));
|
|
548
|
+
return (_jsxs("section", { ref: containerRef, className: "relative plan-block group/diff-block", "data-block-id": blockId, children: [title && _jsx("div", { className: "plan-block-label", children: title }), summary && (_jsx("p", { className: "mb-3 text-sm leading-relaxed text-plan-muted", children: summary })), _jsxs("div", { className: "overflow-hidden rounded-md border border-border bg-background", children: [_jsxs("div", { className: "flex min-h-10 flex-wrap items-center gap-2 border-b border-border bg-muted/60 px-3 py-1.5", children: [_jsx(IconFileDiff, { className: "size-4 shrink-0 text-muted-foreground" }), _jsxs("span", { className: "flex min-w-0 flex-1 items-baseline gap-1.5 font-mono", title: data.filename || undefined, children: [_jsx("span", { className: "min-w-0 max-w-[16rem] truncate text-[13px] font-semibold leading-5 text-foreground", children: fileParts.basename }), fileParts.directory && (_jsx("span", { className: "min-w-0 flex-1 truncate text-[11px] leading-5 text-muted-foreground/70", children: fileParts.directory }))] }), _jsxs("span", { className: "ml-1 flex shrink-0 items-center gap-2 font-mono text-xs", children: [_jsxs("span", { className: "text-emerald-700 dark:text-emerald-300", children: ["+", added] }), _jsxs("span", { className: "text-destructive", children: ["\u2212", removed] })] }), canSplit && (_jsxs("div", { className: "pointer-events-none ml-auto flex shrink-0 items-center overflow-hidden rounded-md border border-border bg-background opacity-0 transition-opacity group-hover/diff-block:pointer-events-auto group-hover/diff-block:opacity-100 group-focus-within/diff-block:pointer-events-auto group-focus-within/diff-block:opacity-100", children: [_jsx(ModeButton, { active: mode === "unified", onClick: () => setMode("unified"), icon: _jsx(IconList, { className: "size-3.5" }), label: "Unified" }), _jsx(ModeButton, { active: mode === "split", onClick: () => setMode("split"), icon: _jsx(IconColumns, { className: "size-3.5" }), label: "Split" })] }))] }), unchanged ? (_jsx("div", { className: "px-4 py-6 text-center font-mono text-sm text-muted-foreground", children: "No changes" })) : effectiveMode === "split" ? (_jsx(SplitView, { rows: rows, language: language, rowLimit: rowLimit, markersForRow: markersForRow, activeIndex: activeIndex, onActiveChange: handleActiveChange })) : (_jsx(UnifiedView, { rows: displayedRows, language: language, expanded: expanded, onToggleRun: toggleRun, markersForRow: markersForRow, anchoredRow: anchoredRow, activeIndex: activeIndex, onActiveChange: handleActiveChange })), !unchanged && shouldLimitRows && (_jsxs("button", { type: "button", "data-plan-interactive": true, "aria-expanded": showAllRows, onClick: () => setShowAllRows((current) => !current), className: "flex h-7 w-full items-center justify-center gap-1.5 border-t border-border bg-background px-2 text-[11px] font-medium text-muted-foreground transition-colors hover:bg-muted/70 hover:text-foreground", children: [_jsx(IconChevronRight, { className: cn("size-3 shrink-0 transition-transform", showAllRows ? "-rotate-90" : "rotate-90") }), showAllRows
|
|
549
|
+
? "Show fewer"
|
|
550
|
+
: `Show all ${totalVisibleLineCount} lines`] }))] }), activeAnnotation && popoverTop != null && (_jsx(AnnotationPopover, { item: activeAnnotation, top: popoverTop, onActiveChange: handleActiveChange, ctx: ctx }))] }));
|
|
469
551
|
}
|
|
470
552
|
function ModeButton({ active, onClick, icon, label, }) {
|
|
471
553
|
return (_jsxs("button", { type: "button", "data-plan-interactive": true, onClick: onClick, "aria-pressed": active, className: cn("flex cursor-pointer items-center gap-1 px-2 py-1 text-xs font-medium transition-colors", active
|
|
@@ -491,6 +573,19 @@ function annotatedRowBg(info) {
|
|
|
491
573
|
? "bg-amber-400/20 dark:bg-amber-300/15"
|
|
492
574
|
: "bg-amber-400/[0.07] dark:bg-amber-300/[0.07]";
|
|
493
575
|
}
|
|
576
|
+
/**
|
|
577
|
+
* Whether `row` is the FIRST line of `marker`'s resolved range. The numbered pip
|
|
578
|
+
* renders only on this line, so a multi-line annotation shows a single marker at
|
|
579
|
+
* the top of its span instead of repeating the same number down every line it
|
|
580
|
+
* covers. The amber band still washes the whole range (via `annotatedRowBg`), so
|
|
581
|
+
* the span stays visually grouped without the column of duplicate numbers.
|
|
582
|
+
*/
|
|
583
|
+
function isMarkerRangeStart(row, marker) {
|
|
584
|
+
if (!marker.range)
|
|
585
|
+
return false;
|
|
586
|
+
const lineNo = annotationSide(marker.annotation) === "before" ? row.oldNo : row.newNo;
|
|
587
|
+
return lineNo === marker.range.start;
|
|
588
|
+
}
|
|
494
589
|
/* ── Unified view ──────────────────────────────────────────────────────────── */
|
|
495
590
|
function UnifiedView({ rows, language, expanded, onToggleRun, markersForRow, anchoredRow, activeIndex, onActiveChange, }) {
|
|
496
591
|
const segments = useMemo(() => segmentRows(rows, anchoredRow), [rows, anchoredRow]);
|
|
@@ -504,7 +599,7 @@ function UnifiedView({ rows, language, expanded, onToggleRun, markersForRow, anc
|
|
|
504
599
|
showMarkerColumn,
|
|
505
600
|
};
|
|
506
601
|
let runIndex = 0;
|
|
507
|
-
return (_jsx("div", { className: "overflow-x-auto", children: _jsx("div", { className: "w-max min-w-full font-mono
|
|
602
|
+
return (_jsx("div", { className: "overflow-x-auto", children: _jsx("div", { className: "w-max min-w-full font-mono [font-size:var(--plan-code-size)] leading-5", children: segments.map((segment, idx) => {
|
|
508
603
|
if ("collapsed" in segment) {
|
|
509
604
|
const key = runIndex++;
|
|
510
605
|
const open = expanded.has(key);
|
|
@@ -517,15 +612,28 @@ function UnifiedView({ rows, language, expanded, onToggleRun, markersForRow, anc
|
|
|
517
612
|
function UnifiedRow({ language, row, markersForRow, activeIndex, onActiveChange, showMarkerColumn, }) {
|
|
518
613
|
const markers = markersForRow(row);
|
|
519
614
|
const info = rowMarkerInfo(markers, activeIndex);
|
|
520
|
-
|
|
615
|
+
const startMarker = markers.find((marker) => isMarkerRangeStart(row, marker));
|
|
616
|
+
return (_jsxs("div", { "data-annot-row": startMarker ? startMarker.index : undefined, className: cn("flex min-h-5 min-w-full", ROW_BG[row.kind], annotatedRowBg(info)), onMouseEnter: info ? () => onActiveChange(info.primaryIndex) : undefined, onMouseLeave: info ? () => onActiveChange(null) : undefined, children: [_jsx("span", { className: cn(LINE_NO_CLASS, "w-[52px]"), children: row.oldNo ?? "" }), _jsx("span", { className: cn(LINE_NO_CLASS, "w-[52px]"), children: row.newNo ?? "" }), _jsx("span", { className: cn("w-6 shrink-0 select-none py-0 text-center font-semibold leading-5", GUTTER_BG[row.kind], SIGN_COLOR[row.kind]), children: SIGN[row.kind] }), showMarkerColumn && (_jsx(MarkerCell, { startMarker: startMarker, active: startMarker != null && startMarker.index === activeIndex })), _jsx(DiffLineText, { text: row.text, language: language })] }));
|
|
521
617
|
}
|
|
522
618
|
/**
|
|
523
619
|
* The fixed-width marker column rendered between the sign gutter and the code.
|
|
524
|
-
*
|
|
525
|
-
*
|
|
620
|
+
* `startMarker` is set only on the FIRST line of an annotation's range, so the
|
|
621
|
+
* numbered pip appears once at the top of a span; every other row (the rest of a
|
|
622
|
+
* span, and every unannotated row in a diff that has annotations) renders an
|
|
623
|
+
* empty spacer so the code text stays aligned.
|
|
624
|
+
*/
|
|
625
|
+
function MarkerCell({ startMarker, active, }) {
|
|
626
|
+
return (_jsx("span", { className: "flex w-6 shrink-0 select-none items-center justify-center py-0", children: startMarker != null && (_jsx(AnnotationGutterMarker, { marker: startMarker.marker, active: active })) }));
|
|
627
|
+
}
|
|
628
|
+
/**
|
|
629
|
+
* The hover popover for a diff annotation, pinned in the diff's right margin and
|
|
630
|
+
* vertically centered on the annotated line (`top` is measured by the caller).
|
|
631
|
+
* It shows the marker pip, line range, optional label, and the markdown note —
|
|
632
|
+
* beside the code instead of interrupting the diff flow — and keeps the
|
|
633
|
+
* annotation active while hovered so the pointer can travel from line to note.
|
|
526
634
|
*/
|
|
527
|
-
function
|
|
528
|
-
return (
|
|
635
|
+
function AnnotationPopover({ item, top, onActiveChange, ctx, }) {
|
|
636
|
+
return (_jsxs("div", { role: "tooltip", style: { top }, onMouseEnter: () => onActiveChange(item.index), onMouseLeave: () => onActiveChange(null), className: "absolute right-2 z-20 w-[min(17rem,calc(100%-3rem))] -translate-y-1/2 rounded-lg border border-amber-400/70 bg-background px-3 py-2.5 shadow-xl dark:border-amber-300/45", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-x-2 gap-y-0.5", children: [_jsx(AnnotationGutterMarker, { marker: item.marker, active: true }), _jsx("span", { className: "text-[11px] font-semibold uppercase tracking-wide text-muted-foreground", children: rangeLabel(item) }), item.annotation.label && (_jsx("span", { className: "text-[13px] font-semibold text-foreground", children: item.annotation.label }))] }), _jsx("div", { className: "plan-annotation-note mt-1 text-[13px] leading-relaxed text-foreground/85", children: ctx.renderMarkdown ? (ctx.renderMarkdown(item.annotation.note)) : (_jsx("p", { children: item.annotation.note })) })] }));
|
|
529
637
|
}
|
|
530
638
|
function CollapsedRow({ count, open, onClick, }) {
|
|
531
639
|
return (_jsxs("button", { type: "button", "data-plan-interactive": true, onClick: onClick, className: "flex w-full cursor-pointer items-center gap-2 border-y border-border bg-muted/70 px-3 py-1 text-left text-xs text-muted-foreground transition-colors hover:bg-muted hover:text-foreground", children: [_jsx(IconDotsVertical, { className: "size-3.5 shrink-0" }), _jsxs("span", { children: [open ? "Hide" : "Show", " ", count, " unchanged line", count === 1 ? "" : "s"] })] }));
|
|
@@ -566,7 +674,7 @@ function SplitView({ language, rowLimit, rows, markersForRow, activeIndex, onAct
|
|
|
566
674
|
const showOldMarkers = useMemo(() => displayedPairs.some((pair) => pair.left && markersForRow(pair.left, "old").length > 0), [displayedPairs, markersForRow]);
|
|
567
675
|
const showNewMarkers = useMemo(() => displayedPairs.some((pair) => pair.right && markersForRow(pair.right, "new").length > 0), [displayedPairs, markersForRow]);
|
|
568
676
|
const cellProps = { language, markersForRow, activeIndex, onActiveChange };
|
|
569
|
-
return (_jsxs("div", { className: "flex w-full bg-background font-mono
|
|
677
|
+
return (_jsxs("div", { className: "flex w-full bg-background font-mono [font-size:var(--plan-code-size)] leading-5", children: [_jsx("div", { className: "min-w-0 flex-1 overflow-x-auto border-r border-border", children: _jsx("div", { className: "inline-block min-w-full", children: displayedPairs.map((pair, idx) => (_jsx(SplitCell, { row: pair.left, side: "old", showMarkerColumn: showOldMarkers, ...cellProps }, `old-${idx}`))) }) }), _jsx("div", { className: "min-w-0 flex-1 overflow-x-auto", children: _jsx("div", { className: "inline-block min-w-full", children: displayedPairs.map((pair, idx) => (_jsx(SplitCell, { row: pair.right, side: "new", showMarkerColumn: showNewMarkers, ...cellProps }, `new-${idx}`))) }) })] }));
|
|
570
678
|
}
|
|
571
679
|
function SplitCell({ language, row, side, markersForRow, activeIndex, onActiveChange, showMarkerColumn, }) {
|
|
572
680
|
if (!row) {
|
|
@@ -576,10 +684,11 @@ function SplitCell({ language, row, side, markersForRow, activeIndex, onActiveCh
|
|
|
576
684
|
const showSign = row.kind !== "context";
|
|
577
685
|
const markers = markersForRow(row, side);
|
|
578
686
|
const info = rowMarkerInfo(markers, activeIndex);
|
|
579
|
-
|
|
687
|
+
const startMarker = markers.find((marker) => isMarkerRangeStart(row, marker));
|
|
688
|
+
return (_jsxs("div", { "data-annot-row": startMarker ? startMarker.index : undefined, className: cn("flex min-h-5 min-w-full", ROW_BG[row.kind], annotatedRowBg(info)), onMouseEnter: info ? () => onActiveChange(info.primaryIndex) : undefined, onMouseLeave: info ? () => onActiveChange(null) : undefined, children: [_jsx("span", { className: cn(LINE_NO_CLASS, "w-[52px]"), children: side === "old" ? (row.oldNo ?? "") : (row.newNo ?? "") }), _jsx("span", { className: cn("w-6 shrink-0 select-none py-0 text-center font-semibold leading-5", GUTTER_BG[row.kind], SIGN_COLOR[row.kind]), children: showSign ? sign : " " }), showMarkerColumn && (_jsx(MarkerCell, { startMarker: startMarker, active: startMarker != null && startMarker.index === activeIndex })), _jsx(DiffLineText, { text: row.text, language: language })] }));
|
|
580
689
|
}
|
|
581
690
|
/* ── Edit (panel) ──────────────────────────────────────────────────────────── */
|
|
582
|
-
const codeAreaClass = "min-h-[140px] font-mono
|
|
691
|
+
const codeAreaClass = "min-h-[140px] font-mono [font-size:var(--plan-code-size)] leading-5";
|
|
583
692
|
function DiffEdit({ data, onChange, editable }) {
|
|
584
693
|
const patch = (next) => onChange({ ...data, ...next });
|
|
585
694
|
const mode = data.mode ?? "unified";
|