@treeseed/core 0.8.2 → 0.8.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 (133) hide show
  1. package/README.md +7 -11
  2. package/dist/dev-watch.js +1 -1
  3. package/dist/dev.d.ts +2 -4
  4. package/dist/dev.js +4 -124
  5. package/dist/env.yaml +23 -175
  6. package/dist/index.d.ts +0 -4
  7. package/dist/index.js +0 -6
  8. package/dist/scripts/build-dist.js +3 -3
  9. package/dist/scripts/dev-platform.js +1 -7
  10. package/dist/scripts/run-fixture-astro-command.js +25 -51
  11. package/dist/scripts/test-smoke.js +50 -7
  12. package/package.json +5 -78
  13. package/templates/github/deploy-web.workflow.yml +106 -0
  14. package/templates/github/hosted-project.workflow.yml +4 -4
  15. package/dist/agent-runtime.d.ts +0 -17
  16. package/dist/agent-runtime.js +0 -117
  17. package/dist/agent.d.ts +0 -11
  18. package/dist/agent.js +0 -25
  19. package/dist/agents/adapters/execution.d.ts +0 -41
  20. package/dist/agents/adapters/execution.js +0 -73
  21. package/dist/agents/adapters/mutations.d.ts +0 -22
  22. package/dist/agents/adapters/mutations.js +0 -30
  23. package/dist/agents/adapters/notification.d.ts +0 -26
  24. package/dist/agents/adapters/notification.js +0 -46
  25. package/dist/agents/adapters/repository.d.ts +0 -23
  26. package/dist/agents/adapters/repository.js +0 -61
  27. package/dist/agents/adapters/research.d.ts +0 -26
  28. package/dist/agents/adapters/research.js +0 -59
  29. package/dist/agents/adapters/verification.d.ts +0 -36
  30. package/dist/agents/adapters/verification.js +0 -62
  31. package/dist/agents/cli-tools.d.ts +0 -1
  32. package/dist/agents/cli-tools.js +0 -5
  33. package/dist/agents/cli.d.ts +0 -15
  34. package/dist/agents/cli.js +0 -109
  35. package/dist/agents/contracts/messages.d.ts +0 -88
  36. package/dist/agents/contracts/messages.js +0 -138
  37. package/dist/agents/contracts/run.d.ts +0 -21
  38. package/dist/agents/contracts/run.js +0 -0
  39. package/dist/agents/index.d.ts +0 -1
  40. package/dist/agents/index.js +0 -5
  41. package/dist/agents/kernel/agent-kernel.d.ts +0 -51
  42. package/dist/agents/kernel/agent-kernel.js +0 -292
  43. package/dist/agents/kernel/trigger-resolver.d.ts +0 -19
  44. package/dist/agents/kernel/trigger-resolver.js +0 -157
  45. package/dist/agents/registry-helper.d.ts +0 -4
  46. package/dist/agents/registry-helper.js +0 -14
  47. package/dist/agents/registry.d.ts +0 -6
  48. package/dist/agents/registry.js +0 -98
  49. package/dist/agents/runtime-types.d.ts +0 -118
  50. package/dist/agents/runtime-types.js +0 -0
  51. package/dist/agents/spec-loader.d.ts +0 -18
  52. package/dist/agents/spec-loader.js +0 -55
  53. package/dist/agents/spec-normalizer.d.ts +0 -2
  54. package/dist/agents/spec-normalizer.js +0 -327
  55. package/dist/agents/spec-types.d.ts +0 -64
  56. package/dist/agents/spec-types.js +0 -0
  57. package/dist/agents/testing/agents-smoke.d.ts +0 -1
  58. package/dist/agents/testing/agents-smoke.js +0 -32
  59. package/dist/agents/testing/e2e-harness.d.ts +0 -44
  60. package/dist/agents/testing/e2e-harness.js +0 -504
  61. package/dist/api/agent-routes.d.ts +0 -13
  62. package/dist/api/agent-routes.js +0 -327
  63. package/dist/api/app.d.ts +0 -5
  64. package/dist/api/app.js +0 -361
  65. package/dist/api/auth/d1-database.d.ts +0 -3
  66. package/dist/api/auth/d1-database.js +0 -20
  67. package/dist/api/auth/d1-provider.d.ts +0 -79
  68. package/dist/api/auth/d1-provider.js +0 -92
  69. package/dist/api/auth/d1-store.d.ts +0 -114
  70. package/dist/api/auth/d1-store.js +0 -895
  71. package/dist/api/auth/memory-provider.d.ts +0 -77
  72. package/dist/api/auth/memory-provider.js +0 -249
  73. package/dist/api/auth/rbac.d.ts +0 -22
  74. package/dist/api/auth/rbac.js +0 -162
  75. package/dist/api/auth/tokens.d.ts +0 -18
  76. package/dist/api/auth/tokens.js +0 -56
  77. package/dist/api/capabilities.d.ts +0 -9
  78. package/dist/api/capabilities.js +0 -33
  79. package/dist/api/config.d.ts +0 -2
  80. package/dist/api/config.js +0 -77
  81. package/dist/api/http.d.ts +0 -28
  82. package/dist/api/http.js +0 -51
  83. package/dist/api/index.d.ts +0 -9
  84. package/dist/api/index.js +0 -18
  85. package/dist/api/operations-routes.d.ts +0 -11
  86. package/dist/api/operations-routes.js +0 -87
  87. package/dist/api/operations.d.ts +0 -3
  88. package/dist/api/operations.js +0 -26
  89. package/dist/api/project-routes.d.ts +0 -8
  90. package/dist/api/project-routes.js +0 -586
  91. package/dist/api/providers.d.ts +0 -2
  92. package/dist/api/providers.js +0 -62
  93. package/dist/api/railway.d.ts +0 -50
  94. package/dist/api/railway.js +0 -69
  95. package/dist/api/sdk-dispatch.d.ts +0 -5
  96. package/dist/api/sdk-dispatch.js +0 -13
  97. package/dist/api/sdk-routes.d.ts +0 -11
  98. package/dist/api/sdk-routes.js +0 -29
  99. package/dist/api/server.d.ts +0 -2
  100. package/dist/api/server.js +0 -10
  101. package/dist/api/templates.d.ts +0 -3
  102. package/dist/api/templates.js +0 -31
  103. package/dist/api/types.d.ts +0 -231
  104. package/dist/api/types.js +0 -0
  105. package/dist/api.d.ts +0 -1
  106. package/dist/api.js +0 -1
  107. package/dist/railway.d.ts +0 -1
  108. package/dist/railway.js +0 -4
  109. package/dist/services/agents.d.ts +0 -11
  110. package/dist/services/agents.js +0 -48
  111. package/dist/services/common.d.ts +0 -66
  112. package/dist/services/common.js +0 -212
  113. package/dist/services/index.d.ts +0 -6
  114. package/dist/services/index.js +0 -19
  115. package/dist/services/manager.d.ts +0 -267
  116. package/dist/services/manager.js +0 -1368
  117. package/dist/services/remote-runner.d.ts +0 -30
  118. package/dist/services/remote-runner.js +0 -230
  119. package/dist/services/workday-content.d.ts +0 -53
  120. package/dist/services/workday-content.js +0 -190
  121. package/dist/services/workday-manager.d.ts +0 -279
  122. package/dist/services/workday-manager.js +0 -163
  123. package/dist/services/workday-report.d.ts +0 -195
  124. package/dist/services/workday-report.js +0 -17
  125. package/dist/services/workday-start.d.ts +0 -195
  126. package/dist/services/workday-start.js +0 -17
  127. package/dist/services/worker-capacity.d.ts +0 -58
  128. package/dist/services/worker-capacity.js +0 -208
  129. package/dist/services/worker-pool-scaler.d.ts +0 -27
  130. package/dist/services/worker-pool-scaler.js +0 -127
  131. package/dist/services/worker.d.ts +0 -19
  132. package/dist/services/worker.js +0 -436
  133. package/templates/github/deploy.workflow.yml +0 -577
@@ -1,586 +0,0 @@
1
- import {
2
- buildKnowledgeCoopKnowledgePackPackage,
3
- buildKnowledgeCoopTemplatePackage,
4
- TreeseedWorkflowSdk
5
- } from "@treeseed/sdk";
6
- import {
7
- getTreeseedMachineConfigPaths,
8
- loadCliDeployConfig,
9
- loadTreeseedMachineConfig,
10
- resolveTreeseedRemoteSession
11
- } from "@treeseed/sdk/workflow-support";
12
- import { normalizeKnowledgeCoopJobStatus } from "@treeseed/sdk";
13
- import { requireTeamCapability } from "./capabilities.js";
14
- import { jsonError } from "./http.js";
15
- function withPrefix(prefix, path) {
16
- if (!prefix) return path;
17
- return `${prefix}${path}`.replace(/\/{2,}/g, "/");
18
- }
19
- function slugify(value) {
20
- return value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64) || "change";
21
- }
22
- function nowIso() {
23
- return (/* @__PURE__ */ new Date()).toISOString();
24
- }
25
- function asRecords(value) {
26
- return Array.isArray(value) ? value : [];
27
- }
28
- function readString(record, ...keys) {
29
- for (const key of keys) {
30
- const value = record[key];
31
- if (typeof value === "string" && value.trim()) return value.trim();
32
- }
33
- return "";
34
- }
35
- function readOptionalString(record, ...keys) {
36
- const value = readString(record, ...keys);
37
- return value || null;
38
- }
39
- function inferMessageKind(type, status) {
40
- if (status === "failed" || type.includes("failed")) return "warning";
41
- if (type.includes("waiting") || type.includes("review") || type.includes("release")) return "action_requested";
42
- if (type.includes("release_completed") || type.includes("task_verified")) return "release_readiness";
43
- return "informational";
44
- }
45
- async function summarizeDirect(sdk, projectId) {
46
- const [objectives, questions, notes, proposals, decisions, workstreams, releases] = await Promise.all([
47
- sdk.search({ model: "objective", sort: [{ field: "updated_at", direction: "desc" }], limit: 50 }),
48
- sdk.search({ model: "question", sort: [{ field: "updated_at", direction: "desc" }], limit: 50 }),
49
- sdk.search({ model: "note", sort: [{ field: "updated_at", direction: "desc" }], limit: 50 }),
50
- sdk.search({ model: "proposal", sort: [{ field: "updated_at", direction: "desc" }], limit: 50 }),
51
- sdk.search({ model: "decision", sort: [{ field: "updated_at", direction: "desc" }], limit: 50 }),
52
- sdk.listWorkstreams(projectId),
53
- sdk.listReleases(projectId)
54
- ]);
55
- const workstreamPayload = workstreams.payload ?? [];
56
- const releasePayload = releases.payload ?? [];
57
- const linkIndex = /* @__PURE__ */ new Map();
58
- for (const workstream of workstreamPayload) {
59
- for (const ref of workstream.linkedItems) {
60
- const key = `${ref.model}:${ref.id}`;
61
- const current = linkIndex.get(key) ?? { workstreamIds: [], releaseIds: [] };
62
- current.workstreamIds.push(workstream.id);
63
- linkIndex.set(key, current);
64
- }
65
- }
66
- for (const release of releasePayload) {
67
- for (const workstreamId of release.workstreamIds) {
68
- const workstream = workstreamPayload.find((entry) => entry.id === workstreamId);
69
- for (const ref of workstream?.linkedItems ?? []) {
70
- const key = `${ref.model}:${ref.id}`;
71
- const current = linkIndex.get(key) ?? { workstreamIds: [], releaseIds: [] };
72
- current.releaseIds.push(release.id);
73
- linkIndex.set(key, current);
74
- }
75
- }
76
- }
77
- const mapItems = (model, entries) => entries.slice(0, 15).map((entry) => {
78
- const id = readString(entry, "id", "slug");
79
- const links = linkIndex.get(`${model}:${id}`) ?? { workstreamIds: [], releaseIds: [] };
80
- return {
81
- model,
82
- id,
83
- title: readString(entry, "title", "name") || id,
84
- status: readOptionalString(entry, "status"),
85
- updatedAt: readOptionalString(entry, "updated_at", "updatedAt", "updated"),
86
- linkedWorkstreamIds: [...new Set(links.workstreamIds)],
87
- linkedReleaseIds: [...new Set(links.releaseIds)]
88
- };
89
- });
90
- return {
91
- projectId,
92
- objectiveCount: objectives.payload.length,
93
- questionCount: questions.payload.length,
94
- noteCount: notes.payload.length,
95
- proposalCount: proposals.payload.length,
96
- decisionCount: decisions.payload.length,
97
- savedViews: ["Now", "Blocked", "Ready for research", "Ready for build", "Release-linked"],
98
- items: [
99
- ...mapItems("objective", objectives.payload),
100
- ...mapItems("question", questions.payload),
101
- ...mapItems("note", notes.payload),
102
- ...mapItems("proposal", proposals.payload),
103
- ...mapItems("decision", decisions.payload)
104
- ].slice(0, 15)
105
- };
106
- }
107
- async function summarizeAgents(sdk, projectId) {
108
- const [specs, runs, messages] = await Promise.all([
109
- sdk.listAgentSpecs({ enabled: true }),
110
- sdk.search({ model: "agent_run", sort: [{ field: "startedAt", direction: "desc" }], limit: 100 }),
111
- sdk.search({ model: "message", sort: [{ field: "updated_at", direction: "desc" }], limit: 100 })
112
- ]);
113
- const workstreams = await sdk.listWorkstreams(projectId);
114
- const workstreamIds = new Set((workstreams.payload ?? []).map((entry) => entry.id));
115
- const agentStatuses = specs.map((spec) => {
116
- const latestRun = runs.payload.find((entry) => readString(entry, "agentSlug", "agent_slug") === spec.slug);
117
- const latestMessage = messages.payload.find((entry) => readString(entry, "type") && readString(entry, "payloadJson", "payload_json"));
118
- return {
119
- agentSlug: spec.slug,
120
- handler: spec.handler,
121
- status: readString(latestRun ?? {}, "status") === "failed" ? "failed" : readString(latestRun ?? {}, "status") === "running" ? "active" : latestRun ? "idle" : "waiting",
122
- currentTask: readOptionalString(latestRun ?? {}, "summary"),
123
- workstreamId: readOptionalString(latestRun ?? {}, "selectedItemKey"),
124
- lastMessage: readOptionalString(latestMessage ?? {}, "type"),
125
- lastRunAt: readOptionalString(latestRun ?? {}, "startedAt", "started_at", "finishedAt", "finished_at")
126
- };
127
- });
128
- const messageRecords = messages.payload.map((entry) => {
129
- const payloadJson = readString(entry, "payloadJson", "payload_json");
130
- let parsed = {};
131
- try {
132
- parsed = payloadJson ? JSON.parse(payloadJson) : {};
133
- } catch {
134
- parsed = {};
135
- }
136
- const workstreamId = typeof parsed.workstreamId === "string" && workstreamIds.has(parsed.workstreamId) ? parsed.workstreamId : null;
137
- return {
138
- id: String(entry.id ?? ""),
139
- agentSlug: readString(parsed, "agentSlug") || readString(entry, "relatedId", "related_id") || "agent",
140
- kind: inferMessageKind(readString(entry, "type"), readString(entry, "status")),
141
- type: readString(entry, "type"),
142
- status: readString(entry, "status") || "pending",
143
- summary: readString(parsed, "summary", "message", "failureSummary", "blockingReason") || readString(entry, "type"),
144
- workstreamId,
145
- releaseId: typeof parsed.releaseId === "string" ? parsed.releaseId : null,
146
- createdAt: readString(entry, "updated_at", "updatedAt", "created_at") || nowIso(),
147
- metadata: parsed
148
- };
149
- });
150
- return {
151
- projectId,
152
- agents: agentStatuses,
153
- messages: messageRecords
154
- };
155
- }
156
- async function summarizeProject(sdk, config, principal) {
157
- const [direct, workstreams, agents, releases, packages] = await Promise.all([
158
- summarizeDirect(sdk, config.projectId),
159
- sdk.listWorkstreams(config.projectId),
160
- summarizeAgents(sdk, config.projectId),
161
- sdk.listReleases(config.projectId),
162
- sdk.listSharePackages(config.projectId)
163
- ]);
164
- const workstreamPayload = workstreams.payload ?? [];
165
- const releasePayload = releases.payload ?? [];
166
- const packagePayload = packages.payload ?? [];
167
- const failedWorkstream = workstreamPayload.find((entry) => entry.verificationStatus === "failed");
168
- const releaseReady = releasePayload.find((entry) => entry.state === "ready_to_publish");
169
- const publishingDraft = packagePayload.find((entry) => entry.state === "ready_to_publish" || entry.state === "published");
170
- let projectConnection = {
171
- projectId: config.projectId,
172
- connection: null,
173
- connected: true,
174
- hubMode: null,
175
- runtimeMode: null,
176
- runtimeRegistration: null,
177
- runtimeAttached: false,
178
- runtimeReady: true,
179
- runnerReady: true,
180
- projectApiReady: true,
181
- mode: "disconnected"
182
- };
183
- try {
184
- const deployConfig = loadCliDeployConfig(config.repoRoot);
185
- const runtimeMode = deployConfig.runtime?.mode ?? "none";
186
- const runtimeRegistration = deployConfig.runtime?.registration ?? "none";
187
- const registrationEnabled = runtimeRegistration === "optional" || runtimeRegistration === "required";
188
- const { configPath } = getTreeseedMachineConfigPaths(config.repoRoot);
189
- const machineConfig = configPath ? loadTreeseedMachineConfig(config.repoRoot) : null;
190
- const marketSettings = machineConfig?.settings?.market && typeof machineConfig.settings.market === "object" ? machineConfig.settings.market : null;
191
- const runnerHostId = typeof marketSettings?.runnerHostId === "string" && marketSettings.runnerHostId.trim() ? marketSettings.runnerHostId.trim() : typeof marketSettings?.projectId === "string" && marketSettings.projectId.trim() ? `market-runner:${marketSettings.projectId.trim()}` : null;
192
- const runnerSession = runnerHostId ? resolveTreeseedRemoteSession(config.repoRoot, runnerHostId) : null;
193
- const runtimeReady = runtimeMode === "none" || !registrationEnabled || Boolean(
194
- marketSettings?.runnerReady === true || typeof runnerSession?.accessToken === "string" && runnerSession.accessToken.length > 0
195
- );
196
- projectConnection = {
197
- projectId: config.projectId,
198
- connection: null,
199
- connected: true,
200
- hubMode: deployConfig.hub?.mode ?? null,
201
- runtimeMode,
202
- runtimeRegistration,
203
- runtimeAttached: runtimeMode !== "none" && (!registrationEnabled || Boolean(marketSettings?.projectId)),
204
- runtimeReady,
205
- runnerReady: runtimeReady,
206
- projectApiReady: deployConfig.runtime?.mode !== "none",
207
- mode: runtimeMode === "treeseed_managed" ? "hosted" : runtimeMode === "byo_attached" ? registrationEnabled ? "hybrid" : "self_hosted" : "disconnected"
208
- };
209
- } catch {
210
- }
211
- const health = failedWorkstream ? { state: "verification_failing", label: "Verification failing", reason: failedWorkstream.verificationSummary ?? "A workstream verification failed." } : releaseReady ? { state: "release_ready", label: "Release ready", reason: "A release candidate is ready for approval." } : publishingDraft ? { state: "sharing_draft", label: "Sharing draft", reason: "A share package is ready for publishing." } : { state: "working_normally", label: "Working normally", reason: "Project workstreams and agents are operating normally." };
212
- const recentActivity = [
213
- ...workstreamPayload.map((entry) => ({
214
- kind: "workstream",
215
- id: entry.id,
216
- title: entry.title,
217
- status: entry.state,
218
- timestamp: entry.updatedAt,
219
- summary: entry.summary ?? entry.verificationSummary,
220
- metadata: { branchName: entry.branchName, linkedItems: entry.linkedItems }
221
- })),
222
- ...releasePayload.map((entry) => ({
223
- kind: "release",
224
- id: entry.id,
225
- title: entry.title ?? entry.version,
226
- status: entry.state,
227
- timestamp: entry.updatedAt,
228
- summary: entry.summary,
229
- metadata: { version: entry.version, releaseTag: entry.releaseTag }
230
- })),
231
- ...agents.messages.map((entry) => ({
232
- kind: "agent_message",
233
- id: entry.id,
234
- title: entry.type,
235
- status: entry.status,
236
- timestamp: entry.createdAt,
237
- summary: entry.summary,
238
- metadata: entry.metadata ?? {}
239
- }))
240
- ].sort((left, right) => String(right.timestamp ?? "").localeCompare(String(left.timestamp ?? ""))).slice(0, 20);
241
- return {
242
- projectId: config.projectId,
243
- teamId: String(principal?.metadata?.teamId ?? config.projectId),
244
- health,
245
- counts: {
246
- objectives: direct.objectiveCount,
247
- questions: direct.questionCount,
248
- notes: direct.noteCount,
249
- proposals: direct.proposalCount,
250
- decisions: direct.decisionCount,
251
- activeWorkstreams: workstreamPayload.filter((entry) => entry.state !== "archived").length,
252
- agents: agents.agents.length,
253
- releases: releasePayload.length
254
- },
255
- connection: {
256
- ...projectConnection
257
- },
258
- nextBestAction: releaseReady ? "Review the ready release and decide whether to publish." : failedWorkstream ? "Inspect the latest failed verification and update the workstream." : "Open Direct or Workstreams to continue work.",
259
- recentActivity
260
- };
261
- }
262
- function registerProjectRoutes(app, options) {
263
- const prefix = options.prefix ?? "";
264
- const workflow = new TreeseedWorkflowSdk({
265
- cwd: options.config.repoRoot,
266
- env: process.env,
267
- transport: "api"
268
- });
269
- app.get(withPrefix(prefix, "/v1/project/summary"), async (c) => {
270
- const principal = c.get("principal");
271
- if (!principal) return jsonError(c, 401, "Authentication required.");
272
- return c.json({
273
- ok: true,
274
- payload: await summarizeProject(options.sharedSdk, options.config, principal)
275
- });
276
- });
277
- app.get(withPrefix(prefix, "/v1/direct/summary"), async (c) => {
278
- const principal = c.get("principal");
279
- if (!principal) return jsonError(c, 401, "Authentication required.");
280
- return c.json({ ok: true, payload: await summarizeDirect(options.sharedSdk, options.config.projectId) });
281
- });
282
- app.get(withPrefix(prefix, "/v1/workstreams"), async (c) => {
283
- const principal = c.get("principal");
284
- if (!principal) return jsonError(c, 401, "Authentication required.");
285
- const items = await options.sharedSdk.listWorkstreams(options.config.projectId);
286
- return c.json({
287
- ok: true,
288
- payload: {
289
- projectId: options.config.projectId,
290
- items: items.payload,
291
- columns: ["Drafting", "Active locally", "Verifying", "Saved remotely", "In staging", "Archived"]
292
- }
293
- });
294
- });
295
- app.post(withPrefix(prefix, "/v1/workstreams"), async (c) => {
296
- const unauthorized = requireTeamCapability(c, "manage_workstreams");
297
- if (unauthorized) return unauthorized;
298
- const body = await c.req.json().catch(() => ({}));
299
- const title = typeof body.title === "string" && body.title.trim() ? body.title.trim() : "Untitled change";
300
- const branchName = typeof body.branchName === "string" && body.branchName.trim() ? body.branchName.trim() : `task/${slugify(title)}`;
301
- await workflow.switchTask({
302
- branchName,
303
- createIfMissing: true,
304
- preview: body.preview === true
305
- });
306
- const workstream = await options.sharedSdk.upsertWorkstream({
307
- projectId: options.config.projectId,
308
- title,
309
- summary: typeof body.summary === "string" ? body.summary : null,
310
- state: "active_local",
311
- branchName,
312
- branchRef: `refs/heads/${branchName}`,
313
- owner: typeof body.owner === "string" ? body.owner : c.get("principal")?.displayName ?? null,
314
- linkedItems: Array.isArray(body.linkedItems) ? body.linkedItems : [],
315
- metadata: typeof body.metadata === "object" && body.metadata ? body.metadata : {}
316
- });
317
- if (workstream.payload) {
318
- await options.sharedSdk.appendWorkstreamEvent({
319
- projectId: options.config.projectId,
320
- workstreamId: workstream.payload.id,
321
- kind: "created",
322
- summary: "Workstream created and branch activated.",
323
- data: { branchName }
324
- });
325
- }
326
- return c.json({ ok: true, payload: workstream.payload }, { status: 201 });
327
- });
328
- app.get(withPrefix(prefix, "/v1/workstreams/:id"), async (c) => {
329
- const principal = c.get("principal");
330
- if (!principal) return jsonError(c, 401, "Authentication required.");
331
- const detail = await options.sharedSdk.getWorkstream(c.req.param("id"));
332
- if (!detail.payload) return jsonError(c, 404, `Unknown workstream "${c.req.param("id")}".`);
333
- return c.json({ ok: true, payload: detail.payload });
334
- });
335
- app.post(withPrefix(prefix, "/v1/workstreams/:id/save"), async (c) => {
336
- const unauthorized = requireTeamCapability(c, "manage_workstreams");
337
- if (unauthorized) return unauthorized;
338
- const existing = await options.sharedSdk.getWorkstream(c.req.param("id"));
339
- if (!existing.payload) return jsonError(c, 404, `Unknown workstream "${c.req.param("id")}".`);
340
- const body = await c.req.json().catch(() => ({}));
341
- const result = await workflow.save({
342
- message: typeof body.message === "string" && body.message.trim() ? body.message.trim() : `Save ${existing.payload.title}`,
343
- verify: body.verify !== false,
344
- refreshPreview: body.refreshPreview === true
345
- });
346
- const updated = await options.sharedSdk.upsertWorkstream({
347
- ...existing.payload,
348
- state: body.verify === false ? "saved_remote" : "verifying",
349
- lastSaveAt: nowIso(),
350
- verificationStatus: result.ok ? "completed" : "failed",
351
- verificationSummary: result.summary ?? null
352
- });
353
- await options.sharedSdk.appendWorkstreamEvent({
354
- projectId: options.config.projectId,
355
- workstreamId: existing.payload.id,
356
- kind: "saved",
357
- summary: result.summary ?? "Workstream saved.",
358
- data: { workflow: result.payload ?? {} }
359
- });
360
- return c.json({ ok: true, payload: updated.payload });
361
- });
362
- app.post(withPrefix(prefix, "/v1/workstreams/:id/stage"), async (c) => {
363
- const unauthorized = requireTeamCapability(c, "stage_releases");
364
- if (unauthorized) return unauthorized;
365
- const existing = await options.sharedSdk.getWorkstream(c.req.param("id"));
366
- if (!existing.payload) return jsonError(c, 404, `Unknown workstream "${c.req.param("id")}".`);
367
- const body = await c.req.json().catch(() => ({}));
368
- const result = await workflow.stage({
369
- message: typeof body.message === "string" && body.message.trim() ? body.message.trim() : `Stage ${existing.payload.title}`
370
- });
371
- const updated = await options.sharedSdk.upsertWorkstream({
372
- ...existing.payload,
373
- state: "in_staging",
374
- lastStageAt: nowIso(),
375
- verificationStatus: result.ok ? "completed" : existing.payload.verificationStatus,
376
- verificationSummary: result.summary ?? existing.payload.verificationSummary
377
- });
378
- await options.sharedSdk.appendWorkstreamEvent({
379
- projectId: options.config.projectId,
380
- workstreamId: existing.payload.id,
381
- kind: "staged",
382
- summary: result.summary ?? "Workstream moved to staging.",
383
- data: { workflow: result.payload ?? {} }
384
- });
385
- return c.json({ ok: true, payload: updated.payload });
386
- });
387
- app.post(withPrefix(prefix, "/v1/workstreams/:id/archive"), async (c) => {
388
- const unauthorized = requireTeamCapability(c, "manage_workstreams");
389
- if (unauthorized) return unauthorized;
390
- const existing = await options.sharedSdk.getWorkstream(c.req.param("id"));
391
- if (!existing.payload) return jsonError(c, 404, `Unknown workstream "${c.req.param("id")}".`);
392
- const updated = await options.sharedSdk.upsertWorkstream({
393
- ...existing.payload,
394
- state: "archived",
395
- archivedAt: nowIso()
396
- });
397
- await options.sharedSdk.appendWorkstreamEvent({
398
- projectId: options.config.projectId,
399
- workstreamId: existing.payload.id,
400
- kind: "archived",
401
- summary: "Workstream archived.",
402
- data: {}
403
- });
404
- return c.json({ ok: true, payload: updated.payload });
405
- });
406
- app.get(withPrefix(prefix, "/v1/releases"), async (c) => {
407
- const principal = c.get("principal");
408
- if (!principal) return jsonError(c, 401, "Authentication required.");
409
- const releases = await options.sharedSdk.listReleases(options.config.projectId);
410
- const history = releases.payload;
411
- return c.json({
412
- ok: true,
413
- payload: {
414
- projectId: options.config.projectId,
415
- history,
416
- currentProd: history.find((entry) => entry.state === "published") ?? null,
417
- stagingCandidates: history.filter((entry) => entry.state === "ready_to_publish" || entry.state === "waiting_on_verification")
418
- }
419
- });
420
- });
421
- app.post(withPrefix(prefix, "/v1/releases"), async (c) => {
422
- const unauthorized = requireTeamCapability(c, "stage_releases");
423
- if (unauthorized) return unauthorized;
424
- const body = await c.req.json().catch(() => ({}));
425
- const workstreams = await options.sharedSdk.listWorkstreams(options.config.projectId);
426
- const selectedIds = Array.isArray(body.workstreamIds) ? body.workstreamIds.map(String) : workstreams.payload.filter((entry) => entry.state === "in_staging").map((entry) => entry.id);
427
- const release = await options.sharedSdk.upsertRelease({
428
- projectId: options.config.projectId,
429
- version: typeof body.version === "string" && body.version.trim() ? body.version.trim() : `draft-${Date.now()}`,
430
- title: typeof body.title === "string" ? body.title : null,
431
- state: "ready_to_publish",
432
- summary: typeof body.summary === "string" ? body.summary : null,
433
- workstreamIds: selectedIds,
434
- items: selectedIds.map((workstreamId) => ({
435
- id: `${workstreamId}-item`,
436
- workstreamId,
437
- model: null,
438
- recordId: null,
439
- summary: "Included workstream",
440
- createdAt: nowIso(),
441
- metadata: {}
442
- }))
443
- });
444
- return c.json({ ok: true, payload: release.payload }, { status: 201 });
445
- });
446
- app.get(withPrefix(prefix, "/v1/releases/:id"), async (c) => {
447
- const principal = c.get("principal");
448
- if (!principal) return jsonError(c, 401, "Authentication required.");
449
- const release = await options.sharedSdk.getRelease(c.req.param("id"));
450
- if (!release.payload) return jsonError(c, 404, `Unknown release "${c.req.param("id")}".`);
451
- return c.json({ ok: true, payload: release.payload });
452
- });
453
- app.post(withPrefix(prefix, "/v1/releases/:id/publish"), async (c) => {
454
- const unauthorized = requireTeamCapability(c, "publish_releases");
455
- if (unauthorized) return unauthorized;
456
- const release = await options.sharedSdk.getRelease(c.req.param("id"));
457
- if (!release.payload) return jsonError(c, 404, `Unknown release "${c.req.param("id")}".`);
458
- const body = await c.req.json().catch(() => ({}));
459
- const workflowResult = await workflow.release({
460
- bump: body.bump === "major" || body.bump === "minor" ? body.bump : "patch"
461
- });
462
- const updated = await options.sharedSdk.upsertRelease({
463
- ...release.payload,
464
- state: "published",
465
- publishedAt: nowIso(),
466
- releaseTag: readOptionalString(workflowResult.payload ?? {}, "version", "releaseTag")
467
- });
468
- return c.json({ ok: true, payload: updated.payload });
469
- });
470
- app.post(withPrefix(prefix, "/v1/releases/:id/rollback"), async (c) => {
471
- const unauthorized = requireTeamCapability(c, "publish_releases");
472
- if (unauthorized) return unauthorized;
473
- const release = await options.sharedSdk.getRelease(c.req.param("id"));
474
- if (!release.payload) return jsonError(c, 404, `Unknown release "${c.req.param("id")}".`);
475
- const updated = await options.sharedSdk.upsertRelease({
476
- ...release.payload,
477
- state: "rolled_back",
478
- rolledBackAt: nowIso()
479
- });
480
- return c.json({ ok: true, payload: updated.payload });
481
- });
482
- app.get(withPrefix(prefix, "/v1/share/status"), async (c) => {
483
- const principal = c.get("principal");
484
- if (!principal) return jsonError(c, 401, "Authentication required.");
485
- const packages = await options.sharedSdk.listSharePackages(options.config.projectId);
486
- return c.json({
487
- ok: true,
488
- payload: {
489
- projectId: options.config.projectId,
490
- packages: packages.payload,
491
- listing: null,
492
- canPublish: packages.payload.some((entry) => entry.state === "ready_to_publish" || entry.state === "published")
493
- }
494
- });
495
- });
496
- for (const [path, kind] of [
497
- ["/v1/share/export", "export"],
498
- ["/v1/share/package-template", "template"],
499
- ["/v1/share/package-knowledge-pack", "knowledge_pack"]
500
- ]) {
501
- app.post(withPrefix(prefix, path), async (c) => {
502
- const unauthorized = requireTeamCapability(c, "manage_products");
503
- if (unauthorized) return unauthorized;
504
- const body = await c.req.json().catch(() => ({}));
505
- const exportResult = kind === "export" ? await workflow.export({
506
- directory: typeof body.directory === "string" ? body.directory : void 0
507
- }) : null;
508
- const packageResult = kind === "template" ? buildKnowledgeCoopTemplatePackage(options.config.repoRoot, {
509
- id: typeof body.id === "string" ? body.id : void 0,
510
- title: typeof body.title === "string" && body.title.trim() ? body.title.trim() : void 0,
511
- summary: typeof body.summary === "string" ? body.summary : null,
512
- outputRoot: typeof body.outputRoot === "string" ? body.outputRoot : null,
513
- projectSlug: typeof body.projectSlug === "string" ? body.projectSlug : options.config.projectId,
514
- market: {
515
- publisherId: typeof c.get("principal")?.metadata?.teamId === "string" ? c.get("principal").metadata.teamId : null,
516
- publisherName: typeof c.get("principal")?.displayName === "string" ? c.get("principal").displayName : null,
517
- publishMetadata: {
518
- projectId: options.config.projectId,
519
- kind
520
- }
521
- }
522
- }) : kind === "knowledge_pack" ? buildKnowledgeCoopKnowledgePackPackage(options.config.repoRoot, {
523
- id: typeof body.id === "string" ? body.id : void 0,
524
- title: typeof body.title === "string" && body.title.trim() ? body.title.trim() : void 0,
525
- summary: typeof body.summary === "string" ? body.summary : null,
526
- outputRoot: typeof body.outputRoot === "string" ? body.outputRoot : null,
527
- projectSlug: typeof body.projectSlug === "string" ? body.projectSlug : options.config.projectId,
528
- includePaths: Array.isArray(body.includePaths) ? body.includePaths.map(String) : void 0,
529
- market: {
530
- publisherId: typeof c.get("principal")?.metadata?.teamId === "string" ? c.get("principal").metadata.teamId : null,
531
- publisherName: typeof c.get("principal")?.displayName === "string" ? c.get("principal").displayName : null,
532
- publishMetadata: {
533
- projectId: options.config.projectId,
534
- kind
535
- }
536
- }
537
- }) : null;
538
- const item = await options.sharedSdk.upsertSharePackage({
539
- projectId: options.config.projectId,
540
- kind,
541
- title: typeof body.title === "string" && body.title.trim() ? body.title.trim() : `${kind}-${Date.now()}`,
542
- summary: kind === "export" ? exportResult?.summary ?? null : packageResult?.manifest.summary ?? null,
543
- state: "ready_to_publish",
544
- version: kind === "export" ? null : packageResult?.manifest.version ?? null,
545
- outputPath: kind === "export" ? readOptionalString(exportResult?.payload ?? {}, "path", "outputPath", "directory") : packageResult?.outputRoot ?? null,
546
- artifactKey: kind === "export" ? null : packageResult?.payloadRoot ?? null,
547
- manifestKey: kind === "export" ? null : packageResult?.manifestPath ?? null,
548
- metadata: kind === "export" ? typeof exportResult?.payload === "object" && exportResult.payload ? exportResult.payload : {} : {
549
- manifest: packageResult?.manifest ?? null,
550
- files: packageResult?.files ?? [],
551
- payloadRoot: packageResult?.payloadRoot ?? null
552
- }
553
- });
554
- return c.json({ ok: true, payload: item.payload });
555
- });
556
- }
557
- app.post(withPrefix(prefix, "/v1/share/publish"), async (c) => {
558
- const unauthorized = requireTeamCapability(c, "publish_market_listings");
559
- if (unauthorized) return unauthorized;
560
- const body = await c.req.json().catch(() => ({}));
561
- const sharePackage = typeof body.packageId === "string" ? await options.sharedSdk.getSharePackage(body.packageId) : null;
562
- if (!sharePackage?.payload) {
563
- return jsonError(c, 404, "Unknown share package.");
564
- }
565
- const updated = await options.sharedSdk.upsertSharePackage({
566
- ...sharePackage.payload,
567
- state: "published"
568
- });
569
- return c.json({ ok: true, payload: updated.payload });
570
- });
571
- app.get(withPrefix(prefix, "/v1/agents/status"), async (c) => {
572
- const principal = c.get("principal");
573
- if (!principal) return jsonError(c, 401, "Authentication required.");
574
- const payload = await summarizeAgents(options.sharedSdk, options.config.projectId);
575
- return c.json({ ok: true, payload: { projectId: options.config.projectId, agents: payload.agents } });
576
- });
577
- app.get(withPrefix(prefix, "/v1/agents/messages"), async (c) => {
578
- const principal = c.get("principal");
579
- if (!principal) return jsonError(c, 401, "Authentication required.");
580
- const payload = await summarizeAgents(options.sharedSdk, options.config.projectId);
581
- return c.json({ ok: true, payload: payload.messages });
582
- });
583
- }
584
- export {
585
- registerProjectRoutes
586
- };
@@ -1,2 +0,0 @@
1
- import type { ApiConfig, ApiRuntimeProviders, ResolvedApiRuntimeProviders } from './types.ts';
2
- export declare function resolveApiRuntimeProviders(config: ApiConfig, overrides?: ApiRuntimeProviders): ResolvedApiRuntimeProviders;
@@ -1,62 +0,0 @@
1
- import { MemoryDeviceCodeAuthProvider } from "./auth/memory-provider.js";
2
- import { D1AuthProvider } from "./auth/d1-provider.js";
3
- import { resolveApiD1Database } from "./auth/d1-database.js";
4
- function addProviders(target, incoming, label) {
5
- for (const [id, value] of Object.entries(incoming ?? {})) {
6
- if (target.has(id)) {
7
- throw new Error(`Treeseed API runtime found duplicate ${label} provider "${id}".`);
8
- }
9
- target.set(id, value);
10
- }
11
- }
12
- function resolveSelectedProvider(registry, selectedId, label) {
13
- const selected = registry.get(selectedId);
14
- if (!selected) {
15
- throw new Error(`Treeseed API runtime could not resolve ${label} provider "${selectedId}".`);
16
- }
17
- return selected;
18
- }
19
- function resolveApiRuntimeProviders(config, overrides = {}) {
20
- const authRegistry = /* @__PURE__ */ new Map();
21
- const agentExecution = /* @__PURE__ */ new Map();
22
- const agentQueue = /* @__PURE__ */ new Map();
23
- const agentNotification = /* @__PURE__ */ new Map();
24
- const agentRepository = /* @__PURE__ */ new Map();
25
- const agentVerification = /* @__PURE__ */ new Map();
26
- addProviders(authRegistry, {
27
- memory: ({ config: runtimeConfig }) => new MemoryDeviceCodeAuthProvider(runtimeConfig),
28
- d1: ({ config: runtimeConfig }) => new D1AuthProvider(runtimeConfig, { db: resolveApiD1Database(runtimeConfig) })
29
- }, "auth");
30
- addProviders(authRegistry, overrides.auth, "auth");
31
- addProviders(agentExecution, { stub: { id: "stub" } }, "agent execution");
32
- addProviders(agentQueue, { memory: { id: "memory" } }, "agent queue");
33
- addProviders(agentNotification, { stub: { id: "stub" } }, "agent notification");
34
- addProviders(agentRepository, { stub: { id: "stub" } }, "agent repository");
35
- addProviders(agentVerification, { stub: { id: "stub" } }, "agent verification");
36
- addProviders(agentExecution, overrides.agentExecution, "agent execution");
37
- addProviders(agentQueue, overrides.agentQueue, "agent queue");
38
- addProviders(agentNotification, overrides.agentNotification, "agent notification");
39
- addProviders(agentRepository, overrides.agentRepository, "agent repository");
40
- addProviders(agentVerification, overrides.agentVerification, "agent verification");
41
- const authFactory = resolveSelectedProvider(authRegistry, config.providers.auth, "auth");
42
- resolveSelectedProvider(agentExecution, config.providers.agents.execution, "agent execution");
43
- resolveSelectedProvider(agentQueue, config.providers.agents.queue, "agent queue");
44
- resolveSelectedProvider(agentNotification, config.providers.agents.notification, "agent notification");
45
- resolveSelectedProvider(agentRepository, config.providers.agents.repository, "agent repository");
46
- resolveSelectedProvider(agentVerification, config.providers.agents.verification, "agent verification");
47
- return {
48
- auth: authFactory({ config }),
49
- registries: {
50
- auth: authRegistry,
51
- agentExecution,
52
- agentQueue,
53
- agentNotification,
54
- agentRepository,
55
- agentVerification
56
- },
57
- selections: config.providers
58
- };
59
- }
60
- export {
61
- resolveApiRuntimeProviders
62
- };