@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,90 @@
1
+ import type { TreeseedWorkflowMode } from './session.ts';
2
+ export type TreeseedWorkflowRunCommand = 'switch' | 'save' | 'close' | 'stage' | 'release' | 'destroy';
3
+ export type TreeseedWorkflowExecutionMode = 'execute' | 'plan';
4
+ export type TreeseedWorkflowRunStatus = 'running' | 'failed' | 'completed';
5
+ export type TreeseedWorkflowRunStep = {
6
+ id: string;
7
+ description: string;
8
+ repoName: string | null;
9
+ repoPath: string | null;
10
+ branch: string | null;
11
+ resumable: boolean;
12
+ status: 'pending' | 'completed' | 'skipped';
13
+ completedAt: string | null;
14
+ data: Record<string, unknown> | null;
15
+ };
16
+ export type TreeseedWorkflowRunJournal = {
17
+ schemaVersion: 1;
18
+ kind: 'treeseed.workflow.run';
19
+ runId: string;
20
+ command: TreeseedWorkflowRunCommand;
21
+ executionMode: TreeseedWorkflowExecutionMode;
22
+ status: TreeseedWorkflowRunStatus;
23
+ createdAt: string;
24
+ updatedAt: string;
25
+ resumable: boolean;
26
+ input: Record<string, unknown>;
27
+ session: {
28
+ root: string;
29
+ mode: TreeseedWorkflowMode;
30
+ branchName: string | null;
31
+ repos: Array<{
32
+ name: string;
33
+ path: string;
34
+ branchName: string | null;
35
+ }>;
36
+ };
37
+ steps: TreeseedWorkflowRunStep[];
38
+ failure: null | {
39
+ code: string;
40
+ message: string;
41
+ details: Record<string, unknown> | null;
42
+ at: string;
43
+ };
44
+ result: Record<string, unknown> | null;
45
+ };
46
+ export type TreeseedWorkflowLockRecord = {
47
+ schemaVersion: 1;
48
+ kind: 'treeseed.workflow.lock';
49
+ runId: string;
50
+ command: TreeseedWorkflowRunCommand;
51
+ root: string;
52
+ host: string;
53
+ pid: number | null;
54
+ createdAt: string;
55
+ updatedAt: string;
56
+ stale: boolean;
57
+ staleReason: string | null;
58
+ };
59
+ export type TreeseedWorkflowLockInspection = {
60
+ lock: TreeseedWorkflowLockRecord | null;
61
+ active: boolean;
62
+ stale: boolean;
63
+ staleReason: string | null;
64
+ };
65
+ export declare function generateWorkflowRunId(command: TreeseedWorkflowRunCommand): string;
66
+ export declare function inspectWorkflowLock(root: string): TreeseedWorkflowLockInspection;
67
+ export declare function acquireWorkflowLock(root: string, command: TreeseedWorkflowRunCommand, runId: string): {
68
+ readonly acquired: false;
69
+ readonly lock: TreeseedWorkflowLockRecord;
70
+ readonly replacedStale?: undefined;
71
+ } | {
72
+ readonly acquired: true;
73
+ readonly lock: TreeseedWorkflowLockRecord;
74
+ readonly replacedStale: boolean;
75
+ };
76
+ export declare function refreshWorkflowLock(root: string, runId: string): TreeseedWorkflowLockRecord | null;
77
+ export declare function releaseWorkflowLock(root: string, runId: string): boolean;
78
+ export declare function writeWorkflowRunJournal(root: string, journal: TreeseedWorkflowRunJournal): TreeseedWorkflowRunJournal;
79
+ export declare function readWorkflowRunJournal(root: string, runId: string): TreeseedWorkflowRunJournal | null;
80
+ export declare function updateWorkflowRunJournal(root: string, runId: string, updater: (journal: TreeseedWorkflowRunJournal) => TreeseedWorkflowRunJournal): TreeseedWorkflowRunJournal | null;
81
+ export declare function createWorkflowRunJournal(root: string, options: {
82
+ runId: string;
83
+ command: TreeseedWorkflowRunCommand;
84
+ executionMode?: TreeseedWorkflowExecutionMode;
85
+ input: Record<string, unknown>;
86
+ session: TreeseedWorkflowRunJournal['session'];
87
+ steps: Omit<TreeseedWorkflowRunStep, 'status' | 'completedAt' | 'data'>[];
88
+ }): TreeseedWorkflowRunJournal;
89
+ export declare function listWorkflowRunJournals(root: string): TreeseedWorkflowRunJournal[];
90
+ export declare function listInterruptedWorkflowRuns(root: string): TreeseedWorkflowRunJournal[];
@@ -0,0 +1,242 @@
1
+ import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs";
2
+ import { hostname } from "node:os";
3
+ import { resolve } from "node:path";
4
+ const WORKFLOW_CONTROL_DIR = ".treeseed/workflow";
5
+ const WORKFLOW_RUNS_DIR = `${WORKFLOW_CONTROL_DIR}/runs`;
6
+ const LOCK_STALE_AFTER_MS = 4 * 60 * 60 * 1e3;
7
+ function nowIso() {
8
+ return (/* @__PURE__ */ new Date()).toISOString();
9
+ }
10
+ function workflowControlRoot(root) {
11
+ return resolve(root, WORKFLOW_CONTROL_DIR);
12
+ }
13
+ function workflowRunsRoot(root) {
14
+ return resolve(root, WORKFLOW_RUNS_DIR);
15
+ }
16
+ function workflowLockPath(root) {
17
+ return resolve(root, WORKFLOW_CONTROL_DIR, "lock.json");
18
+ }
19
+ function workflowRunPath(root, runId) {
20
+ return resolve(root, WORKFLOW_RUNS_DIR, `${runId}.json`);
21
+ }
22
+ function resolveGitDir(root) {
23
+ const gitPath = resolve(root, ".git");
24
+ if (existsSync(resolve(gitPath, "info"))) {
25
+ return gitPath;
26
+ }
27
+ if (!existsSync(gitPath)) {
28
+ return null;
29
+ }
30
+ try {
31
+ const gitFile = readFileSync(gitPath, "utf8").trim();
32
+ const match = gitFile.match(/^gitdir:\s*(.+)$/u);
33
+ return match ? resolve(root, match[1]) : null;
34
+ } catch {
35
+ return null;
36
+ }
37
+ }
38
+ function ensureWorkflowExcludeRule(root) {
39
+ const gitDir = resolveGitDir(root);
40
+ if (!gitDir) {
41
+ return;
42
+ }
43
+ const excludePath = resolve(gitDir, "info", "exclude");
44
+ const pattern = "/.treeseed/workflow/";
45
+ const current = existsSync(excludePath) ? readFileSync(excludePath, "utf8") : "";
46
+ if (current.includes(pattern)) {
47
+ return;
48
+ }
49
+ writeFileSync(excludePath, `${current}${current.endsWith("\n") || current.length === 0 ? "" : "\n"}${pattern}
50
+ `, "utf8");
51
+ }
52
+ function ensureWorkflowControlDirs(root) {
53
+ const controlDir = workflowControlRoot(root);
54
+ const runsDir = workflowRunsRoot(root);
55
+ mkdirSync(runsDir, { recursive: true });
56
+ ensureWorkflowExcludeRule(root);
57
+ writeFileSync(resolve(controlDir, ".gitignore"), "*\n!.gitignore\n!runs/\nruns/*\n!runs/.gitignore\n", "utf8");
58
+ writeFileSync(resolve(runsDir, ".gitignore"), "*\n!.gitignore\n", "utf8");
59
+ return {
60
+ controlDir,
61
+ runsDir,
62
+ lockPath: workflowLockPath(root)
63
+ };
64
+ }
65
+ function safeJsonParse(filePath) {
66
+ if (!existsSync(filePath)) {
67
+ return null;
68
+ }
69
+ try {
70
+ return JSON.parse(readFileSync(filePath, "utf8"));
71
+ } catch {
72
+ return null;
73
+ }
74
+ }
75
+ function pidIsAlive(pid) {
76
+ if (!Number.isInteger(pid) || (pid ?? 0) <= 0) {
77
+ return false;
78
+ }
79
+ try {
80
+ process.kill(pid, 0);
81
+ return true;
82
+ } catch {
83
+ return false;
84
+ }
85
+ }
86
+ function generateWorkflowRunId(command) {
87
+ return `${command}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
88
+ }
89
+ function inspectWorkflowLock(root) {
90
+ const lock = safeJsonParse(workflowLockPath(root));
91
+ if (!lock) {
92
+ return {
93
+ lock: null,
94
+ active: false,
95
+ stale: false,
96
+ staleReason: null
97
+ };
98
+ }
99
+ let staleReason = null;
100
+ if (lock.host === hostname() && lock.pid != null && !pidIsAlive(lock.pid)) {
101
+ staleReason = `process ${lock.pid} is no longer running`;
102
+ } else if (Date.now() - Date.parse(lock.updatedAt) > LOCK_STALE_AFTER_MS) {
103
+ staleReason = "lock heartbeat expired";
104
+ }
105
+ return {
106
+ lock: {
107
+ ...lock,
108
+ stale: staleReason != null,
109
+ staleReason
110
+ },
111
+ active: staleReason == null,
112
+ stale: staleReason != null,
113
+ staleReason
114
+ };
115
+ }
116
+ function acquireWorkflowLock(root, command, runId) {
117
+ const dirs = ensureWorkflowControlDirs(root);
118
+ const inspection = inspectWorkflowLock(root);
119
+ if (inspection.active && inspection.lock && inspection.lock.runId !== runId) {
120
+ return {
121
+ acquired: false,
122
+ lock: inspection.lock
123
+ };
124
+ }
125
+ if (inspection.stale) {
126
+ rmSync(dirs.lockPath, { force: true });
127
+ }
128
+ const timestamp = nowIso();
129
+ const lock = {
130
+ schemaVersion: 1,
131
+ kind: "treeseed.workflow.lock",
132
+ runId,
133
+ command,
134
+ root,
135
+ host: hostname(),
136
+ pid: process.pid,
137
+ createdAt: inspection.lock?.runId === runId ? inspection.lock.createdAt : timestamp,
138
+ updatedAt: timestamp,
139
+ stale: false,
140
+ staleReason: null
141
+ };
142
+ writeFileSync(dirs.lockPath, `${JSON.stringify(lock, null, 2)}
143
+ `, "utf8");
144
+ return {
145
+ acquired: true,
146
+ lock,
147
+ replacedStale: inspection.stale
148
+ };
149
+ }
150
+ function refreshWorkflowLock(root, runId) {
151
+ const path = workflowLockPath(root);
152
+ const lock = safeJsonParse(path);
153
+ if (!lock || lock.runId !== runId) {
154
+ return null;
155
+ }
156
+ const updated = {
157
+ ...lock,
158
+ updatedAt: nowIso(),
159
+ stale: false,
160
+ staleReason: null
161
+ };
162
+ writeFileSync(path, `${JSON.stringify(updated, null, 2)}
163
+ `, "utf8");
164
+ return updated;
165
+ }
166
+ function releaseWorkflowLock(root, runId) {
167
+ const path = workflowLockPath(root);
168
+ const lock = safeJsonParse(path);
169
+ if (!lock || lock.runId !== runId) {
170
+ return false;
171
+ }
172
+ rmSync(path, { force: true });
173
+ return true;
174
+ }
175
+ function writeWorkflowRunJournal(root, journal) {
176
+ ensureWorkflowControlDirs(root);
177
+ writeFileSync(workflowRunPath(root, journal.runId), `${JSON.stringify(journal, null, 2)}
178
+ `, "utf8");
179
+ return journal;
180
+ }
181
+ function readWorkflowRunJournal(root, runId) {
182
+ return safeJsonParse(workflowRunPath(root, runId));
183
+ }
184
+ function updateWorkflowRunJournal(root, runId, updater) {
185
+ const current = readWorkflowRunJournal(root, runId);
186
+ if (!current) {
187
+ return null;
188
+ }
189
+ const updated = updater(current);
190
+ writeWorkflowRunJournal(root, {
191
+ ...updated,
192
+ updatedAt: nowIso()
193
+ });
194
+ return readWorkflowRunJournal(root, runId);
195
+ }
196
+ function createWorkflowRunJournal(root, options) {
197
+ const timestamp = nowIso();
198
+ return writeWorkflowRunJournal(root, {
199
+ schemaVersion: 1,
200
+ kind: "treeseed.workflow.run",
201
+ runId: options.runId,
202
+ command: options.command,
203
+ executionMode: options.executionMode ?? "execute",
204
+ status: "running",
205
+ createdAt: timestamp,
206
+ updatedAt: timestamp,
207
+ resumable: options.steps.every((step) => step.resumable),
208
+ input: options.input,
209
+ session: options.session,
210
+ steps: options.steps.map((step) => ({
211
+ ...step,
212
+ status: "pending",
213
+ completedAt: null,
214
+ data: null
215
+ })),
216
+ failure: null,
217
+ result: null
218
+ });
219
+ }
220
+ function listWorkflowRunJournals(root) {
221
+ const runsDir = workflowRunsRoot(root);
222
+ if (!existsSync(runsDir)) {
223
+ return [];
224
+ }
225
+ return readdirSync(runsDir).filter((entry) => entry.endsWith(".json")).map((entry) => safeJsonParse(resolve(runsDir, entry))).filter((entry) => entry != null).sort((left, right) => right.createdAt.localeCompare(left.createdAt));
226
+ }
227
+ function listInterruptedWorkflowRuns(root) {
228
+ return listWorkflowRunJournals(root).filter((journal) => journal.status === "failed" && journal.resumable);
229
+ }
230
+ export {
231
+ acquireWorkflowLock,
232
+ createWorkflowRunJournal,
233
+ generateWorkflowRunId,
234
+ inspectWorkflowLock,
235
+ listInterruptedWorkflowRuns,
236
+ listWorkflowRunJournals,
237
+ readWorkflowRunJournal,
238
+ refreshWorkflowLock,
239
+ releaseWorkflowLock,
240
+ updateWorkflowRunJournal,
241
+ writeWorkflowRunJournal
242
+ };
@@ -0,0 +1,31 @@
1
+ import { type TreeseedWorkflowBranchRole } from './policy.ts';
2
+ export type TreeseedWorkflowMode = 'root-only' | 'recursive-workspace';
3
+ export type TreeseedWorkflowSessionRepo = {
4
+ name: string;
5
+ path: string;
6
+ relativePath: string;
7
+ branchName: string | null;
8
+ branchRole: TreeseedWorkflowBranchRole;
9
+ dirty: boolean;
10
+ detached: boolean;
11
+ hasOriginRemote: boolean;
12
+ };
13
+ export type TreeseedWorkflowPackageSelection = {
14
+ changed: string[];
15
+ dependents: string[];
16
+ selected: string[];
17
+ };
18
+ export type TreeseedWorkflowSession = {
19
+ root: string;
20
+ gitRoot: string;
21
+ mode: TreeseedWorkflowMode;
22
+ branchName: string | null;
23
+ branchRole: TreeseedWorkflowBranchRole;
24
+ rootRepo: TreeseedWorkflowSessionRepo;
25
+ packageRepos: TreeseedWorkflowSessionRepo[];
26
+ packageSelection: TreeseedWorkflowPackageSelection;
27
+ };
28
+ export declare function checkedOutWorkspacePackageRepos(root: string): any[];
29
+ export declare function workflowModeForRoot(root: string): TreeseedWorkflowMode;
30
+ export declare function collectReleasePackageSelection(root: string): TreeseedWorkflowPackageSelection;
31
+ export declare function resolveTreeseedWorkflowSession(cwd: string): TreeseedWorkflowSession;
@@ -0,0 +1,97 @@
1
+ import { relative } from "node:path";
2
+ import {
3
+ currentBranch,
4
+ gitStatusPorcelain,
5
+ originRemoteUrl,
6
+ repoRoot
7
+ } from "../operations/services/workspace-save.js";
8
+ import {
9
+ changedWorkspacePackages,
10
+ hasCompleteTreeseedPackageCheckout,
11
+ publishableWorkspacePackages,
12
+ sortWorkspacePackages,
13
+ workspacePackages,
14
+ workspaceRoot
15
+ } from "../operations/services/workspace-tools.js";
16
+ import {
17
+ classifyTreeseedBranchRole,
18
+ resolveTreeseedWorkflowPaths
19
+ } from "./policy.js";
20
+ function hasOriginRemote(repoDir) {
21
+ try {
22
+ originRemoteUrl(repoDir);
23
+ return true;
24
+ } catch {
25
+ return false;
26
+ }
27
+ }
28
+ function repoState(root, name, repoDir) {
29
+ const branchName = currentBranch(repoDir) || null;
30
+ return {
31
+ name,
32
+ path: repoDir,
33
+ relativePath: relative(root, repoDir).replaceAll("\\", "/") || ".",
34
+ branchName,
35
+ branchRole: classifyTreeseedBranchRole(branchName, repoDir),
36
+ dirty: gitStatusPorcelain(repoDir).length > 0,
37
+ detached: branchName == null,
38
+ hasOriginRemote: hasOriginRemote(repoDir)
39
+ };
40
+ }
41
+ function checkedOutWorkspacePackageRepos(root) {
42
+ if (!hasCompleteTreeseedPackageCheckout(root)) {
43
+ return [];
44
+ }
45
+ return sortWorkspacePackages(
46
+ workspacePackages(root).filter((pkg) => pkg.name?.startsWith("@treeseed/"))
47
+ );
48
+ }
49
+ function workflowModeForRoot(root) {
50
+ return hasCompleteTreeseedPackageCheckout(root) ? "recursive-workspace" : "root-only";
51
+ }
52
+ function collectReleasePackageSelection(root) {
53
+ const publishable = sortWorkspacePackages(
54
+ publishableWorkspacePackages(root).filter((pkg) => pkg.name?.startsWith("@treeseed/"))
55
+ );
56
+ const changed = changedWorkspacePackages({
57
+ root,
58
+ baseRef: "main",
59
+ includeDependents: false,
60
+ packages: publishable
61
+ });
62
+ const selected = changedWorkspacePackages({
63
+ root,
64
+ baseRef: "main",
65
+ includeDependents: true,
66
+ packages: publishable
67
+ });
68
+ const changedNames = changed.map((pkg) => pkg.name);
69
+ return {
70
+ changed: changedNames,
71
+ dependents: selected.filter((pkg) => !changedNames.includes(pkg.name)).map((pkg) => pkg.name),
72
+ selected: selected.map((pkg) => pkg.name)
73
+ };
74
+ }
75
+ function resolveTreeseedWorkflowSession(cwd) {
76
+ const resolved = resolveTreeseedWorkflowPaths(cwd);
77
+ const root = workspaceRoot(resolved.cwd);
78
+ const gitRoot = repoRoot(root);
79
+ const mode = workflowModeForRoot(root);
80
+ const packageRepos = checkedOutWorkspacePackageRepos(root).map((pkg) => repoState(root, pkg.name, pkg.dir));
81
+ return {
82
+ root,
83
+ gitRoot,
84
+ mode,
85
+ branchName: currentBranch(gitRoot) || null,
86
+ branchRole: classifyTreeseedBranchRole(currentBranch(gitRoot) || null, gitRoot),
87
+ rootRepo: repoState(root, "@treeseed/market", gitRoot),
88
+ packageRepos,
89
+ packageSelection: collectReleasePackageSelection(root)
90
+ };
91
+ }
92
+ export {
93
+ checkedOutWorkspacePackageRepos,
94
+ collectReleasePackageSelection,
95
+ resolveTreeseedWorkflowSession,
96
+ workflowModeForRoot
97
+ };
@@ -12,13 +12,65 @@ export type TreeseedWorkflowState = {
12
12
  branchRole: TreeseedBranchRole;
13
13
  environment: 'local' | 'staging' | 'prod' | 'none';
14
14
  dirtyWorktree: boolean;
15
+ workflowControl: {
16
+ lock: {
17
+ active: boolean;
18
+ stale: boolean;
19
+ runId: string | null;
20
+ command: string | null;
21
+ updatedAt: string | null;
22
+ staleReason: string | null;
23
+ };
24
+ interruptedRuns: Array<{
25
+ runId: string;
26
+ command: string;
27
+ updatedAt: string;
28
+ nextStep: string | null;
29
+ }>;
30
+ blockers: string[];
31
+ };
32
+ packageSync: {
33
+ mode: 'root-only' | 'recursive-workspace';
34
+ completeCheckout: boolean;
35
+ expectedBranch: string | null;
36
+ aligned: boolean;
37
+ dirty: boolean;
38
+ repos: Array<{
39
+ name: string;
40
+ path: string;
41
+ branchName: string | null;
42
+ dirty: boolean;
43
+ aligned: boolean;
44
+ localBranch: boolean;
45
+ remoteBranch: boolean;
46
+ }>;
47
+ blockers: string[];
48
+ };
15
49
  preview: {
16
50
  enabled: boolean;
17
51
  url: string | null;
18
52
  lastDeploymentTimestamp: string | null;
19
53
  };
54
+ webCache: {
55
+ webHost: string | null;
56
+ contentHost: string | null;
57
+ sourcePagePolicy: string | null;
58
+ contentPagePolicy: string | null;
59
+ r2ObjectPolicy: string | null;
60
+ cloudflareRulesManaged: boolean;
61
+ lastDeployPurgeAt: string | null;
62
+ lastDeployPurgeCount: number | null;
63
+ lastContentPurgeAt: string | null;
64
+ lastContentPurgeCount: number | null;
65
+ };
20
66
  persistentEnvironments: Record<string, {
21
67
  initialized: boolean;
68
+ phase: string;
69
+ configured: boolean;
70
+ provisioned: boolean;
71
+ deployable: boolean;
72
+ blockers: string[];
73
+ warnings: string[];
22
74
  lastValidatedAt: string | null;
23
75
  lastDeploymentTimestamp: string | null;
24
76
  lastDeployedUrl: string | null;
@@ -30,6 +82,33 @@ export type TreeseedWorkflowState = {
30
82
  copilot: boolean;
31
83
  remoteApi: boolean;
32
84
  };
85
+ marketConnection: {
86
+ configured: boolean;
87
+ baseUrl: string | null;
88
+ hostId: string | null;
89
+ teamId: string | null;
90
+ teamSlug: string | null;
91
+ projectId: string | null;
92
+ projectSlug: string | null;
93
+ connectionMode: string | null;
94
+ projectApiBaseUrl: string | null;
95
+ hubMode: string | null;
96
+ runtimeMode: string | null;
97
+ runtimeRegistration: string | null;
98
+ runtimeAttached: boolean;
99
+ runtimeReady: boolean;
100
+ runnerHostId: string | null;
101
+ runnerReady: boolean;
102
+ runnerRegisteredAt: string | null;
103
+ runnerLastSeenAt: string | null;
104
+ launchPhase: string | null;
105
+ lastSuccessfulPhase: string | null;
106
+ githubRepository: string | null;
107
+ workflowBootstrapReady: boolean;
108
+ currentWorkstreamId: string | null;
109
+ verificationPosture: 'ready' | 'blocked' | 'pending';
110
+ approvalBlockers: string[];
111
+ };
33
112
  managedServices: Record<string, {
34
113
  enabled: boolean;
35
114
  initialized: boolean;
@@ -41,8 +120,15 @@ export type TreeseedWorkflowState = {
41
120
  treeseedConfig: boolean;
42
121
  machineConfig: boolean;
43
122
  machineKey: boolean;
44
- envLocal: boolean;
45
- devVars: boolean;
123
+ };
124
+ secrets: {
125
+ keyAgentRunning: boolean;
126
+ keyAgentUnlocked: boolean;
127
+ wrappedKeyPresent: boolean;
128
+ migrationRequired: boolean;
129
+ idleTimeoutMs: number;
130
+ idleRemainingMs: number;
131
+ startupPassphraseConfigured: boolean;
46
132
  };
47
133
  releaseReady: boolean;
48
134
  readiness: {