@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,310 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
import { fileURLToPath } from 'node:url'
|
|
3
|
+
import { run_hold, type HoldRead, type RunHold } from './run-hold'
|
|
4
|
+
import { run_preflight, type PreflightDecision } from './run-preflight'
|
|
5
|
+
|
|
6
|
+
// `josh run:hold [<N>]` and `josh run:release [<N> | --force]` — the working-tree guard the typed
|
|
7
|
+
// entry points ask before they start (joshuafolkken/kit#1091).
|
|
8
|
+
//
|
|
9
|
+
// **A numbered claim asks the preflight question first** (joshuafolkken/kit#1965). `run:preflight`
|
|
10
|
+
// was a separate command a run had to ask before this one; the two-step "preflight, then hold" was
|
|
11
|
+
// one call too many, so the claim now runs the check itself and hands back a hold only on a `clean`
|
|
12
|
+
// tree. A `reclaim` / `resume` / `park` tree is returned as that verdict without a record being
|
|
13
|
+
// written, and the read-only check stays re-askable — clean up what it named, ask `run:hold` again.
|
|
14
|
+
// The decision logic itself lives on in `run-preflight.ts` for `run:progress` to reuse; only its CLI
|
|
15
|
+
// went away.
|
|
16
|
+
//
|
|
17
|
+
// **A release names the run it belongs to, exactly as the claim did** (joshuafolkken/kit#1799). The
|
|
18
|
+
// record carries no owner until then, so `run:release` removed whatever was there — and the `busy`
|
|
19
|
+
// stop message tells a person to type it when they judge a record stale, which is a judgement made
|
|
20
|
+
// from outside the run that wrote it. That made the guard's own recovery instruction a way to free a
|
|
21
|
+
// live run's tree: the incident of 2026-08-30, reached through the guard meant to prevent it.
|
|
22
|
+
//
|
|
23
|
+
// **It answers, so the entry point does not judge.** "This one is a small change, it will be fine" is
|
|
24
|
+
// the judgement made under time pressure that produced the incident, and it is the same shape
|
|
25
|
+
// `delegation-policy.ts` refuses to leave to an agent. A token on standard output is what the entry
|
|
26
|
+
// point obeys.
|
|
27
|
+
//
|
|
28
|
+
// The contract is `epic:next`'s: **standard output carries exactly one token** — `hold`, `busy` or
|
|
29
|
+
// `unknown` — and every explanation goes to standard error, so `answer=$(pnpm josh run:hold 1091)`
|
|
30
|
+
// captures something a loop can branch on.
|
|
31
|
+
|
|
32
|
+
const SUCCESS_EXIT_CODE = 0
|
|
33
|
+
const FAILURE_EXIT_CODE = 1
|
|
34
|
+
const ARGV_OFFSET = 2
|
|
35
|
+
const RELEASE_FLAG = '--release'
|
|
36
|
+
// What removes a record this run did not write. **The deliberate friction of the whole change**
|
|
37
|
+
// (joshuafolkken/kit#1799): every release now names the run it belongs to, and the one act that
|
|
38
|
+
// cannot — clearing a record somebody else left behind — is spelled out rather than reached by
|
|
39
|
+
// typing the ordinary command.
|
|
40
|
+
const FORCE_FLAG = '--force'
|
|
41
|
+
const ISSUE_NUMBER_PATTERN = /^[1-9]\d*$/u
|
|
42
|
+
const USAGE = 'Usage: josh run:hold [<issue-number>] | josh run:release [<issue-number> | --force]'
|
|
43
|
+
|
|
44
|
+
const HOLD_VERDICT = 'hold'
|
|
45
|
+
const BUSY_VERDICT = 'busy'
|
|
46
|
+
const UNKNOWN_VERDICT = 'unknown'
|
|
47
|
+
const RELEASED_VERDICT = 'released'
|
|
48
|
+
const NONE_VERDICT = 'none'
|
|
49
|
+
// The record is another run's, so nothing was removed. **It is not `none`**: a release that did not
|
|
50
|
+
// happen must never read to a script as a tree it has just freed.
|
|
51
|
+
const HELD_VERDICT = 'held'
|
|
52
|
+
|
|
53
|
+
const FORCE_RELEASE_KIND = 'force-release'
|
|
54
|
+
|
|
55
|
+
type HoldRequest =
|
|
56
|
+
| { kind: 'release'; claimant: string }
|
|
57
|
+
| { kind: typeof FORCE_RELEASE_KIND }
|
|
58
|
+
| { kind: 'claim'; issue: string }
|
|
59
|
+
|
|
60
|
+
const FORCE_RELEASE_REQUEST: HoldRequest = { kind: FORCE_RELEASE_KIND }
|
|
61
|
+
|
|
62
|
+
function release_request(claimant: string): HoldRequest {
|
|
63
|
+
return { kind: 'release', claimant }
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function parse_claim(argv: ReadonlyArray<string>): HoldRequest | undefined {
|
|
67
|
+
const [first] = argv
|
|
68
|
+
|
|
69
|
+
if (first === undefined) return { kind: 'claim', issue: run_hold.UNNUMBERED_ISSUE }
|
|
70
|
+
|
|
71
|
+
if (argv.length > 1 || !ISSUE_NUMBER_PATTERN.test(first)) return undefined
|
|
72
|
+
|
|
73
|
+
return { kind: 'claim', issue: first }
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function parse_release_argument(first: string): HoldRequest | undefined {
|
|
77
|
+
if (first === FORCE_FLAG) return FORCE_RELEASE_REQUEST
|
|
78
|
+
|
|
79
|
+
return ISSUE_NUMBER_PATTERN.test(first) ? release_request(first) : undefined
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// **A bare `run:release` is the unnumbered run's release, not a release of whatever is there.** It
|
|
83
|
+
// mirrors the bare claim, which records `new`, so the two spellings stay one pair.
|
|
84
|
+
function parse_release(argv: ReadonlyArray<string>): HoldRequest | undefined {
|
|
85
|
+
const [first] = argv
|
|
86
|
+
|
|
87
|
+
if (first === undefined) return release_request(run_hold.UNNUMBERED_ISSUE)
|
|
88
|
+
|
|
89
|
+
return argv.length > 1 ? undefined : parse_release_argument(first)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function parse_request(argv: ReadonlyArray<string>): HoldRequest | undefined {
|
|
93
|
+
if (argv[0] === RELEASE_FLAG) return parse_release(argv.slice(1))
|
|
94
|
+
|
|
95
|
+
return parse_claim(argv)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// One shape for every answer that carries an explanation: the reason to standard error, the single
|
|
99
|
+
// token to standard output, and the exit code that says whether anything was established.
|
|
100
|
+
function report(message: string, verdict: string, code: number): number {
|
|
101
|
+
console.error(message)
|
|
102
|
+
console.info(verdict)
|
|
103
|
+
|
|
104
|
+
return code
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function report_busy(message: string): number {
|
|
108
|
+
return report(message, BUSY_VERDICT, SUCCESS_EXIT_CODE)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function report_hold(): number {
|
|
112
|
+
console.info(HOLD_VERDICT)
|
|
113
|
+
|
|
114
|
+
return SUCCESS_EXIT_CODE
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// What stops a claim, and `undefined` when nothing does. **An unreadable record stops it**: the run
|
|
118
|
+
// that wrote it is the one whose uncommitted work would be trampled, so a record that cannot be
|
|
119
|
+
// parsed is never read as an idle tree. **And an expired record still stops it while the tree is
|
|
120
|
+
// dirty** — that is a run which stopped for a person, and the work is right there in the tree.
|
|
121
|
+
async function blocking_message(read: HoldRead): Promise<string | undefined> {
|
|
122
|
+
if (read.kind === 'held') return run_hold.held_message(read.hold)
|
|
123
|
+
|
|
124
|
+
if (read.kind === 'unreadable') return run_hold.unreadable_message()
|
|
125
|
+
|
|
126
|
+
const is_expired_over_work = read.kind === 'stale' && (await run_hold.is_tree_dirty())
|
|
127
|
+
|
|
128
|
+
return is_expired_over_work ? run_hold.uncommitted_message(read.hold) : undefined
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// A record already here is never overwritten by a claim: overwriting is what the guard exists to
|
|
132
|
+
// prevent, and the person who knows the other run has ended clears it with `run:release --force`.
|
|
133
|
+
function take_free_tree(target: string, issue: string): number {
|
|
134
|
+
if (run_hold.create_hold(target, issue)) return report_hold()
|
|
135
|
+
|
|
136
|
+
return report_busy(run_hold.race_message(run_hold.read_hold(target), target))
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// **The stale path takes the tree the same exclusive way the free path does.** Replacing an expired
|
|
140
|
+
// record with a plain write would tell two sessions that both found it expired that they both won —
|
|
141
|
+
// the race the free path was just fixed for, reintroduced one branch over. Removing it first is what
|
|
142
|
+
// turns the expired record into a free tree; the create is what decides between the two claimants.
|
|
143
|
+
function replace_stale(target: string, issue: string, hold: RunHold): number {
|
|
144
|
+
console.error(run_hold.stale_message(hold))
|
|
145
|
+
run_hold.release_hold(target)
|
|
146
|
+
|
|
147
|
+
return take_free_tree(target, issue)
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// A non-clean preflight verdict is not an error: it is an answer a loop branches on, exactly as
|
|
151
|
+
// `busy` is, so it prints the reason and advice the check composed and exits zero. Only an unreadable
|
|
152
|
+
// tree is `unknown`, and that reaches `report_unknown` through `run`'s catch, as it always did.
|
|
153
|
+
function report_preflight(decision: PreflightDecision): number {
|
|
154
|
+
console.error(`${decision.reason}\n${decision.advice}`)
|
|
155
|
+
console.info(decision.verdict)
|
|
156
|
+
|
|
157
|
+
return SUCCESS_EXIT_CODE
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// **The tree is checked before it is claimed.** A numbered claim carries a child whose branch and
|
|
161
|
+
// pull request the check reads; a non-`clean` verdict stops the claim and is returned as-is, so no
|
|
162
|
+
// record is written over work a run left behind. Two claims skip it: the unnumbered `new` claim has
|
|
163
|
+
// no child to preflight, and a lane claim is covered by `lane:open` instead.
|
|
164
|
+
async function preflight_gate(issue: string, is_linked: boolean): Promise<number | undefined> {
|
|
165
|
+
if (is_linked || issue === run_hold.UNNUMBERED_ISSUE) return undefined
|
|
166
|
+
|
|
167
|
+
const decision = await run_preflight.check(issue)
|
|
168
|
+
|
|
169
|
+
if (decision.verdict === run_preflight.CLEAN_VERDICT) return undefined
|
|
170
|
+
|
|
171
|
+
return report_preflight(decision)
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
async function claim(target: string, issue: string, is_linked: boolean): Promise<number> {
|
|
175
|
+
const gate = await preflight_gate(issue, is_linked)
|
|
176
|
+
|
|
177
|
+
if (gate !== undefined) return gate
|
|
178
|
+
|
|
179
|
+
const read = run_hold.read_hold(target)
|
|
180
|
+
const blocked = await blocking_message(read)
|
|
181
|
+
|
|
182
|
+
if (blocked !== undefined) return report_busy(blocked)
|
|
183
|
+
|
|
184
|
+
if (read.kind === 'stale') return replace_stale(target, issue, read.hold)
|
|
185
|
+
|
|
186
|
+
return take_free_tree(target, issue)
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function remove_record(target: string, was_present: boolean): number {
|
|
190
|
+
run_hold.release_hold(target)
|
|
191
|
+
console.info(was_present ? RELEASED_VERDICT : NONE_VERDICT)
|
|
192
|
+
|
|
193
|
+
return SUCCESS_EXIT_CODE
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function report_held(hold: RunHold): number {
|
|
197
|
+
return report(run_hold.foreign_release_message(hold), HELD_VERDICT, FAILURE_EXIT_CODE)
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// A record nothing can parse names no run, so no claimant can match it — and removing it anyway is
|
|
201
|
+
// the one thing this path exists to refuse. It answers `unknown` for the reason every other
|
|
202
|
+
// unreadable state here does: nothing was established, so nothing may be concluded.
|
|
203
|
+
function report_unreadable_release(): number {
|
|
204
|
+
return report(run_hold.unreadable_message(), UNKNOWN_VERDICT, FAILURE_EXIT_CODE)
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// **A release removes the record only where the record names the run asking** (joshuafolkken/kit#1799).
|
|
208
|
+
// Until then this removed whatever was there, and the `busy` stop message sent a person here to clear
|
|
209
|
+
// a record they had judged stale from outside the run that wrote it — so the guard's own recovery
|
|
210
|
+
// instruction was a way to free a live run's tree, which is the incident it was written after.
|
|
211
|
+
function release(target: string, claimant: string): number {
|
|
212
|
+
const read = run_hold.read_hold(target)
|
|
213
|
+
|
|
214
|
+
if (read.kind === 'free') return remove_record(target, false)
|
|
215
|
+
|
|
216
|
+
if (read.kind === 'unreadable') return report_unreadable_release()
|
|
217
|
+
|
|
218
|
+
if (!run_hold.is_own_hold(read.hold, claimant)) return report_held(read.hold)
|
|
219
|
+
|
|
220
|
+
return remove_record(target, true)
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// The one path that removes a record without matching it, which is why it says what it removed: a
|
|
224
|
+
// record genuinely abandoned by a crashed session has no run left to release it, and the eight-hour
|
|
225
|
+
// expiry alone leaves a dirty tree held until a person acts.
|
|
226
|
+
function force_release(target: string): number {
|
|
227
|
+
const read = run_hold.read_hold(target)
|
|
228
|
+
|
|
229
|
+
if (read.kind === 'held' || read.kind === 'stale') {
|
|
230
|
+
console.error(run_hold.forced_release_message(read.hold))
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return remove_record(target, read.kind !== 'free')
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// A tree whose git directory cannot be read is `unknown` and exits non-zero, never `hold`: the guard
|
|
237
|
+
// has established nothing there, and a run that proceeds on it is the run this command exists to stop.
|
|
238
|
+
function report_unknown(): number {
|
|
239
|
+
return report(run_hold.unknown_message(), UNKNOWN_VERDICT, FAILURE_EXIT_CODE)
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function report_usage(): number {
|
|
243
|
+
console.error(USAGE)
|
|
244
|
+
|
|
245
|
+
return FAILURE_EXIT_CODE
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
async function read_worktree(): Promise<string | undefined> {
|
|
249
|
+
try {
|
|
250
|
+
return await run_hold.worktree_directory()
|
|
251
|
+
} catch {
|
|
252
|
+
return undefined
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
async function dispatch(request: HoldRequest, target: string, is_linked: boolean): Promise<number> {
|
|
257
|
+
if (request.kind === 'claim') return await claim(target, request.issue, is_linked)
|
|
258
|
+
|
|
259
|
+
if (request.kind === FORCE_RELEASE_KIND) return force_release(target)
|
|
260
|
+
|
|
261
|
+
return release(target, request.claimant)
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
async function answer(request: HoldRequest): Promise<number> {
|
|
265
|
+
const directory = await read_worktree()
|
|
266
|
+
|
|
267
|
+
if (directory === undefined) return report_unknown()
|
|
268
|
+
|
|
269
|
+
const is_linked = await run_hold.is_linked_worktree()
|
|
270
|
+
|
|
271
|
+
return await dispatch(request, run_hold.hold_path(directory), is_linked)
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// **Every path out of here prints exactly one token**, including the ones nobody planned: a permission
|
|
275
|
+
// error on the record, or a git binary that is not there, used to leave standard output empty — and an
|
|
276
|
+
// empty `$answer` matches none of the three tokens, which an entry point reads as "not busy" before
|
|
277
|
+
// walking straight past the guard.
|
|
278
|
+
async function run(argv: ReadonlyArray<string>): Promise<number> {
|
|
279
|
+
const request = parse_request(argv)
|
|
280
|
+
|
|
281
|
+
if (request === undefined) return report_usage()
|
|
282
|
+
|
|
283
|
+
try {
|
|
284
|
+
return await answer(request)
|
|
285
|
+
} catch {
|
|
286
|
+
return report_unknown()
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
async function main(argv: ReadonlyArray<string>): Promise<void> {
|
|
291
|
+
process.exitCode = await run(argv)
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
const run_hold_cli = {
|
|
295
|
+
BUSY_VERDICT,
|
|
296
|
+
HELD_VERDICT,
|
|
297
|
+
HOLD_VERDICT,
|
|
298
|
+
NONE_VERDICT,
|
|
299
|
+
RELEASED_VERDICT,
|
|
300
|
+
UNKNOWN_VERDICT,
|
|
301
|
+
USAGE,
|
|
302
|
+
blocking_message,
|
|
303
|
+
main,
|
|
304
|
+
parse_request,
|
|
305
|
+
run,
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
if (process.argv[1] === fileURLToPath(import.meta.url)) await main(process.argv.slice(ARGV_OFFSET))
|
|
309
|
+
|
|
310
|
+
export { run_hold_cli }
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
import { git_command } from '#scripts/git/git-command'
|
|
2
|
+
import { stamp_file } from '#scripts/josh/stamp-file'
|
|
3
|
+
import { z } from 'zod'
|
|
4
|
+
|
|
5
|
+
// joshuafolkken/kit#1091: `epicrun` asks `epic-busy.ts` whether a *repository* already has a child in
|
|
6
|
+
// flight, and the entry points a person types — `fullrun`, `halfrun`, `kickoff` — never reach that
|
|
7
|
+
// guard, because they do not go through `epic:next`. On 2026-08-30 two sessions therefore implemented
|
|
8
|
+
// two issues in one checkout at once, and the second was one command away from committing nine files
|
|
9
|
+
// onto the first one's branch.
|
|
10
|
+
//
|
|
11
|
+
// **The unit is the working tree, not the repository.** What these entries contend for is one branch,
|
|
12
|
+
// one index and one uncommitted diff; a linked work tree has its own three, so a second run there is
|
|
13
|
+
// legitimate and must not be stopped. Reusing `epic-busy.ts` here would stop it — that read answers
|
|
14
|
+
// about a repository, which is a different resource and a different question.
|
|
15
|
+
//
|
|
16
|
+
// The key is the work tree's own git directory: `git rev-parse --absolute-git-dir` answers `.git` in
|
|
17
|
+
// the main work tree and `.git/worktrees/<name>` in a linked one, so two work trees of one repository
|
|
18
|
+
// key differently while two commands in the same work tree key alike.
|
|
19
|
+
|
|
20
|
+
const HOLD_PREFIX = 'josh-run-hold-'
|
|
21
|
+
// The label a `new` entry point writes: the guard has to run *before* the issue is filed, or the
|
|
22
|
+
// stopped run leaves behind the very issue it should not have created.
|
|
23
|
+
const UNNUMBERED_ISSUE = 'new'
|
|
24
|
+
// Longer than any run — a measured `fullrun` is ten to fifty minutes — and short enough that a record
|
|
25
|
+
// abandoned by a crashed session is gone by the next working day. It is what keeps an abnormally
|
|
26
|
+
// ended run from holding the tree forever; a normally ended one is released by `josh followup`.
|
|
27
|
+
const HOLD_MAX_AGE_HOURS = 8
|
|
28
|
+
const MILLISECONDS_PER_HOUR = 3_600_000
|
|
29
|
+
const HOLD_MAX_AGE_MS = HOLD_MAX_AGE_HOURS * MILLISECONDS_PER_HOUR
|
|
30
|
+
|
|
31
|
+
const RELEASE_COMMAND = 'pnpm josh run:release'
|
|
32
|
+
// The spelling that removes a record this run did not write (joshuafolkken/kit#1799). **It is a
|
|
33
|
+
// separate spelling rather than the same one** because a stop message has to name something a person
|
|
34
|
+
// can type when a record really has been abandoned — and the one it named until now removed a *live*
|
|
35
|
+
// run's record just as readily, which is the incident this guard was written after, reached through
|
|
36
|
+
// the guard's own recovery instruction.
|
|
37
|
+
const FORCE_RELEASE_COMMAND = `${RELEASE_COMMAND} --force`
|
|
38
|
+
// The sentence `epic-busy.ts` prints for the same reason: a guard that cannot read its record has not
|
|
39
|
+
// established that the tree is free, and reporting it as free is the one failure that matters here.
|
|
40
|
+
const NOT_IDLE = 'that is not "nothing is running here"'
|
|
41
|
+
|
|
42
|
+
interface RunHold {
|
|
43
|
+
issue: string
|
|
44
|
+
taken_at: string
|
|
45
|
+
pid: number
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
type HoldRead =
|
|
49
|
+
| { kind: 'free' }
|
|
50
|
+
| { kind: 'held'; hold: RunHold }
|
|
51
|
+
| { kind: 'stale'; hold: RunHold }
|
|
52
|
+
| { kind: 'unreadable' }
|
|
53
|
+
|
|
54
|
+
const FREE_READ: HoldRead = { kind: 'free' }
|
|
55
|
+
const UNREADABLE_READ: HoldRead = { kind: 'unreadable' }
|
|
56
|
+
|
|
57
|
+
function hold_path(git_directory: string): string {
|
|
58
|
+
return stamp_file.stamp_path(HOLD_PREFIX, git_directory)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// The first of the two paths git prints is this work tree's own; the second is the common directory
|
|
62
|
+
// every work tree of the repository shares, which is exactly what must not be the key.
|
|
63
|
+
async function worktree_directory(): Promise<string | undefined> {
|
|
64
|
+
const directories = await git_command.git_directories()
|
|
65
|
+
|
|
66
|
+
return directories[0]
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// A linked work tree — a lane — reports its own git directory as the first path and the common
|
|
70
|
+
// directory every work tree of the repository shares as the second; the primary checkout reports one
|
|
71
|
+
// path for both. Comparing the two detects a lane without assuming the git directory is named `.git`:
|
|
72
|
+
// a `--separate-git-dir` clone or a bare repository defeats any `.git`-segment match
|
|
73
|
+
// (joshuafolkken/kit#1106).
|
|
74
|
+
async function is_linked_worktree(): Promise<boolean> {
|
|
75
|
+
const directories = await git_command.git_directories()
|
|
76
|
+
|
|
77
|
+
return directories[0] !== undefined && directories[0] !== directories[1]
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const run_hold_schema = z.object({
|
|
81
|
+
issue: z.string(),
|
|
82
|
+
taken_at: z.string(),
|
|
83
|
+
pid: z.number(),
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
// `undefined` for anything that is not a well-formed record, so the caller decides what a broken one
|
|
87
|
+
// means. It means blocked, not free — see `classify`.
|
|
88
|
+
function parse_hold(raw: string): RunHold | undefined {
|
|
89
|
+
try {
|
|
90
|
+
const parsed = run_hold_schema.safeParse(JSON.parse(raw))
|
|
91
|
+
|
|
92
|
+
return parsed.success ? parsed.data : undefined
|
|
93
|
+
} catch {
|
|
94
|
+
return undefined
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// **A `taken_at` that is not a date is stale, not current.** It passes the schema — it is a string —
|
|
99
|
+
// so reading it as current would leave the tree held with nothing left to expire it, which is the one
|
|
100
|
+
// state the expiry exists to make impossible. Fail-closed is still the answer for the *tree*: a stale
|
|
101
|
+
// record only lets a claim through once `run-hold-cli.ts`'s `blocking_message` has also found the
|
|
102
|
+
// tree clean.
|
|
103
|
+
function is_stale(hold: RunHold, now: Date): boolean {
|
|
104
|
+
const taken = Date.parse(hold.taken_at)
|
|
105
|
+
|
|
106
|
+
if (Number.isNaN(taken)) return true
|
|
107
|
+
|
|
108
|
+
return now.getTime() - taken > HOLD_MAX_AGE_MS
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// **A record that cannot be read is `unreadable`, never `free`.** Absent is free; present and
|
|
112
|
+
// unparseable is the state a guard must not fall open on, because the run that wrote it is the one
|
|
113
|
+
// whose uncommitted work would be trampled.
|
|
114
|
+
function classify(raw: string | undefined, now: Date): HoldRead {
|
|
115
|
+
if (raw === undefined) return FREE_READ
|
|
116
|
+
|
|
117
|
+
const hold = parse_hold(raw)
|
|
118
|
+
|
|
119
|
+
if (hold === undefined) return UNREADABLE_READ
|
|
120
|
+
|
|
121
|
+
return { kind: is_stale(hold, now) ? 'stale' : 'held', hold }
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function read_hold(target: string, now: Date = new Date()): HoldRead {
|
|
125
|
+
return classify(stamp_file.read_stamp_text(target), now)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function build_hold(issue: string, now: Date): RunHold {
|
|
129
|
+
return { issue, taken_at: now.toISOString(), pid: process.pid }
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function write_hold(target: string, issue: string, now: Date = new Date()): RunHold {
|
|
133
|
+
const hold = build_hold(issue, now)
|
|
134
|
+
|
|
135
|
+
stamp_file.write_stamp(target, hold)
|
|
136
|
+
|
|
137
|
+
return hold
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// The claim on a tree that read as free. **Exclusive rather than a plain write**: two sessions typing
|
|
141
|
+
// an entry point in the same second both read `free`, and a write would tell both of them they won —
|
|
142
|
+
// which is the incident this guard was written after, reproduced by the guard itself. `false` means
|
|
143
|
+
// the other one got there first.
|
|
144
|
+
function create_hold(target: string, issue: string, now: Date = new Date()): boolean {
|
|
145
|
+
return stamp_file.create_stamp(target, build_hold(issue, now))
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// **A tree with uncommitted work in it is never handed over, however old its record is.** No age can
|
|
149
|
+
// be chosen that covers a `halfrun` stop or a `needs-human-review` stop: those are held across a
|
|
150
|
+
// person's latency rather than a run's, and the thing that must not be trampled is sitting in the
|
|
151
|
+
// tree where anyone can see it. An unreadable status is dirty, for the reason every other unreadable
|
|
152
|
+
// state here blocks.
|
|
153
|
+
async function is_tree_dirty(): Promise<boolean> {
|
|
154
|
+
try {
|
|
155
|
+
const status = await git_command.status()
|
|
156
|
+
|
|
157
|
+
return status.trim() !== ''
|
|
158
|
+
} catch {
|
|
159
|
+
return true
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function release_hold(target: string): void {
|
|
164
|
+
stamp_file.remove_stamp(target)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// The pid is recorded for the person reading the stop message, never as the liveness test: the process
|
|
168
|
+
// that claims the tree is a short-lived `josh run:hold`, so it has exited by the time anything reads
|
|
169
|
+
// the record back. Age is what expires a record; `pnpm josh run:release --force` is what clears
|
|
170
|
+
// somebody else's early, and `pnpm josh run:release <N>` what the run that wrote it types.
|
|
171
|
+
function describe_holder(hold: RunHold): string {
|
|
172
|
+
const holder = hold.issue === UNNUMBERED_ISSUE ? 'an unnumbered run' : `#${hold.issue}`
|
|
173
|
+
|
|
174
|
+
return `${holder}, recorded ${hold.taken_at} (pid ${String(hold.pid)})`
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// The command the run that *wrote* a record types to remove it — the claim's own spelling, mirrored,
|
|
178
|
+
// so that releasing names the run exactly as claiming did.
|
|
179
|
+
function own_release_command(issue: string): string {
|
|
180
|
+
return issue === UNNUMBERED_ISSUE ? RELEASE_COMMAND : `${RELEASE_COMMAND} ${issue}`
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// The whole of the ownership test, and it is the issue rather than the pid: the process that claims a
|
|
184
|
+
// tree is a short-lived `josh run:hold` that has exited before anything reads the record back, while
|
|
185
|
+
// the issue is what identifies a run across every command it issues. `run-carry.ts` compares a
|
|
186
|
+
// recorded owner against a declared one for the same reason; what differs is only who the owner is.
|
|
187
|
+
function is_own_hold(hold: RunHold, claimant: string): boolean {
|
|
188
|
+
return hold.issue === claimant
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function held_message(hold: RunHold): string {
|
|
192
|
+
return `This working tree is already held by ${describe_holder(hold)}. One run at a time per working tree: a second run here commits its files onto the other run's branch. If that record is stale, run \`${FORCE_RELEASE_COMMAND}\` in this working tree — it removes a record this run did not write, so be sure the run that did has ended — and ask again.`
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// **A release asked by anything but the record's own run removes nothing.** "Stale" is a judgement
|
|
196
|
+
// made from outside the run that wrote the record, and the one place it is made is a person reading a
|
|
197
|
+
// `busy` stop — so the refusal names both ways forward rather than only refusing.
|
|
198
|
+
function foreign_release_message(hold: RunHold): string {
|
|
199
|
+
return `This working tree is held by ${describe_holder(hold)}, and this release did not claim it — nothing was removed. Release it as that run with \`${own_release_command(hold.issue)}\`, or, once you are sure it has ended, remove the record with \`${FORCE_RELEASE_COMMAND}\`.`
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function forced_release_message(hold: RunHold): string {
|
|
203
|
+
return `Forced: removed the run record held by ${describe_holder(hold)}.`
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function unreadable_message(): string {
|
|
207
|
+
return `This working tree's run record could not be read — ${NOT_IDLE}. Run \`${FORCE_RELEASE_COMMAND}\` in this working tree to clear it, then ask again.`
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function stale_message(hold: RunHold): string {
|
|
211
|
+
return `Replaced a stale run record held by ${describe_holder(hold)}: older than ${String(HOLD_MAX_AGE_HOURS)} hours, so the run that wrote it has ended without releasing it.`
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function uncommitted_message(hold: RunHold): string {
|
|
215
|
+
return `This working tree still has uncommitted changes, and its run record — held by ${describe_holder(hold)} — has expired. That is a run which stopped for a person rather than one that finished, so the tree is not free: commit or stash the work, or run \`${own_release_command(hold.issue)}\` once you are done with it, then ask again.`
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// The exclusive claim lost: another process wrote the record between this one's read and its write.
|
|
219
|
+
// Re-reading names the winner where it still holds; where it does not, the record is one this account
|
|
220
|
+
// cannot read — a file another user owns on a shared temp directory — and the answer is still `busy`,
|
|
221
|
+
// because this run did not get the tree. **The path is named** so the person is not sent round a loop
|
|
222
|
+
// of "ask again" that can never come out differently: `run:release` cannot remove a file it does not
|
|
223
|
+
// own either.
|
|
224
|
+
function race_message(read: HoldRead, target: string): string {
|
|
225
|
+
if (read.kind === 'held') return held_message(read.hold)
|
|
226
|
+
|
|
227
|
+
return `A record already exists at ${target} and this run did not write it — ${NOT_IDLE}. Either another run claimed the tree at the same moment, or the record belongs to another account. Run \`${FORCE_RELEASE_COMMAND}\`, and remove that file by hand if it is still there.`
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function unknown_message(): string {
|
|
231
|
+
return `Could not read this working tree's git directory — ${NOT_IDLE}. Run this from inside the checkout the run will edit.`
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const run_hold = {
|
|
235
|
+
FORCE_RELEASE_COMMAND,
|
|
236
|
+
HOLD_MAX_AGE_HOURS,
|
|
237
|
+
HOLD_MAX_AGE_MS,
|
|
238
|
+
RELEASE_COMMAND,
|
|
239
|
+
UNNUMBERED_ISSUE,
|
|
240
|
+
classify,
|
|
241
|
+
create_hold,
|
|
242
|
+
describe_holder,
|
|
243
|
+
foreign_release_message,
|
|
244
|
+
forced_release_message,
|
|
245
|
+
held_message,
|
|
246
|
+
hold_path,
|
|
247
|
+
is_linked_worktree,
|
|
248
|
+
is_own_hold,
|
|
249
|
+
is_tree_dirty,
|
|
250
|
+
own_release_command,
|
|
251
|
+
parse_hold,
|
|
252
|
+
race_message,
|
|
253
|
+
read_hold,
|
|
254
|
+
release_hold,
|
|
255
|
+
stale_message,
|
|
256
|
+
uncommitted_message,
|
|
257
|
+
unknown_message,
|
|
258
|
+
unreadable_message,
|
|
259
|
+
worktree_directory,
|
|
260
|
+
write_hold,
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
export type { HoldRead, RunHold }
|
|
264
|
+
export { run_hold }
|