mockpit 0.0.0-stage → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +22 -0
- package/README.md +232 -2
- package/bin/demoData.js +132 -0
- package/bin/initDesign.js +846 -0
- package/bin/mockpit.js +1830 -0
- package/bin/serveUrl.d.ts +1 -0
- package/bin/serveUrl.js +7 -0
- package/dist/mcp/server.d.ts +2 -0
- package/dist/mcp/server.js +230 -0
- package/dist/server/apiViews.d.ts +329 -0
- package/dist/server/apiViews.js +135 -0
- package/dist/server/app.d.ts +53 -0
- package/dist/server/app.js +3112 -0
- package/dist/server/base64.d.ts +1 -0
- package/dist/server/base64.js +16 -0
- package/dist/server/cdn.d.ts +6 -0
- package/dist/server/cdn.js +33 -0
- package/dist/server/codeRunner.d.ts +5 -0
- package/dist/server/codeRunner.js +89 -0
- package/dist/server/codeWorker.d.ts +1 -0
- package/dist/server/codeWorker.js +196 -0
- package/dist/server/designGuide.d.ts +16 -0
- package/dist/server/designGuide.js +311 -0
- package/dist/server/events.d.ts +53 -0
- package/dist/server/events.js +14 -0
- package/dist/server/feedbackBatch.d.ts +43 -0
- package/dist/server/feedbackBatch.js +98 -0
- package/dist/server/icons.d.ts +50 -0
- package/dist/server/icons.js +225 -0
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.js +64 -0
- package/dist/server/kits.d.ts +36 -0
- package/dist/server/kits.js +279 -0
- package/dist/server/knobs.d.ts +15 -0
- package/dist/server/knobs.js +333 -0
- package/dist/server/mcpHttp.d.ts +53 -0
- package/dist/server/mcpHttp.js +143 -0
- package/dist/server/mcpSpec.d.ts +191 -0
- package/dist/server/mcpSpec.js +402 -0
- package/dist/server/parts.d.ts +31 -0
- package/dist/server/parts.js +338 -0
- package/dist/server/postMarkdown.d.ts +10 -0
- package/dist/server/postMarkdown.js +271 -0
- package/dist/server/postSurfaces.d.ts +40 -0
- package/dist/server/postSurfaces.js +407 -0
- package/dist/server/public.d.ts +5 -0
- package/dist/server/public.js +5 -0
- package/dist/server/push.d.ts +45 -0
- package/dist/server/push.js +234 -0
- package/dist/server/richRender.d.ts +15 -0
- package/dist/server/richRender.js +392 -0
- package/dist/server/run.d.ts +82 -0
- package/dist/server/run.js +290 -0
- package/dist/server/runApi.d.ts +6 -0
- package/dist/server/runApi.js +82 -0
- package/dist/server/slots.d.ts +14 -0
- package/dist/server/slots.js +71 -0
- package/dist/server/sqlStore.d.ts +119 -0
- package/dist/server/sqlStore.js +954 -0
- package/dist/server/sqliteStorage.d.ts +2 -0
- package/dist/server/sqliteStorage.js +90 -0
- package/dist/server/surfacePage.d.ts +48 -0
- package/dist/server/surfacePage.js +1099 -0
- package/dist/server/themes.d.ts +48 -0
- package/dist/server/themes.js +305 -0
- package/dist/server/types.d.ts +599 -0
- package/dist/server/types.js +299 -0
- package/dist/workers/public.d.ts +1 -0
- package/dist/workers/public.js +3 -0
- package/extensions/mockpit.js +703 -0
- package/guide/AGENT_SETUP.md +23 -0
- package/guide/topics/asks.md +87 -0
- package/guide/topics/feedback.md +127 -0
- package/guide/topics/html.md +175 -0
- package/guide/topics/http.md +76 -0
- package/guide/topics/knobs.md +72 -0
- package/guide/topics/scripts.md +129 -0
- package/guide/topics/surfaces.md +100 -0
- package/package.json +165 -4
- package/skills/launch-video/SKILL.md +159 -0
- package/skills/mockpit/SKILL.md +40 -0
- package/viewer/dist/index.html +1922 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function serveUrl(host: string | undefined, port: string): string;
|
package/bin/serveUrl.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// A wildcard listener is reachable locally, but its unspecified address is not
|
|
2
|
+
// a useful browser destination. Concrete bind addresses should be opened as-is.
|
|
3
|
+
export function serveUrl(host, port) {
|
|
4
|
+
const address = !host || host === "0.0.0.0" || host === "::" ? "localhost" : host;
|
|
5
|
+
const authority = address.includes(":") ? `[${address}]` : address;
|
|
6
|
+
return `http://${authority}:${port}`;
|
|
7
|
+
}
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { execFileSync } from "node:child_process";
|
|
3
|
+
import { readFileSync, statSync } from "node:fs";
|
|
4
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
|
+
import { ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
7
|
+
import { MCP_INSTRUCTIONS, MCP_SERVER_INFO, runToolResult, STDIO_MCP_CATALOG, STDIO_MCP_TOOLS, STDIO_RUN_CATALOG, STDIO_RUN_TOOLS, toolResult, } from "../server/mcpSpec.js";
|
|
8
|
+
import { RUN_INSTRUCTIONS } from "../server/runApi.js";
|
|
9
|
+
// Point at a deployed instance later by setting MOCKPIT_URL.
|
|
10
|
+
const API = process.env.MOCKPIT_URL ?? "http://localhost:8228";
|
|
11
|
+
const TOKEN = process.env.MOCKPIT_TOKEN;
|
|
12
|
+
const AGENT = process.env.MOCKPIT_AGENT ?? "claude-code";
|
|
13
|
+
// "code" serves the codemode catalog: one `run` tool instead of the mock tools.
|
|
14
|
+
const CODE_MODE = process.env.MOCKPIT_MCP_MODE === "code";
|
|
15
|
+
async function api(path, init = {}) {
|
|
16
|
+
const headers = { "content-type": "application/json" };
|
|
17
|
+
if (TOKEN)
|
|
18
|
+
headers.authorization = `Bearer ${TOKEN}`;
|
|
19
|
+
let res;
|
|
20
|
+
try {
|
|
21
|
+
res = await fetch(`${API}${path}`, { ...init, headers });
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
throw new Error(`mockpit server not reachable at ${API} — ask the user to start it with "mockpit serve" or "npm run dev"`);
|
|
25
|
+
}
|
|
26
|
+
const text = await res.text();
|
|
27
|
+
if (!res.ok)
|
|
28
|
+
throw new Error(`${res.status} ${res.statusText}: ${text}`);
|
|
29
|
+
return text;
|
|
30
|
+
}
|
|
31
|
+
// Stdio runs on the agent's machine, so a value may name a file: markup and
|
|
32
|
+
// asset bytes never have to travel through the model's context.
|
|
33
|
+
function readMaybeFile(value) {
|
|
34
|
+
if (value.includes("\n") || value.length > 512)
|
|
35
|
+
return value;
|
|
36
|
+
try {
|
|
37
|
+
if (statSync(value).isFile())
|
|
38
|
+
return readFileSync(value, "utf8");
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
// not a path — it is the content itself
|
|
42
|
+
}
|
|
43
|
+
return value;
|
|
44
|
+
}
|
|
45
|
+
// Part values may be file paths too, like html; anything not a string map
|
|
46
|
+
// goes through untouched so the server reports what is wrong with it.
|
|
47
|
+
function readPartFiles(parts) {
|
|
48
|
+
if (!parts || typeof parts !== "object" || Array.isArray(parts))
|
|
49
|
+
return parts;
|
|
50
|
+
return Object.fromEntries(Object.entries(parts).map(([k, v]) => [k, typeof v === "string" ? readMaybeFile(v) : v]));
|
|
51
|
+
}
|
|
52
|
+
// The project this repo is: explicit, environment, git remote, then directory
|
|
53
|
+
// name. Same order as the CLI, so both tiers land in the same project.
|
|
54
|
+
function resolveProject(explicit) {
|
|
55
|
+
if (explicit)
|
|
56
|
+
return explicit;
|
|
57
|
+
if (process.env.MOCKPIT_PROJECT)
|
|
58
|
+
return process.env.MOCKPIT_PROJECT;
|
|
59
|
+
try {
|
|
60
|
+
const url = execFileSync("git", ["remote", "get-url", "origin"], {
|
|
61
|
+
encoding: "utf8",
|
|
62
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
63
|
+
}).trim();
|
|
64
|
+
const m = url.match(/[:/]([^/:]+)\/([^/]+?)(?:\.git)?\/?$/);
|
|
65
|
+
if (m)
|
|
66
|
+
return `${m[1]}/${m[2]}`;
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
// not a git checkout
|
|
70
|
+
}
|
|
71
|
+
return process.cwd().split(/[\\/]/).filter(Boolean).pop() ?? "workspace";
|
|
72
|
+
}
|
|
73
|
+
const ASSET_CONTENT_TYPES = {
|
|
74
|
+
png: "image/png",
|
|
75
|
+
jpg: "image/jpeg",
|
|
76
|
+
jpeg: "image/jpeg",
|
|
77
|
+
gif: "image/gif",
|
|
78
|
+
webp: "image/webp",
|
|
79
|
+
avif: "image/avif",
|
|
80
|
+
svg: "image/svg+xml",
|
|
81
|
+
json: "application/json",
|
|
82
|
+
txt: "text/plain",
|
|
83
|
+
csv: "text/csv",
|
|
84
|
+
pdf: "application/pdf",
|
|
85
|
+
};
|
|
86
|
+
const contentTypeForPath = (file) => ASSET_CONTENT_TYPES[file.split(".").pop()?.toLowerCase() ?? ""] ?? "application/octet-stream";
|
|
87
|
+
const enc = encodeURIComponent;
|
|
88
|
+
const json = async (path, init) => JSON.parse(await api(path, init));
|
|
89
|
+
const post = (path, body, method = "POST") => json(path, { method, body: JSON.stringify(body) });
|
|
90
|
+
const query = (params) => {
|
|
91
|
+
const q = new URLSearchParams();
|
|
92
|
+
for (const [k, v] of Object.entries(params)) {
|
|
93
|
+
if (v !== undefined && v !== null && v !== false)
|
|
94
|
+
q.set(k, v === true ? "1" : String(v));
|
|
95
|
+
}
|
|
96
|
+
const s = q.toString();
|
|
97
|
+
return s ? `?${s}` : "";
|
|
98
|
+
};
|
|
99
|
+
// One MCP server process lives as long as one agent conversation, so a
|
|
100
|
+
// lazily-created session shared across tool calls maps cleanly onto it.
|
|
101
|
+
let sessionId = process.env.MOCKPIT_SESSION ?? null;
|
|
102
|
+
// A resumed Claude Code conversation spawns a new MCP process; its session id
|
|
103
|
+
// survives the resume, so keying on it hands back the same mockpit session.
|
|
104
|
+
const harnessKey = process.env.CLAUDE_CODE_SESSION_ID
|
|
105
|
+
? `claude-code:${process.env.CLAUDE_CODE_SESSION_ID}`
|
|
106
|
+
: undefined;
|
|
107
|
+
// `title` is used only when this call creates the session — once one exists
|
|
108
|
+
// (here or in the viewer, where the user can rename it) it is never retitled.
|
|
109
|
+
async function ensureSession(title) {
|
|
110
|
+
if (sessionId)
|
|
111
|
+
return sessionId;
|
|
112
|
+
const session = JSON.parse(await api("/api/sessions", {
|
|
113
|
+
method: "POST",
|
|
114
|
+
body: JSON.stringify({
|
|
115
|
+
agent: AGENT,
|
|
116
|
+
cwd: process.cwd(),
|
|
117
|
+
title,
|
|
118
|
+
project: resolveProject(),
|
|
119
|
+
key: harnessKey,
|
|
120
|
+
}),
|
|
121
|
+
}));
|
|
122
|
+
sessionId = session.id;
|
|
123
|
+
return sessionId;
|
|
124
|
+
}
|
|
125
|
+
// Every tool is a pass-through to the REST route the CLI uses, mapped the way
|
|
126
|
+
// server/mcpHttp.ts maps HTTP MCP: same request, same response, so the tiers
|
|
127
|
+
// cannot drift. Only the session (one per conversation), the project (this
|
|
128
|
+
// repo) and file paths are filled in here.
|
|
129
|
+
const handlers = {
|
|
130
|
+
async publish(args) {
|
|
131
|
+
const session = await ensureSession(args.sessionTitle);
|
|
132
|
+
const html = typeof args.html === "string" ? readMaybeFile(args.html) : undefined;
|
|
133
|
+
return post("/api/mocks", {
|
|
134
|
+
...args,
|
|
135
|
+
html,
|
|
136
|
+
parts: readPartFiles(args.parts),
|
|
137
|
+
session,
|
|
138
|
+
agent: AGENT,
|
|
139
|
+
project: resolveProject(args.project),
|
|
140
|
+
});
|
|
141
|
+
},
|
|
142
|
+
async ask(args) {
|
|
143
|
+
const session = await ensureSession();
|
|
144
|
+
return post(`/api/mocks/${enc(args.mock)}/asks`, {
|
|
145
|
+
...args,
|
|
146
|
+
session,
|
|
147
|
+
project: resolveProject(args.project),
|
|
148
|
+
});
|
|
149
|
+
},
|
|
150
|
+
read: (args) => json(args.mock === undefined
|
|
151
|
+
? `/api/mocks${query({ project: resolveProject(args.project) })}`
|
|
152
|
+
: `/api/mocks/${enc(args.mock)}${query({
|
|
153
|
+
project: resolveProject(args.project),
|
|
154
|
+
body: args.body,
|
|
155
|
+
history: args.history,
|
|
156
|
+
})}`),
|
|
157
|
+
// Never waits: the server reads from the session's cursor, shared with
|
|
158
|
+
// piggyback and `mockpit watch`, so each Send is delivered exactly once.
|
|
159
|
+
async feedback(args) {
|
|
160
|
+
const session = await ensureSession();
|
|
161
|
+
return json(`/api/feedback${query({ session, project: resolveProject(args.project) })}`);
|
|
162
|
+
},
|
|
163
|
+
async say(args) {
|
|
164
|
+
const session = await ensureSession();
|
|
165
|
+
return post(`/api/mocks/${enc(args.mock)}/say`, {
|
|
166
|
+
state: args.state,
|
|
167
|
+
variant: args.variant,
|
|
168
|
+
project: resolveProject(args.project),
|
|
169
|
+
session,
|
|
170
|
+
message: args.message,
|
|
171
|
+
});
|
|
172
|
+
},
|
|
173
|
+
export: (args) => json(`/api/mocks/${enc(args.mock)}/export${query({
|
|
174
|
+
project: resolveProject(args.project),
|
|
175
|
+
state: args.state,
|
|
176
|
+
variant: args.variant,
|
|
177
|
+
})}`),
|
|
178
|
+
async upload({ path, data, contentType, filename, kind }) {
|
|
179
|
+
const session = await ensureSession();
|
|
180
|
+
// Stdio shares the agent's filesystem, so a path beats base64 in context.
|
|
181
|
+
return post("/api/assets", {
|
|
182
|
+
data: path ? readFileSync(path, "base64") : data,
|
|
183
|
+
contentType: contentType ?? (path ? contentTypeForPath(path) : "application/octet-stream"),
|
|
184
|
+
filename: filename ?? (path ? path.split(/[\\/]/).pop() : undefined),
|
|
185
|
+
kind,
|
|
186
|
+
session,
|
|
187
|
+
});
|
|
188
|
+
},
|
|
189
|
+
// The brief renders this project's real palette, kit, and icons, so the
|
|
190
|
+
// agent never restates them; a topic is the same text on every tier.
|
|
191
|
+
guide: (args) => api(`/agent-howto${query(args.topic === undefined
|
|
192
|
+
? { project: resolveProject(args.project) }
|
|
193
|
+
: { topic: args.topic })}`),
|
|
194
|
+
};
|
|
195
|
+
// The script travels as a file path when it can, so it is never JSON-escaped
|
|
196
|
+
// into the model's tool call.
|
|
197
|
+
async function run(args) {
|
|
198
|
+
const code = typeof args.path === "string" && args.path
|
|
199
|
+
? readFileSync(args.path, "utf8")
|
|
200
|
+
: typeof args.code === "string"
|
|
201
|
+
? readMaybeFile(args.code)
|
|
202
|
+
: "";
|
|
203
|
+
if (!code.trim())
|
|
204
|
+
throw new Error("run needs code, or path to a .js file");
|
|
205
|
+
const session = await ensureSession();
|
|
206
|
+
return json("/api/run", {
|
|
207
|
+
method: "POST",
|
|
208
|
+
body: JSON.stringify({ code, session, project: resolveProject(args.project), agent: AGENT }),
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
const server = new McpServer(MCP_SERVER_INFO, {
|
|
212
|
+
instructions: CODE_MODE ? RUN_INSTRUCTIONS : MCP_INSTRUCTIONS,
|
|
213
|
+
});
|
|
214
|
+
if (CODE_MODE) {
|
|
215
|
+
const [{ name, ...config }] = STDIO_RUN_TOOLS;
|
|
216
|
+
server.registerTool(name, config, async (args) => runToolResult(await run(args)));
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
for (const tool of STDIO_MCP_TOOLS) {
|
|
220
|
+
const handler = handlers[tool.name];
|
|
221
|
+
const { name, ...config } = tool;
|
|
222
|
+
server.registerTool(name, config, async (args) => toolResult(name, await handler(args)));
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
// Replaces the SDK's own listing (registered above), so stdio advertises the
|
|
226
|
+
// same compact 2020-12 schemas as HTTP; calls still validate against zod.
|
|
227
|
+
server.server.setRequestHandler(ListToolsRequestSchema, () => ({
|
|
228
|
+
tools: CODE_MODE ? STDIO_RUN_CATALOG : STDIO_MCP_CATALOG,
|
|
229
|
+
}));
|
|
230
|
+
await server.connect(new StdioServerTransport());
|
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
import { type PartInfo } from "./parts.ts";
|
|
2
|
+
import { type Mock, type Post, type PostVersion, type Session, type Surface } from "./types.ts";
|
|
3
|
+
export declare const surfaceRef: (surface: Pick<Surface, "id" | "kind">, index: number) => {
|
|
4
|
+
id: string | undefined;
|
|
5
|
+
kind: "html" | "diff" | "image" | "markdown" | "terminal" | "mermaid" | "json" | "code";
|
|
6
|
+
index: number;
|
|
7
|
+
};
|
|
8
|
+
export declare const fullSurfaceView: (surface: Surface, index: number) => {
|
|
9
|
+
index: number;
|
|
10
|
+
kind: "html";
|
|
11
|
+
html: string;
|
|
12
|
+
kits?: string[];
|
|
13
|
+
id?: string;
|
|
14
|
+
} | {
|
|
15
|
+
index: number;
|
|
16
|
+
kind: "diff";
|
|
17
|
+
patch?: string;
|
|
18
|
+
files?: import("./types.ts").DiffFile[];
|
|
19
|
+
layout?: "unified" | "split";
|
|
20
|
+
id?: string;
|
|
21
|
+
} | {
|
|
22
|
+
index: number;
|
|
23
|
+
kind: "image";
|
|
24
|
+
assetId: string;
|
|
25
|
+
alt?: string;
|
|
26
|
+
caption?: string;
|
|
27
|
+
id?: string;
|
|
28
|
+
} | {
|
|
29
|
+
index: number;
|
|
30
|
+
kind: "markdown";
|
|
31
|
+
markdown: string;
|
|
32
|
+
id?: string;
|
|
33
|
+
} | {
|
|
34
|
+
index: number;
|
|
35
|
+
kind: "terminal";
|
|
36
|
+
text: string;
|
|
37
|
+
cols?: number;
|
|
38
|
+
title?: string;
|
|
39
|
+
id?: string;
|
|
40
|
+
} | {
|
|
41
|
+
index: number;
|
|
42
|
+
kind: "mermaid";
|
|
43
|
+
mermaid: string;
|
|
44
|
+
id?: string;
|
|
45
|
+
} | {
|
|
46
|
+
index: number;
|
|
47
|
+
kind: "json";
|
|
48
|
+
data: unknown;
|
|
49
|
+
id?: string;
|
|
50
|
+
} | {
|
|
51
|
+
index: number;
|
|
52
|
+
kind: "code";
|
|
53
|
+
code: string;
|
|
54
|
+
language?: string;
|
|
55
|
+
title?: string;
|
|
56
|
+
lineStart?: number;
|
|
57
|
+
id?: string;
|
|
58
|
+
};
|
|
59
|
+
export declare const hydratedSurfaceView: (surface: Surface, index: number) => Record<string, unknown> | {
|
|
60
|
+
index: number;
|
|
61
|
+
kind: "html";
|
|
62
|
+
html: string;
|
|
63
|
+
kits?: string[];
|
|
64
|
+
id?: string;
|
|
65
|
+
} | {
|
|
66
|
+
index: number;
|
|
67
|
+
kind: "diff";
|
|
68
|
+
patch?: string;
|
|
69
|
+
files?: import("./types.ts").DiffFile[];
|
|
70
|
+
layout?: "unified" | "split";
|
|
71
|
+
id?: string;
|
|
72
|
+
} | {
|
|
73
|
+
index: number;
|
|
74
|
+
kind: "image";
|
|
75
|
+
assetId: string;
|
|
76
|
+
alt?: string;
|
|
77
|
+
caption?: string;
|
|
78
|
+
id?: string;
|
|
79
|
+
} | {
|
|
80
|
+
index: number;
|
|
81
|
+
kind: "markdown";
|
|
82
|
+
markdown: string;
|
|
83
|
+
id?: string;
|
|
84
|
+
} | {
|
|
85
|
+
index: number;
|
|
86
|
+
kind: "terminal";
|
|
87
|
+
text: string;
|
|
88
|
+
cols?: number;
|
|
89
|
+
title?: string;
|
|
90
|
+
id?: string;
|
|
91
|
+
} | {
|
|
92
|
+
index: number;
|
|
93
|
+
kind: "mermaid";
|
|
94
|
+
mermaid: string;
|
|
95
|
+
id?: string;
|
|
96
|
+
} | {
|
|
97
|
+
index: number;
|
|
98
|
+
kind: "json";
|
|
99
|
+
data: unknown;
|
|
100
|
+
id?: string;
|
|
101
|
+
} | {
|
|
102
|
+
index: number;
|
|
103
|
+
kind: "code";
|
|
104
|
+
code: string;
|
|
105
|
+
language?: string;
|
|
106
|
+
title?: string;
|
|
107
|
+
lineStart?: number;
|
|
108
|
+
id?: string;
|
|
109
|
+
};
|
|
110
|
+
export declare const historyMetaView: (version: PostVersion) => {
|
|
111
|
+
surfaceKinds: ("html" | "diff" | "image" | "markdown" | "terminal" | "mermaid" | "json" | "code")[];
|
|
112
|
+
author?: string | undefined;
|
|
113
|
+
prompt?: string | undefined;
|
|
114
|
+
from?: number | undefined;
|
|
115
|
+
version: number;
|
|
116
|
+
title: string;
|
|
117
|
+
at: string;
|
|
118
|
+
};
|
|
119
|
+
export interface VariantViewOptions {
|
|
120
|
+
body?: boolean;
|
|
121
|
+
history?: boolean;
|
|
122
|
+
}
|
|
123
|
+
export declare const variantView: (post: Post, opts?: VariantViewOptions) => {
|
|
124
|
+
history?: {
|
|
125
|
+
surfaceKinds: ("html" | "diff" | "image" | "markdown" | "terminal" | "mermaid" | "json" | "code")[];
|
|
126
|
+
author?: string | undefined;
|
|
127
|
+
prompt?: string | undefined;
|
|
128
|
+
from?: number | undefined;
|
|
129
|
+
version: number;
|
|
130
|
+
title: string;
|
|
131
|
+
at: string;
|
|
132
|
+
}[] | undefined;
|
|
133
|
+
parts: string[];
|
|
134
|
+
surfaces: (Record<string, unknown> | {
|
|
135
|
+
index: number;
|
|
136
|
+
kind: "html";
|
|
137
|
+
html: string;
|
|
138
|
+
kits?: string[];
|
|
139
|
+
id?: string;
|
|
140
|
+
} | {
|
|
141
|
+
index: number;
|
|
142
|
+
kind: "diff";
|
|
143
|
+
patch?: string;
|
|
144
|
+
files?: import("./types.ts").DiffFile[];
|
|
145
|
+
layout?: "unified" | "split";
|
|
146
|
+
id?: string;
|
|
147
|
+
} | {
|
|
148
|
+
index: number;
|
|
149
|
+
kind: "image";
|
|
150
|
+
assetId: string;
|
|
151
|
+
alt?: string;
|
|
152
|
+
caption?: string;
|
|
153
|
+
id?: string;
|
|
154
|
+
} | {
|
|
155
|
+
index: number;
|
|
156
|
+
kind: "markdown";
|
|
157
|
+
markdown: string;
|
|
158
|
+
id?: string;
|
|
159
|
+
} | {
|
|
160
|
+
index: number;
|
|
161
|
+
kind: "terminal";
|
|
162
|
+
text: string;
|
|
163
|
+
cols?: number;
|
|
164
|
+
title?: string;
|
|
165
|
+
id?: string;
|
|
166
|
+
} | {
|
|
167
|
+
index: number;
|
|
168
|
+
kind: "mermaid";
|
|
169
|
+
mermaid: string;
|
|
170
|
+
id?: string;
|
|
171
|
+
} | {
|
|
172
|
+
index: number;
|
|
173
|
+
kind: "json";
|
|
174
|
+
data: unknown;
|
|
175
|
+
id?: string;
|
|
176
|
+
} | {
|
|
177
|
+
index: number;
|
|
178
|
+
kind: "code";
|
|
179
|
+
code: string;
|
|
180
|
+
language?: string;
|
|
181
|
+
title?: string;
|
|
182
|
+
lineStart?: number;
|
|
183
|
+
id?: string;
|
|
184
|
+
})[];
|
|
185
|
+
slots?: import("./types.ts").Slot[] | undefined;
|
|
186
|
+
knobs?: import("./types.ts").Knobs | undefined;
|
|
187
|
+
author?: string | undefined;
|
|
188
|
+
prompt?: string | undefined;
|
|
189
|
+
from?: number | undefined;
|
|
190
|
+
postId: string;
|
|
191
|
+
state: string | null;
|
|
192
|
+
variant: string;
|
|
193
|
+
status: import("./types.ts").PostStatus;
|
|
194
|
+
version: number;
|
|
195
|
+
title: string;
|
|
196
|
+
sessionId: string;
|
|
197
|
+
createdAt: string;
|
|
198
|
+
updatedAt: string;
|
|
199
|
+
};
|
|
200
|
+
export interface StateParts {
|
|
201
|
+
state: string | null;
|
|
202
|
+
parts: PartInfo[];
|
|
203
|
+
}
|
|
204
|
+
export declare function partsByState(mock: Mock, posts: Post[]): StateParts[];
|
|
205
|
+
export declare const mockSummaryView: (mock: Mock, posts: Post[]) => {
|
|
206
|
+
id: string;
|
|
207
|
+
project: string;
|
|
208
|
+
slug: string;
|
|
209
|
+
title: string;
|
|
210
|
+
kind: import("./types.ts").MockKind;
|
|
211
|
+
states: string[];
|
|
212
|
+
stateCount: number;
|
|
213
|
+
variants: number;
|
|
214
|
+
open: number;
|
|
215
|
+
sessionId: string | null;
|
|
216
|
+
createdAt: string;
|
|
217
|
+
updatedAt: string;
|
|
218
|
+
thumbnail: {
|
|
219
|
+
postId: string;
|
|
220
|
+
surface: number;
|
|
221
|
+
version: number;
|
|
222
|
+
} | null;
|
|
223
|
+
};
|
|
224
|
+
export declare const mockDetailView: (mock: Mock, posts: Post[], opts?: VariantViewOptions & {
|
|
225
|
+
tuned?: Record<string, unknown>;
|
|
226
|
+
}) => {
|
|
227
|
+
id: string;
|
|
228
|
+
project: string;
|
|
229
|
+
slug: string;
|
|
230
|
+
title: string;
|
|
231
|
+
kind: import("./types.ts").MockKind;
|
|
232
|
+
states: string[];
|
|
233
|
+
asks: import("./types.ts").Ask[];
|
|
234
|
+
open: number;
|
|
235
|
+
knobs: import("./types.ts").Knobs;
|
|
236
|
+
sessionId: string | null;
|
|
237
|
+
createdAt: string;
|
|
238
|
+
updatedAt: string;
|
|
239
|
+
variants: {
|
|
240
|
+
history?: {
|
|
241
|
+
surfaceKinds: ("html" | "diff" | "image" | "markdown" | "terminal" | "mermaid" | "json" | "code")[];
|
|
242
|
+
author?: string | undefined;
|
|
243
|
+
prompt?: string | undefined;
|
|
244
|
+
from?: number | undefined;
|
|
245
|
+
version: number;
|
|
246
|
+
title: string;
|
|
247
|
+
at: string;
|
|
248
|
+
}[] | undefined;
|
|
249
|
+
parts: string[];
|
|
250
|
+
surfaces: (Record<string, unknown> | {
|
|
251
|
+
index: number;
|
|
252
|
+
kind: "html";
|
|
253
|
+
html: string;
|
|
254
|
+
kits?: string[];
|
|
255
|
+
id?: string;
|
|
256
|
+
} | {
|
|
257
|
+
index: number;
|
|
258
|
+
kind: "diff";
|
|
259
|
+
patch?: string;
|
|
260
|
+
files?: import("./types.ts").DiffFile[];
|
|
261
|
+
layout?: "unified" | "split";
|
|
262
|
+
id?: string;
|
|
263
|
+
} | {
|
|
264
|
+
index: number;
|
|
265
|
+
kind: "image";
|
|
266
|
+
assetId: string;
|
|
267
|
+
alt?: string;
|
|
268
|
+
caption?: string;
|
|
269
|
+
id?: string;
|
|
270
|
+
} | {
|
|
271
|
+
index: number;
|
|
272
|
+
kind: "markdown";
|
|
273
|
+
markdown: string;
|
|
274
|
+
id?: string;
|
|
275
|
+
} | {
|
|
276
|
+
index: number;
|
|
277
|
+
kind: "terminal";
|
|
278
|
+
text: string;
|
|
279
|
+
cols?: number;
|
|
280
|
+
title?: string;
|
|
281
|
+
id?: string;
|
|
282
|
+
} | {
|
|
283
|
+
index: number;
|
|
284
|
+
kind: "mermaid";
|
|
285
|
+
mermaid: string;
|
|
286
|
+
id?: string;
|
|
287
|
+
} | {
|
|
288
|
+
index: number;
|
|
289
|
+
kind: "json";
|
|
290
|
+
data: unknown;
|
|
291
|
+
id?: string;
|
|
292
|
+
} | {
|
|
293
|
+
index: number;
|
|
294
|
+
kind: "code";
|
|
295
|
+
code: string;
|
|
296
|
+
language?: string;
|
|
297
|
+
title?: string;
|
|
298
|
+
lineStart?: number;
|
|
299
|
+
id?: string;
|
|
300
|
+
})[];
|
|
301
|
+
slots?: import("./types.ts").Slot[] | undefined;
|
|
302
|
+
knobs?: import("./types.ts").Knobs | undefined;
|
|
303
|
+
author?: string | undefined;
|
|
304
|
+
prompt?: string | undefined;
|
|
305
|
+
from?: number | undefined;
|
|
306
|
+
postId: string;
|
|
307
|
+
state: string | null;
|
|
308
|
+
variant: string;
|
|
309
|
+
status: import("./types.ts").PostStatus;
|
|
310
|
+
version: number;
|
|
311
|
+
title: string;
|
|
312
|
+
sessionId: string;
|
|
313
|
+
createdAt: string;
|
|
314
|
+
updatedAt: string;
|
|
315
|
+
}[];
|
|
316
|
+
parts: StateParts[];
|
|
317
|
+
tuned: Record<string, unknown>;
|
|
318
|
+
};
|
|
319
|
+
export declare const sessionRowView: (session: Session, postCount: number) => {
|
|
320
|
+
postCount: number;
|
|
321
|
+
id: string;
|
|
322
|
+
agent: string;
|
|
323
|
+
title: string | null;
|
|
324
|
+
cwd: string | null;
|
|
325
|
+
createdAt: string;
|
|
326
|
+
lastActiveAt: string;
|
|
327
|
+
agentSeq: number;
|
|
328
|
+
project: string | null;
|
|
329
|
+
};
|