@treeseed/sdk 0.4.12 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/dist/control-plane-client.d.ts +60 -1
  2. package/dist/control-plane-client.js +59 -0
  3. package/dist/control-plane.d.ts +1 -1
  4. package/dist/control-plane.js +11 -4
  5. package/dist/d1-store.d.ts +58 -0
  6. package/dist/d1-store.js +64 -0
  7. package/dist/dispatch.js +6 -0
  8. package/dist/graph/schema.js +4 -0
  9. package/dist/index.d.ts +5 -1
  10. package/dist/index.js +32 -0
  11. package/dist/knowledge-coop.d.ts +223 -0
  12. package/dist/knowledge-coop.js +82 -0
  13. package/dist/model-registry.js +79 -0
  14. package/dist/operations/providers/default.js +128 -7
  15. package/dist/operations/services/config-runtime.d.ts +102 -24
  16. package/dist/operations/services/config-runtime.js +896 -160
  17. package/dist/operations/services/deploy.d.ts +223 -15
  18. package/dist/operations/services/deploy.js +626 -55
  19. package/dist/operations/services/git-workflow.d.ts +47 -3
  20. package/dist/operations/services/git-workflow.js +125 -19
  21. package/dist/operations/services/github-automation.d.ts +85 -0
  22. package/dist/operations/services/github-automation.js +220 -1
  23. package/dist/operations/services/key-agent.d.ts +118 -0
  24. package/dist/operations/services/key-agent.js +476 -0
  25. package/dist/operations/services/knowledge-coop-launch.d.ts +90 -0
  26. package/dist/operations/services/knowledge-coop-launch.js +753 -0
  27. package/dist/operations/services/knowledge-coop-packaging.d.ts +59 -0
  28. package/dist/operations/services/knowledge-coop-packaging.js +234 -0
  29. package/dist/operations/services/local-dev.d.ts +0 -1
  30. package/dist/operations/services/local-dev.js +1 -14
  31. package/dist/operations/services/project-platform.d.ts +42 -182
  32. package/dist/operations/services/project-platform.js +162 -59
  33. package/dist/operations/services/railway-deploy.d.ts +1 -0
  34. package/dist/operations/services/railway-deploy.js +31 -13
  35. package/dist/operations/services/runtime-tools.d.ts +52 -5
  36. package/dist/operations/services/runtime-tools.js +186 -26
  37. package/dist/operations/services/watch-dev.js +2 -4
  38. package/dist/operations/services/workspace-preflight.d.ts +4 -4
  39. package/dist/operations/services/workspace-preflight.js +22 -20
  40. package/dist/operations/services/workspace-save.d.ts +10 -1
  41. package/dist/operations/services/workspace-save.js +54 -3
  42. package/dist/operations/services/workspace-tools.d.ts +1 -0
  43. package/dist/operations/services/workspace-tools.js +20 -5
  44. package/dist/operations-registry.js +15 -8
  45. package/dist/operations-types.d.ts +2 -2
  46. package/dist/platform/contracts.d.ts +39 -3
  47. package/dist/platform/deploy-config.d.ts +12 -1
  48. package/dist/platform/deploy-config.js +214 -15
  49. package/dist/platform/deploy-runtime.d.ts +1 -0
  50. package/dist/platform/deploy-runtime.js +10 -2
  51. package/dist/platform/env.yaml +93 -61
  52. package/dist/platform/environment.d.ts +13 -2
  53. package/dist/platform/environment.js +90 -20
  54. package/dist/platform/plugins/constants.d.ts +1 -0
  55. package/dist/platform/plugins/constants.js +7 -6
  56. package/dist/platform/tenant/runtime-config.js +8 -1
  57. package/dist/platform/tenant-config.js +4 -0
  58. package/dist/platform/utils/site-config-schema.js +18 -0
  59. package/dist/plugin-default.js +2 -2
  60. package/dist/scripts/key-agent.js +165 -0
  61. package/dist/scripts/tenant-build.js +4 -1
  62. package/dist/scripts/tenant-check.js +4 -1
  63. package/dist/scripts/tenant-deploy.js +43 -4
  64. package/dist/scripts/tenant-dev.js +0 -1
  65. package/dist/scripts/workspace-start-warning.js +2 -2
  66. package/dist/sdk-types.d.ts +2 -2
  67. package/dist/sdk-types.js +2 -0
  68. package/dist/sdk.d.ts +13 -0
  69. package/dist/sdk.js +40 -0
  70. package/dist/stores/knowledge-coop-store.d.ts +56 -0
  71. package/dist/stores/knowledge-coop-store.js +482 -0
  72. package/dist/treeseed/template-catalog/templates/starter-basic/template/package.json +6 -2
  73. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/api/server.js +4 -0
  74. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/config.yaml +25 -0
  75. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content/decisions/adopt-initial-proposal-loop.mdx +22 -0
  76. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content/people/starter-steward.mdx +11 -0
  77. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content/proposals/establish-initial-proposal-loop.mdx +17 -0
  78. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/manifest.yaml +17 -10
  79. package/dist/treeseed/template-catalog/templates/starter-basic/template/treeseed.site.yaml +69 -7
  80. package/dist/treeseed/template-catalog/templates/starter-basic/template.config.json +1 -0
  81. package/dist/workflow/operations.d.ts +592 -243
  82. package/dist/workflow/operations.js +1908 -219
  83. package/dist/workflow/runs.d.ts +90 -0
  84. package/dist/workflow/runs.js +242 -0
  85. package/dist/workflow/session.d.ts +31 -0
  86. package/dist/workflow/session.js +97 -0
  87. package/dist/workflow-state.d.ts +88 -2
  88. package/dist/workflow-state.js +288 -26
  89. package/dist/workflow-support.d.ts +1 -1
  90. package/dist/workflow-support.js +32 -2
  91. package/dist/workflow.d.ts +93 -3
  92. package/dist/workflow.js +12 -0
  93. package/package.json +1 -1
  94. package/templates/github/deploy.workflow.yml +11 -1
  95. package/dist/scripts/sync-dev-vars.js +0 -6
  96. package/dist/scripts/workspace-close.js +0 -24
  97. package/dist/scripts/workspace-release.js +0 -42
  98. package/dist/scripts/workspace-start.js +0 -71
@@ -0,0 +1,753 @@
1
+ import { mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
2
+ import { spawnSync } from "node:child_process";
3
+ import { tmpdir } from "node:os";
4
+ import { dirname, join, resolve } from "node:path";
5
+ import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
6
+ import { checkTreeseedProviderConnections, collectTreeseedConfigSeedValues } from "./config-runtime.js";
7
+ import { provisionCloudflareResources, runRemoteD1Migrations, syncCloudflareSecrets, verifyProvisionedCloudflareResources, markDeploymentInitialized, finalizeDeploymentState } from "./deploy.js";
8
+ import {
9
+ createGitHubRepository,
10
+ ensureGitHubDeployAutomation,
11
+ initializeGitHubRepositoryWorkingTree,
12
+ resolveDefaultGitHubOwner
13
+ } from "./github-automation.js";
14
+ import { configuredRailwayServices, deployRailwayService, ensureRailwayScheduledJobs, validateRailwayDeployPrerequisites, verifyRailwayScheduledJobs } from "./railway-deploy.js";
15
+ import { loadCliDeployConfig } from "./runtime-tools.js";
16
+ import { templateCatalogRoot } from "./runtime-paths.js";
17
+ import { scaffoldTemplateProject } from "./template-registry.js";
18
+ import { buildKnowledgeCoopKnowledgePackPackage, buildKnowledgeCoopTemplatePackage, importKnowledgeCoopKnowledgePack } from "./knowledge-coop-packaging.js";
19
+ class KnowledgeCoopLaunchError extends Error {
20
+ phase;
21
+ phases;
22
+ constructor(phase, message, phases = []) {
23
+ super(message);
24
+ this.name = "KnowledgeCoopLaunchError";
25
+ this.phase = phase;
26
+ this.phases = [...phases];
27
+ }
28
+ }
29
+ function nowIso() {
30
+ return (/* @__PURE__ */ new Date()).toISOString();
31
+ }
32
+ function slugify(value, fallback = "project") {
33
+ return String(value ?? "").trim().toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "").replace(/-{2,}/g, "-").slice(0, 96) || fallback;
34
+ }
35
+ function envOrNull(name) {
36
+ const value = process.env[name];
37
+ return typeof value === "string" && value.trim() ? value.trim() : null;
38
+ }
39
+ function normalizeBaseUrl(value) {
40
+ return String(value ?? "").trim().replace(/\/+$/u, "");
41
+ }
42
+ function resolveManagedWebUrl(slug) {
43
+ const baseDomain = envOrNull("TREESEED_MANAGED_WEB_BASE_DOMAIN");
44
+ if (baseDomain) {
45
+ return `https://${slug}.${baseDomain.replace(/^https?:\/\//u, "").replace(/^\.|\/+$/gu, "")}`;
46
+ }
47
+ return `https://${slug}.pages.dev`;
48
+ }
49
+ function resolveManagedApiUrl(slug) {
50
+ const baseDomain = envOrNull("TREESEED_MANAGED_API_BASE_DOMAIN");
51
+ if (baseDomain) {
52
+ return `https://${slug}-api.${baseDomain.replace(/^https?:\/\//u, "").replace(/^\.|\/+$/gu, "")}`;
53
+ }
54
+ return `https://${slug}-api.up.railway.app`;
55
+ }
56
+ function ensureDir(path) {
57
+ mkdirSync(path, { recursive: true });
58
+ }
59
+ function runGit(cwd, args, capture = true) {
60
+ const result = spawnSync("git", args, {
61
+ cwd,
62
+ stdio: capture ? "pipe" : "inherit",
63
+ encoding: "utf8"
64
+ });
65
+ if (result.status !== 0) {
66
+ throw new Error(result.stderr?.trim() || result.stdout?.trim() || `git ${args.join(" ")} failed`);
67
+ }
68
+ return result;
69
+ }
70
+ function writeText(path, body) {
71
+ ensureDir(dirname(path));
72
+ writeFileSync(path, body, "utf8");
73
+ }
74
+ function updateYamlFile(path, updater) {
75
+ const parsed = parseYaml(readFileSync(path, "utf8"));
76
+ const next = updater(parsed ?? {});
77
+ writeText(path, stringifyYaml(next));
78
+ }
79
+ function currentTemplateCatalogUrl() {
80
+ return `file:${resolve(templateCatalogRoot, "catalog.fixture.json")}`;
81
+ }
82
+ function seedKnowledgeCoopContent(projectRoot, input) {
83
+ const objectiveId = `objective:launch-${slugify(input.projectSlug, "hub")}`;
84
+ const questionId = `question:operating-${slugify(input.projectSlug, "hub")}`;
85
+ const proposalId = `proposal:operating-${slugify(input.projectSlug, "hub")}`;
86
+ const decisionId = `decision:launch-${slugify(input.projectSlug, "hub")}`;
87
+ const stewardSlug = "launch-steward";
88
+ const noteSlug = `${slugify(input.projectSlug, "hub")}-operating-model`;
89
+ writeText(resolve(projectRoot, "src/content/people", `${stewardSlug}.mdx`), `---
90
+ name: Launch Steward
91
+ role: Team steward
92
+ affiliation: ${input.projectName}
93
+ status: live
94
+ tags:
95
+ - launch
96
+ - stewardship
97
+ ---
98
+
99
+ The launch steward keeps the first operating cycle legible while the hub moves from setup into active use.
100
+ `);
101
+ writeText(resolve(projectRoot, "src/content/objectives", "launch-knowledge-hub.mdx"), `---
102
+ id: ${objectiveId}
103
+ title: Launch ${input.projectName}
104
+ description: Bring the initial knowledge hub online with live managed infrastructure and a clear operating direction.
105
+ date: ${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}
106
+ summary: Stand up the hub, connect the runtime, and make the first workstream visible to the team.
107
+ status: live
108
+ timeHorizon: near-term
109
+ motivation: Knowledge Coop launches should create immediately usable hubs instead of leaving teams in setup limbo.
110
+ primaryContributor: ${stewardSlug}
111
+ ---
112
+
113
+ Launch ${input.projectName} as a living knowledge hub with real GitHub, Cloudflare, and Railway infrastructure.
114
+ `);
115
+ writeText(resolve(projectRoot, "src/content/questions", "what-should-the-first-release-cover.mdx"), `---
116
+ id: ${questionId}
117
+ title: What Should The First Release Cover?
118
+ description: Scope the first release around the foundation of the hub and the initial operating routines.
119
+ date: ${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}
120
+ summary: Define the first release around setup completion, clear direction, and baseline operating visibility.
121
+ status: live
122
+ questionType: strategy
123
+ motivation: The first release should make the new hub usable without burying the team under setup debt.
124
+ primaryContributor: ${stewardSlug}
125
+ relatedObjectives:
126
+ - launch-knowledge-hub
127
+ ---
128
+
129
+ The first release should verify that the hub is live, the core direction is visible, and the team can move from Direct into Workstreams without setup debt.
130
+ `);
131
+ writeText(resolve(projectRoot, "src/content/notes", `${noteSlug}.mdx`), `---
132
+ title: ${input.projectName} Operating Model
133
+ description: The initial working agreements for this Knowledge Coop hub.
134
+ date: ${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}
135
+ summary: Managed launch created the default branches, runtime wiring, and first operational checkpoints.
136
+ status: live
137
+ ---
138
+
139
+ This hub starts with a managed launch, a seeded objective, and a visible first workstream so the team can continue from a known baseline.
140
+ `);
141
+ writeText(resolve(projectRoot, "src/content/proposals", "establish-initial-operating-routine.mdx"), `---
142
+ id: ${proposalId}
143
+ title: Establish The Initial Operating Routine
144
+ description: Turn the seeded objective and question into a concrete launch proposal for the first team cycle.
145
+ date: ${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}
146
+ summary: Make the launch posture explicit so the team can move from setup into a concrete operating loop.
147
+ status: live
148
+ proposalType: strategy
149
+ motivation: Managed launches work better when the first suggested operating pattern is visible in the content model.
150
+ primaryContributor: ${stewardSlug}
151
+ relatedObjectives:
152
+ - launch-knowledge-hub
153
+ relatedQuestions:
154
+ - what-should-the-first-release-cover
155
+ relatedNotes:
156
+ - ${noteSlug}
157
+ decision: adopt-initial-launch-posture
158
+ ---
159
+
160
+ Adopt a simple first operating routine: keep direction visible, keep the first release narrow, and use notes to capture implementation reality as the hub stabilizes.
161
+ `);
162
+ writeText(resolve(projectRoot, "src/content/decisions", "adopt-initial-launch-posture.mdx"), `---
163
+ id: ${decisionId}
164
+ title: Adopt The Initial Launch Posture
165
+ description: Record the launch decision for the first operating cycle of the hub.
166
+ date: ${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}
167
+ summary: The managed launch will begin with a narrow first release and explicit direction artifacts.
168
+ status: live
169
+ decisionType: approved
170
+ rationale: The initial launch should bias toward clarity, setup completion, and a visible first release loop.
171
+ authority: Knowledge Coop managed launch
172
+ primaryContributor: ${stewardSlug}
173
+ relatedObjectives:
174
+ - launch-knowledge-hub
175
+ relatedQuestions:
176
+ - what-should-the-first-release-cover
177
+ relatedNotes:
178
+ - ${noteSlug}
179
+ relatedProposals:
180
+ - establish-initial-operating-routine
181
+ implements:
182
+ - direct
183
+ - workstreams
184
+ ---
185
+
186
+ The first cycle will keep direction and execution tightly connected: one seeded objective, one seeded question, one proposal, one recorded launch decision, and a narrow release target.
187
+ `);
188
+ writeText(resolve(projectRoot, "src/content/knowledge", "handbook", "index.mdx"), `---
189
+ id: knowledge:${slugify(input.projectSlug, "hub")}-handbook
190
+ title: ${input.projectName} Handbook
191
+ description: Welcome guide for the first team working in this hub.
192
+ type: guide
193
+ status: canonical
194
+ tags:
195
+ - handbook
196
+ - launch
197
+ canonical: true
198
+ domain: product
199
+ audience:
200
+ - maintainer
201
+ - contributor
202
+ ---
203
+
204
+ # ${input.projectName}
205
+
206
+ This knowledge hub was launched from Knowledge Coop and is ready for Direct, Workstreams, Releases, and Share workflows.
207
+ `);
208
+ writeText(resolve(projectRoot, "src/content/pages", "welcome.mdx"), `---
209
+ title: Welcome
210
+ description: ${input.projectName} is live.
211
+ pageLayout: article
212
+ stage: live
213
+ ---
214
+
215
+ # ${input.projectName}
216
+
217
+ This hub is live and ready for the first team release cycle.
218
+ `);
219
+ return {
220
+ objectiveId,
221
+ questionId,
222
+ proposalId,
223
+ decisionId,
224
+ noteSlug
225
+ };
226
+ }
227
+ function ensureHostedProjectFiles(projectRoot) {
228
+ const coreApiPackage = ["@treeseed", "core/api"].join("/");
229
+ writeText(resolve(projectRoot, "src/api/server.js"), `import { createRailwayTreeseedApiServer } from '${coreApiPackage}';
230
+
231
+ const server = await createRailwayTreeseedApiServer();
232
+ console.log(\`Treeseed project API listening on \${server.url}\`);
233
+ `);
234
+ }
235
+ function applyManagedProjectDefaults(projectRoot, input) {
236
+ const slug = slugify(input.projectSlug, "project");
237
+ const marketBaseUrl = normalizeBaseUrl(input.marketBaseUrl ?? envOrNull("TREESEED_MARKET_API_BASE_URL") ?? "https://knowledge.coop");
238
+ const siteUrl = resolveManagedWebUrl(slug);
239
+ const projectApiBaseUrl = normalizeBaseUrl(input.projectApiBaseUrl ?? resolveManagedApiUrl(slug));
240
+ const cloudflareAccountId = envOrNull("TREESEED_CLOUDFLARE_ACCOUNT_ID") ?? envOrNull("CLOUDFLARE_ACCOUNT_ID") ?? "replace-with-cloudflare-account-id";
241
+ const runtimeMode = input.hostingMode === "managed" ? "treeseed_managed" : input.hostingMode === "hybrid" ? "byo_attached" : "none";
242
+ const runtimeRegistration = input.hostingMode === "managed" ? "required" : input.hostingMode === "hybrid" ? "optional" : "none";
243
+ const hubMode = input.hostingMode === "self_hosted" ? "customer_hosted" : "treeseed_hosted";
244
+ const managedRuntime = runtimeMode === "treeseed_managed";
245
+ updateYamlFile(resolve(projectRoot, "treeseed.site.yaml"), (config) => ({
246
+ ...config,
247
+ name: input.projectName,
248
+ slug,
249
+ siteUrl,
250
+ contactEmail: input.contactEmail ?? config.contactEmail ?? `hello+${slug}@knowledge.coop`,
251
+ hub: {
252
+ mode: hubMode
253
+ },
254
+ runtime: {
255
+ mode: runtimeMode,
256
+ registration: runtimeRegistration,
257
+ marketBaseUrl,
258
+ teamId: input.teamId,
259
+ projectId: input.projectId
260
+ },
261
+ hosting: {
262
+ kind: managedRuntime ? "hosted_project" : "self_hosted_project",
263
+ registration: runtimeRegistration === "required" ? "optional" : runtimeRegistration,
264
+ marketBaseUrl,
265
+ teamId: input.teamId,
266
+ projectId: input.projectId
267
+ },
268
+ cloudflare: {
269
+ ...config.cloudflare ?? {},
270
+ accountId: cloudflareAccountId,
271
+ workerName: slug,
272
+ queueName: `${slug}-agent-work`,
273
+ dlqName: `${slug}-agent-work-dlq`,
274
+ pages: {
275
+ projectName: slug,
276
+ previewProjectName: `${slug}-staging`,
277
+ productionBranch: "main",
278
+ stagingBranch: "staging",
279
+ buildOutputDir: "dist",
280
+ ...(config.cloudflare ?? {}).pages ?? {}
281
+ },
282
+ r2: {
283
+ binding: "TREESEED_CONTENT_BUCKET",
284
+ bucketName: `${slug}-content`,
285
+ manifestKeyTemplate: "teams/{teamId}/published/common.json",
286
+ previewRootTemplate: "teams/{teamId}/previews",
287
+ previewTtlHours: 168,
288
+ ...(config.cloudflare ?? {}).r2 ?? {}
289
+ }
290
+ },
291
+ surfaces: {
292
+ web: {
293
+ enabled: true,
294
+ provider: "cloudflare",
295
+ rootDir: ".",
296
+ publicBaseUrl: siteUrl,
297
+ localBaseUrl: "http://127.0.0.1:4321",
298
+ ...config.surfaces?.web ?? {}
299
+ },
300
+ api: {
301
+ enabled: managedRuntime,
302
+ provider: managedRuntime ? "railway" : "none",
303
+ rootDir: ".",
304
+ localBaseUrl: "http://127.0.0.1:3000",
305
+ ...config.surfaces?.api ?? {}
306
+ }
307
+ },
308
+ services: {
309
+ api: {
310
+ enabled: managedRuntime,
311
+ provider: managedRuntime ? "railway" : "none",
312
+ rootDir: ".",
313
+ publicBaseUrl: projectApiBaseUrl,
314
+ railway: {
315
+ serviceName: `${slug}-api`,
316
+ buildCommand: "npm run build",
317
+ startCommand: "node ./src/api/server.js"
318
+ },
319
+ environments: {
320
+ local: {
321
+ baseUrl: "http://127.0.0.1:3000"
322
+ }
323
+ }
324
+ },
325
+ manager: {
326
+ enabled: managedRuntime,
327
+ provider: managedRuntime ? "railway" : "none",
328
+ railway: {
329
+ serviceName: `${slug}-manager`,
330
+ rootDir: ".",
331
+ buildCommand: "npm run build",
332
+ startCommand: "node ./node_modules/@treeseed/core/dist/services/manager.js",
333
+ schedule: "*/5 * * * *"
334
+ }
335
+ },
336
+ worker: {
337
+ enabled: managedRuntime,
338
+ provider: managedRuntime ? "railway" : "none",
339
+ railway: {
340
+ serviceName: `${slug}-worker`,
341
+ rootDir: ".",
342
+ buildCommand: "npm run build",
343
+ startCommand: "node ./node_modules/@treeseed/core/dist/services/worker.js"
344
+ }
345
+ },
346
+ workdayStart: {
347
+ enabled: managedRuntime,
348
+ provider: managedRuntime ? "railway" : "none",
349
+ railway: {
350
+ serviceName: `${slug}-workday-start`,
351
+ rootDir: ".",
352
+ buildCommand: "npm run build",
353
+ startCommand: "node ./node_modules/@treeseed/core/dist/services/workday-start.js",
354
+ schedule: "0 9 * * 1-5"
355
+ }
356
+ },
357
+ workdayReport: {
358
+ enabled: managedRuntime,
359
+ provider: managedRuntime ? "railway" : "none",
360
+ railway: {
361
+ serviceName: `${slug}-workday-report`,
362
+ rootDir: ".",
363
+ buildCommand: "npm run build",
364
+ startCommand: "node ./node_modules/@treeseed/core/dist/services/workday-report.js",
365
+ schedule: "5 17 * * 1-5"
366
+ }
367
+ },
368
+ ...config.services ?? {}
369
+ },
370
+ plugins: [{ package: "@treeseed/core/plugin-default" }],
371
+ providers: {
372
+ ...config.providers ?? {},
373
+ forms: config.providers?.forms ?? "store_only",
374
+ agents: {
375
+ execution: "copilot",
376
+ mutation: "local_branch",
377
+ repository: "git",
378
+ verification: "local",
379
+ notification: "sdk_message",
380
+ research: "project_graph",
381
+ ...config.providers?.agents ?? {}
382
+ },
383
+ deploy: "cloudflare",
384
+ content: {
385
+ runtime: "team_scoped_r2_overlay",
386
+ publish: "team_scoped_r2_overlay",
387
+ docs: "default",
388
+ ...config.providers?.content ?? {}
389
+ },
390
+ site: "default"
391
+ }
392
+ }));
393
+ updateYamlFile(resolve(projectRoot, "src/manifest.yaml"), (manifest) => ({
394
+ ...manifest,
395
+ id: slug,
396
+ content: {
397
+ ...manifest.content ?? {},
398
+ docs: "./src/content/knowledge",
399
+ pages: "./src/content/pages",
400
+ notes: "./src/content/notes",
401
+ questions: "./src/content/questions",
402
+ objectives: "./src/content/objectives",
403
+ proposals: "./src/content/proposals",
404
+ decisions: "./src/content/decisions",
405
+ people: "./src/content/people",
406
+ agents: "./src/content/agents",
407
+ books: "./src/content/books",
408
+ templates: "./src/content/templates",
409
+ knowledge_packs: "./src/content/knowledge-packs",
410
+ workdays: "./src/content/workdays"
411
+ },
412
+ features: {
413
+ docs: true,
414
+ books: false,
415
+ notes: true,
416
+ questions: true,
417
+ objectives: true,
418
+ proposals: true,
419
+ decisions: true,
420
+ agents: input.enableDefaultAgents !== false,
421
+ forms: false,
422
+ ...manifest.features ?? {}
423
+ }
424
+ }));
425
+ return {
426
+ slug,
427
+ siteUrl,
428
+ projectApiBaseUrl,
429
+ marketBaseUrl,
430
+ cloudflareAccountId
431
+ };
432
+ }
433
+ function createDefaultWorkstream(projectId, input, seed) {
434
+ return {
435
+ id: `${projectId}:initial-launch`,
436
+ projectId,
437
+ title: "Initial launch",
438
+ summary: "Managed launch scaffolded the repo, seeded Direct, and prepared the first operating branch.",
439
+ state: "saved_remote",
440
+ branchName: "task/initial-launch",
441
+ branchRef: "refs/heads/task/initial-launch",
442
+ owner: "Knowledge Coop",
443
+ linkedItems: [
444
+ { model: "objective", id: seed.objectiveId },
445
+ { model: "question", id: seed.questionId },
446
+ { model: "note", id: seed.noteSlug }
447
+ ],
448
+ verificationStatus: null,
449
+ verificationSummary: null,
450
+ lastSaveAt: nowIso(),
451
+ lastStageAt: null,
452
+ archivedAt: null,
453
+ createdAt: nowIso(),
454
+ updatedAt: nowIso(),
455
+ metadata: {
456
+ launchedBy: "knowledge_coop_market"
457
+ }
458
+ };
459
+ }
460
+ function pushDefaultWorkstreamBranch(projectRoot) {
461
+ runGit(projectRoot, ["checkout", "-B", "task/initial-launch"], false);
462
+ runGit(projectRoot, ["push", "-u", "origin", "task/initial-launch"], false);
463
+ runGit(projectRoot, ["checkout", "main"], false);
464
+ }
465
+ function loadProjectMetadata(projectId, input, seed, workstream, siteUrl, projectApiBaseUrl, repository) {
466
+ return {
467
+ publicSite: input.publicSite !== false,
468
+ sourceKind: input.sourceKind,
469
+ sourceRef: input.sourceRef ?? null,
470
+ enableDefaultAgents: input.enableDefaultAgents !== false,
471
+ objectiveCount: 1,
472
+ questionCount: 1,
473
+ noteCount: 1,
474
+ proposalCount: 1,
475
+ decisionCount: 1,
476
+ directViews: ["Now", "Blocked", "Ready for research", "Ready for build", "Release-linked"],
477
+ directItems: [
478
+ {
479
+ model: "objective",
480
+ id: seed.objectiveId,
481
+ title: `Launch ${input.projectName}`,
482
+ status: "live",
483
+ updatedAt: nowIso(),
484
+ linkedWorkstreamIds: [workstream.id],
485
+ linkedReleaseIds: []
486
+ },
487
+ {
488
+ model: "question",
489
+ id: seed.questionId,
490
+ title: "What Should The First Release Cover?",
491
+ status: "live",
492
+ updatedAt: nowIso(),
493
+ linkedWorkstreamIds: [workstream.id],
494
+ linkedReleaseIds: []
495
+ },
496
+ {
497
+ model: "note",
498
+ id: seed.noteSlug,
499
+ title: `${input.projectName} Operating Model`,
500
+ status: "live",
501
+ updatedAt: nowIso(),
502
+ linkedWorkstreamIds: [workstream.id],
503
+ linkedReleaseIds: []
504
+ },
505
+ {
506
+ model: "proposal",
507
+ id: seed.proposalId,
508
+ title: "Establish The Initial Operating Routine",
509
+ status: "live",
510
+ updatedAt: nowIso(),
511
+ linkedWorkstreamIds: [workstream.id],
512
+ linkedReleaseIds: []
513
+ },
514
+ {
515
+ model: "decision",
516
+ id: seed.decisionId,
517
+ title: "Adopt The Initial Launch Posture",
518
+ status: "live",
519
+ updatedAt: nowIso(),
520
+ linkedWorkstreamIds: [workstream.id],
521
+ linkedReleaseIds: []
522
+ }
523
+ ],
524
+ workstreams: [workstream],
525
+ siteUrl,
526
+ projectApiBaseUrl,
527
+ repository,
528
+ launchPhase: "completed",
529
+ lastSuccessfulPhase: "runtime_connection"
530
+ };
531
+ }
532
+ function commandAvailable(command) {
533
+ return spawnSync("bash", ["-lc", `command -v ${command}`], { stdio: "ignore" }).status === 0;
534
+ }
535
+ function appendPhase(phases, phase, status, detail) {
536
+ phases.push({
537
+ phase,
538
+ status,
539
+ detail,
540
+ timestamp: nowIso()
541
+ });
542
+ }
543
+ function scaffoldKnowledgeCoopSource(projectRoot, input) {
544
+ const templateId = input.sourceKind === "template" ? slugify(input.sourceRef ?? "starter-basic", "starter-basic") : "starter-basic";
545
+ const templateCatalogEnv = { TREESEED_TEMPLATE_CATALOG_URL: currentTemplateCatalogUrl() };
546
+ if (input.sourceKind === "knowledge_pack") {
547
+ return scaffoldTemplateProject("starter-basic", projectRoot, {
548
+ target: input.projectSlug,
549
+ name: input.projectName,
550
+ slug: input.projectSlug,
551
+ siteUrl: resolveManagedWebUrl(slugify(input.projectSlug, "project")),
552
+ contactEmail: input.contactEmail ?? `hello+${slugify(input.projectSlug, "project")}@knowledge.coop`
553
+ }, {
554
+ cwd: projectRoot,
555
+ env: templateCatalogEnv
556
+ }).then(() => {
557
+ if (!input.sourceRef) {
558
+ throw new Error("Knowledge pack launch requires sourceRef to point to a package manifest or directory.");
559
+ }
560
+ return importKnowledgeCoopKnowledgePack(projectRoot, input.sourceRef);
561
+ });
562
+ }
563
+ return scaffoldTemplateProject(templateId, projectRoot, {
564
+ target: input.projectSlug,
565
+ name: input.projectName,
566
+ slug: input.projectSlug,
567
+ siteUrl: resolveManagedWebUrl(slugify(input.projectSlug, "project")),
568
+ contactEmail: input.contactEmail ?? `hello+${slugify(input.projectSlug, "project")}@knowledge.coop`,
569
+ repositoryUrl: `https://github.com/${slugify(input.repoOwner ?? resolveDefaultGitHubOwner(), "treeseed-ai")}/${slugify(input.projectSlug, "project")}`
570
+ }, {
571
+ cwd: projectRoot,
572
+ env: templateCatalogEnv
573
+ });
574
+ }
575
+ function validateKnowledgeCoopManagedLaunchPrerequisites(tenantRoot = process.cwd()) {
576
+ const values = collectTreeseedConfigSeedValues(tenantRoot, "prod", process.env);
577
+ const requiredConfig = [
578
+ ["TREESEED_BETTER_AUTH_SECRET"],
579
+ ["TREESEED_AGENT_POOL_MIN_WORKERS"],
580
+ ["TREESEED_AGENT_POOL_MAX_WORKERS"],
581
+ ["TREESEED_AGENT_POOL_TARGET_QUEUE_DEPTH"],
582
+ ["TREESEED_AGENT_POOL_COOLDOWN_SECONDS"],
583
+ ["TREESEED_API_WEB_SERVICE_ID"],
584
+ ["TREESEED_API_WEB_SERVICE_SECRET"],
585
+ ["TREESEED_API_WEB_ASSERTION_SECRET"],
586
+ ["CLOUDFLARE_ACCOUNT_ID", "TREESEED_CLOUDFLARE_ACCOUNT_ID"]
587
+ ];
588
+ const missingConfig = requiredConfig.filter((group) => !group.some((name) => {
589
+ const value = values[name];
590
+ return typeof value === "string" && value.trim().length > 0;
591
+ })).map((group) => group.join(" or "));
592
+ const providerChecks = checkTreeseedProviderConnections({ tenantRoot, scope: "prod", env: process.env });
593
+ const commands = {
594
+ git: commandAvailable("git"),
595
+ gh: commandAvailable("gh"),
596
+ wrangler: commandAvailable("wrangler"),
597
+ railway: commandAvailable("railway")
598
+ };
599
+ const ok = missingConfig.length === 0 && providerChecks.ok === true && Object.values(commands).every(Boolean);
600
+ return {
601
+ ok,
602
+ missingConfig,
603
+ providerChecks,
604
+ commands
605
+ };
606
+ }
607
+ async function executeKnowledgeCoopManagedLaunch(input) {
608
+ const phases = [];
609
+ const preflight = validateKnowledgeCoopManagedLaunchPrerequisites(process.cwd());
610
+ if (!preflight.ok) {
611
+ throw new KnowledgeCoopLaunchError(
612
+ "runtime_connection_failed",
613
+ `Knowledge Coop launch preflight failed: ${[...preflight.missingConfig, ...preflight.providerChecks.issues].join("; ") || "provider checks failed."}`,
614
+ []
615
+ );
616
+ }
617
+ const workingRoot = mkdtempSync(join(tmpdir(), `knowledge-coop-launch-${slugify(input.projectSlug, "project")}-`));
618
+ const repoOwner = slugify(input.repoOwner ?? resolveDefaultGitHubOwner(), "treeseed-ai");
619
+ const repoName = slugify(input.projectSlug, "project");
620
+ try {
621
+ appendPhase(phases, "repo_provision", "running", "Creating GitHub repository.");
622
+ const repository = createGitHubRepository({
623
+ owner: repoOwner,
624
+ name: repoName,
625
+ description: input.summary ?? `Knowledge Coop hub for ${input.projectName}`,
626
+ visibility: input.repoVisibility ?? "private",
627
+ homepageUrl: resolveManagedWebUrl(repoName),
628
+ topics: ["knowledge-coop", "treeseed", "knowledge-hub"]
629
+ });
630
+ appendPhase(phases, "repo_provision", "completed", `Created ${repository.slug}.`);
631
+ appendPhase(phases, "content_bootstrap", "running", "Scaffolding the project and seeding initial content.");
632
+ await scaffoldKnowledgeCoopSource(workingRoot, input);
633
+ ensureHostedProjectFiles(workingRoot);
634
+ const managedDefaults = applyManagedProjectDefaults(workingRoot, input);
635
+ const seed = seedKnowledgeCoopContent(workingRoot, input);
636
+ appendPhase(phases, "content_bootstrap", "completed", "Scaffolded the repo and seeded Direct content.");
637
+ appendPhase(phases, "workflow_bootstrap", "running", "Initializing git branches and GitHub workflows.");
638
+ const initResult = initializeGitHubRepositoryWorkingTree(workingRoot, repository, {
639
+ defaultBranch: "main",
640
+ createStaging: true,
641
+ commitMessage: `Initialize ${input.projectName}`
642
+ });
643
+ pushDefaultWorkstreamBranch(workingRoot);
644
+ const workflows = ensureGitHubDeployAutomation(workingRoot);
645
+ appendPhase(phases, "workflow_bootstrap", "completed", "Configured GitHub workflows, secrets, and variables.");
646
+ appendPhase(phases, "hosting_registration", "running", "Provisioning Cloudflare resources and deploy state.");
647
+ const staging = provisionCloudflareResources(workingRoot, { scope: "staging" });
648
+ const prod = provisionCloudflareResources(workingRoot, { scope: "prod" });
649
+ syncCloudflareSecrets(workingRoot, { scope: "prod" });
650
+ runRemoteD1Migrations(workingRoot, { scope: "prod" });
651
+ markDeploymentInitialized(workingRoot, { scope: "staging" });
652
+ const verification = verifyProvisionedCloudflareResources(workingRoot, { scope: "prod" });
653
+ appendPhase(phases, "hosting_registration", "completed", "Provisioned Cloudflare resources.");
654
+ const launchConfig = loadCliDeployConfig(workingRoot);
655
+ const managedRuntime = launchConfig.runtime?.mode === "treeseed_managed";
656
+ let services = [];
657
+ let deployments = [];
658
+ let schedules = [];
659
+ let railwayVerification = [];
660
+ if (managedRuntime) {
661
+ appendPhase(phases, "runtime_connection", "running", "Deploying Railway services and registering runtime connectivity.");
662
+ validateRailwayDeployPrerequisites(workingRoot, "prod");
663
+ services = configuredRailwayServices(workingRoot, "prod");
664
+ deployments = services.map((service) => deployRailwayService(workingRoot, service));
665
+ schedules = await ensureRailwayScheduledJobs(workingRoot, "prod");
666
+ railwayVerification = await verifyRailwayScheduledJobs(workingRoot, "prod");
667
+ finalizeDeploymentState(workingRoot, { scope: "prod", serviceResults: deployments });
668
+ appendPhase(phases, "runtime_connection", "completed", "Deployed Railway services and recorded runtime readiness.");
669
+ } else {
670
+ appendPhase(phases, "runtime_connection", "completed", "Skipped managed runtime deployment for hub-only or BYO runtime launch.");
671
+ }
672
+ const defaultWorkstream = createDefaultWorkstream(input.projectId, input, seed);
673
+ const projectMetadata = loadProjectMetadata(
674
+ input.projectId,
675
+ input,
676
+ seed,
677
+ defaultWorkstream,
678
+ managedDefaults.siteUrl,
679
+ managedDefaults.projectApiBaseUrl,
680
+ { slug: repository.slug, url: repository.url }
681
+ );
682
+ const templatePackage = buildKnowledgeCoopTemplatePackage(workingRoot, {
683
+ projectSlug: input.projectSlug,
684
+ title: `${input.projectName} template`,
685
+ summary: input.summary ?? null,
686
+ market: {
687
+ publisherId: input.teamId,
688
+ publisherName: input.teamSlug ?? input.teamId,
689
+ publishMetadata: {
690
+ sourceProjectId: input.projectId,
691
+ sourceKind: input.sourceKind
692
+ }
693
+ }
694
+ });
695
+ const knowledgePackPackage = buildKnowledgeCoopKnowledgePackPackage(workingRoot, {
696
+ projectSlug: input.projectSlug,
697
+ title: `${input.projectName} knowledge pack`,
698
+ summary: input.summary ?? null,
699
+ market: {
700
+ publisherId: input.teamId,
701
+ publisherName: input.teamSlug ?? input.teamId,
702
+ publishMetadata: {
703
+ sourceProjectId: input.projectId,
704
+ sourceKind: input.sourceKind
705
+ }
706
+ }
707
+ });
708
+ return {
709
+ workingRoot,
710
+ repository: {
711
+ slug: repository.slug,
712
+ owner: repository.owner,
713
+ name: repository.name,
714
+ url: repository.url,
715
+ defaultBranch: initResult.defaultBranch,
716
+ stagingBranch: initResult.stagingBranch,
717
+ visibility: repository.visibility
718
+ },
719
+ workflows,
720
+ cloudflare: {
721
+ staging,
722
+ prod,
723
+ verification
724
+ },
725
+ railway: {
726
+ services,
727
+ deployments,
728
+ schedules,
729
+ verification: railwayVerification
730
+ },
731
+ projectApiBaseUrl: managedDefaults.projectApiBaseUrl,
732
+ projectSiteUrl: managedDefaults.siteUrl,
733
+ projectMetadata,
734
+ defaultWorkstream,
735
+ phases,
736
+ templatePackage,
737
+ knowledgePackPackage
738
+ };
739
+ } catch (error) {
740
+ const message = error instanceof Error ? error.message : String(error);
741
+ const phase = error instanceof KnowledgeCoopLaunchError ? error.phase : phases.some((entry) => entry.phase === "runtime_connection" && entry.status === "running") ? "runtime_connection_failed" : phases.some((entry) => entry.phase === "hosting_registration" && entry.status === "running") ? "hosting_registration_failed" : phases.some((entry) => entry.phase === "workflow_bootstrap" && entry.status === "running") ? "workflow_bootstrap_failed" : phases.some((entry) => entry.phase === "content_bootstrap" && entry.status === "running") ? "content_bootstrap_failed" : "repo_provision_failed";
742
+ appendPhase(phases, phase.replace(/_failed$/u, ""), "failed", message);
743
+ throw new KnowledgeCoopLaunchError(phase, message, phases);
744
+ } finally {
745
+ if (input.preserveWorkingTree === false) {
746
+ rmSync(workingRoot, { recursive: true, force: true });
747
+ }
748
+ }
749
+ }
750
+ export {
751
+ executeKnowledgeCoopManagedLaunch,
752
+ validateKnowledgeCoopManagedLaunchPrerequisites
753
+ };