@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,370 @@
|
|
|
1
|
+
import { git_epic_parse, type ExternalChild } from '#scripts/git/git-epic-parse'
|
|
2
|
+
import { git_gh_command } from '#scripts/git/git-gh-command'
|
|
3
|
+
import type { IssueReadFailure } from '#scripts/git/git-gh-issue-read'
|
|
4
|
+
import { epic_cross_repo } from './epic-cross-repo'
|
|
5
|
+
import type { EpicChild, IssueReference } from './epic-graph'
|
|
6
|
+
import { epic_issue, type EpicIssue } from './epic-issue'
|
|
7
|
+
import { epic_relation_recheck } from './epic-relation-recheck'
|
|
8
|
+
|
|
9
|
+
// Reading an epic and its children from GitHub.
|
|
10
|
+
//
|
|
11
|
+
// All execution state lives on GitHub and nowhere else — no local state file. A run interrupted
|
|
12
|
+
// halfway is resumed by asking again, which is the whole reason `epic:next` can be the base of an
|
|
13
|
+
// unattended run (joshuafolkken/kit#860).
|
|
14
|
+
|
|
15
|
+
const CHILD_LIMIT = 200
|
|
16
|
+
|
|
17
|
+
function to_child(parsed: EpicIssue, repo: string): EpicChild {
|
|
18
|
+
return {
|
|
19
|
+
number: parsed.number,
|
|
20
|
+
repo,
|
|
21
|
+
state: epic_issue.normalize_state(parsed.state),
|
|
22
|
+
labels: epic_issue.label_names(parsed),
|
|
23
|
+
blocked_by: epic_issue.blocker_references_of(parsed, repo),
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// The `--repo` scope a child is read through, in the one place that decides it.
|
|
28
|
+
//
|
|
29
|
+
// A child in the repository the command runs in is read unqualified — exactly as `fetch_children`
|
|
30
|
+
// reads it — and a child elsewhere is read through its own repository, exactly as
|
|
31
|
+
// `fetch_external_children` does. Every read of a child's fields goes through this, bodies included:
|
|
32
|
+
// an unqualified read of a cross-repository child returns *this* repository's issue of that number,
|
|
33
|
+
// a different issue entirely (joshuafolkken/kit#1012).
|
|
34
|
+
function scope_for(child_repo: string, current_repo: string): string | undefined {
|
|
35
|
+
return child_repo === current_repo ? undefined : child_repo
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// One child's blockers, read from the relations listing rather than from the issue's own summary
|
|
39
|
+
// count (joshuafolkken/kit#1113). Addressed through the same `scope_for` every other read of a child
|
|
40
|
+
// goes through. The recheck only ever reaches children of the epic's own repository, so what the
|
|
41
|
+
// scope varies with is where the *epic* is: `epic:next owner/other#858` run from here reads them
|
|
42
|
+
// through `owner/other`, and reading them unqualified would answer from this repository's issues of
|
|
43
|
+
// those numbers instead (joshuafolkken/kit#1012).
|
|
44
|
+
async function read_child_blockers(
|
|
45
|
+
child: EpicChild,
|
|
46
|
+
current_repo: string,
|
|
47
|
+
): Promise<Array<IssueReference>> {
|
|
48
|
+
return await git_gh_command.issue_blocked_by_references(
|
|
49
|
+
String(child.number),
|
|
50
|
+
child.repo,
|
|
51
|
+
scope_for(child.repo, current_repo),
|
|
52
|
+
)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// The epic's own row, read once and parsed once: the body every later step consults, the bare
|
|
56
|
+
// numbers naming children in the epic's repository, and the qualified rows naming children elsewhere.
|
|
57
|
+
interface EpicBody {
|
|
58
|
+
body: string | undefined
|
|
59
|
+
// Why the body produced nothing, when it produced nothing. **The epic's body is the one read whose
|
|
60
|
+
// failure is invisible downstream**: `parse_task_list_issue_numbers(undefined)` answers `[]`, so a
|
|
61
|
+
// body nobody could read is indistinguishable from an epic that tracks no children — and that one
|
|
62
|
+
// is dropped from the views as an ordinary, unpopulated epic. A run whose DNS hiccuped on this one
|
|
63
|
+
// request therefore reported the backlog empty and ended (joshuafolkken/kit#1690).
|
|
64
|
+
body_failure: IssueReadFailure | undefined
|
|
65
|
+
child_numbers: ReadonlyArray<number>
|
|
66
|
+
external: ReadonlyArray<ExternalChild>
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async function fetch_epic_body(epic_number: number, scope?: string): Promise<EpicBody> {
|
|
70
|
+
const read = await git_gh_command.issue_get_body_classified(String(epic_number), scope)
|
|
71
|
+
const body = read.kind === 'read' ? read.text : undefined
|
|
72
|
+
|
|
73
|
+
return {
|
|
74
|
+
body,
|
|
75
|
+
body_failure: read.kind === 'read' ? undefined : read,
|
|
76
|
+
child_numbers: git_epic_parse.parse_task_list_issue_numbers(body),
|
|
77
|
+
external: git_epic_parse.parse_external_task_list_children(body),
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// What the recheck needs to know about the read it is correcting: the epic's body, the repository
|
|
82
|
+
// its bare declared numbers name, and the repository the command runs in.
|
|
83
|
+
interface RecheckScope {
|
|
84
|
+
body: string | undefined
|
|
85
|
+
repo: string
|
|
86
|
+
current_repo: string
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// joshuafolkken/kit#1113: the second look at the relations, taken here rather than in `epic:next`
|
|
90
|
+
// and `epic:audit` separately — both read their children through this one snapshot, so correcting it
|
|
91
|
+
// once corrects both, and neither command needs to know the check exists.
|
|
92
|
+
// `repo` is the epic's own repository, which is what a bare declared number names — not
|
|
93
|
+
// `current_repo`, which is where the command happens to be running.
|
|
94
|
+
async function rechecked_children(
|
|
95
|
+
children: ReadonlyArray<EpicChild>,
|
|
96
|
+
snapshot: RecheckScope,
|
|
97
|
+
): Promise<ReadonlyArray<EpicChild>> {
|
|
98
|
+
return await epic_relation_recheck.recheck_missing_relations(
|
|
99
|
+
children,
|
|
100
|
+
snapshot.body,
|
|
101
|
+
snapshot.repo,
|
|
102
|
+
async (child) => await read_child_blockers(child, snapshot.current_repo),
|
|
103
|
+
)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Numbers read from one repository's task-list rows, as references to issues in that repository.
|
|
107
|
+
function to_references(issue_numbers: ReadonlyArray<number>, repo: string): Array<IssueReference> {
|
|
108
|
+
return issue_numbers.map((issue_number) => ({ repo, number: issue_number }))
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// One child's read: the child when it came back, and whether the failure was one the same request
|
|
112
|
+
// could succeed at a moment later (joshuafolkken/kit#1690). A response that arrived and would not
|
|
113
|
+
// parse is **not** unreachable — asking again answers the same thing.
|
|
114
|
+
interface ChildRead {
|
|
115
|
+
child: EpicChild | undefined
|
|
116
|
+
is_unreachable: boolean
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async function fetch_child_read(
|
|
120
|
+
issue_number: number,
|
|
121
|
+
repo: string,
|
|
122
|
+
scope?: string,
|
|
123
|
+
): Promise<ChildRead> {
|
|
124
|
+
const read = await git_gh_command.issue_get_state_and_relations_classified(
|
|
125
|
+
String(issue_number),
|
|
126
|
+
scope,
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
if (read.kind !== 'read') {
|
|
130
|
+
return { child: undefined, is_unreachable: git_gh_command.is_unreachable_read(read) }
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const parsed = epic_issue.parse_epic_issue(read.json)
|
|
134
|
+
|
|
135
|
+
return { child: parsed === undefined ? undefined : to_child(parsed, repo), is_unreachable: false }
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// One child's state, labels and native relations. A child that cannot be read is reported as
|
|
139
|
+
// missing rather than assumed closed: assuming would let an epic advance past a child nobody looked
|
|
140
|
+
// at.
|
|
141
|
+
async function fetch_child(
|
|
142
|
+
issue_number: number,
|
|
143
|
+
repo: string,
|
|
144
|
+
scope?: string,
|
|
145
|
+
): Promise<EpicChild | undefined> {
|
|
146
|
+
const read = await fetch_child_read(issue_number, repo, scope)
|
|
147
|
+
|
|
148
|
+
return read.child
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// What a batch read produced, with the children it could not read kept rather than dropped.
|
|
152
|
+
//
|
|
153
|
+
// Dropping them is not an option in either direction. An epic whose children all failed to read
|
|
154
|
+
// would otherwise look like an epic with no open children — "complete" — and a single unreadable
|
|
155
|
+
// child would vanish from the graph, so whatever it blocks would look unblocked and be run
|
|
156
|
+
// (joshuafolkken/kit#860).
|
|
157
|
+
//
|
|
158
|
+
// The unread ones carry their repository, not just their number. An epic tracking
|
|
159
|
+
// `- [ ] sveltejs/kit#7` had it refused by the owner restriction and reported as `Could not read #7`,
|
|
160
|
+
// which a reader resolves against the repository they are standing in — a different issue
|
|
161
|
+
// (joshuafolkken/kit#1016).
|
|
162
|
+
interface FetchedChildren {
|
|
163
|
+
children: ReadonlyArray<EpicChild>
|
|
164
|
+
unreadable: ReadonlyArray<IssueReference>
|
|
165
|
+
skipped: ReadonlyArray<IssueReference>
|
|
166
|
+
// How many of the unreadable ones failed on the transport. Carried from the reads themselves
|
|
167
|
+
// rather than probed afterwards: a connection that dropped for a moment fails a read at t=0 and
|
|
168
|
+
// answers a probe fired at t=1 that everything is fine (joshuafolkken/kit#1690).
|
|
169
|
+
//
|
|
170
|
+
// **A count rather than a flag, because the question the caller asks is about _every_ failure.**
|
|
171
|
+
// One child unreachable beside another permanently refused is not a run worth repeating — the
|
|
172
|
+
// refused one answers the same however often it is asked — so a flag ORed across the groups would
|
|
173
|
+
// answer `retry` for ever and never reach the verdict that says a person is needed.
|
|
174
|
+
unreachable_count: number
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function to_children(reads: ReadonlyArray<ChildRead>): Array<EpicChild> {
|
|
178
|
+
return reads.map((read) => read.child).filter((child): child is EpicChild => child !== undefined)
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function count_unreachable(reads: ReadonlyArray<ChildRead>): number {
|
|
182
|
+
return reads.filter((read) => read.is_unreachable).length
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function is_body_unreachable(failure: IssueReadFailure | undefined): boolean {
|
|
186
|
+
return failure !== undefined && git_gh_command.is_unreachable_read(failure)
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Every child the epic's task list tracks, in the order the body lists them.
|
|
190
|
+
async function fetch_children(
|
|
191
|
+
child_numbers: ReadonlyArray<number>,
|
|
192
|
+
repo: string,
|
|
193
|
+
scope?: string,
|
|
194
|
+
): Promise<FetchedChildren> {
|
|
195
|
+
const limited = child_numbers.slice(0, CHILD_LIMIT)
|
|
196
|
+
const reads = await Promise.all(
|
|
197
|
+
limited.map(async (issue_number) => await fetch_child_read(issue_number, repo, scope)),
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
return {
|
|
201
|
+
children: to_children(reads),
|
|
202
|
+
unreadable: to_references(
|
|
203
|
+
limited.filter((_, index) => reads[index]?.child === undefined),
|
|
204
|
+
repo,
|
|
205
|
+
),
|
|
206
|
+
skipped: to_references(child_numbers.slice(CHILD_LIMIT), repo),
|
|
207
|
+
unreachable_count: count_unreachable(reads),
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// The children that live in other repositories, read by naming that repository in the read's REST
|
|
212
|
+
// path (`repos/<owner>/<repo>/issues/<n>`). No local checkout is needed: their state is a GitHub
|
|
213
|
+
// fact, and requiring a clone to learn it is what kept the auto-close from ever running on such an
|
|
214
|
+
// epic (joshuafolkken/kit#864).
|
|
215
|
+
//
|
|
216
|
+
// A repository with a different owner is dropped before it is read, inheriting
|
|
217
|
+
// joshuafolkken/kit#869's restriction rather than restating it.
|
|
218
|
+
async function fetch_external_children(
|
|
219
|
+
external: ReadonlyArray<ExternalChild>,
|
|
220
|
+
current_owner: string,
|
|
221
|
+
): Promise<FetchedChildren> {
|
|
222
|
+
const allowed = external.filter((child) =>
|
|
223
|
+
epic_cross_repo.is_same_owner_repo(child.repo, current_owner),
|
|
224
|
+
)
|
|
225
|
+
const reads = await Promise.all(
|
|
226
|
+
allowed.map(async (child) => await fetch_child_read(child.number, child.repo, child.repo)),
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
// A repository the owner restriction refused is reported as unreadable rather than dropped: an
|
|
230
|
+
// epic must not read as complete while a child nobody may look at is still open.
|
|
231
|
+
const refused = external.filter(
|
|
232
|
+
(child) => !epic_cross_repo.is_same_owner_repo(child.repo, current_owner),
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
return {
|
|
236
|
+
children: to_children(reads),
|
|
237
|
+
unreadable: [...allowed.filter((_, index) => reads[index]?.child === undefined), ...refused],
|
|
238
|
+
skipped: [],
|
|
239
|
+
// A refusal is not a transport failure: the owner restriction answers the same tomorrow.
|
|
240
|
+
unreachable_count: count_unreachable(reads),
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
interface EpicSnapshot {
|
|
245
|
+
body: string | undefined
|
|
246
|
+
// The repository the *epic* lives in — what a bare number in its body and in a declared dependency
|
|
247
|
+
// names. Distinct from `current_repo` below, which is where the command is running
|
|
248
|
+
// (joshuafolkken/kit#1126).
|
|
249
|
+
repo: string
|
|
250
|
+
// The `owner/repo` the command is running in — the repository against which a reference is written
|
|
251
|
+
// bare, and every other one written `owner/repo#N`. Deliberately *not* where the epic lives:
|
|
252
|
+
// `epic:next owner/other#858` reads an epic elsewhere while the person reading the answer is
|
|
253
|
+
// standing here, so writing an unread child bare would send them to their own issue of that number
|
|
254
|
+
// (joshuafolkken/kit#1016).
|
|
255
|
+
current_repo: string
|
|
256
|
+
children: ReadonlyArray<EpicChild>
|
|
257
|
+
child_numbers: ReadonlyArray<number>
|
|
258
|
+
unreadable: ReadonlyArray<IssueReference>
|
|
259
|
+
skipped: ReadonlyArray<IssueReference>
|
|
260
|
+
has_external_children: boolean
|
|
261
|
+
// Why the epic's own body produced nothing, when it produced nothing (joshuafolkken/kit#1690).
|
|
262
|
+
body_failure: IssueReadFailure | undefined
|
|
263
|
+
// Whether **every** read behind this snapshot that failed — the body and each child — failed on
|
|
264
|
+
// the transport, and at least one did. What a caller does with it is its own: `epic:next` marks
|
|
265
|
+
// the anomaly with it, and `backlog:next` asks again instead of reporting the backlog empty.
|
|
266
|
+
//
|
|
267
|
+
// It is `every` rather than `any` so the answer terminates: one child refused for good beside one
|
|
268
|
+
// unreachable would otherwise be retried for ever, and the run would never reach the verdict that
|
|
269
|
+
// says a person is needed (joshuafolkken/kit#1690).
|
|
270
|
+
is_unreachable: boolean
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// The failed reads behind one snapshot, and how many of them are worth asking about again.
|
|
274
|
+
function to_failure_counts(
|
|
275
|
+
body_failure: IssueReadFailure | undefined,
|
|
276
|
+
groups: ReadonlyArray<FetchedChildren>,
|
|
277
|
+
): { failed: number; unreachable: number } {
|
|
278
|
+
const body_failed = body_failure === undefined ? 0 : 1
|
|
279
|
+
|
|
280
|
+
return {
|
|
281
|
+
failed: body_failed + groups.reduce((total, group) => total + group.unreadable.length, 0),
|
|
282
|
+
unreachable:
|
|
283
|
+
(is_body_unreachable(body_failure) ? 1 : 0) +
|
|
284
|
+
groups.reduce((total, group) => total + group.unreachable_count, 0),
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function is_snapshot_unreachable(
|
|
289
|
+
body_failure: IssueReadFailure | undefined,
|
|
290
|
+
groups: ReadonlyArray<FetchedChildren>,
|
|
291
|
+
): boolean {
|
|
292
|
+
const counts = to_failure_counts(body_failure, groups)
|
|
293
|
+
|
|
294
|
+
return counts.failed > 0 && counts.failed === counts.unreachable
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// The snapshot the two reads add up to, with the relations looked at a second time where a declared
|
|
298
|
+
// link says one is missing. Split from the reads above so `fetch_epic` stays a list of requests.
|
|
299
|
+
async function to_snapshot(
|
|
300
|
+
epic_body: EpicBody,
|
|
301
|
+
scope: { repo: string; current_repo: string },
|
|
302
|
+
local: FetchedChildren,
|
|
303
|
+
remote: FetchedChildren,
|
|
304
|
+
): Promise<EpicSnapshot> {
|
|
305
|
+
const { body, body_failure, child_numbers, external } = epic_body
|
|
306
|
+
const children = await rechecked_children([...local.children, ...remote.children], {
|
|
307
|
+
body,
|
|
308
|
+
...scope,
|
|
309
|
+
})
|
|
310
|
+
|
|
311
|
+
return {
|
|
312
|
+
body,
|
|
313
|
+
repo: scope.repo,
|
|
314
|
+
current_repo: scope.current_repo,
|
|
315
|
+
children,
|
|
316
|
+
child_numbers: [...child_numbers, ...external.map((child) => child.number)],
|
|
317
|
+
unreadable: [...local.unreadable, ...remote.unreadable],
|
|
318
|
+
skipped: local.skipped,
|
|
319
|
+
has_external_children: external.length > 0,
|
|
320
|
+
body_failure,
|
|
321
|
+
is_unreachable: is_snapshot_unreachable(body_failure, [local, remote]),
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// The epic and its children, as one read. `has_external_children` is surfaced rather than silently
|
|
326
|
+
// ignored: a cross-repository child needs joshuafolkken/kit#864, and an epic that holds one is not
|
|
327
|
+
// fully answered by this command yet.
|
|
328
|
+
//
|
|
329
|
+
// `repo` is where the *epic* lives and `current_repo` is where the command is running, so the body
|
|
330
|
+
// and its local rows are read through the same `scope_for` every other read goes through. Read
|
|
331
|
+
// unqualified, `epic:next joshuafolkken/app-kit#858` answered from *this* repository's issue 858 and
|
|
332
|
+
// then stamped the children it found there as app-kit's — and since joshuafolkken/kit#1016 makes
|
|
333
|
+
// `repo` decide how an unread child is written, that mislabelling reached the message too. The
|
|
334
|
+
// default keeps a command whose epic is always local reading exactly as before.
|
|
335
|
+
async function fetch_epic(
|
|
336
|
+
epic_number: number,
|
|
337
|
+
repo: string,
|
|
338
|
+
current_repo: string = repo,
|
|
339
|
+
): Promise<EpicSnapshot> {
|
|
340
|
+
const scope = scope_for(repo, current_repo)
|
|
341
|
+
const epic_body = await fetch_epic_body(epic_number, scope)
|
|
342
|
+
// joshuafolkken/kit#869's restriction is about who *we* are, so the owner comes from the repository
|
|
343
|
+
// the command runs in. Derived from the epic's own repository instead, a qualified reference to
|
|
344
|
+
// somebody else's epic would have made their whole organization readable.
|
|
345
|
+
const owner = epic_cross_repo.owner_of(current_repo)
|
|
346
|
+
const local = await fetch_children(epic_body.child_numbers, repo, scope)
|
|
347
|
+
const remote = await fetch_external_children(epic_body.external, owner)
|
|
348
|
+
|
|
349
|
+
return await to_snapshot(epic_body, { repo, current_repo }, local, remote)
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// Everything the fetch produced no child for: the reads that failed and the rows past the limit.
|
|
353
|
+
// Both leave the graph missing a node in the same way, and `epic:next` and `epic:audit` each report
|
|
354
|
+
// the pair together — one definition rather than the same concatenation written in both.
|
|
355
|
+
function missing_children(snapshot: EpicSnapshot): Array<IssueReference> {
|
|
356
|
+
return [...snapshot.unreadable, ...snapshot.skipped]
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
const epic_fetch = {
|
|
360
|
+
CHILD_LIMIT,
|
|
361
|
+
scope_for,
|
|
362
|
+
read_child_blockers,
|
|
363
|
+
missing_children,
|
|
364
|
+
fetch_child,
|
|
365
|
+
fetch_children,
|
|
366
|
+
fetch_epic,
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
export type { EpicSnapshot }
|
|
370
|
+
export { epic_fetch }
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import type { DependencyLink } from '#scripts/git/git-epic-parse'
|
|
2
|
+
import {
|
|
3
|
+
format_dependency_link,
|
|
4
|
+
join_references,
|
|
5
|
+
to_issue_reference,
|
|
6
|
+
type IssueReference,
|
|
7
|
+
} from '#scripts/git/git-epic-reference'
|
|
8
|
+
|
|
9
|
+
// The dependency graph an epic's children form, and the two ways it can be wrong.
|
|
10
|
+
//
|
|
11
|
+
// `epic:next` has to build this graph anyway to decide what is runnable, so the anomaly checks live
|
|
12
|
+
// here rather than in a separate auditor: a cycle makes every session wait forever, and a body that
|
|
13
|
+
// declares one order while the `blocked-by` relations record another means the implementation would
|
|
14
|
+
// proceed in an order nobody agreed to (joshuafolkken/kit#860).
|
|
15
|
+
|
|
16
|
+
// One child, as the graph sees it. `repo` is the `owner/repo` the child lives in, so a caller can
|
|
17
|
+
// bundle candidates per repository.
|
|
18
|
+
//
|
|
19
|
+
// `blocked_by` carries the native relations **with their repository**, not as bare numbers
|
|
20
|
+
// (joshuafolkken/kit#1126). A relation may cross a repository — REST records and returns one — and a
|
|
21
|
+
// number alone cannot say which repository it names, so a bare read resolved every blocker against
|
|
22
|
+
// the blocked child's own repository. A cross-repository blocker then keyed to an issue that does not
|
|
23
|
+
// exist, `blocker_categories` dropped it, and the child ran as though nothing blocked it. It also
|
|
24
|
+
// made `epic_cross_repo.resolve_cross_repo`'s cross-repository branch unreachable: every blocker
|
|
25
|
+
// arrived carrying the blocked child's repository, so `blocker.repo === blocked.repo` always held.
|
|
26
|
+
interface EpicChild {
|
|
27
|
+
number: number
|
|
28
|
+
repo: string
|
|
29
|
+
state: 'OPEN' | 'CLOSED'
|
|
30
|
+
labels: ReadonlyArray<string>
|
|
31
|
+
blocked_by: ReadonlyArray<IssueReference>
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// What is wrong with the graph. Both stop the run — neither is something to pick a winner for.
|
|
35
|
+
type GraphAnomalyKind =
|
|
36
|
+
'cycle' | 'declaration_mismatch' | 'unreadable_children' | 'unreadable_epic_body'
|
|
37
|
+
|
|
38
|
+
interface GraphAnomaly {
|
|
39
|
+
kind: GraphAnomalyKind
|
|
40
|
+
message: string
|
|
41
|
+
// Set when the reads behind this anomaly failed on the transport, so a caller can ask again
|
|
42
|
+
// instead of reporting an unusable graph. It travels from the failed request itself rather than
|
|
43
|
+
// from a probe fired afterwards, which is what let a connection that recovered in a few hundred
|
|
44
|
+
// milliseconds report the graph as permanently broken (joshuafolkken/kit#1690).
|
|
45
|
+
is_unreachable?: boolean
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// An issue's identity across the whole epic. Issue numbers are unique per repository, not globally:
|
|
49
|
+
// an epic tracking both `#7` and `app-kit#7` has two different children, and keying by number alone
|
|
50
|
+
// had them overwrite each other — and had one's blockers resolve against the other
|
|
51
|
+
// (joshuafolkken/kit#864). The audit keys the issues its children *cite* the same way, through this
|
|
52
|
+
// one function rather than a second spelling of it (joshuafolkken/kit#1014).
|
|
53
|
+
function reference_key(repo: string, issue_number: number): string {
|
|
54
|
+
return `${repo}${to_issue_reference(issue_number)}`
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// An `EpicChild` is an `IssueReference` with more on it, so children and citations key the same way.
|
|
58
|
+
function key_of(reference: IssueReference): string {
|
|
59
|
+
return reference_key(reference.repo, reference.number)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// How a reference is written in a message. Bare inside the repository the command runs in — the form
|
|
63
|
+
// every body writes and every existing message used — and `owner/repo#N` outside it, because a bare
|
|
64
|
+
// number resolves against the reader's own repository and names a different issue there
|
|
65
|
+
// (joshuafolkken/kit#864).
|
|
66
|
+
//
|
|
67
|
+
// It lives here rather than in the audit, beside the key it is the readable half of: `epic:next`
|
|
68
|
+
// reports the children it could not read too, and a second spelling there would print a bare `#7`
|
|
69
|
+
// for a child in another repository — the very misreading this exists to prevent
|
|
70
|
+
// (joshuafolkken/kit#1016).
|
|
71
|
+
function format_reference(reference: IssueReference, current_repo: string): string {
|
|
72
|
+
const is_local = reference.repo === '' || reference.repo === current_repo
|
|
73
|
+
|
|
74
|
+
return is_local ? to_issue_reference(reference.number) : key_of(reference)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function format_references(
|
|
78
|
+
references: ReadonlyArray<IssueReference>,
|
|
79
|
+
current_repo: string,
|
|
80
|
+
): string {
|
|
81
|
+
return join_references(references.map((reference) => format_reference(reference, current_repo)))
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// A blocker's key, read from the blocker's own repository rather than from the child it blocks
|
|
85
|
+
// (joshuafolkken/kit#1126). The child is no longer part of the answer: taking the repository from it
|
|
86
|
+
// is exactly what sent a cross-repository blocker to this repository's issue of that number.
|
|
87
|
+
function blocker_key(blocker: IssueReference): string {
|
|
88
|
+
return key_of(blocker)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// The children indexed by identity, for the lookups the walks below do repeatedly.
|
|
92
|
+
function index_children(children: ReadonlyArray<EpicChild>): Map<string, EpicChild> {
|
|
93
|
+
return new Map(children.map((child) => [key_of(child), child]))
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// A child's blockers that belong to this epic, as keys. A blocker outside the epic is somebody
|
|
97
|
+
// else's problem — the resolver decides whether it counts, and it can never be part of a cycle here.
|
|
98
|
+
function blockers_of(index: ReadonlyMap<string, EpicChild>, node: string): ReadonlyArray<string> {
|
|
99
|
+
const child = index.get(node)
|
|
100
|
+
if (child === undefined) return []
|
|
101
|
+
|
|
102
|
+
return child.blocked_by.map((blocker) => blocker_key(blocker))
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function has_remaining_blocker(
|
|
106
|
+
index: ReadonlyMap<string, EpicChild>,
|
|
107
|
+
node: string,
|
|
108
|
+
remaining: ReadonlySet<string>,
|
|
109
|
+
): boolean {
|
|
110
|
+
return blockers_of(index, node).some((blocker) => remaining.has(blocker))
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// The children that can never start, found by peeling: repeatedly drop every child whose blockers
|
|
114
|
+
// have all been dropped. What survives is in a cycle, or blocked by one — and both are the same
|
|
115
|
+
// problem for a caller, since neither will ever become runnable no matter how long it waits.
|
|
116
|
+
//
|
|
117
|
+
// Peeling rather than a depth-first search for a back edge: it is iterative, needs no node marking, and
|
|
118
|
+
// its answer is the more useful one. Purely structural, so a child's state and labels do not enter
|
|
119
|
+
// into it — a cycle is wrong whether or not anything in it has been closed.
|
|
120
|
+
function find_stuck_children(children: ReadonlyArray<EpicChild>): Array<string> {
|
|
121
|
+
const index = index_children(children)
|
|
122
|
+
const remaining = new Set(children.map((child) => key_of(child)))
|
|
123
|
+
|
|
124
|
+
const peel = (): number => {
|
|
125
|
+
const ready = [...remaining].filter((node) => !has_remaining_blocker(index, node, remaining))
|
|
126
|
+
|
|
127
|
+
for (const node of ready) remaining.delete(node)
|
|
128
|
+
|
|
129
|
+
return ready.length
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
while (peel() > 0) {
|
|
133
|
+
/* keep peeling until a pass drops nothing */
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return [...remaining].toSorted((left, right) => left.localeCompare(right))
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Whether a declared link is actually recorded as a native relation on the blocked child.
|
|
140
|
+
//
|
|
141
|
+
// Declared links are always written as bare numbers, which name issues in the epic's own repository —
|
|
142
|
+
// so the blocker they name is matched against that repository rather than against any relation that
|
|
143
|
+
// happens to carry the number (joshuafolkken/kit#1126).
|
|
144
|
+
function is_link_recorded(
|
|
145
|
+
link: DependencyLink,
|
|
146
|
+
children: ReadonlyArray<EpicChild>,
|
|
147
|
+
declared_repo: string,
|
|
148
|
+
): boolean {
|
|
149
|
+
const blocker = reference_key(declared_repo, link.blocker)
|
|
150
|
+
|
|
151
|
+
return children.some(
|
|
152
|
+
(child) =>
|
|
153
|
+
child.number === link.blocked &&
|
|
154
|
+
child.repo === declared_repo &&
|
|
155
|
+
child.blocked_by.some((recorded) => key_of(recorded) === blocker),
|
|
156
|
+
)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Declared links with no matching relation. Reported rather than applied: a body may legitimately be
|
|
160
|
+
// ahead of the relations — an epic written before `josh` recorded them, or one whose recording
|
|
161
|
+
// failed — and a run that silently followed the relations would ignore the order that was actually
|
|
162
|
+
// agreed.
|
|
163
|
+
function missing_relations(
|
|
164
|
+
links: ReadonlyArray<DependencyLink>,
|
|
165
|
+
children: ReadonlyArray<EpicChild>,
|
|
166
|
+
declared_repo: string,
|
|
167
|
+
): Array<DependencyLink> {
|
|
168
|
+
return links.filter((link) => !is_link_recorded(link, children, declared_repo))
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// The other half: declared links a relation actually backs. It is what a caller about to *drop*
|
|
172
|
+
// relations needs — asking `gh` to remove a link that was never recorded is reported as a failure
|
|
173
|
+
// nobody can act on. Written beside `missing_relations` rather than as a subtraction in each caller,
|
|
174
|
+
// so the two answers cannot come to disagree about what "recorded" means (joshuafolkken/kit#1712).
|
|
175
|
+
function recorded_relations(
|
|
176
|
+
links: ReadonlyArray<DependencyLink>,
|
|
177
|
+
children: ReadonlyArray<EpicChild>,
|
|
178
|
+
declared_repo: string,
|
|
179
|
+
): Array<DependencyLink> {
|
|
180
|
+
return links.filter((link) => is_link_recorded(link, children, declared_repo))
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Every relation recorded on one child, as links between children of this epic.
|
|
184
|
+
//
|
|
185
|
+
// Matched by identity rather than by number (joshuafolkken/kit#1126): keyed by number alone, a child
|
|
186
|
+
// in another repository whose number happened to equal a blocker's was reported as a relation nobody
|
|
187
|
+
// recorded. Only relations inside the declared repository become links, because a declared link is
|
|
188
|
+
// written as a bare number and has no way to name one that crosses a repository.
|
|
189
|
+
function child_links(
|
|
190
|
+
child: EpicChild,
|
|
191
|
+
keys: ReadonlySet<string>,
|
|
192
|
+
declared_repo: string,
|
|
193
|
+
): Array<DependencyLink> {
|
|
194
|
+
if (child.repo !== declared_repo) return []
|
|
195
|
+
|
|
196
|
+
return child.blocked_by
|
|
197
|
+
.filter((blocker) => blocker.repo === declared_repo && keys.has(key_of(blocker)))
|
|
198
|
+
.map((blocker) => ({ blocker: blocker.number, blocked: child.number }))
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Relations recorded between children that the body never declares. The other direction of the same
|
|
202
|
+
// disagreement: someone added `--add-blocked-by` by hand and the epic body still says otherwise.
|
|
203
|
+
function undeclared_relations(
|
|
204
|
+
links: ReadonlyArray<DependencyLink>,
|
|
205
|
+
children: ReadonlyArray<EpicChild>,
|
|
206
|
+
declared_repo: string,
|
|
207
|
+
): Array<DependencyLink> {
|
|
208
|
+
const declared = new Set(links.map((link) => format_dependency_link(link)))
|
|
209
|
+
const keys = new Set(children.map((child) => key_of(child)))
|
|
210
|
+
|
|
211
|
+
return children
|
|
212
|
+
.flatMap((child) => child_links(child, keys, declared_repo))
|
|
213
|
+
.filter((link) => !declared.has(format_dependency_link(link)))
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function cycle_anomaly(stuck: ReadonlyArray<string>): GraphAnomaly {
|
|
217
|
+
const list = stuck.join(', ')
|
|
218
|
+
|
|
219
|
+
return {
|
|
220
|
+
kind: 'cycle',
|
|
221
|
+
message: `Circular dependency: ${list} can never start — each is blocked, directly or through a chain, by something that is itself waiting on the group.`,
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function mismatch_anomaly(
|
|
226
|
+
missing: ReadonlyArray<DependencyLink>,
|
|
227
|
+
undeclared: ReadonlyArray<DependencyLink>,
|
|
228
|
+
): GraphAnomaly {
|
|
229
|
+
const lines = [
|
|
230
|
+
'The epic body and the blocked-by relations disagree.',
|
|
231
|
+
...missing.map((link) => ` declared but not recorded: ${format_dependency_link(link)}`),
|
|
232
|
+
...undeclared.map((link) => ` recorded but not declared: ${format_dependency_link(link)}`),
|
|
233
|
+
'Fix one of them; the run will not choose for you.',
|
|
234
|
+
]
|
|
235
|
+
|
|
236
|
+
return { kind: 'declaration_mismatch', message: lines.join('\n') }
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Everything wrong with the graph, in the order a caller should act on it: a cycle first, because a
|
|
240
|
+
// mismatch inside a cyclic graph is noise until the cycle is gone.
|
|
241
|
+
//
|
|
242
|
+
// `is_declared` says whether the body states an order at all — a chain, or the explicit sentence
|
|
243
|
+
// declaring the children independent. Without one there is nothing for the relations to disagree
|
|
244
|
+
// with, and reporting a mismatch against a body that never spoke would fail every epic whose
|
|
245
|
+
// declaration could not be read.
|
|
246
|
+
function find_anomalies(
|
|
247
|
+
children: ReadonlyArray<EpicChild>,
|
|
248
|
+
links: ReadonlyArray<DependencyLink>,
|
|
249
|
+
is_declared: boolean,
|
|
250
|
+
declared_repo: string,
|
|
251
|
+
): Array<GraphAnomaly> {
|
|
252
|
+
const stuck = find_stuck_children(children)
|
|
253
|
+
if (stuck.length > 0) return [cycle_anomaly(stuck)]
|
|
254
|
+
if (!is_declared) return []
|
|
255
|
+
const missing = missing_relations(links, children, declared_repo)
|
|
256
|
+
const undeclared = undeclared_relations(links, children, declared_repo)
|
|
257
|
+
if (missing.length === 0 && undeclared.length === 0) return []
|
|
258
|
+
|
|
259
|
+
return [mismatch_anomaly(missing, undeclared)]
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
const epic_graph = {
|
|
263
|
+
reference_key,
|
|
264
|
+
key_of,
|
|
265
|
+
format_reference,
|
|
266
|
+
format_references,
|
|
267
|
+
blocker_key,
|
|
268
|
+
index_children,
|
|
269
|
+
blockers_of,
|
|
270
|
+
find_stuck_children,
|
|
271
|
+
missing_relations,
|
|
272
|
+
recorded_relations,
|
|
273
|
+
undeclared_relations,
|
|
274
|
+
find_anomalies,
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
export type { EpicChild, GraphAnomaly, GraphAnomalyKind }
|
|
278
|
+
export type { IssueReference } from '#scripts/git/git-epic-reference'
|
|
279
|
+
export { epic_graph }
|