@radnine/storybook-addon-claude 0.5.2 → 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 +201 -47
- package/package.json +1 -1
package/dist/manager.js
CHANGED
|
@@ -86,16 +86,16 @@ function MarkdownContent({ text }) {
|
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
// src/components/MessageList.jsx
|
|
89
|
-
function MessageList({ messages }) {
|
|
89
|
+
function MessageList({ messages, isProcessing }) {
|
|
90
90
|
const bottomRef = useRef(null);
|
|
91
91
|
useEffect(() => {
|
|
92
92
|
var _a;
|
|
93
93
|
(_a = bottomRef.current) == null ? void 0 : _a.scrollIntoView({ behavior: "smooth" });
|
|
94
|
-
}, [messages]);
|
|
94
|
+
}, [messages, isProcessing]);
|
|
95
95
|
if (messages.length === 0) {
|
|
96
96
|
return /* @__PURE__ */ React2.createElement("div", { style: styles.empty }, "No messages yet. Send a message to start chatting with Claude.");
|
|
97
97
|
}
|
|
98
|
-
return /* @__PURE__ */ React2.createElement("div", { style: styles.container }, messages.map((msg) => /* @__PURE__ */ React2.createElement(MessageItem, { key: msg.id, message: msg })), /* @__PURE__ */ React2.createElement("div", { ref: bottomRef }));
|
|
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 }));
|
|
99
99
|
}
|
|
100
100
|
function MessageItem({ message }) {
|
|
101
101
|
switch (message.type) {
|
|
@@ -107,6 +107,8 @@ function MessageItem({ message }) {
|
|
|
107
107
|
return /* @__PURE__ */ React2.createElement(OutputMessage, { data: message.data, replay: message.replay });
|
|
108
108
|
case "complete":
|
|
109
109
|
return /* @__PURE__ */ React2.createElement(CompleteMessage, { message });
|
|
110
|
+
case "cancelled":
|
|
111
|
+
return /* @__PURE__ */ React2.createElement(CancelledMessage, null);
|
|
110
112
|
case "error":
|
|
111
113
|
return /* @__PURE__ */ React2.createElement(ErrorMessage, { message });
|
|
112
114
|
default:
|
|
@@ -211,9 +213,20 @@ function GenericOutputMessage({ data, replay }) {
|
|
|
211
213
|
function CompleteMessage({ message }) {
|
|
212
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`));
|
|
213
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")));
|
|
218
|
+
}
|
|
214
219
|
function SkillInvocationMessage({ skill }) {
|
|
215
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)));
|
|
216
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" } })));
|
|
229
|
+
}
|
|
217
230
|
function ErrorMessage({ message }) {
|
|
218
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"));
|
|
219
232
|
}
|
|
@@ -398,6 +411,29 @@ var styles = {
|
|
|
398
411
|
fontSize: "11px",
|
|
399
412
|
color: "#777"
|
|
400
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
|
+
},
|
|
401
437
|
genericContent: {
|
|
402
438
|
margin: 0,
|
|
403
439
|
padding: "8px",
|
|
@@ -451,7 +487,7 @@ var styles = {
|
|
|
451
487
|
|
|
452
488
|
// src/components/MessageInput.jsx
|
|
453
489
|
import React3, { useState, useRef as useRef2 } from "react";
|
|
454
|
-
function MessageInput({ onSend, disabled, isProcessing, placeholder }) {
|
|
490
|
+
function MessageInput({ onSend, disabled, isProcessing, placeholder, onCancel }) {
|
|
455
491
|
const [text, setText] = useState("");
|
|
456
492
|
const textareaRef = useRef2(null);
|
|
457
493
|
const handleSend = () => {
|
|
@@ -464,7 +500,10 @@ function MessageInput({ onSend, disabled, isProcessing, placeholder }) {
|
|
|
464
500
|
}
|
|
465
501
|
};
|
|
466
502
|
const handleKeyDown = (e) => {
|
|
467
|
-
if (e.key === "
|
|
503
|
+
if (e.key === "Escape" && isProcessing && onCancel) {
|
|
504
|
+
e.preventDefault();
|
|
505
|
+
onCancel();
|
|
506
|
+
} else if (e.key === "Enter" && !e.shiftKey) {
|
|
468
507
|
e.preventDefault();
|
|
469
508
|
handleSend();
|
|
470
509
|
}
|
|
@@ -475,6 +514,29 @@ function MessageInput({ onSend, disabled, isProcessing, placeholder }) {
|
|
|
475
514
|
el.style.height = "auto";
|
|
476
515
|
el.style.height = Math.min(el.scrollHeight, 120) + "px";
|
|
477
516
|
};
|
|
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
|
+
}
|
|
478
540
|
return /* @__PURE__ */ React3.createElement("div", { style: styles2.container }, /* @__PURE__ */ React3.createElement(
|
|
479
541
|
"textarea",
|
|
480
542
|
{
|
|
@@ -498,7 +560,7 @@ function MessageInput({ onSend, disabled, isProcessing, placeholder }) {
|
|
|
498
560
|
disabled: disabled || !text.trim(),
|
|
499
561
|
title: "Send message (Enter)"
|
|
500
562
|
},
|
|
501
|
-
|
|
563
|
+
"Send"
|
|
502
564
|
));
|
|
503
565
|
}
|
|
504
566
|
var styles2 = {
|
|
@@ -537,6 +599,18 @@ var styles2 = {
|
|
|
537
599
|
buttonDisabled: {
|
|
538
600
|
backgroundColor: "#ccc",
|
|
539
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"
|
|
540
614
|
}
|
|
541
615
|
};
|
|
542
616
|
|
|
@@ -674,6 +748,7 @@ var WebSocketClient = class {
|
|
|
674
748
|
this._host = options.host || DEFAULT_HOST;
|
|
675
749
|
this._port = options.port || DEFAULT_PORT;
|
|
676
750
|
this._token = options.token || null;
|
|
751
|
+
this._daemonUrl = options.daemonUrl || null;
|
|
677
752
|
this._ws = null;
|
|
678
753
|
this._state = CONNECTION_STATES.DISCONNECTED;
|
|
679
754
|
this._listeners = /* @__PURE__ */ new Map();
|
|
@@ -693,7 +768,7 @@ var WebSocketClient = class {
|
|
|
693
768
|
}
|
|
694
769
|
/**
|
|
695
770
|
* Register an event listener.
|
|
696
|
-
* Events: 'state_change', 'session_activated', 'output', 'complete', 'error', 'pong'
|
|
771
|
+
* Events: 'state_change', 'session_activated', 'output', 'complete', 'error', 'pong', 'cancelled'
|
|
697
772
|
*/
|
|
698
773
|
on(event, callback) {
|
|
699
774
|
if (!this._listeners.has(event)) {
|
|
@@ -716,7 +791,7 @@ var WebSocketClient = class {
|
|
|
716
791
|
this._setState(CONNECTION_STATES.CONNECTING);
|
|
717
792
|
}
|
|
718
793
|
const params = this._token ? `?token=${encodeURIComponent(this._token)}` : "";
|
|
719
|
-
const url =
|
|
794
|
+
const url = this._buildUrl(params);
|
|
720
795
|
try {
|
|
721
796
|
this._ws = new WebSocket(url);
|
|
722
797
|
} catch (err) {
|
|
@@ -768,6 +843,12 @@ var WebSocketClient = class {
|
|
|
768
843
|
setToken(token) {
|
|
769
844
|
this._token = token;
|
|
770
845
|
}
|
|
846
|
+
/**
|
|
847
|
+
* Update the daemon URL for remote environments.
|
|
848
|
+
*/
|
|
849
|
+
setDaemonUrl(url) {
|
|
850
|
+
this._daemonUrl = url;
|
|
851
|
+
}
|
|
771
852
|
/**
|
|
772
853
|
* Activate a session. Must be called after connecting.
|
|
773
854
|
*/
|
|
@@ -798,6 +879,16 @@ var WebSocketClient = class {
|
|
|
798
879
|
sessionId
|
|
799
880
|
});
|
|
800
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
|
+
}
|
|
801
892
|
/**
|
|
802
893
|
* Send a query to the daemon.
|
|
803
894
|
*/
|
|
@@ -810,6 +901,28 @@ var WebSocketClient = class {
|
|
|
810
901
|
// ---------------------------------------------------------------------------
|
|
811
902
|
// Internal
|
|
812
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
|
+
}
|
|
813
926
|
_send(msg) {
|
|
814
927
|
if (this._ws && this._ws.readyState === WebSocket.OPEN) {
|
|
815
928
|
this._ws.send(JSON.stringify(msg));
|
|
@@ -831,6 +944,7 @@ var WebSocketClient = class {
|
|
|
831
944
|
case "user_input":
|
|
832
945
|
case "pong":
|
|
833
946
|
case "query_result":
|
|
947
|
+
case "cancelled":
|
|
834
948
|
this._emit(msg.type, msg);
|
|
835
949
|
break;
|
|
836
950
|
default:
|
|
@@ -922,6 +1036,7 @@ function useClaudeSession(options = {}) {
|
|
|
922
1036
|
const clientRef = useRef3(null);
|
|
923
1037
|
const sessionIdRef = useRef3(sessionId);
|
|
924
1038
|
sessionIdRef.current = sessionId;
|
|
1039
|
+
const currentCommandIdRef = useRef3(null);
|
|
925
1040
|
useEffect2(() => {
|
|
926
1041
|
const client = new WebSocketClient({ host, port, token });
|
|
927
1042
|
clientRef.current = client;
|
|
@@ -980,6 +1095,12 @@ function useClaudeSession(options = {}) {
|
|
|
980
1095
|
{ type: "error", ...msg, id: crypto.randomUUID(), timestamp: Date.now() }
|
|
981
1096
|
]);
|
|
982
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;
|
|
983
1104
|
})
|
|
984
1105
|
];
|
|
985
1106
|
return () => {
|
|
@@ -1019,7 +1140,9 @@ ${text}` : text;
|
|
|
1019
1140
|
}
|
|
1020
1141
|
]);
|
|
1021
1142
|
setIsProcessing(true);
|
|
1022
|
-
|
|
1143
|
+
const commandId = crypto.randomUUID();
|
|
1144
|
+
currentCommandIdRef.current = commandId;
|
|
1145
|
+
client.sendCommand(sessionIdRef.current, fullText, commandId);
|
|
1023
1146
|
},
|
|
1024
1147
|
[]
|
|
1025
1148
|
);
|
|
@@ -1061,6 +1184,12 @@ ${text}` : text;
|
|
|
1061
1184
|
startSession();
|
|
1062
1185
|
}
|
|
1063
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
|
+
}, []);
|
|
1064
1193
|
return {
|
|
1065
1194
|
connectionState,
|
|
1066
1195
|
messages,
|
|
@@ -1073,44 +1202,42 @@ ${text}` : text;
|
|
|
1073
1202
|
setMessages,
|
|
1074
1203
|
disconnect,
|
|
1075
1204
|
newChat,
|
|
1205
|
+
cancelCommand,
|
|
1076
1206
|
isConnected: connectionState === CONNECTION_STATES.CONNECTED,
|
|
1077
1207
|
client: clientRef.current
|
|
1078
1208
|
};
|
|
1079
1209
|
}
|
|
1080
1210
|
|
|
1081
|
-
// src/
|
|
1211
|
+
// src/useDaemonQuery.js
|
|
1082
1212
|
import { useState as useState4, useEffect as useEffect3, useRef as useRef4, useCallback as useCallback2 } from "react";
|
|
1083
|
-
function
|
|
1084
|
-
const [
|
|
1085
|
-
const [
|
|
1213
|
+
function useDaemonQuery(client, connectionState, queryType, pollIntervalMs) {
|
|
1214
|
+
const [data, setData] = useState4(null);
|
|
1215
|
+
const [error, setError] = useState4(null);
|
|
1086
1216
|
const intervalRef = useRef4(null);
|
|
1087
|
-
const
|
|
1088
|
-
const
|
|
1217
|
+
const dataRef = useRef4(null);
|
|
1218
|
+
const fetchQuery = useCallback2(() => {
|
|
1089
1219
|
if (!client || !client.isConnected) return;
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
}, [client]);
|
|
1220
|
+
client.sendQuery(queryType);
|
|
1221
|
+
}, [client, queryType]);
|
|
1093
1222
|
useEffect3(() => {
|
|
1094
1223
|
if (!client) return;
|
|
1095
1224
|
const unsub = client.on("query_result", (msg) => {
|
|
1096
|
-
if (msg.queryType ===
|
|
1097
|
-
|
|
1098
|
-
|
|
1225
|
+
if (msg.queryType === queryType) {
|
|
1226
|
+
dataRef.current = msg.data || null;
|
|
1227
|
+
setData(msg.data || null);
|
|
1228
|
+
setError(null);
|
|
1099
1229
|
}
|
|
1100
1230
|
});
|
|
1101
1231
|
const unsubErr = client.on("error", (msg) => {
|
|
1102
1232
|
if (msg.code === "UNKNOWN_TYPE" || msg.code === "UNKNOWN_QUERY") {
|
|
1103
|
-
|
|
1233
|
+
setError(msg.message || "Unsupported query");
|
|
1104
1234
|
}
|
|
1105
1235
|
});
|
|
1106
|
-
|
|
1236
|
+
return () => {
|
|
1107
1237
|
unsub();
|
|
1108
1238
|
unsubErr();
|
|
1109
1239
|
};
|
|
1110
|
-
|
|
1111
|
-
if (unsubRef.current) unsubRef.current();
|
|
1112
|
-
};
|
|
1113
|
-
}, [client]);
|
|
1240
|
+
}, [client, queryType]);
|
|
1114
1241
|
useEffect3(() => {
|
|
1115
1242
|
if (connectionState !== CONNECTION_STATES.CONNECTED) {
|
|
1116
1243
|
if (intervalRef.current) {
|
|
@@ -1119,18 +1246,25 @@ function useGitContext(client, connectionState) {
|
|
|
1119
1246
|
}
|
|
1120
1247
|
return;
|
|
1121
1248
|
}
|
|
1122
|
-
|
|
1123
|
-
intervalRef.current = setInterval(
|
|
1249
|
+
fetchQuery();
|
|
1250
|
+
intervalRef.current = setInterval(fetchQuery, pollIntervalMs);
|
|
1124
1251
|
return () => {
|
|
1125
1252
|
if (intervalRef.current) {
|
|
1126
1253
|
clearInterval(intervalRef.current);
|
|
1127
1254
|
intervalRef.current = null;
|
|
1128
1255
|
}
|
|
1129
1256
|
};
|
|
1130
|
-
}, [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);
|
|
1131
1265
|
return {
|
|
1132
|
-
branch: (
|
|
1133
|
-
pr: (
|
|
1266
|
+
branch: (data == null ? void 0 : data.branch) || null,
|
|
1267
|
+
pr: (data == null ? void 0 : data.pr) || null,
|
|
1134
1268
|
loading
|
|
1135
1269
|
};
|
|
1136
1270
|
}
|
|
@@ -1202,6 +1336,7 @@ function ClaudePanel({ active }) {
|
|
|
1202
1336
|
sendMessage,
|
|
1203
1337
|
startSession,
|
|
1204
1338
|
newChat,
|
|
1339
|
+
cancelCommand,
|
|
1205
1340
|
isConnected,
|
|
1206
1341
|
client
|
|
1207
1342
|
} = useClaudeSession({
|
|
@@ -1256,12 +1391,13 @@ function ClaudePanel({ active }) {
|
|
|
1256
1391
|
"aria-label": "New Chat"
|
|
1257
1392
|
},
|
|
1258
1393
|
"New Chat"
|
|
1259
|
-
))), /* @__PURE__ */ React5.createElement(MessageList, { messages }), /* @__PURE__ */ React5.createElement(
|
|
1394
|
+
))), /* @__PURE__ */ React5.createElement(MessageList, { messages, isProcessing }), /* @__PURE__ */ React5.createElement(
|
|
1260
1395
|
MessageInput,
|
|
1261
1396
|
{
|
|
1262
1397
|
onSend: handleSend,
|
|
1263
1398
|
disabled: !isConnected,
|
|
1264
|
-
isProcessing
|
|
1399
|
+
isProcessing,
|
|
1400
|
+
onCancel: cancelCommand
|
|
1265
1401
|
}
|
|
1266
1402
|
));
|
|
1267
1403
|
}
|
|
@@ -1280,6 +1416,9 @@ function getInitialPort() {
|
|
|
1280
1416
|
function getInitialToken() {
|
|
1281
1417
|
var _a, _b;
|
|
1282
1418
|
try {
|
|
1419
|
+
if (typeof window !== "undefined" && window.__CLAUDE_DAEMON_TOKEN__) {
|
|
1420
|
+
return window.__CLAUDE_DAEMON_TOKEN__;
|
|
1421
|
+
}
|
|
1283
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;
|
|
1284
1423
|
} catch {
|
|
1285
1424
|
return null;
|
|
@@ -1382,7 +1521,7 @@ function SkillsBar({ skills, onTrigger, disabled }) {
|
|
|
1382
1521
|
},
|
|
1383
1522
|
onClick: () => onTrigger(skill),
|
|
1384
1523
|
disabled,
|
|
1385
|
-
title: skill.prompt
|
|
1524
|
+
title: skill.description || skill.prompt
|
|
1386
1525
|
},
|
|
1387
1526
|
/* @__PURE__ */ React6.createElement("span", { style: styles5.icon }, skill.icon),
|
|
1388
1527
|
/* @__PURE__ */ React6.createElement("span", null, skill.label)
|
|
@@ -1419,8 +1558,18 @@ var styles5 = {
|
|
|
1419
1558
|
}
|
|
1420
1559
|
};
|
|
1421
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
|
+
|
|
1422
1571
|
// src/skills.js
|
|
1423
|
-
var
|
|
1572
|
+
var DEFAULT_SKILLS = [
|
|
1424
1573
|
{
|
|
1425
1574
|
id: "sync-components",
|
|
1426
1575
|
label: "Sync Components",
|
|
@@ -1456,17 +1605,13 @@ function getPrSkill(pr) {
|
|
|
1456
1605
|
prompt: "Create a new pull request for the current branch with a summary of all changes."
|
|
1457
1606
|
};
|
|
1458
1607
|
}
|
|
1459
|
-
function getGlobalSkills(gitContext) {
|
|
1608
|
+
function getGlobalSkills(gitContext, configSkills) {
|
|
1460
1609
|
const pr = (gitContext == null ? void 0 : gitContext.pr) || null;
|
|
1610
|
+
const skills = configSkills && configSkills.length > 0 ? configSkills : DEFAULT_SKILLS;
|
|
1461
1611
|
return [
|
|
1462
|
-
|
|
1463
|
-
// Sync Components
|
|
1612
|
+
skills[0],
|
|
1464
1613
|
getPrSkill(pr),
|
|
1465
|
-
|
|
1466
|
-
STATIC_SKILLS[1],
|
|
1467
|
-
// Run Tests
|
|
1468
|
-
STATIC_SKILLS[2]
|
|
1469
|
-
// Audit Stories
|
|
1614
|
+
...skills.slice(1)
|
|
1470
1615
|
];
|
|
1471
1616
|
}
|
|
1472
1617
|
|
|
@@ -1490,6 +1635,7 @@ function GlobalPanel() {
|
|
|
1490
1635
|
sendMessage,
|
|
1491
1636
|
startSession,
|
|
1492
1637
|
setMessages,
|
|
1638
|
+
cancelCommand,
|
|
1493
1639
|
isConnected,
|
|
1494
1640
|
client
|
|
1495
1641
|
} = useClaudeSession({
|
|
@@ -1500,7 +1646,11 @@ function GlobalPanel() {
|
|
|
1500
1646
|
storageKey: `${ADDON_ID}:globalSessionId`
|
|
1501
1647
|
});
|
|
1502
1648
|
const gitContext = useGitContext(client, connectionState);
|
|
1503
|
-
const
|
|
1649
|
+
const skillsConfig = useSkillsConfig(client, connectionState);
|
|
1650
|
+
const skills = useMemo2(
|
|
1651
|
+
() => getGlobalSkills(gitContext, skillsConfig.skills),
|
|
1652
|
+
[gitContext, skillsConfig.skills]
|
|
1653
|
+
);
|
|
1504
1654
|
const handleTokenSubmit = useCallback4(
|
|
1505
1655
|
(newToken, newPort) => {
|
|
1506
1656
|
setAddonState({ ...addonState, token: newToken, port: newPort || DEFAULT_PORT });
|
|
@@ -1554,13 +1704,14 @@ function GlobalPanel() {
|
|
|
1554
1704
|
},
|
|
1555
1705
|
"PR #",
|
|
1556
1706
|
gitContext.pr.number
|
|
1557
|
-
))), /* @__PURE__ */ React7.createElement("div", { style: styles6.chatArea }, /* @__PURE__ */ React7.createElement(MessageList, { messages }), /* @__PURE__ */ React7.createElement(
|
|
1707
|
+
))), /* @__PURE__ */ React7.createElement("div", { style: styles6.chatArea }, /* @__PURE__ */ React7.createElement(MessageList, { messages, isProcessing }), /* @__PURE__ */ React7.createElement(
|
|
1558
1708
|
MessageInput,
|
|
1559
1709
|
{
|
|
1560
1710
|
onSend: handleSend,
|
|
1561
1711
|
disabled: !isConnected,
|
|
1562
1712
|
isProcessing,
|
|
1563
|
-
placeholder: "Ask Claude about your project..."
|
|
1713
|
+
placeholder: "Ask Claude about your project...",
|
|
1714
|
+
onCancel: cancelCommand
|
|
1564
1715
|
}
|
|
1565
1716
|
)));
|
|
1566
1717
|
}
|
|
@@ -1579,6 +1730,9 @@ function getInitialPort2() {
|
|
|
1579
1730
|
function getInitialToken2() {
|
|
1580
1731
|
var _a, _b;
|
|
1581
1732
|
try {
|
|
1733
|
+
if (typeof window !== "undefined" && window.__CLAUDE_DAEMON_TOKEN__) {
|
|
1734
|
+
return window.__CLAUDE_DAEMON_TOKEN__;
|
|
1735
|
+
}
|
|
1582
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;
|
|
1583
1737
|
} catch {
|
|
1584
1738
|
return null;
|
package/package.json
CHANGED