@heyramzi/ui 2.7.0 → 2.9.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/COMPONENTS.md +1 -1
- package/README.md +1 -1
- package/package.json +58 -74
- package/src/agents/vendor/draw.ts +4 -4
- package/src/ai/generation-progress/GenerationProgress.svelte +2 -2
- package/src/animations/README.md +1 -1
- package/src/animations/card-tilt.css +1 -1
- package/src/animations/digit-pop-in.css +1 -1
- package/src/animations/input-clear-dissolve.css +2 -2
- package/src/animations/learn-more-hover.css +2 -2
- package/src/animations/like-button.css +1 -1
- package/src/animations/plus-menu-morph.css +1 -1
- package/src/animations/success-check.css +5 -5
- package/src/canvas/headless/canvas-cleanup.test.ts +1 -1
- package/src/canvas/ops/ops.ts +1 -1
- package/src/charts/area-chart.svelte +11 -1
- package/src/charts/bar-chart.css +2 -1
- package/src/charts/bar-chart.svelte +18 -3
- package/src/charts/charts.css +2 -1
- package/src/charts/line-chart.svelte +11 -1
- package/src/components/data-table/data-table.ts +4 -5
- package/src/components/data-table/pagination.svelte +5 -3
- package/src/components/docs/on-this-page.svelte +82 -5
- package/src/components/docs/scroll-spy.svelte.ts +6 -1
- package/src/components/list-page/detail-header.svelte +7 -3
- package/src/components/list-page/empty-state.svelte +4 -2
- package/src/components/list-page/filter-popover.svelte +2 -2
- package/src/components/list-page/rail-row.svelte +5 -2
- package/src/components/mark/mark.svelte +2 -1
- package/src/components/section-card/section-card.svelte +3 -1
- package/src/components/section-header/section-header.svelte +5 -5
- package/src/components/segmented/segment.svelte +1 -1
- package/src/components/table-view/table-view.svelte +6 -1
- package/src/components/tags-input/tags-input.svelte +1 -1
- package/src/components/toolbar/toolbar.svelte +1 -1
- package/src/design/index.css +7 -5
- package/src/editor/anchors.ts +28 -0
- package/src/editor/doc-blocks.ts +168 -0
- package/src/editor/doc-page.css +389 -0
- package/src/editor/editor.svelte +47 -5
- package/src/editor/extensions.ts +26 -2
- package/src/editor/markdown.ts +27 -2
- package/src/editor/slash-items.ts +18 -0
- package/src/effects/reveal/reveal.css +1 -1
- package/src/icons/trades.ts +1 -1
- package/src/inbox/README.md +6 -4
- package/src/inbox/inbox.test.ts +1 -1
- package/src/inbox/index.ts +2 -2
- package/src/inbox/logic.ts +29 -5
- package/src/inbox/thread-inbox.svelte +219 -92
- package/src/inbox/types.ts +27 -1
- package/src/lib/initials.test.ts +25 -0
- package/src/lib/initials.ts +29 -0
- package/src/lib/theme-transition.ts +6 -2
- package/src/modules.test.ts +4 -64
- package/src/panel/README.md +1 -1
- package/src/record/README.md +1 -1
- package/src/record/info-list.svelte +5 -4
- package/src/record/next-up.svelte +1 -1
- package/src/record/project-list.svelte +1 -1
- package/src/record/steps-rail.svelte +3 -3
- package/src/shadcn/badge/badge.svelte +1 -1
- package/src/shadcn/card/card-title.svelte +1 -5
- package/src/shadcn/empty/empty-description.svelte +1 -1
- package/src/shadcn/progress/progress.svelte +8 -1
- package/src/shadcn/table/table-cell.svelte +10 -2
- package/src/slides/theme.css +2 -2
- package/src/status/README.md +1 -1
- package/src/status/status-dot.svelte +3 -3
- package/src/thread/README.md +2 -0
- package/src/thread/index.ts +9 -1
- package/src/thread/logic.ts +33 -3
- package/src/thread/thread-body.svelte +37 -0
- package/src/thread/thread-events.svelte +30 -0
- package/src/thread/thread.svelte +74 -59
- package/src/thread/types.ts +21 -0
- package/src/tokens/craft.css +7 -5
- package/src/{tasks → work}/README.md +11 -8
- package/src/{tasks → work}/detail/task-thread.svelte +8 -15
- package/src/work/docs/doc-editor-page.svelte +194 -0
- package/src/work/docs/doc-menu.svelte +333 -0
- package/src/work/docs/docs-demo.svelte +227 -0
- package/src/work/docs/edited-chip.svelte +125 -0
- package/src/work/docs/edited.ts +54 -0
- package/src/work/docs/index.ts +38 -0
- package/src/work/docs/labels.ts +70 -0
- package/src/work/docs/menu.ts +127 -0
- package/src/work/docs/outline.ts +60 -0
- package/src/{tasks → work}/gantt/gantt-grid.svelte +2 -2
- package/src/{tasks → work}/gantt/gantt-group-row.svelte +1 -1
- package/src/{tasks → work}/gantt/gantt.css +1 -1
- package/src/{tasks → work}/inbox/inbox-card.svelte +113 -50
- package/src/work/inbox/inbox-logic.ts +98 -0
- package/src/work/inbox/inbox-trace.svelte +58 -0
- package/src/{tasks → work}/inbox/inbox-types.ts +2 -0
- package/src/{tasks → work}/index.ts +0 -10
- package/src/{tasks → work}/kanban-board.svelte +1 -1
- package/src/{tasks → work}/kanban-column.svelte +1 -1
- package/src/{tasks → work}/task-list.svelte +2 -2
- package/src/{tasks → work}/time/time-ring.svelte +1 -1
- package/src/{tasks → work}/time/time-tracker.svelte +3 -6
- package/src/tasks/inbox/inbox-logic.ts +0 -21
- package/src/tasks/inbox/inbox-trace.svelte +0 -51
- /package/src/{tasks → work}/ambient.d.ts +0 -0
- /package/src/{tasks → work}/board-order.ts +0 -0
- /package/src/{tasks → work}/dates.ts +0 -0
- /package/src/{tasks → work}/demo.svelte +0 -0
- /package/src/{tasks → work}/detail/detail-demo.svelte +0 -0
- /package/src/{tasks → work}/detail/detail-types.ts +0 -0
- /package/src/{tasks → work}/detail/task-chip.svelte +0 -0
- /package/src/{tasks → work}/detail/task-detail.svelte +0 -0
- /package/src/{tasks → work}/detail/task-property.svelte +0 -0
- /package/src/{tasks → work}/gantt/gantt-bar.svelte +0 -0
- /package/src/{tasks → work}/gantt/gantt-header.svelte +0 -0
- /package/src/{tasks → work}/gantt/gantt-task-row.svelte +0 -0
- /package/src/{tasks → work}/gantt/gantt.test.ts +0 -0
- /package/src/{tasks → work}/gantt/logic.test.ts +0 -0
- /package/src/{tasks → work}/gantt/logic.ts +0 -0
- /package/src/{tasks → work}/inbox/inbox-draft.svelte +0 -0
- /package/src/{tasks → work}/inbox/inbox-statuses.ts +0 -0
- /package/src/{tasks → work}/inbox/index.ts +0 -0
- /package/src/{tasks → work}/kanban-drag.ts +0 -0
- /package/src/{tasks → work}/kanban-types.ts +0 -0
- /package/src/{tasks → work}/presets/sales.ts +0 -0
- /package/src/{tasks → work}/reorder.ts +0 -0
- /package/src/{tasks → work}/task-gantt.svelte +0 -0
- /package/src/{tasks → work}/task-types.ts +0 -0
- /package/src/{tasks → work}/time/duration.ts +0 -0
- /package/src/{tasks → work}/time/time-chip.svelte +0 -0
- /package/src/{tasks → work}/time/time-dot.svelte +0 -0
- /package/src/{tasks → work}/time/time-types.ts +0 -0
- /package/src/{tasks → work}/use-kanban-dnd.svelte.ts +0 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import type { InboxDraft, InboxItem } from "./inbox-types.js";
|
|
2
|
+
|
|
3
|
+
/** The draft to open on: the agent's pick, else the first. */
|
|
4
|
+
export function startDraft(drafts: InboxDraft[], recommended?: string): InboxDraft | undefined {
|
|
5
|
+
return drafts.find((draft) => draft.templateId === recommended) ?? drafts[0];
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/** A person can act on an item only while it waits for them. */
|
|
9
|
+
export function isOpen(item: InboxItem): boolean {
|
|
10
|
+
return item.tier === "ask" && item.state === "proposed";
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function canUndo(item: InboxItem): boolean {
|
|
14
|
+
return item.tier === "auto" && item.state === "done";
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** Lowercase, one space between words, no trailing ellipsis: what two copies of a line share. */
|
|
18
|
+
function plain(text: string): string {
|
|
19
|
+
return text
|
|
20
|
+
.replace(/(…|\.{3})\s*$/, "")
|
|
21
|
+
.replace(/\s+/g, " ")
|
|
22
|
+
.trim()
|
|
23
|
+
.toLowerCase();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** The lines of a card that say something the title and the command don't. */
|
|
27
|
+
export type CardFacts = {
|
|
28
|
+
lines: string[];
|
|
29
|
+
command?: { tool: string; text: string };
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Each fact once: a line that repeats the title or the command, even clipped, is dropped, and
|
|
34
|
+
* one that starts with the title keeps only the rest.
|
|
35
|
+
*/
|
|
36
|
+
export function cardFacts(item: InboxItem): CardFacts {
|
|
37
|
+
const { command, summary, detail } = item.proposal;
|
|
38
|
+
const shown = [plain(item.title)];
|
|
39
|
+
if (command) shown.push(plain(`${command.tool}: ${command.text}`), plain(command.text));
|
|
40
|
+
const lines: string[] = [];
|
|
41
|
+
for (const raw of [summary, detail]) {
|
|
42
|
+
let line = raw?.trim() ?? "";
|
|
43
|
+
const title = item.title.trim();
|
|
44
|
+
if (line.toLowerCase().startsWith(title.toLowerCase()) && line.length > title.length) {
|
|
45
|
+
line = line.slice(title.length).replace(/^[\s:.,;-]+/, "");
|
|
46
|
+
}
|
|
47
|
+
const key = plain(line);
|
|
48
|
+
if (!key || shown.some((seen) => seen.includes(key) || key.includes(seen))) continue;
|
|
49
|
+
shown.push(key);
|
|
50
|
+
lines.push(line);
|
|
51
|
+
}
|
|
52
|
+
return { lines, command };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** The reasoning of a trace when no line of the card already says it. */
|
|
56
|
+
export function freshReasoning(item: InboxItem, facts: CardFacts): string {
|
|
57
|
+
const reasoning = item.trace.reasoning.trim();
|
|
58
|
+
const key = plain(reasoning);
|
|
59
|
+
if (!key) return "";
|
|
60
|
+
const said = [item.title, item.proposal.summary, item.proposal.detail ?? "", ...facts.lines]
|
|
61
|
+
.map(plain)
|
|
62
|
+
.filter(Boolean);
|
|
63
|
+
return said.some((line) => line.includes(key) || key.includes(line)) ? "" : reasoning;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const ISO = /^\d{4}-\d{2}-\d{2}T/;
|
|
67
|
+
const UNITS: [number, Intl.RelativeTimeFormatUnit][] = [
|
|
68
|
+
[604_800, "week"],
|
|
69
|
+
[86_400, "day"],
|
|
70
|
+
[3_600, "hour"],
|
|
71
|
+
[60, "minute"],
|
|
72
|
+
];
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* A time as a person says it: "3 hr. ago", "Oct 12". A host-formatted string stays as written,
|
|
76
|
+
* and a raw ISO string never reaches the screen.
|
|
77
|
+
*/
|
|
78
|
+
export function whenOf(at: string, now: number = Date.now(), locale = "en-GB"): string {
|
|
79
|
+
if (!ISO.test(at)) return at;
|
|
80
|
+
const time = Date.parse(at);
|
|
81
|
+
if (Number.isNaN(time)) return "";
|
|
82
|
+
const seconds = Math.round((time - now) / 1000);
|
|
83
|
+
const age = Math.abs(seconds);
|
|
84
|
+
if (age >= 4 * 604_800) {
|
|
85
|
+
return new Intl.DateTimeFormat(locale, { month: "short", day: "numeric" }).format(time);
|
|
86
|
+
}
|
|
87
|
+
const rtf = new Intl.RelativeTimeFormat(locale, { numeric: "auto", style: "short" });
|
|
88
|
+
for (const [size, unit] of UNITS) {
|
|
89
|
+
if (age >= size) return rtf.format(Math.round(seconds / size), unit);
|
|
90
|
+
}
|
|
91
|
+
return rtf.format(0, "second");
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** True when a key press belongs to a text field and so isn't a shortcut. */
|
|
95
|
+
export function isTyping(target: EventTarget | null): boolean {
|
|
96
|
+
if (!(target instanceof HTMLElement)) return false;
|
|
97
|
+
return target.isContentEditable || /^(INPUT|TEXTAREA|SELECT)$/.test(target.tagName);
|
|
98
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Reasoning, ReasoningContent, ReasoningTrigger } from "../../ai/reasoning/index.js";
|
|
3
|
+
import type { InboxTrace } from "./inbox-types.js";
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
trace: InboxTrace;
|
|
7
|
+
/** The reasoning no other line of the card says. Empty when the card already shows it. */
|
|
8
|
+
reasoning?: string;
|
|
9
|
+
/** The name the card's meta line shows, so the source label doesn't repeat it. */
|
|
10
|
+
agent?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
let { trace, reasoning = "", agent }: Props = $props();
|
|
14
|
+
|
|
15
|
+
let count = $derived(trace.evidence.length);
|
|
16
|
+
let label = $derived(
|
|
17
|
+
trace.source.label.trim() === agent?.trim() ? "" : trace.source.label.trim(),
|
|
18
|
+
);
|
|
19
|
+
</script>
|
|
20
|
+
|
|
21
|
+
<!-- WHY the shared Reasoning and not a local disclosure: it is already the
|
|
22
|
+
collapsed-by-default "how the agent got here" pattern, with the same chevron. -->
|
|
23
|
+
<Reasoning>
|
|
24
|
+
<ReasoningTrigger class="w-auto">
|
|
25
|
+
<span>Trace{count > 0 ? ` · ${count} ${count === 1 ? "quote" : "quotes"}` : ""}</span>
|
|
26
|
+
</ReasoningTrigger>
|
|
27
|
+
<ReasoningContent>
|
|
28
|
+
<div class="flex flex-col gap-3">
|
|
29
|
+
{#if label || trace.source.href}
|
|
30
|
+
<p class="text-foreground">
|
|
31
|
+
{label}
|
|
32
|
+
{#if trace.source.href}
|
|
33
|
+
<a href={trace.source.href} class="text-foreground underline underline-offset-2"
|
|
34
|
+
>Open source</a
|
|
35
|
+
>
|
|
36
|
+
{/if}
|
|
37
|
+
</p>
|
|
38
|
+
{/if}
|
|
39
|
+
{#if count > 0}
|
|
40
|
+
<ul class="flex flex-col gap-2">
|
|
41
|
+
{#each trace.evidence as evidence, i (i)}
|
|
42
|
+
<li>
|
|
43
|
+
<blockquote class="text-foreground">“{evidence.quote}”</blockquote>
|
|
44
|
+
{#if evidence.by || evidence.at}
|
|
45
|
+
<span class="text-xs tabular-nums"
|
|
46
|
+
>{[evidence.by, evidence.at].filter(Boolean).join(", ")}</span
|
|
47
|
+
>
|
|
48
|
+
{/if}
|
|
49
|
+
</li>
|
|
50
|
+
{/each}
|
|
51
|
+
</ul>
|
|
52
|
+
{/if}
|
|
53
|
+
{#if reasoning}
|
|
54
|
+
<p><span class="text-foreground font-medium">Why:</span> {reasoning}</p>
|
|
55
|
+
{/if}
|
|
56
|
+
</div>
|
|
57
|
+
</ReasoningContent>
|
|
58
|
+
</Reasoning>
|
|
@@ -28,6 +28,8 @@ export type InboxDraft = {
|
|
|
28
28
|
export type InboxProposal = {
|
|
29
29
|
summary: string;
|
|
30
30
|
detail?: string;
|
|
31
|
+
/** The exact call to run, drawn once in monospace. Summary and detail that repeat it are dropped. */
|
|
32
|
+
command?: { tool: string; text: string };
|
|
31
33
|
drafts?: InboxDraft[];
|
|
32
34
|
/** The draft to open on. Defaults to the first. */
|
|
33
35
|
recommended?: string;
|
|
@@ -13,16 +13,6 @@ export type {
|
|
|
13
13
|
KanbanMove,
|
|
14
14
|
KanbanSortKey,
|
|
15
15
|
} from "./kanban-types.js";
|
|
16
|
-
export { StatusBadge, StatusDot, StatusIcon, defineStatuses } from "../status/index.js";
|
|
17
|
-
export type {
|
|
18
|
-
StatusDef,
|
|
19
|
-
StatusDotVariant,
|
|
20
|
-
StatusId,
|
|
21
|
-
StatusMap,
|
|
22
|
-
Statuses,
|
|
23
|
-
} from "../status/index.js";
|
|
24
|
-
export { SidePanel } from "../panel/index.js";
|
|
25
|
-
export type { PanelStat, SidePanelWidth } from "../panel/index.js";
|
|
26
16
|
export { default as TaskList } from "./task-list.svelte";
|
|
27
17
|
export { default as TaskGantt } from "./task-gantt.svelte";
|
|
28
18
|
export { addDays, dayNumber, isoFromDay, todayIso } from "./dates.js";
|
|
@@ -93,7 +93,7 @@
|
|
|
93
93
|
.kanban-column-expanding {
|
|
94
94
|
flex: 0 0 280px;
|
|
95
95
|
width: 280px;
|
|
96
|
-
animation: column-expand var(--duration-slow,
|
|
96
|
+
animation: column-expand var(--duration-slow, 300ms) var(--ease-smooth-out, ease-out) both;
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
@keyframes column-expand {
|
|
@@ -254,7 +254,7 @@
|
|
|
254
254
|
<span
|
|
255
255
|
class="grid h-5 min-w-5 place-items-center rounded-sm bg-foreground/5 px-1 text-xs font-medium text-muted-foreground tabular-nums"
|
|
256
256
|
>
|
|
257
|
-
{count}
|
|
257
|
+
{count.toLocaleString()}
|
|
258
258
|
</span>
|
|
259
259
|
{/if}
|
|
260
260
|
{#if actions}
|
|
@@ -408,7 +408,7 @@
|
|
|
408
408
|
}
|
|
409
409
|
|
|
410
410
|
.tl-row {
|
|
411
|
-
animation: tl-row-in var(--duration-slow,
|
|
411
|
+
animation: tl-row-in var(--duration-slow, 300ms)
|
|
412
412
|
var(--ease-smooth-out, cubic-bezier(0.22, 1, 0.36, 1)) backwards;
|
|
413
413
|
animation-delay: calc(var(--tl-i, 0) * var(--duration-stagger, 40ms));
|
|
414
414
|
transition: background-color var(--duration-quick, 150ms) var(--ease-smooth-out, ease-out);
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
<style>
|
|
66
66
|
.time-ring-arc {
|
|
67
67
|
transition:
|
|
68
|
-
stroke-dasharray var(--duration-slow,
|
|
68
|
+
stroke-dasharray var(--duration-slow, 300ms)
|
|
69
69
|
var(--ease-smooth-out, cubic-bezier(0.22, 1, 0.36, 1)),
|
|
70
70
|
color var(--duration-fast, 250ms) var(--ease-smooth-out, cubic-bezier(0.22, 1, 0.36, 1));
|
|
71
71
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script lang="ts" generics="T">
|
|
2
2
|
import type { Snippet } from "svelte";
|
|
3
3
|
import { cn } from "../../lib/utils.js";
|
|
4
|
+
import { initial } from "../../lib/initials.js";
|
|
4
5
|
import { TONE_COLOR, TONE_TEXT } from "../../lib/tone.js";
|
|
5
6
|
import * as Popover from "../../shadcn/popover/index.js";
|
|
6
7
|
import {
|
|
@@ -206,10 +207,6 @@
|
|
|
206
207
|
deleting = null;
|
|
207
208
|
}
|
|
208
209
|
}
|
|
209
|
-
|
|
210
|
-
function initial(name: string): string {
|
|
211
|
-
return name.trim().charAt(0).toLocaleUpperCase() || "?";
|
|
212
|
-
}
|
|
213
210
|
</script>
|
|
214
211
|
|
|
215
212
|
<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
|
|
@@ -468,7 +465,7 @@
|
|
|
468
465
|
}
|
|
469
466
|
|
|
470
467
|
.time-toggle:active {
|
|
471
|
-
transform: scale(0.
|
|
468
|
+
transform: scale(0.96);
|
|
472
469
|
}
|
|
473
470
|
|
|
474
471
|
@media (any-pointer: coarse) {
|
|
@@ -538,7 +535,7 @@
|
|
|
538
535
|
}
|
|
539
536
|
|
|
540
537
|
.time-segment {
|
|
541
|
-
transition: width var(--duration-slow,
|
|
538
|
+
transition: width var(--duration-slow, 300ms)
|
|
542
539
|
var(--ease-smooth-out, cubic-bezier(0.22, 1, 0.36, 1));
|
|
543
540
|
}
|
|
544
541
|
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import type { InboxDraft, InboxItem } from "./inbox-types.js";
|
|
2
|
-
|
|
3
|
-
/** The draft to open on: the agent's pick, else the first. */
|
|
4
|
-
export function startDraft(drafts: InboxDraft[], recommended?: string): InboxDraft | undefined {
|
|
5
|
-
return drafts.find((draft) => draft.templateId === recommended) ?? drafts[0];
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
/** A person can act on an item only while it waits for them. */
|
|
9
|
-
export function isOpen(item: InboxItem): boolean {
|
|
10
|
-
return item.tier === "ask" && item.state === "proposed";
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export function canUndo(item: InboxItem): boolean {
|
|
14
|
-
return item.tier === "auto" && item.state === "done";
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/** True when a key press belongs to a text field and so isn't a shortcut. */
|
|
18
|
-
export function isTyping(target: EventTarget | null): boolean {
|
|
19
|
-
if (!(target instanceof HTMLElement)) return false;
|
|
20
|
-
return target.isContentEditable || /^(INPUT|TEXTAREA|SELECT)$/.test(target.tagName);
|
|
21
|
-
}
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import { Reasoning, ReasoningContent, ReasoningTrigger } from "../../ai/reasoning/index.js";
|
|
3
|
-
import { SOURCE_ICON, SOURCE_LABEL } from "./inbox-statuses.js";
|
|
4
|
-
import type { InboxTrace } from "./inbox-types.js";
|
|
5
|
-
|
|
6
|
-
interface Props {
|
|
7
|
-
trace: InboxTrace;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
let { trace }: Props = $props();
|
|
11
|
-
|
|
12
|
-
let count = $derived(trace.evidence.length);
|
|
13
|
-
let SourceIcon = $derived(SOURCE_ICON[trace.source.type]);
|
|
14
|
-
</script>
|
|
15
|
-
|
|
16
|
-
<!-- WHY the shared Reasoning and not a local disclosure: it is already the
|
|
17
|
-
collapsed-by-default "how the agent got here" pattern, with the same chevron. -->
|
|
18
|
-
<Reasoning>
|
|
19
|
-
<ReasoningTrigger class="w-auto">
|
|
20
|
-
<SourceIcon size={14} class="shrink-0" aria-hidden="true" />
|
|
21
|
-
<span>
|
|
22
|
-
Trace: {SOURCE_LABEL[trace.source.type]}, {trace.source.at}, {count}
|
|
23
|
-
{count === 1 ? "quote" : "quotes"}
|
|
24
|
-
</span>
|
|
25
|
-
</ReasoningTrigger>
|
|
26
|
-
<ReasoningContent>
|
|
27
|
-
<div class="flex flex-col gap-3">
|
|
28
|
-
<p class="text-foreground">
|
|
29
|
-
{trace.source.label}
|
|
30
|
-
{#if trace.source.href}
|
|
31
|
-
<a href={trace.source.href} class="text-foreground ml-1 underline underline-offset-2"
|
|
32
|
-
>Open source</a
|
|
33
|
-
>
|
|
34
|
-
{/if}
|
|
35
|
-
</p>
|
|
36
|
-
<ul class="flex flex-col gap-2">
|
|
37
|
-
{#each trace.evidence as evidence, i (i)}
|
|
38
|
-
<li>
|
|
39
|
-
<blockquote class="text-foreground">“{evidence.quote}”</blockquote>
|
|
40
|
-
{#if evidence.by || evidence.at}
|
|
41
|
-
<span class="text-xs tabular-nums"
|
|
42
|
-
>{[evidence.by, evidence.at].filter(Boolean).join(", ")}</span
|
|
43
|
-
>
|
|
44
|
-
{/if}
|
|
45
|
-
</li>
|
|
46
|
-
{/each}
|
|
47
|
-
</ul>
|
|
48
|
-
<p><span class="text-foreground font-medium">Why:</span> {trace.reasoning}</p>
|
|
49
|
-
</div>
|
|
50
|
-
</ReasoningContent>
|
|
51
|
-
</Reasoning>
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|