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.
Files changed (73) hide show
  1. package/README.md +60 -212
  2. package/bin/demoData.js +2 -2
  3. package/bin/initDesign.js +6 -6
  4. package/bin/mockpit.js +407 -187
  5. package/bin/poster.js +377 -0
  6. package/dist/mcp/server.js +80 -24
  7. package/dist/server/answerAdditions.d.ts +7 -0
  8. package/dist/server/answerAdditions.js +76 -0
  9. package/dist/server/apiViews.d.ts +289 -52
  10. package/dist/server/apiViews.js +189 -81
  11. package/dist/server/app.d.ts +7 -2
  12. package/dist/server/app.js +2845 -832
  13. package/dist/server/appIcon.js +15 -5
  14. package/dist/server/appIconPng.js +3 -3
  15. package/dist/server/askNudges.js +1 -1
  16. package/dist/server/cdnInline.d.ts +8 -0
  17. package/dist/server/cdnInline.js +638 -0
  18. package/dist/server/codeWorker.js +1 -1
  19. package/dist/server/decisionList.d.ts +45 -0
  20. package/dist/server/decisionList.js +302 -0
  21. package/dist/server/decisions.d.ts +4 -4
  22. package/dist/server/decisions.js +9 -9
  23. package/dist/server/designGuide.d.ts +5 -5
  24. package/dist/server/designGuide.js +128 -67
  25. package/dist/server/embeds.d.ts +3 -1
  26. package/dist/server/embeds.js +31 -6
  27. package/dist/server/eventLog.d.ts +2 -2
  28. package/dist/server/eventLog.js +11 -11
  29. package/dist/server/events.d.ts +9 -6
  30. package/dist/server/feedbackBatch.d.ts +35 -13
  31. package/dist/server/feedbackBatch.js +111 -47
  32. package/dist/server/fills.d.ts +4 -0
  33. package/dist/server/fills.js +55 -1
  34. package/dist/server/handoff.d.ts +4 -1
  35. package/dist/server/handoff.js +8 -2
  36. package/dist/server/icons.js +1 -1
  37. package/dist/server/index.js +39 -10
  38. package/dist/server/jump.d.ts +21 -0
  39. package/dist/server/jump.js +175 -0
  40. package/dist/server/knobs.d.ts +3 -3
  41. package/dist/server/knobs.js +6 -6
  42. package/dist/server/mcpHttp.d.ts +5 -1
  43. package/dist/server/mcpHttp.js +16 -11
  44. package/dist/server/mcpSpec.js +118 -46
  45. package/dist/server/parts.js +9 -1
  46. package/dist/server/run.d.ts +1 -1
  47. package/dist/server/run.js +25 -16
  48. package/dist/server/runApi.d.ts +3 -3
  49. package/dist/server/runApi.js +25 -19
  50. package/dist/server/sqlStore.d.ts +112 -96
  51. package/dist/server/sqlStore.js +906 -172
  52. package/dist/server/standings.d.ts +25 -0
  53. package/dist/server/standings.js +113 -0
  54. package/dist/server/surfacePage.d.ts +6 -9
  55. package/dist/server/surfacePage.js +361 -86
  56. package/dist/server/types.d.ts +226 -72
  57. package/dist/server/types.js +73 -78
  58. package/extensions/mockpit.js +89 -72
  59. package/guide/AGENT_SETUP.md +13 -1
  60. package/guide/packs/design-craft.md +2 -3
  61. package/guide/topics/asks.md +106 -62
  62. package/guide/topics/feedback.md +126 -119
  63. package/guide/topics/html.md +17 -24
  64. package/guide/topics/http.md +41 -41
  65. package/guide/topics/knobs.md +7 -10
  66. package/guide/topics/scripts.md +22 -33
  67. package/guide/topics/surfaces.md +39 -48
  68. package/opencode/mockpit.js +120 -0
  69. package/opencode/package.json +8 -0
  70. package/package.json +4 -3
  71. package/skills/launch-video/SKILL.md +11 -11
  72. package/skills/mockpit/SKILL.md +26 -22
  73. package/viewer/dist/index.html +9 -9
@@ -4,24 +4,23 @@ import { GUIDE_TOPICS } from "./designGuide.js";
4
4
  import { feedbackImages } from "./feedbackBatch.js";
5
5
  import { KIT_IDS } from "./kits.js";
6
6
  import { RUN_DESCRIPTION } from "./runApi.js";
7
- import { SURFACE_KINDS } from "./types.js";
7
+ import { MAX_NOTES, SURFACE_KINDS } from "./types.js";
8
8
  export const MCP_SERVER_INFO = { name: "mockpit", version: "0.2.0" };
9
9
  // The `kind` enum both MCP transports advertise — derived from the one canonical
10
10
  // list (types.ts) so the MCP tier can never fall behind what REST/CLI accept.
11
11
  const SURFACE_KIND_ENUM = [...SURFACE_KINDS];
12
- export const MCP_INSTRUCTIONS = "Mockpit shows design work to the user: project > mock > state > variant > version. publish " +
12
+ export const MCP_INSTRUCTIONS = "Mockpit shows design work to the user: project > design > state > variant > version. publish " +
13
13
  "each variant (name states in the user's words; declare parts with data-part); publish again to " +
14
14
  "revise. A choice is several variants plus one question that binds them (ask). One render plus a " +
15
15
  "control: declare a knob. Say where to look, then end your turn; nothing waits. When the " +
16
16
  "user says they answered, call feedback. Writes return feedback too; it is delivered once. " +
17
17
  "Fetch guide before html.";
18
18
  const field = {
19
- mock: "Mock slug or id",
19
+ design: "Design slug, title or id",
20
20
  state: "State label; omit if single-state",
21
- situation: 'Another render of this state ("Couldn\'t save", "Loading"); publish the state itself first',
22
21
  variant: 'Variant label; default "default"',
23
22
  project: "Default: the session's project",
24
- title: "Mock title",
23
+ title: "Design title",
25
24
  session: "Session id from an earlier publish",
26
25
  sessionTitle: "Task name; used only when creating the session",
27
26
  agent: "Agent name for a new session",
@@ -29,11 +28,13 @@ const field = {
29
28
  knobs: 'Global knobs (tunekit usePane shape) keyed by path: [default,min,max,step], boolean, {type:"select",options}, "#hex"',
30
29
  variantKnobs: "Knobs this variant alone has",
31
30
  from: "Branch from this version",
31
+ amend: "Replace the latest version in place: a fix before the user acts on it",
32
+ withdraw: "Take the latest version back, before the user acts on it",
32
33
  fork: 'Start this new variant from a sibling: "variant" or "variant@N"; alone it copies it, with parts/fills it edits the copy',
33
34
  prompt: "What prompted this version; usually omit",
34
- note: "What this variant is; shown beside it, never in the html",
35
+ description: "What this variant is; shown beside it, never in the html",
35
36
  widths: "Widths it ships at, side by side: [390,1280]",
36
- kind: "Only when building the product's screens: page (a screen), component (a piece pages embed). Omit for sketches, diagrams and reviews",
37
+ kind: "Only when building the product's screens: screen, component (a reusable design screens embed). With no html it plans one, drawn by a later publish. Omit for ideas, diagrams and reviews",
37
38
  area: 'Product area in the project\'s words; Home groups by it. "" clears',
38
39
  source: 'Code path implementing it. "" clears',
39
40
  flow: "Flow this state is a step of; alone, only places it",
@@ -82,8 +83,12 @@ export const mcpSurfaceSchema = z
82
83
  const askSchema = z.object({
83
84
  id: z.string().optional().describe("Stable id; reusing one replaces that question"),
84
85
  text: z.string().describe("The question, one sentence"),
85
- scope: z.enum(["mock", "state", "part"]).optional(),
86
+ scope: z.enum(["design", "state", "part"]).optional(),
86
87
  state: z.string().optional(),
88
+ states: z
89
+ .array(z.string())
90
+ .optional()
91
+ .describe("Design-wide question: the states its answers can be seen on, best first"),
87
92
  part: z.string().optional().describe("data-part name, for scope part"),
88
93
  multi: z.boolean().optional(),
89
94
  after: z
@@ -96,6 +101,9 @@ const askSchema = z.object({
96
101
  variant: z.string().optional().describe("Bind to a published variant"),
97
102
  version: z.number().int().optional().describe("And one version of it"),
98
103
  set: z.record(z.string(), z.unknown()).optional().describe("Or to knob values {path: value}"),
104
+ style: z.string().optional().describe("With a set of a new value: its CSS"),
105
+ fill: z.string().optional().describe("With a set of {part: new fill}: its html"),
106
+ html: z.string().optional().describe("Or a whole page"),
99
107
  recommended: z.boolean().optional().describe("The one you would pick; one per ask"),
100
108
  })),
101
109
  });
@@ -131,22 +139,21 @@ function zodParam(p) {
131
139
  return p.req ? s : s.optional();
132
140
  }
133
141
  const P = {
134
- mock: { t: "string", d: field.mock, req: true },
142
+ design: { t: "string", d: field.design, req: true },
135
143
  state: { t: "string", d: field.state },
136
144
  variant: { t: "string", d: field.variant },
137
145
  project: { t: "string", d: field.project },
138
146
  session: { t: "string", d: field.session },
139
147
  };
140
- const VARIANT_REF = { mock: P.mock, state: P.state, variant: P.variant, project: P.project };
148
+ const VARIANT_REF = { design: P.design, state: P.state, variant: P.variant, project: P.project };
141
149
  export const MCP_TOOL_DEFS = [
142
150
  {
143
151
  name: "publish",
144
- description: "Create or version one variant of one state of a mock. One of html, surfaces (the full ordered list), parts or fills (splice the latest version). Returns parts per state, nudges, feedback.",
152
+ description: "Create or version one variant of one state of a design. One of html, surfaces (the full ordered list), parts or fills (splice the latest version); or kind screen or component and none of them, to plan it. Returns parts per state, nudges, feedback.",
145
153
  params: {
146
154
  ...VARIANT_REF,
147
- situation: { t: "string", d: field.situation },
148
155
  title: { t: "string", d: field.title },
149
- kind: { t: "enum", values: ["page", "component", "sketch"], d: field.kind },
156
+ kind: { t: "enum", values: ["screen", "component", "idea"], d: field.kind },
150
157
  area: { t: "string", d: field.area },
151
158
  source: { t: "string", d: field.source },
152
159
  html: { t: "string", d: field.html },
@@ -164,8 +171,10 @@ export const MCP_TOOL_DEFS = [
164
171
  variantKnobs: { t: "object", d: field.variantKnobs },
165
172
  from: { t: "integer", d: field.from },
166
173
  fork: { t: "string", d: field.fork },
174
+ amend: { t: "boolean", d: field.amend },
175
+ withdraw: { t: "boolean", d: field.withdraw },
167
176
  prompt: { t: "string", d: field.prompt },
168
- note: { t: "string", d: field.note },
177
+ description: { t: "string", d: field.description },
169
178
  widths: { t: "integers", d: field.widths },
170
179
  flow: { t: "string", d: field.flow },
171
180
  step: { t: "integer", d: field.step },
@@ -177,9 +186,9 @@ export const MCP_TOOL_DEFS = [
177
186
  },
178
187
  {
179
188
  name: "ask",
180
- description: "Ask structured questions on a mock. A choice is several variants plus one question that binds them; options may also set knob values. Reusing a question id replaces it.",
189
+ description: "Ask structured questions on a design. A choice is several variants plus one question that binds them; options may also set knob values. Reusing a question id replaces it.",
181
190
  params: {
182
- mock: P.mock,
191
+ design: P.design,
183
192
  project: P.project,
184
193
  asks: { t: "asks", d: "Questions with options", req: true },
185
194
  session: P.session,
@@ -188,21 +197,25 @@ export const MCP_TOOL_DEFS = [
188
197
  },
189
198
  {
190
199
  name: "read",
191
- description: "Without mock: every mock (slug, states, variants, open questions), flows, plus pending. With mock: its states, variants, questions with answers, parts, knobs and settled values (every answer's set and tuning sent so far), plus pending. Never consumes feedback.",
200
+ description: "Read this first. Both forms carry decisionList: what the user already settled in this project; it stands unless they say otherwise. Without design: every design (slug, states, variants, open questions), flows, plus pending. With design: its notes (a spec; the user's edits stand), states, variants, questions with answers, parts, knobs and settled values (every answer's set and tuning sent so far), plus pending. Never consumes feedback.",
192
201
  params: {
193
- mock: { t: "string", d: field.mock },
202
+ design: { t: "string", d: field.design },
194
203
  project: P.project,
195
204
  body: { t: "boolean", d: "Include each variant's surfaces" },
196
205
  history: { t: "boolean", d: "Include version rows" },
197
206
  tree: {
198
207
  t: "boolean",
199
- d: "Without mock: the project as a tree (each mock's variants with status and forkedFrom, the mocks it embeds and is embedded in)",
208
+ d: "Without design: the project as a tree (each design's variants with status and forkedFrom, the designs it embeds and is embedded in)",
209
+ },
210
+ decisions: {
211
+ t: "boolean",
212
+ d: "Only the whole decision list, when decisionList says it was cut",
200
213
  },
201
214
  },
202
215
  },
203
216
  {
204
217
  name: "feedback",
205
- description: "Returns at once: what the user sent since you last heard (one batch per mock: reply answers, borrowed parts, tuned knobs, part comments, verdict; thread messages; inUse/archived; or closed with the questions it dismissed), delivered once, plus pending (viewer open, draft progress).",
218
+ description: "Returns at once: what the user sent since you last heard (one batch per design: reply answers, borrowed parts, tuned knobs, part comments, verdict; thread messages; inUse/archived), delivered once, plus pending (viewer open, draft progress).",
206
219
  params: {
207
220
  project: P.project,
208
221
  session: { t: "string", d: "Session id returned by publish", req: true },
@@ -211,7 +224,7 @@ export const MCP_TOOL_DEFS = [
211
224
  },
212
225
  {
213
226
  name: "say",
214
- description: "Post a short plain-text message in a mock's thread. Returns feedback.",
227
+ description: "Post a short plain-text message in a design's thread. Returns feedback.",
215
228
  params: {
216
229
  ...VARIANT_REF,
217
230
  message: { t: "string", d: "Plain text", req: true },
@@ -219,6 +232,24 @@ export const MCP_TOOL_DEFS = [
219
232
  },
220
233
  httpOnly: ["session"],
221
234
  },
235
+ {
236
+ name: "move",
237
+ description: "Tidy up variants: to or toState moves them there and out of here; archive takes them out of view; restore brings them back; a group goes along; one in use stays. Only when the user asks: hideOlder hides each variant's older versions (variants optional: all of them), and deleteOlder deletes them for good, skipping any that a reply, comment, question, embed, copy or fork still points at, or that is in use. Confirm a delete first: it can't be undone. Returns feedback.",
238
+ params: {
239
+ design: P.design,
240
+ state: P.state,
241
+ variants: { t: "strings", d: "Variant names; required except with hideOlder or deleteOlder" },
242
+ to: { t: "string", d: "Target design; default this one" },
243
+ toState: { t: "string", d: "Target state; created if new" },
244
+ archive: { t: "boolean" },
245
+ restore: { t: "boolean" },
246
+ hideOlder: { t: "boolean", d: "Hide all but each variant's newest visible version" },
247
+ deleteOlder: { t: "boolean", d: "Delete them instead; permanent, skips what's referenced" },
248
+ project: P.project,
249
+ session: P.session,
250
+ },
251
+ httpOnly: ["session"],
252
+ },
222
253
  {
223
254
  name: "export",
224
255
  description: "The html in use (else current) per state, version history, screenshot URL, knobs, the settled values and the last reply.",
@@ -226,17 +257,22 @@ export const MCP_TOOL_DEFS = [
226
257
  },
227
258
  {
228
259
  name: "edit",
229
- description: "Change a mock without a new version; a new slug rewrites every reference to the old one. Without mock, rename renames the project and areaOrder orders its areas. Returns feedback.",
260
+ description: "Change a design without a new version; a new slug rewrites every reference to the old one. Without design, rename renames the project and areaOrder orders its areas. Returns feedback.",
230
261
  params: {
231
- mock: { t: "string", d: field.mock },
262
+ design: { t: "string", d: field.design },
232
263
  project: P.project,
233
264
  slug: { t: "string" },
234
265
  title: { t: "string" },
235
- kind: { t: "enum", values: ["page", "component", "sketch"] },
266
+ kind: { t: "enum", values: ["screen", "component", "idea"] },
236
267
  area: { t: "string" },
237
268
  source: { t: "string" },
269
+ firstState: { t: "string", d: "Names a design's one unnamed state, so it can have more" },
270
+ notes: {
271
+ t: "string",
272
+ d: `A short plain-text spec, at most ${MAX_NOTES} characters; "" clears. Not applied over the user's own edit, and the result says so`,
273
+ },
238
274
  rename: { t: "string", d: "New project name" },
239
- areaOrder: { t: "strings", d: "Without mock: Home's area order" },
275
+ areaOrder: { t: "strings", d: "Without design: Home's area order" },
240
276
  session: P.session,
241
277
  },
242
278
  httpOnly: ["session"],
@@ -294,14 +330,14 @@ const bag = z.record(z.string(), z.unknown());
294
330
  const variantRef = o({ state: nullStr, variant: str });
295
331
  const inUseRef = o({ state: nullStr, variant: str, version: num });
296
332
  const partsByState = z.array(o({ state: nullStr, parts: z.array(o({ name: str })) }));
297
- const flowSchema = o({ name: str, steps: z.array(o({ mock: str, state: nullStr })) });
333
+ const flowSchema = o({ name: str, steps: z.array(o({ design: str, state: nullStr })) });
298
334
  const feedbackSchema = o({
299
- mock: nullStr,
335
+ design: nullStr,
300
336
  reply: o({
301
337
  asks: z.array(o({
302
338
  ask: str,
303
339
  chosen: z.array(o({ label: str, other: z.literal(true).optional() })),
304
- note: str.optional(),
340
+ description: str.optional(),
305
341
  })),
306
342
  borrowed: bag.describe("Part → the variant to take it from"),
307
343
  tuned: bag,
@@ -309,39 +345,47 @@ const feedbackSchema = o({
309
345
  reactions: strs.optional().describe('One-tap reactions, e.g. 👍 part "hero" (variant B)'),
310
346
  verdict: o({ kind: z.enum(["use", "revise"]), state: nullStr, variant: str })
311
347
  .optional()
312
- .describe("Use this or Revise on one variant"),
348
+ .describe("Use this or New version on one variant"),
349
+ more: o({
350
+ ask: str,
351
+ text: str,
352
+ existing: strs,
353
+ note: str.optional(),
354
+ answered: z.array(o({ ask: str, text: str, chosen: strs, comment: str.optional() })),
355
+ })
356
+ .optional()
357
+ .describe("The user wants more answers to this question: ask it again, same id, with them"),
313
358
  })
314
359
  .nullable()
315
360
  .describe("The user's Send; null if only messages"),
316
361
  messages: z.array(o({ seq: num, text: str })).describe("What the user wrote in the thread"),
317
362
  inUse: z.array(inUseRef).describe("In use, each at the version the user put in use"),
318
363
  archived: z.array(variantRef),
319
- closed: z
320
- .literal(true)
321
- .optional()
322
- .describe("The user closed the mock: its open questions were closed unanswered"),
323
- dismissed: z
324
- .array(o({ ask: str, text: str }))
325
- .optional()
326
- .describe("The questions the close dismissed; don't ask them again"),
327
- edited: o({ kind: str.optional(), area: nullStr.optional() })
364
+ edited: o({
365
+ kind: str.optional(),
366
+ area: nullStr.optional(),
367
+ notes: nullStr.optional(),
368
+ })
328
369
  .optional()
329
- .describe("The user moved the mock from Home: its kind or area now"),
370
+ .describe("The user moved the design from Home (its kind or area now) or edited its notes"),
330
371
  }).meta({ id: "Feedback" });
331
372
  // Typed once, on feedback: repeating it on every write would cost more than
332
373
  // the rest of the write's output schema.
333
374
  const feedbackRide = z.array(bag).describe("Feedback batches as the feedback tool returns");
334
375
  const pendingSchema = o({
335
- mock: str,
336
- closed: z.literal(true).optional(),
376
+ design: str,
377
+ archived: z.literal(true).optional(),
337
378
  viewerOpen: z.boolean(),
338
379
  draft: o({ answered: num, of: num, comments: num, touchedAt: str }).nullable(),
339
380
  }).meta({ id: "Pending" });
340
381
  const writeOutput = {
341
- post: o({ state: nullStr, variant: str, version: num }),
382
+ post: o({ state: nullStr, variant: str, version: num })
383
+ .optional()
384
+ .describe("Absent when planned: nothing is drawn yet"),
385
+ planned: z.boolean().optional(),
342
386
  sessionId: str,
343
387
  url: str.describe("Viewer link for the user"),
344
- parts: partsByState,
388
+ parts: partsByState.optional(),
345
389
  partChanges: o({ vanished: strs, renamed: z.array(o({ from: str, to: str })) }).optional(),
346
390
  nudges: strs.optional(),
347
391
  suggestedAsk: bag.optional().describe("Send with ask when a nudge names it"),
@@ -378,10 +422,25 @@ const OUTPUT_SCHEMAS = {
378
422
  feedback: feedbackRide,
379
423
  },
380
424
  feedback: {
381
- feedback: z.array(feedbackSchema).describe("One batch per mock; empty when nothing is new"),
425
+ feedback: z.array(feedbackSchema).describe("One batch per design; empty when nothing is new"),
382
426
  pending: z.array(pendingSchema),
383
427
  },
384
428
  say: { feedback: feedbackRide },
429
+ move: {
430
+ variants: z.array(o({ state: str.nullable(), variant: str, status: str })),
431
+ versions: z
432
+ .array(o({ state: str.nullable(), variant: str, version: num }))
433
+ .optional()
434
+ .describe("With hideOlder or deleteOlder: what was hidden or deleted"),
435
+ skipped: z.array(o({ state: str.nullable().optional(), variant: str, version: num.optional(), why: str })),
436
+ to: o({ design: str, title: str, state: str.nullable() }).optional(),
437
+ saved: z
438
+ .array(o({ state: str.nullable(), variant: str, already: z.boolean() }))
439
+ .optional()
440
+ .describe("What each is called there"),
441
+ url: str,
442
+ feedback: feedbackRide,
443
+ },
385
444
  edit: {
386
445
  renamed: o({ from: str, to: str }).optional(),
387
446
  areaOrder: strs.optional(),
@@ -390,7 +449,7 @@ const OUTPUT_SCHEMAS = {
390
449
  feedback: feedbackRide,
391
450
  },
392
451
  read: {
393
- mocks: z.array(o({ slug: str, states: strs, variants: num, open: num })).optional(),
452
+ designs: z.array(o({ slug: str, states: strs, variants: num, open: num })).optional(),
394
453
  states: strs.optional(),
395
454
  asks: z.array(o({ id: str, text: str })).optional(),
396
455
  variants: z
@@ -414,7 +473,20 @@ const OUTPUT_SCHEMAS = {
414
473
  settled: bag.optional().describe("Every knob value the user has sent, later replies winning"),
415
474
  tree: z.array(bag).optional(),
416
475
  flows: z.array(flowSchema).optional(),
417
- pending: z.union([z.array(pendingSchema), pendingSchema]),
476
+ decisionList: o({
477
+ total: num,
478
+ lines: z.array(o({
479
+ design: str,
480
+ text: str,
481
+ here: z.boolean().optional().describe("From the design read"),
482
+ edited: z.boolean().optional(),
483
+ archived: z.boolean().optional(),
484
+ })),
485
+ more: str.optional(),
486
+ }).optional(),
487
+ total: num.optional(),
488
+ lines: z.array(bag).optional(),
489
+ pending: z.union([z.array(pendingSchema), pendingSchema]).optional(),
418
490
  },
419
491
  export: {
420
492
  states: z.array(o({
@@ -48,8 +48,16 @@ export function partsInHtml(html) {
48
48
  }
49
49
  return [...byName.values()];
50
50
  }
51
+ // Cached per surfaces array, which a stored post never mutates: a design's view
52
+ // asks for every variant's parts on every read. Callers must not change the result.
53
+ const bySurfaces = new WeakMap();
51
54
  export function partsInSurfaces(surfaces) {
52
- return mergeParts(surfaces.flatMap((s) => (s.kind === "html" ? [partsInHtml(s.html)] : [])));
55
+ const hit = bySurfaces.get(surfaces);
56
+ if (hit)
57
+ return hit;
58
+ const parts = mergeParts(surfaces.flatMap((s) => (s.kind === "html" ? [partsInHtml(s.html)] : [])));
59
+ bySurfaces.set(surfaces, parts);
60
+ return parts;
53
61
  }
54
62
  // Union several part lists by name, first occurrence first.
55
63
  export function mergeParts(lists) {
@@ -77,6 +77,6 @@ export interface RunDeps {
77
77
  status: number;
78
78
  }>;
79
79
  }
80
- export declare const RUN_UNAVAILABLE = "run is not available on this deployment: it has no script sandbox. Use the mock tools (or REST) instead";
80
+ export declare const RUN_UNAVAILABLE = "run is not available on this deployment: it has no script sandbox. Use the design tools (or REST) instead";
81
81
  export declare function cut(s: string, max: number): string;
82
82
  export declare function createRunFlow(deps: RunDeps): (body: any, ctx: FlowContext) => Promise<FlowResult>;
@@ -26,7 +26,7 @@ export const DEFAULT_RUN_LIMITS = {
26
26
  maxInflight: 4,
27
27
  maxRuns: 4,
28
28
  };
29
- export const RUN_UNAVAILABLE = "run is not available on this deployment: it has no script sandbox. Use the mock tools (or REST) instead";
29
+ export const RUN_UNAVAILABLE = "run is not available on this deployment: it has no script sandbox. Use the design tools (or REST) instead";
30
30
  const text = (v, max) => typeof v === "string" && v.trim() ? v.trim().slice(0, max) : undefined;
31
31
  const plain = (v) => v && typeof v === "object" && !Array.isArray(v) ? v : {};
32
32
  // Keep the head and the tail: the start says what a value is, the end is where
@@ -40,7 +40,7 @@ export function cut(s, max) {
40
40
  }
41
41
  function writeSummary(body) {
42
42
  const post = body?.post;
43
- const slug = body?.mock?.slug ?? "?";
43
+ const slug = body?.design?.slug ?? "?";
44
44
  if (!post)
45
45
  return slug;
46
46
  return `${slug}/${post.state ? `${post.state}/` : ""}${post.variant} v${post.version}`;
@@ -152,26 +152,30 @@ export function createRunFlow(deps) {
152
152
  throw new Error(unknownTopicMessage(String(topic)));
153
153
  return [await deps.guide("", topic), String(topic)];
154
154
  },
155
- async read([mock, opts]) {
156
- if ((mock === undefined || mock === null) && plain(opts).tree === true) {
155
+ async read([design, opts]) {
156
+ if (plain(opts).decisions === true) {
157
+ const value = await take(flows.decisions({ project: await projectOf() }));
158
+ return [value, `${value.total} decisions`];
159
+ }
160
+ if ((design === undefined || design === null) && plain(opts).tree === true) {
157
161
  const value = await take(flows.tree({ project: await projectOf() }));
158
- return [value, `${value.tree.length} mocks`];
162
+ return [value, `${value.tree.length} designs`];
159
163
  }
160
- if (mock === undefined || mock === null) {
164
+ if (design === undefined || design === null) {
161
165
  const value = await take(flows.list({ project: await projectOf() }));
162
- return [value, `${value.mocks.length} mocks`];
166
+ return [value, `${value.designs.length} designs`];
163
167
  }
164
168
  const o = plain(opts);
165
- const value = await take(flows.get(mock, { project, body: o.body === true, history: o.history === true }));
166
- return [value, String(value?.slug ?? mock)];
169
+ const value = await take(flows.get(design, { project, body: o.body === true, history: o.history === true }));
170
+ return [value, String(value?.slug ?? design)];
167
171
  },
168
172
  async publish([v]) {
169
173
  const value = await take(flows.publish({ ...(await mine(plain(v))), agent }, flowCtx));
170
174
  return [value, writeSummary(value)];
171
175
  },
172
- async ask([mock, asks]) {
173
- const value = await take(flows.ask(mock, await mine({ asks }), flowCtx));
174
- return [value, `${value.mock} ${value.asks.length} ask(s)`];
176
+ async ask([design, asks]) {
177
+ const value = await take(flows.ask(design, await mine({ asks }), flowCtx));
178
+ return [value, `${value.design} ${value.asks.length} ask(s)`];
175
179
  },
176
180
  async feedback() {
177
181
  const value = await take(flows.feedback(await mine({}), flowCtx));
@@ -180,8 +184,13 @@ export function createRunFlow(deps) {
180
184
  },
181
185
  async say([v, message]) {
182
186
  const r = plain(v);
183
- await take(flows.say(r.mock, { ...(await mine(r)), message }, flowCtx));
184
- return [null, String(r.mock ?? "?")];
187
+ await take(flows.say(r.design, { ...(await mine(r)), message }, flowCtx));
188
+ return [null, String(r.design ?? "?")];
189
+ },
190
+ async move([v]) {
191
+ const r = plain(v);
192
+ const value = await take(flows.move(r.design, await mine(r), flowCtx));
193
+ return [value, `${value.variants.length} moved`];
185
194
  },
186
195
  async edit([v]) {
187
196
  const r = await mine(plain(v));
@@ -206,8 +215,8 @@ export function createRunFlow(deps) {
206
215
  },
207
216
  async export([v]) {
208
217
  const r = plain(v);
209
- const value = await take(flows.exportMock(r.mock, { ...r, project }, flowCtx));
210
- return [value, `${value.mock} ${value.states.length} state(s)`];
218
+ const value = await take(flows.exportDesign(r.design, { ...r, project }, flowCtx));
219
+ return [value, `${value.design} ${value.states.length} state(s)`];
211
220
  },
212
221
  };
213
222
  const call = (name, argsJson) => {
@@ -1,6 +1,6 @@
1
- export declare const RUN_API = "// The body of an async function, in plain JavaScript (no TypeScript syntax).\n// `await mockpit.*`, `return` a JSON value, print() adds an output line.\n// No network, timers, imports or process. Session, project and agent are fixed\n// for the run; pass the returned session to the next run.\ntype Ref = { mock: string; state?: string; variant?: string };\ntype Knobs = Record<string, unknown>; // path \u2192 [default,min,max,step] | boolean | {type:\"select\",options} | \"#hex\"\ntype Surface =\n | { kind: \"html\"; html: string; kits?: string[] }\n | { kind: \"markdown\"; markdown: string }\n | { kind: \"diff\"; patch?: string; files?: { filename: string; before: string; after: string }[]; layout?: \"unified\" | \"split\" }\n | { kind: \"image\"; assetId: string; alt?: string; caption?: string }\n | { kind: \"terminal\"; text: string; cols?: number; title?: string }\n | { kind: \"mermaid\"; mermaid: string }\n | { kind: \"json\"; data: unknown; title?: string }\n | { kind: \"code\"; code: string; language?: string; lineStart?: number };\ntype Ask = {\n id?: string; text: string; scope?: \"mock\" | \"state\" | \"part\"; state?: string; part?: string; multi?: boolean;\n options: { id?: string; label: string; variant?: string; set?: Knobs; recommended?: boolean }[];\n};\ntype Written = {\n post: { state: string | null; variant: string; version: number }; url: string;\n parts: { state: string | null; parts: { name: string }[] }[];\n partChanges?: { vanished: string[]; renamed: { from: string; to: string }[] };\n nudges?: string[]; suggestedAsk?: Ask; suggestedFillAsks?: Ask[]; // send with ask when nudged\n};\ntype Feedback = {\n mock: string | null;\n reply: null | { asks: { ask: string; chosen: { id: string; label: string; other?: true }[]; note?: string }[]; borrowed: Record<string, string>; tuned: Knobs; comments: { part: string | null; text: string }[]; verdict?: { kind: \"use\" | \"revise\"; state: string | null; variant: string; version?: number } };\n messages: { text: string; state: string | null; variant: string | null }[];\n inUse: { state: string | null; variant: string; version: number }[]; archived: { state: string | null; variant: string }[];\n closed?: true; dismissed?: { ask: string; text: string }[];\n};\ntype Pending = { mock: string; closed?: true; viewerOpen: boolean; draft: null | { answered: number; of: number; comments: number; touchedAt: string } };\ndeclare const mockpit: {\n guide(topic?: \"knobs\" | \"asks\" | \"surfaces\" | \"html\" | \"feedback\" | \"http\" | \"scripts\"): Promise<string>;\n /** No mock: every mock, the flows, plus pending. With one: its states, variants, asks, parts, knobs. */\n read(mock?: string, opts?: { body?: boolean; history?: boolean }): Promise<unknown>;\n /** Creates or versions (mock, state, variant). One of: html; surfaces, the full ordered list\n * ({id} alone keeps that surface, a missing id is removed); parts {\"name\"|\"name#key\": outer html};\n * fills {\"part#fill\": outer html}, replacing or adding one fill of a part. */\n publish(v: Ref & { situation?: string; title?: string; kind?: \"page\" | \"component\" | \"sketch\"; area?: string; source?: string; html?: string; poster?: string; surfaces?: (Surface | { id: string })[]; parts?: Record<string, string>; fills?: Record<string, string>; knobs?: Knobs; variantKnobs?: Knobs; from?: number; prompt?: string; note?: string; widths?: number[]; flow?: string; step?: number }): Promise<Written>;\n ask(mock: string, asks: Ask[]): Promise<{ asks: { id: string; text: string }[]; url: string; nudges?: string[] }>;\n /** Never waits: what the user sent since you last heard, and what they are doing now. */\n feedback(): Promise<{ feedback: Feedback[]; pending: Pending[] }>;\n say(v: Ref, message: string): Promise<void>;\n /** No new version; \"\" clears. { rename } or { areaOrder } without mock edits the project. */\n edit(v: { mock?: string; slug?: string; title?: string; kind?: string; area?: string; source?: string; rename?: string; areaOrder?: string[] }): Promise<{ url: string }>;\n export(v: Ref): Promise<{ states: { state: string | null; variant: string; version: number; html: string; allFills?: string }[]; reply: unknown }>;\n /** data: base64 bytes. Use id as an image surface's assetId. */\n upload(data: string, opts: { contentType: string; filename?: string; kind?: \"image\" | \"file\" }): Promise<{ id: string; url: string }>;\n};\ndeclare function print(...values: unknown[]): void;";
2
- export declare const RUN_FUNCTIONS: readonly ["guide", "read", "publish", "ask", "feedback", "say", "edit", "export", "upload"];
1
+ export declare const RUN_API = "// The body of an async function, in plain JavaScript (no TypeScript syntax).\n// `await mockpit.*`, `return` a JSON value, print() adds an output line.\n// No network, timers, imports or process. Session, project and agent are fixed\n// for the run; pass the returned session to the next run.\ntype Ref = { design: string; state?: string; variant?: string };\ntype Knobs = Record<string, unknown>; // path \u2192 [default,min,max,step] | boolean | {type:\"select\",options} | \"#hex\"\ntype Surface =\n | { kind: \"html\"; html: string; kits?: string[] }\n | { kind: \"markdown\"; markdown: string }\n | { kind: \"diff\"; patch?: string; files?: { filename: string; before: string; after: string }[]; layout?: \"unified\" | \"split\" }\n | { kind: \"image\"; assetId: string; alt?: string; caption?: string }\n | { kind: \"terminal\"; text: string; cols?: number; title?: string }\n | { kind: \"mermaid\"; mermaid: string }\n | { kind: \"json\"; data: unknown; title?: string }\n | { kind: \"code\"; code: string; language?: string; lineStart?: number };\ntype Ask = {\n id?: string; text: string; scope?: \"design\" | \"state\" | \"part\"; state?: string; part?: string; multi?: boolean;\n options: { id?: string; label: string; variant?: string; set?: Knobs; recommended?: boolean }[];\n};\ntype Written = {\n post?: { state: string | null; variant: string; version: number }; planned?: true; url: string;\n parts?: { state: string | null; parts: { name: string }[] }[];\n partChanges?: { vanished: string[]; renamed: { from: string; to: string }[] };\n nudges?: string[]; suggestedAsk?: Ask; suggestedFillAsks?: Ask[]; // send with ask when nudged\n};\ntype Feedback = {\n design: string | null;\n reply: null | { asks: { ask: string; chosen: { id: string; label: string; other?: true }[]; comment?: string }[]; borrowed: Record<string, string>; tuned: Knobs; comments: { part: string | null; text: string }[]; verdict?: { kind: \"use\" | \"revise\"; state: string | null; variant: string; version?: number } };\n messages: { text: string; state: string | null; variant: string | null }[];\n inUse: { state: string | null; variant: string; version: number }[]; archived: { state: string | null; variant: string }[];\n};\ntype Pending = { design: string; archived?: true; viewerOpen: boolean; draft: null | { answered: number; of: number; comments: number; touchedAt: string } };\ndeclare const mockpit: {\n guide(topic?: \"knobs\" | \"asks\" | \"surfaces\" | \"html\" | \"feedback\" | \"http\" | \"scripts\"): Promise<string>;\n /** Read first: decisionList is what the user already settled; it stands unless they say otherwise.\n * No design: every design, the flows, plus pending. With one: its states, variants, asks, parts, knobs.\n * opts.decisions: only the whole list, when a read cut it. */\n read(design?: string, opts?: { body?: boolean; history?: boolean; decisions?: boolean }): Promise<unknown>;\n /** Creates or versions (design, state, variant). One of: html; surfaces, the full ordered list\n * ({id} alone keeps that surface, a missing id is removed); parts {\"name\"|\"name#key\": outer html};\n * fills {\"part#fill\": outer html}, replacing or adding one fill of a part.\n * None of them, with kind screen or component: plans it, for a later publish to draw. */\n publish(v: Ref & { title?: string; kind?: \"screen\" | \"component\" | \"idea\"; area?: string; source?: string; html?: string; poster?: string; surfaces?: (Surface | { id: string })[]; parts?: Record<string, string>; fills?: Record<string, string>; knobs?: Knobs; variantKnobs?: Knobs; from?: number; prompt?: string; description?: string; widths?: number[]; flow?: string; step?: number }): Promise<Written>;\n ask(design: string, asks: Ask[]): Promise<{ asks: { id: string; text: string }[]; url: string; nudges?: string[] }>;\n /** Never waits: what the user sent since you last heard, and what they are doing now. */\n feedback(): Promise<{ feedback: Feedback[]; pending: Pending[] }>;\n say(v: Ref, message: string): Promise<void>;\n /** to or toState moves variants there; archive hides them; restore brings them back. */\n move(v: Ref & { variants: string[]; to?: string; toState?: string; archive?: boolean; restore?: boolean }): Promise<{ variants: { state: string | null; variant: string; status: string }[]; skipped: { variant: string; why: string }[]; url: string }>;\n /** No new version; \"\" clears. { rename } or { areaOrder } without design edits the project.\n * notes: a short plain-text spec; not applied over the user's own edit (notes.applied says). */\n edit(v: { design?: string; slug?: string; title?: string; kind?: string; area?: string; source?: string; firstState?: string; notes?: string; rename?: string; areaOrder?: string[] }): Promise<{ url: string; notes?: { applied: boolean; text?: string } }>;\n export(v: Ref): Promise<{ states: { state: string | null; variant: string; version: number; html: string; allFills?: string }[]; reply: unknown }>;\n /** data: base64 bytes. Use id as an image surface's assetId. */\n upload(data: string, opts: { contentType: string; filename?: string; kind?: \"image\" | \"file\" }): Promise<{ id: string; url: string }>;\n};\ndeclare function print(...values: unknown[]): void;";
2
+ export declare const RUN_FUNCTIONS: readonly ["guide", "read", "publish", "ask", "feedback", "say", "move", "edit", "export", "upload"];
3
3
  export type RunFunction = (typeof RUN_FUNCTIONS)[number];
4
- export declare const RUN_EXAMPLE = "const html = (tone) => `<section data-part=\"hero\" class=\"${tone}\"><h1>Writer</h1></section>`;\nawait mockpit.publish({ mock: \"writer\", variant: \"calm\", html: html(\"calm\") });\nawait mockpit.publish({ mock: \"writer\", variant: \"bold\", html: html(\"bold\") });\nconst { url } = await mockpit.ask(\"writer\", [{ id: \"tone\", text: \"Calm or bold?\",\n options: [{ label: \"Calm\", variant: \"calm\" }, { label: \"Bold\", variant: \"bold\" }] }]);\n// Tell the user where to look and end the turn; a later run reads mockpit.feedback().\nreturn url;";
4
+ export declare const RUN_EXAMPLE = "const html = (tone) => `<section data-part=\"hero\" class=\"${tone}\"><h1>Writer</h1></section>`;\nawait mockpit.publish({ design: \"writer\", variant: \"calm\", html: html(\"calm\") });\nawait mockpit.publish({ design: \"writer\", variant: \"bold\", html: html(\"bold\") });\nconst { url } = await mockpit.ask(\"writer\", [{ id: \"tone\", text: \"Calm or bold?\",\n options: [{ label: \"Calm\", variant: \"calm\" }, { label: \"Bold\", variant: \"bold\" }] }]);\n// Tell the user where to look and end the turn; a later run reads mockpit.feedback().\nreturn url;";
5
5
  export declare const RUN_DESCRIPTION: string;
6
6
  export declare const RUN_INSTRUCTIONS: string;
@@ -8,7 +8,7 @@ export const RUN_API = `// The body of an async function, in plain JavaScript (n
8
8
  // \`await mockpit.*\`, \`return\` a JSON value, print() adds an output line.
9
9
  // No network, timers, imports or process. Session, project and agent are fixed
10
10
  // for the run; pass the returned session to the next run.
11
- type Ref = { mock: string; state?: string; variant?: string };
11
+ type Ref = { design: string; state?: string; variant?: string };
12
12
  type Knobs = Record<string, unknown>; // path → [default,min,max,step] | boolean | {type:"select",options} | "#hex"
13
13
  type Surface =
14
14
  | { kind: "html"; html: string; kits?: string[] }
@@ -20,37 +20,42 @@ type Surface =
20
20
  | { kind: "json"; data: unknown; title?: string }
21
21
  | { kind: "code"; code: string; language?: string; lineStart?: number };
22
22
  type Ask = {
23
- id?: string; text: string; scope?: "mock" | "state" | "part"; state?: string; part?: string; multi?: boolean;
23
+ id?: string; text: string; scope?: "design" | "state" | "part"; state?: string; part?: string; multi?: boolean;
24
24
  options: { id?: string; label: string; variant?: string; set?: Knobs; recommended?: boolean }[];
25
25
  };
26
26
  type Written = {
27
- post: { state: string | null; variant: string; version: number }; url: string;
28
- parts: { state: string | null; parts: { name: string }[] }[];
27
+ post?: { state: string | null; variant: string; version: number }; planned?: true; url: string;
28
+ parts?: { state: string | null; parts: { name: string }[] }[];
29
29
  partChanges?: { vanished: string[]; renamed: { from: string; to: string }[] };
30
30
  nudges?: string[]; suggestedAsk?: Ask; suggestedFillAsks?: Ask[]; // send with ask when nudged
31
31
  };
32
32
  type Feedback = {
33
- mock: string | null;
34
- reply: null | { asks: { ask: string; chosen: { id: string; label: string; other?: true }[]; note?: string }[]; borrowed: Record<string, string>; tuned: Knobs; comments: { part: string | null; text: string }[]; verdict?: { kind: "use" | "revise"; state: string | null; variant: string; version?: number } };
33
+ design: string | null;
34
+ reply: null | { asks: { ask: string; chosen: { id: string; label: string; other?: true }[]; comment?: string }[]; borrowed: Record<string, string>; tuned: Knobs; comments: { part: string | null; text: string }[]; verdict?: { kind: "use" | "revise"; state: string | null; variant: string; version?: number } };
35
35
  messages: { text: string; state: string | null; variant: string | null }[];
36
36
  inUse: { state: string | null; variant: string; version: number }[]; archived: { state: string | null; variant: string }[];
37
- closed?: true; dismissed?: { ask: string; text: string }[];
38
37
  };
39
- type Pending = { mock: string; closed?: true; viewerOpen: boolean; draft: null | { answered: number; of: number; comments: number; touchedAt: string } };
38
+ type Pending = { design: string; archived?: true; viewerOpen: boolean; draft: null | { answered: number; of: number; comments: number; touchedAt: string } };
40
39
  declare const mockpit: {
41
40
  guide(topic?: "knobs" | "asks" | "surfaces" | "html" | "feedback" | "http" | "scripts"): Promise<string>;
42
- /** No mock: every mock, the flows, plus pending. With one: its states, variants, asks, parts, knobs. */
43
- read(mock?: string, opts?: { body?: boolean; history?: boolean }): Promise<unknown>;
44
- /** Creates or versions (mock, state, variant). One of: html; surfaces, the full ordered list
41
+ /** Read first: decisionList is what the user already settled; it stands unless they say otherwise.
42
+ * No design: every design, the flows, plus pending. With one: its states, variants, asks, parts, knobs.
43
+ * opts.decisions: only the whole list, when a read cut it. */
44
+ read(design?: string, opts?: { body?: boolean; history?: boolean; decisions?: boolean }): Promise<unknown>;
45
+ /** Creates or versions (design, state, variant). One of: html; surfaces, the full ordered list
45
46
  * ({id} alone keeps that surface, a missing id is removed); parts {"name"|"name#key": outer html};
46
- * fills {"part#fill": outer html}, replacing or adding one fill of a part. */
47
- publish(v: Ref & { situation?: string; title?: string; kind?: "page" | "component" | "sketch"; area?: string; source?: string; html?: string; poster?: string; surfaces?: (Surface | { id: string })[]; parts?: Record<string, string>; fills?: Record<string, string>; knobs?: Knobs; variantKnobs?: Knobs; from?: number; prompt?: string; note?: string; widths?: number[]; flow?: string; step?: number }): Promise<Written>;
48
- ask(mock: string, asks: Ask[]): Promise<{ asks: { id: string; text: string }[]; url: string; nudges?: string[] }>;
47
+ * fills {"part#fill": outer html}, replacing or adding one fill of a part.
48
+ * None of them, with kind screen or component: plans it, for a later publish to draw. */
49
+ publish(v: Ref & { title?: string; kind?: "screen" | "component" | "idea"; area?: string; source?: string; html?: string; poster?: string; surfaces?: (Surface | { id: string })[]; parts?: Record<string, string>; fills?: Record<string, string>; knobs?: Knobs; variantKnobs?: Knobs; from?: number; prompt?: string; description?: string; widths?: number[]; flow?: string; step?: number }): Promise<Written>;
50
+ ask(design: string, asks: Ask[]): Promise<{ asks: { id: string; text: string }[]; url: string; nudges?: string[] }>;
49
51
  /** Never waits: what the user sent since you last heard, and what they are doing now. */
50
52
  feedback(): Promise<{ feedback: Feedback[]; pending: Pending[] }>;
51
53
  say(v: Ref, message: string): Promise<void>;
52
- /** No new version; "" clears. { rename } or { areaOrder } without mock edits the project. */
53
- edit(v: { mock?: string; slug?: string; title?: string; kind?: string; area?: string; source?: string; rename?: string; areaOrder?: string[] }): Promise<{ url: string }>;
54
+ /** to or toState moves variants there; archive hides them; restore brings them back. */
55
+ move(v: Ref & { variants: string[]; to?: string; toState?: string; archive?: boolean; restore?: boolean }): Promise<{ variants: { state: string | null; variant: string; status: string }[]; skipped: { variant: string; why: string }[]; url: string }>;
56
+ /** No new version; "" clears. { rename } or { areaOrder } without design edits the project.
57
+ * notes: a short plain-text spec; not applied over the user's own edit (notes.applied says). */
58
+ edit(v: { design?: string; slug?: string; title?: string; kind?: string; area?: string; source?: string; firstState?: string; notes?: string; rename?: string; areaOrder?: string[] }): Promise<{ url: string; notes?: { applied: boolean; text?: string } }>;
54
59
  export(v: Ref): Promise<{ states: { state: string | null; variant: string; version: number; html: string; allFills?: string }[]; reply: unknown }>;
55
60
  /** data: base64 bytes. Use id as an image surface's assetId. */
56
61
  upload(data: string, opts: { contentType: string; filename?: string; kind?: "image" | "file" }): Promise<{ id: string; url: string }>;
@@ -64,18 +69,19 @@ export const RUN_FUNCTIONS = [
64
69
  "ask",
65
70
  "feedback",
66
71
  "say",
72
+ "move",
67
73
  "edit",
68
74
  "export",
69
75
  "upload",
70
76
  ];
71
77
  export const RUN_EXAMPLE = `const html = (tone) => \`<section data-part="hero" class="\${tone}"><h1>Writer</h1></section>\`;
72
- await mockpit.publish({ mock: "writer", variant: "calm", html: html("calm") });
73
- await mockpit.publish({ mock: "writer", variant: "bold", html: html("bold") });
78
+ await mockpit.publish({ design: "writer", variant: "calm", html: html("calm") });
79
+ await mockpit.publish({ design: "writer", variant: "bold", html: html("bold") });
74
80
  const { url } = await mockpit.ask("writer", [{ id: "tone", text: "Calm or bold?",
75
81
  options: [{ label: "Calm", variant: "calm" }, { label: "Bold", variant: "bold" }] }]);
76
82
  // Tell the user where to look and end the turn; a later run reads mockpit.feedback().
77
83
  return url;`;
78
- export const RUN_DESCRIPTION = "Run a script against mockpit, which shows design work to the user (project > mock > state > " +
84
+ export const RUN_DESCRIPTION = "Run a script against mockpit, which shows design work to the user (project > design > state > " +
79
85
  "variant > version). Publish variants and ask in one call; nothing waits for the user. Returns " +
80
86
  "value, prints, calls (every host call in order: which writes landed), error {kind, message, " +
81
87
  "line} and feedback (every batch received, even if the script failed). Read mockpit.guide() " +