@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
@@ -13,29 +13,131 @@ import BookList from '../components/site/BookList.astro';
13
13
  import {
14
14
  getPublishedAgents,
15
15
  getPublishedBooks,
16
+ getPublishedDecisions,
16
17
  getPublishedNotes,
17
18
  getPublishedObjectives,
18
19
  getPublishedPeople,
20
+ getPublishedProposals,
19
21
  getPublishedQuestions,
20
22
  resolveContributorsForEntries,
21
23
  } from '../utils/hub-content';
24
+ import {
25
+ isPublishedRuntimeContentMode,
26
+ loadPublishedCollection,
27
+ loadPublishedEntry,
28
+ metadataFromPublishedContent,
29
+ resolvePublishedContributor,
30
+ } from '../utils/site-content-runtime';
22
31
  import { siteModelRendered } from '../utils/site-models.js';
23
32
 
24
33
  const notesRendered = siteModelRendered('notes');
25
34
  const questionsRendered = siteModelRendered('questions');
26
35
  const objectivesRendered = siteModelRendered('objectives');
36
+ const proposalsRendered = siteModelRendered('proposals');
37
+ const decisionsRendered = siteModelRendered('decisions');
27
38
  const peopleRendered = siteModelRendered('people');
28
39
  const agentsRendered = siteModelRendered('agents');
29
40
  const booksRendered = siteModelRendered('books');
30
41
 
31
- const notes = notesRendered ? (await getPublishedNotes()).slice(0, 3) : [];
32
- const questions = questionsRendered ? (await getPublishedQuestions()).slice(0, 2) : [];
33
- const objectives = objectivesRendered ? (await getPublishedObjectives()).slice(0, 2) : [];
34
- const questionContributors = await resolveContributorsForEntries(questions);
35
- const objectiveContributors = await resolveContributorsForEntries(objectives);
36
- const people = peopleRendered ? (await getPublishedPeople()).slice(0, 2) : [];
37
- const agents = agentsRendered ? (await getPublishedAgents()).slice(0, 2) : [];
38
- const books = booksRendered ? await getPublishedBooks() : [];
42
+ const publishedRuntime = isPublishedRuntimeContentMode();
43
+ const notes = notesRendered
44
+ ? (
45
+ publishedRuntime
46
+ ? (await loadPublishedCollection(Astro.locals, 'notes')).sort((a, b) => b.data.date.valueOf() - a.data.date.valueOf())
47
+ : await getPublishedNotes()
48
+ ).slice(0, 3)
49
+ : [];
50
+ const questions = questionsRendered
51
+ ? (
52
+ publishedRuntime
53
+ ? (await loadPublishedCollection(Astro.locals, 'questions')).sort((a, b) => b.data.date.valueOf() - a.data.date.valueOf())
54
+ : await getPublishedQuestions()
55
+ ).slice(0, 2)
56
+ : [];
57
+ const objectives = objectivesRendered
58
+ ? (
59
+ publishedRuntime
60
+ ? (await loadPublishedCollection(Astro.locals, 'objectives')).sort((a, b) => b.data.date.valueOf() - a.data.date.valueOf())
61
+ : await getPublishedObjectives()
62
+ ).slice(0, 2)
63
+ : [];
64
+ const proposals = proposalsRendered
65
+ ? (
66
+ publishedRuntime
67
+ ? (await loadPublishedCollection(Astro.locals, 'proposals')).sort((a, b) => b.data.date.valueOf() - a.data.date.valueOf())
68
+ : await getPublishedProposals()
69
+ ).slice(0, 2)
70
+ : [];
71
+ const decisions = decisionsRendered
72
+ ? (
73
+ publishedRuntime
74
+ ? (await loadPublishedCollection(Astro.locals, 'decisions')).sort((a, b) => b.data.date.valueOf() - a.data.date.valueOf())
75
+ : await getPublishedDecisions()
76
+ ).slice(0, 2)
77
+ : [];
78
+ const questionContributors = publishedRuntime
79
+ ? new Map(
80
+ await Promise.all(
81
+ questions.map(async (question) => {
82
+ const detail = await loadPublishedEntry(Astro.locals, 'questions', question.id);
83
+ const contributor = await resolvePublishedContributor(
84
+ Astro.locals,
85
+ metadataFromPublishedContent(detail?.content)?.primaryContributor,
86
+ );
87
+ return [question.id, contributor ?? null] as const;
88
+ }),
89
+ ),
90
+ )
91
+ : await resolveContributorsForEntries(questions);
92
+ const objectiveContributors = publishedRuntime
93
+ ? new Map(
94
+ await Promise.all(
95
+ objectives.map(async (objective) => {
96
+ const detail = await loadPublishedEntry(Astro.locals, 'objectives', objective.id);
97
+ const contributor = await resolvePublishedContributor(
98
+ Astro.locals,
99
+ metadataFromPublishedContent(detail?.content)?.primaryContributor,
100
+ );
101
+ return [objective.id, contributor ?? null] as const;
102
+ }),
103
+ ),
104
+ )
105
+ : await resolveContributorsForEntries(objectives);
106
+ const proposalContributors = publishedRuntime
107
+ ? new Map(
108
+ await Promise.all(
109
+ proposals.map(async (proposal) => {
110
+ const detail = await loadPublishedEntry(Astro.locals, 'proposals', proposal.id);
111
+ const contributor = await resolvePublishedContributor(
112
+ Astro.locals,
113
+ metadataFromPublishedContent(detail?.content)?.primaryContributor,
114
+ );
115
+ return [proposal.id, contributor ?? null] as const;
116
+ }),
117
+ ),
118
+ )
119
+ : await resolveContributorsForEntries(proposals);
120
+ const decisionContributors = publishedRuntime
121
+ ? new Map(
122
+ await Promise.all(
123
+ decisions.map(async (decision) => {
124
+ const detail = await loadPublishedEntry(Astro.locals, 'decisions', decision.id);
125
+ const contributor = await resolvePublishedContributor(
126
+ Astro.locals,
127
+ metadataFromPublishedContent(detail?.content)?.primaryContributor,
128
+ );
129
+ return [decision.id, contributor ?? null] as const;
130
+ }),
131
+ ),
132
+ )
133
+ : await resolveContributorsForEntries(decisions);
134
+ const people = peopleRendered ? (publishedRuntime ? (await loadPublishedCollection(Astro.locals, 'people')) : await getPublishedPeople()).slice(0, 2) : [];
135
+ const agents = agentsRendered ? (publishedRuntime ? (await loadPublishedCollection(Astro.locals, 'agents')) : await getPublishedAgents()).slice(0, 2) : [];
136
+ const books = booksRendered
137
+ ? publishedRuntime
138
+ ? (await loadPublishedCollection(Astro.locals, 'books')).sort((a, b) => Number(a.data.order ?? 0) - Number(b.data.order ?? 0))
139
+ : await getPublishedBooks()
140
+ : [];
39
141
  const ctaPrimaryHref = questionsRendered ? '/questions/' : objectivesRendered ? '/objectives/' : '/status/';
40
142
  const ctaPrimaryLabel = questionsRendered ? 'Browse questions' : objectivesRendered ? 'Browse objectives' : 'View status';
41
143
  const ctaSecondaryHref = booksRendered ? '/books/' : notesRendered ? '/notes/' : '/vision/';
@@ -62,7 +164,7 @@ const ctaSecondaryLabel = booksRendered ? 'Explore books' : notesRendered ? 'Rea
62
164
  TreeSeed works best when contributors can understand the package, inspect the
63
165
  tenant surface, and verify real workflows without reconstructing everything from
64
166
  source code alone. This fixture keeps those paths visible by combining pages,
65
- questions, objectives, books, agents, and forms in one generic working site.
167
+ questions, objectives, proposals, decisions, books, agents, and forms in one generic working site.
66
168
  </p>
67
169
  </div>
68
170
  <div slot="actions">
@@ -72,7 +174,7 @@ const ctaSecondaryLabel = booksRendered ? 'Explore books' : notesRendered ? 'Rea
72
174
  <div slot="aside" class="space-y-4">
73
175
  <p class="text-sm font-semibold uppercase tracking-[0.16em] text-[color:var(--site-blue-strong)]">Right now</p>
74
176
  <ul class="space-y-4 text-base leading-8 text-[color:var(--site-text-muted)]">
75
- <li>A full TreeSeed content surface with pages, notes, questions, objectives, people, agents, books, and docs.</li>
177
+ <li>A full TreeSeed content surface with pages, notes, questions, objectives, proposals, decisions, people, agents, books, and docs.</li>
76
178
  <li>Package defaults exercised through a realistic tenant instead of isolated unit tests alone.</li>
77
179
  <li>Forms, book exports, and navigation paths that participate in release verification.</li>
78
180
  <li>A documentation-first example meant to stay easy to inspect and easy to maintain.</li>
@@ -117,10 +219,10 @@ const ctaSecondaryLabel = booksRendered ? 'Explore books' : notesRendered ? 'Rea
117
219
  <div class="border border-[color:var(--site-border)] bg-[color:var(--site-surface)] p-6">
118
220
  <h2 class="font-serif text-2xl text-[color:var(--site-text)]">Content commitments</h2>
119
221
  <ul class="mt-4 space-y-3 text-base leading-8 text-[color:var(--site-text-muted)]">
120
- <li>Questions and objectives stay visible instead of disappearing into process notes.</li>
222
+ <li>Questions, objectives, proposals, and decisions stay visible instead of disappearing into process notes.</li>
121
223
  <li>Books and docs remain queryable content, not only navigation configuration.</li>
122
224
  <li>People and agents are explicit contributors rather than invisible supporting actors.</li>
123
- <li>Notes provide a lightweight place to explain decisions as the site changes.</li>
225
+ <li>Notes can still capture evidence and rationale without replacing proposal and decision records.</li>
124
226
  </ul>
125
227
  </div>
126
228
  <div class="border border-[color:var(--site-border)] bg-[color:var(--site-surface)] p-6">
@@ -145,7 +247,7 @@ const ctaSecondaryLabel = booksRendered ? 'Explore books' : notesRendered ? 'Rea
145
247
  <div class="space-y-4 text-base leading-8 text-[color:var(--site-text-muted)]">
146
248
  <p>
147
249
  The current fixture demonstrates the full TreeSeed surface: pages, notes, questions,
148
- objectives, people, agents, books, docs, and forms. That gives package changes a
250
+ objectives, proposals, decisions, people, agents, books, docs, and forms. That gives package changes a
149
251
  tenant-level target instead of relying on isolated examples.
150
252
  </p>
151
253
  <p>
@@ -206,12 +308,12 @@ const ctaSecondaryLabel = booksRendered ? 'Explore books' : notesRendered ? 'Rea
206
308
  </section>
207
309
  )}
208
310
 
209
- {(questionsRendered || objectivesRendered || peopleRendered || agentsRendered || booksRendered) && (
311
+ {(questionsRendered || objectivesRendered || proposalsRendered || decisionsRendered || peopleRendered || agentsRendered || booksRendered) && (
210
312
  <section class="space-y-8 border-t border-[color:var(--site-border)] pt-10">
211
313
  <SectionIntro
212
314
  eyebrow="TreeSeed"
213
- title="Questions, objectives, contributors, and books form one connected working surface"
214
- description="The fixture shows how humans and agents can publish questions, anchor them to objectives, and connect that work to books and contributor profiles."
315
+ title="Questions, objectives, proposals, decisions, contributors, and books form one connected working surface"
316
+ description="The fixture shows how humans and agents can publish questions, anchor them to objectives, turn them into proposals, and record decisions without losing the surrounding context."
215
317
  />
216
318
  <div class="grid gap-10 lg:grid-cols-2">
217
319
  {questionsRendered && (
@@ -255,6 +357,48 @@ const ctaSecondaryLabel = booksRendered ? 'Explore books' : notesRendered ? 'Rea
255
357
  </div>
256
358
  )}
257
359
  </div>
360
+ <div class="grid gap-10 lg:grid-cols-2">
361
+ {proposalsRendered && (
362
+ <div class="space-y-6">
363
+ <SectionIntro
364
+ eyebrow="Proposals"
365
+ title="Suggested change"
366
+ description="Proposals make the next suggested move explicit instead of leaving it scattered across notes or implied by workstream activity."
367
+ />
368
+ <ChronicleList
369
+ items={proposals.map((proposal) => ({
370
+ href: `/proposals/${proposal.id}/`,
371
+ title: proposal.data.title,
372
+ summary: proposal.data.summary,
373
+ status: proposal.data.status,
374
+ date: proposal.data.date,
375
+ meta: proposalContributors.get(proposal.id)?.data.name,
376
+ tags: proposal.data.tags,
377
+ }))}
378
+ />
379
+ </div>
380
+ )}
381
+ {decisionsRendered && (
382
+ <div class="space-y-6">
383
+ <SectionIntro
384
+ eyebrow="Decisions"
385
+ title="Chosen path"
386
+ description="Decisions record what was actually accepted, deferred, rejected, or superseded so the site can accumulate institutional memory instead of only discussion."
387
+ />
388
+ <ChronicleList
389
+ items={decisions.map((decision) => ({
390
+ href: `/decisions/${decision.id}/`,
391
+ title: decision.data.title,
392
+ summary: decision.data.summary,
393
+ status: decision.data.status,
394
+ date: decision.data.date,
395
+ meta: decisionContributors.get(decision.id)?.data.name,
396
+ tags: decision.data.tags,
397
+ }))}
398
+ />
399
+ </div>
400
+ )}
401
+ </div>
258
402
  <div class="grid gap-10 lg:grid-cols-2">
259
403
  {(peopleRendered || agentsRendered) && (
260
404
  <div class="space-y-6">
@@ -1,26 +1,31 @@
1
1
  ---
2
2
  import { getCollection, render } from 'astro:content';
3
3
  import NoteLayout from '../../layouts/NoteLayout.astro';
4
+ import PublishedContentBody from '../../components/site/PublishedContentBody.astro';
4
5
  import RouteNotFound from '../../components/site/RouteNotFound.astro';
6
+ import { isPublishedRuntimeContentMode, loadPublishedEntry } from '../../utils/site-content-runtime';
5
7
 
6
8
  export const prerender = false;
7
9
 
8
10
  const slug = String(Astro.params.slug ?? '');
9
- const notes = await getCollection('notes', ({ data }) => !data.draft);
10
- const note = notes.find((candidate) => candidate.id === slug) ?? null;
11
+ const publishedRuntime = isPublishedRuntimeContentMode();
12
+ const notes = publishedRuntime ? [] : await getCollection('notes', ({ data }) => !data.draft);
13
+ const localNote = publishedRuntime ? null : notes.find((candidate) => candidate.id === slug) ?? null;
14
+ const publishedNote = publishedRuntime ? await loadPublishedEntry(Astro.locals, 'notes', slug) : null;
15
+ const note = publishedRuntime ? publishedNote?.entry ?? null : localNote;
11
16
  if (!note) {
12
17
  Astro.response.status = 404;
13
18
  }
14
- const rendered = note ? await render(note) : null;
19
+ const rendered = !publishedRuntime && localNote ? await render(localNote) : null;
15
20
  const Content = rendered?.Content ?? null;
16
21
  ---
17
22
 
18
23
  {
19
- !note || !Content ? (
24
+ !note || (!Content && !publishedNote?.html) ? (
20
25
  <RouteNotFound title="Note not found" description="The requested note could not be found in this Treeseed." currentPath="/notes/" />
21
26
  ) : (
22
27
  <NoteLayout note={note.data}>
23
- <Content />
28
+ {publishedRuntime ? <PublishedContentBody html={publishedNote?.html ?? ''} /> : <Content />}
24
29
  </NoteLayout>
25
30
  )
26
31
  }
@@ -3,10 +3,13 @@ import { getCollection } from 'astro:content';
3
3
  import MainLayout from '../../layouts/MainLayout.astro';
4
4
  import SectionIntro from '../../components/site/SectionIntro.astro';
5
5
  import NotesList from '../../components/site/NotesList.astro';
6
+ import { isPublishedRuntimeContentMode, loadPublishedCollection } from '../../utils/site-content-runtime';
6
7
 
7
- const notes = (await getCollection('notes', ({ data }) => !data.draft)).sort(
8
- (a, b) => b.data.date.valueOf() - a.data.date.valueOf(),
9
- );
8
+ const notes = isPublishedRuntimeContentMode()
9
+ ? (await loadPublishedCollection(Astro.locals, 'notes')).sort((a, b) => b.data.date.valueOf() - a.data.date.valueOf())
10
+ : (await getCollection('notes', ({ data }) => !data.draft)).sort(
11
+ (a, b) => b.data.date.valueOf() - a.data.date.valueOf(),
12
+ );
10
13
  ---
11
14
 
12
15
  <MainLayout title="Notes" description="Public working notes from the TreeSeed fixture site." currentPath="/notes/">
@@ -2,25 +2,43 @@
2
2
  import { getCollection, render } from 'astro:content';
3
3
  import AuthoredEntryLayout from '../../layouts/AuthoredEntryLayout.astro';
4
4
  import { resolveContributor, resolveReferences } from '../../utils/hub-content';
5
+ import PublishedContentBody from '../../components/site/PublishedContentBody.astro';
5
6
  import RouteNotFound from '../../components/site/RouteNotFound.astro';
7
+ import {
8
+ isPublishedRuntimeContentMode,
9
+ loadPublishedEntry,
10
+ metadataFromPublishedContent,
11
+ resolvePublishedContributor,
12
+ resolvePublishedReferences,
13
+ } from '../../utils/site-content-runtime';
6
14
 
7
15
  export const prerender = false;
8
16
 
9
17
  const slug = String(Astro.params.slug ?? '');
10
- const objectives = await getCollection('objectives', ({ data }) => !data.draft);
11
- const objective = objectives.find((candidate) => candidate.id === slug) ?? null;
18
+ const publishedRuntime = isPublishedRuntimeContentMode();
19
+ const objectives = publishedRuntime ? [] : await getCollection('objectives', ({ data }) => !data.draft);
20
+ const localObjective = publishedRuntime ? null : objectives.find((candidate) => candidate.id === slug) ?? null;
21
+ const publishedObjective = publishedRuntime ? await loadPublishedEntry(Astro.locals, 'objectives', slug) : null;
22
+ const objective = publishedRuntime ? publishedObjective?.entry ?? null : localObjective;
23
+ const metadata = publishedRuntime ? metadataFromPublishedContent(publishedObjective?.content) : null;
12
24
  if (!objective) {
13
25
  Astro.response.status = 404;
14
26
  }
15
- const rendered = objective ? await render(objective) : null;
27
+ const rendered = !publishedRuntime && localObjective ? await render(localObjective) : null;
16
28
  const Content = rendered?.Content ?? null;
17
- const contributor = objective ? await resolveContributor(objective.data.primaryContributor) : null;
18
- const relatedQuestions = objective ? await resolveReferences(objective.data.relatedQuestions) : [];
19
- const relatedBooks = objective ? await resolveReferences(objective.data.relatedBooks) : [];
29
+ const contributor = publishedRuntime
30
+ ? await resolvePublishedContributor(Astro.locals, metadata?.primaryContributor)
31
+ : objective ? await resolveContributor(objective.data.primaryContributor) : null;
32
+ const relatedQuestions = publishedRuntime
33
+ ? await resolvePublishedReferences(Astro.locals, 'questions', metadata?.relatedQuestions)
34
+ : objective ? await resolveReferences(objective.data.relatedQuestions) : [];
35
+ const relatedBooks = publishedRuntime
36
+ ? await resolvePublishedReferences(Astro.locals, 'books', metadata?.relatedBooks)
37
+ : objective ? await resolveReferences(objective.data.relatedBooks) : [];
20
38
  ---
21
39
 
22
40
  {
23
- !objective || !Content ? (
41
+ !objective || (!Content && !publishedObjective?.html) ? (
24
42
  <RouteNotFound title="Objective not found" description="The requested objective could not be found in this Treeseed." currentPath="/objectives/" />
25
43
  ) : (
26
44
  <AuthoredEntryLayout
@@ -28,11 +46,11 @@ const relatedBooks = objective ? await resolveReferences(objective.data.relatedB
28
46
  currentPath="/objectives/"
29
47
  contributor={contributor}
30
48
  metaLabel="Time horizon"
31
- metaValue={objective.data.timeHorizon}
49
+ metaValue={String(objective.data.timeHorizon ?? '')}
32
50
  relatedQuestions={relatedQuestions}
33
51
  relatedBooks={relatedBooks}
34
52
  >
35
- <Content />
53
+ {publishedRuntime ? <PublishedContentBody html={publishedObjective?.html ?? ''} /> : <Content />}
36
54
  </AuthoredEntryLayout>
37
55
  )
38
56
  }
@@ -3,9 +3,26 @@ import MainLayout from '../../layouts/MainLayout.astro';
3
3
  import SectionIntro from '../../components/site/SectionIntro.astro';
4
4
  import ChronicleList from '../../components/site/ChronicleList.astro';
5
5
  import { getPublishedObjectives, resolveContributorsForEntries } from '../../utils/hub-content';
6
+ import { isPublishedRuntimeContentMode, loadPublishedCollection, resolvePublishedContributor, metadataFromPublishedContent, loadPublishedEntry } from '../../utils/site-content-runtime';
6
7
 
7
- const objectives = await getPublishedObjectives();
8
- const contributors = await resolveContributorsForEntries(objectives);
8
+ const publishedRuntime = isPublishedRuntimeContentMode();
9
+ const objectives = publishedRuntime
10
+ ? (await loadPublishedCollection(Astro.locals, 'objectives')).sort((a, b) => b.data.date.valueOf() - a.data.date.valueOf())
11
+ : await getPublishedObjectives();
12
+ const contributors = publishedRuntime
13
+ ? new Map(
14
+ await Promise.all(
15
+ objectives.map(async (objective) => {
16
+ const detail = await loadPublishedEntry(Astro.locals, 'objectives', objective.id);
17
+ const contributor = await resolvePublishedContributor(
18
+ Astro.locals,
19
+ metadataFromPublishedContent(detail?.content)?.primaryContributor,
20
+ );
21
+ return [objective.id, contributor ?? null] as const;
22
+ }),
23
+ ),
24
+ )
25
+ : await resolveContributorsForEntries(objectives);
9
26
  ---
10
27
 
11
28
  <MainLayout title="Objectives" description="Strategic objectives guiding the TreeSeed working site." currentPath="/objectives/">
@@ -2,24 +2,34 @@
2
2
  import { getCollection, render } from 'astro:content';
3
3
  import ProfileLayout from '../../layouts/ProfileLayout.astro';
4
4
  import { resolveReferences } from '../../utils/hub-content';
5
+ import PublishedContentBody from '../../components/site/PublishedContentBody.astro';
5
6
  import RouteNotFound from '../../components/site/RouteNotFound.astro';
7
+ import { isPublishedRuntimeContentMode, loadPublishedEntry, metadataFromPublishedContent, resolvePublishedReferences } from '../../utils/site-content-runtime';
6
8
 
7
9
  export const prerender = false;
8
10
 
9
11
  const slug = String(Astro.params.slug ?? '');
10
- const people = await getCollection('people');
11
- const person = people.find((candidate) => candidate.id === slug) ?? null;
12
+ const publishedRuntime = isPublishedRuntimeContentMode();
13
+ const people = publishedRuntime ? [] : await getCollection('people');
14
+ const localPerson = publishedRuntime ? null : people.find((candidate) => candidate.id === slug) ?? null;
15
+ const publishedPerson = publishedRuntime ? await loadPublishedEntry(Astro.locals, 'people', slug) : null;
16
+ const person = publishedRuntime ? publishedPerson?.entry ?? null : localPerson;
17
+ const metadata = publishedRuntime ? metadataFromPublishedContent(publishedPerson?.content) : null;
12
18
  if (!person) {
13
19
  Astro.response.status = 404;
14
20
  }
15
- const rendered = person ? await render(person) : null;
21
+ const rendered = !publishedRuntime && localPerson ? await render(localPerson) : null;
16
22
  const Content = rendered?.Content ?? null;
17
- const relatedQuestions = person ? await resolveReferences(person.data.relatedQuestions) : [];
18
- const relatedObjectives = person ? await resolveReferences(person.data.relatedObjectives) : [];
23
+ const relatedQuestions = publishedRuntime
24
+ ? await resolvePublishedReferences(Astro.locals, 'questions', metadata?.relatedQuestions)
25
+ : person ? await resolveReferences(person.data.relatedQuestions) : [];
26
+ const relatedObjectives = publishedRuntime
27
+ ? await resolvePublishedReferences(Astro.locals, 'objectives', metadata?.relatedObjectives)
28
+ : person ? await resolveReferences(person.data.relatedObjectives) : [];
19
29
  ---
20
30
 
21
31
  {
22
- !person || !Content ? (
32
+ !person || (!Content && !publishedPerson?.html) ? (
23
33
  <RouteNotFound title="Profile not found" description="The requested person profile could not be found in this Treeseed." currentPath="/people/" />
24
34
  ) : (
25
35
  <ProfileLayout
@@ -30,7 +40,7 @@ const relatedObjectives = person ? await resolveReferences(person.data.relatedOb
30
40
  relatedQuestions={relatedQuestions}
31
41
  relatedObjectives={relatedObjectives}
32
42
  >
33
- <Content />
43
+ {publishedRuntime ? <PublishedContentBody html={publishedPerson?.html ?? ''} /> : <Content />}
34
44
  </ProfileLayout>
35
45
  )
36
46
  }
@@ -3,8 +3,9 @@ import { getCollection } from 'astro:content';
3
3
  import MainLayout from '../../layouts/MainLayout.astro';
4
4
  import SectionIntro from '../../components/site/SectionIntro.astro';
5
5
  import ProfileList from '../../components/site/ProfileList.astro';
6
+ import { isPublishedRuntimeContentMode, loadPublishedCollection } from '../../utils/site-content-runtime';
6
7
 
7
- const people = await getCollection('people');
8
+ const people = isPublishedRuntimeContentMode() ? await loadPublishedCollection(Astro.locals, 'people') : await getCollection('people');
8
9
  ---
9
10
 
10
11
  <MainLayout title="People" description="Human contributors participating in the TreeSeed working site." currentPath="/people/">
@@ -0,0 +1,72 @@
1
+ ---
2
+ import { getCollection, render } from 'astro:content';
3
+ import AuthoredEntryLayout from '../../layouts/AuthoredEntryLayout.astro';
4
+ import { resolveContributor, resolveReferences } from '../../utils/hub-content';
5
+ import PublishedContentBody from '../../components/site/PublishedContentBody.astro';
6
+ import RouteNotFound from '../../components/site/RouteNotFound.astro';
7
+ import {
8
+ isPublishedRuntimeContentMode,
9
+ loadPublishedEntry,
10
+ metadataFromPublishedContent,
11
+ resolvePublishedContributor,
12
+ resolvePublishedReferences,
13
+ } from '../../utils/site-content-runtime';
14
+
15
+ export const prerender = false;
16
+
17
+ const slug = String(Astro.params.slug ?? '');
18
+ const publishedRuntime = isPublishedRuntimeContentMode();
19
+ const proposals = publishedRuntime ? [] : await getCollection('proposals', ({ data }) => !data.draft);
20
+ const localProposal = publishedRuntime ? null : proposals.find((candidate) => candidate.id === slug) ?? null;
21
+ const publishedProposal = publishedRuntime ? await loadPublishedEntry(Astro.locals, 'proposals', slug) : null;
22
+ const proposal = publishedRuntime ? publishedProposal?.entry ?? null : localProposal;
23
+ const metadata = publishedRuntime ? metadataFromPublishedContent(publishedProposal?.content) : null;
24
+ if (!proposal) {
25
+ Astro.response.status = 404;
26
+ }
27
+ const rendered = !publishedRuntime && localProposal ? await render(localProposal) : null;
28
+ const Content = rendered?.Content ?? null;
29
+ const contributor = publishedRuntime
30
+ ? await resolvePublishedContributor(Astro.locals, metadata?.primaryContributor)
31
+ : proposal ? await resolveContributor(proposal.data.primaryContributor) : null;
32
+ const relatedObjectives = publishedRuntime
33
+ ? await resolvePublishedReferences(Astro.locals, 'objectives', metadata?.relatedObjectives)
34
+ : proposal ? await resolveReferences(proposal.data.relatedObjectives) : [];
35
+ const relatedQuestions = publishedRuntime
36
+ ? await resolvePublishedReferences(Astro.locals, 'questions', metadata?.relatedQuestions)
37
+ : proposal ? await resolveReferences(proposal.data.relatedQuestions) : [];
38
+ const relatedNotes = publishedRuntime
39
+ ? await resolvePublishedReferences(Astro.locals, 'notes', metadata?.relatedNotes)
40
+ : proposal ? await resolveReferences(proposal.data.relatedNotes) : [];
41
+ const relatedBooks = publishedRuntime
42
+ ? await resolvePublishedReferences(Astro.locals, 'books', metadata?.relatedBooks)
43
+ : proposal ? await resolveReferences(proposal.data.relatedBooks) : [];
44
+ const relatedDecisions = publishedRuntime
45
+ ? await resolvePublishedReferences(Astro.locals, 'decisions', metadata?.decision ? [String(metadata.decision)] : [])
46
+ : proposal?.data.decision ? await resolveReferences([proposal.data.decision]) : [];
47
+ const supersededProposals = publishedRuntime
48
+ ? await resolvePublishedReferences(Astro.locals, 'proposals', metadata?.supersedes)
49
+ : proposal ? await resolveReferences(proposal.data.supersedes) : [];
50
+ ---
51
+
52
+ {
53
+ !proposal || (!Content && !publishedProposal?.html) ? (
54
+ <RouteNotFound title="Proposal not found" description="The requested proposal could not be found in this Treeseed." currentPath="/proposals/" />
55
+ ) : (
56
+ <AuthoredEntryLayout
57
+ entry={proposal.data}
58
+ currentPath="/proposals/"
59
+ contributor={contributor}
60
+ metaLabel="Proposal type"
61
+ metaValue={String(proposal.data.proposalType ?? '')}
62
+ relatedObjectives={relatedObjectives}
63
+ relatedQuestions={relatedQuestions}
64
+ relatedNotes={relatedNotes}
65
+ relatedDecisions={relatedDecisions}
66
+ relatedProposals={supersededProposals}
67
+ relatedBooks={relatedBooks}
68
+ >
69
+ {publishedRuntime ? <PublishedContentBody html={publishedProposal?.html ?? ''} /> : <Content />}
70
+ </AuthoredEntryLayout>
71
+ )
72
+ }
@@ -0,0 +1,47 @@
1
+ ---
2
+ import MainLayout from '../../layouts/MainLayout.astro';
3
+ import SectionIntro from '../../components/site/SectionIntro.astro';
4
+ import ChronicleList from '../../components/site/ChronicleList.astro';
5
+ import { getPublishedProposals, resolveContributorsForEntries } from '../../utils/hub-content';
6
+ import { isPublishedRuntimeContentMode, loadPublishedCollection, resolvePublishedContributor, metadataFromPublishedContent, loadPublishedEntry } from '../../utils/site-content-runtime';
7
+
8
+ const publishedRuntime = isPublishedRuntimeContentMode();
9
+ const proposals = publishedRuntime
10
+ ? (await loadPublishedCollection(Astro.locals, 'proposals')).sort((a, b) => b.data.date.valueOf() - a.data.date.valueOf())
11
+ : await getPublishedProposals();
12
+ const contributors = publishedRuntime
13
+ ? new Map(
14
+ await Promise.all(
15
+ proposals.map(async (proposal) => {
16
+ const detail = await loadPublishedEntry(Astro.locals, 'proposals', proposal.id);
17
+ const contributor = await resolvePublishedContributor(
18
+ Astro.locals,
19
+ metadataFromPublishedContent(detail?.content)?.primaryContributor,
20
+ );
21
+ return [proposal.id, contributor ?? null] as const;
22
+ }),
23
+ ),
24
+ )
25
+ : await resolveContributorsForEntries(proposals);
26
+ ---
27
+
28
+ <MainLayout title="Proposals" description="Proposals that move Treeseed from context to an explicit suggested change." currentPath="/proposals/">
29
+ <div class="space-y-10">
30
+ <SectionIntro
31
+ eyebrow="Proposals"
32
+ title="Suggested changes made explicit"
33
+ description="Proposals are where TreeSeed turns observations and open questions into a concrete suggested change, policy, implementation, or research move."
34
+ />
35
+ <ChronicleList
36
+ items={proposals.map((proposal) => ({
37
+ href: `/proposals/${proposal.id}/`,
38
+ title: proposal.data.title,
39
+ summary: proposal.data.summary,
40
+ status: proposal.data.status,
41
+ date: proposal.data.date,
42
+ meta: contributors.get(proposal.id)?.data.name,
43
+ tags: proposal.data.tags,
44
+ }))}
45
+ />
46
+ </div>
47
+ </MainLayout>
@@ -2,25 +2,43 @@
2
2
  import { getCollection, render } from 'astro:content';
3
3
  import AuthoredEntryLayout from '../../layouts/AuthoredEntryLayout.astro';
4
4
  import { resolveContributor, resolveReferences } from '../../utils/hub-content';
5
+ import PublishedContentBody from '../../components/site/PublishedContentBody.astro';
5
6
  import RouteNotFound from '../../components/site/RouteNotFound.astro';
7
+ import {
8
+ isPublishedRuntimeContentMode,
9
+ loadPublishedEntry,
10
+ metadataFromPublishedContent,
11
+ resolvePublishedContributor,
12
+ resolvePublishedReferences,
13
+ } from '../../utils/site-content-runtime';
6
14
 
7
15
  export const prerender = false;
8
16
 
9
17
  const slug = String(Astro.params.slug ?? '');
10
- const questions = await getCollection('questions', ({ data }) => !data.draft);
11
- const question = questions.find((candidate) => candidate.id === slug) ?? null;
18
+ const publishedRuntime = isPublishedRuntimeContentMode();
19
+ const questions = publishedRuntime ? [] : await getCollection('questions', ({ data }) => !data.draft);
20
+ const localQuestion = publishedRuntime ? null : questions.find((candidate) => candidate.id === slug) ?? null;
21
+ const publishedQuestion = publishedRuntime ? await loadPublishedEntry(Astro.locals, 'questions', slug) : null;
22
+ const question = publishedRuntime ? publishedQuestion?.entry ?? null : localQuestion;
23
+ const metadata = publishedRuntime ? metadataFromPublishedContent(publishedQuestion?.content) : null;
12
24
  if (!question) {
13
25
  Astro.response.status = 404;
14
26
  }
15
- const rendered = question ? await render(question) : null;
27
+ const rendered = !publishedRuntime && localQuestion ? await render(localQuestion) : null;
16
28
  const Content = rendered?.Content ?? null;
17
- const contributor = question ? await resolveContributor(question.data.primaryContributor) : null;
18
- const relatedObjectives = question ? await resolveReferences(question.data.relatedObjectives) : [];
19
- const relatedBooks = question ? await resolveReferences(question.data.relatedBooks) : [];
29
+ const contributor = publishedRuntime
30
+ ? await resolvePublishedContributor(Astro.locals, metadata?.primaryContributor)
31
+ : question ? await resolveContributor(question.data.primaryContributor) : null;
32
+ const relatedObjectives = publishedRuntime
33
+ ? await resolvePublishedReferences(Astro.locals, 'objectives', metadata?.relatedObjectives)
34
+ : question ? await resolveReferences(question.data.relatedObjectives) : [];
35
+ const relatedBooks = publishedRuntime
36
+ ? await resolvePublishedReferences(Astro.locals, 'books', metadata?.relatedBooks)
37
+ : question ? await resolveReferences(question.data.relatedBooks) : [];
20
38
  ---
21
39
 
22
40
  {
23
- !question || !Content ? (
41
+ !question || (!Content && !publishedQuestion?.html) ? (
24
42
  <RouteNotFound title="Question not found" description="The requested question could not be found in this Treeseed." currentPath="/questions/" />
25
43
  ) : (
26
44
  <AuthoredEntryLayout
@@ -28,11 +46,11 @@ const relatedBooks = question ? await resolveReferences(question.data.relatedBoo
28
46
  currentPath="/questions/"
29
47
  contributor={contributor}
30
48
  metaLabel="Question type"
31
- metaValue={question.data.questionType}
49
+ metaValue={String(question.data.questionType ?? '')}
32
50
  relatedObjectives={relatedObjectives}
33
51
  relatedBooks={relatedBooks}
34
52
  >
35
- <Content />
53
+ {publishedRuntime ? <PublishedContentBody html={publishedQuestion?.html ?? ''} /> : <Content />}
36
54
  </AuthoredEntryLayout>
37
55
  )
38
56
  }