@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,186 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
import { chmodSync, mkdirSync, renameSync, rmSync, writeFileSync } from 'node:fs'
|
|
3
|
+
import path from 'node:path'
|
|
4
|
+
import { fileURLToPath } from 'node:url'
|
|
5
|
+
import { PROJECT_ROOT } from '#scripts/init/init-paths'
|
|
6
|
+
import { stamp_file } from '#scripts/josh/stamp-file'
|
|
7
|
+
import { security_audit } from './security-audit'
|
|
8
|
+
import { security_audit_logic } from './security-audit-logic'
|
|
9
|
+
import { security_audit_provision_logic, type ScannerAsset } from './security-audit-provision-logic'
|
|
10
|
+
|
|
11
|
+
const EXECUTABLE_MODE = 0o755
|
|
12
|
+
const FAILURE_STAMP_PREFIX = 'josh-audit-provision-'
|
|
13
|
+
const FORCE_FLAG = '--force'
|
|
14
|
+
const PATH_LOCATION = 'on PATH'
|
|
15
|
+
const { RETRY_INTERVAL_MS } = security_audit_provision_logic
|
|
16
|
+
|
|
17
|
+
function describe_error(error: unknown): string {
|
|
18
|
+
return error instanceof Error ? error.message : String(error)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// `content` absent is the failure, and `reason` says which one. A 404 — what a bumped version whose
|
|
22
|
+
// asset was renamed looks like, and the one failure that never fixes itself — would otherwise read
|
|
23
|
+
// exactly like a transient 503, and a rejected request like neither.
|
|
24
|
+
interface DownloadOutcome {
|
|
25
|
+
content?: Buffer
|
|
26
|
+
reason: string
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
interface ProvisionOutcome {
|
|
30
|
+
message: string
|
|
31
|
+
is_installed: boolean
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// The rejection is caught here rather than left to `attempt`: being offline, behind a proxy that
|
|
35
|
+
// refuses the host, or past the timeout is a *fetch* failure, and reporting it through the generic
|
|
36
|
+
// catch-all would drop the release URL out of the message that names where the fetch went.
|
|
37
|
+
async function download(url: string, timeout_ms: number): Promise<DownloadOutcome> {
|
|
38
|
+
try {
|
|
39
|
+
const response = await fetch(url, { signal: AbortSignal.timeout(timeout_ms) })
|
|
40
|
+
if (!response.ok) return { reason: `HTTP ${String(response.status)}` }
|
|
41
|
+
|
|
42
|
+
return { content: Buffer.from(await response.arrayBuffer()), reason: '' }
|
|
43
|
+
} catch (error) {
|
|
44
|
+
return { reason: describe_error(error) }
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Staged beside the target and renamed onto it, under a name carrying this process's id. A download
|
|
49
|
+
// interrupted halfway would otherwise leave a truncated file at the path `josh audit` spawns; and a
|
|
50
|
+
// shared staging name would let two sessions of the same project — the `SessionStart` matcher is
|
|
51
|
+
// empty, so a `clear` during a startup's download is exactly that — interleave their writes into one
|
|
52
|
+
// file that both then rename into place, which the checksum cannot catch because it was verified
|
|
53
|
+
// against each process's own buffer. The `finally` removes the staging file on every failing path.
|
|
54
|
+
function install(target_path: string, content: Buffer): void {
|
|
55
|
+
const staging_path = security_audit_provision_logic.build_staging_path(target_path, process.pid)
|
|
56
|
+
|
|
57
|
+
mkdirSync(path.dirname(target_path), { recursive: true })
|
|
58
|
+
|
|
59
|
+
try {
|
|
60
|
+
writeFileSync(staging_path, content)
|
|
61
|
+
chmodSync(staging_path, EXECUTABLE_MODE)
|
|
62
|
+
renameSync(staging_path, target_path)
|
|
63
|
+
} finally {
|
|
64
|
+
rmSync(staging_path, { force: true })
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function failure_stamp_path(target_path: string): string {
|
|
69
|
+
return stamp_file.stamp_path(FAILURE_STAMP_PREFIX, target_path)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function is_in_backoff(target_path: string): boolean {
|
|
73
|
+
const recorded = Number(stamp_file.read_stamp_text(failure_stamp_path(target_path)))
|
|
74
|
+
|
|
75
|
+
return Number.isFinite(recorded) && Date.now() - recorded < RETRY_INTERVAL_MS
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function record_failure(target_path: string, message: string): string {
|
|
79
|
+
stamp_file.write_stamp(failure_stamp_path(target_path), Date.now())
|
|
80
|
+
|
|
81
|
+
return message
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async function provision(
|
|
85
|
+
target_path: string,
|
|
86
|
+
asset: ScannerAsset,
|
|
87
|
+
timeout_ms: number,
|
|
88
|
+
): Promise<ProvisionOutcome> {
|
|
89
|
+
const { format_checksum_mismatch, format_download_failure, format_installed } =
|
|
90
|
+
security_audit_provision_logic
|
|
91
|
+
const outcome = await download(asset.url, timeout_ms)
|
|
92
|
+
|
|
93
|
+
if (outcome.content === undefined) {
|
|
94
|
+
return { is_installed: false, message: format_download_failure(asset.url, outcome.reason) }
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const actual = stamp_file.digest(outcome.content)
|
|
98
|
+
|
|
99
|
+
if (actual !== asset.sha256) {
|
|
100
|
+
return {
|
|
101
|
+
is_installed: false,
|
|
102
|
+
message: format_checksum_mismatch(asset.name, asset.sha256, actual),
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
install(target_path, outcome.content)
|
|
107
|
+
|
|
108
|
+
return { is_installed: true, message: format_installed(target_path) }
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// The one place a failure is recorded, so the backoff covers a rejected fetch, a bad checksum and a
|
|
112
|
+
// write that could not land alike — every reason the next session start would otherwise repeat.
|
|
113
|
+
async function attempt(
|
|
114
|
+
target_path: string,
|
|
115
|
+
asset: ScannerAsset,
|
|
116
|
+
timeout_ms: number,
|
|
117
|
+
): Promise<string> {
|
|
118
|
+
try {
|
|
119
|
+
const outcome = await provision(target_path, asset, timeout_ms)
|
|
120
|
+
if (!outcome.is_installed) return record_failure(target_path, outcome.message)
|
|
121
|
+
|
|
122
|
+
// Cleared on success, or a `pnpm install` that wipes the cache directory — which this design
|
|
123
|
+
// treats as costing one re-fetch — would instead be answered by a stale record telling the
|
|
124
|
+
// reader to pass `--force` for as long as the backoff runs.
|
|
125
|
+
stamp_file.remove_stamp(failure_stamp_path(target_path))
|
|
126
|
+
|
|
127
|
+
return outcome.message
|
|
128
|
+
} catch (error) {
|
|
129
|
+
return record_failure(
|
|
130
|
+
target_path,
|
|
131
|
+
security_audit_provision_logic.format_provision_error(describe_error(error)),
|
|
132
|
+
)
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// PATH first, but only when its scanner meets the floor: a below-floor PATH build (or a leftover
|
|
137
|
+
// managed copy from an earlier pinned version) reads a fraction of the lockfile and calls it clean
|
|
138
|
+
// (joshuafolkken/kit#2200), so it must not be reported as "already available" — doing so is what
|
|
139
|
+
// suppresses the fetch of a floor-meeting build. `is_executable_file` still guards the managed path
|
|
140
|
+
// so a zero-byte or non-executable leftover is never spawned just to read its version.
|
|
141
|
+
function existing_scanner(target_path: string): string | undefined {
|
|
142
|
+
const { BINARY_NAME } = security_audit_logic
|
|
143
|
+
if (security_audit.meets_floor(BINARY_NAME)) return PATH_LOCATION
|
|
144
|
+
|
|
145
|
+
const is_managed_usable =
|
|
146
|
+
security_audit.is_executable_file(target_path) && security_audit.meets_floor(target_path)
|
|
147
|
+
|
|
148
|
+
return is_managed_usable ? target_path : undefined
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
async function report(
|
|
152
|
+
project_root: string,
|
|
153
|
+
platform: string,
|
|
154
|
+
architecture: string,
|
|
155
|
+
is_forced: boolean,
|
|
156
|
+
): Promise<string> {
|
|
157
|
+
const logic = security_audit_provision_logic
|
|
158
|
+
const target_path = security_audit_logic.build_managed_binary_path(project_root, platform)
|
|
159
|
+
const existing = existing_scanner(target_path)
|
|
160
|
+
if (existing !== undefined) return logic.format_already_present(existing)
|
|
161
|
+
|
|
162
|
+
const asset = logic.resolve_asset(platform, architecture)
|
|
163
|
+
if (asset === undefined) return logic.format_unsupported_platform(platform, architecture)
|
|
164
|
+
if (!is_forced && is_in_backoff(target_path)) return logic.format_recent_failure()
|
|
165
|
+
|
|
166
|
+
return await attempt(target_path, asset, logic.build_download_timeout(is_forced))
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Every failure is a printed line and a zero exit, deliberately: this runs at session start, and a
|
|
170
|
+
// non-zero exit there would take an agent's whole session away over a tool it does not need yet.
|
|
171
|
+
// The audit's own gate is unchanged — a scanner that never arrived still fails the pre-push run.
|
|
172
|
+
async function main(): Promise<void> {
|
|
173
|
+
const is_forced = process.argv.includes(FORCE_FLAG)
|
|
174
|
+
|
|
175
|
+
try {
|
|
176
|
+
console.info(await report(PROJECT_ROOT, process.platform, process.arch, is_forced))
|
|
177
|
+
} catch (error) {
|
|
178
|
+
console.warn(security_audit_provision_logic.format_provision_error(describe_error(error)))
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (process.argv[1] === fileURLToPath(import.meta.url)) await main()
|
|
183
|
+
|
|
184
|
+
const security_audit_provision = { attempt, download, install, main, provision, report }
|
|
185
|
+
|
|
186
|
+
export { security_audit_provision }
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
import { accessSync, constants, statSync } from 'node:fs'
|
|
3
|
+
import { fileURLToPath } from 'node:url'
|
|
4
|
+
import { PROJECT_ROOT } from '#scripts/init/init-paths'
|
|
5
|
+
import { execaSync } from 'execa'
|
|
6
|
+
import { security_audit_logic } from './security-audit-logic'
|
|
7
|
+
import { security_audit_provision_logic } from './security-audit-provision-logic'
|
|
8
|
+
|
|
9
|
+
const FAILURE_EXIT_CODE = 1
|
|
10
|
+
const UNKNOWN_VERSION = 'unknown'
|
|
11
|
+
|
|
12
|
+
// execa reports `exitCode: undefined` only when the binary could not be spawned
|
|
13
|
+
// (ENOENT); a non-zero `--version` exit still means the binary exists.
|
|
14
|
+
function is_binary_available(binary_name: string): boolean {
|
|
15
|
+
const result = execaSync(binary_name, ['--version'], { stdio: 'ignore', reject: false })
|
|
16
|
+
|
|
17
|
+
return result.exitCode !== undefined
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// The scanner's own reported version, or `undefined` when it could not be spawned or printed nothing
|
|
21
|
+
// a version could be read from. Captured through the default piped stdio rather than the `ignore` the
|
|
22
|
+
// availability probe uses, because the version is exactly what has to be read back here.
|
|
23
|
+
function scanner_version(binary_or_path: string): string | undefined {
|
|
24
|
+
const result = execaSync(binary_or_path, ['--version'], { reject: false })
|
|
25
|
+
if (result.exitCode === undefined) return undefined
|
|
26
|
+
|
|
27
|
+
return security_audit_provision_logic.parse_scanner_version(result.stdout)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Whether the binary at this name or path parses the whole lockfile, i.e. is at or above the pinned
|
|
31
|
+
// floor. A version that cannot be read is not the floor met — an unspawnable or version-less binary
|
|
32
|
+
// is treated as below it, never as a pass (joshuafolkken/kit#2200).
|
|
33
|
+
function meets_floor(binary_or_path: string): boolean {
|
|
34
|
+
const version = scanner_version(binary_or_path)
|
|
35
|
+
|
|
36
|
+
return version !== undefined && security_audit_provision_logic.meets_version_floor(version)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Existence is not the question a provisioned binary has to answer. An interrupted install, a
|
|
40
|
+
// `chmod` refused by a `noexec` mount or a zero-byte leftover all satisfy `existsSync`, and spawning
|
|
41
|
+
// one of those fails with EACCES or ENOEXEC — an error that names neither the scanner nor how to get
|
|
42
|
+
// one, and that `josh audit:provision` would refuse to repair because something is already there.
|
|
43
|
+
function is_executable_file(candidate_path: string): boolean {
|
|
44
|
+
try {
|
|
45
|
+
accessSync(candidate_path, constants.X_OK)
|
|
46
|
+
const stats = statSync(candidate_path)
|
|
47
|
+
|
|
48
|
+
// `X_OK` succeeds on any traversable directory, and a directory's reported size is never zero,
|
|
49
|
+
// so both other clauses pass for one — reintroducing the very failure this check removes.
|
|
50
|
+
return stats.isFile() && stats.size > 0
|
|
51
|
+
} catch {
|
|
52
|
+
return false
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
interface ScannerChoice {
|
|
57
|
+
path: string
|
|
58
|
+
is_below_floor: boolean
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// A provisioned copy counts only when it is both a real executable and at or above the floor: a
|
|
62
|
+
// leftover from an earlier pinned version would otherwise be preferred over the PATH binary while
|
|
63
|
+
// reading less of the lockfile than it should.
|
|
64
|
+
function managed_scanner(project_root: string, platform: string): string | undefined {
|
|
65
|
+
const managed_path = security_audit_logic.build_managed_binary_path(project_root, platform)
|
|
66
|
+
|
|
67
|
+
return is_executable_file(managed_path) && meets_floor(managed_path) ? managed_path : undefined
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// PATH first, but only when its scanner meets the floor: an older PATH build reads a fraction of the
|
|
71
|
+
// lockfile and calls it clean (joshuafolkken/kit#2200), so a provisioned v2.6.0 is preferred over it
|
|
72
|
+
// rather than the other way round (the preference of joshuafolkken/kit#1563 held only while every
|
|
73
|
+
// build read the whole file). A below-floor PATH binary is the last resort, returned flagged so the
|
|
74
|
+
// audit can warn that its clean result proves nothing. `undefined` means no scanner at all.
|
|
75
|
+
function resolve_scanner(project_root: string, platform: string): ScannerChoice | undefined {
|
|
76
|
+
const { BINARY_NAME } = security_audit_logic
|
|
77
|
+
const has_path_binary = is_binary_available(BINARY_NAME)
|
|
78
|
+
|
|
79
|
+
if (has_path_binary && meets_floor(BINARY_NAME)) {
|
|
80
|
+
return { path: BINARY_NAME, is_below_floor: false }
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const managed = managed_scanner(project_root, platform)
|
|
84
|
+
if (managed !== undefined) return { path: managed, is_below_floor: false }
|
|
85
|
+
|
|
86
|
+
return has_path_binary ? { path: BINARY_NAME, is_below_floor: true } : undefined
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function run_scanner(scanner_path: string): number {
|
|
90
|
+
const { LOCKFILE_PATH, build_scanner_arguments } = security_audit_logic
|
|
91
|
+
const result = execaSync(scanner_path, [...build_scanner_arguments(LOCKFILE_PATH)], {
|
|
92
|
+
stdio: 'inherit',
|
|
93
|
+
reject: false,
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
return result.exitCode ?? FAILURE_EXIT_CODE
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// The clean result of a below-floor scanner is warned about rather than trusted: it means only that
|
|
100
|
+
// a blinkered build read too little of the lockfile to object, which the exit code cannot express.
|
|
101
|
+
function warn_below_floor(scanner_path: string): void {
|
|
102
|
+
const version = scanner_version(scanner_path) ?? UNKNOWN_VERSION
|
|
103
|
+
|
|
104
|
+
console.warn(security_audit_provision_logic.format_below_floor(version))
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function main(): never {
|
|
108
|
+
const { BINARY_NAME, format_missing_binary_error } = security_audit_logic
|
|
109
|
+
const choice = resolve_scanner(PROJECT_ROOT, process.platform)
|
|
110
|
+
|
|
111
|
+
if (choice === undefined) {
|
|
112
|
+
console.error(format_missing_binary_error(BINARY_NAME))
|
|
113
|
+
process.exit(FAILURE_EXIT_CODE)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (choice.is_below_floor) warn_below_floor(choice.path)
|
|
117
|
+
|
|
118
|
+
process.exit(run_scanner(choice.path))
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (process.argv[1] === fileURLToPath(import.meta.url)) main()
|
|
122
|
+
|
|
123
|
+
const security_audit = {
|
|
124
|
+
is_binary_available,
|
|
125
|
+
is_executable_file,
|
|
126
|
+
meets_floor,
|
|
127
|
+
resolve_scanner,
|
|
128
|
+
run_scanner,
|
|
129
|
+
scanner_version,
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export { security_audit }
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { repo_setting, type RepoSettingStatus } from '#scripts/repo/repo-setting'
|
|
2
|
+
|
|
3
|
+
// GitHub's Dependabot security-updates setting, as reported by
|
|
4
|
+
// `GET /repos/{owner}/{repo}/automated-security-fixes`.
|
|
5
|
+
//
|
|
6
|
+
// joshuafolkken/kit#803 set `open-pull-requests-limit: 0` on the npm entry of the distributed
|
|
7
|
+
// `.github/dependabot.yml`, which makes the security-advisory path the only remaining source of npm
|
|
8
|
+
// Dependabot PRs. That path depends on this repository-level setting, which is opt-in and off by
|
|
9
|
+
// default for private repositories — so a consumer that syncs the file without it gets zero npm
|
|
10
|
+
// Dependabot PRs, advisories included. The failure is silent: no PR looks exactly like no advisory
|
|
11
|
+
// (joshuafolkken/kit#805).
|
|
12
|
+
//
|
|
13
|
+
// `paused` is this setting's own third state, which is why the shared two-state classifier is only
|
|
14
|
+
// half the answer here (see classify_security_updates).
|
|
15
|
+
type SecurityUpdatesStatus = RepoSettingStatus | 'paused'
|
|
16
|
+
|
|
17
|
+
const SETTING_LABEL = 'Dependabot security updates'
|
|
18
|
+
const ENABLED_FIELD = 'enabled'
|
|
19
|
+
const PAUSED_FIELD = 'paused'
|
|
20
|
+
const ORIGIN_ISSUE = 'joshuafolkken/kit#803'
|
|
21
|
+
|
|
22
|
+
// The remediation for `disabled`, addressed at the repository the report actually resolved.
|
|
23
|
+
function enable_command(repo: string | undefined): string {
|
|
24
|
+
return `gh api -X PUT repos/${repo_setting.command_target(repo)}/automated-security-fixes`
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// `paused` is held to the same standard as `enabled`: a present but non-boolean value means the
|
|
28
|
+
// payload is not the one this code was written against, and guessing `enabled` from it would print
|
|
29
|
+
// the false all-clear the module exists to prevent. Absent is the older response shape, not a pause.
|
|
30
|
+
function classify_active(paused: unknown): SecurityUpdatesStatus {
|
|
31
|
+
if (paused === undefined) return 'enabled'
|
|
32
|
+
if (typeof paused !== 'boolean') return 'unreadable'
|
|
33
|
+
|
|
34
|
+
return paused ? 'paused' : 'enabled'
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Classify one `gh api` result. The shared classifier answers `enabled` / `disabled` / `unreadable`
|
|
38
|
+
// off the `enabled` field — a failed call, unparseable output and a non-boolean field all landing on
|
|
39
|
+
// `unreadable` — and only an affirmative answer is refined further by `paused`.
|
|
40
|
+
function classify_security_updates(exit_code: number, stdout: string): SecurityUpdatesStatus {
|
|
41
|
+
const payload = repo_setting.parse_payload(exit_code, stdout)
|
|
42
|
+
const status = repo_setting.classify_boolean_setting(payload, ENABLED_FIELD)
|
|
43
|
+
if (status !== 'enabled') return status
|
|
44
|
+
|
|
45
|
+
return classify_active(repo_setting.read_field(payload, PAUSED_FIELD))
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Whether the status leaves npm security advisories unable to open a PR. `unreadable` is excluded:
|
|
49
|
+
// it is worth reporting but it is not evidence of exposure.
|
|
50
|
+
function is_exposed(status: SecurityUpdatesStatus): boolean {
|
|
51
|
+
return status === 'disabled' || status === 'paused'
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// `disabled` and `paused` need different advice. The enable endpoint is a no-op on a paused
|
|
55
|
+
// repository — it is already `enabled: true` — so printing it there would send the reader in a
|
|
56
|
+
// circle and the same warning would return on the next sync.
|
|
57
|
+
function format_exposed_detail(
|
|
58
|
+
status: SecurityUpdatesStatus,
|
|
59
|
+
repo: string | undefined,
|
|
60
|
+
): ReadonlyArray<string> {
|
|
61
|
+
const remediation =
|
|
62
|
+
status === 'paused'
|
|
63
|
+
? [
|
|
64
|
+
' enabled but paused, so no advisory pull request is opened.',
|
|
65
|
+
" Resume it from the repository's Security → Dependabot page; re-running the enable",
|
|
66
|
+
' API does not clear a pause.',
|
|
67
|
+
]
|
|
68
|
+
: [
|
|
69
|
+
' off, so npm advisories open no pull request at all.',
|
|
70
|
+
` Enable: ${enable_command(repo)}`,
|
|
71
|
+
]
|
|
72
|
+
|
|
73
|
+
return [
|
|
74
|
+
...remediation,
|
|
75
|
+
` ${ORIGIN_ISSUE} disabled npm version updates, so this is the only remaining npm path.`,
|
|
76
|
+
]
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Why the setting could not be read. The two branches have different causes and must not share
|
|
80
|
+
// wording: when the repository itself was never identified, admin access and Dependabot's state are
|
|
81
|
+
// both beside the point, and pointing at a Security page names no page the reader can open.
|
|
82
|
+
//
|
|
83
|
+
// For an identified repository the causes are listed rather than asserted. GitHub answers 404 both
|
|
84
|
+
// for a token without admin access and for a repository where Dependabot is not enabled, and the
|
|
85
|
+
// same branch catches a timeout, an offline run and an unparseable body — so naming any one of them
|
|
86
|
+
// as the cause would be a false diagnosis. No enable command here either: it would be wrong whenever
|
|
87
|
+
// the setting is actually on and merely unreadable.
|
|
88
|
+
function format_unreadable_detail(repo: string | undefined): ReadonlyArray<string> {
|
|
89
|
+
if (repo === undefined) {
|
|
90
|
+
return [
|
|
91
|
+
' The repository could not be identified — `gh` is missing, unauthenticated, or this is',
|
|
92
|
+
' not a GitHub remote.',
|
|
93
|
+
]
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return [
|
|
97
|
+
' No admin access, Dependabot not enabled for the repository, or the request failed',
|
|
98
|
+
' (offline, timed out, or an unexpected response).',
|
|
99
|
+
" Check the repository's Security → Dependabot page.",
|
|
100
|
+
]
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// The report block for one repository: a single status line, plus the cause and its remediation when
|
|
104
|
+
// the repository is exposed, or the two possible causes when the setting could not be read.
|
|
105
|
+
function format_security_updates_report(
|
|
106
|
+
status: SecurityUpdatesStatus,
|
|
107
|
+
repo: string | undefined,
|
|
108
|
+
): ReadonlyArray<string> {
|
|
109
|
+
const target = repo_setting.report_target(repo)
|
|
110
|
+
if (status === 'enabled') return [` ✔ ${SETTING_LABEL}: enabled (${target})`]
|
|
111
|
+
|
|
112
|
+
if (!is_exposed(status)) {
|
|
113
|
+
return [
|
|
114
|
+
` ⚠ ${SETTING_LABEL}: could not be read (${target}) — not checked, not necessarily off`,
|
|
115
|
+
...format_unreadable_detail(repo),
|
|
116
|
+
]
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return [` ⚠ ${SETTING_LABEL}: ${status} (${target})`, ...format_exposed_detail(status, repo)]
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const security_updates_logic = {
|
|
123
|
+
SETTING_LABEL,
|
|
124
|
+
enable_command,
|
|
125
|
+
classify_security_updates,
|
|
126
|
+
is_exposed,
|
|
127
|
+
format_security_updates_report,
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export type { SecurityUpdatesStatus }
|
|
131
|
+
export { security_updates_logic }
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { repo_setting } from '#scripts/repo/repo-setting'
|
|
2
|
+
import { security_updates_logic, type SecurityUpdatesStatus } from './security-updates-logic'
|
|
3
|
+
|
|
4
|
+
const SECURITY_FIXES_PATH = 'automated-security-fixes'
|
|
5
|
+
|
|
6
|
+
// Read the repository's Dependabot security-updates setting. Never throws and never propagates a
|
|
7
|
+
// non-zero exit: an unreadable answer is a reported status, not a command failure
|
|
8
|
+
// (joshuafolkken/kit#805).
|
|
9
|
+
function read_security_updates(repo: string): SecurityUpdatesStatus {
|
|
10
|
+
const { exit_code, stdout } = repo_setting.query_repo_api(`repos/${repo}/${SECURITY_FIXES_PATH}`)
|
|
11
|
+
|
|
12
|
+
return security_updates_logic.classify_security_updates(exit_code, stdout)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Report the repository's setting as a blank-line-separated block. A repository that cannot be
|
|
16
|
+
// resolved (no `gh`, not a GitHub remote) reports `unreadable` rather than skipping the check
|
|
17
|
+
// silently — the whole point of joshuafolkken/kit#805 is that an absent answer must not look like a
|
|
18
|
+
// clean one.
|
|
19
|
+
//
|
|
20
|
+
// `repo` is always supplied by the caller — deliberately not a default parameter. A default fires
|
|
21
|
+
// on an explicitly-passed `undefined`, so `josh sync` handing over a failed lookup would silently
|
|
22
|
+
// spawn `gh repo view` a second time, defeating the hoist in exactly the path where `gh` is already
|
|
23
|
+
// known to be failing. `josh init` and `josh sync` already resolve the name for the Sonar config.
|
|
24
|
+
function report_security_updates_section(repo: string | undefined): SecurityUpdatesStatus {
|
|
25
|
+
const status = repo === undefined ? 'unreadable' : read_security_updates(repo)
|
|
26
|
+
|
|
27
|
+
repo_setting.print_section(security_updates_logic.format_security_updates_report(status, repo))
|
|
28
|
+
|
|
29
|
+
return status
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const security_updates = {
|
|
33
|
+
GH_TIMEOUT_MS: repo_setting.GH_TIMEOUT_MS,
|
|
34
|
+
read_security_updates,
|
|
35
|
+
report_security_updates_section,
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export { security_updates }
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
import { init_logic } from '#scripts/init/init-logic'
|
|
4
|
+
import type { SonarIdentifiers } from '#scripts/init/init-logic-sonar'
|
|
5
|
+
|
|
6
|
+
function write_sonar_file(
|
|
7
|
+
template_source: string,
|
|
8
|
+
destination_path: string,
|
|
9
|
+
identifiers: SonarIdentifiers,
|
|
10
|
+
): void {
|
|
11
|
+
const content = init_logic.apply_sonar_template(
|
|
12
|
+
readFileSync(template_source, 'utf8'),
|
|
13
|
+
identifiers.project_key,
|
|
14
|
+
identifiers.organization,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
mkdirSync(path.dirname(destination_path), { recursive: true })
|
|
18
|
+
writeFileSync(destination_path, content)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function merge_sonar_file(
|
|
22
|
+
template_source: string,
|
|
23
|
+
destination_path: string,
|
|
24
|
+
identifiers: SonarIdentifiers,
|
|
25
|
+
): void {
|
|
26
|
+
if (!existsSync(destination_path)) {
|
|
27
|
+
write_sonar_file(template_source, destination_path, identifiers)
|
|
28
|
+
|
|
29
|
+
return
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const template_content = init_logic.apply_sonar_template(
|
|
33
|
+
readFileSync(template_source, 'utf8'),
|
|
34
|
+
identifiers.project_key,
|
|
35
|
+
identifiers.organization,
|
|
36
|
+
)
|
|
37
|
+
const existing = readFileSync(destination_path, 'utf8')
|
|
38
|
+
|
|
39
|
+
writeFileSync(destination_path, init_logic.merge_sonar_properties(existing, template_content))
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const sonar_file = { write_sonar_file, merge_sonar_file }
|
|
43
|
+
|
|
44
|
+
export { sonar_file }
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// The public surface a downstream distribution package imports to refuse a sync aimed at its own
|
|
2
|
+
// repository. Exported rather than left internal because app-kit and game-kit run the same kind of
|
|
3
|
+
// copy and would otherwise each re-implement the detection (joshuafolkken/kit#868), which is the
|
|
4
|
+
// duplication `managed-marker` was extracted to avoid for the workflow stamp.
|
|
5
|
+
export { self_sync_guard } from './self-sync-guard-logic'
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
|
|
4
|
+
// `josh sync` / `josh-app sync` / `josh-game sync` all copy a distribution package's files into a
|
|
5
|
+
// consumer project. Run inside the package's OWN repository the direction reverses: the source of
|
|
6
|
+
// truth is overwritten by the derived template, and the copy transforms fire against a project
|
|
7
|
+
// where they are wrong (a `prompts/…` reference rewritten to `node_modules/@joshuafolkken/kit/…`
|
|
8
|
+
// resolves nowhere, a workflow written from `templates/` loses the pins `.github/workflows` owns).
|
|
9
|
+
// joshuafolkken/game-kit#447 is the incident; joshuafolkken/kit#868 reproduced the same damage in
|
|
10
|
+
// kit — 14 files, including CLAUDE.md, tsconfig.json and both mapped workflows.
|
|
11
|
+
//
|
|
12
|
+
// The check lives here rather than in each package's sync so the three distributors share one
|
|
13
|
+
// implementation: a second copy would drift, and a distributor that spelled the signal differently
|
|
14
|
+
// would keep exactly the hole this closes.
|
|
15
|
+
const MANIFEST_NAME = 'package.json'
|
|
16
|
+
|
|
17
|
+
function read_package_name(directory: string): string | undefined {
|
|
18
|
+
try {
|
|
19
|
+
const manifest: unknown = JSON.parse(readFileSync(path.join(directory, MANIFEST_NAME), 'utf8'))
|
|
20
|
+
if (typeof manifest !== 'object' || manifest === null) return undefined
|
|
21
|
+
const { name } = manifest as { name?: unknown }
|
|
22
|
+
|
|
23
|
+
return typeof name === 'string' ? name : undefined
|
|
24
|
+
} catch {
|
|
25
|
+
// A missing, unreadable or malformed manifest says nothing about self-sync, and refusing to
|
|
26
|
+
// sync on it would break consumers whose manifest this package is about to create.
|
|
27
|
+
return undefined
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function is_same_directory(first: string, second: string): boolean {
|
|
32
|
+
return path.resolve(first) === path.resolve(second)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Is `inner` the same directory as `outer`, or somewhere beneath it? Asked in one direction only.
|
|
36
|
+
// The reverse is the ordinary consumer layout — the package sits at
|
|
37
|
+
// `<project>/node_modules/@joshuafolkken/kit`, so the PACKAGE directory is always inside the
|
|
38
|
+
// PROJECT root — and refusing on that would refuse every sync there is.
|
|
39
|
+
function is_within(inner: string, outer: string): boolean {
|
|
40
|
+
const relative = path.relative(path.resolve(outer), path.resolve(inner))
|
|
41
|
+
|
|
42
|
+
return relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative))
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// The name is the primary signal, not the path: game-kit's incident ran a GLOBAL install of the
|
|
46
|
+
// package against its own repository, so `package_directory` and `project_root` were different
|
|
47
|
+
// directories and a path comparison alone would have missed it.
|
|
48
|
+
function name_reason(
|
|
49
|
+
package_name: string | undefined,
|
|
50
|
+
project_name: string | undefined,
|
|
51
|
+
): string | undefined {
|
|
52
|
+
return package_name !== undefined && package_name === project_name
|
|
53
|
+
? `this is ${package_name}'s own repository`
|
|
54
|
+
: undefined
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Reached only when the project has no readable manifest to name it, which is the whole of what
|
|
58
|
+
// makes containment usable here: a real consumer scaffolded under the checkout (a fixture at
|
|
59
|
+
// `kit/tmp/consumer`) is nested too, and its manifest names it as something other than this package.
|
|
60
|
+
// The nested case is `pnpm josh sync` run from `kit/docs`, where the sync would otherwise scatter a
|
|
61
|
+
// consumer's worth of managed files inside the repository.
|
|
62
|
+
function location_reason(package_directory: string, project_root: string): string | undefined {
|
|
63
|
+
if (is_same_directory(package_directory, project_root)) {
|
|
64
|
+
return 'the package directory and the project root are the same directory'
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return is_within(project_root, package_directory)
|
|
68
|
+
? 'the project root is inside the package directory'
|
|
69
|
+
: undefined
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function self_sync_reason(package_directory: string, project_root: string): string | undefined {
|
|
73
|
+
const project_name = read_package_name(project_root)
|
|
74
|
+
const by_name = name_reason(read_package_name(package_directory), project_name)
|
|
75
|
+
|
|
76
|
+
if (by_name !== undefined) return by_name
|
|
77
|
+
|
|
78
|
+
return project_name === undefined ? location_reason(package_directory, project_root) : undefined
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// The message a sync prints before refusing. Phrased as what was detected plus what to do instead,
|
|
82
|
+
// because the command is usually reached by habit ("re-sync after upgrading") and the user needs to
|
|
83
|
+
// know nothing is wrong with their checkout.
|
|
84
|
+
function self_sync_refusal(package_directory: string, project_root: string): string | undefined {
|
|
85
|
+
const reason = self_sync_reason(package_directory, project_root)
|
|
86
|
+
|
|
87
|
+
if (reason === undefined) return undefined
|
|
88
|
+
|
|
89
|
+
return [
|
|
90
|
+
`Refusing to sync: ${reason}.`,
|
|
91
|
+
'Syncing here would overwrite the distribution source with its own derived templates.',
|
|
92
|
+
'Run this command from a consumer project instead.',
|
|
93
|
+
].join('\n')
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const self_sync_guard = { self_sync_reason, self_sync_refusal, read_package_name }
|
|
97
|
+
|
|
98
|
+
export { self_sync_guard }
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { self_sync_guard } from './self-sync-guard-logic'
|
|
2
|
+
|
|
3
|
+
// The half of the guard that `sync` and `init` share verbatim: print the refusal and leave a
|
|
4
|
+
// non-zero exit code. It lives beside the detection rather than in either entry point because the
|
|
5
|
+
// two commands do the same damage in the source repository — `init` a larger share of it, since it
|
|
6
|
+
// rewrites `package.json` scripts and devDependencies as well (joshuafolkken/kit#879) — and a copy
|
|
7
|
+
// in each `main()` would be the second implementation the shared module exists to prevent.
|
|
8
|
+
//
|
|
9
|
+
// Not re-exported from `index.ts`: the published `@joshuafolkken/kit/self-sync-guard` surface stays
|
|
10
|
+
// the pure detection, so a downstream distributor keeps deciding how its own CLI reports a refusal.
|
|
11
|
+
function did_refuse_self_run(package_directory: string, project_root: string): boolean {
|
|
12
|
+
const refusal = self_sync_guard.self_sync_refusal(package_directory, project_root)
|
|
13
|
+
|
|
14
|
+
if (refusal === undefined) return false
|
|
15
|
+
|
|
16
|
+
console.error(`\n${refusal}\n`)
|
|
17
|
+
process.exitCode = 1
|
|
18
|
+
|
|
19
|
+
return true
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export { did_refuse_self_run }
|