{"_id":"@avelor/stale","name":"@avelor/stale","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@avelor/stale","version":"0.1.0","description":"Find stale TODO/FIXME markers by age. Breaks CI when technical debt sits too long.","keywords":["todo","fixme","technical-debt","ci","git-blame","developer-tools"],"license":"MIT","author":{"name":"Avelor","email":"cruz@avelor.es"},"repository":{"type":"git","url":"git+https://github.com/avelor-es/stale.git"},"publishConfig":{"access":"public"},"type":"module","bin":{"stale":"bin/stale.js"},"dependencies":{"js-yaml":"^4.1.0"},"scripts":{"test":"node --test test/*.test.js"},"engines":{"node":">=18"},"gitHead":"c986165eddafc6cfeadd0010fdaddfab7d064288","_id":"@avelor/stale@0.1.0","bugs":{"url":"https://github.com/avelor-es/stale/issues"},"homepage":"https://github.com/avelor-es/stale#readme","_nodeVersion":"24.13.0","_npmVersion":"11.6.2","dist":{"integrity":"sha512-nuqEUbyH8LXCoNiyNva+Sil0f5dboZl4c0L6gf6892FqLkPb7lbUwgrOzXoow4ajfMTHkZ1adoDuAajqLjGa0g==","shasum":"0793edb7e1df1800df8d31881d42f6032f63f55c","tarball":"https://registry.npmjs.org/@avelor/stale/-/stale-0.1.0.tgz","fileCount":11,"unpackedSize":16169,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIAbzvj9J36f9/Cw9XWDq90wmRkYzeBT2snVLwxlcoqq4AiAVrNBWt+CiD8m2k5DQ6refHvkfYeQnMXsB/Gzyf4q8MQ=="}]},"_npmUser":{"name":"christianecg","email":"contacto@christianecg.com"},"directories":{},"maintainers":[{"name":"christianecg","email":"contacto@christianecg.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/stale_0.1.0_1781057336042_0.2401379112713864"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-10T02:08:55.797Z","0.1.0":"2026-06-10T02:08:56.194Z","modified":"2026-06-10T02:08:56.440Z"},"maintainers":[{"name":"christianecg","email":"contacto@christianecg.com"}],"description":"Find stale TODO/FIXME markers by age. Breaks CI when technical debt sits too long.","homepage":"https://github.com/avelor-es/stale#readme","keywords":["todo","fixme","technical-debt","ci","git-blame","developer-tools"],"repository":{"type":"git","url":"git+https://github.com/avelor-es/stale.git"},"author":{"name":"Avelor","email":"cruz@avelor.es"},"bugs":{"url":"https://github.com/avelor-es/stale/issues"},"license":"MIT","readme":"# stale\n\nFind stale TODO/FIXME markers by age. Breaks CI when technical debt sits too long.\n\n![demo](demo.gif)\n\n```\n 847d  src/auth/middleware.js:43    HACK      # bypass validation for now\n 312d  src/api/payments.js:112     TODO      handle refunds\n  14d  tests/payments.test.js:8    test.todo  handles partial refund\n\n  ✖ 2 markers exceeded the age limit.\n```\n\nThe age comes from `git blame`. Not when the file was last touched — when that specific line was committed.\n\n---\n\n## Install\n\n```bash\nnpm install -g @avelor/stale\n```\n\nRequires Node.js 18+ and git.\n\n---\n\n## Usage\n\n```bash\nstale              # scan using .stale.yml in current directory\nstale tests/       # only scan tests/\nstale --max-age 7  # override max-age for this run\n```\n\nExit code is `0` if nothing is over the limit, `1` if anything is. Any CI pipeline understands this without extra configuration.\n\n---\n\n## .stale.yml\n\n```yaml\nmax-age: 30\nignore:\n  - dist/\n  - \"**/*.generated.*\"\n\nrules:\n  - paths: [src/, lib/]\n    tags: [TODO, FIXME, HACK]\n\n  - paths: [tests/, __tests__/]\n    tags: [test.todo, it.todo, test.skip, describe.skip, xit, xdescribe]\n    max-age: 14\n    ignore:\n      - tests/fixtures/\n```\n\nEach rule is independent. `max-age` and `ignore` at the top level are the defaults — rules inherit them and can override.\n\n| Field | Description |\n|---|---|\n| `max-age` | Days before a marker is considered stale |\n| `ignore` | Glob patterns to skip. Rule-level `ignore` adds to the global list. |\n| `paths` | Directories or files this rule applies to |\n| `tags` | Strings to search for (substring match per line) |\n\n---\n\n## CI / GitHub Actions\n\nUse `--format github` to emit native GitHub annotations — they appear as inline errors on the PR diff.\n\n```yaml\n- name: Check stale markers\n  run: npx @avelor/stale --format github\n```\n\nOutput:\n\n```\n::error file=src/api/payments.js,line=112::TODO is 312d old (limit: 30d) — handle refunds\n::warning file=tests/payments.test.js,line=8::test.todo is 14d old (limit: 14d) — handles partial refund\n```\n\nWarnings for markers approaching the limit. Errors for markers over it.\n\n---\n\n## Options\n\n```\n--max-age <days>    Override global max-age\n--format <type>     human (default), json, github\n--config <path>     Path to config file (default: .stale.yml)\n-h, --help\n```\n\n---\n\n## JSON output\n\nUseful for filtering or feeding into other tools.\n\n```bash\nstale --format json | jq '.[] | select(.violation)'\n```\n\nEach entry:\n\n```json\n{\n  \"file\": \"src/api/payments.js\",\n  \"line\": 112,\n  \"tag\": \"TODO\",\n  \"content\": \"// TODO: handle refunds\",\n  \"ageDays\": 312,\n  \"maxAge\": 30,\n  \"author\": \"Jane Doe\",\n  \"violation\": true\n}\n```\n\n---\n\n## How it works\n\n`stale` reads your `.stale.yml`, walks the configured paths, and searches each file for the configured tags. For every match, it runs `git blame` on that line to get the commit date. Age is calculated from that date to today.\n\nFiles not tracked by git report `0` days and never trigger a violation.\n\n---\n\n## License\n\nMIT\n","readmeFilename":"README.md","_rev":"1-b555bade07e6940708a3feb2c3f64ec2"}