yadflow 4.0.0-next.1 → 4.0.0-next.4

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 (129) hide show
  1. package/CHANGELOG.md +223 -0
  2. package/README.md +168 -20
  3. package/bin/commands.mjs +8 -1
  4. package/bin/yad.mjs +262 -32
  5. package/cli/capture.mjs +419 -0
  6. package/cli/checkpoint.mjs +10 -10
  7. package/cli/claims.mjs +165 -0
  8. package/cli/commit.mjs +48 -12
  9. package/cli/docs.mjs +15 -13
  10. package/cli/doctor.mjs +764 -131
  11. package/cli/epic-state.mjs +50 -24
  12. package/cli/errors.mjs +3 -2
  13. package/cli/find-product.mjs +197 -0
  14. package/cli/fold.mjs +247 -0
  15. package/cli/gate-local.mjs +296 -0
  16. package/cli/gate.mjs +111 -103
  17. package/cli/history.mjs +13 -13
  18. package/cli/hook.mjs +201 -30
  19. package/cli/index-command.mjs +6 -6
  20. package/cli/lib.mjs +91 -29
  21. package/cli/manifest.mjs +213 -98
  22. package/cli/migrate.mjs +208 -17
  23. package/cli/mode.mjs +22 -22
  24. package/cli/next.mjs +30 -10
  25. package/cli/openpr.mjs +39 -24
  26. package/cli/owners.mjs +266 -0
  27. package/cli/people.mjs +26 -11
  28. package/cli/plan.mjs +798 -50
  29. package/cli/platform.mjs +13 -7
  30. package/cli/product-index.mjs +4 -4
  31. package/cli/{hubcommit.mjs → productcommit.mjs} +14 -9
  32. package/cli/protection.mjs +19 -9
  33. package/cli/reconcile.mjs +100 -23
  34. package/cli/repo-publish.mjs +22 -16
  35. package/cli/repo.mjs +128 -33
  36. package/cli/report.mjs +8 -2
  37. package/cli/review.mjs +26 -19
  38. package/cli/setup.mjs +112 -35
  39. package/cli/ship.mjs +1 -1
  40. package/cli/skip.mjs +4 -4
  41. package/cli/tidy.mjs +7 -7
  42. package/cli/update-commit.mjs +22 -19
  43. package/cli/workspace.mjs +495 -0
  44. package/package.json +7 -4
  45. package/skills/sdlc/config.yaml +14 -13
  46. package/skills/sdlc/module-help.csv +8 -8
  47. package/skills/yad-analysis/SKILL.md +10 -6
  48. package/skills/yad-architecture/SKILL.md +7 -5
  49. package/skills/yad-backfill/SKILL.md +11 -5
  50. package/skills/yad-backfill/references/backfill.md +37 -0
  51. package/skills/yad-backfill/templates/checks/backfill-check.sh +208 -17
  52. package/skills/yad-change/SKILL.md +4 -2
  53. package/skills/yad-checks/SKILL.md +54 -26
  54. package/skills/yad-checks/references/check-gates.md +260 -54
  55. package/skills/yad-checks/templates/checks/commit-message.sh +39 -13
  56. package/skills/yad-checks/templates/checks/contract-check.sh +534 -20
  57. package/skills/yad-checks/templates/checks/epic-open.sh +398 -8
  58. package/skills/yad-checks/templates/checks/ledger-guard.sh +75 -25
  59. package/skills/yad-checks/templates/checks/lineage-check.sh +391 -7
  60. package/skills/yad-checks/templates/checks/product-checkout.sh +141 -0
  61. package/skills/yad-checks/templates/checks/reconcile-debt-check.sh +399 -8
  62. package/skills/yad-checks/templates/checks/risk-map-check.sh +35 -3
  63. package/skills/yad-checks/templates/checks/spec-link.sh +36 -3
  64. package/skills/yad-checks/templates/checks/verified-commits.sh +26 -2
  65. package/skills/yad-checks/templates/github/yad-checks.yml +33 -13
  66. package/skills/yad-checks/templates/github/{yad-hub-checks.yml → yad-product-checks.yml} +16 -12
  67. package/skills/yad-checks/templates/github/yad-update-guard.yml +5 -2
  68. package/skills/yad-checks/templates/github/yad-verified-commits.yml +1 -1
  69. package/skills/yad-checks/templates/gitlab/yad-checks.gitlab-ci.yml +12 -0
  70. package/skills/yad-checks/templates/gitlab/{yad-hub-checks.gitlab-ci.yml → yad-product-checks.gitlab-ci.yml} +18 -18
  71. package/skills/yad-checks/templates/gitlab/yad-verified-commits.gitlab-ci.yml +2 -2
  72. package/skills/yad-checks/templates/hooks/ledger-guard-cursor.mjs +130 -0
  73. package/skills/yad-checks/templates/hooks/ledger-guard.mjs +117 -0
  74. package/skills/yad-checks/templates/hooks/yad-capture.mjs +117 -0
  75. package/skills/yad-commit/SKILL.md +18 -7
  76. package/skills/yad-connect-design/SKILL.md +1 -1
  77. package/skills/yad-connect-design/references/design-registry.md +1 -1
  78. package/skills/yad-connect-docs/SKILL.md +16 -11
  79. package/skills/yad-connect-docs/references/docs-registry.md +8 -8
  80. package/skills/yad-connect-learning/SKILL.md +1 -1
  81. package/skills/yad-connect-learning/references/learning-registry.md +1 -1
  82. package/skills/yad-connect-repos/SKILL.md +31 -8
  83. package/skills/yad-connect-repos/references/code-context.md +1 -1
  84. package/skills/yad-connect-repos/references/{hub-config.md → product-config.md} +19 -11
  85. package/skills/yad-connect-repos/references/repos-registry.md +1 -1
  86. package/skills/yad-connect-testing/SKILL.md +1 -1
  87. package/skills/yad-connect-testing/references/testing-registry.md +1 -1
  88. package/skills/yad-discovery/SKILL.md +4 -3
  89. package/skills/yad-discovery/references/discovery-schema.md +1 -1
  90. package/skills/yad-docs/SKILL.md +1 -1
  91. package/skills/yad-docs/references/data-mapping.md +1 -1
  92. package/skills/yad-docs/templates/app/package-lock.json +8 -8
  93. package/skills/yad-docs/templates/app/package.json +1 -1
  94. package/skills/yad-docs/templates/app/src/components/Canvas/FlowCanvas.tsx +2 -2
  95. package/skills/yad-docs-overview/references/pipeline-model.md +3 -3
  96. package/skills/yad-engineer-review/SKILL.md +2 -2
  97. package/skills/yad-engineer-review/references/ship-and-record.md +3 -3
  98. package/skills/yad-epic/SKILL.md +11 -6
  99. package/skills/yad-epic/references/state-schema.md +25 -17
  100. package/skills/yad-open-pr/SKILL.md +1 -1
  101. package/skills/yad-pair-review/SKILL.md +5 -5
  102. package/skills/yad-pair-review/references/session-state.md +2 -2
  103. package/skills/yad-pr-template/SKILL.md +14 -12
  104. package/skills/yad-pr-template/templates/checks/pr-template.sh +28 -17
  105. package/skills/yad-pr-template/templates/checks/pr-title.sh +25 -14
  106. package/skills/yad-pr-template/templates/{hub → product}/github/pull_request_template.md +2 -2
  107. package/skills/yad-pr-template/templates/{hub → product}/gitlab/merge_request_templates/Default.md +2 -2
  108. package/skills/{yad-hub-bridge → yad-product-bridge}/SKILL.md +17 -16
  109. package/skills/{yad-hub-bridge → yad-product-bridge}/references/bridge.md +15 -10
  110. package/skills/{yad-hub-bridge → yad-product-bridge}/references/login-roster.md +2 -2
  111. package/skills/{yad-hub-bridge/templates/checks/hub-route.sh → yad-product-bridge/templates/checks/product-route.sh} +2 -2
  112. package/skills/{yad-hub-bridge → yad-product-bridge}/templates/github/yad-gate-sync.yml +29 -16
  113. package/skills/{yad-hub-bridge → yad-product-bridge}/templates/gitlab/gitlab-ci.include-root.yml +1 -1
  114. package/skills/{yad-hub-bridge → yad-product-bridge}/templates/gitlab/yad-gate-sync.gitlab-ci.yml +5 -3
  115. package/skills/yad-report/SKILL.md +1 -1
  116. package/skills/yad-review-companion/SKILL.md +3 -3
  117. package/skills/yad-review-gate/SKILL.md +97 -107
  118. package/skills/yad-review-gate/references/gating.md +20 -18
  119. package/skills/yad-run/SKILL.md +2 -2
  120. package/skills/yad-run/references/run-loop.md +2 -2
  121. package/skills/yad-spec/SKILL.md +2 -1
  122. package/skills/yad-spec/references/spec-handoff.md +19 -10
  123. package/skills/yad-status/SKILL.md +7 -0
  124. package/skills/yad-stories/SKILL.md +5 -4
  125. package/skills/yad-sync-repos/SKILL.md +19 -3
  126. package/skills/yad-test-cases/SKILL.md +5 -4
  127. package/skills/yad-ui/SKILL.md +6 -4
  128. package/skills/yad-checks/templates/hooks/ledger-guard-cursor.sh +0 -91
  129. package/skills/yad-checks/templates/hooks/ledger-guard.sh +0 -100
package/CHANGELOG.md CHANGED
@@ -1,3 +1,226 @@
1
+ # [4.0.0-next.4](https://github.com/abdelrahmannasr/yadflow/compare/v4.0.0-next.3...v4.0.0-next.4) (2026-09-30)
2
+
3
+
4
+ * feat!: print Product, not hub, in output, --json and commit subjects (E124) ([b982530](https://github.com/abdelrahmannasr/yadflow/commit/b982530402dde171575407e82e72b8a2c405639a))
5
+ * feat!: read product.json first, and refuse two names that disagree (E122) ([2252296](https://github.com/abdelrahmannasr/yadflow/commit/22522969823c8a3525fa255c62a7a08c444b7450))
6
+ * feat!: rename the installed hub names to product, and name what is left (E123) ([91c62b6](https://github.com/abdelrahmannasr/yadflow/commit/91c62b6467d220a13b88970fd16b7bd42d740ffc))
7
+
8
+
9
+ ### Bug Fixes
10
+
11
+ * a broken shared registry never stops a join, and the .git check reads names as Windows does (E79 review 4) ([160ec83](https://github.com/abdelrahmannasr/yadflow/commit/160ec83512df1f6f50245f0f0f2714e7c3588230))
12
+ * a copyable hint never prints a registry name that starts with - (E81 review 10) ([8caa29d](https://github.com/abdelrahmannasr/yadflow/commit/8caa29d752d843f0ec16c1a79a030e532076cb73))
13
+ * a monorepo subfolder is present, refresh keeps to code-context, null entries are named (E81 review 1) ([f899a0d](https://github.com/abdelrahmannasr/yadflow/commit/f899a0dcb37f4f71851802c700ba02f9d2ed39c4))
14
+ * a workspace file sends only the Product's own registered repos to it, and stops the walk when it is not used (E80 review 1) ([2a01287](https://github.com/abdelrahmannasr/yadflow/commit/2a01287bb7fc30f4d2dc604273691ba20aec97e7))
15
+ * a worktree or nested repo inside a registered repo is its own checkout, never swapped for the repo's (E80 review 3) ([de05ebd](https://github.com/abdelrahmannasr/yadflow/commit/de05ebd33b5a21fe0c0d689fd9190ab99f4293c7))
16
+ * allow % in a URL's user and password for https only (E81 review 7) ([b1f05e4](https://github.com/abdelrahmannasr/yadflow/commit/b1f05e42453da655b0644032503fc4b6bec59db2))
17
+ * allow the file transport per URL, not per run (E81 review 4) ([fd88947](https://github.com/abdelrahmannasr/yadflow/commit/fd889479c6c99b3dbd6ac20ad0cfbdf592ec641d))
18
+ * an unreadable record is its own gate state, and the advice reads as steps (E124 review 5) ([8608e8e](https://github.com/abdelrahmannasr/yadflow/commit/8608e8ea6994607f3da8fef65b355823da257738))
19
+ * **checks:** a kept Product is read only when product-repo reaches nothing (E117) ([434f0c0](https://github.com/abdelrahmannasr/yadflow/commit/434f0c03d0ade65ec90f375e95cc129b59f97571))
20
+ * **checks:** a link.md's epic must be its story's own (E118) ([4f09325](https://github.com/abdelrahmannasr/yadflow/commit/4f09325f6e168db74ccc222ba0d8fc7feea30381))
21
+ * **checks:** a Product path starting with - is still walked twice (E117) ([a823dd5](https://github.com/abdelrahmannasr/yadflow/commit/a823dd56e8c13a7d94fb6874a21539fa286d97ec))
22
+ * **checks:** backfill-check folds every character a Mac folds into ASCII (E116) ([e913baa](https://github.com/abdelrahmannasr/yadflow/commit/e913baaf6c68e171e2e06f139c6b25bac9732b79))
23
+ * **checks:** backfill-check folds the Kelvin sign into k (E116) ([c5152c3](https://github.com/abdelrahmannasr/yadflow/commit/c5152c350ab1dd89e6906eac9433316be5ecf261))
24
+ * **checks:** backfill-check lists go through the stream, not the environment (E116) ([f2366f0](https://github.com/abdelrahmannasr/yadflow/commit/f2366f0c1433a05bae614956b66326223f2e51ab))
25
+ * **checks:** backfill-check pairs raw records, frees twins, checks links when specs are hidden (E116) ([6544926](https://github.com/abdelrahmannasr/yadflow/commit/654492634f9f65dbe702701ddaf8af038ba2beae))
26
+ * **checks:** backfill-check reads each spec by its object id (E116) ([6e44ae5](https://github.com/abdelrahmannasr/yadflow/commit/6e44ae576d547333bc1a256a1a3e473f8ddc5e1f))
27
+ * **checks:** backfill-check reads every spelling of the verified key (E116) ([81588e6](https://github.com/abdelrahmannasr/yadflow/commit/81588e62d71c60174fe678a8756d1a0806388554))
28
+ * **checks:** backfill-check reads the last verified: key, as YAML does (E116) ([36cb5cd](https://github.com/abdelrahmannasr/yadflow/commit/36cb5cda6a817b6a4d3504052058fa26c6eefb9d))
29
+ * **checks:** backfill-check reads the spec from the base and refuses links (E116) ([b63f5ac](https://github.com/abdelrahmannasr/yadflow/commit/b63f5ac706cd6155b5db63ffaf258dcd11d4269d))
30
+ * **checks:** close the gaps review 1 found in the Product and epic reads (E117, E118) ([a8d8178](https://github.com/abdelrahmannasr/yadflow/commit/a8d81780c35a651e30e51e5dcc0e30252ac50205))
31
+ * **checks:** close the gaps review 2 found in the Product reads (E117, E118) ([dcc5ea5](https://github.com/abdelrahmannasr/yadflow/commit/dcc5ea5667be4c52676656aef5723813edce4857))
32
+ * **checks:** close the gaps review 3 found in the Product reads (E117) ([fbb0768](https://github.com/abdelrahmannasr/yadflow/commit/fbb076848e5c1ba7f67ad34ff5d7b5b7d5d094e7))
33
+ * **checks:** compare the git folder as a folder, not a spelling (E117) ([2a824a8](https://github.com/abdelrahmannasr/yadflow/commit/2a824a83b4f8eb0129b1275ec8b45832d5f22d87))
34
+ * **checks:** contract-check fails a first spec whose product-repo reaches nothing (E119) ([a4738fc](https://github.com/abdelrahmannasr/yadflow/commit/a4738fce11d4b2e87ef6d03bcea865d22feb52dc))
35
+ * **checks:** contract-check folds every character a Mac folds into ASCII (E121) ([8422e70](https://github.com/abdelrahmannasr/yadflow/commit/8422e70e192f15c26053a94ccbf2ecb8c658d720))
36
+ * **checks:** read every NUL list with a newline in a name as ? (E121) ([2659211](https://github.com/abdelrahmannasr/yadflow/commit/2659211c94a28d52c7a25a956d8c75bab1dd61ec))
37
+ * **checks:** refuse a Product path inside the repo's own .git (E117) ([b726032](https://github.com/abdelrahmannasr/yadflow/commit/b7260323e1aebab247ad6367ea2bd1c6a6d4756d))
38
+ * **checks:** the first-spec FAIL fires only when the Product is not reached (E119) ([322ffe3](https://github.com/abdelrahmannasr/yadflow/commit/322ffe39fd2654aae5022898db3d3f71bd1d4f11))
39
+ * **checks:** the PR no longer chooses where the Product is read from (E117) ([68db03b](https://github.com/abdelrahmannasr/yadflow/commit/68db03b61269346a9c540f7fa39d4b37648f627b))
40
+ * **checks:** walk the Product path again from where it really lands (E117) ([1b0726d](https://github.com/abdelrahmannasr/yadflow/commit/1b0726d04a83544beef2bdfd3aac32f395d373bd))
41
+ * **ci:** Pages write scopes move to the job; one pin per action major (review 1) ([92a51fe](https://github.com/abdelrahmannasr/yadflow/commit/92a51febd1146c7f90528855d67cfa8d1be81255))
42
+ * **ci:** pin every workflow action by commit SHA and make the default token read-only ([43254bb](https://github.com/abdelrahmannasr/yadflow/commit/43254bba2c5606831ba7328896326c83c3dd4a3e))
43
+ * clean every printed path, one wording for the quote, and the door works from a Product subfolder (E49 review 2) ([85ea6a4](https://github.com/abdelrahmannasr/yadflow/commit/85ea6a4f5e99942aba7dd28fdd05605319cc241c))
44
+ * clone a registered repo only from a network address (E81 review 3) ([1582784](https://github.com/abdelrahmannasr/yadflow/commit/15827845f14329d1d592a01d68b8f3a9b122e19c))
45
+ * close the last one-key product.json hints, and refuse before touching .gitignore (E122 review 3) ([2b10f5b](https://github.com/abdelrahmannasr/yadflow/commit/2b10f5bd7568c5121adf72d5ab1f6e832c1029f9))
46
+ * **docs:** raise the docs shell version to 0.0.2 for the brace-expansion bump ([74498a5](https://github.com/abdelrahmannasr/yadflow/commit/74498a545b96923b5096b7adf06631e96ae7e616))
47
+ * **doctor:** ask for --overwrite-local only when a plain --fix would not do (E120 review 8) ([5950b89](https://github.com/abdelrahmannasr/yadflow/commit/5950b89def883390bafc0c3922ce4ad65d2f3131))
48
+ * **doctor:** decide the record's ahead/behind state by git, in one table (E120 review 5) ([1739cc5](https://github.com/abdelrahmannasr/yadflow/commit/1739cc5afff34d638376215c6da90d58aaf191bb))
49
+ * **doctor:** judge an off-branch clone's record as it will be after the switch (E120 review 9) ([39025bd](https://github.com/abdelrahmannasr/yadflow/commit/39025bd09c92870aacdcacca38cb3906c29da502))
50
+ * **doctor:** name `gate repair --push` for a stranded step on a verified Product (E48 review 3) ([29f0340](https://github.com/abdelrahmannasr/yadflow/commit/29f0340be0d0bef0f5e3d40a18d0da645e352b80))
51
+ * **doctor:** name a product-link record committed but never pushed (E120 review 3) ([4db532a](https://github.com/abdelrahmannasr/yadflow/commit/4db532a2712670e63f6caba85aeffd108ee63030))
52
+ * **doctor:** no silence over a broken record, and hints that work off the default branch (E120 review 6) ([97c714b](https://github.com/abdelrahmannasr/yadflow/commit/97c714b66429f3a9731fd0d853ab20fcaaff75f4))
53
+ * **doctor:** one clear step per repo in the product-link hint (E120 review 7) ([c117c3d](https://github.com/abdelrahmannasr/yadflow/commit/c117c3d2aa737df27c2a3167e2001dd8454654aa))
54
+ * **doctor:** tell unpushed, on another branch and behind apart (E120 review 4) ([9356748](https://github.com/abdelrahmannasr/yadflow/commit/935674881340e9c47aaba04b77196b343368cd64))
55
+ * drop the exact registry path from the warning, and clean C1 control characters too (E79 review 7) ([c70911c](https://github.com/abdelrahmannasr/yadflow/commit/c70911c5e199b2433325e3a4996b3fe240be42ad))
56
+ * **e120:** a record is ok only when committed as it stands (review 2) ([f2fc7de](https://github.com/abdelrahmannasr/yadflow/commit/f2fc7dec1435d009ead6966c831d4aa409871306))
57
+ * **e120:** a record right on disk reads ok, and --push still commits it (CI) ([a5cd7f5](https://github.com/abdelrahmannasr/yadflow/commit/a5cd7f541283a6715cc012bd57194f0684e2cdc8))
58
+ * **e120:** commit the record for sure, keep secrets out, keep local runs checking ([e96ed5d](https://github.com/abdelrahmannasr/yadflow/commit/e96ed5dc8b87938097fb35270d4b677c456377e3))
59
+ * every doctor command to copy takes registry text as one plain word (E81 review 11) ([e2d147a](https://github.com/abdelrahmannasr/yadflow/commit/e2d147addb163f5397b054f1e84b506b1732668c))
60
+ * **hook:** fail open under sh -e, follow no GIT_DIR, and name the repair that commits (E48 review 1) ([2991086](https://github.com/abdelrahmannasr/yadflow/commit/29910861d1c76763f765b2483ea412e8eba5d899))
61
+ * **hooks:** advice for a stuck old entry that is true in every case (E113 review 7) ([6d7fff1](https://github.com/abdelrahmannasr/yadflow/commit/6d7fff14a4a3d5bd1cb99b5bd0484cd292a0f109))
62
+ * **hooks:** give a local-ledger guard entry advice that works at apply too (E113 review 6) ([d26b241](https://github.com/abdelrahmannasr/yadflow/commit/d26b241af186961a40ca50dac289e3d6e230e1f8))
63
+ * **hooks:** judge an old hook script against the files as this run leaves them (E113 review 2) ([9a5df22](https://github.com/abdelrahmannasr/yadflow/commit/9a5df224c6e7322a6aebcc9a78b57afee1a2f59a))
64
+ * **hooks:** keep an old hook script until its new entry is committed (E113 review 1) ([c4fb5b3](https://github.com/abdelrahmannasr/yadflow/commit/c4fb5b37e3171604be7376e793cebd0eb194f14b))
65
+ * **hooks:** name what keeps an old hook script, and read HEAD once (E113 review 3) ([f1b95fc](https://github.com/abdelrahmannasr/yadflow/commit/f1b95fc2f135c5f4572d9e21b32e614a1ef77565))
66
+ * **hooks:** one sentence of advice for a stuck old hook entry, at plan and apply (E113 review 5) ([ab22b93](https://github.com/abdelrahmannasr/yadflow/commit/ab22b9348b659130fc1237786a4d6766919a580f))
67
+ * **hooks:** tell a capture-off Product to remove a stuck capture entry (E113 review 8) ([353053a](https://github.com/abdelrahmannasr/yadflow/commit/353053a017c5a0dad46c881abead93d65a9a704b))
68
+ * **hooks:** tell a local-ledger Product to remove a stuck guard entry (E113 review 4) ([0e1eaa5](https://github.com/abdelrahmannasr/yadflow/commit/0e1eaa5009f8cd06c39832faa9642ece7881e17b))
69
+ * **hook:** the agent's refusal gets the same fixes, and doctor names a hook git skips (E48 review 2) ([9551b1a](https://github.com/abdelrahmannasr/yadflow/commit/9551b1a4166bd4174a6a35f6655bbf5e805d3b90))
70
+ * join stays inside the workspace on disk, one bad entry fails alone, and init never takes over a code repo (E79 review 1) ([56f14ae](https://github.com/abdelrahmannasr/yadflow/commit/56f14ae7f90f4eddd6618bcf6a6f7e23947e850e))
71
+ * keep every URL form's host and user to safe characters (E81 review 6) ([61370c2](https://github.com/abdelrahmannasr/yadflow/commit/61370c28a911f4d39223a6eee2df6affc27415d7))
72
+ * keep the rename's own error when writeJSON's cleanup fails (E81 review 20) ([d5b860f](https://github.com/abdelrahmannasr/yadflow/commit/d5b860f66fce3e0c99739327e8662af49ba2fed7))
73
+ * keep writeJSON's own error when the temp cleanup fails (E81 review 19) ([b8d7640](https://github.com/abdelrahmannasr/yadflow/commit/b8d7640abc5b6fde91ef0c45a05e976c134912b4))
74
+ * ledger-guard reads a missing settings file quietly, and the roster hints name the file (E122 review 5) ([d00a117](https://github.com/abdelrahmannasr/yadflow/commit/d00a117d6cd535255b44b0ec3e61a38aa1774169))
75
+ * name a repos.json that does not parse instead of joining with no repos (E79 review 5) ([4a952e2](https://github.com/abdelrahmannasr/yadflow/commit/4a952e2dd80ea36b33aaa37c051da1f702980585))
76
+ * name the file in the last settings hints, refuse a pair that changed, and silence a missing settings file (E122 review 4) ([5aed634](https://github.com/abdelrahmannasr/yadflow/commit/5aed63409178e36954240e37ee11e53b1ab95e04))
77
+ * name the Product from the workspace folder instead of offering a second one, and match paths as the disk stores them (E80 review 2) ([71369b3](https://github.com/abdelrahmannasr/yadflow/commit/71369b3565d273ad6a2f6eb3bd3caa8f685e75f5))
78
+ * name the settings file a person should edit, and settle all pairs or none (E122 review 2) ([ccb8de4](https://github.com/abdelrahmannasr/yadflow/commit/ccb8de49a48397c14446faebf8c3d7ef1222abd5))
79
+ * name the settings file actually read, and keep risk-map advisory (E122 review 1) ([ab4fddc](https://github.com/abdelrahmannasr/yadflow/commit/ab4fddc495433cff0d013742f02086bea94b00a9))
80
+ * name the settings file on disk, and restore the old-name fallback (E124 review 1) ([cf24871](https://github.com/abdelrahmannasr/yadflow/commit/cf248716935eaebc9961ae8e9f8d8b27a123a9d0))
81
+ * never build a login command from a host that is not a plain host name (E81 review 13) ([0a09dc1](https://github.com/abdelrahmannasr/yadflow/commit/0a09dc11e047e483ea046720a9e505078e815ae5))
82
+ * never clone or register a repo path through a .git folder, and say what --dir is for each workspace verb (E79 review 2) ([6be43a2](https://github.com/abdelrahmannasr/yadflow/commit/6be43a274b392c405454d1a09d4f49143257d100))
83
+ * never write over an edited new name, keep one workflow running, and name a gate that rejects product (E123 review 1) ([d7dc72b](https://github.com/abdelrahmannasr/yadflow/commit/d7dc72bf0857ceda09db081be1b95647a20334c2))
84
+ * one plainHost test for every login command doctor prints (E81 review 14) ([8a25d94](https://github.com/abdelrahmannasr/yadflow/commit/8a25d947353538ce7b0ffe0f399d08082e791bab))
85
+ * one samePath for a git path against a Node path, and survive a missing .git/hooks (E48 review 5) ([156ec1e](https://github.com/abdelrahmannasr/yadflow/commit/156ec1e4d9d19e5cd22e454432b1eece6fac6ced))
86
+ * one terminal cleaner for every module that prints registry text (E81 review 12) ([805a4fd](https://github.com/abdelrahmannasr/yadflow/commit/805a4fd200c2465f9a491f44e81b60ed50605946))
87
+ * only the ledger door runs from a subfolder, and the sha — not an indent — keeps :: off a line (E49 review 3) ([9878423](https://github.com/abdelrahmannasr/yadflow/commit/987842384792905cbc15db429d5d3e3da76033e4))
88
+ * read any spelling of the profile mapping and branch, and never a comment (E123 review 3) ([67c3a55](https://github.com/abdelrahmannasr/yadflow/commit/67c3a559ae95dae1abae8f4561d5e04b073eca02))
89
+ * record the new name a kept rename installs, and say a profile gap only when it bites (E123 review 2) ([9c99014](https://github.com/abdelrahmannasr/yadflow/commit/9c990145a68596dddfa4c2534afae18f3615efda))
90
+ * refresh never writes through a .gitignore the Product commits as a link (E81 review 16) ([5d9a982](https://github.com/abdelrahmannasr/yadflow/commit/5d9a9822d73376c5f83a6fe880dd52adf075e67a))
91
+ * refresh stops at a linked .sdlc, --push included (E81 review 18) ([e79d64c](https://github.com/abdelrahmannasr/yadflow/commit/e79d64c503d3d96e8f1005b1560d4e815ecf2820))
92
+ * refuse a clone target with a link on its way, so a committed link cannot reach .git (E79 review 3) ([667d696](https://github.com/abdelrahmannasr/yadflow/commit/667d6964e9ceed75ce0ea1fb82b03d6cf7c324ea))
93
+ * refuse a control character anywhere in a registered git_url (E81 review 8) ([6edf593](https://github.com/abdelrahmannasr/yadflow/commit/6edf5937a094a827faf02454fa2f54803b0f2cd4))
94
+ * refuse any folder holding HEAD on the way to a registered subfolder (E81 review 2) ([0471334](https://github.com/abdelrahmannasr/yadflow/commit/04713341b8b3ea5ee55d59da82b9f818d6bfe2df))
95
+ * refuse encoded C1 and bidi characters; clean the last raw registry text (E81 review 9) ([7f7721b](https://github.com/abdelrahmannasr/yadflow/commit/7f7721b636fc19ed4736c6962ae3cd67726c3007))
96
+ * **release:** install an exact npm version, not npm@latest ([0bf8981](https://github.com/abdelrahmannasr/yadflow/commit/0bf89817da64f43f91fc281d42f76883c0f1a1ef))
97
+ * **setup:** compare hook folders by their long name on Windows (E48) ([8f1ac56](https://github.com/abdelrahmannasr/yadflow/commit/8f1ac5617cf50b89ca8626e5d15ec645b2ff64a5))
98
+ * **setup:** read a core.hooksPath typed in another case as the default folder where the disk ignores case (E48 review 6) ([997f77d](https://github.com/abdelrahmannasr/yadflow/commit/997f77d39d76c49a7e5b63845c867484fb180437))
99
+ * **skills:** yad-connect-repos frontmatter parses; two descriptions fit 1024 ([d6eaf55](https://github.com/abdelrahmannasr/yadflow/commit/d6eaf558d8296dbedacab3c70f9075d497222d56))
100
+ * the --profile hub advice names every gate in the way, in every state (E124 review 4) ([5d125ec](https://github.com/abdelrahmannasr/yadflow/commit/5d125ece69967c3c76d923da2c05decd1c500140))
101
+ * the --profile hub advice reads each gate's real state (E124 review 3) ([f00c51e](https://github.com/abdelrahmannasr/yadflow/commit/f00c51e7a4ec54bb6c126797478088c06365d746))
102
+ * the --profile hub advice waits for a gate that refuses product, and a repo named product is shown by its path (E124 review 2) ([80518c5](https://github.com/abdelrahmannasr/yadflow/commit/80518c5cbd3af2209882167bb381731190d2336a))
103
+ * the clone sets GIT_ALLOW_PROTOCOL; a local source must exist (E81 review 5) ([7963220](https://github.com/abdelrahmannasr/yadflow/commit/796322023a6bc90b541f66b3c383e34b1957c791))
104
+ * the drift advice names yad migrate --apply, and one drift lookup serves all (review 1) ([f158fa1](https://github.com/abdelrahmannasr/yadflow/commit/f158fa1f8311a71e5346dbd51ee6627a231b3dae))
105
+ * the ledger override claims only what it can see, and no control character reaches the CI log (E49 review 1) ([da7a6d9](https://github.com/abdelrahmannasr/yadflow/commit/da7a6d96cf762e7d23f5f4ae3c44c5c2e9dc195d))
106
+ * the solo people count judges each registered path before git runs (E81 review 15) ([993698a](https://github.com/abdelrahmannasr/yadflow/commit/993698a17f2496985da6b8c6160c2e9eeba83449))
107
+ * the unreadable-registry warning gives the real reason, and a null registry is named too (E79 review 6) ([9f426eb](https://github.com/abdelrahmannasr/yadflow/commit/9f426eb3697e473bde80468e0be5946de4041404))
108
+ * the unreadable-settings cell says only what is true (E124 review 6) ([5d43189](https://github.com/abdelrahmannasr/yadflow/commit/5d431894e377065ca1d26316973fd6cfabc7d3c9))
109
+ * when a file's two names disagree, the gate advice says yad migrate first (E124 follow-up) ([75d2184](https://github.com/abdelrahmannasr/yadflow/commit/75d2184480acc0d285d7718533ab9bf9d65cf723))
110
+ * writeJSON's temp file is random and exclusive (E81 review 17) ([b5cbcd9](https://github.com/abdelrahmannasr/yadflow/commit/b5cbcd935a81534b5f749eeba13c36711fb7a471))
111
+
112
+
113
+ ### Documentation
114
+
115
+ * the guides, sites and diagram say Product, and a guide to the hand changes (E124) ([883cd6f](https://github.com/abdelrahmannasr/yadflow/commit/883cd6f56378dc58bbbd1a9ebdba0048a1e35c9a))
116
+
117
+
118
+ ### Features
119
+
120
+ * .yad-workspace.json — yad finds the Product from any repo in the workspace (E80) ([27a7579](https://github.com/abdelrahmannasr/yadflow/commit/27a75793c558d597840d01c9f7986e25e7a5c42a))
121
+ * **checks:** check the Product out in CI where the record says (E120) ([b288326](https://github.com/abdelrahmannasr/yadflow/commit/b288326da2a72c3475d0cfafd2f8bc9540d0670d))
122
+ * **checks:** read where the Product lives from .sdlc/product-link.json on the base (E120) ([6b9e7b1](https://github.com/abdelrahmannasr/yadflow/commit/6b9e7b1f293183b89fda9d1aa9b748bcd62bb7f6))
123
+ * **commit:** yad commit --manual --reason, the door past the ledger hook (E49) ([5b4081a](https://github.com/abdelrahmannasr/yadflow/commit/5b4081a5bea4423c90b41a5ad676e0c5987bf0d9))
124
+ * **doctor:** warn checks:backfill-blind for an older backfill-check (E116) ([bfb82cf](https://github.com/abdelrahmannasr/yadflow/commit/bfb82cf2e0d956165c179a92a0e09fb46e8e97f9))
125
+ * **hook:** refuse a hand commit to the CI-owned ledger with a git pre-commit hook (E48) ([e2258b1](https://github.com/abdelrahmannasr/yadflow/commit/e2258b14f9c35af5057e109713c6407fae50b068))
126
+ * **hooks:** run the agent hooks as Node scripts, so Windows works without WSL (E113) ([887ceea](https://github.com/abdelrahmannasr/yadflow/commit/887ceeadabdb4f20482c3f3a5d29963c5fe74cc8))
127
+ * **repos:** write each code repo's product-link record, and warn when it is missing (E120) ([54f1fe3](https://github.com/abdelrahmannasr/yadflow/commit/54f1fe382d884aa2e72bb56c26197dd3e8e3c5c0))
128
+ * tell a repo named product apart, and name --profile hub in the team's workflows (E124 review 1) ([98fc15d](https://github.com/abdelrahmannasr/yadflow/commit/98fc15d345354c0df83ceae7d7aa4db5765c02b2))
129
+ * yad new, yad init and yad join — the three ways into a workspace (E79) ([dcccf67](https://github.com/abdelrahmannasr/yadflow/commit/dcccf670ffb4cb376aba6af26e602140328c00ea))
130
+ * yad repo clone fetches registered repos missing on this machine (E81) ([8a20504](https://github.com/abdelrahmannasr/yadflow/commit/8a20504f816ec556e55ec5db41b8f4350973e283))
131
+
132
+
133
+ ### BREAKING CHANGES
134
+
135
+ * after `yad update` renames the installed CI names, a
136
+ team's own files that name the old ones must be changed by hand — GitLab
137
+ `needs:` / `dependencies:` / `extends:` / `!reference` naming a
138
+ `yad-hub-*` job, GitHub `workflow_run:` triggers naming `yad-hub-checks`,
139
+ status badges, CODEOWNERS lines, and scripts that read `--json` names or
140
+ `SDLC_HUB_CONFIG` / `.sdlc/hub.json`. Every case, with a before and
141
+ after: docs/migrations/hub-to-product.md.
142
+ * `--json` names that said `hub` now say `product`, and
143
+ `jsonVersion` is 2. `yad doctor` check ids `hub`, `hub-git-url` and
144
+ `ci-tags:hub` are `product`, `product-git-url` and `ci-tags:product`;
145
+ `yad open-pr` answers `baseSource: "product"` and `stage:
146
+ "product-shape" | "product-tooling"`; `yad check` / `yad update` answer
147
+ `items[].scope: "product"` and `commits[].label: "product"`; and
148
+ `yad history show` answers `productConfigWhy` where it answered
149
+ `hubWhy`. The audit commits are `chore(product): …`. See the
150
+ "What moved in jsonVersion 2" table in docs/CLI.md.
151
+ * `yad update` renames the Product's
152
+ .github/workflows/yad-hub-checks.yml and .gitlab/ci/yad-hub-checks.yml to
153
+ yad-product-checks.yml, the GitLab jobs yad-hub-* to yad-product-*, and
154
+ the yad-hub-bridge skill to yad-product-bridge. GitHub job names (the
155
+ required checks) do not change. Your own CI that names an old name — a
156
+ GitLab needs:/dependencies:/extends:/!reference, a GitHub workflow_run:
157
+ trigger on yad-hub-checks, a status badge, a CODEOWNERS line — must be
158
+ changed by hand; `yad doctor` lists each by file and line (renamed-ref:).
159
+ * yadflow 4 reads .sdlc/product.json (and each epic's
160
+ product-prs.json) first; .sdlc/hub.json and hub-prs.json are read only when the
161
+ new name is absent, are still written until 5.0, and are deleted in 5.0. This
162
+ corrects docs/migrations/shape-3.md and the 4.0.0-next.1 notes, which said the
163
+ old names stay the ones read for another major. When both names exist and say
164
+ different things, every command refuses (YAD-STATE-008) and the gates fail;
165
+ run `yad migrate` to see the difference and `yad migrate --apply` (or
166
+ `--apply --keep product|hub`) to choose. Edit settings by hand in
167
+ .sdlc/product.json, then run `yad migrate --apply --keep product`. Gates now
168
+ honour SDLC_PRODUCT_CONFIG before SDLC_HUB_CONFIG.
169
+
170
+ # [4.0.0-next.3](https://github.com/abdelrahmannasr/yadflow/compare/v4.0.0-next.2...v4.0.0-next.3) (2026-09-26)
171
+
172
+
173
+ ### Bug Fixes
174
+
175
+ * **test:** strip the publisher's git identity from the whole test process ([8660f56](https://github.com/abdelrahmannasr/yadflow/commit/8660f5611f1c9f24a67eeead4302c4acca260ba3))
176
+
177
+ # [4.0.0-next.2](https://github.com/abdelrahmannasr/yadflow/compare/v4.0.0-next.1...v4.0.0-next.2) (2026-09-26)
178
+
179
+
180
+ ### Bug Fixes
181
+
182
+ * **capture:** continue origin's branch when there is no local one; name a refused push (E43 review 2) ([8e2c07d](https://github.com/abdelrahmannasr/yadflow/commit/8e2c07d32d1b6882c7b543b9b3c65f96ca67e919))
183
+ * **capture:** every git call takes the environment runCapture was given (E43) ([c347c94](https://github.com/abdelrahmannasr/yadflow/commit/c347c9460154e6b30472a3a1aae2869354a6fce4))
184
+ * **capture:** prune deleted capture branches; read [a-z] and list brackets as GitHub does (E43 review 3) ([2322dcb](https://github.com/abdelrahmannasr/yadflow/commit/2322dcb0321ff02f0ebf22ecfe61b2979236944d))
185
+ * **capture:** subfolder Products, staged-then-deleted files, a plain push, and a truer workflow scan (E43 review) ([14f0eeb](https://github.com/abdelrahmannasr/yadflow/commit/14f0eeb6e5fe9ce21bdfe5fb168ace88a41d7ad6))
186
+ * **capture:** take design-links.json and test-links.json with the artifacts (E44) ([ad4f2cf](https://github.com/abdelrahmannasr/yadflow/commit/ad4f2cfc1f134c3b17616348081795a09939049a))
187
+ * **checks:** a C-quoted path is an artifact change; warn on a rename-blind workflow (E47 review 4) ([e6af8df](https://github.com/abdelrahmannasr/yadflow/commit/e6af8df0f4dafd3ec593da44114b07c45b67f54a))
188
+ * **checks:** E114 review 1 — one odd name per test, split lines, full hint ([df9f4dc](https://github.com/abdelrahmannasr/yadflow/commit/df9f4dcaf5736bfbd93a49c017ffae257e2b4ef6))
189
+ * **checks:** fold the long s into specs; say a file is a file (E115 review 2) ([373ba16](https://github.com/abdelrahmannasr/yadflow/commit/373ba16c81bc3c0eb5c56bb7adae48441b4f07a8))
190
+ * **checks:** let a PR of step owner files alone through on a Product (E47 review 2) ([f7ff5b0](https://github.com/abdelrahmannasr/yadflow/commit/f7ff5b062a51b455a18190a31ccbd5488fe5785f))
191
+ * **checks:** list a rename by both paths in contract-check and backfill-check (E114) ([09bb4de](https://github.com/abdelrahmannasr/yadflow/commit/09bb4de3f36e0fec0eb247565fc2364a46b482b8))
192
+ * **checks:** list renames and unquoted paths in the hub-checks diff (E47 review 3) ([bc270e0](https://github.com/abdelrahmannasr/yadflow/commit/bc270e0583a7583ffccea94b9ecaa1a11498ec46))
193
+ * **checks:** read specs/ without case; name a failed tree read (E115 review 1) ([a9fb725](https://github.com/abdelrahmannasr/yadflow/commit/a9fb72599a5980e9f2e8307cb87eca9ae31f17ca))
194
+ * **checks:** read the changed list as bytes; check each workflow line (E47 review 5) ([edc850b](https://github.com/abdelrahmannasr/yadflow/commit/edc850b20495a13d376b6f01dc02db61658d4e27))
195
+ * **checks:** refuse a second spelling of contracts/ or a story folder (E115 review 3) ([debc7b6](https://github.com/abdelrahmannasr/yadflow/commit/debc7b68f8bbddf5634322228f633327aba8c50a))
196
+ * **checks:** refuse a symlink or submodule under specs/ in contract-check (E115) ([e93387a](https://github.com/abdelrahmannasr/yadflow/commit/e93387aa036cc40b9d6741291a1ef518a0d03e1b))
197
+ * **checks:** say what the story-spelling rule does not catch (E115 review 4) ([3d36c93](https://github.com/abdelrahmannasr/yadflow/commit/3d36c934406b148c3601c5a6bfdacd40abccbad3))
198
+ * **claims:** find the first capture's base in one git call, with no cap (E46 review 2) ([e4a6fcf](https://github.com/abdelrahmannasr/yadflow/commit/e4a6fcf2a33acba0c4b76b5ba54e99d740dcd1d7))
199
+ * **claims:** keep the once-an-hour memory across a push; own edits only; over-report a missing base (E46 review 1) ([7ab038d](https://github.com/abdelrahmannasr/yadflow/commit/7ab038d436fc9d46009fd31139bd7327083ebac3))
200
+ * **claims:** pin the first-capture search against the person's git config (E46 review 3) ([80db192](https://github.com/abdelrahmannasr/yadflow/commit/80db1926695f60884a47b6a72b5a79f634ac5519))
201
+ * **claims:** read the Yad-Base trailer with a pinned separator (E46 review 4) ([c026fef](https://github.com/abdelrahmannasr/yadflow/commit/c026fef2454f6a5799b6e0f8fe5a04ee6cbbad62))
202
+ * **doctor:** read a gate one bash command at a time (E114 review 2) ([06d3f69](https://github.com/abdelrahmannasr/yadflow/commit/06d3f69113e3b19f3b9cee1cf77a637999372775))
203
+ * **doctor:** satisfy eslint — split on ** instead of a NUL placeholder; no useless assignment (E43) ([aad5822](https://github.com/abdelrahmannasr/yadflow/commit/aad582240fa0b8f4a279b0221100fba967ced20d))
204
+ * **fold:** fold a staged deletion; refuse mid-merge and on a detached HEAD (E44 review 1) ([4391b1b](https://github.com/abdelrahmannasr/yadflow/commit/4391b1b1eb6d22990b672a0d3f64b5fb5e77c5ec))
205
+ * **fold:** name a case-only rename only when git shows the new spelling (E44 review 4) ([2a6395c](https://github.com/abdelrahmannasr/yadflow/commit/2a6395c7f9ae7c7d9ee8bf1877e4cb770b2197c0))
206
+ * **fold:** never run git add with an empty list; refuse a git rm --cached path (E44 review 2) ([cfbaefc](https://github.com/abdelrahmannasr/yadflow/commit/cfbaefc9d8334a20ddbd585b9c2c25a0d31992f7))
207
+ * **fold:** tell a case-only rename from git rm --cached (E44 review 3) ([a374fc3](https://github.com/abdelrahmannasr/yadflow/commit/a374fc314f266354cdf96200b54dfa631423d4c2))
208
+ * **fold:** the Product level is seeded under either spelling; truer words (E44 review 6) ([c711326](https://github.com/abdelrahmannasr/yadflow/commit/c71132643b8c3ca1fb1d0b5c3a4739d0b18209dd))
209
+ * **fold:** the verified seed rule asks ledger-guard's own question; a change-epic's seed rides along (E44) ([f0ee36d](https://github.com/abdelrahmannasr/yadflow/commit/f0ee36d60bad06ac0920b64d97bf16e9f19a7a06))
210
+ * **gate:** a round keeps the fingerprint it opened with; one spelling across approvals and comments (E112 review 2) ([d7dbe57](https://github.com/abdelrahmannasr/yadflow/commit/d7dbe57d507f5c798236715e55b70ef42f273dbe))
211
+ * **gate:** approve keeps the review record; one spelling per person; a round is one version (E112 review) ([6f44c18](https://github.com/abdelrahmannasr/yadflow/commit/6f44c1887ae2c846bdcd1c14cf276624a2be91b6))
212
+ * **owners:** never fold an owner file; name off-chain files in doctor (E47 review 1) ([f23f606](https://github.com/abdelrahmannasr/yadflow/commit/f23f606f220aef583500c6f2a632ee8927307b6c))
213
+
214
+
215
+ ### Features
216
+
217
+ * **capture:** yad capture snapshots Shape artifacts onto private yad/wip branches (E43) ([58b0181](https://github.com/abdelrahmannasr/yadflow/commit/58b0181f72fd88e97d391e0e52a46e8b5cdf1183))
218
+ * **claims:** yad claims — who else is editing which artifact, read from the capture branches (E46) ([6668441](https://github.com/abdelrahmannasr/yadflow/commit/66684416b5d3c1a2a04b069cd35b0d7f13e55ddb))
219
+ * **doctor:** warn when a step owner file does nothing (E47) ([b189abd](https://github.com/abdelrahmannasr/yadflow/commit/b189abdbc94aa0a36041d501b9cd09c5577d5a62))
220
+ * **fold:** yad fold <epic> <step> — one clean commit per authoring step (E44) ([a4a5285](https://github.com/abdelrahmannasr/yadflow/commit/a4a52857c2536b83d954e6a313863ecb16ecf01d))
221
+ * **gate:** yad gate approve, comment and advance for a Product with no platform (E112) ([50f7618](https://github.com/abdelrahmannasr/yadflow/commit/50f7618aae85fb269578055e5e12d33e58643fab))
222
+ * **owners:** assign an authoring step to one person (E47) ([f9f9bda](https://github.com/abdelrahmannasr/yadflow/commit/f9f9bdaf31206d8ac4c7d46b4d512f23b1e816d2))
223
+
1
224
  # [4.0.0-next.1](https://github.com/abdelrahmannasr/yadflow/compare/v3.19.0-next.2...v4.0.0-next.1) (2026-09-24)
2
225
 
3
226
 
package/README.md CHANGED
@@ -46,12 +46,20 @@ pass) · 🟦 **can run on auto** (a Build step the team may set to advance on i
46
46
 
47
47
  ## Quickstart
48
48
 
49
- From your **Product** repo (an empty git repo is fine):
49
+ Pick the way in that fits. A **workspace** is the folder that holds the Product (`product/`) and
50
+ your code repos side by side:
50
51
 
51
52
  ```bash
52
- npx yadflow setup # 1. guided wizard: install skills, connect repos, wire CI gates
53
+ npx yadflow new acme # 1a. new product: makes acme/product/, then runs the guided setup
54
+ npx yadflow init # 1b. repos you already have: run in the folder that holds them
55
+ npx yadflow join <url> # 1c. joining a team: clones the Product and every repo it registers
56
+ npx yadflow setup # or run the guided setup inside an existing Product repo
53
57
  ```
54
58
 
59
+ `new` creates nothing outside your machine — it prints the `gh`/`glab` line that puts the Product
60
+ online. `join` never commits or pushes; it only adds per-machine files. All three leave a small
61
+ `.yad-workspace.json` in the workspace, so `yad` finds the Product from any repo it registers.
62
+
55
63
  Then, in your AI IDE, drive the lifecycle by invoking skills by name:
56
64
 
57
65
  ```text
@@ -63,8 +71,20 @@ Every step stops at a gate until a human approves. New here? **Walk it lesson-by
63
71
  [guided tutorial](https://abdelrahmannasr.github.io/yadflow/tutorial/)**, or read the
64
72
  [team guide](TEAM-GUIDE.md).
65
73
 
66
- Running `yad` tells you when a new release is out — upgrade with `npm install yadflow -g`, then
67
- `yad update` to re-sync this project's skills. See [staying up to date](docs/CLI.md#staying-up-to-date).
74
+ Running `yad` tells you when a new release is out. To upgrade, run these in the Product:
75
+
76
+ ```bash
77
+ npm install -g yadflow # 1. install the latest release
78
+ yad migrate # 2. preview: which state files this release would rewrite (writes nothing)
79
+ yad migrate --apply # 3. rewrite them, keeping a <file>.yad-orig copy of each
80
+ yad update # 4. re-sync this project's skills, gate scripts and CI files
81
+ yad doctor # 5. confirm everything is healthy
82
+ ```
83
+
84
+ `yad migrate` moves your state files onto the file shape the new release expects. On a minor or patch
85
+ release it usually has nothing to do. Coming from 3.x? Read
86
+ [upgrading to 4.0](docs/migrations/upgrading-to-4.md) first. See also
87
+ [staying up to date](docs/CLI.md#staying-up-to-date).
68
88
  An update rewrites the files yad manages (gate scripts, CI, PR/MR templates) — but not one **you**
69
89
  edited: yad records the sha of every file it writes, so an edit to one is reported as `modified` and
70
90
  left alone. A file it has no record of (an install predating that record) is still replaced, but only
@@ -73,13 +93,26 @@ after saving a `.yad-orig` backup
73
93
 
74
94
  ## What `npx yadflow setup` installs
75
95
 
76
- ![npx yadflow setup — the guided wizard installs the yad-* skills, wires the CI gates, and stamps the .sdlc config](https://raw.githubusercontent.com/abdelrahmannasr/yadflow/main/docs/media/setup-wizard.gif)
96
+ ![yad new acme — makes acme/product/, runs the guided setup wizard (install the yad-* skills, record the Product, wire the gates, stamp the .sdlc config), then prints the commands that put the Product on GitHub or GitLab](https://raw.githubusercontent.com/abdelrahmannasr/yadflow/main/docs/media/setup-wizard.gif)
77
97
 
78
- The wizard is idempotent and profile-driven (solo/team, greenfield/brownfield, monorepo/separate).
98
+ The recording shows `yad new acme`, which runs this wizard inside the new `acme/product/`
99
+ ([how to re-record it](https://github.com/abdelrahmannasr/yadflow/blob/main/docs/media/setup-wizard.tape)). The wizard is idempotent and profile-driven (solo/team, greenfield/brownfield, monorepo/separate).
79
100
  In one pass it produces:
80
101
 
81
- - **The `yad` CLI** — zero-dependency Node (`setup`, `gate`, `commit`, `open-pr`, `ship`, `repo`,
82
- `thread`, `reconcile`, `usage`, `doctor`), run via `npx` or a global install.
102
+ - **The `yad` CLI** — zero-dependency Node, run via `npx` or a global install. The main groups:
103
+
104
+ | Group | Commands |
105
+ | --- | --- |
106
+ | Start a workspace | `new`, `init`, `join`, `setup` |
107
+ | Drive the lifecycle | `next`, `epic new`, `foundation`, `gate`, `skip` / `defer` / `unblock`, `mode`, `dial`, `kill` |
108
+ | Drafts and owners | `capture`, `claims`, `fold`, `assign` / `unassign` / `owners` |
109
+ | Build | `commit`, `open-pr`, `ship`, `review`, `checkpoint`, `tidy up` |
110
+ | Code repos | `repo` (`list`, `clone`, `refresh`, `sync`), `risk-map`, `codeowners` |
111
+ | Feature threads | `thread`, `reconcile` |
112
+ | Read the record | `history`, `index`, `usage`, `docs` |
113
+ | Keep healthy | `doctor`, `check`, `update`, `migrate`, `report` |
114
+
115
+ Every command, with its flags: [docs/CLI.md](docs/CLI.md#commands).
83
116
  - **38 workflow skills** installed into your AI assistant — Claude Code, Codex CLI, Cursor,
84
117
  Gemini CLI, GitHub Copilot, Zencoder and opencode. See
85
118
  [which agent reads which directory](#which-ai-agents-are-supported).
@@ -92,14 +125,24 @@ In one pass it produces:
92
125
  who has worked in that directory in the last 30 days), and the push-on-main **`yad-update-guard`** (which re-checks any direct-to-default commit — e.g. from
93
126
  `yad update --push` — with just `verified-commits` + `commit-message`), shipped as CI-agnostic bash
94
127
  under `checks/`.
95
- - **An agent guardrail** on a verified Product — `hooks/ledger-guard.sh`, a harness hook that refuses an
128
+ - **An agent guardrail** on a verified Product — `hooks/ledger-guard.mjs`, a harness hook that refuses an
96
129
  agent the CI-owned gate-ledger write at the moment it tries it and names the command that owns the
97
130
  transition, instead of letting it surface as a CI failure twenty minutes later. Harness-agnostic
98
- (stdin payload, exit 0 allows / 2 denies) and fails open — the CI gate stays the authority.
131
+ (stdin payload, exit 0 allows / 2 denies) and fails open — the CI gate stays the authority. The same
132
+ rule guards a person's `git commit` through a `pre-commit` hook `yad check --fix` installs in each clone
133
+ (E48); it never overwrites a hook of your own. What to turn on in GitHub or GitLab so the CI checks
134
+ actually hold a merge: [Branch protection](docs/branch-protection.md).
135
+ - **Background capture** on every Product, in both ledger modes (E43) — `hooks/yad-capture.mjs`, a
136
+ harness hook that runs `yad capture` after each agent edit. It snapshots every changed Shape artifact
137
+ onto your private `yad/wip/<you>/<epic>` branches, so a draft is never lost and nobody types a git
138
+ command. See [Background capture](#background-capture) below.
99
139
  - **PR/MR templates** and an opt-in CodeRabbit config.
100
140
 
101
- Your first `yad-epic` seeds the `epics/EP-<slug>/` ledger — state, approvals, and the contract lock —
102
- so the audit trail starts the moment you begin real work. `yad epic new <slug>` does the same seeding
141
+ Your first `yad-epic` seeds the `epics/EP-<slug>/` ledger — the step state and the approvals — so the
142
+ audit trail starts the moment you begin real work. The contract lock (`.sdlc/contract-lock.json`, the
143
+ hash of the shared contract surface) is written later, by `yad-architecture`. The one exception is a
144
+ change-epic that carries its parent's architecture: `yad epic new <slug> --type change --parent EP-<parent> --inherits architecture,contract`
145
+ (run for you by `yad-change`) writes a small **pointer-lock** that points at the parent's lock. `yad epic new <slug>` does the same seeding
103
146
  from the CLI when you would rather lay the track before the writing starts.
104
147
 
105
148
  Before any epic, you can also frame the whole product once: `yad foundation new` seeds the
@@ -129,6 +172,87 @@ has an INSTALL in one of them — a `skills/` folder, or an armed hook entry —
129
172
  instead; a `.cursor/` holding only Cursor rules is not an install, and is offered the default. Checked against each agent's
130
173
  own documentation on 2026-09-16; `yad doctor` prints the same table's verdict for your project.
131
174
 
175
+ ### Background capture
176
+
177
+ `yad capture` saves your work in progress without touching your checkout (E43). It takes every changed
178
+ file under `epics/` and `foundation/` — except the ledger (any `.sdlc/` folder and `reviews/`; the four
179
+ files a person or a skill writes there, `contract-lock.json`, `change.json`, `design-links.json` and
180
+ `test-links.json`, are included) — and commits it onto
181
+ a private branch per epic, `yad/wip/<your git name>/<epic>`. It uses git's low-level commands in a
182
+ throwaway index, so your branch, your staged changes and your files stay exactly as they were, and no
183
+ git hook runs.
184
+
185
+ | What | How |
186
+ | --- | --- |
187
+ | When | After every agent edit, by a hook yad wires in both ledger modes: Claude Code `PostToolUse` in `.claude/settings.json`, Cursor `afterFileEdit` in `.cursor/hooks.json`. Any other agent or editor: run `yad capture` yourself. Each capture takes every changed artifact, so your own editor's edits ride along |
188
+ | Push | A capture commits at once, locally. The hook pushes your capture branches (and fetches everyone else's, for claims) in the background at most once every 5 minutes, with no password prompt and a short timeout, so an edit never waits on the network. `yad capture` by hand pushes straight away. With no remote, or offline, the captures stay local and nothing fails |
189
+ | CI | yadflow's own push workflow skips `yad/wip/**`. `yad doctor` names any of **your** workflows a push to `yad/wip/*` would start (no branch filter, `branches: ["**"]`, or a `branches-ignore` that does not name it), so you can add `branches-ignore: ["yad/wip/**"]` |
190
+ | Off | `"capture": false` in the Product config (`yad check --fix` then removes the hook), or `YAD_CAPTURE=0` for one shell |
191
+
192
+ The capture commits are unsigned on purpose — a signing prompt inside a hook would hang the agent — and
193
+ each carries `Yad-Epic`, `Yad-Base` and `Yad-Branch` lines. They are drafts: the commit your history
194
+ keeps is the fold, below. The push is never forced: if you capture the same epic on two machines, the second push is refused rather than overwriting the first, and a `yad capture` you run by hand says so and names the branch (delete one copy with `git branch -D` to continue the other) — the hook's background push cannot report it. **To remove a capture branch for good** — say a secret was captured — delete it on origin first, then on every machine that has it run `git branch -D yad/wip/<you>/<epic>` **and** `git branch -dr origin/yad/wip/<you>/<epic>` (the second deletes that machine's saved copy of origin's branch; it says so if there is none): a machine that still holds either one rebuilds the branch and pushes it back. On a fresh clone, a capture continues the branch already on origin. Two people with the same git name share branches. The people count that caps review gates
195
+ (E71) does not count capture commits.
196
+
197
+ ### Who else is editing a file (claims)
198
+
199
+ `yad claims` lists who else is editing which artifact right now (E46). It is **advice, not a lock**:
200
+ nothing stops anyone, because with no server a real lock is impossible. There is nothing to record by
201
+ hand — a claim is read from the capture branches: someone's `yad/wip/<name>/<epic>` branch holds a
202
+ saved change to that file that is not on the default branch yet.
203
+
204
+ | What | How |
205
+ | --- | --- |
206
+ | A claim | A file of the epic that differs between the capture branch's last save and the commit that save was built on — the person's own edits, never what a pull brought in |
207
+ | Ends | 4 hours after that branch's last save, or at once when the file on the default branch matches the saved one (the work was merged) |
208
+ | `yad claims [<epic>]` | Fetches everyone's capture branches first (short timeout, no prompts), then lists each claim: file, person, last save. `--no-fetch` reads what is already here; `--json` too |
209
+ | At edit time | When an edit changes a file someone else has a claim on, the capture hook says so. Under Claude Code the agent reads it (and you see it); under Cursor it is a line on stderr. It never blocks, never waits on the network, and names the same person and file at most once an hour |
210
+ | Fresh enough | The hook's background push (at most every 5 minutes) also fetches everyone's capture branches in the background |
211
+
212
+ **Limits.** Someone with capture off, or offline, is invisible. A claim can be up to about 5 minutes
213
+ late. Two people with the same git name share capture branches, so they never see each other. Times
214
+ are the saver's own clock, shown in UTC.
215
+
216
+ ### Who owns a step (assign)
217
+
218
+ `yad assign` gives one authoring step to one person (E47) — for example "Bob writes the
219
+ architecture". It is stronger advice than a claim, because it is decided in advance, but it is still
220
+ **advice, not a lock**: it never blocks an edit, never holds a review gate and never stops a fold.
221
+
222
+ | What | How |
223
+ | --- | --- |
224
+ | `yad assign <epic> <step> [--to <name>]` | Assigns the step to you, or to the person whose **git name** you give (the name they commit with). Only authoring steps that write an artifact (`epic`, `architecture`, `stories`, …); review steps are not assigned, because the platform and the gate count decide who approves. If someone else already owns the step it is refused and names them; `--force` replaces them |
225
+ | `yad unassign <epic> <step>` | Removes the assignment. Your own freely; someone else's needs `--force` |
226
+ | `yad owners [<epic>]` | Lists every assignment, whether it is live, and any owner file that cannot be read. `--json` too |
227
+ | Where it is kept | One small file per step: `epics/<epic>/.sdlc/owners/<step>.json` (`foundation/.sdlc/owners/` for the Foundation). It is not a ledger file, so you can write it in both ledger modes. `yad assign` does not commit it, and `yad fold` never takes it (an assignment is not authoring): commit it on its own — on a `verified` Product, in a PR of its own (the Product checks let a PR that changes only owner files through, since E47; run `yad update` so your copies of the checks and of the product-checks workflow have that rule; `yad doctor` warns `owners:rename-blind` if a hand-edited workflow was kept) — so the team sees it when they pull. It is captured to your `yad/wip/…` branch like any artifact, but it is not counted as a claim |
228
+ | Live | While the step's work is open: the step is not finished, or its review has not passed yet. After that the file stays as a record; re-opening the step makes it live again. There is no time limit |
229
+ | Shown | `yad next` prints `owner: <name>` under the step (and under its review) while it is live |
230
+ | At edit time | When your edit changes a file of a step someone else owns, the capture hook says so — to the agent under Claude Code, on stderr under Cursor — at most once an hour per step. One note carries both this and any claim warning |
231
+
232
+ **Limits.** The name is the git name, made branch-safe the way capture branch names are — so it matches
233
+ the capture hook without asking GitHub or GitLab. Two people with the same git name look like one owner.
234
+ A git name with no Latin letters is branch-safe only through the person's email, so someone else can
235
+ assign it only once that person has a capture branch here (`--to` finds it by the git name the branch was
236
+ saved under). With capture off, there is no edit-time warning.
237
+
238
+ ### Folding a step into one commit
239
+
240
+ `yad fold <epic> <step>` ends an authoring step (E44). It makes the one commit the record keeps,
241
+ `docs(<epic>): author <step>` — for example `docs(EP-checkout): author architecture`. The authoring
242
+ skills run it at the end of their step; you can run it yourself too.
243
+
244
+ | What | How |
245
+ | --- | --- |
246
+ | Files | Only that step's files: the ones its review covers (architecture is `architecture.md`, `contract.md` and `.sdlc/contract-lock.json`; stories is everything under `stories/`), plus what the step's skill writes beside them (`DESIGN.md` and `.sdlc/design-links.json` for the UI step, `.sdlc/test-links.json` for test cases). Other changed files of the epic are named and left on disk, so a half-written draft of another step never lands in this commit |
247
+ | The ledger | Follows `ledger` mode. `local`: the epic's changed ledger files go in the same commit — one step, one commit. `verified`: CI writes the ledger at merge, so the fold leaves those files for CI — except while the epic is brand new (no `.sdlc/state.json` in HEAD yet): then its new ledger files are its seed, which is the case `ledger-guard` allows and the only way a seed reaches the default branch. Once the epic is seeded, even a NEW ledger file (a `reviews/*.md` written by hand) is left for CI, because the guard would reject it |
248
+ | The seed | While the epic is brand new, the first fold also takes the new person-written `.sdlc/` files beside the ledger — a change-epic's `change.json` and its pointer `contract-lock.json` — in both modes |
249
+ | The commit | A normal `git commit`, so it is signed if your git signs (with `ledger: verified` it warns when signing is off: the review PR's signature check would fail), and your commit hooks run. Only the step's files are committed; anything else you staged stays staged. It ends with `Yad-Epic`, `Yad-Step` and `Yad-Folded` lines — the last is the tip of your capture branch, the drafts this commit folds (`none` with capture off) |
250
+ | Where | With `ledger: verified`, never on the default branch — artifacts reach it only through the review PR. With `ledger: local`, anywhere |
251
+ | The drafts | Your `yad/wip/<you>/<epic>` branch is left as it is: the draft history stays for the later rework measurement (E95), and nothing has to be deleted on other machines. The next capture has nothing new to save |
252
+
253
+ A step with no changed files has nothing to fold, and says so. `yad open-pr` on a review branch warns
254
+ when that step's files have changes no fold has committed — they are not in the review.
255
+
132
256
  ### The local ledger guard, per agent
133
257
 
134
258
  In **verified mode** — where CI owns the gate ledger — yadflow installs a local guardrail that stops
@@ -141,11 +265,11 @@ failed pipeline. It needs a hook that can run *before* a write and refuse it. Tw
141
265
  | Cursor | `.cursor/hooks.json` | `preToolUse` |
142
266
 
143
267
  Cursor answers this kind of hook in JSON rather than by exit code, and treats an empty answer as a
144
- refusal — so a `.cursor` project also gets a small adapter script, `hooks/ledger-guard-cursor.sh`,
268
+ refusal — so a `.cursor` project also gets a small adapter script, `hooks/ledger-guard-cursor.mjs`,
145
269
  which always replies properly. Without it the guard would have blocked every file write instead of
146
270
  just the gate files.
147
271
 
148
- Every other directory gets the script (`hooks/ledger-guard.sh`) and no wiring — they have no such
272
+ Every other directory gets the script (`hooks/ledger-guard.mjs`) and no wiring — they have no such
149
273
  hook, so those agents are guarded by CI alone. `yad doctor` says so by name rather than staying
150
274
  silent. The Cursor wiring follows Cursor's published hook protocol and has not yet been exercised
151
275
  against a live Cursor session.
@@ -158,10 +282,13 @@ against a live Cursor session.
158
282
  setup → AI drafts an artifact → ⛔ gate waits → you approve → next step → ⛔ gate waits → …
159
283
  ```
160
284
 
161
- 1. **`npx yadflow setup`** — the wizard installs skills, connects your repo, and wires the gates.
285
+ 1. **Get a workspace** — `npx yadflow new <name>` for a new product, `npx yadflow init` for repos you
286
+ already have, or `npx yadflow join <url>` to join a team (see [Quickstart](#quickstart)). The
287
+ wizard installs the skills, connects your repos, and wires the gates.
162
288
  2. **Run `yad-epic`** in your assistant — it drafts the epic, then **stops** and writes it to a file.
163
289
  3. **A gate waits.** Nothing advances until you review it.
164
- 4. **You approve** — local, or by merging the review PR/MR.
290
+ 4. **You approve** — by merging the review PR/MR, or, with no GitHub or GitLab, with
291
+ `yad gate approve` and `yad gate advance`.
165
292
  5. **The workflow continues** to the next step, which stops again.
166
293
 
167
294
  Every step is the same contract: *AI proposes → a human decides → the trail is recorded.*
@@ -198,12 +325,13 @@ complementary: bring your favorite, and Yadflow wraps the engineering process ar
198
325
 
199
326
  Reviewing AI-generated code is where governance lives or dies, so Yadflow makes the honest review the
200
327
  *easiest* path. The **Review Companion** turns any PR/MR into a 60-second trailer, swipe-through cards,
201
- and a grounded chat. **Pair Review** (`yad pair-review`) goes further: the AI walks you through the
328
+ and a grounded chat. **Pair Review** (the `yad-pair-review` skill; its CLI side is `yad gate walkthrough` for a Shape
329
+ review and `yad review walkthrough` for a code PR) goes further: the AI walks you through the
202
330
  change one risk-ordered stop at a time, explains each, then asks you about it — until both sides are
203
331
  satisfied.
204
332
 
205
333
  It doubles as a lesson: it teaches a transferable review method, scores you against it, and records
206
- your review-skill growth in a **private, local-only** learning log (`yad status` rolls it up). It's
334
+ your review-skill growth in a **private, local-only** learning log (the `yad-status` skill rolls it up). It's
207
335
  **soft and additive** — it never blocks a merge on its own, yet any genuine concern it surfaces blocks
208
336
  like a normal review comment.
209
337
 
@@ -231,8 +359,28 @@ workflow-hygiene flags — derived read-only, so an EM can see how the team actu
231
359
  ---
232
360
 
233
361
  **Platform support.** Linux and macOS are first-class (CI runs the test suite, bash gates, and the
234
- end-to-end harness on both). On **Windows use [WSL](https://learn.microsoft.com/windows/wsl/)** — native
235
- PowerShell is not yet supported. Requires **Node.js ≥ 18**.
362
+ end-to-end harness on both). **On Windows, the agent hooks run natively, without WSL** (E113), and the
363
+ CLI code they reach has been fixed for Windows — CI runs the hook scripts and those CLI tests on Windows.
364
+ The rest of the CLI is not yet tested there. Requires **Node.js ≥ 18**.
365
+
366
+ | On Windows | What to know |
367
+ | --- | --- |
368
+ | Agent hooks | Each hook is a Node script (`hooks/*.mjs`) that the agent runs as `node <script>`, so nothing needs bash or an execute bit. `node` must be on the PATH your agent runs with — if it is not, the hooks silently do not run |
369
+ | Claude Code | Runs hook commands in **Git Bash** (part of Git for Windows). Without Git Bash it falls back to PowerShell, and the hooks do not run there. `yad doctor` warns when it cannot find Git Bash |
370
+ | Cursor | Runs hook commands through PowerShell. The entry is `node hooks/<script>.mjs`, which PowerShell runs as it is |
371
+ | Line endings | Set `git config core.autocrlf input` in the Product clone. With `true` (the Git for Windows default) git checks files out with CRLF line endings. yad's own managed files still compare equal, but an approval is bound to an artifact's exact bytes, so reviews approved elsewhere read as stale. `yad doctor` warns about this on Windows |
372
+ | Check gates | Still bash scripts (`checks/*.sh`). They run on your CI runner, not on your machine |
373
+ | Not yet tested on Windows | The full test suite and the end-to-end harness run on Linux and macOS only. A machine with no Git Bash is not covered for Claude Code |
374
+
375
+ **Upgrading from a release before E113.** The hooks used to be bash scripts (`hooks/*.sh`). `yad check
376
+ --fix` (or `yad update`) rewrites each hook entry to the Node command and deletes the old script — but
377
+ only a copy yad's own record (`.sdlc/managed.json`) proves it wrote and nobody changed. A script you
378
+ edited, or one your own hook entry still runs, is kept. The old script is also kept until the rewritten
379
+ settings file is **committed**: yad never commits that file for you, and a teammate who pulls must not get
380
+ an entry that runs a deleted script. So the order is: `yad check --fix`, commit `.claude/settings.json` and
381
+ `.cursor/hooks.json`, then `yad check --fix` again to remove the old scripts. Everyone on the team should
382
+ upgrade together: an older yadflow does not know the new entries, and its `check --fix` puts the old
383
+ script and entry back beside them.
236
384
 
237
385
  **Releases** are a human decision. Merging to `main` never publishes; a person fast-forwards the
238
386
  `release` branch, and [semantic-release](https://semantic-release.gitbook.io/) publishes from there
package/bin/commands.mjs CHANGED
@@ -11,9 +11,12 @@
11
11
  // is about to do real work.
12
12
 
13
13
  export { runSetup } from '../cli/setup.mjs';
14
+ export { runNew, runInit, runJoin } from '../cli/workspace.mjs';
15
+ export { findProduct, hasProduct, workspaceProduct, registryEntryFor, WORKSPACE_FILE } from '../cli/find-product.mjs';
14
16
  export { reconcile } from '../cli/reconcile.mjs';
15
17
  export { gateOpen, gateSync, gateComments, gateStatus, gateCi, gateReview, gateTrailer, gateWalkthrough, gateRepair } from '../cli/gate.mjs';
16
- export { isValidEpicId, seedableProfiles } from '../cli/epic-state.mjs';
18
+ export { gateApprove, gateComment, gateAdvance } from '../cli/gate-local.mjs';
19
+ export { isValidEpicId, productDriftError, seedableProfiles } from '../cli/epic-state.mjs';
17
20
  export { runEpicNew, runFoundationNew, runFoundationStatus } from '../cli/epic.mjs';
18
21
  export { runSkillBind, runSkillList, runSkillUnbind } from '../cli/skill.mjs';
19
22
  export { runCommit } from '../cli/commit.mjs';
@@ -22,6 +25,10 @@ export { reviewTrailer, reviewContext, reviewNudge, reviewReconcile, reviewWalkt
22
25
  export { runShip } from '../cli/ship.mjs';
23
26
  export { runCheckpoint } from '../cli/checkpoint.mjs';
24
27
  export { runTidy } from '../cli/tidy.mjs';
28
+ export { runCapture } from '../cli/capture.mjs';
29
+ export { runFold } from '../cli/fold.mjs';
30
+ export { runClaims } from '../cli/claims.mjs';
31
+ export { runAssign, runUnassign, runOwners } from '../cli/owners.mjs';
25
32
  export { runIndex } from '../cli/index-command.mjs';
26
33
  export { runHistory, HISTORY_FLAGS } from '../cli/history.mjs';
27
34
  export { runRepo } from '../cli/repo.mjs';