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
@@ -1,7 +1,8 @@
1
1
  // Response shapes shared by every tier (REST, both MCP transports, the CLI), so
2
2
  // one mock reads the same however an agent asks for it.
3
+ import { slotKnobs, slotsInSurfaces } from "./fills.js";
3
4
  import { mergeParts, partsInSurfaces } from "./parts.js";
4
- import { isSandboxedSurfaceKind, draftedCount, openCount, SURFACE_CONTENT_FIELDS, } from "./types.js";
5
+ import { draftedCount, inUseVersion, isSandboxedSurfaceKind, isLive, openCount, SURFACE_CONTENT_FIELDS, } from "./types.js";
5
6
  export const surfaceRef = (surface, index) => ({
6
7
  id: surface.id,
7
8
  kind: surface.kind,
@@ -48,8 +49,21 @@ export const variantView = (post, opts = {}) => ({
48
49
  ...(post.from === undefined ? {} : { from: post.from }),
49
50
  ...(post.prompt ? { prompt: post.prompt } : {}),
50
51
  ...(post.author === undefined ? {} : { author: post.author }),
51
- ...(post.knobs ? { knobs: post.knobs } : {}),
52
- ...(post.slots.length ? { slots: post.slots } : {}),
52
+ // A slot is a select knob on its part (fills.ts); declared knobs win.
53
+ ...(slotsInSurfaces(post.surfaces).length || post.knobs
54
+ ? { knobs: { ...slotKnobs(slotsInSurfaces(post.surfaces)), ...post.knobs } }
55
+ : {}),
56
+ ...(slotsInSurfaces(post.surfaces).length ? { slots: slotsInSurfaces(post.surfaces) } : {}),
57
+ ...(post.note ? { note: post.note } : {}),
58
+ // Embedded components as they render now (server/embeds.ts); `publishedWith`
59
+ // is what this version rendered with when it was published.
60
+ ...(opts.embeds?.get(post.id)
61
+ ? { embeds: opts.embeds.get(post.id).list, embedsKey: opts.embeds.get(post.id).key }
62
+ : {}),
63
+ ...(post.embeds.length ? { publishedWith: post.embeds } : {}),
64
+ ...(post.forkedFrom ? { forkedFrom: post.forkedFrom } : {}),
65
+ ...(post.starred ? { starred: true } : {}),
66
+ ...(post.acceptedVersion === undefined ? {} : { acceptedVersion: post.acceptedVersion }),
53
67
  // The part names this variant's own markup marks, so the viewer can tell
54
68
  // which looks render a part (Mix) without the html bodies.
55
69
  parts: partsInSurfaces(post.surfaces).map((p) => p.name),
@@ -67,17 +81,23 @@ export const variantView = (post, opts = {}) => ({
67
81
  ...(post.author === undefined ? {} : { author: post.author }),
68
82
  }),
69
83
  ...[...post.history].sort((a, b) => b.version - a.version).map(historyMetaView),
70
- ],
84
+ ].map((row) => post.hiddenVersions?.includes(row.version) ? { ...row, hidden: true } : row),
71
85
  }
72
86
  : {}),
73
87
  });
74
88
  const stateOrder = (mock) => (mock.states.length ? mock.states : [null]);
89
+ // What the user put in use, per state, in the mock's order; a state with
90
+ // nothing accepted is absent. Export and embeds resolve to exactly these.
91
+ export const inUseByState = (mock, posts) => stateOrder(mock).flatMap((state) => {
92
+ const p = posts.find((x) => x.state === state && x.status === "accepted");
93
+ return p ? [{ state, variant: p.variant, version: inUseVersion(p) }] : [];
94
+ });
75
95
  // The parts the agent marked, per state, across the variants still in play.
76
96
  export function partsByState(mock, posts) {
77
97
  return stateOrder(mock).map((state) => ({
78
98
  state,
79
99
  parts: mergeParts(posts
80
- .filter((p) => p.state === state && p.status !== "archived")
100
+ .filter((p) => p.state === state && isLive(p.status))
81
101
  .map((p) => partsInSurfaces(p.surfaces))),
82
102
  }));
83
103
  }
@@ -92,7 +112,7 @@ function thumbnail(mock, posts) {
92
112
  if (!pick)
93
113
  return null;
94
114
  const surface = pick.surfaces.findIndex((s) => isSandboxedSurfaceKind(s.kind));
95
- return { postId: pick.id, surface: Math.max(surface, 0), version: pick.version };
115
+ return { postId: pick.id, surface: Math.max(surface, 0), version: inUseVersion(pick) };
96
116
  }
97
117
  export const mockSummaryView = (mock, posts) => {
98
118
  const drafted = draftedCount(mock, posts);
@@ -109,6 +129,7 @@ export const mockSummaryView = (mock, posts) => {
109
129
  // Only once the user has started one, so a list with no drafts costs nothing.
110
130
  ...(drafted === null ? {} : { drafted }),
111
131
  sessionId: mock.sessionId,
132
+ resolvedAt: mock.resolvedAt,
112
133
  createdAt: mock.createdAt,
113
134
  updatedAt: mock.updatedAt,
114
135
  thumbnail: thumbnail(mock, posts),
@@ -126,15 +147,52 @@ export const mockDetailView = (mock, posts, opts = {}) => ({
126
147
  asks: mock.asks,
127
148
  open: openCount(mock, posts),
128
149
  knobs: mock.knobs,
150
+ widths: mock.widths,
129
151
  sessionId: mock.sessionId,
152
+ resolvedAt: mock.resolvedAt,
130
153
  createdAt: mock.createdAt,
131
154
  updatedAt: mock.updatedAt,
132
155
  variants: posts.map((p) => variantView(p, opts)),
156
+ inUse: inUseByState(mock, posts),
133
157
  parts: partsByState(mock, posts),
134
- // The knob values of the latest reply — what the user last sent, not drafts.
135
- tuned: opts.tuned ?? {},
158
+ // Every knob value the user has sent (answers' sets and tuning, later replies
159
+ // winning), never drafts. Later questions render on top of it.
160
+ settled: opts.settled ?? {},
136
161
  });
137
162
  export const sessionRowView = (session, postCount) => ({
138
163
  ...session,
139
164
  postCount,
140
165
  });
166
+ // One mock as a node of the project tree (GET /api/projects/:name/tree): its
167
+ // variants per state with status and lineage, and the mocks it embeds (`uses`);
168
+ // `usedIn` is filled in once every node is known.
169
+ export const treeNodeView = (mock, posts, extra) => ({
170
+ id: mock.id,
171
+ slug: mock.slug,
172
+ title: mock.title,
173
+ kind: mock.kind,
174
+ open: openCount(mock, posts),
175
+ states: mock.states.length ? mock.states : [null],
176
+ widths: mock.widths,
177
+ createdAt: mock.createdAt,
178
+ updatedAt: mock.updatedAt,
179
+ resolvedAt: mock.resolvedAt,
180
+ settled: extra.settled,
181
+ uses: extra.uses,
182
+ usedIn: [],
183
+ inUse: inUseByState(mock, posts),
184
+ variants: posts.map((p) => ({
185
+ postId: p.id,
186
+ state: p.state,
187
+ variant: p.variant,
188
+ status: p.status,
189
+ version: p.version,
190
+ updatedAt: p.updatedAt,
191
+ surface: p.surfaces.findIndex((x) => isSandboxedSurfaceKind(x.kind)),
192
+ ...(p.note ? { note: p.note } : {}),
193
+ ...(p.forkedFrom ? { forkedFrom: p.forkedFrom } : {}),
194
+ ...(p.starred ? { starred: true } : {}),
195
+ ...(p.acceptedVersion === undefined ? {} : { acceptedVersion: p.acceptedVersion }),
196
+ ...(extra.embeds.get(p.id) ? { embedsKey: extra.embeds.get(p.id).key } : {}),
197
+ })),
198
+ });
@@ -21,6 +21,7 @@ export interface AppOptions {
21
21
  screenshots?: boolean;
22
22
  version?: string;
23
23
  upgradeCommand?: string;
24
+ renderRev?: string;
24
25
  fetchLatestRelease?: () => Promise<LatestRelease | null>;
25
26
  onEvent?: (event: FeedEvent) => void;
26
27
  maxHoldConnections?: number;
@@ -52,4 +53,4 @@ export interface FlowContext {
52
53
  request?: Request;
53
54
  signal?: AbortSignal;
54
55
  }
55
- export declare function createApp({ store, viewerHtml, setupText, topics, authenticate, authToken, basePath, publicRead, screenshots, version, upgradeCommand, fetchLatestRelease, onEvent, maxHoldConnections, executor, runLimits, log, }: AppOptions): Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
56
+ export declare function createApp({ store, viewerHtml, setupText, topics, authenticate, authToken, basePath, publicRead, screenshots, version, upgradeCommand, renderRev, fetchLatestRelease, onEvent, maxHoldConnections, executor, runLimits, log, }: AppOptions): Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;