@sero-ai/ui 0.3.2 → 0.4.1
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/.turbo/turbo-build.log +615 -0
- package/.turbo/turbo-typecheck.log +1 -1
- package/CHANGELOG.md +58 -0
- package/dist/components/context-editor/CapabilitySection.cjs +57 -0
- package/dist/components/context-editor/CapabilitySection.d.cts +20 -0
- package/dist/components/context-editor/CapabilitySection.d.ts +20 -0
- package/dist/components/context-editor/CapabilitySection.js +57 -0
- package/dist/components/context-editor/ContextEditor.cjs +108 -0
- package/dist/components/context-editor/ContextEditor.d.cts +26 -0
- package/dist/components/context-editor/ContextEditor.d.ts +26 -0
- package/dist/components/context-editor/ContextEditor.js +108 -0
- package/dist/components/context-editor/PresetBar.cjs +71 -0
- package/dist/components/context-editor/PresetBar.d.cts +19 -0
- package/dist/components/context-editor/PresetBar.d.ts +19 -0
- package/dist/components/context-editor/PresetBar.js +71 -0
- package/dist/components/context-editor/SkillsSection.cjs +31 -0
- package/dist/components/context-editor/SkillsSection.d.cts +14 -0
- package/dist/components/context-editor/SkillsSection.d.ts +14 -0
- package/dist/components/context-editor/SkillsSection.js +31 -0
- package/dist/components/context-editor/SystemPromptSection.cjs +58 -0
- package/dist/components/context-editor/SystemPromptSection.d.cts +25 -0
- package/dist/components/context-editor/SystemPromptSection.d.ts +25 -0
- package/dist/components/context-editor/SystemPromptSection.js +58 -0
- package/dist/components/context-editor/ToolsSection.cjs +31 -0
- package/dist/components/context-editor/ToolsSection.d.cts +14 -0
- package/dist/components/context-editor/ToolsSection.d.ts +14 -0
- package/dist/components/context-editor/ToolsSection.js +31 -0
- package/dist/components/context-editor/index.cjs +8 -0
- package/dist/components/context-editor/index.d.cts +5 -0
- package/dist/components/context-editor/index.d.ts +5 -0
- package/dist/components/context-editor/index.js +8 -0
- package/dist/components/context-editor/parts.cjs +184 -0
- package/dist/components/context-editor/parts.d.cts +32 -0
- package/dist/components/context-editor/parts.d.ts +32 -0
- package/dist/components/context-editor/parts.js +184 -0
- package/dist/components/context-editor/use-context-editor-model.cjs +194 -0
- package/dist/components/context-editor/use-context-editor-model.d.cts +57 -0
- package/dist/components/context-editor/use-context-editor-model.d.ts +57 -0
- package/dist/components/context-editor/use-context-editor-model.js +194 -0
- package/dist/components/dashboard/activity-list.cjs +59 -0
- package/dist/components/dashboard/activity-list.d.cts +27 -0
- package/dist/components/dashboard/activity-list.d.ts +27 -0
- package/dist/components/dashboard/activity-list.js +59 -0
- package/dist/components/dashboard/catalog.cjs +1 -0
- package/dist/components/dashboard/catalog.d.cts +13 -0
- package/dist/components/dashboard/catalog.d.ts +13 -0
- package/dist/components/dashboard/catalog.js +0 -0
- package/dist/components/dashboard/catalog.json +312 -0
- package/dist/components/dashboard/data-boundary.cjs +29 -0
- package/dist/components/dashboard/data-boundary.d.cts +21 -0
- package/dist/components/dashboard/data-boundary.d.ts +21 -0
- package/dist/components/dashboard/data-boundary.js +29 -0
- package/dist/components/dashboard/empty-state.cjs +49 -0
- package/dist/components/dashboard/empty-state.d.cts +20 -0
- package/dist/components/dashboard/empty-state.d.ts +20 -0
- package/dist/components/dashboard/empty-state.js +49 -0
- package/dist/components/dashboard/icon-button.cjs +40 -0
- package/dist/components/dashboard/icon-button.d.cts +24 -0
- package/dist/components/dashboard/icon-button.d.ts +24 -0
- package/dist/components/dashboard/icon-button.js +40 -0
- package/dist/components/dashboard/index.cjs +15 -0
- package/dist/components/dashboard/index.d.cts +24 -0
- package/dist/components/dashboard/index.d.ts +24 -0
- package/dist/components/dashboard/index.js +15 -0
- package/dist/components/dashboard/item-list.cjs +71 -0
- package/dist/components/dashboard/item-list.d.cts +28 -0
- package/dist/components/dashboard/item-list.d.ts +28 -0
- package/dist/components/dashboard/item-list.js +71 -0
- package/dist/components/dashboard/key-value.cjs +39 -0
- package/dist/components/dashboard/key-value.d.cts +17 -0
- package/dist/components/dashboard/key-value.d.ts +17 -0
- package/dist/components/dashboard/key-value.js +39 -0
- package/dist/components/dashboard/layout.cjs +193 -0
- package/dist/components/dashboard/layout.d.cts +91 -0
- package/dist/components/dashboard/layout.d.ts +91 -0
- package/dist/components/dashboard/layout.js +193 -0
- package/dist/components/dashboard/metric.cjs +98 -0
- package/dist/components/dashboard/metric.d.cts +44 -0
- package/dist/components/dashboard/metric.d.ts +44 -0
- package/dist/components/dashboard/metric.js +98 -0
- package/dist/components/dashboard/progress-ring.cjs +77 -0
- package/dist/components/dashboard/progress-ring.d.cts +25 -0
- package/dist/components/dashboard/progress-ring.d.ts +25 -0
- package/dist/components/dashboard/progress-ring.js +77 -0
- package/dist/components/dashboard/skeletons.cjs +54 -0
- package/dist/components/dashboard/skeletons.d.cts +15 -0
- package/dist/components/dashboard/skeletons.d.ts +15 -0
- package/dist/components/dashboard/skeletons.js +54 -0
- package/dist/components/dashboard/spacing.cjs +10 -0
- package/dist/components/dashboard/spacing.d.cts +4 -0
- package/dist/components/dashboard/spacing.d.ts +4 -0
- package/dist/components/dashboard/spacing.js +10 -0
- package/dist/components/dashboard/stale-indicator.cjs +42 -0
- package/dist/components/dashboard/stale-indicator.d.cts +15 -0
- package/dist/components/dashboard/stale-indicator.d.ts +15 -0
- package/dist/components/dashboard/stale-indicator.js +42 -0
- package/dist/components/dashboard/status.cjs +66 -0
- package/dist/components/dashboard/status.d.cts +15 -0
- package/dist/components/dashboard/status.d.ts +15 -0
- package/dist/components/dashboard/status.js +66 -0
- package/dist/components/dashboard/tone.cjs +34 -0
- package/dist/components/dashboard/tone.d.cts +15 -0
- package/dist/components/dashboard/tone.d.ts +15 -0
- package/dist/components/dashboard/tone.js +34 -0
- package/dist/components/dashboard/typography.cjs +99 -0
- package/dist/components/dashboard/typography.d.cts +57 -0
- package/dist/components/dashboard/typography.d.ts +57 -0
- package/dist/components/dashboard/typography.js +99 -0
- package/dist/components/ui/badge.cjs +5 -1
- package/dist/components/ui/badge.d.cts +1 -1
- package/dist/components/ui/badge.d.ts +1 -1
- package/dist/components/ui/badge.js +5 -1
- package/dist/index.cjs +1 -0
- package/dist/index.d.cts +16 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +1 -0
- package/dist/reference.cjs +1260 -0
- package/dist/reference.d.cts +11 -0
- package/dist/reference.d.ts +11 -0
- package/dist/reference.js +1230 -0
- package/dist/styles/glass-board.css +43 -0
- package/dist/styles/globals.css +59 -0
- package/package.json +16 -4
- package/scripts/ensure-pnpm-publish.mjs +23 -0
- package/scripts/smoke-dist.mjs +68 -0
- package/src/components/context-editor/CapabilitySection.tsx +85 -0
- package/src/components/context-editor/ContextEditor.tsx +138 -0
- package/src/components/context-editor/PresetBar.tsx +94 -0
- package/src/components/context-editor/SkillsSection.tsx +37 -0
- package/src/components/context-editor/SystemPromptSection.tsx +88 -0
- package/src/components/context-editor/ToolsSection.tsx +37 -0
- package/src/components/context-editor/index.ts +7 -0
- package/src/components/context-editor/parts.tsx +217 -0
- package/src/components/context-editor/use-context-editor-model.ts +296 -0
- package/src/components/dashboard/__tests__/catalog.test.ts +62 -0
- package/src/components/dashboard/__tests__/glass.test.tsx +42 -0
- package/src/components/dashboard/__tests__/state.test.tsx +127 -0
- package/src/components/dashboard/__tests__/variants.test.tsx +95 -0
- package/src/components/dashboard/activity-list.tsx +99 -0
- package/src/components/dashboard/catalog.json +312 -0
- package/src/components/dashboard/catalog.ts +29 -0
- package/src/components/dashboard/data-boundary.tsx +54 -0
- package/src/components/dashboard/empty-state.tsx +70 -0
- package/src/components/dashboard/icon-button.tsx +58 -0
- package/src/components/dashboard/index.ts +21 -0
- package/src/components/dashboard/item-list.tsx +106 -0
- package/src/components/dashboard/key-value.tsx +54 -0
- package/src/components/dashboard/layout.tsx +286 -0
- package/src/components/dashboard/metric.tsx +139 -0
- package/src/components/dashboard/progress-ring.tsx +100 -0
- package/src/components/dashboard/skeletons.tsx +73 -0
- package/src/components/dashboard/spacing.ts +14 -0
- package/src/components/dashboard/stale-indicator.tsx +55 -0
- package/src/components/dashboard/status.tsx +88 -0
- package/src/components/dashboard/tone.ts +48 -0
- package/src/components/dashboard/typography.tsx +151 -0
- package/src/components/reference/ActivityExample.tsx +68 -0
- package/src/components/reference/ResourceExample.tsx +78 -0
- package/src/components/reference/SchedulerExample.tsx +88 -0
- package/src/components/reference/StarterExample.tsx +48 -0
- package/src/components/reference/index.ts +10 -0
- package/src/components/ui/badge.tsx +6 -0
- package/src/index.ts +7 -0
- package/src/reference.ts +15 -0
- package/src/styles/glass-board.css +43 -0
- package/src/styles/globals.css +59 -0
- package/tsup.config.ts +18 -4
- package/tsup.reference.config.ts +15 -0
- package/vitest.config.ts +8 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared glass board — the frosted-board look, framework-agnostic.
|
|
3
|
+
*
|
|
4
|
+
* `.glass-canvas` paints the ambient accent-glow backdrop; `.glass-tile`
|
|
5
|
+
* is a translucent, backdrop-blurred surface with a luminous hairline rim.
|
|
6
|
+
* The desktop dashboard and the styleguide preview both consume this file
|
|
7
|
+
* so widgets render on an identical board.
|
|
8
|
+
*
|
|
9
|
+
* Depends on the canonical `--glass-*` tokens in globals.css. Dark is the
|
|
10
|
+
* primary target; light mirrors the same relationships (frosted white
|
|
11
|
+
* glass over a soft tinted canvas).
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/* ── Canvas ──────────────────────────────────────────────────────
|
|
15
|
+
Ambient accent glow the glass tiles pick up. */
|
|
16
|
+
.glass-canvas {
|
|
17
|
+
--glass-canvas-base: #e9eaef;
|
|
18
|
+
--glass-glow-a: color-mix(in srgb, var(--accent-primary) 16%, transparent);
|
|
19
|
+
--glass-glow-b: color-mix(in srgb, var(--brand-primary) 12%, transparent);
|
|
20
|
+
background:
|
|
21
|
+
radial-gradient(90% 70% at 85% -10%, var(--glass-glow-a), transparent 60%),
|
|
22
|
+
radial-gradient(80% 60% at -10% 110%, var(--glass-glow-b), transparent 60%),
|
|
23
|
+
var(--glass-canvas-base);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.dark .glass-canvas {
|
|
27
|
+
--glass-canvas-base: #060608;
|
|
28
|
+
--glass-glow-a: color-mix(in srgb, var(--accent-primary) 48%, transparent);
|
|
29
|
+
--glass-glow-b: color-mix(in srgb, var(--brand-primary) 30%, transparent);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/* ── Glass tile surface ──────────────────────────────────────────
|
|
33
|
+
Translucent, blurred surface floating over the canvas. The surface is
|
|
34
|
+
static on hover — the tile is content, not a button, so pointing at it
|
|
35
|
+
must not change it. (`--glass-hover` is still used for row hover *inside*
|
|
36
|
+
widgets.) The transition covers the drag/resize state changes only. */
|
|
37
|
+
.glass-tile {
|
|
38
|
+
background: var(--glass-tile);
|
|
39
|
+
border: 1px solid var(--glass-border);
|
|
40
|
+
backdrop-filter: blur(24px) saturate(140%);
|
|
41
|
+
box-shadow: inset 0 1px 0 var(--glass-rim);
|
|
42
|
+
transition: background-color 150ms ease, border-color 150ms ease;
|
|
43
|
+
}
|
package/dist/styles/globals.css
CHANGED
|
@@ -179,6 +179,27 @@
|
|
|
179
179
|
--sidebar-accent-foreground: var(--text-primary);
|
|
180
180
|
--sidebar-border: var(--border-subtle);
|
|
181
181
|
--sidebar-ring: var(--border-focus);
|
|
182
|
+
|
|
183
|
+
/* ── Glass (dashboard) ────────────────────────────────────
|
|
184
|
+
Canonical translucent surface language for the glass
|
|
185
|
+
dashboard. The host `dashboard.css` derives its `--dash-*`
|
|
186
|
+
tokens from these, and the `.glass` scope below remaps the
|
|
187
|
+
component-facing `--surface-*` tokens to them. Light =
|
|
188
|
+
frosted white; dark values live in the `.dark` block. */
|
|
189
|
+
--glass-tile: rgba(255, 255, 255, 0.52); /* base tile (host) */
|
|
190
|
+
--glass-surface: rgba(255, 255, 255, 0.62); /* raised card */
|
|
191
|
+
--glass-surface-flat: rgba(255, 255, 255, 0.40); /* flat row */
|
|
192
|
+
--glass-border: rgba(15, 17, 23, 0.10);
|
|
193
|
+
--glass-rim: rgba(255, 255, 255, 0.60);
|
|
194
|
+
--glass-hover: rgba(255, 255, 255, 0.72);
|
|
195
|
+
|
|
196
|
+
/* Component-facing surface tokens. Default to the solid design
|
|
197
|
+
tokens so components look unchanged outside the `.glass`
|
|
198
|
+
scope; the scope flips them to the glass values above. */
|
|
199
|
+
--surface-raised: var(--bg-surface);
|
|
200
|
+
--surface-flat: var(--bg-elevated);
|
|
201
|
+
--surface-line: var(--border-subtle);
|
|
202
|
+
--surface-rim: transparent;
|
|
182
203
|
}
|
|
183
204
|
|
|
184
205
|
/* ── Scrollbars ─────────────────────────────────────────────── */
|
|
@@ -421,6 +442,44 @@
|
|
|
421
442
|
--sidebar-accent-foreground: var(--text-primary);
|
|
422
443
|
--sidebar-border: var(--border-subtle);
|
|
423
444
|
--sidebar-ring: var(--border-focus);
|
|
445
|
+
|
|
446
|
+
/* ── Glass (dashboard) — dark: low-opacity white over the dark
|
|
447
|
+
canvas glow. `--surface-*` defaults stay solid; the `.glass`
|
|
448
|
+
scope flips them (values shared across themes via the vars). */
|
|
449
|
+
--glass-tile: rgba(255, 255, 255, 0.06);
|
|
450
|
+
--glass-surface: rgba(255, 255, 255, 0.09);
|
|
451
|
+
--glass-surface-flat: rgba(255, 255, 255, 0.05);
|
|
452
|
+
--glass-border: rgba(255, 255, 255, 0.12);
|
|
453
|
+
--glass-rim: rgba(255, 255, 255, 0.08);
|
|
454
|
+
--glass-hover: rgba(255, 255, 255, 0.13);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
/* ── Glass scope ─────────────────────────────────────────────────
|
|
458
|
+
Subtree-local class applied by `WidgetContent` (default on). It
|
|
459
|
+
remaps the component-facing surface tokens and the container/border
|
|
460
|
+
shadcn bridge tokens to the translucent glass values, so dashboard
|
|
461
|
+
components read as part of the frosted tile. Interactive controls
|
|
462
|
+
(`--input`) and portalled surfaces (`--popover`, rendered at
|
|
463
|
+
document.body outside this scope) stay solid for legibility. No
|
|
464
|
+
`backdrop-filter` here — the host tile provides the single blur. */
|
|
465
|
+
.glass {
|
|
466
|
+
/* component surface tokens */
|
|
467
|
+
--surface-raised: var(--glass-surface);
|
|
468
|
+
--surface-flat: var(--glass-surface-flat);
|
|
469
|
+
--surface-line: var(--glass-border);
|
|
470
|
+
--surface-rim: var(--glass-rim);
|
|
471
|
+
|
|
472
|
+
/* containers + borders for primitives used inside widgets */
|
|
473
|
+
--card: var(--glass-surface);
|
|
474
|
+
--secondary: var(--glass-surface-flat);
|
|
475
|
+
--muted: var(--glass-surface-flat);
|
|
476
|
+
--accent: var(--glass-surface-flat);
|
|
477
|
+
--border: var(--glass-border);
|
|
478
|
+
|
|
479
|
+
/* keep interactive controls + portalled surfaces solid */
|
|
480
|
+
--input: var(--border-subtle);
|
|
481
|
+
--popover: var(--bg-elevated);
|
|
482
|
+
--ring: var(--border-focus);
|
|
424
483
|
}
|
|
425
484
|
|
|
426
485
|
html {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sero-ai/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "Shared UI components, AI elements, and design tokens for the Sero platform",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -11,6 +11,12 @@
|
|
|
11
11
|
"import": "./dist/index.js",
|
|
12
12
|
"require": "./dist/index.cjs"
|
|
13
13
|
},
|
|
14
|
+
"./dashboard-catalog.json": "./dist/components/dashboard/catalog.json",
|
|
15
|
+
"./reference": {
|
|
16
|
+
"types": "./dist/reference.d.ts",
|
|
17
|
+
"import": "./dist/reference.js",
|
|
18
|
+
"require": "./dist/reference.cjs"
|
|
19
|
+
},
|
|
14
20
|
"./theme": {
|
|
15
21
|
"types": "./dist/theme/index.d.ts",
|
|
16
22
|
"import": "./dist/theme/index.js",
|
|
@@ -79,15 +85,21 @@
|
|
|
79
85
|
"@types/react": "^19.2.13",
|
|
80
86
|
"@types/react-dom": "^19.2.3",
|
|
81
87
|
"@types/react-syntax-highlighter": "^15.5.13",
|
|
88
|
+
"jsdom": "^26.1.0",
|
|
89
|
+
"react": "^19.2.4",
|
|
90
|
+
"react-dom": "^19.2.4",
|
|
82
91
|
"shadcn": "^3.8.5",
|
|
83
92
|
"tailwindcss": "4.1.18",
|
|
84
93
|
"tsup": "^8.5.1",
|
|
85
94
|
"tw-animate-css": "^1.4.0",
|
|
86
|
-
"typescript": "^5.9.3"
|
|
95
|
+
"typescript": "^5.9.3",
|
|
96
|
+
"vitest": "^4.1.7"
|
|
87
97
|
},
|
|
88
98
|
"scripts": {
|
|
89
|
-
"build": "tsup",
|
|
90
|
-
"typecheck": "tsc --noEmit"
|
|
99
|
+
"build": "tsup && tsup --config tsup.reference.config.ts",
|
|
100
|
+
"typecheck": "tsc --noEmit",
|
|
101
|
+
"test": "vitest run",
|
|
102
|
+
"smoke": "node scripts/smoke-dist.mjs"
|
|
91
103
|
},
|
|
92
104
|
"module": "./dist/index.js"
|
|
93
105
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// Publish guard — this package MUST be published with `pnpm publish`.
|
|
2
|
+
//
|
|
3
|
+
// The `publishConfig` block swaps main/types/exports over to the built `dist/`
|
|
4
|
+
// at publish time. That override is a pnpm (and yarn) feature; plain npm
|
|
5
|
+
// IGNORES it and publishes the top-level fields, which point at `src/`. So
|
|
6
|
+
// `npm publish` here silently ships raw TypeScript source instead of the
|
|
7
|
+
// compiled package — exactly how 0.4.0 went out wrong.
|
|
8
|
+
//
|
|
9
|
+
// This runs from `prepublishOnly`, so it fires on every publish. It aborts
|
|
10
|
+
// unless the invoking package manager is pnpm.
|
|
11
|
+
|
|
12
|
+
const ua = process.env.npm_config_user_agent ?? "";
|
|
13
|
+
|
|
14
|
+
if (!ua.startsWith("pnpm")) {
|
|
15
|
+
const tool = ua.split("/")[0] || "an unknown tool";
|
|
16
|
+
console.error(
|
|
17
|
+
`\n✖ @sero-ai/ui must be published with pnpm, but this ran under ${tool}.\n\n` +
|
|
18
|
+
" Plain npm ignores the publishConfig dist overrides and would ship raw\n" +
|
|
19
|
+
" TypeScript source instead of the built dist/. Use:\n\n" +
|
|
20
|
+
" pnpm publish (from packages/ui)\n",
|
|
21
|
+
);
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// Smoke test for the published artifact.
|
|
2
|
+
//
|
|
3
|
+
// The package is bundle:false and bundler-resolved, so its public entrypoints
|
|
4
|
+
// are easy to break under raw Node ESM (extensionless / directory imports).
|
|
5
|
+
// This runs the built dist the way a published consumer would: it imports the
|
|
6
|
+
// reference entry (ESM + CJS) and reads the catalogue JSON, failing loudly if
|
|
7
|
+
// any entrypoint no longer resolves. Run after `pnpm build`.
|
|
8
|
+
|
|
9
|
+
import { createRequire } from "node:module";
|
|
10
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
11
|
+
import { fileURLToPath } from "node:url";
|
|
12
|
+
import { dirname, resolve } from "node:path";
|
|
13
|
+
|
|
14
|
+
const require = createRequire(import.meta.url);
|
|
15
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
16
|
+
const dist = resolve(here, "..", "dist");
|
|
17
|
+
|
|
18
|
+
const fail = (msg) => {
|
|
19
|
+
console.error(`✗ ${msg}`);
|
|
20
|
+
process.exitCode = 1;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
if (!existsSync(dist)) {
|
|
24
|
+
fail("dist/ is missing — run `pnpm build` first");
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// 1. Reference entrypoint resolves as ESM and exposes the example widgets.
|
|
29
|
+
const EXPECTED = [
|
|
30
|
+
"StarterExample",
|
|
31
|
+
"SchedulerExample",
|
|
32
|
+
"ResourceExample",
|
|
33
|
+
"ActivityExample",
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
const esm = await import(resolve(dist, "reference.js"));
|
|
37
|
+
for (const name of EXPECTED) {
|
|
38
|
+
if (typeof esm[name] !== "function") fail(`reference.js missing export ${name}`);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// 2. Reference entrypoint resolves as CJS too.
|
|
42
|
+
const cjs = require(resolve(dist, "reference.cjs"));
|
|
43
|
+
for (const name of EXPECTED) {
|
|
44
|
+
if (typeof cjs[name] !== "function") fail(`reference.cjs missing export ${name}`);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// The publishConfig `types` map points at these; a clean-race once dropped them.
|
|
48
|
+
for (const f of ["reference.d.ts", "reference.d.cts"]) {
|
|
49
|
+
if (!existsSync(resolve(dist, f))) fail(`${f} not emitted to dist`);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// 3. Catalogue ships as plain JSON with the expected shape.
|
|
53
|
+
const catalogPath = resolve(dist, "components", "dashboard", "catalog.json");
|
|
54
|
+
if (!existsSync(catalogPath)) fail("dashboard-catalog.json not emitted to dist");
|
|
55
|
+
else {
|
|
56
|
+
const catalog = JSON.parse(readFileSync(catalogPath, "utf8"));
|
|
57
|
+
if (!Array.isArray(catalog) || catalog.length === 0) {
|
|
58
|
+
fail("dashboard-catalog.json is not a non-empty array");
|
|
59
|
+
} else if (!catalog.every((e) => e.name && e.category && e.kind)) {
|
|
60
|
+
fail("dashboard-catalog.json has malformed entries");
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (process.exitCode) {
|
|
65
|
+
console.error("Smoke test failed.");
|
|
66
|
+
} else {
|
|
67
|
+
console.log("✓ dist entrypoints resolve (reference esm+cjs, catalog json)");
|
|
68
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import type { LucideIcon } from 'lucide-react';
|
|
2
|
+
import type { ContextSkillInfo, ContextToolInfo } from '@sero-ai/common';
|
|
3
|
+
import { Switch } from '../ui/switch';
|
|
4
|
+
import { ContextSection, ToggleRow } from './parts';
|
|
5
|
+
|
|
6
|
+
interface CapabilitySectionProps<TItem extends ContextToolInfo | ContextSkillInfo> {
|
|
7
|
+
icon: LucideIcon;
|
|
8
|
+
title: string;
|
|
9
|
+
tint: 'amber' | 'violet';
|
|
10
|
+
includeAllLabel: string;
|
|
11
|
+
emptyLabel: string;
|
|
12
|
+
items: TItem[];
|
|
13
|
+
allDisabled: boolean;
|
|
14
|
+
enabledCount: number;
|
|
15
|
+
isEnabled: (name: string) => boolean;
|
|
16
|
+
onToggle: (name: string) => void;
|
|
17
|
+
onToggleAll: (disabled: boolean) => void;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function CapabilitySection<TItem extends ContextToolInfo | ContextSkillInfo>({
|
|
21
|
+
icon,
|
|
22
|
+
title,
|
|
23
|
+
tint,
|
|
24
|
+
includeAllLabel,
|
|
25
|
+
emptyLabel,
|
|
26
|
+
items,
|
|
27
|
+
allDisabled,
|
|
28
|
+
enabledCount,
|
|
29
|
+
isEnabled,
|
|
30
|
+
onToggle,
|
|
31
|
+
onToggleAll,
|
|
32
|
+
}: CapabilitySectionProps<TItem>) {
|
|
33
|
+
const badgeVariant = allDisabled
|
|
34
|
+
? 'disabled' as const
|
|
35
|
+
: enabledCount < items.length
|
|
36
|
+
? 'partial' as const
|
|
37
|
+
: 'default' as const;
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<ContextSection
|
|
41
|
+
icon={icon}
|
|
42
|
+
title={title}
|
|
43
|
+
tint={tint}
|
|
44
|
+
count={items.length}
|
|
45
|
+
badge={
|
|
46
|
+
items.length > 0 && enabledCount < items.length
|
|
47
|
+
? `${enabledCount}/${items.length} included`
|
|
48
|
+
: undefined
|
|
49
|
+
}
|
|
50
|
+
badgeVariant={badgeVariant}
|
|
51
|
+
defaultOpen={false}
|
|
52
|
+
>
|
|
53
|
+
<div className="space-y-1">
|
|
54
|
+
{items.length > 0 && (
|
|
55
|
+
<div className="mb-1 flex items-center justify-between rounded-md border-b border-border/20 px-2 pb-2">
|
|
56
|
+
<span className="text-[11px] font-medium text-[var(--text-secondary)]">
|
|
57
|
+
{includeAllLabel}
|
|
58
|
+
</span>
|
|
59
|
+
<Switch
|
|
60
|
+
size="sm"
|
|
61
|
+
checked={!allDisabled}
|
|
62
|
+
onCheckedChange={(checked) => onToggleAll(!checked)}
|
|
63
|
+
/>
|
|
64
|
+
</div>
|
|
65
|
+
)}
|
|
66
|
+
|
|
67
|
+
{items.map((item) => (
|
|
68
|
+
<ToggleRow
|
|
69
|
+
key={item.name}
|
|
70
|
+
name={item.name}
|
|
71
|
+
description={item.description}
|
|
72
|
+
enabled={isEnabled(item.name)}
|
|
73
|
+
onToggle={() => onToggle(item.name)}
|
|
74
|
+
/>
|
|
75
|
+
))}
|
|
76
|
+
|
|
77
|
+
{items.length === 0 && (
|
|
78
|
+
<span className="text-[11px] italic text-[var(--text-muted)]">
|
|
79
|
+
{emptyLabel}
|
|
80
|
+
</span>
|
|
81
|
+
)}
|
|
82
|
+
</div>
|
|
83
|
+
</ContextSection>
|
|
84
|
+
);
|
|
85
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ContextEditor — shared, controlled context editor dialog.
|
|
3
|
+
*
|
|
4
|
+
* Edits a system prompt plus tool/skill enablement and saved presets, against
|
|
5
|
+
* an `available` context. Host-agnostic: the consumer supplies the available
|
|
6
|
+
* context, the current overrides, the preset list, and the persistence
|
|
7
|
+
* callbacks. Used by the desktop chat session editor and by app modules (e.g.
|
|
8
|
+
* the Orchestrator loop context override).
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { useState } from 'react';
|
|
12
|
+
import { AlertCircle, Loader2, Settings2 } from 'lucide-react';
|
|
13
|
+
import type { AvailableContext, ContextOverrides, ContextPreset } from '@sero-ai/common';
|
|
14
|
+
import {
|
|
15
|
+
Dialog,
|
|
16
|
+
DialogContent,
|
|
17
|
+
DialogDescription,
|
|
18
|
+
DialogFooter,
|
|
19
|
+
DialogHeader,
|
|
20
|
+
DialogTitle,
|
|
21
|
+
} from '../ui/dialog';
|
|
22
|
+
import { ScrollArea } from '../ui/scroll-area';
|
|
23
|
+
import { PresetBar } from './PresetBar';
|
|
24
|
+
import { SkillsSection } from './SkillsSection';
|
|
25
|
+
import { SystemPromptSection, type SystemPromptCopy } from './SystemPromptSection';
|
|
26
|
+
import { ToolsSection } from './ToolsSection';
|
|
27
|
+
import { useContextEditorModel, type ContextPresetBody } from './use-context-editor-model';
|
|
28
|
+
|
|
29
|
+
export interface ContextEditorProps {
|
|
30
|
+
open: boolean;
|
|
31
|
+
onOpenChange: (open: boolean) => void;
|
|
32
|
+
available: AvailableContext | null;
|
|
33
|
+
initialOverrides: ContextOverrides | null;
|
|
34
|
+
presets: ContextPreset[];
|
|
35
|
+
/** Persist the chosen overrides. Return false to keep the dialog open (error). */
|
|
36
|
+
onApply: (overrides: ContextOverrides | null) => Promise<boolean> | boolean;
|
|
37
|
+
onSavePreset: (name: string, preset: ContextPresetBody) => void;
|
|
38
|
+
onDeletePreset: (id: string) => void;
|
|
39
|
+
applyError?: string | null;
|
|
40
|
+
title?: string;
|
|
41
|
+
description?: string;
|
|
42
|
+
systemPromptCopy?: SystemPromptCopy;
|
|
43
|
+
applyLabel?: string;
|
|
44
|
+
/** Hide the Tools section (e.g. the Orchestrator picks tools per step, not per loop). */
|
|
45
|
+
hideTools?: boolean;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function ContextEditor({
|
|
49
|
+
open,
|
|
50
|
+
onOpenChange,
|
|
51
|
+
available,
|
|
52
|
+
initialOverrides,
|
|
53
|
+
presets,
|
|
54
|
+
onApply,
|
|
55
|
+
onSavePreset,
|
|
56
|
+
onDeletePreset,
|
|
57
|
+
applyError,
|
|
58
|
+
title = 'Context Editor',
|
|
59
|
+
description = 'Configure what is included in the LLM context.',
|
|
60
|
+
systemPromptCopy,
|
|
61
|
+
applyLabel = 'Apply',
|
|
62
|
+
hideTools = false,
|
|
63
|
+
}: ContextEditorProps) {
|
|
64
|
+
const model = useContextEditorModel({ open, available, initialOverrides, presets, onSavePreset, onDeletePreset });
|
|
65
|
+
const [applying, setApplying] = useState(false);
|
|
66
|
+
|
|
67
|
+
const handleApply = async () => {
|
|
68
|
+
setApplying(true);
|
|
69
|
+
try {
|
|
70
|
+
const ok = await onApply(model.buildOverrides());
|
|
71
|
+
if (ok !== false) onOpenChange(false);
|
|
72
|
+
} finally {
|
|
73
|
+
setApplying(false);
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
return (
|
|
78
|
+
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
79
|
+
<DialogContent
|
|
80
|
+
className="max-h-[85vh] overflow-hidden bg-[var(--bg-surface)] sm:max-w-[58rem]"
|
|
81
|
+
showCloseButton
|
|
82
|
+
>
|
|
83
|
+
<DialogHeader>
|
|
84
|
+
<DialogTitle className="flex items-center gap-2 text-sm">
|
|
85
|
+
<Settings2 className="size-4 text-[var(--text-muted)]" />
|
|
86
|
+
{title}
|
|
87
|
+
</DialogTitle>
|
|
88
|
+
<DialogDescription className="text-xs">{description}</DialogDescription>
|
|
89
|
+
</DialogHeader>
|
|
90
|
+
|
|
91
|
+
<PresetBar {...model.preset} />
|
|
92
|
+
|
|
93
|
+
{!available ? (
|
|
94
|
+
<div className="flex items-center justify-center gap-2 py-8">
|
|
95
|
+
<Loader2 className="size-4 animate-spin text-[var(--text-muted)]" />
|
|
96
|
+
<span className="text-xs text-[var(--text-muted)]">Loading context…</span>
|
|
97
|
+
</div>
|
|
98
|
+
) : (
|
|
99
|
+
<ScrollArea className="max-h-[65vh] overflow-hidden">
|
|
100
|
+
<div className="min-w-0 space-y-2 pr-2">
|
|
101
|
+
<SystemPromptSection
|
|
102
|
+
displayedPrompt={model.displayedPrompt}
|
|
103
|
+
systemPrompt={model.systemPrompt}
|
|
104
|
+
onSystemPromptChange={model.setSystemPrompt}
|
|
105
|
+
copy={systemPromptCopy}
|
|
106
|
+
/>
|
|
107
|
+
{!hideTools && <ToolsSection {...model.tools} />}
|
|
108
|
+
<SkillsSection {...model.skills} />
|
|
109
|
+
</div>
|
|
110
|
+
</ScrollArea>
|
|
111
|
+
)}
|
|
112
|
+
|
|
113
|
+
{applyError && (
|
|
114
|
+
<div className="flex items-start gap-2 rounded-md border border-status-error-border bg-status-error-muted px-3 py-2">
|
|
115
|
+
<AlertCircle className="mt-0.5 size-3.5 shrink-0 text-status-error" />
|
|
116
|
+
<span className="text-[11px] text-status-error">{applyError}</span>
|
|
117
|
+
</div>
|
|
118
|
+
)}
|
|
119
|
+
|
|
120
|
+
<DialogFooter>
|
|
121
|
+
<button type="button"
|
|
122
|
+
onClick={() => onOpenChange(false)}
|
|
123
|
+
className="rounded-md border border-border/50 px-3 py-1.5 text-xs text-[var(--text-secondary)] transition-colors hover:bg-[var(--bg-elevated)]"
|
|
124
|
+
>
|
|
125
|
+
Cancel
|
|
126
|
+
</button>
|
|
127
|
+
<button type="button"
|
|
128
|
+
onClick={() => { void handleApply(); }}
|
|
129
|
+
disabled={!available || applying}
|
|
130
|
+
className="rounded-md bg-[var(--accent-primary)] px-3 py-1.5 text-xs font-medium text-white transition-colors hover:bg-[var(--accent-hover)] disabled:opacity-50"
|
|
131
|
+
>
|
|
132
|
+
{applyLabel}
|
|
133
|
+
</button>
|
|
134
|
+
</DialogFooter>
|
|
135
|
+
</DialogContent>
|
|
136
|
+
</Dialog>
|
|
137
|
+
);
|
|
138
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { RotateCcw, Save, Trash2 } from 'lucide-react';
|
|
2
|
+
import type { ContextPreset } from '@sero-ai/common';
|
|
3
|
+
import {
|
|
4
|
+
Select,
|
|
5
|
+
SelectContent,
|
|
6
|
+
SelectItem,
|
|
7
|
+
SelectTrigger,
|
|
8
|
+
SelectValue,
|
|
9
|
+
} from '../ui/select';
|
|
10
|
+
import { SavePresetInput } from './parts';
|
|
11
|
+
|
|
12
|
+
interface PresetBarProps {
|
|
13
|
+
allPresets: ContextPreset[];
|
|
14
|
+
activePresetId: string | null;
|
|
15
|
+
activeUserPreset: ContextPreset | null;
|
|
16
|
+
hasOverrides: boolean;
|
|
17
|
+
showSaveInput: boolean;
|
|
18
|
+
onPresetChange: (id: string) => void;
|
|
19
|
+
onDelete: (id: string) => void;
|
|
20
|
+
onReset: () => void;
|
|
21
|
+
onShowSave: () => void;
|
|
22
|
+
onSave: (name: string) => void;
|
|
23
|
+
onCancelSave: () => void;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function PresetBar({
|
|
27
|
+
allPresets,
|
|
28
|
+
activePresetId,
|
|
29
|
+
activeUserPreset,
|
|
30
|
+
hasOverrides,
|
|
31
|
+
showSaveInput,
|
|
32
|
+
onPresetChange,
|
|
33
|
+
onDelete,
|
|
34
|
+
onReset,
|
|
35
|
+
onShowSave,
|
|
36
|
+
onSave,
|
|
37
|
+
onCancelSave,
|
|
38
|
+
}: PresetBarProps) {
|
|
39
|
+
return (
|
|
40
|
+
<>
|
|
41
|
+
<div className="flex items-center gap-2">
|
|
42
|
+
<span className="text-[11px] font-medium text-[var(--text-muted)]">
|
|
43
|
+
Preset:
|
|
44
|
+
</span>
|
|
45
|
+
<Select value={activePresetId ?? ''} onValueChange={onPresetChange}>
|
|
46
|
+
<SelectTrigger size="sm" className="h-7 w-40 text-xs">
|
|
47
|
+
<SelectValue placeholder="Custom" />
|
|
48
|
+
</SelectTrigger>
|
|
49
|
+
<SelectContent>
|
|
50
|
+
{allPresets.map((preset) => (
|
|
51
|
+
<SelectItem key={preset.id} value={preset.id}>
|
|
52
|
+
{preset.name}
|
|
53
|
+
</SelectItem>
|
|
54
|
+
))}
|
|
55
|
+
</SelectContent>
|
|
56
|
+
</Select>
|
|
57
|
+
|
|
58
|
+
{activeUserPreset && (
|
|
59
|
+
<button type="button"
|
|
60
|
+
onClick={() => onDelete(activeUserPreset.id)}
|
|
61
|
+
className="flex items-center gap-1 rounded-md px-1.5 py-1 text-[var(--text-muted)] transition-colors hover:bg-status-error-muted hover:text-status-error"
|
|
62
|
+
title={`Delete "${activeUserPreset.name}"`}
|
|
63
|
+
>
|
|
64
|
+
<Trash2 className="size-3" />
|
|
65
|
+
</button>
|
|
66
|
+
)}
|
|
67
|
+
|
|
68
|
+
{!showSaveInput && (
|
|
69
|
+
<button type="button"
|
|
70
|
+
onClick={onShowSave}
|
|
71
|
+
className="flex items-center gap-1 rounded-md px-2 py-1 text-[11px] text-[var(--text-muted)] transition-colors hover:bg-[var(--bg-elevated)] hover:text-[var(--text-secondary)]"
|
|
72
|
+
>
|
|
73
|
+
<Save className="size-3" />
|
|
74
|
+
Save as
|
|
75
|
+
</button>
|
|
76
|
+
)}
|
|
77
|
+
|
|
78
|
+
{hasOverrides && (
|
|
79
|
+
<button type="button"
|
|
80
|
+
onClick={onReset}
|
|
81
|
+
className="ml-auto flex items-center gap-1 rounded-md px-2 py-1 text-[11px] text-[var(--text-muted)] transition-colors hover:bg-[var(--bg-elevated)] hover:text-[var(--text-secondary)]"
|
|
82
|
+
>
|
|
83
|
+
<RotateCcw className="size-3" />
|
|
84
|
+
Reset
|
|
85
|
+
</button>
|
|
86
|
+
)}
|
|
87
|
+
</div>
|
|
88
|
+
|
|
89
|
+
{showSaveInput && (
|
|
90
|
+
<SavePresetInput onSave={onSave} onCancel={onCancelSave} />
|
|
91
|
+
)}
|
|
92
|
+
</>
|
|
93
|
+
);
|
|
94
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Sparkles } from 'lucide-react';
|
|
2
|
+
import type { ContextSkillInfo } from '@sero-ai/common';
|
|
3
|
+
import { CapabilitySection } from './CapabilitySection';
|
|
4
|
+
|
|
5
|
+
interface SkillsSectionProps {
|
|
6
|
+
items: ContextSkillInfo[];
|
|
7
|
+
allDisabled: boolean;
|
|
8
|
+
enabledCount: number;
|
|
9
|
+
isEnabled: (name: string) => boolean;
|
|
10
|
+
onToggle: (name: string) => void;
|
|
11
|
+
onToggleAll: (disabled: boolean) => void;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function SkillsSection({
|
|
15
|
+
items,
|
|
16
|
+
allDisabled,
|
|
17
|
+
enabledCount,
|
|
18
|
+
isEnabled,
|
|
19
|
+
onToggle,
|
|
20
|
+
onToggleAll,
|
|
21
|
+
}: SkillsSectionProps) {
|
|
22
|
+
return (
|
|
23
|
+
<CapabilitySection
|
|
24
|
+
icon={Sparkles}
|
|
25
|
+
title="Skills"
|
|
26
|
+
tint="violet"
|
|
27
|
+
includeAllLabel="Include all skills"
|
|
28
|
+
emptyLabel="No skills available"
|
|
29
|
+
items={items}
|
|
30
|
+
allDisabled={allDisabled}
|
|
31
|
+
enabledCount={enabledCount}
|
|
32
|
+
isEnabled={isEnabled}
|
|
33
|
+
onToggle={onToggle}
|
|
34
|
+
onToggleAll={onToggleAll}
|
|
35
|
+
/>
|
|
36
|
+
);
|
|
37
|
+
}
|