@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,320 @@
|
|
|
1
|
+
import { git_utilities } from '#scripts/git/constants'
|
|
2
|
+
import { stamp_file } from '#scripts/josh/stamp-file'
|
|
3
|
+
import { execaSync } from 'execa'
|
|
4
|
+
import { z } from 'zod'
|
|
5
|
+
|
|
6
|
+
// The report clock `josh run:progress` keeps, in the one form both of its readers can use
|
|
7
|
+
// (joshuafolkken/kit#1570).
|
|
8
|
+
//
|
|
9
|
+
// **It exists because a second reader arrived, and that one cannot await.** The watcher reads the
|
|
10
|
+
// record between ticks, where an `async` call costs nothing; the trigger-delivered rule that refuses
|
|
11
|
+
// an early heartbeat (`scripts/rules/early-heartbeat.ts`) reads it inside a `PreToolUse` hook, whose
|
|
12
|
+
// decision is synchronous from payload to envelope. Copying the record's shape into the hook would be
|
|
13
|
+
// the clone `CLAUDE.md` prohibits, in the one place where two copies disagreeing means the guard
|
|
14
|
+
// silently guards nothing — so the record lives here and each reader brings its own way of naming the
|
|
15
|
+
// work tree.
|
|
16
|
+
//
|
|
17
|
+
// **The key is the work tree's own git directory**, the way `run_hold` keys its record: two lanes of
|
|
18
|
+
// one repository are two runs, and one lane's report must not silence the other's clock. The
|
|
19
|
+
// synchronous twin asks `git rev-parse --absolute-git-dir`, which is the first of the two lines
|
|
20
|
+
// `git_command.git_directories` reads and the one the asynchronous path already takes — so the two
|
|
21
|
+
// spellings cannot name different files.
|
|
22
|
+
|
|
23
|
+
const PROGRESS_PREFIX = 'josh-run-progress-'
|
|
24
|
+
// The watcher's own liveness record, kept apart from the report clock above: that one says *when* the
|
|
25
|
+
// run last reported and is written on every heartbeat, so it can never double as "should this watcher
|
|
26
|
+
// still be running". This one is presence-only — the watcher writes it once when it begins, reads it
|
|
27
|
+
// every tick, and ends the moment it is gone, which is how `josh followup` stops a watcher at the
|
|
28
|
+
// merge instead of leaving it to wait out its whole bound (joshuafolkken/kit#1821). It reuses the same
|
|
29
|
+
// key as the report clock — the work tree's own git directory — so both name one file per run.
|
|
30
|
+
//
|
|
31
|
+
// **The loop that reads its own record and exits when it is gone is `run-wake-loop.ts`'s `run_loop`
|
|
32
|
+
// pattern (joshuafolkken/kit#1727), and the read/write is `stamp_file`.** Neither is re-implemented
|
|
33
|
+
// here: this module only names the record, exactly as it names the report clock. Unlike `run-hold`'s
|
|
34
|
+
// and `run-carry`'s records it needs no expiry, because it is read only by the one watcher that wrote
|
|
35
|
+
// it — never by another run deciding whether a resource is free — so a fresh watcher always overwrites
|
|
36
|
+
// a stale one and there is no cross-run read to fall open.
|
|
37
|
+
const LIFE_PREFIX = 'josh-run-progress-life-'
|
|
38
|
+
// **The ambient surface the heartbeat keeps across a session cut** (joshuafolkken/kit#2156). The report
|
|
39
|
+
// clock holds only the *last* line, which `josh run:wake --list` relays on demand — a person has to
|
|
40
|
+
// type for it, so after a cut the heartbeat sits at the *requested* tier. This log mirrors every
|
|
41
|
+
// heartbeat line into a plain-text file beside the clock, so a person who keeps `tail -F` open on it
|
|
42
|
+
// sees the run's progress without asking again: the *ambient* tier the terminal held before the cut,
|
|
43
|
+
// kept across it. It is a sibling of the clock (`<clock>.log`) so both name one file per work tree, and
|
|
44
|
+
// `.log` rather than `.json` because it holds the lines verbatim for a reader — the `stamp_path`
|
|
45
|
+
// distinction the wake log already draws.
|
|
46
|
+
const LOG_SUFFIX = '.log'
|
|
47
|
+
// A few hours of heartbeats at the twenty-minute interval — enough to read the run's recent shape, and
|
|
48
|
+
// bounded so an unattended run cannot grow the file without limit.
|
|
49
|
+
const LOG_KEEP = 12
|
|
50
|
+
const MS_PER_MINUTE = 60_000
|
|
51
|
+
// Longer than any heartbeat interval and shorter than any gap between two runs. Heartbeats land at most
|
|
52
|
+
// one interval apart while a run is live (twenty minutes by default, well under this), so a newest block
|
|
53
|
+
// older than this belongs to a previous run: past it the log is reset rather than extended, and a fresh
|
|
54
|
+
// run never opens on stale lines.
|
|
55
|
+
const LOG_STALE_MINUTES = 90
|
|
56
|
+
const LOG_STALE_MS = LOG_STALE_MINUTES * MS_PER_MINUTE
|
|
57
|
+
const BLOCK_SEPARATOR = '\n\n'
|
|
58
|
+
// The lookup only ever decides whether a rule speaks, so a git call that hangs must not hold the hook
|
|
59
|
+
// that is holding the user's call. A timeout answers `undefined`, which reads as "no clock here" and
|
|
60
|
+
// lets the call through — the direction every other failure in this path already takes.
|
|
61
|
+
const GIT_TIMEOUT_MS = 5000
|
|
62
|
+
// The first of the two lines `git_command.git_directories` reads, asked on its own because that is the
|
|
63
|
+
// one the record is keyed on. Asking git rather than assuming a directory named `.git` is what makes a
|
|
64
|
+
// linked work tree, a bare repository and a `--separate-git-dir` clone all answer correctly.
|
|
65
|
+
const GIT_DIRECTORY_ARGUMENTS: ReadonlyArray<string> = ['rev-parse', '--absolute-git-dir']
|
|
66
|
+
|
|
67
|
+
// `line` is the last heartbeat the watcher printed, kept verbatim beside the clock so a reader that
|
|
68
|
+
// cannot see the watcher's transcript — a person checking a woken headless `backlogrun` through
|
|
69
|
+
// `josh run:wake --list` — still reads the exact line it emitted (joshuafolkken/kit#1910). It is
|
|
70
|
+
// optional because a bare `--mark` moves the clock without producing one, and because a record written
|
|
71
|
+
// before this field existed carries only `reported_at`.
|
|
72
|
+
const report_stamp_schema = z.object({ reported_at: z.string(), line: z.string().optional() })
|
|
73
|
+
|
|
74
|
+
function parse_stamp(raw: string): number | undefined {
|
|
75
|
+
const parsed = report_stamp_schema.safeParse(JSON.parse(raw))
|
|
76
|
+
|
|
77
|
+
if (!parsed.success) return undefined
|
|
78
|
+
|
|
79
|
+
const reported_at = Date.parse(parsed.data.reported_at)
|
|
80
|
+
|
|
81
|
+
return Number.isNaN(reported_at) ? undefined : reported_at
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* The last heartbeat line the watcher persisted, or `undefined` for an absent, unparsable, or
|
|
86
|
+
* pre-`line` record. This is what `josh run:wake --list` relays to a person who is no longer the parent
|
|
87
|
+
* session — the headless parent woken after a cut prints its progress only to its own transcript, and
|
|
88
|
+
* this record is the one place that line survives (joshuafolkken/kit#1910).
|
|
89
|
+
*/
|
|
90
|
+
function read_last_line(target: string): string | undefined {
|
|
91
|
+
const raw = stamp_file.read_stamp_text(target)
|
|
92
|
+
|
|
93
|
+
if (raw === undefined) return undefined
|
|
94
|
+
|
|
95
|
+
try {
|
|
96
|
+
return report_stamp_schema.safeParse(JSON.parse(raw)).data?.line
|
|
97
|
+
} catch {
|
|
98
|
+
return undefined
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* When the run last reported anything — a real report through `--mark`, or a line the watcher printed.
|
|
104
|
+
*
|
|
105
|
+
* `undefined` for every unreadable shape. The watcher falls back to the moment it started watching;
|
|
106
|
+
* the guard reads it as "this run has no progress clock" and refuses nothing, which is what keeps an
|
|
107
|
+
* ordinary conversational session outside a rule written for unattended runs.
|
|
108
|
+
*/
|
|
109
|
+
function read_last_report(target: string): number | undefined {
|
|
110
|
+
const raw = stamp_file.read_stamp_text(target)
|
|
111
|
+
|
|
112
|
+
if (raw === undefined) return undefined
|
|
113
|
+
|
|
114
|
+
try {
|
|
115
|
+
return parse_stamp(raw)
|
|
116
|
+
} catch {
|
|
117
|
+
return undefined
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// The ambient log's path, a sibling of the report clock so one directory names both and the CLI can
|
|
122
|
+
// derive it from the clock target alone (joshuafolkken/kit#2156).
|
|
123
|
+
function log_path_of(target: string): string {
|
|
124
|
+
return `${target}${LOG_SUFFIX}`
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// **Staleness is read from the report clock's own last timestamp, not the log file's mtime**
|
|
128
|
+
// (joshuafolkken/kit#2156). The clock's `reported_at` is the run's own clock — a copy or a backup can
|
|
129
|
+
// move a file's mtime, and a fresh run whose first heartbeat found a previous run's log would then
|
|
130
|
+
// append to it. It is read before `mark` overwrites the clock, so it sees the *previous* report.
|
|
131
|
+
function is_log_stale(target: string, now_ms: number): boolean {
|
|
132
|
+
const previous_ms = read_last_report(target)
|
|
133
|
+
|
|
134
|
+
return previous_ms === undefined || now_ms - previous_ms > LOG_STALE_MS
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// The blocks already in the log, or none when it is absent or a previous run's. `read_stamp_text` is
|
|
138
|
+
// the symlink-safe read the clock itself uses, so a planted file reads as no record rather than being
|
|
139
|
+
// trusted.
|
|
140
|
+
function recent_blocks(log_target: string, is_fresh: boolean): ReadonlyArray<string> {
|
|
141
|
+
if (is_fresh) return []
|
|
142
|
+
|
|
143
|
+
const raw = stamp_file.read_stamp_text(log_target)
|
|
144
|
+
|
|
145
|
+
if (raw === undefined) return []
|
|
146
|
+
|
|
147
|
+
// `trimEnd` per block so the file's trailing newline, glued to the last block by the split, does not
|
|
148
|
+
// re-join into a `\n\n\n` gap that grows the reader's ambient surface a blank line at a time.
|
|
149
|
+
return raw
|
|
150
|
+
.split(BLOCK_SEPARATOR)
|
|
151
|
+
.map((block) => block.trimEnd())
|
|
152
|
+
.filter((block) => block.length > 0)
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// One heartbeat mirrored into the ambient log, newest last, the oldest rolled off past `LOG_KEEP`. A
|
|
156
|
+
// fresh run — or a stale log — starts the file over. `write_text_stamp` unlinks then creates
|
|
157
|
+
// exclusively, so the write is symlink-safe and `tail -F` re-reads it cleanly after each replacement.
|
|
158
|
+
function append_line(
|
|
159
|
+
log_target: string,
|
|
160
|
+
reported_at: string,
|
|
161
|
+
line: string,
|
|
162
|
+
is_fresh: boolean,
|
|
163
|
+
): void {
|
|
164
|
+
const block = `${reported_at}\n${line}`
|
|
165
|
+
const blocks = [...recent_blocks(log_target, is_fresh), block].slice(-LOG_KEEP)
|
|
166
|
+
|
|
167
|
+
stamp_file.write_text_stamp(log_target, `${blocks.join(BLOCK_SEPARATOR)}\n`)
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// A heartbeat carries its line; a bare `--mark` (a real report resetting the clock) carries none and
|
|
171
|
+
// **preserves the line already there** rather than blanking it — so `josh run:wake --list` keeps
|
|
172
|
+
// showing the most recent heartbeat between a run's real reports rather than going empty on every one
|
|
173
|
+
// (joshuafolkken/kit#1910). A carried line is also mirrored into the ambient log — the surface a person
|
|
174
|
+
// keeps open across a cut — before the clock is overwritten, so staleness sees the previous report
|
|
175
|
+
// (joshuafolkken/kit#2156).
|
|
176
|
+
function mark(target: string, now_ms: number, line?: string): void {
|
|
177
|
+
const reported_at = new Date(now_ms).toISOString()
|
|
178
|
+
const kept = line ?? read_last_line(target)
|
|
179
|
+
|
|
180
|
+
if (line !== undefined) {
|
|
181
|
+
append_line(log_path_of(target), reported_at, line, is_log_stale(target, now_ms))
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
stamp_file.write_stamp(target, kept === undefined ? { reported_at } : { reported_at, line: kept })
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// `undefined` is passed straight through so `stamp_file`'s own default root stands, which is what the
|
|
188
|
+
// caller got before this function existed. Hashing an empty string instead would key the record on a
|
|
189
|
+
// path no other code path produces.
|
|
190
|
+
function stamp_target_of(git_directory: string | undefined): string {
|
|
191
|
+
return stamp_file.stamp_path(PROGRESS_PREFIX, git_directory)
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// The liveness record's path, keyed the same way as the report clock so the watcher and `josh followup`
|
|
195
|
+
// name one file per work tree. A different prefix keeps it a separate file: removing it must not
|
|
196
|
+
// disturb the report clock the early-heartbeat guard reads.
|
|
197
|
+
function life_target_of(git_directory: string | undefined): string {
|
|
198
|
+
return stamp_file.stamp_path(LIFE_PREFIX, git_directory)
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// **`pinged_at` is written by every tick and checked by `is_life_fresh`.** Without it the life record
|
|
202
|
+
// is presence-only — existence is the only signal, and a record from a watcher that stopped an hour
|
|
203
|
+
// ago is indistinguishable from one whose watcher is live. Adding `pinged_at` to the payload lets a
|
|
204
|
+
// guard detect "children in-flight but watcher stale" without a second file (joshuafolkken/kit#2113).
|
|
205
|
+
// Old records carrying only `{ alive: true }` parse successfully; `pinged_at` is optional on read,
|
|
206
|
+
// which is what makes this backward-compatible.
|
|
207
|
+
const life_schema = z.object({ alive: z.literal(true), pinged_at: z.string().optional() })
|
|
208
|
+
|
|
209
|
+
// The watcher declares itself alive. `write_stamp` unlinks first, so a fresh `--wait` cleanly replaces
|
|
210
|
+
// a record an earlier one left behind.
|
|
211
|
+
function begin_life(target: string): void {
|
|
212
|
+
stamp_file.write_stamp(target, { alive: true, pinged_at: new Date().toISOString() })
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Refreshes the `pinged_at` timestamp without disturbing the liveness semantics. Called on every
|
|
216
|
+
// watch tick so the record's age is a proxy for "watcher is running".
|
|
217
|
+
function ping_life(target: string): void {
|
|
218
|
+
begin_life(target)
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function parse_pinged_at(raw: string): number | undefined {
|
|
222
|
+
const parsed = life_schema.safeParse(JSON.parse(raw))
|
|
223
|
+
|
|
224
|
+
if (!parsed.success || parsed.data.pinged_at === undefined) return undefined
|
|
225
|
+
|
|
226
|
+
const pinged_ms = Date.parse(parsed.data.pinged_at)
|
|
227
|
+
|
|
228
|
+
return Number.isNaN(pinged_ms) ? undefined : pinged_ms
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Returns `false` for any absent, unreadable or un-timestamped record — both "no watcher" and "old
|
|
232
|
+
// watcher that predates joshuafolkken/kit#2113" produce `false`, which is the safe direction for a
|
|
233
|
+
// guard: it speaks up rather than staying silent.
|
|
234
|
+
function is_life_fresh(target: string, threshold_ms: number): boolean {
|
|
235
|
+
const raw = stamp_file.read_stamp_text(target)
|
|
236
|
+
|
|
237
|
+
if (raw === undefined) return false
|
|
238
|
+
|
|
239
|
+
try {
|
|
240
|
+
const pinged_ms = parse_pinged_at(raw)
|
|
241
|
+
|
|
242
|
+
return pinged_ms !== undefined && Date.now() - pinged_ms < threshold_ms
|
|
243
|
+
} catch {
|
|
244
|
+
return false
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// **Gone means ended.** `read_stamp_text` answers `undefined` for an absent or unowned record, and the
|
|
249
|
+
// only writer is the watcher itself, so absence means `josh followup` removed it — or nobody began
|
|
250
|
+
// one. Either way the watcher stops, which is the fail-quiet direction: a watcher that kept running on
|
|
251
|
+
// a missing record would be the lingering process joshuafolkken/kit#1821 exists to end.
|
|
252
|
+
function is_life_ended(target: string): boolean {
|
|
253
|
+
return stamp_file.read_stamp_text(target) === undefined
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// What `josh followup` calls at the merge seam, and what the watcher calls when its own bound ends.
|
|
257
|
+
// Removing an absent record is a no-op, so it is safe on either side.
|
|
258
|
+
function end_life(target: string): void {
|
|
259
|
+
stamp_file.remove_stamp(target)
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// execa runs the binary directly with an argument array and no `shell` option, so CLI args cannot
|
|
263
|
+
// break out of a shell sandbox; the git command and args are internally controlled, never untrusted
|
|
264
|
+
// input. tssecurity:S8705 is a false positive here.
|
|
265
|
+
function git_directory_sync(): string | undefined {
|
|
266
|
+
const git_binary = git_utilities.get_git_command_for_spawn()
|
|
267
|
+
const result = execaSync(git_binary, GIT_DIRECTORY_ARGUMENTS, {
|
|
268
|
+
reject: false,
|
|
269
|
+
timeout: GIT_TIMEOUT_MS,
|
|
270
|
+
}) // NOSONAR
|
|
271
|
+
|
|
272
|
+
if (result.exitCode !== 0) return undefined
|
|
273
|
+
|
|
274
|
+
const output = result.stdout.trim()
|
|
275
|
+
|
|
276
|
+
return output === '' ? undefined : output
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function stamp_target_sync(): string | undefined {
|
|
280
|
+
const directory = git_directory_sync()
|
|
281
|
+
|
|
282
|
+
return directory === undefined ? undefined : stamp_target_of(directory)
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* The clock, read from a place that cannot await — the whole reason this module is separate.
|
|
287
|
+
*
|
|
288
|
+
* It answers about the work tree the caller is standing in. A watcher started in another repository's
|
|
289
|
+
* checkout keeps its record there, so a hook running in the session's own tree finds none and the rule
|
|
290
|
+
* stays silent rather than guessing; that is the same limit `backlogrun.md` records for `--mark`.
|
|
291
|
+
*/
|
|
292
|
+
function read_last_report_sync(): number | undefined {
|
|
293
|
+
const target = stamp_target_sync()
|
|
294
|
+
|
|
295
|
+
return target === undefined ? undefined : read_last_report(target)
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
const run_progress_clock = {
|
|
299
|
+
LIFE_PREFIX,
|
|
300
|
+
LOG_KEEP,
|
|
301
|
+
LOG_STALE_MS,
|
|
302
|
+
PROGRESS_PREFIX,
|
|
303
|
+
append_line,
|
|
304
|
+
begin_life,
|
|
305
|
+
end_life,
|
|
306
|
+
is_life_ended,
|
|
307
|
+
is_life_fresh,
|
|
308
|
+
life_target_of,
|
|
309
|
+
log_path_of,
|
|
310
|
+
mark,
|
|
311
|
+
parse_stamp,
|
|
312
|
+
ping_life,
|
|
313
|
+
read_last_line,
|
|
314
|
+
read_last_report,
|
|
315
|
+
read_last_report_sync,
|
|
316
|
+
stamp_target_of,
|
|
317
|
+
stamp_target_sync,
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
export { run_progress_clock }
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
import { z } from 'zod'
|
|
4
|
+
import { run_progress } from './run-progress'
|
|
5
|
+
|
|
6
|
+
// Where the silence interval comes from, and in what order (joshuafolkken/kit#1576).
|
|
7
|
+
//
|
|
8
|
+
// **The setting existed and could not leave the machine.** `JOSH_PROGRESS_INTERVAL_MINUTES` is read
|
|
9
|
+
// from `.env`, which is deliberately never committed — so a person who set fifteen minutes here got
|
|
10
|
+
// twenty on every other machine and in every cloud session, and the guard that enforces the floor got
|
|
11
|
+
// twenty with them. Reporting still happened there, at a cadence nobody asked for.
|
|
12
|
+
//
|
|
13
|
+
// **So the repository carries one of its own.** `josh.progress_interval_minutes` in `package.json` is
|
|
14
|
+
// committed, is per repository rather than per toolkit, and is read through the same reader both
|
|
15
|
+
// halves of the mechanism already share — the watcher before it prints, and the `early-heartbeat` row
|
|
16
|
+
// before it allows an arm. A guard that could disagree with the watcher it guards is worse than no
|
|
17
|
+
// guard, so there is one order and both sides ask for it here.
|
|
18
|
+
//
|
|
19
|
+
// **The environment still outranks the file**, because a person's own machine is allowed to differ
|
|
20
|
+
// from what the repository asks for, and `--interval` outranks both for the watcher alone — a hook has
|
|
21
|
+
// no command line to read.
|
|
22
|
+
//
|
|
23
|
+
// **The nearest declaring `package.json` wins, searched upward.** The two callers do not stand in the
|
|
24
|
+
// same directory — `pnpm` runs a script from the package root and Claude Code runs a hook from the
|
|
25
|
+
// project root — and in a workspace those are different files, only one of which declares a cadence.
|
|
26
|
+
// Reading the working directory alone would let the guard enforce the repository's interval while the
|
|
27
|
+
// watcher it guards kept the default, which is the one state this module exists to prevent.
|
|
28
|
+
|
|
29
|
+
const PACKAGE_FILE = 'package.json'
|
|
30
|
+
const CONFIG_FIELD = 'josh'
|
|
31
|
+
const INTERVAL_FIELD = 'progress_interval_minutes'
|
|
32
|
+
|
|
33
|
+
// Deep enough to cross a workspace package and its root, and bounded so a path that never reaches a
|
|
34
|
+
// root — a broken mount, a mocked `dirname` — cannot spin.
|
|
35
|
+
const MAX_DEPTH = 10
|
|
36
|
+
|
|
37
|
+
// Unknown keys are stripped rather than rejected: this reads a whole `package.json`, and every other
|
|
38
|
+
// field in it is none of this module's business. A present-but-unusable interval fails the parse and
|
|
39
|
+
// falls through, which is the same answer an unusable environment variable already gets.
|
|
40
|
+
const package_schema = z.object({
|
|
41
|
+
josh: z.object({ progress_interval_minutes: z.number().positive() }).optional(),
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
function ancestors_of(start: string): ReadonlyArray<string> {
|
|
45
|
+
const directories: Array<string> = []
|
|
46
|
+
let current = path.resolve(start)
|
|
47
|
+
|
|
48
|
+
while (directories.length < MAX_DEPTH && !directories.includes(current)) {
|
|
49
|
+
directories.push(current)
|
|
50
|
+
current = path.dirname(current)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return directories
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function read_declared_minutes(directory: string): number | undefined {
|
|
57
|
+
try {
|
|
58
|
+
const raw = readFileSync(path.join(directory, PACKAGE_FILE), 'utf8')
|
|
59
|
+
const parsed = package_schema.safeParse(JSON.parse(raw))
|
|
60
|
+
|
|
61
|
+
return parsed.success ? parsed.data.josh?.progress_interval_minutes : undefined
|
|
62
|
+
} catch {
|
|
63
|
+
return undefined
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function read_package_minutes(start: string): number | undefined {
|
|
68
|
+
for (const directory of ancestors_of(start)) {
|
|
69
|
+
const minutes = read_declared_minutes(directory)
|
|
70
|
+
|
|
71
|
+
if (minutes !== undefined) return minutes
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return undefined
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function to_ms(minutes: number | undefined): number | undefined {
|
|
78
|
+
return minutes === undefined ? undefined : minutes * run_progress.MS_PER_MINUTE
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* The interval in force: a hand-typed value, then the environment, then the repository, then twenty.
|
|
83
|
+
*
|
|
84
|
+
* Each step answers `undefined` for anything that is not a positive number, so an unusable value falls
|
|
85
|
+
* through to the next source rather than throwing — this runs unattended, and dying on a typo in an
|
|
86
|
+
* optional setting removes the reporting the setting was there to tune.
|
|
87
|
+
*/
|
|
88
|
+
function resolve_interval_ms(raw: string | undefined, directory: string = process.cwd()): number {
|
|
89
|
+
return (
|
|
90
|
+
to_ms(run_progress.minutes_from(raw)) ??
|
|
91
|
+
to_ms(run_progress.minutes_from(process.env[run_progress.INTERVAL_KEY])) ??
|
|
92
|
+
to_ms(read_package_minutes(directory)) ??
|
|
93
|
+
run_progress.DEFAULT_INTERVAL_MS
|
|
94
|
+
)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* The **floor** the guard enforces — the same order with no command line in it.
|
|
99
|
+
*
|
|
100
|
+
* It is deliberately not the watcher's effective interval: the watcher takes `--interval` on top, and
|
|
101
|
+
* a hook has no flag to read. A `--interval` above the floor makes the watcher quieter than the guard
|
|
102
|
+
* requires, which is the harmless direction; below it, the watcher prints more often than the guard
|
|
103
|
+
* would let a run arm a timer for — so a run that wants a different cadence sets the environment
|
|
104
|
+
* variable or the committed field, which both sides read.
|
|
105
|
+
*/
|
|
106
|
+
function configured_interval_ms(directory: string = process.cwd()): number {
|
|
107
|
+
return resolve_interval_ms(undefined, directory)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const run_progress_config = {
|
|
111
|
+
CONFIG_FIELD,
|
|
112
|
+
INTERVAL_FIELD,
|
|
113
|
+
PACKAGE_FILE,
|
|
114
|
+
configured_interval_ms,
|
|
115
|
+
read_package_minutes,
|
|
116
|
+
resolve_interval_ms,
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export { run_progress_config }
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { loadavg } from 'node:os'
|
|
2
|
+
import { epic_busy } from '#scripts/epic/epic-busy'
|
|
3
|
+
import { git_command } from '#scripts/git/git-command'
|
|
4
|
+
import type { OpenIssueData } from '#scripts/git/schemas'
|
|
5
|
+
import { lane_registry } from '#scripts/lane/lane-registry'
|
|
6
|
+
import { lane_report } from '#scripts/lane/lane-report'
|
|
7
|
+
import { run_carry, type CarryRead } from './run-carry'
|
|
8
|
+
import { run_hold, type HoldRead } from './run-hold'
|
|
9
|
+
import { run_liveness } from './run-liveness'
|
|
10
|
+
import { run_preflight } from './run-preflight'
|
|
11
|
+
import type { ChildObservation, LaneObservation, Observations } from './run-progress'
|
|
12
|
+
import { run_progress_clock } from './run-progress-clock'
|
|
13
|
+
|
|
14
|
+
// Everything `josh run:progress` reads: the last-report record that makes the clock a silence clock,
|
|
15
|
+
// and the observations one tick puts on the line (joshuafolkken/kit#1520).
|
|
16
|
+
//
|
|
17
|
+
// **Every reader here is one that already exists.** The children in flight come from
|
|
18
|
+
// `epic_busy.read_repository`, which is the same `in-progress` listing `epicrun` sizes its lanes
|
|
19
|
+
// from — a second definition of "running" would let the progress line disagree with the loop that
|
|
20
|
+
// printed the child. The pull request comes from `run_preflight`, the lanes from `lane_registry`, and
|
|
21
|
+
// the transcript sample from `run_liveness.sample_output`, whose symlink-following `statSync` is the
|
|
22
|
+
// whole of joshuafolkken/kit#1485; re-`stat`ing the path here would reintroduce that bug.
|
|
23
|
+
//
|
|
24
|
+
// **The record is kept per work tree**, keyed the way `run_hold` keys its own: two lanes of one
|
|
25
|
+
// repository are two runs, and one lane's report must not silence the other's clock.
|
|
26
|
+
|
|
27
|
+
// The record itself — its name, its shape, and how it is read and written — lives in
|
|
28
|
+
// `run-progress-clock.ts`, because the trigger-delivered rule that refuses an early heartbeat reads
|
|
29
|
+
// the same record from inside a `PreToolUse` hook and cannot await the git call this file makes
|
|
30
|
+
// (joshuafolkken/kit#1570). What stays here is the asynchronous way of naming the work tree.
|
|
31
|
+
const { PROGRESS_PREFIX, mark, parse_stamp, read_last_report } = run_progress_clock
|
|
32
|
+
|
|
33
|
+
const FIRST_LOAD_AVERAGE = 0
|
|
34
|
+
|
|
35
|
+
// A listing that arrived and had holders, a listing that arrived empty, and a listing that did not
|
|
36
|
+
// arrive. All three end in no line being printed, and they are kept apart anyway: only the middle one
|
|
37
|
+
// can mean "there is nothing to report", and saying so for the third would be a confident absence
|
|
38
|
+
// built on a read nobody completed. **The middle one is `idle` only when no run has started** — a run
|
|
39
|
+
// underway with no `in-progress` child yet is `observed` with an empty `children`, which is the
|
|
40
|
+
// heartbeat this file emits before the first label appears (joshuafolkken/kit#1900).
|
|
41
|
+
type ObservationRead =
|
|
42
|
+
{ kind: 'idle' } | { kind: 'observed'; observations: Observations } | { kind: 'unreadable' }
|
|
43
|
+
|
|
44
|
+
const IDLE_READ: ObservationRead = { kind: 'idle' }
|
|
45
|
+
const UNREADABLE_READ: ObservationRead = { kind: 'unreadable' }
|
|
46
|
+
|
|
47
|
+
// The one place the record key is resolved: the first of the two paths git prints is this work tree's
|
|
48
|
+
// own git directory; the second is the common directory every work tree shares, which is exactly what
|
|
49
|
+
// must not be the key. Both the report clock and the liveness record key on it, so a single resolver
|
|
50
|
+
// is what keeps the file the watcher writes and the file `josh followup` removes the same one.
|
|
51
|
+
async function worktree_git_directory(): Promise<string | undefined> {
|
|
52
|
+
const [git_directory] = await git_command.git_directories()
|
|
53
|
+
|
|
54
|
+
return git_directory
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async function stamp_target(): Promise<string> {
|
|
58
|
+
return run_progress_clock.stamp_target_of(await worktree_git_directory())
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// The ambient log's path, a sibling of the report clock — the surface `josh run:progress --path` names
|
|
62
|
+
// so a person can keep it open across a session cut (joshuafolkken/kit#2156).
|
|
63
|
+
async function log_target(): Promise<string> {
|
|
64
|
+
return run_progress_clock.log_path_of(await stamp_target())
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// The watcher's liveness record, resolved through the same resolver as `stamp_target`, so the file the
|
|
68
|
+
// watcher begins is the file `josh followup` removes at the merge (joshuafolkken/kit#1821).
|
|
69
|
+
async function live_target(): Promise<string> {
|
|
70
|
+
return run_progress_clock.life_target_of(await worktree_git_directory())
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function to_labels(issue: OpenIssueData): Array<string> {
|
|
74
|
+
return (issue.labels ?? []).map((label) => label.name)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async function to_child(issue: OpenIssueData): Promise<ChildObservation> {
|
|
78
|
+
const number = String(issue.number)
|
|
79
|
+
const child = await run_preflight.read_child_state(number)
|
|
80
|
+
|
|
81
|
+
return { issue: number, labels: to_labels(issue), pr_state: child.pr_state }
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async function read_children(repo: string): Promise<ReadonlyArray<ChildObservation> | undefined> {
|
|
85
|
+
const read = await epic_busy.read_repository(repo)
|
|
86
|
+
|
|
87
|
+
if (read.kind === 'idle') return []
|
|
88
|
+
if (read.kind !== 'busy') return undefined
|
|
89
|
+
|
|
90
|
+
return await Promise.all(read.issues.map(async (issue) => await to_child(issue)))
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async function read_lanes(): Promise<ReadonlyArray<LaneObservation>> {
|
|
94
|
+
const lanes = await lane_registry.list_lanes()
|
|
95
|
+
|
|
96
|
+
return lanes.map((lane) => ({ issue: lane.issue, state: lane_report.lane_state(lane) }))
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function is_mtime(value: number | undefined): value is number {
|
|
100
|
+
return value !== undefined
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* How long ago the newest delegated unit's transcript last grew — the one field that says a run may be
|
|
105
|
+
* stuck rather than merely slow.
|
|
106
|
+
*
|
|
107
|
+
* `undefined` when no path was given or none of them could be sampled, and the line prints `unread`
|
|
108
|
+
* for it. A run started before any unit exists has nothing to name here, and inventing an age for a
|
|
109
|
+
* file nobody read is the failure this command is built not to commit.
|
|
110
|
+
*/
|
|
111
|
+
function read_record_age(paths: ReadonlyArray<string>, now_ms: number): number | undefined {
|
|
112
|
+
const times = paths
|
|
113
|
+
.map((output_path) => run_liveness.sample_output(output_path)?.mtime_ms)
|
|
114
|
+
.filter(is_mtime)
|
|
115
|
+
|
|
116
|
+
if (times.length === 0) return undefined
|
|
117
|
+
|
|
118
|
+
return now_ms - Math.max(...times)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function is_hold_present(read: HoldRead): boolean {
|
|
122
|
+
return read.kind === 'held' || read.kind === 'stale'
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function is_carry_present(read: CarryRead): boolean {
|
|
126
|
+
return read.kind === 'carried' || read.kind === 'expired'
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function hold_present(worktree: string | undefined): boolean {
|
|
130
|
+
return worktree !== undefined && is_hold_present(run_hold.read_hold(run_hold.hold_path(worktree)))
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function carry_present(repository: string | undefined): boolean {
|
|
134
|
+
if (repository === undefined) return false
|
|
135
|
+
|
|
136
|
+
return is_carry_present(run_carry.read_carry(run_carry.carry_path(repository)))
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// The mechanical records that say a run is underway, read from the same git directories the report
|
|
140
|
+
// clock is keyed on: the work tree's own for the hold, the common one for the carried budget.
|
|
141
|
+
async function has_run_record(): Promise<boolean> {
|
|
142
|
+
const [worktree, repository] = await git_command.git_directories()
|
|
143
|
+
|
|
144
|
+
return hold_present(worktree) || carry_present(repository)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Whether a run has started in this checkout, read from a mechanical record rather than from the
|
|
149
|
+
* `in-progress` label — the label is exactly what is missing in the window this bridges
|
|
150
|
+
* (joshuafolkken/kit#1900).
|
|
151
|
+
*
|
|
152
|
+
* A registered lane covers an `epicrun` / `backlogrun` parent whose child has not labelled yet — and
|
|
153
|
+
* it is the one signal already read for the line, so it is asked first and short-circuits the git
|
|
154
|
+
* reads. A held work tree covers a `fullrun` / `halfrun` between `run:hold` and its first label, and a
|
|
155
|
+
* carried budget covers a `backlogrun` / `queue` before its first lane opens.
|
|
156
|
+
*/
|
|
157
|
+
async function has_run_started(lanes: ReadonlyArray<LaneObservation>): Promise<boolean> {
|
|
158
|
+
return lanes.length > 0 || (await has_run_record())
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
interface ObservationRequest {
|
|
162
|
+
now_ms: number
|
|
163
|
+
output_paths: ReadonlyArray<string>
|
|
164
|
+
repo: string
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
async function read_observations(request: ObservationRequest): Promise<ObservationRead> {
|
|
168
|
+
const [children, lanes] = await Promise.all([read_children(request.repo), read_lanes()])
|
|
169
|
+
|
|
170
|
+
if (children === undefined) return UNREADABLE_READ
|
|
171
|
+
if (children.length === 0 && !(await has_run_started(lanes))) return IDLE_READ
|
|
172
|
+
|
|
173
|
+
const observations: Observations = {
|
|
174
|
+
children,
|
|
175
|
+
lanes,
|
|
176
|
+
load_average: loadavg()[FIRST_LOAD_AVERAGE] ?? 0,
|
|
177
|
+
record_age_ms: read_record_age(request.output_paths, request.now_ms),
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return { kind: 'observed', observations }
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const run_progress_read = {
|
|
184
|
+
PROGRESS_PREFIX,
|
|
185
|
+
has_run_started,
|
|
186
|
+
live_target,
|
|
187
|
+
log_target,
|
|
188
|
+
mark,
|
|
189
|
+
parse_stamp,
|
|
190
|
+
read_children,
|
|
191
|
+
read_last_report,
|
|
192
|
+
read_lanes,
|
|
193
|
+
read_observations,
|
|
194
|
+
read_record_age,
|
|
195
|
+
stamp_target,
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export type { ObservationRead }
|
|
199
|
+
export { run_progress_read }
|