@treeseed/sdk 0.4.7 → 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.
@@ -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
- return Object.fromEntries(
246
- registry.entries.filter((entry) => isTreeseedEnvironmentEntryRelevant(entry, registry.context, options.scope, options.purpose)).map((entry) => [entry.id, materializeDefaultValue(entry, registry.context, options.scope)]).filter(([, value]) => value !== void 0)
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 { buildTenantBookRuntime } from '../platform/books-data.js';
4
- import { loadTreeseedManifest } from '../platform/tenant-config.js';
5
- const PROJECT_TENANT = loadTreeseedManifest();
6
- const { BOOKS, TREESEED_LIBRARY_DOWNLOAD } = buildTenantBookRuntime(PROJECT_TENANT, {
7
- projectRoot: PROJECT_TENANT.__tenantRoot ?? process.cwd(),
8
- docsLibraryDownload: {
9
- downloadFileName: 'karyon-knowledge.md',
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
- return path.join(PROJECT_TENANT.content.docs, relativeKnowledgePath);
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
- function resolveExportRoots(book) {
73
- if (Array.isArray(book.exportRoots) && book.exportRoots.length > 0) {
74
- return book.exportRoots;
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 readline from 'node:readline/promises';
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
- const result = await runTreeseedConfigWizard({
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
- authStatus: preflight.checks.auth,
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('\nTreeseed config completed.');
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: ${result.updated.length}`);
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
  }
@@ -1,5 +1,6 @@
1
+ import { checkTreeseedProviderConnections } from '../operations/services/config-runtime.ts';
1
2
  import { resolveTreeseedWorkflowState } from '../workflow-state.ts';
2
- import type { TreeseedCloseInput, TreeseedConfigInput, TreeseedDestroyInput, TreeseedReleaseInput, TreeseedSaveInput, TreeseedStageInput, TreeseedSwitchInput, TreeseedTaskBranchMetadata, TreeseedWorkflowContext, TreeseedWorkflowDevInput, TreeseedWorkflowNextStep, TreeseedWorkflowOperationId, TreeseedWorkflowResult } from '../workflow.ts';
3
+ import type { TreeseedCloseInput, TreeseedConfigInput, TreeseedDestroyInput, TreeseedExportInput, TreeseedReleaseInput, TreeseedSaveInput, TreeseedStageInput, TreeseedSwitchInput, TreeseedTaskBranchMetadata, TreeseedWorkflowContext, TreeseedWorkflowDevInput, TreeseedWorkflowNextStep, TreeseedWorkflowOperationId, TreeseedWorkflowResult } from '../workflow.ts';
3
4
  type WorkflowWrite = NonNullable<TreeseedWorkflowContext['write']>;
4
5
  type WorkflowStatePayload = ReturnType<typeof resolveTreeseedWorkflowState>;
5
6
  export type TreeseedWorkflowErrorCode = 'validation_failed' | 'merge_conflict' | 'missing_runtime_auth' | 'deployment_timeout' | 'confirmation_required' | 'unsupported_transport' | 'unsupported_state';
@@ -22,10 +23,6 @@ export type WorkflowOperationHelpers = {
22
23
  tasks: TreeseedTaskBranchMetadata[];
23
24
  }>>;
24
25
  };
25
- type TreeseedRepairAction = {
26
- id: string;
27
- detail: string;
28
- };
29
26
  export declare function workflowStatus(helpers: WorkflowOperationHelpers): Promise<TreeseedWorkflowResult<import("../workflow-state.ts").TreeseedWorkflowState>>;
30
27
  export declare function workflowTasks(helpers: WorkflowOperationHelpers): Promise<TreeseedWorkflowResult<{
31
28
  tasks: TreeseedTaskBranchMetadata[];
@@ -36,7 +33,7 @@ export declare function workflowConfig(helpers: WorkflowOperationHelpers, input?
36
33
  sync: "all" | "cloudflare" | "railway" | "none" | "github";
37
34
  configPath: string;
38
35
  keyPath: string;
39
- repairs: TreeseedRepairAction[];
36
+ repairs: import("../operations/services/config-runtime.ts").TreeseedRepairAction[];
40
37
  preflight: {
41
38
  ok: boolean;
42
39
  requireAuth: boolean;
@@ -71,13 +68,45 @@ export declare function workflowConfig(helpers: WorkflowOperationHelpers, input?
71
68
  actVerificationReady: any;
72
69
  remediation: string[];
73
70
  };
71
+ context: import("../operations/services/config-runtime.ts").TreeseedCollectedConfigContext;
74
72
  result: {
75
- scopes: string[];
76
- updated: never[];
77
- synced: {};
78
- initialized: never[];
79
- connectionChecks: never[];
73
+ scopes: ("local" | "staging" | "prod")[];
74
+ synced: Record<string, unknown>;
75
+ initialized: Array<{
76
+ scope: import("../operations/services/config-runtime.ts").TreeseedConfigScope;
77
+ secrets: number;
78
+ target: string;
79
+ }>;
80
+ connectionChecks: ReturnType<typeof checkTreeseedProviderConnections>[];
81
+ validationByScope: Record<import("../operations/services/config-runtime.ts").TreeseedConfigScope, ReturnType<typeof import("../platform/environment.ts").validateTreeseedEnvironmentValues>>;
82
+ updated: {
83
+ scope: import("../operations/services/config-runtime.ts").TreeseedConfigScope | "shared";
84
+ id: string;
85
+ reused: boolean;
86
+ cleared: boolean;
87
+ }[];
88
+ envFiles: {
89
+ envLocalPath: string;
90
+ devVarsPath: string;
91
+ } | null;
80
92
  };
93
+ reports: {
94
+ scope: "local" | "staging" | "prod";
95
+ environment: {
96
+ scope: "local" | "staging" | "prod";
97
+ revealSecrets: boolean;
98
+ entries: any;
99
+ };
100
+ provider: {
101
+ scope: string;
102
+ ok: boolean;
103
+ checks: {
104
+ provider: any;
105
+ ready: any;
106
+ detail: any;
107
+ }[];
108
+ };
109
+ }[];
81
110
  state: import("../workflow-state.ts").TreeseedWorkflowState;
82
111
  readiness: {
83
112
  local: {
@@ -108,10 +137,22 @@ export declare function workflowConfig(helpers: WorkflowOperationHelpers, input?
108
137
  secretsRevealed: boolean;
109
138
  reports: {
110
139
  scope: "local" | "staging" | "prod";
111
- environmentReport: string;
112
- providerReport: string;
140
+ environment: {
141
+ scope: "local" | "staging" | "prod";
142
+ revealSecrets: boolean;
143
+ entries: any;
144
+ };
145
+ provider: {
146
+ scope: string;
147
+ ok: boolean;
148
+ checks: {
149
+ provider: any;
150
+ ready: any;
151
+ detail: any;
152
+ }[];
153
+ };
113
154
  }[];
114
- repairs: TreeseedRepairAction[];
155
+ repairs: import("../operations/services/config-runtime.ts").TreeseedRepairAction[];
115
156
  preflight: {
116
157
  ok: boolean;
117
158
  requireAuth: boolean;
@@ -157,7 +198,7 @@ export declare function workflowConfig(helpers: WorkflowOperationHelpers, input?
157
198
  scopes: ("local" | "staging" | "prod")[];
158
199
  sync: "all" | "cloudflare" | "railway" | "none" | "github";
159
200
  keyPath: string;
160
- repairs: TreeseedRepairAction[];
201
+ repairs: import("../operations/services/config-runtime.ts").TreeseedRepairAction[];
161
202
  preflight: {
162
203
  ok: boolean;
163
204
  requireAuth: boolean;
@@ -197,6 +238,9 @@ export declare function workflowConfig(helpers: WorkflowOperationHelpers, input?
197
238
  };
198
239
  nextSteps: TreeseedWorkflowNextStep[];
199
240
  }>;
241
+ export declare function workflowExport(helpers: WorkflowOperationHelpers, input?: TreeseedExportInput): Promise<TreeseedWorkflowResult<import("../operations/services/export-runtime.ts").TreeseedExportResult & {
242
+ finalState: WorkflowStatePayload;
243
+ }>>;
200
244
  export declare function workflowSwitch(helpers: WorkflowOperationHelpers, input: TreeseedSwitchInput): Promise<TreeseedWorkflowResult<{
201
245
  branchName: string;
202
246
  created: boolean;