kapi-ui 0.2.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/overlay.js DELETED
@@ -1,378 +0,0 @@
1
- import { startInspecting, stopInspecting, setOnHover, setOnElementClick, setDisabled, describeElement } from './inspector.js';
2
- import { updateHoverPanel, showProcessingStatus } from './hover-panel.js';
3
- import { beginComment, clearAllComments, cancelOpenDraft, buildCommentsPrompt } from './comments.js';
4
- import { connectSocket, sendComments, setOnCommentsDone, setOnCommentsProcessing } from './socket.js';
5
- const KAPI_TAG = 'kapi-overlay';
6
- const POSITION_KEY = 'kapi-overlay-position';
7
- const DRAG_THRESHOLD = 4;
8
- const COLLAPSED_WIDTH = 40;
9
- const BAR_HEIGHT = 40;
10
- const INSET = 20;
11
- const LOGO_SVG = `
12
- <svg class="kapi-icon kapi-logo-icon" viewBox="0 0 43 36" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
13
- <path d="M3.731 10.7798C4.7147 6.56519 8.79736 3.83476 13.0683 4.5352L35.423 8.20143C40.6186 9.05351 43.6856 14.5012 41.7194 19.3852L37.1373 30.767C35.8843 33.8795 32.8656 35.9183 29.5104 35.9183L8.22545 35.9183C2.9297 35.9184 -0.984859 30.985 0.218806 25.8279L3.731 10.7798Z" fill="white"/>
14
- <path d="M16.7357 15.0244C17.1733 15.2681 17.7263 15.1116 17.9701 14.674C18.1986 14.2637 18.0748 13.7526 17.6979 13.4894L17.6188 13.4398L17.608 13.4338C17.6026 13.4308 17.5951 13.4272 17.5865 13.4226C17.5693 13.4134 17.5457 13.401 17.5161 13.3858C17.457 13.3555 17.374 13.3136 17.2696 13.2651C17.0606 13.168 16.7636 13.0411 16.4038 12.9165C15.6928 12.6703 14.6916 12.4178 13.6095 12.4528C12.4621 12.49 11.5001 12.9362 10.8494 13.343C10.5197 13.5491 10.2567 13.7533 10.074 13.9079C9.98233 13.9855 9.91012 14.0516 9.85863 14.1002C9.83301 14.1243 9.81248 14.1443 9.79727 14.1593C9.78976 14.1667 9.78309 14.173 9.7782 14.1779C9.7758 14.1803 9.77378 14.183 9.77202 14.1847C9.77117 14.1856 9.77044 14.1867 9.76974 14.1874L9.76786 14.188L9.76813 14.1889C9.77063 14.1917 9.81101 14.2311 10.4189 14.82L9.76719 14.1892C9.41868 14.549 9.42824 15.1231 9.78804 15.4717C10.1471 15.8196 10.7197 15.812 11.0686 15.4545L11.0692 15.4533C11.07 15.4525 11.0711 15.4516 11.0725 15.4503C11.078 15.4449 11.0885 15.4343 11.1035 15.4202C11.1335 15.3919 11.1815 15.3479 11.2461 15.2933C11.376 15.1834 11.5687 15.0332 11.8112 14.8816C12.3047 14.5731 12.9535 14.2897 13.6689 14.2666C14.4496 14.2415 15.2179 14.4256 15.8104 14.6308C16.1022 14.7319 16.3409 14.8346 16.5043 14.9105C16.5857 14.9484 16.6482 14.979 16.6879 14.9994C16.7077 15.0095 16.7217 15.0175 16.7299 15.0219L16.7357 15.0244Z" fill="#1E1E1F"/>
15
- <rect width="6.86041" height="9.21865" rx="3.43021" transform="matrix(0.866027 -0.499997 0.500003 0.866024 2.53809 3.43042)" fill="white"/>
16
- <rect width="6.86041" height="9.21865" rx="3.43021" transform="matrix(0.866027 -0.499997 0.500003 0.866024 13.0454 3.43042)" fill="white"/>
17
- <ellipse cx="1.75568" cy="2.16083" rx="1.75568" ry="2.16083" transform="matrix(0.763621 -0.645664 -0.64567 -0.763616 30.3809 18.4956)" fill="#1E1E1F"/>
18
- <ellipse cx="1.75567" cy="2.16083" rx="1.75567" ry="2.16083" transform="matrix(-0.64567 -0.763616 0.763621 -0.645664 36.6602 18.4724)" fill="#1E1E1F"/>
19
- <path d="M29.7427 30.1657C30.9734 30.6086 32.493 30.6762 34.0379 29.778C34.4709 29.5263 34.6185 28.9718 34.367 28.5387C34.1152 28.1056 33.5598 27.9586 33.1266 28.2104C32.1237 28.7936 31.1761 28.7524 30.3576 28.4578C29.508 28.152 28.8183 27.5742 28.4647 27.1562C28.1412 26.7743 27.5695 26.7266 27.1871 27.0496C26.8046 27.3732 26.7568 27.9456 27.0804 28.3282C27.6018 28.9446 28.5433 29.7339 29.7427 30.1657Z" fill="#1E1E1F"/>
20
- <path d="M31.1454 29.5056C32.343 28.4681 33.1357 26.3624 32.6699 24.0613C32.5704 23.5702 32.0916 23.2528 31.6005 23.3523C31.1097 23.4517 30.7924 23.9297 30.8915 24.4206C31.2449 26.1658 30.5984 27.5795 29.9579 28.1345C29.5793 28.4626 29.5381 29.0351 29.8661 29.4138C30.1942 29.7925 30.7668 29.8336 31.1454 29.5056Z" fill="#1E1E1F"/>
21
- </svg>
22
- `;
23
- const WAND_SVG = `
24
- <svg class="kapi-icon" viewBox="0 0 7 7" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
25
- <path d="M3.8742 1.77467L4.77412 2.67453M1.17446 1.47472V2.67453M5.37406 3.87434V5.07416M2.67432 0.274902V0.874809M1.77441 2.07462H0.574521M5.974 4.47425H4.77412M2.97429 0.574856H2.37435M6.16598 0.766826L5.78202 0.382886C5.74827 0.348786 5.70809 0.321716 5.66381 0.303242C5.61953 0.284767 5.57202 0.275255 5.52404 0.275255C5.47606 0.275255 5.42856 0.284767 5.38428 0.303242C5.34 0.321716 5.29982 0.348786 5.26607 0.382886L0.382539 5.26613C0.348438 5.29988 0.321366 5.34005 0.302891 5.38433C0.284415 5.42861 0.274902 5.47611 0.274902 5.52409C0.274902 5.57207 0.284415 5.61957 0.302891 5.66384C0.321366 5.70812 0.348438 5.7483 0.382539 5.78205L0.766502 6.16599C0.800045 6.20046 0.840156 6.22785 0.884464 6.24656C0.928773 6.26526 0.976381 6.2749 1.02448 6.2749C1.07257 6.2749 1.12018 6.26526 1.16449 6.24656C1.2088 6.22785 1.24891 6.20046 1.28245 6.16599L6.16598 1.28275C6.20045 1.24921 6.22785 1.2091 6.24656 1.16479C6.26526 1.12048 6.2749 1.07288 6.2749 1.02479C6.2749 0.976693 6.26526 0.929087 6.24656 0.884781C6.22785 0.840475 6.20045 0.800367 6.16598 0.766826Z" stroke="white" stroke-width="0.55" stroke-linecap="round" stroke-linejoin="round"/>
26
- </svg>
27
- `;
28
- const DELETE_SVG = `
29
- <svg class="kapi-icon" viewBox="0 0 7 7" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
30
- <path d="M2.60824 2.9749V4.7749M3.94157 2.9749V4.7749M5.60824 1.4749V5.6749C5.60824 5.83403 5.538 5.98664 5.41297 6.09917C5.28795 6.21169 5.11838 6.2749 4.94157 6.2749H1.60824C1.43142 6.2749 1.26186 6.21169 1.13683 6.09917C1.01181 5.98664 0.941569 5.83403 0.941569 5.6749V1.4749M0.274902 1.4749H6.2749M1.94157 1.4749V0.874902C1.94157 0.715772 2.01181 0.56316 2.13683 0.450638C2.26186 0.338116 2.43142 0.274902 2.60824 0.274902H3.94157C4.11838 0.274902 4.28795 0.338116 4.41297 0.450638C4.538 0.56316 4.60824 0.715772 4.60824 0.874902V1.4749" stroke="white" stroke-width="0.55" stroke-linecap="round" stroke-linejoin="round"/>
31
- </svg>
32
- `;
33
- const STYLES = `
34
- :host {
35
- /* Reset anything inheritable coming from the host page. */
36
- all: initial;
37
-
38
- --kapi-bg: #1e1e1f;
39
- --kapi-bg-hover: #2a2a2b;
40
- --kapi-bg-active: #161617;
41
- --kapi-ring: rgba(255, 255, 255, 0.14);
42
- --kapi-divider: rgba(255, 255, 255, 0.16);
43
-
44
- position: fixed;
45
- top: 0;
46
- left: 0;
47
- z-index: 2147483647;
48
- color-scheme: dark;
49
- touch-action: none;
50
- }
51
-
52
- .kapi-bar {
53
- display: flex;
54
- align-items: center;
55
- box-sizing: border-box;
56
- width: ${COLLAPSED_WIDTH}px;
57
- height: ${BAR_HEIGHT}px;
58
- padding: 4px;
59
- gap: 6px;
60
- border-radius: 12px;
61
- background: var(--kapi-bg);
62
- box-shadow:
63
- inset 0 0 0 1px var(--kapi-ring),
64
- 0 2px 4px rgba(0, 0, 0, 0.2),
65
- 0 8px 16px rgba(0, 0, 0, 0.2);
66
- overflow: hidden;
67
- transition:
68
- width 260ms cubic-bezier(0.34, 1.56, 0.64, 1),
69
- border-radius 260ms ease;
70
- transition-delay: 120ms, 120ms;
71
- }
72
-
73
- .kapi-bar.kapi-expanded {
74
- width: var(--kapi-expanded-width, ${COLLAPSED_WIDTH}px);
75
- border-radius: 12px;
76
- transition-delay: 0ms, 0ms;
77
- }
78
-
79
- .kapi-btn {
80
- display: flex;
81
- align-items: center;
82
- justify-content: center;
83
- box-sizing: border-box;
84
- flex: none;
85
- width: 32px;
86
- height: 32px;
87
- padding: 0;
88
- margin: 0;
89
- border: none;
90
- border-radius: 8px;
91
- background: transparent;
92
- cursor: pointer;
93
- user-select: none;
94
- -webkit-tap-highlight-color: transparent;
95
- transition: background 150ms ease, transform 150ms ease;
96
- }
97
-
98
- .kapi-btn:hover {
99
- background: var(--kapi-bg-hover);
100
- }
101
-
102
- .kapi-btn:active {
103
- background: var(--kapi-bg-active);
104
- transform: scale(0.92);
105
- transition: none;
106
- }
107
-
108
- .kapi-btn:focus-visible {
109
- outline: 2px solid #fff;
110
- outline-offset: 2px;
111
- }
112
-
113
- .kapi-logo-btn {
114
- cursor: pointer;
115
- touch-action: none;
116
- }
117
-
118
- .kapi-logo-btn.kapi-dragging {
119
- cursor: grabbing;
120
- background: var(--kapi-bg-active);
121
- transform: scale(0.95);
122
- transition: none;
123
- }
124
-
125
- .kapi-icon {
126
- pointer-events: none;
127
- }
128
-
129
- .kapi-logo-icon {
130
- width: 18px;
131
- height: auto;
132
- }
133
-
134
- .kapi-btn:not(.kapi-logo-btn) .kapi-icon {
135
- width: 15.5px;
136
- height: auto;
137
- }
138
-
139
- .kapi-extra {
140
- display: flex;
141
- align-items: center;
142
- gap: 6px;
143
- flex: none;
144
- opacity: 0;
145
- transform: scale(0.9);
146
- transition: opacity 160ms ease, transform 160ms ease;
147
- transition-delay: 0ms;
148
- }
149
-
150
- .kapi-btn-group {
151
- display: flex;
152
- align-items: center;
153
- gap: 0;
154
- flex: none;
155
- }
156
-
157
- .kapi-bar.kapi-expanded .kapi-extra {
158
- opacity: 1;
159
- transform: scale(1);
160
- transition-delay: 140ms;
161
- }
162
-
163
- .kapi-divider {
164
- flex: none;
165
- width: 1px;
166
- height: 18px;
167
- background: var(--kapi-divider);
168
- }
169
-
170
- @media (prefers-reduced-motion: reduce) {
171
- .kapi-bar,
172
- .kapi-btn,
173
- .kapi-extra {
174
- transition: none;
175
- }
176
- }
177
- `;
178
- function loadPosition() {
179
- try {
180
- const raw = localStorage.getItem(POSITION_KEY);
181
- if (!raw)
182
- return null;
183
- const parsed = JSON.parse(raw);
184
- if (typeof parsed?.left === 'number' && typeof parsed?.top === 'number')
185
- return parsed;
186
- }
187
- catch {
188
- /* ignore corrupt/inaccessible storage */
189
- }
190
- return null;
191
- }
192
- function savePosition(position) {
193
- try {
194
- localStorage.setItem(POSITION_KEY, JSON.stringify(position));
195
- }
196
- catch {
197
- /* ignore (e.g. storage disabled) */
198
- }
199
- }
200
- function clamp(value, min, max) {
201
- return Math.min(Math.max(value, min), max);
202
- }
203
- export function insertOverlay() {
204
- if (document.querySelector(KAPI_TAG))
205
- return;
206
- connectSocket();
207
- const host = document.createElement(KAPI_TAG);
208
- const root = host.attachShadow({ mode: 'open' });
209
- const style = document.createElement('style');
210
- style.textContent = STYLES;
211
- const bar = document.createElement('div');
212
- bar.className = 'kapi-bar';
213
- const logoBtn = document.createElement('button');
214
- logoBtn.className = 'kapi-btn kapi-logo-btn';
215
- logoBtn.type = 'button';
216
- logoBtn.setAttribute('aria-label', 'Toggle Kapi');
217
- logoBtn.setAttribute('aria-expanded', 'false');
218
- logoBtn.innerHTML = LOGO_SVG;
219
- const extra = document.createElement('div');
220
- extra.className = 'kapi-extra';
221
- const makeDivider = () => {
222
- const divider = document.createElement('span');
223
- divider.className = 'kapi-divider';
224
- return divider;
225
- };
226
- const wandBtn = document.createElement('button');
227
- wandBtn.className = 'kapi-btn';
228
- wandBtn.type = 'button';
229
- wandBtn.setAttribute('aria-label', 'Magic wand');
230
- wandBtn.innerHTML = WAND_SVG;
231
- wandBtn.addEventListener('click', () => {
232
- const prompt = buildCommentsPrompt();
233
- if (prompt)
234
- sendComments(prompt);
235
- });
236
- const deleteBtn = document.createElement('button');
237
- deleteBtn.className = 'kapi-btn';
238
- deleteBtn.type = 'button';
239
- deleteBtn.setAttribute('aria-label', 'Delete');
240
- deleteBtn.innerHTML = DELETE_SVG;
241
- deleteBtn.addEventListener('click', () => clearAllComments());
242
- const btnGroup = document.createElement('div');
243
- btnGroup.className = 'kapi-btn-group';
244
- btnGroup.append(wandBtn, deleteBtn);
245
- extra.append(makeDivider(), btnGroup);
246
- bar.append(logoBtn, extra);
247
- root.append(style, bar);
248
- document.body.appendChild(host);
249
- setOnHover((el) => {
250
- updateHoverPanel(el ? describeElement(el) : null);
251
- });
252
- setOnElementClick((el, clientX, clientY) => {
253
- beginComment(el, clientX, clientY);
254
- });
255
- setOnCommentsProcessing((status) => {
256
- cancelOpenDraft();
257
- setDisabled(true);
258
- showProcessingStatus(status);
259
- });
260
- setOnCommentsDone(() => {
261
- clearAllComments();
262
- setDisabled(false);
263
- if (expanded)
264
- startInspecting();
265
- updateHoverPanel(null);
266
- });
267
- let expanded = false;
268
- const measureExpandedWidth = () => {
269
- const barStyle = getComputedStyle(bar);
270
- const paddingX = parseFloat(barStyle.paddingLeft) + parseFloat(barStyle.paddingRight);
271
- const gap = parseFloat(barStyle.columnGap || barStyle.gap) || 0;
272
- const width = Math.round(logoBtn.offsetWidth + gap + extra.offsetWidth + paddingX);
273
- bar.style.setProperty('--kapi-expanded-width', `${width}px`);
274
- return width;
275
- };
276
- let expandedWidth = measureExpandedWidth();
277
- const currentSize = () => ({
278
- width: expanded ? expandedWidth : COLLAPSED_WIDTH,
279
- height: BAR_HEIGHT,
280
- });
281
- const place = (left, top) => {
282
- const { width, height } = currentSize();
283
- const maxLeft = window.innerWidth - width - INSET;
284
- const maxTop = window.innerHeight - height - INSET;
285
- host.style.left = `${clamp(left, INSET, Math.max(INSET, maxLeft))}px`;
286
- host.style.top = `${clamp(top, INSET, Math.max(INSET, maxTop))}px`;
287
- };
288
- const setExpanded = (next) => {
289
- if (expanded === next)
290
- return;
291
- if (next)
292
- expandedWidth = measureExpandedWidth();
293
- expanded = next;
294
- bar.classList.toggle('kapi-expanded', expanded);
295
- logoBtn.setAttribute('aria-expanded', String(expanded));
296
- const rect = host.getBoundingClientRect();
297
- place(rect.left, rect.top);
298
- if (expanded) {
299
- startInspecting();
300
- }
301
- else {
302
- stopInspecting();
303
- }
304
- };
305
- const saved = loadPosition();
306
- if (saved) {
307
- place(saved.left, saved.top);
308
- }
309
- else {
310
- place(INSET, window.innerHeight - COLLAPSED_WIDTH - INSET);
311
- }
312
- window.addEventListener('resize', () => {
313
- const rect = host.getBoundingClientRect();
314
- place(rect.left, rect.top);
315
- });
316
- let pointerId = null;
317
- let dragging = false;
318
- let startX = 0;
319
- let startY = 0;
320
- let originLeft = 0;
321
- let originTop = 0;
322
- const suppressNextClick = (e) => {
323
- e.preventDefault();
324
- e.stopPropagation();
325
- logoBtn.removeEventListener('click', suppressNextClick, true);
326
- };
327
- logoBtn.addEventListener('click', () => setExpanded(!expanded));
328
- logoBtn.addEventListener('pointerdown', (e) => {
329
- if (e.button !== 0 && e.pointerType === 'mouse')
330
- return;
331
- pointerId = e.pointerId;
332
- dragging = false;
333
- startX = e.clientX;
334
- startY = e.clientY;
335
- const rect = host.getBoundingClientRect();
336
- originLeft = rect.left;
337
- originTop = rect.top;
338
- logoBtn.setPointerCapture(pointerId);
339
- });
340
- logoBtn.addEventListener('pointermove', (e) => {
341
- if (e.pointerId !== pointerId)
342
- return;
343
- const dx = e.clientX - startX;
344
- const dy = e.clientY - startY;
345
- if (!dragging) {
346
- if (Math.abs(dx) + Math.abs(dy) < DRAG_THRESHOLD)
347
- return;
348
- dragging = true;
349
- logoBtn.classList.add('kapi-dragging');
350
- logoBtn.addEventListener('click', suppressNextClick, true);
351
- stopInspecting();
352
- }
353
- place(originLeft + dx, originTop + dy);
354
- });
355
- const endDrag = (e) => {
356
- if (e.pointerId !== pointerId)
357
- return;
358
- if (logoBtn.hasPointerCapture(pointerId))
359
- logoBtn.releasePointerCapture(pointerId);
360
- pointerId = null;
361
- if (dragging) {
362
- logoBtn.classList.remove('kapi-dragging');
363
- const rect = host.getBoundingClientRect();
364
- savePosition({ left: rect.left, top: rect.top });
365
- if (expanded)
366
- startInspecting();
367
- }
368
- dragging = false;
369
- };
370
- logoBtn.addEventListener('pointerup', endDrag);
371
- logoBtn.addEventListener('pointercancel', endDrag);
372
- }
373
- if (document.readyState === 'loading') {
374
- document.addEventListener('DOMContentLoaded', () => insertOverlay(), { once: true });
375
- }
376
- else {
377
- insertOverlay();
378
- }
package/dist/server.js DELETED
@@ -1,118 +0,0 @@
1
- import http from "http";
2
- import { spawn } from "child_process";
3
- import { WebSocketServer, WebSocket } from "ws";
4
- let sessionId = null;
5
- export function getSessionId() {
6
- return sessionId;
7
- }
8
- const KAPI_SESSION_PROMPT = "This session is dedicated to giving you commands on what to edit in the codebase, with specific file locations and specs, so give precise, actionable details.";
9
- function startClaudeSession() {
10
- const claude = spawn("claude", ["-p", KAPI_SESSION_PROMPT, "--output-format", "json"], { stdio: ["ignore", "pipe", "pipe"] });
11
- let stdout = "";
12
- claude.stdout.on("data", (chunk) => {
13
- stdout += chunk;
14
- });
15
- claude.stderr.pipe(process.stderr);
16
- claude.on("close", () => {
17
- try {
18
- const result = JSON.parse(stdout);
19
- sessionId = result.session_id;
20
- console.log(`Claude session started: ${sessionId}`);
21
- }
22
- catch (err) {
23
- console.error("Failed to parse claude -p output:", err);
24
- }
25
- });
26
- }
27
- function send(socket, msg) {
28
- if (socket.readyState === WebSocket.OPEN)
29
- socket.send(JSON.stringify(msg));
30
- }
31
- function describeToolUse(name, input) {
32
- switch (name) {
33
- case "Read":
34
- return `Reading ${input?.file_path ?? "a file"}`;
35
- case "Edit":
36
- case "Write":
37
- return `Editing ${input?.file_path ?? "a file"}`;
38
- case "Bash":
39
- return `Running: ${String(input?.command ?? "").slice(0, 60)}`;
40
- case "Grep":
41
- return `Searching for "${input?.pattern ?? ""}"`;
42
- case "Glob":
43
- return `Finding files matching ${input?.pattern ?? ""}`;
44
- default:
45
- return `Using ${name}`;
46
- }
47
- }
48
- function describeStreamEvent(event) {
49
- if (event.type !== "assistant" || !event.message?.content)
50
- return null;
51
- for (const block of event.message.content) {
52
- if (block.type === "tool_use")
53
- return describeToolUse(block.name, block.input);
54
- if (block.type === "text" && block.text)
55
- return block.text.slice(0, 120);
56
- }
57
- return null;
58
- }
59
- function processComments(prompt, socket) {
60
- if (!sessionId) {
61
- console.error("[kapi] cannot process comments: no active claude session");
62
- return;
63
- }
64
- send(socket, { type: "comments:processing", status: "Starting..." });
65
- const claude = spawn("claude", ["-p", "--resume", sessionId, "--permission-mode", "auto", prompt, "--output-format", "stream-json", "--verbose"], { stdio: ["ignore", "pipe", "pipe"] });
66
- let buffer = "";
67
- claude.stdout.on("data", (chunk) => {
68
- buffer += chunk.toString();
69
- let newlineIndex;
70
- while ((newlineIndex = buffer.indexOf("\n")) !== -1) {
71
- const line = buffer.slice(0, newlineIndex).trim();
72
- buffer = buffer.slice(newlineIndex + 1);
73
- if (!line)
74
- continue;
75
- let event;
76
- try {
77
- event = JSON.parse(line);
78
- }
79
- catch {
80
- continue;
81
- }
82
- if (event.type === "result" && event.session_id)
83
- sessionId = event.session_id;
84
- const status = describeStreamEvent(event);
85
- if (status)
86
- send(socket, { type: "comments:processing", status });
87
- }
88
- });
89
- claude.stderr.pipe(process.stderr);
90
- claude.on("close", () => {
91
- send(socket, { type: "comments:done" });
92
- });
93
- }
94
- export function startServer(portNumber) {
95
- const server = http.createServer((req, res) => {
96
- res.writeHead(200, { "Content-Type": "text/plain" });
97
- res.end("I love capybaras");
98
- });
99
- server.listen(portNumber, "localhost", () => {
100
- console.log(`Server running at http://localhost:${portNumber}`);
101
- });
102
- const wss = new WebSocketServer({ server });
103
- wss.on("connection", (socket) => {
104
- console.log("[kapi] overlay connected via websocket");
105
- socket.on("close", () => console.log("[kapi] overlay disconnected"));
106
- socket.on("message", (data) => {
107
- try {
108
- const msg = JSON.parse(data.toString());
109
- if (msg.type === "comments:submit")
110
- processComments(msg.prompt, socket);
111
- }
112
- catch {
113
- /* ignore malformed messages */
114
- }
115
- });
116
- });
117
- startClaudeSession();
118
- }
package/dist/setup.js DELETED
@@ -1,65 +0,0 @@
1
- #!/usr/bin/env node
2
- import prompts from 'prompts';
3
- import { installKapi, injectVitePlugin, injectNuxtModule, KAPI_PACKAGE_NAME } from './utils.js';
4
- async function setup() {
5
- console.log(`
6
- ██ ██ █████ ██████ ██
7
- ██ ██ ██ ██ ██ ██ ██
8
- █████ ███████ ██████ ██
9
- ██ ██ ██ ██ ██ ██
10
- ██ ██ ██ ██ ██ ██
11
- `);
12
- const response = await prompts({
13
- type: 'select',
14
- name: 'setupChoice',
15
- message: 'Setup',
16
- choices: [
17
- { title: 'Vite', value: 'vite' },
18
- { title: 'Nuxt', value: 'nuxt' },
19
- ],
20
- });
21
- if (!response.setupChoice) {
22
- console.log('Setup cancelled.');
23
- process.exit(0);
24
- }
25
- console.log(`\n✨ Setting up Kapi for ${response.setupChoice}...\n`);
26
- if (response.setupChoice === 'vite') {
27
- try {
28
- installKapi(process.cwd());
29
- await injectVitePlugin(process.cwd());
30
- console.log('done!');
31
- }
32
- catch (err) {
33
- console.error('Failed to update vite.config automatically:', err);
34
- console.log(`
35
- Add this manually to your vite.config:
36
-
37
- import kapi from '${KAPI_PACKAGE_NAME}/vite-plugin'
38
-
39
- export default defineConfig({
40
- plugins: [kapi()],
41
- })
42
- `);
43
- process.exit(1);
44
- }
45
- }
46
- if (response.setupChoice === 'nuxt') {
47
- try {
48
- installKapi(process.cwd());
49
- await injectNuxtModule(process.cwd());
50
- console.log('done!');
51
- }
52
- catch (err) {
53
- console.error('Failed to update nuxt.config automatically:', err);
54
- console.log(`
55
- Add this manually to your nuxt.config:
56
-
57
- export default defineNuxtConfig({
58
- modules: ['${KAPI_PACKAGE_NAME}/nuxt'],
59
- })
60
- `);
61
- process.exit(1);
62
- }
63
- }
64
- }
65
- setup().catch(console.error);
package/dist/socket.js DELETED
@@ -1,36 +0,0 @@
1
- import { KAPI_SERVER_PORT } from './constants.js';
2
- let socket = null;
3
- let onCommentsDone = null;
4
- let onCommentsProcessing = null;
5
- export function connectSocket() {
6
- socket = new WebSocket(`ws://localhost:${KAPI_SERVER_PORT}`);
7
- socket.addEventListener('open', () => console.log('[kapi] connected to kapi server'));
8
- socket.addEventListener('close', () => console.log('[kapi] disconnected from kapi server'));
9
- socket.addEventListener('error', (e) => console.error('[kapi] websocket error', e));
10
- socket.addEventListener('message', (e) => {
11
- try {
12
- const msg = JSON.parse(e.data);
13
- if (msg.type === 'comments:done')
14
- onCommentsDone?.();
15
- if (msg.type === 'comments:processing')
16
- onCommentsProcessing?.(msg.status);
17
- }
18
- catch {
19
- /* ignore malformed messages */
20
- }
21
- });
22
- return socket;
23
- }
24
- export function sendComments(prompt) {
25
- if (!socket || socket.readyState !== WebSocket.OPEN) {
26
- console.error('[kapi] cannot send comments: socket not connected');
27
- return;
28
- }
29
- socket.send(JSON.stringify({ type: 'comments:submit', prompt }));
30
- }
31
- export function setOnCommentsDone(callback) {
32
- onCommentsDone = callback;
33
- }
34
- export function setOnCommentsProcessing(callback) {
35
- onCommentsProcessing = callback;
36
- }
package/dist/types.js DELETED
@@ -1 +0,0 @@
1
- export {};
@@ -1,44 +0,0 @@
1
- import path from 'path';
2
- import { fileURLToPath } from 'url';
3
- import { searchForWorkspaceRoot } from 'vite';
4
- import { startServer } from './server.js';
5
- import { stampTemplateLocations } from './location-transform.js';
6
- import { KAPI_SERVER_PORT } from './constants.js';
7
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
8
- const overlayPath = path.resolve(__dirname, './overlay.js');
9
- export default function kapi() {
10
- let isDev = false;
11
- return {
12
- name: 'kapi-ui',
13
- enforce: 'pre',
14
- config(_config, { command }) {
15
- isDev = command === 'serve';
16
- return {
17
- server: {
18
- fs: {
19
- allow: [searchForWorkspaceRoot(process.cwd()), path.dirname(overlayPath)],
20
- },
21
- },
22
- };
23
- },
24
- configureServer() {
25
- startServer(KAPI_SERVER_PORT);
26
- },
27
- resolveId(id) {
28
- if (id === '/@kapi-ui/overlay')
29
- return overlayPath;
30
- },
31
- transform(code, id) {
32
- if (!isDev)
33
- return;
34
- const [bareId] = id.split('?');
35
- if (!bareId.endsWith('.vue'))
36
- return;
37
- const relativeFile = path.relative(process.cwd(), bareId);
38
- return { code: stampTemplateLocations(code, relativeFile), map: null };
39
- },
40
- transformIndexHtml(html) {
41
- return html.replace('</body>', `<script type="module" src="/@kapi-ui/overlay"></script></body>`);
42
- },
43
- };
44
- }