@radnine/storybook-addon-claude 0.5.1 → 0.5.3
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/dist/manager.js +359 -304
- package/package.json +1 -1
package/dist/manager.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/manager.js
|
|
2
|
-
import
|
|
2
|
+
import React9 from "react";
|
|
3
3
|
import { addons, types, useStorybookState as useStorybookState2 } from "storybook/manager-api";
|
|
4
4
|
|
|
5
5
|
// src/constants.js
|
|
@@ -18,111 +18,14 @@ var CONNECTION_STATES = {
|
|
|
18
18
|
};
|
|
19
19
|
|
|
20
20
|
// src/Panel.jsx
|
|
21
|
-
import
|
|
21
|
+
import React5, { useCallback as useCallback3 } from "react";
|
|
22
22
|
import { useAddonState } from "storybook/manager-api";
|
|
23
23
|
|
|
24
|
-
// src/components/ConnectionStatus.jsx
|
|
25
|
-
import React from "react";
|
|
26
|
-
var STATUS_CONFIG = {
|
|
27
|
-
[CONNECTION_STATES.CONNECTED]: {
|
|
28
|
-
label: "Connected",
|
|
29
|
-
color: "#4caf50"
|
|
30
|
-
},
|
|
31
|
-
[CONNECTION_STATES.CONNECTING]: {
|
|
32
|
-
label: "Connecting...",
|
|
33
|
-
color: "#ff9800"
|
|
34
|
-
},
|
|
35
|
-
[CONNECTION_STATES.RECONNECTING]: {
|
|
36
|
-
label: "Reconnecting...",
|
|
37
|
-
color: "#ff9800"
|
|
38
|
-
},
|
|
39
|
-
[CONNECTION_STATES.DISCONNECTED]: {
|
|
40
|
-
label: "Disconnected",
|
|
41
|
-
color: "#f44336"
|
|
42
|
-
}
|
|
43
|
-
};
|
|
44
|
-
function ConnectionStatus({ state, sessionId, onDisconnect, onNewChat, isProcessing }) {
|
|
45
|
-
const config = STATUS_CONFIG[state] || STATUS_CONFIG[CONNECTION_STATES.DISCONNECTED];
|
|
46
|
-
const isConnected = state === CONNECTION_STATES.CONNECTED;
|
|
47
|
-
return /* @__PURE__ */ React.createElement("div", { style: styles.container }, /* @__PURE__ */ React.createElement("div", { style: styles.indicator }, /* @__PURE__ */ React.createElement("span", { style: { ...styles.dot, backgroundColor: config.color } }), /* @__PURE__ */ React.createElement("span", { style: styles.label }, config.label)), /* @__PURE__ */ React.createElement("div", { style: styles.right }, sessionId && /* @__PURE__ */ React.createElement("span", { style: styles.sessionId, title: sessionId }, sessionId.slice(0, 8), "..."), onNewChat && isConnected && /* @__PURE__ */ React.createElement(
|
|
48
|
-
"button",
|
|
49
|
-
{
|
|
50
|
-
onClick: onNewChat,
|
|
51
|
-
disabled: isProcessing,
|
|
52
|
-
style: {
|
|
53
|
-
...styles.actionButton,
|
|
54
|
-
...isProcessing ? styles.actionButtonDisabled : {}
|
|
55
|
-
},
|
|
56
|
-
title: "Clear chat and start fresh session",
|
|
57
|
-
"aria-label": "New Chat"
|
|
58
|
-
},
|
|
59
|
-
"New Chat"
|
|
60
|
-
), onDisconnect && /* @__PURE__ */ React.createElement(
|
|
61
|
-
"button",
|
|
62
|
-
{
|
|
63
|
-
onClick: onDisconnect,
|
|
64
|
-
style: styles.actionButton,
|
|
65
|
-
title: isConnected ? "Disconnect" : "Change Token",
|
|
66
|
-
"aria-label": isConnected ? "Disconnect" : "Change Token"
|
|
67
|
-
},
|
|
68
|
-
isConnected ? "Disconnect" : "Change Token"
|
|
69
|
-
)));
|
|
70
|
-
}
|
|
71
|
-
var styles = {
|
|
72
|
-
container: {
|
|
73
|
-
display: "flex",
|
|
74
|
-
alignItems: "center",
|
|
75
|
-
justifyContent: "space-between",
|
|
76
|
-
padding: "6px 12px",
|
|
77
|
-
borderBottom: "1px solid rgba(0,0,0,0.1)",
|
|
78
|
-
fontSize: "12px",
|
|
79
|
-
fontFamily: "inherit"
|
|
80
|
-
},
|
|
81
|
-
indicator: {
|
|
82
|
-
display: "flex",
|
|
83
|
-
alignItems: "center",
|
|
84
|
-
gap: "6px"
|
|
85
|
-
},
|
|
86
|
-
dot: {
|
|
87
|
-
width: "8px",
|
|
88
|
-
height: "8px",
|
|
89
|
-
borderRadius: "50%",
|
|
90
|
-
display: "inline-block"
|
|
91
|
-
},
|
|
92
|
-
label: {
|
|
93
|
-
color: "#666"
|
|
94
|
-
},
|
|
95
|
-
right: {
|
|
96
|
-
display: "flex",
|
|
97
|
-
alignItems: "center",
|
|
98
|
-
gap: "8px"
|
|
99
|
-
},
|
|
100
|
-
sessionId: {
|
|
101
|
-
color: "#999",
|
|
102
|
-
fontFamily: "monospace",
|
|
103
|
-
fontSize: "11px"
|
|
104
|
-
},
|
|
105
|
-
actionButton: {
|
|
106
|
-
padding: "2px 8px",
|
|
107
|
-
border: "1px solid #ccc",
|
|
108
|
-
borderRadius: "4px",
|
|
109
|
-
backgroundColor: "transparent",
|
|
110
|
-
color: "#666",
|
|
111
|
-
fontSize: "11px",
|
|
112
|
-
cursor: "pointer",
|
|
113
|
-
lineHeight: "1.4"
|
|
114
|
-
},
|
|
115
|
-
actionButtonDisabled: {
|
|
116
|
-
opacity: 0.4,
|
|
117
|
-
cursor: "default"
|
|
118
|
-
}
|
|
119
|
-
};
|
|
120
|
-
|
|
121
24
|
// src/components/MessageList.jsx
|
|
122
|
-
import
|
|
25
|
+
import React2, { useEffect, useRef } from "react";
|
|
123
26
|
|
|
124
27
|
// src/components/MarkdownContent.jsx
|
|
125
|
-
import
|
|
28
|
+
import React, { useMemo } from "react";
|
|
126
29
|
import { marked } from "marked";
|
|
127
30
|
var renderer = new marked.Renderer();
|
|
128
31
|
renderer.link = function({ href, title, text }) {
|
|
@@ -173,7 +76,7 @@ function MarkdownContent({ text }) {
|
|
|
173
76
|
if (!text) return "";
|
|
174
77
|
return marked.parse(text);
|
|
175
78
|
}, [text]);
|
|
176
|
-
return /* @__PURE__ */
|
|
79
|
+
return /* @__PURE__ */ React.createElement(
|
|
177
80
|
"div",
|
|
178
81
|
{
|
|
179
82
|
className: "claude-md",
|
|
@@ -183,56 +86,58 @@ function MarkdownContent({ text }) {
|
|
|
183
86
|
}
|
|
184
87
|
|
|
185
88
|
// src/components/MessageList.jsx
|
|
186
|
-
function MessageList({ messages }) {
|
|
89
|
+
function MessageList({ messages, isProcessing }) {
|
|
187
90
|
const bottomRef = useRef(null);
|
|
188
91
|
useEffect(() => {
|
|
189
92
|
var _a;
|
|
190
93
|
(_a = bottomRef.current) == null ? void 0 : _a.scrollIntoView({ behavior: "smooth" });
|
|
191
|
-
}, [messages]);
|
|
94
|
+
}, [messages, isProcessing]);
|
|
192
95
|
if (messages.length === 0) {
|
|
193
|
-
return /* @__PURE__ */
|
|
96
|
+
return /* @__PURE__ */ React2.createElement("div", { style: styles.empty }, "No messages yet. Send a message to start chatting with Claude.");
|
|
194
97
|
}
|
|
195
|
-
return /* @__PURE__ */
|
|
98
|
+
return /* @__PURE__ */ React2.createElement("div", { style: styles.container }, messages.map((msg) => /* @__PURE__ */ React2.createElement(MessageItem, { key: msg.id, message: msg })), isProcessing && /* @__PURE__ */ React2.createElement(TypingIndicator, null), /* @__PURE__ */ React2.createElement("div", { ref: bottomRef }));
|
|
196
99
|
}
|
|
197
100
|
function MessageItem({ message }) {
|
|
198
101
|
switch (message.type) {
|
|
199
102
|
case "user_input":
|
|
200
|
-
return /* @__PURE__ */
|
|
103
|
+
return /* @__PURE__ */ React2.createElement(UserMessage, { text: message.text });
|
|
201
104
|
case "skill_invocation":
|
|
202
|
-
return /* @__PURE__ */
|
|
105
|
+
return /* @__PURE__ */ React2.createElement(SkillInvocationMessage, { skill: message.skill });
|
|
203
106
|
case "output":
|
|
204
|
-
return /* @__PURE__ */
|
|
107
|
+
return /* @__PURE__ */ React2.createElement(OutputMessage, { data: message.data, replay: message.replay });
|
|
205
108
|
case "complete":
|
|
206
|
-
return /* @__PURE__ */
|
|
109
|
+
return /* @__PURE__ */ React2.createElement(CompleteMessage, { message });
|
|
110
|
+
case "cancelled":
|
|
111
|
+
return /* @__PURE__ */ React2.createElement(CancelledMessage, null);
|
|
207
112
|
case "error":
|
|
208
|
-
return /* @__PURE__ */
|
|
113
|
+
return /* @__PURE__ */ React2.createElement(ErrorMessage, { message });
|
|
209
114
|
default:
|
|
210
115
|
return null;
|
|
211
116
|
}
|
|
212
117
|
}
|
|
213
118
|
function UserMessage({ text }) {
|
|
214
|
-
return /* @__PURE__ */
|
|
119
|
+
return /* @__PURE__ */ React2.createElement("div", { style: styles.userRow }, /* @__PURE__ */ React2.createElement("div", { style: styles.userBubble }, text));
|
|
215
120
|
}
|
|
216
121
|
function OutputMessage({ data, replay }) {
|
|
217
122
|
if (!data) return null;
|
|
218
123
|
const classifiedType = classifyOutputType(data);
|
|
219
124
|
switch (classifiedType) {
|
|
220
125
|
case "assistant":
|
|
221
|
-
return /* @__PURE__ */
|
|
126
|
+
return /* @__PURE__ */ React2.createElement(AssistantMessage, { data, replay });
|
|
222
127
|
case "tool_use":
|
|
223
|
-
return /* @__PURE__ */
|
|
128
|
+
return /* @__PURE__ */ React2.createElement(ToolUseMessage, { data });
|
|
224
129
|
case "tool_result":
|
|
225
|
-
return /* @__PURE__ */
|
|
130
|
+
return /* @__PURE__ */ React2.createElement(ToolResultMessage, { data });
|
|
226
131
|
case "result":
|
|
227
|
-
return /* @__PURE__ */
|
|
132
|
+
return /* @__PURE__ */ React2.createElement(ResultMessage, { data });
|
|
228
133
|
case "system":
|
|
229
|
-
return /* @__PURE__ */
|
|
134
|
+
return /* @__PURE__ */ React2.createElement(SystemMessage, { data });
|
|
230
135
|
case "rate_limit_event":
|
|
231
|
-
return /* @__PURE__ */
|
|
136
|
+
return /* @__PURE__ */ React2.createElement(RateLimitMessage, { data });
|
|
232
137
|
case "_skip":
|
|
233
138
|
return null;
|
|
234
139
|
default:
|
|
235
|
-
return /* @__PURE__ */
|
|
140
|
+
return /* @__PURE__ */ React2.createElement(GenericOutputMessage, { data, replay });
|
|
236
141
|
}
|
|
237
142
|
}
|
|
238
143
|
function classifyOutputType(data) {
|
|
@@ -268,31 +173,31 @@ function classifyOutputType(data) {
|
|
|
268
173
|
}
|
|
269
174
|
function AssistantMessage({ data, replay }) {
|
|
270
175
|
const text = extractAssistantText(data);
|
|
271
|
-
return /* @__PURE__ */
|
|
176
|
+
return /* @__PURE__ */ React2.createElement("div", { style: styles.assistantRow }, /* @__PURE__ */ React2.createElement("div", { style: { ...styles.assistantBubble, ...replay ? styles.replay : {} } }, text ? /* @__PURE__ */ React2.createElement(MarkdownContent, { text }) : "(empty response)"));
|
|
272
177
|
}
|
|
273
178
|
function ToolUseMessage({ data }) {
|
|
274
179
|
const toolName = extractToolName(data);
|
|
275
180
|
const summary = extractToolSummary(data);
|
|
276
|
-
return /* @__PURE__ */
|
|
181
|
+
return /* @__PURE__ */ React2.createElement("div", { style: styles.toolRow }, /* @__PURE__ */ React2.createElement("details", { style: styles.toolDetails }, /* @__PURE__ */ React2.createElement("summary", { style: styles.toolSummary }, /* @__PURE__ */ React2.createElement("span", { style: styles.toolIcon }, "\u2699"), " ", toolName, summary ? `: ${summary}` : ""), /* @__PURE__ */ React2.createElement("pre", { style: styles.toolContent }, JSON.stringify(data, null, 2))));
|
|
277
182
|
}
|
|
278
183
|
function ToolResultMessage({ data }) {
|
|
279
184
|
const isError = extractToolResultError(data);
|
|
280
185
|
const summary = extractToolResultSummary(data);
|
|
281
|
-
return /* @__PURE__ */
|
|
186
|
+
return /* @__PURE__ */ React2.createElement("div", { style: styles.toolRow }, /* @__PURE__ */ React2.createElement("details", { style: styles.toolDetails }, /* @__PURE__ */ React2.createElement("summary", { style: { ...styles.toolSummary, color: isError ? "#f44336" : "#4caf50" } }, isError ? "Error" : "Done", summary ? `: ${summary}` : ""), /* @__PURE__ */ React2.createElement("pre", { style: styles.toolContent }, JSON.stringify(data, null, 2))));
|
|
282
187
|
}
|
|
283
188
|
function ResultMessage({ data }) {
|
|
284
189
|
const subtype = (data == null ? void 0 : data.subtype) || "unknown";
|
|
285
|
-
return /* @__PURE__ */
|
|
190
|
+
return /* @__PURE__ */ React2.createElement("div", { style: styles.resultRow }, /* @__PURE__ */ React2.createElement("div", { style: styles.resultBubble }, /* @__PURE__ */ React2.createElement("span", { style: styles.resultLabel }, subtype === "success" ? "Completed" : `Result: ${subtype}`)));
|
|
286
191
|
}
|
|
287
192
|
function SystemMessage({ data }) {
|
|
288
193
|
if (typeof (data == null ? void 0 : data.message) === "string") {
|
|
289
|
-
return /* @__PURE__ */
|
|
194
|
+
return /* @__PURE__ */ React2.createElement("div", { style: styles.systemRow }, /* @__PURE__ */ React2.createElement("div", { style: styles.systemBubble }, data.message));
|
|
290
195
|
}
|
|
291
196
|
const label = (data == null ? void 0 : data.subtype) ? `System: ${data.subtype}` : "System event";
|
|
292
|
-
return /* @__PURE__ */
|
|
197
|
+
return /* @__PURE__ */ React2.createElement("div", { style: styles.toolRow }, /* @__PURE__ */ React2.createElement("details", { style: styles.toolDetails }, /* @__PURE__ */ React2.createElement("summary", { style: styles.toolSummary }, label), /* @__PURE__ */ React2.createElement("pre", { style: styles.toolContent }, JSON.stringify(data, null, 2))));
|
|
293
198
|
}
|
|
294
199
|
function RateLimitMessage({ data }) {
|
|
295
|
-
return /* @__PURE__ */
|
|
200
|
+
return /* @__PURE__ */ React2.createElement("div", { style: styles.toolRow }, /* @__PURE__ */ React2.createElement("details", { style: styles.toolDetails }, /* @__PURE__ */ React2.createElement("summary", { style: { ...styles.toolSummary, color: "#ff9800" } }, "Rate limited (waiting...)"), /* @__PURE__ */ React2.createElement("pre", { style: styles.toolContent }, JSON.stringify(data, null, 2))));
|
|
296
201
|
}
|
|
297
202
|
function GenericOutputMessage({ data, replay }) {
|
|
298
203
|
const text = extractAssistantText(data);
|
|
@@ -300,19 +205,30 @@ function GenericOutputMessage({ data, replay }) {
|
|
|
300
205
|
return null;
|
|
301
206
|
}
|
|
302
207
|
if (text) {
|
|
303
|
-
return /* @__PURE__ */
|
|
208
|
+
return /* @__PURE__ */ React2.createElement("div", { style: styles.assistantRow }, /* @__PURE__ */ React2.createElement("div", { style: { ...styles.assistantBubble, ...replay ? styles.replay : {} } }, /* @__PURE__ */ React2.createElement(MarkdownContent, { text })));
|
|
304
209
|
}
|
|
305
210
|
const summaryLabel = typeof data === "object" && data.type ? `System: ${data.type}` : "System message";
|
|
306
|
-
return /* @__PURE__ */
|
|
211
|
+
return /* @__PURE__ */ React2.createElement("div", { style: styles.toolRow }, /* @__PURE__ */ React2.createElement("details", { style: styles.toolDetails }, /* @__PURE__ */ React2.createElement("summary", { style: styles.toolSummary }, summaryLabel), /* @__PURE__ */ React2.createElement("pre", { style: styles.toolContent }, JSON.stringify(data, null, 2))));
|
|
307
212
|
}
|
|
308
213
|
function CompleteMessage({ message }) {
|
|
309
|
-
return /* @__PURE__ */
|
|
214
|
+
return /* @__PURE__ */ React2.createElement("div", { style: styles.systemRow }, /* @__PURE__ */ React2.createElement("div", { style: styles.completeBubble }, "Command completed (exit ", message.exitCode ?? "?", ")", message.durationMs != null && ` in ${(message.durationMs / 1e3).toFixed(1)}s`));
|
|
215
|
+
}
|
|
216
|
+
function CancelledMessage() {
|
|
217
|
+
return /* @__PURE__ */ React2.createElement("div", { style: styles.resultRow }, /* @__PURE__ */ React2.createElement("div", { style: styles.cancelledBubble }, /* @__PURE__ */ React2.createElement("span", { style: styles.resultLabel }, "Cancelled")));
|
|
310
218
|
}
|
|
311
219
|
function SkillInvocationMessage({ skill }) {
|
|
312
|
-
return /* @__PURE__ */
|
|
220
|
+
return /* @__PURE__ */ React2.createElement("div", { style: styles.skillRow }, /* @__PURE__ */ React2.createElement("div", { style: styles.skillBubble }, /* @__PURE__ */ React2.createElement("span", { style: styles.skillIcon }, skill.icon), /* @__PURE__ */ React2.createElement("span", { style: styles.skillLabel }, "Skill: ", skill.label)));
|
|
221
|
+
}
|
|
222
|
+
function TypingIndicator() {
|
|
223
|
+
return /* @__PURE__ */ React2.createElement("div", { style: styles.assistantRow }, /* @__PURE__ */ React2.createElement("style", null, `
|
|
224
|
+
@keyframes claude-typing-bounce {
|
|
225
|
+
0%, 60%, 100% { opacity: 0.3; transform: translateY(0); }
|
|
226
|
+
30% { opacity: 1; transform: translateY(-3px); }
|
|
227
|
+
}
|
|
228
|
+
`), /* @__PURE__ */ React2.createElement("div", { style: styles.typingBubble }, /* @__PURE__ */ React2.createElement("span", { style: styles.typingDot }), /* @__PURE__ */ React2.createElement("span", { style: { ...styles.typingDot, animationDelay: "0.2s" } }), /* @__PURE__ */ React2.createElement("span", { style: { ...styles.typingDot, animationDelay: "0.4s" } })));
|
|
313
229
|
}
|
|
314
230
|
function ErrorMessage({ message }) {
|
|
315
|
-
return /* @__PURE__ */
|
|
231
|
+
return /* @__PURE__ */ React2.createElement("div", { style: styles.errorRow }, /* @__PURE__ */ React2.createElement("div", { style: styles.errorBubble }, message.code && /* @__PURE__ */ React2.createElement("span", { style: styles.errorCode }, message.code, ": "), message.message || "Unknown error"));
|
|
316
232
|
}
|
|
317
233
|
function extractAssistantText(data) {
|
|
318
234
|
var _a;
|
|
@@ -369,7 +285,7 @@ function extractToolResultSummary(data) {
|
|
|
369
285
|
}
|
|
370
286
|
return null;
|
|
371
287
|
}
|
|
372
|
-
var
|
|
288
|
+
var styles = {
|
|
373
289
|
container: {
|
|
374
290
|
flex: 1,
|
|
375
291
|
overflowY: "auto",
|
|
@@ -495,6 +411,29 @@ var styles2 = {
|
|
|
495
411
|
fontSize: "11px",
|
|
496
412
|
color: "#777"
|
|
497
413
|
},
|
|
414
|
+
typingBubble: {
|
|
415
|
+
display: "flex",
|
|
416
|
+
alignItems: "center",
|
|
417
|
+
gap: "4px",
|
|
418
|
+
padding: "10px 14px",
|
|
419
|
+
borderRadius: "12px 12px 12px 2px",
|
|
420
|
+
backgroundColor: "#f0f0f0"
|
|
421
|
+
},
|
|
422
|
+
typingDot: {
|
|
423
|
+
width: "6px",
|
|
424
|
+
height: "6px",
|
|
425
|
+
borderRadius: "50%",
|
|
426
|
+
backgroundColor: "#999",
|
|
427
|
+
animation: "claude-typing-bounce 1.2s infinite"
|
|
428
|
+
},
|
|
429
|
+
cancelledBubble: {
|
|
430
|
+
padding: "6px 12px",
|
|
431
|
+
borderRadius: "8px",
|
|
432
|
+
backgroundColor: "#fff3e0",
|
|
433
|
+
fontSize: "12px",
|
|
434
|
+
color: "#e65100",
|
|
435
|
+
textAlign: "center"
|
|
436
|
+
},
|
|
498
437
|
genericContent: {
|
|
499
438
|
margin: 0,
|
|
500
439
|
padding: "8px",
|
|
@@ -547,8 +486,8 @@ var styles2 = {
|
|
|
547
486
|
};
|
|
548
487
|
|
|
549
488
|
// src/components/MessageInput.jsx
|
|
550
|
-
import
|
|
551
|
-
function MessageInput({ onSend, disabled, isProcessing, placeholder }) {
|
|
489
|
+
import React3, { useState, useRef as useRef2 } from "react";
|
|
490
|
+
function MessageInput({ onSend, disabled, isProcessing, placeholder, onCancel }) {
|
|
552
491
|
const [text, setText] = useState("");
|
|
553
492
|
const textareaRef = useRef2(null);
|
|
554
493
|
const handleSend = () => {
|
|
@@ -561,7 +500,10 @@ function MessageInput({ onSend, disabled, isProcessing, placeholder }) {
|
|
|
561
500
|
}
|
|
562
501
|
};
|
|
563
502
|
const handleKeyDown = (e) => {
|
|
564
|
-
if (e.key === "
|
|
503
|
+
if (e.key === "Escape" && isProcessing && onCancel) {
|
|
504
|
+
e.preventDefault();
|
|
505
|
+
onCancel();
|
|
506
|
+
} else if (e.key === "Enter" && !e.shiftKey) {
|
|
565
507
|
e.preventDefault();
|
|
566
508
|
handleSend();
|
|
567
509
|
}
|
|
@@ -572,11 +514,34 @@ function MessageInput({ onSend, disabled, isProcessing, placeholder }) {
|
|
|
572
514
|
el.style.height = "auto";
|
|
573
515
|
el.style.height = Math.min(el.scrollHeight, 120) + "px";
|
|
574
516
|
};
|
|
575
|
-
|
|
517
|
+
if (isProcessing && onCancel) {
|
|
518
|
+
return /* @__PURE__ */ React3.createElement("div", { style: styles2.container }, /* @__PURE__ */ React3.createElement(
|
|
519
|
+
"textarea",
|
|
520
|
+
{
|
|
521
|
+
ref: textareaRef,
|
|
522
|
+
style: styles2.textarea,
|
|
523
|
+
value: text,
|
|
524
|
+
onChange: handleInput,
|
|
525
|
+
onKeyDown: handleKeyDown,
|
|
526
|
+
placeholder: disabled ? "Connect to daemon first..." : placeholder || "Ask Claude...",
|
|
527
|
+
disabled: true,
|
|
528
|
+
rows: 1
|
|
529
|
+
}
|
|
530
|
+
), /* @__PURE__ */ React3.createElement(
|
|
531
|
+
"button",
|
|
532
|
+
{
|
|
533
|
+
style: styles2.buttonCancel,
|
|
534
|
+
onClick: onCancel,
|
|
535
|
+
title: "Cancel response (Escape)"
|
|
536
|
+
},
|
|
537
|
+
"Cancel"
|
|
538
|
+
));
|
|
539
|
+
}
|
|
540
|
+
return /* @__PURE__ */ React3.createElement("div", { style: styles2.container }, /* @__PURE__ */ React3.createElement(
|
|
576
541
|
"textarea",
|
|
577
542
|
{
|
|
578
543
|
ref: textareaRef,
|
|
579
|
-
style:
|
|
544
|
+
style: styles2.textarea,
|
|
580
545
|
value: text,
|
|
581
546
|
onChange: handleInput,
|
|
582
547
|
onKeyDown: handleKeyDown,
|
|
@@ -584,21 +549,21 @@ function MessageInput({ onSend, disabled, isProcessing, placeholder }) {
|
|
|
584
549
|
disabled,
|
|
585
550
|
rows: 1
|
|
586
551
|
}
|
|
587
|
-
), /* @__PURE__ */
|
|
552
|
+
), /* @__PURE__ */ React3.createElement(
|
|
588
553
|
"button",
|
|
589
554
|
{
|
|
590
555
|
style: {
|
|
591
|
-
...
|
|
592
|
-
...disabled || !text.trim() ?
|
|
556
|
+
...styles2.button,
|
|
557
|
+
...disabled || !text.trim() ? styles2.buttonDisabled : {}
|
|
593
558
|
},
|
|
594
559
|
onClick: handleSend,
|
|
595
560
|
disabled: disabled || !text.trim(),
|
|
596
561
|
title: "Send message (Enter)"
|
|
597
562
|
},
|
|
598
|
-
|
|
563
|
+
"Send"
|
|
599
564
|
));
|
|
600
565
|
}
|
|
601
|
-
var
|
|
566
|
+
var styles2 = {
|
|
602
567
|
container: {
|
|
603
568
|
display: "flex",
|
|
604
569
|
alignItems: "flex-end",
|
|
@@ -634,11 +599,23 @@ var styles3 = {
|
|
|
634
599
|
buttonDisabled: {
|
|
635
600
|
backgroundColor: "#ccc",
|
|
636
601
|
cursor: "not-allowed"
|
|
602
|
+
},
|
|
603
|
+
buttonCancel: {
|
|
604
|
+
padding: "8px 16px",
|
|
605
|
+
border: "none",
|
|
606
|
+
borderRadius: "8px",
|
|
607
|
+
backgroundColor: "#e53e3e",
|
|
608
|
+
color: "#fff",
|
|
609
|
+
fontSize: "13px",
|
|
610
|
+
fontWeight: 600,
|
|
611
|
+
cursor: "pointer",
|
|
612
|
+
whiteSpace: "nowrap",
|
|
613
|
+
minHeight: "36px"
|
|
637
614
|
}
|
|
638
615
|
};
|
|
639
616
|
|
|
640
617
|
// src/components/TokenInput.jsx
|
|
641
|
-
import
|
|
618
|
+
import React4, { useState as useState2 } from "react";
|
|
642
619
|
function TokenInput({ onSubmit, defaultPort = 3001 }) {
|
|
643
620
|
const [token, setToken] = useState2("");
|
|
644
621
|
const [port, setPort] = useState2(String(defaultPort));
|
|
@@ -650,42 +627,42 @@ function TokenInput({ onSubmit, defaultPort = 3001 }) {
|
|
|
650
627
|
onSubmit(trimmed, portNum);
|
|
651
628
|
}
|
|
652
629
|
};
|
|
653
|
-
return /* @__PURE__ */
|
|
630
|
+
return /* @__PURE__ */ React4.createElement("div", { style: styles3.container }, /* @__PURE__ */ React4.createElement("div", { style: styles3.title }, "Connect to Claude Daemon"), /* @__PURE__ */ React4.createElement("p", { style: styles3.description }, "Enter the auth token from the daemon's startup output, or set the ", /* @__PURE__ */ React4.createElement("code", { style: styles3.code }, "CLAUDE_DAEMON_TOKEN"), " environment variable."), /* @__PURE__ */ React4.createElement("form", { onSubmit: handleSubmit, style: styles3.form }, /* @__PURE__ */ React4.createElement("div", { style: styles3.inputRow }, /* @__PURE__ */ React4.createElement(
|
|
654
631
|
"input",
|
|
655
632
|
{
|
|
656
633
|
type: "text",
|
|
657
634
|
value: token,
|
|
658
635
|
onChange: (e) => setToken(e.target.value),
|
|
659
636
|
placeholder: "Paste daemon auth token...",
|
|
660
|
-
style:
|
|
637
|
+
style: styles3.input,
|
|
661
638
|
autoFocus: true
|
|
662
639
|
}
|
|
663
|
-
), /* @__PURE__ */
|
|
640
|
+
), /* @__PURE__ */ React4.createElement(
|
|
664
641
|
"input",
|
|
665
642
|
{
|
|
666
643
|
type: "number",
|
|
667
644
|
value: port,
|
|
668
645
|
onChange: (e) => setPort(e.target.value),
|
|
669
646
|
placeholder: "Port",
|
|
670
|
-
style:
|
|
647
|
+
style: styles3.portInput,
|
|
671
648
|
min: "1",
|
|
672
649
|
max: "65535",
|
|
673
650
|
"aria-label": "Port"
|
|
674
651
|
}
|
|
675
|
-
)), /* @__PURE__ */
|
|
652
|
+
)), /* @__PURE__ */ React4.createElement(
|
|
676
653
|
"button",
|
|
677
654
|
{
|
|
678
655
|
type: "submit",
|
|
679
656
|
disabled: !token.trim(),
|
|
680
657
|
style: {
|
|
681
|
-
...
|
|
682
|
-
...!token.trim() ?
|
|
658
|
+
...styles3.button,
|
|
659
|
+
...!token.trim() ? styles3.buttonDisabled : {}
|
|
683
660
|
}
|
|
684
661
|
},
|
|
685
662
|
"Connect"
|
|
686
663
|
)));
|
|
687
664
|
}
|
|
688
|
-
var
|
|
665
|
+
var styles3 = {
|
|
689
666
|
container: {
|
|
690
667
|
display: "flex",
|
|
691
668
|
flexDirection: "column",
|
|
@@ -762,63 +739,6 @@ var styles4 = {
|
|
|
762
739
|
}
|
|
763
740
|
};
|
|
764
741
|
|
|
765
|
-
// src/components/GitContextBar.jsx
|
|
766
|
-
import React6 from "react";
|
|
767
|
-
function GitContextBar({ branch, pr, loading }) {
|
|
768
|
-
if (loading || !branch) return null;
|
|
769
|
-
return /* @__PURE__ */ React6.createElement("div", { style: styles5.container }, /* @__PURE__ */ React6.createElement("div", { style: styles5.left }, /* @__PURE__ */ React6.createElement("span", { style: styles5.branchIcon, title: "Git branch" }, "\u2387"), /* @__PURE__ */ React6.createElement("span", { style: styles5.branchName }, branch)), pr && /* @__PURE__ */ React6.createElement("div", { style: styles5.right }, /* @__PURE__ */ React6.createElement(
|
|
770
|
-
"a",
|
|
771
|
-
{
|
|
772
|
-
href: pr.url,
|
|
773
|
-
target: "_blank",
|
|
774
|
-
rel: "noopener noreferrer",
|
|
775
|
-
style: styles5.prLink,
|
|
776
|
-
title: pr.title
|
|
777
|
-
},
|
|
778
|
-
"PR #",
|
|
779
|
-
pr.number
|
|
780
|
-
)));
|
|
781
|
-
}
|
|
782
|
-
var styles5 = {
|
|
783
|
-
container: {
|
|
784
|
-
display: "flex",
|
|
785
|
-
alignItems: "center",
|
|
786
|
-
justifyContent: "space-between",
|
|
787
|
-
padding: "3px 12px",
|
|
788
|
-
borderBottom: "1px solid rgba(0,0,0,0.1)",
|
|
789
|
-
backgroundColor: "#f5f5f5",
|
|
790
|
-
fontSize: "11px",
|
|
791
|
-
fontFamily: "inherit"
|
|
792
|
-
},
|
|
793
|
-
left: {
|
|
794
|
-
display: "flex",
|
|
795
|
-
alignItems: "center",
|
|
796
|
-
gap: "4px"
|
|
797
|
-
},
|
|
798
|
-
branchIcon: {
|
|
799
|
-
fontSize: "12px",
|
|
800
|
-
color: "#888"
|
|
801
|
-
},
|
|
802
|
-
branchName: {
|
|
803
|
-
fontFamily: "monospace",
|
|
804
|
-
fontSize: "11px",
|
|
805
|
-
color: "#555",
|
|
806
|
-
backgroundColor: "#eee",
|
|
807
|
-
padding: "1px 5px",
|
|
808
|
-
borderRadius: "3px"
|
|
809
|
-
},
|
|
810
|
-
right: {
|
|
811
|
-
display: "flex",
|
|
812
|
-
alignItems: "center"
|
|
813
|
-
},
|
|
814
|
-
prLink: {
|
|
815
|
-
color: "#0366d6",
|
|
816
|
-
textDecoration: "none",
|
|
817
|
-
fontFamily: "monospace",
|
|
818
|
-
fontSize: "11px"
|
|
819
|
-
}
|
|
820
|
-
};
|
|
821
|
-
|
|
822
742
|
// src/useClaudeSession.js
|
|
823
743
|
import { useState as useState3, useEffect as useEffect2, useRef as useRef3, useCallback } from "react";
|
|
824
744
|
|
|
@@ -828,6 +748,7 @@ var WebSocketClient = class {
|
|
|
828
748
|
this._host = options.host || DEFAULT_HOST;
|
|
829
749
|
this._port = options.port || DEFAULT_PORT;
|
|
830
750
|
this._token = options.token || null;
|
|
751
|
+
this._daemonUrl = options.daemonUrl || null;
|
|
831
752
|
this._ws = null;
|
|
832
753
|
this._state = CONNECTION_STATES.DISCONNECTED;
|
|
833
754
|
this._listeners = /* @__PURE__ */ new Map();
|
|
@@ -847,7 +768,7 @@ var WebSocketClient = class {
|
|
|
847
768
|
}
|
|
848
769
|
/**
|
|
849
770
|
* Register an event listener.
|
|
850
|
-
* Events: 'state_change', 'session_activated', 'output', 'complete', 'error', 'pong'
|
|
771
|
+
* Events: 'state_change', 'session_activated', 'output', 'complete', 'error', 'pong', 'cancelled'
|
|
851
772
|
*/
|
|
852
773
|
on(event, callback) {
|
|
853
774
|
if (!this._listeners.has(event)) {
|
|
@@ -870,7 +791,7 @@ var WebSocketClient = class {
|
|
|
870
791
|
this._setState(CONNECTION_STATES.CONNECTING);
|
|
871
792
|
}
|
|
872
793
|
const params = this._token ? `?token=${encodeURIComponent(this._token)}` : "";
|
|
873
|
-
const url =
|
|
794
|
+
const url = this._buildUrl(params);
|
|
874
795
|
try {
|
|
875
796
|
this._ws = new WebSocket(url);
|
|
876
797
|
} catch (err) {
|
|
@@ -922,6 +843,12 @@ var WebSocketClient = class {
|
|
|
922
843
|
setToken(token) {
|
|
923
844
|
this._token = token;
|
|
924
845
|
}
|
|
846
|
+
/**
|
|
847
|
+
* Update the daemon URL for remote environments.
|
|
848
|
+
*/
|
|
849
|
+
setDaemonUrl(url) {
|
|
850
|
+
this._daemonUrl = url;
|
|
851
|
+
}
|
|
925
852
|
/**
|
|
926
853
|
* Activate a session. Must be called after connecting.
|
|
927
854
|
*/
|
|
@@ -952,6 +879,16 @@ var WebSocketClient = class {
|
|
|
952
879
|
sessionId
|
|
953
880
|
});
|
|
954
881
|
}
|
|
882
|
+
/**
|
|
883
|
+
* Cancel a command in progress.
|
|
884
|
+
*/
|
|
885
|
+
cancelCommand(sessionId, commandId) {
|
|
886
|
+
this._send({
|
|
887
|
+
type: "cancel",
|
|
888
|
+
sessionId,
|
|
889
|
+
commandId
|
|
890
|
+
});
|
|
891
|
+
}
|
|
955
892
|
/**
|
|
956
893
|
* Send a query to the daemon.
|
|
957
894
|
*/
|
|
@@ -964,6 +901,28 @@ var WebSocketClient = class {
|
|
|
964
901
|
// ---------------------------------------------------------------------------
|
|
965
902
|
// Internal
|
|
966
903
|
// ---------------------------------------------------------------------------
|
|
904
|
+
/**
|
|
905
|
+
* Build the WebSocket URL. Priority:
|
|
906
|
+
* 1. Explicit `daemonUrl` option (fully custom URL)
|
|
907
|
+
* 2. Auto-detected Codespaces forwarded URL (derived from current hostname)
|
|
908
|
+
* 3. Local `ws://host:port/` fallback
|
|
909
|
+
*/
|
|
910
|
+
_buildUrl(params) {
|
|
911
|
+
if (this._daemonUrl) {
|
|
912
|
+
const base = this._daemonUrl.replace(/\/$/, "");
|
|
913
|
+
return `${base}/${params}`;
|
|
914
|
+
}
|
|
915
|
+
if (typeof window !== "undefined" && window.location) {
|
|
916
|
+
const hostname = window.location.hostname;
|
|
917
|
+
const match = hostname.match(/^(.+)-(\d+)(\..*\.app\.github\.dev)$/);
|
|
918
|
+
if (match) {
|
|
919
|
+
const [, prefix, , suffix] = match;
|
|
920
|
+
const daemonHost = `${prefix}-${this._port}${suffix}`;
|
|
921
|
+
return `wss://${daemonHost}/${params}`;
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
return `ws://${this._host}:${this._port}/${params}`;
|
|
925
|
+
}
|
|
967
926
|
_send(msg) {
|
|
968
927
|
if (this._ws && this._ws.readyState === WebSocket.OPEN) {
|
|
969
928
|
this._ws.send(JSON.stringify(msg));
|
|
@@ -985,6 +944,7 @@ var WebSocketClient = class {
|
|
|
985
944
|
case "user_input":
|
|
986
945
|
case "pong":
|
|
987
946
|
case "query_result":
|
|
947
|
+
case "cancelled":
|
|
988
948
|
this._emit(msg.type, msg);
|
|
989
949
|
break;
|
|
990
950
|
default:
|
|
@@ -1076,6 +1036,7 @@ function useClaudeSession(options = {}) {
|
|
|
1076
1036
|
const clientRef = useRef3(null);
|
|
1077
1037
|
const sessionIdRef = useRef3(sessionId);
|
|
1078
1038
|
sessionIdRef.current = sessionId;
|
|
1039
|
+
const currentCommandIdRef = useRef3(null);
|
|
1079
1040
|
useEffect2(() => {
|
|
1080
1041
|
const client = new WebSocketClient({ host, port, token });
|
|
1081
1042
|
clientRef.current = client;
|
|
@@ -1134,6 +1095,12 @@ function useClaudeSession(options = {}) {
|
|
|
1134
1095
|
{ type: "error", ...msg, id: crypto.randomUUID(), timestamp: Date.now() }
|
|
1135
1096
|
]);
|
|
1136
1097
|
setIsProcessing(false);
|
|
1098
|
+
}),
|
|
1099
|
+
client.on("cancelled", (msg) => {
|
|
1100
|
+
if (msg.sessionId !== sessionIdRef.current) return;
|
|
1101
|
+
setMessages((prev) => [...prev, { type: "cancelled", id: crypto.randomUUID(), timestamp: msg.timestamp, sessionId: msg.sessionId }]);
|
|
1102
|
+
setIsProcessing(false);
|
|
1103
|
+
currentCommandIdRef.current = null;
|
|
1137
1104
|
})
|
|
1138
1105
|
];
|
|
1139
1106
|
return () => {
|
|
@@ -1173,7 +1140,9 @@ ${text}` : text;
|
|
|
1173
1140
|
}
|
|
1174
1141
|
]);
|
|
1175
1142
|
setIsProcessing(true);
|
|
1176
|
-
|
|
1143
|
+
const commandId = crypto.randomUUID();
|
|
1144
|
+
currentCommandIdRef.current = commandId;
|
|
1145
|
+
client.sendCommand(sessionIdRef.current, fullText, commandId);
|
|
1177
1146
|
},
|
|
1178
1147
|
[]
|
|
1179
1148
|
);
|
|
@@ -1215,6 +1184,12 @@ ${text}` : text;
|
|
|
1215
1184
|
startSession();
|
|
1216
1185
|
}
|
|
1217
1186
|
}, [startSession]);
|
|
1187
|
+
const cancelCommand = useCallback(() => {
|
|
1188
|
+
const client = clientRef.current;
|
|
1189
|
+
const cmdId = currentCommandIdRef.current;
|
|
1190
|
+
if (!client || !client.isConnected || !sessionIdRef.current) return;
|
|
1191
|
+
client.cancelCommand(sessionIdRef.current, cmdId);
|
|
1192
|
+
}, []);
|
|
1218
1193
|
return {
|
|
1219
1194
|
connectionState,
|
|
1220
1195
|
messages,
|
|
@@ -1227,44 +1202,42 @@ ${text}` : text;
|
|
|
1227
1202
|
setMessages,
|
|
1228
1203
|
disconnect,
|
|
1229
1204
|
newChat,
|
|
1205
|
+
cancelCommand,
|
|
1230
1206
|
isConnected: connectionState === CONNECTION_STATES.CONNECTED,
|
|
1231
1207
|
client: clientRef.current
|
|
1232
1208
|
};
|
|
1233
1209
|
}
|
|
1234
1210
|
|
|
1235
|
-
// src/
|
|
1211
|
+
// src/useDaemonQuery.js
|
|
1236
1212
|
import { useState as useState4, useEffect as useEffect3, useRef as useRef4, useCallback as useCallback2 } from "react";
|
|
1237
|
-
function
|
|
1238
|
-
const [
|
|
1239
|
-
const [
|
|
1213
|
+
function useDaemonQuery(client, connectionState, queryType, pollIntervalMs) {
|
|
1214
|
+
const [data, setData] = useState4(null);
|
|
1215
|
+
const [error, setError] = useState4(null);
|
|
1240
1216
|
const intervalRef = useRef4(null);
|
|
1241
|
-
const
|
|
1242
|
-
const
|
|
1217
|
+
const dataRef = useRef4(null);
|
|
1218
|
+
const fetchQuery = useCallback2(() => {
|
|
1243
1219
|
if (!client || !client.isConnected) return;
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
}, [client]);
|
|
1220
|
+
client.sendQuery(queryType);
|
|
1221
|
+
}, [client, queryType]);
|
|
1247
1222
|
useEffect3(() => {
|
|
1248
1223
|
if (!client) return;
|
|
1249
1224
|
const unsub = client.on("query_result", (msg) => {
|
|
1250
|
-
if (msg.queryType ===
|
|
1251
|
-
|
|
1252
|
-
|
|
1225
|
+
if (msg.queryType === queryType) {
|
|
1226
|
+
dataRef.current = msg.data || null;
|
|
1227
|
+
setData(msg.data || null);
|
|
1228
|
+
setError(null);
|
|
1253
1229
|
}
|
|
1254
1230
|
});
|
|
1255
1231
|
const unsubErr = client.on("error", (msg) => {
|
|
1256
1232
|
if (msg.code === "UNKNOWN_TYPE" || msg.code === "UNKNOWN_QUERY") {
|
|
1257
|
-
|
|
1233
|
+
setError(msg.message || "Unsupported query");
|
|
1258
1234
|
}
|
|
1259
1235
|
});
|
|
1260
|
-
|
|
1236
|
+
return () => {
|
|
1261
1237
|
unsub();
|
|
1262
1238
|
unsubErr();
|
|
1263
1239
|
};
|
|
1264
|
-
|
|
1265
|
-
if (unsubRef.current) unsubRef.current();
|
|
1266
|
-
};
|
|
1267
|
-
}, [client]);
|
|
1240
|
+
}, [client, queryType]);
|
|
1268
1241
|
useEffect3(() => {
|
|
1269
1242
|
if (connectionState !== CONNECTION_STATES.CONNECTED) {
|
|
1270
1243
|
if (intervalRef.current) {
|
|
@@ -1273,18 +1246,25 @@ function useGitContext(client, connectionState) {
|
|
|
1273
1246
|
}
|
|
1274
1247
|
return;
|
|
1275
1248
|
}
|
|
1276
|
-
|
|
1277
|
-
intervalRef.current = setInterval(
|
|
1249
|
+
fetchQuery();
|
|
1250
|
+
intervalRef.current = setInterval(fetchQuery, pollIntervalMs);
|
|
1278
1251
|
return () => {
|
|
1279
1252
|
if (intervalRef.current) {
|
|
1280
1253
|
clearInterval(intervalRef.current);
|
|
1281
1254
|
intervalRef.current = null;
|
|
1282
1255
|
}
|
|
1283
1256
|
};
|
|
1284
|
-
}, [connectionState,
|
|
1257
|
+
}, [connectionState, fetchQuery, pollIntervalMs]);
|
|
1258
|
+
const loading = data === null && dataRef.current === null && error === null;
|
|
1259
|
+
return { data, loading, error };
|
|
1260
|
+
}
|
|
1261
|
+
|
|
1262
|
+
// src/useGitContext.js
|
|
1263
|
+
function useGitContext(client, connectionState) {
|
|
1264
|
+
const { data, loading } = useDaemonQuery(client, connectionState, "git_context", 6e4);
|
|
1285
1265
|
return {
|
|
1286
|
-
branch: (
|
|
1287
|
-
pr: (
|
|
1266
|
+
branch: (data == null ? void 0 : data.branch) || null,
|
|
1267
|
+
pr: (data == null ? void 0 : data.pr) || null,
|
|
1288
1268
|
loading
|
|
1289
1269
|
};
|
|
1290
1270
|
}
|
|
@@ -1342,12 +1322,10 @@ function storyFileToComponentFile(storyPath) {
|
|
|
1342
1322
|
function ClaudePanel({ active }) {
|
|
1343
1323
|
const [addonState, setAddonState] = useAddonState(ADDON_ID, {
|
|
1344
1324
|
token: getInitialToken(),
|
|
1345
|
-
port: getInitialPort()
|
|
1346
|
-
contextEnabled: true
|
|
1325
|
+
port: getInitialPort()
|
|
1347
1326
|
});
|
|
1348
1327
|
const token = (addonState == null ? void 0 : addonState.token) || null;
|
|
1349
1328
|
const port = (addonState == null ? void 0 : addonState.port) || DEFAULT_PORT;
|
|
1350
|
-
const contextEnabled = (addonState == null ? void 0 : addonState.contextEnabled) ?? true;
|
|
1351
1329
|
const storyContext = useStoryContext();
|
|
1352
1330
|
const {
|
|
1353
1331
|
connectionState,
|
|
@@ -1357,8 +1335,8 @@ function ClaudePanel({ active }) {
|
|
|
1357
1335
|
authFailed,
|
|
1358
1336
|
sendMessage,
|
|
1359
1337
|
startSession,
|
|
1360
|
-
disconnect,
|
|
1361
1338
|
newChat,
|
|
1339
|
+
cancelCommand,
|
|
1362
1340
|
isConnected,
|
|
1363
1341
|
client
|
|
1364
1342
|
} = useClaudeSession({
|
|
@@ -1373,41 +1351,53 @@ function ClaudePanel({ active }) {
|
|
|
1373
1351
|
},
|
|
1374
1352
|
[addonState, setAddonState]
|
|
1375
1353
|
);
|
|
1376
|
-
const handleDisconnect = useCallback3(() => {
|
|
1377
|
-
disconnect();
|
|
1378
|
-
setAddonState({ ...addonState, token: null });
|
|
1379
|
-
}, [addonState, setAddonState, disconnect]);
|
|
1380
1354
|
const handleSend = useCallback3(
|
|
1381
1355
|
(text) => {
|
|
1382
1356
|
if (!sessionId) {
|
|
1383
1357
|
startSession();
|
|
1384
1358
|
}
|
|
1385
|
-
const prefix =
|
|
1359
|
+
const prefix = buildContextPrefix(storyContext);
|
|
1386
1360
|
sendMessage(text, prefix);
|
|
1387
1361
|
},
|
|
1388
|
-
[sessionId, startSession, sendMessage,
|
|
1362
|
+
[sessionId, startSession, sendMessage, storyContext]
|
|
1389
1363
|
);
|
|
1390
|
-
const toggleContext = useCallback3(() => {
|
|
1391
|
-
setAddonState({ ...addonState, contextEnabled: !contextEnabled });
|
|
1392
|
-
}, [addonState, contextEnabled, setAddonState]);
|
|
1393
1364
|
if (!active) return null;
|
|
1394
1365
|
if (authFailed && !token) {
|
|
1395
|
-
return /* @__PURE__ */
|
|
1366
|
+
return /* @__PURE__ */ React5.createElement("div", { style: styles4.panel }, /* @__PURE__ */ React5.createElement(TokenInput, { onSubmit: handleTokenSubmit }));
|
|
1396
1367
|
}
|
|
1397
|
-
|
|
1398
|
-
|
|
1368
|
+
const statusColor = connectionState === CONNECTION_STATES.CONNECTED ? "#4caf50" : connectionState === CONNECTION_STATES.DISCONNECTED ? "#f44336" : "#ff9800";
|
|
1369
|
+
const statusLabel = connectionState === CONNECTION_STATES.CONNECTED ? "Connected" : connectionState === CONNECTION_STATES.CONNECTING ? "Connecting..." : connectionState === CONNECTION_STATES.RECONNECTING ? "Reconnecting..." : "Disconnected";
|
|
1370
|
+
return /* @__PURE__ */ React5.createElement("div", { style: styles4.panel }, /* @__PURE__ */ React5.createElement("div", { style: styles4.headerBar }, /* @__PURE__ */ React5.createElement("div", { style: styles4.headerLeft }, /* @__PURE__ */ React5.createElement("span", { style: { ...styles4.statusDot, backgroundColor: statusColor }, title: statusLabel }), /* @__PURE__ */ React5.createElement("span", { style: styles4.statusLabel }, statusLabel)), /* @__PURE__ */ React5.createElement("div", { style: styles4.headerRight }, gitContext.branch && /* @__PURE__ */ React5.createElement("div", { style: styles4.gitContext }, /* @__PURE__ */ React5.createElement("div", { style: styles4.branchName }, /* @__PURE__ */ React5.createElement("span", { style: styles4.branchIcon, title: "Git branch" }, "\u2387"), gitContext.branch), gitContext.pr && /* @__PURE__ */ React5.createElement(
|
|
1371
|
+
"a",
|
|
1399
1372
|
{
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
style:
|
|
1404
|
-
|
|
1405
|
-
|
|
1373
|
+
href: gitContext.pr.url,
|
|
1374
|
+
target: "_blank",
|
|
1375
|
+
rel: "noopener noreferrer",
|
|
1376
|
+
style: styles4.prLink,
|
|
1377
|
+
title: gitContext.pr.title
|
|
1378
|
+
},
|
|
1379
|
+
"PR #",
|
|
1380
|
+
gitContext.pr.number
|
|
1381
|
+
)), isConnected && /* @__PURE__ */ React5.createElement(
|
|
1382
|
+
"button",
|
|
1383
|
+
{
|
|
1384
|
+
onClick: newChat,
|
|
1385
|
+
disabled: isProcessing,
|
|
1386
|
+
style: {
|
|
1387
|
+
...styles4.newChatButton,
|
|
1388
|
+
...isProcessing ? styles4.newChatButtonDisabled : {}
|
|
1389
|
+
},
|
|
1390
|
+
title: "Clear chat and start fresh session",
|
|
1391
|
+
"aria-label": "New Chat"
|
|
1392
|
+
},
|
|
1393
|
+
"New Chat"
|
|
1394
|
+
))), /* @__PURE__ */ React5.createElement(MessageList, { messages, isProcessing }), /* @__PURE__ */ React5.createElement(
|
|
1406
1395
|
MessageInput,
|
|
1407
1396
|
{
|
|
1408
1397
|
onSend: handleSend,
|
|
1409
1398
|
disabled: !isConnected,
|
|
1410
|
-
isProcessing
|
|
1399
|
+
isProcessing,
|
|
1400
|
+
onCancel: cancelCommand
|
|
1411
1401
|
}
|
|
1412
1402
|
));
|
|
1413
1403
|
}
|
|
@@ -1426,68 +1416,118 @@ function getInitialPort() {
|
|
|
1426
1416
|
function getInitialToken() {
|
|
1427
1417
|
var _a, _b;
|
|
1428
1418
|
try {
|
|
1419
|
+
if (typeof window !== "undefined" && window.__CLAUDE_DAEMON_TOKEN__) {
|
|
1420
|
+
return window.__CLAUDE_DAEMON_TOKEN__;
|
|
1421
|
+
}
|
|
1429
1422
|
return typeof process !== "undefined" && ((_a = process.env) == null ? void 0 : _a.STORYBOOK_CLAUDE_DAEMON_TOKEN) || typeof process !== "undefined" && ((_b = process.env) == null ? void 0 : _b.CLAUDE_DAEMON_TOKEN) || null;
|
|
1430
1423
|
} catch {
|
|
1431
1424
|
return null;
|
|
1432
1425
|
}
|
|
1433
1426
|
}
|
|
1434
|
-
var
|
|
1427
|
+
var styles4 = {
|
|
1435
1428
|
panel: {
|
|
1436
1429
|
display: "flex",
|
|
1437
1430
|
flexDirection: "column",
|
|
1438
1431
|
height: "100%",
|
|
1439
1432
|
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif'
|
|
1440
1433
|
},
|
|
1441
|
-
|
|
1442
|
-
|
|
1434
|
+
headerBar: {
|
|
1435
|
+
display: "flex",
|
|
1436
|
+
alignItems: "center",
|
|
1437
|
+
justifyContent: "space-between",
|
|
1438
|
+
padding: "6px 12px",
|
|
1443
1439
|
borderBottom: "1px solid rgba(0,0,0,0.1)",
|
|
1444
|
-
backgroundColor: "#
|
|
1445
|
-
fontSize: "12px"
|
|
1440
|
+
backgroundColor: "#f5f5f5",
|
|
1441
|
+
fontSize: "12px",
|
|
1442
|
+
fontFamily: "inherit"
|
|
1446
1443
|
},
|
|
1447
|
-
|
|
1444
|
+
headerLeft: {
|
|
1448
1445
|
display: "flex",
|
|
1449
1446
|
alignItems: "center",
|
|
1450
|
-
gap: "
|
|
1451
|
-
color: "#666",
|
|
1452
|
-
cursor: "pointer"
|
|
1447
|
+
gap: "6px"
|
|
1453
1448
|
},
|
|
1454
|
-
|
|
1455
|
-
|
|
1449
|
+
statusDot: {
|
|
1450
|
+
width: "8px",
|
|
1451
|
+
height: "8px",
|
|
1452
|
+
borderRadius: "50%",
|
|
1453
|
+
display: "inline-block",
|
|
1454
|
+
flexShrink: 0
|
|
1456
1455
|
},
|
|
1457
|
-
|
|
1456
|
+
statusLabel: {
|
|
1457
|
+
fontSize: "12px",
|
|
1458
|
+
color: "#666"
|
|
1459
|
+
},
|
|
1460
|
+
headerRight: {
|
|
1461
|
+
display: "flex",
|
|
1462
|
+
alignItems: "center",
|
|
1463
|
+
gap: "12px"
|
|
1464
|
+
},
|
|
1465
|
+
gitContext: {
|
|
1466
|
+
display: "flex",
|
|
1467
|
+
flexDirection: "column",
|
|
1468
|
+
alignItems: "flex-end",
|
|
1469
|
+
gap: "1px"
|
|
1470
|
+
},
|
|
1471
|
+
branchName: {
|
|
1458
1472
|
fontFamily: "monospace",
|
|
1459
1473
|
fontSize: "11px",
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1474
|
+
color: "#555",
|
|
1475
|
+
display: "flex",
|
|
1476
|
+
alignItems: "center",
|
|
1477
|
+
gap: "3px"
|
|
1478
|
+
},
|
|
1479
|
+
branchIcon: {
|
|
1480
|
+
fontSize: "12px",
|
|
1481
|
+
color: "#888"
|
|
1482
|
+
},
|
|
1483
|
+
prLink: {
|
|
1484
|
+
color: "#0366d6",
|
|
1485
|
+
textDecoration: "none",
|
|
1486
|
+
fontFamily: "monospace",
|
|
1487
|
+
fontSize: "11px"
|
|
1488
|
+
},
|
|
1489
|
+
newChatButton: {
|
|
1490
|
+
padding: "2px 8px",
|
|
1491
|
+
border: "1px solid #ccc",
|
|
1492
|
+
borderRadius: "4px",
|
|
1493
|
+
backgroundColor: "transparent",
|
|
1494
|
+
color: "#666",
|
|
1495
|
+
fontSize: "11px",
|
|
1496
|
+
cursor: "pointer",
|
|
1497
|
+
lineHeight: "1.4",
|
|
1498
|
+
whiteSpace: "nowrap"
|
|
1499
|
+
},
|
|
1500
|
+
newChatButtonDisabled: {
|
|
1501
|
+
opacity: 0.4,
|
|
1502
|
+
cursor: "default"
|
|
1463
1503
|
}
|
|
1464
1504
|
};
|
|
1465
1505
|
|
|
1466
1506
|
// src/GlobalPanel.jsx
|
|
1467
|
-
import
|
|
1507
|
+
import React7, { useCallback as useCallback4, useMemo as useMemo2 } from "react";
|
|
1468
1508
|
import { useAddonState as useAddonState2 } from "storybook/manager-api";
|
|
1469
1509
|
|
|
1470
1510
|
// src/components/SkillsBar.jsx
|
|
1471
|
-
import
|
|
1511
|
+
import React6 from "react";
|
|
1472
1512
|
function SkillsBar({ skills, onTrigger, disabled }) {
|
|
1473
1513
|
if (!skills || skills.length === 0) return null;
|
|
1474
|
-
return /* @__PURE__ */
|
|
1514
|
+
return /* @__PURE__ */ React6.createElement("div", { style: styles5.bar }, skills.map((skill) => /* @__PURE__ */ React6.createElement(
|
|
1475
1515
|
"button",
|
|
1476
1516
|
{
|
|
1477
1517
|
key: skill.id,
|
|
1478
1518
|
style: {
|
|
1479
|
-
...
|
|
1480
|
-
...disabled ?
|
|
1519
|
+
...styles5.button,
|
|
1520
|
+
...disabled ? styles5.buttonDisabled : {}
|
|
1481
1521
|
},
|
|
1482
1522
|
onClick: () => onTrigger(skill),
|
|
1483
1523
|
disabled,
|
|
1484
|
-
title: skill.prompt
|
|
1524
|
+
title: skill.description || skill.prompt
|
|
1485
1525
|
},
|
|
1486
|
-
/* @__PURE__ */
|
|
1487
|
-
/* @__PURE__ */
|
|
1526
|
+
/* @__PURE__ */ React6.createElement("span", { style: styles5.icon }, skill.icon),
|
|
1527
|
+
/* @__PURE__ */ React6.createElement("span", null, skill.label)
|
|
1488
1528
|
)));
|
|
1489
1529
|
}
|
|
1490
|
-
var
|
|
1530
|
+
var styles5 = {
|
|
1491
1531
|
bar: {
|
|
1492
1532
|
display: "flex",
|
|
1493
1533
|
gap: "6px",
|
|
@@ -1518,8 +1558,18 @@ var styles7 = {
|
|
|
1518
1558
|
}
|
|
1519
1559
|
};
|
|
1520
1560
|
|
|
1561
|
+
// src/useSkillsConfig.js
|
|
1562
|
+
function useSkillsConfig(client, connectionState) {
|
|
1563
|
+
const { data, loading } = useDaemonQuery(client, connectionState, "skills_config", 12e4);
|
|
1564
|
+
return {
|
|
1565
|
+
skills: (data == null ? void 0 : data.skills) || [],
|
|
1566
|
+
source: (data == null ? void 0 : data.source) || "none",
|
|
1567
|
+
loading
|
|
1568
|
+
};
|
|
1569
|
+
}
|
|
1570
|
+
|
|
1521
1571
|
// src/skills.js
|
|
1522
|
-
var
|
|
1572
|
+
var DEFAULT_SKILLS = [
|
|
1523
1573
|
{
|
|
1524
1574
|
id: "sync-components",
|
|
1525
1575
|
label: "Sync Components",
|
|
@@ -1555,17 +1605,13 @@ function getPrSkill(pr) {
|
|
|
1555
1605
|
prompt: "Create a new pull request for the current branch with a summary of all changes."
|
|
1556
1606
|
};
|
|
1557
1607
|
}
|
|
1558
|
-
function getGlobalSkills(gitContext) {
|
|
1608
|
+
function getGlobalSkills(gitContext, configSkills) {
|
|
1559
1609
|
const pr = (gitContext == null ? void 0 : gitContext.pr) || null;
|
|
1610
|
+
const skills = configSkills && configSkills.length > 0 ? configSkills : DEFAULT_SKILLS;
|
|
1560
1611
|
return [
|
|
1561
|
-
|
|
1562
|
-
// Sync Components
|
|
1612
|
+
skills[0],
|
|
1563
1613
|
getPrSkill(pr),
|
|
1564
|
-
|
|
1565
|
-
STATIC_SKILLS[1],
|
|
1566
|
-
// Run Tests
|
|
1567
|
-
STATIC_SKILLS[2]
|
|
1568
|
-
// Audit Stories
|
|
1614
|
+
...skills.slice(1)
|
|
1569
1615
|
];
|
|
1570
1616
|
}
|
|
1571
1617
|
|
|
@@ -1589,6 +1635,7 @@ function GlobalPanel() {
|
|
|
1589
1635
|
sendMessage,
|
|
1590
1636
|
startSession,
|
|
1591
1637
|
setMessages,
|
|
1638
|
+
cancelCommand,
|
|
1592
1639
|
isConnected,
|
|
1593
1640
|
client
|
|
1594
1641
|
} = useClaudeSession({
|
|
@@ -1599,7 +1646,11 @@ function GlobalPanel() {
|
|
|
1599
1646
|
storageKey: `${ADDON_ID}:globalSessionId`
|
|
1600
1647
|
});
|
|
1601
1648
|
const gitContext = useGitContext(client, connectionState);
|
|
1602
|
-
const
|
|
1649
|
+
const skillsConfig = useSkillsConfig(client, connectionState);
|
|
1650
|
+
const skills = useMemo2(
|
|
1651
|
+
() => getGlobalSkills(gitContext, skillsConfig.skills),
|
|
1652
|
+
[gitContext, skillsConfig.skills]
|
|
1653
|
+
);
|
|
1603
1654
|
const handleTokenSubmit = useCallback4(
|
|
1604
1655
|
(newToken, newPort) => {
|
|
1605
1656
|
setAddonState({ ...addonState, token: newToken, port: newPort || DEFAULT_PORT });
|
|
@@ -1631,35 +1682,36 @@ function GlobalPanel() {
|
|
|
1631
1682
|
[handleSend, setMessages]
|
|
1632
1683
|
);
|
|
1633
1684
|
if (authFailed && !token) {
|
|
1634
|
-
return /* @__PURE__ */
|
|
1685
|
+
return /* @__PURE__ */ React7.createElement("div", { style: styles6.page }, /* @__PURE__ */ React7.createElement(TokenInput, { onSubmit: handleTokenSubmit }));
|
|
1635
1686
|
}
|
|
1636
1687
|
const statusColor = connectionState === CONNECTION_STATES.CONNECTED ? "#4caf50" : connectionState === CONNECTION_STATES.DISCONNECTED ? "#f44336" : "#ff9800";
|
|
1637
1688
|
const statusLabel = connectionState === CONNECTION_STATES.CONNECTED ? "Connected" : connectionState === CONNECTION_STATES.CONNECTING ? "Connecting..." : connectionState === CONNECTION_STATES.RECONNECTING ? "Reconnecting..." : "Disconnected";
|
|
1638
|
-
return /* @__PURE__ */
|
|
1689
|
+
return /* @__PURE__ */ React7.createElement("div", { style: styles6.page }, /* @__PURE__ */ React7.createElement("div", { style: styles6.titleBar }, /* @__PURE__ */ React7.createElement("div", { style: styles6.titleLeft }, /* @__PURE__ */ React7.createElement("div", { style: styles6.title }, "Claude \u2014 Global Chat"), /* @__PURE__ */ React7.createElement("span", { style: { ...styles6.statusDot, backgroundColor: statusColor }, title: statusLabel }), /* @__PURE__ */ React7.createElement("span", { style: styles6.statusLabel }, statusLabel), /* @__PURE__ */ React7.createElement(
|
|
1639
1690
|
"span",
|
|
1640
1691
|
{
|
|
1641
|
-
style:
|
|
1692
|
+
style: styles6.infoIcon,
|
|
1642
1693
|
title: "Chat with Claude about your entire project. Not scoped to any specific component."
|
|
1643
1694
|
},
|
|
1644
|
-
/* @__PURE__ */
|
|
1645
|
-
)), /* @__PURE__ */
|
|
1695
|
+
/* @__PURE__ */ React7.createElement("svg", { viewBox: "0 0 16 16", width: "14", height: "14", fill: "currentColor" }, /* @__PURE__ */ React7.createElement("path", { d: "M8 0a8 8 0 1 0 0 16A8 8 0 0 0 8 0zm.93 12.588-.003.009H7.074l-.003-.01c-.027-.18-.04-.362-.04-.545 0-1.02.356-1.852 1.065-2.497.295-.268.59-.502.793-.737.2-.232.303-.493.303-.784 0-.318-.112-.564-.337-.738-.228-.177-.56-.266-.994-.266-.39 0-.738.074-1.046.222-.307.148-.57.35-.787.607l-.12.152-.94-.762.12-.152c.32-.395.727-.71 1.222-.943A3.77 3.77 0 0 1 7.92 5.4c.744 0 1.35.19 1.818.57.47.382.706.886.706 1.514 0 .474-.14.892-.42 1.254-.277.358-.656.68-1.137.966-.38.226-.636.463-.765.71-.13.25-.196.564-.196.943 0 .082.003.163.01.244l-.006-.013zM8 14.074a.87.87 0 0 1-.638-.262.87.87 0 0 1-.262-.638c0-.25.087-.463.262-.638A.87.87 0 0 1 8 12.274c.25 0 .463.087.638.262a.87.87 0 0 1 .262.638.87.87 0 0 1-.262.638A.87.87 0 0 1 8 14.074z" }))
|
|
1696
|
+
)), /* @__PURE__ */ React7.createElement("button", { style: styles6.backButton, onClick: handleBack, title: "Back to components" }, /* @__PURE__ */ React7.createElement("svg", { viewBox: "0 0 24 24", width: "14", height: "14", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React7.createElement("path", { d: "M19 12H5" }), /* @__PURE__ */ React7.createElement("path", { d: "M12 19l-7-7 7-7" })), /* @__PURE__ */ React7.createElement("span", { style: { marginLeft: "4px" } }, "Back"))), /* @__PURE__ */ React7.createElement("div", { style: styles6.toolsBar }, /* @__PURE__ */ React7.createElement(SkillsBar, { skills, onTrigger: handleSkillTrigger, disabled: !isConnected }), gitContext.branch && /* @__PURE__ */ React7.createElement("div", { style: styles6.gitContext }, /* @__PURE__ */ React7.createElement("div", { style: styles6.branchName }, /* @__PURE__ */ React7.createElement("span", { style: styles6.branchIcon, title: "Git branch" }, "\u2387"), gitContext.branch), gitContext.pr && /* @__PURE__ */ React7.createElement(
|
|
1646
1697
|
"a",
|
|
1647
1698
|
{
|
|
1648
1699
|
href: gitContext.pr.url,
|
|
1649
1700
|
target: "_blank",
|
|
1650
1701
|
rel: "noopener noreferrer",
|
|
1651
|
-
style:
|
|
1702
|
+
style: styles6.prLink,
|
|
1652
1703
|
title: gitContext.pr.title
|
|
1653
1704
|
},
|
|
1654
1705
|
"PR #",
|
|
1655
1706
|
gitContext.pr.number
|
|
1656
|
-
))), /* @__PURE__ */
|
|
1707
|
+
))), /* @__PURE__ */ React7.createElement("div", { style: styles6.chatArea }, /* @__PURE__ */ React7.createElement(MessageList, { messages, isProcessing }), /* @__PURE__ */ React7.createElement(
|
|
1657
1708
|
MessageInput,
|
|
1658
1709
|
{
|
|
1659
1710
|
onSend: handleSend,
|
|
1660
1711
|
disabled: !isConnected,
|
|
1661
1712
|
isProcessing,
|
|
1662
|
-
placeholder: "Ask Claude about your project..."
|
|
1713
|
+
placeholder: "Ask Claude about your project...",
|
|
1714
|
+
onCancel: cancelCommand
|
|
1663
1715
|
}
|
|
1664
1716
|
)));
|
|
1665
1717
|
}
|
|
@@ -1678,12 +1730,15 @@ function getInitialPort2() {
|
|
|
1678
1730
|
function getInitialToken2() {
|
|
1679
1731
|
var _a, _b;
|
|
1680
1732
|
try {
|
|
1733
|
+
if (typeof window !== "undefined" && window.__CLAUDE_DAEMON_TOKEN__) {
|
|
1734
|
+
return window.__CLAUDE_DAEMON_TOKEN__;
|
|
1735
|
+
}
|
|
1681
1736
|
return typeof process !== "undefined" && ((_a = process.env) == null ? void 0 : _a.STORYBOOK_CLAUDE_DAEMON_TOKEN) || typeof process !== "undefined" && ((_b = process.env) == null ? void 0 : _b.CLAUDE_DAEMON_TOKEN) || null;
|
|
1682
1737
|
} catch {
|
|
1683
1738
|
return null;
|
|
1684
1739
|
}
|
|
1685
1740
|
}
|
|
1686
|
-
var
|
|
1741
|
+
var styles6 = {
|
|
1687
1742
|
page: {
|
|
1688
1743
|
display: "flex",
|
|
1689
1744
|
flexDirection: "column",
|
|
@@ -1782,7 +1837,7 @@ var styles8 = {
|
|
|
1782
1837
|
};
|
|
1783
1838
|
|
|
1784
1839
|
// src/components/GlobalChatButton.jsx
|
|
1785
|
-
import
|
|
1840
|
+
import React8, { useCallback as useCallback5 } from "react";
|
|
1786
1841
|
import { useStorybookApi } from "storybook/manager-api";
|
|
1787
1842
|
import { Button } from "storybook/internal/components";
|
|
1788
1843
|
function GlobalChatButton() {
|
|
@@ -1790,7 +1845,7 @@ function GlobalChatButton() {
|
|
|
1790
1845
|
const handleClick = useCallback5(() => {
|
|
1791
1846
|
api.navigateUrl("/?path=/claude", { replace: false });
|
|
1792
1847
|
}, [api]);
|
|
1793
|
-
return /* @__PURE__ */
|
|
1848
|
+
return /* @__PURE__ */ React8.createElement(Button, { variant: "ghost", padding: "small", "aria-label": "Open Claude Global Chat", onClick: handleClick }, /* @__PURE__ */ React8.createElement(
|
|
1794
1849
|
"svg",
|
|
1795
1850
|
{
|
|
1796
1851
|
viewBox: "0 0 24 24",
|
|
@@ -1802,7 +1857,7 @@ function GlobalChatButton() {
|
|
|
1802
1857
|
strokeLinecap: "round",
|
|
1803
1858
|
strokeLinejoin: "round"
|
|
1804
1859
|
},
|
|
1805
|
-
/* @__PURE__ */
|
|
1860
|
+
/* @__PURE__ */ React8.createElement("path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" })
|
|
1806
1861
|
));
|
|
1807
1862
|
}
|
|
1808
1863
|
|
|
@@ -1810,7 +1865,7 @@ function GlobalChatButton() {
|
|
|
1810
1865
|
function ClaudePageRoute() {
|
|
1811
1866
|
const { path } = useStorybookState2();
|
|
1812
1867
|
if (path !== "/claude") return null;
|
|
1813
|
-
return /* @__PURE__ */
|
|
1868
|
+
return /* @__PURE__ */ React9.createElement(GlobalPanel, null);
|
|
1814
1869
|
}
|
|
1815
1870
|
addons.register(ADDON_ID, (api) => {
|
|
1816
1871
|
addons.add(PANEL_ID, {
|
package/package.json
CHANGED