@treeseed/sdk 0.4.6 → 0.4.8
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/operations/providers/default.js +1 -0
- package/dist/operations/services/config-runtime.d.ts +121 -26
- package/dist/operations/services/config-runtime.js +330 -196
- package/dist/operations/services/export-runtime.d.ts +18 -0
- package/dist/operations/services/export-runtime.js +136 -0
- package/dist/operations/services/template-registry.d.ts +2 -0
- package/dist/operations/services/template-registry.js +55 -6
- package/dist/operations-registry.js +1 -0
- package/dist/operations-types.d.ts +1 -1
- package/dist/platform/book-export.d.ts +78 -0
- package/dist/platform/book-export.js +449 -0
- package/dist/platform/contracts.d.ts +5 -0
- package/dist/platform/deploy-config.d.ts +2 -0
- package/dist/platform/deploy-config.js +30 -2
- package/dist/platform/env.yaml +5 -0
- package/dist/platform/environment.d.ts +10 -1
- package/dist/platform/environment.js +82 -6
- package/dist/scripts/aggregate-book.js +13 -118
- package/dist/scripts/config-treeseed.js +18 -27
- package/dist/sdk-types.d.ts +1 -0
- package/dist/template-catalog.js +1 -0
- package/dist/workflow/operations.d.ts +293 -177
- package/dist/workflow/operations.js +302 -188
- package/dist/workflow/policy.d.ts +12 -0
- package/dist/workflow/policy.js +58 -0
- package/dist/workflow-state.d.ts +19 -1
- package/dist/workflow-state.js +57 -39
- package/dist/workflow-support.d.ts +2 -1
- package/dist/workflow-support.js +14 -6
- package/dist/workflow.d.ts +14 -1
- package/dist/workflow.js +8 -1
- package/package.json +6 -1
|
@@ -21,6 +21,7 @@ const TREESEED_ENVIRONMENT_TARGETS = [
|
|
|
21
21
|
];
|
|
22
22
|
const TREESEED_ENVIRONMENT_PURPOSES = ["dev", "save", "deploy", "destroy", "config"];
|
|
23
23
|
const TREESEED_ENVIRONMENT_SENSITIVITY = ["secret", "plain", "derived"];
|
|
24
|
+
const TREESEED_ENVIRONMENT_STORAGE = ["scoped", "shared"];
|
|
24
25
|
const moduleDir = dirname(fileURLToPath(import.meta.url));
|
|
25
26
|
const CORE_ENVIRONMENT_PATH = resolve(moduleDir, "env.yaml");
|
|
26
27
|
const TENANT_ENVIRONMENT_OVERLAY_PATH = "src/env.yaml";
|
|
@@ -45,9 +46,69 @@ function railwayManagedEnabled(context) {
|
|
|
45
46
|
function generatedSecret(bytes = 24) {
|
|
46
47
|
return randomBytes(bytes).toString("hex");
|
|
47
48
|
}
|
|
49
|
+
function normalizeUrl(value) {
|
|
50
|
+
return value.trim().replace(/\/$/u, "");
|
|
51
|
+
}
|
|
52
|
+
function primaryHostFromUrl(value) {
|
|
53
|
+
if (!value || value.trim().length === 0) {
|
|
54
|
+
return void 0;
|
|
55
|
+
}
|
|
56
|
+
try {
|
|
57
|
+
return new URL(value).host;
|
|
58
|
+
} catch {
|
|
59
|
+
return void 0;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function parseDomainList(value) {
|
|
63
|
+
return String(value ?? "").split(",").map((entry) => entry.trim()).filter(Boolean);
|
|
64
|
+
}
|
|
65
|
+
function deriveApiDomainFromProjectDomain(domain) {
|
|
66
|
+
if (!domain) {
|
|
67
|
+
return void 0;
|
|
68
|
+
}
|
|
69
|
+
if (domain.startsWith("api.")) {
|
|
70
|
+
return domain;
|
|
71
|
+
}
|
|
72
|
+
const segments = domain.split(".").filter(Boolean);
|
|
73
|
+
if (segments.length <= 2) {
|
|
74
|
+
return `api.${domain}`;
|
|
75
|
+
}
|
|
76
|
+
return `api.${segments.slice(1).join(".")}`;
|
|
77
|
+
}
|
|
78
|
+
function resolveConfiguredApiBaseUrl(context, scope, values = {}) {
|
|
79
|
+
const localBaseUrl = context.deployConfig.services?.api?.environments?.local?.baseUrl ?? context.deployConfig.surfaces?.api?.localBaseUrl ?? "http://127.0.0.1:3000";
|
|
80
|
+
if (scope === "local") {
|
|
81
|
+
return normalizeUrl(localBaseUrl);
|
|
82
|
+
}
|
|
83
|
+
const scopedBaseUrl = context.deployConfig.services?.api?.environments?.[scope]?.baseUrl ?? context.deployConfig.services?.api?.publicBaseUrl ?? context.deployConfig.surfaces?.api?.publicBaseUrl;
|
|
84
|
+
if (scopedBaseUrl) {
|
|
85
|
+
return normalizeUrl(scopedBaseUrl);
|
|
86
|
+
}
|
|
87
|
+
const projectDomains = [
|
|
88
|
+
...parseDomainList(values.TREESEED_PROJECT_DOMAINS),
|
|
89
|
+
primaryHostFromUrl(context.deployConfig.siteUrl)
|
|
90
|
+
].filter(Boolean);
|
|
91
|
+
for (const domain of projectDomains) {
|
|
92
|
+
const apiDomain = deriveApiDomainFromProjectDomain(domain);
|
|
93
|
+
if (apiDomain) {
|
|
94
|
+
return `https://${apiDomain}`;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return void 0;
|
|
98
|
+
}
|
|
99
|
+
function resolveWebServiceId(_values = {}) {
|
|
100
|
+
return "web";
|
|
101
|
+
}
|
|
102
|
+
function resolveApiWebServiceId(values = {}) {
|
|
103
|
+
return values.TREESEED_WEB_SERVICE_ID?.trim() || "web";
|
|
104
|
+
}
|
|
48
105
|
const VALUE_RESOLVERS = {
|
|
49
106
|
generatedSecret: () => generatedSecret(),
|
|
50
|
-
localFormsBypassDefault: () => "true"
|
|
107
|
+
localFormsBypassDefault: () => "true",
|
|
108
|
+
projectDomainsDefault: (context) => primaryHostFromUrl(context.deployConfig.siteUrl),
|
|
109
|
+
apiBaseUrlDefault: (context, scope, values) => resolveConfiguredApiBaseUrl(context, scope, values),
|
|
110
|
+
webServiceIdDefault: (_context, _scope, values) => resolveWebServiceId(values),
|
|
111
|
+
apiWebServiceIdDefault: (_context, _scope, values) => resolveApiWebServiceId(values)
|
|
51
112
|
};
|
|
52
113
|
const PREDICATES = {
|
|
53
114
|
turnstileEnabled: (context) => turnstileEnabled(context),
|
|
@@ -135,6 +196,7 @@ function materializeEntry(id, entry) {
|
|
|
135
196
|
return {
|
|
136
197
|
...entry,
|
|
137
198
|
id,
|
|
199
|
+
storage: entry.storage ?? "scoped",
|
|
138
200
|
defaultValue: resolveNamedValueResolver(entry.defaultValueRef),
|
|
139
201
|
localDefaultValue: resolveNamedValueResolver(entry.localDefaultValueRef),
|
|
140
202
|
isRelevant: resolveNamedPredicate(entry.relevanceRef),
|
|
@@ -233,18 +295,30 @@ function isEntryRequired(entry, context, scope, purpose) {
|
|
|
233
295
|
}
|
|
234
296
|
return false;
|
|
235
297
|
}
|
|
236
|
-
function materializeDefaultValue(entry, context, scope) {
|
|
298
|
+
function materializeDefaultValue(entry, context, scope, values = {}) {
|
|
237
299
|
const source = scope === "local" && entry.localDefaultValue !== void 0 ? entry.localDefaultValue : entry.defaultValue;
|
|
238
300
|
if (source === void 0) {
|
|
239
301
|
return void 0;
|
|
240
302
|
}
|
|
241
|
-
return typeof source === "function" ? source(context, scope) : source;
|
|
303
|
+
return typeof source === "function" ? source(context, scope, values) : source;
|
|
242
304
|
}
|
|
243
305
|
function getTreeseedEnvironmentSuggestedValues(options) {
|
|
244
306
|
const registry = resolveTreeseedEnvironmentRegistry(options);
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
307
|
+
const suggestedValues = {};
|
|
308
|
+
const seedValues = { ...options.values ?? {} };
|
|
309
|
+
for (const entry of registry.entries.filter(
|
|
310
|
+
(candidate) => isTreeseedEnvironmentEntryRelevant(candidate, registry.context, options.scope, options.purpose)
|
|
311
|
+
)) {
|
|
312
|
+
const value = materializeDefaultValue(entry, registry.context, options.scope, { ...suggestedValues, ...seedValues });
|
|
313
|
+
if (value === void 0) {
|
|
314
|
+
continue;
|
|
315
|
+
}
|
|
316
|
+
suggestedValues[entry.id] = value;
|
|
317
|
+
}
|
|
318
|
+
return suggestedValues;
|
|
319
|
+
}
|
|
320
|
+
function isTreeseedEnvironmentEntryRequired(entry, context, scope, purpose) {
|
|
321
|
+
return isEntryRequired(entry, context, scope, purpose);
|
|
248
322
|
}
|
|
249
323
|
function valuePresent(value) {
|
|
250
324
|
return typeof value === "string" && value.trim().length > 0;
|
|
@@ -322,9 +396,11 @@ export {
|
|
|
322
396
|
TREESEED_ENVIRONMENT_REQUIREMENTS,
|
|
323
397
|
TREESEED_ENVIRONMENT_SCOPES,
|
|
324
398
|
TREESEED_ENVIRONMENT_SENSITIVITY,
|
|
399
|
+
TREESEED_ENVIRONMENT_STORAGE,
|
|
325
400
|
TREESEED_ENVIRONMENT_TARGETS,
|
|
326
401
|
getTreeseedEnvironmentSuggestedValues,
|
|
327
402
|
isTreeseedEnvironmentEntryRelevant,
|
|
403
|
+
isTreeseedEnvironmentEntryRequired,
|
|
328
404
|
loadTreeseedEnvironmentOverlay,
|
|
329
405
|
resolveTreeseedEnvironmentContext,
|
|
330
406
|
resolveTreeseedEnvironmentRegistry,
|
|
@@ -1,121 +1,16 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
1
|
import path from 'node:path';
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
downloadHref: '/books/karyon-knowledge.md',
|
|
11
|
-
downloadTitle: 'Karyon Knowledge Library',
|
|
12
|
-
},
|
|
13
|
-
});
|
|
14
|
-
const projectRoot = PROJECT_TENANT.__tenantRoot ?? process.cwd();
|
|
15
|
-
const outputDir = path.join(projectRoot, 'public', 'books');
|
|
16
|
-
const legacyOutputFile = path.join(projectRoot, 'public', 'book.md');
|
|
17
|
-
function sortPaths(paths) {
|
|
18
|
-
return [...paths].sort((left, right) => left.localeCompare(right, undefined, { numeric: true, sensitivity: 'base' }));
|
|
19
|
-
}
|
|
20
|
-
function getSidebarOrder(filePath) {
|
|
21
|
-
const rawContent = fs.readFileSync(filePath, 'utf8');
|
|
22
|
-
const frontmatterMatch = rawContent.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
23
|
-
if (!frontmatterMatch)
|
|
24
|
-
return Number.POSITIVE_INFINITY;
|
|
25
|
-
const orderMatch = frontmatterMatch[1].match(/^\s{2}order:\s*(\d+)\s*$/m);
|
|
26
|
-
return orderMatch ? Number.parseInt(orderMatch[1], 10) : Number.POSITIVE_INFINITY;
|
|
27
|
-
}
|
|
28
|
-
function collectMarkdownFiles(rootPath) {
|
|
29
|
-
if (!fs.existsSync(rootPath)) {
|
|
30
|
-
throw new Error(`Book export root not found: ${rootPath}`);
|
|
31
|
-
}
|
|
32
|
-
const stats = fs.statSync(rootPath);
|
|
33
|
-
if (stats.isFile()) {
|
|
34
|
-
return [rootPath];
|
|
35
|
-
}
|
|
36
|
-
const entries = fs.readdirSync(rootPath, { withFileTypes: true });
|
|
37
|
-
return sortPaths(entries.flatMap((entry) => {
|
|
38
|
-
const fullPath = path.join(rootPath, entry.name);
|
|
39
|
-
if (entry.isDirectory()) {
|
|
40
|
-
return collectMarkdownFiles(fullPath);
|
|
41
|
-
}
|
|
42
|
-
if (entry.isFile() && (entry.name.endsWith('.md') || entry.name.endsWith('.mdx'))) {
|
|
43
|
-
return [fullPath];
|
|
44
|
-
}
|
|
45
|
-
return [];
|
|
46
|
-
}));
|
|
47
|
-
}
|
|
48
|
-
function stripFrontmatter(content) {
|
|
49
|
-
return content.replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/, '').trim();
|
|
50
|
-
}
|
|
51
|
-
function stripMdxOnlySyntax(content) {
|
|
52
|
-
return content
|
|
53
|
-
.replace(/^import\s.+$/gm, '')
|
|
54
|
-
.replace(/^\s*<\/?[A-Z][^>]*>\s*$/gm, '')
|
|
55
|
-
.replace(/\n{3,}/g, '\n\n')
|
|
56
|
-
.trim();
|
|
57
|
-
}
|
|
58
|
-
function inferExportRootFromBasePath(book) {
|
|
59
|
-
const normalizedBasePath = String(book.basePath || '').trim();
|
|
60
|
-
const knowledgePrefix = '/knowledge/';
|
|
61
|
-
if (!normalizedBasePath.startsWith(knowledgePrefix)) {
|
|
62
|
-
throw new Error(`Book basePath must start with "${knowledgePrefix}" to infer exports: ${book.basePath}`);
|
|
63
|
-
}
|
|
64
|
-
const relativeKnowledgePath = normalizedBasePath
|
|
65
|
-
.slice(knowledgePrefix.length)
|
|
66
|
-
.replace(/^\/+|\/+$/g, '');
|
|
67
|
-
if (!relativeKnowledgePath) {
|
|
68
|
-
throw new Error(`Book basePath must identify a knowledge directory: ${book.basePath}`);
|
|
2
|
+
import { exportTenantBookPackages } from '../platform/book-export.js';
|
|
3
|
+
async function main() {
|
|
4
|
+
console.log('Generating Treeseed AI book packages...');
|
|
5
|
+
const result = await exportTenantBookPackages({ projectRoot: process.cwd() });
|
|
6
|
+
for (const entry of result.bookPackages) {
|
|
7
|
+
console.log(`Generated ${path.relative(result.projectRoot, entry.markdownPath)}`);
|
|
8
|
+
console.log(`Generated ${path.relative(result.projectRoot, entry.indexPath)}`);
|
|
69
9
|
}
|
|
70
|
-
|
|
10
|
+
console.log(`Generated ${path.relative(result.projectRoot, result.libraryPackage.markdownPath)}`);
|
|
11
|
+
console.log(`Generated ${path.relative(result.projectRoot, result.libraryPackage.indexPath)}`);
|
|
71
12
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
return [inferExportRootFromBasePath(book)];
|
|
77
|
-
}
|
|
78
|
-
function resolveBookFiles(book) {
|
|
79
|
-
const files = resolveExportRoots(book).flatMap((root) => collectMarkdownFiles(path.resolve(projectRoot, root)).sort((left, right) => {
|
|
80
|
-
const orderDelta = getSidebarOrder(left) - getSidebarOrder(right);
|
|
81
|
-
if (orderDelta !== 0)
|
|
82
|
-
return orderDelta;
|
|
83
|
-
return left.localeCompare(right, undefined, { numeric: true, sensitivity: 'base' });
|
|
84
|
-
}));
|
|
85
|
-
return Array.from(new Set(files));
|
|
86
|
-
}
|
|
87
|
-
function buildBookMarkdown(book) {
|
|
88
|
-
const sections = resolveBookFiles(book).map((filePath) => {
|
|
89
|
-
const rawContent = fs.readFileSync(filePath, 'utf8');
|
|
90
|
-
return stripMdxOnlySyntax(stripFrontmatter(rawContent));
|
|
91
|
-
});
|
|
92
|
-
return `# ${book.downloadTitle}\n\n> This document is auto-generated from the Karyon knowledge source.\n\n${sections.join('\n\n---\n\n')}\n`;
|
|
93
|
-
}
|
|
94
|
-
function ensureOutputDir() {
|
|
95
|
-
fs.mkdirSync(outputDir, { recursive: true });
|
|
96
|
-
}
|
|
97
|
-
function writeBookOutput(fileName, content) {
|
|
98
|
-
const outputPath = path.join(outputDir, fileName);
|
|
99
|
-
fs.writeFileSync(outputPath, content);
|
|
100
|
-
return outputPath;
|
|
101
|
-
}
|
|
102
|
-
function main() {
|
|
103
|
-
console.log('Generating contextual Karyon knowledge exports...');
|
|
104
|
-
ensureOutputDir();
|
|
105
|
-
const bookOutputs = BOOKS.map((book) => {
|
|
106
|
-
const content = buildBookMarkdown(book);
|
|
107
|
-
const outputPath = writeBookOutput(book.downloadFileName, content);
|
|
108
|
-
console.log(`Generated ${path.relative(projectRoot, outputPath)}`);
|
|
109
|
-
return { book, content };
|
|
110
|
-
});
|
|
111
|
-
const compositeContent = `# ${TREESEED_LIBRARY_DOWNLOAD.downloadTitle}\n\n> This document is auto-generated from the Karyon knowledge source.\n\n${bookOutputs
|
|
112
|
-
.map(({ content }) => content.trim())
|
|
113
|
-
.join('\n\n---\n\n')}\n`;
|
|
114
|
-
const compositeOutputPath = writeBookOutput(TREESEED_LIBRARY_DOWNLOAD.downloadFileName, compositeContent);
|
|
115
|
-
console.log(`Generated ${path.relative(projectRoot, compositeOutputPath)}`);
|
|
116
|
-
if (fs.existsSync(legacyOutputFile)) {
|
|
117
|
-
fs.rmSync(legacyOutputFile);
|
|
118
|
-
console.log(`Removed legacy export ${path.relative(projectRoot, legacyOutputFile)}`);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
main();
|
|
13
|
+
main().catch((error) => {
|
|
14
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
15
|
+
process.exitCode = 1;
|
|
16
|
+
});
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import
|
|
3
|
-
import { stdin as input, stdout as output } from 'node:process';
|
|
4
|
-
import { collectCliPreflight } from '../operations/services/workspace-preflight.js';
|
|
5
|
-
import { applyTreeseedEnvironmentToProcess, ensureTreeseedGitignoreEntries, getTreeseedMachineConfigPaths, rotateTreeseedMachineKey, runTreeseedConfigWizard, writeTreeseedLocalEnvironmentFiles, } from '../operations/services/config-runtime.js';
|
|
2
|
+
import { applyTreeseedConfigValues, applyTreeseedSafeRepairs, collectTreeseedConfigContext, ensureTreeseedGitignoreEntries, finalizeTreeseedConfig, getTreeseedMachineConfigPaths, rotateTreeseedMachineKey, } from '../operations/services/config-runtime.js';
|
|
6
3
|
const tenantRoot = process.cwd();
|
|
7
4
|
function parseArgs(argv) {
|
|
8
5
|
const parsed = {
|
|
@@ -45,42 +42,37 @@ const scopes = options.scopes.length === 0 || options.scopes.includes('all')
|
|
|
45
42
|
? ['local', 'staging', 'prod']
|
|
46
43
|
: ['local', 'staging', 'prod'].filter((scope) => options.scopes.includes(scope));
|
|
47
44
|
ensureTreeseedGitignoreEntries(tenantRoot);
|
|
48
|
-
const preflight = collectCliPreflight({ cwd: tenantRoot, requireAuth: false });
|
|
49
|
-
const rl = readline.createInterface({ input, output });
|
|
50
45
|
try {
|
|
51
|
-
console.log('Treeseed configuration wizard');
|
|
52
|
-
console.log('This command writes a local machine config, generates .env.local and .dev.vars, and can sync GitHub or Cloudflare settings.');
|
|
53
|
-
console.log('Enter a value to set it, press Enter to keep the current/default value, or enter "-" to clear a value.\n');
|
|
54
46
|
if (options.rotateMachineKey) {
|
|
55
47
|
const result = rotateTreeseedMachineKey(tenantRoot);
|
|
56
48
|
console.log('Treeseed machine key rotated.');
|
|
57
49
|
console.log(`Machine key: ${result.keyPath}`);
|
|
58
50
|
}
|
|
59
51
|
else {
|
|
60
|
-
|
|
52
|
+
applyTreeseedSafeRepairs(tenantRoot);
|
|
53
|
+
const context = collectTreeseedConfigContext({
|
|
54
|
+
tenantRoot,
|
|
55
|
+
scopes,
|
|
56
|
+
env: process.env,
|
|
57
|
+
});
|
|
58
|
+
const updates = scopes.flatMap((scope) => context.entriesByScope[scope].map((entry) => ({
|
|
59
|
+
scope,
|
|
60
|
+
entryId: entry.id,
|
|
61
|
+
value: entry.effectiveValue,
|
|
62
|
+
reused: entry.currentValue.length > 0 || entry.suggestedValue.length > 0,
|
|
63
|
+
})));
|
|
64
|
+
const applyResult = applyTreeseedConfigValues({ tenantRoot, updates });
|
|
65
|
+
const result = finalizeTreeseedConfig({
|
|
61
66
|
tenantRoot,
|
|
62
67
|
scopes,
|
|
63
68
|
sync: options.sync,
|
|
64
|
-
|
|
65
|
-
prompt: async (message) => {
|
|
66
|
-
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
67
|
-
return '';
|
|
68
|
-
}
|
|
69
|
-
try {
|
|
70
|
-
return await rl.question(message);
|
|
71
|
-
}
|
|
72
|
-
catch {
|
|
73
|
-
return '';
|
|
74
|
-
}
|
|
75
|
-
},
|
|
69
|
+
env: process.env,
|
|
76
70
|
});
|
|
77
|
-
writeTreeseedLocalEnvironmentFiles(tenantRoot);
|
|
78
|
-
applyTreeseedEnvironmentToProcess({ tenantRoot, scope: 'local', override: true });
|
|
79
71
|
const { configPath, keyPath } = getTreeseedMachineConfigPaths(tenantRoot);
|
|
80
|
-
console.log('
|
|
72
|
+
console.log('Treeseed config completed.');
|
|
81
73
|
console.log(`Machine config: ${configPath}`);
|
|
82
74
|
console.log(`Machine key: ${keyPath}`);
|
|
83
|
-
console.log(`Updated values: ${
|
|
75
|
+
console.log(`Updated values: ${applyResult.updated.length}`);
|
|
84
76
|
console.log(`Initialized environments: ${result.initialized.length}`);
|
|
85
77
|
if (result.synced.github) {
|
|
86
78
|
console.log(`GitHub sync: ${result.synced.github.secrets.length} secrets, ${result.synced.github.variables.length} variables (${result.synced.github.repository})`);
|
|
@@ -91,5 +83,4 @@ try {
|
|
|
91
83
|
}
|
|
92
84
|
}
|
|
93
85
|
finally {
|
|
94
|
-
rl.close();
|
|
95
86
|
}
|
package/dist/sdk-types.d.ts
CHANGED
|
@@ -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;
|
package/dist/template-catalog.js
CHANGED
|
@@ -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"),
|