@fuzdev/fuz_gitops 0.78.0 → 0.79.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 (196) hide show
  1. package/README.md +91 -17
  2. package/dist/ModulesDetail.svelte +22 -27
  3. package/dist/ModulesDetail.svelte.d.ts.map +1 -1
  4. package/dist/ModulesNav.svelte +8 -5
  5. package/dist/ModulesNav.svelte.d.ts.map +1 -1
  6. package/dist/ModulesPage.svelte +3 -5
  7. package/dist/ModulesPage.svelte.d.ts.map +1 -1
  8. package/dist/PageFooter.svelte +2 -2
  9. package/dist/PageHeader.svelte +6 -6
  10. package/dist/PageHeader.svelte.d.ts +0 -3
  11. package/dist/PageHeader.svelte.d.ts.map +1 -1
  12. package/dist/PullRequestsDetail.svelte +29 -20
  13. package/dist/PullRequestsDetail.svelte.d.ts.map +1 -1
  14. package/dist/PullRequestsPage.svelte +4 -6
  15. package/dist/PullRequestsPage.svelte.d.ts.map +1 -1
  16. package/dist/ReposTable.svelte +43 -55
  17. package/dist/ReposTable.svelte.d.ts.map +1 -1
  18. package/dist/ReposTree.svelte +9 -21
  19. package/dist/ReposTree.svelte.d.ts.map +1 -1
  20. package/dist/ReposTreeNav.svelte +9 -12
  21. package/dist/ReposTreeNav.svelte.d.ts.map +1 -1
  22. package/dist/TablePage.svelte +3 -5
  23. package/dist/TablePage.svelte.d.ts.map +1 -1
  24. package/dist/TreeItemPage.svelte +3 -5
  25. package/dist/TreeItemPage.svelte.d.ts.map +1 -1
  26. package/dist/TreePage.svelte +3 -5
  27. package/dist/TreePage.svelte.d.ts.map +1 -1
  28. package/dist/changeset_generator.d.ts.map +1 -1
  29. package/dist/changeset_generator.js +2 -2
  30. package/dist/changeset_reader.d.ts.map +1 -1
  31. package/dist/changeset_reader.js +3 -3
  32. package/dist/ci_reconcile.d.ts +6 -10
  33. package/dist/ci_reconcile.d.ts.map +1 -1
  34. package/dist/ci_reconcile.js +6 -8
  35. package/dist/dependency_graph.d.ts +26 -49
  36. package/dist/dependency_graph.d.ts.map +1 -1
  37. package/dist/dependency_graph.js +40 -83
  38. package/dist/dependency_updater.d.ts +1 -1
  39. package/dist/dependency_updater.d.ts.map +1 -1
  40. package/dist/dependency_updater.js +14 -9
  41. package/dist/fetch_repo_data.d.ts +34 -8
  42. package/dist/fetch_repo_data.d.ts.map +1 -1
  43. package/dist/fetch_repo_data.js +44 -22
  44. package/dist/fs_fetch_value_cache.d.ts +1 -1
  45. package/dist/fs_fetch_value_cache.d.ts.map +1 -1
  46. package/dist/fs_fetch_value_cache.js +3 -3
  47. package/dist/git_operations.d.ts +6 -49
  48. package/dist/git_operations.d.ts.map +1 -1
  49. package/dist/git_operations.js +13 -126
  50. package/dist/github.d.ts +17 -2
  51. package/dist/github.d.ts.map +1 -1
  52. package/dist/github.js +17 -8
  53. package/dist/github_helpers.d.ts.map +1 -1
  54. package/dist/github_helpers.js +3 -11
  55. package/dist/gitops_analyze.task.d.ts +24 -2
  56. package/dist/gitops_analyze.task.d.ts.map +1 -1
  57. package/dist/gitops_analyze.task.js +47 -34
  58. package/dist/gitops_config.d.ts +34 -79
  59. package/dist/gitops_config.d.ts.map +1 -1
  60. package/dist/gitops_config.js +76 -53
  61. package/dist/gitops_constants.d.ts +6 -4
  62. package/dist/gitops_constants.d.ts.map +1 -1
  63. package/dist/gitops_constants.js +6 -4
  64. package/dist/gitops_plan.task.d.ts +29 -3
  65. package/dist/gitops_plan.task.d.ts.map +1 -1
  66. package/dist/gitops_plan.task.js +83 -61
  67. package/dist/gitops_publish.task.d.ts +62 -2
  68. package/dist/gitops_publish.task.d.ts.map +1 -1
  69. package/dist/gitops_publish.task.js +193 -105
  70. package/dist/gitops_run.task.d.ts +74 -0
  71. package/dist/gitops_run.task.d.ts.map +1 -1
  72. package/dist/gitops_run.task.js +176 -162
  73. package/dist/gitops_sync.task.d.ts +65 -3
  74. package/dist/gitops_sync.task.d.ts.map +1 -1
  75. package/dist/gitops_sync.task.js +163 -37
  76. package/dist/gitops_task_helpers.d.ts +86 -59
  77. package/dist/gitops_task_helpers.d.ts.map +1 -1
  78. package/dist/gitops_task_helpers.js +120 -79
  79. package/dist/gitops_validate.task.d.ts +1 -2
  80. package/dist/gitops_validate.task.d.ts.map +1 -1
  81. package/dist/gitops_validate.task.js +25 -32
  82. package/dist/graph_validation.d.ts +16 -27
  83. package/dist/graph_validation.d.ts.map +1 -1
  84. package/dist/graph_validation.js +24 -65
  85. package/dist/local_repo.d.ts +50 -62
  86. package/dist/local_repo.d.ts.map +1 -1
  87. package/dist/local_repo.js +83 -196
  88. package/dist/log_helpers.d.ts +8 -8
  89. package/dist/log_helpers.d.ts.map +1 -1
  90. package/dist/multi_repo_publisher.d.ts +10 -0
  91. package/dist/multi_repo_publisher.d.ts.map +1 -1
  92. package/dist/multi_repo_publisher.js +125 -61
  93. package/dist/npm_registry.d.ts +23 -19
  94. package/dist/npm_registry.d.ts.map +1 -1
  95. package/dist/npm_registry.js +21 -48
  96. package/dist/operations.d.ts +75 -180
  97. package/dist/operations.d.ts.map +1 -1
  98. package/dist/operations.js +15 -7
  99. package/dist/operations_defaults.d.ts +17 -2
  100. package/dist/operations_defaults.d.ts.map +1 -1
  101. package/dist/operations_defaults.js +111 -128
  102. package/dist/output_helpers.d.ts +36 -0
  103. package/dist/output_helpers.d.ts.map +1 -1
  104. package/dist/output_helpers.js +37 -3
  105. package/dist/preflight_checks.d.ts +20 -27
  106. package/dist/preflight_checks.d.ts.map +1 -1
  107. package/dist/preflight_checks.js +37 -126
  108. package/dist/publish_gate.d.ts.map +1 -1
  109. package/dist/publish_steps.d.ts +2 -4
  110. package/dist/publish_steps.d.ts.map +1 -1
  111. package/dist/publish_steps.js +4 -8
  112. package/dist/publishing_event.d.ts +2 -8
  113. package/dist/publishing_event.d.ts.map +1 -1
  114. package/dist/publishing_event.js +20 -17
  115. package/dist/publishing_event_handler.d.ts +10 -8
  116. package/dist/publishing_event_handler.d.ts.map +1 -1
  117. package/dist/publishing_event_handler.js +19 -17
  118. package/dist/publishing_plan.d.ts +16 -1
  119. package/dist/publishing_plan.d.ts.map +1 -1
  120. package/dist/publishing_plan.js +332 -254
  121. package/dist/publishing_plan_helpers.d.ts.map +1 -1
  122. package/dist/publishing_plan_helpers.js +3 -3
  123. package/dist/publishing_plan_logging.d.ts +1 -1
  124. package/dist/publishing_plan_logging.d.ts.map +1 -1
  125. package/dist/publishing_plan_logging.js +22 -15
  126. package/dist/repo.svelte.d.ts +7 -0
  127. package/dist/repo.svelte.d.ts.map +1 -1
  128. package/dist/repo.svelte.js +3 -0
  129. package/dist/repo_readiness.d.ts +210 -0
  130. package/dist/repo_readiness.d.ts.map +1 -0
  131. package/dist/repo_readiness.js +516 -0
  132. package/dist/repos_status.d.ts +3340 -0
  133. package/dist/repos_status.d.ts.map +1 -0
  134. package/dist/repos_status.js +555 -0
  135. package/dist/repos_status_load.d.ts +65 -0
  136. package/dist/repos_status_load.d.ts.map +1 -0
  137. package/dist/repos_status_load.js +131 -0
  138. package/dist/version_utils.js +1 -1
  139. package/package.json +15 -34
  140. package/src/lib/cargo_toml.ts +3 -3
  141. package/src/lib/changeset_generator.ts +19 -19
  142. package/src/lib/changeset_reader.ts +18 -18
  143. package/src/lib/ci_reconcile.ts +12 -16
  144. package/src/lib/dependency_graph.ts +61 -113
  145. package/src/lib/dependency_updater.ts +36 -30
  146. package/src/lib/fetch_repo_data.ts +71 -34
  147. package/src/lib/fs_fetch_value_cache.ts +15 -11
  148. package/src/lib/git_operations.ts +22 -194
  149. package/src/lib/github.ts +33 -21
  150. package/src/lib/github_helpers.ts +9 -16
  151. package/src/lib/gitops_analyze.task.ts +104 -66
  152. package/src/lib/gitops_config.ts +90 -139
  153. package/src/lib/gitops_constants.ts +6 -4
  154. package/src/lib/gitops_plan.task.ts +128 -76
  155. package/src/lib/gitops_publish.task.ts +280 -144
  156. package/src/lib/gitops_run.task.ts +265 -193
  157. package/src/lib/gitops_sync.task.ts +236 -52
  158. package/src/lib/gitops_task_helpers.ts +170 -114
  159. package/src/lib/gitops_validate.task.ts +44 -54
  160. package/src/lib/graph_validation.ts +28 -89
  161. package/src/lib/local_repo.ts +128 -335
  162. package/src/lib/log_helpers.ts +18 -28
  163. package/src/lib/multi_repo_publisher.ts +192 -110
  164. package/src/lib/npm_registry.ts +42 -67
  165. package/src/lib/operations.ts +99 -160
  166. package/src/lib/operations_defaults.ts +157 -201
  167. package/src/lib/output_helpers.ts +58 -6
  168. package/src/lib/preflight_checks.ts +52 -188
  169. package/src/lib/publish_gate.ts +7 -9
  170. package/src/lib/publish_steps.ts +27 -25
  171. package/src/lib/publishing_event.ts +26 -23
  172. package/src/lib/publishing_event_handler.ts +24 -22
  173. package/src/lib/publishing_plan.ts +474 -310
  174. package/src/lib/publishing_plan_helpers.ts +16 -12
  175. package/src/lib/publishing_plan_logging.ts +53 -44
  176. package/src/lib/repo.svelte.ts +16 -8
  177. package/src/lib/repo_readiness.ts +647 -0
  178. package/src/lib/repos_status.ts +671 -0
  179. package/src/lib/repos_status_load.ts +173 -0
  180. package/src/lib/version_utils.ts +3 -3
  181. package/dist/config_reconcile.d.ts +0 -46
  182. package/dist/config_reconcile.d.ts.map +0 -1
  183. package/dist/config_reconcile.js +0 -60
  184. package/dist/paths.d.ts +0 -7
  185. package/dist/paths.d.ts.map +0 -1
  186. package/dist/paths.js +0 -6
  187. package/dist/repo_ops.d.ts +0 -59
  188. package/dist/repo_ops.d.ts.map +0 -1
  189. package/dist/repo_ops.js +0 -170
  190. package/dist/resolved_gitops_config.d.ts +0 -9
  191. package/dist/resolved_gitops_config.d.ts.map +0 -1
  192. package/dist/resolved_gitops_config.js +0 -12
  193. package/src/lib/config_reconcile.ts +0 -94
  194. package/src/lib/paths.ts +0 -6
  195. package/src/lib/repo_ops.ts +0 -216
  196. package/src/lib/resolved_gitops_config.ts +0 -27
@@ -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;
@@ -11,28 +11,44 @@ export interface WaitOptions {
11
11
  timeout?: number;
12
12
  }
13
13
 
14
- export interface PackageInfo {
15
- name: string;
16
- version: string;
14
+ /**
15
+ * The side effects of the registry checks — running npm, sleeping, and reading
16
+ * the clock — injected so tests drive them with plain objects.
17
+ */
18
+ export interface NpmRegistryDeps {
19
+ /**
20
+ * Runs `npm` with `args` and resolves to what it wrote to stdout — empty when
21
+ * nothing, or when npm couldn't run. A throw counts as unavailable too.
22
+ */
23
+ run_npm: (args: Array<string>) => Promise<string>;
24
+ /** Sleeps for `ms` milliseconds. */
25
+ wait: (ms: number) => Promise<void>;
26
+ /** The current time in milliseconds, as `Date.now`. */
27
+ now: () => number;
17
28
  }
18
29
 
30
+ export const default_npm_registry_deps: NpmRegistryDeps = {
31
+ run_npm: async (args) => (await spawn_out('npm', args)).stdout ?? '',
32
+ wait,
33
+ now: () => Date.now()
34
+ };
35
+
36
+ /**
37
+ * Checks whether `pkg@version` is on the npm registry, by `npm view`.
38
+ *
39
+ * @returns `true` when the registry reports that exact version, `false` when it
40
+ * doesn't or npm couldn't run
41
+ */
19
42
  export const check_package_available = async (
20
43
  pkg: string,
21
44
  version: string,
22
- options: {log?: Logger} = {},
45
+ options: { log?: Logger } = {},
46
+ deps: NpmRegistryDeps = default_npm_registry_deps
23
47
  ): Promise<boolean> => {
24
- const {log} = options;
48
+ const { log } = options;
25
49
  try {
26
- // Use npm view to check if the specific version exists
27
- const result = await spawn_out('npm', ['view', `${pkg}@${version}`, 'version']);
28
-
29
- if (result.stdout) {
30
- const output = result.stdout.trim();
31
- // If we get a version back, it exists
32
- return output === version;
33
- }
34
-
35
- return false;
50
+ const stdout = await deps.run_npm(['view', `${pkg}@${version}`, 'version']);
51
+ return stdout.trim() === version;
36
52
  } catch (error) {
37
53
  log?.debug(`Failed to check ${pkg}@${version}: ${error}`);
38
54
  return false;
@@ -58,43 +74,41 @@ export const wait_for_package = async (
58
74
  pkg: string,
59
75
  version: string,
60
76
  options: WaitOptions = {},
77
+ deps: NpmRegistryDeps = default_npm_registry_deps
61
78
  ): Promise<void> => {
62
79
  const {
63
80
  log,
64
81
  max_attempts = 30,
65
82
  initial_delay = 1000,
66
83
  max_delay = 60000,
67
- timeout = 300000, // 5 minutes default
84
+ timeout = 300000 // 5 minutes default
68
85
  } = options;
69
86
 
70
- const start_time = Date.now();
87
+ const start_time = deps.now();
71
88
  let attempt = 0;
72
89
  let delay = initial_delay;
73
90
 
74
91
  while (attempt < max_attempts) {
75
92
  attempt++;
76
93
 
77
- // Check timeout
78
- if (Date.now() - start_time > timeout) {
94
+ if (deps.now() - start_time > timeout) {
79
95
  throw new Error(`Timeout waiting for ${pkg}@${version} after ${timeout}ms`);
80
96
  }
81
97
 
82
- // Check if package is available
83
-
84
- if (await check_package_available(pkg, version, {log})) {
98
+ if (await check_package_available(pkg, version, { log }, deps)) {
85
99
  log?.info(st('green', ` ✓ ${pkg}@${version} is now available on NPM`));
86
100
  return;
87
101
  }
88
102
 
89
103
  // Log progress occasionally
90
- if (attempt > 0 && attempt % 5 === 0) {
104
+ if (attempt % 5 === 0) {
91
105
  log?.info(st('dim', ` Still waiting... (attempt ${attempt}/${max_attempts})`));
92
106
  }
93
107
 
94
108
  // Wait with exponential backoff + jitter
95
109
  const jitter = Math.random() * delay * 0.1; // 10% jitter
96
110
  const actual_delay = Math.min(delay + jitter, max_delay);
97
- await wait(actual_delay);
111
+ await deps.wait(actual_delay);
98
112
 
99
113
  // Exponential backoff
100
114
  delay = Math.min(delay * 1.5, max_delay);
@@ -102,42 +116,3 @@ export const wait_for_package = async (
102
116
 
103
117
  throw new Error(`${pkg}@${version} not available after ${max_attempts} attempts`);
104
118
  };
105
-
106
- /**
107
- * Fetches package metadata from NPM registry.
108
- *
109
- * Returns name and latest version. Returns null if package doesn't exist
110
- * or registry is unreachable.
111
- *
112
- * @returns package info or null on error/not found
113
- */
114
- export const get_package_info = async (
115
- pkg: string,
116
- options: {log?: Logger} = {},
117
- ): Promise<PackageInfo | null> => {
118
- const {log} = options;
119
- try {
120
- const result = await spawn_out('npm', ['view', pkg, '--json']);
121
-
122
- if (result.stdout) {
123
- const data = JSON.parse(result.stdout);
124
- return {
125
- name: data.name,
126
- version: data.version,
127
- };
128
- }
129
-
130
- return null;
131
- } catch (error) {
132
- log?.debug(`Failed to get package info for ${pkg}: ${error}`);
133
- return null;
134
- }
135
- };
136
-
137
- export const package_exists = async (
138
- pkg: string,
139
- options: {log?: Logger} = {},
140
- ): Promise<boolean> => {
141
- const info = await get_package_info(pkg, options);
142
- return info !== null;
143
- };
@@ -2,7 +2,8 @@
2
2
  * Operations interfaces for dependency injection.
3
3
  *
4
4
  * This is the core pattern enabling testability without mocks.
5
- * All side effects (git, npm, fs, process) are abstracted into interfaces.
5
+ * All side effects (git, npm, fs, process, build, and the `repos` binary) are
6
+ * abstracted into interfaces.
6
7
  *
7
8
  * **Design principles:**
8
9
  * - All operations accept a single `options` object parameter
@@ -13,35 +14,42 @@
13
14
  *
14
15
  * **Production usage:**
15
16
  * ```typescript
16
- * import {default_gitops_operations} from './operations_defaults.js';
17
- * const result = await ops.git.current_branch_name({cwd: '/path'});
17
+ * import {default_gitops_operations} from './operations_defaults.ts';
18
+ * const ops = default_gitops_operations;
19
+ * const result = await ops.git.current_commit_hash({cwd: '/path'});
18
20
  * if (!result.ok) {
19
21
  * throw new TaskError(result.message);
20
22
  * }
21
- * const branch = result.value;
23
+ * const commit = result.value;
22
24
  * ```
23
25
  *
24
26
  * **Test usage:**
25
27
  * ```typescript
26
- * const mock_ops = create_mock_operations();
27
- * const result = await publish_repos(repos, {...options, ops: mock_ops});
28
+ * import {create_mock_gitops_ops} from './test_helpers.ts';
29
+ * const ops = create_mock_gitops_ops({
30
+ * changeset: {has_changesets: async () => ({ok: true, value: false})}
31
+ * });
32
+ * const result = await publish_repos(repos, {...options, ops});
28
33
  * // Assert on result without any real git/npm calls
29
34
  * ```
30
35
  *
31
- * See `operations_defaults.ts` for real implementations.
32
- * See test files (`*.test.ts`) for mock implementations.
36
+ * See `operations_defaults.ts` for real implementations, and the test-side mock
37
+ * factories: `create_mock_gitops_ops` in `src/test/test_helpers.ts` (plain
38
+ * objects with per-group overrides) and `create_fixture_gitops_ops` in
39
+ * `src/test/fixtures/mock_operations.ts` (a fixture's changesets over
40
+ * `create_mock_gitops_ops`, its fs empty).
33
41
  *
34
42
  * @module
35
43
  */
36
44
 
37
- import type {Result} from '@fuzdev/fuz_util/result.ts';
38
- import type {FsError} from '@fuzdev/fuz_util/fs.ts';
39
- import type {Logger} from '@fuzdev/fuz_util/log.ts';
40
- import type {LocalRepo} from './local_repo.ts';
41
- import type {ChangesetInfo} from './changeset_reader.ts';
42
- import type {BumpType} from './version_utils.ts';
43
- import type {PreflightOptions, PreflightResult} from './preflight_checks.ts';
44
- import type {WaitOptions} from './npm_registry.ts';
45
+ import type { Result } from '@fuzdev/fuz_util/result.ts';
46
+ import type { FsError } from '@fuzdev/fuz_util/fs.ts';
47
+ import type { Logger } from '@fuzdev/fuz_util/log.ts';
48
+ import type { LocalRepo } from './local_repo.ts';
49
+ import type { ChangesetInfo } from './changeset_reader.ts';
50
+ import type { BumpType } from './version_utils.ts';
51
+ import type { PreflightResult, RunPreflightChecksOptions } from './preflight_checks.ts';
52
+ import type { WaitOptions } from './npm_registry.ts';
45
53
 
46
54
  /**
47
55
  * Changeset operations for reading and predicting versions from `.changeset/*.md` files.
@@ -53,7 +61,7 @@ export interface ChangesetOperations {
53
61
  */
54
62
  has_changesets: (options: {
55
63
  repo: LocalRepo;
56
- }) => Promise<Result<{value: boolean}, {message: string}>>;
64
+ }) => Promise<Result<{ value: boolean }, { message: string }>>;
57
65
 
58
66
  /**
59
67
  * Reads all changeset files from a repo.
@@ -62,7 +70,7 @@ export interface ChangesetOperations {
62
70
  read_changesets: (options: {
63
71
  repo: LocalRepo;
64
72
  log?: Logger;
65
- }) => Promise<Result<{value: Array<ChangesetInfo>}, {message: string}>>;
73
+ }) => Promise<Result<{ value: Array<ChangesetInfo> }, { message: string }>>;
66
74
 
67
75
  /**
68
76
  * Predicts the next version based on changesets.
@@ -72,66 +80,22 @@ export interface ChangesetOperations {
72
80
  predict_next_version: (options: {
73
81
  repo: LocalRepo;
74
82
  log?: Logger;
75
- }) => Promise<Result<{version: string; bump_type: BumpType}, {message: string}> | null>;
83
+ }) => Promise<Result<{ version: string; bump_type: BumpType }, { message: string }> | null>;
76
84
  }
77
85
 
78
86
  /**
79
- * Git operations for branch management, commits, tags, and workspace state.
80
- * All operations return `Result` instead of throwing errors.
87
+ * Git operations the publishing executor authors with: staging and committing
88
+ * dependency updates and auto-changesets, and reading the commit it published.
89
+ * All operations return `Result` instead of throwing errors. Where each repo
90
+ * sits (branch, dirt, relation to origin) is `ReposOperations`'s to report.
81
91
  */
82
92
  export interface GitOperations {
83
- /**
84
- * Gets the current branch name.
85
- */
86
- current_branch_name: (options?: {
87
- cwd?: string;
88
- }) => Promise<Result<{value: string}, {message: string}>>;
89
-
90
93
  /**
91
94
  * Gets the current commit hash.
92
95
  */
93
96
  current_commit_hash: (options?: {
94
- branch?: string;
95
97
  cwd?: string;
96
- }) => Promise<Result<{value: string}, {message: string}>>;
97
-
98
- /**
99
- * Checks if the workspace is clean (no uncommitted changes).
100
- */
101
- check_clean_workspace: (options?: {
102
- cwd?: string;
103
- }) => Promise<Result<{value: boolean}, {message: string}>>;
104
-
105
- /**
106
- * Checks out a branch.
107
- */
108
- checkout: (options: {branch: string; cwd?: string}) => Promise<Result<object, {message: string}>>;
109
-
110
- /**
111
- * Pulls changes from remote.
112
- */
113
- pull: (options?: {
114
- origin?: string;
115
- branch?: string;
116
- cwd?: string;
117
- }) => Promise<Result<object, {message: string}>>;
118
-
119
- /**
120
- * Switches to a branch, optionally pulling.
121
- */
122
- switch_branch: (options: {
123
- branch: string;
124
- pull?: boolean;
125
- cwd?: string;
126
- }) => Promise<Result<object, {message: string}>>;
127
-
128
- /**
129
- * Checks if a remote exists.
130
- */
131
- has_remote: (options?: {
132
- remote?: string;
133
- cwd?: string;
134
- }) => Promise<Result<{value: boolean}, {message: string}>>;
98
+ }) => Promise<Result<{ value: string }, { message: string }>>;
135
99
 
136
100
  /**
137
101
  * Stages files for commit.
@@ -139,88 +103,75 @@ export interface GitOperations {
139
103
  add: (options: {
140
104
  files: string | Array<string>;
141
105
  cwd?: string;
142
- }) => Promise<Result<object, {message: string}>>;
143
-
144
- /**
145
- * Creates a commit.
146
- */
147
- commit: (options: {message: string; cwd?: string}) => Promise<Result<object, {message: string}>>;
106
+ }) => Promise<Result<object, { message: string }>>;
148
107
 
149
108
  /**
150
- * Stages files and creates a commit.
109
+ * Commits `files` alone (`git commit -- <files>`), leaving anything else
110
+ * staged out of the commit; `files` must be non-empty.
151
111
  */
152
- add_and_commit: (options: {
153
- files: string | Array<string>;
112
+ commit: (options: {
154
113
  message: string;
114
+ files: Array<string>;
155
115
  cwd?: string;
156
- }) => Promise<Result<object, {message: string}>>;
157
-
158
- /**
159
- * Checks whether the working tree has any changes — staged, unstaged, or
160
- * untracked (`git status --porcelain`). Broader than `list_uncommitted_files`,
161
- * which reports only tracked working-tree changes relative to HEAD.
162
- */
163
- has_changes: (options?: {cwd?: string}) => Promise<Result<{value: boolean}, {message: string}>>;
164
-
165
- /**
166
- * Lists uncommitted files in the working tree (`git diff --name-only HEAD`),
167
- * i.e. working-tree changes relative to HEAD (not a diff between two refs).
168
- */
169
- list_uncommitted_files: (options?: {
170
- cwd?: string;
171
- }) => Promise<Result<{value: Array<string>}, {message: string}>>;
172
-
173
- /**
174
- * Creates a git tag.
175
- */
176
- tag: (options: {
177
- tag_name: string;
178
- message?: string;
179
- cwd?: string;
180
- }) => Promise<Result<object, {message: string}>>;
116
+ }) => Promise<Result<object, { message: string }>>;
117
+ }
181
118
 
119
+ /**
120
+ * Process operations for the commands the publishing executor runs in a repo
121
+ * (`gro publish`, `gro deploy`).
122
+ */
123
+ export interface ProcessOperations {
182
124
  /**
183
- * Pushes a tag to remote.
125
+ * Runs a command in the foreground and waits for it to exit: stdin is the
126
+ * terminal's, so a prompt (npm's 2FA one-time password) can be answered, and
127
+ * the child's output shows live — its stdout on ours, or on our stderr when
128
+ * `stdout` says so, and its stderr on ours. A failure carries the end of
129
+ * what the child wrote to stderr, bounded in lines and characters.
184
130
  */
185
- push_tag: (options: {
186
- tag_name: string;
187
- origin?: string;
131
+ run_interactive: (options: {
132
+ cmd: string;
133
+ args: Array<string>;
188
134
  cwd?: string;
189
- }) => Promise<Result<object, {message: string}>>;
190
-
191
- /**
192
- * Stashes uncommitted changes.
193
- */
194
- stash: (options?: {message?: string; cwd?: string}) => Promise<Result<object, {message: string}>>;
195
-
196
- /**
197
- * Pops the most recent stash.
198
- */
199
- stash_pop: (options?: {cwd?: string}) => Promise<Result<object, {message: string}>>;
135
+ /**
136
+ * Where the child's stdout goes: our stdout, or our stderr when our stdout
137
+ * carries a machine-readable stream (JSON-lines events, a JSON or markdown
138
+ * report) the child's output would corrupt.
139
+ *
140
+ * @default 'stdout'
141
+ */
142
+ stdout?: 'stdout' | 'stderr';
143
+ }) => Promise<Result<object, { message: string; stderr_tail?: string }>>;
144
+ }
200
145
 
201
- /**
202
- * Checks if a specific file changed between two commits.
203
- */
204
- has_file_changed: (options: {
205
- from_commit: string;
206
- to_commit: string;
207
- file_path: string;
208
- cwd?: string;
209
- }) => Promise<Result<{value: boolean}, {message: string}>>;
146
+ /**
147
+ * What a `repos` command printed and how it exited, unparsed.
148
+ */
149
+ export interface ReposCommandOutput {
150
+ stdout: string;
151
+ stderr: string;
152
+ /** `0` for a report, `2` for an error document, `1` for a fatal I/O error (maybe no JSON). */
153
+ exit_code: number;
210
154
  }
211
155
 
212
156
  /**
213
- * Process spawning operations for running shell commands.
157
+ * Operations running the Rust `repos` binary, which owns fleet git state.
158
+ * Parsing its output is `repos_status_load.ts`'s, not the runner's.
214
159
  */
215
- export interface ProcessOperations {
160
+ export interface ReposOperations {
216
161
  /**
217
- * Spawns a child process and waits for completion.
162
+ * Runs `repos [--registry <path>] status [--fetch] <keys…> --json` in the
163
+ * process's cwd and returns what it printed, whatever its exit code. With
164
+ * `fetch`, `repos` fetches each entry from origin first, which writes
165
+ * remote-tracking refs and nothing else. Fails only when the binary didn't
166
+ * run to an exit: `not_found` when it isn't on `PATH`.
218
167
  */
219
- spawn: (options: {
220
- cmd: string;
221
- args: Array<string>;
222
- cwd?: string;
223
- }) => Promise<Result<{stdout?: string; stderr?: string}, {message: string; stderr?: string}>>;
168
+ status: (options: {
169
+ keys: Array<string>;
170
+ registry?: string;
171
+ fetch?: boolean;
172
+ }) => Promise<
173
+ Result<{ output: ReposCommandOutput }, { kind: 'not_found' | 'failed'; message: string }>
174
+ >;
224
175
  }
225
176
 
226
177
  /**
@@ -232,8 +183,7 @@ export interface BuildOperations {
232
183
  */
233
184
  build_package: (options: {
234
185
  repo: LocalRepo;
235
- log?: Logger;
236
- }) => Promise<Result<object, {message: string; output?: string}>>;
186
+ }) => Promise<Result<object, { message: string; output?: string }>>;
237
187
  }
238
188
 
239
189
  /**
@@ -250,42 +200,29 @@ export interface NpmOperations {
250
200
  version: string;
251
201
  wait_options?: WaitOptions;
252
202
  log?: Logger;
253
- }) => Promise<Result<object, {message: string; timeout?: boolean}>>;
203
+ }) => Promise<Result<object, { message: string }>>;
254
204
 
255
205
  /**
256
206
  * Checks npm authentication status.
257
207
  */
258
- check_auth: () => Promise<Result<{username: string}, {message: string}>>;
208
+ check_auth: () => Promise<Result<{ username: string }, { message: string }>>;
259
209
 
260
210
  /**
261
211
  * Checks if npm registry is reachable.
262
212
  */
263
- check_registry: () => Promise<Result<object, {message: string}>>;
264
-
265
- /**
266
- * Installs npm dependencies.
267
- */
268
- install: (options?: {
269
- cwd?: string;
270
- }) => Promise<Result<object, {message: string; stderr?: string}>>;
213
+ check_registry: () => Promise<Result<object, { message: string }>>;
271
214
  }
272
215
 
273
216
  /**
274
- * Preflight validation operations to ensure repos are ready for publishing.
275
- * Validates workspace state, branches, builds, and npm authentication.
217
+ * Preflight validation operations run before publishing: building every
218
+ * package the plan publishes, and npm authentication. Repo git state is the
219
+ * readiness gate's, before preflight (see `repo_readiness.ts`).
276
220
  */
277
221
  export interface PreflightOperations {
278
222
  /**
279
223
  * Runs preflight validation checks before publishing.
280
224
  */
281
- run_preflight_checks: (options: {
282
- repos: Array<LocalRepo>;
283
- preflight_options: PreflightOptions;
284
- git_ops?: GitOperations;
285
- npm_ops?: NpmOperations;
286
- build_ops?: BuildOperations;
287
- changeset_ops?: ChangesetOperations;
288
- }) => Promise<PreflightResult>;
225
+ run_preflight_checks: (options: RunPreflightChecksOptions) => Promise<PreflightResult>;
289
226
  }
290
227
 
291
228
  /**
@@ -302,22 +239,22 @@ export interface FsOperations {
302
239
  readFile: (options: {
303
240
  path: string;
304
241
  encoding: BufferEncoding;
305
- }) => Promise<Result<{value: string}, FsError>>;
242
+ }) => Promise<Result<{ value: string }, FsError>>;
306
243
 
307
244
  /**
308
245
  * Writes a file to the file system.
309
246
  */
310
- writeFile: (options: {path: string; content: string}) => Promise<Result<object, FsError>>;
247
+ writeFile: (options: { path: string; content: string }) => Promise<Result<object, FsError>>;
311
248
 
312
249
  /**
313
250
  * Creates a directory, optionally with recursive creation.
314
251
  */
315
- mkdir: (options: {path: string; recursive?: boolean}) => Promise<Result<object, FsError>>;
252
+ mkdir: (options: { path: string; recursive?: boolean }) => Promise<Result<object, FsError>>;
316
253
 
317
254
  /**
318
255
  * Checks if a path exists on the file system.
319
256
  */
320
- exists: (options: {path: string}) => Promise<boolean>;
257
+ exists: (options: { path: string }) => Promise<boolean>;
321
258
  }
322
259
 
323
260
  /**
@@ -332,4 +269,6 @@ export interface GitopsOperations {
332
269
  preflight: PreflightOperations;
333
270
  fs: FsOperations;
334
271
  build: BuildOperations;
272
+ /** `repos status`, for the executor's re-check of each repo right before its publish. */
273
+ repos: ReposOperations;
335
274
  }