@unbrained/pm-cli 2026.7.18 → 2026.7.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +2 -2
- package/CHANGELOG.md +17 -0
- package/dist/cli/commands/claim.js +6 -4
- package/dist/cli/commands/claim.js.map +1 -1
- package/dist/cli/commands/comments.js +5 -2
- package/dist/cli/commands/comments.js.map +1 -1
- package/dist/cli/commands/context.d.ts +10 -1
- package/dist/cli/commands/context.js +44 -6
- package/dist/cli/commands/context.js.map +1 -1
- package/dist/cli/commands/create.js +15 -4
- package/dist/cli/commands/create.js.map +1 -1
- package/dist/cli/commands/next.js +13 -3
- package/dist/cli/commands/next.js.map +1 -1
- package/dist/cli/commands/update.js +14 -3
- package/dist/cli/commands/update.js.map +1 -1
- package/dist/cli/error-guidance.js +23 -4
- package/dist/cli/error-guidance.js.map +1 -1
- package/dist/cli/extension-command-help.d.ts +11 -0
- package/dist/cli/extension-command-help.js +62 -2
- package/dist/cli/extension-command-help.js.map +1 -1
- package/dist/cli/main.d.ts +1 -0
- package/dist/cli/main.js +16 -11
- package/dist/cli/main.js.map +1 -1
- package/dist/cli-bundle/bundle-manifest.json +326 -350
- package/dist/cli-bundle/chunks/{append-5YF3TO7I.js → append-MBXHNWSX.js} +5 -5
- package/dist/cli-bundle/chunks/append-XUYF7NON.js +11 -0
- package/dist/cli-bundle/chunks/{chunk-BIRYX32V.js → chunk-2UCG5H6B.js} +3 -3
- package/dist/cli-bundle/chunks/{chunk-VE6ZSTQW.js → chunk-2XPDCXK5.js} +4 -4
- package/dist/cli-bundle/chunks/{chunk-I3INI567.js → chunk-3EZZTFL2.js} +909 -124
- package/dist/cli-bundle/chunks/chunk-3EZZTFL2.js.map +7 -0
- package/dist/cli-bundle/chunks/{chunk-GLZKZON6.js → chunk-3HSRP6T2.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-XWBD6DSR.js → chunk-3KPNOZOH.js} +23 -23
- package/dist/cli-bundle/chunks/{chunk-MR4SHYR4.js → chunk-3QNUDDY2.js} +104 -23
- package/dist/cli-bundle/chunks/chunk-3QNUDDY2.js.map +7 -0
- package/dist/cli-bundle/chunks/{chunk-SIPOACV5.js → chunk-46Z6FAVP.js} +888 -124
- package/dist/cli-bundle/chunks/chunk-46Z6FAVP.js.map +1 -0
- package/dist/cli-bundle/chunks/{chunk-HO4DLBNK.js → chunk-4M6RZJXF.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-RXPQ5Q23.js → chunk-4PSJVGRE.js} +11 -11
- package/dist/cli-bundle/chunks/{chunk-ADXDCAKP.js → chunk-5S6IZXK7.js} +146 -32
- package/dist/cli-bundle/chunks/{chunk-IL5SPRMH.js.map → chunk-5S6IZXK7.js.map} +7 -1
- package/dist/cli-bundle/chunks/chunk-66SRNEBK.js +143 -0
- package/dist/cli-bundle/chunks/chunk-66SRNEBK.js.map +7 -0
- package/dist/cli-bundle/chunks/{chunk-YFE7JHX3.js → chunk-6BNV3G6C.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-43UMFKCK.js → chunk-6V4T4RD3.js} +23 -23
- package/dist/cli-bundle/chunks/chunk-77XFQRTD.js +140 -0
- package/dist/cli-bundle/chunks/chunk-77XFQRTD.js.map +1 -0
- package/dist/cli-bundle/chunks/{chunk-EHJFUOXL.js → chunk-7B7IHMLH.js} +3 -3
- package/dist/cli-bundle/chunks/{chunk-I7DIDUSP.js → chunk-7CHWLT2J.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-L6FVNR7X.js → chunk-A3GAQLBH.js} +5 -5
- package/dist/cli-bundle/chunks/{chunk-B57RJHBZ.js → chunk-A4FVWFZY.js} +4 -4
- package/dist/cli-bundle/chunks/{chunk-D52ZN3BF.js → chunk-A5EQPNV7.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-TZAE66GQ.js → chunk-AGEBQRBG.js} +15 -15
- package/dist/cli-bundle/chunks/{chunk-WU3KAN6A.js → chunk-AQUNTB7G.js} +3 -3
- package/dist/cli-bundle/chunks/{chunk-OGVTB5VO.js → chunk-AR24KW26.js} +237 -36
- package/dist/cli-bundle/chunks/chunk-AR24KW26.js.map +7 -0
- package/dist/cli-bundle/chunks/{chunk-XWYQ2LT4.js → chunk-BBGR4FKQ.js} +4 -4
- package/dist/cli-bundle/chunks/{chunk-HTXXXF45.js → chunk-BDC4TW4B.js} +98 -24
- package/dist/cli-bundle/chunks/chunk-BDC4TW4B.js.map +1 -0
- package/dist/cli-bundle/chunks/{chunk-2FUOXSRN.js → chunk-BFJP4VYC.js} +4 -4
- package/dist/cli-bundle/chunks/{chunk-633PKXLT.js → chunk-BZKE2O5V.js} +3 -3
- package/dist/cli-bundle/chunks/{chunk-XPUTSGJU.js → chunk-CZA2DXCV.js} +230 -36
- package/dist/cli-bundle/chunks/chunk-CZA2DXCV.js.map +1 -0
- package/dist/cli-bundle/chunks/{chunk-KX62NMZC.js → chunk-D35WYXWC.js} +626 -5
- package/dist/cli-bundle/chunks/chunk-D35WYXWC.js.map +1 -0
- package/dist/cli-bundle/chunks/chunk-DOASIOQR.js +289 -0
- package/dist/cli-bundle/chunks/chunk-DOASIOQR.js.map +7 -0
- package/dist/cli-bundle/chunks/{chunk-L337QKWJ.js → chunk-DUDLSQFG.js} +5 -5
- package/dist/cli-bundle/chunks/{chunk-BVLOMU6O.js → chunk-E7KBMWEF.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-3QDR6ZLU.js → chunk-EAV3P54W.js} +9 -9
- package/dist/cli-bundle/chunks/{chunk-3QDR6ZLU.js.map → chunk-EAV3P54W.js.map} +2 -2
- package/dist/cli-bundle/chunks/{chunk-WQXRZMFN.js → chunk-EEECAV5M.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-35FHWD4C.js → chunk-EI3UIMZM.js} +4 -4
- package/dist/cli-bundle/chunks/{chunk-RGMWJLXF.js → chunk-EVAN5VJA.js} +8 -5
- package/dist/cli-bundle/chunks/{chunk-RGMWJLXF.js.map → chunk-EVAN5VJA.js.map} +2 -2
- package/dist/cli-bundle/chunks/{chunk-PT7MCCGD.js → chunk-FIUTBFC6.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-7H5NNCJ5.js → chunk-FQF6VVPH.js} +4 -4
- package/dist/cli-bundle/chunks/{chunk-6DYOZS6C.js → chunk-FQO5THHM.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-5HGZKQUL.js → chunk-FQODDTE7.js} +4 -4
- package/dist/cli-bundle/chunks/{chunk-67RO3H4N.js → chunk-G33XIMRT.js} +6 -6
- package/dist/cli-bundle/chunks/{chunk-D53RTYVI.js → chunk-GFZB5CLP.js} +20 -10
- package/dist/cli-bundle/chunks/chunk-GFZB5CLP.js.map +7 -0
- package/dist/cli-bundle/chunks/{chunk-QWBKN3QC.js → chunk-GKCEEXMA.js} +8 -8
- package/dist/cli-bundle/chunks/{chunk-DG2EQRIH.js → chunk-GRDK25BN.js} +7 -7
- package/dist/cli-bundle/chunks/{chunk-FXFCFL73.js → chunk-H3YKUVDR.js} +5 -5
- package/dist/cli-bundle/chunks/{chunk-IL5SPRMH.js → chunk-IEMXESIS.js} +123 -16
- package/dist/cli-bundle/chunks/chunk-IEMXESIS.js.map +1 -0
- package/dist/cli-bundle/chunks/{chunk-ARGDWQ4J.js → chunk-IGBBTPM5.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-QPGQNLPI.js → chunk-IR3GOO6E.js} +3842 -4109
- package/dist/cli-bundle/chunks/chunk-IR3GOO6E.js.map +1 -0
- package/dist/cli-bundle/chunks/{chunk-FY4RLHSC.js → chunk-IRJ6F23W.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-66MKH7SZ.js → chunk-IXG5CMBR.js} +4 -4
- package/dist/cli-bundle/chunks/{chunk-F3VC3GOV.js → chunk-JBW2S2C6.js} +2090 -253
- package/dist/cli-bundle/chunks/chunk-JBW2S2C6.js.map +7 -0
- package/dist/cli-bundle/chunks/{chunk-7UCY6DR5.js → chunk-JPWUZOMR.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-FVNWHUME.js → chunk-K2L6FZBX.js} +8 -8
- package/dist/cli-bundle/chunks/chunk-KGPLSHJD.js +286 -0
- package/dist/cli-bundle/chunks/chunk-KGPLSHJD.js.map +1 -0
- package/dist/cli-bundle/chunks/{chunk-YQEZWI3R.js → chunk-KZ5AC6B5.js} +5 -3
- package/dist/cli-bundle/chunks/chunk-KZ5AC6B5.js.map +7 -0
- package/dist/cli-bundle/chunks/{chunk-X2MGQMZO.js → chunk-LT5UWU7H.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-KH6QAHME.js → chunk-M4B4RK4J.js} +3 -3
- package/dist/cli-bundle/chunks/{chunk-QRZNCRNA.js → chunk-MI3346YW.js} +377 -240
- package/dist/cli-bundle/chunks/chunk-MI3346YW.js.map +1 -0
- package/dist/cli-bundle/chunks/{chunk-2XOSFSTH.js → chunk-MQOSMBWV.js} +5 -5
- package/dist/cli-bundle/chunks/{chunk-YIIIAKCE.js → chunk-MRXAHR4B.js} +28 -22
- package/dist/cli-bundle/chunks/chunk-MRXAHR4B.js.map +1 -0
- package/dist/cli-bundle/chunks/{chunk-7R6UIHYY.js → chunk-N2TEEOXJ.js} +5 -5
- package/dist/cli-bundle/chunks/{chunk-NTRQLE2R.js → chunk-N7FCFJ76.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-37DRDP2B.js → chunk-NPEYH6CE.js} +5 -5
- package/dist/cli-bundle/chunks/{chunk-GKPCTQYG.js → chunk-NTS2RKHN.js} +3942 -4216
- package/dist/cli-bundle/chunks/chunk-NTS2RKHN.js.map +7 -0
- package/dist/cli-bundle/chunks/{chunk-6VHUGVNP.js → chunk-ODEIDKGW.js} +2062 -246
- package/dist/cli-bundle/chunks/chunk-ODEIDKGW.js.map +1 -0
- package/dist/cli-bundle/chunks/{chunk-2CXL335K.js → chunk-OK7VSX3N.js} +3 -3
- package/dist/cli-bundle/chunks/{chunk-NNANAWFH.js → chunk-OKPZDH43.js} +3 -3
- package/dist/cli-bundle/chunks/{chunk-G6MYGULG.js → chunk-OKWJUL6F.js} +6 -6
- package/dist/cli-bundle/chunks/{chunk-HPAYDSR2.js → chunk-P24ZU5QV.js} +27 -21
- package/dist/cli-bundle/chunks/chunk-P24ZU5QV.js.map +7 -0
- package/dist/cli-bundle/chunks/{chunk-TGBTLGPX.js → chunk-Q4PSG2GV.js} +13 -4
- package/dist/cli-bundle/chunks/{chunk-TGBTLGPX.js.map → chunk-Q4PSG2GV.js.map} +1 -1
- package/dist/cli-bundle/chunks/{chunk-5UKQLQM2.js → chunk-Q5NHJ6RO.js} +6 -4
- package/dist/cli-bundle/chunks/chunk-Q5NHJ6RO.js.map +1 -0
- package/dist/cli-bundle/chunks/{chunk-D5XHO4Q7.js → chunk-Q6JPYR7I.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-P22HGFFI.js → chunk-QFG4MB7P.js} +5 -5
- package/dist/cli-bundle/chunks/{chunk-P22HGFFI.js.map → chunk-QFG4MB7P.js.map} +1 -1
- package/dist/cli-bundle/chunks/{chunk-IE5KRAKN.js → chunk-QQ77W23U.js} +4 -4
- package/dist/cli-bundle/chunks/{chunk-M7MVOKVV.js → chunk-QYGK2XQ3.js} +3 -3
- package/dist/cli-bundle/chunks/{chunk-646MQXFW.js → chunk-RLLOZAM2.js} +4 -4
- package/dist/cli-bundle/chunks/{chunk-646MQXFW.js.map → chunk-RLLOZAM2.js.map} +2 -2
- package/dist/cli-bundle/chunks/{chunk-X5YCTFKT.js → chunk-RWAIRGBC.js} +3 -3
- package/dist/cli-bundle/chunks/{chunk-W5E2UUSH.js → chunk-RX53WHFI.js} +3 -3
- package/dist/cli-bundle/chunks/{chunk-R5XTTZSJ.js → chunk-SBW7EQC4.js} +5 -5
- package/dist/cli-bundle/chunks/{chunk-TM5CIO3F.js → chunk-SGJB6PXA.js} +3 -3
- package/dist/cli-bundle/chunks/{chunk-DDFGYUCQ.js → chunk-STBCBDKF.js} +7 -7
- package/dist/cli-bundle/chunks/{chunk-EX7OQT3Y.js → chunk-SUNZKVAH.js} +10 -10
- package/dist/cli-bundle/chunks/{chunk-EX7OQT3Y.js.map → chunk-SUNZKVAH.js.map} +1 -1
- package/dist/cli-bundle/chunks/{chunk-FHOBCGQO.js → chunk-SVAWG7EE.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-6O44IN44.js → chunk-T6MOTLOJ.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-HSYV4ZYT.js → chunk-TELI67UP.js} +9 -6
- package/dist/cli-bundle/chunks/{chunk-HSYV4ZYT.js.map → chunk-TELI67UP.js.map} +1 -1
- package/dist/cli-bundle/chunks/{chunk-EWIT5WIC.js → chunk-U6RYD446.js} +11 -11
- package/dist/cli-bundle/chunks/{chunk-E4FXM2XB.js → chunk-UE7LK3RE.js} +5 -5
- package/dist/cli-bundle/chunks/{chunk-N33FD2UI.js → chunk-UNNCT5QY.js} +3 -3
- package/dist/cli-bundle/chunks/{chunk-2IPNL3DR.js → chunk-UOIFZ66L.js} +3 -3
- package/dist/cli-bundle/chunks/{chunk-LSOWTLEM.js → chunk-UU6EP25G.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-HYTOJW2Q.js → chunk-UW6HCMP2.js} +15 -15
- package/dist/cli-bundle/chunks/{chunk-47HXN6RX.js → chunk-UWAQI3B7.js} +3 -3
- package/dist/cli-bundle/chunks/{chunk-YKFHF37B.js → chunk-V4QHAMI5.js} +3 -3
- package/dist/cli-bundle/chunks/{chunk-VAHZIPWS.js → chunk-VA3H7VVC.js} +4 -4
- package/dist/cli-bundle/chunks/{chunk-XC2HEEOV.js → chunk-VFA5EIEN.js} +21 -11
- package/dist/cli-bundle/chunks/chunk-VFA5EIEN.js.map +1 -0
- package/dist/cli-bundle/chunks/{chunk-TLWJP5BF.js → chunk-VQOG2ETB.js} +4 -4
- package/dist/cli-bundle/chunks/{chunk-H5IOT54C.js → chunk-VSQE43NO.js} +8 -8
- package/dist/cli-bundle/chunks/{chunk-BDA35QG5.js → chunk-W6IEJXNC.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-WACRQ26A.js → chunk-WCBB6VI3.js} +637 -9
- package/dist/cli-bundle/chunks/chunk-WCBB6VI3.js.map +7 -0
- package/dist/cli-bundle/chunks/{chunk-OWP6QFBV.js → chunk-XDWXPG2E.js} +4 -4
- package/dist/cli-bundle/chunks/{chunk-CKX4WOPC.js → chunk-XKVHL3MB.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-WL3SS45P.js → chunk-XVB6BATY.js} +3 -3
- package/dist/cli-bundle/chunks/{chunk-NVZ6NVHJ.js → chunk-XXWDEQ6O.js} +4 -4
- package/dist/cli-bundle/chunks/{chunk-ILVOOAT4.js → chunk-Y2VSGFT4.js} +8 -8
- package/dist/cli-bundle/chunks/{chunk-NCVT6XEL.js → chunk-YG56M3NE.js} +11 -11
- package/dist/cli-bundle/chunks/{chunk-AFGKSHAM.js → chunk-YGEA4CLH.js} +4 -4
- package/dist/cli-bundle/chunks/{chunk-AXRT7K5V.js → chunk-YIC5NGXF.js} +11 -11
- package/dist/cli-bundle/chunks/{chunk-DHNG452T.js → chunk-ZF52NVRT.js} +396 -245
- package/dist/cli-bundle/chunks/chunk-ZF52NVRT.js.map +7 -0
- package/dist/cli-bundle/chunks/{chunk-XXLXJL7V.js → chunk-ZUCBPXNA.js} +4 -4
- package/dist/cli-bundle/chunks/{close-X3CF6FQP.js → close-7NWA3GLA.js} +5 -5
- package/dist/cli-bundle/chunks/close-ZZCDDWJT.js +12 -0
- package/dist/cli-bundle/chunks/close-many-QCZHFCON.js +23 -0
- package/dist/cli-bundle/chunks/{close-many-J7A5EHOQ.js → close-many-YALQ7AXS.js} +14 -14
- package/dist/cli-bundle/chunks/comments-FMQNYPSZ.js +13 -0
- package/dist/cli-bundle/chunks/{comments-TMHMALA5.js → comments-SQIQ5WYR.js} +7 -7
- package/dist/cli-bundle/chunks/copy-GI3RCVZP.js +9 -0
- package/dist/cli-bundle/chunks/{copy-FWQA5OU4.js → copy-YDAMENCP.js} +4 -4
- package/dist/cli-bundle/chunks/{create-AQ5SIGZC.js → create-JSL6CXU3.js} +11 -9
- package/dist/cli-bundle/chunks/create-LXMLYJNM.js +29 -0
- package/dist/cli-bundle/chunks/delete-5DFAXJNI.js +10 -0
- package/dist/cli-bundle/chunks/{delete-YYYFOSEA.js → delete-IGVOZEU2.js} +4 -4
- package/dist/cli-bundle/chunks/{deps-NIIKXLPB.js → deps-BQAXUQAK.js} +6 -6
- package/dist/cli-bundle/chunks/{deps-MQ4ZIGZB.js → deps-CBPPSS6J.js} +6 -6
- package/dist/cli-bundle/chunks/docs-KCWPLQOV.js +14 -0
- package/dist/cli-bundle/chunks/{docs-53NUGMIQ.js → docs-NS2AZWCN.js} +7 -7
- package/dist/cli-bundle/chunks/{files-3PXGXYDB.js → files-PVWEPT5J.js} +7 -7
- package/dist/cli-bundle/chunks/{files-EGLKHD7O.js → files-XUUBQ76I.js} +7 -7
- package/dist/cli-bundle/chunks/focus-3EJVFI3D.js +10 -0
- package/dist/cli-bundle/chunks/{focus-SRPASFTN.js → focus-DHBHKK3E.js} +5 -5
- package/dist/cli-bundle/chunks/{history-compact-G4DULDCX.js → history-compact-3TNPYVFG.js} +6 -6
- package/dist/cli-bundle/chunks/history-compact-JHYVDYLW.js +16 -0
- package/dist/cli-bundle/chunks/{history-redact-IUSJ6X3E.js → history-redact-ELRL73XN.js} +4 -4
- package/dist/cli-bundle/chunks/{history-redact-THHGRQXV.js → history-redact-KKFDICCF.js} +4 -4
- package/dist/cli-bundle/chunks/{history-repair-LUQWRS7X.js → history-repair-J7WKZFAG.js} +6 -6
- package/dist/cli-bundle/chunks/history-repair-REMI7DDI.js +16 -0
- package/dist/cli-bundle/chunks/learnings-O6V5WDCV.js +13 -0
- package/dist/cli-bundle/chunks/{learnings-2MRNBFJF.js → learnings-X4D6JCCG.js} +7 -7
- package/dist/cli-bundle/chunks/{notes-73JWKWUD.js → notes-UQC6VS6N.js} +7 -7
- package/dist/cli-bundle/chunks/notes-ZSZREWZA.js +13 -0
- package/dist/cli-bundle/chunks/{plan-AZPMCG37.js → plan-5GKRBJJO.js} +12 -10
- package/dist/cli-bundle/chunks/plan-EZW2YDDY.js +26 -0
- package/dist/cli-bundle/chunks/{profile-AVCIIZID.js → profile-5PQAPCLF.js} +10 -10
- package/dist/cli-bundle/chunks/{profile-LFYO3HHX.js → profile-CW4BD3FO.js} +10 -10
- package/dist/cli-bundle/chunks/{register-list-query-UKMF55FT.js → register-list-query-HTDQE6VI.js} +24 -24
- package/dist/cli-bundle/chunks/{register-list-query-MZUF2EEC.js → register-list-query-PHIPDFP2.js} +24 -24
- package/dist/cli-bundle/chunks/{register-mutation-T6RVNJC4.js → register-mutation-BLEWM5I6.js} +32 -32
- package/dist/cli-bundle/chunks/{register-mutation-2PBW2GEX.js → register-mutation-OTYHR7J6.js} +32 -32
- package/dist/cli-bundle/chunks/{register-operations-KHZYR6MG.js → register-operations-AMCUFYEW.js} +38 -40
- package/dist/cli-bundle/chunks/{register-operations-KHZYR6MG.js.map → register-operations-AMCUFYEW.js.map} +1 -1
- package/dist/cli-bundle/chunks/{register-operations-WPQ2LWZJ.js → register-operations-MRLHOZYR.js} +36 -38
- package/dist/cli-bundle/chunks/{register-operations-WPQ2LWZJ.js.map → register-operations-MRLHOZYR.js.map} +1 -1
- package/dist/cli-bundle/chunks/{register-setup-PGDNOXDQ.js → register-setup-N2FOSWAG.js} +15 -17
- package/dist/cli-bundle/chunks/{register-setup-PGDNOXDQ.js.map → register-setup-N2FOSWAG.js.map} +1 -1
- package/dist/cli-bundle/chunks/{register-setup-TDN7WAO6.js → register-setup-ZVKTDL4G.js} +17 -19
- package/dist/cli-bundle/chunks/{register-setup-TDN7WAO6.js.map → register-setup-ZVKTDL4G.js.map} +1 -1
- package/dist/cli-bundle/chunks/restore-A55MLFAI.js +14 -0
- package/dist/cli-bundle/chunks/{restore-E3PRGDN3.js → restore-HEQAG6EK.js} +6 -6
- package/dist/cli-bundle/chunks/{schema-5JNFQFUW.js → schema-MAXAIHEC.js} +6 -6
- package/dist/cli-bundle/chunks/{schema-TMIW4XZC.js → schema-Q5DAWJ2S.js} +6 -6
- package/dist/cli-bundle/chunks/update-5DTSCWVF.js +23 -0
- package/dist/cli-bundle/chunks/{update-SQYZA3ZW.js → update-DWFXXJKP.js} +15 -13
- package/dist/cli-bundle/chunks/update-many-6T4ZLZS7.js +34 -0
- package/dist/cli-bundle/chunks/update-many-MYRK6VBJ.js +38 -0
- package/dist/cli-bundle/main.js +152 -29
- package/dist/cli-bundle/main.js.map +3 -3
- package/dist/cli-bundle/sdk-runtime.js +72 -75
- package/dist/cli-bundle/sdk-testing.js +8 -8
- package/dist/cli-bundle/sdk.js +288 -642
- package/dist/cli-bundle/sdk.js.map +4 -4
- package/dist/core/extensions/activation-summary.d.ts +2 -0
- package/dist/core/extensions/activation-summary.js +7 -2
- package/dist/core/extensions/activation-summary.js.map +1 -1
- package/dist/core/extensions/capability-usage.d.ts +1 -1
- package/dist/core/extensions/capability-usage.js +5 -2
- package/dist/core/extensions/capability-usage.js.map +1 -1
- package/dist/core/extensions/extension-hook-runtime.js +3 -2
- package/dist/core/extensions/extension-hook-runtime.js.map +1 -1
- package/dist/core/extensions/extension-registries.js +3 -2
- package/dist/core/extensions/extension-registries.js.map +1 -1
- package/dist/core/extensions/extension-types.d.ts +38 -1
- package/dist/core/extensions/extension-types.js +3 -2
- package/dist/core/extensions/extension-types.js.map +1 -1
- package/dist/core/extensions/loader.js +36 -2
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/store/item-store.d.ts +4 -1
- package/dist/core/store/item-store.js +3 -3
- package/dist/core/store/item-store.js.map +1 -1
- package/dist/core/store/paths.d.ts +2 -0
- package/dist/core/store/paths.js +26 -3
- package/dist/core/store/paths.js.map +1 -1
- package/dist/sdk/cli-contracts/enum-contracts.d.ts +1 -1
- package/dist/sdk/compose.d.ts +3 -0
- package/dist/sdk/compose.js +14 -2
- package/dist/sdk/compose.js.map +1 -1
- package/dist/sdk/dependencies.js +3 -3
- package/dist/sdk/dependencies.js.map +1 -1
- package/dist/sdk/extension-command-context.d.ts +10 -0
- package/dist/sdk/extension-command-context.js +30 -0
- package/dist/sdk/extension-command-context.js.map +1 -0
- package/dist/sdk/graph/assembly.js +14 -4
- package/dist/sdk/graph/assembly.js.map +1 -1
- package/dist/sdk/graph/index.d.ts +1 -0
- package/dist/sdk/graph/index.js +3 -2
- package/dist/sdk/graph/index.js.map +1 -1
- package/dist/sdk/graph/mutation-advisory.d.ts +20 -0
- package/dist/sdk/graph/mutation-advisory.js +80 -0
- package/dist/sdk/graph/mutation-advisory.js.map +1 -0
- package/dist/sdk/graph/run.d.ts +5 -1
- package/dist/sdk/graph/run.js +11 -3
- package/dist/sdk/graph/run.js.map +1 -1
- package/dist/sdk/index.d.ts +4 -1
- package/dist/sdk/index.js +5 -2
- package/dist/sdk/index.js.map +1 -1
- package/dist/sdk/ownership-source.d.ts +2 -0
- package/dist/sdk/ownership-source.js +22 -0
- package/dist/sdk/ownership-source.js.map +1 -0
- package/dist/sdk/relationship-history.d.ts +38 -0
- package/dist/sdk/relationship-history.js +60 -2
- package/dist/sdk/relationship-history.js.map +1 -1
- package/dist/sdk/relationships.js +49 -8
- package/dist/sdk/relationships.js.map +1 -1
- package/dist/sdk/runtime-input.js +3 -2
- package/dist/sdk/runtime-input.js.map +1 -1
- package/dist/sdk/runtime.d.ts +2 -0
- package/dist/sdk/runtime.js +19 -2
- package/dist/sdk/runtime.js.map +1 -1
- package/dist/sdk/tracker-root-discovery.d.ts +6 -0
- package/dist/sdk/tracker-root-discovery.js +10 -0
- package/dist/sdk/tracker-root-discovery.js.map +1 -0
- package/dist/sdk/workspace-transaction.d.ts +83 -0
- package/dist/sdk/workspace-transaction.js +364 -0
- package/dist/sdk/workspace-transaction.js.map +1 -0
- package/docs/AGENT_UX_CONTRACTS.md +41 -0
- package/docs/EXTENSIONS.md +4 -4
- package/docs/README.md +1 -0
- package/docs/SDK.md +102 -1
- package/marketplace.json +2 -2
- package/package.json +1 -1
- package/packages/pm-beads/package.json +1 -1
- package/packages/pm-calendar/package.json +1 -1
- package/packages/pm-command-kit/package.json +1 -1
- package/packages/pm-governance-audit/package.json +1 -1
- package/packages/pm-guide-shell/package.json +1 -1
- package/packages/pm-kanban/package.json +1 -1
- package/packages/pm-lifecycle-hooks/package.json +1 -1
- package/packages/pm-linked-test-adapters/package.json +1 -1
- package/packages/pm-search-advanced/package.json +1 -1
- package/packages/pm-templates/package.json +1 -1
- package/packages/pm-todos/package.json +1 -1
- package/packages/pm-vcs/GAP_REPORT.md +31 -0
- package/packages/pm-vcs/README.md +62 -0
- package/packages/pm-vcs/extensions/vcs/index.ts +745 -0
- package/packages/pm-vcs/extensions/vcs/manifest.json +19 -0
- package/packages/pm-vcs/extensions/vcs/package.json +3 -0
- package/packages/pm-vcs/package.json +55 -0
- package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
- package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
- package/dist/cli-bundle/chunks/append-JHO5K6RP.js +0 -11
- package/dist/cli-bundle/chunks/chunk-2BX74BAS.js +0 -125
- package/dist/cli-bundle/chunks/chunk-2BX74BAS.js.map +0 -7
- package/dist/cli-bundle/chunks/chunk-3CUQZNQ6.js +0 -672
- package/dist/cli-bundle/chunks/chunk-3CUQZNQ6.js.map +0 -7
- package/dist/cli-bundle/chunks/chunk-5UKQLQM2.js.map +0 -1
- package/dist/cli-bundle/chunks/chunk-6VHUGVNP.js.map +0 -1
- package/dist/cli-bundle/chunks/chunk-74FKFFXO.js +0 -172
- package/dist/cli-bundle/chunks/chunk-74FKFFXO.js.map +0 -7
- package/dist/cli-bundle/chunks/chunk-ADXDCAKP.js.map +0 -7
- package/dist/cli-bundle/chunks/chunk-BAP7G3N2.js +0 -178
- package/dist/cli-bundle/chunks/chunk-BAP7G3N2.js.map +0 -7
- package/dist/cli-bundle/chunks/chunk-D53RTYVI.js.map +0 -7
- package/dist/cli-bundle/chunks/chunk-DHNG452T.js.map +0 -7
- package/dist/cli-bundle/chunks/chunk-EY7ZE3TG.js +0 -1831
- package/dist/cli-bundle/chunks/chunk-EY7ZE3TG.js.map +0 -1
- package/dist/cli-bundle/chunks/chunk-F3VC3GOV.js.map +0 -7
- package/dist/cli-bundle/chunks/chunk-FL4D53ND.js +0 -162
- package/dist/cli-bundle/chunks/chunk-FL4D53ND.js.map +0 -1
- package/dist/cli-bundle/chunks/chunk-GKPCTQYG.js.map +0 -7
- package/dist/cli-bundle/chunks/chunk-HPAYDSR2.js.map +0 -7
- package/dist/cli-bundle/chunks/chunk-HTXXXF45.js.map +0 -1
- package/dist/cli-bundle/chunks/chunk-I3INI567.js.map +0 -7
- package/dist/cli-bundle/chunks/chunk-KX62NMZC.js.map +0 -1
- package/dist/cli-bundle/chunks/chunk-L5BTTDU5.js +0 -662
- package/dist/cli-bundle/chunks/chunk-L5BTTDU5.js.map +0 -1
- package/dist/cli-bundle/chunks/chunk-MR4SHYR4.js.map +0 -7
- package/dist/cli-bundle/chunks/chunk-OGVTB5VO.js.map +0 -7
- package/dist/cli-bundle/chunks/chunk-QPGQNLPI.js.map +0 -1
- package/dist/cli-bundle/chunks/chunk-QRZNCRNA.js.map +0 -1
- package/dist/cli-bundle/chunks/chunk-RC4UOUXA.js +0 -122
- package/dist/cli-bundle/chunks/chunk-RC4UOUXA.js.map +0 -1
- package/dist/cli-bundle/chunks/chunk-RTBX3C4C.js +0 -1841
- package/dist/cli-bundle/chunks/chunk-RTBX3C4C.js.map +0 -7
- package/dist/cli-bundle/chunks/chunk-SIPOACV5.js.map +0 -1
- package/dist/cli-bundle/chunks/chunk-WACRQ26A.js.map +0 -7
- package/dist/cli-bundle/chunks/chunk-XC2HEEOV.js.map +0 -1
- package/dist/cli-bundle/chunks/chunk-XPUTSGJU.js.map +0 -1
- package/dist/cli-bundle/chunks/chunk-YIIIAKCE.js.map +0 -1
- package/dist/cli-bundle/chunks/chunk-YJSURTBB.js +0 -175
- package/dist/cli-bundle/chunks/chunk-YJSURTBB.js.map +0 -1
- package/dist/cli-bundle/chunks/chunk-YQEZWI3R.js.map +0 -7
- package/dist/cli-bundle/chunks/close-GPD7DTJV.js +0 -12
- package/dist/cli-bundle/chunks/close-many-NQLYGPYW.js +0 -23
- package/dist/cli-bundle/chunks/comments-2AOZQ5D2.js +0 -13
- package/dist/cli-bundle/chunks/copy-N3LCQBMC.js +0 -9
- package/dist/cli-bundle/chunks/create-KOGQ3JKD.js +0 -27
- package/dist/cli-bundle/chunks/delete-6G3MBZ6S.js +0 -10
- package/dist/cli-bundle/chunks/docs-OWRGDMNY.js +0 -14
- package/dist/cli-bundle/chunks/focus-KZLIA6WS.js +0 -10
- package/dist/cli-bundle/chunks/history-compact-HHIUOMZ7.js +0 -16
- package/dist/cli-bundle/chunks/history-repair-KG7SWXI6.js +0 -16
- package/dist/cli-bundle/chunks/learnings-ZVHSALJY.js +0 -13
- package/dist/cli-bundle/chunks/notes-BAKUL5DJ.js +0 -13
- package/dist/cli-bundle/chunks/plan-LEAGLPGP.js +0 -24
- package/dist/cli-bundle/chunks/restore-KIUYTAEJ.js +0 -14
- package/dist/cli-bundle/chunks/update-XZJYS5X7.js +0 -21
- package/dist/cli-bundle/chunks/update-many-R24B3GBK.js +0 -36
- package/dist/cli-bundle/chunks/update-many-WQ3R3J6N.js +0 -32
- /package/dist/cli-bundle/chunks/{append-5YF3TO7I.js.map → append-MBXHNWSX.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{append-JHO5K6RP.js.map → append-XUYF7NON.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-BIRYX32V.js.map → chunk-2UCG5H6B.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-VE6ZSTQW.js.map → chunk-2XPDCXK5.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-GLZKZON6.js.map → chunk-3HSRP6T2.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-XWBD6DSR.js.map → chunk-3KPNOZOH.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-HO4DLBNK.js.map → chunk-4M6RZJXF.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-RXPQ5Q23.js.map → chunk-4PSJVGRE.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-YFE7JHX3.js.map → chunk-6BNV3G6C.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-43UMFKCK.js.map → chunk-6V4T4RD3.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-EHJFUOXL.js.map → chunk-7B7IHMLH.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-I7DIDUSP.js.map → chunk-7CHWLT2J.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-L6FVNR7X.js.map → chunk-A3GAQLBH.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-B57RJHBZ.js.map → chunk-A4FVWFZY.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-D52ZN3BF.js.map → chunk-A5EQPNV7.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-TZAE66GQ.js.map → chunk-AGEBQRBG.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-WU3KAN6A.js.map → chunk-AQUNTB7G.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-XWYQ2LT4.js.map → chunk-BBGR4FKQ.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-2FUOXSRN.js.map → chunk-BFJP4VYC.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-633PKXLT.js.map → chunk-BZKE2O5V.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-L337QKWJ.js.map → chunk-DUDLSQFG.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-BVLOMU6O.js.map → chunk-E7KBMWEF.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-WQXRZMFN.js.map → chunk-EEECAV5M.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-35FHWD4C.js.map → chunk-EI3UIMZM.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-PT7MCCGD.js.map → chunk-FIUTBFC6.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-7H5NNCJ5.js.map → chunk-FQF6VVPH.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-6DYOZS6C.js.map → chunk-FQO5THHM.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-5HGZKQUL.js.map → chunk-FQODDTE7.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-67RO3H4N.js.map → chunk-G33XIMRT.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-QWBKN3QC.js.map → chunk-GKCEEXMA.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-DG2EQRIH.js.map → chunk-GRDK25BN.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-FXFCFL73.js.map → chunk-H3YKUVDR.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-ARGDWQ4J.js.map → chunk-IGBBTPM5.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-FY4RLHSC.js.map → chunk-IRJ6F23W.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-66MKH7SZ.js.map → chunk-IXG5CMBR.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-7UCY6DR5.js.map → chunk-JPWUZOMR.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-FVNWHUME.js.map → chunk-K2L6FZBX.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-X2MGQMZO.js.map → chunk-LT5UWU7H.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-KH6QAHME.js.map → chunk-M4B4RK4J.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-2XOSFSTH.js.map → chunk-MQOSMBWV.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-7R6UIHYY.js.map → chunk-N2TEEOXJ.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-NTRQLE2R.js.map → chunk-N7FCFJ76.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-37DRDP2B.js.map → chunk-NPEYH6CE.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-2CXL335K.js.map → chunk-OK7VSX3N.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-NNANAWFH.js.map → chunk-OKPZDH43.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-G6MYGULG.js.map → chunk-OKWJUL6F.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-D5XHO4Q7.js.map → chunk-Q6JPYR7I.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-IE5KRAKN.js.map → chunk-QQ77W23U.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-M7MVOKVV.js.map → chunk-QYGK2XQ3.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-X5YCTFKT.js.map → chunk-RWAIRGBC.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-W5E2UUSH.js.map → chunk-RX53WHFI.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-R5XTTZSJ.js.map → chunk-SBW7EQC4.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-TM5CIO3F.js.map → chunk-SGJB6PXA.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-DDFGYUCQ.js.map → chunk-STBCBDKF.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-FHOBCGQO.js.map → chunk-SVAWG7EE.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-6O44IN44.js.map → chunk-T6MOTLOJ.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-EWIT5WIC.js.map → chunk-U6RYD446.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-E4FXM2XB.js.map → chunk-UE7LK3RE.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-N33FD2UI.js.map → chunk-UNNCT5QY.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-2IPNL3DR.js.map → chunk-UOIFZ66L.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-LSOWTLEM.js.map → chunk-UU6EP25G.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-HYTOJW2Q.js.map → chunk-UW6HCMP2.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-47HXN6RX.js.map → chunk-UWAQI3B7.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-YKFHF37B.js.map → chunk-V4QHAMI5.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-VAHZIPWS.js.map → chunk-VA3H7VVC.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-TLWJP5BF.js.map → chunk-VQOG2ETB.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-H5IOT54C.js.map → chunk-VSQE43NO.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-BDA35QG5.js.map → chunk-W6IEJXNC.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-OWP6QFBV.js.map → chunk-XDWXPG2E.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-CKX4WOPC.js.map → chunk-XKVHL3MB.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-WL3SS45P.js.map → chunk-XVB6BATY.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-NVZ6NVHJ.js.map → chunk-XXWDEQ6O.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-ILVOOAT4.js.map → chunk-Y2VSGFT4.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-NCVT6XEL.js.map → chunk-YG56M3NE.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-AFGKSHAM.js.map → chunk-YGEA4CLH.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-AXRT7K5V.js.map → chunk-YIC5NGXF.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{chunk-XXLXJL7V.js.map → chunk-ZUCBPXNA.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{close-X3CF6FQP.js.map → close-7NWA3GLA.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{close-GPD7DTJV.js.map → close-ZZCDDWJT.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{close-many-NQLYGPYW.js.map → close-many-QCZHFCON.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{close-many-J7A5EHOQ.js.map → close-many-YALQ7AXS.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{comments-2AOZQ5D2.js.map → comments-FMQNYPSZ.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{comments-TMHMALA5.js.map → comments-SQIQ5WYR.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{copy-N3LCQBMC.js.map → copy-GI3RCVZP.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{copy-FWQA5OU4.js.map → copy-YDAMENCP.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{create-AQ5SIGZC.js.map → create-JSL6CXU3.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{create-KOGQ3JKD.js.map → create-LXMLYJNM.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{delete-6G3MBZ6S.js.map → delete-5DFAXJNI.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{delete-YYYFOSEA.js.map → delete-IGVOZEU2.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{deps-NIIKXLPB.js.map → deps-BQAXUQAK.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{deps-MQ4ZIGZB.js.map → deps-CBPPSS6J.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{docs-OWRGDMNY.js.map → docs-KCWPLQOV.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{docs-53NUGMIQ.js.map → docs-NS2AZWCN.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{files-3PXGXYDB.js.map → files-PVWEPT5J.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{files-EGLKHD7O.js.map → files-XUUBQ76I.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{focus-KZLIA6WS.js.map → focus-3EJVFI3D.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{focus-SRPASFTN.js.map → focus-DHBHKK3E.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{history-compact-G4DULDCX.js.map → history-compact-3TNPYVFG.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{history-compact-HHIUOMZ7.js.map → history-compact-JHYVDYLW.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{history-redact-IUSJ6X3E.js.map → history-redact-ELRL73XN.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{history-redact-THHGRQXV.js.map → history-redact-KKFDICCF.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{history-repair-LUQWRS7X.js.map → history-repair-J7WKZFAG.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{history-repair-KG7SWXI6.js.map → history-repair-REMI7DDI.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{learnings-ZVHSALJY.js.map → learnings-O6V5WDCV.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{learnings-2MRNBFJF.js.map → learnings-X4D6JCCG.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{notes-73JWKWUD.js.map → notes-UQC6VS6N.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{notes-BAKUL5DJ.js.map → notes-ZSZREWZA.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{plan-AZPMCG37.js.map → plan-5GKRBJJO.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{plan-LEAGLPGP.js.map → plan-EZW2YDDY.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{profile-AVCIIZID.js.map → profile-5PQAPCLF.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{profile-LFYO3HHX.js.map → profile-CW4BD3FO.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{register-list-query-UKMF55FT.js.map → register-list-query-HTDQE6VI.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{register-list-query-MZUF2EEC.js.map → register-list-query-PHIPDFP2.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{register-mutation-T6RVNJC4.js.map → register-mutation-BLEWM5I6.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{register-mutation-2PBW2GEX.js.map → register-mutation-OTYHR7J6.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{restore-KIUYTAEJ.js.map → restore-A55MLFAI.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{restore-E3PRGDN3.js.map → restore-HEQAG6EK.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{schema-5JNFQFUW.js.map → schema-MAXAIHEC.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{schema-TMIW4XZC.js.map → schema-Q5DAWJ2S.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{update-XZJYS5X7.js.map → update-5DTSCWVF.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{update-SQYZA3ZW.js.map → update-DWFXXJKP.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{update-many-WQ3R3J6N.js.map → update-many-6T4ZLZS7.js.map} +0 -0
- /package/dist/cli-bundle/chunks/{update-many-R24B3GBK.js.map → update-many-MYRK6VBJ.js.map} +0 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module sdk/tracker-root-discovery
|
|
3
|
+
*
|
|
4
|
+
* Exposes safe tracker-root discovery primitives to CLI and package consumers.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="3989cf71-e5bd-5c4f-8dd1-c98c7cd79f79")}catch(e){}}();
|
|
8
|
+
export { discoverNearbyPmRoot } from "../core/store/paths.js";
|
|
9
|
+
//# sourceMappingURL=tracker-root-discovery.js.map
|
|
10
|
+
//# debugId=3989cf71-e5bd-5c4f-8dd1-c98c7cd79f79
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tracker-root-discovery.js","sources":["sdk/tracker-root-discovery.ts"],"sourceRoot":"/","sourcesContent":["/**\n * @module sdk/tracker-root-discovery\n *\n * Exposes safe tracker-root discovery primitives to CLI and package consumers.\n */\nexport { discoverNearbyPmRoot } from \"../core/store/paths.js\";\n"],"names":[],"mappings":"AAAA;;;;GAIG;;;AACH,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC","debugId":"3989cf71-e5bd-5c4f-8dd1-c98c7cd79f79"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/** Durable state reported by a transaction step inspection. */
|
|
2
|
+
export type WorkspaceTransactionStepState = "pending" | "applied" | "compensated";
|
|
3
|
+
/** JSON-compatible values retained in the durable transaction journal. */
|
|
4
|
+
export type WorkspaceTransactionJsonValue = null | boolean | number | string | WorkspaceTransactionJsonValue[] | {
|
|
5
|
+
[key: string]: WorkspaceTransactionJsonValue;
|
|
6
|
+
};
|
|
7
|
+
/** Result returned by a step inspection during replay or recovery. */
|
|
8
|
+
export interface WorkspaceTransactionStepInspection {
|
|
9
|
+
/** Current durable state of the step's domain mutation. */
|
|
10
|
+
state: WorkspaceTransactionStepState;
|
|
11
|
+
/** Reconstructed result when the mutation is already applied. */
|
|
12
|
+
result?: WorkspaceTransactionJsonValue;
|
|
13
|
+
}
|
|
14
|
+
/** One idempotent forward mutation with an append-only compensation. */
|
|
15
|
+
export interface WorkspaceTransactionStep {
|
|
16
|
+
/** Stable identifier unique within the transaction plan. */
|
|
17
|
+
id: string;
|
|
18
|
+
/** Inspect durable domain state without mutating it. */
|
|
19
|
+
inspect(): Promise<WorkspaceTransactionStepInspection>;
|
|
20
|
+
/** Capture journal-safe pre-mutation data required by compensation. */
|
|
21
|
+
prepareCompensation?(): Promise<WorkspaceTransactionJsonValue | undefined>;
|
|
22
|
+
/** Apply the forward mutation and return a journal-safe result, or store nothing. */
|
|
23
|
+
apply(): Promise<WorkspaceTransactionJsonValue | undefined>;
|
|
24
|
+
/** Idempotently reconcile only this step's exact forward mutation when present. */
|
|
25
|
+
compensate(data?: WorkspaceTransactionJsonValue): Promise<void>;
|
|
26
|
+
}
|
|
27
|
+
/** Observable transition points available to diagnostics and failure injection. */
|
|
28
|
+
export type WorkspaceTransactionTransition = "prepared" | "step_applied" | "step_recorded" | "committing" | "committed" | "compensating" | "step_compensating" | "step_compensated" | "compensated";
|
|
29
|
+
/** Context emitted at each transaction transition. */
|
|
30
|
+
export interface WorkspaceTransactionTransitionContext {
|
|
31
|
+
/** Stable transaction identifier. */
|
|
32
|
+
transactionId: string;
|
|
33
|
+
/** Current durable transaction attempt. */
|
|
34
|
+
attempt: number;
|
|
35
|
+
/** Transition reached; `step_applied` follows mutation and precedes journal recording. */
|
|
36
|
+
transition: WorkspaceTransactionTransition;
|
|
37
|
+
/** Step associated with a step-level transition. */
|
|
38
|
+
stepId?: string;
|
|
39
|
+
}
|
|
40
|
+
/** Options accepted by the public workspace transaction coordinator. */
|
|
41
|
+
export interface CommitWorkspaceTransactionOptions {
|
|
42
|
+
/** Tracker root that owns the journal and workspace-wide writer lock. */
|
|
43
|
+
pmRoot: string;
|
|
44
|
+
/** Stable idempotency key reused to recover an interrupted transaction. */
|
|
45
|
+
transactionId: string;
|
|
46
|
+
/** Attributable actor recorded in the durable journal. */
|
|
47
|
+
author: string;
|
|
48
|
+
/** Ordered idempotent mutations; compensations run in reverse order. */
|
|
49
|
+
steps: readonly WorkspaceTransactionStep[];
|
|
50
|
+
/** Lock lifetime in seconds; size this above the longest expected attempt. */
|
|
51
|
+
lockTtlSeconds?: number;
|
|
52
|
+
/** Maximum time to wait for the workspace writer lock. */
|
|
53
|
+
lockWaitMs?: number;
|
|
54
|
+
/** Optional transition observer used by telemetry and deterministic crash tests. */
|
|
55
|
+
onTransition?(context: WorkspaceTransactionTransitionContext): void | Promise<void>;
|
|
56
|
+
}
|
|
57
|
+
/** Successful durable transaction result. */
|
|
58
|
+
export interface WorkspaceTransactionCommitResult {
|
|
59
|
+
/** Stable transaction identifier. */
|
|
60
|
+
transactionId: string;
|
|
61
|
+
/** Final durable state. */
|
|
62
|
+
status: "committed";
|
|
63
|
+
/** Whether an interrupted journal was resumed. */
|
|
64
|
+
recovered: boolean;
|
|
65
|
+
/** One result per ordered transaction step. */
|
|
66
|
+
results: Record<string, WorkspaceTransactionJsonValue>;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Deliberate process-boundary interruption used by deterministic crash tests.
|
|
70
|
+
* Throwing this from `onTransition` leaves the journal resumable and skips the
|
|
71
|
+
* normal in-process compensation path.
|
|
72
|
+
*/
|
|
73
|
+
export declare class WorkspaceTransactionInterruptedError extends Error {
|
|
74
|
+
/** Create one explicit crash-boundary interruption. */
|
|
75
|
+
constructor(message?: string);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Commit an ordered set of idempotent SDK mutations under one workspace writer
|
|
79
|
+
* lock. The durable journal resumes interrupted forward work, while ordinary
|
|
80
|
+
* failures append reverse-order compensations. This provides atomic logical
|
|
81
|
+
* replay without deleting or rewriting immutable domain histories.
|
|
82
|
+
*/
|
|
83
|
+
export declare function commitWorkspaceTransaction(options: CommitWorkspaceTransactionOptions): Promise<WorkspaceTransactionCommitResult>;
|
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module sdk/workspace-transaction
|
|
3
|
+
*
|
|
4
|
+
* Coordinates crash-recoverable, compensating transactions across public SDK
|
|
5
|
+
* mutation primitives without rewriting immutable item or relationship history.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="2f31b5a8-1462-545e-aa55-8e8f09f511b5")}catch(e){}}();
|
|
9
|
+
import { mkdir, readFile } from "node:fs/promises";
|
|
10
|
+
import path from "node:path";
|
|
11
|
+
import { acquireLock } from "../core/lock/lock.js";
|
|
12
|
+
import { writeFileAtomic } from "../core/fs/fs-utils.js";
|
|
13
|
+
import { nowIso } from "../core/shared/time.js";
|
|
14
|
+
/**
|
|
15
|
+
* Deliberate process-boundary interruption used by deterministic crash tests.
|
|
16
|
+
* Throwing this from `onTransition` leaves the journal resumable and skips the
|
|
17
|
+
* normal in-process compensation path.
|
|
18
|
+
*/
|
|
19
|
+
export class WorkspaceTransactionInterruptedError extends Error {
|
|
20
|
+
/** Create one explicit crash-boundary interruption. */
|
|
21
|
+
constructor(message = "Workspace transaction interrupted") {
|
|
22
|
+
super(message);
|
|
23
|
+
this.name = "WorkspaceTransactionInterruptedError";
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
const WORKSPACE_TRANSACTION_LOCK_ID = "sdk-workspace-transaction";
|
|
27
|
+
const TRANSACTION_ID_PATTERN = /^[a-zA-Z0-9._-]+$/;
|
|
28
|
+
const DEFAULT_LOCK_TTL_SECONDS = 30;
|
|
29
|
+
const DEFAULT_LOCK_WAIT_MS = 3_000;
|
|
30
|
+
function requiredIdentifier(value, label) {
|
|
31
|
+
if (typeof value !== "string")
|
|
32
|
+
throw new TypeError(`${label} must be a string`);
|
|
33
|
+
const normalized = value.trim();
|
|
34
|
+
if (!normalized || !TRANSACTION_ID_PATTERN.test(normalized))
|
|
35
|
+
throw new TypeError(`${label} must match [a-zA-Z0-9._-]+`);
|
|
36
|
+
return normalized;
|
|
37
|
+
}
|
|
38
|
+
function requiredText(value, label) {
|
|
39
|
+
if (typeof value !== "string")
|
|
40
|
+
throw new TypeError(`${label} must be a string`);
|
|
41
|
+
const normalized = value.trim();
|
|
42
|
+
if (!normalized)
|
|
43
|
+
throw new TypeError(`${label} must be non-empty`);
|
|
44
|
+
return normalized;
|
|
45
|
+
}
|
|
46
|
+
function positiveInteger(value, fallback, label) {
|
|
47
|
+
const resolved = value ?? fallback;
|
|
48
|
+
if (!Number.isInteger(resolved) || resolved <= 0)
|
|
49
|
+
throw new TypeError(`${label} must be a positive integer`);
|
|
50
|
+
return resolved;
|
|
51
|
+
}
|
|
52
|
+
function journalPath(pmRoot, transactionId) {
|
|
53
|
+
return path.join(pmRoot, "transactions", "sdk", `${transactionId}.json`);
|
|
54
|
+
}
|
|
55
|
+
async function writeJournal(pmRoot, journal) {
|
|
56
|
+
journal.updatedAt = nowIso();
|
|
57
|
+
const target = journalPath(pmRoot, journal.transactionId);
|
|
58
|
+
await mkdir(path.dirname(target), { recursive: true });
|
|
59
|
+
await writeFileAtomic(target, `${JSON.stringify(journal, null, 2)}\n`);
|
|
60
|
+
}
|
|
61
|
+
function hasValidJournalMetadata(journal) {
|
|
62
|
+
return (Number.isInteger(journal.attempt) &&
|
|
63
|
+
typeof journal.author === "string" &&
|
|
64
|
+
typeof journal.createdAt === "string" &&
|
|
65
|
+
typeof journal.updatedAt === "string");
|
|
66
|
+
}
|
|
67
|
+
function createResultMap(source) {
|
|
68
|
+
return Object.assign(Object.create(null), source);
|
|
69
|
+
}
|
|
70
|
+
function cloneJournalValue(value, label) {
|
|
71
|
+
try {
|
|
72
|
+
const serialized = JSON.stringify(value, (_key, nestedValue) => {
|
|
73
|
+
if (typeof nestedValue === "number" && !Number.isFinite(nestedValue))
|
|
74
|
+
throw new TypeError(`${label} contains a non-finite number`);
|
|
75
|
+
if (nestedValue === undefined ||
|
|
76
|
+
typeof nestedValue === "function" ||
|
|
77
|
+
typeof nestedValue === "symbol")
|
|
78
|
+
throw new TypeError(`${label} contains a non-JSON value`);
|
|
79
|
+
return nestedValue;
|
|
80
|
+
});
|
|
81
|
+
return JSON.parse(serialized);
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
throw new TypeError(`${label} must be JSON serializable`, { cause: error });
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function cloneOptionalJournalValue(value, label) {
|
|
88
|
+
return value === undefined ? undefined : cloneJournalValue(value, label);
|
|
89
|
+
}
|
|
90
|
+
function setJournalEntry(target, stepId, value, label) {
|
|
91
|
+
const cloned = cloneOptionalJournalValue(value, label);
|
|
92
|
+
if (cloned === undefined)
|
|
93
|
+
delete target[stepId];
|
|
94
|
+
else
|
|
95
|
+
target[stepId] = cloned;
|
|
96
|
+
}
|
|
97
|
+
function isJournalMap(value) {
|
|
98
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
99
|
+
}
|
|
100
|
+
function hasUniqueKnownStepIds(value, stepIds) {
|
|
101
|
+
return (Array.isArray(value) &&
|
|
102
|
+
new Set(value).size === value.length &&
|
|
103
|
+
value.every((stepId) => typeof stepId === "string" && stepIds.includes(stepId)));
|
|
104
|
+
}
|
|
105
|
+
function hasValidJournalLifecycle(journal, stepIds) {
|
|
106
|
+
if (!hasUniqueKnownStepIds(journal.startedStepIds, stepIds) ||
|
|
107
|
+
!hasUniqueKnownStepIds(journal.completedStepIds, stepIds) ||
|
|
108
|
+
!isJournalMap(journal.results) ||
|
|
109
|
+
!isJournalMap(journal.compensationData))
|
|
110
|
+
return false;
|
|
111
|
+
const startedStepIds = journal.startedStepIds;
|
|
112
|
+
const started = new Set(startedStepIds);
|
|
113
|
+
const completedStepIds = journal.completedStepIds;
|
|
114
|
+
const completed = new Set(completedStepIds);
|
|
115
|
+
if (Object.keys(journal.compensationData).some((stepId) => !started.has(stepId)) ||
|
|
116
|
+
Object.keys(journal.results).some((stepId) => !completed.has(stepId)))
|
|
117
|
+
return false;
|
|
118
|
+
if (journal.status === "committed")
|
|
119
|
+
return stepIds.every((stepId) => completed.has(stepId));
|
|
120
|
+
return (journal.status !== "compensated" ||
|
|
121
|
+
(completed.size === 0 && started.size === 0));
|
|
122
|
+
}
|
|
123
|
+
function parseJournal(raw, transactionId, stepIds) {
|
|
124
|
+
let parsed;
|
|
125
|
+
try {
|
|
126
|
+
parsed = JSON.parse(raw);
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
throw new TypeError(`Workspace transaction ${transactionId} journal is invalid JSON`);
|
|
130
|
+
}
|
|
131
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
132
|
+
throw new TypeError(`Workspace transaction ${transactionId} journal is invalid`);
|
|
133
|
+
const journal = parsed;
|
|
134
|
+
const identityMatches = journal.schemaVersion === 1 && journal.transactionId === transactionId;
|
|
135
|
+
const stepsMatch = Array.isArray(journal.stepIds) &&
|
|
136
|
+
journal.stepIds.length === stepIds.length &&
|
|
137
|
+
journal.stepIds.every((stepId, index) => stepId === stepIds[index]);
|
|
138
|
+
const lifecycleMatches = hasValidJournalLifecycle(journal, stepIds);
|
|
139
|
+
const metadataMatches = hasValidJournalMetadata(journal);
|
|
140
|
+
const statusMatches = [
|
|
141
|
+
"applying",
|
|
142
|
+
"compensating",
|
|
143
|
+
"compensated",
|
|
144
|
+
"committed",
|
|
145
|
+
].includes(String(journal.status));
|
|
146
|
+
if (!identityMatches ||
|
|
147
|
+
!stepsMatch ||
|
|
148
|
+
!lifecycleMatches ||
|
|
149
|
+
!metadataMatches ||
|
|
150
|
+
!statusMatches)
|
|
151
|
+
throw new TypeError(`Workspace transaction ${transactionId} journal does not match the supplied plan`);
|
|
152
|
+
return {
|
|
153
|
+
...journal,
|
|
154
|
+
results: createResultMap(journal.results),
|
|
155
|
+
compensationData: createResultMap(journal.compensationData),
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
async function prepareJournalForApply(options, transactionId, author, stepIds, existing) {
|
|
159
|
+
let journal = existing;
|
|
160
|
+
const recovered = journal !== undefined;
|
|
161
|
+
if (journal?.status === "compensating")
|
|
162
|
+
await compensateAppliedSteps(options, journal);
|
|
163
|
+
if (journal === undefined || journal.status === "compensated") {
|
|
164
|
+
const timestamp = nowIso();
|
|
165
|
+
journal = {
|
|
166
|
+
schemaVersion: 1,
|
|
167
|
+
transactionId,
|
|
168
|
+
author,
|
|
169
|
+
status: "applying",
|
|
170
|
+
attempt: (journal?.attempt ?? 0) + 1,
|
|
171
|
+
createdAt: journal?.createdAt ?? timestamp,
|
|
172
|
+
updatedAt: timestamp,
|
|
173
|
+
stepIds,
|
|
174
|
+
startedStepIds: [],
|
|
175
|
+
completedStepIds: [],
|
|
176
|
+
results: createResultMap(),
|
|
177
|
+
compensationData: createResultMap(),
|
|
178
|
+
};
|
|
179
|
+
await writeJournal(options.pmRoot, journal);
|
|
180
|
+
await emitTransition(options, journal, "prepared");
|
|
181
|
+
}
|
|
182
|
+
return { journal, recovered };
|
|
183
|
+
}
|
|
184
|
+
async function applyPreparedTransaction(options, journal, recovered) {
|
|
185
|
+
try {
|
|
186
|
+
await discoverAppliedSteps(journal, options.steps);
|
|
187
|
+
await writeJournal(options.pmRoot, journal);
|
|
188
|
+
const completed = new Set(journal.completedStepIds);
|
|
189
|
+
const started = new Set(journal.startedStepIds);
|
|
190
|
+
for (const step of options.steps) {
|
|
191
|
+
if (completed.has(step.id))
|
|
192
|
+
continue;
|
|
193
|
+
const inspection = await step.inspect();
|
|
194
|
+
let result = cloneOptionalJournalValue(inspection.result, `Step ${step.id} result`);
|
|
195
|
+
if (inspection.state !== "applied") {
|
|
196
|
+
const compensationData = await step.prepareCompensation?.();
|
|
197
|
+
setJournalEntry(journal.compensationData, step.id, compensationData, `Step ${step.id} compensation data`);
|
|
198
|
+
started.add(step.id);
|
|
199
|
+
journal.startedStepIds = options.steps
|
|
200
|
+
.map((candidate) => candidate.id)
|
|
201
|
+
.filter((stepId) => started.has(stepId));
|
|
202
|
+
await writeJournal(options.pmRoot, journal);
|
|
203
|
+
const appliedResult = await step.apply();
|
|
204
|
+
result = cloneOptionalJournalValue(appliedResult, `Step ${step.id} result`);
|
|
205
|
+
}
|
|
206
|
+
await emitTransition(options, journal, "step_applied", step.id);
|
|
207
|
+
completed.add(step.id);
|
|
208
|
+
journal.completedStepIds = options.steps
|
|
209
|
+
.map((candidate) => candidate.id)
|
|
210
|
+
.filter((stepId) => completed.has(stepId));
|
|
211
|
+
setJournalEntry(journal.results, step.id, result, `Step ${step.id} result`);
|
|
212
|
+
await writeJournal(options.pmRoot, journal);
|
|
213
|
+
await emitTransition(options, journal, "step_recorded", step.id);
|
|
214
|
+
}
|
|
215
|
+
await emitTransition(options, journal, "committing");
|
|
216
|
+
journal.status = "committed";
|
|
217
|
+
await writeJournal(options.pmRoot, journal);
|
|
218
|
+
await emitTransition(options, journal, "committed");
|
|
219
|
+
return {
|
|
220
|
+
transactionId: journal.transactionId,
|
|
221
|
+
status: "committed",
|
|
222
|
+
recovered,
|
|
223
|
+
results: createResultMap(journal.results),
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
catch (error) {
|
|
227
|
+
if (error instanceof WorkspaceTransactionInterruptedError ||
|
|
228
|
+
journal.status === "committed")
|
|
229
|
+
throw error;
|
|
230
|
+
try {
|
|
231
|
+
await compensateAppliedSteps(options, journal);
|
|
232
|
+
}
|
|
233
|
+
catch (compensationError) {
|
|
234
|
+
throw new AggregateError([error, compensationError], `Workspace transaction failed and compensation failed: ${String(compensationError)}`, { cause: compensationError });
|
|
235
|
+
}
|
|
236
|
+
throw error;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
async function loadJournal(pmRoot, transactionId, stepIds) {
|
|
240
|
+
try {
|
|
241
|
+
return parseJournal(await readFile(journalPath(pmRoot, transactionId), "utf8"), transactionId, stepIds);
|
|
242
|
+
}
|
|
243
|
+
catch (error) {
|
|
244
|
+
if (error !== null &&
|
|
245
|
+
typeof error === "object" &&
|
|
246
|
+
"code" in error &&
|
|
247
|
+
error.code === "ENOENT")
|
|
248
|
+
return undefined;
|
|
249
|
+
throw error;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
async function emitTransition(options, journal, transition, stepId) {
|
|
253
|
+
await options.onTransition?.({
|
|
254
|
+
transactionId: journal.transactionId,
|
|
255
|
+
attempt: journal.attempt,
|
|
256
|
+
transition,
|
|
257
|
+
...(stepId === undefined ? {} : { stepId }),
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
async function discoverAppliedSteps(journal, steps) {
|
|
261
|
+
const completed = new Set();
|
|
262
|
+
const results = createResultMap();
|
|
263
|
+
for (const step of steps) {
|
|
264
|
+
const inspection = await step.inspect();
|
|
265
|
+
if (inspection.state === "applied") {
|
|
266
|
+
completed.add(step.id);
|
|
267
|
+
setJournalEntry(results, step.id, inspection.result, `Step ${step.id} result`);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
journal.results = results;
|
|
271
|
+
journal.completedStepIds = steps
|
|
272
|
+
.map((step) => step.id)
|
|
273
|
+
.filter((stepId) => completed.has(stepId));
|
|
274
|
+
}
|
|
275
|
+
async function compensateAppliedSteps(options, journal) {
|
|
276
|
+
journal.status = "compensating";
|
|
277
|
+
await writeJournal(options.pmRoot, journal);
|
|
278
|
+
await emitTransition(options, journal, "compensating");
|
|
279
|
+
const completed = new Set(journal.completedStepIds);
|
|
280
|
+
const started = new Set(journal.startedStepIds);
|
|
281
|
+
for (const step of [...options.steps].reverse()) {
|
|
282
|
+
if (!started.has(step.id) && !completed.has(step.id))
|
|
283
|
+
continue;
|
|
284
|
+
let shouldCompensate;
|
|
285
|
+
try {
|
|
286
|
+
shouldCompensate =
|
|
287
|
+
started.has(step.id) && (await step.inspect()).state === "applied";
|
|
288
|
+
}
|
|
289
|
+
catch {
|
|
290
|
+
shouldCompensate = started.has(step.id);
|
|
291
|
+
}
|
|
292
|
+
if (shouldCompensate) {
|
|
293
|
+
await emitTransition(options, journal, "step_compensating", step.id);
|
|
294
|
+
await step.compensate(journal.compensationData[step.id]);
|
|
295
|
+
}
|
|
296
|
+
completed.delete(step.id);
|
|
297
|
+
started.delete(step.id);
|
|
298
|
+
journal.completedStepIds = options.steps
|
|
299
|
+
.map((candidate) => candidate.id)
|
|
300
|
+
.filter((stepId) => completed.has(stepId));
|
|
301
|
+
journal.startedStepIds = options.steps
|
|
302
|
+
.map((candidate) => candidate.id)
|
|
303
|
+
.filter((stepId) => started.has(stepId));
|
|
304
|
+
delete journal.results[step.id];
|
|
305
|
+
delete journal.compensationData[step.id];
|
|
306
|
+
await writeJournal(options.pmRoot, journal);
|
|
307
|
+
await emitTransition(options, journal, "step_compensated", step.id);
|
|
308
|
+
}
|
|
309
|
+
journal.status = "compensated";
|
|
310
|
+
await writeJournal(options.pmRoot, journal);
|
|
311
|
+
await emitTransition(options, journal, "compensated");
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Commit an ordered set of idempotent SDK mutations under one workspace writer
|
|
315
|
+
* lock. The durable journal resumes interrupted forward work, while ordinary
|
|
316
|
+
* failures append reverse-order compensations. This provides atomic logical
|
|
317
|
+
* replay without deleting or rewriting immutable domain histories.
|
|
318
|
+
*/
|
|
319
|
+
export async function commitWorkspaceTransaction(options) {
|
|
320
|
+
const pmRoot = requiredText(options.pmRoot, "Transaction pmRoot");
|
|
321
|
+
const transactionId = requiredIdentifier(options.transactionId, "Transaction id");
|
|
322
|
+
const author = requiredText(options.author, "Transaction author");
|
|
323
|
+
const lockTtlSeconds = positiveInteger(options.lockTtlSeconds, DEFAULT_LOCK_TTL_SECONDS, "Transaction lock TTL");
|
|
324
|
+
const lockWaitMs = positiveInteger(options.lockWaitMs, DEFAULT_LOCK_WAIT_MS, "Transaction lock wait");
|
|
325
|
+
const steps = [...options.steps];
|
|
326
|
+
if (steps.length === 0)
|
|
327
|
+
throw new TypeError("Workspace transaction requires at least one step");
|
|
328
|
+
const stepIds = steps.map((step) => {
|
|
329
|
+
const stepId = requiredIdentifier(step.id, "Transaction step id");
|
|
330
|
+
if (stepId !== step.id)
|
|
331
|
+
throw new TypeError("Transaction step id must not contain surrounding whitespace");
|
|
332
|
+
return stepId;
|
|
333
|
+
});
|
|
334
|
+
if (new Set(stepIds).size !== stepIds.length)
|
|
335
|
+
throw new TypeError("Workspace transaction step ids must be unique");
|
|
336
|
+
const stableOptions = {
|
|
337
|
+
...options,
|
|
338
|
+
pmRoot,
|
|
339
|
+
transactionId,
|
|
340
|
+
author,
|
|
341
|
+
steps,
|
|
342
|
+
lockTtlSeconds,
|
|
343
|
+
lockWaitMs,
|
|
344
|
+
};
|
|
345
|
+
const release = await acquireLock(pmRoot, WORKSPACE_TRANSACTION_LOCK_ID, lockTtlSeconds, author, false, false, lockWaitMs);
|
|
346
|
+
try {
|
|
347
|
+
const existing = await loadJournal(pmRoot, transactionId, stepIds);
|
|
348
|
+
const recovered = existing !== undefined;
|
|
349
|
+
if (existing?.status === "committed")
|
|
350
|
+
return {
|
|
351
|
+
transactionId,
|
|
352
|
+
status: "committed",
|
|
353
|
+
recovered: true,
|
|
354
|
+
results: createResultMap(existing.results),
|
|
355
|
+
};
|
|
356
|
+
const prepared = await prepareJournalForApply(stableOptions, transactionId, author, stepIds, existing);
|
|
357
|
+
return await applyPreparedTransaction(stableOptions, prepared.journal, recovered || prepared.recovered);
|
|
358
|
+
}
|
|
359
|
+
finally {
|
|
360
|
+
await release();
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
//# sourceMappingURL=workspace-transaction.js.map
|
|
364
|
+
//# debugId=2f31b5a8-1462-545e-aa55-8e8f09f511b5
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace-transaction.js","sources":["sdk/workspace-transaction.ts"],"sourceRoot":"/","sourcesContent":["/**\n * @module sdk/workspace-transaction\n *\n * Coordinates crash-recoverable, compensating transactions across public SDK\n * mutation primitives without rewriting immutable item or relationship history.\n */\nimport { mkdir, readFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { acquireLock } from \"../core/lock/lock.js\";\nimport { writeFileAtomic } from \"../core/fs/fs-utils.js\";\nimport { nowIso } from \"../core/shared/time.js\";\n\n/** Durable state reported by a transaction step inspection. */\nexport type WorkspaceTransactionStepState =\n | \"pending\"\n | \"applied\"\n | \"compensated\";\n\n/** JSON-compatible values retained in the durable transaction journal. */\nexport type WorkspaceTransactionJsonValue =\n | null\n | boolean\n | number\n | string\n | WorkspaceTransactionJsonValue[]\n | { [key: string]: WorkspaceTransactionJsonValue };\n\n/** Result returned by a step inspection during replay or recovery. */\nexport interface WorkspaceTransactionStepInspection {\n /** Current durable state of the step's domain mutation. */\n state: WorkspaceTransactionStepState;\n /** Reconstructed result when the mutation is already applied. */\n result?: WorkspaceTransactionJsonValue;\n}\n\n/** One idempotent forward mutation with an append-only compensation. */\nexport interface WorkspaceTransactionStep {\n /** Stable identifier unique within the transaction plan. */\n id: string;\n /** Inspect durable domain state without mutating it. */\n inspect(): Promise<WorkspaceTransactionStepInspection>;\n /** Capture journal-safe pre-mutation data required by compensation. */\n prepareCompensation?(): Promise<WorkspaceTransactionJsonValue | undefined>;\n /** Apply the forward mutation and return a journal-safe result, or store nothing. */\n apply(): Promise<WorkspaceTransactionJsonValue | undefined>;\n /** Idempotently reconcile only this step's exact forward mutation when present. */\n compensate(data?: WorkspaceTransactionJsonValue): Promise<void>;\n}\n\n/** Observable transition points available to diagnostics and failure injection. */\nexport type WorkspaceTransactionTransition =\n | \"prepared\"\n | \"step_applied\"\n | \"step_recorded\"\n | \"committing\"\n | \"committed\"\n | \"compensating\"\n | \"step_compensating\"\n | \"step_compensated\"\n | \"compensated\";\n\n/** Context emitted at each transaction transition. */\nexport interface WorkspaceTransactionTransitionContext {\n /** Stable transaction identifier. */\n transactionId: string;\n /** Current durable transaction attempt. */\n attempt: number;\n /** Transition reached; `step_applied` follows mutation and precedes journal recording. */\n transition: WorkspaceTransactionTransition;\n /** Step associated with a step-level transition. */\n stepId?: string;\n}\n\n/** Options accepted by the public workspace transaction coordinator. */\nexport interface CommitWorkspaceTransactionOptions {\n /** Tracker root that owns the journal and workspace-wide writer lock. */\n pmRoot: string;\n /** Stable idempotency key reused to recover an interrupted transaction. */\n transactionId: string;\n /** Attributable actor recorded in the durable journal. */\n author: string;\n /** Ordered idempotent mutations; compensations run in reverse order. */\n steps: readonly WorkspaceTransactionStep[];\n /** Lock lifetime in seconds; size this above the longest expected attempt. */\n lockTtlSeconds?: number;\n /** Maximum time to wait for the workspace writer lock. */\n lockWaitMs?: number;\n /** Optional transition observer used by telemetry and deterministic crash tests. */\n onTransition?(\n context: WorkspaceTransactionTransitionContext,\n ): void | Promise<void>;\n}\n\n/** Successful durable transaction result. */\nexport interface WorkspaceTransactionCommitResult {\n /** Stable transaction identifier. */\n transactionId: string;\n /** Final durable state. */\n status: \"committed\";\n /** Whether an interrupted journal was resumed. */\n recovered: boolean;\n /** One result per ordered transaction step. */\n results: Record<string, WorkspaceTransactionJsonValue>;\n}\n\n/**\n * Deliberate process-boundary interruption used by deterministic crash tests.\n * Throwing this from `onTransition` leaves the journal resumable and skips the\n * normal in-process compensation path.\n */\nexport class WorkspaceTransactionInterruptedError extends Error {\n /** Create one explicit crash-boundary interruption. */\n public constructor(message = \"Workspace transaction interrupted\") {\n super(message);\n this.name = \"WorkspaceTransactionInterruptedError\";\n }\n}\n\ntype WorkspaceTransactionJournalStatus =\n | \"applying\"\n | \"compensating\"\n | \"compensated\"\n | \"committed\";\n\ninterface WorkspaceTransactionJournal {\n schemaVersion: 1;\n transactionId: string;\n author: string;\n status: WorkspaceTransactionJournalStatus;\n attempt: number;\n createdAt: string;\n updatedAt: string;\n stepIds: string[];\n startedStepIds: string[];\n completedStepIds: string[];\n results: Record<string, WorkspaceTransactionJsonValue>;\n compensationData: Record<string, WorkspaceTransactionJsonValue>;\n}\n\nconst WORKSPACE_TRANSACTION_LOCK_ID = \"sdk-workspace-transaction\";\nconst TRANSACTION_ID_PATTERN = /^[a-zA-Z0-9._-]+$/;\nconst DEFAULT_LOCK_TTL_SECONDS = 30;\nconst DEFAULT_LOCK_WAIT_MS = 3_000;\n\nfunction requiredIdentifier(value: unknown, label: string): string {\n if (typeof value !== \"string\")\n throw new TypeError(`${label} must be a string`);\n const normalized = value.trim();\n if (!normalized || !TRANSACTION_ID_PATTERN.test(normalized))\n throw new TypeError(`${label} must match [a-zA-Z0-9._-]+`);\n return normalized;\n}\n\nfunction requiredText(value: unknown, label: string): string {\n if (typeof value !== \"string\")\n throw new TypeError(`${label} must be a string`);\n const normalized = value.trim();\n if (!normalized) throw new TypeError(`${label} must be non-empty`);\n return normalized;\n}\n\nfunction positiveInteger(\n value: number | undefined,\n fallback: number,\n label: string,\n) {\n const resolved = value ?? fallback;\n if (!Number.isInteger(resolved) || resolved <= 0)\n throw new TypeError(`${label} must be a positive integer`);\n return resolved;\n}\n\nfunction journalPath(pmRoot: string, transactionId: string): string {\n return path.join(pmRoot, \"transactions\", \"sdk\", `${transactionId}.json`);\n}\n\nasync function writeJournal(\n pmRoot: string,\n journal: WorkspaceTransactionJournal,\n): Promise<void> {\n journal.updatedAt = nowIso();\n const target = journalPath(pmRoot, journal.transactionId);\n await mkdir(path.dirname(target), { recursive: true });\n await writeFileAtomic(target, `${JSON.stringify(journal, null, 2)}\\n`);\n}\n\nfunction hasValidJournalMetadata(\n journal: Partial<WorkspaceTransactionJournal>,\n): boolean {\n return (\n Number.isInteger(journal.attempt) &&\n typeof journal.author === \"string\" &&\n typeof journal.createdAt === \"string\" &&\n typeof journal.updatedAt === \"string\"\n );\n}\n\nfunction createResultMap(\n source?: Record<string, WorkspaceTransactionJsonValue>,\n): Record<string, WorkspaceTransactionJsonValue> {\n return Object.assign(\n Object.create(null) as Record<string, WorkspaceTransactionJsonValue>,\n source,\n );\n}\n\nfunction cloneJournalValue(\n value: unknown,\n label: string,\n): WorkspaceTransactionJsonValue {\n try {\n const serialized = JSON.stringify(value, (_key, nestedValue: unknown) => {\n if (typeof nestedValue === \"number\" && !Number.isFinite(nestedValue))\n throw new TypeError(`${label} contains a non-finite number`);\n if (\n nestedValue === undefined ||\n typeof nestedValue === \"function\" ||\n typeof nestedValue === \"symbol\"\n )\n throw new TypeError(`${label} contains a non-JSON value`);\n return nestedValue;\n }) as string;\n return JSON.parse(serialized) as WorkspaceTransactionJsonValue;\n } catch (error) {\n throw new TypeError(`${label} must be JSON serializable`, { cause: error });\n }\n}\n\nfunction cloneOptionalJournalValue(\n value: unknown,\n label: string,\n): WorkspaceTransactionJsonValue | undefined {\n return value === undefined ? undefined : cloneJournalValue(value, label);\n}\n\nfunction setJournalEntry(\n target: Record<string, WorkspaceTransactionJsonValue>,\n stepId: string,\n value: unknown,\n label: string,\n): void {\n const cloned = cloneOptionalJournalValue(value, label);\n if (cloned === undefined) delete target[stepId];\n else target[stepId] = cloned;\n}\n\nfunction isJournalMap(\n value: unknown,\n): value is Record<string, WorkspaceTransactionJsonValue> {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction hasUniqueKnownStepIds(\n value: unknown,\n stepIds: readonly string[],\n): value is string[] {\n return (\n Array.isArray(value) &&\n new Set(value).size === value.length &&\n value.every(\n (stepId) => typeof stepId === \"string\" && stepIds.includes(stepId),\n )\n );\n}\n\nfunction hasValidJournalLifecycle(\n journal: Partial<WorkspaceTransactionJournal>,\n stepIds: readonly string[],\n): boolean {\n if (\n !hasUniqueKnownStepIds(journal.startedStepIds, stepIds) ||\n !hasUniqueKnownStepIds(journal.completedStepIds, stepIds) ||\n !isJournalMap(journal.results) ||\n !isJournalMap(journal.compensationData)\n )\n return false;\n const startedStepIds = journal.startedStepIds;\n const started = new Set(startedStepIds);\n const completedStepIds = journal.completedStepIds;\n const completed = new Set(completedStepIds);\n if (\n Object.keys(journal.compensationData).some(\n (stepId) => !started.has(stepId),\n ) ||\n Object.keys(journal.results).some((stepId) => !completed.has(stepId))\n )\n return false;\n if (journal.status === \"committed\")\n return stepIds.every((stepId) => completed.has(stepId));\n return (\n journal.status !== \"compensated\" ||\n (completed.size === 0 && started.size === 0)\n );\n}\n\nfunction parseJournal(\n raw: string,\n transactionId: string,\n stepIds: readonly string[],\n): WorkspaceTransactionJournal {\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw) as unknown;\n } catch {\n throw new TypeError(\n `Workspace transaction ${transactionId} journal is invalid JSON`,\n );\n }\n if (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed))\n throw new TypeError(\n `Workspace transaction ${transactionId} journal is invalid`,\n );\n const journal = parsed as Partial<WorkspaceTransactionJournal>;\n const identityMatches =\n journal.schemaVersion === 1 && journal.transactionId === transactionId;\n const stepsMatch =\n Array.isArray(journal.stepIds) &&\n journal.stepIds.length === stepIds.length &&\n journal.stepIds.every((stepId, index) => stepId === stepIds[index]);\n const lifecycleMatches = hasValidJournalLifecycle(journal, stepIds);\n const metadataMatches = hasValidJournalMetadata(journal);\n const statusMatches = [\n \"applying\",\n \"compensating\",\n \"compensated\",\n \"committed\",\n ].includes(String(journal.status));\n if (\n !identityMatches ||\n !stepsMatch ||\n !lifecycleMatches ||\n !metadataMatches ||\n !statusMatches\n )\n throw new TypeError(\n `Workspace transaction ${transactionId} journal does not match the supplied plan`,\n );\n return {\n ...(journal as WorkspaceTransactionJournal),\n results: createResultMap(journal.results),\n compensationData: createResultMap(journal.compensationData),\n };\n}\n\nasync function prepareJournalForApply(\n options: CommitWorkspaceTransactionOptions,\n transactionId: string,\n author: string,\n stepIds: string[],\n existing: WorkspaceTransactionJournal | undefined,\n): Promise<{\n journal: WorkspaceTransactionJournal;\n recovered: boolean;\n}> {\n let journal = existing;\n const recovered = journal !== undefined;\n if (journal?.status === \"compensating\")\n await compensateAppliedSteps(options, journal);\n if (journal === undefined || journal.status === \"compensated\") {\n const timestamp = nowIso();\n journal = {\n schemaVersion: 1,\n transactionId,\n author,\n status: \"applying\",\n attempt: (journal?.attempt ?? 0) + 1,\n createdAt: journal?.createdAt ?? timestamp,\n updatedAt: timestamp,\n stepIds,\n startedStepIds: [],\n completedStepIds: [],\n results: createResultMap(),\n compensationData: createResultMap(),\n };\n await writeJournal(options.pmRoot, journal);\n await emitTransition(options, journal, \"prepared\");\n }\n return { journal, recovered };\n}\n\nasync function applyPreparedTransaction(\n options: CommitWorkspaceTransactionOptions,\n journal: WorkspaceTransactionJournal,\n recovered: boolean,\n): Promise<WorkspaceTransactionCommitResult> {\n try {\n await discoverAppliedSteps(journal, options.steps);\n await writeJournal(options.pmRoot, journal);\n const completed = new Set(journal.completedStepIds);\n const started = new Set(journal.startedStepIds);\n for (const step of options.steps) {\n if (completed.has(step.id)) continue;\n const inspection = await step.inspect();\n let result = cloneOptionalJournalValue(\n inspection.result,\n `Step ${step.id} result`,\n );\n if (inspection.state !== \"applied\") {\n const compensationData = await step.prepareCompensation?.();\n setJournalEntry(\n journal.compensationData,\n step.id,\n compensationData,\n `Step ${step.id} compensation data`,\n );\n started.add(step.id);\n journal.startedStepIds = options.steps\n .map((candidate) => candidate.id)\n .filter((stepId) => started.has(stepId));\n await writeJournal(options.pmRoot, journal);\n const appliedResult = await step.apply();\n result = cloneOptionalJournalValue(\n appliedResult,\n `Step ${step.id} result`,\n );\n }\n await emitTransition(options, journal, \"step_applied\", step.id);\n completed.add(step.id);\n journal.completedStepIds = options.steps\n .map((candidate) => candidate.id)\n .filter((stepId) => completed.has(stepId));\n setJournalEntry(\n journal.results,\n step.id,\n result,\n `Step ${step.id} result`,\n );\n await writeJournal(options.pmRoot, journal);\n await emitTransition(options, journal, \"step_recorded\", step.id);\n }\n await emitTransition(options, journal, \"committing\");\n journal.status = \"committed\";\n await writeJournal(options.pmRoot, journal);\n await emitTransition(options, journal, \"committed\");\n return {\n transactionId: journal.transactionId,\n status: \"committed\",\n recovered,\n results: createResultMap(journal.results),\n };\n } catch (error) {\n if (\n error instanceof WorkspaceTransactionInterruptedError ||\n journal.status === \"committed\"\n )\n throw error;\n try {\n await compensateAppliedSteps(options, journal);\n } catch (compensationError) {\n throw new AggregateError(\n [error, compensationError],\n `Workspace transaction failed and compensation failed: ${String(compensationError)}`,\n { cause: compensationError },\n );\n }\n throw error;\n }\n}\n\nasync function loadJournal(\n pmRoot: string,\n transactionId: string,\n stepIds: readonly string[],\n): Promise<WorkspaceTransactionJournal | undefined> {\n try {\n return parseJournal(\n await readFile(journalPath(pmRoot, transactionId), \"utf8\"),\n transactionId,\n stepIds,\n );\n } catch (error) {\n if (\n error !== null &&\n typeof error === \"object\" &&\n \"code\" in error &&\n error.code === \"ENOENT\"\n )\n return undefined;\n throw error;\n }\n}\n\nasync function emitTransition(\n options: CommitWorkspaceTransactionOptions,\n journal: WorkspaceTransactionJournal,\n transition: WorkspaceTransactionTransition,\n stepId?: string,\n): Promise<void> {\n await options.onTransition?.({\n transactionId: journal.transactionId,\n attempt: journal.attempt,\n transition,\n ...(stepId === undefined ? {} : { stepId }),\n });\n}\n\nasync function discoverAppliedSteps(\n journal: WorkspaceTransactionJournal,\n steps: readonly WorkspaceTransactionStep[],\n): Promise<void> {\n const completed = new Set<string>();\n const results = createResultMap();\n for (const step of steps) {\n const inspection = await step.inspect();\n if (inspection.state === \"applied\") {\n completed.add(step.id);\n setJournalEntry(\n results,\n step.id,\n inspection.result,\n `Step ${step.id} result`,\n );\n }\n }\n journal.results = results;\n journal.completedStepIds = steps\n .map((step) => step.id)\n .filter((stepId) => completed.has(stepId));\n}\n\nasync function compensateAppliedSteps(\n options: CommitWorkspaceTransactionOptions,\n journal: WorkspaceTransactionJournal,\n): Promise<void> {\n journal.status = \"compensating\";\n await writeJournal(options.pmRoot, journal);\n await emitTransition(options, journal, \"compensating\");\n const completed = new Set(journal.completedStepIds);\n const started = new Set(journal.startedStepIds);\n for (const step of [...options.steps].reverse()) {\n if (!started.has(step.id) && !completed.has(step.id)) continue;\n let shouldCompensate: boolean;\n try {\n shouldCompensate =\n started.has(step.id) && (await step.inspect()).state === \"applied\";\n } catch {\n shouldCompensate = started.has(step.id);\n }\n if (shouldCompensate) {\n await emitTransition(options, journal, \"step_compensating\", step.id);\n await step.compensate(journal.compensationData[step.id]);\n }\n completed.delete(step.id);\n started.delete(step.id);\n journal.completedStepIds = options.steps\n .map((candidate) => candidate.id)\n .filter((stepId) => completed.has(stepId));\n journal.startedStepIds = options.steps\n .map((candidate) => candidate.id)\n .filter((stepId) => started.has(stepId));\n delete journal.results[step.id];\n delete journal.compensationData[step.id];\n await writeJournal(options.pmRoot, journal);\n await emitTransition(options, journal, \"step_compensated\", step.id);\n }\n journal.status = \"compensated\";\n await writeJournal(options.pmRoot, journal);\n await emitTransition(options, journal, \"compensated\");\n}\n\n/**\n * Commit an ordered set of idempotent SDK mutations under one workspace writer\n * lock. The durable journal resumes interrupted forward work, while ordinary\n * failures append reverse-order compensations. This provides atomic logical\n * replay without deleting or rewriting immutable domain histories.\n */\nexport async function commitWorkspaceTransaction(\n options: CommitWorkspaceTransactionOptions,\n): Promise<WorkspaceTransactionCommitResult> {\n const pmRoot = requiredText(options.pmRoot, \"Transaction pmRoot\");\n const transactionId = requiredIdentifier(\n options.transactionId,\n \"Transaction id\",\n );\n const author = requiredText(options.author, \"Transaction author\");\n const lockTtlSeconds = positiveInteger(\n options.lockTtlSeconds,\n DEFAULT_LOCK_TTL_SECONDS,\n \"Transaction lock TTL\",\n );\n const lockWaitMs = positiveInteger(\n options.lockWaitMs,\n DEFAULT_LOCK_WAIT_MS,\n \"Transaction lock wait\",\n );\n const steps = [...options.steps];\n if (steps.length === 0)\n throw new TypeError(\"Workspace transaction requires at least one step\");\n const stepIds = steps.map((step) => {\n const stepId = requiredIdentifier(step.id, \"Transaction step id\");\n if (stepId !== step.id)\n throw new TypeError(\n \"Transaction step id must not contain surrounding whitespace\",\n );\n return stepId;\n });\n if (new Set(stepIds).size !== stepIds.length)\n throw new TypeError(\"Workspace transaction step ids must be unique\");\n const stableOptions: CommitWorkspaceTransactionOptions = {\n ...options,\n pmRoot,\n transactionId,\n author,\n steps,\n lockTtlSeconds,\n lockWaitMs,\n };\n\n const release = await acquireLock(\n pmRoot,\n WORKSPACE_TRANSACTION_LOCK_ID,\n lockTtlSeconds,\n author,\n false,\n false,\n lockWaitMs,\n );\n try {\n const existing = await loadJournal(pmRoot, transactionId, stepIds);\n const recovered = existing !== undefined;\n if (existing?.status === \"committed\")\n return {\n transactionId,\n status: \"committed\",\n recovered: true,\n results: createResultMap(existing.results),\n };\n const prepared = await prepareJournalForApply(\n stableOptions,\n transactionId,\n author,\n stepIds,\n existing,\n );\n return await applyPreparedTransaction(\n stableOptions,\n prepared.journal,\n recovered || prepared.recovered,\n );\n } finally {\n await release();\n }\n}\n"],"names":[],"mappings":"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","debugId":"2f31b5a8-1462-545e-aa55-8e8f09f511b5"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Agent UX Contracts
|
|
2
|
+
|
|
3
|
+
Tracker references: [pm-v1yo](../.agents/pm/issues/pm-v1yo.toon), [pm-i6pi](../.agents/pm/issues/pm-i6pi.toon), [pm-um4g](../.agents/pm/issues/pm-um4g.toon), [pm-tmhs](../.agents/pm/issues/pm-tmhs.toon), [pm-6m1i](../.agents/pm/issues/pm-6m1i.toon), [pm-cj9v](../.agents/pm/issues/pm-cj9v.toon), [pm-yp56](../.agents/pm/issues/pm-yp56.toon).
|
|
4
|
+
|
|
5
|
+
These contracts keep common agent loops deterministic, token-efficient, and recoverable. Runtime contracts and `--help --json` remain the exact source for available flags.
|
|
6
|
+
|
|
7
|
+
## Relationship mutations
|
|
8
|
+
|
|
9
|
+
`pm create`, `pm update`, and `pm update-many` preserve existing relationship data, including legacy cycles. When a mutation introduces a new cycle through an ordering relationship such as `blocked_by`, the result includes an `ordering_cycle_created:` warning with a concrete cycle path and a `pm graph audit` recovery pointer.
|
|
10
|
+
|
|
11
|
+
The public SDK exports `collectNewOrderingCycleWarnings(beforeItems, afterItems, changedItemId)` from `@unbrained/pm-cli/sdk`. Package authors can apply the same immutable-snapshot advisory to custom mutation workflows; activated custom relationship kinds participate through the shared registry.
|
|
12
|
+
|
|
13
|
+
`pm graph audit` uses two explicit units:
|
|
14
|
+
|
|
15
|
+
- `finding_count`, `findings_by_severity`, and `findings_by_code` count finding rows.
|
|
16
|
+
- `affected_subjects_by_severity` and `affected_subjects_by_code` count the items or edges represented by those findings.
|
|
17
|
+
|
|
18
|
+
Compatibility note: before the 2026.7.19 release, `findings_by_code` incorrectly accumulated affected-subject counts while `findings_by_severity` counted finding rows. SDK and JSON consumers that depended on that old unit must migrate to `affected_subjects_by_code`; consumers comparing code and severity finding counts should keep using `findings_by_code`.
|
|
19
|
+
|
|
20
|
+
## Extension command ownership
|
|
21
|
+
|
|
22
|
+
Extension handler aliases may create their own command groups, but they may not replace a core command or graft a handler beneath a core-owned command prefix. Collisions preserve the core command and emit `extension_command_collision:` with the core and extension owners. Package authors should rename or namespace the alias.
|
|
23
|
+
|
|
24
|
+
## Context and work selection
|
|
25
|
+
|
|
26
|
+
When an agenda event belongs to an item already emitted in `high_level`, `low_level`, or `blocked_fallback`, `pm context` emits a compact event containing `reference_only: true`, the item ID, time, kind, and event-specific data. Unlisted agenda items retain the full calendar projection.
|
|
27
|
+
|
|
28
|
+
`pm next --assignee <identity>` ranks from that assignee's perspective unless `--caller-author` explicitly overrides it. This makes delegated work selection useful without temporarily changing `PM_AUTHOR`.
|
|
29
|
+
|
|
30
|
+
Claim conflicts distinguish stored assignment from an explicit claim:
|
|
31
|
+
|
|
32
|
+
- `assigned to <identity>` means assignment metadata owns the current value.
|
|
33
|
+
- `claimed by <identity>` means the latest ownership mutation was `pm claim`.
|
|
34
|
+
|
|
35
|
+
The structured conflict code remains `already_claimed_by` for compatibility with atomic claim retry loops.
|
|
36
|
+
|
|
37
|
+
## Input and tracker recovery
|
|
38
|
+
|
|
39
|
+
`--message` labels mutation history; it is never comment content. A comment invocation that supplies `--message` without positional text, `--add`, `--stdin`, or `--file` exits with a usage error instead of silently listing comments.
|
|
40
|
+
|
|
41
|
+
Implicit tracker discovery covers the default `.agents/pm` layout and ancestor root-layout trackers. If the command misses those layouts but detects a directly nested custom tracker, recovery guidance names the existing root and shows both `--pm-path <root>` and `PM_PATH=<root>` forms. Initialize a new tracker only when no intended existing root is available.
|
package/docs/EXTENSIONS.md
CHANGED
|
@@ -225,6 +225,7 @@ First-party package exemplars:
|
|
|
225
225
|
- [`pm-search-advanced`](../packages/pm-search-advanced/README.md): deterministic local search provider registration.
|
|
226
226
|
- [`pm-templates`](../packages/pm-templates/README.md): reusable create-template package.
|
|
227
227
|
- [`pm-todos`](../packages/pm-todos/README.md): todo import/export package with generated command contracts.
|
|
228
|
+
- [`pm-vcs`](../packages/pm-vcs/README.md): deliberately non-PM VCS exemplar using custom schema, lifecycle commands, point-in-time reads, and durable relationship projections entirely through public SDK contracts.
|
|
228
229
|
|
|
229
230
|
## Governance Policy
|
|
230
231
|
|
|
@@ -296,17 +297,16 @@ Common APIs:
|
|
|
296
297
|
- `api.registerFlags(command, flags)` adds runtime command flags. A flag may declare `value_type` (canonical; the legacy `type` alias is honored only when `value_type` is absent), `list: true` to accumulate repeated/comma-joined values like core `--tags`, and a `default` applied when the flag is omitted.
|
|
297
298
|
- `api.registerItemFields(fields)` adds custom metadata fields. Agents can set declared fields with repeatable `pm create --field name=value` and `pm update <id> --field name=value`; undeclared names are rejected. Each field `type` is validated against `string | number | boolean | array | object` at activation, with a did-you-mean hint on typos.
|
|
298
299
|
- `api.registerItemTypes(types)` adds custom item types.
|
|
300
|
+
- `api.registerRelationshipKinds(definitions)` adds validated graph semantics. Definitions declare direction, inverse spelling, ordering/precedence, hierarchy, cardinality, lifecycle, aliases, payload schema, compatibility version, and self-edge policy. Active definitions are merged into native CLI, MCP, and SDK workspace graph assembly. Requires the `schema` capability and is governed by the `schema.relationshipkinds` policy surface.
|
|
299
301
|
- `api.registerMigration(definition)` adds schema migrations.
|
|
300
302
|
- `api.registerProfile(profile)` contributes a project profile — a declarative archetype bundling item types, statuses, fields, per-type workflows, config, templates, and package recommendations. Once active it resolves by name through `pm profile list/show/apply` alongside the core `agile`/`ops`/`research` archetypes (built-in names are reserved; a colliding registration is ignored with a warning). Requires the `schema` capability.
|
|
301
303
|
- `api.registerService("output_format", handler)` customizes output formatting through the service override API. Return `context.payload`, `null`, or `undefined` for commands the extension does not own.
|
|
302
304
|
- `api.registerRenderer("toon" | "json", renderer)` adds format-specific renderers. Return `null` for unrelated payloads so pm falls back to native rendering.
|
|
303
|
-
- `suppressHostOutput(result?)` from `@unbrained/pm-cli/sdk`
|
|
304
|
-
result marker for commands that already wrote their output. The CLI emits no
|
|
305
|
-
second payload; the optional `result` remains available to hooks, telemetry,
|
|
306
|
-
and embedded hosts.
|
|
305
|
+
- `suppressHostOutput(result?)` from `@unbrained/pm-cli/sdk` marks commands that already wrote output, preventing a second CLI payload while retaining the optional result for hooks, telemetry, and embedded hosts.
|
|
307
306
|
- `api.hooks.beforeCommand(handler)`, `api.hooks.afterCommand(handler)`, `api.hooks.onWrite(handler)`, `api.hooks.onRead(handler)`, and `api.hooks.onIndex(handler)` add lifecycle hooks.
|
|
308
307
|
`afterCommand` receives command outcome fields plus optional compact `affected` item entries for mutations, including `previous_status`, `status`, `changed_fields`, and partial `previous`/`current` item metadata snapshots.
|
|
309
308
|
`onWrite` always includes `path`, `scope`, and `op`; item mutations also add optional `item_id`, `item_type`, `before`, `after`, and `changed_fields`.
|
|
309
|
+
- Registered command handlers receive `context.sdk`, a host-bound service bundle containing a native-action `PmClient`, `getItemAt`, and `openRelationshipEventStore`. The client reuses the already-active extension schema context without recursively loading extensions, so package commands can compose core lifecycle operations safely in CLI and SDK hosts.
|
|
310
310
|
- An optional module-level `deactivate()` export (VS Code-style) is invoked by the host on shutdown/reload — including by the long-running MCP server between native-action requests — to close connections, clear timers, and release resources opened during `activate`. Teardown is best-effort and timeout-bounded by default so it does not block other extensions, except when a host explicitly disables waiting limits with `deactivate_timeout_ms: 0` or `Infinity`, which can wait indefinitely for a hanging `deactivate()` hook.
|
|
311
311
|
|
|
312
312
|
The bundled `pm-lifecycle-hooks` package is the hook exemplar: it declares only
|
package/docs/README.md
CHANGED
|
@@ -39,6 +39,7 @@ pm guide release --json
|
|
|
39
39
|
- [Testing](TESTING.md) - sandbox-safe local tests and linked-test orchestration.
|
|
40
40
|
- [Architecture](ARCHITECTURE.md) - contributor internals: storage, mutation flow, search, extensions, and command contracts.
|
|
41
41
|
- [SDK Primitive Inventory](SDK_PRIMITIVE_INVENTORY.md) - SDK-first migration map and private-import ratchet for CLI/MCP layering.
|
|
42
|
+
- [Agent UX Contracts](AGENT_UX_CONTRACTS.md) - ordering-cycle advisories, graph count units, collision safety, compact context, ownership wording, and recovery behavior.
|
|
42
43
|
- [Packages and Extensions](EXTENSIONS.md) - package install workflows, runtime extension lifecycle, and API reference.
|
|
43
44
|
- [Extension Author Contracts](EXTENSION_AUTHOR_CONTRACTS.md) - the stability guarantees and contract surface package authors build against.
|
|
44
45
|
- [SDK](SDK.md) - public import surfaces and typed authoring examples.
|