@treeseed/sdk 0.4.12 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/dist/control-plane-client.d.ts +60 -1
  2. package/dist/control-plane-client.js +59 -0
  3. package/dist/control-plane.d.ts +1 -1
  4. package/dist/control-plane.js +11 -4
  5. package/dist/d1-store.d.ts +58 -0
  6. package/dist/d1-store.js +64 -0
  7. package/dist/dispatch.js +6 -0
  8. package/dist/graph/schema.js +4 -0
  9. package/dist/index.d.ts +5 -1
  10. package/dist/index.js +32 -0
  11. package/dist/knowledge-coop.d.ts +223 -0
  12. package/dist/knowledge-coop.js +82 -0
  13. package/dist/model-registry.js +79 -0
  14. package/dist/operations/providers/default.js +128 -7
  15. package/dist/operations/services/config-runtime.d.ts +102 -24
  16. package/dist/operations/services/config-runtime.js +896 -160
  17. package/dist/operations/services/deploy.d.ts +223 -15
  18. package/dist/operations/services/deploy.js +626 -55
  19. package/dist/operations/services/git-workflow.d.ts +47 -3
  20. package/dist/operations/services/git-workflow.js +125 -19
  21. package/dist/operations/services/github-automation.d.ts +85 -0
  22. package/dist/operations/services/github-automation.js +220 -1
  23. package/dist/operations/services/key-agent.d.ts +118 -0
  24. package/dist/operations/services/key-agent.js +476 -0
  25. package/dist/operations/services/knowledge-coop-launch.d.ts +90 -0
  26. package/dist/operations/services/knowledge-coop-launch.js +753 -0
  27. package/dist/operations/services/knowledge-coop-packaging.d.ts +59 -0
  28. package/dist/operations/services/knowledge-coop-packaging.js +234 -0
  29. package/dist/operations/services/local-dev.d.ts +0 -1
  30. package/dist/operations/services/local-dev.js +1 -14
  31. package/dist/operations/services/project-platform.d.ts +42 -182
  32. package/dist/operations/services/project-platform.js +162 -59
  33. package/dist/operations/services/railway-deploy.d.ts +1 -0
  34. package/dist/operations/services/railway-deploy.js +31 -13
  35. package/dist/operations/services/runtime-tools.d.ts +52 -5
  36. package/dist/operations/services/runtime-tools.js +186 -26
  37. package/dist/operations/services/watch-dev.js +2 -4
  38. package/dist/operations/services/workspace-preflight.d.ts +4 -4
  39. package/dist/operations/services/workspace-preflight.js +22 -20
  40. package/dist/operations/services/workspace-save.d.ts +10 -1
  41. package/dist/operations/services/workspace-save.js +54 -3
  42. package/dist/operations/services/workspace-tools.d.ts +1 -0
  43. package/dist/operations/services/workspace-tools.js +20 -5
  44. package/dist/operations-registry.js +15 -8
  45. package/dist/operations-types.d.ts +2 -2
  46. package/dist/platform/contracts.d.ts +39 -3
  47. package/dist/platform/deploy-config.d.ts +12 -1
  48. package/dist/platform/deploy-config.js +214 -15
  49. package/dist/platform/deploy-runtime.d.ts +1 -0
  50. package/dist/platform/deploy-runtime.js +10 -2
  51. package/dist/platform/env.yaml +93 -61
  52. package/dist/platform/environment.d.ts +13 -2
  53. package/dist/platform/environment.js +90 -20
  54. package/dist/platform/plugins/constants.d.ts +1 -0
  55. package/dist/platform/plugins/constants.js +7 -6
  56. package/dist/platform/tenant/runtime-config.js +8 -1
  57. package/dist/platform/tenant-config.js +4 -0
  58. package/dist/platform/utils/site-config-schema.js +18 -0
  59. package/dist/plugin-default.js +2 -2
  60. package/dist/scripts/key-agent.js +165 -0
  61. package/dist/scripts/tenant-build.js +4 -1
  62. package/dist/scripts/tenant-check.js +4 -1
  63. package/dist/scripts/tenant-deploy.js +43 -4
  64. package/dist/scripts/tenant-dev.js +0 -1
  65. package/dist/scripts/workspace-start-warning.js +2 -2
  66. package/dist/sdk-types.d.ts +2 -2
  67. package/dist/sdk-types.js +2 -0
  68. package/dist/sdk.d.ts +13 -0
  69. package/dist/sdk.js +40 -0
  70. package/dist/stores/knowledge-coop-store.d.ts +56 -0
  71. package/dist/stores/knowledge-coop-store.js +482 -0
  72. package/dist/treeseed/template-catalog/templates/starter-basic/template/package.json +6 -2
  73. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/api/server.js +4 -0
  74. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/config.yaml +25 -0
  75. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content/decisions/adopt-initial-proposal-loop.mdx +22 -0
  76. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content/people/starter-steward.mdx +11 -0
  77. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content/proposals/establish-initial-proposal-loop.mdx +17 -0
  78. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/manifest.yaml +17 -10
  79. package/dist/treeseed/template-catalog/templates/starter-basic/template/treeseed.site.yaml +69 -7
  80. package/dist/treeseed/template-catalog/templates/starter-basic/template.config.json +1 -0
  81. package/dist/workflow/operations.d.ts +592 -243
  82. package/dist/workflow/operations.js +1908 -219
  83. package/dist/workflow/runs.d.ts +90 -0
  84. package/dist/workflow/runs.js +242 -0
  85. package/dist/workflow/session.d.ts +31 -0
  86. package/dist/workflow/session.js +97 -0
  87. package/dist/workflow-state.d.ts +88 -2
  88. package/dist/workflow-state.js +288 -26
  89. package/dist/workflow-support.d.ts +1 -1
  90. package/dist/workflow-support.js +32 -2
  91. package/dist/workflow.d.ts +93 -3
  92. package/dist/workflow.js +12 -0
  93. package/package.json +1 -1
  94. package/templates/github/deploy.workflow.yml +11 -1
  95. package/dist/scripts/sync-dev-vars.js +0 -6
  96. package/dist/scripts/workspace-close.js +0 -24
  97. package/dist/scripts/workspace-release.js +0 -42
  98. package/dist/scripts/workspace-start.js +0 -71
@@ -0,0 +1,223 @@
1
+ import type { ProjectConnection, RemoteJobStatus } from './sdk-types.ts';
2
+ export declare const KNOWLEDGE_COOP_TEAM_CAPABILITIES: readonly ["launch_projects", "edit_direct", "manage_workstreams", "stage_releases", "publish_releases", "publish_market_listings", "manage_products", "manage_billing", "approve_remote_execution"];
3
+ export declare const KNOWLEDGE_COOP_JOB_STATUSES: readonly ["queued", "running", "waiting_for_approval", "failed", "completed", "rolled_back", "cancelled"];
4
+ export declare const KNOWLEDGE_COOP_WORKSTREAM_STATES: readonly ["drafting", "active_local", "verifying", "saved_remote", "in_staging", "archived"];
5
+ export declare const KNOWLEDGE_COOP_RELEASE_STATES: readonly ["drafting", "waiting_on_verification", "ready_to_publish", "published", "rolled_back"];
6
+ export declare const KNOWLEDGE_COOP_SHARE_PACKAGE_STATES: readonly ["draft", "packaged", "ready_to_publish", "published", "archived", "failed"];
7
+ export declare const KNOWLEDGE_COOP_AGENT_MESSAGE_KINDS: readonly ["informational", "warning", "action_requested", "release_readiness"];
8
+ export type TeamCapability = (typeof KNOWLEDGE_COOP_TEAM_CAPABILITIES)[number];
9
+ export type KnowledgeCoopJobStatus = (typeof KNOWLEDGE_COOP_JOB_STATUSES)[number];
10
+ export type WorkstreamState = (typeof KNOWLEDGE_COOP_WORKSTREAM_STATES)[number];
11
+ export type ReleaseState = (typeof KNOWLEDGE_COOP_RELEASE_STATES)[number];
12
+ export type SharePackageState = (typeof KNOWLEDGE_COOP_SHARE_PACKAGE_STATES)[number];
13
+ export type AgentMessageKind = (typeof KNOWLEDGE_COOP_AGENT_MESSAGE_KINDS)[number];
14
+ export interface LinkedProjectRecordRef {
15
+ model: 'objective' | 'question' | 'note' | 'proposal' | 'decision';
16
+ id: string;
17
+ }
18
+ export interface DirectBoardItemSummary {
19
+ model: 'objective' | 'question' | 'note' | 'proposal' | 'decision';
20
+ id: string;
21
+ title: string;
22
+ status: string | null;
23
+ updatedAt: string | null;
24
+ linkedWorkstreamIds: string[];
25
+ linkedReleaseIds: string[];
26
+ }
27
+ export interface WorkstreamEvent {
28
+ id: string;
29
+ workstreamId: string;
30
+ projectId: string;
31
+ kind: string;
32
+ summary: string | null;
33
+ data: Record<string, unknown>;
34
+ createdAt: string;
35
+ }
36
+ export interface WorkstreamSummary {
37
+ id: string;
38
+ projectId: string;
39
+ title: string;
40
+ summary: string | null;
41
+ state: WorkstreamState;
42
+ branchName: string | null;
43
+ branchRef: string | null;
44
+ owner: string | null;
45
+ linkedItems: LinkedProjectRecordRef[];
46
+ verificationStatus: 'completed' | 'failed' | 'waiting' | null;
47
+ verificationSummary: string | null;
48
+ lastSaveAt: string | null;
49
+ lastStageAt: string | null;
50
+ archivedAt: string | null;
51
+ createdAt: string;
52
+ updatedAt: string;
53
+ metadata?: Record<string, unknown>;
54
+ }
55
+ export interface WorkstreamDetail extends WorkstreamSummary {
56
+ events: WorkstreamEvent[];
57
+ }
58
+ export interface ReleaseSummary {
59
+ id: string;
60
+ projectId: string;
61
+ version: string;
62
+ title: string | null;
63
+ state: ReleaseState;
64
+ summary: string | null;
65
+ workstreamIds: string[];
66
+ releaseTag: string | null;
67
+ commitSha: string | null;
68
+ publishedAt: string | null;
69
+ rolledBackAt: string | null;
70
+ createdAt: string;
71
+ updatedAt: string;
72
+ metadata?: Record<string, unknown>;
73
+ }
74
+ export interface ReleaseDetail extends ReleaseSummary {
75
+ items: Array<{
76
+ id: string;
77
+ workstreamId: string | null;
78
+ model: string | null;
79
+ recordId: string | null;
80
+ summary: string | null;
81
+ metadata?: Record<string, unknown>;
82
+ createdAt: string;
83
+ }>;
84
+ }
85
+ export interface SharePackageStatus {
86
+ id: string;
87
+ projectId: string;
88
+ kind: 'export' | 'template' | 'knowledge_pack' | 'market_listing';
89
+ state: SharePackageState;
90
+ title: string;
91
+ summary: string | null;
92
+ version: string | null;
93
+ outputPath: string | null;
94
+ artifactKey: string | null;
95
+ manifestKey: string | null;
96
+ publishedItemId: string | null;
97
+ lastError: string | null;
98
+ createdAt: string;
99
+ updatedAt: string;
100
+ metadata?: Record<string, unknown>;
101
+ }
102
+ export interface AgentStatusRecord {
103
+ agentSlug: string;
104
+ handler: string;
105
+ status: 'active' | 'idle' | 'failed' | 'waiting';
106
+ currentTask: string | null;
107
+ workstreamId: string | null;
108
+ lastMessage: string | null;
109
+ lastRunAt: string | null;
110
+ }
111
+ export interface AgentMessageRecord {
112
+ id: string;
113
+ agentSlug: string;
114
+ kind: AgentMessageKind;
115
+ type: string;
116
+ status: string;
117
+ summary: string;
118
+ workstreamId: string | null;
119
+ releaseId: string | null;
120
+ createdAt: string;
121
+ metadata?: Record<string, unknown>;
122
+ }
123
+ export interface ProjectConnectionStatus {
124
+ projectId: string;
125
+ connection: ProjectConnection | null;
126
+ connected: boolean;
127
+ hubMode?: 'treeseed_hosted' | 'customer_hosted' | null;
128
+ runtimeMode?: 'none' | 'byo_attached' | 'treeseed_managed' | null;
129
+ runtimeRegistration?: 'optional' | 'required' | 'none' | null;
130
+ runtimeAttached?: boolean;
131
+ runtimeReady?: boolean;
132
+ runnerReady: boolean;
133
+ projectApiReady: boolean;
134
+ mode: ProjectConnection['mode'] | 'disconnected';
135
+ }
136
+ export interface ProjectOverviewSummary {
137
+ projectId: string;
138
+ teamId: string;
139
+ health: {
140
+ state: string;
141
+ label: string;
142
+ reason: string;
143
+ };
144
+ counts: {
145
+ objectives: number;
146
+ questions: number;
147
+ notes: number;
148
+ proposals: number;
149
+ decisions: number;
150
+ activeWorkstreams: number;
151
+ agents: number;
152
+ releases: number;
153
+ };
154
+ connection: ProjectConnectionStatus;
155
+ nextBestAction: string;
156
+ recentActivity: Array<{
157
+ kind: string;
158
+ id: string;
159
+ title: string;
160
+ status: string | null;
161
+ timestamp: string | null;
162
+ summary: string | null;
163
+ metadata?: Record<string, unknown>;
164
+ }>;
165
+ }
166
+ export interface TeamHomeSummary {
167
+ teamId: string;
168
+ projects: ProjectOverviewSummary[];
169
+ inboxCount: number;
170
+ productsCount: number;
171
+ }
172
+ export interface TeamMemberSummary {
173
+ id: string;
174
+ teamId: string;
175
+ userId: string;
176
+ status: string;
177
+ displayName: string | null;
178
+ email: string | null;
179
+ roles: string[];
180
+ createdAt: string;
181
+ updatedAt: string;
182
+ }
183
+ export interface InboxItem {
184
+ id: string;
185
+ teamId: string;
186
+ projectId: string | null;
187
+ kind: string;
188
+ state: KnowledgeCoopJobStatus | string;
189
+ title: string;
190
+ summary: string | null;
191
+ href: string | null;
192
+ metadata?: Record<string, unknown>;
193
+ createdAt: string;
194
+ updatedAt: string;
195
+ }
196
+ export interface LaunchProjectRequest {
197
+ teamId: string;
198
+ name: string;
199
+ slug: string;
200
+ summary?: string | null;
201
+ sourceKind: 'blank' | 'template' | 'knowledge_pack';
202
+ sourceRef?: string | null;
203
+ hostingMode: 'managed' | 'hybrid' | 'self_hosted';
204
+ publicSite?: boolean;
205
+ repoProvider?: 'github';
206
+ repoVisibility?: 'private' | 'public';
207
+ enableDefaultAgents?: boolean;
208
+ initialObjectives?: string[];
209
+ }
210
+ export interface LaunchProjectResult {
211
+ project: {
212
+ id: string;
213
+ teamId: string;
214
+ slug: string;
215
+ name: string;
216
+ description: string | null;
217
+ };
218
+ connection: ProjectConnection | null;
219
+ launchJobId: string | null;
220
+ overview: ProjectOverviewSummary | null;
221
+ }
222
+ export declare function normalizeKnowledgeCoopJobStatus(status: string | null | undefined): KnowledgeCoopJobStatus;
223
+ export declare function normalizeRemoteJobStatus(status: RemoteJobStatus): KnowledgeCoopJobStatus;
@@ -0,0 +1,82 @@
1
+ const KNOWLEDGE_COOP_TEAM_CAPABILITIES = [
2
+ "launch_projects",
3
+ "edit_direct",
4
+ "manage_workstreams",
5
+ "stage_releases",
6
+ "publish_releases",
7
+ "publish_market_listings",
8
+ "manage_products",
9
+ "manage_billing",
10
+ "approve_remote_execution"
11
+ ];
12
+ const KNOWLEDGE_COOP_JOB_STATUSES = [
13
+ "queued",
14
+ "running",
15
+ "waiting_for_approval",
16
+ "failed",
17
+ "completed",
18
+ "rolled_back",
19
+ "cancelled"
20
+ ];
21
+ const KNOWLEDGE_COOP_WORKSTREAM_STATES = [
22
+ "drafting",
23
+ "active_local",
24
+ "verifying",
25
+ "saved_remote",
26
+ "in_staging",
27
+ "archived"
28
+ ];
29
+ const KNOWLEDGE_COOP_RELEASE_STATES = [
30
+ "drafting",
31
+ "waiting_on_verification",
32
+ "ready_to_publish",
33
+ "published",
34
+ "rolled_back"
35
+ ];
36
+ const KNOWLEDGE_COOP_SHARE_PACKAGE_STATES = [
37
+ "draft",
38
+ "packaged",
39
+ "ready_to_publish",
40
+ "published",
41
+ "archived",
42
+ "failed"
43
+ ];
44
+ const KNOWLEDGE_COOP_AGENT_MESSAGE_KINDS = [
45
+ "informational",
46
+ "warning",
47
+ "action_requested",
48
+ "release_readiness"
49
+ ];
50
+ function normalizeKnowledgeCoopJobStatus(status) {
51
+ switch (String(status ?? "").trim()) {
52
+ case "running":
53
+ return "running";
54
+ case "waiting_for_approval":
55
+ return "waiting_for_approval";
56
+ case "failed":
57
+ return "failed";
58
+ case "completed":
59
+ return "completed";
60
+ case "rolled_back":
61
+ return "rolled_back";
62
+ case "cancelled":
63
+ return "cancelled";
64
+ case "claimed":
65
+ case "pending":
66
+ default:
67
+ return "queued";
68
+ }
69
+ }
70
+ function normalizeRemoteJobStatus(status) {
71
+ return normalizeKnowledgeCoopJobStatus(status);
72
+ }
73
+ export {
74
+ KNOWLEDGE_COOP_AGENT_MESSAGE_KINDS,
75
+ KNOWLEDGE_COOP_JOB_STATUSES,
76
+ KNOWLEDGE_COOP_RELEASE_STATES,
77
+ KNOWLEDGE_COOP_SHARE_PACKAGE_STATES,
78
+ KNOWLEDGE_COOP_TEAM_CAPABILITIES,
79
+ KNOWLEDGE_COOP_WORKSTREAM_STATES,
80
+ normalizeKnowledgeCoopJobStatus,
81
+ normalizeRemoteJobStatus
82
+ };
@@ -107,6 +107,85 @@ function buildBuiltinModelRegistry(repoRoot) {
107
107
  contentCollection: "questions",
108
108
  contentDir: path.join(root, "questions")
109
109
  },
110
+ proposal: {
111
+ name: "proposal",
112
+ aliases: ["proposals"],
113
+ storage: "content",
114
+ operations: ["get", "read", "search", "follow", "pick", "create", "update"],
115
+ graph: graph({
116
+ entityType: "Proposal",
117
+ titleField: "title",
118
+ tagField: "tags",
119
+ enableSections: true,
120
+ referenceFields: [
121
+ { field: "related_objectives", edgeType: "REFERENCES", targetModels: ["objective"], multiple: true },
122
+ { field: "related_questions", edgeType: "REFERENCES", targetModels: ["question"], multiple: true },
123
+ { field: "related_notes", edgeType: "REFERENCES", targetModels: ["note"], multiple: true },
124
+ { field: "related_books", edgeType: "REFERENCES", targetModels: ["book"], multiple: true },
125
+ { field: "decision", edgeType: "REFERENCES", targetModels: ["decision"] },
126
+ { field: "supersedes", edgeType: "SUPERSEDES", targetModels: ["proposal"], multiple: true },
127
+ { field: "primary_contributor", edgeType: "REFERENCES", targetModels: ["person", "agent"] }
128
+ ]
129
+ }),
130
+ fields: {
131
+ title: field("title", { filterable: true, sortable: true, contentKeys: ["title"], writeContentKey: "title" }),
132
+ status: field("status", { filterable: true, contentKeys: ["status"], writeContentKey: "status" }),
133
+ tags: field("tags", { filterable: true, comparableAs: "string_array", contentKeys: ["tags"], writeContentKey: "tags" }),
134
+ date: field("date", { filterable: true, sortable: true, comparableAs: "date", contentKeys: ["date"], writeContentKey: "date" }),
135
+ proposal_type: field("proposal_type", { aliases: ["proposalType"], filterable: true, contentKeys: ["proposal_type", "proposalType"], writeContentKey: "proposal_type" }),
136
+ related_objectives: field("related_objectives", { aliases: ["relatedObjectives"], filterable: true, comparableAs: "string_array", contentKeys: ["related_objectives", "relatedObjectives"], writeContentKey: "related_objectives" }),
137
+ related_questions: field("related_questions", { aliases: ["relatedQuestions"], filterable: true, comparableAs: "string_array", contentKeys: ["related_questions", "relatedQuestions"], writeContentKey: "related_questions" }),
138
+ related_notes: field("related_notes", { aliases: ["relatedNotes"], filterable: true, comparableAs: "string_array", contentKeys: ["related_notes", "relatedNotes"], writeContentKey: "related_notes" }),
139
+ related_books: field("related_books", { aliases: ["relatedBooks"], filterable: true, comparableAs: "string_array", contentKeys: ["related_books", "relatedBooks"], writeContentKey: "related_books" }),
140
+ decision: field("decision", { filterable: true, contentKeys: ["decision"], writeContentKey: "decision" }),
141
+ updated_at: field("updated_at", { aliases: ["updated", "updatedAt"], sortable: true, comparableAs: "date", contentKeys: ["updated_at", "updated", "updatedAt"], writeContentKey: "updated_at" })
142
+ },
143
+ filterableFields: ["title", "status", "tags", "date", "proposal_type", "related_objectives", "related_questions", "related_notes", "related_books", "decision"],
144
+ sortableFields: ["title", "date", "updated_at"],
145
+ pickField: "date",
146
+ contentCollection: "proposals",
147
+ contentDir: path.join(root, "proposals")
148
+ },
149
+ decision: {
150
+ name: "decision",
151
+ aliases: ["decisions"],
152
+ storage: "content",
153
+ operations: ["get", "read", "search", "follow", "pick", "create", "update"],
154
+ graph: graph({
155
+ entityType: "Decision",
156
+ titleField: "title",
157
+ tagField: "tags",
158
+ enableSections: true,
159
+ referenceFields: [
160
+ { field: "related_objectives", edgeType: "REFERENCES", targetModels: ["objective"], multiple: true },
161
+ { field: "related_questions", edgeType: "REFERENCES", targetModels: ["question"], multiple: true },
162
+ { field: "related_notes", edgeType: "REFERENCES", targetModels: ["note"], multiple: true },
163
+ { field: "related_proposals", edgeType: "REFERENCES", targetModels: ["proposal"], multiple: true },
164
+ { field: "related_books", edgeType: "REFERENCES", targetModels: ["book"], multiple: true },
165
+ { field: "supersedes", edgeType: "SUPERSEDES", targetModels: ["decision"], multiple: true },
166
+ { field: "primary_contributor", edgeType: "REFERENCES", targetModels: ["person", "agent"] }
167
+ ]
168
+ }),
169
+ fields: {
170
+ title: field("title", { filterable: true, sortable: true, contentKeys: ["title"], writeContentKey: "title" }),
171
+ status: field("status", { filterable: true, contentKeys: ["status"], writeContentKey: "status" }),
172
+ tags: field("tags", { filterable: true, comparableAs: "string_array", contentKeys: ["tags"], writeContentKey: "tags" }),
173
+ date: field("date", { filterable: true, sortable: true, comparableAs: "date", contentKeys: ["date"], writeContentKey: "date" }),
174
+ decision_type: field("decision_type", { aliases: ["decisionType"], filterable: true, contentKeys: ["decision_type", "decisionType"], writeContentKey: "decision_type" }),
175
+ authority: field("authority", { filterable: true, contentKeys: ["authority"], writeContentKey: "authority" }),
176
+ related_objectives: field("related_objectives", { aliases: ["relatedObjectives"], filterable: true, comparableAs: "string_array", contentKeys: ["related_objectives", "relatedObjectives"], writeContentKey: "related_objectives" }),
177
+ related_questions: field("related_questions", { aliases: ["relatedQuestions"], filterable: true, comparableAs: "string_array", contentKeys: ["related_questions", "relatedQuestions"], writeContentKey: "related_questions" }),
178
+ related_notes: field("related_notes", { aliases: ["relatedNotes"], filterable: true, comparableAs: "string_array", contentKeys: ["related_notes", "relatedNotes"], writeContentKey: "related_notes" }),
179
+ related_proposals: field("related_proposals", { aliases: ["relatedProposals"], filterable: true, comparableAs: "string_array", contentKeys: ["related_proposals", "relatedProposals"], writeContentKey: "related_proposals" }),
180
+ related_books: field("related_books", { aliases: ["relatedBooks"], filterable: true, comparableAs: "string_array", contentKeys: ["related_books", "relatedBooks"], writeContentKey: "related_books" }),
181
+ updated_at: field("updated_at", { aliases: ["updated", "updatedAt"], sortable: true, comparableAs: "date", contentKeys: ["updated_at", "updated", "updatedAt"], writeContentKey: "updated_at" })
182
+ },
183
+ filterableFields: ["title", "status", "tags", "date", "decision_type", "authority", "related_objectives", "related_questions", "related_notes", "related_proposals", "related_books"],
184
+ sortableFields: ["title", "date", "updated_at"],
185
+ pickField: "date",
186
+ contentCollection: "decisions",
187
+ contentDir: path.join(root, "decisions")
188
+ },
110
189
  book: {
111
190
  name: "book",
112
191
  aliases: ["books"],
@@ -9,8 +9,17 @@ import {
9
9
  } from "../../operations-registry.js";
10
10
  import {
11
11
  clearTreeseedRemoteSession,
12
+ inspectTreeseedKeyAgentStatus,
13
+ lockTreeseedSecretSession,
14
+ migrateTreeseedMachineKeyToWrapped,
15
+ resolveTreeseedLaunchEnvironment,
12
16
  resolveTreeseedRemoteConfig,
13
- setTreeseedRemoteSession
17
+ rotateTreeseedMachineKey,
18
+ rotateTreeseedMachineKeyPassphrase,
19
+ setTreeseedRemoteSession,
20
+ TREESEED_MACHINE_KEY_PASSPHRASE_ENV,
21
+ TreeseedKeyAgentError,
22
+ unlockTreeseedSecretSessionFromEnv
14
23
  } from "../../operations/services/config-runtime.js";
15
24
  import {
16
25
  createPersistentDeployTarget,
@@ -37,6 +46,7 @@ import {
37
46
  syncTemplateProject,
38
47
  validateTemplateProduct
39
48
  } from "../../operations/services/template-registry.js";
49
+ import { validateKnowledgeCoopManagedLaunchPrerequisites } from "../../operations/services/knowledge-coop-launch.js";
40
50
  import {
41
51
  collectCliPreflight,
42
52
  formatCliPreflightReport
@@ -68,11 +78,15 @@ function failureResult(metadata, message, options = {}) {
68
78
  function contextEnv(context) {
69
79
  return { ...process.env, ...context.env ?? {} };
70
80
  }
81
+ function operationEnv(context) {
82
+ const tenantConfigPath = resolve(context.cwd, "treeseed.site.yaml");
83
+ return existsSync(tenantConfigPath) ? resolveTreeseedLaunchEnvironment({ tenantRoot: context.cwd, scope: "local", baseEnv: contextEnv(context) }) : contextEnv(context);
84
+ }
71
85
  function runNodeScript(metadata, scriptName, args, context) {
72
86
  if (context.spawn) {
73
87
  const result2 = context.spawn(process.execPath, [packageScriptPath(scriptName), ...args], {
74
88
  cwd: context.cwd,
75
- env: contextEnv(context),
89
+ env: operationEnv(context),
76
90
  stdio: "inherit"
77
91
  });
78
92
  return operationResult(metadata, {
@@ -85,7 +99,7 @@ function runNodeScript(metadata, scriptName, args, context) {
85
99
  }
86
100
  const result = spawnSync(process.execPath, [packageScriptPath(scriptName), ...args], {
87
101
  cwd: context.cwd,
88
- env: contextEnv(context),
102
+ env: operationEnv(context),
89
103
  encoding: "utf8",
90
104
  stdio: "pipe"
91
105
  });
@@ -198,11 +212,30 @@ class PreflightOperation extends BaseOperation {
198
212
  cwd: context.cwd,
199
213
  requireAuth: input.requireAuth ?? this.requireAuth
200
214
  });
215
+ const launch = input.launch === true || input.managedLaunch === true ? validateKnowledgeCoopManagedLaunchPrerequisites(context.cwd) : null;
201
216
  const stdout = [formatCliPreflightReport(report)];
217
+ if (launch) {
218
+ stdout.push(
219
+ "",
220
+ "Knowledge Coop managed launch preflight",
221
+ `- ok: ${launch.ok ? "yes" : "no"}`,
222
+ `- commands: git=${launch.commands.git ? "ok" : "missing"}, gh=${launch.commands.gh ? "ok" : "missing"}, wrangler=${launch.commands.wrangler ? "ok" : "missing"}, railway=${launch.commands.railway ? "ok" : "missing"}`
223
+ );
224
+ if (launch.missingConfig.length > 0) {
225
+ stdout.push(...launch.missingConfig.map((item) => `- missing config: ${item}`));
226
+ }
227
+ if (launch.providerChecks.issues.length > 0) {
228
+ stdout.push(...launch.providerChecks.issues.map((item) => `- provider issue: ${item}`));
229
+ }
230
+ }
202
231
  for (const line of stdout) context.write?.(line, "stdout");
203
- return operationResult(this.metadata, report, {
204
- ok: report.ok,
205
- exitCode: report.ok ? 0 : 1,
232
+ const ok = report.ok && (!launch || launch.ok);
233
+ return operationResult(this.metadata, {
234
+ ...report,
235
+ launch
236
+ }, {
237
+ ok,
238
+ exitCode: ok ? 0 : 1,
206
239
  stdout,
207
240
  stderr: []
208
241
  });
@@ -350,6 +383,87 @@ class AuthWhoAmIOperation extends BaseOperation {
350
383
  });
351
384
  }
352
385
  }
386
+ class SecretsStatusOperation extends BaseOperation {
387
+ async execute(_input, context) {
388
+ return operationResult(this.metadata, {
389
+ status: inspectTreeseedKeyAgentStatus(context.cwd)
390
+ });
391
+ }
392
+ }
393
+ class SecretsUnlockOperation extends BaseOperation {
394
+ async execute(input, context) {
395
+ try {
396
+ const status = unlockTreeseedSecretSessionFromEnv(context.cwd, {
397
+ allowMigration: input.allowMigration !== false,
398
+ createIfMissing: input.createIfMissing !== false
399
+ });
400
+ return operationResult(this.metadata, { status });
401
+ } catch (error) {
402
+ if (error instanceof TreeseedKeyAgentError) {
403
+ return failureResult(this.metadata, error.message, { meta: { code: error.code, details: error.details ?? null } });
404
+ }
405
+ throw error;
406
+ }
407
+ }
408
+ }
409
+ class SecretsLockOperation extends BaseOperation {
410
+ async execute(_input, context) {
411
+ try {
412
+ return operationResult(this.metadata, {
413
+ status: lockTreeseedSecretSession(context.cwd)
414
+ });
415
+ } catch (error) {
416
+ if (error instanceof TreeseedKeyAgentError) {
417
+ return failureResult(this.metadata, error.message, { meta: { code: error.code, details: error.details ?? null } });
418
+ }
419
+ throw error;
420
+ }
421
+ }
422
+ }
423
+ class SecretsMigrateKeyOperation extends BaseOperation {
424
+ async execute(input, context) {
425
+ const passphrase = String(input.passphrase ?? context.env?.[TREESEED_MACHINE_KEY_PASSPHRASE_ENV] ?? "").trim();
426
+ if (!passphrase) {
427
+ return failureResult(this.metadata, `Set ${TREESEED_MACHINE_KEY_PASSPHRASE_ENV} or pass { passphrase } when migrating the machine key.`);
428
+ }
429
+ try {
430
+ return operationResult(this.metadata, migrateTreeseedMachineKeyToWrapped(context.cwd, passphrase));
431
+ } catch (error) {
432
+ if (error instanceof TreeseedKeyAgentError) {
433
+ return failureResult(this.metadata, error.message, { meta: { code: error.code, details: error.details ?? null } });
434
+ }
435
+ throw error;
436
+ }
437
+ }
438
+ }
439
+ class SecretsRotatePassphraseOperation extends BaseOperation {
440
+ async execute(input, context) {
441
+ const passphrase = String(input.passphrase ?? context.env?.[TREESEED_MACHINE_KEY_PASSPHRASE_ENV] ?? "").trim();
442
+ if (!passphrase) {
443
+ return failureResult(this.metadata, `Set ${TREESEED_MACHINE_KEY_PASSPHRASE_ENV} or pass { passphrase } when rotating the wrapped-key passphrase.`);
444
+ }
445
+ try {
446
+ return operationResult(this.metadata, rotateTreeseedMachineKeyPassphrase(context.cwd, passphrase));
447
+ } catch (error) {
448
+ if (error instanceof TreeseedKeyAgentError) {
449
+ return failureResult(this.metadata, error.message, { meta: { code: error.code, details: error.details ?? null } });
450
+ }
451
+ throw error;
452
+ }
453
+ }
454
+ }
455
+ class SecretsRotateMachineKeyOperation extends BaseOperation {
456
+ async execute(_input, context) {
457
+ try {
458
+ return operationResult(this.metadata, rotateTreeseedMachineKey(context.cwd));
459
+ } catch (error) {
460
+ if (error instanceof TreeseedKeyAgentError) {
461
+ return failureResult(this.metadata, error.message, { meta: { code: error.code, details: error.details ?? null } });
462
+ }
463
+ throw error;
464
+ }
465
+ }
466
+ }
353
467
  class RollbackOperation extends BaseOperation {
354
468
  async execute(input, context) {
355
469
  const scope = typeof input.environment === "string" ? input.environment : null;
@@ -454,6 +568,8 @@ class DefaultTreeseedOperationsProvider {
454
568
  new WorkflowOperation("save"),
455
569
  new WorkflowOperation("close"),
456
570
  new WorkflowOperation("stage"),
571
+ new WorkflowOperation("resume"),
572
+ new WorkflowOperation("recover"),
457
573
  new WorkflowOperation("config"),
458
574
  new WorkflowOperation("export"),
459
575
  new WorkflowOperation("release"),
@@ -467,6 +583,12 @@ class DefaultTreeseedOperationsProvider {
467
583
  new AuthLoginOperation("auth:login"),
468
584
  new AuthLogoutOperation("auth:logout"),
469
585
  new AuthWhoAmIOperation("auth:whoami"),
586
+ new SecretsStatusOperation("secrets:status"),
587
+ new SecretsUnlockOperation("secrets:unlock"),
588
+ new SecretsLockOperation("secrets:lock"),
589
+ new SecretsMigrateKeyOperation("secrets:migrate-key"),
590
+ new SecretsRotatePassphraseOperation("secrets:rotate-passphrase"),
591
+ new SecretsRotateMachineKeyOperation("secrets:rotate-machine-key"),
470
592
  new RollbackOperation("rollback"),
471
593
  new ScriptOperation("build", "tenant-build"),
472
594
  new ScriptOperation("check", "tenant-check"),
@@ -484,7 +606,6 @@ class DefaultTreeseedOperationsProvider {
484
606
  new ScriptOperation("test:release:full", "workspace-release-verify", ["--full-smoke"]),
485
607
  new ScriptOperation("release:publish:changed", "workspace-publish-changed-packages"),
486
608
  new ScriptOperation("astro", "tenant-astro-command"),
487
- new ScriptOperation("sync:devvars", "sync-dev-vars"),
488
609
  new MailpitUpOperation("mailpit:up"),
489
610
  new MailpitDownOperation("mailpit:down"),
490
611
  new MailpitLogsOperation("mailpit:logs"),