@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,472 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
import { fileURLToPath } from 'node:url'
|
|
3
|
+
import type { IssueReference } from '#scripts/git/git-epic-reference'
|
|
4
|
+
import { git_gh_command } from '#scripts/git/git-gh-command'
|
|
5
|
+
import { cutoff_of, type ScanCutoff } from '#scripts/git/listing-cutoff'
|
|
6
|
+
import { parse_json_array_or_undefined } from '#scripts/git/parse-json-array'
|
|
7
|
+
import { bounded_pool } from '#scripts/lib/bounded-pool'
|
|
8
|
+
import { issue_citation } from '#scripts/rules/issue-citation'
|
|
9
|
+
import { z } from 'zod'
|
|
10
|
+
import {
|
|
11
|
+
epic_bundle,
|
|
12
|
+
type BacklogIssue,
|
|
13
|
+
type BundleAction,
|
|
14
|
+
type BundleDecision,
|
|
15
|
+
} from './epic-bundle'
|
|
16
|
+
import { epic_bundle_evidence } from './epic-bundle-evidence'
|
|
17
|
+
import { epic_bundle_gaps } from './epic-bundle-gaps'
|
|
18
|
+
import { epic_bundle_referenced, type ReferencedContext } from './epic-bundle-referenced'
|
|
19
|
+
import { epic_index, epic_schema, type FetchedEpics } from './epic-index'
|
|
20
|
+
import { epic_issue } from './epic-issue'
|
|
21
|
+
|
|
22
|
+
// `josh epic:bundle <N>` — after an issue is filed, look at the open backlog and say whether it
|
|
23
|
+
// belongs with something already there (joshuafolkken/kit#873).
|
|
24
|
+
//
|
|
25
|
+
// The machine finds the candidates; the decision to bundle is the caller's. This command prints what
|
|
26
|
+
// it found and what it recommends, and writes nothing.
|
|
27
|
+
|
|
28
|
+
const SUCCESS_EXIT_CODE = 0
|
|
29
|
+
const FAILURE_EXIT_CODE = 1
|
|
30
|
+
const ARGV_OFFSET = 2
|
|
31
|
+
// The open backlog was 13 issues when this was written. Scanning all of them is instant, so there is
|
|
32
|
+
// no index and no cache; add one when the number makes it necessary, not before.
|
|
33
|
+
const BACKLOG_LIMIT = 200
|
|
34
|
+
const USAGE = 'Usage: josh epic:bundle <issue-number>'
|
|
35
|
+
const UNKNOWN_REPO_MESSAGE =
|
|
36
|
+
'Could not read this repository from `git remote`, so the backlog cannot be keyed by repository — check `gh auth status` and that this is a checkout with an `origin` remote.'
|
|
37
|
+
|
|
38
|
+
// The backlog listing asks for the title too (joshuafolkken/kit#1252). Kept apart from the epic
|
|
39
|
+
// listing's schema rather than made optional on one: the epic listing does not ask for the field, and
|
|
40
|
+
// a schema that tolerates its absence everywhere would let a missing title pass unnoticed here.
|
|
41
|
+
//
|
|
42
|
+
// `blocked_by_count` is the blocker count GitHub already puts in the listing response
|
|
43
|
+
// (joshuafolkken/kit#1736). It is **nullish rather than defaulted**, and that is the whole safety of
|
|
44
|
+
// the read below: a row the listing carries no summary for must not be read as a row with no
|
|
45
|
+
// blockers, because that reading is what would silently drop a relation instead of costing a
|
|
46
|
+
// request. Nothing in today's pipeline is expected to arrive without one — the response carries the
|
|
47
|
+
// summary on every issue, and `git-gh-issue-list.ts` filters pull requests, which are what lack it,
|
|
48
|
+
// out client-side — so this tolerates a shape the listing is not supposed to hand over rather than
|
|
49
|
+
// describing one it does.
|
|
50
|
+
const backlog_schema = epic_schema.extend({
|
|
51
|
+
title: z.string().nullable(),
|
|
52
|
+
blocked_by_count: z.number().nullish(),
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
type BacklogRow = z.infer<typeof backlog_schema>
|
|
56
|
+
|
|
57
|
+
// The epic index is `epic-index.ts`'s, shared with the `auto-ok` pickup since
|
|
58
|
+
// joshuafolkken/kit#1633: both commands ask which epic tracks an issue, and a second copy of the
|
|
59
|
+
// task-list read would answer differently the first time that shape moved.
|
|
60
|
+
const { build_epic_index } = epic_index
|
|
61
|
+
|
|
62
|
+
function to_epic_field(epic: number | undefined): { epic?: number } {
|
|
63
|
+
return epic === undefined ? {} : { epic }
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Undefined when the read failed, which the caller reports — as opposed to an issue that genuinely
|
|
67
|
+
// declares no relations, which is an empty array.
|
|
68
|
+
async function epic_issue_relations(
|
|
69
|
+
issue_number: string,
|
|
70
|
+
repo: string,
|
|
71
|
+
): Promise<Array<IssueReference> | undefined> {
|
|
72
|
+
const parsed = epic_issue.parse_epic_issue(
|
|
73
|
+
await git_gh_command.issue_get_state_and_relations(issue_number),
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
return parsed === undefined ? undefined : epic_issue.blocker_references_of(parsed, repo)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// One read per backlog issue *that has blockers*, a few at a time.
|
|
80
|
+
//
|
|
81
|
+
// Since joshuafolkken/kit#1024 a read is `gh api`: one REST request for the issue, and a second to
|
|
82
|
+
// its `dependencies/blocked_by` endpoint unless the issue's own dependency summary reports exactly
|
|
83
|
+
// zero blockers. That second request was already skipped on a zero; the first one was not, so the
|
|
84
|
+
// command still paid one request for every open issue in the repository — a cost that grows with the
|
|
85
|
+
// backlog and made the command heavier exactly as more issues made it more useful
|
|
86
|
+
// (joshuafolkken/kit#1736). The listing that produced these rows already carries that same summary,
|
|
87
|
+
// so the zero is known *before* the read rather than inside it, and the read is skipped outright.
|
|
88
|
+
//
|
|
89
|
+
// One read would do if `gh` exposed the reverse of `blockedBy`, but it does not (`blocks` is not a
|
|
90
|
+
// JSON field), so a dependency declared on the *other* issue is only visible by asking that issue.
|
|
91
|
+
// Spawning all of them at once is what turns a rate limit into a wrong answer: a refused read becomes
|
|
92
|
+
// an empty relation list, and a bundle that should have been proposed is reported as "no strong
|
|
93
|
+
// signal" instead. Batching bounds the burst; the `unreadable` list below is what keeps a refused
|
|
94
|
+
// read from passing as an answer (joshuafolkken/kit#873). The pool itself is `bounded-pool.ts`,
|
|
95
|
+
// shared with the reference reads below it and with the eval suite (joshuafolkken/kit#1144).
|
|
96
|
+
const RELATION_CONCURRENCY = 8
|
|
97
|
+
const NO_BLOCKERS = 0
|
|
98
|
+
|
|
99
|
+
// GitHub's own count, not an inference from what was read. Strictly `=== 0`, so a row carrying no
|
|
100
|
+
// summary at all answers `false` and keeps its read: an absent count says nothing about whether the
|
|
101
|
+
// issue has blockers, and treating the two alike is the one way this shortcut could lose a
|
|
102
|
+
// relation. Skipping is cheap and wrong-in-silence; reading is a request and always right.
|
|
103
|
+
function has_no_blockers(row: BacklogRow): boolean {
|
|
104
|
+
return row.blocked_by_count === NO_BLOCKERS
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Every row still gets an entry, in order, so the index alignment `fetch_backlog` relies on is the
|
|
108
|
+
// same whether a row was read or answered from the listing.
|
|
109
|
+
async function fetch_relations(
|
|
110
|
+
rows: ReadonlyArray<BacklogRow>,
|
|
111
|
+
repo: string,
|
|
112
|
+
): Promise<Array<Array<IssueReference> | undefined>> {
|
|
113
|
+
return await bounded_pool.bounded_map(rows, RELATION_CONCURRENCY, async (row) =>
|
|
114
|
+
has_no_blockers(row) ? [] : await epic_issue_relations(String(row.number), repo),
|
|
115
|
+
)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// The open backlog, with each issue's relations and the epic tracking it. `unreadable` names the
|
|
119
|
+
// issues whose relations could not be read, so a "nothing to bundle" verdict is never quietly based
|
|
120
|
+
// on data that never arrived.
|
|
121
|
+
interface FetchedBacklog {
|
|
122
|
+
issues: Array<BacklogIssue>
|
|
123
|
+
unreadable: Array<number>
|
|
124
|
+
is_readable: boolean
|
|
125
|
+
// Why the backlog listing stopped short, or that it did not. A `ScanCutoff` rather than a flag
|
|
126
|
+
// since joshuafolkken/kit#1067: the page ceiling now bounds this listing too, and the two cutoffs
|
|
127
|
+
// cite different numbers.
|
|
128
|
+
cutoff?: ScanCutoff
|
|
129
|
+
has_epic_list?: boolean
|
|
130
|
+
// The epic listing's own cutoff. Separate from `cutoff`, which is the backlog listing's: the two
|
|
131
|
+
// hide different things, so a caller told only "something was truncated" cannot tell whether the
|
|
132
|
+
// epic that tracks a candidate was among what it could not see.
|
|
133
|
+
epic_cutoff?: ScanCutoff
|
|
134
|
+
// The epic view, kept so a referenced issue read afterwards can be placed without a second read.
|
|
135
|
+
context?: ReferencedContext
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// One listing row as the bundler reads it. Split from the fetch so that function stays a list of
|
|
139
|
+
// requests rather than a request list plus a row mapping.
|
|
140
|
+
function to_backlog_issue(
|
|
141
|
+
row: { number: number; title?: string | null; body?: string | null },
|
|
142
|
+
context: { repo: string; epics: Map<number, number>; epic_numbers: ReadonlySet<number> },
|
|
143
|
+
blocked_by: ReadonlyArray<IssueReference>,
|
|
144
|
+
): BacklogIssue {
|
|
145
|
+
return {
|
|
146
|
+
number: row.number,
|
|
147
|
+
repo: context.repo,
|
|
148
|
+
title: row.title ?? '',
|
|
149
|
+
body: row.body ?? '',
|
|
150
|
+
blocked_by,
|
|
151
|
+
is_epic: context.epic_numbers.has(row.number),
|
|
152
|
+
...to_epic_field(context.epics.get(row.number)),
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// What a caller does not need read for it. `issue:scout` asks about an issue that does not exist yet:
|
|
157
|
+
// it has no number, so no recorded dependency can name it and it declares none of its own — the
|
|
158
|
+
// relation reads cannot change its answer, and skipping them takes one request per open issue off the
|
|
159
|
+
// command a run makes before every filing (joshuafolkken/kit#1252). `epic:bundle` leaves it unset and
|
|
160
|
+
// reads them exactly as before.
|
|
161
|
+
interface BacklogOptions {
|
|
162
|
+
include_relations?: boolean
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// The relations, or an empty list each when the caller asked for none. Every issue still gets a row,
|
|
166
|
+
// so the index alignment `fetch_backlog` relies on holds either way.
|
|
167
|
+
async function read_relations(
|
|
168
|
+
rows: ReadonlyArray<BacklogRow>,
|
|
169
|
+
repo: string,
|
|
170
|
+
options: BacklogOptions | undefined,
|
|
171
|
+
): Promise<Array<Array<IssueReference> | undefined>> {
|
|
172
|
+
if (options?.include_relations === false) return rows.map(() => [])
|
|
173
|
+
|
|
174
|
+
return await fetch_relations(rows, repo)
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
async function fetch_backlog(
|
|
178
|
+
repo: string,
|
|
179
|
+
epics: Map<number, number>,
|
|
180
|
+
epic_numbers: ReadonlySet<number> = new Set(epics.values()),
|
|
181
|
+
options?: BacklogOptions,
|
|
182
|
+
): Promise<FetchedBacklog> {
|
|
183
|
+
const { json, is_capped } = await git_gh_command.issue_list_open_bodies(BACKLOG_LIMIT)
|
|
184
|
+
// A failed listing is not an empty backlog. Reported rather than degraded into one, which would
|
|
185
|
+
// have a `gh` failure arrive as "that issue does not exist".
|
|
186
|
+
if (json === undefined) return { issues: [], unreadable: [], is_readable: false }
|
|
187
|
+
// Same reason as `fetch_epics`: an unparseable listing is not an empty backlog.
|
|
188
|
+
const rows = parse_json_array_or_undefined(json, backlog_schema)
|
|
189
|
+
if (rows === undefined) return { issues: [], unreadable: [], is_readable: false }
|
|
190
|
+
const relations = await read_relations(rows, repo, options)
|
|
191
|
+
|
|
192
|
+
return {
|
|
193
|
+
is_readable: true,
|
|
194
|
+
// Either cutoff hides the same thing: a related issue past it, reported as "no existing issue
|
|
195
|
+
// shares a reference" — an assertion about data that was never loaded.
|
|
196
|
+
cutoff: cutoff_of(rows.length, BACKLOG_LIMIT, is_capped),
|
|
197
|
+
issues: rows.map((row, index) =>
|
|
198
|
+
to_backlog_issue(row, { repo, epics, epic_numbers }, relations[index] ?? []),
|
|
199
|
+
),
|
|
200
|
+
unreadable: rows.filter((_, index) => relations[index] === undefined).map((row) => row.number),
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const ACTION_LINES: Readonly<Record<string, string>> = {
|
|
205
|
+
add_to_epic: 'Add it to the epic that already tracks a related issue (Tier A — do it).',
|
|
206
|
+
create_epic: 'Create an epic for these (Tier A — do it).',
|
|
207
|
+
ask: 'Related issues sit in more than one epic: choose the one you recommend, add it, and record why (Tier A — do it).',
|
|
208
|
+
none: 'Nothing to bundle.',
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// `Nothing to bundle.` is right when nothing was found, and wrong when an epic already tracks the
|
|
212
|
+
// issue — there the answer is actionable: a caller looking for somewhere to put a prerequisite adds
|
|
213
|
+
// it to *that* epic rather than creating a second one (joshuafolkken/kit#943).
|
|
214
|
+
const ALREADY_TRACKED_LINE = 'Already in an epic — add to that one, do not create a second.'
|
|
215
|
+
|
|
216
|
+
function headline(decision: BundleDecision): string {
|
|
217
|
+
if (decision.action === 'none' && decision.epics.length > 0) return ALREADY_TRACKED_LINE
|
|
218
|
+
|
|
219
|
+
return ACTION_LINES[decision.action] ?? ''
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// The epics currently open, at this command's own listing limit. A failed read stays `undefined` and
|
|
223
|
+
// is reported: without the list, an issue an epic already tracks is told to create a second one —
|
|
224
|
+
// confidently, and with exit 0 (joshuafolkken/kit#950).
|
|
225
|
+
async function fetch_epics(): Promise<FetchedEpics | undefined> {
|
|
226
|
+
return await epic_index.fetch_epics(BACKLOG_LIMIT)
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function format_numbers(numbers: ReadonlyArray<number>): string {
|
|
230
|
+
return numbers.map((issue_number) => `#${String(issue_number)}`).join(', ')
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// The order to record alongside the bundle. Bundling without it records the batch and loses the
|
|
234
|
+
// reason it is a batch, so the recommendation carries it rather than leaving it to be remembered.
|
|
235
|
+
function format_links(links: ReadonlyArray<{ blocker: number; blocked: number }>): string {
|
|
236
|
+
if (links.length === 0) return ' Order: none declared — do not invent one'
|
|
237
|
+
const arrows = links.map((link) => `#${String(link.blocker)} -> #${String(link.blocked)}`)
|
|
238
|
+
|
|
239
|
+
return ` Order: ${arrows.join(', ')}`
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function format_order(
|
|
243
|
+
decision: BundleDecision,
|
|
244
|
+
subject: BacklogIssue,
|
|
245
|
+
backlog: ReadonlyArray<BacklogIssue>,
|
|
246
|
+
): Array<string> {
|
|
247
|
+
if (decision.action !== 'add_to_epic' && decision.action !== 'create_epic') return []
|
|
248
|
+
const members = backlog.filter((issue) => decision.candidates.includes(issue.number))
|
|
249
|
+
const children = epic_bundle.bundle_children(subject, members)
|
|
250
|
+
|
|
251
|
+
// The evidence goes under the order rather than beside the verdict: what it explains is the
|
|
252
|
+
// order, and a reader checking one reads straight on into the other (joshuafolkken/kit#1737).
|
|
253
|
+
return [
|
|
254
|
+
` Children: ${format_numbers(children)}`,
|
|
255
|
+
format_links(epic_bundle.bundle_dependency_links(subject, members)),
|
|
256
|
+
...epic_bundle_evidence.format_evidence(subject, members),
|
|
257
|
+
]
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// The verdicts that put the subject into an epic. Each one asserts that no epic already tracks it —
|
|
261
|
+
// `create_epic` asserts as much about the candidates too — and that negative is exactly what a cut
|
|
262
|
+
// epic listing cannot establish (joshuafolkken/kit#1697). `none` is absent on purpose: it either
|
|
263
|
+
// names the epic it *found* tracking the subject, which a cut cannot unseat, or reports no candidate
|
|
264
|
+
// at all, which says nothing about epics.
|
|
265
|
+
const PLACING_ACTIONS: ReadonlySet<BundleAction> = new Set<BundleAction>([
|
|
266
|
+
'add_to_epic',
|
|
267
|
+
'create_epic',
|
|
268
|
+
'ask',
|
|
269
|
+
])
|
|
270
|
+
|
|
271
|
+
// `is_membership_established` is what separates "no epic tracks these" from "their epics were never
|
|
272
|
+
// read".
|
|
273
|
+
function format_decision(
|
|
274
|
+
decision: BundleDecision,
|
|
275
|
+
subject: BacklogIssue,
|
|
276
|
+
backlog: ReadonlyArray<BacklogIssue>,
|
|
277
|
+
is_membership_established: boolean,
|
|
278
|
+
): string {
|
|
279
|
+
if (!is_membership_established && PLACING_ACTIONS.has(decision.action)) {
|
|
280
|
+
return epic_bundle_gaps.unconfirmed_membership(format_numbers(decision.candidates)).join('\n')
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const lines = [headline(decision), ` ${decision.reason}`]
|
|
284
|
+
|
|
285
|
+
if (decision.candidates.length > 0) {
|
|
286
|
+
lines.push(` Related: ${format_numbers(decision.candidates)}`)
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
if (decision.epics.length > 1) {
|
|
290
|
+
lines.push(` Epics involved: ${format_numbers(decision.epics)}`)
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
return [...lines, ...format_order(decision, subject, backlog)].join('\n')
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// The open backlog and the epics tracking it, read once.
|
|
297
|
+
async function read_backlog(repo: string, options?: BacklogOptions): Promise<FetchedBacklog> {
|
|
298
|
+
const open_epics = await fetch_epics()
|
|
299
|
+
|
|
300
|
+
if (open_epics === undefined) {
|
|
301
|
+
return { issues: [], unreadable: [], is_readable: false, has_epic_list: false }
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
const epics = build_epic_index(open_epics.epics)
|
|
305
|
+
// From the epic list itself, not from the index's values: an epic tracking no child yet has no
|
|
306
|
+
// entry in the index, and would enter the backlog as an ordinary issue that its own children then
|
|
307
|
+
// propose bundling with (joshuafolkken/kit#873).
|
|
308
|
+
const epic_numbers = new Set(open_epics.epics.map((epic) => epic.number))
|
|
309
|
+
|
|
310
|
+
return {
|
|
311
|
+
...(await fetch_backlog(repo, epics, epic_numbers, options)),
|
|
312
|
+
has_epic_list: true,
|
|
313
|
+
epic_cutoff: open_epics.cutoff,
|
|
314
|
+
context: { repo, epics, epic_numbers },
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// The backlog the decision is made from: the open listing, plus the referenced issues it could not
|
|
319
|
+
// show. Without the second half the command answers about a window that closes minutes after the
|
|
320
|
+
// follow-up issue is filed (joshuafolkken/kit#947).
|
|
321
|
+
async function widen_with_referenced(
|
|
322
|
+
subject: BacklogIssue,
|
|
323
|
+
backlog: FetchedBacklog,
|
|
324
|
+
): Promise<FetchedBacklog> {
|
|
325
|
+
const { context } = backlog
|
|
326
|
+
if (context === undefined) return backlog
|
|
327
|
+
// An issue an epic already tracks has nothing to bundle — `decide_bundle` answers from that alone
|
|
328
|
+
// and never looks at the candidates. Widening first spends a request per reference on a verdict
|
|
329
|
+
// that ignores them, and prints "⚠ Could not read #891." above "Already in an epic", which reads
|
|
330
|
+
// as a gap in an answer the read was never part of.
|
|
331
|
+
if (subject.epic !== undefined) return backlog
|
|
332
|
+
const known = new Set(backlog.issues.map((issue) => issue.number))
|
|
333
|
+
const found = await epic_bundle_referenced.referenced_candidates(subject, known, context)
|
|
334
|
+
if (found === undefined) return backlog
|
|
335
|
+
|
|
336
|
+
return {
|
|
337
|
+
...backlog,
|
|
338
|
+
issues: [...backlog.issues, ...found.issues],
|
|
339
|
+
unreadable: [...backlog.unreadable, ...found.unreadable],
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// Why nothing could be recommended, when the backlog could not be read. A failed listing is not an
|
|
344
|
+
// empty backlog: degrading it into one had a `gh` failure arrive as "that issue does not exist".
|
|
345
|
+
function unreadable_backlog_message(backlog: FetchedBacklog): string {
|
|
346
|
+
return backlog.has_epic_list === false
|
|
347
|
+
? 'Could not list the open epics; no recommendation was made.'
|
|
348
|
+
: 'Could not list the open issues; no recommendation was made.'
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
const NO_CUTOFF: ScanCutoff = 'none'
|
|
352
|
+
|
|
353
|
+
function warn_cutoff(message: string | undefined): void {
|
|
354
|
+
if (message !== undefined) console.error(message)
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// What the read could not cover, so a verdict is never quietly based on data that never arrived. The
|
|
358
|
+
// wording of each gap is `epic-bundle-gaps.ts`'s; what stays here is which gaps this command has.
|
|
359
|
+
function warn_about_gaps(backlog: FetchedBacklog): void {
|
|
360
|
+
if (backlog.unreadable.length > 0) {
|
|
361
|
+
console.error(`⚠ Could not read ${format_numbers(backlog.unreadable)}.`)
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
warn_cutoff(epic_bundle_gaps.backlog_gap(backlog.cutoff ?? NO_CUTOFF, BACKLOG_LIMIT))
|
|
365
|
+
warn_cutoff(epic_bundle_gaps.epic_gap(backlog.epic_cutoff ?? NO_CUTOFF, BACKLOG_LIMIT))
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
function report_decision(subject: BacklogIssue, backlog: FetchedBacklog, repo: string): number {
|
|
369
|
+
const others = backlog.issues.filter((issue) => issue.number !== subject.number)
|
|
370
|
+
const is_established = epic_bundle_gaps.is_membership_established(backlog.epic_cutoff)
|
|
371
|
+
const decision = epic_bundle.decide_bundle(subject, others)
|
|
372
|
+
|
|
373
|
+
// The `Related:` / `Children:` listings name issues as `#N`; linkified here so the recommendation a
|
|
374
|
+
// run copies into its reply carries clickable references rather than bare ones (joshuafolkken/kit#2329).
|
|
375
|
+
const report = format_decision(decision, subject, others, is_established)
|
|
376
|
+
|
|
377
|
+
console.info(issue_citation.linkify(report, repo))
|
|
378
|
+
|
|
379
|
+
return SUCCESS_EXIT_CODE
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// Widen, report what the read could not cover, then decide. Split out of `report_for`, which is
|
|
383
|
+
// otherwise all guard clauses.
|
|
384
|
+
async function report_widened(
|
|
385
|
+
subject: BacklogIssue,
|
|
386
|
+
backlog: FetchedBacklog,
|
|
387
|
+
repo: string,
|
|
388
|
+
): Promise<number> {
|
|
389
|
+
const widened = await widen_with_referenced(subject, backlog)
|
|
390
|
+
|
|
391
|
+
warn_about_gaps(widened)
|
|
392
|
+
|
|
393
|
+
return report_decision(subject, widened, repo)
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// The recommendation for one issue, from the open backlog around it.
|
|
397
|
+
async function report_for(issue_number: number, repo: string): Promise<number> {
|
|
398
|
+
const backlog = await read_backlog(repo)
|
|
399
|
+
|
|
400
|
+
if (!backlog.is_readable) {
|
|
401
|
+
console.error(unreadable_backlog_message(backlog))
|
|
402
|
+
|
|
403
|
+
return FAILURE_EXIT_CODE
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
const subject = backlog.issues.find((issue) => issue.number === issue_number)
|
|
407
|
+
|
|
408
|
+
if (subject === undefined) {
|
|
409
|
+
console.error(`#${String(issue_number)} is not an open issue in ${repo}.`)
|
|
410
|
+
|
|
411
|
+
return FAILURE_EXIT_CODE
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
return await report_widened(subject, backlog, repo)
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
async function run(argv: ReadonlyArray<string>): Promise<number> {
|
|
418
|
+
const issue_number = epic_issue.parse_epic_number(argv[0])
|
|
419
|
+
|
|
420
|
+
if (issue_number === undefined) {
|
|
421
|
+
console.error(USAGE)
|
|
422
|
+
|
|
423
|
+
return FAILURE_EXIT_CODE
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
const repo = await git_gh_command.repo_get_name_with_owner()
|
|
427
|
+
|
|
428
|
+
// A repository that could not be read is refused rather than stood in for. Since
|
|
429
|
+
// joshuafolkken/kit#1130 the members are keyed by repository and the blockers carry their own, so a
|
|
430
|
+
// placeholder matches nothing: every recorded dependency would vanish and the command would answer
|
|
431
|
+
// `Nothing to bundle.` with exit 0 — a confident verdict built on a read that failed, on the
|
|
432
|
+
// command a run consults before deciding an issue belongs nowhere.
|
|
433
|
+
if (repo === undefined) {
|
|
434
|
+
console.error(UNKNOWN_REPO_MESSAGE)
|
|
435
|
+
|
|
436
|
+
return FAILURE_EXIT_CODE
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
return await report_for(issue_number, repo)
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
// `process.exitCode` rather than `process.exit()`: the answer goes to standard output and a write to
|
|
443
|
+
// a pipe is asynchronous on macOS, so exiting can tear the process down before it drains. This
|
|
444
|
+
// command's answer is what a workflow reads and acts on, which is exactly that pipe. The same shape
|
|
445
|
+
// is in `scripts/cost-runtime/cost-cli.ts`, which met the truncation first (joshuafolkken/kit#1005).
|
|
446
|
+
async function main(argv: ReadonlyArray<string>): Promise<void> {
|
|
447
|
+
process.exitCode = await run(argv)
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
const epic_bundle_cli = {
|
|
451
|
+
USAGE,
|
|
452
|
+
BACKLOG_LIMIT,
|
|
453
|
+
ACTION_LINES,
|
|
454
|
+
ALREADY_TRACKED_LINE,
|
|
455
|
+
build_epic_index,
|
|
456
|
+
format_numbers,
|
|
457
|
+
format_order,
|
|
458
|
+
unreadable_backlog_message,
|
|
459
|
+
read_backlog,
|
|
460
|
+
report_for,
|
|
461
|
+
fetch_epics,
|
|
462
|
+
fetch_backlog,
|
|
463
|
+
widen_with_referenced,
|
|
464
|
+
warn_about_gaps,
|
|
465
|
+
format_decision,
|
|
466
|
+
run,
|
|
467
|
+
main,
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
if (process.argv[1] === fileURLToPath(import.meta.url)) await main(process.argv.slice(ARGV_OFFSET))
|
|
471
|
+
|
|
472
|
+
export { epic_bundle_cli }
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { epic_bundle, type BacklogIssue } from './epic-bundle'
|
|
2
|
+
|
|
3
|
+
// The facts the bundle decision was already made from, printed beside the order it prints
|
|
4
|
+
// (joshuafolkken/kit#1737).
|
|
5
|
+
//
|
|
6
|
+
// `is_strong_signal` reads exactly two things — whether a body names the other issue's number, and
|
|
7
|
+
// whether a `blocked-by` is already recorded in either direction — and neither ever reached the
|
|
8
|
+
// output. What did reach it was the verdict and, where relations happened to be recorded, the
|
|
9
|
+
// arrows. So confirming "should this issue really follow #123" meant opening both issue bodies and
|
|
10
|
+
// re-deriving by hand what the command had just finished reading. The facts cost nothing to fetch a
|
|
11
|
+
// second time: they are in hand at the moment the verdict is composed.
|
|
12
|
+
//
|
|
13
|
+
// **It states the facts and the direction they point, and stops there.** No line here says where to
|
|
14
|
+
// put the issue and none composes a command to run: ordering depends on intent, so a machine that
|
|
15
|
+
// decided it would write a confident order nobody's data supports. What is added is the material for
|
|
16
|
+
// the judgement, not the judgement.
|
|
17
|
+
|
|
18
|
+
// Which of the two readings a line came from. Kept apart in the data rather than only in the
|
|
19
|
+
// wording, so a caller can tell a recorded relation from a sentence somebody wrote.
|
|
20
|
+
type EvidenceKind = 'dependency' | 'reference'
|
|
21
|
+
|
|
22
|
+
// One fact, and the order it points to. `first` is the issue the fact puts ahead of `second`.
|
|
23
|
+
interface OrderingEvidence {
|
|
24
|
+
kind: EvidenceKind
|
|
25
|
+
first: number
|
|
26
|
+
second: number
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// The two readings, each written as a directed test of one issue against another. Both are
|
|
30
|
+
// `epic-bundle.ts`'s own, called rather than restated: the candidate search decides from exactly
|
|
31
|
+
// these, and a second spelling here would let the two disagree about what a signal is.
|
|
32
|
+
//
|
|
33
|
+
// **Both put the named issue first, and that is why one shape covers them.** A recorded
|
|
34
|
+
// `blocked-by` says so outright: the blocker has to land before the issue that declares it. A
|
|
35
|
+
// reference says it by having been written — the issue that names another was drafted with that
|
|
36
|
+
// other one already in existence, so the named one is the earlier of the two.
|
|
37
|
+
const EVIDENCE_TESTS: ReadonlyArray<{
|
|
38
|
+
kind: EvidenceKind
|
|
39
|
+
holds: (from: BacklogIssue, to: BacklogIssue) => boolean
|
|
40
|
+
}> = [
|
|
41
|
+
{ kind: 'dependency', holds: (from, to) => epic_bundle.names_as_blocker(from, to) },
|
|
42
|
+
{ kind: 'reference', holds: (from, to) => epic_bundle.names_in_body(from, to) },
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
// Both directions of one pair, because both are facts. Two issues that name each other produce two
|
|
46
|
+
// lines pointing opposite ways, which is the honest report: the reader is the one deciding.
|
|
47
|
+
function pair_evidence(subject: BacklogIssue, other: BacklogIssue): Array<OrderingEvidence> {
|
|
48
|
+
const directions = [
|
|
49
|
+
{ from: subject, to: other },
|
|
50
|
+
{ from: other, to: subject },
|
|
51
|
+
]
|
|
52
|
+
|
|
53
|
+
return EVIDENCE_TESTS.flatMap(({ kind, holds }) =>
|
|
54
|
+
directions
|
|
55
|
+
.filter((pair) => holds(pair.from, pair.to))
|
|
56
|
+
.map((pair) => ({ kind, first: pair.to.number, second: pair.from.number })),
|
|
57
|
+
)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Every unordered pair of the bundle's members.
|
|
61
|
+
//
|
|
62
|
+
// **The pairs are the ones `bundle_dependency_links` walks, not the subject's alone.** That function
|
|
63
|
+
// builds its member set as `[subject, ...candidates]` and emits an arrow for any pair of them, so an
|
|
64
|
+
// arrow between two candidates is ordinary — and evidence taken over the subject's pairs would leave
|
|
65
|
+
// exactly that arrow unexplained, which is the gap this whole block exists to close.
|
|
66
|
+
function member_pairs(
|
|
67
|
+
members: ReadonlyArray<BacklogIssue>,
|
|
68
|
+
): Array<{ left: BacklogIssue; right: BacklogIssue }> {
|
|
69
|
+
return members.flatMap((left, index) =>
|
|
70
|
+
members.slice(index + 1).map((right) => ({ left, right })),
|
|
71
|
+
)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Every fact behind the bundle, over the members the order is drawn from.
|
|
75
|
+
//
|
|
76
|
+
// The repository filter is the one `bundle_dependency_links` applies: a bare number declared in a
|
|
77
|
+
// member elsewhere would be resolved against this repository by the epic body, naming a different
|
|
78
|
+
// issue entirely (joshuafolkken/kit#1130).
|
|
79
|
+
function ordering_evidence(
|
|
80
|
+
subject: BacklogIssue,
|
|
81
|
+
candidates: ReadonlyArray<BacklogIssue>,
|
|
82
|
+
): Array<OrderingEvidence> {
|
|
83
|
+
const members = [subject, ...candidates].filter((member) => member.repo === subject.repo)
|
|
84
|
+
|
|
85
|
+
return member_pairs(members).flatMap((pair) => pair_evidence(pair.left, pair.right))
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// How each kind reads. `where` says the fact came from prose rather than from a recorded relation,
|
|
89
|
+
// and the two `order_*` halves say how strongly the fact settles the order.
|
|
90
|
+
//
|
|
91
|
+
// **A recorded dependency states the order; a reference only points at it.** A `blocked-by` says
|
|
92
|
+
// outright that the blocker lands first. A reference says it by having been written — which holds
|
|
93
|
+
// while a body is written once and stops holding the moment somebody edits an older issue to add a
|
|
94
|
+
// backlink to a newer one, as the review round cap and the upstream-interrupt rules both require. So
|
|
95
|
+
// the reference line reports the direction it points to and asserts nothing further; deciding is
|
|
96
|
+
// still the reader's.
|
|
97
|
+
const EVIDENCE_WORDING: Readonly<
|
|
98
|
+
Record<EvidenceKind, { verb: string; where: string; order_prefix: string; order_suffix: string }>
|
|
99
|
+
> = {
|
|
100
|
+
dependency: {
|
|
101
|
+
verb: 'is recorded as blocked by',
|
|
102
|
+
where: '',
|
|
103
|
+
order_prefix: '',
|
|
104
|
+
order_suffix: ' comes first',
|
|
105
|
+
},
|
|
106
|
+
reference: {
|
|
107
|
+
verb: 'names',
|
|
108
|
+
where: ' in its body',
|
|
109
|
+
order_prefix: 'that points to ',
|
|
110
|
+
order_suffix: ' first',
|
|
111
|
+
},
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const EVIDENCE_HEADING = ' Evidence:'
|
|
115
|
+
// One step deeper than the heading, which is itself indented under the verdict.
|
|
116
|
+
const EVIDENCE_INDENT_WIDTH = 4
|
|
117
|
+
const EVIDENCE_INDENT = ' '.repeat(EVIDENCE_INDENT_WIDTH)
|
|
118
|
+
|
|
119
|
+
function format_one(item: OrderingEvidence): string {
|
|
120
|
+
const { verb, where, order_prefix, order_suffix } = EVIDENCE_WORDING[item.kind]
|
|
121
|
+
const first = `#${String(item.first)}`
|
|
122
|
+
const second = `#${String(item.second)}`
|
|
123
|
+
const order = `${order_prefix}${first}${order_suffix}`
|
|
124
|
+
|
|
125
|
+
return `${EVIDENCE_INDENT}${second} ${verb} ${first}${where} — ${order}`
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// The block that goes under `Order:`. Empty when neither reading found anything, which leaves the
|
|
129
|
+
// existing `none declared — do not invent one` wording standing on its own.
|
|
130
|
+
function format_evidence(
|
|
131
|
+
subject: BacklogIssue,
|
|
132
|
+
candidates: ReadonlyArray<BacklogIssue>,
|
|
133
|
+
): Array<string> {
|
|
134
|
+
const found = ordering_evidence(subject, candidates)
|
|
135
|
+
if (found.length === 0) return []
|
|
136
|
+
|
|
137
|
+
return [EVIDENCE_HEADING, ...found.map((item) => format_one(item))]
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const epic_bundle_evidence = {
|
|
141
|
+
EVIDENCE_HEADING,
|
|
142
|
+
ordering_evidence,
|
|
143
|
+
format_evidence,
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export type { EvidenceKind, OrderingEvidence }
|
|
147
|
+
export { epic_bundle_evidence }
|