@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,516 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
import { fileURLToPath } from 'node:url'
|
|
3
|
+
import { epic_bundle_gaps } from '#scripts/epic/epic-bundle-gaps'
|
|
4
|
+
import { epic_index, type FetchedEpics } from '#scripts/epic/epic-index'
|
|
5
|
+
import { epic_issue } from '#scripts/epic/epic-issue'
|
|
6
|
+
import { git_gh_command } from '#scripts/git/git-gh-command'
|
|
7
|
+
import { SUMMARY_FIELDS } from '#scripts/git/git-gh-issue'
|
|
8
|
+
import { git_next_issues } from '#scripts/git/git-next-issues'
|
|
9
|
+
import { AUTO_OK_LABEL } from '#scripts/git/issue-labels'
|
|
10
|
+
import { cutoff_cause, cutoff_of, type ScanCutoff } from '#scripts/git/listing-cutoff'
|
|
11
|
+
import { read_json_listing } from '#scripts/git/parse-json-array'
|
|
12
|
+
import { open_issue_schema, type OpenIssueData } from '#scripts/git/schemas'
|
|
13
|
+
|
|
14
|
+
// `josh auto-ok:next` — which issue outside the epic an unattended run picks up next
|
|
15
|
+
// (joshuafolkken/kit#906).
|
|
16
|
+
//
|
|
17
|
+
// A command rather than a documented `gh` invocation, for the reason the label constant exists: the
|
|
18
|
+
// name `auto-ok` is single-sourced in `scripts/git/issue-labels.ts`, and a procedure that told an
|
|
19
|
+
// agent to type `gh issue list --label auto-ok` would put a second copy of it in prose, where
|
|
20
|
+
// nothing checks it. The contract is `epic:next`'s: one token on standard output, every explanation
|
|
21
|
+
// on standard error, so `answer=$(pnpm josh auto-ok:next)` reads it.
|
|
22
|
+
|
|
23
|
+
const ARGV_OFFSET = 2
|
|
24
|
+
const SUCCESS_EXIT_CODE = 0
|
|
25
|
+
const FAILURE_EXIT_CODE = 1
|
|
26
|
+
const EXCLUDE_FLAG = '--exclude'
|
|
27
|
+
const EXCLUDE_SEPARATOR = ','
|
|
28
|
+
// A `--exclude` occurrence is the flag plus its value.
|
|
29
|
+
const EXCLUDE_PAIR_SIZE = 2
|
|
30
|
+
const USAGE = `Usage: josh auto-ok:next [${EXCLUDE_FLAG} <issue-number>[,<issue-number>...]]...`
|
|
31
|
+
// The token for "nobody has opted anything in", which is the ordinary answer: opting in is the
|
|
32
|
+
// default absence, so a repository that has never used the label answers this on every run.
|
|
33
|
+
const NONE_TOKEN = 'none'
|
|
34
|
+
// Wide enough that the cap is never what decides the order. The listing is newest first because
|
|
35
|
+
// `git-gh-issue-list.ts` spells `sort=created&direction=desc` into every request rather than leaning
|
|
36
|
+
// on REST's default (joshuafolkken/kit#1025), so a truncated listing drops the *oldest* opted-in
|
|
37
|
+
// issues — which is reported rather than silently ranked.
|
|
38
|
+
const LISTING_LIMIT = 200
|
|
39
|
+
|
|
40
|
+
// Two different gaps, told apart because they send a person to two different places. A listing that
|
|
41
|
+
// never arrived is an access or connectivity problem; a listing that arrived in a shape the schema
|
|
42
|
+
// rejects is the rows' fields having changed under the REST mapping in `git-gh-issue-rest.ts`, where
|
|
43
|
+
// `gh auth status` is green and checking it wastes the one hint the message had to give
|
|
44
|
+
// (joshuafolkken/kit#996).
|
|
45
|
+
//
|
|
46
|
+
// The second message named `gh --version` until joshuafolkken/kit#1069. The listing has been REST
|
|
47
|
+
// since joshuafolkken/kit#1025 and `git-gh-issue-list.ts` builds the JSON this parser reads, so the
|
|
48
|
+
// CLI's version cannot be what changed the row shape — the same misdirection the message below
|
|
49
|
+
// already refuses to repeat for the blocker relations, left standing one constant above it.
|
|
50
|
+
const UNREADABLE_MESSAGE = `Could not read the \`${AUTO_OK_LABEL}\` listing. That is not "nothing is opted in" — check \`gh auth status\` and ask again.`
|
|
51
|
+
const UNEXPECTED_SHAPE_MESSAGE = `Read the \`${AUTO_OK_LABEL}\` listing but could not parse it. That is not "nothing is opted in" — the rows came back in a shape this command does not recognize, so check the fields it asks for and the REST field mapping in \`scripts/git/git-gh-issue-rest.ts\` rather than your authentication.`
|
|
52
|
+
// The blocker relations failing takes the whole listing with them, and `issue_list` swallows
|
|
53
|
+
// the error — so the read looks exactly like an access failure and sends the reader to
|
|
54
|
+
// `gh auth status`, which is green. That is the misdirection joshuafolkken/kit#996 added the message
|
|
55
|
+
// above to remove, walked straight back in by the field the same change started asking for
|
|
56
|
+
// (joshuafolkken/kit#1005).
|
|
57
|
+
//
|
|
58
|
+
// The listing is REST now, so the cause is no longer `gh`'s version: the relations come from each
|
|
59
|
+
// issue's own `dependencies/blocked_by` endpoint, and it is those requests — not the CLI — that the
|
|
60
|
+
// probe has just shown to be the difference. Naming `gh --version` here would send a reader on a
|
|
61
|
+
// current `gh` to the one place the answer is not.
|
|
62
|
+
//
|
|
63
|
+
// It names both causes rather than asserting one. The probe separates "the relations" from "the
|
|
64
|
+
// listing", and it cannot separate a host that does not serve dependencies from a rate limit reached
|
|
65
|
+
// by the one-request-per-blocked-issue pass — so claiming the first would be the same misdirection
|
|
66
|
+
// in a new place (joshuafolkken/kit#1025).
|
|
67
|
+
const BLOCKERS_UNREADABLE_MESSAGE = `Could not read the \`${AUTO_OK_LABEL}\` listing, though the same listing reads once the blocker relations are dropped from it — so it is reading the relations that failed, not your authentication. That is one \`dependencies/blocked_by\` request per opted-in issue declaring a blocker: either this GitHub host does not serve issue dependencies, or those requests are being rate limited. Ask again, and check the host if it persists.`
|
|
68
|
+
// Said once the answer is known, so it never claims there is an answer below when there is not.
|
|
69
|
+
// Either cutoff only ever drops the *oldest* opted-in issues, the listing being newest first, so the
|
|
70
|
+
// consequence is one sentence — but the two cite different numbers and a reader who wants the
|
|
71
|
+
// listing widened reaches for a different knob for each (joshuafolkken/kit#1067).
|
|
72
|
+
const TRUNCATED_BY_LIMIT = `hit the ${String(LISTING_LIMIT)}-issue cap`
|
|
73
|
+
const TRUNCATED_WITH_ANSWER =
|
|
74
|
+
'; the answer below is opted in, but it may not be the highest-priority one.'
|
|
75
|
+
const TRUNCATED_WITHOUT_ANSWER =
|
|
76
|
+
', and every issue in it was excluded — an opted-in issue older than the cut may still be runnable.'
|
|
77
|
+
|
|
78
|
+
function truncated_cause(cutoff: ScanCutoff): string | undefined {
|
|
79
|
+
return cutoff_cause(cutoff, TRUNCATED_BY_LIMIT)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const NONE_OPTED_IN_MESSAGE = `No open issue carries \`${AUTO_OK_LABEL}\`.`
|
|
83
|
+
// The epic listing failing is not "no epic tracks anything". Read that way, every child of every
|
|
84
|
+
// epic reads as a standalone candidate and the pickup hands one back out of its epic's order — the
|
|
85
|
+
// single failure joshuafolkken/kit#1633 is about, arriving with exit 0 and nothing said.
|
|
86
|
+
const EPICS_UNREADABLE_MESSAGE = `Could not read the epic listing, so which issues an epic already tracks is unknown. That is not "no epic tracks anything" — an opted-in child would be handed back outside its epic's order, so no answer is given. Check \`gh auth status\` and ask again.`
|
|
87
|
+
const CLOSED_STATE = 'CLOSED'
|
|
88
|
+
const NO_CUTOFF: ScanCutoff = 'none'
|
|
89
|
+
|
|
90
|
+
// The issue just merged, so the next answer cannot be it again. GitHub applies the `closes #N` side
|
|
91
|
+
// effect asynchronously, so for a few seconds after a merge the issue is still listed as open —
|
|
92
|
+
// which is why `prioritize` takes this number at all, and why a pickup loop that never passes it
|
|
93
|
+
// leaves an already-merged issue to be excluded only by the `in-progress` label it happens to still
|
|
94
|
+
// carry (joshuafolkken/kit#906).
|
|
95
|
+
interface NextOptions {
|
|
96
|
+
// Every number the caller asked to skip. A pickup loop passes the ones it has already run this
|
|
97
|
+
// session, not just the last: `closes #N` can fail to fire — a reference dropped from a PR body —
|
|
98
|
+
// and the `in-progress` label the procedure itself calls an unreliable guard is then the only
|
|
99
|
+
// thing standing between the loop and running an issue twice (joshuafolkken/kit#996).
|
|
100
|
+
exclude?: ReadonlyArray<number>
|
|
101
|
+
usage?: string
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// An issue number, or `undefined` for a value that is not a positive whole number — an empty string,
|
|
105
|
+
// a zero, a negative, or anything `Number` cannot read at all. Alternative spellings `Number` does
|
|
106
|
+
// accept (`1e3`, `0x38`, `12.0`) are read as the number they denote rather than refused; they cost
|
|
107
|
+
// a mistyped exclusion at worst, and the answer is still an opted-in issue.
|
|
108
|
+
function parse_issue_number(value: string): number | undefined {
|
|
109
|
+
const parsed = Number(value)
|
|
110
|
+
if (!Number.isSafeInteger(parsed) || parsed <= 0) return undefined
|
|
111
|
+
|
|
112
|
+
return parsed
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// One `--exclude` value, which may name several issues at once. `undefined` for a missing value or
|
|
116
|
+
// any entry that is not a usable issue number — a partly-valid list is refused whole, so a typo
|
|
117
|
+
// cannot silently narrow the exclusion.
|
|
118
|
+
function parse_exclude(value: string | undefined): ReadonlyArray<number> | undefined {
|
|
119
|
+
if (value === undefined) return undefined
|
|
120
|
+
const parsed = value.split(EXCLUDE_SEPARATOR).map((entry) => parse_issue_number(entry.trim()))
|
|
121
|
+
|
|
122
|
+
return parsed.every((entry) => entry !== undefined) ? parsed : undefined
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// One `--exclude <value>` pair at `index`, or `undefined` when that is not what is there.
|
|
126
|
+
function parse_pair(argv: ReadonlyArray<string>, index: number): ReadonlyArray<number> | undefined {
|
|
127
|
+
if (argv[index] !== EXCLUDE_FLAG) return undefined
|
|
128
|
+
|
|
129
|
+
return parse_exclude(argv[index + 1])
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// `--exclude` may also be repeated, so a loop can add one number per pickup without rebuilding a
|
|
133
|
+
// list. Anything that is not a `--exclude` pair is a usage error rather than a silently ignored
|
|
134
|
+
// argument.
|
|
135
|
+
//
|
|
136
|
+
// `usage` is a parameter so a second command with the same `--exclude` grammar reuses this rather
|
|
137
|
+
// than copying the loop — `josh backlog:next` does (joshuafolkken/kit#1630). Only the line printed on
|
|
138
|
+
// a bad argument differs between them, and a caller that passes nothing gets this command's own.
|
|
139
|
+
function parse_options(argv: ReadonlyArray<string>, usage: string = USAGE): NextOptions {
|
|
140
|
+
const exclude: Array<number> = []
|
|
141
|
+
|
|
142
|
+
for (let index = 0; index < argv.length; index += EXCLUDE_PAIR_SIZE) {
|
|
143
|
+
const parsed = parse_pair(argv, index)
|
|
144
|
+
if (parsed === undefined) return { usage }
|
|
145
|
+
exclude.push(...parsed)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return exclude.length === 0 ? {} : { exclude }
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Every open issue carrying the label, or which of two gaps stopped the read. Neither gap is an
|
|
152
|
+
// empty listing: reading a failed read as "none" ends the run reporting a confident absence built on
|
|
153
|
+
// a response nobody parsed (joshuafolkken/kit#950). They stay apart from each other because the zod
|
|
154
|
+
// rejection `parse_json_array_or_undefined` deliberately rethrows means the listing's *fields*
|
|
155
|
+
// changed, not that the caller's authentication lapsed (joshuafolkken/kit#996).
|
|
156
|
+
type OptedInRead =
|
|
157
|
+
| { kind: 'read'; issues: Array<OpenIssueData>; cutoff: ScanCutoff }
|
|
158
|
+
| { kind: 'unreadable' }
|
|
159
|
+
| { kind: 'unexpected_shape' }
|
|
160
|
+
| { kind: 'blockers_unreadable' }
|
|
161
|
+
|
|
162
|
+
// The two gaps `read_json_listing` names, carried through unchanged. Since joshuafolkken/kit#1025
|
|
163
|
+
// `raw` is the JSON `git-gh-issue-list.ts` assembles from the REST rows rather than a CLI's stdout,
|
|
164
|
+
// so a transport failure — a rate limit, a dropped connection — never reaches this parser at all:
|
|
165
|
+
// `issue_list` catches it into `json === undefined` and `classify_failed_read` decides what it
|
|
166
|
+
// was. What does reach here is the rethrown zod rejection, meaning the listing arrived and its
|
|
167
|
+
// *fields* were not what was asked for. `unreadable` is passed on rather than folded away because
|
|
168
|
+
// reading a gap as an empty listing is the confident absence kit#950 exists to prevent, and this is
|
|
169
|
+
// not the place to make that assumption.
|
|
170
|
+
function parse_listing(raw: string, is_capped: boolean): OptedInRead {
|
|
171
|
+
const read = read_json_listing(raw, open_issue_schema)
|
|
172
|
+
if (read.kind !== 'read') return { kind: read.kind }
|
|
173
|
+
|
|
174
|
+
return {
|
|
175
|
+
kind: 'read',
|
|
176
|
+
issues: read.rows,
|
|
177
|
+
cutoff: cutoff_of(read.rows.length, LISTING_LIMIT, is_capped),
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Whether the *identical* listing reads once `blockedBy` is dropped from it. Named for what it
|
|
182
|
+
// answers rather than for what it implies, because the two are opposite: a `true` here means the
|
|
183
|
+
// field was the problem, and an earlier spelling returned the failure instead — correct only because
|
|
184
|
+
// its one call site inverted it back (joshuafolkken/kit#1005).
|
|
185
|
+
//
|
|
186
|
+
// **Only the field list changes.** Varying the limit as well would let a rate limit or a timeout that
|
|
187
|
+
// a smaller request happens to survive read as the blocker relations failing, on a host that serves
|
|
188
|
+
// them perfectly well.
|
|
189
|
+
async function reads_without_blocked_by(): Promise<boolean> {
|
|
190
|
+
const probe = await git_gh_command.issue_list_by_label_summary(AUTO_OK_LABEL, LISTING_LIMIT, {
|
|
191
|
+
json_fields: SUMMARY_FIELDS,
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
return probe.json !== undefined
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Which gap a failed listing was. Both probes run only here, so a healthy run never spends either.
|
|
198
|
+
//
|
|
199
|
+
// **The relations are blamed only when they fail twice and the form without them succeeds.** One
|
|
200
|
+
// success of that form is not enough on its own: a network blip or a passing rate limit on the first
|
|
201
|
+
// read clears by the time the probe runs, and the run would then send someone whose host serves
|
|
202
|
+
// dependencies perfectly well to look at it. `issue_list` swallows the underlying error, so
|
|
203
|
+
// repeating the original read is what separates a transient failure from a standing one
|
|
204
|
+
// (joshuafolkken/kit#1005).
|
|
205
|
+
async function classify_failed_read(): Promise<OptedInRead> {
|
|
206
|
+
if (!(await reads_without_blocked_by())) return { kind: 'unreadable' }
|
|
207
|
+
|
|
208
|
+
const retry = await git_gh_command.issue_list_by_label_summary(AUTO_OK_LABEL, LISTING_LIMIT)
|
|
209
|
+
|
|
210
|
+
// The original form working on the second attempt means nothing was wrong with the field.
|
|
211
|
+
return retry.json === undefined
|
|
212
|
+
? { kind: 'blockers_unreadable' }
|
|
213
|
+
: parse_listing(retry.json, retry.is_capped)
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
async function fetch_opted_in(): Promise<OptedInRead> {
|
|
217
|
+
const { json, is_capped } = await git_gh_command.issue_list_by_label_summary(
|
|
218
|
+
AUTO_OK_LABEL,
|
|
219
|
+
LISTING_LIMIT,
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
return json === undefined ? await classify_failed_read() : parse_listing(json, is_capped)
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Whether every issue this one declares as a blocker has closed. `blockedBy` is the same native
|
|
226
|
+
// relation `epic:next` builds its graph from, and each blocker's state comes back alongside its
|
|
227
|
+
// number, so no blocker needs a read of its own.
|
|
228
|
+
//
|
|
229
|
+
// The relations are not in the listing response at all since joshuafolkken/kit#1025 — REST serves
|
|
230
|
+
// them from each issue's own dependencies endpoint — so this pickup pays one extra request per row
|
|
231
|
+
// whose own dependency summary does not report exactly zero blockers, and nothing for the rest.
|
|
232
|
+
//
|
|
233
|
+
// An unattended run must not start an issue whose prerequisite is still open: `auto-ok` is applied
|
|
234
|
+
// by a person to an issue they judged needs no decision, which says nothing about ordering, and the
|
|
235
|
+
// pickup previously consulted only the `epic` / `in-progress` / `needs-decision` labels
|
|
236
|
+
// (joshuafolkken/kit#996). A blocker with no state reads as standing — the safe direction, since the
|
|
237
|
+
// cost is deferring an issue rather than implementing one out of order.
|
|
238
|
+
// `nodes` is a page — fifty under GraphQL, one hundred under REST. When `totalCount` says there are
|
|
239
|
+
// more, the ones outside the page are unknown, and unknown reads as standing — the same direction
|
|
240
|
+
// as a blocker with no state. Deferring costs a poll; starting out of order costs the ordering
|
|
241
|
+
// itself. The `?? nodes.length` fallback reads a listing that carries no count at all as complete,
|
|
242
|
+
// which every row this pickup reads does carry, from its own dependency summary.
|
|
243
|
+
function is_page_complete(blocked_by: OpenIssueData['blockedBy']): boolean {
|
|
244
|
+
const nodes = blocked_by?.nodes ?? []
|
|
245
|
+
|
|
246
|
+
return (blocked_by?.totalCount ?? nodes.length) <= nodes.length
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// `epic_issue.normalize_state` rather than a second spelling of it: the epic commands already read
|
|
250
|
+
// GitHub's state casing through one function, and "is this blocker closed" is the question it
|
|
251
|
+
// answers (joshuafolkken/kit#862). A blocker reported without a state reads as standing.
|
|
252
|
+
function is_closed(blocker: { state?: string | undefined }): boolean {
|
|
253
|
+
return epic_issue.normalize_state(blocker.state ?? '') === CLOSED_STATE
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function is_unblocked(issue: OpenIssueData): boolean {
|
|
257
|
+
if (!is_page_complete(issue.blockedBy)) return false
|
|
258
|
+
|
|
259
|
+
return (issue.blockedBy?.nodes ?? []).every((blocker) => is_closed(blocker))
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Which issues an epic already tracks, or that the epic listing could not be read.
|
|
263
|
+
//
|
|
264
|
+
// **The question is membership, not a label** (joshuafolkken/kit#1633). An epic's child carries none
|
|
265
|
+
// of `epic` / `in-progress` / `needs-decision`, so the label comparison inside `prioritize` never
|
|
266
|
+
// saw one — and `auto-ok` on a child put that child in the standalone candidate set, where the
|
|
267
|
+
// epic's `blockedBy` ordering is never consulted. The epics themselves are still found by the `epic`
|
|
268
|
+
// label, exactly as `epic:bundle` finds them, so this does not survive an epic that never received
|
|
269
|
+
// it — what it removes is the *child's* labels deciding, which is the half that was failing.
|
|
270
|
+
//
|
|
271
|
+
// **The whole index is carried rather than its key set** (joshuafolkken/kit#1668). Which epic tracks
|
|
272
|
+
// a child decides both whether the standalone half withholds it — `epic_index.withheld_children` —
|
|
273
|
+
// and, when it is withheld, the number `backlog:plan` names as the reason. Flattening to a `Set`
|
|
274
|
+
// here threw that number away, so the plan reported a listing cap it had never reached.
|
|
275
|
+
//
|
|
276
|
+
// **And every tracking epic, not one winner** (joshuafolkken/kit#1694). Two epics can name the same
|
|
277
|
+
// child, and a map of one epic per child keeps whichever came last — so an opted-in epic that came
|
|
278
|
+
// earlier vanished, and the child was offered standalone *and* through that epic.
|
|
279
|
+
type TrackingRead =
|
|
280
|
+
| { kind: 'read'; index: ReadonlyMap<number, ReadonlyArray<number>>; cutoff: ScanCutoff }
|
|
281
|
+
| { kind: 'epics_unreadable' }
|
|
282
|
+
|
|
283
|
+
async function read_open_epics(): Promise<FetchedEpics | undefined> {
|
|
284
|
+
try {
|
|
285
|
+
return await epic_index.fetch_epics(LISTING_LIMIT)
|
|
286
|
+
} catch {
|
|
287
|
+
return undefined
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// Nothing opted in means no candidate an epic could be tracking, so the listing is not paid for at
|
|
292
|
+
// all — the ordinary answer on a repository that has never used the label.
|
|
293
|
+
//
|
|
294
|
+
// **The rejection is caught, not left to escape.** `parse_json_array_or_undefined` answers
|
|
295
|
+
// `undefined` only for a response that is not a JSON array at all and *rethrows* a schema mismatch —
|
|
296
|
+
// so a changed field mapping in `git-gh-issue-rest.ts` would take this command down with a stack
|
|
297
|
+
// trace and an empty standard output, which `answer=$(pnpm josh auto-ok:next)` reads as the empty
|
|
298
|
+
// string. The opted-in listing already refuses that through `read_json_listing`; this one refuses it
|
|
299
|
+
// here, and both gaps land on the same message because both mean the same thing: the tracking is
|
|
300
|
+
// unknown, so no answer is given.
|
|
301
|
+
async function fetch_tracking(count: number): Promise<TrackingRead> {
|
|
302
|
+
if (count === 0) return { kind: 'read', index: new Map(), cutoff: NO_CUTOFF }
|
|
303
|
+
const open_epics = await read_open_epics()
|
|
304
|
+
if (open_epics === undefined) return { kind: 'epics_unreadable' }
|
|
305
|
+
|
|
306
|
+
return {
|
|
307
|
+
kind: 'read',
|
|
308
|
+
index: epic_index.build_tracking_index(open_epics.epics),
|
|
309
|
+
cutoff: open_epics.cutoff,
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// The pickup *order* is `git_next_issues.prioritize` itself, not a copy of it: newest first, with the
|
|
314
|
+
// `epic` / `in-progress` / `needs-decision` exclusions. Its display cap does not reach this caller,
|
|
315
|
+
// which reads only the first row.
|
|
316
|
+
//
|
|
317
|
+
// The two are no longer the same *set*, and deliberately so: since joshuafolkken/kit#996 the pickup
|
|
318
|
+
// also drops a candidate whose prerequisite is still open, while `🗒 Next issues` shows every open
|
|
319
|
+
// issue and leaves the judgement to the person reading it. So the display can name an issue this
|
|
320
|
+
// command refuses — a person can see a blocked issue is next and decide to start it anyway, and an
|
|
321
|
+
// unattended run must not.
|
|
322
|
+
//
|
|
323
|
+
// Membership of the label is the *query's* job, not this function's: `--label` is what makes the
|
|
324
|
+
// listing the opted-in set, so re-testing it here would be a second definition of opting in.
|
|
325
|
+
//
|
|
326
|
+
// The exclusions are applied **before** `prioritize`, not after: it keeps only its first few rows,
|
|
327
|
+
// so filtering its output would answer `none` whenever those rows happen to be blocked while a
|
|
328
|
+
// runnable issue sits below them.
|
|
329
|
+
//
|
|
330
|
+
// The `🗒 Next issues` display is deliberately *not* filtered this way; `git-next-issues.ts` records
|
|
331
|
+
// why, and the short version is that a person can see a blocked issue and choose to start it anyway
|
|
332
|
+
// while an unattended run cannot (joshuafolkken/kit#1005).
|
|
333
|
+
//
|
|
334
|
+
// A child of an epic that is itself opted in is dropped here for the same reason and by the same
|
|
335
|
+
// rule: that epic's declared order sequences its children, and it is going to offer them, so a
|
|
336
|
+
// standalone offer would skip the order and hand the same issue over twice (joshuafolkken/kit#1633).
|
|
337
|
+
// **A child of an epic that is *not* opted in is no longer dropped** — no path would ever offer it,
|
|
338
|
+
// which made a person's `auto-ok` on the child silently inert, and the order it does have is carried
|
|
339
|
+
// by the native `blockedBy` relations `is_unblocked` already refuses to run past
|
|
340
|
+
// (joshuafolkken/kit#1668). `tracked` is the narrowed set `epic_index.withheld_children` builds, not
|
|
341
|
+
// every tracked child; this function only applies it.
|
|
342
|
+
function is_runnable(
|
|
343
|
+
issue: OpenIssueData,
|
|
344
|
+
tracked: ReadonlyMap<number, number>,
|
|
345
|
+
exclude: ReadonlyArray<number>,
|
|
346
|
+
): boolean {
|
|
347
|
+
if (tracked.has(issue.number)) return false
|
|
348
|
+
|
|
349
|
+
return is_unblocked(issue) && !exclude.includes(issue.number)
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
function pick_next(
|
|
353
|
+
issues: ReadonlyArray<OpenIssueData>,
|
|
354
|
+
tracked: ReadonlyMap<number, number> = new Map(),
|
|
355
|
+
exclude: ReadonlyArray<number> = [],
|
|
356
|
+
): OpenIssueData | undefined {
|
|
357
|
+
const runnable = issues.filter((issue) => is_runnable(issue, tracked, exclude))
|
|
358
|
+
|
|
359
|
+
return git_next_issues.prioritize(runnable)[0]
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// Why there is nothing to run. "No open issue carries the label" and "every opted-in issue is
|
|
363
|
+
// excluded" look identical from the token, and telling a person the label is absent when it is
|
|
364
|
+
// applied sends them to apply it again.
|
|
365
|
+
function none_reason(count: number): string {
|
|
366
|
+
if (count === 0) return NONE_OPTED_IN_MESSAGE
|
|
367
|
+
|
|
368
|
+
return `All ${String(count)} open \`${AUTO_OK_LABEL}\` issue(s) are excluded — tracked by an opted-in epic, an epic itself, already in progress, parked, blocked by an open issue, or the one just merged.`
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// Said only when the cap actually bit, and worded from the answer rather than before it: the one run
|
|
372
|
+
// where truncation matters is the one where everything listed was excluded, and announcing "the
|
|
373
|
+
// answer below is opted in" there contradicted the `none` that followed (joshuafolkken/kit#996).
|
|
374
|
+
function truncation_note(cutoff: ScanCutoff, has_answer: boolean): string | undefined {
|
|
375
|
+
const cause = truncated_cause(cutoff)
|
|
376
|
+
if (cause === undefined) return undefined
|
|
377
|
+
const tail = has_answer ? TRUNCATED_WITH_ANSWER : TRUNCATED_WITHOUT_ANSWER
|
|
378
|
+
|
|
379
|
+
return `⚠ The listing ${cause}, so the oldest \`${AUTO_OK_LABEL}\` issues are not in it${tail}`
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// What the two listings could not see. The epic gap is `epic:bundle`'s own wording rather than a
|
|
383
|
+
// second copy of it: the sentence says an epic past the cut was not considered, which is the same
|
|
384
|
+
// fact here — and here it means a child of that epic reads as standalone.
|
|
385
|
+
function warn_gaps(context: PickupContext, has_answer: boolean): void {
|
|
386
|
+
const note = truncation_note(context.cutoff, has_answer)
|
|
387
|
+
|
|
388
|
+
if (note !== undefined) console.error(note)
|
|
389
|
+
const epic_note = epic_bundle_gaps.epic_gap(context.epic_cutoff, LISTING_LIMIT)
|
|
390
|
+
|
|
391
|
+
if (epic_note !== undefined) console.error(epic_note)
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// Grouped rather than passed one by one: the pickup now answers from two listings, and the
|
|
395
|
+
// parameter limit is four.
|
|
396
|
+
interface PickupContext {
|
|
397
|
+
issues: ReadonlyArray<OpenIssueData>
|
|
398
|
+
cutoff: ScanCutoff
|
|
399
|
+
tracked: ReadonlyMap<number, number>
|
|
400
|
+
epic_cutoff: ScanCutoff
|
|
401
|
+
exclude: ReadonlyArray<number> | undefined
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
function report(context: PickupContext): number {
|
|
405
|
+
const { issues } = context
|
|
406
|
+
const next = pick_next(issues, context.tracked, context.exclude)
|
|
407
|
+
|
|
408
|
+
warn_gaps(context, next !== undefined)
|
|
409
|
+
|
|
410
|
+
if (next === undefined) {
|
|
411
|
+
console.error(none_reason(issues.length))
|
|
412
|
+
console.info(NONE_TOKEN)
|
|
413
|
+
|
|
414
|
+
return SUCCESS_EXIT_CODE
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
console.error(`#${String(next.number)} ${next.title}`)
|
|
418
|
+
console.info(String(next.number))
|
|
419
|
+
|
|
420
|
+
return SUCCESS_EXIT_CODE
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// The second listing runs only once the first one has an answer to filter, and its failure is
|
|
424
|
+
// reported rather than folded into "no epic tracks anything" (joshuafolkken/kit#1633).
|
|
425
|
+
async function answer(
|
|
426
|
+
read: { issues: Array<OpenIssueData>; cutoff: ScanCutoff },
|
|
427
|
+
exclude?: ReadonlyArray<number>,
|
|
428
|
+
): Promise<number> {
|
|
429
|
+
const tracking = await fetch_tracking(read.issues.length)
|
|
430
|
+
|
|
431
|
+
if (tracking.kind !== 'read') {
|
|
432
|
+
console.error(EPICS_UNREADABLE_MESSAGE)
|
|
433
|
+
|
|
434
|
+
return FAILURE_EXIT_CODE
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
return report({
|
|
438
|
+
issues: read.issues,
|
|
439
|
+
cutoff: read.cutoff,
|
|
440
|
+
tracked: epic_index.withheld_children(tracking.index, read.issues),
|
|
441
|
+
epic_cutoff: tracking.cutoff,
|
|
442
|
+
exclude,
|
|
443
|
+
})
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// The gap that stopped the read decides the message, so a changed field list does not send anyone to
|
|
447
|
+
// `gh auth status` (joshuafolkken/kit#996).
|
|
448
|
+
const READ_FAILURE_MESSAGES = {
|
|
449
|
+
unreadable: UNREADABLE_MESSAGE,
|
|
450
|
+
unexpected_shape: UNEXPECTED_SHAPE_MESSAGE,
|
|
451
|
+
blockers_unreadable: BLOCKERS_UNREADABLE_MESSAGE,
|
|
452
|
+
} as const
|
|
453
|
+
|
|
454
|
+
async function run(argv: ReadonlyArray<string>): Promise<number> {
|
|
455
|
+
const options = parse_options(argv)
|
|
456
|
+
|
|
457
|
+
if (options.usage !== undefined) {
|
|
458
|
+
console.error(options.usage)
|
|
459
|
+
|
|
460
|
+
return FAILURE_EXIT_CODE
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
const read = await fetch_opted_in()
|
|
464
|
+
|
|
465
|
+
if (read.kind !== 'read') {
|
|
466
|
+
console.error(READ_FAILURE_MESSAGES[read.kind])
|
|
467
|
+
|
|
468
|
+
return FAILURE_EXIT_CODE
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
return await answer(read, options.exclude)
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
// `process.exitCode` rather than `process.exit()`: the answer is written with `console.info`, and on
|
|
475
|
+
// macOS a write to a pipe is asynchronous — `process.exit()` can tear the process down before it has
|
|
476
|
+
// drained, and this command's whole contract is `answer=$(pnpm josh auto-ok:next)`. The same shape
|
|
477
|
+
// is already in `scripts/cost-runtime/cost-cli.ts`, which met the truncation first (joshuafolkken/kit#996).
|
|
478
|
+
async function main(argv: ReadonlyArray<string>): Promise<void> {
|
|
479
|
+
process.exitCode = await run(argv)
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
const auto_ok_cli = {
|
|
483
|
+
USAGE,
|
|
484
|
+
NONE_TOKEN,
|
|
485
|
+
LISTING_LIMIT,
|
|
486
|
+
UNREADABLE_MESSAGE,
|
|
487
|
+
UNEXPECTED_SHAPE_MESSAGE,
|
|
488
|
+
BLOCKERS_UNREADABLE_MESSAGE,
|
|
489
|
+
EPICS_UNREADABLE_MESSAGE,
|
|
490
|
+
TRUNCATED_WITH_ANSWER,
|
|
491
|
+
TRUNCATED_WITHOUT_ANSWER,
|
|
492
|
+
NONE_OPTED_IN_MESSAGE,
|
|
493
|
+
truncated_cause,
|
|
494
|
+
parse_issue_number,
|
|
495
|
+
parse_exclude,
|
|
496
|
+
parse_pair,
|
|
497
|
+
parse_options,
|
|
498
|
+
fetch_opted_in,
|
|
499
|
+
parse_listing,
|
|
500
|
+
is_page_complete,
|
|
501
|
+
is_closed,
|
|
502
|
+
is_unblocked,
|
|
503
|
+
fetch_tracking,
|
|
504
|
+
is_runnable,
|
|
505
|
+
pick_next,
|
|
506
|
+
truncation_note,
|
|
507
|
+
none_reason,
|
|
508
|
+
report,
|
|
509
|
+
run,
|
|
510
|
+
main,
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
if (process.argv[1] === fileURLToPath(import.meta.url)) await main(process.argv.slice(ARGV_OFFSET))
|
|
514
|
+
|
|
515
|
+
export { auto_ok_cli }
|
|
516
|
+
export type { NextOptions, OptedInRead, PickupContext, TrackingRead }
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import type { JoshResult } from '#scripts/josh/josh-run'
|
|
2
|
+
import { run_headless } from '#scripts/run/run-headless'
|
|
3
|
+
import { backlog_next } from './backlog-next'
|
|
4
|
+
import { backlog_ready, type ReadyPorts, type ReadyReading } from './backlog-ready'
|
|
5
|
+
import { backlog_stalled } from './backlog-stalled'
|
|
6
|
+
|
|
7
|
+
// The arrival probe a `backlogrun` parent's `--wait` watcher runs while children are in flight
|
|
8
|
+
// (joshuafolkken/kit#2503). An issue opted in with `auto-ok` mid-run was picked up only when the parent
|
|
9
|
+
// next woke — a child's merge, or the progress interval — and in practice the ten-minute stall detector
|
|
10
|
+
// became the pick-up: #2493 waited 10.5 minutes, and the person got a ⏳ notification for it.
|
|
11
|
+
//
|
|
12
|
+
// **The watcher's exit is the only thing that wakes a live parent**, so the probe rides it: once a
|
|
13
|
+
// minute it reads the backlog the pick-up line reads (`backlog_ready.read_ready`, cheap first — a full
|
|
14
|
+
// pool answers without the network read), and an issue runnable now that was not runnable when the
|
|
15
|
+
// watcher started ends the wait. The exit prints the `ready #N` line as every exit does, and that line
|
|
16
|
+
// is what sends the parent to `backlog:offer`. The stall detector goes back to being the safety net.
|
|
17
|
+
//
|
|
18
|
+
// **"New" is measured against the watcher's own start**, so one issue wakes the parent once: the next
|
|
19
|
+
// `--wait` the parent starts takes the pool as it stands then — the woken issue included, dispatched or
|
|
20
|
+
// not — as its baseline. A reading that fails is not an arrival; the probe says nothing and the
|
|
21
|
+
// interval still wakes the parent. A baseline that cannot be read leaves that one wait inert rather than
|
|
22
|
+
// reading it as empty — an empty one would wake the parent for the whole pool — and the next `--wait`
|
|
23
|
+
// reads it again.
|
|
24
|
+
//
|
|
25
|
+
// **Every read is bounded.** The probe is awaited inside the watcher's tick loop, so a `gh` call that
|
|
26
|
+
// hangs would otherwise freeze the loop — its `--hours` bound, its liveness ping and the exit that is
|
|
27
|
+
// the parent's wake. A read past `READ_TIMEOUT_MS` is killed and counts as a failed read.
|
|
28
|
+
//
|
|
29
|
+
// **And strict.** `backlog:next` exits 0 on a `retry` (a transport failure) or an `error` verdict, which
|
|
30
|
+
// the lenient pick-up read takes as an empty pool — here that empty baseline is the whole-pool wake the
|
|
31
|
+
// paragraph above rules out, so either verdict, like a non-zero exit, is a read that did not answer.
|
|
32
|
+
|
|
33
|
+
const PROBE_INTERVAL_MS = 60_000
|
|
34
|
+
const READ_TIMEOUT_MS = 30_000
|
|
35
|
+
const SUCCESS_EXIT_CODE = 0
|
|
36
|
+
const NO_FREE = 0
|
|
37
|
+
const NONE = 0
|
|
38
|
+
const UNANSWERED: ReadonlySet<string> = new Set([
|
|
39
|
+
backlog_next.VERDICT_TOKENS.error,
|
|
40
|
+
backlog_next.VERDICT_TOKENS.retry,
|
|
41
|
+
])
|
|
42
|
+
|
|
43
|
+
// The runnable issues a `backlog:next` result names, or a throw where it did not answer. `undefined` is
|
|
44
|
+
// a `--only` run, whose pool is empty by definition.
|
|
45
|
+
function answered_issues(result: JoshResult | undefined): ReadonlyArray<string> {
|
|
46
|
+
if (result === undefined) return []
|
|
47
|
+
|
|
48
|
+
const lines = result.out.split('\n').map((line) => line.trim())
|
|
49
|
+
|
|
50
|
+
if (result.code !== SUCCESS_EXIT_CODE || lines.some((line) => UNANSWERED.has(line))) {
|
|
51
|
+
throw new Error('`backlog:next` did not answer')
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return backlog_stalled.ready_tokens(result.out)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async function bounded_ready_issues(): Promise<ReadonlyArray<string>> {
|
|
58
|
+
return answered_issues(await backlog_ready.read_backlog_next(READ_TIMEOUT_MS))
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const ARRIVAL_PORTS: ReadyPorts = {
|
|
62
|
+
free_lane_count: backlog_ready.free_lane_count,
|
|
63
|
+
ready_issues: bounded_ready_issues,
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
interface ArrivalProbe {
|
|
67
|
+
has_arrived: (now_ms: number) => Promise<boolean>
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Runnable now, not runnable at the start, and a lane free to take it.
|
|
71
|
+
function arrivals(baseline: ReadonlySet<string>, reading: ReadyReading): ReadonlyArray<string> {
|
|
72
|
+
if (reading.free_lanes <= NO_FREE) return []
|
|
73
|
+
|
|
74
|
+
return reading.issues.filter((issue) => !baseline.has(issue))
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// The baseline is the whole runnable pool, free lane or not: an issue that was waiting for a lane is not
|
|
78
|
+
// new when one frees, and the child's merge that freed it already wakes the parent.
|
|
79
|
+
async function read_baseline(ports: ReadyPorts): Promise<ReadonlySet<string> | undefined> {
|
|
80
|
+
try {
|
|
81
|
+
return new Set(await ports.ready_issues())
|
|
82
|
+
} catch {
|
|
83
|
+
return undefined
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async function read_reading(ports: ReadyPorts): Promise<ReadyReading | undefined> {
|
|
88
|
+
try {
|
|
89
|
+
return await backlog_ready.read_ready(ports)
|
|
90
|
+
} catch {
|
|
91
|
+
return undefined
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
async function is_parent_safely(is_parent: () => Promise<boolean>): Promise<boolean> {
|
|
96
|
+
try {
|
|
97
|
+
return await is_parent()
|
|
98
|
+
} catch {
|
|
99
|
+
return false
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async function never_arrives(): Promise<boolean> {
|
|
104
|
+
return false
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const INERT: ArrivalProbe = { has_arrived: never_arrives }
|
|
108
|
+
|
|
109
|
+
// Only the next-probe instant changes between probes, and it is set before the read is awaited.
|
|
110
|
+
function probe_of(
|
|
111
|
+
baseline: ReadonlySet<string>,
|
|
112
|
+
first_ms: number,
|
|
113
|
+
ports: ReadyPorts,
|
|
114
|
+
): ArrivalProbe {
|
|
115
|
+
let next_ms = first_ms
|
|
116
|
+
|
|
117
|
+
async function has_arrived(now_ms: number): Promise<boolean> {
|
|
118
|
+
if (now_ms < next_ms) return false
|
|
119
|
+
|
|
120
|
+
next_ms = now_ms + PROBE_INTERVAL_MS
|
|
121
|
+
|
|
122
|
+
const reading = await read_reading(ports)
|
|
123
|
+
|
|
124
|
+
return reading !== undefined && arrivals(baseline, reading).length > NONE
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return { has_arrived }
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Inert outside a driving `backlogrun` parent — a `fullrun` watcher has no pool to pick from — and there
|
|
131
|
+
// it reads nothing at all.
|
|
132
|
+
async function start(
|
|
133
|
+
now_ms: number,
|
|
134
|
+
ports: ReadyPorts = ARRIVAL_PORTS,
|
|
135
|
+
is_parent: () => Promise<boolean> = run_headless.is_backlog_parent,
|
|
136
|
+
): Promise<ArrivalProbe> {
|
|
137
|
+
if (!(await is_parent_safely(is_parent))) return INERT
|
|
138
|
+
|
|
139
|
+
const baseline = await read_baseline(ports)
|
|
140
|
+
|
|
141
|
+
return baseline === undefined ? INERT : probe_of(baseline, now_ms + PROBE_INTERVAL_MS, ports)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const backlog_arrival = { INERT, PROBE_INTERVAL_MS, answered_issues, arrivals, start }
|
|
145
|
+
|
|
146
|
+
export type { ArrivalProbe }
|
|
147
|
+
export { backlog_arrival }
|