@a-company/paradigm 5.10.0 → 5.21.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/dist/accept-orchestration-IUAWQZUN.js +18 -0
- package/dist/add-P76GEMGF.js +8 -0
- package/dist/agent-UUTYOFTH.js +33 -0
- package/dist/agent-loader-EPXURMO7.js +2 -0
- package/dist/agent-loader-PYGPX6D2.js +2 -0
- package/dist/agent-state-KSQ3S7OB.js +2 -0
- package/dist/agents-suggest-HYTFMQD3.js +10 -0
- package/dist/aggregate-W66DM3GA.js +10 -0
- package/dist/ambient-HYZR42NX.js +35 -0
- package/dist/assess-UFPYEJKP.js +9 -0
- package/dist/auto-RHJXOZFL.js +14 -0
- package/dist/beacon-5QVYV5DF.js +13 -0
- package/dist/calibration-OLJYB5HN.js +7 -0
- package/dist/check-THVGY4R5.js +14 -0
- package/dist/chunk-22ISTMKI.js +31 -0
- package/dist/chunk-2QO33NYK.js +3 -0
- package/dist/chunk-33LKBMVK.js +134 -0
- package/dist/chunk-4QADCWPU.js +7 -0
- package/dist/chunk-4TXOVRWD.js +3 -0
- package/dist/chunk-4UJ4NIEQ.js +4 -0
- package/dist/chunk-4ZGGWZ32.js +3 -0
- package/dist/chunk-5TAVYPOV.js +2 -0
- package/dist/chunk-6EX37L4Q.js +8 -0
- package/dist/chunk-AD5TAD2A.js +5 -0
- package/dist/chunk-AGVAHVUA.js +2 -0
- package/dist/chunk-AO7ZSRME.js +13 -0
- package/dist/chunk-BFD3GFRK.js +2 -0
- package/dist/chunk-D34YFK4M.js +6 -0
- package/dist/chunk-DVZWCXB6.js +2 -0
- package/dist/chunk-EKZDFEJW.js +2 -0
- package/dist/chunk-ET5XJTSX.js +2 -0
- package/dist/chunk-FYDRENK7.js +3 -0
- package/dist/chunk-HMQ5BHP2.js +743 -0
- package/dist/chunk-HXKWL3VK.js +29 -0
- package/dist/chunk-IZSBGW6E.js +2 -0
- package/dist/chunk-J32OPJEX.js +2 -0
- package/dist/chunk-JBDMCRPP.js +7 -0
- package/dist/chunk-JIXHEBGK.js +7 -0
- package/dist/chunk-JNSJVCTU.js +2 -0
- package/dist/chunk-JQKKVAAN.js +2 -0
- package/dist/chunk-KLBH26PA.js +429 -0
- package/dist/chunk-L6K5HNDL.js +24 -0
- package/dist/chunk-LKAT7IAK.js +2 -0
- package/dist/chunk-M4UMM6DC.js +5 -0
- package/dist/chunk-NKYNHSA5.js +424 -0
- package/dist/chunk-NW6OKHE6.js +5 -0
- package/dist/chunk-NXRVR37G.js +60 -0
- package/dist/chunk-ODVKPZZ4.js +2 -0
- package/dist/chunk-PUBB7LIT.js +5 -0
- package/dist/chunk-Q2J542ST.js +2 -0
- package/dist/chunk-QGZRM6ZB.js +2 -0
- package/dist/chunk-QNZEG7IT.js +13 -0
- package/dist/chunk-QT2LKB3P.js +7 -0
- package/dist/chunk-RVRARWSY.js +9 -0
- package/dist/chunk-T6IDXUUA.js +2 -0
- package/dist/chunk-TYWB5IQJ.js +3 -0
- package/dist/chunk-UIKLE3WD.js +2 -0
- package/dist/chunk-V7K6CQVX.js +111 -0
- package/dist/chunk-VCKKJDLP.js +8 -0
- package/dist/chunk-VG7FN2TU.js +4 -0
- package/dist/chunk-W5IWDW4Y.js +16 -0
- package/dist/chunk-W7C6FFMO.js +8 -0
- package/dist/chunk-WESTEMIM.js +10 -0
- package/dist/chunk-WR6D3SC6.js +5 -0
- package/dist/chunk-WS2N27RX.js +3 -0
- package/dist/chunk-XMAV5AG6.js +2 -0
- package/dist/chunk-XROULIQN.js +2 -0
- package/dist/chunk-XUFYOXOU.js +3 -0
- package/dist/chunk-Y4XFVDZC.js +3 -0
- package/dist/chunk-Y6KXTQBG.js +2 -0
- package/dist/{chunk-GTR2TBIJ.js → chunk-Z2UZUCY6.js} +237 -1047
- package/dist/chunk-Z34K6GY2.js +8 -0
- package/dist/claude-4LR3LJQZ.js +13 -0
- package/dist/claude-cli-UP6HGH7C.js +6 -0
- package/dist/claude-code-RLJ4GX77.js +11 -0
- package/dist/claude-code-teams-R37HJY3Y.js +29 -0
- package/dist/commands-LMUD5L6R.js +455 -0
- package/dist/compliance-GZ7UAOG3.js +6 -0
- package/dist/conductor-Y5IXELTL.js +4 -0
- package/dist/config-schema-HR7LDEQ6.js +2 -0
- package/dist/constellation-CG7C4WFE.js +13 -0
- package/dist/context-audit-RSSRX6XC.js +6 -0
- package/dist/cost-IDNVMAEV.js +10 -0
- package/dist/cost-PK4KIF7R.js +2 -0
- package/dist/cursor-cli-QKF7Z6M2.js +4 -0
- package/dist/cursorrules-U5O4G5T4.js +14 -0
- package/dist/decision-loader-2XPZE4EZ.js +2 -0
- package/dist/delete-P5VULXR4.js +14 -0
- package/dist/diff-RTFUKJHF.js +9 -0
- package/dist/discipline-H7LDI6NT.js +2 -0
- package/dist/dist-3ZCH25SG.js +2 -0
- package/dist/dist-KGRCLBJP-2QAPFYNF.js +39 -0
- package/dist/dist-R3RWD35F.js +2 -0
- package/dist/dist-VGFSP3XM.js +2 -0
- package/dist/dist-VXCZWVVJ.js +2 -0
- package/dist/dist-W3XCATBJ.js +2 -0
- package/dist/docs-EDQ2STFK.js +2 -0
- package/dist/docs-RXPN6CK7.js +12 -0
- package/dist/doctor-2T2QL6VM.js +2 -0
- package/dist/drift-ILZE5BFJ.js +13 -0
- package/dist/echo-UPTQUEDU.js +46 -0
- package/dist/edit-GUU3HBVW.js +9 -0
- package/dist/event-Y3VXC2RV.js +3 -0
- package/dist/explain-files-3GPZUETV.js +4 -0
- package/dist/export-CV5KCTPS.js +2 -0
- package/dist/flow-S3RQ4YPY.js +11 -0
- package/dist/global-C44FW4G2.js +13 -0
- package/dist/graduate-3BBSC27A.js +5 -0
- package/dist/graph-CNDE5TAT.js +2 -0
- package/dist/graph-server-COZR5C3Z.js +14 -0
- package/dist/habits-4J2KRYUL.js +42 -0
- package/dist/history-UW454SDP.js +12 -0
- package/dist/hooks-XH52VGOU.js +2 -0
- package/dist/index.js +15 -1039
- package/dist/init-24MAQJFM.js +2 -0
- package/dist/integrity-UYDOOJDP.js +7 -0
- package/dist/integrity-checker-DHGMZQDG.js +2 -0
- package/dist/journal-loader-GLH7XFTK.js +2 -0
- package/dist/lint-IGKE6UPS.js +26 -0
- package/dist/list-5IUGP3ZB.js +7 -0
- package/dist/list-YKIQNKGB.js +6 -0
- package/dist/lore-loader-RVQI5GXL.js +2 -0
- package/dist/lore-loader-XY5MZRR2.js +2 -0
- package/dist/lore-server-FC2GMDLT.js +14 -0
- package/dist/manual-RXSPSFLL.js +20 -0
- package/dist/mcp.js +93 -20484
- package/dist/migrate-X5OMAFAQ.js +59 -0
- package/dist/migrate-assessments-GEI5WMI2.js +4 -0
- package/dist/model-discovery-HMB3YI4L.js +2 -0
- package/dist/nomination-engine-XF7TWPAP.js +2 -0
- package/dist/notebook-PE3JSYZI.js +11 -0
- package/dist/notebook-loader-CENTDDUJ.js +2 -0
- package/dist/orchestrate-35HBQ3O3.js +8 -0
- package/dist/peers-P2KXU7ZK.js +5 -0
- package/dist/persona-STQWZH5P.js +29 -0
- package/dist/pipeline-MZUITRVN.js +4 -0
- package/dist/platform-server-2KXHGHFV.js +25 -0
- package/dist/plugin-update-checker-M7PW434O.js +2 -0
- package/dist/portal-check-3JVNLOEP.js +8 -0
- package/dist/portal-compliance-2UG4VKWH.js +2 -0
- package/dist/probe-5L5BQDGE.js +6 -0
- package/dist/project-type-SURTOIG7.js +2 -0
- package/dist/promote-NJQDZBZA.js +8 -0
- package/dist/providers-4PXMWA7V.js +8 -0
- package/dist/quiz-FE5UGAY2.js +10 -0
- package/dist/record-YXPB34MY.js +6 -0
- package/dist/reindex-PGDQSM42.js +2 -0
- package/dist/remember-MJRNTXYS.js +14 -0
- package/dist/retag-N5XF3KXP.js +6 -0
- package/dist/review-6UAH6V3R.js +11 -0
- package/dist/review-77QI6VOC.js +6 -0
- package/dist/ripple-ZGDITCGB.js +10 -0
- package/dist/roster-FLRZ5J42.js +2 -0
- package/dist/sentinel-HYAZ3CO5.js +19 -0
- package/dist/sentinel-bridge-VR357PKL.js +2 -0
- package/dist/sentinel-mcp.js +38 -3808
- package/dist/sentinel.js +1 -34
- package/dist/serve-JE6UF5P2.js +8 -0
- package/dist/serve-L52ZUTU6.js +10 -0
- package/dist/serve-OY6XYL7F.js +12 -0
- package/dist/server-2MNROHF6.js +7 -0
- package/dist/server-4YNUIK4W.js +8 -0
- package/dist/session-tracker-SKOMBDOW.js +2 -0
- package/dist/session-work-log-3MNUDEZ6.js +2 -0
- package/dist/session-work-log-J2H5OZBR.js +2 -0
- package/dist/setup-3F5IK7MO.js +31 -0
- package/dist/setup-KPIMRZ4Q.js +2 -0
- package/dist/shift-6GCNH666.js +11 -0
- package/dist/show-BOAVWZPZ.js +7 -0
- package/dist/show-PJ5LFLIL.js +5 -0
- package/dist/snapshot-L2G56RPL.js +8 -0
- package/dist/spawn-UH5RENSE.js +12 -0
- package/dist/status-77M3SDIF.js +8 -0
- package/dist/status-A37ECYNJ.js +6 -0
- package/dist/summary-ZJLQ6KHB.js +7 -0
- package/dist/sweep-HU74OPVW.js +17 -0
- package/dist/switch-CTW4PDGI.js +17 -0
- package/dist/symphony-3QMBGCZY.js +2 -0
- package/dist/symphony-QI63XL62.js +53 -0
- package/dist/symphony-loader-XACVV2E3.js +2 -0
- package/dist/symphony-peers-U4KHMKGI.js +2 -0
- package/dist/symphony-peers-X5NGWXFP.js +2 -0
- package/dist/symphony-relay-5GY5JIPT.js +3 -0
- package/dist/sync-QRDSFETO.js +2 -0
- package/dist/sync-llms-HL5PPW3M.js +15 -0
- package/dist/task-loader-NZFDTUQ5.js +2 -0
- package/dist/team-WGERKGNP.js +2 -0
- package/dist/test-BQJMS4Y2.js +111 -0
- package/dist/thread-HFXK65D4.js +41 -0
- package/dist/timeline-K3ZFKJ3R.js +6 -0
- package/dist/triage-FCWOZASE.js +18 -0
- package/dist/tutorial-UC6YQMNN.js +305 -0
- package/dist/university-content/courses/.purpose +74 -5
- package/dist/university-content/courses/para-701.json +807 -0
- package/dist/university-content/plsat/.purpose +3 -2
- package/dist/university-ui/assets/{index-BjewBB6s.js → index-CGFJczb1.js} +2 -2
- package/dist/university-ui/assets/{index-BjewBB6s.js.map → index-CGFJczb1.js.map} +1 -1
- package/dist/university-ui/index.html +1 -1
- package/dist/upgrade-B4IOLZYK.js +53 -0
- package/dist/validate-C6SMKGYD.js +9 -0
- package/dist/validate-LSCDOLBO.js +13 -0
- package/dist/validate-VZXTJHGO.js +6 -0
- package/dist/watch-LRM5XD46.js +8 -0
- package/dist/watch-PZCCUP6K.js +9 -0
- package/dist/wisdom-XZ3QKPNP.js +7 -0
- package/dist/work-log-loader-DL5GZ2BQ.js +2 -0
- package/dist/workspace-2ODL5WLY.js +2 -0
- package/package.json +1 -1
- package/platform-ui/dist/assets/AmbientSection-DqQ2mfCO.js +1 -0
- package/platform-ui/dist/assets/{CanvasSection-DwPTRdIN.js → CanvasSection-DLW0s-Bu.js} +1 -1
- package/platform-ui/dist/assets/{DocsSection-BJc_ws4I.js → DocsSection-BQ9Hi51g.js} +1 -1
- package/platform-ui/dist/assets/{GitSection-DhqBo1xc.js → GitSection-QQeUX6o3.js} +1 -1
- package/platform-ui/dist/assets/{GraphSection-D9fhVnZ0.js → GraphSection-0c9C-w7K.js} +2 -2
- package/platform-ui/dist/assets/{GraphSection-BlgXTl53.css → GraphSection-Bbs2a8sC.css} +1 -1
- package/platform-ui/dist/assets/LoreSection--t56kCj2.js +1 -0
- package/platform-ui/dist/assets/LoreSection-qnmm3o4y.css +1 -0
- package/platform-ui/dist/assets/SentinelSection-C4OoME9U.js +1 -0
- package/platform-ui/dist/assets/{SymphonySection-BRoBaUSS.js → SymphonySection-B-rvsLxq.js} +1 -1
- package/platform-ui/dist/assets/TeamSection-CBFmNEEo.js +1 -0
- package/platform-ui/dist/assets/index-Bxp0TVaf.css +1 -0
- package/platform-ui/dist/assets/index-DPpOdAtC.js +57 -0
- package/platform-ui/dist/index.html +2 -2
- package/dist/accept-orchestration-UQLM7PTQ.js +0 -189
- package/dist/add-FZRKEGH4.js +0 -81
- package/dist/agent-WERIO2XV.js +0 -523
- package/dist/agent-loader-TFIANSF4.js +0 -44
- package/dist/agent-state-S5DAWPTF.js +0 -24
- package/dist/agents-suggest-DNSYJ6IA.js +0 -83
- package/dist/aggregate-H57K7PNV.js +0 -88
- package/dist/assess-4WVXZLZQ.js +0 -68
- package/dist/auto-QFS5NHQU.js +0 -504
- package/dist/beacon-KXZXYQHX.js +0 -251
- package/dist/calibration-V46G7JTY.js +0 -135
- package/dist/check-OWAIWV23.js +0 -175
- package/dist/chunk-2IO7JAG2.js +0 -148
- package/dist/chunk-2T6BTYBN.js +0 -712
- package/dist/chunk-36TKPM5Z.js +0 -400
- package/dist/chunk-45MUDW6E.js +0 -804
- package/dist/chunk-4BLYIB7J.js +0 -5701
- package/dist/chunk-4L3UTYQX.js +0 -677
- package/dist/chunk-4NCFWYGG.js +0 -110
- package/dist/chunk-54LTTQBH.js +0 -138
- package/dist/chunk-5EWAQHFY.js +0 -269
- package/dist/chunk-5JGJACDU.js +0 -37
- package/dist/chunk-5OUOLN6M.js +0 -659
- package/dist/chunk-5VKJBNJL.js +0 -444
- package/dist/chunk-6N3JTACN.js +0 -2260
- package/dist/chunk-6QC3YGB6.js +0 -114
- package/dist/chunk-7N7GSU6K.js +0 -34
- package/dist/chunk-ABVQGRF7.js +0 -268
- package/dist/chunk-CL7JSK52.js +0 -129
- package/dist/chunk-CSD7IHSN.js +0 -152
- package/dist/chunk-EDOAWN7J.js +0 -717
- package/dist/chunk-EKGMAM62.js +0 -525
- package/dist/chunk-EZ3GOCYC.js +0 -132
- package/dist/chunk-F3BCHPYT.js +0 -143
- package/dist/chunk-FKJUBQU3.js +0 -3081
- package/dist/chunk-GT5QGC2H.js +0 -253
- package/dist/chunk-GZDFVP2N.js +0 -540
- package/dist/chunk-IRKUEJVW.js +0 -405
- package/dist/chunk-J2JEQRT3.js +0 -164
- package/dist/chunk-JASGXLK3.js +0 -679
- package/dist/chunk-KVDYJLTC.js +0 -121
- package/dist/chunk-L27I3CPZ.js +0 -357
- package/dist/chunk-LHLIAYQ3.js +0 -185
- package/dist/chunk-MCMOGQMU.js +0 -145
- package/dist/chunk-NQKQG45G.js +0 -688
- package/dist/chunk-PBHIFAL4.js +0 -259
- package/dist/chunk-PDX44BCA.js +0 -11
- package/dist/chunk-PMXRGPRQ.js +0 -305
- package/dist/chunk-RAB5IKPR.js +0 -487
- package/dist/chunk-RJE5G7WO.js +0 -590
- package/dist/chunk-RTHA3XRE.js +0 -880
- package/dist/chunk-S2HO5MLR.js +0 -621
- package/dist/chunk-S3ORKP3V.js +0 -716
- package/dist/chunk-TAIJOFOE.js +0 -124
- package/dist/chunk-TXESEO7Y.js +0 -245
- package/dist/chunk-UPLDI7CN.js +0 -1334
- package/dist/chunk-VL67H5IC.js +0 -506
- package/dist/chunk-VPPK3SY4.js +0 -1136
- package/dist/chunk-YMDLDELF.js +0 -314
- package/dist/chunk-YO6DVTL7.js +0 -99
- package/dist/chunk-YRZ5RPEB.js +0 -1561
- package/dist/chunk-ZDHLG5VP.js +0 -5676
- package/dist/chunk-ZGUAAVMA.js +0 -756
- package/dist/chunk-ZSYVKSY6.js +0 -2602
- package/dist/claude-FRRWJSTJ.js +0 -362
- package/dist/claude-cli-XJLK2X4L.js +0 -276
- package/dist/claude-code-HTBA4XRB.js +0 -126
- package/dist/claude-code-teams-T4SP24MD.js +0 -199
- package/dist/commands-5N4ILTPH.js +0 -5859
- package/dist/conductor-CQVGTEQN.js +0 -161
- package/dist/config-schema-EA4XALGG.js +0 -154
- package/dist/constellation-A26CCGQS.js +0 -225
- package/dist/context-audit-RLO3ETRP.js +0 -682
- package/dist/cost-BGM32XJU.js +0 -93
- package/dist/cost-VI46A4XL.js +0 -174
- package/dist/cursor-cli-JVEZGHWQ.js +0 -269
- package/dist/cursorrules-HLIKJJZT.js +0 -84
- package/dist/decision-loader-WWCLIQPJ.js +0 -20
- package/dist/delete-KBRPQLPC.js +0 -56
- package/dist/diff-D4X53HAC.js +0 -126
- package/dist/discipline-FA4OZXIS.js +0 -24
- package/dist/dist-34NA5RS5.js +0 -74
- package/dist/dist-5QE2BB2B-5S3T6Y3T.js +0 -6919
- package/dist/dist-77JDTVAY.js +0 -62
- package/dist/dist-OGTSAZ55.js +0 -1358
- package/dist/dist-QK4SQAK7.js +0 -64
- package/dist/dist-TA6LSC2Q.js +0 -20
- package/dist/docs-PBZB7LYP.js +0 -89
- package/dist/docs-QIYKO3BR.js +0 -155
- package/dist/doctor-ULBOHEIC.js +0 -11
- package/dist/drift-R5NRKFHI.js +0 -251
- package/dist/echo-O2LY7CC2.js +0 -248
- package/dist/edit-R2HNLMOG.js +0 -63
- package/dist/event-25OJKDCE.js +0 -31
- package/dist/export-IWVL7XLF.js +0 -38
- package/dist/flow-CRRVV3O3.js +0 -185
- package/dist/global-3NG5JXUB.js +0 -136
- package/dist/graduate-USAWGBJM.js +0 -160
- package/dist/graph-VHUMAAS6.js +0 -12
- package/dist/graph-server-YL22VBBN.js +0 -116
- package/dist/habits-OL5NGPXO.js +0 -1405
- package/dist/history-WOWC573W.js +0 -277
- package/dist/hooks-HFWSCGPV.js +0 -12
- package/dist/integrity-IHO4FZTS.js +0 -194
- package/dist/integrity-checker-PSKJA5SB.js +0 -12
- package/dist/journal-loader-5EYSBFFY.js +0 -18
- package/dist/lint-K6CJGGPH.js +0 -456
- package/dist/list-4YK7QKFF.js +0 -57
- package/dist/list-ENR7Q4CR.js +0 -56
- package/dist/lore-loader-7NO6N6FT.js +0 -26
- package/dist/lore-server-UNJY5KC3.js +0 -118
- package/dist/manual-G6FISID5.js +0 -204
- package/dist/migrate-LS45DNEV.js +0 -889
- package/dist/migrate-assessments-RGH4O6IX.js +0 -97
- package/dist/model-discovery-D2H3VBGC.js +0 -8
- package/dist/nomination-engine-RV5CNO5B.js +0 -42
- package/dist/notebook-YWIYGEHV.js +0 -155
- package/dist/orchestrate-JLILBBJE.js +0 -324
- package/dist/peers-DEOUIZM6.js +0 -82
- package/dist/persona-UHAHIVST.js +0 -390
- package/dist/pipeline-L4HCSBGN.js +0 -263
- package/dist/platform-server-H5YO3DQD.js +0 -1475
- package/dist/plugin-update-checker-KRRSGXMV.js +0 -12
- package/dist/portal-check-NPYGII2D.js +0 -42
- package/dist/portal-compliance-J7DGAPFX.js +0 -18
- package/dist/probe-MHL5HQZ2.js +0 -167
- package/dist/promote-F6ZYZZAL.js +0 -182
- package/dist/providers-GK7PB2OL.js +0 -104
- package/dist/quiz-M66SC7F7.js +0 -99
- package/dist/record-RA4WR2BO.js +0 -49
- package/dist/reindex-5LTD53ZC.js +0 -16
- package/dist/remember-HBWJ655S.js +0 -77
- package/dist/retag-3OLCVDEQ.js +0 -62
- package/dist/review-27ATYTD2.js +0 -33
- package/dist/review-57QMURZV.js +0 -334
- package/dist/ripple-JPBXP5I3.js +0 -215
- package/dist/sentinel-4XIG4STA.js +0 -63
- package/dist/sentinel-bridge-MDUXTQRL.js +0 -109
- package/dist/serve-CAH3PHE7.js +0 -33
- package/dist/serve-INL7SNBK.js +0 -36
- package/dist/serve-KBSE36PL.js +0 -49
- package/dist/server-54SKYFFY.js +0 -1647
- package/dist/server-XUOIO7E6.js +0 -338
- package/dist/session-tracker-C4BMD5WG.js +0 -13
- package/dist/session-work-log-MZ47OAPB.js +0 -20
- package/dist/setup-EDS27WUR.js +0 -25
- package/dist/setup-KO5AFC4K.js +0 -296
- package/dist/shift-D2JOHHBF.js +0 -668
- package/dist/show-5PV5KFJE.js +0 -176
- package/dist/show-NQKYX6WQ.js +0 -82
- package/dist/snapshot-BK4RBPCG.js +0 -62
- package/dist/spawn-RCHNXDHE.js +0 -196
- package/dist/status-WGIAQODY.js +0 -71
- package/dist/summary-NIRABMF5.js +0 -140
- package/dist/sweep-QMHNSIY5.js +0 -934
- package/dist/switch-6EJPZDIA.js +0 -232
- package/dist/symphony-4OCY36AI.js +0 -791
- package/dist/symphony-B75X2MME.js +0 -326
- package/dist/symphony-loader-UZGON56V.js +0 -90
- package/dist/symphony-peers-2ZQYLRNI.js +0 -34
- package/dist/symphony-peers-OL7F6M5S.js +0 -121
- package/dist/symphony-relay-UJYUXN65.js +0 -710
- package/dist/sync-VEHUH4OA.js +0 -11
- package/dist/sync-llms-YHCFIE6X.js +0 -166
- package/dist/task-loader-LDYWQSLM.js +0 -20
- package/dist/team-O5MIIFMA.js +0 -34
- package/dist/test-566CP5KC.js +0 -1017
- package/dist/thread-N754I4D5.js +0 -274
- package/dist/timeline-M3CICQFE.js +0 -112
- package/dist/triage-HHYGT3HY.js +0 -671
- package/dist/tutorial-KD22SUNO.js +0 -666
- package/dist/upgrade-H5PF32BW.js +0 -551
- package/dist/validate-CNKEKO6A.js +0 -134
- package/dist/validate-MB5ULIHS.js +0 -39
- package/dist/validate-QH3LADM6.js +0 -64
- package/dist/watch-2TKP5PVL.js +0 -199
- package/dist/watch-ZF4ML6CD.js +0 -111
- package/dist/wisdom-AATMGNFA.js +0 -319
- package/dist/work-log-loader-5L45XNYZ.js +0 -14
- package/dist/workspace-6E6OSRNU.js +0 -21
- package/platform-ui/dist/assets/AmbientSection-WtHfNedO.js +0 -1
- package/platform-ui/dist/assets/LoreSection-C3EixkjW.css +0 -1
- package/platform-ui/dist/assets/LoreSection-CwDDHrz9.js +0 -1
- package/platform-ui/dist/assets/SentinelSection-Cl7e5oZ6.js +0 -1
- package/platform-ui/dist/assets/TeamSection-CqSIMrKz.js +0 -1
- package/platform-ui/dist/assets/index-CfpZFjea.css +0 -1
- package/platform-ui/dist/assets/index-F0KL9xrN.js +0 -57
|
@@ -1,14 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
// src/commands/hooks/index.ts
|
|
4
|
-
import * as fs from "fs";
|
|
5
|
-
import * as path from "path";
|
|
6
|
-
import * as os from "os";
|
|
7
|
-
import { execSync } from "child_process";
|
|
8
|
-
import chalk from "chalk";
|
|
9
|
-
|
|
10
|
-
// src/commands/hooks/generated-hooks.ts
|
|
11
|
-
var COMMON_HOOK = `#!/bin/sh
|
|
2
|
+
import*as e from'fs';import*as r from'path';import*as E from'os';import {execSync}from'child_process';import o from'chalk';var C=`#!/bin/sh
|
|
12
3
|
# paradigm-common.sh \u2014 Shared compliance checks for Paradigm stop hooks
|
|
13
4
|
# Sourced by claude-code-stop.sh and cursor-stop.sh
|
|
14
5
|
#
|
|
@@ -35,10 +26,10 @@ var COMMON_HOOK = `#!/bin/sh
|
|
|
35
26
|
# 5. Per-directory .purpose freshness (tracked via .pending-review)
|
|
36
27
|
# 6. Aspect coverage advisory
|
|
37
28
|
# 7. Lore entry expected for significant sessions (3+ source files)
|
|
38
|
-
# 8. Blocking habits not satisfied (from
|
|
29
|
+
# 8. Blocking habits not satisfied (from unified compliance-check)
|
|
39
30
|
# 9. Purpose-required patterns from config.yaml
|
|
40
|
-
# 10. Aspect drift detection with auto-heal
|
|
41
|
-
# 11. Portal gate implementation compliance
|
|
31
|
+
# 10. Aspect drift detection with auto-heal (from unified compliance-check)
|
|
32
|
+
# 11. Portal gate implementation compliance (from unified compliance-check)
|
|
42
33
|
|
|
43
34
|
VIOLATIONS=""
|
|
44
35
|
VIOLATION_COUNT=0
|
|
@@ -46,9 +37,24 @@ AUTO_FIXED=""
|
|
|
46
37
|
AUTO_FIX_COUNT=0
|
|
47
38
|
PARADIGM_AUTO_FIX="\${PARADIGM_AUTO_FIX:-0}"
|
|
48
39
|
|
|
40
|
+
# --- Cache .purpose file paths (avoid repeated find scans) ---
|
|
41
|
+
PURPOSE_CACHE=".paradigm/.purpose-paths"
|
|
42
|
+
if [ -f "$PURPOSE_CACHE" ]; then
|
|
43
|
+
PURPOSE_PATHS=$(cat "$PURPOSE_CACHE")
|
|
44
|
+
else
|
|
45
|
+
PURPOSE_PATHS=$(find . -name ".purpose" -not -path "*/node_modules/*" -not -path "*/.git/*" 2>/dev/null)
|
|
46
|
+
if [ -n "$PURPOSE_PATHS" ]; then
|
|
47
|
+
echo "$PURPOSE_PATHS" > "$PURPOSE_CACHE"
|
|
48
|
+
fi
|
|
49
|
+
fi
|
|
50
|
+
|
|
49
51
|
# --- Check 1: Source files modified without .purpose updates ---
|
|
52
|
+
# Instead of counting total source files globally, check per-directory:
|
|
53
|
+
# only flag directories where source files were modified but no .purpose
|
|
54
|
+
# exists in that directory's ancestor chain OR the covering .purpose was not updated.
|
|
50
55
|
SOURCE_COUNT=0
|
|
51
56
|
PARADIGM_COUNT=0
|
|
57
|
+
UNCOVERED_SOURCE_DIRS=""
|
|
52
58
|
|
|
53
59
|
for file in $MODIFIED; do
|
|
54
60
|
case "$file" in
|
|
@@ -58,13 +64,54 @@ for file in $MODIFIED; do
|
|
|
58
64
|
*.md|*.lock|*.log|.gitignore|.env*|*.json) ;;
|
|
59
65
|
*)
|
|
60
66
|
SOURCE_COUNT=$((SOURCE_COUNT + 1))
|
|
67
|
+
# Check if this file's directory has a covering .purpose that was modified
|
|
68
|
+
src_dir=$(dirname "$file")
|
|
69
|
+
covering=""
|
|
70
|
+
walk_dir="$src_dir"
|
|
71
|
+
while [ "$walk_dir" != "." ] && [ "$walk_dir" != "" ]; do
|
|
72
|
+
if [ -f "$walk_dir/.purpose" ]; then
|
|
73
|
+
covering="$walk_dir/.purpose"
|
|
74
|
+
break
|
|
75
|
+
fi
|
|
76
|
+
walk_dir=$(dirname "$walk_dir")
|
|
77
|
+
done
|
|
78
|
+
if [ -z "$covering" ] && [ -f ".purpose" ]; then
|
|
79
|
+
covering=".purpose"
|
|
80
|
+
fi
|
|
81
|
+
# If there IS a covering .purpose, check if it was modified too
|
|
82
|
+
if [ -n "$covering" ]; then
|
|
83
|
+
purpose_was_modified=false
|
|
84
|
+
for mod_file in $MODIFIED; do
|
|
85
|
+
if [ "$mod_file" = "$covering" ]; then
|
|
86
|
+
purpose_was_modified=true
|
|
87
|
+
break
|
|
88
|
+
fi
|
|
89
|
+
done
|
|
90
|
+
if [ "$purpose_was_modified" = false ]; then
|
|
91
|
+
# Deduplicate by directory
|
|
92
|
+
case "$UNCOVERED_SOURCE_DIRS" in
|
|
93
|
+
*"$src_dir"*) ;;
|
|
94
|
+
*) UNCOVERED_SOURCE_DIRS="$UNCOVERED_SOURCE_DIRS $src_dir" ;;
|
|
95
|
+
esac
|
|
96
|
+
fi
|
|
97
|
+
else
|
|
98
|
+
# No .purpose at all \u2014 already caught by Check 2
|
|
99
|
+
:
|
|
100
|
+
fi
|
|
61
101
|
;;
|
|
62
102
|
esac
|
|
63
103
|
done
|
|
64
104
|
|
|
65
|
-
|
|
105
|
+
# Only flag if there are uncovered directories AND zero paradigm files were touched
|
|
106
|
+
if [ -n "$UNCOVERED_SOURCE_DIRS" ] && [ "$PARADIGM_COUNT" -eq 0 ]; then
|
|
107
|
+
# Count uncovered dirs
|
|
108
|
+
UNCOVERED_DIR_COUNT=0
|
|
109
|
+
for _d in $UNCOVERED_SOURCE_DIRS; do
|
|
110
|
+
UNCOVERED_DIR_COUNT=$((UNCOVERED_DIR_COUNT + 1))
|
|
111
|
+
done
|
|
66
112
|
VIOLATIONS="$VIOLATIONS
|
|
67
|
-
- You modified
|
|
113
|
+
- You modified source files in $UNCOVERED_DIR_COUNT director(ies) without updating their .purpose files:
|
|
114
|
+
$UNCOVERED_SOURCE_DIRS
|
|
68
115
|
Update the nearest .purpose file for each modified code area."
|
|
69
116
|
VIOLATION_COUNT=$((VIOLATION_COUNT + 1))
|
|
70
117
|
fi
|
|
@@ -132,12 +179,29 @@ if [ -f "portal.yaml" ] || echo "$MODIFIED" | grep -q "portal.yaml"; then
|
|
|
132
179
|
: # portal.yaml exists or was modified \u2014 OK
|
|
133
180
|
else
|
|
134
181
|
# Check if any modified files contain route-like patterns
|
|
182
|
+
# Skip: test/spec/fixture files, markdown, and comment-only matches
|
|
135
183
|
ROUTE_FILES=""
|
|
136
184
|
for file in $MODIFIED; do
|
|
185
|
+
# Skip test, spec, and fixture files entirely
|
|
186
|
+
case "$file" in
|
|
187
|
+
*test*|*spec*|*fixture*|*__tests__*|*__mocks__*|*.test.*|*.spec.*) continue ;;
|
|
188
|
+
esac
|
|
137
189
|
case "$file" in
|
|
138
190
|
*.ts|*.js|*.tsx|*.jsx|*.py|*.rs|*.go)
|
|
139
191
|
if [ -f "$file" ]; then
|
|
140
|
-
|
|
192
|
+
# Grep for route patterns, then filter out comment lines and description strings
|
|
193
|
+
ROUTE_MATCH=$(grep -nE '\\.(get|post|put|patch|delete)\\s*\\(|router\\.|app\\.(get|post|put|delete)|@(Get|Post|Put|Delete)|#\\[actix_web::(get|post)' "$file" 2>/dev/null \\
|
|
194
|
+
| grep -v '^\\s*[0-9]*:\\s*//' \\
|
|
195
|
+
| grep -v '^\\s*[0-9]*:\\s*\\*' \\
|
|
196
|
+
| grep -v '^\\s*[0-9]*:\\s*#' \\
|
|
197
|
+
| grep -v '^\\s*[0-9]*:\\s*<!--' \\
|
|
198
|
+
| grep -v 'description:' \\
|
|
199
|
+
| grep -v 'summary:' \\
|
|
200
|
+
| grep -v 'comment:' \\
|
|
201
|
+
| grep -v '@example' \\
|
|
202
|
+
| grep -v '@see' \\
|
|
203
|
+
|| true)
|
|
204
|
+
if [ -n "$ROUTE_MATCH" ]; then
|
|
141
205
|
ROUTE_FILES="$ROUTE_FILES $file"
|
|
142
206
|
fi
|
|
143
207
|
fi
|
|
@@ -155,7 +219,7 @@ else
|
|
|
155
219
|
fi
|
|
156
220
|
|
|
157
221
|
# --- Check 4: Aspect anchor files that no longer exist ---
|
|
158
|
-
for purpose_file in $
|
|
222
|
+
for purpose_file in $PURPOSE_PATHS; do
|
|
159
223
|
if grep -q "anchors:" "$purpose_file" 2>/dev/null; then
|
|
160
224
|
purpose_dir=$(dirname "$purpose_file")
|
|
161
225
|
in_anchors=false
|
|
@@ -183,9 +247,22 @@ for purpose_file in $(find . -name ".purpose" -not -path "*/node_modules/*" -not
|
|
|
183
247
|
done
|
|
184
248
|
|
|
185
249
|
# --- Check 5: Per-directory .purpose freshness ---
|
|
250
|
+
# Uses .pending-review if available, plus a git-based fallback that cross-references
|
|
251
|
+
# modified source files against .purpose modification times.
|
|
186
252
|
PENDING_FILE=".paradigm/.pending-review"
|
|
253
|
+
STALE_PURPOSES=""
|
|
254
|
+
|
|
255
|
+
# Helper: record a stale .purpose (deduplicating)
|
|
256
|
+
_record_stale_purpose() {
|
|
257
|
+
_cov="$1"
|
|
258
|
+
case "$STALE_PURPOSES" in
|
|
259
|
+
*"$_cov"*) ;;
|
|
260
|
+
*) STALE_PURPOSES="$STALE_PURPOSES $_cov" ;;
|
|
261
|
+
esac
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
# Strategy A: Use .pending-review tracking file if present
|
|
187
265
|
if [ -f "$PENDING_FILE" ]; then
|
|
188
|
-
STALE_PURPOSES=""
|
|
189
266
|
while IFS= read -r tracked_file; do
|
|
190
267
|
[ -z "$tracked_file" ] && continue
|
|
191
268
|
# Find covering .purpose for this tracked file
|
|
@@ -204,28 +281,65 @@ if [ -f "$PENDING_FILE" ]; then
|
|
|
204
281
|
# Check if covering .purpose was also modified
|
|
205
282
|
if [ -n "$covering_purpose" ]; then
|
|
206
283
|
if ! echo "$MODIFIED" | grep -qxF "$covering_purpose"; then
|
|
207
|
-
|
|
208
|
-
case "$STALE_PURPOSES" in
|
|
209
|
-
*"$covering_purpose"*) ;;
|
|
210
|
-
*) STALE_PURPOSES="$STALE_PURPOSES $covering_purpose" ;;
|
|
211
|
-
esac
|
|
284
|
+
_record_stale_purpose "$covering_purpose"
|
|
212
285
|
fi
|
|
213
286
|
fi
|
|
214
287
|
done < "$PENDING_FILE"
|
|
288
|
+
fi
|
|
215
289
|
|
|
216
|
-
|
|
217
|
-
|
|
290
|
+
# Strategy B: Git-based fallback \u2014 for each modified source file, check whether
|
|
291
|
+
# its covering .purpose was modified more recently (by filesystem mtime).
|
|
292
|
+
# This catches cases where .pending-review is missing or out of sync.
|
|
293
|
+
for file in $MODIFIED; do
|
|
294
|
+
case "$file" in
|
|
295
|
+
.paradigm/*|*.md|*.lock|*.log|.gitignore|.env*|*.json|*.purpose|portal.yaml) continue ;;
|
|
296
|
+
esac
|
|
297
|
+
[ -f "$file" ] || continue
|
|
298
|
+
|
|
299
|
+
# Find covering .purpose
|
|
300
|
+
check_dir=$(dirname "$file")
|
|
301
|
+
covering_purpose=""
|
|
302
|
+
while [ "$check_dir" != "." ] && [ "$check_dir" != "" ]; do
|
|
303
|
+
if [ -f "$check_dir/.purpose" ]; then
|
|
304
|
+
covering_purpose="$check_dir/.purpose"
|
|
305
|
+
break
|
|
306
|
+
fi
|
|
307
|
+
check_dir=$(dirname "$check_dir")
|
|
308
|
+
done
|
|
309
|
+
if [ -z "$covering_purpose" ] && [ -f ".purpose" ]; then
|
|
310
|
+
covering_purpose=".purpose"
|
|
311
|
+
fi
|
|
312
|
+
[ -n "$covering_purpose" ] || continue
|
|
313
|
+
|
|
314
|
+
# Skip if .purpose was in the modified list (already updated this session)
|
|
315
|
+
echo "$MODIFIED" | grep -qxF "$covering_purpose" && continue
|
|
316
|
+
|
|
317
|
+
# Compare modification times: if source file is newer than .purpose, it's stale
|
|
318
|
+
if [ -f "$covering_purpose" ]; then
|
|
319
|
+
# Use portable stat-based mtime comparison (works on macOS + Linux)
|
|
320
|
+
if command -v stat >/dev/null 2>&1; then
|
|
321
|
+
# macOS stat: -f %m gives epoch seconds; Linux stat: -c %Y
|
|
322
|
+
src_mtime=$(stat -f %m "$file" 2>/dev/null || stat -c %Y "$file" 2>/dev/null || echo "0")
|
|
323
|
+
purpose_mtime=$(stat -f %m "$covering_purpose" 2>/dev/null || stat -c %Y "$covering_purpose" 2>/dev/null || echo "0")
|
|
324
|
+
if [ "$src_mtime" -gt "$purpose_mtime" ] 2>/dev/null; then
|
|
325
|
+
_record_stale_purpose "$covering_purpose"
|
|
326
|
+
fi
|
|
327
|
+
fi
|
|
328
|
+
fi
|
|
329
|
+
done
|
|
330
|
+
|
|
331
|
+
if [ -n "$STALE_PURPOSES" ]; then
|
|
332
|
+
VIOLATIONS="$VIOLATIONS
|
|
218
333
|
- These .purpose files cover modified source code but were NOT updated:
|
|
219
334
|
$STALE_PURPOSES
|
|
220
335
|
Update each with: #components, ~aspects (with anchors), !signals, \\$flows, ^gates."
|
|
221
|
-
|
|
222
|
-
fi
|
|
336
|
+
VIOLATION_COUNT=$((VIOLATION_COUNT + 1))
|
|
223
337
|
fi
|
|
224
338
|
|
|
225
339
|
# --- Check 6: Aspect coverage advisory ---
|
|
226
340
|
ADVISORY=""
|
|
227
341
|
HAS_ASPECTS=false
|
|
228
|
-
for purpose_file in $
|
|
342
|
+
for purpose_file in $PURPOSE_PATHS; do
|
|
229
343
|
if grep -qE '^\\s*~' "$purpose_file" 2>/dev/null; then
|
|
230
344
|
HAS_ASPECTS=true
|
|
231
345
|
break
|
|
@@ -320,21 +434,64 @@ LOREEOF
|
|
|
320
434
|
fi
|
|
321
435
|
fi
|
|
322
436
|
|
|
323
|
-
# ---
|
|
437
|
+
# --- Checks 8, 10, 11: Unified compliance check (single Node.js process) ---
|
|
438
|
+
# Replaces 3 separate subprocess calls (habits check, drift check, portal check)
|
|
439
|
+
# with a single \`paradigm compliance-check\` invocation.
|
|
440
|
+
COMPLIANCE_RESULT=""
|
|
324
441
|
if command -v paradigm >/dev/null 2>&1; then
|
|
325
|
-
paradigm
|
|
442
|
+
COMPLIANCE_RESULT=$(paradigm compliance-check --json --auto-heal --learn --trigger on-stop 2>/dev/null) || true
|
|
326
443
|
elif command -v npx >/dev/null 2>&1; then
|
|
327
|
-
npx paradigm
|
|
444
|
+
COMPLIANCE_RESULT=$(npx paradigm compliance-check --json --auto-heal --learn --trigger on-stop 2>/dev/null) || true
|
|
328
445
|
fi
|
|
329
446
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
447
|
+
if [ -n "$COMPLIANCE_RESULT" ]; then
|
|
448
|
+
# --- Check 8: Blocking habits (from unified result) ---
|
|
449
|
+
# The compliance-check command writes .habits-blocking marker internally
|
|
450
|
+
if [ -f ".paradigm/.habits-blocking" ]; then
|
|
451
|
+
HABITS_BLOCKING=$(cat ".paradigm/.habits-blocking")
|
|
452
|
+
VIOLATIONS="$VIOLATIONS
|
|
334
453
|
- Blocking habit(s) not satisfied:
|
|
335
454
|
$HABITS_BLOCKING
|
|
336
455
|
Call paradigm_habits_check with trigger=\\"on-stop\\" after fixing the above."
|
|
337
|
-
|
|
456
|
+
VIOLATION_COUNT=$((VIOLATION_COUNT + 1))
|
|
457
|
+
fi
|
|
458
|
+
|
|
459
|
+
# --- Check 10: Aspect drift (from unified result) ---
|
|
460
|
+
DRIFTED_COUNT=$(echo "$COMPLIANCE_RESULT" | grep -o '"driftedCount":[0-9]*' | sed 's/.*://')
|
|
461
|
+
HEALED_COUNT=$(echo "$COMPLIANCE_RESULT" | grep -o '"healedCount":[0-9]*' | sed 's/.*://')
|
|
462
|
+
|
|
463
|
+
if [ -n "$HEALED_COUNT" ] && [ "$HEALED_COUNT" -gt 0 ] 2>/dev/null; then
|
|
464
|
+
echo "[paradigm] Auto-healed $HEALED_COUNT shifted anchor(s)." >&2
|
|
465
|
+
fi
|
|
466
|
+
|
|
467
|
+
if [ -n "$DRIFTED_COUNT" ] && [ "$DRIFTED_COUNT" -gt 0 ] 2>/dev/null; then
|
|
468
|
+
VIOLATIONS="$VIOLATIONS
|
|
469
|
+
- $DRIFTED_COUNT aspect anchor(s) have drifted (content genuinely changed).
|
|
470
|
+
Run paradigm_aspect_check to review. Update anchors in .purpose files."
|
|
471
|
+
VIOLATION_COUNT=$((VIOLATION_COUNT + 1))
|
|
472
|
+
fi
|
|
473
|
+
|
|
474
|
+
# --- Check 11: Portal gate compliance (from unified result) ---
|
|
475
|
+
UNDECLARED=$(echo "$COMPLIANCE_RESULT" | grep -o '"usedButUndeclaredCount":[0-9]*' | sed 's/.*://')
|
|
476
|
+
|
|
477
|
+
if [ -n "$UNDECLARED" ] && [ "$UNDECLARED" -gt 0 ] 2>/dev/null; then
|
|
478
|
+
UNDECLARED_LIST=$(echo "$COMPLIANCE_RESULT" | grep -o '"usedButUndeclared":\\[[^]]*\\]' | sed 's/.*\\[//;s/\\].*//;s/"//g')
|
|
479
|
+
VIOLATIONS="$VIOLATIONS
|
|
480
|
+
- $UNDECLARED gate(s) used in code but not declared in portal.yaml:
|
|
481
|
+
$UNDECLARED_LIST
|
|
482
|
+
Add them to portal.yaml or use paradigm_portal_add_gate."
|
|
483
|
+
VIOLATION_COUNT=$((VIOLATION_COUNT + 1))
|
|
484
|
+
fi
|
|
485
|
+
else
|
|
486
|
+
# Fallback: check habits blocking marker even if compliance-check unavailable
|
|
487
|
+
if [ -f ".paradigm/.habits-blocking" ]; then
|
|
488
|
+
HABITS_BLOCKING=$(cat ".paradigm/.habits-blocking")
|
|
489
|
+
VIOLATIONS="$VIOLATIONS
|
|
490
|
+
- Blocking habit(s) not satisfied:
|
|
491
|
+
$HABITS_BLOCKING
|
|
492
|
+
Call paradigm_habits_check with trigger=\\"on-stop\\" after fixing the above."
|
|
493
|
+
VIOLATION_COUNT=$((VIOLATION_COUNT + 1))
|
|
494
|
+
fi
|
|
338
495
|
fi
|
|
339
496
|
|
|
340
497
|
# --- Check 9: Purpose-required patterns from config.yaml ---
|
|
@@ -435,55 +592,6 @@ PURPOSEEOF
|
|
|
435
592
|
fi
|
|
436
593
|
fi
|
|
437
594
|
|
|
438
|
-
# --- Check 10: Aspect drift detection with auto-heal ---
|
|
439
|
-
if [ -f ".paradigm/aspect-graph.db" ]; then
|
|
440
|
-
DRIFT_RESULT=""
|
|
441
|
-
if command -v paradigm >/dev/null 2>&1; then
|
|
442
|
-
DRIFT_RESULT=$(paradigm drift check --json --auto-heal 2>/dev/null) || true
|
|
443
|
-
elif command -v npx >/dev/null 2>&1; then
|
|
444
|
-
DRIFT_RESULT=$(npx paradigm drift check --json --auto-heal 2>/dev/null) || true
|
|
445
|
-
fi
|
|
446
|
-
|
|
447
|
-
if [ -n "$DRIFT_RESULT" ]; then
|
|
448
|
-
DRIFTED_COUNT=$(echo "$DRIFT_RESULT" | grep -o '"driftedCount":[0-9]*' | sed 's/.*://')
|
|
449
|
-
HEALED_COUNT=$(echo "$DRIFT_RESULT" | grep -o '"healedCount":[0-9]*' | sed 's/.*://')
|
|
450
|
-
|
|
451
|
-
if [ -n "$HEALED_COUNT" ] && [ "$HEALED_COUNT" -gt 0 ] 2>/dev/null; then
|
|
452
|
-
echo "[paradigm] Auto-healed $HEALED_COUNT shifted anchor(s)." >&2
|
|
453
|
-
fi
|
|
454
|
-
|
|
455
|
-
if [ -n "$DRIFTED_COUNT" ] && [ "$DRIFTED_COUNT" -gt 0 ] 2>/dev/null; then
|
|
456
|
-
VIOLATIONS="$VIOLATIONS
|
|
457
|
-
- $DRIFTED_COUNT aspect anchor(s) have drifted (content genuinely changed).
|
|
458
|
-
Run paradigm_aspect_check to review. Update anchors in .purpose files."
|
|
459
|
-
VIOLATION_COUNT=$((VIOLATION_COUNT + 1))
|
|
460
|
-
fi
|
|
461
|
-
fi
|
|
462
|
-
fi
|
|
463
|
-
|
|
464
|
-
# --- Check 11: Portal gate implementation compliance ---
|
|
465
|
-
if [ -f "portal.yaml" ]; then
|
|
466
|
-
PORTAL_RESULT=""
|
|
467
|
-
if command -v paradigm >/dev/null 2>&1; then
|
|
468
|
-
PORTAL_RESULT=$(paradigm portal check --json 2>/dev/null) || true
|
|
469
|
-
elif command -v npx >/dev/null 2>&1; then
|
|
470
|
-
PORTAL_RESULT=$(npx paradigm portal check --json 2>/dev/null) || true
|
|
471
|
-
fi
|
|
472
|
-
|
|
473
|
-
if [ -n "$PORTAL_RESULT" ]; then
|
|
474
|
-
UNDECLARED=$(echo "$PORTAL_RESULT" | grep -o '"usedButUndeclaredCount":[0-9]*' | sed 's/.*://')
|
|
475
|
-
|
|
476
|
-
if [ -n "$UNDECLARED" ] && [ "$UNDECLARED" -gt 0 ] 2>/dev/null; then
|
|
477
|
-
UNDECLARED_LIST=$(echo "$PORTAL_RESULT" | grep -o '"usedButUndeclared":\\[[^]]*\\]' | sed 's/.*\\[//;s/\\].*//;s/"//g')
|
|
478
|
-
VIOLATIONS="$VIOLATIONS
|
|
479
|
-
- $UNDECLARED gate(s) used in code but not declared in portal.yaml:
|
|
480
|
-
$UNDECLARED_LIST
|
|
481
|
-
Add them to portal.yaml or use paradigm_portal_add_gate."
|
|
482
|
-
VIOLATION_COUNT=$((VIOLATION_COUNT + 1))
|
|
483
|
-
fi
|
|
484
|
-
fi
|
|
485
|
-
fi
|
|
486
|
-
|
|
487
595
|
# --- Check 12: Graduation failure tracking ---
|
|
488
596
|
# When violations occur for graduated habits, record failures for auto-demotion.
|
|
489
597
|
if [ "$VIOLATION_COUNT" -gt 0 ] && [ -f ".paradigm/graduation.yaml" ]; then
|
|
@@ -531,8 +639,7 @@ if [ "$VIOLATION_COUNT" -gt 0 ] && [ -f ".paradigm/graduation.yaml" ]; then
|
|
|
531
639
|
fi
|
|
532
640
|
done
|
|
533
641
|
fi
|
|
534
|
-
|
|
535
|
-
var CLAUDE_CODE_STOP_HOOK = `#!/bin/sh
|
|
642
|
+
`,R=`#!/bin/sh
|
|
536
643
|
# Paradigm Claude Code Stop Hook (v2)
|
|
537
644
|
# Validates paradigm compliance before allowing the agent to finish.
|
|
538
645
|
# Installed by: paradigm hooks install --claude-code
|
|
@@ -585,7 +692,8 @@ fi
|
|
|
585
692
|
|
|
586
693
|
# --- Final verdict ---
|
|
587
694
|
if [ "$VIOLATION_COUNT" -gt 0 ]; then
|
|
588
|
-
# Emit compliance-violation event (fire-and-forget)
|
|
695
|
+
# Emit compliance-violation event (fire-and-forget, backgrounded)
|
|
696
|
+
# NOTE: Could be absorbed into compliance-check command in a future iteration.
|
|
589
697
|
if command -v paradigm >/dev/null 2>&1; then
|
|
590
698
|
paradigm event emit --type compliance-violation --source stop-hook --severity error --context "Stop hook: $VIOLATION_COUNT violation(s)" &
|
|
591
699
|
fi
|
|
@@ -618,6 +726,7 @@ if [ -n "$ADVISORY" ]; then
|
|
|
618
726
|
fi
|
|
619
727
|
|
|
620
728
|
# Auto-demote graduated habits with 3+ failures
|
|
729
|
+
# NOTE: Could be absorbed into compliance-check command in a future iteration.
|
|
621
730
|
if [ -d ".paradigm/.graduation-failures" ]; then
|
|
622
731
|
for fail_file in .paradigm/.graduation-failures/*; do
|
|
623
732
|
[ -f "$fail_file" ] || continue
|
|
@@ -637,144 +746,14 @@ fi
|
|
|
637
746
|
rm -f ".paradigm/.pending-review"
|
|
638
747
|
rm -f ".paradigm/.habits-blocking"
|
|
639
748
|
rm -f ".paradigm/.session-started"
|
|
749
|
+
rm -f ".paradigm/.purpose-paths"
|
|
640
750
|
|
|
641
751
|
exit 0
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
#
|
|
645
|
-
# Fires after Edit/Write tool calls.
|
|
646
|
-
# Tracks modified source files in .paradigm/.pending-review
|
|
647
|
-
# and outputs compliance reminders.
|
|
648
|
-
# Installed by: paradigm hooks install --claude-code
|
|
649
|
-
#
|
|
650
|
-
# Hook type: PostToolUse (matcher: Edit,Write)
|
|
651
|
-
# Exit 0 always (never blocks \u2014 advisory only)
|
|
652
|
-
#
|
|
653
|
-
# NOTE: stdin JSON can be 8KB+ (tool_response includes full file contents).
|
|
654
|
-
# Using echo "$INPUT" | jq corrupts the JSON via shell string handling.
|
|
655
|
-
# Fix: write stdin to temp file, use jq < file for all extractions.
|
|
656
|
-
|
|
657
|
-
# Save stdin to temp file \u2014 avoids echo corruption on large JSON
|
|
658
|
-
TMPINPUT=$(mktemp)
|
|
659
|
-
trap 'rm -f "$TMPINPUT"' EXIT
|
|
660
|
-
cat > "$TMPINPUT"
|
|
661
|
-
|
|
662
|
-
# Extract the file path from tool_input
|
|
663
|
-
if command -v jq >/dev/null 2>&1; then
|
|
664
|
-
FILE_PATH=$(jq -r '.tool_input.file_path // .tool_input.filePath // empty' < "$TMPINPUT" 2>/dev/null)
|
|
665
|
-
else
|
|
666
|
-
FILE_PATH=$(grep -o '"file_path"[[:space:]]*:[[:space:]]*"[^"]*"' "$TMPINPUT" | head -1 | sed 's/.*"file_path"[[:space:]]*:[[:space:]]*"//' | sed 's/"$//')
|
|
667
|
-
if [ -z "$FILE_PATH" ]; then
|
|
668
|
-
FILE_PATH=$(grep -o '"filePath"[[:space:]]*:[[:space:]]*"[^"]*"' "$TMPINPUT" | head -1 | sed 's/.*"filePath"[[:space:]]*:[[:space:]]*"//' | sed 's/"$//')
|
|
669
|
-
fi
|
|
670
|
-
fi
|
|
671
|
-
|
|
672
|
-
if [ -z "$FILE_PATH" ]; then
|
|
673
|
-
exit 0
|
|
674
|
-
fi
|
|
675
|
-
|
|
676
|
-
# Extract cwd from input
|
|
677
|
-
if command -v jq >/dev/null 2>&1; then
|
|
678
|
-
CWD=$(jq -r '.cwd // empty' < "$TMPINPUT" 2>/dev/null)
|
|
679
|
-
else
|
|
680
|
-
CWD=$(grep -o '"cwd"[[:space:]]*:[[:space:]]*"[^"]*"' "$TMPINPUT" | sed 's/.*"cwd"[[:space:]]*:[[:space:]]*"//' | sed 's/"$//')
|
|
681
|
-
fi
|
|
682
|
-
if [ -n "$CWD" ]; then
|
|
683
|
-
cd "$CWD" || exit 0
|
|
684
|
-
fi
|
|
685
|
-
|
|
686
|
-
# Skip non-source files
|
|
687
|
-
case "$FILE_PATH" in
|
|
688
|
-
*.purpose|portal.yaml|*.md|*.lock|*.log|*.json|*.yaml|*.yml|.gitignore|.env*) exit 0 ;;
|
|
689
|
-
esac
|
|
690
|
-
|
|
691
|
-
# Skip .paradigm, .claude, and .cursor directories
|
|
692
|
-
case "$FILE_PATH" in
|
|
693
|
-
*/.paradigm/*|.paradigm/*|*/.claude/*|.claude/*|*/.cursor/*|.cursor/*) exit 0 ;;
|
|
694
|
-
esac
|
|
695
|
-
|
|
696
|
-
# Not a paradigm project \u2014 pass
|
|
697
|
-
if [ ! -d ".paradigm" ]; then
|
|
698
|
-
exit 0
|
|
699
|
-
fi
|
|
700
|
-
|
|
701
|
-
# Pseudo-session-start: first edit of session emits one-time guidance
|
|
702
|
-
if [ ! -f ".paradigm/.session-started" ]; then
|
|
703
|
-
PREV_PENDING=$(cat .paradigm/.pending-review 2>/dev/null | wc -l | tr -d ' ')
|
|
704
|
-
if [ "$PREV_PENDING" -gt 0 ] 2>/dev/null; then
|
|
705
|
-
echo "[paradigm] Session started. $PREV_PENDING uncovered edit(s) from last session." >&2
|
|
706
|
-
fi
|
|
707
|
-
touch ".paradigm/.session-started"
|
|
708
|
-
fi
|
|
709
|
-
|
|
710
|
-
# Convert to relative path (strip project root prefix)
|
|
711
|
-
PROJECT_ROOT="$(pwd)"
|
|
712
|
-
REL_PATH="$FILE_PATH"
|
|
713
|
-
case "$FILE_PATH" in
|
|
714
|
-
"$PROJECT_ROOT"/*) REL_PATH=$(echo "$FILE_PATH" | sed "s|^$PROJECT_ROOT/||") ;;
|
|
715
|
-
esac
|
|
716
|
-
|
|
717
|
-
# If still absolute, file is outside project \u2014 skip
|
|
718
|
-
case "$REL_PATH" in
|
|
719
|
-
/*) exit 0 ;;
|
|
720
|
-
esac
|
|
721
|
-
|
|
722
|
-
# Emit file-modified event (fire-and-forget)
|
|
723
|
-
if command -v paradigm >/dev/null 2>&1; then
|
|
724
|
-
paradigm event emit --type file-modified --source post-write-hook --path "$REL_PATH" &
|
|
725
|
-
fi
|
|
726
|
-
|
|
727
|
-
# Track: append to .paradigm/.pending-review (deduplicated)
|
|
728
|
-
PENDING_FILE=".paradigm/.pending-review"
|
|
729
|
-
if [ -f "$PENDING_FILE" ]; then
|
|
730
|
-
if ! grep -qxF "$REL_PATH" "$PENDING_FILE" 2>/dev/null; then
|
|
731
|
-
echo "$REL_PATH" >> "$PENDING_FILE"
|
|
732
|
-
fi
|
|
733
|
-
else
|
|
734
|
-
echo "$REL_PATH" > "$PENDING_FILE"
|
|
735
|
-
fi
|
|
736
|
-
|
|
737
|
-
# Count pending files
|
|
738
|
-
PENDING_COUNT=$(wc -l < "$PENDING_FILE" | tr -d ' ')
|
|
739
|
-
|
|
740
|
-
# Walk up from the file's directory to find a .purpose file
|
|
741
|
-
dir=$(dirname "$REL_PATH")
|
|
742
|
-
found_purpose=""
|
|
743
|
-
|
|
744
|
-
while [ "$dir" != "." ] && [ "$dir" != "/" ] && [ "$dir" != "" ]; do
|
|
745
|
-
if [ -f "$dir/.purpose" ]; then
|
|
746
|
-
found_purpose="$dir/.purpose"
|
|
747
|
-
break
|
|
748
|
-
fi
|
|
749
|
-
dir=$(dirname "$dir")
|
|
750
|
-
done
|
|
751
|
-
|
|
752
|
-
# Check root .purpose
|
|
753
|
-
if [ -z "$found_purpose" ] && [ -f ".purpose" ]; then
|
|
754
|
-
found_purpose=".purpose"
|
|
755
|
-
fi
|
|
756
|
-
|
|
757
|
-
if [ -z "$found_purpose" ]; then
|
|
758
|
-
file_dir=$(dirname "$REL_PATH")
|
|
759
|
-
echo "" >&2
|
|
760
|
-
echo "[paradigm] No .purpose file covers $file_dir/" >&2
|
|
761
|
-
echo " Create one: paradigm_purpose_init + paradigm_purpose_add_component" >&2
|
|
762
|
-
echo " $PENDING_COUNT file(s) pending review. The stop hook WILL BLOCK." >&2
|
|
763
|
-
elif [ "$PENDING_COUNT" -gt 0 ] && [ "$((PENDING_COUNT % 3))" -eq 0 ]; then
|
|
764
|
-
echo "" >&2
|
|
765
|
-
echo "[paradigm] $PENDING_COUNT source file(s) modified. Update $found_purpose:" >&2
|
|
766
|
-
echo " -> #components, ~aspects (with anchors), !signals, \\$flows, ^gates" >&2
|
|
767
|
-
echo " The stop hook WILL BLOCK if .purpose files aren't updated." >&2
|
|
768
|
-
fi
|
|
769
|
-
|
|
770
|
-
# Context budget heuristic: suggest handoff check at high edit counts
|
|
771
|
-
if [ "$PENDING_COUNT" -ge 30 ]; then
|
|
772
|
-
echo "[paradigm] ~$PENDING_COUNT edits this session. Consider preparing handoff." >&2
|
|
773
|
-
fi
|
|
774
|
-
|
|
752
|
+
`,U=`#!/bin/sh
|
|
753
|
+
# Legacy afterFileEdit hook \u2014 replaced by paradigm-posttooluse.sh (postToolUse)
|
|
754
|
+
# Kept as a no-op because Claude Code expects the file to exist.
|
|
775
755
|
exit 0
|
|
776
|
-
|
|
777
|
-
var CLAUDE_CODE_PRECOMMIT_HOOK = `#!/bin/sh
|
|
756
|
+
`,A=`#!/bin/sh
|
|
778
757
|
# Paradigm Claude Code Pre-Commit Hook
|
|
779
758
|
# Intercepts git commit Bash calls and auto-rebuilds the index.
|
|
780
759
|
# Installed by: paradigm hooks install --claude-code
|
|
@@ -819,8 +798,7 @@ done
|
|
|
819
798
|
|
|
820
799
|
# Never block \u2014 exit 0
|
|
821
800
|
exit 0
|
|
822
|
-
|
|
823
|
-
var CURSOR_SESSION_START_HOOK = `#!/bin/sh
|
|
801
|
+
`,P=`#!/bin/sh
|
|
824
802
|
# Paradigm Cursor Session Start Hook
|
|
825
803
|
# Fires before the agent does anything \u2014 injects additional_context
|
|
826
804
|
# that acts as a deterministic system prompt (not subject to context compaction).
|
|
@@ -920,8 +898,7 @@ fi
|
|
|
920
898
|
printf '{"additional_context":"%s","continue":true}\\n' "$CONTEXT"
|
|
921
899
|
|
|
922
900
|
exit 0
|
|
923
|
-
|
|
924
|
-
var CURSOR_STOP_HOOK = `#!/bin/sh
|
|
901
|
+
`,v=`#!/bin/sh
|
|
925
902
|
# Paradigm Cursor Stop Hook (v2)
|
|
926
903
|
# Validates paradigm compliance before allowing the agent to finish.
|
|
927
904
|
# Installed by: paradigm hooks install --cursor
|
|
@@ -1050,104 +1027,14 @@ rm -f ".paradigm/.pending-review"
|
|
|
1050
1027
|
rm -f ".paradigm/.habits-blocking"
|
|
1051
1028
|
rm -f ".paradigm/.stop-hook-active"
|
|
1052
1029
|
rm -f ".paradigm/.session-started"
|
|
1030
|
+
rm -f ".paradigm/.purpose-paths"
|
|
1053
1031
|
|
|
1054
1032
|
exit 0
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
#
|
|
1058
|
-
# Fires after file edits via Cursor's afterFileEdit hook type.
|
|
1059
|
-
# Installed by: paradigm hooks install --cursor
|
|
1060
|
-
#
|
|
1061
|
-
# IMPORTANT: Cursor ignores all output (stdout + stderr) from afterFileEdit hooks.
|
|
1062
|
-
# This hook's advisory messages are INVISIBLE to the agent. The postToolUse hook
|
|
1063
|
-
# (cursor-posttooluse.sh) is now the primary advisory mechanism.
|
|
1064
|
-
#
|
|
1065
|
-
# This hook is kept for backward compatibility and background file tracking only.
|
|
1066
|
-
# Both preToolUse and stop hooks depend on the .pending-review file this writes.
|
|
1067
|
-
#
|
|
1068
|
-
# Hook type: afterFileEdit
|
|
1069
|
-
# Exit 0 always (never blocks \u2014 advisory only)
|
|
1070
|
-
|
|
1071
|
-
# Read JSON from stdin (hook input)
|
|
1072
|
-
INPUT=$(cat)
|
|
1073
|
-
|
|
1074
|
-
# Extract file path from Cursor's afterFileEdit input
|
|
1075
|
-
if command -v jq >/dev/null 2>&1; then
|
|
1076
|
-
FILE_PATH=$(echo "$INPUT" | jq -r '.file // .filePath // empty' 2>/dev/null)
|
|
1077
|
-
else
|
|
1078
|
-
FILE_PATH=$(echo "$INPUT" | grep -o '"file"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*"file"[[:space:]]*:[[:space:]]*"//' | sed 's/"$//')
|
|
1079
|
-
if [ -z "$FILE_PATH" ]; then
|
|
1080
|
-
FILE_PATH=$(echo "$INPUT" | grep -o '"filePath"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*"filePath"[[:space:]]*:[[:space:]]*"//' | sed 's/"$//')
|
|
1081
|
-
fi
|
|
1082
|
-
fi
|
|
1083
|
-
|
|
1084
|
-
if [ -z "$FILE_PATH" ]; then
|
|
1085
|
-
exit 0
|
|
1086
|
-
fi
|
|
1087
|
-
|
|
1088
|
-
# Skip non-source files
|
|
1089
|
-
case "$FILE_PATH" in
|
|
1090
|
-
*.purpose|portal.yaml|*.md|*.lock|*.log|*.json|*.yaml|*.yml|.gitignore|.env*) exit 0 ;;
|
|
1091
|
-
esac
|
|
1092
|
-
|
|
1093
|
-
# Skip .paradigm, .claude, and .cursor directories
|
|
1094
|
-
case "$FILE_PATH" in
|
|
1095
|
-
*/.paradigm/*|.paradigm/*|*/.claude/*|.claude/*|*/.cursor/*|.cursor/*) exit 0 ;;
|
|
1096
|
-
esac
|
|
1097
|
-
|
|
1098
|
-
# Not a paradigm project \u2014 pass
|
|
1099
|
-
if [ ! -d ".paradigm" ]; then
|
|
1100
|
-
exit 0
|
|
1101
|
-
fi
|
|
1102
|
-
|
|
1103
|
-
# Convert to relative path (strip project root prefix)
|
|
1104
|
-
PROJECT_ROOT="$(pwd)"
|
|
1105
|
-
REL_PATH="$FILE_PATH"
|
|
1106
|
-
case "$FILE_PATH" in
|
|
1107
|
-
"$PROJECT_ROOT"/*) REL_PATH=$(echo "$FILE_PATH" | sed "s|^$PROJECT_ROOT/||") ;;
|
|
1108
|
-
esac
|
|
1109
|
-
|
|
1110
|
-
# If still absolute, file is outside project \u2014 skip
|
|
1111
|
-
case "$REL_PATH" in
|
|
1112
|
-
/*) exit 0 ;;
|
|
1113
|
-
esac
|
|
1114
|
-
|
|
1115
|
-
# Track: append to .paradigm/.pending-review (deduplicated)
|
|
1116
|
-
PENDING_FILE=".paradigm/.pending-review"
|
|
1117
|
-
if [ -f "$PENDING_FILE" ]; then
|
|
1118
|
-
if ! grep -qxF "$REL_PATH" "$PENDING_FILE" 2>/dev/null; then
|
|
1119
|
-
echo "$REL_PATH" >> "$PENDING_FILE"
|
|
1120
|
-
fi
|
|
1121
|
-
else
|
|
1122
|
-
echo "$REL_PATH" > "$PENDING_FILE"
|
|
1123
|
-
fi
|
|
1124
|
-
|
|
1125
|
-
# Count pending files
|
|
1126
|
-
PENDING_COUNT=$(wc -l < "$PENDING_FILE" | tr -d ' ')
|
|
1127
|
-
|
|
1128
|
-
# Walk up from the file's directory to find a .purpose file
|
|
1129
|
-
dir=$(dirname "$REL_PATH")
|
|
1130
|
-
found_purpose=""
|
|
1131
|
-
|
|
1132
|
-
while [ "$dir" != "." ] && [ "$dir" != "/" ] && [ "$dir" != "" ]; do
|
|
1133
|
-
if [ -f "$dir/.purpose" ]; then
|
|
1134
|
-
found_purpose="$dir/.purpose"
|
|
1135
|
-
break
|
|
1136
|
-
fi
|
|
1137
|
-
dir=$(dirname "$dir")
|
|
1138
|
-
done
|
|
1139
|
-
|
|
1140
|
-
# Check root .purpose
|
|
1141
|
-
if [ -z "$found_purpose" ] && [ -f ".purpose" ]; then
|
|
1142
|
-
found_purpose=".purpose"
|
|
1143
|
-
fi
|
|
1144
|
-
|
|
1145
|
-
# NOTE: No stderr output here \u2014 Cursor ignores afterFileEdit output.
|
|
1146
|
-
# Advisory messages are handled by cursor-posttooluse.sh (postToolUse hook).
|
|
1147
|
-
|
|
1033
|
+
`,D=`#!/bin/sh
|
|
1034
|
+
# Legacy afterFileEdit hook \u2014 replaced by paradigm-posttooluse.sh (postToolUse)
|
|
1035
|
+
# Kept as a no-op because Cursor expects the file to exist.
|
|
1148
1036
|
exit 0
|
|
1149
|
-
|
|
1150
|
-
var CURSOR_PRECOMMIT_HOOK = `#!/bin/sh
|
|
1037
|
+
`,b=`#!/bin/sh
|
|
1151
1038
|
# Paradigm Cursor Pre-Commit Hook
|
|
1152
1039
|
# Intercepts git commit shell executions and auto-rebuilds the index.
|
|
1153
1040
|
# Installed by: paradigm hooks install --cursor
|
|
@@ -1192,8 +1079,7 @@ done
|
|
|
1192
1079
|
|
|
1193
1080
|
# Never block \u2014 exit 0
|
|
1194
1081
|
exit 0
|
|
1195
|
-
|
|
1196
|
-
var CURSOR_PRETOOLUSE_HOOK = `#!/bin/sh
|
|
1082
|
+
`,L=`#!/bin/sh
|
|
1197
1083
|
# Paradigm Cursor PreToolUse Hook \u2014 Graduated Blocking
|
|
1198
1084
|
# Fires BEFORE the agent calls Edit or Write.
|
|
1199
1085
|
# Uses graduated enforcement based on uncovered source edits.
|
|
@@ -1338,8 +1224,7 @@ else
|
|
|
1338
1224
|
echo " Then retry your edit." >&2
|
|
1339
1225
|
exit 2
|
|
1340
1226
|
fi
|
|
1341
|
-
|
|
1342
|
-
var CURSOR_POSTTOOLUSE_HOOK = `#!/bin/sh
|
|
1227
|
+
`,w=`#!/bin/sh
|
|
1343
1228
|
# Paradigm Cursor PostToolUse Hook \u2014 Advisory Feedback
|
|
1344
1229
|
# Fires AFTER the agent calls Edit or Write.
|
|
1345
1230
|
# Tracks modified source files and outputs advisory the agent can see.
|
|
@@ -1463,165 +1348,9 @@ if [ "$PENDING_COUNT" -ge 30 ]; then
|
|
|
1463
1348
|
fi
|
|
1464
1349
|
|
|
1465
1350
|
exit 0
|
|
1466
|
-
`;
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
function isParadigmPluginActive() {
|
|
1470
|
-
try {
|
|
1471
|
-
const globalSettingsPath = path.join(os.homedir(), ".claude", "settings.json");
|
|
1472
|
-
if (!fs.existsSync(globalSettingsPath)) return { active: false };
|
|
1473
|
-
const settings = JSON.parse(fs.readFileSync(globalSettingsPath, "utf8"));
|
|
1474
|
-
const enabled = settings.enabledPlugins?.["paradigm@a-paradigm"];
|
|
1475
|
-
if (!enabled) return { active: false };
|
|
1476
|
-
const cacheBase = path.join(os.homedir(), ".claude", "plugins", "cache", "a-paradigm", "paradigm");
|
|
1477
|
-
if (!fs.existsSync(cacheBase)) return { active: false };
|
|
1478
|
-
const versions = fs.readdirSync(cacheBase).filter((d) => fs.statSync(path.join(cacheBase, d)).isDirectory()).sort().reverse();
|
|
1479
|
-
if (versions.length === 0) return { active: false };
|
|
1480
|
-
const latestCache = path.join(cacheBase, versions[0]);
|
|
1481
|
-
const hooksJson = path.join(latestCache, "hooks", "hooks.json");
|
|
1482
|
-
if (!fs.existsSync(hooksJson)) return { active: false };
|
|
1483
|
-
return { active: true, cacheVersion: versions[0] };
|
|
1484
|
-
} catch {
|
|
1485
|
-
return { active: false };
|
|
1486
|
-
}
|
|
1487
|
-
}
|
|
1488
|
-
function checkPluginVersionCompatibility() {
|
|
1489
|
-
try {
|
|
1490
|
-
const pluginInfo = isParadigmPluginActive();
|
|
1491
|
-
if (!pluginInfo.active || !pluginInfo.cacheVersion) {
|
|
1492
|
-
return { compatible: true };
|
|
1493
|
-
}
|
|
1494
|
-
const hooksJsonPath = path.join(
|
|
1495
|
-
os.homedir(),
|
|
1496
|
-
".claude",
|
|
1497
|
-
"plugins",
|
|
1498
|
-
"cache",
|
|
1499
|
-
"a-paradigm",
|
|
1500
|
-
"paradigm",
|
|
1501
|
-
pluginInfo.cacheVersion,
|
|
1502
|
-
"hooks.json"
|
|
1503
|
-
);
|
|
1504
|
-
if (!fs.existsSync(hooksJsonPath)) {
|
|
1505
|
-
return { compatible: true };
|
|
1506
|
-
}
|
|
1507
|
-
const hooksData = JSON.parse(fs.readFileSync(hooksJsonPath, "utf8"));
|
|
1508
|
-
const compatibleVersions = hooksData.compatibleVersions;
|
|
1509
|
-
if (!compatibleVersions) {
|
|
1510
|
-
return { compatible: true };
|
|
1511
|
-
}
|
|
1512
|
-
const currentVersion = getCurrentParadigmVersion();
|
|
1513
|
-
if (!currentVersion) {
|
|
1514
|
-
return { compatible: true };
|
|
1515
|
-
}
|
|
1516
|
-
const parts = compatibleVersions.split(/\s+/);
|
|
1517
|
-
for (const part of parts) {
|
|
1518
|
-
const match = part.match(/^(>=?|<=?)\s*(\d+\.\d+\.\d+)/);
|
|
1519
|
-
if (!match) continue;
|
|
1520
|
-
const [, op, ver] = match;
|
|
1521
|
-
const cmp = compareVersions(currentVersion, ver);
|
|
1522
|
-
if (op === ">=" && cmp < 0) return { compatible: false, message: `Plugin requires paradigm ${compatibleVersions}, current: ${currentVersion}` };
|
|
1523
|
-
if (op === ">" && cmp <= 0) return { compatible: false, message: `Plugin requires paradigm ${compatibleVersions}, current: ${currentVersion}` };
|
|
1524
|
-
if (op === "<=" && cmp > 0) return { compatible: false, message: `Plugin requires paradigm ${compatibleVersions}, current: ${currentVersion}` };
|
|
1525
|
-
if (op === "<" && cmp >= 0) return { compatible: false, message: `Plugin requires paradigm ${compatibleVersions}, current: ${currentVersion}` };
|
|
1526
|
-
}
|
|
1527
|
-
return { compatible: true };
|
|
1528
|
-
} catch {
|
|
1529
|
-
return { compatible: true };
|
|
1530
|
-
}
|
|
1531
|
-
}
|
|
1532
|
-
function getCurrentParadigmVersion() {
|
|
1533
|
-
try {
|
|
1534
|
-
const pkgPath = path.join(path.dirname(new URL(import.meta.url).pathname), "..", "..", "package.json");
|
|
1535
|
-
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
|
|
1536
|
-
return pkg.version || null;
|
|
1537
|
-
} catch {
|
|
1538
|
-
return null;
|
|
1539
|
-
}
|
|
1540
|
-
}
|
|
1541
|
-
function compareVersions(a, b) {
|
|
1542
|
-
const pa = a.split(".").map(Number);
|
|
1543
|
-
const pb = b.split(".").map(Number);
|
|
1544
|
-
for (let i = 0; i < 3; i++) {
|
|
1545
|
-
if ((pa[i] || 0) < (pb[i] || 0)) return -1;
|
|
1546
|
-
if ((pa[i] || 0) > (pb[i] || 0)) return 1;
|
|
1547
|
-
}
|
|
1548
|
-
return 0;
|
|
1549
|
-
}
|
|
1550
|
-
function cleanupProjectClaudeCodeHooks(rootDir) {
|
|
1551
|
-
const removed = [];
|
|
1552
|
-
const claudeHooksDir = path.join(rootDir, ".claude", "hooks");
|
|
1553
|
-
if (fs.existsSync(claudeHooksDir)) {
|
|
1554
|
-
for (const hookName of ["paradigm-common.sh", "paradigm-stop.sh", "paradigm-precommit.sh", "paradigm-postwrite.sh"]) {
|
|
1555
|
-
const hookPath = path.join(claudeHooksDir, hookName);
|
|
1556
|
-
if (fs.existsSync(hookPath)) {
|
|
1557
|
-
fs.unlinkSync(hookPath);
|
|
1558
|
-
removed.push(hookName);
|
|
1559
|
-
}
|
|
1560
|
-
}
|
|
1561
|
-
try {
|
|
1562
|
-
const remaining = fs.readdirSync(claudeHooksDir);
|
|
1563
|
-
if (remaining.length === 0) {
|
|
1564
|
-
fs.rmdirSync(claudeHooksDir);
|
|
1565
|
-
}
|
|
1566
|
-
} catch {
|
|
1567
|
-
}
|
|
1568
|
-
}
|
|
1569
|
-
const settingsPath = path.join(rootDir, ".claude", "settings.json");
|
|
1570
|
-
if (fs.existsSync(settingsPath)) {
|
|
1571
|
-
try {
|
|
1572
|
-
const settings = JSON.parse(fs.readFileSync(settingsPath, "utf8"));
|
|
1573
|
-
const hooks = settings.hooks;
|
|
1574
|
-
if (hooks) {
|
|
1575
|
-
let modified = false;
|
|
1576
|
-
for (const [key, arr] of Object.entries(hooks)) {
|
|
1577
|
-
if (!Array.isArray(arr)) continue;
|
|
1578
|
-
const filtered = arr.filter(
|
|
1579
|
-
(h) => !JSON.stringify(h).includes("paradigm-")
|
|
1580
|
-
);
|
|
1581
|
-
if (filtered.length !== arr.length) {
|
|
1582
|
-
modified = true;
|
|
1583
|
-
if (filtered.length === 0) {
|
|
1584
|
-
delete hooks[key];
|
|
1585
|
-
} else {
|
|
1586
|
-
hooks[key] = filtered;
|
|
1587
|
-
}
|
|
1588
|
-
}
|
|
1589
|
-
}
|
|
1590
|
-
if (modified) {
|
|
1591
|
-
if (Object.keys(hooks).length === 0) {
|
|
1592
|
-
delete settings.hooks;
|
|
1593
|
-
} else {
|
|
1594
|
-
settings.hooks = hooks;
|
|
1595
|
-
}
|
|
1596
|
-
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf8");
|
|
1597
|
-
removed.push("settings.json hooks");
|
|
1598
|
-
}
|
|
1599
|
-
}
|
|
1600
|
-
} catch {
|
|
1601
|
-
}
|
|
1602
|
-
}
|
|
1603
|
-
return { cleaned: removed.length > 0, removed };
|
|
1604
|
-
}
|
|
1605
|
-
function validateBashSyntax(scriptContent, scriptName) {
|
|
1606
|
-
try {
|
|
1607
|
-
const tmpPath = path.join(os.tmpdir(), `paradigm-hook-validate-${Date.now()}.sh`);
|
|
1608
|
-
fs.writeFileSync(tmpPath, scriptContent, "utf8");
|
|
1609
|
-
try {
|
|
1610
|
-
execSync(`bash -n "${tmpPath}" 2>&1`, { encoding: "utf-8" });
|
|
1611
|
-
return null;
|
|
1612
|
-
} catch (err) {
|
|
1613
|
-
return `${scriptName}: bash syntax error \u2014 ${err.message?.split("\n")[0] || "unknown error"}`;
|
|
1614
|
-
} finally {
|
|
1615
|
-
try {
|
|
1616
|
-
fs.unlinkSync(tmpPath);
|
|
1617
|
-
} catch {
|
|
1618
|
-
}
|
|
1619
|
-
}
|
|
1620
|
-
} catch {
|
|
1621
|
-
return null;
|
|
1622
|
-
}
|
|
1623
|
-
}
|
|
1624
|
-
var POST_COMMIT_HOOK = `#!/bin/sh
|
|
1351
|
+
`;function x(){try{let i=r.join(E.homedir(),".claude","settings.json");if(!e.existsSync(i))return {active:!1};if(!JSON.parse(e.readFileSync(i,"utf8")).enabledPlugins?.["paradigm@a-paradigm"])return {active:!1};let d=r.join(E.homedir(),".claude","plugins","cache","a-paradigm","paradigm");if(!e.existsSync(d))return {active:!1};let a=e.readdirSync(d).filter(s=>e.statSync(r.join(d,s)).isDirectory()).sort().reverse();if(a.length===0)return {active:!1};let p=r.join(d,a[0]),l=r.join(p,"hooks","hooks.json");return e.existsSync(l)?{active:!0,cacheVersion:a[0]}:{active:!1}}catch{return {active:false}}}function X(){try{let i=x();if(!i.active||!i.cacheVersion)return {compatible:!0};let h=r.join(E.homedir(),".claude","plugins","cache","a-paradigm","paradigm",i.cacheVersion,"hooks.json");if(!e.existsSync(h))return {compatible:!0};let d=JSON.parse(e.readFileSync(h,"utf8")).compatibleVersions;if(!d)return {compatible:!0};let a=W();if(!a)return {compatible:!0};let p=d.split(/\s+/);for(let l of p){let s=l.match(/^(>=?|<=?)\s*(\d+\.\d+\.\d+)/);if(!s)continue;let[,t,n]=s,f=Y(a,n);if(t===">="&&f<0)return {compatible:!1,message:`Plugin requires paradigm ${d}, current: ${a}`};if(t===">"&&f<=0)return {compatible:!1,message:`Plugin requires paradigm ${d}, current: ${a}`};if(t==="<="&&f>0)return {compatible:!1,message:`Plugin requires paradigm ${d}, current: ${a}`};if(t==="<"&&f>=0)return {compatible:!1,message:`Plugin requires paradigm ${d}, current: ${a}`}}return {compatible:!0}}catch{return {compatible:true}}}function W(){try{let i=r.join(r.dirname(new URL(import.meta.url).pathname),"..","..","package.json");return JSON.parse(e.readFileSync(i,"utf8")).version||null}catch{return null}}function Y(i,h){let c=i.split(".").map(Number),d=h.split(".").map(Number);for(let a=0;a<3;a++){if((c[a]||0)<(d[a]||0))return -1;if((c[a]||0)>(d[a]||0))return 1}return 0}function J(i){let h=[],c=r.join(i,".claude","hooks");if(e.existsSync(c)){for(let a of ["paradigm-common.sh","paradigm-stop.sh","paradigm-precommit.sh","paradigm-postwrite.sh"]){let p=r.join(c,a);e.existsSync(p)&&(e.unlinkSync(p),h.push(a));}try{e.readdirSync(c).length===0&&e.rmdirSync(c);}catch{}}let d=r.join(i,".claude","settings.json");if(e.existsSync(d))try{let a=JSON.parse(e.readFileSync(d,"utf8")),p=a.hooks;if(p){let l=!1;for(let[s,t]of Object.entries(p)){if(!Array.isArray(t))continue;let n=t.filter(f=>!JSON.stringify(f).includes("paradigm-"));n.length!==t.length&&(l=!0,n.length===0?delete p[s]:p[s]=n);}l&&(Object.keys(p).length===0?delete a.hooks:a.hooks=p,e.writeFileSync(d,JSON.stringify(a,null,2)+`
|
|
1352
|
+
`,"utf8"),h.push("settings.json hooks"));}}catch{}return {cleaned:h.length>0,removed:h}}function q(i,h){try{let c=r.join(E.tmpdir(),`paradigm-hook-validate-${Date.now()}.sh`);e.writeFileSync(c,i,"utf8");try{return execSync(`bash -n "${c}" 2>&1`,{encoding:"utf-8"}),null}catch(d){return `${h}: bash syntax error \u2014 ${d.message?.split(`
|
|
1353
|
+
`)[0]||"unknown error"}`}finally{try{e.unlinkSync(c);}catch{}}}catch{return null}}var H=`#!/bin/sh
|
|
1625
1354
|
# Paradigm post-commit hook - captures history from commits
|
|
1626
1355
|
# Installed by: paradigm hooks install
|
|
1627
1356
|
|
|
@@ -1705,8 +1434,7 @@ if [ -n "$SYMBOLS" ] && [ -d ".paradigm/history" ]; then
|
|
|
1705
1434
|
|
|
1706
1435
|
echo "[paradigm] History entry $ID recorded"
|
|
1707
1436
|
fi
|
|
1708
|
-
|
|
1709
|
-
var PRE_PUSH_HOOK = `#!/bin/sh
|
|
1437
|
+
`,j=`#!/bin/sh
|
|
1710
1438
|
# Paradigm pre-push hook - reindex history before pushing
|
|
1711
1439
|
# Installed by: paradigm hooks install
|
|
1712
1440
|
|
|
@@ -1714,563 +1442,25 @@ if [ -d ".paradigm/history" ] && [ -f ".paradigm/history/log.jsonl" ]; then
|
|
|
1714
1442
|
echo "[paradigm] Reindexing history..."
|
|
1715
1443
|
npx paradigm history reindex 2>/dev/null || true
|
|
1716
1444
|
fi
|
|
1717
|
-
`;
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
if (
|
|
1722
|
-
|
|
1723
|
-
}
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
{ name: "cursor-posttooluse", content: CURSOR_POSTTOOLUSE_HOOK }
|
|
1740
|
-
];
|
|
1741
|
-
for (const script of scriptsToValidate) {
|
|
1742
|
-
const err = validateBashSyntax(script.content, script.name);
|
|
1743
|
-
if (err) {
|
|
1744
|
-
console.log(chalk.red(`Hook syntax error: ${err}`));
|
|
1745
|
-
console.log(chalk.gray("Aborting installation. Fix the hook script and try again."));
|
|
1746
|
-
return;
|
|
1747
|
-
}
|
|
1748
|
-
}
|
|
1749
|
-
}
|
|
1750
|
-
const compat = checkPluginVersionCompatibility();
|
|
1751
|
-
if (!compat.compatible) {
|
|
1752
|
-
console.log(chalk.yellow(`
|
|
1753
|
-
\u26A0 ${compat.message}`));
|
|
1754
|
-
console.log(chalk.gray(" Hook installation will continue, but behavior may differ from plugin expectations.\n"));
|
|
1755
|
-
}
|
|
1756
|
-
if (!onlyClaudeCode && !onlyCursor) {
|
|
1757
|
-
const gitDir = path.join(rootDir, ".git");
|
|
1758
|
-
if (!fs.existsSync(gitDir)) {
|
|
1759
|
-
console.log(chalk.red("Not a git repository."));
|
|
1760
|
-
return;
|
|
1761
|
-
}
|
|
1762
|
-
const hooksDir = path.join(gitDir, "hooks");
|
|
1763
|
-
const installAllGit = !options.postCommit && !options.prePush && !options.claudeCode;
|
|
1764
|
-
const installed = [];
|
|
1765
|
-
if (installAllGit || options.postCommit) {
|
|
1766
|
-
const hookPath = path.join(hooksDir, "post-commit");
|
|
1767
|
-
if (dryRun) {
|
|
1768
|
-
const action = fs.existsSync(hookPath) && !options.force ? "skip (exists)" : "install";
|
|
1769
|
-
console.log(chalk.gray(` post-commit: ${action} \u2192 ${hookPath}`));
|
|
1770
|
-
} else {
|
|
1771
|
-
if (fs.existsSync(hookPath) && !options.force) {
|
|
1772
|
-
const content = fs.readFileSync(hookPath, "utf8");
|
|
1773
|
-
if (!content.includes("paradigm")) {
|
|
1774
|
-
console.log(chalk.yellow("post-commit hook exists. Use --force to overwrite."));
|
|
1775
|
-
} else {
|
|
1776
|
-
console.log(chalk.gray("post-commit hook already installed by paradigm"));
|
|
1777
|
-
}
|
|
1778
|
-
} else {
|
|
1779
|
-
fs.mkdirSync(hooksDir, { recursive: true });
|
|
1780
|
-
fs.writeFileSync(hookPath, POST_COMMIT_HOOK);
|
|
1781
|
-
fs.chmodSync(hookPath, "755");
|
|
1782
|
-
installed.push("post-commit");
|
|
1783
|
-
}
|
|
1784
|
-
}
|
|
1785
|
-
}
|
|
1786
|
-
if (installAllGit || options.prePush) {
|
|
1787
|
-
const hookPath = path.join(hooksDir, "pre-push");
|
|
1788
|
-
if (dryRun) {
|
|
1789
|
-
const action = fs.existsSync(hookPath) && !options.force ? "skip (exists)" : "install";
|
|
1790
|
-
console.log(chalk.gray(` pre-push: ${action} \u2192 ${hookPath}`));
|
|
1791
|
-
} else {
|
|
1792
|
-
if (fs.existsSync(hookPath) && !options.force) {
|
|
1793
|
-
const content = fs.readFileSync(hookPath, "utf8");
|
|
1794
|
-
if (!content.includes("paradigm")) {
|
|
1795
|
-
console.log(chalk.yellow("pre-push hook exists. Use --force to overwrite."));
|
|
1796
|
-
} else {
|
|
1797
|
-
console.log(chalk.gray("pre-push hook already installed by paradigm"));
|
|
1798
|
-
}
|
|
1799
|
-
} else {
|
|
1800
|
-
fs.mkdirSync(hooksDir, { recursive: true });
|
|
1801
|
-
fs.writeFileSync(hookPath, PRE_PUSH_HOOK);
|
|
1802
|
-
fs.chmodSync(hookPath, "755");
|
|
1803
|
-
installed.push("pre-push");
|
|
1804
|
-
}
|
|
1805
|
-
}
|
|
1806
|
-
}
|
|
1807
|
-
if (!dryRun && installed.length > 0) {
|
|
1808
|
-
console.log(chalk.green(`Git hooks installed: ${installed.join(", ")}`));
|
|
1809
|
-
}
|
|
1810
|
-
const historyDir = path.join(rootDir, ".paradigm/history");
|
|
1811
|
-
if (!fs.existsSync(historyDir) && !dryRun) {
|
|
1812
|
-
console.log(chalk.gray("Tip: Run `paradigm history init` to initialize history tracking"));
|
|
1813
|
-
}
|
|
1814
|
-
}
|
|
1815
|
-
const installAll = !options.postCommit && !options.prePush && !options.claudeCode && !options.cursor;
|
|
1816
|
-
if (installAll || options.claudeCode) {
|
|
1817
|
-
if (dryRun) {
|
|
1818
|
-
console.log(chalk.gray(" Claude Code hooks: would install paradigm-stop.sh, paradigm-precommit.sh, paradigm-postwrite.sh"));
|
|
1819
|
-
console.log(chalk.gray(` \u2192 ${path.join(rootDir, ".claude", "hooks")}/`));
|
|
1820
|
-
console.log(chalk.gray(" \u2192 Update .claude/settings.json with hook configuration"));
|
|
1821
|
-
} else {
|
|
1822
|
-
await installClaudeCodeHooks(rootDir, options.force);
|
|
1823
|
-
}
|
|
1824
|
-
}
|
|
1825
|
-
if (installAll || options.cursor) {
|
|
1826
|
-
if (dryRun) {
|
|
1827
|
-
console.log(chalk.gray(" Cursor hooks: would install paradigm-session-start.sh, paradigm-stop.sh, paradigm-precommit.sh, paradigm-postwrite.sh, paradigm-pretooluse.sh, paradigm-posttooluse.sh"));
|
|
1828
|
-
console.log(chalk.gray(` \u2192 ${path.join(rootDir, ".cursor", "hooks")}/`));
|
|
1829
|
-
console.log(chalk.gray(" \u2192 Update .cursor/hooks.json"));
|
|
1830
|
-
} else {
|
|
1831
|
-
await installCursorHooks(rootDir, options.force);
|
|
1832
|
-
}
|
|
1833
|
-
}
|
|
1834
|
-
if (dryRun) {
|
|
1835
|
-
console.log(chalk.cyan("\n [dry-run] No changes made.\n"));
|
|
1836
|
-
}
|
|
1837
|
-
}
|
|
1838
|
-
async function installClaudeCodeHooks(rootDir, force) {
|
|
1839
|
-
const plugin = isParadigmPluginActive();
|
|
1840
|
-
if (plugin.active) {
|
|
1841
|
-
console.log(chalk.cyan(` Paradigm plugin v${plugin.cacheVersion} is active \u2014 hooks are managed by the plugin.`));
|
|
1842
|
-
const { cleaned, removed } = cleanupProjectClaudeCodeHooks(rootDir);
|
|
1843
|
-
if (cleaned) {
|
|
1844
|
-
console.log(chalk.green(` Cleaned up stale project hooks: ${removed.join(", ")}`));
|
|
1845
|
-
} else {
|
|
1846
|
-
console.log(chalk.gray(" No stale project hooks to clean up."));
|
|
1847
|
-
}
|
|
1848
|
-
console.log(chalk.gray(" Plugin hooks auto-update with each session \u2014 no manual install needed."));
|
|
1849
|
-
return;
|
|
1850
|
-
}
|
|
1851
|
-
const claudeHooksDir = path.join(rootDir, ".claude", "hooks");
|
|
1852
|
-
fs.mkdirSync(claudeHooksDir, { recursive: true });
|
|
1853
|
-
const installed = [];
|
|
1854
|
-
const commonPath = path.join(claudeHooksDir, "paradigm-common.sh");
|
|
1855
|
-
fs.writeFileSync(commonPath, COMMON_HOOK, "utf8");
|
|
1856
|
-
fs.chmodSync(commonPath, "755");
|
|
1857
|
-
const hookScripts = [
|
|
1858
|
-
{ name: "paradigm-stop.sh", content: CLAUDE_CODE_STOP_HOOK },
|
|
1859
|
-
{ name: "paradigm-precommit.sh", content: CLAUDE_CODE_PRECOMMIT_HOOK },
|
|
1860
|
-
{ name: "paradigm-postwrite.sh", content: CLAUDE_CODE_POSTWRITE_HOOK }
|
|
1861
|
-
];
|
|
1862
|
-
for (const hook of hookScripts) {
|
|
1863
|
-
const destPath = path.join(claudeHooksDir, hook.name);
|
|
1864
|
-
if (fs.existsSync(destPath) && !force) {
|
|
1865
|
-
console.log(chalk.gray(` ${hook.name}: already installed`));
|
|
1866
|
-
continue;
|
|
1867
|
-
}
|
|
1868
|
-
fs.writeFileSync(destPath, hook.content, "utf8");
|
|
1869
|
-
fs.chmodSync(destPath, "755");
|
|
1870
|
-
installed.push(hook.name);
|
|
1871
|
-
}
|
|
1872
|
-
const settingsPath = path.join(rootDir, ".claude", "settings.json");
|
|
1873
|
-
let settings = {};
|
|
1874
|
-
if (fs.existsSync(settingsPath)) {
|
|
1875
|
-
try {
|
|
1876
|
-
settings = JSON.parse(fs.readFileSync(settingsPath, "utf8"));
|
|
1877
|
-
} catch {
|
|
1878
|
-
}
|
|
1879
|
-
}
|
|
1880
|
-
const hooks = settings.hooks || {};
|
|
1881
|
-
const stopHookEntry = {
|
|
1882
|
-
hooks: [{
|
|
1883
|
-
type: "command",
|
|
1884
|
-
command: `bash "$CLAUDE_PROJECT_DIR/.claude/hooks/paradigm-stop.sh"`,
|
|
1885
|
-
timeout: 10
|
|
1886
|
-
}]
|
|
1887
|
-
};
|
|
1888
|
-
const preCommitHookEntry = {
|
|
1889
|
-
matcher: "Bash",
|
|
1890
|
-
hooks: [{
|
|
1891
|
-
type: "command",
|
|
1892
|
-
command: `bash "$CLAUDE_PROJECT_DIR/.claude/hooks/paradigm-precommit.sh"`,
|
|
1893
|
-
timeout: 30
|
|
1894
|
-
}]
|
|
1895
|
-
};
|
|
1896
|
-
const stopHooks = hooks.Stop || [];
|
|
1897
|
-
const hasParadigmStop = stopHooks.some(
|
|
1898
|
-
(h) => JSON.stringify(h).includes("paradigm-stop.sh")
|
|
1899
|
-
);
|
|
1900
|
-
if (!hasParadigmStop) {
|
|
1901
|
-
stopHooks.push(stopHookEntry);
|
|
1902
|
-
}
|
|
1903
|
-
hooks.Stop = stopHooks;
|
|
1904
|
-
const preToolUseHooks = hooks.PreToolUse || [];
|
|
1905
|
-
const hasParadigmPrecommit = preToolUseHooks.some(
|
|
1906
|
-
(h) => JSON.stringify(h).includes("paradigm-precommit.sh")
|
|
1907
|
-
);
|
|
1908
|
-
if (!hasParadigmPrecommit) {
|
|
1909
|
-
preToolUseHooks.push(preCommitHookEntry);
|
|
1910
|
-
}
|
|
1911
|
-
hooks.PreToolUse = preToolUseHooks;
|
|
1912
|
-
const postWriteHookEntry = {
|
|
1913
|
-
matcher: "Edit,Write",
|
|
1914
|
-
hooks: [{
|
|
1915
|
-
type: "command",
|
|
1916
|
-
command: `bash "$CLAUDE_PROJECT_DIR/.claude/hooks/paradigm-postwrite.sh"`,
|
|
1917
|
-
timeout: 5
|
|
1918
|
-
}]
|
|
1919
|
-
};
|
|
1920
|
-
const postToolUseHooks = hooks.PostToolUse || [];
|
|
1921
|
-
const hasParadigmPostwrite = postToolUseHooks.some(
|
|
1922
|
-
(h) => JSON.stringify(h).includes("paradigm-postwrite.sh")
|
|
1923
|
-
);
|
|
1924
|
-
if (!hasParadigmPostwrite) {
|
|
1925
|
-
postToolUseHooks.push(postWriteHookEntry);
|
|
1926
|
-
}
|
|
1927
|
-
hooks.PostToolUse = postToolUseHooks;
|
|
1928
|
-
settings.hooks = hooks;
|
|
1929
|
-
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf8");
|
|
1930
|
-
if (installed.length > 0) {
|
|
1931
|
-
console.log(chalk.green(`Claude Code hooks installed: ${installed.join(", ")}`));
|
|
1932
|
-
}
|
|
1933
|
-
console.log(chalk.green("Claude Code settings.json updated with hook configuration"));
|
|
1934
|
-
}
|
|
1935
|
-
async function installCursorHooks(rootDir, force) {
|
|
1936
|
-
const cursorHooksDir = path.join(rootDir, ".cursor", "hooks");
|
|
1937
|
-
fs.mkdirSync(cursorHooksDir, { recursive: true });
|
|
1938
|
-
const installed = [];
|
|
1939
|
-
const cursorCommonPath = path.join(cursorHooksDir, "paradigm-common.sh");
|
|
1940
|
-
fs.writeFileSync(cursorCommonPath, COMMON_HOOK, "utf8");
|
|
1941
|
-
fs.chmodSync(cursorCommonPath, "755");
|
|
1942
|
-
const hookScripts = [
|
|
1943
|
-
{ name: "paradigm-session-start.sh", content: CURSOR_SESSION_START_HOOK },
|
|
1944
|
-
{ name: "paradigm-stop.sh", content: CURSOR_STOP_HOOK },
|
|
1945
|
-
{ name: "paradigm-precommit.sh", content: CURSOR_PRECOMMIT_HOOK },
|
|
1946
|
-
{ name: "paradigm-postwrite.sh", content: CURSOR_POSTWRITE_HOOK },
|
|
1947
|
-
{ name: "paradigm-pretooluse.sh", content: CURSOR_PRETOOLUSE_HOOK },
|
|
1948
|
-
{ name: "paradigm-posttooluse.sh", content: CURSOR_POSTTOOLUSE_HOOK }
|
|
1949
|
-
];
|
|
1950
|
-
for (const hook of hookScripts) {
|
|
1951
|
-
const destPath = path.join(cursorHooksDir, hook.name);
|
|
1952
|
-
if (fs.existsSync(destPath) && !force) {
|
|
1953
|
-
console.log(chalk.gray(` ${hook.name}: already installed (Cursor)`));
|
|
1954
|
-
continue;
|
|
1955
|
-
}
|
|
1956
|
-
fs.writeFileSync(destPath, hook.content, "utf8");
|
|
1957
|
-
fs.chmodSync(destPath, "755");
|
|
1958
|
-
installed.push(hook.name);
|
|
1959
|
-
}
|
|
1960
|
-
const hooksJsonPath = path.join(rootDir, ".cursor", "hooks.json");
|
|
1961
|
-
let hooksConfig = {};
|
|
1962
|
-
if (fs.existsSync(hooksJsonPath)) {
|
|
1963
|
-
try {
|
|
1964
|
-
hooksConfig = JSON.parse(fs.readFileSync(hooksJsonPath, "utf8"));
|
|
1965
|
-
} catch {
|
|
1966
|
-
}
|
|
1967
|
-
}
|
|
1968
|
-
hooksConfig.version = 1;
|
|
1969
|
-
const hooks = hooksConfig.hooks || {};
|
|
1970
|
-
const paradigmSessionStartEntry = {
|
|
1971
|
-
command: ".cursor/hooks/paradigm-session-start.sh",
|
|
1972
|
-
timeout: 5
|
|
1973
|
-
};
|
|
1974
|
-
const paradigmStopEntry = {
|
|
1975
|
-
command: ".cursor/hooks/paradigm-stop.sh",
|
|
1976
|
-
timeout: 10,
|
|
1977
|
-
loop_limit: 3
|
|
1978
|
-
};
|
|
1979
|
-
const paradigmPostwriteEntry = {
|
|
1980
|
-
command: ".cursor/hooks/paradigm-postwrite.sh",
|
|
1981
|
-
timeout: 5
|
|
1982
|
-
};
|
|
1983
|
-
const paradigmPrecommitEntry = {
|
|
1984
|
-
command: ".cursor/hooks/paradigm-precommit.sh",
|
|
1985
|
-
matcher: "git commit",
|
|
1986
|
-
timeout: 30
|
|
1987
|
-
};
|
|
1988
|
-
const sessionStartHooks = hooks.sessionStart || [];
|
|
1989
|
-
const hasParadigmSessionStart = sessionStartHooks.some(
|
|
1990
|
-
(h) => JSON.stringify(h).includes("paradigm-session-start.sh")
|
|
1991
|
-
);
|
|
1992
|
-
if (!hasParadigmSessionStart) {
|
|
1993
|
-
sessionStartHooks.push(paradigmSessionStartEntry);
|
|
1994
|
-
}
|
|
1995
|
-
hooks.sessionStart = sessionStartHooks;
|
|
1996
|
-
const stopHooks = hooks.stop || [];
|
|
1997
|
-
const hasParadigmStop = stopHooks.some(
|
|
1998
|
-
(h) => JSON.stringify(h).includes("paradigm-stop.sh")
|
|
1999
|
-
);
|
|
2000
|
-
if (!hasParadigmStop) {
|
|
2001
|
-
stopHooks.push(paradigmStopEntry);
|
|
2002
|
-
}
|
|
2003
|
-
hooks.stop = stopHooks;
|
|
2004
|
-
const afterFileEditHooks = hooks.afterFileEdit || [];
|
|
2005
|
-
const hasParadigmPostwrite = afterFileEditHooks.some(
|
|
2006
|
-
(h) => JSON.stringify(h).includes("paradigm-postwrite.sh")
|
|
2007
|
-
);
|
|
2008
|
-
if (!hasParadigmPostwrite) {
|
|
2009
|
-
afterFileEditHooks.push(paradigmPostwriteEntry);
|
|
2010
|
-
}
|
|
2011
|
-
hooks.afterFileEdit = afterFileEditHooks;
|
|
2012
|
-
const paradigmPretoolUseEntry = {
|
|
2013
|
-
command: ".cursor/hooks/paradigm-pretooluse.sh",
|
|
2014
|
-
matcher: "Edit|Write",
|
|
2015
|
-
timeout: 5
|
|
2016
|
-
};
|
|
2017
|
-
const preToolUseHooks = hooks.preToolUse || [];
|
|
2018
|
-
const hasParadigmPretoolUse = preToolUseHooks.some(
|
|
2019
|
-
(h) => JSON.stringify(h).includes("paradigm-pretooluse.sh")
|
|
2020
|
-
);
|
|
2021
|
-
if (!hasParadigmPretoolUse) {
|
|
2022
|
-
preToolUseHooks.push(paradigmPretoolUseEntry);
|
|
2023
|
-
}
|
|
2024
|
-
hooks.preToolUse = preToolUseHooks;
|
|
2025
|
-
const paradigmPosttoolUseEntry = {
|
|
2026
|
-
command: ".cursor/hooks/paradigm-posttooluse.sh",
|
|
2027
|
-
matcher: "Edit|Write",
|
|
2028
|
-
timeout: 5
|
|
2029
|
-
};
|
|
2030
|
-
const postToolUseHooks = hooks.postToolUse || [];
|
|
2031
|
-
const hasParadigmPosttoolUse = postToolUseHooks.some(
|
|
2032
|
-
(h) => JSON.stringify(h).includes("paradigm-posttooluse.sh")
|
|
2033
|
-
);
|
|
2034
|
-
if (!hasParadigmPosttoolUse) {
|
|
2035
|
-
postToolUseHooks.push(paradigmPosttoolUseEntry);
|
|
2036
|
-
}
|
|
2037
|
-
hooks.postToolUse = postToolUseHooks;
|
|
2038
|
-
const beforeShellHooks = hooks.beforeShellExecution || [];
|
|
2039
|
-
const hasParadigmPrecommit = beforeShellHooks.some(
|
|
2040
|
-
(h) => JSON.stringify(h).includes("paradigm-precommit.sh")
|
|
2041
|
-
);
|
|
2042
|
-
if (!hasParadigmPrecommit) {
|
|
2043
|
-
beforeShellHooks.push(paradigmPrecommitEntry);
|
|
2044
|
-
}
|
|
2045
|
-
hooks.beforeShellExecution = beforeShellHooks;
|
|
2046
|
-
hooksConfig.hooks = hooks;
|
|
2047
|
-
fs.writeFileSync(hooksJsonPath, JSON.stringify(hooksConfig, null, 2) + "\n", "utf8");
|
|
2048
|
-
if (installed.length > 0) {
|
|
2049
|
-
console.log(chalk.green(`Cursor hooks installed: ${installed.join(", ")}`));
|
|
2050
|
-
}
|
|
2051
|
-
console.log(chalk.green("Cursor hooks.json updated with hook configuration"));
|
|
2052
|
-
}
|
|
2053
|
-
async function hooksUninstallCommand(options = {}) {
|
|
2054
|
-
const rootDir = process.cwd();
|
|
2055
|
-
const dryRun = options.dryRun || false;
|
|
2056
|
-
if (dryRun) {
|
|
2057
|
-
console.log(chalk.cyan("\n [dry-run] Showing what would be removed:\n"));
|
|
2058
|
-
}
|
|
2059
|
-
if (!options.cursor) {
|
|
2060
|
-
const gitDir = path.join(rootDir, ".git");
|
|
2061
|
-
if (!fs.existsSync(gitDir)) {
|
|
2062
|
-
console.log(chalk.red("Not a git repository."));
|
|
2063
|
-
return;
|
|
2064
|
-
}
|
|
2065
|
-
const hooksDir = path.join(gitDir, "hooks");
|
|
2066
|
-
const removed = [];
|
|
2067
|
-
for (const hookName of ["post-commit", "pre-push"]) {
|
|
2068
|
-
const hookPath = path.join(hooksDir, hookName);
|
|
2069
|
-
if (fs.existsSync(hookPath)) {
|
|
2070
|
-
const content = fs.readFileSync(hookPath, "utf8");
|
|
2071
|
-
if (content.includes("paradigm")) {
|
|
2072
|
-
if (dryRun) {
|
|
2073
|
-
console.log(chalk.gray(` Would remove: ${hookPath}`));
|
|
2074
|
-
} else {
|
|
2075
|
-
fs.unlinkSync(hookPath);
|
|
2076
|
-
}
|
|
2077
|
-
removed.push(hookName);
|
|
2078
|
-
}
|
|
2079
|
-
}
|
|
2080
|
-
}
|
|
2081
|
-
if (!dryRun) {
|
|
2082
|
-
if (removed.length > 0) {
|
|
2083
|
-
console.log(chalk.green(`Git hooks removed: ${removed.join(", ")}`));
|
|
2084
|
-
} else {
|
|
2085
|
-
console.log(chalk.gray("No paradigm git hooks found to remove"));
|
|
2086
|
-
}
|
|
2087
|
-
} else if (removed.length === 0) {
|
|
2088
|
-
console.log(chalk.gray(" No paradigm git hooks to remove"));
|
|
2089
|
-
}
|
|
2090
|
-
}
|
|
2091
|
-
if (options.cursor) {
|
|
2092
|
-
const cursorHooksDir = path.join(rootDir, ".cursor", "hooks");
|
|
2093
|
-
const cursorRemoved = [];
|
|
2094
|
-
for (const hookName of ["paradigm-session-start.sh", "paradigm-stop.sh", "paradigm-precommit.sh", "paradigm-postwrite.sh", "paradigm-pretooluse.sh", "paradigm-posttooluse.sh"]) {
|
|
2095
|
-
const hookPath = path.join(cursorHooksDir, hookName);
|
|
2096
|
-
if (fs.existsSync(hookPath)) {
|
|
2097
|
-
if (dryRun) {
|
|
2098
|
-
console.log(chalk.gray(` Would remove: ${hookPath}`));
|
|
2099
|
-
} else {
|
|
2100
|
-
fs.unlinkSync(hookPath);
|
|
2101
|
-
}
|
|
2102
|
-
cursorRemoved.push(hookName);
|
|
2103
|
-
}
|
|
2104
|
-
}
|
|
2105
|
-
const hooksJsonPath = path.join(rootDir, ".cursor", "hooks.json");
|
|
2106
|
-
if (fs.existsSync(hooksJsonPath)) {
|
|
2107
|
-
if (dryRun) {
|
|
2108
|
-
console.log(chalk.gray(` Would clean paradigm entries from: ${hooksJsonPath}`));
|
|
2109
|
-
} else {
|
|
2110
|
-
try {
|
|
2111
|
-
const hooksConfig = JSON.parse(fs.readFileSync(hooksJsonPath, "utf8"));
|
|
2112
|
-
const hooks = hooksConfig.hooks || {};
|
|
2113
|
-
for (const key of ["sessionStart", "stop", "afterFileEdit", "beforeShellExecution", "preToolUse", "postToolUse"]) {
|
|
2114
|
-
if (Array.isArray(hooks[key])) {
|
|
2115
|
-
hooks[key] = hooks[key].filter(
|
|
2116
|
-
(h) => !JSON.stringify(h).includes("paradigm-")
|
|
2117
|
-
);
|
|
2118
|
-
if (hooks[key].length === 0) {
|
|
2119
|
-
delete hooks[key];
|
|
2120
|
-
}
|
|
2121
|
-
}
|
|
2122
|
-
}
|
|
2123
|
-
hooksConfig.hooks = hooks;
|
|
2124
|
-
fs.writeFileSync(hooksJsonPath, JSON.stringify(hooksConfig, null, 2) + "\n", "utf8");
|
|
2125
|
-
} catch {
|
|
2126
|
-
}
|
|
2127
|
-
}
|
|
2128
|
-
}
|
|
2129
|
-
if (!dryRun) {
|
|
2130
|
-
if (cursorRemoved.length > 0) {
|
|
2131
|
-
console.log(chalk.green(`Cursor hooks removed: ${cursorRemoved.join(", ")}`));
|
|
2132
|
-
} else {
|
|
2133
|
-
console.log(chalk.gray("No paradigm Cursor hooks found to remove"));
|
|
2134
|
-
}
|
|
2135
|
-
} else if (cursorRemoved.length === 0) {
|
|
2136
|
-
console.log(chalk.gray(" No paradigm Cursor hooks to remove"));
|
|
2137
|
-
}
|
|
2138
|
-
}
|
|
2139
|
-
if (dryRun) {
|
|
2140
|
-
console.log(chalk.cyan("\n [dry-run] No changes made.\n"));
|
|
2141
|
-
}
|
|
2142
|
-
}
|
|
2143
|
-
async function hooksStatusCommand() {
|
|
2144
|
-
const rootDir = process.cwd();
|
|
2145
|
-
const gitDir = path.join(rootDir, ".git");
|
|
2146
|
-
if (fs.existsSync(gitDir)) {
|
|
2147
|
-
console.log(chalk.magenta("\n Git Hooks Status\n"));
|
|
2148
|
-
const hooksDir = path.join(gitDir, "hooks");
|
|
2149
|
-
const hooks = ["post-commit", "pre-push"];
|
|
2150
|
-
for (const hookName of hooks) {
|
|
2151
|
-
const hookPath = path.join(hooksDir, hookName);
|
|
2152
|
-
if (fs.existsSync(hookPath)) {
|
|
2153
|
-
const content = fs.readFileSync(hookPath, "utf8");
|
|
2154
|
-
if (content.includes("paradigm")) {
|
|
2155
|
-
console.log(chalk.green(` ${hookName}: installed (paradigm)`));
|
|
2156
|
-
} else {
|
|
2157
|
-
console.log(chalk.yellow(` ${hookName}: exists (other)`));
|
|
2158
|
-
}
|
|
2159
|
-
} else {
|
|
2160
|
-
console.log(chalk.gray(` ${hookName}: not installed`));
|
|
2161
|
-
}
|
|
2162
|
-
}
|
|
2163
|
-
console.log();
|
|
2164
|
-
const historyDir = path.join(rootDir, ".paradigm/history");
|
|
2165
|
-
if (fs.existsSync(historyDir)) {
|
|
2166
|
-
const logPath = path.join(historyDir, "log.jsonl");
|
|
2167
|
-
if (fs.existsSync(logPath)) {
|
|
2168
|
-
const content = fs.readFileSync(logPath, "utf8");
|
|
2169
|
-
const count = content.split("\n").filter((l) => l.trim()).length;
|
|
2170
|
-
console.log(chalk.white(` History entries: ${count}`));
|
|
2171
|
-
}
|
|
2172
|
-
} else {
|
|
2173
|
-
console.log(chalk.gray(" History: not initialized"));
|
|
2174
|
-
console.log(chalk.gray(" Run `paradigm history init` to enable"));
|
|
2175
|
-
}
|
|
2176
|
-
} else {
|
|
2177
|
-
console.log(chalk.gray("\n Not a git repository (git hooks N/A)\n"));
|
|
2178
|
-
}
|
|
2179
|
-
console.log(chalk.magenta(" Claude Code Hooks Status\n"));
|
|
2180
|
-
const plugin = isParadigmPluginActive();
|
|
2181
|
-
if (plugin.active) {
|
|
2182
|
-
console.log(chalk.cyan(` Plugin: paradigm v${plugin.cacheVersion} (active)`));
|
|
2183
|
-
console.log(chalk.green(" Hooks are managed by the plugin \u2014 auto-updates with each session."));
|
|
2184
|
-
const claudeHooksDir = path.join(rootDir, ".claude", "hooks");
|
|
2185
|
-
const staleHooks = [];
|
|
2186
|
-
for (const hookName of ["paradigm-common.sh", "paradigm-stop.sh", "paradigm-precommit.sh", "paradigm-postwrite.sh"]) {
|
|
2187
|
-
if (fs.existsSync(path.join(claudeHooksDir, hookName))) {
|
|
2188
|
-
staleHooks.push(hookName);
|
|
2189
|
-
}
|
|
2190
|
-
}
|
|
2191
|
-
const settingsPath = path.join(rootDir, ".claude", "settings.json");
|
|
2192
|
-
let hasProjectHookEntries = false;
|
|
2193
|
-
if (fs.existsSync(settingsPath)) {
|
|
2194
|
-
try {
|
|
2195
|
-
const settings = JSON.parse(fs.readFileSync(settingsPath, "utf8"));
|
|
2196
|
-
hasProjectHookEntries = JSON.stringify(settings.hooks || {}).includes("paradigm-");
|
|
2197
|
-
} catch {
|
|
2198
|
-
}
|
|
2199
|
-
}
|
|
2200
|
-
if (staleHooks.length > 0 || hasProjectHookEntries) {
|
|
2201
|
-
console.log(chalk.yellow(` WARNING: Stale project hooks detected (${staleHooks.join(", ")}${hasProjectHookEntries ? ", settings.json entries" : ""})`));
|
|
2202
|
-
console.log(chalk.yellow(" These shadow the plugin hooks and may run outdated logic."));
|
|
2203
|
-
console.log(chalk.gray(" Run `paradigm hooks install --claude-code` to clean them up."));
|
|
2204
|
-
}
|
|
2205
|
-
} else {
|
|
2206
|
-
console.log(chalk.gray(" Plugin: not active (using project-level hooks)"));
|
|
2207
|
-
const claudeHooksDir = path.join(rootDir, ".claude", "hooks");
|
|
2208
|
-
const claudeHooks = ["paradigm-stop.sh", "paradigm-precommit.sh", "paradigm-postwrite.sh"];
|
|
2209
|
-
for (const hookName of claudeHooks) {
|
|
2210
|
-
const hookPath = path.join(claudeHooksDir, hookName);
|
|
2211
|
-
if (fs.existsSync(hookPath)) {
|
|
2212
|
-
console.log(chalk.green(` ${hookName}: installed`));
|
|
2213
|
-
} else {
|
|
2214
|
-
console.log(chalk.gray(` ${hookName}: not installed`));
|
|
2215
|
-
}
|
|
2216
|
-
}
|
|
2217
|
-
const settingsPath = path.join(rootDir, ".claude", "settings.json");
|
|
2218
|
-
if (fs.existsSync(settingsPath)) {
|
|
2219
|
-
try {
|
|
2220
|
-
const settings = JSON.parse(fs.readFileSync(settingsPath, "utf8"));
|
|
2221
|
-
const hooks = settings.hooks || {};
|
|
2222
|
-
const hasStop = JSON.stringify(hooks.Stop || []).includes("paradigm-stop.sh");
|
|
2223
|
-
const hasPrecommit = JSON.stringify(hooks.PreToolUse || []).includes("paradigm-precommit.sh");
|
|
2224
|
-
const hasPostwrite = JSON.stringify(hooks.PostToolUse || []).includes("paradigm-postwrite.sh");
|
|
2225
|
-
console.log(chalk.gray(` settings.json Stop hook: ${hasStop ? "configured" : "missing"}`));
|
|
2226
|
-
console.log(chalk.gray(` settings.json PreToolUse hook: ${hasPrecommit ? "configured" : "missing"}`));
|
|
2227
|
-
console.log(chalk.gray(` settings.json PostToolUse hook: ${hasPostwrite ? "configured" : "missing"}`));
|
|
2228
|
-
} catch {
|
|
2229
|
-
console.log(chalk.yellow(" settings.json: parse error"));
|
|
2230
|
-
}
|
|
2231
|
-
} else {
|
|
2232
|
-
console.log(chalk.gray(" settings.json: not found"));
|
|
2233
|
-
}
|
|
2234
|
-
}
|
|
2235
|
-
console.log(chalk.magenta("\n Cursor Hooks Status\n"));
|
|
2236
|
-
const cursorHooksDir = path.join(rootDir, ".cursor", "hooks");
|
|
2237
|
-
const cursorHooks = ["paradigm-session-start.sh", "paradigm-stop.sh", "paradigm-precommit.sh", "paradigm-postwrite.sh", "paradigm-pretooluse.sh", "paradigm-posttooluse.sh"];
|
|
2238
|
-
for (const hookName of cursorHooks) {
|
|
2239
|
-
const hookPath = path.join(cursorHooksDir, hookName);
|
|
2240
|
-
if (fs.existsSync(hookPath)) {
|
|
2241
|
-
console.log(chalk.green(` ${hookName}: installed`));
|
|
2242
|
-
} else {
|
|
2243
|
-
console.log(chalk.gray(` ${hookName}: not installed`));
|
|
2244
|
-
}
|
|
2245
|
-
}
|
|
2246
|
-
const cursorHooksJsonPath = path.join(rootDir, ".cursor", "hooks.json");
|
|
2247
|
-
if (fs.existsSync(cursorHooksJsonPath)) {
|
|
2248
|
-
try {
|
|
2249
|
-
const hooksJson = JSON.parse(fs.readFileSync(cursorHooksJsonPath, "utf8"));
|
|
2250
|
-
const hooks = hooksJson.hooks || {};
|
|
2251
|
-
const hasSessionStart = JSON.stringify(hooks.sessionStart || []).includes("paradigm-session-start.sh");
|
|
2252
|
-
const hasStop = JSON.stringify(hooks.stop || []).includes("paradigm-stop.sh");
|
|
2253
|
-
const hasPostwrite = JSON.stringify(hooks.afterFileEdit || []).includes("paradigm-postwrite.sh");
|
|
2254
|
-
const hasPrecommit = JSON.stringify(hooks.beforeShellExecution || []).includes("paradigm-precommit.sh");
|
|
2255
|
-
const hasPretoolUse = JSON.stringify(hooks.preToolUse || []).includes("paradigm-pretooluse.sh");
|
|
2256
|
-
const hasPosttoolUse = JSON.stringify(hooks.postToolUse || []).includes("paradigm-posttooluse.sh");
|
|
2257
|
-
console.log(chalk.gray(` hooks.json sessionStart: ${hasSessionStart ? "configured" : "missing"}`));
|
|
2258
|
-
console.log(chalk.gray(` hooks.json stop: ${hasStop ? "configured" : "missing"}`));
|
|
2259
|
-
console.log(chalk.gray(` hooks.json afterFileEdit: ${hasPostwrite ? "configured" : "missing"}`));
|
|
2260
|
-
console.log(chalk.gray(` hooks.json preToolUse: ${hasPretoolUse ? "configured" : "missing"}`));
|
|
2261
|
-
console.log(chalk.gray(` hooks.json postToolUse: ${hasPosttoolUse ? "configured" : "missing"}`));
|
|
2262
|
-
console.log(chalk.gray(` hooks.json beforeShellExecution: ${hasPrecommit ? "configured" : "missing"}`));
|
|
2263
|
-
} catch {
|
|
2264
|
-
console.log(chalk.yellow(" hooks.json: parse error"));
|
|
2265
|
-
}
|
|
2266
|
-
} else {
|
|
2267
|
-
console.log(chalk.gray(" hooks.json: not found"));
|
|
2268
|
-
}
|
|
2269
|
-
console.log();
|
|
2270
|
-
}
|
|
2271
|
-
|
|
2272
|
-
export {
|
|
2273
|
-
hooksInstallCommand,
|
|
2274
|
-
hooksUninstallCommand,
|
|
2275
|
-
hooksStatusCommand
|
|
2276
|
-
};
|
|
1445
|
+
`;async function te(i={}){let h=process.cwd(),c=i.dryRun||false;c&&console.log(o.cyan(`
|
|
1446
|
+
[dry-run] Showing what would be installed:
|
|
1447
|
+
`));let d=i.claudeCode&&!i.postCommit&&!i.prePush&&!i.cursor,a=i.cursor&&!i.postCommit&&!i.prePush&&!i.claudeCode;if(!c){let s=[{name:"post-commit",content:H},{name:"pre-push",content:j},{name:"paradigm-common",content:C},{name:"claude-code-stop",content:R},{name:"claude-code-precommit",content:A},{name:"claude-code-postwrite",content:U},{name:"cursor-session-start",content:P},{name:"cursor-stop",content:v},{name:"cursor-precommit",content:b},{name:"cursor-postwrite",content:D},{name:"cursor-pretooluse",content:L},{name:"cursor-posttooluse",content:w}];for(let t of s){let n=q(t.content,t.name);if(n){console.log(o.red(`Hook syntax error: ${n}`)),console.log(o.gray("Aborting installation. Fix the hook script and try again."));return}}}let p=X();if(p.compatible||(console.log(o.yellow(`
|
|
1448
|
+
\u26A0 ${p.message}`)),console.log(o.gray(` Hook installation will continue, but behavior may differ from plugin expectations.
|
|
1449
|
+
`))),!d&&!a){let s=r.join(h,".git");if(!e.existsSync(s)){console.log(o.red("Not a git repository."));return}let t=r.join(s,"hooks"),n=!i.postCommit&&!i.prePush&&!i.claudeCode,f=[];if(n||i.postCommit){let u=r.join(t,"post-commit");if(c){let g=e.existsSync(u)&&!i.force?"skip (exists)":"install";console.log(o.gray(` post-commit: ${g} \u2192 ${u}`));}else e.existsSync(u)&&!i.force?e.readFileSync(u,"utf8").includes("paradigm")?console.log(o.gray("post-commit hook already installed by paradigm")):console.log(o.yellow("post-commit hook exists. Use --force to overwrite.")):(e.mkdirSync(t,{recursive:true}),e.writeFileSync(u,H),e.chmodSync(u,"755"),f.push("post-commit"));}if(n||i.prePush){let u=r.join(t,"pre-push");if(c){let g=e.existsSync(u)&&!i.force?"skip (exists)":"install";console.log(o.gray(` pre-push: ${g} \u2192 ${u}`));}else e.existsSync(u)&&!i.force?e.readFileSync(u,"utf8").includes("paradigm")?console.log(o.gray("pre-push hook already installed by paradigm")):console.log(o.yellow("pre-push hook exists. Use --force to overwrite.")):(e.mkdirSync(t,{recursive:true}),e.writeFileSync(u,j),e.chmodSync(u,"755"),f.push("pre-push"));}!c&&f.length>0&&console.log(o.green(`Git hooks installed: ${f.join(", ")}`));let _=r.join(h,".paradigm/history");!e.existsSync(_)&&!c&&console.log(o.gray("Tip: Run `paradigm history init` to initialize history tracking"));}let l=!i.postCommit&&!i.prePush&&!i.claudeCode&&!i.cursor;(l||i.claudeCode)&&(c?(console.log(o.gray(" Claude Code hooks: would install paradigm-stop.sh, paradigm-precommit.sh, paradigm-postwrite.sh")),console.log(o.gray(` \u2192 ${r.join(h,".claude","hooks")}/`)),console.log(o.gray(" \u2192 Update .claude/settings.json with hook configuration"))):await B(h,i.force)),(l||i.cursor)&&(c?(console.log(o.gray(" Cursor hooks: would install paradigm-session-start.sh, paradigm-stop.sh, paradigm-precommit.sh, paradigm-postwrite.sh, paradigm-pretooluse.sh, paradigm-posttooluse.sh")),console.log(o.gray(` \u2192 ${r.join(h,".cursor","hooks")}/`)),console.log(o.gray(" \u2192 Update .cursor/hooks.json"))):await K(h,i.force)),c&&console.log(o.cyan(`
|
|
1450
|
+
[dry-run] No changes made.
|
|
1451
|
+
`));}async function B(i,h){let c=x();if(c.active){console.log(o.cyan(` Paradigm plugin v${c.cacheVersion} is active \u2014 hooks are managed by the plugin.`));let{cleaned:O,removed:$}=J(i);console.log(O?o.green(` Cleaned up stale project hooks: ${$.join(", ")}`):o.gray(" No stale project hooks to clean up.")),console.log(o.gray(" Plugin hooks auto-update with each session \u2014 no manual install needed."));return}let d=r.join(i,".claude","hooks");e.mkdirSync(d,{recursive:true});let a=[],p=r.join(d,"paradigm-common.sh");e.writeFileSync(p,C,"utf8"),e.chmodSync(p,"755");let l=[{name:"paradigm-stop.sh",content:R},{name:"paradigm-precommit.sh",content:A},{name:"paradigm-postwrite.sh",content:U}];for(let O of l){let $=r.join(d,O.name);if(e.existsSync($)&&!h){console.log(o.gray(` ${O.name}: already installed`));continue}e.writeFileSync($,O.content,"utf8"),e.chmodSync($,"755"),a.push(O.name);}let s=r.join(i,".claude","settings.json"),t={};if(e.existsSync(s))try{t=JSON.parse(e.readFileSync(s,"utf8"));}catch{}let n=t.hooks||{},f={hooks:[{type:"command",command:'bash "$CLAUDE_PROJECT_DIR/.claude/hooks/paradigm-stop.sh"',timeout:10}]},_={matcher:"Bash",hooks:[{type:"command",command:'bash "$CLAUDE_PROJECT_DIR/.claude/hooks/paradigm-precommit.sh"',timeout:30}]},u=n.Stop||[];u.some(O=>JSON.stringify(O).includes("paradigm-stop.sh"))||u.push(f),n.Stop=u;let S=n.PreToolUse||[];S.some(O=>JSON.stringify(O).includes("paradigm-precommit.sh"))||S.push(_),n.PreToolUse=S;let F={matcher:"Edit,Write",hooks:[{type:"command",command:'bash "$CLAUDE_PROJECT_DIR/.claude/hooks/paradigm-postwrite.sh"',timeout:5}]},T=n.PostToolUse||[];T.some(O=>JSON.stringify(O).includes("paradigm-postwrite.sh"))||T.push(F),n.PostToolUse=T,t.hooks=n,e.writeFileSync(s,JSON.stringify(t,null,2)+`
|
|
1452
|
+
`,"utf8"),a.length>0&&console.log(o.green(`Claude Code hooks installed: ${a.join(", ")}`)),console.log(o.green("Claude Code settings.json updated with hook configuration"));}async function K(i,h){let c=r.join(i,".cursor","hooks");e.mkdirSync(c,{recursive:true});let d=[],a=r.join(c,"paradigm-common.sh");e.writeFileSync(a,C,"utf8"),e.chmodSync(a,"755");let p=[{name:"paradigm-session-start.sh",content:P},{name:"paradigm-stop.sh",content:v},{name:"paradigm-precommit.sh",content:b},{name:"paradigm-postwrite.sh",content:D},{name:"paradigm-pretooluse.sh",content:L},{name:"paradigm-posttooluse.sh",content:w}];for(let m of p){let k=r.join(c,m.name);if(e.existsSync(k)&&!h){console.log(o.gray(` ${m.name}: already installed (Cursor)`));continue}e.writeFileSync(k,m.content,"utf8"),e.chmodSync(k,"755"),d.push(m.name);}let l=r.join(i,".cursor","hooks.json"),s={};if(e.existsSync(l))try{s=JSON.parse(e.readFileSync(l,"utf8"));}catch{}s.version=1;let t=s.hooks||{},n={command:".cursor/hooks/paradigm-session-start.sh",timeout:5},f={command:".cursor/hooks/paradigm-stop.sh",timeout:10,loop_limit:3},_={command:".cursor/hooks/paradigm-postwrite.sh",timeout:5},u={command:".cursor/hooks/paradigm-precommit.sh",matcher:"git commit",timeout:30},g=t.sessionStart||[];g.some(m=>JSON.stringify(m).includes("paradigm-session-start.sh"))||g.push(n),t.sessionStart=g;let I=t.stop||[];I.some(m=>JSON.stringify(m).includes("paradigm-stop.sh"))||I.push(f),t.stop=I;let T=t.afterFileEdit||[];T.some(m=>JSON.stringify(m).includes("paradigm-postwrite.sh"))||T.push(_),t.afterFileEdit=T;let O={command:".cursor/hooks/paradigm-pretooluse.sh",matcher:"Edit|Write",timeout:5},$=t.preToolUse||[];$.some(m=>JSON.stringify(m).includes("paradigm-pretooluse.sh"))||$.push(O),t.preToolUse=$;let V={command:".cursor/hooks/paradigm-posttooluse.sh",matcher:"Edit|Write",timeout:5},y=t.postToolUse||[];y.some(m=>JSON.stringify(m).includes("paradigm-posttooluse.sh"))||y.push(V),t.postToolUse=y;let N=t.beforeShellExecution||[];N.some(m=>JSON.stringify(m).includes("paradigm-precommit.sh"))||N.push(u),t.beforeShellExecution=N,s.hooks=t,e.writeFileSync(l,JSON.stringify(s,null,2)+`
|
|
1453
|
+
`,"utf8"),d.length>0&&console.log(o.green(`Cursor hooks installed: ${d.join(", ")}`)),console.log(o.green("Cursor hooks.json updated with hook configuration"));}async function re(i={}){let h=process.cwd(),c=i.dryRun||false;if(c&&console.log(o.cyan(`
|
|
1454
|
+
[dry-run] Showing what would be removed:
|
|
1455
|
+
`)),!i.cursor){let d=r.join(h,".git");if(!e.existsSync(d)){console.log(o.red("Not a git repository."));return}let a=r.join(d,"hooks"),p=[];for(let l of ["post-commit","pre-push"]){let s=r.join(a,l);e.existsSync(s)&&e.readFileSync(s,"utf8").includes("paradigm")&&(c?console.log(o.gray(` Would remove: ${s}`)):e.unlinkSync(s),p.push(l));}c?p.length===0&&console.log(o.gray(" No paradigm git hooks to remove")):p.length>0?console.log(o.green(`Git hooks removed: ${p.join(", ")}`)):console.log(o.gray("No paradigm git hooks found to remove"));}if(i.cursor){let d=r.join(h,".cursor","hooks"),a=[];for(let l of ["paradigm-session-start.sh","paradigm-stop.sh","paradigm-precommit.sh","paradigm-postwrite.sh","paradigm-pretooluse.sh","paradigm-posttooluse.sh"]){let s=r.join(d,l);e.existsSync(s)&&(c?console.log(o.gray(` Would remove: ${s}`)):e.unlinkSync(s),a.push(l));}let p=r.join(h,".cursor","hooks.json");if(e.existsSync(p))if(c)console.log(o.gray(` Would clean paradigm entries from: ${p}`));else try{let l=JSON.parse(e.readFileSync(p,"utf8")),s=l.hooks||{};for(let t of ["sessionStart","stop","afterFileEdit","beforeShellExecution","preToolUse","postToolUse"])Array.isArray(s[t])&&(s[t]=s[t].filter(n=>!JSON.stringify(n).includes("paradigm-")),s[t].length===0&&delete s[t]);l.hooks=s,e.writeFileSync(p,JSON.stringify(l,null,2)+`
|
|
1456
|
+
`,"utf8");}catch{}c?a.length===0&&console.log(o.gray(" No paradigm Cursor hooks to remove")):a.length>0?console.log(o.green(`Cursor hooks removed: ${a.join(", ")}`)):console.log(o.gray("No paradigm Cursor hooks found to remove"));}c&&console.log(o.cyan(`
|
|
1457
|
+
[dry-run] No changes made.
|
|
1458
|
+
`));}async function ae(){let i=process.cwd(),h=r.join(i,".git");if(e.existsSync(h)){console.log(o.magenta(`
|
|
1459
|
+
Git Hooks Status
|
|
1460
|
+
`));let l=r.join(h,"hooks"),s=["post-commit","pre-push"];for(let n of s){let f=r.join(l,n);e.existsSync(f)?e.readFileSync(f,"utf8").includes("paradigm")?console.log(o.green(` ${n}: installed (paradigm)`)):console.log(o.yellow(` ${n}: exists (other)`)):console.log(o.gray(` ${n}: not installed`));}console.log();let t=r.join(i,".paradigm/history");if(e.existsSync(t)){let n=r.join(t,"log.jsonl");if(e.existsSync(n)){let _=e.readFileSync(n,"utf8").split(`
|
|
1461
|
+
`).filter(u=>u.trim()).length;console.log(o.white(` History entries: ${_}`));}}else console.log(o.gray(" History: not initialized")),console.log(o.gray(" Run `paradigm history init` to enable"));}else console.log(o.gray(`
|
|
1462
|
+
Not a git repository (git hooks N/A)
|
|
1463
|
+
`));console.log(o.magenta(` Claude Code Hooks Status
|
|
1464
|
+
`));let c=x();if(c.active){console.log(o.cyan(` Plugin: paradigm v${c.cacheVersion} (active)`)),console.log(o.green(" Hooks are managed by the plugin \u2014 auto-updates with each session."));let l=r.join(i,".claude","hooks"),s=[];for(let f of ["paradigm-common.sh","paradigm-stop.sh","paradigm-precommit.sh","paradigm-postwrite.sh"])e.existsSync(r.join(l,f))&&s.push(f);let t=r.join(i,".claude","settings.json"),n=false;if(e.existsSync(t))try{let f=JSON.parse(e.readFileSync(t,"utf8"));n=JSON.stringify(f.hooks||{}).includes("paradigm-");}catch{}(s.length>0||n)&&(console.log(o.yellow(` WARNING: Stale project hooks detected (${s.join(", ")}${n?", settings.json entries":""})`)),console.log(o.yellow(" These shadow the plugin hooks and may run outdated logic.")),console.log(o.gray(" Run `paradigm hooks install --claude-code` to clean them up.")));}else {console.log(o.gray(" Plugin: not active (using project-level hooks)"));let l=r.join(i,".claude","hooks"),s=["paradigm-stop.sh","paradigm-precommit.sh","paradigm-postwrite.sh"];for(let n of s){let f=r.join(l,n);e.existsSync(f)?console.log(o.green(` ${n}: installed`)):console.log(o.gray(` ${n}: not installed`));}let t=r.join(i,".claude","settings.json");if(e.existsSync(t))try{let f=JSON.parse(e.readFileSync(t,"utf8")).hooks||{},_=JSON.stringify(f.Stop||[]).includes("paradigm-stop.sh"),u=JSON.stringify(f.PreToolUse||[]).includes("paradigm-precommit.sh"),g=JSON.stringify(f.PostToolUse||[]).includes("paradigm-postwrite.sh");console.log(o.gray(` settings.json Stop hook: ${_?"configured":"missing"}`)),console.log(o.gray(` settings.json PreToolUse hook: ${u?"configured":"missing"}`)),console.log(o.gray(` settings.json PostToolUse hook: ${g?"configured":"missing"}`));}catch{console.log(o.yellow(" settings.json: parse error"));}else console.log(o.gray(" settings.json: not found"));}console.log(o.magenta(`
|
|
1465
|
+
Cursor Hooks Status
|
|
1466
|
+
`));let d=r.join(i,".cursor","hooks"),a=["paradigm-session-start.sh","paradigm-stop.sh","paradigm-precommit.sh","paradigm-postwrite.sh","paradigm-pretooluse.sh","paradigm-posttooluse.sh"];for(let l of a){let s=r.join(d,l);e.existsSync(s)?console.log(o.green(` ${l}: installed`)):console.log(o.gray(` ${l}: not installed`));}let p=r.join(i,".cursor","hooks.json");if(e.existsSync(p))try{let s=JSON.parse(e.readFileSync(p,"utf8")).hooks||{},t=JSON.stringify(s.sessionStart||[]).includes("paradigm-session-start.sh"),n=JSON.stringify(s.stop||[]).includes("paradigm-stop.sh"),f=JSON.stringify(s.afterFileEdit||[]).includes("paradigm-postwrite.sh"),_=JSON.stringify(s.beforeShellExecution||[]).includes("paradigm-precommit.sh"),u=JSON.stringify(s.preToolUse||[]).includes("paradigm-pretooluse.sh"),g=JSON.stringify(s.postToolUse||[]).includes("paradigm-posttooluse.sh");console.log(o.gray(` hooks.json sessionStart: ${t?"configured":"missing"}`)),console.log(o.gray(` hooks.json stop: ${n?"configured":"missing"}`)),console.log(o.gray(` hooks.json afterFileEdit: ${f?"configured":"missing"}`)),console.log(o.gray(` hooks.json preToolUse: ${u?"configured":"missing"}`)),console.log(o.gray(` hooks.json postToolUse: ${g?"configured":"missing"}`)),console.log(o.gray(` hooks.json beforeShellExecution: ${_?"configured":"missing"}`));}catch{console.log(o.yellow(" hooks.json: parse error"));}else console.log(o.gray(" hooks.json: not found"));console.log();}export{te as a,re as b,ae as c};
|