@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
@@ -0,0 +1,173 @@
1
+ /**
2
+ * Reads fleet git state from the Rust `repos` binary: runs
3
+ * `repos status <keys…> --json` through the injected `ReposOperations` and
4
+ * parses what it printed with the `repos_status.ts` mirror.
5
+ *
6
+ * Parsing is pure (`parse_repos_status_output`): the format version is read
7
+ * first, so a binary and npm package out of step fail with both versions and
8
+ * the install command rather than a schema error; then the document is parsed
9
+ * strictly as a report or, when it carries `error`, as an error document,
10
+ * whose kind maps to a message saying what to change.
11
+ *
12
+ * @module
13
+ */
14
+
15
+ import type { Result } from '@fuzdev/fuz_util/result.ts';
16
+ import { z } from 'zod';
17
+
18
+ import {
19
+ REPOS_STATUS_FORMAT_VERSION,
20
+ ReposStatusErrorReport,
21
+ ReposStatusReport,
22
+ type ReposStatusErrorBody
23
+ } from './repos_status.ts';
24
+ import type { ReposCommandOutput, ReposOperations } from './operations.ts';
25
+
26
+ /**
27
+ * How to install the `repos` binary, run in a `fuz_repos` checkout. The npm
28
+ * package doesn't carry the binary, so the two are installed separately.
29
+ */
30
+ export const REPOS_INSTALL_COMMAND = 'cargo install --path crates/fuz_repos --locked';
31
+
32
+ /**
33
+ * The `repos` invocation a suggested fix names: `repos`, or `repos --registry
34
+ * <path>` when the run passed one, the path POSIX-shell-quoted when it needs it.
35
+ *
36
+ * @param registry - the run's `--registry`, if any
37
+ * @returns the command prefix, ready for a subcommand
38
+ */
39
+ export const to_repos_command = (registry: string | undefined): string =>
40
+ registry === undefined ? 'repos' : `repos --registry ${shell_quote(registry)}`;
41
+
42
+ const shell_quote = (arg: string): string =>
43
+ /^[\w@%+=:,./-]+$/.test(arg) ? arg : `'${arg.replaceAll("'", `'\\''`)}'`;
44
+
45
+ /**
46
+ * Why `repos status` gave no report: a message saying what to change, and the
47
+ * error document when `repos` printed one.
48
+ */
49
+ export interface ReposStatusLoadFailure {
50
+ message: string;
51
+ error?: ReposStatusErrorBody;
52
+ }
53
+
54
+ /**
55
+ * Parses what `repos status --json` printed into its report, or a message
56
+ * saying what went wrong and what to change.
57
+ *
58
+ * @param output - the command's stdout, stderr, and exit code
59
+ * @returns the report, or a message naming the error document's kind and hint, a format version mismatch, or output that isn't a status document; an error document rides along as `error`
60
+ */
61
+ export const parse_repos_status_output = (
62
+ output: ReposCommandOutput
63
+ ): Result<{ report: ReposStatusReport }, ReposStatusLoadFailure> => {
64
+ const { stdout, stderr, exit_code } = output;
65
+
66
+ let json: unknown;
67
+ try {
68
+ json = JSON.parse(stdout);
69
+ } catch {
70
+ // exit 1 is a fatal I/O error, which may print no JSON
71
+ const detail = stderr.trim() || stdout.trim() || 'no output';
72
+ return {
73
+ ok: false,
74
+ message: `\`repos status --json\` exited ${exit_code} without a JSON document: ${detail}`
75
+ };
76
+ }
77
+
78
+ if (typeof json !== 'object' || json === null || Array.isArray(json)) {
79
+ return { ok: false, message: '`repos status --json` printed JSON that is not a document' };
80
+ }
81
+
82
+ const version = 'version' in json ? json.version : undefined;
83
+ if (version !== REPOS_STATUS_FORMAT_VERSION) {
84
+ const fix =
85
+ typeof version === 'number' && version > REPOS_STATUS_FORMAT_VERSION
86
+ ? "upgrade @fuzdev/fuz_gitops to match the binary, or install the binary from a fuz_repos checkout at this package's version"
87
+ : "install the binary from a fuz_repos checkout at this package's version";
88
+ return {
89
+ ok: false,
90
+ message:
91
+ `the \`repos\` binary prints status format ${JSON.stringify(version ?? null)}, ` +
92
+ `but this @fuzdev/fuz_gitops parses format ${REPOS_STATUS_FORMAT_VERSION}: ` +
93
+ `${fix} (\`${REPOS_INSTALL_COMMAND}\`) — the npm package and the binary are installed separately`
94
+ };
95
+ }
96
+
97
+ if ('error' in json) {
98
+ const parsed = ReposStatusErrorReport.safeParse(json);
99
+ if (!parsed.success) {
100
+ return {
101
+ ok: false,
102
+ message: `\`repos status --json\` printed an error document this package can't parse:\n${z.prettifyError(parsed.error)}`
103
+ };
104
+ }
105
+ return {
106
+ ok: false,
107
+ message: format_repos_status_error(parsed.data.error),
108
+ error: parsed.data.error
109
+ };
110
+ }
111
+
112
+ const parsed = ReposStatusReport.safeParse(json);
113
+ if (!parsed.success) {
114
+ return {
115
+ ok: false,
116
+ message: `\`repos status --json\` printed a report this package can't parse:\n${z.prettifyError(parsed.error)}`
117
+ };
118
+ }
119
+ return { ok: true, report: parsed.data };
120
+ };
121
+
122
+ const format_repos_status_error = (error: ReposStatusErrorBody): string => {
123
+ switch (error.kind) {
124
+ case 'unknown_entry': {
125
+ const suggestions = error.suggestions.length
126
+ ? ` — did you mean ${error.suggestions.map((s) => `\`${s}\``).join(', ')}?`
127
+ : '';
128
+ return `the gitops config lists \`${error.name}\`, which the registry (repos.toml) doesn't name${suggestions}`;
129
+ }
130
+ case 'registry_not_found':
131
+ return (
132
+ `${error.message}: the gitops tasks read repo state from a repos.toml registry — ` +
133
+ `run inside its workspace, or pass \`--registry <path>\``
134
+ );
135
+ default: {
136
+ const hint = error.hint ? `\n hint: ${error.hint}` : '';
137
+ return `\`repos status\` failed (${error.kind}): ${error.message}${hint}`;
138
+ }
139
+ }
140
+ };
141
+
142
+ /**
143
+ * Runs `repos status <keys…> --json` and parses its report.
144
+ *
145
+ * @param options.keys - the registry keys to report on; must not be empty, since no targets means every entry
146
+ * @param options.registry - a `repos.toml` to use instead of the one found walking up from the cwd
147
+ * @param options.fetch - fetch each entry from origin first (`--fetch`), which writes remote-tracking refs and nothing else
148
+ * @param options.repos_ops - the `repos` runner
149
+ * @returns the report, or a message saying what went wrong and what to change
150
+ */
151
+ export const load_repos_status = async (options: {
152
+ keys: Array<string>;
153
+ registry?: string;
154
+ fetch?: boolean;
155
+ repos_ops: ReposOperations;
156
+ }): Promise<Result<{ report: ReposStatusReport }, ReposStatusLoadFailure>> => {
157
+ const { keys, registry, fetch, repos_ops } = options;
158
+ if (keys.length === 0) {
159
+ // `repos status` with no targets reports every entry
160
+ return { ok: false, message: 'no registry keys to report on' };
161
+ }
162
+ const ran = await repos_ops.status(fetch ? { keys, registry, fetch } : { keys, registry });
163
+ if (!ran.ok) {
164
+ return {
165
+ ok: false,
166
+ message:
167
+ ran.kind === 'not_found'
168
+ ? `the \`repos\` binary was not found on PATH: install it from a fuz_repos checkout with \`${REPOS_INSTALL_COMMAND}\` — the npm package doesn't carry it`
169
+ : `\`repos status\` didn't run: ${ran.message}`
170
+ };
171
+ }
172
+ return parse_repos_status_output(ran.output);
173
+ };
@@ -79,7 +79,7 @@ export const needs_update = (current: string, new_version: string): boolean => {
79
79
  */
80
80
  export const get_update_prefix = (
81
81
  current_version: string,
82
- default_strategy: '^' | '~' | '' | '>=' = '^',
82
+ default_strategy: '^' | '~' | '' | '>=' = '^'
83
83
  ): string => {
84
84
  // Use caret for wildcard replacements
85
85
  if (is_wildcard(current_version)) {
@@ -128,7 +128,7 @@ export const is_breaking_change = (old_version: string, bump_type: BumpType): bo
128
128
  */
129
129
  export const required_bump_for_dependency_update = (
130
130
  current_version: string,
131
- has_breaking_deps: boolean,
131
+ has_breaking_deps: boolean
132
132
  ): BumpType => {
133
133
  const [major] = current_version.split('.').map(Number);
134
134
  const is_pre_1_0 = major === 0;
@@ -156,7 +156,7 @@ export const compare_bump_types = (a: BumpType, b: BumpType): number => {
156
156
  const order: Record<BumpType, number> = {
157
157
  major: 3,
158
158
  minor: 2,
159
- patch: 1,
159
+ patch: 1
160
160
  };
161
161
  return order[a] - order[b];
162
162
  };
@@ -1,46 +0,0 @@
1
- /**
2
- * Reconciles repo metadata across multiple gitops configs.
3
- *
4
- * The ecosystem keeps several gitops configs — a canonical superset plus
5
- * narrower per-project subsets. They can't share one source of truth (the
6
- * superset includes private repos that public configs may not reference), so the
7
- * same repo is declared independently in each. This check flags when a subset's
8
- * intrinsic fields drift from the canonical config, or when a subset lists a
9
- * repo the canonical config doesn't. `repo_dir` is per-config and ignored.
10
- *
11
- * @module
12
- */
13
- import type { GitopsRepoConfig } from './gitops_config.js';
14
- /** Repo fields that must agree across every config that lists the repo. */
15
- declare const INTRINSIC_FIELDS: readonly ["visibility", "ci", "archived", "branch"];
16
- export type IntrinsicField = (typeof INTRINSIC_FIELDS)[number];
17
- export type ConfigDriftKind =
18
- /** The repo is in a subset config but absent from the canonical config. */
19
- 'missing_from_canonical'
20
- /** An intrinsic field disagrees between the subset and the canonical config. */
21
- | 'field_mismatch';
22
- export interface ConfigDrift {
23
- repo_url: string;
24
- /** Name of the subset config whose entry diverges. */
25
- config: string;
26
- kind: ConfigDriftKind;
27
- /** The field that disagrees, set when `kind` is `'field_mismatch'`. */
28
- field?: IntrinsicField;
29
- /** The canonical config's value, set when `kind` is `'field_mismatch'`. */
30
- canonical_value?: string;
31
- /** The subset config's value, set when `kind` is `'field_mismatch'`. */
32
- config_value?: string;
33
- }
34
- export interface NamedRepos {
35
- name: string;
36
- repos: Array<GitopsRepoConfig>;
37
- }
38
- /**
39
- * Compares each subset config against the canonical config. Repos that live only
40
- * in the canonical config are fine — the subsets are intentional partial views.
41
- * @returns one `ConfigDrift` per subset entry that is missing from the canonical
42
- * config or whose intrinsic fields disagree with it
43
- */
44
- export declare const reconcile_configs: (canonical: NamedRepos, subsets: Array<NamedRepos>) => Array<ConfigDrift>;
45
- export {};
46
- //# sourceMappingURL=config_reconcile.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"config_reconcile.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/config_reconcile.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,oBAAoB,CAAC;AAEzD,2EAA2E;AAC3E,QAAA,MAAM,gBAAgB,qDAAsD,CAAC;AAE7E,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE/D,MAAM,MAAM,eAAe;AAC1B,2EAA2E;AACzE,wBAAwB;AAC1B,gFAAgF;GAC9E,gBAAgB,CAAC;AAEpB,MAAM,WAAW,WAAW;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,sDAAsD;IACtD,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,eAAe,CAAC;IACtB,uEAAuE;IACvE,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB,2EAA2E;IAC3E,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,wEAAwE;IACxE,YAAY,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,UAAU;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,KAAK,CAAC,gBAAgB,CAAC,CAAC;CAC/B;AAeD;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,GAC7B,WAAW,UAAU,EACrB,SAAS,KAAK,CAAC,UAAU,CAAC,KACxB,KAAK,CAAC,WAAW,CA2BnB,CAAC"}
@@ -1,60 +0,0 @@
1
- /**
2
- * Reconciles repo metadata across multiple gitops configs.
3
- *
4
- * The ecosystem keeps several gitops configs — a canonical superset plus
5
- * narrower per-project subsets. They can't share one source of truth (the
6
- * superset includes private repos that public configs may not reference), so the
7
- * same repo is declared independently in each. This check flags when a subset's
8
- * intrinsic fields drift from the canonical config, or when a subset lists a
9
- * repo the canonical config doesn't. `repo_dir` is per-config and ignored.
10
- *
11
- * @module
12
- */
13
- /** Repo fields that must agree across every config that lists the repo. */
14
- const INTRINSIC_FIELDS = ['visibility', 'ci', 'archived', 'branch'];
15
- const field_value = (repo, field) => {
16
- switch (field) {
17
- case 'visibility':
18
- return repo.visibility;
19
- case 'ci':
20
- return String(repo.ci);
21
- case 'archived':
22
- return String(repo.archived);
23
- case 'branch':
24
- return repo.branch;
25
- }
26
- };
27
- /**
28
- * Compares each subset config against the canonical config. Repos that live only
29
- * in the canonical config are fine — the subsets are intentional partial views.
30
- * @returns one `ConfigDrift` per subset entry that is missing from the canonical
31
- * config or whose intrinsic fields disagree with it
32
- */
33
- export const reconcile_configs = (canonical, subsets) => {
34
- const drift = [];
35
- const canonical_by_url = new Map(canonical.repos.map((r) => [r.repo_url, r]));
36
- for (const subset of subsets) {
37
- for (const repo of subset.repos) {
38
- const canon = canonical_by_url.get(repo.repo_url);
39
- if (!canon) {
40
- drift.push({ repo_url: repo.repo_url, config: subset.name, kind: 'missing_from_canonical' });
41
- continue;
42
- }
43
- for (const field of INTRINSIC_FIELDS) {
44
- const canonical_value = field_value(canon, field);
45
- const config_value = field_value(repo, field);
46
- if (canonical_value !== config_value) {
47
- drift.push({
48
- repo_url: repo.repo_url,
49
- config: subset.name,
50
- kind: 'field_mismatch',
51
- field,
52
- canonical_value,
53
- config_value,
54
- });
55
- }
56
- }
57
- }
58
- }
59
- return drift;
60
- };
package/dist/paths.d.ts DELETED
@@ -1,7 +0,0 @@
1
- /**
2
- * Default repos directory relative to gitops config file.
3
- * Resolves to the parent of the directory with the config
4
- * (e.g., `~/dev/repo/gitops.config.ts` resolves to `~/dev/`).
5
- */
6
- export declare const DEFAULT_REPOS_DIR = "..";
7
- //# sourceMappingURL=paths.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"paths.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/paths.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,OAAO,CAAC"}
package/dist/paths.js DELETED
@@ -1,6 +0,0 @@
1
- /**
2
- * Default repos directory relative to gitops config file.
3
- * Resolves to the parent of the directory with the config
4
- * (e.g., `~/dev/repo/gitops.config.ts` resolves to `~/dev/`).
5
- */
6
- export const DEFAULT_REPOS_DIR = '..';
@@ -1,59 +0,0 @@
1
- /**
2
- * Generic repository operations for scripts that work across repos.
3
- *
4
- * Provides lightweight utilities for:
5
- * - Getting repo paths from gitops config (without full git sync)
6
- * - Walking files in repos with sensible exclusions
7
- * - Common exclusion patterns for node/svelte projects
8
- *
9
- * For full git sync/clone functionality, use `get_gitops_ready()` from `gitops_task_helpers`.
10
- *
11
- * @module
12
- */
13
- /** Default directories to exclude from file walking */
14
- export declare const DEFAULT_EXCLUDE_DIRS: readonly ["node_modules", ".git", ".gro", ".svelte-kit", ".deno", ".vscode", ".idea", "dist", "build", "coverage", ".cache", ".turbo"];
15
- /** Default binary/non-text extensions to exclude from content processing */
16
- export declare const DEFAULT_EXCLUDE_EXTENSIONS: readonly [".png", ".jpg", ".jpeg", ".gif", ".svg", ".ico", ".webp", ".woff", ".woff2", ".ttf", ".eot", ".mp4", ".webm", ".mp3", ".wav", ".ogg", ".zip", ".tar", ".gz", ".lock", ".pdf"];
17
- export interface WalkOptions {
18
- /** Additional directories to exclude (merged with defaults) */
19
- exclude_dirs?: Array<string>;
20
- /** Additional extensions to exclude (merged with defaults) */
21
- exclude_extensions?: Array<string>;
22
- /** Maximum file size in bytes (default: 10MB) */
23
- max_file_size?: number;
24
- /** Include directories in output (default: false) */
25
- include_dirs?: boolean;
26
- /** Use only provided exclusions, ignoring defaults */
27
- no_defaults?: boolean;
28
- }
29
- export interface RepoPath {
30
- name: string;
31
- path: string;
32
- url: string;
33
- }
34
- /**
35
- * Get repo paths from gitops config without full git sync.
36
- * Lighter weight than `get_gitops_ready()` - just resolves paths.
37
- *
38
- * @param config_path - path to the gitops config file (defaults to `gitops.config.ts`)
39
- * @returns array of repo info with name, path, and url
40
- */
41
- export declare const get_repo_paths: (config_path?: string) => Promise<Array<RepoPath>>;
42
- /**
43
- * Check if a path should be excluded based on options.
44
- */
45
- export declare const should_exclude_path: (file_path: string, options?: WalkOptions) => boolean;
46
- /**
47
- * Walk files in a directory, respecting common exclusions.
48
- * Yields absolute paths to files (and optionally directories).
49
- *
50
- * @param dir - directory to walk
51
- * @param options - walk options for exclusions and filtering
52
- */
53
- export declare function walk_repo_files(dir: string, options?: WalkOptions): AsyncGenerator<string, void, undefined>;
54
- /**
55
- * Collect all files from `walk_repo_files` into an array.
56
- * Convenience function for when you need all paths upfront.
57
- */
58
- export declare const collect_repo_files: (dir: string, options?: WalkOptions) => Promise<Array<string>>;
59
- //# sourceMappingURL=repo_ops.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"repo_ops.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/repo_ops.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAUH,uDAAuD;AACvD,eAAO,MAAM,oBAAoB,wIAavB,CAAC;AAEX,4EAA4E;AAC5E,eAAO,MAAM,0BAA0B,yLAsB7B,CAAC;AAEX,MAAM,WAAW,WAAW;IAC3B,+DAA+D;IAC/D,YAAY,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC7B,8DAA8D;IAC9D,kBAAkB,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACnC,iDAAiD;IACjD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,qDAAqD;IACrD,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,sDAAsD;IACtD,WAAW,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,QAAQ;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACZ;AAED;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,GAAU,cAAc,MAAM,KAAG,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CA4BlF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,mBAAmB,GAAI,WAAW,MAAM,EAAE,UAAU,WAAW,KAAG,OA2B9E,CAAC;AAEF;;;;;;GAMG;AACH,wBAAuB,eAAe,CACrC,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,WAAW,GACnB,cAAc,CAAC,MAAM,EAAE,IAAI,EAAE,SAAS,CAAC,CAwCzC;AAED;;;GAGG;AACH,eAAO,MAAM,kBAAkB,GAC9B,KAAK,MAAM,EACX,UAAU,WAAW,KACnB,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAMvB,CAAC"}
package/dist/repo_ops.js DELETED
@@ -1,170 +0,0 @@
1
- /**
2
- * Generic repository operations for scripts that work across repos.
3
- *
4
- * Provides lightweight utilities for:
5
- * - Getting repo paths from gitops config (without full git sync)
6
- * - Walking files in repos with sensible exclusions
7
- * - Common exclusion patterns for node/svelte projects
8
- *
9
- * For full git sync/clone functionality, use `get_gitops_ready()` from `gitops_task_helpers`.
10
- *
11
- * @module
12
- */
13
- import { existsSync } from 'node:fs';
14
- import { readdir, stat } from 'node:fs/promises';
15
- import { join, resolve, dirname } from 'node:path';
16
- import { load_gitops_config } from './gitops_config.js';
17
- import { DEFAULT_REPOS_DIR } from './paths.js';
18
- import { GITOPS_CONFIG_PATH_DEFAULT } from './gitops_constants.js';
19
- /** Default directories to exclude from file walking */
20
- export const DEFAULT_EXCLUDE_DIRS = [
21
- 'node_modules',
22
- '.git',
23
- '.gro',
24
- '.svelte-kit',
25
- '.deno',
26
- '.vscode',
27
- '.idea',
28
- 'dist',
29
- 'build',
30
- 'coverage',
31
- '.cache',
32
- '.turbo',
33
- ];
34
- /** Default binary/non-text extensions to exclude from content processing */
35
- export const DEFAULT_EXCLUDE_EXTENSIONS = [
36
- '.png',
37
- '.jpg',
38
- '.jpeg',
39
- '.gif',
40
- '.svg',
41
- '.ico',
42
- '.webp',
43
- '.woff',
44
- '.woff2',
45
- '.ttf',
46
- '.eot',
47
- '.mp4',
48
- '.webm',
49
- '.mp3',
50
- '.wav',
51
- '.ogg',
52
- '.zip',
53
- '.tar',
54
- '.gz',
55
- '.lock',
56
- '.pdf',
57
- ];
58
- /**
59
- * Get repo paths from gitops config without full git sync.
60
- * Lighter weight than `get_gitops_ready()` - just resolves paths.
61
- *
62
- * @param config_path - path to the gitops config file (defaults to `gitops.config.ts`)
63
- * @returns array of repo info with name, path, and url
64
- */
65
- export const get_repo_paths = async (config_path) => {
66
- const resolved_config_path = resolve(config_path ?? GITOPS_CONFIG_PATH_DEFAULT);
67
- const config = await load_gitops_config(resolved_config_path);
68
- if (!config) {
69
- throw new Error(`No gitops config found at ${resolved_config_path}`);
70
- }
71
- const config_dir = dirname(resolved_config_path);
72
- const repos_dir = resolve(config_dir, config.repos_dir || DEFAULT_REPOS_DIR);
73
- const repos = [];
74
- for (const repo_config of config.repos) {
75
- const url = repo_config.repo_url;
76
- const name = url.split('/').at(-1);
77
- if (!name)
78
- continue;
79
- const path = repo_config.repo_dir
80
- ? resolve(config_dir, repo_config.repo_dir)
81
- : join(repos_dir, name);
82
- if (existsSync(path)) {
83
- repos.push({ name, path, url });
84
- }
85
- }
86
- return repos;
87
- };
88
- /**
89
- * Check if a path should be excluded based on options.
90
- */
91
- export const should_exclude_path = (file_path, options) => {
92
- const exclude_dirs = options?.no_defaults
93
- ? (options.exclude_dirs ?? [])
94
- : [...DEFAULT_EXCLUDE_DIRS, ...(options?.exclude_dirs ?? [])];
95
- const exclude_extensions = options?.no_defaults
96
- ? (options.exclude_extensions ?? [])
97
- : [...DEFAULT_EXCLUDE_EXTENSIONS, ...(options?.exclude_extensions ?? [])];
98
- const normalized = file_path.toLowerCase();
99
- // Check excluded directories
100
- for (const dir of exclude_dirs) {
101
- // Must match as a full directory component, not a prefix
102
- if (normalized.includes(`/${dir}/`) || normalized.endsWith(`/${dir}`)) {
103
- return true;
104
- }
105
- }
106
- // Check excluded extensions
107
- for (const ext of exclude_extensions) {
108
- if (normalized.endsWith(ext)) {
109
- return true;
110
- }
111
- }
112
- return false;
113
- };
114
- /**
115
- * Walk files in a directory, respecting common exclusions.
116
- * Yields absolute paths to files (and optionally directories).
117
- *
118
- * @param dir - directory to walk
119
- * @param options - walk options for exclusions and filtering
120
- */
121
- export async function* walk_repo_files(dir, options) {
122
- const max_file_size = options?.max_file_size ?? 10 * 1024 * 1024;
123
- const include_dirs = options?.include_dirs ?? false;
124
- async function* walk(current_dir) {
125
- let entries;
126
- try {
127
- entries = await readdir(current_dir, { withFileTypes: true });
128
- }
129
- catch {
130
- // Skip directories we can't read
131
- return;
132
- }
133
- for (const entry of entries) {
134
- const full_path = join(current_dir, entry.name);
135
- if (should_exclude_path(full_path, options)) {
136
- continue;
137
- }
138
- if (entry.isDirectory()) {
139
- if (include_dirs) {
140
- yield full_path;
141
- }
142
- yield* walk(full_path);
143
- }
144
- else if (entry.isFile()) {
145
- // Check file size
146
- try {
147
- const file_stat = await stat(full_path);
148
- if (file_stat.size <= max_file_size) {
149
- yield full_path;
150
- }
151
- }
152
- catch {
153
- // Skip files we can't stat
154
- }
155
- }
156
- }
157
- }
158
- yield* walk(dir);
159
- }
160
- /**
161
- * Collect all files from `walk_repo_files` into an array.
162
- * Convenience function for when you need all paths upfront.
163
- */
164
- export const collect_repo_files = async (dir, options) => {
165
- const files = [];
166
- for await (const file of walk_repo_files(dir, options)) {
167
- files.push(file);
168
- }
169
- return files;
170
- };
@@ -1,9 +0,0 @@
1
- import type { GitopsConfig } from './gitops_config.js';
2
- import { type LocalRepoPath, type LocalRepoMissing } from './local_repo.js';
3
- export interface ResolvedGitopsConfig {
4
- local_repos: Array<LocalRepoPath | LocalRepoMissing> | null;
5
- local_repo_paths: Array<LocalRepoPath> | null;
6
- local_repos_missing: Array<LocalRepoMissing> | null;
7
- }
8
- export declare const resolve_gitops_config: (gitops_config: GitopsConfig, repos_dir: string) => ResolvedGitopsConfig;
9
- //# sourceMappingURL=resolved_gitops_config.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"resolved_gitops_config.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/resolved_gitops_config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAoB,KAAK,aAAa,EAAE,KAAK,gBAAgB,EAAC,MAAM,iBAAiB,CAAC;AAE7F,MAAM,WAAW,oBAAoB;IACpC,WAAW,EAAE,KAAK,CAAC,aAAa,GAAG,gBAAgB,CAAC,GAAG,IAAI,CAAC;IAC5D,gBAAgB,EAAE,KAAK,CAAC,aAAa,CAAC,GAAG,IAAI,CAAC;IAC9C,mBAAmB,EAAE,KAAK,CAAC,gBAAgB,CAAC,GAAG,IAAI,CAAC;CACpD;AAED,eAAO,MAAM,qBAAqB,GACjC,eAAe,YAAY,EAC3B,WAAW,MAAM,KACf,oBAcF,CAAC"}
@@ -1,12 +0,0 @@
1
- import { local_repo_locate } from './local_repo.js';
2
- export const resolve_gitops_config = (gitops_config, repos_dir) => {
3
- const local_repos = gitops_config.repos.map((r) => local_repo_locate({ repo_config: r, repos_dir }));
4
- const local_repo_paths = local_repos.filter((r) => r.type === 'local_repo_path');
5
- const local_repos_missing = local_repos.filter((r) => r.type === 'local_repo_missing');
6
- const config = {
7
- local_repos: local_repos.length ? local_repos : null,
8
- local_repo_paths: local_repo_paths.length ? local_repo_paths : null,
9
- local_repos_missing: local_repos_missing.length ? local_repos_missing : null,
10
- };
11
- return config;
12
- };