yadflow 3.4.0 → 3.4.2

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/CHANGELOG.md CHANGED
@@ -1,9 +1,10 @@
1
- # [3.4.0](https://github.com/abdelrahmannasr/yadflow/compare/v3.3.1...v3.4.0) (2026-07-01)
1
+ ## [3.4.2](https://github.com/abdelrahmannasr/yadflow/compare/v3.4.1...v3.4.2) (2026-07-01)
2
2
 
3
3
 
4
- ### Features
4
+ ### Bug Fixes
5
5
 
6
- * **report:** add self issue reporter with auto-scrubbed diagnostics ([cd70965](https://github.com/abdelrahmannasr/yadflow/commit/cd7096568995d52501a2e9b57a7ac091a22620f1))
6
+ * **doctor:** warn YAD-CFG-005 on hub.json missing git_url; stop misleading YAD-ENV-002 ([3f588af](https://github.com/abdelrahmannasr/yadflow/commit/3f588af2e01e117e661b08b5f5b8e069e41e887f))
7
+ * **setup:** write and backfill hub.json git_url from the origin remote ([c809358](https://github.com/abdelrahmannasr/yadflow/commit/c8093581319dcb9700b3dd0ebe930dbf784348ff))
7
8
 
8
9
  # [2.2.0](https://github.com/abdelrahmannasr/yadflow/compare/v2.1.0...v2.2.0) (2026-06-14)
9
10
 
package/README.md CHANGED
@@ -91,7 +91,7 @@ development, not another code generator.
91
91
  - **[Terminology & workflow report](https://abdelrahmannasr.github.io/yadflow/)** — every term, artifact, gate, and skill on one illustrated page.
92
92
  - **[TEAM-GUIDE.md](TEAM-GUIDE.md)** — the short, plain-language version for a developer team.
93
93
  - **[docs/CLI.md](docs/CLI.md)** — the full `yad` command reference, the PR-driven gate, and `yad doctor` codes.
94
- - **[docs/SKILLS.md](docs/SKILLS.md)** — the catalogue of all 36 agent skills.
94
+ - **[docs/SKILLS.md](docs/SKILLS.md)** — the catalogue of all 37 agent skills.
95
95
  - **[docs/WALKTHROUGH.md](docs/WALKTHROUGH.md)** — the by-hand, end-to-end path through every phase.
96
96
  - **[CONTRIBUTING.md](CONTRIBUTING.md)** · **[RESEARCH-NOTES.md](RESEARCH-NOTES.md)** · **[RELEASING.md](RELEASING.md)**
97
97
 
package/cli/doctor.mjs CHANGED
@@ -76,13 +76,25 @@ export function projectChecks(checks, root) {
76
76
  // platform CLI + auth (best-effort; auth probing is the user's own session)
77
77
  const cli = cliFor(hub.platform);
78
78
  if (cli) {
79
- // Scope the auth probe to the hub's own host (derived from git_url). `${cli} auth status`
80
- // without --hostname exits non-zero when ANY configured instance fails, so an unrelated
81
- // stale login (e.g. a dead gitlab.com token) would falsely flag a working self-hosted hub.
82
- const host = hostFromGitUrl(hub.git_url);
83
- const authArgs = host ? ['auth', 'status', '--hostname', host] : ['auth', 'status'];
79
+ // git_url is required whenever a platform is set doctor needs it to scope the auth probe
80
+ // and the bridge/PR flow needs it to open PRs. Warn on its absence directly (not on the
81
+ // resolved host), so it fires even when an origin remote can substitute: the field itself
82
+ // is required regardless.
83
+ if (!hostFromGitUrl(hub.git_url)) {
84
+ check(checks, 'hub-git-url', 'project', 'warn',
85
+ `${PROJECT_FILES.hubConfig} sets platform '${hub.platform}' but has no git_url [YAD-CFG-005]`,
86
+ 'add git_url to hub.json (or re-run `yad setup`) — auth/PR checks need the hub host');
87
+ }
88
+ // Scope the auth probe to the hub's own host (derived from git_url, falling back to the
89
+ // origin remote). `${cli} auth status` without --hostname exits non-zero when ANY configured
90
+ // instance fails, so an unrelated stale login (e.g. a dead gitlab.com token) would falsely
91
+ // flag a working self-hosted hub — so we SKIP the probe entirely when no host resolves
92
+ // rather than run the flaky unscoped form.
93
+ const host = hostFromGitUrl(hub.git_url)
94
+ || hostFromGitUrl(run('git', ['remote', 'get-url', 'origin'], { cwd: root }).stdout);
84
95
  if (!has(cli)) check(checks, 'platform-cli', 'project', 'warn', `${cli} not found on PATH [YAD-ENV-002]`, `install ${cli} — the gate degrades to file-only without it`);
85
- else if (!run(cli, authArgs).ok) check(checks, 'platform-cli', 'project', 'warn', `${cli} present but not authenticated${host ? ` for ${host}` : ''} [YAD-ENV-002]`, `run \`${cli} auth login${host ? ` --hostname ${host}` : ''}\``);
96
+ else if (!host) check(checks, 'platform-cli', 'project', 'warn', 'auth check skipped hub host unknown (no git_url / origin)', 'add git_url to hub.json so the auth probe can target the right host');
97
+ else if (!run(cli, ['auth', 'status', '--hostname', host]).ok) check(checks, 'platform-cli', 'project', 'warn', `${cli} present but not authenticated for ${host} [YAD-ENV-002]`, `run \`${cli} auth login --hostname ${host}\``);
86
98
  else {
87
99
  check(checks, 'platform-cli', 'project', 'ok', `${cli} present and authenticated`);
88
100
  // Re-validate each roster login against the hub (warn-only). Skips when a login is already
@@ -99,10 +111,10 @@ export function projectChecks(checks, root) {
99
111
  // probe a cheap api call (warn-only) to surface it before a sync silently holds the gate.
100
112
  if (hub.platform === 'gitlab') {
101
113
  // Scope the probe to the hub's own host (like the auth check above) so a multi-instance
102
- // setup doesn't hit the wrong GitLab and emit a misleading warning.
103
- const apiArgs = host ? ['api', 'version', '--hostname', host] : ['api', 'version'];
104
- if (!run('glab', apiArgs).ok) {
105
- check(checks, 'gitlab-api', 'project', 'warn', `glab is authenticated but \`glab api\` failed${host ? ` for ${host}` : ''} [YAD-ENV-002]`, 'ensure the token has `api` scope — the gate reads MR approvals/discussions via the API');
114
+ // setup doesn't hit the wrong GitLab. `host` is guaranteed truthy here (we skip the whole
115
+ // auth branch when it cannot be resolved), so the probe is always host-scoped.
116
+ if (!run('glab', ['api', 'version', '--hostname', host]).ok) {
117
+ check(checks, 'gitlab-api', 'project', 'warn', `glab is authenticated but \`glab api\` failed for ${host} [YAD-ENV-002]`, 'ensure the token has `api` scope — the gate reads MR approvals/discussions via the API');
106
118
  }
107
119
  }
108
120
  // Solo + GitHub: a branch that "requires approvals" would block the solo dev's own merge
package/cli/errors.mjs CHANGED
@@ -23,6 +23,7 @@ export const CODES = {
23
23
  'YAD-CFG-002': 'design.json names an unknown design tool (expected one of config.yaml design.tools, or none)',
24
24
  'YAD-CFG-003': 'testing.json names an unknown testing tool (expected one of config.yaml testing.tools, or none)',
25
25
  'YAD-CFG-004': 'learning.json names an unknown learning tool (expected one of config.yaml learning.tools, or none)',
26
+ 'YAD-CFG-005': 'hub.json sets a platform but is missing git_url (required to scope auth + open PRs)',
26
27
  };
27
28
 
28
29
  export const err = (code, message, hint) => new YadError(code, message, hint);
package/cli/next.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  // `yad next` — the unified next-step driver. Read-only: it never writes state or acts. It reads the
2
2
  // file ledger and prints the ONE concrete, copy-pasteable next action (and a one-line why), so a user
3
- // never has to remember which of the 31 skills / gate commands comes next. "Guide, don't act" — the
3
+ // never has to remember which of the 37 skills / gate commands comes next. "Guide, don't act" — the
4
4
  // front half still never auto-advances. Once an epic is `ready-for-build`, it reads each story's
5
5
  // build-state and prints the next BUILD sub-step per repo (spec → tasks → implement → checks → engineer-review)
6
6
  // plus the remaining chain — so the build half is guided too, not just hinted at.
package/cli/setup.mjs CHANGED
@@ -482,16 +482,24 @@ export async function runSetup(root, opts = {}) {
482
482
  // `bridge_enabled` is the canonical flag (hub-config schema); keep the legacy `bridge` spelling
483
483
  // for anything that still reads it.
484
484
  const enabled = platform !== 'none';
485
- writeJSON(hubPath, { platform: enabled ? platform : null, bridge_enabled: enabled, bridge: enabled, default_branch, roster, solo, profile: { codebase, repo_layout, team_size } });
485
+ // Record git_url doctor needs it to scope the auth probe (YAD-CFG-005) and the bridge/PR flow
486
+ // needs it to open PRs. Derived from the origin remote already resolved above; null when local-only.
487
+ const git_url = enabled ? ((remote.ok && remote.stdout.trim()) || null) : null;
488
+ writeJSON(hubPath, { platform: enabled ? platform : null, git_url, bridge_enabled: enabled, bridge: enabled, default_branch, roster, solo, profile: { codebase, repo_layout, team_size } });
486
489
  ok(`wrote ${PROJECT_FILES.hubConfig} (${roster.length} reviewer(s)${solo ? ', solo mode' : ''})`);
487
490
  }
488
491
  // Persist the profile + solo flag even on the "keeping existing" path, so re-running setup with new
489
492
  // flags (e.g. `yad setup --solo`) updates the mode without a full reconfigure. Merge, never clobber.
493
+ // Also backfill a missing git_url from origin here (idempotent repair for the doctor's YAD-CFG-005).
490
494
  if (exists(hubPath)) {
491
495
  const cur = readJSON(hubPath, {}) || {};
492
- if (cur.solo !== solo || JSON.stringify(cur.profile || {}) !== JSON.stringify({ codebase, repo_layout, team_size })) {
493
- writeJSON(hubPath, { ...cur, solo, profile: { codebase, repo_layout, team_size } });
494
- info(`recorded profile: ${solo ? 'solo' : `team(${team_size})`}, ${codebase}, ${repo_layout}`);
496
+ const backfillUrl = (cur.platform && !cur.git_url)
497
+ ? ((run('git', ['remote', 'get-url', 'origin'], { cwd: root }).stdout || '').trim() || null)
498
+ : null;
499
+ if (cur.solo !== solo || JSON.stringify(cur.profile || {}) !== JSON.stringify({ codebase, repo_layout, team_size }) || backfillUrl) {
500
+ writeJSON(hubPath, { ...cur, ...(backfillUrl ? { git_url: backfillUrl } : {}), solo, profile: { codebase, repo_layout, team_size } });
501
+ if (backfillUrl) info(`backfilled hub git_url from origin: ${backfillUrl}`);
502
+ else info(`recorded profile: ${solo ? 'solo' : `team(${team_size})`}, ${codebase}, ${repo_layout}`);
495
503
  }
496
504
  }
497
505
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "yadflow",
3
- "version": "3.4.0",
4
- "description": "Yadflow — the gated, team, multi-repo SDLC: author → review → build with a PR-driven review gate and a zero-dependency `yad` CLI (setup, gate, commit, open-pr, ship, repo, thread, reconcile). A BMAD module + 34 yad-* skills.",
3
+ "version": "3.4.2",
4
+ "description": "Yadflow — the gated, team, multi-repo SDLC: author → review → build with a PR-driven review gate and a zero-dependency `yad` CLI (setup, gate, commit, open-pr, ship, repo, thread, reconcile). A BMAD module + 37 yad-* skills.",
5
5
  "type": "module",
6
6
  "author": "AbdelRahman Nasr",
7
7
  "license": "MIT",
@@ -16,7 +16,7 @@ login to an SDLC name + role. It is a single object for the hub itself — the s
16
16
  ```json
17
17
  {
18
18
  "platform": "github", // github | gitlab (from the hub's own remote host); null when local-only
19
- "git_url": "https://github.com/abdelrahmannasr/yadflow.git",
19
+ "git_url": "https://github.com/abdelrahmannasr/yadflow.git", // REQUIRED when platform is non-null (scopes auth + opens PRs); yad doctor warns YAD-CFG-005 if absent
20
20
  "default_branch": "main",
21
21
  "bridge_enabled": true, // open review PRs/MRs on the hub for front-half reviews
22
22
  "review": { "requireEngagement": false }, // Review Companion: false (soft) counts bare approves but nudges; true counts only verified-engagement approvals
@@ -69,6 +69,11 @@ run `git remote get-url origin` **on the hub itself** and read the host —
69
69
  Auth is the **local user's own** `gh`/`glab`/git credentials; **no tokens are ever stored** (same rule
70
70
  as the registry). `detect-hub` upserts `hub.json` in place — it is idempotent and safe to re-run.
71
71
 
72
+ **`git_url` is required whenever `platform` is non-null.** `yad doctor` uses it to scope the auth
73
+ probe to the hub's own host (an unscoped `glab auth status` fails on any unrelated broken instance),
74
+ and the bridge/PR flow uses it to open PRs. Doctor flags its absence with a warn (`YAD-CFG-005`);
75
+ re-running `yad setup` backfills it from the origin remote (idempotent, non-interactive).
76
+
72
77
  ## Bridge enable / degradation
73
78
 
74
79
  - `bridge_enabled: true` **and** a non-null `platform` **and** `gh`/`glab` authenticated → the front-half