@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,793 @@
|
|
|
1
|
+
import { investigation_reads } from '#scripts/delegation/investigation-reads'
|
|
2
|
+
import { hook_decision, type GuardRun, type TranscriptGuardSpec } from '#scripts/josh/hook-decision'
|
|
3
|
+
import { lane_guard_policy } from '#scripts/lane/lane-guard-policy'
|
|
4
|
+
import { time_batch_guard, type GuardedCall } from '#scripts/time-runtime/time-batch-guard'
|
|
5
|
+
import { bash_triggers } from './bash-triggers'
|
|
6
|
+
import { early_heartbeat } from './early-heartbeat'
|
|
7
|
+
import { file_body } from './file-body'
|
|
8
|
+
import { filing_cap } from './filing-cap'
|
|
9
|
+
import { gh_api } from './gh-api'
|
|
10
|
+
import { git_force } from './git-force'
|
|
11
|
+
import { implementation_cut } from './implementation-cut'
|
|
12
|
+
import { issue_fold } from './issue-fold'
|
|
13
|
+
import { issue_scout } from './issue-scout'
|
|
14
|
+
import { josh_git_bare } from './josh-git-bare'
|
|
15
|
+
import { lane_carry_conflict } from './lane-carry-conflict'
|
|
16
|
+
import { lane_interactive_ask } from './lane-interactive-ask'
|
|
17
|
+
import { lane_park } from './lane-park'
|
|
18
|
+
import { lane_switch_main } from './lane-switch-main'
|
|
19
|
+
import { oracle_consulted } from './oracle-consulted'
|
|
20
|
+
import { piped_verification } from './piped-verification'
|
|
21
|
+
import { poll_loop } from './poll-loop'
|
|
22
|
+
import { pre_gate_cut } from './pre-gate-cut'
|
|
23
|
+
import { prior_comment_read } from './prior-comment-read'
|
|
24
|
+
import { raw_field_body } from './raw-field-body'
|
|
25
|
+
import { rule_body_guard } from './rule-body-guard'
|
|
26
|
+
import { run_tail } from './run-tail'
|
|
27
|
+
import { shell_body_trigger } from './shell-body-trigger'
|
|
28
|
+
import { shell_segments } from './shell-segments'
|
|
29
|
+
import { test_declared_commit } from './test-declared-commit'
|
|
30
|
+
import { third_party_write } from './third-party-write'
|
|
31
|
+
import { worktree_guard } from './worktree-guard'
|
|
32
|
+
|
|
33
|
+
// The enumeration of rules delivered at the moment they bind, rather than carried resident in
|
|
34
|
+
// `CLAUDE.md` on every turn (joshuafolkken/kit#1524).
|
|
35
|
+
//
|
|
36
|
+
// **It exists because residency ran out and delivery did not.** `CLAUDE.md` sits 6 tokens under the
|
|
37
|
+
// ceiling `scripts/claude/workflow-skills.test.ts` enforces, while `prompts/` and `.claude/skills/` hold
|
|
38
|
+
// fifteen times as much on demand — so the pressure is on the one channel that costs every turn.
|
|
39
|
+
// joshuafolkken/kit#1344 measured three consecutive runs in which resident prose about batching moved
|
|
40
|
+
// the number not at all, and joshuafolkken/kit#1460 measured the same for the investigation
|
|
41
|
+
// threshold; in both, a `PreToolUse` refusal was what finally moved it. A rule whose trigger can be
|
|
42
|
+
// named is therefore cheaper **and** stronger delivered than carried.
|
|
43
|
+
//
|
|
44
|
+
// **No new machinery.** `hook_decision.create_transcript_guard` is the shell both existing guards
|
|
45
|
+
// already share (joshuafolkken/kit#1460) — the payload schema, the deny envelope, the switch, the
|
|
46
|
+
// `.env` load and the once-per-run stamp — and every entry below is one of its specs. Building a
|
|
47
|
+
// second delivery path would be the clone `CLAUDE.md` prohibits, in the one place where two paths
|
|
48
|
+
// would disagree about whether a rule was delivered at all.
|
|
49
|
+
//
|
|
50
|
+
// **What this file is not.** It holds no rule *text* that exists nowhere else: each entry's reason is
|
|
51
|
+
// the trigger plus the instruction that must be obeyed before anything else is read, and names the
|
|
52
|
+
// topic file that carries the procedure — the same "trigger plus pointer" shape a resident rule takes
|
|
53
|
+
// (`prompts/collaboration-workflow/residency.md`).
|
|
54
|
+
|
|
55
|
+
// The escape hatch, on by default like the other two guards. A distributed convention nobody enabled
|
|
56
|
+
// would leave this Issue where it started.
|
|
57
|
+
const SWITCH_ENV_KEY = 'JOSH_RULE_GUARD'
|
|
58
|
+
|
|
59
|
+
// **What a compliance test is asked of: the call, the turn it went out in, and the run it belongs
|
|
60
|
+
// to** — the calls the same assistant message issued, and every call the run made
|
|
61
|
+
// (joshuafolkken/kit#1792 for the turn, joshuafolkken/kit#1867 for the run). Every row but two answers
|
|
62
|
+
// from the call alone and simply ignores the rest, which is why widening the one signature costs them
|
|
63
|
+
// nothing. **The batching rule cannot be written without the turn**: its subject is *how many calls a
|
|
64
|
+
// turn carried*, and no field of a single call says that. **The pre-gate cut cannot be written without
|
|
65
|
+
// the run**: a cut relaunches a second process that issues the identical entry check, so the two
|
|
66
|
+
// halves are separable only by a call one of them makes elsewhere in the run. In both cases the
|
|
67
|
+
// alternative was a second predicate slot beside this one, i.e. two ways to declare the same thing.
|
|
68
|
+
type CallTest = (
|
|
69
|
+
call: GuardedCall,
|
|
70
|
+
turn: ReadonlyArray<GuardedCall>,
|
|
71
|
+
run: ReadonlyArray<GuardedCall>,
|
|
72
|
+
) => boolean
|
|
73
|
+
|
|
74
|
+
// One rule delivered by trigger. `id` keys its own refusal record, so one rule firing never spends
|
|
75
|
+
// another's budget.
|
|
76
|
+
interface DeliveredRule {
|
|
77
|
+
id: string
|
|
78
|
+
// Whether this call is the moment the rule binds, judged from the call alone.
|
|
79
|
+
is_trigger: (call: GuardedCall) => boolean
|
|
80
|
+
// What the model is told. The deny reason is the only text that reaches it, so it carries the
|
|
81
|
+
// instruction and the pointer rather than a summary of either.
|
|
82
|
+
reason: string
|
|
83
|
+
// **A stand-down read from the transcript tail, not the call** (joshuafolkken/kit#1905). A rule
|
|
84
|
+
// whose subject a run can *satisfy earlier in the run* — the comments read on the first open, so a
|
|
85
|
+
// later body read of the same Issue asks for nothing new — supplies this so the delivery is
|
|
86
|
+
// suppressed once that earlier act is on the tail. It is checked before `is_first_delivery`, so a
|
|
87
|
+
// satisfied call neither refuses nor spends the once-per-run record. Absent, delivery is unchanged.
|
|
88
|
+
already_satisfied?: (tail: string, call: GuardedCall) => boolean
|
|
89
|
+
// **A rule that has to bind on every occurrence supplies this, and once-per-run stops applying to
|
|
90
|
+
// it** (joshuafolkken/kit#1570). Once per run is right for a rule a run then obeys — read the
|
|
91
|
+
// comments, count the Issues, put the body in a file — because the refusal changes what the run
|
|
92
|
+
// knows. It is wrong for one whose subject is a *recurring* act: refused once and free
|
|
93
|
+
// afterwards, the enforcement is back to the parent's self-restraint, which is the thing that
|
|
94
|
+
// failed. A row with this field is asked it instead, and it is asked on every candidate call —
|
|
95
|
+
// `can_record` is what the batching stand-aside becomes for such a row (see `delivery_decision`).
|
|
96
|
+
// **`delivered_at_ms` is this row's own last refusal instant** (joshuafolkken/kit#2385) — `fire_once`
|
|
97
|
+
// writes the stamp only when a refusal actually fired, so a row that fires per crossing but must let
|
|
98
|
+
// an immediate reissue through (the implementation-phase cut) can tell a fresh crossing from a
|
|
99
|
+
// reissue of the edit it just refused. Rows that refuse unconditionally ignore it.
|
|
100
|
+
decide?: (call: GuardedCall, run: GuardRun, can_record: boolean, at_ms: number) => boolean
|
|
101
|
+
// **What keeping this rule looks like, as a call** (joshuafolkken/kit#1525). It names the act the
|
|
102
|
+
// rule asks for, so a run that made it *before* the trigger fired can be told apart from one that
|
|
103
|
+
// complied only because the refusal made it. `scripts/rules/rule-value.ts` reads that difference
|
|
104
|
+
// off recorded sessions to score what the rule's carried text earns unaided; a row that declares
|
|
105
|
+
// none is reported unmeasured rather than scored, because "never kept" and "always kept" are both
|
|
106
|
+
// claims the absence of a predicate does not support. It lives here rather than in the
|
|
107
|
+
// measurement so a rule's trigger and its compliance test stay one definition.
|
|
108
|
+
keeps?: CallTest
|
|
109
|
+
// **The occasion the rule governs, read in either spelling** (joshuafolkken/kit#1643).
|
|
110
|
+
// `is_trigger` is the right denominator for a rule whose trigger is a *neutral* act — filing an
|
|
111
|
+
// Issue, reading one — because a run that keeps the rule makes that call too. It is the wrong one
|
|
112
|
+
// for a rule whose trigger is the violation itself: a run that backgrounded every push never trips
|
|
113
|
+
// `run-tail`, so it drops out of the reading altogether and the rate is taken over runs that broke
|
|
114
|
+
// the rule at least once. Such a row declares this instead, and `scripts/rules/rule-value.ts`
|
|
115
|
+
// counts a run that reached it whether or not the trigger fired. Absent, the denominator stays
|
|
116
|
+
// `is_trigger` and the row's reading is exactly what it was.
|
|
117
|
+
reaches?: CallTest
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// **A rule the measurement scores, whether or not `pnpm josh rule:guard` is what delivers it**
|
|
121
|
+
// (joshuafolkken/kit#1792). `DELIVERED_RULES` is the *delivery* registry — every row in it becomes a
|
|
122
|
+
// live `PreToolUse` guard through `GUARDS` below — so a rule already delivered by a binary of its own
|
|
123
|
+
// cannot join it without being refused twice for one violation, each refusal spending a record the
|
|
124
|
+
// other cannot see. The batching guard is that rule: `pnpm josh batch:guard` has delivered it since
|
|
125
|
+
// joshuafolkken/kit#1344, and until now it was the one delivered rule `pnpm josh rule:value` could
|
|
126
|
+
// not read. So the two registries are separated rather than merged, and `is_trigger` — the field
|
|
127
|
+
// that only a *delivered* row needs, because it is what `guard_of` makes the candidate test from —
|
|
128
|
+
// becomes the one optional field here.
|
|
129
|
+
type MeasuredRule = Omit<DeliveredRule, 'is_trigger'> & {
|
|
130
|
+
is_trigger?: DeliveredRule['is_trigger']
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const STAMP_PREFIX = 'josh-rule-guard-'
|
|
134
|
+
|
|
135
|
+
// **`is_issue_filing` and `on_bash_command` moved to `bash-triggers.ts`** (joshuafolkken/kit#2119):
|
|
136
|
+
// three rows now share the filing trigger — the WIP cap, the scout gate and the per-run filing cap —
|
|
137
|
+
// and the last two live in their own modules, which could not import the enumeration back to reach a
|
|
138
|
+
// private function of it. `on_bash_command` went with it because those modules build their own rows.
|
|
139
|
+
const { is_issue_filing, on_bash_command } = bash_triggers
|
|
140
|
+
|
|
141
|
+
// The whole of the WIP cap, in the shape a refusal can carry: the count, the refusal, the two
|
|
142
|
+
// exemptions and the three tests that decide the second one. The three tests are spelled out rather
|
|
143
|
+
// than named, because a delivery that said only "an interrupt is exempt" would hand the deciding back
|
|
144
|
+
// to judgement at exactly the moment nothing else is open to read (joshuafolkken/kit#1518).
|
|
145
|
+
const WIP_CAP_REASON =
|
|
146
|
+
"⛔ backlog WIP cap: count the target repository's open Issues before filing. With more than 30 " +
|
|
147
|
+
'open, close one first; nothing honestly closable means do not file. Two filings are exempt and ' +
|
|
148
|
+
'proceed while stating the overage — one the run is blocked by, and an interrupt, decided by ' +
|
|
149
|
+
'three tests rather than judgement: a verification answers wrongly, a documented workflow cannot ' +
|
|
150
|
+
'complete, or data is lost or written outside the repository. Meeting none of the three, the ' +
|
|
151
|
+
'finding is discretionary and waits. The count command and both procedures are in ' +
|
|
152
|
+
'`prompts/collaboration-workflow/wip-cap.md`. Reissue this call once you have counted — it fires ' +
|
|
153
|
+
'once per run and cannot repeat on the call in hand.'
|
|
154
|
+
|
|
155
|
+
// **A shell line carries several commands, and the subcommand has to be the one being invoked.**
|
|
156
|
+
// Each segment is judged on its own, anchored at its start, so `gh issue comment <N> -b "… gh issue
|
|
157
|
+
// view <N> …"` is read as the write it is rather than as the read it quotes. The cut itself is
|
|
158
|
+
// `shell-segments.ts`, shared with the triggers that need the same one.
|
|
159
|
+
// Global flags may precede the subcommand (`gh --repo o/r issue view 1`), so they are skipped —
|
|
160
|
+
// the same optional-flag prefix `gh-api.ts` skips in front of `api`, shared from there.
|
|
161
|
+
const ISSUE_VIEW_COMMAND = new RegExp(String.raw`^gh\s+${gh_api.GH_FLAGS}issue\s+view\s`, 'u')
|
|
162
|
+
// `…/issues/<N>` — **one** Issue's body. The number has to end the path, so the listing
|
|
163
|
+
// (`…/issues`) and every sub-resource under it (`…/issues/1319/comments`) are left alone.
|
|
164
|
+
const ISSUE_BODY_PATH = /repos\/[^\s'"]*\/issues\/\d+(?=$|["'\s])/u
|
|
165
|
+
// **A write to that path is not a read of it**, which is why the body read below asks `gh_api.is_read`:
|
|
166
|
+
// `gh api` sends POST as soon as any field flag appears, and `kickoff` PATCHes `…/issues/<N>` to
|
|
167
|
+
// normalize a title and to fill a blank body — so without the read check the delivery would be spent
|
|
168
|
+
// refusing a write, and the genuine body read later in the same run would never be guarded.
|
|
169
|
+
// A segment that fetches comments: the flag, a `comments` field in a `--json` projection, or the
|
|
170
|
+
// comments endpoint. The short `-c` is deliberately absent — it belongs to `wc`, `grep` and `sort`
|
|
171
|
+
// far more often than to `gh`, and reading it as "comments included" silenced the rule on any line
|
|
172
|
+
// that ended in a pipe. A run that types it pays one round trip instead.
|
|
173
|
+
const FETCHES_COMMENTS = /--comments\b|--json\s[\w,]*\bcomments\b|\/comments\b/u
|
|
174
|
+
const ISSUES_PATH = /repos\/[^\s'"]*\/issues\//u
|
|
175
|
+
|
|
176
|
+
// A field projection — `--jq` for `gh api`, `--json` for `gh issue view` — whose value never names the
|
|
177
|
+
// body. `gh api …/issues/<N> --jq '{state, labels}'` fetches the Issue only to read its state or its
|
|
178
|
+
// labels, which is a state check and not the body read this rule guards (joshuafolkken/kit#1905); a
|
|
179
|
+
// `--jq '.body'` still names the body and stays a body read. The value is taken quoted or bare, so the
|
|
180
|
+
// comma list `--json state,labels` and the expression `'{state, labels}'` are read the same way.
|
|
181
|
+
const FIELD_PROJECTION = /(?:--jq|--json)[= ]\s*('[^']*'|"[^"]*"|\S+)/u
|
|
182
|
+
const NAMES_THE_BODY = /\bbody\b/u
|
|
183
|
+
|
|
184
|
+
function projects_away_body(segment: string): boolean {
|
|
185
|
+
const projection = FIELD_PROJECTION.exec(segment)
|
|
186
|
+
|
|
187
|
+
return projection !== null && !NAMES_THE_BODY.test(projection[1] ?? '')
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function is_body_read_segment(segment: string): boolean {
|
|
191
|
+
if (projects_away_body(segment)) return false
|
|
192
|
+
|
|
193
|
+
if (ISSUE_VIEW_COMMAND.test(segment)) return true
|
|
194
|
+
|
|
195
|
+
return gh_api.is_gh_api(segment) && ISSUE_BODY_PATH.test(segment) && gh_api.is_read(segment)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// **An Issue's comments, not just any comments.** Batching pushes a run to fetch the body and the
|
|
199
|
+
// comments on one line, so the allowance has to reach across segments — but `gh pr view 42 --json
|
|
200
|
+
// comments` says nothing about whether *this* Issue was read whole, so the segment doing the
|
|
201
|
+
// fetching has to be an Issue read itself.
|
|
202
|
+
function fetches_issue_comments(segment: string): boolean {
|
|
203
|
+
if (!FETCHES_COMMENTS.test(segment)) return false
|
|
204
|
+
|
|
205
|
+
return (
|
|
206
|
+
ISSUE_VIEW_COMMAND.test(segment) || (gh_api.is_gh_api(segment) && ISSUES_PATH.test(segment))
|
|
207
|
+
)
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// **The trigger is the body read, not the start of implementation.** The moment an Issue's body
|
|
211
|
+
// reaches a run is the moment the rule binds, and it is one shell call — the test
|
|
212
|
+
// `prompts/collaboration-workflow/rule-delivery.md` sets for leaving residency.
|
|
213
|
+
function is_body_only_issue_read(command: string): boolean {
|
|
214
|
+
const segments = shell_segments.segments_of(command)
|
|
215
|
+
|
|
216
|
+
if (segments.some((segment) => fetches_issue_comments(segment))) return false
|
|
217
|
+
|
|
218
|
+
return segments.some((segment) => is_body_read_segment(segment))
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// **The refusal hands over the command that fixes it**, because reading is not the same as
|
|
222
|
+
// obeying: a sentence saying "also read the comments" is prose of exactly the kind
|
|
223
|
+
// joshuafolkken/kit#1344 measured as moving nothing, while a refused body read leaves the run
|
|
224
|
+
// holding the reissue that makes the comments *present*. The conflict rule ships with it — a
|
|
225
|
+
// delivery that said only "read them" would hand back the deciding at the moment nothing else is
|
|
226
|
+
// open to read, the mistake joshuafolkken/kit#1518 corrected for the WIP cap.
|
|
227
|
+
const ISSUE_COMMENTS_REASON =
|
|
228
|
+
"⛔ an Issue's comments are part of the Issue: read them before implementing, not only the body. " +
|
|
229
|
+
'A decision recorded after the body was written lives only in a comment — a corrected diagnosis ' +
|
|
230
|
+
'(joshuafolkken/kit#1537), a changed default and an added acceptance criterion ' +
|
|
231
|
+
'(joshuafolkken/kit#1520), a scope handed to another Issue (joshuafolkken/kit#1304) — and ' +
|
|
232
|
+
'nothing in the body says it was superseded, so a body-only reader builds the wrong thing and ' +
|
|
233
|
+
'sees no contradiction. Reissue this read with the comments included: ' +
|
|
234
|
+
"`gh api repos/{owner}/{repo}/issues/<N>/comments --jq '.[] | {user: .user.login, created_at, " +
|
|
235
|
+
"body}'` beside the body read, or `gh issue view <N> --comments` where GraphQL is reachable. " +
|
|
236
|
+
'Then the later text is the agreement in force — a comment supersedes the body it contradicts — ' +
|
|
237
|
+
"except for two answers that are not the run's to make: work a comment reassigns to another " +
|
|
238
|
+
'Issue is out of scope and is not implemented, and a comment saying the Issue no longer has a ' +
|
|
239
|
+
'reason to exist stops the run with a `confirmation` Telegram. The procedure is ' +
|
|
240
|
+
'`.claude/skills/workflow-commands/SKILL.md` → "An Issue\'s comments are part of the Issue". It ' +
|
|
241
|
+
'fires once per run and cannot repeat on the call in hand.'
|
|
242
|
+
|
|
243
|
+
// The reading of the call itself — which spellings carry a body inline, and what the shell does to
|
|
244
|
+
// the value — is `shell-body-trigger.ts`, beside its own cases, as is the refusal text. A row states
|
|
245
|
+
// its trigger and its text; a model of zsh quoting is more than a row.
|
|
246
|
+
const { SHELL_BODY_REASON, carries_a_body, is_shell_evaluated_body, keeps_body_safe } =
|
|
247
|
+
shell_body_trigger
|
|
248
|
+
|
|
249
|
+
// **Keeping the WIP cap is counting the open Issues**, which is the one act the rule asks for before
|
|
250
|
+
// a filing.
|
|
251
|
+
//
|
|
252
|
+
// **It has to be Issues, open, and a listing — all three, in one segment.** A pattern that took any
|
|
253
|
+
// of them alone scored `gh pr list --state open` and `epic:bundle`'s candidate search as the count,
|
|
254
|
+
// and those inflate exactly the ratio the retirement decision reads. `gh issue list` alone is not
|
|
255
|
+
// enough either: the cap is about *open* Issues, and a listing that does not say so is some other
|
|
256
|
+
// question. Segment-wise like the comments predicate, so a spelling quoted inside a filing's body
|
|
257
|
+
// is not read as the count that filing skipped.
|
|
258
|
+
const ISSUE_LISTING = /^gh\s+(?:-{1,2}[\w-]+(?:[= ]\S+)?\s+)*issue\s+list\b/u
|
|
259
|
+
const ISSUES_QUERY = /repos\/[^\s'"]*\/issues\?[^\s'"]*state=open/u
|
|
260
|
+
const OPEN_STATE = /--state[= ]open|state=open/u
|
|
261
|
+
// **A label filter makes it a different question.** `gh issue list --label epic --state open` and
|
|
262
|
+
// `…/issues?labels=epic&state=open` ask which epics are open, which is what `epic:bundle` and the
|
|
263
|
+
// Issue template do; counting either as the WIP count would credit the cap as kept by a run that
|
|
264
|
+
// never counted the backlog. The residual the pattern cannot separate is named in
|
|
265
|
+
// `docs/josh-commands.md`: the inventory command in the `diag` skill is byte-identical to the count
|
|
266
|
+
// command in `wip-cap.md`, so no pattern can tell those two apart.
|
|
267
|
+
const LABEL_FILTER = /--label\b|[?&]labels=/u
|
|
268
|
+
|
|
269
|
+
function counts_open_issues(command: string): boolean {
|
|
270
|
+
return shell_segments.segments_of(command).some((segment) => {
|
|
271
|
+
if (LABEL_FILTER.test(segment)) return false
|
|
272
|
+
|
|
273
|
+
return (ISSUE_LISTING.test(segment) && OPEN_STATE.test(segment)) || ISSUES_QUERY.test(segment)
|
|
274
|
+
})
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// **Keeping the comments rule is fetching them**, in any of the spellings the refusal hands back.
|
|
278
|
+
function reads_issue_comments(command: string): boolean {
|
|
279
|
+
return shell_segments.segments_of(command).some((segment) => fetches_issue_comments(segment))
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// **The occasion the pre-gate cut governs, in the one shape that separates a cut run's two halves**
|
|
283
|
+
// (joshuafolkken/kit#1867). Asking about the cut is what a lane child does whatever it goes on to do;
|
|
284
|
+
// claiming the working tree is what only the process on the near side of the boundary does, because
|
|
285
|
+
// the `resume` verdict tells its counterpart to skip that claim. A run doing both reached the
|
|
286
|
+
// boundary; a run that asked without claiming is the session the cut produced, which had no cut of
|
|
287
|
+
const DELIVERED_RULES: ReadonlyArray<DeliveredRule> = [
|
|
288
|
+
// **Listed first, ahead of the filing trigger it overlaps** (joshuafolkken/kit#2122). A `gh api`
|
|
289
|
+
// that files an Issue into a repository we do not own trips both this row and `wip-cap` /
|
|
290
|
+
// `issue-scout` / `filing-cap` — but the backlog count, the scout and the per-run cap are all about
|
|
291
|
+
// filing into *our own* backlog, so on a third-party target the right answer is to stop the write
|
|
292
|
+
// entirely rather than to count anything. Placing it first means a third-party write is refused
|
|
293
|
+
// before any of those speak; on a first-party filing it is silent (the owners match), so `wip-cap`
|
|
294
|
+
// still speaks first, exactly as before. It fires on every occurrence (`git-force.ts`).
|
|
295
|
+
third_party_write.ROW,
|
|
296
|
+
{
|
|
297
|
+
id: 'wip-cap',
|
|
298
|
+
is_trigger: on_bash_command(is_issue_filing),
|
|
299
|
+
reason: WIP_CAP_REASON,
|
|
300
|
+
keeps: on_bash_command(counts_open_issues),
|
|
301
|
+
},
|
|
302
|
+
// **Three rows share the filing trigger** (joshuafolkken/kit#2119), listed after `wip-cap` so the
|
|
303
|
+
// backlog count still speaks first: `issue-scout` refuses a filing the run has not scouted (once per
|
|
304
|
+
// run, stood down once the scout is on the tail), and `filing-cap` refuses every filing past the
|
|
305
|
+
// per-run ceiling. Each is a real instance of the admissible overlap the comment on `delivery`
|
|
306
|
+
// describes — the losing rule's delivery is still correct one reissue later — so a scout-less,
|
|
307
|
+
// over-cap filing is delivered `wip-cap`, then `issue-scout`, then `filing-cap` across its reissues.
|
|
308
|
+
issue_scout.ROW,
|
|
309
|
+
filing_cap.ROW,
|
|
310
|
+
// **`issue-fold` shares the same filing trigger** (joshuafolkken/kit#2213), listed after
|
|
311
|
+
// `filing-cap`: it refuses a *second* filing the run has not folded, once per run, stood down off
|
|
312
|
+
// the tail when the run has already folded or has filed nothing earlier. It is another instance of
|
|
313
|
+
// the admissible overlap — the losing rule's delivery is still correct one reissue later — so a
|
|
314
|
+
// scout-less, unfolded, over-cap second filing is delivered `wip-cap`, then `issue-scout`, then
|
|
315
|
+
// `filing-cap`, then `issue-fold` across its reissues.
|
|
316
|
+
issue_fold.ROW,
|
|
317
|
+
{
|
|
318
|
+
id: 'issue-comments',
|
|
319
|
+
is_trigger: on_bash_command(is_body_only_issue_read),
|
|
320
|
+
reason: ISSUE_COMMENTS_REASON,
|
|
321
|
+
already_satisfied: prior_comment_read.already_read_for_call,
|
|
322
|
+
keeps: on_bash_command(reads_issue_comments),
|
|
323
|
+
},
|
|
324
|
+
{
|
|
325
|
+
id: 'shell-body',
|
|
326
|
+
is_trigger: on_bash_command(is_shell_evaluated_body),
|
|
327
|
+
reason: SHELL_BODY_REASON,
|
|
328
|
+
keeps: on_bash_command(keeps_body_safe),
|
|
329
|
+
reaches: on_bash_command(carries_a_body),
|
|
330
|
+
},
|
|
331
|
+
// **The sibling of `shell-body`, one call further along** (joshuafolkken/kit#2304). `shell-body`
|
|
332
|
+
// refuses a body passed inline so the shell evaluates it; this refuses a body passed by path with
|
|
333
|
+
// the raw field flag (`-f` / `--raw-field body=@<path>`), which posts the literal `@<path>`. It
|
|
334
|
+
// claims no command any row above does — `shell-body` triggers on a backtick or `$`, which the
|
|
335
|
+
// `@<path>` misfire carries neither, and `is_issue_filing` leaves the comment endpoint alone — so
|
|
336
|
+
// the exactly-one-rule invariant over its fixtures holds. It fires on every occurrence (`git-force.ts`).
|
|
337
|
+
raw_field_body.ROW,
|
|
338
|
+
{
|
|
339
|
+
id: 'piped-verification',
|
|
340
|
+
is_trigger: on_bash_command(piped_verification.is_masked_verification),
|
|
341
|
+
reason: piped_verification.PIPED_VERIFICATION_REASON,
|
|
342
|
+
keeps: on_bash_command(piped_verification.keeps_verdict_intact),
|
|
343
|
+
reaches: on_bash_command(piped_verification.runs_verification),
|
|
344
|
+
},
|
|
345
|
+
{
|
|
346
|
+
id: 'early-heartbeat',
|
|
347
|
+
is_trigger: on_bash_command(early_heartbeat.is_wait_timer),
|
|
348
|
+
reason: early_heartbeat.EARLY_HEARTBEAT_REASON,
|
|
349
|
+
decide: early_heartbeat.decide,
|
|
350
|
+
keeps: on_bash_command(early_heartbeat.is_progress_watch),
|
|
351
|
+
reaches: on_bash_command(early_heartbeat.waits_for_progress),
|
|
352
|
+
},
|
|
353
|
+
// **Listed before `run-tail`, the one row it deliberately overlaps** (joshuafolkken/kit#2118). A
|
|
354
|
+
// foreground `pnpm josh git -y` with no test beside the change is claimed by both: `test-declared`
|
|
355
|
+
// decides whether the commit should happen at all, so it is listed first, exactly as `wip-cap`
|
|
356
|
+
// precedes `shell-body` for deciding whether an Issue should exist. Nothing is lost by `run-tail`
|
|
357
|
+
// losing the race — the stamps are keyed per `id`, so the reissued push is delivered `run-tail`,
|
|
358
|
+
// which is asserted rather than assumed. The overlap only arises in a real checkout where the
|
|
359
|
+
// verdict is `required`; in the hermetic non-repo suite the git read fails to `exempt`, so
|
|
360
|
+
// `test-declared` claims nothing and the "exactly one rule" invariant over `run-tail`'s fixture holds.
|
|
361
|
+
test_declared_commit.ROW,
|
|
362
|
+
// **The one row whose trigger reads a field of the input beside the command**, so it supplies its
|
|
363
|
+
// own tool-name check rather than going through `on_bash_command`: a push step already issued with
|
|
364
|
+
// `run_in_background` is the rule obeyed, and refusing it would charge a run for doing the right
|
|
365
|
+
// thing. It supplies `decide` because a push is a recurring act — one per child in a batch, and a
|
|
366
|
+
// second inside one `fullrun` when round 2 fixes a finding in place.
|
|
367
|
+
{
|
|
368
|
+
id: 'run-tail',
|
|
369
|
+
is_trigger: run_tail.is_foreground_push_step,
|
|
370
|
+
reason: run_tail.RUN_TAIL_REASON,
|
|
371
|
+
decide: run_tail.decide,
|
|
372
|
+
keeps: run_tail.is_backgrounded_push_step,
|
|
373
|
+
reaches: run_tail.is_push_step_call,
|
|
374
|
+
},
|
|
375
|
+
// **The one row whose trigger consults the world beside the command**, because "is this a lane that
|
|
376
|
+
// has not cut" is not readable from the call: it is the working directory's own name and the cut
|
|
377
|
+
// record on disk. Both reads are synchronous, and the command match runs first, so a run that never
|
|
378
|
+
// types `pnpm josh gate` pays nothing for it.
|
|
379
|
+
//
|
|
380
|
+
// **Once per run rather than `decide`, and the direction of the error is why.** Taking the cut ends
|
|
381
|
+
// the process, so this is not the recurring act joshuafolkken/kit#1570 wrote `decide` for — and the
|
|
382
|
+
// five verdicts that legitimately leave a run at the gate (`not-a-lane`, `unready`, `busy`,
|
|
383
|
+
// `failed`, `unknown`) all need the reissue to go through. A row that refused every time would wedge exactly
|
|
384
|
+
// those runs; a row that refuses once cannot.
|
|
385
|
+
//
|
|
386
|
+
// **`pnpm josh rule:value` read this row with a ceiling of about 50%, and joshuafolkken/kit#1867 is
|
|
387
|
+
// what removed it** (the ceiling was recorded here by joshuafolkken/kit#1864's review round 2). A
|
|
388
|
+
// cut relaunches a *new session*, which the measurement groups as a run of its own, and that
|
|
389
|
+
// resumed run issues the entry check — so scored on the asking alone it joined the denominator
|
|
390
|
+
// while never being able to satisfy `keeps`, which only the cutting run can, and ten perfectly
|
|
391
|
+
// obedient children read as ten kept out of twenty. **The two halves are separable, just not from
|
|
392
|
+
// one call**: both processes issue byte-identical `--resume` strings, but the `fresh` verdict sends
|
|
393
|
+
// a run on to claim the working-tree hold while the `resume` verdict tells its counterpart to skip
|
|
394
|
+
// that claim. `reaches_the_pre_gate_boundary` is that conjunction, and it is why `CallTest` is
|
|
395
|
+
// handed the run's calls beside the turn's rather than a second predicate slot of its own.
|
|
396
|
+
// Dropping `reaches` altogether is still strictly worse — the trigger evaluates against the
|
|
397
|
+
// *measuring* process's working directory, so it is always false from the main checkout and the row
|
|
398
|
+
// would read as no runs at all.
|
|
399
|
+
//
|
|
400
|
+
// **It overlaps `piped-verification` on a piped gate call, and the order is safe in both
|
|
401
|
+
// directions.** `pnpm josh gate | tail` in an uncut lane is a real instance of both defects; the
|
|
402
|
+
// earlier row speaks, its own reason says to reissue, and this one delivers on the reissue — the
|
|
403
|
+
// reading "the losing rule's delivery is still correct one call later" that the comment below
|
|
404
|
+
// requires of any admissible overlap.
|
|
405
|
+
{
|
|
406
|
+
id: 'pre-gate-cut',
|
|
407
|
+
is_trigger: on_bash_command(pre_gate_cut.is_uncut_gate),
|
|
408
|
+
reason: pre_gate_cut.PRE_GATE_CUT_REASON,
|
|
409
|
+
keeps: on_bash_command(pre_gate_cut.takes_the_cut),
|
|
410
|
+
reaches: pre_gate_cut.reaches_the_pre_gate_boundary,
|
|
411
|
+
},
|
|
412
|
+
// **The second row whose trigger consults the world beside the command** (joshuafolkken/kit#2034):
|
|
413
|
+
// "is this a dispatched lane child" is the dispatch mark against this checkout's own issue, read
|
|
414
|
+
// synchronously by `lane_child_marker.is_child_of`, and the command match runs first so an ordinary
|
|
415
|
+
// run pays nothing for it.
|
|
416
|
+
//
|
|
417
|
+
// **Once per run rather than `decide`, and no `already_satisfied`.** The stop ends the turn, so it
|
|
418
|
+
// is not the recurring act joshuafolkken/kit#1570 wrote `decide` for. It carries no
|
|
419
|
+
// `already_satisfied` because the park it asks for is a GitHub label a synchronous guard cannot
|
|
420
|
+
// read, and the transcript-tail alternative would read a child that merely *read*
|
|
421
|
+
// `backlogrun-park.md` — whose prose carries the `labels[]=needs-decision` command — as compliant
|
|
422
|
+
// and fall silent on a real violation. `lane-park.ts` states why one wasted reissue on the compliant
|
|
423
|
+
// path is the safe direction. `keeps` reads an actual label-application `Bash` command, never the
|
|
424
|
+
// tail, so it is not fooled the same way; `reaches` stays `is_trigger`, since a compliant run issues
|
|
425
|
+
// the same confirmation notify and belongs in the denominator.
|
|
426
|
+
{
|
|
427
|
+
id: 'lane-park',
|
|
428
|
+
is_trigger: on_bash_command(lane_park.is_unparked_stop),
|
|
429
|
+
reason: lane_park.LANE_PARK_REASON,
|
|
430
|
+
keeps: on_bash_command(lane_park.records_the_park),
|
|
431
|
+
},
|
|
432
|
+
// **joshuafolkken/kit#2034's rule, one tool-call earlier** (joshuafolkken/kit#2201). `lane-park`
|
|
433
|
+
// fires on the `confirmation` notify a routed child reaches; a child that reaches for
|
|
434
|
+
// `AskUserQuestion` never gets there, because the harness ends its turn at the refused ask. This
|
|
435
|
+
// row's trigger is that ask, so the refusal becomes an instruction — park the question — instead of
|
|
436
|
+
// the child's death. Its trigger reads the input's tool name and consults the dispatch mark, like
|
|
437
|
+
// `lane-park`, and shares no command with any Bash row, so it claims no `gh` / `git` / `josh` call.
|
|
438
|
+
// It fires on every occurrence (`decide` returns true), the disposition `git-force.ts` takes: an
|
|
439
|
+
// interactive ask must never succeed in a child, and the route is always the park, never a reissue.
|
|
440
|
+
lane_interactive_ask.ROW,
|
|
441
|
+
// **The parent budget commands a lane child must never run** (joshuafolkken/kit#2267). A dispatched
|
|
442
|
+
// child that ran `pnpm josh run:merge` read its `busy` as a competing session and parked its Issue
|
|
443
|
+
// unimplemented — but the live carry record is the parent that launched it, never a competitor. This
|
|
444
|
+
// row refuses `run:merge` / `run:carry` in a lane child and hands back the mechanical branch: the
|
|
445
|
+
// record is the parent's, so continue implementing rather than park or ask. Its trigger claims a
|
|
446
|
+
// `josh` subcommand no other row does (the filing rows are `gh`, `run-tail` is `git push`), so it
|
|
447
|
+
// overlaps nothing. It fires on every occurrence (`decide` returns true): a child must never run
|
|
448
|
+
// these, and the route is always "continue", never a reissue (`git-force.ts`).
|
|
449
|
+
lane_carry_conflict.ROW,
|
|
450
|
+
// **The `git switch main` a lane child can never succeed at** (joshuafolkken/kit#2313), the fifth of
|
|
451
|
+
// the "always fails" misfires joshuafolkken/kit#2297 catalogued. A lane is a linked work tree and the
|
|
452
|
+
// primary checkout holds the default branch, so a child's `git switch main` fails structurally
|
|
453
|
+
// (`already used by worktree`); this refuses it before it fails and hands back the next command —
|
|
454
|
+
// skip the step, `pnpm josh main:merge` brings the default in during the gate. Its trigger reads the
|
|
455
|
+
// dispatch mark and the lane branch like `lane-carry-conflict`, and claims a `git switch` no row
|
|
456
|
+
// above matches — `git-force` is `git push` / `git branch`, `worktree-mutation` is `git checkout --`
|
|
457
|
+
// / `restore` / `stash` — so no two rows claim one command. It fires on every occurrence (`decide`
|
|
458
|
+
// returns true): a child must never run this, and the route is always "continue" (`git-force.ts`).
|
|
459
|
+
lane_switch_main.ROW,
|
|
460
|
+
// **A `pnpm josh git` with no `-y` cannot succeed from an agent** (joshuafolkken/kit#2297). It
|
|
461
|
+
// prompts to confirm the staging, the no-TTY prompt cancels, and the run reissues with `-y` after
|
|
462
|
+
// throwing away the time it took to fail. This row refuses the bare call and hands back the `-y`
|
|
463
|
+
// form. It is disjoint from `run-tail` by the flag — that row requires `-y`, this refuses its
|
|
464
|
+
// absence — so no two rows claim one command. It fires on every occurrence (`decide` returns true):
|
|
465
|
+
// a bare call wastes the same time each time, so the route is always the `-y` reissue
|
|
466
|
+
// (`git-force.ts`).
|
|
467
|
+
josh_git_bare.ROW,
|
|
468
|
+
// **The three Bash-string gaps the deny glob cannot express** (joshuafolkken/kit#2120), each reading
|
|
469
|
+
// the command's argv rather than a literal a glob keys on. They share no trigger with any row above —
|
|
470
|
+
// force/delete is `git push` / `git branch`, the worktree change is `git checkout` / `restore` /
|
|
471
|
+
// `stash`, and the file body is a heredoc / `node -e` / `perl -i` — so no two rows claim one command,
|
|
472
|
+
// which `delivered-rules-bash.test.ts` pins. Each declares `decide` returning true: a destructive or
|
|
473
|
+
// billed act is refused on every occurrence, never once per run (`git-force.ts`).
|
|
474
|
+
git_force.ROW,
|
|
475
|
+
worktree_guard.ROW,
|
|
476
|
+
file_body.ROW,
|
|
477
|
+
// **The hand-written wait loop a lane child improvises over a backgrounded command's output**
|
|
478
|
+
// (joshuafolkken/kit#2371). `early-heartbeat` refuses a bare `sleep` and stands down on any loop
|
|
479
|
+
// keyword; this is the loop it left — a `while`/`until` that sleeps between probes of an output
|
|
480
|
+
// file. Its trigger claims a command no row above matches: the loop-plus-`sleep` shape carries no
|
|
481
|
+
// `gh` / `git` / `josh` subcommand any other trigger keys on, and a poll loop is never a bare
|
|
482
|
+
// `sleep` (the loop keyword makes `early-heartbeat.is_wait_timer` false), so the Bash
|
|
483
|
+
// `rules_claiming` invariant holds. It fires on every occurrence (`decide` returns true): a poll
|
|
484
|
+
// loop wastes the same round trips each time, so the route is always "background it and end the
|
|
485
|
+
// turn", never a reissue (`git-force.ts`).
|
|
486
|
+
poll_loop.ROW,
|
|
487
|
+
// **The second row whose trigger is an `Edit` / `Write` rather than a shell call**
|
|
488
|
+
// (joshuafolkken/kit#2310), and the third that consults the world beside the call: "is this a lane
|
|
489
|
+
// child whose recent-context cost has crossed the threshold" reads the dispatch mark, the cut record
|
|
490
|
+
// on disk and the synchronous `pnpm josh cost --cut` verdict — the same measurement the parent
|
|
491
|
+
// hand-off uses, never a second one (joshuafolkken/kit#1933). The `Edit` / `Write` name match runs
|
|
492
|
+
// first, then the lane read, then the transcript-priced verdict, so a run that is not a dispatched
|
|
493
|
+
// child in an uncut lane pays nothing for it. It self-gates on the tool name, so it claims no `Bash`
|
|
494
|
+
// command any row above matches — the Bash `rules_claiming` invariant is untouched.
|
|
495
|
+
//
|
|
496
|
+
// **Listed before `rule-body`, the one row it can overlap.** Both trigger on an `Edit` / `Write`; a
|
|
497
|
+
// rule-document edit made in a lane child that is already over threshold trips both. The cut is the
|
|
498
|
+
// right thing to do first — end the process and drop the accumulated context — and on the reissue in
|
|
499
|
+
// the fresh, under-threshold process this row is silent and `rule-body` delivers, the "losing rule's
|
|
500
|
+
// delivery still correct one reissue later" reading any admissible overlap needs.
|
|
501
|
+
//
|
|
502
|
+
// **It carries `decide`, and the inversion of the pre-gate cut's reasoning is why** (joshuafolkken/kit#2385).
|
|
503
|
+
// `pre-gate-cut` and `lane-park` are once per run because taking the cut, or the park, *ends the
|
|
504
|
+
// process* — the one act is not a recurring one, and the five verdicts that leave a run holding it
|
|
505
|
+
// all need the one reissue to go through. This cut ends the process too, but its *trigger* does not:
|
|
506
|
+
// crossing the threshold mid-implementation is a recurring state that once-per-run silenced for the
|
|
507
|
+
// rest of a process the moment its first refusal landed — so a `busy` / `failed` / `unready` verdict,
|
|
508
|
+
// or an edit the model reissued unchanged, left the context to grow unwatched (joshuafolkken/kit#2382
|
|
509
|
+
// ran to 282,747 tokens with the cut never taken). `decide` re-asks on every over-threshold edit, and
|
|
510
|
+
// its `delivered_at_ms` lets an edit reissued right after a refusal through, so `busy` / `failed`
|
|
511
|
+
// cannot wedge the run edit after edit — the reissue path once-per-run gave for free, now made
|
|
512
|
+
// explicit. The fresh process after a successful cut reads its own transcript under threshold, so it
|
|
513
|
+
// is silent without needing a carried record to quiet it.
|
|
514
|
+
//
|
|
515
|
+
// **No `reaches`, because the occasion is live-only.** `pre-gate-cut` gives a `reaches` because both
|
|
516
|
+
// its halves leave a command-string trace (`run:cut --resume` at entry); this row's occasion —
|
|
517
|
+
// crossing the threshold mid-implementation — is the working directory, the cut record and the cost
|
|
518
|
+
// verdict, none of which a transcript records. `pnpm josh rule:value` therefore reads it as no runs
|
|
519
|
+
// rather than as 0% kept (`keeps` stays, so the compliance act is named for a future measurement
|
|
520
|
+
// redesign), the same honest-unmeasured stance the batching and investigation rows take for the same
|
|
521
|
+
// reason: a trigger no transcript can reconstruct. The row itself lives in `implementation-cut.ts`.
|
|
522
|
+
implementation_cut.ROW,
|
|
523
|
+
// **The first row whose trigger is an `Edit` / `Write` rather than a shell call**
|
|
524
|
+
// (joshuafolkken/kit#2272). It delivers the residency questions at the edit that writes a rule into
|
|
525
|
+
// prose, and self-gates on the tool name and the file path, so it claims no `Bash` command any row
|
|
526
|
+
// above matches — the `rules_claiming` invariant over Bash fixtures is untouched. It carries no
|
|
527
|
+
// `decide`, so it is once per run and takes the batching stand-aside `is_first_delivery` gives every
|
|
528
|
+
// default row: the batching guard treats an `Edit` as a candidate, exactly as it treats an Issue
|
|
529
|
+
// read, so this row stands aside on a batched turn and delivers on the reissue.
|
|
530
|
+
rule_body_guard.ROW,
|
|
531
|
+
// **The generic oracle-consulted rows, one per oracle that declared a firing point**
|
|
532
|
+
// (joshuafolkken/kit#2324). Each refuses the action the oracle governs when the run has not run that
|
|
533
|
+
// oracle's command first, stood down once it has — `issue-scout`'s shape read from the registry
|
|
534
|
+
// rather than hand-written. Listed last so an oracle whose firing point overlaps a filing
|
|
535
|
+
// (`issue:lint`) delivers on the reissue, after `wip-cap` / `issue-scout` / `filing-cap` /
|
|
536
|
+
// `issue-fold` have each had their turn. The non-overlapping firing point (`pkg:scout` on a package
|
|
537
|
+
// add) claims a command no row above matches.
|
|
538
|
+
...oracle_consulted.ROWS,
|
|
539
|
+
]
|
|
540
|
+
|
|
541
|
+
// A turn that issued more than this many calls is a turn that batched. The guard counts turns that
|
|
542
|
+
// issued a *single* tool call, so the boundary is the same one `SEQUENCE_BEFORE_LIMIT` is counted in.
|
|
543
|
+
const ALONE_IN_TURN = 1
|
|
544
|
+
|
|
545
|
+
// **Keeping the batching rule is a refusable call that went out beside siblings** — the one
|
|
546
|
+
// compliance test of the seven that cannot be read off the call alone (joshuafolkken/kit#1792). The
|
|
547
|
+
// guard's whole subject is the run of turns that each issued one call, so the act it asks for is a
|
|
548
|
+
// turn carrying more than one, and `is_guarded_call` is what keeps the credit to calls the guard
|
|
549
|
+
// could actually have refused: a turn of two `Write`s is not the rule being kept, because neither
|
|
550
|
+
// call was ever at risk.
|
|
551
|
+
function batches_the_turn(call: GuardedCall, turn: ReadonlyArray<GuardedCall>): boolean {
|
|
552
|
+
return time_batch_guard.is_guarded_call(call) && turn.length > ALONE_IN_TURN
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
// **The row `pnpm josh rule:value` scores the batching guard from** (joshuafolkken/kit#1792). It is
|
|
556
|
+
// measured but not delivered, for the reason `MeasuredRule` states.
|
|
557
|
+
//
|
|
558
|
+
// **It declares no `is_trigger`, and that is the honest answer rather than a gap.** Whether a call
|
|
559
|
+
// would be refused depends on the turns *behind* it — `time_batch_guard.should_block` reads the
|
|
560
|
+
// transcript tail for exactly that — and `scripts/rules/rule-value.ts` hands a predicate one call at
|
|
561
|
+
// a time, so a call-shaped trigger here could only ever be a guess. What the transcript does record
|
|
562
|
+
// is the refusal itself, and the measurement takes that as the trigger: compliance credited after a
|
|
563
|
+
// refusal is the delivery's contribution, which is the same line every other row is scored on.
|
|
564
|
+
//
|
|
565
|
+
// **The `reaches` half is what keeps the reading off zero**, the failure joshuafolkken/kit#1643
|
|
566
|
+
// named. The batching guard fires only on the violation, so scored against its trigger the rate
|
|
567
|
+
// would be taken over runs that broke the rule at least once and would read near zero by
|
|
568
|
+
// construction — a manufactured retirement candidate for the most-cited resident rule there is. The
|
|
569
|
+
// occasion it governs is issuing a call the guard could refuse, in *either* spelling: alone in its
|
|
570
|
+
// turn, or beside the calls that did not need its result.
|
|
571
|
+
const BATCHING_RULE: MeasuredRule = {
|
|
572
|
+
id: 'batching',
|
|
573
|
+
reason: time_batch_guard.REASON,
|
|
574
|
+
keeps: batches_the_turn,
|
|
575
|
+
reaches: time_batch_guard.is_guarded_call,
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
// **The row `pnpm josh rule:value` scores the investigation guard from** (joshuafolkken/kit#1764).
|
|
579
|
+
// It is measured but not delivered, for exactly the reason the batching row is: `josh
|
|
580
|
+
// investigation:guard` has delivered it since joshuafolkken/kit#1460, and a row in `DELIVERED_RULES`
|
|
581
|
+
// would refuse the same violation a second time, each refusal spending a record the other cannot
|
|
582
|
+
// see. Until now it was the second delivered rule the measurement could not read at all — and the
|
|
583
|
+
// one whose subject, `investigation` at 35.9% of a run's turns, is the largest contributor any
|
|
584
|
+
// mechanism here addresses.
|
|
585
|
+
//
|
|
586
|
+
// **It declares no `is_trigger`, and that is honest rather than a gap.** Whether a read would be
|
|
587
|
+
// refused depends on the reads *behind* it — `investigation_reads.should_block` reads the transcript
|
|
588
|
+
// tail for exactly that — and the measurement hands a predicate one call at a time, so a call-shaped
|
|
589
|
+
// trigger could only be a guess. The refusal itself is what the transcript records, and
|
|
590
|
+
// `observe_error` takes that as the trigger.
|
|
591
|
+
//
|
|
592
|
+
// **`reaches` is the read the guard could have refused, not the refusal**, the distinction
|
|
593
|
+
// joshuafolkken/kit#1643 drew: scored against a trigger that fires only on the violation, the rate
|
|
594
|
+
// would be taken over runs that broke the rule at least once and would read near zero by
|
|
595
|
+
// construction.
|
|
596
|
+
//
|
|
597
|
+
// **It declares no `keeps` either, and the unmeasured cell is the honest answer rather than a gap.**
|
|
598
|
+
// The obvious predicate — a subagent dispatch — credits *any* dispatch, because that is what the
|
|
599
|
+
// guard's own reset does; a run that read twenty files in the main line, was never refused and sent
|
|
600
|
+
// one review agent at the end would score as full compliance. That row would sit near 100% for the
|
|
601
|
+
// rule this very Issue measures as let through on a third of all reads, and `pnpm josh rule:value` is
|
|
602
|
+
// what retirement decisions are read from. The module's own doctrine settles it: a rule with no
|
|
603
|
+
// `keeps` is reported unmeasured, because 0 and 1 are both claims the data does not make. **The
|
|
604
|
+
// compliance reading exists elsewhere and is better**: `pnpm josh time`'s `Investigation reads:`
|
|
605
|
+
// block, built from this same guard's predicates, says per run how much reading was refused, let
|
|
606
|
+
// through, or main-line by design. What this row adds is the reach and the delivery count, which is
|
|
607
|
+
// the continuous reading the guard had none of.
|
|
608
|
+
const INVESTIGATION_RULE: MeasuredRule = {
|
|
609
|
+
id: 'investigation',
|
|
610
|
+
reason: investigation_reads.REASON,
|
|
611
|
+
reaches: investigation_reads.is_refusable_call,
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
// Every rule the measurement can score, delivery registry first so a printed table reads in
|
|
615
|
+
// enumeration order with the rows delivered from here at the top.
|
|
616
|
+
const MEASURED_RULES: ReadonlyArray<MeasuredRule> = [
|
|
617
|
+
...DELIVERED_RULES,
|
|
618
|
+
BATCHING_RULE,
|
|
619
|
+
INVESTIGATION_RULE,
|
|
620
|
+
]
|
|
621
|
+
|
|
622
|
+
// **Once per run, never once per call.** A rule delivered again on the next call would wedge a run
|
|
623
|
+
// that had already obeyed it, which is the failure `hook_decision`'s stamp exists to prevent; the
|
|
624
|
+
// reason text says so, so a reader knows reissuing is the expected next move.
|
|
625
|
+
//
|
|
626
|
+
// **The tail read is what keeps two `Bash` guards off the same call.** `pnpm josh batch:guard` is
|
|
627
|
+
// wired to `Bash` as well, and the shared shell records the stamp *before* returning a reason. Claude
|
|
628
|
+
// Code surfaces one permission decision per call, so a call both hooks refused would lose one of the
|
|
629
|
+
// two reasons while both records were already written — and a rule whose record is set can never fire
|
|
630
|
+
// again in that run. That is a silent deletion, of exactly the kind this enumeration exists to
|
|
631
|
+
// prevent. So a call the batching guard may refuse is **stepped aside from rather than delivered
|
|
632
|
+
// on**: nothing is recorded (the shared shell stamps only after `should_block` answers true), the
|
|
633
|
+
// batching guard's own reason says to reissue the call, and this rule delivers on the reissue.
|
|
634
|
+
//
|
|
635
|
+
// **Inert for `wip-cap` and live for `issue-comments`, which is why it was written before either
|
|
636
|
+
// needed it.** The batching guard does not treat a filing call as a candidate at all, so the branch
|
|
637
|
+
// never fires for `wip-cap`; it *does* treat `gh issue view` as one, so the second row genuinely
|
|
638
|
+
// stands aside on a turn the batching guard is about to refuse and delivers on the reissue.
|
|
639
|
+
// `delivered-rules.test.ts` pins both halves, and it is what any new row has to be re-checked
|
|
640
|
+
// against. Erring toward standing aside costs at most one call's delay, while erring the other way
|
|
641
|
+
// costs the rule for the whole run.
|
|
642
|
+
// The batching guard's own record for this run, read through the same shell that writes it.
|
|
643
|
+
const BATCH_STAMP = hook_decision.create_refusal_stamp(time_batch_guard.STAMP_PREFIX)
|
|
644
|
+
|
|
645
|
+
// **A record this young is the batching guard speaking about the call in hand.** The two hooks are
|
|
646
|
+
// separate processes started for the same `PreToolUse` event with no ordering between them, and the
|
|
647
|
+
// shared shell writes its stamp *before* it returns a reason — so presence alone cannot answer "has
|
|
648
|
+
// it refused?" without making the stand-aside depend on which process won the race. A record older
|
|
649
|
+
// than this window is a refusal about an earlier call, which that guard will not repeat on the same
|
|
650
|
+
// open sequence, and this rule is free to speak.
|
|
651
|
+
const BATCH_REFUSAL_WINDOW_MS = 10_000
|
|
652
|
+
|
|
653
|
+
// **The question is what the batching guard will do on this call, not what it would do from a clean
|
|
654
|
+
// slate.** Asked with `NEVER_MS` in place of its record, the answer stayed `true` for the whole of an
|
|
655
|
+
// open sequence it had *already* refused — and since that guard will not refuse the same sequence
|
|
656
|
+
// twice, a run that kept single-calling after being refused had neither hook speak, and this rule was
|
|
657
|
+
// lost for the run with nothing recorded to say so. That is the silent deletion the stand-aside
|
|
658
|
+
// exists to prevent, arrived at from the other side.
|
|
659
|
+
function will_batch_guard_refuse(tail: string, call: GuardedCall, run: GuardRun): boolean {
|
|
660
|
+
// In a dispatched lane child the batching guard no longer refuses (joshuafolkken/kit#2138,
|
|
661
|
+
// joshuafolkken/kit#2164, joshuafolkken/kit#2178, joshuafolkken/kit#2276): its mode is `notice`, so it
|
|
662
|
+
// speaks but never denies. It will *refuse* nothing there, and the stand-aside must agree — or a lone
|
|
663
|
+
// rule trigger (`shell-body`) would be stepped aside from for a batching refusal that can no longer
|
|
664
|
+
// come and lost for the run. The test is therefore "will it refuse", i.e. mode `refuse`, not "is it
|
|
665
|
+
// notice or off".
|
|
666
|
+
if (lane_guard_policy.mode_here('batching') !== 'refuse') return false
|
|
667
|
+
|
|
668
|
+
const refused_at_ms = BATCH_STAMP.last_ms(BATCH_STAMP.path(run.transcript))
|
|
669
|
+
|
|
670
|
+
if (run.now_ms - refused_at_ms < BATCH_REFUSAL_WINDOW_MS) return true
|
|
671
|
+
|
|
672
|
+
return time_batch_guard.should_block(tail, call, refused_at_ms)
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
function is_first_delivery(
|
|
676
|
+
tail: string,
|
|
677
|
+
call: GuardedCall,
|
|
678
|
+
delivered_at_ms: number,
|
|
679
|
+
run: GuardRun,
|
|
680
|
+
): boolean {
|
|
681
|
+
return delivered_at_ms === hook_decision.NEVER_MS && !will_batch_guard_refuse(tail, call, run)
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
// **For a row that decides for itself, the stand-aside changes what it protects.** For a once-per-run
|
|
685
|
+
// row it protects the *record*, because a lost race spends the one delivery the run gets. A recurring
|
|
686
|
+
// row cannot be silently deleted that way — it fires again — and standing aside from the refusal would
|
|
687
|
+
// instead make it silent on precisely the lone `Bash` call the batching guard also claims, which is
|
|
688
|
+
// what an armed timer always is, for the whole ten-second window and the reissue inside it. So the
|
|
689
|
+
// refusal is asked unconditionally and the stand-aside is handed to the row as `can_record`: what must
|
|
690
|
+
// not happen on a call another hook may stop is the *write*, which would record a timer that never ran.
|
|
691
|
+
// **It is a trade, and the other side is named rather than hidden**: an arm allowed inside that window
|
|
692
|
+
// that really does run is not recorded either, so a second one before it fires goes uncaught. A missing
|
|
693
|
+
// record loses one detection; a wrong one blocks every arm until it expires.
|
|
694
|
+
// **Both extras hang off `is_first_delivery`, and a row declares at most one.** `decide` is for a
|
|
695
|
+
// recurring rule (joshuafolkken/kit#1570); `already_satisfied` is for a once-per-run rule the run can
|
|
696
|
+
// satisfy earlier (joshuafolkken/kit#1905), where the earlier act stands the delivery down before the
|
|
697
|
+
// once-per-run record is spent. A row with neither takes `is_first_delivery` unchanged.
|
|
698
|
+
function delivery_decision(rule: DeliveredRule): TranscriptGuardSpec['should_block'] {
|
|
699
|
+
const { decide, already_satisfied } = rule
|
|
700
|
+
|
|
701
|
+
if (decide === undefined && already_satisfied === undefined) return is_first_delivery
|
|
702
|
+
|
|
703
|
+
return function should_block(
|
|
704
|
+
tail: string,
|
|
705
|
+
call: GuardedCall,
|
|
706
|
+
delivered_at_ms: number,
|
|
707
|
+
run: GuardRun,
|
|
708
|
+
): boolean {
|
|
709
|
+
if (already_satisfied?.(tail, call) === true) return false
|
|
710
|
+
if (decide === undefined) return is_first_delivery(tail, call, delivered_at_ms, run)
|
|
711
|
+
|
|
712
|
+
return decide(call, run, !will_batch_guard_refuse(tail, call, run), delivered_at_ms)
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
function guard_of(rule: DeliveredRule): ReturnType<typeof hook_decision.create_transcript_guard> {
|
|
717
|
+
return hook_decision.create_transcript_guard({
|
|
718
|
+
prefix: `${STAMP_PREFIX}${rule.id}-`,
|
|
719
|
+
switch_key: SWITCH_ENV_KEY,
|
|
720
|
+
is_candidate: rule.is_trigger,
|
|
721
|
+
should_block: delivery_decision(rule),
|
|
722
|
+
reason: rule.reason,
|
|
723
|
+
})
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
const GUARDS = new Map(DELIVERED_RULES.map((rule) => [rule.id, guard_of(rule)]))
|
|
727
|
+
|
|
728
|
+
// Where one rule's once-per-run record lives, so a caller can clear it. Exposed for the suite: the
|
|
729
|
+
// records land in the shared temp directory rather than under any directory a test owns, and a record
|
|
730
|
+
// left behind would silence the next case exactly as it silences the next call.
|
|
731
|
+
function delivery_path(rule_id: string, transcript_path: string): string {
|
|
732
|
+
return GUARDS.get(rule_id)?.refusal_path(transcript_path) ?? ''
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
// **The first entry whose delivery actually fires wins — not the first whose trigger matches.** Only
|
|
736
|
+
// one refusal can leave a `PreToolUse` hook, so a rule that matched but has already been delivered
|
|
737
|
+
// this run falls through and a later rule may speak on the same call. **A rule added here whose
|
|
738
|
+
// trigger another row also matches is admissible only when the overlap is safe** — the losing rule's
|
|
739
|
+
// delivery still correct one reissue later — and the enumeration's own suite asserts, per fixture,
|
|
740
|
+
// that every command is claimed by exactly the rows meant to overlap on it.
|
|
741
|
+
//
|
|
742
|
+
// **The filing trigger is shared by three rows, and the order is what makes the overlap safe**
|
|
743
|
+
// (joshuafolkken/kit#2119). `wip-cap`, `issue-scout` and `filing-cap` all match a filing; a
|
|
744
|
+
// scout-less, over-cap filing is delivered `wip-cap`, then `issue-scout`, then `filing-cap` across its
|
|
745
|
+
// reissues, each still the right thing to say when it is reached. `wip-cap` is listed first because it
|
|
746
|
+
// decides whether the backlog has room at all — the same reason it precedes `shell-body`, which claims
|
|
747
|
+
// a filing whose body carries a backtick (joshuafolkken/kit#1198). Nothing is lost by losing a race:
|
|
748
|
+
// the stamps are keyed per `id`, so the reissued call is delivered the next rule.
|
|
749
|
+
function delivery(raw_payload: string, now_ms: number = Date.now()): string | undefined {
|
|
750
|
+
for (const guard of GUARDS.values()) {
|
|
751
|
+
const reason = guard.refusal(raw_payload, now_ms)
|
|
752
|
+
|
|
753
|
+
if (reason !== undefined) return reason
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
return undefined
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
function is_enabled(): boolean {
|
|
760
|
+
return hook_decision.is_switch_enabled(SWITCH_ENV_KEY)
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
const delivered_rules = {
|
|
764
|
+
DELIVERED_RULES,
|
|
765
|
+
EARLY_HEARTBEAT_REASON: early_heartbeat.EARLY_HEARTBEAT_REASON,
|
|
766
|
+
FILE_BODY_REASON: file_body.FILE_BODY_REASON,
|
|
767
|
+
FILING_CAP_REASON: filing_cap.FILING_CAP_REASON,
|
|
768
|
+
GIT_FORCE_REASON: git_force.GIT_FORCE_REASON,
|
|
769
|
+
ISSUE_COMMENTS_REASON,
|
|
770
|
+
ISSUE_FOLD_REASON: issue_fold.ISSUE_FOLD_REASON,
|
|
771
|
+
ISSUE_SCOUT_REASON: issue_scout.ISSUE_SCOUT_REASON,
|
|
772
|
+
LANE_INTERACTIVE_ASK_REASON: lane_interactive_ask.LANE_INTERACTIVE_ASK_REASON,
|
|
773
|
+
LANE_PARK_REASON: lane_park.LANE_PARK_REASON,
|
|
774
|
+
MEASURED_RULES,
|
|
775
|
+
PIPED_VERIFICATION_REASON: piped_verification.PIPED_VERIFICATION_REASON,
|
|
776
|
+
POLL_LOOP_REASON: poll_loop.POLL_LOOP_REASON,
|
|
777
|
+
PRE_GATE_CUT_REASON: pre_gate_cut.PRE_GATE_CUT_REASON,
|
|
778
|
+
RAW_FIELD_BODY_REASON: raw_field_body.RAW_FIELD_BODY_REASON,
|
|
779
|
+
RUN_TAIL_REASON: run_tail.RUN_TAIL_REASON,
|
|
780
|
+
SHELL_BODY_REASON,
|
|
781
|
+
SWITCH_ENV_KEY,
|
|
782
|
+
THIRD_PARTY_WRITE_REASON: third_party_write.THIRD_PARTY_WRITE_REASON,
|
|
783
|
+
WIP_CAP_REASON,
|
|
784
|
+
WORKTREE_MUTATION_REASON: worktree_guard.WORKTREE_MUTATION_REASON,
|
|
785
|
+
delivery,
|
|
786
|
+
delivery_path,
|
|
787
|
+
is_body_only_issue_read,
|
|
788
|
+
is_enabled,
|
|
789
|
+
is_issue_filing,
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
export type { DeliveredRule, MeasuredRule }
|
|
793
|
+
export { delivered_rules }
|