@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,510 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
import { existsSync } from 'node:fs'
|
|
3
|
+
import path from 'node:path'
|
|
4
|
+
import { text } from 'node:stream/consumers'
|
|
5
|
+
import { fileURLToPath } from 'node:url'
|
|
6
|
+
import { resolve_local_bin, resolve_package_bin } from '#scripts/build/local-bin'
|
|
7
|
+
import { ESLINT_EDIT_CACHE_FLAGS } from '#scripts/josh/josh-command-types'
|
|
8
|
+
import { time_density_hook } from '#scripts/time-runtime/time-density-hook'
|
|
9
|
+
import { execa } from 'execa'
|
|
10
|
+
import { z } from 'zod'
|
|
11
|
+
import { edited_cspell } from './edited-cspell'
|
|
12
|
+
import { rewrite_notice } from './format-rewrite-notice'
|
|
13
|
+
|
|
14
|
+
// Claude Code hands a `PostToolUse` hook the tool call as JSON on stdin; for `Edit` and `Write` the
|
|
15
|
+
// edited path is `tool_input.file_path`. Everything else in the payload is ignored, and a payload
|
|
16
|
+
// that does not carry a path is a no-op rather than an error — this hook runs after the edit has
|
|
17
|
+
// already been applied and must never turn a successful edit into a failure.
|
|
18
|
+
const hook_payload_schema = z.object({
|
|
19
|
+
tool_input: z.object({ file_path: z.string().min(1) }).optional(),
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
// What prettier is asked to write. Kept explicit rather than deferring to `--ignore-unknown` alone
|
|
23
|
+
// so the hook's cost is bounded by a list that can be read, and so a path this project has no
|
|
24
|
+
// opinion about never spawns a process at all.
|
|
25
|
+
const PRETTIER_EXTENSIONS = new Set([
|
|
26
|
+
'.ts',
|
|
27
|
+
'.tsx',
|
|
28
|
+
'.js',
|
|
29
|
+
'.jsx',
|
|
30
|
+
'.mjs',
|
|
31
|
+
'.cjs',
|
|
32
|
+
'.svelte',
|
|
33
|
+
'.json',
|
|
34
|
+
'.jsonc',
|
|
35
|
+
'.md',
|
|
36
|
+
'.yml',
|
|
37
|
+
'.yaml',
|
|
38
|
+
'.css',
|
|
39
|
+
'.html',
|
|
40
|
+
])
|
|
41
|
+
|
|
42
|
+
// eslint only runs where the config has rules to apply. A `--fix` pass on a `.md` or `.yml` file
|
|
43
|
+
// costs a process start to do nothing.
|
|
44
|
+
const ESLINT_EXTENSIONS = new Set(['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs', '.svelte'])
|
|
45
|
+
|
|
46
|
+
// Never this project's to format, however the edit reached them. Split in two because depth means
|
|
47
|
+
// different things: an installed package or a git internal is off-limits wherever it sits, while
|
|
48
|
+
// `dist` and `build` name build output only at the top level — `src/routes/build/+page.ts` is
|
|
49
|
+
// ordinary source, and excluding it by name would switch the hook off for a real part of the tree.
|
|
50
|
+
const EXCLUDED_ANYWHERE = new Set(['node_modules', '.git'])
|
|
51
|
+
const EXCLUDED_AT_ROOT = new Set(['dist', 'build'])
|
|
52
|
+
const PARENT_SEGMENT = '..'
|
|
53
|
+
|
|
54
|
+
// The shims under `node_modules/.bin` are spawned directly rather than through `pnpm exec`. This
|
|
55
|
+
// runs on every edit, and each `pnpm exec` is another process start on a chain that already holds
|
|
56
|
+
// `pnpm josh` and tsx — the two saved are the ones this file controls.
|
|
57
|
+
const PNPM = 'pnpm'
|
|
58
|
+
const PRETTIER_BIN = 'prettier'
|
|
59
|
+
const PRETTIER_ARGUMENTS: ReadonlyArray<string> = ['--write', '--ignore-unknown']
|
|
60
|
+
// `--no-error-on-unmatched-pattern` covers a file the eslint config does not cover: the hook has
|
|
61
|
+
// nothing to say about it, and a non-zero exit here would be reported as a failed hook.
|
|
62
|
+
//
|
|
63
|
+
// The cache flags are not here to make the hook faster — they are here to stop it destroying the
|
|
64
|
+
// gate's cache (joshuafolkken/kit#1332). ESLint started *without* `--cache` deletes the file at
|
|
65
|
+
// `--cache-location`, so this hook wiped `.eslintcache` on every edit and the gate's lint ran cold
|
|
66
|
+
// every time. Passing them points that deletion, and the hook's own reads and writes, at a location
|
|
67
|
+
// of its own — its own rather than the gate's because the two run concurrently, and each eslint run
|
|
68
|
+
// rewrites its cache file whole from the copy it loaded at start-up. `ESLINT_EDIT_CACHE_FLAGS` is
|
|
69
|
+
// single-sourced beside the gate's so the two locations cannot drift into being the same file.
|
|
70
|
+
const ESLINT_BIN = 'eslint'
|
|
71
|
+
const ESLINT_ARGUMENTS: ReadonlyArray<string> = [
|
|
72
|
+
'--fix',
|
|
73
|
+
'--no-error-on-unmatched-pattern',
|
|
74
|
+
...ESLINT_EDIT_CACHE_FLAGS,
|
|
75
|
+
]
|
|
76
|
+
// eslint is what this hook spends its time on, and almost none of it is the file: measured on this
|
|
77
|
+
// repository, one `eslint --fix` on a single TypeScript file takes 1.70s of a 2.50s hook, and a
|
|
78
|
+
// second lint inside the same process takes 0.13s. The 1.6s difference is the flat config, its
|
|
79
|
+
// plugins and the type-aware program, rebuilt from nothing on every edit. `eslint_d` keeps one warm
|
|
80
|
+
// eslint — the *project's* own eslint, held to that by `ESLINT_D_MISS=fail` below rather than by
|
|
81
|
+
// hope — behind a socket and forwards the same arguments to it, which is why the fixed output is
|
|
82
|
+
// identical rather than merely similar. The config entry file is re-read per request; the modules it
|
|
83
|
+
// imports are not, which `plan_daemon_restart` below is the answer to. The daemon exits after 15
|
|
84
|
+
// minutes of inactivity (joshuafolkken/kit#1259).
|
|
85
|
+
const ESLINT_DAEMON = 'eslint_d'
|
|
86
|
+
const DAEMON_RESTART = 'restart'
|
|
87
|
+
// The two shapes a flat config is built from here and in every consumer of this kit: the root
|
|
88
|
+
// `eslint.config.*` entry, and the rule modules under `eslint/` that it imports.
|
|
89
|
+
const ESLINT_CONFIG_DIR = 'eslint'
|
|
90
|
+
const ESLINT_CONFIG_ENTRY = /^eslint\.config\.[cm]?[jt]s$/u
|
|
91
|
+
// A formatter that hangs would hold the edit's turn open, so each spawn is bounded. The bound has
|
|
92
|
+
// to be read against the *worst-case run* rather than one spawn: an edit to a config input plans
|
|
93
|
+
// eslint, prettier and `eslint_d restart`, and the first and last each have a second route behind
|
|
94
|
+
// the daemon — five spawns. The hook entry in `.claude/settings.json` declares 90 seconds, so the
|
|
95
|
+
// per-spawn bound must leave five of them under it, or the harness kill lands first and lands at a
|
|
96
|
+
// moment this file did not choose — possibly inside `prettier --write`, which rewrites in place and
|
|
97
|
+
// can leave the file truncated. 15s × 5 = 75s. It is still two orders of magnitude beyond the 0.84s
|
|
98
|
+
// a warm run takes, so reaching it means something is already wrong.
|
|
99
|
+
const PROCESS_TIMEOUT_MS = 15_000
|
|
100
|
+
|
|
101
|
+
// The problems eslint could not auto-fix are handed to the model verbatim from eslint's own stdout —
|
|
102
|
+
// its default formatter already prints the file, the `line:col`, and the rule name the issue asks
|
|
103
|
+
// for (joshuafolkken/kit#2275). A header names what the block is, since additionalContext arrives
|
|
104
|
+
// with no framing of its own.
|
|
105
|
+
const DIAGNOSTIC_HEADER =
|
|
106
|
+
'The edit hook could not auto-fix these lint problems; address them now rather than at the gate:'
|
|
107
|
+
// additionalContext rides back on an edit, so an unbounded lint dump would balloon the run's
|
|
108
|
+
// context. Past this many characters the block is cut and marked. One place, so the bound is read
|
|
109
|
+
// rather than guessed.
|
|
110
|
+
const MAX_DIAGNOSTIC_CHARS = 4000
|
|
111
|
+
const DIAGNOSTIC_TRUNCATION_NOTICE = '\n…(diagnostics truncated)'
|
|
112
|
+
// The density line first, then the lint problems, with a blank line between them when both are
|
|
113
|
+
// present.
|
|
114
|
+
const SECTION_SEPARATOR = '\n\n'
|
|
115
|
+
|
|
116
|
+
// Where this file sits inside the kit package. `eslint_d` is kit's dependency rather than the
|
|
117
|
+
// consumer's, and pnpm writes a `node_modules/.bin` shim only for a project's *direct* dependencies,
|
|
118
|
+
// so a consumer's project root cannot see it and this directory can.
|
|
119
|
+
const MODULE_DIRECTORY = path.dirname(fileURLToPath(import.meta.url))
|
|
120
|
+
|
|
121
|
+
interface FormatCommand {
|
|
122
|
+
bin: string
|
|
123
|
+
command_arguments: ReadonlyArray<string>
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// The three ways this hook can reach a formatter, fastest first — a warm daemon, the project's own
|
|
127
|
+
// shim, then `pnpm exec`. Each later route exists because the one before it can be absent, so a
|
|
128
|
+
// project without the daemon behaves exactly as it did before it was introduced. Both fields are
|
|
129
|
+
// declared rather than optional: `exactOptionalPropertyTypes` makes an absent key and an explicit
|
|
130
|
+
// `undefined` different types, and every caller here computes the value rather than omitting it.
|
|
131
|
+
interface BinRoutes {
|
|
132
|
+
daemon_cli: string | undefined
|
|
133
|
+
shim: string | undefined
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// What one spawn answered. The exit code alone cannot say whether a formatter ran, because
|
|
137
|
+
// `eslint --fix` exits non-zero whenever something it could not fix remains — its ordinary outcome
|
|
138
|
+
// on a half-written file. The stdout the spawn captured is what separates the two: eslint prints the
|
|
139
|
+
// problems it is exiting non-zero about, while a daemon that could not start prints its reason to
|
|
140
|
+
// stderr and leaves stdout empty. It is kept whole rather than reduced to a boolean because the
|
|
141
|
+
// problems eslint could not fix are reported to the model from it (joshuafolkken/kit#2275).
|
|
142
|
+
interface CommandOutcome {
|
|
143
|
+
exit_code: number
|
|
144
|
+
stdout: string
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
type CommandRunner = (command: FormatCommand, project_root: string) => Promise<CommandOutcome>
|
|
148
|
+
|
|
149
|
+
function parse_edited_path(raw_payload: string): string | undefined {
|
|
150
|
+
try {
|
|
151
|
+
const result = hook_payload_schema.safeParse(JSON.parse(raw_payload))
|
|
152
|
+
|
|
153
|
+
return result.success ? result.data.tool_input?.file_path : undefined
|
|
154
|
+
} catch {
|
|
155
|
+
return undefined
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Read against the path relative to the project root, never the absolute one: a checkout that lives
|
|
160
|
+
// under a directory called `build` or `dist` would otherwise have the hook silently switched off for
|
|
161
|
+
// every file in it.
|
|
162
|
+
function is_excluded(relative_path: string): boolean {
|
|
163
|
+
const segments = relative_path.split(path.sep)
|
|
164
|
+
|
|
165
|
+
return (
|
|
166
|
+
segments.some((segment) => EXCLUDED_ANYWHERE.has(segment)) ||
|
|
167
|
+
EXCLUDED_AT_ROOT.has(segments[0] ?? '')
|
|
168
|
+
)
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Claude Code runs a hook from the project directory, and this project's prettier and eslint config
|
|
172
|
+
// is the only config the hook has. An edit can still land outside that tree — a session may carry
|
|
173
|
+
// additional working directories, and paths in another checkout or a home-directory config file are
|
|
174
|
+
// governed by their own rules — so a path that is not under the root is left alone rather than
|
|
175
|
+
// rewritten to kit's taste.
|
|
176
|
+
// Returns the path relative to the root, or nothing when the file is not under it. The first
|
|
177
|
+
// segment is compared to `..` rather than tested as a prefix: `..config.ts` is a file in the root,
|
|
178
|
+
// not a step above it.
|
|
179
|
+
function relative_to_root(project_root: string, file_path: string): string | undefined {
|
|
180
|
+
const relative = path.relative(path.resolve(project_root), path.resolve(file_path))
|
|
181
|
+
const is_inside_root =
|
|
182
|
+
relative !== '' && relative.split(path.sep)[0] !== PARENT_SEGMENT && !path.isAbsolute(relative)
|
|
183
|
+
|
|
184
|
+
return is_inside_root ? relative : undefined
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// One question, asked before any list is built: is this a file this project formats at all?
|
|
188
|
+
function is_formattable(file_path: string, project_root: string): boolean {
|
|
189
|
+
const relative = relative_to_root(project_root, file_path)
|
|
190
|
+
|
|
191
|
+
return relative !== undefined && !is_excluded(relative) && existsSync(file_path)
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Returns the commands to run, in order. eslint goes first and prettier last so prettier has the
|
|
195
|
+
// final word: an `--fix` that removes a now-unused disable directive leaves the whitespace behind
|
|
196
|
+
// it, and running in the other order shipped exactly that — a file the hook had just "formatted"
|
|
197
|
+
// that `prettier --check` then rejected. An empty list means the hook has nothing to do: the file is
|
|
198
|
+
// outside the project, gone by the time the hook ran, or of a kind nothing formats.
|
|
199
|
+
function plan_commands(file_path: string, project_root: string): ReadonlyArray<FormatCommand> {
|
|
200
|
+
if (!is_formattable(file_path, project_root)) return []
|
|
201
|
+
|
|
202
|
+
const extension = path.extname(file_path).toLowerCase()
|
|
203
|
+
const commands: Array<FormatCommand> = []
|
|
204
|
+
|
|
205
|
+
if (ESLINT_EXTENSIONS.has(extension)) {
|
|
206
|
+
commands.push({ bin: ESLINT_BIN, command_arguments: [...ESLINT_ARGUMENTS, file_path] })
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (PRETTIER_EXTENSIONS.has(extension)) {
|
|
210
|
+
commands.push({ bin: PRETTIER_BIN, command_arguments: [...PRETTIER_ARGUMENTS, file_path] })
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return commands
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// The daemon when it is installed, the local shim when it is there, `pnpm exec` when neither is. A
|
|
217
|
+
// workspace sub-package keeps its binaries somewhere other than the root's `node_modules/.bin`, and
|
|
218
|
+
// with output ignored a missing shim would otherwise make the hook a permanent silent no-op rather
|
|
219
|
+
// than a slower one. Kept pure and separate from the disk lookups so the choice itself is what the
|
|
220
|
+
// unit tests read.
|
|
221
|
+
function select_invocation(command: FormatCommand, routes: BinRoutes): FormatCommand {
|
|
222
|
+
if (routes.daemon_cli !== undefined) {
|
|
223
|
+
return {
|
|
224
|
+
bin: process.execPath,
|
|
225
|
+
command_arguments: [routes.daemon_cli, ...command.command_arguments],
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (routes.shim !== undefined) {
|
|
230
|
+
return { bin: routes.shim, command_arguments: command.command_arguments }
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return { bin: PNPM, command_arguments: ['exec', command.bin, ...command.command_arguments] }
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Only eslint has a daemon here. prettier costs 0.21s against eslint's 1.70s, so a second warm
|
|
237
|
+
// process would buy little and double what can go stale. `eslint_d` itself is in the set because the
|
|
238
|
+
// restart below is addressed to the daemon rather than to a formatter.
|
|
239
|
+
const DAEMON_BINS: ReadonlySet<string> = new Set([ESLINT_BIN, ESLINT_DAEMON])
|
|
240
|
+
|
|
241
|
+
function resolve_daemon_cli(bin: string, project_root: string): string | undefined {
|
|
242
|
+
if (!DAEMON_BINS.has(bin)) return undefined
|
|
243
|
+
|
|
244
|
+
return (
|
|
245
|
+
resolve_package_bin(MODULE_DIRECTORY, ESLINT_DAEMON, ESLINT_DAEMON) ??
|
|
246
|
+
resolve_package_bin(project_root, ESLINT_DAEMON, ESLINT_DAEMON)
|
|
247
|
+
)
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// Only the config *entry file* is re-read per request: ESLint cache-busts `eslint.config.js` by
|
|
251
|
+
// appending its mtime to the import URL, and the modules that file imports carry no such query, so a
|
|
252
|
+
// long-lived daemon keeps the rule modules it loaded first. Edit `eslint/rules/naming-convention.js`
|
|
253
|
+
// and then any source file, and it would be auto-fixed against the pre-edit rules for as long as the
|
|
254
|
+
// daemon lives — an author testing a rule change would read that as the rule being broken. Restarting
|
|
255
|
+
// after an edit to a config input is what makes the whole config current, not just its first file.
|
|
256
|
+
function is_eslint_config_input(relative_path: string): boolean {
|
|
257
|
+
return (
|
|
258
|
+
relative_path.split(path.sep)[0] === ESLINT_CONFIG_DIR ||
|
|
259
|
+
ESLINT_CONFIG_ENTRY.test(relative_path)
|
|
260
|
+
)
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
function plan_daemon_restart(
|
|
264
|
+
file_path: string,
|
|
265
|
+
project_root: string,
|
|
266
|
+
): ReadonlyArray<FormatCommand> {
|
|
267
|
+
const relative = relative_to_root(project_root, file_path)
|
|
268
|
+
|
|
269
|
+
if (relative === undefined || !is_eslint_config_input(relative)) return []
|
|
270
|
+
if (resolve_daemon_cli(ESLINT_DAEMON, project_root) === undefined) return []
|
|
271
|
+
|
|
272
|
+
return [{ bin: ESLINT_DAEMON, command_arguments: [DAEMON_RESTART] }]
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// The routes to try, fastest first. The second entry is the one that has always been here, and it
|
|
276
|
+
// is what a project with no daemon runs directly — resolving the daemon is not the same as it
|
|
277
|
+
// starting, so the slower route stays reachable rather than being replaced.
|
|
278
|
+
function resolve_invocations(
|
|
279
|
+
command: FormatCommand,
|
|
280
|
+
project_root: string,
|
|
281
|
+
): ReadonlyArray<FormatCommand> {
|
|
282
|
+
const shim = resolve_local_bin(project_root, command.bin)
|
|
283
|
+
const routes: BinRoutes = {
|
|
284
|
+
daemon_cli: resolve_daemon_cli(command.bin, project_root),
|
|
285
|
+
shim: existsSync(shim) ? shim : undefined,
|
|
286
|
+
}
|
|
287
|
+
const without_daemon = select_invocation(command, { ...routes, daemon_cli: undefined })
|
|
288
|
+
|
|
289
|
+
if (routes.daemon_cli === undefined) return [without_daemon]
|
|
290
|
+
|
|
291
|
+
return [select_invocation(command, routes), without_daemon]
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// A daemon that resolved on disk can still fail to start — a blocked loopback bind, a watch-limit
|
|
295
|
+
// refusal, a read-only store it cannot write its own config into — and it says so on stderr while
|
|
296
|
+
// exiting non-zero with nothing on stdout. `ESLINT_D_MISS=fail` below lands in the same shape.
|
|
297
|
+
// Without this the hook would silently stop fixing anything with eslint wherever the daemon cannot
|
|
298
|
+
// run, which is the "permanent silent no-op rather than a slower one" the shim fallback exists to
|
|
299
|
+
// prevent, reintroduced one level up.
|
|
300
|
+
function is_start_failure(outcome: CommandOutcome): boolean {
|
|
301
|
+
return outcome.exit_code !== 0 && outcome.stdout.length === 0
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// `cwd` is not decoration: the daemon runs each request under the cwd of the process that forwarded
|
|
305
|
+
// it, so it is what decides which eslint installation and which flat config answer.
|
|
306
|
+
// `ESLINT_D_MISS=fail` refuses the bundled eslint the daemon would otherwise fall back to when the
|
|
307
|
+
// project's own is not resolvable — the hook must format with the project's eslint or not at all,
|
|
308
|
+
// and a refusal here is a start failure, which the caller retries on the slower route.
|
|
309
|
+
async function spawn_invocation(
|
|
310
|
+
invocation: FormatCommand,
|
|
311
|
+
project_root: string,
|
|
312
|
+
): Promise<CommandOutcome> {
|
|
313
|
+
const result = await execa(invocation.bin, [...invocation.command_arguments], {
|
|
314
|
+
reject: false,
|
|
315
|
+
cwd: project_root,
|
|
316
|
+
env: { ESLINT_D_MISS: 'fail' },
|
|
317
|
+
stdout: 'pipe',
|
|
318
|
+
stderr: 'ignore',
|
|
319
|
+
timeout: PROCESS_TIMEOUT_MS,
|
|
320
|
+
})
|
|
321
|
+
|
|
322
|
+
return { exit_code: result.exitCode ?? 1, stdout: result.stdout }
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// One planned command, tried down its routes. A route is retried only when the one before it failed
|
|
326
|
+
// to start — never when the formatter itself reported problems, which is its normal way of exiting.
|
|
327
|
+
async function run_command(command: FormatCommand, project_root: string): Promise<CommandOutcome> {
|
|
328
|
+
let outcome: CommandOutcome = { exit_code: 0, stdout: '' }
|
|
329
|
+
|
|
330
|
+
for (const invocation of resolve_invocations(command, project_root)) {
|
|
331
|
+
outcome = await spawn_invocation(invocation, project_root)
|
|
332
|
+
if (!is_start_failure(outcome)) return outcome
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
return outcome
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// eslint's stdout is diagnostics only when eslint is the command and it exited non-zero with
|
|
339
|
+
// something to say. A start failure (non-zero, empty) has already been retried and carries no
|
|
340
|
+
// problems, and prettier's stdout is the list of files it wrote rather than anything to act on.
|
|
341
|
+
function eslint_unfixed(command: FormatCommand, outcome: CommandOutcome): string | undefined {
|
|
342
|
+
if (command.bin !== ESLINT_BIN) return undefined
|
|
343
|
+
if (outcome.exit_code === 0 || outcome.stdout.length === 0) return undefined
|
|
344
|
+
|
|
345
|
+
return outcome.stdout
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// The block the model reads: the header, then eslint's own output, cut to the bound so a large lint
|
|
349
|
+
// dump cannot balloon the run's context. `undefined` when eslint had nothing left unfixed, so the
|
|
350
|
+
// ordinary edit adds nothing to additionalContext.
|
|
351
|
+
function format_diagnostics(unfixed: string | undefined): string | undefined {
|
|
352
|
+
if (unfixed === undefined) return undefined
|
|
353
|
+
|
|
354
|
+
const is_over = unfixed.length > MAX_DIAGNOSTIC_CHARS
|
|
355
|
+
const body = is_over
|
|
356
|
+
? `${unfixed.slice(0, MAX_DIAGNOSTIC_CHARS)}${DIAGNOSTIC_TRUNCATION_NOTICE}`
|
|
357
|
+
: unfixed
|
|
358
|
+
|
|
359
|
+
return `${DIAGNOSTIC_HEADER}\n${body}`
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// The fixes eslint could apply are applied silently, as before; what it could not fix is returned so
|
|
363
|
+
// the model sees it on this edit rather than at the gate (joshuafolkken/kit#2275). A `PostToolUse`
|
|
364
|
+
// hook still reports no failure — the edit already landed, and returning the problems is not the same
|
|
365
|
+
// as failing the write.
|
|
366
|
+
// Runs the planned commands in order, returning the last unfixed eslint output. Empty until eslint
|
|
367
|
+
// reports something it could not fix; `eslint_unfixed` never returns an empty string, so '' stays the
|
|
368
|
+
// "nothing to report" sentinel.
|
|
369
|
+
async function collect_unfixed(
|
|
370
|
+
plan: ReadonlyArray<FormatCommand>,
|
|
371
|
+
runner: CommandRunner,
|
|
372
|
+
project_root: string,
|
|
373
|
+
): Promise<string> {
|
|
374
|
+
let unfixed = ''
|
|
375
|
+
|
|
376
|
+
for (const command of plan) {
|
|
377
|
+
try {
|
|
378
|
+
unfixed = eslint_unfixed(command, await runner(command, project_root)) ?? unfixed
|
|
379
|
+
} catch {
|
|
380
|
+
// One formatter failing to start is not a reason to skip the next: prettier runs last, and
|
|
381
|
+
// it is the one whose output the project's own lint step checks.
|
|
382
|
+
continue
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
return unfixed
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
async function format_edited_file(
|
|
390
|
+
raw_payload: string,
|
|
391
|
+
runner: CommandRunner,
|
|
392
|
+
project_root: string,
|
|
393
|
+
): Promise<string | undefined> {
|
|
394
|
+
const file_path = parse_edited_path(raw_payload)
|
|
395
|
+
|
|
396
|
+
if (file_path === undefined) return undefined
|
|
397
|
+
|
|
398
|
+
const plan = [
|
|
399
|
+
...plan_commands(file_path, project_root),
|
|
400
|
+
...plan_daemon_restart(file_path, project_root),
|
|
401
|
+
]
|
|
402
|
+
const unfixed = await collect_unfixed(plan, runner, project_root)
|
|
403
|
+
|
|
404
|
+
return format_diagnostics(unfixed === '' ? undefined : unfixed)
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// Provider adapters use the same live runner as the direct Claude hook without exporting that
|
|
408
|
+
// implementation detail or recreating its fallback sequence.
|
|
409
|
+
async function format_edited_payload(
|
|
410
|
+
raw_payload: string,
|
|
411
|
+
project_root: string,
|
|
412
|
+
): Promise<string | undefined> {
|
|
413
|
+
return await format_edited_file(raw_payload, run_command, project_root)
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// The one hook event this file is wired to, and the value the envelope below has to name.
|
|
417
|
+
const HOOK_EVENT_NAME = 'PostToolUse'
|
|
418
|
+
|
|
419
|
+
// The live round-trip density line, riding this hook rather than one of its own
|
|
420
|
+
// (joshuafolkken/kit#1329) — a `PostToolUse` matcher covering every tool would add a process start to
|
|
421
|
+
// all ~250 calls of a run.
|
|
422
|
+
//
|
|
423
|
+
// **A `PostToolUse` hook's plain stdout never reaches the model**; only `additionalContext` inside
|
|
424
|
+
// the documented envelope does, which is why the line cannot simply be printed. `undefined` when
|
|
425
|
+
// there is nothing to say, so the ordinary edit writes nothing at all to stdout and the payload the
|
|
426
|
+
// harness parses stays empty.
|
|
427
|
+
// Both the density line and eslint's unfixed problems reach the model the same way — as
|
|
428
|
+
// additionalContext on this one hook — and a `PostToolUse` hook's stdout carries a single envelope,
|
|
429
|
+
// so the two are joined into one rather than written twice: a second JSON object on stdout would
|
|
430
|
+
// leave the harness unable to parse either. No `permissionDecision` is ever set, so returning the
|
|
431
|
+
// problems does not turn the edit into a failure.
|
|
432
|
+
function build_envelope(additional_context: string): string {
|
|
433
|
+
return JSON.stringify({
|
|
434
|
+
hookSpecificOutput: { hookEventName: HOOK_EVENT_NAME, additionalContext: additional_context },
|
|
435
|
+
})
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
function density_envelope(raw_payload: string): string | undefined {
|
|
439
|
+
const notice = time_density_hook.density_notice(raw_payload)
|
|
440
|
+
|
|
441
|
+
return notice === undefined ? undefined : build_envelope(notice)
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
// The density line and the lint problems, joined when both are present. `undefined` when there is
|
|
445
|
+
// nothing to say, so the ordinary edit writes nothing at all to stdout.
|
|
446
|
+
function compose_context(
|
|
447
|
+
notice: string | undefined,
|
|
448
|
+
diagnostics: string | undefined,
|
|
449
|
+
): string | undefined {
|
|
450
|
+
const sections = [notice, diagnostics].filter(
|
|
451
|
+
(section): section is string => section !== undefined,
|
|
452
|
+
)
|
|
453
|
+
|
|
454
|
+
return sections.length === 0 ? undefined : sections.join(SECTION_SEPARATOR)
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// Run from a terminal there is no payload coming, and waiting for one looks like a hang.
|
|
458
|
+
function report_no_payload(): void {
|
|
459
|
+
process.stderr.write(
|
|
460
|
+
'format:edited reads a Claude Code PostToolUse payload on stdin; it is not run by hand.\n',
|
|
461
|
+
)
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
// The lint problems come from eslint and the unknown words from cspell, so both are known only once
|
|
465
|
+
// their processes have run; the density line is joined to them into the single envelope the harness
|
|
466
|
+
// can parse, rather than written first on its own. The rewrite notice is read from the file itself —
|
|
467
|
+
// its content before the formatters ran against its content after — so it too is known only once they
|
|
468
|
+
// have (joshuafolkken/kit#2314). The rewrite, lint and spell blocks are composed together first, then
|
|
469
|
+
// joined to the density line — one envelope, since a `PostToolUse` hook's stdout carries only one
|
|
470
|
+
// (joshuafolkken/kit#2296). A hook killed at its 15s timeout is the one case this loses the density
|
|
471
|
+
// line to — a run already gone pathologically wrong, per PROCESS_TIMEOUT_MS.
|
|
472
|
+
async function run_hook(payload: string): Promise<void> {
|
|
473
|
+
const notice = time_density_hook.density_notice(payload)
|
|
474
|
+
const file_path = parse_edited_path(payload)
|
|
475
|
+
const before = rewrite_notice.read_text(file_path)
|
|
476
|
+
const lint = await format_edited_payload(payload, process.cwd())
|
|
477
|
+
const rewrite = rewrite_notice.build(before, rewrite_notice.read_text(file_path))
|
|
478
|
+
const spelling = await edited_cspell.spelling_diagnostics(file_path, process.cwd())
|
|
479
|
+
const parts = compose_context(rewrite, compose_context(lint, spelling))
|
|
480
|
+
const context = compose_context(notice, parts)
|
|
481
|
+
|
|
482
|
+
if (context !== undefined) process.stdout.write(`${build_envelope(context)}\n`)
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
if (process.argv[1] === fileURLToPath(import.meta.url)) {
|
|
486
|
+
if (process.stdin.isTTY) {
|
|
487
|
+
report_no_payload()
|
|
488
|
+
} else {
|
|
489
|
+
await run_hook(await text(process.stdin))
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
export {
|
|
494
|
+
build_envelope,
|
|
495
|
+
compose_context,
|
|
496
|
+
density_envelope,
|
|
497
|
+
format_edited_file,
|
|
498
|
+
format_edited_payload,
|
|
499
|
+
is_start_failure,
|
|
500
|
+
parse_edited_path,
|
|
501
|
+
plan_commands,
|
|
502
|
+
plan_daemon_restart,
|
|
503
|
+
relative_to_root,
|
|
504
|
+
resolve_invocations,
|
|
505
|
+
select_invocation,
|
|
506
|
+
ESLINT_DAEMON,
|
|
507
|
+
MAX_DIAGNOSTIC_CHARS,
|
|
508
|
+
PROCESS_TIMEOUT_MS,
|
|
509
|
+
}
|
|
510
|
+
export type { CommandRunner, FormatCommand }
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs'
|
|
2
|
+
|
|
3
|
+
// The rewrite half of the edit hook (joshuafolkken/kit#2314). The format hook runs prettier and
|
|
4
|
+
// `eslint --fix` in place after every edit, so a file the model just wrote can be rewritten out from
|
|
5
|
+
// under the image the model holds — and the next `Edit` against that stale image misses, then pays for
|
|
6
|
+
// a full re-read that rides every later request. joshuafolkken/kit#2275 built the `additionalContext`
|
|
7
|
+
// path this rides and joshuafolkken/kit#2296 put cspell on it; this returns the fact that the file
|
|
8
|
+
// changed and the region that changed, so the model reissues against current text without re-reading
|
|
9
|
+
// the whole file. Nothing is added when formatting left the file untouched.
|
|
10
|
+
|
|
11
|
+
// additionalContext rides back on the edit, so the changed region is cut to this bound rather than
|
|
12
|
+
// let a large reformat balloon the run's context — the notice is a cheaper hint than the full re-read
|
|
13
|
+
// it replaces, and stays cheaper only while it is bounded.
|
|
14
|
+
const MAX_REWRITE_CHARS = 1200
|
|
15
|
+
const REWRITE_TRUNCATION_NOTICE = '\n…(rewrite preview truncated)'
|
|
16
|
+
// The header names what the block is, since additionalContext arrives with no framing of its own, and
|
|
17
|
+
// says the one thing the model has to act on: its copy is stale, so re-read before the next edit.
|
|
18
|
+
const REWRITE_HEADER =
|
|
19
|
+
'The format hook rewrote this file after your edit, so your in-memory copy is now stale — re-read it before the next Edit or the match will miss.'
|
|
20
|
+
const REWRITE_RANGE_PREFIX = 'Changed around lines '
|
|
21
|
+
const LINE_SEPARATOR = '\n'
|
|
22
|
+
const FIRST_LINE = 1
|
|
23
|
+
|
|
24
|
+
// The span of the post-format file that differs from the pre-format one — the common head and tail
|
|
25
|
+
// are trimmed so the range points at what actually moved rather than the whole file.
|
|
26
|
+
interface ChangedRange {
|
|
27
|
+
start_line: number
|
|
28
|
+
end_line: number
|
|
29
|
+
body: string
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function common_prefix_length(before: ReadonlyArray<string>, after: ReadonlyArray<string>): number {
|
|
33
|
+
const limit = Math.min(before.length, after.length)
|
|
34
|
+
let index = 0
|
|
35
|
+
|
|
36
|
+
while (index < limit && before[index] === after[index]) index += 1
|
|
37
|
+
|
|
38
|
+
return index
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function common_suffix_length(
|
|
42
|
+
before: ReadonlyArray<string>,
|
|
43
|
+
after: ReadonlyArray<string>,
|
|
44
|
+
prefix: number,
|
|
45
|
+
): number {
|
|
46
|
+
const limit = Math.min(before.length, after.length) - prefix
|
|
47
|
+
let index = 0
|
|
48
|
+
|
|
49
|
+
while (index < limit && before.at(-1 - index) === after.at(-1 - index)) index += 1
|
|
50
|
+
|
|
51
|
+
return index
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function changed_range(before: string, after: string): ChangedRange {
|
|
55
|
+
const before_lines = before.split(LINE_SEPARATOR)
|
|
56
|
+
const after_lines = after.split(LINE_SEPARATOR)
|
|
57
|
+
const prefix = common_prefix_length(before_lines, after_lines)
|
|
58
|
+
const last = after_lines.length - common_suffix_length(before_lines, after_lines, prefix)
|
|
59
|
+
|
|
60
|
+
return {
|
|
61
|
+
start_line: prefix + FIRST_LINE,
|
|
62
|
+
end_line: Math.max(prefix + FIRST_LINE, last),
|
|
63
|
+
body: after_lines.slice(prefix, last).join(LINE_SEPARATOR),
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function cap_body(body: string): string {
|
|
68
|
+
if (body.length <= MAX_REWRITE_CHARS) return body
|
|
69
|
+
|
|
70
|
+
return `${body.slice(0, MAX_REWRITE_CHARS)}${REWRITE_TRUNCATION_NOTICE}`
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// The block the model reads: the header, the line range, then the region's new text cut to the bound.
|
|
74
|
+
// `undefined` when formatting changed nothing, so the ordinary edit adds nothing to additionalContext.
|
|
75
|
+
function build(before: string, after: string): string | undefined {
|
|
76
|
+
if (before === after) return undefined
|
|
77
|
+
|
|
78
|
+
const range = changed_range(before, after)
|
|
79
|
+
const location = `${REWRITE_RANGE_PREFIX}${String(range.start_line)}-${String(range.end_line)}:`
|
|
80
|
+
|
|
81
|
+
return `${REWRITE_HEADER}\n${location}\n${cap_body(range.body)}`
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// The file content around a format run, read for the before/after comparison. A path the hook was
|
|
85
|
+
// handed nothing for, or one gone by the time it reads, compares as an empty string rather than
|
|
86
|
+
// throwing — the hook runs after the write already succeeded and must never turn it into a failure.
|
|
87
|
+
function read_text(file_path: string | undefined): string {
|
|
88
|
+
if (file_path === undefined) return ''
|
|
89
|
+
|
|
90
|
+
try {
|
|
91
|
+
return readFileSync(file_path, 'utf8')
|
|
92
|
+
} catch {
|
|
93
|
+
return ''
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const rewrite_notice = { build, read_text }
|
|
98
|
+
|
|
99
|
+
export { rewrite_notice, MAX_REWRITE_CHARS }
|