@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,209 @@
|
|
|
1
|
+
import { git_epic_parse } from '#scripts/git/git-epic-parse'
|
|
2
|
+
import { git_gh_command } from '#scripts/git/git-gh-command'
|
|
3
|
+
import { EPIC_LABEL, has_any_label } from '#scripts/git/issue-labels'
|
|
4
|
+
import { cutoff_of, type ScanCutoff } from '#scripts/git/listing-cutoff'
|
|
5
|
+
import { parse_json_array_or_undefined } from '#scripts/git/parse-json-array'
|
|
6
|
+
import type { OpenIssueData } from '#scripts/git/schemas'
|
|
7
|
+
import { z } from 'zod'
|
|
8
|
+
|
|
9
|
+
// Which epic tracks which issue — the one answer, in one place (joshuafolkken/kit#1633).
|
|
10
|
+
//
|
|
11
|
+
// `epic:bundle` has asked it since joshuafolkken/kit#873, to keep an issue an epic already tracks
|
|
12
|
+
// from being recommended a second one. The `auto-ok` pickup needs the same answer for the opposite
|
|
13
|
+
// reason: an issue tracked by an epic that will offer it must run through that epic's order and
|
|
14
|
+
// never be picked up standalone. Two callers, one question, so the read and the index live here
|
|
15
|
+
// rather than in either command — a second copy would drift the first time the task-list shape
|
|
16
|
+
// moved. `withheld_children` below is where the *second* half of that answer lives: which of the
|
|
17
|
+
// tracked children the standalone half actually has to hold back.
|
|
18
|
+
|
|
19
|
+
const epic_schema = z.object({ number: z.number(), body: z.string().nullable() })
|
|
20
|
+
|
|
21
|
+
interface FetchedEpics {
|
|
22
|
+
epics: Array<{ number: number; body: string }>
|
|
23
|
+
// The listing can be cut short. An epic past the cut is invisible, so an issue it tracks reads as
|
|
24
|
+
// tracked by nothing — which is a duplicate epic for `epic:bundle` and an out-of-order run for the
|
|
25
|
+
// `auto-ok` pickup. Both callers report it rather than answering as if the listing were complete.
|
|
26
|
+
cutoff: ScanCutoff
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Which epics track each issue, from the epics' own task lists. **A child can be named by more than
|
|
30
|
+
// one** (joshuafolkken/kit#1694): a task list expresses at most one epic per row, and nothing stops
|
|
31
|
+
// two epics writing the same row — `epic_lane_offer.dedupe_pools` has handled exactly that collision
|
|
32
|
+
// on the `epic:next` side since it was written. So the tracking is recorded whole here, and each
|
|
33
|
+
// caller collapses it for its own question rather than losing the other epics at build time.
|
|
34
|
+
//
|
|
35
|
+
// A child a single epic lists twice repeats that epic's number, which neither caller distinguishes
|
|
36
|
+
// from listing it once.
|
|
37
|
+
function build_tracking_index(
|
|
38
|
+
epics: ReadonlyArray<{ number: number; body: string }>,
|
|
39
|
+
): Map<number, ReadonlyArray<number>> {
|
|
40
|
+
const index = new Map<number, ReadonlyArray<number>>()
|
|
41
|
+
|
|
42
|
+
for (const epic of epics) {
|
|
43
|
+
for (const child of git_epic_parse.parse_task_list_issue_numbers(epic.body)) {
|
|
44
|
+
index.set(child, [...(index.get(child) ?? []), epic.number])
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return index
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Which *one* epic tracks each issue — `epic:bundle`'s question, which asks whether the issue is
|
|
52
|
+
// already in an epic and names it. The last epic to list the child wins, exactly as it did when this
|
|
53
|
+
// was built by a single `index.set` per row, so a collision answers as it always has.
|
|
54
|
+
function build_epic_index(
|
|
55
|
+
epics: ReadonlyArray<{ number: number; body: string }>,
|
|
56
|
+
): Map<number, number> {
|
|
57
|
+
const index = new Map<number, number>()
|
|
58
|
+
|
|
59
|
+
for (const [child, tracked_by] of build_tracking_index(epics)) {
|
|
60
|
+
const winner = tracked_by.at(-1)
|
|
61
|
+
if (winner !== undefined) index.set(child, winner)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return index
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const EPIC_LABELS: ReadonlySet<string> = new Set([EPIC_LABEL])
|
|
68
|
+
|
|
69
|
+
// Which epics in the opted-in listing stand for their children. An epic that carries `auto-ok` is a
|
|
70
|
+
// row of that listing which also carries `epic`, so no second read of an epic's labels is made.
|
|
71
|
+
function opted_in_epic_numbers(issues: ReadonlyArray<OpenIssueData>): ReadonlySet<number> {
|
|
72
|
+
return new Set(
|
|
73
|
+
issues.filter((issue) => has_any_label(issue.labels, EPIC_LABELS)).map((issue) => issue.number),
|
|
74
|
+
)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// The reverse of the tracking index — which children each epic lists, keyed by the epic. `index`
|
|
78
|
+
// answers child → its tracking epics; the closure walk below needs epic → its children, so the
|
|
79
|
+
// mapping is inverted once here rather than scanned per step.
|
|
80
|
+
function push_child(map: Map<number, Array<number>>, parent: number, child: number): void {
|
|
81
|
+
map.set(parent, [...(map.get(parent) ?? []), child])
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function invert_tracking(
|
|
85
|
+
index: ReadonlyMap<number, ReadonlyArray<number>>,
|
|
86
|
+
): Map<number, Array<number>> {
|
|
87
|
+
const children_of = new Map<number, Array<number>>()
|
|
88
|
+
|
|
89
|
+
for (const [child, parents] of index) {
|
|
90
|
+
for (const parent of parents) push_child(children_of, parent, child)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return children_of
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// An epic's children that are themselves epics — the only edges the closure walk follows. A child is
|
|
97
|
+
// an epic when it lists children of its own, so it is a key of the inverted index; a plain leaf child
|
|
98
|
+
// is never chased, and a childless nested epic has nothing to expand and drops out with no cost.
|
|
99
|
+
function child_epics_of(
|
|
100
|
+
children_of: ReadonlyMap<number, ReadonlyArray<number>>,
|
|
101
|
+
epic: number,
|
|
102
|
+
): ReadonlyArray<number> {
|
|
103
|
+
return (children_of.get(epic) ?? []).filter((child) => children_of.has(child))
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Every epic an `auto-ok` root opts in — the root itself and, transitively, every nested epic reached
|
|
107
|
+
// through its task list and theirs in turn (joshuafolkken/kit#2244). A person puts `auto-ok` on a root
|
|
108
|
+
// to approve everything under it, and the direct-children-only reading (joshuafolkken/kit#1668) stopped
|
|
109
|
+
// one level short: a grandchild fell out as "not opted in", though the same reasoning that admits the
|
|
110
|
+
// child admits it. So the root's approval is read down the whole subtree rather than one level of it.
|
|
111
|
+
//
|
|
112
|
+
// **Unlimited depth, and it terminates.** The epic graph is finite — every node is an open epic, capped
|
|
113
|
+
// at the listing limit — so no depth bound is needed to stop the walk; the `visited` set turns a cycle
|
|
114
|
+
// or a self-reference into a node already seen rather than an edge walked again, and an epic reachable
|
|
115
|
+
// through two roots is added once by that same set.
|
|
116
|
+
function reachable_epic_numbers(
|
|
117
|
+
index: ReadonlyMap<number, ReadonlyArray<number>>,
|
|
118
|
+
opted_in: ReadonlyArray<OpenIssueData>,
|
|
119
|
+
): ReadonlySet<number> {
|
|
120
|
+
const children_of = invert_tracking(index)
|
|
121
|
+
const visited = new Set<number>()
|
|
122
|
+
const stack = [...opted_in_epic_numbers(opted_in)]
|
|
123
|
+
|
|
124
|
+
while (stack.length > 0) {
|
|
125
|
+
const epic = stack.pop()
|
|
126
|
+
if (epic === undefined || visited.has(epic)) continue
|
|
127
|
+
visited.add(epic)
|
|
128
|
+
stack.push(...child_epics_of(children_of, epic).filter((child) => !visited.has(child)))
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return visited
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// **Which wins when an epic's declared order and a child's own `auto-ok` disagree — the single
|
|
135
|
+
// source** (joshuafolkken/kit#1668, narrowing joshuafolkken/kit#1633).
|
|
136
|
+
//
|
|
137
|
+
// The epic wins wherever the epic is actually going to offer the child, and only there. So the
|
|
138
|
+
// standalone half withholds a tracked child when the epic tracking it carries `auto-ok`: that epic's
|
|
139
|
+
// `blocked-by` graph sequences its children, and offering the child standalone as well would both
|
|
140
|
+
// skip that order and hand the same issue over twice.
|
|
141
|
+
//
|
|
142
|
+
// It withholds nothing when the tracking epic is **not** opted in. joshuafolkken/kit#1633 dropped
|
|
143
|
+
// that child too, on the ground that the standalone path read none of the ordering graph — which has
|
|
144
|
+
// since stopped being true: `auto_ok_cli.is_runnable` refuses a candidate whose `blockedBy` is still
|
|
145
|
+
// open, and `josh epic --ordered` records an epic's declared order as exactly those native
|
|
146
|
+
// relations. So the order survives the standalone route, while the old rule left a person's `auto-ok`
|
|
147
|
+
// on the child silently inert — no path offered it at all, because the epic side never reads an epic
|
|
148
|
+
// that did not opt in.
|
|
149
|
+
// **It answers with the epic, not merely with membership**, because the withholding and the sentence
|
|
150
|
+
// `backlog:plan` prints about it have to come from one answer. Handing the scope layer the whole
|
|
151
|
+
// index instead let it name an epic that was not withholding anything — the same misreport, moved.
|
|
152
|
+
//
|
|
153
|
+
// **Any one opted-in epic withholds the child** (joshuafolkken/kit#1694). It reads the whole tracking
|
|
154
|
+
// rather than one collapsed winner because the two are not the same answer when two epics name the
|
|
155
|
+
// same child: collapsed, an opted-in epic that merely came earlier in the listing is gone, the child
|
|
156
|
+
// reads as tracked by nobody who would offer it, and the standalone half hands it over while the
|
|
157
|
+
// opted-in epic hands it over too. The epic named as the reason is the first opted-in one in listing
|
|
158
|
+
// order — any of them is withholding it, and picking by position keeps the sentence deterministic.
|
|
159
|
+
//
|
|
160
|
+
// **The opted-in set is the transitive closure, not one level of it** (joshuafolkken/kit#2244). A
|
|
161
|
+
// child of a nested epic is withheld from the standalone half exactly when that nested epic is one the
|
|
162
|
+
// backlog is going to offer — which, since the closure reaches it, it now is. Withholding only the
|
|
163
|
+
// direct roots' children here would leave a nested epic's child offered both through the epic and
|
|
164
|
+
// standalone, the double-offer this whole rule exists to prevent.
|
|
165
|
+
function withheld_children(
|
|
166
|
+
index: ReadonlyMap<number, ReadonlyArray<number>>,
|
|
167
|
+
opted_in: ReadonlyArray<OpenIssueData>,
|
|
168
|
+
): ReadonlyMap<number, number> {
|
|
169
|
+
const epics = reachable_epic_numbers(index, opted_in)
|
|
170
|
+
const withheld = new Map<number, number>()
|
|
171
|
+
|
|
172
|
+
for (const [child, tracked_by] of index) {
|
|
173
|
+
const epic = tracked_by.find((candidate) => epics.has(candidate))
|
|
174
|
+
if (epic !== undefined) withheld.set(child, epic)
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return withheld
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// The epics currently open, so an issue can be matched to the one already tracking it.
|
|
181
|
+
//
|
|
182
|
+
// A failed read is reported rather than treated as "there are no epics": without the list, every
|
|
183
|
+
// tracked child reads as untracked, and both callers then act confidently on an answer built from a
|
|
184
|
+
// response nobody parsed.
|
|
185
|
+
async function fetch_epics(limit: number): Promise<FetchedEpics | undefined> {
|
|
186
|
+
const { json, is_capped } = await git_gh_command.issue_list_by_label(EPIC_LABEL, limit)
|
|
187
|
+
if (json === undefined) return undefined
|
|
188
|
+
// Not `parse_json_array_safe`: it answers `[]` for a response that is not JSON at all, which is
|
|
189
|
+
// indistinguishable from "no epics are open" — the silent absence this whole rule is about.
|
|
190
|
+
const rows = parse_json_array_or_undefined(json, epic_schema)
|
|
191
|
+
if (rows === undefined) return undefined
|
|
192
|
+
|
|
193
|
+
return {
|
|
194
|
+
cutoff: cutoff_of(rows.length, limit, is_capped),
|
|
195
|
+
epics: rows.map((row) => ({ number: row.number, body: row.body ?? '' })),
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const epic_index = {
|
|
200
|
+
build_epic_index,
|
|
201
|
+
build_tracking_index,
|
|
202
|
+
fetch_epics,
|
|
203
|
+
opted_in_epic_numbers,
|
|
204
|
+
reachable_epic_numbers,
|
|
205
|
+
withheld_children,
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export { epic_index, epic_schema }
|
|
209
|
+
export type { FetchedEpics }
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import type { IssueReference } from '#scripts/git/git-epic-reference'
|
|
2
|
+
import { git_gh_issue_rest } from '#scripts/git/git-gh-issue-rest'
|
|
3
|
+
import { parse_json_object_safe } from '#scripts/git/parse-json-array'
|
|
4
|
+
import { blocked_by_schema } from '#scripts/git/schemas'
|
|
5
|
+
import { z } from 'zod'
|
|
6
|
+
|
|
7
|
+
// The shapes one issue is read as, and the argument every epic command takes.
|
|
8
|
+
//
|
|
9
|
+
// The read goes through `gh api` (REST) since joshuafolkken/kit#1024; `git-gh-issue-rest.ts` maps
|
|
10
|
+
// the response back into the field names `gh issue view --json …` used, so the shapes below are
|
|
11
|
+
// the ones they always were.
|
|
12
|
+
//
|
|
13
|
+
// Single-sourced because three commands read the same JSON and take the same argument. Each had its
|
|
14
|
+
// own copy of the schema, the `blockedBy` unwrapping and the number parser, which is three places to
|
|
15
|
+
// fix the next time `gh` changes shape — and the one place a divergence would not be noticed
|
|
16
|
+
// (joshuafolkken/kit#862).
|
|
17
|
+
|
|
18
|
+
const label_schema = z.object({ name: z.string() })
|
|
19
|
+
|
|
20
|
+
const CLOSED = 'CLOSED'
|
|
21
|
+
const OPEN = 'OPEN'
|
|
22
|
+
const UNKNOWN_STATE = 'UNKNOWN'
|
|
23
|
+
const PULL_REQUEST_SEGMENT = '/pull/'
|
|
24
|
+
|
|
25
|
+
// Every field any epic command reads. Only `number` is required: a child reported with a field
|
|
26
|
+
// missing is still a child, and dropping it would hide it from the view a decision is made from.
|
|
27
|
+
// `body` is nullable as a guard: REST answers JSON null for an issue with none, and
|
|
28
|
+
// `git-gh-issue-rest.ts` already maps that to an empty string before this schema sees it.
|
|
29
|
+
const epic_issue_schema = z.object({
|
|
30
|
+
number: z.number(),
|
|
31
|
+
title: z.string().default(''),
|
|
32
|
+
body: z
|
|
33
|
+
.string()
|
|
34
|
+
.nullable()
|
|
35
|
+
.default('')
|
|
36
|
+
.transform((value) => value ?? ''),
|
|
37
|
+
state: z.string().default(UNKNOWN_STATE),
|
|
38
|
+
// The issue endpoint answers for a pull request as readily as for an issue, and nothing in the
|
|
39
|
+
// other fields separates them — an open PR reports `state: OPEN`, a merged one `MERGED`. The URL
|
|
40
|
+
// is what says which it is: `/pull/<n>` against `/issues/<n>` (joshuafolkken/kit#947).
|
|
41
|
+
url: z.string().default(''),
|
|
42
|
+
labels: z.array(label_schema).default([]),
|
|
43
|
+
blockedBy: blocked_by_schema,
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
type EpicIssue = z.infer<typeof epic_issue_schema>
|
|
47
|
+
|
|
48
|
+
// A shape surprise reads as an unreadable issue rather than throwing: `gh`'s JSON is somebody else's
|
|
49
|
+
// contract, and these commands are what a run consults before it starts.
|
|
50
|
+
function parse_epic_issue(raw: string | undefined): EpicIssue | undefined {
|
|
51
|
+
if (raw === undefined) return undefined
|
|
52
|
+
|
|
53
|
+
try {
|
|
54
|
+
return parse_json_object_safe(raw, epic_issue_schema)
|
|
55
|
+
} catch {
|
|
56
|
+
return undefined
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// The blockers an issue declares, unwrapped from the connection and carrying the repository each one
|
|
61
|
+
// lives in (joshuafolkken/kit#1126).
|
|
62
|
+
//
|
|
63
|
+
// `fallback_repo` is what an unqualified relation has always meant: the repository the issue itself is
|
|
64
|
+
// read in. REST names the blocker's repository in `repository_url`, and a relation may cross one — so
|
|
65
|
+
// keeping only the number resolved every blocker against the blocked issue's own repository, which
|
|
66
|
+
// named a different issue or none at all.
|
|
67
|
+
//
|
|
68
|
+
// The parameter is narrowed to the one field this reads, so a caller holding a differently-shaped
|
|
69
|
+
// issue — `backlog-pool.ts`'s standalone rows arrive as `OpenIssueData` — resolves through this same
|
|
70
|
+
// function instead of repeating the `repository_url` unwrapping (joshuafolkken/kit#1654).
|
|
71
|
+
function blocker_references_of(
|
|
72
|
+
issue: Pick<EpicIssue, 'blockedBy'>,
|
|
73
|
+
fallback_repo = '',
|
|
74
|
+
): Array<IssueReference> {
|
|
75
|
+
return (issue.blockedBy?.nodes ?? []).map((blocker) =>
|
|
76
|
+
git_gh_issue_rest.reference_of_blocker(blocker, fallback_repo),
|
|
77
|
+
)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// The same blockers as bare numbers, for the callers that predate the qualified read: the planner and
|
|
81
|
+
// the bundler. A projection of the read above rather than a second unwrapping of the connection.
|
|
82
|
+
//
|
|
83
|
+
// **The number alone is lossy, and those callers inherit that.** A blocker in another repository
|
|
84
|
+
// collapses to its number here and can then match a local issue that happens to share it —
|
|
85
|
+
// joshuafolkken/kit#1130 carries the case, which is `epic:bundle` reading a false relation and
|
|
86
|
+
// recording one onto the wrong issue. It predates joshuafolkken/kit#1126 rather than being introduced
|
|
87
|
+
// by it, and threading the repository through the bundler is its own change with its own reach.
|
|
88
|
+
function blockers_of(issue: EpicIssue): Array<number> {
|
|
89
|
+
return blocker_references_of(issue).map((blocker) => blocker.number)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function label_names(issue: EpicIssue): Array<string> {
|
|
93
|
+
return issue.labels.map((label) => label.name)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// `OPEN` or `CLOSED`, whatever casing the state arrived in.
|
|
97
|
+
//
|
|
98
|
+
// Anything that is not `CLOSED` reads as open, which is right for the auto-close it was written for:
|
|
99
|
+
// a child in any other state still has work left. It is **not** a test for "this issue is open" —
|
|
100
|
+
// `MERGED` maps to `OPEN` here — so a caller that needs that must ask `is_open` instead.
|
|
101
|
+
function normalize_state(state: string): 'OPEN' | 'CLOSED' {
|
|
102
|
+
return state.toUpperCase() === CLOSED ? CLOSED : 'OPEN'
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Strictly open: exactly `OPEN`, so `MERGED` (a pull request) and the `UNKNOWN` default of a read
|
|
106
|
+
// that came back shaped wrong both answer false rather than passing as an open issue.
|
|
107
|
+
function is_open(state: string): boolean {
|
|
108
|
+
return state.toUpperCase() === OPEN
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Whether the number answered with a pull request rather than an issue. The issue endpoint
|
|
112
|
+
// (`repos/{owner}/{repo}/issues/{N}`) serves both.
|
|
113
|
+
function is_pull_request(issue: EpicIssue): boolean {
|
|
114
|
+
return issue.url.includes(PULL_REQUEST_SEGMENT)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// `#123` and `123` are both accepted: the number is copied out of an issue reference as often as it
|
|
118
|
+
// is typed. `owner/repo#123` is refused rather than read as `123`, which would answer about *this*
|
|
119
|
+
// repository's issue of that number — a different issue entirely.
|
|
120
|
+
function parse_epic_number(raw = ''): number | undefined {
|
|
121
|
+
if (raw.includes('/')) return undefined
|
|
122
|
+
const parsed = Number(raw.replace('#', ''))
|
|
123
|
+
|
|
124
|
+
return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : undefined
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// An epic reference: `858`, `#858`, or `owner/repo#858` for an epic in another repository.
|
|
128
|
+
//
|
|
129
|
+
// A cross-repository epic must be qualified. A bare `#858` resolves to *this* repository's issue 858
|
|
130
|
+
// — a different issue entirely — so reading it as the other repository's would silently point at the
|
|
131
|
+
// wrong thing (joshuafolkken/kit#864).
|
|
132
|
+
interface EpicReference {
|
|
133
|
+
repo?: string
|
|
134
|
+
number: number
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const QUALIFIED_REFERENCE = /^([\w.-]+\/[\w.-]+)#(\d+)$/u
|
|
138
|
+
const QUALIFIED_REPO_GROUP = 1
|
|
139
|
+
const QUALIFIED_NUMBER_GROUP = 2
|
|
140
|
+
|
|
141
|
+
function to_qualified_reference(match: RegExpExecArray): EpicReference | undefined {
|
|
142
|
+
const repo = match[QUALIFIED_REPO_GROUP]
|
|
143
|
+
if (repo === undefined) return undefined
|
|
144
|
+
const number = Number(match[QUALIFIED_NUMBER_GROUP])
|
|
145
|
+
|
|
146
|
+
return Number.isSafeInteger(number) && number > 0 ? { repo, number } : undefined
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function parse_epic_reference(raw = ''): EpicReference | undefined {
|
|
150
|
+
const match = QUALIFIED_REFERENCE.exec(raw.trim())
|
|
151
|
+
if (match !== null) return to_qualified_reference(match)
|
|
152
|
+
const number = parse_epic_number(raw)
|
|
153
|
+
|
|
154
|
+
return number === undefined ? undefined : { number }
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const epic_issue = {
|
|
158
|
+
CLOSED,
|
|
159
|
+
blocker_references_of,
|
|
160
|
+
UNKNOWN_STATE,
|
|
161
|
+
parse_epic_issue,
|
|
162
|
+
blockers_of,
|
|
163
|
+
label_names,
|
|
164
|
+
normalize_state,
|
|
165
|
+
is_open,
|
|
166
|
+
is_pull_request,
|
|
167
|
+
parse_epic_number,
|
|
168
|
+
parse_epic_reference,
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export type { EpicIssue, EpicReference }
|
|
172
|
+
export { epic_issue }
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import { lane_capacity } from '#scripts/lane/lane-capacity'
|
|
2
|
+
import { epic_busy, type BusyRead } from './epic-busy'
|
|
3
|
+
import {
|
|
4
|
+
epic_candidate_confirm,
|
|
5
|
+
type ConfirmContext,
|
|
6
|
+
type RepoAnswer,
|
|
7
|
+
} from './epic-candidate-confirm'
|
|
8
|
+
import { epic_graph, type EpicChild } from './epic-graph'
|
|
9
|
+
import type { EpicVerdict } from './epic-report'
|
|
10
|
+
|
|
11
|
+
// Which children a repository has room to start right now (joshuafolkken/kit#1491).
|
|
12
|
+
//
|
|
13
|
+
// Until joshuafolkken/kit#1490 the answer was one or none: the contended resource was one working
|
|
14
|
+
// tree, so a single `in-progress` issue excluded everything else in that repository. A lane is its
|
|
15
|
+
// own checkout, so the question became how many are free — the repository's occupancy counted from
|
|
16
|
+
// GitHub, compared against `lane_capacity`'s limit.
|
|
17
|
+
//
|
|
18
|
+
// **The pool takes several sources, and none of them is an epic.** `RepoPool` is a candidate list
|
|
19
|
+
// with the context needed to confirm it. Since joshuafolkken/kit#1493 `epic:next` builds one per
|
|
20
|
+
// named epic and passes them all, which cost the caller change this design predicted and no rewrite
|
|
21
|
+
// of the scheduler: the signatures never learned what an epic is, because once the guarded resource
|
|
22
|
+
// is the lane rather than the repository, which epic a child came from stops mattering. The one
|
|
23
|
+
// thing several sources did add is `dedupe_pools` below — two epics can name the same child, and one
|
|
24
|
+
// child is one lane.
|
|
25
|
+
|
|
26
|
+
const WAIT_VERDICT: EpicVerdict = 'wait'
|
|
27
|
+
const RUN_VERDICT: EpicVerdict = 'run'
|
|
28
|
+
const NO_LANES = 0
|
|
29
|
+
const ONE_LANE = 1
|
|
30
|
+
|
|
31
|
+
// One source of candidates, with what confirming them needs. The context carries the graph a
|
|
32
|
+
// candidate is re-classified against, which is per-source by construction — two epics are two pools,
|
|
33
|
+
// each confirmed against its own graph.
|
|
34
|
+
interface RepoPool {
|
|
35
|
+
candidates: ReadonlyArray<EpicChild>
|
|
36
|
+
context: ConfirmContext
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// What is being asked of one repository. `is_all_lanes` is the caller's appetite rather than the
|
|
40
|
+
// repository's capacity: `epic:next --repo` prints a single token unless `--lanes` was passed, so a
|
|
41
|
+
// caller written against the one-child contract keeps getting exactly one child.
|
|
42
|
+
interface LaneRequest {
|
|
43
|
+
repo: string
|
|
44
|
+
limit: number
|
|
45
|
+
is_all_lanes: boolean
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// The answer for one repository: the children to start, the verdict standing in their place when
|
|
49
|
+
// there are none, and the line explaining either. The notice goes to standard error — standard
|
|
50
|
+
// output carries issue numbers or a verdict and nothing else.
|
|
51
|
+
interface LaneOffer {
|
|
52
|
+
children: ReadonlyArray<EpicChild>
|
|
53
|
+
verdict: EpicVerdict
|
|
54
|
+
notice: string
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// A read that could not see the whole listing authorizes nothing, whatever its count says. Kept as a
|
|
58
|
+
// kind test rather than folded into the arithmetic: "I saw no holder" and "there are no holders"
|
|
59
|
+
// differ, and only the first one is a reason to wait.
|
|
60
|
+
function is_held(read: BusyRead): boolean {
|
|
61
|
+
return read.kind === 'unreadable' || read.kind === 'truncated'
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function free_lanes(read: BusyRead, limit: number): number {
|
|
65
|
+
return is_held(read) ? NO_LANES : lane_capacity.free_lanes(limit, epic_busy.occupied_lanes(read))
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function wanted_of(request: LaneRequest, free: number): number {
|
|
69
|
+
return request.is_all_lanes ? free : Math.min(ONE_LANE, free)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Said out loud because a run told only "wait" has nothing to go and look at, and because the
|
|
73
|
+
// occupancy is the number a person tunes `JOSH_LANE_LIMIT` against.
|
|
74
|
+
function withheld_message(repo: string): string {
|
|
75
|
+
return `No runnable child in ${repo}: every candidate was withheld when its blocker relations were confirmed — the reason for each is above.`
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function offered_notice(
|
|
79
|
+
children: ReadonlyArray<EpicChild>,
|
|
80
|
+
read: BusyRead,
|
|
81
|
+
request: LaneRequest,
|
|
82
|
+
): string {
|
|
83
|
+
if (children.length === NO_LANES) return withheld_message(request.repo)
|
|
84
|
+
if (read.kind !== 'busy') return ''
|
|
85
|
+
|
|
86
|
+
return epic_busy.occupancy_message(read.issues, request.repo, request.limit)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Two pools that both offered nothing can disagree about why, and the answer has to be the one that
|
|
90
|
+
// says what a caller should do. The order is `epic_report.decide_verdict`'s own — waiting before
|
|
91
|
+
// stopping, because a run that stops while something is still resolving on its own gives up on an
|
|
92
|
+
// epic that was going to finish — rather than a second ranking invented here.
|
|
93
|
+
const VERDICT_PRIORITY: ReadonlyArray<EpicVerdict> = [RUN_VERDICT, WAIT_VERDICT, 'stop', 'complete']
|
|
94
|
+
|
|
95
|
+
function combine_verdicts(left: EpicVerdict, right: EpicVerdict): EpicVerdict {
|
|
96
|
+
return VERDICT_PRIORITY.indexOf(left) <= VERDICT_PRIORITY.indexOf(right) ? left : right
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Every pool is a source of candidates **for the repository the request names**. The free-lane count
|
|
100
|
+
// was read for that one repository, so spending it on a child that lives somewhere else would
|
|
101
|
+
// allocate a lane nobody counted — the double-allocation joshuafolkken/kit#925 exists to prevent.
|
|
102
|
+
// Dropped rather than offered: a caller with children in two repositories asks twice, once per
|
|
103
|
+
// repository, exactly as `--repo` already makes it.
|
|
104
|
+
function candidates_in(pool: RepoPool, repo: string): RepoPool {
|
|
105
|
+
return { ...pool, candidates: pool.candidates.filter((child) => child.repo === repo) }
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// One pool's candidates, minus every one an earlier pool already carries. `seen` is mutated rather
|
|
109
|
+
// than rebuilt because the earlier pools' claim is what the later one is filtered against.
|
|
110
|
+
function unseen_candidates(pool: RepoPool, seen: Set<string>): RepoPool {
|
|
111
|
+
const candidates: Array<EpicChild> = []
|
|
112
|
+
|
|
113
|
+
for (const child of pool.candidates) {
|
|
114
|
+
const key = epic_graph.key_of(child)
|
|
115
|
+
|
|
116
|
+
if (seen.has(key)) continue
|
|
117
|
+
seen.add(key)
|
|
118
|
+
candidates.push(child)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return { ...pool, candidates }
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// A child two epics both track is still one child, and entering it twice would open two lanes on one
|
|
125
|
+
// issue — two branches, two pull requests, and the second one merging over the first
|
|
126
|
+
// (joshuafolkken/kit#1493). Keyed through `epic_graph.key_of`, the one spelling of an issue's
|
|
127
|
+
// identity in this package: a bare number names a different issue in another repository.
|
|
128
|
+
//
|
|
129
|
+
// **The earlier pool keeps it**, and that is a decision rather than an accident of iteration order.
|
|
130
|
+
// The pool order is the order the epics were named, which is the only ranking a person typed. It
|
|
131
|
+
// also settles what happens when the first pool *withholds* the child: it stays withheld, because a
|
|
132
|
+
// `blocked-by` relation belongs to the issue rather than to the epic that lists it, so offering it
|
|
133
|
+
// from the second pool would start work the first pool's confirmation had just refused.
|
|
134
|
+
function dedupe_pools(pools: ReadonlyArray<RepoPool>): ReadonlyArray<RepoPool> {
|
|
135
|
+
const seen = new Set<string>()
|
|
136
|
+
|
|
137
|
+
return pools.map((pool) => unseen_candidates(pool, seen))
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
async function ask_pool(pool: RepoPool, wanted: number): Promise<RepoAnswer> {
|
|
141
|
+
return await epic_candidate_confirm.answer_for_repo(pool.candidates, pool.context, wanted)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// The pools walked in order until the free lanes are spoken for. The confirmation walk itself is
|
|
145
|
+
// per-pool, so a candidate is still re-classified against its own graph; what this adds is that a
|
|
146
|
+
// second pool is asked only for the lanes the first one left — and is not asked at all once there
|
|
147
|
+
// are none, since a walk with no appetite would answer "every candidate was withheld" having
|
|
148
|
+
// examined none of them.
|
|
149
|
+
async function collect(
|
|
150
|
+
pools: ReadonlyArray<RepoPool>,
|
|
151
|
+
wanted: number,
|
|
152
|
+
): Promise<{ children: ReadonlyArray<EpicChild>; verdict: EpicVerdict }> {
|
|
153
|
+
const children: Array<EpicChild> = []
|
|
154
|
+
let verdict: EpicVerdict = 'complete'
|
|
155
|
+
|
|
156
|
+
for (const pool of pools) {
|
|
157
|
+
if (children.length >= wanted) break
|
|
158
|
+
|
|
159
|
+
const answer = await ask_pool(pool, wanted - children.length)
|
|
160
|
+
|
|
161
|
+
children.push(...answer.children)
|
|
162
|
+
verdict = combine_verdicts(verdict, answer.verdict)
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return { children, verdict: children.length > NO_LANES ? RUN_VERDICT : verdict }
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// The repository is asked how full it is **before** any candidate is confirmed, for the reason
|
|
169
|
+
// joshuafolkken/kit#1121 records: a repository with no free lane is handed nothing, so the relations
|
|
170
|
+
// request that would confirm a candidate there buys an answer nobody reads — and a polling `epicrun`
|
|
171
|
+
// would pay it every round.
|
|
172
|
+
async function offer_for_repo(
|
|
173
|
+
pools: ReadonlyArray<RepoPool>,
|
|
174
|
+
request: LaneRequest,
|
|
175
|
+
): Promise<LaneOffer> {
|
|
176
|
+
const read = await epic_busy.read_repository(request.repo)
|
|
177
|
+
const free = free_lanes(read, request.limit)
|
|
178
|
+
|
|
179
|
+
if (free === NO_LANES) {
|
|
180
|
+
return {
|
|
181
|
+
children: [],
|
|
182
|
+
verdict: WAIT_VERDICT,
|
|
183
|
+
notice: epic_busy.busy_reason(read, request.repo, request.limit),
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const for_repo = dedupe_pools(pools.map((pool) => candidates_in(pool, request.repo)))
|
|
188
|
+
const answer = await collect(for_repo, wanted_of(request, free))
|
|
189
|
+
|
|
190
|
+
return { ...answer, notice: offered_notice(answer.children, read, request) }
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const epic_lane_offer = {
|
|
194
|
+
is_held,
|
|
195
|
+
free_lanes,
|
|
196
|
+
wanted_of,
|
|
197
|
+
combine_verdicts,
|
|
198
|
+
candidates_in,
|
|
199
|
+
unseen_candidates,
|
|
200
|
+
dedupe_pools,
|
|
201
|
+
withheld_message,
|
|
202
|
+
collect,
|
|
203
|
+
offer_for_repo,
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
export type { LaneOffer, LaneRequest, RepoPool }
|
|
207
|
+
export { epic_lane_offer }
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { EPIC_LABEL, has_label_name } from '#scripts/git/issue-labels'
|
|
2
|
+
import type { EpicChild } from './epic-graph'
|
|
3
|
+
|
|
4
|
+
// Whether a task-list row points at another epic (joshuafolkken/kit#1476).
|
|
5
|
+
//
|
|
6
|
+
// An epic's body can hold `- [ ] #<another epic>` — nothing stops it being typed — and until this
|
|
7
|
+
// module nothing read it. `epic-classify.ts` sorted the row like any other child and
|
|
8
|
+
// `from_blockers` minted `runnable` for it, so `epicrun` handed an epic to `fullrun` as an ordinary
|
|
9
|
+
// issue and the run had nothing to implement.
|
|
10
|
+
//
|
|
11
|
+
// Two callers ask the question and they must not answer it differently: the classification, which
|
|
12
|
+
// **withholds** the row, and the audit, which **reports** it. Spelled twice they would drift, and a
|
|
13
|
+
// row the audit called fine would then be one the classification refused, or the reverse.
|
|
14
|
+
|
|
15
|
+
// **The test is the child's `epic` label, and nothing else.**
|
|
16
|
+
//
|
|
17
|
+
// It is deliberately not any reading of how the row is written. A row naming `owner/repo#N` is a
|
|
18
|
+
// **different** property, and a legitimate one: such a row disables the epic auto-close by design,
|
|
19
|
+
// which is why `CLAUDE.md` requires a cross-repository backlink to be written as prose rather than
|
|
20
|
+
// as a task-list row. Collapsing the two would refuse the very shape that document asks for.
|
|
21
|
+
//
|
|
22
|
+
// The properties are orthogonal, and all four combinations are meant to work: a cross-repository
|
|
23
|
+
// child that is not an epic stays runnable and unreported, and one that is an epic is withheld and
|
|
24
|
+
// reported exactly like a local one.
|
|
25
|
+
//
|
|
26
|
+
// The comparison is case-insensitive because GitHub keeps the casing a label was created with and
|
|
27
|
+
// treats `Epic` and `epic` as one label — a repository that predates these scripts can answer with
|
|
28
|
+
// either spelling, and a row read by eye against the lowercase string is one nothing withholds.
|
|
29
|
+
function is_nested_epic(child: EpicChild): boolean {
|
|
30
|
+
return has_label_name(child.labels, EPIC_LABEL)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const epic_nested = {
|
|
34
|
+
is_nested_epic,
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export { epic_nested }
|