@fuzdev/fuz_gitops 0.78.0 → 0.78.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 (137) hide show
  1. package/README.md +20 -0
  2. package/dist/ModulesDetail.svelte +14 -12
  3. package/dist/ModulesDetail.svelte.d.ts.map +1 -1
  4. package/dist/ModulesNav.svelte +6 -6
  5. package/dist/ModulesNav.svelte.d.ts.map +1 -1
  6. package/dist/ModulesPage.svelte +2 -2
  7. package/dist/ModulesPage.svelte.d.ts.map +1 -1
  8. package/dist/PageFooter.svelte +2 -2
  9. package/dist/PageHeader.svelte +5 -5
  10. package/dist/PageHeader.svelte.d.ts.map +1 -1
  11. package/dist/PullRequestsDetail.svelte +25 -17
  12. package/dist/PullRequestsDetail.svelte.d.ts.map +1 -1
  13. package/dist/PullRequestsPage.svelte +3 -3
  14. package/dist/PullRequestsPage.svelte.d.ts.map +1 -1
  15. package/dist/ReposTable.svelte +24 -15
  16. package/dist/ReposTable.svelte.d.ts.map +1 -1
  17. package/dist/ReposTree.svelte +8 -6
  18. package/dist/ReposTree.svelte.d.ts.map +1 -1
  19. package/dist/ReposTreeNav.svelte +10 -11
  20. package/dist/ReposTreeNav.svelte.d.ts.map +1 -1
  21. package/dist/TablePage.svelte +2 -2
  22. package/dist/TablePage.svelte.d.ts.map +1 -1
  23. package/dist/TreeItemPage.svelte +2 -2
  24. package/dist/TreeItemPage.svelte.d.ts.map +1 -1
  25. package/dist/TreePage.svelte +2 -2
  26. package/dist/TreePage.svelte.d.ts.map +1 -1
  27. package/dist/changeset_generator.d.ts.map +1 -1
  28. package/dist/changeset_generator.js +2 -2
  29. package/dist/changeset_reader.d.ts.map +1 -1
  30. package/dist/changeset_reader.js +3 -3
  31. package/dist/config_reconcile.d.ts.map +1 -1
  32. package/dist/config_reconcile.js +6 -2
  33. package/dist/dependency_graph.d.ts.map +1 -1
  34. package/dist/dependency_graph.js +5 -5
  35. package/dist/dependency_updater.d.ts.map +1 -1
  36. package/dist/dependency_updater.js +8 -8
  37. package/dist/fetch_repo_data.d.ts.map +1 -1
  38. package/dist/fetch_repo_data.js +3 -3
  39. package/dist/fs_fetch_value_cache.d.ts.map +1 -1
  40. package/dist/fs_fetch_value_cache.js +2 -2
  41. package/dist/git_operations.d.ts.map +1 -1
  42. package/dist/git_operations.js +1 -1
  43. package/dist/github.d.ts.map +1 -1
  44. package/dist/github.js +6 -6
  45. package/dist/github_helpers.d.ts.map +1 -1
  46. package/dist/gitops_analyze.task.d.ts.map +1 -1
  47. package/dist/gitops_analyze.task.js +7 -7
  48. package/dist/gitops_config.d.ts.map +1 -1
  49. package/dist/gitops_config.js +4 -4
  50. package/dist/gitops_plan.task.d.ts.map +1 -1
  51. package/dist/gitops_plan.task.js +8 -8
  52. package/dist/gitops_publish.task.d.ts.map +1 -1
  53. package/dist/gitops_publish.task.js +15 -12
  54. package/dist/gitops_run.task.d.ts.map +1 -1
  55. package/dist/gitops_run.task.js +8 -8
  56. package/dist/gitops_sync.task.d.ts.map +1 -1
  57. package/dist/gitops_sync.task.js +11 -9
  58. package/dist/gitops_task_helpers.d.ts.map +1 -1
  59. package/dist/gitops_task_helpers.js +3 -3
  60. package/dist/gitops_validate.task.d.ts.map +1 -1
  61. package/dist/gitops_validate.task.js +14 -14
  62. package/dist/graph_validation.d.ts.map +1 -1
  63. package/dist/graph_validation.js +2 -2
  64. package/dist/local_repo.d.ts +4 -4
  65. package/dist/local_repo.d.ts.map +1 -1
  66. package/dist/local_repo.js +13 -13
  67. package/dist/log_helpers.d.ts.map +1 -1
  68. package/dist/multi_repo_publisher.d.ts.map +1 -1
  69. package/dist/multi_repo_publisher.js +19 -19
  70. package/dist/npm_registry.d.ts.map +1 -1
  71. package/dist/npm_registry.js +2 -2
  72. package/dist/operations.d.ts.map +1 -1
  73. package/dist/operations_defaults.d.ts.map +1 -1
  74. package/dist/operations_defaults.js +12 -12
  75. package/dist/output_helpers.d.ts.map +1 -1
  76. package/dist/preflight_checks.d.ts +1 -1
  77. package/dist/preflight_checks.d.ts.map +1 -1
  78. package/dist/preflight_checks.js +4 -4
  79. package/dist/publish_gate.d.ts.map +1 -1
  80. package/dist/publish_steps.d.ts.map +1 -1
  81. package/dist/publish_steps.js +3 -3
  82. package/dist/publishing_event.d.ts.map +1 -1
  83. package/dist/publishing_event.js +16 -14
  84. package/dist/publishing_event_handler.d.ts.map +1 -1
  85. package/dist/publishing_event_handler.js +6 -6
  86. package/dist/publishing_plan.d.ts.map +1 -1
  87. package/dist/publishing_plan.js +14 -14
  88. package/dist/publishing_plan_helpers.d.ts.map +1 -1
  89. package/dist/publishing_plan_helpers.js +3 -3
  90. package/dist/publishing_plan_logging.d.ts.map +1 -1
  91. package/dist/publishing_plan_logging.js +2 -2
  92. package/dist/repo.svelte.d.ts.map +1 -1
  93. package/dist/repo_ops.js +2 -2
  94. package/dist/resolved_gitops_config.d.ts.map +1 -1
  95. package/dist/resolved_gitops_config.js +1 -1
  96. package/dist/version_utils.js +1 -1
  97. package/package.json +16 -15
  98. package/src/lib/cargo_toml.ts +3 -3
  99. package/src/lib/changeset_generator.ts +19 -19
  100. package/src/lib/changeset_reader.ts +18 -18
  101. package/src/lib/ci_reconcile.ts +5 -5
  102. package/src/lib/config_reconcile.ts +8 -4
  103. package/src/lib/dependency_graph.ts +26 -26
  104. package/src/lib/dependency_updater.ts +29 -29
  105. package/src/lib/fetch_repo_data.ts +11 -11
  106. package/src/lib/fs_fetch_value_cache.ts +14 -10
  107. package/src/lib/git_operations.ts +30 -30
  108. package/src/lib/github.ts +19 -19
  109. package/src/lib/github_helpers.ts +6 -6
  110. package/src/lib/gitops_analyze.task.ts +40 -40
  111. package/src/lib/gitops_config.ts +14 -14
  112. package/src/lib/gitops_plan.task.ts +31 -31
  113. package/src/lib/gitops_publish.task.ts +51 -48
  114. package/src/lib/gitops_run.task.ts +29 -29
  115. package/src/lib/gitops_sync.task.ts +39 -30
  116. package/src/lib/gitops_task_helpers.ts +21 -21
  117. package/src/lib/gitops_validate.task.ts +37 -37
  118. package/src/lib/graph_validation.ts +13 -13
  119. package/src/lib/local_repo.ts +70 -70
  120. package/src/lib/log_helpers.ts +15 -15
  121. package/src/lib/multi_repo_publisher.ts +67 -70
  122. package/src/lib/npm_registry.ts +13 -13
  123. package/src/lib/operations.ts +49 -38
  124. package/src/lib/operations_defaults.ts +106 -104
  125. package/src/lib/output_helpers.ts +4 -4
  126. package/src/lib/preflight_checks.ts +26 -26
  127. package/src/lib/publish_gate.ts +7 -9
  128. package/src/lib/publish_steps.ts +15 -15
  129. package/src/lib/publishing_event.ts +22 -20
  130. package/src/lib/publishing_event_handler.ts +8 -8
  131. package/src/lib/publishing_plan.ts +55 -55
  132. package/src/lib/publishing_plan_helpers.ts +16 -12
  133. package/src/lib/publishing_plan_logging.ts +22 -22
  134. package/src/lib/repo.svelte.ts +8 -8
  135. package/src/lib/repo_ops.ts +12 -12
  136. package/src/lib/resolved_gitops_config.ts +5 -5
  137. package/src/lib/version_utils.ts +3 -3
@@ -1,14 +1,14 @@
1
- import type {Logger} from '@fuzdev/fuz_util/log.ts';
2
- import {styleText as st} from 'node:util';
1
+ import type { Logger } from '@fuzdev/fuz_util/log.ts';
2
+ import { styleText as st } from 'node:util';
3
3
 
4
- import type {DependencyGraphBuilder} from './dependency_graph.ts';
4
+ import type { DependencyGraphBuilder } from './dependency_graph.ts';
5
5
 
6
6
  /**
7
7
  * Formats wildcard dependencies as styled strings.
8
8
  * Returns array of lines for inclusion in output.
9
9
  */
10
10
  export const format_wildcard_dependencies = (
11
- analysis: ReturnType<DependencyGraphBuilder['analyze']>,
11
+ analysis: ReturnType<DependencyGraphBuilder['analyze']>
12
12
  ): Array<string> => {
13
13
  if (analysis.wildcard_deps.length === 0) return [];
14
14
 
@@ -17,7 +17,7 @@ export const format_wildcard_dependencies = (
17
17
  // a leading `\n` in the header would leave the header line unprefixed.
18
18
  lines.push('');
19
19
  lines.push(st('yellow', `⚠️ Found ${analysis.wildcard_deps.length} wildcard dependencies:`));
20
- for (const {pkg, dep, version} of analysis.wildcard_deps) {
20
+ for (const { pkg, dep, version } of analysis.wildcard_deps) {
21
21
  lines.push(` ${pkg} → ${dep} ${st('red', version)}`);
22
22
  }
23
23
  return lines;
@@ -28,7 +28,7 @@ export const format_wildcard_dependencies = (
28
28
  * Returns array of lines for inclusion in output.
29
29
  */
30
30
  export const format_dev_cycles = (
31
- analysis: ReturnType<DependencyGraphBuilder['analyze']>,
31
+ analysis: ReturnType<DependencyGraphBuilder['analyze']>
32
32
  ): Array<string> => {
33
33
  if (analysis.dev_cycles.length === 0) return [];
34
34
 
@@ -37,8 +37,8 @@ export const format_dev_cycles = (
37
37
  lines.push(
38
38
  st(
39
39
  'dim',
40
- `ℹ️ Found ${analysis.dev_cycles.length} dev circular dependencies (normal, non-blocking):`,
41
- ),
40
+ `ℹ️ Found ${analysis.dev_cycles.length} dev circular dependencies (normal, non-blocking):`
41
+ )
42
42
  );
43
43
  for (const cycle of analysis.dev_cycles) {
44
44
  lines.push(st('dim', ` ${cycle.join(' → ')}`));
@@ -51,7 +51,7 @@ export const format_dev_cycles = (
51
51
  * Returns array of lines for inclusion in output.
52
52
  */
53
53
  export const format_production_cycles = (
54
- analysis: ReturnType<DependencyGraphBuilder['analyze']>,
54
+ analysis: ReturnType<DependencyGraphBuilder['analyze']>
55
55
  ): Array<string> => {
56
56
  if (analysis.production_cycles.length === 0) return [];
57
57
 
@@ -60,8 +60,8 @@ export const format_production_cycles = (
60
60
  lines.push(
61
61
  st(
62
62
  'red',
63
- `❌ Found ${analysis.production_cycles.length} production/peer circular dependencies (blocks publishing):`,
64
- ),
63
+ `❌ Found ${analysis.production_cycles.length} production/peer circular dependencies (blocks publishing):`
64
+ )
65
65
  );
66
66
  for (const cycle of analysis.production_cycles) {
67
67
  lines.push(` ${st('red', cycle.join(' → '))}`);
@@ -76,7 +76,7 @@ export const format_production_cycles = (
76
76
  export const log_wildcard_dependencies = (
77
77
  analysis: ReturnType<DependencyGraphBuilder['analyze']>,
78
78
  log: Logger,
79
- indent = '',
79
+ indent = ''
80
80
  ): void => {
81
81
  const lines = format_wildcard_dependencies(analysis);
82
82
  for (const line of lines) {
@@ -91,7 +91,7 @@ export const log_wildcard_dependencies = (
91
91
  export const log_dev_cycles = (
92
92
  analysis: ReturnType<DependencyGraphBuilder['analyze']>,
93
93
  log: Logger,
94
- indent = '',
94
+ indent = ''
95
95
  ): void => {
96
96
  const lines = format_dev_cycles(analysis);
97
97
  for (const line of lines) {
@@ -106,7 +106,7 @@ export const log_dev_cycles = (
106
106
  export const log_production_cycles = (
107
107
  analysis: ReturnType<DependencyGraphBuilder['analyze']>,
108
108
  log: Logger,
109
- indent = '',
109
+ indent = ''
110
110
  ): void => {
111
111
  const lines = format_production_cycles(analysis);
112
112
  for (const line of lines) {
@@ -121,7 +121,7 @@ export const log_production_cycles = (
121
121
  export const log_dependency_analysis = (
122
122
  analysis: ReturnType<DependencyGraphBuilder['analyze']>,
123
123
  log: Logger,
124
- indent = '',
124
+ indent = ''
125
125
  ): void => {
126
126
  log_wildcard_dependencies(analysis, log, indent);
127
127
  log_production_cycles(analysis, log, indent);
@@ -1,29 +1,29 @@
1
- import type {Logger} from '@fuzdev/fuz_util/log.ts';
2
- import {TaskError} from '@fuzdev/gro';
3
- import {join} from 'node:path';
4
- import {styleText as st} from 'node:util';
1
+ import type { Logger } from '@fuzdev/fuz_util/log.ts';
2
+ import { TaskError } from '@fuzdev/gro';
3
+ import { join } from 'node:path';
4
+ import { styleText as st } from 'node:util';
5
5
 
6
- import {repo_is_npm, type LocalRepo} from './local_repo.ts';
7
- import {update_package_json, type VersionStrategy} from './dependency_updater.ts';
6
+ import { repo_is_npm, type LocalRepo } from './local_repo.ts';
7
+ import { update_package_json, type VersionStrategy } from './dependency_updater.ts';
8
8
  import {
9
9
  generate_publishing_plan,
10
10
  type VersionChange,
11
11
  type DependencyUpdate,
12
- type PublishingPlan,
12
+ type PublishingPlan
13
13
  } from './publishing_plan.ts';
14
- import type {PreflightOptions} from './preflight_checks.ts';
15
- import type {GitopsOperations} from './operations.ts';
16
- import {default_gitops_operations} from './operations_defaults.ts';
17
- import {GITOPS_NPM_WAIT_TIMEOUT_DEFAULT} from './gitops_constants.ts';
14
+ import type { PreflightOptions } from './preflight_checks.ts';
15
+ import type { GitopsOperations } from './operations.ts';
16
+ import { default_gitops_operations } from './operations_defaults.ts';
17
+ import { GITOPS_NPM_WAIT_TIMEOUT_DEFAULT } from './gitops_constants.ts';
18
18
  import {
19
19
  type PublishingEvent,
20
20
  type PublishingRunSummary,
21
- summarize_events,
21
+ summarize_events
22
22
  } from './publishing_event.ts';
23
23
  import {
24
24
  type PublishingEventHandler,
25
25
  capture_handler,
26
- multi_handler,
26
+ multi_handler
27
27
  } from './publishing_event_handler.ts';
28
28
 
29
29
  export interface PublishingOptions {
@@ -50,7 +50,7 @@ export interface PublishedVersion {
50
50
  export interface PublishingResult {
51
51
  ok: boolean;
52
52
  published: Array<PublishedVersion>;
53
- failed: Array<{name: string; error: Error}>;
53
+ failed: Array<{ name: string; error: Error }>;
54
54
  duration: number;
55
55
  /** The structured event stream for this run, in emission order. */
56
56
  events: Array<PublishingEvent>;
@@ -64,13 +64,13 @@ export interface PublishingResult {
64
64
 
65
65
  export const publish_repos = async (
66
66
  repos: Array<LocalRepo>,
67
- options: PublishingOptions,
67
+ options: PublishingOptions
68
68
  ): Promise<PublishingResult> => {
69
- const {log, ops = default_gitops_operations} = options;
69
+ const { log, ops = default_gitops_operations } = options;
70
70
  // Convenience entry: generate the plan, then execute it. Callers that already hold a
71
71
  // plan (e.g. to display and confirm it first) call `execute_publishing_plan` directly,
72
72
  // so the plan is generated exactly once per command.
73
- const plan = await generate_publishing_plan(repos, {log, ops: ops.changeset});
73
+ const plan = await generate_publishing_plan(repos, { log, ops: ops.changeset });
74
74
  return execute_publishing_plan(repos, plan, options);
75
75
  };
76
76
 
@@ -85,10 +85,10 @@ export const publish_repos = async (
85
85
  export const execute_publishing_plan = async (
86
86
  all_repos: Array<LocalRepo>,
87
87
  plan: PublishingPlan,
88
- options: PublishingOptions,
88
+ options: PublishingOptions
89
89
  ): Promise<PublishingResult> => {
90
90
  const start_time = Date.now();
91
- const {wetrun, log, ops = default_gitops_operations} = options;
91
+ const { wetrun, log, ops = default_gitops_operations } = options;
92
92
 
93
93
  // Only npm repos publish; drop any non-npm repos (e.g. cargo) so preflight and the
94
94
  // executor's name lookup never touch them. The plan already excludes them too.
@@ -99,7 +99,7 @@ export const execute_publishing_plan = async (
99
99
  // (no side effects) but the result is not ok (see the summary below).
100
100
  if (wetrun && plan.errors.length > 0) {
101
101
  throw new TaskError(
102
- `Cannot publish — the plan has ${plan.errors.length} error(s):\n ${plan.errors.join('\n ')}`,
102
+ `Cannot publish — the plan has ${plan.errors.length} error(s):\n ${plan.errors.join('\n ')}`
103
103
  );
104
104
  }
105
105
 
@@ -115,7 +115,7 @@ export const execute_publishing_plan = async (
115
115
  const preflight_options: PreflightOptions = {
116
116
  skip_changesets: false, // Always check for changesets
117
117
  required_branch: 'main',
118
- log,
118
+ log
119
119
  };
120
120
  const preflight = await ops.preflight.run_preflight_checks({
121
121
  repos,
@@ -123,7 +123,7 @@ export const execute_publishing_plan = async (
123
123
  git_ops: ops.git,
124
124
  npm_ops: ops.npm,
125
125
  build_ops: ops.build,
126
- changeset_ops: ops.changeset,
126
+ changeset_ops: ops.changeset
127
127
  });
128
128
 
129
129
  if (!preflight.ok) {
@@ -138,13 +138,13 @@ export const execute_publishing_plan = async (
138
138
  // frozen topological order directly, re-deriving nothing.
139
139
  const order = plan.publishing_order;
140
140
  const plan_changes: Map<string, VersionChange> = new Map(
141
- plan.version_changes.map((vc) => [vc.package_name, vc]),
141
+ plan.version_changes.map((vc) => [vc.package_name, vc])
142
142
  );
143
143
  if (order.length > 0) {
144
144
  log?.info(` Publishing order: ${order.join(' → ')}`);
145
145
  }
146
146
 
147
- emit({event: 'run_started', wetrun, total: order.length});
147
+ emit({ event: 'run_started', wetrun, total: order.length });
148
148
 
149
149
  const published: Map<string, PublishedVersion> = new Map();
150
150
  const failed: Map<string, Error> = new Map();
@@ -165,7 +165,7 @@ export const execute_publishing_plan = async (
165
165
 
166
166
  // Not in the plan = no changesets and no dependency updates = nothing to publish.
167
167
  if (!planned) {
168
- emit({event: 'package_skipped', name: pkg_name, reason: 'no changesets'});
168
+ emit({ event: 'package_skipped', name: pkg_name, reason: 'no changesets' });
169
169
  log?.info(st('yellow', ` ⚠️ Skipping ${pkg_name} - no changesets`));
170
170
  continue;
171
171
  }
@@ -182,8 +182,8 @@ export const execute_publishing_plan = async (
182
182
  log?.info(
183
183
  st(
184
184
  'dim',
185
- ` [${i + 1}/${order.length}] ${wetrun ? 'Publishing' : 'Would publish'} ${pkg_name}...`,
186
- ),
185
+ ` [${i + 1}/${order.length}] ${wetrun ? 'Publishing' : 'Would publish'} ${pkg_name}...`
186
+ )
187
187
  );
188
188
  const version = await publish_single_repo(repo, options, ops, planned);
189
189
 
@@ -194,10 +194,10 @@ export const execute_publishing_plan = async (
194
194
  if (wetrun && version.new_version !== planned.to) {
195
195
  const err = new Error(
196
196
  `Plan drift for ${pkg_name}: published ${version.new_version} but the plan predicted ${planned.to}. ` +
197
- `Aborting — re-run 'gro gitops_publish --wetrun' to re-plan from the current state.`,
197
+ `Aborting — re-run 'gro gitops_publish --wetrun' to re-plan from the current state.`
198
198
  );
199
199
  failed.set(pkg_name, err);
200
- emit({event: 'package_failed', name: pkg_name, error: err.message, code: 'drift'});
200
+ emit({ event: 'package_failed', name: pkg_name, error: err.message, code: 'drift' });
201
201
  log?.error(st('red', ` ❌ ${err.message}`));
202
202
  break;
203
203
  }
@@ -212,12 +212,12 @@ export const execute_publishing_plan = async (
212
212
  bump_type: version.bump_type,
213
213
  breaking: version.breaking,
214
214
  commit: version.commit,
215
- tag: version.tag,
215
+ tag: version.tag
216
216
  });
217
217
  log?.info(
218
218
  wetrun
219
219
  ? st('green', ` ✅ Published ${pkg_name}@${version.new_version}`)
220
- : st('cyan', ` ◇ Would publish ${pkg_name}@${version.new_version}`),
220
+ : st('cyan', ` ◇ Would publish ${pkg_name}@${version.new_version}`)
221
221
  );
222
222
 
223
223
  if (wetrun) {
@@ -230,9 +230,9 @@ export const execute_publishing_plan = async (
230
230
  max_attempts: 30,
231
231
  initial_delay: 1000,
232
232
  max_delay: 60000,
233
- timeout: options.max_wait ?? GITOPS_NPM_WAIT_TIMEOUT_DEFAULT,
233
+ timeout: options.max_wait ?? GITOPS_NPM_WAIT_TIMEOUT_DEFAULT
234
234
  },
235
- log,
235
+ log
236
236
  });
237
237
 
238
238
  if (!wait_result.ok) {
@@ -240,14 +240,14 @@ export const execute_publishing_plan = async (
240
240
  // carries a typed `timeout` signal, so we know this is a network failure
241
241
  // without sniffing the message.
242
242
  const err = new Error(
243
- `Failed to wait for package: ${wait_result.message}${wait_result.timeout ? ' (timeout)' : ''}`,
243
+ `Failed to wait for package: ${wait_result.message}${wait_result.timeout ? ' (timeout)' : ''}`
244
244
  );
245
245
  failed.set(pkg_name, err);
246
- emit({event: 'package_failed', name: pkg_name, error: err.message, code: 'network'});
246
+ emit({ event: 'package_failed', name: pkg_name, error: err.message, code: 'network' });
247
247
  log?.error(st('red', ` ❌ Failed to publish ${pkg_name}: ${err.message}`));
248
248
  break; // fail fast
249
249
  }
250
- emit({event: 'npm_waited', name: pkg_name, version: version.new_version});
250
+ emit({ event: 'npm_waited', name: pkg_name, version: version.new_version });
251
251
 
252
252
  // 3. Update every dependent the plan says has a prod/peer dep on this package.
253
253
  // This rewrites their package.json ranges and creates their auto-changeset,
@@ -258,7 +258,7 @@ export const execute_publishing_plan = async (
258
258
  published,
259
259
  (update) =>
260
260
  update.updated_dependency === pkg_name &&
261
- (update.type === 'dependencies' || update.type === 'peerDependencies'),
261
+ (update.type === 'dependencies' || update.type === 'peerDependencies')
262
262
  );
263
263
  for (const [dependent_name, updates] of dependent_updates) {
264
264
  const dependent_repo = repo_by_name.get(dependent_name);
@@ -277,7 +277,7 @@ export const execute_publishing_plan = async (
277
277
  dependency: dep_name,
278
278
  version: dep_version,
279
279
  dep_type: dependency_update_type(plan, dependent_name, dep_name),
280
- creates_changeset: republishes,
280
+ creates_changeset: republishes
281
281
  });
282
282
  }
283
283
  changed_repos.add(dependent_name); // Mark as changed for deployment
@@ -287,7 +287,7 @@ export const execute_publishing_plan = async (
287
287
  published_versions: published, // creates the auto-changeset
288
288
  log,
289
289
  git_ops: ops.git,
290
- fs_ops: ops.fs,
290
+ fs_ops: ops.fs
291
291
  });
292
292
  } else {
293
293
  // update-only leaf: rewrite ranges + commit, no changeset (it won't republish)
@@ -295,7 +295,7 @@ export const execute_publishing_plan = async (
295
295
  strategy: options.version_strategy || 'caret',
296
296
  log,
297
297
  git_ops: ops.git,
298
- fs_ops: ops.fs,
298
+ fs_ops: ops.fs
299
299
  });
300
300
  }
301
301
  }
@@ -310,7 +310,7 @@ export const execute_publishing_plan = async (
310
310
  // TODO: emit a precise code once the npm/process ops return typed errors —
311
311
  // today a publish-step cause lives in unstructured stderr, so use the honest
312
312
  // coarse bucket rather than guessing 'auth'/'network'/'build' from the message.
313
- code: 'publish',
313
+ code: 'publish'
314
314
  });
315
315
  log?.error(st('red', ` ❌ Failed to publish ${pkg_name}: ${err.message}`));
316
316
  break; // Always fail fast on error
@@ -327,7 +327,7 @@ export const execute_publishing_plan = async (
327
327
  const dev_updates_by_repo = group_dependency_updates(
328
328
  plan.dependency_updates,
329
329
  published,
330
- (update) => update.type === 'devDependencies',
330
+ (update) => update.type === 'devDependencies'
331
331
  );
332
332
 
333
333
  if (dev_updates_by_repo.size > 0) {
@@ -346,7 +346,7 @@ export const execute_publishing_plan = async (
346
346
  dependency: dep_name,
347
347
  version: dep_version,
348
348
  dep_type: 'dev',
349
- creates_changeset: false, // dev-dep updates redeploy without republishing
349
+ creates_changeset: false // dev-dep updates redeploy without republishing
350
350
  });
351
351
  }
352
352
  changed_repos.add(repo_name); // Mark as changed for deployment
@@ -357,7 +357,7 @@ export const execute_publishing_plan = async (
357
357
  strategy: options.version_strategy || 'caret',
358
358
  log,
359
359
  git_ops: ops.git,
360
- fs_ops: ops.fs,
360
+ fs_ops: ops.fs
361
361
  });
362
362
  }
363
363
  }
@@ -371,15 +371,12 @@ export const execute_publishing_plan = async (
371
371
  .map((name) => repo_by_name.get(name))
372
372
  .filter((r): r is LocalRepo => r !== undefined);
373
373
  log?.info(
374
- st(
375
- 'cyan',
376
- `\n🚢 Deploying ${repos_to_deploy.length}/${repos.length} repos with changes...\n`,
377
- ),
374
+ st('cyan', `\n🚢 Deploying ${repos_to_deploy.length}/${repos.length} repos with changes...\n`)
378
375
  );
379
376
 
380
377
  for (const repo of repos_to_deploy) {
381
378
  try {
382
- emit({event: 'deploy_started', name: repo.library.name});
379
+ emit({ event: 'deploy_started', name: repo.library.name });
383
380
  log?.info(` Deploying ${repo.library.name}...`);
384
381
  // Build fresh (no --no-build): a deployed site bundles its dependencies, so it
385
382
  // must be rebuilt against the versions this run just published — the preflight
@@ -387,19 +384,19 @@ export const execute_publishing_plan = async (
387
384
  const deploy_result = await ops.process.spawn({
388
385
  cmd: 'gro',
389
386
  args: ['deploy'],
390
- cwd: repo.repo_dir,
387
+ cwd: repo.repo_dir
391
388
  });
392
389
 
393
390
  if (deploy_result.ok) {
394
- emit({event: 'deploy_completed', name: repo.library.name});
391
+ emit({ event: 'deploy_completed', name: repo.library.name });
395
392
  log?.info(st('green', ` ✅ Deployed ${repo.library.name}`));
396
393
  } else {
397
- emit({event: 'deploy_failed', name: repo.library.name, error: deploy_result.message});
394
+ emit({ event: 'deploy_failed', name: repo.library.name, error: deploy_result.message });
398
395
  log?.warn(st('yellow', ` ⚠️ Failed to deploy ${repo.library.name}`));
399
396
  }
400
397
  } catch (error) {
401
398
  const err = error instanceof Error ? error : new Error(String(error));
402
- emit({event: 'deploy_failed', name: repo.library.name, error: err.message});
399
+ emit({ event: 'deploy_failed', name: repo.library.name, error: err.message });
403
400
  log?.error(st('red', ` ❌ Error deploying ${repo.library.name}: ${err.message}`));
404
401
  }
405
402
  }
@@ -435,8 +432,8 @@ export const execute_publishing_plan = async (
435
432
  log?.info(
436
433
  st(
437
434
  'green',
438
- `\n✨ Dry run complete — ${published.size} package(s) would be published. Re-run with --wetrun to publish.`,
439
- ),
435
+ `\n✨ Dry run complete — ${published.size} package(s) would be published. Re-run with --wetrun to publish.`
436
+ )
440
437
  );
441
438
  // The dry run is driven by the same plan as `gro gitops_plan`, so this
442
439
  // count includes bump escalations and auto-generated changesets — it
@@ -449,22 +446,22 @@ export const execute_publishing_plan = async (
449
446
  'red',
450
447
  wetrun
451
448
  ? '\n❌ Some packages failed to publish\n'
452
- : '\n❌ Some packages failed during dry run\n',
453
- ),
449
+ : '\n❌ Some packages failed during dry run\n'
450
+ )
454
451
  );
455
452
  }
456
453
 
457
- emit({event: 'run_finished', summary});
454
+ emit({ event: 'run_finished', summary });
458
455
 
459
456
  return {
460
457
  ok,
461
458
  published: Array.from(published.values()),
462
- failed: Array.from(failed.entries()).map(([name, error]) => ({name, error})),
459
+ failed: Array.from(failed.entries()).map(([name, error]) => ({ name, error })),
463
460
  duration,
464
461
  events: capture.events,
465
462
  summary,
466
463
  plan_errors: plan.errors,
467
- plan_warnings: plan.warnings,
464
+ plan_warnings: plan.warnings
468
465
  };
469
466
  };
470
467
 
@@ -483,9 +480,9 @@ const publish_single_repo = async (
483
480
  repo: LocalRepo,
484
481
  options: PublishingOptions,
485
482
  ops: GitopsOperations,
486
- planned: VersionChange,
483
+ planned: VersionChange
487
484
  ): Promise<PublishedVersion> => {
488
- const {wetrun} = options;
485
+ const { wetrun } = options;
489
486
 
490
487
  if (!wetrun) {
491
488
  // Dry run reports the precomputed plan — the single source of truth for the
@@ -497,7 +494,7 @@ const publish_single_repo = async (
497
494
  bump_type: planned.bump_type,
498
495
  breaking: planned.breaking,
499
496
  commit: 'simulated',
500
- tag: `v${planned.to}`,
497
+ tag: `v${planned.to}`
501
498
  };
502
499
  }
503
500
 
@@ -505,7 +502,7 @@ const publish_single_repo = async (
505
502
  const publish_result = await ops.process.spawn({
506
503
  cmd: 'gro',
507
504
  args: ['publish', '--no-build'],
508
- cwd: repo.repo_dir,
505
+ cwd: repo.repo_dir
509
506
  });
510
507
 
511
508
  if (!publish_result.ok) {
@@ -514,7 +511,7 @@ const publish_single_repo = async (
514
511
 
515
512
  // Read the new version from package.json after gro publish
516
513
  const package_json_path = join(repo.repo_dir, 'package.json');
517
- const content_result = await ops.fs.readFile({path: package_json_path, encoding: 'utf8'});
514
+ const content_result = await ops.fs.readFile({ path: package_json_path, encoding: 'utf8' });
518
515
 
519
516
  if (!content_result.ok) {
520
517
  throw new Error(`Failed to read package.json: ${content_result.message}`);
@@ -524,7 +521,7 @@ const publish_single_repo = async (
524
521
  const new_version = package_json.version;
525
522
 
526
523
  // Get actual commit hash
527
- const commit_result = await ops.git.current_commit_hash({cwd: repo.repo_dir});
524
+ const commit_result = await ops.git.current_commit_hash({ cwd: repo.repo_dir });
528
525
 
529
526
  if (!commit_result.ok) {
530
527
  throw new Error(`Failed to get commit hash: ${commit_result.message}`);
@@ -541,7 +538,7 @@ const publish_single_repo = async (
541
538
  bump_type: planned.bump_type,
542
539
  breaking: planned.breaking,
543
540
  commit,
544
- tag: `v${new_version}`,
541
+ tag: `v${new_version}`
545
542
  };
546
543
  };
547
544
 
@@ -554,7 +551,7 @@ const publish_single_repo = async (
554
551
  export const group_dependency_updates = (
555
552
  updates: Array<DependencyUpdate>,
556
553
  published: Map<string, PublishedVersion>,
557
- predicate: (update: DependencyUpdate) => boolean,
554
+ predicate: (update: DependencyUpdate) => boolean
558
555
  ): Map<string, Map<string, string>> => {
559
556
  const by_repo: Map<string, Map<string, string>> = new Map();
560
557
  for (const update of updates) {
@@ -577,13 +574,13 @@ export const group_dependency_updates = (
577
574
  const dependency_update_type = (
578
575
  plan: PublishingPlan,
579
576
  dependent: string,
580
- dependency: string,
577
+ dependency: string
581
578
  ): 'prod' | 'peer' =>
582
579
  plan.dependency_updates.some(
583
580
  (u) =>
584
581
  u.dependent_package === dependent &&
585
582
  u.updated_dependency === dependency &&
586
- u.type === 'peerDependencies',
583
+ u.type === 'peerDependencies'
587
584
  )
588
585
  ? 'peer'
589
586
  : 'prod';
@@ -1,7 +1,7 @@
1
- import type {Logger} from '@fuzdev/fuz_util/log.ts';
2
- import {spawn_out} from '@fuzdev/fuz_util/process.ts';
3
- import {wait} from '@fuzdev/fuz_util/async.ts';
4
- import {styleText as st} from 'node:util';
1
+ import type { Logger } from '@fuzdev/fuz_util/log.ts';
2
+ import { spawn_out } from '@fuzdev/fuz_util/process.ts';
3
+ import { wait } from '@fuzdev/fuz_util/async.ts';
4
+ import { styleText as st } from 'node:util';
5
5
 
6
6
  export interface WaitOptions {
7
7
  log?: Logger;
@@ -19,9 +19,9 @@ export interface PackageInfo {
19
19
  export const check_package_available = async (
20
20
  pkg: string,
21
21
  version: string,
22
- options: {log?: Logger} = {},
22
+ options: { log?: Logger } = {}
23
23
  ): Promise<boolean> => {
24
- const {log} = options;
24
+ const { log } = options;
25
25
  try {
26
26
  // Use npm view to check if the specific version exists
27
27
  const result = await spawn_out('npm', ['view', `${pkg}@${version}`, 'version']);
@@ -57,14 +57,14 @@ export const check_package_available = async (
57
57
  export const wait_for_package = async (
58
58
  pkg: string,
59
59
  version: string,
60
- options: WaitOptions = {},
60
+ options: WaitOptions = {}
61
61
  ): Promise<void> => {
62
62
  const {
63
63
  log,
64
64
  max_attempts = 30,
65
65
  initial_delay = 1000,
66
66
  max_delay = 60000,
67
- timeout = 300000, // 5 minutes default
67
+ timeout = 300000 // 5 minutes default
68
68
  } = options;
69
69
 
70
70
  const start_time = Date.now();
@@ -81,7 +81,7 @@ export const wait_for_package = async (
81
81
 
82
82
  // Check if package is available
83
83
 
84
- if (await check_package_available(pkg, version, {log})) {
84
+ if (await check_package_available(pkg, version, { log })) {
85
85
  log?.info(st('green', ` ✓ ${pkg}@${version} is now available on NPM`));
86
86
  return;
87
87
  }
@@ -113,9 +113,9 @@ export const wait_for_package = async (
113
113
  */
114
114
  export const get_package_info = async (
115
115
  pkg: string,
116
- options: {log?: Logger} = {},
116
+ options: { log?: Logger } = {}
117
117
  ): Promise<PackageInfo | null> => {
118
- const {log} = options;
118
+ const { log } = options;
119
119
  try {
120
120
  const result = await spawn_out('npm', ['view', pkg, '--json']);
121
121
 
@@ -123,7 +123,7 @@ export const get_package_info = async (
123
123
  const data = JSON.parse(result.stdout);
124
124
  return {
125
125
  name: data.name,
126
- version: data.version,
126
+ version: data.version
127
127
  };
128
128
  }
129
129
 
@@ -136,7 +136,7 @@ export const get_package_info = async (
136
136
 
137
137
  export const package_exists = async (
138
138
  pkg: string,
139
- options: {log?: Logger} = {},
139
+ options: { log?: Logger } = {}
140
140
  ): Promise<boolean> => {
141
141
  const info = await get_package_info(pkg, options);
142
142
  return info !== null;