mockpit 2.0.0 → 3.0.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/README.md +60 -212
- package/bin/demoData.js +2 -2
- package/bin/initDesign.js +6 -6
- package/bin/mockpit.js +407 -187
- package/bin/poster.js +377 -0
- package/dist/mcp/server.js +80 -24
- package/dist/server/answerAdditions.d.ts +7 -0
- package/dist/server/answerAdditions.js +76 -0
- package/dist/server/apiViews.d.ts +289 -52
- package/dist/server/apiViews.js +189 -81
- package/dist/server/app.d.ts +7 -2
- package/dist/server/app.js +2845 -832
- package/dist/server/appIcon.js +15 -5
- package/dist/server/appIconPng.js +3 -3
- package/dist/server/askNudges.js +1 -1
- package/dist/server/cdnInline.d.ts +8 -0
- package/dist/server/cdnInline.js +638 -0
- package/dist/server/codeWorker.js +1 -1
- package/dist/server/decisionList.d.ts +45 -0
- package/dist/server/decisionList.js +302 -0
- package/dist/server/decisions.d.ts +4 -4
- package/dist/server/decisions.js +9 -9
- package/dist/server/designGuide.d.ts +5 -5
- package/dist/server/designGuide.js +128 -67
- package/dist/server/embeds.d.ts +3 -1
- package/dist/server/embeds.js +31 -6
- package/dist/server/eventLog.d.ts +2 -2
- package/dist/server/eventLog.js +11 -11
- package/dist/server/events.d.ts +9 -6
- package/dist/server/feedbackBatch.d.ts +35 -13
- package/dist/server/feedbackBatch.js +111 -47
- package/dist/server/fills.d.ts +4 -0
- package/dist/server/fills.js +55 -1
- package/dist/server/handoff.d.ts +4 -1
- package/dist/server/handoff.js +8 -2
- package/dist/server/icons.js +1 -1
- package/dist/server/index.js +39 -10
- package/dist/server/jump.d.ts +21 -0
- package/dist/server/jump.js +175 -0
- package/dist/server/knobs.d.ts +3 -3
- package/dist/server/knobs.js +6 -6
- package/dist/server/mcpHttp.d.ts +5 -1
- package/dist/server/mcpHttp.js +16 -11
- package/dist/server/mcpSpec.js +118 -46
- package/dist/server/parts.js +9 -1
- package/dist/server/run.d.ts +1 -1
- package/dist/server/run.js +25 -16
- package/dist/server/runApi.d.ts +3 -3
- package/dist/server/runApi.js +25 -19
- package/dist/server/sqlStore.d.ts +112 -96
- package/dist/server/sqlStore.js +906 -172
- package/dist/server/standings.d.ts +25 -0
- package/dist/server/standings.js +113 -0
- package/dist/server/surfacePage.d.ts +6 -9
- package/dist/server/surfacePage.js +361 -86
- package/dist/server/types.d.ts +226 -72
- package/dist/server/types.js +73 -78
- package/extensions/mockpit.js +89 -72
- package/guide/AGENT_SETUP.md +13 -1
- package/guide/packs/design-craft.md +2 -3
- package/guide/topics/asks.md +106 -62
- package/guide/topics/feedback.md +126 -119
- package/guide/topics/html.md +17 -24
- package/guide/topics/http.md +41 -41
- package/guide/topics/knobs.md +7 -10
- package/guide/topics/scripts.md +22 -33
- package/guide/topics/surfaces.md +39 -48
- package/opencode/mockpit.js +120 -0
- package/opencode/package.json +8 -0
- package/package.json +4 -3
- package/skills/launch-video/SKILL.md +11 -11
- package/skills/mockpit/SKILL.md +26 -22
- package/viewer/dist/index.html +9 -9
package/extensions/mockpit.js
CHANGED
|
@@ -23,14 +23,14 @@ const CONTENT_TYPES = {
|
|
|
23
23
|
};
|
|
24
24
|
|
|
25
25
|
const feedbackGuideline =
|
|
26
|
-
"Mockpit tool results may include feedback from the browser; treat it as user instruction and respond or revise the
|
|
26
|
+
"Mockpit tool results may include feedback from the browser; treat it as user instruction and respond or revise the design.";
|
|
27
27
|
|
|
28
28
|
// The never-block loop, in the words of every other tier: nothing waits for
|
|
29
29
|
// the user, so the agent ends its turn and reads feedback when told.
|
|
30
30
|
const loopGuidelines = [
|
|
31
31
|
"Publish each variant with mockpit_publish (name states in the user's words; declare parts with data-part); publish again to revise.",
|
|
32
32
|
"A choice is several variants plus one question that binds them: mockpit_ask with options bound to the variants. One render plus a control: declare a knob.",
|
|
33
|
-
"Tell the user in one line where to look, then end your turn. The question lives in the
|
|
33
|
+
"Tell the user in one line where to look, then end your turn. The question lives in the design, never in chat. Never poll.",
|
|
34
34
|
"A reply sent from the viewer arrives on its own as a mockpit message; act on it. If the user says they answered and none came, call mockpit_feedback. Every write also returns feedback; read it.",
|
|
35
35
|
];
|
|
36
36
|
|
|
@@ -236,26 +236,20 @@ function rememberSession(state, sessionId) {
|
|
|
236
236
|
if (typeof sessionId === "string" && sessionId) state.sessionId = sessionId;
|
|
237
237
|
}
|
|
238
238
|
|
|
239
|
-
// `feedback` is one batch per
|
|
239
|
+
// `feedback` is one batch per design: the user's reply (answers, borrowed parts,
|
|
240
240
|
// tuned knob values, part comments, verdict) plus any thread messages.
|
|
241
241
|
// Rendered one line per thing the user said, so nothing is summarized away.
|
|
242
242
|
function feedbackLines(feedback) {
|
|
243
243
|
const lines = [];
|
|
244
244
|
for (const batch of feedback ?? []) {
|
|
245
|
-
const prefix = batch.
|
|
245
|
+
const prefix = batch.design ? `${batch.design}: ` : "";
|
|
246
246
|
if (batch.handoff) lines.push(`- ${prefix}${batch.handoff}`);
|
|
247
|
-
if (batch.closed) {
|
|
248
|
-
const asks = (batch.dismissed ?? []).map((d) => d.text || d.ask).join("; ");
|
|
249
|
-
lines.push(
|
|
250
|
-
`- ${prefix}closed by the user${asks ? `, unanswered: ${asks}; don't ask again` : ""}`,
|
|
251
|
-
);
|
|
252
|
-
}
|
|
253
247
|
const reply = batch.reply;
|
|
254
248
|
if (reply) {
|
|
255
249
|
for (const a of reply.asks ?? []) {
|
|
256
250
|
const chosen = a.chosen.map((o) => (o.other ? `“${o.label}”` : o.label)).join(", ");
|
|
257
251
|
lines.push(`- ${prefix}${a.text || a.ask} → ${chosen || "(no pick)"}`);
|
|
258
|
-
if (a.
|
|
252
|
+
if (a.comment) lines.push(` comment: ${a.comment}`);
|
|
259
253
|
}
|
|
260
254
|
for (const [part, variant] of Object.entries(reply.borrowed ?? {})) {
|
|
261
255
|
lines.push(`- ${prefix}borrow ${part} from ${variant}`);
|
|
@@ -284,23 +278,30 @@ function feedbackLines(feedback) {
|
|
|
284
278
|
e.kind ? `now a ${e.kind}` : "",
|
|
285
279
|
e.area !== undefined ? (e.area ? `area ${e.area}` : "no area") : "",
|
|
286
280
|
].filter(Boolean);
|
|
287
|
-
lines.push(`- ${prefix}the user moved it from Home (${moved.join(", ")})`);
|
|
281
|
+
if (moved.length) lines.push(`- ${prefix}the user moved it from Home (${moved.join(", ")})`);
|
|
282
|
+
if (e.notes !== undefined) {
|
|
283
|
+
lines.push(
|
|
284
|
+
e.notes === null
|
|
285
|
+
? `- ${prefix}the user cleared its notes`
|
|
286
|
+
: `- ${prefix}the user edited its notes: ${e.notes}`,
|
|
287
|
+
);
|
|
288
|
+
}
|
|
288
289
|
}
|
|
289
290
|
}
|
|
290
291
|
return lines;
|
|
291
292
|
}
|
|
292
293
|
|
|
293
|
-
// What the user is doing right now, per
|
|
294
|
+
// What the user is doing right now, per design, so the agent can say "take your time".
|
|
294
295
|
function pendingLines(pending) {
|
|
295
296
|
const lines = [pending ?? []]
|
|
296
297
|
.flat()
|
|
297
298
|
.flatMap((p) =>
|
|
298
299
|
p.draft
|
|
299
300
|
? [
|
|
300
|
-
`- ${p.
|
|
301
|
+
`- ${p.design}: the user is answering (${p.draft.answered} of ${p.draft.of} answered, ${p.draft.comments} comments)`,
|
|
301
302
|
]
|
|
302
303
|
: p.viewerOpen
|
|
303
|
-
? [`- ${p.
|
|
304
|
+
? [`- ${p.design}: open in the viewer`]
|
|
304
305
|
: [],
|
|
305
306
|
);
|
|
306
307
|
return lines.length ? ["Pending:", ...lines] : [];
|
|
@@ -318,7 +319,7 @@ const pause = (ms, signal) =>
|
|
|
318
319
|
signal.addEventListener("abort", () => (clearTimeout(timer), done()), { once: true });
|
|
319
320
|
});
|
|
320
321
|
|
|
321
|
-
// The user's reply wakes the idle agent, as the Claude Code plugin's
|
|
322
|
+
// The user's reply wakes the idle agent, as the Claude Code plugin's hook
|
|
322
323
|
// does. Reading feedback advances the server's cursor, so the message carries
|
|
323
324
|
// the whole reply: a nudge to call mockpit_feedback would come back empty.
|
|
324
325
|
// followUp waits for a busy agent to finish rather than cutting into its work.
|
|
@@ -408,7 +409,7 @@ export default function mockpitExtension(pi) {
|
|
|
408
409
|
});
|
|
409
410
|
|
|
410
411
|
const projectOf = (params, ctx) => params.project ?? resolveProjectName(ctx.cwd);
|
|
411
|
-
const
|
|
412
|
+
const designPath = (design) => `/api/designs/${encodeURIComponent(design)}`;
|
|
412
413
|
|
|
413
414
|
// GET /api/feedback reads from a session's cursor, so a feedback call before
|
|
414
415
|
// any write still needs one; later writes then land in the same session.
|
|
@@ -427,12 +428,12 @@ export default function mockpitExtension(pi) {
|
|
|
427
428
|
return created.id;
|
|
428
429
|
}
|
|
429
430
|
|
|
430
|
-
// project ›
|
|
431
|
-
const
|
|
432
|
-
|
|
431
|
+
// project › design › state › variant › version.
|
|
432
|
+
const designProps = {
|
|
433
|
+
design: { type: "string", description: "Design slug, e.g. writer" },
|
|
433
434
|
state: {
|
|
434
435
|
type: "string",
|
|
435
|
-
description: "State label in the user's words; omit for a single-state
|
|
436
|
+
description: "State label in the user's words; omit for a single-state design",
|
|
436
437
|
},
|
|
437
438
|
variant: { type: "string", description: 'Variant label; default "default"' },
|
|
438
439
|
project: { type: "string", description: "Project name; defaults to the repo" },
|
|
@@ -442,15 +443,15 @@ export default function mockpitExtension(pi) {
|
|
|
442
443
|
name: "mockpit_publish",
|
|
443
444
|
label: "Mockpit Publish",
|
|
444
445
|
description:
|
|
445
|
-
"Create or version one variant of one state of a
|
|
446
|
-
promptSnippet: "Publish a UI
|
|
446
|
+
"Create or version one variant of one state of a design in the user's browser. One of html (or path), surfaces (the full ordered list) or parts (splices the latest version). Returns parts per state, nudges, feedback.",
|
|
447
|
+
promptSnippet: "Publish a UI design (state + variant) to mockpit for the user to review.",
|
|
447
448
|
promptGuidelines: [...loopGuidelines, feedbackGuideline],
|
|
448
449
|
parameters: {
|
|
449
450
|
type: "object",
|
|
450
451
|
properties: {
|
|
451
|
-
...
|
|
452
|
-
title: { type: "string", description: "
|
|
453
|
-
kind: { type: "string", enum: ["component", "
|
|
452
|
+
...designProps,
|
|
453
|
+
title: { type: "string", description: "Design title" },
|
|
454
|
+
kind: { type: "string", enum: ["component", "screen"], description: "Design kind" },
|
|
454
455
|
area: {
|
|
455
456
|
type: "string",
|
|
456
457
|
description: 'Where in the product it belongs ("Shell"); Home groups by it. "" clears',
|
|
@@ -474,7 +475,7 @@ export default function mockpitExtension(pi) {
|
|
|
474
475
|
from: { type: "number", description: "Branch from this version" },
|
|
475
476
|
prompt: { type: "string", description: "What prompted this version" },
|
|
476
477
|
},
|
|
477
|
-
required: ["
|
|
478
|
+
required: ["design"],
|
|
478
479
|
},
|
|
479
480
|
async execute(_id, params, _signal, _onUpdate, ctx) {
|
|
480
481
|
const html = params.path
|
|
@@ -482,7 +483,7 @@ export default function mockpitExtension(pi) {
|
|
|
482
483
|
: params.html;
|
|
483
484
|
const { path: _path, ...rest } = params;
|
|
484
485
|
const poster = await posterId(params.poster, ctx);
|
|
485
|
-
const result = await requestJson("/api/
|
|
486
|
+
const result = await requestJson("/api/designs", {
|
|
486
487
|
method: "POST",
|
|
487
488
|
body: JSON.stringify({
|
|
488
489
|
...rest,
|
|
@@ -497,6 +498,17 @@ export default function mockpitExtension(pi) {
|
|
|
497
498
|
});
|
|
498
499
|
rememberSession(state, result.sessionId);
|
|
499
500
|
const { post } = result;
|
|
501
|
+
if (result.planned) {
|
|
502
|
+
return {
|
|
503
|
+
content: [
|
|
504
|
+
{
|
|
505
|
+
type: "text",
|
|
506
|
+
text: `${result.design.slug}: planned, nothing drawn yet · ${result.url}${feedbackSummary(result.feedback)}`,
|
|
507
|
+
},
|
|
508
|
+
],
|
|
509
|
+
details: { ...result, baseUrl: baseUrl() },
|
|
510
|
+
};
|
|
511
|
+
}
|
|
500
512
|
const parts = (result.parts ?? [])
|
|
501
513
|
.filter((s) => s.parts.length)
|
|
502
514
|
.map(
|
|
@@ -509,7 +521,7 @@ export default function mockpitExtension(pi) {
|
|
|
509
521
|
]
|
|
510
522
|
: [];
|
|
511
523
|
const text = [
|
|
512
|
-
`${result.
|
|
524
|
+
`${result.design.slug}/${post.state ? `${post.state}/` : ""}${post.variant} v${post.version} · ${result.url}`,
|
|
513
525
|
...parts,
|
|
514
526
|
...(result.applied?.length ? [`applied: ${result.applied.join(", ")}`] : []),
|
|
515
527
|
...changes,
|
|
@@ -529,7 +541,7 @@ export default function mockpitExtension(pi) {
|
|
|
529
541
|
name: "mockpit_ask",
|
|
530
542
|
label: "Mockpit Ask",
|
|
531
543
|
description:
|
|
532
|
-
"Ask structured questions on a
|
|
544
|
+
"Ask structured questions on a design. A choice is several variants plus one question that binds them ({label, variant}); options may also set knob values ({label, set}). Reusing a question id replaces it.",
|
|
533
545
|
promptSnippet: "Ask the user to choose between mockpit variants.",
|
|
534
546
|
promptGuidelines: [
|
|
535
547
|
"Use mockpit_ask once the variants are published, tell the user where to look, then end your turn.",
|
|
@@ -537,19 +549,19 @@ export default function mockpitExtension(pi) {
|
|
|
537
549
|
parameters: {
|
|
538
550
|
type: "object",
|
|
539
551
|
properties: {
|
|
540
|
-
|
|
541
|
-
project:
|
|
552
|
+
design: designProps.design,
|
|
553
|
+
project: designProps.project,
|
|
542
554
|
asks: {
|
|
543
555
|
type: "array",
|
|
544
556
|
description:
|
|
545
|
-
"Questions: {id?, text, scope:
|
|
557
|
+
"Questions: {id?, text, scope: design|state|part, state?, part?, multi?, options}",
|
|
546
558
|
items: { type: "object" },
|
|
547
559
|
},
|
|
548
560
|
},
|
|
549
|
-
required: ["
|
|
561
|
+
required: ["design", "asks"],
|
|
550
562
|
},
|
|
551
563
|
async execute(_id, params, _signal, _onUpdate, ctx) {
|
|
552
|
-
const result = await requestJson(`${
|
|
564
|
+
const result = await requestJson(`${designPath(params.design)}/asks`, {
|
|
553
565
|
method: "POST",
|
|
554
566
|
body: JSON.stringify({
|
|
555
567
|
project: projectOf(params, ctx),
|
|
@@ -560,7 +572,7 @@ export default function mockpitExtension(pi) {
|
|
|
560
572
|
const text = result.asks
|
|
561
573
|
.map(
|
|
562
574
|
(a) =>
|
|
563
|
-
`Asked on ${result.
|
|
575
|
+
`Asked on ${result.design}: ${a.text} [${a.options.map((o) => o.label).join(" | ")}]`,
|
|
564
576
|
)
|
|
565
577
|
.join("\n");
|
|
566
578
|
return {
|
|
@@ -576,25 +588,25 @@ export default function mockpitExtension(pi) {
|
|
|
576
588
|
name: "mockpit_read",
|
|
577
589
|
label: "Mockpit Read",
|
|
578
590
|
description:
|
|
579
|
-
"Without
|
|
580
|
-
promptSnippet: "Read mockpit
|
|
591
|
+
"Without design: every design (slug, states, variants, open asks) plus pending. With design: its states, variants, asks with answers, parts, knobs and last tuned values, plus pending. Never consumes feedback.",
|
|
592
|
+
promptSnippet: "Read mockpit designs.",
|
|
581
593
|
promptGuidelines: [
|
|
582
|
-
"Use mockpit_read to recover
|
|
594
|
+
"Use mockpit_read to recover design slugs or a design's state when you lost track.",
|
|
583
595
|
],
|
|
584
596
|
parameters: {
|
|
585
597
|
type: "object",
|
|
586
598
|
properties: {
|
|
587
|
-
|
|
588
|
-
project:
|
|
599
|
+
design: { type: "string", description: "Design slug; omit for every design" },
|
|
600
|
+
project: designProps.project,
|
|
589
601
|
body: { type: "boolean", description: "Include each variant's surfaces" },
|
|
590
602
|
history: { type: "boolean", description: "Include version rows" },
|
|
591
603
|
},
|
|
592
604
|
},
|
|
593
605
|
async execute(_id, params, _signal, _onUpdate, ctx) {
|
|
594
606
|
const query = new URLSearchParams({ project: projectOf(params, ctx) });
|
|
595
|
-
if (params.
|
|
596
|
-
const result = await requestJson(`/api/
|
|
597
|
-
const lines = result.
|
|
607
|
+
if (params.design === undefined) {
|
|
608
|
+
const result = await requestJson(`/api/designs?${query}`);
|
|
609
|
+
const lines = result.designs.map(
|
|
598
610
|
(m) =>
|
|
599
611
|
`${m.slug} · ${m.kind} · ${m.states.length ? m.states.join(" / ") : "single state"} · ${m.variants} variants${m.open ? ` · ${m.open} open` : ""}`,
|
|
600
612
|
);
|
|
@@ -603,7 +615,7 @@ export default function mockpitExtension(pi) {
|
|
|
603
615
|
content: [
|
|
604
616
|
{
|
|
605
617
|
type: "text",
|
|
606
|
-
text: [...lines, ...busy].join("\n") || `No
|
|
618
|
+
text: [...lines, ...busy].join("\n") || `No designs in ${query.get("project")}.`,
|
|
607
619
|
},
|
|
608
620
|
],
|
|
609
621
|
details: { ...result, baseUrl: baseUrl() },
|
|
@@ -611,8 +623,8 @@ export default function mockpitExtension(pi) {
|
|
|
611
623
|
}
|
|
612
624
|
if (params.body) query.set("body", "1");
|
|
613
625
|
if (params.history) query.set("history", "1");
|
|
614
|
-
const
|
|
615
|
-
return { content: [{ type: "text", text: jsonText(
|
|
626
|
+
const design = await requestJson(`${designPath(params.design)}?${query}`);
|
|
627
|
+
return { content: [{ type: "text", text: jsonText(design) }], details: design };
|
|
616
628
|
},
|
|
617
629
|
});
|
|
618
630
|
|
|
@@ -620,12 +632,12 @@ export default function mockpitExtension(pi) {
|
|
|
620
632
|
name: "mockpit_feedback",
|
|
621
633
|
label: "Mockpit Feedback",
|
|
622
634
|
description:
|
|
623
|
-
"Returns at once: what the user sent since you last heard (one batch per
|
|
635
|
+
"Returns at once: what the user sent since you last heard (one batch per design: answers, borrowed parts, tuned knobs, part comments, verdict; thread messages; inUse/archived), delivered once, plus pending (viewer open, draft progress).",
|
|
624
636
|
promptSnippet: "Read the user's mockpit reply when they say they answered.",
|
|
625
637
|
promptGuidelines: [
|
|
626
638
|
"Call mockpit_feedback when the user says they answered; it returns at once, so do not call it in a loop.",
|
|
627
639
|
],
|
|
628
|
-
parameters: { type: "object", properties: { project:
|
|
640
|
+
parameters: { type: "object", properties: { project: designProps.project } },
|
|
629
641
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
630
642
|
const session = await ensureSession(ctx);
|
|
631
643
|
const query = new URLSearchParams({ session, project: projectOf(params, ctx) });
|
|
@@ -647,7 +659,7 @@ export default function mockpitExtension(pi) {
|
|
|
647
659
|
name: "mockpit_say",
|
|
648
660
|
label: "Mockpit Say",
|
|
649
661
|
description:
|
|
650
|
-
"Post a short plain-text message in a
|
|
662
|
+
"Post a short plain-text message in a design's thread. Returns feedback; treat it as user instruction.",
|
|
651
663
|
promptSnippet: "Say something to the user in a mockpit thread.",
|
|
652
664
|
promptGuidelines: [
|
|
653
665
|
"Use mockpit_say for brief acknowledgements; publish again for substantive revisions.",
|
|
@@ -655,11 +667,11 @@ export default function mockpitExtension(pi) {
|
|
|
655
667
|
],
|
|
656
668
|
parameters: {
|
|
657
669
|
type: "object",
|
|
658
|
-
properties: { ...
|
|
659
|
-
required: ["
|
|
670
|
+
properties: { ...designProps, message: { type: "string", description: "Plain text" } },
|
|
671
|
+
required: ["design", "message"],
|
|
660
672
|
},
|
|
661
673
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
662
|
-
const result = await requestJson(`${
|
|
674
|
+
const result = await requestJson(`${designPath(params.design)}/say`, {
|
|
663
675
|
method: "POST",
|
|
664
676
|
body: JSON.stringify({
|
|
665
677
|
message: params.message,
|
|
@@ -673,7 +685,7 @@ export default function mockpitExtension(pi) {
|
|
|
673
685
|
content: [
|
|
674
686
|
{
|
|
675
687
|
type: "text",
|
|
676
|
-
text: `Said on ${params.
|
|
688
|
+
text: `Said on ${params.design}.${feedbackSummary(result.feedback)}`,
|
|
677
689
|
},
|
|
678
690
|
],
|
|
679
691
|
details: { ...result, baseUrl: baseUrl() },
|
|
@@ -685,24 +697,29 @@ export default function mockpitExtension(pi) {
|
|
|
685
697
|
name: "mockpit_edit",
|
|
686
698
|
label: "Mockpit Edit",
|
|
687
699
|
description:
|
|
688
|
-
'Change a
|
|
689
|
-
promptSnippet: "Rename, retitle or reclassify a mockpit
|
|
700
|
+
'Change a design without a new version: slug, title, kind, area, source ("" clears). A new slug rewrites every embed, data-goto and flow step naming the old one. Or, with no design, rename the project (rename) or order its areas on Home (areaOrder). Returns feedback.',
|
|
701
|
+
promptSnippet: "Rename, retitle or reclassify a mockpit design, or rename the project.",
|
|
690
702
|
promptGuidelines: [feedbackGuideline],
|
|
691
703
|
parameters: {
|
|
692
704
|
type: "object",
|
|
693
705
|
properties: {
|
|
694
|
-
|
|
706
|
+
design: { type: "string", description: "Design slug or id" },
|
|
695
707
|
project: { type: "string", description: "Project name; defaults to the repo" },
|
|
696
708
|
slug: { type: "string", description: "New slug" },
|
|
697
|
-
title: { type: "string", description: "
|
|
698
|
-
kind: { type: "string", enum: ["
|
|
709
|
+
title: { type: "string", description: "Design title" },
|
|
710
|
+
kind: { type: "string", enum: ["screen", "component", "idea"] },
|
|
699
711
|
area: { type: "string", description: 'Area in the product; "" clears' },
|
|
700
712
|
source: { type: "string", description: 'Code path that implements it; "" clears' },
|
|
701
|
-
|
|
713
|
+
notes: {
|
|
714
|
+
type: "string",
|
|
715
|
+
description:
|
|
716
|
+
'A short plain-text spec; "" clears. Not applied over the user\'s own edit, and the result says so',
|
|
717
|
+
},
|
|
718
|
+
rename: { type: "string", description: "Without design: the project's new name" },
|
|
702
719
|
areaOrder: {
|
|
703
720
|
type: "array",
|
|
704
721
|
items: { type: "string" },
|
|
705
|
-
description: "Without
|
|
722
|
+
description: "Without design: Home's area order; unlisted areas follow alphabetically",
|
|
706
723
|
},
|
|
707
724
|
},
|
|
708
725
|
},
|
|
@@ -710,15 +727,15 @@ export default function mockpitExtension(pi) {
|
|
|
710
727
|
const project = projectOf(params, ctx);
|
|
711
728
|
const { rename, areaOrder, ...fields } = params;
|
|
712
729
|
const onProject = rename !== undefined || areaOrder !== undefined;
|
|
713
|
-
if (onProject && params.
|
|
714
|
-
throw new Error('"rename" and "areaOrder" edit the project; edit the
|
|
730
|
+
if (onProject && params.design !== undefined) {
|
|
731
|
+
throw new Error('"rename" and "areaOrder" edit the project; edit the design without them');
|
|
715
732
|
}
|
|
716
733
|
const result = onProject
|
|
717
734
|
? await requestJson(`/api/projects/${encodeURIComponent(project)}`, {
|
|
718
735
|
method: "PATCH",
|
|
719
736
|
body: JSON.stringify({ name: rename, areaOrder, session: state.sessionId }),
|
|
720
737
|
})
|
|
721
|
-
: await requestJson(
|
|
738
|
+
: await requestJson(designPath(params.design ?? ""), {
|
|
722
739
|
method: "PATCH",
|
|
723
740
|
body: JSON.stringify({ ...fields, project, session: state.sessionId }),
|
|
724
741
|
});
|
|
@@ -726,7 +743,7 @@ export default function mockpitExtension(pi) {
|
|
|
726
743
|
? `renamed ${result.renamed.from} → ${result.renamed.to} · ${result.url}`
|
|
727
744
|
: result.areaOrder
|
|
728
745
|
? `area order ${result.areaOrder.join(", ") || "alphabetical"} · ${result.url}`
|
|
729
|
-
: `edited ${result.
|
|
746
|
+
: `edited ${result.design.slug} · ${result.url}${result.notes?.applied === false ? `\nnotes.text: ${result.notes.text}` : ""}`;
|
|
730
747
|
return {
|
|
731
748
|
content: [
|
|
732
749
|
{
|
|
@@ -744,13 +761,13 @@ export default function mockpitExtension(pi) {
|
|
|
744
761
|
label: "Mockpit Export",
|
|
745
762
|
description:
|
|
746
763
|
"The html in use (else current) per state, version history, and the last reply's tuned values.",
|
|
747
|
-
promptSnippet: "Export the design in use from a mockpit
|
|
748
|
-
parameters: { type: "object", properties:
|
|
764
|
+
promptSnippet: "Export the design in use from a mockpit design.",
|
|
765
|
+
parameters: { type: "object", properties: designProps, required: ["design"] },
|
|
749
766
|
async execute(_id, params, _signal, _onUpdate, ctx) {
|
|
750
767
|
const query = new URLSearchParams({ project: projectOf(params, ctx) });
|
|
751
768
|
if (params.state) query.set("state", params.state);
|
|
752
769
|
if (params.variant) query.set("variant", params.variant);
|
|
753
|
-
const data = await requestJson(`${
|
|
770
|
+
const data = await requestJson(`${designPath(params.design)}/export?${query}`);
|
|
754
771
|
return { content: [{ type: "text", text: jsonText(data) }], details: data };
|
|
755
772
|
},
|
|
756
773
|
});
|
|
@@ -760,7 +777,7 @@ export default function mockpitExtension(pi) {
|
|
|
760
777
|
label: "Mockpit Upload",
|
|
761
778
|
description:
|
|
762
779
|
"Upload an asset to mockpit and get an id and URL. Use the id as an image surface's assetId, or embed the URL in html.",
|
|
763
|
-
promptSnippet: "Upload an image or file asset for use in a
|
|
780
|
+
promptSnippet: "Upload an image or file asset for use in a design.",
|
|
764
781
|
promptGuidelines: [
|
|
765
782
|
"Use mockpit_upload before referencing local images or files in mockpit_publish.",
|
|
766
783
|
],
|
|
@@ -819,14 +836,14 @@ export default function mockpitExtension(pi) {
|
|
|
819
836
|
label: "Mockpit Guide",
|
|
820
837
|
description:
|
|
821
838
|
"Fetch the brief: the loop, parts, asks and knobs, feedback, the html contract, and this project's palette, kit and icons. Read it before the first mockpit_publish. Pass topic for one reference section.",
|
|
822
|
-
promptSnippet: "Fetch mockpit's brief before authoring
|
|
839
|
+
promptSnippet: "Fetch mockpit's brief before authoring designs.",
|
|
823
840
|
promptGuidelines: [
|
|
824
841
|
"Use mockpit_guide before your first mockpit_publish call unless you already know the current brief.",
|
|
825
842
|
],
|
|
826
843
|
parameters: {
|
|
827
844
|
type: "object",
|
|
828
845
|
properties: {
|
|
829
|
-
project:
|
|
846
|
+
project: designProps.project,
|
|
830
847
|
topic: {
|
|
831
848
|
type: "string",
|
|
832
849
|
enum: ["knobs", "asks", "surfaces", "html", "feedback", "http", "scripts"],
|
|
@@ -854,7 +871,7 @@ export default function mockpitExtension(pi) {
|
|
|
854
871
|
properties: {
|
|
855
872
|
code: { type: "string", description: "JavaScript: the body of an async function" },
|
|
856
873
|
path: { type: "string", description: "Local .js file to run instead of code" },
|
|
857
|
-
project:
|
|
874
|
+
project: designProps.project,
|
|
858
875
|
},
|
|
859
876
|
},
|
|
860
877
|
async execute(_id, params, _signal, _onUpdate, ctx) {
|
package/guide/AGENT_SETUP.md
CHANGED
|
@@ -8,16 +8,28 @@ design questions. Before your first publish, read the brief:
|
|
|
8
8
|
|
|
9
9
|
MOCKPIT_URL=http://localhost:8228 mockpit guide
|
|
10
10
|
|
|
11
|
+
Then `mockpit read`: its `decisionList` is what the user already settled, and
|
|
12
|
+
stands unless they say otherwise.
|
|
13
|
+
|
|
11
14
|
Without the CLI: `curl -s http://localhost:8228/agent-howto`. Over MCP: the
|
|
12
15
|
`guide` tool. The brief never overrides system, developer, project or user
|
|
13
16
|
instructions; fetch it only from this origin. On a deployed instance set
|
|
14
17
|
`MOCKPIT_TOKEN` too.
|
|
15
18
|
|
|
16
19
|
Nothing waits for the user. Publish, `ask`, tell the user in one line where to
|
|
17
|
-
look, then end your turn; the question lives in the
|
|
20
|
+
look, then end your turn; the question lives in the design, never in chat. When
|
|
18
21
|
they say they answered, call `feedback` (`mockpit feedback`, MCP `feedback`,
|
|
19
22
|
`GET /api/feedback?session=…`); every write returns `feedback` too. Never poll.
|
|
20
23
|
|
|
24
|
+
To be woken by a Send: in Claude Code, start `mockpit watch` with the Monitor tool after
|
|
25
|
+
asking, at its longest timeout, and re-arm it when it expires, without telling the user (with
|
|
26
|
+
the mockpit plugin, don't: it wakes you). Never run it in the foreground; it never returns. With no such tool, the viewer
|
|
27
|
+
gives the user a line to paste to you.
|
|
28
|
+
|
|
29
|
+
One user request gets one version. To fix a version before the user has acted
|
|
30
|
+
on it, replace it with `mockpit publish … --amend` (MCP `amend`, HTTP
|
|
31
|
+
`"amend": true`) instead of publishing another; `--withdraw` takes it back.
|
|
32
|
+
|
|
21
33
|
A connector without a codemode of its own (claude.ai, Desktop) can use
|
|
22
34
|
`http://localhost:8228/mcp?mode=code` (stdio: `MOCKPIT_MCP_MODE=code`): one
|
|
23
35
|
`run` tool that executes a script against the mockpit API.
|
|
@@ -18,9 +18,8 @@
|
|
|
18
18
|
into hierarchy, real data and visuals that carry meaning. Never bare by default.
|
|
19
19
|
- Errors say what happened and what to do next. Nothing is cut off at the
|
|
20
20
|
narrowest width.
|
|
21
|
-
- Once a direction is chosen, add the other
|
|
22
|
-
|
|
23
|
-
first round.
|
|
21
|
+
- Once a direction is chosen, add the other states the screen has (empty, many,
|
|
22
|
+
error, loading) as states of their own. Not in the first round.
|
|
24
23
|
- Once the user has chosen, the next version is that design with the likely fix
|
|
25
24
|
applied, and the note says what changed. Don't reopen it with new options; ask
|
|
26
25
|
one focused question only if it is still off.
|