mockpit 2.0.0 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/README.md +59 -223
  2. package/bin/demoData.js +2 -2
  3. package/bin/initDesign.js +17 -22
  4. package/bin/mockpit.js +626 -216
  5. package/bin/poster.js +434 -0
  6. package/dist/mcp/server.js +127 -29
  7. package/dist/server/answerAdditions.d.ts +7 -0
  8. package/dist/server/answerAdditions.js +76 -0
  9. package/dist/server/apiViews.d.ts +627 -385
  10. package/dist/server/apiViews.js +198 -81
  11. package/dist/server/app.d.ts +7 -2
  12. package/dist/server/app.js +3514 -984
  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 +640 -0
  18. package/dist/server/codeWorker.js +2 -2
  19. package/dist/server/contrast.d.ts +4 -0
  20. package/dist/server/contrast.js +157 -0
  21. package/dist/server/decisionList.d.ts +48 -0
  22. package/dist/server/decisionList.js +340 -0
  23. package/dist/server/decisions.d.ts +4 -4
  24. package/dist/server/decisions.js +9 -9
  25. package/dist/server/designGuide.d.ts +14 -7
  26. package/dist/server/designGuide.js +314 -88
  27. package/dist/server/embeds.d.ts +3 -1
  28. package/dist/server/embeds.js +31 -6
  29. package/dist/server/eventLog.d.ts +2 -2
  30. package/dist/server/eventLog.js +11 -11
  31. package/dist/server/events.d.ts +15 -6
  32. package/dist/server/feedbackBatch.d.ts +39 -13
  33. package/dist/server/feedbackBatch.js +129 -47
  34. package/dist/server/fills.d.ts +4 -0
  35. package/dist/server/fills.js +55 -1
  36. package/dist/server/guidance.d.ts +1 -1
  37. package/dist/server/guidance.js +2 -2
  38. package/dist/server/handoff.d.ts +4 -1
  39. package/dist/server/handoff.js +8 -2
  40. package/dist/server/icons.js +1 -1
  41. package/dist/server/index.js +39 -10
  42. package/dist/server/jump.d.ts +21 -0
  43. package/dist/server/jump.js +175 -0
  44. package/dist/server/kits.d.ts +2 -2
  45. package/dist/server/kits.js +54 -1
  46. package/dist/server/knobs.d.ts +3 -3
  47. package/dist/server/knobs.js +6 -6
  48. package/dist/server/mcpHttp.d.ts +7 -1
  49. package/dist/server/mcpHttp.js +29 -12
  50. package/dist/server/mcpSpec.d.ts +27 -27
  51. package/dist/server/mcpSpec.js +196 -56
  52. package/dist/server/parts.js +9 -1
  53. package/dist/server/run.d.ts +1 -1
  54. package/dist/server/run.js +47 -17
  55. package/dist/server/runApi.d.ts +3 -3
  56. package/dist/server/runApi.js +34 -21
  57. package/dist/server/sqlStore.d.ts +148 -103
  58. package/dist/server/sqlStore.js +1052 -181
  59. package/dist/server/standings.d.ts +25 -0
  60. package/dist/server/standings.js +113 -0
  61. package/dist/server/surfacePage.d.ts +8 -9
  62. package/dist/server/surfacePage.js +423 -100
  63. package/dist/server/system.d.ts +234 -0
  64. package/dist/server/system.js +1508 -0
  65. package/dist/server/systemChecks.d.ts +15 -0
  66. package/dist/server/systemChecks.js +224 -0
  67. package/dist/server/systemSpecimen.d.ts +2 -0
  68. package/dist/server/systemSpecimen.js +49 -0
  69. package/dist/server/themes.d.ts +9 -7
  70. package/dist/server/themes.js +43 -90
  71. package/dist/server/types.d.ts +266 -93
  72. package/dist/server/types.js +76 -79
  73. package/extensions/mockpit.js +89 -72
  74. package/guide/AGENT_SETUP.md +15 -1
  75. package/guide/packs/design-craft.md +2 -3
  76. package/guide/packs/foundations.md +35 -0
  77. package/guide/topics/asks.md +108 -63
  78. package/guide/topics/feedback.md +129 -120
  79. package/guide/topics/html.md +18 -25
  80. package/guide/topics/http.md +43 -41
  81. package/guide/topics/knobs.md +7 -10
  82. package/guide/topics/scripts.md +22 -33
  83. package/guide/topics/surfaces.md +39 -48
  84. package/guide/topics/system.md +157 -0
  85. package/opencode/mockpit.js +120 -0
  86. package/opencode/package.json +8 -0
  87. package/package.json +15 -14
  88. package/skills/launch-video/SKILL.md +11 -11
  89. package/skills/mockpit/SKILL.md +33 -26
  90. package/viewer/dist/index.html +10 -9
@@ -8,14 +8,14 @@ export declare const MCP_INSTRUCTIONS: string;
8
8
  export declare const mcpSurfaceSchema: z.ZodObject<{
9
9
  id: z.ZodOptional<z.ZodString>;
10
10
  kind: z.ZodOptional<z.ZodEnum<{
11
- html: "html";
11
+ code: "code";
12
12
  diff: "diff";
13
+ html: "html";
13
14
  image: "image";
15
+ json: "json";
14
16
  markdown: "markdown";
15
- terminal: "terminal";
16
17
  mermaid: "mermaid";
17
- json: "json";
18
- code: "code";
18
+ terminal: "terminal";
19
19
  }>>;
20
20
  html: z.ZodOptional<z.ZodString>;
21
21
  kits: z.ZodOptional<z.ZodArray<z.ZodString>>;
@@ -30,8 +30,8 @@ export declare const mcpSurfaceSchema: z.ZodObject<{
30
30
  language: z.ZodOptional<z.ZodString>;
31
31
  }, z.core.$strip>>>;
32
32
  layout: z.ZodOptional<z.ZodEnum<{
33
- unified: "unified";
34
33
  split: "split";
34
+ unified: "unified";
35
35
  }>>;
36
36
  assetId: z.ZodOptional<z.ZodString>;
37
37
  alt: z.ZodOptional<z.ZodString>;
@@ -54,7 +54,7 @@ type Param = {
54
54
  d?: string;
55
55
  req?: boolean;
56
56
  } | {
57
- t: "surfaces" | "asks" | "object" | "integers" | "strings";
57
+ t: "surfaces" | "asks" | "object" | "objects" | "named" | "pairs" | "json" | "integers" | "strings";
58
58
  d?: string;
59
59
  req?: boolean;
60
60
  };
@@ -72,115 +72,115 @@ export declare const HTTP_MCP_TOOLS: ({
72
72
  _meta: {
73
73
  "anthropic/alwaysLoad": boolean;
74
74
  };
75
- outputSchema?: Json | undefined;
76
75
  name: string;
77
76
  description: string;
78
77
  inputSchema: Json;
78
+ outputSchema?: Json | undefined;
79
79
  } | {
80
80
  _meta?: undefined;
81
- outputSchema?: Json | undefined;
82
81
  name: string;
83
82
  description: string;
84
83
  inputSchema: Json;
84
+ outputSchema?: Json | undefined;
85
85
  })[];
86
86
  export declare const STDIO_MCP_CATALOG: ({
87
87
  _meta: {
88
88
  "anthropic/alwaysLoad": boolean;
89
89
  };
90
- outputSchema?: Json | undefined;
91
90
  name: string;
92
91
  description: string;
93
92
  inputSchema: Json;
93
+ outputSchema?: Json | undefined;
94
94
  } | {
95
95
  _meta?: undefined;
96
- outputSchema?: Json | undefined;
97
96
  name: string;
98
97
  description: string;
99
98
  inputSchema: Json;
99
+ outputSchema?: Json | undefined;
100
100
  })[];
101
101
  export declare const HTTP_RUN_TOOLS: ({
102
102
  _meta: {
103
103
  "anthropic/alwaysLoad": boolean;
104
104
  };
105
- outputSchema?: Json | undefined;
106
105
  name: string;
107
106
  description: string;
108
107
  inputSchema: Json;
108
+ outputSchema?: Json | undefined;
109
109
  } | {
110
110
  _meta?: undefined;
111
- outputSchema?: Json | undefined;
112
111
  name: string;
113
112
  description: string;
114
113
  inputSchema: Json;
114
+ outputSchema?: Json | undefined;
115
115
  })[];
116
116
  export declare const STDIO_RUN_CATALOG: ({
117
117
  _meta: {
118
118
  "anthropic/alwaysLoad": boolean;
119
119
  };
120
- outputSchema?: Json | undefined;
121
120
  name: string;
122
121
  description: string;
123
122
  inputSchema: Json;
123
+ outputSchema?: Json | undefined;
124
124
  } | {
125
125
  _meta?: undefined;
126
- outputSchema?: Json | undefined;
127
126
  name: string;
128
127
  description: string;
129
128
  inputSchema: Json;
129
+ outputSchema?: Json | undefined;
130
130
  })[];
131
131
  export declare const STDIO_MCP_TOOLS: ({
132
132
  _meta: {
133
133
  "anthropic/alwaysLoad": boolean;
134
134
  };
135
- outputSchema?: z.ZodObject<{
136
- [x: string]: z.core.$ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>;
137
- }, z.core.$loose> | undefined;
138
135
  name: string;
139
136
  description: string;
140
137
  inputSchema: Readonly<{
141
138
  [k: string]: z.core.$ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>;
142
139
  }>;
143
- } | {
144
- _meta?: undefined;
145
140
  outputSchema?: z.ZodObject<{
146
141
  [x: string]: z.core.$ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>;
147
142
  }, z.core.$loose> | undefined;
143
+ } | {
144
+ _meta?: undefined;
148
145
  name: string;
149
146
  description: string;
150
147
  inputSchema: Readonly<{
151
148
  [k: string]: z.core.$ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>;
152
149
  }>;
150
+ outputSchema?: z.ZodObject<{
151
+ [x: string]: z.core.$ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>;
152
+ }, z.core.$loose> | undefined;
153
153
  })[];
154
154
  export declare const STDIO_RUN_TOOLS: ({
155
155
  _meta: {
156
156
  "anthropic/alwaysLoad": boolean;
157
157
  };
158
- outputSchema?: z.ZodObject<{
159
- [x: string]: z.core.$ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>;
160
- }, z.core.$loose> | undefined;
161
158
  name: string;
162
159
  description: string;
163
160
  inputSchema: Readonly<{
164
161
  [k: string]: z.core.$ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>;
165
162
  }>;
166
- } | {
167
- _meta?: undefined;
168
163
  outputSchema?: z.ZodObject<{
169
164
  [x: string]: z.core.$ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>;
170
165
  }, z.core.$loose> | undefined;
166
+ } | {
167
+ _meta?: undefined;
171
168
  name: string;
172
169
  description: string;
173
170
  inputSchema: Readonly<{
174
171
  [k: string]: z.core.$ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>;
175
172
  }>;
173
+ outputSchema?: z.ZodObject<{
174
+ [x: string]: z.core.$ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>;
175
+ }, z.core.$loose> | undefined;
176
176
  })[];
177
177
  export declare const MCP_TOOL_NAMES: string[];
178
178
  export declare function toolResult(name: string, value: unknown): {
179
- structuredContent?: Record<string, unknown> | undefined;
180
179
  content: {
181
180
  type: "text";
182
181
  text: string;
183
182
  }[];
183
+ structuredContent?: Record<string, unknown> | undefined;
184
184
  };
185
185
  export declare const MAX_RESULT_IMAGES = 8;
186
186
  export declare function withFeedbackImages<T extends {
@@ -190,11 +190,11 @@ export declare function withFeedbackImages<T extends {
190
190
  mimeType: string;
191
191
  } | null>): Promise<T>;
192
192
  export declare function runToolResult(envelope: unknown): {
193
- isError?: boolean | undefined;
194
- structuredContent?: Record<string, unknown> | undefined;
195
193
  content: {
196
194
  type: "text";
197
195
  text: string;
198
196
  }[];
197
+ structuredContent?: Record<string, unknown> | undefined;
198
+ isError?: boolean | undefined;
199
199
  };
200
200
  export {};
@@ -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,13 @@ 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
+ palette: z
107
+ .string()
108
+ .optional()
109
+ .describe("Or a palette id of the project's system; the answer makes it the default"),
110
+ html: z.string().optional().describe("Or a whole page"),
99
111
  recommended: z.boolean().optional().describe("The one you would pick; one per ask"),
100
112
  })),
101
113
  });
@@ -114,6 +126,23 @@ function zodParam(p) {
114
126
  case "object":
115
127
  s = z.record(z.string(), z.unknown());
116
128
  break;
129
+ case "objects":
130
+ s = z.array(z.record(z.string(), z.unknown()));
131
+ break;
132
+ // A list of objects where a bare name stands for {name}.
133
+ case "named":
134
+ s = z.array(z.union([z.string(), z.record(z.string(), z.unknown())]));
135
+ break;
136
+ // [foreground, background, minimum?]
137
+ case "pairs":
138
+ s = z.array(z
139
+ .array(z.union([z.string(), z.number()]))
140
+ .min(2)
141
+ .max(3));
142
+ break;
143
+ case "json":
144
+ s = z.unknown();
145
+ break;
117
146
  case "integer":
118
147
  s = z.number().int();
119
148
  break;
@@ -131,22 +160,21 @@ function zodParam(p) {
131
160
  return p.req ? s : s.optional();
132
161
  }
133
162
  const P = {
134
- mock: { t: "string", d: field.mock, req: true },
163
+ design: { t: "string", d: field.design, req: true },
135
164
  state: { t: "string", d: field.state },
136
165
  variant: { t: "string", d: field.variant },
137
166
  project: { t: "string", d: field.project },
138
167
  session: { t: "string", d: field.session },
139
168
  };
140
- const VARIANT_REF = { mock: P.mock, state: P.state, variant: P.variant, project: P.project };
169
+ const VARIANT_REF = { design: P.design, state: P.state, variant: P.variant, project: P.project };
141
170
  export const MCP_TOOL_DEFS = [
142
171
  {
143
172
  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.",
173
+ 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
174
  params: {
146
175
  ...VARIANT_REF,
147
- situation: { t: "string", d: field.situation },
148
176
  title: { t: "string", d: field.title },
149
- kind: { t: "enum", values: ["page", "component", "sketch"], d: field.kind },
177
+ kind: { t: "enum", values: ["screen", "component", "idea"], d: field.kind },
150
178
  area: { t: "string", d: field.area },
151
179
  source: { t: "string", d: field.source },
152
180
  html: { t: "string", d: field.html },
@@ -164,8 +192,10 @@ export const MCP_TOOL_DEFS = [
164
192
  variantKnobs: { t: "object", d: field.variantKnobs },
165
193
  from: { t: "integer", d: field.from },
166
194
  fork: { t: "string", d: field.fork },
195
+ amend: { t: "boolean", d: field.amend },
196
+ withdraw: { t: "boolean", d: field.withdraw },
167
197
  prompt: { t: "string", d: field.prompt },
168
- note: { t: "string", d: field.note },
198
+ description: { t: "string", d: field.description },
169
199
  widths: { t: "integers", d: field.widths },
170
200
  flow: { t: "string", d: field.flow },
171
201
  step: { t: "integer", d: field.step },
@@ -177,9 +207,9 @@ export const MCP_TOOL_DEFS = [
177
207
  },
178
208
  {
179
209
  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.",
210
+ 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
211
  params: {
182
- mock: P.mock,
212
+ design: P.design,
183
213
  project: P.project,
184
214
  asks: { t: "asks", d: "Questions with options", req: true },
185
215
  session: P.session,
@@ -188,21 +218,25 @@ export const MCP_TOOL_DEFS = [
188
218
  },
189
219
  {
190
220
  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.",
221
+ 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
222
  params: {
193
- mock: { t: "string", d: field.mock },
223
+ design: { t: "string", d: field.design },
194
224
  project: P.project,
195
225
  body: { t: "boolean", d: "Include each variant's surfaces" },
196
226
  history: { t: "boolean", d: "Include version rows" },
197
227
  tree: {
198
228
  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)",
229
+ d: "Without design: the project as a tree (each design's variants with status and forkedFrom, the designs it embeds and is embedded in)",
230
+ },
231
+ decisions: {
232
+ t: "boolean",
233
+ d: "Only the whole decision list, when decisionList says it was cut",
200
234
  },
201
235
  },
202
236
  },
203
237
  {
204
238
  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).",
239
+ 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
240
  params: {
207
241
  project: P.project,
208
242
  session: { t: "string", d: "Session id returned by publish", req: true },
@@ -211,7 +245,7 @@ export const MCP_TOOL_DEFS = [
211
245
  },
212
246
  {
213
247
  name: "say",
214
- description: "Post a short plain-text message in a mock's thread. Returns feedback.",
248
+ description: "Post a short plain-text message in a design's thread. Returns feedback.",
215
249
  params: {
216
250
  ...VARIANT_REF,
217
251
  message: { t: "string", d: "Plain text", req: true },
@@ -219,24 +253,47 @@ export const MCP_TOOL_DEFS = [
219
253
  },
220
254
  httpOnly: ["session"],
221
255
  },
256
+ {
257
+ name: "move",
258
+ 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.",
259
+ params: {
260
+ design: P.design,
261
+ state: P.state,
262
+ variants: { t: "strings", d: "Variant names; required except with hideOlder or deleteOlder" },
263
+ to: { t: "string", d: "Target design; default this one" },
264
+ toState: { t: "string", d: "Target state; created if new" },
265
+ archive: { t: "boolean" },
266
+ restore: { t: "boolean" },
267
+ hideOlder: { t: "boolean", d: "Hide all but each variant's newest visible version" },
268
+ deleteOlder: { t: "boolean", d: "Delete them instead; permanent, skips what's referenced" },
269
+ project: P.project,
270
+ session: P.session,
271
+ },
272
+ httpOnly: ["session"],
273
+ },
222
274
  {
223
275
  name: "export",
224
- description: "The html in use (else current) per state, version history, screenshot URL, knobs, the settled values and the last reply.",
225
- params: VARIANT_REF,
276
+ description: "The html in use (else current) per state, version history, screenshot URL, knobs, the settled values and the last reply. Without design: the project's system for code (sheet, tokens as CSS and JSON, settled project knobs, components' sources).",
277
+ params: { ...VARIANT_REF, design: { t: "string", d: field.design } },
226
278
  },
227
279
  {
228
280
  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.",
281
+ 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
282
  params: {
231
- mock: { t: "string", d: field.mock },
283
+ design: { t: "string", d: field.design },
232
284
  project: P.project,
233
285
  slug: { t: "string" },
234
286
  title: { t: "string" },
235
- kind: { t: "enum", values: ["page", "component", "sketch"] },
287
+ kind: { t: "enum", values: ["screen", "component", "idea"] },
236
288
  area: { t: "string" },
237
289
  source: { t: "string" },
290
+ firstState: { t: "string", d: "Names a design's one unnamed state, so it can have more" },
291
+ notes: {
292
+ t: "string",
293
+ 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`,
294
+ },
238
295
  rename: { t: "string", d: "New project name" },
239
- areaOrder: { t: "strings", d: "Without mock: Home's area order" },
296
+ areaOrder: { t: "strings", d: "Without design: Home's area order" },
240
297
  session: P.session,
241
298
  },
242
299
  httpOnly: ["session"],
@@ -254,10 +311,34 @@ export const MCP_TOOL_DEFS = [
254
311
  httpOnly: ["session"],
255
312
  stdioExtra: { path: { t: "string", d: "Local file path; use instead of data" } },
256
313
  },
314
+ {
315
+ name: "system",
316
+ description: "Read or change the project's system (sheet, tokens, scales, palettes, project knobs), which every render wears at once. No arguments reads it; each argument replaces its part, tokens, scales and palettes upsert. Shapes: topic system.",
317
+ params: {
318
+ project: P.project,
319
+ sheet: { t: "string", d: "CSS; no @import" },
320
+ classes: { t: "named", d: "[{name, note}] or names" },
321
+ fonts: { t: "objects", d: "[{family, href?}]" },
322
+ tokens: { t: "objects", d: "[{name, type, value, note?}]" },
323
+ scales: {
324
+ t: "objects",
325
+ d: "[{id, family: type|space, prefix, steps, zero, base, ratio, fluid?}]",
326
+ },
327
+ roles: { t: "named", d: "[{name, note}] or names" },
328
+ palettes: { t: "objects", d: "[{id, label, note, light, dark}]" },
329
+ pairs: { t: "pairs", d: "[[fg, bg, min?]]" },
330
+ as: { t: "object" },
331
+ knobs: { t: "object", d: "Project knobs" },
332
+ remove: { t: "object", d: "{tokens?, palettes?, scales?}" },
333
+ restore: { t: "integer", d: "A revision, alone" },
334
+ session: P.session,
335
+ },
336
+ httpOnly: ["session"],
337
+ },
257
338
  {
258
339
  name: "guide",
259
340
  description: "Fetch the brief: the loop, parts, asks and knobs, feedback, the html contract, and this " +
260
- "project's palette, kit and icons. Read it before the first publish. Pass topic for one " +
341
+ "project's system, kit and icons. Read it before the first publish. Pass topic for one " +
261
342
  `reference section (${GUIDE_TOPICS.join(", ")}).`,
262
343
  params: {
263
344
  project: P.project,
@@ -294,14 +375,14 @@ const bag = z.record(z.string(), z.unknown());
294
375
  const variantRef = o({ state: nullStr, variant: str });
295
376
  const inUseRef = o({ state: nullStr, variant: str, version: num });
296
377
  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 })) });
378
+ const flowSchema = o({ name: str, steps: z.array(o({ design: str, state: nullStr })) });
298
379
  const feedbackSchema = o({
299
- mock: nullStr,
380
+ design: nullStr,
300
381
  reply: o({
301
382
  asks: z.array(o({
302
383
  ask: str,
303
384
  chosen: z.array(o({ label: str, other: z.literal(true).optional() })),
304
- note: str.optional(),
385
+ description: str.optional(),
305
386
  })),
306
387
  borrowed: bag.describe("Part → the variant to take it from"),
307
388
  tuned: bag,
@@ -309,39 +390,47 @@ const feedbackSchema = o({
309
390
  reactions: strs.optional().describe('One-tap reactions, e.g. 👍 part "hero" (variant B)'),
310
391
  verdict: o({ kind: z.enum(["use", "revise"]), state: nullStr, variant: str })
311
392
  .optional()
312
- .describe("Use this or Revise on one variant"),
393
+ .describe("Use this or New version on one variant"),
394
+ more: o({
395
+ ask: str,
396
+ text: str,
397
+ existing: strs,
398
+ note: str.optional(),
399
+ answered: z.array(o({ ask: str, text: str, chosen: strs, comment: str.optional() })),
400
+ })
401
+ .optional()
402
+ .describe("The user wants more answers to this question: ask it again, same id, with them"),
313
403
  })
314
404
  .nullable()
315
405
  .describe("The user's Send; null if only messages"),
316
406
  messages: z.array(o({ seq: num, text: str })).describe("What the user wrote in the thread"),
317
407
  inUse: z.array(inUseRef).describe("In use, each at the version the user put in use"),
318
408
  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() })
409
+ edited: o({
410
+ kind: str.optional(),
411
+ area: nullStr.optional(),
412
+ notes: nullStr.optional(),
413
+ })
328
414
  .optional()
329
- .describe("The user moved the mock from Home: its kind or area now"),
415
+ .describe("The user moved the design from Home (its kind or area now) or edited its notes"),
330
416
  }).meta({ id: "Feedback" });
331
417
  // Typed once, on feedback: repeating it on every write would cost more than
332
418
  // the rest of the write's output schema.
333
419
  const feedbackRide = z.array(bag).describe("Feedback batches as the feedback tool returns");
334
420
  const pendingSchema = o({
335
- mock: str,
336
- closed: z.literal(true).optional(),
421
+ design: str,
422
+ archived: z.literal(true).optional(),
337
423
  viewerOpen: z.boolean(),
338
424
  draft: o({ answered: num, of: num, comments: num, touchedAt: str }).nullable(),
339
425
  }).meta({ id: "Pending" });
340
426
  const writeOutput = {
341
- post: o({ state: nullStr, variant: str, version: num }),
427
+ post: o({ state: nullStr, variant: str, version: num })
428
+ .optional()
429
+ .describe("Absent when planned: nothing is drawn yet"),
430
+ planned: z.boolean().optional(),
342
431
  sessionId: str,
343
432
  url: str.describe("Viewer link for the user"),
344
- parts: partsByState,
433
+ parts: partsByState.optional(),
345
434
  partChanges: o({ vanished: strs, renamed: z.array(o({ from: str, to: str })) }).optional(),
346
435
  nudges: strs.optional(),
347
436
  suggestedAsk: bag.optional().describe("Send with ask when a nudge names it"),
@@ -378,10 +467,33 @@ const OUTPUT_SCHEMAS = {
378
467
  feedback: feedbackRide,
379
468
  },
380
469
  feedback: {
381
- feedback: z.array(feedbackSchema).describe("One batch per mock; empty when nothing is new"),
470
+ feedback: z.array(feedbackSchema).describe("One batch per design; empty when nothing is new"),
382
471
  pending: z.array(pendingSchema),
383
472
  },
384
473
  say: { feedback: feedbackRide },
474
+ move: {
475
+ variants: z.array(o({ state: str.nullable(), variant: str, status: str })),
476
+ versions: z
477
+ .array(o({ state: str.nullable(), variant: str, version: num }))
478
+ .optional()
479
+ .describe("With hideOlder or deleteOlder: what was hidden or deleted"),
480
+ skipped: z.array(o({ state: str.nullable().optional(), variant: str, version: num.optional(), why: str })),
481
+ to: o({ design: str, title: str, state: str.nullable() }).optional(),
482
+ saved: z
483
+ .array(o({ state: str.nullable(), variant: str, already: z.boolean() }))
484
+ .optional()
485
+ .describe("What each is called there"),
486
+ url: str,
487
+ feedback: feedbackRide,
488
+ },
489
+ system: {
490
+ rev: num,
491
+ changed: strs.optional().describe("What this write changed, as the Thread says it"),
492
+ checks: strs,
493
+ nudges: strs.optional(),
494
+ url: str,
495
+ feedback: feedbackRide.optional(),
496
+ },
385
497
  edit: {
386
498
  renamed: o({ from: str, to: str }).optional(),
387
499
  areaOrder: strs.optional(),
@@ -390,7 +502,7 @@ const OUTPUT_SCHEMAS = {
390
502
  feedback: feedbackRide,
391
503
  },
392
504
  read: {
393
- mocks: z.array(o({ slug: str, states: strs, variants: num, open: num })).optional(),
505
+ designs: z.array(o({ slug: str, states: strs, variants: num, open: num })).optional(),
394
506
  states: strs.optional(),
395
507
  asks: z.array(o({ id: str, text: str })).optional(),
396
508
  variants: z
@@ -411,13 +523,31 @@ const OUTPUT_SCHEMAS = {
411
523
  .optional()
412
524
  .describe("Per state, the version the user put in use; export and embeds resolve to it"),
413
525
  knobs: bag.optional(),
526
+ system: str
527
+ .optional()
528
+ .describe("Without design: what the project's renders wear (rev, palettes, counts, failing checks)"),
414
529
  settled: bag.optional().describe("Every knob value the user has sent, later replies winning"),
415
530
  tree: z.array(bag).optional(),
416
531
  flows: z.array(flowSchema).optional(),
417
- pending: z.union([z.array(pendingSchema), pendingSchema]),
532
+ decisionList: o({
533
+ total: num,
534
+ lines: z.array(o({
535
+ design: str,
536
+ text: str,
537
+ here: z.boolean().optional().describe("From the design read"),
538
+ system: z.boolean().optional().describe("The project's own, on every design"),
539
+ edited: z.boolean().optional(),
540
+ archived: z.boolean().optional(),
541
+ })),
542
+ more: str.optional(),
543
+ }).optional(),
544
+ total: num.optional(),
545
+ lines: z.array(bag).optional(),
546
+ pending: z.union([z.array(pendingSchema), pendingSchema]).optional(),
418
547
  },
419
548
  export: {
420
- states: z.array(o({
549
+ states: z
550
+ .array(o({
421
551
  state: nullStr,
422
552
  variant: str,
423
553
  version: num,
@@ -425,9 +555,17 @@ const OUTPUT_SCHEMAS = {
425
555
  html: str.describe("With fills: only the chosen ones"),
426
556
  allFills: str.optional().describe("With fills: the html with every fill"),
427
557
  markdown: str,
428
- })),
429
- settled: bag,
430
- reply: bag.nullable(),
558
+ }))
559
+ .optional(),
560
+ settled: bag.optional(),
561
+ reply: bag.nullable().optional(),
562
+ sheet: str.optional().describe("Without design: the project's sheet"),
563
+ css: str
564
+ .optional()
565
+ .describe("Without design: tokens as CSS, the default palette on :root, kept ones by [data-palette]"),
566
+ tokens: bag.optional().describe("Without design: the same as data"),
567
+ knobs: bag.optional().describe("Without design: the project knobs' values"),
568
+ components: z.array(bag).optional(),
431
569
  },
432
570
  };
433
571
  // The core loop, loaded up front by harnesses that defer the rest of the
@@ -443,9 +581,11 @@ function shapeFor(tool, transport) {
443
581
  shape[key] =
444
582
  transport === "stdio" && key === "html" && tool.name === "publish"
445
583
  ? z.string().optional().describe(`${field.html}; or a file path`)
446
- : transport === "stdio" && key === "poster" && tool.name === "publish"
447
- ? z.string().optional().describe(`${p.d}; or an image file path`)
448
- : zodParam(p);
584
+ : transport === "stdio" && key === "sheet" && tool.name === "system"
585
+ ? z.string().optional().describe(`${p.d}; or a file path`)
586
+ : transport === "stdio" && key === "poster" && tool.name === "publish"
587
+ ? z.string().optional().describe(`${p.d}; or an image file path`)
588
+ : zodParam(p);
449
589
  }
450
590
  return shape;
451
591
  }