yadflow 4.0.1 → 4.2.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.
package/cli/doctor.mjs CHANGED
@@ -25,6 +25,7 @@ import { soloTeamHint, TEAM_CMD } from './people.mjs';
25
25
  import { indexFreshness, INDEX_FILE } from './product-index.mjs';
26
26
  import { productGit, resolveDefaultBranch } from './productcommit.mjs';
27
27
  import { readOwners } from './owners.mjs';
28
+ import { loadChoices, readToolboxFile } from './toolbox.mjs';
28
29
 
29
30
  // A registered path doctor may run git in (E81): a checkout the judgement accepts — never a refused
30
31
  // entry (git run in a folder the Product shaped as a repo reads its `config`, which can run a command),
@@ -446,6 +447,7 @@ export function projectChecks(checks, root, { headCount = null } = {}) {
446
447
  // inside the `project` block. The renderer prints a header every time the section CHANGES, so a
447
448
  // `project` check added after the `shape` section prints the word "project" a second time.
448
449
  skillBindingChecks(checks, root);
450
+ toolboxFileChecks(checks, root);
449
451
 
450
452
  // repos.json: parse + every entry is a live git repo; staleness vs syncedHead
451
453
  let registry = { repos: [] };
@@ -2107,6 +2109,28 @@ export function skillBindingChecks(checks, root) {
2107
2109
  }
2108
2110
  }
2109
2111
 
2112
+ // `.sdlc/toolbox.json`: which toolbox tools this Product uses or skips, and its own tools (E86). Absent is
2113
+ // the normal case. THE FILE ONLY: whether a tool is installed is `yad toolbox check`'s answer, and a
2114
+ // missing tool is never a doctor line (decided with E86 — no tool is required). A broken file fails, as
2115
+ // skills.json does; a line that does nothing warns, because `yad toolbox list` quietly shows the default.
2116
+ export function toolboxFileChecks(checks, root) {
2117
+ const rel = PROJECT_FILES.toolboxConfig;
2118
+ if (!exists(path.join(root, rel))) return;
2119
+ const { error } = readToolboxFile(root);
2120
+ if (error) {
2121
+ check(checks, 'toolbox', 'project', 'fail', `${rel} ${error}`, 'fix the JSON or restore it from git — `yad toolbox list` shows the defaults until then');
2122
+ return;
2123
+ }
2124
+ const { problems, unreachable, shipped, custom } = loadChoices(root);
2125
+ if (problems.length) {
2126
+ // An entry with no id (or an empty one) is out of `remove`'s reach; only hand-editing fixes it.
2127
+ check(checks, 'toolbox', 'project', 'warn', `${rel}: ${problems.length} line(s) do nothing — ${problems.map((p) => p.replace(`${rel}: `, '')).join('; ')} [YAD-CFG-007]`,
2128
+ `fix them by hand, or \`yad toolbox remove <id>\` — it clears whatever the file holds under that id — and add the tool again${unreachable ? ' (an entry with no id, or an empty one: fix it by hand)' : ''}`);
2129
+ return;
2130
+ }
2131
+ check(checks, 'toolbox', 'project', 'ok', `toolbox: ${shipped.size} shipped tool choice(s), ${custom.length} tool(s) of this project's own`);
2132
+ }
2133
+
2110
2134
  // A step this release does not recognise. Every step the engine can run has a row in the step
2111
2135
  // catalogue (E4), and that row is what gives it both a phase and a skill. So an id no phase claims is
2112
2136
  // an id with no row at all: one `yad next` cannot guide, `yad gate` has no artifact rule for, and no
package/cli/errors.mjs CHANGED
@@ -30,6 +30,7 @@ export const CODES = {
30
30
  'YAD-CFG-004': 'learning.json names an unknown learning tool (expected one of config.yaml learning.tools, or none)',
31
31
  'YAD-CFG-005': 'the Product settings (product.json, or hub.json on a Product that has only that name) set a platform but are missing git_url (required to scope auth + open PRs)',
32
32
  'YAD-CFG-006': 'skills.json binds a step to something that is not a skill name (expected a string, or a non-empty list of strings)',
33
+ 'YAD-CFG-007': 'toolbox.json has a line that does nothing — a tool this yadflow does not ship, a choice other than use or skip, or a custom tool that is incomplete, malformed, listed twice or uses a shipped tool\'s id',
33
34
  'YAD-CLI-001': 'a --json run needed an answer that only a prompt could give',
34
35
  };
35
36
 
package/cli/manifest.mjs CHANGED
@@ -275,6 +275,9 @@ export const PROJECT_FILES = {
275
275
  // the normal case and means "every step uses the skill the catalogue names" — like design.json,
276
276
  // which is absent on a markdown-only project.
277
277
  skillsConfig: '.sdlc/skills.json',
278
+ // Which toolbox tools this project uses or skips, and its own tools (E86). Absent is the normal case:
279
+ // the core tools and the connected design, testing and learning tools are the ones in use.
280
+ toolboxConfig: '.sdlc/toolbox.json',
278
281
  // The kill switch and the Shape steps a team has set to `advance: auto` (E34). Absent is the normal
279
282
  // case: the switch is off and every Shape step is `human`. A project file, not the module config the
280
283
  // switch lived in before (`_bmad/sdlc/config.yaml` then, `.sdlc/config.yaml` since E3) — that one is