@consciousclouds/operator-shell 0.1.0 → 0.2.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.
Files changed (93) hide show
  1. package/CHANGELOG.md +66 -0
  2. package/README.md +80 -31
  3. package/dist/chief/ChiefDrawer.d.ts +34 -2
  4. package/dist/chief/ChiefDrawer.d.ts.map +1 -1
  5. package/dist/chief/ChiefDrawer.js +43 -30
  6. package/dist/chief/ChiefDrawer.js.map +1 -1
  7. package/dist/chief/ChiefHeaderBar.d.ts +19 -0
  8. package/dist/chief/ChiefHeaderBar.d.ts.map +1 -0
  9. package/dist/chief/ChiefHeaderBar.js +7 -0
  10. package/dist/chief/ChiefHeaderBar.js.map +1 -0
  11. package/dist/chief/ChiefMarkdown.d.ts +12 -0
  12. package/dist/chief/ChiefMarkdown.d.ts.map +1 -0
  13. package/dist/chief/ChiefMarkdown.js +95 -0
  14. package/dist/chief/ChiefMarkdown.js.map +1 -0
  15. package/dist/chief/ChiefPanel.d.ts +44 -1
  16. package/dist/chief/ChiefPanel.d.ts.map +1 -1
  17. package/dist/chief/ChiefPanel.js +79 -29
  18. package/dist/chief/ChiefPanel.js.map +1 -1
  19. package/dist/chief/ChiefRegion.d.ts +44 -1
  20. package/dist/chief/ChiefRegion.d.ts.map +1 -1
  21. package/dist/chief/ChiefRegion.js +63 -27
  22. package/dist/chief/ChiefRegion.js.map +1 -1
  23. package/dist/chief/ChiefSession.d.ts +46 -10
  24. package/dist/chief/ChiefSession.d.ts.map +1 -1
  25. package/dist/chief/ChiefSession.js +252 -6
  26. package/dist/chief/ChiefSession.js.map +1 -1
  27. package/dist/chief/ChiefTrigger.d.ts +26 -0
  28. package/dist/chief/ChiefTrigger.d.ts.map +1 -0
  29. package/dist/chief/ChiefTrigger.js +21 -0
  30. package/dist/chief/ChiefTrigger.js.map +1 -0
  31. package/dist/chief/conversation-adapter.d.ts +70 -0
  32. package/dist/chief/conversation-adapter.d.ts.map +1 -0
  33. package/dist/chief/conversation-adapter.js +26 -0
  34. package/dist/chief/conversation-adapter.js.map +1 -0
  35. package/dist/chief/conversation-identity.d.ts +48 -0
  36. package/dist/chief/conversation-identity.d.ts.map +1 -0
  37. package/dist/chief/conversation-identity.js +100 -0
  38. package/dist/chief/conversation-identity.js.map +1 -0
  39. package/dist/chief/personality-display.d.ts +56 -0
  40. package/dist/chief/personality-display.d.ts.map +1 -0
  41. package/dist/chief/personality-display.js +52 -0
  42. package/dist/chief/personality-display.js.map +1 -0
  43. package/dist/chief/turn-adapter.d.ts +45 -0
  44. package/dist/chief/turn-adapter.d.ts.map +1 -1
  45. package/dist/chief/use-chief-turn.d.ts +127 -14
  46. package/dist/chief/use-chief-turn.d.ts.map +1 -1
  47. package/dist/chief/use-chief-turn.js +284 -28
  48. package/dist/chief/use-chief-turn.js.map +1 -1
  49. package/dist/chief/use-controlled-open.d.ts +2 -0
  50. package/dist/chief/use-controlled-open.d.ts.map +1 -0
  51. package/dist/chief/use-controlled-open.js +27 -0
  52. package/dist/chief/use-controlled-open.js.map +1 -0
  53. package/dist/chief/use-smooth-stream.d.ts +8 -0
  54. package/dist/chief/use-smooth-stream.d.ts.map +1 -0
  55. package/dist/chief/use-smooth-stream.js +128 -0
  56. package/dist/chief/use-smooth-stream.js.map +1 -0
  57. package/dist/flavor/types.d.ts +36 -21
  58. package/dist/flavor/types.d.ts.map +1 -1
  59. package/dist/frame/ComposedWorkspace.d.ts +39 -0
  60. package/dist/frame/ComposedWorkspace.d.ts.map +1 -0
  61. package/dist/frame/ComposedWorkspace.js +94 -0
  62. package/dist/frame/ComposedWorkspace.js.map +1 -0
  63. package/dist/frame/OperatorShell.d.ts +115 -13
  64. package/dist/frame/OperatorShell.d.ts.map +1 -1
  65. package/dist/frame/OperatorShell.js +200 -12
  66. package/dist/frame/OperatorShell.js.map +1 -1
  67. package/dist/guard/permissions.d.ts +2 -2
  68. package/dist/guard/permissions.js +2 -2
  69. package/dist/header/OperatorHeader.d.ts +15 -2
  70. package/dist/header/OperatorHeader.d.ts.map +1 -1
  71. package/dist/header/OperatorHeader.js +3 -3
  72. package/dist/header/OperatorHeader.js.map +1 -1
  73. package/dist/icons/registry.d.ts +7 -1
  74. package/dist/icons/registry.d.ts.map +1 -1
  75. package/dist/icons/registry.js +31 -2
  76. package/dist/icons/registry.js.map +1 -1
  77. package/dist/index.d.ts +24 -11
  78. package/dist/index.d.ts.map +1 -1
  79. package/dist/index.js +43 -17
  80. package/dist/index.js.map +1 -1
  81. package/dist/sidebar/OperatorSidebar.d.ts +16 -1
  82. package/dist/sidebar/OperatorSidebar.d.ts.map +1 -1
  83. package/dist/sidebar/OperatorSidebar.js +13 -10
  84. package/dist/sidebar/OperatorSidebar.js.map +1 -1
  85. package/dist/workspace/FormWorkspace.d.ts +2 -3
  86. package/dist/workspace/FormWorkspace.d.ts.map +1 -1
  87. package/dist/workspace/FormWorkspace.js.map +1 -1
  88. package/dist/workspace/session-adapter.d.ts +95 -0
  89. package/dist/workspace/session-adapter.d.ts.map +1 -0
  90. package/dist/workspace/session-adapter.js +29 -0
  91. package/dist/workspace/session-adapter.js.map +1 -0
  92. package/package.json +10 -5
  93. package/styles/source.css +9 -0
@@ -1,9 +1,255 @@
1
1
  "use client";
2
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { ArrowRight, Loader2 } from "lucide-react";
4
- import { Button, cn } from "@consciousclouds/ui";
5
- export function ChiefSession({ session, composerRef, className }) {
6
- const { title, placeholder, hint, hintExample, cmd, setCmd, busy, question, answer, meta, showThread, submit, } = session;
7
- return (_jsxs("div", { className: cn("flex min-h-0 flex-1 flex-col", className), children: [_jsxs("div", { className: "flex min-h-0 flex-1 flex-col gap-3 overflow-y-auto p-4", children: [!showThread && (_jsxs("p", { className: "text-xs text-muted-foreground/70", children: [hint, hintExample ? (_jsxs(_Fragment, { children: [" ", "(", _jsx("span", { className: "font-medium text-foreground/80", children: hintExample }), ")"] })) : null, ". Some commands move the surface directly, with zero model tokens."] })), showThread && (_jsxs("div", { className: "space-y-3", children: [_jsx("div", { className: "text-xs font-medium text-muted-foreground", children: question }), answer && (_jsxs("div", { className: "whitespace-pre-wrap rounded-lg border border-border bg-card px-3 py-2 text-sm leading-relaxed text-foreground", children: [answer, busy && _jsx("span", { className: "ml-0.5 inline-block animate-pulse", children: "\u258D" })] })), busy && !answer && (_jsxs("div", { className: "flex items-center gap-2 text-xs text-muted-foreground", children: [_jsx(Loader2, { className: "size-3.5 animate-spin" }), " ", title, " is thinking\u2026"] })), meta && (_jsx("div", { className: cn("rounded-md border px-3 py-2 text-xs", meta.kind === "routed" && "border-primary/30 bg-primary/5 text-foreground", meta.kind === "unavailable" && "border-border bg-muted/40 text-muted-foreground", meta.kind === "error" && "border-destructive/30 bg-destructive/5 text-destructive"), children: meta.text }))] }))] }), _jsx("form", { onSubmit: submit, className: "shrink-0 border-t border-border p-3", children: _jsxs("div", { className: "flex items-center gap-2 rounded-lg border border-border bg-card px-3 py-2 focus-within:ring-1 focus-within:ring-ring", children: [_jsx("input", { ref: composerRef, value: cmd, onChange: (e) => setCmd(e.target.value), placeholder: placeholder, className: "min-w-0 flex-1 bg-transparent text-sm outline-none placeholder:text-muted-foreground/60", "aria-label": `Command ${title}` }), _jsx(Button, { type: "submit", variant: "ghost", size: "icon-xs", disabled: busy || !cmd.trim(), className: "text-primary hover:text-primary", "aria-label": "Send", children: busy ? _jsx(Loader2, { className: "size-4 animate-spin" }) : _jsx(ArrowRight, { className: "size-4" }) })] }) })] }));
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ /**
4
+ * ChiefSession the AI Region's shared BODY: the empty state (hint card +
5
+ * suggestion chips), the thread (question · streamed markdown answer ·
6
+ * color-coded metadata bar), and the pill composer, rendered from a
7
+ * ChiefTurnSession. Pure presentation of the one turn flow every placement
8
+ * (rail, push, overlay) mounts this same column inside its own chrome, so
9
+ * moving Chief never forks its behavior or its look.
10
+ *
11
+ * Suggestion chips are inert Flavor strings (`flavor.chief.suggestions`);
12
+ * clicking one submits its text through `submitPrompt` — the SAME entry the
13
+ * composer uses, so a chip is a canned question, never a second code path.
14
+ *
15
+ * `composerRef` exposes the composer input to the mounting placement — ⌘J
16
+ * focus on the rail, focus-on-open in the dismissible placements;
17
+ * presentation only, no behavior lives here.
18
+ *
19
+ * MOTION (presentation only — the turn STATE and the adapter are untouched):
20
+ * the conversation is animated with the ConsciousClouds motion vocabulary
21
+ * (`@consciousclouds/tokens`' `motionTokens` — durations/curves/offsets, no
22
+ * inline magic numbers) through `motion/react`. The empty-state hint rises in
23
+ * and the suggestion chips STAGGER in gently; when the first turn starts the
24
+ * thread rises in (empty → active); inside the thread the "thinking…" state
25
+ * and the answer CROSSFADE (the leaving one lifts out as an absolute overlay,
26
+ * so nothing reflows) and the answer SETTLES to full size the instant
27
+ * streaming completes; the status line eases in. The token stream itself is
28
+ * never animated per-character (that fights the stream) — only the CONTAINER
29
+ * and the turn state are. Every gesture respects `prefers-reduced-motion`
30
+ * (`useReducedMotion`): reduced → instant, no transform, no fade.
31
+ */
32
+ import * as React from "react";
33
+ import { ArrowRight, Loader2, Sparkles } from "lucide-react";
34
+ import { AnimatePresence, motion } from "motion/react";
35
+ import { motionTokens } from "@consciousclouds/tokens";
36
+ import { Button, cn, useReducedMotion } from "@consciousclouds/ui";
37
+ import { ChiefMarkdown } from "./ChiefMarkdown.js";
38
+ import { useSmoothStream } from "./use-smooth-stream.js";
39
+ /**
40
+ * The stream-settle amplitude: while a turn streams, the answer bubble sits a
41
+ * hair under full size and eases to `1` the moment the stream completes (busy
42
+ * → done) — a sub-perceptual "lock-in". An amplitude only; the timing and
43
+ * curve of the settle come from the motion tokens (`duration.base` /
44
+ * `easing.standard`), never inlined.
45
+ */
46
+ const STREAM_SETTLE_SCALE = 0.995;
47
+ /** The metadata bar's color coding, shared by settled and live turns. */
48
+ function metaClasses(kind) {
49
+ return cn("rounded-md border px-3 py-2 text-xs", kind === "routed" && "border-primary/5 bg-primary/5 text-primary", kind === "unavailable" && "border-border bg-muted/40 text-muted-foreground", kind === "error" &&
50
+ "border-destructive/30 bg-destructive/5 text-destructive");
51
+ }
52
+ /** Compact relative recency for a thread row ("just now" · "5m" · "3h" · "2d"). */
53
+ function relativeRecency(iso) {
54
+ if (!iso)
55
+ return "";
56
+ const then = Date.parse(iso);
57
+ if (Number.isNaN(then))
58
+ return "";
59
+ const mins = Math.max(0, Math.round((Date.now() - then) / 60000));
60
+ if (mins < 1)
61
+ return "just now";
62
+ if (mins < 60)
63
+ return `${mins}m`;
64
+ const hours = Math.round(mins / 60);
65
+ if (hours < 24)
66
+ return `${hours}h`;
67
+ return `${Math.round(hours / 24)}d`;
68
+ }
69
+ /** The shared row style for the list tabs (Conversations / Workspaces). */
70
+ const listRowClasses = "w-full rounded-md border border-border/60 px-3 py-2 text-left text-[13px] text-foreground/80 transition-colors hover:bg-background/60 hover:text-foreground";
71
+ export function ChiefSession({ session, composerRef, accentColor, workspaces, className, }) {
72
+ const { title, placeholder, hint, hintExample, suggestions, cmd, setCmd, busy, turns, question, answer, meta, showThread, submit, submitPrompt, transcriptEnabled, conversations, activeConversationId, openConversation, newConversation, } = session;
73
+ // The drawer's view tabs. Rendered only when a beyond-the-thread surface exists
74
+ // (a transcript adapter and/or a workspaces region) — without either, the body
75
+ // is exactly the pre-tab thread column (fail-closed slots, zero change).
76
+ const [tab, setTab] = React.useState("conversation");
77
+ const showTabs = transcriptEnabled || Boolean(workspaces);
78
+ const activeTab = showTabs ? tab : "conversation";
79
+ // The composer stays visible on every tab (speaking is always one keystroke
80
+ // away), so submitting RETURNS to the Conversation tab — the answer must
81
+ // stream where the operator can see it, never into the hidden pane.
82
+ const submitAndShowThread = React.useCallback(async (e) => {
83
+ setTab("conversation");
84
+ await submit(e);
85
+ }, [submit]);
86
+ // The accessibility contract: reduced → every preset below is a no-op, so
87
+ // the render is instant (no transform, no fade). Defaults to reduced before
88
+ // hydration, so first paint never animates (the shared hook's safe default).
89
+ const reduced = useReducedMotion();
90
+ // Smooth streaming: the answer flows onto the screen at a paced, adaptive
91
+ // rate instead of chunking with the network's bursty deltas (the technique
92
+ // every polished chat UI uses). `displayed` is a catching-up prefix of the
93
+ // received `answer` (the LIVE — last — turn's; settled turns render their
94
+ // final text directly); `revealing` is true while it's still draining (the
95
+ // cursor rides + the bubble stays settled until the reveal finishes). Reduced
96
+ // motion → `displayed === answer` (the full answer paints at once).
97
+ const displayed = useSmoothStream(answer, { streaming: busy, reduced });
98
+ const revealing = displayed.length < answer.length;
99
+ // The settled thread — every exchange but the live one; those render their
100
+ // final text with no stream motion (they already animated when they were live).
101
+ const settled = turns.slice(0, -1);
102
+ // The live entry's render key — keys the live block so a NEW turn REPLACES it
103
+ // outright instead of crossfading out of it (the exit ghost belonged to the
104
+ // pre-thread replace model; under the append model the previous answer already
105
+ // stands in `settled`, so an exiting duplicate would double-render it).
106
+ const liveKey = turns.length > 0 ? turns[turns.length - 1].key : "live";
107
+ // Follow the stream — but only while the operator is AT the bottom: scrolling
108
+ // up to re-read a settled turn must never be yanked back by the reveal ticks.
109
+ // Submitting a new turn re-engages the pin (you return to your question).
110
+ // Instant (never smooth) — animated scrolling fights the token stream.
111
+ const scrollRef = React.useRef(null);
112
+ const stickRef = React.useRef(true);
113
+ const onThreadScroll = React.useCallback(() => {
114
+ const el = scrollRef.current;
115
+ if (el)
116
+ stickRef.current = el.scrollHeight - el.scrollTop - el.clientHeight < 48;
117
+ }, []);
118
+ React.useEffect(() => {
119
+ stickRef.current = true; // a new exchange re-engages follow (declared BEFORE the pin effect)
120
+ }, [turns.length]);
121
+ React.useEffect(() => {
122
+ // Returning to the thread re-engages follow and pins to the newest content:
123
+ // while the pane was display:none every pin was a spec no-op (no layout box),
124
+ // and the browser may fire a restoration scroll that would clear the stick —
125
+ // re-entering the tab means "show me the conversation now", so land at the end.
126
+ if (activeTab !== "conversation")
127
+ return;
128
+ stickRef.current = true;
129
+ const el = scrollRef.current;
130
+ if (el)
131
+ el.scrollTop = el.scrollHeight;
132
+ }, [activeTab]);
133
+ React.useEffect(() => {
134
+ const el = scrollRef.current;
135
+ if (el && stickRef.current)
136
+ el.scrollTop = el.scrollHeight;
137
+ }, [turns.length, displayed, busy]);
138
+ // The motion vocabulary — durations/curves/offsets from the tokens only.
139
+ const enterY = motionTokens.offset.enter.y;
140
+ const exitY = motionTokens.offset.exit.y;
141
+ const base = {
142
+ duration: motionTokens.duration.base,
143
+ ease: motionTokens.easing.standard,
144
+ };
145
+ const fast = {
146
+ duration: motionTokens.duration.fast,
147
+ ease: motionTokens.easing.standard,
148
+ };
149
+ // Empty state — the idle hint rises in; the chips stagger in one `fast` step
150
+ // apart (the harvested SDK ships no stagger, so this minimal, token-timed
151
+ // cascade lives here; see the return summary).
152
+ const hintMotion = reduced
153
+ ? {}
154
+ : {
155
+ initial: { opacity: 0, y: enterY },
156
+ animate: { opacity: 1, y: 0 },
157
+ transition: base,
158
+ };
159
+ const chipsListMotion = reduced
160
+ ? {}
161
+ : {
162
+ initial: "hidden",
163
+ animate: "show",
164
+ variants: {
165
+ hidden: {},
166
+ show: { transition: { staggerChildren: motionTokens.duration.fast } },
167
+ },
168
+ };
169
+ const chipMotion = reduced
170
+ ? {}
171
+ : {
172
+ variants: {
173
+ hidden: { opacity: 0, y: enterY },
174
+ show: { opacity: 1, y: 0, transition: base },
175
+ },
176
+ };
177
+ // Thread — the whole thread rises in when the first turn starts (empty →
178
+ // active). Inside it the thinking indicator and the answer crossfade: the
179
+ // leaving one lifts out (exit offset) as an ABSOLUTE overlay (the `relative`
180
+ // wrapper anchors it) so the answer rises into place with no reflow; the
181
+ // answer settles to full size when streaming ends; the status line eases in.
182
+ const threadMotion = reduced
183
+ ? {}
184
+ : {
185
+ initial: { opacity: 0, y: enterY },
186
+ animate: { opacity: 1, y: 0 },
187
+ transition: base,
188
+ };
189
+ const answerMotion = reduced
190
+ ? {}
191
+ : {
192
+ initial: { opacity: 0, y: enterY },
193
+ animate: {
194
+ opacity: 1,
195
+ y: 0,
196
+ scale: busy || revealing ? STREAM_SETTLE_SCALE : 1,
197
+ },
198
+ exit: { opacity: 0, y: exitY, position: "absolute" },
199
+ transition: base,
200
+ };
201
+ const thinkingMotion = reduced
202
+ ? {}
203
+ : {
204
+ initial: { opacity: 0, y: enterY },
205
+ animate: { opacity: 1, y: 0 },
206
+ exit: { opacity: 0, y: exitY, position: "absolute" },
207
+ transition: fast,
208
+ };
209
+ const metaMotion = reduced
210
+ ? {}
211
+ : {
212
+ initial: { opacity: 0, y: enterY },
213
+ animate: { opacity: 1, y: 0 },
214
+ transition: base,
215
+ };
216
+ return (_jsxs("div", { className: cn("flex min-h-0 flex-1 flex-col", className), children: [showTabs && (_jsx("div", { role: "tablist", "aria-label": `${title} views`, className: "flex shrink-0 items-center gap-1 border-b border-border/50 px-3 py-2", children: [
217
+ {
218
+ key: "conversation",
219
+ label: "Conversation",
220
+ present: true,
221
+ },
222
+ {
223
+ key: "conversations",
224
+ label: "Conversations",
225
+ present: transcriptEnabled,
226
+ },
227
+ {
228
+ key: "workspaces",
229
+ label: "Workspaces",
230
+ present: Boolean(workspaces),
231
+ },
232
+ ]
233
+ .filter((t) => t.present)
234
+ .map((t) => (_jsx("button", { type: "button", role: "tab", "aria-selected": activeTab === t.key, onClick: () => setTab(t.key), className: cn("rounded-md px-2.5 py-1 text-xs font-medium transition-colors", activeTab === t.key
235
+ ? "bg-background/80 text-foreground"
236
+ : "text-muted-foreground hover:bg-background/50 hover:text-foreground"), children: t.label }, t.key))) })), activeTab === "conversations" && (_jsxs("div", { className: "flex min-h-0 flex-1 flex-col gap-1.5 overflow-y-auto p-4", role: "tabpanel", children: [_jsx("button", { type: "button", onClick: () => {
237
+ newConversation();
238
+ setTab("conversation");
239
+ }, className: cn(listRowClasses, "border-dashed text-center font-medium"), children: "+ New conversation" }), conversations.length === 0 ? (_jsxs("p", { className: "px-1 pt-2 text-xs text-muted-foreground", children: ["No conversations yet \u2014 ask ", title, " something and the thread becomes durable."] })) : (conversations.map((c) => {
240
+ const active = c.conversationId === activeConversationId;
241
+ return (_jsxs("button", { type: "button", onClick: () => {
242
+ openConversation(c.conversationId);
243
+ setTab("conversation");
244
+ }, className: cn(listRowClasses, active && "border-primary/30 bg-primary/5"), children: [_jsxs("span", { className: "block truncate font-medium text-foreground/90", children: ["Conversation ", c.conversationId.slice(0, 8), active ? " · active" : ""] }), _jsxs("span", { className: "block text-xs text-muted-foreground", children: [typeof c.records === "number"
245
+ ? `${c.records} messages`
246
+ : "—", c.lastActivity
247
+ ? ` · ${relativeRecency(c.lastActivity)}`
248
+ : ""] })] }, c.conversationId));
249
+ }))] })), activeTab === "workspaces" && workspaces && (_jsx("div", { className: "flex min-h-0 flex-1 flex-col gap-1.5 overflow-y-auto p-4", role: "tabpanel", children: workspaces.items.length === 0 ? (_jsx("p", { className: "px-1 pt-2 text-xs text-muted-foreground", children: "No kept workspaces yet \u2014 compose one and keep it by name." })) : (workspaces.items.map((w) => (_jsx("button", { type: "button", onClick: () => {
250
+ workspaces.onOpen(w.workspaceId);
251
+ setTab("conversation");
252
+ }, className: cn(listRowClasses, w.workspaceId === workspaces.activeId &&
253
+ "border-primary/30 bg-primary/5"), children: _jsx("span", { className: "block truncate", children: w.name }) }, w.workspaceId)))) })), _jsxs("div", { ref: scrollRef, onScroll: onThreadScroll, className: cn("flex min-h-0 flex-1 flex-col gap-3 overflow-y-auto p-4", activeTab !== "conversation" && "hidden"), children: [!showThread && (_jsxs(_Fragment, { children: [_jsx(motion.div, { ...hintMotion, className: "rounded-lg bg-background/60 p-3", children: _jsxs("p", { className: "text-[13px] leading-relaxed text-foreground/80", children: [hint, hintExample ? (_jsxs(_Fragment, { children: [" ", "(", _jsx("span", { className: "font-medium text-foreground", children: hintExample }), ")"] })) : null, ". Some commands move the surface directly, with zero model tokens."] }) }), suggestions.length > 0 && (_jsx(motion.div, { ...chipsListMotion, className: "flex flex-col gap-1.5", children: suggestions.map((suggestion) => (_jsx(motion.button, { ...chipMotion, type: "button", disabled: busy, onClick: () => void submitPrompt(suggestion), className: "rounded-md border border-border/60 px-3 py-2 text-left text-[13px] text-foreground/80 transition-colors hover:bg-background/60 hover:text-foreground disabled:pointer-events-none disabled:opacity-50", children: suggestion }, suggestion))) }))] })), showThread && (_jsxs(motion.div, { ...threadMotion, className: "space-y-4", children: [settled.map((t) => (_jsxs("div", { className: "space-y-3", children: [_jsx("div", { className: "text-xs font-medium text-muted-foreground", children: t.question }), t.answer ? (_jsx("div", { className: "rounded-lg bg-background/60 px-3 py-2 text-sm leading-relaxed text-foreground", children: _jsx(ChiefMarkdown, { children: t.answer }) })) : null, t.meta ? (_jsx("div", { className: metaClasses(t.meta.kind), children: t.meta.text })) : null] }, t.key))), _jsxs("div", { className: "relative space-y-3", children: [_jsx("div", { className: "text-xs font-medium text-muted-foreground", children: question }), _jsx(AnimatePresence, { initial: false, children: displayed ? (_jsx(motion.div, { ...answerMotion, className: "rounded-lg bg-background/60 px-3 py-2 text-sm leading-relaxed text-foreground", children: _jsx(ChiefMarkdown, { streaming: busy || revealing, wordFade: busy || revealing, children: displayed }) }, "answer")) : busy ? (_jsxs(motion.div, { ...thinkingMotion, className: "flex items-center gap-2 text-xs text-muted-foreground", children: [_jsx(Loader2, { className: "size-3.5 animate-spin" }), " ", title, " is thinking\u2026"] }, "thinking")) : null }), _jsx(AnimatePresence, { initial: false, children: meta && (_jsx(motion.div, { ...metaMotion, className: metaClasses(meta.kind), children: meta.text }, meta.kind)) })] }, liveKey)] }))] }), _jsx("form", { onSubmit: submitAndShowThread, className: "shrink-0 border-t border-border/50 p-3", children: _jsxs("div", { className: "flex items-center gap-2 rounded-full bg-background/60 px-3 py-2 focus-within:ring-1 focus-within:ring-ring/40", children: [_jsx(Sparkles, { "aria-hidden": true, className: "size-3.5 shrink-0 text-muted-foreground", style: accentColor ? { color: accentColor } : undefined }), _jsx("input", { ref: composerRef, value: cmd, onChange: (e) => setCmd(e.target.value), placeholder: placeholder, className: "min-w-0 flex-1 bg-transparent text-sm outline-none placeholder:text-muted-foreground", "aria-label": `Command ${title}` }), _jsx(Button, { type: "submit", variant: "ghost", size: "icon-xs", disabled: busy || !cmd.trim(), className: "rounded-full text-primary hover:text-primary", "aria-label": "Send", children: busy ? (_jsx(Loader2, { className: "size-4 animate-spin" })) : (_jsx(ArrowRight, { className: "size-4" })) })] }) })] }));
8
254
  }
9
255
  //# sourceMappingURL=ChiefSession.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ChiefSession.js","sourceRoot":"","sources":["../../src/chief/ChiefSession.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAeb,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEnD,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,qBAAqB,CAAC;AAWjD,MAAM,UAAU,YAAY,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,SAAS,EAAqB;IACjF,MAAM,EACJ,KAAK,EACL,WAAW,EACX,IAAI,EACJ,WAAW,EACX,GAAG,EACH,MAAM,EACN,IAAI,EACJ,QAAQ,EACR,MAAM,EACN,IAAI,EACJ,UAAU,EACV,MAAM,GACP,GAAG,OAAO,CAAC;IAEZ,OAAO,CACL,eAAK,SAAS,EAAE,EAAE,CAAC,8BAA8B,EAAE,SAAS,CAAC,aAC3D,eAAK,SAAS,EAAC,wDAAwD,aACpE,CAAC,UAAU,IAAI,CACd,aAAG,SAAS,EAAC,kCAAkC,aAC5C,IAAI,EACJ,WAAW,CAAC,CAAC,CAAC,CACb,8BACG,GAAG,OACH,eAAM,SAAS,EAAC,gCAAgC,YAAE,WAAW,GAAQ,SACrE,CACJ,CAAC,CAAC,CAAC,IAAI,0EAEN,CACL,EAEA,UAAU,IAAI,CACb,eAAK,SAAS,EAAC,WAAW,aACxB,cAAK,SAAS,EAAC,2CAA2C,YAAE,QAAQ,GAAO,EAE1E,MAAM,IAAI,CACT,eAAK,SAAS,EAAC,+GAA+G,aAC3H,MAAM,EACN,IAAI,IAAI,eAAM,SAAS,EAAC,mCAAmC,uBAAS,IACjE,CACP,EAEA,IAAI,IAAI,CAAC,MAAM,IAAI,CAClB,eAAK,SAAS,EAAC,uDAAuD,aACpE,KAAC,OAAO,IAAC,SAAS,EAAC,uBAAuB,GAAG,OAAE,KAAK,0BAChD,CACP,EAEA,IAAI,IAAI,CACP,cACE,SAAS,EAAE,EAAE,CACX,qCAAqC,EACrC,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,gDAAgD,EAC1E,IAAI,CAAC,IAAI,KAAK,aAAa,IAAI,iDAAiD,EAChF,IAAI,CAAC,IAAI,KAAK,OAAO,IAAI,yDAAyD,CACnF,YAEA,IAAI,CAAC,IAAI,GACN,CACP,IACG,CACP,IACG,EAEN,eAAM,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAC,qCAAqC,YACrE,eAAK,SAAS,EAAC,sHAAsH,aACnI,gBACE,GAAG,EAAE,WAAW,EAChB,KAAK,EAAE,GAAG,EACV,QAAQ,EAAE,CAAC,CAAsC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAC5E,WAAW,EAAE,WAAW,EACxB,SAAS,EAAC,yFAAyF,gBACvF,WAAW,KAAK,EAAE,GAC9B,EACF,KAAC,MAAM,IACL,IAAI,EAAC,QAAQ,EACb,OAAO,EAAC,OAAO,EACf,IAAI,EAAC,SAAS,EACd,QAAQ,EAAE,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,EAC7B,SAAS,EAAC,iCAAiC,gBAChC,MAAM,YAEhB,IAAI,CAAC,CAAC,CAAC,KAAC,OAAO,IAAC,SAAS,EAAC,qBAAqB,GAAG,CAAC,CAAC,CAAC,KAAC,UAAU,IAAC,SAAS,EAAC,QAAQ,GAAG,GAChF,IACL,GACD,IACH,CACP,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"ChiefSession.js","sourceRoot":"","sources":["../../src/chief/ChiefSession.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,EAAoB,MAAM,cAAc,CAAC;AAEzE,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAEnE,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEzD;;;;;;GAMG;AACH,MAAM,mBAAmB,GAAG,KAAK,CAAC;AA4BlC,yEAAyE;AACzE,SAAS,WAAW,CAAC,IAAwC;IAC3D,OAAO,EAAE,CACP,qCAAqC,EACrC,IAAI,KAAK,QAAQ,IAAI,4CAA4C,EACjE,IAAI,KAAK,aAAa,IAAI,iDAAiD,EAC3E,IAAI,KAAK,OAAO;QACd,yDAAyD,CAC5D,CAAC;AACJ,CAAC;AAED,mFAAmF;AACnF,SAAS,eAAe,CAAC,GAAY;IACnC,IAAI,CAAC,GAAG;QAAE,OAAO,EAAE,CAAC;IACpB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC7B,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC;IAClC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,KAAM,CAAC,CAAC,CAAC;IACnE,IAAI,IAAI,GAAG,CAAC;QAAE,OAAO,UAAU,CAAC;IAChC,IAAI,IAAI,GAAG,EAAE;QAAE,OAAO,GAAG,IAAI,GAAG,CAAC;IACjC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC;IACpC,IAAI,KAAK,GAAG,EAAE;QAAE,OAAO,GAAG,KAAK,GAAG,CAAC;IACnC,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,EAAE,CAAC,GAAG,CAAC;AACtC,CAAC;AAED,2EAA2E;AAC3E,MAAM,cAAc,GAClB,6JAA6J,CAAC;AAEhK,MAAM,UAAU,YAAY,CAAC,EAC3B,OAAO,EACP,WAAW,EACX,WAAW,EACX,UAAU,EACV,SAAS,GACS;IAClB,MAAM,EACJ,KAAK,EACL,WAAW,EACX,IAAI,EACJ,WAAW,EACX,WAAW,EACX,GAAG,EACH,MAAM,EACN,IAAI,EACJ,KAAK,EACL,QAAQ,EACR,MAAM,EACN,IAAI,EACJ,UAAU,EACV,MAAM,EACN,YAAY,EACZ,iBAAiB,EACjB,aAAa,EACb,oBAAoB,EACpB,gBAAgB,EAChB,eAAe,GAChB,GAAG,OAAO,CAAC;IAEZ,gFAAgF;IAChF,+EAA+E;IAC/E,yEAAyE;IACzE,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAW,cAAc,CAAC,CAAC;IAC/D,MAAM,QAAQ,GAAG,iBAAiB,IAAI,OAAO,CAAC,UAAU,CAAC,CAAC;IAC1D,MAAM,SAAS,GAAa,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,cAAc,CAAC;IAE5D,4EAA4E;IAC5E,yEAAyE;IACzE,oEAAoE;IACpE,MAAM,mBAAmB,GAAG,KAAK,CAAC,WAAW,CAC3C,KAAK,EAAE,CAAkB,EAAE,EAAE;QAC3B,MAAM,CAAC,cAAc,CAAC,CAAC;QACvB,MAAM,MAAM,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,EACD,CAAC,MAAM,CAAC,CACT,CAAC;IAEF,0EAA0E;IAC1E,4EAA4E;IAC5E,6EAA6E;IAC7E,MAAM,OAAO,GAAG,gBAAgB,EAAE,CAAC;IAEnC,0EAA0E;IAC1E,2EAA2E;IAC3E,2EAA2E;IAC3E,0EAA0E;IAC1E,2EAA2E;IAC3E,8EAA8E;IAC9E,oEAAoE;IACpE,MAAM,SAAS,GAAG,eAAe,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;IACxE,MAAM,SAAS,GAAG,SAAS,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;IAEnD,2EAA2E;IAC3E,gFAAgF;IAChF,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACnC,8EAA8E;IAC9E,4EAA4E;IAC5E,+EAA+E;IAC/E,wEAAwE;IACxE,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAE,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC;IAEzE,8EAA8E;IAC9E,8EAA8E;IAC9E,0EAA0E;IAC1E,uEAAuE;IACvE,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,CAAwB,IAAI,CAAC,CAAC;IAC5D,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACpC,MAAM,cAAc,GAAG,KAAK,CAAC,WAAW,CAAC,GAAG,EAAE;QAC5C,MAAM,EAAE,GAAG,SAAS,CAAC,OAAO,CAAC;QAC7B,IAAI,EAAE;YACJ,QAAQ,CAAC,OAAO,GAAG,EAAE,CAAC,YAAY,GAAG,EAAE,CAAC,SAAS,GAAG,EAAE,CAAC,YAAY,GAAG,EAAE,CAAC;IAC7E,CAAC,EAAE,EAAE,CAAC,CAAC;IACP,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACnB,QAAQ,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC,oEAAoE;IAC/F,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;IACnB,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACnB,4EAA4E;QAC5E,8EAA8E;QAC9E,6EAA6E;QAC7E,gFAAgF;QAChF,IAAI,SAAS,KAAK,cAAc;YAAE,OAAO;QACzC,QAAQ,CAAC,OAAO,GAAG,IAAI,CAAC;QACxB,MAAM,EAAE,GAAG,SAAS,CAAC,OAAO,CAAC;QAC7B,IAAI,EAAE;YAAE,EAAE,CAAC,SAAS,GAAG,EAAE,CAAC,YAAY,CAAC;IACzC,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC;IAChB,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACnB,MAAM,EAAE,GAAG,SAAS,CAAC,OAAO,CAAC;QAC7B,IAAI,EAAE,IAAI,QAAQ,CAAC,OAAO;YAAE,EAAE,CAAC,SAAS,GAAG,EAAE,CAAC,YAAY,CAAC;IAC7D,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;IAEpC,yEAAyE;IACzE,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IAC3C,MAAM,KAAK,GAAG,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;IACzC,MAAM,IAAI,GAAG;QACX,QAAQ,EAAE,YAAY,CAAC,QAAQ,CAAC,IAAI;QACpC,IAAI,EAAE,YAAY,CAAC,MAAM,CAAC,QAAQ;KACnC,CAAC;IACF,MAAM,IAAI,GAAG;QACX,QAAQ,EAAE,YAAY,CAAC,QAAQ,CAAC,IAAI;QACpC,IAAI,EAAE,YAAY,CAAC,MAAM,CAAC,QAAQ;KACnC,CAAC;IAEF,6EAA6E;IAC7E,0EAA0E;IAC1E,+CAA+C;IAC/C,MAAM,UAAU,GAAgB,OAAO;QACrC,CAAC,CAAC,EAAE;QACJ,CAAC,CAAC;YACE,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE;YAClC,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;YAC7B,UAAU,EAAE,IAAI;SACjB,CAAC;IACN,MAAM,eAAe,GAAgB,OAAO;QAC1C,CAAC,CAAC,EAAE;QACJ,CAAC,CAAC;YACE,OAAO,EAAE,QAAQ;YACjB,OAAO,EAAE,MAAM;YACf,QAAQ,EAAE;gBACR,MAAM,EAAE,EAAE;gBACV,IAAI,EAAE,EAAE,UAAU,EAAE,EAAE,eAAe,EAAE,YAAY,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE;aACtE;SACF,CAAC;IACN,MAAM,UAAU,GAAgB,OAAO;QACrC,CAAC,CAAC,EAAE;QACJ,CAAC,CAAC;YACE,QAAQ,EAAE;gBACR,MAAM,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE;gBACjC,IAAI,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE;aAC7C;SACF,CAAC;IAEN,yEAAyE;IACzE,0EAA0E;IAC1E,6EAA6E;IAC7E,yEAAyE;IACzE,6EAA6E;IAC7E,MAAM,YAAY,GAAgB,OAAO;QACvC,CAAC,CAAC,EAAE;QACJ,CAAC,CAAC;YACE,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE;YAClC,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;YAC7B,UAAU,EAAE,IAAI;SACjB,CAAC;IACN,MAAM,YAAY,GAAgB,OAAO;QACvC,CAAC,CAAC,EAAE;QACJ,CAAC,CAAC;YACE,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE;YAClC,OAAO,EAAE;gBACP,OAAO,EAAE,CAAC;gBACV,CAAC,EAAE,CAAC;gBACJ,KAAK,EAAE,IAAI,IAAI,SAAS,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC;aACnD;YACD,IAAI,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE;YACpD,UAAU,EAAE,IAAI;SACjB,CAAC;IACN,MAAM,cAAc,GAAgB,OAAO;QACzC,CAAC,CAAC,EAAE;QACJ,CAAC,CAAC;YACE,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE;YAClC,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;YAC7B,IAAI,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE;YACpD,UAAU,EAAE,IAAI;SACjB,CAAC;IACN,MAAM,UAAU,GAAgB,OAAO;QACrC,CAAC,CAAC,EAAE;QACJ,CAAC,CAAC;YACE,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE;YAClC,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;YAC7B,UAAU,EAAE,IAAI;SACjB,CAAC;IAEN,OAAO,CACL,eAAK,SAAS,EAAE,EAAE,CAAC,8BAA8B,EAAE,SAAS,CAAC,aAG1D,QAAQ,IAAI,CACX,cACE,IAAI,EAAC,SAAS,gBACF,GAAG,KAAK,QAAQ,EAC5B,SAAS,EAAC,sEAAsE,YAG9E;oBACE;wBACE,GAAG,EAAE,cAA0B;wBAC/B,KAAK,EAAE,cAAc;wBACrB,OAAO,EAAE,IAAI;qBACd;oBACD;wBACE,GAAG,EAAE,eAA2B;wBAChC,KAAK,EAAE,eAAe;wBACtB,OAAO,EAAE,iBAAiB;qBAC3B;oBACD;wBACE,GAAG,EAAE,YAAwB;wBAC7B,KAAK,EAAE,YAAY;wBACnB,OAAO,EAAE,OAAO,CAAC,UAAU,CAAC;qBAC7B;iBAEJ;qBACE,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;qBACxB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CACV,iBAEE,IAAI,EAAC,QAAQ,EACb,IAAI,EAAC,KAAK,mBACK,SAAS,KAAK,CAAC,CAAC,GAAG,EAClC,OAAO,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAC5B,SAAS,EAAE,EAAE,CACX,8DAA8D,EAC9D,SAAS,KAAK,CAAC,CAAC,GAAG;wBACjB,CAAC,CAAC,kCAAkC;wBACpC,CAAC,CAAC,oEAAoE,CACzE,YAEA,CAAC,CAAC,KAAK,IAZH,CAAC,CAAC,GAAG,CAaH,CACV,CAAC,GACA,CACP,EAEA,SAAS,KAAK,eAAe,IAAI,CAChC,eACE,SAAS,EAAC,0DAA0D,EACpE,IAAI,EAAC,UAAU,aAGf,iBACE,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,GAAG,EAAE;4BACZ,eAAe,EAAE,CAAC;4BAClB,MAAM,CAAC,cAAc,CAAC,CAAC;wBACzB,CAAC,EACD,SAAS,EAAE,EAAE,CACX,cAAc,EACd,uCAAuC,CACxC,mCAGM,EACR,aAAa,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAC5B,aAAG,SAAS,EAAC,yCAAyC,iDACxB,KAAK,kDAE/B,CACL,CAAC,CAAC,CAAC,CACF,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;wBACtB,MAAM,MAAM,GAAG,CAAC,CAAC,cAAc,KAAK,oBAAoB,CAAC;wBACzD,OAAO,CACL,kBAEE,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,GAAG,EAAE;gCACZ,gBAAgB,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC;gCACnC,MAAM,CAAC,cAAc,CAAC,CAAC;4BACzB,CAAC,EACD,SAAS,EAAE,EAAE,CACX,cAAc,EACd,MAAM,IAAI,gCAAgC,CAC3C,aAED,gBAAM,SAAS,EAAC,+CAA+C,8BAC/C,CAAC,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EACzC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,IACrB,EACP,gBAAM,SAAS,EAAC,qCAAqC,aAClD,OAAO,CAAC,CAAC,OAAO,KAAK,QAAQ;4CAC5B,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,WAAW;4CACzB,CAAC,CAAC,GAAG,EACN,CAAC,CAAC,YAAY;4CACb,CAAC,CAAC,MAAM,eAAe,CAAC,CAAC,CAAC,YAAY,CAAC,EAAE;4CACzC,CAAC,CAAC,EAAE,IACD,KAtBF,CAAC,CAAC,cAAc,CAuBd,CACV,CAAC;oBACJ,CAAC,CAAC,CACH,IACG,CACP,EAEA,SAAS,KAAK,YAAY,IAAI,UAAU,IAAI,CAC3C,cACE,SAAS,EAAC,0DAA0D,EACpE,IAAI,EAAC,UAAU,YAEd,UAAU,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAC/B,YAAG,SAAS,EAAC,yCAAyC,+EAElD,CACL,CAAC,CAAC,CAAC,CACF,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAC1B,iBAEE,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,GAAG,EAAE;wBACZ,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;wBACjC,MAAM,CAAC,cAAc,CAAC,CAAC;oBACzB,CAAC,EACD,SAAS,EAAE,EAAE,CACX,cAAc,EACd,CAAC,CAAC,WAAW,KAAK,UAAU,CAAC,QAAQ;wBACnC,gCAAgC,CACnC,YAED,eAAM,SAAS,EAAC,gBAAgB,YAAE,CAAC,CAAC,IAAI,GAAQ,IAZ3C,CAAC,CAAC,WAAW,CAaX,CACV,CAAC,CACH,GACG,CACP,EAED,eACE,GAAG,EAAE,SAAS,EACd,QAAQ,EAAE,cAAc,EACxB,SAAS,EAAE,EAAE,CACX,wDAAwD,EACxD,SAAS,KAAK,cAAc,IAAI,QAAQ,CACzC,aAEA,CAAC,UAAU,IAAI,CACd,8BAEE,KAAC,MAAM,CAAC,GAAG,OACL,UAAU,EACd,SAAS,EAAC,iCAAiC,YAE3C,aAAG,SAAS,EAAC,gDAAgD,aAC1D,IAAI,EACJ,WAAW,CAAC,CAAC,CAAC,CACb,8BACG,GAAG,OAEJ,eAAM,SAAS,EAAC,6BAA6B,YAC1C,WAAW,GACP,SAEN,CACJ,CAAC,CAAC,CAAC,IAAI,0EAGN,GACO,EAIZ,WAAW,CAAC,MAAM,GAAG,CAAC,IAAI,CACzB,KAAC,MAAM,CAAC,GAAG,OACL,eAAe,EACnB,SAAS,EAAC,uBAAuB,YAEhC,WAAW,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,CAC/B,KAAC,MAAM,CAAC,MAAM,OAER,UAAU,EACd,IAAI,EAAC,QAAQ,EACb,QAAQ,EAAE,IAAI,EACd,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK,YAAY,CAAC,UAAU,CAAC,EAC5C,SAAS,EAAC,uMAAuM,YAEhN,UAAU,IAPN,UAAU,CAQD,CACjB,CAAC,GACS,CACd,IACA,CACJ,EAEA,UAAU,IAAI,CACb,MAAC,MAAM,CAAC,GAAG,OAAK,YAAY,EAAE,SAAS,EAAC,WAAW,aAIhD,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAClB,eAAiB,SAAS,EAAC,WAAW,aACpC,cAAK,SAAS,EAAC,2CAA2C,YACvD,CAAC,CAAC,QAAQ,GACP,EACL,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CACV,cAAK,SAAS,EAAC,+EAA+E,YAC5F,KAAC,aAAa,cAAE,CAAC,CAAC,MAAM,GAAiB,GACrC,CACP,CAAC,CAAC,CAAC,IAAI,EACP,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CACR,cAAK,SAAS,EAAE,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,YAAG,CAAC,CAAC,IAAI,CAAC,IAAI,GAAO,CAC9D,CAAC,CAAC,CAAC,IAAI,KAXA,CAAC,CAAC,GAAG,CAYT,CACP,CAAC,EAGF,eAAmB,SAAS,EAAC,oBAAoB,aAC/C,cAAK,SAAS,EAAC,2CAA2C,YACvD,QAAQ,GACL,EAIN,KAAC,eAAe,IAAC,OAAO,EAAE,KAAK,YAC5B,SAAS,CAAC,CAAC,CAAC,CACX,KAAC,MAAM,CAAC,GAAG,OAEL,YAAY,EAChB,SAAS,EAAC,+EAA+E,YAOzF,KAAC,aAAa,IACZ,SAAS,EAAE,IAAI,IAAI,SAAS,EAC5B,QAAQ,EAAE,IAAI,IAAI,SAAS,YAE1B,SAAS,GACI,IAdZ,QAAQ,CAeD,CACd,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CACT,MAAC,MAAM,CAAC,GAAG,OAEL,cAAc,EAClB,SAAS,EAAC,uDAAuD,aAEjE,KAAC,OAAO,IAAC,SAAS,EAAC,uBAAuB,GAAG,OAAE,KAAK,2BAJhD,UAAU,CAMH,CACd,CAAC,CAAC,CAAC,IAAI,GACQ,EAIlB,KAAC,eAAe,IAAC,OAAO,EAAE,KAAK,YAC5B,IAAI,IAAI,CACP,KAAC,MAAM,CAAC,GAAG,OAEL,UAAU,EACd,SAAS,EAAE,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,YAEhC,IAAI,CAAC,IAAI,IAJL,IAAI,CAAC,IAAI,CAKH,CACd,GACe,KAlDV,OAAO,CAmDX,IACK,CACd,IACG,EAGN,eACE,QAAQ,EAAE,mBAAmB,EAC7B,SAAS,EAAC,wCAAwC,YAElD,eAAK,SAAS,EAAC,+GAA+G,aAC5H,KAAC,QAAQ,yBAEP,SAAS,EAAC,yCAAyC,EACnD,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,SAAS,GACvD,EACF,gBACE,GAAG,EAAE,WAAW,EAChB,KAAK,EAAE,GAAG,EACV,QAAQ,EAAE,CAAC,CAAsC,EAAE,EAAE,CACnD,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAExB,WAAW,EAAE,WAAW,EACxB,SAAS,EAAC,sFAAsF,gBACpF,WAAW,KAAK,EAAE,GAC9B,EACF,KAAC,MAAM,IACL,IAAI,EAAC,QAAQ,EACb,OAAO,EAAC,OAAO,EACf,IAAI,EAAC,SAAS,EACd,QAAQ,EAAE,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,EAC7B,SAAS,EAAC,8CAA8C,gBAC7C,MAAM,YAEhB,IAAI,CAAC,CAAC,CAAC,CACN,KAAC,OAAO,IAAC,SAAS,EAAC,qBAAqB,GAAG,CAC5C,CAAC,CAAC,CAAC,CACF,KAAC,UAAU,IAAC,SAAS,EAAC,QAAQ,GAAG,CAClC,GACM,IACL,GACD,IACH,CACP,CAAC;AACJ,CAAC"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * ChiefTrigger — the AI Region's header trigger: a pill button carrying the
3
+ * personality's icon + display name that summons/dismisses the Chief panel
4
+ * (the click twin of ⌘J). The frame mounts it in the header by default; a
5
+ * custom composition root may mount it anywhere and hand its element to the
6
+ * panel via `getTriggerElement` (outside-click exclusion + focus return).
7
+ *
8
+ * Icon and accent arrive RESOLVED (registry component + token-role color) —
9
+ * references resolve upstream, raw values never enter here.
10
+ */
11
+ import * as React from "react";
12
+ import type { LucideIcon } from "lucide-react";
13
+ export interface ChiefTriggerProps {
14
+ /** The panel's current open state (drives aria-expanded + the active tint). */
15
+ open: boolean;
16
+ /** Summon/dismiss — the same open state ⌘J and the panel's dismissals drive. */
17
+ onToggle: () => void;
18
+ /** The personality display name (the D-Q2 precedence, resolved upstream). */
19
+ label: string;
20
+ icon: LucideIcon;
21
+ /** Composable CSS color from a token ROLE (resolvePersonalityAccent). */
22
+ accentColor?: string;
23
+ className?: string;
24
+ }
25
+ export declare const ChiefTrigger: React.ForwardRefExoticComponent<ChiefTriggerProps & React.RefAttributes<HTMLButtonElement>>;
26
+ //# sourceMappingURL=ChiefTrigger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChiefTrigger.d.ts","sourceRoot":"","sources":["../../src/chief/ChiefTrigger.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;GASG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAM/C,MAAM,WAAW,iBAAiB;IAChC,+EAA+E;IAC/E,IAAI,EAAE,OAAO,CAAC;IACd,gFAAgF;IAChF,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,6EAA6E;IAC7E,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,UAAU,CAAC;IACjB,yEAAyE;IACzE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,YAAY,6FA4BxB,CAAC"}
@@ -0,0 +1,21 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ /**
4
+ * ChiefTrigger — the AI Region's header trigger: a pill button carrying the
5
+ * personality's icon + display name that summons/dismisses the Chief panel
6
+ * (the click twin of ⌘J). The frame mounts it in the header by default; a
7
+ * custom composition root may mount it anywhere and hand its element to the
8
+ * panel via `getTriggerElement` (outside-click exclusion + focus return).
9
+ *
10
+ * Icon and accent arrive RESOLVED (registry component + token-role color) —
11
+ * references resolve upstream, raw values never enter here.
12
+ */
13
+ import * as React from "react";
14
+ import { cn } from "@consciousclouds/ui";
15
+ import { CHIEF_SHORTCUT_LABEL } from "./use-chief-shortcut.js";
16
+ export const ChiefTrigger = React.forwardRef(function ChiefTrigger({ open, onToggle, label, icon: Icon, accentColor, className }, ref) {
17
+ return (_jsxs("button", { ref: ref, type: "button", onClick: onToggle, "aria-haspopup": "dialog", "aria-expanded": open, "aria-label": `${open ? "Close" : "Open"} ${label}`, title: `${label} — ${CHIEF_SHORTCUT_LABEL}`, className: cn("flex h-8 items-center gap-1.5 rounded-full px-2.5 text-[13px] font-medium transition-colors", open
18
+ ? "bg-primary/10 text-primary hover:bg-primary/15"
19
+ : "text-muted-foreground hover:bg-muted hover:text-foreground", className), children: [_jsx(Icon, { "aria-hidden": true, className: "size-3.5 shrink-0", style: accentColor ? { color: accentColor } : undefined }), _jsx("span", { className: "hidden sm:inline", children: label })] }));
20
+ });
21
+ //# sourceMappingURL=ChiefTrigger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChiefTrigger.js","sourceRoot":"","sources":["../../src/chief/ChiefTrigger.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb;;;;;;;;;GASG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,OAAO,EAAE,EAAE,EAAE,MAAM,qBAAqB,CAAC;AAEzC,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAe/D,MAAM,CAAC,MAAM,YAAY,GAAG,KAAK,CAAC,UAAU,CAC1C,SAAS,YAAY,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,SAAS,EAAE,EAAE,GAAG;IACtF,OAAO,CACL,kBACE,GAAG,EAAE,GAAG,EACR,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,QAAQ,mBACH,QAAQ,mBACP,IAAI,gBACP,GAAG,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,IAAI,KAAK,EAAE,EACjD,KAAK,EAAE,GAAG,KAAK,MAAM,oBAAoB,EAAE,EAC3C,SAAS,EAAE,EAAE,CACX,6FAA6F,EAC7F,IAAI;YACF,CAAC,CAAC,gDAAgD;YAClD,CAAC,CAAC,4DAA4D,EAChE,SAAS,CACV,aAED,KAAC,IAAI,yBAEH,SAAS,EAAC,mBAAmB,EAC7B,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,SAAS,GACvD,EACF,eAAM,SAAS,EAAC,kBAAkB,YAAE,KAAK,GAAQ,IAC1C,CACV,CAAC;AACJ,CAAC,CACF,CAAC"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * ConversationAdapter — the conversation TRANSCRIPT transport seam (Session
3
+ * Binder consumption slice), the read dual of TurnAdapter.
4
+ *
5
+ * THE SHELL OWNS THE THREAD; THE PRODUCT OWNS THE WIRE — the same injection
6
+ * contract as TurnAdapter (P1-1) and SessionAdapter. The shell ships the
7
+ * drawer's Conversations tab, thread hydration on restore/adoption, and the
8
+ * new-conversation gesture; it does NOT ship transport. The product implements
9
+ * and injects this adapter; its BFF routes, gateway URL, and credentials
10
+ * posture stay in the product. No adapter → no tabs, no hydration — the live
11
+ * turn flow stands alone (fail-closed slot, like every shell seam).
12
+ *
13
+ * STORAGE-AGNOSTIC BY CONTRACT (docs/design/session-binder.md, "the shell's
14
+ * read contract"): `listTurns` returns TURNS — {turnId, prompt, answer,
15
+ * outcome, composed?, createdAt} — never storage records. Whatever grammar the
16
+ * product's store speaks (Memory Tier-0 records, anything later), the ADAPTER
17
+ * folds it into turns; the shell renders turns and knows nothing of records.
18
+ *
19
+ * READS ARE GOVERNED, NEVER TRUSTED CLIENT STATE: the wire behind a real
20
+ * adapter re-authorizes every read (Control Plane `conversation.view` + the
21
+ * attested operator sub scoping rows server-side), so the adapter can only
22
+ * ever surface the operator's OWN transcripts. The conversation id names a
23
+ * thread; it is never authority.
24
+ */
25
+ /** One thread of the operator's transcript, for the Conversations tab. */
26
+ export interface ConversationThreadSummary {
27
+ conversationId: string;
28
+ /** ISO timestamp of the thread's most recent record, for recency display. */
29
+ lastActivity?: string;
30
+ /** How many records the thread holds (a message ≈ half a turn). */
31
+ records?: number;
32
+ }
33
+ /**
34
+ * The assistant record's RAW outcome, as the runtime recorded it:
35
+ * `routed` (deterministic navigation, carries `target`) · `error` (carries
36
+ * `code`) · `none`/absent (a plain answered turn).
37
+ */
38
+ export interface ConversationTurnOutcome {
39
+ kind: string;
40
+ target?: string;
41
+ code?: string;
42
+ }
43
+ /**
44
+ * One TURN of a conversation, CHRONOLOGICAL (oldest first) — the locked
45
+ * storage-agnostic read shape (session-binder.md). `turnId` is the canonical
46
+ * conductor id (the durable transcript and the screen share one name).
47
+ */
48
+ export interface ConversationTurn {
49
+ /** The canonical conductor turn id. */
50
+ turnId?: string;
51
+ /** The operator's question. */
52
+ prompt: string;
53
+ /** The final assistant answer (markdown; empty for a routed/failed turn). */
54
+ answer: string;
55
+ /** The turn's recorded outcome (routed target / error code / none). */
56
+ outcome?: ConversationTurnOutcome;
57
+ /** The composed-workspace marker, when the turn composed one. */
58
+ composed?: {
59
+ composer?: string;
60
+ intent?: string;
61
+ };
62
+ /** ISO timestamp of the turn's first record. */
63
+ createdAt?: string;
64
+ }
65
+ /** The injected transcript transport: list the operator's threads; read one thread as TURNS. */
66
+ export interface ConversationAdapter {
67
+ listConversations(): Promise<ConversationThreadSummary[]>;
68
+ listTurns(conversationId: string): Promise<ConversationTurn[]>;
69
+ }
70
+ //# sourceMappingURL=conversation-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conversation-adapter.d.ts","sourceRoot":"","sources":["../../src/chief/conversation-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,0EAA0E;AAC1E,MAAM,WAAW,yBAAyB;IACxC,cAAc,EAAE,MAAM,CAAC;IACvB,6EAA6E;IAC7E,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,mEAAmE;IACnE,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,+BAA+B;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,6EAA6E;IAC7E,MAAM,EAAE,MAAM,CAAC;IACf,uEAAuE;IACvE,OAAO,CAAC,EAAE,uBAAuB,CAAC;IAClC,iEAAiE;IACjE,QAAQ,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAClD,gDAAgD;IAChD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,gGAAgG;AAChG,MAAM,WAAW,mBAAmB;IAClC,iBAAiB,IAAI,OAAO,CAAC,yBAAyB,EAAE,CAAC,CAAC;IAC1D,SAAS,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC;CAChE"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * ConversationAdapter — the conversation TRANSCRIPT transport seam (Session
3
+ * Binder consumption slice), the read dual of TurnAdapter.
4
+ *
5
+ * THE SHELL OWNS THE THREAD; THE PRODUCT OWNS THE WIRE — the same injection
6
+ * contract as TurnAdapter (P1-1) and SessionAdapter. The shell ships the
7
+ * drawer's Conversations tab, thread hydration on restore/adoption, and the
8
+ * new-conversation gesture; it does NOT ship transport. The product implements
9
+ * and injects this adapter; its BFF routes, gateway URL, and credentials
10
+ * posture stay in the product. No adapter → no tabs, no hydration — the live
11
+ * turn flow stands alone (fail-closed slot, like every shell seam).
12
+ *
13
+ * STORAGE-AGNOSTIC BY CONTRACT (docs/design/session-binder.md, "the shell's
14
+ * read contract"): `listTurns` returns TURNS — {turnId, prompt, answer,
15
+ * outcome, composed?, createdAt} — never storage records. Whatever grammar the
16
+ * product's store speaks (Memory Tier-0 records, anything later), the ADAPTER
17
+ * folds it into turns; the shell renders turns and knows nothing of records.
18
+ *
19
+ * READS ARE GOVERNED, NEVER TRUSTED CLIENT STATE: the wire behind a real
20
+ * adapter re-authorizes every read (Control Plane `conversation.view` + the
21
+ * attested operator sub scoping rows server-side), so the adapter can only
22
+ * ever surface the operator's OWN transcripts. The conversation id names a
23
+ * thread; it is never authority.
24
+ */
25
+ export {};
26
+ //# sourceMappingURL=conversation-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conversation-adapter.js","sourceRoot":"","sources":["../../src/chief/conversation-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Conversation identity — the shell-owned MINT-OR-ADOPT seam (Session Binder
3
+ * slice 2a; docs/design/session-binder.md).
4
+ *
5
+ * The shell owns the conversation surface, so the shell owns the identity of
6
+ * the conversation it renders: ONE durable conversation id per personality,
7
+ * minted on first use, persisted in localStorage so a hard refresh continues
8
+ * the same thread, and ADOPTED (replaced) when the operator opens a kept
9
+ * Workspace Session that names its owning conversation — "a conversation owns
10
+ * a workspace" (Canvas OS §4), so opening the workspace rejoins its
11
+ * conversation.
12
+ *
13
+ * A CORRELATION REFERENCE ONLY — never authority. It rides the turn wire
14
+ * verbatim (`conversation_id`, the contract's inert thread-grouping key) and
15
+ * composition provenance; the conductor records turns under it, and every
16
+ * durable read is re-authorized server-side against the verified operator —
17
+ * a fabricated id can never read anyone else's thread.
18
+ *
19
+ * Storage failures (private mode, disabled storage) degrade to an EPHEMERAL
20
+ * per-mount id — the turn flow never breaks because persistence is unavailable.
21
+ */
22
+ /**
23
+ * The storage key for a personality's conversation identity. Keyed by the
24
+ * Flavor's inert personality REFERENCE so distinct personalities on one origin
25
+ * keep distinct threads; products on their own origins are isolated anyway.
26
+ */
27
+ export declare function conversationStorageKey(personalityRef?: string): string;
28
+ /**
29
+ * Restore the persisted conversation id, or mint-and-persist a fresh one.
30
+ * SSR-safe: on the server this returns "" (no conversation exists outside a
31
+ * browser); the client render mints/restores the real id. The id is never
32
+ * rendered into markup, so the difference cannot cause a hydration mismatch.
33
+ */
34
+ export declare function getOrMintConversationId(storageKey: string): string;
35
+ /**
36
+ * Adopt an existing conversation id (opening a kept Workspace Session rejoins
37
+ * the conversation that owns it): persist it and broadcast to live hooks in
38
+ * this tab. Empty ids are ignored — a record that predates conversation
39
+ * identity must not erase the current thread.
40
+ */
41
+ export declare function adoptConversationId(storageKey: string, id: string): void;
42
+ /**
43
+ * Subscribe to conversation-identity changes for a storage key: same-tab
44
+ * adoptions (the custom event) and cross-tab changes (the `storage` event).
45
+ * Returns the unsubscribe.
46
+ */
47
+ export declare function subscribeConversationId(storageKey: string, onChange: (id: string) => void): () => void;
48
+ //# sourceMappingURL=conversation-identity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conversation-identity.d.ts","sourceRoot":"","sources":["../../src/chief/conversation-identity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAYH;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,MAAM,CAEtE;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAelE;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAUxE;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,GAC7B,MAAM,IAAI,CAeZ"}
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Conversation identity — the shell-owned MINT-OR-ADOPT seam (Session Binder
3
+ * slice 2a; docs/design/session-binder.md).
4
+ *
5
+ * The shell owns the conversation surface, so the shell owns the identity of
6
+ * the conversation it renders: ONE durable conversation id per personality,
7
+ * minted on first use, persisted in localStorage so a hard refresh continues
8
+ * the same thread, and ADOPTED (replaced) when the operator opens a kept
9
+ * Workspace Session that names its owning conversation — "a conversation owns
10
+ * a workspace" (Canvas OS §4), so opening the workspace rejoins its
11
+ * conversation.
12
+ *
13
+ * A CORRELATION REFERENCE ONLY — never authority. It rides the turn wire
14
+ * verbatim (`conversation_id`, the contract's inert thread-grouping key) and
15
+ * composition provenance; the conductor records turns under it, and every
16
+ * durable read is re-authorized server-side against the verified operator —
17
+ * a fabricated id can never read anyone else's thread.
18
+ *
19
+ * Storage failures (private mode, disabled storage) degrade to an EPHEMERAL
20
+ * per-mount id — the turn flow never breaks because persistence is unavailable.
21
+ */
22
+ const STORAGE_PREFIX = "cc.chief.conversation:";
23
+ /** Same-tab adoption broadcast (the `storage` event only fires cross-tab). */
24
+ const ADOPT_EVENT = "cc:chief-conversation-adopted";
25
+ /**
26
+ * The storage key for a personality's conversation identity. Keyed by the
27
+ * Flavor's inert personality REFERENCE so distinct personalities on one origin
28
+ * keep distinct threads; products on their own origins are isolated anyway.
29
+ */
30
+ export function conversationStorageKey(personalityRef) {
31
+ return `${STORAGE_PREFIX}${personalityRef ?? "default"}`;
32
+ }
33
+ /**
34
+ * Restore the persisted conversation id, or mint-and-persist a fresh one.
35
+ * SSR-safe: on the server this returns "" (no conversation exists outside a
36
+ * browser); the client render mints/restores the real id. The id is never
37
+ * rendered into markup, so the difference cannot cause a hydration mismatch.
38
+ */
39
+ export function getOrMintConversationId(storageKey) {
40
+ if (typeof window === "undefined")
41
+ return "";
42
+ try {
43
+ const existing = window.localStorage.getItem(storageKey);
44
+ if (existing)
45
+ return existing;
46
+ }
47
+ catch {
48
+ /* storage unavailable — fall through to an ephemeral mint */
49
+ }
50
+ const minted = crypto.randomUUID();
51
+ try {
52
+ window.localStorage.setItem(storageKey, minted);
53
+ }
54
+ catch {
55
+ /* unpersisted mint: the conversation lives for this mount only */
56
+ }
57
+ return minted;
58
+ }
59
+ /**
60
+ * Adopt an existing conversation id (opening a kept Workspace Session rejoins
61
+ * the conversation that owns it): persist it and broadcast to live hooks in
62
+ * this tab. Empty ids are ignored — a record that predates conversation
63
+ * identity must not erase the current thread.
64
+ */
65
+ export function adoptConversationId(storageKey, id) {
66
+ if (typeof window === "undefined" || !id)
67
+ return;
68
+ try {
69
+ window.localStorage.setItem(storageKey, id);
70
+ }
71
+ catch {
72
+ /* adoption still applies in-memory via the broadcast below */
73
+ }
74
+ window.dispatchEvent(new CustomEvent(ADOPT_EVENT, { detail: { storageKey, id } }));
75
+ }
76
+ /**
77
+ * Subscribe to conversation-identity changes for a storage key: same-tab
78
+ * adoptions (the custom event) and cross-tab changes (the `storage` event).
79
+ * Returns the unsubscribe.
80
+ */
81
+ export function subscribeConversationId(storageKey, onChange) {
82
+ if (typeof window === "undefined")
83
+ return () => { };
84
+ const onAdopt = (e) => {
85
+ const detail = e.detail;
86
+ if (detail?.storageKey === storageKey && detail.id)
87
+ onChange(detail.id);
88
+ };
89
+ const onStorage = (e) => {
90
+ if (e.key === storageKey && e.newValue)
91
+ onChange(e.newValue);
92
+ };
93
+ window.addEventListener(ADOPT_EVENT, onAdopt);
94
+ window.addEventListener("storage", onStorage);
95
+ return () => {
96
+ window.removeEventListener(ADOPT_EVENT, onAdopt);
97
+ window.removeEventListener("storage", onStorage);
98
+ };
99
+ }
100
+ //# sourceMappingURL=conversation-identity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conversation-identity.js","sourceRoot":"","sources":["../../src/chief/conversation-identity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,MAAM,cAAc,GAAG,wBAAwB,CAAC;AAEhD,8EAA8E;AAC9E,MAAM,WAAW,GAAG,+BAA+B,CAAC;AAOpD;;;;GAIG;AACH,MAAM,UAAU,sBAAsB,CAAC,cAAuB;IAC5D,OAAO,GAAG,cAAc,GAAG,cAAc,IAAI,SAAS,EAAE,CAAC;AAC3D,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CAAC,UAAkB;IACxD,IAAI,OAAO,MAAM,KAAK,WAAW;QAAE,OAAO,EAAE,CAAC;IAC7C,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QACzD,IAAI,QAAQ;YAAE,OAAO,QAAQ,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,6DAA6D;IAC/D,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,CAAC,UAAU,EAAE,CAAC;IACnC,IAAI,CAAC;QACH,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;IAClD,CAAC;IAAC,MAAM,CAAC;QACP,kEAAkE;IACpE,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,UAAkB,EAAE,EAAU;IAChE,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,CAAC,EAAE;QAAE,OAAO;IACjD,IAAI,CAAC;QACH,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IAC9C,CAAC;IAAC,MAAM,CAAC;QACP,8DAA8D;IAChE,CAAC;IACD,MAAM,CAAC,aAAa,CAClB,IAAI,WAAW,CAAc,WAAW,EAAE,EAAE,MAAM,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,EAAE,CAAC,CAC1E,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,uBAAuB,CACrC,UAAkB,EAClB,QAA8B;IAE9B,IAAI,OAAO,MAAM,KAAK,WAAW;QAAE,OAAO,GAAG,EAAE,GAAE,CAAC,CAAC;IACnD,MAAM,OAAO,GAAG,CAAC,CAAQ,EAAE,EAAE;QAC3B,MAAM,MAAM,GAAI,CAA8B,CAAC,MAAM,CAAC;QACtD,IAAI,MAAM,EAAE,UAAU,KAAK,UAAU,IAAI,MAAM,CAAC,EAAE;YAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC1E,CAAC,CAAC;IACF,MAAM,SAAS,GAAG,CAAC,CAAe,EAAE,EAAE;QACpC,IAAI,CAAC,CAAC,GAAG,KAAK,UAAU,IAAI,CAAC,CAAC,QAAQ;YAAE,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;IAC/D,CAAC,CAAC;IACF,MAAM,CAAC,gBAAgB,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IAC9C,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;IAC9C,OAAO,GAAG,EAAE;QACV,MAAM,CAAC,mBAAmB,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QACjD,MAAM,CAAC,mBAAmB,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;IACnD,CAAC,CAAC;AACJ,CAAC"}