@treeseed/core 0.4.13 → 0.5.3

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 (81) hide show
  1. package/dist/agents/adapters/notification.d.ts +16 -1
  2. package/dist/agents/adapters/notification.js +31 -1
  3. package/dist/agents/adapters/research.d.ts +13 -1
  4. package/dist/agents/adapters/research.js +35 -1
  5. package/dist/agents/contracts/run.d.ts +1 -0
  6. package/dist/agents/kernel/agent-kernel.d.ts +2 -2
  7. package/dist/agents/kernel/agent-kernel.js +10 -3
  8. package/dist/agents/kernel/trigger-resolver.d.ts +1 -0
  9. package/dist/agents/kernel/trigger-resolver.js +5 -1
  10. package/dist/agents/runtime-types.d.ts +1 -0
  11. package/dist/api/app.js +10 -0
  12. package/dist/api/auth/d1-store.js +5 -0
  13. package/dist/api/auth/memory-provider.js +6 -1
  14. package/dist/api/auth/rbac.d.ts +2 -2
  15. package/dist/api/auth/rbac.js +2 -0
  16. package/dist/api/capabilities.d.ts +9 -0
  17. package/dist/api/capabilities.js +33 -0
  18. package/dist/api/operations-routes.d.ts +4 -0
  19. package/dist/api/operations-routes.js +49 -1
  20. package/dist/api/project-routes.d.ts +8 -0
  21. package/dist/api/project-routes.js +586 -0
  22. package/dist/api/types.d.ts +7 -0
  23. package/dist/components/site/NotesList.astro +13 -2
  24. package/dist/components/site/PublishedContentBody.astro +5 -0
  25. package/dist/content.js +77 -9
  26. package/dist/dev.d.ts +2 -2
  27. package/dist/dev.js +0 -15
  28. package/dist/env.yaml +39 -26
  29. package/dist/index.d.ts +1 -0
  30. package/dist/index.js +7 -1
  31. package/dist/launch.d.ts +3 -0
  32. package/dist/launch.js +8 -0
  33. package/dist/layouts/AuthoredEntryLayout.astro +76 -28
  34. package/dist/layouts/ProfileLayout.astro +9 -5
  35. package/dist/middleware.js +11 -0
  36. package/dist/pages/[slug].astro +10 -6
  37. package/dist/pages/agents/[slug].astro +17 -7
  38. package/dist/pages/agents/index.astro +2 -1
  39. package/dist/pages/books/[slug].astro +10 -5
  40. package/dist/pages/books/index.astro +4 -1
  41. package/dist/pages/decisions/[slug].astro +73 -0
  42. package/dist/pages/decisions/index.astro +47 -0
  43. package/dist/pages/docs-runtime/[...slug].astro +102 -0
  44. package/dist/pages/docs-runtime/index.astro +89 -0
  45. package/dist/pages/feed.xml.js +2 -1
  46. package/dist/pages/index.astro +160 -16
  47. package/dist/pages/notes/[slug].astro +10 -5
  48. package/dist/pages/notes/index.astro +6 -3
  49. package/dist/pages/objectives/[slug].astro +27 -9
  50. package/dist/pages/objectives/index.astro +19 -2
  51. package/dist/pages/people/[slug].astro +17 -7
  52. package/dist/pages/people/index.astro +2 -1
  53. package/dist/pages/proposals/[slug].astro +72 -0
  54. package/dist/pages/proposals/index.astro +47 -0
  55. package/dist/pages/questions/[slug].astro +27 -9
  56. package/dist/pages/questions/index.astro +19 -2
  57. package/dist/scripts/dev-platform.js +0 -1
  58. package/dist/scripts/release-verify.js +29 -2
  59. package/dist/scripts/tenant-build.js +4 -1
  60. package/dist/scripts/tenant-check.js +4 -1
  61. package/dist/services/agents.d.ts +1 -12
  62. package/dist/services/agents.js +28 -9
  63. package/dist/services/index.d.ts +0 -2
  64. package/dist/services/index.js +0 -6
  65. package/dist/services/manager.d.ts +4 -4
  66. package/dist/services/manager.js +123 -50
  67. package/dist/services/workday-report.d.ts +3 -3
  68. package/dist/services/workday-start.d.ts +3 -3
  69. package/dist/services/worker-capacity.d.ts +58 -0
  70. package/dist/services/worker-capacity.js +208 -0
  71. package/dist/services/worker.js +70 -13
  72. package/dist/site.js +18 -5
  73. package/dist/tenant/runtime-config.js +8 -1
  74. package/dist/utils/hub-content.js +14 -0
  75. package/dist/utils/published-content.js +13 -0
  76. package/dist/utils/site-config.js +20 -0
  77. package/dist/utils/site-content-runtime.js +185 -0
  78. package/dist/utils/web-cache.js +149 -0
  79. package/package.json +11 -6
  80. package/scripts/verify-driver.mjs +34 -0
  81. package/templates/github/deploy.workflow.yml +11 -1
package/dist/content.js CHANGED
@@ -5,6 +5,7 @@ import { existsSync, readdirSync } from "node:fs";
5
5
  import { AGENT_CLI_ALLOW_TOOLS } from "@treeseed/sdk/types/agents";
6
6
  import { loadTreeseedPluginRuntime } from "@treeseed/sdk/platform/plugins";
7
7
  import { loadTreeseedDeployConfig } from "@treeseed/sdk/platform/deploy-config";
8
+ import { getTreeseedContentServingMode } from "@treeseed/sdk/platform/deploy-runtime";
8
9
  import {
9
10
  AGENT_MODEL_DEFAULTS,
10
11
  BOOK_MODEL_DEFAULTS,
@@ -13,12 +14,16 @@ import {
13
14
  OBJECTIVE_MODEL_DEFAULTS,
14
15
  PAGE_MODEL_DEFAULTS,
15
16
  PEOPLE_MODEL_DEFAULTS,
16
- QUESTION_MODEL_DEFAULTS
17
+ PROPOSAL_MODEL_DEFAULTS,
18
+ QUESTION_MODEL_DEFAULTS,
19
+ DECISION_MODEL_DEFAULTS
17
20
  } from "./utils/site-config.js";
18
21
  import { preprocessAliasedRecord } from "@treeseed/sdk/field-aliases";
19
22
  const statusValues = ["live", "in progress", "exploratory", "planned", "speculative"];
20
23
  const pageLayoutValues = ["article", "bridge"];
21
24
  const questionTypeValues = ["research", "implementation", "strategy", "evaluation"];
25
+ const proposalTypeValues = ["strategy", "policy", "implementation", "research"];
26
+ const decisionTypeValues = ["approved", "rejected", "deferred", "superseded"];
22
27
  const timeHorizonValues = ["near-term", "mid-term", "long-term"];
23
28
  const runtimeStatusValues = ["active", "experimental", "dormant"];
24
29
  const agentTriggerTypeValues = ["schedule", "message", "follow", "startup"];
@@ -89,6 +94,7 @@ function resolveDocsCollectionProvider(tenantConfig, dependencies) {
89
94
  throw new Error(`Treeseed docs provider "${selectedId}" is not registered.`);
90
95
  }
91
96
  function createTreeseedCollections(tenantConfig, { docsLoader, docsSchema }) {
97
+ const publishedRuntime = getTreeseedContentServingMode() === "published_runtime";
92
98
  const pageFieldAliases = {
93
99
  pageLayout: { key: "pageLayout", aliases: ["page_layout"] },
94
100
  seoTitle: { key: "seoTitle", aliases: ["seo_title"] },
@@ -106,6 +112,25 @@ function createTreeseedCollections(tenantConfig, { docsLoader, docsSchema }) {
106
112
  relatedQuestions: { key: "relatedQuestions", aliases: ["related_questions"] },
107
113
  relatedBooks: { key: "relatedBooks", aliases: ["related_books"] }
108
114
  };
115
+ const proposalFieldAliases = {
116
+ proposalType: { key: "proposalType", aliases: ["proposal_type"] },
117
+ primaryContributor: { key: "primaryContributor", aliases: ["primary_contributor"] },
118
+ relatedObjectives: { key: "relatedObjectives", aliases: ["related_objectives"] },
119
+ relatedQuestions: { key: "relatedQuestions", aliases: ["related_questions"] },
120
+ relatedNotes: { key: "relatedNotes", aliases: ["related_notes"] },
121
+ relatedBooks: { key: "relatedBooks", aliases: ["related_books"] },
122
+ canonicalRoute: { key: "canonicalRoute", aliases: ["canonical_route"] }
123
+ };
124
+ const decisionFieldAliases = {
125
+ decisionType: { key: "decisionType", aliases: ["decision_type"] },
126
+ primaryContributor: { key: "primaryContributor", aliases: ["primary_contributor"] },
127
+ relatedObjectives: { key: "relatedObjectives", aliases: ["related_objectives"] },
128
+ relatedQuestions: { key: "relatedQuestions", aliases: ["related_questions"] },
129
+ relatedNotes: { key: "relatedNotes", aliases: ["related_notes"] },
130
+ relatedProposals: { key: "relatedProposals", aliases: ["related_proposals"] },
131
+ relatedBooks: { key: "relatedBooks", aliases: ["related_books"] },
132
+ canonicalRoute: { key: "canonicalRoute", aliases: ["canonical_route"] }
133
+ };
109
134
  const agentFieldAliases = {
110
135
  runtimeStatus: { key: "runtimeStatus", aliases: ["runtime_status"] },
111
136
  systemPrompt: { key: "systemPrompt", aliases: ["system_prompt"] },
@@ -183,6 +208,46 @@ function createTreeseedCollections(tenantConfig, { docsLoader, docsSchema }) {
183
208
  relatedQuestions: z.array(reference("questions")).default([]),
184
209
  relatedBooks: z.array(reference("books")).default([])
185
210
  }));
211
+ const proposalSchema = z.preprocess((value) => preprocessAliasedRecord(proposalFieldAliases, value), z.object({
212
+ title: z.string(),
213
+ description: z.string(),
214
+ date: z.coerce.date(),
215
+ status: withOptionalDefault(z.enum(statusValues), PROPOSAL_MODEL_DEFAULTS.status),
216
+ tags: z.array(z.string()).default(PROPOSAL_MODEL_DEFAULTS.tags ?? []),
217
+ summary: z.string(),
218
+ draft: z.boolean().default(PROPOSAL_MODEL_DEFAULTS.draft ?? false),
219
+ proposalType: z.enum(proposalTypeValues),
220
+ motivation: z.string(),
221
+ primaryContributor: contributorReference,
222
+ relatedObjectives: z.array(reference("objectives")).default([]),
223
+ relatedQuestions: z.array(reference("questions")).default([]),
224
+ relatedNotes: z.array(reference("notes")).default([]),
225
+ relatedBooks: z.array(reference("books")).default([]),
226
+ decision: reference("decisions").optional(),
227
+ supersedes: z.array(reference("proposals")).default([]),
228
+ canonicalRoute: z.string().optional()
229
+ }));
230
+ const decisionSchema = z.preprocess((value) => preprocessAliasedRecord(decisionFieldAliases, value), z.object({
231
+ title: z.string(),
232
+ description: z.string(),
233
+ date: z.coerce.date(),
234
+ status: withOptionalDefault(z.enum(statusValues), DECISION_MODEL_DEFAULTS.status),
235
+ tags: z.array(z.string()).default(DECISION_MODEL_DEFAULTS.tags ?? []),
236
+ summary: z.string(),
237
+ draft: z.boolean().default(DECISION_MODEL_DEFAULTS.draft ?? false),
238
+ decisionType: z.enum(decisionTypeValues),
239
+ rationale: z.string(),
240
+ authority: z.string(),
241
+ primaryContributor: contributorReference,
242
+ relatedObjectives: z.array(reference("objectives")).default([]),
243
+ relatedQuestions: z.array(reference("questions")).default([]),
244
+ relatedNotes: z.array(reference("notes")).default([]),
245
+ relatedProposals: z.array(reference("proposals")).default([]),
246
+ relatedBooks: z.array(reference("books")).default([]),
247
+ supersedes: z.array(reference("decisions")).default([]),
248
+ implements: z.array(z.string()).default([]),
249
+ canonicalRoute: z.string().optional()
250
+ }));
186
251
  const profileLinkSchema = z.object({ label: z.string(), href: z.string() });
187
252
  const agentCliSchema = z.object({
188
253
  model: z.string().optional(),
@@ -402,16 +467,19 @@ function createTreeseedCollections(tenantConfig, { docsLoader, docsSchema }) {
402
467
  metadata: z.record(z.any()).default({})
403
468
  });
404
469
  const docsCollectionProvider = resolveDocsCollectionProvider(tenantConfig, { docsLoader, docsSchema });
470
+ const markdownLoader = (base) => publishedRuntime ? optionalMarkdownGlob(base) : glob({ pattern: "**/*.{md,mdx}", base });
405
471
  const collections = {
406
- pages: defineCollection({ loader: glob({ pattern: "**/*.{md,mdx}", base: tenantConfig.content.pages }), schema: pageSchema }),
407
- notes: defineCollection({ loader: glob({ pattern: "**/*.{md,mdx}", base: tenantConfig.content.notes }), schema: noteSchema }),
408
- questions: defineCollection({ loader: glob({ pattern: "**/*.{md,mdx}", base: tenantConfig.content.questions }), schema: questionSchema }),
409
- objectives: defineCollection({ loader: glob({ pattern: "**/*.{md,mdx}", base: tenantConfig.content.objectives }), schema: objectiveSchema }),
410
- people: defineCollection({ loader: glob({ pattern: "**/*.{md,mdx}", base: tenantConfig.content.people }), schema: peopleSchema }),
411
- agents: defineCollection({ loader: glob({ pattern: "**/*.{md,mdx}", base: tenantConfig.content.agents }), schema: agentSchema }),
412
- books: defineCollection({ loader: glob({ pattern: "**/*.{md,mdx}", base: tenantConfig.content.books }), schema: bookSchema }),
472
+ pages: defineCollection({ loader: markdownLoader(tenantConfig.content.pages), schema: pageSchema }),
473
+ notes: defineCollection({ loader: markdownLoader(tenantConfig.content.notes), schema: noteSchema }),
474
+ questions: defineCollection({ loader: markdownLoader(tenantConfig.content.questions), schema: questionSchema }),
475
+ objectives: defineCollection({ loader: markdownLoader(tenantConfig.content.objectives), schema: objectiveSchema }),
476
+ proposals: defineCollection({ loader: markdownLoader(tenantConfig.content.proposals), schema: proposalSchema }),
477
+ decisions: defineCollection({ loader: markdownLoader(tenantConfig.content.decisions), schema: decisionSchema }),
478
+ people: defineCollection({ loader: markdownLoader(tenantConfig.content.people), schema: peopleSchema }),
479
+ agents: defineCollection({ loader: markdownLoader(tenantConfig.content.agents), schema: agentSchema }),
480
+ books: defineCollection({ loader: markdownLoader(tenantConfig.content.books), schema: bookSchema }),
413
481
  docs: defineCollection({
414
- loader: docsCollectionProvider.loader,
482
+ loader: publishedRuntime ? optionalMarkdownGlob(tenantConfig.content.docs) : docsCollectionProvider.loader,
415
483
  schema: docsCollectionProvider.schema
416
484
  })
417
485
  };
package/dist/dev.d.ts CHANGED
@@ -4,7 +4,7 @@ export declare const TREESEED_DEFAULT_WEB_PORT = 4321;
4
4
  export declare const TREESEED_DEFAULT_API_HOST = "127.0.0.1";
5
5
  export declare const TREESEED_DEFAULT_API_PORT = 3000;
6
6
  export declare const TREESEED_DEFAULT_MANAGER_PORT = 3100;
7
- export type TreeseedIntegratedDevSurface = 'integrated' | 'services' | 'web' | 'api' | 'manager' | 'worker' | 'agents';
7
+ export type TreeseedIntegratedDevSurface = 'integrated' | 'services' | 'web' | 'api' | 'manager' | 'worker';
8
8
  export type TreeseedIntegratedDevOptions = {
9
9
  surface?: TreeseedIntegratedDevSurface;
10
10
  watch?: boolean;
@@ -21,7 +21,7 @@ export type TreeseedIntegratedDevOptions = {
21
21
  teamId?: string;
22
22
  };
23
23
  export type TreeseedIntegratedDevCommand = {
24
- id: 'web' | 'api' | 'manager' | 'worker' | 'agents';
24
+ id: 'web' | 'api' | 'manager' | 'worker';
25
25
  label: string;
26
26
  command: string;
27
27
  args: string[];
package/dist/dev.js CHANGED
@@ -103,11 +103,6 @@ function createTreeseedIntegratedDevPlan(options = {}) {
103
103
  "src/services/worker.ts",
104
104
  "dist/services/worker.js"
105
105
  );
106
- const agentsEntrypoint = resolveNodeEntrypoint(
107
- packageRoot,
108
- "src/services/agents.ts",
109
- "dist/services/agents.js"
110
- );
111
106
  const watchPaths = [
112
107
  resolve(packageRoot, existsSync(resolve(packageRoot, "src")) ? "src" : "dist"),
113
108
  resolve(tenantRoot, "src"),
@@ -173,16 +168,6 @@ function createTreeseedIntegratedDevPlan(options = {}) {
173
168
  env: sharedEnv
174
169
  });
175
170
  }
176
- if (includeServices || surface === "agents") {
177
- commands.push({
178
- id: "agents",
179
- label: "Agents",
180
- command: agentsEntrypoint.command,
181
- args: watch ? withWatchArgs(agentsEntrypoint.args, watchPaths) : agentsEntrypoint.args,
182
- cwd: tenantRoot,
183
- env: sharedEnv
184
- });
185
- }
186
171
  return {
187
172
  surface,
188
173
  tenantRoot,
package/dist/env.yaml CHANGED
@@ -6,7 +6,7 @@ entries:
6
6
  howToGet: "Create a GitHub fine-grained personal access token scoped to the TreeSeed repository. Required repository permissions: Contents read/write, Environments read/write, Secrets and variables read/write, Actions and workflows read/write, Pull requests read/write, Issues read/write. Then paste it here as GH_TOKEN."
7
7
  sensitivity: secret
8
8
  targets:
9
- - local-file
9
+ - local-runtime
10
10
  - railway-secret
11
11
  scopes:
12
12
  - local
@@ -18,6 +18,7 @@ entries:
18
18
  - config
19
19
  validation:
20
20
  kind: nonempty
21
+ minLength: 8
21
22
  sourcePriority:
22
23
  - machine-config
23
24
  - process-env
@@ -28,7 +29,7 @@ entries:
28
29
  howToGet: "Create a Cloudflare account-level API token scoped to the target domain and account. Required permissions: Account Cloudflare Pages edit, Account Workers Scripts edit, Account Workers KV Storage edit, Account D1 edit, Account Queues edit, Zone DNS edit. Then paste it here as CLOUDFLARE_API_TOKEN."
29
30
  sensitivity: secret
30
31
  targets:
31
- - local-file
32
+ - local-runtime
32
33
  - github-secret
33
34
  scopes:
34
35
  - local
@@ -42,6 +43,7 @@ entries:
42
43
  - config
43
44
  validation:
44
45
  kind: nonempty
46
+ minLength: 8
45
47
  sourcePriority:
46
48
  - machine-config
47
49
  - process-env
@@ -49,10 +51,10 @@ entries:
49
51
  label: Railway API token
50
52
  group: auth
51
53
  description: Primary Railway token for user or workspace scoped access, including project creation and most Treeseed-managed Railway flows.
52
- howToGet: In Railway, create a user or workspace API token that can create and manage the target project, then paste it here as RAILWAY_API_TOKEN.
54
+ howToGet: In Railway, create a user or workspace API token that can create and manage the target project, then paste it here. Treeseed also accepts the legacy alias RAILWAY_API_KEY from process env.
53
55
  sensitivity: secret
54
56
  targets:
55
- - local-file
57
+ - local-runtime
56
58
  - railway-secret
57
59
  scopes:
58
60
  - local
@@ -65,6 +67,7 @@ entries:
65
67
  - config
66
68
  validation:
67
69
  kind: nonempty
70
+ minLength: 8
68
71
  sourcePriority:
69
72
  - machine-config
70
73
  - process-env
@@ -77,7 +80,7 @@ entries:
77
80
  howToGet: In Railway, generate a project-scoped token only if you need project resource management separate from the primary API token, then paste it here as RAILWAY_TOKEN.
78
81
  sensitivity: secret
79
82
  targets:
80
- - local-file
83
+ - local-runtime
81
84
  - railway-secret
82
85
  scopes:
83
86
  - local
@@ -90,6 +93,7 @@ entries:
90
93
  - config
91
94
  validation:
92
95
  kind: nonempty
96
+ minLength: 8
93
97
  sourcePriority:
94
98
  - machine-config
95
99
  - process-env
@@ -101,7 +105,7 @@ entries:
101
105
  howToGet: In the Cloudflare dashboard, open Workers & Pages or Account Home and copy the account ID.
102
106
  sensitivity: plain
103
107
  targets:
104
- - local-file
108
+ - local-runtime
105
109
  - github-variable
106
110
  - config-file
107
111
  scopes:
@@ -126,14 +130,15 @@ entries:
126
130
  howToGet: Treeseed can generate a strong random secret for you. Reuse it across environments only if that matches your security model.
127
131
  sensitivity: secret
128
132
  targets:
129
- - local-file
130
- - wrangler-dev-vars
133
+ - local-runtime
134
+ - local-cloudflare
131
135
  - github-secret
132
136
  - cloudflare-secret
133
137
  scopes:
134
138
  - local
135
139
  - staging
136
140
  - prod
141
+ storage: shared
137
142
  requirement: required
138
143
  purposes:
139
144
  - dev
@@ -154,14 +159,15 @@ entries:
154
159
  howToGet: Create a Turnstile widget in Cloudflare Turnstile and copy the site key.
155
160
  sensitivity: plain
156
161
  targets:
157
- - local-file
158
- - wrangler-dev-vars
162
+ - local-runtime
163
+ - local-cloudflare
159
164
  - github-variable
160
165
  - cloudflare-var
161
166
  scopes:
162
167
  - local
163
168
  - staging
164
169
  - prod
170
+ storage: shared
165
171
  requirement: conditional
166
172
  purposes:
167
173
  - dev
@@ -182,14 +188,15 @@ entries:
182
188
  howToGet: Create a Turnstile widget in Cloudflare Turnstile and copy the secret key.
183
189
  sensitivity: secret
184
190
  targets:
185
- - local-file
186
- - wrangler-dev-vars
191
+ - local-runtime
192
+ - local-cloudflare
187
193
  - github-secret
188
194
  - cloudflare-secret
189
195
  scopes:
190
196
  - local
191
197
  - staging
192
198
  - prod
199
+ storage: shared
193
200
  requirement: conditional
194
201
  purposes:
195
202
  - dev
@@ -210,8 +217,8 @@ entries:
210
217
  howToGet: Treeseed defaults this to true for local development. You can switch it off if you want to test with real Turnstile keys locally.
211
218
  sensitivity: plain
212
219
  targets:
213
- - local-file
214
- - wrangler-dev-vars
220
+ - local-runtime
221
+ - local-cloudflare
215
222
  scopes:
216
223
  - local
217
224
  requirement: optional
@@ -231,14 +238,15 @@ entries:
231
238
  howToGet: Use the SMTP hostname from your email provider or local Mailpit instance.
232
239
  sensitivity: plain
233
240
  targets:
234
- - local-file
235
- - wrangler-dev-vars
241
+ - local-runtime
242
+ - local-cloudflare
236
243
  - github-variable
237
244
  - cloudflare-var
238
245
  scopes:
239
246
  - local
240
247
  - staging
241
248
  - prod
249
+ storage: shared
242
250
  requirement: conditional
243
251
  purposes:
244
252
  - dev
@@ -259,14 +267,15 @@ entries:
259
267
  howToGet: Use the port provided by your email service, commonly 587, 465, or the Mailpit local port.
260
268
  sensitivity: plain
261
269
  targets:
262
- - local-file
263
- - wrangler-dev-vars
270
+ - local-runtime
271
+ - local-cloudflare
264
272
  - github-variable
265
273
  - cloudflare-var
266
274
  scopes:
267
275
  - local
268
276
  - staging
269
277
  - prod
278
+ storage: shared
270
279
  requirement: conditional
271
280
  purposes:
272
281
  - dev
@@ -287,14 +296,15 @@ entries:
287
296
  howToGet: Use the SMTP username or mailbox identity from your email provider.
288
297
  sensitivity: plain
289
298
  targets:
290
- - local-file
291
- - wrangler-dev-vars
299
+ - local-runtime
300
+ - local-cloudflare
292
301
  - github-variable
293
302
  - cloudflare-var
294
303
  scopes:
295
304
  - local
296
305
  - staging
297
306
  - prod
307
+ storage: shared
298
308
  requirement: conditional
299
309
  purposes:
300
310
  - dev
@@ -315,14 +325,15 @@ entries:
315
325
  howToGet: Use the SMTP password or app-specific password from your email provider.
316
326
  sensitivity: secret
317
327
  targets:
318
- - local-file
319
- - wrangler-dev-vars
328
+ - local-runtime
329
+ - local-cloudflare
320
330
  - github-secret
321
331
  - cloudflare-secret
322
332
  scopes:
323
333
  - local
324
334
  - staging
325
335
  - prod
336
+ storage: shared
326
337
  requirement: conditional
327
338
  purposes:
328
339
  - dev
@@ -343,14 +354,15 @@ entries:
343
354
  howToGet: Use a verified sender address from your SMTP provider.
344
355
  sensitivity: plain
345
356
  targets:
346
- - local-file
347
- - wrangler-dev-vars
357
+ - local-runtime
358
+ - local-cloudflare
348
359
  - github-variable
349
360
  - cloudflare-var
350
361
  scopes:
351
362
  - local
352
363
  - staging
353
364
  - prod
365
+ storage: shared
354
366
  requirement: conditional
355
367
  purposes:
356
368
  - dev
@@ -371,14 +383,15 @@ entries:
371
383
  howToGet: Use a monitored mailbox that should receive replies from end users.
372
384
  sensitivity: plain
373
385
  targets:
374
- - local-file
375
- - wrangler-dev-vars
386
+ - local-runtime
387
+ - local-cloudflare
376
388
  - github-variable
377
389
  - cloudflare-var
378
390
  scopes:
379
391
  - local
380
392
  - staging
381
393
  - prod
394
+ storage: shared
382
395
  requirement: conditional
383
396
  purposes:
384
397
  - dev
package/dist/index.d.ts CHANGED
@@ -4,6 +4,7 @@ export { parseSiteConfig } from './utils/site-config-schema.js';
4
4
  export { createTreeseedApiApp } from './api/app';
5
5
  export { createRailwayTreeseedApiServer } from './api/railway';
6
6
  export { resolveApiConfig } from './api/config';
7
+ export { executeKnowledgeCoopManagedLaunch, validateKnowledgeCoopManagedLaunchPrerequisites, } from './launch';
7
8
  export { createTreeseedIntegratedDevPlan, runTreeseedIntegratedDev, type TreeseedIntegratedDevCommand, type TreeseedIntegratedDevOptions, type TreeseedIntegratedDevPlan, type TreeseedIntegratedDevSurface, } from './dev';
8
9
  export { filterSiteRenderedModels, isSiteRenderedModel, siteModelRendered, } from './utils/site-models.ts';
9
10
  export type * from './api/types';
package/dist/index.js CHANGED
@@ -14,6 +14,10 @@ import { parseSiteConfig } from "./utils/site-config-schema.js";
14
14
  import { createTreeseedApiApp } from "./api/app.js";
15
15
  import { createRailwayTreeseedApiServer } from "./api/railway.js";
16
16
  import { resolveApiConfig } from "./api/config.js";
17
+ import {
18
+ executeKnowledgeCoopManagedLaunch,
19
+ validateKnowledgeCoopManagedLaunchPrerequisites
20
+ } from "./launch.js";
17
21
  import {
18
22
  createTreeseedIntegratedDevPlan,
19
23
  runTreeseedIntegratedDev
@@ -31,6 +35,7 @@ export {
31
35
  createRailwayTreeseedApiServer,
32
36
  createTreeseedApiApp,
33
37
  createTreeseedIntegratedDevPlan,
38
+ executeKnowledgeCoopManagedLaunch,
34
39
  filterSiteRenderedModels,
35
40
  isSiteRenderedModel,
36
41
  parseSiteConfig,
@@ -40,5 +45,6 @@ export {
40
45
  resolveTreeseedSiteResource,
41
46
  resolveTreeseedStyleEntrypoint,
42
47
  runTreeseedIntegratedDev,
43
- siteModelRendered
48
+ siteModelRendered,
49
+ validateKnowledgeCoopManagedLaunchPrerequisites
44
50
  };
@@ -0,0 +1,3 @@
1
+ import { executeKnowledgeCoopManagedLaunch, validateKnowledgeCoopManagedLaunchPrerequisites, type KnowledgeCoopManagedLaunchInput, type KnowledgeCoopManagedLaunchResult, type KnowledgeCoopLaunchPreflightReport } from '@treeseed/sdk';
2
+ export { executeKnowledgeCoopManagedLaunch, validateKnowledgeCoopManagedLaunchPrerequisites, };
3
+ export type { KnowledgeCoopManagedLaunchInput, KnowledgeCoopManagedLaunchResult, KnowledgeCoopLaunchPreflightReport, };
package/dist/launch.js ADDED
@@ -0,0 +1,8 @@
1
+ import {
2
+ executeKnowledgeCoopManagedLaunch,
3
+ validateKnowledgeCoopManagedLaunchPrerequisites
4
+ } from "@treeseed/sdk";
5
+ export {
6
+ executeKnowledgeCoopManagedLaunch,
7
+ validateKnowledgeCoopManagedLaunchPrerequisites
8
+ };
@@ -1,7 +1,17 @@
1
1
  ---
2
2
  import MainLayout from './MainLayout.astro';
3
3
  import StatusBadge from '../components/content/StatusBadge.astro';
4
- import type { CollectionEntry } from 'astro:content';
4
+ import type { RuntimeReferenceEntry } from '../utils/site-content-runtime';
5
+
6
+ type LocalContributor = {
7
+ data: {
8
+ name: string;
9
+ };
10
+ };
11
+
12
+ function entryTitle(entry: RuntimeReferenceEntry) {
13
+ return entry.data.title ?? entry.data.name ?? entry.id;
14
+ }
5
15
 
6
16
  const {
7
17
  entry,
@@ -11,7 +21,11 @@ const {
11
21
  metaValue,
12
22
  relatedQuestions = [],
13
23
  relatedObjectives = [],
24
+ relatedNotes = [],
25
+ relatedProposals = [],
26
+ relatedDecisions = [],
14
27
  relatedBooks = [],
28
+ introText,
15
29
  } = Astro.props as {
16
30
  entry: {
17
31
  title: string;
@@ -19,16 +33,20 @@ const {
19
33
  summary: string;
20
34
  status: 'live' | 'in progress' | 'exploratory' | 'planned' | 'speculative';
21
35
  date: Date;
22
- motivation: string;
36
+ motivation?: string;
23
37
  tags: string[];
24
38
  };
25
39
  currentPath: string;
26
- contributor: CollectionEntry<'people'> | CollectionEntry<'agents'> | undefined | null;
40
+ contributor: LocalContributor | RuntimeReferenceEntry | undefined | null;
27
41
  metaLabel?: string;
28
42
  metaValue?: string;
29
- relatedQuestions?: CollectionEntry<'questions'>[];
30
- relatedObjectives?: CollectionEntry<'objectives'>[];
31
- relatedBooks?: CollectionEntry<'books'>[];
43
+ relatedQuestions?: RuntimeReferenceEntry[];
44
+ relatedObjectives?: RuntimeReferenceEntry[];
45
+ relatedNotes?: RuntimeReferenceEntry[];
46
+ relatedProposals?: RuntimeReferenceEntry[];
47
+ relatedDecisions?: RuntimeReferenceEntry[];
48
+ relatedBooks?: RuntimeReferenceEntry[];
49
+ introText?: string;
32
50
  };
33
51
  ---
34
52
 
@@ -43,7 +61,7 @@ const {
43
61
  </div>
44
62
  <h1 class="max-w-4xl font-serif text-5xl font-bold tracking-tight text-[color:var(--site-text)] md:text-6xl">{entry.title}</h1>
45
63
  <p class="max-w-3xl text-xl leading-10 text-[color:var(--site-text-muted)]">{entry.summary}</p>
46
- <p class="max-w-3xl text-base leading-8 text-[color:var(--site-text-muted)]">{entry.motivation}</p>
64
+ {(introText ?? entry.motivation) && <p class="max-w-3xl text-base leading-8 text-[color:var(--site-text-muted)]">{introText ?? entry.motivation}</p>}
47
65
  {entry.tags.length > 0 && (
48
66
  <p class="text-sm uppercase tracking-[0.14em] text-[color:var(--site-accent-strong)]">{entry.tags.join(' / ')}</p>
49
67
  )}
@@ -54,33 +72,63 @@ const {
54
72
  <div class="grid gap-6 border-t border-[color:var(--site-border)] pt-8 md:grid-cols-3">
55
73
  {relatedQuestions.length > 0 && (
56
74
  <div>
57
- <p class="text-sm font-semibold uppercase tracking-[0.14em] text-[color:var(--site-blue-strong)]">Related questions</p>
58
- <ul class="mt-3 space-y-2 text-[color:var(--site-text-muted)]">
59
- {relatedQuestions.map((question) => (
60
- <li><a href={`/questions/${question.id}/`} class="hover:text-[color:var(--site-text)]">{question.data.title}</a></li>
61
- ))}
62
- </ul>
63
- </div>
75
+ <p class="text-sm font-semibold uppercase tracking-[0.14em] text-[color:var(--site-blue-strong)]">Related questions</p>
76
+ <ul class="mt-3 space-y-2 text-[color:var(--site-text-muted)]">
77
+ {relatedQuestions.map((question) => (
78
+ <li><a href={`/questions/${question.id}/`} class="hover:text-[color:var(--site-text)]">{entryTitle(question)}</a></li>
79
+ ))}
80
+ </ul>
81
+ </div>
64
82
  )}
65
83
  {relatedObjectives.length > 0 && (
66
84
  <div>
67
- <p class="text-sm font-semibold uppercase tracking-[0.14em] text-[color:var(--site-blue-strong)]">Related objectives</p>
68
- <ul class="mt-3 space-y-2 text-[color:var(--site-text-muted)]">
69
- {relatedObjectives.map((objective) => (
70
- <li><a href={`/objectives/${objective.id}/`} class="hover:text-[color:var(--site-text)]">{objective.data.title}</a></li>
71
- ))}
72
- </ul>
73
- </div>
85
+ <p class="text-sm font-semibold uppercase tracking-[0.14em] text-[color:var(--site-blue-strong)]">Related objectives</p>
86
+ <ul class="mt-3 space-y-2 text-[color:var(--site-text-muted)]">
87
+ {relatedObjectives.map((objective) => (
88
+ <li><a href={`/objectives/${objective.id}/`} class="hover:text-[color:var(--site-text)]">{entryTitle(objective)}</a></li>
89
+ ))}
90
+ </ul>
91
+ </div>
92
+ )}
93
+ {relatedNotes.length > 0 && (
94
+ <div>
95
+ <p class="text-sm font-semibold uppercase tracking-[0.14em] text-[color:var(--site-blue-strong)]">Related notes</p>
96
+ <ul class="mt-3 space-y-2 text-[color:var(--site-text-muted)]">
97
+ {relatedNotes.map((note) => (
98
+ <li><a href={`/notes/${note.id}/`} class="hover:text-[color:var(--site-text)]">{entryTitle(note)}</a></li>
99
+ ))}
100
+ </ul>
101
+ </div>
102
+ )}
103
+ {relatedProposals.length > 0 && (
104
+ <div>
105
+ <p class="text-sm font-semibold uppercase tracking-[0.14em] text-[color:var(--site-blue-strong)]">Related proposals</p>
106
+ <ul class="mt-3 space-y-2 text-[color:var(--site-text-muted)]">
107
+ {relatedProposals.map((proposal) => (
108
+ <li><a href={`/proposals/${proposal.id}/`} class="hover:text-[color:var(--site-text)]">{entryTitle(proposal)}</a></li>
109
+ ))}
110
+ </ul>
111
+ </div>
112
+ )}
113
+ {relatedDecisions.length > 0 && (
114
+ <div>
115
+ <p class="text-sm font-semibold uppercase tracking-[0.14em] text-[color:var(--site-blue-strong)]">Related decisions</p>
116
+ <ul class="mt-3 space-y-2 text-[color:var(--site-text-muted)]">
117
+ {relatedDecisions.map((decision) => (
118
+ <li><a href={`/decisions/${decision.id}/`} class="hover:text-[color:var(--site-text)]">{entryTitle(decision)}</a></li>
119
+ ))}
120
+ </ul>
121
+ </div>
74
122
  )}
75
123
  {relatedBooks.length > 0 && (
76
124
  <div>
77
- <p class="text-sm font-semibold uppercase tracking-[0.14em] text-[color:var(--site-blue-strong)]">Related books</p>
78
- <ul class="mt-3 space-y-2 text-[color:var(--site-text-muted)]">
79
- {relatedBooks.map((book) => (
80
- <li><a href={`/books/${book.id}/`} class="hover:text-[color:var(--site-text)]">{book.data.title}</a></li>
81
- ))}
82
- </ul>
83
- </div>
125
+ <p class="text-sm font-semibold uppercase tracking-[0.14em] text-[color:var(--site-blue-strong)]">Related books</p>
126
+ <ul class="mt-3 space-y-2 text-[color:var(--site-text-muted)]">
127
+ {relatedBooks.map((book) => (
128
+ <li><a href={`/books/${book.id}/`} class="hover:text-[color:var(--site-text)]">{entryTitle(book)}</a></li>
129
+ ))}
130
+ </ul>
131
+ </div>
84
132
  )}
85
133
  </div>
86
134
  </article>