@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,199 @@
|
|
|
1
|
+
import { git_epic_parse, type ExternalChild } from './git-epic-parse'
|
|
2
|
+
import { git_gh_command } from './git-gh-command'
|
|
3
|
+
import { read_json_listing } from './parse-json-array'
|
|
4
|
+
import { rest_comment_schema, type RestCommentData } from './schemas'
|
|
5
|
+
|
|
6
|
+
// The comment the epic auto-close announces itself with, and how a run recognizes the one a previous
|
|
7
|
+
// run already posted.
|
|
8
|
+
//
|
|
9
|
+
// Kept apart from `git-epic-close.ts` because the two answer different questions — that file decides
|
|
10
|
+
// *whether* an epic may close, this one decides what the announcement says and whether it is already
|
|
11
|
+
// there — and because the file it was split from is within twenty lines of the three hundred a file
|
|
12
|
+
// may hold (joshuafolkken/kit#1039).
|
|
13
|
+
|
|
14
|
+
// The epic's children, near and far. Named structurally rather than by importing `EpicIssue`: the
|
|
15
|
+
// dependency runs one way, from the auto-close to here, and a type import back would put a cycle
|
|
16
|
+
// between two files that have no reason to know each other's shapes.
|
|
17
|
+
interface EpicChildren {
|
|
18
|
+
children: ReadonlyArray<number>
|
|
19
|
+
external_children: ReadonlyArray<ExternalChild>
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// The fixed sentence the announcement's prose ends with. It is what a person reads, and it is no
|
|
23
|
+
// longer what the retry check matches on (joshuafolkken/kit#1068): people and agents quote the
|
|
24
|
+
// auto-close output in ordinary issue comments, and matching prose made any such quote answer
|
|
25
|
+
// "already announced" — the epic then closed with no comment, losing the record of which children it
|
|
26
|
+
// closed against.
|
|
27
|
+
const CLOSE_ANNOUNCEMENT = 'Closing this epic automatically.'
|
|
28
|
+
|
|
29
|
+
// The marker, which GitHub renders as nothing at all. Quoting the sentence above therefore no longer
|
|
30
|
+
// suppresses anything: what is quoted is the rendered text, and the marker is not in it.
|
|
31
|
+
//
|
|
32
|
+
// **It carries the child set the announcement named.** That is what makes an epic which was
|
|
33
|
+
// reopened, gained a child and completed again announce a *second* time instead of closing silently
|
|
34
|
+
// against a stale list. joshuafolkken/kit#1039 rejected matching the whole composed body for a
|
|
35
|
+
// neighboring reason — the visible child list varies, so an unchanged epic would have been read as
|
|
36
|
+
// "not posted yet" whenever the wording drifted — and the marker keeps that failure out by being
|
|
37
|
+
// built from the child set alone: the prose can be rephrased without moving it, and the set is
|
|
38
|
+
// compared as a set, so reordering the epic's task list does not move it either.
|
|
39
|
+
const MARKER_OPEN = '<!-- josh:epic-auto-close children='
|
|
40
|
+
const MARKER_CLOSE = ' -->'
|
|
41
|
+
|
|
42
|
+
// Every child, near and far. Listing only the local ones left an all-external epic announcing "All
|
|
43
|
+
// child issues are closed ()" (joshuafolkken/kit#864).
|
|
44
|
+
function child_references(epic: EpicChildren): Array<string> {
|
|
45
|
+
return [
|
|
46
|
+
...epic.children.map((child) => `#${String(child)}`),
|
|
47
|
+
...epic.external_children.map((child) => `${child.repo}#${String(child.number)}`),
|
|
48
|
+
]
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function build_marker(epic: EpicChildren): string {
|
|
52
|
+
return `${MARKER_OPEN}${child_references(epic).join(',')}${MARKER_CLOSE}`
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Four spaces open a markdown code block, so a line indented that far is quoted text rather than
|
|
56
|
+
// the announcement's own marker — and the announcement never indents its marker at all.
|
|
57
|
+
const INDENTED_CODE_SPACES = 4
|
|
58
|
+
|
|
59
|
+
function indent_of(line: string): number {
|
|
60
|
+
return line.length - line.trimStart().length
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// The child set a marker line records, or `undefined` for any other line. The empty filter is what
|
|
64
|
+
// keeps an epic tracking nothing from reading as tracking one nameless child.
|
|
65
|
+
function marker_children(line: string): Array<string> | undefined {
|
|
66
|
+
if (indent_of(line) >= INDENTED_CODE_SPACES) return undefined
|
|
67
|
+
|
|
68
|
+
const trimmed = line.trim()
|
|
69
|
+
if (!trimmed.startsWith(MARKER_OPEN)) return undefined
|
|
70
|
+
if (!trimmed.endsWith(MARKER_CLOSE)) return undefined
|
|
71
|
+
|
|
72
|
+
const listed = trimmed.slice(MARKER_OPEN.length, -MARKER_CLOSE.length)
|
|
73
|
+
|
|
74
|
+
return listed.split(',').filter((reference) => reference.length > 0)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Compared as sets rather than as strings: the marker is written in whatever order the epic happens
|
|
78
|
+
// to list its children, and reordering a task list changes neither the batch nor what was announced
|
|
79
|
+
// about it. Comparing the rendered strings would have needed a canonical order, and every ordering
|
|
80
|
+
// available for `owner/repo#N` text is either locale-dependent or a lint exception — a set says what
|
|
81
|
+
// is actually meant and is the same answer on every machine.
|
|
82
|
+
function is_same_children(left: ReadonlyArray<string>, right: ReadonlyArray<string>): boolean {
|
|
83
|
+
const left_set = new Set(left)
|
|
84
|
+
const right_set = new Set(right)
|
|
85
|
+
|
|
86
|
+
return left_set.size === right_set.size && [...left_set].every((one) => right_set.has(one))
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// The prose the reader sees, then the marker the next run matches on.
|
|
90
|
+
function build_close_comment(epic: EpicChildren): string {
|
|
91
|
+
return `All child issues are closed (${child_references(epic).join(', ')}). ${CLOSE_ANNOUNCEMENT}\n\n${build_marker(epic)}`
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// MIGRATION ONLY (joshuafolkken/kit#1068) — remove together with `is_legacy_announcement`.
|
|
95
|
+
//
|
|
96
|
+
// Announcements posted by v1.179.0 through the release before this one carry no marker, so an epic
|
|
97
|
+
// sitting in the half-succeeded state right now would be read as "not announced" and receive the
|
|
98
|
+
// second comment joshuafolkken/kit#1039 removed. This matches those.
|
|
99
|
+
//
|
|
100
|
+
// **The wording here is a frozen copy of what was released, not a second spelling of the constants
|
|
101
|
+
// above.** Deriving it from them would make a future rephrasing of the announcement silently stop
|
|
102
|
+
// matching comments already on GitHub, which no edit can change.
|
|
103
|
+
//
|
|
104
|
+
// It matches only a comment whose **entire** body is the old announcement — which is what the
|
|
105
|
+
// auto-close posted, and what a quote never is: a quote sits inside prose, or behind `> `, or in a
|
|
106
|
+
// fence, and none of those trim down to this.
|
|
107
|
+
//
|
|
108
|
+
// **When it can be removed:** once no *open* epic can still carry a marker-less announcement. Closed
|
|
109
|
+
// epics do not matter — the auto-close reads its candidates from a `state=open` listing, so they are
|
|
110
|
+
// never considered. Establish it by listing the open epics and looking for one whose comments hold a
|
|
111
|
+
// body matching this pattern:
|
|
112
|
+
//
|
|
113
|
+
// gh issue list --label epic --state open --json number --jq '.[].number' |
|
|
114
|
+
// while read -r n; do
|
|
115
|
+
// gh api "repos/{owner}/{repo}/issues/$n/comments" --paginate --jq '.[].body' |
|
|
116
|
+
// grep -c '^All child issues are closed (.*)\. Closing this epic automatically\.$'
|
|
117
|
+
// done
|
|
118
|
+
//
|
|
119
|
+
// A total of zero means every remaining announcement carries the marker; delete this constant,
|
|
120
|
+
// `is_legacy_announcement`, and the tests naming them.
|
|
121
|
+
const LEGACY_ANNOUNCEMENT_PATTERN =
|
|
122
|
+
/^All child issues are closed \([^)]*\)\. Closing this epic automatically\.$/u
|
|
123
|
+
|
|
124
|
+
function is_legacy_announcement(body: string): boolean {
|
|
125
|
+
return LEGACY_ANNOUNCEMENT_PATTERN.test(body.trim())
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Whether the epic already carries the announcement.
|
|
129
|
+
//
|
|
130
|
+
// `unreadable` is deliberately not folded into `absent`, though the caller acts the same way on
|
|
131
|
+
// both: a listing that could not be read says nothing about what is on the issue, and reporting it
|
|
132
|
+
// as "nothing is there" would have the run state a fact it never established — the misread
|
|
133
|
+
// joshuafolkken/kit#973 and joshuafolkken/kit#959 were each about. Keeping it apart is what lets
|
|
134
|
+
// `git-epic-close.ts` say out loud that the duplicate check did not run, which is the whole
|
|
135
|
+
// difference between the two answers there.
|
|
136
|
+
//
|
|
137
|
+
// **Both of `read_json_listing`'s gaps arrive as `unreadable`**, rows the schema rejects included.
|
|
138
|
+
// `parse_json_array_or_undefined` rethrows that one, which is right where a shape change should stay
|
|
139
|
+
// visible — and wrong here: this answer decides whether a *write* posts, so an exception in place of
|
|
140
|
+
// the safe answer is the one outcome the function must not produce.
|
|
141
|
+
type CloseCommentState = 'present' | 'absent' | 'unreadable'
|
|
142
|
+
|
|
143
|
+
// The marker has to be a line of its own, outside any fence — not merely present in the body. A
|
|
144
|
+
// quote is exactly what must not suppress the next announcement, and the two ways of quoting an
|
|
145
|
+
// announcement carry the raw marker along with everything else: GitHub's "Quote reply" puts every
|
|
146
|
+
// line behind `> `, which the line comparison rejects, and a code block reproduces the marker line
|
|
147
|
+
// verbatim — a fenced one caught by the mask, an indented one by the indent check. `fence_mask` is the same walk every other body predicate
|
|
148
|
+
// in this codebase reads through, rather than a second one written here (joshuafolkken/kit#890).
|
|
149
|
+
function has_marker(body: string, children: ReadonlyArray<string>): boolean {
|
|
150
|
+
const mask = git_epic_parse.fence_mask(body)
|
|
151
|
+
|
|
152
|
+
return body.split('\n').some((line, index) => {
|
|
153
|
+
if (mask[index] !== true) return false
|
|
154
|
+
|
|
155
|
+
const announced = marker_children(line)
|
|
156
|
+
|
|
157
|
+
return announced !== undefined && is_same_children(announced, children)
|
|
158
|
+
})
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function has_announcement(
|
|
162
|
+
comments: ReadonlyArray<RestCommentData>,
|
|
163
|
+
children: ReadonlyArray<string>,
|
|
164
|
+
): boolean {
|
|
165
|
+
return comments.some((comment) => {
|
|
166
|
+
const body = comment.body ?? ''
|
|
167
|
+
|
|
168
|
+
return has_marker(body, children) || is_legacy_announcement(body)
|
|
169
|
+
})
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// One request, and it is spent only on a run that is about to close an epic: the caller reaches this
|
|
173
|
+
// after every child has been read and found closed, which happens once in an epic's life. Every
|
|
174
|
+
// other `josh followup` run leaves the epic short of complete and never gets here, so the ordinary
|
|
175
|
+
// path costs nothing.
|
|
176
|
+
//
|
|
177
|
+
// An epic that has already **closed** is a different situation and never arrives here at all: the
|
|
178
|
+
// auto-close reads its candidates from an `state=open` listing (`git-gh-issue-list.ts`), so a closed
|
|
179
|
+
// epic is not among them and no comment of any kind is considered for it.
|
|
180
|
+
async function read_close_comment_state(
|
|
181
|
+
epic_number: string,
|
|
182
|
+
epic: EpicChildren,
|
|
183
|
+
): Promise<CloseCommentState> {
|
|
184
|
+
const raw_json = await git_gh_command.issue_list_comments(epic_number)
|
|
185
|
+
if (raw_json === undefined) return 'unreadable'
|
|
186
|
+
|
|
187
|
+
const listing = read_json_listing(raw_json, rest_comment_schema)
|
|
188
|
+
if (listing.kind !== 'read') return 'unreadable'
|
|
189
|
+
|
|
190
|
+
return has_announcement(listing.rows, child_references(epic)) ? 'present' : 'absent'
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const git_epic_close_comment = {
|
|
194
|
+
build_close_comment,
|
|
195
|
+
read_close_comment_state,
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export type { CloseCommentState, EpicChildren }
|
|
199
|
+
export { git_epic_close_comment, CLOSE_ANNOUNCEMENT }
|
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
import { git_epic_close_comment } from './git-epic-close-comment'
|
|
2
|
+
import { git_epic_parse, type ExternalChild } from './git-epic-parse'
|
|
3
|
+
import { git_gh_command } from './git-gh-command'
|
|
4
|
+
import { EPIC_LABEL } from './issue-labels'
|
|
5
|
+
import { cutoff_cause, cutoff_of, type ScanCutoff } from './listing-cutoff'
|
|
6
|
+
import { parse_json_array_or_undefined, parse_json_object_safe } from './parse-json-array'
|
|
7
|
+
import { epic_child_schema, epic_issue_schema, type EpicChildData } from './schemas'
|
|
8
|
+
|
|
9
|
+
// How many open epics the auto-close will look at. `git-gh-issue-list.ts` pages until `limit` rows
|
|
10
|
+
// have been selected or the backlog runs out, so this is what keeps the ordinary case at exactly one
|
|
11
|
+
// request — 100 is `PER_PAGE`. Since joshuafolkken/kit#1067 the paging's own page ceiling bounds
|
|
12
|
+
// this listing too, but as a backstop rather than as this number's replacement: it stops the request
|
|
13
|
+
// count, not the row count.
|
|
14
|
+
//
|
|
15
|
+
// The listing is newest-first and the surplus is cut off the tail, so a repository holding more open
|
|
16
|
+
// epics than this loses the oldest. It no longer loses them silently: since joshuafolkken/kit#1067
|
|
17
|
+
// both cutoffs are reported, because an epic past the cut is never checked for completion and stays
|
|
18
|
+
// open with nothing saying why — the same silence this file's `undefined`-not-`[]` handling exists
|
|
19
|
+
// to remove. The value still sits well above the number of epics ever open at once, so the report is
|
|
20
|
+
// the exception rather than a line on every merge.
|
|
21
|
+
const EPIC_LIST_LIMIT = 100
|
|
22
|
+
|
|
23
|
+
// Printed rather than thrown: this runs after the PR has already merged, so nothing here may fail
|
|
24
|
+
// the run. `console.info` is what every other note in this file uses, for that same reason.
|
|
25
|
+
function truncated_epic_list_note(cutoff: ScanCutoff): string | undefined {
|
|
26
|
+
const cause = cutoff_cause(cutoff, `hit its ${String(EPIC_LIST_LIMIT)}-epic cap`)
|
|
27
|
+
if (cause === undefined) return undefined
|
|
28
|
+
|
|
29
|
+
return `⚠️ The open epic listing ${cause}; an epic past it was not checked for completion.`
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
interface EpicIssue {
|
|
33
|
+
number: number
|
|
34
|
+
children: Array<number>
|
|
35
|
+
external_children: Array<ExternalChild>
|
|
36
|
+
has_declared_order: boolean
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
interface SiblingState {
|
|
40
|
+
is_closed: boolean
|
|
41
|
+
has_blocked_by: boolean
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function to_epic_issue(raw: { number: number; body?: string | undefined }): EpicIssue {
|
|
45
|
+
return {
|
|
46
|
+
number: raw.number,
|
|
47
|
+
children: git_epic_parse.parse_task_list_issue_numbers(raw.body),
|
|
48
|
+
external_children: git_epic_parse.parse_external_task_list_children(raw.body),
|
|
49
|
+
has_declared_order: git_epic_parse.has_declared_dependency_chain(raw.body),
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// `undefined` when the listing could not be read at all — the request failed, or the answer was not
|
|
54
|
+
// a JSON array. Not `[]`, which is a real answer meaning no epic is open.
|
|
55
|
+
//
|
|
56
|
+
// `parse_json_array_safe` returns `[]` for both, and the auto-close then decides there is no epic to
|
|
57
|
+
// close: it stops for a reason that never reaches a log, and the epic stays open with nothing saying
|
|
58
|
+
// why. The failure leans safe — the other direction, taken by `epic:bundle`, invented a second epic
|
|
59
|
+
// (joshuafolkken/kit#950) — but silence is the same defect, so the two are told apart here as well
|
|
60
|
+
// (joshuafolkken/kit#959).
|
|
61
|
+
//
|
|
62
|
+
// The two ways of failing are folded into one answer deliberately. Which one occurred does not
|
|
63
|
+
// change what the auto-close may do — in neither case does it know what the open epics are — and
|
|
64
|
+
// splitting them would put two warnings on one decision.
|
|
65
|
+
async function fetch_open_epics(): Promise<Array<EpicIssue> | undefined> {
|
|
66
|
+
const { json, is_capped } = await git_gh_command.issue_list_by_label(EPIC_LABEL, EPIC_LIST_LIMIT)
|
|
67
|
+
if (json === undefined) return undefined
|
|
68
|
+
|
|
69
|
+
const rows = parse_json_array_or_undefined(json, epic_issue_schema)
|
|
70
|
+
if (rows === undefined) return undefined
|
|
71
|
+
const note = truncated_epic_list_note(cutoff_of(rows.length, EPIC_LIST_LIMIT, is_capped))
|
|
72
|
+
|
|
73
|
+
if (note !== undefined) console.info(note)
|
|
74
|
+
|
|
75
|
+
return rows.map((raw) => to_epic_issue(raw))
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function parse_child(raw_json: string | undefined): EpicChildData | undefined {
|
|
79
|
+
if (raw_json === undefined) return undefined
|
|
80
|
+
|
|
81
|
+
return parse_json_object_safe(raw_json, epic_child_schema)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function has_blocked_by(child: EpicChildData | undefined): boolean {
|
|
85
|
+
const blocked_by = child?.blockedBy
|
|
86
|
+
|
|
87
|
+
return (blocked_by?.totalCount ?? 0) > 0
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function to_sibling_state(raw_json: string | undefined): SiblingState {
|
|
91
|
+
const child = parse_child(raw_json)
|
|
92
|
+
|
|
93
|
+
return {
|
|
94
|
+
is_closed: git_epic_parse.is_state_closed(child?.state),
|
|
95
|
+
has_blocked_by: has_blocked_by(child),
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async function inspect_sibling(sibling: number, repo?: string): Promise<SiblingState> {
|
|
100
|
+
return to_sibling_state(await git_gh_command.issue_get_state_and_relations(String(sibling), repo))
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// A cross-repository child, read by naming its repository in the read's REST path. `is_readable`
|
|
104
|
+
// is what decides whether the epic may close at all: closing while a child's state is unknown is
|
|
105
|
+
// exactly what the old refusal prevented, and reading them is the only thing that changed
|
|
106
|
+
// (joshuafolkken/kit#864).
|
|
107
|
+
async function inspect_external(
|
|
108
|
+
child: ExternalChild,
|
|
109
|
+
): Promise<SiblingState & { is_readable: boolean }> {
|
|
110
|
+
const raw = await git_gh_command.issue_get_state_and_relations(String(child.number), child.repo)
|
|
111
|
+
|
|
112
|
+
return { ...to_sibling_state(raw), is_readable: raw !== undefined }
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// The merged Issue is excluded rather than queried: GitHub applies `closes #N` asynchronously, so
|
|
116
|
+
// reading its state immediately after the merge races with that propagation.
|
|
117
|
+
async function inspect_siblings(
|
|
118
|
+
epic: EpicIssue,
|
|
119
|
+
merged_number: number,
|
|
120
|
+
): Promise<Array<SiblingState>> {
|
|
121
|
+
const siblings = epic.children.filter((child) => child !== merged_number)
|
|
122
|
+
|
|
123
|
+
return await Promise.all(siblings.map(async (sibling) => await inspect_sibling(sibling)))
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// `pnpm josh epic --ordered` and `--add` record the declared chain themselves, through the REST
|
|
127
|
+
// dependencies endpoint (`git-epic-relations.ts`, joshuafolkken/kit#1026), so the default route
|
|
128
|
+
// arrives here with the relations already in place. Three routes still reach a declared order with
|
|
129
|
+
// none recorded: an epic body written by hand, the manual fallback in `issue-template.md`, and
|
|
130
|
+
// `apply_relations` failing — it counts the refusals, reports that the body is intact and lets the
|
|
131
|
+
// batch finish. Each is otherwise symptomless, which is what this warning is for. The epic body's
|
|
132
|
+
// declared chain is the trigger: since #713 every split gets an epic, so its existence no longer
|
|
133
|
+
// implies an order, and warning on that alone would fire on every unordered batch. Only a total
|
|
134
|
+
// absence of relations is reported — checking each dependent pair would mean inferring the chain
|
|
135
|
+
// from task-list order, which need not match.
|
|
136
|
+
function warn_when_order_unrecorded(epic: EpicIssue, states: ReadonlyArray<SiblingState>): void {
|
|
137
|
+
if (
|
|
138
|
+
states.length === 0 ||
|
|
139
|
+
!epic.has_declared_order ||
|
|
140
|
+
states.some((state) => state.has_blocked_by)
|
|
141
|
+
) {
|
|
142
|
+
return
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
console.info(
|
|
146
|
+
`ℹ️ Epic #${String(epic.number)} has no blocked-by relation on any child; ` +
|
|
147
|
+
'the batch order was never recorded natively (see the epic creation procedure).',
|
|
148
|
+
)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// The one thing the two refusals below ask for, written once — a child state that could not be read,
|
|
152
|
+
// and a close the API refused (joshuafolkken/kit#1039).
|
|
153
|
+
const CLOSE_MANUALLY = 'close it manually.'
|
|
154
|
+
|
|
155
|
+
// The nesting cascade's safety valve. A closed child epic is itself a completed child, so the same
|
|
156
|
+
// completion check is re-run for the epics that list *it*, closing a nested parent in the same pass
|
|
157
|
+
// (joshuafolkken/kit#2008). `evaluated` already terminates a cycle or a shared child; this is the
|
|
158
|
+
// backstop for a nesting so deep it is likelier a mistake than a plan. On reaching it the cascade
|
|
159
|
+
// stops and asks for a manual close, exactly as an unreadable or refused child close does.
|
|
160
|
+
const MAX_CASCADE_DEPTH = 10
|
|
161
|
+
|
|
162
|
+
const CASCADE_DEPTH_NOTE = `⚠️ Epic auto-close cascade reached its ${String(
|
|
163
|
+
MAX_CASCADE_DEPTH,
|
|
164
|
+
)}-level cap; ${CLOSE_MANUALLY}`
|
|
165
|
+
|
|
166
|
+
// **An unreadable comment listing does not stop the close.** It is announced and closed exactly as
|
|
167
|
+
// it was before the duplicate check existed, because refusing here would strand the epic: nothing
|
|
168
|
+
// re-triggers the auto-close once every child is closed — `resolve_and_close` only evaluates epics
|
|
169
|
+
// holding the issue that just merged, and that merge has already happened. One rate-limited read
|
|
170
|
+
// would leave a finished epic open until somebody noticed.
|
|
171
|
+
//
|
|
172
|
+
// The direction is chosen on what each mistake costs, and they are not symmetric. Announcing twice
|
|
173
|
+
// costs one redundant comment and nothing else, because the epic *closes* — which is what ends the
|
|
174
|
+
// loop joshuafolkken/kit#1039 is about, where the comment repeated once per attempt for as long as
|
|
175
|
+
// the close kept failing. Refusing costs a manual close on every transient failure.
|
|
176
|
+
const UNREADABLE_COMMENTS_NOTE =
|
|
177
|
+
"'s comments could not be read; announcing again rather than leaving it open."
|
|
178
|
+
|
|
179
|
+
// The write, once the announcement has been decided. `comment` is `undefined` when the epic already
|
|
180
|
+
// carries one — which is what stops a run whose comment landed and whose close was refused from
|
|
181
|
+
// posting the same comment again on the next attempt, and again for as long as the close keeps
|
|
182
|
+
// failing (joshuafolkken/kit#1039).
|
|
183
|
+
//
|
|
184
|
+
// The comment-first ordering inside `issue_close` is what produces that half-succeeded state, and it
|
|
185
|
+
// is left exactly as it is: it is what keeps a `false` meaning "the epic is still open" in every
|
|
186
|
+
// branch, which is the answer the second message here is written against (joshuafolkken/kit#1026).
|
|
187
|
+
async function close_epic_with(epic_number: string, comment: string | undefined): Promise<boolean> {
|
|
188
|
+
const is_closed = await git_gh_command.issue_close(epic_number, comment)
|
|
189
|
+
|
|
190
|
+
console.info(
|
|
191
|
+
is_closed
|
|
192
|
+
? `🏁 Closed epic #${epic_number} — every child issue is complete.`
|
|
193
|
+
: `⚠️ Could not close epic #${epic_number}; ${CLOSE_MANUALLY}`,
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
return is_closed
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// The comment listing is read **once**: only `present` skips the announcement, so an answer of
|
|
200
|
+
// `absent` and one of `unreadable` both post it, and the second says so.
|
|
201
|
+
async function close_epic(epic: EpicIssue): Promise<boolean> {
|
|
202
|
+
const epic_number = String(epic.number)
|
|
203
|
+
const state = await git_epic_close_comment.read_close_comment_state(epic_number, epic)
|
|
204
|
+
|
|
205
|
+
if (state === 'unreadable') console.info(`ℹ️ Epic #${epic_number}${UNREADABLE_COMMENTS_NOTE}`)
|
|
206
|
+
|
|
207
|
+
const comment = state === 'present' ? undefined : git_epic_close_comment.build_close_comment(epic)
|
|
208
|
+
|
|
209
|
+
return await close_epic_with(epic_number, comment)
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// The cross-repository children's states, and whether every one of them could be read. An epic with
|
|
213
|
+
// a child whose state is unknown keeps the old handling — left open for manual closing.
|
|
214
|
+
async function inspect_external_children(
|
|
215
|
+
epic: EpicIssue,
|
|
216
|
+
): Promise<{ states: Array<SiblingState>; is_complete: boolean }> {
|
|
217
|
+
if (epic.external_children.length === 0) return { states: [], is_complete: true }
|
|
218
|
+
const results = await Promise.all(
|
|
219
|
+
epic.external_children.map(async (child) => await inspect_external(child)),
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
return {
|
|
223
|
+
states: results.map((result) => ({
|
|
224
|
+
is_closed: result.is_closed,
|
|
225
|
+
has_blocked_by: result.has_blocked_by,
|
|
226
|
+
})),
|
|
227
|
+
is_complete: results.every((result) => result.is_readable),
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
async function close_epic_when_complete(epic: EpicIssue, merged_number: number): Promise<boolean> {
|
|
232
|
+
const external = await inspect_external_children(epic)
|
|
233
|
+
|
|
234
|
+
if (!external.is_complete) {
|
|
235
|
+
console.info(
|
|
236
|
+
`ℹ️ Epic #${String(epic.number)} has a child in another repository whose state could not be read; ${CLOSE_MANUALLY}`,
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
return false
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const states = [...(await inspect_siblings(epic, merged_number)), ...external.states]
|
|
243
|
+
|
|
244
|
+
warn_when_order_unrecorded(epic, states)
|
|
245
|
+
|
|
246
|
+
if (states.some((state) => !state.is_closed)) return false
|
|
247
|
+
|
|
248
|
+
return await close_epic(epic)
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// Each epic is isolated: one that cannot be read or closed must not stop the others from being
|
|
252
|
+
// evaluated, since they are independent batches that merely share this child. `false` — the epic did
|
|
253
|
+
// not close, whether because a sibling is still open, a read failed or the close was refused — is
|
|
254
|
+
// what stops the cascade from walking past it to a parent (joshuafolkken/kit#2008).
|
|
255
|
+
async function close_epic_isolated(epic: EpicIssue, merged_number: number): Promise<boolean> {
|
|
256
|
+
try {
|
|
257
|
+
return await close_epic_when_complete(epic, merged_number)
|
|
258
|
+
} catch (error) {
|
|
259
|
+
const message = error instanceof Error ? error.message : String(error)
|
|
260
|
+
|
|
261
|
+
console.info(`⚠️ Skipped epic #${String(epic.number)}: ${message}`)
|
|
262
|
+
|
|
263
|
+
return false
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
function parents_of(open_epics: ReadonlyArray<EpicIssue>, child_number: number): Array<EpicIssue> {
|
|
268
|
+
return open_epics.filter((epic) => git_epic_parse.has_child(epic.children, child_number))
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Closes one epic unless a cycle or a shared child already reached it — the closed number, or
|
|
272
|
+
// `undefined`. `evaluated` is marked before the close, so a refused close is not retried by a later
|
|
273
|
+
// path either.
|
|
274
|
+
async function close_if_unseen(
|
|
275
|
+
epic: EpicIssue,
|
|
276
|
+
child_number: number,
|
|
277
|
+
evaluated: Set<number>,
|
|
278
|
+
): Promise<number | undefined> {
|
|
279
|
+
if (evaluated.has(epic.number)) return undefined
|
|
280
|
+
evaluated.add(epic.number)
|
|
281
|
+
|
|
282
|
+
return (await close_epic_isolated(epic, child_number)) ? epic.number : undefined
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// The epics that list `child_number` and close because of it. The numbers returned are the next
|
|
286
|
+
// cascade frontier: each is a closed epic, itself a completed child of whatever lists it.
|
|
287
|
+
async function close_parents_of(
|
|
288
|
+
open_epics: ReadonlyArray<EpicIssue>,
|
|
289
|
+
child_number: number,
|
|
290
|
+
evaluated: Set<number>,
|
|
291
|
+
): Promise<Array<number>> {
|
|
292
|
+
const closed: Array<number> = []
|
|
293
|
+
|
|
294
|
+
for (const epic of parents_of(open_epics, child_number)) {
|
|
295
|
+
const number = await close_if_unseen(epic, child_number, evaluated)
|
|
296
|
+
if (number !== undefined) closed.push(number)
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
return closed
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
async function close_next_level(
|
|
303
|
+
open_epics: ReadonlyArray<EpicIssue>,
|
|
304
|
+
frontier: ReadonlyArray<number>,
|
|
305
|
+
evaluated: Set<number>,
|
|
306
|
+
): Promise<Array<number>> {
|
|
307
|
+
const next: Array<number> = []
|
|
308
|
+
|
|
309
|
+
for (const child_number of frontier) {
|
|
310
|
+
next.push(...(await close_parents_of(open_epics, child_number, evaluated)))
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
return next
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// Breadth-first up the nesting: level 0 closes the epics holding the merged issue, and each closed
|
|
317
|
+
// epic becomes the next level's completed child, so a fully-finished parent closes in the same pass.
|
|
318
|
+
async function cascade_close(
|
|
319
|
+
open_epics: ReadonlyArray<EpicIssue>,
|
|
320
|
+
merged_number: number,
|
|
321
|
+
): Promise<void> {
|
|
322
|
+
const evaluated = new Set<number>()
|
|
323
|
+
let frontier: ReadonlyArray<number> = [merged_number]
|
|
324
|
+
|
|
325
|
+
for (let depth = 0; depth < MAX_CASCADE_DEPTH; depth++) {
|
|
326
|
+
if (frontier.length === 0) return
|
|
327
|
+
frontier = await close_next_level(open_epics, frontier, evaluated)
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
if (frontier.length > 0) console.info(CASCADE_DEPTH_NOTE)
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
const UNREADABLE_EPIC_LIST_MESSAGE =
|
|
334
|
+
'⚠️ Could not read the open epic listing; skipped the epic auto-close check.'
|
|
335
|
+
|
|
336
|
+
async function resolve_and_close(merged_number: number): Promise<void> {
|
|
337
|
+
const open_epics = await fetch_open_epics()
|
|
338
|
+
|
|
339
|
+
if (open_epics === undefined) {
|
|
340
|
+
console.info(UNREADABLE_EPIC_LIST_MESSAGE)
|
|
341
|
+
|
|
342
|
+
return
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
await cascade_close(open_epics, merged_number)
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// Runs after the PR has already merged, so nothing here may reject: it would make `followup` exit
|
|
349
|
+
// non-zero on an otherwise successful run and read as a merge blocker.
|
|
350
|
+
async function resolve_and_close_safely(merged_number: number): Promise<void> {
|
|
351
|
+
try {
|
|
352
|
+
await resolve_and_close(merged_number)
|
|
353
|
+
} catch (error) {
|
|
354
|
+
const message = error instanceof Error ? error.message : String(error)
|
|
355
|
+
|
|
356
|
+
console.info(`⚠️ Skipped the epic auto-close check: ${message}`)
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* Close every open epic whose task list is fully complete once `issue_number` closed.
|
|
362
|
+
*
|
|
363
|
+
* Requires `is_merged`: the linked Issue is treated as closed without being queried, which only
|
|
364
|
+
* holds once the PR actually merged. On a `--no-merge` run that Issue is still open, so skipping
|
|
365
|
+
* this guard would close an epic whose batch is not finished.
|
|
366
|
+
*/
|
|
367
|
+
async function close_completed_epics(input: {
|
|
368
|
+
issue_number: string | undefined
|
|
369
|
+
is_merged: boolean
|
|
370
|
+
}): Promise<void> {
|
|
371
|
+
if (!input.is_merged) return
|
|
372
|
+
|
|
373
|
+
const merged_number = Number(input.issue_number)
|
|
374
|
+
if (!Number.isSafeInteger(merged_number)) return
|
|
375
|
+
|
|
376
|
+
await resolve_and_close_safely(merged_number)
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
const git_epic_close = {
|
|
380
|
+
close_completed_epics,
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
export {
|
|
384
|
+
git_epic_close,
|
|
385
|
+
close_completed_epics,
|
|
386
|
+
truncated_epic_list_note,
|
|
387
|
+
EPIC_LIST_LIMIT,
|
|
388
|
+
MAX_CASCADE_DEPTH,
|
|
389
|
+
CASCADE_DEPTH_NOTE,
|
|
390
|
+
UNREADABLE_EPIC_LIST_MESSAGE,
|
|
391
|
+
UNREADABLE_COMMENTS_NOTE,
|
|
392
|
+
}
|
|
393
|
+
export type { EpicIssue }
|