staticforge 0.0.0-stage → 0.1.0

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.
Files changed (123) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +49 -2
  3. package/dist/.tsbuildinfo +1 -0
  4. package/dist/bin.d.ts +3 -0
  5. package/dist/bin.d.ts.map +1 -0
  6. package/dist/bin.js +4 -0
  7. package/dist/bin.js.map +1 -0
  8. package/dist/browser.d.ts +3 -0
  9. package/dist/browser.d.ts.map +1 -0
  10. package/dist/browser.js +18 -0
  11. package/dist/browser.js.map +1 -0
  12. package/dist/cloud.d.ts +31 -0
  13. package/dist/cloud.d.ts.map +1 -0
  14. package/dist/cloud.js +102 -0
  15. package/dist/cloud.js.map +1 -0
  16. package/dist/command.d.ts +54 -0
  17. package/dist/command.d.ts.map +1 -0
  18. package/dist/command.js +70 -0
  19. package/dist/command.js.map +1 -0
  20. package/dist/commands/build.d.ts +4 -0
  21. package/dist/commands/build.d.ts.map +1 -0
  22. package/dist/commands/build.js +54 -0
  23. package/dist/commands/build.js.map +1 -0
  24. package/dist/commands/check.d.ts +4 -0
  25. package/dist/commands/check.d.ts.map +1 -0
  26. package/dist/commands/check.js +100 -0
  27. package/dist/commands/check.js.map +1 -0
  28. package/dist/commands/config.d.ts +4 -0
  29. package/dist/commands/config.d.ts.map +1 -0
  30. package/dist/commands/config.js +27 -0
  31. package/dist/commands/config.js.map +1 -0
  32. package/dist/commands/deploy.d.ts +4 -0
  33. package/dist/commands/deploy.d.ts.map +1 -0
  34. package/dist/commands/deploy.js +184 -0
  35. package/dist/commands/deploy.js.map +1 -0
  36. package/dist/commands/dev.d.ts +4 -0
  37. package/dist/commands/dev.d.ts.map +1 -0
  38. package/dist/commands/dev.js +81 -0
  39. package/dist/commands/dev.js.map +1 -0
  40. package/dist/commands/iac.d.ts +4 -0
  41. package/dist/commands/iac.d.ts.map +1 -0
  42. package/dist/commands/iac.js +64 -0
  43. package/dist/commands/iac.js.map +1 -0
  44. package/dist/commands/init.d.ts +4 -0
  45. package/dist/commands/init.d.ts.map +1 -0
  46. package/dist/commands/init.js +55 -0
  47. package/dist/commands/init.js.map +1 -0
  48. package/dist/commands/mcp.d.ts +4 -0
  49. package/dist/commands/mcp.d.ts.map +1 -0
  50. package/dist/commands/mcp.js +46 -0
  51. package/dist/commands/mcp.js.map +1 -0
  52. package/dist/commands/new.d.ts +4 -0
  53. package/dist/commands/new.d.ts.map +1 -0
  54. package/dist/commands/new.js +30 -0
  55. package/dist/commands/new.js.map +1 -0
  56. package/dist/commands/preview.d.ts +4 -0
  57. package/dist/commands/preview.d.ts.map +1 -0
  58. package/dist/commands/preview.js +34 -0
  59. package/dist/commands/preview.js.map +1 -0
  60. package/dist/commands/provision.d.ts +11 -0
  61. package/dist/commands/provision.d.ts.map +1 -0
  62. package/dist/commands/provision.js +133 -0
  63. package/dist/commands/provision.js.map +1 -0
  64. package/dist/commands/schema.d.ts +4 -0
  65. package/dist/commands/schema.d.ts.map +1 -0
  66. package/dist/commands/schema.js +21 -0
  67. package/dist/commands/schema.js.map +1 -0
  68. package/dist/commands/version.d.ts +4 -0
  69. package/dist/commands/version.d.ts.map +1 -0
  70. package/dist/commands/version.js +17 -0
  71. package/dist/commands/version.js.map +1 -0
  72. package/dist/context.d.ts +27 -0
  73. package/dist/context.d.ts.map +1 -0
  74. package/dist/context.js +19 -0
  75. package/dist/context.js.map +1 -0
  76. package/dist/io.d.ts +19 -0
  77. package/dist/io.d.ts.map +1 -0
  78. package/dist/io.js +34 -0
  79. package/dist/io.js.map +1 -0
  80. package/dist/main.d.ts +10 -0
  81. package/dist/main.d.ts.map +1 -0
  82. package/dist/main.js +81 -0
  83. package/dist/main.js.map +1 -0
  84. package/dist/mcp/invoke.d.ts +29 -0
  85. package/dist/mcp/invoke.d.ts.map +1 -0
  86. package/dist/mcp/invoke.js +82 -0
  87. package/dist/mcp/invoke.js.map +1 -0
  88. package/dist/mcp/server.d.ts +25 -0
  89. package/dist/mcp/server.d.ts.map +1 -0
  90. package/dist/mcp/server.js +531 -0
  91. package/dist/mcp/server.js.map +1 -0
  92. package/dist/output.d.ts +17 -0
  93. package/dist/output.d.ts.map +1 -0
  94. package/dist/output.js +37 -0
  95. package/dist/output.js.map +1 -0
  96. package/dist/paths.d.ts +3 -0
  97. package/dist/paths.d.ts.map +1 -0
  98. package/dist/paths.js +9 -0
  99. package/dist/paths.js.map +1 -0
  100. package/dist/project.d.ts +10 -0
  101. package/dist/project.d.ts.map +1 -0
  102. package/dist/project.js +20 -0
  103. package/dist/project.js.map +1 -0
  104. package/dist/schemas.d.ts +16 -0
  105. package/dist/schemas.d.ts.map +1 -0
  106. package/dist/schemas.js +241 -0
  107. package/dist/schemas.js.map +1 -0
  108. package/dist/server-options.d.ts +12 -0
  109. package/dist/server-options.d.ts.map +1 -0
  110. package/dist/server-options.js +26 -0
  111. package/dist/server-options.js.map +1 -0
  112. package/dist/version.d.ts +3 -0
  113. package/dist/version.d.ts.map +1 -0
  114. package/dist/version.js +4 -0
  115. package/dist/version.js.map +1 -0
  116. package/dist/workers.d.ts +7 -0
  117. package/dist/workers.d.ts.map +1 -0
  118. package/dist/workers.js +20 -0
  119. package/dist/workers.js.map +1 -0
  120. package/package.json +64 -3
  121. package/schema/diagnostics.schema.json +183 -0
  122. package/schema/output.schema.json +1537 -0
  123. package/schema/staticforge.schema.json +649 -0
@@ -0,0 +1,184 @@
1
+ import { join, resolve } from 'node:path';
2
+ import { ErrorCode, SforgeError, countBySeverity, createWorkerPool, formatDiagnostic, poolSize, } from '@staticforge/core';
3
+ import { action } from '../command.js';
4
+ import { confirmAction, deployerFor, targetContext, truthy } from '../cloud.js';
5
+ import { displayPath } from '../paths.js';
6
+ import { loadProjectConfig } from '../project.js';
7
+ import { VERSION } from '../version.js';
8
+ import { addWorkersOption, withWorkers } from '../workers.js';
9
+ function formatBytes(bytes) {
10
+ if (bytes < 1024)
11
+ return `${bytes} B`;
12
+ if (bytes < 1024 * 1024)
13
+ return `${(bytes / 1024).toFixed(1)} KiB`;
14
+ return `${(bytes / 1024 / 1024).toFixed(1)} MiB`;
15
+ }
16
+ function describeDeploy(result) {
17
+ const verb = result.dryRun ? 'Would deploy' : 'Deployed';
18
+ const lines = [
19
+ `${verb} ${result.preview ? `preview ${result.versionId}` : `version ${result.versionId}`} to "${result.target}": ` +
20
+ `${result.uploaded} uploaded (${formatBytes(result.bytes)}), ${result.copied} copied, ` +
21
+ `${result.skipped} unchanged, ${result.deleted} removed`,
22
+ ];
23
+ if (result.pruned.length > 0)
24
+ lines.push(`Removed old versions: ${result.pruned.join(', ')}`);
25
+ if (result.invalidated)
26
+ lines.push('Invalidated the CloudFront cache (/*).');
27
+ lines.push(`${result.dryRun ? 'Would be live' : 'Live'} at ${result.url}`);
28
+ return lines.join('\n');
29
+ }
30
+ /** Run the checker on a finished build; throw SF_CHECK_FAILED at or above check.failOn. */
31
+ async function checkBeforeDeploy(ctx, options) {
32
+ const { checkBuild, finalizeDiagnostics } = await import('@staticforge/checker');
33
+ const { config } = options;
34
+ const headless = options.headless ?? config.check.headless;
35
+ const checked = await checkBuild({
36
+ rootDir: options.rootDir,
37
+ config,
38
+ build: options.build,
39
+ headless,
40
+ requireBrowser: options.headless === true || truthy(ctx.io.env.CI),
41
+ ...(ctx.io.env.SFORGE_CHROMIUM_PATH && { executablePath: ctx.io.env.SFORGE_CHROMIUM_PATH }),
42
+ ...(options.pool && { pool: options.pool }),
43
+ logger: ctx.logger,
44
+ });
45
+ const diagnostics = finalizeDiagnostics(checked.findings, config.check.ignore);
46
+ const summary = countBySeverity(diagnostics);
47
+ const failing = diagnostics.filter((d) => d.severity === 'error' || (config.check.failOn === 'warning' && d.severity === 'warning'));
48
+ if (failing.length > 0) {
49
+ if (!ctx.json)
50
+ for (const d of failing)
51
+ ctx.logger.error(formatDiagnostic(d));
52
+ throw new SforgeError(ErrorCode.CheckFailed, `The check found ${failing.length} problem${failing.length === 1 ? '' : 's'} at or above "${config.check.failOn}"; nothing was deployed`, {
53
+ details: { summary, diagnostics: failing },
54
+ hint: 'Fix them (see `sforge check`), or deploy anyway with --no-check.',
55
+ });
56
+ }
57
+ return { summary, rendered: checked.rendered };
58
+ }
59
+ export function registerDeployCommands(program, runtime) {
60
+ addWorkersOption(program
61
+ .command('deploy')
62
+ .description('Build, check and deploy the site to a provisioned target')
63
+ .argument('<target>', 'target name from the config')
64
+ .option('--preview <id>', 'deploy a PR preview (e.g. pr-42) instead of production')
65
+ .option('--no-build', 'deploy the existing build in build.outDir')
66
+ .option('--no-check', 'deploy even if `sforge check` would fail')
67
+ .option('--headless', 'run rendered checks in headless Chromium (default: check.headless)')
68
+ .option('--no-headless', 'skip rendered checks')
69
+ .option('--invalidate', 'invalidate the CDN cache afterwards (normally unnecessary)')
70
+ .option('--dry-run', 'show what would be uploaded, change nothing')).action(action(runtime, async (ctx, { args, options }) => {
71
+ const loaded = await loadProjectConfig(ctx);
72
+ const { rootDir } = loaded;
73
+ const config = withWorkers(loaded.config, options);
74
+ const target = await targetContext(runtime, ctx, loaded, args[0]);
75
+ const preview = options.preview;
76
+ if (preview !== undefined)
77
+ (await import('@staticforge/provider-api')).assertPreviewId(preview);
78
+ const deployer = await deployerFor(ctx, target);
79
+ const outDir = resolve(rootDir, config.build.outDir);
80
+ const previewBaseUrl = preview === undefined ? undefined : deployer.previewBaseUrl?.(preview);
81
+ let check;
82
+ if (options.build !== false) {
83
+ // One pool for the build and the check.
84
+ const size = poolSize(config.build.workers);
85
+ const pool = size > 0 ? createWorkerPool(size) : undefined;
86
+ try {
87
+ const { buildSite } = await import('@staticforge/build');
88
+ // Previews get their own canonical URLs, feeds and sitemap.
89
+ const build = await buildSite({
90
+ rootDir,
91
+ config,
92
+ ...(previewBaseUrl !== undefined && { baseUrl: previewBaseUrl }),
93
+ generator: `staticforge ${VERSION}`,
94
+ logger: ctx.logger,
95
+ ...(pool && { pool }),
96
+ });
97
+ if (!build.ok) {
98
+ throw new SforgeError(ErrorCode.CheckFailed, 'The build failed; nothing was deployed', {
99
+ details: { diagnostics: build.diagnostics.filter((d) => d.severity === 'error') },
100
+ });
101
+ }
102
+ if (options.check !== false) {
103
+ check = await checkBeforeDeploy(ctx, {
104
+ rootDir,
105
+ config,
106
+ build,
107
+ ...(options.headless !== undefined && { headless: options.headless }),
108
+ ...(pool && { pool }),
109
+ });
110
+ }
111
+ }
112
+ finally {
113
+ await pool?.close();
114
+ }
115
+ }
116
+ else {
117
+ ctx.logger.warn('--no-build: deploying the existing build, which is not checked again');
118
+ }
119
+ const result = await deployer.deploy({
120
+ buildDir: outDir,
121
+ ...(preview !== undefined && { preview }),
122
+ invalidate: options.invalidate === true,
123
+ dryRun: options.dryRun === true,
124
+ });
125
+ return {
126
+ data: { ...result, buildDir: outDir, ...(check && { check }) },
127
+ text: `${describeDeploy(result)}\nBuild: ${displayPath(ctx.cwd, join(outDir))}`,
128
+ };
129
+ }));
130
+ program
131
+ .command('versions')
132
+ .description('List the deployed versions and previews of a target')
133
+ .argument('<target>', 'target name from the config')
134
+ .action(action(runtime, async (ctx, { args }) => {
135
+ const loaded = await loadProjectConfig(ctx);
136
+ const target = await targetContext(runtime, ctx, loaded, args[0]);
137
+ const versions = await (await deployerFor(ctx, target)).versions();
138
+ const rows = versions.map((v) => `${v.active ? '*' : ' '} ${v.id.padEnd(28)} ${v.createdAt} ${String(v.files).padStart(5)} files ${formatBytes(v.bytes)}` +
139
+ (v.preview ? ` preview${v.url ? ` ${v.url}` : ''}` : ''));
140
+ return {
141
+ data: { target: target.targetName, versions },
142
+ text: rows.length > 0
143
+ ? rows.join('\n')
144
+ : `Nothing has been deployed to "${target.targetName}".`,
145
+ };
146
+ }));
147
+ program
148
+ .command('rollback')
149
+ .description('Serve an earlier version again (default: the one before the active version)')
150
+ .argument('<target>', 'target name from the config')
151
+ .option('--to <versionId>', 'version to serve (see `sforge versions`)')
152
+ .option('-y, --yes', 'roll back without asking')
153
+ .action(action(runtime, async (ctx, { args, options }) => {
154
+ const loaded = await loadProjectConfig(ctx);
155
+ const target = await targetContext(runtime, ctx, loaded, args[0]);
156
+ const deployer = await deployerFor(ctx, target);
157
+ const to = options.to;
158
+ await confirmAction(ctx, options.yes === true, `Roll "${target.targetName}" back to ${to ?? 'the previous version'}?`);
159
+ const result = await deployer.rollback(to);
160
+ return {
161
+ data: result,
162
+ text: `"${result.target}" now serves ${result.versionId} (was ${result.previousVersionId ?? 'none'}) at ${result.url}`,
163
+ };
164
+ }));
165
+ program
166
+ .command('preview-destroy')
167
+ .description('Remove a PR preview')
168
+ .argument('<target>', 'target name from the config')
169
+ .argument('<id>', 'preview id, e.g. pr-42')
170
+ .action(action(runtime, async (ctx, { args }) => {
171
+ const loaded = await loadProjectConfig(ctx);
172
+ const target = await targetContext(runtime, ctx, loaded, args[0]);
173
+ const result = await (await deployerFor(ctx, target)).destroyPreview(args[1]);
174
+ return {
175
+ data: result,
176
+ text: result.existed
177
+ ? `Removed preview ${result.previewId}${result.deleted > 0 ? ` (${result.deleted} files)` : ''}`
178
+ : result.deleted > 0
179
+ ? `No preview ${result.previewId} was recorded; removed ${result.deleted} leftover files`
180
+ : `No preview ${result.previewId} exists`,
181
+ };
182
+ }));
183
+ }
184
+ //# sourceMappingURL=deploy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deploy.js","sourceRoot":"","sources":["../../src/commands/deploy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAG1C,OAAO,EACL,SAAS,EACT,WAAW,EAEX,eAAe,EACf,gBAAgB,EAChB,gBAAgB,EAChB,QAAQ,GACT,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAgB,MAAM,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAEhF,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE9D,SAAS,WAAW,CAAC,KAAa;IAChC,IAAI,KAAK,GAAG,IAAI;QAAE,OAAO,GAAG,KAAK,IAAI,CAAC;IACtC,IAAI,KAAK,GAAG,IAAI,GAAG,IAAI;QAAE,OAAO,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC;IACnE,OAAO,GAAG,CAAC,KAAK,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC;AACnD,CAAC;AAED,SAAS,cAAc,CAAC,MAAoB;IAC1C,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,UAAU,CAAC;IACzD,MAAM,KAAK,GAAG;QACZ,GAAG,IAAI,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,WAAW,MAAM,CAAC,SAAS,EAAE,QAAQ,MAAM,CAAC,MAAM,KAAK;YACjH,GAAG,MAAM,CAAC,QAAQ,cAAc,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,MAAM,CAAC,MAAM,WAAW;YACvF,GAAG,MAAM,CAAC,OAAO,eAAe,MAAM,CAAC,OAAO,UAAU;KAC3D,CAAC;IACF,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC;QAAE,KAAK,CAAC,IAAI,CAAC,yBAAyB,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC9F,IAAI,MAAM,CAAC,WAAW;QAAE,KAAK,CAAC,IAAI,CAAC,wCAAwC,CAAC,CAAC;IAC7E,KAAK,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,MAAM,OAAO,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC;IAC3E,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,2FAA2F;AAC3F,KAAK,UAAU,iBAAiB,CAC9B,GAAmB,EACnB,OAGC;IAED,MAAM,EAAE,UAAU,EAAE,mBAAmB,EAAE,GAAG,MAAM,MAAM,CAAC,sBAAsB,CAAC,CAAC;IACjF,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IAC3B,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC;IAC3D,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC;QAC/B,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,MAAM;QACN,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,QAAQ;QACR,cAAc,EAAE,OAAO,CAAC,QAAQ,KAAK,IAAI,IAAI,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC;QAClE,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,oBAAoB,IAAI,EAAE,cAAc,EAAE,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,oBAAoB,EAAE,CAAC;QAC3F,GAAG,CAAC,OAAO,CAAC,IAAI,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC;QAC3C,MAAM,EAAE,GAAG,CAAC,MAAM;KACnB,CAAC,CAAC;IACH,MAAM,WAAW,GAAG,mBAAmB,CAAC,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC/E,MAAM,OAAO,GAAG,eAAe,CAAC,WAAW,CAAC,CAAC;IAC7C,MAAM,OAAO,GAAG,WAAW,CAAC,MAAM,CAChC,CAAC,CAAC,EAAE,EAAE,CACJ,CAAC,CAAC,QAAQ,KAAK,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,CAAC,QAAQ,KAAK,SAAS,CAAC,CAC5F,CAAC;IACF,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,IAAI,CAAC,GAAG,CAAC,IAAI;YAAE,KAAK,MAAM,CAAC,IAAI,OAAO;gBAAE,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC;QAC9E,MAAM,IAAI,WAAW,CACnB,SAAS,CAAC,WAAW,EACrB,mBAAmB,OAAO,CAAC,MAAM,WAAW,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,iBAAiB,MAAM,CAAC,KAAK,CAAC,MAAM,yBAAyB,EACxI;YACE,OAAO,EAAE,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE;YAC1C,IAAI,EAAE,kEAAkE;SACzE,CACF,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,OAAgB,EAAE,OAAgB;IACvE,gBAAgB,CACd,OAAO;SACJ,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,0DAA0D,CAAC;SACvE,QAAQ,CAAC,UAAU,EAAE,6BAA6B,CAAC;SACnD,MAAM,CAAC,gBAAgB,EAAE,wDAAwD,CAAC;SAClF,MAAM,CAAC,YAAY,EAAE,2CAA2C,CAAC;SACjE,MAAM,CAAC,YAAY,EAAE,0CAA0C,CAAC;SAChE,MAAM,CAAC,YAAY,EAAE,oEAAoE,CAAC;SAC1F,MAAM,CAAC,eAAe,EAAE,sBAAsB,CAAC;SAC/C,MAAM,CAAC,cAAc,EAAE,4DAA4D,CAAC;SACpF,MAAM,CAAC,WAAW,EAAE,6CAA6C,CAAC,CACtE,CAAC,MAAM,CACN,MAAM,CAAC,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE;QAC/C,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,GAAG,CAAC,CAAC;QAC5C,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,CAAC;QAC3B,MAAM,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACnD,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC,CAAW,CAAC,CAAC;QAC5E,MAAM,OAAO,GAAG,OAAO,CAAC,OAA6B,CAAC;QACtD,IAAI,OAAO,KAAK,SAAS;YACvB,CAAC,MAAM,MAAM,CAAC,2BAA2B,CAAC,CAAC,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;QACvE,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QAEhD,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QACrD,MAAM,cAAc,GAAG,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,cAAc,EAAE,CAAC,OAAO,CAAC,CAAC;QAC9F,IAAI,KAAgE,CAAC;QACrE,IAAI,OAAO,CAAC,KAAK,KAAK,KAAK,EAAE,CAAC;YAC5B,wCAAwC;YACxC,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YAC5C,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;YAC3D,IAAI,CAAC;gBACH,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC;gBACzD,4DAA4D;gBAC5D,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC;oBAC5B,OAAO;oBACP,MAAM;oBACN,GAAG,CAAC,cAAc,KAAK,SAAS,IAAI,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC;oBAChE,SAAS,EAAE,eAAe,OAAO,EAAE;oBACnC,MAAM,EAAE,GAAG,CAAC,MAAM;oBAClB,GAAG,CAAC,IAAI,IAAI,EAAE,IAAI,EAAE,CAAC;iBACtB,CAAC,CAAC;gBACH,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC;oBACd,MAAM,IAAI,WAAW,CAAC,SAAS,CAAC,WAAW,EAAE,wCAAwC,EAAE;wBACrF,OAAO,EAAE,EAAE,WAAW,EAAE,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,EAAE;qBAClF,CAAC,CAAC;gBACL,CAAC;gBACD,IAAI,OAAO,CAAC,KAAK,KAAK,KAAK,EAAE,CAAC;oBAC5B,KAAK,GAAG,MAAM,iBAAiB,CAAC,GAAG,EAAE;wBACnC,OAAO;wBACP,MAAM;wBACN,KAAK;wBACL,GAAG,CAAC,OAAO,CAAC,QAAQ,KAAK,SAAS,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAmB,EAAE,CAAC;wBAChF,GAAG,CAAC,IAAI,IAAI,EAAE,IAAI,EAAE,CAAC;qBACtB,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;oBAAS,CAAC;gBACT,MAAM,IAAI,EAAE,KAAK,EAAE,CAAC;YACtB,CAAC;QACH,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,sEAAsE,CAAC,CAAC;QAC1F,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC;YACnC,QAAQ,EAAE,MAAM;YAChB,GAAG,CAAC,OAAO,KAAK,SAAS,IAAI,EAAE,OAAO,EAAE,CAAC;YACzC,UAAU,EAAE,OAAO,CAAC,UAAU,KAAK,IAAI;YACvC,MAAM,EAAE,OAAO,CAAC,MAAM,KAAK,IAAI;SAChC,CAAC,CAAC;QACH,OAAO;YACL,IAAI,EAAE,EAAE,GAAG,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,CAAC,KAAK,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE;YAC9D,IAAI,EAAE,GAAG,cAAc,CAAC,MAAM,CAAC,YAAY,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE;SAChF,CAAC;IACJ,CAAC,CAAC,CACH,CAAC;IAEF,OAAO;SACJ,OAAO,CAAC,UAAU,CAAC;SACnB,WAAW,CAAC,qDAAqD,CAAC;SAClE,QAAQ,CAAC,UAAU,EAAE,6BAA6B,CAAC;SACnD,MAAM,CACL,MAAM,CAAC,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE;QACtC,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,GAAG,CAAC,CAAC;QAC5C,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC,CAAW,CAAC,CAAC;QAC5E,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,WAAW,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;QACnE,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CACvB,CAAC,CAAC,EAAE,EAAE,CACJ,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,SAAS,KAAK,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE;YAC1H,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAC5D,CAAC;QACF,OAAO;YACL,IAAI,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,UAAU,EAAE,QAAQ,EAAE;YAC7C,IAAI,EACF,IAAI,CAAC,MAAM,GAAG,CAAC;gBACb,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;gBACjB,CAAC,CAAC,iCAAiC,MAAM,CAAC,UAAU,IAAI;SAC7D,CAAC;IACJ,CAAC,CAAC,CACH,CAAC;IAEJ,OAAO;SACJ,OAAO,CAAC,UAAU,CAAC;SACnB,WAAW,CAAC,6EAA6E,CAAC;SAC1F,QAAQ,CAAC,UAAU,EAAE,6BAA6B,CAAC;SACnD,MAAM,CAAC,kBAAkB,EAAE,0CAA0C,CAAC;SACtE,MAAM,CAAC,WAAW,EAAE,0BAA0B,CAAC;SAC/C,MAAM,CACL,MAAM,CAAC,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE;QAC/C,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,GAAG,CAAC,CAAC;QAC5C,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC,CAAW,CAAC,CAAC;QAC5E,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QAChD,MAAM,EAAE,GAAG,OAAO,CAAC,EAAwB,CAAC;QAC5C,MAAM,aAAa,CACjB,GAAG,EACH,OAAO,CAAC,GAAG,KAAK,IAAI,EACpB,SAAS,MAAM,CAAC,UAAU,aAAa,EAAE,IAAI,sBAAsB,GAAG,CACvE,CAAC;QACF,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QAC3C,OAAO;YACL,IAAI,EAAE,MAAM;YACZ,IAAI,EAAE,IAAI,MAAM,CAAC,MAAM,gBAAgB,MAAM,CAAC,SAAS,SAAS,MAAM,CAAC,iBAAiB,IAAI,MAAM,QAAQ,MAAM,CAAC,GAAG,EAAE;SACvH,CAAC;IACJ,CAAC,CAAC,CACH,CAAC;IAEJ,OAAO;SACJ,OAAO,CAAC,iBAAiB,CAAC;SAC1B,WAAW,CAAC,qBAAqB,CAAC;SAClC,QAAQ,CAAC,UAAU,EAAE,6BAA6B,CAAC;SACnD,QAAQ,CAAC,MAAM,EAAE,wBAAwB,CAAC;SAC1C,MAAM,CACL,MAAM,CAAC,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE;QACtC,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,GAAG,CAAC,CAAC;QAC5C,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC,CAAW,CAAC,CAAC;QAC5E,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,WAAW,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAW,CAAC,CAAC;QACxF,OAAO;YACL,IAAI,EAAE,MAAM;YACZ,IAAI,EAAE,MAAM,CAAC,OAAO;gBAClB,CAAC,CAAC,mBAAmB,MAAM,CAAC,SAAS,GAAG,MAAM,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,OAAO,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE;gBAChG,CAAC,CAAC,MAAM,CAAC,OAAO,GAAG,CAAC;oBAClB,CAAC,CAAC,cAAc,MAAM,CAAC,SAAS,0BAA0B,MAAM,CAAC,OAAO,iBAAiB;oBACzF,CAAC,CAAC,cAAc,MAAM,CAAC,SAAS,SAAS;SAC9C,CAAC;IACJ,CAAC,CAAC,CACH,CAAC;AACN,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { Command } from 'commander';
2
+ import { type Runtime } from '../command.js';
3
+ export declare function registerDevCommand(program: Command, runtime: Runtime): void;
4
+ //# sourceMappingURL=dev.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../src/commands/dev.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIzC,OAAO,EAAE,KAAK,OAAO,EAAU,MAAM,eAAe,CAAC;AA2BrD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CA6D3E"}
@@ -0,0 +1,81 @@
1
+ import { formatDiagnostic } from '@staticforge/core';
2
+ import { openBrowser } from '../browser.js';
3
+ import { action } from '../command.js';
4
+ import { loadProjectConfig } from '../project.js';
5
+ import { addServerOptions, hostFrom } from '../server-options.js';
6
+ import { VERSION } from '../version.js';
7
+ import { addWorkersOption, withWorkers } from '../workers.js';
8
+ function logBuild(state, problems, logger) {
9
+ if (state.error !== undefined) {
10
+ logger.error(`Build failed: ${state.error.message}`);
11
+ if (state.error.hint !== undefined)
12
+ logger.info(`hint: ${state.error.hint}`);
13
+ return;
14
+ }
15
+ for (const d of problems) {
16
+ if (d.severity === 'error')
17
+ logger.error(formatDiagnostic(d));
18
+ else
19
+ logger.warn(formatDiagnostic(d));
20
+ }
21
+ const error = problems.filter((d) => d.severity === 'error').length;
22
+ const warning = problems.length - error;
23
+ const trigger = state.changed.length > 0
24
+ ? ` (${state.changed.slice(0, 3).join(', ')}${state.changed.length > 3 ? ', …' : ''})`
25
+ : '';
26
+ logger.info(`Built in ${state.result?.durationMs ?? 0}ms${trigger}: ${error} errors, ${warning} warnings`);
27
+ }
28
+ export function registerDevCommand(program, runtime) {
29
+ addServerOptions(addWorkersOption(program
30
+ .command('dev')
31
+ .description('Build and serve the site locally, rebuilding and reloading the browser on changes')
32
+ .option('--drafts', 'include pages marked draft: true')), 4321).action(action(runtime, async (ctx, { options }) => {
33
+ const { problemsOf, startDevServer } = await import('@staticforge/dev-server');
34
+ const flags = options;
35
+ const server = await startDevServer({
36
+ loadConfig: async () => {
37
+ const loaded = await loadProjectConfig(ctx);
38
+ return { ...loaded, config: withWorkers(loaded.config, options) };
39
+ },
40
+ host: hostFrom(flags, ctx.logger),
41
+ port: flags.port,
42
+ ...(flags.drafts === true && { drafts: true }),
43
+ generator: `staticforge ${VERSION}`,
44
+ logger: ctx.logger,
45
+ onBuild: (state) => logBuild(state, problemsOf(state), ctx.logger),
46
+ });
47
+ if (flags.open && ctx.interactive)
48
+ openBrowser(server.url);
49
+ const stopped = new Promise((resolve) => {
50
+ ctx.io.onShutdown(() => {
51
+ ctx.logger.info('Stopping dev server');
52
+ void server.close().then(resolve);
53
+ });
54
+ });
55
+ // The latest build: the first one now, later ones for in-process callers.
56
+ const data = () => {
57
+ const state = server.state;
58
+ return {
59
+ url: server.url,
60
+ host: server.host,
61
+ port: server.port,
62
+ rootDir: server.rootDir,
63
+ build: {
64
+ ok: state.ok,
65
+ summary: state.result?.summary,
66
+ pages: state.result?.pages,
67
+ diagnostics: state.diagnostics,
68
+ error: state.error,
69
+ },
70
+ };
71
+ };
72
+ return {
73
+ ok: true,
74
+ data: data(),
75
+ live: data,
76
+ text: `Dev server running at ${server.url}\nWatching ${server.rootDir} for changes. Press Ctrl+C to stop.`,
77
+ wait: stopped,
78
+ };
79
+ }));
80
+ }
81
+ //# sourceMappingURL=dev.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dev.js","sourceRoot":"","sources":["../../src/commands/dev.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { type Command } from 'commander';
2
+ import { type Runtime } from '../command.js';
3
+ export declare function registerIacCommand(program: Command, runtime: Runtime): void;
4
+ //# sourceMappingURL=iac.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"iac.d.ts","sourceRoot":"","sources":["../../src/commands/iac.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,OAAO,EAAE,MAAM,WAAW,CAAC;AAEnD,OAAO,EAAE,KAAK,OAAO,EAAU,MAAM,eAAe,CAAC;AAkBrD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CA6D3E"}
@@ -0,0 +1,64 @@
1
+ import { Argument } from 'commander';
2
+ import { action } from '../command.js';
3
+ import { targetContext } from '../cloud.js';
4
+ import { displayPath } from '../paths.js';
5
+ import { loadProjectConfig } from '../project.js';
6
+ import { localStateFrom } from './provision.js';
7
+ const ENGINE_COMMANDS = [
8
+ 'init',
9
+ 'plan',
10
+ 'apply',
11
+ 'output',
12
+ 'validate',
13
+ 'state',
14
+ 'show',
15
+ 'import',
16
+ 'console',
17
+ ];
18
+ export function registerIacCommand(program, runtime) {
19
+ program
20
+ .command('iac')
21
+ .description("Low-level access to a target's generated OpenTofu/Terraform workspace (.sforge/iac/<target>/)")
22
+ .addArgument(new Argument('<command>', 'path, or an engine command').choices(['path', ...ENGINE_COMMANDS]))
23
+ .argument('<target>', 'target name from the config')
24
+ .argument('[args...]', 'extra engine arguments, after --')
25
+ .option('--local-state', 'use the state in .sforge/iac/<target>/')
26
+ .option('--force-local-state', 'allow --local-state in CI')
27
+ .addHelpText('after', '\nExamples:\n sforge iac path staging\n sforge iac plan staging -- -target=module.site.aws_s3_bucket.site\n sforge iac output staging -- -json')
28
+ .action(action(runtime, async (ctx, { args, options }) => {
29
+ const { passthrough, prepareWorkspace } = await import('@staticforge/iac');
30
+ const [command, name, extra] = args;
31
+ const loaded = await loadProjectConfig(ctx);
32
+ const target = await targetContext(runtime, ctx, loaded, name, localStateFrom(options, ctx.io.env));
33
+ if (command === 'path') {
34
+ const { ws } = await prepareWorkspace(target.iac);
35
+ return { data: { target: name, workspace: ws.dir, engine: ws.engine }, text: ws.dir };
36
+ }
37
+ // Engine output is for humans: it goes to stderr, keeping stdout for the result.
38
+ const result = await passthrough({
39
+ ...target.iac,
40
+ command: command,
41
+ args: extra ?? [],
42
+ onStdout: (chunk) => (ctx.json ? ctx.io.stderr : ctx.io.stdout).write(chunk),
43
+ onStderr: (chunk) => ctx.io.stderr.write(chunk),
44
+ interactive: ctx.interactive,
45
+ });
46
+ // plan -detailed-exitcode uses 2 for "changes"; anything else non-zero failed.
47
+ const failed = result.exitCode !== 0 &&
48
+ !(command === 'plan' && result.exitCode === 2 && extra?.includes('-detailed-exitcode'));
49
+ return {
50
+ ok: !failed,
51
+ data: {
52
+ target: name,
53
+ command,
54
+ exitCode: result.exitCode,
55
+ workspace: result.workspace,
56
+ diagnostics: result.diagnostics,
57
+ },
58
+ ...(failed && {
59
+ text: `${loaded.config.iac.engine} ${command} failed with exit code ${result.exitCode} in ${displayPath(ctx.cwd, result.workspace)}`,
60
+ }),
61
+ };
62
+ }));
63
+ }
64
+ //# sourceMappingURL=iac.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"iac.js","sourceRoot":"","sources":["../../src/commands/iac.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAgB,MAAM,WAAW,CAAC;AAEnD,OAAO,EAAgB,MAAM,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEhD,MAAM,eAAe,GAAyB;IAC5C,MAAM;IACN,MAAM;IACN,OAAO;IACP,QAAQ;IACR,UAAU;IACV,OAAO;IACP,MAAM;IACN,QAAQ;IACR,SAAS;CACV,CAAC;AAEF,MAAM,UAAU,kBAAkB,CAAC,OAAgB,EAAE,OAAgB;IACnE,OAAO;SACJ,OAAO,CAAC,KAAK,CAAC;SACd,WAAW,CACV,+FAA+F,CAChG;SACA,WAAW,CACV,IAAI,QAAQ,CAAC,WAAW,EAAE,4BAA4B,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,GAAG,eAAe,CAAC,CAAC,CAC9F;SACA,QAAQ,CAAC,UAAU,EAAE,6BAA6B,CAAC;SACnD,QAAQ,CAAC,WAAW,EAAE,kCAAkC,CAAC;SACzD,MAAM,CAAC,eAAe,EAAE,wCAAwC,CAAC;SACjE,MAAM,CAAC,qBAAqB,EAAE,2BAA2B,CAAC;SAC1D,WAAW,CACV,OAAO,EACP,mJAAmJ,CACpJ;SACA,MAAM,CACL,MAAM,CAA0B,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE;QACxE,MAAM,EAAE,WAAW,EAAE,gBAAgB,EAAE,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAC;QAC3E,MAAM,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,GAAG,IAAkC,CAAC;QAClE,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,GAAG,CAAC,CAAC;QAC5C,MAAM,MAAM,GAAG,MAAM,aAAa,CAChC,OAAO,EACP,GAAG,EACH,MAAM,EACN,IAAI,EACJ,cAAc,CAAC,OAAO,EAAE,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CACpC,CAAC;QACF,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;YACvB,MAAM,EAAE,EAAE,EAAE,GAAG,MAAM,gBAAgB,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAClD,OAAO,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,GAAG,EAAE,CAAC;QACxF,CAAC;QACD,iFAAiF;QACjF,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC;YAC/B,GAAG,MAAM,CAAC,GAAG;YACb,OAAO,EAAE,OAA6B;YACtC,IAAI,EAAE,KAAK,IAAI,EAAE;YACjB,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC;YAC5E,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC;YAC/C,WAAW,EAAE,GAAG,CAAC,WAAW;SAC7B,CAAC,CAAC;QACH,+EAA+E;QAC/E,MAAM,MAAM,GACV,MAAM,CAAC,QAAQ,KAAK,CAAC;YACrB,CAAC,CAAC,OAAO,KAAK,MAAM,IAAI,MAAM,CAAC,QAAQ,KAAK,CAAC,IAAI,KAAK,EAAE,QAAQ,CAAC,oBAAoB,CAAC,CAAC,CAAC;QAC1F,OAAO;YACL,EAAE,EAAE,CAAC,MAAM;YACX,IAAI,EAAE;gBACJ,MAAM,EAAE,IAAI;gBACZ,OAAO;gBACP,QAAQ,EAAE,MAAM,CAAC,QAAQ;gBACzB,SAAS,EAAE,MAAM,CAAC,SAAS;gBAC3B,WAAW,EAAE,MAAM,CAAC,WAAW;aAChC;YACD,GAAG,CAAC,MAAM,IAAI;gBACZ,IAAI,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,IAAI,OAAO,0BAA0B,MAAM,CAAC,QAAQ,OAAO,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,SAAS,CAAC,EAAE;aACrI,CAAC;SACH,CAAC;IACJ,CAAC,CAAC,CACH,CAAC;AACN,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { type Command } from 'commander';
2
+ import { type Runtime } from '../command.js';
3
+ export declare function registerInitCommand(program: Command, runtime: Runtime): void;
4
+ //# sourceMappingURL=init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,OAAO,EAAE,MAAM,WAAW,CAAC;AAEjD,OAAO,EAAE,KAAK,OAAO,EAAU,MAAM,eAAe,CAAC;AAGrD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CA0D5E"}
@@ -0,0 +1,55 @@
1
+ import { Option } from 'commander';
2
+ import { resolve } from 'node:path';
3
+ import { action } from '../command.js';
4
+ import { displayPath } from '../paths.js';
5
+ export function registerInitCommand(program, runtime) {
6
+ program
7
+ .command('init')
8
+ .description('Create a new site: config, starter content and styles')
9
+ .argument('[dir]', 'project directory (created if missing)', '.')
10
+ .option('--title <title>', 'site title (default: from the directory name)')
11
+ .option('--base-url <url>', 'production URL of the site', 'https://example.com')
12
+ .option('--language <tag>', 'BCP 47 language of the content', 'en')
13
+ .addOption(new Option('--format <format>', 'config file format')
14
+ .choices(['ts', 'json', 'yaml'])
15
+ .default('ts'))
16
+ .addOption(new Option('--provider <provider>', 'add a "staging" deploy target').choices([
17
+ 'aws',
18
+ 'azure',
19
+ ]))
20
+ .option('--region <region>', 'AWS region or Azure location for the target')
21
+ .option('--force', 'overwrite existing starter files')
22
+ .action(action(runtime, async (ctx, { args, options }) => {
23
+ const { initProject } = await import('@staticforge/build');
24
+ const dir = resolve(ctx.cwd, String(args[0]));
25
+ const result = initProject({
26
+ dir,
27
+ title: options.title,
28
+ baseUrl: options.baseUrl,
29
+ language: options.language,
30
+ format: options.format,
31
+ provider: options.provider,
32
+ region: options.region,
33
+ force: options.force === true,
34
+ });
35
+ const where = displayPath(ctx.cwd, dir);
36
+ const lines = [
37
+ ...result.created.map((path) => ` created ${path}`),
38
+ ...result.skipped.map((path) => ` skipped ${path} (exists)`),
39
+ '',
40
+ 'Next steps:',
41
+ ...(where === '.' ? [] : [` cd ${where}`]),
42
+ ' sforge dev # preview at http://127.0.0.1:4321 with live reload',
43
+ ' sforge check # accessibility and link checks',
44
+ ' sforge build',
45
+ ];
46
+ if (options.baseUrl === 'https://example.com') {
47
+ ctx.logger.warn('site.baseUrl is https://example.com; set it to your real URL before deploying');
48
+ }
49
+ return {
50
+ data: result,
51
+ text: `Initialized staticforge project in ${where}\n${lines.join('\n')}`,
52
+ };
53
+ }));
54
+ }
55
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { Command } from 'commander';
2
+ import type { Runtime } from '../command.js';
3
+ export declare function registerMcpCommand(program: Command, runtime: Runtime): void;
4
+ //# sourceMappingURL=mcp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../../src/commands/mcp.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAY7C,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAsC3E"}
@@ -0,0 +1,46 @@
1
+ import { createContext } from '../context.js';
2
+ /** Global options of `sforge mcp` that every tool call inherits. */
3
+ function inheritedArgs(opts) {
4
+ return [
5
+ ...(opts.config !== undefined ? ['--config', opts.config] : []),
6
+ ...(opts.quiet === true ? ['--quiet'] : []),
7
+ ...(opts.verbose === true ? ['--verbose'] : []),
8
+ ];
9
+ }
10
+ export function registerMcpCommand(program, runtime) {
11
+ program
12
+ .command('mcp')
13
+ .description('Serve the sforge commands to AI agents as Model Context Protocol tools (stdio transport)')
14
+ .option('--allow-infra', 'also offer the provision and destroy tools')
15
+ .action(async (_options, command) => {
16
+ const ctx = createContext(command, runtime.io);
17
+ // stdout carries the protocol: anything a library prints goes to stderr instead.
18
+ console.log = console.info = console.debug = console.error;
19
+ // Imported here: main.ts registers this command, so a static import would be a
20
+ // cycle, and the MCP SDK would slow down every other command.
21
+ const { run } = await import('../main.js');
22
+ const { createSforgeMcp } = await import('../mcp/server.js');
23
+ const { serveStdio } = await import('@modelcontextprotocol/server/stdio');
24
+ const mcp = createSforgeMcp({
25
+ run,
26
+ cwd: ctx.cwd,
27
+ globalArgs: inheritedArgs(command.optsWithGlobals()),
28
+ env: ctx.io.env,
29
+ allowInfra: command.opts().allowInfra === true,
30
+ log: (line) => ctx.io.stderr.write(`${line}\n`),
31
+ });
32
+ const handle = serveStdio(() => mcp.createServer(), {
33
+ onerror: (error) => ctx.logger.error(`MCP: ${error.message}`),
34
+ });
35
+ ctx.logger.debug(`sforge MCP server ready for ${ctx.cwd}`);
36
+ // Serve until the client closes stdin, or until SIGINT/SIGTERM.
37
+ await new Promise((resolve) => {
38
+ process.stdin.once('end', resolve);
39
+ process.stdin.once('close', resolve);
40
+ ctx.io.onShutdown(resolve);
41
+ });
42
+ await handle.close();
43
+ await mcp.close();
44
+ });
45
+ }
46
+ //# sourceMappingURL=mcp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../src/commands/mcp.ts"],"names":[],"mappings":"AAEA,OAAO,EAAsB,aAAa,EAAE,MAAM,eAAe,CAAC;AAElE,oEAAoE;AACpE,SAAS,aAAa,CAAC,IAAmB;IACxC,OAAO;QACL,GAAG,CAAC,IAAI,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/D,GAAG,CAAC,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3C,GAAG,CAAC,IAAI,CAAC,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;KAChD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,OAAgB,EAAE,OAAgB;IACnE,OAAO;SACJ,OAAO,CAAC,KAAK,CAAC;SACd,WAAW,CACV,0FAA0F,CAC3F;SACA,MAAM,CAAC,eAAe,EAAE,4CAA4C,CAAC;SACrE,MAAM,CAAC,KAAK,EAAE,QAAiB,EAAE,OAAgB,EAAE,EAAE;QACpD,MAAM,GAAG,GAAG,aAAa,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC;QAC/C,iFAAiF;QACjF,OAAO,CAAC,GAAG,GAAG,OAAO,CAAC,IAAI,GAAG,OAAO,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAC3D,+EAA+E;QAC/E,8DAA8D;QAC9D,MAAM,EAAE,GAAG,EAAE,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,CAAC;QAC3C,MAAM,EAAE,eAAe,EAAE,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAC;QAC7D,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,oCAAoC,CAAC,CAAC;QAC1E,MAAM,GAAG,GAAG,eAAe,CAAC;YAC1B,GAAG;YACH,GAAG,EAAE,GAAG,CAAC,GAAG;YACZ,UAAU,EAAE,aAAa,CAAC,OAAO,CAAC,eAAe,EAAiB,CAAC;YACnE,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC,GAAG;YACf,UAAU,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,UAAU,KAAK,IAAI;YAC9C,GAAG,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,IAAI,CAAC;SAChD,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,YAAY,EAAE,EAAE;YAClD,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,KAAK,CAAC,OAAO,EAAE,CAAC;SAC9D,CAAC,CAAC;QACH,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,+BAA+B,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC;QAE3D,gEAAgE;QAChE,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;YAClC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;YACnC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YACrC,GAAG,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QAC7B,CAAC,CAAC,CAAC;QACH,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QACrB,MAAM,GAAG,CAAC,KAAK,EAAE,CAAC;IACpB,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { type Command } from 'commander';
2
+ import { type Runtime } from '../command.js';
3
+ export declare function registerNewCommand(program: Command, runtime: Runtime): void;
4
+ //# sourceMappingURL=new.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"new.d.ts","sourceRoot":"","sources":["../../src/commands/new.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,KAAK,OAAO,EAAE,MAAM,WAAW,CAAC;AAC3D,OAAO,EAAE,KAAK,OAAO,EAAU,MAAM,eAAe,CAAC;AAGrD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAgC3E"}
@@ -0,0 +1,30 @@
1
+ import { Argument, Option } from 'commander';
2
+ import { action } from '../command.js';
3
+ import { loadProjectConfig } from '../project.js';
4
+ export function registerNewCommand(program, runtime) {
5
+ program
6
+ .command('new')
7
+ .description('Create a page or blog post with front-matter')
8
+ .addArgument(new Argument('<kind>', 'what to create').choices(['page', 'post']))
9
+ .argument('<path>', 'path inside content/, e.g. "about" or "guides/setup" (posts default to blog/)')
10
+ .option('--title <title>', 'title (default: from the path)')
11
+ .addOption(new Option('--format <format>', 'source format').choices(['md', 'html']).default('md'))
12
+ .option('--draft', 'mark as draft (excluded from builds unless --drafts)')
13
+ .option('--force', 'overwrite an existing file')
14
+ .action(action(runtime, async (ctx, { args, options }) => {
15
+ const { newContent } = await import('@staticforge/build');
16
+ const { config, rootDir } = await loadProjectConfig(ctx);
17
+ const result = newContent({
18
+ rootDir,
19
+ kind: args[0],
20
+ path: String(args[1]),
21
+ title: options.title,
22
+ format: options.format,
23
+ draft: options.draft === true,
24
+ force: options.force === true,
25
+ urls: config.build,
26
+ });
27
+ return { data: result, text: `Created ${result.file} (${result.url})` };
28
+ }));
29
+ }
30
+ //# sourceMappingURL=new.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"new.js","sourceRoot":"","sources":["../../src/commands/new.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAgB,MAAM,WAAW,CAAC;AAC3D,OAAO,EAAgB,MAAM,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAElD,MAAM,UAAU,kBAAkB,CAAC,OAAgB,EAAE,OAAgB;IACnE,OAAO;SACJ,OAAO,CAAC,KAAK,CAAC;SACd,WAAW,CAAC,8CAA8C,CAAC;SAC3D,WAAW,CAAC,IAAI,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;SAC/E,QAAQ,CACP,QAAQ,EACR,+EAA+E,CAChF;SACA,MAAM,CAAC,iBAAiB,EAAE,gCAAgC,CAAC;SAC3D,SAAS,CACR,IAAI,MAAM,CAAC,mBAAmB,EAAE,eAAe,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CACvF;SACA,MAAM,CAAC,SAAS,EAAE,sDAAsD,CAAC;SACzE,MAAM,CAAC,SAAS,EAAE,4BAA4B,CAAC;SAC/C,MAAM,CACL,MAAM,CAAC,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE;QAC/C,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC;QAC1D,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,iBAAiB,CAAC,GAAG,CAAC,CAAC;QACzD,MAAM,MAAM,GAAG,UAAU,CAAC;YACxB,OAAO;YACP,IAAI,EAAE,IAAI,CAAC,CAAC,CAAoB;YAChC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACrB,KAAK,EAAE,OAAO,CAAC,KAA2B;YAC1C,MAAM,EAAE,OAAO,CAAC,MAAuB;YACvC,KAAK,EAAE,OAAO,CAAC,KAAK,KAAK,IAAI;YAC7B,KAAK,EAAE,OAAO,CAAC,KAAK,KAAK,IAAI;YAC7B,IAAI,EAAE,MAAM,CAAC,KAAK;SACnB,CAAC,CAAC;QACH,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,MAAM,CAAC,IAAI,KAAK,MAAM,CAAC,GAAG,GAAG,EAAE,CAAC;IAC1E,CAAC,CAAC,CACH,CAAC;AACN,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { Command } from 'commander';
2
+ import { type Runtime } from '../command.js';
3
+ export declare function registerPreviewCommand(program: Command, runtime: Runtime): void;
4
+ //# sourceMappingURL=preview.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preview.d.ts","sourceRoot":"","sources":["../../src/commands/preview.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,EAAE,KAAK,OAAO,EAAU,MAAM,eAAe,CAAC;AAKrD,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAkC/E"}
@@ -0,0 +1,34 @@
1
+ import { resolve } from 'node:path';
2
+ import { openBrowser } from '../browser.js';
3
+ import { action } from '../command.js';
4
+ import { displayPath } from '../paths.js';
5
+ import { loadProjectConfig } from '../project.js';
6
+ import { addServerOptions, hostFrom } from '../server-options.js';
7
+ export function registerPreviewCommand(program, runtime) {
8
+ addServerOptions(program
9
+ .command('preview')
10
+ .description('Serve an existing build (no rebuilding), as it will be served in production')
11
+ .option('--dir <dir>', 'directory to serve (default: build.outDir)'), 4322).action(action(runtime, async (ctx, { options }) => {
12
+ const { startPreviewServer } = await import('@staticforge/dev-server');
13
+ const flags = options;
14
+ const { config, rootDir } = await loadProjectConfig(ctx);
15
+ const dir = resolve(flags.dir !== undefined ? ctx.cwd : rootDir, flags.dir ?? config.build.outDir);
16
+ const server = await startPreviewServer({
17
+ dir,
18
+ host: hostFrom(flags, ctx.logger),
19
+ port: flags.port,
20
+ trailingSlash: config.build.trailingSlash,
21
+ });
22
+ if (flags.open && ctx.interactive)
23
+ openBrowser(server.url);
24
+ const stopped = new Promise((resolveStop) => {
25
+ ctx.io.onShutdown(() => void server.close().then(resolveStop));
26
+ });
27
+ return {
28
+ data: { url: server.url, host: server.host, port: server.port, dir },
29
+ text: `Serving ${displayPath(ctx.cwd, dir)} at ${server.url}\nPress Ctrl+C to stop.`,
30
+ wait: stopped,
31
+ };
32
+ }));
33
+ }
34
+ //# sourceMappingURL=preview.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preview.js","sourceRoot":"","sources":["../../src/commands/preview.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAgB,MAAM,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAoB,gBAAgB,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAEpF,MAAM,UAAU,sBAAsB,CAAC,OAAgB,EAAE,OAAgB;IACvE,gBAAgB,CACd,OAAO;SACJ,OAAO,CAAC,SAAS,CAAC;SAClB,WAAW,CAAC,6EAA6E,CAAC;SAC1F,MAAM,CAAC,aAAa,EAAE,4CAA4C,CAAC,EACtE,IAAI,CACL,CAAC,MAAM,CACN,MAAM,CAAC,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;QACzC,MAAM,EAAE,kBAAkB,EAAE,GAAG,MAAM,MAAM,CAAC,yBAAyB,CAAC,CAAC;QACvE,MAAM,KAAK,GAAG,OAAoD,CAAC;QACnE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,iBAAiB,CAAC,GAAG,CAAC,CAAC;QACzD,MAAM,GAAG,GAAG,OAAO,CACjB,KAAK,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,EAC3C,KAAK,CAAC,GAAG,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,CACjC,CAAC;QACF,MAAM,MAAM,GAAG,MAAM,kBAAkB,CAAC;YACtC,GAAG;YACH,IAAI,EAAE,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC;YACjC,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,aAAa,EAAE,MAAM,CAAC,KAAK,CAAC,aAAa;SAC1C,CAAC,CAAC;QACH,IAAI,KAAK,CAAC,IAAI,IAAI,GAAG,CAAC,WAAW;YAAE,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAE3D,MAAM,OAAO,GAAG,IAAI,OAAO,CAAO,CAAC,WAAW,EAAE,EAAE;YAChD,GAAG,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,KAAK,MAAM,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;QACjE,CAAC,CAAC,CAAC;QACH,OAAO;YACL,IAAI,EAAE,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE;YACpE,IAAI,EAAE,WAAW,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,OAAO,MAAM,CAAC,GAAG,yBAAyB;YACpF,IAAI,EAAE,OAAO;SACd,CAAC;IACJ,CAAC,CAAC,CACH,CAAC;AACJ,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { Command } from 'commander';
2
+ import { type Runtime } from '../command.js';
3
+ interface StateFlags {
4
+ localState?: boolean;
5
+ forceLocalState?: boolean;
6
+ }
7
+ /** --local-state is for experiments: refused in CI unless forced. */
8
+ export declare function localStateFrom(flags: StateFlags, env: NodeJS.ProcessEnv): boolean;
9
+ export declare function registerProvisionCommands(program: Command, runtime: Runtime): void;
10
+ export {};
11
+ //# sourceMappingURL=provision.d.ts.map