@treeseed/core 0.6.50 → 0.7.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/index.d.ts +1 -1
- package/dist/index.js +4 -4
- package/dist/launch.d.ts +3 -3
- package/dist/launch.js +4 -4
- package/dist/services/remote-runner.js +122 -3
- package/dist/services/worker.js +55 -2
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export { parseSiteConfig } from './utils/site-config-schema.js';
|
|
|
4
4
|
export { createTreeseedApiApp } from './api/app';
|
|
5
5
|
export { createRailwayTreeseedApiServer } from './api/railway';
|
|
6
6
|
export { resolveApiConfig } from './api/config';
|
|
7
|
-
export {
|
|
7
|
+
export { executeKnowledgeHubProviderLaunch, validateKnowledgeHubProviderLaunchPrerequisites, } from './launch';
|
|
8
8
|
export { createTreeseedIntegratedDevPlan, runTreeseedIntegratedDev, type TreeseedIntegratedDevCommand, type TreeseedIntegratedDevOptions, type TreeseedIntegratedDevPlan, type TreeseedIntegratedDevSurface, } from './dev';
|
|
9
9
|
export { filterSiteRenderedModels, isSiteRenderedModel, siteModelRendered, } from './utils/site-models.ts';
|
|
10
10
|
export type * from './api/types';
|
package/dist/index.js
CHANGED
|
@@ -15,8 +15,8 @@ import { createTreeseedApiApp } from "./api/app.js";
|
|
|
15
15
|
import { createRailwayTreeseedApiServer } from "./api/railway.js";
|
|
16
16
|
import { resolveApiConfig } from "./api/config.js";
|
|
17
17
|
import {
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
executeKnowledgeHubProviderLaunch,
|
|
19
|
+
validateKnowledgeHubProviderLaunchPrerequisites
|
|
20
20
|
} from "./launch.js";
|
|
21
21
|
import {
|
|
22
22
|
createTreeseedIntegratedDevPlan,
|
|
@@ -35,7 +35,7 @@ export {
|
|
|
35
35
|
createRailwayTreeseedApiServer,
|
|
36
36
|
createTreeseedApiApp,
|
|
37
37
|
createTreeseedIntegratedDevPlan,
|
|
38
|
-
|
|
38
|
+
executeKnowledgeHubProviderLaunch,
|
|
39
39
|
filterSiteRenderedModels,
|
|
40
40
|
isSiteRenderedModel,
|
|
41
41
|
parseSiteConfig,
|
|
@@ -46,5 +46,5 @@ export {
|
|
|
46
46
|
resolveTreeseedStyleEntrypoint,
|
|
47
47
|
runTreeseedIntegratedDev,
|
|
48
48
|
siteModelRendered,
|
|
49
|
-
|
|
49
|
+
validateKnowledgeHubProviderLaunchPrerequisites
|
|
50
50
|
};
|
package/dist/launch.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export {
|
|
3
|
-
export type {
|
|
1
|
+
import { executeKnowledgeHubProviderLaunch, validateKnowledgeHubProviderLaunchPrerequisites, type KnowledgeHubProviderLaunchInput, type KnowledgeHubProviderLaunchResult, type KnowledgeHubProviderLaunchPreflightReport } from '@treeseed/sdk';
|
|
2
|
+
export { executeKnowledgeHubProviderLaunch, validateKnowledgeHubProviderLaunchPrerequisites, };
|
|
3
|
+
export type { KnowledgeHubProviderLaunchInput, KnowledgeHubProviderLaunchResult, KnowledgeHubProviderLaunchPreflightReport, };
|
package/dist/launch.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
executeKnowledgeHubProviderLaunch,
|
|
3
|
+
validateKnowledgeHubProviderLaunchPrerequisites
|
|
4
4
|
} from "@treeseed/sdk";
|
|
5
5
|
export {
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
executeKnowledgeHubProviderLaunch,
|
|
7
|
+
validateKnowledgeHubProviderLaunchPrerequisites
|
|
8
8
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { fileURLToPath } from "node:url";
|
|
3
|
-
import { AgentSdk, RemoteTreeseedClient, RemoteTreeseedRunnerClient } from "@treeseed/sdk";
|
|
3
|
+
import { AgentSdk, RemoteTreeseedClient, RemoteTreeseedRunnerClient, TreeseedOperationsSdk } from "@treeseed/sdk";
|
|
4
4
|
import { createServiceSdk } from "./common.js";
|
|
5
5
|
function integerFromEnv(name, fallback) {
|
|
6
6
|
const value = process.env[name];
|
|
@@ -41,6 +41,79 @@ function createRunnerClient(config, fetchImpl) {
|
|
|
41
41
|
fetchImpl
|
|
42
42
|
}));
|
|
43
43
|
}
|
|
44
|
+
function asRecord(value) {
|
|
45
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
46
|
+
}
|
|
47
|
+
function runnerWorkspacePaths(projectId) {
|
|
48
|
+
const volumeRoot = envValue("TREESEED_WORKER_VOLUME_ROOT") || "/data";
|
|
49
|
+
const workspaceRoot = `${volumeRoot}/workspaces/${projectId}`;
|
|
50
|
+
return {
|
|
51
|
+
root: workspaceRoot,
|
|
52
|
+
site: `${workspaceRoot}/site`,
|
|
53
|
+
content: `${workspaceRoot}/content`,
|
|
54
|
+
parent: `${workspaceRoot}/workspace-root`
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
function inputForRunnerJob(job) {
|
|
58
|
+
const input = asRecord(job.input);
|
|
59
|
+
if (job.namespace !== "content" || job.operation !== "publish") {
|
|
60
|
+
return input;
|
|
61
|
+
}
|
|
62
|
+
const paths = runnerWorkspacePaths(job.projectId);
|
|
63
|
+
return {
|
|
64
|
+
...input,
|
|
65
|
+
tenantRoot: typeof input.tenantRoot === "string" ? input.tenantRoot : paths.site,
|
|
66
|
+
contentRepositoryRoot: typeof input.contentRepositoryRoot === "string" ? input.contentRepositoryRoot : paths.content,
|
|
67
|
+
workspaceRoot: typeof input.workspaceRoot === "string" ? input.workspaceRoot : paths.root
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
async function prepareLaunchIntentWithCredentialSessions(runner, jobId, launchJobInput, launchIntent) {
|
|
71
|
+
const sessions = asRecord(launchJobInput.credentialSessions);
|
|
72
|
+
const nextIntent = JSON.parse(JSON.stringify(launchIntent));
|
|
73
|
+
const execution = asRecord(nextIntent.execution);
|
|
74
|
+
const providerLaunchInput = asRecord(execution.providerLaunchInput);
|
|
75
|
+
const envOverlay = {};
|
|
76
|
+
const consume = async (key) => {
|
|
77
|
+
const sessionId = typeof sessions[key] === "string" ? sessions[key].trim() : "";
|
|
78
|
+
if (!sessionId || !runner) return null;
|
|
79
|
+
return (await runner.consumeCredentialSession(jobId, sessionId)).payload;
|
|
80
|
+
};
|
|
81
|
+
const repositorySession = await consume("repositoryHost");
|
|
82
|
+
if (repositorySession?.config) {
|
|
83
|
+
const token = repositorySession.config.GH_TOKEN ?? repositorySession.config.GITHUB_TOKEN;
|
|
84
|
+
if (token) {
|
|
85
|
+
envOverlay.GH_TOKEN = token;
|
|
86
|
+
envOverlay.GITHUB_TOKEN = repositorySession.config.GITHUB_TOKEN ?? token;
|
|
87
|
+
}
|
|
88
|
+
const owner = repositorySession.config.organizationOrOwner ?? repositorySession.config.owner;
|
|
89
|
+
if (owner) {
|
|
90
|
+
nextIntent.repository = {
|
|
91
|
+
...asRecord(nextIntent.repository),
|
|
92
|
+
owner
|
|
93
|
+
};
|
|
94
|
+
providerLaunchInput.repoOwner = owner;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
const webSession = await consume("webHost");
|
|
98
|
+
if (webSession?.config) {
|
|
99
|
+
providerLaunchInput.cloudflareHost = {
|
|
100
|
+
...asRecord(providerLaunchInput.cloudflareHost),
|
|
101
|
+
config: webSession.config
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
const processingSession = await consume("processingHost");
|
|
105
|
+
if (processingSession?.config) {
|
|
106
|
+
providerLaunchInput.processingHost = {
|
|
107
|
+
...asRecord(providerLaunchInput.processingHost),
|
|
108
|
+
config: processingSession.config
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
nextIntent.execution = {
|
|
112
|
+
...execution,
|
|
113
|
+
providerLaunchInput
|
|
114
|
+
};
|
|
115
|
+
return { intent: nextIntent, envOverlay };
|
|
116
|
+
}
|
|
44
117
|
async function runRemoteRunnerCycle(options = {}) {
|
|
45
118
|
const config = options.config ?? resolveRemoteRunnerConfig();
|
|
46
119
|
const sdk = options.sdk ?? createServiceSdk();
|
|
@@ -65,12 +138,58 @@ async function runRemoteRunnerCycle(options = {}) {
|
|
|
65
138
|
status: "running"
|
|
66
139
|
}
|
|
67
140
|
});
|
|
68
|
-
const
|
|
141
|
+
const launchJobInput = job.input && typeof job.input === "object" ? job.input : {};
|
|
142
|
+
const launchIntent = launchJobInput.launchIntent && typeof launchJobInput.launchIntent === "object" ? launchJobInput.launchIntent : launchJobInput;
|
|
143
|
+
const isLaunchJob = job.namespace === "workflow" && job.operation === "launch_project";
|
|
144
|
+
if (isLaunchJob) {
|
|
145
|
+
await runner.progress(job.id, {
|
|
146
|
+
summary: "Validating launch plan and preparing repository topology.",
|
|
147
|
+
data: {
|
|
148
|
+
runnerId: config.runnerId,
|
|
149
|
+
phase: "preflight_running",
|
|
150
|
+
status: "running",
|
|
151
|
+
title: "Validating launch plan"
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
const preparedLaunch = isLaunchJob ? await prepareLaunchIntentWithCredentialSessions(runner, job.id, launchJobInput, launchIntent) : null;
|
|
156
|
+
const result = isLaunchJob ? await new TreeseedOperationsSdk().execute({
|
|
157
|
+
operationName: launchJobInput.resume === true ? "hub.resume_launch" : "hub.execute_launch",
|
|
158
|
+
input: preparedLaunch?.intent ?? launchIntent
|
|
159
|
+
}, {
|
|
160
|
+
cwd: process.env.TREESEED_MARKET_REPO_ROOT?.trim() || process.cwd(),
|
|
161
|
+
env: {
|
|
162
|
+
...process.env,
|
|
163
|
+
...preparedLaunch?.envOverlay ?? {}
|
|
164
|
+
},
|
|
165
|
+
transport: "sdk",
|
|
166
|
+
onProgress: async (event) => {
|
|
167
|
+
if (event.kind !== "hub_launch_phase") return;
|
|
168
|
+
await runner.progress(job.id, {
|
|
169
|
+
summary: typeof event.summary === "string" ? event.summary : null,
|
|
170
|
+
data: {
|
|
171
|
+
...event,
|
|
172
|
+
runnerId: config.runnerId
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
}) : await sdk.dispatch({
|
|
69
177
|
namespace: job.namespace,
|
|
70
178
|
operation: job.operation,
|
|
71
|
-
input: job
|
|
179
|
+
input: inputForRunnerJob(job),
|
|
72
180
|
preferredMode: "prefer_local"
|
|
73
181
|
});
|
|
182
|
+
if (isLaunchJob) {
|
|
183
|
+
await runner.progress(job.id, {
|
|
184
|
+
summary: "Launch execution completed; applying control-plane projections.",
|
|
185
|
+
data: {
|
|
186
|
+
runnerId: config.runnerId,
|
|
187
|
+
phase: "projection_running",
|
|
188
|
+
status: "running",
|
|
189
|
+
title: "Recording launch result"
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
}
|
|
74
193
|
await runner.complete(job.id, {
|
|
75
194
|
output: result.mode === "inline" ? result.payload : result
|
|
76
195
|
});
|
package/dist/services/worker.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { mkdir } from "node:fs/promises";
|
|
2
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import { AgentKernel } from "../agents/kernel/agent-kernel.js";
|
|
@@ -28,6 +28,54 @@ function runnerRepositoryPath(volumeRoot, repositoryId, taskId) {
|
|
|
28
28
|
worktree: join(repositoryRoot, "worktrees", taskId)
|
|
29
29
|
};
|
|
30
30
|
}
|
|
31
|
+
function runnerComposedWorkspacePath(volumeRoot, hubId) {
|
|
32
|
+
const workspaceRoot = join(volumeRoot, "workspaces", hubId);
|
|
33
|
+
return {
|
|
34
|
+
root: workspaceRoot,
|
|
35
|
+
parent: join(workspaceRoot, "workspace-root"),
|
|
36
|
+
site: join(workspaceRoot, "site"),
|
|
37
|
+
content: join(workspaceRoot, "content"),
|
|
38
|
+
manifest: join(workspaceRoot, ".treeseed", "workspace.json")
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
async function ensureRunnerComposedWorkspace(volumeRoot, task) {
|
|
42
|
+
const payload = parseTaskPayload(task);
|
|
43
|
+
const workspace = asRecord(payload.workspace);
|
|
44
|
+
const hubId = String(workspace.hubId ?? payload.projectId ?? task.projectId ?? "").trim();
|
|
45
|
+
if (!hubId) return null;
|
|
46
|
+
const paths = runnerComposedWorkspacePath(volumeRoot, hubId);
|
|
47
|
+
await mkdir(paths.parent, { recursive: true });
|
|
48
|
+
await mkdir(paths.site, { recursive: true });
|
|
49
|
+
await mkdir(paths.content, { recursive: true });
|
|
50
|
+
await mkdir(join(paths.root, ".treeseed"), { recursive: true });
|
|
51
|
+
await writeFile(paths.manifest, `${JSON.stringify({
|
|
52
|
+
schemaVersion: 1,
|
|
53
|
+
kind: "treeseed_composed_workspace",
|
|
54
|
+
hubId,
|
|
55
|
+
softwareRepository: workspace.softwareRepository ?? null,
|
|
56
|
+
contentRepository: workspace.contentRepository ?? null,
|
|
57
|
+
parentRepository: workspace.parentRepository ?? null,
|
|
58
|
+
paths: {
|
|
59
|
+
workspaceRoot: paths.parent,
|
|
60
|
+
site: paths.site,
|
|
61
|
+
content: paths.content
|
|
62
|
+
},
|
|
63
|
+
allowedWriteTargets: Array.isArray(workspace.allowedWriteTargets) ? workspace.allowedWriteTargets : ["content"],
|
|
64
|
+
credentialSessionScopes: workspace.credentialSessionScopes ?? {
|
|
65
|
+
software: ["repository:software"],
|
|
66
|
+
content: ["repository:content"],
|
|
67
|
+
parentWorkspace: []
|
|
68
|
+
},
|
|
69
|
+
credentialScopes: workspace.credentialScopes ?? {
|
|
70
|
+
software: ["repository:software"],
|
|
71
|
+
content: ["repository:content"],
|
|
72
|
+
parentWorkspace: []
|
|
73
|
+
},
|
|
74
|
+
contentOverlay: workspace.contentOverlay ?? "src_content_when_present"
|
|
75
|
+
}, null, 2)}
|
|
76
|
+
`, "utf8");
|
|
77
|
+
return paths;
|
|
78
|
+
}
|
|
31
79
|
class WorkerPausedForApproval extends Error {
|
|
32
80
|
constructor(request) {
|
|
33
81
|
super(String(request.summary ?? request.title ?? "Task paused for approval."));
|
|
@@ -39,6 +87,10 @@ async function executeQueuedTask(options) {
|
|
|
39
87
|
const context = await buildTaskContext(options.sdk, options.taskId);
|
|
40
88
|
const task = context.task;
|
|
41
89
|
const payload = parseTaskPayload(task);
|
|
90
|
+
await ensureRunnerComposedWorkspace(options.volumeRoot, {
|
|
91
|
+
...task ?? {},
|
|
92
|
+
payloadJson: JSON.stringify(payload)
|
|
93
|
+
});
|
|
42
94
|
const capacityEnvelope = readCapacityEnvelope(payload);
|
|
43
95
|
const explicitApproval = asRecord(payload.approvalRequest);
|
|
44
96
|
if (Object.keys(explicitApproval).length > 0 || capacityEnvelope?.maxCredits === 0) {
|
|
@@ -233,7 +285,8 @@ async function runWorkerCycle() {
|
|
|
233
285
|
kernel,
|
|
234
286
|
taskId: message.body.taskId,
|
|
235
287
|
workerId: config.workerId,
|
|
236
|
-
queueAttempt: message.attempts
|
|
288
|
+
queueAttempt: message.attempts,
|
|
289
|
+
volumeRoot: config.volumeRoot
|
|
237
290
|
});
|
|
238
291
|
} catch (error) {
|
|
239
292
|
if (error instanceof WorkerPausedForApproval) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@treeseed/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Treeseed integrated platform starter for Astro/Starlight web runtimes and Hono API runtimes.",
|
|
5
5
|
"license": "AGPL-3.0-only",
|
|
6
6
|
"repository": {
|
|
@@ -78,7 +78,7 @@
|
|
|
78
78
|
"@astrojs/sitemap": "3.7.0",
|
|
79
79
|
"@astrojs/starlight": "0.37.6",
|
|
80
80
|
"@tailwindcss/vite": "^4.1.4",
|
|
81
|
-
"@treeseed/sdk": "0.
|
|
81
|
+
"@treeseed/sdk": "0.7.0",
|
|
82
82
|
"astro": "^5.6.1",
|
|
83
83
|
"esbuild": "^0.28.0",
|
|
84
84
|
"hono": "^4.8.2",
|