@treeseed/sdk 0.4.13 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) 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 +126 -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/github-automation.d.ts +60 -0
  20. package/dist/operations/services/github-automation.js +138 -0
  21. package/dist/operations/services/key-agent.d.ts +118 -0
  22. package/dist/operations/services/key-agent.js +476 -0
  23. package/dist/operations/services/knowledge-coop-launch.d.ts +90 -0
  24. package/dist/operations/services/knowledge-coop-launch.js +753 -0
  25. package/dist/operations/services/knowledge-coop-packaging.d.ts +59 -0
  26. package/dist/operations/services/knowledge-coop-packaging.js +234 -0
  27. package/dist/operations/services/local-dev.d.ts +0 -1
  28. package/dist/operations/services/local-dev.js +1 -14
  29. package/dist/operations/services/project-platform.d.ts +42 -182
  30. package/dist/operations/services/project-platform.js +162 -59
  31. package/dist/operations/services/railway-deploy.d.ts +1 -0
  32. package/dist/operations/services/railway-deploy.js +31 -13
  33. package/dist/operations/services/runtime-tools.d.ts +52 -5
  34. package/dist/operations/services/runtime-tools.js +186 -26
  35. package/dist/operations/services/watch-dev.js +2 -4
  36. package/dist/operations/services/workspace-preflight.d.ts +4 -4
  37. package/dist/operations/services/workspace-preflight.js +22 -20
  38. package/dist/operations-registry.js +7 -2
  39. package/dist/platform/contracts.d.ts +39 -3
  40. package/dist/platform/deploy-config.d.ts +12 -1
  41. package/dist/platform/deploy-config.js +214 -15
  42. package/dist/platform/deploy-runtime.d.ts +1 -0
  43. package/dist/platform/deploy-runtime.js +10 -2
  44. package/dist/platform/env.yaml +93 -61
  45. package/dist/platform/environment.d.ts +13 -2
  46. package/dist/platform/environment.js +90 -20
  47. package/dist/platform/plugins/constants.d.ts +1 -0
  48. package/dist/platform/plugins/constants.js +7 -6
  49. package/dist/platform/tenant/runtime-config.js +8 -1
  50. package/dist/platform/tenant-config.js +4 -0
  51. package/dist/platform/utils/site-config-schema.js +18 -0
  52. package/dist/plugin-default.js +2 -2
  53. package/dist/scripts/key-agent.js +165 -0
  54. package/dist/scripts/tenant-build.js +4 -1
  55. package/dist/scripts/tenant-check.js +4 -1
  56. package/dist/scripts/tenant-deploy.js +43 -4
  57. package/dist/scripts/tenant-dev.js +0 -1
  58. package/dist/sdk-types.d.ts +2 -2
  59. package/dist/sdk-types.js +2 -0
  60. package/dist/sdk.d.ts +13 -0
  61. package/dist/sdk.js +40 -0
  62. package/dist/stores/knowledge-coop-store.d.ts +56 -0
  63. package/dist/stores/knowledge-coop-store.js +482 -0
  64. package/dist/treeseed/template-catalog/templates/starter-basic/template/package.json +6 -2
  65. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/api/server.js +4 -0
  66. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/config.yaml +25 -0
  67. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content/decisions/adopt-initial-proposal-loop.mdx +22 -0
  68. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content/people/starter-steward.mdx +11 -0
  69. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content/proposals/establish-initial-proposal-loop.mdx +17 -0
  70. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/manifest.yaml +17 -10
  71. package/dist/treeseed/template-catalog/templates/starter-basic/template/treeseed.site.yaml +69 -7
  72. package/dist/treeseed/template-catalog/templates/starter-basic/template.config.json +1 -0
  73. package/dist/verification.js +90 -2
  74. package/dist/workflow/operations.d.ts +98 -0
  75. package/dist/workflow/operations.js +229 -7
  76. package/dist/workflow-state.d.ts +54 -2
  77. package/dist/workflow-state.js +170 -24
  78. package/dist/workflow-support.d.ts +1 -1
  79. package/dist/workflow-support.js +32 -2
  80. package/dist/workflow.d.ts +29 -0
  81. package/package.json +1 -1
  82. package/templates/github/deploy.workflow.yml +11 -1
  83. package/dist/scripts/sync-dev-vars.js +0 -6
@@ -37,12 +37,12 @@ const TREESEED_DEFAULT_PLUGIN_REFERENCES = [
37
37
  const TREESEED_DEFAULT_PROVIDER_SELECTIONS = {
38
38
  forms: "store_only",
39
39
  agents: {
40
- execution: "stub",
40
+ execution: "copilot",
41
41
  mutation: "local_branch",
42
- repository: "stub",
43
- verification: "stub",
44
- notification: "stub",
45
- research: "stub"
42
+ repository: "git",
43
+ verification: "local",
44
+ notification: "sdk_message",
45
+ research: "project_graph"
46
46
  },
47
47
  deploy: "cloudflare",
48
48
  content: {
@@ -52,9 +52,57 @@ const TREESEED_DEFAULT_PROVIDER_SELECTIONS = {
52
52
  },
53
53
  site: "default"
54
54
  };
55
- const TRESEED_MANAGED_SERVICE_KEYS = ["api", "agents", "manager", "worker", "runner", "workdayStart", "workdayReport"];
55
+ const TRESEED_MANAGED_SERVICE_KEYS = ["api", "manager", "worker", "workdayStart", "workdayReport"];
56
56
  const TRESEED_WORKSPACE_PACKAGE_DIRS = ["sdk", "core", "cli"];
57
57
  const CLOUDFLARE_ACCOUNT_ID_PLACEHOLDER = "replace-with-cloudflare-account-id";
58
+ function normalizePlanesFromLegacyHosting(hosting) {
59
+ if (!hosting || Object.keys(hosting).length === 0) {
60
+ return {
61
+ hub: { mode: "treeseed_hosted" },
62
+ runtime: { mode: "none", registration: "none" }
63
+ };
64
+ }
65
+ if (hosting.kind === "market_control_plane" || hosting.kind === "hosted_project") {
66
+ return {
67
+ hub: { mode: "treeseed_hosted" },
68
+ runtime: {
69
+ mode: "treeseed_managed",
70
+ registration: hosting.kind === "market_control_plane" ? "none" : hosting.registration ?? "none",
71
+ marketBaseUrl: hosting.marketBaseUrl,
72
+ teamId: hosting.teamId,
73
+ projectId: hosting.projectId
74
+ }
75
+ };
76
+ }
77
+ return {
78
+ hub: { mode: "customer_hosted" },
79
+ runtime: {
80
+ mode: "byo_attached",
81
+ registration: hosting.registration ?? "none",
82
+ marketBaseUrl: hosting.marketBaseUrl,
83
+ teamId: hosting.teamId,
84
+ projectId: hosting.projectId
85
+ }
86
+ };
87
+ }
88
+ function normalizeLegacyHostingFromPlanes(hub, runtime) {
89
+ if (runtime.mode === "treeseed_managed" && hub.mode === "treeseed_hosted") {
90
+ return {
91
+ kind: "hosted_project",
92
+ registration: runtime.registration === "required" ? "optional" : runtime.registration ?? "none",
93
+ marketBaseUrl: runtime.marketBaseUrl,
94
+ teamId: runtime.teamId,
95
+ projectId: runtime.projectId
96
+ };
97
+ }
98
+ return {
99
+ kind: "self_hosted_project",
100
+ registration: runtime.registration === "required" ? "optional" : runtime.registration ?? "none",
101
+ marketBaseUrl: runtime.marketBaseUrl,
102
+ teamId: runtime.teamId,
103
+ projectId: runtime.projectId
104
+ };
105
+ }
58
106
  function parseServiceEnvironmentConfig(value) {
59
107
  const record = optionalRecord(value, "service environment") ?? {};
60
108
  return {
@@ -108,6 +156,81 @@ function parseManagedServicesConfig(value) {
108
156
  ])
109
157
  );
110
158
  }
159
+ function parseWebSurfaceCacheConfig(value, label) {
160
+ const record = optionalRecord(value, label) ?? {};
161
+ if (Object.keys(record).length === 0) {
162
+ return void 0;
163
+ }
164
+ return {
165
+ sourcePages: parseWebCachePolicyRecord(record.sourcePages ?? record.source_pages, `${label}.sourcePages`, {
166
+ paths: ["/", "/contact", "/404"]
167
+ }),
168
+ contentPages: parseWebCachePolicyRecord(record.contentPages ?? record.content_pages, `${label}.contentPages`),
169
+ r2PublishedObjects: parseWebCachePolicyRecord(
170
+ record.r2PublishedObjects ?? record.r2_published_objects,
171
+ `${label}.r2PublishedObjects`
172
+ )
173
+ };
174
+ }
175
+ function parseWebCachePolicyRecord(value, label, options = {}) {
176
+ const record = optionalRecord(value, label) ?? {};
177
+ if (Object.keys(record).length === 0) {
178
+ return options.paths ? { paths: [...options.paths] } : void 0;
179
+ }
180
+ const parsed = {
181
+ browserTtlSeconds: optionalNonNegativeNumber(
182
+ record.browserTtlSeconds ?? record.browser_ttl_seconds,
183
+ `${label}.browserTtlSeconds`
184
+ ),
185
+ edgeTtlSeconds: optionalNonNegativeNumber(
186
+ record.edgeTtlSeconds ?? record.edge_ttl_seconds,
187
+ `${label}.edgeTtlSeconds`
188
+ ),
189
+ staleWhileRevalidateSeconds: optionalNonNegativeNumber(
190
+ record.staleWhileRevalidateSeconds ?? record.stale_while_revalidate_seconds,
191
+ `${label}.staleWhileRevalidateSeconds`
192
+ ),
193
+ staleIfErrorSeconds: optionalNonNegativeNumber(
194
+ record.staleIfErrorSeconds ?? record.stale_if_error_seconds,
195
+ `${label}.staleIfErrorSeconds`
196
+ )
197
+ };
198
+ if (options.paths) {
199
+ parsed.paths = [...new Set(Array.isArray(record.paths) ? record.paths.map((entry) => optionalString(entry)).filter(Boolean) : options.paths)];
200
+ }
201
+ return parsed;
202
+ }
203
+ function parseSurfaceConfig(value, label) {
204
+ const record = optionalRecord(value, label);
205
+ if (!record) {
206
+ return void 0;
207
+ }
208
+ return {
209
+ enabled: record.enabled === void 0 ? void 0 : optionalBoolean(record.enabled, `${label}.enabled`),
210
+ provider: optionalString(record.provider),
211
+ rootDir: optionalString(record.rootDir),
212
+ publicBaseUrl: optionalString(record.publicBaseUrl),
213
+ localBaseUrl: optionalString(record.localBaseUrl),
214
+ cache: parseWebSurfaceCacheConfig(record.cache, `${label}.cache`)
215
+ };
216
+ }
217
+ function parsePlatformSurfacesConfig(value) {
218
+ const record = optionalRecord(value, "surfaces");
219
+ if (!record) {
220
+ return void 0;
221
+ }
222
+ return Object.fromEntries(
223
+ Object.entries(record).map(([surfaceKey, surfaceValue]) => [
224
+ surfaceKey,
225
+ parseSurfaceConfig(surfaceValue, `surfaces.${surfaceKey}`)
226
+ ])
227
+ );
228
+ }
229
+ function inferManagedRuntimeFromServices(services) {
230
+ return Object.values(services ?? {}).some(
231
+ (service) => service && service.enabled !== false && (service.provider ?? "railway") === "railway"
232
+ );
233
+ }
111
234
  const packageRoot = packageRootFromSource;
112
235
  const packageScriptRoot = resolve(packageRoot, "scripts");
113
236
  const packageDistScriptRoot = resolve(packageRoot, "dist", "scripts");
@@ -272,6 +395,15 @@ function optionalPositiveNumber(value, label) {
272
395
  }
273
396
  return value;
274
397
  }
398
+ function optionalNonNegativeNumber(value, label) {
399
+ if (value === void 0) {
400
+ return void 0;
401
+ }
402
+ if (typeof value !== "number" || !Number.isFinite(value) || value < 0) {
403
+ throw new Error(`Invalid deploy config: expected ${label} to be a non-negative number when provided.`);
404
+ }
405
+ return value;
406
+ }
275
407
  function optionalEnum(value, label, allowed) {
276
408
  const normalized = optionalString(value);
277
409
  if (!normalized) {
@@ -314,6 +446,35 @@ function parseFallbackDeployConfig(configPath) {
314
446
  const cloudflarePages = optionalRecord(cloudflare.pages, "cloudflare.pages") ?? {};
315
447
  const cloudflareR2 = optionalRecord(cloudflare.r2, "cloudflare.r2") ?? {};
316
448
  const hosting = optionalRecord(record.hosting, "hosting") ?? {};
449
+ const parsedHosting = Object.keys(hosting).length === 0 ? void 0 : {
450
+ kind: optionalEnum(hosting.kind, "hosting.kind", [
451
+ "market_control_plane",
452
+ "hosted_project",
453
+ "self_hosted_project"
454
+ ]) ?? "self_hosted_project",
455
+ registration: optionalEnum(hosting.registration, "hosting.registration", ["optional", "none"]) ?? "none",
456
+ marketBaseUrl: optionalString(process.env.TREESEED_MARKET_API_BASE_URL),
457
+ teamId: optionalString(process.env.TREESEED_HOSTING_TEAM_ID),
458
+ projectId: optionalString(process.env.TREESEED_PROJECT_ID)
459
+ };
460
+ const services = parseManagedServicesConfig(record.services);
461
+ const normalizedPlanes = normalizePlanesFromLegacyHosting(parsedHosting);
462
+ const inferredPlanes = !parsedHosting && record.hub === void 0 && record.runtime === void 0 && inferManagedRuntimeFromServices(services) ? {
463
+ hub: { mode: "customer_hosted" },
464
+ runtime: { mode: "treeseed_managed", registration: "none" }
465
+ } : normalizedPlanes;
466
+ const hubRecord = optionalRecord(record.hub, "hub") ?? {};
467
+ const runtimeRecord = optionalRecord(record.runtime, "runtime") ?? {};
468
+ const hub = {
469
+ mode: optionalEnum(hubRecord.mode, "hub.mode", ["treeseed_hosted", "customer_hosted"]) ?? inferredPlanes.hub.mode
470
+ };
471
+ const runtime = {
472
+ mode: optionalEnum(runtimeRecord.mode, "runtime.mode", ["none", "byo_attached", "treeseed_managed"]) ?? inferredPlanes.runtime.mode,
473
+ registration: optionalEnum(runtimeRecord.registration, "runtime.registration", ["optional", "required", "none"]) ?? inferredPlanes.runtime.registration ?? "none",
474
+ marketBaseUrl: optionalString(process.env.TREESEED_MARKET_API_BASE_URL) ?? inferredPlanes.runtime.marketBaseUrl,
475
+ teamId: optionalString(process.env.TREESEED_HOSTING_TEAM_ID) ?? inferredPlanes.runtime.teamId,
476
+ projectId: optionalString(process.env.TREESEED_PROJECT_ID) ?? inferredPlanes.runtime.projectId
477
+ };
317
478
  const smtp = optionalRecord(record.smtp, "smtp") ?? {};
318
479
  const turnstile = optionalRecord(record.turnstile, "turnstile") ?? {};
319
480
  const agentProviders = optionalRecord(optionalRecord(record.providers, "providers")?.agents, "providers.agents") ?? {};
@@ -323,35 +484,28 @@ function parseFallbackDeployConfig(configPath) {
323
484
  slug: expectString(record.slug, "slug"),
324
485
  siteUrl: expectString(record.siteUrl, "siteUrl"),
325
486
  contactEmail: expectString(record.contactEmail, "contactEmail"),
326
- hosting: Object.keys(hosting).length === 0 ? void 0 : {
327
- kind: optionalEnum(hosting.kind, "hosting.kind", [
328
- "market_control_plane",
329
- "hosted_project",
330
- "self_hosted_project"
331
- ]) ?? "self_hosted_project",
332
- registration: optionalEnum(hosting.registration, "hosting.registration", ["optional", "none"]) ?? "none",
333
- marketBaseUrl: optionalString(hosting.marketBaseUrl),
334
- teamId: optionalString(hosting.teamId),
335
- projectId: optionalString(hosting.projectId)
336
- },
487
+ hosting: parsedHosting && record.hub === void 0 && record.runtime === void 0 ? parsedHosting : normalizeLegacyHostingFromPlanes(hub, runtime),
488
+ hub,
489
+ runtime,
337
490
  cloudflare: {
338
- accountId: optionalCloudflareAccountId(cloudflare.accountId) ?? optionalCloudflareAccountId(process.env.CLOUDFLARE_ACCOUNT_ID) ?? CLOUDFLARE_ACCOUNT_ID_PLACEHOLDER,
491
+ accountId: optionalCloudflareAccountId(process.env.CLOUDFLARE_ACCOUNT_ID) ?? CLOUDFLARE_ACCOUNT_ID_PLACEHOLDER,
492
+ zoneId: optionalString(cloudflare.zoneId ?? cloudflare.zone_id),
339
493
  workerName: optionalString(cloudflare.workerName),
340
494
  queueName: optionalString(cloudflare.queueName),
341
495
  dlqName: optionalString(cloudflare.dlqName),
342
496
  d1Binding: optionalString(cloudflare.d1Binding),
343
497
  queueBinding: optionalString(cloudflare.queueBinding),
344
498
  pages: cloudflare.pages === void 0 ? void 0 : {
345
- projectName: optionalString(cloudflarePages.projectName) ?? optionalString(process.env.TREESEED_CLOUDFLARE_PAGES_PROJECT_NAME),
346
- previewProjectName: optionalString(cloudflarePages.previewProjectName) ?? optionalString(process.env.TREESEED_CLOUDFLARE_PAGES_PREVIEW_PROJECT_NAME),
499
+ projectName: optionalString(process.env.TREESEED_CLOUDFLARE_PAGES_PROJECT_NAME) ?? optionalString(cloudflarePages.projectName),
500
+ previewProjectName: optionalString(process.env.TREESEED_CLOUDFLARE_PAGES_PREVIEW_PROJECT_NAME) ?? optionalString(cloudflarePages.previewProjectName),
347
501
  productionBranch: optionalString(cloudflarePages.productionBranch) ?? "main",
348
502
  stagingBranch: optionalString(cloudflarePages.stagingBranch) ?? "staging",
349
503
  buildOutputDir: optionalString(cloudflarePages.buildOutputDir)
350
504
  },
351
505
  r2: cloudflare.r2 === void 0 ? void 0 : {
352
- binding: optionalString(cloudflareR2.binding) ?? optionalString(process.env.TREESEED_CONTENT_BUCKET_BINDING),
353
- bucketName: optionalString(cloudflareR2.bucketName) ?? optionalString(process.env.TREESEED_CONTENT_BUCKET_NAME),
354
- publicBaseUrl: optionalString(cloudflareR2.publicBaseUrl) ?? optionalString(process.env.TREESEED_CONTENT_PUBLIC_BASE_URL),
506
+ binding: optionalString(process.env.TREESEED_CONTENT_BUCKET_BINDING),
507
+ bucketName: optionalString(process.env.TREESEED_CONTENT_BUCKET_NAME),
508
+ publicBaseUrl: optionalString(process.env.TREESEED_CONTENT_PUBLIC_BASE_URL),
355
509
  manifestKeyTemplate: optionalString(cloudflareR2.manifestKeyTemplate ?? cloudflareR2.manifestKey) ?? "teams/{teamId}/published/common.json",
356
510
  previewRootTemplate: optionalString(cloudflareR2.previewRootTemplate ?? cloudflareR2.previewRoot) ?? "teams/{teamId}/previews",
357
511
  previewTtlHours: optionalPositiveNumber(cloudflareR2.previewTtlHours, "cloudflare.r2.previewTtlHours") ?? 168
@@ -381,16 +535,22 @@ function parseFallbackDeployConfig(configPath) {
381
535
  docs: expectString(
382
536
  contentProviders.docs ?? contentProviders.runtime ?? TREESEED_DEFAULT_PROVIDER_SELECTIONS.content.docs ?? TREESEED_DEFAULT_PROVIDER_SELECTIONS.content.runtime,
383
537
  "providers.content.docs"
384
- )
538
+ ),
539
+ serving: optionalEnum(
540
+ contentProviders.serving,
541
+ "providers.content.serving",
542
+ ["local_collections", "published_runtime"]
543
+ ) ?? TREESEED_DEFAULT_PROVIDER_SELECTIONS.content.serving
385
544
  },
386
545
  site: expectString(record.providers?.site ?? TREESEED_DEFAULT_PROVIDER_SELECTIONS.site, "providers.site")
387
546
  },
388
- services: parseManagedServicesConfig(record.services),
547
+ surfaces: parsePlatformSurfacesConfig(record.surfaces),
548
+ services,
389
549
  smtp: {
390
550
  enabled: optionalBoolean(smtp.enabled, "smtp.enabled")
391
551
  },
392
552
  turnstile: {
393
- enabled: optionalBoolean(turnstile.enabled, "turnstile.enabled") ?? true
553
+ enabled: optionalBoolean(turnstile.enabled, "turnstile.enabled") ?? false
394
554
  }
395
555
  };
396
556
  Object.defineProperty(deployConfig, "__tenantRoot", {
@@ -40,7 +40,7 @@ function shouldIgnoreWatchPath(filePath, rootPath) {
40
40
  return false;
41
41
  }
42
42
  const normalized = rel.split(sep).join("/");
43
- return normalized === ".git" || normalized.startsWith(".git/") || normalized === "node_modules" || normalized.startsWith("node_modules/") || normalized === ".astro" || normalized.startsWith(".astro/") || normalized === ".wrangler" || normalized.startsWith(".wrangler/") || normalized === ".local" || normalized.startsWith(".local/") || normalized === ".treeseed" || normalized.startsWith(".treeseed/") || normalized === "dist" || normalized.startsWith("dist/") || normalized === "coverage" || normalized.startsWith("coverage/") || normalized === ".dev.vars" || normalized === "books" || normalized.startsWith("books/") || normalized === "__treeseed" || normalized.startsWith("__treeseed/") || normalized.startsWith("public/books/") || normalized.startsWith("public/__treeseed/");
43
+ return normalized === ".git" || normalized.startsWith(".git/") || normalized === "node_modules" || normalized.startsWith("node_modules/") || normalized === ".astro" || normalized.startsWith(".astro/") || normalized === ".wrangler" || normalized.startsWith(".wrangler/") || normalized === ".local" || normalized.startsWith(".local/") || normalized === ".treeseed" || normalized.startsWith(".treeseed/") || normalized === "dist" || normalized.startsWith("dist/") || normalized === "coverage" || normalized.startsWith("coverage/") || normalized === "books" || normalized.startsWith("books/") || normalized === "__treeseed" || normalized.startsWith("__treeseed/") || normalized.startsWith("public/books/") || normalized.startsWith("public/__treeseed/");
44
44
  }
45
45
  function collectRootSnapshot(rootPath, snapshot) {
46
46
  if (!existsSync(rootPath)) {
@@ -135,9 +135,7 @@ function createTenantWatchEntries(tenantRoot) {
135
135
  { kind: "tenant", root: resolve(tenantRoot, "src") },
136
136
  { kind: "tenant", root: resolve(tenantRoot, "public") },
137
137
  { kind: "tenant", root: resolve(tenantRoot, "astro.config.ts") },
138
- { kind: "tenant", root: resolve(tenantRoot, "treeseed.site.yaml") },
139
- { kind: "tenant", root: resolve(tenantRoot, ".env.local") },
140
- { kind: "tenant", root: resolve(tenantRoot, ".env.local.example") }
138
+ { kind: "tenant", root: resolve(tenantRoot, "treeseed.site.yaml") }
141
139
  ];
142
140
  if (isEditablePackageWorkspace()) {
143
141
  const sdkRoot = workspaceSdkRoot();
@@ -2,19 +2,19 @@ export declare function createWranglerCommandEnv(overrides?: {}): {
2
2
  XDG_CONFIG_HOME: string;
3
3
  WRANGLER_SEND_METRICS: string;
4
4
  };
5
- export declare function parseGitHubAuthStatus(): {
5
+ export declare function parseGitHubAuthStatus(values?: NodeJS.ProcessEnv): {
6
6
  authenticated: boolean;
7
7
  detail: string;
8
8
  };
9
- export declare function parseWranglerWhoAmI(): {
9
+ export declare function parseWranglerWhoAmI(values?: NodeJS.ProcessEnv): {
10
10
  authenticated: boolean;
11
11
  detail: string;
12
12
  };
13
- export declare function parseRailwayWhoAmI(): {
13
+ export declare function parseRailwayWhoAmI(values?: NodeJS.ProcessEnv): {
14
14
  authenticated: boolean;
15
15
  detail: string;
16
16
  };
17
- export declare function parseCopilotSessionStatus(): {
17
+ export declare function parseCopilotSessionStatus(values?: NodeJS.ProcessEnv): {
18
18
  configured: boolean;
19
19
  detail: string;
20
20
  };
@@ -1,6 +1,7 @@
1
1
  import { mkdirSync, writeFileSync } from "node:fs";
2
2
  import { spawnSync } from "node:child_process";
3
3
  import { dirname, resolve } from "node:path";
4
+ import { collectTreeseedConfigSeedValues } from "./config-runtime.js";
4
5
  import { createTempDir } from "./workspace-tools.js";
5
6
  function runCapture(command, args, options = {}) {
6
7
  const result = spawnSync(command, args, {
@@ -32,43 +33,44 @@ function createWranglerCommandEnv(overrides = {}) {
32
33
  ...overrides
33
34
  };
34
35
  }
35
- function envTokenStatus(keys, label) {
36
+ function envTokenStatus(keys, label, values = process.env) {
36
37
  const foundKey = keys.find((key) => {
37
- const value = process.env[key];
38
+ const value = values[key];
38
39
  return typeof value === "string" && value.trim().length > 0;
39
40
  }) ?? null;
40
41
  return {
41
42
  ready: Boolean(foundKey),
42
- detail: foundKey ? `${label} token detected from ${foundKey}.` : `${label} token is not configured. Set ${keys.join(" or ")}.`,
43
- source: foundKey ? "env" : "missing"
43
+ detail: foundKey ? `${label} token detected from configured Treeseed environment (${foundKey}).` : `${label} token is not configured. Set ${keys.join(" or ")}.`,
44
+ source: foundKey ? "config" : "missing"
44
45
  };
45
46
  }
46
- function parseGitHubAuthStatus() {
47
+ function parseGitHubAuthStatus(values = process.env) {
47
48
  return {
48
- authenticated: envTokenStatus(["GH_TOKEN"], "GitHub").ready,
49
- detail: envTokenStatus(["GH_TOKEN"], "GitHub").detail
49
+ authenticated: envTokenStatus(["GH_TOKEN"], "GitHub", values).ready,
50
+ detail: envTokenStatus(["GH_TOKEN"], "GitHub", values).detail
50
51
  };
51
52
  }
52
- function parseWranglerWhoAmI() {
53
+ function parseWranglerWhoAmI(values = process.env) {
53
54
  return {
54
- authenticated: envTokenStatus(["CLOUDFLARE_API_TOKEN"], "Cloudflare").ready,
55
- detail: envTokenStatus(["CLOUDFLARE_API_TOKEN"], "Cloudflare").detail
55
+ authenticated: envTokenStatus(["CLOUDFLARE_API_TOKEN"], "Cloudflare", values).ready,
56
+ detail: envTokenStatus(["CLOUDFLARE_API_TOKEN"], "Cloudflare", values).detail
56
57
  };
57
58
  }
58
- function parseRailwayWhoAmI() {
59
+ function parseRailwayWhoAmI(values = process.env) {
59
60
  return {
60
- authenticated: envTokenStatus(["RAILWAY_API_TOKEN"], "Railway").ready,
61
- detail: envTokenStatus(["RAILWAY_API_TOKEN"], "Railway").detail
61
+ authenticated: envTokenStatus(["RAILWAY_API_TOKEN", "RAILWAY_TOKEN"], "Railway", values).ready,
62
+ detail: envTokenStatus(["RAILWAY_API_TOKEN", "RAILWAY_TOKEN"], "Railway", values).detail
62
63
  };
63
64
  }
64
- function parseCopilotSessionStatus() {
65
- const status = envTokenStatus(["GH_TOKEN"], "GitHub");
65
+ function parseCopilotSessionStatus(values = process.env) {
66
+ const status = envTokenStatus(["GH_TOKEN"], "GitHub", values);
66
67
  return {
67
68
  configured: status.ready,
68
- detail: status.ready ? "GitHub token detected from GH_TOKEN for Copilot-backed workflows." : "GitHub token is not configured. Set GH_TOKEN for Copilot-backed workflows."
69
+ detail: status.ready ? "GitHub token detected from configured Treeseed environment for Copilot-backed workflows." : "GitHub token is not configured. Set GH_TOKEN for Copilot-backed workflows."
69
70
  };
70
71
  }
71
72
  function collectCliPreflight({ cwd = process.cwd(), requireAuth = false } = {}) {
73
+ const configuredValues = collectTreeseedConfigSeedValues(cwd, "local");
72
74
  const binaries = {
73
75
  git: locateBinary("git"),
74
76
  npm: locateBinary("npm"),
@@ -87,22 +89,22 @@ function collectCliPreflight({ cwd = process.cwd(), requireAuth = false } = {})
87
89
  auth: {}
88
90
  };
89
91
  if (binaries.gh) {
90
- checks.auth.gh = parseGitHubAuthStatus();
92
+ checks.auth.gh = parseGitHubAuthStatus(configuredValues);
91
93
  } else {
92
94
  checks.auth.gh = { authenticated: false, detail: "GitHub CLI is not installed." };
93
95
  }
94
96
  if (binaries.wrangler) {
95
- checks.auth.wrangler = parseWranglerWhoAmI();
97
+ checks.auth.wrangler = parseWranglerWhoAmI(configuredValues);
96
98
  } else {
97
99
  checks.auth.wrangler = { authenticated: false, detail: "Wrangler CLI is not installed." };
98
100
  }
99
101
  if (binaries.railway) {
100
- checks.auth.railway = parseRailwayWhoAmI();
102
+ checks.auth.railway = parseRailwayWhoAmI(configuredValues);
101
103
  } else {
102
104
  checks.auth.railway = { authenticated: false, detail: "Railway CLI is not installed." };
103
105
  }
104
106
  if (binaries.copilot) {
105
- checks.auth.copilot = parseCopilotSessionStatus();
107
+ checks.auth.copilot = parseCopilotSessionStatus(configuredValues);
106
108
  } else {
107
109
  checks.auth.copilot = { configured: false, detail: "Copilot CLI is not installed." };
108
110
  }
@@ -15,10 +15,16 @@ const TRESEED_OPERATION_SPECS = [
15
15
  operation({ id: "auth.login", name: "auth:login", aliases: [], group: "Validation", summary: "Authenticate against the configured Treeseed API.", description: "Start the device login flow against the active Treeseed API host and persist the returned session locally.", provider: "default", related: ["auth:check", "auth:whoami", "auth:logout"] }),
16
16
  operation({ id: "auth.logout", name: "auth:logout", aliases: [], group: "Validation", summary: "Clear locally stored Treeseed API credentials.", description: "Remove the persisted local device-flow session for the active Treeseed API host.", provider: "default", related: ["auth:login", "auth:whoami"] }),
17
17
  operation({ id: "auth.whoami", name: "auth:whoami", aliases: [], group: "Validation", summary: "Inspect the active Treeseed API identity.", description: "Use the persisted local remote session to query the active Treeseed API principal.", provider: "default", related: ["auth:login", "status"] }),
18
+ operation({ id: "secrets.status", name: "secrets:status", aliases: [], group: "Validation", summary: "Inspect the local wrapped machine-key session.", description: "Report whether the local key agent is running, whether the wrapped machine key exists, and whether the secret session is unlocked.", provider: "default", related: ["secrets:unlock", "secrets:lock"] }),
19
+ operation({ id: "secrets.unlock", name: "secrets:unlock", aliases: [], group: "Validation", summary: "Unlock the local Treeseed secret session.", description: "Unlock the host-local Treeseed key agent from an interactive passphrase prompt or an explicit startup passphrase env var.", provider: "default", related: ["secrets:status", "secrets:lock", "secrets:migrate-key"] }),
20
+ operation({ id: "secrets.lock", name: "secrets:lock", aliases: [], group: "Validation", summary: "Lock the local Treeseed secret session.", description: "Clear the in-memory machine key from the host-local Treeseed key agent.", provider: "default", related: ["secrets:status", "secrets:unlock"] }),
21
+ operation({ id: "secrets.migrateKey", name: "secrets:migrate-key", aliases: [], group: "Validation", summary: "Wrap a legacy plaintext machine key.", description: "Replace the legacy plaintext machine-key file with the wrapped passphrase-protected format used by the Treeseed key agent.", provider: "default", related: ["secrets:unlock", "secrets:rotate-passphrase"] }),
22
+ operation({ id: "secrets.rotatePassphrase", name: "secrets:rotate-passphrase", aliases: [], group: "Validation", summary: "Rotate the wrapped machine-key passphrase.", description: "Re-wrap the existing machine key with a newly entered passphrase without changing the underlying machine key.", provider: "default", related: ["secrets:unlock", "secrets:rotate-machine-key"] }),
23
+ operation({ id: "secrets.rotateMachineKey", name: "secrets:rotate-machine-key", aliases: [], group: "Validation", summary: "Rotate the encrypted machine key itself.", description: "Generate a new machine key, re-encrypt stored local secrets and remote auth sessions, and re-wrap the result with the configured passphrase.", provider: "default", related: ["config", "secrets:rotate-passphrase"] }),
18
24
  operation({ id: "template.list", name: "template", aliases: [], group: "Utilities", summary: "List, inspect, and validate templates from the Treeseed catalog.", description: "Use remote template metadata to list templates, show one template, or validate local template artifacts.", provider: "default", related: ["init", "sync"] }),
19
25
  operation({ id: "template.sync", name: "sync", aliases: [], group: "Validation", summary: "Validate or reconcile the managed template surface for the current site.", description: "Use remote template metadata plus the local scaffold artifact to check or apply updates to the managed scaffold surface.", provider: "default", related: ["template", "init", "status"] }),
20
26
  operation({ id: "project.init", name: "init", aliases: [], group: "Workflow", summary: "Scaffold a new Treeseed tenant project.", description: "Create a new Treeseed tenant directory from a remote-catalog template backed by the packaged scaffold artifact.", provider: "default", related: ["config", "switch", "dev"] }),
21
- operation({ id: "project.config", name: "config", aliases: [], group: "Workflow", summary: "Configure and test the runtime foundation.", description: "Apply safe repairs, collect environment values, write local machine config, generate local env files, initialize environments, sync providers, and run doctor-style checks.", provider: "default", related: ["status", "switch", "dev"] }),
27
+ operation({ id: "project.config", name: "config", aliases: [], group: "Workflow", summary: "Configure and test the runtime foundation.", description: "Apply safe repairs, collect environment values, write local machine config, initialize environments, sync providers, and run doctor-style checks.", provider: "default", related: ["status", "switch", "dev"] }),
22
28
  operation({ id: "project.export", name: "export", aliases: [], group: "Utilities", summary: "Export a Markdown snapshot of the current codebase.", description: "Generate a Markdown codebase snapshot for the selected directory using the SDK-owned repomix integration and store it under .treeseed/exports.", provider: "default", related: ["status", "config"] }),
23
29
  operation({ id: "deploy.release", name: "release", aliases: [], group: "Workflow", summary: "Release changed packages and market from staging to production.", description: "Select changed packages plus dependents, validate publish workflows, release packages first, then promote market from staging to main with aligned package pointers.", provider: "default", related: ["stage", "status", "rollback"] }),
24
30
  operation({ id: "deploy.destroy", name: "destroy", aliases: [], group: "Workflow", summary: "Destroy a persistent environment and its local state.", description: "Delete the selected persistent environment resources and remove the local deploy state after confirmation.", provider: "default", related: ["config", "status"] }),
@@ -40,7 +46,6 @@ const TRESEED_OPERATION_SPECS = [
40
46
  operation({ id: "release.verify", name: "test:release:full", aliases: ["release:verify"], group: "Release Utilities", summary: "Run the full release verification path.", description: "Run the full release verification path.", provider: "default" }),
41
47
  operation({ id: "release.publishChanged", name: "release:publish:changed", aliases: [], group: "Release Utilities", summary: "Publish changed Treeseed workspace packages.", description: "Publish changed Treeseed workspace packages.", provider: "default" }),
42
48
  operation({ id: "tools.astro", name: "astro", aliases: [], group: "Passthrough", summary: "Pass through to the packaged Astro CLI wrapper.", description: "Pass through to the packaged Astro CLI wrapper.", provider: "default" }),
43
- operation({ id: "tools.syncDevvars", name: "sync:devvars", aliases: [], group: "Utilities", summary: "Regenerate .dev.vars from local configuration.", description: "Regenerate .dev.vars from local configuration.", provider: "default" }),
44
49
  operation({ id: "services.mailpitUp", name: "mailpit:up", aliases: [], group: "Utilities", summary: "Start the package-managed Mailpit service.", description: "Start the package-managed Mailpit service.", provider: "default" }),
45
50
  operation({ id: "services.mailpitDown", name: "mailpit:down", aliases: [], group: "Utilities", summary: "Stop the package-managed Mailpit service.", description: "Stop the package-managed Mailpit service.", provider: "default" }),
46
51
  operation({ id: "services.mailpitLogs", name: "mailpit:logs", aliases: [], group: "Utilities", summary: "Show Mailpit logs.", description: "Show Mailpit logs.", provider: "default" }),
@@ -1,11 +1,13 @@
1
- export type TreeseedFeatureName = 'docs' | 'books' | 'notes' | 'questions' | 'objectives' | 'agents' | 'forms';
2
- export type TreeseedContentCollection = 'pages' | 'notes' | 'questions' | 'objectives' | 'people' | 'agents' | 'books' | 'docs' | 'templates' | 'knowledge_packs' | 'workdays';
1
+ export type TreeseedFeatureName = 'docs' | 'books' | 'notes' | 'questions' | 'objectives' | 'proposals' | 'decisions' | 'agents' | 'forms';
2
+ export type TreeseedContentCollection = 'pages' | 'notes' | 'questions' | 'objectives' | 'proposals' | 'decisions' | 'people' | 'agents' | 'books' | 'docs' | 'templates' | 'knowledge_packs' | 'workdays';
3
3
  export interface TreeseedFeatureModules {
4
4
  docs?: boolean;
5
5
  books?: boolean;
6
6
  notes?: boolean;
7
7
  questions?: boolean;
8
8
  objectives?: boolean;
9
+ proposals?: boolean;
10
+ decisions?: boolean;
9
11
  agents?: boolean;
10
12
  forms?: boolean;
11
13
  [key: string]: boolean | undefined;
@@ -15,6 +17,8 @@ export interface TreeseedContentMap {
15
17
  notes: string;
16
18
  questions: string;
17
19
  objectives: string;
20
+ proposals: string;
21
+ decisions: string;
18
22
  people: string;
19
23
  agents: string;
20
24
  books: string;
@@ -118,7 +122,23 @@ export interface TreeseedPlatformSurfaceConfig {
118
122
  rootDir?: string;
119
123
  publicBaseUrl?: string;
120
124
  localBaseUrl?: string;
125
+ cache?: TreeseedWebSurfaceCacheConfig;
121
126
  }
127
+ export interface TreeseedWebCachePolicyConfig {
128
+ browserTtlSeconds?: number;
129
+ edgeTtlSeconds?: number;
130
+ staleWhileRevalidateSeconds?: number;
131
+ staleIfErrorSeconds?: number;
132
+ }
133
+ export interface TreeseedWebSourcePageCacheConfig extends TreeseedWebCachePolicyConfig {
134
+ paths?: string[];
135
+ }
136
+ export interface TreeseedWebSurfaceCacheConfig {
137
+ sourcePages?: TreeseedWebSourcePageCacheConfig;
138
+ contentPages?: TreeseedWebCachePolicyConfig;
139
+ r2PublishedObjects?: TreeseedWebCachePolicyConfig;
140
+ }
141
+ export type TreeseedContentServingMode = 'local_collections' | 'published_runtime';
122
142
  export interface TreeseedCloudflareR2Config {
123
143
  binding?: string;
124
144
  bucketName?: string;
@@ -136,6 +156,9 @@ export interface TreeseedCloudflarePagesConfig {
136
156
  }
137
157
  export type TreeseedHostingKind = 'market_control_plane' | 'hosted_project' | 'self_hosted_project';
138
158
  export type TreeseedHostingRegistration = 'optional' | 'none';
159
+ export type TreeseedHubMode = 'treeseed_hosted' | 'customer_hosted';
160
+ export type TreeseedRuntimeMode = 'none' | 'byo_attached' | 'treeseed_managed';
161
+ export type TreeseedRuntimeRegistration = 'optional' | 'required' | 'none';
139
162
  export interface TreeseedHostingConfig {
140
163
  kind: TreeseedHostingKind;
141
164
  registration?: TreeseedHostingRegistration;
@@ -143,6 +166,16 @@ export interface TreeseedHostingConfig {
143
166
  teamId?: string;
144
167
  projectId?: string;
145
168
  }
169
+ export interface TreeseedHubConfig {
170
+ mode: TreeseedHubMode;
171
+ }
172
+ export interface TreeseedRuntimeConfig {
173
+ mode: TreeseedRuntimeMode;
174
+ registration?: TreeseedRuntimeRegistration;
175
+ marketBaseUrl?: string;
176
+ teamId?: string;
177
+ projectId?: string;
178
+ }
146
179
  export interface TreeseedManagedServiceEnvironmentConfig {
147
180
  baseUrl?: string;
148
181
  domain?: string;
@@ -172,7 +205,6 @@ export interface TreeseedManagedServiceConfig {
172
205
  }
173
206
  export interface TreeseedManagedServicesConfig {
174
207
  api?: TreeseedManagedServiceConfig;
175
- agents?: TreeseedManagedServiceConfig;
176
208
  [key: string]: TreeseedManagedServiceConfig | undefined;
177
209
  }
178
210
  export interface TreeseedPlatformSurfacesConfig {
@@ -196,6 +228,7 @@ export interface TreeseedProviderSelections {
196
228
  runtime: string;
197
229
  publish: string;
198
230
  docs?: string;
231
+ serving?: TreeseedContentServingMode;
199
232
  };
200
233
  site?: string;
201
234
  }
@@ -209,8 +242,11 @@ export interface TreeseedDeployConfig {
209
242
  siteUrl: string;
210
243
  contactEmail: string;
211
244
  hosting?: TreeseedHostingConfig;
245
+ hub: TreeseedHubConfig;
246
+ runtime: TreeseedRuntimeConfig;
212
247
  cloudflare: {
213
248
  accountId: string;
249
+ zoneId?: string;
214
250
  workerName?: string;
215
251
  queueName?: string;
216
252
  dlqName?: string;
@@ -1,6 +1,17 @@
1
- import type { TreeseedDeployConfig } from './contracts.ts';
1
+ import type { TreeseedDeployConfig, TreeseedWebCachePolicyConfig } from './contracts.ts';
2
2
  export declare function resolveTreeseedDeployConfigPath(configPath?: string): string;
3
3
  export declare function resolveTreeseedDeployConfigPathFromRoot(tenantRoot: string, configPath?: string): string;
4
4
  export declare function deriveCloudflareWorkerName(config: TreeseedDeployConfig): string;
5
+ export declare function resolveTreeseedWebCachePolicy(config: TreeseedDeployConfig): {
6
+ sourcePages: {
7
+ paths: string[];
8
+ browserTtlSeconds: number;
9
+ edgeTtlSeconds: number;
10
+ staleWhileRevalidateSeconds: number;
11
+ staleIfErrorSeconds: number;
12
+ };
13
+ contentPages: Required<TreeseedWebCachePolicyConfig>;
14
+ r2PublishedObjects: Required<TreeseedWebCachePolicyConfig>;
15
+ };
5
16
  export declare function loadTreeseedDeployConfig(configPath?: string): TreeseedDeployConfig;
6
17
  export declare function loadTreeseedDeployConfigFromPath(resolvedConfigPath: string): TreeseedDeployConfig;