@treeseed/core 0.4.1 → 0.4.4

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 (64) hide show
  1. package/README.md +7 -1
  2. package/dist/api/agent-routes.d.ts +13 -0
  3. package/dist/api/agent-routes.js +402 -0
  4. package/dist/api/app.d.ts +5 -0
  5. package/dist/api/app.js +270 -0
  6. package/dist/api/auth/d1-database.d.ts +3 -0
  7. package/dist/api/auth/d1-database.js +24 -0
  8. package/dist/api/auth/d1-provider.d.ts +67 -0
  9. package/dist/api/auth/d1-provider.js +84 -0
  10. package/dist/api/auth/d1-store.d.ts +97 -0
  11. package/dist/api/auth/d1-store.js +631 -0
  12. package/dist/api/auth/memory-provider.d.ts +73 -0
  13. package/dist/api/auth/memory-provider.js +239 -0
  14. package/dist/api/auth/rbac.d.ts +22 -0
  15. package/dist/api/auth/rbac.js +158 -0
  16. package/dist/api/auth/tokens.d.ts +18 -0
  17. package/dist/api/auth/tokens.js +56 -0
  18. package/dist/api/config.d.ts +2 -0
  19. package/dist/api/config.js +65 -0
  20. package/dist/api/gateway.d.ts +5 -0
  21. package/dist/api/gateway.js +35 -0
  22. package/dist/api/http.d.ts +24 -0
  23. package/dist/api/http.js +44 -0
  24. package/dist/api/index.d.ts +9 -0
  25. package/dist/api/index.js +18 -0
  26. package/dist/api/operations-routes.d.ts +6 -0
  27. package/dist/api/operations-routes.js +34 -0
  28. package/dist/api/operations.d.ts +3 -0
  29. package/dist/api/operations.js +26 -0
  30. package/dist/api/providers.d.ts +2 -0
  31. package/dist/api/providers.js +61 -0
  32. package/dist/api/railway.d.ts +45 -0
  33. package/dist/api/railway.js +69 -0
  34. package/dist/api/sdk-dispatch.d.ts +14 -0
  35. package/dist/api/sdk-dispatch.js +145 -0
  36. package/dist/api/sdk-routes.d.ts +10 -0
  37. package/dist/api/sdk-routes.js +25 -0
  38. package/dist/api/server.d.ts +2 -0
  39. package/dist/api/server.js +10 -0
  40. package/dist/api/templates.d.ts +3 -0
  41. package/dist/api/templates.js +31 -0
  42. package/dist/api/types.d.ts +193 -0
  43. package/dist/api/types.js +0 -0
  44. package/dist/api.d.ts +1 -0
  45. package/dist/api.js +1 -0
  46. package/dist/dev.d.ts +41 -0
  47. package/dist/dev.js +189 -0
  48. package/dist/index.d.ts +9 -0
  49. package/dist/index.js +23 -1
  50. package/dist/platform-resources.d.ts +37 -0
  51. package/dist/platform-resources.js +133 -0
  52. package/dist/platform.d.ts +2 -0
  53. package/dist/platform.js +16 -0
  54. package/dist/plugin-default.d.ts +1 -0
  55. package/dist/plugin-default.js +4 -0
  56. package/dist/railway.d.ts +1 -0
  57. package/dist/railway.js +4 -0
  58. package/dist/scripts/build-dist.js +7 -0
  59. package/dist/scripts/dev-platform.js +24 -0
  60. package/dist/scripts/workspace-bootstrap.js +24 -10
  61. package/dist/site-resources.d.ts +1 -29
  62. package/dist/site-resources.js +7 -120
  63. package/dist/site.js +3 -1
  64. package/package.json +37 -3
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @treeseed/core
2
2
 
3
- `@treeseed/core` is the Treeseed Research Hub package for Astro/Starlight sites. It contains the published site runtime, shared components and styles, the knowledge-factory content model, and the Astro-specific forms stack used by Treeseed tenants.
3
+ `@treeseed/core` is the Treeseed integrated platform starter for Astro/Starlight sites and Hono API runtimes. It contains the published web runtime, API runtime, integrated local dev orchestration, shared components and styles, the knowledge-factory content model, and the forms stack used by Treeseed tenants.
4
4
 
5
5
  This repository is the package root. Run package commands from [`core`](./), not from the top-level `treeseed` workspace.
6
6
 
@@ -54,6 +54,9 @@ This keeps the shared fixture canonical while preserving Core’s package bounda
54
54
  ### Core development
55
55
 
56
56
  ```bash
57
+ npm run dev
58
+ npm run dev:web
59
+ npm run dev:api
57
60
  npm run fixtures:check
58
61
  npm run build:dist
59
62
  npm run test:unit
@@ -64,6 +67,9 @@ npm run test:smoke
64
67
 
65
68
  What they do:
66
69
 
70
+ - `dev`: starts the integrated Astro UI and Hono API local runtime from `core`
71
+ - `dev:web`: starts only the Astro UI dev surface through the `core` runtime
72
+ - `dev:api`: starts only the Hono API dev surface through the `core` runtime
67
73
  - `fixtures:check`: verifies that the pinned shared fixture is initialized and usable
68
74
  - `build:dist`: builds the publishable `dist/` package output
69
75
  - `test:unit`: runs package unit tests with Vitest
@@ -0,0 +1,13 @@
1
+ import type { Hono } from 'hono';
2
+ import type { AgentSdk } from '@treeseed/sdk';
3
+ import type { GatewayQueueProducer } from './types.ts';
4
+ interface RegisterAgentRoutesOptions {
5
+ sdk: AgentSdk;
6
+ prefix?: string;
7
+ scope?: string | null;
8
+ projectId?: string;
9
+ queueProducer?: GatewayQueueProducer;
10
+ defaultActor?: string;
11
+ }
12
+ export declare function registerAgentRoutes(app: Hono<any>, options: RegisterAgentRoutesOptions): void;
13
+ export {};
@@ -0,0 +1,402 @@
1
+ import crypto from "node:crypto";
2
+ import { jsonError, requireScope } from "./http.js";
3
+ async function importOptionalAgentRuntime() {
4
+ try {
5
+ const dynamicImport = new Function("specifier", "return import(specifier)");
6
+ return await dynamicImport("@treeseed/agent");
7
+ } catch {
8
+ return null;
9
+ }
10
+ }
11
+ async function listRegisteredHandlers() {
12
+ const agent = await importOptionalAgentRuntime();
13
+ return agent?.listRegisteredAgentHandlers?.() ?? [];
14
+ }
15
+ function queueEnvelopeForTask(task) {
16
+ return {
17
+ messageId: crypto.randomUUID(),
18
+ taskId: String(task.id ?? ""),
19
+ workDayId: String(task.workDayId ?? task.work_day_id ?? ""),
20
+ agentId: String(task.agentId ?? task.agent_id ?? ""),
21
+ taskType: String(task.type ?? ""),
22
+ idempotencyKey: String(task.idempotencyKey ?? task.idempotency_key ?? ""),
23
+ attempt: Number(task.attemptCount ?? task.attempt_count ?? 0) + 1,
24
+ payloadRef: `d1:tasks/${String(task.id ?? "")}`,
25
+ graphVersion: task.graphVersion !== void 0 && task.graphVersion !== null ? String(task.graphVersion) : task.graph_version !== void 0 && task.graph_version !== null ? String(task.graph_version) : null,
26
+ budgetHint: 1
27
+ };
28
+ }
29
+ function withPrefix(prefix, path) {
30
+ return `${prefix}${path}`.replace(/\/{2,}/g, "/");
31
+ }
32
+ function actor(body, fallback) {
33
+ return String(body.actor ?? fallback);
34
+ }
35
+ async function enqueueTask(options, request) {
36
+ if (!options.queueProducer) {
37
+ throw new Error("Queue producer not configured.");
38
+ }
39
+ const task = await options.sdk.get({ model: "task", id: request.taskId });
40
+ if (!task.payload) {
41
+ throw new Error("Unknown task.");
42
+ }
43
+ await options.queueProducer.enqueue({
44
+ queueName: request.queueName,
45
+ message: queueEnvelopeForTask(task.payload),
46
+ delaySeconds: request.deliveryDelaySeconds ?? 0
47
+ });
48
+ await options.sdk.recordTaskProgress({
49
+ id: request.taskId,
50
+ state: "queued",
51
+ appendEvent: { kind: "queued", data: { queueName: request.queueName ?? null } },
52
+ actor: request.actor
53
+ });
54
+ return { ok: true, taskId: request.taskId, queued: true };
55
+ }
56
+ async function buildTaskContext(sdk, taskId) {
57
+ const context = await sdk.getManagerContext(taskId);
58
+ const task = context.payload.task;
59
+ const agent = task ? (await sdk.get({ model: "agent", slug: String(task.agentId) })).payload : null;
60
+ return {
61
+ ...context.payload,
62
+ agent
63
+ };
64
+ }
65
+ function registerAgentRoutes(app, options) {
66
+ const prefix = options.prefix ?? "/agent";
67
+ const defaultActor = options.defaultActor ?? "api";
68
+ app.get(withPrefix(prefix, "/healthz"), async (c) => c.json({
69
+ ok: true,
70
+ service: "treeseed-agent-api",
71
+ handlerCount: (await listRegisteredHandlers()).length
72
+ }));
73
+ app.get(withPrefix(prefix, "/specs"), async (c) => {
74
+ if (options.scope) {
75
+ const unauthorized = requireScope(c, options.scope);
76
+ if (unauthorized) return unauthorized;
77
+ }
78
+ const payload = await options.sdk.listAgentSpecs({ enabled: true });
79
+ return c.json({
80
+ ok: true,
81
+ payload,
82
+ handlers: await listRegisteredHandlers()
83
+ });
84
+ });
85
+ app.post(withPrefix(prefix, "/workdays/start"), async (c) => {
86
+ if (options.scope) {
87
+ const unauthorized = requireScope(c, options.scope);
88
+ if (unauthorized) return unauthorized;
89
+ }
90
+ const body = await c.req.json().catch(() => ({}));
91
+ const graphRefresh = await options.sdk.refreshGraph();
92
+ const result = await options.sdk.startWorkDay({
93
+ id: typeof body.id === "string" ? body.id : void 0,
94
+ projectId: String(body.projectId ?? options.projectId ?? "treeseed-market"),
95
+ capacityBudget: body.capacityBudget === void 0 ? void 0 : Number(body.capacityBudget),
96
+ graphVersion: typeof body.graphVersion === "string" ? body.graphVersion : graphRefresh.snapshotRoot,
97
+ summary: body.summary ?? { graphRefresh },
98
+ actor: actor(body, defaultActor)
99
+ });
100
+ return c.json(result);
101
+ });
102
+ app.post(withPrefix(prefix, "/workdays/:id/close"), async (c) => {
103
+ if (options.scope) {
104
+ const unauthorized = requireScope(c, options.scope);
105
+ if (unauthorized) return unauthorized;
106
+ }
107
+ const body = await c.req.json().catch(() => ({}));
108
+ const result = await options.sdk.closeWorkDay({
109
+ id: c.req.param("id"),
110
+ state: body.state,
111
+ summary: body.summary ?? null,
112
+ actor: actor(body, defaultActor)
113
+ });
114
+ return result.payload ? c.json(result) : jsonError(c, 404, "Unknown work day.");
115
+ });
116
+ app.post(withPrefix(prefix, "/tasks"), async (c) => {
117
+ if (options.scope) {
118
+ const unauthorized = requireScope(c, options.scope);
119
+ if (unauthorized) return unauthorized;
120
+ }
121
+ const body = await c.req.json().catch(() => ({}));
122
+ const result = await options.sdk.createTask({
123
+ id: typeof body.id === "string" ? body.id : void 0,
124
+ workDayId: String(body.workDayId ?? ""),
125
+ agentId: String(body.agentId ?? ""),
126
+ type: String(body.type ?? ""),
127
+ state: typeof body.state === "string" ? body.state : "pending",
128
+ priority: body.priority === void 0 ? void 0 : Number(body.priority),
129
+ idempotencyKey: String(body.idempotencyKey ?? ""),
130
+ payload: body.payload ?? {},
131
+ payloadHash: typeof body.payloadHash === "string" ? body.payloadHash : null,
132
+ maxAttempts: body.maxAttempts === void 0 ? void 0 : Number(body.maxAttempts),
133
+ availableAt: typeof body.availableAt === "string" ? body.availableAt : void 0,
134
+ graphVersion: typeof body.graphVersion === "string" ? body.graphVersion : null,
135
+ parentTaskId: typeof body.parentTaskId === "string" ? body.parentTaskId : null,
136
+ actor: actor(body, defaultActor)
137
+ });
138
+ return c.json(result);
139
+ });
140
+ app.post(withPrefix(prefix, "/tasks/search"), async (c) => {
141
+ if (options.scope) {
142
+ const unauthorized = requireScope(c, options.scope);
143
+ if (unauthorized) return unauthorized;
144
+ }
145
+ const body = await c.req.json().catch(() => ({}));
146
+ const result = await options.sdk.searchTasks({
147
+ workDayId: typeof body.workDayId === "string" ? body.workDayId : void 0,
148
+ agentId: typeof body.agentId === "string" ? body.agentId : void 0,
149
+ state: Array.isArray(body.state) || typeof body.state === "string" ? body.state : void 0,
150
+ limit: body.limit === void 0 ? void 0 : Number(body.limit)
151
+ });
152
+ return c.json(result);
153
+ });
154
+ app.post(withPrefix(prefix, "/tasks/:id/claim"), async (c) => {
155
+ if (options.scope) {
156
+ const unauthorized = requireScope(c, options.scope);
157
+ if (unauthorized) return unauthorized;
158
+ }
159
+ const body = await c.req.json().catch(() => ({}));
160
+ const result = await options.sdk.claimTask({
161
+ id: c.req.param("id"),
162
+ workerId: String(body.workerId ?? "worker"),
163
+ leaseSeconds: Number(body.leaseSeconds ?? 120),
164
+ actor: actor(body, defaultActor)
165
+ });
166
+ return result.payload ? c.json(result) : jsonError(c, 404, "Unknown task.");
167
+ });
168
+ app.post(withPrefix(prefix, "/tasks/:id/progress"), async (c) => {
169
+ if (options.scope) {
170
+ const unauthorized = requireScope(c, options.scope);
171
+ if (unauthorized) return unauthorized;
172
+ }
173
+ const body = await c.req.json().catch(() => ({}));
174
+ const result = await options.sdk.recordTaskProgress({
175
+ id: c.req.param("id"),
176
+ workerId: typeof body.workerId === "string" ? body.workerId : null,
177
+ state: typeof body.state === "string" ? body.state : void 0,
178
+ appendEvent: body.appendEvent,
179
+ patch: body.patch,
180
+ actor: actor(body, defaultActor)
181
+ });
182
+ return result.payload ? c.json(result) : jsonError(c, 404, "Unknown task.");
183
+ });
184
+ app.post(withPrefix(prefix, "/tasks/:id/complete"), async (c) => {
185
+ if (options.scope) {
186
+ const unauthorized = requireScope(c, options.scope);
187
+ if (unauthorized) return unauthorized;
188
+ }
189
+ const body = await c.req.json().catch(() => ({}));
190
+ const result = await options.sdk.completeTask({
191
+ id: c.req.param("id"),
192
+ output: body.output ?? null,
193
+ outputRef: typeof body.outputRef === "string" ? body.outputRef : null,
194
+ summary: body.summary ?? null,
195
+ actor: actor(body, defaultActor)
196
+ });
197
+ return result.payload ? c.json(result) : jsonError(c, 404, "Unknown task.");
198
+ });
199
+ app.post(withPrefix(prefix, "/tasks/:id/fail"), async (c) => {
200
+ if (options.scope) {
201
+ const unauthorized = requireScope(c, options.scope);
202
+ if (unauthorized) return unauthorized;
203
+ }
204
+ const body = await c.req.json().catch(() => ({}));
205
+ const result = await options.sdk.failTask({
206
+ id: c.req.param("id"),
207
+ errorCode: typeof body.errorCode === "string" ? body.errorCode : null,
208
+ errorMessage: String(body.errorMessage ?? "Task failed"),
209
+ retryable: Boolean(body.retryable),
210
+ nextVisibleAt: typeof body.nextVisibleAt === "string" ? body.nextVisibleAt : null,
211
+ actor: actor(body, defaultActor)
212
+ });
213
+ return result.payload ? c.json(result) : jsonError(c, 404, "Unknown task.");
214
+ });
215
+ app.post(withPrefix(prefix, "/tasks/:id/requeue"), async (c) => {
216
+ if (options.scope) {
217
+ const unauthorized = requireScope(c, options.scope);
218
+ if (unauthorized) return unauthorized;
219
+ }
220
+ const body = await c.req.json().catch(() => ({}));
221
+ try {
222
+ return c.json(await enqueueTask(options, {
223
+ taskId: c.req.param("id"),
224
+ queueName: typeof body.queueName === "string" ? body.queueName : void 0,
225
+ deliveryDelaySeconds: body.delaySeconds === void 0 ? void 0 : Number(body.delaySeconds),
226
+ actor: actor(body, defaultActor)
227
+ }));
228
+ } catch (error) {
229
+ const message = error instanceof Error ? error.message : String(error);
230
+ return jsonError(c, /Unknown task/.test(message) ? 404 : /Queue producer/.test(message) ? 501 : 500, message);
231
+ }
232
+ });
233
+ app.post(withPrefix(prefix, "/tasks/:id/followups"), async (c) => {
234
+ if (options.scope) {
235
+ const unauthorized = requireScope(c, options.scope);
236
+ if (unauthorized) return unauthorized;
237
+ }
238
+ const body = await c.req.json().catch(() => ({}));
239
+ const current = await options.sdk.get({ model: "task", id: c.req.param("id") });
240
+ if (!current.payload) {
241
+ return jsonError(c, 404, "Unknown task.");
242
+ }
243
+ const currentTask = current.payload;
244
+ const followups = Array.isArray(body.followups) ? body.followups : [];
245
+ const created = [];
246
+ for (const followup of followups) {
247
+ created.push(await options.sdk.createTask({
248
+ workDayId: String(followup.workDayId ?? currentTask.workDayId ?? ""),
249
+ agentId: String(followup.agentId ?? currentTask.agentId ?? ""),
250
+ type: String(followup.type ?? "followup"),
251
+ priority: followup.priority === void 0 ? void 0 : Number(followup.priority),
252
+ idempotencyKey: String(followup.idempotencyKey ?? `${c.req.param("id")}:${created.length}`),
253
+ payload: followup.payload ?? {},
254
+ graphVersion: typeof followup.graphVersion === "string" ? followup.graphVersion : null,
255
+ parentTaskId: c.req.param("id"),
256
+ actor: actor(followup, defaultActor)
257
+ }));
258
+ }
259
+ return c.json({ ok: true, payload: created.map((entry) => entry.payload) });
260
+ });
261
+ app.post(withPrefix(prefix, "/queue/enqueue"), async (c) => {
262
+ if (options.scope) {
263
+ const unauthorized = requireScope(c, options.scope);
264
+ if (unauthorized) return unauthorized;
265
+ }
266
+ const body = await c.req.json().catch(() => ({}));
267
+ try {
268
+ return c.json(await enqueueTask(options, {
269
+ taskId: String(body.taskId ?? ""),
270
+ queueName: typeof body.queueName === "string" ? body.queueName : void 0,
271
+ deliveryDelaySeconds: body.deliveryDelaySeconds === void 0 ? void 0 : Number(body.deliveryDelaySeconds),
272
+ actor: actor(body, defaultActor)
273
+ }));
274
+ } catch (error) {
275
+ const message = error instanceof Error ? error.message : String(error);
276
+ return jsonError(c, /Unknown task/.test(message) ? 404 : /Queue producer/.test(message) ? 501 : 500, message);
277
+ }
278
+ });
279
+ app.post(withPrefix(prefix, "/reports"), async (c) => {
280
+ if (options.scope) {
281
+ const unauthorized = requireScope(c, options.scope);
282
+ if (unauthorized) return unauthorized;
283
+ }
284
+ const body = await c.req.json().catch(() => ({}));
285
+ const result = await options.sdk.createReport({
286
+ id: typeof body.id === "string" ? body.id : void 0,
287
+ workDayId: String(body.workDayId ?? ""),
288
+ kind: String(body.kind ?? "workday_summary"),
289
+ body: body.body ?? {},
290
+ renderedRef: typeof body.renderedRef === "string" ? body.renderedRef : null,
291
+ sentAt: typeof body.sentAt === "string" ? body.sentAt : null,
292
+ actor: actor(body, defaultActor)
293
+ });
294
+ return c.json(result);
295
+ });
296
+ app.post(withPrefix(prefix, "/context/resolve-task"), async (c) => {
297
+ if (options.scope) {
298
+ const unauthorized = requireScope(c, options.scope);
299
+ if (unauthorized) return unauthorized;
300
+ }
301
+ const body = await c.req.json().catch(() => ({}));
302
+ return c.json({
303
+ ok: true,
304
+ payload: await buildTaskContext(options.sdk, String(body.taskId ?? ""))
305
+ });
306
+ });
307
+ app.post(withPrefix(prefix, "/graph/search"), async (c) => {
308
+ if (options.scope) {
309
+ const unauthorized = requireScope(c, options.scope);
310
+ if (unauthorized) return unauthorized;
311
+ }
312
+ const body = await c.req.json().catch(() => ({}));
313
+ const query = String(body.query ?? "");
314
+ const scope = String(body.scope ?? "sections");
315
+ const payload = scope === "files" ? await options.sdk.searchFiles(query, body.options) : scope === "entities" ? await options.sdk.searchEntities(query, body.options) : await options.sdk.searchSections(query, body.options);
316
+ return c.json({ ok: true, payload });
317
+ });
318
+ app.post(withPrefix(prefix, "/graph/subgraph"), async (c) => {
319
+ if (options.scope) {
320
+ const unauthorized = requireScope(c, options.scope);
321
+ if (unauthorized) return unauthorized;
322
+ }
323
+ const body = await c.req.json().catch(() => ({}));
324
+ const payload = await options.sdk.getSubgraph(
325
+ Array.isArray(body.seedIds) ? body.seedIds.map(String) : [],
326
+ body.options
327
+ );
328
+ return c.json({ ok: true, payload });
329
+ });
330
+ app.post(withPrefix(prefix, "/graph/query"), async (c) => {
331
+ if (options.scope) {
332
+ const unauthorized = requireScope(c, options.scope);
333
+ if (unauthorized) return unauthorized;
334
+ }
335
+ const body = await c.req.json().catch(() => ({}));
336
+ const payload = await options.sdk.queryGraph(body);
337
+ if (typeof body.workDayId === "string" && body.workDayId) {
338
+ await options.sdk.create({
339
+ model: "graph_run",
340
+ data: {
341
+ workDayId: body.workDayId,
342
+ corpusHash: String(body.corpusHash ?? "query-graph"),
343
+ graphVersion: String(body.graphVersion ?? ""),
344
+ queryJson: JSON.stringify(body),
345
+ seedIdsJson: JSON.stringify(payload.seedIds),
346
+ selectedNodeIdsJson: JSON.stringify(payload.nodes.map((entry) => entry.node.id)),
347
+ statsJson: JSON.stringify({ nodeCount: payload.nodes.length, edgeCount: payload.edges.length })
348
+ },
349
+ actor: actor(body, defaultActor)
350
+ });
351
+ }
352
+ return c.json({ ok: true, payload });
353
+ });
354
+ app.post(withPrefix(prefix, "/graph/context-pack"), async (c) => {
355
+ if (options.scope) {
356
+ const unauthorized = requireScope(c, options.scope);
357
+ if (unauthorized) return unauthorized;
358
+ }
359
+ const body = await c.req.json().catch(() => ({}));
360
+ const payload = await options.sdk.buildContextPack(body);
361
+ if (typeof body.workDayId === "string" && body.workDayId) {
362
+ await options.sdk.create({
363
+ model: "graph_run",
364
+ data: {
365
+ workDayId: body.workDayId,
366
+ corpusHash: String(body.corpusHash ?? "context-pack"),
367
+ graphVersion: String(body.graphVersion ?? ""),
368
+ queryJson: JSON.stringify(body),
369
+ seedIdsJson: JSON.stringify(payload.seedIds),
370
+ selectedNodeIdsJson: JSON.stringify(payload.includedNodeIds),
371
+ statsJson: JSON.stringify({
372
+ nodeCount: payload.nodes.length,
373
+ edgeCount: payload.edges.length,
374
+ totalTokenEstimate: payload.totalTokenEstimate
375
+ })
376
+ },
377
+ actor: actor(body, defaultActor)
378
+ });
379
+ }
380
+ return c.json({ ok: true, payload });
381
+ });
382
+ app.post(withPrefix(prefix, "/graph/parse-dsl"), async (c) => {
383
+ if (options.scope) {
384
+ const unauthorized = requireScope(c, options.scope);
385
+ if (unauthorized) return unauthorized;
386
+ }
387
+ const body = await c.req.json().catch(() => ({}));
388
+ const payload = await options.sdk.parseGraphDsl(String(body.source ?? body.query ?? ""));
389
+ return c.json({ ok: true, payload });
390
+ });
391
+ app.get(withPrefix(prefix, "/graph/node/:id"), async (c) => {
392
+ if (options.scope) {
393
+ const unauthorized = requireScope(c, options.scope);
394
+ if (unauthorized) return unauthorized;
395
+ }
396
+ const payload = await options.sdk.getGraphNode(c.req.param("id"));
397
+ return payload ? c.json({ ok: true, payload }) : jsonError(c, 404, "Unknown graph node.");
398
+ });
399
+ }
400
+ export {
401
+ registerAgentRoutes
402
+ };
@@ -0,0 +1,5 @@
1
+ import { Hono } from 'hono';
2
+ import type { ApiServerOptions, AppVariables } from './types.ts';
3
+ export declare function createTreeseedApiApp(options?: ApiServerOptions): Hono<{
4
+ Variables: AppVariables;
5
+ }, import("hono/types").BlankSchema, "/">;