From 3eb377a3a3b31307a7bd91f7a199a2acee662f7b Mon Sep 17 00:00:00 2001 From: Sutu Sebastian Date: Mon, 27 Apr 2026 13:06:54 +0300 Subject: [PATCH 01/12] chore(deps): bump runtime and dev dependencies Routine bumps caught by lockfile drift; no functional changes. --- bun.lock | 254 ++++++++++++++++++++++++++------------------------- package.json | 22 ++--- 2 files changed, 143 insertions(+), 133 deletions(-) diff --git a/bun.lock b/bun.lock index 724744c..e77861c 100644 --- a/bun.lock +++ b/bun.lock @@ -6,26 +6,26 @@ "name": "@stainless-code/codemap", "dependencies": { "@clack/prompts": "^1.2.0", - "better-sqlite3": "^12.8.0", + "better-sqlite3": "^12.9.0", "lightningcss": "^1.32.0", - "oxc-parser": "^0.124.0", + "oxc-parser": "^0.127.0", "oxc-resolver": "^11.19.1", - "tinyglobby": "^0.2.15", + "tinyglobby": "^0.2.16", "zod": "^4.3.6", }, "devDependencies": { "@changesets/changelog-github": "^0.6.0", - "@changesets/cli": "^2.30.0", + "@changesets/cli": "^2.31.0", "@types/better-sqlite3": "^7.6.13", - "@types/bun": "^1.3.11", - "@types/node": "^25.5.2", - "@typescript/native-preview": "^7.0.0-dev.20260407.1", + "@types/bun": "^1.3.13", + "@types/node": "^25.6.0", + "@typescript/native-preview": "^7.0.0-dev.20260427.1", "husky": "^9.1.7", "lint-staged": "^16.4.0", - "oxfmt": "^0.44.0", - "oxlint": "^1.59.0", - "tsdown": "^0.21.7", - "typescript": "^6.0.2", + "oxfmt": "^0.46.0", + "oxlint": "^1.61.0", + "tsdown": "^0.21.10", + "typescript": "^6.0.3", }, }, }, @@ -42,25 +42,25 @@ "@babel/types": ["@babel/types@8.0.0-rc.3", "", { "dependencies": { "@babel/helper-string-parser": "^8.0.0-rc.3", "@babel/helper-validator-identifier": "^8.0.0-rc.3" } }, "sha512-mOm5ZrYmphGfqVWoH5YYMTITb3cDXsFgmvFlvkvWDMsR9X8RFnt7a0Wb6yNIdoFsiMO9WjYLq+U/FMtqIYAF8Q=="], - "@changesets/apply-release-plan": ["@changesets/apply-release-plan@7.1.0", "", { "dependencies": { "@changesets/config": "^3.1.3", "@changesets/get-version-range-type": "^0.4.0", "@changesets/git": "^3.0.4", "@changesets/should-skip-package": "^0.1.2", "@changesets/types": "^6.1.0", "@manypkg/get-packages": "^1.1.3", "detect-indent": "^6.0.0", "fs-extra": "^7.0.1", "lodash.startcase": "^4.4.0", "outdent": "^0.5.0", "prettier": "^2.7.1", "resolve-from": "^5.0.0", "semver": "^7.5.3" } }, "sha512-yq8ML3YS7koKQ/9bk1PqO0HMzApIFNwjlwCnwFEXMzNe8NpzeeYYKCmnhWJGkN8g7E51MnWaSbqRcTcdIxUgnQ=="], + "@changesets/apply-release-plan": ["@changesets/apply-release-plan@7.1.1", "", { "dependencies": { "@changesets/config": "^3.1.4", "@changesets/get-version-range-type": "^0.4.0", "@changesets/git": "^3.0.4", "@changesets/should-skip-package": "^0.1.2", "@changesets/types": "^6.1.0", "@manypkg/get-packages": "^1.1.3", "detect-indent": "^6.0.0", "fs-extra": "^7.0.1", "lodash.startcase": "^4.4.0", "outdent": "^0.5.0", "prettier": "^2.7.1", "resolve-from": "^5.0.0", "semver": "^7.5.3" } }, "sha512-9qPCm/rLx/xoOFXIHGB229+4GOL76S4MC+7tyOuTsR6+1jYlfFDQORdvwR5hDA6y4FL2BPt3qpbcQIS+dW85LA=="], - "@changesets/assemble-release-plan": ["@changesets/assemble-release-plan@6.0.9", "", { "dependencies": { "@changesets/errors": "^0.2.0", "@changesets/get-dependents-graph": "^2.1.3", "@changesets/should-skip-package": "^0.1.2", "@changesets/types": "^6.1.0", "@manypkg/get-packages": "^1.1.3", "semver": "^7.5.3" } }, "sha512-tPgeeqCHIwNo8sypKlS3gOPmsS3wP0zHt67JDuL20P4QcXiw/O4Hl7oXiuLnP9yg+rXLQ2sScdV1Kkzde61iSQ=="], + "@changesets/assemble-release-plan": ["@changesets/assemble-release-plan@6.0.10", "", { "dependencies": { "@changesets/errors": "^0.2.0", "@changesets/get-dependents-graph": "^2.1.4", "@changesets/should-skip-package": "^0.1.2", "@changesets/types": "^6.1.0", "@manypkg/get-packages": "^1.1.3", "semver": "^7.5.3" } }, "sha512-rSDcqdJ9KbVyjpBIuCidhvZNIiVt1XaIYp73ycVQRIA5n/j6wQaEk0ChRLMUQ1vkxZe51PTQ9OIhbg6HQMW45A=="], "@changesets/changelog-git": ["@changesets/changelog-git@0.2.1", "", { "dependencies": { "@changesets/types": "^6.1.0" } }, "sha512-x/xEleCFLH28c3bQeQIyeZf8lFXyDFVn1SgcBiR2Tw/r4IAWlk1fzxCEZ6NxQAjF2Nwtczoen3OA2qR+UawQ8Q=="], "@changesets/changelog-github": ["@changesets/changelog-github@0.6.0", "", { "dependencies": { "@changesets/get-github-info": "^0.8.0", "@changesets/types": "^6.1.0", "dotenv": "^8.1.0" } }, "sha512-wA2/y4hR/A1K411cCT75rz0d46Iezxp1WYRFoFJDIUpkQ6oDBAIUiU7BZkDCmYgz0NBl94X1lgcZO+mHoiHnFg=="], - "@changesets/cli": ["@changesets/cli@2.30.0", "", { "dependencies": { "@changesets/apply-release-plan": "^7.1.0", "@changesets/assemble-release-plan": "^6.0.9", "@changesets/changelog-git": "^0.2.1", "@changesets/config": "^3.1.3", "@changesets/errors": "^0.2.0", "@changesets/get-dependents-graph": "^2.1.3", "@changesets/get-release-plan": "^4.0.15", "@changesets/git": "^3.0.4", "@changesets/logger": "^0.1.1", "@changesets/pre": "^2.0.2", "@changesets/read": "^0.6.7", "@changesets/should-skip-package": "^0.1.2", "@changesets/types": "^6.1.0", "@changesets/write": "^0.4.0", "@inquirer/external-editor": "^1.0.2", "@manypkg/get-packages": "^1.1.3", "ansi-colors": "^4.1.3", "enquirer": "^2.4.1", "fs-extra": "^7.0.1", "mri": "^1.2.0", "package-manager-detector": "^0.2.0", "picocolors": "^1.1.0", "resolve-from": "^5.0.0", "semver": "^7.5.3", "spawndamnit": "^3.0.1", "term-size": "^2.1.0" }, "bin": { "changeset": "bin.js" } }, "sha512-5D3Nk2JPqMI1wK25pEymeWRSlSMdo5QOGlyfrKg0AOufrUcjEE3RQgaCpHoBiM31CSNrtSgdJ0U6zL1rLDDfBA=="], + "@changesets/cli": ["@changesets/cli@2.31.0", "", { "dependencies": { "@changesets/apply-release-plan": "^7.1.1", "@changesets/assemble-release-plan": "^6.0.10", "@changesets/changelog-git": "^0.2.1", "@changesets/config": "^3.1.4", "@changesets/errors": "^0.2.0", "@changesets/get-dependents-graph": "^2.1.4", "@changesets/get-release-plan": "^4.0.16", "@changesets/git": "^3.0.4", "@changesets/logger": "^0.1.1", "@changesets/pre": "^2.0.2", "@changesets/read": "^0.6.7", "@changesets/should-skip-package": "^0.1.2", "@changesets/types": "^6.1.0", "@changesets/write": "^0.4.0", "@inquirer/external-editor": "^1.0.2", "@manypkg/get-packages": "^1.1.3", "ansi-colors": "^4.1.3", "enquirer": "^2.4.1", "fs-extra": "^7.0.1", "mri": "^1.2.0", "package-manager-detector": "^0.2.0", "picocolors": "^1.1.0", "resolve-from": "^5.0.0", "semver": "^7.5.3", "spawndamnit": "^3.0.1", "term-size": "^2.1.0" }, "bin": { "changeset": "bin.js" } }, "sha512-AhI4enNTgHu2IZr6K4WZyf0EPch4XVMn1yOMFmCD9gsfBGqMYaHXls5HyDv6/CL5axVQABz68eG30eCtbr2wFg=="], - "@changesets/config": ["@changesets/config@3.1.3", "", { "dependencies": { "@changesets/errors": "^0.2.0", "@changesets/get-dependents-graph": "^2.1.3", "@changesets/logger": "^0.1.1", "@changesets/should-skip-package": "^0.1.2", "@changesets/types": "^6.1.0", "@manypkg/get-packages": "^1.1.3", "fs-extra": "^7.0.1", "micromatch": "^4.0.8" } }, "sha512-vnXjcey8YgBn2L1OPWd3ORs0bGC4LoYcK/ubpgvzNVr53JXV5GiTVj7fWdMRsoKUH7hhhMAQnsJUqLr21EncNw=="], + "@changesets/config": ["@changesets/config@3.1.4", "", { "dependencies": { "@changesets/errors": "^0.2.0", "@changesets/get-dependents-graph": "^2.1.4", "@changesets/logger": "^0.1.1", "@changesets/should-skip-package": "^0.1.2", "@changesets/types": "^6.1.0", "@manypkg/get-packages": "^1.1.3", "fs-extra": "^7.0.1", "micromatch": "^4.0.8" } }, "sha512-pf0bvD/v6WI2cRlZ6hzpjtZdSlXDXMAJ+Iz7xfFzV4ZxJ8OGGAON+1qYc99ZPrijnt4xp3VGG7eNvAOGS24V1Q=="], "@changesets/errors": ["@changesets/errors@0.2.0", "", { "dependencies": { "extendable-error": "^0.1.5" } }, "sha512-6BLOQUscTpZeGljvyQXlWOItQyU71kCdGz7Pi8H8zdw6BI0g3m43iL4xKUVPWtG+qrrL9DTjpdn8eYuCQSRpow=="], - "@changesets/get-dependents-graph": ["@changesets/get-dependents-graph@2.1.3", "", { "dependencies": { "@changesets/types": "^6.1.0", "@manypkg/get-packages": "^1.1.3", "picocolors": "^1.1.0", "semver": "^7.5.3" } }, "sha512-gphr+v0mv2I3Oxt19VdWRRUxq3sseyUpX9DaHpTUmLj92Y10AGy+XOtV+kbM6L/fDcpx7/ISDFK6T8A/P3lOdQ=="], + "@changesets/get-dependents-graph": ["@changesets/get-dependents-graph@2.1.4", "", { "dependencies": { "@changesets/types": "^6.1.0", "@manypkg/get-packages": "^1.1.3", "picocolors": "^1.1.0", "semver": "^7.5.3" } }, "sha512-ZsS00x6WvmHq3sQv8oCMwL0f/z3wbXCVuSVTJwCnnmbC/iBdNJGFx1EcbMG4PC6sXRyH69liM4A2WKXzn/kRPg=="], "@changesets/get-github-info": ["@changesets/get-github-info@0.8.0", "", { "dependencies": { "dataloader": "^1.4.0", "node-fetch": "^2.5.0" } }, "sha512-cRnC+xdF0JIik7coko3iUP9qbnfi1iJQ3sAa6dE+Tx3+ET8bjFEm63PA4WEohgjYcmsOikPHWzPsMWWiZmntOQ=="], - "@changesets/get-release-plan": ["@changesets/get-release-plan@4.0.15", "", { "dependencies": { "@changesets/assemble-release-plan": "^6.0.9", "@changesets/config": "^3.1.3", "@changesets/pre": "^2.0.2", "@changesets/read": "^0.6.7", "@changesets/types": "^6.1.0", "@manypkg/get-packages": "^1.1.3" } }, "sha512-Q04ZaRPuEVZtA+auOYgFaVQQSA98dXiVe/yFaZfY7hoSmQICHGvP0TF4u3EDNHWmmCS4ekA/XSpKlSM2PyTS2g=="], + "@changesets/get-release-plan": ["@changesets/get-release-plan@4.0.16", "", { "dependencies": { "@changesets/assemble-release-plan": "^6.0.10", "@changesets/config": "^3.1.4", "@changesets/pre": "^2.0.2", "@changesets/read": "^0.6.7", "@changesets/types": "^6.1.0", "@manypkg/get-packages": "^1.1.3" } }, "sha512-2K5Om6CrMPm45rtvckfzWo7e9jOVCKLCnXia5eUPaURH7/LWzri7pK1TycdzAuAtehLkW7VPbWLCSExTHmiI6g=="], "@changesets/get-version-range-type": ["@changesets/get-version-range-type@0.4.0", "", {}, "sha512-hwawtob9DryoGTpixy1D3ZXbGgJu1Rhr+ySH2PvTLHvkZuQ7sRT4oQwMh0hbqZH1weAooedEjRsbrWcGLCeyVQ=="], @@ -84,11 +84,11 @@ "@clack/prompts": ["@clack/prompts@1.2.0", "", { "dependencies": { "@clack/core": "1.2.0", "fast-string-width": "^1.1.0", "fast-wrap-ansi": "^0.1.3", "sisteransi": "^1.0.5" } }, "sha512-4jmztR9fMqPMjz6H/UZXj0zEmE43ha1euENwkckKKel4XpSfokExPo5AiVStdHSAlHekz4d0CA/r45Ok1E4D3w=="], - "@emnapi/core": ["@emnapi/core@1.9.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.0", "tslib": "^2.4.0" } }, "sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA=="], + "@emnapi/core": ["@emnapi/core@1.9.2", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" } }, "sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA=="], - "@emnapi/runtime": ["@emnapi/runtime@1.9.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA=="], + "@emnapi/runtime": ["@emnapi/runtime@1.9.2", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw=="], - "@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg=="], + "@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w=="], "@inquirer/external-editor": ["@inquirer/external-editor@1.0.3", "", { "dependencies": { "chardet": "^2.1.1", "iconv-lite": "^0.7.0" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA=="], @@ -104,7 +104,7 @@ "@manypkg/get-packages": ["@manypkg/get-packages@1.1.3", "", { "dependencies": { "@babel/runtime": "^7.5.5", "@changesets/types": "^4.0.1", "@manypkg/find-root": "^1.1.0", "fs-extra": "^8.1.0", "globby": "^11.0.0", "read-yaml-file": "^1.1.0" } }, "sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A=="], - "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.2", "", { "dependencies": { "@tybys/wasm-util": "^0.10.1" }, "peerDependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1" } }, "sha512-sNXv5oLJ7ob93xkZ1XnxisYhGYXfaG9f65/ZgYuAu3qt7b3NadcOEhLvx28hv31PgX8SZJRYrAIPQilQmFpLVw=="], + "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.4", "", { "dependencies": { "@tybys/wasm-util": "^0.10.1" }, "peerDependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1" } }, "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow=="], "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="], @@ -112,47 +112,47 @@ "@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="], - "@oxc-parser/binding-android-arm-eabi": ["@oxc-parser/binding-android-arm-eabi@0.124.0", "", { "os": "android", "cpu": "arm" }, "sha512-+R9zCafSL8ovjokdPtorUp3sXrh8zQ2AC2L0ivXNvlLR0WS+5WdPkNVrnENq5UvzagM4Xgl0NPsJKz3Hv9+y8g=="], + "@oxc-parser/binding-android-arm-eabi": ["@oxc-parser/binding-android-arm-eabi@0.127.0", "", { "os": "android", "cpu": "arm" }, "sha512-0LC7ye4hvqbIKxAzThzvswgHLFu2AURKzYLeSVvLdu2TBOYWQDmHnTqPLeA597BcUCxiLqLsS4CJ5uoI5WYWCQ=="], - "@oxc-parser/binding-android-arm64": ["@oxc-parser/binding-android-arm64@0.124.0", "", { "os": "android", "cpu": "arm64" }, "sha512-ULHC/gVZ+nP4pd3kNNQTYaQ/e066BW/KuY5qUsvwkVWwOUQGDg+WpfyVOmQ4xfxoue6cMlkKkJ+ntdzfDXpNlg=="], + "@oxc-parser/binding-android-arm64": ["@oxc-parser/binding-android-arm64@0.127.0", "", { "os": "android", "cpu": "arm64" }, "sha512-b5jtVTH6AU5CJXHNdj7Jj9IEiR9yVjjnwHzPJhGyHGPdcsZSzBCkS9GBbV33niRMvKthDwQRFRJfI4a+k4PvYg=="], - "@oxc-parser/binding-darwin-arm64": ["@oxc-parser/binding-darwin-arm64@0.124.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-fGJ2hw7bnbUYn6UvTjp0m4WJ9zXz3cohgcwcgeo7gUZehpPNpvcVEVeIVHNmHnAuAw/ysf4YJR8DA1E+xCA4Lw=="], + "@oxc-parser/binding-darwin-arm64": ["@oxc-parser/binding-darwin-arm64@0.127.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-obCE8B7ISKkJidjlhv9xRGJPOSDG2Yu6PRga9Ruaz35uintHxbp1Ki/Yc71wx4rj3Edrm0a1kzG1TAwit0wFpg=="], - "@oxc-parser/binding-darwin-x64": ["@oxc-parser/binding-darwin-x64@0.124.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-j0+re9pgps5BH2Tk3fm59Hi3QuLP3C4KhqXi6A+wRHHHJWDFR8mc/KI9mBrfk2JRT+15doGo+zv1eN75/9DuOw=="], + "@oxc-parser/binding-darwin-x64": ["@oxc-parser/binding-darwin-x64@0.127.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-JL6Xb5IwPQT8rUzlpsX7E+AgfcdNklXNPFp8pjCQQ5MQOQo5rtEB2ui+3Hgg9Sn7Y9Egj6YOLLiHhLpdAe12Aw=="], - "@oxc-parser/binding-freebsd-x64": ["@oxc-parser/binding-freebsd-x64@0.124.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-0k5mS0npnrhKy72UfF51lpOZ2ESoPWn6gdFw+RdeRWcokraDW1O2kSx3laQ+yk7cCEavQdJSpWCYS/GvBbUCXQ=="], + "@oxc-parser/binding-freebsd-x64": ["@oxc-parser/binding-freebsd-x64@0.127.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-SDQ/3MQFw58fqQz3Z1PhSKFF3JoCF4gmlNjziDm8X02tTahCw0qJbd7FGPDKw1i4VTBZene9JPyC3mHtSvi+wA=="], - "@oxc-parser/binding-linux-arm-gnueabihf": ["@oxc-parser/binding-linux-arm-gnueabihf@0.124.0", "", { "os": "linux", "cpu": "arm" }, "sha512-P/i4eguRWvAUfGdfhQYg1jpwYkyUV6D3gefIH7HhmRl1Ph6P4IqTIEVcyJr1i/3vr1V5OHU4wonH6/ue/Qzvrw=="], + "@oxc-parser/binding-linux-arm-gnueabihf": ["@oxc-parser/binding-linux-arm-gnueabihf@0.127.0", "", { "os": "linux", "cpu": "arm" }, "sha512-Av+D1MIqzV0YMGPT9we2SIZaMKD7Cxs4CvXSx/yxaWHewZjYEjScpOf5igc8IILASViw4WTnjlwUdI1KzVtDHQ=="], - "@oxc-parser/binding-linux-arm-musleabihf": ["@oxc-parser/binding-linux-arm-musleabihf@0.124.0", "", { "os": "linux", "cpu": "arm" }, "sha512-/ameqFQH5fFP+66Atr8Ynv/2rYe4utcU7L4MoWS5JtrFLVO78g4qDLavyIlJxa6caSwYOvG/eO3c/DXqY5/6Rw=="], + "@oxc-parser/binding-linux-arm-musleabihf": ["@oxc-parser/binding-linux-arm-musleabihf@0.127.0", "", { "os": "linux", "cpu": "arm" }, "sha512-Cs2fdJ8cPpFdeebj6p4dag8A4+56hPvZ0AhQQzlaLswGz1tz7bXt1nETLeorrM9+AMcWFFkqxcXwDGfTVidY8g=="], - "@oxc-parser/binding-linux-arm64-gnu": ["@oxc-parser/binding-linux-arm64-gnu@0.124.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-gNeyEcXTtfrRCbj2EfxWU85Fs0wIX3p44Y3twnvuMfkWlLrb9M1Z25AYNSKjJM+fdAjeeQCjw0on47zFuBYwQw=="], + "@oxc-parser/binding-linux-arm64-gnu": ["@oxc-parser/binding-linux-arm64-gnu@0.127.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-qdOfTcT6SY8gsJrrV92uyEUyjqMGPpIB5JZUG6QN5dukYd+7/j0kX6MwK1DgQj39jtUYixxPiaRUiEN1+0CXgQ=="], - "@oxc-parser/binding-linux-arm64-musl": ["@oxc-parser/binding-linux-arm64-musl@0.124.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-uvG7v4Tz9S8/PVqY0SP0DLHxo4hZGe+Pv2tGVnwcsjKCCUPjplbrFVvDzXq+kOaEoUkiCY0Kt1hlZ6FDJ1LKNQ=="], + "@oxc-parser/binding-linux-arm64-musl": ["@oxc-parser/binding-linux-arm64-musl@0.127.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-EoTCZneNFU/P2qrpEM+RHmQwt+CvDkyGESG6qhr7KaegXLZwePfbrkCDfAk8/rhxbDUVGsZILX+2tqPzFtoFWA=="], - "@oxc-parser/binding-linux-ppc64-gnu": ["@oxc-parser/binding-linux-ppc64-gnu@0.124.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-t7KZaaUhfp2au0MRpoENEFqwLKYDdptEry6V7pTAVdPEcFG4P6ii8yeGU9m6p5vb+b8WEKmdpGMNXBEYy7iJdw=="], + "@oxc-parser/binding-linux-ppc64-gnu": ["@oxc-parser/binding-linux-ppc64-gnu@0.127.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-zALjmZYgxFLHjXeudcDF0xFGNydTAtkAeXAr2EuC17ywCyFxcmQra4w0BMde0Yi/re4Bi4iwEoEXtYN7l6eBLQ=="], - "@oxc-parser/binding-linux-riscv64-gnu": ["@oxc-parser/binding-linux-riscv64-gnu@0.124.0", "", { "os": "linux", "cpu": "none" }, "sha512-eurGGaxHZiIQ+fBSageS8TAkRqZgdOiBeqNrWAqAPup9hXBTmQ0WcBjwsLElf+3jvDL9NhnX0dOgOqPfsjSjdg=="], + "@oxc-parser/binding-linux-riscv64-gnu": ["@oxc-parser/binding-linux-riscv64-gnu@0.127.0", "", { "os": "linux", "cpu": "none" }, "sha512-fPP8M6zQLS7Jz7o9d5ArUSuAuSK3e+WCYVrCpdzeCOejidtZExJ9tjhDrAd3HEPqARBCPmdpqxESPFqy44vkBQ=="], - "@oxc-parser/binding-linux-riscv64-musl": ["@oxc-parser/binding-linux-riscv64-musl@0.124.0", "", { "os": "linux", "cpu": "none" }, "sha512-d1V7/ll1i/LhqE/gZy6Wbz6evlk0egh2XKkwMI3epiojtbtUwQSLIER0Y3yDBBocPuWOjJdvmjtEmPTTLXje/w=="], + "@oxc-parser/binding-linux-riscv64-musl": ["@oxc-parser/binding-linux-riscv64-musl@0.127.0", "", { "os": "linux", "cpu": "none" }, "sha512-7IcC4Ao02oGpfnjt+X/oF4U2mllo2qoSkw5xxiXNKL9MCTsTiAC6616beOuehdxGcnz1bRoPC1RQ2f1GQDdN+g=="], - "@oxc-parser/binding-linux-s390x-gnu": ["@oxc-parser/binding-linux-s390x-gnu@0.124.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-w1+cBvriUteOpox6ATqCFVkpGL47PFdcfCPGmgUZbd78Fw44U0gQkc+kVGvAOTvGrptMYgwomD1c6OTVvkrpGg=="], + "@oxc-parser/binding-linux-s390x-gnu": ["@oxc-parser/binding-linux-s390x-gnu@0.127.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-pbXIhiNFHoqWeqDNLiJ9JkpHz1IM9k4DXa66x+1GTWMG7iLxtkXgE53iiuKSXwmk3zIYmaPVfBvgcAhS583K4Q=="], - "@oxc-parser/binding-linux-x64-gnu": ["@oxc-parser/binding-linux-x64-gnu@0.124.0", "", { "os": "linux", "cpu": "x64" }, "sha512-RRB1evQiXRtMCsQQiAh9U0H3HzguLpE0ytfStuhRgmOj7tqUCOVxkHsvM9geZjAax6NqVRj7VXx32qjjkZPsBw=="], + "@oxc-parser/binding-linux-x64-gnu": ["@oxc-parser/binding-linux-x64-gnu@0.127.0", "", { "os": "linux", "cpu": "x64" }, "sha512-MYCguB9RvBvlSd6gbuNI7QwiLoCCAlGnlRJFPrzLI6U1/9wkC/WK6LtBAUln55H1Ctqw45PWmqrobKoMhsYQzQ=="], - "@oxc-parser/binding-linux-x64-musl": ["@oxc-parser/binding-linux-x64-musl@0.124.0", "", { "os": "linux", "cpu": "x64" }, "sha512-asVYN0qmSHlCU8H9Q47SmeJ/Z5EG4IWCC+QGxkfFboI5qh15aLlJnHmnrV61MwQRPXGnVC/sC3qKhrUyqGxUqw=="], + "@oxc-parser/binding-linux-x64-musl": ["@oxc-parser/binding-linux-x64-musl@0.127.0", "", { "os": "linux", "cpu": "x64" }, "sha512-5eY0B/bxf1xIUxb4NOTvOI3KWtBQfPWYyKAzgcrCt0mDibSZygVpO1Pz8bkeiSZ5Jj9+M09dkggG3H8I5d0Uyg=="], - "@oxc-parser/binding-openharmony-arm64": ["@oxc-parser/binding-openharmony-arm64@0.124.0", "", { "os": "none", "cpu": "arm64" }, "sha512-nhwuxm6B8pn9lzAzMUfa571L5hCXYwQo8C8cx5aGOuHWCzruR8gPJnRRXGBci+uGaIIQEZDyU/U6HDgrSp/JlQ=="], + "@oxc-parser/binding-openharmony-arm64": ["@oxc-parser/binding-openharmony-arm64@0.127.0", "", { "os": "none", "cpu": "arm64" }, "sha512-Gld0ajrFTUXNtdw20fVBuTQx66FA75nIVg+//pPfR3sXkuABB4mTBhl3r9JNzrJpgW//qiwxf0nWXUWGJSL3UQ=="], - "@oxc-parser/binding-wasm32-wasi": ["@oxc-parser/binding-wasm32-wasi@0.124.0", "", { "dependencies": { "@napi-rs/wasm-runtime": "^1.1.2" }, "cpu": "none" }, "sha512-LWuq4Dl9tff7n+HjJcqoBjDlVCtruc0shgtdtGM+rTUIE9aFxHA/P+wCYR+aWMjN8m9vNaRME/sKXErmhmeKrA=="], + "@oxc-parser/binding-wasm32-wasi": ["@oxc-parser/binding-wasm32-wasi@0.127.0", "", { "dependencies": { "@emnapi/core": "1.9.2", "@emnapi/runtime": "1.9.2", "@napi-rs/wasm-runtime": "^1.1.4" }, "cpu": "none" }, "sha512-T6KVD7rhLzFlwGRXMnxUFfkCZD8FHnb968wVXW1mXzgRFc5RNXOBY2mPPDZ77x5Ln76ltLMgtPg0cOkU1NSrEQ=="], - "@oxc-parser/binding-win32-arm64-msvc": ["@oxc-parser/binding-win32-arm64-msvc@0.124.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-aOh3Lf3AeH0dgzT4yBXcArFZ8VhqNXwZ/xlN0GqBtgVaGoHOOqL2YHlcVIgT+ghsXPVR2PTtYgBiQ1CNK7jp5A=="], + "@oxc-parser/binding-win32-arm64-msvc": ["@oxc-parser/binding-win32-arm64-msvc@0.127.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-Ujvw4X+LD1CCGULcsQcvb4YNVoBGqt+JHgNNzGGaCImELiZLk477ifUH53gIbE7EKd933NdTi25JWEr9K2HwXw=="], - "@oxc-parser/binding-win32-ia32-msvc": ["@oxc-parser/binding-win32-ia32-msvc@0.124.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-sib5xC0nz/+SCpaETBuHBz4SXS02KuG5HtyOcHsO/SK5ZvLRGhOZx0elDKawjb6adFkD7dQCqpXUS25wY6ELKQ=="], + "@oxc-parser/binding-win32-ia32-msvc": ["@oxc-parser/binding-win32-ia32-msvc@0.127.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-0cwxKO7KHQQQfo4Uf4B2SQrhgm+cJaP9OvFFhx52Tkg4bezsacu83GB2/In5bC415Ueeym+kXdnge/57rbSfTw=="], - "@oxc-parser/binding-win32-x64-msvc": ["@oxc-parser/binding-win32-x64-msvc@0.124.0", "", { "os": "win32", "cpu": "x64" }, "sha512-UgojtjGUgZgAZQYt7SC6VO65OVdxEkRe2q+2vbHJO//18qw3Hrk6UvHGQKldsQKgbVcIBT/YBrt85YberiYIPQ=="], + "@oxc-parser/binding-win32-x64-msvc": ["@oxc-parser/binding-win32-x64-msvc@0.127.0", "", { "os": "win32", "cpu": "x64" }, "sha512-rOrnSQSCbhI2kowr9XxE7m9a8oQXnBHjnS6j95LxxAnEZ0+Fz20WlRXG4ondQb+ejjt2KOsa65sE6++L6kUd+w=="], - "@oxc-project/types": ["@oxc-project/types@0.124.0", "", {}, "sha512-VBFWMTBvHxS11Z5Lvlr3IWgrwhMTXV+Md+EQF0Xf60+wAdsGFTBx7X7K/hP4pi8N7dcm1RvcHwDxZ16Qx8keUg=="], + "@oxc-project/types": ["@oxc-project/types@0.127.0", "", {}, "sha512-aIYXQBo4lCbO4z0R3FHeucQHpF46l2LbMdxRvqvuRuW2OxdnSkcng5B8+K12spgLDj93rtN3+J2Vac/TIO+ciQ=="], "@oxc-resolver/binding-android-arm-eabi": ["@oxc-resolver/binding-android-arm-eabi@11.19.1", "", { "os": "android", "cpu": "arm" }, "sha512-aUs47y+xyXHUKlbhqHUjBABjvycq6YSD7bpxSW7vplUmdzAlJ93yXY6ZR0c1o1x5A/QKbENCvs3+NlY8IpIVzg=="], @@ -194,143 +194,143 @@ "@oxc-resolver/binding-win32-x64-msvc": ["@oxc-resolver/binding-win32-x64-msvc@11.19.1", "", { "os": "win32", "cpu": "x64" }, "sha512-6hIU3RQu45B+VNTY4Ru8ppFwjVS/S5qwYyGhBotmjxfEKk41I2DlGtRfGJndZ5+6lneE2pwloqunlOyZuX/XAw=="], - "@oxfmt/binding-android-arm-eabi": ["@oxfmt/binding-android-arm-eabi@0.44.0", "", { "os": "android", "cpu": "arm" }, "sha512-5UvghMd9SA/yvKTWCAxMAPXS1d2i054UeOf4iFjZjfayTwCINcC3oaSXjtbZfCaEpxgJod7XiOjTtby5yEv/BQ=="], + "@oxfmt/binding-android-arm-eabi": ["@oxfmt/binding-android-arm-eabi@0.46.0", "", { "os": "android", "cpu": "arm" }, "sha512-b1doV4WRcJU+BESSlCvCjV+5CEr/T6h0frArAdV26Nir+gGNFNaylvDiiMPfF1pxeV0txZEs38ojzJaxBYg+ng=="], - "@oxfmt/binding-android-arm64": ["@oxfmt/binding-android-arm64@0.44.0", "", { "os": "android", "cpu": "arm64" }, "sha512-IVudM1BWfvrYO++Khtzr8q9n5Rxu7msUvoFMqzGJVdX7HfUXUDHwaH2zHZNB58svx2J56pmCUzophyaPFkcG/A=="], + "@oxfmt/binding-android-arm64": ["@oxfmt/binding-android-arm64@0.46.0", "", { "os": "android", "cpu": "arm64" }, "sha512-v6+HhjsoV3GO0u2u9jLSAZrvWfTraDxKofUIQ7/ktS7tzS+epVsxdHmeM+XxuNcAY/nWxxU1Sg4JcGTNRXraBA=="], - "@oxfmt/binding-darwin-arm64": ["@oxfmt/binding-darwin-arm64@0.44.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-eWCLAIKAHfx88EqEP1Ga2yz7qVcqDU5lemn4xck+07bH182hDdprOHjbogyk0In1Djys3T0/pO2JepFnRJ41Mg=="], + "@oxfmt/binding-darwin-arm64": ["@oxfmt/binding-darwin-arm64@0.46.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-3eeooJGrqGIlI5MyryDZsAcKXSmKIgAD4yYtfRrRJzXZ0UTFZtiSveIur56YPrGMYZwT4XyVhHsMqrNwr1XeFA=="], - "@oxfmt/binding-darwin-x64": ["@oxfmt/binding-darwin-x64@0.44.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-eHTBznHLM49++dwz07MblQ2cOXyIgeedmE3Wgy4ptUESj38/qYZyRi1MPwC9olQJWssMeY6WI3UZ7YmU5ggvyQ=="], + "@oxfmt/binding-darwin-x64": ["@oxfmt/binding-darwin-x64@0.46.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-QG8BDM0CXWbu84k2SKmCqfEddPQPFiBicwtYnLqHRWZZl57HbtOLRMac/KTq2NO4AEc4ICCBpFxJIV9zcqYfkQ=="], - "@oxfmt/binding-freebsd-x64": ["@oxfmt/binding-freebsd-x64@0.44.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-jLMmbj0u0Ft43QpkUVr/0v1ZfQCGWAvU+WznEHcN3wZC/q6ox7XeSJtk9P36CCpiDSUf3sGnzbIuG1KdEMEDJQ=="], + "@oxfmt/binding-freebsd-x64": ["@oxfmt/binding-freebsd-x64@0.46.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-9DdCqS/n2ncu/Chazvt3cpgAjAmIGQDz7hFKSrNItMApyV/Ja9mz3hD4JakIE3nS8PW9smEbPWnb389QLBY4nw=="], - "@oxfmt/binding-linux-arm-gnueabihf": ["@oxfmt/binding-linux-arm-gnueabihf@0.44.0", "", { "os": "linux", "cpu": "arm" }, "sha512-n+A/u/ByK1qV8FVGOwyaSpw5NPNl0qlZfgTBqHeGIqr8Qzq1tyWZ4lAaxPoe5mZqE3w88vn3+jZtMxriHPE7tg=="], + "@oxfmt/binding-linux-arm-gnueabihf": ["@oxfmt/binding-linux-arm-gnueabihf@0.46.0", "", { "os": "linux", "cpu": "arm" }, "sha512-Dgs7VeE2jT0LHMhw6tPEt0xQYe54kBqHEovmWsv4FVQlegCOvlIJNx0S8n4vj8WUtpT+Z6BD2HhKJPLglLxvZg=="], - "@oxfmt/binding-linux-arm-musleabihf": ["@oxfmt/binding-linux-arm-musleabihf@0.44.0", "", { "os": "linux", "cpu": "arm" }, "sha512-5eax+FkxyCqAi3Rw0mrZFr7+KTt/XweFsbALR+B5ljWBLBl8nHe4ADrUnb1gLEfQCJLl+Ca5FIVD4xEt95AwIw=="], + "@oxfmt/binding-linux-arm-musleabihf": ["@oxfmt/binding-linux-arm-musleabihf@0.46.0", "", { "os": "linux", "cpu": "arm" }, "sha512-Zxn3adhTH13JKnU4xXJj8FeEfF680XjXh3gSShKl57HCMBRde2tUJTgogV/1MSHA80PJEVrDa7r66TLVq3Ia7Q=="], - "@oxfmt/binding-linux-arm64-gnu": ["@oxfmt/binding-linux-arm64-gnu@0.44.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-58l8JaHxSGOmOMOG2CIrNsnkRJAj0YcHQCmvNACniOa/vd1iRHhlPajczegzS5jwMENlqgreyiTR9iNlke8qCw=="], + "@oxfmt/binding-linux-arm64-gnu": ["@oxfmt/binding-linux-arm64-gnu@0.46.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-+TWipjrgVM8D7aIdDD0tlr3teLTTvQTn7QTE5BpT10H1Fj82gfdn9X6nn2sDgx/MepuSCfSnzFNJq2paLL0OiA=="], - "@oxfmt/binding-linux-arm64-musl": ["@oxfmt/binding-linux-arm64-musl@0.44.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-AlObQIXyVRZ96LbtVljtFq0JqH5B92NU+BQeDFrXWBUWlCKAM0wF5GLfIhCLT5kQ3Sl+U0YjRJ7Alqj5hGQaCg=="], + "@oxfmt/binding-linux-arm64-musl": ["@oxfmt/binding-linux-arm64-musl@0.46.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-aAUPBWJ1lGwwnxZUEDLJ94+Iy6MuwJwPxUgO4sCA5mEEyDk7b+cDQ+JpX1VR150Zoyd+D49gsrUzpUK5h587Eg=="], - "@oxfmt/binding-linux-ppc64-gnu": ["@oxfmt/binding-linux-ppc64-gnu@0.44.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-YcFE8/q/BbrCiIiM5piwbkA6GwJc5QqhMQp2yDrqQ2fuVkZ7CInb1aIijZ/k8EXc72qXMSwKpVlBv1w/MsGO/A=="], + "@oxfmt/binding-linux-ppc64-gnu": ["@oxfmt/binding-linux-ppc64-gnu@0.46.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-ufBCJukyFX/UDrokP/r6BGDoTInnsDs7bxyzKAgMiZlt2Qu8GPJSJ6Zm6whIiJzKk0naxA8ilwmbO1LMw6Htxw=="], - "@oxfmt/binding-linux-riscv64-gnu": ["@oxfmt/binding-linux-riscv64-gnu@0.44.0", "", { "os": "linux", "cpu": "none" }, "sha512-eOdzs6RqkRzuqNHUX5C8ISN5xfGh4xDww8OEd9YAmc3OWN8oAe5bmlIqQ+rrHLpv58/0BuU48bxkhnIGjA/ATQ=="], + "@oxfmt/binding-linux-riscv64-gnu": ["@oxfmt/binding-linux-riscv64-gnu@0.46.0", "", { "os": "linux", "cpu": "none" }, "sha512-eqtlC2YmPqjun76R1gVfGLuKWx7NuEnLEAudZ7n6ipSKbCZTqIKSs1b5Y8K/JHZsRpLkeSmAAjig5HOIg8fQzQ=="], - "@oxfmt/binding-linux-riscv64-musl": ["@oxfmt/binding-linux-riscv64-musl@0.44.0", "", { "os": "linux", "cpu": "none" }, "sha512-YBgNTxntD/QvlFUfgvh8bEdwOhXiquX8gaofZJAwYa/Xp1S1DQrFVZEeck7GFktr24DztsSp8N8WtWCBwxs0Hw=="], + "@oxfmt/binding-linux-riscv64-musl": ["@oxfmt/binding-linux-riscv64-musl@0.46.0", "", { "os": "linux", "cpu": "none" }, "sha512-yccVOO2nMXkQLGgy0He3EQEwKD7NF0zEk+/OWmroznkqXyJdN6bfK0LtNnr6/14Bh3FjpYq7bP33l/VloCnxpA=="], - "@oxfmt/binding-linux-s390x-gnu": ["@oxfmt/binding-linux-s390x-gnu@0.44.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-GLIh1R6WHWshl/i4QQDNgj0WtT25aRO4HNUWEoitxiywyRdhTFmFEYT2rXlcl9U6/26vhmOqG5cRlMLG3ocaIA=="], + "@oxfmt/binding-linux-s390x-gnu": ["@oxfmt/binding-linux-s390x-gnu@0.46.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-aAf7fG23OQCey6VRPj9IeCraoYtpgtx0ZyJ1CXkPyT1wjzBE7c3xtuxHe/AdHaJfVVb/SXpSk8Gl1LzyQupSqw=="], - "@oxfmt/binding-linux-x64-gnu": ["@oxfmt/binding-linux-x64-gnu@0.44.0", "", { "os": "linux", "cpu": "x64" }, "sha512-gZOpgTlOsLcLfAF9qgpTr7FIIFSKnQN3hDf/0JvQ4CIwMY7h+eilNjxq/CorqvYcEOu+LRt1W4ZS7KccEHLOdA=="], + "@oxfmt/binding-linux-x64-gnu": ["@oxfmt/binding-linux-x64-gnu@0.46.0", "", { "os": "linux", "cpu": "x64" }, "sha512-q0JPsTMyJNjYrBvYFDz4WbVsafNZaPCZv4RnFypRotLqpKROtBZcEaXQW4eb9YmvLU3NckVemLJnzkSZSdmOxw=="], - "@oxfmt/binding-linux-x64-musl": ["@oxfmt/binding-linux-x64-musl@0.44.0", "", { "os": "linux", "cpu": "x64" }, "sha512-1CyS9JTB+pCUFYFI6pkQGGZaT/AY5gnhHVrQQLhFba6idP9AzVYm1xbdWfywoldTYvjxQJV6x4SuduCIfP3W+A=="], + "@oxfmt/binding-linux-x64-musl": ["@oxfmt/binding-linux-x64-musl@0.46.0", "", { "os": "linux", "cpu": "x64" }, "sha512-7LsLY9Cw57GPkhSR+duI3mt9baRczK/DtHYSldQ4BEU92da9igBQNl4z7Vq5U9NNPsh1FmpKvv1q9WDtiUQR1A=="], - "@oxfmt/binding-openharmony-arm64": ["@oxfmt/binding-openharmony-arm64@0.44.0", "", { "os": "none", "cpu": "arm64" }, "sha512-bmEv70Ak6jLr1xotCbF5TxIKjsmQaiX+jFRtnGtfA03tJPf6VG3cKh96S21boAt3JZc+Vjx8PYcDuLj39vM2Pw=="], + "@oxfmt/binding-openharmony-arm64": ["@oxfmt/binding-openharmony-arm64@0.46.0", "", { "os": "none", "cpu": "arm64" }, "sha512-lHiBOz8Duaku7JtRNLlps3j++eOaICPZSd8FCVmTDM4DFOPT71Bjn7g6iar1z7StXlKRweUKxWUs4sA+zWGDXg=="], - "@oxfmt/binding-win32-arm64-msvc": ["@oxfmt/binding-win32-arm64-msvc@0.44.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-yWzB+oCpSnP/dmw85eFLAT5o35Ve5pkGS2uF/UCISpIwDqf1xa7OpmtomiqY/Vzg8VyvMbuf6vroF2khF/+1Vg=="], + "@oxfmt/binding-win32-arm64-msvc": ["@oxfmt/binding-win32-arm64-msvc@0.46.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-/5ktYUliP89RhgC37DBH1x20U5zPSZMy3cMEcO0j3793rbHP9MWsknBwQB6eozRzWmYrh0IFM/p20EbPvDlYlg=="], - "@oxfmt/binding-win32-ia32-msvc": ["@oxfmt/binding-win32-ia32-msvc@0.44.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-TcWpo18xEIE3AmIG2kpr3kz5IEhQgnx0lazl2+8L+3eTopOAUevQcmlr4nhguImNWz0OMeOZrYZOhJNCf16nlQ=="], + "@oxfmt/binding-win32-ia32-msvc": ["@oxfmt/binding-win32-ia32-msvc@0.46.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-3WTnoiuIr8XvV0DIY7SN+1uJSwKf4sPpcbHfobcRT9JutGcLaef/miyBB87jxd3aqH+mS0+G5lsgHuXLUwjjpQ=="], - "@oxfmt/binding-win32-x64-msvc": ["@oxfmt/binding-win32-x64-msvc@0.44.0", "", { "os": "win32", "cpu": "x64" }, "sha512-oj8aLkPJZppIM4CMQNsyir9ybM1Xw/CfGPTSsTnzpVGyljgfbdP0EVUlURiGM0BDrmw5psQ6ArmGCcUY/yABaQ=="], + "@oxfmt/binding-win32-x64-msvc": ["@oxfmt/binding-win32-x64-msvc@0.46.0", "", { "os": "win32", "cpu": "x64" }, "sha512-IXxiQpkYnOwNfP23vzwSfhdpxJzyiPTY7eTn6dn3DsriKddESzM8i6kfq9R7CD/PUJwCvQT22NgtygBeug3KoA=="], - "@oxlint/binding-android-arm-eabi": ["@oxlint/binding-android-arm-eabi@1.59.0", "", { "os": "android", "cpu": "arm" }, "sha512-etYDw/UaEv936AQUd/CRMBVd+e+XuuU6wC+VzOv1STvsTyZenLChepLWqLtnyTTp4YMlM22ypzogDDwqYxv5cg=="], + "@oxlint/binding-android-arm-eabi": ["@oxlint/binding-android-arm-eabi@1.61.0", "", { "os": "android", "cpu": "arm" }, "sha512-6eZBPgiigK5txqoVgRqxbaxiom4lM8AP8CyKPPvpzKnQ3iFRFOIDc+0AapF+qsUSwjOzr5SGk4SxQDpQhkSJMQ=="], - "@oxlint/binding-android-arm64": ["@oxlint/binding-android-arm64@1.59.0", "", { "os": "android", "cpu": "arm64" }, "sha512-TgLc7XVLKH2a4h8j3vn1MDjfK33i9MY60f/bKhRGWyVzbk5LCZ4X01VZG7iHrMmi5vYbAp8//Ponigx03CLsdw=="], + "@oxlint/binding-android-arm64": ["@oxlint/binding-android-arm64@1.61.0", "", { "os": "android", "cpu": "arm64" }, "sha512-CkwLR69MUnyv5wjzebvbbtTSUwqLxM35CXE79bHqDIK+NtKmPEUpStTcLQRZMCo4MP0qRT6TXIQVpK0ZVScnMA=="], - "@oxlint/binding-darwin-arm64": ["@oxlint/binding-darwin-arm64@1.59.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-DXyFPf5ZKldMLloRHx/B9fsxsiTQomaw7cmEW3YIJko2HgCh+GUhp9gGYwHrqlLJPsEe3dYj9JebjX92D3j3AA=="], + "@oxlint/binding-darwin-arm64": ["@oxlint/binding-darwin-arm64@1.61.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-8JbefTkbmvqkqWjmQrHke+MdpgT2UghhD/ktM4FOQSpGeCgbMToJEKdl9zwhr/YWTl92i4QI1KiTwVExpcUN8A=="], - "@oxlint/binding-darwin-x64": ["@oxlint/binding-darwin-x64@1.59.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-LgvrsdgVLX1qWqIEmNsSmMXJhpAWdtUQ0M+oR0CySwi+9IHWyOGuIL8w8+u/kbZNMyZr4WUyYB5i0+D+AKgkLg=="], + "@oxlint/binding-darwin-x64": ["@oxlint/binding-darwin-x64@1.61.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-uWpoxDT47hTnDLcdEh5jVbso8rlTTu5o0zuqa9J8E0JAKmIWn7kGFEIB03Pycn2hd2vKxybPGLhjURy/9We5FQ=="], - "@oxlint/binding-freebsd-x64": ["@oxlint/binding-freebsd-x64@1.59.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-bOJhqX/ny4hrFuTPlyk8foSRx/vLRpxJh0jOOKN2NWW6FScXHPAA5rQbrwdQPcgGB5V8Ua51RS03fke8ssBcug=="], + "@oxlint/binding-freebsd-x64": ["@oxlint/binding-freebsd-x64@1.61.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-K/o4hEyW7flfMel0iBVznmMBt7VIMHGdjADocHKpK1DUF9erpWnJ+BSSWd2W0c8K3mPtpph+CuHzRU6CI3l9jQ=="], - "@oxlint/binding-linux-arm-gnueabihf": ["@oxlint/binding-linux-arm-gnueabihf@1.59.0", "", { "os": "linux", "cpu": "arm" }, "sha512-vVUXxYMF9trXCsz4m9H6U0IjehosVHxBzVgJUxly1uz4W1PdDyicaBnpC0KRXsHYretLVe+uS9pJy8iM57Kujw=="], + "@oxlint/binding-linux-arm-gnueabihf": ["@oxlint/binding-linux-arm-gnueabihf@1.61.0", "", { "os": "linux", "cpu": "arm" }, "sha512-P6040ZkcyweJ0Po9yEFqJCdvZnf3VNCGs1SIHgXDf8AAQNC6ID/heXQs9iSgo2FH7gKaKq32VWc59XZwL34C5Q=="], - "@oxlint/binding-linux-arm-musleabihf": ["@oxlint/binding-linux-arm-musleabihf@1.59.0", "", { "os": "linux", "cpu": "arm" }, "sha512-TULQW8YBPGRWg5yZpFPL54HLOnJ3/HiX6VenDPi6YfxB/jlItwSMFh3/hCeSNbh+DAMaE1Py0j5MOaivHkI/9Q=="], + "@oxlint/binding-linux-arm-musleabihf": ["@oxlint/binding-linux-arm-musleabihf@1.61.0", "", { "os": "linux", "cpu": "arm" }, "sha512-bwxrGCzTZkuB+THv2TQ1aTkVEfv5oz8sl+0XZZCpoYzErJD8OhPQOTA0ENPd1zJz8QsVdSzSrS2umKtPq4/JXg=="], - "@oxlint/binding-linux-arm64-gnu": ["@oxlint/binding-linux-arm64-gnu@1.59.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-Gt54Y4eqSgYJ90xipm24xeyaPV854706o/kiT8oZvUt3VDY7qqxdqyGqchMaujd87ib+/MXvnl9WkK8Cc1BExg=="], + "@oxlint/binding-linux-arm64-gnu": ["@oxlint/binding-linux-arm64-gnu@1.61.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-vkhb9/wKguMkLlrm3FoJW/Xmdv31GgYAE+x8lxxQ+7HeOxXUySI0q36a3NTVIuQUdLzxCI1zzMGsk1o37FOe3w=="], - "@oxlint/binding-linux-arm64-musl": ["@oxlint/binding-linux-arm64-musl@1.59.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-3CtsKp7NFB3OfqQzbuAecrY7GIZeiv7AD+xutU4tefVQzlfmTI7/ygWLrvkzsDEjTlMq41rYHxgsn6Yh8tybmA=="], + "@oxlint/binding-linux-arm64-musl": ["@oxlint/binding-linux-arm64-musl@1.61.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-bl1dQh8LnVqsj6oOQAcxwbuOmNJkwc4p6o//HTBZhNTzJy21TLDwAviMqUFNUxDHkPGpmdKTSN4tWTjLryP8xg=="], - "@oxlint/binding-linux-ppc64-gnu": ["@oxlint/binding-linux-ppc64-gnu@1.59.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-K0diOpT3ncDmOfl9I1HuvpEsAuTxkts0VYwIv/w6Xiy9CdwyPBVX88Ga9l8VlGgMrwBMnSY4xIvVlVY/fkQk7Q=="], + "@oxlint/binding-linux-ppc64-gnu": ["@oxlint/binding-linux-ppc64-gnu@1.61.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-QoOX6KB2IiEpyOj/HKqaxi+NQHPnOgNgnr22n9N4ANJCzXkUlj1UmeAbFb4PpqdlHIzvGDM5xZ0OKtcLq9RhiQ=="], - "@oxlint/binding-linux-riscv64-gnu": ["@oxlint/binding-linux-riscv64-gnu@1.59.0", "", { "os": "linux", "cpu": "none" }, "sha512-xAU7+QDU6kTJJ7mJLOGgo7oOjtAtkKyFZ0Yjdb5cEo3DiCCPFLvyr08rWiQh6evZ7RiUTf+o65NY/bqttzJiQQ=="], + "@oxlint/binding-linux-riscv64-gnu": ["@oxlint/binding-linux-riscv64-gnu@1.61.0", "", { "os": "linux", "cpu": "none" }, "sha512-1TGcTerjY6p152wCof3oKElccq3xHljS/Mucp04gV/4ATpP6nO7YNnp7opEg6SHkv2a57/b4b8Ndm9znJ1/qAw=="], - "@oxlint/binding-linux-riscv64-musl": ["@oxlint/binding-linux-riscv64-musl@1.59.0", "", { "os": "linux", "cpu": "none" }, "sha512-KUmZmKlTTyauOnvUNVxK7G40sSSx0+w5l1UhaGsC6KPpOYHenx2oqJTnabmpLJicok7IC+3Y6fXAUOMyexaeJQ=="], + "@oxlint/binding-linux-riscv64-musl": ["@oxlint/binding-linux-riscv64-musl@1.61.0", "", { "os": "linux", "cpu": "none" }, "sha512-65wXEmZIrX2ADwC8i/qFL4EWLSbeuBpAm3suuX1vu4IQkKd+wLT/HU/BOl84kp91u2SxPkPDyQgu4yrqp8vwVA=="], - "@oxlint/binding-linux-s390x-gnu": ["@oxlint/binding-linux-s390x-gnu@1.59.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-4usRxC8gS0PGdkHnRmwJt/4zrQNZyk6vL0trCxwZSsAKM+OxhB8nKiR+mhjdBbl8lbMh2gc3bZpNN/ik8c4c2A=="], + "@oxlint/binding-linux-s390x-gnu": ["@oxlint/binding-linux-s390x-gnu@1.61.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-TVvhgMvor7Qa6COeXxCJ7ENOM+lcAOGsQ0iUdPSCv2hxb9qSHLQ4XF1h50S6RE1gBOJ0WV3rNukg4JJJP1LWRA=="], - "@oxlint/binding-linux-x64-gnu": ["@oxlint/binding-linux-x64-gnu@1.59.0", "", { "os": "linux", "cpu": "x64" }, "sha512-s/rNE2gDmbwAOOP493xk2X7M8LZfI1LJFSSW1+yanz3vuQCFPiHkx4GY+O1HuLUDtkzGlhtMrIcxxzyYLv308w=="], + "@oxlint/binding-linux-x64-gnu": ["@oxlint/binding-linux-x64-gnu@1.61.0", "", { "os": "linux", "cpu": "x64" }, "sha512-SjpS5uYuFoDnDdZPwZE59ndF95AsY47R5MliuneTWR1pDm2CxGJaYXbKULI71t5TVfLQUWmrHEGRL9xvuq6dnA=="], - "@oxlint/binding-linux-x64-musl": ["@oxlint/binding-linux-x64-musl@1.59.0", "", { "os": "linux", "cpu": "x64" }, "sha512-+yYj1udJa2UvvIUmEm0IcKgc0UlPMgz0nsSTvkPL2y6n0uU5LgIHSwVu4AHhrve6j9BpVSoRksnz8c9QcvITJA=="], + "@oxlint/binding-linux-x64-musl": ["@oxlint/binding-linux-x64-musl@1.61.0", "", { "os": "linux", "cpu": "x64" }, "sha512-gGfAeGD4sNJGILZbc/yKcIimO9wQnPMoYp9swAaKeEtwsSQAbU+rsdQze5SBtIP6j0QDzeYd4XSSUCRCF+LIeQ=="], - "@oxlint/binding-openharmony-arm64": ["@oxlint/binding-openharmony-arm64@1.59.0", "", { "os": "none", "cpu": "arm64" }, "sha512-bUplUb48LYsB3hHlQXP2ZMOenpieWoOyppLAnnAhuPag3MGPnt+7caxE3w/Vl9wpQsTA3gzLntQi9rxWrs7Xqg=="], + "@oxlint/binding-openharmony-arm64": ["@oxlint/binding-openharmony-arm64@1.61.0", "", { "os": "none", "cpu": "arm64" }, "sha512-OlVT0LrG/ct33EVtWRyR+B/othwmDWeRxfi13wUdPeb3lAT5TgTcFDcfLfarZtzB4W1nWF/zICMgYdkggX2WmQ=="], - "@oxlint/binding-win32-arm64-msvc": ["@oxlint/binding-win32-arm64-msvc@1.59.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-/HLsLuz42rWl7h7ePdmMTpHm2HIDmPtcEMYgm5BBEHiEiuNOrzMaUpd2z7UnNni5LGN9obJy2YoAYBLXQwazrA=="], + "@oxlint/binding-win32-arm64-msvc": ["@oxlint/binding-win32-arm64-msvc@1.61.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-vI//NZPJk6DToiovPtaiwD4iQ7kO1r5ReWQD0sOOyKRtP3E2f6jxin4uvwi3OvDzHA2EFfd7DcZl5dtkQh7g1w=="], - "@oxlint/binding-win32-ia32-msvc": ["@oxlint/binding-win32-ia32-msvc@1.59.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-rUPy+JnanpPwV/aJCPnxAD1fW50+XPI0VkWr7f0vEbqcdsS8NpB24Rw6RsS7SdpFv8Dw+8ugCwao5nCFbqOUSg=="], + "@oxlint/binding-win32-ia32-msvc": ["@oxlint/binding-win32-ia32-msvc@1.61.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-0ySj4/4zd2XjePs3XAQq7IigIstN4LPQZgCyigX5/ERMLjdWAJfnxcTsrtxZxuij8guJW8foXuHmhGxW0H4dDA=="], - "@oxlint/binding-win32-x64-msvc": ["@oxlint/binding-win32-x64-msvc@1.59.0", "", { "os": "win32", "cpu": "x64" }, "sha512-xkE7puteDS/vUyRngLXW0t8WgdWoS/tfxXjhP/P7SMqPDx+hs44SpssO3h3qmTqECYEuXBUPzcAw5257Ka+ofA=="], + "@oxlint/binding-win32-x64-msvc": ["@oxlint/binding-win32-x64-msvc@1.61.0", "", { "os": "win32", "cpu": "x64" }, "sha512-0xgSiyeqDLDZxXoe9CVJrOx3TUVsfyoOY7cNi03JbItNcC9WCZqrSNdrAbHONxhSPaVh/lzfnDcON1RqSUMhHw=="], "@quansync/fs": ["@quansync/fs@1.0.0", "", { "dependencies": { "quansync": "^1.0.0" } }, "sha512-4TJ3DFtlf1L5LDMaM6CanJ/0lckGNtJcMjQ1NAV6zDmA0tEHKZtxNKin8EgPaVX1YzljbxckyT2tJrpQKAtngQ=="], - "@rolldown/binding-android-arm64": ["@rolldown/binding-android-arm64@1.0.0-rc.12", "", { "os": "android", "cpu": "arm64" }, "sha512-pv1y2Fv0JybcykuiiD3qBOBdz6RteYojRFY1d+b95WVuzx211CRh+ytI/+9iVyWQ6koTh5dawe4S/yRfOFjgaA=="], + "@rolldown/binding-android-arm64": ["@rolldown/binding-android-arm64@1.0.0-rc.17", "", { "os": "android", "cpu": "arm64" }, "sha512-s70pVGhw4zqGeFnXWvAzJDlvxhlRollagdCCKRgOsgUOH3N1l0LIxf83AtGzmb5SiVM4Hjl5HyarMRfdfj3DaQ=="], - "@rolldown/binding-darwin-arm64": ["@rolldown/binding-darwin-arm64@1.0.0-rc.12", "", { "os": "darwin", "cpu": "arm64" }, "sha512-cFYr6zTG/3PXXF3pUO+umXxt1wkRK/0AYT8lDwuqvRC+LuKYWSAQAQZjCWDQpAH172ZV6ieYrNnFzVVcnSflAg=="], + "@rolldown/binding-darwin-arm64": ["@rolldown/binding-darwin-arm64@1.0.0-rc.17", "", { "os": "darwin", "cpu": "arm64" }, "sha512-4ksWc9n0mhlZpZ9PMZgTGjeOPRu8MB1Z3Tz0Mo02eWfWCHMW1zN82Qz/pL/rC+yQa+8ZnutMF0JjJe7PjwasYw=="], - "@rolldown/binding-darwin-x64": ["@rolldown/binding-darwin-x64@1.0.0-rc.12", "", { "os": "darwin", "cpu": "x64" }, "sha512-ZCsYknnHzeXYps0lGBz8JrF37GpE9bFVefrlmDrAQhOEi4IOIlcoU1+FwHEtyXGx2VkYAvhu7dyBf75EJQffBw=="], + "@rolldown/binding-darwin-x64": ["@rolldown/binding-darwin-x64@1.0.0-rc.17", "", { "os": "darwin", "cpu": "x64" }, "sha512-SUSDOI6WwUVNcWxd02QEBjLdY1VPHvlEkw6T/8nYG322iYWCTxRb1vzk4E+mWWYehTp7ERibq54LSJGjmouOsw=="], - "@rolldown/binding-freebsd-x64": ["@rolldown/binding-freebsd-x64@1.0.0-rc.12", "", { "os": "freebsd", "cpu": "x64" }, "sha512-dMLeprcVsyJsKolRXyoTH3NL6qtsT0Y2xeuEA8WQJquWFXkEC4bcu1rLZZSnZRMtAqwtrF/Ib9Ddtpa/Gkge9Q=="], + "@rolldown/binding-freebsd-x64": ["@rolldown/binding-freebsd-x64@1.0.0-rc.17", "", { "os": "freebsd", "cpu": "x64" }, "sha512-hwnz3nw9dbJ05EDO/PvcjaaewqqDy7Y1rn1UO81l8iIK1GjenME75dl16ajbvSSMfv66WXSRCYKIqfgq2KCfxw=="], - "@rolldown/binding-linux-arm-gnueabihf": ["@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.12", "", { "os": "linux", "cpu": "arm" }, "sha512-YqWjAgGC/9M1lz3GR1r1rP79nMgo3mQiiA+Hfo+pvKFK1fAJ1bCi0ZQVh8noOqNacuY1qIcfyVfP6HoyBRZ85Q=="], + "@rolldown/binding-linux-arm-gnueabihf": ["@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.17", "", { "os": "linux", "cpu": "arm" }, "sha512-IS+W7epTcwANmFSQFrS1SivEXHtl1JtuQA9wlxrZTcNi6mx+FDOYrakGevvvTwgj2JvWiK8B29/qD9BELZPyXQ=="], - "@rolldown/binding-linux-arm64-gnu": ["@rolldown/binding-linux-arm64-gnu@1.0.0-rc.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-/I5AS4cIroLpslsmzXfwbe5OmWvSsrFuEw3mwvbQ1kDxJ822hFHIx+vsN/TAzNVyepI/j/GSzrtCIwQPeKCLIg=="], + "@rolldown/binding-linux-arm64-gnu": ["@rolldown/binding-linux-arm64-gnu@1.0.0-rc.17", "", { "os": "linux", "cpu": "arm64" }, "sha512-e6usGaHKW5BMNZOymS1UcEYGowQMWcgZ71Z17Sl/h2+ZziNJ1a9n3Zvcz6LdRyIW5572wBCTH/Z+bKuZouGk9Q=="], - "@rolldown/binding-linux-arm64-musl": ["@rolldown/binding-linux-arm64-musl@1.0.0-rc.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-V6/wZztnBqlx5hJQqNWwFdxIKN0m38p8Jas+VoSfgH54HSj9tKTt1dZvG6JRHcjh6D7TvrJPWFGaY9UBVOaWPw=="], + "@rolldown/binding-linux-arm64-musl": ["@rolldown/binding-linux-arm64-musl@1.0.0-rc.17", "", { "os": "linux", "cpu": "arm64" }, "sha512-b/CgbwAJpmrRLp02RPfhbudf5tZnN9nsPWK82znefso832etkem8H7FSZwxrOI9djcdTP7U6YfNhbRnh7djErg=="], - "@rolldown/binding-linux-ppc64-gnu": ["@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.12", "", { "os": "linux", "cpu": "ppc64" }, "sha512-AP3E9BpcUYliZCxa3w5Kwj9OtEVDYK6sVoUzy4vTOJsjPOgdaJZKFmN4oOlX0Wp0RPV2ETfmIra9x1xuayFB7g=="], + "@rolldown/binding-linux-ppc64-gnu": ["@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.17", "", { "os": "linux", "cpu": "ppc64" }, "sha512-4EII1iNGRUN5WwGbF/kOh/EIkoDN9HsupgLQoXfY+D1oyJm7/F4t5PYU5n8SWZgG0FEwakyM8pGgwcBYruGTlA=="], - "@rolldown/binding-linux-s390x-gnu": ["@rolldown/binding-linux-s390x-gnu@1.0.0-rc.12", "", { "os": "linux", "cpu": "s390x" }, "sha512-nWwpvUSPkoFmZo0kQazZYOrT7J5DGOJ/+QHHzjvNlooDZED8oH82Yg67HvehPPLAg5fUff7TfWFHQS8IV1n3og=="], + "@rolldown/binding-linux-s390x-gnu": ["@rolldown/binding-linux-s390x-gnu@1.0.0-rc.17", "", { "os": "linux", "cpu": "s390x" }, "sha512-AH8oq3XqQo4IibpVXvPeLDI5pzkpYn0WiZAfT05kFzoJ6tQNzwRdDYQ45M8I/gslbodRZwW8uxLhbSBbkv96rA=="], - "@rolldown/binding-linux-x64-gnu": ["@rolldown/binding-linux-x64-gnu@1.0.0-rc.12", "", { "os": "linux", "cpu": "x64" }, "sha512-RNrafz5bcwRy+O9e6P8Z/OCAJW/A+qtBczIqVYwTs14pf4iV1/+eKEjdOUta93q2TsT/FI0XYDP3TCky38LMAg=="], + "@rolldown/binding-linux-x64-gnu": ["@rolldown/binding-linux-x64-gnu@1.0.0-rc.17", "", { "os": "linux", "cpu": "x64" }, "sha512-cLnjV3xfo7KslbU41Z7z8BH/E1y5mzUYzAqih1d1MDaIGZRCMqTijqLv76/P7fyHuvUcfGsIpqCdddbxLLK9rA=="], - "@rolldown/binding-linux-x64-musl": ["@rolldown/binding-linux-x64-musl@1.0.0-rc.12", "", { "os": "linux", "cpu": "x64" }, "sha512-Jpw/0iwoKWx3LJ2rc1yjFrj+T7iHZn2JDg1Yny1ma0luviFS4mhAIcd1LFNxK3EYu3DHWCps0ydXQ5i/rrJ2ig=="], + "@rolldown/binding-linux-x64-musl": ["@rolldown/binding-linux-x64-musl@1.0.0-rc.17", "", { "os": "linux", "cpu": "x64" }, "sha512-0phclDw1spsL7dUB37sIARuis2tAgomCJXAHZlpt8PXZ4Ba0dRP1e+66lsRqrfhISeN9bEGNjQs+T/Fbd7oYGw=="], - "@rolldown/binding-openharmony-arm64": ["@rolldown/binding-openharmony-arm64@1.0.0-rc.12", "", { "os": "none", "cpu": "arm64" }, "sha512-vRugONE4yMfVn0+7lUKdKvN4D5YusEiPilaoO2sgUWpCvrncvWgPMzK00ZFFJuiPgLwgFNP5eSiUlv2tfc+lpA=="], + "@rolldown/binding-openharmony-arm64": ["@rolldown/binding-openharmony-arm64@1.0.0-rc.17", "", { "os": "none", "cpu": "arm64" }, "sha512-0ag/hEgXOwgw4t8QyQvUCxvEg+V0KBcA6YuOx9g0r02MprutRF5dyljgm3EmR02O292UX7UeS6HzWHAl6KgyhA=="], - "@rolldown/binding-wasm32-wasi": ["@rolldown/binding-wasm32-wasi@1.0.0-rc.12", "", { "dependencies": { "@napi-rs/wasm-runtime": "^1.1.1" }, "cpu": "none" }, "sha512-ykGiLr/6kkiHc0XnBfmFJuCjr5ZYKKofkx+chJWDjitX+KsJuAmrzWhwyOMSHzPhzOHOy7u9HlFoa5MoAOJ/Zg=="], + "@rolldown/binding-wasm32-wasi": ["@rolldown/binding-wasm32-wasi@1.0.0-rc.17", "", { "dependencies": { "@emnapi/core": "1.10.0", "@emnapi/runtime": "1.10.0", "@napi-rs/wasm-runtime": "^1.1.4" }, "cpu": "none" }, "sha512-LEXei6vo0E5wTGwpkJ4KoT3OZJRnglwldt5ziLzOlc6qqb55z4tWNq2A+PFqCJuvWWdP53CVhG1Z9NtToDPJrA=="], - "@rolldown/binding-win32-arm64-msvc": ["@rolldown/binding-win32-arm64-msvc@1.0.0-rc.12", "", { "os": "win32", "cpu": "arm64" }, "sha512-5eOND4duWkwx1AzCxadcOrNeighiLwMInEADT0YM7xeEOOFcovWZCq8dadXgcRHSf3Ulh1kFo/qvzoFiCLOL1Q=="], + "@rolldown/binding-win32-arm64-msvc": ["@rolldown/binding-win32-arm64-msvc@1.0.0-rc.17", "", { "os": "win32", "cpu": "arm64" }, "sha512-gUmyzBl3SPMa6hrqFUth9sVfcLBlYsbMzBx5PlexMroZStgzGqlZ26pYG89rBb45Mnia+oil6YAIFeEWGWhoZA=="], - "@rolldown/binding-win32-x64-msvc": ["@rolldown/binding-win32-x64-msvc@1.0.0-rc.12", "", { "os": "win32", "cpu": "x64" }, "sha512-PyqoipaswDLAZtot351MLhrlrh6lcZPo2LSYE+VDxbVk24LVKAGOuE4hb8xZQmrPAuEtTZW8E6D2zc5EUZX4Lw=="], + "@rolldown/binding-win32-x64-msvc": ["@rolldown/binding-win32-x64-msvc@1.0.0-rc.17", "", { "os": "win32", "cpu": "x64" }, "sha512-3hkiolcUAvPB9FLb3UZdfjVVNWherN1f/skkGWJP/fgSQhYUZpSIRr0/I8ZK9TkF3F7kxvJAk0+IcKvPHk9qQg=="], - "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-rc.12", "", {}, "sha512-HHMwmarRKvoFsJorqYlFeFRzXZqCt2ETQlEDOb9aqssrnVBB1/+xgTGtuTrIk5vzLNX1MjMtTf7W9z3tsSbrxw=="], + "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-rc.17", "", {}, "sha512-n8iosDOt6Ig1UhJ2AYqoIhHWh/isz0xpicHTzpKBeotdVsTEcxsSA/i3EVM7gQAj0rU27OLAxCjzlj15IWY7bg=="], "@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], "@types/better-sqlite3": ["@types/better-sqlite3@7.6.13", "", { "dependencies": { "@types/node": "*" } }, "sha512-NMv9ASNARoKksWtsq/SHakpYAYnhBrQgGD8zkLYk/jaK8jUGn08CfEdTRgYhMypUQAfzSP8W6gNLe0q19/t4VA=="], - "@types/bun": ["@types/bun@1.3.11", "", { "dependencies": { "bun-types": "1.3.11" } }, "sha512-5vPne5QvtpjGpsGYXiFyycfpDF2ECyPcTSsFBMa0fraoxiQyMJ3SmuQIGhzPg2WJuWxVBoxWJ2kClYTcw/4fAg=="], + "@types/bun": ["@types/bun@1.3.13", "", { "dependencies": { "bun-types": "1.3.13" } }, "sha512-9fqXWk5YIHGGnUau9TEi+qdlTYDAnOj+xLCmSTwXfAIqXr2x4tytJb43E9uCvt09zJURKXwAtkoH4nLQfzeTXw=="], "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], "@types/jsesc": ["@types/jsesc@2.5.1", "", {}, "sha512-9VN+6yxLOPLOav+7PwjZbxiID2bVaeq0ED4qSQmdQTdjnXJSaCVKTR58t15oqH1H5t8Ng2ZX1SabJVoN9Q34bw=="], - "@types/node": ["@types/node@25.5.2", "", { "dependencies": { "undici-types": "~7.18.0" } }, "sha512-tO4ZIRKNC+MDWV4qKVZe3Ql/woTnmHDr5JD8UI5hn2pwBrHEwOEMZK7WlNb5RKB6EoJ02gwmQS9OrjuFnZYdpg=="], + "@types/node": ["@types/node@25.6.0", "", { "dependencies": { "undici-types": "~7.19.0" } }, "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ=="], - "@typescript/native-preview": ["@typescript/native-preview@7.0.0-dev.20260407.1", "", { "optionalDependencies": { "@typescript/native-preview-darwin-arm64": "7.0.0-dev.20260407.1", "@typescript/native-preview-darwin-x64": "7.0.0-dev.20260407.1", "@typescript/native-preview-linux-arm": "7.0.0-dev.20260407.1", "@typescript/native-preview-linux-arm64": "7.0.0-dev.20260407.1", "@typescript/native-preview-linux-x64": "7.0.0-dev.20260407.1", "@typescript/native-preview-win32-arm64": "7.0.0-dev.20260407.1", "@typescript/native-preview-win32-x64": "7.0.0-dev.20260407.1" }, "bin": { "tsgo": "bin/tsgo.js" } }, "sha512-gf1W3UbzVTDkZJuwhNtOcfQ6l3hpDcxuWh90ANlp/cKupmAqaXNGpT23YjTYqXsaI7RDQR7JUELCKeWbW9PJIg=="], + "@typescript/native-preview": ["@typescript/native-preview@7.0.0-dev.20260427.1", "", { "optionalDependencies": { "@typescript/native-preview-darwin-arm64": "7.0.0-dev.20260427.1", "@typescript/native-preview-darwin-x64": "7.0.0-dev.20260427.1", "@typescript/native-preview-linux-arm": "7.0.0-dev.20260427.1", "@typescript/native-preview-linux-arm64": "7.0.0-dev.20260427.1", "@typescript/native-preview-linux-x64": "7.0.0-dev.20260427.1", "@typescript/native-preview-win32-arm64": "7.0.0-dev.20260427.1", "@typescript/native-preview-win32-x64": "7.0.0-dev.20260427.1" }, "bin": { "tsgo": "bin/tsgo.js" } }, "sha512-g6L7hed1Y2OGwAzZ+vXoGSvtJUdWUtTqtsn/16+UjYbu3+6pol0cggdWj26SFxI41R+jLfnT2+JGtoXRBdH+RQ=="], - "@typescript/native-preview-darwin-arm64": ["@typescript/native-preview-darwin-arm64@7.0.0-dev.20260407.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-akoBfxvDbULMWLqHPDBI5sRkhjQ0blX5+iG7GBoSstqJZW4P0nzd516COGs7xWHsu3apBhaBgSTMCFO78kG80w=="], + "@typescript/native-preview-darwin-arm64": ["@typescript/native-preview-darwin-arm64@7.0.0-dev.20260427.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-8zxaaEgIpHSadCoCAvUsp0C6WDH0dUXix7Mm7IBjh+EhSxI2clhXwPZTqgtDqbowXHeE82BG5mBbQx+CXDwGOQ=="], - "@typescript/native-preview-darwin-x64": ["@typescript/native-preview-darwin-x64@7.0.0-dev.20260407.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-j/V5BS+tgcRFGQC+y95vZB78fI45UgobAEY1+NlFZ3Yih9ICKWRfJPcalpiP5vjiO2NgqVzcFfO9XbpJyq5TTA=="], + "@typescript/native-preview-darwin-x64": ["@typescript/native-preview-darwin-x64@7.0.0-dev.20260427.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-6MjekGfajPtny/bBoBYJ+8dTOlgw6nhSSgJ3Us4R/4L8R90ll803Krz+iz907r1SnYeK5eWubDMV/p1ryLNXkQ=="], - "@typescript/native-preview-linux-arm": ["@typescript/native-preview-linux-arm@7.0.0-dev.20260407.1", "", { "os": "linux", "cpu": "arm" }, "sha512-ZDr+zQFSTPmLIGyXDWixYFeFtktWUDGAD6s65rTI5EJgyt4X5/kEMnNd04mf4PbN0ChSiTRzJYLzaM+JGo+jww=="], + "@typescript/native-preview-linux-arm": ["@typescript/native-preview-linux-arm@7.0.0-dev.20260427.1", "", { "os": "linux", "cpu": "arm" }, "sha512-3bhv/NxU9FHIN3MSmoplIAkIHF62mlF9l5XooAFawwj8yscvPZih/m5fkYIiP5qGri3828XwGyT1Cksaft6FWQ=="], - "@typescript/native-preview-linux-arm64": ["@typescript/native-preview-linux-arm64@7.0.0-dev.20260407.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-QG0E0lmcZQZimvNltxyi5Q3Oz1pd0BdztS7K5T9HTs30E3TSeYHq7Csw3SbDfAVwcqs2HTe/AVqLy6ar+1zm3Q=="], + "@typescript/native-preview-linux-arm64": ["@typescript/native-preview-linux-arm64@7.0.0-dev.20260427.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-a1yG/vrLaN3dORvaMuNqXz5jcTaTEPBfhmq77vzqRn8As7EdqxtizPosfxB9K1s7PEB8NeGQKqHEQroPUCsPFg=="], - "@typescript/native-preview-linux-x64": ["@typescript/native-preview-linux-x64@7.0.0-dev.20260407.1", "", { "os": "linux", "cpu": "x64" }, "sha512-a82yGx039yqZBS0dwKG8+kgeF2xVA7Pg6lL2SrswbaxWz3bXpI0ASX3HgUw+JMSIr4fbZ5ulKcaorPqbhc48/A=="], + "@typescript/native-preview-linux-x64": ["@typescript/native-preview-linux-x64@7.0.0-dev.20260427.1", "", { "os": "linux", "cpu": "x64" }, "sha512-lqaA9oF9ZSw1jn87+Ncxo0Sf0d65eVXMjAD0z44ne7QKFRgWd+QpvK4AXAG4lxnFR+XdndWlVm6O1/tdvcG7xQ=="], - "@typescript/native-preview-win32-arm64": ["@typescript/native-preview-win32-arm64@7.0.0-dev.20260407.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-e38ow5yqBrdiz4GunQCRk1E7cTtowpbXeAvVJf1wXrWbFqEc0D8BE7YPmTy9W2fOI0KFHUrsFg5h4Ad/TKVjug=="], + "@typescript/native-preview-win32-arm64": ["@typescript/native-preview-win32-arm64@7.0.0-dev.20260427.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-ZGXRDC0WPVK/Ky2fZRhy2EcNmdHg22biVYWcWgOUK5tCbJd/KJs3VXk758gn0UbFHEQAR5d7dsvDucCCjZkWpA=="], - "@typescript/native-preview-win32-x64": ["@typescript/native-preview-win32-x64@7.0.0-dev.20260407.1", "", { "os": "win32", "cpu": "x64" }, "sha512-1Jiij5NQOvlM72/DdfXzAVia1pdffgHiVgWZVmDwXECpzwQB0WwWfhI/0IddXP92Y9gVQFCGo9lypSAnamfGPA=="], + "@typescript/native-preview-win32-x64": ["@typescript/native-preview-win32-x64@7.0.0-dev.20260427.1", "", { "os": "win32", "cpu": "x64" }, "sha512-Ut4Hncq1IuSeNIfcPs1s719j8H3ZA+ogsJ53W3s/Wy1UF5BIhu5Hkspdc7TzGgJgYqGJKo/+pr4vsRnbBPdWgQ=="], "ansi-colors": ["ansi-colors@4.1.3", "", {}, "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw=="], @@ -352,7 +352,7 @@ "better-path-resolve": ["better-path-resolve@1.0.0", "", { "dependencies": { "is-windows": "^1.0.0" } }, "sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g=="], - "better-sqlite3": ["better-sqlite3@12.8.0", "", { "dependencies": { "bindings": "^1.5.0", "prebuild-install": "^7.1.1" } }, "sha512-RxD2Vd96sQDjQr20kdP+F+dK/1OUNiVOl200vKBZY8u0vTwysfolF6Hq+3ZK2+h8My9YvZhHsF+RSGZW2VYrPQ=="], + "better-sqlite3": ["better-sqlite3@12.9.0", "", { "dependencies": { "bindings": "^1.5.0", "prebuild-install": "^7.1.1" } }, "sha512-wqUv4Gm3toFpHDQmaKD4QhZm3g1DjUBI0yzS4UBl6lElUmXFYdTQmmEDpAFa5o8FiFiymURypEnfVHzILKaxqQ=="], "bindings": ["bindings@1.5.0", "", { "dependencies": { "file-uri-to-path": "1.0.0" } }, "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ=="], @@ -364,7 +364,7 @@ "buffer": ["buffer@5.7.1", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="], - "bun-types": ["bun-types@1.3.11", "", { "dependencies": { "@types/node": "*" } }, "sha512-1KGPpoxQWl9f6wcZh57LvrPIInQMn2TQ7jsgxqpRzg+l0QPOFvJVH7HmvHo/AiPgwXy+/Thf6Ov3EdVn1vOabg=="], + "bun-types": ["bun-types@1.3.13", "", { "dependencies": { "@types/node": "*" } }, "sha512-QXKeHLlOLqQX9LgYaHJfzdBaV21T63HhFJnvuRCcjZiaUDpbs5ED1MgxbMra71CsryN/1dAoXuJJJwIv/2drVA=="], "cac": ["cac@7.0.0", "", {}, "sha512-tixWYgm5ZoOD+3g6UTea91eow5z6AAHaho3g0V9CNSNb45gM8SmflpAc+GRd1InC4AqN/07Unrgp56Y94N9hJQ=="], @@ -388,7 +388,7 @@ "deep-extend": ["deep-extend@0.6.0", "", {}, "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="], - "defu": ["defu@6.1.6", "", {}, "sha512-f8mefEW4WIVg4LckePx3mALjQSPQgFlg9U8yaPdlsbdYcHQyj9n2zL2LJEA52smeYxOvmd/nB7TpMtHGMTHcug=="], + "defu": ["defu@6.1.7", "", {}, "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ=="], "detect-indent": ["detect-indent@6.1.0", "", {}, "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA=="], @@ -454,7 +454,7 @@ "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], - "hookable": ["hookable@6.1.0", "", {}, "sha512-ZoKZSJgu8voGK2geJS+6YtYjvIzu9AOM/KZXsBxr83uhLL++e9pEv/dlgwgy3dvHg06kTz6JOh1hk3C8Ceiymw=="], + "hookable": ["hookable@6.1.1", "", {}, "sha512-U9LYDy1CwhMCnprUfeAZWZGByVbhd54hwepegYTK7Pi5NvqEj63ifz5z+xukznehT7i6NIZRu89Ay1AZmRsLEQ=="], "human-id": ["human-id@4.1.3", "", { "bin": { "human-id": "dist/cli.js" } }, "sha512-tsYlhAYpjCKa//8rXZ9DqKEawhPoSytweBC2eNvcaDK+57RZLHGqNs3PZTQO6yekLFSuvA6AlnAfrw1uBvtb+Q=="], @@ -466,7 +466,7 @@ "ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], - "import-without-cache": ["import-without-cache@0.2.5", "", {}, "sha512-B6Lc2s6yApwnD2/pMzFh/d5AVjdsDXjgkeJ766FmFuJELIGHNycKRj+l3A39yZPM4CchqNCB4RITEAYB1KUM6A=="], + "import-without-cache": ["import-without-cache@0.3.3", "", {}, "sha512-bDxwDdF04gm550DfZHgffvlX+9kUlcz32UD0AeBTmVPFiWkrexF2XVmiuFFbDhiFuP8fQkrkvI2KdSNPYWAXkQ=="], "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], @@ -554,13 +554,13 @@ "outdent": ["outdent@0.5.0", "", {}, "sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q=="], - "oxc-parser": ["oxc-parser@0.124.0", "", { "dependencies": { "@oxc-project/types": "^0.124.0" }, "optionalDependencies": { "@oxc-parser/binding-android-arm-eabi": "0.124.0", "@oxc-parser/binding-android-arm64": "0.124.0", "@oxc-parser/binding-darwin-arm64": "0.124.0", "@oxc-parser/binding-darwin-x64": "0.124.0", "@oxc-parser/binding-freebsd-x64": "0.124.0", "@oxc-parser/binding-linux-arm-gnueabihf": "0.124.0", "@oxc-parser/binding-linux-arm-musleabihf": "0.124.0", "@oxc-parser/binding-linux-arm64-gnu": "0.124.0", "@oxc-parser/binding-linux-arm64-musl": "0.124.0", "@oxc-parser/binding-linux-ppc64-gnu": "0.124.0", "@oxc-parser/binding-linux-riscv64-gnu": "0.124.0", "@oxc-parser/binding-linux-riscv64-musl": "0.124.0", "@oxc-parser/binding-linux-s390x-gnu": "0.124.0", "@oxc-parser/binding-linux-x64-gnu": "0.124.0", "@oxc-parser/binding-linux-x64-musl": "0.124.0", "@oxc-parser/binding-openharmony-arm64": "0.124.0", "@oxc-parser/binding-wasm32-wasi": "0.124.0", "@oxc-parser/binding-win32-arm64-msvc": "0.124.0", "@oxc-parser/binding-win32-ia32-msvc": "0.124.0", "@oxc-parser/binding-win32-x64-msvc": "0.124.0" } }, "sha512-h07SFj/tp2U3cf3+LFX6MmOguQiM9ahwpGs0ZK5CGhgL8p4kk24etrJKsEzhXAvo7mfvoKTZooZ5MLKAPRmJ1g=="], + "oxc-parser": ["oxc-parser@0.127.0", "", { "dependencies": { "@oxc-project/types": "^0.127.0" }, "optionalDependencies": { "@oxc-parser/binding-android-arm-eabi": "0.127.0", "@oxc-parser/binding-android-arm64": "0.127.0", "@oxc-parser/binding-darwin-arm64": "0.127.0", "@oxc-parser/binding-darwin-x64": "0.127.0", "@oxc-parser/binding-freebsd-x64": "0.127.0", "@oxc-parser/binding-linux-arm-gnueabihf": "0.127.0", "@oxc-parser/binding-linux-arm-musleabihf": "0.127.0", "@oxc-parser/binding-linux-arm64-gnu": "0.127.0", "@oxc-parser/binding-linux-arm64-musl": "0.127.0", "@oxc-parser/binding-linux-ppc64-gnu": "0.127.0", "@oxc-parser/binding-linux-riscv64-gnu": "0.127.0", "@oxc-parser/binding-linux-riscv64-musl": "0.127.0", "@oxc-parser/binding-linux-s390x-gnu": "0.127.0", "@oxc-parser/binding-linux-x64-gnu": "0.127.0", "@oxc-parser/binding-linux-x64-musl": "0.127.0", "@oxc-parser/binding-openharmony-arm64": "0.127.0", "@oxc-parser/binding-wasm32-wasi": "0.127.0", "@oxc-parser/binding-win32-arm64-msvc": "0.127.0", "@oxc-parser/binding-win32-ia32-msvc": "0.127.0", "@oxc-parser/binding-win32-x64-msvc": "0.127.0" } }, "sha512-bkgD4qHlN7WxLdX8bLXdaU54TtQtAIg/ZBAfm0aje/mo3MRDo3P0hZSgr4U7O3xfX+fQmR5AP04JS/TGcZLcFA=="], "oxc-resolver": ["oxc-resolver@11.19.1", "", { "optionalDependencies": { "@oxc-resolver/binding-android-arm-eabi": "11.19.1", "@oxc-resolver/binding-android-arm64": "11.19.1", "@oxc-resolver/binding-darwin-arm64": "11.19.1", "@oxc-resolver/binding-darwin-x64": "11.19.1", "@oxc-resolver/binding-freebsd-x64": "11.19.1", "@oxc-resolver/binding-linux-arm-gnueabihf": "11.19.1", "@oxc-resolver/binding-linux-arm-musleabihf": "11.19.1", "@oxc-resolver/binding-linux-arm64-gnu": "11.19.1", "@oxc-resolver/binding-linux-arm64-musl": "11.19.1", "@oxc-resolver/binding-linux-ppc64-gnu": "11.19.1", "@oxc-resolver/binding-linux-riscv64-gnu": "11.19.1", "@oxc-resolver/binding-linux-riscv64-musl": "11.19.1", "@oxc-resolver/binding-linux-s390x-gnu": "11.19.1", "@oxc-resolver/binding-linux-x64-gnu": "11.19.1", "@oxc-resolver/binding-linux-x64-musl": "11.19.1", "@oxc-resolver/binding-openharmony-arm64": "11.19.1", "@oxc-resolver/binding-wasm32-wasi": "11.19.1", "@oxc-resolver/binding-win32-arm64-msvc": "11.19.1", "@oxc-resolver/binding-win32-ia32-msvc": "11.19.1", "@oxc-resolver/binding-win32-x64-msvc": "11.19.1" } }, "sha512-qE/CIg/spwrTBFt5aKmwe3ifeDdLfA2NESN30E42X/lII5ClF8V7Wt6WIJhcGZjp0/Q+nQ+9vgxGk//xZNX2hg=="], - "oxfmt": ["oxfmt@0.44.0", "", { "dependencies": { "tinypool": "2.1.0" }, "optionalDependencies": { "@oxfmt/binding-android-arm-eabi": "0.44.0", "@oxfmt/binding-android-arm64": "0.44.0", "@oxfmt/binding-darwin-arm64": "0.44.0", "@oxfmt/binding-darwin-x64": "0.44.0", "@oxfmt/binding-freebsd-x64": "0.44.0", "@oxfmt/binding-linux-arm-gnueabihf": "0.44.0", "@oxfmt/binding-linux-arm-musleabihf": "0.44.0", "@oxfmt/binding-linux-arm64-gnu": "0.44.0", "@oxfmt/binding-linux-arm64-musl": "0.44.0", "@oxfmt/binding-linux-ppc64-gnu": "0.44.0", "@oxfmt/binding-linux-riscv64-gnu": "0.44.0", "@oxfmt/binding-linux-riscv64-musl": "0.44.0", "@oxfmt/binding-linux-s390x-gnu": "0.44.0", "@oxfmt/binding-linux-x64-gnu": "0.44.0", "@oxfmt/binding-linux-x64-musl": "0.44.0", "@oxfmt/binding-openharmony-arm64": "0.44.0", "@oxfmt/binding-win32-arm64-msvc": "0.44.0", "@oxfmt/binding-win32-ia32-msvc": "0.44.0", "@oxfmt/binding-win32-x64-msvc": "0.44.0" }, "bin": { "oxfmt": "bin/oxfmt" } }, "sha512-lnncqvHewyRvaqdrnntVIrZV2tEddz8lbvPsQzG/zlkfvgZkwy0HP1p/2u1aCDToeg1jb9zBpbJdfkV73Itw+w=="], + "oxfmt": ["oxfmt@0.46.0", "", { "dependencies": { "tinypool": "2.1.0" }, "optionalDependencies": { "@oxfmt/binding-android-arm-eabi": "0.46.0", "@oxfmt/binding-android-arm64": "0.46.0", "@oxfmt/binding-darwin-arm64": "0.46.0", "@oxfmt/binding-darwin-x64": "0.46.0", "@oxfmt/binding-freebsd-x64": "0.46.0", "@oxfmt/binding-linux-arm-gnueabihf": "0.46.0", "@oxfmt/binding-linux-arm-musleabihf": "0.46.0", "@oxfmt/binding-linux-arm64-gnu": "0.46.0", "@oxfmt/binding-linux-arm64-musl": "0.46.0", "@oxfmt/binding-linux-ppc64-gnu": "0.46.0", "@oxfmt/binding-linux-riscv64-gnu": "0.46.0", "@oxfmt/binding-linux-riscv64-musl": "0.46.0", "@oxfmt/binding-linux-s390x-gnu": "0.46.0", "@oxfmt/binding-linux-x64-gnu": "0.46.0", "@oxfmt/binding-linux-x64-musl": "0.46.0", "@oxfmt/binding-openharmony-arm64": "0.46.0", "@oxfmt/binding-win32-arm64-msvc": "0.46.0", "@oxfmt/binding-win32-ia32-msvc": "0.46.0", "@oxfmt/binding-win32-x64-msvc": "0.46.0" }, "bin": { "oxfmt": "bin/oxfmt" } }, "sha512-CopwJOwPAjZ9p76fCvz+mSOJTw9/NY3cSksZK3VO/bUQ8UoEcketNgUuYS0UB3p+R9XnXe7wGGXUmyFxc7QxJA=="], - "oxlint": ["oxlint@1.59.0", "", { "optionalDependencies": { "@oxlint/binding-android-arm-eabi": "1.59.0", "@oxlint/binding-android-arm64": "1.59.0", "@oxlint/binding-darwin-arm64": "1.59.0", "@oxlint/binding-darwin-x64": "1.59.0", "@oxlint/binding-freebsd-x64": "1.59.0", "@oxlint/binding-linux-arm-gnueabihf": "1.59.0", "@oxlint/binding-linux-arm-musleabihf": "1.59.0", "@oxlint/binding-linux-arm64-gnu": "1.59.0", "@oxlint/binding-linux-arm64-musl": "1.59.0", "@oxlint/binding-linux-ppc64-gnu": "1.59.0", "@oxlint/binding-linux-riscv64-gnu": "1.59.0", "@oxlint/binding-linux-riscv64-musl": "1.59.0", "@oxlint/binding-linux-s390x-gnu": "1.59.0", "@oxlint/binding-linux-x64-gnu": "1.59.0", "@oxlint/binding-linux-x64-musl": "1.59.0", "@oxlint/binding-openharmony-arm64": "1.59.0", "@oxlint/binding-win32-arm64-msvc": "1.59.0", "@oxlint/binding-win32-ia32-msvc": "1.59.0", "@oxlint/binding-win32-x64-msvc": "1.59.0" }, "peerDependencies": { "oxlint-tsgolint": ">=0.18.0" }, "optionalPeers": ["oxlint-tsgolint"], "bin": { "oxlint": "bin/oxlint" } }, "sha512-0xBLeGGjP4vD9pygRo8iuOkOzEU1MqOnfiOl7KYezL/QvWL8NUg6n03zXc7ZVqltiOpUxBk2zgHI3PnRIEdAvw=="], + "oxlint": ["oxlint@1.61.0", "", { "optionalDependencies": { "@oxlint/binding-android-arm-eabi": "1.61.0", "@oxlint/binding-android-arm64": "1.61.0", "@oxlint/binding-darwin-arm64": "1.61.0", "@oxlint/binding-darwin-x64": "1.61.0", "@oxlint/binding-freebsd-x64": "1.61.0", "@oxlint/binding-linux-arm-gnueabihf": "1.61.0", "@oxlint/binding-linux-arm-musleabihf": "1.61.0", "@oxlint/binding-linux-arm64-gnu": "1.61.0", "@oxlint/binding-linux-arm64-musl": "1.61.0", "@oxlint/binding-linux-ppc64-gnu": "1.61.0", "@oxlint/binding-linux-riscv64-gnu": "1.61.0", "@oxlint/binding-linux-riscv64-musl": "1.61.0", "@oxlint/binding-linux-s390x-gnu": "1.61.0", "@oxlint/binding-linux-x64-gnu": "1.61.0", "@oxlint/binding-linux-x64-musl": "1.61.0", "@oxlint/binding-openharmony-arm64": "1.61.0", "@oxlint/binding-win32-arm64-msvc": "1.61.0", "@oxlint/binding-win32-ia32-msvc": "1.61.0", "@oxlint/binding-win32-x64-msvc": "1.61.0" }, "peerDependencies": { "oxlint-tsgolint": ">=0.18.0" }, "optionalPeers": ["oxlint-tsgolint"], "bin": { "oxlint": "bin/oxlint" } }, "sha512-ZC0ALuhDZ6ivOFG+sy0D0pEDN49EvsId98zVlmYdkcXHsEM14m/qTNUEsUpiFiCVbpIxYtVBmmLE87nsbUHohQ=="], "p-filter": ["p-filter@2.1.0", "", { "dependencies": { "p-map": "^2.0.0" } }, "sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw=="], @@ -614,7 +614,7 @@ "rfdc": ["rfdc@1.4.1", "", {}, "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA=="], - "rolldown": ["rolldown@1.0.0-rc.12", "", { "dependencies": { "@oxc-project/types": "=0.122.0", "@rolldown/pluginutils": "1.0.0-rc.12" }, "optionalDependencies": { "@rolldown/binding-android-arm64": "1.0.0-rc.12", "@rolldown/binding-darwin-arm64": "1.0.0-rc.12", "@rolldown/binding-darwin-x64": "1.0.0-rc.12", "@rolldown/binding-freebsd-x64": "1.0.0-rc.12", "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.12", "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.12", "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.12", "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.12", "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.12", "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.12", "@rolldown/binding-linux-x64-musl": "1.0.0-rc.12", "@rolldown/binding-openharmony-arm64": "1.0.0-rc.12", "@rolldown/binding-wasm32-wasi": "1.0.0-rc.12", "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.12", "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.12" }, "bin": { "rolldown": "bin/cli.mjs" } }, "sha512-yP4USLIMYrwpPHEFB5JGH1uxhcslv6/hL0OyvTuY+3qlOSJvZ7ntYnoWpehBxufkgN0cvXxppuTu5hHa/zPh+A=="], + "rolldown": ["rolldown@1.0.0-rc.17", "", { "dependencies": { "@oxc-project/types": "=0.127.0", "@rolldown/pluginutils": "1.0.0-rc.17" }, "optionalDependencies": { "@rolldown/binding-android-arm64": "1.0.0-rc.17", "@rolldown/binding-darwin-arm64": "1.0.0-rc.17", "@rolldown/binding-darwin-x64": "1.0.0-rc.17", "@rolldown/binding-freebsd-x64": "1.0.0-rc.17", "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.17", "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.17", "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.17", "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.17", "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.17", "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.17", "@rolldown/binding-linux-x64-musl": "1.0.0-rc.17", "@rolldown/binding-openharmony-arm64": "1.0.0-rc.17", "@rolldown/binding-wasm32-wasi": "1.0.0-rc.17", "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.17", "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.17" }, "bin": { "rolldown": "bin/cli.mjs" } }, "sha512-ZrT53oAKrtA4+YtBWPQbtPOxIbVDbxT0orcYERKd63VJTF13zPcgXTvD4843L8pcsI7M6MErt8QtON6lrB9tyA=="], "rolldown-plugin-dts": ["rolldown-plugin-dts@0.23.2", "", { "dependencies": { "@babel/generator": "8.0.0-rc.3", "@babel/helper-validator-identifier": "8.0.0-rc.3", "@babel/parser": "8.0.0-rc.3", "@babel/types": "8.0.0-rc.3", "ast-kit": "^3.0.0-beta.1", "birpc": "^4.0.0", "dts-resolver": "^2.1.3", "get-tsconfig": "^4.13.7", "obug": "^2.1.1", "picomatch": "^4.0.4" }, "peerDependencies": { "@ts-macro/tsc": "^0.3.6", "@typescript/native-preview": ">=7.0.0-dev.20260325.1", "rolldown": "^1.0.0-rc.12", "typescript": "^5.0.0 || ^6.0.0", "vue-tsc": "~3.2.0" }, "optionalPeers": ["@ts-macro/tsc", "@typescript/native-preview", "typescript", "vue-tsc"] }, "sha512-PbSqLawLgZBGcOGT3yqWBGn4cX+wh2nt5FuBGdcMHyOhoukmjbhYAl8NT9sE4U38Cm9tqLOIQeOrvzeayM0DLQ=="], @@ -666,7 +666,7 @@ "tinyexec": ["tinyexec@1.0.4", "", {}, "sha512-u9r3uZC0bdpGOXtlxUIdwf9pkmvhqJdrVCH9fapQtgy/OeTTMZ1nqH7agtvEfmGui6e1XxjcdrlxvxJvc3sMqw=="], - "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="], + "tinyglobby": ["tinyglobby@0.2.16", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg=="], "tinypool": ["tinypool@2.1.0", "", {}, "sha512-Pugqs6M0m7Lv1I7FtxN4aoyToKg1C4tu+/381vH35y8oENM/Ai7f7C4StcoK4/+BSw9ebcS8jRiVrORFKCALLw=="], @@ -676,21 +676,21 @@ "tree-kill": ["tree-kill@1.2.2", "", { "bin": { "tree-kill": "cli.js" } }, "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A=="], - "tsdown": ["tsdown@0.21.7", "", { "dependencies": { "ansis": "^4.2.0", "cac": "^7.0.0", "defu": "^6.1.4", "empathic": "^2.0.0", "hookable": "^6.1.0", "import-without-cache": "^0.2.5", "obug": "^2.1.1", "picomatch": "^4.0.4", "rolldown": "1.0.0-rc.12", "rolldown-plugin-dts": "^0.23.2", "semver": "^7.7.4", "tinyexec": "^1.0.4", "tinyglobby": "^0.2.15", "tree-kill": "^1.2.2", "unconfig-core": "^7.5.0", "unrun": "^0.2.34" }, "peerDependencies": { "@arethetypeswrong/core": "^0.18.1", "@tsdown/css": "0.21.7", "@tsdown/exe": "0.21.7", "@vitejs/devtools": "*", "publint": "^0.3.0", "typescript": "^5.0.0 || ^6.0.0", "unplugin-unused": "^0.5.0" }, "optionalPeers": ["@arethetypeswrong/core", "@tsdown/css", "@tsdown/exe", "@vitejs/devtools", "publint", "typescript", "unplugin-unused"], "bin": { "tsdown": "dist/run.mjs" } }, "sha512-ukKIxKQzngkWvOYJAyptudclkm4VQqbjq+9HF5K5qDO8GJsYtMh8gIRwicbnZEnvFPr6mquFwYAVZ8JKt3rY2g=="], + "tsdown": ["tsdown@0.21.10", "", { "dependencies": { "ansis": "^4.2.0", "cac": "^7.0.0", "defu": "^6.1.7", "empathic": "^2.0.0", "hookable": "^6.1.1", "import-without-cache": "^0.3.3", "obug": "^2.1.1", "picomatch": "^4.0.4", "rolldown": "1.0.0-rc.17", "rolldown-plugin-dts": "^0.23.2", "semver": "^7.7.4", "tinyexec": "^1.1.1", "tinyglobby": "^0.2.16", "tree-kill": "^1.2.2", "unconfig-core": "^7.5.0", "unrun": "^0.2.37" }, "peerDependencies": { "@arethetypeswrong/core": "^0.18.1", "@tsdown/css": "0.21.10", "@tsdown/exe": "0.21.10", "@vitejs/devtools": "*", "publint": "^0.3.0", "typescript": "^5.0.0 || ^6.0.0", "unplugin-unused": "^0.5.0" }, "optionalPeers": ["@arethetypeswrong/core", "@tsdown/css", "@tsdown/exe", "@vitejs/devtools", "publint", "typescript", "unplugin-unused"], "bin": { "tsdown": "dist/run.mjs" } }, "sha512-3wk73yBhZe/wX7REqSdivNQ84TDs1mJ+IlnzrrEREP70xlJ/AEIzqaI04l/TzMKVIdkTdC3CPaADn2Lk/0SkdA=="], "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], "tunnel-agent": ["tunnel-agent@0.6.0", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w=="], - "typescript": ["typescript@6.0.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ=="], + "typescript": ["typescript@6.0.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw=="], "unconfig-core": ["unconfig-core@7.5.0", "", { "dependencies": { "@quansync/fs": "^1.0.0", "quansync": "^1.0.0" } }, "sha512-Su3FauozOGP44ZmKdHy2oE6LPjk51M/TRRjHv2HNCWiDvfvCoxC2lno6jevMA91MYAdCdwP05QnWdWpSbncX/w=="], - "undici-types": ["undici-types@7.18.2", "", {}, "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w=="], + "undici-types": ["undici-types@7.19.2", "", {}, "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg=="], "universalify": ["universalify@0.1.2", "", {}, "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="], - "unrun": ["unrun@0.2.34", "", { "dependencies": { "rolldown": "1.0.0-rc.12" }, "peerDependencies": { "synckit": "^0.11.11" }, "optionalPeers": ["synckit"], "bin": { "unrun": "dist/cli.mjs" } }, "sha512-LyaghRBR++r7svhDK6tnDz2XaYHWdneBOA0jbS8wnRsHerI9MFljX4fIiTgbbNbEVzZ0C9P1OjWLLe1OqoaaEw=="], + "unrun": ["unrun@0.2.37", "", { "dependencies": { "rolldown": "1.0.0-rc.17" }, "peerDependencies": { "synckit": "^0.11.11" }, "optionalPeers": ["synckit"], "bin": { "unrun": "dist/cli.mjs" } }, "sha512-AA7vDuYsgeSYVzJMm16UKA+aXFKhy7nFqW9z5l7q44K4ppFWZAMqYS58ePRZbugMLPH0fwwMzD5A8nP0avxwZQ=="], "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], @@ -716,8 +716,16 @@ "@manypkg/get-packages/fs-extra": ["fs-extra@8.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^4.0.0", "universalify": "^0.1.0" } }, "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g=="], + "@oxc-resolver/binding-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.2", "", { "dependencies": { "@tybys/wasm-util": "^0.10.1" }, "peerDependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1" } }, "sha512-sNXv5oLJ7ob93xkZ1XnxisYhGYXfaG9f65/ZgYuAu3qt7b3NadcOEhLvx28hv31PgX8SZJRYrAIPQilQmFpLVw=="], + "@quansync/fs/quansync": ["quansync@1.0.0", "", {}, "sha512-5xZacEEufv3HSTPQuchrvV6soaiACMFnq1H8wkVioctoH3TRha9Sz66lOxRwPK/qZj7HPiSveih9yAyh98gvqA=="], + "@rolldown/binding-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.10.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" } }, "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw=="], + + "@rolldown/binding-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.10.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA=="], + + "@types/better-sqlite3/@types/node": ["@types/node@25.5.2", "", { "dependencies": { "undici-types": "~7.18.0" } }, "sha512-tO4ZIRKNC+MDWV4qKVZe3Ql/woTnmHDr5JD8UI5hn2pwBrHEwOEMZK7WlNb5RKB6EoJ02gwmQS9OrjuFnZYdpg=="], + "log-update/slice-ansi": ["slice-ansi@7.1.2", "", { "dependencies": { "ansi-styles": "^6.2.1", "is-fullwidth-code-point": "^5.0.0" } }, "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w=="], "log-update/strip-ansi": ["strip-ansi@7.2.0", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="], @@ -726,16 +734,18 @@ "read-yaml-file/js-yaml": ["js-yaml@3.14.2", "", { "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg=="], - "rolldown/@oxc-project/types": ["@oxc-project/types@0.122.0", "", {}, "sha512-oLAl5kBpV4w69UtFZ9xqcmTi+GENWOcPF7FCrczTiBbmC0ibXxCwyvZGbO39rCVEuLGAZM84DH0pUIyyv/YJzA=="], - "string-width/strip-ansi": ["strip-ansi@7.2.0", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="], + "tsdown/tinyexec": ["tinyexec@1.1.1", "", {}, "sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg=="], + "unconfig-core/quansync": ["quansync@1.0.0", "", {}, "sha512-5xZacEEufv3HSTPQuchrvV6soaiACMFnq1H8wkVioctoH3TRha9Sz66lOxRwPK/qZj7HPiSveih9yAyh98gvqA=="], "wrap-ansi/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="], "wrap-ansi/strip-ansi": ["strip-ansi@7.2.0", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="], + "@types/better-sqlite3/@types/node/undici-types": ["undici-types@7.18.2", "", {}, "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w=="], + "log-update/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], "read-yaml-file/js-yaml/argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="], diff --git a/package.json b/package.json index dd7a68c..27d9a2f 100644 --- a/package.json +++ b/package.json @@ -72,26 +72,26 @@ }, "dependencies": { "@clack/prompts": "^1.2.0", - "better-sqlite3": "^12.8.0", + "better-sqlite3": "^12.9.0", "lightningcss": "^1.32.0", - "oxc-parser": "^0.124.0", + "oxc-parser": "^0.127.0", "oxc-resolver": "^11.19.1", - "tinyglobby": "^0.2.15", + "tinyglobby": "^0.2.16", "zod": "^4.3.6" }, "devDependencies": { "@changesets/changelog-github": "^0.6.0", - "@changesets/cli": "^2.30.0", + "@changesets/cli": "^2.31.0", "@types/better-sqlite3": "^7.6.13", - "@types/bun": "^1.3.11", - "@types/node": "^25.5.2", - "@typescript/native-preview": "^7.0.0-dev.20260407.1", + "@types/bun": "^1.3.13", + "@types/node": "^25.6.0", + "@typescript/native-preview": "^7.0.0-dev.20260427.1", "husky": "^9.1.7", "lint-staged": "^16.4.0", - "oxfmt": "^0.44.0", - "oxlint": "^1.59.0", - "tsdown": "^0.21.7", - "typescript": "^6.0.2" + "oxfmt": "^0.46.0", + "oxlint": "^1.61.0", + "tsdown": "^0.21.10", + "typescript": "^6.0.3" }, "engines": { "bun": ">=1.0.0", From 5734479f11084cd2f64cf94e2f1d35a9f0a346f9 Mon Sep 17 00:00:00 2001 From: Sutu Sebastian Date: Mon, 27 Apr 2026 13:07:08 +0300 Subject: [PATCH 02/12] docs: anti-pitch, scenario-keyed token table, capability table, daily commands MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - why-codemap.md: add "What Codemap is not" section (anti-pitch — preempts "is this an LSP / agent / smart tool?" reading); replace narrative token-savings text with scenario-keyed rows (single lookup → 50-turn session) backed by a methodology footnote pointing at bun run benchmark:query - README.md: add "What you get" Grep/Read vs Codemap capability table near the top; add a "Daily commands" stripe and a "version-matched Agent Skill" packaging line in the CLI section - docs/research/competitive-scan-2026-04.md: capture the audit of fallow, AZidan/codemap, and JordanCoin/codemap that drove the messaging changes - .agents/lessons.md: add bump-policy lesson (patch by default for 0.x; reserve minor for schema-breaking changes; strict SemVer post-1.0) --- .agents/lessons.md | 2 + README.md | 31 ++++ docs/research/competitive-scan-2026-04.md | 209 ++++++++++++++++++++++ docs/why-codemap.md | 29 ++- 4 files changed, 265 insertions(+), 6 deletions(-) create mode 100644 docs/research/competitive-scan-2026-04.md diff --git a/.agents/lessons.md b/.agents/lessons.md index 9a93f0c..615be73 100644 --- a/.agents/lessons.md +++ b/.agents/lessons.md @@ -7,3 +7,5 @@ Persistent log of corrections and insights from past sessions. Agents **must** c Each entry is a single bullet: `- **** — `. Newest entries at the bottom. ## Lessons + +- **changesets bump policy (pre-v1)** — while in `0.x`, default to **patch** for everything (additive features, fixes, docs, internal refactors); reserve **minor** for schema-breaking changes that force a `.codemap.db` rebuild (matches 0.2.0 precedent: new tables/columns/`SCHEMA_VERSION` bump). Strict SemVer kicks in only after `1.0.0`. Don't propose `minor` just because new CLI commands or public types were added. diff --git a/README.md b/README.md index 1f5d101..2e8c36a 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,23 @@ --- +## What you get + +Structural questions answered in **one SQL round-trip** instead of 3–5 file reads: + +| Question | Grep / Read (today) | Codemap | +| -------------------------------------------------- | ------------------------------------------------------------ | -------------------------------------------------------------------------------------- | +| Find a symbol by exact name | Glob + Read + filter by hand | `SELECT name, file_path, line_start FROM symbols WHERE name = 'X'` | +| Who imports `~/utils/date`? | Grep + resolve `tsconfig` aliases manually | `SELECT DISTINCT from_path FROM dependencies WHERE to_path LIKE '%utils/date%'` | +| Components using the `useQuery` hook | Grep `useQuery` + filter to component files | `SELECT name, file_path FROM components WHERE hooks_used LIKE '%useQuery%'` | +| Heaviest files by import fan-out | Impractical without a parser | `SELECT from_path, COUNT(*) AS n FROM dependencies GROUP BY from_path ORDER BY n DESC` | +| All CSS keyframes / design tokens / module classes | Grep `@keyframes`, `--var-`, `.module.css` then disambiguate | One `SELECT` against `css_keyframes` / `css_variables` / `css_classes` | +| Deprecated symbols (`@deprecated` JSDoc) | Grep `@deprecated` + cross-reference symbol | `SELECT name, kind FROM symbols WHERE doc_comment LIKE '%@deprecated%'` | + +Full schema and recipe catalog: [docs/architecture.md § Schema](docs/architecture.md#schema) · [docs/why-codemap.md](docs/why-codemap.md) · `codemap query --recipes-json`. + +--- + ## Install ```bash @@ -25,6 +42,20 @@ bun add @stainless-code/codemap - **Installed package:** `codemap`, `bunx @stainless-code/codemap`, or `node node_modules/@stainless-code/codemap/dist/index.mjs` - **This repo (dev):** `bun src/index.ts` (same flags) +### Daily commands + +```bash +codemap # incremental index (run once per session) +codemap query --json --recipe fan-out # bundled SQL via recipe id +codemap query --json "SELECT name, file_path FROM symbols WHERE name = 'foo'" # ad-hoc SQL +codemap --files src/a.ts src/b.tsx # targeted re-index after edits +codemap agents init # scaffold .agents/ rules + skills +``` + +**Version-matched agent guidance:** the published npm package ships **`templates/agents/`** (rules + skills) keyed to that version, so `codemap agents init` writes guidance that matches the CLI you installed. See [docs/agents.md](docs/agents.md). + +### Full reference + ```bash # Index project root (optional codemap.config.ts / codemap.config.json) codemap diff --git a/docs/research/competitive-scan-2026-04.md b/docs/research/competitive-scan-2026-04.md new file mode 100644 index 0000000..972388a --- /dev/null +++ b/docs/research/competitive-scan-2026-04.md @@ -0,0 +1,209 @@ +# Competitive scan — fallow, AZidan/codemap, JordanCoin/codemap + +> Inspiration scan from three sibling tools in the "AI-friendly code intelligence" space. +> Goal: identify candidates we should adopt, ignore, or watch for our positioning of +> **`@stainless-code/codemap`** (local SQLite index of structural metadata, queried via SQL). + +Sources: + +- [fallow-rs/fallow](https://github.com/fallow-rs/fallow) — Rust, ~1.1k stars, TS/JS-only, "codebase intelligence" (dead code, dupes, complexity, boundaries, runtime). 91 framework plugins. +- [AZidan/codemap](https://github.com/AZidan/codemap) — Python, ~55 stars, "make LLM reads cheaper" (symbol→line-range index). Multi-language tree-sitter. +- [JordanCoin/codemap](https://github.com/JordanCoin/codemap) — Go, ~525 stars, "project brain" (tree+diff+deps+skyline+handoff). Hooks/MCP/HTTP/skills. + +--- + +## 1. Positioning recap (us) + +We are: **structural SQLite index** → agents call **SQL** for symbols, imports, exports, components, calls, type members, deps, CSS tokens/classes/keyframes, markers. AST-backed (oxc, lightningcss, oxc-resolver). Bun + Node, TS/CSS-first. CLI **`codemap query --json`** + **`codemap agents init`** for IDE wiring. + +We are **not**: dead-code detector, duplication finder, dependency-flow visualizer, semantic understanding layer, agent runtime/MCP server (yet). + +--- + +## 2. Side-by-side + +| Axis | **us** | fallow | AZidan/codemap | JordanCoin/codemap | +| ----------------- | --------------------------------------- | ------------------------------------------------------ | ------------------------------------ | -------------------------------------------- | +| Lang of impl | TS (Bun/Node) | Rust | Python | Go | +| Storage | SQLite (`.codemap.db`) | in-process; SARIF/JSON outputs | distributed JSON (`.codemap/*.json`) | per-project `.codemap/` JSON artifacts | +| Query surface | **SQL** (full power) | CLI subcommands, `--format json` | `find`/`show`/`stats` CLI | `tree`/`--diff`/`--deps`/`context`/MCP/HTTP | +| What's indexed | symbols, imports/exports, deps, CSS, … | module graph, dupe clones, complexity, boundary rules | symbols + line ranges + hash | tree + dep flow + hubs + working set | +| Agent integration | rules/skills via `agents init` | MCP, LSP, VSCode ext, `--format json` w/ fix `actions` | Claude plugin, MCP planned | hooks, MCP, HTTP, "context envelope", skills | +| Refresh model | git-diff incremental + targeted `files` | full+changed-since | hash + watch + git pre-commit | daemon, hooks, watch | +| TS/JS depth | oxc AST | oxc AST + boundary/dup/complexity | tree-sitter | ast-grep (deps only) | +| Other langs | CSS | TS/JS only (intentional) | 14 langs (tree-sitter) | 18 langs (deps via ast-grep) | +| Headline pitch | "query your codebase" | "codebase truth layer for agents" | "make every read cheaper" | "project brain for your AI" | +| License | MIT | MIT (+ paid runtime) | MIT | MIT | + +--- + +## 3. Candidates worth stealing / borrowing + +Ranked by impact × fit for our SQL-index thesis. **Adopt** = strong fit; **Watch** = revisit; +**Pass** = scope/philosophy mismatch. + +### 3.1 ADOPT — short list + +#### A. **MCP server wrapping `query`** (already in [roadmap.md backlog](../roadmap.md)) + +- **Inspired by:** JordanCoin (`codemap mcp` over stdio + `list_skills`, `get_skill`, `context`), fallow (MCP server bundled in npm), AZidan (planned). +- **Why:** Our SQL surface is more powerful than any of theirs once exposed. An MCP `query`/`recipe`/`list_recipes` tool gives Cursor/Claude/Windsurf agents direct access without shelling out. Strongest single move. +- **Concrete shape:** + - Tools: `query` (SQL string → JSON rows), `recipe` (id → JSON rows), `list_recipes` (catalog), `index` (incremental), `schema` (DDL). + - Resources: bundled `SKILL.md`, `agents/rules/codemap.md`, current schema, recipe catalog. + - Prompts: a couple of "explore this codebase" templates that pre-bind the SQL skill. +- **Fit:** Tracer-bullet friendly — slice = one tool (`query`) + one transport (stdio) wired into existing `cli/cmd-query.ts`. + +#### B. **HTTP API** (`codemap serve`) + +- **Inspired by:** JordanCoin (`codemap serve` → `/api/context`, `/api/skills`, `/api/working-set`). +- **Why:** Some integrations don't speak MCP yet. A localhost HTTP server with the same query/recipe surface (`POST /query`, `GET /recipes`, `GET /recipes/:id`, `GET /schema`) is ~50 lines and unblocks tooling outside the MCP ecosystem. +- **Caveat:** Bind to `127.0.0.1`. No auth needed for local; reject non-loopback unless `--host` overridden. + +#### C. **Recipes-as-content registry** (extension of what we already ship) + +- **Inspired by:** JordanCoin "skills framework" (markdown w/ YAML frontmatter, project-local override, `skill list`/`show`/`init`); fallow "framework plugins" (91 of them). +- **Why:** We already have `query --recipes-json` / `--print-sql`. Pairing each recipe with a short markdown explanation (when to use, what shape, follow-up SQL) gives agents executable context. A `codemap recipes show ` could print SQL + prose. Project-local recipes in `.codemap/recipes/*.sql` (or `.json`) would let teams ship internal SQL. +- **Concrete shape:** + - Bundled recipes already exist in **`src/cli/query-recipes.ts`** — add an optional `description.md` sibling and surface in `--recipes-json`. + - Allow user recipes from `.codemap/recipes/` (read at query time) — first-class extension point that doesn't require new adapter API. + +#### D. **`codemap context` JSON envelope** for any agent/CLI + +- **Inspired by:** JordanCoin `codemap context` / `--for "intent"` / `--compact`. +- **Why:** Single command emitting a stable JSON object — project metadata, schema version, top hubs, recent markers, file count, recipe catalog — that any agent can pipe into a prompt. Cheap to build because it's just a few of our existing recipes serialized into one envelope. +- **Stub:** `codemap context [--compact] [--for ""]` → `{ project, schema, hubs, recipes, recent_markers, file_count }`. + +#### E. **Hash-based staleness check** (verify without re-reading) + +- **Inspired by:** AZidan `codemap validate` (returns stale entries; LLM checks if a file changed _without_ re-reading). +- **Why:** We already store **`files.content_hash`** (SHA-256). Expose `codemap validate [paths…]` that prints stale paths in JSON. Tiny lift, big agent UX win — agents can ask "are my notes still valid?" for the cost of a SQL row, then re-read only the dirty ones. +- **One-liner:** `SELECT path FROM files WHERE content_hash != ?` — implementation just a CLI wrapper. + +#### F. **Hub / fan-in summary as first-class output** (we have data, lacking presentation) + +- **Inspired by:** JordanCoin "HUBS: config (12←), api (8←)" surface in `--deps`. +- **Why:** We already compute fan-in/fan-out via `dependencies` table and have a `fan-out` recipe. Add `hubs` recipe (top-N most-imported files) and surface in the `context` envelope above. Pure SQL, no new code. + +#### G. **Doc-comment + `@deprecated` recipes** (we already store `doc_comment`) + +- **Inspired by:** Fallow JSDoc visibility tags (`@public`, `@internal`, `@deprecated` driving dead-code policy). +- **Why:** Our `symbols.doc_comment` already preserves `@deprecated`. Recipes: + - `deprecated-symbols` — `WHERE doc_comment LIKE '%@deprecated%'` + - `internal-only` — visibility tag scan +- Cheap, recipe-only change. + +### 3.2 WATCH — interesting, defer until v2 + +#### W1. **Targeted reads as the main UX** (AZidan) + +- The "find symbol → read only lines 15–89" workflow is exactly what our `symbols.line_start/line_end` enables, but we don't currently ship a one-step CLI like `codemap show src/file.ts` or `codemap snippet symbolName`. Worth considering once MCP lands; agents can do it via SQL today. +- Low-hanging recipe: `read-symbol` — input `name` → output `file_path, line_start, line_end, signature`. + +#### W2. **Watch mode** (already in roadmap; both JordanCoin and AZidan ship it) + +- Both projects use file watchers (chokidar / `fsnotify`) to keep their index live. Our incremental + `--files` already cover most of this; a `codemap watch` is plumbing, not architecture. + +#### W3. **Project-local skills/recipes** (JordanCoin, fallow plugins) + +- A `.codemap/skills/*.md` or `.codemap/recipes/*.sql` directory that overrides bundled — same pattern as JordanCoin's project-local skill override. Pairs naturally with our existing `agents init`. + +#### W4. **Cross-agent handoff artifact** (JordanCoin) + +- Layered prefix/delta JSON written on session-stop, read on session-start. Interesting because it's complementary to indexing — a separate "what's been touched lately" log. Probably an _outside-of-codemap_ tool, but the daemon mode is worth thinking about (one persistent process can host MCP + HTTP + watcher). + +#### W5. **Remote-repo support** (JordanCoin `codemap github.com/x/y`) + +- Shallow clone to temp dir, index, query, cleanup. Trivial wrapper around `git clone --depth 1` + our existing CLI. Not central to our thesis but very low-cost demo. + +### 3.3 PASS — explicit non-goals + +| Idea | Source | Why we pass | +| ----------------------------------------------------------- | ----------------------------------- | ----------------------------------------------------------------------------------------------------------------- | +| Dead-code, duplication, complexity, boundaries, fix-actions | fallow | Different product class. Our "structural index" thesis stays a primitive that fallow-style tools could _consume_. | +| Runtime/V8/Istanbul coverage merging, paid tier | fallow runtime | Out of scope for v1; would massively expand surface. | +| 91 framework plugins | fallow | They're entry-point detectors for _dead-code_. Our index isn't entry-point-aware (we index everything globbed). | +| PageRank-style "summarization" | aider RepoMap (mentioned by AZidan) | We agree with AZidan: don't summarize, let the agent decide via SQL. | +| Skyline ASCII-art / animation | JordanCoin | Pure demoware. | +| Daemon process for hooks | JordanCoin | Optional later. SQLite already supports concurrent readers; one-shot CLI is fine for now. | +| Embedded "intent classification" (regex over user prompts) | JordanCoin | Belongs in the agent / MCP host, not in the index tool. | + +--- + +## 4. Messaging lessons + +The three highest-signal positioning lessons from this audit. Each one has a clear target file and a one-shot edit. + +### 4.1 Anti-pitch — "what Codemap is **not**" + +- **Source:** AZidan's _"What CodeMap is not"_ section ("not a semantic analyzer / not an LSP / not an agent / not smart"). +- **Why it wins:** preempts the "is this an LSP / agent / smart tool?" question before the reader forms it. Cleaner than our current framing in [why-codemap.md](../why-codemap.md). +- **Where to land it:** [docs/why-codemap.md](../why-codemap.md) — add a subsection above "The Solution" that explicitly lists Codemap is **not** full-text search, **not** an LSP, **not** an agent, **not** a static analyzer / dead-code detector, **not** a semantic embedder. +- **Cost:** ~10 lines, pure docs. + +### 4.2 Token-savings table — concrete scenarios, our own numbers + +- **Source:** AZidan's table: + | Scenario | Without | With | Savings | + | --- | --- | --- | --- | + | Single class lookup | 1,700 tok | 1,000 tok | 41% | + | 10-file refactor | 51,000 tok | 11,600 tok | 77% | + | 50-turn coding session | 70,000 tok | 21,000 tok | 70% | +- **Why it wins:** "very large vs ~5K" (our current text) reads as hand-waving. A 3-row table reads as evidence. +- **Where to land it:** [docs/why-codemap.md § Across a Typical Session](../why-codemap.md#across-a-typical-session) — replace the existing `Token cost (10/20 questions)` table with scenario-keyed rows. +- **Cost:** numbers come from `bun run benchmark:query` + `src/benchmark.ts` (already producing token impact estimates). Just present them. + +### 4.3 "Grep/Read vs Codemap" capability table + +- **Source:** Fallow's "Linter vs Fallow" table — rows like _"unused export that nothing imports"_ with `yes / no` per tool. +- **Why it wins:** concrete capability rows are far more persuasive than prose. Many such rows already live in our [golden-queries.md](../golden-queries.md) and [SKILL.md](../../.agents/skills/codemap/SKILL.md) but they're buried. +- **Where to land it:** [README.md](../../README.md), near the top — table with rows like: + | Question | Grep / Read | Codemap | + | --- | --- | --- | + | Find symbol by exact name | yes (slow + noisy) | one SQL row | + | Who imports `~/utils/date`? | resolve aliases manually | one SQL row | + | Components using `useQuery` | grep + filter manually | one SQL row | + | All CSS keyframes in project | grep `@keyframes` | one SQL row | + | Heaviest files by import fan-out | impractical | one SQL row | +- **Cost:** ~15 lines of markdown, all queries already exist as recipes. + +--- + +## 4b. Other doc-shape ideas (lower priority) + +- **Comparison table — Codemap vs Aider RepoMap / Serena / RepoPrompt / Fallow** — situating row in [why-codemap.md](../why-codemap.md). AZidan's table is the model. +- **Fallow's "version-matched Agent Skill" framing** — we already do this via `templates/agents/`; calling it out as "version-matched" in README packaging copy is free credibility. +- **JordanCoin's "Daily commands" block** — curate 5–6 most-used commands at the top of the README CLI section instead of the current dense list. + +--- + +## 5. Concrete suggested next steps (tracer-bullet sized) + +Mapped to existing layers per [.cursor/rules/tracer-bullets.mdc](../../.cursor/rules/tracer-bullets.mdc): + +1. **Recipe: `validate-stale-files`** — pure SQL recipe added to **`src/cli/query-recipes.ts`** (input: array of paths via SQL bind, output: stale paths). Tracer slice = one recipe + golden test. **(F + E above)** +2. **Recipe: `hubs`** — top-N most-imported files using `dependencies`. Pairs with existing `fan-out`. **(F)** +3. **Recipe: `deprecated-symbols`** — JSDoc-tag scan over `symbols.doc_comment`. **(G)** +4. **`codemap context` subcommand** — emits a JSON envelope composed from a fixed set of recipes. Tracer slice = one CLI command + 1 golden test on `fixtures/minimal/`. **(D)** +5. **MCP server (`codemap mcp`)** — single `query` tool first; expand later. Tracer slice = stdio transport + one tool wired through existing `runQueryCmd` core. **(A)** +6. **HTTP server (`codemap serve --port`)** — minimal Hono/native http, `POST /query` + `GET /recipes`. Tracer slice = `bun --hot` smoke test + golden response shape. **(B)** +7. **README polish** — add "Daily commands", "What Codemap is not", "Codemap vs alternatives" tables (see §4). Pure docs PR, no code. + +--- + +## 6. Open questions + +- **Should recipes own their description?** — JordanCoin couples skills + content tightly via YAML frontmatter; we currently keep recipes as code constants. Moving to one `recipes/.{sql,md}` pair on disk (read at runtime via Bun `import.meta.glob` / Node `readdirSync`) makes them more discoverable and contributable. +- **Daemon vs one-shot** — JordanCoin's daemon is the only way they get sub-100ms hooks. Our CLI startup is ~50–100 ms cold (Node) and lower on Bun; we may not need a daemon at all. Worth measuring once MCP/HTTP land. +- **Path-prefix / monorepo workspace awareness** — fallow has `--changed-workspaces`, `--workspace @scope/app`, JordanCoin has implicit project root detection. Already in our [roadmap § Backlog](../roadmap.md#backlog). +- **Should we adopt fallow's `--save-baseline` pattern?** — only relevant once we ship audit-style commands; today we don't, so it's noise. + +--- + +## 7. Citations / cross-links + +- [docs/roadmap.md](../roadmap.md) — current backlog including MCP, watch mode, monorepo awareness. +- [docs/why-codemap.md](../why-codemap.md) — token-cost framing this scan should feed back into. +- [docs/architecture.md](../architecture.md) — schema and CLI layering touched by these proposals. +- [src/cli/query-recipes.ts](../../src/cli/query-recipes.ts) — where recipe additions land. +- [.agents/skills/codemap/SKILL.md](../../.agents/skills/codemap/SKILL.md) — agent guidance we'd extend with new recipes. diff --git a/docs/why-codemap.md b/docs/why-codemap.md index 34733bf..1d88b86 100644 --- a/docs/why-codemap.md +++ b/docs/why-codemap.md @@ -13,6 +13,19 @@ AI coding agents (Cursor, Copilot, Windsurf, etc.) discover code by scanning fil This burns context window, wastes tokens, slows response time, and produces less accurate results. +## What Codemap is not + +Codemap is intentionally narrow. It is **not**: + +- **Full-text search** — use `ripgrep` / your IDE for raw string queries on file bodies. +- **A language server (LSP)** — no rename, no go-to-definition wired to your editor, no hover types. +- **An AI agent** — Codemap does not reason, decide, or generate. Agents call Codemap; Codemap does not call agents. +- **A static analyzer** — no dead-code detection, duplication detection, complexity scoring, or boundary enforcement (those are different products — e.g. [fallow](https://github.com/fallow-rs/fallow), `knip`, `jscpd`). +- **A semantic / embedding index** — no vector search, no PageRank summarization, no "what's relevant" inference. +- **A replacement for reading code** — the index returns paths, line ranges, signatures; the agent still reads the snippets it needs. + +What Codemap **is**: a deterministic, AST-backed SQLite index of structural facts (symbols, imports, exports, components, calls, dependencies, CSS tokens, markers) that an agent can query in **one SQL round-trip** instead of scanning the tree. + ## The Solution A pre-built SQLite index (`.codemap.db`) that extracts and structures code metadata at index time. Agents query it with SQL instead of scanning files. Timings, scenarios, and methodology: [benchmark.md](./benchmark.md). @@ -43,13 +56,17 @@ Traditional cost **depends on the question**: scanning all `app/**/*.{ts,tsx}` i ### Across a Typical Session -A typical AI agent session involves 10-20 discovery questions (finding definitions, tracing imports, checking dependencies). At traditional rates on a large app: +Token cost compounds across a session. The savings are not "any single lookup" — they are "every lookup, multiplied". Concrete shapes: + +| Scenario | Without Codemap | With Codemap | Savings | +| ------------------------------------------------------------ | ------------------------------------------------------- | ----------------------------------------------------- | ------- | +| **Single symbol lookup** ("where is `UserService` defined?") | 1 Glob + 1–2 Reads to disambiguate ≈ **0.5–1K tokens** | 1 SQL row → file/line range ≈ **~150 tokens** | ~70–85% | +| **Trace dependents** ("who imports `~/utils/date`?") | Grep + read 5–10 files to resolve aliases ≈ **30–100K** | 1 SQL row set ≈ **~500 tokens** | ~95% | +| **10-file refactor session** | 10× full file reads + grep traces ≈ **100–300K** | 10× targeted SQL + 10× line-range reads ≈ **~10–25K** | ~85–90% | +| **50-turn agent session** (mixed discovery + reads) | ≈ **500K – 1M+ tokens** | ≈ **30–60K tokens** | ~90%+ | +| **Tool calls per discovery question** | 3–5 (Glob → Read → Grep → Read → …) | 1 (`codemap query`) | 60–80% | -| Metric | Traditional | Indexed | Savings | -| ------------------------- | ----------- | ----------- | ---------- | -| Token cost (10 questions) | very large | ~5K tokens | **~99%+** | -| Token cost (20 questions) | very large | ~10K tokens | **~99%+** | -| Tool calls per question | 3-5 | 1 | **60-80%** | +> Token estimates assume **~4 bytes/token** and a medium TS codebase. Actual numbers vary by repo. Run `bun run benchmark:query` against your tree for concrete values; methodology in [benchmark.md § Query stdout](./benchmark.md#query-stdout-table-vs-json-benchmarkquery). ### Real-World Context Window Impact From 3791bbab7c9e4351ffe35aa368cba1ed91bf2518 Mon Sep 17 00:00:00 2001 From: Sutu Sebastian Date: Mon, 27 Apr 2026 13:07:21 +0300 Subject: [PATCH 03/12] chore(lint): tighten oxlint baseline; ignore fixtures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the import plugin and 11 stricter rules: prefer-const, type-import hoisting (consistent-type-specifier-style: prefer-top-level), interface preference for object types, no-confusing-non-null-assertion, no-unnecessary-{boolean-literal-compare,template-expression,type-assertion}, prefer-{includes,nullish-coalescing,optional-chain}, and unicorn/switch-case-braces. Add fixtures/ to ignorePatterns so hand-crafted parser test corpora are never auto-mutated (prevents golden churn — discovered when an auto-fix on fixtures/minimal/src/consumer.ts split a mixed import and broke the imports-consumer-alias / files-hashes / index-summary scenarios). Source-side auto-fixes from these rules ship with the feature commits that follow. --- .oxlintrc.json | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/.oxlintrc.json b/.oxlintrc.json index e5cdd04..b466945 100644 --- a/.oxlintrc.json +++ b/.oxlintrc.json @@ -1,5 +1,25 @@ { "$schema": "./node_modules/oxlint/configuration_schema.json", - "ignorePatterns": [".output", "node_modules", "dist", "coverage", "bun.lock"], - "plugins": ["eslint", "typescript", "unicorn", "oxc"] + "ignorePatterns": [ + ".output", + "bun.lock", + "coverage", + "dist", + "fixtures", + "node_modules" + ], + "plugins": ["eslint", "typescript", "unicorn", "oxc", "import"], + "rules": { + "eslint/prefer-const": "error", + "import/consistent-type-specifier-style": ["error", "prefer-top-level"], + "typescript/consistent-type-definitions": ["error", "interface"], + "typescript/no-confusing-non-null-assertion": "error", + "typescript/no-unnecessary-boolean-literal-compare": "error", + "typescript/no-unnecessary-template-expression": "error", + "typescript/no-unnecessary-type-assertion": "error", + "typescript/prefer-includes": "error", + "typescript/prefer-nullish-coalescing": "error", + "typescript/prefer-optional-chain": "error", + "unicorn/switch-case-braces": "error" + } } From ab32f87e653876d170e56950c69e0b2a788df6ea Mon Sep 17 00:00:00 2001 From: Sutu Sebastian Date: Mon, 27 Apr 2026 13:07:34 +0300 Subject: [PATCH 04/12] feat(query): four new recipes, -r short alias, cleaner --help MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Recipes (all parameterless SQL on the existing schema): - deprecated-symbols — symbols whose JSDoc contains @deprecated; lets agents flag callers of soon-to-be-removed APIs - visibility-tags — symbols tagged @internal / @private / @alpha / @beta - files-hashes — every indexed file with content_hash; powers the forthcoming `codemap validate` CLI - barrel-files — top files by export count (public-API hubs) CLI: - -r is now a short alias for --recipe (e.g. `codemap query -r fan-out`) - --help is reorganized: sectioned flags, dynamic recipe-id padding, examples for both --recipe and -r forms Fixtures: - @deprecated and @internal JSDoc added to fixtures/minimal/src/utils/date.ts to give the new recipes real rows to assert on - 4 new golden scenarios + index-summary refresh (symbols 8 → 9) --- fixtures/golden/minimal/barrel-files.json | 22 +++++++ .../golden/minimal/deprecated-symbols.json | 10 ++++ fixtures/golden/minimal/files-hashes.json | 57 ++++++++++++++++++ fixtures/golden/minimal/index-summary.json | 2 +- fixtures/golden/minimal/visibility-tags.json | 10 ++++ fixtures/golden/scenarios.json | 20 +++++++ fixtures/minimal/src/utils/date.ts | 11 ++++ src/cli/cmd-query.test.ts | 17 ++++++ src/cli/cmd-query.ts | 33 +++++----- src/cli/query-recipes.ts | 60 ++++++++++++++++++- 10 files changed, 225 insertions(+), 17 deletions(-) create mode 100644 fixtures/golden/minimal/barrel-files.json create mode 100644 fixtures/golden/minimal/deprecated-symbols.json create mode 100644 fixtures/golden/minimal/files-hashes.json create mode 100644 fixtures/golden/minimal/visibility-tags.json diff --git a/fixtures/golden/minimal/barrel-files.json b/fixtures/golden/minimal/barrel-files.json new file mode 100644 index 0000000..d67000f --- /dev/null +++ b/fixtures/golden/minimal/barrel-files.json @@ -0,0 +1,22 @@ +[ + { + "file_path": "src/api/client.ts", + "exports": 2 + }, + { + "file_path": "src/components/shop/ShopButton.tsx", + "exports": 2 + }, + { + "file_path": "src/utils/date.ts", + "exports": 2 + }, + { + "file_path": "src/consumer.ts", + "exports": 1 + }, + { + "file_path": "src/usePermissions.ts", + "exports": 1 + } +] diff --git a/fixtures/golden/minimal/deprecated-symbols.json b/fixtures/golden/minimal/deprecated-symbols.json new file mode 100644 index 0000000..bd54a77 --- /dev/null +++ b/fixtures/golden/minimal/deprecated-symbols.json @@ -0,0 +1,10 @@ +[ + { + "name": "now", + "kind": "function", + "file_path": "src/utils/date.ts", + "line_start": 5, + "signature": "now(): number", + "doc_comment": "@deprecated Use `Date.now()` directly. Kept as a fixture for the\n`deprecated-symbols` recipe golden test." + } +] diff --git a/fixtures/golden/minimal/files-hashes.json b/fixtures/golden/minimal/files-hashes.json new file mode 100644 index 0000000..bf22e2b --- /dev/null +++ b/fixtures/golden/minimal/files-hashes.json @@ -0,0 +1,57 @@ +[ + { + "path": "README.md", + "language": "md", + "line_count": 11 + }, + { + "path": "package.json", + "language": "json", + "line_count": 11 + }, + { + "path": "src/api/client.ts", + "language": "ts", + "line_count": 9 + }, + { + "path": "src/components/shop/ShopButton.tsx", + "language": "tsx", + "line_count": 8 + }, + { + "path": "src/consumer.ts", + "language": "ts", + "line_count": 11 + }, + { + "path": "src/notes.md", + "language": "md", + "line_count": 4 + }, + { + "path": "src/styles/button.module.css", + "language": "css", + "line_count": 16 + }, + { + "path": "src/theme.css", + "language": "css", + "line_count": 9 + }, + { + "path": "src/usePermissions.ts", + "language": "ts", + "line_count": 4 + }, + { + "path": "src/utils/date.ts", + "language": "ts", + "line_count": 15 + }, + { + "path": "tsconfig.json", + "language": "json", + "line_count": 17 + } +] diff --git a/fixtures/golden/minimal/index-summary.json b/fixtures/golden/minimal/index-summary.json index f17d55d..8b550d6 100644 --- a/fixtures/golden/minimal/index-summary.json +++ b/fixtures/golden/minimal/index-summary.json @@ -1,7 +1,7 @@ [ { "files": 11, - "symbols": 8, + "symbols": 9, "imports": 3, "components": 1, "dependencies": 2 diff --git a/fixtures/golden/minimal/visibility-tags.json b/fixtures/golden/minimal/visibility-tags.json new file mode 100644 index 0000000..478aec0 --- /dev/null +++ b/fixtures/golden/minimal/visibility-tags.json @@ -0,0 +1,10 @@ +[ + { + "name": "_epochSeconds", + "kind": "function", + "file_path": "src/utils/date.ts", + "line_start": 12, + "signature": "_epochSeconds(): number", + "doc_comment": "@internal Implementation helper — fixture for the `visibility-tags` recipe." + } +] diff --git a/fixtures/golden/scenarios.json b/fixtures/golden/scenarios.json index 5982c35..9deadbc 100644 --- a/fixtures/golden/scenarios.json +++ b/fixtures/golden/scenarios.json @@ -73,5 +73,25 @@ "id": "calls-consumer", "prompt": "What does the run function in consumer.ts call?", "sql": "SELECT DISTINCT callee_name FROM calls WHERE caller_name = 'run' AND file_path = 'src/consumer.ts' ORDER BY callee_name" + }, + { + "id": "deprecated-symbols", + "prompt": "Which symbols are flagged @deprecated in JSDoc?", + "recipe": "deprecated-symbols" + }, + { + "id": "visibility-tags", + "prompt": "Which symbols are tagged @internal / @private / @alpha / @beta?", + "recipe": "visibility-tags" + }, + { + "id": "files-hashes", + "prompt": "All indexed file paths with language and line count (powers `codemap validate`)", + "sql": "SELECT path, language, line_count FROM files ORDER BY path" + }, + { + "id": "barrel-files", + "prompt": "Top files by export count (barrel candidates)", + "recipe": "barrel-files" } ] diff --git a/fixtures/minimal/src/utils/date.ts b/fixtures/minimal/src/utils/date.ts index 69ba0d8..0c5f897 100644 --- a/fixtures/minimal/src/utils/date.ts +++ b/fixtures/minimal/src/utils/date.ts @@ -1,3 +1,14 @@ +/** + * @deprecated Use `Date.now()` directly. Kept as a fixture for the + * `deprecated-symbols` recipe golden test. + */ export function now(): number { return Date.now(); } + +/** + * @internal Implementation helper — fixture for the `visibility-tags` recipe. + */ +export function _epochSeconds(): number { + return Math.floor(Date.now() / 1000); +} diff --git a/src/cli/cmd-query.test.ts b/src/cli/cmd-query.test.ts index deffdd9..066f46f 100644 --- a/src/cli/cmd-query.test.ts +++ b/src/cli/cmd-query.test.ts @@ -81,6 +81,23 @@ describe("parseQueryRest", () => { }); }); + it("accepts -r as a short alias for --recipe", () => { + const r = parseQueryRest(["query", "--json", "-r", "fan-out"]); + const sql = getQueryRecipeSql("fan-out"); + expect(sql).toBeDefined(); + expect(r).toEqual({ + kind: "run", + sql: sql!, + json: true, + }); + }); + + it("errors when -r has no id", () => { + const r = parseQueryRest(["query", "-r"]); + expect(r.kind).toBe("error"); + if (r.kind === "error") expect(r.message).toContain("-r"); + }); + it("errors on unknown recipe", () => { const r = parseQueryRest(["query", "--recipe", "nope"]); expect(r.kind).toBe("error"); diff --git a/src/cli/cmd-query.ts b/src/cli/cmd-query.ts index 441e03c..c461fde 100644 --- a/src/cli/cmd-query.ts +++ b/src/cli/cmd-query.ts @@ -66,13 +66,12 @@ export function parseQueryRest( i += 2; continue; } - if (a === "--recipe") { + if (a === "--recipe" || a === "-r") { const name = rest[i + 1]; if (name === undefined || name.startsWith("-")) { return { kind: "error", - message: - 'codemap: "--recipe" requires a recipe id. Example: codemap query --recipe fan-out', + message: `codemap: "${a}" requires a recipe id. Example: codemap query ${a} fan-out`, }; } recipeId = name; @@ -172,10 +171,11 @@ export function printRecipeSqlToStdout(id: string): boolean { function formatRecipeHelpLines(): string { const ids = listQueryRecipeIds(); + const width = ids.reduce((n, id) => Math.max(n, id.length), 0); const lines = ids.map((id) => { const meta = QUERY_RECIPES[id]; const desc = meta?.description ?? ""; - return ` ${id.padEnd(16)} ${desc}`; + return ` ${id.padEnd(width)} ${desc}`; }); return lines.join("\n"); } @@ -186,30 +186,35 @@ function formatRecipeHelpLines(): string { export function printQueryCmdHelp(): void { const recipeBlock = formatRecipeHelpLines(); console.log(`Usage: codemap query [--json] "" - codemap query [--json] --recipe + codemap query [--json] --recipe (alias: -r) codemap query --recipes-json codemap query --print-sql Read-only SQL against .codemap.db (after at least one successful index run). The CLI does not cap row count — use SQL LIMIT (and ORDER BY) when you need a bounded result set. - --json Print a JSON array of row objects to stdout (for agents and scripts). - On error, prints a single object: {"error":""} to stdout. - - --recipe Run bundled SQL (no SQL string on the command line). - - --recipes-json Print all bundled recipes (id, description, sql) as JSON to stdout. No DB. - - --print-sql Print one recipe's SQL text to stdout (does not run the query). No DB. +Flags: + --json Print a JSON array of row objects to stdout (for agents and scripts). + On error, prints a single object: {"error":""} to stdout. + --recipe, -r Run bundled SQL (no SQL string on the command line). + --recipes-json Print all bundled recipes (id, description, sql) as JSON to stdout. No DB. + --print-sql Print one recipe's SQL text to stdout (does not run the query). No DB. + --help, -h Show this help. Bundled recipes: ${recipeBlock} Examples: + # Ad-hoc SQL codemap query "SELECT name, file_path FROM symbols LIMIT 10" codemap query --json "SELECT COUNT(*) AS n FROM symbols" + + # Bundled recipe (full flag and short alias) codemap query --recipe fan-out - codemap query --json --recipe fan-out-sample + codemap query -r fan-out + codemap query --json -r deprecated-symbols + + # Inspect recipes without touching the DB codemap query --recipes-json codemap query --print-sql fan-out `); diff --git a/src/cli/query-recipes.ts b/src/cli/query-recipes.ts index 770cfa5..7c96964 100644 --- a/src/cli/query-recipes.ts +++ b/src/cli/query-recipes.ts @@ -1,11 +1,11 @@ /** * One bundled recipe: id, human description, and SQL (canonical source for CLI and `--recipes-json`). */ -export type QueryRecipeCatalogEntry = { +export interface QueryRecipeCatalogEntry { id: string; description: string; sql: string; -}; +} /** * Bundled read-only SQL for `codemap query --recipe `. Keys match **`codemap query --help`**. @@ -104,6 +104,62 @@ FROM markers GROUP BY kind ORDER BY count DESC, kind ASC`, }, + /** + * Symbols documented with `@deprecated` in their leading JSDoc. Useful for + * agents to flag callers of soon-to-be-removed APIs before suggesting changes. + */ + "deprecated-symbols": { + description: + "Symbols whose JSDoc contains @deprecated (caller-warning candidates)", + sql: `SELECT name, kind, file_path, line_start, signature, doc_comment +FROM symbols +WHERE doc_comment LIKE '%@deprecated%' +ORDER BY file_path ASC, line_start ASC +LIMIT 50`, + }, + /** + * Symbols carrying JSDoc visibility tags (`@internal`, `@private`, `@alpha`, + * `@beta`). Useful for agents to know what is *not* part of the public API + * before suggesting imports or extending re-exports. + */ + "visibility-tags": { + description: + "Symbols tagged @internal / @private / @alpha / @beta in JSDoc", + sql: `SELECT name, kind, file_path, line_start, signature, doc_comment +FROM symbols +WHERE doc_comment LIKE '%@internal%' + OR doc_comment LIKE '%@private%' + OR doc_comment LIKE '%@alpha%' + OR doc_comment LIKE '%@beta%' +ORDER BY file_path ASC, line_start ASC +LIMIT 100`, + }, + /** + * All indexed file paths with their content hash. Powers the \`codemap validate\` + * CLI: callers diff this list against on-disk content to detect stale entries + * without paying to re-read every file. + */ + "files-hashes": { + description: + "All indexed files with content_hash (input for staleness checks)", + sql: `SELECT path, content_hash, language, line_count +FROM files +ORDER BY path ASC`, + }, + /** + * "Barrel" candidates — files that re-export a lot. High export count can + * indicate either an intentional public API surface or accidental fan-out; + * agents can use it to decide whether a new export should land here or stay local. + */ + "barrel-files": { + description: + "Top 20 files by export count (barrel / public-API candidates)", + sql: `SELECT file_path, COUNT(*) AS exports +FROM exports +GROUP BY file_path +ORDER BY exports DESC, file_path ASC +LIMIT 20`, + }, }; /** From efcb010a29a49ea085183dbaa9a695aec6cb11cd Mon Sep 17 00:00:00 2001 From: Sutu Sebastian Date: Mon, 27 Apr 2026 13:08:04 +0300 Subject: [PATCH 05/12] feat(cli): codemap validate, codemap context, --performance, friendlier no-DB error; JSDoc the public type surface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CLI commands and flags - codemap validate [--json] [paths...] — diffs disk SHA-256 against files.content_hash; statuses: stale | missing | unindexed; exits 1 on any drift (git-status semantics) so agents can branch on $? - codemap context [--compact] [--for ""] — stable JSON envelope (project metadata, top hubs, recent markers, recipe catalog). --for runs lightweight intent classification (refactor / debug / test / feature / explore / other) and returns matched recipe ids plus a hint - codemap --performance — per-phase breakdown (collect / parse / insert / index_create) plus top-10 slowest files by parse time during full rebuild; surfaces pathological inputs - Friendlier no-.codemap.db error — `no such table: ` rewrites to an actionable hint pointing at `codemap` / `codemap --full`, on both the JSON and human paths - bootstrap.ts whitelists the new subcommands and flag Public type surface (visible in dist/index.d.mts via the existing index re-exports) - New IndexPerformanceReport; IndexRunStats.performance? field - Per-field JSDoc on IndexResult, IndexRunStats, IndexPerformanceReport, IndexTableStats (snake_case key note), ResolvedCodemapConfig - Interface-level JSDoc on every db.ts row interface (FileRow, SymbolRow, ImportRow, ExportRow, ComponentRow, DependencyRow, MarkerRow, CssVariableRow, CssClassRow, CssKeyframeRow, CallRow, TypeMemberRow) with cross-links to docs/architecture.md § Schema as the single source - Per-field JSDoc on ParsedFile (clarifies error vs parseError, category semantics, CSS-only fields, cssImportSources main-thread conversion) - @param/@returns on getAdapterForExtension Implementation plumbing - ParsedFile gains optional parseMs?, populated by parse-worker-core.ts - RunIndexOptions.performance threads through index-engine.ts and run-index.ts - index-engine.ts times collect / parse / insert / createIndexes phases when the flag is on; bottom-of-summary block prints the breakdown plus the slowest_files list Auto-fixes from the new lint baseline - import type hoisting (consistent-type-specifier-style: prefer-top-level) - type X = {...} → interface X {...} for object shapes (ValidateRow, ValidateOpts, ContextEnvelope, ContextOpts) - switch case braces in src/parser.ts (12 keyword-mapping cases) and src/agents-init.ts Tests - 9 new tests for cmd-validate (parse + computeValidateRows: stale, missing, unindexed, dedup, sort) - 14 new tests for cmd-context (parse + classifyIntent: 6 categories + fallback) - 2 new cases on cmd-query for -r Changeset entered as patch (matches 0.x precedent for additive changes; schema unchanged). --- .changeset/agent-friendly-cli-recipes.md | 15 ++ scripts/benchmark-query-output.ts | 5 +- scripts/query-golden.ts | 7 +- src/adapters/builtin.ts | 11 + src/agents-init.ts | 27 ++- src/api.ts | 10 +- src/application/index-engine.ts | 82 +++++++- src/application/run-index.ts | 23 +- src/application/types.ts | 54 +++-- src/benchmark.ts | 6 +- src/cli/bootstrap.ts | 12 +- src/cli/cmd-context.test.ts | 87 ++++++++ src/cli/cmd-context.ts | 257 +++++++++++++++++++++++ src/cli/cmd-index.ts | 2 + src/cli/cmd-validate.test.ts | 127 +++++++++++ src/cli/cmd-validate.ts | 176 ++++++++++++++++ src/cli/main.ts | 42 ++++ src/config.test.ts | 2 +- src/config.ts | 10 +- src/db.ts | 98 ++++++++- src/parse-worker-core.ts | 2 + src/parsed-types.ts | 39 +++- src/parser.ts | 42 ++-- src/sqlite-db.ts | 4 +- 24 files changed, 1070 insertions(+), 70 deletions(-) create mode 100644 .changeset/agent-friendly-cli-recipes.md create mode 100644 src/cli/cmd-context.test.ts create mode 100644 src/cli/cmd-context.ts create mode 100644 src/cli/cmd-validate.test.ts create mode 100644 src/cli/cmd-validate.ts diff --git a/.changeset/agent-friendly-cli-recipes.md b/.changeset/agent-friendly-cli-recipes.md new file mode 100644 index 0000000..c095943 --- /dev/null +++ b/.changeset/agent-friendly-cli-recipes.md @@ -0,0 +1,15 @@ +--- +"@stainless-code/codemap": patch +--- + +Agent-friendly CLI surface: `codemap validate`, `codemap context`, `--performance`, `-r` recipe alias, and four new bundled query recipes. + +- **New: `codemap validate [--json] [paths...]`** — diffs the on-disk SHA-256 of indexed files against `files.content_hash` and prints stale / missing / unindexed rows. Lets agents skip re-reads they don't need; exits `1` on any drift (git-status semantics) +- **New: `codemap context [--compact] [--for ""]`** — emits a stable JSON envelope (project metadata, top hubs, recent markers, recipe catalog) for any agent or editor that wants the index in one cheap shot. `--for` runs lightweight intent classification (refactor / debug / test / feature / explore / other) and returns matched recipe ids plus a hint +- **New: `codemap --performance`** flag — prints a per-phase timing breakdown (collect / parse / insert / index_create) and the top-10 slowest files by parse time during full rebuilds, for triaging giant or pathological inputs +- **New: `-r` short alias for `codemap query --recipe`** + cleaner organized `codemap query --help` (sectioned flags, dynamic recipe-id padding, examples for both forms) +- **New recipes**: `deprecated-symbols` (`@deprecated` JSDoc tag scan), `visibility-tags` (`@internal` / `@private` / `@alpha` / `@beta`), `files-hashes` (powers `validate`), `barrel-files` (top files by export count) +- **Friendlier no-`.codemap.db` error**: `no such table: ` now rewrites to an actionable hint pointing at `codemap` / `codemap --full`, on both the JSON and human paths +- **Public type surface**: new `IndexPerformanceReport`; `IndexRunStats.performance?` field; per-field JSDoc coverage on `IndexResult`, `IndexRunStats`, `ResolvedCodemapConfig`, all `db.ts` row interfaces (`FileRow`, `SymbolRow`, `ImportRow`, `ExportRow`, `ComponentRow`, `DependencyRow`, `MarkerRow`, `CssVariableRow`, `CssClassRow`, `CssKeyframeRow`, `CallRow`, `TypeMemberRow`), and `ParsedFile` +- **Documentation**: README now leads with a "What you get" Grep/Read vs Codemap capability table and a "Daily commands" stripe; `docs/why-codemap.md` adds a "What Codemap is **not**" anti-pitch section and a scenario-keyed token-savings table (single lookup → 50-turn session) replacing the earlier hand-wave +- **Stricter lint baseline**: enabled `prefer-const`, `consistent-type-specifier-style`, `consistent-type-definitions`, `no-confusing-non-null-assertion`, `no-unnecessary-{boolean-literal-compare,template-expression,type-assertion}`, `prefer-{includes,nullish-coalescing,optional-chain}`, and `unicorn/switch-case-braces` diff --git a/scripts/benchmark-query-output.ts b/scripts/benchmark-query-output.ts index bd45230..37155ac 100644 --- a/scripts/benchmark-query-output.ts +++ b/scripts/benchmark-query-output.ts @@ -13,7 +13,10 @@ import { fileURLToPath } from "node:url"; const REPO_ROOT = join(dirname(fileURLToPath(import.meta.url)), ".."); const INDEX_TS = join(REPO_ROOT, "src/index.ts"); -type Scenario = { label: string; args: string[] }; +interface Scenario { + label: string; + args: string[]; +} const SCENARIOS: Scenario[] = [ { diff --git a/scripts/query-golden.ts b/scripts/query-golden.ts index 11b90a1..4093a77 100644 --- a/scripts/query-golden.ts +++ b/scripts/query-golden.ts @@ -5,11 +5,8 @@ import { fileURLToPath } from "node:url"; import { createCodemap } from "../src/api"; import { getQueryRecipeSql } from "../src/cli/query-recipes"; -import { - type GoldenMatch, - type GoldenScenario, - parseScenariosJson, -} from "./query-golden/schema"; +import { parseScenariosJson } from "./query-golden/schema"; +import type { GoldenMatch, GoldenScenario } from "./query-golden/schema"; const REPO_ROOT = join(dirname(fileURLToPath(import.meta.url)), ".."); diff --git a/src/adapters/builtin.ts b/src/adapters/builtin.ts index 1286374..4e54e34 100644 --- a/src/adapters/builtin.ts +++ b/src/adapters/builtin.ts @@ -77,6 +77,17 @@ export const BUILTIN_ADAPTERS: readonly LanguageAdapter[] = [ }, ]; +/** + * First-match lookup of a {@link LanguageAdapter} by file extension. + * + * @param ext - File extension **with leading dot**, e.g. `".tsx"`. Compared + * verbatim against each adapter's `extensions` array. + * @param adapters - Adapter list to search; defaults to {@link BUILTIN_ADAPTERS}. + * Pass a custom list to support project-local adapters once a registration + * API lands (see [docs/roadmap.md](../../docs/roadmap.md)). + * @returns The first adapter whose `extensions` contains `ext`, or `undefined` + * when no adapter matches (the indexer then falls back to markers-only text). + */ export function getAdapterForExtension( ext: string, adapters: readonly LanguageAdapter[] = BUILTIN_ADAPTERS, diff --git a/src/agents-init.ts b/src/agents-init.ts index 276f152..a2dbe8a 100644 --- a/src/agents-init.ts +++ b/src/agents-init.ts @@ -366,10 +366,11 @@ export function applyAgentsInitTargets( for (const t of targets) { switch (t) { - case "cursor": + case "cursor": { applyCursorIntegration(projectRoot, linkMode, force); break; - case "windsurf": + } + case "windsurf": { wireAgentsRulesTo( projectRoot, join(projectRoot, ".windsurf", "rules"), @@ -378,7 +379,8 @@ export function applyAgentsInitTargets( force, ); break; - case "continue": + } + case "continue": { wireAgentsRulesTo( projectRoot, join(projectRoot, ".continue", "rules"), @@ -387,7 +389,8 @@ export function applyAgentsInitTargets( force, ); break; - case "cline": + } + case "cline": { wireAgentsRulesTo( projectRoot, join(projectRoot, ".clinerules"), @@ -396,7 +399,8 @@ export function applyAgentsInitTargets( force, ); break; - case "amazon-q": + } + case "amazon-q": { wireAgentsRulesTo( projectRoot, join(projectRoot, ".amazonq", "rules"), @@ -405,7 +409,8 @@ export function applyAgentsInitTargets( force, ); break; - case "claude-md": + } + case "claude-md": { upsertCodemapPointerFile( join(projectRoot, "CLAUDE.md"), CLAUDE_MD_TEMPLATE, @@ -413,7 +418,8 @@ export function applyAgentsInitTargets( force, ); break; - case "copilot": + } + case "copilot": { mkdirSync(join(projectRoot, ".github"), { recursive: true }); upsertCodemapPointerFile( join(projectRoot, ".github", "copilot-instructions.md"), @@ -422,7 +428,8 @@ export function applyAgentsInitTargets( force, ); break; - case "agents-md": + } + case "agents-md": { upsertCodemapPointerFile( join(projectRoot, "AGENTS.md"), AGENTS_MD_TEMPLATE, @@ -430,7 +437,8 @@ export function applyAgentsInitTargets( force, ); break; - case "gemini-md": + } + case "gemini-md": { upsertCodemapPointerFile( join(projectRoot, "GEMINI.md"), GEMINI_MD_TEMPLATE, @@ -438,6 +446,7 @@ export function applyAgentsInitTargets( force, ); break; + } } } } diff --git a/src/api.ts b/src/api.ts index 48d0718..d62a9b8 100644 --- a/src/api.ts +++ b/src/api.ts @@ -1,13 +1,11 @@ import { resolve } from "node:path"; import { queryRows } from "./application/index-engine"; -import { runCodemapIndex, type RunIndexOptions } from "./application/run-index"; +import { runCodemapIndex } from "./application/run-index"; +import type { RunIndexOptions } from "./application/run-index"; import type { IndexResult } from "./application/types"; -import { - type CodemapUserConfig, - loadUserConfig, - resolveCodemapConfig, -} from "./config"; +import { loadUserConfig, resolveCodemapConfig } from "./config"; +import type { CodemapUserConfig } from "./config"; import { closeDb, openDb } from "./db"; import { configureResolver } from "./resolver"; import { diff --git a/src/application/index-engine.ts b/src/application/index-engine.ts index 999f959..b47a59d 100644 --- a/src/application/index-engine.ts +++ b/src/application/index-engine.ts @@ -28,9 +28,8 @@ import { insertCalls, getAllFileHashes, SCHEMA_VERSION, - type CodemapDatabase, - type FileRow, } from "../db"; +import type { CodemapDatabase, FileRow } from "../db"; import { globSync } from "../glob-sync"; import { hashContent } from "../hash"; import { extractMarkers } from "../markers"; @@ -39,7 +38,11 @@ import { extractFileData } from "../parser"; import { resolveImports } from "../resolver"; import { getIncludePatterns, getProjectRoot, isPathExcluded } from "../runtime"; import { parseFilesParallel } from "../worker-pool"; -import type { IndexRunStats, IndexTableStats } from "./types"; +import type { + IndexPerformanceReport, + IndexRunStats, + IndexTableStats, +} from "./types"; export const VALID_EXTENSIONS = new Set(Object.keys(LANG_MAP)); @@ -270,10 +273,15 @@ export async function indexFiles( filePaths: string[], fullRebuild: boolean, knownIndexedPaths?: Set, - options?: { quiet?: boolean }, + options?: { quiet?: boolean; performance?: boolean; collectMs?: number }, ): Promise { const quiet = options?.quiet ?? false; + const wantPerformance = options?.performance === true; const startTime = performance.now(); + let parseMs = 0; + let insertMs = 0; + let indexCreateMs = 0; + let slowest: { path: string; parse_ms: number }[] = []; if (fullRebuild) { dropAll(db); @@ -290,9 +298,20 @@ export async function indexFiles( let skipped = 0; if (fullRebuild) { + const parseStart = performance.now(); const results = await parseFilesParallel(filePaths); + parseMs = performance.now() - parseStart; results.sort((a, b) => a.relPath.localeCompare(b.relPath)); + if (wantPerformance) { + slowest = results + .filter((r) => typeof r.parseMs === "number") + .map((r) => ({ path: r.relPath, parse_ms: Math.round(r.parseMs!) })) + .sort((a, b) => b.parse_ms - a.parse_ms) + .slice(0, 10); + } + const insertStart = performance.now(); indexed = insertParsedResults(db, results, indexedPaths); + insertMs = performance.now() - insertStart; } else { const existingHashes = getAllFileHashes(db); const root = getProjectRoot(); @@ -390,7 +409,9 @@ export async function indexFiles( } if (fullRebuild) { + const idxStart = performance.now(); createIndexes(db); + indexCreateMs = performance.now() - idxStart; db.run("PRAGMA synchronous = NORMAL"); db.run("PRAGMA foreign_keys = ON"); setMeta(db, "schema_version", String(SCHEMA_VERSION)); @@ -407,6 +428,19 @@ export async function indexFiles( const elapsed = Math.round(performance.now() - startTime); const stats = fetchTableStats(db); + let perf: IndexPerformanceReport | undefined; + if (wantPerformance) { + const collectMs = Math.round(options?.collectMs ?? 0); + perf = { + collect_ms: collectMs, + parse_ms: Math.round(parseMs), + insert_ms: Math.round(insertMs), + index_create_ms: Math.round(indexCreateMs), + total_ms: elapsed, + slowest_files: slowest, + }; + } + if (!quiet) { console.log( `\n Codemap ${fullRebuild ? "(full rebuild)" : "(incremental)"}`, @@ -418,6 +452,27 @@ export async function indexFiles( for (const [key, value] of Object.entries(stats)) { console.log(` ${(key + ":").padEnd(14)}${value}`); } + if (perf) { + console.log(` ───────────────────────────────────`); + console.log(` Performance breakdown (ms)`); + console.log(` collect: ${perf.collect_ms} (file glob)`); + console.log(` parse: ${perf.parse_ms} (workers)`); + console.log(` insert: ${perf.insert_ms} (bulk SQL)`); + console.log( + ` index_create: ${perf.index_create_ms} (B-tree build)`, + ); + console.log( + ` index_run: ${perf.total_ms} (parse + insert + index_create + DDL)`, + ); + if (perf.slowest_files.length > 0) { + console.log( + ` Top ${perf.slowest_files.length} slowest files (parse ms)`, + ); + for (const f of perf.slowest_files) { + console.log(` ${String(f.parse_ms).padStart(5)} ${f.path}`); + } + } + } console.log(); } @@ -427,6 +482,7 @@ export async function indexFiles( elapsedMs: elapsed, fullRebuild, stats, + performance: perf, }; } @@ -491,7 +547,9 @@ export function printQueryResult( } return 0; } catch (err) { - const msg = err instanceof Error ? err.message : String(err); + const msg = enrichQueryError( + err instanceof Error ? err.message : String(err), + ); if (json) { console.log(JSON.stringify({ error: msg })); } else { @@ -503,6 +561,20 @@ export function printQueryResult( } } +/** + * Rewrites raw SQLite errors that almost always indicate a missing or empty + * `.codemap.db` into an actionable hint. Other errors are returned unchanged. + */ +function enrichQueryError(message: string): string { + if ( + /^no such table:\s*\w+/i.test(message) || + /^no such column:\s*\w+/i.test(message) + ) { + return `${message} — run \`codemap\` (or \`codemap --full\`) first to build the index, then re-run your query.`; + } + return message; +} + /** * Open the index, run SQL, return all rows, then close. Used by the public **`Codemap.query`** method. * @throws On invalid SQL or database errors (same as `better-sqlite3`-style `.all()`). diff --git a/src/application/run-index.ts b/src/application/run-index.ts index 83959b9..2b80be4 100644 --- a/src/application/run-index.ts +++ b/src/application/run-index.ts @@ -49,6 +49,11 @@ export interface RunIndexOptions { * Suppresses progress logs; parse failures may still be printed. Defaults to `false`. */ quiet?: boolean; + /** + * Emits a per-phase timing breakdown and the top-10 slowest files (full + * rebuild only). Off by default — wired by the CLI's `--performance` flag. + */ + performance?: boolean; } /** @@ -68,10 +73,18 @@ export async function runCodemapIndex( const quiet = options.quiet ?? false; const mode: IndexMode = options.mode ?? "incremental"; + const wantPerformance = options.performance === true; + if (mode === "full") { if (!quiet) console.log(" Full rebuild requested..."); + const collectStart = performance.now(); const files = collectFiles(); - const run = await indexFiles(db, files, true, undefined, { quiet }); + const collectMs = performance.now() - collectStart; + const run = await indexFiles(db, files, true, undefined, { + quiet, + performance: wantPerformance, + collectMs, + }); return { mode: "full", indexed: run.indexed, @@ -156,8 +169,14 @@ export async function runCodemapIndex( " No previous index or incompatible history, doing full rebuild...", ); } + const fallbackCollectStart = performance.now(); const files = collectFiles(); - const run = await indexFiles(db, files, true, undefined, { quiet }); + const fallbackCollectMs = performance.now() - fallbackCollectStart; + const run = await indexFiles(db, files, true, undefined, { + quiet, + performance: wantPerformance, + collectMs: fallbackCollectMs, + }); return { mode: "full", indexed: run.indexed, diff --git a/src/application/types.ts b/src/application/types.ts index 32a386f..5e02a33 100644 --- a/src/application/types.ts +++ b/src/application/types.ts @@ -1,5 +1,8 @@ /** - * Row counts per table after an index run (mirrors CLI summary output). + * Row counts per table after an index run (mirrors CLI summary output). Keys + * use the **SQLite table names** (snake_case: `type_members`, `css_vars`, + * `css_classes`, `css_keyframes`) so the same identifiers work directly in + * `SELECT … FROM ` queries. */ export interface IndexTableStats extends Record { files: number; @@ -16,37 +19,62 @@ export interface IndexTableStats extends Record { css_keyframes: number; } +/** + * Optional per-phase timing breakdown emitted when `--performance` is set. + * Top-10 slowest files are surfaced for quick triage of pathological inputs + * (giant generated files, regex-heavy fixtures, etc.). + */ +export interface IndexPerformanceReport { + /** Time to glob the project root and collect candidate paths. */ + collect_ms: number; + /** Worker-side parse time (sum across workers, full rebuild only). */ + parse_ms: number; + /** Bulk SQL INSERT time on the main thread. */ + insert_ms: number; + /** Deferred B-tree build via `CREATE INDEX` (full rebuild only). */ + index_create_ms: number; + /** + * `indexFiles` wall-clock — `parse + insert + index_create + DDL`. Does + * **not** include `collect_ms` (collect happens before `indexFiles`); the + * end-to-end run wall is `collect_ms + total_ms`. + */ + total_ms: number; + /** Up to 10 files with the highest per-file parse time, descending. */ + slowest_files: { path: string; parse_ms: number }[]; +} + /** * Per-run counters; see {@link IndexResult} for the public shape returned from indexing APIs. */ export interface IndexRunStats { + /** Number of files written or re-indexed in this run. */ indexed: number; + /** Files whose `content_hash` matched the index (no work done). */ skipped: number; + /** Wall-clock time for the indexing pipeline, in milliseconds. */ elapsedMs: number; + /** `true` if this run dropped and rebuilt all tables; `false` for incremental / targeted. */ fullRebuild: boolean; + /** Row counts per table after the run completed. */ stats: IndexTableStats; + /** Set only when `--performance` (or `RunIndexOptions.performance`) is on. */ + performance?: IndexPerformanceReport; } /** * Outcome of `Codemap#index` or `runCodemapIndex` (CLI and programmatic index runs). */ export interface IndexResult { - /** - * How the index was updated. - */ + /** How the index was updated. */ mode: "full" | "incremental" | "files"; - /** - * Files written or re-indexed in this run. - */ + /** Files written or re-indexed in this run. */ indexed: number; - /** - * Files skipped (unchanged hash). - */ + /** Files skipped (unchanged hash). */ skipped: number; + /** Wall-clock time for the indexing pipeline, in milliseconds. */ elapsedMs: number; + /** Row counts per table after the run completed. */ stats: IndexTableStats; - /** - * Set when no file bodies were indexed (already fresh, empty `files` list, or deletions-only pass). - */ + /** Set when no file bodies were indexed (already fresh, empty `files` list, or deletions-only pass). */ idle?: boolean; } diff --git a/src/benchmark.ts b/src/benchmark.ts index 677a194..9fc945f 100644 --- a/src/benchmark.ts +++ b/src/benchmark.ts @@ -2,10 +2,8 @@ import { existsSync, statSync } from "node:fs"; import { join, resolve } from "node:path"; import { loadScenariosFromConfigFile } from "./benchmark-config"; -import { - getDefaultScenarios, - type Scenario, -} from "./benchmark-default-scenarios"; +import { getDefaultScenarios } from "./benchmark-default-scenarios"; +import type { Scenario } from "./benchmark-default-scenarios"; import { loadUserConfig, resolveCodemapConfig } from "./config"; import { closeDb, openDb } from "./db"; import { configureResolver } from "./resolver"; diff --git a/src/cli/bootstrap.ts b/src/cli/bootstrap.ts index dab4449..4744109 100644 --- a/src/cli/bootstrap.ts +++ b/src/cli/bootstrap.ts @@ -16,6 +16,12 @@ Query: codemap query [--json] "" codemap query [--json] --recipe +Validate (compare on-disk SHA-256 to indexed hash): + codemap validate [--json] [paths...] + +Context (project snapshot envelope for any agent): + codemap context [--compact] [--for ""] + Agents: codemap agents init [--force] [--interactive|-i] @@ -27,6 +33,8 @@ Environment: CODEMAP_ROOT (same as --root) Options: --full Full rebuild + --performance Print per-phase timing breakdown + top-10 slowest files + (full rebuild only) --help, -h Show this help `); } @@ -42,6 +50,8 @@ export function printVersion(): void { export function validateIndexModeArgs(rest: string[]): void { if (rest.length === 0) return; if (rest[0] === "query") return; + if (rest[0] === "validate") return; + if (rest[0] === "context") return; if (rest[0] === "agents") { if (rest[1] === "init") return; @@ -54,7 +64,7 @@ export function validateIndexModeArgs(rest: string[]): void { let i = 0; while (i < rest.length) { const a = rest[i]; - if (a === "--full") { + if (a === "--full" || a === "--performance") { i++; continue; } diff --git a/src/cli/cmd-context.test.ts b/src/cli/cmd-context.test.ts new file mode 100644 index 0000000..cef9238 --- /dev/null +++ b/src/cli/cmd-context.test.ts @@ -0,0 +1,87 @@ +import { describe, expect, it } from "bun:test"; + +import { classifyIntent, parseContextRest } from "./cmd-context"; + +describe("parseContextRest", () => { + it("returns help for --help / -h", () => { + expect(parseContextRest(["context", "--help"]).kind).toBe("help"); + expect(parseContextRest(["context", "-h"]).kind).toBe("help"); + }); + + it("parses no args as default run", () => { + expect(parseContextRest(["context"])).toEqual({ + kind: "run", + compact: false, + intent: null, + }); + }); + + it("parses --compact", () => { + expect(parseContextRest(["context", "--compact"])).toEqual({ + kind: "run", + compact: true, + intent: null, + }); + }); + + it("parses --for with quoted intent", () => { + expect(parseContextRest(["context", "--for", "refactor auth"])).toEqual({ + kind: "run", + compact: false, + intent: "refactor auth", + }); + }); + + it("parses --compact + --for in any order", () => { + expect( + parseContextRest(["context", "--for", "fix bug", "--compact"]), + ).toEqual({ kind: "run", compact: true, intent: "fix bug" }); + }); + + it("errors when --for has no value", () => { + const r = parseContextRest(["context", "--for"]); + expect(r.kind).toBe("error"); + }); + + it("errors when --for value looks like a flag", () => { + const r = parseContextRest(["context", "--for", "--compact"]); + expect(r.kind).toBe("error"); + }); + + it("rejects unknown options", () => { + expect(parseContextRest(["context", "--nope"]).kind).toBe("error"); + }); +}); + +describe("classifyIntent", () => { + it("classifies refactor intent", () => { + const r = classifyIntent("refactor the auth module"); + expect(r.classified_as).toBe("refactor"); + expect(r.matched_recipes).toContain("fan-in"); + }); + + it("classifies debug intent", () => { + expect(classifyIntent("fix this crash").classified_as).toBe("debug"); + expect(classifyIntent("debug regression").classified_as).toBe("debug"); + }); + + it("classifies test intent", () => { + expect(classifyIntent("add coverage for parser").classified_as).toBe( + "test", + ); + }); + + it("classifies feature intent", () => { + expect(classifyIntent("implement dark mode").classified_as).toBe("feature"); + }); + + it("classifies explore intent", () => { + expect( + classifyIntent("give me an overview of the repo").classified_as, + ).toBe("explore"); + }); + + it("falls back to other for unmatched intent", () => { + expect(classifyIntent("xyz").classified_as).toBe("other"); + }); +}); diff --git a/src/cli/cmd-context.ts b/src/cli/cmd-context.ts new file mode 100644 index 0000000..f76c6bd --- /dev/null +++ b/src/cli/cmd-context.ts @@ -0,0 +1,257 @@ +import { loadUserConfig, resolveCodemapConfig } from "../config"; +import { closeDb, getMeta, openDb, SCHEMA_VERSION } from "../db"; +import type { CodemapDatabase } from "../db"; +import { configureResolver } from "../resolver"; +import { getProjectRoot, getTsconfigPath, initCodemap } from "../runtime"; +import { CODEMAP_VERSION } from "../version"; +import { QUERY_RECIPES } from "./query-recipes"; + +/** + * Snapshot envelope emitted by `codemap context`. Stable JSON shape any agent + * or CLI can pipe into a prompt without parsing prose. + */ +export interface ContextEnvelope { + codemap: { + cli_version: string; + schema_version: number; + }; + project: { + root: string; + file_count: number; + last_indexed_commit: string | null; + languages: { language: string; files: number }[]; + }; + hubs?: { to_path: string; fan_in: number }[]; + recent_markers?: { + file_path: string; + line_number: number; + kind: string; + content: string; + }[]; + recipes: { id: string; description: string }[]; + intent?: { + input: string; + classified_as: string; + matched_recipes: string[]; + hint: string; + }; +} + +interface ContextOpts { + root: string; + configFile: string | undefined; + compact: boolean; + intent: string | null; +} + +/** + * Print **`codemap context`** usage. + */ +export function printContextCmdHelp(): void { + console.log(`Usage: codemap context [--compact] [--for ""] + +Emit a JSON envelope describing the current index — project metadata, top +hubs (fan-in), recent markers, and the bundled recipe catalog. Designed for +agents and editors that want a single-command "give me everything cheap". + +Flags: + --compact Drop hubs and recent_markers (smaller payload). + --for "" Pre-classify a free-text intent (refactor, debug, test, + feature, explore) and recommend recipes that match. + --help, -h Show this help. + +Examples: + codemap context + codemap context --compact + codemap context --for "refactor the auth module" +`); +} + +/** + * Parse `argv` after the bootstrap split: `rest[0]` must be `"context"`. + */ +export function parseContextRest( + rest: string[], +): + | { kind: "help" } + | { kind: "error"; message: string } + | { kind: "run"; compact: boolean; intent: string | null } { + if (rest[0] !== "context") { + throw new Error("parseContextRest: expected context"); + } + let compact = false; + let intent: string | null = null; + for (let i = 1; i < rest.length; i++) { + const a = rest[i]; + if (a === "--help" || a === "-h") return { kind: "help" }; + if (a === "--compact") { + compact = true; + continue; + } + if (a === "--for") { + const v = rest[i + 1]; + if (v === undefined || v.startsWith("--")) { + return { + kind: "error", + message: 'codemap: "--for" requires an intent string in quotes.', + }; + } + intent = v; + i++; + continue; + } + return { + kind: "error", + message: `codemap: unknown option "${a}". Run codemap context --help for usage.`, + }; + } + return { kind: "run", compact, intent }; +} + +/** + * Map a free-text intent into a coarse category and a list of recipe ids + * worth running first. Pure regex matching — agents can override or ignore it. + */ +export function classifyIntent(intent: string): { + classified_as: string; + matched_recipes: string[]; + hint: string; +} { + const t = intent.toLowerCase(); + if (/refactor|rename|restructur|extract|move\b/.test(t)) { + return { + classified_as: "refactor", + matched_recipes: [ + "fan-in", + "fan-out", + "barrel-files", + "deprecated-symbols", + ], + hint: "Inspect fan-in / fan-out before moving symbols; barrel-files surfaces public-API hubs; deprecated-symbols flags risky callers.", + }; + } + if (/bug|fix|debug|error|crash|broken|regress/.test(t)) { + return { + classified_as: "debug", + matched_recipes: ["markers-by-kind", "fan-in", "deprecated-symbols"], + hint: "Markers (TODO/FIXME) and deprecated-symbols often hint at known gotchas; fan-in shows the blast radius of a change.", + }; + } + if (/test|coverage|spec|mock/.test(t)) { + return { + classified_as: "test", + matched_recipes: ["files-largest", "fan-in", "components-by-hooks"], + hint: "files-largest and fan-in surface high-leverage code worth testing first.", + }; + } + if (/add|implement|create|new feature|introduce|build/.test(t)) { + return { + classified_as: "feature", + matched_recipes: ["barrel-files", "components-by-hooks", "fan-out"], + hint: "barrel-files shows where new exports usually land; fan-out shows the dependency reach of starting points.", + }; + } + if (/explore|understand|read|tour|map|overview/.test(t)) { + return { + classified_as: "explore", + matched_recipes: [ + "index-summary", + "fan-in", + "files-largest", + "barrel-files", + ], + hint: "Start with index-summary for shape, fan-in for hubs, then drill into files-largest.", + }; + } + return { + classified_as: "other", + matched_recipes: ["index-summary", "fan-in", "markers-by-kind"], + hint: "No specific category matched — the index-summary / fan-in / markers triple is a safe default.", + }; +} + +/** + * Build the envelope from an open DB. Pure-ish (reads from DB but takes no I/O + * outside of it) — covered by unit tests against a temp DB. + */ +export function buildContextEnvelope( + db: CodemapDatabase, + projectRoot: string, + opts: { compact: boolean; intent: string | null }, +): ContextEnvelope { + const fileCount = readScalarInt(db, "SELECT COUNT(*) AS n FROM files"); + const lastCommit = getMeta(db, "last_indexed_commit") ?? null; + const languages = ( + db + .query( + "SELECT language, COUNT(*) AS files FROM files GROUP BY language ORDER BY files DESC, language ASC", + ) + .all() as { language: string; files: number }[] + ).map((r) => ({ language: r.language, files: r.files })); + + const envelope: ContextEnvelope = { + codemap: { + cli_version: CODEMAP_VERSION, + schema_version: SCHEMA_VERSION, + }, + project: { + root: projectRoot, + file_count: fileCount, + last_indexed_commit: lastCommit, + languages, + }, + recipes: Object.entries(QUERY_RECIPES).map(([id, meta]) => ({ + id, + description: meta.description, + })), + }; + + if (!opts.compact) { + envelope.hubs = db + .query(QUERY_RECIPES["fan-in"]!.sql) + .all() as ContextEnvelope["hubs"]; + envelope.recent_markers = db + .query( + "SELECT file_path, line_number, kind, content FROM markers ORDER BY file_path ASC, line_number ASC LIMIT 20", + ) + .all() as ContextEnvelope["recent_markers"]; + } + + if (opts.intent !== null) { + const cls = classifyIntent(opts.intent); + envelope.intent = { input: opts.intent, ...cls }; + } + + return envelope; +} + +function readScalarInt(db: CodemapDatabase, sql: string): number { + const row = db.query(sql).get() as { n?: number } | undefined; + return row?.n ?? 0; +} + +/** + * Initialize Codemap for `opts.root`, then print the context envelope as JSON. + */ +export async function runContextCmd(opts: ContextOpts): Promise { + try { + const user = await loadUserConfig(opts.root, opts.configFile); + initCodemap(resolveCodemapConfig(opts.root, user)); + configureResolver(getProjectRoot(), getTsconfigPath()); + const db = openDb(); + let envelope: ContextEnvelope; + try { + envelope = buildContextEnvelope(db, getProjectRoot(), { + compact: opts.compact, + intent: opts.intent, + }); + } finally { + closeDb(db, { readonly: true }); + } + console.log(JSON.stringify(envelope, null, 2)); + } catch (err) { + const msg = err instanceof Error ? err.message : String(err); + console.log(JSON.stringify({ error: msg })); + process.exitCode = 1; + } +} diff --git a/src/cli/cmd-index.ts b/src/cli/cmd-index.ts index 46230a8..9880a96 100644 --- a/src/cli/cmd-index.ts +++ b/src/cli/cmd-index.ts @@ -34,8 +34,10 @@ export async function runIndexCmd(opts: { } } else { const fullRebuild = args.includes("--full"); + const performance = args.includes("--performance"); await runCodemapIndex(db, { mode: fullRebuild ? "full" : "incremental", + performance, }); } } finally { diff --git a/src/cli/cmd-validate.test.ts b/src/cli/cmd-validate.test.ts new file mode 100644 index 0000000..3adc331 --- /dev/null +++ b/src/cli/cmd-validate.test.ts @@ -0,0 +1,127 @@ +import { afterEach, beforeEach, describe, expect, it } from "bun:test"; +import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; + +import { resolveCodemapConfig } from "../config"; +import { closeDb, openDb } from "../db"; +import { hashContent } from "../hash"; +import { initCodemap } from "../runtime"; +import { computeValidateRows, parseValidateRest } from "./cmd-validate"; +import type { ValidateRow } from "./cmd-validate"; + +let tmpRoot = ""; + +beforeEach(() => { + tmpRoot = mkdtempSync(join(tmpdir(), "codemap-validate-")); + mkdirSync(join(tmpRoot, "src"), { recursive: true }); + initCodemap(resolveCodemapConfig(tmpRoot, {})); + const db = openDb(); + db.run( + "CREATE TABLE IF NOT EXISTS files (path TEXT PRIMARY KEY, content_hash TEXT, size INTEGER, line_count INTEGER, language TEXT, last_modified INTEGER, indexed_at INTEGER) STRICT", + ); + closeDb(db, { readonly: false }); +}); + +afterEach(() => { + rmSync(tmpRoot, { recursive: true, force: true }); +}); + +function seedIndex(rows: { path: string; content_hash: string }[]) { + const db = openDb(); + try { + for (const r of rows) { + db.run( + "INSERT INTO files (path, content_hash, size, line_count, language, last_modified, indexed_at) VALUES (?, ?, 0, 0, 'ts', 0, 0)", + [r.path, r.content_hash], + ); + } + } finally { + closeDb(db, { readonly: false }); + } +} + +function withDb(fn: (db: ReturnType) => T): T { + const db = openDb(); + try { + return fn(db); + } finally { + closeDb(db, { readonly: true }); + } +} + +describe("parseValidateRest", () => { + it("returns help for --help", () => { + expect(parseValidateRest(["validate", "--help"]).kind).toBe("help"); + expect(parseValidateRest(["validate", "-h"]).kind).toBe("help"); + }); + + it("parses no args (check all)", () => { + expect(parseValidateRest(["validate"])).toEqual({ + kind: "run", + paths: [], + json: false, + }); + }); + + it("parses --json with paths", () => { + expect(parseValidateRest(["validate", "--json", "a.ts", "b.ts"])).toEqual({ + kind: "run", + paths: ["a.ts", "b.ts"], + json: true, + }); + }); + + it("rejects unknown option", () => { + const r = parseValidateRest(["validate", "--nope"]); + expect(r.kind).toBe("error"); + }); +}); + +describe("computeValidateRows", () => { + it("returns empty when everything matches", () => { + const content = "export const a = 1\n"; + writeFileSync(join(tmpRoot, "src/a.ts"), content); + seedIndex([{ path: "src/a.ts", content_hash: hashContent(content) }]); + const rows = withDb((db) => computeValidateRows(db, tmpRoot, [])); + expect(rows).toEqual([]); + }); + + it("flags stale entries", () => { + const old = "export const a = 1\n"; + writeFileSync(join(tmpRoot, "src/a.ts"), "export const a = 2\n"); + seedIndex([{ path: "src/a.ts", content_hash: hashContent(old) }]); + const rows = withDb((db) => computeValidateRows(db, tmpRoot, [])); + expect(rows).toEqual([{ path: "src/a.ts", status: "stale" }]); + }); + + it("flags missing files", () => { + seedIndex([{ path: "src/gone.ts", content_hash: "deadbeef" }]); + const rows = withDb((db) => computeValidateRows(db, tmpRoot, [])); + expect(rows).toEqual([{ path: "src/gone.ts", status: "missing" }]); + }); + + it("flags unindexed files when explicit paths are passed", () => { + writeFileSync(join(tmpRoot, "src/new.ts"), "export const x = 0\n"); + const rows = withDb((db) => + computeValidateRows(db, tmpRoot, ["src/new.ts"]), + ); + expect(rows).toEqual([{ path: "src/new.ts", status: "unindexed" }]); + }); + + it("dedupes paths and sorts by path", () => { + writeFileSync(join(tmpRoot, "src/a.ts"), "v2\n"); + writeFileSync(join(tmpRoot, "src/b.ts"), "v2\n"); + seedIndex([ + { path: "src/a.ts", content_hash: hashContent("v1\n") }, + { path: "src/b.ts", content_hash: hashContent("v1\n") }, + ]); + const rows = withDb((db) => + computeValidateRows(db, tmpRoot, ["src/b.ts", "src/a.ts", "src/a.ts"]), + ); + expect(rows.map((r: ValidateRow) => r.path)).toEqual([ + "src/a.ts", + "src/b.ts", + ]); + }); +}); diff --git a/src/cli/cmd-validate.ts b/src/cli/cmd-validate.ts new file mode 100644 index 0000000..5c81ba0 --- /dev/null +++ b/src/cli/cmd-validate.ts @@ -0,0 +1,176 @@ +import { existsSync, readFileSync } from "node:fs"; +import { isAbsolute, relative, resolve } from "node:path"; + +import { loadUserConfig, resolveCodemapConfig } from "../config"; +import { closeDb, openDb } from "../db"; +import type { CodemapDatabase } from "../db"; +import { hashContent } from "../hash"; +import { configureResolver } from "../resolver"; +import { getProjectRoot, getTsconfigPath, initCodemap } from "../runtime"; + +/** + * One row in the staleness report. `status` distinguishes the three cases an + * agent might want to act on differently. + */ +export interface ValidateRow { + path: string; + status: "stale" | "missing" | "unindexed"; +} + +interface ValidateOpts { + root: string; + configFile: string | undefined; + paths: string[]; + json?: boolean; +} + +/** + * Print **`codemap validate`** usage. + */ +export function printValidateCmdHelp(): void { + console.log(`Usage: codemap validate [--json] [paths...] + +Compare the SHA-256 stored in .codemap.db against the on-disk content of each +file. Prints rows for entries that are out of sync — without the agent paying +to re-read every file. + + paths Project-relative or absolute file paths to check. If omitted, + all indexed files are checked. + +Statuses: + stale The file exists but its content_hash differs from the index. + missing The file is in the index but has been deleted on disk. + unindexed The file exists on disk but is not present in the index (only + when explicit paths are passed). + +Flags: + --json Emit a JSON array of {path, status} objects (for agents). + --help, -h Show this help. + +Examples: + codemap validate # check every indexed file + codemap validate src/parser.ts # check just one file + codemap validate --json src/a.ts src/b.ts +`); +} + +/** + * Parse `argv` after the bootstrap split: `rest[0]` must be `"validate"`. + */ +export function parseValidateRest( + rest: string[], +): + | { kind: "help" } + | { kind: "error"; message: string } + | { kind: "run"; paths: string[]; json: boolean } { + if (rest[0] !== "validate") { + throw new Error("parseValidateRest: expected validate"); + } + let json = false; + const paths: string[] = []; + for (let i = 1; i < rest.length; i++) { + const a = rest[i]; + if (a === "--help" || a === "-h") return { kind: "help" }; + if (a === "--json") { + json = true; + continue; + } + if (a.startsWith("-")) { + return { + kind: "error", + message: `codemap: unknown option "${a}". Run codemap validate --help for usage.`, + }; + } + paths.push(a); + } + return { kind: "run", paths, json }; +} + +/** + * Walk the indexed files (or the explicit `paths` set), comparing on-disk + * SHA-256 to `files.content_hash`. Returns rows that are out of sync. Pure + * function over an open DB and the project root — covered by unit tests. + */ +export function computeValidateRows( + db: CodemapDatabase, + projectRoot: string, + explicitPaths: string[], +): ValidateRow[] { + const indexed = db.query("SELECT path, content_hash FROM files").all() as { + path: string; + content_hash: string; + }[]; + + const indexByPath = new Map(); + for (const row of indexed) indexByPath.set(row.path, row.content_hash); + + const targets = + explicitPaths.length === 0 ? indexed.map((r) => r.path) : explicitPaths; + + const seen = new Set(); + const rows: ValidateRow[] = []; + for (const raw of targets) { + const rel = toProjectRelative(projectRoot, raw); + if (seen.has(rel)) continue; + seen.add(rel); + + const indexedHash = indexByPath.get(rel); + const abs = resolve(projectRoot, rel); + const onDisk = existsSync(abs); + + if (indexedHash === undefined) { + if (onDisk) rows.push({ path: rel, status: "unindexed" }); + continue; + } + if (!onDisk) { + rows.push({ path: rel, status: "missing" }); + continue; + } + const diskHash = hashContent(readFileSync(abs, "utf8")); + if (diskHash !== indexedHash) rows.push({ path: rel, status: "stale" }); + } + rows.sort((a, b) => a.path.localeCompare(b.path)); + return rows; +} + +function toProjectRelative(projectRoot: string, p: string): string { + if (isAbsolute(p)) return relative(projectRoot, p); + return p; +} + +/** + * Initialize Codemap for `opts.root`, then print the staleness report. + * Sets **`process.exitCode`** to **1** if any rows are returned (mirrors + * `git status` semantics so agents can branch on `$?`). + */ +export async function runValidateCmd(opts: ValidateOpts): Promise { + const json = opts.json === true; + try { + const user = await loadUserConfig(opts.root, opts.configFile); + initCodemap(resolveCodemapConfig(opts.root, user)); + configureResolver(getProjectRoot(), getTsconfigPath()); + const db = openDb(); + let rows: ValidateRow[]; + try { + rows = computeValidateRows(db, getProjectRoot(), opts.paths); + } finally { + closeDb(db, { readonly: true }); + } + if (json) { + console.log(JSON.stringify(rows)); + } else if (rows.length === 0) { + console.log("(everything in sync)"); + } else { + console.table(rows); + } + if (rows.length > 0) process.exitCode = 1; + } catch (err) { + const msg = err instanceof Error ? err.message : String(err); + if (json) { + console.log(JSON.stringify({ error: msg })); + } else { + console.error(msg); + } + process.exitCode = 1; + } +} diff --git a/src/cli/main.ts b/src/cli/main.ts index aaec406..0c0b48e 100644 --- a/src/cli/main.ts +++ b/src/cli/main.ts @@ -66,6 +66,48 @@ Copies bundled agent templates into .agents/ under the project root. validateIndexModeArgs(rest); + if (rest[0] === "context") { + const { parseContextRest, printContextCmdHelp, runContextCmd } = + await import("./cmd-context.js"); + const parsed = parseContextRest(rest); + if (parsed.kind === "help") { + printContextCmdHelp(); + return; + } + if (parsed.kind === "error") { + console.error(parsed.message); + process.exit(1); + } + await runContextCmd({ + root, + configFile, + compact: parsed.compact, + intent: parsed.intent, + }); + return; + } + + if (rest[0] === "validate") { + const { parseValidateRest, printValidateCmdHelp, runValidateCmd } = + await import("./cmd-validate.js"); + const parsed = parseValidateRest(rest); + if (parsed.kind === "help") { + printValidateCmdHelp(); + return; + } + if (parsed.kind === "error") { + console.error(parsed.message); + process.exit(1); + } + await runValidateCmd({ + root, + configFile, + paths: parsed.paths, + json: parsed.json, + }); + return; + } + if (rest[0] === "query") { const { parseQueryRest, diff --git a/src/config.test.ts b/src/config.test.ts index 755c5a2..14e3888 100644 --- a/src/config.test.ts +++ b/src/config.test.ts @@ -9,8 +9,8 @@ import { loadUserConfig, parseCodemapUserConfig, resolveCodemapConfig, - type CodemapUserConfig, } from "./config"; +import type { CodemapUserConfig } from "./config"; describe("parseCodemapUserConfig / defineConfig", () => { it("accepts an empty object", () => { diff --git a/src/config.ts b/src/config.ts index a38b95f..9ffa0f1 100644 --- a/src/config.ts +++ b/src/config.ts @@ -97,13 +97,21 @@ function formatCodemapConfigError(error: z.ZodError): string { } /** - * Fully resolved configuration after {@link resolveCodemapConfig}. + * Fully resolved configuration after {@link resolveCodemapConfig} — defaults + * filled in, paths absolute, types narrowed. Stored in the process-global + * runtime by {@link initCodemap} and read by every layer that needs project + * context (workers, resolver, DB, glob). */ export interface ResolvedCodemapConfig { + /** Absolute project root (from CLI `--root`, env, or `process.cwd()`). */ readonly root: string; + /** Absolute path to the SQLite database file (default `/.codemap.db`). */ readonly databasePath: string; + /** Glob patterns relative to `root`; either user-supplied or {@link DEFAULT_INCLUDE_PATTERNS}. */ readonly include: readonly string[]; + /** Directory **names** (any segment) to skip — either user-supplied or {@link DEFAULT_EXCLUDE_DIR_NAMES}. */ readonly excludeDirNames: ReadonlySet; + /** Absolute path to `tsconfig.json` for alias resolution, or `null` to disable. */ readonly tsconfigPath: string | null; } diff --git a/src/db.ts b/src/db.ts index dd7e897..a58cb53 100644 --- a/src/db.ts +++ b/src/db.ts @@ -1,8 +1,5 @@ -import { - openCodemapDatabase, - type CodemapDatabase, - type BindValues, -} from "./sqlite-db"; +import { openCodemapDatabase } from "./sqlite-db"; +import type { CodemapDatabase, BindValues } from "./sqlite-db"; /** * Bump in lockstep with `createTables` / `createIndexes` whenever on-disk schema @@ -250,6 +247,13 @@ export function deleteFileData(db: CodemapDatabase, filePath: string) { db.run("DELETE FROM files WHERE path = ?", [filePath]); } +/** + * One row in the `files` table — the header for every indexed file. All other + * row types reference `path` (FK with `ON DELETE CASCADE`). `content_hash` is + * SHA-256 hex from `src/hash.ts` and drives incremental staleness detection. + * + * Schema: see [docs/architecture.md § `files`](../docs/architecture.md#files--every-indexed-file-strict). + */ export interface FileRow { path: string; content_hash: string; @@ -276,6 +280,15 @@ export function insertFile(db: CodemapDatabase, file: FileRow) { ); } +/** + * One row in the `symbols` table — top-level or nested function / const / class + * / interface / type / enum / method / property / getter / setter. Class + * members carry `parent_name`. JSDoc tags (`@deprecated`, `@internal`, etc.) + * live in `doc_comment` and power the `deprecated-symbols` / + * `visibility-tags` recipes. + * + * Schema: see [docs/architecture.md § `symbols`](../docs/architecture.md#symbols--functions-constants-classes-interfaces-types-enums-strict). + */ export interface SymbolRow { file_path: string; name: string; @@ -341,6 +354,14 @@ export function insertSymbols(db: CodemapDatabase, symbols: SymbolRow[]) { ); } +/** + * One row in the `imports` table — a raw `import` statement. `specifiers` is a + * JSON-encoded string array. `resolved_path` is non-null only when the + * resolver could map `source` to a file inside the indexed set (see + * `dependencies` for the resolved edge view). + * + * Schema: see [docs/architecture.md § `imports`](../docs/architecture.md#imports--import-statements-strict). + */ export interface ImportRow { file_path: string; source: string; @@ -368,6 +389,13 @@ export function insertImports(db: CodemapDatabase, imports: ImportRow[]) { ); } +/** + * One row in the `exports` table — named, default, or re-export. `kind` is one + * of `value` / `type` / `re-export`; `re_export_source` is non-null only for + * `re-export` rows. + * + * Schema: see [docs/architecture.md § `exports`](../docs/architecture.md#exports--export-declarations-strict). + */ export interface ExportRow { file_path: string; name: string; @@ -387,6 +415,15 @@ export function insertExports(db: CodemapDatabase, exports: ExportRow[]) { ); } +/** + * One row in the `components` table — React component detected by PascalCase + * name plus JSX return or hook usage. `hooks_used` is a JSON-encoded string + * array (e.g. `'["useState","useEffect"]'`). PascalCase functions in `.tsx` + * that neither return JSX nor call hooks are stored as `symbols` only, never + * as `components`. + * + * Schema: see [docs/architecture.md § `components`](../docs/architecture.md#components--react-components-detected-by-pascalcase--jsx-return-or-hook-usage-strict). + */ export interface ComponentRow { file_path: string; name: string; @@ -415,6 +452,14 @@ export function insertComponents( ); } +/** + * One row in the `dependencies` table — a resolved file-to-file edge derived + * from `imports.resolved_path`. Self-edges and unresolved imports are + * excluded. `(from_path, to_path)` is the composite primary key + * (`STRICT, WITHOUT ROWID`). + * + * Schema: see [docs/architecture.md § `dependencies`](../docs/architecture.md#dependencies--resolved-file-to-file-dependency-graph-strict-without-rowid). + */ export interface DependencyRow { from_path: string; to_path: string; @@ -430,6 +475,13 @@ export function insertDependencies(db: CodemapDatabase, deps: DependencyRow[]) { ); } +/** + * One row in the `markers` table — a `TODO` / `FIXME` / `HACK` / `NOTE` comment + * extracted from any indexed file (TS, CSS, Markdown, JSON, YAML, …). + * `content` is the comment text without the marker prefix. + * + * Schema: see [docs/architecture.md § `markers`](../docs/architecture.md#markers--todofixmehacknote-comments-extracted-from-all-file-types-strict). + */ export interface MarkerRow { file_path: string; line_number: number; @@ -447,6 +499,13 @@ export function insertMarkers(db: CodemapDatabase, markers: MarkerRow[]) { ); } +/** + * One row in the `css_variables` table — a CSS custom property + * (`--token: value`). `scope` is `:root`, `@theme` (Tailwind v4), or the + * selector text where the property was declared. + * + * Schema: see [docs/architecture.md § `css_variables`](../docs/architecture.md#css_variables--css-custom-properties-design-tokens-strict). + */ export interface CssVariableRow { file_path: string; name: string; @@ -469,6 +528,13 @@ export function insertCssVariables( ); } +/** + * One row in the `css_classes` table — a class name extracted from a CSS + * selector (without the leading `.`). `is_module` is `1` when the file ends + * in `.module.css` (CSS Modules — names are usually rewritten by bundlers). + * + * Schema: see [docs/architecture.md § `css_classes`](../docs/architecture.md#css_classes--css-class-definitions-strict). + */ export interface CssClassRow { file_path: string; name: string; @@ -486,6 +552,11 @@ export function insertCssClasses(db: CodemapDatabase, classes: CssClassRow[]) { ); } +/** + * One row in the `css_keyframes` table — a `@keyframes ` declaration. + * + * Schema: see [docs/architecture.md § `css_keyframes`](../docs/architecture.md#css_keyframes--keyframes-animation-definitions-strict). + */ export interface CssKeyframeRow { file_path: string; name: string; @@ -505,6 +576,15 @@ export function insertCssKeyframes( ); } +/** + * One row in the `calls` table — a function-scoped call edge, deduped per + * `(caller_scope, callee_name)` per file. `caller_scope` is the dot-joined + * enclosing scope (e.g. `UserService.run`) so same-named methods in different + * classes stay distinct. Module-level calls (outside any function) are + * intentionally excluded. + * + * Schema: see [docs/architecture.md § `calls`](../docs/architecture.md#calls--function-scoped-call-edges-deduped-per-file-strict). + */ export interface CallRow { file_path: string; caller_name: string; @@ -522,6 +602,14 @@ export function insertCalls(db: CodemapDatabase, calls: CallRow[]) { ); } +/** + * One row in the `type_members` table — a property or method signature on an + * interface or object-literal type alias. `symbol_name` references the parent + * `symbols.name`; `type` is the raw annotation string (or `null` when the + * parser cannot reconstruct it). + * + * Schema: see [docs/architecture.md § `type_members`](../docs/architecture.md#type_members--properties-and-methods-of-interfaces-and-object-literal-types-strict). + */ export interface TypeMemberRow { file_path: string; symbol_name: string; diff --git a/src/parse-worker-core.ts b/src/parse-worker-core.ts index c88a876..348bd77 100644 --- a/src/parse-worker-core.ts +++ b/src/parse-worker-core.ts @@ -75,6 +75,7 @@ export function parseWorkerInput(input: WorkerInput): WorkerOutput { const ctx: ParseContext = { absPath, relPath, source }; + const parseStart = performance.now(); try { const adapter = getAdapterForExtension(ext); const payload = adapter @@ -84,6 +85,7 @@ export function parseWorkerInput(input: WorkerInput): WorkerOutput { } catch (err) { parsed.parseError = err instanceof Error ? err.message : String(err); } + parsed.parseMs = performance.now() - parseStart; results.push(parsed); } diff --git a/src/parsed-types.ts b/src/parsed-types.ts index 3aaa457..902a37d 100644 --- a/src/parsed-types.ts +++ b/src/parsed-types.ts @@ -13,23 +13,60 @@ import type { } from "./db"; /** - * One indexed file’s extracted data (workers return arrays of these). + * One indexed file's extracted data — workers return arrays of these and + * `LanguageAdapter`s populate a {@link ParsedFilePayload} subset of these + * fields. Row shapes (`SymbolRow`, `ImportRow`, …) mirror the SQLite schema + * documented in `docs/architecture.md § Schema`. */ export interface ParsedFile { + /** Path relative to project root; primary key for the `files` table. */ relPath: string; + /** + * Set to `true` when the file could not even be read from disk + * (`fileRow` is then a placeholder and other fields are undefined). + * Distinct from {@link ParsedFile.parseError} — see that field. + */ error?: boolean; + /** + * Error message from the parser when extraction threw but the file *was* + * read successfully. The `files` row is still inserted so incremental + * runs do not retry parsing on every pass. + */ parseError?: string; + /** Row to insert into the `files` table (path, hash, size, language, …). */ fileRow: FileRow; + /** + * Selects which extraction path the result came from: + * - `ts` — TS/TSX/JS/JSX (oxc-parser): symbols/imports/exports/etc. + * - `css` — CSS (lightningcss): variables/classes/keyframes/imports. + * - `text` — Markers-only (Markdown, JSON, YAML, fallback for unknown ext). + */ category: "ts" | "css" | "text"; + /** Worker-side wall-clock parse time; surfaced by `--performance`. */ + parseMs?: number; + /** Top-level + nested symbols (functions, classes, interfaces, …). */ symbols?: SymbolRow[]; + /** `import` statements (alias-resolved separately into `dependencies`). */ imports?: ImportRow[]; + /** Named, default, and re-exports. */ exports?: ExportRow[]; + /** React components detected via PascalCase + JSX/hooks heuristic. */ components?: ComponentRow[]; + /** `TODO` / `FIXME` / `HACK` / `NOTE` comments (extracted from any category). */ markers?: MarkerRow[]; + /** Properties and method signatures of interfaces / object-literal types. */ typeMembers?: TypeMemberRow[]; + /** Function-scoped call edges (deduped per `caller_scope` + `callee_name`). */ calls?: CallRow[]; + /** CSS custom properties (`--var`) — only emitted when `category === "css"`. */ cssVariables?: CssVariableRow[]; + /** CSS class definitions, with `is_module` flag for `.module.css` files. */ cssClasses?: CssClassRow[]; + /** `@keyframes` animation definitions. */ cssKeyframes?: CssKeyframeRow[]; + /** + * Raw `@import` source strings from CSS — main thread converts them into + * `imports` rows (with `resolved_path = null`) before insertion. + */ cssImportSources?: string[]; } diff --git a/src/parser.ts b/src/parser.ts index 1ba5701..2ecd2b3 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -568,30 +568,42 @@ function stringifyTypeNode(node: any): string | null { } return name; } - case "TSStringKeyword": + case "TSStringKeyword": { return "string"; - case "TSNumberKeyword": + } + case "TSNumberKeyword": { return "number"; - case "TSBooleanKeyword": + } + case "TSBooleanKeyword": { return "boolean"; - case "TSVoidKeyword": + } + case "TSVoidKeyword": { return "void"; - case "TSNullKeyword": + } + case "TSNullKeyword": { return "null"; - case "TSUndefinedKeyword": + } + case "TSUndefinedKeyword": { return "undefined"; - case "TSAnyKeyword": + } + case "TSAnyKeyword": { return "any"; - case "TSNeverKeyword": + } + case "TSNeverKeyword": { return "never"; - case "TSUnknownKeyword": + } + case "TSUnknownKeyword": { return "unknown"; - case "TSObjectKeyword": + } + case "TSObjectKeyword": { return "object"; - case "TSBigIntKeyword": + } + case "TSBigIntKeyword": { return "bigint"; - case "TSSymbolKeyword": + } + case "TSSymbolKeyword": { return "symbol"; + } case "TSArrayType": { const elem = stringifyTypeNode(node.elementType); return elem ? `${elem}[]` : null; @@ -625,10 +637,12 @@ function stringifyTypeNode(node: any): string | null { const inner = stringifyTypeNode(node.typeAnnotation); return inner ? `${node.operator} ${inner}` : null; } - case "TSThisType": + case "TSThisType": { return "this"; - default: + } + default: { return null; + } } } diff --git a/src/sqlite-db.ts b/src/sqlite-db.ts index 6593cc9..bcf05ff 100644 --- a/src/sqlite-db.ts +++ b/src/sqlite-db.ts @@ -22,7 +22,7 @@ export interface CodemapDatabase { close(): void; } -type SqliteInner = { +interface SqliteInner { run(sql: string, params?: BindValues): void; query(sql: string): { get(...params: unknown[]): unknown; @@ -30,7 +30,7 @@ type SqliteInner = { }; transaction(fn: () => T): unknown; close(): void; -}; +} /** * `better-sqlite3` allows only one statement per `prepare()`; `bun:sqlite` accepts several. From 0fafbff197c680efcb07417e44cbd0e17011c4a2 Mon Sep 17 00:00:00 2001 From: Sutu Sebastian Date: Mon, 27 Apr 2026 13:34:45 +0300 Subject: [PATCH 06/12] =?UTF-8?q?fix(cli):=20address=20PR=20#23=20review?= =?UTF-8?q?=20=E2=80=94=20recent=5Fmarkers=20misnomer,=20validate=20TOCTOU?= =?UTF-8?q?,=20--compact,=20--for=20guard,=20README?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adopts the 7 valid items from CodeRabbit review. A1 — `recent_markers` was alphabetical-first-20, not recency-ordered (the markers table has no timestamp column). Rename to `sample_markers` with a JSDoc note pointing at the proper time-ordered query (join `files.last_modified`). A2 — `cmd-validate.ts` had a TOCTOU between existsSync and readFileSync. Replace with a single guarded read; also drops one syscall in the common path (open instead of stat + open). N2 — Rename `performance` local in cmd-index.ts to `reportPerformance` to avoid shadowing the global `performance` API. N4 — Route the `files-hashes` golden through the bundled recipe (was inline SQL); now exercises the recipe SQL itself and prevents drift. Snapshot refreshed. N5 — Add `validate` and `context` to the README "Daily commands" stripe; they were the headline additions in this PR but weren't on the showcase. N7 — `--for ""` was accepted as a valid intent and silently classified as "other". Reject empty-string values with the same error as missing. N8 — `--compact` now actually compacts: `JSON.stringify` is called without indent in compact mode (was unconditional 2-space pretty-print). Tests: +1 case for `--for ""` rejection. 19/19 goldens green, 24/24 cmd-context + cmd-validate tests pass. --- README.md | 4 +++- fixtures/golden/minimal/files-hashes.json | 11 +++++++++ fixtures/golden/scenarios.json | 4 ++-- src/cli/cmd-context.test.ts | 5 +++++ src/cli/cmd-context.ts | 27 ++++++++++++++++------- src/cli/cmd-index.ts | 4 ++-- src/cli/cmd-validate.ts | 18 ++++++++++----- 7 files changed, 54 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 2e8c36a..92cc1dc 100644 --- a/README.md +++ b/README.md @@ -46,9 +46,11 @@ bun add @stainless-code/codemap ```bash codemap # incremental index (run once per session) -codemap query --json --recipe fan-out # bundled SQL via recipe id +codemap query --json --recipe fan-out # bundled SQL via recipe id (alias: -r) codemap query --json "SELECT name, file_path FROM symbols WHERE name = 'foo'" # ad-hoc SQL codemap --files src/a.ts src/b.tsx # targeted re-index after edits +codemap validate --json # detect stale / missing / unindexed files +codemap context --compact --for "refactor auth" # JSON envelope + intent-matched recipes codemap agents init # scaffold .agents/ rules + skills ``` diff --git a/fixtures/golden/minimal/files-hashes.json b/fixtures/golden/minimal/files-hashes.json index bf22e2b..bd85eb8 100644 --- a/fixtures/golden/minimal/files-hashes.json +++ b/fixtures/golden/minimal/files-hashes.json @@ -1,56 +1,67 @@ [ { "path": "README.md", + "content_hash": "428564b4ac5e4864ca2292a4195b726be3d4c7c5cac3d19dd01f17714d026c66", "language": "md", "line_count": 11 }, { "path": "package.json", + "content_hash": "a8e79efc943697cee4d4435360de9150bd7261376abe9e2c34c0c7238177c7de", "language": "json", "line_count": 11 }, { "path": "src/api/client.ts", + "content_hash": "4d0ec5edad3f758e7f84898dd602dbacaf3ea65ad87614ae9f179bd2383bbf56", "language": "ts", "line_count": 9 }, { "path": "src/components/shop/ShopButton.tsx", + "content_hash": "481b9ff2e493fd69b36b67d2738e298999ce55040bce64c4c38a2e736c0573fd", "language": "tsx", "line_count": 8 }, { "path": "src/consumer.ts", + "content_hash": "420ad98f7fedaf07ec07d1a64ef6ade100be4a7973883718a3942c68b1350903", "language": "ts", "line_count": 11 }, { "path": "src/notes.md", + "content_hash": "1a2bff433137690132077b15032ba3f07f5ed1b576b894816890342155ab640a", "language": "md", "line_count": 4 }, { "path": "src/styles/button.module.css", + "content_hash": "1c385277a506b2cb1c70c2d2128bbd280bf080796c83ab37f6f3434655c17348", "language": "css", "line_count": 16 }, { "path": "src/theme.css", + "content_hash": "19ff92a0acce67e5a385e8f1b1607f787462626669d3b941ee0fc91030672b67", "language": "css", "line_count": 9 }, { "path": "src/usePermissions.ts", + "content_hash": "8758cc9ba2756e08198f11fca9ff58a0612fc9219173d06784e0b7e2f2ca1e1f", "language": "ts", "line_count": 4 }, { "path": "src/utils/date.ts", + "content_hash": "89e6301076caeb9f4c13cee8ea06f7f25a5e1aa239daf921f7ff984236ffa177", "language": "ts", "line_count": 15 }, { "path": "tsconfig.json", + "content_hash": "6b8ead4b09e6885483c805937a35fa0df3cbc47de346abb2d0ed8b73dc7f9e92", "language": "json", "line_count": 17 } diff --git a/fixtures/golden/scenarios.json b/fixtures/golden/scenarios.json index 9deadbc..2869429 100644 --- a/fixtures/golden/scenarios.json +++ b/fixtures/golden/scenarios.json @@ -86,8 +86,8 @@ }, { "id": "files-hashes", - "prompt": "All indexed file paths with language and line count (powers `codemap validate`)", - "sql": "SELECT path, language, line_count FROM files ORDER BY path" + "prompt": "All indexed files with content_hash (recipe powers `codemap validate`)", + "recipe": "files-hashes" }, { "id": "barrel-files", diff --git a/src/cli/cmd-context.test.ts b/src/cli/cmd-context.test.ts index cef9238..864b041 100644 --- a/src/cli/cmd-context.test.ts +++ b/src/cli/cmd-context.test.ts @@ -48,6 +48,11 @@ describe("parseContextRest", () => { expect(r.kind).toBe("error"); }); + it("errors when --for value is an empty string", () => { + const r = parseContextRest(["context", "--for", ""]); + expect(r.kind).toBe("error"); + }); + it("rejects unknown options", () => { expect(parseContextRest(["context", "--nope"]).kind).toBe("error"); }); diff --git a/src/cli/cmd-context.ts b/src/cli/cmd-context.ts index f76c6bd..2dee972 100644 --- a/src/cli/cmd-context.ts +++ b/src/cli/cmd-context.ts @@ -22,7 +22,13 @@ export interface ContextEnvelope { languages: { language: string; files: number }[]; }; hubs?: { to_path: string; fan_in: number }[]; - recent_markers?: { + /** + * A flavor sample of TODO/FIXME/HACK/NOTE markers — the alphabetically-first + * 20 across the repo, ordered by `(file_path, line_number)`. Not a recency + * signal; for time-ordered output query `markers` directly, joining + * `files.last_modified`. + */ + sample_markers?: { file_path: string; line_number: number; kind: string; @@ -51,11 +57,12 @@ export function printContextCmdHelp(): void { console.log(`Usage: codemap context [--compact] [--for ""] Emit a JSON envelope describing the current index — project metadata, top -hubs (fan-in), recent markers, and the bundled recipe catalog. Designed for -agents and editors that want a single-command "give me everything cheap". +hubs (fan-in), a sample of markers, and the bundled recipe catalog. Designed +for agents and editors that want a single-command "give me everything cheap". Flags: - --compact Drop hubs and recent_markers (smaller payload). + --compact Drop hubs and sample_markers; emit JSON without + pretty-print (smaller payload). --for "" Pre-classify a free-text intent (refactor, debug, test, feature, explore) and recommend recipes that match. --help, -h Show this help. @@ -90,7 +97,7 @@ export function parseContextRest( } if (a === "--for") { const v = rest[i + 1]; - if (v === undefined || v.startsWith("--")) { + if (v === undefined || v === "" || v.startsWith("--")) { return { kind: "error", message: 'codemap: "--for" requires an intent string in quotes.', @@ -210,11 +217,11 @@ export function buildContextEnvelope( envelope.hubs = db .query(QUERY_RECIPES["fan-in"]!.sql) .all() as ContextEnvelope["hubs"]; - envelope.recent_markers = db + envelope.sample_markers = db .query( "SELECT file_path, line_number, kind, content FROM markers ORDER BY file_path ASC, line_number ASC LIMIT 20", ) - .all() as ContextEnvelope["recent_markers"]; + .all() as ContextEnvelope["sample_markers"]; } if (opts.intent !== null) { @@ -248,7 +255,11 @@ export async function runContextCmd(opts: ContextOpts): Promise { } finally { closeDb(db, { readonly: true }); } - console.log(JSON.stringify(envelope, null, 2)); + console.log( + opts.compact + ? JSON.stringify(envelope) + : JSON.stringify(envelope, null, 2), + ); } catch (err) { const msg = err instanceof Error ? err.message : String(err); console.log(JSON.stringify({ error: msg })); diff --git a/src/cli/cmd-index.ts b/src/cli/cmd-index.ts index 9880a96..575e776 100644 --- a/src/cli/cmd-index.ts +++ b/src/cli/cmd-index.ts @@ -34,10 +34,10 @@ export async function runIndexCmd(opts: { } } else { const fullRebuild = args.includes("--full"); - const performance = args.includes("--performance"); + const reportPerformance = args.includes("--performance"); await runCodemapIndex(db, { mode: fullRebuild ? "full" : "incremental", - performance, + performance: reportPerformance, }); } } finally { diff --git a/src/cli/cmd-validate.ts b/src/cli/cmd-validate.ts index 5c81ba0..8d1d144 100644 --- a/src/cli/cmd-validate.ts +++ b/src/cli/cmd-validate.ts @@ -1,4 +1,4 @@ -import { existsSync, readFileSync } from "node:fs"; +import { readFileSync } from "node:fs"; import { isAbsolute, relative, resolve } from "node:path"; import { loadUserConfig, resolveCodemapConfig } from "../config"; @@ -116,18 +116,24 @@ export function computeValidateRows( const indexedHash = indexByPath.get(rel); const abs = resolve(projectRoot, rel); - const onDisk = existsSync(abs); + let source: string | undefined; + try { + source = readFileSync(abs, "utf8"); + } catch { + source = undefined; + } if (indexedHash === undefined) { - if (onDisk) rows.push({ path: rel, status: "unindexed" }); + if (source !== undefined) rows.push({ path: rel, status: "unindexed" }); continue; } - if (!onDisk) { + if (source === undefined) { rows.push({ path: rel, status: "missing" }); continue; } - const diskHash = hashContent(readFileSync(abs, "utf8")); - if (diskHash !== indexedHash) rows.push({ path: rel, status: "stale" }); + if (hashContent(source) !== indexedHash) { + rows.push({ path: rel, status: "stale" }); + } } rows.sort((a, b) => a.path.localeCompare(b.path)); return rows; From a78a72c49a8fa1ed624b6903ec1d289c6f7c09e2 Mon Sep 17 00:00:00 2001 From: Sutu Sebastian Date: Mon, 27 Apr 2026 14:35:03 +0300 Subject: [PATCH 07/12] =?UTF-8?q?feat(db):=20tighten=20NOT=20NULL=20on=20e?= =?UTF-8?q?very=20Row-interface=20non-nullable=20column;=20bump=20SCHEMA?= =?UTF-8?q?=5FVERSION=202=20=E2=86=92=203?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes review item N1: until now FileRow declared `size`, `line_count`, `language`, `last_modified`, `indexed_at` as non-nullable in TypeScript, but the SQLite schema only required `path` and `content_hash` to be NOT NULL — so a row read back via `query(...)` could legally surface null for any of those columns. The same gap applied to 8 other tables (symbols, imports, exports, components, markers, css_variables, css_classes, css_keyframes, type_members). This commit aligns the SQL invariants with the existing TypeScript types: add NOT NULL to every column whose Row-interface type is non-nullable. The DEFAULT 0 columns gain NOT NULL too so the constraint is enforced even when the writer omits the column. `calls` and `dependencies` were already fully constrained — no change. `SCHEMA_VERSION` bumps 2 → 3. The existing `createSchema()` version- mismatch detector picks up the bump on first open and triggers a full rebuild — verified locally (meta.schema_version = "3" after one run). Changeset bumped to minor per .agents/lessons.md (schema-breaking changes that force a .codemap.db rebuild are minor, even pre-1.0). --- .changeset/agent-friendly-cli-recipes.md | 5 +- docs/architecture.md | 2 +- src/db.ts | 60 +++++++++++++----------- 3 files changed, 37 insertions(+), 30 deletions(-) diff --git a/.changeset/agent-friendly-cli-recipes.md b/.changeset/agent-friendly-cli-recipes.md index c095943..2c832da 100644 --- a/.changeset/agent-friendly-cli-recipes.md +++ b/.changeset/agent-friendly-cli-recipes.md @@ -1,8 +1,8 @@ --- -"@stainless-code/codemap": patch +"@stainless-code/codemap": minor --- -Agent-friendly CLI surface: `codemap validate`, `codemap context`, `--performance`, `-r` recipe alias, and four new bundled query recipes. +Agent-friendly CLI surface plus a schema v3 bump that tightens `NOT NULL` invariants. Existing `.codemap.db` files auto-rebuild on first open. - **New: `codemap validate [--json] [paths...]`** — diffs the on-disk SHA-256 of indexed files against `files.content_hash` and prints stale / missing / unindexed rows. Lets agents skip re-reads they don't need; exits `1` on any drift (git-status semantics) - **New: `codemap context [--compact] [--for ""]`** — emits a stable JSON envelope (project metadata, top hubs, recent markers, recipe catalog) for any agent or editor that wants the index in one cheap shot. `--for` runs lightweight intent classification (refactor / debug / test / feature / explore / other) and returns matched recipe ids plus a hint @@ -13,3 +13,4 @@ Agent-friendly CLI surface: `codemap validate`, `codemap context`, `--performanc - **Public type surface**: new `IndexPerformanceReport`; `IndexRunStats.performance?` field; per-field JSDoc coverage on `IndexResult`, `IndexRunStats`, `ResolvedCodemapConfig`, all `db.ts` row interfaces (`FileRow`, `SymbolRow`, `ImportRow`, `ExportRow`, `ComponentRow`, `DependencyRow`, `MarkerRow`, `CssVariableRow`, `CssClassRow`, `CssKeyframeRow`, `CallRow`, `TypeMemberRow`), and `ParsedFile` - **Documentation**: README now leads with a "What you get" Grep/Read vs Codemap capability table and a "Daily commands" stripe; `docs/why-codemap.md` adds a "What Codemap is **not**" anti-pitch section and a scenario-keyed token-savings table (single lookup → 50-turn session) replacing the earlier hand-wave - **Stricter lint baseline**: enabled `prefer-const`, `consistent-type-specifier-style`, `consistent-type-definitions`, `no-confusing-non-null-assertion`, `no-unnecessary-{boolean-literal-compare,template-expression,type-assertion}`, `prefer-{includes,nullish-coalescing,optional-chain}`, and `unicorn/switch-case-braces` +- **Schema v3 — tighter `NOT NULL` invariants**: every column whose `Row`-interface type was non-nullable is now `NOT NULL` in the SQLite DDL (`files.size`/`line_count`/`language`/`last_modified`/`indexed_at`, `symbols.line_start`/`line_end`/`signature`/`is_exported`/`is_default_export`, `imports.specifiers`/`is_type_only`/`line_number`, `exports.kind`/`is_default`, `components.hooks_used`/`is_default_export`, `markers.line_number`/`content`, `css_variables.scope`/`line_number`, `css_classes.is_module`/`line_number`, `css_keyframes.line_number`, `type_members.is_optional`/`is_readonly`). Existing v2 databases auto-rebuild via `createSchema()`'s version-mismatch detector — no manual action needed diff --git a/docs/architecture.md b/docs/architecture.md index b9da137..72918b1 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -155,7 +155,7 @@ Optional **`codemap.config.ts`** (default export: object or async factory) or ** **Fresh database:** the default CLI **`codemap`** (incremental) calls **`createSchema()`** in **`runCodemapIndex`** before **`getChangedFiles()`**, so the **`meta`** table exists before **`getMeta(..., "last_indexed_commit")`** runs on an empty **`.codemap.db`**. -Current schema version: **2** — see [Schema Versioning](#schema-versioning) for details. +Current schema version: **3** — see [Schema Versioning](#schema-versioning) for details. All tables use `STRICT` mode. Tables marked with `WITHOUT ROWID` store data directly in the primary key B-tree. PRAGMAs and index design: [SQLite Performance Configuration](#sqlite-performance-configuration). diff --git a/src/db.ts b/src/db.ts index a58cb53..ec4b7cf 100644 --- a/src/db.ts +++ b/src/db.ts @@ -4,8 +4,14 @@ import type { CodemapDatabase, BindValues } from "./sqlite-db"; /** * Bump in lockstep with `createTables` / `createIndexes` whenever on-disk schema * changes. `createSchema()` rebuilds automatically on version mismatch. + * + * @remarks + * v3 (this PR): tightened `NOT NULL` on every column whose Row-interface type + * is non-nullable, so SQLite enforces the same invariants at write time that + * the TypeScript reads already assume. Existing v2 DBs auto-rebuild on first + * open via the version-mismatch detector below. */ -export const SCHEMA_VERSION = 2; +export const SCHEMA_VERSION = 3; export type { CodemapDatabase }; @@ -29,11 +35,11 @@ export function createTables(db: CodemapDatabase) { CREATE TABLE IF NOT EXISTS files ( path TEXT PRIMARY KEY, content_hash TEXT NOT NULL, - size INTEGER, - line_count INTEGER, - language TEXT, - last_modified INTEGER, - indexed_at INTEGER + size INTEGER NOT NULL, + line_count INTEGER NOT NULL, + language TEXT NOT NULL, + last_modified INTEGER NOT NULL, + indexed_at INTEGER NOT NULL ) STRICT; CREATE TABLE IF NOT EXISTS symbols ( @@ -41,11 +47,11 @@ export function createTables(db: CodemapDatabase) { file_path TEXT NOT NULL REFERENCES files(path) ON DELETE CASCADE, name TEXT NOT NULL, kind TEXT NOT NULL, - line_start INTEGER, - line_end INTEGER, - signature TEXT, - is_exported INTEGER DEFAULT 0, - is_default_export INTEGER DEFAULT 0, + line_start INTEGER NOT NULL, + line_end INTEGER NOT NULL, + signature TEXT NOT NULL, + is_exported INTEGER NOT NULL DEFAULT 0, + is_default_export INTEGER NOT NULL DEFAULT 0, members TEXT, doc_comment TEXT, value TEXT, @@ -57,17 +63,17 @@ export function createTables(db: CodemapDatabase) { file_path TEXT NOT NULL REFERENCES files(path) ON DELETE CASCADE, source TEXT NOT NULL, resolved_path TEXT, - specifiers TEXT, - is_type_only INTEGER DEFAULT 0, - line_number INTEGER + specifiers TEXT NOT NULL, + is_type_only INTEGER NOT NULL DEFAULT 0, + line_number INTEGER NOT NULL ) STRICT; CREATE TABLE IF NOT EXISTS exports ( id INTEGER PRIMARY KEY AUTOINCREMENT, file_path TEXT NOT NULL REFERENCES files(path) ON DELETE CASCADE, name TEXT NOT NULL, - kind TEXT, - is_default INTEGER DEFAULT 0, + kind TEXT NOT NULL, + is_default INTEGER NOT NULL DEFAULT 0, re_export_source TEXT ) STRICT; @@ -76,8 +82,8 @@ export function createTables(db: CodemapDatabase) { file_path TEXT NOT NULL REFERENCES files(path) ON DELETE CASCADE, name TEXT NOT NULL, props_type TEXT, - hooks_used TEXT, - is_default_export INTEGER DEFAULT 0 + hooks_used TEXT NOT NULL, + is_default_export INTEGER NOT NULL DEFAULT 0 ) STRICT; CREATE TABLE IF NOT EXISTS dependencies ( @@ -89,9 +95,9 @@ export function createTables(db: CodemapDatabase) { CREATE TABLE IF NOT EXISTS markers ( id INTEGER PRIMARY KEY AUTOINCREMENT, file_path TEXT NOT NULL REFERENCES files(path) ON DELETE CASCADE, - line_number INTEGER, + line_number INTEGER NOT NULL, kind TEXT NOT NULL, - content TEXT + content TEXT NOT NULL ) STRICT; CREATE TABLE IF NOT EXISTS css_variables ( @@ -99,23 +105,23 @@ export function createTables(db: CodemapDatabase) { file_path TEXT NOT NULL REFERENCES files(path) ON DELETE CASCADE, name TEXT NOT NULL, value TEXT, - scope TEXT, - line_number INTEGER + scope TEXT NOT NULL, + line_number INTEGER NOT NULL ) STRICT; CREATE TABLE IF NOT EXISTS css_classes ( id INTEGER PRIMARY KEY AUTOINCREMENT, file_path TEXT NOT NULL REFERENCES files(path) ON DELETE CASCADE, name TEXT NOT NULL, - is_module INTEGER DEFAULT 0, - line_number INTEGER + is_module INTEGER NOT NULL DEFAULT 0, + line_number INTEGER NOT NULL ) STRICT; CREATE TABLE IF NOT EXISTS css_keyframes ( id INTEGER PRIMARY KEY AUTOINCREMENT, file_path TEXT NOT NULL REFERENCES files(path) ON DELETE CASCADE, name TEXT NOT NULL, - line_number INTEGER + line_number INTEGER NOT NULL ) STRICT; CREATE TABLE IF NOT EXISTS calls ( @@ -132,8 +138,8 @@ export function createTables(db: CodemapDatabase) { symbol_name TEXT NOT NULL, name TEXT NOT NULL, type TEXT, - is_optional INTEGER DEFAULT 0, - is_readonly INTEGER DEFAULT 0 + is_optional INTEGER NOT NULL DEFAULT 0, + is_readonly INTEGER NOT NULL DEFAULT 0 ) STRICT; CREATE TABLE IF NOT EXISTS meta ( From 4ea0821646a7e381b34af565c899a8accf837577 Mon Sep 17 00:00:00 2001 From: Sutu Sebastian Date: Mon, 27 Apr 2026 14:39:47 +0300 Subject: [PATCH 08/12] docs: tighten JSDoc comments on public types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Concise rewrite of the JSDocs added in the previous commits. Keeps the non-obvious facts (FK cascade, JSON-encoded fields, recipe pointers, related-table cross-references, total_ms vs collect_ms gotcha, snake_case key convention on IndexTableStats) and drops the boilerplate: - 12 row interfaces in db.ts: collapse the per-table architecture.md links (single source already lives in docs/architecture.md § Schema). Keep the high-signal hints (FK behavior on FileRow, JSDoc-tag recipes on SymbolRow, dependencies cross-link on ImportRow, JSON shape on ComponentRow.hooks_used, scope semantics on CssVariableRow, is_module/`.module.css` rule on CssClassRow, dedup keying on CallRow, null type semantics on TypeMemberRow). - ParsedFile: drop redundant per-field one-liners that just restated the field name; keep error/parseError distinction, category meaning, CSS-only grouping, cssImportSources main-thread conversion. - SCHEMA_VERSION: drop the v3-specific @remarks paragraph (that belongs in the changelog/changeset, not in code that lives forever). - ResolvedCodemapConfig: tighten interface doc; per-field one-liners unchanged. - getAdapterForExtension: collapse multi-paragraph JSDoc to one sentence retaining the leading-dot rule and the markers-only fallback. application/types.ts left as-is — already balanced, and the verbose parts there encode invariants worth keeping (snake_case keys, total_ms != wall_time). --- src/adapters/builtin.ts | 12 ++--- src/config.ts | 6 +-- src/db.ts | 111 ++++++++++++---------------------------- src/parsed-types.ts | 46 ++++------------- 4 files changed, 46 insertions(+), 129 deletions(-) diff --git a/src/adapters/builtin.ts b/src/adapters/builtin.ts index 4e54e34..3f0d743 100644 --- a/src/adapters/builtin.ts +++ b/src/adapters/builtin.ts @@ -78,15 +78,9 @@ export const BUILTIN_ADAPTERS: readonly LanguageAdapter[] = [ ]; /** - * First-match lookup of a {@link LanguageAdapter} by file extension. - * - * @param ext - File extension **with leading dot**, e.g. `".tsx"`. Compared - * verbatim against each adapter's `extensions` array. - * @param adapters - Adapter list to search; defaults to {@link BUILTIN_ADAPTERS}. - * Pass a custom list to support project-local adapters once a registration - * API lands (see [docs/roadmap.md](../../docs/roadmap.md)). - * @returns The first adapter whose `extensions` contains `ext`, or `undefined` - * when no adapter matches (the indexer then falls back to markers-only text). + * First-match adapter lookup by file extension. `ext` must include the + * leading dot (`.tsx`); returns `undefined` when nothing matches (the + * indexer then falls back to markers-only text). */ export function getAdapterForExtension( ext: string, diff --git a/src/config.ts b/src/config.ts index 9ffa0f1..33bd977 100644 --- a/src/config.ts +++ b/src/config.ts @@ -97,10 +97,8 @@ function formatCodemapConfigError(error: z.ZodError): string { } /** - * Fully resolved configuration after {@link resolveCodemapConfig} — defaults - * filled in, paths absolute, types narrowed. Stored in the process-global - * runtime by {@link initCodemap} and read by every layer that needs project - * context (workers, resolver, DB, glob). + * Fully resolved config (defaults filled, paths absolute) — stored in the + * process-global runtime by {@link initCodemap} and read by every layer. */ export interface ResolvedCodemapConfig { /** Absolute project root (from CLI `--root`, env, or `process.cwd()`). */ diff --git a/src/db.ts b/src/db.ts index ec4b7cf..222ff95 100644 --- a/src/db.ts +++ b/src/db.ts @@ -1,16 +1,7 @@ import { openCodemapDatabase } from "./sqlite-db"; import type { CodemapDatabase, BindValues } from "./sqlite-db"; -/** - * Bump in lockstep with `createTables` / `createIndexes` whenever on-disk schema - * changes. `createSchema()` rebuilds automatically on version mismatch. - * - * @remarks - * v3 (this PR): tightened `NOT NULL` on every column whose Row-interface type - * is non-nullable, so SQLite enforces the same invariants at write time that - * the TypeScript reads already assume. Existing v2 DBs auto-rebuild on first - * open via the version-mismatch detector below. - */ +/** Bump on any DDL change; `createSchema()` auto-rebuilds on mismatch. */ export const SCHEMA_VERSION = 3; export type { CodemapDatabase }; @@ -254,11 +245,9 @@ export function deleteFileData(db: CodemapDatabase, filePath: string) { } /** - * One row in the `files` table — the header for every indexed file. All other - * row types reference `path` (FK with `ON DELETE CASCADE`). `content_hash` is - * SHA-256 hex from `src/hash.ts` and drives incremental staleness detection. - * - * Schema: see [docs/architecture.md § `files`](../docs/architecture.md#files--every-indexed-file-strict). + * Header row for every indexed file; all other rows FK `file_path` here with + * `ON DELETE CASCADE`. `content_hash` is SHA-256 hex (see `src/hash.ts`) and + * drives incremental staleness detection + the `files-hashes` recipe. */ export interface FileRow { path: string; @@ -287,13 +276,10 @@ export function insertFile(db: CodemapDatabase, file: FileRow) { } /** - * One row in the `symbols` table — top-level or nested function / const / class - * / interface / type / enum / method / property / getter / setter. Class - * members carry `parent_name`. JSDoc tags (`@deprecated`, `@internal`, etc.) - * live in `doc_comment` and power the `deprecated-symbols` / - * `visibility-tags` recipes. - * - * Schema: see [docs/architecture.md § `symbols`](../docs/architecture.md#symbols--functions-constants-classes-interfaces-types-enums-strict). + * Function / const / class / interface / type / enum, plus class members + * (`method` / `property` / `getter` / `setter`) — class members carry + * `parent_name`. JSDoc tags in `doc_comment` power the `deprecated-symbols` + * and `visibility-tags` recipes; `members` is JSON for enums. */ export interface SymbolRow { file_path: string; @@ -361,12 +347,9 @@ export function insertSymbols(db: CodemapDatabase, symbols: SymbolRow[]) { } /** - * One row in the `imports` table — a raw `import` statement. `specifiers` is a - * JSON-encoded string array. `resolved_path` is non-null only when the - * resolver could map `source` to a file inside the indexed set (see - * `dependencies` for the resolved edge view). - * - * Schema: see [docs/architecture.md § `imports`](../docs/architecture.md#imports--import-statements-strict). + * Raw `import` statement. `specifiers` is JSON; `resolved_path` is null when + * the resolver couldn't map `source` to an indexed file (see `dependencies` + * for the resolved edge view). */ export interface ImportRow { file_path: string; @@ -396,11 +379,8 @@ export function insertImports(db: CodemapDatabase, imports: ImportRow[]) { } /** - * One row in the `exports` table — named, default, or re-export. `kind` is one - * of `value` / `type` / `re-export`; `re_export_source` is non-null only for - * `re-export` rows. - * - * Schema: see [docs/architecture.md § `exports`](../docs/architecture.md#exports--export-declarations-strict). + * Named, default, or re-export. `kind` is `value` / `type` / `re-export`; + * `re_export_source` is non-null only for `re-export` rows. */ export interface ExportRow { file_path: string; @@ -422,13 +402,9 @@ export function insertExports(db: CodemapDatabase, exports: ExportRow[]) { } /** - * One row in the `components` table — React component detected by PascalCase - * name plus JSX return or hook usage. `hooks_used` is a JSON-encoded string - * array (e.g. `'["useState","useEffect"]'`). PascalCase functions in `.tsx` - * that neither return JSX nor call hooks are stored as `symbols` only, never - * as `components`. - * - * Schema: see [docs/architecture.md § `components`](../docs/architecture.md#components--react-components-detected-by-pascalcase--jsx-return-or-hook-usage-strict). + * React component (PascalCase + JSX return or hook usage). `hooks_used` is + * JSON, e.g. `'["useState","useEffect"]'`. PascalCase functions that neither + * return JSX nor call hooks stay in `symbols` only. */ export interface ComponentRow { file_path: string; @@ -459,12 +435,8 @@ export function insertComponents( } /** - * One row in the `dependencies` table — a resolved file-to-file edge derived - * from `imports.resolved_path`. Self-edges and unresolved imports are - * excluded. `(from_path, to_path)` is the composite primary key - * (`STRICT, WITHOUT ROWID`). - * - * Schema: see [docs/architecture.md § `dependencies`](../docs/architecture.md#dependencies--resolved-file-to-file-dependency-graph-strict-without-rowid). + * Resolved file-to-file edge derived from `imports.resolved_path`. Composite + * PK `(from_path, to_path)`; self-edges and unresolved imports are excluded. */ export interface DependencyRow { from_path: string; @@ -482,11 +454,8 @@ export function insertDependencies(db: CodemapDatabase, deps: DependencyRow[]) { } /** - * One row in the `markers` table — a `TODO` / `FIXME` / `HACK` / `NOTE` comment - * extracted from any indexed file (TS, CSS, Markdown, JSON, YAML, …). - * `content` is the comment text without the marker prefix. - * - * Schema: see [docs/architecture.md § `markers`](../docs/architecture.md#markers--todofixmehacknote-comments-extracted-from-all-file-types-strict). + * `TODO` / `FIXME` / `HACK` / `NOTE` comment from any indexed file (TS, CSS, + * Markdown, JSON, YAML, …). `content` excludes the marker prefix. */ export interface MarkerRow { file_path: string; @@ -506,11 +475,8 @@ export function insertMarkers(db: CodemapDatabase, markers: MarkerRow[]) { } /** - * One row in the `css_variables` table — a CSS custom property - * (`--token: value`). `scope` is `:root`, `@theme` (Tailwind v4), or the - * selector text where the property was declared. - * - * Schema: see [docs/architecture.md § `css_variables`](../docs/architecture.md#css_variables--css-custom-properties-design-tokens-strict). + * CSS custom property (`--token: value`). `scope` is `:root`, `@theme` + * (Tailwind v4), or the selector text where the property was declared. */ export interface CssVariableRow { file_path: string; @@ -535,11 +501,8 @@ export function insertCssVariables( } /** - * One row in the `css_classes` table — a class name extracted from a CSS - * selector (without the leading `.`). `is_module` is `1` when the file ends - * in `.module.css` (CSS Modules — names are usually rewritten by bundlers). - * - * Schema: see [docs/architecture.md § `css_classes`](../docs/architecture.md#css_classes--css-class-definitions-strict). + * Class name from a CSS selector (no leading `.`). `is_module = 1` for + * `.module.css` files (names get rewritten by bundlers). */ export interface CssClassRow { file_path: string; @@ -558,11 +521,7 @@ export function insertCssClasses(db: CodemapDatabase, classes: CssClassRow[]) { ); } -/** - * One row in the `css_keyframes` table — a `@keyframes ` declaration. - * - * Schema: see [docs/architecture.md § `css_keyframes`](../docs/architecture.md#css_keyframes--keyframes-animation-definitions-strict). - */ +/** `@keyframes ` declaration. */ export interface CssKeyframeRow { file_path: string; name: string; @@ -583,13 +542,10 @@ export function insertCssKeyframes( } /** - * One row in the `calls` table — a function-scoped call edge, deduped per - * `(caller_scope, callee_name)` per file. `caller_scope` is the dot-joined - * enclosing scope (e.g. `UserService.run`) so same-named methods in different - * classes stay distinct. Module-level calls (outside any function) are - * intentionally excluded. - * - * Schema: see [docs/architecture.md § `calls`](../docs/architecture.md#calls--function-scoped-call-edges-deduped-per-file-strict). + * Function-scoped call edge, deduped per `(caller_scope, callee_name)` per + * file. `caller_scope` is the dot-joined enclosing scope (e.g. `UserService.run`) + * so same-named methods in different classes stay distinct. Module-level + * calls are excluded. */ export interface CallRow { file_path: string; @@ -609,12 +565,9 @@ export function insertCalls(db: CodemapDatabase, calls: CallRow[]) { } /** - * One row in the `type_members` table — a property or method signature on an - * interface or object-literal type alias. `symbol_name` references the parent - * `symbols.name`; `type` is the raw annotation string (or `null` when the - * parser cannot reconstruct it). - * - * Schema: see [docs/architecture.md § `type_members`](../docs/architecture.md#type_members--properties-and-methods-of-interfaces-and-object-literal-types-strict). + * Property / method signature on an interface or object-literal type. + * `symbol_name` references the parent `symbols.name`; `type` is null when + * the parser can't reconstruct the annotation. */ export interface TypeMemberRow { file_path: string; diff --git a/src/parsed-types.ts b/src/parsed-types.ts index 902a37d..9d66c1d 100644 --- a/src/parsed-types.ts +++ b/src/parsed-types.ts @@ -13,60 +13,32 @@ import type { } from "./db"; /** - * One indexed file's extracted data — workers return arrays of these and - * `LanguageAdapter`s populate a {@link ParsedFilePayload} subset of these - * fields. Row shapes (`SymbolRow`, `ImportRow`, …) mirror the SQLite schema - * documented in `docs/architecture.md § Schema`. + * One indexed file's extracted data; workers return arrays of these and + * `LanguageAdapter`s populate a {@link ParsedFilePayload} subset. */ export interface ParsedFile { - /** Path relative to project root; primary key for the `files` table. */ + /** Path relative to project root. */ relPath: string; - /** - * Set to `true` when the file could not even be read from disk - * (`fileRow` is then a placeholder and other fields are undefined). - * Distinct from {@link ParsedFile.parseError} — see that field. - */ + /** `true` when the file couldn't be read from disk (distinct from `parseError`). */ error?: boolean; - /** - * Error message from the parser when extraction threw but the file *was* - * read successfully. The `files` row is still inserted so incremental - * runs do not retry parsing on every pass. - */ + /** Parser threw but the file was read; the `files` row is still inserted. */ parseError?: string; - /** Row to insert into the `files` table (path, hash, size, language, …). */ fileRow: FileRow; - /** - * Selects which extraction path the result came from: - * - `ts` — TS/TSX/JS/JSX (oxc-parser): symbols/imports/exports/etc. - * - `css` — CSS (lightningcss): variables/classes/keyframes/imports. - * - `text` — Markers-only (Markdown, JSON, YAML, fallback for unknown ext). - */ + /** Extraction path: `ts` (oxc), `css` (lightningcss), or `text` (markers-only). */ category: "ts" | "css" | "text"; - /** Worker-side wall-clock parse time; surfaced by `--performance`. */ + /** Worker-side parse wall-clock; surfaced by `--performance`. */ parseMs?: number; - /** Top-level + nested symbols (functions, classes, interfaces, …). */ symbols?: SymbolRow[]; - /** `import` statements (alias-resolved separately into `dependencies`). */ imports?: ImportRow[]; - /** Named, default, and re-exports. */ exports?: ExportRow[]; - /** React components detected via PascalCase + JSX/hooks heuristic. */ components?: ComponentRow[]; - /** `TODO` / `FIXME` / `HACK` / `NOTE` comments (extracted from any category). */ markers?: MarkerRow[]; - /** Properties and method signatures of interfaces / object-literal types. */ typeMembers?: TypeMemberRow[]; - /** Function-scoped call edges (deduped per `caller_scope` + `callee_name`). */ calls?: CallRow[]; - /** CSS custom properties (`--var`) — only emitted when `category === "css"`. */ + /** CSS-only fields (populated when `category === "css"`). */ cssVariables?: CssVariableRow[]; - /** CSS class definitions, with `is_module` flag for `.module.css` files. */ cssClasses?: CssClassRow[]; - /** `@keyframes` animation definitions. */ cssKeyframes?: CssKeyframeRow[]; - /** - * Raw `@import` source strings from CSS — main thread converts them into - * `imports` rows (with `resolved_path = null`) before insertion. - */ + /** Raw `@import` strings; main thread converts these to `imports` rows. */ cssImportSources?: string[]; } From 351a0fa9cef922562236ff136cf3a8ccebc0bfc4 Mon Sep 17 00:00:00 2001 From: Sutu Sebastian Date: Mon, 27 Apr 2026 14:45:30 +0300 Subject: [PATCH 09/12] fix(cli): trim --for whitespace, normalize POSIX separators in validate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two follow-ups from PR #23 review: C1 — `cmd-context.ts:98-109` — `--for " "` (whitespace-only) was slipping past the `v === ""` guard added in 0fafbff and silently being classified as "other" with `intent.input = " "`. Reject anything that trims to empty, and store the trimmed value so leading/trailing spaces in quoted intents don't leak into the envelope. +2 tests (whitespace-only rejection, trim-around-content). C2 — `cmd-validate.ts:142-145` — Cross-platform bug. The `files.path` column always stores POSIX paths (tinyglobby and Bun.Glob normalize on Windows; git diff emits POSIX universally), but `path.relative()` on Windows returns backslash-separated paths. So `codemap validate C:\proj\src\foo.ts` would build a `src\foo.ts` lookup key that fails to match `src/foo.ts` in the index, falsely reporting a tracked file as `unindexed`. Mirror the same `replace(/\\/g, "/")` normalization already in `lint-staged.config.js:12,21`. No new test — the helper is private and the `sep === "/"` short-circuit makes it a no-op on macOS / Linux. --- src/cli/cmd-context.test.ts | 14 ++++++++++++++ src/cli/cmd-context.ts | 4 ++-- src/cli/cmd-validate.ts | 13 ++++++++++--- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/src/cli/cmd-context.test.ts b/src/cli/cmd-context.test.ts index 864b041..b31a252 100644 --- a/src/cli/cmd-context.test.ts +++ b/src/cli/cmd-context.test.ts @@ -53,6 +53,20 @@ describe("parseContextRest", () => { expect(r.kind).toBe("error"); }); + it("errors when --for value is whitespace-only", () => { + const r = parseContextRest(["context", "--for", " "]); + expect(r.kind).toBe("error"); + }); + + it("trims the intent before storing it", () => { + const r = parseContextRest(["context", "--for", " refactor auth "]); + expect(r).toEqual({ + kind: "run", + compact: false, + intent: "refactor auth", + }); + }); + it("rejects unknown options", () => { expect(parseContextRest(["context", "--nope"]).kind).toBe("error"); }); diff --git a/src/cli/cmd-context.ts b/src/cli/cmd-context.ts index 2dee972..c75bcff 100644 --- a/src/cli/cmd-context.ts +++ b/src/cli/cmd-context.ts @@ -97,13 +97,13 @@ export function parseContextRest( } if (a === "--for") { const v = rest[i + 1]; - if (v === undefined || v === "" || v.startsWith("--")) { + if (v === undefined || v.startsWith("--") || v.trim() === "") { return { kind: "error", message: 'codemap: "--for" requires an intent string in quotes.', }; } - intent = v; + intent = v.trim(); i++; continue; } diff --git a/src/cli/cmd-validate.ts b/src/cli/cmd-validate.ts index 8d1d144..4a87a03 100644 --- a/src/cli/cmd-validate.ts +++ b/src/cli/cmd-validate.ts @@ -1,5 +1,5 @@ import { readFileSync } from "node:fs"; -import { isAbsolute, relative, resolve } from "node:path"; +import { isAbsolute, relative, resolve, sep } from "node:path"; import { loadUserConfig, resolveCodemapConfig } from "../config"; import { closeDb, openDb } from "../db"; @@ -139,9 +139,16 @@ export function computeValidateRows( return rows; } +/** + * Convert a CLI-supplied path to a project-relative POSIX-style key matching + * the `files.path` format stored in the index. `path.relative()` returns + * backslash-separated paths on Windows; the index always stores forward + * slashes (tinyglobby / Bun.Glob / git diff all emit POSIX), so we normalize + * here to make `indexByPath.get(rel)` succeed cross-platform. + */ function toProjectRelative(projectRoot: string, p: string): string { - if (isAbsolute(p)) return relative(projectRoot, p); - return p; + const rel = isAbsolute(p) ? relative(projectRoot, p) : p; + return sep === "/" ? rel : rel.split(sep).join("/"); } /** From 81ee46a18094f83fa9059a65b7d5da9d23e808fb Mon Sep 17 00:00:00 2001 From: Sutu Sebastian Date: Mon, 27 Apr 2026 14:52:59 +0300 Subject: [PATCH 10/12] docs: migrate competitive scan into roadmap, why-codemap, and the docs index MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Following docs/README.md conventions ("one topic per file", no flag duplication, single-source-of-truth): roadmap.md - Drop `--performance` from backlog (shipped in PR #23). - Add 4 backlog entries that the scan flagged as still open: MCP server, HTTP API (`codemap serve`), recipes-as-content registry + project-local recipes, targeted-read CLI (`codemap show `), cross-agent handoff artifact (speculative). - Expand "Non-goals (v1)" with the explicit list inherited from the scan's PASS table — static analysis (fallow's class), visualization (skyline), daemon, deep intent classification beyond `codemap context`. Roadmap is now the canonical home for these. why-codemap.md - Add "Codemap vs alternatives" comparison (Codemap / fallow / Aider RepoMap / LSP) — durable positioning material from the scan's side-by-side. Frames the four tools as solving different problems rather than competing for one slot. docs/research/competitive-scan-2026-04.md - Slim from 210 lines (full ranked adopt/watch/pass list, messaging lessons, next steps) to 87 lines of durable narrative: dated context, sources, positioning recap, raw side-by-side, "what shipped" appendix linking to canonical homes, "what moved to roadmap" pointer, two open questions still open, citations. - Replaces sections that are now duplicates of canonical docs. docs/README.md - Add a `research/` row to the topic index pointing at the new folder convention (dated snapshot notes that link back to canonical homes). - Add "Non-goals (v1)" row to the Single Source of Truth table — roadmap.md is canonical, why-codemap.md carries the consumer-facing framing, research/ notes link here and never re-list. --- docs/README.md | 24 +-- docs/research/competitive-scan-2026-04.md | 207 +++++----------------- docs/roadmap.md | 21 ++- docs/why-codemap.md | 19 ++ 4 files changed, 94 insertions(+), 177 deletions(-) diff --git a/docs/README.md b/docs/README.md index a8bdadf..b1e3cab 100644 --- a/docs/README.md +++ b/docs/README.md @@ -15,20 +15,22 @@ Technical docs for **[@stainless-code/codemap](https://github.com/stainless-code | [fixtures/benchmark/](../fixtures/benchmark/) | Tracked [scenarios.example.json](../fixtures/benchmark/scenarios.example.json) — copy to `*.local.json` (gitignored) for [`CODEMAP_BENCHMARK_CONFIG`](./benchmark.md#custom-scenarios-codemap_benchmark_config) | | [fixtures/qa/](../fixtures/qa/) | [prompts.external.template.md](../fixtures/qa/prompts.external.template.md) — optional chat QA prompts for an external index (`*.local.md` gitignored) | | [packaging.md](./packaging.md) | **`CHANGELOG.md` / `dist/` / `templates/`** on npm, **engines**, [**Node vs Bun**](./packaging.md#node-vs-bun), [**Releases**](./packaging.md#releases) (Changesets; **`bun run version`** + oxfmt **`CHANGELOG.md`**) | -| [roadmap.md](./roadmap.md) | Forward-looking backlog (not a `src/` inventory) | +| [roadmap.md](./roadmap.md) | Forward-looking [**Backlog**](./roadmap.md#backlog) and [**Non-goals**](./roadmap.md#non-goals-v1) (not a `src/` inventory) | +| [research/](./research/) | Dated, snapshot-style notes (e.g. competitive scans). Each note links shipped items back to canonical homes — see [research/competitive-scan-2026-04.md](./research/competitive-scan-2026-04.md) | ## Single source of truth (do not duplicate) -| Topic | Canonical doc | Elsewhere | -| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | -| Runtime splits (SQLite, workers, globs, JSON config I/O) | [packaging § Node vs Bun](./packaging.md#node-vs-bun) — **the table lives here** | [architecture § Runtime](./architecture.md#runtime-and-database) links here; do not copy the table | -| **`codemap.config.*`** shape / Zod validation | [architecture § User config](./architecture.md#user-config) | Root [README § Configuration](../README.md#configuration) points here | -| **`codemap agents init`**: **`--force`** on **`.agents/`** in **consumer projects** (template file paths only), IDE matrix, per-file symlink/copy, **`templates/agents`** | [agents.md](./agents.md) | Link here; do not paste the integration table into README or packaging | -| **`CLAUDE.md` / `AGENTS.md` / `GEMINI.md` / Copilot** — managed **`codemap-pointer`** sections, merge vs **`--force`** | [agents.md § Pointer files](./agents.md#pointer-files) | Link here; do not duplicate the situation table | -| End-user CLI (index, **`query --json`**, **`query --recipe`**, **`query --recipes-json`**, **`query --print-sql`**, agents, flags, env) — query has no row cap; use SQL **`LIMIT`**; **`--json`** errors include SQL, DB open, and bootstrap failures; bundled **`templates/agents/`** examples default to **`--json`** | [../README.md § CLI](../README.md#cli) | [architecture § CLI usage](./architecture.md#cli-usage) summarizes and links back; [agents.md](./agents.md) | -| Golden query regression (`test:golden`, `test:golden:external`, `--update`) | [golden-queries.md](./golden-queries.md) | CONTRIBUTING § Golden queries; [benchmark § Fixtures](./benchmark.md#fixtures) | -| **`CODEMAP_BENCHMARK_CONFIG`** (per-repo benchmark JSON) | [benchmark § Custom scenarios](./benchmark.md#custom-scenarios-codemap_benchmark_config) | [fixtures/benchmark/scenarios.example.json](../fixtures/benchmark/scenarios.example.json) only | -| `bun run qa:external` — index + disk checks + `benchmark.ts` on **`CODEMAP_*`** | [.github/CONTRIBUTING.md](../.github/CONTRIBUTING.md) | [scripts/qa-external-repo.ts](../scripts/qa-external-repo.ts) (invocation only) | +| Topic | Canonical doc | Elsewhere | +| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Runtime splits (SQLite, workers, globs, JSON config I/O) | [packaging § Node vs Bun](./packaging.md#node-vs-bun) — **the table lives here** | [architecture § Runtime](./architecture.md#runtime-and-database) links here; do not copy the table | +| **`codemap.config.*`** shape / Zod validation | [architecture § User config](./architecture.md#user-config) | Root [README § Configuration](../README.md#configuration) points here | +| **`codemap agents init`**: **`--force`** on **`.agents/`** in **consumer projects** (template file paths only), IDE matrix, per-file symlink/copy, **`templates/agents`** | [agents.md](./agents.md) | Link here; do not paste the integration table into README or packaging | +| **`CLAUDE.md` / `AGENTS.md` / `GEMINI.md` / Copilot** — managed **`codemap-pointer`** sections, merge vs **`--force`** | [agents.md § Pointer files](./agents.md#pointer-files) | Link here; do not duplicate the situation table | +| End-user CLI (index, **`query --json`**, **`query --recipe`**, **`query --recipes-json`**, **`query --print-sql`**, agents, flags, env) — query has no row cap; use SQL **`LIMIT`**; **`--json`** errors include SQL, DB open, and bootstrap failures; bundled **`templates/agents/`** examples default to **`--json`** | [../README.md § CLI](../README.md#cli) | [architecture § CLI usage](./architecture.md#cli-usage) summarizes and links back; [agents.md](./agents.md) | +| Golden query regression (`test:golden`, `test:golden:external`, `--update`) | [golden-queries.md](./golden-queries.md) | CONTRIBUTING § Golden queries; [benchmark § Fixtures](./benchmark.md#fixtures) | +| **`CODEMAP_BENCHMARK_CONFIG`** (per-repo benchmark JSON) | [benchmark § Custom scenarios](./benchmark.md#custom-scenarios-codemap_benchmark_config) | [fixtures/benchmark/scenarios.example.json](../fixtures/benchmark/scenarios.example.json) only | +| `bun run qa:external` — index + disk checks + `benchmark.ts` on **`CODEMAP_*`** | [.github/CONTRIBUTING.md](../.github/CONTRIBUTING.md) | [scripts/qa-external-repo.ts](../scripts/qa-external-repo.ts) (invocation only) | +| **Non-goals (v1)** — what Codemap deliberately doesn't do (full-text search, LSP, static analysis, visualization, daemon, deep intent classification) | [roadmap.md § Non-goals](./roadmap.md#non-goals-v1) | [why-codemap.md § What Codemap is not](./why-codemap.md#what-codemap-is-not) (consumer-facing framing) — links here; [research/](./research/) notes link here, never re-list | ## Conventions diff --git a/docs/research/competitive-scan-2026-04.md b/docs/research/competitive-scan-2026-04.md index 972388a..a746cbf 100644 --- a/docs/research/competitive-scan-2026-04.md +++ b/docs/research/competitive-scan-2026-04.md @@ -1,8 +1,7 @@ # Competitive scan — fallow, AZidan/codemap, JordanCoin/codemap > Inspiration scan from three sibling tools in the "AI-friendly code intelligence" space. -> Goal: identify candidates we should adopt, ignore, or watch for our positioning of -> **`@stainless-code/codemap`** (local SQLite index of structural metadata, queried via SQL). +> Captured **2026-04-27** during PR [#23](https://github.com/stainless-code/codemap/pull/23). Most adopt items shipped in that PR; remaining items moved to [docs/roadmap.md](../roadmap.md). Sources: @@ -12,15 +11,15 @@ Sources: --- -## 1. Positioning recap (us) +## 1. Positioning recap (snapshot at scan time) -We are: **structural SQLite index** → agents call **SQL** for symbols, imports, exports, components, calls, type members, deps, CSS tokens/classes/keyframes, markers. AST-backed (oxc, lightningcss, oxc-resolver). Bun + Node, TS/CSS-first. CLI **`codemap query --json`** + **`codemap agents init`** for IDE wiring. +**Codemap is:** a **structural SQLite index** → agents call **SQL** for symbols, imports, exports, components, calls, type members, deps, CSS tokens/classes/keyframes, markers. AST-backed (oxc, lightningcss, oxc-resolver). Bun + Node, TS/CSS-first. CLI **`codemap query --json`** + **`codemap agents init`** for IDE wiring. -We are **not**: dead-code detector, duplication finder, dependency-flow visualizer, semantic understanding layer, agent runtime/MCP server (yet). +**Codemap is not:** a dead-code detector, duplication finder, dependency-flow visualizer, semantic understanding layer, or agent runtime. The canonical "what Codemap is not" list now lives in [why-codemap.md § What Codemap is not](../why-codemap.md#what-codemap-is-not) and the explicit non-goals are in [roadmap.md § Non-goals](../roadmap.md#non-goals-v1) — keep this doc free of duplicates. --- -## 2. Side-by-side +## 2. Side-by-side (snapshot) | Axis | **us** | fallow | AZidan/codemap | JordanCoin/codemap | | ----------------- | --------------------------------------- | ------------------------------------------------------ | ------------------------------------ | -------------------------------------------- | @@ -35,175 +34,63 @@ We are **not**: dead-code detector, duplication finder, dependency-flow visualiz | Headline pitch | "query your codebase" | "codebase truth layer for agents" | "make every read cheaper" | "project brain for your AI" | | License | MIT | MIT (+ paid runtime) | MIT | MIT | ---- - -## 3. Candidates worth stealing / borrowing - -Ranked by impact × fit for our SQL-index thesis. **Adopt** = strong fit; **Watch** = revisit; -**Pass** = scope/philosophy mismatch. - -### 3.1 ADOPT — short list - -#### A. **MCP server wrapping `query`** (already in [roadmap.md backlog](../roadmap.md)) - -- **Inspired by:** JordanCoin (`codemap mcp` over stdio + `list_skills`, `get_skill`, `context`), fallow (MCP server bundled in npm), AZidan (planned). -- **Why:** Our SQL surface is more powerful than any of theirs once exposed. An MCP `query`/`recipe`/`list_recipes` tool gives Cursor/Claude/Windsurf agents direct access without shelling out. Strongest single move. -- **Concrete shape:** - - Tools: `query` (SQL string → JSON rows), `recipe` (id → JSON rows), `list_recipes` (catalog), `index` (incremental), `schema` (DDL). - - Resources: bundled `SKILL.md`, `agents/rules/codemap.md`, current schema, recipe catalog. - - Prompts: a couple of "explore this codebase" templates that pre-bind the SQL skill. -- **Fit:** Tracer-bullet friendly — slice = one tool (`query`) + one transport (stdio) wired into existing `cli/cmd-query.ts`. - -#### B. **HTTP API** (`codemap serve`) - -- **Inspired by:** JordanCoin (`codemap serve` → `/api/context`, `/api/skills`, `/api/working-set`). -- **Why:** Some integrations don't speak MCP yet. A localhost HTTP server with the same query/recipe surface (`POST /query`, `GET /recipes`, `GET /recipes/:id`, `GET /schema`) is ~50 lines and unblocks tooling outside the MCP ecosystem. -- **Caveat:** Bind to `127.0.0.1`. No auth needed for local; reject non-loopback unless `--host` overridden. - -#### C. **Recipes-as-content registry** (extension of what we already ship) - -- **Inspired by:** JordanCoin "skills framework" (markdown w/ YAML frontmatter, project-local override, `skill list`/`show`/`init`); fallow "framework plugins" (91 of them). -- **Why:** We already have `query --recipes-json` / `--print-sql`. Pairing each recipe with a short markdown explanation (when to use, what shape, follow-up SQL) gives agents executable context. A `codemap recipes show ` could print SQL + prose. Project-local recipes in `.codemap/recipes/*.sql` (or `.json`) would let teams ship internal SQL. -- **Concrete shape:** - - Bundled recipes already exist in **`src/cli/query-recipes.ts`** — add an optional `description.md` sibling and surface in `--recipes-json`. - - Allow user recipes from `.codemap/recipes/` (read at query time) — first-class extension point that doesn't require new adapter API. - -#### D. **`codemap context` JSON envelope** for any agent/CLI - -- **Inspired by:** JordanCoin `codemap context` / `--for "intent"` / `--compact`. -- **Why:** Single command emitting a stable JSON object — project metadata, schema version, top hubs, recent markers, file count, recipe catalog — that any agent can pipe into a prompt. Cheap to build because it's just a few of our existing recipes serialized into one envelope. -- **Stub:** `codemap context [--compact] [--for ""]` → `{ project, schema, hubs, recipes, recent_markers, file_count }`. - -#### E. **Hash-based staleness check** (verify without re-reading) - -- **Inspired by:** AZidan `codemap validate` (returns stale entries; LLM checks if a file changed _without_ re-reading). -- **Why:** We already store **`files.content_hash`** (SHA-256). Expose `codemap validate [paths…]` that prints stale paths in JSON. Tiny lift, big agent UX win — agents can ask "are my notes still valid?" for the cost of a SQL row, then re-read only the dirty ones. -- **One-liner:** `SELECT path FROM files WHERE content_hash != ?` — implementation just a CLI wrapper. - -#### F. **Hub / fan-in summary as first-class output** (we have data, lacking presentation) - -- **Inspired by:** JordanCoin "HUBS: config (12←), api (8←)" surface in `--deps`. -- **Why:** We already compute fan-in/fan-out via `dependencies` table and have a `fan-out` recipe. Add `hubs` recipe (top-N most-imported files) and surface in the `context` envelope above. Pure SQL, no new code. - -#### G. **Doc-comment + `@deprecated` recipes** (we already store `doc_comment`) - -- **Inspired by:** Fallow JSDoc visibility tags (`@public`, `@internal`, `@deprecated` driving dead-code policy). -- **Why:** Our `symbols.doc_comment` already preserves `@deprecated`. Recipes: - - `deprecated-symbols` — `WHERE doc_comment LIKE '%@deprecated%'` - - `internal-only` — visibility tag scan -- Cheap, recipe-only change. - -### 3.2 WATCH — interesting, defer until v2 - -#### W1. **Targeted reads as the main UX** (AZidan) - -- The "find symbol → read only lines 15–89" workflow is exactly what our `symbols.line_start/line_end` enables, but we don't currently ship a one-step CLI like `codemap show src/file.ts` or `codemap snippet symbolName`. Worth considering once MCP lands; agents can do it via SQL today. -- Low-hanging recipe: `read-symbol` — input `name` → output `file_path, line_start, line_end, signature`. - -#### W2. **Watch mode** (already in roadmap; both JordanCoin and AZidan ship it) - -- Both projects use file watchers (chokidar / `fsnotify`) to keep their index live. Our incremental + `--files` already cover most of this; a `codemap watch` is plumbing, not architecture. - -#### W3. **Project-local skills/recipes** (JordanCoin, fallow plugins) - -- A `.codemap/skills/*.md` or `.codemap/recipes/*.sql` directory that overrides bundled — same pattern as JordanCoin's project-local skill override. Pairs naturally with our existing `agents init`. - -#### W4. **Cross-agent handoff artifact** (JordanCoin) - -- Layered prefix/delta JSON written on session-stop, read on session-start. Interesting because it's complementary to indexing — a separate "what's been touched lately" log. Probably an _outside-of-codemap_ tool, but the daemon mode is worth thinking about (one persistent process can host MCP + HTTP + watcher). - -#### W5. **Remote-repo support** (JordanCoin `codemap github.com/x/y`) - -- Shallow clone to temp dir, index, query, cleanup. Trivial wrapper around `git clone --depth 1` + our existing CLI. Not central to our thesis but very low-cost demo. - -### 3.3 PASS — explicit non-goals - -| Idea | Source | Why we pass | -| ----------------------------------------------------------- | ----------------------------------- | ----------------------------------------------------------------------------------------------------------------- | -| Dead-code, duplication, complexity, boundaries, fix-actions | fallow | Different product class. Our "structural index" thesis stays a primitive that fallow-style tools could _consume_. | -| Runtime/V8/Istanbul coverage merging, paid tier | fallow runtime | Out of scope for v1; would massively expand surface. | -| 91 framework plugins | fallow | They're entry-point detectors for _dead-code_. Our index isn't entry-point-aware (we index everything globbed). | -| PageRank-style "summarization" | aider RepoMap (mentioned by AZidan) | We agree with AZidan: don't summarize, let the agent decide via SQL. | -| Skyline ASCII-art / animation | JordanCoin | Pure demoware. | -| Daemon process for hooks | JordanCoin | Optional later. SQLite already supports concurrent readers; one-shot CLI is fine for now. | -| Embedded "intent classification" (regex over user prompts) | JordanCoin | Belongs in the agent / MCP host, not in the index tool. | +> A consumer-facing distillation of this table — focused on philosophy/scope rather than implementation — lives in [why-codemap.md § Codemap vs alternatives](../why-codemap.md#codemap-vs-alternatives). Keep prose comparisons there; this row is the unfiltered scan record. --- -## 4. Messaging lessons - -The three highest-signal positioning lessons from this audit. Each one has a clear target file and a one-shot edit. - -### 4.1 Anti-pitch — "what Codemap is **not**" - -- **Source:** AZidan's _"What CodeMap is not"_ section ("not a semantic analyzer / not an LSP / not an agent / not smart"). -- **Why it wins:** preempts the "is this an LSP / agent / smart tool?" question before the reader forms it. Cleaner than our current framing in [why-codemap.md](../why-codemap.md). -- **Where to land it:** [docs/why-codemap.md](../why-codemap.md) — add a subsection above "The Solution" that explicitly lists Codemap is **not** full-text search, **not** an LSP, **not** an agent, **not** a static analyzer / dead-code detector, **not** a semantic embedder. -- **Cost:** ~10 lines, pure docs. - -### 4.2 Token-savings table — concrete scenarios, our own numbers - -- **Source:** AZidan's table: - | Scenario | Without | With | Savings | - | --- | --- | --- | --- | - | Single class lookup | 1,700 tok | 1,000 tok | 41% | - | 10-file refactor | 51,000 tok | 11,600 tok | 77% | - | 50-turn coding session | 70,000 tok | 21,000 tok | 70% | -- **Why it wins:** "very large vs ~5K" (our current text) reads as hand-waving. A 3-row table reads as evidence. -- **Where to land it:** [docs/why-codemap.md § Across a Typical Session](../why-codemap.md#across-a-typical-session) — replace the existing `Token cost (10/20 questions)` table with scenario-keyed rows. -- **Cost:** numbers come from `bun run benchmark:query` + `src/benchmark.ts` (already producing token impact estimates). Just present them. - -### 4.3 "Grep/Read vs Codemap" capability table - -- **Source:** Fallow's "Linter vs Fallow" table — rows like _"unused export that nothing imports"_ with `yes / no` per tool. -- **Why it wins:** concrete capability rows are far more persuasive than prose. Many such rows already live in our [golden-queries.md](../golden-queries.md) and [SKILL.md](../../.agents/skills/codemap/SKILL.md) but they're buried. -- **Where to land it:** [README.md](../../README.md), near the top — table with rows like: - | Question | Grep / Read | Codemap | - | --- | --- | --- | - | Find symbol by exact name | yes (slow + noisy) | one SQL row | - | Who imports `~/utils/date`? | resolve aliases manually | one SQL row | - | Components using `useQuery` | grep + filter manually | one SQL row | - | All CSS keyframes in project | grep `@keyframes` | one SQL row | - | Heaviest files by import fan-out | impractical | one SQL row | -- **Cost:** ~15 lines of markdown, all queries already exist as recipes. +## 3. What shipped from this scan + +| Idea (originally §3 / §4 / §5 of this scan) | Shipped where | Inspired by | +| --------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | ----------------------------------------------------- | +| `codemap context` JSON envelope (incl. `--for ""` thin classifier, `--compact`) | `src/cli/cmd-context.ts` | JordanCoin (`codemap context`) | +| `codemap validate` (hash-based staleness, no re-read) | `src/cli/cmd-validate.ts` | AZidan (`codemap validate`) | +| `--performance` per-phase timing + top-10 slowest files | `src/application/index-engine.ts` | own roadmap, sharpened by JordanCoin's daemon framing | +| `deprecated-symbols` recipe | `src/cli/query-recipes.ts` | fallow JSDoc visibility tags | +| `visibility-tags` recipe (`@internal` / `@private` / `@alpha` / `@beta`) | `src/cli/query-recipes.ts` | fallow JSDoc visibility tags | +| `barrel-files` recipe (top files by export count) | `src/cli/query-recipes.ts` | own derivation from JordanCoin "hubs" framing | +| `files-hashes` recipe powering `validate` | `src/cli/query-recipes.ts` | AZidan | +| `-r` short alias for `--recipe`, cleaner `--help` | `src/cli/cmd-query.ts` | own UX polish | +| Friendlier "no `.codemap.db`" error | `src/application/index-engine.ts` | own UX polish | +| Anti-pitch — "What Codemap is not" | [why-codemap.md § What Codemap is not](../why-codemap.md#what-codemap-is-not) | AZidan | +| Scenario-keyed token-savings table | [why-codemap.md § Across a Typical Session](../why-codemap.md#across-a-typical-session) | AZidan | +| "Grep/Read vs Codemap" capability table | [README.md § What you get](../../README.md#what-you-get) | fallow ("Linter vs Fallow") | +| "Daily commands" stripe + version-matched skill framing | [README.md § CLI](../../README.md#cli) | JordanCoin / fallow packaging | +| Alternatives comparison table | [why-codemap.md § Codemap vs alternatives](../why-codemap.md#codemap-vs-alternatives) | AZidan ("CodeMap vs RepoMap/Serena/RepoPrompt") | +| Schema v3 — `NOT NULL` audit (orthogonal to scan but landed in same PR) | `src/db.ts` | CodeRabbit review during PR #23 | + +All shipped under PR [#23](https://github.com/stainless-code/codemap/pull/23) as schema-bump-driven minor release. --- -## 4b. Other doc-shape ideas (lower priority) +## 4. What moved to the roadmap -- **Comparison table — Codemap vs Aider RepoMap / Serena / RepoPrompt / Fallow** — situating row in [why-codemap.md](../why-codemap.md). AZidan's table is the model. -- **Fallow's "version-matched Agent Skill" framing** — we already do this via `templates/agents/`; calling it out as "version-matched" in README packaging copy is free credibility. -- **JordanCoin's "Daily commands" block** — curate 5–6 most-used commands at the top of the README CLI section instead of the current dense list. +Items the scan called out as "watch / defer / future" that are now tracked in [docs/roadmap.md § Backlog](../roadmap.md#backlog) — go there for the latest status, not here: ---- +- MCP server wrapping `query` +- HTTP API (`codemap serve`) +- Recipes-as-content registry + project-local recipes (`.codemap/recipes/`) +- Targeted-read CLI (`codemap show `) +- Watch mode (`codemap watch`) +- Cross-agent handoff artifact (speculative) -## 5. Concrete suggested next steps (tracer-bullet sized) +The scan's "PASS" list (dead-code / dupes / complexity / boundaries / fix actions, runtime/V8 coverage merging, framework plugins, PageRank summarization, skyline visualization, daemon process, embedded intent classification) has been folded into [roadmap.md § Non-goals](../roadmap.md#non-goals-v1) — that's the canonical home; do not duplicate here. -Mapped to existing layers per [.cursor/rules/tracer-bullets.mdc](../../.cursor/rules/tracer-bullets.mdc): - -1. **Recipe: `validate-stale-files`** — pure SQL recipe added to **`src/cli/query-recipes.ts`** (input: array of paths via SQL bind, output: stale paths). Tracer slice = one recipe + golden test. **(F + E above)** -2. **Recipe: `hubs`** — top-N most-imported files using `dependencies`. Pairs with existing `fan-out`. **(F)** -3. **Recipe: `deprecated-symbols`** — JSDoc-tag scan over `symbols.doc_comment`. **(G)** -4. **`codemap context` subcommand** — emits a JSON envelope composed from a fixed set of recipes. Tracer slice = one CLI command + 1 golden test on `fixtures/minimal/`. **(D)** -5. **MCP server (`codemap mcp`)** — single `query` tool first; expand later. Tracer slice = stdio transport + one tool wired through existing `runQueryCmd` core. **(A)** -6. **HTTP server (`codemap serve --port`)** — minimal Hono/native http, `POST /query` + `GET /recipes`. Tracer slice = `bun --hot` smoke test + golden response shape. **(B)** -7. **README polish** — add "Daily commands", "What Codemap is not", "Codemap vs alternatives" tables (see §4). Pure docs PR, no code. +**Explicitly dropped:** "remote-repo support" (`codemap github.com/x/y`) — discussed in [PR #23](https://github.com/stainless-code/codemap/pull/23) and rejected as demoware that doesn't fit the SQL-index thesis. --- -## 6. Open questions +## 5. Open questions (still open) + +These were not resolved in PR #23 and warrant their own design conversations: -- **Should recipes own their description?** — JordanCoin couples skills + content tightly via YAML frontmatter; we currently keep recipes as code constants. Moving to one `recipes/.{sql,md}` pair on disk (read at runtime via Bun `import.meta.glob` / Node `readdirSync`) makes them more discoverable and contributable. -- **Daemon vs one-shot** — JordanCoin's daemon is the only way they get sub-100ms hooks. Our CLI startup is ~50–100 ms cold (Node) and lower on Bun; we may not need a daemon at all. Worth measuring once MCP/HTTP land. -- **Path-prefix / monorepo workspace awareness** — fallow has `--changed-workspaces`, `--workspace @scope/app`, JordanCoin has implicit project root detection. Already in our [roadmap § Backlog](../roadmap.md#backlog). -- **Should we adopt fallow's `--save-baseline` pattern?** — only relevant once we ship audit-style commands; today we don't, so it's noise. +- **Should recipes own their description?** — JordanCoin couples skills + content tightly via YAML frontmatter; we currently keep recipes as code constants. Moving to one `recipes/.{sql,md}` pair on disk (read at runtime via Bun `import.meta.glob` / Node `readdirSync`) makes them more discoverable and contributable. Tracked under "Recipes-as-content registry" in [roadmap.md § Backlog](../roadmap.md#backlog). +- **Daemon vs one-shot** — JordanCoin's daemon is the only way they get sub-100ms hooks. Our CLI startup is ~50–100 ms cold (Node) and lower on Bun; we may not need a daemon at all. Worth measuring once MCP/HTTP land. Roadmap lists "persistent daemon" as a non-goal **for now** with this caveat. --- -## 7. Citations / cross-links +## 6. Citations / cross-links -- [docs/roadmap.md](../roadmap.md) — current backlog including MCP, watch mode, monorepo awareness. -- [docs/why-codemap.md](../why-codemap.md) — token-cost framing this scan should feed back into. -- [docs/architecture.md](../architecture.md) — schema and CLI layering touched by these proposals. -- [src/cli/query-recipes.ts](../../src/cli/query-recipes.ts) — where recipe additions land. -- [.agents/skills/codemap/SKILL.md](../../.agents/skills/codemap/SKILL.md) — agent guidance we'd extend with new recipes. +- [docs/roadmap.md](../roadmap.md) — current backlog and non-goals +- [docs/why-codemap.md](../why-codemap.md) — anti-pitch, token-cost framing, alternatives comparison +- [docs/architecture.md](../architecture.md) — schema and CLI layering +- [PR #23](https://github.com/stainless-code/codemap/pull/23) — the implementation pass driven by this scan diff --git a/docs/roadmap.md b/docs/roadmap.md index 35121cd..a8819df 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -23,19 +23,28 @@ Forward-looking plans only — **not** a mirror of `src/`. **Doc index:** [READM ## Non-goals (v1) -- Full-text search across all file bodies (use ripgrep / IDE) -- Replacing LSP or language servers +Codemap stays a structural-index primitive that other tools can consume. Out of scope: + +- **Full-text search** across all file bodies — use ripgrep / IDE / opt-in FTS5 (see backlog) +- **Replacing LSP** or language servers — no rename / go-to-definition / hover types +- **Static analysis** — dead code, duplication, complexity, architecture-boundary detection, fix actions are a different product class (e.g. [fallow](https://github.com/fallow-rs/fallow), `knip`, `jscpd`) +- **Visualization** — skyline / ASCII art / animated diagrams; the index emits structured rows, rendering belongs to the consumer +- **Embedded intent classification** beyond the thin keyword classifier in `codemap context --for ""` — deeper routing belongs in the agent host (Cursor / Claude Code / MCP client) +- **Persistent daemon process** — SQLite supports concurrent readers and our one-shot CLI startup is sub-100ms; revisit only if MCP / HTTP measurements demand it --- ## Backlog -- [ ] **`--performance` CLI flag** — per-phase timing breakdown (glob, parse, resolve, insert, indexes) via `performance.now()`; `index-engine.ts` already has total elapsed, gap is per-phase granularity -- [ ] **Adapter scaffolding** — `codemap create-adapter --name [name]` generates adapter + test + fixture boilerplate; blocked on community adapter registration API (could land with manual registration) -- [ ] **Config loader** — two candidates: (a) [c12](https://unjs.io/packages/c12) — battle-tested (Nuxt/Nitro), adds extends, env overrides, RC files, watching; still executes config via `jiti`. (b) AST-based extraction with `oxc-parser` — faster, no side effects, safer in untrusted repos; can't handle async/dynamic configs, needs `import()` fallback. Current: native `import()` in `config.ts` -- [ ] **MCP** server wrapping `query` +- [ ] **MCP** server wrapping `query` — single stdio tool first (`query` SQL string → JSON rows), then expand to `recipe`, `list_recipes`, `schema`, `index`. Resources expose the bundled `SKILL.md` and recipe catalog +- [ ] **HTTP API** — `codemap serve [--port] [--host 127.0.0.1]` exposing `POST /query`, `GET /recipes`, `GET /recipes/:id`, `GET /schema`, `GET /context`. Bind to loopback by default; reject non-loopback unless `--host` overridden. Unblocks tools that don't speak MCP yet +- [ ] **Recipes-as-content registry** — pair every bundled recipe in `src/cli/query-recipes.ts` with a sibling `.md` (or YAML frontmatter) describing _when to use, follow-up SQL_; surface in `--recipes-json`. Plus **project-local recipes** loaded from `.codemap/recipes/*.{sql,md}` so teams can ship internal SQL without an adapter API +- [ ] **Targeted-read CLI** — `codemap show ` / `codemap snippet ` returns `file_path:line_start-line_end` + `signature` for one symbol. Same data as `SELECT … FROM symbols WHERE name = ?`, but a one-step CLI keeps agents from composing SQL for trivial precise reads - [ ] **Watch mode** for dev — `node:fs.watch` recursive + `--files` re-index loop; Linux `recursive` requires Node 19.1+ - [ ] **Monorepo / workspace awareness** — discover workspaces from `pnpm-workspace.yaml` / `package.json` and index per-workspace dependency graphs +- [ ] **Cross-agent handoff artifact** — _speculative_; layered prefix/delta JSON written on session-stop, read on session-start. Complementary to indexing rather than core to it; revisit if user demand emerges +- [ ] **Adapter scaffolding** — `codemap create-adapter --name [name]` generates adapter + test + fixture boilerplate; blocked on community adapter registration API (could land with manual registration) +- [ ] **Config loader** — two candidates: (a) [c12](https://unjs.io/packages/c12) — battle-tested (Nuxt/Nitro), adds extends, env overrides, RC files, watching; still executes config via `jiti`. (b) AST-based extraction with `oxc-parser` — faster, no side effects, safer in untrusted repos; can't handle async/dynamic configs, needs `import()` fallback. Current: native `import()` in `config.ts` - [ ] Optional **GitHub Actions** `workflow_dispatch` — run golden/benchmark against a **public** corpus only (never private app code) - [ ] Optional **FTS5** for opt-in full-text - [ ] **Sass / Less / SCSS:** [Lightning CSS](https://lightningcss.dev/) is CSS-only; preprocessors need a compile step before CSS parsing — see [architecture.md § CSS](./architecture.md#css--css-parserts-lightningcss) diff --git a/docs/why-codemap.md b/docs/why-codemap.md index 1d88b86..4f6400d 100644 --- a/docs/why-codemap.md +++ b/docs/why-codemap.md @@ -103,6 +103,25 @@ Some queries are trivial with the index but impractical (or slow) with tradition | "Exports from a specific module" | `SELECT name, kind FROM exports WHERE file_path = '...'` | Read the file → parse mentally → identify exports vs internal | | "All CSS animations in the project" | `SELECT name, file_path FROM css_keyframes` | Grep `@keyframes` across CSS files → parse names | +## Codemap vs alternatives + +Other "AI-friendly code intelligence" tools occupy different points in the design space. Each one is solving a different problem: + +| Axis | **Codemap** | [fallow](https://github.com/fallow-rs/fallow) | [Aider RepoMap](https://aider.chat) | LSP servers | +| ----------------- | ------------------------------------- | ------------------------------------------------------------- | ----------------------------------- | --------------------------- | +| Primary thesis | Query structure with **SQL** | Detect dead code / dupes / complexity | Summarize repo into a context blob | Per-edit semantic helpers | +| Output shape | Result rows from a SQL query | SARIF / JSON findings, fix `actions` | Markdown / token-budgeted text | LSP messages over stdio | +| Decides relevance | The agent (via SQL) | The tool (via static rules) | The tool (PageRank-style) | The editor | +| Scope | Structural facts (definitions, edges) | Static analysis verdicts | Whole-repo summary | One file at a time | +| Storage | Local SQLite (`.codemap.db`) | In-process; emits findings | In-prompt context | In-process index | +| Token cost | Per-query; tiny result rows | Per-run; finding lists | Upfront; bounded by token budget | None (editor-side) | +| Best for | Targeted "where / what / who" lookups | "Did this PR introduce dead code / dupes / complexity drift?" | First-touch context priming | Editor-time refactoring | +| Worst for | Whole-file semantic understanding | Granular structural lookups (different shape) | Targeted line-range reads | Cross-cutting graph queries | + +**Why this matters:** Codemap deliberately **doesn't try to be smart**. Other tools predict what context an agent will need; Codemap lets the agent decide and just makes each decision cheap. The same agent can use Codemap **and** fallow **and** an LSP — they don't compete for the same slot. + +For more on what Codemap deliberately does **not** do, see [What Codemap is not](#what-codemap-is-not) above and [docs/roadmap.md § Non-goals](./roadmap.md#non-goals-v1). + ## Cost Summary | Dimension | Without Index | With Index | Improvement | From b4c33600b316eea9360b818bea4592cbc4ef91c3 Mon Sep 17 00:00:00 2001 From: Sutu Sebastian Date: Mon, 27 Apr 2026 15:01:59 +0300 Subject: [PATCH 11/12] docs(governance): adopt rules + lifecycle from PaySpace analytics docs; add glossary, plans/ folder, and an enforcement rule MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Lifts the high-signal subset of the analytics docs governance pattern: - Rules for Agents (numbered, normative — cite by number in PR review) - Document Lifecycle (4 doc types: Reference / Roadmap / Plan / Research) - Existence test for whether a doc earns its place - Top-level cap rule - Closing rules for research notes (codifies what we did manually for competitive-scan-2026-04.md) docs/README.md - Restructure into File Ownership → Rules for Agents → Single Source of Truth → Document Lifecycle → Naming Conventions → Conventions. - Move existing "Conventions" prose to the bottom as a stylistic addendum to the rules above. - Add 9 numbered rules (one source of truth, ship-flow, plans, table freshness, relative paths, no inventory counts, no line-numbers, research closing, glossary updates). - Add Document Lifecycle section with 4 doc types, the existence test, closing-research rules, and the top-level cap. - Add `glossary.md`, `plans/`, `research/` rows to File Ownership. - Add "Domain term definitions" + "Non-goals" rows to Single Source of Truth (canonical = glossary.md / roadmap.md, others link). docs/glossary.md (new) - ~70 entries covering schema/parser/recipe/agent terminology. - Disambiguates pairs that look similar: FileRow vs `files` table, recipe vs query, schema vs DDL, hub vs barrel-file, fan-in vs fan-out, parser vs adapter, plan vs research, rule vs skill. - Links recipe + table entries back to architecture.md schema sections for deep details (Rule 1 — one source of truth). docs/plans/.gitkeep (new) - Empty folder so the convention is in place for the first plan that lands. Don't add the `-plan` suffix per the naming convention. .agents/rules/docs-governance.md + .cursor/rules/docs-governance.mdc (new) - alwaysApply rule pointing at docs/README.md as canonical source. - Carries the 9-rule quick checklist + the existence test + top-level cap so agents see them at session start without reading the full docs/README.md every time. - Symlinked into .cursor/rules/ per the agents-first-convention rule. No source code touched; 185/185 tests still pass; goldens all green. --- .agents/rules/docs-governance.md | 60 +++++ .cursor/rules/docs-governance.mdc | 1 + docs/README.md | 121 +++++++-- docs/glossary.md | 412 ++++++++++++++++++++++++++++++ docs/plans/.gitkeep | 0 5 files changed, 577 insertions(+), 17 deletions(-) create mode 100644 .agents/rules/docs-governance.md create mode 120000 .cursor/rules/docs-governance.mdc create mode 100644 docs/glossary.md create mode 100644 docs/plans/.gitkeep diff --git a/.agents/rules/docs-governance.md b/.agents/rules/docs-governance.md new file mode 100644 index 0000000..503bf72 --- /dev/null +++ b/.agents/rules/docs-governance.md @@ -0,0 +1,60 @@ +--- +description: Always follow the docs governance in docs/README.md when touching files under docs/. Specifically: cite Rules by number, update File Ownership and Single Source of Truth tables when adding/removing docs, fold new content into existing files unless it passes the Existence Test. +alwaysApply: true +--- + +# Docs Governance + +`docs/README.md` is the source of truth for how the docs folder is organized and edited. Read it first whenever you touch anything under `docs/`. + +## Quick checklist + +When you change a doc, these checks must pass before the PR ships: + +- **Rule 1 — One source of truth.** No prose duplicated across files. Cross-reference by relative path instead. +- **Rule 2 — Shipped items leave the roadmap.** When a backlog item lands, move its description to its canonical home (architecture / why-codemap / README) and remove it from `roadmap.md`. +- **Rule 3 — Plans get their own file.** Don't embed plans in `roadmap.md`. Create `docs/plans/.md` and link from the roadmap entry. +- **Rule 4 — Tables stay current.** When you add or delete a doc, update the **File Ownership** and **Single Source of Truth** tables in `docs/README.md` in the same PR. +- **Rule 5 — Relative cross-references.** `[architecture.md § Section](./architecture.md#section)` — never absolute paths or repo URLs for in-tree docs. +- **Rule 6 — No inventory counts in narrative.** Don't hardcode counts of files / symbols / recipes. Use qualitative descriptors or a `codemap query` example. Decision values (cache TTLs, `SCHEMA_VERSION`) are fine. +- **Rule 7 — No line-number references.** Cite by function name, section heading, or `codemap query` lookup. Methodology tables in `benchmark.md` are exempt. +- **Rule 8 — Close research notes.** When a `research/` scan's adopt items ship, slim it to a "What shipped" appendix linking to canonical homes. Rejected items keep a `Status: Rejected (date) — ` header. +- **Rule 9 — New term ⇒ glossary.** Every PR that introduces a new domain noun (table name, recipe id, parser name, schema column) updates `docs/glossary.md` in the same PR. Disambiguations (e.g. `FileRow` TS shape vs `files` SQLite table) take priority. + +## Document Lifecycle (full text in `docs/README.md`) + +Four doc types: **Reference** (lives forever), **Roadmap** (single file, items move in/out), **Plan** (created on commit, deleted on ship), **Research** (created for evaluations, closed per § Closing research). + +Backlogs / frameworks / decisions don't get their own file — they fold into one of the four. + +### Existence test (apply on every doc-touching PR) + +A file earns its place if it meets at least one of: + +1. Source code or another doc cites it (grep finds the path). +2. It documents durable policy or framework unavailable elsewhere. +3. It tracks open work. +4. It carries unique historical context that `git log` + `architecture.md` cannot reconstruct. + +If none → fold any salvageable content into roadmap / architecture / glossary, fix cross-refs, **delete the file**. + +### Top-level cap + +Adding a new top-level doc requires: + +1. The topic doesn't fit any existing root-level doc. +2. The new file passes the existence test on day one. +3. **File Ownership** table in `docs/README.md` updated in the same PR. + +When in doubt, default to absorbing into the closest existing root-level file. + +## Why this exists + +- Avoids the slow rot that hits any docs folder where any contributor (human or agent) can drop a new top-level file at any time. +- Gives reviewers cite-able rule numbers ("violates Rule 4") instead of vague "this should go elsewhere" feedback. +- Keeps `git log` legible by making doc files have predictable lifecycles. + +## Reference + +- [`docs/README.md`](../../docs/README.md) — full text of all rules, the lifecycle, and the existence test. +- Adapted from PaySpace `analytics/docs/README.md` governance pattern. diff --git a/.cursor/rules/docs-governance.mdc b/.cursor/rules/docs-governance.mdc new file mode 120000 index 0000000..e70b39f --- /dev/null +++ b/.cursor/rules/docs-governance.mdc @@ -0,0 +1 @@ +../../.agents/rules/docs-governance.md \ No newline at end of file diff --git a/docs/README.md b/docs/README.md index b1e3cab..13a7e81 100644 --- a/docs/README.md +++ b/docs/README.md @@ -4,22 +4,48 @@ Technical docs for **[@stainless-code/codemap](https://github.com/stainless-code **Start here:** [../README.md](../README.md) (install, CLI, API, dev commands). **This folder** is deeper reference — pick a row below. -| File | Topic | -| --------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [why-codemap.md](./why-codemap.md) | Why index + SQL for agents (speed, tokens, accuracy) — good first read after the readme | -| [architecture.md](./architecture.md) | Schema, layering, CLI internals, API, [**User config**](./architecture.md#user-config) (Zod), parsers, [Key Files](./architecture.md#key-files) | -| [agents.md](./agents.md) | **`codemap agents init`** — bundled **`templates/agents`** → **`.agents/`** in **consumer projects** (this repo’s **`.agents/`** is dev/maintainer — see [agents.md](./agents.md)); per-file IDE symlink/copy, **[pointer files](./agents.md#pointer-files)** (`codemap-pointer`), **`--interactive`**, **`.gitignore` / `.codemap.*`** | -| [benchmark.md](./benchmark.md) | [**Indexing another project**](./benchmark.md#indexing-another-project) · [**Benchmark script**](./benchmark.md#the-benchmark-script) · [**Query stdout (table vs JSON)**](./benchmark.md#query-stdout-table-vs-json-benchmarkquery) · [**Custom scenarios**](./benchmark.md#custom-scenarios-codemap_benchmark_config) (`CODEMAP_BENCHMARK_CONFIG`) · [`fixtures/minimal/`](../fixtures/minimal/) | -| [golden-queries.md](./golden-queries.md) | Golden `query` **design & policy** (Tier A/B, no proprietary trees); runner: [scripts/query-golden.ts](../scripts/query-golden.ts) | -| [fixtures/golden/](../fixtures/golden/) | [scenarios.json](../fixtures/golden/scenarios.json) + [minimal/](../fixtures/golden/minimal/) — **`bun run test:golden`**; Tier B: [scenarios.external.example.json](../fixtures/golden/scenarios.external.example.json) + **`bun run test:golden:external`** ([benchmark § Fixtures](./benchmark.md#fixtures)) | -| [fixtures/benchmark/](../fixtures/benchmark/) | Tracked [scenarios.example.json](../fixtures/benchmark/scenarios.example.json) — copy to `*.local.json` (gitignored) for [`CODEMAP_BENCHMARK_CONFIG`](./benchmark.md#custom-scenarios-codemap_benchmark_config) | -| [fixtures/qa/](../fixtures/qa/) | [prompts.external.template.md](../fixtures/qa/prompts.external.template.md) — optional chat QA prompts for an external index (`*.local.md` gitignored) | -| [packaging.md](./packaging.md) | **`CHANGELOG.md` / `dist/` / `templates/`** on npm, **engines**, [**Node vs Bun**](./packaging.md#node-vs-bun), [**Releases**](./packaging.md#releases) (Changesets; **`bun run version`** + oxfmt **`CHANGELOG.md`**) | -| [roadmap.md](./roadmap.md) | Forward-looking [**Backlog**](./roadmap.md#backlog) and [**Non-goals**](./roadmap.md#non-goals-v1) (not a `src/` inventory) | -| [research/](./research/) | Dated, snapshot-style notes (e.g. competitive scans). Each note links shipped items back to canonical homes — see [research/competitive-scan-2026-04.md](./research/competitive-scan-2026-04.md) | +## File Ownership + +Each topic has exactly one canonical file. Other files cross-reference by relative path, never duplicate. + +| File | Topic | +| --------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [why-codemap.md](./why-codemap.md) | Why index + SQL for agents (speed, tokens, accuracy). Anti-pitch ([What Codemap is not](./why-codemap.md#what-codemap-is-not)) and [alternatives comparison](./why-codemap.md#codemap-vs-alternatives). Good first read after the readme. | +| [architecture.md](./architecture.md) | Schema, layering, CLI internals, API, [**User config**](./architecture.md#user-config) (Zod), parsers, [Key Files](./architecture.md#key-files). | +| [glossary.md](./glossary.md) | Canonical term definitions. Disambiguates pairs like `FileRow` vs `files` table, recipe vs query, schema vs DDL, hub vs barrel. | +| [agents.md](./agents.md) | **`codemap agents init`** — bundled **`templates/agents`** → **`.agents/`** in **consumer projects** (this repo's **`.agents/`** is dev/maintainer); per-file IDE symlink/copy, **[pointer files](./agents.md#pointer-files)** (`codemap-pointer`), **`--interactive`**, **`.gitignore` / `.codemap.*`**. | +| [benchmark.md](./benchmark.md) | [**Indexing another project**](./benchmark.md#indexing-another-project) · [**Benchmark script**](./benchmark.md#the-benchmark-script) · [**Query stdout (table vs JSON)**](./benchmark.md#query-stdout-table-vs-json-benchmarkquery) · [**Custom scenarios**](./benchmark.md#custom-scenarios-codemap_benchmark_config) (`CODEMAP_BENCHMARK_CONFIG`) · [`fixtures/minimal/`](../fixtures/minimal/). | +| [golden-queries.md](./golden-queries.md) | Golden `query` **design & policy** (Tier A/B, no proprietary trees); runner: [scripts/query-golden.ts](../scripts/query-golden.ts). | +| [fixtures/golden/](../fixtures/golden/) | [scenarios.json](../fixtures/golden/scenarios.json) + [minimal/](../fixtures/golden/minimal/) — **`bun run test:golden`**; Tier B: [scenarios.external.example.json](../fixtures/golden/scenarios.external.example.json) + **`bun run test:golden:external`** ([benchmark § Fixtures](./benchmark.md#fixtures)). | +| [fixtures/benchmark/](../fixtures/benchmark/) | Tracked [scenarios.example.json](../fixtures/benchmark/scenarios.example.json) — copy to `*.local.json` (gitignored) for [`CODEMAP_BENCHMARK_CONFIG`](./benchmark.md#custom-scenarios-codemap_benchmark_config). | +| [fixtures/qa/](../fixtures/qa/) | [prompts.external.template.md](../fixtures/qa/prompts.external.template.md) — optional chat QA prompts for an external index (`*.local.md` gitignored). | +| [packaging.md](./packaging.md) | **`CHANGELOG.md` / `dist/` / `templates/`** on npm, **engines**, [**Node vs Bun**](./packaging.md#node-vs-bun), [**Releases**](./packaging.md#releases) (Changesets; **`bun run version`** + oxfmt **`CHANGELOG.md`**). | +| [roadmap.md](./roadmap.md) | Forward-looking [**Backlog**](./roadmap.md#backlog) and [**Non-goals**](./roadmap.md#non-goals-v1) (not a `src/` inventory). | +| [plans/](./plans/) | One `.md` per in-flight plan. Created on demand — don't add the `-plan` suffix; the folder provides context. Empty until the first plan lands. | +| [research/](./research/) | Dated, snapshot-style notes (e.g. competitive scans). Each note links shipped items back to canonical homes — see [research/competitive-scan-2026-04.md](./research/competitive-scan-2026-04.md). | + +--- + +## Rules for Agents + +These rules are normative — cite them by number in PR review. Ordered by how often they fire, not severity. + +1. **One source of truth** — every topic lives in exactly one file. Other files cross-reference by relative path; never duplicate prose. See the [Single source of truth](#single-source-of-truth-do-not-duplicate) table for cross-cutting topics. +2. **When a backlog item ships** — move the description from [roadmap.md](./roadmap.md) to its canonical home ([architecture.md](./architecture.md), [why-codemap.md](./why-codemap.md), or root [README.md](../README.md)). Remove the item from `roadmap.md` entirely; the roadmap is forward-looking. +3. **When adding a feature plan** — create `plans/.md`. Don't embed plans in `roadmap.md`; link from there. +4. **Keep ownership tables current** — when creating or deleting a doc file, update the [File Ownership](#file-ownership) and [Single source of truth](#single-source-of-truth-do-not-duplicate) tables in the same PR. A stale table is worse than no table. +5. **Cross-references use relative paths** — `[architecture.md § Section](./architecture.md#section)` or `[plans/foo.md](./plans/foo.md)`. Prefer section-deep links over file-only links. +6. **No inventory counts in narrative** — don't hardcode counts of files, symbols, recipes, or other code-derived quantities. Use qualitative descriptors or a `codemap query --json` example. Decision values (cache TTLs, batch sizes, schema version) are fine — those are decisions, not inventory. +7. **No line-number references** — line numbers (e.g. `parser.ts:241`) rot on every edit. Reference by function name, section heading, or symbol from `codemap query` instead. Methodology tables in [benchmark.md](./benchmark.md) are exempt. +8. **Research notes get closed** — when a research scan's adopt items ship, slim the note to a "What shipped" appendix linking to canonical homes (see [research/competitive-scan-2026-04.md](./research/competitive-scan-2026-04.md) as the precedent). Rejected items keep a `Status: Rejected (date) — ` header. +9. **New term ⇒ update [glossary.md](./glossary.md) in the same PR** — when a PR introduces a new domain noun / verb / acronym (table name, recipe id, parser name, schema column), add or update its entry. Disambiguations (e.g. `FileRow` TS shape vs `files` SQLite table) take priority over single defs. + +--- ## Single source of truth (do not duplicate) +Cross-cutting topics that span multiple files. Each has exactly one canonical home; other files link, never copy. + | Topic | Canonical doc | Elsewhere | | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Runtime splits (SQLite, workers, globs, JSON config I/O) | [packaging § Node vs Bun](./packaging.md#node-vs-bun) — **the table lives here** | [architecture § Runtime](./architecture.md#runtime-and-database) links here; do not copy the table | @@ -31,11 +57,72 @@ Technical docs for **[@stainless-code/codemap](https://github.com/stainless-code | **`CODEMAP_BENCHMARK_CONFIG`** (per-repo benchmark JSON) | [benchmark § Custom scenarios](./benchmark.md#custom-scenarios-codemap_benchmark_config) | [fixtures/benchmark/scenarios.example.json](../fixtures/benchmark/scenarios.example.json) only | | `bun run qa:external` — index + disk checks + `benchmark.ts` on **`CODEMAP_*`** | [.github/CONTRIBUTING.md](../.github/CONTRIBUTING.md) | [scripts/qa-external-repo.ts](../scripts/qa-external-repo.ts) (invocation only) | | **Non-goals (v1)** — what Codemap deliberately doesn't do (full-text search, LSP, static analysis, visualization, daemon, deep intent classification) | [roadmap.md § Non-goals](./roadmap.md#non-goals-v1) | [why-codemap.md § What Codemap is not](./why-codemap.md#what-codemap-is-not) (consumer-facing framing) — links here; [research/](./research/) notes link here, never re-list | +| **Domain term definitions** (FileRow vs `files`, recipe vs query, schema vs DDL, hub vs barrel, fan-in vs fan-out, …) | [glossary.md](./glossary.md) | Other docs link to a glossary entry on first use; never inline a definition that conflicts | + +--- + +## Document Lifecycle + +Every doc here falls into one of four types. New content fits an existing type, or absorbs into an existing file — it does not spawn a new top-level doc by default. + +### Types + +| Type | Folder | Lifecycle | +| ------------- | --------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- | +| **Reference** | root (`architecture.md`, `agents.md`, `benchmark.md`, `golden-queries.md`, `packaging.md`, `glossary.md`, `why-codemap.md`) | Lives forever. Kept current per Rules 4, 7, 9. | +| **Roadmap** | root (`roadmap.md`, single file) | Lives forever. Items move in (new findings) and out (per Rule 2). | +| **Plan** | `plans/.md` | Created when work commits. Deleted when work ships (per Rule 3). | +| **Research** | `research/.md` | Created on demand for a third-party scan or evaluation. Closed per [Closing research](#closing-research). | + +Backlogs, frameworks, and decisions don't get their own top-level file. They fold into one of the four: + +- **Backlogs** of open items → a section in `roadmap.md`. +- **Frameworks / playbooks** → `architecture.md` if Codemap-internal, or `.agents/rules/` / `.agents/skills/` if project-wide policy. +- **Decisions of record** from concluded research → lift into the relevant reference doc; the research file's job is the evaluation, not the decision. + +### Existence test (apply on every doc-touching PR) + +A file earns its place if it meets at least one of: + +1. **Source code or another doc cites it** (grep finds the path). +2. **It documents durable policy or framework** unavailable elsewhere. +3. **It tracks open work** (open audit findings, in-flight plan, roadmap items). +4. **It carries unique historical context** that `git log` + `architecture.md` cannot reconstruct. + +If none → fold any salvageable content into roadmap / architecture / glossary, fix the cross-refs, delete the file. + +### Closing research + +A research note's job is the evaluation. When it concludes: + +- **Adopted** → lift the decisions-of-record into the relevant reference doc; slim the note to a "What shipped" appendix linking to canonical homes (precedent: [research/competitive-scan-2026-04.md](./research/competitive-scan-2026-04.md)). +- **Rejected** → add `Status: Rejected (YYYY-MM-DD) — ` at the top. Keep the file. Don't delete; the rejection rationale saves the next agent from re-litigating. +- **Open** → stays in `research/` with no status header (open is the default). + +### Top-level cap + +Adding a new top-level doc requires: + +1. The topic doesn't fit any existing root-level doc. +2. The new file passes the existence test on day one. +3. [File Ownership](#file-ownership) table updated in the same PR. + +When in doubt, default to absorbing into the closest existing root-level file (usually `roadmap.md` for forward-looking work, `architecture.md` for shipped behavior, `glossary.md` for terminology, `research/` for snapshot notes). + +--- + +## Naming Conventions + +- **`plans/` files**: `.md` — the folder provides "plan" context, don't add a `-plan` suffix. +- **`research/` files**: `-YYYY-MM.md` for dated snapshots (e.g. `competitive-scan-2026-04.md`); `.md` for ongoing tool evaluations. +- **Top-level files**: descriptive domain noun (`architecture.md`, `glossary.md`, `roadmap.md`) — no prefix or suffix. + +--- ## Conventions -- **One topic per file**; prefer relative links between these docs. -- **CLI flags and examples** — canonical [README.md § CLI](../README.md#cli). Other docs **summarize and link**; do not copy full flag lists (see **Single source of truth** above). **Implementation paths** (`src/cli/…`, **`QUERY_RECIPES`**) belong in [architecture.md § CLI usage](./architecture.md#cli-usage) only. -- **Avoid stale file/symbol counts** in narrative text — use `codemap query --json` / `bun run dev query --json` after indexing (or omit **`--json`** for a terminal table); methodology tables in [benchmark.md](./benchmark.md) are fine. -- **This repo:** `bun run dev` is **`bun src/index.ts`**; `bun run build` → tsdown → `dist/`; `bun run clean` / `bun run check-updates` — [.github/CONTRIBUTING.md](../.github/CONTRIBUTING.md). +Stylistic addendum to the rules above: + +- **CLI flags and examples** — canonical [README.md § CLI](../README.md#cli). Other docs **summarize and link**; do not copy full flag lists. **Implementation paths** (`src/cli/…`, **`QUERY_RECIPES`**) belong in [architecture.md § CLI usage](./architecture.md#cli-usage) only. +- **This repo:** `bun run dev` is **`bun src/index.ts`**; `bun run build` → tsdown → `dist/`; `bun run clean` / `bun run check-updates` — see [.github/CONTRIBUTING.md](../.github/CONTRIBUTING.md). - **Contributors:** branch + PR into **`main`** ([CI](../.github/workflows/ci.yml)), `bun run check`, JSDoc on public API. diff --git a/docs/glossary.md b/docs/glossary.md new file mode 100644 index 0000000..5d3fdbf --- /dev/null +++ b/docs/glossary.md @@ -0,0 +1,412 @@ +# Glossary + +Canonical definitions of Codemap terms. Disambiguates pairs that look similar (TS shape vs SQL table, recipe vs query, hub vs barrel) and pins the SQL-table names so cross-references are unambiguous. + +When introducing a new domain noun in a PR, add or update its entry here per [README § Rules for Agents (Rule 9)](./README.md#rules-for-agents). + +## Sorting + +Alphabetical, lowercase. Disambiguation pairs link to each other. + +## Conventions + +- **TS shape** = a TypeScript interface or type alias. +- **SQLite table** = an actual on-disk table in `.codemap.db`. +- **Recipe** = a bundled SQL string in `src/cli/query-recipes.ts`, exposed via `codemap query --recipe `. +- **Query** = any SQL run against the index (recipe or ad-hoc). + +--- + +## A + +### `.agents/` + +Repo-level directory holding **rules** (`.agents/rules/.md`) and **skills** (`.agents/skills//SKILL.md`). Source of truth; IDE-agnostic. Mirrored to `.cursor/rules/` via per-file symlinks per [agents-first-convention](../.agents/rules/agents-first-convention.md). + +### adapter + +See **language adapter**. + +### agent rule + +A `.agents/rules/.md` file with YAML frontmatter. Distinct from a **skill** (longer, scenario-specific). Distinct from a **bundled recipe** (which is SQL, not Markdown). + +--- + +## B + +### barrel file + +In Codemap usage: a file with a high number of `exports` rows — typically a public-API hub like `src/index.ts`. Surfaced by the `barrel-files` recipe. Distinct from **hub** below — barrel measures _exports out_, hub measures _imports in_. + +### batch insert + +The shared `batchInsert()` helper in `src/db.ts`. Splits inserts into multi-row `INSERT … VALUES (…),(…)` statements of `BATCH_SIZE` (500) rows each, with pre-computed placeholder strings. Used by every `insertX` function. + +### `bun:sqlite` + +Bun's native SQLite binding. Codemap uses it on Bun; falls back to `better-sqlite3` on Node. Both are wrapped by `src/sqlite-db.ts` so call sites are runtime-agnostic. + +### `better-sqlite3` + +Synchronous Node.js SQLite binding. The Node-side counterpart to `bun:sqlite`. Allows **one statement per `prepare()`**, unlike `bun:sqlite` which accepts multiple — see [packaging § Node vs Bun](./packaging.md#node-vs-bun). + +--- + +## C + +### `calls` (table) + +Function-scoped call edges, deduped per `(caller_scope, callee_name)` per file. **`caller_scope`** is dot-joined enclosing scope (e.g. `UserService.run`). Module-level calls are excluded. See `CallRow` for the TS shape. + +### `CallRow` + +TS shape for one row of the `calls` table. Maps 1:1 to the SQLite columns. + +### category + +The extraction path a file took during parsing. One of `ts`, `css`, or `text`. Stored on `ParsedFile.category`, not on a SQLite table. See `ParsedFile`. + +### `.codemap.db` + +The on-disk SQLite database file at `/.codemap.db`. Always accompanied by `.codemap.db-wal` and `.codemap.db-shm` while open (WAL mode). Gitignored via the `.codemap.*` pattern that `codemap agents init` ensures. + +### `codemap context` + +CLI subcommand emitting a JSON envelope (`ContextEnvelope`) with project metadata, top hubs, sample markers, recipe catalog, and optional intent classification via `--for ""`. + +### `codemap validate` + +CLI subcommand comparing on-disk SHA-256 against `files.content_hash`. Statuses: `stale | missing | unindexed`. Exits `1` on any drift. + +### `components` (table) + +React components (PascalCase + JSX return or hook usage). PascalCase functions that neither return JSX nor call hooks stay in `symbols` only — never `components`. `hooks_used` is JSON-encoded. See `ComponentRow`. + +### `content_hash` + +Column on the `files` table. Lowercase SHA-256 hex of file bytes computed by `src/hash.ts`. Drives incremental staleness detection (`getChangedFiles`) and powers the `files-hashes` recipe + `codemap validate` CLI. + +### `ContextEnvelope` + +TS shape for the JSON emitted by `codemap context`. Stable contract; agents can key off field names. + +### covering index + +A SQLite index that includes every column needed by a query, so SQLite reads everything from the index B-tree without touching the main table. The query plan shows `USING COVERING INDEX`. Used heavily for AI agent query patterns — see [architecture § Covering indexes](./architecture.md#covering-indexes). + +### `css_classes` (table) + +CSS class names from selectors (no leading `.`). `is_module = 1` for `.module.css` files. See `CssClassRow`. + +### `css_keyframes` (table) + +`@keyframes ` declarations. See `CssKeyframeRow`. + +### `css_variables` (table) + +CSS custom properties (`--token: value`). `scope` is `:root`, `@theme` (Tailwind v4), or the selector text. See `CssVariableRow`. + +--- + +## D + +### DDL + +Data Definition Language — the `CREATE TABLE` / `CREATE INDEX` strings in `src/db.ts`. Distinct from **schema** (the conceptual structure) and from **`SCHEMA_VERSION`** (the integer that triggers auto-rebuild on mismatch). + +### `dependencies` (table) + +Resolved file-to-file edges derived from `imports.resolved_path`. Composite primary key `(from_path, to_path)`. Self-edges and unresolved imports are excluded. `STRICT, WITHOUT ROWID`. See `DependencyRow`. + +### `DependencyRow` + +TS shape for one row of the `dependencies` table. + +--- + +## E + +### existence test + +The 4-criterion gate for whether a doc earns its place — see [README § Existence test](./README.md#existence-test-apply-on-every-doc-touching-pr). Forces deletion of stale docs. + +### `exports` (table) + +Named, default, and re-exports. `kind` is `value` / `type` / `re-export`; `re_export_source` is non-null only for `re-export` rows. See `ExportRow`. + +### `ExportRow` + +TS shape for one row of the `exports` table. + +--- + +## F + +### fan-in + +Number of edges _into_ a file in the `dependencies` table — `COUNT(*) FROM dependencies WHERE to_path = ?`. Surfaces as the `fan-in` recipe (top files by inbound edges, i.e. **hubs**). + +### fan-out + +Number of edges _out of_ a file — `COUNT(*) FROM dependencies WHERE from_path = ?`. Surfaces as the `fan-out` recipe. + +### `files` (table) + +Header row for every indexed file. `path` is the primary key; all other tables FK to it with `ON DELETE CASCADE`. See `FileRow`. + +### `FileRow` + +TS shape for one row of the `files` table. Distinct from the `files` SQLite table itself (the table name is lowercase plural; the TS interface is PascalCase singular). + +### fixture + +Hand-crafted source tree under `fixtures/minimal/` used as the corpus for golden tests. Excluded from oxlint via `ignorePatterns: ["fixtures"]` so auto-fixes never mutate test corpora. + +### full rebuild + +Index mode that drops every table and rebuilds from scratch — `codemap --full` or `cm.index({ mode: "full" })`. Triggers automatically when `SCHEMA_VERSION` mismatches or when no previous index exists. Optimized via worker threads, deferred index creation, and relaxed PRAGMAs. + +--- + +## G + +### `getMeta` / `setMeta` + +Read/write helpers for the `meta` key-value table. Stores `schema_version`, `last_indexed_commit`, `indexed_at`, etc. + +### glob + +Include patterns (relative to project root) used to find indexable files. Defaults in `DEFAULT_INCLUDE_PATTERNS`. Implemented via `tinyglobby` on Node and `Bun.Glob` on Bun (both emit POSIX paths). + +### golden test + +A `bun scripts/query-golden.ts` regression that compares a query/recipe's output against a checked-in JSON snapshot. Tier A uses `fixtures/minimal/`; Tier B uses external trees via `CODEMAP_*`. See [golden-queries.md](./golden-queries.md). + +--- + +## H + +### hash + +SHA-256 hex computed over file bytes via `src/hash.ts`. Same algorithm on Bun and Node — `Bun.hash` is **not** used because it differs across runtimes. + +### hub + +A file with high **fan-in** — many other files import it. Surfaced by the `fan-in` recipe (which we historically also called `hubs`). Distinct from **barrel file** (high _fan-out_ via exports). + +--- + +## I + +### incremental index + +Index mode that diffs against `last_indexed_commit` (git) and only re-indexes changed files. Default mode (no flag); falls back to full rebuild if commit history is incompatible. + +### `imports` (table) + +Raw `import` statements. `specifiers` is JSON-encoded; `resolved_path` is non-null only when the resolver could map `source` to an indexed file. See `ImportRow` and the resolved view `dependencies`. + +### `ImportRow` + +TS shape for one row of the `imports` table. + +### `IndexPerformanceReport` + +TS shape emitted under `IndexRunStats.performance` when `--performance` is set. Per-phase timing + top-10 slowest files. Note: `total_ms` is `indexFiles` wall-clock and excludes `collect_ms`. + +### `IndexResult` + +Public TS shape returned from `Codemap#index()` and `runCodemapIndex()`. Wall-clock + row counts + optional performance report. + +--- + +## L + +### language adapter + +A `LanguageAdapter` registered in `src/adapters/builtin.ts` that maps file extensions to a parser (`parse(ctx) → ParsedFilePayload`). Currently three built-ins: `builtin.ts-js` (oxc), `builtin.css` (lightningcss), `builtin.text` (markers-only). Future community adapters can register additional ones. + +### `last_indexed_commit` + +`meta` key holding the HEAD SHA at the end of the previous successful index run. Used by `getChangedFiles` to compute the changed set. + +### lightningcss + +Rust-based CSS parser (NAPI bindings). Codemap's `src/css-parser.ts` uses its visitor pattern to extract custom properties, classes, keyframes, and `@import` sources. Not a preprocessor — Sass / Less / SCSS are out of scope. + +--- + +## M + +### markers + +`TODO` / `FIXME` / `HACK` / `NOTE` comments extracted from any indexed file (TS, CSS, Markdown, JSON, YAML, …). Stored in the `markers` table; surfaced by the `markers-by-kind` recipe. See `MarkerRow`. + +### `MarkerRow` + +TS shape for one row of the `markers` table. + +### `meta` (table) + +Key-value metadata table. Holds `schema_version`, `last_indexed_commit`, `indexed_at`, `file_count`, `project_root`. `STRICT, WITHOUT ROWID`. + +--- + +## O + +### oxc-parser + +Rust-based TypeScript / JavaScript parser (NAPI bindings). Codemap's `src/parser.ts` uses it to extract symbols, imports, exports, components, type members, calls, and markers from `.ts` / `.tsx` / `.js` / `.jsx` (and `.mts` / `.cts` / `.mjs` / `.cjs`). + +### oxc-resolver + +Rust-based import-path resolver (NAPI bindings). Configured with `tsconfig.json` for alias resolution (`~/utils/foo`). Produces the `dependencies` table from `imports.resolved_path`. + +### oxlint + +Rust-based linter. Configured in `.oxlintrc.json`. Auto-fixes most violations via `bun run lint:fix`. + +### oxfmt + +Rust-based formatter. Run via `bun run format` / `format:check`. + +--- + +## P + +### `ParsedFile` + +TS shape returned by parse workers and built up by language adapters. Header (`relPath`, `fileRow`, `category`, `parseMs?`) plus optional row arrays per category (TS / CSS / text). Subset that adapters populate is `ParsedFilePayload`. + +### parser + +Code that turns source bytes into structured rows. Three implementations: `parser.ts` (oxc), `css-parser.ts` (lightningcss), `markers.ts` (regex). Distinct from **adapter** — an adapter wires a parser to a set of file extensions. + +### plan + +A `docs/plans/.md` file tracking in-flight work. Created on commit; deleted when the feature ships per [README § Rule 3](./README.md#rules-for-agents). + +### pointer file + +A managed root-level file (`CLAUDE.md`, `AGENTS.md`, `GEMINI.md`, `.github/copilot-instructions.md`) with a `` / `` section. Written by `codemap agents init`. See [agents.md § Pointer files](./agents.md#pointer-files). + +--- + +## Q + +### query + +Any SQL run against `.codemap.db` — either a **recipe** (bundled SQL) or ad-hoc. Distinct from **query-recipes.ts** (the file that holds bundled recipe SQL strings). + +### query recipe + +See **recipe**. + +--- + +## R + +### recipe + +A bundled SQL string in `src/cli/query-recipes.ts`, identified by id (e.g. `fan-in`, `deprecated-symbols`, `files-hashes`). Run via `codemap query --recipe ` (alias `-r`). Distinct from an ad-hoc **query** (which is any SQL string the agent composes itself). + +### research + +A snapshot-style note under `docs/research/` capturing a competitive scan or evaluation. Closed per [README § Closing research](./README.md#closing-research) — adopted items are slimmed to a "What shipped" appendix; rejected items keep a status header. + +### resolver + +`oxc-resolver`, configured by `src/resolver.ts`. Maps import specifiers to absolute file paths using `tsconfig` aliases. + +### `ResolvedCodemapConfig` + +TS shape after `resolveCodemapConfig()` fills defaults and absolutifies paths. Stored in process-global runtime by `initCodemap`. Distinct from **`CodemapUserConfig`** (the user-facing input shape with optional fields). + +### roadmap + +`docs/roadmap.md`. Forward-looking only; shipped items are removed (see [README § Rule 2](./README.md#rules-for-agents)). Holds the canonical [Non-goals (v1)](./roadmap.md#non-goals-v1) list. + +### row + +One record in a SQLite table. Each table has a corresponding TS interface (`FileRow`, `SymbolRow`, …) so reads via `db.query(sql).all()` are typed. + +--- + +## S + +### schema + +Conceptually, the structure of the SQLite database — every table, column, constraint, and index. Defined by **DDL** in `src/db.ts`. Versioned by **`SCHEMA_VERSION`**. Documented in [architecture § Schema](./architecture.md#schema). + +### `SCHEMA_VERSION` + +Integer constant in `src/db.ts`. Bumped whenever the DDL changes. `createSchema()` reads `meta.schema_version` and triggers a full rebuild on mismatch. + +### skill + +A `.agents/skills//SKILL.md` file with YAML frontmatter. Longer than a rule; describes a complete agent workflow. Distinct from a **rule** (shorter, normative). + +### `STRICT` + +SQLite per-table option enforcing column types at insert time. Every Codemap table uses `STRICT`. + +### `symbols` (table) + +Functions / consts / classes / interfaces / types / enums, plus class members (`method`, `property`, `getter`, `setter`). Class members carry `parent_name`. JSDoc tags in `doc_comment` power the `deprecated-symbols` and `visibility-tags` recipes; `members` is JSON for enums. See `SymbolRow`. + +### `SymbolRow` + +TS shape for one row of the `symbols` table. + +--- + +## T + +### targeted reindex + +Index mode that re-parses only the explicit file paths passed to `--files`. Skips git diff and the full glob. See `targetedReindex` in `src/application/index-engine.ts`. + +### `templates/agents` + +The `templates/agents/` directory shipped with the npm package. Source for `codemap agents init`, which copies (or symlinks, in interactive mode) the bundled rules and skills into the consumer's `.agents/`. + +### tinyglobby + +The Node-side glob implementation. Returns POSIX-separated paths regardless of OS — same as `Bun.Glob` and `git`. Why `cmd-validate.ts` normalizes its inputs to POSIX. + +### tracer bullet + +A small end-to-end vertical slice (see [`.cursor/rules/tracer-bullets.mdc`](../.cursor/rules/tracer-bullets.mdc)). Used in PRs to validate the critical path before expanding. + +### `type_members` (table) + +Properties and method signatures on interfaces and object-literal types. `symbol_name` references the parent `symbols.name`. `type` is null when the parser can't reconstruct the annotation. See `TypeMemberRow`. + +### `TypeMemberRow` + +TS shape for one row of the `type_members` table. + +--- + +## V + +### visibility tag + +A JSDoc tag controlling export visibility — `@public`, `@internal`, `@private`, `@alpha`, `@beta`, `@deprecated`. Stored in `symbols.doc_comment`. The `visibility-tags` and `deprecated-symbols` recipes filter on these. + +--- + +## W + +### WAL + +Write-Ahead Log mode. Set by `PRAGMA journal_mode = WAL` on every `openDb()`. Why `.codemap.db-wal` and `.codemap.db-shm` files exist alongside `.codemap.db`. Allows concurrent readers during writes. + +### `WITHOUT ROWID` + +SQLite per-table option that stores data directly in the primary key B-tree, eliminating a rowid lookup indirection. Used on `dependencies` (composite PK) and `meta` (single-column TEXT PK). + +### worker pool + +Parallel parse workers in `src/worker-pool.ts`. Bun `Worker` on Bun, Node `worker_threads` on Node. Used during full rebuild only — incremental and targeted indexing run sequentially. diff --git a/docs/plans/.gitkeep b/docs/plans/.gitkeep new file mode 100644 index 0000000..e69de29 From 22939c2f89b8185f4341ed18ab06c4d7d08d2eaf Mon Sep 17 00:00:00 2001 From: Sutu Sebastian Date: Mon, 27 Apr 2026 15:15:42 +0300 Subject: [PATCH 12/12] docs: dogfood the new docs/README.md governance MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Audited every doc against the 9 numbered rules in the new docs/README.md. Three violations found and fixed; the rest pass. Rule 2 — When a backlog item ships, document it in its canonical home - architecture.md § CLI usage gains four new implementation-note paragraphs: * Validate wiring (cmd-validate.ts, computeValidateRows pure function, POSIX path normalization, exit-1 git-status semantics). * Context wiring (buildContextEnvelope composing existing recipes, classifyIntent regex routing, --compact behavior). * Performance wiring (RunIndexOptions.performance, parseMs on ParsedFile, IndexPerformanceReport assembly, total_ms gotcha). * Friendlier no-DB error rewriting in enrichQueryError + the new -r alias on --recipe (folded into existing Query wiring paragraph). Rule 4 — Keep ownership tables current - Key Files `cli/` row updated to mention `validate` / `context` modes alongside `query` / `agents init` / index modes. Rule 6 — No inventory counts in narrative - golden-queries.md said "15 scenarios" — now 19 after this PR's additions. Replaced with a qualitative descriptor + a `codemap query` example so the doc never goes stale on count again. Rules 1, 3, 5, 7, 8, 9 all pass — no duplicated prose, no unintended plans, no absolute paths to in-tree files, no line-number references (except Rule 7's own example), competitive scan already closed, every new term from this PR is in glossary.md. --- docs/architecture.md | 10 ++++++++-- docs/golden-queries.md | 14 +++++++------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/docs/architecture.md b/docs/architecture.md index 72918b1..ce73d40 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -95,7 +95,7 @@ A local SQLite database (`.codemap.db`) indexes the project tree and stores stru | File | Purpose | | ------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `index.ts` | Package entry — re-exports `api` / `config`, runs CLI when main | -| `cli/` | CLI — bootstrap argv, lazy command modules, `query` / `agents init` / index modes | +| `cli/` | CLI — bootstrap argv, lazy command modules, `query` / `validate` / `context` / `agents init` / index modes | | `api.ts` | Programmatic API — `createCodemap`, `Codemap`, `runCodemapIndex` | | `application/` | Indexing use cases and engine (`run-index`, `index-engine`, types) | | `worker-pool.ts` | Parallel parse workers (Bun / Node) | @@ -117,7 +117,13 @@ A local SQLite database (`.codemap.db`) indexes the project tree and stores stru **Commands and flags** (index, query, **`codemap agents init`**, **`--root`**, **`--config`**, environment): [../README.md § CLI](../README.md#cli) — **do not duplicate** flag lists here; this section only adds implementation notes. From this repository: **`bun run dev`** or **`bun src/index.ts`** (same flags). -**Query wiring:** **`src/cli/cmd-query.ts`** (argv, **`printQueryResult`**), **`src/cli/query-recipes.ts`** (**`QUERY_RECIPES`** — bundled SQL only source), **`src/cli/main.ts`** (**`--recipes-json`** / **`--print-sql`** exit before config/DB). With **`--json`**, errors use **`{"error":"…"}`** on stdout for SQL failures, DB open, and bootstrap (same shape); **`runQueryCmd`** sets **`process.exitCode`** instead of **`process.exit`**. The **`components-by-hooks`** recipe ranks by hook count with a **comma-based tally** on **`hooks_used`** (no SQLite JSON1). Shipped **`templates/agents/`** documents **`codemap query --json`** as the primary agent example ([README § CLI](../README.md#cli)). +**Query wiring:** **`src/cli/cmd-query.ts`** (argv, **`printQueryResult`**, `--recipe` / `-r` alias), **`src/cli/query-recipes.ts`** (**`QUERY_RECIPES`** — bundled SQL only source), **`src/cli/main.ts`** (**`--recipes-json`** / **`--print-sql`** exit before config/DB). With **`--json`**, errors use **`{"error":"…"}`** on stdout for SQL failures, DB open, and bootstrap (same shape); **`runQueryCmd`** sets **`process.exitCode`** instead of **`process.exit`**. Friendlier "no `.codemap.db`" — `no such table: ` and `no such column: ` errors are rewritten in **`enrichQueryError`** to point at `codemap` / `codemap --full`. The **`components-by-hooks`** recipe ranks by hook count with a **comma-based tally** on **`hooks_used`** (no SQLite JSON1). Shipped **`templates/agents/`** documents **`codemap query --json`** as the primary agent example ([README § CLI](../README.md#cli)). + +**Validate wiring:** **`src/cli/cmd-validate.ts`** — **`computeValidateRows`** is a pure function over `(db, projectRoot, paths)` returning `{path, status}` rows where `status ∈ stale | missing | unindexed`. CLI wraps it with read-once-and-print + exits **1** on any drift (git-status semantics). Path normalization: **`toProjectRelative`** converts CLI input to POSIX-style relative keys matching the `files.path` storage format (Windows backslash → forward slash); same convention as `lint-staged.config.js`. + +**Context wiring:** **`src/cli/cmd-context.ts`** — **`buildContextEnvelope`** composes the JSON envelope from existing recipes (`fan-in` for `hubs`, `markers` SELECT for `sample_markers`, `QUERY_RECIPES` map for the catalog). **`classifyIntent`** maps `--for ""` to one of `refactor | debug | test | feature | explore | other` via regex against the trimmed input; whitespace-only intents are rejected. `--compact` drops `hubs` + `sample_markers` and emits one-line JSON; otherwise pretty-prints with 2-space indent. + +**Performance wiring:** **`--performance`** plumbs through **`RunIndexOptions.performance`** → **`indexFiles({ performance, collectMs })`**. `parse-worker-core.ts` records per-file **`parseMs`** on each `ParsedFile`; main thread times the four phases (`collect`, `parse`, `insert`, `index_create`) and assembles **`IndexPerformanceReport`** under `IndexRunStats.performance`. Note: `total_ms` is `indexFiles` wall-clock, **not** end-to-end run wall — `collect_ms` happens before `indexFiles` and is reported separately. **Agent templates:** `codemap agents init` — full matrix [agents.md](./agents.md). diff --git a/docs/golden-queries.md b/docs/golden-queries.md index 220b6c9..630cb54 100644 --- a/docs/golden-queries.md +++ b/docs/golden-queries.md @@ -69,13 +69,13 @@ Scenarios live in **`fixtures/golden/scenarios.json`** (Tier A) or optional **`s ## Status -| Area | State | -| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| Tier A runner + CI | **`bun run test:golden`** in `check` | -| Tier A scenario coverage | 15 scenarios across all indexed tables: files, symbols, imports, exports, components, dependencies, markers, type_members, calls, CSS vars/classes/keyframes | -| Tier B external + schema | **`test:golden:external`**, Zod in **`scripts/query-golden/schema.ts`** | -| Subset matchers + budgets | **`match`**, **`budgetMs`**, **`--strict-budget`** | -| Optional CI for public corpus | Deferred — [roadmap § Backlog](./roadmap.md#backlog) | +| Area | State | +| ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Tier A runner + CI | **`bun run test:golden`** in `check` | +| Tier A scenario coverage | Scenarios across every indexed table — files, symbols, imports, exports, components, dependencies, markers, type_members, calls, CSS vars/classes/keyframes — plus bundled-recipe smoke tests. Current count: `bun src/index.ts query --json "SELECT COUNT(*) AS n FROM markers"` against the fixture, or count rows in [scenarios.json](../fixtures/golden/scenarios.json) | +| Tier B external + schema | **`test:golden:external`**, Zod in **`scripts/query-golden/schema.ts`** | +| Subset matchers + budgets | **`match`**, **`budgetMs`**, **`--strict-budget`** | +| Optional CI for public corpus | Deferred — [roadmap § Backlog](./roadmap.md#backlog) | ---