@lovinka/vitrinka 1.1.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/mcp.js ADDED
@@ -0,0 +1,405 @@
1
+ #!/usr/bin/env node
2
+ // mcp/server.ts — the standalone vitrinka MCP server (stdio transport).
3
+ //
4
+ // A thin, STATELESS local process: every tool call becomes one HTTPS request
5
+ // against the deployed Go server, so N concurrent agent sessions are just N
6
+ // independent processes — no shared connection to keep alive (design:
7
+ // docs/plans/2026-07-04-set-names-cli-shim-mcp-design.md).
8
+ //
9
+ // Zero dependencies, erasable TypeScript (node: builtins only) — same rules as
10
+ // the CLI (pkg/src/cli.ts, shipped as the `vitrinka` bin). The MCP JSON-RPC surface used
11
+ // here (initialize / tools/list / tools/call, protocol 2025-06-18) is small
12
+ // enough to speak directly.
13
+ //
14
+ // Config (env):
15
+ // VITRINKA_BASE_URL default https://vitrinka.lovinka.com
16
+ // VITRINKA_TOKEN Bearer token; falls back to ~/.config/vitrinka/token
17
+ // (the CLI's convention); required only by mutating tools
18
+ //
19
+ // Register (user-level MCP config):
20
+ // claude mcp add --scope user vitrinka -- node <repo>/mcp/server.ts
21
+ import { createInterface } from 'node:readline';
22
+ import { readToken } from "./lib/token.js";
23
+ import { readOperator, actorHeaderValue } from "./lib/operator.js";
24
+ import { resolveBaseUrl } from "./lib/base-url.js";
25
+ import { makeApi } from "./lib/http.js";
26
+ const BASE_URL = resolveBaseUrl();
27
+ const TOKEN = readToken();
28
+ // Operator persona (install.sh onboarding): stamps X-Board-Actor on write
29
+ // calls so the board credits the operator's machine. Explicit body-level
30
+ // attribution (reply author "claude", attach_after agent "claude") still wins
31
+ // on the server — agent-authored content stays the agent's. A SET-but-empty
32
+ // VITRINKA_OPERATOR explicitly disables the stamp (keeps tests hermetic), so
33
+ // this side uses the MCP semantics (treatEmptyAsUnset=false).
34
+ const OPERATOR = actorHeaderValue(readOperator(false));
35
+ const PROTOCOL_VERSION = '2025-06-18';
36
+ const SERVER_INFO = { name: 'vitrinka', version: '1.1.0' };
37
+ // ---------- HTTP helper ----------
38
+ const rawApi = makeApi({ baseUrl: BASE_URL, token: TOKEN, operator: OPERATOR });
39
+ // Thin shim so the existing call sites keep their (method, path, body, opts)
40
+ // shape — the shared helper takes the body inside opts.
41
+ function api(method, path, body, opts) {
42
+ const merged = { ...opts };
43
+ if (body !== undefined)
44
+ merged.body = body;
45
+ return rawApi(method, path, merged);
46
+ }
47
+ function seg(s) {
48
+ return encodeURIComponent(String(s));
49
+ }
50
+ const selectorProps = {
51
+ project: { type: 'string', description: 'Project, e.g. "fixit"' },
52
+ branch: { type: 'string', description: 'Branch slug, e.g. "main"' },
53
+ selector: {
54
+ type: 'string',
55
+ description: 'Set selector: a version number ("2"), "latest", the set\'s custom name, or its key',
56
+ },
57
+ };
58
+ const TOOLS = {
59
+ list_projects: {
60
+ description: 'List all projects in the vitrinka artifacts library (name, branch count, set count, last update).',
61
+ inputSchema: { type: 'object', properties: {}, additionalProperties: false },
62
+ handler: () => api('GET', '/api/v1/projects'),
63
+ },
64
+ list_sets: {
65
+ description: 'List the artifact sets of a project (all branches) or of one branch — newest first, without file lists. Each set has a share URL, version, key, optional custom name and title.',
66
+ inputSchema: {
67
+ type: 'object',
68
+ properties: { project: selectorProps.project, branch: { ...selectorProps.branch, description: 'Branch slug; omit for all branches of the project' } },
69
+ required: ['project'],
70
+ additionalProperties: false,
71
+ },
72
+ handler: (a) => api('GET', `/api/v1/sets/${seg(a.project)}${a.branch ? `/${seg(a.branch)}` : ''}`),
73
+ },
74
+ get_set: {
75
+ description: 'Get one artifact set: metadata (version, key, name, title, commit, PR, issue) plus its full file list and share URL.',
76
+ inputSchema: {
77
+ type: 'object',
78
+ properties: selectorProps,
79
+ required: ['project', 'branch', 'selector'],
80
+ additionalProperties: false,
81
+ },
82
+ handler: (a) => api('GET', `/api/v1/sets/${seg(a.project)}/${seg(a.branch)}/${seg(a.selector)}`),
83
+ },
84
+ rename_set: {
85
+ description: 'Set (or change) the custom URL-addressable name of a set — e.g. name fixit/main v2 "payout-flow" so https://…/fixit/main/payout-flow resolves. Pass an empty name to clear it. Requires VITRINKA_TOKEN.',
86
+ inputSchema: {
87
+ type: 'object',
88
+ properties: {
89
+ ...selectorProps,
90
+ name: { type: 'string', description: 'New name: lowercase slug [a-z0-9][a-z0-9._-]{0,63}, not purely numeric, not "latest". Empty string clears the name.' },
91
+ },
92
+ required: ['project', 'branch', 'selector', 'name'],
93
+ additionalProperties: false,
94
+ },
95
+ handler: (a) => api('PATCH', `/api/v1/sets/${seg(a.project)}/${seg(a.branch)}/${seg(a.selector)}`, { name: String(a.name).toLowerCase() }),
96
+ },
97
+ update_set: {
98
+ description: 'Edit a set\'s mutable metadata: custom name and/or human title. Omitted fields stay untouched; empty string clears. Requires VITRINKA_TOKEN.',
99
+ inputSchema: {
100
+ type: 'object',
101
+ properties: {
102
+ ...selectorProps,
103
+ name: { type: 'string', description: 'New name slug; "" clears; omit to leave unchanged' },
104
+ title: { type: 'string', description: 'New human title (max 200 chars); "" clears; omit to leave unchanged' },
105
+ },
106
+ required: ['project', 'branch', 'selector'],
107
+ additionalProperties: false,
108
+ },
109
+ handler: (a) => {
110
+ const patch = {};
111
+ if (a.name !== undefined)
112
+ patch.name = String(a.name).toLowerCase();
113
+ if (a.title !== undefined)
114
+ patch.title = String(a.title);
115
+ return api('PATCH', `/api/v1/sets/${seg(a.project)}/${seg(a.branch)}/${seg(a.selector)}`, patch);
116
+ },
117
+ },
118
+ // ---- annotation-board work queue (design 2026-07-04) ----
119
+ //
120
+ // The agent loop: list_work → set_status working → fix the app →
121
+ // `vitrinka snap`/push the after shot as a new set → attach_after →
122
+ // reply → set_status in_review. Only the USER resolves (accept in the
123
+ // board UI); never set status "resolved" yourself.
124
+ list_boards: {
125
+ description: 'List the annotation boards (Freeform-style canvases over screenshot sets). Each has a slug, title and URL.',
126
+ inputSchema: { type: 'object', properties: {}, additionalProperties: false },
127
+ handler: () => api('GET', '/api/v1/boards'),
128
+ },
129
+ ask_board: {
130
+ description: 'Ask the operator a first-class multiple-choice question on a board — rendered as one-click pills, optionally anchored to a card. The answer returns on the work wire as a {type:"choice"} item (wait_for_work), so this is how you let the user "pick B" in one click instead of prose. An "Other / Něco jiného" free-text escape is always added by the engine, so pass only the real options — never hard-block off-vocabulary answers. Stamps the operator as X-Board-Actor.',
131
+ inputSchema: {
132
+ type: 'object',
133
+ properties: {
134
+ board: { type: 'string', description: 'Board slug (from list_boards)' },
135
+ prompt: { type: 'string', description: 'The question' },
136
+ options: {
137
+ type: 'array', items: { type: 'string' },
138
+ description: '1-12 answer options (the "Other" escape is appended automatically)',
139
+ },
140
+ cardId: { type: 'number', description: 'Optional card id to anchor the question to (omit for a board-level question)' },
141
+ },
142
+ required: ['board', 'prompt', 'options'],
143
+ additionalProperties: false,
144
+ },
145
+ handler: (a) => api('POST', `/api/v1/boards/${seg(a.board)}/questions`, {
146
+ prompt: String(a.prompt),
147
+ options: Array.isArray(a.options) ? a.options.map(String) : [],
148
+ ...(a.cardId !== undefined ? { cardId: Number(a.cardId) } : {}),
149
+ }),
150
+ },
151
+ scrape_board: {
152
+ description: 'Read a WHOLE board as one structured testing digest — every media image (URL), note text and annotation — with the connect-tool edges walked into ordered journey chains ("flow": [[A,B,C]]). Use this to process a testing session end-to-end (pasted screenshots + notes) rather than acting on one annotation at a time; the flow tells you the user\'s step order. Images are absolute URLs (no auth on the mesh) — fetch them to SEE each step.',
153
+ inputSchema: {
154
+ type: 'object',
155
+ properties: { slug: { type: 'string', description: 'Board slug (from list_boards)' } },
156
+ required: ['slug'],
157
+ additionalProperties: false,
158
+ },
159
+ handler: (a) => api('GET', `/api/v1/boards/${seg(a.slug)}/scrape`),
160
+ },
161
+ wait_for_work: {
162
+ description: 'BLOCK until annotation work exists — the continuous-work tool (board-v3). Long-polls the server: costs nothing while idle, returns up to 3 ready-to-act markdown capsules the instant the user annotates (or re-queues). {"idle":true} means the window elapsed quietly — simply call it again. Scope to just your session\'s work with project + branch (or a board slug). A listening session (/vitrinka:listen) loops on this forever.',
163
+ inputSchema: {
164
+ type: 'object',
165
+ properties: {
166
+ board: { type: 'string', description: 'Only wait for one board\'s work (slug); omit for any board' },
167
+ project: { type: 'string', description: 'Only wait for one project\'s work (matches the card set_ref); pair with branch to scope to your repo+branch' },
168
+ branch: { type: 'string', description: 'Only wait for one branch slug\'s work (with project)' },
169
+ timeoutSec: { type: 'number', description: 'Long-poll window in seconds, 1-55 (default 50)' },
170
+ },
171
+ additionalProperties: false,
172
+ },
173
+ handler: (a) => {
174
+ const secs = Math.min(55, Math.max(1, Number(a.timeoutSec ?? 50)));
175
+ const q = new URLSearchParams({ timeout: String(secs) });
176
+ if (a.board)
177
+ q.set('board', String(a.board));
178
+ if (a.project)
179
+ q.set('project', String(a.project));
180
+ if (a.branch)
181
+ q.set('branch', String(a.branch));
182
+ return api('GET', `/api/v1/work/wait?${q}`, undefined, { timeoutMs: (secs + 15) * 1000 });
183
+ },
184
+ },
185
+ get_capsule: {
186
+ description: 'One annotation\'s compact markdown work brief (same shape wait_for_work delivers): ask, region, source set, thread tail, protocol. Cheaper than get_annotation when you just need to act.',
187
+ inputSchema: {
188
+ type: 'object',
189
+ properties: { id: { type: 'number', description: 'Annotation id' } },
190
+ required: ['id'],
191
+ additionalProperties: false,
192
+ },
193
+ handler: (a) => api('GET', `/api/v1/annotations/${seg(a.id)}/capsule`, undefined, { raw: true }),
194
+ },
195
+ list_work: {
196
+ description: 'List annotation work items (the agent queue), FIFO. Each item: id, board, intent (fix|investigate|refactor|redesign|other), prompt, source set ref + file, crop URL. Filter by status (open = waiting for an agent), board slug, and/or project + branch (scope to your repo+branch). Start here.',
197
+ inputSchema: {
198
+ type: 'object',
199
+ properties: {
200
+ status: { type: 'string', enum: ['open', 'working', 'in_review', 'resolved'], description: 'Filter by lifecycle status; use "open" to find waiting work' },
201
+ board: { type: 'string', description: 'Filter by board slug' },
202
+ project: { type: 'string', description: 'Filter by project (matches the card set_ref)' },
203
+ branch: { type: 'string', description: 'Filter by branch slug (with project)' },
204
+ },
205
+ additionalProperties: false,
206
+ },
207
+ handler: (a) => {
208
+ const q = new URLSearchParams();
209
+ if (a.status)
210
+ q.set('status', String(a.status));
211
+ if (a.board)
212
+ q.set('board', String(a.board));
213
+ if (a.project)
214
+ q.set('project', String(a.project));
215
+ if (a.branch)
216
+ q.set('branch', String(a.branch));
217
+ const qs = q.toString();
218
+ return api('GET', `/api/v1/work${qs ? '?' + qs : ''}`);
219
+ },
220
+ },
221
+ get_annotation: {
222
+ description: 'Get one annotation\'s full brief: region, intent, prompt revisions, thread messages (incl. file attachments the user added — fetch their URLs), fix attempts (before/after history), the element context (elements: E-numbers the region overlaps + screen siblings) and its card\'s source set. Fetch the cropUrl (PNG, no auth on the mesh) to SEE the annotated region — user markup strokes are baked in.',
223
+ inputSchema: {
224
+ type: 'object',
225
+ properties: { id: { type: 'number', description: 'Annotation id (from list_work)' } },
226
+ required: ['id'],
227
+ additionalProperties: false,
228
+ },
229
+ handler: (a) => api('GET', `/api/v1/annotations/${seg(a.id)}`),
230
+ },
231
+ set_status: {
232
+ description: 'Move an annotation through its lifecycle. Agents use: "working" when picking an item up, "in_review" after attaching the after-shot and replying. Never "resolved" — the user accepts in the board UI. A 409 "cancelled" means the user withdrew the annotation mid-flight: revert your changes for it and move on. Requires VITRINKA_TOKEN.',
233
+ inputSchema: {
234
+ type: 'object',
235
+ properties: {
236
+ id: { type: 'number' },
237
+ status: { type: 'string', enum: ['open', 'working', 'in_review'] },
238
+ },
239
+ required: ['id', 'status'],
240
+ additionalProperties: false,
241
+ },
242
+ handler: (a) => api('PATCH', `/api/v1/annotations/${seg(a.id)}`, { status: String(a.status) }),
243
+ },
244
+ reply: {
245
+ description: 'Post a reply into an annotation\'s thread as the agent (author "claude"). Use it to report what was done, ask a clarifying question, or explain a push-back. Requires VITRINKA_TOKEN.',
246
+ inputSchema: {
247
+ type: 'object',
248
+ properties: {
249
+ id: { type: 'number' },
250
+ text: { type: 'string', description: 'Message body (markdown-ish plain text)' },
251
+ },
252
+ required: ['id', 'text'],
253
+ additionalProperties: false,
254
+ },
255
+ handler: (a) => api('POST', `/api/v1/annotations/${seg(a.id)}/messages`, { author: 'claude', body: String(a.text) }),
256
+ },
257
+ attach_after: {
258
+ description: 'Attach the "after" proof shot to an annotation: names a file inside a set version you already pushed (vitrinka snap/push). Appends a fix attempt to the before/after deck AND advances the annotated card\'s face on the board immediately (the user\'s accept blesses it, reject rolls it back) — this is the canonical way to show a fix; never paste the after as a new card. Requires VITRINKA_TOKEN.',
259
+ inputSchema: {
260
+ type: 'object',
261
+ properties: {
262
+ id: { type: 'number', description: 'Annotation id' },
263
+ project: selectorProps.project,
264
+ branch: selectorProps.branch,
265
+ selector: selectorProps.selector,
266
+ file: { type: 'string', description: 'File path inside that set, e.g. "2026-07-04/01-domov.png"' },
267
+ commit: { type: 'string', description: 'Commit SHA of the fix (optional)' },
268
+ },
269
+ required: ['id', 'project', 'branch', 'selector', 'file'],
270
+ additionalProperties: false,
271
+ },
272
+ handler: (a) => api('POST', `/api/v1/annotations/${seg(a.id)}/attempts`, {
273
+ project: String(a.project), branch: String(a.branch), selector: String(a.selector),
274
+ file: String(a.file), agent: 'claude', ...(a.commit ? { commit: String(a.commit) } : {}),
275
+ }),
276
+ },
277
+ highlight: {
278
+ description: 'Visually highlight a rectangle on an annotation\'s shot card — draws an ink rectangle on the board that appears live for the user (SSE). Defaults to the annotation\'s own region; pass x/y/w/h (source-image pixels) to point at something else on the same card, e.g. "the element you actually mean is HERE". Requires VITRINKA_TOKEN.',
279
+ inputSchema: {
280
+ type: 'object',
281
+ properties: {
282
+ id: { type: 'number', description: 'Annotation id — the highlight lands on its card' },
283
+ x: { type: 'number' }, y: { type: 'number' },
284
+ w: { type: 'number' }, h: { type: 'number' },
285
+ color: { type: 'string', description: 'CSS color; default #ffb020 (agent amber, distinct from the user\'s red ink)' },
286
+ },
287
+ required: ['id'],
288
+ additionalProperties: false,
289
+ },
290
+ handler: async (a) => {
291
+ const ann = await api('GET', `/api/v1/annotations/${seg(a.id)}`);
292
+ if (ann.status >= 400)
293
+ return ann;
294
+ const body = ann.body;
295
+ const r = a.x !== undefined && a.y !== undefined && a.w !== undefined && a.h !== undefined
296
+ ? { x: Number(a.x), y: Number(a.y), w: Number(a.w), h: Number(a.h) }
297
+ : body.annotation.region;
298
+ const rect = [
299
+ [r.x, r.y, 1], [r.x + r.w, r.y, 1], [r.x + r.w, r.y + r.h, 1],
300
+ [r.x, r.y + r.h, 1], [r.x, r.y, 1],
301
+ ];
302
+ return api('POST', `/api/v1/boards/${seg(body.board)}/strokes`, {
303
+ strokes: [{ cardId: body.annotation.cardId, path: rect, color: String(a.color ?? '#ffb020'), width: 6 }],
304
+ });
305
+ },
306
+ },
307
+ };
308
+ function send(msg) {
309
+ process.stdout.write(JSON.stringify(msg) + '\n');
310
+ }
311
+ function reply(id, result) {
312
+ send({ jsonrpc: '2.0', id, result });
313
+ }
314
+ function replyError(id, code, message) {
315
+ send({ jsonrpc: '2.0', id, error: { code, message } });
316
+ }
317
+ async function handle(msg) {
318
+ const { id, method, params } = msg;
319
+ if (method === undefined)
320
+ return; // responses/junk — nothing to do
321
+ const isNotification = id === undefined;
322
+ switch (method) {
323
+ case 'initialize':
324
+ reply(id, {
325
+ protocolVersion: PROTOCOL_VERSION,
326
+ capabilities: { tools: {} },
327
+ serverInfo: SERVER_INFO,
328
+ instructions: 'Vitrinka is BOARD-FIRST: the annotation board is the default surface for '
329
+ + 'sharing and reviewing UI work. When publishing screenshots/journeys, create or update '
330
+ + 'the flow board (vitrinka board-from-set) and hand the user the /boards/<slug> URL as the '
331
+ + 'primary link; set/share pages are the archive behind it. Boards are live and interactive: '
332
+ + 'the user annotates regions and thread replies route to claude by default (@eve only when '
333
+ + 'explicitly mentioned) — a session in the app repo keeps listening via /vitrinka:listen, which '
334
+ + 'arms a native background monitor (`vitrinka watch`) that re-invokes the session on each new '
335
+ + 'annotation (zero-token idle); the session then drains the queue via wait_for_work.',
336
+ });
337
+ return;
338
+ case 'notifications/initialized':
339
+ return;
340
+ case 'ping':
341
+ if (!isNotification)
342
+ reply(id, {});
343
+ return;
344
+ case 'tools/list':
345
+ reply(id, {
346
+ tools: Object.entries(TOOLS).map(([name, t]) => ({
347
+ name, description: t.description, inputSchema: t.inputSchema,
348
+ })),
349
+ });
350
+ return;
351
+ case 'tools/call': {
352
+ const name = params?.name;
353
+ const tool = TOOLS[name];
354
+ if (!tool) {
355
+ replyError(id ?? null, -32602, `unknown tool: ${name}`);
356
+ return;
357
+ }
358
+ try {
359
+ const res = await tool.handler(params?.arguments ?? {});
360
+ const isErr = res.status >= 400;
361
+ const text = typeof res.body === 'string' ? res.body : JSON.stringify(res.body, null, 2);
362
+ reply(id, {
363
+ content: [{ type: 'text', text }],
364
+ isError: isErr,
365
+ });
366
+ }
367
+ catch (e) {
368
+ // Transport failure (server unreachable, timeout) — an in-band tool
369
+ // error so the model can see and report it, never a dead process.
370
+ reply(id, {
371
+ content: [{ type: 'text', text: `vitrinka unreachable at ${BASE_URL}: ${e instanceof Error ? e.message : String(e)}` }],
372
+ isError: true,
373
+ });
374
+ }
375
+ return;
376
+ }
377
+ default:
378
+ if (!isNotification)
379
+ replyError(id ?? null, -32601, `method not found: ${method}`);
380
+ }
381
+ }
382
+ const rl = createInterface({ input: process.stdin, terminal: false });
383
+ rl.on('line', (line) => {
384
+ const trimmed = line.trim();
385
+ if (!trimmed)
386
+ return;
387
+ let msg;
388
+ try {
389
+ msg = JSON.parse(trimmed);
390
+ }
391
+ catch (e) {
392
+ replyError(null, -32700, `parse error: ${e.message}`);
393
+ return;
394
+ }
395
+ void handle(msg).catch((e) => {
396
+ // handle() replies in-band for tool failures; anything reaching here is a
397
+ // server bug — log it loudly on stderr (never stdout: that's the protocol
398
+ // channel) and answer with an RPC error so the client isn't left hanging.
399
+ console.error('vitrinka-mcp internal error:', e);
400
+ if (msg.id !== undefined)
401
+ replyError(msg.id ?? null, -32603, 'internal error');
402
+ });
403
+ });
404
+ rl.on('close', () => process.exit(0));
405
+ //# sourceMappingURL=mcp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp.js","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"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"}
package/dist/work.js ADDED
@@ -0,0 +1,143 @@
1
+ #!/usr/bin/env node
2
+ // mcp/work.ts — the unattended fallback worker (board-v3 continuous-work
3
+ // design §daemon). When NO listening Claude Code session is open, this thin
4
+ // watcher long-polls /work/wait and spawns one `claude -p` per annotation —
5
+ // audit from the iPad at midnight and fixes still happen.
6
+ //
7
+ // The LISTENING SESSION is the primary lane (see /vitrinka:listen): it claims
8
+ // work by flipping status to "working", so the daemon waits a grace period
9
+ // and re-checks before spawning. Serial on purpose — one fix at a time.
10
+ //
11
+ // Zero dependencies, erasable TypeScript, same rules as server.ts.
12
+ //
13
+ // node mcp/work.ts --repo ~/Documents/Work/FixIt [--board <slug>] [--grace 8]
14
+ //
15
+ // Env: VITRINKA_BASE_URL (default https://vitrinka.lovinka.com),
16
+ // VITRINKA_TOKEN (~/.config/vitrinka/token fallback),
17
+ // CLAUDE_BIN (default "claude"; tests inject a stub).
18
+ import { spawn } from 'node:child_process';
19
+ import { existsSync } from 'node:fs';
20
+ import { join } from 'node:path';
21
+ import { fileURLToPath } from 'node:url';
22
+ import { readToken } from "./lib/token.js";
23
+ import { resolveBaseUrl } from "./lib/base-url.js";
24
+ import { makeApi } from "./lib/http.js";
25
+ const BASE_URL = resolveBaseUrl();
26
+ const CLAUDE_BIN = process.env.CLAUDE_BIN || 'claude';
27
+ const TOKEN = readToken();
28
+ function arg(name) {
29
+ const i = process.argv.indexOf(`--${name}`);
30
+ return i !== -1 ? process.argv[i + 1] : undefined;
31
+ }
32
+ const REPO = arg('repo');
33
+ const BOARD = arg('board');
34
+ const GRACE = Math.max(0, Number(arg('grace') ?? 8));
35
+ if (!REPO) {
36
+ console.error('usage: node mcp/work.ts --repo <app repo dir> [--board <slug>] [--grace <sec>]');
37
+ process.exit(2);
38
+ }
39
+ const rawApi = makeApi({ baseUrl: BASE_URL, token: TOKEN });
40
+ // The worker only ever does token-authed GETs; wrap the shared helper to keep
41
+ // the (path, timeoutMs) call shape the poll loop uses.
42
+ function api(path, timeoutMs = 30_000) {
43
+ return rawApi('GET', path, { timeoutMs });
44
+ }
45
+ const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
46
+ function runClaude(prompt) {
47
+ return new Promise((resolve) => {
48
+ const child = spawn(CLAUDE_BIN, ['-p', prompt, '--permission-mode', 'acceptEdits'], {
49
+ cwd: REPO,
50
+ stdio: 'inherit',
51
+ });
52
+ child.on('exit', (code) => resolve(code ?? 1));
53
+ child.on('error', (err) => {
54
+ console.error(`vitrinka-work: cannot spawn ${CLAUDE_BIN}:`, err.message);
55
+ resolve(1);
56
+ });
57
+ });
58
+ }
59
+ let stopping = false;
60
+ process.on('SIGINT', () => { stopping = true; });
61
+ process.on('SIGTERM', () => { stopping = true; });
62
+ // refreshIndex keeps the repo's file/route autocomplete index fresh while the
63
+ // daemon is the active lane (project-index design 2026-07-05). Delegates to
64
+ // the CLI (the single index-builder implementation); hash-gated there, so an
65
+ // unchanged repo is one no-op process. Missing CLI warns once.
66
+ //
67
+ // The worker and CLI ship in the same package, so prefer the sibling module
68
+ // (dist/cli.js when compiled, ./cli.ts when running from source); $VITRINKA_CLI
69
+ // overrides, and the legacy global-skill path is the last resort.
70
+ function resolveIndexCli() {
71
+ if (process.env.VITRINKA_CLI)
72
+ return process.env.VITRINKA_CLI;
73
+ for (const ext of ['cli.js', 'cli.ts']) {
74
+ const sibling = fileURLToPath(new URL(`./${ext}`, import.meta.url));
75
+ if (existsSync(sibling))
76
+ return sibling;
77
+ }
78
+ return join(process.env.HOME || '', '.claude', 'skills', 'vitrinka', 'cli.ts');
79
+ }
80
+ const INDEX_CLI = resolveIndexCli();
81
+ let indexCliWarned = false;
82
+ function refreshIndex() {
83
+ return new Promise((resolve) => {
84
+ if (!existsSync(INDEX_CLI)) {
85
+ if (!indexCliWarned) {
86
+ indexCliWarned = true;
87
+ console.error(`vitrinka-work: no CLI at ${INDEX_CLI} — project index stays stale (set VITRINKA_CLI)`);
88
+ }
89
+ return resolve();
90
+ }
91
+ const child = spawn(process.execPath, [INDEX_CLI, 'index', '--root', join(REPO, '.screenshots')], { stdio: ['ignore', 'inherit', 'inherit'] });
92
+ child.on('exit', () => resolve());
93
+ child.on('error', (err) => {
94
+ console.error('vitrinka-work: index refresh failed to spawn:', err.message);
95
+ resolve();
96
+ });
97
+ });
98
+ }
99
+ async function main() {
100
+ console.error(`vitrinka-work: watching ${BASE_URL}${BOARD ? ` board ${BOARD}` : ''} → ${REPO} (grace ${GRACE}s)`);
101
+ await refreshIndex();
102
+ while (!stopping) {
103
+ let res;
104
+ try {
105
+ const q = new URLSearchParams({ timeout: '55' });
106
+ if (BOARD)
107
+ q.set('board', BOARD);
108
+ res = await api(`/api/v1/work/wait?${q}`, 70_000);
109
+ }
110
+ catch (e) {
111
+ console.error('vitrinka-work: wait failed, retrying in 5s:', e instanceof Error ? e.message : e);
112
+ await sleep(5_000);
113
+ continue;
114
+ }
115
+ if (res.status >= 400 || !Array.isArray(res.body?.work) || res.body.work.length === 0) {
116
+ continue; // idle window (or transient server error → next poll)
117
+ }
118
+ for (const item of res.body.work) {
119
+ if (stopping)
120
+ return;
121
+ // Grace: a listening session claims by flipping status to "working".
122
+ if (GRACE > 0)
123
+ await sleep(GRACE * 1_000);
124
+ try {
125
+ const check = await api(`/api/v1/annotations/${item.id}`);
126
+ if (check.status >= 400 || check.body?.annotation?.status !== 'open') {
127
+ console.error(`vitrinka-work: №${item.id} claimed elsewhere — skipping`);
128
+ continue;
129
+ }
130
+ }
131
+ catch {
132
+ continue; // re-discovered on the next poll if still open
133
+ }
134
+ console.error(`vitrinka-work: №${item.id} → claude -p (cwd ${REPO})`);
135
+ const prompt = `${item.capsule}\nYou are the vitrinka unattended worker. Follow the protocol above using the vitrinka MCP tools, working in this repository. Serial, this one annotation only.`;
136
+ const code = await runClaude(prompt);
137
+ console.error(`vitrinka-work: №${item.id} session exited (${code})`);
138
+ await refreshIndex(); // the fix may have added routes/files
139
+ }
140
+ }
141
+ }
142
+ void main().then(() => process.exit(0));
143
+ //# sourceMappingURL=work.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"work.js","sourceRoot":"","sources":["../src/work.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@lovinka/vitrinka",
3
+ "version": "1.1.0",
4
+ "description": "vitrinka CLI + MCP server — capture and publish artifact sets, drive the annotation-board work queue from any MCP-aware AI.",
5
+ "type": "module",
6
+ "bin": {
7
+ "vitrinka": "dist/cli.js",
8
+ "vitrinka-mcp": "dist/bin-mcp.js"
9
+ },
10
+ "files": [
11
+ "dist",
12
+ "README.md"
13
+ ],
14
+ "scripts": {
15
+ "build": "tsc -p tsconfig.json",
16
+ "dev": "tsc -p tsconfig.json --watch",
17
+ "typecheck": "tsc -p tsconfig.json --noEmit",
18
+ "test": "node --test tests/*.test.mjs tests/*.test.ts",
19
+ "prepublishOnly": "npm run build"
20
+ },
21
+ "engines": {
22
+ "node": ">=20"
23
+ },
24
+ "keywords": [
25
+ "mcp",
26
+ "model-context-protocol",
27
+ "vitrinka",
28
+ "lovinka",
29
+ "cli",
30
+ "screenshots",
31
+ "ai"
32
+ ],
33
+ "author": "Lovinka",
34
+ "license": "MIT",
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "git+https://github.com/lefteq/vitrinka.git",
38
+ "directory": "pkg"
39
+ },
40
+ "devDependencies": {
41
+ "@types/node": "^22.10.0",
42
+ "typescript": "^5.8.0"
43
+ }
44
+ }