@joshuafolkken/kit 1.872.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/.claude-plugin/plugin.json +11 -0
- package/.claude/settings.json +110 -0
- package/.claude/skills/dependency-update/SKILL.md +76 -0
- package/.claude/skills/epic-commands/SKILL.md +463 -0
- package/.claude/skills/verify-ui/SKILL.md +96 -0
- package/.claude/skills/workflow-commands/SKILL.md +265 -0
- package/.claude/skills/workflow-commands/background-commands.md +130 -0
- package/.claude/skills/workflow-commands/backlogrun-child.md +364 -0
- package/.claude/skills/workflow-commands/backlogrun-lanes.md +345 -0
- package/.claude/skills/workflow-commands/backlogrun-park.md +179 -0
- package/.claude/skills/workflow-commands/backlogrun-progress.md +600 -0
- package/.claude/skills/workflow-commands/backlogrun-steps.md +604 -0
- package/.claude/skills/workflow-commands/backlogrun.md +109 -0
- package/.claude/skills/workflow-commands/chain-rule.md +98 -0
- package/.claude/skills/workflow-commands/delegation.md +52 -0
- package/.claude/skills/workflow-commands/followup-reference.md +118 -0
- package/.claude/skills/workflow-commands/followup.md +222 -0
- package/.claude/skills/workflow-commands/fullrun-steps.md +93 -0
- package/.claude/skills/workflow-commands/fullrun.md +82 -0
- package/.claude/skills/workflow-commands/halfrun.md +73 -0
- package/.claude/skills/workflow-commands/into-target.md +48 -0
- package/.claude/skills/workflow-commands/issue-comments.md +109 -0
- package/.claude/skills/workflow-commands/issue-fold-existing.md +27 -0
- package/.claude/skills/workflow-commands/issue-scout.md +45 -0
- package/.claude/skills/workflow-commands/kickoff.md +82 -0
- package/.claude/skills/workflow-commands/latest-gate.md +85 -0
- package/.claude/skills/workflow-commands/needs-human-review.md +64 -0
- package/.claude/skills/workflow-commands/observation-filing.md +349 -0
- package/.claude/skills/workflow-commands/pre-gate-cut.md +340 -0
- package/.claude/skills/workflow-commands/prerequisite.md +62 -0
- package/.claude/skills/workflow-commands/retrospective.md +81 -0
- package/.claude/skills/workflow-commands/rule-residency.md +267 -0
- package/.claude/skills/workflow-commands/split-assessment.md +130 -0
- package/.claude/skills/workflow-commands/target-repository.md +58 -0
- package/.claude/skills/workflow-commands/working-tree-hold.md +66 -0
- package/.claude-plugin/marketplace.json +15 -0
- package/.coderabbit.yaml +50 -0
- package/.codex/config.toml +8 -0
- package/.codex/hooks.json +71 -0
- package/.cursorrules +45 -0
- package/.gitattributes +7 -0
- package/.github/dependabot.yml +19 -0
- package/.github/pull_request_template.md +1 -0
- package/.github/release.yml +18 -0
- package/.github/workflows/auto-tag.yml +111 -0
- package/.github/workflows/ci.yml +681 -0
- package/.github/workflows/dependabot-auto-merge.yml +55 -0
- package/.github/workflows/production.yml +47 -0
- package/.github/workflows/publish.yml +39 -0
- package/.github/workflows/sonar-qube.yml +34 -0
- package/.mcp.json +8 -0
- package/.ncurc.json +3 -0
- package/.prettierignore +20 -0
- package/.vscode/extensions.json +21 -0
- package/.vscode/settings.json +41 -0
- package/AGENTS.md +29 -0
- package/CLAUDE.md +207 -0
- package/CODE_OF_CONDUCT.md +132 -0
- package/GEMINI.md +30 -0
- package/LICENSE +21 -0
- package/README.md +41 -0
- package/SECURITY.md +34 -0
- package/cspell/index.yaml +177 -0
- package/dist/CLAUDE.md +207 -0
- package/dist/config-merge/index.d.ts +29 -0
- package/dist/config-merge/index.js +459 -0
- package/dist/hooks/batch-guard.js +28 -0
- package/dist/hooks/chunk-25JL6FMS.js +4970 -0
- package/dist/hooks/chunk-2ANGT3XM.js +375 -0
- package/dist/hooks/chunk-2EI5GBSW.js +42 -0
- package/dist/hooks/chunk-2OT5XE2N.js +5014 -0
- package/dist/hooks/chunk-2RUPMGGV.js +137 -0
- package/dist/hooks/chunk-2XIGZQMQ.js +3299 -0
- package/dist/hooks/chunk-33ELOKEV.js +910 -0
- package/dist/hooks/chunk-33YRTKM7.js +230 -0
- package/dist/hooks/chunk-36JQU5NN.js +77 -0
- package/dist/hooks/chunk-3EJBTWVS.js +1769 -0
- package/dist/hooks/chunk-3FK5SFAC.js +432 -0
- package/dist/hooks/chunk-3PWPYDD2.js +240 -0
- package/dist/hooks/chunk-3TQU7TDH.js +375 -0
- package/dist/hooks/chunk-3TVLSFZ6.js +432 -0
- package/dist/hooks/chunk-3VXYCB4E.js +77 -0
- package/dist/hooks/chunk-44M6JXGV.js +3398 -0
- package/dist/hooks/chunk-46EEEHC3.js +240 -0
- package/dist/hooks/chunk-4A7UVP2P.js +364 -0
- package/dist/hooks/chunk-4LFQEZS4.js +137 -0
- package/dist/hooks/chunk-4OCX3V2T.js +469 -0
- package/dist/hooks/chunk-4OHA5DE7.js +49 -0
- package/dist/hooks/chunk-4PMDW3YD.js +68 -0
- package/dist/hooks/chunk-4QHBNAI4.js +68 -0
- package/dist/hooks/chunk-4SSB3FEE.js +3273 -0
- package/dist/hooks/chunk-5A2WQ2CQ.js +5390 -0
- package/dist/hooks/chunk-5EVA2JQB.js +5390 -0
- package/dist/hooks/chunk-5P7VF5VE.js +3230 -0
- package/dist/hooks/chunk-5QWJGGZP.js +49 -0
- package/dist/hooks/chunk-5U5EZYG6.js +77 -0
- package/dist/hooks/chunk-5VUUF3ZV.js +240 -0
- package/dist/hooks/chunk-5WA7UBT3.js +374 -0
- package/dist/hooks/chunk-6EBGRQ3Q.js +301 -0
- package/dist/hooks/chunk-6TVHWMD3.js +432 -0
- package/dist/hooks/chunk-6V5OPIUU.js +13 -0
- package/dist/hooks/chunk-6VAGLEMB.js +68 -0
- package/dist/hooks/chunk-75BTXKFJ.js +3424 -0
- package/dist/hooks/chunk-75RHN67S.js +137 -0
- package/dist/hooks/chunk-76KC3BDD.js +3414 -0
- package/dist/hooks/chunk-76SLS7CZ.js +898 -0
- package/dist/hooks/chunk-7DHZ4DWT.js +5015 -0
- package/dist/hooks/chunk-7INSJDGE.js +458 -0
- package/dist/hooks/chunk-7VJ4FTDX.js +268 -0
- package/dist/hooks/chunk-7XCYNHQK.js +77 -0
- package/dist/hooks/chunk-A5YJ3H7E.js +375 -0
- package/dist/hooks/chunk-AAEXXUUL.js +268 -0
- package/dist/hooks/chunk-ABVEVV2M.js +432 -0
- package/dist/hooks/chunk-ACN3YXFL.js +68 -0
- package/dist/hooks/chunk-AD3XE3QZ.js +397 -0
- package/dist/hooks/chunk-AENFZPZH.js +230 -0
- package/dist/hooks/chunk-AFKRFQ6W.js +68 -0
- package/dist/hooks/chunk-AHD5IPWI.js +375 -0
- package/dist/hooks/chunk-AMK5JGV7.js +77 -0
- package/dist/hooks/chunk-ARN7NCQI.js +425 -0
- package/dist/hooks/chunk-AUFY653N.js +3425 -0
- package/dist/hooks/chunk-AXQBNFEF.js +375 -0
- package/dist/hooks/chunk-AYC7R6U4.js +3316 -0
- package/dist/hooks/chunk-AYEA2FJ7.js +5015 -0
- package/dist/hooks/chunk-B2LIXYFL.js +77 -0
- package/dist/hooks/chunk-B4HPNY2I.js +375 -0
- package/dist/hooks/chunk-B4YNCUGB.js +469 -0
- package/dist/hooks/chunk-B57S3VWT.js +922 -0
- package/dist/hooks/chunk-BINZ3PLI.js +364 -0
- package/dist/hooks/chunk-BIWLABFK.js +432 -0
- package/dist/hooks/chunk-BODUSXKK.js +410 -0
- package/dist/hooks/chunk-BQBAT2YK.js +375 -0
- package/dist/hooks/chunk-BUJEBW75.js +391 -0
- package/dist/hooks/chunk-BVNWORKA.js +72 -0
- package/dist/hooks/chunk-BWI47LQS.js +5205 -0
- package/dist/hooks/chunk-C25HRMJX.js +137 -0
- package/dist/hooks/chunk-CBFZNC74.js +375 -0
- package/dist/hooks/chunk-CECYXS4Y.js +3424 -0
- package/dist/hooks/chunk-CELGUP5F.js +49 -0
- package/dist/hooks/chunk-CMHANU3F.js +3442 -0
- package/dist/hooks/chunk-CMN372LI.js +68 -0
- package/dist/hooks/chunk-CPGZLMMK.js +3299 -0
- package/dist/hooks/chunk-CTQKXDC7.js +268 -0
- package/dist/hooks/chunk-CYAT4RIT.js +68 -0
- package/dist/hooks/chunk-CYTWYCH2.js +5014 -0
- package/dist/hooks/chunk-CZSOLRBA.js +77 -0
- package/dist/hooks/chunk-D2PIDYJR.js +3438 -0
- package/dist/hooks/chunk-DE57HI6T.js +137 -0
- package/dist/hooks/chunk-DGXDGAPG.js +5306 -0
- package/dist/hooks/chunk-DNYRSYQG.js +5014 -0
- package/dist/hooks/chunk-DTAXH2A2.js +240 -0
- package/dist/hooks/chunk-E2IZUWI5.js +375 -0
- package/dist/hooks/chunk-E4L2K2BL.js +397 -0
- package/dist/hooks/chunk-E55NKX5F.js +68 -0
- package/dist/hooks/chunk-ECXVCCVD.js +3079 -0
- package/dist/hooks/chunk-EPHO443D.js +68 -0
- package/dist/hooks/chunk-EUFK2BI2.js +375 -0
- package/dist/hooks/chunk-EYCD5ZAV.js +137 -0
- package/dist/hooks/chunk-F2SDYJU4.js +240 -0
- package/dist/hooks/chunk-F4B5D5TF.js +68 -0
- package/dist/hooks/chunk-FGEO3NDX.js +432 -0
- package/dist/hooks/chunk-FJYI52RE.js +137 -0
- package/dist/hooks/chunk-FXAKJKTB.js +18 -0
- package/dist/hooks/chunk-FYTZHIY4.js +3085 -0
- package/dist/hooks/chunk-G7JL2A5K.js +375 -0
- package/dist/hooks/chunk-GA3ITDBW.js +42 -0
- package/dist/hooks/chunk-GDR4H4SV.js +469 -0
- package/dist/hooks/chunk-GFKDXPSM.js +2855 -0
- package/dist/hooks/chunk-GIMRTKFU.js +566 -0
- package/dist/hooks/chunk-GOPHRLGO.js +240 -0
- package/dist/hooks/chunk-GX4HO7SJ.js +230 -0
- package/dist/hooks/chunk-GXKKK23T.js +240 -0
- package/dist/hooks/chunk-GZ6FUVIK.js +566 -0
- package/dist/hooks/chunk-H5HPY5M5.js +2869 -0
- package/dist/hooks/chunk-HCF3OGEE.js +1829 -0
- package/dist/hooks/chunk-HDEXAOUM.js +469 -0
- package/dist/hooks/chunk-HM2TY3TN.js +469 -0
- package/dist/hooks/chunk-HOA7NXA2.js +55 -0
- package/dist/hooks/chunk-HOFEWH6H.js +240 -0
- package/dist/hooks/chunk-HUUI6S5J.js +2669 -0
- package/dist/hooks/chunk-I4D3NVUD.js +469 -0
- package/dist/hooks/chunk-I4Q6WAJE.js +68 -0
- package/dist/hooks/chunk-IB6N4CR2.js +432 -0
- package/dist/hooks/chunk-IFLDYJMD.js +469 -0
- package/dist/hooks/chunk-IGU466YD.js +77 -0
- package/dist/hooks/chunk-IJCQUHKY.js +375 -0
- package/dist/hooks/chunk-IKUMBDJB.js +230 -0
- package/dist/hooks/chunk-IM3BDIBJ.js +5005 -0
- package/dist/hooks/chunk-IMYMAODK.js +3431 -0
- package/dist/hooks/chunk-IN2ZVGXA.js +5005 -0
- package/dist/hooks/chunk-ITVJ2MKQ.js +18 -0
- package/dist/hooks/chunk-J5RIJYTM.js +2669 -0
- package/dist/hooks/chunk-JFLMH4K5.js +3460 -0
- package/dist/hooks/chunk-JR25IFML.js +77 -0
- package/dist/hooks/chunk-JT5AUXFI.js +432 -0
- package/dist/hooks/chunk-JY5YVN6N.js +3234 -0
- package/dist/hooks/chunk-K5Q4ETVI.js +391 -0
- package/dist/hooks/chunk-K67V2F24.js +137 -0
- package/dist/hooks/chunk-KABG6AEW.js +3460 -0
- package/dist/hooks/chunk-KATZESEC.js +3273 -0
- package/dist/hooks/chunk-KFH4H7W7.js +469 -0
- package/dist/hooks/chunk-KMUEI6RX.js +910 -0
- package/dist/hooks/chunk-KMV4OY77.js +3438 -0
- package/dist/hooks/chunk-KQAZNWEY.js +137 -0
- package/dist/hooks/chunk-KZZR6JER.js +5015 -0
- package/dist/hooks/chunk-LAR6DREP.js +77 -0
- package/dist/hooks/chunk-LNCJWEZD.js +5015 -0
- package/dist/hooks/chunk-LRYD2GLM.js +6 -0
- package/dist/hooks/chunk-LXBKYHDV.js +77 -0
- package/dist/hooks/chunk-LYLKIUNE.js +5024 -0
- package/dist/hooks/chunk-LZKCFOVC.js +432 -0
- package/dist/hooks/chunk-M4FCIYRI.js +77 -0
- package/dist/hooks/chunk-M5M7327Q.js +3425 -0
- package/dist/hooks/chunk-MF72MHSX.js +3455 -0
- package/dist/hooks/chunk-MK56LKDO.js +397 -0
- package/dist/hooks/chunk-N3MJADY7.js +240 -0
- package/dist/hooks/chunk-NFQSUDBN.js +458 -0
- package/dist/hooks/chunk-NHREKY45.js +137 -0
- package/dist/hooks/chunk-NP5TTAAW.js +375 -0
- package/dist/hooks/chunk-NQTLTKTJ.js +2993 -0
- package/dist/hooks/chunk-NVRCZPBZ.js +391 -0
- package/dist/hooks/chunk-O46HMMLJ.js +469 -0
- package/dist/hooks/chunk-OFJGH2L4.js +240 -0
- package/dist/hooks/chunk-OLFMCZH5.js +240 -0
- package/dist/hooks/chunk-OMCZS46I.js +49 -0
- package/dist/hooks/chunk-OQZEZW5G.js +469 -0
- package/dist/hooks/chunk-P2MDAT2Y.js +1897 -0
- package/dist/hooks/chunk-P3M2JJIF.js +68 -0
- package/dist/hooks/chunk-PDVHQITQ.js +3453 -0
- package/dist/hooks/chunk-PNT2AMDH.js +391 -0
- package/dist/hooks/chunk-PR2LVSY6.js +3445 -0
- package/dist/hooks/chunk-PRR5R4JK.js +137 -0
- package/dist/hooks/chunk-PXT44QVN.js +566 -0
- package/dist/hooks/chunk-PZLWJLAP.js +469 -0
- package/dist/hooks/chunk-Q2FEAZJ2.js +77 -0
- package/dist/hooks/chunk-Q32WETDO.js +3265 -0
- package/dist/hooks/chunk-Q45DUBLE.js +3600 -0
- package/dist/hooks/chunk-Q7NZSWQ5.js +240 -0
- package/dist/hooks/chunk-QH2JNAMK.js +3085 -0
- package/dist/hooks/chunk-QNNWYQ2R.js +375 -0
- package/dist/hooks/chunk-QPU5H2OS.js +68 -0
- package/dist/hooks/chunk-QRAHZ5TO.js +1829 -0
- package/dist/hooks/chunk-QUZ5HPIE.js +469 -0
- package/dist/hooks/chunk-QVCRG34O.js +2893 -0
- package/dist/hooks/chunk-R3MY4E3S.js +1675 -0
- package/dist/hooks/chunk-R6TXJJXP.js +77 -0
- package/dist/hooks/chunk-REJU6VT7.js +1829 -0
- package/dist/hooks/chunk-REQAQLRC.js +2993 -0
- package/dist/hooks/chunk-RFCXPAHH.js +391 -0
- package/dist/hooks/chunk-RHI6Y22X.js +137 -0
- package/dist/hooks/chunk-RKZVOBBS.js +469 -0
- package/dist/hooks/chunk-RL57TT2Y.js +566 -0
- package/dist/hooks/chunk-RORDOD4S.js +3321 -0
- package/dist/hooks/chunk-RZKYW5P2.js +77 -0
- package/dist/hooks/chunk-SJPJ6VSI.js +391 -0
- package/dist/hooks/chunk-SKSIJQQQ.js +432 -0
- package/dist/hooks/chunk-SSQDZKXG.js +268 -0
- package/dist/hooks/chunk-SSX23SJ2.js +89 -0
- package/dist/hooks/chunk-SYHFKE4C.js +77 -0
- package/dist/hooks/chunk-TCGNI2ZY.js +42 -0
- package/dist/hooks/chunk-TG3WXJF5.js +137 -0
- package/dist/hooks/chunk-TH7IJAY5.js +77 -0
- package/dist/hooks/chunk-TLZ27PCY.js +240 -0
- package/dist/hooks/chunk-U652FXTN.js +566 -0
- package/dist/hooks/chunk-UEK47YUF.js +268 -0
- package/dist/hooks/chunk-UIO45H3O.js +432 -0
- package/dist/hooks/chunk-UNLZEEVH.js +5005 -0
- package/dist/hooks/chunk-UNRVF3SZ.js +432 -0
- package/dist/hooks/chunk-USLFAFOI.js +3453 -0
- package/dist/hooks/chunk-VAEELMLL.js +442 -0
- package/dist/hooks/chunk-VALSWLDQ.js +3453 -0
- package/dist/hooks/chunk-VC5JEPNY.js +3398 -0
- package/dist/hooks/chunk-VEZVK6C7.js +230 -0
- package/dist/hooks/chunk-VK5JKFAR.js +49 -0
- package/dist/hooks/chunk-VNF2KP7Z.js +469 -0
- package/dist/hooks/chunk-VWWCUMW6.js +2669 -0
- package/dist/hooks/chunk-W4JARUQV.js +137 -0
- package/dist/hooks/chunk-WCYPBPJC.js +5014 -0
- package/dist/hooks/chunk-WEOBMNJG.js +2993 -0
- package/dist/hooks/chunk-WKJU3J5Y.js +5390 -0
- package/dist/hooks/chunk-WMN4TSVF.js +3299 -0
- package/dist/hooks/chunk-WNON54PT.js +3469 -0
- package/dist/hooks/chunk-WOVKBPPX.js +137 -0
- package/dist/hooks/chunk-WRVFORYJ.js +432 -0
- package/dist/hooks/chunk-WUBVYGQZ.js +240 -0
- package/dist/hooks/chunk-WWULTUOM.js +68 -0
- package/dist/hooks/chunk-WXHKKB45.js +4962 -0
- package/dist/hooks/chunk-XAI3YTHJ.js +469 -0
- package/dist/hooks/chunk-XFZH6JZJ.js +77 -0
- package/dist/hooks/chunk-XGPWX6IA.js +137 -0
- package/dist/hooks/chunk-XIXXIVGY.js +566 -0
- package/dist/hooks/chunk-XKDOYJGA.js +922 -0
- package/dist/hooks/chunk-YALTVBHM.js +432 -0
- package/dist/hooks/chunk-YEBEPBFK.js +5014 -0
- package/dist/hooks/chunk-YI2BQ3DK.js +3441 -0
- package/dist/hooks/chunk-YVNBCFGG.js +1829 -0
- package/dist/hooks/chunk-YXBN3RGG.js +432 -0
- package/dist/hooks/chunk-Z2OOJSW3.js +3163 -0
- package/dist/hooks/chunk-ZA3HVBOY.js +2644 -0
- package/dist/hooks/chunk-ZKID46U3.js +137 -0
- package/dist/hooks/chunk-ZPMU2JV6.js +49 -0
- package/dist/hooks/chunk-ZRKY4W7O.js +432 -0
- package/dist/hooks/chunk-ZTMRB7LJ.js +268 -0
- package/dist/hooks/chunk-ZVPPBQ3L.js +3413 -0
- package/dist/hooks/codex-hook-adapter.js +164 -0
- package/dist/hooks/duplicate-read-guard.js +29 -0
- package/dist/hooks/format-edited.js +37 -0
- package/dist/hooks/investigation-guard.js +31 -0
- package/dist/hooks/pretool-guard.js +21 -0
- package/dist/hooks/session-lang.js +34 -0
- package/dist/hooks/stop-guard.js +1597 -0
- package/dist/josh.js +1795 -0
- package/dist/managed-marker/index.d.ts +10 -0
- package/dist/managed-marker/index.js +32 -0
- package/dist/self-sync-guard/index.d.ts +10 -0
- package/dist/self-sync-guard/index.js +49 -0
- package/dist/version/index.d.ts +93 -0
- package/dist/version/index.js +1024 -0
- package/env/index.d.ts +7 -0
- package/env/index.js +62 -0
- package/eslint/base.js +233 -0
- package/eslint/checkout-rooted-parser.js +34 -0
- package/eslint/config-fingerprint.js +103 -0
- package/eslint/rules/code-quality.js +292 -0
- package/eslint/rules/english-only-prose.js +135 -0
- package/eslint/rules/formatting.js +44 -0
- package/eslint/rules/import.js +83 -0
- package/eslint/rules/namespace-object-export.js +107 -0
- package/eslint/rules/naming-convention.js +109 -0
- package/eslint/rules/promise.js +17 -0
- package/eslint/rules/sonarjs.js +45 -0
- package/eslint/rules/test-filename.js +91 -0
- package/eslint/rules/typescript.js +186 -0
- package/eslint/rules/unicorn.js +191 -0
- package/eslint/vanilla.js +1 -0
- package/evals/scenarios/consult-not-execute.json +20 -0
- package/evals/scenarios/no-implicit-workflow.json +26 -0
- package/evals/scenarios/overrides-both-locations.json +29 -0
- package/evals/scenarios/upstream-interrupt.json +23 -0
- package/evals/scenarios/workflow-skill-loaded.json +16 -0
- package/lefthook/base.yml +131 -0
- package/lefthook/vanilla.yml +7 -0
- package/package.json +169 -0
- package/playwright.config.ts +160 -0
- package/pnpm-workspace.yaml +41 -0
- package/ports/index.d.ts +17 -0
- package/ports/index.js +256 -0
- package/prettier/index.d.ts +3 -0
- package/prettier/index.js +31 -0
- package/prompts/agent-lint-protocol.json +79 -0
- package/prompts/agent-rules.md +63 -0
- package/prompts/coding-standards.md +382 -0
- package/prompts/collaboration-workflow/consultation-vs-execution.md +8 -0
- package/prompts/collaboration-workflow/cross-repo-epic.md +54 -0
- package/prompts/collaboration-workflow/distributed-docs.md +7 -0
- package/prompts/collaboration-workflow/durable-rules.md +24 -0
- package/prompts/collaboration-workflow/epic-audit.md +56 -0
- package/prompts/collaboration-workflow/epic-bundle.md +109 -0
- package/prompts/collaboration-workflow/file-edits.md +124 -0
- package/prompts/collaboration-workflow/gh-rest.md +57 -0
- package/prompts/collaboration-workflow/issue-citation.md +38 -0
- package/prompts/collaboration-workflow/issue-template.md +190 -0
- package/prompts/collaboration-workflow/latest-first.md +14 -0
- package/prompts/collaboration-workflow/no-clones.md +11 -0
- package/prompts/collaboration-workflow/operating-rules.md +123 -0
- package/prompts/collaboration-workflow/output-bounds.md +107 -0
- package/prompts/collaboration-workflow/overview.md +35 -0
- package/prompts/collaboration-workflow/plan-comment.md +85 -0
- package/prompts/collaboration-workflow/proposal-request.md +23 -0
- package/prompts/collaboration-workflow/report-format.md +206 -0
- package/prompts/collaboration-workflow/residency.md +94 -0
- package/prompts/collaboration-workflow/rule-delivery.md +146 -0
- package/prompts/collaboration-workflow/shell-body.md +82 -0
- package/prompts/collaboration-workflow/simplicity-first.md +9 -0
- package/prompts/collaboration-workflow/single-source-rules.md +13 -0
- package/prompts/collaboration-workflow/turn-batching.md +137 -0
- package/prompts/collaboration-workflow/upstream-interrupt.md +51 -0
- package/prompts/collaboration-workflow/wip-cap.md +118 -0
- package/prompts/collaboration-workflow.md +52 -0
- package/prompts/refactoring.md +103 -0
- package/prompts/review-rubric.md +338 -0
- package/prompts/review.md +217 -0
- package/prompts/sonar-hotspot-handling.md +77 -0
- package/prompts/testing-guide.md +277 -0
- package/scripts/adopt/adopt-logic.ts +107 -0
- package/scripts/adopt/adopt-toolkits.ts +181 -0
- package/scripts/adopt/adopt.ts +171 -0
- package/scripts/agent/agent-argv.ts +140 -0
- package/scripts/agent/agent-diagnostics.ts +120 -0
- package/scripts/agent/agent-event.ts +173 -0
- package/scripts/agent/agent-exit-record.ts +32 -0
- package/scripts/agent/agent-launch-environment.ts +71 -0
- package/scripts/agent/agent-role-profile.ts +329 -0
- package/scripts/agent/api-outage.ts +51 -0
- package/scripts/agent/claude-agent-argv.ts +151 -0
- package/scripts/agent/claude-result-event.ts +98 -0
- package/scripts/agent/codex-agent-argv.ts +94 -0
- package/scripts/agent/codex-home-source.ts +11 -0
- package/scripts/agent/interactive-ask.ts +91 -0
- package/scripts/auto-ok/auto-ok-cli.ts +516 -0
- package/scripts/backlog/backlog-arrival.ts +147 -0
- package/scripts/backlog/backlog-budget-cli.ts +220 -0
- package/scripts/backlog/backlog-budget.ts +284 -0
- package/scripts/backlog/backlog-defect-priority.ts +77 -0
- package/scripts/backlog/backlog-drive-cli.ts +377 -0
- package/scripts/backlog/backlog-drive-finish.ts +23 -0
- package/scripts/backlog/backlog-drive-named-offer.ts +81 -0
- package/scripts/backlog/backlog-drive-named.ts +101 -0
- package/scripts/backlog/backlog-drive-offer-argv.ts +29 -0
- package/scripts/backlog/backlog-drive-owner.ts +22 -0
- package/scripts/backlog/backlog-drive-restore.ts +67 -0
- package/scripts/backlog/backlog-drive.ts +322 -0
- package/scripts/backlog/backlog-named.ts +164 -0
- package/scripts/backlog/backlog-next.ts +376 -0
- package/scripts/backlog/backlog-offer-cli.ts +279 -0
- package/scripts/backlog/backlog-offer.ts +93 -0
- package/scripts/backlog/backlog-plan-cli.ts +235 -0
- package/scripts/backlog/backlog-plan.ts +231 -0
- package/scripts/backlog/backlog-pool.ts +322 -0
- package/scripts/backlog/backlog-ready.ts +146 -0
- package/scripts/backlog/backlog-scope.ts +144 -0
- package/scripts/backlog/backlog-stalled-cli.ts +30 -0
- package/scripts/backlog/backlog-stalled-detect.ts +143 -0
- package/scripts/backlog/backlog-stalled.ts +118 -0
- package/scripts/behavior/behavior-assertion.ts +87 -0
- package/scripts/behavior/behavior-cli.ts +88 -0
- package/scripts/behavior/behavior-rules.ts +128 -0
- package/scripts/build/build-bin.ts +36 -0
- package/scripts/build/build-claude-md.ts +42 -0
- package/scripts/build/build-config-merge.ts +26 -0
- package/scripts/build/build-hooks.ts +79 -0
- package/scripts/build/build-library.ts +83 -0
- package/scripts/build/build-managed-marker.ts +26 -0
- package/scripts/build/build-self-sync-guard.ts +26 -0
- package/scripts/build/build-version.ts +25 -0
- package/scripts/build/local-bin.ts +97 -0
- package/scripts/build/shim-shell.ts +25 -0
- package/scripts/bytes/bytes-command.ts +181 -0
- package/scripts/cases/cases-cli.ts +48 -0
- package/scripts/cases/cases-logic.ts +100 -0
- package/scripts/claude/skill-meta.ts +37 -0
- package/scripts/claude/workflow-destination.ts +13 -0
- package/scripts/clone/clone-aggregate.ts +76 -0
- package/scripts/clone/clone-fingerprint.ts +96 -0
- package/scripts/clone/clone-scan-cli.ts +39 -0
- package/scripts/clone/clone-scan.ts +158 -0
- package/scripts/config-merge/index.ts +19 -0
- package/scripts/config-merge/json-format.ts +128 -0
- package/scripts/config-merge/list-patch.ts +61 -0
- package/scripts/config-merge/parse-jsonc.ts +14 -0
- package/scripts/config-merge/patch-json-key.ts +439 -0
- package/scripts/config-merge/patch-json-list.ts +38 -0
- package/scripts/config-merge/patch-yaml-list.ts +107 -0
- package/scripts/cost-runtime/codex-usage.ts +119 -0
- package/scripts/cost-runtime/context-cut-payback.ts +77 -0
- package/scripts/cost-runtime/context-cut-threshold.ts +21 -0
- package/scripts/cost-runtime/cost-attribute.ts +168 -0
- package/scripts/cost-runtime/cost-blocks.ts +149 -0
- package/scripts/cost-runtime/cost-cli.ts +318 -0
- package/scripts/cost-runtime/cost-corpus.ts +278 -0
- package/scripts/cost-runtime/cost-format.ts +32 -0
- package/scripts/cost-runtime/cost-pricing.ts +176 -0
- package/scripts/cost-runtime/cost-tokens.ts +84 -0
- package/scripts/cost-runtime/cost-transcript.ts +531 -0
- package/scripts/cost-runtime/cost-usage.ts +287 -0
- package/scripts/cost-runtime/cost-verdict.ts +89 -0
- package/scripts/cost-runtime/own-session.ts +58 -0
- package/scripts/cost-runtime/transcript-cwd.ts +14 -0
- package/scripts/delegation/delegation-cli.ts +91 -0
- package/scripts/delegation/delegation-policy.ts +178 -0
- package/scripts/delegation/duplicate-read-guard.ts +244 -0
- package/scripts/delegation/fanout-cli.ts +61 -0
- package/scripts/delegation/fanout.ts +95 -0
- package/scripts/delegation/investigation-guard.ts +131 -0
- package/scripts/delegation/investigation-reads.ts +637 -0
- package/scripts/discovery/repo-discovery.ts +166 -0
- package/scripts/discovery/repo-map-logic.ts +102 -0
- package/scripts/discovery/repo-origin.ts +153 -0
- package/scripts/discovery/repo-party-cli.ts +69 -0
- package/scripts/discovery/repo-party.ts +46 -0
- package/scripts/doctor/doctor-consumer.ts +181 -0
- package/scripts/doctor/doctor-io.ts +210 -0
- package/scripts/doctor/doctor-logic.ts +122 -0
- package/scripts/doctor/doctor-ports.ts +117 -0
- package/scripts/doctor/doctor.ts +232 -0
- package/scripts/document/backlogrun-parent-read-set.ts +48 -0
- package/scripts/document/bash-output-cap.ts +45 -0
- package/scripts/document/document-byte-budget.ts +183 -0
- package/scripts/document/document-byte-check.ts +131 -0
- package/scripts/document/document-reachability.ts +131 -0
- package/scripts/document/document-read-cli.ts +82 -0
- package/scripts/document/document-scan.ts +108 -0
- package/scripts/document/document-section-cli.ts +101 -0
- package/scripts/document/document-section.ts +156 -0
- package/scripts/document/edit-files-cli.ts +280 -0
- package/scripts/document/entry-read-budget.ts +154 -0
- package/scripts/document/entry-read-set.ts +471 -0
- package/scripts/document/generate-catalog.ts +69 -0
- package/scripts/document/lane-child-read-set.ts +88 -0
- package/scripts/document/read-files-cli.ts +135 -0
- package/scripts/document/read-set-cli.ts +295 -0
- package/scripts/document/read-set-point-of-use.ts +89 -0
- package/scripts/document/read-set-pricing.ts +52 -0
- package/scripts/document/read-set-trim.ts +78 -0
- package/scripts/document/retired-phrases.ts +143 -0
- package/scripts/document/review-agent-type.ts +46 -0
- package/scripts/document/single-source.ts +73 -0
- package/scripts/epic/epic-audit-checks.ts +452 -0
- package/scripts/epic/epic-audit-cli.ts +374 -0
- package/scripts/epic/epic-audit-orphans.ts +142 -0
- package/scripts/epic/epic-audit-rationale.ts +191 -0
- package/scripts/epic/epic-audit-report.ts +101 -0
- package/scripts/epic/epic-audit.ts +240 -0
- package/scripts/epic/epic-bundle-cli.ts +472 -0
- package/scripts/epic/epic-bundle-evidence.ts +147 -0
- package/scripts/epic/epic-bundle-gaps.ts +86 -0
- package/scripts/epic/epic-bundle-referenced.ts +195 -0
- package/scripts/epic/epic-bundle.ts +309 -0
- package/scripts/epic/epic-busy.ts +204 -0
- package/scripts/epic/epic-candidate-confirm.ts +279 -0
- package/scripts/epic/epic-classify.ts +294 -0
- package/scripts/epic/epic-cross-repo.ts +366 -0
- package/scripts/epic/epic-fetch.ts +370 -0
- package/scripts/epic/epic-graph.ts +279 -0
- package/scripts/epic/epic-index.ts +209 -0
- package/scripts/epic/epic-issue.ts +172 -0
- package/scripts/epic/epic-lane-offer.ts +207 -0
- package/scripts/epic/epic-nested.ts +37 -0
- package/scripts/epic/epic-next-read.ts +141 -0
- package/scripts/epic/epic-next-views.ts +144 -0
- package/scripts/epic/epic-next.ts +477 -0
- package/scripts/epic/epic-outside-blocker.ts +113 -0
- package/scripts/epic/epic-relation-recheck.ts +108 -0
- package/scripts/epic/epic-report.ts +200 -0
- package/scripts/gate/core-budget.ts +292 -0
- package/scripts/gate/gate-log.ts +95 -0
- package/scripts/gate/gate-plan.ts +356 -0
- package/scripts/gate/gate-report.ts +207 -0
- package/scripts/gate/gate-skip.ts +123 -0
- package/scripts/gate/gate-tree.ts +49 -0
- package/scripts/gate/hook-gate-reuse.ts +130 -0
- package/scripts/gate/pre-commit-type-check.ts +187 -0
- package/scripts/gate/scoped-green.ts +260 -0
- package/scripts/gate/type-check-step.ts +90 -0
- package/scripts/gate/verification-gate.ts +531 -0
- package/scripts/gh/fix-gh-packages-logic.ts +232 -0
- package/scripts/gh/fix-gh-packages.ts +129 -0
- package/scripts/gh/gh-cli-token.ts +18 -0
- package/scripts/gh/gh-spawn.ts +44 -0
- package/scripts/git/animation-helpers.ts +81 -0
- package/scripts/git/change-base.ts +26 -0
- package/scripts/git/changed-file-scope.ts +209 -0
- package/scripts/git/changed-paths.ts +30 -0
- package/scripts/git/constants.ts +41 -0
- package/scripts/git/git-ai-review-scan.ts +154 -0
- package/scripts/git/git-animation.ts +41 -0
- package/scripts/git/git-branch.ts +127 -0
- package/scripts/git/git-command.ts +587 -0
- package/scripts/git/git-commit.ts +27 -0
- package/scripts/git/git-common-directory.ts +38 -0
- package/scripts/git/git-epic-add-body.ts +365 -0
- package/scripts/git/git-epic-add-plan.ts +421 -0
- package/scripts/git/git-epic-add.ts +249 -0
- package/scripts/git/git-epic-body.ts +150 -0
- package/scripts/git/git-epic-chains.ts +411 -0
- package/scripts/git/git-epic-close-comment.ts +199 -0
- package/scripts/git/git-epic-close.ts +393 -0
- package/scripts/git/git-epic-decision.ts +171 -0
- package/scripts/git/git-epic-parse.ts +351 -0
- package/scripts/git/git-epic-promote.ts +102 -0
- package/scripts/git/git-epic-read.ts +73 -0
- package/scripts/git/git-epic-reconcile.ts +246 -0
- package/scripts/git/git-epic-reference.ts +98 -0
- package/scripts/git/git-epic-relations.ts +78 -0
- package/scripts/git/git-epic-remove-plan.ts +152 -0
- package/scripts/git/git-epic-remove.ts +101 -0
- package/scripts/git/git-epic-run.ts +223 -0
- package/scripts/git/git-epic-sections.ts +98 -0
- package/scripts/git/git-epic-shape.ts +81 -0
- package/scripts/git/git-epic-validate.ts +155 -0
- package/scripts/git/git-error.ts +78 -0
- package/scripts/git/git-execa-error.ts +35 -0
- package/scripts/git/git-fixture-workspace.ts +88 -0
- package/scripts/git/git-followup-cleanup.ts +88 -0
- package/scripts/git/git-followup-flush.ts +63 -0
- package/scripts/git/git-followup-label.ts +67 -0
- package/scripts/git/git-followup-pending.ts +95 -0
- package/scripts/git/git-followup-stages.ts +149 -0
- package/scripts/git/git-gh-api-path.ts +118 -0
- package/scripts/git/git-gh-check.ts +21 -0
- package/scripts/git/git-gh-command.ts +17 -0
- package/scripts/git/git-gh-exec.ts +344 -0
- package/scripts/git/git-gh-failure.ts +103 -0
- package/scripts/git/git-gh-helpers.ts +44 -0
- package/scripts/git/git-gh-issue-list.ts +257 -0
- package/scripts/git/git-gh-issue-read.ts +457 -0
- package/scripts/git/git-gh-issue-rest.ts +238 -0
- package/scripts/git/git-gh-issue-write.ts +285 -0
- package/scripts/git/git-gh-issue.ts +161 -0
- package/scripts/git/git-gh-pr-auto-merge.ts +85 -0
- package/scripts/git/git-gh-pr-read.ts +322 -0
- package/scripts/git/git-gh-pr-rest.ts +172 -0
- package/scripts/git/git-gh-pr-review.ts +103 -0
- package/scripts/git/git-gh-pr-rollup.ts +91 -0
- package/scripts/git/git-gh-pr-snapshot.ts +138 -0
- package/scripts/git/git-gh-pr.ts +219 -0
- package/scripts/git/git-gh-reachability.ts +56 -0
- package/scripts/git/git-gh-repo.ts +37 -0
- package/scripts/git/git-gh-rest-state.ts +14 -0
- package/scripts/git/git-issue.ts +168 -0
- package/scripts/git/git-location-environment.ts +62 -0
- package/scripts/git/git-ls-remote.ts +28 -0
- package/scripts/git/git-next-issues.ts +98 -0
- package/scripts/git/git-notify.ts +104 -0
- package/scripts/git/git-pr-ai-review.ts +180 -0
- package/scripts/git/git-pr-checks-eval.ts +265 -0
- package/scripts/git/git-pr-checks-parse.ts +153 -0
- package/scripts/git/git-pr-checks-watch.ts +184 -0
- package/scripts/git/git-pr-checks.ts +387 -0
- package/scripts/git/git-pr-coderabbit.ts +129 -0
- package/scripts/git/git-pr-confirmation.ts +64 -0
- package/scripts/git/git-pr-error.ts +25 -0
- package/scripts/git/git-pr-followup-wrapup.ts +225 -0
- package/scripts/git/git-pr-followup.ts +436 -0
- package/scripts/git/git-pr-managed-config.ts +69 -0
- package/scripts/git/git-pr-messages.ts +37 -0
- package/scripts/git/git-pr.ts +181 -0
- package/scripts/git/git-prompt-display.ts +22 -0
- package/scripts/git/git-prompt.ts +207 -0
- package/scripts/git/git-push-transport.ts +173 -0
- package/scripts/git/git-push.ts +27 -0
- package/scripts/git/git-remote-branch.ts +40 -0
- package/scripts/git/git-spawn.ts +47 -0
- package/scripts/git/git-staging.ts +128 -0
- package/scripts/git/git-stash.ts +124 -0
- package/scripts/git/git-status.ts +198 -0
- package/scripts/git/git-worktree.ts +110 -0
- package/scripts/git/github-issue-url.ts +105 -0
- package/scripts/git/gone-branch.ts +113 -0
- package/scripts/git/issue-labels.ts +279 -0
- package/scripts/git/listing-cutoff.ts +51 -0
- package/scripts/git/main-merge-guard.ts +134 -0
- package/scripts/git/main-merge.ts +120 -0
- package/scripts/git/main-sync.ts +121 -0
- package/scripts/git/parse-json-array.ts +102 -0
- package/scripts/git/schemas.ts +166 -0
- package/scripts/git/stash-orphans.ts +91 -0
- package/scripts/git/stash-pop-args.ts +59 -0
- package/scripts/git/stash-pop-cli.ts +105 -0
- package/scripts/git/telegram-notify.ts +404 -0
- package/scripts/hooks/batch-guard.ts +144 -0
- package/scripts/hooks/check-commit-message.ts +134 -0
- package/scripts/hooks/codex-hook-adapter.ts +155 -0
- package/scripts/hooks/edited-cspell.ts +128 -0
- package/scripts/hooks/format-edited-file-fixtures.ts +109 -0
- package/scripts/hooks/format-edited-file.ts +510 -0
- package/scripts/hooks/format-rewrite-notice.ts +99 -0
- package/scripts/hooks/pre-push-unit.ts +146 -0
- package/scripts/hooks/pretool-guard.ts +96 -0
- package/scripts/hooks/prevent-main-commit.ts +38 -0
- package/scripts/hooks/prompt-hooks.ts +38 -0
- package/scripts/hooks/reserved-run.ts +90 -0
- package/scripts/hooks/stop-guard.ts +135 -0
- package/scripts/init/claude-plugin-config.ts +51 -0
- package/scripts/init/distributed-paths.ts +100 -0
- package/scripts/init/hook-command-rewrite.ts +85 -0
- package/scripts/init/hook-launch.ts +31 -0
- package/scripts/init/init-actions.ts +147 -0
- package/scripts/init/init-ai-copy.ts +235 -0
- package/scripts/init/init-copy-content.ts +50 -0
- package/scripts/init/init-logic-deploy-vps.ts +43 -0
- package/scripts/init/init-logic-json-merge.ts +340 -0
- package/scripts/init/init-logic-migrate.ts +62 -0
- package/scripts/init/init-logic-package-key-order.ts +50 -0
- package/scripts/init/init-logic-secretlint.ts +36 -0
- package/scripts/init/init-logic-sonar.ts +197 -0
- package/scripts/init/init-logic-templates.ts +142 -0
- package/scripts/init/init-logic-workspace.ts +59 -0
- package/scripts/init/init-logic-yaml-merge.ts +57 -0
- package/scripts/init/init-logic.ts +474 -0
- package/scripts/init/init-paths.ts +11 -0
- package/scripts/init/init-sonar.ts +32 -0
- package/scripts/init/init.ts +219 -0
- package/scripts/init/kit-base-preset.ts +60 -0
- package/scripts/init/plugin-install-hint.ts +47 -0
- package/scripts/init/tsconfig-preset-migration.ts +67 -0
- package/scripts/issue/baseline-measure.ts +105 -0
- package/scripts/issue/behavior-change-lint.ts +122 -0
- package/scripts/issue/defect-rate-cli.ts +167 -0
- package/scripts/issue/defect-rate.ts +145 -0
- package/scripts/issue/issue-backlinks-cli.ts +97 -0
- package/scripts/issue/issue-backlinks.ts +164 -0
- package/scripts/issue/issue-cite-cli.ts +158 -0
- package/scripts/issue/issue-cite.ts +102 -0
- package/scripts/issue/issue-comment-cli.ts +95 -0
- package/scripts/issue/issue-fold-cli.ts +104 -0
- package/scripts/issue/issue-fold-existing-cli.ts +81 -0
- package/scripts/issue/issue-fold-existing.ts +73 -0
- package/scripts/issue/issue-fold.ts +42 -0
- package/scripts/issue/issue-lint-cli.ts +60 -0
- package/scripts/issue/issue-lint.ts +26 -0
- package/scripts/issue/issue-logic.ts +50 -0
- package/scripts/issue/issue-read-cli.ts +190 -0
- package/scripts/issue/issue-read.ts +145 -0
- package/scripts/issue/issue-scout-cli.ts +482 -0
- package/scripts/issue/issue-scout.ts +244 -0
- package/scripts/issue/issue-state-cli.ts +260 -0
- package/scripts/issue/issue-state.ts +109 -0
- package/scripts/issue/markdown-section.ts +39 -0
- package/scripts/issue/measure-rerun-cli.ts +98 -0
- package/scripts/issue/reproduction-measure.ts +59 -0
- package/scripts/josh/__snapshots__/josh-command-map.test.ts.snap +1171 -0
- package/scripts/josh/agent-session-environment.ts +188 -0
- package/scripts/josh/cli-body.ts +96 -0
- package/scripts/josh/command-suggest.ts +57 -0
- package/scripts/josh/file-map-stamp.ts +264 -0
- package/scripts/josh/hook-decision.ts +479 -0
- package/scripts/josh/josh-command-map.ts +196 -0
- package/scripts/josh/josh-command-types.ts +226 -0
- package/scripts/josh/josh-commands-ai.ts +327 -0
- package/scripts/josh/josh-commands-backlog.ts +54 -0
- package/scripts/josh/josh-commands-clone.ts +18 -0
- package/scripts/josh/josh-commands-development.ts +206 -0
- package/scripts/josh/josh-commands-document.ts +45 -0
- package/scripts/josh/josh-commands-guard.ts +38 -0
- package/scripts/josh/josh-commands-hooks.ts +42 -0
- package/scripts/josh/josh-commands-issue.ts +69 -0
- package/scripts/josh/josh-commands-lane.ts +75 -0
- package/scripts/josh/josh-commands-lint.ts +37 -0
- package/scripts/josh/josh-commands-maintenance.ts +80 -0
- package/scripts/josh/josh-commands-project.ts +53 -0
- package/scripts/josh/josh-commands-split.ts +20 -0
- package/scripts/josh/josh-commands-versioning.ts +48 -0
- package/scripts/josh/josh-commands-workflow.ts +116 -0
- package/scripts/josh/josh-composite-arguments.ts +55 -0
- package/scripts/josh/josh-environment-file.ts +31 -0
- package/scripts/josh/josh-in-process.ts +80 -0
- package/scripts/josh/josh-logic.ts +308 -0
- package/scripts/josh/josh-run.ts +53 -0
- package/scripts/josh/josh-script-reader.ts +11 -0
- package/scripts/josh/josh-verdict.ts +111 -0
- package/scripts/josh/josh.ts +60 -0
- package/scripts/josh/kit-only.ts +33 -0
- package/scripts/josh/path-decision.ts +104 -0
- package/scripts/josh/platform-temporary.ts +66 -0
- package/scripts/josh/process-identity.ts +335 -0
- package/scripts/josh/session-language-cli.ts +51 -0
- package/scripts/josh/session-language.ts +30 -0
- package/scripts/josh/stamp-file.ts +194 -0
- package/scripts/lane/lane-await.ts +165 -0
- package/scripts/lane/lane-cache-run.ts +39 -0
- package/scripts/lane/lane-cache.ts +135 -0
- package/scripts/lane/lane-capacity.ts +69 -0
- package/scripts/lane/lane-child-invocation.ts +73 -0
- package/scripts/lane/lane-child-marker.ts +58 -0
- package/scripts/lane/lane-cli.ts +410 -0
- package/scripts/lane/lane-close.ts +197 -0
- package/scripts/lane/lane-dispatch-log.ts +13 -0
- package/scripts/lane/lane-dispatch.ts +458 -0
- package/scripts/lane/lane-environment.ts +253 -0
- package/scripts/lane/lane-guard-policy.ts +136 -0
- package/scripts/lane/lane-install.ts +94 -0
- package/scripts/lane/lane-launch-cli.ts +133 -0
- package/scripts/lane/lane-occupancy.ts +112 -0
- package/scripts/lane/lane-open.ts +275 -0
- package/scripts/lane/lane-output.ts +124 -0
- package/scripts/lane/lane-paths.ts +96 -0
- package/scripts/lane/lane-reap.ts +137 -0
- package/scripts/lane/lane-registry.ts +261 -0
- package/scripts/lane/lane-relaunch.ts +68 -0
- package/scripts/lane/lane-report.ts +95 -0
- package/scripts/lane/lane-resume.ts +61 -0
- package/scripts/lane/lane-seed.ts +44 -0
- package/scripts/lane/lane-start-point.ts +175 -0
- package/scripts/lane/openai-lane-supervisor-cli.ts +32 -0
- package/scripts/lane/openai-lane-supervisor-decision.ts +63 -0
- package/scripts/lane/openai-lane-supervisor.ts +337 -0
- package/scripts/lib/bounded-pool.ts +109 -0
- package/scripts/lib/buffered-process.ts +82 -0
- package/scripts/lib/caddy-logs.sh +45 -0
- package/scripts/lib/cli-flags.ts +19 -0
- package/scripts/lib/json-value.ts +24 -0
- package/scripts/lib/poll.ts +57 -0
- package/scripts/lib/read-file.ts +16 -0
- package/scripts/lib/schemas.ts +67 -0
- package/scripts/lib/spawn-exit.ts +45 -0
- package/scripts/lib/status-icons.ts +24 -0
- package/scripts/lines/effective-limit.ts +156 -0
- package/scripts/lines/line-budget.ts +404 -0
- package/scripts/lines/line-targets.ts +80 -0
- package/scripts/lines/lines-command.ts +174 -0
- package/scripts/lint/cspell-cached.ts +41 -0
- package/scripts/lint/lint-parallel.ts +72 -0
- package/scripts/lint/lint-related-scope.ts +128 -0
- package/scripts/lint/lint-related.ts +104 -0
- package/scripts/managed-marker/index.ts +5 -0
- package/scripts/managed-marker/managed-marker-logic.ts +67 -0
- package/scripts/observations/observation-ledger-home.ts +32 -0
- package/scripts/observations/observation-ledger-line.ts +93 -0
- package/scripts/observations/observation-ledger.ts +35 -0
- package/scripts/observations/observations-flush-cli.ts +42 -0
- package/scripts/observations/observations-flush-landing.ts +97 -0
- package/scripts/observations/observations-flush.ts +420 -0
- package/scripts/overrides/lockfile-overrides.ts +105 -0
- package/scripts/overrides/overrides-check.ts +84 -0
- package/scripts/overrides/overrides-files.ts +19 -0
- package/scripts/overrides/overrides-logic.ts +211 -0
- package/scripts/overrides/schemas.ts +49 -0
- package/scripts/package/package-scout-cli.ts +195 -0
- package/scripts/package/package-scout-format.ts +151 -0
- package/scripts/package/package-scout.ts +121 -0
- package/scripts/ports/port-command.ts +87 -0
- package/scripts/propagate/propagate-git-failure.ts +191 -0
- package/scripts/propagate/propagate-git.ts +224 -0
- package/scripts/propagate/propagate-publish.ts +181 -0
- package/scripts/propagate/propagate-run.ts +201 -0
- package/scripts/propagate/propagate-steps.ts +421 -0
- package/scripts/propagate/propagate-targets.ts +160 -0
- package/scripts/propagate/propagate.ts +216 -0
- package/scripts/refactor/import-graph.ts +187 -0
- package/scripts/refactor/refactor-lint.ts +250 -0
- package/scripts/refactor/refactor-scan-cli.ts +10 -0
- package/scripts/refactor/refactor-scan.ts +124 -0
- package/scripts/refactor/refactor-targets.ts +103 -0
- package/scripts/release/release-cli.ts +88 -0
- package/scripts/release/release-history.ts +132 -0
- package/scripts/release/release-plan.ts +130 -0
- package/scripts/release/release-publish.ts +152 -0
- package/scripts/release/release-scope-cli.ts +103 -0
- package/scripts/release/release-tag.ts +93 -0
- package/scripts/release/release-worktree.ts +71 -0
- package/scripts/repo/auto-merge-setting-logic.ts +100 -0
- package/scripts/repo/auto-merge-setting.ts +37 -0
- package/scripts/repo/repo-setting.ts +112 -0
- package/scripts/report/report-lint-cli.ts +49 -0
- package/scripts/report/report-lint.ts +250 -0
- package/scripts/retrospective/retrospective-cli.ts +97 -0
- package/scripts/retrospective/retrospective.ts +127 -0
- package/scripts/review/disposition-cli.ts +44 -0
- package/scripts/review/disposition-logic.ts +45 -0
- package/scripts/review/live-evidence.ts +62 -0
- package/scripts/review/review-attest-cli.ts +115 -0
- package/scripts/review/review-attest.ts +319 -0
- package/scripts/review/review-brief-cli.ts +290 -0
- package/scripts/review/review-brief.ts +440 -0
- package/scripts/review/review-checkout.ts +56 -0
- package/scripts/review/review-finding-ledger.ts +167 -0
- package/scripts/review/review-findings-cli.ts +57 -0
- package/scripts/review/review-level.ts +86 -0
- package/scripts/review/review-record-cli.ts +196 -0
- package/scripts/review/review-record.ts +74 -0
- package/scripts/review/review-round2-cli.ts +84 -0
- package/scripts/review/review-round2.ts +139 -0
- package/scripts/review/review-stamps.ts +113 -0
- package/scripts/review/review-tree.ts +58 -0
- package/scripts/rules/bash-triggers.ts +44 -0
- package/scripts/rules/decision-oracle.ts +342 -0
- package/scripts/rules/delivered-rules-harness.ts +72 -0
- package/scripts/rules/delivered-rules.ts +793 -0
- package/scripts/rules/early-heartbeat.ts +241 -0
- package/scripts/rules/file-body.ts +150 -0
- package/scripts/rules/filing-cap.ts +133 -0
- package/scripts/rules/filing-offer.ts +81 -0
- package/scripts/rules/firing-point.ts +63 -0
- package/scripts/rules/gh-api.ts +65 -0
- package/scripts/rules/git-argv.ts +129 -0
- package/scripts/rules/git-force.ts +104 -0
- package/scripts/rules/implementation-cut-verdict.ts +84 -0
- package/scripts/rules/implementation-cut.ts +202 -0
- package/scripts/rules/issue-citation.ts +242 -0
- package/scripts/rules/issue-fold.ts +73 -0
- package/scripts/rules/issue-scout.ts +64 -0
- package/scripts/rules/josh-git-bare.ts +80 -0
- package/scripts/rules/lane-carry-conflict.ts +96 -0
- package/scripts/rules/lane-interactive-ask.ts +71 -0
- package/scripts/rules/lane-park.ts +122 -0
- package/scripts/rules/lane-switch-main.ts +139 -0
- package/scripts/rules/oracle-consulted.ts +81 -0
- package/scripts/rules/oracle-firing.ts +151 -0
- package/scripts/rules/oracle-list-cli.ts +81 -0
- package/scripts/rules/piped-verification.ts +126 -0
- package/scripts/rules/poll-loop.ts +125 -0
- package/scripts/rules/pre-gate-cut.ts +207 -0
- package/scripts/rules/prior-comment-read.ts +106 -0
- package/scripts/rules/raw-field-body.ts +56 -0
- package/scripts/rules/reply-language.ts +116 -0
- package/scripts/rules/rule-body-guard.ts +206 -0
- package/scripts/rules/rule-guard.ts +23 -0
- package/scripts/rules/rule-value-cli.ts +129 -0
- package/scripts/rules/rule-value.ts +397 -0
- package/scripts/rules/run-tail.ts +178 -0
- package/scripts/rules/shell-body-trigger.ts +204 -0
- package/scripts/rules/shell-segments.ts +45 -0
- package/scripts/rules/stop-rules.ts +329 -0
- package/scripts/rules/tail-commands.ts +35 -0
- package/scripts/rules/test-declared-commit.ts +51 -0
- package/scripts/rules/third-party-write.ts +90 -0
- package/scripts/rules/top-level-scripts-guard.ts +47 -0
- package/scripts/rules/worktree-guard.ts +130 -0
- package/scripts/run/detached-launch.ts +360 -0
- package/scripts/run/run-carry-args.ts +264 -0
- package/scripts/run/run-carry-change.ts +69 -0
- package/scripts/run/run-carry-cli.ts +441 -0
- package/scripts/run/run-carry-flush.ts +63 -0
- package/scripts/run/run-carry-stash.ts +71 -0
- package/scripts/run/run-carry-streak.ts +113 -0
- package/scripts/run/run-carry.ts +550 -0
- package/scripts/run/run-cut-args.ts +132 -0
- package/scripts/run/run-cut-cli.ts +461 -0
- package/scripts/run/run-cut-handoff.ts +126 -0
- package/scripts/run/run-cut.ts +531 -0
- package/scripts/run/run-ending-cli.ts +111 -0
- package/scripts/run/run-ending.ts +239 -0
- package/scripts/run/run-entry-cli.ts +135 -0
- package/scripts/run/run-entry.ts +95 -0
- package/scripts/run/run-event-cli.ts +210 -0
- package/scripts/run/run-event-follow.ts +65 -0
- package/scripts/run/run-event-render.ts +75 -0
- package/scripts/run/run-event-scope.ts +127 -0
- package/scripts/run/run-event-stream-emit.ts +140 -0
- package/scripts/run/run-event-stream.ts +258 -0
- package/scripts/run/run-event-watch.ts +37 -0
- package/scripts/run/run-headless.ts +105 -0
- package/scripts/run/run-hold-cli.ts +310 -0
- package/scripts/run/run-hold.ts +264 -0
- package/scripts/run/run-invocation.ts +237 -0
- package/scripts/run/run-issue-number.ts +19 -0
- package/scripts/run/run-liveness-cli.ts +169 -0
- package/scripts/run/run-liveness.ts +424 -0
- package/scripts/run/run-merge-cli.ts +385 -0
- package/scripts/run/run-merge-steps.ts +326 -0
- package/scripts/run/run-merge.ts +158 -0
- package/scripts/run/run-next-cli.ts +48 -0
- package/scripts/run/run-next.ts +80 -0
- package/scripts/run/run-preflight.ts +337 -0
- package/scripts/run/run-prep-cli.ts +151 -0
- package/scripts/run/run-prep.ts +84 -0
- package/scripts/run/run-progress-args.ts +65 -0
- package/scripts/run/run-progress-cli.ts +508 -0
- package/scripts/run/run-progress-clock.ts +320 -0
- package/scripts/run/run-progress-config.ts +119 -0
- package/scripts/run/run-progress-read.ts +199 -0
- package/scripts/run/run-progress.ts +366 -0
- package/scripts/run/run-report-cli.ts +71 -0
- package/scripts/run/run-report.ts +78 -0
- package/scripts/run/run-review-cli.ts +130 -0
- package/scripts/run/run-review-steps.ts +161 -0
- package/scripts/run/run-review.ts +121 -0
- package/scripts/run/run-ship-cli.ts +431 -0
- package/scripts/run/run-ship-detach.ts +200 -0
- package/scripts/run/run-ship-probe.ts +103 -0
- package/scripts/run/run-ship-return.ts +75 -0
- package/scripts/run/run-ship-review-steps.ts +227 -0
- package/scripts/run/run-ship-review.ts +177 -0
- package/scripts/run/run-ship-stage.ts +150 -0
- package/scripts/run/run-ship.ts +78 -0
- package/scripts/run/run-status-cli.ts +175 -0
- package/scripts/run/run-status.ts +77 -0
- package/scripts/run/run-step-cli.ts +111 -0
- package/scripts/run/run-step.ts +292 -0
- package/scripts/run/run-stop-notify.ts +52 -0
- package/scripts/run/run-stranded-cli.ts +31 -0
- package/scripts/run/run-stranded-detect.ts +134 -0
- package/scripts/run/run-stranded.ts +120 -0
- package/scripts/run/run-tail-cli.ts +105 -0
- package/scripts/run/run-tail.ts +61 -0
- package/scripts/run/run-transcript.golden.txt +57 -0
- package/scripts/run/run-wake-cli.ts +428 -0
- package/scripts/run/run-wake-describe.ts +97 -0
- package/scripts/run/run-wake-driver.ts +80 -0
- package/scripts/run/run-wake-handoff.ts +29 -0
- package/scripts/run/run-wake-loop.ts +223 -0
- package/scripts/run/run-wake-session.ts +150 -0
- package/scripts/run/run-wake-work.ts +104 -0
- package/scripts/run/run-wake.ts +607 -0
- package/scripts/run/run-watcher-guard-cli.ts +37 -0
- package/scripts/run/run-watcher-guard.ts +59 -0
- package/scripts/run/run-watcher-hook.ts +86 -0
- package/scripts/security/secretlint-scan.ts +86 -0
- package/scripts/security/security-audit-logic.ts +51 -0
- package/scripts/security/security-audit-provision-logic.ts +217 -0
- package/scripts/security/security-audit-provision.ts +186 -0
- package/scripts/security/security-audit.ts +132 -0
- package/scripts/security/security-updates-logic.ts +131 -0
- package/scripts/security/security-updates.ts +38 -0
- package/scripts/security/sonar-file.ts +44 -0
- package/scripts/self-sync-guard/index.ts +5 -0
- package/scripts/self-sync-guard/self-sync-guard-logic.ts +98 -0
- package/scripts/self-sync-guard/self-sync-refusal.ts +22 -0
- package/scripts/sonar/sonar-hotspots-cli.ts +149 -0
- package/scripts/sonar/sonar-hotspots.ts +111 -0
- package/scripts/split/split-assess-cli.ts +52 -0
- package/scripts/split/split-assess.ts +124 -0
- package/scripts/sync/dependabot-pin-logic.ts +135 -0
- package/scripts/sync/directory-copy-guard.ts +187 -0
- package/scripts/sync/file-content.ts +49 -0
- package/scripts/sync/managed-config-scope-cli.ts +64 -0
- package/scripts/sync/managed-config-scope.ts +123 -0
- package/scripts/sync/plugin-skill-directories.ts +15 -0
- package/scripts/sync/reconcile-templates.ts +53 -0
- package/scripts/sync/removed-skill-manifest.ts +27 -0
- package/scripts/sync/skill-migration.ts +192 -0
- package/scripts/sync/sync-configs.ts +156 -0
- package/scripts/sync/sync-hook-safety.ts +82 -0
- package/scripts/sync/sync.ts +417 -0
- package/scripts/sync/synced-paths.ts +52 -0
- package/scripts/sync/template-source-logic.ts +122 -0
- package/scripts/sync/workflow-pin-logic.ts +240 -0
- package/scripts/test/classify-isolation.ts +149 -0
- package/scripts/test/e2e-retry-check.ts +150 -0
- package/scripts/test/http-fault-injection.ts +79 -0
- package/scripts/test/josh-harness-environment.ts +260 -0
- package/scripts/test/josh-harness.ts +96 -0
- package/scripts/test/pilot-files.ts +457 -0
- package/scripts/test/pilot-measure.ts +78 -0
- package/scripts/test/test-declared-changed.ts +99 -0
- package/scripts/test/test-declared-logic.ts +91 -0
- package/scripts/test/test-declared-match.ts +106 -0
- package/scripts/test/test-declared.ts +180 -0
- package/scripts/test/test-e2e-guard.ts +86 -0
- package/scripts/test/test-network-guard.ts +453 -0
- package/scripts/test/test-red-commit.ts +51 -0
- package/scripts/test/test-red-logic.ts +76 -0
- package/scripts/test/test-red.ts +154 -0
- package/scripts/test/test-related-scope.ts +115 -0
- package/scripts/test/test-related.ts +73 -0
- package/scripts/test/test-repository-guard.ts +317 -0
- package/scripts/test/test-state-guard.ts +85 -0
- package/scripts/test/test-stdout-guard.ts +54 -0
- package/scripts/test/test-telegram-guard.ts +90 -0
- package/scripts/test/test-type-logic.ts +31 -0
- package/scripts/test/test-unit-guard.ts +185 -0
- package/scripts/test/unit-guard-environment.ts +12 -0
- package/scripts/test/unit-projects.ts +139 -0
- package/scripts/test/unit-worker-share.ts +251 -0
- package/scripts/test/vitest-include-globs.ts +12 -0
- package/scripts/time-runtime/time-agent-bundles.ts +128 -0
- package/scripts/time-runtime/time-background.ts +300 -0
- package/scripts/time-runtime/time-batch-guard-fixtures.ts +66 -0
- package/scripts/time-runtime/time-batch-guard.ts +529 -0
- package/scripts/time-runtime/time-bundle-call.ts +575 -0
- package/scripts/time-runtime/time-bundles.ts +536 -0
- package/scripts/time-runtime/time-call-identity.ts +37 -0
- package/scripts/time-runtime/time-command-key.ts +35 -0
- package/scripts/time-runtime/time-density-hook.ts +166 -0
- package/scripts/time-runtime/time-density.ts +147 -0
- package/scripts/time-runtime/time-followup-stage.ts +107 -0
- package/scripts/time-runtime/time-format.ts +186 -0
- package/scripts/time-runtime/time-hook-transcript.ts +82 -0
- package/scripts/time-runtime/time-instant.ts +20 -0
- package/scripts/time-runtime/time-markers.ts +228 -0
- package/scripts/time-runtime/time-phase-names.ts +123 -0
- package/scripts/time-runtime/time-reported-failure.ts +227 -0
- package/scripts/time-runtime/time-round-trips.ts +279 -0
- package/scripts/time-runtime/time-shell.ts +286 -0
- package/scripts/time-runtime/time-single-check.ts +65 -0
- package/scripts/time-runtime/time-spans.ts +545 -0
- package/scripts/time-runtime/time-transcript-line.ts +253 -0
- package/scripts/time-runtime/time-writes.ts +71 -0
- package/scripts/ui/ui-routes-cli.ts +122 -0
- package/scripts/ui/ui-routes.ts +102 -0
- package/scripts/version/bump-version.ts +71 -0
- package/scripts/version/effective-upstream.ts +93 -0
- package/scripts/version/index.ts +25 -0
- package/scripts/version/kit-descriptor.ts +10 -0
- package/scripts/version/kit-version-config.ts +30 -0
- package/scripts/version/latest-corepack.ts +404 -0
- package/scripts/version/latest-lane-guard.ts +49 -0
- package/scripts/version/latest-regression.ts +93 -0
- package/scripts/version/latest-scope-cli.ts +147 -0
- package/scripts/version/latest-stamp.ts +107 -0
- package/scripts/version/latest-update.ts +198 -0
- package/scripts/version/package-manager-version.ts +95 -0
- package/scripts/version/parse-json.ts +13 -0
- package/scripts/version/preinstall-version-update.ts +84 -0
- package/scripts/version/publishable-range-check.ts +74 -0
- package/scripts/version/publishable-range.ts +123 -0
- package/scripts/version/release-age.ts +146 -0
- package/scripts/version/release-hold.ts +142 -0
- package/scripts/version/running-binary.ts +42 -0
- package/scripts/version/upgrade-command-guard.ts +49 -0
- package/scripts/version/upgrade-shell-command.ts +30 -0
- package/scripts/version/version-check-logic.ts +333 -0
- package/scripts/version/version-check.ts +14 -0
- package/scripts/version/version-command-config.ts +177 -0
- package/scripts/version/version-commands.ts +296 -0
- package/scripts/version/version-remote.ts +86 -0
- package/scripts/version/version-targets.ts +81 -0
- package/scripts/yaml/yaml-document.ts +46 -0
- package/scripts-ai/completion-gate.ts +13 -0
- package/scripts-ai/environment-loader.ts +9 -0
- package/scripts-ai/epic-check.ts +34 -0
- package/scripts-ai/epic-cli-argv.ts +77 -0
- package/scripts-ai/epic-cli-remove.ts +71 -0
- package/scripts-ai/epic-cli.ts +413 -0
- package/scripts-ai/epic.ts +192 -0
- package/scripts-ai/followup-issue-number.ts +31 -0
- package/scripts-ai/git-followup-finish.ts +217 -0
- package/scripts-ai/git-followup-workflow.ts +252 -0
- package/scripts-ai/git-workflow.ts +246 -0
- package/scripts-ai/telegram-test-logic.ts +88 -0
- package/scripts-ai/telegram-test.ts +130 -0
- package/templates/gitignore +76 -0
- package/templates/sonar-project.properties +52 -0
- package/templates/workflows/ci.yml +639 -0
- package/templates/workflows/dependabot-auto-merge.yml +428 -0
- package/tsconfig/base.json +50 -0
- package/tsconfig.sonar.json +34 -0
|
@@ -0,0 +1,404 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto'
|
|
2
|
+
import { statSync } from 'node:fs'
|
|
3
|
+
import path from 'node:path'
|
|
4
|
+
import { find_local_bin_upwards } from '#scripts/build/local-bin'
|
|
5
|
+
import { stamp_file } from '#scripts/josh/stamp-file'
|
|
6
|
+
import { execa } from 'execa'
|
|
7
|
+
import { z } from 'zod'
|
|
8
|
+
import { effective_limit, type LineRuleOptions } from './effective-limit'
|
|
9
|
+
|
|
10
|
+
// joshuafolkken/kit#1425: the file line limit was only ever reported *after* the writing was done.
|
|
11
|
+
// Measured by hand from run #1406's transcript (PR #1422, 45.8 minutes), 19.8% of the whole run —
|
|
12
|
+
// 543 seconds — went on reacting to `max-lines` once the implementation was already finished:
|
|
13
|
+
// `pnpm josh gate` five times and `pnpm josh lint` four, of which 115 seconds was tool execution and
|
|
14
|
+
// the remaining 353 was model time in between. The splitting itself was correct work; what was wrong
|
|
15
|
+
// is that it was decided after the fact rather than at design time.
|
|
16
|
+
//
|
|
17
|
+
// **The limit is not changed here, and nothing in this file counts lines its own way.** That is the
|
|
18
|
+
// trap a headroom report walks into: a second counting method becomes a way to satisfy the limit by
|
|
19
|
+
// counting differently, and `CLAUDE.md` treats reinterpreting a verification gate as a prohibited
|
|
20
|
+
// workaround. So the number is not computed — it is *asked of the project's own eslint*, the same
|
|
21
|
+
// invocation `pnpm josh lint` reaches, with `max-lines` lowered to 0 so the rule reports
|
|
22
|
+
// unconditionally and its message carries the count it would have compared against the real limit.
|
|
23
|
+
//
|
|
24
|
+
// **Running ESLint in process instead was tried first and is wrong.** `new Linter().verify(...)` and
|
|
25
|
+
// `new ESLint().lintFiles(...)` both answer **one line lower than the `eslint` CLI on any file that
|
|
26
|
+
// starts with `#!`** — measured on eslint 10.10.0 with this repository's own config, `301` from the
|
|
27
|
+
// CLI against `300` from either API for the same file. Every `scripts/*.ts` entry point has a
|
|
28
|
+
// hashbang, so an in-process count would have been quietly wrong for most of this package while the
|
|
29
|
+
// gate went on failing at a number the report never showed. Spawning costs a process; agreeing with
|
|
30
|
+
// the gate is the whole point of the report.
|
|
31
|
+
//
|
|
32
|
+
// **joshuafolkken/kit#1454: the limit and the counting options come from the same place the count
|
|
33
|
+
// does.** They used to be read from kit's own `eslint/rules/code-quality.js` while the count was asked
|
|
34
|
+
// of the project's eslint — identical in kit, and two different rules in a consumer that overrides
|
|
35
|
+
// `max-lines` after `create_base_config`. `effective-limit.ts` resolves the entry the project's own
|
|
36
|
+
// eslint applies **to each file**, and nothing in this file reads kit's copy any more. Where no entry
|
|
37
|
+
// can be resolved there is no budget, and the count is reported without one: falling back to kit's
|
|
38
|
+
// number would restore the defect and do it silently.
|
|
39
|
+
|
|
40
|
+
const MAX_LINES_RULE = 'max-lines'
|
|
41
|
+
// The rule reports when the count is **greater than** `max`, and 0 is the lowest value its own schema
|
|
42
|
+
// accepts — so at `max: 0` every file reports except one whose counted code lines are exactly 0. That
|
|
43
|
+
// is not only the empty file: with `skipBlankLines` and `skipComments` on, a comments-and-blank-lines
|
|
44
|
+
// module counts 0 too. `count_or_zero` below is what keeps that case an answer rather than a shrug —
|
|
45
|
+
// and `--no-inline-config` is what keeps a silenced rule from being mistaken for one of those files.
|
|
46
|
+
const PROBE_MAX = 0
|
|
47
|
+
const PROBE_SEVERITY = 'error'
|
|
48
|
+
// The boundary between having headroom and being over the limit. Deliberately *not* `PROBE_MAX`, which
|
|
49
|
+
// they happen to share the value of today: one is the value handed to the rule and the other is a
|
|
50
|
+
// property of a budget, and reading the two as one constant means raising either silently moves the
|
|
51
|
+
// other.
|
|
52
|
+
const NO_HEADROOM = 0
|
|
53
|
+
// A file eslint linted but said nothing about under this rule has exactly this many code lines.
|
|
54
|
+
const NO_CODE_LINES = 0
|
|
55
|
+
// `File has too many lines (229). Maximum allowed is 0.` — the first parenthesised number is the
|
|
56
|
+
// count. Pinned by a test that feeds the number back as the real limit and checks that the gate's own
|
|
57
|
+
// verdict flips at exactly that boundary, so a reworded message fails there rather than reporting a
|
|
58
|
+
// wrong number quietly.
|
|
59
|
+
const COUNT_PATTERN = /\((\d+)\)/u
|
|
60
|
+
const COUNT_GROUP = 1
|
|
61
|
+
|
|
62
|
+
// **Why 85%, and how it lines up with joshuafolkken/kit#1249.** That issue asks for the same shape
|
|
63
|
+
// for a distributed document's resident budget and is still open with nothing settled, so there is no
|
|
64
|
+
// number there to copy; what it and joshuafolkken/kit#951 settle is the *form* — a margin that turns
|
|
65
|
+
// "at the limit" into a warning while there is still room to write the fix. Matching the resident
|
|
66
|
+
// reserve's fraction instead (2,000 of 60,000 bytes, 3.3%) would leave 10 lines of margin, less than
|
|
67
|
+
// one function is allowed to be, which is a warning arriving with nowhere left to go. 45 lines is a
|
|
68
|
+
// little under two functions at the 25-line function limit — enough to write the split into.
|
|
69
|
+
const NEAR_LIMIT_FRACTION = 0.85
|
|
70
|
+
const PERCENT = 100
|
|
71
|
+
|
|
72
|
+
const ESLINT_BIN = 'eslint'
|
|
73
|
+
const PNPM = 'pnpm'
|
|
74
|
+
const PNPM_EXEC = 'exec'
|
|
75
|
+
// `--no-inline-config` is not tidiness: a `/* eslint-disable max-lines */` at the top of a file
|
|
76
|
+
// silences the rule, an inline directive beats the `--rule` override, and the probe would then see no
|
|
77
|
+
// message and read the file as 0 code lines — printing `300 to spare` for a 500-line file, which is
|
|
78
|
+
// the most dangerous direction this report can be wrong in. With inline configuration off, the count
|
|
79
|
+
// is always the rule's own.
|
|
80
|
+
const FORMAT_FLAGS: ReadonlyArray<string> = ['--format', 'json', '--no-inline-config']
|
|
81
|
+
const RULE_FLAG = '--rule'
|
|
82
|
+
// **No `--cache`, and a `--cache-location` all the same.** An eslint run started *without* `--cache`
|
|
83
|
+
// deletes whatever `--cache-location` names, which is how the edit hook once wiped the gate's cache
|
|
84
|
+
// (joshuafolkken/kit#1332) — so the flag has to be here, pointed somewhere harmless, even though this
|
|
85
|
+
// probe keeps no cache. It keeps none because the only key available is the checkout, and two
|
|
86
|
+
// `josh lines` calls at once in one repository — routine with parallel agents here — would then be two
|
|
87
|
+
// unsynchronized writers of one file. A cold run is a couple of seconds against the 543 this report
|
|
88
|
+
// exists to save, so the cache is not worth a shared-state hazard.
|
|
89
|
+
//
|
|
90
|
+
// **The path is per probe, not per call** (joshuafolkken/kit#1454). Since the counting method decides
|
|
91
|
+
// how many probes one call starts, two of them can now run concurrently — and each deletes whatever
|
|
92
|
+
// `--cache-location` names as it starts, so one shared path would have them racing to unlink the file
|
|
93
|
+
// the other just made. The option set's own key is folded into the name, which makes the paths
|
|
94
|
+
// distinct exactly when the probes are.
|
|
95
|
+
const CACHE_PREFIX = 'josh-lines-eslint-cache-'
|
|
96
|
+
const CACHE_LOCATION_FLAG = '--cache-location'
|
|
97
|
+
const CACHE_KEY_LENGTH = 8
|
|
98
|
+
// Bounded so a hung child ends the call rather than holding it open. A cold type-aware lint of a few
|
|
99
|
+
// files is seconds; this is two orders of magnitude beyond that.
|
|
100
|
+
const PROCESS_TIMEOUT_MS = 180_000
|
|
101
|
+
|
|
102
|
+
// Only the two fields this reads. `ruleId` is nullable on a parse error or an ignore warning, and
|
|
103
|
+
// both of those are answers — "no count for this path" — rather than failures.
|
|
104
|
+
const message_schema = z.object({ ruleId: z.string().nullish(), message: z.string() })
|
|
105
|
+
const results_schema = z.array(
|
|
106
|
+
z.object({ filePath: z.string(), messages: z.array(message_schema) }),
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
interface LineBudget {
|
|
110
|
+
code_lines: number
|
|
111
|
+
limit: number
|
|
112
|
+
headroom: number
|
|
113
|
+
is_near_limit: boolean
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// `limit` is carried beside the budget, and it is not the same thing as `budget.limit`: a path this
|
|
117
|
+
// project enforces no `max-lines` on has no limit at all, and the caller has to be able to say that
|
|
118
|
+
// rather than say the count failed (joshuafolkken/kit#1454).
|
|
119
|
+
interface FileBudget {
|
|
120
|
+
file_path: string
|
|
121
|
+
limit: number | undefined
|
|
122
|
+
budget: LineBudget | undefined
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// The paths that share one counting method, and therefore one eslint run. `key` identifies that
|
|
126
|
+
// method — it is what the paths were grouped by, and what keeps two concurrent probes off one cache
|
|
127
|
+
// path.
|
|
128
|
+
interface ProbeGroup {
|
|
129
|
+
key: string
|
|
130
|
+
options: LineRuleOptions
|
|
131
|
+
paths: Array<string>
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function near_limit_threshold(limit: number): number {
|
|
135
|
+
return Math.ceil(limit * NEAR_LIMIT_FRACTION)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// The share of the limit at which "near the limit" begins, for a report that has no single limit to
|
|
139
|
+
// state the boundary as a line count against.
|
|
140
|
+
function near_limit_percent(): number {
|
|
141
|
+
return Math.round(NEAR_LIMIT_FRACTION * PERCENT)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function budget_of(code_lines: number, limit: number): LineBudget {
|
|
145
|
+
return {
|
|
146
|
+
code_lines,
|
|
147
|
+
limit,
|
|
148
|
+
headroom: limit - code_lines,
|
|
149
|
+
is_near_limit: code_lines >= near_limit_threshold(limit),
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// The counting options are the project's own, so a consumer that turns `skipComments` off is counted
|
|
154
|
+
// its way. Lowering `max` is the only change the probe makes.
|
|
155
|
+
function probe_rule(options: LineRuleOptions): string {
|
|
156
|
+
return JSON.stringify({
|
|
157
|
+
[MAX_LINES_RULE]: [PROBE_SEVERITY, { ...options, max: PROBE_MAX }],
|
|
158
|
+
})
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function cache_prefix(key: string): string {
|
|
162
|
+
const digest = createHash('sha256').update(key).digest('hex').slice(0, CACHE_KEY_LENGTH)
|
|
163
|
+
|
|
164
|
+
return `${CACHE_PREFIX}${digest}-`
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function probe_arguments(group: ProbeGroup, project_root: string): Array<string> {
|
|
168
|
+
return [
|
|
169
|
+
...FORMAT_FLAGS,
|
|
170
|
+
RULE_FLAG,
|
|
171
|
+
probe_rule(group.options),
|
|
172
|
+
CACHE_LOCATION_FLAG,
|
|
173
|
+
stamp_file.stamp_path(cache_prefix(group.key), project_root),
|
|
174
|
+
...group.paths,
|
|
175
|
+
]
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// The project's own eslint, through its own shim when there is one and `pnpm exec` when there is not
|
|
179
|
+
// — the same two routes every other command in this package reaches a local binary by. The lookup
|
|
180
|
+
// **walks up** from the given directory, because pnpm does: resolving only the directory the command
|
|
181
|
+
// was invoked in would disagree with the very binary it spawns, which is joshuafolkken/kit#934 and the
|
|
182
|
+
// reason `local-bin.ts` ships this variant.
|
|
183
|
+
function probe_command(project_root: string, probe_args: ReadonlyArray<string>): Array<string> {
|
|
184
|
+
const shim = find_local_bin_upwards(project_root, ESLINT_BIN)
|
|
185
|
+
|
|
186
|
+
return shim === undefined ? [PNPM, PNPM_EXEC, ESLINT_BIN, ...probe_args] : [shim, ...probe_args]
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// `execa` directly rather than through `buffered-process.ts`: that helper merges stderr into stdout
|
|
190
|
+
// and forces color, both of which a JSON reader cannot use.
|
|
191
|
+
async function run_probe(group: ProbeGroup, project_root: string): Promise<string | undefined> {
|
|
192
|
+
const [bin, ...command_arguments] = probe_command(
|
|
193
|
+
project_root,
|
|
194
|
+
probe_arguments(group, project_root),
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
try {
|
|
198
|
+
const result = await execa(bin ?? PNPM, command_arguments, {
|
|
199
|
+
cwd: project_root,
|
|
200
|
+
reject: false,
|
|
201
|
+
stdout: 'pipe',
|
|
202
|
+
stderr: 'ignore',
|
|
203
|
+
timeout: PROCESS_TIMEOUT_MS,
|
|
204
|
+
})
|
|
205
|
+
|
|
206
|
+
return result.stdout
|
|
207
|
+
} catch {
|
|
208
|
+
return undefined
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function count_in_message(message: string): number | undefined {
|
|
213
|
+
const raw = COUNT_PATTERN.exec(message)?.[COUNT_GROUP]
|
|
214
|
+
|
|
215
|
+
return raw === undefined ? undefined : Number(raw)
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function count_in(messages: ReadonlyArray<z.infer<typeof message_schema>>): number | undefined {
|
|
219
|
+
const reported = messages.find((message) => message.ruleId === MAX_LINES_RULE)
|
|
220
|
+
|
|
221
|
+
return reported === undefined ? undefined : count_in_message(reported.message)
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// **No `max-lines` message is two different answers, and they must not be merged.** A file eslint
|
|
225
|
+
// refused — ignored, covered by no configuration, unparseable — carries a message with no `ruleId`,
|
|
226
|
+
// and that one has no count. A file eslint linted and this rule did not fire on has exactly 0 code
|
|
227
|
+
// lines, which is a number and is reported as one.
|
|
228
|
+
function count_or_zero(
|
|
229
|
+
messages: ReadonlyArray<z.infer<typeof message_schema>>,
|
|
230
|
+
): number | undefined {
|
|
231
|
+
const counted = count_in(messages)
|
|
232
|
+
|
|
233
|
+
if (counted !== undefined) return counted
|
|
234
|
+
|
|
235
|
+
const is_refused = messages.some((message) => message.ruleId === null)
|
|
236
|
+
|
|
237
|
+
return is_refused ? undefined : NO_CODE_LINES
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Keyed by the absolute path eslint reports, so the caller's spelling of a path does not have to
|
|
241
|
+
// match it. A path eslint refused is simply absent, and the caller reports that rather than a number.
|
|
242
|
+
function counts_in(raw_output: string | undefined): ReadonlyMap<string, number> {
|
|
243
|
+
const counts = new Map<string, number>()
|
|
244
|
+
const parsed = results_schema.safeParse(JSON.parse(raw_output ?? 'null'))
|
|
245
|
+
|
|
246
|
+
if (!parsed.success) return counts
|
|
247
|
+
|
|
248
|
+
for (const result of parsed.data) {
|
|
249
|
+
const code_lines = count_or_zero(result.messages)
|
|
250
|
+
|
|
251
|
+
if (code_lines !== undefined) counts.set(path.resolve(result.filePath), code_lines)
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
return counts
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// The safe entry point, and the only one exported: eslint's output can be empty or truncated, and
|
|
258
|
+
// `JSON.parse` throws on both.
|
|
259
|
+
function parse_counts(raw_output: string | undefined): ReadonlyMap<string, number> {
|
|
260
|
+
try {
|
|
261
|
+
return counts_in(raw_output)
|
|
262
|
+
} catch {
|
|
263
|
+
return new Map<string, number>()
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// **Only regular files are passed to eslint, and this is not tidiness.** One argument eslint cannot
|
|
268
|
+
// match — a path that is gone, or a directory whose every entry is ignored — makes it exit with no
|
|
269
|
+
// JSON at all, and because this sends every path in one run to keep the cost at one process start,
|
|
270
|
+
// that single bad argument would leave every *other* path unanswered.
|
|
271
|
+
// `throwIfNoEntry: false` covers a path that is not there and nothing else — an unreadable parent
|
|
272
|
+
// directory raises `EACCES`, which would leave this call with no answer at all rather than one bad
|
|
273
|
+
// row, taking every other path in the same invocation with it.
|
|
274
|
+
function is_lintable_path(file_path: string): boolean {
|
|
275
|
+
try {
|
|
276
|
+
return statSync(file_path, { throwIfNoEntry: false })?.isFile() === true
|
|
277
|
+
} catch {
|
|
278
|
+
return false
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
function lintable_paths(file_paths: ReadonlyArray<string>): ReadonlyArray<string> {
|
|
283
|
+
return file_paths.filter((file_path) => is_lintable_path(file_path))
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// One eslint run per *distinct counting method*, rather than one per path. The cost of this report is
|
|
287
|
+
// a process start, so the number of paths is the one thing that must not multiply it — and the number
|
|
288
|
+
// of distinct `max-lines` option sets in one project is one, in every configuration that does not
|
|
289
|
+
// deliberately count two groups of files differently (joshuafolkken/kit#1454).
|
|
290
|
+
// The keys are sorted before they are written out, so two config blocks that state the same options in
|
|
291
|
+
// a different order are one group rather than two. Unsorted, a purely cosmetic difference would split
|
|
292
|
+
// the probe in two and cost a second eslint process for nothing.
|
|
293
|
+
function options_key(options: LineRuleOptions): string {
|
|
294
|
+
return JSON.stringify(
|
|
295
|
+
options,
|
|
296
|
+
Object.keys(options).toSorted((left, right) => left.localeCompare(right)),
|
|
297
|
+
)
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
function grouped(
|
|
301
|
+
options_by_path: ReadonlyMap<string, LineRuleOptions>,
|
|
302
|
+
): ReadonlyMap<string, ProbeGroup> {
|
|
303
|
+
const groups = new Map<string, ProbeGroup>()
|
|
304
|
+
|
|
305
|
+
for (const [file_path, options] of options_by_path) {
|
|
306
|
+
const key = options_key(options)
|
|
307
|
+
const group = groups.get(key) ?? { key, options, paths: [] }
|
|
308
|
+
|
|
309
|
+
group.paths.push(file_path)
|
|
310
|
+
groups.set(key, group)
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
return groups
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
async function counts_for(
|
|
317
|
+
options_by_path: ReadonlyMap<string, LineRuleOptions>,
|
|
318
|
+
project_root: string,
|
|
319
|
+
): Promise<ReadonlyMap<string, number>> {
|
|
320
|
+
const groups: Array<ProbeGroup> = []
|
|
321
|
+
|
|
322
|
+
for (const [, group] of grouped(options_by_path)) groups.push(group)
|
|
323
|
+
|
|
324
|
+
const outputs = await Promise.all(
|
|
325
|
+
groups.map(async (group) => await run_probe(group, project_root)),
|
|
326
|
+
)
|
|
327
|
+
const counts = new Map<string, number>()
|
|
328
|
+
|
|
329
|
+
for (const output of outputs) {
|
|
330
|
+
for (const [file_path, code_lines] of parse_counts(output)) counts.set(file_path, code_lines)
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
return counts
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
function budget_for(
|
|
337
|
+
code_lines: number | undefined,
|
|
338
|
+
limit: number | undefined,
|
|
339
|
+
): LineBudget | undefined {
|
|
340
|
+
if (code_lines === undefined || limit === undefined) return undefined
|
|
341
|
+
|
|
342
|
+
return budget_of(code_lines, limit)
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// A path is counted only where its limit is known, because a count with nothing to compare it against
|
|
346
|
+
// is reported as a bare number rather than as a budget — so probing it would buy nothing.
|
|
347
|
+
async function budgets_for(
|
|
348
|
+
file_paths: ReadonlyArray<string>,
|
|
349
|
+
project_root: string,
|
|
350
|
+
): Promise<ReadonlyArray<FileBudget>> {
|
|
351
|
+
const options = await effective_limit.options_for(lintable_paths(file_paths), project_root)
|
|
352
|
+
const counts = await counts_for(options, project_root)
|
|
353
|
+
|
|
354
|
+
return file_paths.map((file_path) => {
|
|
355
|
+
const resolved = path.resolve(file_path)
|
|
356
|
+
const code_lines = counts.get(resolved)
|
|
357
|
+
const limit = options.get(resolved)?.max
|
|
358
|
+
|
|
359
|
+
return { file_path, limit, budget: budget_for(code_lines, limit) }
|
|
360
|
+
})
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// `268/300 code lines (89%), 32 to spare` — the one phrasing every reader of this budget prints, so
|
|
364
|
+
// two of them can never describe the same file differently.
|
|
365
|
+
// The share is floored rather than rounded, so it cannot print a number the advice disagrees with:
|
|
366
|
+
// rounded, 254/300 reads `85%` while `near_limit_threshold` is 255 and no advice follows it — and the
|
|
367
|
+
// documentation tells the reader that 85% is where "near the limit" begins.
|
|
368
|
+
function describe(budget: LineBudget): string {
|
|
369
|
+
const share = Math.floor((budget.code_lines / budget.limit) * PERCENT)
|
|
370
|
+
const remaining =
|
|
371
|
+
budget.headroom < NO_HEADROOM
|
|
372
|
+
? `${String(-budget.headroom)} over`
|
|
373
|
+
: `${String(budget.headroom)} to spare`
|
|
374
|
+
const counted = `${String(budget.code_lines)}/${String(budget.limit)}`
|
|
375
|
+
|
|
376
|
+
return `${counted} code lines (${String(share)}%), ${remaining}`
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// What to do about it, and nothing when there is nothing to do. Over the limit the gate will report
|
|
380
|
+
// it anyway; near it, the decision is the one Step 0 is supposed to make before the writing starts.
|
|
381
|
+
function advice(budget: LineBudget): string | undefined {
|
|
382
|
+
if (budget.headroom < NO_HEADROOM) return 'over the limit: split it before the gate reports it'
|
|
383
|
+
if (!budget.is_near_limit) return undefined
|
|
384
|
+
|
|
385
|
+
return 'near the limit: declare the splitting plan in Step 0 before writing into it'
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
const line_budget = {
|
|
389
|
+
advice,
|
|
390
|
+
budget_of,
|
|
391
|
+
budgets_for,
|
|
392
|
+
describe,
|
|
393
|
+
is_lintable_path,
|
|
394
|
+
near_limit_percent,
|
|
395
|
+
near_limit_threshold,
|
|
396
|
+
parse_counts,
|
|
397
|
+
probe_arguments,
|
|
398
|
+
probe_command,
|
|
399
|
+
probe_rule,
|
|
400
|
+
NEAR_LIMIT_FRACTION,
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
export { line_budget }
|
|
404
|
+
export type { FileBudget, LineBudget }
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import path from 'node:path'
|
|
2
|
+
import { git_spawn } from '#scripts/git/git-spawn'
|
|
3
|
+
|
|
4
|
+
// The no-argument half of joshuafolkken/kit#1809. `josh lines <path>` answers for a file someone
|
|
5
|
+
// already named; a file near the limit that nobody has named yet is invisible until the gate reports
|
|
6
|
+
// it. This enumerates the repository's own lint-target files so the no-argument scan can report every
|
|
7
|
+
// one of them near the limit at once, before the first edit rather than after it.
|
|
8
|
+
//
|
|
9
|
+
// **The list is git's, not a filesystem walk, and it is not this file's own idea of a source file.**
|
|
10
|
+
// `git ls-files --cached --others --exclude-standard` is exactly what git would consider tracked plus
|
|
11
|
+
// what is new and not ignored — so a fresh file near the limit shows up and a build artifact under a
|
|
12
|
+
// gitignore does not, with no ignore parser of this module's own to drift from `.gitignore`. The
|
|
13
|
+
// extension filter is only a pre-filter that keeps the eslint probe from being handed thousands of
|
|
14
|
+
// non-source paths: whether a path actually has a `max-lines` budget is still `budgets_for`'s to
|
|
15
|
+
// decide from the project's own eslint, and a path with none is dropped from the report there.
|
|
16
|
+
|
|
17
|
+
const LINT_EXTENSIONS: ReadonlySet<string> = new Set([
|
|
18
|
+
'.ts',
|
|
19
|
+
'.tsx',
|
|
20
|
+
'.mts',
|
|
21
|
+
'.cts',
|
|
22
|
+
'.js',
|
|
23
|
+
'.jsx',
|
|
24
|
+
'.mjs',
|
|
25
|
+
'.cjs',
|
|
26
|
+
'.svelte',
|
|
27
|
+
])
|
|
28
|
+
|
|
29
|
+
// `--full-name` and the `:/` pathspec print repository-root-relative paths for the whole tree
|
|
30
|
+
// wherever the command runs, matching the spelling every other reading in this package resolves
|
|
31
|
+
// against the root; `-z` separates them with NUL so a path with an unusual character is never quoted
|
|
32
|
+
// or escaped, which removes any need for `core.quotePath=false`.
|
|
33
|
+
const WHOLE_TREE_PATHSPEC = ':/'
|
|
34
|
+
const LS_FILES_FLAGS: ReadonlyArray<string> = [
|
|
35
|
+
'ls-files',
|
|
36
|
+
'--cached',
|
|
37
|
+
'--others',
|
|
38
|
+
'--exclude-standard',
|
|
39
|
+
'--full-name',
|
|
40
|
+
'-z',
|
|
41
|
+
]
|
|
42
|
+
const NUL = '\0'
|
|
43
|
+
// `--show-toplevel` prints the absolute repository (or worktree) root from anywhere inside it, so the
|
|
44
|
+
// root-relative names `--full-name` returns resolve to the right absolute paths wherever the command
|
|
45
|
+
// was invoked.
|
|
46
|
+
const SHOW_TOPLEVEL: ReadonlyArray<string> = ['rev-parse', '--show-toplevel']
|
|
47
|
+
|
|
48
|
+
function is_lint_target(relative_path: string): boolean {
|
|
49
|
+
return LINT_EXTENSIONS.has(path.extname(relative_path))
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function split_names(output: string): ReadonlyArray<string> {
|
|
53
|
+
return output.split(NUL).filter((name) => name.length > 0)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// `git_spawn.read` is the one place ordinary git commands are spawned from, so this reuses it rather
|
|
57
|
+
// than growing a second spawn site (joshuafolkken/kit#1640).
|
|
58
|
+
async function repo_root(): Promise<string> {
|
|
59
|
+
return await git_spawn.read([...SHOW_TOPLEVEL])
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// The names resolve against the repository `root`, never the process cwd: `--full-name` prints them
|
|
63
|
+
// relative to the root wherever the command runs, so resolving against cwd would double the prefix
|
|
64
|
+
// and drop every file when the command is invoked from a subdirectory.
|
|
65
|
+
async function lint_target_files(root: string): Promise<ReadonlyArray<string>> {
|
|
66
|
+
const output = await git_spawn.read([...LS_FILES_FLAGS, WHOLE_TREE_PATHSPEC])
|
|
67
|
+
|
|
68
|
+
return split_names(output)
|
|
69
|
+
.filter((name) => is_lint_target(name))
|
|
70
|
+
.map((name) => path.resolve(root, name))
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const line_targets = {
|
|
74
|
+
is_lint_target,
|
|
75
|
+
lint_target_files,
|
|
76
|
+
repo_root,
|
|
77
|
+
split_names,
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export { line_targets }
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
import { fileURLToPath } from 'node:url'
|
|
4
|
+
import { line_budget, type FileBudget, type LineBudget } from './line-budget'
|
|
5
|
+
import { line_targets } from './line-targets'
|
|
6
|
+
|
|
7
|
+
// `josh lines` — the ask-before-writing half of joshuafolkken/kit#1425. `pnpm josh lint` reports the
|
|
8
|
+
// file line limit only once it has been broken, and by then the writing is finished and the splitting
|
|
9
|
+
// that follows is rework. This answers the same question before the first edit: how many code lines
|
|
10
|
+
// each target file already has, and how many are left.
|
|
11
|
+
//
|
|
12
|
+
// **It reports and never fails.** The limit is lint's to enforce, and a second command exiting
|
|
13
|
+
// non-zero on the same condition would be a second enforcement point for it — which is how a headroom
|
|
14
|
+
// report turns into a way to reinterpret the gate. A non-zero exit here means the arguments were
|
|
15
|
+
// unusable, never that a file is large.
|
|
16
|
+
|
|
17
|
+
const ARGV_START = 2
|
|
18
|
+
const ROW_GAP = ' '
|
|
19
|
+
// The no-argument scan's answer when nothing is near the limit — a defined "none" rather than a
|
|
20
|
+
// failure, so an empty result reads as "the repository is clear" instead of "the command broke".
|
|
21
|
+
const NONE_NEAR = 'no files near the limit'
|
|
22
|
+
|
|
23
|
+
// Why a path carries no number, said in the row rather than left blank — a blank would read as zero
|
|
24
|
+
// code lines, which is the one answer this command must never appear to give.
|
|
25
|
+
//
|
|
26
|
+
// **Three reasons, and none claims more than it knows.** A path that is not a regular file — a typo,
|
|
27
|
+
// or a directory — is never sent to eslint at all, so quoting eslint's verdict for it would answer a
|
|
28
|
+
// question nobody asked, and a reader would take a typo for a real file eslint declined to count. A
|
|
29
|
+
// path this project sets no `max-lines` on has nothing to be counted *against*, which is `NO_LIMIT`
|
|
30
|
+
// below. The last covers everything that reached the probe without coming back with a number: a path
|
|
31
|
+
// eslint ignores, one no configuration covers, one it could not parse, and a probe that could not run
|
|
32
|
+
// at all. It deliberately does not name eslint, because the last of those is not eslint's doing.
|
|
33
|
+
const NOT_A_FILE = 'not counted: not a regular file'
|
|
34
|
+
const NOT_COUNTED = 'not counted: no line count for this path'
|
|
35
|
+
// The third reason, and the one that replaced a wrong number (joshuafolkken/kit#1454). This project's
|
|
36
|
+
// eslint enforces no `max-lines` here, so there is nothing to report a budget against — and the
|
|
37
|
+
// alternative to saying so is quoting kit's limit for someone else's project, which is the defect. It
|
|
38
|
+
// names no cause because there are several: the rule is turned off for this path, no configuration
|
|
39
|
+
// covers it with a `max`, or the project's eslint could not be loaded at all. The row would otherwise
|
|
40
|
+
// assert whichever of them it guessed.
|
|
41
|
+
const NO_LIMIT = 'not counted: no max-lines limit for this path'
|
|
42
|
+
|
|
43
|
+
function not_counted_reason(entry: FileBudget): string {
|
|
44
|
+
if (!line_budget.is_lintable_path(entry.file_path)) return NOT_A_FILE
|
|
45
|
+
|
|
46
|
+
return entry.limit === undefined ? NO_LIMIT : NOT_COUNTED
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function budgeted(budget: NonNullable<FileBudget['budget']>): string {
|
|
50
|
+
const note = line_budget.advice(budget)
|
|
51
|
+
const suffix = note === undefined ? '' : ` — ${note}`
|
|
52
|
+
|
|
53
|
+
return `${line_budget.describe(budget)}${suffix}`
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function row(relative_path: string, entry: FileBudget): string {
|
|
57
|
+
const body = entry.budget === undefined ? not_counted_reason(entry) : budgeted(entry.budget)
|
|
58
|
+
|
|
59
|
+
return `${relative_path}${ROW_GAP}${body}`
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// The threshold is printed with the rows rather than left implicit: a reader who sees "near the limit"
|
|
63
|
+
// on one file and nothing on the next needs the boundary to know which side a third one is on.
|
|
64
|
+
//
|
|
65
|
+
// **It is read off the budgets rather than from a limit of this command's own** (joshuafolkken/kit#1454).
|
|
66
|
+
// Each file's limit is whatever that project's eslint enforces for it, so there is a line count to
|
|
67
|
+
// print here only where every counted file agrees on one; where they do not — or where none was
|
|
68
|
+
// resolved — the boundary is stated as the share it has always been, and each row carries its own
|
|
69
|
+
// limit beside its own percentage.
|
|
70
|
+
function header(budgets: ReadonlyArray<FileBudget>): string {
|
|
71
|
+
const limits = [...new Set(budgets.map((entry) => entry.limit))].filter(
|
|
72
|
+
(limit) => limit !== undefined,
|
|
73
|
+
)
|
|
74
|
+
const [only] = limits
|
|
75
|
+
|
|
76
|
+
if (only === undefined || limits.length !== 1) {
|
|
77
|
+
return `near from ${String(line_budget.near_limit_percent())}% of each file's own limit`
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return `limit ${String(only)} code lines · near from ${String(line_budget.near_limit_threshold(only))}`
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function rows_for(budgets: ReadonlyArray<FileBudget>, project_root: string): ReadonlyArray<string> {
|
|
84
|
+
return budgets.map((entry) => row(path.relative(project_root, entry.file_path), entry))
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// A budget that reached the "near the limit" threshold, narrowed so the sort below can read
|
|
88
|
+
// `headroom` without a non-null assertion — the filter is what proves `budget` is present.
|
|
89
|
+
function is_near(entry: FileBudget): entry is FileBudget & { budget: LineBudget } {
|
|
90
|
+
return entry.budget?.is_near_limit === true
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// The no-argument scan reports only what is near the limit, least headroom first, so an over-limit
|
|
94
|
+
// file — negative headroom — sorts ahead of one that merely has little room left.
|
|
95
|
+
function near_limit_budgets(budgets: ReadonlyArray<FileBudget>): ReadonlyArray<FileBudget> {
|
|
96
|
+
return budgets
|
|
97
|
+
.filter(is_near)
|
|
98
|
+
.toSorted((left, right) => left.budget.headroom - right.budget.headroom)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
async function scan_budgets(root: string): Promise<ReadonlyArray<FileBudget>> {
|
|
102
|
+
const targets = await line_targets.lint_target_files(root)
|
|
103
|
+
const budgets = await line_budget.budgets_for(targets, root)
|
|
104
|
+
|
|
105
|
+
return near_limit_budgets(budgets)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async function argument_budgets(
|
|
109
|
+
command_arguments: ReadonlyArray<string>,
|
|
110
|
+
project_root: string,
|
|
111
|
+
): Promise<ReadonlyArray<FileBudget>> {
|
|
112
|
+
const targets = command_arguments.map((argument) => path.resolve(project_root, argument))
|
|
113
|
+
|
|
114
|
+
return await line_budget.budgets_for(targets, project_root)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Only the scan can be empty — a path argument always yields a row, even a "not counted" one — so the
|
|
118
|
+
// none-line is the scan's defined answer and never a path run's.
|
|
119
|
+
function render(budgets: ReadonlyArray<FileBudget>, project_root: string): string {
|
|
120
|
+
if (budgets.length === 0) return NONE_NEAR
|
|
121
|
+
|
|
122
|
+
return [header(budgets), ...rows_for(budgets, project_root)].join('\n')
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// The scan resolves the repository root first — `budgets_for` and the row display both key off it — so
|
|
126
|
+
// a run started from a subdirectory reports the same files as one started from the root.
|
|
127
|
+
async function run_scan(): Promise<number> {
|
|
128
|
+
const root = await line_targets.repo_root()
|
|
129
|
+
const budgets = await scan_budgets(root)
|
|
130
|
+
|
|
131
|
+
process.stdout.write(`${render(budgets, root)}\n`)
|
|
132
|
+
|
|
133
|
+
return 0
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
async function run_arguments(
|
|
137
|
+
command_arguments: ReadonlyArray<string>,
|
|
138
|
+
project_root: string,
|
|
139
|
+
): Promise<number> {
|
|
140
|
+
const budgets = await argument_budgets(command_arguments, project_root)
|
|
141
|
+
|
|
142
|
+
process.stdout.write(`${render(budgets, project_root)}\n`)
|
|
143
|
+
|
|
144
|
+
return 0
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
async function run_lines(
|
|
148
|
+
command_arguments: ReadonlyArray<string>,
|
|
149
|
+
project_root: string,
|
|
150
|
+
): Promise<number> {
|
|
151
|
+
return command_arguments.length === 0
|
|
152
|
+
? await run_scan()
|
|
153
|
+
: await run_arguments(command_arguments, project_root)
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (process.argv[1] === fileURLToPath(import.meta.url)) {
|
|
157
|
+
process.exitCode = await run_lines(process.argv.slice(ARGV_START), process.cwd())
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const lines_command = {
|
|
161
|
+
header,
|
|
162
|
+
near_limit_budgets,
|
|
163
|
+
not_counted_reason,
|
|
164
|
+
render,
|
|
165
|
+
row,
|
|
166
|
+
rows_for,
|
|
167
|
+
run_lines,
|
|
168
|
+
NONE_NEAR,
|
|
169
|
+
NOT_A_FILE,
|
|
170
|
+
NO_LIMIT,
|
|
171
|
+
NOT_COUNTED,
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export { lines_command }
|