@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.
- package/dist/control-plane-client.d.ts +60 -1
- package/dist/control-plane-client.js +59 -0
- package/dist/control-plane.d.ts +1 -1
- package/dist/control-plane.js +11 -4
- package/dist/d1-store.d.ts +58 -0
- package/dist/d1-store.js +64 -0
- package/dist/dispatch.js +6 -0
- package/dist/graph/schema.js +4 -0
- package/dist/index.d.ts +5 -1
- package/dist/index.js +32 -0
- package/dist/knowledge-coop.d.ts +223 -0
- package/dist/knowledge-coop.js +82 -0
- package/dist/model-registry.js +79 -0
- package/dist/operations/providers/default.js +128 -7
- package/dist/operations/services/config-runtime.d.ts +102 -24
- package/dist/operations/services/config-runtime.js +896 -160
- package/dist/operations/services/deploy.d.ts +223 -15
- package/dist/operations/services/deploy.js +626 -55
- package/dist/operations/services/git-workflow.d.ts +47 -3
- package/dist/operations/services/git-workflow.js +125 -19
- package/dist/operations/services/github-automation.d.ts +85 -0
- package/dist/operations/services/github-automation.js +220 -1
- package/dist/operations/services/key-agent.d.ts +118 -0
- package/dist/operations/services/key-agent.js +476 -0
- package/dist/operations/services/knowledge-coop-launch.d.ts +90 -0
- package/dist/operations/services/knowledge-coop-launch.js +753 -0
- package/dist/operations/services/knowledge-coop-packaging.d.ts +59 -0
- package/dist/operations/services/knowledge-coop-packaging.js +234 -0
- package/dist/operations/services/local-dev.d.ts +0 -1
- package/dist/operations/services/local-dev.js +1 -14
- package/dist/operations/services/project-platform.d.ts +42 -182
- package/dist/operations/services/project-platform.js +162 -59
- package/dist/operations/services/railway-deploy.d.ts +1 -0
- package/dist/operations/services/railway-deploy.js +31 -13
- package/dist/operations/services/runtime-tools.d.ts +52 -5
- package/dist/operations/services/runtime-tools.js +186 -26
- package/dist/operations/services/watch-dev.js +2 -4
- package/dist/operations/services/workspace-preflight.d.ts +4 -4
- package/dist/operations/services/workspace-preflight.js +22 -20
- package/dist/operations/services/workspace-save.d.ts +10 -1
- package/dist/operations/services/workspace-save.js +54 -3
- package/dist/operations/services/workspace-tools.d.ts +1 -0
- package/dist/operations/services/workspace-tools.js +20 -5
- package/dist/operations-registry.js +15 -8
- package/dist/operations-types.d.ts +2 -2
- package/dist/platform/contracts.d.ts +39 -3
- package/dist/platform/deploy-config.d.ts +12 -1
- package/dist/platform/deploy-config.js +214 -15
- package/dist/platform/deploy-runtime.d.ts +1 -0
- package/dist/platform/deploy-runtime.js +10 -2
- package/dist/platform/env.yaml +93 -61
- package/dist/platform/environment.d.ts +13 -2
- package/dist/platform/environment.js +90 -20
- package/dist/platform/plugins/constants.d.ts +1 -0
- package/dist/platform/plugins/constants.js +7 -6
- package/dist/platform/tenant/runtime-config.js +8 -1
- package/dist/platform/tenant-config.js +4 -0
- package/dist/platform/utils/site-config-schema.js +18 -0
- package/dist/plugin-default.js +2 -2
- package/dist/scripts/key-agent.js +165 -0
- package/dist/scripts/tenant-build.js +4 -1
- package/dist/scripts/tenant-check.js +4 -1
- package/dist/scripts/tenant-deploy.js +43 -4
- package/dist/scripts/tenant-dev.js +0 -1
- package/dist/scripts/workspace-start-warning.js +2 -2
- package/dist/sdk-types.d.ts +2 -2
- package/dist/sdk-types.js +2 -0
- package/dist/sdk.d.ts +13 -0
- package/dist/sdk.js +40 -0
- package/dist/stores/knowledge-coop-store.d.ts +56 -0
- package/dist/stores/knowledge-coop-store.js +482 -0
- package/dist/treeseed/template-catalog/templates/starter-basic/template/package.json +6 -2
- package/dist/treeseed/template-catalog/templates/starter-basic/template/src/api/server.js +4 -0
- package/dist/treeseed/template-catalog/templates/starter-basic/template/src/config.yaml +25 -0
- package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content/decisions/adopt-initial-proposal-loop.mdx +22 -0
- package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content/people/starter-steward.mdx +11 -0
- package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content/proposals/establish-initial-proposal-loop.mdx +17 -0
- package/dist/treeseed/template-catalog/templates/starter-basic/template/src/manifest.yaml +17 -10
- package/dist/treeseed/template-catalog/templates/starter-basic/template/treeseed.site.yaml +69 -7
- package/dist/treeseed/template-catalog/templates/starter-basic/template.config.json +1 -0
- package/dist/workflow/operations.d.ts +592 -243
- package/dist/workflow/operations.js +1908 -219
- package/dist/workflow/runs.d.ts +90 -0
- package/dist/workflow/runs.js +242 -0
- package/dist/workflow/session.d.ts +31 -0
- package/dist/workflow/session.js +97 -0
- package/dist/workflow-state.d.ts +88 -2
- package/dist/workflow-state.js +288 -26
- package/dist/workflow-support.d.ts +1 -1
- package/dist/workflow-support.js +32 -2
- package/dist/workflow.d.ts +93 -3
- package/dist/workflow.js +12 -0
- package/package.json +1 -1
- package/templates/github/deploy.workflow.yml +11 -1
- package/dist/scripts/sync-dev-vars.js +0 -6
- package/dist/scripts/workspace-close.js +0 -24
- package/dist/scripts/workspace-release.js +0 -42
- 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
|
+
};
|
package/dist/workflow-state.d.ts
CHANGED
|
@@ -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
|
-
|
|
45
|
-
|
|
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: {
|