@usetheo/ui 0.10.0-next.0 → 0.11.0-next.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/CHANGELOG.md +119 -3
- package/README.md +22 -21
- package/dist/chunk-BX7A5GUV.js +78 -0
- package/dist/chunk-BX7A5GUV.js.map +1 -0
- package/dist/{chunk-H3ANHVEL.js → chunk-DKQAHZG2.js} +4 -4
- package/dist/{chunk-H3ANHVEL.js.map → chunk-DKQAHZG2.js.map} +1 -1
- package/dist/{chunk-DAKIL5PC.js → chunk-IPEYGWA7.js} +3 -3
- package/dist/{chunk-DAKIL5PC.js.map → chunk-IPEYGWA7.js.map} +1 -1
- package/dist/chunk-IWSLOBYG.js +199 -0
- package/dist/chunk-IWSLOBYG.js.map +1 -0
- package/dist/chunk-MI5CXMZU.js +171 -0
- package/dist/chunk-MI5CXMZU.js.map +1 -0
- package/dist/chunk-QJGGTIUN.js +110 -0
- package/dist/chunk-QJGGTIUN.js.map +1 -0
- package/dist/chunk-R2PAGRDP.js +152 -0
- package/dist/chunk-R2PAGRDP.js.map +1 -0
- package/dist/{chunk-QU6RLHYH.js → chunk-TNBJ36XJ.js} +3 -3
- package/dist/{chunk-QU6RLHYH.js.map → chunk-TNBJ36XJ.js.map} +1 -1
- package/dist/components.css +1 -1
- package/dist/composites/agent-stream/index.js +3 -3
- package/dist/composites/data-table/index.js +10 -0
- package/dist/composites/data-table/index.js.map +1 -0
- package/dist/composites/page-shell/index.js +7 -0
- package/dist/composites/page-shell/index.js.map +1 -0
- package/dist/composites/rule-editor/index.js +2 -2
- package/dist/composites/skill-editor/index.js +2 -2
- package/dist/index.d.ts +281 -12
- package/dist/index.js +47 -42
- package/dist/index.js.map +1 -1
- package/dist/primitives/action-bar/index.js +4 -0
- package/dist/primitives/action-bar/index.js.map +1 -0
- package/dist/primitives/dropdown-menu/index.js +4 -0
- package/dist/primitives/dropdown-menu/index.js.map +1 -0
- package/dist/primitives/pin-input/index.js +4 -0
- package/dist/primitives/pin-input/index.js.map +1 -0
- package/llms.txt +4 -3
- package/package.json +63 -43
- package/registry/index.json +30 -0
- package/registry/r/action-bar.json +22 -0
- package/registry/r/data-table.json +27 -0
- package/registry/r/dropdown-menu.json +23 -0
- package/registry/r/page-shell.json +25 -0
- package/registry/r/pin-input.json +20 -0
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,106 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.11.0-next.0] - 2026-05-25
|
|
11
|
+
|
|
12
|
+
Minor (additive, zero breaking change) — ships Brief #5 from the
|
|
13
|
+
TheoCloud dashboard team, closing 3 measured Deep Review findings.
|
|
14
|
+
Five new components: 3 brief-asks (PinInput, DataTable, PageShell)
|
|
15
|
+
+ 2 explicit pre-requisites (DropdownMenu, ActionBar) that the
|
|
16
|
+
brief assumed existed but didn't.
|
|
17
|
+
|
|
18
|
+
Plan: `.claude/knowledge-base/plans/dashboard-primitives-brief-5-plan.md`
|
|
19
|
+
ADR: `.claude/knowledge-base/decisions/page-shell-composite-pattern.md`
|
|
20
|
+
Brief: `theo/docs/handoff/2026-05-25-theo-ui-cloud-dashboard-brief-5.md`
|
|
21
|
+
|
|
22
|
+
### Added
|
|
23
|
+
|
|
24
|
+
- **`<DropdownMenu>` primitive (NEW, Brief #5 pre-req)** — accessible
|
|
25
|
+
menu built on `@radix-ui/react-dropdown-menu` (already a bundled
|
|
26
|
+
dep, no new peer needed). Sub-components attached via
|
|
27
|
+
`Object.assign`: `Trigger`, `Portal`, `Content`, `Item`,
|
|
28
|
+
`CheckboxItem`, `RadioItem`, `Label`, `Separator`, `Shortcut`,
|
|
29
|
+
`Group`, `Sub`, `SubTrigger`, `SubContent`, `RadioGroup`. Styled
|
|
30
|
+
with `@usetheo/ui` design tokens. Consolidates 5 prior direct-
|
|
31
|
+
Radix usages (`model-selector`, `intent-selector`, `agent-profile`,
|
|
32
|
+
`theme-switcher`, `theo-code-shell`) under a single styled
|
|
33
|
+
wrapper. 6 unit tests + 5 Ladle stories. SSR-safe.
|
|
34
|
+
- **`<ActionBar>` primitive (NEW, Brief #5 pre-req)** — page-top
|
|
35
|
+
action strip with three optional slots: search input (flex-1,
|
|
36
|
+
grows to fill), filter icon button, primary action button
|
|
37
|
+
(right-aligned). Returns `null` when no slots are provided.
|
|
38
|
+
Primary action supports `loading` state with `Loader2` spinner.
|
|
39
|
+
Usable standalone or composed inside `<PageShell>`. 6 unit tests
|
|
40
|
+
+ 5 Ladle stories.
|
|
41
|
+
- **`<PinInput>` primitive (NEW)** — multi-slot OTP / code input
|
|
42
|
+
with auto-advance focus, paste handling (whitespace stripped),
|
|
43
|
+
arrow-key navigation, backspace clearing + focus back. Default
|
|
44
|
+
6 slots, configurable. `inputMode="numeric"` (default, triggers
|
|
45
|
+
mobile numeric keyboard via `pattern="[0-9]*"`) or
|
|
46
|
+
`alphanumeric` (auto-uppercase). Optional `mask` renders bullets.
|
|
47
|
+
Optional `error` state applies destructive border. `onComplete`
|
|
48
|
+
fires once on transitions to complete (NOT on mount with pre-
|
|
49
|
+
filled value — verified via test). Closes Deep Review § 2.12 P2
|
|
50
|
+
(Verification page off-brand single-input pattern). 17 unit
|
|
51
|
+
tests + 7 Ladle stories.
|
|
52
|
+
- **`<DataTable>` composite (NEW)** — generic, sortable,
|
|
53
|
+
expandable composite over `<Table>` + `<Pagination>` +
|
|
54
|
+
`<Skeleton>` + `<EmptyState>` + `<DropdownMenu>`. Generic over
|
|
55
|
+
`T` (e.g. `DataTable<Domain>`). Sortable headers (controlled via
|
|
56
|
+
`onSortChange` OR uncontrolled client-side). Sticky header
|
|
57
|
+
(default true). Expandable rows with `expandable(row)` callback
|
|
58
|
+
— multi-row default, opt-in `expandMode="single"`. Row actions
|
|
59
|
+
via `rowActions(row)` opens DropdownMenu. Client-side pagination
|
|
60
|
+
with `pageSize`; sort changes reset to page 0. Loading state
|
|
61
|
+
renders 5 skeleton rows. Empty state delegates to `<EmptyState>`
|
|
62
|
+
or custom `emptyState` prop. Expanded row `colSpan` correctly
|
|
63
|
+
accounts for chevron + actions columns (EC-1 fix). pageSize<=0
|
|
64
|
+
clamps to 1 graceful degradation. Closes Deep Review Top-5
|
|
65
|
+
fix #2, § 2.2 P1, § 2.4 P1 (card-grid → sortable table for
|
|
66
|
+
Domains + Projects). 19 unit tests + 8 Ladle stories.
|
|
67
|
+
- **`<PageShell>` composite (NEW)** — page-level scaffold. Title
|
|
68
|
+
+ optional description + optional ActionBar (when search /
|
|
69
|
+
primaryAction / onFilterClick provided), then one of four
|
|
70
|
+
mutually-exclusive content states with strict precedence:
|
|
71
|
+
loading > error > empty > children. Default loading is a
|
|
72
|
+
centered spinner Card; `loadingNode?` escape hatch for custom
|
|
73
|
+
skeletons. Error renders Card with message + optional retry
|
|
74
|
+
button + optional docs link. Empty delegates to `<EmptyState>`.
|
|
75
|
+
`aria-busy="true"` on the `<main>` element while loading. Does
|
|
76
|
+
NOT manage `document.title` (D3 scope-narrowing); consumers
|
|
77
|
+
wire `onTitleChange?` callback to their own hook. Dedupes
|
|
78
|
+
~20 LOC × 13 dashboard pages of boilerplate. 15 unit tests + 6
|
|
79
|
+
Ladle stories.
|
|
80
|
+
|
|
81
|
+
### Notes
|
|
82
|
+
|
|
83
|
+
- Edge-case review surfaced 1 MUST FIX (DataTable expanded row
|
|
84
|
+
colSpan miscalculation when rowActions present) + 14 SHOULD TEST
|
|
85
|
+
+ 7 DOCUMENT — all incorporated into TDD blocks before
|
|
86
|
+
implementation.
|
|
87
|
+
- D3 scope-narrowing: PageShell does NOT include `useSetPageTitle`
|
|
88
|
+
/ `PageMetaProvider` — those are consumer-scope hooks. The
|
|
89
|
+
library exposes only the visible heading + an `onTitleChange?`
|
|
90
|
+
callback for the consumer to wire their own title management.
|
|
91
|
+
- DropdownMenu consolidation is opt-in: the 5 existing direct-
|
|
92
|
+
Radix usages stay untouched in this release; migration is a
|
|
93
|
+
follow-up PR.
|
|
94
|
+
- Zero new peer-deps. `@radix-ui/react-dropdown-menu` was already
|
|
95
|
+
bundled.
|
|
96
|
+
|
|
97
|
+
### Bundle delta (consumer canary)
|
|
98
|
+
|
|
99
|
+
Measured against TheoCloud dashboard (no consumer migration to the
|
|
100
|
+
new primitives yet — pure version bump):
|
|
101
|
+
|
|
102
|
+
| Metric | 0.10.0-next.0 | 0.11.0-next.0 | Δ |
|
|
103
|
+
|---|---|---|---|
|
|
104
|
+
| `@usetheo/ui` chunk | TBD | TBD | TBD |
|
|
105
|
+
| TOTAL initial JS | TBD | TBD | TBD |
|
|
106
|
+
|
|
107
|
+
(Evidence file:
|
|
108
|
+
`.claude/knowledge-base/baselines/2026-05-26-post-brief-5/theocloud-bundle-delta.txt`)
|
|
109
|
+
|
|
10
110
|
## [0.10.0-next.0] - 2026-05-25
|
|
11
111
|
|
|
12
112
|
Minor (additive, zero breaking change) — fixes a publishing-pipeline
|
|
@@ -87,10 +187,26 @@ Brief: `theo/docs/handoff/2026-05-24-theo-ui-subpath-tree-shaking-brief-4.md`
|
|
|
87
187
|
| **Shared chunks (`dist/chunk-*.js`)** | 0 | 119 | + |
|
|
88
188
|
|
|
89
189
|
The barrel shrank because all component code now lives in shared
|
|
90
|
-
chunks. Consumer-side bundle delta against TheoCloud dashboard
|
|
91
|
-
|
|
190
|
+
chunks. **Consumer-side bundle delta against TheoCloud dashboard
|
|
191
|
+
(measured 2026-05-25):**
|
|
192
|
+
|
|
193
|
+
| Metric | 0.9.0-next.0 | 0.10.0-next.0 | Δ |
|
|
194
|
+
|---|---|---|---|
|
|
195
|
+
| `@usetheo/ui` chunk | 36.96 KB brotli | 10.96 KB brotli | **−26.00 KB (−70.3%)** |
|
|
196
|
+
| TOTAL initial JS | 176.27 KB brotli | 134.68 KB brotli | −41.59 KB (−23.6%) |
|
|
197
|
+
|
|
198
|
+
Per-chunk cap (50 KB): passes with 39 KB headroom (was 13 KB).
|
|
199
|
+
Total hard gate (240 KB): passes with 105 KB headroom (was 64 KB).
|
|
200
|
+
|
|
201
|
+
**Notable:** the savings were realized WITHOUT migrating consumer
|
|
202
|
+
imports to subpath form. The barrel benefits from tree-shaking now
|
|
203
|
+
because `dist/index.js` is structured as a collection of
|
|
204
|
+
per-component re-exports from shared chunks — Vite/Rollup's
|
|
205
|
+
tree-shaker can drop individual chunks per consumer usage. Subpath-
|
|
206
|
+
form migration is expected to yield additional savings on top.
|
|
207
|
+
|
|
208
|
+
Evidence file:
|
|
92
209
|
`.claude/knowledge-base/baselines/2026-05-25-post-subpath/theocloud-bundle-delta.txt`
|
|
93
|
-
once measured.
|
|
94
210
|
|
|
95
211
|
### Migration (consumer-side, opt-in)
|
|
96
212
|
|
package/README.md
CHANGED
|
@@ -13,8 +13,8 @@ A React component library built for AI agent surfaces and cloud dashboards. **10
|
|
|
13
13
|
<!-- BEGIN:counts -->
|
|
14
14
|
[](./LICENSE)
|
|
15
15
|
[](https://react.dev)
|
|
16
|
-
[](#quality-gates)
|
|
17
|
+
[](#component-catalog)
|
|
18
18
|
[](https://ui.shadcn.com/docs/registry)
|
|
19
19
|
<!-- END:counts -->
|
|
20
20
|
|
|
@@ -133,32 +133,33 @@ import { ThemeProvider, ThemeScript } from "@usetheo/ui";
|
|
|
133
133
|
## Component catalog
|
|
134
134
|
|
|
135
135
|
<!-- BEGIN:component-catalog-intro -->
|
|
136
|
-
**
|
|
136
|
+
**139 components**, organized by mechanical rule: a *primitive* imports no other `@usetheo/ui` component; a *composite* does.
|
|
137
137
|
<!-- END:component-catalog-intro -->
|
|
138
138
|
|
|
139
139
|
<details>
|
|
140
140
|
<summary>
|
|
141
141
|
<!-- BEGIN:primitives-count -->
|
|
142
|
-
**Primitives** (
|
|
142
|
+
**Primitives** (92) — building blocks
|
|
143
143
|
<!-- END:primitives-count -->
|
|
144
144
|
</summary>
|
|
145
145
|
|
|
146
146
|
<!-- BEGIN:primitives -->
|
|
147
|
-
`AgentErrorCard` · `AgentEvent` · `AgentHandoff` · `AgentProfile` · `AgentStartingState`
|
|
148
|
-
`Alert` · `ArtifactPreview` · `AttachmentChip` · `AuditLogEntry` · `AutoCompactNotice`
|
|
149
|
-
`Badge` · `BrowserControls` · `BuildLogStream` · `Button` · `CapabilityIndicator`
|
|
150
|
-
`ChatThread` · `Checkbox` · `ContextCard` · `ContextWindowBar` · `CopyButton`
|
|
151
|
-
`CreatedFilesCard` · `CronJobCard` · `DangerZone` · `Dialog` · `DiffViewer`
|
|
152
|
-
`
|
|
153
|
-
`
|
|
154
|
-
`
|
|
155
|
-
`
|
|
156
|
-
`
|
|
157
|
-
`
|
|
158
|
-
`
|
|
159
|
-
`
|
|
160
|
-
`
|
|
161
|
-
`
|
|
147
|
+
`ActionBar` · `AgentErrorCard` · `AgentEvent` · `AgentHandoff` · `AgentProfile` · `AgentStartingState`
|
|
148
|
+
`AgentStreaming` · `Alert` · `ArtifactPreview` · `AttachmentChip` · `AuditLogEntry` · `AutoCompactNotice`
|
|
149
|
+
`Avatar` · `Badge` · `BrowserControls` · `BuildLogStream` · `Button` · `CapabilityIndicator`
|
|
150
|
+
`Card` · `ChatThread` · `Checkbox` · `ContextCard` · `ContextWindowBar` · `CopyButton`
|
|
151
|
+
`CostMeter` · `CreatedFilesCard` · `CronJobCard` · `DangerZone` · `Dialog` · `DiffViewer`
|
|
152
|
+
`DropdownMenu` · `EmptyState` · `FolderContextCard` · `FolderSelector` · `FormField` · `HookConfig`
|
|
153
|
+
`HookEventLog` · `Input` · `IntentSelector` · `Label` · `LaneBoard` · `LoginSplit`
|
|
154
|
+
`MCPServerCard` · `MemoryEditor` · `MentionMenu` · `MetricsPanel` · `ModelCard` · `ModelSelector`
|
|
155
|
+
`Pagination` · `PermissionMatrix` · `PinInput` · `PlanBadge` · `Progress` · `ProgressChecklist`
|
|
156
|
+
`ProjectSwitcher` · `QuickActionChips` · `RadioGroup` · `RecentFoldersList` · `RuleCard` · `RunStats`
|
|
157
|
+
`RunningTasksPanel` · `ScrollArea` · `Select` · `SessionListItem` · `SessionTimeline` · `Sheet`
|
|
158
|
+
`Sidebar` · `Skeleton` · `SkillCard` · `SocialAuthRow` · `StatTile` · `StatusDot`
|
|
159
|
+
`StepsRail` · `SubAgentDispatch` · `Switch` · `SystemPromptEditor` · `Table` · `Tabs`
|
|
160
|
+
`TaskNode` · `TaskPlan` · `TerminalPanel` · `Textarea` · `Timestamp` · `Toast`
|
|
161
|
+
`Toaster` · `TokenUsageChart` · `ToolCall` · `ToolCallCard` · `ToolResult` · `ToolsList`
|
|
162
|
+
`Tooltip` · `TopNav`
|
|
162
163
|
<!-- END:primitives -->
|
|
163
164
|
|
|
164
165
|
</details>
|
|
@@ -166,12 +167,12 @@ import { ThemeProvider, ThemeScript } from "@usetheo/ui";
|
|
|
166
167
|
<details>
|
|
167
168
|
<summary>
|
|
168
169
|
<!-- BEGIN:composites-count -->
|
|
169
|
-
**Composites** (
|
|
170
|
+
**Composites** (47) — assembled flows
|
|
170
171
|
<!-- END:composites-count -->
|
|
171
172
|
</summary>
|
|
172
173
|
|
|
173
174
|
<!-- BEGIN:composites -->
|
|
174
|
-
`AccountMenu` · `AgentComposer` · `AgentEditor` · `AgentStream` · `AgentTimeline` · `ApprovalCard` · `ChatComposer` · `ChatMessage` · `ChatMessageAction` · `ChatMessageActions` · `ChatMessageBranch` · `ChatMessageBranchContent` · `ChatMessageBranchNext` · `ChatMessageBranchPage` · `ChatMessageBranchPrevious` · `ChatMessageBranchSelector` · `ChatMessageContent` · `ChatMessageResponse` · `ChatMessageRoot` · `ChatMessageToolbar` · `CodeBlock` · `CommandPalette` · `ConfirmDialog` · `CronJobsList` · `DataPart` · `DeploymentRow` · `DomainConfig` · `EnvVarEditor` · `FilePart` · `MCPServerList` · `PermissionModal` · `PreviewEnvCard` · `PreviewPanel` · `ProjectCard` · `ReasoningPart` · `RollbackUI` · `RuleEditor` · `SkillEditor` · `SkillsList` · `SourceDocumentPart` · `SourceUrlPart` · `TaskHeader` · `TextPart` · `ToolCallPart` · `UsageMeter`
|
|
175
|
+
`AccountMenu` · `AgentComposer` · `AgentEditor` · `AgentStream` · `AgentTimeline` · `ApprovalCard` · `ChatComposer` · `ChatMessage` · `ChatMessageAction` · `ChatMessageActions` · `ChatMessageBranch` · `ChatMessageBranchContent` · `ChatMessageBranchNext` · `ChatMessageBranchPage` · `ChatMessageBranchPrevious` · `ChatMessageBranchSelector` · `ChatMessageContent` · `ChatMessageResponse` · `ChatMessageRoot` · `ChatMessageToolbar` · `CodeBlock` · `CommandPalette` · `ConfirmDialog` · `CronJobsList` · `DataPart` · `DataTable` · `DeploymentRow` · `DomainConfig` · `EnvVarEditor` · `FilePart` · `MCPServerList` · `PageShell` · `PermissionModal` · `PreviewEnvCard` · `PreviewPanel` · `ProjectCard` · `ReasoningPart` · `RollbackUI` · `RuleEditor` · `SkillEditor` · `SkillsList` · `SourceDocumentPart` · `SourceUrlPart` · `TaskHeader` · `TextPart` · `ToolCallPart` · `UsageMeter`
|
|
175
176
|
<!-- END:composites -->
|
|
176
177
|
|
|
177
178
|
</details>
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { cn } from './chunk-ZSRJCIWF.js';
|
|
2
|
+
import { Search, Filter, Loader2 } from 'lucide-react';
|
|
3
|
+
import { forwardRef } from 'react';
|
|
4
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
5
|
+
|
|
6
|
+
var ActionBar = forwardRef(
|
|
7
|
+
({ className, search, primaryAction, onFilterClick, ...props }, ref) => {
|
|
8
|
+
if (!search && !primaryAction && !onFilterClick) {
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
const PrimaryIcon = primaryAction?.icon;
|
|
12
|
+
const isLoading = primaryAction?.loading === true;
|
|
13
|
+
return /* @__PURE__ */ jsxs("div", { ref, className: cn("flex w-full items-center gap-2", className), ...props, children: [
|
|
14
|
+
search ? /* @__PURE__ */ jsxs("div", { className: "relative flex-1", children: [
|
|
15
|
+
/* @__PURE__ */ jsx(
|
|
16
|
+
Search,
|
|
17
|
+
{
|
|
18
|
+
"aria-hidden": "true",
|
|
19
|
+
className: "-translate-y-1/2 absolute top-1/2 left-3 size-4 text-muted-foreground"
|
|
20
|
+
}
|
|
21
|
+
),
|
|
22
|
+
/* @__PURE__ */ jsx(
|
|
23
|
+
"input",
|
|
24
|
+
{
|
|
25
|
+
type: "search",
|
|
26
|
+
placeholder: search.placeholder,
|
|
27
|
+
value: search.value,
|
|
28
|
+
onChange: (e) => search.onChange(e.target.value),
|
|
29
|
+
className: cn(
|
|
30
|
+
"w-full rounded-md border border-border/40 bg-card py-2 pr-3 pl-9",
|
|
31
|
+
"font-sans text-body-sm text-foreground placeholder:text-muted-foreground",
|
|
32
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
33
|
+
)
|
|
34
|
+
}
|
|
35
|
+
)
|
|
36
|
+
] }) : null,
|
|
37
|
+
onFilterClick !== void 0 ? /* @__PURE__ */ jsx(
|
|
38
|
+
"button",
|
|
39
|
+
{
|
|
40
|
+
type: "button",
|
|
41
|
+
onClick: onFilterClick,
|
|
42
|
+
"aria-label": "Filter",
|
|
43
|
+
className: cn(
|
|
44
|
+
"inline-flex size-9 items-center justify-center rounded-md border border-border/40",
|
|
45
|
+
"text-muted-foreground transition-colors",
|
|
46
|
+
"hover:bg-muted hover:text-foreground",
|
|
47
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
48
|
+
),
|
|
49
|
+
children: /* @__PURE__ */ jsx(Filter, { "aria-hidden": "true", className: "size-4" })
|
|
50
|
+
}
|
|
51
|
+
) : null,
|
|
52
|
+
primaryAction !== void 0 ? /* @__PURE__ */ jsxs(
|
|
53
|
+
"button",
|
|
54
|
+
{
|
|
55
|
+
type: "button",
|
|
56
|
+
onClick: primaryAction.onClick,
|
|
57
|
+
disabled: isLoading,
|
|
58
|
+
className: cn(
|
|
59
|
+
"ml-auto inline-flex items-center gap-2 rounded-md bg-primary px-3 py-2",
|
|
60
|
+
"font-medium font-sans text-body-sm text-primary-foreground",
|
|
61
|
+
"transition-colors hover:bg-primary-deep",
|
|
62
|
+
"disabled:cursor-not-allowed disabled:opacity-60",
|
|
63
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
|
|
64
|
+
),
|
|
65
|
+
children: [
|
|
66
|
+
isLoading ? /* @__PURE__ */ jsx(Loader2, { "aria-hidden": "true", className: "size-4 animate-spin" }) : PrimaryIcon ? /* @__PURE__ */ jsx(PrimaryIcon, { "aria-hidden": "true", className: "size-4" }) : null,
|
|
67
|
+
primaryAction.label
|
|
68
|
+
]
|
|
69
|
+
}
|
|
70
|
+
) : null
|
|
71
|
+
] });
|
|
72
|
+
}
|
|
73
|
+
);
|
|
74
|
+
ActionBar.displayName = "ActionBar";
|
|
75
|
+
|
|
76
|
+
export { ActionBar };
|
|
77
|
+
//# sourceMappingURL=chunk-BX7A5GUV.js.map
|
|
78
|
+
//# sourceMappingURL=chunk-BX7A5GUV.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/primitives/action-bar/action-bar.tsx"],"names":[],"mappings":";;;;;AAsCA,IAAM,SAAA,GAAY,UAAA;AAAA,EAChB,CAAC,EAAE,SAAA,EAAW,MAAA,EAAQ,eAAe,aAAA,EAAe,GAAG,KAAA,EAAM,EAAG,GAAA,KAAQ;AACtE,IAAA,IAAI,CAAC,MAAA,IAAU,CAAC,aAAA,IAAiB,CAAC,aAAA,EAAe;AAC/C,MAAA,OAAO,IAAA;AAAA,IACT;AAEA,IAAA,MAAM,cAAc,aAAA,EAAe,IAAA;AACnC,IAAA,MAAM,SAAA,GAAY,eAAe,OAAA,KAAY,IAAA;AAE7C,IAAA,uBACE,IAAA,CAAC,SAAI,GAAA,EAAU,SAAA,EAAW,GAAG,gCAAA,EAAkC,SAAS,CAAA,EAAI,GAAG,KAAA,EAC5E,QAAA,EAAA;AAAA,MAAA,MAAA,mBACC,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,iBAAA,EACb,QAAA,EAAA;AAAA,wBAAA,GAAA;AAAA,UAAC,MAAA;AAAA,UAAA;AAAA,YACC,aAAA,EAAY,MAAA;AAAA,YACZ,SAAA,EAAU;AAAA;AAAA,SACZ;AAAA,wBACA,GAAA;AAAA,UAAC,OAAA;AAAA,UAAA;AAAA,YACC,IAAA,EAAK,QAAA;AAAA,YACL,aAAa,MAAA,CAAO,WAAA;AAAA,YACpB,OAAO,MAAA,CAAO,KAAA;AAAA,YACd,UAAU,CAAC,CAAA,KAAM,OAAO,QAAA,CAAS,CAAA,CAAE,OAAO,KAAK,CAAA;AAAA,YAC/C,SAAA,EAAW,EAAA;AAAA,cACT,kEAAA;AAAA,cACA,0EAAA;AAAA,cACA;AAAA;AACF;AAAA;AACF,OAAA,EACF,CAAA,GACE,IAAA;AAAA,MACH,kBAAkB,MAAA,mBACjB,GAAA;AAAA,QAAC,QAAA;AAAA,QAAA;AAAA,UACC,IAAA,EAAK,QAAA;AAAA,UACL,OAAA,EAAS,aAAA;AAAA,UACT,YAAA,EAAW,QAAA;AAAA,UACX,SAAA,EAAW,EAAA;AAAA,YACT,mFAAA;AAAA,YACA,yCAAA;AAAA,YACA,sCAAA;AAAA,YACA;AAAA,WACF;AAAA,UAEA,QAAA,kBAAA,GAAA,CAAC,MAAA,EAAA,EAAO,aAAA,EAAY,MAAA,EAAO,WAAU,QAAA,EAAS;AAAA;AAAA,OAChD,GACE,IAAA;AAAA,MACH,kBAAkB,MAAA,mBACjB,IAAA;AAAA,QAAC,QAAA;AAAA,QAAA;AAAA,UACC,IAAA,EAAK,QAAA;AAAA,UACL,SAAS,aAAA,CAAc,OAAA;AAAA,UACvB,QAAA,EAAU,SAAA;AAAA,UACV,SAAA,EAAW,EAAA;AAAA,YACT,wEAAA;AAAA,YACA,4DAAA;AAAA,YACA,yCAAA;AAAA,YACA,iDAAA;AAAA,YACA;AAAA,WACF;AAAA,UAEC,QAAA,EAAA;AAAA,YAAA,SAAA,mBACC,GAAA,CAAC,OAAA,EAAA,EAAQ,aAAA,EAAY,MAAA,EAAO,WAAU,qBAAA,EAAsB,CAAA,GAC1D,WAAA,mBACF,GAAA,CAAC,WAAA,EAAA,EAAY,aAAA,EAAY,MAAA,EAAO,SAAA,EAAU,UAAS,CAAA,GACjD,IAAA;AAAA,YACH,aAAA,CAAc;AAAA;AAAA;AAAA,OACjB,GACE;AAAA,KAAA,EACN,CAAA;AAAA,EAEJ;AACF;AACA,SAAA,CAAU,WAAA,GAAc,WAAA","file":"chunk-BX7A5GUV.js","sourcesContent":["import { Filter, Loader2, Search } from \"lucide-react\";\nimport { forwardRef } from \"react\";\nimport type { ElementType, HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"../../../lib/cn.js\";\n\n/**\n * ActionBar — page-top action strip primitive.\n *\n * A horizontal flexbox row with three optional slots:\n * - Search input (flex-1, grows to fill)\n * - Filter icon button (next to search)\n * - Primary action button (right-aligned)\n *\n * Returns `null` when no props are provided — don't render an empty\n * bar. Used standalone or composed inside `<PageShell>` (Brief #5).\n *\n * @example\n * <ActionBar\n * search={{ placeholder: \"Search projects…\", value: q, onChange: setQ }}\n * primaryAction={{ label: \"New project\", icon: Plus, onClick: openModal }}\n * />\n */\n\nexport interface ActionBarProps extends Omit<HTMLAttributes<HTMLDivElement>, \"children\"> {\n search?: {\n placeholder: string;\n value: string;\n onChange: (value: string) => void;\n };\n primaryAction?: {\n label: ReactNode;\n icon?: ElementType;\n onClick: () => void;\n loading?: boolean;\n };\n onFilterClick?: () => void;\n}\n\nconst ActionBar = forwardRef<HTMLDivElement, ActionBarProps>(\n ({ className, search, primaryAction, onFilterClick, ...props }, ref) => {\n if (!search && !primaryAction && !onFilterClick) {\n return null;\n }\n\n const PrimaryIcon = primaryAction?.icon;\n const isLoading = primaryAction?.loading === true;\n\n return (\n <div ref={ref} className={cn(\"flex w-full items-center gap-2\", className)} {...props}>\n {search ? (\n <div className=\"relative flex-1\">\n <Search\n aria-hidden=\"true\"\n className=\"-translate-y-1/2 absolute top-1/2 left-3 size-4 text-muted-foreground\"\n />\n <input\n type=\"search\"\n placeholder={search.placeholder}\n value={search.value}\n onChange={(e) => search.onChange(e.target.value)}\n className={cn(\n \"w-full rounded-md border border-border/40 bg-card py-2 pr-3 pl-9\",\n \"font-sans text-body-sm text-foreground placeholder:text-muted-foreground\",\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\",\n )}\n />\n </div>\n ) : null}\n {onFilterClick !== undefined ? (\n <button\n type=\"button\"\n onClick={onFilterClick}\n aria-label=\"Filter\"\n className={cn(\n \"inline-flex size-9 items-center justify-center rounded-md border border-border/40\",\n \"text-muted-foreground transition-colors\",\n \"hover:bg-muted hover:text-foreground\",\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\",\n )}\n >\n <Filter aria-hidden=\"true\" className=\"size-4\" />\n </button>\n ) : null}\n {primaryAction !== undefined ? (\n <button\n type=\"button\"\n onClick={primaryAction.onClick}\n disabled={isLoading}\n className={cn(\n \"ml-auto inline-flex items-center gap-2 rounded-md bg-primary px-3 py-2\",\n \"font-medium font-sans text-body-sm text-primary-foreground\",\n \"transition-colors hover:bg-primary-deep\",\n \"disabled:cursor-not-allowed disabled:opacity-60\",\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\",\n )}\n >\n {isLoading ? (\n <Loader2 aria-hidden=\"true\" className=\"size-4 animate-spin\" />\n ) : PrimaryIcon ? (\n <PrimaryIcon aria-hidden=\"true\" className=\"size-4\" />\n ) : null}\n {primaryAction.label}\n </button>\n ) : null}\n </div>\n );\n },\n);\nActionBar.displayName = \"ActionBar\";\n\nexport { ActionBar };\n"]}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { ChatMessage } from './chunk-VI5M7KJ2.js';
|
|
2
1
|
import { ApprovalCard } from './chunk-SF6R5VMQ.js';
|
|
2
|
+
import { ChatMessage } from './chunk-VI5M7KJ2.js';
|
|
3
3
|
import { ToolCallCard } from './chunk-CWFMFKDI.js';
|
|
4
|
-
import { AgentErrorCard } from './chunk-HGPBGLNP.js';
|
|
5
4
|
import { AgentStreaming } from './chunk-ETEIDY34.js';
|
|
5
|
+
import { AgentErrorCard } from './chunk-HGPBGLNP.js';
|
|
6
6
|
import { LiveRegionProvider } from './chunk-UGKI466V.js';
|
|
7
7
|
import { cn } from './chunk-ZSRJCIWF.js';
|
|
8
8
|
import { forwardRef } from 'react';
|
|
@@ -79,5 +79,5 @@ var AgentStream = forwardRef(
|
|
|
79
79
|
AgentStream.displayName = "AgentStream";
|
|
80
80
|
|
|
81
81
|
export { AgentStream };
|
|
82
|
-
//# sourceMappingURL=chunk-
|
|
83
|
-
//# sourceMappingURL=chunk-
|
|
82
|
+
//# sourceMappingURL=chunk-DKQAHZG2.js.map
|
|
83
|
+
//# sourceMappingURL=chunk-DKQAHZG2.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/composites/agent-stream/agent-stream.tsx"],"names":[],"mappings":";;;;;;;;;;AA2FA,IAAM,WAAA,GAAc,UAAA;AAAA,EAClB,CAAC,EAAE,SAAA,EAAW,KAAA,EAAO,GAAG,OAAM,EAAG,GAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAK/B,GAAA,CAAC,kBAAA,EAAA,EAAmB,KAAA,EAAO,IAAA,EACzB,QAAA,kBAAA,GAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,GAAA;AAAA,QACA,IAAA,EAAK,KAAA;AAAA,QACL,WAAA,EAAU,QAAA;AAAA,QACV,eAAA,EAAc,WAAA;AAAA,QAGd,aAAA,EAAY,OAAA;AAAA,QACZ,SAAA,EAAW,EAAA,CAAG,qBAAA,EAAuB,SAAS,CAAA;AAAA,QAC7C,GAAG,KAAA;AAAA,QAEH,QAAA,EAAA,KAAA,CAAM,GAAA,CAAI,CAAC,IAAA,KAAS;AACnB,UAAA,IAAI,IAAA,CAAK,IAAA,KAAS,SAAA,EAAW,uBAAO,GAAA,CAAC,eAA0B,OAAA,EAAS,IAAA,CAAK,OAAA,EAAA,EAAvB,IAAA,CAAK,EAA2B,CAAA;AACtF,UAAA,IAAI,KAAK,IAAA,KAAS,WAAA;AAChB,YAAA,uBACE,GAAA;AAAA,cAAC,YAAA;AAAA,cAAA;AAAA,gBAEC,MAAM,IAAA,CAAK,IAAA;AAAA,gBACX,MAAM,IAAA,CAAK,IAAA;AAAA,gBACX,QAAQ,IAAA,CAAK,MAAA;AAAA,gBACb,QAAQ,IAAA,CAAK,MAAA;AAAA,gBACb,QAAQ,IAAA,CAAK,MAAA;AAAA,gBACb,iBAAiB,IAAA,CAAK,eAAA;AAAA,gBACtB,WAAW,IAAA,CAAK;AAAA,eAAA;AAAA,cAPX,IAAA,CAAK;AAAA,aAQZ;AAEJ,UAAA,IAAI,KAAK,IAAA,KAAS,UAAA;AAChB,YAAA,uBACE,GAAA;AAAA,cAAC,YAAA;AAAA,cAAA;AAAA,gBAEC,UAAU,IAAA,CAAK,QAAA;AAAA,gBACf,OAAO,IAAA,CAAK,KAAA;AAAA,gBACZ,SAAS,IAAA,CAAK,OAAA;AAAA,gBACd,aAAa,IAAA,CAAK,WAAA;AAAA,gBAClB,SAAS,IAAA,CAAK,OAAA;AAAA,gBACd,WAAW,IAAA,CAAK,SAAA;AAAA,gBAChB,QAAQ,IAAA,CAAK,MAAA;AAAA,gBACb,UAAU,IAAA,CAAK;AAAA,eAAA;AAAA,cARV,IAAA,CAAK;AAAA,aASZ;AAEJ,UAAA,IAAI,KAAK,IAAA,KAAS,OAAA;AAChB,YAAA,uBACE,GAAA;AAAA,cAAC,cAAA;AAAA,cAAA;AAAA,gBAEC,MAAM,IAAA,CAAK,SAAA;AAAA,gBACX,OAAO,IAAA,CAAK,KAAA;AAAA,gBACZ,QAAQ,IAAA,CAAK,MAAA;AAAA,gBACb,SAAS,IAAA,CAAK,OAAA;AAAA,gBACd,WAAW,IAAA,CAAK;AAAA,eAAA;AAAA,cALX,IAAA,CAAK;AAAA,aAMZ;AAEJ,UAAA,IAAI,KAAK,IAAA,KAAS,WAAA;AAChB,YAAA,uBAAO,GAAA,CAAC,kBAA6B,KAAA,EAAO,IAAA,CAAK,OAAO,OAAA,EAAS,IAAA,CAAK,OAAA,EAAA,EAA1C,IAAA,CAAK,EAA8C,CAAA;AACjF,UAAA,IAAI,IAAA,CAAK,SAAS,QAAA,EAAU,2BAAQ,KAAA,EAAA,EAAmB,QAAA,EAAA,IAAA,CAAK,IAAA,EAAA,EAAf,IAAA,CAAK,EAAe,CAAA;AACjE,UAAA,OAAO,IAAA;AAAA,QACT,CAAC;AAAA;AAAA,KACH,EACF;AAAA;AAEJ;AACA,WAAA,CAAY,WAAA,GAAc,aAAA","file":"chunk-
|
|
1
|
+
{"version":3,"sources":["../src/components/composites/agent-stream/agent-stream.tsx"],"names":[],"mappings":";;;;;;;;;;AA2FA,IAAM,WAAA,GAAc,UAAA;AAAA,EAClB,CAAC,EAAE,SAAA,EAAW,KAAA,EAAO,GAAG,OAAM,EAAG,GAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAK/B,GAAA,CAAC,kBAAA,EAAA,EAAmB,KAAA,EAAO,IAAA,EACzB,QAAA,kBAAA,GAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,GAAA;AAAA,QACA,IAAA,EAAK,KAAA;AAAA,QACL,WAAA,EAAU,QAAA;AAAA,QACV,eAAA,EAAc,WAAA;AAAA,QAGd,aAAA,EAAY,OAAA;AAAA,QACZ,SAAA,EAAW,EAAA,CAAG,qBAAA,EAAuB,SAAS,CAAA;AAAA,QAC7C,GAAG,KAAA;AAAA,QAEH,QAAA,EAAA,KAAA,CAAM,GAAA,CAAI,CAAC,IAAA,KAAS;AACnB,UAAA,IAAI,IAAA,CAAK,IAAA,KAAS,SAAA,EAAW,uBAAO,GAAA,CAAC,eAA0B,OAAA,EAAS,IAAA,CAAK,OAAA,EAAA,EAAvB,IAAA,CAAK,EAA2B,CAAA;AACtF,UAAA,IAAI,KAAK,IAAA,KAAS,WAAA;AAChB,YAAA,uBACE,GAAA;AAAA,cAAC,YAAA;AAAA,cAAA;AAAA,gBAEC,MAAM,IAAA,CAAK,IAAA;AAAA,gBACX,MAAM,IAAA,CAAK,IAAA;AAAA,gBACX,QAAQ,IAAA,CAAK,MAAA;AAAA,gBACb,QAAQ,IAAA,CAAK,MAAA;AAAA,gBACb,QAAQ,IAAA,CAAK,MAAA;AAAA,gBACb,iBAAiB,IAAA,CAAK,eAAA;AAAA,gBACtB,WAAW,IAAA,CAAK;AAAA,eAAA;AAAA,cAPX,IAAA,CAAK;AAAA,aAQZ;AAEJ,UAAA,IAAI,KAAK,IAAA,KAAS,UAAA;AAChB,YAAA,uBACE,GAAA;AAAA,cAAC,YAAA;AAAA,cAAA;AAAA,gBAEC,UAAU,IAAA,CAAK,QAAA;AAAA,gBACf,OAAO,IAAA,CAAK,KAAA;AAAA,gBACZ,SAAS,IAAA,CAAK,OAAA;AAAA,gBACd,aAAa,IAAA,CAAK,WAAA;AAAA,gBAClB,SAAS,IAAA,CAAK,OAAA;AAAA,gBACd,WAAW,IAAA,CAAK,SAAA;AAAA,gBAChB,QAAQ,IAAA,CAAK,MAAA;AAAA,gBACb,UAAU,IAAA,CAAK;AAAA,eAAA;AAAA,cARV,IAAA,CAAK;AAAA,aASZ;AAEJ,UAAA,IAAI,KAAK,IAAA,KAAS,OAAA;AAChB,YAAA,uBACE,GAAA;AAAA,cAAC,cAAA;AAAA,cAAA;AAAA,gBAEC,MAAM,IAAA,CAAK,SAAA;AAAA,gBACX,OAAO,IAAA,CAAK,KAAA;AAAA,gBACZ,QAAQ,IAAA,CAAK,MAAA;AAAA,gBACb,SAAS,IAAA,CAAK,OAAA;AAAA,gBACd,WAAW,IAAA,CAAK;AAAA,eAAA;AAAA,cALX,IAAA,CAAK;AAAA,aAMZ;AAEJ,UAAA,IAAI,KAAK,IAAA,KAAS,WAAA;AAChB,YAAA,uBAAO,GAAA,CAAC,kBAA6B,KAAA,EAAO,IAAA,CAAK,OAAO,OAAA,EAAS,IAAA,CAAK,OAAA,EAAA,EAA1C,IAAA,CAAK,EAA8C,CAAA;AACjF,UAAA,IAAI,IAAA,CAAK,SAAS,QAAA,EAAU,2BAAQ,KAAA,EAAA,EAAmB,QAAA,EAAA,IAAA,CAAK,IAAA,EAAA,EAAf,IAAA,CAAK,EAAe,CAAA;AACjE,UAAA,OAAO,IAAA;AAAA,QACT,CAAC;AAAA;AAAA,KACH,EACF;AAAA;AAEJ;AACA,WAAA,CAAY,WAAA,GAAc,aAAA","file":"chunk-DKQAHZG2.js","sourcesContent":["import { forwardRef } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"../../../lib/cn.js\";\nimport { LiveRegionProvider } from \"../../../lib/live-region-context.js\";\nimport type { IconComponent } from \"../../../lib/types.js\";\nimport type { UIMessage } from \"../../../types/chat.js\";\nimport { AgentErrorCard, type AgentErrorKind } from \"../../primitives/agent-error-card/index.js\";\nimport { AgentStreaming } from \"../../primitives/agent-streaming/index.js\";\nimport { ToolCallCard, type ToolCallStatus } from \"../../primitives/tool-call-card/index.js\";\nimport { ApprovalCard, type ApprovalSeverity } from \"../approval-card/index.js\";\nimport { ChatMessage } from \"../chat-message/index.js\";\n\n/**\n * AgentStream — the canonical conversation surface for a code agent.\n *\n * Interleaves chat messages (user + assistant), tool invocations, approval\n * gates, errors, and the live streaming indicator. Mirrors how Claude Code\n * presents work to the user: conversation-centric, tool calls embedded,\n * approvals pause the flow inline, errors surface where they happen.\n *\n * Items are rendered in array order. The consumer fully controls the data;\n * AgentStream is a pure presentational composite over its child primitives.\n */\n\ninterface ToolCallStreamItem {\n kind: \"tool-call\";\n id: string;\n tool: ReactNode;\n icon?: IconComponent;\n target?: ReactNode;\n status: ToolCallStatus;\n output?: ReactNode;\n defaultExpanded?: boolean;\n timestamp?: ReactNode;\n}\n\ninterface ApprovalStreamItem {\n kind: \"approval\";\n id: string;\n severity?: ApprovalSeverity;\n title: ReactNode;\n request: ReactNode;\n description?: ReactNode;\n details?: ReactNode;\n onApprove?: () => void;\n onDeny?: () => void;\n onAlways?: () => void;\n}\n\ninterface ErrorStreamItem {\n kind: \"error\";\n id: string;\n errorKind?: AgentErrorKind;\n title: ReactNode;\n detail?: ReactNode;\n actions?: ReactNode;\n timestamp?: ReactNode;\n}\n\ninterface StreamingStreamItem {\n kind: \"streaming\";\n id: string;\n model?: ReactNode;\n partial?: ReactNode;\n}\n\ninterface MessageStreamItem {\n kind: \"message\";\n id: string;\n message: UIMessage;\n}\n\ninterface CustomStreamItem {\n kind: \"custom\";\n id: string;\n /** Arbitrary node — escape hatch for inline diff cards, etc. */\n node: ReactNode;\n}\n\nexport type AgentStreamItem =\n | MessageStreamItem\n | ToolCallStreamItem\n | ApprovalStreamItem\n | ErrorStreamItem\n | StreamingStreamItem\n | CustomStreamItem;\n\ninterface AgentStreamProps extends HTMLAttributes<HTMLDivElement> {\n items: AgentStreamItem[];\n}\n\nconst AgentStream = forwardRef<HTMLDivElement, AgentStreamProps>(\n ({ className, items, ...props }, ref) => (\n // T4.1 (MF-4): AgentStream is the canonical live region for the stream\n // surface. Wrap children in LiveRegionProvider so nested AgentStreaming,\n // AgentErrorCard, AutoCompactNotice, Skeleton, etc. don't declare their\n // own aria-live (which would cause double announcements).\n <LiveRegionProvider value={true}>\n <div\n ref={ref}\n role=\"log\"\n aria-live=\"polite\"\n aria-relevant=\"additions\"\n // MEDIUM-001: explicit aria-atomic=\"false\" so VoiceOver/macOS doesn't\n // reannounce the entire stream on each new item.\n aria-atomic=\"false\"\n className={cn(\"flex flex-col gap-3\", className)}\n {...props}\n >\n {items.map((item) => {\n if (item.kind === \"message\") return <ChatMessage key={item.id} message={item.message} />;\n if (item.kind === \"tool-call\")\n return (\n <ToolCallCard\n key={item.id}\n tool={item.tool}\n icon={item.icon}\n target={item.target}\n status={item.status}\n output={item.output}\n defaultExpanded={item.defaultExpanded}\n timestamp={item.timestamp}\n />\n );\n if (item.kind === \"approval\")\n return (\n <ApprovalCard\n key={item.id}\n severity={item.severity}\n title={item.title}\n request={item.request}\n description={item.description}\n details={item.details}\n onApprove={item.onApprove}\n onDeny={item.onDeny}\n onAlways={item.onAlways}\n />\n );\n if (item.kind === \"error\")\n return (\n <AgentErrorCard\n key={item.id}\n kind={item.errorKind}\n title={item.title}\n detail={item.detail}\n actions={item.actions}\n timestamp={item.timestamp}\n />\n );\n if (item.kind === \"streaming\")\n return <AgentStreaming key={item.id} model={item.model} partial={item.partial} />;\n if (item.kind === \"custom\") return <div key={item.id}>{item.node}</div>;\n return null;\n })}\n </div>\n </LiveRegionProvider>\n ),\n);\nAgentStream.displayName = \"AgentStream\";\n\nexport { AgentStream };\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ALL_MODES, MODE_LABEL } from './chunk-VM4RMQQN.js';
|
|
2
|
-
import { Switch } from './chunk-3HOXC25T.js';
|
|
3
2
|
import { Textarea } from './chunk-WWNH5ENT.js';
|
|
3
|
+
import { Switch } from './chunk-3HOXC25T.js';
|
|
4
4
|
import { Select } from './chunk-EP25QJ4N.js';
|
|
5
5
|
import { FormField } from './chunk-TK24HQJJ.js';
|
|
6
6
|
import { Input } from './chunk-H3VJMFJQ.js';
|
|
@@ -182,5 +182,5 @@ function SkillEditor({
|
|
|
182
182
|
}
|
|
183
183
|
|
|
184
184
|
export { SkillEditor };
|
|
185
|
-
//# sourceMappingURL=chunk-
|
|
186
|
-
//# sourceMappingURL=chunk-
|
|
185
|
+
//# sourceMappingURL=chunk-IPEYGWA7.js.map
|
|
186
|
+
//# sourceMappingURL=chunk-IPEYGWA7.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/composites/skill-editor/skill-editor.tsx"],"names":[],"mappings":"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","file":"chunk-DAKIL5PC.js","sourcesContent":["import { useState } from \"react\";\nimport type { FormEvent, HTMLAttributes } from \"react\";\nimport { cn } from \"../../../lib/cn.js\";\nimport { ALL_MODES, MODE_LABEL, type Mode } from \"../../../types/mode.js\";\nimport { Button } from \"../../primitives/button/index.js\";\nimport { FormField } from \"../../primitives/form-field/index.js\";\nimport { Input } from \"../../primitives/input/index.js\";\nimport { Select } from \"../../primitives/select/index.js\";\nimport type { Skill, SkillSource, SkillState } from \"../../primitives/skill-card/index.js\";\nimport { Switch } from \"../../primitives/switch/index.js\";\nimport { Textarea } from \"../../primitives/textarea/index.js\";\n\n/**\n * SkillEditor — form for creating or editing a Skill.\n */\n\ntype SkillDraft = Omit<Skill, \"id\"> & {\n id?: string;\n instructions?: string;\n};\n\ninterface SkillEditorProps extends Omit<HTMLAttributes<HTMLFormElement>, \"onSubmit\" | \"onChange\"> {\n initial?: Partial<Skill> & { instructions?: string };\n onSave: (draft: SkillDraft) => void;\n onCancel?: () => void;\n onDelete?: () => void;\n}\n\nconst SOURCES: Array<{ id: SkillSource; label: string }> = [\n { id: \"user\", label: \"User — defined by you\" },\n { id: \"project\", label: \"Project — lives in this workspace\" },\n { id: \"plugin\", label: \"Plugin — imported from a package\" },\n { id: \"builtin\", label: \"Built-in — shipped with Theo\" },\n];\n\nexport function SkillEditor({\n className,\n initial,\n onSave,\n onCancel,\n onDelete,\n ...formProps\n}: SkillEditorProps) {\n const [name, setName] = useState(initial?.name ?? \"\");\n const [description, setDescription] = useState(\n typeof initial?.description === \"string\" ? initial.description : \"\",\n );\n const [instructions, setInstructions] = useState(initial?.instructions ?? \"\");\n const [source, setSource] = useState<SkillSource>(initial?.source ?? \"user\");\n const [allowedToolsRaw, setAllowedToolsRaw] = useState(initial?.allowedTools?.join(\", \") ?? \"\");\n const [triggersRaw, setTriggersRaw] = useState(initial?.triggers?.join(\", \") ?? \"\");\n const [enabled, setEnabled] = useState<SkillState>(initial?.state ?? \"enabled\");\n const [modes, setModes] = useState<Mode[]>(initial?.modes ?? []);\n\n // Note: state is only seeded once on mount. To reset the form when editing\n // a different skill, use the React `key` pattern at the call site:\n // <SkillEditor key={skill.id} initial={skill} ... />\n const toggleMode = (m: Mode) =>\n setModes((prev) => (prev.includes(m) ? prev.filter((x) => x !== m) : [...prev, m]));\n\n const canSave = name.trim().length > 0;\n const handleSubmit = (e: FormEvent) => {\n e.preventDefault();\n if (!canSave) return;\n onSave({\n id: initial?.id,\n name: name.trim(),\n description: description.trim() || undefined,\n instructions: instructions.trim() || undefined,\n source,\n state: enabled,\n allowedTools: allowedToolsRaw\n .split(\",\")\n .map((t) => t.trim())\n .filter(Boolean),\n triggers: triggersRaw\n .split(\",\")\n .map((t) => t.trim())\n .filter(Boolean),\n modes: modes.length > 0 ? modes : undefined,\n });\n };\n\n return (\n <form\n onSubmit={handleSubmit}\n className={cn(\"flex h-full flex-col gap-4\", className)}\n {...formProps}\n >\n <FormField>\n <FormField.Label>Name</FormField.Label>\n <FormField.Control>\n <Input\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder=\"diff-explainer\"\n required\n />\n </FormField.Control>\n <FormField.Hint>Kebab-case identifier the agent uses to invoke this skill.</FormField.Hint>\n </FormField>\n\n <FormField>\n <FormField.Label>Description</FormField.Label>\n <FormField.Control>\n <Input\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder=\"Explain a diff in plain English.\"\n />\n </FormField.Control>\n </FormField>\n\n <FormField className=\"flex-1\">\n <FormField.Label>Instructions</FormField.Label>\n <FormField.Control>\n <Textarea\n value={instructions}\n onChange={(e) => setInstructions(e.target.value)}\n rows={6}\n placeholder=\"When invoked, read the diff via Read or Grep and produce a concise summary of intent + risk.\"\n className=\"min-h-[10rem] flex-1 font-mono text-code-sm\"\n />\n </FormField.Control>\n <FormField.Hint>Sub-prompt loaded when the skill is invoked.</FormField.Hint>\n </FormField>\n\n <div className=\"grid grid-cols-2 gap-3\">\n <FormField>\n <FormField.Label>Source</FormField.Label>\n <FormField.Control>\n <Select\n value={source}\n onValueChange={(v) => {\n // Re-audit Issue 7: narrow Select string value against\n // SOURCES.id before casting. Silent no-op for unknown.\n const next = SOURCES.find((s) => s.id === v);\n if (next) setSource(next.id);\n }}\n >\n <Select.Trigger aria-label=\"Select skill source\">\n <Select.Value />\n </Select.Trigger>\n <Select.Content>\n {SOURCES.map((s) => (\n <Select.Item key={s.id} value={s.id}>\n {s.label}\n </Select.Item>\n ))}\n </Select.Content>\n </Select>\n </FormField.Control>\n </FormField>\n <FormField>\n <FormField.Label>Allowed tools</FormField.Label>\n <FormField.Control>\n <Input\n value={allowedToolsRaw}\n onChange={(e) => setAllowedToolsRaw(e.target.value)}\n placeholder=\"Read, Grep, Bash\"\n />\n </FormField.Control>\n </FormField>\n </div>\n\n <FormField>\n <FormField.Label>Triggers</FormField.Label>\n <FormField.Control>\n <Input\n value={triggersRaw}\n onChange={(e) => setTriggersRaw(e.target.value)}\n placeholder=\"explain diff, summarize change\"\n />\n </FormField.Control>\n <FormField.Hint>Optional keywords / patterns for auto-discovery.</FormField.Hint>\n </FormField>\n\n <FormField>\n <FormField.Label>Active modes</FormField.Label>\n <div className=\"flex flex-wrap gap-1.5\">\n {ALL_MODES.map((m) => {\n const on = modes.includes(m);\n return (\n <button\n key={m}\n type=\"button\"\n onClick={() => toggleMode(m)}\n aria-pressed={on}\n className={cn(\n \"inline-flex h-7 items-center rounded-full border px-3 font-mono text-body-sm transition-colors\",\n on\n ? \"border-primary bg-primary/15 text-primary\"\n : \"border-border/60 bg-card text-muted-foreground hover:text-foreground\",\n )}\n >\n {MODE_LABEL[m]}\n </button>\n );\n })}\n </div>\n <FormField.Hint>\n {modes.length === 0\n ? \"Empty = global (available in every mode).\"\n : `Only visible in: ${modes.map((m) => MODE_LABEL[m]).join(\", \")}.`}\n </FormField.Hint>\n </FormField>\n\n <div className=\"flex items-center gap-3\">\n <Switch\n checked={enabled === \"enabled\"}\n onCheckedChange={(v) => setEnabled(v ? \"enabled\" : \"disabled\")}\n aria-label=\"Enabled\"\n />\n <span className=\"text-body-sm text-muted-foreground\">\n {enabled === \"enabled\"\n ? \"Enabled — available to the agent.\"\n : \"Disabled — kept but hidden from the agent.\"}\n </span>\n </div>\n\n <footer className=\"flex items-center justify-between gap-2 border-border/40 border-t pt-4\">\n <div>\n {onDelete ? (\n <Button type=\"button\" variant=\"ghost\" onClick={onDelete}>\n Delete\n </Button>\n ) : null}\n </div>\n <div className=\"flex items-center gap-2\">\n {onCancel ? (\n <Button type=\"button\" variant=\"secondary\" onClick={onCancel}>\n Cancel\n </Button>\n ) : null}\n <Button type=\"submit\" disabled={!canSave}>\n {initial?.id ? \"Save changes\" : \"Create skill\"}\n </Button>\n </div>\n </footer>\n </form>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/components/composites/skill-editor/skill-editor.tsx"],"names":[],"mappings":"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","file":"chunk-IPEYGWA7.js","sourcesContent":["import { useState } from \"react\";\nimport type { FormEvent, HTMLAttributes } from \"react\";\nimport { cn } from \"../../../lib/cn.js\";\nimport { ALL_MODES, MODE_LABEL, type Mode } from \"../../../types/mode.js\";\nimport { Button } from \"../../primitives/button/index.js\";\nimport { FormField } from \"../../primitives/form-field/index.js\";\nimport { Input } from \"../../primitives/input/index.js\";\nimport { Select } from \"../../primitives/select/index.js\";\nimport type { Skill, SkillSource, SkillState } from \"../../primitives/skill-card/index.js\";\nimport { Switch } from \"../../primitives/switch/index.js\";\nimport { Textarea } from \"../../primitives/textarea/index.js\";\n\n/**\n * SkillEditor — form for creating or editing a Skill.\n */\n\ntype SkillDraft = Omit<Skill, \"id\"> & {\n id?: string;\n instructions?: string;\n};\n\ninterface SkillEditorProps extends Omit<HTMLAttributes<HTMLFormElement>, \"onSubmit\" | \"onChange\"> {\n initial?: Partial<Skill> & { instructions?: string };\n onSave: (draft: SkillDraft) => void;\n onCancel?: () => void;\n onDelete?: () => void;\n}\n\nconst SOURCES: Array<{ id: SkillSource; label: string }> = [\n { id: \"user\", label: \"User — defined by you\" },\n { id: \"project\", label: \"Project — lives in this workspace\" },\n { id: \"plugin\", label: \"Plugin — imported from a package\" },\n { id: \"builtin\", label: \"Built-in — shipped with Theo\" },\n];\n\nexport function SkillEditor({\n className,\n initial,\n onSave,\n onCancel,\n onDelete,\n ...formProps\n}: SkillEditorProps) {\n const [name, setName] = useState(initial?.name ?? \"\");\n const [description, setDescription] = useState(\n typeof initial?.description === \"string\" ? initial.description : \"\",\n );\n const [instructions, setInstructions] = useState(initial?.instructions ?? \"\");\n const [source, setSource] = useState<SkillSource>(initial?.source ?? \"user\");\n const [allowedToolsRaw, setAllowedToolsRaw] = useState(initial?.allowedTools?.join(\", \") ?? \"\");\n const [triggersRaw, setTriggersRaw] = useState(initial?.triggers?.join(\", \") ?? \"\");\n const [enabled, setEnabled] = useState<SkillState>(initial?.state ?? \"enabled\");\n const [modes, setModes] = useState<Mode[]>(initial?.modes ?? []);\n\n // Note: state is only seeded once on mount. To reset the form when editing\n // a different skill, use the React `key` pattern at the call site:\n // <SkillEditor key={skill.id} initial={skill} ... />\n const toggleMode = (m: Mode) =>\n setModes((prev) => (prev.includes(m) ? prev.filter((x) => x !== m) : [...prev, m]));\n\n const canSave = name.trim().length > 0;\n const handleSubmit = (e: FormEvent) => {\n e.preventDefault();\n if (!canSave) return;\n onSave({\n id: initial?.id,\n name: name.trim(),\n description: description.trim() || undefined,\n instructions: instructions.trim() || undefined,\n source,\n state: enabled,\n allowedTools: allowedToolsRaw\n .split(\",\")\n .map((t) => t.trim())\n .filter(Boolean),\n triggers: triggersRaw\n .split(\",\")\n .map((t) => t.trim())\n .filter(Boolean),\n modes: modes.length > 0 ? modes : undefined,\n });\n };\n\n return (\n <form\n onSubmit={handleSubmit}\n className={cn(\"flex h-full flex-col gap-4\", className)}\n {...formProps}\n >\n <FormField>\n <FormField.Label>Name</FormField.Label>\n <FormField.Control>\n <Input\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder=\"diff-explainer\"\n required\n />\n </FormField.Control>\n <FormField.Hint>Kebab-case identifier the agent uses to invoke this skill.</FormField.Hint>\n </FormField>\n\n <FormField>\n <FormField.Label>Description</FormField.Label>\n <FormField.Control>\n <Input\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder=\"Explain a diff in plain English.\"\n />\n </FormField.Control>\n </FormField>\n\n <FormField className=\"flex-1\">\n <FormField.Label>Instructions</FormField.Label>\n <FormField.Control>\n <Textarea\n value={instructions}\n onChange={(e) => setInstructions(e.target.value)}\n rows={6}\n placeholder=\"When invoked, read the diff via Read or Grep and produce a concise summary of intent + risk.\"\n className=\"min-h-[10rem] flex-1 font-mono text-code-sm\"\n />\n </FormField.Control>\n <FormField.Hint>Sub-prompt loaded when the skill is invoked.</FormField.Hint>\n </FormField>\n\n <div className=\"grid grid-cols-2 gap-3\">\n <FormField>\n <FormField.Label>Source</FormField.Label>\n <FormField.Control>\n <Select\n value={source}\n onValueChange={(v) => {\n // Re-audit Issue 7: narrow Select string value against\n // SOURCES.id before casting. Silent no-op for unknown.\n const next = SOURCES.find((s) => s.id === v);\n if (next) setSource(next.id);\n }}\n >\n <Select.Trigger aria-label=\"Select skill source\">\n <Select.Value />\n </Select.Trigger>\n <Select.Content>\n {SOURCES.map((s) => (\n <Select.Item key={s.id} value={s.id}>\n {s.label}\n </Select.Item>\n ))}\n </Select.Content>\n </Select>\n </FormField.Control>\n </FormField>\n <FormField>\n <FormField.Label>Allowed tools</FormField.Label>\n <FormField.Control>\n <Input\n value={allowedToolsRaw}\n onChange={(e) => setAllowedToolsRaw(e.target.value)}\n placeholder=\"Read, Grep, Bash\"\n />\n </FormField.Control>\n </FormField>\n </div>\n\n <FormField>\n <FormField.Label>Triggers</FormField.Label>\n <FormField.Control>\n <Input\n value={triggersRaw}\n onChange={(e) => setTriggersRaw(e.target.value)}\n placeholder=\"explain diff, summarize change\"\n />\n </FormField.Control>\n <FormField.Hint>Optional keywords / patterns for auto-discovery.</FormField.Hint>\n </FormField>\n\n <FormField>\n <FormField.Label>Active modes</FormField.Label>\n <div className=\"flex flex-wrap gap-1.5\">\n {ALL_MODES.map((m) => {\n const on = modes.includes(m);\n return (\n <button\n key={m}\n type=\"button\"\n onClick={() => toggleMode(m)}\n aria-pressed={on}\n className={cn(\n \"inline-flex h-7 items-center rounded-full border px-3 font-mono text-body-sm transition-colors\",\n on\n ? \"border-primary bg-primary/15 text-primary\"\n : \"border-border/60 bg-card text-muted-foreground hover:text-foreground\",\n )}\n >\n {MODE_LABEL[m]}\n </button>\n );\n })}\n </div>\n <FormField.Hint>\n {modes.length === 0\n ? \"Empty = global (available in every mode).\"\n : `Only visible in: ${modes.map((m) => MODE_LABEL[m]).join(\", \")}.`}\n </FormField.Hint>\n </FormField>\n\n <div className=\"flex items-center gap-3\">\n <Switch\n checked={enabled === \"enabled\"}\n onCheckedChange={(v) => setEnabled(v ? \"enabled\" : \"disabled\")}\n aria-label=\"Enabled\"\n />\n <span className=\"text-body-sm text-muted-foreground\">\n {enabled === \"enabled\"\n ? \"Enabled — available to the agent.\"\n : \"Disabled — kept but hidden from the agent.\"}\n </span>\n </div>\n\n <footer className=\"flex items-center justify-between gap-2 border-border/40 border-t pt-4\">\n <div>\n {onDelete ? (\n <Button type=\"button\" variant=\"ghost\" onClick={onDelete}>\n Delete\n </Button>\n ) : null}\n </div>\n <div className=\"flex items-center gap-2\">\n {onCancel ? (\n <Button type=\"button\" variant=\"secondary\" onClick={onCancel}>\n Cancel\n </Button>\n ) : null}\n <Button type=\"submit\" disabled={!canSave}>\n {initial?.id ? \"Save changes\" : \"Create skill\"}\n </Button>\n </div>\n </footer>\n </form>\n );\n}\n"]}
|