@treeseed/sdk 0.1.2 → 0.3.1
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/README.md +97 -506
- package/dist/{src/cli-tools.d.ts → cli-tools.d.ts} +1 -1
- package/dist/cli-tools.js +5 -3
- package/dist/{src/content-store.d.ts → content-store.d.ts} +3 -2
- package/dist/content-store.js +52 -20
- package/dist/{src/d1-store.d.ts → d1-store.d.ts} +62 -1
- package/dist/d1-store.js +625 -65
- package/dist/field-aliases.d.ts +11 -0
- package/dist/field-aliases.js +41 -0
- package/dist/graph/build.d.ts +19 -0
- package/dist/graph/build.js +949 -0
- package/dist/graph/dsl.d.ts +2 -0
- package/dist/graph/dsl.js +243 -0
- package/dist/graph/query.d.ts +47 -0
- package/dist/graph/query.js +447 -0
- package/dist/graph/ranking.d.ts +3 -0
- package/dist/graph/ranking.js +483 -0
- package/dist/graph/schema.d.ts +142 -0
- package/dist/graph/schema.js +133 -0
- package/dist/graph.d.ts +52 -0
- package/dist/graph.js +133 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.js +91 -2
- package/dist/model-registry.d.ts +8 -0
- package/dist/model-registry.js +351 -25
- package/dist/operations/providers/default.d.ts +10 -0
- package/dist/operations/providers/default.js +514 -0
- package/dist/operations/runtime.d.ts +7 -0
- package/dist/operations/runtime.js +60 -0
- package/dist/operations/services/config-runtime.d.ts +269 -0
- package/dist/operations/services/config-runtime.js +1397 -0
- package/dist/operations/services/d1-migration.d.ts +6 -0
- package/dist/operations/services/d1-migration.js +89 -0
- package/dist/operations/services/deploy.d.ts +371 -0
- package/dist/operations/services/deploy.js +981 -0
- package/dist/operations/services/git-workflow.d.ts +49 -0
- package/dist/operations/services/git-workflow.js +218 -0
- package/dist/operations/services/github-automation.d.ts +156 -0
- package/dist/operations/services/github-automation.js +256 -0
- package/dist/operations/services/local-dev.d.ts +9 -0
- package/dist/operations/services/local-dev.js +106 -0
- package/dist/operations/services/mailpit-runtime.d.ts +4 -0
- package/dist/operations/services/mailpit-runtime.js +59 -0
- package/dist/operations/services/railway-deploy.d.ts +53 -0
- package/dist/operations/services/railway-deploy.js +123 -0
- package/dist/operations/services/runtime-paths.d.ts +19 -0
- package/dist/operations/services/runtime-paths.js +54 -0
- package/dist/operations/services/runtime-tools.d.ts +117 -0
- package/dist/operations/services/runtime-tools.js +358 -0
- package/dist/operations/services/save-deploy-preflight.d.ts +34 -0
- package/dist/operations/services/save-deploy-preflight.js +76 -0
- package/dist/operations/services/template-registry.d.ts +88 -0
- package/dist/operations/services/template-registry.js +407 -0
- package/dist/operations/services/watch-dev.d.ts +21 -0
- package/dist/operations/services/watch-dev.js +284 -0
- package/dist/operations/services/workspace-preflight.d.ts +40 -0
- package/dist/operations/services/workspace-preflight.js +165 -0
- package/dist/operations/services/workspace-save.d.ts +42 -0
- package/dist/operations/services/workspace-save.js +235 -0
- package/dist/operations/services/workspace-tools.d.ts +16 -0
- package/dist/operations/services/workspace-tools.js +270 -0
- package/dist/operations-registry.d.ts +5 -0
- package/dist/operations-registry.js +68 -0
- package/dist/operations-types.d.ts +71 -0
- package/dist/operations-types.js +17 -0
- package/dist/operations.d.ts +6 -0
- package/dist/operations.js +16 -0
- package/dist/platform/books-data.d.ts +1 -0
- package/dist/platform/books-data.js +1 -0
- package/dist/platform/contracts.d.ts +158 -0
- package/dist/platform/contracts.js +0 -0
- package/dist/platform/deploy/config.d.ts +4 -0
- package/dist/platform/deploy/config.js +222 -0
- package/dist/platform/deploy-config.d.ts +1 -0
- package/dist/platform/deploy-config.js +1 -0
- package/dist/platform/deploy-runtime.d.ts +18 -0
- package/dist/platform/deploy-runtime.js +78 -0
- package/dist/platform/env.yaml +394 -0
- package/dist/platform/environment.d.ts +130 -0
- package/dist/platform/environment.js +331 -0
- package/dist/platform/plugin.d.ts +2 -0
- package/dist/platform/plugin.js +4 -0
- package/dist/platform/plugins/constants.d.ts +22 -0
- package/dist/platform/plugins/constants.js +29 -0
- package/dist/platform/plugins/plugin.d.ts +51 -0
- package/dist/platform/plugins/plugin.js +6 -0
- package/dist/platform/plugins/runtime.d.ts +35 -0
- package/dist/platform/plugins/runtime.js +161 -0
- package/dist/platform/plugins.d.ts +6 -0
- package/dist/platform/plugins.js +38 -0
- package/dist/platform/site-config-schema.js +1 -0
- package/dist/platform/tenant/config.d.ts +9 -0
- package/dist/platform/tenant/config.js +154 -0
- package/dist/platform/tenant/runtime-config.d.ts +4 -0
- package/dist/platform/tenant/runtime-config.js +20 -0
- package/dist/platform/tenant-config.d.ts +1 -0
- package/dist/platform/tenant-config.js +1 -0
- package/dist/platform/utils/books-data.d.ts +29 -0
- package/dist/platform/utils/books-data.js +82 -0
- package/dist/platform/utils/site-config-schema.js +321 -0
- package/dist/remote.d.ts +175 -0
- package/dist/remote.js +202 -0
- package/dist/runtime.js +35 -22
- package/dist/scripts/aggregate-book.js +121 -0
- package/dist/scripts/build-dist.js +54 -13
- package/dist/scripts/build-tenant-worker.js +36 -0
- package/dist/scripts/cleanup-markdown.js +373 -0
- package/dist/scripts/cli-test-fixtures.js +48 -0
- package/dist/scripts/config-treeseed.js +95 -0
- package/dist/scripts/ensure-mailpit.js +29 -0
- package/dist/scripts/local-dev.js +129 -0
- package/dist/scripts/logs-mailpit.js +2 -0
- package/dist/scripts/patch-starlight-content-path.js +172 -0
- package/dist/scripts/release-verify.js +34 -6
- package/dist/scripts/run-fixture-astro-command.js +18 -0
- package/dist/scripts/scaffold-site.js +65 -0
- package/dist/scripts/stop-mailpit.js +5 -0
- package/dist/scripts/sync-dev-vars.js +6 -0
- package/dist/scripts/sync-template.js +20 -0
- package/dist/scripts/template-catalog.test.js +100 -0
- package/dist/scripts/template-command.js +31 -0
- package/dist/scripts/tenant-astro-command.js +3 -0
- package/dist/scripts/tenant-build.js +16 -0
- package/dist/scripts/tenant-check.js +7 -0
- package/dist/scripts/tenant-d1-migrate-local.js +11 -0
- package/dist/scripts/tenant-deploy.js +180 -0
- package/dist/scripts/tenant-destroy.js +104 -0
- package/dist/scripts/tenant-dev.js +171 -0
- package/dist/scripts/tenant-lint.js +4 -0
- package/dist/scripts/tenant-test.js +4 -0
- package/dist/scripts/test-cloudflare-local.js +212 -0
- package/dist/scripts/test-scaffold.js +314 -0
- package/dist/scripts/test-smoke.js +71 -13
- package/dist/scripts/treeseed-assert-release-tag-version.js +21 -0
- package/dist/scripts/treeseed-build-dist.js +134 -0
- package/dist/scripts/treeseed-publish-package.js +19 -0
- package/dist/scripts/treeseed-release-verify.js +131 -0
- package/dist/scripts/treeseed-run-ts.js +45 -0
- package/dist/scripts/validate-templates.js +6 -0
- package/dist/scripts/verify-driver.js +29 -0
- package/dist/scripts/workflow-commands.test.js +39 -0
- package/dist/scripts/workspace-close.js +24 -0
- package/dist/scripts/workspace-command-e2e.js +718 -0
- package/dist/scripts/workspace-lint.js +9 -0
- package/dist/scripts/workspace-preflight.js +22 -0
- package/dist/scripts/workspace-publish-changed-packages.js +16 -0
- package/dist/scripts/workspace-release-verify.js +81 -0
- package/dist/scripts/workspace-release.js +42 -0
- package/dist/scripts/workspace-save.js +124 -0
- package/dist/scripts/workspace-start-warning.js +3 -0
- package/dist/scripts/workspace-start.js +71 -0
- package/dist/scripts/workspace-test-unit.js +4 -0
- package/dist/scripts/workspace-test.js +11 -0
- package/dist/sdk-fields.d.ts +11 -0
- package/dist/sdk-fields.js +169 -0
- package/dist/sdk-filters.d.ts +4 -0
- package/dist/sdk-filters.js +12 -15
- package/dist/sdk-types.d.ts +796 -0
- package/dist/sdk-types.js +7 -1
- package/dist/sdk-version.d.ts +2 -0
- package/dist/sdk-version.js +42 -0
- package/dist/sdk.d.ts +215 -0
- package/dist/sdk.js +235 -11
- package/dist/stores/cursor-store.js +9 -3
- package/dist/stores/lease-store.js +8 -2
- package/dist/{src/stores → stores}/message-store.d.ts +1 -1
- package/dist/stores/message-store.js +27 -3
- package/dist/stores/operational-store.d.ts +24 -0
- package/dist/stores/operational-store.js +279 -0
- package/dist/stores/run-store.js +8 -1
- package/dist/stores/subscription-store.js +7 -5
- package/dist/template-catalog.d.ts +13 -0
- package/dist/template-catalog.js +141 -0
- package/dist/treeseed/services/compose.yml +7 -0
- package/dist/treeseed/template-catalog/catalog.fixture.json +55 -0
- package/dist/treeseed/template-catalog/templates/starter-basic/template/astro.config.d.ts +2 -0
- package/dist/treeseed/template-catalog/templates/starter-basic/template/astro.config.ts +3 -0
- package/dist/treeseed/template-catalog/templates/starter-basic/template/package.json +32 -0
- package/dist/treeseed/template-catalog/templates/starter-basic/template/src/config.yaml +40 -0
- package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content/empty/.gitkeep +1 -0
- package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content/knowledge/handbook/index.mdx +11 -0
- package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content/pages/welcome.mdx +11 -0
- package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content.config.d.ts +1 -0
- package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content.config.ts +3 -0
- package/dist/treeseed/template-catalog/templates/starter-basic/template/src/env.yaml +1 -0
- package/dist/treeseed/template-catalog/templates/starter-basic/template/src/manifest.yaml +19 -0
- package/dist/treeseed/template-catalog/templates/starter-basic/template/treeseed.site.yaml +26 -0
- package/dist/treeseed/template-catalog/templates/starter-basic/template/tsconfig.json +9 -0
- package/dist/treeseed/template-catalog/templates/starter-basic/template.config.json +90 -0
- package/dist/utils/agents/contracts/messages.d.ts +88 -0
- package/dist/utils/agents/contracts/messages.js +138 -0
- package/dist/utils/agents/contracts/run.d.ts +20 -0
- package/dist/utils/agents/contracts/run.js +0 -0
- package/dist/utils/agents/runtime-types.d.ts +117 -0
- package/dist/utils/agents/runtime-types.js +4 -0
- package/dist/verification.d.ts +20 -0
- package/dist/verification.js +98 -0
- package/dist/workflow/operations.d.ts +396 -0
- package/dist/workflow/operations.js +841 -0
- package/dist/workflow-state.d.ts +56 -0
- package/dist/workflow-state.js +195 -0
- package/dist/workflow-support.d.ts +9 -0
- package/dist/workflow-support.js +176 -0
- package/dist/workflow.d.ts +111 -0
- package/dist/workflow.js +97 -0
- package/package.json +111 -5
- package/scripts/verify-driver.mjs +29 -0
- package/dist/scripts/.ts-run-1775630384291-crtqr3izsa.js +0 -22
- package/dist/scripts/.ts-run-1775630388025-vnjle0z75a.js +0 -129
- package/dist/scripts/assert-release-tag-version.d.ts +0 -1
- package/dist/scripts/build-dist.d.ts +0 -1
- package/dist/scripts/fixture-tools.d.ts +0 -5
- package/dist/scripts/package-tools.d.ts +0 -15
- package/dist/scripts/publish-package.d.ts +0 -1
- package/dist/scripts/release-verify.d.ts +0 -1
- package/dist/scripts/test-smoke.d.ts +0 -1
- package/dist/src/index.d.ts +0 -6
- package/dist/src/model-registry.d.ts +0 -4
- package/dist/src/sdk-filters.d.ts +0 -4
- package/dist/src/sdk-types.d.ts +0 -285
- package/dist/src/sdk.d.ts +0 -109
- package/dist/test/test-fixture.d.ts +0 -1
- package/dist/test/utils/envelopes.test.d.ts +0 -1
- package/dist/test/utils/sdk.test.d.ts +0 -1
- package/dist/vitest.config.d.ts +0 -2
- /package/dist/{src/frontmatter.d.ts → frontmatter.d.ts} +0 -0
- /package/dist/{src/git-runtime.d.ts → git-runtime.d.ts} +0 -0
- /package/dist/{src/runtime.d.ts → runtime.d.ts} +0 -0
- /package/dist/{src/stores → stores}/cursor-store.d.ts +0 -0
- /package/dist/{src/stores → stores}/envelopes.d.ts +0 -0
- /package/dist/{src/stores → stores}/helpers.d.ts +0 -0
- /package/dist/{src/stores → stores}/lease-store.d.ts +0 -0
- /package/dist/{src/stores → stores}/run-store.d.ts +0 -0
- /package/dist/{src/stores → stores}/subscription-store.d.ts +0 -0
- /package/dist/{src/types → types}/agents.d.ts +0 -0
- /package/dist/{src/types → types}/cloudflare.d.ts +0 -0
- /package/dist/{src/wrangler-d1.d.ts → wrangler-d1.d.ts} +0 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
import { dockerIsAvailable, findRunningMailpitContainer } from '../operations/services/mailpit-runtime.js';
|
|
3
|
+
import { mailpitComposeFile, packageRoot } from '../operations/services/runtime-paths.js';
|
|
4
|
+
if (!dockerIsAvailable()) {
|
|
5
|
+
console.error('Docker is required for Treeseed form email testing. Start Docker and rerun the Mailpit command.');
|
|
6
|
+
process.exit(1);
|
|
7
|
+
}
|
|
8
|
+
const existingMailpit = findRunningMailpitContainer();
|
|
9
|
+
if (existingMailpit) {
|
|
10
|
+
console.log(`Reusing existing Mailpit container "${existingMailpit.name}" on ports 1025 and 8025.`);
|
|
11
|
+
process.exit(0);
|
|
12
|
+
}
|
|
13
|
+
const result = spawnSync('docker', ['compose', '-f', mailpitComposeFile, 'up', '-d', 'mailpit'], {
|
|
14
|
+
encoding: 'utf8',
|
|
15
|
+
cwd: packageRoot,
|
|
16
|
+
env: { ...process.env },
|
|
17
|
+
});
|
|
18
|
+
if (result.status !== 0) {
|
|
19
|
+
const reusedMailpit = findRunningMailpitContainer();
|
|
20
|
+
if (reusedMailpit) {
|
|
21
|
+
console.log(`Reusing existing Mailpit container "${reusedMailpit.name}" on ports 1025 and 8025.`);
|
|
22
|
+
process.exit(0);
|
|
23
|
+
}
|
|
24
|
+
if (result.stdout)
|
|
25
|
+
process.stdout.write(result.stdout);
|
|
26
|
+
if (result.stderr)
|
|
27
|
+
process.stderr.write(result.stderr);
|
|
28
|
+
}
|
|
29
|
+
process.exit(result.status ?? 1);
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
import { corePackageRoot } from '../operations/services/runtime-tools.js';
|
|
3
|
+
import { fixtureRoot } from '../operations/services/runtime-paths.js';
|
|
4
|
+
import { prepareCloudflareLocalRuntime, startWranglerDev } from '../operations/services/local-dev.js';
|
|
5
|
+
import { clearStagedBuildOutput, createWatchBuildPaths, createTenantWatchEntries, startPollingWatch, stopManagedProcess, swapStagedBuildOutput, writeDevReloadStamp, workspaceSdkRoot, } from '../operations/services/watch-dev.js';
|
|
6
|
+
const cliArgs = process.argv.slice(2);
|
|
7
|
+
const watchMode = cliArgs.includes('--watch');
|
|
8
|
+
const wranglerArgs = cliArgs.filter((arg) => arg !== '--watch');
|
|
9
|
+
let wranglerChild = null;
|
|
10
|
+
let stopWatching = null;
|
|
11
|
+
let isStoppingForRebuild = false;
|
|
12
|
+
let shuttingDown = false;
|
|
13
|
+
function runStep(command, args, { cwd = corePackageRoot, env = {}, fatal = true } = {}) {
|
|
14
|
+
const result = spawnSync(command, args, {
|
|
15
|
+
stdio: 'inherit',
|
|
16
|
+
cwd,
|
|
17
|
+
env: { ...process.env, ...env },
|
|
18
|
+
});
|
|
19
|
+
if (result.status !== 0 && fatal) {
|
|
20
|
+
process.exit(result.status ?? 1);
|
|
21
|
+
}
|
|
22
|
+
return result.status === 0;
|
|
23
|
+
}
|
|
24
|
+
function runFixtureBuildCycle({ includePackageBuild = false, includeSdkBuild = false, fatal = true, stagedOutput = false } = {}) {
|
|
25
|
+
if (includeSdkBuild) {
|
|
26
|
+
const sdkRoot = workspaceSdkRoot();
|
|
27
|
+
if (sdkRoot) {
|
|
28
|
+
const built = runStep('npm', ['run', 'build:dist'], { cwd: sdkRoot, fatal });
|
|
29
|
+
if (!built) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
if (includePackageBuild) {
|
|
35
|
+
const built = runStep('npm', ['run', 'build:dist'], { cwd: corePackageRoot, fatal });
|
|
36
|
+
if (!built) {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
if (watchMode) {
|
|
41
|
+
writeDevReloadStamp(fixtureRoot);
|
|
42
|
+
}
|
|
43
|
+
try {
|
|
44
|
+
const outDir = stagedOutput ? createWatchBuildPaths(fixtureRoot).stagedDistRoot : undefined;
|
|
45
|
+
if (stagedOutput) {
|
|
46
|
+
clearStagedBuildOutput(fixtureRoot);
|
|
47
|
+
}
|
|
48
|
+
prepareCloudflareLocalRuntime({
|
|
49
|
+
envOverrides: watchMode ? { TREESEED_PUBLIC_DEV_WATCH_RELOAD: 'true' } : {},
|
|
50
|
+
outDir,
|
|
51
|
+
});
|
|
52
|
+
if (stagedOutput) {
|
|
53
|
+
swapStagedBuildOutput(fixtureRoot);
|
|
54
|
+
}
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
if (fatal) {
|
|
59
|
+
throw error;
|
|
60
|
+
}
|
|
61
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function startWrangler() {
|
|
66
|
+
const child = startWranglerDev(wranglerArgs, {
|
|
67
|
+
env: watchMode ? { TREESEED_PUBLIC_DEV_WATCH_RELOAD: 'true' } : {},
|
|
68
|
+
detached: process.platform !== 'win32',
|
|
69
|
+
});
|
|
70
|
+
wranglerChild = child;
|
|
71
|
+
child.on('exit', (code, signal) => {
|
|
72
|
+
if (child !== wranglerChild) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
wranglerChild = null;
|
|
76
|
+
if (isStoppingForRebuild || shuttingDown) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
if (stopWatching) {
|
|
80
|
+
stopWatching();
|
|
81
|
+
}
|
|
82
|
+
if (signal) {
|
|
83
|
+
process.kill(process.pid, signal);
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
process.exit(code ?? 0);
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
async function shutdownAndExit(code = 0) {
|
|
90
|
+
shuttingDown = true;
|
|
91
|
+
if (stopWatching) {
|
|
92
|
+
stopWatching();
|
|
93
|
+
}
|
|
94
|
+
await stopManagedProcess(wranglerChild);
|
|
95
|
+
process.exit(code);
|
|
96
|
+
}
|
|
97
|
+
process.on('SIGINT', () => {
|
|
98
|
+
void shutdownAndExit(130);
|
|
99
|
+
});
|
|
100
|
+
process.on('SIGTERM', () => {
|
|
101
|
+
void shutdownAndExit(143);
|
|
102
|
+
});
|
|
103
|
+
runFixtureBuildCycle({ includeSdkBuild: true, includePackageBuild: true, fatal: true });
|
|
104
|
+
startWrangler();
|
|
105
|
+
if (watchMode) {
|
|
106
|
+
console.log('Starting fixture watch mode. Changes will rebuild the package fixture and refresh the browser.');
|
|
107
|
+
stopWatching = startPollingWatch({
|
|
108
|
+
watchEntries: createTenantWatchEntries(fixtureRoot),
|
|
109
|
+
onChange: async ({ changedPaths, packageChanged, sdkChanged }) => {
|
|
110
|
+
console.log(`Detected ${changedPaths.length} change${changedPaths.length === 1 ? '' : 's'}; rebuilding ${sdkChanged ? 'sdk, core, and fixture' : packageChanged ? 'core and fixture' : 'fixture'} output...`);
|
|
111
|
+
isStoppingForRebuild = true;
|
|
112
|
+
await stopManagedProcess(wranglerChild);
|
|
113
|
+
isStoppingForRebuild = false;
|
|
114
|
+
const ok = runFixtureBuildCycle({
|
|
115
|
+
includeSdkBuild: sdkChanged,
|
|
116
|
+
includePackageBuild: packageChanged || sdkChanged,
|
|
117
|
+
fatal: false,
|
|
118
|
+
stagedOutput: false,
|
|
119
|
+
});
|
|
120
|
+
if (ok) {
|
|
121
|
+
startWrangler();
|
|
122
|
+
console.log('Rebuild complete. Wrangler restarted with the updated fixture output.');
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
console.error('Rebuild failed. Wrangler remains stopped until the next successful save.');
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
});
|
|
129
|
+
}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import process from 'node:process';
|
|
4
|
+
import { packageRoot } from '../operations/services/runtime-paths.js';
|
|
5
|
+
const legacyDocsRoot = path.resolve(packageRoot, '../..');
|
|
6
|
+
const candidateStarlightRoots = [
|
|
7
|
+
path.join(process.cwd(), 'node_modules/@astrojs/starlight'),
|
|
8
|
+
path.join(packageRoot, 'node_modules/@astrojs/starlight'),
|
|
9
|
+
path.join(legacyDocsRoot, 'node_modules/@astrojs/starlight'),
|
|
10
|
+
];
|
|
11
|
+
const candidateCollectionFiles = [
|
|
12
|
+
path.join(process.cwd(), 'node_modules/@astrojs/starlight/utils/collection.ts'),
|
|
13
|
+
path.join(packageRoot, 'node_modules/@astrojs/starlight/utils/collection.ts'),
|
|
14
|
+
path.join(legacyDocsRoot, 'node_modules/@astrojs/starlight/utils/collection.ts'),
|
|
15
|
+
];
|
|
16
|
+
const originalSource = `export type StarlightCollection = 'docs' | 'i18n';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* We still rely on the content collection folder structure to be fixed for now:
|
|
20
|
+
*
|
|
21
|
+
* - At build time, if the feature is enabled, we get all the last commit dates for each file in
|
|
22
|
+
* the docs folder ahead of time. In the current approach, we cannot know at this time the
|
|
23
|
+
* user-defined content folder path in the integration context as this would only be available
|
|
24
|
+
* from the loader. A potential solution could be to do that from a custom loader re-implementing
|
|
25
|
+
* the glob loader or built on top of it. Although, we don't have access to the Starlight
|
|
26
|
+
* configuration from the loader to even know we should do that.
|
|
27
|
+
* - Remark plugins get passed down an absolute path to a content file and we need to figure out
|
|
28
|
+
* the language from that path. Without knowing the content folder path, we cannot reliably do
|
|
29
|
+
* so.
|
|
30
|
+
*
|
|
31
|
+
* Below are various functions to easily get paths to these collections and avoid having to
|
|
32
|
+
* hardcode them throughout the codebase. When user-defined content folder locations are supported,
|
|
33
|
+
* these helper functions should be updated to reflect that in one place.
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
export function getCollectionUrl(collection: StarlightCollection, srcDir: URL) {
|
|
37
|
+
\treturn new URL(\`content/\${collection}/\`, srcDir);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function getCollectionPathFromRoot(
|
|
41
|
+
\tcollection: StarlightCollection,
|
|
42
|
+
\t{ root, srcDir }: { root: URL | string; srcDir: URL | string }
|
|
43
|
+
) {
|
|
44
|
+
\treturn (
|
|
45
|
+
\t\t(typeof srcDir === 'string' ? srcDir : srcDir.pathname).replace(
|
|
46
|
+
\t\t\ttypeof root === 'string' ? root : root.pathname,
|
|
47
|
+
\t\t\t''
|
|
48
|
+
\t\t) +
|
|
49
|
+
\t\t'content/' +
|
|
50
|
+
\t\tcollection
|
|
51
|
+
\t);
|
|
52
|
+
}
|
|
53
|
+
`;
|
|
54
|
+
const patchedSource = `export type StarlightCollection = 'docs' | 'i18n';
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* We still rely on the content collection folder structure to be fixed for now:
|
|
58
|
+
*
|
|
59
|
+
* - At build time, if the feature is enabled, we get all the last commit dates for each file in
|
|
60
|
+
* the docs folder ahead of time. In the current approach, we cannot know at this time the
|
|
61
|
+
* user-defined content folder path in the integration context as this would only be available
|
|
62
|
+
* from the loader. A potential solution could be to do that from a custom loader re-implementing
|
|
63
|
+
* the glob loader or built on top of it. Although, we don't have access to the Starlight
|
|
64
|
+
* configuration from the loader to even know we should do that.
|
|
65
|
+
* - Remark plugins get passed down an absolute path to a content file and we need to figure out
|
|
66
|
+
* the language from that path. Without knowing the content folder path, we cannot reliably do
|
|
67
|
+
* so.
|
|
68
|
+
*
|
|
69
|
+
* Below are various functions to easily get paths to these collections and avoid having to
|
|
70
|
+
* hardcode them throughout the codebase. When user-defined content folder locations are supported,
|
|
71
|
+
* these helper functions should be updated to reflect that in one place.
|
|
72
|
+
*/
|
|
73
|
+
|
|
74
|
+
export function getCollectionUrl(collection: StarlightCollection, srcDir: URL) {
|
|
75
|
+
\treturn new URL(\`content/\${getCollectionDir(collection)}/\`, srcDir);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function getCollectionDir(collection: StarlightCollection) {
|
|
79
|
+
\treturn collection === 'docs' ? 'knowledge' : collection;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function getCollectionPathFromRoot(
|
|
83
|
+
\tcollection: StarlightCollection,
|
|
84
|
+
\t{ root, srcDir }: { root: URL | string; srcDir: URL | string }
|
|
85
|
+
) {
|
|
86
|
+
\treturn (
|
|
87
|
+
\t\t(typeof srcDir === 'string' ? srcDir : srcDir.pathname).replace(
|
|
88
|
+
\t\t\ttypeof root === 'string' ? root : root.pathname,
|
|
89
|
+
\t\t\t''
|
|
90
|
+
\t\t) +
|
|
91
|
+
\t\t'content/' +
|
|
92
|
+
\t\tgetCollectionDir(collection)
|
|
93
|
+
\t);
|
|
94
|
+
}
|
|
95
|
+
`;
|
|
96
|
+
async function patchCollectionFile(collectionFile) {
|
|
97
|
+
const source = await fs.readFile(collectionFile, 'utf8');
|
|
98
|
+
if (source === patchedSource) {
|
|
99
|
+
return 'already';
|
|
100
|
+
}
|
|
101
|
+
if (source !== originalSource) {
|
|
102
|
+
throw new Error(`Unexpected Starlight collection helper format in ${collectionFile}`);
|
|
103
|
+
}
|
|
104
|
+
await fs.writeFile(collectionFile, patchedSource);
|
|
105
|
+
return 'patched';
|
|
106
|
+
}
|
|
107
|
+
async function copyVendoredTree(sourceRoot, targetRoot) {
|
|
108
|
+
const entries = await fs.readdir(sourceRoot, { withFileTypes: true });
|
|
109
|
+
for (const entry of entries) {
|
|
110
|
+
const sourcePath = path.join(sourceRoot, entry.name);
|
|
111
|
+
const targetPath = path.join(targetRoot, entry.name);
|
|
112
|
+
if (entry.isDirectory()) {
|
|
113
|
+
await fs.mkdir(targetPath, { recursive: true });
|
|
114
|
+
await copyVendoredTree(sourcePath, targetPath);
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
await fs.copyFile(sourcePath, targetPath);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
async function patchStarlightPackageRoot(starlightRoot) {
|
|
121
|
+
const packageJsonPath = path.join(starlightRoot, 'package.json');
|
|
122
|
+
const packageJson = JSON.parse(await fs.readFile(packageJsonPath, 'utf8'));
|
|
123
|
+
const coreVendorRoot = path.join(path.dirname(path.dirname(starlightRoot)), '@treeseed/core/dist/vendor/starlight');
|
|
124
|
+
await copyVendoredTree(coreVendorRoot, starlightRoot);
|
|
125
|
+
packageJson.exports = {
|
|
126
|
+
...packageJson.exports,
|
|
127
|
+
'.': './index.js',
|
|
128
|
+
'./schema': './schema.js',
|
|
129
|
+
'./loaders': './loaders.js',
|
|
130
|
+
'./route-data': './route-data.js',
|
|
131
|
+
'./internal': './internal.js',
|
|
132
|
+
'./components': './components.js',
|
|
133
|
+
};
|
|
134
|
+
await fs.writeFile(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}\n`, 'utf8');
|
|
135
|
+
}
|
|
136
|
+
async function run() {
|
|
137
|
+
const existingFiles = [];
|
|
138
|
+
for (const collectionFile of candidateCollectionFiles) {
|
|
139
|
+
try {
|
|
140
|
+
await fs.access(collectionFile);
|
|
141
|
+
existingFiles.push(collectionFile);
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
// Ignore missing dependency trees.
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
if (existingFiles.length === 0) {
|
|
148
|
+
throw new Error('Unable to find any Starlight collection helper files to patch.');
|
|
149
|
+
}
|
|
150
|
+
let patchedAny = false;
|
|
151
|
+
for (const collectionFile of existingFiles) {
|
|
152
|
+
const result = await patchCollectionFile(collectionFile);
|
|
153
|
+
patchedAny = patchedAny || result === 'patched';
|
|
154
|
+
}
|
|
155
|
+
for (const starlightRoot of candidateStarlightRoots) {
|
|
156
|
+
try {
|
|
157
|
+
await fs.access(path.join(starlightRoot, 'package.json'));
|
|
158
|
+
await patchStarlightPackageRoot(starlightRoot);
|
|
159
|
+
patchedAny = true;
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
// Ignore missing dependency trees.
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
console.log(patchedAny
|
|
166
|
+
? 'Applied Starlight knowledge-path patch.'
|
|
167
|
+
: 'Starlight knowledge-path patch already applied.');
|
|
168
|
+
}
|
|
169
|
+
run().catch((error) => {
|
|
170
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
171
|
+
process.exitCode = 1;
|
|
172
|
+
});
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { readFileSync, readdirSync } from 'node:fs';
|
|
2
|
-
import { extname, join, resolve } from 'node:path';
|
|
1
|
+
import { existsSync, readFileSync, readdirSync } from 'node:fs';
|
|
2
|
+
import { basename, extname, join, resolve } from 'node:path';
|
|
3
|
+
import { tmpdir } from 'node:os';
|
|
3
4
|
import { spawnSync } from 'node:child_process';
|
|
4
5
|
import { packageRoot } from './package-tools.js';
|
|
6
|
+
const npmCacheDir = resolve(tmpdir(), 'treeseed-npm-cache');
|
|
5
7
|
const textExtensions = new Set(['.js', '.ts', '.mjs', '.cjs', '.d.js', '.json', '.md']);
|
|
6
8
|
const forbiddenPatterns = [
|
|
7
|
-
/['"`]file:[^'"`\n]+['"`]/,
|
|
8
9
|
/['"`]workspace:[^'"`\n]+['"`]/,
|
|
9
10
|
/['"`](?:\.\.\/|\.\/)[^'"`\n]*src\/[^'"`\n]*\.(?:[cm]?js|ts|tsx|json|astro|css)['"`]/,
|
|
10
11
|
/['"`][^'"`\n]*\/packages\/[^'"`\n]*\/src\/[^'"`\n]*['"`]/,
|
|
@@ -13,7 +14,11 @@ function run(command, args) {
|
|
|
13
14
|
const result = spawnSync(command, args, {
|
|
14
15
|
cwd: packageRoot,
|
|
15
16
|
stdio: 'inherit',
|
|
16
|
-
env:
|
|
17
|
+
env: {
|
|
18
|
+
...process.env,
|
|
19
|
+
npm_config_cache: npmCacheDir,
|
|
20
|
+
NPM_CONFIG_CACHE: npmCacheDir,
|
|
21
|
+
},
|
|
17
22
|
});
|
|
18
23
|
if (result.status !== 0) {
|
|
19
24
|
process.exit(result.status ?? 1);
|
|
@@ -43,8 +48,31 @@ function scanDirectory(root) {
|
|
|
43
48
|
}
|
|
44
49
|
}
|
|
45
50
|
}
|
|
46
|
-
|
|
47
|
-
|
|
51
|
+
function assertCleanDistArtifacts() {
|
|
52
|
+
const forbiddenPaths = [
|
|
53
|
+
resolve(packageRoot, 'dist', 'src'),
|
|
54
|
+
resolve(packageRoot, 'dist', 'test'),
|
|
55
|
+
resolve(packageRoot, 'dist', 'vitest.config.d.ts'),
|
|
56
|
+
];
|
|
57
|
+
for (const targetPath of forbiddenPaths) {
|
|
58
|
+
if (existsSync(targetPath)) {
|
|
59
|
+
throw new Error(`Unexpected publish artifact present in dist: ${targetPath}`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
for (const filePath of walkFiles(resolve(packageRoot, 'dist'))) {
|
|
63
|
+
if (filePath.endsWith('.d.js')) {
|
|
64
|
+
throw new Error(`Unexpected generated declaration runtime artifact: ${filePath}`);
|
|
65
|
+
}
|
|
66
|
+
if (basename(filePath).startsWith('.ts-run-')) {
|
|
67
|
+
throw new Error(`Unexpected temporary runtime artifact: ${filePath}`);
|
|
68
|
+
}
|
|
69
|
+
if (filePath.includes('/dist/scripts/') && filePath.endsWith('.d.js')) {
|
|
70
|
+
throw new Error(`Unexpected script declaration artifact: ${filePath}`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
run('npm', ['run', 'lint']);
|
|
48
75
|
scanDirectory(resolve(packageRoot, 'dist'));
|
|
76
|
+
assertCleanDistArtifacts();
|
|
49
77
|
run('npm', ['run', 'test:unit']);
|
|
50
78
|
run('npm', ['run', 'test:smoke']);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
import { corePackageRoot, fixtureRoot } from '../operations/services/runtime-paths.js';
|
|
3
|
+
const [command, ...rest] = process.argv.slice(2);
|
|
4
|
+
if (!command) {
|
|
5
|
+
console.error('Usage: node ./scripts/run-fixture-astro-command.mjs <check|build|preview|dev> [...args]');
|
|
6
|
+
process.exit(1);
|
|
7
|
+
}
|
|
8
|
+
const result = spawnSync('npx', ['astro', command, '--root', fixtureRoot, ...rest], {
|
|
9
|
+
cwd: corePackageRoot,
|
|
10
|
+
stdio: 'inherit',
|
|
11
|
+
env: process.env,
|
|
12
|
+
shell: process.platform === 'win32',
|
|
13
|
+
});
|
|
14
|
+
if (result.error) {
|
|
15
|
+
console.error(result.error.message);
|
|
16
|
+
process.exit(1);
|
|
17
|
+
}
|
|
18
|
+
process.exit(result.status ?? 1);
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
import { scaffoldTemplateProject } from '../operations/services/template-registry.js';
|
|
4
|
+
function parseArgs(argv) {
|
|
5
|
+
const args = {
|
|
6
|
+
target: null,
|
|
7
|
+
template: 'starter-basic',
|
|
8
|
+
name: null,
|
|
9
|
+
slug: null,
|
|
10
|
+
siteUrl: null,
|
|
11
|
+
contactEmail: null,
|
|
12
|
+
repositoryUrl: null,
|
|
13
|
+
discordUrl: 'https://discord.gg/example',
|
|
14
|
+
};
|
|
15
|
+
const rest = [...argv];
|
|
16
|
+
while (rest.length > 0) {
|
|
17
|
+
const current = rest.shift();
|
|
18
|
+
if (!current)
|
|
19
|
+
continue;
|
|
20
|
+
if (!args.target && !current.startsWith('--')) {
|
|
21
|
+
args.target = current;
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
if (current === '--template')
|
|
25
|
+
args.template = rest.shift() ?? args.template;
|
|
26
|
+
else if (current === '--name')
|
|
27
|
+
args.name = rest.shift() ?? null;
|
|
28
|
+
else if (current === '--slug')
|
|
29
|
+
args.slug = rest.shift() ?? null;
|
|
30
|
+
else if (current === '--site-url')
|
|
31
|
+
args.siteUrl = rest.shift() ?? null;
|
|
32
|
+
else if (current === '--contact-email')
|
|
33
|
+
args.contactEmail = rest.shift() ?? null;
|
|
34
|
+
else if (current === '--repo')
|
|
35
|
+
args.repositoryUrl = rest.shift() ?? null;
|
|
36
|
+
else if (current === '--discord')
|
|
37
|
+
args.discordUrl = rest.shift() ?? args.discordUrl;
|
|
38
|
+
else
|
|
39
|
+
throw new Error(`Unknown argument: ${current}`);
|
|
40
|
+
}
|
|
41
|
+
if (!args.target)
|
|
42
|
+
throw new Error('Usage: treeseed init <directory> [--template <starter-id>] [--name <site name>] [--slug <slug>] [--site-url <url>] [--contact-email <email>] [--repo <url>] [--discord <url>]');
|
|
43
|
+
return args;
|
|
44
|
+
}
|
|
45
|
+
const options = parseArgs(process.argv.slice(2));
|
|
46
|
+
const targetRoot = resolve(process.cwd(), options.target);
|
|
47
|
+
const definition = await scaffoldTemplateProject(options.template, targetRoot, {
|
|
48
|
+
target: options.target,
|
|
49
|
+
name: options.name,
|
|
50
|
+
slug: options.slug,
|
|
51
|
+
siteUrl: options.siteUrl,
|
|
52
|
+
contactEmail: options.contactEmail,
|
|
53
|
+
repositoryUrl: options.repositoryUrl,
|
|
54
|
+
discordUrl: options.discordUrl,
|
|
55
|
+
}, {
|
|
56
|
+
writeWarning: (message) => console.warn(message),
|
|
57
|
+
});
|
|
58
|
+
console.log(`Created Treeseed tenant from ${definition.id} at ${targetRoot}`);
|
|
59
|
+
console.log('Next steps:');
|
|
60
|
+
console.log(` cd ${options.target}`);
|
|
61
|
+
console.log(' npm install');
|
|
62
|
+
console.log(' treeseed template show starter-basic');
|
|
63
|
+
console.log(' treeseed sync --check');
|
|
64
|
+
console.log(' treeseed config --environment local');
|
|
65
|
+
console.log(' treeseed dev');
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { applyTreeseedEnvironmentToProcess, writeTreeseedLocalEnvironmentFiles } from '../operations/services/config-runtime.js';
|
|
2
|
+
const tenantRoot = process.cwd();
|
|
3
|
+
applyTreeseedEnvironmentToProcess({ tenantRoot, scope: 'local', override: true });
|
|
4
|
+
const result = writeTreeseedLocalEnvironmentFiles(tenantRoot);
|
|
5
|
+
console.log(`Wrote ${result.envLocalPath}`);
|
|
6
|
+
console.log(`Wrote ${result.devVarsPath}`);
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { syncTemplateProject } from '../operations/services/template-registry.js';
|
|
3
|
+
const args = process.argv.slice(2);
|
|
4
|
+
const check = args.includes('--check');
|
|
5
|
+
const changed = await syncTemplateProject(process.cwd(), {
|
|
6
|
+
check,
|
|
7
|
+
writeWarning: (message) => console.warn(message),
|
|
8
|
+
});
|
|
9
|
+
if (check) {
|
|
10
|
+
if (changed.length === 0) {
|
|
11
|
+
console.log('managed surface is up to date');
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
console.log(`managed surface drift: ${changed.join(', ')}`);
|
|
15
|
+
process.exitCode = 1;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
console.log(changed.length === 0 ? 'managed surface already up to date' : `updated: ${changed.join(', ')}`);
|
|
20
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { mkdtempSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
4
|
+
import { tmpdir } from 'node:os';
|
|
5
|
+
import { join, resolve } from 'node:path';
|
|
6
|
+
import { listTemplateProducts, resolveTemplateDefinition } from '../dist/scripts/template-registry-lib.js';
|
|
7
|
+
|
|
8
|
+
function makeMachineConfigRoot(endpoint) {
|
|
9
|
+
const root = mkdtempSync(join(tmpdir(), 'treeseed-cli-template-catalog-'));
|
|
10
|
+
const configDir = resolve(root, '.treeseed', 'config');
|
|
11
|
+
mkdirSync(configDir, { recursive: true });
|
|
12
|
+
writeFileSync(resolve(configDir, 'machine.yaml'), [
|
|
13
|
+
'version: 1',
|
|
14
|
+
'settings:',
|
|
15
|
+
' templates:',
|
|
16
|
+
` catalogEndpoint: ${endpoint}`,
|
|
17
|
+
'',
|
|
18
|
+
].join('\n'), 'utf8');
|
|
19
|
+
return root;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function writeCatalogFixture(root, fileName, items) {
|
|
23
|
+
const fixturePath = resolve(root, fileName);
|
|
24
|
+
writeFileSync(fixturePath, JSON.stringify({ items }, null, 2), 'utf8');
|
|
25
|
+
return fixturePath;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function writeCatalogCache(root, endpoint, items) {
|
|
29
|
+
const cacheDir = resolve(root, '.treeseed', 'cache');
|
|
30
|
+
mkdirSync(cacheDir, { recursive: true });
|
|
31
|
+
writeFileSync(resolve(cacheDir, 'template-catalog.json'), JSON.stringify({
|
|
32
|
+
endpoint,
|
|
33
|
+
fetchedAt: '2026-04-08T00:00:00.000Z',
|
|
34
|
+
items,
|
|
35
|
+
}, null, 2), 'utf8');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const starterTemplate = {
|
|
39
|
+
id: 'starter-basic',
|
|
40
|
+
displayName: 'TreeSeed Basic',
|
|
41
|
+
description: 'Starter',
|
|
42
|
+
summary: 'Starter summary',
|
|
43
|
+
status: 'live',
|
|
44
|
+
category: 'starter',
|
|
45
|
+
publisher: {
|
|
46
|
+
id: 'treeseed',
|
|
47
|
+
name: 'TreeSeed',
|
|
48
|
+
},
|
|
49
|
+
templateVersion: '1.0.0',
|
|
50
|
+
templateApiVersion: 1,
|
|
51
|
+
minCliVersion: '0.1.1',
|
|
52
|
+
minCoreVersion: '0.1.2',
|
|
53
|
+
fulfillment: {
|
|
54
|
+
source: {
|
|
55
|
+
repoUrl: 'https://example.com/repo.git',
|
|
56
|
+
directory: 'templates/starter-basic',
|
|
57
|
+
ref: 'main',
|
|
58
|
+
},
|
|
59
|
+
hooksPolicy: 'builtin_only',
|
|
60
|
+
supportsReconcile: true,
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
test('template registry reads the remote catalog from a configured file endpoint and falls back to cache', async () => {
|
|
65
|
+
const root = mkdtempSync(join(tmpdir(), 'treeseed-cli-template-catalog-fixture-'));
|
|
66
|
+
const fixturePath = writeCatalogFixture(root, 'catalog.json', [starterTemplate]);
|
|
67
|
+
const fallbackEndpoint = 'https://127.0.0.1:9/search/templates';
|
|
68
|
+
const cwd = makeMachineConfigRoot(`file:${fixturePath}`);
|
|
69
|
+
|
|
70
|
+
const remoteProducts = await listTemplateProducts({ cwd, env: {} });
|
|
71
|
+
assert.equal(remoteProducts.length, 1);
|
|
72
|
+
assert.equal(remoteProducts[0]?.id, 'starter-basic');
|
|
73
|
+
|
|
74
|
+
writeCatalogCache(cwd, fallbackEndpoint, [starterTemplate]);
|
|
75
|
+
|
|
76
|
+
const warnings = [];
|
|
77
|
+
const cachedProducts = await listTemplateProducts({
|
|
78
|
+
cwd,
|
|
79
|
+
env: {
|
|
80
|
+
TREESEED_TEMPLATE_CATALOG_URL: fallbackEndpoint,
|
|
81
|
+
},
|
|
82
|
+
writeWarning: (message) => warnings.push(message),
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
assert.equal(cachedProducts.length, 1);
|
|
86
|
+
assert.equal(cachedProducts[0]?.id, 'starter-basic');
|
|
87
|
+
assert.equal(warnings.length, 1);
|
|
88
|
+
assert.match(warnings[0], /Using cached template catalog/);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test('template definition resolution rejects templates missing from the remote catalog', async () => {
|
|
92
|
+
const root = mkdtempSync(join(tmpdir(), 'treeseed-cli-template-catalog-empty-'));
|
|
93
|
+
const fixturePath = writeCatalogFixture(root, 'empty.json', []);
|
|
94
|
+
const cwd = makeMachineConfigRoot(`file:${fixturePath}`);
|
|
95
|
+
|
|
96
|
+
await assert.rejects(
|
|
97
|
+
() => resolveTemplateDefinition('starter-basic', { cwd, env: {} }),
|
|
98
|
+
/Unable to resolve remote template product "starter-basic"\./,
|
|
99
|
+
);
|
|
100
|
+
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { listTemplateProducts, resolveTemplateProduct, serializeTemplateRegistryEntry, validateTemplateProduct } from '../operations/services/template-registry.js';
|
|
3
|
+
const [action = 'list', target] = process.argv.slice(2);
|
|
4
|
+
const writeWarning = (message) => console.warn(message);
|
|
5
|
+
switch (action) {
|
|
6
|
+
case 'list': {
|
|
7
|
+
for (const product of await listTemplateProducts({ writeWarning })) {
|
|
8
|
+
console.log(`${product.id}\t${product.displayName}\t${product.description}`);
|
|
9
|
+
}
|
|
10
|
+
break;
|
|
11
|
+
}
|
|
12
|
+
case 'show': {
|
|
13
|
+
if (!target) {
|
|
14
|
+
throw new Error('Usage: treeseed template show <id>');
|
|
15
|
+
}
|
|
16
|
+
console.log(JSON.stringify(serializeTemplateRegistryEntry(await resolveTemplateProduct(target, { writeWarning })), null, 2));
|
|
17
|
+
break;
|
|
18
|
+
}
|
|
19
|
+
case 'validate': {
|
|
20
|
+
const products = target
|
|
21
|
+
? [await resolveTemplateProduct(target, { writeWarning })]
|
|
22
|
+
: await listTemplateProducts({ writeWarning });
|
|
23
|
+
for (const product of products) {
|
|
24
|
+
await validateTemplateProduct(product, { writeWarning });
|
|
25
|
+
console.log(`validated ${product.id}`);
|
|
26
|
+
}
|
|
27
|
+
break;
|
|
28
|
+
}
|
|
29
|
+
default:
|
|
30
|
+
throw new Error(`Unknown template action: ${action}`);
|
|
31
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { resolveAstroBin, createProductionBuildEnv, packageScriptPath, runNodeBinary, runNodeScript } from '../operations/services/runtime-tools.js';
|
|
2
|
+
process.env.TREESEED_LOCAL_DEV_MODE = process.env.TREESEED_LOCAL_DEV_MODE ?? 'cloudflare';
|
|
3
|
+
runNodeScript(packageScriptPath('patch-starlight-content-path'), [], { cwd: process.cwd() });
|
|
4
|
+
runNodeScript(packageScriptPath('aggregate-book'), [], { cwd: process.cwd() });
|
|
5
|
+
runNodeBinary(resolveAstroBin(), ['build'], {
|
|
6
|
+
cwd: process.cwd(),
|
|
7
|
+
env: createProductionBuildEnv({
|
|
8
|
+
TREESEED_LOCAL_DEV_MODE: process.env.TREESEED_LOCAL_DEV_MODE,
|
|
9
|
+
}),
|
|
10
|
+
});
|
|
11
|
+
runNodeScript(packageScriptPath('build-tenant-worker'), [], {
|
|
12
|
+
cwd: process.cwd(),
|
|
13
|
+
env: createProductionBuildEnv({
|
|
14
|
+
TREESEED_LOCAL_DEV_MODE: process.env.TREESEED_LOCAL_DEV_MODE,
|
|
15
|
+
}),
|
|
16
|
+
});
|