@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,154 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs'
|
|
2
|
+
import { copyFile, mkdir, mkdtemp, readFile, rm, symlink } from 'node:fs/promises'
|
|
3
|
+
import { tmpdir } from 'node:os'
|
|
4
|
+
import path from 'node:path'
|
|
5
|
+
import { fileURLToPath } from 'node:url'
|
|
6
|
+
import { change_base } from '#scripts/git/change-base'
|
|
7
|
+
import { changed_paths } from '#scripts/git/changed-paths'
|
|
8
|
+
import { git_location_environment } from '#scripts/git/git-location-environment'
|
|
9
|
+
import { git_worktree } from '#scripts/git/git-worktree'
|
|
10
|
+
import { execa } from 'execa'
|
|
11
|
+
import { test_red_logic, type RedVerdict } from './test-red-logic'
|
|
12
|
+
|
|
13
|
+
// `josh test:red` — run the added and changed Vitest files against the pre-fix tree and print `red`,
|
|
14
|
+
// `green` or `no-test` (joshuafolkken/kit#2448).
|
|
15
|
+
//
|
|
16
|
+
// **The pre-fix tree is a detached worktree at the merge-base, never the caller's checkout.** The tests
|
|
17
|
+
// are copied in from the working tree, so what runs is the new test against the old code, and the
|
|
18
|
+
// caller's tree and index are never read back or written. The worktree borrows this checkout's
|
|
19
|
+
// `node_modules` through a symlink rather than installing its own: what is being asked about is the
|
|
20
|
+
// source the fix changed, and an install would add seconds and a network dependency to every commit.
|
|
21
|
+
|
|
22
|
+
const ARGV_OFFSET = 2
|
|
23
|
+
const TREE_PREFIX = 'josh-test-red-'
|
|
24
|
+
const TREE_NAME = 'tree'
|
|
25
|
+
const REPORT_NAME = 'report.json'
|
|
26
|
+
const NODE_MODULES = 'node_modules'
|
|
27
|
+
const VITEST_BIN = path.join(NODE_MODULES, '.bin', 'vitest')
|
|
28
|
+
const USAGE =
|
|
29
|
+
'Usage: josh test:red — prints red / green / no-test for the changed tests on the merge-base'
|
|
30
|
+
|
|
31
|
+
interface RedRun {
|
|
32
|
+
verdict: RedVerdict
|
|
33
|
+
files: ReadonlyArray<string>
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// The changed Vitest files that still exist — a deleted test has nothing to run.
|
|
37
|
+
async function changed_tests(): Promise<Array<string>> {
|
|
38
|
+
const paths = await changed_paths.read_changed_paths(false)
|
|
39
|
+
|
|
40
|
+
return test_red_logic.unit_test_files(paths).filter((file) => existsSync(file))
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async function copy_in(tree: string, files: ReadonlyArray<string>): Promise<void> {
|
|
44
|
+
for (const file of files) {
|
|
45
|
+
const target = path.join(tree, file)
|
|
46
|
+
|
|
47
|
+
await mkdir(path.dirname(target), { recursive: true })
|
|
48
|
+
await copyFile(file, target)
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async function prepare(tree: string, base: string, files: ReadonlyArray<string>): Promise<void> {
|
|
53
|
+
await git_worktree.worktree_add_detached(tree, base)
|
|
54
|
+
await symlink(path.resolve(NODE_MODULES), path.join(tree, NODE_MODULES), 'dir')
|
|
55
|
+
await copy_in(tree, files)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function reporter_arguments(report: string): Array<string> {
|
|
59
|
+
// The plain `--outputFile`, not `--outputFile.json`: a config that sets `test.outputFile` as a string
|
|
60
|
+
// wins over the keyed form, which would send the report into the tree and read every run `no-test`.
|
|
61
|
+
return ['--reporter=json', `--outputFile=${report}`]
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async function read_report(report: string): Promise<string> {
|
|
65
|
+
return existsSync(report) ? await readFile(report, 'utf8') : ''
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// The verdict of one run. `--passWithNoTests` keeps "the filter matched nothing" from reading as a
|
|
69
|
+
// failure, and the JSON report — written beside the tree, never into it — says whether anything ran at
|
|
70
|
+
// all, so a file the old config excludes is `no-test` rather than a `green` that refuses a correct fix.
|
|
71
|
+
// A test that ran and broke, or a file that could not load against the old code, makes it `red`.
|
|
72
|
+
async function verdict_in(
|
|
73
|
+
parent: string,
|
|
74
|
+
tree: string,
|
|
75
|
+
files: ReadonlyArray<string>,
|
|
76
|
+
): Promise<RedVerdict> {
|
|
77
|
+
const report = path.join(parent, REPORT_NAME)
|
|
78
|
+
const vitest_args = ['run', '--passWithNoTests', ...reporter_arguments(report), ...files]
|
|
79
|
+
const result = await execa(path.join(tree, VITEST_BIN), vitest_args, {
|
|
80
|
+
cwd: tree,
|
|
81
|
+
env: git_location_environment.location_free_environment(),
|
|
82
|
+
extendEnv: true,
|
|
83
|
+
reject: false,
|
|
84
|
+
})
|
|
85
|
+
const ran = test_red_logic.ran_file_count(await read_report(report))
|
|
86
|
+
|
|
87
|
+
return test_red_logic.verdict_for(ran, result.exitCode !== 0)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Best effort: a removal that fails leaves a registration `worktree prune` drops once the directory is
|
|
91
|
+
// gone, so the cleanup never replaces the verdict with its own error.
|
|
92
|
+
async function remove_tree(parent: string, tree: string): Promise<void> {
|
|
93
|
+
try {
|
|
94
|
+
await git_worktree.worktree_remove(tree)
|
|
95
|
+
} catch {
|
|
96
|
+
// The directory is deleted below and the prune drops the stale registration.
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
await rm(parent, { force: true, recursive: true })
|
|
100
|
+
|
|
101
|
+
try {
|
|
102
|
+
await git_worktree.worktree_prune()
|
|
103
|
+
} catch {
|
|
104
|
+
// A failed prune leaves a stale registration the next prune drops; the verdict stands.
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async function verdict_on(base: string, files: ReadonlyArray<string>): Promise<RedVerdict> {
|
|
109
|
+
const parent = await mkdtemp(path.join(tmpdir(), TREE_PREFIX))
|
|
110
|
+
const tree = path.join(parent, TREE_NAME)
|
|
111
|
+
|
|
112
|
+
try {
|
|
113
|
+
await prepare(tree, base, files)
|
|
114
|
+
|
|
115
|
+
return await verdict_in(parent, tree, files)
|
|
116
|
+
} finally {
|
|
117
|
+
await remove_tree(parent, tree)
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// The verdict over the current checkout. No merge-base (not a repository, no default branch) reads as
|
|
122
|
+
// `no-test` — there is no pre-fix tree to run against, and a guard fails open.
|
|
123
|
+
async function run(): Promise<RedRun> {
|
|
124
|
+
const base = await change_base.resolved()
|
|
125
|
+
const files = await changed_tests()
|
|
126
|
+
|
|
127
|
+
if (base === undefined || files.length === 0) return { verdict: 'no-test', files }
|
|
128
|
+
|
|
129
|
+
return { verdict: await verdict_on(base, files), files }
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
async function main(argv: ReadonlyArray<string>): Promise<number> {
|
|
133
|
+
if (argv.length > 0) {
|
|
134
|
+
process.stderr.write(`${USAGE}\n`)
|
|
135
|
+
|
|
136
|
+
return argv.includes('--help') ? 0 : 1
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const { verdict, files } = await run()
|
|
140
|
+
|
|
141
|
+
process.stdout.write(`${verdict}\n`)
|
|
142
|
+
if (files.length > 0) process.stderr.write(`${files.join('\n')}\n`)
|
|
143
|
+
|
|
144
|
+
return 0
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (process.argv[1] === fileURLToPath(import.meta.url)) {
|
|
148
|
+
process.exitCode = await main(process.argv.slice(ARGV_OFFSET))
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const test_red = { USAGE, run }
|
|
152
|
+
|
|
153
|
+
export type { RedRun }
|
|
154
|
+
export { test_red }
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import path from 'node:path'
|
|
2
|
+
import {
|
|
3
|
+
changed_file_scope,
|
|
4
|
+
type ChangedFileScope,
|
|
5
|
+
type ScopeInputs,
|
|
6
|
+
type ScopeVocabulary,
|
|
7
|
+
} from '#scripts/git/changed-file-scope'
|
|
8
|
+
|
|
9
|
+
// joshuafolkken/kit#1257: the unit suite always ran whole. Measured warm on kit, that is 384 files
|
|
10
|
+
// and 6,616 tests — 13.9s wall and 110s of CPU, 84% of everything the four gate checks spend, and
|
|
11
|
+
// an implementation loop paid it again on every re-check. The same tree narrowed to one changed
|
|
12
|
+
// file runs 31 files and 566 tests in 2.4s (7.9s of CPU, −93%).
|
|
13
|
+
//
|
|
14
|
+
// **This narrowing is added in front of the whole suite, never in place of it.** A test that breaks
|
|
15
|
+
// without importing what changed — a marker suite reading a document, a fixture compared against a
|
|
16
|
+
// generated file — is invisible to a module graph, so the verification gate keeps running
|
|
17
|
+
// `josh test:unit` over everything before the commit.
|
|
18
|
+
//
|
|
19
|
+
// The decision this file makes is which extensions vitest can walk a module graph back from, and
|
|
20
|
+
// what to print about it. Everything the decision shares with `josh lint:related` — reading the
|
|
21
|
+
// change, dropping what the tree no longer holds, and the two fallbacks — is
|
|
22
|
+
// `changed-file-scope.ts`, so the two commands cannot drift apart about what "changed" means
|
|
23
|
+
// (joshuafolkken/kit#1298).
|
|
24
|
+
|
|
25
|
+
type RelatedScope = ChangedFileScope
|
|
26
|
+
|
|
27
|
+
// The extensions vitest can walk a module graph back from. A changed `.md`, `.yaml` or `.json` is
|
|
28
|
+
// dropped rather than passed through: `vitest related` would match no test file for it, and a run
|
|
29
|
+
// narrowed to nothing at all is the one outcome this module exists to prevent.
|
|
30
|
+
const RELATABLE_EXTENSIONS: ReadonlySet<string> = new Set([
|
|
31
|
+
'.ts',
|
|
32
|
+
'.tsx',
|
|
33
|
+
'.mts',
|
|
34
|
+
'.cts',
|
|
35
|
+
'.js',
|
|
36
|
+
'.jsx',
|
|
37
|
+
'.mjs',
|
|
38
|
+
'.cjs',
|
|
39
|
+
'.svelte',
|
|
40
|
+
])
|
|
41
|
+
|
|
42
|
+
const { UNREADABLE_REASON } = changed_file_scope
|
|
43
|
+
const NOTHING_RELATABLE_REASON = 'no changed file is one a test can import'
|
|
44
|
+
|
|
45
|
+
// The command this narrowing belongs to, defined once: the guard prints it when it skips, and the
|
|
46
|
+
// line below prints it in front of every decision.
|
|
47
|
+
const COMMAND_NAME = 'test:related'
|
|
48
|
+
const COMMAND_LABEL = `josh ${COMMAND_NAME}`
|
|
49
|
+
const { LISTED_FILE_LIMIT } = changed_file_scope
|
|
50
|
+
|
|
51
|
+
const VOCABULARY: ScopeVocabulary = {
|
|
52
|
+
label: COMMAND_LABEL,
|
|
53
|
+
fallback_suffix: 'running the full unit suite instead',
|
|
54
|
+
narrowed_suffix: 'running only the tests related to them',
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const RUN_FLAG = '--run'
|
|
58
|
+
const RELATED_SUBCOMMAND = 'related'
|
|
59
|
+
const RUN_SUBCOMMAND = 'run'
|
|
60
|
+
|
|
61
|
+
function is_relatable(file_path: string): boolean {
|
|
62
|
+
return RELATABLE_EXTENSIONS.has(path.extname(file_path))
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// The three inputs that make the shared narrowing this command's, handed over as one value so the
|
|
66
|
+
// CLI and the two functions below cannot disagree about any of them.
|
|
67
|
+
function scope_inputs(is_present: (file_path: string) => boolean): ScopeInputs {
|
|
68
|
+
return { is_present, is_selectable: is_relatable, nothing_reason: NOTHING_RELATABLE_REASON }
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function select_related_files(
|
|
72
|
+
paths: ReadonlyArray<string>,
|
|
73
|
+
is_present: (file_path: string) => boolean,
|
|
74
|
+
): Array<string> {
|
|
75
|
+
return changed_file_scope.select_files(paths, scope_inputs(is_present))
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function resolve_scope(
|
|
79
|
+
paths: ReadonlyArray<string> | undefined,
|
|
80
|
+
is_present: (file_path: string) => boolean,
|
|
81
|
+
): RelatedScope {
|
|
82
|
+
return changed_file_scope.resolve_scope(paths, scope_inputs(is_present))
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function describe_scope(scope: RelatedScope, root: string): string {
|
|
86
|
+
return changed_file_scope.describe_scope(scope, root, VOCABULARY)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// `--run` is what keeps `vitest related` out of watch mode; the `run` sub-command already implies it
|
|
90
|
+
// on the full-suite side, which is why only one of the two branches carries the flag.
|
|
91
|
+
function vitest_arguments(
|
|
92
|
+
scope: RelatedScope,
|
|
93
|
+
extra_flags: ReadonlyArray<string> = [],
|
|
94
|
+
): ReadonlyArray<string> {
|
|
95
|
+
if (scope.mode === 'all') return [RUN_SUBCOMMAND, ...extra_flags]
|
|
96
|
+
|
|
97
|
+
return [RELATED_SUBCOMMAND, ...scope.files, RUN_FLAG, ...extra_flags]
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const related_scope = {
|
|
101
|
+
COMMAND_LABEL,
|
|
102
|
+
COMMAND_NAME,
|
|
103
|
+
LISTED_FILE_LIMIT,
|
|
104
|
+
NOTHING_RELATABLE_REASON,
|
|
105
|
+
UNREADABLE_REASON,
|
|
106
|
+
describe_scope,
|
|
107
|
+
is_relatable,
|
|
108
|
+
resolve_scope,
|
|
109
|
+
scope_inputs,
|
|
110
|
+
select_related_files,
|
|
111
|
+
vitest_arguments,
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export type { ScopeMode } from '#scripts/git/changed-file-scope'
|
|
115
|
+
export { related_scope }
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
import { existsSync } from 'node:fs'
|
|
3
|
+
import { fileURLToPath } from 'node:url'
|
|
4
|
+
import type { GateTree } from '#scripts/gate/gate-tree'
|
|
5
|
+
import { scoped_green } from '#scripts/gate/scoped-green'
|
|
6
|
+
import { changed_file_scope } from '#scripts/git/changed-file-scope'
|
|
7
|
+
import { review_stamps } from '#scripts/review/review-stamps'
|
|
8
|
+
import { related_scope } from './test-related-scope'
|
|
9
|
+
import { test_unit_guard } from './test-unit-guard'
|
|
10
|
+
|
|
11
|
+
// `josh test:related` — the unit check an implementation loop runs between edits
|
|
12
|
+
// (joshuafolkken/kit#1257). The narrowing itself is `test-related-scope.ts` over the shared
|
|
13
|
+
// decision in `changed-file-scope.ts`; this is the process around it — how the run reaches vitest
|
|
14
|
+
// through the same guard `josh test:unit` goes through.
|
|
15
|
+
//
|
|
16
|
+
// **A green run leaves a record of the tree it was green on** (joshuafolkken/kit#1511), so
|
|
17
|
+
// `josh review:brief` can tell a tree this check has read from one it has not. What the record means,
|
|
18
|
+
// and the three states in which it is withheld, are `scoped-green.ts`.
|
|
19
|
+
|
|
20
|
+
// **A skipped vitest exits 0, and a zero from a run that started nothing must vouch for no tree.**
|
|
21
|
+
// `test_unit_guard.report_no_run` returns 0 on its skip branch — vitest not installed — so in a
|
|
22
|
+
// project with no unit suite the record would say the tests were green over a run in which none
|
|
23
|
+
// executed, and `josh review:brief` would stop refusing on the strength of it. **The guard's own
|
|
24
|
+
// decision is asked again rather than re-derived here**, so the two can never disagree; it is asked
|
|
25
|
+
// only when a record is otherwise due, since the question costs a project-wide glob.
|
|
26
|
+
function conclusive_tree(before: GateTree | undefined): GateTree | undefined {
|
|
27
|
+
if (before === undefined) return undefined
|
|
28
|
+
|
|
29
|
+
const action = test_unit_guard.resolve_guard_action(
|
|
30
|
+
test_unit_guard.is_vitest_installed(process.cwd()),
|
|
31
|
+
test_unit_guard.has_unit_tests(process.cwd()),
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
return action === 'run' ? before : undefined
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async function run_related_tests(command_arguments: ReadonlyArray<string>): Promise<number> {
|
|
38
|
+
const root = await changed_file_scope.repository_root_or_cwd()
|
|
39
|
+
const scope = await changed_file_scope.resolve_command_scope({
|
|
40
|
+
command_arguments,
|
|
41
|
+
root,
|
|
42
|
+
inputs: related_scope.scope_inputs(existsSync),
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
changed_file_scope.report_unusable_arguments(
|
|
46
|
+
command_arguments,
|
|
47
|
+
scope,
|
|
48
|
+
related_scope.COMMAND_LABEL,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
const before = await scoped_green.read_before(command_arguments)
|
|
52
|
+
const exit_code = await test_unit_guard.run_guarded_vitest(
|
|
53
|
+
process.cwd(),
|
|
54
|
+
related_scope.vitest_arguments(scope, changed_file_scope.flags_of(command_arguments)),
|
|
55
|
+
related_scope.COMMAND_NAME,
|
|
56
|
+
related_scope.describe_scope(scope, root),
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
await scoped_green.record_if_green(review_stamps.test_related_stamp, {
|
|
60
|
+
before: conclusive_tree(before),
|
|
61
|
+
exit_code,
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
return exit_code
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (process.argv[1] === fileURLToPath(import.meta.url)) {
|
|
68
|
+
process.exitCode = await run_related_tests(process.argv.slice(changed_file_scope.ARGV_START))
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const test_related = { run_related_tests }
|
|
72
|
+
|
|
73
|
+
export { test_related }
|
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
import { execFileSync } from 'node:child_process'
|
|
2
|
+
import { shim_shell } from '#scripts/build/shim-shell'
|
|
3
|
+
import {
|
|
4
|
+
git_location_environment,
|
|
5
|
+
GIT_LOCATION_VARIABLES,
|
|
6
|
+
} from '#scripts/git/git-location-environment'
|
|
7
|
+
|
|
8
|
+
// **A unit test must not write into the repository the suite is running in**, and until
|
|
9
|
+
// joshuafolkken/kit#1530 nothing said so out loud.
|
|
10
|
+
//
|
|
11
|
+
// `lane-change-base.test.ts` builds a real git topology in a temp directory and hands its helper
|
|
12
|
+
// `{ cwd }` and nothing else. Run from the pre-push hook it inherited `GIT_DIR` and `GIT_INDEX_FILE`
|
|
13
|
+
// from the hook environment — both of which beat `cwd` — so the fixture's own commits landed on the
|
|
14
|
+
// branch being pushed. `1085-lane`'s reflog carries three of them, titled `base` and
|
|
15
|
+
// `another lane merged`, 26 seconds after the run's real commit; `1080-lane` took one. The same
|
|
16
|
+
// helper's `git config user.email` wrote a fixture identity into `--local` config, which every
|
|
17
|
+
// linked work tree of the repository shares, so all five checkouts on the machine started authoring
|
|
18
|
+
// commits as `Lane Fixture <lane@example.test>`.
|
|
19
|
+
//
|
|
20
|
+
// **This is the second instance of one class in a day.** joshuafolkken/kit#1515 fixed the first, in
|
|
21
|
+
// `propagate-git`'s probes, by clearing the location variables — and fixing the instance is all it
|
|
22
|
+
// did. The class recurred within hours, in a file written after it, arriving the same way: silently,
|
|
23
|
+
// with the only evidence a reflog someone had to go and read.
|
|
24
|
+
//
|
|
25
|
+
// **So the guard is built one dimension over from #1515's own network guard, on the same mechanism**
|
|
26
|
+
// (`test-network-guard.ts` arms the `PATH` shim, holds the record and fails the run from
|
|
27
|
+
// `globalSetup`'s teardown; this module contributes the `sh` that decides). Reusing it rather than
|
|
28
|
+
// writing a second guard is `CLAUDE.md` → "No clones", and it is also the only way the two can share
|
|
29
|
+
// one record: a run that both reached the network and wrote to the repository reports both.
|
|
30
|
+
//
|
|
31
|
+
// **What it refuses, and why that is narrower than "any command touching the repository".** Reads
|
|
32
|
+
// are the suite's business — half of it reads the repository it is running in, and refusing that
|
|
33
|
+
// would stop the suite rather than the defect. A read also cannot move a branch. So the arm is the
|
|
34
|
+
// *writing* subcommands, and it refuses one on either of two findings:
|
|
35
|
+
//
|
|
36
|
+
// 1. **Any git location variable is set.** A fixture is targeted by clearing the environment, never
|
|
37
|
+
// by out-arguing it, so a writing command reaching git with `GIT_DIR` or `GIT_INDEX_FILE` still
|
|
38
|
+
// in its environment is refused whatever it was aimed at. This is the exact shape of both
|
|
39
|
+
// instances, and it is decided without spawning anything.
|
|
40
|
+
// 2. **The command resolves into the guarded repository.** The environment can be clean and the
|
|
41
|
+
// write still land here, by way of an ambient `cwd` — a test that `process.chdir`s into the
|
|
42
|
+
// checkout and commits. The resolution is git's own `rev-parse --absolute-git-dir`, **asked with
|
|
43
|
+
// the caller's own global options in front of it**, so `-C <fixture>` is not refused for the
|
|
44
|
+
// directory the shim happens to sit in and `--git-dir <checkout>` is not let through for it.
|
|
45
|
+
//
|
|
46
|
+
// The two lists below say which finding a subcommand faces: an unambiguous writer faces both, and
|
|
47
|
+
// one whose reading spelling this suite uses faces the first only.
|
|
48
|
+
//
|
|
49
|
+
// **It fails closed on the second finding**: a resolution that fails means the command is not inside
|
|
50
|
+
// any repository at all — that is an answer, not an unknown, and the first finding has already
|
|
51
|
+
// refused every environment that could have redirected it elsewhere.
|
|
52
|
+
//
|
|
53
|
+
// **The one deliberate fail-open** is a `PROJECT_ROOT` that is not a git repository, where there is
|
|
54
|
+
// no repository for a test to damage and the second finding is left out of the generated shim. The
|
|
55
|
+
// first finding is generated unconditionally, so an inherited environment is refused either way.
|
|
56
|
+
//
|
|
57
|
+
// **What it names.** The shim cannot see which test called it — it is a `PATH` shim, and vitest puts
|
|
58
|
+
// no test identity in the environment. It does not need to: it refuses **at the call**, with `exit 1`
|
|
59
|
+
// and the command and the finding on stderr, so `execa` throws inside the test and vitest names the
|
|
60
|
+
// file and the test itself. The record read at teardown is the backstop for a test that swallows the
|
|
61
|
+
// error, and it carries the command and the finding for the same reason — so nobody has to
|
|
62
|
+
// reconstruct it from a reflog the way joshuafolkken/kit#1530 was.
|
|
63
|
+
|
|
64
|
+
// The `git` subcommands that can write to a repository, an index or a config. Absent from it are the
|
|
65
|
+
// reads the suite lives on (`status`, `log`, `diff`, `rev-parse`, `merge-base`, `show`,
|
|
66
|
+
// `ls-files`, `cat-file`, `describe`) and the network subcommands, which `test-network-guard.ts`
|
|
67
|
+
// refuses outright before this arm is reached.
|
|
68
|
+
//
|
|
69
|
+
// **`symbolic-ref` is deliberately absent**: its writing spelling takes a second argument and its
|
|
70
|
+
// reading spelling does not, and splitting that inside a shell `case` fails open when it gets it
|
|
71
|
+
// wrong. Nothing in this suite writes a symbolic ref, and the branch-moving spellings that matter
|
|
72
|
+
// (`update-ref`, `checkout`, `switch`, `reset`) are all here.
|
|
73
|
+
const GIT_WRITING_SUBCOMMANDS: ReadonlyArray<string> = [
|
|
74
|
+
'add',
|
|
75
|
+
'am',
|
|
76
|
+
'checkout',
|
|
77
|
+
'cherry-pick',
|
|
78
|
+
'clean',
|
|
79
|
+
'commit',
|
|
80
|
+
'gc',
|
|
81
|
+
'init',
|
|
82
|
+
'merge',
|
|
83
|
+
'mv',
|
|
84
|
+
'prune',
|
|
85
|
+
'rebase',
|
|
86
|
+
'reset',
|
|
87
|
+
'restore',
|
|
88
|
+
'revert',
|
|
89
|
+
'rm',
|
|
90
|
+
'switch',
|
|
91
|
+
'update-index',
|
|
92
|
+
'update-ref',
|
|
93
|
+
]
|
|
94
|
+
|
|
95
|
+
// The subcommands whose **reading** spelling this suite actually uses — `worktree list`,
|
|
96
|
+
// `branch --show-current`, `config --get`, `stash list`, `tag -l`, `notes list`, `apply --check`.
|
|
97
|
+
// They are refused on the inherited-environment finding only.
|
|
98
|
+
//
|
|
99
|
+
// **Which is not a hole, but the line between the two findings drawn where it belongs.** An
|
|
100
|
+
// inherited environment is wrong for a read as surely as for a write — it is the other half of what
|
|
101
|
+
// joshuafolkken/kit#1530 did, where `git_command`'s readings answered about the repository being
|
|
102
|
+
// pushed — so finding 1 covers these whole, `config user.email <value>` and `worktree add` included.
|
|
103
|
+
// Finding 2 is the one that cannot tell them apart: an ambient `cwd` inside the checkout is exactly
|
|
104
|
+
// how a legitimate read of the real repository is spelled, and refusing that would stop the suite
|
|
105
|
+
// rather than the defect (`test-network-guard.ts` names the worktree machinery as a read that has to
|
|
106
|
+
// keep working). Splitting them on their flags instead was rejected for the reason the network list
|
|
107
|
+
// refuses `remote` whole: getting a flag `case` wrong in `sh` fails **open**.
|
|
108
|
+
const GIT_AMBIGUOUS_SUBCOMMANDS: ReadonlyArray<string> = [
|
|
109
|
+
'apply',
|
|
110
|
+
'branch',
|
|
111
|
+
'config',
|
|
112
|
+
'notes',
|
|
113
|
+
'stash',
|
|
114
|
+
'tag',
|
|
115
|
+
'worktree',
|
|
116
|
+
]
|
|
117
|
+
|
|
118
|
+
// The word every recorded write violation starts with, so one shared record still says which guard
|
|
119
|
+
// caught which call and `describe_violations` can report each kind under its own heading.
|
|
120
|
+
const WRITE_MARKER = 'repository write:'
|
|
121
|
+
// **The headline states the rule and the detail line states the finding**, because the two findings
|
|
122
|
+
// have different fixes: clearing the environment is the answer to the first and gives the second a
|
|
123
|
+
// misleading instruction, which is what the same sentence said for both until review round 1.
|
|
124
|
+
const BLOCKED_WRITE_MESSAGE =
|
|
125
|
+
'josh: a unit test must not run a writing git command against the repository the suite is running in'
|
|
126
|
+
// Finding-neutral, like the stderr message and for the same reason: each recorded line carries its
|
|
127
|
+
// own `— via …`, and a run failed on the working-directory finding must not be told to clear an
|
|
128
|
+
// environment that was already clean (review round 2).
|
|
129
|
+
const WRITE_VIOLATION_HEADING =
|
|
130
|
+
'The unit suite ran a writing git command against the repository it is running in. Each line names what took it there:'
|
|
131
|
+
|
|
132
|
+
// The record and the stderr detail both read as prose and both expand in `sh`: `$*` is the arguments
|
|
133
|
+
// the shim stood in for, `$guard_via` the finding that refused them.
|
|
134
|
+
const REFUSED_COMMAND = 'git $* — via $guard_via'
|
|
135
|
+
const RECORDED_WRITE = `${WRITE_MARKER} ${REFUSED_COMMAND}`
|
|
136
|
+
|
|
137
|
+
const GIT_DIRECTORY_ARGUMENTS = ['rev-parse', '--path-format=absolute', '--git-common-dir']
|
|
138
|
+
|
|
139
|
+
// **The one failure that is an answer rather than an unknown.** There is no repository at
|
|
140
|
+
// `PROJECT_ROOT`, so finding 2 has nothing to protect and is left out of the generated shim while
|
|
141
|
+
// finding 1 stays armed. Every other failure — an unreadable directory, a git that cannot run — is a
|
|
142
|
+
// guard that does not know what it is guarding, and a guard that cannot answer must not report the
|
|
143
|
+
// run clean (review round 1 of joshuafolkken/kit#1530).
|
|
144
|
+
const NOT_A_REPOSITORY = 'not a git repository'
|
|
145
|
+
const RESOLUTION_HEADING =
|
|
146
|
+
'The unit-suite repository guard could not work out which repository it protects, so the run proves nothing:'
|
|
147
|
+
|
|
148
|
+
function text_of(value: unknown): string {
|
|
149
|
+
return typeof value === 'string' ? value : ''
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// What git said, plus what node said when git never ran — the two places the reason can be, joined
|
|
153
|
+
// so one `includes` decides between them.
|
|
154
|
+
function stderr_of(error: unknown): string {
|
|
155
|
+
if (typeof error !== 'object' || error === null) return ''
|
|
156
|
+
|
|
157
|
+
const stderr = 'stderr' in error ? text_of(error.stderr) : ''
|
|
158
|
+
const message = 'message' in error ? text_of(error.message) : ''
|
|
159
|
+
|
|
160
|
+
return `${stderr} ${message}`.trim()
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function is_absent_repository(error: unknown): boolean {
|
|
164
|
+
return stderr_of(error).includes(NOT_A_REPOSITORY)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// The repository this guard protects, as git itself resolves it — the **common** directory rather
|
|
168
|
+
// than the per-work-tree one, so a lane's shim refuses a write into any of the repository's linked
|
|
169
|
+
// work trees and not only into its own.
|
|
170
|
+
function guarded_git_directory(git_binary: string | undefined, from: string): string | undefined {
|
|
171
|
+
if (git_binary === undefined) return undefined
|
|
172
|
+
|
|
173
|
+
try {
|
|
174
|
+
return execFileSync(git_binary, GIT_DIRECTORY_ARGUMENTS, {
|
|
175
|
+
cwd: from,
|
|
176
|
+
encoding: 'utf8',
|
|
177
|
+
// **Cleared here too, and not belt-and-braces.** The guard is armed from `globalSetup`, and
|
|
178
|
+
// under the pre-push hook that process has itself inherited `GIT_DIR` — so asking without
|
|
179
|
+
// clearing it answers about whatever the hook was pointed at, and the shim would be built
|
|
180
|
+
// to protect a repository this suite has nothing to do with.
|
|
181
|
+
env: { ...process.env, ...git_location_environment.location_free_environment() },
|
|
182
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
183
|
+
}).trim()
|
|
184
|
+
} catch (error) {
|
|
185
|
+
if (!is_absent_repository(error)) {
|
|
186
|
+
throw new Error(`${RESOLUTION_HEADING} ${stderr_of(error)}`, { cause: error })
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return undefined
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Finding 1, one line per variable. `${NAME-}` rather than `$NAME` so an unset name is the empty
|
|
194
|
+
// string under `set -u` as readily as without it.
|
|
195
|
+
function environment_lines(): Array<string> {
|
|
196
|
+
return GIT_LOCATION_VARIABLES.map(
|
|
197
|
+
(name) => `[ -z "\${${name}-}" ] || guard_env="$guard_env ${name}"`,
|
|
198
|
+
)
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// The `sh` function finding 2 resolves through, emitted once at the top of the shim.
|
|
202
|
+
//
|
|
203
|
+
// **It keeps the caller's own global options** — the words the scan counted before the subcommand —
|
|
204
|
+
// and asks git where *that* command would act. `cwd` alone is not that answer, in both directions:
|
|
205
|
+
// `git -C <fixture>` moves it away from the directory the shim was spawned in, and
|
|
206
|
+
// `git --git-dir <checkout>` moves it towards the guarded one. A resolution taken from `cwd` refused
|
|
207
|
+
// the first and let the second straight through, which is the bypass review round 1 demonstrated.
|
|
208
|
+
//
|
|
209
|
+
// The rotation is how a POSIX shell function keeps only its first `n` arguments: each of the first
|
|
210
|
+
// `n` is moved to the end, and everything left in front of them is then dropped. A function has its
|
|
211
|
+
// own positional parameters, so the shim's `$@` is untouched and still `exec`s intact.
|
|
212
|
+
function resolver_lines(git_binary: string): Array<string> {
|
|
213
|
+
return [
|
|
214
|
+
'guard_dir_of() {',
|
|
215
|
+
'\tguard_kept=$1',
|
|
216
|
+
'\tshift',
|
|
217
|
+
'\tguard_i=0',
|
|
218
|
+
'\twhile [ "$guard_i" -lt "$guard_kept" ]; do',
|
|
219
|
+
'\t\tguard_head=$1',
|
|
220
|
+
'\t\tshift',
|
|
221
|
+
'\t\tset -- "$@" "$guard_head"',
|
|
222
|
+
'\t\tguard_i=$((guard_i + 1))',
|
|
223
|
+
'\tdone',
|
|
224
|
+
'\twhile [ "$#" -gt "$guard_kept" ]; do shift; done',
|
|
225
|
+
`\t${shim_shell.quoted(git_binary)} "$@" rev-parse --absolute-git-dir 2>/dev/null`,
|
|
226
|
+
'}',
|
|
227
|
+
]
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Finding 2, asked only when finding 1 found nothing — a contaminated environment is already a
|
|
231
|
+
// refusal, and asking git where it would write costs a process.
|
|
232
|
+
function target_lines(guarded_directory: string): Array<string> {
|
|
233
|
+
const quoted_directory = shim_shell.quoted(guarded_directory)
|
|
234
|
+
|
|
235
|
+
return [
|
|
236
|
+
'if [ -z "$guard_via" ]; then',
|
|
237
|
+
'\tguard_dir=$(guard_dir_of "$guard_seen" "$@")',
|
|
238
|
+
'\tcase "$guard_dir" in',
|
|
239
|
+
`\t\t${quoted_directory}|${quoted_directory}/*) guard_via="a working directory inside $guard_dir" ;;`,
|
|
240
|
+
'\tesac',
|
|
241
|
+
'fi',
|
|
242
|
+
]
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function refusal_lines(log_file: string): Array<string> {
|
|
246
|
+
return [
|
|
247
|
+
'if [ -n "$guard_via" ]; then',
|
|
248
|
+
`\t${shim_shell.record_line(log_file, RECORDED_WRITE)}`,
|
|
249
|
+
`\techo ${shim_shell.quoted(BLOCKED_WRITE_MESSAGE)} >&2`,
|
|
250
|
+
`\techo " refused: ${REFUSED_COMMAND}" >&2`,
|
|
251
|
+
'\texit 1',
|
|
252
|
+
'fi',
|
|
253
|
+
]
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
interface WriteGuard {
|
|
257
|
+
log_file: string
|
|
258
|
+
guarded_directory: string | undefined
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// Finding 1, with the two variables it answers through declared empty first.
|
|
262
|
+
function environment_findings(): Array<string> {
|
|
263
|
+
return [
|
|
264
|
+
"guard_env=''",
|
|
265
|
+
...environment_lines(),
|
|
266
|
+
"guard_via=''",
|
|
267
|
+
'[ -z "$guard_env" ] || guard_via="an inherited git environment:$guard_env"',
|
|
268
|
+
]
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Finding 1 on its own, which is also the whole of the ambiguous arm.
|
|
272
|
+
function environment_guard_lines(log_file: string): Array<string> {
|
|
273
|
+
return [...environment_findings(), ...refusal_lines(log_file)]
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// The whole `sh` body of the shim's writing-subcommand arm, unindented — the caller indents it into
|
|
277
|
+
// the `case` the way it does the blocking lines it already had. Finding 1 then finding 2, with the
|
|
278
|
+
// refusal after both, so the cheap one answers first and the process is spawned only when it must be.
|
|
279
|
+
function write_guard_lines(guard: WriteGuard): Array<string> {
|
|
280
|
+
const { guarded_directory } = guard
|
|
281
|
+
|
|
282
|
+
if (guarded_directory === undefined) return environment_guard_lines(guard.log_file)
|
|
283
|
+
|
|
284
|
+
return [
|
|
285
|
+
...environment_findings(),
|
|
286
|
+
...target_lines(guarded_directory),
|
|
287
|
+
...refusal_lines(guard.log_file),
|
|
288
|
+
]
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// The shim's prelude: the resolver, where there is a repository to resolve against.
|
|
292
|
+
function prelude_lines(git_binary: string, guarded_directory: string | undefined): Array<string> {
|
|
293
|
+
return guarded_directory === undefined ? [] : resolver_lines(git_binary)
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// Which heading a recorded line belongs under. The record is shared with the network guard, so the
|
|
297
|
+
// marker is what tells the two apart at teardown.
|
|
298
|
+
function is_write_violation(call: string): boolean {
|
|
299
|
+
return call.startsWith(WRITE_MARKER)
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
const test_repository_guard = {
|
|
303
|
+
BLOCKED_WRITE_MESSAGE,
|
|
304
|
+
GIT_AMBIGUOUS_SUBCOMMANDS,
|
|
305
|
+
GIT_WRITING_SUBCOMMANDS,
|
|
306
|
+
RESOLUTION_HEADING,
|
|
307
|
+
WRITE_MARKER,
|
|
308
|
+
WRITE_VIOLATION_HEADING,
|
|
309
|
+
environment_guard_lines,
|
|
310
|
+
guarded_git_directory,
|
|
311
|
+
is_write_violation,
|
|
312
|
+
prelude_lines,
|
|
313
|
+
write_guard_lines,
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
export { test_repository_guard }
|
|
317
|
+
export type { WriteGuard }
|