chapterhouse 0.8.2 → 0.9.1
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/dist/api/korg.js +2 -19
- package/dist/api/route-coverage.test.js +224 -0
- package/dist/api/server.js +238 -14
- package/dist/api/server.test.js +88 -2
- package/dist/shared/api-schemas.js +615 -0
- package/dist/store/db.js +1 -0
- package/dist/wiki/index-manager.js +1 -1
- package/package.json +1 -1
- package/web/dist/assets/{index-BbX9RKf3.js → index-iQrv3lQN.js} +155 -94
- package/web/dist/assets/index-iQrv3lQN.js.map +1 -0
- package/web/dist/index.html +1 -1
- package/dist/api/korg.test.js +0 -42
- package/web/dist/assets/index-BbX9RKf3.js.map +0 -1
|
@@ -0,0 +1,615 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared API contract schemas — single source of truth for every server↔client
|
|
3
|
+
* response type in Chapterhouse.
|
|
4
|
+
*
|
|
5
|
+
* Both the backend (`src/api/server.ts`) and the frontend (`web/src/api-schemas.ts`)
|
|
6
|
+
* import from here. When a server response shape changes, the TypeScript compiler
|
|
7
|
+
* immediately surfaces any mismatch on the import side — schema drift becomes a
|
|
8
|
+
* compile error rather than a runtime bug.
|
|
9
|
+
*
|
|
10
|
+
* Excluded from this file:
|
|
11
|
+
* - Parts model (TextPart, ToolCallPart, etc.) — client-only; synthesised from SSE
|
|
12
|
+
* frames in the frontend store. Lives in `web/src/api-schemas.ts`.
|
|
13
|
+
* - TurnEventSchema — depends on the client-side PartSchema (which includes the
|
|
14
|
+
* client-only ActivityHeartbeatPart). Lives in `web/src/api-schemas.ts`.
|
|
15
|
+
* See `src/copilot/turn-events.ts` for the daemon-side TypeScript mirror.
|
|
16
|
+
*
|
|
17
|
+
* Migration status: initial extraction from web/src/api-schemas.ts (issue #369).
|
|
18
|
+
*/
|
|
19
|
+
import { z } from "zod";
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
// /api/config/public
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
const StandaloneConfigSchema = z.object({
|
|
24
|
+
appName: z.literal("Chapterhouse"),
|
|
25
|
+
entraAuthEnabled: z.literal(false),
|
|
26
|
+
standalone: z.literal(true),
|
|
27
|
+
chatSseEnabled: z.boolean().optional(),
|
|
28
|
+
});
|
|
29
|
+
const NonStandaloneConfigSchema = z.object({
|
|
30
|
+
appName: z.literal("Chapterhouse"),
|
|
31
|
+
entraAuthEnabled: z.literal(false),
|
|
32
|
+
standalone: z.literal(false),
|
|
33
|
+
chatSseEnabled: z.boolean().optional(),
|
|
34
|
+
});
|
|
35
|
+
const EntraRuntimeConfigSchema = z.object({
|
|
36
|
+
appName: z.literal("Chapterhouse"),
|
|
37
|
+
entraAuthEnabled: z.literal(true),
|
|
38
|
+
entraClientId: z.string(),
|
|
39
|
+
entraTenantId: z.string(),
|
|
40
|
+
chatSseEnabled: z.boolean().optional(),
|
|
41
|
+
});
|
|
42
|
+
export const PublicConfigResponseSchema = z.union([
|
|
43
|
+
StandaloneConfigSchema,
|
|
44
|
+
NonStandaloneConfigSchema,
|
|
45
|
+
EntraRuntimeConfigSchema,
|
|
46
|
+
]);
|
|
47
|
+
// ---------------------------------------------------------------------------
|
|
48
|
+
// /api/bootstrap
|
|
49
|
+
// ---------------------------------------------------------------------------
|
|
50
|
+
export const BootstrapResponseSchema = z.union([
|
|
51
|
+
z.object({ authMode: z.literal("legacy"), token: z.string().nullable() }),
|
|
52
|
+
z.object({ authMode: z.literal("entra") }),
|
|
53
|
+
z.object({ authMode: z.literal("standalone") }),
|
|
54
|
+
]);
|
|
55
|
+
// ---------------------------------------------------------------------------
|
|
56
|
+
// /api/message /api/restart
|
|
57
|
+
// ---------------------------------------------------------------------------
|
|
58
|
+
export const StatusResponseSchema = z.object({ status: z.string() });
|
|
59
|
+
// ---------------------------------------------------------------------------
|
|
60
|
+
// /api/cancel
|
|
61
|
+
// ---------------------------------------------------------------------------
|
|
62
|
+
export const CancelResponseSchema = z.object({
|
|
63
|
+
status: z.string(),
|
|
64
|
+
cancelled: z.boolean(),
|
|
65
|
+
});
|
|
66
|
+
// ---------------------------------------------------------------------------
|
|
67
|
+
// /api/agents
|
|
68
|
+
// ---------------------------------------------------------------------------
|
|
69
|
+
export const AgentSummarySchema = z.object({
|
|
70
|
+
name: z.string(),
|
|
71
|
+
slug: z.string(),
|
|
72
|
+
description: z.string(),
|
|
73
|
+
model: z.string(),
|
|
74
|
+
scope: z.string().nullable(),
|
|
75
|
+
type: z.enum(["builtin", "custom"]),
|
|
76
|
+
lastEdited: z.string().nullable(),
|
|
77
|
+
});
|
|
78
|
+
export const AgentListSchema = z.array(AgentSummarySchema);
|
|
79
|
+
export const AgentDetailSchema = z.object({
|
|
80
|
+
name: z.string(),
|
|
81
|
+
slug: z.string(),
|
|
82
|
+
description: z.string(),
|
|
83
|
+
model: z.string(),
|
|
84
|
+
scope: z.string().nullable(),
|
|
85
|
+
persistent: z.boolean(),
|
|
86
|
+
skills: z.array(z.string()),
|
|
87
|
+
type: z.enum(["builtin", "custom"]),
|
|
88
|
+
editable: z.boolean(),
|
|
89
|
+
systemPrompt: z.string(),
|
|
90
|
+
});
|
|
91
|
+
export const AgentPatchRequestSchema = z.object({
|
|
92
|
+
name: z.string().optional(),
|
|
93
|
+
description: z.string().optional(),
|
|
94
|
+
model: z.string().optional(),
|
|
95
|
+
systemPrompt: z.string().optional(),
|
|
96
|
+
}).strict();
|
|
97
|
+
// ---------------------------------------------------------------------------
|
|
98
|
+
// /api/projects
|
|
99
|
+
// ---------------------------------------------------------------------------
|
|
100
|
+
export const ProjectSummarySchema = z.object({
|
|
101
|
+
slug: z.string(),
|
|
102
|
+
cwd: z.string(),
|
|
103
|
+
hardRuleCount: z.number().int().nullable(),
|
|
104
|
+
softRuleCount: z.number().int().nullable(),
|
|
105
|
+
});
|
|
106
|
+
export const ProjectListSchema = z.array(ProjectSummarySchema);
|
|
107
|
+
export const ProjectHardRulesSchema = z.object({
|
|
108
|
+
auto_pr: z.boolean(),
|
|
109
|
+
require_worktree: z.boolean(),
|
|
110
|
+
pr_draft_default: z.boolean(),
|
|
111
|
+
default_branch: z.string(),
|
|
112
|
+
commit_co_author: z.string(),
|
|
113
|
+
test_command: z.string(),
|
|
114
|
+
build_command: z.string(),
|
|
115
|
+
lint_command: z.string(),
|
|
116
|
+
require_clean_worktree: z.boolean(),
|
|
117
|
+
});
|
|
118
|
+
export const ProjectHardRulesUpdateRequestSchema = z.object({
|
|
119
|
+
hardRules: ProjectHardRulesSchema,
|
|
120
|
+
});
|
|
121
|
+
export const ProjectSoftRulesUpdateRequestSchema = z.object({
|
|
122
|
+
softRules: z.array(z.string()),
|
|
123
|
+
});
|
|
124
|
+
export const ProjectDetailSchema = z.discriminatedUnion("rulesFound", [
|
|
125
|
+
z.object({
|
|
126
|
+
slug: z.string(),
|
|
127
|
+
cwd: z.string(),
|
|
128
|
+
rulesFound: z.literal(true),
|
|
129
|
+
hardRules: ProjectHardRulesSchema,
|
|
130
|
+
softRules: z.array(z.string()),
|
|
131
|
+
}),
|
|
132
|
+
z.object({
|
|
133
|
+
slug: z.string(),
|
|
134
|
+
cwd: z.string(),
|
|
135
|
+
rulesFound: z.literal(false),
|
|
136
|
+
hardRules: z.null(),
|
|
137
|
+
softRules: z.array(z.string()),
|
|
138
|
+
}),
|
|
139
|
+
]);
|
|
140
|
+
export const ProjectDeleteResponseSchema = z.object({
|
|
141
|
+
ok: z.literal(true),
|
|
142
|
+
slug: z.string(),
|
|
143
|
+
});
|
|
144
|
+
export const AgentSaveResponseSchema = z.object({
|
|
145
|
+
ok: z.literal(true),
|
|
146
|
+
slug: z.string(),
|
|
147
|
+
});
|
|
148
|
+
// ---------------------------------------------------------------------------
|
|
149
|
+
// /api/workers (list)
|
|
150
|
+
// ---------------------------------------------------------------------------
|
|
151
|
+
export const WorkerRowSchema = z.object({
|
|
152
|
+
slug: z.string(),
|
|
153
|
+
name: z.string(),
|
|
154
|
+
model: z.string(),
|
|
155
|
+
taskId: z.string(),
|
|
156
|
+
description: z.string(),
|
|
157
|
+
status: z.string(),
|
|
158
|
+
startedAt: z.string(),
|
|
159
|
+
completedAt: z.string().nullable(),
|
|
160
|
+
});
|
|
161
|
+
export const WorkerListSchema = z.array(WorkerRowSchema);
|
|
162
|
+
// ---------------------------------------------------------------------------
|
|
163
|
+
// /api/workers/:taskId (detail)
|
|
164
|
+
// ---------------------------------------------------------------------------
|
|
165
|
+
export const WorkerDetailSchema = z.object({
|
|
166
|
+
taskId: z.string(),
|
|
167
|
+
agentSlug: z.string(),
|
|
168
|
+
name: z.string(),
|
|
169
|
+
description: z.string(),
|
|
170
|
+
prompt: z.string().nullable(),
|
|
171
|
+
status: z.string(),
|
|
172
|
+
result: z.string().nullable(),
|
|
173
|
+
startedAt: z.string(),
|
|
174
|
+
completedAt: z.string().nullable(),
|
|
175
|
+
});
|
|
176
|
+
// ---------------------------------------------------------------------------
|
|
177
|
+
// /api/workers/:taskId/events (historical event log)
|
|
178
|
+
// ---------------------------------------------------------------------------
|
|
179
|
+
export const TaskEventSchema = z.object({
|
|
180
|
+
id: z.number(),
|
|
181
|
+
taskId: z.string(),
|
|
182
|
+
seq: z.number(),
|
|
183
|
+
ts: z.number(),
|
|
184
|
+
kind: z.enum(["tool_start", "tool_complete"]),
|
|
185
|
+
toolName: z.string().nullable(),
|
|
186
|
+
summary: z.string().nullable(),
|
|
187
|
+
});
|
|
188
|
+
export const TaskEventsResponseSchema = z.object({
|
|
189
|
+
taskId: z.string(),
|
|
190
|
+
events: z.array(TaskEventSchema),
|
|
191
|
+
});
|
|
192
|
+
// ---------------------------------------------------------------------------
|
|
193
|
+
// /api/model (get / set)
|
|
194
|
+
// ---------------------------------------------------------------------------
|
|
195
|
+
export const ModelResponseSchema = z.object({ model: z.string() });
|
|
196
|
+
export const SetModelResponseSchema = z.object({ previous: z.string(), current: z.string() });
|
|
197
|
+
export const ListModelsResponseSchema = z.object({
|
|
198
|
+
models: z.array(z.string()),
|
|
199
|
+
current: z.string(),
|
|
200
|
+
});
|
|
201
|
+
// ---------------------------------------------------------------------------
|
|
202
|
+
// /api/auto
|
|
203
|
+
// ---------------------------------------------------------------------------
|
|
204
|
+
export const AutoConfigSchema = z.object({
|
|
205
|
+
enabled: z.boolean(),
|
|
206
|
+
tierModels: z.record(z.string(), z.string()),
|
|
207
|
+
cooldownMessages: z.number(),
|
|
208
|
+
currentModel: z.string(),
|
|
209
|
+
lastRoute: z.unknown(),
|
|
210
|
+
});
|
|
211
|
+
// ---------------------------------------------------------------------------
|
|
212
|
+
// /api/wiki/pages
|
|
213
|
+
// ---------------------------------------------------------------------------
|
|
214
|
+
export const WikiPageMetaSchema = z.object({
|
|
215
|
+
path: z.string(),
|
|
216
|
+
title: z.string(),
|
|
217
|
+
summary: z.string(),
|
|
218
|
+
section: z.string(),
|
|
219
|
+
tags: z.array(z.string()),
|
|
220
|
+
updated: z.string(),
|
|
221
|
+
scope: z.enum(["personal", "team"]),
|
|
222
|
+
});
|
|
223
|
+
export const WikiPageListSchema = z.array(WikiPageMetaSchema);
|
|
224
|
+
// ---------------------------------------------------------------------------
|
|
225
|
+
// /api/wiki/page (read / write / delete)
|
|
226
|
+
// ---------------------------------------------------------------------------
|
|
227
|
+
const WikiFrontmatterValueSchema = z.union([z.string(), z.array(z.string()), z.boolean()]);
|
|
228
|
+
export const WikiPageFrontmatterSchema = z.object({
|
|
229
|
+
title: z.string().optional(),
|
|
230
|
+
summary: z.string().optional(),
|
|
231
|
+
updated: z.string().optional(),
|
|
232
|
+
tags: z.array(z.string()).optional(),
|
|
233
|
+
autostub: z.boolean().optional(),
|
|
234
|
+
confidence: z.enum(["high", "medium", "low"]).optional(),
|
|
235
|
+
contested: z.boolean().optional(),
|
|
236
|
+
contradictions: z.array(z.string()).optional(),
|
|
237
|
+
related: z.array(z.string()).optional(),
|
|
238
|
+
auto_pr: z.boolean().optional(),
|
|
239
|
+
require_worktree: z.boolean().optional(),
|
|
240
|
+
pr_draft_default: z.boolean().optional(),
|
|
241
|
+
default_branch: z.string().optional(),
|
|
242
|
+
commit_co_author: z.string().optional(),
|
|
243
|
+
test_command: z.string().optional(),
|
|
244
|
+
build_command: z.string().optional(),
|
|
245
|
+
lint_command: z.string().optional(),
|
|
246
|
+
require_clean_worktree: z.boolean().optional(),
|
|
247
|
+
metadata: z.record(z.string(), WikiFrontmatterValueSchema),
|
|
248
|
+
});
|
|
249
|
+
export const WikiPageContentSchema = z.object({
|
|
250
|
+
path: z.string(),
|
|
251
|
+
content: z.string(),
|
|
252
|
+
renderedContent: z.string(),
|
|
253
|
+
frontmatter: WikiPageFrontmatterSchema,
|
|
254
|
+
});
|
|
255
|
+
export const WikiWriteResponseSchema = z.object({
|
|
256
|
+
ok: z.boolean(),
|
|
257
|
+
created: z.boolean(),
|
|
258
|
+
path: z.string(),
|
|
259
|
+
});
|
|
260
|
+
export const WikiDeleteResponseSchema = z.object({
|
|
261
|
+
ok: z.boolean(),
|
|
262
|
+
path: z.string(),
|
|
263
|
+
});
|
|
264
|
+
export const WikiBrowserPageSchema = z.object({
|
|
265
|
+
slug: z.string(),
|
|
266
|
+
title: z.string().default(""),
|
|
267
|
+
summary: z.string().default(""),
|
|
268
|
+
type: z.string().default("topics"),
|
|
269
|
+
last_updated: z.string().default(""),
|
|
270
|
+
pinned: z.boolean().optional(),
|
|
271
|
+
}).passthrough();
|
|
272
|
+
export const WikiBrowserPageListSchema = z.object({
|
|
273
|
+
pages: z.array(WikiBrowserPageSchema),
|
|
274
|
+
});
|
|
275
|
+
export const WikiLinkSchema = z.object({
|
|
276
|
+
source_slug: z.string(),
|
|
277
|
+
target_slug: z.string(),
|
|
278
|
+
link_type: z.string(),
|
|
279
|
+
}).passthrough();
|
|
280
|
+
export const WikiLinksResponseSchema = z.object({
|
|
281
|
+
links: z.array(WikiLinkSchema),
|
|
282
|
+
});
|
|
283
|
+
export const WikiSourceSchema = z.object({
|
|
284
|
+
source_url: z.string().optional(),
|
|
285
|
+
path: z.string().optional(),
|
|
286
|
+
kind: z.string(),
|
|
287
|
+
status: z.string(),
|
|
288
|
+
session_id: z.string().nullable().optional(),
|
|
289
|
+
ingested_at: z.string().nullable().optional(),
|
|
290
|
+
}).passthrough();
|
|
291
|
+
export const WikiSourcesResponseSchema = z.object({
|
|
292
|
+
sources: z.array(WikiSourceSchema),
|
|
293
|
+
});
|
|
294
|
+
export const WikiResearchSessionSchema = z.object({
|
|
295
|
+
id: z.string().optional(),
|
|
296
|
+
name: z.string(),
|
|
297
|
+
source_count: z.number().int().default(0),
|
|
298
|
+
open_questions_count: z.number().int().default(0),
|
|
299
|
+
last_activity_at: z.string().default(""),
|
|
300
|
+
}).passthrough();
|
|
301
|
+
export const WikiResearchSessionsResponseSchema = z.object({
|
|
302
|
+
sessions: z.array(WikiResearchSessionSchema),
|
|
303
|
+
});
|
|
304
|
+
export const WikiPageDetailSchema = z.object({
|
|
305
|
+
page: WikiBrowserPageSchema.extend({
|
|
306
|
+
compiled_truth: z.string().default(""),
|
|
307
|
+
pinned: z.boolean().default(false),
|
|
308
|
+
frontmatter: z.record(z.string(), z.unknown()).optional(),
|
|
309
|
+
links: z.array(WikiLinkSchema).optional(),
|
|
310
|
+
}).passthrough(),
|
|
311
|
+
});
|
|
312
|
+
export const WikiPageUpdateResponseSchema = z.object({
|
|
313
|
+
ok: z.boolean(),
|
|
314
|
+
page: WikiPageDetailSchema.shape.page.optional(),
|
|
315
|
+
pinned: z.boolean().optional(),
|
|
316
|
+
}).passthrough();
|
|
317
|
+
export const WikiReingestResponseSchema = z.object({
|
|
318
|
+
ok: z.boolean(),
|
|
319
|
+
}).passthrough();
|
|
320
|
+
// ---------------------------------------------------------------------------
|
|
321
|
+
// /api/skills
|
|
322
|
+
// ---------------------------------------------------------------------------
|
|
323
|
+
export const SkillSchema = z.object({
|
|
324
|
+
slug: z.string(),
|
|
325
|
+
name: z.string(),
|
|
326
|
+
description: z.string(),
|
|
327
|
+
directory: z.string(),
|
|
328
|
+
source: z.enum(["bundled", "local", "global"]),
|
|
329
|
+
});
|
|
330
|
+
export const SkillListSchema = z.array(SkillSchema);
|
|
331
|
+
export const RemoveSkillResponseSchema = z.object({
|
|
332
|
+
ok: z.boolean(),
|
|
333
|
+
message: z.string(),
|
|
334
|
+
});
|
|
335
|
+
// ---------------------------------------------------------------------------
|
|
336
|
+
// /api/channels
|
|
337
|
+
// ---------------------------------------------------------------------------
|
|
338
|
+
export const ChannelSchema = z.object({
|
|
339
|
+
key: z.string().min(1),
|
|
340
|
+
label: z.string().min(1),
|
|
341
|
+
slug: z.string().optional(),
|
|
342
|
+
name: z.string().optional(),
|
|
343
|
+
description: z.string().optional(),
|
|
344
|
+
scope: z.string().optional(),
|
|
345
|
+
});
|
|
346
|
+
export const ChannelListSchema = z.array(ChannelSchema);
|
|
347
|
+
// ---------------------------------------------------------------------------
|
|
348
|
+
// /api/session/:key/messages
|
|
349
|
+
// ---------------------------------------------------------------------------
|
|
350
|
+
export const SessionMessageSchema = z.object({
|
|
351
|
+
id: z.number().int(),
|
|
352
|
+
role: z.enum(["user", "assistant"]),
|
|
353
|
+
content: z.string(),
|
|
354
|
+
ts: z.string(),
|
|
355
|
+
turn_id: z.string().nullable(),
|
|
356
|
+
turnId: z.string().optional(),
|
|
357
|
+
agentSlug: z.string().optional(),
|
|
358
|
+
agentDisplayName: z.string().optional(),
|
|
359
|
+
});
|
|
360
|
+
export const SessionMessagesResponseSchema = z.object({
|
|
361
|
+
sessionKey: z.string(),
|
|
362
|
+
messages: z.array(SessionMessageSchema),
|
|
363
|
+
});
|
|
364
|
+
// ---------------------------------------------------------------------------
|
|
365
|
+
// SSE stream events (/stream)
|
|
366
|
+
// ---------------------------------------------------------------------------
|
|
367
|
+
const RouteInfoSchema = z.object({
|
|
368
|
+
model: z.string(),
|
|
369
|
+
routerMode: z.string().optional(),
|
|
370
|
+
tier: z.string().nullable().optional(),
|
|
371
|
+
overrideName: z.string().optional(),
|
|
372
|
+
});
|
|
373
|
+
const ThinkingDeltaFrameSchema = z.object({
|
|
374
|
+
kind: z.literal("thinking_delta"),
|
|
375
|
+
reasoningId: z.string(),
|
|
376
|
+
deltaContent: z.string(),
|
|
377
|
+
agentSlug: z.string().optional(),
|
|
378
|
+
});
|
|
379
|
+
const ToolStartFrameSchema = z.object({
|
|
380
|
+
kind: z.literal("tool_start"),
|
|
381
|
+
toolCallId: z.string(),
|
|
382
|
+
toolName: z.string(),
|
|
383
|
+
mcpServerName: z.string().optional(),
|
|
384
|
+
arguments: z.record(z.string(), z.unknown()).optional(),
|
|
385
|
+
agentSlug: z.string().optional(),
|
|
386
|
+
});
|
|
387
|
+
const ToolCompleteFrameSchema = z.object({
|
|
388
|
+
kind: z.literal("tool_complete"),
|
|
389
|
+
toolCallId: z.string(),
|
|
390
|
+
success: z.boolean(),
|
|
391
|
+
resultPreview: z.string().optional(),
|
|
392
|
+
detailedContent: z.string().optional(),
|
|
393
|
+
agentSlug: z.string().optional(),
|
|
394
|
+
});
|
|
395
|
+
const SubagentStartedFrameSchema = z.object({
|
|
396
|
+
kind: z.literal("subagent_started"),
|
|
397
|
+
toolCallId: z.string(),
|
|
398
|
+
agentName: z.string(),
|
|
399
|
+
agentDisplayName: z.string(),
|
|
400
|
+
agentDescription: z.string(),
|
|
401
|
+
agentSlug: z.string().optional(),
|
|
402
|
+
});
|
|
403
|
+
const SubagentCompletedFrameSchema = z.object({
|
|
404
|
+
kind: z.literal("subagent_completed"),
|
|
405
|
+
toolCallId: z.string(),
|
|
406
|
+
agentName: z.string(),
|
|
407
|
+
agentDisplayName: z.string(),
|
|
408
|
+
durationMs: z.number().optional(),
|
|
409
|
+
agentSlug: z.string().optional(),
|
|
410
|
+
});
|
|
411
|
+
const SubagentFailedFrameSchema = z.object({
|
|
412
|
+
kind: z.literal("subagent_failed"),
|
|
413
|
+
toolCallId: z.string(),
|
|
414
|
+
agentName: z.string(),
|
|
415
|
+
agentDisplayName: z.string(),
|
|
416
|
+
error: z.string().optional(),
|
|
417
|
+
agentSlug: z.string().optional(),
|
|
418
|
+
});
|
|
419
|
+
export const ActivityFrameSchema = z.discriminatedUnion("kind", [
|
|
420
|
+
ThinkingDeltaFrameSchema,
|
|
421
|
+
ToolStartFrameSchema,
|
|
422
|
+
ToolCompleteFrameSchema,
|
|
423
|
+
SubagentStartedFrameSchema,
|
|
424
|
+
SubagentCompletedFrameSchema,
|
|
425
|
+
SubagentFailedFrameSchema,
|
|
426
|
+
]);
|
|
427
|
+
export const StreamEventSchema = z.union([
|
|
428
|
+
z.object({ type: z.literal("connected"), connectionId: z.string() }),
|
|
429
|
+
z.object({ type: z.literal("delta"), content: z.string(), sessionKey: z.string().optional(), turnId: z.string().optional() }),
|
|
430
|
+
z.object({
|
|
431
|
+
type: z.literal("message"),
|
|
432
|
+
content: z.string(),
|
|
433
|
+
sessionKey: z.string().optional(),
|
|
434
|
+
turnId: z.string().optional(),
|
|
435
|
+
route: RouteInfoSchema.optional(),
|
|
436
|
+
}),
|
|
437
|
+
z.object({ type: z.literal("cancelled"), sessionKey: z.string().optional() }),
|
|
438
|
+
z.object({
|
|
439
|
+
type: z.literal("status"),
|
|
440
|
+
status: z.enum(["idle", "dreaming"]),
|
|
441
|
+
message: z.string(),
|
|
442
|
+
}),
|
|
443
|
+
z.object({
|
|
444
|
+
type: z.literal("agent_reload_pending"),
|
|
445
|
+
slug: z.string(),
|
|
446
|
+
reason: z.literal("in_flight"),
|
|
447
|
+
}),
|
|
448
|
+
z.object({
|
|
449
|
+
type: z.literal("agent_reloaded"),
|
|
450
|
+
slug: z.string(),
|
|
451
|
+
reason: z.enum(["session_restart", "confirmed_restart"]),
|
|
452
|
+
}),
|
|
453
|
+
z.object({
|
|
454
|
+
type: z.literal("queued"),
|
|
455
|
+
position: z.number(),
|
|
456
|
+
sessionKey: z.string().optional(),
|
|
457
|
+
turnId: z.string().optional(),
|
|
458
|
+
msgId: z.string().optional(),
|
|
459
|
+
}),
|
|
460
|
+
// Activity events — each ActivityFrame kind merged inline with the activity wrapper.
|
|
461
|
+
// turnId is included for future use (e.g., the activity sidecar in #85) but is NOT
|
|
462
|
+
// used by App.tsx for bubble-boundary detection — activity events don't drive bubble
|
|
463
|
+
// boundaries; only delta/message events (which carry the authoritative turnId) do.
|
|
464
|
+
z.object({
|
|
465
|
+
type: z.literal("activity"),
|
|
466
|
+
sessionKey: z.string().optional(),
|
|
467
|
+
turnId: z.string().optional(),
|
|
468
|
+
kind: z.literal("thinking_delta"),
|
|
469
|
+
reasoningId: z.string(),
|
|
470
|
+
deltaContent: z.string(),
|
|
471
|
+
agentSlug: z.string().optional(),
|
|
472
|
+
}),
|
|
473
|
+
z.object({
|
|
474
|
+
type: z.literal("activity"),
|
|
475
|
+
sessionKey: z.string().optional(),
|
|
476
|
+
turnId: z.string().optional(),
|
|
477
|
+
kind: z.literal("tool_start"),
|
|
478
|
+
toolCallId: z.string(),
|
|
479
|
+
toolName: z.string(),
|
|
480
|
+
mcpServerName: z.string().optional(),
|
|
481
|
+
arguments: z.record(z.string(), z.unknown()).optional(),
|
|
482
|
+
agentSlug: z.string().optional(),
|
|
483
|
+
}),
|
|
484
|
+
z.object({
|
|
485
|
+
type: z.literal("activity"),
|
|
486
|
+
sessionKey: z.string().optional(),
|
|
487
|
+
turnId: z.string().optional(),
|
|
488
|
+
kind: z.literal("tool_complete"),
|
|
489
|
+
toolCallId: z.string(),
|
|
490
|
+
success: z.boolean(),
|
|
491
|
+
resultPreview: z.string().optional(),
|
|
492
|
+
detailedContent: z.string().optional(),
|
|
493
|
+
agentSlug: z.string().optional(),
|
|
494
|
+
}),
|
|
495
|
+
z.object({
|
|
496
|
+
type: z.literal("activity"),
|
|
497
|
+
sessionKey: z.string().optional(),
|
|
498
|
+
turnId: z.string().optional(),
|
|
499
|
+
kind: z.literal("subagent_started"),
|
|
500
|
+
toolCallId: z.string(),
|
|
501
|
+
agentName: z.string(),
|
|
502
|
+
agentDisplayName: z.string(),
|
|
503
|
+
agentDescription: z.string(),
|
|
504
|
+
agentSlug: z.string().optional(),
|
|
505
|
+
}),
|
|
506
|
+
z.object({
|
|
507
|
+
type: z.literal("activity"),
|
|
508
|
+
sessionKey: z.string().optional(),
|
|
509
|
+
turnId: z.string().optional(),
|
|
510
|
+
kind: z.literal("subagent_completed"),
|
|
511
|
+
toolCallId: z.string(),
|
|
512
|
+
agentName: z.string(),
|
|
513
|
+
agentDisplayName: z.string(),
|
|
514
|
+
durationMs: z.number().optional(),
|
|
515
|
+
agentSlug: z.string().optional(),
|
|
516
|
+
}),
|
|
517
|
+
z.object({
|
|
518
|
+
type: z.literal("activity"),
|
|
519
|
+
sessionKey: z.string().optional(),
|
|
520
|
+
turnId: z.string().optional(),
|
|
521
|
+
kind: z.literal("subagent_failed"),
|
|
522
|
+
toolCallId: z.string(),
|
|
523
|
+
agentName: z.string(),
|
|
524
|
+
agentDisplayName: z.string(),
|
|
525
|
+
error: z.string().optional(),
|
|
526
|
+
agentSlug: z.string().optional(),
|
|
527
|
+
}),
|
|
528
|
+
// Emitted by the backend when a queued turn starts processing, with the number
|
|
529
|
+
// of messages still waiting behind it. Frontend renumbers "N ahead" indicators.
|
|
530
|
+
z.object({
|
|
531
|
+
type: z.literal("queue-advance"),
|
|
532
|
+
length: z.number(),
|
|
533
|
+
sessionKey: z.string().optional(),
|
|
534
|
+
}),
|
|
535
|
+
// Emitted by the backend when an active turn is aborted by the user via the
|
|
536
|
+
// interrupt endpoint. The frontend should drop the partial in-flight bubble
|
|
537
|
+
// (identified by abortedTurnId) so the replacement turn renders fresh.
|
|
538
|
+
z.object({
|
|
539
|
+
type: z.literal("turn-interrupted"),
|
|
540
|
+
abortedTurnId: z.string(),
|
|
541
|
+
sessionKey: z.string().optional(),
|
|
542
|
+
}),
|
|
543
|
+
]);
|
|
544
|
+
// ---------------------------------------------------------------------------
|
|
545
|
+
// /api/sessions/:key/turn (POST — fire-and-forget submit, #131)
|
|
546
|
+
// ---------------------------------------------------------------------------
|
|
547
|
+
export const SubmitTurnResponseSchema = z.object({
|
|
548
|
+
turnId: z.string(),
|
|
549
|
+
});
|
|
550
|
+
// ---------------------------------------------------------------------------
|
|
551
|
+
// /api/memory/active-scope (GET + POST)
|
|
552
|
+
// ---------------------------------------------------------------------------
|
|
553
|
+
export const ActiveMemoryScopeSchema = z.object({
|
|
554
|
+
slug: z.string(),
|
|
555
|
+
title: z.string(),
|
|
556
|
+
}).nullable();
|
|
557
|
+
export const SetActiveScopeResponseSchema = z.object({
|
|
558
|
+
ok: z.literal(true),
|
|
559
|
+
scope: z.string().nullable(),
|
|
560
|
+
});
|
|
561
|
+
// ---------------------------------------------------------------------------
|
|
562
|
+
// /api/memory/scopes
|
|
563
|
+
// ---------------------------------------------------------------------------
|
|
564
|
+
const MemoryScopeCountsSchema = z.object({
|
|
565
|
+
observations: z.number(),
|
|
566
|
+
decisions: z.number(),
|
|
567
|
+
entities: z.number(),
|
|
568
|
+
action_items: z.number(),
|
|
569
|
+
});
|
|
570
|
+
const MemoryScopeItemSchema = z.object({
|
|
571
|
+
slug: z.string(),
|
|
572
|
+
title: z.string(),
|
|
573
|
+
description: z.string(),
|
|
574
|
+
active: z.boolean(),
|
|
575
|
+
counts: MemoryScopeCountsSchema,
|
|
576
|
+
});
|
|
577
|
+
export const MemoryScopeListSchema = z.object({
|
|
578
|
+
scopes: z.array(MemoryScopeItemSchema),
|
|
579
|
+
});
|
|
580
|
+
// ---------------------------------------------------------------------------
|
|
581
|
+
// /api/memory/:scope (entries)
|
|
582
|
+
// ---------------------------------------------------------------------------
|
|
583
|
+
export const MemoryEntriesSchema = z.object({
|
|
584
|
+
entries: z.array(z.record(z.string(), z.unknown())),
|
|
585
|
+
total: z.number(),
|
|
586
|
+
});
|
|
587
|
+
// ---------------------------------------------------------------------------
|
|
588
|
+
// /api/memory/:scope/remember
|
|
589
|
+
// ---------------------------------------------------------------------------
|
|
590
|
+
export const MemoryRememberResponseSchema = z.object({
|
|
591
|
+
ok: z.literal(true),
|
|
592
|
+
id: z.string(),
|
|
593
|
+
});
|
|
594
|
+
// ---------------------------------------------------------------------------
|
|
595
|
+
// /api/memory/inbox
|
|
596
|
+
// ---------------------------------------------------------------------------
|
|
597
|
+
const InboxItemSchema = z.object({
|
|
598
|
+
id: z.number(),
|
|
599
|
+
scope_slug: z.string().nullable(),
|
|
600
|
+
kind: z.string(),
|
|
601
|
+
payload: z.string(),
|
|
602
|
+
source_agent: z.string(),
|
|
603
|
+
created_at: z.string(),
|
|
604
|
+
});
|
|
605
|
+
export const MemoryInboxSchema = z.object({
|
|
606
|
+
items: z.array(InboxItemSchema),
|
|
607
|
+
total: z.number(),
|
|
608
|
+
});
|
|
609
|
+
// ---------------------------------------------------------------------------
|
|
610
|
+
// /api/memory/inbox/:id/route
|
|
611
|
+
// ---------------------------------------------------------------------------
|
|
612
|
+
export const InboxRouteResponseSchema = z.object({
|
|
613
|
+
ok: z.literal(true),
|
|
614
|
+
});
|
|
615
|
+
//# sourceMappingURL=api-schemas.js.map
|
package/dist/store/db.js
CHANGED
|
@@ -551,6 +551,7 @@ export function getDb() {
|
|
|
551
551
|
ensureChapterhouseHome();
|
|
552
552
|
db = new Database(getDbPath());
|
|
553
553
|
db.pragma("journal_mode = WAL");
|
|
554
|
+
db.pragma("busy_timeout = 5000");
|
|
554
555
|
db.pragma("foreign_keys = ON");
|
|
555
556
|
db.exec(`
|
|
556
557
|
CREATE TABLE IF NOT EXISTS worker_sessions (
|
|
@@ -77,7 +77,7 @@ export function upsertWikiPage(path, frontmatter, summary) {
|
|
|
77
77
|
const db = getDb();
|
|
78
78
|
const normalizedPath = normalizeWikiPath(path);
|
|
79
79
|
const title = frontmatter.title ?? basenameTitle(normalizedPath);
|
|
80
|
-
const entityType = frontmatter.metadata?.["entity_type"] ??
|
|
80
|
+
const entityType = frontmatter.metadata?.["entity_type"] ?? categoryOfPath(normalizedPath);
|
|
81
81
|
const tags = JSON.stringify(frontmatter.tags ?? []);
|
|
82
82
|
const lastUpdated = frontmatter.updated ?? new Date().toISOString();
|
|
83
83
|
db.prepare(`
|
package/package.json
CHANGED