@radnine/storybook-addon-claude 0.3.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,14 +6,14 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.GlobalPanel = GlobalPanel;
7
7
  var _react = _interopRequireWildcard(require("react"));
8
8
  var _managerApi = require("storybook/manager-api");
9
- var _ConnectionStatus = require("./components/ConnectionStatus");
10
9
  var _MessageList = require("./components/MessageList");
11
10
  var _MessageInput = require("./components/MessageInput");
12
11
  var _TokenInput = require("./components/TokenInput");
13
- var _GitContextBar = require("./components/GitContextBar");
14
12
  var _useClaudeSession = require("./useClaudeSession");
13
+ var _SkillsBar = require("./components/SkillsBar");
15
14
  var _useGitContext = require("./useGitContext");
16
15
  var _constants = require("./constants");
16
+ var _skills = require("./skills");
17
17
  var _jsxRuntime = require("react/jsx-runtime");
18
18
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
19
19
  /**
@@ -41,7 +41,7 @@ function GlobalPanel() {
41
41
  authFailed,
42
42
  sendMessage,
43
43
  startSession,
44
- disconnect,
44
+ setMessages,
45
45
  isConnected,
46
46
  client
47
47
  } = (0, _useClaudeSession.useClaudeSession)({
@@ -54,6 +54,7 @@ function GlobalPanel() {
54
54
 
55
55
  // Git context from daemon
56
56
  const gitContext = (0, _useGitContext.useGitContext)(client, connectionState);
57
+ const skills = (0, _react.useMemo)(() => (0, _skills.getGlobalSkills)(gitContext), [gitContext]);
57
58
  const handleTokenSubmit = (0, _react.useCallback)((newToken, newPort) => {
58
59
  setAddonState({
59
60
  ...addonState,
@@ -61,19 +62,23 @@ function GlobalPanel() {
61
62
  port: newPort || _constants.DEFAULT_PORT
62
63
  });
63
64
  }, [addonState, setAddonState]);
64
- const handleDisconnect = (0, _react.useCallback)(() => {
65
- disconnect();
66
- setAddonState({
67
- ...addonState,
68
- token: null
69
- });
70
- }, [addonState, setAddonState, disconnect]);
71
65
  const handleSend = (0, _react.useCallback)(text => {
72
66
  if (!sessionId) {
73
67
  startSession(_constants.GLOBAL_SESSION_KEY);
74
68
  }
75
69
  sendMessage(text);
76
70
  }, [sessionId, startSession, sendMessage]);
71
+ const handleSkillTrigger = (0, _react.useCallback)(skill => {
72
+ // Insert a visual indicator in the chat
73
+ setMessages(prev => [...prev, {
74
+ type: 'skill_invocation',
75
+ skill,
76
+ id: crypto.randomUUID(),
77
+ timestamp: Date.now()
78
+ }]);
79
+ // Send the skill's prompt through the normal chat flow
80
+ handleSend(skill.prompt);
81
+ }, [handleSend, setMessages]);
77
82
  if (authFailed && !token) {
78
83
  return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
79
84
  style: styles.page,
@@ -82,57 +87,91 @@ function GlobalPanel() {
82
87
  })
83
88
  });
84
89
  }
90
+ const statusColor = connectionState === _constants.CONNECTION_STATES.CONNECTED ? '#4caf50' : connectionState === _constants.CONNECTION_STATES.DISCONNECTED ? '#f44336' : '#ff9800';
91
+ const statusLabel = connectionState === _constants.CONNECTION_STATES.CONNECTED ? 'Connected' : connectionState === _constants.CONNECTION_STATES.CONNECTING ? 'Connecting...' : connectionState === _constants.CONNECTION_STATES.RECONNECTING ? 'Reconnecting...' : 'Disconnected';
85
92
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
86
93
  style: styles.page,
87
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
88
- style: styles.header,
89
- children: /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
90
- style: styles.headerRow,
91
- children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
92
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
93
- style: styles.title,
94
- children: "Claude \u2014 Global Chat"
95
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
96
- style: styles.subtitle,
97
- children: "Chat with Claude about your entire project. Not scoped to any specific component."
98
- })]
99
- }), /*#__PURE__*/(0, _jsxRuntime.jsxs)("button", {
100
- style: styles.backButton,
101
- onClick: handleBack,
102
- title: "Back to components",
103
- children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)("svg", {
104
- viewBox: "0 0 24 24",
94
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
95
+ style: styles.titleBar,
96
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
97
+ style: styles.titleLeft,
98
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
99
+ style: styles.title,
100
+ children: "Claude \u2014 Global Chat"
101
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
102
+ style: {
103
+ ...styles.statusDot,
104
+ backgroundColor: statusColor
105
+ },
106
+ title: statusLabel
107
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
108
+ style: styles.statusLabel,
109
+ children: statusLabel
110
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
111
+ style: styles.infoIcon,
112
+ title: "Chat with Claude about your entire project. Not scoped to any specific component.",
113
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("svg", {
114
+ viewBox: "0 0 16 16",
105
115
  width: "14",
106
116
  height: "14",
107
- fill: "none",
108
- stroke: "currentColor",
109
- strokeWidth: "2",
110
- strokeLinecap: "round",
111
- strokeLinejoin: "round",
112
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("path", {
113
- d: "M19 12H5"
114
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)("path", {
115
- d: "M12 19l-7-7 7-7"
116
- })]
117
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
118
- style: {
119
- marginLeft: '4px'
120
- },
121
- children: "Back"
117
+ fill: "currentColor",
118
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("path", {
119
+ 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"
120
+ })
121
+ })
122
+ })]
123
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)("button", {
124
+ style: styles.backButton,
125
+ onClick: handleBack,
126
+ title: "Back to components",
127
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)("svg", {
128
+ viewBox: "0 0 24 24",
129
+ width: "14",
130
+ height: "14",
131
+ fill: "none",
132
+ stroke: "currentColor",
133
+ strokeWidth: "2",
134
+ strokeLinecap: "round",
135
+ strokeLinejoin: "round",
136
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("path", {
137
+ d: "M19 12H5"
138
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("path", {
139
+ d: "M12 19l-7-7 7-7"
122
140
  })]
141
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
142
+ style: {
143
+ marginLeft: '4px'
144
+ },
145
+ children: "Back"
123
146
  })]
124
- })
147
+ })]
148
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
149
+ style: styles.toolsBar,
150
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_SkillsBar.SkillsBar, {
151
+ skills: skills,
152
+ onTrigger: handleSkillTrigger,
153
+ disabled: !isConnected
154
+ }), gitContext.branch && /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
155
+ style: styles.gitContext,
156
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
157
+ style: styles.branchName,
158
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
159
+ style: styles.branchIcon,
160
+ title: "Git branch",
161
+ children: "\u2387"
162
+ }), gitContext.branch]
163
+ }), gitContext.pr && /*#__PURE__*/(0, _jsxRuntime.jsxs)("a", {
164
+ href: gitContext.pr.url,
165
+ target: "_blank",
166
+ rel: "noopener noreferrer",
167
+ style: styles.prLink,
168
+ title: gitContext.pr.title,
169
+ children: ["PR #", gitContext.pr.number]
170
+ })]
171
+ })]
125
172
  }), /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
126
173
  style: styles.chatArea,
127
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_ConnectionStatus.ConnectionStatus, {
128
- state: connectionState,
129
- sessionId: sessionId,
130
- onDisconnect: handleDisconnect
131
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_GitContextBar.GitContextBar, {
132
- branch: gitContext.branch,
133
- pr: gitContext.pr,
134
- loading: gitContext.loading
135
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_MessageList.MessageList, {
174
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_MessageList.MessageList, {
136
175
  messages: messages
137
176
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_MessageInput.MessageInput, {
138
177
  onSend: handleSend,
@@ -168,14 +207,40 @@ const styles = {
168
207
  height: '100vh',
169
208
  fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif'
170
209
  },
171
- header: {
172
- padding: '16px 24px',
210
+ // Bar 1
211
+ titleBar: {
212
+ display: 'flex',
213
+ justifyContent: 'space-between',
214
+ alignItems: 'center',
215
+ padding: '10px 16px',
173
216
  borderBottom: '1px solid rgba(0,0,0,0.1)',
174
217
  backgroundColor: '#fafafa'
175
218
  },
176
- headerRow: {
219
+ titleLeft: {
177
220
  display: 'flex',
178
- justifyContent: 'space-between',
221
+ alignItems: 'center',
222
+ gap: '8px'
223
+ },
224
+ title: {
225
+ fontSize: '16px',
226
+ fontWeight: 600,
227
+ color: '#333'
228
+ },
229
+ statusDot: {
230
+ width: '8px',
231
+ height: '8px',
232
+ borderRadius: '50%',
233
+ display: 'inline-block',
234
+ flexShrink: 0
235
+ },
236
+ statusLabel: {
237
+ fontSize: '12px',
238
+ color: '#888'
239
+ },
240
+ infoIcon: {
241
+ color: '#bbb',
242
+ cursor: 'help',
243
+ display: 'inline-flex',
179
244
  alignItems: 'center'
180
245
  },
181
246
  backButton: {
@@ -190,16 +255,41 @@ const styles = {
190
255
  cursor: 'pointer',
191
256
  whiteSpace: 'nowrap'
192
257
  },
193
- title: {
194
- fontSize: '18px',
195
- fontWeight: 600,
196
- color: '#333'
258
+ // Bar 2
259
+ toolsBar: {
260
+ display: 'flex',
261
+ alignItems: 'center',
262
+ justifyContent: 'space-between',
263
+ borderBottom: '1px solid rgba(0,0,0,0.06)',
264
+ backgroundColor: '#fff'
197
265
  },
198
- subtitle: {
199
- fontSize: '13px',
200
- color: '#888',
201
- marginTop: '4px'
266
+ gitContext: {
267
+ display: 'flex',
268
+ flexDirection: 'column',
269
+ alignItems: 'flex-end',
270
+ gap: '1px',
271
+ padding: '6px 12px',
272
+ flexShrink: 0
273
+ },
274
+ branchName: {
275
+ fontFamily: 'monospace',
276
+ fontSize: '11px',
277
+ color: '#555',
278
+ display: 'flex',
279
+ alignItems: 'center',
280
+ gap: '3px'
281
+ },
282
+ branchIcon: {
283
+ fontSize: '12px',
284
+ color: '#888'
285
+ },
286
+ prLink: {
287
+ color: '#0366d6',
288
+ textDecoration: 'none',
289
+ fontFamily: 'monospace',
290
+ fontSize: '11px'
202
291
  },
292
+ // Chat area
203
293
  chatArea: {
204
294
  display: 'flex',
205
295
  flexDirection: 'column',
@@ -53,6 +53,10 @@ function MessageItem({
53
53
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(UserMessage, {
54
54
  text: message.text
55
55
  });
56
+ case 'skill_invocation':
57
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(SkillInvocationMessage, {
58
+ skill: message.skill
59
+ });
56
60
  case 'output':
57
61
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(OutputMessage, {
58
62
  data: message.data,
@@ -354,6 +358,23 @@ function CompleteMessage({
354
358
  })
355
359
  });
356
360
  }
361
+ function SkillInvocationMessage({
362
+ skill
363
+ }) {
364
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
365
+ style: styles.skillRow,
366
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
367
+ style: styles.skillBubble,
368
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
369
+ style: styles.skillIcon,
370
+ children: skill.icon
371
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)("span", {
372
+ style: styles.skillLabel,
373
+ children: ["Skill: ", skill.label]
374
+ })]
375
+ })
376
+ });
377
+ }
357
378
  function ErrorMessage({
358
379
  message
359
380
  }) {
@@ -567,6 +588,28 @@ const styles = {
567
588
  maxHeight: '200px',
568
589
  maxWidth: '90%'
569
590
  },
591
+ // Skill invocation
592
+ skillRow: {
593
+ display: 'flex',
594
+ justifyContent: 'center'
595
+ },
596
+ skillBubble: {
597
+ display: 'inline-flex',
598
+ alignItems: 'center',
599
+ gap: '6px',
600
+ padding: '6px 14px',
601
+ borderRadius: '8px',
602
+ backgroundColor: '#e8eaf6',
603
+ fontSize: '12px',
604
+ color: '#3949ab',
605
+ fontWeight: 500
606
+ },
607
+ skillIcon: {
608
+ fontSize: '14px'
609
+ },
610
+ skillLabel: {
611
+ fontWeight: 600
612
+ },
570
613
  // Error messages
571
614
  errorRow: {
572
615
  display: 'flex',
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.SkillsBar = SkillsBar;
7
+ var _react = _interopRequireDefault(require("react"));
8
+ var _jsxRuntime = require("react/jsx-runtime");
9
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
10
+ /**
11
+ * Horizontal row of skill buttons rendered in the global chat page.
12
+ *
13
+ * Each button triggers its skill's prompt through the chat session.
14
+ * Disabled when not connected to the daemon.
15
+ */
16
+ function SkillsBar({
17
+ skills,
18
+ onTrigger,
19
+ disabled
20
+ }) {
21
+ if (!skills || skills.length === 0) return null;
22
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
23
+ style: styles.bar,
24
+ children: skills.map(skill => /*#__PURE__*/(0, _jsxRuntime.jsxs)("button", {
25
+ style: {
26
+ ...styles.button,
27
+ ...(disabled ? styles.buttonDisabled : {})
28
+ },
29
+ onClick: () => onTrigger(skill),
30
+ disabled: disabled,
31
+ title: skill.prompt,
32
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
33
+ style: styles.icon,
34
+ children: skill.icon
35
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
36
+ children: skill.label
37
+ })]
38
+ }, skill.id))
39
+ });
40
+ }
41
+ const styles = {
42
+ bar: {
43
+ display: 'flex',
44
+ gap: '6px',
45
+ padding: '8px 12px',
46
+ overflowX: 'auto',
47
+ flexShrink: 0
48
+ },
49
+ button: {
50
+ display: 'inline-flex',
51
+ alignItems: 'center',
52
+ gap: '4px',
53
+ padding: '5px 10px',
54
+ border: '1px solid rgba(0,0,0,0.12)',
55
+ borderRadius: '16px',
56
+ backgroundColor: '#fff',
57
+ color: '#444',
58
+ fontSize: '12px',
59
+ cursor: 'pointer',
60
+ whiteSpace: 'nowrap',
61
+ transition: 'background-color 0.15s'
62
+ },
63
+ buttonDisabled: {
64
+ opacity: 0.45,
65
+ cursor: 'default'
66
+ },
67
+ icon: {
68
+ fontSize: '13px'
69
+ }
70
+ };
package/dist/skills.js ADDED
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getGlobalSkills = getGlobalSkills;
7
+ /**
8
+ * Hardcoded global skill definitions.
9
+ *
10
+ * Each skill is a chat shortcut — triggering it sends the prompt through the
11
+ * active session and shows a visual indicator in the message list.
12
+ */
13
+
14
+ const STATIC_SKILLS = [{
15
+ id: 'sync-components',
16
+ label: 'Sync Components',
17
+ icon: '\u21BB',
18
+ prompt: 'Synchronize all Storybook components with their Figma designs. Report what changed.'
19
+ }, {
20
+ id: 'run-tests',
21
+ label: 'Run Tests',
22
+ icon: '\u25B6',
23
+ prompt: 'Run the full test suite and summarize the results.'
24
+ }, {
25
+ id: 'audit-stories',
26
+ label: 'Audit Stories',
27
+ icon: '\uD83D\uDD0D',
28
+ prompt: 'Audit all components and list any that are missing Storybook stories or have outdated ones.'
29
+ }];
30
+
31
+ /**
32
+ * Returns the PR skill definition based on whether a PR exists on the current branch.
33
+ */
34
+ function getPrSkill(pr) {
35
+ if (pr && pr.number) {
36
+ return {
37
+ id: 'finalize-pr',
38
+ label: 'Finalize PR',
39
+ icon: '\u2714',
40
+ prompt: `Check the status of PR #${pr.number} (${pr.url}). Review CI checks, review status, and merge conflicts. If everything is green and approved, offer to merge it. If there are issues, summarize what needs attention to make it ready for merge.`
41
+ };
42
+ }
43
+ return {
44
+ id: 'new-pr',
45
+ label: 'New PR',
46
+ icon: '\u2795',
47
+ prompt: 'Create a new pull request for the current branch with a summary of all changes.'
48
+ };
49
+ }
50
+
51
+ /**
52
+ * Build the full skills list, with the PR skill adapting to git context.
53
+ */
54
+ function getGlobalSkills(gitContext) {
55
+ const pr = gitContext?.pr || null;
56
+ return [STATIC_SKILLS[0],
57
+ // Sync Components
58
+ getPrSkill(pr),
59
+ // New PR / Finalize PR
60
+ STATIC_SKILLS[1],
61
+ // Run Tests
62
+ STATIC_SKILLS[2] // Audit Stories
63
+ ];
64
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@radnine/storybook-addon-claude",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "Storybook addon panel for chatting with Claude via the standalone daemon",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "repository": {