@radnine/storybook-addon-claude 0.2.4 → 0.2.6
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/Panel.js +20 -1
- package/dist/WebSocketClient.js +1 -0
- package/dist/components/MessageList.js +56 -3
- package/dist/useClaudeSession.js +17 -0
- package/package.json +1 -1
package/dist/Panel.js
CHANGED
|
@@ -27,7 +27,7 @@ function ClaudePanel({
|
|
|
27
27
|
// Persisted addon state for the token and port
|
|
28
28
|
const [addonState, setAddonState] = (0, _managerApi.useAddonState)(_constants.ADDON_ID, {
|
|
29
29
|
token: getInitialToken(),
|
|
30
|
-
port:
|
|
30
|
+
port: getInitialPort(),
|
|
31
31
|
contextEnabled: true
|
|
32
32
|
});
|
|
33
33
|
const token = addonState?.token || null;
|
|
@@ -124,6 +124,25 @@ function ClaudePanel({
|
|
|
124
124
|
});
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
+
/**
|
|
128
|
+
* Read initial port from environment or global variable if available.
|
|
129
|
+
* Supports: window.__CLAUDE_DAEMON_PORT__ (set via managerHead in main.ts)
|
|
130
|
+
* process.env.STORYBOOK_CLAUDE_DAEMON_PORT (if available)
|
|
131
|
+
*/
|
|
132
|
+
function getInitialPort() {
|
|
133
|
+
try {
|
|
134
|
+
// Manager-injected global (most reliable for addon panels)
|
|
135
|
+
if (typeof window !== 'undefined' && window.__CLAUDE_DAEMON_PORT__) {
|
|
136
|
+
return parseInt(window.__CLAUDE_DAEMON_PORT__, 10) || _constants.DEFAULT_PORT;
|
|
137
|
+
}
|
|
138
|
+
// Env var fallback (works in preview iframe with Vite replacement)
|
|
139
|
+
const envPort = typeof process !== 'undefined' && process.env?.STORYBOOK_CLAUDE_DAEMON_PORT || null;
|
|
140
|
+
return envPort ? parseInt(envPort, 10) : _constants.DEFAULT_PORT;
|
|
141
|
+
} catch {
|
|
142
|
+
return _constants.DEFAULT_PORT;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
127
146
|
/**
|
|
128
147
|
* Read initial token from environment variable if available.
|
|
129
148
|
*/
|
package/dist/WebSocketClient.js
CHANGED
|
@@ -86,8 +86,14 @@ function OutputMessage({
|
|
|
86
86
|
replay
|
|
87
87
|
}) {
|
|
88
88
|
if (!data) return null;
|
|
89
|
-
|
|
90
|
-
|
|
89
|
+
|
|
90
|
+
// Classify the message the same way the daemon's message-parser does:
|
|
91
|
+
// - assistant with tool_use content → tool_use
|
|
92
|
+
// - user with tool_result content → tool_result
|
|
93
|
+
// - plain user echo → hide (noise)
|
|
94
|
+
// - system init → hide (noise)
|
|
95
|
+
const classifiedType = classifyOutputType(data);
|
|
96
|
+
switch (classifiedType) {
|
|
91
97
|
case 'assistant':
|
|
92
98
|
return /*#__PURE__*/(0, _jsxRuntime.jsx)(AssistantMessage, {
|
|
93
99
|
data: data,
|
|
@@ -113,14 +119,61 @@ function OutputMessage({
|
|
|
113
119
|
return /*#__PURE__*/(0, _jsxRuntime.jsx)(RateLimitMessage, {
|
|
114
120
|
data: data
|
|
115
121
|
});
|
|
122
|
+
case '_skip':
|
|
123
|
+
return null;
|
|
116
124
|
default:
|
|
117
|
-
// If data is a classified output with message content, try to extract text
|
|
118
125
|
return /*#__PURE__*/(0, _jsxRuntime.jsx)(GenericOutputMessage, {
|
|
119
126
|
data: data,
|
|
120
127
|
replay: replay
|
|
121
128
|
});
|
|
122
129
|
}
|
|
123
130
|
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Classify a raw Claude CLI stream-json message into a display type.
|
|
134
|
+
*
|
|
135
|
+
* Claude CLI emits:
|
|
136
|
+
* { type: 'assistant', message: { content: [...] } } — may contain text and/or tool_use blocks
|
|
137
|
+
* { type: 'user', message: { content: [...] } } — echoed tool_result blocks (internal noise)
|
|
138
|
+
* { type: 'system', subtype: 'init', ... } — system init (internal noise)
|
|
139
|
+
*
|
|
140
|
+
* We reclassify so the UI routes to the right renderer.
|
|
141
|
+
*/
|
|
142
|
+
function classifyOutputType(data) {
|
|
143
|
+
if (!data || typeof data !== 'object') return undefined;
|
|
144
|
+
const rawType = data.type;
|
|
145
|
+
const content = data?.message?.content || data?.content;
|
|
146
|
+
const contentArray = Array.isArray(content) ? content : [];
|
|
147
|
+
switch (rawType) {
|
|
148
|
+
case 'assistant':
|
|
149
|
+
{
|
|
150
|
+
const hasToolUse = contentArray.some(b => b?.type === 'tool_use');
|
|
151
|
+
const hasText = contentArray.some(b => b?.type === 'text' && b.text?.trim());
|
|
152
|
+
// Only thinking blocks and no text/tool_use — skip (internal noise)
|
|
153
|
+
const hasOnlyThinking = contentArray.length > 0 && contentArray.every(b => b?.type === 'thinking');
|
|
154
|
+
if (hasOnlyThinking) return '_skip';
|
|
155
|
+
// Tool use with no meaningful text → tool_use renderer
|
|
156
|
+
if (hasToolUse && !hasText) return 'tool_use';
|
|
157
|
+
return 'assistant';
|
|
158
|
+
}
|
|
159
|
+
case 'user':
|
|
160
|
+
{
|
|
161
|
+
// User messages with tool_result content are internal echoes — render as tool_result
|
|
162
|
+
const hasToolResult = contentArray.some(b => b?.type === 'tool_result');
|
|
163
|
+
if (hasToolResult) return 'tool_result';
|
|
164
|
+
// Plain user echo is noise — skip
|
|
165
|
+
return '_skip';
|
|
166
|
+
}
|
|
167
|
+
case 'system':
|
|
168
|
+
{
|
|
169
|
+
// System init messages are noise — skip
|
|
170
|
+
if (data.subtype === 'init') return '_skip';
|
|
171
|
+
return 'system';
|
|
172
|
+
}
|
|
173
|
+
default:
|
|
174
|
+
return rawType;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
124
177
|
function AssistantMessage({
|
|
125
178
|
data,
|
|
126
179
|
replay
|
package/dist/useClaudeSession.js
CHANGED
|
@@ -71,6 +71,23 @@ function useClaudeSession(options = {}) {
|
|
|
71
71
|
...msg,
|
|
72
72
|
id: crypto.randomUUID()
|
|
73
73
|
}]);
|
|
74
|
+
}), client.on('user_input', msg => {
|
|
75
|
+
if (msg.sessionId !== sessionIdRef.current) return;
|
|
76
|
+
// Replayed user messages from session history — strip context prefix
|
|
77
|
+
let text = msg.text || '';
|
|
78
|
+
const ctxMarker = '[Context from Storybook]';
|
|
79
|
+
if (text.startsWith(ctxMarker)) {
|
|
80
|
+
// Strip everything up to the double-newline separator
|
|
81
|
+
const idx = text.indexOf('\n\n');
|
|
82
|
+
text = idx >= 0 ? text.slice(idx + 2) : text;
|
|
83
|
+
}
|
|
84
|
+
setMessages(prev => [...prev, {
|
|
85
|
+
type: 'user_input',
|
|
86
|
+
text,
|
|
87
|
+
id: crypto.randomUUID(),
|
|
88
|
+
timestamp: msg.timestamp,
|
|
89
|
+
replay: true
|
|
90
|
+
}]);
|
|
74
91
|
}), client.on('complete', msg => {
|
|
75
92
|
if (msg.sessionId !== sessionIdRef.current) return;
|
|
76
93
|
setMessages(prev => [...prev, {
|
package/package.json
CHANGED