@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,143 @@
|
|
|
1
|
+
import { telegram_notify } from '#scripts/git/telegram-notify'
|
|
2
|
+
import { run_event_stream, type RunEvent } from '#scripts/run/run-event-stream'
|
|
3
|
+
import { run_event_stream_emit } from '#scripts/run/run-event-stream-emit'
|
|
4
|
+
import { backlog_ready, type ReadyPorts } from './backlog-ready'
|
|
5
|
+
import { backlog_stalled, type StallReading, type StallVerdict } from './backlog-stalled'
|
|
6
|
+
|
|
7
|
+
// The I/O half of the stall detector (joshuafolkken/kit#2359): it gathers the three counts the pure
|
|
8
|
+
// judge in `backlog-stalled.ts` weighs, then — on a stall — leaves the marker and sends the one
|
|
9
|
+
// notification. `stop-guard.ts` wires it into the Stop hook, so it runs at each loop boundary; the CLI
|
|
10
|
+
// exposes the same call for a person to run by hand.
|
|
11
|
+
//
|
|
12
|
+
// **Cheap first.** The costly read is `backlog:next`, a subprocess that hits the network. The two local
|
|
13
|
+
// reads gate it: the dispatch age comes free from the stream this already reads, and the free-lane count
|
|
14
|
+
// is one `git worktree list`. Neither the lane count nor the backlog read is made unless the cheaper
|
|
15
|
+
// condition ahead of it already holds, so an ordinary stop — a run not idle, or with no free lane —
|
|
16
|
+
// costs a single file read and nothing more.
|
|
17
|
+
|
|
18
|
+
const NO_FREE = 0
|
|
19
|
+
const NO_READY = 0
|
|
20
|
+
const NO_AGE = 0
|
|
21
|
+
|
|
22
|
+
// The recovery line names the command that resolves the stall — the same one `run:step` points a stalled
|
|
23
|
+
// run at — so the person the notification reaches has the fix in hand.
|
|
24
|
+
const STALL_RECOVERY = 'Dispatch the ready work with `pnpm josh backlog:next`.'
|
|
25
|
+
|
|
26
|
+
// The seams a test replaces: the stream target and its events, the clock, the two counts, and the two
|
|
27
|
+
// side effects. The defaults are the real readers; a test hands fakes so the gather and report logic run
|
|
28
|
+
// without a git tree, a network or a wall clock.
|
|
29
|
+
interface DetectPorts {
|
|
30
|
+
resolve_target: () => Promise<string | undefined>
|
|
31
|
+
read_events: (target: string) => ReadonlyArray<RunEvent>
|
|
32
|
+
now_ms: () => number
|
|
33
|
+
free_lane_count: () => Promise<number>
|
|
34
|
+
ready_count: () => Promise<number>
|
|
35
|
+
emit_stall: (text: string) => Promise<boolean>
|
|
36
|
+
notify_stalled: (body: string) => Promise<boolean>
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// The free-lane and runnable-issue reads are `backlog-ready.ts`'s — the watcher's ready line reads the
|
|
40
|
+
// same two, so they live once there (joshuafolkken/kit#2452) — and a caller that reads them again after
|
|
41
|
+
// this check hands its own ports in, so the two share one reading (joshuafolkken/kit#2472).
|
|
42
|
+
function ready_count_of(ready: ReadyPorts): () => Promise<number> {
|
|
43
|
+
return async function (): Promise<number> {
|
|
44
|
+
const issues = await ready.ready_issues()
|
|
45
|
+
|
|
46
|
+
return issues.length
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// One stall per episode, and the episode ends at a dispatch rather than at whatever event lands next
|
|
51
|
+
// (joshuafolkken/kit#2464) — every parallel lane appends to this stream, so a newest-event dedup re-fired.
|
|
52
|
+
async function real_emit_stall(text: string): Promise<boolean> {
|
|
53
|
+
const { STALL, CHILD_LAUNCH } = run_event_stream.EVENT_KIND
|
|
54
|
+
|
|
55
|
+
return await run_event_stream_emit.emit_once_since(STALL, text, CHILD_LAUNCH)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async function real_notify_stalled(body: string): Promise<boolean> {
|
|
59
|
+
return await telegram_notify.stalled({ body, recovery: STALL_RECOVERY })
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function ports_over(ready: ReadyPorts): DetectPorts {
|
|
63
|
+
return {
|
|
64
|
+
resolve_target: run_event_stream_emit.stream_target,
|
|
65
|
+
read_events: run_event_stream.read_events,
|
|
66
|
+
now_ms: () => Date.now(),
|
|
67
|
+
free_lane_count: ready.free_lane_count,
|
|
68
|
+
ready_count: ready_count_of(ready),
|
|
69
|
+
emit_stall: real_emit_stall,
|
|
70
|
+
notify_stalled: real_notify_stalled,
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const DEFAULT_PORTS: DetectPorts = ports_over(backlog_ready.DEFAULT_PORTS)
|
|
75
|
+
|
|
76
|
+
function ok_reading(dispatch_age_ms: number): StallReading {
|
|
77
|
+
return { ready_count: NO_READY, free_lanes: NO_FREE, dispatch_age_ms }
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// The idle-and-past-threshold branch, where the costly reads finally happen: count the free lanes, and
|
|
81
|
+
// only if one is free read the backlog. A full pool short-circuits before the network call — a stall
|
|
82
|
+
// needs a lane to go into.
|
|
83
|
+
async function probe_reading(ports: DetectPorts, dispatch_age_ms: number): Promise<StallReading> {
|
|
84
|
+
const free_lanes = await ports.free_lane_count()
|
|
85
|
+
|
|
86
|
+
if (free_lanes <= NO_FREE) return { ready_count: NO_READY, free_lanes, dispatch_age_ms }
|
|
87
|
+
|
|
88
|
+
return { ready_count: await ports.ready_count(), free_lanes, dispatch_age_ms }
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// The reading that decides the verdict, assembled cheap-condition-first. `undefined` is the unreadable
|
|
92
|
+
// answer: no stream to key on, so no run to be stalled. Every early return yields a reading the judge
|
|
93
|
+
// maps to `ok`; only when the run is idle past the threshold does `probe_reading` make the costly reads.
|
|
94
|
+
async function gather(ports: DetectPorts, threshold_ms: number): Promise<StallReading | undefined> {
|
|
95
|
+
const target = await ports.resolve_target()
|
|
96
|
+
|
|
97
|
+
if (target === undefined) return undefined
|
|
98
|
+
|
|
99
|
+
const age = backlog_stalled.dispatch_age_ms(ports.read_events(target), ports.now_ms())
|
|
100
|
+
|
|
101
|
+
if (age === undefined) return ok_reading(NO_AGE)
|
|
102
|
+
if (age <= threshold_ms) return ok_reading(age)
|
|
103
|
+
|
|
104
|
+
return await probe_reading(ports, age)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// The marker and the notification, both once per stall episode. `emit_stall` refuses a second until a
|
|
108
|
+
// dispatch has intervened, and its `false` is what holds the notification back too — so a stall
|
|
109
|
+
// polled every stop reaches the person once, not once a turn.
|
|
110
|
+
async function report(ports: DetectPorts, reading: StallReading): Promise<void> {
|
|
111
|
+
const text = backlog_stalled.describe(reading)
|
|
112
|
+
|
|
113
|
+
if (await ports.emit_stall(text)) await ports.notify_stalled(text)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Read the three conditions, print nothing, and on a stall leave the marker and notify. The verdict is
|
|
117
|
+
// returned for the CLI to print; the side effects are the report's.
|
|
118
|
+
async function detect_and_report(
|
|
119
|
+
ports: DetectPorts = DEFAULT_PORTS,
|
|
120
|
+
threshold_ms: number = backlog_stalled.STALL_THRESHOLD_MS,
|
|
121
|
+
): Promise<StallVerdict> {
|
|
122
|
+
const reading = await gather(ports, threshold_ms)
|
|
123
|
+
const verdict = backlog_stalled.assess(reading, threshold_ms)
|
|
124
|
+
|
|
125
|
+
if (reading !== undefined && verdict === backlog_stalled.STALLED) await report(ports, reading)
|
|
126
|
+
|
|
127
|
+
return verdict
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Best-effort for the Stop hook: the detector is a report, so a failure to gather or notify is dropped
|
|
131
|
+
// rather than raised into the stop decision it rides alongside.
|
|
132
|
+
async function run_stall_check(ready: ReadyPorts = backlog_ready.DEFAULT_PORTS): Promise<void> {
|
|
133
|
+
try {
|
|
134
|
+
await detect_and_report(ports_over(ready))
|
|
135
|
+
} catch {
|
|
136
|
+
// Reporting is best-effort: a stall we could not read or send is dropped, never a blocked stop.
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const backlog_stalled_detect = { DEFAULT_PORTS, detect_and_report, gather, report, run_stall_check }
|
|
141
|
+
|
|
142
|
+
export { backlog_stalled_detect }
|
|
143
|
+
export type { DetectPorts }
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { run_event_stream, type RunEvent } from '#scripts/run/run-event-stream'
|
|
2
|
+
|
|
3
|
+
// When ready backlog work sits undispatched while lanes are free, nobody notices until a person asks
|
|
4
|
+
// (joshuafolkken/kit#2359). This is the mechanical judge of that state: three facts read, never
|
|
5
|
+
// weighed — is there runnable work, is there a free lane, and has nothing been dispatched for a while.
|
|
6
|
+
// The verdict is a report, not a stop: a false positive costs one notification, never a halted run.
|
|
7
|
+
//
|
|
8
|
+
// **Pure by design.** The clock and the counts are handed in, so the four acceptance cases — work with
|
|
9
|
+
// a free lane, work with no free lane, no work, and an unreadable record — and the elapsed-time
|
|
10
|
+
// boundary are unit-tested without a git tree, a network or a wall clock. The I/O that gathers the
|
|
11
|
+
// counts is `backlog-stalled-detect.ts`; this file only decides.
|
|
12
|
+
|
|
13
|
+
const STALL_THRESHOLD_MINUTES = 10
|
|
14
|
+
const MS_PER_MINUTE = 60_000
|
|
15
|
+
const STALL_THRESHOLD_MS = STALL_THRESHOLD_MINUTES * MS_PER_MINUTE
|
|
16
|
+
const NONE = 0
|
|
17
|
+
|
|
18
|
+
// `stalled` when all three conditions hold, `unreadable` when the dispatch record could not be read at
|
|
19
|
+
// all, `ok` otherwise. An issue number is never one of these — they are the only three answers. The
|
|
20
|
+
// verdicts carry this type rather than a bare literal so the exported `backlog_stalled` namespace does
|
|
21
|
+
// not widen them to `string` at the object boundary (object-literal widening).
|
|
22
|
+
type StallVerdict = 'stalled' | 'ok' | 'unreadable'
|
|
23
|
+
|
|
24
|
+
const STALLED: StallVerdict = 'stalled'
|
|
25
|
+
const OK: StallVerdict = 'ok'
|
|
26
|
+
const UNREADABLE: StallVerdict = 'unreadable'
|
|
27
|
+
|
|
28
|
+
// The three facts, read and never judged: how many issues could start now, how many lanes are free, and
|
|
29
|
+
// how long since the last dispatch. Assembled by the detect layer; consumed only here.
|
|
30
|
+
interface StallReading {
|
|
31
|
+
ready_count: number
|
|
32
|
+
free_lanes: number
|
|
33
|
+
dispatch_age_ms: number
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// All three together, and only together. Separated from `assess` so the short-circuit gate in the
|
|
37
|
+
// detect layer — the one that decides whether the expensive backlog read is worth making — reads the
|
|
38
|
+
// same condition rather than a second copy of it.
|
|
39
|
+
function is_stalled(reading: StallReading, threshold_ms: number): boolean {
|
|
40
|
+
return (
|
|
41
|
+
reading.ready_count > NONE &&
|
|
42
|
+
reading.free_lanes > NONE &&
|
|
43
|
+
reading.dispatch_age_ms > threshold_ms
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// **The verdict, and the whole of the judgement.** An unread record answers first — `undefined` is the
|
|
48
|
+
// detect layer saying it could not resolve the run's own stream — so a missing record never reads as a
|
|
49
|
+
// stall. The boundary is strict: exactly at the threshold is not yet a stall, one millisecond past it
|
|
50
|
+
// is.
|
|
51
|
+
function assess(reading: StallReading | undefined, threshold_ms: number): StallVerdict {
|
|
52
|
+
if (reading === undefined) return UNREADABLE
|
|
53
|
+
if (is_stalled(reading, threshold_ms)) return STALLED
|
|
54
|
+
|
|
55
|
+
return OK
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// The time a stall is measured from: the newest dispatch (`child-launch`), or — before the first
|
|
59
|
+
// dispatch — the run's earliest recorded event, so a run that has never dispatched is still aged from
|
|
60
|
+
// when it began. `undefined` for a stream with nothing on it: there is no run to be stalled.
|
|
61
|
+
function dispatch_reference_iso(events: ReadonlyArray<RunEvent>): string | undefined {
|
|
62
|
+
const last_launch = events.findLast(
|
|
63
|
+
(event) => event.kind === run_event_stream.EVENT_KIND.CHILD_LAUNCH,
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
return last_launch?.at ?? events[0]?.at
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Milliseconds since that reference, or `undefined` when there is no reference or the stamp is
|
|
70
|
+
// unparseable — the caller reads either as "nothing to age against" and returns no stall.
|
|
71
|
+
function dispatch_age_ms(events: ReadonlyArray<RunEvent>, now_ms: number): number | undefined {
|
|
72
|
+
const iso = dispatch_reference_iso(events)
|
|
73
|
+
|
|
74
|
+
if (iso === undefined) return undefined
|
|
75
|
+
|
|
76
|
+
const at = Date.parse(iso)
|
|
77
|
+
|
|
78
|
+
return Number.isNaN(at) ? undefined : now_ms - at
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// The one line a person reads in the notification and on the stream: what is waiting and how long.
|
|
82
|
+
function describe(reading: StallReading): string {
|
|
83
|
+
const minutes = Math.floor(reading.dispatch_age_ms / MS_PER_MINUTE)
|
|
84
|
+
|
|
85
|
+
return `${String(reading.ready_count)} ready, ${String(reading.free_lanes)} free lane(s), ${String(minutes)}m since the last dispatch`
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const NUMERIC_TOKEN = /^\d+$/u
|
|
89
|
+
|
|
90
|
+
// The runnable issue numbers `backlog:next` printed: one token per line, a bare number per runnable
|
|
91
|
+
// issue and a verdict word (`wait`, `stop`, …) when there is none — so the numeric lines are the ready
|
|
92
|
+
// issues.
|
|
93
|
+
function ready_tokens(out: string): ReadonlyArray<string> {
|
|
94
|
+
return out
|
|
95
|
+
.split('\n')
|
|
96
|
+
.map((token) => token.trim())
|
|
97
|
+
.filter((token) => NUMERIC_TOKEN.test(token))
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function count_ready_tokens(out: string): number {
|
|
101
|
+
return ready_tokens(out).length
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const backlog_stalled = {
|
|
105
|
+
STALLED,
|
|
106
|
+
OK,
|
|
107
|
+
UNREADABLE,
|
|
108
|
+
STALL_THRESHOLD_MS,
|
|
109
|
+
assess,
|
|
110
|
+
count_ready_tokens,
|
|
111
|
+
describe,
|
|
112
|
+
dispatch_age_ms,
|
|
113
|
+
is_stalled,
|
|
114
|
+
ready_tokens,
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export { backlog_stalled }
|
|
118
|
+
export type { StallReading, StallVerdict }
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import {
|
|
2
|
+
time_transcript_line,
|
|
3
|
+
type TranscriptLine,
|
|
4
|
+
} from '#scripts/time-runtime/time-transcript-line'
|
|
5
|
+
|
|
6
|
+
// Verifying an agent's behavior against the transcripts every run already writes, with no live
|
|
7
|
+
// Claude session and no model call (joshuafolkken/kit#2365).
|
|
8
|
+
//
|
|
9
|
+
// **The mechanism that measured behavior used to be the completion gate's own, and it was removed
|
|
10
|
+
// for being slow rather than for being wrong.** joshuafolkken/kit#1922 took `josh eval`'s five
|
|
11
|
+
// scenarios out of the gate because each starts a real Claude session, so the step never ran without
|
|
12
|
+
// `JOSH_EVAL` and paid a prompt-and-report cost every run for nothing. What it left behind is a gate
|
|
13
|
+
// that proves the *machinery* works — 8,000-odd unit tests — and nothing at all that proves the
|
|
14
|
+
// agent *behaves*. This is the half worth keeping, separated from the half worth removing: an
|
|
15
|
+
// assertion read off a recorded transcript is deterministic, re-runnable and never calls a model.
|
|
16
|
+
//
|
|
17
|
+
// **The reading is single-sourced, not re-implemented.** One transcript line is parsed by
|
|
18
|
+
// `time-transcript-line.ts` — the reader the span walk and the guards already use — and the files are
|
|
19
|
+
// located and read by `cost-transcript.ts`. This module is only the assertions and the walk over the
|
|
20
|
+
// parsed turns; it owns no second copy of "where a transcript lives" or "how a line is shaped".
|
|
21
|
+
|
|
22
|
+
// Where in a transcript an assertion broke: which run, and which point in it. The failure names the
|
|
23
|
+
// next place a reader looks rather than reporting that a rule broke somewhere in a session.
|
|
24
|
+
interface Violation {
|
|
25
|
+
// The rule that broke, by name — so a reader tells one broken assertion from another without
|
|
26
|
+
// re-deriving it from the detail.
|
|
27
|
+
assertion: string
|
|
28
|
+
// The run the transcript belongs to. `''` until the caller that read the file stamps it, because
|
|
29
|
+
// the scan knows the turn and the detail but not which session file it was handed.
|
|
30
|
+
session_id: string
|
|
31
|
+
// The 1-based line position of the offending turn in the transcript, so "which point" is a place
|
|
32
|
+
// a reader can open rather than a description.
|
|
33
|
+
position: number
|
|
34
|
+
// What broke, in the assertion's own words — for the git-index rule, the command that mutated the
|
|
35
|
+
// index directly.
|
|
36
|
+
detail: string
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// A violation before the session it was found in is attached. The scan produces these; the reader
|
|
40
|
+
// that opened the file supplies the `session_id`.
|
|
41
|
+
type Finding = Omit<Violation, 'session_id'>
|
|
42
|
+
|
|
43
|
+
// One behavior rule: a name, a human description, and a pure scan over the parsed turns of one
|
|
44
|
+
// transcript. The scan returns every point it broke, so a single transcript can report more than one
|
|
45
|
+
// violation and each names its own position.
|
|
46
|
+
interface Assertion {
|
|
47
|
+
name: string
|
|
48
|
+
describe: string
|
|
49
|
+
scan: (lines: ReadonlyArray<TranscriptLine>) => ReadonlyArray<Finding>
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// The parsed turns of one transcript, in file order. A line that fails to parse is dropped rather
|
|
53
|
+
// than dated — it has no turn to point at — exactly as `time-spans.ts` drops it.
|
|
54
|
+
function parse_transcript(text: string): ReadonlyArray<TranscriptLine> {
|
|
55
|
+
return text
|
|
56
|
+
.split('\n')
|
|
57
|
+
.map((line) => time_transcript_line.parse_line(line))
|
|
58
|
+
.filter((line): line is TranscriptLine => line !== undefined)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Every assertion's findings over one set of parsed turns, each stamped with the session it was read
|
|
62
|
+
// from. The single walk the CLI and the tests share, so a synthetic transcript and a real one are
|
|
63
|
+
// checked the same way.
|
|
64
|
+
function check_lines(
|
|
65
|
+
lines: ReadonlyArray<TranscriptLine>,
|
|
66
|
+
session_id: string,
|
|
67
|
+
assertions: ReadonlyArray<Assertion>,
|
|
68
|
+
): ReadonlyArray<Violation> {
|
|
69
|
+
return assertions.flatMap((assertion) =>
|
|
70
|
+
assertion.scan(lines).map((finding) => ({ ...finding, session_id })),
|
|
71
|
+
)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// One transcript's raw text checked against every assertion — parsed once, then walked. The entry
|
|
75
|
+
// point a caller uses when it holds the text rather than the parsed lines.
|
|
76
|
+
function check_transcript(
|
|
77
|
+
text: string,
|
|
78
|
+
session_id: string,
|
|
79
|
+
assertions: ReadonlyArray<Assertion>,
|
|
80
|
+
): ReadonlyArray<Violation> {
|
|
81
|
+
return check_lines(parse_transcript(text), session_id, assertions)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const behavior_assertion = { parse_transcript, check_lines, check_transcript }
|
|
85
|
+
|
|
86
|
+
export type { Assertion, Finding, Violation }
|
|
87
|
+
export { behavior_assertion }
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
import { fileURLToPath } from 'node:url'
|
|
3
|
+
import { cost_transcript, type SessionFile } from '#scripts/cost-runtime/cost-transcript'
|
|
4
|
+
import { status_icons } from '#scripts/lib/status-icons'
|
|
5
|
+
import { behavior_assertion, type Violation } from './behavior-assertion'
|
|
6
|
+
import { behavior_rules } from './behavior-rules'
|
|
7
|
+
|
|
8
|
+
// `josh behavior` — check the current run's recorded transcript against the behavior assertions and
|
|
9
|
+
// report where any broke (joshuafolkken/kit#2365). It runs inside `pnpm josh gate`, calls no model,
|
|
10
|
+
// and reads one file: the session it is running in.
|
|
11
|
+
//
|
|
12
|
+
// **The scope is the current run, not the whole corpus.** The store holds thousands of transcripts
|
|
13
|
+
// and over a gigabyte; walking all of it every gate would cost minutes, not the seconds the other
|
|
14
|
+
// checks take. Each gate checks its own run, so across runs the whole corpus is covered a run at a
|
|
15
|
+
// time — and the engine stays general, so a broad scan of past runs (the greenness check this seed
|
|
16
|
+
// assertion was verified with) is the same walk over a different set of files.
|
|
17
|
+
|
|
18
|
+
const PASS_EXIT_CODE = 0
|
|
19
|
+
const FAIL_EXIT_CODE = 1
|
|
20
|
+
const LABEL = 'josh behavior'
|
|
21
|
+
|
|
22
|
+
// The current run's transcript: the newest of the session's *own* files across the directories a run
|
|
23
|
+
// writes to, resolved by `cost-transcript.ts` exactly as `josh cost` resolves "the run that just
|
|
24
|
+
// finished". A gate runs inside that session, so its transcript is the newest own file.
|
|
25
|
+
function current_session(cwd: string = process.cwd()): SessionFile | undefined {
|
|
26
|
+
const directories = cost_transcript.transcript_directories(cwd)
|
|
27
|
+
const sessions = cost_transcript.list_sessions_across(directories)
|
|
28
|
+
|
|
29
|
+
return sessions[cost_transcript.latest_own_index(sessions)]
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// **A run with no transcript passes, and passes without the skip marker.** The gate reads `—
|
|
33
|
+
// skipping` to withhold its green record; a behavior check that found no transcript — a CI runner has
|
|
34
|
+
// none — has nothing to say about the tree and must not withhold the record the other checks earned.
|
|
35
|
+
function report_no_transcript(): number {
|
|
36
|
+
console.info(`${LABEL}: no recorded transcript to check ${status_icons.PASS_ICON}`)
|
|
37
|
+
|
|
38
|
+
return PASS_EXIT_CODE
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Which run and which point, in the assertion's own words — the failure names the place a reader
|
|
42
|
+
// opens rather than reporting that a rule broke somewhere.
|
|
43
|
+
function format_violation(violation: Violation): string {
|
|
44
|
+
const where = `run ${violation.session_id} at position ${String(violation.position)}`
|
|
45
|
+
|
|
46
|
+
return `${status_icons.FAIL_ICON} ${violation.assertion} broke in ${where}\n ${violation.detail}`
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function report_violations(violations: ReadonlyArray<Violation>): number {
|
|
50
|
+
for (const violation of violations) console.error(format_violation(violation))
|
|
51
|
+
console.error(`${LABEL}: ${String(violations.length)} behavior assertion(s) broke`)
|
|
52
|
+
|
|
53
|
+
return FAIL_EXIT_CODE
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function report_green(session_id: string): number {
|
|
57
|
+
const count = String(behavior_rules.ALL_ASSERTIONS.length)
|
|
58
|
+
|
|
59
|
+
console.info(`${LABEL}: ${count} assertion(s) green in ${session_id} ${status_icons.PASS_ICON}`)
|
|
60
|
+
|
|
61
|
+
return PASS_EXIT_CODE
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function check_session(file: SessionFile): number {
|
|
65
|
+
const text = cost_transcript.read_optional(file)
|
|
66
|
+
|
|
67
|
+
if (text === undefined) return report_no_transcript()
|
|
68
|
+
|
|
69
|
+
const violations = behavior_assertion.check_transcript(
|
|
70
|
+
text,
|
|
71
|
+
file.session_id,
|
|
72
|
+
behavior_rules.ALL_ASSERTIONS,
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
return violations.length > 0 ? report_violations(violations) : report_green(file.session_id)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function run(cwd: string = process.cwd()): number {
|
|
79
|
+
const file = current_session(cwd)
|
|
80
|
+
|
|
81
|
+
return file === undefined ? report_no_transcript() : check_session(file)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const behavior_cli = { LABEL, check_session, current_session, run }
|
|
85
|
+
|
|
86
|
+
if (process.argv[1] === fileURLToPath(import.meta.url)) process.exitCode = run()
|
|
87
|
+
|
|
88
|
+
export { behavior_cli }
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { json_value } from '#scripts/lib/json-value'
|
|
2
|
+
import type { Block, TranscriptLine } from '#scripts/time-runtime/time-transcript-line'
|
|
3
|
+
import type { Assertion, Finding } from './behavior-assertion'
|
|
4
|
+
|
|
5
|
+
// The behavior assertions checked against recorded transcripts (joshuafolkken/kit#2365). This is the
|
|
6
|
+
// **seed set** — the issue's own plan is to land one rule that is green across the recorded corpus,
|
|
7
|
+
// then add more one at a time, each verified green before it joins. Starting with many would land a
|
|
8
|
+
// wall of red that says nothing about which behavior actually regressed.
|
|
9
|
+
|
|
10
|
+
const BASH_TOOL = 'Bash'
|
|
11
|
+
const TOOL_USE = 'tool_use'
|
|
12
|
+
const COMMAND_KEY = 'command'
|
|
13
|
+
const FIRST_POSITION_OFFSET = 1
|
|
14
|
+
const TOOL_RESULT = 'tool_result'
|
|
15
|
+
const DENIED_BASH_PREFIX = 'Permission to use Bash with command '
|
|
16
|
+
|
|
17
|
+
// The git subcommands that stage or rewrite the index — the ones `CLAUDE.md` reserves for `pnpm josh
|
|
18
|
+
// git` under "Never stage or mutate the git index on your own". An agent that runs one directly has
|
|
19
|
+
// overwritten the user's snapshot with a command the settings deny it.
|
|
20
|
+
//
|
|
21
|
+
// **The match is anchored at the start of a command segment, not searched anywhere in the string.** A
|
|
22
|
+
// `grep '…git commit…'` or an `echo "git add"` mentions the words without running them, and searching
|
|
23
|
+
// the whole command would read the mention as the act — the exact false positive that would turn a
|
|
24
|
+
// run that only investigated git into a red gate. Splitting on the shell's own separators and
|
|
25
|
+
// requiring the segment to *begin* with the mutation is what tells the command from the quotation.
|
|
26
|
+
const SEGMENT_SEPARATOR = /[\n;&|]+/u
|
|
27
|
+
const INDEX_MUTATION_HEAD = /^git\s+(?:commit|add|rm\s+--cached|restore\s+--staged)\b/u
|
|
28
|
+
// `git add -n` / `--dry-run` stage nothing, so they are not a mutation — the one such command in the
|
|
29
|
+
// recorded corpus is a `git add -n .` dry run, and reading it as a violation would fail the assertion
|
|
30
|
+
// on a run that broke no rule. **`-n` means dry-run only where the subcommand defines it that way**:
|
|
31
|
+
// for `add`/`rm` it is `--dry-run`, but for `git commit` `-n` is `--no-verify`, a real commit — so the
|
|
32
|
+
// short flag is honored only after an `add`/`rm` head, while `--dry-run` is unambiguous everywhere.
|
|
33
|
+
const DRY_RUN_LONG = /(?:^|\s)--dry-run(?:\s|$)/u
|
|
34
|
+
const DRY_RUN_SHORT = /(?:^|\s)-n(?:\s|$)/u
|
|
35
|
+
const DRY_RUN_SHORT_HEAD = /^git\s+(?:add|rm)\b/u
|
|
36
|
+
|
|
37
|
+
function is_dry_run(segment: string): boolean {
|
|
38
|
+
if (DRY_RUN_LONG.test(segment)) return true
|
|
39
|
+
|
|
40
|
+
return DRY_RUN_SHORT_HEAD.test(segment) && DRY_RUN_SHORT.test(segment)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const INDEX_ASSERTION_NAME = 'no-direct-git-index-mutation'
|
|
44
|
+
|
|
45
|
+
// The Bash command a tool-use block requested, or `undefined` for every other block — a text block,
|
|
46
|
+
// a tool result, or a call to any tool but `Bash`. Read through `json_value.is_record` so a malformed
|
|
47
|
+
// input is treated as absent rather than throwing mid-scan.
|
|
48
|
+
function command_of(block: Block): string | undefined {
|
|
49
|
+
if (block.type !== TOOL_USE || block.name !== BASH_TOOL) return undefined
|
|
50
|
+
if (!json_value.is_record(block.input)) return undefined
|
|
51
|
+
|
|
52
|
+
const command = block.input[COMMAND_KEY]
|
|
53
|
+
|
|
54
|
+
return typeof command === 'string' ? command : undefined
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Whether any segment of a command directly mutates the index: it begins with a staging or commit
|
|
58
|
+
// subcommand and is not a dry run. Each `;`/`&&`/`|`-separated segment is judged on its own, so a
|
|
59
|
+
// mutation anywhere in a chain is caught while a mention inside another command's argument is not.
|
|
60
|
+
function is_index_mutation(command: string): boolean {
|
|
61
|
+
return command
|
|
62
|
+
.split(SEGMENT_SEPARATOR)
|
|
63
|
+
.map((segment) => segment.trim())
|
|
64
|
+
.some((segment) => INDEX_MUTATION_HEAD.test(segment) && !is_dry_run(segment))
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// An errored result alone may mean a command ran and failed. Only the permission layer's refusal
|
|
68
|
+
// identifies a Bash call that never ran; the parser keeps the opening of that result's text.
|
|
69
|
+
function is_denied_result(block: Block): boolean {
|
|
70
|
+
return (
|
|
71
|
+
block.type === TOOL_RESULT &&
|
|
72
|
+
block.result_id !== '' &&
|
|
73
|
+
block.is_error === true &&
|
|
74
|
+
block.error_text.startsWith(DENIED_BASH_PREFIX)
|
|
75
|
+
)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function denied_call_ids(lines: ReadonlyArray<TranscriptLine>): ReadonlySet<string> {
|
|
79
|
+
return new Set(
|
|
80
|
+
lines.flatMap((line) =>
|
|
81
|
+
line.blocks.filter((block) => is_denied_result(block)).map((block) => block.result_id),
|
|
82
|
+
),
|
|
83
|
+
)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// The direct index mutations one transcript line ran, each as a finding at that line's position. A
|
|
87
|
+
// line is one assistant content block, so its position is a place a reader can open in the file.
|
|
88
|
+
function line_mutations(
|
|
89
|
+
line: TranscriptLine,
|
|
90
|
+
index: number,
|
|
91
|
+
denied_ids: ReadonlySet<string>,
|
|
92
|
+
): ReadonlyArray<Finding> {
|
|
93
|
+
return line.blocks
|
|
94
|
+
.filter((block) => !denied_ids.has(block.id))
|
|
95
|
+
.map((block) => command_of(block))
|
|
96
|
+
.filter((command): command is string => command !== undefined && is_index_mutation(command))
|
|
97
|
+
.map((command) => ({
|
|
98
|
+
assertion: INDEX_ASSERTION_NAME,
|
|
99
|
+
position: index + FIRST_POSITION_OFFSET,
|
|
100
|
+
detail: command,
|
|
101
|
+
}))
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function scan_index_mutation(lines: ReadonlyArray<TranscriptLine>): ReadonlyArray<Finding> {
|
|
105
|
+
const denied_ids = denied_call_ids(lines)
|
|
106
|
+
|
|
107
|
+
return lines.flatMap((line, index) => line_mutations(line, index, denied_ids))
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const index_mutation_assertion: Assertion = {
|
|
111
|
+
name: INDEX_ASSERTION_NAME,
|
|
112
|
+
describe: 'git staging or commit must go through `pnpm josh git`, never a direct git call',
|
|
113
|
+
scan: scan_index_mutation,
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// The seed set: every rule green across the recorded corpus today. A new rule is appended here only
|
|
117
|
+
// after it has been verified green against past real runs.
|
|
118
|
+
const ALL_ASSERTIONS: ReadonlyArray<Assertion> = [index_mutation_assertion]
|
|
119
|
+
|
|
120
|
+
const behavior_rules = {
|
|
121
|
+
ALL_ASSERTIONS,
|
|
122
|
+
INDEX_ASSERTION_NAME,
|
|
123
|
+
command_of,
|
|
124
|
+
index_mutation_assertion,
|
|
125
|
+
is_index_mutation,
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export { behavior_rules }
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
import { fileURLToPath } from 'node:url'
|
|
4
|
+
import { build } from 'esbuild'
|
|
5
|
+
|
|
6
|
+
const PACKAGE_DIR = path.join(path.dirname(fileURLToPath(import.meta.url)), '..', '..')
|
|
7
|
+
const ENTRY_POINT = path.join(PACKAGE_DIR, 'scripts', 'josh', 'josh.ts')
|
|
8
|
+
const OUTFILE = path.join(PACKAGE_DIR, 'dist', 'josh.js')
|
|
9
|
+
const NODE_BANNER = '#!/usr/bin/env node'
|
|
10
|
+
|
|
11
|
+
async function build_bin(): Promise<void> {
|
|
12
|
+
await build({
|
|
13
|
+
entryPoints: [ENTRY_POINT],
|
|
14
|
+
outfile: OUTFILE,
|
|
15
|
+
bundle: true,
|
|
16
|
+
platform: 'node',
|
|
17
|
+
format: 'esm',
|
|
18
|
+
target: 'node22',
|
|
19
|
+
packages: 'external',
|
|
20
|
+
banner: { js: NODE_BANNER },
|
|
21
|
+
})
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async function main(): Promise<void> {
|
|
25
|
+
try {
|
|
26
|
+
await build_bin()
|
|
27
|
+
console.info(` ✔ ${OUTFILE} built`)
|
|
28
|
+
} catch (error) {
|
|
29
|
+
console.error(error instanceof Error ? error.message : String(error))
|
|
30
|
+
process.exit(1)
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (process.argv[1] === fileURLToPath(import.meta.url)) await main()
|
|
35
|
+
|
|
36
|
+
export { build_bin, NODE_BANNER, OUTFILE }
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
import { mkdirSync, readFileSync, writeFileSync } from 'node:fs'
|
|
3
|
+
import path from 'node:path'
|
|
4
|
+
import { fileURLToPath } from 'node:url'
|
|
5
|
+
import { init_logic } from '#scripts/init/init-logic'
|
|
6
|
+
|
|
7
|
+
const SCRIPT_DIR = path.dirname(fileURLToPath(import.meta.url))
|
|
8
|
+
const REPO_ROOT = path.resolve(SCRIPT_DIR, '..', '..')
|
|
9
|
+
const SOURCE_CLAUDE_MD = path.join(REPO_ROOT, 'CLAUDE.md')
|
|
10
|
+
const DIST_CLAUDE_MD = path.join(REPO_ROOT, 'dist', 'CLAUDE.md')
|
|
11
|
+
|
|
12
|
+
// Read kit's own CLAUDE.md and apply the distribution path transform. kit's source keeps relative
|
|
13
|
+
// paths so it resolves inside the kit repository; the published copy rewrites them so every backtick
|
|
14
|
+
// reference resolves in a consumer too (joshuafolkken/kit#1878). Pure — the guard test asserts the
|
|
15
|
+
// result carries no reference a consumer cannot open.
|
|
16
|
+
function generate_distributed_claude_md(): string {
|
|
17
|
+
return init_logic.transform_distributed_paths(readFileSync(SOURCE_CLAUDE_MD, 'utf8'))
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Ship the transformed CLAUDE.md from dist/, like every other build artifact: gitignored, but carried
|
|
21
|
+
// into the package by the `files` array, so a consumer imports it at
|
|
22
|
+
// node_modules/@joshuafolkken/kit/dist/CLAUDE.md.
|
|
23
|
+
function build_claude_md(): string {
|
|
24
|
+
mkdirSync(path.dirname(DIST_CLAUDE_MD), { recursive: true })
|
|
25
|
+
writeFileSync(DIST_CLAUDE_MD, generate_distributed_claude_md())
|
|
26
|
+
|
|
27
|
+
return DIST_CLAUDE_MD
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function main(): void {
|
|
31
|
+
console.info(` ✔ ${build_claude_md()} built`)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (process.argv[1] === fileURLToPath(import.meta.url)) main()
|
|
35
|
+
|
|
36
|
+
export {
|
|
37
|
+
build_claude_md,
|
|
38
|
+
generate_distributed_claude_md,
|
|
39
|
+
SOURCE_CLAUDE_MD,
|
|
40
|
+
DIST_CLAUDE_MD,
|
|
41
|
+
REPO_ROOT,
|
|
42
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
import { fileURLToPath } from 'node:url'
|
|
3
|
+
import { build_library, library_paths } from './build-library'
|
|
4
|
+
|
|
5
|
+
const CONFIG_MERGE_LIBRARY = 'config-merge'
|
|
6
|
+
const { outfile: CONFIG_MERGE_OUTFILE, dts_file: CONFIG_MERGE_DTS_FILE } =
|
|
7
|
+
library_paths(CONFIG_MERGE_LIBRARY)
|
|
8
|
+
|
|
9
|
+
async function build_config_merge_library(): Promise<void> {
|
|
10
|
+
await build_library(CONFIG_MERGE_LIBRARY)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
async function main(): Promise<void> {
|
|
14
|
+
try {
|
|
15
|
+
await build_config_merge_library()
|
|
16
|
+
console.info(` ✔ ${CONFIG_MERGE_OUTFILE} built`)
|
|
17
|
+
console.info(` ✔ ${CONFIG_MERGE_DTS_FILE} built`)
|
|
18
|
+
} catch (error) {
|
|
19
|
+
console.error(error instanceof Error ? error.message : String(error))
|
|
20
|
+
process.exit(1)
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (process.argv[1] === fileURLToPath(import.meta.url)) await main()
|
|
25
|
+
|
|
26
|
+
export { build_config_merge_library, CONFIG_MERGE_OUTFILE, CONFIG_MERGE_DTS_FILE }
|