@hominis/fireforge 0.10.1 → 0.11.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.
Files changed (174) hide show
  1. package/CHANGELOG.md +93 -1
  2. package/README.md +125 -238
  3. package/dist/bin/fireforge.js +26 -0
  4. package/dist/src/cli.d.ts +1 -1
  5. package/dist/src/cli.js +131 -52
  6. package/dist/src/commands/bootstrap.js +6 -2
  7. package/dist/src/commands/build.js +4 -2
  8. package/dist/src/commands/discard.js +16 -4
  9. package/dist/src/commands/doctor-furnace.d.ts +8 -0
  10. package/dist/src/commands/doctor-furnace.js +422 -0
  11. package/dist/src/commands/doctor.d.ts +115 -0
  12. package/dist/src/commands/doctor.js +327 -258
  13. package/dist/src/commands/download.js +16 -1
  14. package/dist/src/commands/export-all.js +15 -0
  15. package/dist/src/commands/export-flow.d.ts +91 -0
  16. package/dist/src/commands/export-flow.js +344 -0
  17. package/dist/src/commands/export.js +151 -5
  18. package/dist/src/commands/furnace/apply.d.ts +3 -2
  19. package/dist/src/commands/furnace/apply.js +169 -36
  20. package/dist/src/commands/furnace/create.js +162 -52
  21. package/dist/src/commands/furnace/deploy.js +156 -144
  22. package/dist/src/commands/furnace/diff.d.ts +8 -4
  23. package/dist/src/commands/furnace/diff.js +142 -73
  24. package/dist/src/commands/furnace/index.d.ts +6 -2
  25. package/dist/src/commands/furnace/index.js +76 -25
  26. package/dist/src/commands/furnace/init.d.ts +11 -0
  27. package/dist/src/commands/furnace/init.js +76 -0
  28. package/dist/src/commands/furnace/list.d.ts +4 -1
  29. package/dist/src/commands/furnace/list.js +35 -3
  30. package/dist/src/commands/furnace/override.d.ts +8 -0
  31. package/dist/src/commands/furnace/override.js +216 -26
  32. package/dist/src/commands/furnace/preview.js +184 -30
  33. package/dist/src/commands/furnace/refresh.d.ts +10 -0
  34. package/dist/src/commands/furnace/refresh.js +268 -0
  35. package/dist/src/commands/furnace/remove.js +285 -89
  36. package/dist/src/commands/furnace/rename.d.ts +5 -0
  37. package/dist/src/commands/furnace/rename.js +308 -0
  38. package/dist/src/commands/furnace/scan.d.ts +4 -1
  39. package/dist/src/commands/furnace/scan.js +72 -11
  40. package/dist/src/commands/furnace/status.js +85 -20
  41. package/dist/src/commands/furnace/sync.d.ts +12 -0
  42. package/dist/src/commands/furnace/sync.js +77 -0
  43. package/dist/src/commands/furnace/validate.d.ts +4 -1
  44. package/dist/src/commands/furnace/validate.js +99 -3
  45. package/dist/src/commands/furnace/validation-output.d.ts +24 -1
  46. package/dist/src/commands/furnace/validation-output.js +93 -1
  47. package/dist/src/commands/import.js +37 -4
  48. package/dist/src/commands/lint.js +11 -2
  49. package/dist/src/commands/manifest.d.ts +39 -0
  50. package/dist/src/commands/manifest.js +59 -0
  51. package/dist/src/commands/patch/delete.d.ts +28 -0
  52. package/dist/src/commands/patch/delete.js +209 -0
  53. package/dist/src/commands/patch/index.d.ts +17 -0
  54. package/dist/src/commands/patch/index.js +25 -0
  55. package/dist/src/commands/patch/reorder.d.ts +30 -0
  56. package/dist/src/commands/patch/reorder.js +377 -0
  57. package/dist/src/commands/re-export-files.d.ts +17 -0
  58. package/dist/src/commands/re-export-files.js +177 -0
  59. package/dist/src/commands/re-export.js +44 -0
  60. package/dist/src/commands/rebase/abort.d.ts +1 -1
  61. package/dist/src/commands/rebase/abort.js +12 -3
  62. package/dist/src/commands/rebase/confirm.d.ts +3 -3
  63. package/dist/src/commands/rebase/confirm.js +4 -4
  64. package/dist/src/commands/rebase/index.js +13 -4
  65. package/dist/src/commands/reset.js +20 -4
  66. package/dist/src/commands/run.js +46 -1
  67. package/dist/src/commands/setup-support.js +6 -5
  68. package/dist/src/commands/status.js +97 -6
  69. package/dist/src/commands/test.js +5 -37
  70. package/dist/src/commands/verify.d.ts +31 -0
  71. package/dist/src/commands/verify.js +126 -0
  72. package/dist/src/core/build-prepare.js +40 -16
  73. package/dist/src/core/destructive.d.ts +96 -0
  74. package/dist/src/core/destructive.js +137 -0
  75. package/dist/src/core/diff-hunks.d.ts +73 -0
  76. package/dist/src/core/diff-hunks.js +268 -0
  77. package/dist/src/core/firefox.d.ts +1 -1
  78. package/dist/src/core/firefox.js +1 -1
  79. package/dist/src/core/furnace-apply-helpers.d.ts +89 -6
  80. package/dist/src/core/furnace-apply-helpers.js +302 -57
  81. package/dist/src/core/furnace-apply-output.d.ts +16 -0
  82. package/dist/src/core/furnace-apply-output.js +57 -0
  83. package/dist/src/core/furnace-apply.d.ts +21 -3
  84. package/dist/src/core/furnace-apply.js +260 -29
  85. package/dist/src/core/furnace-checksum-utils.d.ts +4 -0
  86. package/dist/src/core/furnace-checksum-utils.js +24 -0
  87. package/dist/src/core/furnace-config.d.ts +28 -1
  88. package/dist/src/core/furnace-config.js +180 -17
  89. package/dist/src/core/furnace-constants.d.ts +22 -0
  90. package/dist/src/core/furnace-constants.js +36 -0
  91. package/dist/src/core/furnace-graph-utils.d.ts +11 -0
  92. package/dist/src/core/furnace-graph-utils.js +94 -0
  93. package/dist/src/core/furnace-operation.d.ts +108 -0
  94. package/dist/src/core/furnace-operation.js +220 -0
  95. package/dist/src/core/furnace-refresh.d.ts +20 -0
  96. package/dist/src/core/furnace-refresh.js +118 -0
  97. package/dist/src/core/furnace-registration-ast.d.ts +5 -0
  98. package/dist/src/core/furnace-registration-ast.js +134 -4
  99. package/dist/src/core/furnace-registration-remove.d.ts +25 -3
  100. package/dist/src/core/furnace-registration-remove.js +196 -62
  101. package/dist/src/core/furnace-registration-validate.d.ts +13 -1
  102. package/dist/src/core/furnace-registration-validate.js +15 -3
  103. package/dist/src/core/furnace-registration.d.ts +27 -4
  104. package/dist/src/core/furnace-registration.js +93 -11
  105. package/dist/src/core/furnace-rollback.d.ts +11 -0
  106. package/dist/src/core/furnace-rollback.js +78 -7
  107. package/dist/src/core/furnace-scanner.d.ts +8 -2
  108. package/dist/src/core/furnace-scanner.js +152 -55
  109. package/dist/src/core/furnace-stories.js +7 -5
  110. package/dist/src/core/furnace-validate-accessibility.js +7 -1
  111. package/dist/src/core/furnace-validate-compatibility.d.ts +1 -1
  112. package/dist/src/core/furnace-validate-compatibility.js +85 -1
  113. package/dist/src/core/furnace-validate-helpers.d.ts +4 -0
  114. package/dist/src/core/furnace-validate-helpers.js +31 -0
  115. package/dist/src/core/furnace-validate-registration.d.ts +17 -2
  116. package/dist/src/core/furnace-validate-registration.js +73 -3
  117. package/dist/src/core/furnace-validate-structure.d.ts +10 -2
  118. package/dist/src/core/furnace-validate-structure.js +45 -3
  119. package/dist/src/core/furnace-validate.d.ts +10 -1
  120. package/dist/src/core/furnace-validate.js +80 -6
  121. package/dist/src/core/furnace-version-drift.d.ts +55 -0
  122. package/dist/src/core/furnace-version-drift.js +101 -0
  123. package/dist/src/core/git-file-ops.d.ts +8 -0
  124. package/dist/src/core/git-file-ops.js +19 -6
  125. package/dist/src/core/lint-projection.d.ts +25 -0
  126. package/dist/src/core/lint-projection.js +44 -0
  127. package/dist/src/core/mach.d.ts +4 -2
  128. package/dist/src/core/mach.js +17 -2
  129. package/dist/src/core/markdown-table.d.ts +104 -0
  130. package/dist/src/core/markdown-table.js +266 -0
  131. package/dist/src/core/ownership-table.d.ts +53 -0
  132. package/dist/src/core/ownership-table.js +144 -0
  133. package/dist/src/core/patch-apply.d.ts +17 -3
  134. package/dist/src/core/patch-apply.js +86 -8
  135. package/dist/src/core/patch-export.d.ts +119 -5
  136. package/dist/src/core/patch-export.js +183 -25
  137. package/dist/src/core/patch-lint-cross.d.ts +195 -0
  138. package/dist/src/core/patch-lint-cross.js +428 -0
  139. package/dist/src/core/patch-lint-diff.d.ts +33 -0
  140. package/dist/src/core/patch-lint-diff.js +84 -0
  141. package/dist/src/core/patch-lint.d.ts +2 -4
  142. package/dist/src/core/patch-lint.js +12 -50
  143. package/dist/src/core/patch-lock.js +2 -1
  144. package/dist/src/core/patch-manifest-io.d.ts +102 -1
  145. package/dist/src/core/patch-manifest-io.js +270 -2
  146. package/dist/src/core/patch-manifest-query.d.ts +1 -1
  147. package/dist/src/core/patch-manifest-query.js +1 -1
  148. package/dist/src/core/patch-manifest.d.ts +1 -1
  149. package/dist/src/core/patch-manifest.js +1 -1
  150. package/dist/src/core/patch-transform.d.ts +12 -0
  151. package/dist/src/core/patch-transform.js +21 -7
  152. package/dist/src/core/token-manager.js +67 -69
  153. package/dist/src/core/wire-destroy.js +6 -3
  154. package/dist/src/core/wire-init.js +10 -4
  155. package/dist/src/core/wire-subscript.js +9 -3
  156. package/dist/src/core/wire-utils.d.ts +52 -5
  157. package/dist/src/core/wire-utils.js +69 -6
  158. package/dist/src/errors/base.d.ts +20 -0
  159. package/dist/src/errors/base.js +24 -0
  160. package/dist/src/errors/furnace.js +7 -1
  161. package/dist/src/errors/rebase.js +6 -1
  162. package/dist/src/types/commands/index.d.ts +1 -1
  163. package/dist/src/types/commands/options.d.ts +125 -4
  164. package/dist/src/types/commands/patches.d.ts +11 -1
  165. package/dist/src/types/config.d.ts +1 -1
  166. package/dist/src/types/furnace.d.ts +55 -1
  167. package/dist/src/utils/fs.d.ts +12 -0
  168. package/dist/src/utils/fs.js +30 -1
  169. package/dist/src/utils/package-root.d.ts +5 -0
  170. package/dist/src/utils/package-root.js +12 -0
  171. package/dist/src/utils/process.js +9 -4
  172. package/dist/src/utils/validation.d.ts +20 -2
  173. package/dist/src/utils/validation.js +26 -3
  174. package/package.json +1 -1
@@ -0,0 +1,268 @@
1
+ // SPDX-License-Identifier: EUPL-1.2
2
+ import { readdir } from 'node:fs/promises';
3
+ import { join } from 'node:path';
4
+ import { getProjectPaths, loadConfig, loadState } from '../../core/config.js';
5
+ import { getOverrideEngineTargetPath } from '../../core/furnace-apply-helpers.js';
6
+ import { getFurnacePaths, loadFurnaceConfig, writeFurnaceConfig, } from '../../core/furnace-config.js';
7
+ import { resolveFtlDir } from '../../core/furnace-constants.js';
8
+ import { isComponentSourceFile } from '../../core/furnace-constants.js';
9
+ import { recordFurnaceRollbackFailure, runFurnaceMutation } from '../../core/furnace-operation.js';
10
+ import { refreshOverrideFile } from '../../core/furnace-refresh.js';
11
+ import { createRollbackJournal, restoreRollbackJournal, restoreRollbackJournalOrThrow, snapshotDir, snapshotFile, } from '../../core/furnace-rollback.js';
12
+ import { getHead } from '../../core/git.js';
13
+ import { FurnaceError } from '../../errors/furnace.js';
14
+ import { toError } from '../../utils/errors.js';
15
+ import { pathExists } from '../../utils/fs.js';
16
+ import { formatErrorText, formatSuccessText, info, intro, note, outro, warn, } from '../../utils/logger.js';
17
+ function displayRefreshResults(results, name, currentVersion, dryRun) {
18
+ const merged = results.filter((r) => r.status === 'merged');
19
+ const conflicts = results.filter((r) => r.status === 'conflict');
20
+ const unchanged = results.filter((r) => r.status === 'unchanged');
21
+ const newFiles = results.filter((r) => r.status === 'new-file');
22
+ for (const r of merged) {
23
+ info(formatSuccessText(` merged: ${r.fileName}`));
24
+ }
25
+ for (const r of unchanged) {
26
+ info(` unchanged: ${r.fileName}`);
27
+ }
28
+ for (const r of newFiles) {
29
+ info(` new file: ${r.fileName}`);
30
+ }
31
+ if (conflicts.length > 0) {
32
+ for (const r of conflicts) {
33
+ info(formatErrorText(` CONFLICT: ${r.fileName} (${r.conflictMarkers} marker(s))`));
34
+ }
35
+ warn('Conflict markers have been left in the affected files. ' +
36
+ `Resolve them manually, then re-run "fireforge furnace refresh ${name}" to update baseVersion.`);
37
+ }
38
+ const summary = `${merged.length} merged, ${unchanged.length} unchanged, ` +
39
+ `${newFiles.length} new, ${conflicts.length} conflicts`;
40
+ if (dryRun) {
41
+ note(summary, 'Dry Run Summary');
42
+ outro('Dry run complete (no files modified)');
43
+ }
44
+ else if (conflicts.length > 0) {
45
+ note(summary, 'Refresh Summary');
46
+ outro('Refresh complete with conflicts — resolve before applying');
47
+ }
48
+ else {
49
+ note(`${summary}\nbaseVersion updated to ${currentVersion} in furnace.json`, 'Refresh Summary');
50
+ outro('Refresh complete');
51
+ }
52
+ }
53
+ /**
54
+ * Refreshes a single override component against the current Firefox source.
55
+ * Returns the per-file merge results.
56
+ */
57
+ async function refreshSingleOverride(projectRoot, name, options = {}) {
58
+ const config = await loadFurnaceConfig(projectRoot);
59
+ const paths = getProjectPaths(projectRoot);
60
+ const furnacePaths = getFurnacePaths(projectRoot);
61
+ const ftlDir = resolveFtlDir(config.ftlBasePath);
62
+ // Only overrides can be refreshed
63
+ const overrideConfig = config.overrides[name];
64
+ if (!overrideConfig) {
65
+ throw new FurnaceError(`"${name}" is not an override component. Only overrides can be refreshed against upstream.`, name);
66
+ }
67
+ const overrideDir = join(furnacePaths.overridesDir, name);
68
+ if (!(await pathExists(overrideDir))) {
69
+ throw new FurnaceError(`Override directory not found: components/overrides/${name}`, name);
70
+ }
71
+ const forgeConfig = await loadConfig(projectRoot);
72
+ const currentVersion = forgeConfig.firefox.version;
73
+ const state = await loadState(projectRoot);
74
+ // --reset-base: skip three-way merge and re-snapshot the current engine
75
+ // state as the new baseline. This recovers from unreachable baseCommits
76
+ // (e.g. after history rewrite or re-clone).
77
+ if (options.resetBase) {
78
+ const headCommit = await getHead(paths.engine);
79
+ info(`Resetting "${name}" baseline to Firefox ${currentVersion} (${headCommit.slice(0, 8)}). ` +
80
+ 'Three-way merge skipped — current workspace content is preserved as-is.');
81
+ if (!options.dryRun) {
82
+ const freshConfig = await loadFurnaceConfig(projectRoot);
83
+ freshConfig.overrides[name] = {
84
+ ...overrideConfig,
85
+ baseVersion: currentVersion,
86
+ baseCommit: headCommit,
87
+ };
88
+ await writeFurnaceConfig(projectRoot, freshConfig);
89
+ }
90
+ return { results: [], currentVersion };
91
+ }
92
+ // Prefer the per-override baseCommit (survives download --force); fall back
93
+ // to the project-wide value for overrides created before this field existed.
94
+ const baseCommit = overrideConfig.baseCommit ?? state.baseCommit;
95
+ if (!baseCommit) {
96
+ throw new FurnaceError('Cannot refresh: baseCommit not found. Re-run "fireforge download" to establish a baseline, ' +
97
+ 'or use --reset-base to snapshot the current engine as the new baseline.', name);
98
+ }
99
+ // If there's no version drift, refreshing is a no-op
100
+ if (overrideConfig.baseVersion === currentVersion) {
101
+ info(`Override "${name}" is already at Firefox ${currentVersion}. Nothing to refresh.`);
102
+ return { results: [], currentVersion };
103
+ }
104
+ info(`Refreshing "${name}": Firefox ${overrideConfig.baseVersion} → ${currentVersion}`);
105
+ // Collect override files
106
+ const entries = await readdir(overrideDir, { withFileTypes: true });
107
+ const overrideFiles = entries.filter((e) => e.isFile() && isComponentSourceFile(e.name));
108
+ if (overrideFiles.length === 0) {
109
+ info('No source files to refresh.');
110
+ return { results: [], currentVersion };
111
+ }
112
+ const dryRun = options.dryRun ?? false;
113
+ const strategy = options.strategy;
114
+ // Run all merges within a transactional mutation so failures can be rolled back
115
+ const results = await runFurnaceMutation(projectRoot, 'refresh-rollback', async (ctx) => {
116
+ const journal = createRollbackJournal();
117
+ ctx.registerJournal(journal);
118
+ try {
119
+ const fileResults = [];
120
+ if (!dryRun) {
121
+ // Snapshot all override files before mutation
122
+ await snapshotDir(journal, overrideDir);
123
+ await snapshotFile(journal, furnacePaths.furnaceConfig);
124
+ }
125
+ for (const entry of overrideFiles) {
126
+ const overridePath = join(overrideDir, entry.name);
127
+ const engineRelPath = getOverrideEngineTargetPath(paths.engine, overrideConfig, entry.name, ftlDir).slice(paths.engine.length + 1);
128
+ const result = await refreshOverrideFile(paths.engine, overridePath, engineRelPath, baseCommit, entry.name, dryRun, strategy);
129
+ fileResults.push(result);
130
+ }
131
+ // Update baseVersion and baseCommit on clean merge (not dry-run, no conflicts)
132
+ const hasConflicts = fileResults.some((r) => r.status === 'conflict');
133
+ if (!dryRun && !hasConflicts) {
134
+ // Re-load config to pick up any concurrent changes from a prior override
135
+ // in a batch refresh.
136
+ const freshConfig = await loadFurnaceConfig(projectRoot);
137
+ freshConfig.overrides[name] = {
138
+ ...overrideConfig,
139
+ baseVersion: currentVersion,
140
+ baseCommit: await getHead(paths.engine),
141
+ };
142
+ await writeFurnaceConfig(projectRoot, freshConfig);
143
+ }
144
+ return fileResults;
145
+ }
146
+ catch (error) {
147
+ if (!dryRun) {
148
+ try {
149
+ await restoreRollbackJournalOrThrow(journal, `Failed to refresh override "${name}"`);
150
+ }
151
+ catch (rollbackError) {
152
+ await recordFurnaceRollbackFailure(projectRoot, 'refresh-rollback', toError(rollbackError).message);
153
+ throw rollbackError;
154
+ }
155
+ }
156
+ throw error;
157
+ }
158
+ }, { dryRun });
159
+ return { results, currentVersion };
160
+ }
161
+ /**
162
+ * Runs the furnace refresh command to merge upstream Firefox changes into
163
+ * an override component using three-way merge.
164
+ *
165
+ * @param projectRoot - Root directory of the project
166
+ * @param name - Component tag name to refresh (omit when using --all)
167
+ * @param options - Command options
168
+ */
169
+ export async function furnaceRefreshCommand(projectRoot, name, options = {}) {
170
+ const refreshAll = options.all ?? false;
171
+ if (!name && !refreshAll) {
172
+ throw new FurnaceError('Specify a component name or use --all to refresh every override.');
173
+ }
174
+ if (name && refreshAll) {
175
+ throw new FurnaceError('Cannot specify both a component name and --all. Use one or the other.');
176
+ }
177
+ // Verify engine exists — refresh reads engine files for three-way merge
178
+ // and --reset-base reads engine HEAD. Without this check, the user gets
179
+ // an obscure git error instead of a clear precondition message.
180
+ const paths = getProjectPaths(projectRoot);
181
+ if (!(await pathExists(paths.engine))) {
182
+ throw new FurnaceError('Engine directory not found. Run "fireforge download" first.');
183
+ }
184
+ const dryRun = options.dryRun ?? false;
185
+ if (name) {
186
+ intro('Furnace Refresh');
187
+ if (dryRun) {
188
+ info('Dry run — showing what would change without modifying files.');
189
+ }
190
+ const { results, currentVersion } = await refreshSingleOverride(projectRoot, name, options);
191
+ if (results.length > 0) {
192
+ displayRefreshResults(results, name, currentVersion, dryRun);
193
+ }
194
+ else {
195
+ outro('Done');
196
+ }
197
+ return;
198
+ }
199
+ // --all mode: refresh every override sequentially
200
+ intro('Furnace Refresh (all overrides)');
201
+ if (dryRun) {
202
+ info('Dry run — showing what would change without modifying files.');
203
+ }
204
+ const config = await loadFurnaceConfig(projectRoot);
205
+ const overrideNames = Object.keys(config.overrides);
206
+ if (overrideNames.length === 0) {
207
+ info('No overrides to refresh.');
208
+ outro('Done');
209
+ return;
210
+ }
211
+ let totalMerged = 0;
212
+ let totalConflicts = 0;
213
+ let totalUnchanged = 0;
214
+ let totalSkipped = 0;
215
+ const conflictComponents = [];
216
+ // Snapshot furnace.json before the batch loop so an unexpected failure
217
+ // (process crash, unhandled error) can be recovered from. Per-component
218
+ // errors caught below are expected and do not trigger a restore — only
219
+ // an error that escapes the loop entirely warrants rolling back.
220
+ const batchJournal = dryRun ? undefined : createRollbackJournal();
221
+ if (batchJournal) {
222
+ const furnacePaths = getFurnacePaths(projectRoot);
223
+ await snapshotFile(batchJournal, furnacePaths.furnaceConfig);
224
+ }
225
+ try {
226
+ for (const overrideName of overrideNames) {
227
+ try {
228
+ const { results } = await refreshSingleOverride(projectRoot, overrideName, options);
229
+ if (results.length === 0) {
230
+ totalSkipped++;
231
+ continue;
232
+ }
233
+ for (const r of results) {
234
+ if (r.status === 'merged')
235
+ totalMerged++;
236
+ else if (r.status === 'conflict') {
237
+ totalConflicts++;
238
+ if (!conflictComponents.includes(overrideName)) {
239
+ conflictComponents.push(overrideName);
240
+ }
241
+ }
242
+ else if (r.status === 'unchanged')
243
+ totalUnchanged++;
244
+ }
245
+ }
246
+ catch (error) {
247
+ warn(`${overrideName}: ${toError(error).message}`);
248
+ }
249
+ }
250
+ }
251
+ catch (error) {
252
+ // Unexpected batch-level failure: restore furnace.json to its
253
+ // pre-batch state so the config is not left partially updated.
254
+ if (batchJournal) {
255
+ await restoreRollbackJournal(batchJournal);
256
+ }
257
+ throw error;
258
+ }
259
+ const summary = `${overrideNames.length} override(s) processed, ${totalSkipped} already up-to-date\n` +
260
+ `${totalMerged} file(s) merged, ${totalUnchanged} unchanged, ${totalConflicts} conflict(s)`;
261
+ if (conflictComponents.length > 0) {
262
+ warn(`Conflicts in: ${conflictComponents.join(', ')}. ` +
263
+ 'Resolve conflict markers, then re-run refresh for those components to update baseVersion.');
264
+ }
265
+ note(summary, dryRun ? 'Dry Run Summary' : 'Refresh Summary');
266
+ outro(dryRun ? 'Dry run complete' : 'Refresh complete');
267
+ }
268
+ //# sourceMappingURL=refresh.js.map