@treeseed/sdk 0.10.22 → 0.10.24
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/db/market-schema.js +3 -2
- package/dist/market-client.d.ts +4 -0
- package/dist/market-client.js +6 -0
- package/dist/operations/providers/default.js +26 -4
- package/dist/operations/repository-operations.js +6 -2
- package/dist/operations/services/bootstrap-runner.d.ts +5 -1
- package/dist/operations/services/bootstrap-runner.js +34 -5
- package/dist/operations/services/config-runtime.d.ts +2 -1
- package/dist/operations/services/deploy.d.ts +18 -1
- package/dist/operations/services/deploy.js +176 -24
- package/dist/operations/services/github-automation.d.ts +10 -1
- package/dist/operations/services/github-automation.js +18 -4
- package/dist/operations/services/hosting-audit.d.ts +2 -1
- package/dist/operations/services/hosting-audit.js +12 -1
- package/dist/operations/services/hub-launch.d.ts +1 -0
- package/dist/operations/services/hub-launch.js +1 -0
- package/dist/operations/services/hub-provider-launch.d.ts +9 -0
- package/dist/operations/services/hub-provider-launch.js +140 -40
- package/dist/operations/services/managed-host-security.d.ts +1 -1
- package/dist/operations/services/managed-host-security.js +4 -1
- package/dist/operations/services/project-platform.d.ts +25 -0
- package/dist/operations/services/project-platform.js +91 -23
- package/dist/operations/services/railway-api.js +2 -1
- package/dist/operations/services/railway-deploy.d.ts +32 -2
- package/dist/operations/services/railway-deploy.js +94 -27
- package/dist/operations/services/template-registry.js +33 -3
- package/dist/platform/contracts.d.ts +1 -0
- package/dist/platform/deploy-config.js +8 -1
- package/dist/platform/deploy-runtime.js +1 -0
- package/dist/platform/environment.d.ts +1 -1
- package/dist/platform/environment.js +1 -1
- package/dist/reconcile/builtin-adapters.js +155 -25
- package/dist/reconcile/contracts.d.ts +1 -1
- package/dist/reconcile/desired-state.js +17 -1
- package/dist/reconcile/engine.d.ts +2 -0
- package/dist/reconcile/engine.js +58 -3
- package/dist/reconcile/units.js +1 -0
- package/dist/sdk-types.d.ts +1 -1
- package/dist/sdk-types.js +2 -0
- package/dist/timing.d.ts +20 -0
- package/dist/timing.js +73 -0
- package/dist/treeseed/template-catalog/catalog.fixture.json +150 -0
- package/dist/workflow/operations.d.ts +2 -0
- package/drizzle/market/0000_market_control_plane.sql +3 -3
- package/drizzle/market/0003_project_team_slug_unique.sql +4 -0
- package/package.json +1 -1
- package/templates/github/deploy-web.workflow.yml +4 -0
package/dist/db/market-schema.js
CHANGED
|
@@ -297,13 +297,14 @@ const webSessions = pgTable("web_sessions", {
|
|
|
297
297
|
const projects = pgTable("projects", {
|
|
298
298
|
id: text("id").primaryKey(),
|
|
299
299
|
teamId: text("team_id").notNull(),
|
|
300
|
-
slug: text("slug").notNull()
|
|
300
|
+
slug: text("slug").notNull(),
|
|
301
301
|
name: text("name").notNull(),
|
|
302
302
|
description: text("description"),
|
|
303
303
|
metadataJson: text("metadata_json"),
|
|
304
304
|
createdAt: text("created_at").notNull(),
|
|
305
305
|
updatedAt: text("updated_at").notNull()
|
|
306
306
|
}, (table) => [
|
|
307
|
+
uniqueIndex("idx_projects_team_slug").on(table.teamId, table.slug),
|
|
307
308
|
index("idx_projects_team_id").on(table.teamId)
|
|
308
309
|
]);
|
|
309
310
|
const projectConnections = pgTable("project_connections", {
|
|
@@ -445,7 +446,7 @@ const catalogItems = pgTable("catalog_items", {
|
|
|
445
446
|
createdAt: text("created_at").notNull(),
|
|
446
447
|
updatedAt: text("updated_at").notNull()
|
|
447
448
|
}, (table) => [
|
|
448
|
-
uniqueIndex("
|
|
449
|
+
uniqueIndex("idx_catalog_items_team_kind_slug").on(table.teamId, table.kind, table.slug),
|
|
449
450
|
index("idx_catalog_items_team_kind").on(table.teamId, table.kind, table.updatedAt),
|
|
450
451
|
index("idx_catalog_items_visibility_listing").on(table.visibility, table.listingEnabled, table.updatedAt)
|
|
451
452
|
]);
|
package/dist/market-client.d.ts
CHANGED
|
@@ -374,6 +374,10 @@ export declare class MarketClient {
|
|
|
374
374
|
ok: true;
|
|
375
375
|
payload: ProjectDeployment;
|
|
376
376
|
}>;
|
|
377
|
+
projectDeploymentById(deploymentId: string): Promise<{
|
|
378
|
+
ok: true;
|
|
379
|
+
payload: ProjectDeployment;
|
|
380
|
+
}>;
|
|
377
381
|
projectDeploymentEvents(projectId: string, deploymentId: string, options?: {
|
|
378
382
|
limit?: number | string | null;
|
|
379
383
|
}): Promise<{
|
package/dist/market-client.js
CHANGED
|
@@ -485,6 +485,12 @@ class MarketClient {
|
|
|
485
485
|
{ requireAuth: true }
|
|
486
486
|
);
|
|
487
487
|
}
|
|
488
|
+
projectDeploymentById(deploymentId) {
|
|
489
|
+
return this.request(
|
|
490
|
+
`/v1/project-deployments/${encodeURIComponent(deploymentId)}`,
|
|
491
|
+
{ requireAuth: true }
|
|
492
|
+
);
|
|
493
|
+
}
|
|
488
494
|
projectDeploymentEvents(projectId, deploymentId, options = {}) {
|
|
489
495
|
const query = options.limit ? `?limit=${encodeURIComponent(String(options.limit))}` : "";
|
|
490
496
|
return this.request(
|
|
@@ -91,6 +91,28 @@ function failureResult(metadata, message, options = {}) {
|
|
|
91
91
|
function contextEnv(context) {
|
|
92
92
|
return { ...process.env, ...context.env ?? {} };
|
|
93
93
|
}
|
|
94
|
+
async function withTemporaryProcessEnv(env, action) {
|
|
95
|
+
const previous = /* @__PURE__ */ new Map();
|
|
96
|
+
for (const [key, value] of Object.entries(env)) {
|
|
97
|
+
previous.set(key, process.env[key]);
|
|
98
|
+
if (value === void 0) {
|
|
99
|
+
delete process.env[key];
|
|
100
|
+
} else {
|
|
101
|
+
process.env[key] = value;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
try {
|
|
105
|
+
return await action();
|
|
106
|
+
} finally {
|
|
107
|
+
for (const [key, value] of previous) {
|
|
108
|
+
if (value === void 0) {
|
|
109
|
+
delete process.env[key];
|
|
110
|
+
} else {
|
|
111
|
+
process.env[key] = value;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
94
116
|
function operationEnv(context) {
|
|
95
117
|
const tenantConfigPath = resolve(context.cwd, "treeseed.site.yaml");
|
|
96
118
|
return existsSync(tenantConfigPath) ? resolveTreeseedLaunchEnvironment({ tenantRoot: context.cwd, scope: "local", baseEnv: contextEnv(context) }) : contextEnv(context);
|
|
@@ -399,21 +421,21 @@ class HubValidateLaunchOperation extends BaseOperation {
|
|
|
399
421
|
class HubExecuteLaunchOperation extends BaseOperation {
|
|
400
422
|
async execute(input, context) {
|
|
401
423
|
const intent = input.intent && typeof input.intent === "object" ? input.intent : input;
|
|
402
|
-
const result = await executeKnowledgeHubLaunch(intent, {
|
|
424
|
+
const result = await withTemporaryProcessEnv(contextEnv(context), () => executeKnowledgeHubLaunch(intent, {
|
|
403
425
|
onPhase: async (phase) => {
|
|
404
426
|
await context.onProgress?.({
|
|
405
427
|
kind: "hub_launch_phase",
|
|
406
428
|
...phase
|
|
407
429
|
});
|
|
408
430
|
}
|
|
409
|
-
});
|
|
431
|
+
}));
|
|
410
432
|
return operationResult(this.metadata, result);
|
|
411
433
|
}
|
|
412
434
|
}
|
|
413
435
|
class HubResumeLaunchOperation extends BaseOperation {
|
|
414
436
|
async execute(input, context) {
|
|
415
437
|
const intent = input.intent && typeof input.intent === "object" ? input.intent : input;
|
|
416
|
-
const result = await executeKnowledgeHubLaunch(intent, {
|
|
438
|
+
const result = await withTemporaryProcessEnv(contextEnv(context), () => executeKnowledgeHubLaunch(intent, {
|
|
417
439
|
onPhase: async (phase) => {
|
|
418
440
|
await context.onProgress?.({
|
|
419
441
|
kind: "hub_launch_phase",
|
|
@@ -421,7 +443,7 @@ class HubResumeLaunchOperation extends BaseOperation {
|
|
|
421
443
|
...phase
|
|
422
444
|
});
|
|
423
445
|
}
|
|
424
|
-
});
|
|
446
|
+
}));
|
|
425
447
|
return operationResult(this.metadata, {
|
|
426
448
|
resumed: true,
|
|
427
449
|
...result
|
|
@@ -310,15 +310,19 @@ async function writeContentRecord(repoPath, collection, input, normalizedInput)
|
|
|
310
310
|
const existingTarget = input.overwrite === true ? [`${normalized.slug}.mdx`, `${normalized.slug}.md`].map((file) => resolve(root, file)).find((candidate) => existsSync(candidate)) : null;
|
|
311
311
|
const target = existingTarget ?? safeContentPath(repoPath, collection, normalized.slug, normalized.extension);
|
|
312
312
|
if (existsSync(target) && input.overwrite !== true) throw new Error("A content record with that slug already exists.");
|
|
313
|
+
const frontmatter = existingTarget && input.preserveFrontmatter === true ? {
|
|
314
|
+
...normalized.frontmatter,
|
|
315
|
+
...(await readContentRecord(repoPath, collection, normalized.slug)).frontmatter
|
|
316
|
+
} : normalized.frontmatter;
|
|
313
317
|
const relativePath = await writeParsedRecord(repoPath, {
|
|
314
318
|
path: target,
|
|
315
|
-
frontmatter
|
|
319
|
+
frontmatter,
|
|
316
320
|
body: normalized.body
|
|
317
321
|
});
|
|
318
322
|
return {
|
|
319
323
|
collection,
|
|
320
324
|
slug: normalized.slug,
|
|
321
|
-
id:
|
|
325
|
+
id: frontmatter.id,
|
|
322
326
|
path: relativePath,
|
|
323
327
|
href: collection === "agents" ? `/app/projects/${encodeURIComponent(String(input.projectId ?? ""))}/agents/${encodeURIComponent(normalized.slug)}` : `/app/work/${collection}/${encodeURIComponent(normalized.slug)}`
|
|
324
328
|
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type TreeseedTimingEntry } from '../../timing.ts';
|
|
1
2
|
export type TreeseedBootstrapExecution = 'parallel' | 'sequential';
|
|
2
3
|
export type TreeseedBootstrapStream = 'stdout' | 'stderr';
|
|
3
4
|
export type TreeseedBootstrapWriter = (line: string, stream?: TreeseedBootstrapStream) => void;
|
|
@@ -11,13 +12,16 @@ export type TreeseedBootstrapDagNode<TResult = unknown> = {
|
|
|
11
12
|
id: string;
|
|
12
13
|
dependencies?: string[];
|
|
13
14
|
run: () => Promise<TResult> | TResult;
|
|
15
|
+
label?: string;
|
|
14
16
|
};
|
|
15
17
|
export declare function formatTreeseedBootstrapPrefix(prefix: TreeseedBootstrapTaskPrefix): string;
|
|
16
18
|
export declare function formatTreeseedBootstrapLine(prefix: TreeseedBootstrapTaskPrefix, line: string): string;
|
|
17
19
|
export declare function writeTreeseedBootstrapLine(write: TreeseedBootstrapWriter | undefined, prefix: TreeseedBootstrapTaskPrefix, line: string, stream?: TreeseedBootstrapStream): void;
|
|
18
|
-
export declare function runTreeseedBootstrapDag<TResult = unknown>({ nodes, execution, }: {
|
|
20
|
+
export declare function runTreeseedBootstrapDag<TResult = unknown>({ nodes, execution, write, timings, }: {
|
|
19
21
|
nodes: Array<TreeseedBootstrapDagNode<TResult>>;
|
|
20
22
|
execution?: TreeseedBootstrapExecution;
|
|
23
|
+
write?: TreeseedBootstrapWriter;
|
|
24
|
+
timings?: TreeseedTimingEntry[];
|
|
21
25
|
}): Promise<Map<string, TResult>>;
|
|
22
26
|
export declare function sleep(milliseconds: number): Promise<void>;
|
|
23
27
|
export declare function runPrefixedCommand(command: string, args: string[], { cwd, env, input, write, prefix, }: {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
|
+
import { elapsedMs, formatDurationMs } from "../../timing.js";
|
|
2
3
|
function formatTreeseedBootstrapPrefix(prefix) {
|
|
3
4
|
return `[${prefix.scope}][${prefix.system}][${prefix.task}][${prefix.stage}]`;
|
|
4
5
|
}
|
|
@@ -43,19 +44,47 @@ function dependencyLevels(nodes) {
|
|
|
43
44
|
}
|
|
44
45
|
async function runTreeseedBootstrapDag({
|
|
45
46
|
nodes,
|
|
46
|
-
execution = "parallel"
|
|
47
|
+
execution = "parallel",
|
|
48
|
+
write,
|
|
49
|
+
timings
|
|
47
50
|
}) {
|
|
48
51
|
const results = /* @__PURE__ */ new Map();
|
|
52
|
+
const recordNode = async (node) => {
|
|
53
|
+
const label = node.label ?? node.id;
|
|
54
|
+
const startMs = performance.now();
|
|
55
|
+
const entry = {
|
|
56
|
+
name: `bootstrap:${label}`,
|
|
57
|
+
durationMs: 0,
|
|
58
|
+
status: "running",
|
|
59
|
+
metadata: { nodeId: node.id, dependencies: node.dependencies ?? [] }
|
|
60
|
+
};
|
|
61
|
+
timings?.push(entry);
|
|
62
|
+
write?.(`[bootstrap][${node.id}] started`);
|
|
63
|
+
try {
|
|
64
|
+
const result = await Promise.resolve(node.run());
|
|
65
|
+
entry.durationMs = elapsedMs(startMs);
|
|
66
|
+
entry.status = "success";
|
|
67
|
+
write?.(`[bootstrap][${node.id}] completed in ${formatDurationMs(entry.durationMs)}`);
|
|
68
|
+
results.set(node.id, result);
|
|
69
|
+
} catch (error) {
|
|
70
|
+
entry.durationMs = elapsedMs(startMs);
|
|
71
|
+
entry.status = "failed";
|
|
72
|
+
entry.metadata = {
|
|
73
|
+
...entry.metadata ?? {},
|
|
74
|
+
error: error instanceof Error ? error.message : String(error)
|
|
75
|
+
};
|
|
76
|
+
write?.(`[bootstrap][${node.id}] failed after ${formatDurationMs(entry.durationMs)}`, "stderr");
|
|
77
|
+
throw error;
|
|
78
|
+
}
|
|
79
|
+
};
|
|
49
80
|
for (const level of dependencyLevels(nodes)) {
|
|
50
81
|
if (execution === "sequential") {
|
|
51
82
|
for (const node of level) {
|
|
52
|
-
|
|
83
|
+
await recordNode(node);
|
|
53
84
|
}
|
|
54
85
|
continue;
|
|
55
86
|
}
|
|
56
|
-
await Promise.all(level.map(
|
|
57
|
-
results.set(node.id, await Promise.resolve(node.run()));
|
|
58
|
-
}));
|
|
87
|
+
await Promise.all(level.map(recordNode));
|
|
59
88
|
}
|
|
60
89
|
return results;
|
|
61
90
|
}
|
|
@@ -55,7 +55,7 @@ export type TreeseedConfigEntrySnapshot = {
|
|
|
55
55
|
group: string;
|
|
56
56
|
cluster: string;
|
|
57
57
|
startupProfile: 'core' | 'optional' | 'advanced';
|
|
58
|
-
requirement: 'required' | 'conditional' | 'optional';
|
|
58
|
+
requirement: 'required' | 'conditional' | 'optional' | 'generated';
|
|
59
59
|
description: string;
|
|
60
60
|
howToGet: string;
|
|
61
61
|
sensitivity: 'secret' | 'plain' | 'derived';
|
|
@@ -385,6 +385,7 @@ export declare function initializeTreeseedPersistentEnvironment({ tenantRoot, sc
|
|
|
385
385
|
plans: import("../../reconcile/contracts.ts").TreeseedReconcilePlan[];
|
|
386
386
|
results: import("../../reconcile/contracts.ts").TreeseedReconcileResult[];
|
|
387
387
|
state: import("../../reconcile/contracts.ts").TreeseedReconcileStateRecord;
|
|
388
|
+
timings: import("../../timing.ts").TreeseedTimingEntry[];
|
|
388
389
|
};
|
|
389
390
|
secrets: string[];
|
|
390
391
|
}>;
|
|
@@ -85,7 +85,7 @@ export declare function buildPublicVars(deployConfig: any, options?: {}): {
|
|
|
85
85
|
export declare function buildSecretMap(deployConfig: any, state: any): {
|
|
86
86
|
TREESEED_FORM_TOKEN_SECRET: any;
|
|
87
87
|
TREESEED_EDITORIAL_PREVIEW_SECRET: any;
|
|
88
|
-
TREESEED_TURNSTILE_SECRET_KEY:
|
|
88
|
+
TREESEED_TURNSTILE_SECRET_KEY: any;
|
|
89
89
|
TREESEED_SMTP_PASSWORD: string | null;
|
|
90
90
|
};
|
|
91
91
|
export declare function loadDeployState(tenantRoot: any, deployConfig: any, options?: {}): any;
|
|
@@ -307,6 +307,10 @@ export declare function listD1Databases(tenantRoot: any, env: any): any;
|
|
|
307
307
|
export declare function listQueues(tenantRoot: any, env: any): any;
|
|
308
308
|
export declare function listR2Buckets(tenantRoot: any, env: any): any;
|
|
309
309
|
export declare function listPagesProjects(tenantRoot: any, env: any): any;
|
|
310
|
+
export declare function listTurnstileWidgets(tenantRoot: any, env: any): any;
|
|
311
|
+
export declare function getTurnstileWidget(env: any, sitekey: any): any;
|
|
312
|
+
export declare function createTurnstileWidget(env: any, input: any): any;
|
|
313
|
+
export declare function updateTurnstileWidget(env: any, sitekey: any, input: any): any;
|
|
310
314
|
export declare function buildCloudflarePagesFunctionBindings(state: any): {
|
|
311
315
|
r2_buckets?: {
|
|
312
316
|
[x: number]: {
|
|
@@ -330,6 +334,7 @@ export declare function buildProvisioningSummary(deployConfig: any, state: any,
|
|
|
330
334
|
siteUrl: any;
|
|
331
335
|
accountId: any;
|
|
332
336
|
pages: any;
|
|
337
|
+
turnstileWidget: any;
|
|
333
338
|
formGuardKv: any;
|
|
334
339
|
sessionKv: any;
|
|
335
340
|
siteDataDb: any;
|
|
@@ -341,6 +346,7 @@ export declare function buildProvisioningSummary(deployConfig: any, state: any,
|
|
|
341
346
|
queue: any;
|
|
342
347
|
dlq: any;
|
|
343
348
|
database: any;
|
|
349
|
+
turnstileWidget: any;
|
|
344
350
|
formGuardKv: any;
|
|
345
351
|
railwayProject: any;
|
|
346
352
|
webDomain: any;
|
|
@@ -891,6 +897,7 @@ export declare function destroyTreeseedEnvironmentResources(tenantRoot: any, opt
|
|
|
891
897
|
siteUrl: any;
|
|
892
898
|
accountId: any;
|
|
893
899
|
pages: any;
|
|
900
|
+
turnstileWidget: any;
|
|
894
901
|
formGuardKv: any;
|
|
895
902
|
sessionKv: any;
|
|
896
903
|
siteDataDb: any;
|
|
@@ -902,6 +909,7 @@ export declare function destroyTreeseedEnvironmentResources(tenantRoot: any, opt
|
|
|
902
909
|
queue: any;
|
|
903
910
|
dlq: any;
|
|
904
911
|
database: any;
|
|
912
|
+
turnstileWidget: any;
|
|
905
913
|
formGuardKv: any;
|
|
906
914
|
railwayProject: any;
|
|
907
915
|
webDomain: any;
|
|
@@ -963,6 +971,7 @@ export declare function destroyCloudflareResources(tenantRoot: any, options?: {}
|
|
|
963
971
|
siteUrl: any;
|
|
964
972
|
accountId: any;
|
|
965
973
|
pages: any;
|
|
974
|
+
turnstileWidget: any;
|
|
966
975
|
formGuardKv: any;
|
|
967
976
|
sessionKv: any;
|
|
968
977
|
siteDataDb: any;
|
|
@@ -974,6 +983,7 @@ export declare function destroyCloudflareResources(tenantRoot: any, options?: {}
|
|
|
974
983
|
queue: any;
|
|
975
984
|
dlq: any;
|
|
976
985
|
database: any;
|
|
986
|
+
turnstileWidget: any;
|
|
977
987
|
formGuardKv: any;
|
|
978
988
|
railwayProject: any;
|
|
979
989
|
webDomain: any;
|
|
@@ -1008,6 +1018,11 @@ export declare function destroyCloudflareResources(tenantRoot: any, options?: {}
|
|
|
1008
1018
|
status: any;
|
|
1009
1019
|
name: any;
|
|
1010
1020
|
};
|
|
1021
|
+
turnstileWidget: {
|
|
1022
|
+
status: any;
|
|
1023
|
+
sitekey: any;
|
|
1024
|
+
name: null;
|
|
1025
|
+
};
|
|
1011
1026
|
formGuard: {
|
|
1012
1027
|
status: string;
|
|
1013
1028
|
id: any;
|
|
@@ -1064,6 +1079,7 @@ export declare function provisionCloudflareResources(tenantRoot: any, options?:
|
|
|
1064
1079
|
siteUrl: any;
|
|
1065
1080
|
accountId: any;
|
|
1066
1081
|
pages: any;
|
|
1082
|
+
turnstileWidget: any;
|
|
1067
1083
|
formGuardKv: any;
|
|
1068
1084
|
sessionKv: any;
|
|
1069
1085
|
siteDataDb: any;
|
|
@@ -1075,6 +1091,7 @@ export declare function provisionCloudflareResources(tenantRoot: any, options?:
|
|
|
1075
1091
|
queue: any;
|
|
1076
1092
|
dlq: any;
|
|
1077
1093
|
database: any;
|
|
1094
|
+
turnstileWidget: any;
|
|
1078
1095
|
formGuardKv: any;
|
|
1079
1096
|
railwayProject: any;
|
|
1080
1097
|
webDomain: any;
|