From c5ca7f1e8457ce925d63b3ff03345f282db180c6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 7 Aug 2026 10:08:19 +0000 Subject: [PATCH 01/14] chore(deps-dev): bump js-yaml from 5.2.2 to 5.2.3 (#605) Bumps [js-yaml](https://github.com/nodeca/js-yaml) from 5.2.2 to 5.2.3. - [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md) - [Commits](https://github.com/nodeca/js-yaml/compare/5.2.2...5.2.3) --- updated-dependencies: - dependency-name: js-yaml dependency-version: 5.2.3 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- pnpm-lock.yaml | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 2106ee56..bc195738 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "@commitlint/config-conventional": "^21.2.0", "ajv": "8.20.0", "ajv-formats": "3.0.1", - "js-yaml": "5.2.2", + "js-yaml": "5.2.3", "lefthook": "^2.1.10" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 30849ae0..fd363ec9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -21,8 +21,8 @@ importers: specifier: 3.0.1 version: 3.0.1(ajv@8.20.0) js-yaml: - specifier: 5.2.2 - version: 5.2.2 + specifier: 5.2.3 + version: 5.2.3 lefthook: specifier: ^2.1.10 version: 2.1.10 @@ -263,8 +263,8 @@ packages: resolution: {integrity: sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==} hasBin: true - js-yaml@5.2.2: - resolution: {integrity: sha512-dayzUzKkJ1MkuUtZglSebU43utNXH0OWQByK9rKOOuYIO8M5TV1y+n8ALMdG0rdzBnfNkOmZEqrURepb0ejqBw==} + js-yaml@5.2.3: + resolution: {integrity: sha512-n+mUVyUX5bVv7G/G2zyIHOhdxfuU1dY2NOFzTQUWiMUbFss8b57NFlgCCaggU78wSw5KVS9cllzeLyzyR+n5nw==} hasBin: true json-parse-even-better-errors@2.3.1: @@ -641,7 +641,7 @@ snapshots: dependencies: argparse: 2.0.1 - js-yaml@5.2.2: + js-yaml@5.2.3: dependencies: argparse: 2.0.1 From 97337af5f45bfbe0a383f932637201d9ce8f05ac Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 7 Aug 2026 10:08:23 +0000 Subject: [PATCH 02/14] chore(deps-dev): bump jscpd from 5.0.7 to 5.0.14 in /cli (#606) Bumps [jscpd](https://github.com/kucherenko/jscpd/tree/HEAD/rust/jscpd) from 5.0.7 to 5.0.14. - [Release notes](https://github.com/kucherenko/jscpd/releases) - [Changelog](https://github.com/kucherenko/jscpd/blob/master/CHANGELOG.md) - [Commits](https://github.com/kucherenko/jscpd/commits/v5.0.14/rust/jscpd) --- updated-dependencies: - dependency-name: jscpd dependency-version: 5.0.14 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- cli/pnpm-lock.yaml | 116 ++++++++++++++++++++++----------------------- 1 file changed, 58 insertions(+), 58 deletions(-) diff --git a/cli/pnpm-lock.yaml b/cli/pnpm-lock.yaml index 852533d8..9cb43bd0 100644 --- a/cli/pnpm-lock.yaml +++ b/cli/pnpm-lock.yaml @@ -77,7 +77,7 @@ importers: version: 4.0.0(@types/react@19.2.18) jscpd: specifier: ^5.0.0 - version: 5.0.7 + version: 5.0.14 knip: specifier: ^6.0.0 version: 6.31.0 @@ -1669,36 +1669,6 @@ packages: typescript: optional: true - cpd-darwin-arm64@5.0.7: - resolution: {integrity: sha512-yfqUd+y1lqCp0Oso462SxYmaLhnkZRumhvZB+Noz/jg4+AvQDZcsVnb7gbjr7Wu3+Te8Jz41mZs+ka2XDJ257g==} - cpu: [arm64] - os: [darwin] - - cpd-darwin-x64@5.0.7: - resolution: {integrity: sha512-RFT71RYdfuejaRY5K0jxEg/hIb/lDX7DK3+Y8SvQixrQi4Epo5EMhtiechCYlIcuDkbq4b2htpldipqssEcc/g==} - cpu: [x64] - os: [darwin] - - cpd-linux-arm64-gnu@5.0.7: - resolution: {integrity: sha512-SBkIVIgH+oqsPJCh89PzOA8EJ0URF97FP9JgGgQrYogfQ3AmNyjJIGpgTClj9IyTb5jTomJVpwa75FYqERXVIQ==} - cpu: [arm64] - os: [linux] - - cpd-linux-x64-gnu@5.0.7: - resolution: {integrity: sha512-UE+BGxcJSYJPNGD01vPZcIFNFKOc3lgMGpe717JppCCSjyjXd8fKO3FXDePcy3MRTZymC67i2rg6IZkLVsmBWQ==} - cpu: [x64] - os: [linux] - - cpd-linux-x64-musl@5.0.7: - resolution: {integrity: sha512-1Lv5BXw5AHTb5x5quL813UryKmbzJAJ2uG2lonnanEarWA+j/D0jKNJjY7k3+rnKaeAugiMltmeF6Rf9PAFSIw==} - cpu: [x64] - os: [linux] - - cpd-windows-x64-msvc@5.0.7: - resolution: {integrity: sha512-rISkx5Vfl9Chl6kIuOJrf03pDtV4xBGqPaXcS32RE5t65JlAO+AEt0uVpjMWDPm9SKS6onyBKHdRoQkiluqW/Q==} - cpu: [x64] - os: [win32] - cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} @@ -2052,8 +2022,38 @@ packages: resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true - jscpd@5.0.7: - resolution: {integrity: sha512-V2YemuWeT7qOF6TeNG1zkKavamuDJJQppdHOQjG8dR2bzWNEJacaPgi/ALQPTlNbtXoL/rsQGhPQC8ASN+WzMQ==} + jscpd-darwin-arm64@5.0.14: + resolution: {integrity: sha512-Ojjl79SBuj9tEW6WbjZ1a/1ZOR89dneH9yLQYQu8WyWaQownttnx7RYFEHU6aGhS4jIvwUEbr+1wxzFTb37cwg==} + cpu: [arm64] + os: [darwin] + + jscpd-darwin-x64@5.0.14: + resolution: {integrity: sha512-DxFg5XvjMZ81iVeqillnM5apqcGCfNTbroNF+mPLr7RkHLGH6mudLgtO+ILL/hfpZXy1bF9oIY5BSudPmN/k9A==} + cpu: [x64] + os: [darwin] + + jscpd-linux-arm64-gnu@5.0.14: + resolution: {integrity: sha512-1uw+XBHEt9pONXNICSp5HpaVWPjG6mQ6deDXaq9Yb0xCNJkX4/8gmn0vhzekIyZD2DspRYKPUolbDsqm/HEdYg==} + cpu: [arm64] + os: [linux] + + jscpd-linux-x64-gnu@5.0.14: + resolution: {integrity: sha512-dFTbyyrm+Z9pcXIVzJQCw8QAgiNqIiO69sm4AfA7/wFdPoizoVzjhaXsYXcSV4bs0aoPiWbNazg0J0HgslT/5A==} + cpu: [x64] + os: [linux] + + jscpd-linux-x64-musl@5.0.14: + resolution: {integrity: sha512-SayS7qQJvixyy9eR0+UjepkTsUUwqvlsiuSxfIdHgG2qzqoh/thnkgiu4By8fsiiDpQONsQrRrZDwHRQ3GDrBQ==} + cpu: [x64] + os: [linux] + + jscpd-windows-x64-msvc@5.0.14: + resolution: {integrity: sha512-DqjxlVkUanlahGgY2lY7Zkrau4BUTI+AwWky+bPGK4kSK2AIOaUziY9Q19u8b58idXmJA9FKK98Fuu4ajNXVjQ==} + cpu: [x64] + os: [win32] + + jscpd@5.0.14: + resolution: {integrity: sha512-zge+FPZZAymt2Do5Z0+QHyIn4/XcUhrO/W7of9HcHZfx2AK8++dYhLA1uWtwXj47ml3Of8PbcUW4wUWvYMCc3w==} engines: {node: '>=18'} hasBin: true @@ -4128,24 +4128,6 @@ snapshots: optionalDependencies: typescript: 7.0.2 - cpd-darwin-arm64@5.0.7: - optional: true - - cpd-darwin-x64@5.0.7: - optional: true - - cpd-linux-arm64-gnu@5.0.7: - optional: true - - cpd-linux-x64-gnu@5.0.7: - optional: true - - cpd-linux-x64-musl@5.0.7: - optional: true - - cpd-windows-x64-msvc@5.0.7: - optional: true - cross-spawn@7.0.6: dependencies: path-key: 3.1.1 @@ -4527,14 +4509,32 @@ snapshots: dependencies: argparse: 2.0.1 - jscpd@5.0.7: + jscpd-darwin-arm64@5.0.14: + optional: true + + jscpd-darwin-x64@5.0.14: + optional: true + + jscpd-linux-arm64-gnu@5.0.14: + optional: true + + jscpd-linux-x64-gnu@5.0.14: + optional: true + + jscpd-linux-x64-musl@5.0.14: + optional: true + + jscpd-windows-x64-msvc@5.0.14: + optional: true + + jscpd@5.0.14: optionalDependencies: - cpd-darwin-arm64: 5.0.7 - cpd-darwin-x64: 5.0.7 - cpd-linux-arm64-gnu: 5.0.7 - cpd-linux-x64-gnu: 5.0.7 - cpd-linux-x64-musl: 5.0.7 - cpd-windows-x64-msvc: 5.0.7 + jscpd-darwin-arm64: 5.0.14 + jscpd-darwin-x64: 5.0.14 + jscpd-linux-arm64-gnu: 5.0.14 + jscpd-linux-x64-gnu: 5.0.14 + jscpd-linux-x64-musl: 5.0.14 + jscpd-windows-x64-msvc: 5.0.14 jsesc@3.1.0: {} From f1b2c95f70acae64f5c4019894ea26effae4611b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 7 Aug 2026 10:08:48 +0000 Subject: [PATCH 03/14] chore(deps-dev): bump fast-check from 4.7.0 to 4.9.0 in /cli (#607) Bumps [fast-check](https://github.com/dubzzz/fast-check/tree/HEAD/packages/fast-check) from 4.7.0 to 4.9.0. - [Release notes](https://github.com/dubzzz/fast-check/releases) - [Changelog](https://github.com/dubzzz/fast-check/blob/main/packages/fast-check/CHANGELOG.md) - [Commits](https://github.com/dubzzz/fast-check/commits/v4.9.0/packages/fast-check) --- updated-dependencies: - dependency-name: fast-check dependency-version: 4.9.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- cli/pnpm-lock.yaml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/cli/pnpm-lock.yaml b/cli/pnpm-lock.yaml index 9cb43bd0..33cbb1a1 100644 --- a/cli/pnpm-lock.yaml +++ b/cli/pnpm-lock.yaml @@ -71,7 +71,7 @@ importers: version: 3.2.6(vitest@3.2.6(@types/node@26.1.2)) fast-check: specifier: ^4.7.0 - version: 4.7.0 + version: 4.9.0 ink-testing-library: specifier: 4.0.0 version: 4.0.0(@types/react@19.2.18) @@ -1781,8 +1781,8 @@ packages: resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==} engines: {node: '>=0.10.0'} - fast-check@4.7.0: - resolution: {integrity: sha512-NsZRtqvSSoCP0HbNjUD+r1JH8zqZalyp6gLY9e7OYs7NK9b6AHOs2baBFeBG7bVNsuoukh89x2Yg3rPsul8ziQ==} + fast-check@4.9.0: + resolution: {integrity: sha512-7ms6T7SybUev/PQITciI0yLM2pOSFy5zpG8Ty7tQofcVaQUvrMXp6CBwqF6fThLCLOrfBtuHAtwq6Yu4XPCllg==} engines: {node: '>=12.17.0'} fast-deep-equal@3.1.3: @@ -2338,8 +2338,8 @@ packages: resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} engines: {node: '>=0.4.0'} - pure-rand@8.4.0: - resolution: {integrity: sha512-IoM8YF/jY0hiugFo/wOWqfmarlE6J0wc6fDK1PhftMk7MGhVZl88sZimmqBBFomLOCSmcCCpsfj7wXASCpvK9A==} + pure-rand@8.4.2: + resolution: {integrity: sha512-vvuOGgcuPJAirlHvuQw1TrOiw7ptaIXXmIbNuiNOY6lNGJJH49PQ1Kj4nd783nPdQhQdicgOjVI2yI/9BD6/Ng==} qs@6.15.2: resolution: {integrity: sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==} @@ -4271,9 +4271,9 @@ snapshots: dependencies: is-extendable: 0.1.1 - fast-check@4.7.0: + fast-check@4.9.0: dependencies: - pure-rand: 8.4.0 + pure-rand: 8.4.2 fast-deep-equal@3.1.3: {} @@ -4810,7 +4810,7 @@ snapshots: progress@2.0.3: {} - pure-rand@8.4.0: {} + pure-rand@8.4.2: {} qs@6.15.2: dependencies: From 75b4f0a897f4cc84c6164203e618922378d00e0b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 20:57:10 +0000 Subject: [PATCH 04/14] chore(deps-dev): bump knip from 6.31.0 to 6.32.0 in /cli (#613) Bumps [knip](https://github.com/webpro-nl/knip/tree/HEAD/packages/knip) from 6.31.0 to 6.32.0. - [Release notes](https://github.com/webpro-nl/knip/releases) - [Commits](https://github.com/webpro-nl/knip/commits/knip@6.32.0/packages/knip) --- updated-dependencies: - dependency-name: knip dependency-version: 6.32.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- cli/pnpm-lock.yaml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/cli/pnpm-lock.yaml b/cli/pnpm-lock.yaml index 33cbb1a1..9ca5e427 100644 --- a/cli/pnpm-lock.yaml +++ b/cli/pnpm-lock.yaml @@ -80,7 +80,7 @@ importers: version: 5.0.14 knip: specifier: ^6.0.0 - version: 6.31.0 + version: 6.32.0 lefthook: specifier: ^2.1.10 version: 2.1.10 @@ -1860,8 +1860,8 @@ packages: resolution: {integrity: sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==} engines: {node: '>=18'} - get-tsconfig@4.14.0: - resolution: {integrity: sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==} + get-tsconfig@4.14.1: + resolution: {integrity: sha512-Dz/6HxkrxgNehhxLVeyv8sad9UzF2xBVeaKBQNDfJ5XiSXmp2gTR0eO0RWiT2NCKS5aGP9jjkOMggTN90qU50A==} glob@10.5.0: resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} @@ -2080,8 +2080,8 @@ packages: resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} engines: {node: '>=0.10.0'} - knip@6.31.0: - resolution: {integrity: sha512-NbeIEmUS2VUMjAkbiSNOKPJeV9wpCsr0660sUyKyMQbk4Iom0++nTLInVp4MJ+LfR4kORnw67bDi5tvO7YLnzA==} + knip@6.32.0: + resolution: {integrity: sha512-KDX9OmmOFmlvmxTkrx6Z0GHISMut+pXMSKR8eg84bovaxJKx2NdQD4JYCXveSbvieRe107W6vCD2xCpmz0qBYA==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true @@ -2625,8 +2625,8 @@ packages: ufo@1.6.3: resolution: {integrity: sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==} - unbash@4.0.5: - resolution: {integrity: sha512-EE9xv9cr93DSppe086Rnbq0jwG7MBCEe22JZ4UQ8Bn9RyUwDSoUpBmzdb5+7PzocdqBEb/K73FGPaQUMmLxTQQ==} + unbash@4.0.10: + resolution: {integrity: sha512-b7zoBQvpWp0vuN5q2vK2RRBR2SvuruQAs50DApdDveBSn3eSYd84IaHodFqQIMlvY9K2VnyBUEXgwOBuGU9GBg==} engines: {node: '>=14'} underscore@1.13.8: @@ -4350,7 +4350,7 @@ snapshots: '@sec-ant/readable-stream': 0.4.1 is-stream: 4.0.1 - get-tsconfig@4.14.0: + get-tsconfig@4.14.1: dependencies: resolve-pkg-maps: 1.0.0 @@ -4548,11 +4548,11 @@ snapshots: kind-of@6.0.3: {} - knip@6.31.0: + knip@6.32.0: dependencies: fdir: 6.5.0(picomatch@4.0.5) formatly: 0.3.0 - get-tsconfig: 4.14.0 + get-tsconfig: 4.14.1 jiti: 2.7.0 oxc-parser: 0.142.0 oxc-resolver: 11.24.2 @@ -4560,7 +4560,7 @@ snapshots: smol-toml: 1.7.1 strip-json-comments: 5.0.3 tinyglobby: 0.2.17 - unbash: 4.0.5 + unbash: 4.0.10 yaml: 2.9.0 zod: 4.4.3 @@ -5129,7 +5129,7 @@ snapshots: ufo@1.6.3: {} - unbash@4.0.5: {} + unbash@4.0.10: {} underscore@1.13.8: {} From 174136fec26051dfc0fb0a6d3f504ae605fb68a4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 20:57:35 +0000 Subject: [PATCH 05/14] chore(deps): bump smol-toml from 1.6.1 to 1.7.1 in /cli (#614) Bumps [smol-toml](https://github.com/squirrelchat/smol-toml) from 1.6.1 to 1.7.1. - [Release notes](https://github.com/squirrelchat/smol-toml/releases) - [Commits](https://github.com/squirrelchat/smol-toml/compare/v1.6.1...v1.7.1) --- updated-dependencies: - dependency-name: smol-toml dependency-version: 1.7.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- cli/pnpm-lock.yaml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/cli/pnpm-lock.yaml b/cli/pnpm-lock.yaml index 9ca5e427..6134a378 100644 --- a/cli/pnpm-lock.yaml +++ b/cli/pnpm-lock.yaml @@ -43,7 +43,7 @@ importers: version: 3.36.0 smol-toml: specifier: ^1.6.1 - version: 1.6.1 + version: 1.7.1 devDependencies: '@biomejs/biome': specifier: ^2.4.7 @@ -2446,10 +2446,6 @@ packages: resolution: {integrity: sha512-SO/3iYL5S3W57LLEniscOGPZgOqZUPCx6d3dB+52B80yJ0XstzsC/eV8gnA4tM3MHDrKz+OCFSLNjswdSC+/bA==} engines: {node: '>=22'} - smol-toml@1.6.1: - resolution: {integrity: sha512-dWUG8F5sIIARXih1DTaQAX4SsiTXhInKf1buxdY9DIg4ZYPZK5nGM1VRIYmEbDbsHt7USo99xSLFu5Q1IqTmsg==} - engines: {node: '>= 18'} - smol-toml@1.7.1: resolution: {integrity: sha512-PPlsspAZ4jbMBu5DMFhfUGDQLu/vrL4SyBROVS37x8ynnVmFIs1VPBz1Co8Xks3TvpIaZXmU85y4DrQ+UyVFoQ==} engines: {node: '>= 18'} @@ -4941,8 +4937,6 @@ snapshots: ansi-styles: 6.2.3 is-fullwidth-code-point: 5.1.0 - smol-toml@1.6.1: {} - smol-toml@1.7.1: {} source-map-js@1.2.1: {} From 08c3023b563d586cfc636dade44294045d468ef7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 20:57:39 +0000 Subject: [PATCH 06/14] chore(deps-dev): bump @types/node from 26.1.2 to 26.2.0 in /cli (#615) Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 26.1.2 to 26.2.0. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node) --- updated-dependencies: - dependency-name: "@types/node" dependency-version: 26.2.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- cli/pnpm-lock.yaml | 192 ++++++++++++++++++++++----------------------- 1 file changed, 96 insertions(+), 96 deletions(-) diff --git a/cli/pnpm-lock.yaml b/cli/pnpm-lock.yaml index 6134a378..12cfb2f5 100644 --- a/cli/pnpm-lock.yaml +++ b/cli/pnpm-lock.yaml @@ -16,7 +16,7 @@ importers: dependencies: '@inquirer/prompts': specifier: ^8.5.2 - version: 8.5.2(@types/node@26.1.2) + version: 8.5.2(@types/node@26.2.0) ajv: specifier: ^8.20.0 version: 8.20.0 @@ -50,25 +50,25 @@ importers: version: 2.5.6 '@commitlint/cli': specifier: ^21.2.1 - version: 21.2.1(@types/node@26.1.2)(conventional-commits-parser@7.1.1)(typescript@7.0.2) + version: 21.2.1(@types/node@26.2.0)(conventional-commits-parser@7.1.1)(typescript@7.0.2) '@commitlint/config-conventional': specifier: ^21.2.0 version: 21.2.0 '@stryker-mutator/core': specifier: ^9.6.1 - version: 9.6.1(@types/node@26.1.2) + version: 9.6.1(@types/node@26.2.0) '@stryker-mutator/vitest-runner': specifier: ^9.6.1 - version: 9.6.1(@stryker-mutator/core@9.6.1(@types/node@26.1.2))(vitest@3.2.6(@types/node@26.1.2)) + version: 9.6.1(@stryker-mutator/core@9.6.1(@types/node@26.2.0))(vitest@3.2.6(@types/node@26.2.0)) '@types/node': specifier: ^26.1.1 - version: 26.1.2 + version: 26.2.0 '@types/react': specifier: 19.2.18 version: 19.2.18 '@vitest/coverage-v8': specifier: ^3.2.6 - version: 3.2.6(vitest@3.2.6(@types/node@26.1.2)) + version: 3.2.6(vitest@3.2.6(@types/node@26.2.0)) fast-check: specifier: ^4.7.0 version: 4.9.0 @@ -92,7 +92,7 @@ importers: version: 7.0.2 vitest: specifier: ^3.2.6 - version: 3.2.6(@types/node@26.1.2) + version: 3.2.6(@types/node@26.2.0) packages: @@ -1279,8 +1279,8 @@ packages: '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} - '@types/node@26.1.2': - resolution: {integrity: sha512-Vu4a5UFA9rIIFJ7rB/Vaafh9lrCQszopTCx6KjFboXTGQbPNasehVR5TEiithSDGyd1DEiUByggTZsg8jukeIg==} + '@types/node@26.2.0': + resolution: {integrity: sha512-5IviulTZeRNp2vAJ514cc/HUlY5nZ9fCbq9DMyC52BrhFZACo3nI0R7qBxhQmo/d27NFe96ur/b7Wwxklda+kg==} '@types/react@19.2.18': resolution: {integrity: sha512-AnzbBERsrLKtk2XSfTbYRLjQPdy116Sty4q+T+Bp3IC4l6jNBvreVPAHmpq9qhXQM7CXZPjLVmGMw9sy+hxQ3w==} @@ -3052,12 +3052,12 @@ snapshots: '@colors/colors@1.5.0': optional: true - '@commitlint/cli@21.2.1(@types/node@26.1.2)(conventional-commits-parser@7.1.1)(typescript@7.0.2)': + '@commitlint/cli@21.2.1(@types/node@26.2.0)(conventional-commits-parser@7.1.1)(typescript@7.0.2)': dependencies: '@commitlint/config-conventional': 21.2.0 '@commitlint/format': 21.2.0 '@commitlint/lint': 21.2.0 - '@commitlint/load': 21.2.0(@types/node@26.1.2)(typescript@7.0.2) + '@commitlint/load': 21.2.0(@types/node@26.2.0)(typescript@7.0.2) '@commitlint/read': 21.2.1(conventional-commits-parser@7.1.1) '@commitlint/types': 21.2.0 tinyexec: 1.0.2 @@ -3102,14 +3102,14 @@ snapshots: '@commitlint/rules': 21.2.0 '@commitlint/types': 21.2.0 - '@commitlint/load@21.2.0(@types/node@26.1.2)(typescript@7.0.2)': + '@commitlint/load@21.2.0(@types/node@26.2.0)(typescript@7.0.2)': dependencies: '@commitlint/config-validator': 21.2.0 '@commitlint/execute-rule': 21.0.1 '@commitlint/resolve-extends': 21.2.0 '@commitlint/types': 21.2.0 cosmiconfig: 9.0.1(typescript@7.0.2) - cosmiconfig-typescript-loader: 6.2.0(@types/node@26.1.2)(cosmiconfig@9.0.1(typescript@7.0.2))(typescript@7.0.2) + cosmiconfig-typescript-loader: 6.2.0(@types/node@26.2.0)(cosmiconfig@9.0.1(typescript@7.0.2))(typescript@7.0.2) es-toolkit: 1.50.0 is-plain-obj: 4.1.0 picocolors: 1.1.1 @@ -3336,122 +3336,122 @@ snapshots: '@inquirer/ansi@2.0.7': {} - '@inquirer/checkbox@5.2.1(@types/node@26.1.2)': + '@inquirer/checkbox@5.2.1(@types/node@26.2.0)': dependencies: '@inquirer/ansi': 2.0.7 - '@inquirer/core': 11.2.1(@types/node@26.1.2) + '@inquirer/core': 11.2.1(@types/node@26.2.0) '@inquirer/figures': 2.0.7 - '@inquirer/type': 4.0.7(@types/node@26.1.2) + '@inquirer/type': 4.0.7(@types/node@26.2.0) optionalDependencies: - '@types/node': 26.1.2 + '@types/node': 26.2.0 - '@inquirer/confirm@6.1.1(@types/node@26.1.2)': + '@inquirer/confirm@6.1.1(@types/node@26.2.0)': dependencies: - '@inquirer/core': 11.2.1(@types/node@26.1.2) - '@inquirer/type': 4.0.7(@types/node@26.1.2) + '@inquirer/core': 11.2.1(@types/node@26.2.0) + '@inquirer/type': 4.0.7(@types/node@26.2.0) optionalDependencies: - '@types/node': 26.1.2 + '@types/node': 26.2.0 - '@inquirer/core@11.2.1(@types/node@26.1.2)': + '@inquirer/core@11.2.1(@types/node@26.2.0)': dependencies: '@inquirer/ansi': 2.0.7 '@inquirer/figures': 2.0.7 - '@inquirer/type': 4.0.7(@types/node@26.1.2) + '@inquirer/type': 4.0.7(@types/node@26.2.0) cli-width: 4.1.0 fast-wrap-ansi: 0.2.2 mute-stream: 3.0.0 signal-exit: 4.1.0 optionalDependencies: - '@types/node': 26.1.2 + '@types/node': 26.2.0 - '@inquirer/editor@5.2.2(@types/node@26.1.2)': + '@inquirer/editor@5.2.2(@types/node@26.2.0)': dependencies: - '@inquirer/core': 11.2.1(@types/node@26.1.2) - '@inquirer/external-editor': 3.0.3(@types/node@26.1.2) - '@inquirer/type': 4.0.7(@types/node@26.1.2) + '@inquirer/core': 11.2.1(@types/node@26.2.0) + '@inquirer/external-editor': 3.0.3(@types/node@26.2.0) + '@inquirer/type': 4.0.7(@types/node@26.2.0) optionalDependencies: - '@types/node': 26.1.2 + '@types/node': 26.2.0 - '@inquirer/expand@5.1.1(@types/node@26.1.2)': + '@inquirer/expand@5.1.1(@types/node@26.2.0)': dependencies: - '@inquirer/core': 11.2.1(@types/node@26.1.2) - '@inquirer/type': 4.0.7(@types/node@26.1.2) + '@inquirer/core': 11.2.1(@types/node@26.2.0) + '@inquirer/type': 4.0.7(@types/node@26.2.0) optionalDependencies: - '@types/node': 26.1.2 + '@types/node': 26.2.0 - '@inquirer/external-editor@3.0.3(@types/node@26.1.2)': + '@inquirer/external-editor@3.0.3(@types/node@26.2.0)': dependencies: chardet: 2.2.0 iconv-lite: 0.7.3 optionalDependencies: - '@types/node': 26.1.2 + '@types/node': 26.2.0 '@inquirer/figures@2.0.7': {} - '@inquirer/input@5.1.2(@types/node@26.1.2)': + '@inquirer/input@5.1.2(@types/node@26.2.0)': dependencies: - '@inquirer/core': 11.2.1(@types/node@26.1.2) - '@inquirer/type': 4.0.7(@types/node@26.1.2) + '@inquirer/core': 11.2.1(@types/node@26.2.0) + '@inquirer/type': 4.0.7(@types/node@26.2.0) optionalDependencies: - '@types/node': 26.1.2 + '@types/node': 26.2.0 - '@inquirer/number@4.1.1(@types/node@26.1.2)': + '@inquirer/number@4.1.1(@types/node@26.2.0)': dependencies: - '@inquirer/core': 11.2.1(@types/node@26.1.2) - '@inquirer/type': 4.0.7(@types/node@26.1.2) + '@inquirer/core': 11.2.1(@types/node@26.2.0) + '@inquirer/type': 4.0.7(@types/node@26.2.0) optionalDependencies: - '@types/node': 26.1.2 + '@types/node': 26.2.0 - '@inquirer/password@5.1.1(@types/node@26.1.2)': + '@inquirer/password@5.1.1(@types/node@26.2.0)': dependencies: '@inquirer/ansi': 2.0.7 - '@inquirer/core': 11.2.1(@types/node@26.1.2) - '@inquirer/type': 4.0.7(@types/node@26.1.2) + '@inquirer/core': 11.2.1(@types/node@26.2.0) + '@inquirer/type': 4.0.7(@types/node@26.2.0) optionalDependencies: - '@types/node': 26.1.2 - - '@inquirer/prompts@8.5.2(@types/node@26.1.2)': - dependencies: - '@inquirer/checkbox': 5.2.1(@types/node@26.1.2) - '@inquirer/confirm': 6.1.1(@types/node@26.1.2) - '@inquirer/editor': 5.2.2(@types/node@26.1.2) - '@inquirer/expand': 5.1.1(@types/node@26.1.2) - '@inquirer/input': 5.1.2(@types/node@26.1.2) - '@inquirer/number': 4.1.1(@types/node@26.1.2) - '@inquirer/password': 5.1.1(@types/node@26.1.2) - '@inquirer/rawlist': 5.3.1(@types/node@26.1.2) - '@inquirer/search': 4.2.1(@types/node@26.1.2) - '@inquirer/select': 5.2.1(@types/node@26.1.2) + '@types/node': 26.2.0 + + '@inquirer/prompts@8.5.2(@types/node@26.2.0)': + dependencies: + '@inquirer/checkbox': 5.2.1(@types/node@26.2.0) + '@inquirer/confirm': 6.1.1(@types/node@26.2.0) + '@inquirer/editor': 5.2.2(@types/node@26.2.0) + '@inquirer/expand': 5.1.1(@types/node@26.2.0) + '@inquirer/input': 5.1.2(@types/node@26.2.0) + '@inquirer/number': 4.1.1(@types/node@26.2.0) + '@inquirer/password': 5.1.1(@types/node@26.2.0) + '@inquirer/rawlist': 5.3.1(@types/node@26.2.0) + '@inquirer/search': 4.2.1(@types/node@26.2.0) + '@inquirer/select': 5.2.1(@types/node@26.2.0) optionalDependencies: - '@types/node': 26.1.2 + '@types/node': 26.2.0 - '@inquirer/rawlist@5.3.1(@types/node@26.1.2)': + '@inquirer/rawlist@5.3.1(@types/node@26.2.0)': dependencies: - '@inquirer/core': 11.2.1(@types/node@26.1.2) - '@inquirer/type': 4.0.7(@types/node@26.1.2) + '@inquirer/core': 11.2.1(@types/node@26.2.0) + '@inquirer/type': 4.0.7(@types/node@26.2.0) optionalDependencies: - '@types/node': 26.1.2 + '@types/node': 26.2.0 - '@inquirer/search@4.2.1(@types/node@26.1.2)': + '@inquirer/search@4.2.1(@types/node@26.2.0)': dependencies: - '@inquirer/core': 11.2.1(@types/node@26.1.2) + '@inquirer/core': 11.2.1(@types/node@26.2.0) '@inquirer/figures': 2.0.7 - '@inquirer/type': 4.0.7(@types/node@26.1.2) + '@inquirer/type': 4.0.7(@types/node@26.2.0) optionalDependencies: - '@types/node': 26.1.2 + '@types/node': 26.2.0 - '@inquirer/select@5.2.1(@types/node@26.1.2)': + '@inquirer/select@5.2.1(@types/node@26.2.0)': dependencies: '@inquirer/ansi': 2.0.7 - '@inquirer/core': 11.2.1(@types/node@26.1.2) + '@inquirer/core': 11.2.1(@types/node@26.2.0) '@inquirer/figures': 2.0.7 - '@inquirer/type': 4.0.7(@types/node@26.1.2) + '@inquirer/type': 4.0.7(@types/node@26.2.0) optionalDependencies: - '@types/node': 26.1.2 + '@types/node': 26.2.0 - '@inquirer/type@4.0.7(@types/node@26.1.2)': + '@inquirer/type@4.0.7(@types/node@26.2.0)': optionalDependencies: - '@types/node': 26.1.2 + '@types/node': 26.2.0 '@isaacs/cliui@8.0.2': dependencies: @@ -3726,9 +3726,9 @@ snapshots: tslib: 2.8.1 typed-inject: 5.0.0 - '@stryker-mutator/core@9.6.1(@types/node@26.1.2)': + '@stryker-mutator/core@9.6.1(@types/node@26.2.0)': dependencies: - '@inquirer/prompts': 8.5.2(@types/node@26.1.2) + '@inquirer/prompts': 8.5.2(@types/node@26.2.0) '@stryker-mutator/api': 9.6.1 '@stryker-mutator/instrumenter': 9.6.1 '@stryker-mutator/util': 9.6.1 @@ -3777,14 +3777,14 @@ snapshots: '@stryker-mutator/util@9.6.1': {} - '@stryker-mutator/vitest-runner@9.6.1(@stryker-mutator/core@9.6.1(@types/node@26.1.2))(vitest@3.2.6(@types/node@26.1.2))': + '@stryker-mutator/vitest-runner@9.6.1(@stryker-mutator/core@9.6.1(@types/node@26.2.0))(vitest@3.2.6(@types/node@26.2.0))': dependencies: '@stryker-mutator/api': 9.6.1 - '@stryker-mutator/core': 9.6.1(@types/node@26.1.2) + '@stryker-mutator/core': 9.6.1(@types/node@26.2.0) '@stryker-mutator/util': 9.6.1 semver: 7.7.4 tslib: 2.8.1 - vitest: 3.2.6(@types/node@26.1.2) + vitest: 3.2.6(@types/node@26.2.0) '@tybys/wasm-util@0.10.3': dependencies: @@ -3800,7 +3800,7 @@ snapshots: '@types/estree@1.0.8': {} - '@types/node@26.1.2': + '@types/node@26.2.0': dependencies: undici-types: 8.3.0 @@ -3868,7 +3868,7 @@ snapshots: '@typescript/typescript-win32-x64@7.0.2': optional: true - '@vitest/coverage-v8@3.2.6(vitest@3.2.6(@types/node@26.1.2))': + '@vitest/coverage-v8@3.2.6(vitest@3.2.6(@types/node@26.2.0))': dependencies: '@ampproject/remapping': 2.3.0 '@bcoe/v8-coverage': 1.0.2 @@ -3883,7 +3883,7 @@ snapshots: std-env: 3.10.0 test-exclude: 7.0.2 tinyrainbow: 2.0.0 - vitest: 3.2.6(@types/node@26.1.2) + vitest: 3.2.6(@types/node@26.2.0) transitivePeerDependencies: - supports-color @@ -3895,13 +3895,13 @@ snapshots: chai: 5.3.3 tinyrainbow: 2.0.0 - '@vitest/mocker@3.2.6(vite@5.4.21(@types/node@26.1.2))': + '@vitest/mocker@3.2.6(vite@5.4.21(@types/node@26.2.0))': dependencies: '@vitest/spy': 3.2.6 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 5.4.21(@types/node@26.1.2) + vite: 5.4.21(@types/node@26.2.0) '@vitest/pretty-format@3.2.6': dependencies: @@ -4108,9 +4108,9 @@ snapshots: convert-to-spaces@2.0.1: {} - cosmiconfig-typescript-loader@6.2.0(@types/node@26.1.2)(cosmiconfig@9.0.1(typescript@7.0.2))(typescript@7.0.2): + cosmiconfig-typescript-loader@6.2.0(@types/node@26.2.0)(cosmiconfig@9.0.1(typescript@7.0.2))(typescript@7.0.2): dependencies: - '@types/node': 26.1.2 + '@types/node': 26.2.0 cosmiconfig: 9.0.1(typescript@7.0.2) jiti: 2.7.0 typescript: 7.0.2 @@ -5137,13 +5137,13 @@ snapshots: escalade: 3.2.0 picocolors: 1.1.1 - vite-node@3.2.4(@types/node@26.1.2): + vite-node@3.2.4(@types/node@26.2.0): dependencies: cac: 6.7.14 debug: 4.4.3 es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 5.4.21(@types/node@26.1.2) + vite: 5.4.21(@types/node@26.2.0) transitivePeerDependencies: - '@types/node' - less @@ -5155,20 +5155,20 @@ snapshots: - supports-color - terser - vite@5.4.21(@types/node@26.1.2): + vite@5.4.21(@types/node@26.2.0): dependencies: esbuild: 0.21.5 postcss: 8.5.15 rollup: 4.59.0 optionalDependencies: - '@types/node': 26.1.2 + '@types/node': 26.2.0 fsevents: 2.3.3 - vitest@3.2.6(@types/node@26.1.2): + vitest@3.2.6(@types/node@26.2.0): dependencies: '@types/chai': 5.2.3 '@vitest/expect': 3.2.6 - '@vitest/mocker': 3.2.6(vite@5.4.21(@types/node@26.1.2)) + '@vitest/mocker': 3.2.6(vite@5.4.21(@types/node@26.2.0)) '@vitest/pretty-format': 3.2.6 '@vitest/runner': 3.2.6 '@vitest/snapshot': 3.2.6 @@ -5186,11 +5186,11 @@ snapshots: tinyglobby: 0.2.15 tinypool: 1.1.1 tinyrainbow: 2.0.0 - vite: 5.4.21(@types/node@26.1.2) - vite-node: 3.2.4(@types/node@26.1.2) + vite: 5.4.21(@types/node@26.2.0) + vite-node: 3.2.4(@types/node@26.2.0) why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 26.1.2 + '@types/node': 26.2.0 transitivePeerDependencies: - less - lightningcss From d559063b30b783774748330e4a51eacca5104ca9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 20:58:04 +0000 Subject: [PATCH 07/14] chore(deps-dev): bump @biomejs/biome from 2.5.6 to 2.5.7 in /cli (#616) Bumps [@biomejs/biome](https://github.com/biomejs/biome/tree/HEAD/packages/@biomejs/biome) from 2.5.6 to 2.5.7. - [Release notes](https://github.com/biomejs/biome/releases) - [Changelog](https://github.com/biomejs/biome/blob/main/packages/@biomejs/biome/CHANGELOG.md) - [Commits](https://github.com/biomejs/biome/commits/@biomejs/biome@2.5.7/packages/@biomejs/biome) --- updated-dependencies: - dependency-name: "@biomejs/biome" dependency-version: 2.5.7 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- cli/pnpm-lock.yaml | 72 +++++++++++++++++++++++----------------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/cli/pnpm-lock.yaml b/cli/pnpm-lock.yaml index 12cfb2f5..606d1345 100644 --- a/cli/pnpm-lock.yaml +++ b/cli/pnpm-lock.yaml @@ -47,7 +47,7 @@ importers: devDependencies: '@biomejs/biome': specifier: ^2.4.7 - version: 2.5.6 + version: 2.5.7 '@commitlint/cli': specifier: ^21.2.1 version: 21.2.1(@types/node@26.2.0)(conventional-commits-parser@7.1.1)(typescript@7.0.2) @@ -261,55 +261,55 @@ packages: resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==} engines: {node: '>=18'} - '@biomejs/biome@2.5.6': - resolution: {integrity: sha512-lxVNjv7UF6KfhMJfL9gaUHbWdJdHbsAj6OSmwSYNdhRuG67NxNQ4Xdvh3TUxsSK9sBzJBQhEJj3AopmmNJ5pSA==} + '@biomejs/biome@2.5.7': + resolution: {integrity: sha512-zr8K/DcY5tYsQOQwqMJ0AWElo6QgmgNI7idXgXLhevVszlt8RGVpesEJPqx3ThazLaOwjJ5Y8fz3BtH5fGZNsw==} engines: {node: '>=14.21.3'} hasBin: true - '@biomejs/cli-darwin-arm64@2.5.6': - resolution: {integrity: sha512-zMOLZP4oMrjh6m1zcSj1ud2awUPgTuMVbmQhYYWL7J8HwCnbHHBvTm7VBTRuY7epT5bez76IpKYQ11ZAqHFlnw==} + '@biomejs/cli-darwin-arm64@2.5.7': + resolution: {integrity: sha512-vxo/Ls3/PYdQWyLhYYcgMOCzQypAjcY+iihS8M0wW03l16TCLW4zqZzGo75gm1VdCMj38hTVZ31KBWrZ4G9dJw==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [darwin] - '@biomejs/cli-darwin-x64@2.5.6': - resolution: {integrity: sha512-JAC1VqzvO7Th5ZplU0G2uGfkZbxEe9uDDektPAhF0JLusoz1w+T4okp2bkykI0bbaO2vslKiRfj4gU43JaGreA==} + '@biomejs/cli-darwin-x64@2.5.7': + resolution: {integrity: sha512-Cd3Ga61amT/Yl/0x8elP5hhGYaFy4bw6WuysTgf7oo8TA5tJ5A1k+DkVoJ2BHbTVil51gTX9VPzArnrlLJ3Kyg==} engines: {node: '>=14.21.3'} cpu: [x64] os: [darwin] - '@biomejs/cli-linux-arm64-musl@2.5.6': - resolution: {integrity: sha512-eUa3jeeYvfMt19LBeh6E5PUZpxnTC4JqNWo+EDjTtQjAr2xLGnWaxACtVU1DQqmHYbvThlJzLX+ZsYgrqh2qVw==} + '@biomejs/cli-linux-arm64-musl@2.5.7': + resolution: {integrity: sha512-xPI5yB6XlpDbNkS+bm1t42olw5c4l3UrlOmLg7KtLJvjvkNF/1V4tnUgfkylGIeb3u/T+BzMGYqgQhzjAoJzuQ==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] - '@biomejs/cli-linux-arm64@2.5.6': - resolution: {integrity: sha512-6XsYwCFkp5sMxl85ffhgeGpGgs6A7dRYFnkceZ7WVxvycuTnGdD5xa534Z3xfrBQ0JCMK/mujT6ZNPJoghedwg==} + '@biomejs/cli-linux-arm64@2.5.7': + resolution: {integrity: sha512-rR2QE0yF2GYSuYuKIa7pKvODGJqnOH+2eDREAM8wV+mWKSkMQKdAp4zXEZfTaxY8PMoNONnpgSWcBCyLDPDOKg==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] - '@biomejs/cli-linux-x64-musl@2.5.6': - resolution: {integrity: sha512-2Vp13QdKysH3HIWLaYLhUUwbK+jbZonJD1K+Lr0d0RO4wH7mkYd43vJixEDm8cUWrowoRz4UUHF1nm9Ae7ym8A==} + '@biomejs/cli-linux-x64-musl@2.5.7': + resolution: {integrity: sha512-rE5VZi+qtmPgQH+l7jVxYoZ18b/TiHEhulhMpjmCZH1PltSbjRcxNWywC3HZ9tYottG7ORkeTtoscBilKSBm0g==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] - '@biomejs/cli-linux-x64@2.5.6': - resolution: {integrity: sha512-Pop9VXCFUhFTMfFefZ39S+u2rOPyNp5iHlxbZRwXGACHLy2r0jjiRgJHmaEKJzL3SyxlVeGShXhvvElvWowonA==} + '@biomejs/cli-linux-x64@2.5.7': + resolution: {integrity: sha512-FQgqJhscrqJUFptGaRSUJWlXAExwWcDwLuK49dvKfkQ1bB5SEEyFssnsxQY83Xm6jR0EbbX3+8+D5bfvYqUG2Q==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] - '@biomejs/cli-win32-arm64@2.5.6': - resolution: {integrity: sha512-tDGshcm6BdkZOCGnTDX0Y8/U4IfBSlnUU7T56nNDuPEfed+aHg+u8G36NB43fJVl0Os6+QURXIE1yuD7AaEofA==} + '@biomejs/cli-win32-arm64@2.5.7': + resolution: {integrity: sha512-Oq4x0CCwP4jirrcTywXs5kOGZ4v5vuEP+gWrbtjApOA2CL9F3F9GlIdQIci8AKSCa/zURanMRpX/4wQ7Am6hHg==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [win32] - '@biomejs/cli-win32-x64@2.5.6': - resolution: {integrity: sha512-WN05KwXnTO/2J45RQPvzZMXf7tZUIofHoR35xIPfCo7pQ2RFidxI8sfb5mGsaTxdMmEOzHzOPRCdA5/fCpc7xQ==} + '@biomejs/cli-win32-x64@2.5.7': + resolution: {integrity: sha512-V+0wu/nrj2S+MhP4EQ0uHNolP0IALEsz45pg0WoKkHfDeh0+ItHwP/p7bX5RPoMOl9NkpHYWdYPhIcy2mACHvQ==} engines: {node: '>=14.21.3'} cpu: [x64] os: [win32] @@ -3014,39 +3014,39 @@ snapshots: '@bcoe/v8-coverage@1.0.2': {} - '@biomejs/biome@2.5.6': + '@biomejs/biome@2.5.7': optionalDependencies: - '@biomejs/cli-darwin-arm64': 2.5.6 - '@biomejs/cli-darwin-x64': 2.5.6 - '@biomejs/cli-linux-arm64': 2.5.6 - '@biomejs/cli-linux-arm64-musl': 2.5.6 - '@biomejs/cli-linux-x64': 2.5.6 - '@biomejs/cli-linux-x64-musl': 2.5.6 - '@biomejs/cli-win32-arm64': 2.5.6 - '@biomejs/cli-win32-x64': 2.5.6 + '@biomejs/cli-darwin-arm64': 2.5.7 + '@biomejs/cli-darwin-x64': 2.5.7 + '@biomejs/cli-linux-arm64': 2.5.7 + '@biomejs/cli-linux-arm64-musl': 2.5.7 + '@biomejs/cli-linux-x64': 2.5.7 + '@biomejs/cli-linux-x64-musl': 2.5.7 + '@biomejs/cli-win32-arm64': 2.5.7 + '@biomejs/cli-win32-x64': 2.5.7 - '@biomejs/cli-darwin-arm64@2.5.6': + '@biomejs/cli-darwin-arm64@2.5.7': optional: true - '@biomejs/cli-darwin-x64@2.5.6': + '@biomejs/cli-darwin-x64@2.5.7': optional: true - '@biomejs/cli-linux-arm64-musl@2.5.6': + '@biomejs/cli-linux-arm64-musl@2.5.7': optional: true - '@biomejs/cli-linux-arm64@2.5.6': + '@biomejs/cli-linux-arm64@2.5.7': optional: true - '@biomejs/cli-linux-x64-musl@2.5.6': + '@biomejs/cli-linux-x64-musl@2.5.7': optional: true - '@biomejs/cli-linux-x64@2.5.6': + '@biomejs/cli-linux-x64@2.5.7': optional: true - '@biomejs/cli-win32-arm64@2.5.6': + '@biomejs/cli-win32-arm64@2.5.7': optional: true - '@biomejs/cli-win32-x64@2.5.6': + '@biomejs/cli-win32-x64@2.5.7': optional: true '@colors/colors@1.5.0': From 53119262f26400a3c9a1af9339d4c5149d776e63 Mon Sep 17 00:00:00 2001 From: Baptiste LAFOURCADE <119650761+blafourcade@users.noreply.github.com> Date: Wed, 12 Aug 2026 09:02:50 +0200 Subject: [PATCH 08/14] fix(aidd-context): make 10-learn's recommendation step consistent (#622) fix(aidd-context): make 10-learn's recommendation step consistent and enforce scope The confirm step rendered differently every run (full table, bare list, or an approval prompt with nothing shown first) and sometimes proposed learnings outside the current PR or logged a fixed bug as a decision. - assess always fills a fixed recommendation-table asset (Packet/Score/ Destination/Reconciliation, one bare value per cell) before asking approve/modify/skip, never the reverse - gather drops signals outside the source's scope and bugs fixed without an explicit request to remember them - destinations gain a `contract` case (amend an existing project contract file directly, e.g. skill-authoring.md) and reconciliation gains `retracts` (remove, no replacement), each with a real apply rule - write-report asset gives 04-write a fixed add/modify/remove report, matching the emoji convention already used in 01-plan - dedup pass across router/actions/references: removed restated rules, merged near-duplicate destination rows, closed a gap where the assess step never emitted a source scope for gather to filter against Fixes #561 Co-authored-by: Claude Sonnet 5 --- plugins/aidd-context/CATALOG.md | 2 ++ plugins/aidd-context/skills/10-learn/SKILL.md | 8 +++-- .../skills/10-learn/actions/01-source.md | 4 +-- .../skills/10-learn/actions/03-assess.md | 10 +++++-- .../skills/10-learn/actions/04-write.md | 10 ++++--- .../skills/10-learn/actions/05-sync.md | 2 +- .../skills/10-learn/assets/learning-packet.md | 8 ++--- .../10-learn/assets/recommendation-table.md | 5 ++++ .../skills/10-learn/assets/write-report.md | 7 +++++ .../skills/10-learn/references/assessment.md | 3 +- .../10-learn/references/destinations.md | 15 +++++++--- .../10-learn/references/gather-protocol.md | 29 +++++++++---------- .../10-learn/references/review-protocol.md | 4 +-- .../skills/10-learn/references/sources.md | 3 +- 14 files changed, 70 insertions(+), 40 deletions(-) create mode 100644 plugins/aidd-context/skills/10-learn/assets/recommendation-table.md create mode 100644 plugins/aidd-context/skills/10-learn/assets/write-report.md diff --git a/plugins/aidd-context/CATALOG.md b/plugins/aidd-context/CATALOG.md index f59078fd..8e17421e 100644 --- a/plugins/aidd-context/CATALOG.md +++ b/plugins/aidd-context/CATALOG.md @@ -180,6 +180,8 @@ Auto-generated index of skills, agents, references and assets shipped by the `ai | `actions` | [05-sync.md](skills/10-learn/actions/05-sync.md) | - | | `assets` | [adr-template.md](skills/10-learn/assets/adr-template.md) | - | | `assets` | [learning-packet.md](skills/10-learn/assets/learning-packet.md) | - | +| `assets` | [recommendation-table.md](skills/10-learn/assets/recommendation-table.md) | - | +| `assets` | [write-report.md](skills/10-learn/assets/write-report.md) | - | | `references` | [assessment.md](skills/10-learn/references/assessment.md) | - | | `references` | [destinations.md](skills/10-learn/references/destinations.md) | - | | `references` | [gather-protocol.md](skills/10-learn/references/gather-protocol.md) | - | diff --git a/plugins/aidd-context/skills/10-learn/SKILL.md b/plugins/aidd-context/skills/10-learn/SKILL.md index d80b29b5..8e1c5e63 100644 --- a/plugins/aidd-context/skills/10-learn/SKILL.md +++ b/plugins/aidd-context/skills/10-learn/SKILL.md @@ -8,8 +8,12 @@ argument-hint: conversation | file | diff | review ```mermaid flowchart LR source --> gather --> assess --> write + source -->|"missing, empty, or ambiguous"| sourceStop([stop]) + gather -->|"no candidates"| gatherEnd([end]) + assess -->|"all covered"| assessEnd([end]) write -->|"memory or ADR"| sync write -->|"rule or skill"| handoff([handoff]) + sync -->|"failure"| syncStop([stop]) ``` ## Actions @@ -20,7 +24,7 @@ Run the flow above. Read only the next action file. | ------ | ---- | | source | identify and challenge the origin | | gather | read the origin and extract candidates | -| assess | score, reconcile, and confirm | +| assess | score, reconcile, show, and confirm | | write | write or hand off approved lessons | | sync | refresh memory references | @@ -28,4 +32,4 @@ Run the flow above. Read only the next action file. - Write only the user-approved plan. - Preserve user edits and touch affected files only. -- Write project files only, never personal or global memory, never scaffold `aidd_docs/memory/` yourself. +- Write project files only, never personal or global memory. diff --git a/plugins/aidd-context/skills/10-learn/actions/01-source.md b/plugins/aidd-context/skills/10-learn/actions/01-source.md index 941ef431..4ad8d293 100644 --- a/plugins/aidd-context/skills/10-learn/actions/01-source.md +++ b/plugins/aidd-context/skills/10-learn/actions/01-source.md @@ -16,11 +16,11 @@ One or more source descriptions that name where to look and how narrowly to read 2. **Select.** Select the smallest readable source set that fits the current context. 3. **Ask.** Ask only when the source choice would change what gets learned. 4. **Stop.** Stop on a missing, empty, or ambiguous source. -5. **Emit.** Emit the selected source descriptions. +5. **Emit.** Emit each source's kind, label, and scope. ## Test | Case | Pass | | --- | --- | -| A source is readable | one or more source descriptions are emitted | +| A source is readable | one or more sources are emitted, each with kind, label, and scope | | A source cannot be read | the run stops and names it | diff --git a/plugins/aidd-context/skills/10-learn/actions/03-assess.md b/plugins/aidd-context/skills/10-learn/actions/03-assess.md index aba6ea35..e908a57f 100644 --- a/plugins/aidd-context/skills/10-learn/actions/03-assess.md +++ b/plugins/aidd-context/skills/10-learn/actions/03-assess.md @@ -12,9 +12,10 @@ A learning plan approved by the user and ready to write. ## Process -1. **Frame.** Apply [assessment](../references/assessment.md), then use [destinations](../references/destinations.md) to propose where each candidate should land. -2. **Score.** Score each candidate and reconcile existing coverage. -3. **Confirm.** Show the scored recommendation and ask which packets to approve, edit, redirect, or skip. +1. **Score.** Apply [assessment](../references/assessment.md) and [destinations](../references/destinations.md): reason internally to a 0-10 score, reconcile existing coverage, and propose where it lands. +2. **Show.** State the source in one line, then fill and show the [recommendation table](../assets/recommendation-table.md). +3. **Confirm.** Ask, per packet: approve, modify, or skip. + - When every packet is covered, skip the question. 4. **Fill.** Fill [learning packet](../assets/learning-packet.md) for approved items only. ## Test @@ -23,3 +24,6 @@ A learning plan approved by the user and ready to write. | --- | --- | | A packet is approved | it carries score, approved destination, reconciliation, and user approval | | An item is skipped or already covered | it is not written | +| The confirm step runs | only the source line and the table appear before it | +| The confirm question is asked | it names approve, modify, and skip | +| Every candidate is covered | the run ends, nothing is asked | diff --git a/plugins/aidd-context/skills/10-learn/actions/04-write.md b/plugins/aidd-context/skills/10-learn/actions/04-write.md index 8d629aad..075f0913 100644 --- a/plugins/aidd-context/skills/10-learn/actions/04-write.md +++ b/plugins/aidd-context/skills/10-learn/actions/04-write.md @@ -12,11 +12,12 @@ The created or updated files, and a summary table. ## Process -1. **Start.** Start from the approved learning packet. -2. **Route.** Apply only the destination path in [destinations](../references/destinations.md). -3. **Fill.** Load the destination asset when one is required, fill it from the packet, and strip its guidance comment. +1. **Start.** Start from each approved learning packet. +2. **Route.** Apply the destination and reconciliation rules in [destinations](../references/destinations.md). +3. **Fill.** Load the destination asset when one is required and follow its instructions. + - For a retraction, remove the entry instead of filling one. 4. **Review.** Apply [review protocol](../references/review-protocol.md) to every touched file or handoff. -5. **Report.** Report packet, destination, action, file or handoff, and review verdict. +5. **Report.** Fill [write report](../assets/write-report.md) grouped by destination. ## Test @@ -25,3 +26,4 @@ The created or updated files, and a summary table. | A lesson is approved | it appears in the table, at the destination the user chose | | A packet has no user approval | it is neither written nor handed off | | The report is delivered | it carries a review verdict for every touched file and handoff | +| A candidate retracts existing content | the entry is removed, not left in place with a note | diff --git a/plugins/aidd-context/skills/10-learn/actions/05-sync.md b/plugins/aidd-context/skills/10-learn/actions/05-sync.md index 393c3866..441baa33 100644 --- a/plugins/aidd-context/skills/10-learn/actions/05-sync.md +++ b/plugins/aidd-context/skills/10-learn/actions/05-sync.md @@ -4,7 +4,7 @@ Refresh context references after memory or ADR writes. ## Input -The write summary, confirming at least one memory or ADR file changed. Skip this action when write only handed off rules or skills. +The write summary, confirming at least one memory or ADR file changed. ## Output diff --git a/plugins/aidd-context/skills/10-learn/assets/learning-packet.md b/plugins/aidd-context/skills/10-learn/assets/learning-packet.md index 7615f4b8..1d76fe0a 100644 --- a/plugins/aidd-context/skills/10-learn/assets/learning-packet.md +++ b/plugins/aidd-context/skills/10-learn/assets/learning-packet.md @@ -6,8 +6,8 @@ - Source: - Evidence: - Score: <0-10 + reason> -- Destination: -- Reconciliation: -- User approval: -- Scope: +- Destination: +- Reconciliation: +- User approval: +- Applies to: - Request: diff --git a/plugins/aidd-context/skills/10-learn/assets/recommendation-table.md b/plugins/aidd-context/skills/10-learn/assets/recommendation-table.md new file mode 100644 index 00000000..0e32dbe9 --- /dev/null +++ b/plugins/aidd-context/skills/10-learn/assets/recommendation-table.md @@ -0,0 +1,5 @@ + + +| Packet | Score | Destination | Reconciliation | +| --- | --- | --- | --- | +| | <0-10> | <memory \| ADR \| contract: \<file\> \| rule \| skill> | <✅ new \| covered \| ✏️ updates \| ✏️ supersedes \| ❌ retracts> | diff --git a/plugins/aidd-context/skills/10-learn/assets/write-report.md b/plugins/aidd-context/skills/10-learn/assets/write-report.md new file mode 100644 index 00000000..b867a42a --- /dev/null +++ b/plugins/aidd-context/skills/10-learn/assets/write-report.md @@ -0,0 +1,7 @@ +<!-- Group rows by destination, one row per touched file or handoff, then strip this comment. --> + +### <memory | ADR | contract | rule | skill> + +| Action | File | Lesson | Review | +| --- | --- | --- | --- | +| <✅ add \| ✏️ modify \| ❌ remove> | <path, "new" when created> | <the lesson written> | <verdict> | diff --git a/plugins/aidd-context/skills/10-learn/references/assessment.md b/plugins/aidd-context/skills/10-learn/references/assessment.md index 4dd0edca..15e290b3 100644 --- a/plugins/aidd-context/skills/10-learn/references/assessment.md +++ b/plugins/aidd-context/skills/10-learn/references/assessment.md @@ -21,4 +21,5 @@ Reconcile before approval: - `new`: no equivalent content exists. - `covered`: existing content already carries it. - `updates`: refine an existing memory, rule, ADR, or skill. -- `supersedes`: reverses an earlier decision or rule; require an explicit link. +- `supersedes`: reverses an earlier decision or rule. +- `retracts`: existing content no longer holds and nothing replaces it. diff --git a/plugins/aidd-context/skills/10-learn/references/destinations.md b/plugins/aidd-context/skills/10-learn/references/destinations.md index cfc0b610..cf7f8a5b 100644 --- a/plugins/aidd-context/skills/10-learn/references/destinations.md +++ b/plugins/aidd-context/skills/10-learn/references/destinations.md @@ -6,15 +6,22 @@ Every destination starts from the approved learning packet. | ----------- | -------- | ----- | | memory | durable project fact, convention, or gotcha | write the packet into the matching memory entry | | ADR | explicit choice with context and consequences | write the packet to `aidd_docs/memory/internal/decisions/<slug>.md` through [ADR template](../assets/adr-template.md) | -| rule | enforceable coding or agent behavior | send the packet to rule-generate | +| contract | enforceable behavior already owned by an existing project contract file | write the packet by amending that file | +| rule | enforceable coding or agent behavior with no existing owner | send the packet to rule-generate | | skill | reusable workflow worth a dedicated skill | send the packet to skill-generate | +Reconciliation: + +| Value | Apply | +| --- | --- | +| updates | replace the existing entry; do not add contradictions | +| supersedes | replace the entry; link both decision records for an ADR | +| retracts | remove the entry; delete the file only when nothing remains | + Rules: - If the project memory bank is missing, say what is missing and ask before handing off to project-memory. - If the destination structure is unclear, ask. Do not invent a new taxonomy. -- Replace superseded entries. Do not add contradictions. -- For ADR supersession, link both decision records. - Prefer the narrowest destination that can own the lesson. - The user may choose another destination after seeing the recommendation. -- Learn writes memory and ADRs. Learn hands off rules and skills. +- Write memory, ADRs, and contract amendments directly. Hand off rules and skills. diff --git a/plugins/aidd-context/skills/10-learn/references/gather-protocol.md b/plugins/aidd-context/skills/10-learn/references/gather-protocol.md index eba80bc0..8ad63195 100644 --- a/plugins/aidd-context/skills/10-learn/references/gather-protocol.md +++ b/plugins/aidd-context/skills/10-learn/references/gather-protocol.md @@ -2,21 +2,20 @@ Extract only durable project learning. -Keep: - -- Decision, tradeoff, or consequence. -- Convention or recurring project rule. -- Pitfall, failed path, or costly pivot. -- Reusable workflow worth documenting or automating. -- Missing context that should prevent the same confusion later. - -Drop: - -- Personal preferences. -- AI behavior preferences. -- Routine implementation details. -- One-off facts with no reuse. -- Items already obviously covered by the source itself. +| Signal | Verdict | +| --- | --- | +| Decision, tradeoff, or consequence | Keep | +| Convention or recurring project rule | Keep | +| Pitfall, failed path, or costly pivot | Keep | +| Reusable workflow worth documenting or automating | Keep | +| Missing context that should prevent the same confusion later | Keep | +| Personal preference | Drop | +| AI behavior preference | Drop | +| Routine implementation detail | Drop | +| One-off fact with no reuse | Drop | +| Item already obviously covered by the source itself | Drop | +| Signal outside the selected source's scope, even when noticed while reading | Drop | +| Bug already fixed as part of the current change, unless the user explicitly asked to remember it as a decision | Drop | For each candidate, include: diff --git a/plugins/aidd-context/skills/10-learn/references/review-protocol.md b/plugins/aidd-context/skills/10-learn/references/review-protocol.md index f5ee71c2..f8b5ef28 100644 --- a/plugins/aidd-context/skills/10-learn/references/review-protocol.md +++ b/plugins/aidd-context/skills/10-learn/references/review-protocol.md @@ -7,7 +7,7 @@ Check: - The approved packet is represented. - No duplicate or contradictory entry was added. - Superseded ADRs or rules point to the newer decision. +- A retracted entry is gone, not just marked. +- A contract amendment lands in the file the packet names. - Memory and ADR references are synced when those destinations changed. - Rule and skill handoffs carry the approved packet and name the target generator. - -Do not expand scope into unrelated project cleanup. diff --git a/plugins/aidd-context/skills/10-learn/references/sources.md b/plugins/aidd-context/skills/10-learn/references/sources.md index 3d4e7f9e..7fa839b1 100644 --- a/plugins/aidd-context/skills/10-learn/references/sources.md +++ b/plugins/aidd-context/skills/10-learn/references/sources.md @@ -18,9 +18,8 @@ Kind meaning: Selection: - Explicit hint narrows the source kind. -- No hint defaults to the current conversation, same as before this skill could take an explicit pointer. +- No hint defaults to the current conversation. - Multiple specs are allowed when one source cannot explain the learning alone. -- Ask before continuing when several source sets are plausible. Limits: From c584da0f58afdc13d4dbf955b7463ec7b8cbda6d Mon Sep 17 00:00:00 2001 From: Baptiste LAFOURCADE <119650761+blafourcade@users.noreply.github.com> Date: Thu, 13 Aug 2026 07:19:15 +0200 Subject: [PATCH 09/14] feat(refine): remove condense skill and its hook (#624) The condense skill duplicated a concern that belongs to the host tool's own output settings, and its `UserPromptSubmit` hook parsed a marker line the model emitted only inconsistently (see the eval harness's own "known findings" note). Rather than harden a best-effort mechanism, drop it. Removing `03-condense` frees the slot, so the two skills after it move up to keep the plugin's numbering contiguous. BREAKING CHANGE: `aidd-refine:03-condense` is removed, and the skills after it are renumbered: `04-shadow-areas` becomes `03-shadow-areas`, and `05-fact-check` becomes `04-fact-check`. Any pinned reference to the old names must be updated. The plugin no longer ships a hooks directory. Co-authored-by: Claude Opus 5 <noreply@anthropic.com> --- .claude-plugin/marketplace.json | 2 +- README.md | 8 +- aidd_docs/README.md | 4 +- docs/ARCHITECTURE.md | 1 - docs/CATALOG.md | 7 +- .../aidd-refine/.claude-plugin/plugin.json | 7 +- plugins/aidd-refine/CATALOG.md | 62 ++--- plugins/aidd-refine/README.md | 7 +- plugins/aidd-refine/hooks/condense-stats.js | 217 ------------------ plugins/aidd-refine/hooks/hooks.json | 14 -- .../aidd-refine/skills/03-condense/SKILL.md | 34 --- .../skills/03-condense/actions/01-condense.md | 27 --- .../skills/03-condense/actions/02-stats.md | 26 --- .../references/intensity-levels.md | 47 ---- .../SKILL.md | 2 +- .../actions/01-detect.md | 0 .../actions/02-render-report.md | 0 .../actions/03-diff.md | 0 .../assets/report-template.md | 0 .../references/categories.md | 0 .../references/locked-sets.json | 0 .../references/probe-style.md | 0 .../references/severity-rubric.md | 0 .../{05-fact-check => 04-fact-check}/SKILL.md | 2 +- .../actions/01-identify-claims.md | 0 .../actions/02-verify.md | 2 +- .../actions/03-report.md | 0 .../assets/report-template.md | 0 .../references/claim-categories.md | 0 .../references/report-output-discipline.md | 0 .../references/verification-cascade.md | 0 scripts/skill-eval.mjs | 2 +- scripts/skill-eval/README.md | 13 +- scripts/skill-eval/cases.json | 17 +- 34 files changed, 49 insertions(+), 452 deletions(-) delete mode 100644 plugins/aidd-refine/hooks/condense-stats.js delete mode 100644 plugins/aidd-refine/hooks/hooks.json delete mode 100644 plugins/aidd-refine/skills/03-condense/SKILL.md delete mode 100644 plugins/aidd-refine/skills/03-condense/actions/01-condense.md delete mode 100644 plugins/aidd-refine/skills/03-condense/actions/02-stats.md delete mode 100644 plugins/aidd-refine/skills/03-condense/references/intensity-levels.md rename plugins/aidd-refine/skills/{04-shadow-areas => 03-shadow-areas}/SKILL.md (99%) rename plugins/aidd-refine/skills/{04-shadow-areas => 03-shadow-areas}/actions/01-detect.md (100%) rename plugins/aidd-refine/skills/{04-shadow-areas => 03-shadow-areas}/actions/02-render-report.md (100%) rename plugins/aidd-refine/skills/{04-shadow-areas => 03-shadow-areas}/actions/03-diff.md (100%) rename plugins/aidd-refine/skills/{04-shadow-areas => 03-shadow-areas}/assets/report-template.md (100%) rename plugins/aidd-refine/skills/{04-shadow-areas => 03-shadow-areas}/references/categories.md (100%) rename plugins/aidd-refine/skills/{04-shadow-areas => 03-shadow-areas}/references/locked-sets.json (100%) rename plugins/aidd-refine/skills/{04-shadow-areas => 03-shadow-areas}/references/probe-style.md (100%) rename plugins/aidd-refine/skills/{04-shadow-areas => 03-shadow-areas}/references/severity-rubric.md (100%) rename plugins/aidd-refine/skills/{05-fact-check => 04-fact-check}/SKILL.md (99%) rename plugins/aidd-refine/skills/{05-fact-check => 04-fact-check}/actions/01-identify-claims.md (100%) rename plugins/aidd-refine/skills/{05-fact-check => 04-fact-check}/actions/02-verify.md (90%) rename plugins/aidd-refine/skills/{05-fact-check => 04-fact-check}/actions/03-report.md (100%) rename plugins/aidd-refine/skills/{05-fact-check => 04-fact-check}/assets/report-template.md (100%) rename plugins/aidd-refine/skills/{05-fact-check => 04-fact-check}/references/claim-categories.md (100%) rename plugins/aidd-refine/skills/{05-fact-check => 04-fact-check}/references/report-output-discipline.md (100%) rename plugins/aidd-refine/skills/{05-fact-check => 04-fact-check}/references/verification-cascade.md (100%) diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 72d3826b..d2adb050 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -45,7 +45,7 @@ { "name": "aidd-refine", "source": "./plugins/aidd-refine", - "description": "Meta-cognition: refine input through brainstorming, refine output through challenge and condensed communication mode.", + "description": "Meta-cognition: refine input through brainstorming, refine output through challenge, blind-spot scanning, and fact-checking.", "strict": true, "recommended": true }, diff --git a/README.md b/README.md index 62246e07..74777425 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ _(Already tested on `Legacy` codebases)_ [![Made in France](https://img.shields.io/badge/made%20in-France-0055A4?labelColor=EF4135)](https://www.ai-driven-dev.fr/) <p> - <!--counts:start--><kbd>7 plugins</kbd> · <kbd>48 skills</kbd> · <kbd>2 agents</kbd><!--counts:end--> · <kbd>MIT</kbd> + <!--counts:start--><kbd>7 plugins</kbd> · <kbd>47 skills</kbd> · <kbd>2 agents</kbd><!--counts:end--> · <kbd>MIT</kbd> </p> [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) @@ -36,7 +36,7 @@ Why not just write your own commands? → [FAQ](docs/FAQ.md#-why-aidd-instead-of ## ✅ Prerequisites - **An AI coding tool** — Claude Code (native), or Cursor / Copilot / Codex / OpenCode (see [Compatibility](#-compatibility)). -- **[Node](https://nodejs.org)** on your `PATH` — for the plugins that ship hooks ([what they do](docs/ARCHITECTURE.md#-bundled-hooks)). +- **[Node](https://nodejs.org)** on your `PATH` — for the plugin that ships hooks ([what they do](docs/ARCHITECTURE.md#-bundled-hooks)). ## 🔌 Compatibility @@ -257,9 +257,9 @@ Three Amigos refinement, Product Briefs, Epics, User Stories, Tasks, Spikes, Def ### 🪞 [aidd-refine](plugins/aidd-refine/README.md) -`5 skills` · stable +`4 skills` · stable -Brainstorm, challenge, condense, shadow-areas, fact-check. +Brainstorm, challenge, shadow-areas, fact-check. </td> <td width="33%" valign="top"> diff --git a/aidd_docs/README.md b/aidd_docs/README.md index 36dc7dc2..2f6c32ac 100644 --- a/aidd_docs/README.md +++ b/aidd_docs/README.md @@ -38,7 +38,7 @@ Skills are grouped into plugins by domain. Install only the plugins you need. | Plugin | Purpose | Example skills | | ----------------- | ---------------------------------------------------------------------------------- | ----------------------------------------------------------- | | aidd-context | Bootstrap, project init, generation of context artifacts (skills, agents, rules, commands, hooks, plugins, marketplaces), mermaid diagrams, learn, discovery | `02-project-memory`, `03-context-generate`, `09-mermaid` | -| aidd-refine | Meta-cognition: brainstorm, challenge prior work, condensed communication mode | `01-brainstorm`, `02-challenge`, `03-condense` | +| aidd-refine | Meta-cognition: brainstorm, challenge prior work, blind-spot scan, fact-check | `01-brainstorm`, `02-challenge`, `03-shadow-areas` | | aidd-pm | Product management: backlog artifacts, refinement, Product Briefs, PRD, spec | `02-user-stories`, `05-spike`, `07-epic`, `09-defect`, `10-task` | | aidd-dev | Code transformation: plan, implement, assert, audit, review, test, refactor, debug, for-sure | `01-plan`, `02-implement`, `05-review`, `06-test` | | aidd-vcs | VCS workflows: commit, pull/merge request, release tag, issue creation | `01-commit`, `02-pull-request`, `04-issue-create` | @@ -103,7 +103,7 @@ AIDD is delivered as a plugin marketplace. Pick what you need; do not install ev | Plugin | Skills | | ------------ | ------------------------------------------------------------------------------------------------------------------- | | aidd-context | 00-onboard, 01-bootstrap, 02-project-memory, 03-context-generate, 09-mermaid, 10-learn, 11-explore | -| aidd-refine | 01-brainstorm, 02-challenge, 03-condense, 04-shadow-areas, 05-fact-check | +| aidd-refine | 01-brainstorm, 02-challenge, 03-shadow-areas, 04-fact-check | | aidd-dev | 01-plan, 02-implement, 03-assert, 04-audit, 05-review, 06-test, 07-refactor, 08-debug, 09-for-sure, 10-todo | | aidd-orchestrator | 00-async-dev, 01-sdlc | | aidd-vcs | 01-commit, 02-pull-request, 03-release-tag, 04-issue-create | diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 0ac4be6c..56508cc0 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -40,7 +40,6 @@ Declared in `plugins/<plugin>/hooks/hooks.json`. They run Node, so users need `n | Plugin | Event | Runs | Purpose | | -------------- | ------------------ | ------------------------- | -------------------------------------------------------- | | `aidd-context` | `SessionStart` | `hooks/update_memory.js` | Refresh the project memory block in the AI context files | -| `aidd-refine` | `UserPromptSubmit` | `hooks/condense-stats.js` | Report token savings while condensed output mode is on | ## 🧠 Plugin concerns and layers diff --git a/docs/CATALOG.md b/docs/CATALOG.md index 273600a8..b2abe30d 100644 --- a/docs/CATALOG.md +++ b/docs/CATALOG.md @@ -69,15 +69,14 @@ Product backlog artifacts, refinement, Product Briefs, Epics, User Stories, Task ## 🪞 aidd-refine -Meta-cognition: brainstorm, challenge, condense, blind-spot scan, fact-check. +Meta-cognition: brainstorm, challenge, blind-spot scan, fact-check. | Skill | Role | Actions | | ------------------ | ---------------------------------------------------------- | --------------------------------------------------------------------------------------------- | | `01-brainstorm` | Clarify a vague product or technical intent through natural discovery | `01-capture`, `02-probe`, `03-integrate`, `04-finalize` | | `02-challenge` | Rethink prior work to verify correctness against a plan | `01-challenge` | -| `03-condense` | Toggle terse output mode and report token savings | `01-condense`, `02-stats` | -| `04-shadow-areas` | Scan a markdown artifact for blind spots | `01-detect`, `02-render-report`, `03-diff` | -| `05-fact-check` | Verify factual claims against sources and cite them | `01-identify-claims`, `02-verify`, `03-report` | +| `03-shadow-areas` | Scan a markdown artifact for blind spots | `01-detect`, `02-render-report`, `03-diff` | +| `04-fact-check` | Verify factual claims against sources and cite them | `01-identify-claims`, `02-verify`, `03-report` | ## 🌿 aidd-vcs diff --git a/plugins/aidd-refine/.claude-plugin/plugin.json b/plugins/aidd-refine/.claude-plugin/plugin.json index fde51cbe..7b7ef5e6 100644 --- a/plugins/aidd-refine/.claude-plugin/plugin.json +++ b/plugins/aidd-refine/.claude-plugin/plugin.json @@ -2,7 +2,7 @@ "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json", "name": "aidd-refine", "version": "2.2.4", - "description": "Meta-cognition: refine input through brainstorming, refine output through challenge and condensed communication mode.", + "description": "Meta-cognition: refine input through brainstorming, refine output through challenge, blind-spot scanning, and fact-checking.", "author": { "name": "AI-Driven Dev", "url": "https://github.com/ai-driven-dev" @@ -10,9 +10,8 @@ "skills": [ "./skills/01-brainstorm", "./skills/02-challenge", - "./skills/03-condense", - "./skills/04-shadow-areas", - "./skills/05-fact-check" + "./skills/03-shadow-areas", + "./skills/04-fact-check" ], "keywords": [ "brainstorm", diff --git a/plugins/aidd-refine/CATALOG.md b/plugins/aidd-refine/CATALOG.md index 7ecf3cd8..0f48fb44 100644 --- a/plugins/aidd-refine/CATALOG.md +++ b/plugins/aidd-refine/CATALOG.md @@ -7,13 +7,11 @@ Auto-generated index of skills, agents, references and assets shipped by the `ai ## Table of Contents - [`.claude-plugin`](#claude-plugin) -- [`hooks`](#hooks) - [`skills`](#skills) - [`skills/01-brainstorm`](#skills01-brainstorm) - [`skills/02-challenge`](#skills02-challenge) - - [`skills/03-condense`](#skills03-condense) - - [`skills/04-shadow-areas`](#skills04-shadow-areas) - - [`skills/05-fact-check`](#skills05-fact-check) + - [`skills/03-shadow-areas`](#skills03-shadow-areas) + - [`skills/04-fact-check`](#skills04-fact-check) --- @@ -23,13 +21,6 @@ Auto-generated index of skills, agents, references and assets shipped by the `ai |------| | [plugin.json](.claude-plugin/plugin.json) | -### `hooks` - -| File | -|------| -| [condense-stats.js](hooks/condense-stats.js) | -| [hooks.json](hooks/hooks.json) | - ### `skills` #### `skills/01-brainstorm` @@ -59,39 +50,30 @@ Auto-generated index of skills, agents, references and assets shipped by the `ai | `references` | [confidence-rubric.md](skills/02-challenge/references/confidence-rubric.md) | - | | `-` | [SKILL.md](skills/02-challenge/SKILL.md) | `Rethink just-completed work against an agreed plan, classifying findings as deal-breaker, suggestion, or correct, with a confidence score. Use to challenge or critically review recent work. Not for line-by-line style review or writing code.` | -#### `skills/03-condense` - -| Group | File | Description | -|-------|------|---| -| `actions` | [01-condense.md](skills/03-condense/actions/01-condense.md) | - | -| `actions` | [02-stats.md](skills/03-condense/actions/02-stats.md) | - | -| `references` | [intensity-levels.md](skills/03-condense/references/intensity-levels.md) | - | -| `-` | [SKILL.md](skills/03-condense/SKILL.md) | `Toggle terse output mode (lite, full, ultra) that drops filler while code and errors stay verbatim, and report token savings. Use to condense output, switch intensity, or check savings. Not for editing prose or compressing code.` | - -#### `skills/04-shadow-areas` +#### `skills/03-shadow-areas` | Group | File | Description | |-------|------|---| -| `actions` | [01-detect.md](skills/04-shadow-areas/actions/01-detect.md) | - | -| `actions` | [02-render-report.md](skills/04-shadow-areas/actions/02-render-report.md) | - | -| `actions` | [03-diff.md](skills/04-shadow-areas/actions/03-diff.md) | - | -| `assets` | [report-template.md](skills/04-shadow-areas/assets/report-template.md) | - | -| `references` | [categories.md](skills/04-shadow-areas/references/categories.md) | - | -| `references` | [locked-sets.json](skills/04-shadow-areas/references/locked-sets.json) | - | -| `references` | [probe-style.md](skills/04-shadow-areas/references/probe-style.md) | - | -| `references` | [severity-rubric.md](skills/04-shadow-areas/references/severity-rubric.md) | - | -| `-` | [SKILL.md](skills/04-shadow-areas/SKILL.md) | `Scan a markdown artifact (idea, stories, PRD, spec) for blind spots into a shadow report grouped by category and severity. Use to find gaps or what is missing in a written artifact. Not for interactive Q&A or code review.` | - -#### `skills/05-fact-check` +| `actions` | [01-detect.md](skills/03-shadow-areas/actions/01-detect.md) | - | +| `actions` | [02-render-report.md](skills/03-shadow-areas/actions/02-render-report.md) | - | +| `actions` | [03-diff.md](skills/03-shadow-areas/actions/03-diff.md) | - | +| `assets` | [report-template.md](skills/03-shadow-areas/assets/report-template.md) | - | +| `references` | [categories.md](skills/03-shadow-areas/references/categories.md) | - | +| `references` | [locked-sets.json](skills/03-shadow-areas/references/locked-sets.json) | - | +| `references` | [probe-style.md](skills/03-shadow-areas/references/probe-style.md) | - | +| `references` | [severity-rubric.md](skills/03-shadow-areas/references/severity-rubric.md) | - | +| `-` | [SKILL.md](skills/03-shadow-areas/SKILL.md) | `Scan a markdown artifact (idea, stories, PRD, spec) for blind spots into a shadow report grouped by category and severity. Use to find gaps or what is missing in a written artifact. Not for interactive Q&A or code review.` | + +#### `skills/04-fact-check` | Group | File | Description | |-------|------|---| -| `actions` | [01-identify-claims.md](skills/05-fact-check/actions/01-identify-claims.md) | - | -| `actions` | [02-verify.md](skills/05-fact-check/actions/02-verify.md) | - | -| `actions` | [03-report.md](skills/05-fact-check/actions/03-report.md) | - | -| `assets` | [report-template.md](skills/05-fact-check/assets/report-template.md) | - | -| `references` | [claim-categories.md](skills/05-fact-check/references/claim-categories.md) | - | -| `references` | [report-output-discipline.md](skills/05-fact-check/references/report-output-discipline.md) | - | -| `references` | [verification-cascade.md](skills/05-fact-check/references/verification-cascade.md) | - | -| `-` | [SKILL.md](skills/05-fact-check/SKILL.md) | `Verify factual claims in a text against authoritative sources and rewrite it with footnote citations, hedging the unconfirmed. Use to fact-check, verify a claim, or cite sources on request. Not for judging code or clarifying requirements.` | +| `actions` | [01-identify-claims.md](skills/04-fact-check/actions/01-identify-claims.md) | - | +| `actions` | [02-verify.md](skills/04-fact-check/actions/02-verify.md) | - | +| `actions` | [03-report.md](skills/04-fact-check/actions/03-report.md) | - | +| `assets` | [report-template.md](skills/04-fact-check/assets/report-template.md) | - | +| `references` | [claim-categories.md](skills/04-fact-check/references/claim-categories.md) | - | +| `references` | [report-output-discipline.md](skills/04-fact-check/references/report-output-discipline.md) | - | +| `references` | [verification-cascade.md](skills/04-fact-check/references/verification-cascade.md) | - | +| `-` | [SKILL.md](skills/04-fact-check/SKILL.md) | `Verify factual claims in a text against authoritative sources and rewrite it with footnote citations, hedging the unconfirmed. Use to fact-check, verify a claim, or cite sources on request. Not for judging code or clarifying requirements.` | diff --git a/plugins/aidd-refine/README.md b/plugins/aidd-refine/README.md index faefc204..02480dea 100644 --- a/plugins/aidd-refine/README.md +++ b/plugins/aidd-refine/README.md @@ -8,7 +8,7 @@ Meta-cognition plugin for the AI-Driven Development framework. First time? Install with `/plugin install aidd-refine@aidd-framework`, then run `aidd-refine:01-brainstorm`. -Five skills that refine inputs and outputs through reflection: clarify vague requests, challenge prior work for correctness, toggle a condensed output mode, analytically scan artifacts for blind spots, and verify factual claims against authoritative sources. +Four skills that refine inputs and outputs through reflection: clarify vague requests, challenge prior work for correctness, analytically scan artifacts for blind spots, and verify factual claims against authoritative sources. ## Skills @@ -16,6 +16,5 @@ Five skills that refine inputs and outputs through reflection: clarify vague req | ---------- | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [5.1] | [brainstorm](skills/01-brainstorm/SKILL.md) | Clarify a vague product or technical intent through natural discovery, converging until the idea is precise enough to act on. | | [5.2] | [challenge](skills/02-challenge/SKILL.md) | Rethink prior work to verify correctness against an agreed plan, classifying findings with a confidence score. | -| [5.3] | [condense](skills/03-condense/SKILL.md) | Toggle terse output mode with intensity levels so prose drops fluff while code, errors, and warnings stay verbatim. | -| [5.4] | [shadow-areas](skills/04-shadow-areas/SKILL.md) | Analytical scan of a written artifact for blind spots: each gap is classified by category and severity, paired with a direct-question probe. | -| [5.5] | [fact-check](skills/05-fact-check/SKILL.md) | Verify factual claims against authoritative sources and rewrite the text with footnote citations, hedging anything that cannot be confirmed. | +| [5.3] | [shadow-areas](skills/03-shadow-areas/SKILL.md) | Analytical scan of a written artifact for blind spots: each gap is classified by category and severity, paired with a direct-question probe. | +| [5.4] | [fact-check](skills/04-fact-check/SKILL.md) | Verify factual claims against authoritative sources and rewrite the text with footnote citations, hedging anything that cannot be confirmed. | diff --git a/plugins/aidd-refine/hooks/condense-stats.js b/plugins/aidd-refine/hooks/condense-stats.js deleted file mode 100644 index 88e82761..00000000 --- a/plugins/aidd-refine/hooks/condense-stats.js +++ /dev/null @@ -1,217 +0,0 @@ -#!/usr/bin/env node -/** - * condense-stats.js - * - * UserPromptSubmit hook for aidd-refine:03-condense :: action 02-stats. - * - * Triggers on user prompts that ask for condense stats. Reads the current - * Claude Code session transcript, detects intensity transitions emitted by - * the condense action, approximates token usage, and returns a formatted - * report so the model does not need to recompute. - * - * Trigger patterns (case-insensitive): - * /condense-stats - * /condense stats - * condense stats - * how much have we saved - * token savings - * - * Hook contract: receives a JSON payload on stdin with at least - * { hook_event_name, session_id, transcript_path, cwd, prompt } - * Returns JSON on stdout when blocking; exits silently when not matched. - */ - -'use strict'; - -const fs = require('fs'); - -const TRIGGER_PATTERNS = [ - /\/condense[-\s]?stats\b/i, - /\bcondense\s+stats\b/i, - /how\s+much\s+(have\s+)?we\s+saved\b/i, - /\btoken\s+savings\b/i, -]; - -const LEVEL_DEFAULT = 'full'; -const COMPRESSION_RATIO = { - lite: 0.18, - full: 0.38, - ultra: 0.58, -}; - -function readStdin() { - return new Promise((resolve) => { - let data = ''; - process.stdin.setEncoding('utf8'); - process.stdin.on('data', (chunk) => { data += chunk; }); - process.stdin.on('end', () => resolve(data)); - process.stdin.on('error', () => resolve('')); - }); -} - -function passthrough() { - process.exit(0); -} - -function block(reason) { - process.stdout.write(JSON.stringify({ decision: 'block', reason }) + '\n'); - process.exit(0); -} - -function matchTrigger(prompt) { - if (!prompt || typeof prompt !== 'string') return false; - return TRIGGER_PATTERNS.some((re) => re.test(prompt)); -} - -function readTranscript(transcriptPath) { - if (!transcriptPath || !fs.existsSync(transcriptPath)) return []; - const lines = fs.readFileSync(transcriptPath, 'utf8').split(/\r?\n/); - const messages = []; - for (const line of lines) { - if (!line.trim()) continue; - try { - messages.push(JSON.parse(line)); - } catch { - // ignore malformed lines - } - } - return messages; -} - -function extractAssistantText(message) { - if (!message || message.type !== 'assistant') return null; - const content = message?.message?.content; - if (typeof content === 'string') return content; - if (Array.isArray(content)) { - return content - .filter((part) => part && part.type === 'text' && typeof part.text === 'string') - .map((part) => part.text) - .join('\n'); - } - return null; -} - -function detectTransitionLevel(text) { - if (!text) return null; - const onMatch = text.match(/Condense:\s*ON\s*\(([a-z]+)\)/i); - if (onMatch) return onMatch[1].toLowerCase(); - if (/Condense:\s*OFF/i.test(text)) return 'off'; - return null; -} - -function approxTokens(text) { - if (!text) return 0; - return Math.ceil(text.length / 4); -} - -function computeStats(messages) { - let activeLevel = null; - let activeTurns = 0; - let totalTurns = 0; - let activeTokens = 0; - let offTokens = 0; - const levelTokens = { lite: 0, full: 0, ultra: 0 }; - const levelTurns = { lite: 0, full: 0, ultra: 0 }; - - for (const message of messages) { - const text = extractAssistantText(message); - if (text === null) continue; - totalTurns += 1; - - const transition = detectTransitionLevel(text); - if (transition === 'off') { - activeLevel = null; - } else if (transition && transition in COMPRESSION_RATIO) { - activeLevel = transition; - } - - const tokens = approxTokens(text); - if (activeLevel) { - activeTurns += 1; - activeTokens += tokens; - levelTokens[activeLevel] += tokens; - levelTurns[activeLevel] += 1; - } else { - offTokens += tokens; - } - } - - let approxSaved = 0; - for (const [level, tokens] of Object.entries(levelTokens)) { - const ratio = COMPRESSION_RATIO[level]; - if (!ratio || tokens === 0) continue; - // tokens here are the compressed output; baseline = tokens / (1 - ratio) - const baseline = tokens / (1 - ratio); - approxSaved += baseline - tokens; - } - - const activeRatio = totalTurns === 0 ? 0 : (activeTurns / totalTurns) * 100; - const avgSaved = activeTurns === 0 - ? 0 - : (Object.entries(levelTurns).reduce((acc, [level, turns]) => { - return acc + (turns * (COMPRESSION_RATIO[level] || 0)); - }, 0) / activeTurns) * 100; - - const topSavings = Object.entries(levelTurns) - .filter(([, turns]) => turns > 0) - .sort((a, b) => b[1] - a[1]) - .map(([level]) => `${level} (-${Math.round((COMPRESSION_RATIO[level] || 0) * 100)}%)`) - .join(', ') || 'none yet'; - - return { - mode: activeLevel ? `ON (${activeLevel})` : 'OFF', - activeTurns, - totalTurns, - activeRatio: Math.round(activeRatio), - activeTokens: Math.round(activeTokens / 10) * 10, - offTokens: Math.round(offTokens / 10) * 10, - avgSaved: Math.round(avgSaved), - approxSaved: Math.round(approxSaved / 10) * 10, - topSavings, - }; -} - -function format(stats) { - return [ - 'Condense session stats', - '----------------------', - `Mode: ${stats.mode}`, - `Active turns: ${stats.activeTurns} / ${stats.totalTurns} (${stats.activeRatio}%)`, - `Tokens out (active):${' '.repeat(Math.max(1, 4 - String(stats.activeTokens).length))}${stats.activeTokens}`, - `Tokens out (off): ${stats.offTokens}`, - `Avg saved / turn: ~${stats.avgSaved}%`, - `Approx total saved: ~${stats.approxSaved} tokens`, - '', - `Top savings: ${stats.topSavings}.`, - '', - 'Source: session transcript. Baseline ratios are published averages (lite 18%, full 38%, ultra 58%); replace with measured values when available.', - ].join('\n'); -} - -async function main() { - const raw = await readStdin(); - let payload = {}; - try { - payload = raw ? JSON.parse(raw) : {}; - } catch { - passthrough(); - return; - } - - const prompt = payload.prompt || payload.user_prompt || ''; - if (!matchTrigger(prompt)) { - passthrough(); - return; - } - - const messages = readTranscript(payload.transcript_path); - if (messages.length === 0) { - block('Condense session stats unavailable: transcript not found or empty.'); - return; - } - - const stats = computeStats(messages); - block(format(stats)); -} - -main().catch(() => passthrough()); diff --git a/plugins/aidd-refine/hooks/hooks.json b/plugins/aidd-refine/hooks/hooks.json deleted file mode 100644 index bbe89419..00000000 --- a/plugins/aidd-refine/hooks/hooks.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "hooks": { - "UserPromptSubmit": [ - { - "hooks": [ - { - "type": "command", - "command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/condense-stats.js" - } - ] - } - ] - } -} diff --git a/plugins/aidd-refine/skills/03-condense/SKILL.md b/plugins/aidd-refine/skills/03-condense/SKILL.md deleted file mode 100644 index c95881af..00000000 --- a/plugins/aidd-refine/skills/03-condense/SKILL.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -name: 03-condense -description: Toggle terse output mode (lite, full, ultra) that drops filler while code and errors stay verbatim, and report token savings. Use to condense output, switch intensity, or check savings. Not for editing prose or compressing code. -argument-hint: lite | full | ultra | stats ---- - -# Condense - -Toggles a terse output mode with three intensity levels (lite, full, ultra). Strips articles, filler, and pleasantries from prose while preserving technical substance, code blocks, quoted errors, and security warnings. - -## Actions - -| # | Action | Role | Input | -| --- | ---------- | --------------------------------------------------------------------- | ------------------------------------ | -| 01 | `condense` | Toggle terse mode and apply intensity rules | current state + requested level | -| 02 | `stats` | Report real token usage and estimated savings for the current session | session messages + level timeline | - -Dispatch by intent: a toggle phrase → `condense`, a savings query → `stats`. -Before running an action, read its file in `actions/`, not only the table or assets. - -## Transversal rules - -- **Persistence**: once active, terse mode applies to EVERY response until explicitly turned off. Do not drift back to verbose prose after many turns, when uncertain, or when the task changes. The level remains active for the rest of the session unless changed or stopped. -- **Off switch**: terse mode stops only on explicit user signal: `stop condense`, `normal mode`, or invoking the skill again to toggle. -- **Toggle**: invoking the skill while active toggles it off; invoking while off turns it on at the default level (`full`) unless an explicit intensity is given. -- **Drop fluff**: drop articles (a/an/the), filler (just/really/basically/actually/simply), pleasantries (sure/certainly/of course/happy to), and hedging. Fragments are acceptable. -- **Short synonyms**: prefer short words (big not extensive, fix not "implement a solution for"). Technical terms stay exact. Code blocks are unchanged. Errors are quoted verbatim. -- **Pattern**: `[thing] [action] [reason]. [next step].` -- **Auto-pause**: drop terse mode for the passages listed in `references/intensity-levels.md` (security warnings, irreversible confirmations, ambiguity risks), then resume. -- **Boundaries**: code, commits, and pull request bodies are written in normal English regardless of intensity. - -## References - -- `references/intensity-levels.md`: detailed per-level rules and side-by-side examples. diff --git a/plugins/aidd-refine/skills/03-condense/actions/01-condense.md b/plugins/aidd-refine/skills/03-condense/actions/01-condense.md deleted file mode 100644 index 5049b0ef..00000000 --- a/plugins/aidd-refine/skills/03-condense/actions/01-condense.md +++ /dev/null @@ -1,27 +0,0 @@ -# 01 - Condense - -Toggle terse output mode and apply the requested intensity rules to subsequent prose turns. - -## Input - -- Whether condense is currently on (and at which level) or off, read from session context. -- The requested change: a level (lite, full, ultra) or a plain on/off toggle. - -## Output - -A single confirmation line: `Condense: ON (<level>).` when enabling, or `Condense: OFF.` when disabling. - -## Process - -1. **Detect.** Read the toggle command and target level from the user message. -2. **Resolve.** Combine the current state with the request: - - Explicit level (`lite | full | ultra`) sets that level (or switches level if already on). - - `toggle` flips on/off; default level when turning on is `full`. - - Off phrases (`stop condense`, `normal mode`) force off. -3. **Emit.** The reply MUST begin with this exact line, filled in and unaltered: `Condense: ON (<level>).` when enabling, or `Condense: OFF.` when disabling. The stats action and the hook parse this line from the transcript, so never paraphrase, decorate, or omit it. -4. **Apply.** Apply the transversal rules to every subsequent prose turn until the next off signal, using per-level rules and auto-pause passages from [intensity-levels.md](../references/intensity-levels.md). - -## Test - -- After ON, the next non-code, non-warning turn drops articles at the active intensity; after OFF, it returns to normal prose. -- Code blocks, quoted errors, and security warnings stay verbatim regardless of state. diff --git a/plugins/aidd-refine/skills/03-condense/actions/02-stats.md b/plugins/aidd-refine/skills/03-condense/actions/02-stats.md deleted file mode 100644 index 0501cf25..00000000 --- a/plugins/aidd-refine/skills/03-condense/actions/02-stats.md +++ /dev/null @@ -1,26 +0,0 @@ -# 02 - Stats - -Show real token usage and estimated savings for the current session under condense mode. On Claude Code the bundled `hooks/condense-stats.js` hook owns this path; the model runs the steps below only on tools without hook support. - -## Input - -- The session's assistant messages since it started. -- The active level and every on/off switch during the session. - -## Output - -A stats block reporting, in order: mode, active turns and ratio, tokens out while active, tokens out while off, average saved per turn versus the unmodified baseline, approximate total saved, and per-level top savings. - -## Process - -1. **Read.** Load the session log for the current AI tool (Claude Code: the active session JSONL; other tools: their equivalent transcript). -2. **Detect.** Scan assistant messages for the confirmation line emitted by `01-condense` (`Condense: ON (...)` / `Condense: OFF`). Build a timeline of `(turn_index, level)` segments. -3. **Tokenize.** Count tokens per assistant message. Use the AI tool's token counter when available, otherwise approximate at 4 chars per token. -4. **Compute.** For each `active` segment, estimate the verbose-prose baseline using the level's compression ratio (`lite ~18%`, `full ~38%`, `ultra ~58%`, published averages, replaceable by measured ratios when available). -5. **Render.** Emit the report with the exact field order shown in `## Output`. Round percentages to whole numbers; round token counts to the nearest 10. -6. **Stop.** Do not invoke any other action. - -## Test - -- The output follows the `## Output` field order, every numeric field filled (no `-`). -- The active-turns ratio matches the detected intensity transitions. diff --git a/plugins/aidd-refine/skills/03-condense/references/intensity-levels.md b/plugins/aidd-refine/skills/03-condense/references/intensity-levels.md deleted file mode 100644 index 53e12cd2..00000000 --- a/plugins/aidd-refine/skills/03-condense/references/intensity-levels.md +++ /dev/null @@ -1,47 +0,0 @@ -# Intensity levels - -The `condense` action supports three intensity levels. Each row applies progressively more aggressive compression. - -| Level | What change | -| --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **lite** | No filler or hedging. Articles and full sentences are kept. Professional but tight. | -| **full** | Drop articles, fragments are acceptable, short synonyms. Classic terse mode. | -| **ultra** | Abbreviate prose words (DB, auth, config, req, res, fn, impl), strip conjunctions, arrows for causality (X to Y), one word when one word is enough. Code symbols, function names, API names, and error strings: never abbreviate. | - -## Side-by-side examples - -### Example 1: "Why does a React component re-render?" - -- **lite**: "Your component re-renders because you create a new object reference each render. Wrap it in `useMemo`." -- **full**: "New object ref each render. Inline object prop = new ref = re-render. Wrap in `useMemo`." -- **ultra**: "Inline obj prop to new ref to re-render. `useMemo`." - -### Example 2: "Explain database connection pooling." - -- **lite**: "Connection pooling reuses open connections instead of creating new ones per request. It avoids repeated handshake overhead." -- **full**: "Pool reuse open DB connections. No new connection per request. Skip handshake overhead." -- **ultra**: "Pool = reuse DB conn. Skip handshake to fast under load." - -### Example 3: "What is a debounce function?" - -- **lite**: "Debounce delays a function call until input stops for a chosen interval. Used for search inputs and resize handlers." -- **full**: "Debounce delay call until input stop for chosen interval. Use for search inputs, resize handlers." -- **ultra**: "Debounce delay call until input stop. Use for search, resize." - -## Auto-pause passages (always normal prose) - -These passages render in normal English regardless of the active level. Resume terse mode after the passage is clear. - -- **Security warnings**: full sentences explaining the risk and the safer alternative. -- **Irreversible action confirmations**: full sentences describing the consequence and any backup step. -- **Multi-step sequences** where dropped conjunctions or fragment order risks misread. -- **Clarifications**: if compression itself creates technical ambiguity, fall back for that bullet. -- **User confusion**: if the user repeats a question or asks "what do you mean", expand for that answer. - -### Example: irreversible operation - -> **Warning:** This permanently deletes all rows in the `users` table and cannot be undone. -> ```sql -> DROP TABLE users; -> ``` -> Terse mode resumes. Verify backup exists first. diff --git a/plugins/aidd-refine/skills/04-shadow-areas/SKILL.md b/plugins/aidd-refine/skills/03-shadow-areas/SKILL.md similarity index 99% rename from plugins/aidd-refine/skills/04-shadow-areas/SKILL.md rename to plugins/aidd-refine/skills/03-shadow-areas/SKILL.md index 8738b78f..a09d1fd5 100644 --- a/plugins/aidd-refine/skills/04-shadow-areas/SKILL.md +++ b/plugins/aidd-refine/skills/03-shadow-areas/SKILL.md @@ -1,5 +1,5 @@ --- -name: 04-shadow-areas +name: 03-shadow-areas description: Scan a markdown artifact (idea, stories, PRD, spec) for blind spots into a shadow report grouped by category and severity. Use to find gaps or what is missing in a written artifact. Not for interactive Q&A or code review. argument-hint: file | text --- diff --git a/plugins/aidd-refine/skills/04-shadow-areas/actions/01-detect.md b/plugins/aidd-refine/skills/03-shadow-areas/actions/01-detect.md similarity index 100% rename from plugins/aidd-refine/skills/04-shadow-areas/actions/01-detect.md rename to plugins/aidd-refine/skills/03-shadow-areas/actions/01-detect.md diff --git a/plugins/aidd-refine/skills/04-shadow-areas/actions/02-render-report.md b/plugins/aidd-refine/skills/03-shadow-areas/actions/02-render-report.md similarity index 100% rename from plugins/aidd-refine/skills/04-shadow-areas/actions/02-render-report.md rename to plugins/aidd-refine/skills/03-shadow-areas/actions/02-render-report.md diff --git a/plugins/aidd-refine/skills/04-shadow-areas/actions/03-diff.md b/plugins/aidd-refine/skills/03-shadow-areas/actions/03-diff.md similarity index 100% rename from plugins/aidd-refine/skills/04-shadow-areas/actions/03-diff.md rename to plugins/aidd-refine/skills/03-shadow-areas/actions/03-diff.md diff --git a/plugins/aidd-refine/skills/04-shadow-areas/assets/report-template.md b/plugins/aidd-refine/skills/03-shadow-areas/assets/report-template.md similarity index 100% rename from plugins/aidd-refine/skills/04-shadow-areas/assets/report-template.md rename to plugins/aidd-refine/skills/03-shadow-areas/assets/report-template.md diff --git a/plugins/aidd-refine/skills/04-shadow-areas/references/categories.md b/plugins/aidd-refine/skills/03-shadow-areas/references/categories.md similarity index 100% rename from plugins/aidd-refine/skills/04-shadow-areas/references/categories.md rename to plugins/aidd-refine/skills/03-shadow-areas/references/categories.md diff --git a/plugins/aidd-refine/skills/04-shadow-areas/references/locked-sets.json b/plugins/aidd-refine/skills/03-shadow-areas/references/locked-sets.json similarity index 100% rename from plugins/aidd-refine/skills/04-shadow-areas/references/locked-sets.json rename to plugins/aidd-refine/skills/03-shadow-areas/references/locked-sets.json diff --git a/plugins/aidd-refine/skills/04-shadow-areas/references/probe-style.md b/plugins/aidd-refine/skills/03-shadow-areas/references/probe-style.md similarity index 100% rename from plugins/aidd-refine/skills/04-shadow-areas/references/probe-style.md rename to plugins/aidd-refine/skills/03-shadow-areas/references/probe-style.md diff --git a/plugins/aidd-refine/skills/04-shadow-areas/references/severity-rubric.md b/plugins/aidd-refine/skills/03-shadow-areas/references/severity-rubric.md similarity index 100% rename from plugins/aidd-refine/skills/04-shadow-areas/references/severity-rubric.md rename to plugins/aidd-refine/skills/03-shadow-areas/references/severity-rubric.md diff --git a/plugins/aidd-refine/skills/05-fact-check/SKILL.md b/plugins/aidd-refine/skills/04-fact-check/SKILL.md similarity index 99% rename from plugins/aidd-refine/skills/05-fact-check/SKILL.md rename to plugins/aidd-refine/skills/04-fact-check/SKILL.md index 5ede3ee4..debeeb30 100644 --- a/plugins/aidd-refine/skills/05-fact-check/SKILL.md +++ b/plugins/aidd-refine/skills/04-fact-check/SKILL.md @@ -1,5 +1,5 @@ --- -name: 05-fact-check +name: 04-fact-check description: Verify factual claims in a text against authoritative sources and rewrite it with footnote citations, hedging the unconfirmed. Use to fact-check, verify a claim, or cite sources on request. Not for judging code or clarifying requirements. argument-hint: text --- diff --git a/plugins/aidd-refine/skills/05-fact-check/actions/01-identify-claims.md b/plugins/aidd-refine/skills/04-fact-check/actions/01-identify-claims.md similarity index 100% rename from plugins/aidd-refine/skills/05-fact-check/actions/01-identify-claims.md rename to plugins/aidd-refine/skills/04-fact-check/actions/01-identify-claims.md diff --git a/plugins/aidd-refine/skills/05-fact-check/actions/02-verify.md b/plugins/aidd-refine/skills/04-fact-check/actions/02-verify.md similarity index 90% rename from plugins/aidd-refine/skills/05-fact-check/actions/02-verify.md rename to plugins/aidd-refine/skills/04-fact-check/actions/02-verify.md index 70ad3d8d..4f82b6e7 100644 --- a/plugins/aidd-refine/skills/05-fact-check/actions/02-verify.md +++ b/plugins/aidd-refine/skills/04-fact-check/actions/02-verify.md @@ -21,4 +21,4 @@ A list of verdicts: each claim gains one verdict (verified, refuted, conflict, o ## Test -- Run on `"the source file plugins/aidd-refine/hooks/condense-stats.js exists in this repo"`: the cascade resolves at the codebase tier, the verdict is verified, the source is that file path, and the web tier is never reached. +- Run on `"the source file plugins/aidd-context/hooks/update_memory.js exists in this repo"`: the cascade resolves at the codebase tier, the verdict is verified, the source is that file path, and the web tier is never reached. diff --git a/plugins/aidd-refine/skills/05-fact-check/actions/03-report.md b/plugins/aidd-refine/skills/04-fact-check/actions/03-report.md similarity index 100% rename from plugins/aidd-refine/skills/05-fact-check/actions/03-report.md rename to plugins/aidd-refine/skills/04-fact-check/actions/03-report.md diff --git a/plugins/aidd-refine/skills/05-fact-check/assets/report-template.md b/plugins/aidd-refine/skills/04-fact-check/assets/report-template.md similarity index 100% rename from plugins/aidd-refine/skills/05-fact-check/assets/report-template.md rename to plugins/aidd-refine/skills/04-fact-check/assets/report-template.md diff --git a/plugins/aidd-refine/skills/05-fact-check/references/claim-categories.md b/plugins/aidd-refine/skills/04-fact-check/references/claim-categories.md similarity index 100% rename from plugins/aidd-refine/skills/05-fact-check/references/claim-categories.md rename to plugins/aidd-refine/skills/04-fact-check/references/claim-categories.md diff --git a/plugins/aidd-refine/skills/05-fact-check/references/report-output-discipline.md b/plugins/aidd-refine/skills/04-fact-check/references/report-output-discipline.md similarity index 100% rename from plugins/aidd-refine/skills/05-fact-check/references/report-output-discipline.md rename to plugins/aidd-refine/skills/04-fact-check/references/report-output-discipline.md diff --git a/plugins/aidd-refine/skills/05-fact-check/references/verification-cascade.md b/plugins/aidd-refine/skills/04-fact-check/references/verification-cascade.md similarity index 100% rename from plugins/aidd-refine/skills/05-fact-check/references/verification-cascade.md rename to plugins/aidd-refine/skills/04-fact-check/references/verification-cascade.md diff --git a/scripts/skill-eval.mjs b/scripts/skill-eval.mjs index ab66e1f7..eee13a69 100644 --- a/scripts/skill-eval.mjs +++ b/scripts/skill-eval.mjs @@ -8,7 +8,7 @@ // // Usage: // node scripts/skill-eval.mjs # run every case (deterministic checks) -// node scripts/skill-eval.mjs 04-shadow-areas # run cases for one skill +// node scripts/skill-eval.mjs 03-shadow-areas # run cases for one skill // node scripts/skill-eval.mjs --judge # also run LLM-judge criteria (metered) // node scripts/skill-eval.mjs --keep # keep temp dirs for inspection // diff --git a/scripts/skill-eval/README.md b/scripts/skill-eval/README.md index 663cda8e..a6a57d21 100644 --- a/scripts/skill-eval/README.md +++ b/scripts/skill-eval/README.md @@ -8,7 +8,7 @@ blocks describe. ```bash node scripts/skill-eval.mjs # every case, deterministic checks -node scripts/skill-eval.mjs 04-shadow-areas # one skill +node scripts/skill-eval.mjs 03-shadow-areas # one skill node scripts/skill-eval.mjs --judge # also run LLM-judge criteria (metered) node scripts/skill-eval.mjs --keep # keep temp dirs to inspect ``` @@ -31,7 +31,7 @@ output. ```json { - "skill": "04-shadow-areas", + "skill": "03-shadow-areas", "evalName": "xeval-shadow", "name": "short description", "setup": { "files": { "prd.md": "..." } }, @@ -63,15 +63,8 @@ as grader, for outcomes that cannot be matched literally. ## Known findings -The harness surfaced two limitations worth tracking: +The harness surfaced one limitation worth tracking: -- **condense's `Condense: ON (<level>).` line is model-emitted, not guaranteed.** - `02-stats` and the `condense-stats.js` hook parse that exact line from the - transcript, but the model paraphrases it ("Condense mode on, level full") - even when the action mandates the literal. So the condense case gates on - semantics (mentions condense + the level), not the literal, and stats - detection is best-effort. A robust fix would emit the marker from the hook - rather than rely on model output. - **empty-source scanning varies.** Most runs produce exactly one blocker, but the exact count/header drifts between runs. The case asserts deterministically only that a report is written, and gates the "exactly one blocker" semantics diff --git a/scripts/skill-eval/cases.json b/scripts/skill-eval/cases.json index ad8bd4b8..8311d708 100644 --- a/scripts/skill-eval/cases.json +++ b/scripts/skill-eval/cases.json @@ -1,6 +1,6 @@ [ { - "skill": "04-shadow-areas", + "skill": "03-shadow-areas", "evalName": "xeval-shadow", "name": "scans a PRD and writes a structured report", "setup": { @@ -15,7 +15,7 @@ } }, { - "skill": "04-shadow-areas", + "skill": "03-shadow-areas", "evalName": "xeval-shadow", "name": "filename rule keeps a dotless name (Makefile)", "setup": { "files": { "Makefile": "build:\n\techo hi\n" } }, @@ -23,7 +23,7 @@ "expect": { "filesExist": ["Makefile-shadow-report.md"] } }, { - "skill": "04-shadow-areas", + "skill": "03-shadow-areas", "evalName": "xeval-shadow", "name": "empty source yields a single blocker", "setup": { "files": { "empty.md": "" } }, @@ -35,7 +35,7 @@ } }, { - "skill": "05-fact-check", + "skill": "04-fact-check", "evalName": "xeval-factcheck", "name": "verifies a real file, refutes a fake one, hedges the unknowable, hides mechanics", "setup": { "files": { "src/auth.ts": "export const auth = true;\n" } }, @@ -47,15 +47,6 @@ "judgeFiles": [] } }, - { - "skill": "03-condense", - "evalName": "xeval-condense", - "name": "turning on confirms condense at the full level", - "prompt": "Use the {{SKILL}} skill to turn condense mode on, set to the full level (not lite, not ultra).", - "expect": { - "stdoutContains": ["condense", "full"] - } - }, { "skill": "02-challenge", "evalName": "xeval-challenge", From 3909f6ccec6f3d7efc2d2c39aab4dc0f9c58c8f6 Mon Sep 17 00:00:00 2001 From: Baptiste LAFOURCADE <119650761+blafourcade@users.noreply.github.com> Date: Fri, 14 Aug 2026 09:55:38 +0200 Subject: [PATCH 10/14] refactor(aidd-pm): migrate ticket-info, prd, and spec to router contract (#628) * refactor(aidd-pm): migrate 01-ticket-info to router contract Moves tool/identifier lookup rules into references/tool-detection.md, standardizes the display output via assets/ticket-template.md, and replaces the old action table with the mermaid + | Action | Does | shape used by the other 7 aidd-pm skills. Part of #564; phase 1 of 3. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * refactor(aidd-pm): migrate 03-prd to router contract Splits the single prd action into draft/finalize (single responsibility each, matching 08-three-amigos), restores the 5+1 Transversal rules boilerplate shared by 6 other aidd-pm skills, drops the dead task-template.md asset, and inlines the save path into finalize instead of a one-fact references/ file. Part of #564; phase 2 of 3. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * refactor(aidd-pm): migrate 04-spec to router contract Moves the build-vs-refine dispatch into the mermaid as two entry nodes, gives TBD: one canonical spelling in references/tbd-marker.md (fixing the 2 drifted spellings in 02-refine.md), and keeps spec's own Transversal rules rather than the epic/task/prd boilerplate, which doesn't fit a skill with no approval gate. Also fixes two pre-existing gaps caught while auditing citations: spec-template.md was never actually linked from build.md, and the feature-folder resolve step was underspecified. Two follow-up issues filed for behavior gaps out of this issue's "no behaviour change" scope: #625 (SDLC never validates a spec before handing it to Deliver) and #626 (spec-template.md has no home for TBD markers, confirmed non-deterministic placement). Closes #564. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com> --- .../phase-1.md | 65 +++++++++++++++++++ .../phase-2.md | 39 +++++++++++ .../phase-3.md | 37 +++++++++++ .../plan.md | 53 +++++++++++++++ plugins/aidd-pm/CATALOG.md | 7 +- .../aidd-pm/skills/01-ticket-info/SKILL.md | 20 +++--- .../01-ticket-info/actions/01-ticket-info.md | 12 ++-- .../01-ticket-info/assets/ticket-template.md | 12 ++++ .../references/tool-detection.md | 10 +++ plugins/aidd-pm/skills/03-prd/SKILL.md | 30 ++++----- .../aidd-pm/skills/03-prd/actions/01-draft.md | 27 ++++++++ .../aidd-pm/skills/03-prd/actions/01-prd.md | 28 -------- .../skills/03-prd/actions/02-finalize.md | 24 +++++++ .../skills/03-prd/assets/task-template.md | 15 ----- plugins/aidd-pm/skills/04-spec/SKILL.md | 32 +++++---- .../skills/04-spec/actions/01-build.md | 18 ++--- .../skills/04-spec/actions/02-refine.md | 9 +-- .../skills/04-spec/references/tbd-marker.md | 3 + 18 files changed, 333 insertions(+), 108 deletions(-) create mode 100644 aidd_docs/tasks/2026_08/2026_08_10_migrate-pm-router-contract/phase-1.md create mode 100644 aidd_docs/tasks/2026_08/2026_08_10_migrate-pm-router-contract/phase-2.md create mode 100644 aidd_docs/tasks/2026_08/2026_08_10_migrate-pm-router-contract/phase-3.md create mode 100644 aidd_docs/tasks/2026_08/2026_08_10_migrate-pm-router-contract/plan.md create mode 100644 plugins/aidd-pm/skills/01-ticket-info/assets/ticket-template.md create mode 100644 plugins/aidd-pm/skills/01-ticket-info/references/tool-detection.md create mode 100644 plugins/aidd-pm/skills/03-prd/actions/01-draft.md delete mode 100644 plugins/aidd-pm/skills/03-prd/actions/01-prd.md create mode 100644 plugins/aidd-pm/skills/03-prd/actions/02-finalize.md delete mode 100644 plugins/aidd-pm/skills/03-prd/assets/task-template.md create mode 100644 plugins/aidd-pm/skills/04-spec/references/tbd-marker.md diff --git a/aidd_docs/tasks/2026_08/2026_08_10_migrate-pm-router-contract/phase-1.md b/aidd_docs/tasks/2026_08/2026_08_10_migrate-pm-router-contract/phase-1.md new file mode 100644 index 00000000..35233ec6 --- /dev/null +++ b/aidd_docs/tasks/2026_08/2026_08_10_migrate-pm-router-contract/phase-1.md @@ -0,0 +1,65 @@ +--- +status: done +--- + +# Instruction: Migrate `01-ticket-info` to the router contract + +## Architecture projection + +> ✅ create · ✏️ modify · ❌ delete + +```txt +. +└── plugins/aidd-pm/skills/01-ticket-info/ + ├── SKILL.md ✏️ mermaid flow, `| Action | Does |` table, canonical lead-in; drop the `| # | Action | Role | Input |` shape and duplicated process rules + ├── actions/01-ticket-info.md ✏️ cite references/ and assets/ instead of restating rules and output fields + ├── references/ ✅ create — issue scope mandates a references/ folder on every one of the 3 skills + │ └── tool-detection.md ✅ create — where the configured ticketing tool and identifier convention are declared + └── assets/ + └── ticket-template.md ✅ create — standardizes the display fields (title, status, assignee, priority, URL, description); user-requested during phase review, not in the original issue scope +``` + +## Tasks to do + +### `1)` Rebuild the router + +> Router keeps only the flow, the action table, and whatever rule truly belongs to no single action or reference (R6, R9, R10). + +1. Add a mermaid `flowchart LR`: one entry node (ticket id or branch-derived id) → `ticket-info` → terminal node (displayed ticket). Single action, no loop. +2. Replace the `| # | Action | Role | Input |` table with `| Action | Does |`: bare slug `ticket-info`, lowercase imperative half-line, no trailing period (R8). +3. Replace "Before running an action, read its file in `actions/`, not only the table or assets." with the canonical lead-in: "Run the flow above. Read only the next action file." (matches `07-epic`, `skill-template.md`). +4. Compare each line under `## Transversal rules` against `actions/01-ticket-info.md`'s `## Process` steps 1-3: every rule already stated there is deleted from the router, not restated (R17). +5. Drop the line repeating the frontmatter `Not for` list / intent — `description` already carries it (R3). + +### `2)` Create `references/tool-detection.md`, decide the rest + +> Issue Scope is explicit: "Give each of the three a `references/` folder." Not optional — this is the one reference file this skill gets. + +1. Create `references/tool-detection.md`: a table or list stating where the configured ticketing tool is declared (project memory first, otherwise repo configuration or environment) and the identifier-format convention (branch-derived id, project prefix/separator/casing) — the two facts that are lookup-order-shaped, not process-shaped (R15). +2. Cite it from the action's `## Process` steps 1 and 3 with a relative link (R14, R18) — delete the equivalent prose from the router's `## Transversal rules` once cited, don't keep both (R17). +3. Check whether "read-only: never create, comment, transition, or reassign" states something the frontmatter `description`'s `Not for` clause doesn't already cover. If it's pure duplication, delete it; otherwise it's the one line that stays in `## Transversal rules` (it governs the whole skill, not one process step). + +### `3)` Create `assets/ticket-template.md` + +> User-requested during phase review: standardize the display output. Checked first whether `aidd-orchestrator:01-sdlc` (the known caller, `references/01-frame.md:15-16`) needs a specific shape — it consumes `$resolved_source` as free text, no schema, so this is a display-consistency choice, not an external contract requirement. + +1. Create `assets/ticket-template.md` with the fields the action already outputs: title, status, assignee, priority, URL, description. Follow the existing template idiom (leading HTML comment instructing fill-and-strip, bracketed placeholders — see `spec-template.md`, `epic-template.md`). +2. Cite it from the action's `## Output` and the `## Process` "Display" step (R18) instead of enumerating the fields inline. +3. Do not add a router `## Assets` section — R6 forbids it; the citation lives in the action, same as every other asset in the plugin. + +### `4)` Verify the action still stands alone + +> The action file must state everything needed to run, citing references and assets rather than depending on the router. + +1. Re-read `actions/01-ticket-info.md`: confirm it states, on its own plus its citations, everything needed to run — no missing step because the router used to cover it. +2. Confirm each citation sits in the sentence that uses it (R18), not as a standalone line. + +## Test acceptance criteria + +| Task | Acceptance criteria | +| ---- | ------------------------------------------------------------------------------------------------------ | +| 1 | `SKILL.md` has a mermaid flow, a `\| Action \| Does \|` table, and the exact canonical lead-in sentence. | +| 1 | No line in `## Transversal rules` duplicates a `## Process` step in `actions/01-ticket-info.md`, nor the frontmatter `description`. | +| 2 | `references/tool-detection.md` exists, is cited from `actions/01-ticket-info.md`, and states a fact no action process step restates. | +| 3 | `assets/ticket-template.md` exists, is cited from `actions/01-ticket-info.md`, and `SKILL.md` has no `## Assets` section. | +| 4 | `actions/01-ticket-info.md` read together with its cited reference and asset fully describes how to run the action, with nothing left only in `SKILL.md`. | diff --git a/aidd_docs/tasks/2026_08/2026_08_10_migrate-pm-router-contract/phase-2.md b/aidd_docs/tasks/2026_08/2026_08_10_migrate-pm-router-contract/phase-2.md new file mode 100644 index 00000000..8f4b09fa --- /dev/null +++ b/aidd_docs/tasks/2026_08/2026_08_10_migrate-pm-router-contract/phase-2.md @@ -0,0 +1,39 @@ +--- +status: done +--- + +# Instruction: Migrate `03-prd` to the router contract + +## Architecture projection + +> ✅ create · ✏️ modify · ❌ delete + +```txt +. +└── plugins/aidd-pm/skills/03-prd/ + ├── SKILL.md ✏️ mermaid (3-node chain), `| Action | Does |`, canonical lead-in, 5+1 Transversal rules, no `## Assets` + ├── actions/01-prd.md ❌ delete — split below + ├── actions/01-draft.md ✅ create — parse+fill+iterate to approval + ├── actions/02-finalize.md ✅ create — save+verify + ├── assets/prd-template.md — unchanged, sole source of truth for the 8 sections + └── assets/task-template.md ❌ delete — unfilled, collides by name with 10-task's real Task template +``` + +No `references/` folder. Issue Scope says "give each of the three a `references/` folder", but the only candidate content (the save path, one sentence) isn't reference-shaped — no table, no branching, nothing 04-spec's `tbd-marker.md`-style multi-site drift applies to. The literal AC ("no router states a rule an action or reference could hold") is satisfied either way; inlined into `finalize`'s Process step 1 instead. + +## Decisions made during review (deviate from the original phase draft) + +- **Split `01-prd` into `draft` + `finalize`.** The 1-action design (parse+draft+validate+save in one file) was measurably more verbose per-action than every comparable migrated skill. Matches `08-three-amigos`'s 2-action, single-responsibility shape. Net behavior unchanged (same approval gate, same output) — action-count restructuring past issue #564's literal "no behaviour change" scope, so flagged here rather than silently absorbed. +- **Added the 5-line shared boilerplate + 1 skill-specific line to `## Transversal rules`.** 6 of 7 already-migrated skills (`02,05,06,07,09,10`) share these 5 lines verbatim; a missed pattern in the first draft. +- **Dropped `affected relations` and `before -> after`** from `finalize`'s report contract — both are copy-pasted from Task/Defect/Epic, neither applies (PRD has no `relations.md`, and always creates a fresh dated file — no update-in-place exists to diff). +- **No `references/persistence.md`.** See above. + +## Test acceptance criteria + +| # | Acceptance criteria | +| - | -------------------- | +| 1 | `assets/task-template.md` no longer exists; nothing references it. | +| 2 | `SKILL.md` has a mermaid flow, `\| Action \| Does \|` table, canonical lead-in, no `## Assets`, and the 5+1 `## Transversal rules`. | +| 3 | The 8 PRD section names appear in exactly one file: `assets/prd-template.md`. | +| 4 | `draft` never writes to disk; `finalize` only ever receives an already-approved draft. | +| 5 | Live headless run: both actions chain correctly, saved file matches `prd-template.md` exactly (verified). | diff --git a/aidd_docs/tasks/2026_08/2026_08_10_migrate-pm-router-contract/phase-3.md b/aidd_docs/tasks/2026_08/2026_08_10_migrate-pm-router-contract/phase-3.md new file mode 100644 index 00000000..7a2b5100 --- /dev/null +++ b/aidd_docs/tasks/2026_08/2026_08_10_migrate-pm-router-contract/phase-3.md @@ -0,0 +1,37 @@ +--- +status: done +--- + +# Instruction: Migrate `04-spec` to the router contract + +## Architecture projection + +> ✅ create · ✏️ modify · ❌ delete + +```txt +. +└── plugins/aidd-pm/skills/04-spec/ + ├── SKILL.md ✏️ mermaid (2 entry nodes: build vs refine), `| Action | Does |`, canonical lead-in, no `## Assets`, own 4-line Transversal rules (not the epic/task/prd boilerplate — spec has no approval gate, doesn't fit) + ├── actions/01-build.md ✏️ cite tbd-marker.md, cite spec-template.md (pre-existing gap, was never actually linked), drop before->after/affected relations (always creates fresh, no diff) + ├── actions/02-refine.md ✏️ cite tbd-marker.md, fix 2 drifted TBD spellings, keep before->after (legitimate — rewrites in place), drop affected relations + └── references/ + └── tbd-marker.md ✅ create — the one canonical `TBD: <precise question>` spelling +``` + +## Decisions + +- **No epic/task/prd Transversal-rules boilerplate.** Checked each of the 5 shared lines against what `build`/`refine` actually do: no approval gate before write, no lifecycle, uses TBD-marking instead of interactive questioning. None of it fits — inventing it would add behavior that doesn't exist. Kept spec's own rules instead (matches `08-three-amigos`'s precedent of not sharing the boilerplate either). +- **Dispatch-by-input moved into the mermaid** as two entry nodes (request/PRD → `build`, spec+findings → `refine`), replacing the router prose that stated the same branch (R7, R17). +- **`before -> after` kept in `refine`, dropped from `build`.** `refine` genuinely rewrites an existing file in place (real diff). `build` always creates a fresh dated file — no prior state exists to diff. +- **Router never cites a reference.** No other router does (checked all 7) — R18 only names Process/Output/Test as valid citation sites. Router states policy in plain words ("Never invent; mark every gap instead of guessing"); the actions cite `tbd-marker.md` where they apply it. +- **`tbd-marker.md` trimmed to the literal string only** (`TBD: <precise question>`, no policy prose) — the policy already lives once in the router; anything more would duplicate it. +- **`build.md`'s Source step split into 2 sub-bullets** (PRD path vs free-form request) instead of one dense sentence; "never explore the codebase" promoted out of it into the router's Transversal rules (applies to both actions, not just Source). +- **`refine.md`'s Output cut to one line**, TBD citation removed from Output (stays in Process step 4 only — was duplicated), added an explicit `Verify` step so `before -> after` reporting has a Process home instead of living only in prose. +- **Two pre-existing gaps fixed while auditing citations, not part of the original scope:** `build.md` never linked `spec-template.md` (called it "the template" in prose only); the router's "reuse the folder when it exists" line was deleted without moving its actual path pattern into `build.md` (first draft), caught by a live headless run hitting the gap itself. Second catch: the fixed version still lost the word "resolve" (search-then-reuse-or-create), reducing it to a same-day-only check — restored the two-outcome framing. +- **Two follow-up issues filed, not fixed here** (behavior changes, out of #564's "no behaviour change" scope): [#625](https://github.com/ai-driven-dev/framework/issues/625) — SDLC's Frame stage never checks `spec-validator.yml` before handing a spec to Deliver. [#626](https://github.com/ai-driven-dev/framework/issues/626) — `spec-template.md` has no `## Open Questions` section, so TBD placement is non-deterministic (confirmed: same feature, two runs, two different placements). + +## Plugin-wide verification (AC#1, AC#5 — span all 10 skills, checked here as the last phase) + +- All 10 `SKILL.md` files: `# Title` → `## Actions` (mermaid + `| Action | Does |` + canonical lead-in) → optional `## Transversal rules`. Section presence varies only where content is legitimately absent (`01-ticket-info` has none — real precedent elsewhere in the framework, e.g. `aidd-dev:01-plan`), never order. +- Every asset in `plugins/aidd-pm/skills/*/assets/*` is cited from a named action. `spec-validator.yml` is read against, not filled — the "consumed by a named action" reading (see `plan.md` Decisions) covers it. +- **Issue count correction:** issue #564 says "eight follow the contract, three don't" (= 11) and AC#1 says "the eleven routers." The plugin holds 10 skills, not 11 — 7 already matched the contract, 3 migrated here. Reporting this rather than silently treating "eleven" as satisfied. diff --git a/aidd_docs/tasks/2026_08/2026_08_10_migrate-pm-router-contract/plan.md b/aidd_docs/tasks/2026_08/2026_08_10_migrate-pm-router-contract/plan.md new file mode 100644 index 00000000..d48df384 --- /dev/null +++ b/aidd_docs/tasks/2026_08/2026_08_10_migrate-pm-router-contract/plan.md @@ -0,0 +1,53 @@ +--- +objective: "01-ticket-info, 03-prd, and 04-spec routers match the aidd-pm contract (07-epic shape): references/ hold every rule an action doesn't, TBD: has one spelling in one file, and the PRD sections live only in prd-template.md." +status: implemented +--- + +# Plan: Migrate ticket-info, PRD, spec to the router contract + +## Overview + +| Field | Value | +| ---------- | ---------------------------------------------------------------------- | +| **Goal** | Bring the 3 remaining `aidd-pm` skills in line with the other 7: mermaid flow, `\| Action \| Does \|` table, canonical lead-in, no `## Assets`, one rule one home. | +| **Source** | GitHub issue #564 (ai-driven-dev/framework) | + +Each phase migrates exactly one skill. Stop after each phase for interactive review before starting the next — explicit user instruction, not the default. + +## Phases + +| # | Phase | File | +| --- | ------------------------------- | ------------------------------ | +| 1 | Migrate `01-ticket-info` | [`phase-1.md`](./phase-1.md) | +| 2 | Migrate `03-prd` | [`phase-2.md`](./phase-2.md) | +| 3 | Migrate `04-spec` | [`phase-3.md`](./phase-3.md) | + +## Resources + +| Source | Verified | +| --------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | +| GitHub issue #564 | Scope, acceptance criteria, and the two corrected claims (argument-hint, `## Test` shape). | +| `plugins/aidd-pm/skills/07-epic/*` | Reference migration: router mermaid + `\| Action \| Does \|` shape, references/ split, canonical lead-in wording. | +| `plugins/aidd-context/skills/04-skill-generate/references/skill-authoring.md` | The contract, R1-R19, per artifact (skill, router, action, reference, asset). | +| `plugins/aidd-context/skills/04-skill-generate/assets/{skill,action}-template.md` | Exact canonical lead-in text and section order/frontmatter shape. | +| Direct read of all 3 target `SKILL.md` + `actions/*.md` | Confirmed every duplication the issue names, and the exact 3 spellings of `TBD:` in `04-spec`. | + +## Decisions + +| Decision | Why | +| -------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ | +| `TBD:` marker's one home is `04-spec/references/tbd-marker.md`, not a shared cross-skill reference | All 3 `TBD:` sites (`SKILL.md`, `01-build.md`, `02-refine.md`) live inside `04-spec`; this codebase doesn't share reference files across skills. | +| `references/` is per-skill judgment, not mandatory on all 3 | Issue Scope says "give each of the three a `references/` folder", but the literal AC only requires a rule to live in *an action or reference* — not that the folder exist. `01-ticket-info` gets one (`tool-detection.md`, genuinely lookup-table-shaped). `03-prd` doesn't — its only candidate (a one-sentence save path) isn't reference-shaped, inlined into `finalize` instead. | +| `01-ticket-info` ends up with no `## Transversal rules`; `03-prd` gets the 6-line pattern | `01-ticket-info`: every prior line moved to a reference or was a pure duplicate of `description` — real precedent, 8 framework skills ship `## Actions` with no `## Transversal rules`. `03-prd`: 6 of 7 already-migrated skills share 5 verbatim boilerplate lines + 1 skill-specific line — missed in the first draft, restored during review. | +| `03-prd` splits into `draft` + `finalize` (2 actions), matching `08-three-amigos`'s single-responsibility shape | User-requested during phase 2 review: the 1-action design (parse+draft+validate+save) was measurably more verbose per-action than every comparable migrated skill. Net behavior unchanged (same approval gate, same output) but this is action-count restructuring — past issue #564's literal "no behaviour change" scope. Extension flagged, not silently absorbed. | +| `03-prd`'s report contract drops `affected relations` and `before -> after` | Both copy-pasted from Task/Defect/Epic; neither applies — PRD has no `relations.md`, and always creates a fresh dated file (no update-in-place to diff). | +| `04-spec`'s build-vs-refine dispatch moves into the mermaid as two entry nodes, not prose | R7: a branch stated in prose is a branch missing from the flow; R17: one fact, one home. | +| One phase per skill, review gate between phases | User-requested; keeps each migration independently verifiable against the shape criterion. | +| Verify AC#1 (section order, all 10 skills) and AC#5 (every plugin asset filled) in phase 3, not a separate phase | Both criteria span skills beyond any single phase's scope; checking them after the last migration is cheaper than a 4th review-gated phase. | +| AC#5's "filled by an action" reads as "consumed by a named action" — a template is filled, a validator/checklist is read against | `spec-validator.yml` is read, never written; the issue's actual named defect is `task-template.md` being cited by nothing at all. Resolving the reading now avoids relitigating it mid-phase-3. | +| `04-spec` keeps its own 4-line `## Transversal rules`, not the epic/task/prd 5+1 boilerplate | Checked each shared line against what `build`/`refine` actually do: no approval gate before write, no lifecycle, TBD-marking instead of interactive questioning. None fit — matches `08-three-amigos`'s precedent of not sharing the boilerplate either. | +| `04-spec`'s report contract keeps `before -> after` in `refine`, drops it from `build`; drops `affected relations` from both | `refine` rewrites an existing file in place (real diff); `build` always creates fresh (nothing to diff). No `relations.md` exists for spec, same as PRD. | + +## Correction + +The issue's own arithmetic doesn't match the repo: "Eight `aidd-pm` skills follow the router contract. Three never migrated" (= 11) and AC#1 "the eleven `aidd-pm` routers" both assume 11 skills. `plugins/aidd-pm/skills/` holds 10 (`01`-`10`). 7 already match the contract (`02,05,06,07,08,09,10` — confirmed identical heading sequence, mermaid, and canonical lead-in against `07-epic`), plus the 3 this plan migrates = 10, not 11. Same category of error as the two claims the issue itself already corrected under "What already landed". Flagged for the user in phase 3, not silently resolved. diff --git a/plugins/aidd-pm/CATALOG.md b/plugins/aidd-pm/CATALOG.md index 4f526419..027f408b 100644 --- a/plugins/aidd-pm/CATALOG.md +++ b/plugins/aidd-pm/CATALOG.md @@ -34,6 +34,8 @@ Auto-generated index of skills, agents, references and assets shipped by the `ai | Group | File | Description | |-------|------|---| | `actions` | [01-ticket-info.md](skills/01-ticket-info/actions/01-ticket-info.md) | - | +| `assets` | [ticket-template.md](skills/01-ticket-info/assets/ticket-template.md) | - | +| `references` | [tool-detection.md](skills/01-ticket-info/references/tool-detection.md) | - | | `-` | [SKILL.md](skills/01-ticket-info/SKILL.md) | `Retrieve and display a ticket from the configured ticketing tool. Use when the user wants to see, show, or look up a ticket's details. Not for creating a ticket, or commenting on, transitioning, or reassigning one.` | #### `skills/02-user-stories` @@ -63,9 +65,9 @@ Auto-generated index of skills, agents, references and assets shipped by the `ai | Group | File | Description | |-------|------|---| -| `actions` | [01-prd.md](skills/03-prd/actions/01-prd.md) | - | +| `actions` | [01-draft.md](skills/03-prd/actions/01-draft.md) | - | +| `actions` | [02-finalize.md](skills/03-prd/actions/02-finalize.md) | - | | `assets` | [prd-template.md](skills/03-prd/assets/prd-template.md) | - | -| `assets` | [task-template.md](skills/03-prd/assets/task-template.md) | `Task tracking system to ensure all tasks are categorized and addressed` | | `-` | [SKILL.md](skills/03-prd/SKILL.md) | `Generate a structured Product Requirements Document from a need, idea, or brainstorm, confirmed before save. Use when the user wants to draft or generate a PRD or product requirements. Not for user stories or a technical plan.` | #### `skills/04-spec` @@ -75,6 +77,7 @@ Auto-generated index of skills, agents, references and assets shipped by the `ai | `actions` | [01-build.md](skills/04-spec/actions/01-build.md) | - | | `actions` | [02-refine.md](skills/04-spec/actions/02-refine.md) | - | | `assets` | [spec-template.md](skills/04-spec/assets/spec-template.md) | - | +| `references` | [tbd-marker.md](skills/04-spec/references/tbd-marker.md) | - | | `-` | [SKILL.md](skills/04-spec/SKILL.md) | `Generate or refine a spec, a feature's immutable contract, from a request, a PRD, or review findings. Use when the user wants to draft or refine a spec. Not for writing code, a full PRD, or changing a locked spec.` | #### `skills/05-spike` diff --git a/plugins/aidd-pm/skills/01-ticket-info/SKILL.md b/plugins/aidd-pm/skills/01-ticket-info/SKILL.md index 15887ab2..1e90b79b 100644 --- a/plugins/aidd-pm/skills/01-ticket-info/SKILL.md +++ b/plugins/aidd-pm/skills/01-ticket-info/SKILL.md @@ -6,19 +6,15 @@ argument-hint: ticket # Ticket Info -Reads ticket details from the configured ticketing tool. Read-only and tool-agnostic. +```mermaid +flowchart LR + source([ticket id, or none]) --> ticket-info --> done([ticket displayed]) +``` ## Actions -| # | Action | Role | Input | -| --- | -------------- | ------------------------------------------------------------- | ---------------------------------- | -| 01 | `ticket-info` | Resolve ticket id, query the configured tool, display fields | ticket_id (optional) | +Run the flow above. Read only the next action file. -Before running an action, read its file in `actions/`, not only the table or assets. - -## Transversal rules - -- Read the configured ticketing tool from project memory first; otherwise inspect repo configuration or environment. -- Auto-detect the ticket identifier from the current branch name when none is provided. -- Format the identifier per project convention before querying. -- Read-only: never create, comment, transition, or reassign from this skill. +| Action | Does | +| ------------- | --------------------------------------------------------- | +| ticket-info | resolve ticket id, query configured tool, display fields | diff --git a/plugins/aidd-pm/skills/01-ticket-info/actions/01-ticket-info.md b/plugins/aidd-pm/skills/01-ticket-info/actions/01-ticket-info.md index 134a1d28..95a09690 100644 --- a/plugins/aidd-pm/skills/01-ticket-info/actions/01-ticket-info.md +++ b/plugins/aidd-pm/skills/01-ticket-info/actions/01-ticket-info.md @@ -8,19 +8,17 @@ An optional ticket id or URL. When omitted, auto-detect it from the current bran ## Output -The ticket's title, description, status, assignee, priority, and URL, displayed for the user. +The ticket rendered per [ticket-template.md](../assets/ticket-template.md). ## Process -1. **Tool.** Use the ticketing tool declared in project memory. Otherwise inspect the repo configuration or environment for the configured tool. -2. **Identifier.** Use the provided ticket id when given. Otherwise take it from the current branch name, per project convention. -3. **Format.** Apply the project ticketing convention to the identifier (prefix, separator, casing). -4. **Query.** Invoke the configured ticketing tool to fetch the ticket record. -5. **Display.** Render the title, description, status, assignee, priority, and URL. +1. **Resolve.** Resolve the ticketing tool and the ticket identifier per [tool-detection.md](../references/tool-detection.md). +2. **Query.** Invoke the configured ticketing tool to fetch the ticket record. +3. **Display.** Fill [ticket-template.md](../assets/ticket-template.md) from the queried record and render it for the user. ## Test | Case | Pass | | --- | --- | -| The id resolves and the tool answers | title, description, status, assignee, priority, and URL match the queried record | +| The id resolves and the tool answers | every field `ticket-template.md` defines matches the queried record | | The displayed URL is opened | the tracker shows the same ticket | diff --git a/plugins/aidd-pm/skills/01-ticket-info/assets/ticket-template.md b/plugins/aidd-pm/skills/01-ticket-info/assets/ticket-template.md new file mode 100644 index 00000000..c34725e1 --- /dev/null +++ b/plugins/aidd-pm/skills/01-ticket-info/assets/ticket-template.md @@ -0,0 +1,12 @@ +<!-- Ticket display template. Fill every placeholder; strip this comment. --> + +# <Title> + +| Field | Value | +| --------- | ----------- | +| Status | <status> | +| Assignee | <assignee> | +| Priority | <priority> | +| URL | <url> | + +<Description, as written in the tracker.> diff --git a/plugins/aidd-pm/skills/01-ticket-info/references/tool-detection.md b/plugins/aidd-pm/skills/01-ticket-info/references/tool-detection.md new file mode 100644 index 00000000..92a44dca --- /dev/null +++ b/plugins/aidd-pm/skills/01-ticket-info/references/tool-detection.md @@ -0,0 +1,10 @@ +# Tool detection + +| Source, in order | Holds | +| -------------------- | ---------------------------- | +| project memory | the configured ticketing tool | +| repo configuration | fallback | +| environment | fallback | + +Ticket identifier: the one given, or the current branch name. +Format it per the project's ticketing convention (prefix, separator, casing). diff --git a/plugins/aidd-pm/skills/03-prd/SKILL.md b/plugins/aidd-pm/skills/03-prd/SKILL.md index c367c401..683b1ba3 100644 --- a/plugins/aidd-pm/skills/03-prd/SKILL.md +++ b/plugins/aidd-pm/skills/03-prd/SKILL.md @@ -6,25 +6,25 @@ argument-hint: need | brainstorm # PRD -Drafts a structured Product Requirements Document covering scope, goals, and acceptance criteria. +```mermaid +flowchart LR + source([feature description, optionally with user stories]) --> draft --> finalize --> done([saved PRD]) +``` ## Actions -| # | Action | Role | Input | -| --- | ------- | ---------------------------------------------------- | ----------------------------------------------- | -| 01 | `prd` | Parse input, draft per template, validate, save | feature_description, user_stories (optional) | +Run the flow above. Read only the next action file. -Before running an action, read its file in `actions/`, not only the table or assets. +| Action | Does | +| -------- | -------------------------------------- | +| draft | draft per template, iterate to approval | +| finalize | save the approved draft | ## Transversal rules -- Focus on what and why; never include technical implementation detail. -- Sections stay concise and actionable. -- Always wait for explicit user validation before saving. -- Save path: `aidd_docs/tasks/<yyyy_mm>/<yyyy_mm_dd>-<feature_name>-prd.md`. -- Source of truth for structure: `assets/prd-template.md`. - -## Assets - -- `assets/prd-template.md`: PRD body template. -- `assets/task-template.md`: Lightweight task template referenced from the PRD when needed. +- Keep product and lifecycle decisions with the user. +- Separate evidence, decisions, and assumptions. +- Preserve source links and existing edits. +- Ask natural questions; never expose actions, references, or unchanged state. +- Require explicit approval or caller-provided bounded authority before any write. +- State what and why; never a technical plan or user stories. diff --git a/plugins/aidd-pm/skills/03-prd/actions/01-draft.md b/plugins/aidd-pm/skills/03-prd/actions/01-draft.md new file mode 100644 index 00000000..068cf11e --- /dev/null +++ b/plugins/aidd-pm/skills/03-prd/actions/01-draft.md @@ -0,0 +1,27 @@ +# 01 - Draft + +Draft a PRD from the template, iterating with the user to approval. + +## Input + +A feature description, and optionally existing user stories. + +## Output + +One approved PRD draft. + +## Process + +1. **Parse.** Extract scope, goals, and constraints from the description and any user stories. +2. **Fill.** Draft [prd-template.md](../assets/prd-template.md), keeping every section concise and actionable. +3. **Show.** Present the full draft and wait for explicit approval. +4. **Revise.** Fold corrections and re-show until approved. + +## Test + +| Case | Pass | +| --- | --- | +| Draft shown | every section `prd-template.md` defines is present, and no other | +| Solution detail proposed | none: no tech-stack, data-model, architecture section, or code | +| Revision requested | draft updates, then re-shown | +| Approved | unchanged draft passed to `finalize` | diff --git a/plugins/aidd-pm/skills/03-prd/actions/01-prd.md b/plugins/aidd-pm/skills/03-prd/actions/01-prd.md deleted file mode 100644 index 8cd6ab10..00000000 --- a/plugins/aidd-pm/skills/03-prd/actions/01-prd.md +++ /dev/null @@ -1,28 +0,0 @@ -# 01 - PRD - -Parse the feature input, draft a structured PRD from the template, validate with the user, then save the file under `aidd_docs/tasks/`. - -## Input - -A feature description (required), and optionally existing user stories (ids or text) to anchor the PRD. - -## Output - -The saved PRD at `aidd_docs/tasks/<yyyy_mm>/<yyyy_mm_dd>-<feature_name>-prd.md`, carrying all eight sections. After writing, report its stable identity, changed fields as `before -> after`, affected relations, and verification result. Without a write, state that no persisted change occurred. - -## Process - -1. **Parse.** Extract the feature scope, goals, and constraints from the description and any user stories. -2. **Draft.** Fill [prd-template.md](../assets/prd-template.md) with its eight sections: overview, problem statement, goals, non-goals, user stories, acceptance criteria, dependencies, open questions. -3. **Validate.** Show the full draft, wait for explicit approval, and re-show after each revision. -4. **Save.** Write the approved PRD to its dated path, creating the month directory when missing. - -## Test - -| Case | Pass | -| --- | --- | -| The action completes | the PRD file exists on disk | -| The file is read back | it holds the eight headings of `assets/prd-template.md` and no other | -| Solution detail was proposed | no tech-stack, data-model, architecture section, `## Implementation` heading, or source code was written | -| A write happened | the result reports the stable identity, `before -> after` fields, affected relations, and verification result | -| No write happened | the result states that no persisted change occurred | diff --git a/plugins/aidd-pm/skills/03-prd/actions/02-finalize.md b/plugins/aidd-pm/skills/03-prd/actions/02-finalize.md new file mode 100644 index 00000000..c52db39e --- /dev/null +++ b/plugins/aidd-pm/skills/03-prd/actions/02-finalize.md @@ -0,0 +1,24 @@ +# 02 - Finalize + +Save the approved PRD. + +## Input + +One approved PRD draft. + +## Output + +The saved PRD, or no change if not written. + +## Process + +1. **Save.** Write to `aidd_docs/tasks/<yyyy_mm>/<yyyy_mm_dd>-<feature_name>-prd.md`, creating the month directory when missing. +2. **Verify.** Read the saved PRD back and report what changed. + +## Test + +| Case | Pass | +| --- | --- | +| Save succeeds | the PRD file exists on disk | +| Save reported | identity and verification result | +| No write happened | the result states that no persisted change occurred | diff --git a/plugins/aidd-pm/skills/03-prd/assets/task-template.md b/plugins/aidd-pm/skills/03-prd/assets/task-template.md deleted file mode 100644 index 5f71ea95..00000000 --- a/plugins/aidd-pm/skills/03-prd/assets/task-template.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -name: task -description: Task tracking system to ensure all tasks are categorized and addressed ---- - -# Task [<feature_name>] - -{{Full description}} - -## Main step 1 - -- [ ] {Task 1} -- [ ] {Task 2} -- [ ] {Task 3} -- ... diff --git a/plugins/aidd-pm/skills/04-spec/SKILL.md b/plugins/aidd-pm/skills/04-spec/SKILL.md index 9763776f..10afd34c 100644 --- a/plugins/aidd-pm/skills/04-spec/SKILL.md +++ b/plugins/aidd-pm/skills/04-spec/SKILL.md @@ -6,27 +6,25 @@ argument-hint: request | prd | spec # Spec -Generate or refine the immutable contract for a feature: its target, hard constraints, non-goals, and done-when. +```mermaid +flowchart LR + request([request or PRD path]) --> build --> done([spec.md]) + target([spec path + findings]) --> refine --> done +``` ## Actions -| # | Action | Role | Input | -| --- | -------- | ---------------------------------------------------- | ---------------------------- | -| 01 | `build` | Draft a fresh spec from a request or an existing PRD | a request or a PRD path | -| 02 | `refine` | Rewrite an existing spec to address review findings | a spec path and the findings | +Run the flow above. Read only the next action file. -Dispatch by input: a spec path with findings runs `refine`; a request or PRD path runs `build`. -Before running an action, read its file in `actions/`, not only the table or assets. +| Action | Does | +| ------ | -------------------------------------------------- | +| build | draft a fresh spec from a request or PRD | +| refine | rewrite an existing spec to address findings | ## Transversal rules -- Never invent. Mark every gap as `TBD: <precise question>` rather than guessing. When a request is too vague to draft anything useful, stop and ask for a clearer one. -- The spec holds intent, never implementation. It is solution-agnostic: no file, component, hook, route, library, pattern, or token, and no "how". The done-when conditions are outcome-level, not steps. Keep the acceptance criteria few. All of that belongs to the plan. -- Keep it readable: clear section headers, bulleted criteria, explicit non-goals. -- Output: one `spec.md` in the feature folder (`aidd_docs/tasks/<yyyy_mm>/<yyyy_mm_dd>_<slug>/`), from `assets/spec-template.md`. Reuse the folder when it exists. -- Immutable once validated: never rewrite a spec that has been locked. - -## Assets - -- `assets/spec-template.md`: the spec's structure. -- `assets/spec-validator.yml`: the checklist a spec is validated against. +- Never invent; mark every gap instead of guessing. +- Never explore the codebase. +- Hold intent, never implementation: solution-agnostic, no how, few acceptance criteria. +- Keep it readable: clear headers, bulleted criteria, explicit non-goals. +- Immutable once validated: never rewrite a locked spec. diff --git a/plugins/aidd-pm/skills/04-spec/actions/01-build.md b/plugins/aidd-pm/skills/04-spec/actions/01-build.md index a2076de9..ba2e7111 100644 --- a/plugins/aidd-pm/skills/04-spec/actions/01-build.md +++ b/plugins/aidd-pm/skills/04-spec/actions/01-build.md @@ -8,15 +8,18 @@ A free-form request, or a path to an existing PRD. A feature name for the folder ## Output -The path to `spec.md` in the feature folder, drafted from the template, with the ambiguities and assumptions noted. Report its stable identity, changed fields as `before -> after`, affected relations, and verification result. Without a write, state that no persisted change occurred. +The path to `spec.md` in the feature folder, drafted from the template, with the ambiguities and assumptions noted, or no write when the request is too vague. ## Process -1. **Source.** From a PRD path, lift its target, hard constraints, non-goals, and done-when into the template, dropping any implementation detail. From a request, map it onto the template sections directly. Do not explore the codebase. -2. **Gaps.** Replace any missing required field with `TBD: <precise question>`. Never guess. -3. **Check.** Confirm every section the validator requires is present. Omit an optional section (stakeholders, context) that has nothing to say rather than emit a placeholder. -4. **Write.** Resolve the feature folder, reusing it when it exists, and save the spec there as `spec.md`. -5. **Return.** Surface the spec path and the notes. +1. **Qualify.** When the request is too vague to draft anything useful, stop and ask for a clearer one. +2. **Source.** Map the input onto [spec-template.md](../assets/spec-template.md), dropping any implementation detail. + - PRD path: lift its target, hard constraints, non-goals, and done-when. + - Free-form request: map it directly onto the template sections. +3. **Gaps.** Replace any missing required field per [tbd-marker.md](../references/tbd-marker.md). +4. **Check.** Confirm every section the validator requires is present. Omit an optional section (stakeholders, context) that has nothing to say rather than emit a placeholder. +5. **Write.** Resolve the feature folder: reuse an existing `aidd_docs/tasks/<yyyy_mm>/<yyyy_mm_dd>_<slug>/` match for this feature, or create one. Save it there. +6. **Return.** Surface its path and the notes. ## Test @@ -25,5 +28,4 @@ The path to `spec.md` in the feature folder, drafted from the template, with the | The action completes | `spec.md` exists in the feature folder | | The file is validated | every section required by [spec-validator.yml](../assets/spec-validator.yml) is present | | The spec is read back | it carries no library name, framework pattern, or source-file layout | -| A write happened | the result reports the stable identity, `before -> after` fields, affected relations, and verification result | -| No write happened | the result states that no persisted change occurred | +| Too vague | no write; one clarifying question returned | diff --git a/plugins/aidd-pm/skills/04-spec/actions/02-refine.md b/plugins/aidd-pm/skills/04-spec/actions/02-refine.md index 06cf699d..cf4e7f6f 100644 --- a/plugins/aidd-pm/skills/04-spec/actions/02-refine.md +++ b/plugins/aidd-pm/skills/04-spec/actions/02-refine.md @@ -8,15 +8,16 @@ The path to the current spec, and the findings to address, a list or free text. ## Output -The refined spec at the same path, with the changes applied and any residual `TBD` questions noted. Report its stable identity, changed fields as `before -> after`, affected relations, and verification result. Without a write, state that no persisted change occurred. +The refined spec at the same path, or no change if not written. ## Process 1. **Load.** Read the spec and the findings. 2. **Map.** Pair each finding with the section it touches. 3. **Rewrite.** Apply each finding in place: clarify wording, add missing fields, remove invalid claims. Leave untouched sections as they are. -4. **Gaps.** Replace any field still unanswered with `TBD: <precise question>`. Never guess. +4. **Gaps.** Replace any field still unanswered per [tbd-marker.md](../references/tbd-marker.md). 5. **Check.** Confirm every section the validator requires is present, then overwrite the spec at its path. +6. **Verify.** Report what changed as `before -> after`, and the verification result. ## Test @@ -24,6 +25,6 @@ The refined spec at the same path, with the changes applied and any residual `TB | --- | --- | | The action completes | the spec still exists at its path with every section required by [spec-validator.yml](../assets/spec-validator.yml) | | A finding is resolved | the spec changed at the section it names | -| A finding cannot be resolved | an explicit `TBD: <question>` marks it in place | -| A write happened | the result reports the stable identity, `before -> after` fields, affected relations, and verification result | +| A finding cannot be resolved | the marker from [tbd-marker.md](../references/tbd-marker.md) marks it in place | +| A write happened | the result reports the stable identity, `before -> after` fields, and verification result | | No write happened | the result states that no persisted change occurred | diff --git a/plugins/aidd-pm/skills/04-spec/references/tbd-marker.md b/plugins/aidd-pm/skills/04-spec/references/tbd-marker.md new file mode 100644 index 00000000..9cbcbda6 --- /dev/null +++ b/plugins/aidd-pm/skills/04-spec/references/tbd-marker.md @@ -0,0 +1,3 @@ +# TBD marker + +`TBD: <precise question>` From 8d1a6166e1e85feb05c5e805881b802686767b81 Mon Sep 17 00:00:00 2001 From: Baptiste LAFOURCADE <119650761+blafourcade@users.noreply.github.com> Date: Fri, 14 Aug 2026 09:55:48 +0200 Subject: [PATCH 11/14] fix(ci): render the star history chart from the repo's own token (#627) * ci: render the star history chart in the repo's own CI GitHub restricted the stargazers API to a repository's own admins and collaborators on June 30 2026, so the third-party chart the README embeds now returns a placeholder telling readers the data is unavailable. The repository can still read its own stargazers, so the chart is rendered here from that data and published on the star-history orphan branch. No credential leaves the repository, and the renderer is deterministic, so a run that finds no new star produces no commit. The push trigger is temporary: schedule and workflow_dispatch only fire from the default branch, so it is the only way to exercise the workflow before the merge. It is removed later in this same pull request. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs: point the star chart at the self-hosted SVG api.star-history.com now answers with a placeholder image reading "GitHub restricted access to star data", so the README advertised a dead chart. It now embeds the SVG this repository renders itself, and the image links to the stargazers page. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * ci: drop the temporary trigger from the star history workflow It existed to run the workflow from this branch, since schedule and workflow_dispatch only fire from the default branch. Runs 31746866236 and 31746963019 proved both paths: the first published the chart, the second found no new star and committed nothing. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * style(ci): drop the em-dash from the star chart caption Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com> --- .github/workflows/star-history.yml | 66 ++++++++++++++ README.md | 2 +- scripts/generate-star-history.mjs | 135 +++++++++++++++++++++++++++++ 3 files changed, 202 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/star-history.yml create mode 100644 scripts/generate-star-history.mjs diff --git a/.github/workflows/star-history.yml b/.github/workflows/star-history.yml new file mode 100644 index 00000000..0184d883 --- /dev/null +++ b/.github/workflows/star-history.yml @@ -0,0 +1,66 @@ +name: Star history + +# Regenerates the star history chart the README embeds. GitHub restricted the +# stargazers API to a repository's own admins and collaborators on June 30 2026, +# so no third-party service can draw this chart any more — only the repository +# itself can, with its own token. +# +# The SVG is published on the `star-history` orphan branch rather than committed +# to main: main requires a pull request, and a data-only branch keeps generated +# bytes out of the source history while staying servable over raw.githubusercontent. + +on: + schedule: + - cron: "0 5 * * 1" # Mondays 05:00 UTC + workflow_dispatch: + +concurrency: + group: star-history + cancel-in-progress: false + +permissions: + contents: write + +jobs: + star-history: + name: Render the chart and publish it + runs-on: ubuntu-latest + env: + BRANCH: star-history + FILE: star-history.svg + steps: + - name: Checkout + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - name: Setup Node + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + with: + node-version: "22" + + - name: Render the chart + env: + GH_TOKEN: ${{ github.token }} + run: node scripts/generate-star-history.mjs > "$FILE" + + - name: Publish it to the ${{ env.BRANCH }} branch + run: | + set -euo pipefail + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + + parent="" + if git fetch --depth=1 origin "$BRANCH" 2>/dev/null; then + parent=$(git rev-parse FETCH_HEAD) + fi + + blob=$(git hash-object -w "$FILE") + tree=$(printf '100644 blob %s\t%s\n' "$blob" "$FILE" | git mktree) + + # The renderer is deterministic, so an identical tree means no new star. + if [ -n "$parent" ] && [ "$(git rev-parse "$parent^{tree}")" = "$tree" ]; then + echo "Star history unchanged." + exit 0 + fi + + commit=$(git commit-tree "$tree" ${parent:+-p "$parent"} -m "chore(ci): refresh star history chart") + git push origin "$commit:refs/heads/$BRANCH" diff --git a/README.md b/README.md index 74777425..d08a2c21 100644 --- a/README.md +++ b/README.md @@ -326,7 +326,7 @@ Free and open-source (MIT). If it saves you time, [a ⭐](https://github.com/ai- <div align="center"> -<img src="https://api.star-history.com/svg?repos=ai-driven-dev/framework&type=Date" alt="Star History Chart" width="500" /> +<a href="https://github.com/ai-driven-dev/framework/stargazers"><img src="https://raw.githubusercontent.com/ai-driven-dev/framework/star-history/star-history.svg" alt="Star History Chart" width="500" /></a> Made with care in France 🇫🇷 · ← [AIDD organisation](https://github.com/ai-driven-dev) diff --git a/scripts/generate-star-history.mjs b/scripts/generate-star-history.mjs new file mode 100644 index 00000000..a97ba2d1 --- /dev/null +++ b/scripts/generate-star-history.mjs @@ -0,0 +1,135 @@ +#!/usr/bin/env node +// Renders the repository's star history as an SVG on stdout, from the GitHub +// stargazers API. Since June 30 2026 that API only answers a repository's own +// admins and collaborators, which killed the third-party chart services the +// README used to embed. Running it here, with the repository's own credentials, +// is the only way left to keep a live chart. +// +// GH_TOKEN=$(gh auth token) node scripts/generate-star-history.mjs > star-history.svg +// +// The output is deterministic: identical star data yields identical bytes, so a +// scheduled run that finds no new star produces no commit. Nothing renders the +// current date, and no <style> or <script> is emitted, because GitHub strips +// both when it serves an SVG into a README. + +const REPO = process.env.GITHUB_REPOSITORY ?? "ai-driven-dev/framework"; +const TOKEN = process.env.GH_TOKEN ?? process.env.GITHUB_TOKEN; + +const WIDTH = 800; +const HEIGHT = 400; +const MARGIN = { top: 28, right: 24, bottom: 40, left: 60 }; +const MAX_POINTS = 200; +const X_TICKS = 5; +const Y_TICKS = 4; + +const AXIS_COLOR = "#8b949e"; +const GRID_COLOR = "#8b949e40"; +const LINE_COLOR = "#e3b341"; +const AREA_COLOR = "#e3b34126"; + +const PLOT_WIDTH = WIDTH - MARGIN.left - MARGIN.right; +const PLOT_HEIGHT = HEIGHT - MARGIN.top - MARGIN.bottom; + +async function fetchStarDates() { + const dates = []; + let url = `https://api.github.com/repos/${REPO}/stargazers?per_page=100`; + + while (url) { + const response = await fetch(url, { + headers: { + accept: "application/vnd.github.star+json", + "x-github-api-version": "2022-11-28", + ...(TOKEN ? { authorization: `Bearer ${TOKEN}` } : {}), + }, + }); + + if (!response.ok) { + throw new Error(`GET ${url} -> ${response.status} ${response.statusText}`); + } + + for (const { starred_at } of await response.json()) { + if (starred_at) dates.push(Date.parse(starred_at)); + } + + url = nextPage(response.headers.get("link")); + } + + return dates.sort((a, b) => a - b); +} + +function nextPage(linkHeader) { + return linkHeader?.match(/<([^>]+)>;\s*rel="next"/)?.[1] ?? null; +} + +// A cumulative curve of N stars is N points; every chart is 800px wide. Keeping +// one point per pixel at most holds the file small without any visible loss. +function sample(dates) { + if (dates.length <= MAX_POINTS) { + return dates.map((date, index) => ({ date, count: index + 1 })); + } + + const step = (dates.length - 1) / (MAX_POINTS - 1); + return Array.from({ length: MAX_POINTS }, (_, i) => { + const index = Math.round(i * step); + return { date: dates[index], count: index + 1 }; + }); +} + +// Rounds a tick step up to the next 1, 2 or 5 x 10^k, so labels read as round +// numbers instead of arbitrary fractions of the total. +function niceStep(rawStep) { + const magnitude = 10 ** Math.floor(Math.log10(rawStep)); + const normalized = rawStep / magnitude; + const rounded = normalized <= 1 ? 1 : normalized <= 2 ? 2 : normalized <= 5 ? 5 : 10; + return rounded * magnitude; +} + +function buildSvg(points) { + const firstDate = points[0].date; + const lastDate = points[points.length - 1].date; + const total = points[points.length - 1].count; + const span = Math.max(lastDate - firstDate, 1); + + const x = (date) => MARGIN.left + ((date - firstDate) / span) * PLOT_WIDTH; + const y = (count) => MARGIN.top + PLOT_HEIGHT - (count / total) * PLOT_HEIGHT; + const round = (value) => Math.round(value * 10) / 10; + + const curve = points.map((p) => `${round(x(p.date))},${round(y(p.count))}`).join(" "); + const baseline = MARGIN.top + PLOT_HEIGHT; + + const yStep = niceStep(total / Y_TICKS); + const yTicks = []; + for (let count = 0; count <= total; count += yStep) yTicks.push(count); + + const xTicks = Array.from({ length: X_TICKS }, (_, i) => firstDate + (span * i) / (X_TICKS - 1)); + + return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${WIDTH} ${HEIGHT}" width="${WIDTH}" height="${HEIGHT}" font-family="sans-serif" font-size="12"> +<title>Star history of ${REPO}: ${total} stars +${yTicks + .map( + (count) => + `` + + `${count}`, + ) + .join("\n")} +${xTicks + .map((date, index) => { + // The edge labels are anchored inwards, otherwise half of each sits outside the viewBox. + const anchor = index === 0 ? "start" : index === xTicks.length - 1 ? "end" : "middle"; + return `${new Date(date).toISOString().slice(0, 7)}`; + }) + .join("\n")} + + +${REPO} · ${total} stars + +`; +} + +const dates = await fetchStarDates(); + +if (dates.length < 2) { + throw new Error(`${REPO} has ${dates.length} dated star(s); nothing to chart.`); +} + +process.stdout.write(buildSvg(sample(dates))); From 304960c15c361f1254538d9a64e6085d1dae1be9 Mon Sep 17 00:00:00 2001 From: David MOHAMED Date: Fri, 14 Aug 2026 10:21:18 +0200 Subject: [PATCH 12/14] fix(cli): transform codex marketplace skills (#571) * fix(cli): transform codex marketplace skills Reuse the Codex skill-frontmatter conversion when building native marketplace artifacts so installed skills do not declare Claude models.\n\nRefs ai-driven-dev/framework#570 * refactor(cli): simplify marketplace skill writing --- .../phase-1.md | 51 +++++++++++++++++++ .../phase-2.md | 47 +++++++++++++++++ .../plan.md | 32 ++++++++++++ .../review.md | 34 +++++++++++++ .../validation.md | 32 ++++++++++++ .../strategies/marketplace-build-strategy.ts | 5 +- .../marketplace-strategy-helpers.ts | 35 +++++++++---- .../framework/strategies/tool-contracts.ts | 11 +++- cli/src/domain/models/framework-build.ts | 1 + cli/src/domain/tools/ai/codex.ts | 2 +- ...e-build-strategy.codex.integration.test.ts | 39 ++++++++++++++ .../aidd-codex-fixture/skills/sample/SKILL.md | 4 ++ .../skills/sample/assets/template.md | 7 +++ 13 files changed, 286 insertions(+), 14 deletions(-) create mode 100644 aidd_docs/tasks/2026_08/2026_08_03_codex-marketplace-skill-transform/phase-1.md create mode 100644 aidd_docs/tasks/2026_08/2026_08_03_codex-marketplace-skill-transform/phase-2.md create mode 100644 aidd_docs/tasks/2026_08/2026_08_03_codex-marketplace-skill-transform/plan.md create mode 100644 aidd_docs/tasks/2026_08/2026_08_03_codex-marketplace-skill-transform/review.md create mode 100644 aidd_docs/tasks/2026_08/2026_08_03_codex-marketplace-skill-transform/validation.md create mode 100644 cli/tests/fixtures/framework-codex/plugins/aidd-codex-fixture/skills/sample/assets/template.md diff --git a/aidd_docs/tasks/2026_08/2026_08_03_codex-marketplace-skill-transform/phase-1.md b/aidd_docs/tasks/2026_08/2026_08_03_codex-marketplace-skill-transform/phase-1.md new file mode 100644 index 00000000..2e0618f9 --- /dev/null +++ b/aidd_docs/tasks/2026_08/2026_08_03_codex-marketplace-skill-transform/phase-1.md @@ -0,0 +1,51 @@ +--- +status: done +--- + +# Instruction: Apply and prove skill transformation + +## Architecture projection + +> Tree of the final files. ✅ create · ✏️ modify · ❌ delete + +```txt +. +✏️ cli/src/application/use-cases/framework/strategies/marketplace-build-strategy.ts +✏️ cli/src/application/use-cases/framework/strategies/marketplace-strategy-helpers.ts +✏️ cli/src/application/use-cases/framework/strategies/tool-contracts.ts +✏️ cli/src/domain/tools/ai/codex.ts +✏️ cli/tests/application/use-cases/framework/marketplace-build-strategy.codex.integration.test.ts +``` + +## User Journey + +```mermaid +flowchart TD + A[Framework source skill] --> B[Codex marketplace build] + B --> C[Codex-transformed SKILL.md] + C --> D[Native marketplace artifact] +``` + +## Tasks to do + +### `1)` Reuse the Codex skill converter during marketplace builds + +> Route markdown skill files through the target artifact transform after link rewriting. + +1. Extend the marketplace skill-tree writer to receive and apply the skill artifact transform. +2. Expose or extract the existing Codex frontmatter allowlist as the build transform's source of truth. +3. Configure the Codex marketplace contract to transform skill markdown while preserving non-markdown assets and existing link rewriting. + +### `2)` Lock the regression with an integration test + +> Assert the native Codex marketplace artifact omits `model` and unsupported frontmatter. + +1. Add a fixture-backed test covering a skill with Claude model metadata. +2. Assert supported Codex frontmatter remains and `model` is absent. + +## Test acceptance criteria + +| Task | Acceptance criteria | +| --- | --- | +| 1 | A Codex marketplace build emits every markdown skill using the Codex frontmatter allowlist, while source skills remain unchanged. | +| 2 | The build integration suite fails if a native Codex marketplace `SKILL.md` contains `model`. | diff --git a/aidd_docs/tasks/2026_08/2026_08_03_codex-marketplace-skill-transform/phase-2.md b/aidd_docs/tasks/2026_08/2026_08_03_codex-marketplace-skill-transform/phase-2.md new file mode 100644 index 00000000..4633db1b --- /dev/null +++ b/aidd_docs/tasks/2026_08/2026_08_03_codex-marketplace-skill-transform/phase-2.md @@ -0,0 +1,47 @@ +--- +status: done +--- + +# Instruction: Verify installed origin marketplace + +## Architecture projection + +> Tree of the final files. ✅ create · ✏️ modify · ❌ delete + +```txt +. +``` + +## User Journey + +```mermaid +flowchart TD + A[Build current origin] --> B[Install its Codex marketplace] + B --> C[Inspect installed skills] + C --> D[No model frontmatter] +``` + +## Tasks to do + +### `1)` Build and test the current origin + +> Run the targeted regression suite and create a fresh Codex marketplace output from this worktree. + +1. Run the Codex marketplace integration tests. +2. Build a fresh Codex marketplace from the worktree. +3. Scan the generated `SKILL.md` files for a `model` frontmatter key. + +### `2)` Install and identify the local origin artifact + +> Use Codex to install the marketplace generated from this worktree in an isolated Codex home, then inspect installed skills and marketplace metadata. + +1. Install from a local artifact or an origin-addressable ref that names this repository, never the upstream repository. +2. Assert installed skill files contain no `model` frontmatter key. +3. Assert installation metadata identifies this origin artifact, not `ai-driven-dev/framework`. + +## Test acceptance criteria + +| Task | Acceptance criteria | +| --- | --- | +| 1 | The current-worktree Codex marketplace build and targeted integration tests succeed, and generated skills have no `model` key. | +| 2 | An isolated Codex installation sourced from this origin artifact has no `model` key in installed `SKILL.md` files and carries origin-specific marketplace identity. | diff --git a/aidd_docs/tasks/2026_08/2026_08_03_codex-marketplace-skill-transform/plan.md b/aidd_docs/tasks/2026_08/2026_08_03_codex-marketplace-skill-transform/plan.md new file mode 100644 index 00000000..cab96086 --- /dev/null +++ b/aidd_docs/tasks/2026_08/2026_08_03_codex-marketplace-skill-transform/plan.md @@ -0,0 +1,32 @@ +--- +objective: "Codex marketplace installs from this origin distribute transformed SKILL.md files with no model frontmatter." +status: reviewed +--- + +# Plan: Transform Codex marketplace skills + +## Overview + +| Field | Value | +| --- | --- | +| **Goal** | Make native Codex marketplace output use the same skill-frontmatter conversion as the AIDD CLI install path. | +| **Source** | [upstream issue #570](https://github.com/ai-driven-dev/framework/issues/570) | + +## Phases + +| # | Phase | File | +| --- | --- | --- | +| 1 | Apply and prove skill transformation | [phase-1.md](./phase-1.md) | +| 2 | Verify installed origin marketplace | [phase-2.md](./phase-2.md) | + +## Resources + +| Source | Verified | +| --- | --- | +| https://github.com/ai-driven-dev/framework/issues/570 | Native Codex marketplace currently bypasses `stripCodexSkillFrontmatter`; installed skills must omit `model`. | + +## Decisions + +| Decision | Why | +| --- | --- | +| Make marketplace skill writes honor each target's existing skill artifact transform. | It reuses the target contract rather than adding a Codex-only branch, keeps Claude source untouched, and makes native marketplace output follow the same conversion policy as the CLI install path. | diff --git a/aidd_docs/tasks/2026_08/2026_08_03_codex-marketplace-skill-transform/review.md b/aidd_docs/tasks/2026_08/2026_08_03_codex-marketplace-skill-transform/review.md new file mode 100644 index 00000000..968b3506 --- /dev/null +++ b/aidd_docs/tasks/2026_08/2026_08_03_codex-marketplace-skill-transform/review.md @@ -0,0 +1,34 @@ +# Review: Transform Codex marketplace skills + +- **Verdict**: approve +- **Diff**: `main...20e46f31967a308c795015c975fd89967ba2cdf1 + worktree` +- **Axes run**: code, functional, relevancy +- **Date**: 2026-08-03 +- **Findings**: 0 critical, 0 warning, 0 minor + +## Phases + +### Phase 1 — Apply and prove skill transformation + +- [x] A Codex marketplace build emits every `SKILL.md` using the Codex frontmatter allowlist while source skills remain unchanged; auxiliary Markdown assets remain byte-preserved. — `cli/src/application/use-cases/framework/strategies/marketplace-build-strategy.ts:80-84`, `cli/src/application/use-cases/framework/strategies/marketplace-strategy-helpers.ts:93-102`, `cli/src/application/use-cases/framework/strategies/tool-contracts.ts:337-360`, `cli/tests/application/use-cases/framework/marketplace-build-strategy.codex.integration.test.ts:227-263` +- [x] The build integration suite fails if a native Codex marketplace `SKILL.md` contains `model`. — `cli/tests/application/use-cases/framework/marketplace-build-strategy.codex.integration.test.ts:227-243`, `cli/tests/fixtures/framework-codex/plugins/aidd-codex-fixture/skills/sample/SKILL.md:1-8` + +### Phase 2 — Verify installed origin marketplace + +- [x] The current-worktree Codex marketplace build and targeted integration tests succeed, and generated `SKILL.md` files have no `model` key. — `aidd_docs/tasks/2026_08/2026_08_03_codex-marketplace-skill-transform/validation.md:3-10`, `aidd_docs/tasks/2026_08/2026_08_03_codex-marketplace-skill-transform/validation.md:31-32`; `pnpm vitest run tests/application/use-cases/framework/marketplace-build-strategy.codex.integration.test.ts` => `30 passed` +- [x] An isolated Codex installation sourced from the local artifact has no `model` in installed `SKILL.md` and carries origin-specific marketplace identity. — `aidd_docs/tasks/2026_08/2026_08_03_codex-marketplace-skill-transform/validation.md:17-32` (`sourceType: local`, local artifact path, 13 installed `SKILL.md`, scan clean) + +## Findings + +| Sev | Kind | Phase | Location | Issue | Fix | +| --- | ---- | ----- | -------- | ----- | --- | +| — | — | — | — | None. | — | + +## Verification + +| Metric | Value | +| --- | --- | +| Verified | 100% (4/4) | +| Files checked | `cli/src/application/use-cases/framework/strategies/marketplace-build-strategy.ts`, `cli/src/application/use-cases/framework/strategies/marketplace-strategy-helpers.ts`, `cli/src/application/use-cases/framework/strategies/tool-contracts.ts`, `cli/src/domain/tools/ai/codex.ts`, `cli/tests/application/use-cases/framework/marketplace-build-strategy.codex.integration.test.ts`, `cli/tests/fixtures/framework-codex/plugins/aidd-codex-fixture/skills/sample/SKILL.md`, `cli/tests/fixtures/framework-codex/plugins/aidd-codex-fixture/skills/sample/assets/template.md`, `aidd_docs/tasks/2026_08/2026_08_03_codex-marketplace-skill-transform/validation.md` | +| Unchecked | none | +| Unplanned | `aidd_docs/tasks/2026_08/2026_08_03_codex-marketplace-skill-transform/review.md` is the required review deliverable; none otherwise | diff --git a/aidd_docs/tasks/2026_08/2026_08_03_codex-marketplace-skill-transform/validation.md b/aidd_docs/tasks/2026_08/2026_08_03_codex-marketplace-skill-transform/validation.md new file mode 100644 index 00000000..72e25709 --- /dev/null +++ b/aidd_docs/tasks/2026_08/2026_08_03_codex-marketplace-skill-transform/validation.md @@ -0,0 +1,32 @@ +# Native Codex installation validation + +Observed on 2026-08-03 from a locally built marketplace artifact: + +```json +{ + "marketplaceName": "aidd-framework", + "installedRoot": "/private/tmp/aidd-codex-marketplace.EOuI9t/marketplace", + "alreadyAdded": false +} +``` + +Installed plugin identity: + +```json +{ + "pluginId": "aidd-context@aidd-framework", + "installedPath": "/tmp/aidd-codex-marketplace.EOuI9t/home/.codex/plugins/cache/aidd-framework/aidd-context/2.5.0", + "source": { + "source": "local", + "path": "/private/tmp/aidd-codex-marketplace.EOuI9t/marketplace/plugins/aidd-context" + }, + "marketplaceSource": { + "sourceType": "local", + "source": "/private/tmp/aidd-codex-marketplace.EOuI9t/marketplace" + } +} +``` + +`sourceType: "local"` and the temporary artifact path prove this is not the upstream +`ai-driven-dev/framework` marketplace. The installed cache contained 13 `SKILL.md` files; +the completed `^model:` scan returned no matches. diff --git a/cli/src/application/use-cases/framework/strategies/marketplace-build-strategy.ts b/cli/src/application/use-cases/framework/strategies/marketplace-build-strategy.ts index c3cc931c..18798641 100644 --- a/cli/src/application/use-cases/framework/strategies/marketplace-build-strategy.ts +++ b/cli/src/application/use-cases/framework/strategies/marketplace-build-strategy.ts @@ -78,9 +78,10 @@ export class MarketplaceBuildStrategy implements BuildOutputStrategy { } async writeSkills(pluginName: string, pluginSrc: string, outDir: string): Promise { - if (!this.contract.artifacts.skills.supported) return 0; + const artifact = this.contract.artifacts.skills; + if (!artifact.supported) return 0; const pluginOut = join(outDir, "plugins", pluginName); - return writeSkillTree(this.fs, pluginName, pluginSrc, pluginOut); + return writeSkillTree(this.fs, pluginName, pluginSrc, pluginOut, artifact.transform); } async writeHooks(pluginName: string, pluginSrc: string, outDir: string): Promise { diff --git a/cli/src/application/use-cases/framework/strategies/marketplace-strategy-helpers.ts b/cli/src/application/use-cases/framework/strategies/marketplace-strategy-helpers.ts index 45234b04..10c87a55 100644 --- a/cli/src/application/use-cases/framework/strategies/marketplace-strategy-helpers.ts +++ b/cli/src/application/use-cases/framework/strategies/marketplace-strategy-helpers.ts @@ -1,15 +1,17 @@ -import { join, relative } from "node:path"; +import { basename, join, relative } from "node:path"; import { InvalidSourceMarketplaceError } from "../../../../domain/errors.js"; import { rewriteRelativeLinks } from "../../../../domain/formats/relative-link-rewrite.js"; import { PLUGIN_AGENT_INPUT_EXT, PLUGIN_HOOKS_RELATIVE, PLUGIN_MCP_RELATIVE, + PLUGIN_SKILL_ENTRY_FILE, } from "../../../../domain/models/framework-build.js"; import type { FileReader } from "../../../../domain/ports/file-reader.js"; import type { FileWriter } from "../../../../domain/ports/file-writer.js"; import { assertNoToolsPlaceholder } from "../shared-plugin-helpers.js"; +type SkillContentTransform = (content: string, plugin: string, basename: string) => string; export interface PluginPresenceFlags { readonly hasAgents: boolean; /** Agent markdown files relative to the plugin's `agents/` dir (e.g. "planner.md"), sorted. */ @@ -40,7 +42,11 @@ export async function listSkillNames( const files = await fs.listFilesRecursive(skillsDir); const names = new Set(); for (const f of files) { - if (!f.endsWith("/SKILL.md") && !f.endsWith("\\SKILL.md") && !f.endsWith("SKILL.md")) { + if ( + !f.endsWith(`/${PLUGIN_SKILL_ENTRY_FILE}`) && + !f.endsWith(`\\${PLUGIN_SKILL_ENTRY_FILE}`) && + !f.endsWith(PLUGIN_SKILL_ENTRY_FILE) + ) { continue; } const rel = relative(skillsDir, f); @@ -66,14 +72,15 @@ export async function writeSkillTree( fs: FileReader & FileWriter, pluginName: string, pluginSrc: string, - pluginOut: string + pluginOut: string, + transform?: SkillContentTransform ): Promise { const skillsSrc = join(pluginSrc, "skills"); if (!(await fs.fileExists(skillsSrc))) return 0; const files = await fs.listFilesRecursive(skillsSrc); let count = 0; for (const absPath of files) { - count += await writeSkillFile(fs, pluginName, absPath, skillsSrc, pluginOut); + count += await writeSkillFile(fs, pluginName, absPath, skillsSrc, pluginOut, transform); } return count; } @@ -83,18 +90,26 @@ async function writeSkillFile( pluginName: string, absPath: string, skillsSrc: string, - pluginOut: string + pluginOut: string, + transform?: SkillContentTransform ): Promise { const relPath = relative(skillsSrc, absPath).replace(/\\/g, "/"); const destPath = join(pluginOut, "skills", relPath); const content = await fs.readFile(absPath); - if (absPath.endsWith(".md")) { - assertNoToolsPlaceholder(content, pluginName, relPath); - const currentFilePluginRelative = `skills/${relPath}`; - await fs.writeFile(destPath, rewriteRelativeLinks(content, { currentFilePluginRelative })); - } else { + if (!absPath.endsWith(".md")) { await fs.writeFile(destPath, content); + return 1; } + + assertNoToolsPlaceholder(content, pluginName, relPath); + const rewritten = rewriteRelativeLinks(content, { + currentFilePluginRelative: `skills/${relPath}`, + }); + let output = rewritten; + if (transform && basename(absPath) === PLUGIN_SKILL_ENTRY_FILE) { + output = transform(rewritten, pluginName, PLUGIN_SKILL_ENTRY_FILE); + } + await fs.writeFile(destPath, output); return 1; } diff --git a/cli/src/application/use-cases/framework/strategies/tool-contracts.ts b/cli/src/application/use-cases/framework/strategies/tool-contracts.ts index 3f1f09e8..dfbc49dd 100644 --- a/cli/src/application/use-cases/framework/strategies/tool-contracts.ts +++ b/cli/src/application/use-cases/framework/strategies/tool-contracts.ts @@ -57,7 +57,10 @@ import { } from "../../../../domain/models/framework-build.js"; import type { FileReader } from "../../../../domain/ports/file-reader.js"; import type { FileWriter } from "../../../../domain/ports/file-writer.js"; -import { mergeCodexConfigToml } from "../../../../domain/tools/ai/codex.js"; +import { + mergeCodexConfigToml, + stripCodexSkillFrontmatter, +} from "../../../../domain/tools/ai/codex.js"; import { transformMcpToOpencode } from "../../../../domain/tools/ai/opencode.js"; import type { PluginPresence, ToolBuildContract } from "../../../../domain/tools/build-contract.js"; import { @@ -331,6 +334,11 @@ function buildCodexManifest( return manifest; } +function transformCodexSkill(content: string): string { + const { frontmatter, body } = parseFrontmatter(content); + return serializeFrontmatter(stripCodexSkillFrontmatter(frontmatter), body); +} + export function buildCodexContract(): ToolBuildContract { const manifestRelative = OUTPUT_CODEX_MANIFEST_RELATIVE; const marketplaceRelative = OUTPUT_CODEX_MARKETPLACE_RELATIVE; @@ -348,6 +356,7 @@ export function buildCodexContract(): ToolBuildContract { supported: true, source: { kind: "fullTree", srcDir: "skills" }, path: (_p, rel) => rel, + transform: transformCodexSkill, }, agents: { supported: true, diff --git a/cli/src/domain/models/framework-build.ts b/cli/src/domain/models/framework-build.ts index c1d527bc..0d06ab2b 100644 --- a/cli/src/domain/models/framework-build.ts +++ b/cli/src/domain/models/framework-build.ts @@ -70,6 +70,7 @@ export const OUTPUT_MARKETPLACE_RELATIVE = ".plugin/marketplace.json"; export const PLUGIN_HOOKS_RELATIVE = "hooks/hooks.json"; export const PLUGIN_MCP_RELATIVE = ".mcp.json"; export const PLUGIN_AGENT_INPUT_EXT = ".md"; +export const PLUGIN_SKILL_ENTRY_FILE = "SKILL.md"; /** Subdirectory names that are out-of-scope for MVP1 and receive a warn+skip. */ export const OUT_OF_SCOPE_PLUGIN_SECTIONS: readonly ["commands", "rules"] = ["commands", "rules"]; diff --git a/cli/src/domain/tools/ai/codex.ts b/cli/src/domain/tools/ai/codex.ts index 0af158e6..55eff261 100644 --- a/cli/src/domain/tools/ai/codex.ts +++ b/cli/src/domain/tools/ai/codex.ts @@ -173,7 +173,7 @@ function buildCodexSkillFilePath(fileName: string): string { return `${AGENTS_SKILLS_PREFIX}aidd-${skillNameFromPath(fileName)}/SKILL.md`; } -function stripCodexSkillFrontmatter(fm: Record): Record { +export function stripCodexSkillFrontmatter(fm: Record): Record { const result: Record = {}; if (fm.name !== undefined) result.name = fm.name; if (fm.description !== undefined) result.description = fm.description; diff --git a/cli/tests/application/use-cases/framework/marketplace-build-strategy.codex.integration.test.ts b/cli/tests/application/use-cases/framework/marketplace-build-strategy.codex.integration.test.ts index c6dd6f01..bca0989a 100644 --- a/cli/tests/application/use-cases/framework/marketplace-build-strategy.codex.integration.test.ts +++ b/cli/tests/application/use-cases/framework/marketplace-build-strategy.codex.integration.test.ts @@ -9,6 +9,7 @@ import { InvalidBuildPathsError, JsonSchemaValidationError, } from "../../../../src/domain/errors.js"; +import { parseFrontmatter } from "../../../../src/domain/formats/markdown.js"; import { parseToml } from "../../../../src/domain/formats/toml.js"; import type { AssetProvider } from "../../../../src/domain/ports/asset-provider.js"; import { AjvSchemaValidatorAdapter } from "../../../../src/infrastructure/adapters/ajv-schema-validator-adapter.js"; @@ -223,6 +224,44 @@ describe("CodexOutputStrategy", () => { }); describe("skill rewrite (AC #6)", () => { + it("uses the skill frontmatter allowlist without changing the source", async () => { + const fs = await makeSeededFsFromCodex(); + const sourcePath = `${CODEX_FIXTURE_DIR}/plugins/aidd-codex-fixture/skills/sample/SKILL.md`; + const sourceBefore = await fs.readFile(sourcePath); + const uc = makeUseCase(fs); + + await uc.execute({ sourceDir: CODEX_FIXTURE_DIR, outDir: OUT_DIR, target: "codex" }); + + const output = + fs.getFile(`${OUT_DIR}/plugins/aidd-codex-fixture/skills/sample/SKILL.md`) ?? ""; + expect(parseFrontmatter(output).frontmatter).toEqual({ + name: "sample", + description: "Sample skill for testing reference rewriting.", + allowed_tools: ["Read"], + }); + expect(output).not.toMatch(/^model:/m); + expect(await fs.readFile(sourcePath)).toBe(sourceBefore); + }); + + it("preserves auxiliary Markdown frontmatter", async () => { + const fs = await makeSeededFsFromCodex(); + const sourcePath = `${CODEX_FIXTURE_DIR}/plugins/aidd-codex-fixture/skills/sample/assets/template.md`; + const source = await fs.readFile(sourcePath); + const uc = makeUseCase(fs); + + await uc.execute({ sourceDir: CODEX_FIXTURE_DIR, outDir: OUT_DIR, target: "codex" }); + + const output = fs.getFile( + `${OUT_DIR}/plugins/aidd-codex-fixture/skills/sample/assets/template.md` + ); + expect(output).toBe(source); + expect(parseFrontmatter(output ?? "").frontmatter).toEqual({ + name: "template", + model: "opus", + custom: "keep-this", + }); + }); + it("rewrites @./ references in skill SKILL.md to markdown links", async () => { const fs = await makeSeededFsFromCodex(); const uc = makeUseCase(fs); diff --git a/cli/tests/fixtures/framework-codex/plugins/aidd-codex-fixture/skills/sample/SKILL.md b/cli/tests/fixtures/framework-codex/plugins/aidd-codex-fixture/skills/sample/SKILL.md index f6b3520c..2de72055 100644 --- a/cli/tests/fixtures/framework-codex/plugins/aidd-codex-fixture/skills/sample/SKILL.md +++ b/cli/tests/fixtures/framework-codex/plugins/aidd-codex-fixture/skills/sample/SKILL.md @@ -1,6 +1,10 @@ --- name: sample description: Sample skill for testing reference rewriting. +allowed_tools: + - Read +model: opus +unsupported: discard-me --- # Sample Skill diff --git a/cli/tests/fixtures/framework-codex/plugins/aidd-codex-fixture/skills/sample/assets/template.md b/cli/tests/fixtures/framework-codex/plugins/aidd-codex-fixture/skills/sample/assets/template.md new file mode 100644 index 00000000..38356c67 --- /dev/null +++ b/cli/tests/fixtures/framework-codex/plugins/aidd-codex-fixture/skills/sample/assets/template.md @@ -0,0 +1,7 @@ +--- +name: template +model: opus +custom: keep-this +--- + +# Asset template From dfcb68cd64ea4b4a38c160560211f718c564b31f Mon Sep 17 00:00:00 2001 From: Baptiste LAFOURCADE <119650761+blafourcade@users.noreply.github.com> Date: Fri, 14 Aug 2026 12:41:36 +0200 Subject: [PATCH 13/14] refactor(aidd-context): project memory shows what it would change before writing (#633) * refactor(aidd-context): split project memory into write, check, and sync 02-project-memory conflated writing the bank with judging it: one action wrote a file then decided whether it was good, which is why a duplicated fact could survive and a user's hand-written gotcha could be deleted as a "safe" fix. - 02-generate splits into 02-write (writes, stops) and 03-check (judges, changes nothing on its own), and 03-sync becomes 04-sync. - check reports to aidd_docs/tasks//_memory-check/, printing a summary and writing the tables, so a 30-finding run stays readable at any terminal width. - refresh gains a real behaviour: the scan shows only the delta, derived from reading memory-destinations.md backwards. - ecosystem memory lands: an always-on capability whose file is one mermaid graph of the external tools, who reaches them and how. - Ticketing leaves core/vcs.md; version control owns branches, commits and the platform, not the tracker. - capability signals stop being npm-shaped: package, realtime, desktop and ui now detect outside JavaScript. - update_memory.js anchors on CLAUDE_PROJECT_DIR, so a run started elsewhere no longer exits 0 having done nothing. The eval harness grows what these fixes needed to be provable: per-case plugin, --model (sonnet by default), --jobs, --repeat to measure a flaky skill, --case to select one without editing cases.json, filesUnchanged to assert a read-only action, and fileMatches to assert a whole file's shape. * refactor(aidd-context): give project memory a reading list and a readable report The skill knew how to prove a capability but never what to read to understand the project. `01-scan` said "look for something to remember", a presence test, so the bank's quality rested on whatever the model happened to open. - references/reading-sources.md: what to read, cheapest first, and a keep-or-drop table so reading widely still writes little. - assets/scan-summary.md: the table the user confirms before anything is written, filled with placeholders rather than a schema. - check runs the scan first, so a capability that holds with no file is finally visible; it ends by offering the write instead of a silence. - The report splits what the tables prove, which holds every run, from what the reviewers saw, which does not. It lands in the dated task folder and prints a summary no terminal reflows. - The ecosystem graph drops `click`: a .md href downloads the file and GitHub strips the directive. The owning file now follows the tool name after a middle dot. An edge earns its place by informing, so a plain `Human -- web -->` goes and `human only` is stated. - Detection stops saying "third-party": a bot the platform itself runs holds state outside the repo just the same. - Scaffolded docs join memory-destinations.md, so one table holds every path; structure.md keeps the shape and who owns which part. - Actions drop 13 sub-items that restated a transversal rule or a report rule, and test cases go from six words to two. Known defect, measured not guessed: a hand-written line in an existing memory file survives a refresh 1 run in 2, against 3 in 3 before this change. reading-sources.md's keep-or-drop table competes with the rule that keeps user content; scoping it to the reading helped without closing the gap. Do not run refresh on a bank holding notes worth keeping until this is fixed. * refactor(aidd-context): refresh shows what it would change before writing A memory file records no authorship, so "keep every line the user wrote" asked the model to tell its own output from a human's. It could not, and a hand-written note survived a refresh about one run in two. The fix is structural, not a better sentence. `refresh` now runs scan, then check, then write: check reports what drifted and changes nothing, the user picks, and write applies that list and nothing else. Provenance stops mattering because nothing is rewritten unasked. - `check` merges into `refresh`; the verbs become setup, refresh, rewire. `setup` still writes freely: with no bank there is nothing to lose, and the scan already confirmed what it understood before writing. - The transversal rule drops the unenforceable claim. An existing bank changes only through what the user approved. - `01-scan` stops reading `memory-destinations.md` backwards. That was check's job all along, and reordering the flow made the duplicate visible. - `ecosystem` loses the escape hatch that let it produce no file. It is an always row like the core ones, and a repo always has a platform. - A tool nobody drives keeps its node through its hand-off. Dropping the noisy `Human -- web -->` edges had silently removed release bots and scanners, which act on their own and are worth recording for it. Measured twice per case on the final shape: setup, check, rewire and the empty repo pass 2/2, refresh 3/4. Two known flakes left, each seen once: the report header goes missing, and a delta file lands without naming its evidence. Neither is patched, since one sample does not justify a rewrite. --- docs/CATALOG.md | 2 +- plugins/aidd-context/CATALOG.md | 14 +- plugins/aidd-context/hooks/update_memory.js | 6 + .../skills/02-project-memory/SKILL.md | 21 +- .../02-project-memory/actions/01-scan.md | 21 +- .../02-project-memory/actions/02-generate.md | 35 --- .../02-project-memory/actions/02-write.md | 30 ++ .../02-project-memory/actions/03-check.md | 38 +++ .../02-project-memory/actions/03-sync.md | 35 --- .../02-project-memory/actions/04-sync.md | 34 +++ .../skills/02-project-memory/assets/report.md | 59 +++- .../02-project-memory/assets/scan-summary.md | 23 ++ .../assets/{ => templates}/AGENTS.md | 0 .../assets/{ => templates}/CONTRIBUTING.md | 2 +- .../assets/{ => templates}/GUIDELINES.md | 0 .../assets/{ => templates}/README.md | 0 .../templates/memory/api/integration.md | 16 +- .../assets/templates/memory/core/vcs.md | 1 - .../templates/memory/ecosystem/ecosystem.md | 32 ++ .../references/capability-signals.md | 15 +- .../references/ecosystem-signals.md | 47 +++ .../references/memory-destinations.md | 59 ++-- .../references/memory-rules.md | 2 + .../references/reading-sources.md | 45 +++ .../references/review-protocol.md | 7 +- .../02-project-memory/references/structure.md | 17 +- .../02-project-memory/references/tools.md | 3 + .../assets/recipes/token-optimization.md | 4 +- scripts/skill-eval.mjs | 116 +++++-- scripts/skill-eval/cases.json | 283 +++++++++++++++++- 30 files changed, 772 insertions(+), 195 deletions(-) delete mode 100644 plugins/aidd-context/skills/02-project-memory/actions/02-generate.md create mode 100644 plugins/aidd-context/skills/02-project-memory/actions/02-write.md create mode 100644 plugins/aidd-context/skills/02-project-memory/actions/03-check.md delete mode 100644 plugins/aidd-context/skills/02-project-memory/actions/03-sync.md create mode 100644 plugins/aidd-context/skills/02-project-memory/actions/04-sync.md create mode 100644 plugins/aidd-context/skills/02-project-memory/assets/scan-summary.md rename plugins/aidd-context/skills/02-project-memory/assets/{ => templates}/AGENTS.md (100%) rename plugins/aidd-context/skills/02-project-memory/assets/{ => templates}/CONTRIBUTING.md (78%) rename plugins/aidd-context/skills/02-project-memory/assets/{ => templates}/GUIDELINES.md (100%) rename plugins/aidd-context/skills/02-project-memory/assets/{ => templates}/README.md (100%) create mode 100644 plugins/aidd-context/skills/02-project-memory/assets/templates/memory/ecosystem/ecosystem.md create mode 100644 plugins/aidd-context/skills/02-project-memory/references/ecosystem-signals.md create mode 100644 plugins/aidd-context/skills/02-project-memory/references/reading-sources.md diff --git a/docs/CATALOG.md b/docs/CATALOG.md index b2abe30d..d08bf469 100644 --- a/docs/CATALOG.md +++ b/docs/CATALOG.md @@ -20,7 +20,7 @@ Bootstrap, project init, context-artifact generation, diagrams, learning, and ex | ---------------------- | ----------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- | | `00-onboard` | Guide the project's journey through AIDD, from first setup to shipping a feature | `01-scan`, `02-assess`, `03-present`, `04-run` | | `01-bootstrap` | Imagine and validate a new SaaS architecture, output an `INSTALL.md` | `01-gather-needs`, `02-propose-candidates`, `03-audit-candidates`, `04-pick-and-design`, `05-write-install-md` | -| `02-project-memory` | Give the AI a memory of the project, wired into the tools you use | `01-scan`, `02-generate`, `03-sync` | +| `02-project-memory` | Give the AI a memory of the project, wired into the tools you use | `01-scan`, `02-write`, `03-check`, `04-sync` | | `03-context-generate` | Router that dispatches an artifact-generation request to the dedicated generator below | delegates to `04`–`08` (and plugins / marketplaces) | | `04-skill-generate` | Generate a router-based skill across the host AI tool(s) | `01-scope`, `02-plan`, `03-write`, `04-validate` | | `05-rule-generate` | Generate a coding rule that governs editor and agent behavior | `01-capture-rule`, `02-write-rule`, `03-validate` | diff --git a/plugins/aidd-context/CATALOG.md b/plugins/aidd-context/CATALOG.md index 8e17421e..d549a084 100644 --- a/plugins/aidd-context/CATALOG.md +++ b/plugins/aidd-context/CATALOG.md @@ -72,20 +72,20 @@ Auto-generated index of skills, agents, references and assets shipped by the `ai | Group | File | Description | |-------|------|---| | `actions` | [01-scan.md](skills/02-project-memory/actions/01-scan.md) | - | -| `actions` | [02-generate.md](skills/02-project-memory/actions/02-generate.md) | - | -| `actions` | [03-sync.md](skills/02-project-memory/actions/03-sync.md) | - | -| `assets` | [AGENTS.md](skills/02-project-memory/assets/AGENTS.md) | - | -| `assets` | [CONTRIBUTING.md](skills/02-project-memory/assets/CONTRIBUTING.md) | - | -| `assets` | [GUIDELINES.md](skills/02-project-memory/assets/GUIDELINES.md) | - | -| `assets` | [README.md](skills/02-project-memory/assets/README.md) | - | +| `actions` | [02-write.md](skills/02-project-memory/actions/02-write.md) | - | +| `actions` | [03-check.md](skills/02-project-memory/actions/03-check.md) | - | +| `actions` | [04-sync.md](skills/02-project-memory/actions/04-sync.md) | - | | `assets` | [report.md](skills/02-project-memory/assets/report.md) | - | +| `assets` | [scan-summary.md](skills/02-project-memory/assets/scan-summary.md) | - | | `references` | [capability-signals.md](skills/02-project-memory/references/capability-signals.md) | - | +| `references` | [ecosystem-signals.md](skills/02-project-memory/references/ecosystem-signals.md) | - | | `references` | [memory-destinations.md](skills/02-project-memory/references/memory-destinations.md) | - | | `references` | [memory-rules.md](skills/02-project-memory/references/memory-rules.md) | - | +| `references` | [reading-sources.md](skills/02-project-memory/references/reading-sources.md) | - | | `references` | [review-protocol.md](skills/02-project-memory/references/review-protocol.md) | - | | `references` | [structure.md](skills/02-project-memory/references/structure.md) | - | | `references` | [tools.md](skills/02-project-memory/references/tools.md) | - | -| `-` | [SKILL.md](skills/02-project-memory/SKILL.md) | `Build the project's memory of its architecture, conventions, and decisions, and wire it into the tools you use. Use when the user wants to set up or refresh project memory. Not for editing one existing memory file.` | +| `-` | [SKILL.md](skills/02-project-memory/SKILL.md) | `Build the project's memory of its architecture, conventions, and decisions, and wire it into your AI tools. Use when the user wants to set up or refresh project memory, or rewire it into a tool. Not for editing one existing memory file.` | #### `skills/03-context-generate` diff --git a/plugins/aidd-context/hooks/update_memory.js b/plugins/aidd-context/hooks/update_memory.js index f6db0c9e..495b4ea7 100644 --- a/plugins/aidd-context/hooks/update_memory.js +++ b/plugins/aidd-context/hooks/update_memory.js @@ -190,6 +190,12 @@ function gitAdd(childProcess, files) { const path = await import("node:path"); const childProcess = await import("node:child_process"); + // Every path below is project-relative, so anchor on the project root when + // Claude Code names it. Without this a run started elsewhere finds no bank + // and exits 0, which reads as success. + const root = process.env.CLAUDE_PROJECT_DIR; + if (root && fs.existsSync(root)) process.chdir(root); + if (!fs.existsSync(DOCS_DIR)) process.exit(0); const tools = process.argv.slice(2).map((arg) => arg.toLowerCase()); diff --git a/plugins/aidd-context/skills/02-project-memory/SKILL.md b/plugins/aidd-context/skills/02-project-memory/SKILL.md index 633beb60..e854cb94 100644 --- a/plugins/aidd-context/skills/02-project-memory/SKILL.md +++ b/plugins/aidd-context/skills/02-project-memory/SKILL.md @@ -1,6 +1,6 @@ --- name: 02-project-memory -description: Build the project's memory of its architecture, conventions, and decisions, and wire it into the tools you use. Use when the user wants to set up or refresh project memory. Not for editing one existing memory file. +description: Build the project's memory of its architecture, conventions, and decisions, and wire it into your AI tools. Use when the user wants to set up or refresh project memory, or rewire it into a tool. Not for editing one existing memory file. argument-hint: setup | refresh | rewire --- @@ -8,23 +8,26 @@ argument-hint: setup | refresh | rewire ```mermaid flowchart LR - build([no argument, setup, or refresh]) --> scan --> generate --> sync + new([no argument, or setup]) --> scan --> write --> sync --> wired([memory wired]) + update([refresh]) --> scan --> check --> write rewire([rewire]) --> sync + scan -.-> empty([nothing to remember]) ``` ## Actions -Run the flow above. Read only the next action file. +Run the flow above, reading only the next action file. -| Action | Does | -| -------- | -------------------------- | -| scan | read the project | -| generate | write the memory | -| sync | pick the tools, wire it in | +| Action | Does | +| ------ | ------------------------------- | +| scan | read the project | +| write | write the memory | +| check | show what drifted, change nothing | +| sync | pick the tools, wire it in | ## Transversal rules - If a referenced file cannot be read, stop and say so. Never invent its content. - Ask before anything ambiguous. Never default silently. -- Create or revise a file, keeping the user's edits. Delete one only when the user asks. +- A bank that already exists changes only through what the user approved, file by file and line by line. - End with a short report of what changed. diff --git a/plugins/aidd-context/skills/02-project-memory/actions/01-scan.md b/plugins/aidd-context/skills/02-project-memory/actions/01-scan.md index 1cf311f2..d40e4533 100644 --- a/plugins/aidd-context/skills/02-project-memory/actions/01-scan.md +++ b/plugins/aidd-context/skills/02-project-memory/actions/01-scan.md @@ -8,20 +8,23 @@ The project root. ## Output -The confirmed capabilities, printed nowhere. +The confirmed capabilities and external tools, printed nowhere. ## Process -1. **Ground.** Look for something to remember: source code, or anything written about what the project is. - - Nothing there: stop, say so, send the user to create something first. -2. **Find.** Detect the project's capabilities per [capability-signals.md](../references/capability-signals.md), each with its repo evidence. -3. **Ask.** Show each capability with its evidence. Ask the user to add or drop one. Wait for the answer. -4. **Confirm.** Keep the confirmed set in context for generate. +1. **Ground.** Read the project against [reading-sources.md](../references/reading-sources.md), and stop when it holds nothing to read. +2. **Find.** Detect the capabilities per [capability-signals.md](../references/capability-signals.md), each with its evidence. +3. **Map.** Detect the external tools per [ecosystem-signals.md](../references/ecosystem-signals.md), which fill the always-on `ecosystem` capability. +4. **Ask.** Show the scan as [scan-summary.md](../assets/scan-summary.md) does, ask for what the repo cannot prove, and wait. +5. **Confirm.** Keep what the scan found, plus the user's additions, minus their drops. ## Test | Case | Pass | | --- | --- | -| The action completes | `git status --porcelain` reads the same after as before | -| A capability is confirmed | a file or dependency for it exists in the repo | -| The repo holds no code and nothing describing it | the run stops at Ground and hands nothing to generate | +| Completion | no file under the project changed | +| Evidence | the path or dependency named for a capability exists | +| Summary | one row per capability and per tool, each carrying evidence | +| Tool | one access mode per actor that reaches it | +| Every run | the same capabilities for the same repo, bank or no bank | +| Empty repo | the run stops at Ground and hands nothing on | diff --git a/plugins/aidd-context/skills/02-project-memory/actions/02-generate.md b/plugins/aidd-context/skills/02-project-memory/actions/02-generate.md deleted file mode 100644 index bd6d2b60..00000000 --- a/plugins/aidd-context/skills/02-project-memory/actions/02-generate.md +++ /dev/null @@ -1,35 +0,0 @@ -# 02 - Generate - -Write the memory the project deserves. - -## Input - -The confirmed capabilities from `01-scan`. - -## Output - -The written memory bank, and a report of what changed. - -## Process - -1. **Scaffold.** Create the tree in [structure.md](../references/structure.md). -2. **Select.** Take the rows to write from [memory-destinations.md](../references/memory-destinations.md). -3. **Write.** Write each selected row to its destination, against [memory-rules.md](../references/memory-rules.md). - - The destination is the one the table names. Never derive a path. - - Absent file: fill the template, strip its guidance comment. - - Existing file: revise it in place. - - Report a template section the file now lacks when the project has something for it. Never inject it. -4. **Prune.** A file on disk whose capability is no longer selected: flag it, offer to remove it, delete only on the user's word. -5. **Review.** Have each memory file reviewed against [review-protocol.md](../references/review-protocol.md) by an independent agent, a checker agent if the project has one, in parallel. Without subagents, make one fresh pass per file yourself, and say so in the report. -6. **Fix.** Apply the safe findings. On a duplicated fact, keep its home and drop the copy. -7. **Report.** Fill [report.md](../assets/report.md). - -## Test - -| Case | Pass | -| --- | --- | -| The bank is written | `find aidd_docs/memory -mindepth 2 -name '*.md'` returns nothing outside `internal/` and `external/` | -| A destination is checked | every `core` path and every [structure.md](../references/structure.md) path exists at its exact place | -| The scaffold is checked | `internal/` and `external/` each hold a `.gitkeep` and no memory file | -| A written file is read back | no `TODO` and no `` remains | -| The action runs again on a bank the user edited | the user's line survives and a flagged missing section stays absent | diff --git a/plugins/aidd-context/skills/02-project-memory/actions/02-write.md b/plugins/aidd-context/skills/02-project-memory/actions/02-write.md new file mode 100644 index 00000000..92a44120 --- /dev/null +++ b/plugins/aidd-context/skills/02-project-memory/actions/02-write.md @@ -0,0 +1,30 @@ +# 02 - Write + +Write the memory the project deserves. + +## Input + +The confirmed capabilities, external tools, access modes and hand-offs, plus the findings the user approved when a bank already exists. + +## Output + +The written memory bank. + +## Process + +1. **Scaffold.** Create the tree in [structure.md](../references/structure.md). +2. **Select.** Take the rows to write from [memory-destinations.md](../references/memory-destinations.md). +3. **Write.** Write each row to its destination against [memory-rules.md](../references/memory-rules.md). + - Absent file: fill the template, strip its guidance comment. + - Existing file: apply the approved findings and nothing else. + - A section the file lacks: report it when the project has something for it, never inject it. + +## Test + +| Case | Pass | +| --- | --- | +| Bank written | every selected row exists at its exact path | +| Tree | no `.md` under `memory/` outside `internal/` and `external/`, each holding a `.gitkeep` | +| Memory file | no `TODO` and no `` remains | +| Scaffolded doc | its placeholders are untouched | +| Rerun | only the approved findings changed, every other line survives | diff --git a/plugins/aidd-context/skills/02-project-memory/actions/03-check.md b/plugins/aidd-context/skills/02-project-memory/actions/03-check.md new file mode 100644 index 00000000..0a81ecf8 --- /dev/null +++ b/plugins/aidd-context/skills/02-project-memory/actions/03-check.md @@ -0,0 +1,38 @@ +# 03 - Check + +Show what drifted in the bank, and let the user pick what to fix. Change nothing. + +## Input + +The bank in `aidd_docs/memory/`, and the capabilities the scan found. + +## Output + +A report file under `aidd_docs/tasks/`, a short summary printed, and the findings the user approved. + +## Process + +1. **Match.** Compare the bank against [memory-destinations.md](../references/memory-destinations.md) and [structure.md](../references/structure.md). + - A file no row produces: flag it, and name the row it should have come from. + - A found capability, or a scaffolded path, with nothing on disk: flag it missing. +2. **Review.** Have each memory file reviewed against [review-protocol.md](../references/review-protocol.md) in parallel. +3. **Prune.** Offer to remove each file whose capability the scan did not find, and none when the scan asked nothing. +4. **Report.** Fill [report.md](../assets/report.md), write it to `aidd_docs/tasks//_memory-check/report.md`, and print the summary with that path. + - The folder already holds a report: ask before replacing it. +5. **Offer.** Ask which findings to apply, and hand the approved ones to write. + - Nothing drifted: call the bank current, hand nothing on. + +## Test + +| Case | Pass | +| --- | --- | +| Any run | no file under `aidd_docs/memory/` changed | +| Any finding | the summary holds no table, names the report path, ends on the question | +| Nothing drifted | nothing offered, the bank called current | +| Report | structural gaps and reviewer findings under separate headings | +| Report | no step of this skill named in it | +| Orphan | flagged, with the row it should have come from | +| Missing | a found capability with no file is flagged | +| Contradiction | flagged, the line left in place | +| Duplicate | flagged, both files left as they are | +| Removal declined | the file is still there | diff --git a/plugins/aidd-context/skills/02-project-memory/actions/03-sync.md b/plugins/aidd-context/skills/02-project-memory/actions/03-sync.md deleted file mode 100644 index 0ea79a69..00000000 --- a/plugins/aidd-context/skills/02-project-memory/actions/03-sync.md +++ /dev/null @@ -1,35 +0,0 @@ -# 03 - Sync - -Wire the memory into the tools the user picks. - -## Input - -The memory bank in `aidd_docs/memory/`. - -## Output - -Each picked tool's context file, carrying the filled block. - -## Process - -1. **Require.** Stop unless `aidd_docs/memory/` holds a `.md` file. Send the user to generate first. -2. **Detect.** Find the AI tools present per [tools.md](../references/tools.md). -3. **Pick.** Show every tool, the detected ones ticked. Let the user pick one or several. Wait for the pick. -4. **Upsert.** Ensure each picked tool's context file carries the block, shaped like [AGENTS.md](../assets/AGENTS.md). - - Absent file: create it from that template. - - Existing file: add only the missing `## Memory Management` section or block, leaving the rest untouched. - - If its AIDD structure differs from [AGENTS.md](../assets/AGENTS.md), offer to reconcile it, applying only what the user approves. - - Touch no file a picked tool does not resolve to. -5. **Fill.** Run `hooks/update_memory.js` from the project root, naming the picked tools. -6. **Guard.** On a non-zero script exit, show the error and stop. -7. **Verify.** Read each picked tool's block back. An empty one means the fill did not land. - -## Test - -| Case | Pass | -| --- | --- | -| `aidd_docs/memory/` holds no `.md` | sync creates no context file and stops | -| The script runs | it exits `0` | -| A tool was picked | its context file exists, its block listing every file in `aidd_docs/memory/` | -| A tool was not picked | its context file is unchanged | -| The action completes | `git diff --cached` is empty | diff --git a/plugins/aidd-context/skills/02-project-memory/actions/04-sync.md b/plugins/aidd-context/skills/02-project-memory/actions/04-sync.md new file mode 100644 index 00000000..e96e752a --- /dev/null +++ b/plugins/aidd-context/skills/02-project-memory/actions/04-sync.md @@ -0,0 +1,34 @@ +# 04 - Sync + +Wire the memory into the tools the user picks. + +## Input + +The memory bank in `aidd_docs/memory/`. + +## Output + +Each picked tool's context file, carrying the filled block. + +## Process + +1. **Require.** Stop unless `aidd_docs/memory/` holds a `.md`, sending the user to write the memory first. +2. **Detect.** Find the AI tools present per [tools.md](../references/tools.md). +3. **Pick.** Show every tool, the detected ones ticked, and wait for one or several. +4. **Upsert.** Ensure each picked tool's context file carries the block, per [tools.md](../references/tools.md). + - Absent file: create it from [AGENTS.md](../assets/templates/AGENTS.md). + - Its AIDD structure differs: offer to reconcile it, applying only what the user approves. +5. **Fill.** Run `hooks/update_memory.js` from the project root, naming the picked tools, and stop on a non-zero exit. + - No script, the skill shipped alone: write each block from the bank. +6. **Verify.** Read each picked tool's block back and compare it to the bank. + - A file in one and not the other: the fill did not land, report it and stop. + +## Test + +| Case | Pass | +| --- | --- | +| Empty bank | no context file created, the run stops | +| Script | it exits `0` | +| Picked tool | its block lists every root `.md` except `README.md`, nothing else | +| Bank grew | the block gains that file and keeps the rest | +| Unpicked tool | its context file is unchanged | diff --git a/plugins/aidd-context/skills/02-project-memory/assets/report.md b/plugins/aidd-context/skills/02-project-memory/assets/report.md index 41a41b5d..4d5225e0 100644 --- a/plugins/aidd-context/skills/02-project-memory/assets/report.md +++ b/plugins/aidd-context/skills/02-project-memory/assets/report.md @@ -1,13 +1,56 @@ - + -```txt -Memory bank — files under aidd_docs/memory/ +## Printed once, at any terminal width - new | revised - ... +```txt +Memory bank — on disk, gaps, findings -Flagged - + .md missing + .md orphan + .md + .md -Review — independent reviewers | ran without subagents, one fresh pass + aidd_docs/tasks//_memory-check/report.md ``` + +No table, and one file per line. A terminal is narrow: a table reflows into unreadable blocks, and +so does a line that lists several files. Keep every line under forty characters, the path aside. + +## Written to that path + +### Structure + +What the tables prove. Same answer every run. + +| File | Gap | Why | +| ----------- | ------- | ------------------------------------- | +| `.md` | missing | the capability always holds | +| `.md` | missing | `structure.md` scaffolds it | +| `.md` | orphan | no destination row produces it | + +### Findings + +What the reviewers saw this run. Another run may see more. + +| File | Finding | Evidence | +| ----------- | -------------------------------- | ----------------------------------- | +| `.md` | `` | `` | +| `.md` | names a path that does not exist | `` | + +### Duplicated facts + +| Fact | Home | Copy | +| --------- | ----------- | ----------- | +| `` | `.md` | `.md` | + +### Notes + +- `.md` — `` + +Notes hold what this run could not settle about the bank, and nothing else. Name a file, a +capability, a fact about the project. Never how this skill works, never one of its steps: the reader +wants their bank, not its machinery. + +- One row per file, per finding, per duplicated fact. Never a paragraph in a cell. +- A finding is a fragment; its evidence is the fact that settles it. +- Drop a table, a column, or a section that has nothing to say. diff --git a/plugins/aidd-context/skills/02-project-memory/assets/scan-summary.md b/plugins/aidd-context/skills/02-project-memory/assets/scan-summary.md new file mode 100644 index 00000000..669583a3 --- /dev/null +++ b/plugins/aidd-context/skills/02-project-memory/assets/scan-summary.md @@ -0,0 +1,23 @@ + + +Here is what I read. Correct me before I write. + +| Capability | Holds because | +| -------------- | ---------------------------------------------- | +| core | always | +| ecosystem | always | +| `` | `` | +| `` | `` | + +| Tool | Human | Agent | Owned by | +| ---------------- | -------- | -------- | ------------- | +| `` | `` | `` | `.md` | +| `` | `` | `` | `.md` | +| `` | `` | none | none | + +Then ask for what the repo cannot prove: a tool nobody committed, an access mode, a hand-off between +two tools. Name what is missing rather than asking an open question. + +- One row per capability, one row per tool. The evidence is a path or a dependency, never a claim. +- A capability that holds always says so; do not invent evidence for it. +- Drop the second table when the project reaches nothing outside itself. diff --git a/plugins/aidd-context/skills/02-project-memory/assets/AGENTS.md b/plugins/aidd-context/skills/02-project-memory/assets/templates/AGENTS.md similarity index 100% rename from plugins/aidd-context/skills/02-project-memory/assets/AGENTS.md rename to plugins/aidd-context/skills/02-project-memory/assets/templates/AGENTS.md diff --git a/plugins/aidd-context/skills/02-project-memory/assets/CONTRIBUTING.md b/plugins/aidd-context/skills/02-project-memory/assets/templates/CONTRIBUTING.md similarity index 78% rename from plugins/aidd-context/skills/02-project-memory/assets/CONTRIBUTING.md rename to plugins/aidd-context/skills/02-project-memory/assets/templates/CONTRIBUTING.md index 9c1848aa..0a44d577 100644 --- a/plugins/aidd-context/skills/02-project-memory/assets/CONTRIBUTING.md +++ b/plugins/aidd-context/skills/02-project-memory/assets/templates/CONTRIBUTING.md @@ -1,6 +1,6 @@ # Contributing to this project's AI context -How to add or change the context the AI relies on here. For authoring AIDD skills, agents, rules, and templates, see the framework guide: . +How to add or change the context the AI relies on here. Fill the placeholders below, drop what does not apply. For authoring AIDD skills, agents, rules, and templates, see the framework guide: . ## Changing project memory diff --git a/plugins/aidd-context/skills/02-project-memory/assets/GUIDELINES.md b/plugins/aidd-context/skills/02-project-memory/assets/templates/GUIDELINES.md similarity index 100% rename from plugins/aidd-context/skills/02-project-memory/assets/GUIDELINES.md rename to plugins/aidd-context/skills/02-project-memory/assets/templates/GUIDELINES.md diff --git a/plugins/aidd-context/skills/02-project-memory/assets/README.md b/plugins/aidd-context/skills/02-project-memory/assets/templates/README.md similarity index 100% rename from plugins/aidd-context/skills/02-project-memory/assets/README.md rename to plugins/aidd-context/skills/02-project-memory/assets/templates/README.md diff --git a/plugins/aidd-context/skills/02-project-memory/assets/templates/memory/api/integration.md b/plugins/aidd-context/skills/02-project-memory/assets/templates/memory/api/integration.md index 5896eee9..63229f53 100644 --- a/plugins/aidd-context/skills/02-project-memory/assets/templates/memory/api/integration.md +++ b/plugins/aidd-context/skills/02-project-memory/assets/templates/memory/api/integration.md @@ -1,17 +1,17 @@ # Integration -How this system integrates with external/third-party services. +How this system integrates with external/third-party services. The map of every tool around the +project, this one included, lives in the ecosystem memory. ## External services -- +- -```mermaid -flowchart LR - A[TODO: macro map of this system and its external services] -``` +## Calling conventions + +- diff --git a/plugins/aidd-context/skills/02-project-memory/assets/templates/memory/core/vcs.md b/plugins/aidd-context/skills/02-project-memory/assets/templates/memory/core/vcs.md index 2140213f..67413f33 100644 --- a/plugins/aidd-context/skills/02-project-memory/assets/templates/memory/core/vcs.md +++ b/plugins/aidd-context/skills/02-project-memory/assets/templates/memory/core/vcs.md @@ -6,7 +6,6 @@ The version-control conventions this project follows: branches, commits, and the - Main branch: `` - Platform: `` -- Ticketing: `` ## Branches diff --git a/plugins/aidd-context/skills/02-project-memory/assets/templates/memory/ecosystem/ecosystem.md b/plugins/aidd-context/skills/02-project-memory/assets/templates/memory/ecosystem/ecosystem.md new file mode 100644 index 00000000..57a002c5 --- /dev/null +++ b/plugins/aidd-context/skills/02-project-memory/assets/templates/memory/ecosystem/ecosystem.md @@ -0,0 +1,32 @@ +# Ecosystem + +```mermaid +flowchart LR + Human([Human]) + Agent([Agent]) + App([App]) + Vcs[" · vcs.md"] + Tracker[" · backlog.md"] + Service[" · integration.md"] + Chat[" · human only"] + Bot[""] + + Agent -- cli --> Vcs + Agent -- mcp --> Tracker + App -- http --> Service + Human -- web --> Chat + + Vcs -- "" --> Tracker + Bot -- "" --> Vcs +``` + + diff --git a/plugins/aidd-context/skills/02-project-memory/references/capability-signals.md b/plugins/aidd-context/skills/02-project-memory/references/capability-signals.md index 9f649f77..47b2d05c 100644 --- a/plugins/aidd-context/skills/02-project-memory/references/capability-signals.md +++ b/plugins/aidd-context/skills/02-project-memory/references/capability-signals.md @@ -2,20 +2,23 @@ A concern scan detects from a concrete fact in the repo, or an equivalent one, never inferred from the domain. +In a monorepo, every workspace is scanned, never the root manifest alone. + | Capability | Means | Detected when | | ------------ | ------------------------------ | ----------------------------------------------------------------------------------------- | -| `core` | always | always | -| `backlog` | organizes planned work | local backlog artifacts, issue templates, or a repo file naming backlog conventions | -| `ui` | renders a user interface | a web frontend framework (not React Native), or a `components/` or `pages/` dir | +| `core` | is a project at all | always | +| `ecosystem` | works through external tools | always | +| `backlog` | organizes planned work | local backlog artifacts, issue templates, a ticketing tool in use, or a repo file naming backlog conventions | +| `ui` | renders a user interface | a web frontend framework (not React Native), or a `components/`, `pages/`, or `views/` dir | | `api` | exposes HTTP or RPC | a server framework, or a `routes/`, `controllers/`, or `api/` dir | | `database` | persists data | an ORM or driver, a `migrations/` dir, or a schema file | | `auth` | authenticates or authorizes | an auth library (passport, next-auth, clerk, auth0, devise), auth middleware, or an auth module | -| `realtime` | pushes live updates | a websocket or SSE library (socket.io, ws, pusher, ably) | +| `realtime` | pushes live updates | a websocket or SSE library (socket.io, ws, pusher, ably, channels, actioncable), or a socket endpoint | | `messaging` | async messages | a queue or broker (kafka, rabbitmq, sqs, bullmq) with producers or consumers | | `deployment` | is built and shipped | a CI config, or a `Dockerfile` | | `infra` | infrastructure as code | Terraform, Pulumi, Kubernetes, or Helm files | | `mobile` | ships a mobile app | an `ios/` or `android/` dir, a `pubspec.yaml`, a `Podfile`, or React Native or Flutter | -| `desktop` | ships a desktop app | Electron or Tauri | -| `package` | ships a reusable library | an importable entry (`main`, `module`, `exports`) that is not the CLI bin, and publishable | +| `desktop` | ships a desktop app | Electron, Tauri, or a native desktop toolkit (Qt, GTK, WPF, AppKit) | +| `package` | ships a reusable library | a publishable manifest declaring an importable entry that is not the CLI bin (`package.json`, `Cargo.toml`, `pyproject.toml`, `go.mod`) | | `cli` | runs as a command-line tool | a `bin` field, or a CLI parser (commander, yargs, oclif, clap, click) | | `data` | processes data or trains models | notebooks, a data-versioning or ML tool, or pipeline and model files | diff --git a/plugins/aidd-context/skills/02-project-memory/references/ecosystem-signals.md b/plugins/aidd-context/skills/02-project-memory/references/ecosystem-signals.md new file mode 100644 index 00000000..4bc0445b --- /dev/null +++ b/plugins/aidd-context/skills/02-project-memory/references/ecosystem-signals.md @@ -0,0 +1,47 @@ +# Ecosystem signals + +What the scan learns about the services the project uses and does not build. The AI hosts it wires +the memory into are `tools.md`, not this. + +## What earns an entry + +- It holds state, or does work, outside the repo past a single CI run. A build step does not. +- One entry per role: a platform that is also the tracker gives two. +- The VCS platform always counts: a repo has one, so the graph is never empty. + +## Actors + +| Actor | Is | +| ------- | ------------------------- | +| `Human` | a person opening the tool | +| `Agent` | an AI assistant driving it | +| `App` | the running code calling it | + +## Access modes + +| Mode | Means | +| ------ | --------------------------------------- | +| `mcp` | an MCP server the agent calls | +| `cli` | a command run in a terminal | +| `http` | a direct API call | +| `web` | a browser interface, nothing programmatic | + +## What earns an edge + +| Edge | Verdict | +| --------------------------------- | ---------------------------------------------------------- | +| `Agent` reaching a tool | keep, what an assistant can drive is never obvious | +| `App` reaching a tool | keep, it names a runtime dependency | +| `Human` reaching a tool by `web` | drop, a person opens anything in a browser | +| `Human` where no agent can follow | keep as `human only` in the label, so absence is not doubt | +| a hand-off with its trigger | keep, the trigger is what makes it a rule | +| a tool nobody drives | keep it for its hand-off alone: acting on its own is the fact | +| a hand-off without one | keep the edge, name the trigger the repo proves | + +## Detected when + +| Fact | Read as | +| -------------------------------------------------------------------- | ------------------------------------------ | +| a service config or a repo integration, whoever runs it, plus a badge | the tool exists | +| a CI config, a webhook, or an integration naming two tools | a hand-off between them | +| the user names it | what the repo cannot prove | diff --git a/plugins/aidd-context/skills/02-project-memory/references/memory-destinations.md b/plugins/aidd-context/skills/02-project-memory/references/memory-destinations.md index 6db2a23b..dbffcffb 100644 --- a/plugins/aidd-context/skills/02-project-memory/references/memory-destinations.md +++ b/plugins/aidd-context/skills/02-project-memory/references/memory-destinations.md @@ -1,29 +1,36 @@ # Memory destinations -Where each template lands: flat under `aidd_docs/memory/`, read from this table, never derived. +Where each template under `assets/templates/` lands. Read from this table, never derived. -| Capability | Template | Write to | -| ---------- | --------------------------- | ---------------------------------------- | -| core | `core/project-brief.md` | `aidd_docs/memory/project-brief.md` | -| core | `core/architecture.md` | `aidd_docs/memory/architecture.md` | -| core | `core/codebase-map.md` | `aidd_docs/memory/codebase-map.md` | -| core | `core/coding-assertions.md` | `aidd_docs/memory/coding-assertions.md` | -| core | `core/testing.md` | `aidd_docs/memory/testing.md` | -| core | `core/vcs.md` | `aidd_docs/memory/vcs.md` | -| backlog | `backlog/backlog.md` | `aidd_docs/memory/backlog.md` | -| api | `api/api.md` | `aidd_docs/memory/api.md` | -| api | `api/integration.md` | `aidd_docs/memory/integration.md` | -| auth | `auth/auth.md` | `aidd_docs/memory/auth.md` | -| cli | `cli/cli.md` | `aidd_docs/memory/cli.md` | -| data | `data/data.md` | `aidd_docs/memory/data.md` | -| database | `database/database.md` | `aidd_docs/memory/database.md` | -| deployment | `deployment/deployment.md` | `aidd_docs/memory/deployment.md` | -| desktop | `desktop/desktop.md` | `aidd_docs/memory/desktop.md` | -| infra | `infra/infra.md` | `aidd_docs/memory/infra.md` | -| messaging | `messaging/messaging.md` | `aidd_docs/memory/messaging.md` | -| mobile | `mobile/mobile.md` | `aidd_docs/memory/mobile.md` | -| package | `package/package.md` | `aidd_docs/memory/package.md` | -| realtime | `realtime/realtime.md` | `aidd_docs/memory/realtime.md` | -| ui | `ui/design.md` | `aidd_docs/memory/design.md` | -| ui | `ui/forms.md` | `aidd_docs/memory/forms.md` | -| ui | `ui/navigation.md` | `aidd_docs/memory/navigation.md` | +Read backwards, it names the capabilities a bank already holds: a file present means its row's capability held when the bank was written. + +| Capability | Template | Write to | +| ---------- | ---------------------------------- | --------------------------------------- | +| core | `README.md` | `aidd_docs/README.md` | +| core | `GUIDELINES.md` | `aidd_docs/GUIDELINES.md` | +| core | `CONTRIBUTING.md` | `aidd_docs/CONTRIBUTING.md` | +| core | `memory/README.md` | `aidd_docs/memory/README.md` | +| core | `memory/core/project-brief.md` | `aidd_docs/memory/project-brief.md` | +| core | `memory/core/architecture.md` | `aidd_docs/memory/architecture.md` | +| core | `memory/core/codebase-map.md` | `aidd_docs/memory/codebase-map.md` | +| core | `memory/core/coding-assertions.md` | `aidd_docs/memory/coding-assertions.md` | +| core | `memory/core/testing.md` | `aidd_docs/memory/testing.md` | +| core | `memory/core/vcs.md` | `aidd_docs/memory/vcs.md` | +| ecosystem | `memory/ecosystem/ecosystem.md` | `aidd_docs/memory/ecosystem.md` | +| backlog | `memory/backlog/backlog.md` | `aidd_docs/memory/backlog.md` | +| api | `memory/api/api.md` | `aidd_docs/memory/api.md` | +| api | `memory/api/integration.md` | `aidd_docs/memory/integration.md` | +| auth | `memory/auth/auth.md` | `aidd_docs/memory/auth.md` | +| cli | `memory/cli/cli.md` | `aidd_docs/memory/cli.md` | +| data | `memory/data/data.md` | `aidd_docs/memory/data.md` | +| database | `memory/database/database.md` | `aidd_docs/memory/database.md` | +| deployment | `memory/deployment/deployment.md` | `aidd_docs/memory/deployment.md` | +| desktop | `memory/desktop/desktop.md` | `aidd_docs/memory/desktop.md` | +| infra | `memory/infra/infra.md` | `aidd_docs/memory/infra.md` | +| messaging | `memory/messaging/messaging.md` | `aidd_docs/memory/messaging.md` | +| mobile | `memory/mobile/mobile.md` | `aidd_docs/memory/mobile.md` | +| package | `memory/package/package.md` | `aidd_docs/memory/package.md` | +| realtime | `memory/realtime/realtime.md` | `aidd_docs/memory/realtime.md` | +| ui | `memory/ui/design.md` | `aidd_docs/memory/design.md` | +| ui | `memory/ui/forms.md` | `aidd_docs/memory/forms.md` | +| ui | `memory/ui/navigation.md` | `aidd_docs/memory/navigation.md` | diff --git a/plugins/aidd-context/skills/02-project-memory/references/memory-rules.md b/plugins/aidd-context/skills/02-project-memory/references/memory-rules.md index 73524d16..fa434fcd 100644 --- a/plugins/aidd-context/skills/02-project-memory/references/memory-rules.md +++ b/plugins/aidd-context/skills/02-project-memory/references/memory-rules.md @@ -6,6 +6,8 @@ A memory file: - Never restates a schema or a file tree. - Points to the code over a copy. - Holds one fact in one home, referenced elsewhere. +- A duplicate keeps its home and loses the copy. - Stays small: short bullets, code in backticks. - Names a tech without its version (`React`, not `React 19`). - Reflects the current state only: no unused section, no placeholder. +- Carries the diagram alone when a diagram is its payload: no note, no caption under it. diff --git a/plugins/aidd-context/skills/02-project-memory/references/reading-sources.md b/plugins/aidd-context/skills/02-project-memory/references/reading-sources.md new file mode 100644 index 00000000..dbc39a76 --- /dev/null +++ b/plugins/aidd-context/skills/02-project-memory/references/reading-sources.md @@ -0,0 +1,45 @@ +# Reading sources + +What the scan reads to understand the project, and what survives the reading. Read widely, keep +little: `memory-rules.md` wants a small file, and most of what a repository shows is re-derivable by +opening it again. + +## Read in this order + +| Source | Answers | +| -------------------------------------------- | -------------------------------------------- | +| the manifest, and a lockfile beside it | the stack, the workspaces, the published name | +| the root README, then any `docs/` | what it does, for whom, its domain words | +| the top-level directories | the shape, and which areas own what | +| the entry points the manifest declares | where execution starts | +| every file under the VCS platform's own directory | how it ships, and what runs on its own schedule | +| the test configuration and one test file | the layers, the tools, the conventions | +| the code, area by area | what the writing above got wrong | + +Stop at the first source that answers a question. Read the code last: it is the most expensive and +the least quotable, and it exists to correct the others, not to be summarised. + +## Keep or drop + +This table judges what the reading yields, never what a memory file already holds. A line the user +wrote stays whatever the verdicts below say. + +| Signal | Verdict | +| ------------------------------------------------------------- | ------- | +| a decision, and the constraint behind it | keep | +| a convention the files repeat without stating | keep | +| a gotcha, a trap, a thing that surprises a newcomer | keep | +| the stack, and how the main parts fit | keep | +| the domain words a contributor must know to read the code | keep | +| a fact one open file re-derives | drop | +| a file tree, a schema, a dependency list | drop | +| a version number | drop | +| anything true of every project built this way | drop | +| a work item, a live value, a technical id | drop | +| a plan, a wish, a thing not shipped | drop | + +## Depth + +- Every workspace of a monorepo, never the root manifest alone. +- A directory whose name repeats across areas is read once, not per area. +- Nothing under a dependency directory, a build output, or a path the VCS ignores. diff --git a/plugins/aidd-context/skills/02-project-memory/references/review-protocol.md b/plugins/aidd-context/skills/02-project-memory/references/review-protocol.md index 261bba90..7d1d5309 100644 --- a/plugins/aidd-context/skills/02-project-memory/references/review-protocol.md +++ b/plugins/aidd-context/skills/02-project-memory/references/review-protocol.md @@ -2,12 +2,15 @@ You review one memory file the AI loads every session. Catch what its writer could not see. +Memory holds what the code cannot show: an intent, a constraint, a warning. Code silent on a line is +not code that contradicts it. + 1. **Read** the file, the code it describes, and the other memory files' names. 2. **Flag** each of these, with a reason and a location: - - A claim the code does not back, or has gone stale. + - A claim the code contradicts, or that has gone stale. - A command, path, or file that does not exist or would not run. - A "why" the code and history do not support. - A decision, convention, or gotcha the code shows but the file omits. - - A fact that belongs under another file's name, for generate to dedup. + - A fact that belongs under another file's name, for check to dedup. - Any remaining breach of `memory-rules.md`. 3. **Return** the flags. Do not edit the file. diff --git a/plugins/aidd-context/skills/02-project-memory/references/structure.md b/plugins/aidd-context/skills/02-project-memory/references/structure.md index 2d06a2d2..ced17dcf 100644 --- a/plugins/aidd-context/skills/02-project-memory/references/structure.md +++ b/plugins/aidd-context/skills/02-project-memory/references/structure.md @@ -1,15 +1,20 @@ # Structure -The tree generate scaffolds. +The tree write scaffolds. Which template fills which file is `memory-destinations.md`; this is the +shape around them, and who owns each part. ```txt aidd_docs/ -├── README.md from assets/README.md -├── GUIDELINES.md from assets/GUIDELINES.md -├── CONTRIBUTING.md from assets/CONTRIBUTING.md +├── README.md copied as is +├── GUIDELINES.md the team fills its placeholders +├── CONTRIBUTING.md the team fills its placeholders └── memory/ - ├── README.md from assets/templates/memory/README.md - ├── .md the memory files, flat (see memory-destinations.md) + ├── README.md copied as is, its file list refreshed by the hook + ├── .md the AI writes these, flat, never nested ├── internal/ a .gitkeep, internal notes read on demand └── external/ a .gitkeep, external notes read on demand ``` + +- The three root docs are the team's. Their placeholders survive until a human answers them. +- Everything under `memory/` is the AI's, and sits at its root. +- `internal/` and `external/` exist even when empty. diff --git a/plugins/aidd-context/skills/02-project-memory/references/tools.md b/plugins/aidd-context/skills/02-project-memory/references/tools.md index c0c470c1..4b90d76d 100644 --- a/plugins/aidd-context/skills/02-project-memory/references/tools.md +++ b/plugins/aidd-context/skills/02-project-memory/references/tools.md @@ -12,3 +12,6 @@ The AI tools a project can use. - A shared `AGENTS.md` is a wiring target, never a detection signal. - Tools sharing a context file wire it once; the block serves them all. +- A context file carries the block under a `## Memory Management` section, shaped like `assets/templates/AGENTS.md`. +- An existing context file keeps everything else: add only what is missing. +- Touch no context file a picked tool does not resolve to. diff --git a/plugins/aidd-context/skills/12-cook/assets/recipes/token-optimization.md b/plugins/aidd-context/skills/12-cook/assets/recipes/token-optimization.md index 67c096fa..afcfd364 100644 --- a/plugins/aidd-context/skills/12-cook/assets/recipes/token-optimization.md +++ b/plugins/aidd-context/skills/12-cook/assets/recipes/token-optimization.md @@ -74,10 +74,10 @@ Your instruction file ships every turn, so each cut line saves on every message. 1. Open `CLAUDE.md` (or `.github/copilot-instructions.md`). 2. Cut it to essentials and add explicit conciseness rules. -3. Model it on a real concise instruction file: [AGENTS.md](../../../02-project-memory/assets/AGENTS.md). +3. Model it on the instruction file the project-memory skill scaffolds, which is already written this way. ```md -# CLAUDE.md — keep it terse (see AGENTS.md for the full example) +# CLAUDE.md — keep it terse - Answer first. Lead with the result, then the reason. Drop pleasantries and hedging. - No tool-call narration. No decorative tables or emoji unless they carry information. - Keep verbatim: code, quoted errors, security warnings. Cut the rest. diff --git a/scripts/skill-eval.mjs b/scripts/skill-eval.mjs index eee13a69..fc04ea82 100644 --- a/scripts/skill-eval.mjs +++ b/scripts/skill-eval.mjs @@ -1,5 +1,5 @@ #!/usr/bin/env node -// Behavioral eval harness for aidd-refine skills. +// Behavioral eval harness for the framework skills. // // Each case runs the skill for real through a headless `claude -p`, in an // isolated temp project where the skill is installed under a unique name as a @@ -8,6 +8,10 @@ // // Usage: // node scripts/skill-eval.mjs # run every case (deterministic checks) +// node scripts/skill-eval.mjs --model=opus # override the model (default: sonnet) +// node scripts/skill-eval.mjs --jobs=1 # run serially (default: 4 at a time) +// node scripts/skill-eval.mjs --repeat=3 # run each case 3 times, to measure flakiness +// node scripts/skill-eval.mjs --case=refresh # run only cases whose name matches // node scripts/skill-eval.mjs 03-shadow-areas # run cases for one skill // node scripts/skill-eval.mjs --judge # also run LLM-judge criteria (metered) // node scripts/skill-eval.mjs --keep # keep temp dirs for inspection @@ -18,19 +22,27 @@ import { mkdtempSync, mkdirSync, writeFileSync, cpSync, rmSync, readFileSync, existsSync } from "node:fs"; import { tmpdir } from "node:os"; import { join, dirname, resolve } from "node:path"; -import { spawnSync } from "node:child_process"; +import { spawn } from "node:child_process"; import { fileURLToPath } from "node:url"; const HERE = dirname(fileURLToPath(import.meta.url)); const ROOT = resolve(HERE, ".."); -const SKILLS_DIR = join(ROOT, "plugins", "aidd-refine", "skills"); +const skillsDir = (c) => join(ROOT, "plugins", c.plugin || "aidd-refine", "skills"); const CASES = JSON.parse(readFileSync(join(HERE, "skill-eval", "cases.json"), "utf8")); const args = process.argv.slice(2); const JUDGE = args.includes("--judge"); const KEEP = args.includes("--keep"); +const MODEL = (args.find((a) => a.startsWith("--model=")) || "--model=sonnet").split("=")[1]; +const JOBS = Number((args.find((a) => a.startsWith("--jobs=")) || "--jobs=4").split("=")[1]); const filter = args.find((a) => !a.startsWith("--")); -const cases = CASES.filter((c) => !filter || c.skill === filter); +const REPEAT = Number((args.find((a) => a.startsWith("--repeat=")) || "--repeat=1").split("=")[1]); +const CASE = (args.find((a) => a.startsWith("--case=")) || "--case=").split("=")[1]; +const selected = CASES.filter( + (c) => (!filter || c.skill === filter || c.plugin === filter) && (!CASE || c.name.toLowerCase().includes(CASE.toLowerCase())), +); +// A skill is not deterministic. Repeating a case turns "it failed" into a rate. +const cases = selected.flatMap((c) => Array.from({ length: REPEAT }, (_, i) => (REPEAT > 1 ? { ...c, name: `${c.name} [${i + 1}/${REPEAT}]` } : c))); if (cases.length === 0) { console.error(`No cases match ${filter ? `"${filter}"` : "(any)"}.`); @@ -38,15 +50,21 @@ if (cases.length === 0) { } function runClaude(prompt, cwd) { - const res = spawnSync( - "claude", + return new Promise((ok, ko) => { // --setting-sources project,local isolates the run from the user's global // settings (hooks, output modes) so results are reproducible across machines. - ["-p", prompt, "--setting-sources", "project,local", "--add-dir", cwd, "--dangerously-skip-permissions"], - { cwd, input: "", encoding: "utf8", timeout: 600000, maxBuffer: 10 * 1024 * 1024 }, - ); - if (res.error) throw res.error; - return (res.stdout || "") + (res.stderr || ""); + const child = spawn( + "claude", + ["-p", prompt, "--model", MODEL, "--setting-sources", "project,local", "--add-dir", cwd, "--dangerously-skip-permissions"], + { cwd, timeout: 600000 }, + ); + let out = ""; + child.stdout.on("data", (d) => (out += d)); + child.stderr.on("data", (d) => (out += d)); + child.on("error", ko); + child.on("close", () => ok(out)); + child.stdin.end(); + }); } function has(haystack, needle) { @@ -54,17 +72,30 @@ function has(haystack, needle) { } // One assertion = { ok: boolean, label: string } -function evaluate(expect, ctx) { +async function evaluate(expect, ctx) { const checks = []; const fileText = (name) => (existsSync(join(ctx.tmp, name)) ? readFileSync(join(ctx.tmp, name), "utf8") : null); for (const name of expect.filesExist || []) { checks.push({ ok: existsSync(join(ctx.tmp, name)), label: `file exists: ${name}` }); } + for (const name of expect.filesAbsent || []) { + checks.push({ ok: !existsSync(join(ctx.tmp, name)), label: `file absent: ${name}` }); + } + // The only way to assert that a read-only action stayed read-only. + for (const name of expect.filesUnchanged || []) { + const before = ctx.setup[name]; + checks.push({ ok: before != null && fileText(name) === before, label: `file unchanged: ${name}` }); + } for (const [name, subs] of Object.entries(expect.fileContains || {})) { const text = fileText(name); for (const s of subs) checks.push({ ok: text != null && has(text, s), label: `${name} contains "${s}"` }); } + // The only way to assert a file's whole shape, not just its parts. + for (const [name, re] of Object.entries(expect.fileMatches || {})) { + const text = fileText(name); + checks.push({ ok: text != null && new RegExp(re).test(text), label: `${name} matches /${re}/` }); + } for (const [name, subs] of Object.entries(expect.fileNotContains || {})) { const text = fileText(name); for (const s of subs) checks.push({ ok: text != null && !has(text, s), label: `${name} omits "${s}"` }); @@ -84,7 +115,7 @@ function evaluate(expect, ctx) { checks.push({ ok: true, skipped: true, label: `judge (skipped, pass --judge): ${expect.judge}` }); } else { const evidence = [ctx.stdout, ...(expect.judgeFiles || []).map((n) => fileText(n) || "")].join("\n\n"); - const verdict = runClaude( + const verdict = await runClaude( `You grade a test. Criterion: "${expect.judge}". Output under test follows between <<< and >>>.\n` + `Reply with exactly PASS or FAIL on the first line, then one line of reason.\n<<<\n${evidence}\n>>>`, ctx.tmp, @@ -99,7 +130,11 @@ function setupCase(c) { const tmp = mkdtempSync(join(tmpdir(), "skilleval-")); const skillDst = join(tmp, ".claude", "skills", c.evalName); mkdirSync(skillDst, { recursive: true }); - cpSync(join(SKILLS_DIR, c.skill), skillDst, { recursive: true }); + cpSync(join(skillsDir(c), c.skill), skillDst, { recursive: true }); + // A skill may run a script its plugin bundles. Stage it next to the skill so + // the sandbox matches an installed plugin rather than a skill copied alone. + const hooks = join(ROOT, "plugins", c.plugin || "aidd-refine", "hooks"); + if (existsSync(hooks)) cpSync(hooks, join(skillDst, "hooks"), { recursive: true }); // Rewrite the frontmatter name so it matches the unique eval folder. const skillMd = join(skillDst, "SKILL.md"); const rewritten = readFileSync(skillMd, "utf8").replace(/^name:.*$/m, `name: ${c.evalName}`); @@ -112,29 +147,54 @@ function setupCase(c) { return tmp; } -console.log(`Running ${cases.length} case(s)${JUDGE ? " with --judge" : ""}.\n`); -let failed = 0; -for (const c of cases) { - const tmp = setupCase(c); +async function runCase(c) { + // setupCase can throw on a case whose skill folder is gone. Keep it inside the + // guard: one broken case must not abort a suite that takes minutes to run. + let tmp = null; let checks; + let stdout = ""; try { + tmp = setupCase(c); const prompt = c.prompt.replaceAll("{{SKILL}}", c.evalName); - const stdout = runClaude(prompt, tmp); - checks = evaluate(c.expect, { tmp, stdout }); + stdout = await runClaude(prompt, tmp); + checks = await evaluate(c.expect, { tmp, stdout, setup: c.setup?.files || {} }); } catch (err) { checks = [{ ok: false, label: `run error: ${err.message}` }]; } - const caseFailed = checks.some((k) => !k.ok); - if (caseFailed) failed++; - console.log(`${caseFailed ? "FAIL" : "PASS"} ${c.skill} :: ${c.name}`); + // A case that fails because the run itself failed looks identical to a case + // that fails on the skill's behavior. Keep the tail so the two are separable. + const broke = checks.some((k) => !k.ok); + if (broke) { + const tail = stdout.trim().slice(-400).replace(/\s+/g, " "); + checks.push({ ok: true, skipped: true, label: `run said: ${tail || "(nothing)"}` }); + } + if (!KEEP && tmp) rmSync(tmp, { recursive: true, force: true }); + // Report as each case lands, in one write so parallel cases never interleave. + // A long suite that is interrupted still leaves every finished case behind. + const lines = [`${broke ? "FAIL" : "PASS"} ${c.skill} :: ${c.name}`]; for (const k of checks) { - const mark = k.skipped ? "~" : k.ok ? "✓" : "✗"; - console.log(` ${mark} ${k.label}${k.note ? ` (${k.note})` : ""}`); + lines.push(` ${k.skipped ? "~" : k.ok ? "✓" : "✗"} ${k.label}${k.note ? ` (${k.note})` : ""}`); } - if (KEEP) console.log(` tmp: ${tmp}`); - else rmSync(tmp, { recursive: true, force: true }); - console.log(""); + if (KEEP && tmp) lines.push(` tmp: ${tmp}`); + console.log(`${lines.join("\n")}\n`); + return { c, checks, tmp }; +} + +// Cases are independent, each in its own temp project, so they run concurrently. +// The cap keeps a large suite from spawning one `claude` per case at once. +async function runAll(list, jobs) { + const out = []; + let next = 0; + const worker = async () => { + while (next < list.length) out[next] = await runCase(list[next++]); + }; + await Promise.all(Array.from({ length: Math.min(jobs, list.length) }, worker)); + return out; } +console.log(`Running ${cases.length} case(s) on ${MODEL}, ${JOBS} at a time${JUDGE ? ", with --judge" : ""}.\n`); +const results = await runAll(cases, JOBS); +const failed = results.filter(({ checks }) => checks.some((k) => !k.ok)).length; + console.log(`${cases.length - failed}/${cases.length} cases passed.`); process.exit(failed ? 1 : 0); diff --git a/scripts/skill-eval/cases.json b/scripts/skill-eval/cases.json index 8311d708..90aacca4 100644 --- a/scripts/skill-eval/cases.json +++ b/scripts/skill-eval/cases.json @@ -10,39 +10,77 @@ }, "prompt": "Use the {{SKILL}} skill on ./prd.md to find blind spots and write the shadow report file next to it.", "expect": { - "filesExist": ["prd-shadow-report.md"], - "fileContains": { "prd-shadow-report.md": ["# Shadow Areas Report", "## Gaps by Category", "Total gaps:", "[blocker]"] } + "filesExist": [ + "prd-shadow-report.md" + ], + "fileContains": { + "prd-shadow-report.md": [ + "# Shadow Areas Report", + "## Gaps by Category", + "Total gaps:", + "[blocker]" + ] + } } }, { "skill": "03-shadow-areas", "evalName": "xeval-shadow", "name": "filename rule keeps a dotless name (Makefile)", - "setup": { "files": { "Makefile": "build:\n\techo hi\n" } }, + "setup": { + "files": { + "Makefile": "build:\n\techo hi\n" + } + }, "prompt": "Use the {{SKILL}} skill on ./Makefile to find blind spots and write the shadow report next to it.", - "expect": { "filesExist": ["Makefile-shadow-report.md"] } + "expect": { + "filesExist": [ + "Makefile-shadow-report.md" + ] + } }, { "skill": "03-shadow-areas", "evalName": "xeval-shadow", "name": "empty source yields a single blocker", - "setup": { "files": { "empty.md": "" } }, + "setup": { + "files": { + "empty.md": "" + } + }, "prompt": "Use the {{SKILL}} skill on ./empty.md to find blind spots and write the shadow report next to it.", "expect": { - "filesExist": ["empty-shadow-report.md"], + "filesExist": [ + "empty-shadow-report.md" + ], "judge": "The report flags exactly one blocker gap, asking what content the (empty) artifact should contain.", - "judgeFiles": ["empty-shadow-report.md"] + "judgeFiles": [ + "empty-shadow-report.md" + ] } }, { "skill": "04-fact-check", "evalName": "xeval-factcheck", "name": "verifies a real file, refutes a fake one, hedges the unknowable, hides mechanics", - "setup": { "files": { "src/auth.ts": "export const auth = true;\n" } }, + "setup": { + "files": { + "src/auth.ts": "export const auth = true;\n" + } + }, "prompt": "Use the {{SKILL}} skill to fact-check this text and rewrite it with citations: \"The file src/auth.ts exists in this repo. The file src/ghost9000.ts exists in this repo. The lead maintainer of this project owns exactly 47 cats.\"", "expect": { - "stdoutContains": ["## Sources", "(unverified - no source found)"], - "stdoutNotContains": ["tier 1", "tier 2", "tier 3", "Cascade", "codebase inspection"], + "stdoutContains": [ + "## Sources", + "(unverified - no source found)" + ], + "stdoutNotContains": [ + "tier 1", + "tier 2", + "tier 3", + "Cascade", + "codebase inspection" + ], "judge": "src/auth.ts is confirmed with a citation; the src/ghost9000.ts claim is corrected as not present (never restated as true); the 47-cats claim is marked unverified; no shell commands or inspection methods appear.", "judgeFiles": [] } @@ -53,8 +91,231 @@ "name": "flags a plan violation as a deal breaker with low confidence", "prompt": "Use the {{SKILL}} skill. Agreed plan: the function must RETURN THE SUM of a and b. Work to review: function add(a, b) { return a - b }. Challenge the work against the plan and emit the report.", "expect": { - "stdoutContains": ["confidence", "Deal breakers"], + "stdoutContains": [ + "confidence", + "Deal breakers" + ], "judge": "A confidence percentage below 75% is stated, and the subtraction (returning a - b instead of a + b) is listed as a deal breaker." } + }, + { + "plugin": "aidd-context", + "skill": "02-project-memory", + "evalName": "xeval-memory", + "name": "setup writes the bank to its destinations", + "setup": { + "files": { + "package.json": "{\n \"name\": \"shop\",\n \"version\": \"1.0.0\",\n \"scripts\": { \"test\": \"vitest\" },\n \"dependencies\": { \"express\": \"^4.19.0\" }\n}\n", + "README.md": "# Shop\n\nA small order API. Express server, Postgres behind it.\n", + "src/server.js": "const express = require(\"express\");\nconst app = express();\napp.get(\"/orders\", (req, res) => res.json([]));\nmodule.exports = app;\n", + ".github/workflows/ci.yml": "name: CI\non: [push]\njobs:\n test:\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n", + ".github/dependabot.yml": "version: 2\nupdates:\n - package-ecosystem: npm\n directory: \"/\"\n schedule:\n interval: weekly\n" + } + }, + "prompt": "Use the {{SKILL}} skill to set up the project memory. You are running headless with no human available, so answer every question yourself from the repo evidence, never wait for input, and complete the whole flow.", + "expect": { + "filesExist": [ + "aidd_docs/memory/project-brief.md", + "aidd_docs/memory/architecture.md", + "aidd_docs/memory/codebase-map.md", + "aidd_docs/memory/coding-assertions.md", + "aidd_docs/memory/testing.md", + "aidd_docs/memory/vcs.md", + "aidd_docs/memory/ecosystem.md", + "aidd_docs/memory/README.md", + "aidd_docs/GUIDELINES.md", + "aidd_docs/CONTRIBUTING.md" + ], + "fileNotContains": { + "aidd_docs/memory/vcs.md": [ + "Ticketing" + ], + "aidd_docs/memory/ecosystem.md": [ + "", + "", + "", + "Remove this comment" + ] + }, + "fileContains": { + "aidd_docs/memory/ecosystem.md": [ + "flowchart", + "·", + "ependabot" + ], + "aidd_docs/GUIDELINES.md": [ + "A rule the AI must follow here" + ], + "aidd_docs/CONTRIBUTING.md": [ + "A naming or placement rule specific to this repo" + ] + }, + "fileMatches": { + "aidd_docs/memory/ecosystem.md": "^# Ecosystem\\s*```mermaid\\n[\\s\\S]*\\n```\\s*$" + } + } + }, + { + "plugin": "aidd-context", + "skill": "02-project-memory", + "evalName": "xeval-memory", + "name": "check flags an orphan file and deletes nothing", + "setup": { + "files": { + "package.json": "{ \"name\": \"shop\", \"version\": \"1.0.0\" }\n", + "src/index.js": "module.exports = 1;\n", + "aidd_docs/memory/vcs.md": "# VCS\n\n- Main branch: main\n- Platform: github\n", + "aidd_docs/memory/architecture.md": "# Architecture\n\n## Stack\n\n- Node, CommonJS\n\n## Gotchas\n\n- QUARTZLINE runs on Node.js 18 only\n", + "aidd_docs/memory/browsing.md": "# Browsing\n\n- Pages are server rendered.\n" + } + }, + "prompt": "Use the {{SKILL}} skill to check the project memory. You are running headless with no human available, so report what drifted and delete nothing.", + "expect": { + "filesExist": [ + "aidd_docs/memory/browsing.md" + ], + "stdoutContains": [ + "Memory bank", + "aidd_docs/tasks/" + ], + "filesUnchanged": [ + "aidd_docs/memory/architecture.md", + "aidd_docs/memory/vcs.md", + "aidd_docs/memory/browsing.md" + ], + "judge": "The report describes only the memory bank: no cell or note names a step of the skill, nor explains how a finding was reached.", + "stdoutNotContains": [ + "Match step", + "Review step", + "Prune step", + "02-write", + "03-check", + "01-scan" + ] + } + }, + { + "plugin": "aidd-context", + "skill": "02-project-memory", + "evalName": "xeval-memory", + "name": "check flags the always file the bank lacks", + "setup": { + "files": { + "package.json": "{ \"name\": \"shop\", \"version\": \"1.0.0\" }\n", + "src/index.js": "module.exports = 1;\n", + ".github/workflows/ci.yml": "name: CI\non: [push]\njobs:\n build:\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n", + "aidd_docs/memory/vcs.md": "# VCS\n\n- Main branch: main\n- Platform: github\n", + "aidd_docs/memory/architecture.md": "# Architecture\n\n## Stack\n\n- Node, CommonJS\n" + } + }, + "prompt": "Use the {{SKILL}} skill to check the project memory. You are running headless with no human available, so report what drifted, change nothing, and do not wait for input.", + "expect": { + "stdoutContains": [ + "Memory bank", + "aidd_docs/tasks/", + "ecosystem" + ], + "filesAbsent": [ + "aidd_docs/memory/ecosystem.md" + ], + "filesUnchanged": [ + "aidd_docs/memory/vcs.md", + "aidd_docs/memory/architecture.md" + ], + "judge": "The report describes only the memory bank: no cell or note names a step of the skill, nor explains how a finding was reached.", + "stdoutNotContains": [ + "Match step", + "Review step", + "Prune step", + "02-write", + "03-check", + "01-scan" + ] + } + }, + { + "plugin": "aidd-context", + "skill": "02-project-memory", + "evalName": "xeval-memory", + "name": "rewire fills the context block", + "setup": { + "files": { + "package.json": "{ \"name\": \"shop\", \"version\": \"1.0.0\" }\n", + "aidd_docs/memory/architecture.md": "# Architecture\n\n## Stack\n\n- Node\n", + "aidd_docs/memory/vcs.md": "# VCS\n\n- Main branch: main\n", + "CLAUDE.md": "# Shop\n\n## Memory Management\n\n\n\n" + } + }, + "prompt": "Use the {{SKILL}} skill to rewire the existing project memory into Claude. You are running headless with no human available, so pick Claude yourself and do not wait for input.", + "expect": { + "fileContains": { + "CLAUDE.md": [ + "@aidd_docs/memory/architecture.md", + "@aidd_docs/memory/vcs.md" + ] + } + } + }, + { + "plugin": "aidd-context", + "skill": "02-project-memory", + "evalName": "xeval-memory", + "name": "an empty repo produces no bank", + "setup": { + "files": { + "notes.txt": "\n" + } + }, + "prompt": "Use the {{SKILL}} skill to set up the project memory. You are running headless with no human available, so do not wait for input.", + "expect": { + "filesAbsent": [ + "aidd_docs/memory/architecture.md", + "aidd_docs/memory/vcs.md" + ] + } + }, + { + "plugin": "aidd-context", + "skill": "02-project-memory", + "evalName": "xeval-memory", + "name": "refresh applies what is approved and leaves the rest", + "setup": { + "files": { + "package.json": "{\n \"name\": \"shop\",\n \"version\": \"1.0.0\",\n \"dependencies\": { \"express\": \"^4.19.0\" }\n}\n", + "src/server.js": "const express = require(\"express\");\nmodule.exports = express();\n", + "Dockerfile": "FROM node:22-alpine\nWORKDIR /app\nCOPY . .\nCMD [\"node\", \"src/server.js\"]\n", + "aidd_docs/memory/README.md": "# memory/\n\n\n\n", + "aidd_docs/memory/architecture.md": "# Architecture\n\n## Stack\n\n- Node and Express\n\n## Gotchas\n\n- ZEBRAQUARTZ the order queue is single threaded on purpose, do not parallelise it\n", + "aidd_docs/memory/vcs.md": "# VCS\n\n- Main branch: main\n- Platform: github\n", + "aidd_docs/memory/project-brief.md": "# Project Brief\n\n## What it is\n\n- A small order API\n", + "aidd_docs/memory/codebase-map.md": "# Codebase Map\n\n## Areas\n\n- `src/`: the server\n", + "aidd_docs/memory/coding-assertions.md": "# Coding Assertions\n\n## Before commit\n\n| Order | Command | Checks |\n| --- | --- | --- |\n| 1 | `npm test` | tests |\n", + "aidd_docs/memory/testing.md": "# Testing\n\n## Run\n\n- `npm test`\n", + ".github/workflows/ci.yml": "name: CI\non: [push]\njobs:\n build:\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n" + } + }, + "prompt": "Use the {{SKILL}} skill to refresh the project memory. A bank already exists. You are running headless with no human available: answer for me, approving every finding that adds or corrects a fact, and declining every finding that would remove a line already in a file. Never wait for input, and complete the whole flow.", + "expect": { + "filesExist": [ + "aidd_docs/memory/deployment.md", + "aidd_docs/memory/ecosystem.md", + "aidd_docs/memory/architecture.md", + "aidd_docs/memory/vcs.md", + "aidd_docs/memory/project-brief.md" + ], + "fileContains": { + "aidd_docs/memory/architecture.md": [ + "ZEBRAQUARTZ" + ], + "aidd_docs/memory/deployment.md": [ + "Docker" + ] + }, + "fileNotContains": { + "aidd_docs/memory/vcs.md": [ + "Ticketing" + ] + } + } } ] From f83da88ba492ee21c2ee6f7560b16a02715902e5 Mon Sep 17 00:00:00 2001 From: Baptiste LAFOURCADE <119650761+blafourcade@users.noreply.github.com> Date: Fri, 14 Aug 2026 13:19:17 +0200 Subject: [PATCH 14/14] fix(ci): promote widens its window until it reproduces next (#634) The promote window was anchored at the most recent back-merge sync commit, on the assumption that everything before it already lived on main. A back-merge only folds main into next; it never carries next's own commits back to main. Work that landed on next after the previous promote but before the last back-merge therefore fell behind the boundary and was dropped for good, which is how #605, #606 and #607 went missing. Anchor the window at the newest sync, then widen it to older syncs until the replayed branch reproduces origin/next exactly, and filter every candidate through git cherry so commits main already carries under a rebased hash are never replayed. The tree comparison is now the acceptance test that drives the search rather than a final assertion. Key the no-op path on main and next sharing a tree instead of on an empty window: an empty window is precisely what silently swallowed the dropped commits. Fetch the promote branch so --force-with-lease leases against the real ref. Co-authored-by: aidd-bot[bot] Co-authored-by: Claude Opus 5 --- .github/workflows/promote.yml | 109 ++++++++++++++++++++++------------ 1 file changed, 72 insertions(+), 37 deletions(-) diff --git a/.github/workflows/promote.yml b/.github/workflows/promote.yml index 4a286a2c..cf2d7b33 100644 --- a/.github/workflows/promote.yml +++ b/.github/workflows/promote.yml @@ -45,23 +45,27 @@ jobs: git config user.name "aidd-bot[bot]" git config user.email "aidd-bot[bot]@users.noreply.github.com" git remote set-url origin "https://x-access-token:${GH_TOKEN}@github.com/${REPO}.git" + BRANCH="promote/next-to-main-linear" git fetch origin main next --prune + git fetch origin "+refs/heads/${BRANCH}:refs/remotes/origin/${BRANCH}" 2>/dev/null || true - BRANCH="promote/next-to-main-linear" - git switch -C "$BRANCH" origin/main + if [ "$(git rev-parse origin/main^{tree})" = "$(git rev-parse origin/next^{tree})" ]; then + echo "No commits to promote." + exit 0 + fi - # A "sync commit" marks a point where main's history was already - # folded into next by back-merge.yml, so it (and everything before - # it) must NOT be replayed onto main again. back-merge.yml lands a + # A "sync commit" marks a point where main's history was folded into + # next by back-merge.yml, so the sync itself carries main's own + # content and must NOT be replayed onto main. back-merge.yml lands a # sync two ways: # - no conflicts: a direct-pushed real merge commit (2 parents) # - conflicts: a PR merged by squash (this repo disallows # merge-commit PRs), whose subject is stamped verbatim from # back-merge.yml's fixed PR title - # Both must count as boundaries, or a squash sync gets mistaken for - # genuine next-only work and cherry-picked back onto main, colliding - # with content main already has. Keep the title prefix below in - # sync with back-merge.yml's `gh pr create --title`. + # Both must be recognised, or a squash sync gets mistaken for genuine + # next-only work and cherry-picked back onto main, colliding with + # content main already has. Keep the title prefix below in sync with + # back-merge.yml's `gh pr create --title`. is_sync_commit() { git rev-parse --verify -q "$1^2" >/dev/null 2>&1 && return 0 local subject @@ -75,37 +79,68 @@ jobs: is_sync_commit "$c" && SYNCS+=("$c") done - # The most recent sync is the boundary: everything up to and - # including it is already folded into main (that's what "sync" - # means), so only commits strictly after it are genuine next-only - # work still owed to main. Picking an older sync here replays a - # window of already-promoted commits, which either no-ops as empty - # cherry-picks (halting the script, since it doesn't pass - # --allow-empty) or, worse, collides with unrelated commits that - # touched the same files in between (e.g. sequential dependency - # lockfile bumps), producing spurious conflicts. - if [ "${#SYNCS[@]}" -ge 1 ]; then - START="${SYNCS[$((${#SYNCS[@]} - 1))]}" - else - START="origin/main" - fi - - COMMITS=() - while IFS= read -r c; do - is_sync_commit "$c" || COMMITS+=("$c") - done < <(git rev-list --first-parent --reverse "${START}..origin/next") - - if [ "${#COMMITS[@]}" -eq 0 ]; then - echo "No commits to promote." - exit 0 - fi - - git cherry-pick "${COMMITS[@]}" - if [ "$(git rev-parse HEAD^{tree})" != "$(git rev-parse origin/next^{tree})" ]; then - echo "Linear promotion branch does not match origin/next." + # Commits main already carries. A promote is a rebase-merge, so main's + # copy of a promoted commit keeps the same patch under a new hash, and + # `git cherry` marks it "-". Skipping those is what stops an + # already-promoted commit from being replayed as an empty cherry-pick + # (which would halt the script, since it doesn't pass --allow-empty) + # or as a spurious conflict with a later bump to the same lockfile. + declare -A ALREADY=() + while read -r sign sha; do + [ "$sign" = "-" ] && ALREADY["$sha"]=1 + done < <(git cherry origin/main origin/next) + + # Start the window at the most recent sync and widen to older syncs + # until the replayed branch reproduces origin/next exactly. The + # narrowest window is right only when every commit before the last + # back-merge was already promoted. It is wrong when work landed on + # next after the previous promote but before that back-merge: a + # back-merge only folds main into next, it never carries next's own + # commits to main, so those commits are still owed and a sync-anchored + # window silently drops them forever. Widening recovers them, and the + # tree comparison against origin/next is the acceptance test. + PICKED=() + MATCHED="" + for ((i = ${#SYNCS[@]} - 1; i >= -1; i--)); do + if [ "$i" -ge 0 ]; then + START="${SYNCS[$i]}" + else + START="origin/main" + fi + + COMMITS=() + while IFS= read -r c; do + is_sync_commit "$c" && continue + [ -n "${ALREADY[$c]:-}" ] && continue + COMMITS+=("$c") + done < <(git rev-list --first-parent --reverse "${START}..origin/next") + + if [ "${#COMMITS[@]}" -eq 0 ]; then + continue + fi + + git cherry-pick --abort >/dev/null 2>&1 || true + git switch -C "$BRANCH" origin/main + if ! git cherry-pick "${COMMITS[@]}"; then + git cherry-pick --abort >/dev/null 2>&1 || true + echo "Window from ${START} conflicts on replay; widening." + continue + fi + if [ "$(git rev-parse HEAD^{tree})" = "$(git rev-parse origin/next^{tree})" ]; then + PICKED=("${COMMITS[@]}") + MATCHED=1 + break + fi + echo "Window from ${START} does not reproduce origin/next; widening." git diff --stat HEAD origin/next + done + + if [ -z "$MATCHED" ]; then + echo "No window of next-only commits reproduces origin/next." + echo "main and next have diverged beyond a linear replay; back-merge main into next first." exit 1 fi + echo "Promoting ${#PICKED[@]} commits." git push --force-with-lease origin "HEAD:refs/heads/${BRANCH}"