mockpit 1.2.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/README.md +13 -8
  2. package/bin/mockpit.js +116 -16
  3. package/dist/mcp/server.js +10 -7
  4. package/dist/server/apiViews.d.ts +118 -17
  5. package/dist/server/apiViews.js +66 -8
  6. package/dist/server/app.d.ts +2 -1
  7. package/dist/server/app.js +917 -144
  8. package/dist/server/decisions.d.ts +23 -0
  9. package/dist/server/decisions.js +99 -0
  10. package/dist/server/designGuide.js +45 -10
  11. package/dist/server/embeds.d.ts +25 -0
  12. package/dist/server/embeds.js +118 -0
  13. package/dist/server/eventLog.js +2 -1
  14. package/dist/server/feedbackBatch.d.ts +12 -1
  15. package/dist/server/feedbackBatch.js +20 -3
  16. package/dist/server/fills.d.ts +41 -0
  17. package/dist/server/fills.js +328 -0
  18. package/dist/server/index.js +15 -1
  19. package/dist/server/knobs.d.ts +6 -2
  20. package/dist/server/knobs.js +11 -1
  21. package/dist/server/mcpHttp.d.ts +3 -0
  22. package/dist/server/mcpHttp.js +3 -0
  23. package/dist/server/mcpSpec.d.ts +13 -13
  24. package/dist/server/mcpSpec.js +73 -8
  25. package/dist/server/postSurfaces.js +3 -12
  26. package/dist/server/richRender.js +3 -1
  27. package/dist/server/run.js +4 -0
  28. package/dist/server/runApi.d.ts +1 -1
  29. package/dist/server/runApi.js +4 -3
  30. package/dist/server/sqlStore.d.ts +89 -4
  31. package/dist/server/sqlStore.js +149 -23
  32. package/dist/server/surfacePage.d.ts +6 -2
  33. package/dist/server/surfacePage.js +142 -10
  34. package/dist/server/themes.d.ts +2 -0
  35. package/dist/server/themes.js +23 -3
  36. package/dist/server/types.d.ts +73 -11
  37. package/dist/server/types.js +42 -2
  38. package/dist/server/viewerRequest.d.ts +2 -0
  39. package/dist/server/viewerRequest.js +14 -0
  40. package/guide/topics/asks.md +50 -3
  41. package/guide/topics/feedback.md +89 -11
  42. package/guide/topics/html.md +5 -1
  43. package/guide/topics/http.md +2 -1
  44. package/guide/topics/knobs.md +2 -1
  45. package/guide/topics/surfaces.md +24 -8
  46. package/package.json +4 -13
  47. package/skills/launch-video/SKILL.md +1 -1
  48. package/skills/mockpit/SKILL.md +12 -4
  49. package/viewer/dist/index.html +8 -8
  50. package/dist/server/slots.d.ts +0 -14
  51. package/dist/server/slots.js +0 -71
@@ -28,7 +28,12 @@ const field = {
28
28
  knobs: 'Global knobs (tunekit usePane shape) keyed by path: [default,min,max,step], boolean, {type:"select",options}, "#hex"',
29
29
  variantKnobs: "Knobs this variant alone has",
30
30
  from: "Branch from this version",
31
+ fork: 'Start this new variant from a sibling: "variant" or "variant@N"; alone it copies it, with parts/fills it edits the copy',
31
32
  prompt: "What prompted this version; usually omit",
33
+ note: "What this variant is; shown beside it, never in the html",
34
+ widths: "Widths it ships at, side by side: [390,1280]",
35
+ flow: "Flow this screen is a step of; alone, only places it",
36
+ step: "1-based place; 0 removes",
32
37
  kits: `Opt-in bundles: ${KIT_IDS.join("|")}`,
33
38
  };
34
39
  const diffFileSchema = z.object({
@@ -75,10 +80,15 @@ const askSchema = z.object({
75
80
  state: z.string().optional(),
76
81
  part: z.string().optional().describe("data-part name, for scope part"),
77
82
  multi: z.boolean().optional(),
83
+ after: z
84
+ .string()
85
+ .optional()
86
+ .describe("Id of an earlier ask this depends on; it opens once that one is answered"),
78
87
  options: z.array(z.object({
79
88
  id: z.string().optional(),
80
89
  label: z.string(),
81
90
  variant: z.string().optional().describe("Bind to a published variant"),
91
+ version: z.number().int().optional().describe("And one version of it"),
82
92
  set: z.record(z.string(), z.unknown()).optional().describe("Or to knob values {path: value}"),
83
93
  })),
84
94
  });
@@ -100,6 +110,9 @@ function zodParam(p) {
100
110
  case "integer":
101
111
  s = z.number().int();
102
112
  break;
113
+ case "integers":
114
+ s = z.array(z.number().int());
115
+ break;
103
116
  default:
104
117
  s = p.t === "string" ? z.string() : p.t === "number" ? z.number() : z.boolean();
105
118
  }
@@ -118,7 +131,7 @@ const VARIANT_REF = { mock: P.mock, state: P.state, variant: P.variant, project:
118
131
  export const MCP_TOOL_DEFS = [
119
132
  {
120
133
  name: "publish",
121
- description: "Create or version one variant of one state of a mock. One of html, surfaces (the full ordered list) or parts (splices the latest version). Returns parts per state, nudges, feedback.",
134
+ 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.",
122
135
  params: {
123
136
  ...VARIANT_REF,
124
137
  title: { t: "string", d: field.title },
@@ -129,10 +142,19 @@ export const MCP_TOOL_DEFS = [
129
142
  d: "Full ordered list: {id} keeps a surface, a missing id removes it",
130
143
  },
131
144
  parts: { t: "object", d: '{"name"|"name#key": outer html}; splices marked parts' },
145
+ fills: {
146
+ t: "object",
147
+ d: '{"part#fill": outer html}; replaces that fill of a slot, or adds it after the others',
148
+ },
132
149
  knobs: { t: "object", d: field.knobs },
133
150
  variantKnobs: { t: "object", d: field.variantKnobs },
134
151
  from: { t: "integer", d: field.from },
152
+ fork: { t: "string", d: field.fork },
135
153
  prompt: { t: "string", d: field.prompt },
154
+ note: { t: "string", d: field.note },
155
+ widths: { t: "integers", d: field.widths },
156
+ flow: { t: "string", d: field.flow },
157
+ step: { t: "integer", d: field.step },
136
158
  session: P.session,
137
159
  sessionTitle: { t: "string", d: field.sessionTitle },
138
160
  agent: { t: "string", d: field.agent },
@@ -152,17 +174,21 @@ export const MCP_TOOL_DEFS = [
152
174
  },
153
175
  {
154
176
  name: "read",
155
- description: "Without mock: every mock (slug, states, variants, open asks) plus pending. With mock: its states, variants, asks with answers, parts, knobs and last tuned values, plus pending. Never consumes feedback.",
177
+ description: "Without mock: every mock (slug, states, variants, open asks), flows, plus pending. With mock: its states, variants, asks with answers, parts, knobs and settled values (every answer's set and tuning sent so far), plus pending. Never consumes feedback.",
156
178
  params: {
157
179
  mock: { t: "string", d: field.mock },
158
180
  project: P.project,
159
181
  body: { t: "boolean", d: "Include each variant's surfaces" },
160
182
  history: { t: "boolean", d: "Include version rows" },
183
+ tree: {
184
+ t: "boolean",
185
+ d: "Without mock: the project as a tree (each mock's variants with status and forkedFrom, the mocks it uses and is used in)",
186
+ },
161
187
  },
162
188
  },
163
189
  {
164
190
  name: "feedback",
165
- description: "Returns at once: what the user sent since you last heard (one batch per mock: reply answers, mix, tuned knobs, part comments, comments, accepted/archived), delivered once, plus pending (viewer open, draft progress).",
191
+ description: "Returns at once: what the user sent since you last heard (one batch per mock: reply answers, mix, tuned knobs, part comments, comments, accepted/archived/dropped, or resolved with the asks it dismissed), delivered once, plus pending (viewer open, draft progress).",
166
192
  params: {
167
193
  project: P.project,
168
194
  session: { t: "string", d: "Session id returned by publish", req: true },
@@ -181,7 +207,7 @@ export const MCP_TOOL_DEFS = [
181
207
  },
182
208
  {
183
209
  name: "export",
184
- description: "The accepted (or current) html per state, version history, screenshot URL, knobs and the last reply's tuned values.",
210
+ description: "The html in use (else current) per state, version history, screenshot URL, knobs, the settled values and the last reply.",
185
211
  params: VARIANT_REF,
186
212
  },
187
213
  {
@@ -235,7 +261,9 @@ const nullStr = z.string().nullable();
235
261
  const strs = z.array(z.string());
236
262
  const bag = z.record(z.string(), z.unknown());
237
263
  const variantRef = o({ state: nullStr, variant: str });
264
+ const inUseRef = o({ state: nullStr, variant: str, version: num });
238
265
  const partsByState = z.array(o({ state: nullStr, parts: z.array(o({ name: str })) }));
266
+ const flowSchema = o({ name: str, steps: z.array(o({ mock: str, state: nullStr })) });
239
267
  const feedbackSchema = o({
240
268
  mock: nullStr,
241
269
  reply: o({
@@ -252,14 +280,24 @@ const feedbackSchema = o({
252
280
  .nullable()
253
281
  .describe("The user's Send; null if only comments"),
254
282
  comments: z.array(o({ seq: num, text: str })),
255
- accepted: z.array(variantRef),
283
+ accepted: z.array(inUseRef).describe("Accepted, each at the version put in use"),
256
284
  archived: z.array(variantRef),
285
+ dropped: z.array(variantRef),
286
+ resolved: z
287
+ .literal(true)
288
+ .optional()
289
+ .describe("The user resolved the mock: its open asks were closed unanswered"),
290
+ dismissed: z
291
+ .array(o({ ask: str, text: str }))
292
+ .optional()
293
+ .describe("The asks the resolution closed; don't ask them again"),
257
294
  }).meta({ id: "Feedback" });
258
295
  // Typed once, on feedback: repeating it on every write would cost more than
259
296
  // the rest of the write's output schema.
260
297
  const feedbackRide = z.array(bag).describe("Feedback batches as the feedback tool returns");
261
298
  const pendingSchema = o({
262
299
  mock: str,
300
+ resolved: z.literal(true).optional(),
263
301
  viewerOpen: z.boolean(),
264
302
  draft: o({ answered: num, of: num, comments: num, touchedAt: str }).nullable(),
265
303
  }).meta({ id: "Pending" });
@@ -271,6 +309,7 @@ const writeOutput = {
271
309
  partChanges: o({ vanished: strs, renamed: z.array(o({ from: str, to: str })) }).optional(),
272
310
  nudges: strs.optional(),
273
311
  suggestedAsk: bag.optional().describe("Send with ask when a nudge names it"),
312
+ flow: flowSchema.optional(),
274
313
  feedback: feedbackRide,
275
314
  };
276
315
  const OUTPUT_SCHEMAS = {
@@ -307,13 +346,39 @@ const OUTPUT_SCHEMAS = {
307
346
  mocks: z.array(o({ slug: str, states: strs, variants: num, open: num })).optional(),
308
347
  states: strs.optional(),
309
348
  asks: z.array(o({ id: str, text: str })).optional(),
310
- variants: z.array(o({ state: nullStr, variant: str, status: str, version: num })).optional(),
349
+ variants: z
350
+ .array(o({
351
+ state: nullStr,
352
+ variant: str,
353
+ status: str,
354
+ version: num,
355
+ acceptedVersion: num.optional().describe("Set when accepted: the version in use"),
356
+ history: z
357
+ .array(o({ version: num, hidden: z.boolean().optional() }))
358
+ .optional()
359
+ .describe("With history: version rows; hidden ones the user put away are flagged"),
360
+ }))
361
+ .optional(),
362
+ inUse: z
363
+ .array(inUseRef)
364
+ .optional()
365
+ .describe("Per state, the version the user put in use; export and embeds resolve to it"),
311
366
  knobs: bag.optional(),
312
- tuned: bag.optional().describe("Knob values from the latest reply"),
367
+ settled: bag.optional().describe("Every knob value the user has sent, later replies winning"),
368
+ tree: z.array(bag).optional(),
369
+ flows: z.array(flowSchema).optional(),
313
370
  pending: z.union([z.array(pendingSchema), pendingSchema]),
314
371
  },
315
372
  export: {
316
- states: z.array(o({ state: nullStr, variant: str, version: num, html: str, markdown: str })),
373
+ states: z.array(o({
374
+ state: nullStr,
375
+ variant: str,
376
+ version: num,
377
+ latest: num.optional().describe("Your newer version, not in use yet"),
378
+ html: str,
379
+ markdown: str,
380
+ })),
381
+ settled: bag,
317
382
  reply: bag.nullable(),
318
383
  },
319
384
  };
@@ -6,23 +6,14 @@ const MERMAID_PARSE_NEXT_STEPS = [
6
6
  'Keep the diagram declaration on the first non-comment line (for example, "flowchart TD").',
7
7
  "Reduce the diagram to a minimal valid form, then add statements back until the failing line is isolated.",
8
8
  ];
9
- const requiredString = (name) => z.string({
10
- required_error: `requires string "${name}"`,
11
- invalid_type_error: `requires string "${name}"`,
12
- });
9
+ const requiredString = (name) => z.string({ error: `requires string "${name}"` });
13
10
  const optionalLooseString = z.preprocess((v) => (typeof v === "string" ? v : undefined), z.string().optional());
14
11
  const looseLayout = z.preprocess((v) => (v === "unified" || v === "split" ? v : undefined), z.enum(["unified", "split"]).optional());
15
12
  const optionalLooseNumber = z.preprocess((v) => (typeof v === "number" && Number.isFinite(v) ? v : undefined), z.number().optional());
16
13
  const strictDiffFile = z.object({
17
14
  filename: requiredString("filename"),
18
- before: z.string({
19
- required_error: 'requires string "before" and "after"',
20
- invalid_type_error: 'requires string "before" and "after"',
21
- }),
22
- after: z.string({
23
- required_error: 'requires string "before" and "after"',
24
- invalid_type_error: 'requires string "before" and "after"',
25
- }),
15
+ before: z.string({ error: 'requires string "before" and "after"' }),
16
+ after: z.string({ error: 'requires string "before" and "after"' }),
26
17
  language: z.string().optional(),
27
18
  });
28
19
  const looseDiffFile = z
@@ -139,7 +139,9 @@ blockquote {
139
139
  color: var(--muted);
140
140
  }
141
141
  table { border-collapse: collapse; font-size: 13px; }
142
- th, td { border: 0.5px solid var(--border); padding: 4px 8px; text-align: left; }
142
+ /* break-word, not the body's anywhere: anywhere lets a column shrink to one
143
+ letter, so a long cell beside it squeezes "Topic" into "Top/ic". */
144
+ th, td { border: 0.5px solid var(--border); padding: 4px 8px; text-align: left; overflow-wrap: break-word; }
143
145
  th { background: var(--hover); }
144
146
  img { max-width: 100%; height: auto; border-radius: 6px; }
145
147
  hr { border: none; border-top: 0.5px solid var(--border); margin: 1em 0; }
@@ -153,6 +153,10 @@ export function createRunFlow(deps) {
153
153
  return [await deps.guide("", topic), String(topic)];
154
154
  },
155
155
  async read([mock, opts]) {
156
+ if ((mock === undefined || mock === null) && plain(opts).tree === true) {
157
+ const value = await take(flows.tree({ project: await projectOf() }));
158
+ return [value, `${value.tree.length} mocks`];
159
+ }
156
160
  if (mock === undefined || mock === null) {
157
161
  const value = await take(flows.list({ project: await projectOf() }));
158
162
  return [value, `${value.mocks.length} mocks`];
@@ -1,4 +1,4 @@
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 }[];\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; // send it 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 }[]; mix: Knobs; tuned: Knobs; comments: { part: string | null; text: string }[] };\n comments: { text: string; state: string | null; variant: string | null }[];\n accepted: { state: string | null; variant: string }[]; archived: { state: string | null; variant: string }[];\n};\ntype Pending = { mock: string; 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 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 publish(v: Ref & { title?: string; kind?: \"component\" | \"page\"; html?: string; surfaces?: (Surface | { id: string })[]; parts?: Record<string, string>; knobs?: Knobs; variantKnobs?: Knobs; from?: 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 export(v: Ref): Promise<{ states: { state: string | null; variant: string; version: number; html: 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;";
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 }[];\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; // send it 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 }[]; mix: Knobs; tuned: Knobs; comments: { part: string | null; text: string }[] };\n comments: { text: string; state: string | null; variant: string | null }[];\n accepted: { state: string | null; variant: string }[]; archived: { state: string | null; variant: string }[];\n};\ntype Pending = { mock: string; 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 alternative of a slot. */\n publish(v: Ref & { title?: string; kind?: \"component\" | \"page\"; html?: 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 export(v: Ref): Promise<{ states: { state: string | null; variant: string; version: number; html: 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
2
  export declare const RUN_FUNCTIONS: readonly ["guide", "read", "publish", "ask", "feedback", "say", "export", "upload"];
3
3
  export type RunFunction = (typeof RUN_FUNCTIONS)[number];
4
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: \"look\", text: \"Which look?\",\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;";
@@ -38,11 +38,12 @@ type Feedback = {
38
38
  type Pending = { mock: string; viewerOpen: boolean; draft: null | { answered: number; of: number; comments: number; touchedAt: string } };
39
39
  declare const mockpit: {
40
40
  guide(topic?: "knobs" | "asks" | "surfaces" | "html" | "feedback" | "http" | "scripts"): Promise<string>;
41
- /** No mock: every mock plus pending. With one: its states, variants, asks, parts, knobs. */
41
+ /** No mock: every mock, the flows, plus pending. With one: its states, variants, asks, parts, knobs. */
42
42
  read(mock?: string, opts?: { body?: boolean; history?: boolean }): Promise<unknown>;
43
43
  /** Creates or versions (mock, state, variant). One of: html; surfaces, the full ordered list
44
- * ({id} alone keeps that surface, a missing id is removed); parts {"name"|"name#key": outer html}. */
45
- publish(v: Ref & { title?: string; kind?: "component" | "page"; html?: string; surfaces?: (Surface | { id: string })[]; parts?: Record<string, string>; knobs?: Knobs; variantKnobs?: Knobs; from?: number }): Promise<Written>;
44
+ * ({id} alone keeps that surface, a missing id is removed); parts {"name"|"name#key": outer html};
45
+ * fills {"part#fill": outer html}, replacing or adding one alternative of a slot. */
46
+ publish(v: Ref & { title?: string; kind?: "component" | "page"; html?: 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>;
46
47
  ask(mock: string, asks: Ask[]): Promise<{ asks: { id: string; text: string }[]; url: string; nudges?: string[] }>;
47
48
  /** Never waits: what the user sent since you last heard, and what they are doing now. */
48
49
  feedback(): Promise<{ feedback: Feedback[]; pending: Pending[] }>;
@@ -1,4 +1,4 @@
1
- import { type Ask, type Asset, type Comment, type CommentQuery, type CommitReplyInput, type CreateAssetInput, type CreateCommentInput, type CreateMockInput, type CreatePostInput, type CreateSessionInput, type Draft, type Knobs, type Mock, type MockKind, type Post, type PostQuery, type PostStatus, type PostVersion, type Session, type Slot, type SqlStorage, type Store, type Surface, type UpdateMockInput, type UpdatePostInput } from "./types.ts";
1
+ import { type Ask, type Asset, type Comment, type CommentQuery, type CommitReplyInput, type CreateAssetInput, type CreateCommentInput, type CreateMockInput, type CreatePostInput, type CreateSessionInput, type Draft, type Knobs, type Mock, type MockKind, type Post, type PostQuery, type PostStatus, type PostVersion, type Session, type Embed, type Flow, type FlowStep, type ForkRef, type SqlStorage, type Store, type Surface, type UpdateMockInput, type UpdatePostInput } from "./types.ts";
2
2
  export declare class SqlStore implements Store {
3
3
  private sql;
4
4
  private assetRefCache;
@@ -45,6 +45,10 @@ export declare class SqlStore implements Store {
45
45
  createMock(input: CreateMockInput): Promise<Mock>;
46
46
  updateMock(id: string, patch: UpdateMockInput): Promise<Mock | null>;
47
47
  removeMock(id: string): Promise<boolean>;
48
+ private flowsOf;
49
+ private writeFlow;
50
+ listFlows(project: string): Promise<Flow[]>;
51
+ placeFlowStep(project: string, name: string, screen: FlowStep, step: number): Promise<Flow | null>;
48
52
  putDraft(mockId: string, draft: Draft | null): Promise<{
49
53
  draft: Draft | null;
50
54
  id: string;
@@ -55,7 +59,9 @@ export declare class SqlStore implements Store {
55
59
  states: string[];
56
60
  asks: Ask[];
57
61
  knobs: Knobs;
62
+ widths: number[];
58
63
  sessionId: string | null;
64
+ resolvedAt: string | null;
59
65
  createdAt: string;
60
66
  updatedAt: string;
61
67
  } | null>;
@@ -67,13 +73,14 @@ export declare class SqlStore implements Store {
67
73
  createPost(input: CreatePostInput): Promise<Post | null>;
68
74
  updatePost(id: string, patch: UpdatePostInput): Promise<{
69
75
  author?: string | undefined;
70
- slots: Slot[];
76
+ embeds: Embed[];
71
77
  state: string | null;
72
78
  version: number;
73
79
  updatedAt: string;
74
80
  history: PostVersion[];
75
81
  from: number;
76
82
  prompt: string;
83
+ note?: string | undefined;
77
84
  knobs?: Knobs | undefined;
78
85
  title: string;
79
86
  surfaces: Surface[];
@@ -83,9 +90,13 @@ export declare class SqlStore implements Store {
83
90
  variant: string;
84
91
  status: PostStatus;
85
92
  createdAt: string;
93
+ forkedFrom?: ForkRef;
94
+ starred?: true;
95
+ acceptedVersion?: number;
96
+ hiddenVersions?: number[];
86
97
  } | null>;
87
98
  removePost(id: string): Promise<boolean>;
88
- setPostStatus(id: string, status: PostStatus): Promise<{
99
+ setPostStatus(id: string, status: PostStatus, acceptedVersion?: number): Promise<{
89
100
  status: PostStatus;
90
101
  id: string;
91
102
  sessionId: string;
@@ -99,11 +110,85 @@ export declare class SqlStore implements Store {
99
110
  version: number;
100
111
  history: PostVersion[];
101
112
  knobs?: Knobs;
102
- slots: Slot[];
113
+ note?: string;
114
+ embeds: Embed[];
115
+ forkedFrom?: ForkRef;
116
+ starred?: true;
117
+ hiddenVersions?: number[];
118
+ from?: number;
119
+ prompt?: string;
120
+ author?: string;
121
+ } | {
122
+ status: PostStatus;
123
+ acceptedVersion: number;
124
+ id: string;
125
+ sessionId: string;
126
+ mock: string;
127
+ state: string | null;
128
+ variant: string;
129
+ title: string;
130
+ surfaces: Surface[];
131
+ createdAt: string;
132
+ updatedAt: string;
133
+ version: number;
134
+ history: PostVersion[];
135
+ knobs?: Knobs;
136
+ note?: string;
137
+ embeds: Embed[];
138
+ forkedFrom?: ForkRef;
139
+ starred?: true;
140
+ hiddenVersions?: number[];
141
+ from?: number;
142
+ prompt?: string;
143
+ author?: string;
144
+ } | null>;
145
+ setPostStarred(id: string, starred: boolean): Promise<{
146
+ id: string;
147
+ sessionId: string;
148
+ mock: string;
149
+ state: string | null;
150
+ variant: string;
151
+ status: PostStatus;
152
+ title: string;
153
+ surfaces: Surface[];
154
+ createdAt: string;
155
+ updatedAt: string;
156
+ version: number;
157
+ history: PostVersion[];
158
+ knobs?: Knobs;
159
+ note?: string;
160
+ embeds: Embed[];
161
+ forkedFrom?: ForkRef;
162
+ acceptedVersion?: number;
163
+ hiddenVersions?: number[];
164
+ from?: number;
165
+ prompt?: string;
166
+ author?: string;
167
+ } | {
168
+ starred: true;
169
+ id: string;
170
+ sessionId: string;
171
+ mock: string;
172
+ state: string | null;
173
+ variant: string;
174
+ status: PostStatus;
175
+ title: string;
176
+ surfaces: Surface[];
177
+ createdAt: string;
178
+ updatedAt: string;
179
+ version: number;
180
+ history: PostVersion[];
181
+ knobs?: Knobs;
182
+ note?: string;
183
+ embeds: Embed[];
184
+ forkedFrom?: ForkRef;
185
+ acceptedVersion?: number;
186
+ hiddenVersions?: number[];
103
187
  from?: number;
104
188
  prompt?: string;
105
189
  author?: string;
106
190
  } | null>;
191
+ setVersionHidden(id: string, version: number, hidden: boolean): Promise<Post | null>;
107
192
  listComments(query: CommentQuery): Promise<Comment[]>;
108
193
  private insertComment;
109
194
  createComment(input: CreateCommentInput): Promise<Comment | null>;