@treeseed/sdk 0.4.5 → 0.4.7

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.
@@ -4,7 +4,7 @@ export type FixtureSupportDeclaration = {
4
4
  modes: readonly FixtureInjectionMode[];
5
5
  workspaceDirName?: string;
6
6
  entrySpecifier?: string;
7
- contractsShim?: 'agent';
7
+ contractsShim?: 'core-agent';
8
8
  };
9
9
  export type ResolveSharedFixtureOptions = {
10
10
  packageRoot?: string;
@@ -106,15 +106,15 @@ function ensureFixtureLinkedPackage(fixtureRoot, packageName, resolvedPackageRoo
106
106
  rmSync(packageDir, { recursive: true, force: true });
107
107
  symlinkSync(resolvedPackageRoot, packageDir, "dir");
108
108
  }
109
- function buildAgentContractsShimPackage(fixtureRoot) {
110
- const packageDir = resolve(fixtureRoot, "node_modules", "@treeseed", "agent");
109
+ function buildCoreAgentContractsShimPackage(fixtureRoot) {
110
+ const packageDir = resolve(fixtureRoot, "node_modules", "@treeseed", "core");
111
111
  rmSync(packageDir, { recursive: true, force: true });
112
112
  mkdirSync(resolve(packageDir, "contracts"), { recursive: true });
113
113
  writeFileSync(
114
114
  resolve(packageDir, "package.json"),
115
115
  JSON.stringify(
116
116
  {
117
- name: "@treeseed/agent",
117
+ name: "@treeseed/core",
118
118
  type: "module",
119
119
  exports: {
120
120
  "./runtime-types": {
@@ -315,8 +315,8 @@ function prepareFixturePackages(options) {
315
315
  satisfied = true;
316
316
  break;
317
317
  }
318
- if (mode === "contracts-only" && declaration.contractsShim === "agent") {
319
- buildAgentContractsShimPackage(options.fixtureRoot);
318
+ if (mode === "contracts-only" && declaration.contractsShim === "core-agent") {
319
+ buildCoreAgentContractsShimPackage(options.fixtureRoot);
320
320
  satisfied = true;
321
321
  break;
322
322
  }
@@ -1064,7 +1064,7 @@ function syncTreeseedRailwayEnvironment({ tenantRoot, scope = "prod", dryRun = f
1064
1064
  }
1065
1065
  const environment = service.environments?.[scope];
1066
1066
  const fallbackServiceName = serviceKey === "api" ? config.settings.services.railway.apiServiceName : serviceKey === "agents" ? config.settings.services.railway.agentsServiceName : "";
1067
- const defaultRootDir = serviceKey === "api" ? "." : "packages/agent";
1067
+ const defaultRootDir = ["api", "manager", "worker", "workdayStart", "workdayReport"].includes(serviceKey) ? "." : "packages/core";
1068
1068
  return {
1069
1069
  service: serviceKey,
1070
1070
  projectName: service.railway?.projectName ?? config.settings.services.railway.projectName,
@@ -26,7 +26,7 @@ function configuredRailwayServices(tenantRoot, scope) {
26
26
  if (!service || service.enabled === false || (service.provider ?? "railway") !== "railway") {
27
27
  return null;
28
28
  }
29
- const defaultRootDir = serviceKey === "api" ? "." : "packages/agent";
29
+ const defaultRootDir = ["api", "manager", "worker", "workdayStart", "workdayReport"].includes(serviceKey) ? "." : "packages/core";
30
30
  const serviceRoot = resolve(tenantRoot, service.railway?.rootDir ?? service.rootDir ?? defaultRootDir);
31
31
  const railwayEnvironment = service.environments?.[normalizedScope]?.railwayEnvironment ?? normalizedScope;
32
32
  const publicBaseUrl = service.environments?.[normalizedScope]?.baseUrl ?? service.publicBaseUrl ?? null;
@@ -19,7 +19,6 @@ export declare function resolveAstroBin(): string;
19
19
  export declare function resolveWranglerBin(): string;
20
20
  export declare const corePackageRoot: string;
21
21
  export declare const sdkPackageRoot: string;
22
- export declare const agentPackageRoot: string;
23
22
  export declare function loadPackageJson(root?: string): any;
24
23
  export declare function isWorkspaceRoot(root?: string): boolean;
25
24
  export declare function createProductionBuildEnv(extraEnv?: {}): {
@@ -51,7 +51,7 @@ const TREESEED_DEFAULT_PROVIDER_SELECTIONS = {
51
51
  site: "default"
52
52
  };
53
53
  const TRESEED_MANAGED_SERVICE_KEYS = ["api", "agents", "gateway", "manager", "worker", "workdayStart", "workdayReport"];
54
- const TRESEED_WORKSPACE_PACKAGE_DIRS = ["sdk", "core", "cli", "agent"];
54
+ const TRESEED_WORKSPACE_PACKAGE_DIRS = ["sdk", "core", "cli"];
55
55
  const CLOUDFLARE_ACCOUNT_ID_PLACEHOLDER = "replace-with-cloudflare-account-id";
56
56
  function parseServiceEnvironmentConfig(value) {
57
57
  const record = optionalRecord(value, "service environment") ?? {};
@@ -178,7 +178,6 @@ function resolveWranglerBin() {
178
178
  }
179
179
  const corePackageRoot = resolveTreeseedPackageRoot("@treeseed/core", "@treeseed/core/config", "core");
180
180
  const sdkPackageRoot = resolveTreeseedPackageRoot("@treeseed/sdk", "@treeseed/sdk", "sdk");
181
- const agentPackageRoot = resolveTreeseedPackageRoot("@treeseed/agent", "@treeseed/agent", "agent");
182
181
  function loadPackageJson(root = process.cwd()) {
183
182
  const packageJsonPath = resolve(root, "package.json");
184
183
  if (!existsSync(packageJsonPath)) {
@@ -372,7 +371,6 @@ function spawnNodeBinary(binPath, args, options = {}) {
372
371
  });
373
372
  }
374
373
  export {
375
- agentPackageRoot,
376
374
  corePackageRoot,
377
375
  createProductionBuildEnv,
378
376
  isWorkspaceRoot,
@@ -37,6 +37,7 @@ export interface TemplateProductDefinition extends SdkTemplateCatalogEntry {
37
37
  artifactRoot: string;
38
38
  artifactManifestPath: string;
39
39
  templateRoot: string;
40
+ fulfillmentMode: 'packaged' | 'git';
40
41
  }
41
42
  export interface ResolvedTemplateDefinition {
42
43
  product: TemplateProductDefinition;
@@ -82,6 +83,7 @@ export declare function serializeTemplateRegistryEntry(product: Pick<TemplatePro
82
83
  templateApiVersion: number;
83
84
  minCliVersion: string;
84
85
  minCoreVersion: string | undefined;
86
+ fulfillmentMode: "git" | "packaged";
85
87
  source: import("../../sdk-types.ts").SdkTemplateCatalogSource;
86
88
  };
87
89
  export declare function exportTemplateCatalogYaml(options?: TemplateCatalogOptions): Promise<string>;
@@ -1,4 +1,5 @@
1
- import { cpSync, existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
1
+ import { cpSync, existsSync, mkdirSync, readdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
2
+ import { spawnSync } from "node:child_process";
2
3
  import { basename, dirname, relative, resolve } from "node:path";
3
4
  import { RemoteTemplateCatalogClient } from "../../template-catalog.js";
4
5
  import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
@@ -53,10 +54,10 @@ function validateTemplateProductShape(product) {
53
54
  if (product.status !== "draft" && product.status !== "live" && product.status !== "archived") {
54
55
  throw new Error(`Template product ${product.id} uses unsupported status "${product.status}".`);
55
56
  }
56
- if (!existsSync(product.artifactManifestPath)) {
57
+ if (product.fulfillmentMode === "packaged" && !existsSync(product.artifactManifestPath)) {
57
58
  throw new Error(`Template product ${product.id} points to a missing artifact manifest: ${product.artifactManifestPath}`);
58
59
  }
59
- if (!existsSync(product.templateRoot)) {
60
+ if (product.fulfillmentMode === "packaged" && !existsSync(product.templateRoot)) {
60
61
  throw new Error(`Template product ${product.id} points to a missing template payload: ${product.templateRoot}`);
61
62
  }
62
63
  }
@@ -101,9 +102,55 @@ function normalizeTemplateProduct(remoteProduct) {
101
102
  contentPath: `${remoteProduct.fulfillment.source.repoUrl}#${remoteProduct.id}`,
102
103
  artifactRoot,
103
104
  artifactManifestPath: resolve(artifactRoot, "template.config.json"),
105
+ templateRoot: resolve(artifactRoot, "template"),
106
+ fulfillmentMode: remoteProduct.fulfillment.mode ?? "packaged"
107
+ };
108
+ }
109
+ function sanitizeCacheSegment(value) {
110
+ return value.replace(/[^A-Za-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "source";
111
+ }
112
+ function resolveTemplateSourceCacheRoot(product, options) {
113
+ const cachePath = resolveTreeseedTemplateCatalogCachePath(options.cwd ?? process.cwd());
114
+ return resolve(dirname(cachePath), "templates", sanitizeCacheSegment(product.id), sanitizeCacheSegment(product.fulfillment.source.ref));
115
+ }
116
+ function runGit(commandArgs, cwd) {
117
+ const result = spawnSync("git", commandArgs, {
118
+ cwd,
119
+ stdio: "pipe",
120
+ encoding: "utf8"
121
+ });
122
+ if (result.status !== 0) {
123
+ throw new Error(result.stderr?.trim() || result.stdout?.trim() || `git ${commandArgs.join(" ")} failed`);
124
+ }
125
+ }
126
+ function materializeGitTemplateSource(product, options) {
127
+ const cacheRoot = resolveTemplateSourceCacheRoot(product, options);
128
+ const repoRoot = resolve(cacheRoot, "repo");
129
+ const source = product.fulfillment.source;
130
+ if (!existsSync(resolve(repoRoot, ".git"))) {
131
+ rmSync(cacheRoot, { recursive: true, force: true });
132
+ mkdirSync(cacheRoot, { recursive: true });
133
+ runGit(["clone", "--no-checkout", source.repoUrl, repoRoot]);
134
+ }
135
+ runGit(["fetch", "--all", "--tags"], repoRoot);
136
+ runGit(["checkout", "--force", source.ref], repoRoot);
137
+ const artifactRoot = resolve(repoRoot, source.directory);
138
+ return {
139
+ artifactRoot,
140
+ manifestPath: resolve(artifactRoot, "template.config.json"),
104
141
  templateRoot: resolve(artifactRoot, "template")
105
142
  };
106
143
  }
144
+ function resolveTemplateDefinitionPaths(product, options) {
145
+ if (existsSync(product.artifactManifestPath) && existsSync(product.templateRoot)) {
146
+ return {
147
+ artifactRoot: product.artifactRoot,
148
+ manifestPath: product.artifactManifestPath,
149
+ templateRoot: product.templateRoot
150
+ };
151
+ }
152
+ return materializeGitTemplateSource(product, options);
153
+ }
107
154
  function readTemplateCatalogCache(cachePath) {
108
155
  if (!existsSync(cachePath)) {
109
156
  return null;
@@ -268,11 +315,12 @@ async function resolveTemplateDefinition(id, options = {}, category) {
268
315
  throw new Error(`Unable to resolve template "${id}" in category "${category}".`);
269
316
  }
270
317
  validateTemplateProductShape(product);
271
- const manifest = loadJsonFile(product.artifactManifestPath);
318
+ const resolvedPaths = resolveTemplateDefinitionPaths(product, options);
319
+ const manifest = loadJsonFile(resolvedPaths.manifestPath);
272
320
  const definition = {
273
321
  product,
274
- manifestPath: product.artifactManifestPath,
275
- templateRoot: product.templateRoot,
322
+ manifestPath: resolvedPaths.manifestPath,
323
+ templateRoot: resolvedPaths.templateRoot,
276
324
  manifest
277
325
  };
278
326
  validateTemplateManifest(definition);
@@ -387,6 +435,7 @@ function serializeTemplateRegistryEntry(product) {
387
435
  templateApiVersion: product.templateApiVersion,
388
436
  minCliVersion: product.minCliVersion,
389
437
  minCoreVersion: product.minCoreVersion,
438
+ fulfillmentMode: product.fulfillment.mode ?? "packaged",
390
439
  source: product.fulfillment.source
391
440
  };
392
441
  }
@@ -3,7 +3,7 @@ import { cpSync, existsSync, mkdirSync, mkdtempSync, readdirSync, readFileSync,
3
3
  import { tmpdir } from 'node:os';
4
4
  import { dirname, join, resolve } from 'node:path';
5
5
  import { spawnSync } from 'node:child_process';
6
- import { agentPackageRoot, corePackageRoot, packageRoot, packageScriptPath, sdkPackageRoot } from '../operations/services/runtime-tools.js';
6
+ import { corePackageRoot, packageRoot, packageScriptPath, sdkPackageRoot } from '../operations/services/runtime-tools.js';
7
7
  import { listTemplateProducts, validateTemplateProduct } from '../operations/services/template-registry.js';
8
8
  const npmCacheDir = process.env.TREESEED_SCAFFOLD_NPM_CACHE_DIR
9
9
  ? resolve(process.env.TREESEED_SCAFFOLD_NPM_CACHE_DIR)
@@ -11,7 +11,6 @@ const npmCacheDir = process.env.TREESEED_SCAFFOLD_NPM_CACHE_DIR
11
11
  const packageJson = JSON.parse(readFileSync(resolve(corePackageRoot, 'package.json'), 'utf8'));
12
12
  const sdkPackageJson = JSON.parse(readFileSync(resolve(sdkPackageRoot, 'package.json'), 'utf8'));
13
13
  const cliPackageJson = JSON.parse(readFileSync(resolve(packageRoot, 'package.json'), 'utf8'));
14
- const agentPackageJson = JSON.parse(readFileSync(resolve(agentPackageRoot, 'package.json'), 'utf8'));
15
14
  const workspaceTarballs = (() => {
16
15
  try {
17
16
  return JSON.parse(process.env.TREESEED_WORKSPACE_TARBALLS ?? '{}');
@@ -35,12 +34,7 @@ const externalCliTarball = process.env.TREESEED_SCAFFOLD_CLI_TARBALL
35
34
  : typeof workspaceTarballs['@treeseed/cli'] === 'string'
36
35
  ? resolve(workspaceTarballs['@treeseed/cli'])
37
36
  : null;
38
- const externalAgentTarball = process.env.TREESEED_SCAFFOLD_AGENT_TARBALL
39
- ? resolve(process.env.TREESEED_SCAFFOLD_AGENT_TARBALL)
40
- : typeof workspaceTarballs['@treeseed/agent'] === 'string'
41
- ? resolve(workspaceTarballs['@treeseed/agent'])
42
- : null;
43
- const reusesExternalTarballs = Boolean(externalCoreTarball || externalSdkTarball || externalCliTarball || externalAgentTarball);
37
+ const reusesExternalTarballs = Boolean(externalCoreTarball || externalSdkTarball || externalCliTarball);
44
38
  const scaffoldChecks = new Set((process.env.TREESEED_SCAFFOLD_CHECKS ?? 'build,deploy')
45
39
  .split(',')
46
40
  .map((value) => value.trim())
@@ -177,7 +171,7 @@ function linkTreeseedBins(siteRoot) {
177
171
  mkdirSync(binRoot, { recursive: true });
178
172
  for (const [name, relativeTarget] of [
179
173
  ['treeseed', '../@treeseed/cli/dist/cli/main.js'],
180
- ['treeseed-agents', '../@treeseed/agent/dist/scripts/treeseed-agents.js'],
174
+ ['treeseed-agents', '../@treeseed/core/dist/agents/cli.js'],
181
175
  ]) {
182
176
  symlinkSync(relativeTarget, resolve(binRoot, name));
183
177
  }
@@ -210,12 +204,11 @@ async function scaffoldSite(siteRoot) {
210
204
  }
211
205
  runStep(process.execPath, [packageScriptPath('scaffold-site'), siteRoot, '--template', 'starter-basic', '--name', 'Smoke Site', '--site-url', 'https://smoke.example.com', '--contact-email', 'hello@example.com']);
212
206
  }
213
- function installScaffold(siteRoot, { coreTarballPath, sdkTarballPath, cliTarballPath, agentTarballPath }) {
214
- if (coreTarballPath && sdkTarballPath && cliTarballPath && agentTarballPath) {
207
+ function installScaffold(siteRoot, { coreTarballPath, sdkTarballPath, cliTarballPath }) {
208
+ if (coreTarballPath && sdkTarballPath && cliTarballPath) {
215
209
  linkWorkspacePackage(siteRoot, sdkPackageJson.name, sdkPackageRoot);
216
210
  linkWorkspacePackage(siteRoot, packageJson.name, corePackageRoot);
217
211
  linkWorkspacePackage(siteRoot, cliPackageJson.name, packageRoot);
218
- linkWorkspacePackage(siteRoot, agentPackageJson.name, agentPackageRoot);
219
212
  mirrorSharedNodeModules(siteRoot);
220
213
  linkTreeseedBins(siteRoot);
221
214
  return;
@@ -247,7 +240,6 @@ const siteRoot = createTempSiteRoot();
247
240
  let tarballPath = externalCoreTarball;
248
241
  let sdkTarballPath = externalSdkTarball;
249
242
  let cliTarballPath = externalCliTarball;
250
- let agentTarballPath = externalAgentTarball;
251
243
  try {
252
244
  if (!reusesExternalTarballs && resetScaffoldCache) {
253
245
  logStep(`resetting npm cache at ${npmCacheDir}`);
@@ -267,13 +259,6 @@ try {
267
259
  else {
268
260
  logStep(`reusing provided @treeseed/core tarball: ${tarballPath}`);
269
261
  }
270
- if (!agentTarballPath) {
271
- logStep('building and packing @treeseed/agent');
272
- agentTarballPath = createTarball(agentPackageRoot, agentPackageJson);
273
- }
274
- else {
275
- logStep(`reusing provided @treeseed/agent tarball: ${agentTarballPath}`);
276
- }
277
262
  if (!cliTarballPath) {
278
263
  logStep('building and packing @treeseed/cli');
279
264
  cliTarballPath = createTarball(packageRoot, cliPackageJson);
@@ -292,7 +277,6 @@ try {
292
277
  coreTarballPath: tarballPath,
293
278
  sdkTarballPath,
294
279
  cliTarballPath,
295
- agentTarballPath,
296
280
  });
297
281
  });
298
282
  logStep('running scaffold smoke checks');
@@ -3,7 +3,7 @@ import { mkdtempSync } from 'node:fs';
3
3
  import { tmpdir } from 'node:os';
4
4
  import { dirname, extname, join, resolve } from 'node:path';
5
5
  import { spawnSync } from 'node:child_process';
6
- import { agentPackageRoot, corePackageRoot, packageRoot, sdkPackageRoot } from '../operations/services/runtime-tools.js';
6
+ import { corePackageRoot, packageRoot, sdkPackageRoot } from '../operations/services/runtime-tools.js';
7
7
  const textExtensions = new Set(['.js', '.ts', '.mjs', '.cjs', '.d.js', '.json', '.md']);
8
8
  const forbiddenPatterns = [
9
9
  /['"`]workspace:[^'"`\n]+['"`]/,
@@ -108,11 +108,11 @@ function hasWorkspacePackageSource(root) {
108
108
  run('npm', ['run', 'build']);
109
109
  scanDirectory(resolve(packageRoot, 'dist'));
110
110
  run('npm', ['test']);
111
- if (hasWorkspacePackageSource(sdkPackageRoot) && hasWorkspacePackageSource(corePackageRoot) && hasWorkspacePackageSource(agentPackageRoot)) {
111
+ if (hasWorkspacePackageSource(sdkPackageRoot) && hasWorkspacePackageSource(corePackageRoot)) {
112
112
  run('npm', ['run', 'test:scaffold']);
113
113
  }
114
114
  else {
115
- console.log('Skipping scaffold verification because local sdk/core/agent package sources are not available.');
115
+ console.log('Skipping scaffold verification because local sdk/core package sources are not available.');
116
116
  }
117
117
  const stageRoot = mkdtempSync(join(tmpdir(), 'treeseed-cli-release-'));
118
118
  const extractRoot = resolve(stageRoot, 'extract');
@@ -777,6 +777,7 @@ export interface SdkTemplateCatalogEntry {
777
777
  minCliVersion: string;
778
778
  minCoreVersion?: string;
779
779
  fulfillment: {
780
+ mode?: 'packaged' | 'git';
780
781
  source: SdkTemplateCatalogSource;
781
782
  hooksPolicy: 'builtin_only' | 'trusted_only' | 'disabled';
782
783
  supportsReconcile: boolean;
@@ -66,6 +66,7 @@ function normalizeTemplateCatalogEntry(value) {
66
66
  minCliVersion: expectString(record.minCliVersion, "minCliVersion"),
67
67
  minCoreVersion: optionalString(record.minCoreVersion),
68
68
  fulfillment: {
69
+ mode: optionalString(fulfillment.mode),
69
70
  source: {
70
71
  kind: "git",
71
72
  repoUrl: expectString(source.repoUrl, "fulfillment.source.repoUrl"),