@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,607 @@
|
|
|
1
|
+
import { agent_role_profile, type AgentProfile } from '#scripts/agent/agent-role-profile'
|
|
2
|
+
import { backlog_budget } from '#scripts/backlog/backlog-budget'
|
|
3
|
+
import { process_identity } from '#scripts/josh/process-identity'
|
|
4
|
+
import { stamp_file } from '#scripts/josh/stamp-file'
|
|
5
|
+
import { z } from 'zod'
|
|
6
|
+
import type { CarryRead } from './run-carry'
|
|
7
|
+
|
|
8
|
+
// joshuafolkken/kit#1719. joshuafolkken/kit#1714 made a `backlogrun`'s budget survive the session cut
|
|
9
|
+
// and left out the one thing that starts the next session, so the record was carried and the
|
|
10
|
+
// keystroke stayed: a cut still ended with a `confirmation` Telegram and a resume line, and a run
|
|
11
|
+
// measured to cut about every 50 minutes did nothing at all until a person came back to it. Overnight
|
|
12
|
+
// that is the whole night.
|
|
13
|
+
//
|
|
14
|
+
// This is that starter — a process outside the conversation, which the cut does not end.
|
|
15
|
+
//
|
|
16
|
+
// **Whether to wake is the record's answer, never a judgement.** `carried` *and* handed off is the one
|
|
17
|
+
// state that wakes; `none`, `expired` and `unreadable` stop the supervisor. So the 8-hour whole-run
|
|
18
|
+
// bound needs no check of its own here: it **is** the carry record's expiry, so a run past it reads
|
|
19
|
+
// `expired` and the supervisor stops (`run-carry.ts` → `CARRY_MAX_AGE_MS`, itself imported from
|
|
20
|
+
// `backlog-budget.ts` rather than restated). A bound re-derived here is one that drifts, and it drifts
|
|
21
|
+
// silently in the direction that matters — the supervisor would go on waking past a budget the record
|
|
22
|
+
// already calls spent.
|
|
23
|
+
//
|
|
24
|
+
// **A hand-off is what separates a cut from a session that is simply working.** `is_handed_off` is set
|
|
25
|
+
// by `run:carry --cut`, and by this supervisor only when it recovers a record whose owner has *died*
|
|
26
|
+
// (`run-wake-handoff.ts`, joshuafolkken/kit#2437) — so a live session's record never reads as waiting to
|
|
27
|
+
// be woken, and a crash is carried on as if the dead session had cut rather than left standing.
|
|
28
|
+
//
|
|
29
|
+
// **The supervisor owns the record while its deterministic driver spends the budget.** After a cut or
|
|
30
|
+
// dead-owner recovery it adopts the record as this process, so `run:merge` has one live owner to
|
|
31
|
+
// count against. A judgment branch first hands the record off; `classify_claim` reads that explicit
|
|
32
|
+
// handoff before liveness, allowing one AI session to adopt it even while the supervisor is alive.
|
|
33
|
+
// The supervisor does not keep running the driver while that session owns the record.
|
|
34
|
+
|
|
35
|
+
const WAKE_PREFIX = 'josh-run-wake-'
|
|
36
|
+
// **Where the output of everything this supervisor starts is kept** (joshuafolkken/kit#1746).
|
|
37
|
+
// `detached` is what puts a child outside the conversation; discarding its output was a second choice
|
|
38
|
+
// riding along with it, and the two are separate requirements. Discarded, a session that exits without
|
|
39
|
+
// claiming the carry record leaves nothing at all to diagnose it by — which is the state
|
|
40
|
+
// joshuafolkken/kit#1746 was filed from, where three sessions died silently and the record could say
|
|
41
|
+
// only that none of them had arrived.
|
|
42
|
+
//
|
|
43
|
+
// One file per repository, appended to, so every attempt of every cut is in one place; keyed exactly
|
|
44
|
+
// as the wake and carry records are, so the three are found together. `.log` rather than `.json`
|
|
45
|
+
// because it holds another process's output verbatim — the distinction `stamp_file.stamp_path`'s
|
|
46
|
+
// `suffix` argument exists for.
|
|
47
|
+
const WAKE_LOG_PREFIX = 'josh-run-wake-log-'
|
|
48
|
+
const WAKE_LOG_SUFFIX = '.log'
|
|
49
|
+
// How long a woken session has to claim the carry record before that wake is treated as lost.
|
|
50
|
+
//
|
|
51
|
+
// **The window is measured from the spawn, so it has to cover everything before the session's first
|
|
52
|
+
// `run:carry --begin`** — the agent CLI's cold start, the resident preamble, and reading `SKILL.md`,
|
|
53
|
+
// `backlogrun.md`, `backlogrun.md` and the `fullrun` set. Ten minutes is several times the observed cost
|
|
54
|
+
// of that and still far inside the roughly 50-minute cut interval this exists to bridge. It was two
|
|
55
|
+
// minutes first, which is inside the range a merely *slow* start occupies — and a slow start booked as
|
|
56
|
+
// a failure ends the whole overnight run.
|
|
57
|
+
//
|
|
58
|
+
// **This one window is the only launch-failure detector, deliberately.** Reading the spawned process's
|
|
59
|
+
// exit code would catch a missing binary and miss the two failures that actually recur — a session
|
|
60
|
+
// that starts and dies during boot, and one that runs but never picks the run up. Asking instead
|
|
61
|
+
// whether the record was claimed catches all three, because it tests the thing that was wanted rather
|
|
62
|
+
// than the thing that was easy to observe.
|
|
63
|
+
const WAKE_GRACE_MS = 600_000
|
|
64
|
+
// **A lost wake is retried before it is called a failure**, because stopping is the expensive answer:
|
|
65
|
+
// it ends a run nobody is watching, for the night. Three attempts against a ten-minute window is
|
|
66
|
+
// half an hour of trying, which outlasts every transient cause worth surviving; past that the cause
|
|
67
|
+
// is not transient and a person has to see it.
|
|
68
|
+
const MAX_WAKE_ATTEMPTS = 3
|
|
69
|
+
// **How long a launch may be deferred for want of work before one is woken anyway**
|
|
70
|
+
// (joshuafolkken/kit#2417). A run whose backlog stays empty still needs one session to finish it — the
|
|
71
|
+
// drain, the retrospective and `run:carry --end` are a session's to do, not this process's — so a
|
|
72
|
+
// deferral without a ceiling would leave the record carried until its 8-hour expiry and end on a
|
|
73
|
+
// warning instead of a report. The ceiling is the `backlogrun` idle watch's own default, imported
|
|
74
|
+
// rather than restated: the supervisor watches the empty backlog for exactly as long as a woken session
|
|
75
|
+
// would have, only without paying a session to do it.
|
|
76
|
+
const IDLE_CEILING_MS = backlog_budget.DEFAULT_IDLE_MS
|
|
77
|
+
const NO_WAKES = 0
|
|
78
|
+
const ONE_WAKE = 1
|
|
79
|
+
|
|
80
|
+
// The supervisor's own record: which invocation it is watching, which process it is, and how many
|
|
81
|
+
// times it has woken a session.
|
|
82
|
+
interface RunWake {
|
|
83
|
+
// Copied from the carry record at `--start`, so the two cannot disagree about what is being
|
|
84
|
+
// continued. It is what the woken session is handed as its prompt.
|
|
85
|
+
invocation: string
|
|
86
|
+
profile?: AgentProfile | undefined
|
|
87
|
+
started_at: string
|
|
88
|
+
// The supervisor process. Unlike `run-hold.ts`, which records a pid it explicitly never reads back,
|
|
89
|
+
// this one is read: `--list` reports whether the supervisor is still running and `--stop` needs
|
|
90
|
+
// something to signal. The start-time token is what tells a reissued pid from the original.
|
|
91
|
+
pid: number
|
|
92
|
+
process_start?: string | undefined
|
|
93
|
+
// Criterion: the number of wakes tracks the carry record's `cuts`. Counting them here is what makes
|
|
94
|
+
// that checkable rather than merely argued from the structure. **It counts cuts served, not
|
|
95
|
+
// launches**, so a retry of the same cut does not inflate it — `attempts` is what counts those.
|
|
96
|
+
//
|
|
97
|
+
// **A recovery is a wake without a cut, so `woke` may run ahead of `cuts`** (joshuafolkken/kit#2336).
|
|
98
|
+
// When a session claims the record and then dies without cutting, the supervisor re-wakes and the
|
|
99
|
+
// replacement's claim is counted here too — so `woke == cuts` becomes `woke >= cuts`, the gap being
|
|
100
|
+
// the recoveries whose replacement claim a poll observed. `woke < cuts` still means a cut went
|
|
101
|
+
// unserved, and `outstanding_line` remains the authoritative signal of a launch not yet claimed.
|
|
102
|
+
//
|
|
103
|
+
// **A cut is served when the woken session claims the carry record, not when a process starts**
|
|
104
|
+
// (joshuafolkken/kit#1746). Counted at the spawn, the number asserted the very thing the supervisor
|
|
105
|
+
// had not yet checked: on 2026-09-10 three sessions were launched for one cut and none of them ever
|
|
106
|
+
// claimed the record, while `--list` went on reporting `woke 1 session(s) across 1 cut(s)` for forty
|
|
107
|
+
// minutes — the published invariant reading as held throughout the failure it exists to expose. So
|
|
108
|
+
// the increment moved to the one pass that observes a claim, and a wake nobody claimed now leaves
|
|
109
|
+
// `woke` behind `cuts`, which is what the invariant was always meant to say.
|
|
110
|
+
//
|
|
111
|
+
// **It is observed at a poll, so it lags a claim by up to one polling interval** — a minute by
|
|
112
|
+
// default. A shortfall read within that window is a claim not yet seen rather than one that never
|
|
113
|
+
// happened, and the two are told apart by `attempts`: a cut still being retried has launches
|
|
114
|
+
// outstanding, and one already claimed has none.
|
|
115
|
+
woke: number
|
|
116
|
+
// When the last wake happened, cleared as soon as the woken session claims the carry record. Its
|
|
117
|
+
// presence is what the grace window above is measured from.
|
|
118
|
+
woke_at?: string | undefined
|
|
119
|
+
// Launches for the cut currently being served, reset when a session claims the record. Separate
|
|
120
|
+
// from `woke` so a retried cut still reports as one wake against one cut — and, since
|
|
121
|
+
// joshuafolkken/kit#1746, so the two say different things: this counts what was started and `woke`
|
|
122
|
+
// counts what arrived, which is the gap a silent failure lives in.
|
|
123
|
+
attempts?: number | undefined
|
|
124
|
+
// The process the last launch produced. It is named in the failure warning rather than killed: a
|
|
125
|
+
// session that is merely slow is still doing the run's work, and a supervisor that killed what it
|
|
126
|
+
// could not account for would destroy exactly the work it exists to keep going.
|
|
127
|
+
woke_pid?: number | undefined
|
|
128
|
+
// When the wait on a still-running predecessor began. **It is its own field rather than a second
|
|
129
|
+
// use of `woke_at`, and that is the whole of the bound working as described.** Marked on `woke_at`,
|
|
130
|
+
// the first pass of a wait was the last one that could see the predecessor exit — every later pass
|
|
131
|
+
// read the mark as an outstanding wake and answered `pending` — so a predecessor that ended two
|
|
132
|
+
// seconds after the hold still cost the full grace window on a supervisor whose point is not to
|
|
133
|
+
// stall. Kept apart, the predecessor's liveness is read on every pass and the mark only bounds how
|
|
134
|
+
// long the wait may last.
|
|
135
|
+
held_at?: string | undefined
|
|
136
|
+
// The transcript ids of every session this supervisor forced with `--session-id`
|
|
137
|
+
// (joshuafolkken/kit#2407). `josh time --run` attributes a whiff only to a session in this list, so
|
|
138
|
+
// an unrelated read-only session that moved while the supervisor was alive is no longer counted
|
|
139
|
+
// against the wake role — the $7.68 the Issue read as a ceiling becomes the real figure. Appended
|
|
140
|
+
// once per launch, retries included, since each retry is a real session that woke and may have done
|
|
141
|
+
// nothing, and carried across a supervisor restart exactly like the counters beside it.
|
|
142
|
+
spawned?: ReadonlyArray<string> | undefined
|
|
143
|
+
// When the supervisor first deferred a launch because there was no work (joshuafolkken/kit#2417).
|
|
144
|
+
// Marked once and cleared by the next launch or claim, so it measures one unbroken idle stretch: it
|
|
145
|
+
// bounds the deferral at `IDLE_CEILING_MS`, and `run-wake-loop.ts` stretches the polling interval
|
|
146
|
+
// by it, which is the back-off after repeated whiffs.
|
|
147
|
+
idle_since?: string | undefined
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
type WakeStopReason = 'ended' | 'expired' | 'unreadable' | 'failed' | 'stopped'
|
|
151
|
+
|
|
152
|
+
// What the loop's tidy-up found at its own target (joshuafolkken/kit#1727). `absent` is the ordinary
|
|
153
|
+
// `--stop`, `removed` the ordinary end of a loop, and `superseded` the one that has to be said out
|
|
154
|
+
// loud: another supervisor holds the record and this process is the replaced one.
|
|
155
|
+
type WakeTidyResult = 'absent' | 'removed' | 'superseded'
|
|
156
|
+
|
|
157
|
+
// `wait` and `pending` are two states rather than one because the wake mark is cleared in the first
|
|
158
|
+
// and must survive the second — collapsed into one answer, a supervisor inside its grace window would
|
|
159
|
+
// forget it had already woken and wake again every interval. `idle` is a launch the record called for
|
|
160
|
+
// and the work did not: nothing is started, and the stretch is marked so it can be bounded.
|
|
161
|
+
type WakeDecision =
|
|
162
|
+
| { kind: 'wake' }
|
|
163
|
+
| { kind: 'idle' }
|
|
164
|
+
| { kind: 'wait' }
|
|
165
|
+
| { kind: 'pending' }
|
|
166
|
+
| { kind: 'hold' }
|
|
167
|
+
| { kind: 'failed' }
|
|
168
|
+
| { kind: 'stop'; reason: WakeStopReason }
|
|
169
|
+
|
|
170
|
+
interface WakeDecisionInput {
|
|
171
|
+
read: CarryRead
|
|
172
|
+
woke_at: string | undefined
|
|
173
|
+
attempts: number
|
|
174
|
+
// Whether the process named on the carry record is still running. **A cut is the run's last write,
|
|
175
|
+
// not the moment its process is gone** — so a supervisor that woke the instant it saw the hand-off
|
|
176
|
+
// could have the new session answered `busy`, because `run-carry.ts` → `classify_claim` tests
|
|
177
|
+
// `is_foreign_live_owner` before it tests the hand-off. Answered `busy`, the woken session stops
|
|
178
|
+
// without claiming anything, and the supervisor would eventually call its own wake a failure and end
|
|
179
|
+
// the run. So the predecessor is waited out first.
|
|
180
|
+
is_owner_live: boolean
|
|
181
|
+
// When the wait on that predecessor began, so the wait can be bounded without spending the mark
|
|
182
|
+
// that measures a launch.
|
|
183
|
+
held_at: string | undefined
|
|
184
|
+
// **Whether a woken session would find anything to do** (joshuafolkken/kit#2417). Before this the
|
|
185
|
+
// decision read the carry record alone, so a session was launched whether or not the backlog held a
|
|
186
|
+
// runnable issue or a lane was free — and a session that found nothing ended without touching
|
|
187
|
+
// anything, which is the whiff. `undefined` is "cannot tell", and it wakes: a failed read is not an
|
|
188
|
+
// empty backlog, and the error that costs a whiff is cheaper than the one that stalls the run.
|
|
189
|
+
// Optional for that reason: an input that does not say reads exactly as the record-only decision did.
|
|
190
|
+
has_work?: boolean | undefined
|
|
191
|
+
// When the current idle stretch began, so the deferral can be bounded.
|
|
192
|
+
idle_since?: string | undefined
|
|
193
|
+
now: Date
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const WAKE_DECISION: WakeDecision = { kind: 'wake' }
|
|
197
|
+
const IDLE_DECISION: WakeDecision = { kind: 'idle' }
|
|
198
|
+
const WAIT_DECISION: WakeDecision = { kind: 'wait' }
|
|
199
|
+
const PENDING_DECISION: WakeDecision = { kind: 'pending' }
|
|
200
|
+
const HOLD_DECISION: WakeDecision = { kind: 'hold' }
|
|
201
|
+
const FAILED_DECISION: WakeDecision = { kind: 'failed' }
|
|
202
|
+
|
|
203
|
+
// The three carry reads that are not `carried`, each mapped to why the supervisor stops. `none` is the
|
|
204
|
+
// run having ended normally (`run:carry --end`); `expired` is the whole-run bound; `unreadable` is a
|
|
205
|
+
// record that cannot be trusted to say anything, which is a reason to stop rather than to guess.
|
|
206
|
+
const STOP_REASONS: Record<'none' | 'expired' | 'unreadable', WakeStopReason> = {
|
|
207
|
+
none: 'ended',
|
|
208
|
+
expired: 'expired',
|
|
209
|
+
unreadable: 'unreadable',
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const run_wake_schema = z.object({
|
|
213
|
+
invocation: z.string(),
|
|
214
|
+
started_at: z.string(),
|
|
215
|
+
pid: z.number(),
|
|
216
|
+
process_start: z.string().optional(),
|
|
217
|
+
woke: z.number(),
|
|
218
|
+
woke_at: z.string().optional(),
|
|
219
|
+
// **Every optional field of `RunWake` has to be listed here.** `z.object` strips what it does not
|
|
220
|
+
// declare, so a field added to the interface alone round-trips through disk as `undefined` — which
|
|
221
|
+
// reads as "no attempt has been made yet" and would restart the retry count on every pass.
|
|
222
|
+
attempts: z.number().optional(),
|
|
223
|
+
woke_pid: z.number().optional(),
|
|
224
|
+
held_at: z.string().optional(),
|
|
225
|
+
spawned: z.array(z.string()).optional(),
|
|
226
|
+
idle_since: z.string().optional(),
|
|
227
|
+
profile: agent_role_profile.PROFILE_SCHEMA.optional(),
|
|
228
|
+
})
|
|
229
|
+
|
|
230
|
+
// An unparsable stamp reads as overdue rather than as fresh: a mark whose time cannot be established
|
|
231
|
+
// is one that cannot be confirmed to have worked, and the safe direction is to report the failure.
|
|
232
|
+
function is_overdue(marked_at: string, now: Date, limit_ms: number = WAKE_GRACE_MS): boolean {
|
|
233
|
+
const marked = Date.parse(marked_at)
|
|
234
|
+
|
|
235
|
+
if (Number.isNaN(marked)) return true
|
|
236
|
+
|
|
237
|
+
return now.getTime() - marked > limit_ms
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// **A launch goes out only where there is work, or where the idle stretch has run past its ceiling**
|
|
241
|
+
// (joshuafolkken/kit#2417). This is the one gate every launch passes — the first wake of a cut, the
|
|
242
|
+
// recovery of a dead owner and a retry alike — because a retry into an empty backlog is the same whiff
|
|
243
|
+
// as a first wake into one. Past the ceiling the session is woken anyway, to finish the run.
|
|
244
|
+
function launch_or_idle(input: WakeDecisionInput): WakeDecision {
|
|
245
|
+
if (input.has_work !== false) return WAKE_DECISION
|
|
246
|
+
if (input.idle_since === undefined) return IDLE_DECISION
|
|
247
|
+
|
|
248
|
+
return is_overdue(input.idle_since, input.now, IDLE_CEILING_MS) ? WAKE_DECISION : IDLE_DECISION
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// **Whether to launch, pend, retry or give up, read from the wake mark alone.** It is reached from two
|
|
252
|
+
// places — a record a cut handed off whose predecessor has gone, and a record no cut handed off whose
|
|
253
|
+
// owner has *died* (the recovery below) — because both ask the same question once the decision to press
|
|
254
|
+
// on has been made: is a wake already out, is it still inside its grace window, and are there retries
|
|
255
|
+
// left. `woke_at === undefined` is "nothing outstanding, launch"; inside the window is `pending`; past
|
|
256
|
+
// it, a retry while attempts remain and otherwise `failed`.
|
|
257
|
+
function decide_launch(input: WakeDecisionInput): WakeDecision {
|
|
258
|
+
if (input.woke_at === undefined) return launch_or_idle(input)
|
|
259
|
+
if (!is_overdue(input.woke_at, input.now)) return PENDING_DECISION
|
|
260
|
+
|
|
261
|
+
return input.attempts < MAX_WAKE_ATTEMPTS ? launch_or_idle(input) : FAILED_DECISION
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// **A record no cut handed off is one of two things, told apart by the owner's liveness**
|
|
265
|
+
// (joshuafolkken/kit#2336). A *live* owner is a session spending the budget — the ordinary in-flight
|
|
266
|
+
// state, and there is nothing to do but wait. A *dead* owner is the defect this branch exists for: a
|
|
267
|
+
// session that claimed the record and then exited without cutting or ending — a woken session that
|
|
268
|
+
// crashed during boot, reported its state and stopped, or was ended by a stray notification — leaves
|
|
269
|
+
// the record `carried`, owned by a gone process, with no hand-off. Before this the supervisor answered
|
|
270
|
+
// `wait` to both and so waited on the dead one until the 8-hour bound, stopping the whole run in
|
|
271
|
+
// silence. Now a dead owner is recovered through the same grace/retry machinery a hand-off uses, so a
|
|
272
|
+
// crash between the claim and the next cut re-wakes rather than stranding the invocation.
|
|
273
|
+
//
|
|
274
|
+
// **`is_owner_live` is `!== false`, so "cannot tell" counts as living** (`run-carry.ts` →
|
|
275
|
+
// `is_owner_live`): a liveness read that cannot prove death keeps the safe answer, `wait`, and never
|
|
276
|
+
// double-wakes a session that is merely unreadable.
|
|
277
|
+
function decide_not_handed_off(input: WakeDecisionInput): WakeDecision {
|
|
278
|
+
if (input.is_owner_live) return WAIT_DECISION
|
|
279
|
+
|
|
280
|
+
return decide_launch(input)
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Only before the first launch for this cut. Once a wake is out, the record's owner is whatever the
|
|
284
|
+
// woken session declares, and waiting on it again would stall the grace window indefinitely.
|
|
285
|
+
//
|
|
286
|
+
// **The wait is bounded, and the bound is not decoration.** The owner is the agent process of the
|
|
287
|
+
// session that cut, and an interactive one often outlives its own cut — waited on without a bound, the
|
|
288
|
+
// supervisor would pend every interval for the record's whole life, wake nothing, and end on `expired`,
|
|
289
|
+
// which sends no warning. That is a silent overnight failure, which is worse than the `busy` race this
|
|
290
|
+
// wait exists to avoid: a `busy` merely costs one attempt, and attempts are retried. So the wait is
|
|
291
|
+
// marked when it starts and expires into an ordinary wake through the same grace window everything
|
|
292
|
+
// else uses.
|
|
293
|
+
//
|
|
294
|
+
// **And the wait ends the moment the predecessor does, because its liveness is read on every pass.**
|
|
295
|
+
// The bound is the ceiling on the wait, never its length: a predecessor that exits two seconds after
|
|
296
|
+
// the hold is waited two seconds. That is what `held_at` is a separate field for — marked on `woke_at`,
|
|
297
|
+
// this test could not fire a second time, so every wait cost the whole ceiling.
|
|
298
|
+
function is_predecessor_exiting(input: WakeDecisionInput): boolean {
|
|
299
|
+
if (input.woke_at !== undefined || !input.is_owner_live) return false
|
|
300
|
+
|
|
301
|
+
return input.held_at === undefined || !is_overdue(input.held_at, input.now)
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// The whole policy, in four lines. Nothing else in this module decides whether to wake.
|
|
305
|
+
function decide(input: WakeDecisionInput): WakeDecision {
|
|
306
|
+
if (input.read.kind !== 'carried') return { kind: 'stop', reason: STOP_REASONS[input.read.kind] }
|
|
307
|
+
if (input.read.carry.is_handed_off !== true) return decide_not_handed_off(input)
|
|
308
|
+
if (is_predecessor_exiting(input)) return HOLD_DECISION
|
|
309
|
+
|
|
310
|
+
return decide_launch(input)
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// Keyed on the repository's common git directory, exactly as the carry record is — one supervisor per
|
|
314
|
+
// invocation, and every lane of that repository keys alike. `run_carry.repository_directory` is what
|
|
315
|
+
// resolves it, so the two records can never key differently.
|
|
316
|
+
function wake_path(git_directory: string): string {
|
|
317
|
+
return stamp_file.stamp_path(WAKE_PREFIX, git_directory)
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// Keyed on the same directory as the two records, so a person handed one path can find the others.
|
|
321
|
+
function wake_log_path(git_directory: string): string {
|
|
322
|
+
return stamp_file.stamp_path(WAKE_LOG_PREFIX, git_directory, WAKE_LOG_SUFFIX)
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
function parse_wake(raw: string): RunWake | undefined {
|
|
326
|
+
try {
|
|
327
|
+
return run_wake_schema.parse(JSON.parse(raw))
|
|
328
|
+
} catch {
|
|
329
|
+
return undefined
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
function read_wake(target: string): RunWake | undefined {
|
|
334
|
+
const raw = stamp_file.read_stamp_text(target)
|
|
335
|
+
|
|
336
|
+
return raw === undefined ? undefined : parse_wake(raw)
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
function write_wake(target: string, wake: RunWake): void {
|
|
340
|
+
stamp_file.write_stamp(target, wake)
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
function remove_wake(target: string): void {
|
|
344
|
+
stamp_file.remove_stamp(target)
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
function fresh_wake(invocation: string, now: Date, profile?: AgentProfile): RunWake {
|
|
348
|
+
return {
|
|
349
|
+
invocation,
|
|
350
|
+
...(profile && { profile }),
|
|
351
|
+
started_at: now.toISOString(),
|
|
352
|
+
woke: NO_WAKES,
|
|
353
|
+
...process_identity.own_fields(),
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// **`!== false`, so "cannot tell" counts as running.** The two errors are not symmetric: a live
|
|
358
|
+
// supervisor read as dead means two supervisors waking two sessions into one budget, while a dead one
|
|
359
|
+
// read as live costs a refused `--start` the person can retry after `--stop`. This takes the second.
|
|
360
|
+
function is_supervisor_live(wake: RunWake): boolean {
|
|
361
|
+
return process_identity.is_same_process(wake.pid, wake.process_start) !== false
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// A restarted supervisor inherits the whole wake state rather than starting it over. `woke` is
|
|
365
|
+
// published against the carry record's `cuts` as an invariant, so a `--stop` / `--start` cycle mid-run
|
|
366
|
+
// that reset it would make `--list` under-report and the published check read as a defect that never
|
|
367
|
+
// happened. **`woke_at` and `attempts` come with it, and dropping them is not cosmetic**: a restart
|
|
368
|
+
// inside the grace window would otherwise see no wake mark, launch a second session for the *same*
|
|
369
|
+
// cut, count it as another cut served, and leave two sessions racing for one record. The invocation
|
|
370
|
+
// has to match — a different one is a different run, and its state is not this one's.
|
|
371
|
+
// **`woke_pid` and `held_at` come across too.** Without the first, a restart inside the grace window
|
|
372
|
+
// that then spends its retries reports "the last one was none" in the warning — the one fact the
|
|
373
|
+
// warning exists to hand the person, dropped exactly where it is needed. Without the second, a restart
|
|
374
|
+
// restarts the bounded wait, which is the ceiling sliding by another road.
|
|
375
|
+
function carried_state(existing: RunWake | undefined, invocation: string): Partial<RunWake> {
|
|
376
|
+
if (existing?.invocation !== invocation) return { woke: NO_WAKES }
|
|
377
|
+
|
|
378
|
+
return {
|
|
379
|
+
woke: existing.woke,
|
|
380
|
+
woke_at: existing.woke_at,
|
|
381
|
+
attempts: existing.attempts,
|
|
382
|
+
woke_pid: existing.woke_pid,
|
|
383
|
+
held_at: existing.held_at,
|
|
384
|
+
// **`spawned` carries across too, or a restart mid-run would lose the ids of every session it
|
|
385
|
+
// already started** (joshuafolkken/kit#2407) — and `josh time --run`, reading the record after
|
|
386
|
+
// the restart, would under-count the whiffs and read the loss as a saving.
|
|
387
|
+
spawned: existing.spawned,
|
|
388
|
+
// And `idle_since`, or a restart would slide the idle ceiling by the time already spent idle.
|
|
389
|
+
idle_since: existing.idle_since,
|
|
390
|
+
...(existing.profile && { profile: existing.profile }),
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
function is_held_by_live_supervisor(existing: RunWake | undefined): boolean {
|
|
395
|
+
return existing !== undefined && is_supervisor_live(existing)
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// The second attempt, reached only because something was already at the target: the dead-marker sweep
|
|
399
|
+
// `unit-worker-share.ts` does for the unit-suite share, and then one more exclusive create. The record
|
|
400
|
+
// is re-read first, because between the two creates it may have become a live supervisor's.
|
|
401
|
+
function reclaim(target: string, wake: RunWake): RunWake | undefined {
|
|
402
|
+
if (is_held_by_live_supervisor(read_wake(target))) return undefined
|
|
403
|
+
|
|
404
|
+
remove_wake(target)
|
|
405
|
+
|
|
406
|
+
return stamp_file.create_stamp(target, wake) ? wake : undefined
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// `create_stamp` rather than `write_stamp`: two `--start`s racing must not both come away believing
|
|
410
|
+
// they own the record.
|
|
411
|
+
//
|
|
412
|
+
// **The create is attempted before anything is removed, and that ordering is the exclusion.** Sweeping
|
|
413
|
+
// first — which this did, unconditionally — gives the exclusive create nothing to exclude: two claims
|
|
414
|
+
// that both read an empty target would each delete what the other had just created, and both would
|
|
415
|
+
// then succeed, leaving two supervisors waking two sessions into one carry budget. Attempted first, the
|
|
416
|
+
// create is what decides between them, and the sweep runs only where it found something already there
|
|
417
|
+
// — including a stamp that could not be parsed at all, which is why the sweep is not simply dropped.
|
|
418
|
+
function claim(
|
|
419
|
+
target: string,
|
|
420
|
+
invocation: string,
|
|
421
|
+
now: Date,
|
|
422
|
+
profile?: AgentProfile,
|
|
423
|
+
): RunWake | undefined {
|
|
424
|
+
const existing = read_wake(target)
|
|
425
|
+
|
|
426
|
+
if (is_held_by_live_supervisor(existing)) return undefined
|
|
427
|
+
|
|
428
|
+
const wake = { ...fresh_wake(invocation, now, profile), ...carried_state(existing, invocation) }
|
|
429
|
+
|
|
430
|
+
return stamp_file.create_stamp(target, wake) ? wake : reclaim(target, wake)
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// A launch marks the attempt and nothing else. `woke` is left alone here because a process that has
|
|
434
|
+
// started has not yet done the thing `woke` counts — `count_claim` is where that is decided.
|
|
435
|
+
//
|
|
436
|
+
// **The forced session id is recorded here, at the launch, because that is where it is known**
|
|
437
|
+
// (joshuafolkken/kit#2407). It is appended rather than replaced: a run spawns one session per cut plus
|
|
438
|
+
// one per retry, and `josh time --run` needs every id to tell a session it started from an unrelated
|
|
439
|
+
// one that merely moved while it was alive.
|
|
440
|
+
function count_wake(wake: RunWake, now: Date, pid: number, session_id: string): RunWake {
|
|
441
|
+
const attempts = (wake.attempts ?? NO_WAKES) + ONE_WAKE
|
|
442
|
+
const spawned = [...(wake.spawned ?? []), session_id]
|
|
443
|
+
const woke_at = now.toISOString()
|
|
444
|
+
|
|
445
|
+
return {
|
|
446
|
+
...wake,
|
|
447
|
+
attempts,
|
|
448
|
+
spawned,
|
|
449
|
+
woke_at,
|
|
450
|
+
woke_pid: pid,
|
|
451
|
+
held_at: undefined,
|
|
452
|
+
idle_since: undefined,
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
// Starts the clock on a wait without launching anything. `attempts` is deliberately untouched, so the
|
|
457
|
+
// bounded wait costs no retry: what it buys is that the wait expires into an ordinary wake instead of
|
|
458
|
+
// running until the carry record does.
|
|
459
|
+
//
|
|
460
|
+
// **Marked once, so the ceiling does not slide.** A mark rewritten on every pass would measure from the
|
|
461
|
+
// latest pass rather than from the start of the wait, and a predecessor that never exits would then be
|
|
462
|
+
// waited on for ever — the unbounded wait this bound exists to prevent, arrived at by another road.
|
|
463
|
+
function mark_wait(wake: RunWake, now: Date): RunWake {
|
|
464
|
+
return wake.held_at === undefined ? { ...wake, held_at: now.toISOString() } : wake
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
// Starts the idle stretch a deferred launch is bounded by (joshuafolkken/kit#2417). Marked once, for
|
|
468
|
+
// the reason `mark_wait` is: rewritten each pass, the ceiling would slide and never be reached.
|
|
469
|
+
function mark_idle(wake: RunWake, now: Date): RunWake {
|
|
470
|
+
return wake.idle_since === undefined ? { ...wake, idle_since: now.toISOString() } : wake
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
// **The one pass that observes a claim, and therefore the one place `woke` may grow**
|
|
474
|
+
// (joshuafolkken/kit#1746). The supervisor reaches it when the carry record stops reading as handed
|
|
475
|
+
// off, which `run-carry.ts` → `adopt_carry` does only from the session that took the record over — so
|
|
476
|
+
// the count is of records actually claimed rather than of processes started.
|
|
477
|
+
//
|
|
478
|
+
// **The mark is what says a wake was outstanding.** Without it this same state is an ordinary live
|
|
479
|
+
// session working through its budget, which no supervisor woke and which must not be counted; with
|
|
480
|
+
// it, the wake that was pending has just been answered.
|
|
481
|
+
//
|
|
482
|
+
// `undefined` rather than a deleted key, because `JSON.stringify` drops it on the way to disk and the
|
|
483
|
+
// reader treats absent and undefined alike — the same round-trip `run-carry.ts` documents for its own
|
|
484
|
+
// optional fields.
|
|
485
|
+
function count_claim(wake: RunWake): RunWake {
|
|
486
|
+
const woke = wake.woke_at === undefined ? wake.woke : wake.woke + ONE_WAKE
|
|
487
|
+
|
|
488
|
+
return {
|
|
489
|
+
...wake,
|
|
490
|
+
woke,
|
|
491
|
+
woke_at: undefined,
|
|
492
|
+
attempts: undefined,
|
|
493
|
+
held_at: undefined,
|
|
494
|
+
idle_since: undefined,
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
// **Whether the record at the target is this process's own** (joshuafolkken/kit#1727). Everything
|
|
499
|
+
// below that decides a write or a removal asks this rather than asking whether a record is there.
|
|
500
|
+
//
|
|
501
|
+
// **Existence was standing in for ownership, and the two come apart exactly when it matters.** A
|
|
502
|
+
// `--stop` that removes the record but does not reach the process — `EPERM`, or a liveness read that
|
|
503
|
+
// calls a running process dead — followed by a person's `--start` leaves the old loop awake beside a
|
|
504
|
+
// new supervisor's record. Asked only whether *a* record is there, the old loop writes its own pid
|
|
505
|
+
// and counters into the new one, and two supervisors then wake two sessions into one carry budget:
|
|
506
|
+
// the state `claim`'s exclusive create exists to prevent, reached after the create rather than
|
|
507
|
+
// through it. Asked whether the record is *its own*, it finds it is not and does nothing.
|
|
508
|
+
//
|
|
509
|
+
// **The precedent is `run-carry.ts` alone**, whose `is_owned_by` compares a record's `owner_pid` and
|
|
510
|
+
// `owner_start` against the owner the caller declares, and whose `is_foreign_live_owner` is that
|
|
511
|
+
// comparison deciding what a caller may touch. `run-hold.ts` is **not** a precedent and reading it as
|
|
512
|
+
// one is the mistake this note exists to prevent: it records a pid for the person reading the stop
|
|
513
|
+
// message and explicitly never reads it back (`run-hold.ts` → `describe_holder`), which is the
|
|
514
|
+
// distinction `RunWake.pid` above already draws.
|
|
515
|
+
//
|
|
516
|
+
// The one difference from `run-carry.ts` is who the owner is. There the owner is declared from
|
|
517
|
+
// outside, because the process spending the budget is not the one writing the record; here the writer
|
|
518
|
+
// *is* the owner, so the declaration is `process_identity.own_fields()` and the comparison is against
|
|
519
|
+
// this process.
|
|
520
|
+
function is_own_wake(wake: RunWake): boolean {
|
|
521
|
+
return process_identity.is_own_process(wake.pid, wake.process_start)
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
// The record only where it is this process's own. It is what the loop reads at the top of each pass,
|
|
525
|
+
// so a supervisor whose record has been taken over ends **before** it decides anything — refusing the
|
|
526
|
+
// write-back alone would still have spawned a session for a run somebody else is already watching.
|
|
527
|
+
function read_own_wake(target: string): RunWake | undefined {
|
|
528
|
+
const wake = read_wake(target)
|
|
529
|
+
|
|
530
|
+
return wake !== undefined && is_own_wake(wake) ? wake : undefined
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
// **Removes only this process's own record.** `--stop` and the dead-marker sweep in `reclaim` keep
|
|
534
|
+
// using `remove_wake`, and that is deliberate: a person stopping the supervisor is removing someone
|
|
535
|
+
// else's record on purpose, and a sweep is removing a record whose writer is gone. What must not
|
|
536
|
+
// happen is the loop's own tidy-up taking a live successor's record with it, which leaves the run
|
|
537
|
+
// unwatched with nothing anywhere saying so.
|
|
538
|
+
//
|
|
539
|
+
// **Read-then-remove, so a take-over landing between the two still costs the successor its record.**
|
|
540
|
+
// The same residual window `update_wake` has, and closing it needs an exclusive operation the stamp
|
|
541
|
+
// layer does not offer. What this removes is the case that was certain — the loop ending after a
|
|
542
|
+
// take-over it had already noticed — rather than the one that needs the hand-over to land inside two
|
|
543
|
+
// statements.
|
|
544
|
+
//
|
|
545
|
+
// **Three answers rather than a boolean, because the caller has to tell two of them apart.** An
|
|
546
|
+
// ordinary `--stop` and a take-over both leave this process with nothing to remove, and only the
|
|
547
|
+
// second is worth saying anything about — a `false` covering both put the caller in the position of
|
|
548
|
+
// re-deriving which one it was from a second read, which is a branch that can be written the wrong
|
|
549
|
+
// way round and would then announce a supersession on every ordinary stop. Answered here, the
|
|
550
|
+
// distinction is decided once, in the place that already holds the record.
|
|
551
|
+
function tidy_own_wake(target: string): WakeTidyResult {
|
|
552
|
+
const wake = read_wake(target)
|
|
553
|
+
|
|
554
|
+
if (wake === undefined) return 'absent'
|
|
555
|
+
if (!is_own_wake(wake)) return 'superseded'
|
|
556
|
+
|
|
557
|
+
remove_wake(target)
|
|
558
|
+
|
|
559
|
+
return 'removed'
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
// **Writes only where the record is still there *and* is this process's own.** `--stop` removes it,
|
|
563
|
+
// and the loop's pass is not instantaneous — it spawns a process — so an unconditional write-back can
|
|
564
|
+
// recreate a record a person has just deleted, leaving a supervisor that outlives its own stop; the
|
|
565
|
+
// presence check narrows that window rather than closing it outright, and what closes it is that the
|
|
566
|
+
// next pass reads the record again. The ownership check is the second half: a foreign record is
|
|
567
|
+
// never written back, however long the pass took.
|
|
568
|
+
//
|
|
569
|
+
// **That is a claim about the write and about nothing else.** A take-over landing mid-pass is still
|
|
570
|
+
// narrowed rather than closed — the pass spawns a process, so a session can go out for a cut the
|
|
571
|
+
// successor is also serving, and only the write-back that follows it is refused. What closes the
|
|
572
|
+
// window at the top of a pass is `read_own_wake`, and what closes it inside one is nothing here:
|
|
573
|
+
// this is a refusal to make the damage permanent, not a lock.
|
|
574
|
+
function update_wake(target: string, wake: RunWake): boolean {
|
|
575
|
+
if (read_own_wake(target) === undefined) return false
|
|
576
|
+
|
|
577
|
+
write_wake(target, wake)
|
|
578
|
+
|
|
579
|
+
return true
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
const run_wake = {
|
|
583
|
+
IDLE_CEILING_MS,
|
|
584
|
+
MAX_WAKE_ATTEMPTS,
|
|
585
|
+
WAKE_GRACE_MS,
|
|
586
|
+
WAKE_PREFIX,
|
|
587
|
+
claim,
|
|
588
|
+
count_claim,
|
|
589
|
+
count_wake,
|
|
590
|
+
decide,
|
|
591
|
+
fresh_wake,
|
|
592
|
+
is_supervisor_live,
|
|
593
|
+
mark_idle,
|
|
594
|
+
mark_wait,
|
|
595
|
+
parse_wake,
|
|
596
|
+
read_own_wake,
|
|
597
|
+
read_wake,
|
|
598
|
+
remove_wake,
|
|
599
|
+
tidy_own_wake,
|
|
600
|
+
update_wake,
|
|
601
|
+
wake_log_path,
|
|
602
|
+
wake_path,
|
|
603
|
+
write_wake,
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
export type { RunWake, WakeDecision, WakeDecisionInput, WakeStopReason, WakeTidyResult }
|
|
607
|
+
export { run_wake }
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
import { fileURLToPath } from 'node:url'
|
|
3
|
+
import { run_progress_read } from './run-progress-read'
|
|
4
|
+
import { run_watcher_guard } from './run-watcher-guard'
|
|
5
|
+
|
|
6
|
+
// `josh run:watcher:guard` — refuses when lane children are in-flight but the progress watcher has not
|
|
7
|
+
// pinged its life record recently (joshuafolkken/kit#2113). This is the hand-run form, kept for a run
|
|
8
|
+
// that calls it before a loop iteration; the *automatic* wiring is in `pretool-guard.ts`, which
|
|
9
|
+
// composes the same guard through `run-watcher-hook.ts` so every tool call is checked
|
|
10
|
+
// (joshuafolkken/kit#2353).
|
|
11
|
+
//
|
|
12
|
+
// **Exits 0 (ok) or 1 (stale).** A non-zero exit is what the hook mechanism treats as a refusal —
|
|
13
|
+
// the same contract `batch:guard` and `rule:guard` hold.
|
|
14
|
+
|
|
15
|
+
const SUCCESS_EXIT_CODE = 0
|
|
16
|
+
const FAILURE_EXIT_CODE = 1
|
|
17
|
+
|
|
18
|
+
async function run(): Promise<number> {
|
|
19
|
+
const life_target = await run_progress_read.live_target()
|
|
20
|
+
const result = await run_watcher_guard.check(life_target)
|
|
21
|
+
|
|
22
|
+
if (result.kind === 'ok') return SUCCESS_EXIT_CODE
|
|
23
|
+
|
|
24
|
+
console.error(result.note)
|
|
25
|
+
|
|
26
|
+
return FAILURE_EXIT_CODE
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async function main(): Promise<void> {
|
|
30
|
+
process.exitCode = await run()
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const run_watcher_guard_cli = { run }
|
|
34
|
+
|
|
35
|
+
if (process.argv[1] === fileURLToPath(import.meta.url)) await main()
|
|
36
|
+
|
|
37
|
+
export { run_watcher_guard_cli }
|