@fuzdev/fuz_gitops 0.77.0 → 0.78.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 (94) hide show
  1. package/README.md +5 -5
  2. package/dist/ModulesDetail.svelte +1 -1
  3. package/dist/PageFooter.svelte +2 -2
  4. package/dist/PageHeader.svelte +1 -1
  5. package/dist/PageHeader.svelte.d.ts +1 -1
  6. package/dist/ReposTable.svelte +1 -1
  7. package/dist/ReposTree.svelte +1 -1
  8. package/dist/cargo_toml.d.ts +33 -0
  9. package/dist/cargo_toml.d.ts.map +1 -0
  10. package/dist/cargo_toml.js +74 -0
  11. package/dist/changeset_generator.d.ts +1 -1
  12. package/dist/changeset_reader.d.ts +1 -1
  13. package/dist/dependency_graph.d.ts +2 -2
  14. package/dist/dependency_graph.js +4 -4
  15. package/dist/dependency_updater.d.ts +1 -1
  16. package/dist/fetch_repo_data.d.ts +2 -2
  17. package/dist/fetch_repo_data.js +1 -1
  18. package/dist/fs_fetch_value_cache.d.ts +1 -1
  19. package/dist/fs_fetch_value_cache.js +3 -3
  20. package/dist/git_operations.d.ts +1 -1
  21. package/dist/git_operations.js +2 -2
  22. package/dist/github.d.ts +2 -2
  23. package/dist/github.js +1 -1
  24. package/dist/github_helpers.js +1 -1
  25. package/dist/gitops_analyze.task.d.ts.map +1 -1
  26. package/dist/gitops_analyze.task.js +15 -8
  27. package/dist/gitops_config.d.ts +2 -2
  28. package/dist/gitops_config.js +1 -1
  29. package/dist/gitops_run.task.js +2 -2
  30. package/dist/gitops_sync.task.js +4 -4
  31. package/dist/gitops_task_helpers.d.ts +1 -1
  32. package/dist/gitops_task_helpers.js +1 -1
  33. package/dist/graph_validation.d.ts +2 -2
  34. package/dist/graph_validation.d.ts.map +1 -1
  35. package/dist/graph_validation.js +3 -1
  36. package/dist/local_repo.d.ts +17 -3
  37. package/dist/local_repo.d.ts.map +1 -1
  38. package/dist/local_repo.js +54 -6
  39. package/dist/log_helpers.d.ts +1 -1
  40. package/dist/multi_repo_publisher.d.ts +3 -3
  41. package/dist/multi_repo_publisher.d.ts.map +1 -1
  42. package/dist/multi_repo_publisher.js +5 -1
  43. package/dist/npm_registry.d.ts +1 -1
  44. package/dist/npm_registry.js +2 -2
  45. package/dist/operations.d.ts +4 -4
  46. package/dist/operations_defaults.js +4 -4
  47. package/dist/output_helpers.d.ts +1 -1
  48. package/dist/preflight_checks.d.ts +1 -1
  49. package/dist/preflight_checks.js +1 -1
  50. package/dist/publish_steps.js +1 -1
  51. package/dist/publishing_plan.d.ts +3 -3
  52. package/dist/publishing_plan.d.ts.map +1 -1
  53. package/dist/publishing_plan.js +11 -1
  54. package/dist/publishing_plan_logging.d.ts +1 -1
  55. package/dist/repo.svelte.d.ts +5 -5
  56. package/dist/repo.svelte.js +2 -2
  57. package/package.json +6 -6
  58. package/src/lib/cargo_toml.ts +82 -0
  59. package/src/lib/changeset_generator.ts +6 -6
  60. package/src/lib/changeset_reader.ts +3 -3
  61. package/src/lib/config_reconcile.ts +1 -1
  62. package/src/lib/dependency_graph.ts +5 -5
  63. package/src/lib/dependency_updater.ts +7 -7
  64. package/src/lib/fetch_repo_data.ts +6 -6
  65. package/src/lib/fs_fetch_value_cache.ts +3 -3
  66. package/src/lib/git_operations.ts +2 -2
  67. package/src/lib/github.ts +2 -2
  68. package/src/lib/github_helpers.ts +3 -3
  69. package/src/lib/gitops_analyze.task.ts +26 -18
  70. package/src/lib/gitops_config.ts +4 -4
  71. package/src/lib/gitops_plan.task.ts +4 -4
  72. package/src/lib/gitops_publish.task.ts +9 -9
  73. package/src/lib/gitops_run.task.ts +4 -4
  74. package/src/lib/gitops_sync.task.ts +8 -8
  75. package/src/lib/gitops_task_helpers.ts +7 -7
  76. package/src/lib/gitops_validate.task.ts +7 -7
  77. package/src/lib/graph_validation.ts +5 -4
  78. package/src/lib/local_repo.ts +81 -15
  79. package/src/lib/log_helpers.ts +2 -2
  80. package/src/lib/multi_repo_publisher.ts +15 -11
  81. package/src/lib/npm_registry.ts +3 -3
  82. package/src/lib/operations.ts +9 -9
  83. package/src/lib/operations_defaults.ts +9 -9
  84. package/src/lib/output_helpers.ts +1 -1
  85. package/src/lib/preflight_checks.ts +6 -6
  86. package/src/lib/publish_gate.ts +2 -2
  87. package/src/lib/publish_steps.ts +3 -3
  88. package/src/lib/publishing_event_handler.ts +1 -1
  89. package/src/lib/publishing_plan.ts +22 -10
  90. package/src/lib/publishing_plan_helpers.ts +3 -3
  91. package/src/lib/publishing_plan_logging.ts +2 -2
  92. package/src/lib/repo.svelte.ts +7 -7
  93. package/src/lib/repo_ops.ts +3 -3
  94. package/src/lib/resolved_gitops_config.ts +2 -2
@@ -1,13 +1,16 @@
1
- import { strip_end } from '@fuzdev/fuz_util/string.js';
2
- import { Library } from '@fuzdev/fuz_ui/library.svelte.js';
1
+ import { strip_end } from '@fuzdev/fuz_util/string.ts';
2
+ import { to_error_message } from '@fuzdev/fuz_util/error.ts';
3
+ import { library_json_from_modules } from '@fuzdev/fuz_util/library_json.ts';
4
+ import { Library } from '@fuzdev/fuz_ui/library.svelte.ts';
3
5
  import { existsSync } from 'node:fs';
4
6
  import { join } from 'node:path';
5
7
  import { TaskError } from '@fuzdev/gro';
6
- import { library_load_from_repo } from '@fuzdev/gro/library_load.js';
7
- import { spawn_out } from '@fuzdev/fuz_util/process.js';
8
- import { map_concurrent_settled } from '@fuzdev/fuz_util/async.js';
8
+ import { library_load_from_repo } from '@fuzdev/gro/library_load.ts';
9
+ import { spawn_out } from '@fuzdev/fuz_util/process.ts';
10
+ import { map_concurrent_settled } from '@fuzdev/fuz_util/async.ts';
9
11
  import { default_git_operations, default_npm_operations } from './operations_defaults.js';
10
12
  import { GITOPS_CONCURRENCY_DEFAULT } from './gitops_constants.js';
13
+ import { cargo_toml_load } from './cargo_toml.js';
11
14
  /**
12
15
  * Loads repo data, optionally syncing the working tree first.
13
16
  *
@@ -117,6 +120,13 @@ export const local_repo_load = async ({ local_repo_path, log: _log, git_ops = de
117
120
  }
118
121
  }
119
122
  }
123
+ // A repo with no `package.json` but a Rust `Cargo.toml` isn't an npm package and can't be
124
+ // analyzed as a library. Load it as a dashboard-only `cargo` repo (CI, PRs, identity) that
125
+ // publishing/analysis skips. Anything else falls through to the npm loader below, whose
126
+ // error covers a genuinely missing or unreadable manifest.
127
+ if (!existsSync(join(repo_dir, 'package.json')) && existsSync(join(repo_dir, 'Cargo.toml'))) {
128
+ return local_repo_load_cargo({ local_repo_path });
129
+ }
120
130
  // Load library metadata via svelte-docinfo analysis (cached under `.gro/library.json`).
121
131
  let library_json;
122
132
  let package_json;
@@ -124,12 +134,13 @@ export const local_repo_load = async ({ local_repo_path, log: _log, git_ops = de
124
134
  ({ library_json, package_json } = await library_load_from_repo(repo_dir, { log: _log }));
125
135
  }
126
136
  catch (err) {
127
- const message = err instanceof Error ? err.message : String(err);
137
+ const message = to_error_message(err);
128
138
  _log?.warn(`Failed to load library metadata for repo "${repo_name}" in ${repo_dir}: ${message}`);
129
139
  throw new TaskError(`Failed to load library metadata for repo "${repo_name}" in ${repo_dir}: ${message}`);
130
140
  }
131
141
  const library = new Library(library_json);
132
142
  const local_repo = {
143
+ kind: 'npm',
133
144
  library,
134
145
  package_json,
135
146
  repo_dir,
@@ -148,6 +159,43 @@ export const local_repo_load = async ({ local_repo_path, log: _log, git_ops = de
148
159
  }
149
160
  return local_repo;
150
161
  };
162
+ /**
163
+ * Whether a repo is an npm package and so participates in publishing and
164
+ * dependency analysis. Non-npm repos (e.g. Rust `cargo` repos) are still synced
165
+ * and rendered on the dashboard, but excluded from the changeset cascade.
166
+ */
167
+ export const repo_is_npm = (repo) => repo.kind === 'npm';
168
+ /**
169
+ * Loads a non-npm Rust repo as a dashboard-only `LocalRepo`. It has no
170
+ * `package.json`, so there's no `svelte-docinfo` analysis and no npm dependency
171
+ * graph — a lightweight `Library` is synthesized from the repo's `Cargo.toml`
172
+ * (best-effort name/version/description) and its configured repo URL, which is
173
+ * what the dashboard renders (CI status, PRs, identity). Marked `private` so it
174
+ * never reads as an npm publish target, and tagged `cargo` so the publishing and
175
+ * analysis paths skip it (see `repo_is_npm`).
176
+ */
177
+ const local_repo_load_cargo = async ({ local_repo_path, }) => {
178
+ const { repo_config, repo_dir, repo_name, repo_url, repo_git_ssh_url } = local_repo_path;
179
+ const cargo = await cargo_toml_load(repo_dir);
180
+ // A Cargo workspace root has no `name`, so fall back to the repo name parsed from
181
+ // the URL; the config's `repo_url` is the authoritative `repository`.
182
+ const package_json = {
183
+ name: cargo?.name ?? repo_name,
184
+ version: cargo?.version ?? '0.0.0',
185
+ repository: cargo?.repository ?? repo_url,
186
+ private: true,
187
+ ...(cargo?.description ? { description: cargo.description } : null),
188
+ };
189
+ const library = new Library(library_json_from_modules(package_json, []));
190
+ return {
191
+ kind: 'cargo',
192
+ library,
193
+ package_json,
194
+ repo_dir,
195
+ repo_git_ssh_url,
196
+ repo_config,
197
+ };
198
+ };
151
199
  export const local_repos_ensure = async ({ resolved_config, repos_dir, gitops_config, download, log, npm_ops = default_npm_operations, }) => {
152
200
  let local_repo_paths = null;
153
201
  if (!resolved_config.local_repos_missing) {
@@ -1,4 +1,4 @@
1
- import type { Logger } from '@fuzdev/fuz_util/log.js';
1
+ import type { Logger } from '@fuzdev/fuz_util/log.ts';
2
2
  import type { DependencyGraphBuilder } from './dependency_graph.js';
3
3
  /**
4
4
  * Formats wildcard dependencies as styled strings.
@@ -1,5 +1,5 @@
1
- import type { Logger } from '@fuzdev/fuz_util/log.js';
2
- import type { LocalRepo } from './local_repo.js';
1
+ import type { Logger } from '@fuzdev/fuz_util/log.ts';
2
+ import { type LocalRepo } from './local_repo.js';
3
3
  import { type VersionStrategy } from './dependency_updater.js';
4
4
  import { type DependencyUpdate, type PublishingPlan } from './publishing_plan.js';
5
5
  import type { GitopsOperations } from './operations.js';
@@ -50,7 +50,7 @@ export declare const publish_repos: (repos: Array<LocalRepo>, options: Publishin
50
50
  * before any side effect, a dry run still reports the partial cascade but returns
51
51
  * `ok: false`. This is the single error gate — `--no-plan` can't bypass it.
52
52
  */
53
- export declare const execute_publishing_plan: (repos: Array<LocalRepo>, plan: PublishingPlan, options: PublishingOptions) => Promise<PublishingResult>;
53
+ export declare const execute_publishing_plan: (all_repos: Array<LocalRepo>, plan: PublishingPlan, options: PublishingOptions) => Promise<PublishingResult>;
54
54
  /**
55
55
  * Groups dependency updates by dependent package — `dependent → (dependency → new
56
56
  * version)`, the shape `update_package_json` consumes. Restricted by `predicate` (e.g.
@@ -1 +1 @@
1
- {"version":3,"file":"multi_repo_publisher.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/multi_repo_publisher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAC;AAKpD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAsB,KAAK,eAAe,EAAC,MAAM,yBAAyB,CAAC;AAClF,OAAO,EAGN,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,iBAAiB,CAAC;AAGtD,OAAO,EACN,KAAK,eAAe,EACpB,KAAK,oBAAoB,EAEzB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACN,KAAK,sBAAsB,EAG3B,MAAM,+BAA+B,CAAC;AAEvC,MAAM,WAAW,iBAAiB;IACjC,MAAM,EAAE,OAAO,CAAC;IAChB,gBAAgB,CAAC,EAAE,eAAe,CAAC;IACnC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,gBAAgB,CAAC;IACvB,sFAAsF;IACtF,MAAM,CAAC,EAAE,sBAAsB,CAAC;CAChC;AAED,MAAM,WAAW,gBAAgB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;IACvC,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,gBAAgB;IAChC,EAAE,EAAE,OAAO,CAAC;IACZ,SAAS,EAAE,KAAK,CAAC,gBAAgB,CAAC,CAAC;IACnC,MAAM,EAAE,KAAK,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,KAAK,CAAA;KAAC,CAAC,CAAC;IAC5C,QAAQ,EAAE,MAAM,CAAC;IACjB,mEAAmE;IACnE,MAAM,EAAE,KAAK,CAAC,eAAe,CAAC,CAAC;IAC/B,8CAA8C;IAC9C,OAAO,EAAE,oBAAoB,CAAC;IAC9B,+FAA+F;IAC/F,WAAW,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC3B,yEAAyE;IACzE,aAAa,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;CAC7B;AAED,eAAO,MAAM,aAAa,GACzB,OAAO,KAAK,CAAC,SAAS,CAAC,EACvB,SAAS,iBAAiB,KACxB,OAAO,CAAC,gBAAgB,CAO1B,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB,GACnC,OAAO,KAAK,CAAC,SAAS,CAAC,EACvB,MAAM,cAAc,EACpB,SAAS,iBAAiB,KACxB,OAAO,CAAC,gBAAgB,CAwX1B,CAAC;AA+EF;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,GACpC,SAAS,KAAK,CAAC,gBAAgB,CAAC,EAChC,WAAW,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,EACxC,WAAW,CAAC,MAAM,EAAE,gBAAgB,KAAK,OAAO,KAC9C,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAcjC,CAAC"}
1
+ {"version":3,"file":"multi_repo_publisher.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/multi_repo_publisher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAC;AAKpD,OAAO,EAAc,KAAK,SAAS,EAAC,MAAM,iBAAiB,CAAC;AAC5D,OAAO,EAAsB,KAAK,eAAe,EAAC,MAAM,yBAAyB,CAAC;AAClF,OAAO,EAGN,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,iBAAiB,CAAC;AAGtD,OAAO,EACN,KAAK,eAAe,EACpB,KAAK,oBAAoB,EAEzB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACN,KAAK,sBAAsB,EAG3B,MAAM,+BAA+B,CAAC;AAEvC,MAAM,WAAW,iBAAiB;IACjC,MAAM,EAAE,OAAO,CAAC;IAChB,gBAAgB,CAAC,EAAE,eAAe,CAAC;IACnC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,gBAAgB,CAAC;IACvB,sFAAsF;IACtF,MAAM,CAAC,EAAE,sBAAsB,CAAC;CAChC;AAED,MAAM,WAAW,gBAAgB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;IACvC,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,gBAAgB;IAChC,EAAE,EAAE,OAAO,CAAC;IACZ,SAAS,EAAE,KAAK,CAAC,gBAAgB,CAAC,CAAC;IACnC,MAAM,EAAE,KAAK,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,KAAK,CAAA;KAAC,CAAC,CAAC;IAC5C,QAAQ,EAAE,MAAM,CAAC;IACjB,mEAAmE;IACnE,MAAM,EAAE,KAAK,CAAC,eAAe,CAAC,CAAC;IAC/B,8CAA8C;IAC9C,OAAO,EAAE,oBAAoB,CAAC;IAC9B,+FAA+F;IAC/F,WAAW,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC3B,yEAAyE;IACzE,aAAa,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;CAC7B;AAED,eAAO,MAAM,aAAa,GACzB,OAAO,KAAK,CAAC,SAAS,CAAC,EACvB,SAAS,iBAAiB,KACxB,OAAO,CAAC,gBAAgB,CAO1B,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB,GACnC,WAAW,KAAK,CAAC,SAAS,CAAC,EAC3B,MAAM,cAAc,EACpB,SAAS,iBAAiB,KACxB,OAAO,CAAC,gBAAgB,CA4X1B,CAAC;AA+EF;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,GACpC,SAAS,KAAK,CAAC,gBAAgB,CAAC,EAChC,WAAW,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,EACxC,WAAW,CAAC,MAAM,EAAE,gBAAgB,KAAK,OAAO,KAC9C,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAcjC,CAAC"}
@@ -1,6 +1,7 @@
1
1
  import { TaskError } from '@fuzdev/gro';
2
2
  import { join } from 'node:path';
3
3
  import { styleText as st } from 'node:util';
4
+ import { repo_is_npm } from './local_repo.js';
4
5
  import { update_package_json } from './dependency_updater.js';
5
6
  import { generate_publishing_plan, } from './publishing_plan.js';
6
7
  import { default_gitops_operations } from './operations_defaults.js';
@@ -23,9 +24,12 @@ export const publish_repos = async (repos, options) => {
23
24
  * before any side effect, a dry run still reports the partial cascade but returns
24
25
  * `ok: false`. This is the single error gate — `--no-plan` can't bypass it.
25
26
  */
26
- export const execute_publishing_plan = async (repos, plan, options) => {
27
+ export const execute_publishing_plan = async (all_repos, plan, options) => {
27
28
  const start_time = Date.now();
28
29
  const { wetrun, log, ops = default_gitops_operations } = options;
30
+ // Only npm repos publish; drop any non-npm repos (e.g. cargo) so preflight and the
31
+ // executor's name lookup never touch them. The plan already excludes them too.
32
+ const repos = all_repos.filter(repo_is_npm);
29
33
  // Fail loud on an incomplete plan. Executing one with errors would silently skip the
30
34
  // affected packages. A wetrun aborts before touching npm or git; a dry run proceeds
31
35
  // (no side effects) but the result is not ok (see the summary below).
@@ -1,4 +1,4 @@
1
- import type { Logger } from '@fuzdev/fuz_util/log.js';
1
+ import type { Logger } from '@fuzdev/fuz_util/log.ts';
2
2
  export interface WaitOptions {
3
3
  log?: Logger;
4
4
  max_attempts?: number;
@@ -1,5 +1,5 @@
1
- import { spawn_out } from '@fuzdev/fuz_util/process.js';
2
- import { wait } from '@fuzdev/fuz_util/async.js';
1
+ import { spawn_out } from '@fuzdev/fuz_util/process.ts';
2
+ import { wait } from '@fuzdev/fuz_util/async.ts';
3
3
  import { styleText as st } from 'node:util';
4
4
  export const check_package_available = async (pkg, version, options = {}) => {
5
5
  const { log } = options;
@@ -33,9 +33,9 @@
33
33
  *
34
34
  * @module
35
35
  */
36
- import type { Result } from '@fuzdev/fuz_util/result.js';
37
- import type { FsError } from '@fuzdev/fuz_util/fs.js';
38
- import type { Logger } from '@fuzdev/fuz_util/log.js';
36
+ import type { Result } from '@fuzdev/fuz_util/result.ts';
37
+ import type { FsError } from '@fuzdev/fuz_util/fs.ts';
38
+ import type { Logger } from '@fuzdev/fuz_util/log.ts';
39
39
  import type { LocalRepo } from './local_repo.js';
40
40
  import type { ChangesetInfo } from './changeset_reader.js';
41
41
  import type { BumpType } from './version_utils.js';
@@ -359,7 +359,7 @@ export interface PreflightOperations {
359
359
  *
360
360
  * Errors are typed via `FsError` (`not_found | permission_denied |
361
361
  * already_exists | io_error`) so callers can branch on `kind` instead of
362
- * regex-matching `message`. See `@fuzdev/fuz_util/fs.js`.
362
+ * regex-matching `message`. See `@fuzdev/fuz_util/fs.ts`.
363
363
  */
364
364
  export interface FsOperations {
365
365
  /**
@@ -6,11 +6,11 @@
6
6
  *
7
7
  * @module
8
8
  */
9
- import { spawn_out } from '@fuzdev/fuz_util/process.js';
9
+ import { spawn_out } from '@fuzdev/fuz_util/process.ts';
10
10
  import { readFile, writeFile, mkdir, stat } from 'node:fs/promises';
11
- import { git_checkout } from '@fuzdev/fuz_util/git.js';
12
- import { fs_classify_error } from '@fuzdev/fuz_util/fs.js';
13
- import { EMPTY_OBJECT } from '@fuzdev/fuz_util/object.js';
11
+ import { git_checkout } from '@fuzdev/fuz_util/git.ts';
12
+ import { fs_classify_error } from '@fuzdev/fuz_util/fs.ts';
13
+ import { EMPTY_OBJECT } from '@fuzdev/fuz_util/object.ts';
14
14
  import { has_changesets, read_changesets, predict_next_version } from './changeset_reader.js';
15
15
  import { wait_for_package } from './npm_registry.js';
16
16
  import { run_preflight_checks } from './preflight_checks.js';
@@ -1,4 +1,4 @@
1
- import type { Logger } from '@fuzdev/fuz_util/log.js';
1
+ import type { Logger } from '@fuzdev/fuz_util/log.ts';
2
2
  export type OutputFormat = 'stdout' | 'json' | 'markdown';
3
3
  export interface OutputOptions {
4
4
  format: OutputFormat;
@@ -1,4 +1,4 @@
1
- import type { Logger } from '@fuzdev/fuz_util/log.js';
1
+ import type { Logger } from '@fuzdev/fuz_util/log.ts';
2
2
  import type { LocalRepo } from './local_repo.js';
3
3
  import type { GitOperations, NpmOperations, BuildOperations, ChangesetOperations } from './operations.js';
4
4
  export interface PreflightOptions {
@@ -1,4 +1,4 @@
1
- import { spawn_out } from '@fuzdev/fuz_util/process.js';
1
+ import { spawn_out } from '@fuzdev/fuz_util/process.ts';
2
2
  import { styleText as st } from 'node:util';
3
3
  import { default_git_operations, default_npm_operations, default_build_operations, default_changeset_operations, } from './operations_defaults.js';
4
4
  /**
@@ -7,7 +7,7 @@
7
7
  *
8
8
  * @module
9
9
  */
10
- import { UnreachableError } from '@fuzdev/fuz_util/error.js';
10
+ import { UnreachableError } from '@fuzdev/fuz_util/error.ts';
11
11
  const step_via = (change) => change.needs_bump_escalation
12
12
  ? 'escalation'
13
13
  : change.has_changesets
@@ -1,5 +1,5 @@
1
- import type { Logger } from '@fuzdev/fuz_util/log.js';
2
- import type { LocalRepo } from './local_repo.js';
1
+ import type { Logger } from '@fuzdev/fuz_util/log.ts';
2
+ import { type LocalRepo } from './local_repo.js';
3
3
  import { type BumpType } from './version_utils.js';
4
4
  import type { ChangesetOperations } from './operations.js';
5
5
  export { log_publishing_plan, type LogPlanOptions } from './publishing_plan_logging.js';
@@ -95,5 +95,5 @@ export interface GeneratePlanOptions {
95
95
  * Shows version changes, dependency updates, and breaking change cascades.
96
96
  * Uses fixed-point iteration to resolve transitive cascades.
97
97
  */
98
- export declare const generate_publishing_plan: (repos: Array<LocalRepo>, options?: GeneratePlanOptions) => Promise<PublishingPlan>;
98
+ export declare const generate_publishing_plan: (all_repos: Array<LocalRepo>, options?: GeneratePlanOptions) => Promise<PublishingPlan>;
99
99
  //# sourceMappingURL=publishing_plan.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"publishing_plan.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/publishing_plan.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"publishing_plan.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/publishing_plan.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import { styleText as st } from 'node:util';
2
+ import { repo_is_npm } from './local_repo.js';
2
3
  import { validate_dependency_graph } from './graph_validation.js';
3
4
  import { is_breaking_change, compare_bump_types, calculate_next_version, } from './version_utils.js';
4
5
  import { default_changeset_operations } from './operations_defaults.js';
@@ -11,12 +12,21 @@ export { log_publishing_plan } from './publishing_plan_logging.js';
11
12
  * Shows version changes, dependency updates, and breaking change cascades.
12
13
  * Uses fixed-point iteration to resolve transitive cascades.
13
14
  */
14
- export const generate_publishing_plan = async (repos, options = {}) => {
15
+ export const generate_publishing_plan = async (all_repos, options = {}) => {
15
16
  const { log, ops = default_changeset_operations, verbose } = options;
16
17
  log?.info(st('cyan', 'Generating publishing plan...'));
17
18
  const warnings = [];
18
19
  const info = []; // Informational status (not warnings)
19
20
  const errors = [];
21
+ // Publishing concerns only npm packages. Non-npm repos (e.g. Rust cargo repos) are
22
+ // loaded for the dashboard but have no npm identity in the changeset cascade — drop them
23
+ // before building the graph so they never appear in the plan or publishing order.
24
+ const non_npm_repos = all_repos.filter((r) => !repo_is_npm(r));
25
+ if (non_npm_repos.length > 0) {
26
+ info.push(`Excluded ${non_npm_repos.length} non-npm repo(s) from publishing: ` +
27
+ non_npm_repos.map((r) => r.library.name).join(', '));
28
+ }
29
+ const repos = all_repos.filter(repo_is_npm);
20
30
  // Verbose data collection
21
31
  const verbose_changeset_details = [];
22
32
  const verbose_iterations = [];
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * @module
7
7
  */
8
- import type { Logger } from '@fuzdev/fuz_util/log.js';
8
+ import type { Logger } from '@fuzdev/fuz_util/log.ts';
9
9
  import type { PublishingPlan } from './publishing_plan.js';
10
10
  export interface LogPlanOptions {
11
11
  verbose?: boolean;
@@ -1,8 +1,8 @@
1
- import type { LibraryJson, SourceJson } from '@fuzdev/fuz_util/library_json.js';
2
- import type { PkgJson } from '@fuzdev/fuz_util/pkg_json.js';
3
- import type { PackageJson } from '@fuzdev/fuz_util/package_json.js';
4
- import type { Url } from '@fuzdev/fuz_util/url.js';
5
- import { Library } from '@fuzdev/fuz_ui/library.svelte.js';
1
+ import type { LibraryJson, SourceJson } from '@fuzdev/fuz_util/library_json.ts';
2
+ import type { PkgJson } from '@fuzdev/fuz_util/pkg_json.ts';
3
+ import type { PackageJson } from '@fuzdev/fuz_util/package_json.ts';
4
+ import type { Url } from '@fuzdev/fuz_util/url.ts';
5
+ import { Library } from '@fuzdev/fuz_ui/library.svelte.ts';
6
6
  import { GithubCheckRunsItem, type GithubPullRequest } from './github.js';
7
7
  /**
8
8
  * Serialized repo data as stored in `repos.ts` (JSON).
@@ -1,5 +1,5 @@
1
- import { create_context } from '@fuzdev/fuz_ui/context_helpers.js';
2
- import { Library } from '@fuzdev/fuz_ui/library.svelte.js';
1
+ import { create_context } from '@fuzdev/fuz_ui/context_helpers.ts';
2
+ import { Library } from '@fuzdev/fuz_ui/library.svelte.ts';
3
3
  import { GithubCheckRunsItem } from './github.js';
4
4
  /**
5
5
  * Runtime repo with `Library` composition for package metadata.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fuzdev/fuz_gitops",
3
- "version": "0.77.0",
3
+ "version": "0.78.0",
4
4
  "description": "a tool for managing many repos",
5
5
  "glyph": "🪄",
6
6
  "logo": "logo.svg",
@@ -31,7 +31,7 @@
31
31
  "peerDependencies": {
32
32
  "@fuzdev/fuz_css": ">=0.62.0",
33
33
  "@fuzdev/fuz_ui": ">=0.205.1",
34
- "@fuzdev/fuz_util": ">=0.65.1",
34
+ "@fuzdev/fuz_util": ">=0.65.2",
35
35
  "@fuzdev/gro": ">=0.204.0",
36
36
  "@sveltejs/kit": "^2",
37
37
  "svelte": "^5",
@@ -43,15 +43,15 @@
43
43
  "@fuzdev/fuz_code": "^0.46.1",
44
44
  "@fuzdev/fuz_css": "^0.63.2",
45
45
  "@fuzdev/fuz_ui": "^0.205.1",
46
- "@fuzdev/fuz_util": "^0.65.1",
47
- "@fuzdev/gro": "^0.204.0",
46
+ "@fuzdev/fuz_util": "^0.65.2",
47
+ "@fuzdev/gro": "^0.205.1",
48
48
  "@fuzdev/mdz": "^0.1.0",
49
49
  "@ryanatkn/eslint-config": "^0.12.1",
50
50
  "@sveltejs/acorn-typescript": "^1.0.9",
51
51
  "@sveltejs/adapter-static": "^3.0.10",
52
52
  "@sveltejs/kit": "^2.63.0",
53
53
  "@sveltejs/package": "^2.5.7",
54
- "@sveltejs/vite-plugin-svelte": "^6.2.4",
54
+ "@sveltejs/vite-plugin-svelte": "^7.1.2",
55
55
  "@types/estree": "^1.0.8",
56
56
  "@types/node": "^24.10.1",
57
57
  "@webref/css": "^8.2.0",
@@ -68,7 +68,7 @@
68
68
  "tslib": "^2.8.1",
69
69
  "typescript": "^5.9.3",
70
70
  "typescript-eslint": "^8.48.1",
71
- "vite": "^7.3.1",
71
+ "vite": "^8.0.16",
72
72
  "vitest": "^4.0.15",
73
73
  "zimmerframe": "^1.1.4",
74
74
  "zod": "^4.3.6"
@@ -0,0 +1,82 @@
1
+ import {existsSync} from 'node:fs';
2
+ import {readFile} from 'node:fs/promises';
3
+ import {join} from 'node:path';
4
+
5
+ /**
6
+ * The handful of identity fields gitops reads from a Rust repo's `Cargo.toml`
7
+ * to render it on the dashboard. Everything is optional — a workspace root has
8
+ * no `name`, and any field may be absent or inherited.
9
+ */
10
+ export interface CargoMetadata {
11
+ name?: string;
12
+ version?: string;
13
+ description?: string;
14
+ repository?: string;
15
+ }
16
+
17
+ /** The `Cargo.toml` tables that carry package identity (single-crate vs workspace root). */
18
+ const CARGO_METADATA_SECTIONS: ReadonlySet<string> = new Set(['package', 'workspace.package']);
19
+ const CARGO_METADATA_KEYS = ['name', 'version', 'description', 'repository'] as const;
20
+ type CargoMetadataKey = (typeof CARGO_METADATA_KEYS)[number];
21
+
22
+ /**
23
+ * Best-effort read of a repo's root `Cargo.toml` for the identity fields the
24
+ * gitops dashboard renders. Returns `null` when there's no `Cargo.toml`.
25
+ *
26
+ * @param repo_dir - absolute path to the repo
27
+ */
28
+ export const cargo_toml_load = async (repo_dir: string): Promise<CargoMetadata | null> => {
29
+ const cargo_toml_path = join(repo_dir, 'Cargo.toml');
30
+ if (!existsSync(cargo_toml_path)) return null;
31
+ return cargo_toml_parse(await readFile(cargo_toml_path, 'utf8'));
32
+ };
33
+
34
+ /**
35
+ * Extracts `name`/`version`/`description`/`repository` from the `[package]` and
36
+ * `[workspace.package]` tables of a `Cargo.toml`.
37
+ *
38
+ * Deliberately not a full TOML parser: it scans for simple `key = "value"`
39
+ * string entries in those two tables, which covers both a single-crate manifest
40
+ * and a workspace root. Inline-table values like `version = { workspace = true }`
41
+ * (and the equivalent `version.workspace = true`) are ignored — a member crate
42
+ * inheriting from the workspace has no literal here, and gitops only ever reads a
43
+ * repo's root manifest, where these are concrete. The first non-empty value for a
44
+ * key wins, so a top-level `[package]` takes precedence over `[workspace.package]`
45
+ * when both appear.
46
+ */
47
+ export const cargo_toml_parse = (contents: string): CargoMetadata => {
48
+ const metadata: CargoMetadata = {};
49
+ let in_metadata_section = false;
50
+ for (const raw_line of contents.split('\n')) {
51
+ const line = raw_line.trim();
52
+ if (line === '' || line.startsWith('#')) continue;
53
+ // Section header — only `[package]`/`[workspace.package]` arm value capture.
54
+ if (line.startsWith('[')) {
55
+ const end = line.indexOf(']');
56
+ in_metadata_section = end !== -1 && CARGO_METADATA_SECTIONS.has(line.slice(1, end).trim());
57
+ continue;
58
+ }
59
+ if (!in_metadata_section) continue;
60
+ const eq = line.indexOf('=');
61
+ if (eq === -1) continue;
62
+ const key = line.slice(0, eq).trim();
63
+ if (!CARGO_METADATA_KEYS.includes(key as CargoMetadataKey)) continue;
64
+ if (metadata[key as CargoMetadataKey] !== undefined) continue; // first value wins
65
+ const value = cargo_toml_string_value(line.slice(eq + 1).trim());
66
+ if (value !== null) metadata[key as CargoMetadataKey] = value;
67
+ }
68
+ return metadata;
69
+ };
70
+
71
+ /**
72
+ * Reads a simple single- or double-quoted TOML string, ignoring any trailing
73
+ * inline comment. Returns `null` for non-string values (inline tables, arrays,
74
+ * booleans, numbers), which the caller skips.
75
+ */
76
+ const cargo_toml_string_value = (raw: string): string | null => {
77
+ const quote = raw[0];
78
+ if (quote !== '"' && quote !== "'") return null;
79
+ const end = raw.indexOf(quote, 1);
80
+ if (end === -1) return null;
81
+ return raw.slice(1, end);
82
+ };
@@ -8,16 +8,16 @@
8
8
  */
9
9
 
10
10
  import {join} from 'node:path';
11
- import type {Logger} from '@fuzdev/fuz_util/log.js';
12
- import type {LocalRepo} from './local_repo.js';
13
- import type {PublishedVersion} from './multi_repo_publisher.js';
11
+ import type {Logger} from '@fuzdev/fuz_util/log.ts';
12
+ import type {LocalRepo} from './local_repo.ts';
13
+ import type {PublishedVersion} from './multi_repo_publisher.ts';
14
14
  import {
15
15
  strip_version_prefix,
16
16
  required_bump_for_dependency_update,
17
17
  type BumpType,
18
- } from './version_utils.js';
19
- import type {FsOperations} from './operations.js';
20
- import {default_fs_operations} from './operations_defaults.js';
18
+ } from './version_utils.ts';
19
+ import type {FsOperations} from './operations.ts';
20
+ import {default_fs_operations} from './operations_defaults.ts';
21
21
 
22
22
  export interface DependencyVersionChange {
23
23
  package_name: string;
@@ -7,13 +7,13 @@
7
7
  * @module
8
8
  */
9
9
 
10
- import type {Logger} from '@fuzdev/fuz_util/log.js';
10
+ import type {Logger} from '@fuzdev/fuz_util/log.ts';
11
11
  import {existsSync} from 'node:fs';
12
12
  import {readdir, readFile} from 'node:fs/promises';
13
13
  import {join} from 'node:path';
14
14
 
15
- import type {LocalRepo} from './local_repo.js';
16
- import {compare_bump_types, calculate_next_version, type BumpType} from './version_utils.js';
15
+ import type {LocalRepo} from './local_repo.ts';
16
+ import {compare_bump_types, calculate_next_version, type BumpType} from './version_utils.ts';
17
17
 
18
18
  export interface ChangesetInfo {
19
19
  filename: string;
@@ -11,7 +11,7 @@
11
11
  * @module
12
12
  */
13
13
 
14
- import type {GitopsRepoConfig} from './gitops_config.js';
14
+ import type {GitopsRepoConfig} from './gitops_config.ts';
15
15
 
16
16
  /** Repo fields that must agree across every config that lists the repo. */
17
17
  const INTRINSIC_FIELDS = ['visibility', 'ci', 'archived', 'branch'] as const;
@@ -1,17 +1,17 @@
1
1
  /**
2
2
  * Dependency graph data structure and algorithms for multi-repo publishing.
3
3
  *
4
- * Provides `DependencyGraph` class with topological sort (via `@fuzdev/fuz_util/sort.js`)
4
+ * Provides `DependencyGraph` class with topological sort (via `@fuzdev/fuz_util/sort.ts`)
5
5
  * and cycle detection by dependency type.
6
6
  * For validation workflow and publishing order computation, see `graph_validation.ts`.
7
7
  *
8
8
  * @module
9
9
  */
10
10
 
11
- import {EMPTY_OBJECT} from '@fuzdev/fuz_util/object.js';
12
- import {topological_sort as topological_sort_generic} from '@fuzdev/fuz_util/sort.js';
11
+ import {EMPTY_OBJECT} from '@fuzdev/fuz_util/object.ts';
12
+ import {topological_sort as topological_sort_generic} from '@fuzdev/fuz_util/sort.ts';
13
13
 
14
- import type {LocalRepo} from './local_repo.js';
14
+ import type {LocalRepo} from './local_repo.ts';
15
15
 
16
16
  export const DEPENDENCY_TYPE = {
17
17
  PROD: 'prod',
@@ -122,7 +122,7 @@ export class DependencyGraph {
122
122
  /**
123
123
  * Computes topological sort order for dependency graph.
124
124
  *
125
- * Delegates to `@fuzdev/fuz_util/sort.js` for the sorting algorithm.
125
+ * Delegates to `@fuzdev/fuz_util/sort.ts` for the sorting algorithm.
126
126
  * Throws if cycles detected.
127
127
  *
128
128
  * @param exclude_dev - if true, excludes dev dependencies to break cycles
@@ -1,15 +1,15 @@
1
- import type {Logger} from '@fuzdev/fuz_util/log.js';
1
+ import type {Logger} from '@fuzdev/fuz_util/log.ts';
2
2
  import {join} from 'node:path';
3
3
 
4
- import type {LocalRepo} from './local_repo.js';
5
- import type {PublishedVersion} from './multi_repo_publisher.js';
4
+ import type {LocalRepo} from './local_repo.ts';
5
+ import type {PublishedVersion} from './multi_repo_publisher.ts';
6
6
  import {
7
7
  create_changeset_for_dependency_updates,
8
8
  create_dependency_updates,
9
- } from './changeset_generator.js';
10
- import {needs_update, get_update_prefix} from './version_utils.js';
11
- import type {GitOperations, FsOperations} from './operations.js';
12
- import {default_git_operations, default_fs_operations} from './operations_defaults.js';
9
+ } from './changeset_generator.ts';
10
+ import {needs_update, get_update_prefix} from './version_utils.ts';
11
+ import type {GitOperations, FsOperations} from './operations.ts';
12
+ import {default_git_operations, default_fs_operations} from './operations_defaults.ts';
13
13
 
14
14
  export type VersionStrategy = 'exact' | 'caret' | 'tilde' | 'gte';
15
15
 
@@ -1,10 +1,10 @@
1
- import type {Logger} from '@fuzdev/fuz_util/log.js';
2
- import {wait} from '@fuzdev/fuz_util/async.js';
3
- import type {FetchValueCache} from '@fuzdev/fuz_util/fetch.js';
1
+ import type {Logger} from '@fuzdev/fuz_util/log.ts';
2
+ import {wait} from '@fuzdev/fuz_util/async.ts';
3
+ import type {FetchValueCache} from '@fuzdev/fuz_util/fetch.ts';
4
4
 
5
- import {fetch_github_check_runs, fetch_github_pull_requests} from './github.js';
6
- import type {RepoJson} from './repo.svelte.js';
7
- import type {LocalRepo} from './local_repo.js';
5
+ import {fetch_github_check_runs, fetch_github_pull_requests} from './github.ts';
6
+ import type {RepoJson} from './repo.svelte.ts';
7
+ import type {LocalRepo} from './local_repo.ts';
8
8
 
9
9
  /**
10
10
  * Fetches GitHub metadata (CI status, PRs) for all repos.
@@ -1,8 +1,8 @@
1
1
  import {mkdir, readFile, rm, writeFile} from 'node:fs/promises';
2
2
  import {dirname, join} from 'node:path';
3
- import {paths} from '@fuzdev/gro/paths.js';
4
- import {format_file} from '@fuzdev/gro/format_file.js';
5
- import {deserialize_cache, serialize_cache, type FetchValueCache} from '@fuzdev/fuz_util/fetch.js';
3
+ import {paths} from '@fuzdev/gro/paths.ts';
4
+ import {format_file} from '@fuzdev/gro/format_file.ts';
5
+ import {deserialize_cache, serialize_cache, type FetchValueCache} from '@fuzdev/fuz_util/fetch.ts';
6
6
  import {existsSync} from 'node:fs';
7
7
 
8
8
  // TODO upstream to Gro probably, and rename/redesign?
@@ -1,4 +1,4 @@
1
- import {spawn_out, spawn_result_to_message} from '@fuzdev/fuz_util/process.js';
1
+ import {spawn_out, spawn_result_to_message} from '@fuzdev/fuz_util/process.ts';
2
2
  import type {SpawnOptions} from 'node:child_process';
3
3
  import {
4
4
  git_check_clean_workspace as gro_git_check_clean_workspace,
@@ -8,7 +8,7 @@ import {
8
8
  git_current_commit_hash as gro_git_current_commit_hash,
9
9
  type GitBranch,
10
10
  type GitOrigin,
11
- } from '@fuzdev/fuz_util/git.js';
11
+ } from '@fuzdev/fuz_util/git.ts';
12
12
 
13
13
  /**
14
14
  * Adds files to git staging area and throws if anything goes wrong.
package/src/lib/github.ts CHANGED
@@ -1,6 +1,6 @@
1
- import type {Logger} from '@fuzdev/fuz_util/log.js';
1
+ import type {Logger} from '@fuzdev/fuz_util/log.ts';
2
2
  import {z} from 'zod';
3
- import {fetch_value, type FetchValueCache} from '@fuzdev/fuz_util/fetch.js';
3
+ import {fetch_value, type FetchValueCache} from '@fuzdev/fuz_util/fetch.ts';
4
4
 
5
5
  /**
6
6
  * Minimal interface for GitHub API calls - works with both `Pkg` and `Repo`.