@neuronection/assistant-ui 0.18.0 → 0.20.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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/text-diff-view/lineDiff.ts","../src/components/text-diff-view/TextDiffView.tsx"],"names":["i","j","index","TextDiffView"],"mappings":";;;;;;;;AA0BA,IAAM,aAAA,GAAgB,GAAA;AACtB,IAAM,cAAA,GAAiB,GAAA;AAIvB,SAAS,EAAA,CAAM,MAAoB,KAAA,EAAkB;AACnD,EAAA,MAAM,KAAA,GAAQ,KAAK,KAAK,CAAA;AACxB,EAAA,IAAI,UAAU,MAAA,EAAW;AACvB,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,gBAAA,EAAmB,KAAK,CAAA,cAAA,CAAgB,CAAA;AAAA,EAC1D;AACA,EAAA,OAAO,KAAA;AACT;AAEA,SAAS,KAAA,CAAM,MAAkB,KAAA,EAAuB;AACtD,EAAA,MAAM,KAAA,GAAQ,KAAK,KAAK,CAAA;AACxB,EAAA,IAAI,UAAU,MAAA,EAAW;AACvB,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,gBAAA,EAAmB,KAAK,CAAA,cAAA,CAAgB,CAAA;AAAA,EAC1D;AACA,EAAA,OAAO,KAAA;AACT;AAEA,SAAS,WAAW,IAAA,EAAwB;AAC1C,EAAA,IAAI,SAAS,EAAA,EAAI;AACf,IAAA,OAAO,EAAC;AAAA,EACV;AACA,EAAA,OAAO,KAAK,OAAA,CAAQ,QAAA,EAAU,IAAI,CAAA,CAAE,MAAM,IAAI,CAAA;AAChD;AAEA,SAAS,OAAA,CAAQ,CAAA,EAAa,CAAA,EAAa,QAAA,GAAW,aAAA,EAAqB;AACzE,EAAA,MAAM,IAAI,CAAA,CAAE,MAAA;AACZ,EAAA,MAAM,IAAI,CAAA,CAAE,MAAA;AACZ,EAAA,MAAM,MAAY,EAAC;AACnB,EAAA,IAAI,CAAA,GAAI,IAAI,QAAA,EAAU;AACpB,IAAA,KAAA,MAAW,QAAQ,CAAA,EAAG;AACpB,MAAA,GAAA,CAAI,IAAA,CAAK,EAAE,IAAA,EAAM,KAAA,EAAO,MAAM,CAAA;AAAA,IAChC;AACA,IAAA,KAAA,MAAW,QAAQ,CAAA,EAAG;AACpB,MAAA,GAAA,CAAI,IAAA,CAAK,EAAE,IAAA,EAAM,KAAA,EAAO,MAAM,CAAA;AAAA,IAChC;AACA,IAAA,OAAO,GAAA;AAAA,EACT;AACA,EAAA,MAAM,QAAQ,CAAA,GAAI,CAAA;AAClB,EAAA,MAAM,GAAA,GAAM,IAAI,UAAA,CAAA,CAAY,CAAA,GAAI,KAAK,KAAK,CAAA;AAC1C,EAAA,KAAA,IAASA,KAAI,CAAA,GAAI,CAAA,EAAGA,EAAAA,IAAK,CAAA,EAAGA,MAAK,CAAA,EAAG;AAClC,IAAA,KAAA,IAASC,KAAI,CAAA,GAAI,CAAA,EAAGA,EAAAA,IAAK,CAAA,EAAGA,MAAK,CAAA,EAAG;AAClC,MAAA,GAAA,CAAID,KAAI,KAAA,GAAQC,EAAC,CAAA,GACf,EAAA,CAAG,GAAGD,EAAC,CAAA,KAAM,EAAA,CAAG,CAAA,EAAGC,EAAC,CAAA,GAChB,KAAA,CAAM,GAAA,EAAA,CAAMD,EAAAA,GAAI,KAAK,KAAA,GAAQC,EAAAA,GAAI,CAAC,CAAA,GAAI,IACtC,IAAA,CAAK,GAAA,CAAI,KAAA,CAAM,GAAA,EAAA,CAAMD,KAAI,CAAA,IAAK,KAAA,GAAQC,EAAC,CAAA,EAAG,MAAM,GAAA,EAAKD,EAAAA,GAAI,KAAA,GAAQC,EAAAA,GAAI,CAAC,CAAC,CAAA;AAAA,IAC/E;AAAA,EACF;AACA,EAAA,IAAI,CAAA,GAAI,CAAA;AACR,EAAA,IAAI,CAAA,GAAI,CAAA;AACR,EAAA,OAAO,CAAA,GAAI,CAAA,IAAK,CAAA,GAAI,CAAA,EAAG;AACrB,IAAA,IAAI,GAAG,CAAA,EAAG,CAAC,MAAM,EAAA,CAAG,CAAA,EAAG,CAAC,CAAA,EAAG;AACzB,MAAA,GAAA,CAAI,IAAA,CAAK,EAAE,IAAA,EAAM,OAAA,EAAS,MAAM,EAAA,CAAG,CAAA,EAAG,CAAC,CAAA,EAAG,CAAA;AAC1C,MAAA,CAAA,IAAK,CAAA;AACL,MAAA,CAAA,IAAK,CAAA;AAAA,IACP,CAAA,MAAA,IAAW,KAAA,CAAM,GAAA,EAAA,CAAM,CAAA,GAAI,KAAK,KAAA,GAAQ,CAAC,CAAA,IAAK,KAAA,CAAM,GAAA,EAAK,CAAA,GAAI,KAAA,GAAQ,CAAA,GAAI,CAAC,CAAA,EAAG;AAC3E,MAAA,GAAA,CAAI,IAAA,CAAK,EAAE,IAAA,EAAM,KAAA,EAAO,MAAM,EAAA,CAAG,CAAA,EAAG,CAAC,CAAA,EAAG,CAAA;AACxC,MAAA,CAAA,IAAK,CAAA;AAAA,IACP,CAAA,MAAO;AACL,MAAA,GAAA,CAAI,IAAA,CAAK,EAAE,IAAA,EAAM,KAAA,EAAO,MAAM,EAAA,CAAG,CAAA,EAAG,CAAC,CAAA,EAAG,CAAA;AACxC,MAAA,CAAA,IAAK,CAAA;AAAA,IACP;AAAA,EACF;AACA,EAAA,OAAO,IAAI,CAAA,EAAG;AACZ,IAAA,GAAA,CAAI,IAAA,CAAK,EAAE,IAAA,EAAM,KAAA,EAAO,MAAM,EAAA,CAAG,CAAA,EAAG,CAAC,CAAA,EAAG,CAAA;AACxC,IAAA,CAAA,IAAK,CAAA;AAAA,EACP;AACA,EAAA,OAAO,IAAI,CAAA,EAAG;AACZ,IAAA,GAAA,CAAI,IAAA,CAAK,EAAE,IAAA,EAAM,KAAA,EAAO,MAAM,EAAA,CAAG,CAAA,EAAG,CAAC,CAAA,EAAG,CAAA;AACxC,IAAA,CAAA,IAAK,CAAA;AAAA,EACP;AACA,EAAA,OAAO,GAAA;AACT;AAEA,SAAS,SAAS,IAAA,EAAwB;AACxC,EAAA,OAAO,IAAA,CAAK,KAAA,CAAM,UAAU,CAAA,IAAK,EAAC;AACpC;AAEA,SAAS,aAAa,KAAA,EAAwB;AAC5C,EAAA,OAAO,IAAA,CAAK,KAAK,KAAK,CAAA;AACxB;AAEA,SAAS,cAAc,QAAA,EAAwC;AAC7D,EAAA,MAAM,SAAwB,EAAC;AAC/B,EAAA,KAAA,MAAW,WAAW,QAAA,EAAU;AAC9B,IAAA,MAAM,IAAA,GAAO,MAAA,CAAO,MAAA,CAAO,MAAA,GAAS,CAAC,CAAA;AACrC,IAAA,IAAI,IAAA,KAAS,MAAA,IAAa,IAAA,CAAK,OAAA,KAAY,QAAQ,OAAA,EAAS;AAC1D,MAAA,IAAA,CAAK,QAAQ,OAAA,CAAQ,IAAA;AAAA,IACvB,CAAA,MAAO;AACL,MAAA,MAAA,CAAO,IAAA,CAAK,EAAE,GAAG,OAAA,EAAS,CAAA;AAAA,IAC5B;AAAA,EACF;AACA,EAAA,OAAO,MAAA;AACT;AAEO,SAAS,YAAA,CACd,UACA,SAAA,EAC+C;AAC/C,EAAA,MAAM,CAAA,GAAI,SAAS,QAAQ,CAAA;AAC3B,EAAA,MAAM,CAAA,GAAI,SAAS,SAAS,CAAA;AAC5B,EAAA,MAAM,GAAA,GAAM,OAAA,CAAQ,CAAA,EAAG,CAAA,EAAG,cAAc,CAAA;AACxC,EAAA,MAAM,OAAsB,EAAC;AAC7B,EAAA,MAAM,QAAuB,EAAC;AAC9B,EAAA,KAAA,MAAW,MAAM,GAAA,EAAK;AACpB,IAAA,IAAI,EAAA,CAAG,SAAS,OAAA,EAAS;AACvB,MAAA,IAAA,CAAK,KAAK,EAAE,IAAA,EAAM,GAAG,IAAA,EAAM,OAAA,EAAS,OAAO,CAAA;AAC3C,MAAA,KAAA,CAAM,KAAK,EAAE,IAAA,EAAM,GAAG,IAAA,EAAM,OAAA,EAAS,OAAO,CAAA;AAAA,IAC9C,CAAA,MAAA,IAAW,EAAA,CAAG,IAAA,KAAS,KAAA,EAAO;AAC5B,MAAA,IAAA,CAAK,IAAA,CAAK,EAAE,IAAA,EAAM,EAAA,CAAG,IAAA,EAAM,SAAS,YAAA,CAAa,EAAA,CAAG,IAAI,CAAA,EAAG,CAAA;AAAA,IAC7D,CAAA,MAAO;AACL,MAAA,KAAA,CAAM,IAAA,CAAK,EAAE,IAAA,EAAM,EAAA,CAAG,IAAA,EAAM,SAAS,YAAA,CAAa,EAAA,CAAG,IAAI,CAAA,EAAG,CAAA;AAAA,IAC9D;AAAA,EACF;AACA,EAAA,OAAO,EAAE,MAAM,aAAA,CAAc,IAAI,GAAG,KAAA,EAAO,aAAA,CAAc,KAAK,CAAA,EAAE;AAClE;AAEA,SAAS,SAAS,GAAA,EAAsB;AACtC,EAAA,MAAM,OAAkB,EAAC;AACzB,EAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,EAAA,OAAO,KAAA,GAAQ,IAAI,MAAA,EAAQ;AACzB,IAAA,MAAM,EAAA,GAAK,EAAA,CAAG,GAAA,EAAK,KAAK,CAAA;AACxB,IAAA,IAAI,EAAA,CAAG,SAAS,OAAA,EAAS;AACvB,MAAA,IAAA,CAAK,IAAA,CAAK;AAAA,QACR,IAAA,EAAM,MAAA;AAAA,QACN,MAAM,EAAE,IAAA,EAAM,SAAA,EAAW,IAAA,EAAM,GAAG,IAAA,EAAK;AAAA,QACvC,OAAO,EAAE,IAAA,EAAM,SAAA,EAAW,IAAA,EAAM,GAAG,IAAA;AAAK,OACzC,CAAA;AACD,MAAA,KAAA,IAAS,CAAA;AACT,MAAA;AAAA,IACF;AACA,IAAA,MAAM,OAAiB,EAAC;AACxB,IAAA,MAAM,OAAiB,EAAC;AACxB,IAAA,OAAO,KAAA,GAAQ,IAAI,MAAA,IAAU,EAAA,CAAG,KAAK,KAAK,CAAA,CAAE,SAAS,OAAA,EAAS;AAC5D,MAAA,MAAM,OAAA,GAAU,EAAA,CAAG,GAAA,EAAK,KAAK,CAAA;AAC7B,MAAA,IAAI,OAAA,CAAQ,SAAS,KAAA,EAAO;AAC1B,QAAA,IAAA,CAAK,IAAA,CAAK,QAAQ,IAAI,CAAA;AAAA,MACxB,CAAA,MAAO;AACL,QAAA,IAAA,CAAK,IAAA,CAAK,QAAQ,IAAI,CAAA;AAAA,MACxB;AACA,MAAA,KAAA,IAAS,CAAA;AAAA,IACX;AACA,IAAA,MAAM,YAAY,IAAA,CAAK,GAAA,CAAI,IAAA,CAAK,MAAA,EAAQ,KAAK,MAAM,CAAA;AACnD,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,SAAA,EAAW,KAAK,CAAA,EAAG;AACrC,MAAA,MAAM,WAAW,CAAA,GAAI,IAAA,CAAK,SAAS,EAAA,CAAG,IAAA,EAAM,CAAC,CAAA,GAAI,IAAA;AACjD,MAAA,MAAM,YAAY,CAAA,GAAI,IAAA,CAAK,SAAS,EAAA,CAAG,IAAA,EAAM,CAAC,CAAA,GAAI,IAAA;AAClD,MAAA,MAAM,QAAA,GACJ,aAAa,IAAA,GAAO,EAAE,MAAM,KAAA,EAAO,IAAA,EAAM,UAAS,GAAI,IAAA;AACxD,MAAA,MAAM,SAAA,GACJ,cAAc,IAAA,GAAO,EAAE,MAAM,KAAA,EAAO,IAAA,EAAM,WAAU,GAAI,IAAA;AAC1D,MAAA,IACE,QAAA,KAAa,QACb,SAAA,KAAc,IAAA,IACd,aAAa,IAAA,IACb,SAAA,KAAc,IAAA,IACd,QAAA,KAAa,SAAA,EACb;AACA,QAAA,MAAM,KAAA,GAAQ,YAAA,CAAa,QAAA,EAAU,SAAS,CAAA;AAC9C,QAAA,QAAA,CAAS,WAAW,KAAA,CAAM,IAAA;AAC1B,QAAA,SAAA,CAAU,WAAW,KAAA,CAAM,KAAA;AAAA,MAC7B;AACA,MAAA,IAAA,CAAK,IAAA,CAAK,EAAE,IAAA,EAAM,MAAA,EAAQ,MAAM,QAAA,EAAU,KAAA,EAAO,WAAW,CAAA;AAAA,IAC9D;AAAA,EACF;AACA,EAAA,OAAO,IAAA;AACT;AAEA,SAAS,WAAW,IAAA,EAAuB;AACzC,EAAA,IAAI,MAAA,GAAS,CAAA;AACb,EAAA,IAAI,OAAA,GAAU,CAAA;AACd,EAAA,KAAA,MAAW,OAAO,IAAA,EAAM;AACtB,IAAA,IAAI,GAAA,CAAI,SAAS,MAAA,EAAQ;AACvB,MAAA;AAAA,IACF;AACA,IAAA,IAAI,GAAA,CAAI,SAAS,IAAA,EAAM;AACrB,MAAA,MAAA,IAAU,CAAA;AACV,MAAA,GAAA,CAAI,KAAK,EAAA,GAAK,MAAA;AAAA,IAChB;AACA,IAAA,IAAI,GAAA,CAAI,UAAU,IAAA,EAAM;AACtB,MAAA,OAAA,IAAW,CAAA;AACX,MAAA,GAAA,CAAI,MAAM,EAAA,GAAK,OAAA;AAAA,IACjB;AAAA,EACF;AACF;AAEA,SAAS,QAAA,CAAS,MAAiB,YAAA,EAAiC;AAClE,EAAA,MAAM,SAAA,GAAY,IAAA,CAAK,IAAA,CAAK,CAAC,GAAA,KAAQ;AACnC,IAAA,IAAI,GAAA,CAAI,SAAS,MAAA,EAAQ;AACvB,MAAA,OAAO,KAAA;AAAA,IACT;AACA,IAAA,OAAO,IAAI,IAAA,EAAM,IAAA,KAAS,SAAA,IAAa,GAAA,CAAI,OAAO,IAAA,KAAS,SAAA;AAAA,EAC7D,CAAC,CAAA;AACD,EAAA,IAAI,CAAC,SAAA,IAAa,YAAA,GAAe,CAAA,EAAG;AAClC,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,MAAM,OAAyC,EAAC;AAChD,EAAA,IAAI,KAAA,GAAQ,EAAA;AACZ,EAAA,KAAA,IAASC,SAAQ,CAAA,EAAGA,MAAAA,IAAS,IAAA,CAAK,MAAA,EAAQA,UAAS,CAAA,EAAG;AACpD,IAAA,MAAM,GAAA,GAAM,KAAKA,MAAK,CAAA;AACtB,IAAA,MAAM,SAAA,GACJA,MAAAA,GAAQ,IAAA,CAAK,MAAA,IACb,QAAQ,MAAA,IACR,GAAA,CAAI,IAAA,KAAS,MAAA,IACb,IAAI,IAAA,EAAM,IAAA,KAAS,SAAA,IACnB,GAAA,CAAI,OAAO,IAAA,KAAS,SAAA;AACtB,IAAA,IAAI,SAAA,EAAW;AACb,MAAA,IAAI,UAAU,EAAA,EAAI;AAChB,QAAA,KAAA,GAAQA,MAAAA;AAAA,MACV;AAAA,IACF,CAAA,MAAA,IAAW,UAAU,EAAA,EAAI;AACvB,MAAA,IAAA,CAAK,IAAA,CAAK,EAAE,KAAA,EAAO,GAAA,EAAKA,QAAO,CAAA;AAC/B,MAAA,KAAA,GAAQ,EAAA;AAAA,IACV;AAAA,EACF;AACA,EAAA,MAAM,QAAA,uBAAe,GAAA,EAAuB;AAC5C,EAAA,KAAA,MAAW,OAAO,IAAA,EAAM;AACtB,IAAA,MAAM,MAAA,GAAS,GAAA,CAAI,GAAA,GAAM,GAAA,CAAI,KAAA;AAC7B,IAAA,MAAM,UAAA,GAAa,IAAI,KAAA,KAAU,CAAA;AACjC,IAAA,MAAM,SAAA,GAAY,GAAA,CAAI,GAAA,KAAQ,IAAA,CAAK,MAAA;AACnC,IAAA,MAAM,UAAA,GAAa,aAAa,CAAA,GAAI,YAAA;AACpC,IAAA,MAAM,SAAA,GAAY,YAAY,CAAA,GAAI,YAAA;AAClC,IAAA,MAAM,SAAA,GAAY,SAAS,UAAA,GAAa,SAAA;AACxC,IAAA,IAAI,aAAa,CAAA,EAAG;AAClB,MAAA;AAAA,IACF;AACA,IAAA,MAAM,MAAA,GAAS,KAAK,KAAA,CAAM,GAAA,CAAI,QAAQ,UAAA,EAAY,GAAA,CAAI,KAAA,GAAQ,UAAA,GAAa,SAAS,CAAA;AACpF,IAAA,QAAA,CAAS,GAAA,CAAI,GAAA,CAAI,KAAA,GAAQ,UAAA,EAAY,MAAM,CAAA;AAAA,EAC7C;AACA,EAAA,MAAM,SAAoB,EAAC;AAC3B,EAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,EAAA,OAAO,KAAA,GAAQ,KAAK,MAAA,EAAQ;AAC1B,IAAA,MAAM,MAAA,GAAS,QAAA,CAAS,GAAA,CAAI,KAAK,CAAA;AACjC,IAAA,IAAI,WAAW,MAAA,EAAW;AACxB,MAAA,MAAA,CAAO,IAAA,CAAK,EAAA,CAAG,IAAA,EAAM,KAAK,CAAC,CAAA;AAC3B,MAAA,KAAA,IAAS,CAAA;AAAA,IACX,CAAA,MAAO;AACL,MAAA,MAAA,CAAO,IAAA,CAAK,EAAE,IAAA,EAAM,MAAA,EAAQ,OAAO,MAAA,CAAO,MAAA,EAAQ,QAAQ,CAAA;AAC1D,MAAA,KAAA,IAAS,MAAA,CAAO,MAAA;AAAA,IAClB;AAAA,EACF;AACA,EAAA,OAAO,MAAA;AACT;AAEO,SAAS,eAAA,CACd,QAAA,EACA,SAAA,EACA,OAAA,GAA2B,EAAC,EACZ;AAChB,EAAA,MAAM,YAAA,GAAe,QAAQ,YAAA,IAAgB,CAAA;AAC7C,EAAA,MAAM,MAAM,OAAA,CAAQ,UAAA,CAAW,QAAQ,CAAA,EAAG,UAAA,CAAW,SAAS,CAAC,CAAA;AAC/D,EAAA,MAAM,QAAA,GAAW,SAAS,GAAG,CAAA;AAC7B,EAAA,UAAA,CAAW,QAAQ,CAAA;AACnB,EAAA,MAAM,IAAA,GAAO,QAAA,CAAS,QAAA,EAAU,YAAY,CAAA;AAC5C,EAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,EAAA,IAAI,OAAA,GAAU,CAAA;AACd,EAAA,KAAA,MAAW,OAAO,QAAA,EAAU;AAC1B,IAAA,IAAI,GAAA,CAAI,SAAS,MAAA,EAAQ;AACvB,MAAA;AAAA,IACF;AACA,IAAA,IAAI,GAAA,CAAI,KAAA,EAAO,IAAA,KAAS,KAAA,EAAO;AAC7B,MAAA,KAAA,IAAS,CAAA;AAAA,IACX;AACA,IAAA,IAAI,GAAA,CAAI,IAAA,EAAM,IAAA,KAAS,KAAA,EAAO;AAC5B,MAAA,OAAA,IAAW,CAAA;AAAA,IACb;AAAA,EACF;AACA,EAAA,OAAO,EAAE,IAAA,EAAM,KAAA,EAAO,OAAA,EAAQ;AAChC;AC9QA,IAAM,cAAA,GAA+C;AAAA,EACnD,QAAA,EAAU,UAAA;AAAA,EACV,SAAA,EAAW,WAAA;AAAA,EACX,gBAAgB,CAAC,KAAA,KACf,UAAU,CAAA,GAAI,kBAAA,GAAqB,GAAG,KAAK,CAAA,gBAAA,CAAA;AAAA,EAC7C,QAAA,EAAU,WAAA;AAAA,EACV,UAAA,EAAY,iBAAA;AAAA,EACZ,UAAA,EAAY,aAAA;AAAA,EACZ,gBAAgB,CAAC,KAAA,EAAO,UAAU,CAAA,EAAG,KAAK,IAAI,KAAK,CAAA;AACrD,CAAA;AAgBA,SAAS,aAAa,GAAA,EAAuB;AAC3C,EAAA,OACE,GAAA,CAAI,SAAS,MAAA,KACZ,GAAA,CAAI,MAAM,IAAA,KAAS,KAAA,IAAS,GAAA,CAAI,KAAA,EAAO,IAAA,KAAS,KAAA,CAAA;AAErD;AASA,SAAS,WAAA,CAAY,EAAE,IAAA,EAAK,EAAuB;AACjD,EAAA,IAAI,IAAA,CAAK,aAAa,MAAA,EAAW;AAC/B,IAAA,uBAAO,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,iCAAA,EAAmC,eAAK,IAAA,EAAK,CAAA;AAAA,EACtE;AACA,EAAA,uBACE,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,iCAAA,EACb,eAAK,QAAA,CAAS,GAAA;AAAA,IAAI,CAAC,OAAA,EAAS,KAAA,KAC3B,OAAA,CAAQ,OAAA,mBACN,GAAA;AAAA,MAAC,MAAA;AAAA,MAAA;AAAA,QAEC,SAAA,EAAW,EAAA;AAAA,UACT,4BAAA;AAAA,UACA,IAAA,CAAK,IAAA,KAAS,KAAA,GAAQ,2BAAA,GAA8B;AAAA,SACtD;AAAA,QAEC,QAAA,EAAA,OAAA,CAAQ;AAAA,OAAA;AAAA,MANJ;AAAA,KAOP,mBAEA,GAAA,CAAC,MAAA,EAAA,EAAkB,QAAA,EAAA,OAAA,CAAQ,QAAhB,KAAqB;AAAA,GAEpC,EACF,CAAA;AAEJ;AAEO,IAAM,YAAA,GAAqB,KAAA,CAAA,UAAA;AAAA,EAChC,SAASC,aAAAA,CACP;AAAA,IACE,QAAA;AAAA,IACA,SAAA;AAAA,IACA,YAAA,GAAe,CAAA;AAAA,IACf,UAAA,GAAa,IAAA;AAAA,IACb,OAAA,GAAU,IAAA;AAAA,IACV,MAAA;AAAA,IACA,SAAA;AAAA,IACA;AAAA,KAEF,GAAA,EACA;AACA,IAAA,MAAM,YAAA,GAAe,EAAE,GAAG,cAAA,EAAgB,GAAG,MAAA,EAAO;AACpD,IAAA,MAAM,CAAC,QAAA,EAAU,WAAW,IAAI,QAAA,iBAAsB,IAAI,KAAK,CAAA;AAC/D,IAAA,MAAM,CAAC,WAAA,EAAa,cAAc,CAAA,GAAI,SAAS,CAAC,CAAA;AAChD,IAAA,MAAM,SAAA,GAAkB,aAA8B,IAAI,CAAA;AAC1D,IAAA,MAAM,IAAA,GAAO,OAAA;AAAA,MACX,MAAM,eAAA,CAAgB,QAAA,EAAU,SAAA,EAAW,EAAE,cAAc,CAAA;AAAA,MAC3D,CAAC,QAAA,EAAU,SAAA,EAAW,YAAY;AAAA,KACpC;AAEA,IAAA,MAAM,QAAA,GAAW,QAAmB,MAAM;AACxC,MAAA,MAAM,MAAiB,EAAC;AACxB,MAAA,IAAA,CAAK,IAAA,CAAK,OAAA,CAAQ,CAAC,GAAA,EAAK,KAAA,KAAU;AAChC,QAAA,IAAI,IAAI,IAAA,KAAS,MAAA,IAAU,QAAA,CAAS,GAAA,CAAI,KAAK,CAAA,EAAG;AAC9C,UAAA,GAAA,CAAI,MAAA,CAAO,OAAA,CAAQ,CAAC,SAAA,EAAW,WAAA,KAAgB;AAC7C,YAAA,GAAA,CAAI,IAAA,CAAK,EAAE,GAAA,EAAK,CAAA,EAAG,KAAK,IAAI,WAAW,CAAA,CAAA,EAAI,GAAA,EAAK,SAAA,EAAW,CAAA;AAAA,UAC7D,CAAC,CAAA;AACD,UAAA,GAAA,CAAI,IAAA,CAAK,EAAE,GAAA,EAAK,CAAA,EAAG,KAAK,CAAA,SAAA,CAAA,EAAa,GAAA,EAAK,UAAA,EAAY,KAAA,EAAO,CAAA;AAAA,QAC/D,CAAA,MAAO;AACL,UAAA,GAAA,CAAI,IAAA,CAAK;AAAA,YACP,GAAA,EAAK,OAAO,KAAK,CAAA;AAAA,YACjB,GAAA;AAAA,YACA,MAAA,EAAQ,GAAA,CAAI,IAAA,KAAS,MAAA,GAAS,KAAA,GAAQ;AAAA,WACvC,CAAA;AAAA,QACH;AAAA,MACF,CAAC,CAAA;AACD,MAAA,OAAO,GAAA;AAAA,IACT,CAAA,EAAG,CAAC,IAAA,CAAK,IAAA,EAAM,QAAQ,CAAC,CAAA;AAExB,IAAA,MAAM,YAAA,GAAe,QAAkB,MAAM;AAC3C,MAAA,MAAM,SAAmB,EAAC;AAC1B,MAAA,IAAI,OAAA,GAAU,KAAA;AACd,MAAA,QAAA,CAAS,OAAA,CAAQ,CAAC,KAAA,EAAO,KAAA,KAAU;AACjC,QAAA,MAAM,OAAA,GAAU,YAAA,CAAa,KAAA,CAAM,GAAG,CAAA;AACtC,QAAA,IAAI,OAAA,IAAW,CAAC,OAAA,EAAS;AACvB,UAAA,MAAA,CAAO,KAAK,KAAK,CAAA;AAAA,QACnB;AACA,QAAA,OAAA,GAAU,OAAA;AAAA,MACZ,CAAC,CAAA;AACD,MAAA,OAAO,MAAA;AAAA,IACT,CAAA,EAAG,CAAC,QAAQ,CAAC,CAAA;AAEb,IAAA,MAAM,cAAc,cAAA,CAAe;AAAA,MACjC,OAAO,QAAA,CAAS,MAAA;AAAA,MAChB,gBAAA,EAAkB,MAAM,SAAA,CAAU,OAAA;AAAA,MAClC,cAAc,MAAM,EAAA;AAAA,MACpB,QAAA,EAAU,EAAA;AAAA,MACV,UAAA,EAAY,CAAC,KAAA,KAAU,QAAA,CAAS,KAAK,CAAA,EAAG,GAAA,IAAO,OAAO,KAAK;AAAA,KAC5D,CAAA;AAED,IAAA,SAAA,CAAU,MAAM;AACd,MAAA,WAAA,iBAAY,IAAI,KAAK,CAAA;AACrB,MAAA,cAAA,CAAe,CAAC,CAAA;AAAA,IAClB,CAAA,EAAG,CAAC,QAAA,EAAU,SAAS,CAAC,CAAA;AAExB,IAAA,SAAA,CAAU,MAAM;AACd,MAAA,IAAI,WAAA,IAAe,aAAa,MAAA,EAAQ;AACtC,QAAA,cAAA,CAAe,CAAC,CAAA;AAAA,MAClB;AAAA,IACF,CAAA,EAAG,CAAC,WAAA,EAAa,YAAA,CAAa,MAAM,CAAC,CAAA;AAErC,IAAA,SAAA,CAAU,MAAM;AACd,MAAA,MAAM,MAAA,GAAS,aAAa,WAAW,CAAA;AACvC,MAAA,IAAI,WAAW,MAAA,EAAW;AACxB,QAAA,WAAA,CAAY,aAAA,CAAc,MAAA,EAAQ,EAAE,KAAA,EAAO,UAAU,CAAA;AAAA,MACvD;AAAA,IACF,CAAA,EAAG,CAAC,WAAA,EAAa,YAAA,EAAc,WAAW,CAAC,CAAA;AAE3C,IAAA,IAAI,IAAA,CAAK,KAAA,KAAU,CAAA,IAAK,IAAA,CAAK,YAAY,CAAA,EAAG;AAC1C,MAAA,uBACE,GAAA;AAAA,QAAC,GAAA;AAAA,QAAA;AAAA,UACC,GAAA;AAAA,UACA,SAAA,EAAW,EAAA;AAAA,YACT,yGAAA;AAAA,YACA;AAAA,WACF;AAAA,UAEC,QAAA,EAAA;AAAA;AAAA,OACH;AAAA,IAEJ;AAEA,IAAA,MAAM,gBAAA,GAAmB,aAAa,WAAW,CAAA;AACjD,IAAA,MAAM,cAAA,GACJ,gBAAA,KAAqB,MAAA,GACjB,MAAA,GAAA,CACC,MAAM;AACL,MAAA,KAAA,IAAS,QAAQ,gBAAA,GAAmB,CAAA,EAAG,QAAQ,QAAA,CAAS,MAAA,EAAQ,SAAS,CAAA,EAAG;AAC1E,QAAA,MAAM,KAAA,GAAQ,SAAS,KAAK,CAAA;AAC5B,QAAA,IAAI,KAAA,KAAU,MAAA,IAAa,YAAA,CAAa,KAAA,CAAM,GAAG,CAAA,EAAG;AAClD,UAAA,OAAO,KAAA;AAAA,QACT;AAAA,MACF;AACA,MAAA,OAAO,QAAA,CAAS,MAAA;AAAA,IAClB,CAAA,GAAG;AAET,IAAA,MAAM,SAAA,GAAY,CAAC,KAAA,EAAgB,KAAA,KAAkB;AACnD,MAAA,MAAM,MAAM,KAAA,CAAM,GAAA;AAClB,MAAA,IAAI,GAAA,CAAI,SAAS,MAAA,EAAQ;AACvB,QAAA,IAAI,KAAA,CAAM,eAAe,MAAA,EAAW;AAClC,UAAA,MAAM,aAAa,KAAA,CAAM,UAAA;AACzB,UAAA,uBACE,IAAA;AAAA,YAAC,QAAA;AAAA,YAAA;AAAA,cAEC,IAAA,EAAK,QAAA;AAAA,cACL,OAAA,EAAS,MACP,WAAA,CAAY,CAAC,OAAA,KAAY;AACvB,gBAAA,MAAM,IAAA,GAAO,IAAI,GAAA,CAAI,OAAO,CAAA;AAC5B,gBAAA,IAAA,CAAK,OAAO,UAAU,CAAA;AACtB,gBAAA,OAAO,IAAA;AAAA,cACT,CAAC,CAAA;AAAA,cAEH,SAAA,EAAU,kJAAA;AAAA,cAEV,QAAA,EAAA;AAAA,gCAAA,GAAA,CAAC,WAAA,EAAA,EAAY,SAAA,EAAU,QAAA,EAAS,aAAA,EAAW,IAAA,EAAC,CAAA;AAAA,gBAC3C,YAAA,CAAa;AAAA;AAAA,aAAA;AAAA,YAZT,KAAA,CAAM;AAAA,WAab;AAAA,QAEJ;AACA,QAAA,MAAM,SAAS,KAAA,CAAM,MAAA;AACrB,QAAA,uBACE,IAAA;AAAA,UAAC,QAAA;AAAA,UAAA;AAAA,YAEC,IAAA,EAAK,QAAA;AAAA,YACL,SAAS,MAAM;AACb,cAAA,IAAI,WAAW,MAAA,EAAW;AACxB,gBAAA,WAAA,CAAY,CAAC,OAAA,KAAY;AACvB,kBAAA,MAAM,IAAA,GAAO,IAAI,GAAA,CAAI,OAAO,CAAA;AAC5B,kBAAA,IAAA,CAAK,IAAI,MAAM,CAAA;AACf,kBAAA,OAAO,IAAA;AAAA,gBACT,CAAC,CAAA;AAAA,cACH;AAAA,YACF,CAAA;AAAA,YACA,SAAA,EAAU,kJAAA;AAAA,YAEV,QAAA,EAAA;AAAA,8BAAA,GAAA,CAAC,YAAA,EAAA,EAAa,SAAA,EAAU,QAAA,EAAS,aAAA,EAAW,IAAA,EAAC,CAAA;AAAA,cAC5C,YAAA,CAAa,cAAA,CAAe,GAAA,CAAI,KAAK;AAAA;AAAA,WAAA;AAAA,UAdjC,KAAA,CAAM;AAAA,SAeb;AAAA,MAEJ;AACA,MAAA,MAAM,OAAA,GAAU,aAAa,GAAG,CAAA;AAChC,MAAA,MAAM,SACJ,gBAAA,KAAqB,MAAA,IACrB,mBAAmB,MAAA,IACnB,KAAA,IAAS,oBACT,KAAA,GAAQ,cAAA;AACV,MAAA,uBACE,GAAA;AAAA,QAAC,KAAA;AAAA,QAAA;AAAA,UAEC,SAAA,EAAW,EAAA,CAAG,kBAAA,EAAoB,MAAA,IAAU,0BAA0B,CAAA;AAAA,UACtE,gBAAc,OAAA,IAAW,MAAA;AAAA,UACzB,eAAa,MAAA,IAAU,MAAA;AAAA,UAErB,WAAC,MAAA,EAAQ,OAAO,CAAA,CAAY,GAAA,CAAI,CAAC,IAAA,KAAS;AAC1C,YAAA,MAAM,IAAA,GAAO,IAAI,IAAI,CAAA;AACrB,YAAA,MAAM,KAAA,GAAQ,MAAM,IAAA,KAAS,KAAA;AAC7B,YAAA,MAAM,KAAA,GAAQ,MAAM,IAAA,KAAS,KAAA;AAC7B,YAAA,uBACE,IAAA;AAAA,cAAC,KAAA;AAAA,cAAA;AAAA,gBAEC,SAAA,EAAW,EAAA;AAAA,kBACT,kCAAA;AAAA,kBACA,KAAA,IAAS,oDAAA;AAAA,kBACT,KAAA,IAAS;AAAA,iBACX;AAAA,gBAEA,QAAA,EAAA;AAAA,kCAAA,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,uFAAA,EACb,QAAA,EAAA,IAAA,EAAM,MAAM,EAAA,EACf,CAAA;AAAA,kCACA,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,sCAAA,EAAuC,aAAA,EAAW,MAC/D,QAAA,EAAA,KAAA,GAAQ,GAAA,GAAM,KAAA,GAAQ,GAAA,GAAM,EAAA,EAC/B,CAAA;AAAA,kCACA,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,gBAAA,EACb,QAAA,EAAA,IAAA,KAAS,OAAO,IAAA,mBAAO,GAAA,CAAC,WAAA,EAAA,EAAY,IAAA,EAAY,CAAA,EACnD;AAAA;AAAA,eAAA;AAAA,cAfK;AAAA,aAgBP;AAAA,UAEJ,CAAC;AAAA,SAAA;AAAA,QA7BI,KAAA,CAAM;AAAA,OA8Bb;AAAA,IAEJ,CAAA;AAEA,IAAA,uBACE,IAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,GAAA;AAAA,QACA,SAAA,EAAQ,gBAAA;AAAA,QACR,SAAA,EAAW,EAAA;AAAA,UACT,mIAAA;AAAA,UACA;AAAA,SACF;AAAA,QAEC,QAAA,EAAA;AAAA,UAAA,UAAA,mBACC,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,2KAAA,EACb,QAAA,EAAA;AAAA,4BAAA,IAAA,CAAC,MAAA,EAAA,EAAK,WAAU,yBAAA,EACd,QAAA,EAAA;AAAA,8BAAA,GAAA,CAAC,KAAA,EAAA,EAAM,SAAA,EAAU,gCAAA,EAAiC,aAAA,EAAW,IAAA,EAAC,CAAA;AAAA,cAC7D,YAAA,CAAa;AAAA,aAAA,EAChB,CAAA;AAAA,4BACA,IAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,yBAAA,EACd,QAAA,EAAA;AAAA,8BAAA,IAAA,CAAC,MAAA,EAAA,EACC,QAAA,EAAA;AAAA,gCAAA,IAAA,CAAC,MAAA,EAAA,EAAK,WAAU,0BAAA,EAA2B,QAAA,EAAA;AAAA,kBAAA,GAAA;AAAA,kBAAE,IAAA,CAAK;AAAA,iBAAA,EAAM,CAAA;AAAA,gBAAQ,GAAA;AAAA,gCAChE,IAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,yBAAA,EAA0B,QAAA,EAAA;AAAA,kBAAA,QAAA;AAAA,kBAAE,IAAA,CAAK;AAAA,iBAAA,EAAQ;AAAA,eAAA,EAC3D,CAAA;AAAA,cACC,WAAW,YAAA,CAAa,MAAA,GAAS,oBAChC,IAAA,CAAC,MAAA,EAAA,EAAK,WAAU,2BAAA,EACd,QAAA,EAAA;AAAA,gCAAA,GAAA;AAAA,kBAAC,QAAA;AAAA,kBAAA;AAAA,oBACC,IAAA,EAAK,QAAA;AAAA,oBACL,cAAY,YAAA,CAAa,UAAA;AAAA,oBACzB,OAAO,YAAA,CAAa,UAAA;AAAA,oBACpB,UAAU,WAAA,KAAgB,CAAA;AAAA,oBAC1B,OAAA,EAAS,MAAM,cAAA,CAAe,CAAC,KAAA,KAAU,KAAK,GAAA,CAAI,CAAA,EAAG,KAAA,GAAQ,CAAC,CAAC,CAAA;AAAA,oBAC/D,SAAA,EAAU,yFAAA;AAAA,oBAEV,QAAA,kBAAA,GAAA,CAAC,SAAA,EAAA,EAAU,SAAA,EAAU,UAAA,EAAW,eAAW,IAAA,EAAC;AAAA;AAAA,iBAC9C;AAAA,gCACA,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,cAAA,EACb,QAAA,EAAA,YAAA,CAAa,eAAe,WAAA,GAAc,CAAA,EAAG,YAAA,CAAa,MAAM,CAAA,EACnE,CAAA;AAAA,gCACA,GAAA;AAAA,kBAAC,QAAA;AAAA,kBAAA;AAAA,oBACC,IAAA,EAAK,QAAA;AAAA,oBACL,cAAY,YAAA,CAAa,UAAA;AAAA,oBACzB,OAAO,YAAA,CAAa,UAAA;AAAA,oBACpB,QAAA,EAAU,WAAA,IAAe,YAAA,CAAa,MAAA,GAAS,CAAA;AAAA,oBAC/C,OAAA,EAAS,MACP,cAAA,CAAe,CAAC,KAAA,KAAU,IAAA,CAAK,GAAA,CAAI,YAAA,CAAa,MAAA,GAAS,CAAA,EAAG,KAAA,GAAQ,CAAC,CAAC,CAAA;AAAA,oBAExE,SAAA,EAAU,yFAAA;AAAA,oBAEV,QAAA,kBAAA,GAAA,CAAC,WAAA,EAAA,EAAY,SAAA,EAAU,UAAA,EAAW,eAAW,IAAA,EAAC;AAAA;AAAA;AAChD,eAAA,EACF,CAAA,GACE;AAAA,aAAA,EACN,CAAA;AAAA,4BACA,IAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,qCAAA,EACb,QAAA,EAAA;AAAA,cAAA,YAAA,CAAa,SAAA;AAAA,8BACd,GAAA,CAAC,IAAA,EAAA,EAAK,SAAA,EAAU,iCAAA,EAAkC,eAAW,IAAA,EAAC;AAAA,aAAA,EAChE;AAAA,WAAA,EACF,CAAA,GACE,IAAA;AAAA,0BACJ,GAAA,CAAC,SAAI,GAAA,EAAK,SAAA,EAAW,WAAW,EAAA,CAAG,gCAAA,EAAkC,aAAa,CAAA,EAChF,QAAA,kBAAA,GAAA;AAAA,YAAC,KAAA;AAAA,YAAA;AAAA,cACC,KAAA,EAAO;AAAA,gBACL,MAAA,EAAQ,YAAY,YAAA,EAAa;AAAA,gBACjC,QAAA,EAAU,UAAA;AAAA,gBACV,KAAA,EAAO;AAAA,eACT;AAAA,cAEC,QAAA,EAAA,WAAA,CAAY,eAAA,EAAgB,CAAE,GAAA,CAAI,CAAC,WAAA,qBAClC,GAAA;AAAA,gBAAC,KAAA;AAAA,gBAAA;AAAA,kBAEC,cAAY,WAAA,CAAY,KAAA;AAAA,kBACxB,KAAK,WAAA,CAAY,cAAA;AAAA,kBACjB,KAAA,EAAO;AAAA,oBACL,QAAA,EAAU,UAAA;AAAA,oBACV,GAAA,EAAK,CAAA;AAAA,oBACL,IAAA,EAAM,CAAA;AAAA,oBACN,KAAA,EAAO,MAAA;AAAA,oBACP,SAAA,EAAW,CAAA,WAAA,EAAc,WAAA,CAAY,KAAK,CAAA,GAAA;AAAA,mBAC5C;AAAA,kBAEE,QAAA,EAAA,CAAA,MAAM;AACN,oBAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,WAAA,CAAY,KAAK,CAAA;AACxC,oBAAA,OAAO,UAAU,MAAA,GAAY,IAAA,GAAO,SAAA,CAAU,KAAA,EAAO,YAAY,KAAK,CAAA;AAAA,kBACxE,CAAA;AAAG,iBAAA;AAAA,gBAdE,WAAA,CAAY;AAAA,eAgBpB;AAAA;AAAA,WACH,EACF;AAAA;AAAA;AAAA,KACF;AAAA,EAEJ;AACF","file":"chunk-2PR6POP6.js","sourcesContent":["export interface DiffSegment {\n text: string\n changed: boolean\n}\n\nexport interface DiffCell {\n kind: 'add' | 'del' | 'context'\n text: string\n no?: number\n segments?: DiffSegment[]\n}\n\nexport type DiffRow =\n | { kind: 'pair'; left: DiffCell | null; right: DiffCell | null }\n | { kind: 'fold'; count: number; hidden: DiffRow[] }\n\nexport interface LineDiffOptions {\n contextLines?: number\n}\n\nexport interface LineDiffResult {\n rows: DiffRow[]\n added: number\n removed: number\n}\n\nconst MAX_LCS_CELLS = 4_000_000\nconst MAX_WORD_CELLS = 40_000\n\ntype Op = { type: 'equal' | 'del' | 'add'; text: string }\n\nfunction at<T>(list: readonly T[], index: number): T {\n const value = list[index]\n if (value === undefined) {\n throw new Error(`lineDiff: index ${index} out of bounds`)\n }\n return value\n}\n\nfunction atNum(list: Int32Array, index: number): number {\n const value = list[index]\n if (value === undefined) {\n throw new Error(`lineDiff: index ${index} out of bounds`)\n }\n return value\n}\n\nfunction splitLines(text: string): string[] {\n if (text === '') {\n return []\n }\n return text.replace(/\\r\\n?/g, '\\n').split('\\n')\n}\n\nfunction diffOps(a: string[], b: string[], maxCells = MAX_LCS_CELLS): Op[] {\n const n = a.length\n const m = b.length\n const ops: Op[] = []\n if (n * m > maxCells) {\n for (const text of a) {\n ops.push({ type: 'del', text })\n }\n for (const text of b) {\n ops.push({ type: 'add', text })\n }\n return ops\n }\n const width = m + 1\n const lcs = new Int32Array((n + 1) * width)\n for (let i = n - 1; i >= 0; i -= 1) {\n for (let j = m - 1; j >= 0; j -= 1) {\n lcs[i * width + j] =\n at(a, i) === at(b, j)\n ? atNum(lcs, (i + 1) * width + j + 1) + 1\n : Math.max(atNum(lcs, (i + 1) * width + j), atNum(lcs, i * width + j + 1))\n }\n }\n let i = 0\n let j = 0\n while (i < n && j < m) {\n if (at(a, i) === at(b, j)) {\n ops.push({ type: 'equal', text: at(a, i) })\n i += 1\n j += 1\n } else if (atNum(lcs, (i + 1) * width + j) >= atNum(lcs, i * width + j + 1)) {\n ops.push({ type: 'del', text: at(a, i) })\n i += 1\n } else {\n ops.push({ type: 'add', text: at(b, j) })\n j += 1\n }\n }\n while (i < n) {\n ops.push({ type: 'del', text: at(a, i) })\n i += 1\n }\n while (j < m) {\n ops.push({ type: 'add', text: at(b, j) })\n j += 1\n }\n return ops\n}\n\nfunction tokenize(text: string): string[] {\n return text.match(/\\S+|\\s+/g) ?? []\n}\n\nfunction isMeaningful(token: string): boolean {\n return /\\S/.test(token)\n}\n\nfunction mergeSegments(segments: DiffSegment[]): DiffSegment[] {\n const merged: DiffSegment[] = []\n for (const segment of segments) {\n const last = merged[merged.length - 1]\n if (last !== undefined && last.changed === segment.changed) {\n last.text += segment.text\n } else {\n merged.push({ ...segment })\n }\n }\n return merged\n}\n\nexport function wordSegments(\n original: string,\n suggested: string,\n): { left: DiffSegment[]; right: DiffSegment[] } {\n const a = tokenize(original)\n const b = tokenize(suggested)\n const ops = diffOps(a, b, MAX_WORD_CELLS)\n const left: DiffSegment[] = []\n const right: DiffSegment[] = []\n for (const op of ops) {\n if (op.type === 'equal') {\n left.push({ text: op.text, changed: false })\n right.push({ text: op.text, changed: false })\n } else if (op.type === 'del') {\n left.push({ text: op.text, changed: isMeaningful(op.text) })\n } else {\n right.push({ text: op.text, changed: isMeaningful(op.text) })\n }\n }\n return { left: mergeSegments(left), right: mergeSegments(right) }\n}\n\nfunction pairRows(ops: Op[]): DiffRow[] {\n const rows: DiffRow[] = []\n let index = 0\n while (index < ops.length) {\n const op = at(ops, index)\n if (op.type === 'equal') {\n rows.push({\n kind: 'pair',\n left: { kind: 'context', text: op.text },\n right: { kind: 'context', text: op.text },\n })\n index += 1\n continue\n }\n const dels: string[] = []\n const adds: string[] = []\n while (index < ops.length && at(ops, index).type !== 'equal') {\n const current = at(ops, index)\n if (current.type === 'del') {\n dels.push(current.text)\n } else {\n adds.push(current.text)\n }\n index += 1\n }\n const pairCount = Math.max(dels.length, adds.length)\n for (let k = 0; k < pairCount; k += 1) {\n const leftText = k < dels.length ? at(dels, k) : null\n const rightText = k < adds.length ? at(adds, k) : null\n const leftCell: DiffCell | null =\n leftText !== null ? { kind: 'del', text: leftText } : null\n const rightCell: DiffCell | null =\n rightText !== null ? { kind: 'add', text: rightText } : null\n if (\n leftCell !== null &&\n rightCell !== null &&\n leftText !== null &&\n rightText !== null &&\n leftText !== rightText\n ) {\n const words = wordSegments(leftText, rightText)\n leftCell.segments = words.left\n rightCell.segments = words.right\n }\n rows.push({ kind: 'pair', left: leftCell, right: rightCell })\n }\n }\n return rows\n}\n\nfunction numberRows(rows: DiffRow[]): void {\n let leftNo = 0\n let rightNo = 0\n for (const row of rows) {\n if (row.kind !== 'pair') {\n continue\n }\n if (row.left !== null) {\n leftNo += 1\n row.left.no = leftNo\n }\n if (row.right !== null) {\n rightNo += 1\n row.right.no = rightNo\n }\n }\n}\n\nfunction foldRows(rows: DiffRow[], contextLines: number): DiffRow[] {\n const hasChange = rows.some((row) => {\n if (row.kind !== 'pair') {\n return false\n }\n return row.left?.kind !== 'context' || row.right?.kind !== 'context'\n })\n if (!hasChange || contextLines < 0) {\n return rows\n }\n const runs: { start: number; end: number }[] = []\n let start = -1\n for (let index = 0; index <= rows.length; index += 1) {\n const row = rows[index]\n const isContext =\n index < rows.length &&\n row !== undefined &&\n row.kind === 'pair' &&\n row.left?.kind === 'context' &&\n row.right?.kind === 'context'\n if (isContext) {\n if (start === -1) {\n start = index\n }\n } else if (start !== -1) {\n runs.push({ start, end: index })\n start = -1\n }\n }\n const hiddenAt = new Map<number, DiffRow[]>()\n for (const run of runs) {\n const length = run.end - run.start\n const isFirstRun = run.start === 0\n const isLastRun = run.end === rows.length\n const keepBefore = isFirstRun ? 0 : contextLines\n const keepAfter = isLastRun ? 0 : contextLines\n const foldCount = length - keepBefore - keepAfter\n if (foldCount <= 0) {\n continue\n }\n const hidden = rows.slice(run.start + keepBefore, run.start + keepBefore + foldCount)\n hiddenAt.set(run.start + keepBefore, hidden)\n }\n const folded: DiffRow[] = []\n let index = 0\n while (index < rows.length) {\n const hidden = hiddenAt.get(index)\n if (hidden === undefined) {\n folded.push(at(rows, index))\n index += 1\n } else {\n folded.push({ kind: 'fold', count: hidden.length, hidden })\n index += hidden.length\n }\n }\n return folded\n}\n\nexport function computeLineDiff(\n original: string,\n suggested: string,\n options: LineDiffOptions = {},\n): LineDiffResult {\n const contextLines = options.contextLines ?? 2\n const ops = diffOps(splitLines(original), splitLines(suggested))\n const flatRows = pairRows(ops)\n numberRows(flatRows)\n const rows = foldRows(flatRows, contextLines)\n let added = 0\n let removed = 0\n for (const row of flatRows) {\n if (row.kind !== 'pair') {\n continue\n }\n if (row.right?.kind === 'add') {\n added += 1\n }\n if (row.left?.kind === 'del') {\n removed += 1\n }\n }\n return { rows, added, removed }\n}\n","import * as React from 'react'\nimport { useEffect, useMemo, useState } from 'react'\nimport { useVirtualizer } from '@tanstack/react-virtual'\nimport {\n ChevronDown,\n ChevronRight,\n ChevronUp,\n Minus,\n Plus,\n} from 'lucide-react'\n\nimport { cn } from '../../lib/utils'\n\nimport { computeLineDiff, type DiffCell, type DiffRow } from './lineDiff'\n\nexport interface TextDiffViewLabels {\n original?: string\n suggested?: string\n /** Fold summary for a run of hidden unchanged lines. */\n unchangedLines?: (count: number) => string\n showLess?: string\n prevChange?: string\n nextChange?: string\n changePosition?: (index: number, total: number) => string\n}\n\nconst DEFAULT_LABELS: Required<TextDiffViewLabels> = {\n original: 'Original',\n suggested: 'Suggested',\n unchangedLines: (count) =>\n count === 1 ? '1 unchanged line' : `${count} unchanged lines`,\n showLess: 'Show less',\n prevChange: 'Previous change',\n nextChange: 'Next change',\n changePosition: (index, total) => `${index}/${total}`,\n}\n\nexport interface TextDiffViewProps {\n original: string\n suggested: string\n /** Unchanged context lines kept visible around each changed block. Default 2. */\n contextLines?: number\n showHeader?: boolean\n showNav?: boolean\n labels?: Partial<TextDiffViewLabels>\n /** Applied to the outer box. */\n className?: string\n /** Applied to the scrolling body — size the view here (e.g. `max-h-64`). */\n bodyClassName?: string\n}\n\nfunction isChangedRow(row: DiffRow): boolean {\n return (\n row.kind === 'pair' &&\n (row.left?.kind === 'del' || row.right?.kind === 'add')\n )\n}\n\ninterface FlatRow {\n key: string\n row: DiffRow\n foldOf?: number\n collapseOf?: number\n}\n\nfunction CellContent({ cell }: { cell: DiffCell }) {\n if (cell.segments === undefined) {\n return <span className=\"whitespace-pre-wrap break-words\">{cell.text}</span>\n }\n return (\n <span className=\"whitespace-pre-wrap break-words\">\n {cell.segments.map((segment, index) =>\n segment.changed ? (\n <mark\n key={index}\n className={cn(\n 'rounded-[2px] text-inherit',\n cell.kind === 'add' ? 'bg-[var(--as-success)]/30' : 'bg-[var(--as-danger)]/30',\n )}\n >\n {segment.text}\n </mark>\n ) : (\n <span key={index}>{segment.text}</span>\n ),\n )}\n </span>\n )\n}\n\nexport const TextDiffView = React.forwardRef<HTMLDivElement, TextDiffViewProps>(\n function TextDiffView(\n {\n original,\n suggested,\n contextLines = 2,\n showHeader = true,\n showNav = true,\n labels,\n className,\n bodyClassName,\n },\n ref,\n ) {\n const mergedLabels = { ...DEFAULT_LABELS, ...labels }\n const [expanded, setExpanded] = useState<Set<number>>(new Set())\n const [activeGroup, setActiveGroup] = useState(0)\n const scrollRef = React.useRef<HTMLDivElement | null>(null)\n const diff = useMemo(\n () => computeLineDiff(original, suggested, { contextLines }),\n [original, suggested, contextLines],\n )\n\n const flatRows = useMemo<FlatRow[]>(() => {\n const out: FlatRow[] = []\n diff.rows.forEach((row, index) => {\n if (row.kind === 'fold' && expanded.has(index)) {\n row.hidden.forEach((hiddenRow, hiddenIndex) => {\n out.push({ key: `${index}.${hiddenIndex}`, row: hiddenRow })\n })\n out.push({ key: `${index}.collapse`, row, collapseOf: index })\n } else {\n out.push({\n key: String(index),\n row,\n foldOf: row.kind === 'fold' ? index : undefined,\n })\n }\n })\n return out\n }, [diff.rows, expanded])\n\n const changeGroups = useMemo<number[]>(() => {\n const groups: number[] = []\n let inGroup = false\n flatRows.forEach((entry, index) => {\n const changed = isChangedRow(entry.row)\n if (changed && !inGroup) {\n groups.push(index)\n }\n inGroup = changed\n })\n return groups\n }, [flatRows])\n\n const virtualizer = useVirtualizer({\n count: flatRows.length,\n getScrollElement: () => scrollRef.current,\n estimateSize: () => 22,\n overscan: 12,\n getItemKey: (index) => flatRows[index]?.key ?? String(index),\n })\n\n useEffect(() => {\n setExpanded(new Set())\n setActiveGroup(0)\n }, [original, suggested])\n\n useEffect(() => {\n if (activeGroup >= changeGroups.length) {\n setActiveGroup(0)\n }\n }, [activeGroup, changeGroups.length])\n\n useEffect(() => {\n const target = changeGroups[activeGroup]\n if (target !== undefined) {\n virtualizer.scrollToIndex(target, { align: 'center' })\n }\n }, [activeGroup, changeGroups, virtualizer])\n\n if (diff.added === 0 && diff.removed === 0) {\n return (\n <p\n ref={ref}\n className={cn(\n 'text-[var(--as-muted-fg)] border-[var(--as-border)] bg-[var(--as-subtle)] rounded-md border p-3 text-xs',\n className,\n )}\n >\n {'No changes'}\n </p>\n )\n }\n\n const activeGroupStart = changeGroups[activeGroup]\n const activeGroupEnd =\n activeGroupStart === undefined\n ? undefined\n : (() => {\n for (let index = activeGroupStart + 1; index < flatRows.length; index += 1) {\n const entry = flatRows[index]\n if (entry !== undefined && isChangedRow(entry.row)) {\n return index\n }\n }\n return flatRows.length\n })()\n\n const renderRow = (entry: FlatRow, index: number) => {\n const row = entry.row\n if (row.kind === 'fold') {\n if (entry.collapseOf !== undefined) {\n const collapseOf = entry.collapseOf\n return (\n <button\n key={entry.key}\n type=\"button\"\n onClick={() =>\n setExpanded((current) => {\n const next = new Set(current)\n next.delete(collapseOf)\n return next\n })\n }\n className=\"text-[var(--as-muted-fg)] hover:bg-[var(--as-subtle)] hover:text-[var(--as-fg)] flex w-full items-center gap-1 px-3 py-0.5 text-left text-[11px]\"\n >\n <ChevronDown className=\"size-3\" aria-hidden />\n {mergedLabels.showLess}\n </button>\n )\n }\n const foldOf = entry.foldOf\n return (\n <button\n key={entry.key}\n type=\"button\"\n onClick={() => {\n if (foldOf !== undefined) {\n setExpanded((current) => {\n const next = new Set(current)\n next.add(foldOf)\n return next\n })\n }\n }}\n className=\"text-[var(--as-muted-fg)] hover:bg-[var(--as-subtle)] hover:text-[var(--as-fg)] flex w-full items-center gap-1 px-3 py-0.5 text-left text-[11px]\"\n >\n <ChevronRight className=\"size-3\" aria-hidden />\n {mergedLabels.unchangedLines(row.count)}\n </button>\n )\n }\n const changed = isChangedRow(row)\n const active =\n activeGroupStart !== undefined &&\n activeGroupEnd !== undefined &&\n index >= activeGroupStart &&\n index < activeGroupEnd\n return (\n <div\n key={entry.key}\n className={cn('grid grid-cols-2', active && 'bg-[var(--as-primary)]/5')}\n data-changed={changed || undefined}\n data-active={active || undefined}\n >\n {(['left', 'right'] as const).map((side) => {\n const cell = row[side]\n const isAdd = cell?.kind === 'add'\n const isDel = cell?.kind === 'del'\n return (\n <pre\n key={side}\n className={cn(\n 'flex min-w-0 gap-1.5 px-2 py-0.5',\n isAdd && 'bg-[var(--as-success)]/10 text-[var(--as-success)]',\n isDel && 'bg-[var(--as-danger)]/10 text-[var(--as-danger)]',\n )}\n >\n <span className=\"w-7 shrink-0 select-none text-right text-[var(--as-muted-fg)] tabular-nums opacity-70\">\n {cell?.no ?? ''}\n </span>\n <span className=\"w-2 shrink-0 select-none text-center\" aria-hidden>\n {isAdd ? '+' : isDel ? '-' : ''}\n </span>\n <span className=\"min-w-0 flex-1\">\n {cell === null ? null : <CellContent cell={cell} />}\n </span>\n </pre>\n )\n })}\n </div>\n )\n }\n\n return (\n <div\n ref={ref}\n data-as=\"text-diff-view\"\n className={cn(\n 'bg-[var(--as-subtle)] border-[var(--as-border)] flex flex-col overflow-hidden rounded-md border font-mono text-xs leading-relaxed',\n className,\n )}\n >\n {showHeader ? (\n <div className=\"border-[var(--as-border)] text-[var(--as-muted-fg)] grid grid-cols-[1fr_auto_1fr] items-center gap-2 border-b px-3 py-1.5 text-[11px] font-medium tracking-wide uppercase\">\n <span className=\"flex items-center gap-1\">\n <Minus className=\"size-3 text-[var(--as-danger)]\" aria-hidden />\n {mergedLabels.original}\n </span>\n <span className=\"flex items-center gap-2\">\n <span>\n <span className=\"text-[var(--as-success)]\">+{diff.added}</span>{' '}\n <span className=\"text-[var(--as-danger)]\">−{diff.removed}</span>\n </span>\n {showNav && changeGroups.length > 0 ? (\n <span className=\"flex items-center gap-0.5\">\n <button\n type=\"button\"\n aria-label={mergedLabels.prevChange}\n title={mergedLabels.prevChange}\n disabled={activeGroup === 0}\n onClick={() => setActiveGroup((value) => Math.max(0, value - 1))}\n className=\"hover:bg-[var(--as-border)] hover:text-[var(--as-fg)] rounded p-0.5 disabled:opacity-40\"\n >\n <ChevronUp className=\"size-3.5\" aria-hidden />\n </button>\n <span className=\"tabular-nums\">\n {mergedLabels.changePosition(activeGroup + 1, changeGroups.length)}\n </span>\n <button\n type=\"button\"\n aria-label={mergedLabels.nextChange}\n title={mergedLabels.nextChange}\n disabled={activeGroup >= changeGroups.length - 1}\n onClick={() =>\n setActiveGroup((value) => Math.min(changeGroups.length - 1, value + 1))\n }\n className=\"hover:bg-[var(--as-border)] hover:text-[var(--as-fg)] rounded p-0.5 disabled:opacity-40\"\n >\n <ChevronDown className=\"size-3.5\" aria-hidden />\n </button>\n </span>\n ) : null}\n </span>\n <span className=\"flex items-center justify-end gap-1\">\n {mergedLabels.suggested}\n <Plus className=\"size-3 text-[var(--as-success)]\" aria-hidden />\n </span>\n </div>\n ) : null}\n <div ref={scrollRef} className={cn('min-h-0 flex-1 overflow-y-auto', bodyClassName)}>\n <div\n style={{\n height: virtualizer.getTotalSize(),\n position: 'relative',\n width: '100%',\n }}\n >\n {virtualizer.getVirtualItems().map((virtualItem) => (\n <div\n key={virtualItem.key}\n data-index={virtualItem.index}\n ref={virtualizer.measureElement}\n style={{\n position: 'absolute',\n top: 0,\n left: 0,\n width: '100%',\n transform: `translateY(${virtualItem.start}px)`,\n }}\n >\n {(() => {\n const entry = flatRows[virtualItem.index]\n return entry === undefined ? null : renderRow(entry, virtualItem.index)\n })()}\n </div>\n ))}\n </div>\n </div>\n </div>\n )\n },\n)\n"]}
@@ -0,0 +1,156 @@
1
+ import { useState, useRef, useCallback, useEffect } from 'react';
2
+
3
+ // src/components/ai-text-transform/useAiTextTransform.ts
4
+ function useAiTextTransform(options) {
5
+ const {
6
+ transport,
7
+ pollIntervalMs = 800,
8
+ timeoutMs = 9e4,
9
+ flushMs = 50
10
+ } = options;
11
+ const [status, setStatus] = useState("idle");
12
+ const [jobId, setJobId] = useState(null);
13
+ const [result, setResult] = useState("");
14
+ const [error, setError] = useState(null);
15
+ const transportRef = useRef(transport);
16
+ transportRef.current = transport;
17
+ const unsubscribeRef = useRef(null);
18
+ const bufferRef = useRef("");
19
+ const flushTimerRef = useRef(null);
20
+ const lastFlushRef = useRef(0);
21
+ const terminalRef = useRef(false);
22
+ const cancelFlush = useCallback(() => {
23
+ if (flushTimerRef.current !== null) {
24
+ window.clearTimeout(flushTimerRef.current);
25
+ flushTimerRef.current = null;
26
+ }
27
+ }, []);
28
+ const flush = useCallback(() => {
29
+ cancelFlush();
30
+ lastFlushRef.current = Date.now();
31
+ if (bufferRef.current !== "") {
32
+ const chunk = bufferRef.current;
33
+ bufferRef.current = "";
34
+ setResult((current) => current + chunk);
35
+ }
36
+ }, [cancelFlush]);
37
+ const scheduleFlush = useCallback(() => {
38
+ if (flushTimerRef.current !== null) {
39
+ return;
40
+ }
41
+ const elapsed = Date.now() - lastFlushRef.current;
42
+ const delay = Math.max(0, flushMs - elapsed);
43
+ flushTimerRef.current = window.setTimeout(() => {
44
+ flushTimerRef.current = null;
45
+ flush();
46
+ }, delay);
47
+ }, [flush, flushMs]);
48
+ const detach = useCallback(() => {
49
+ unsubscribeRef.current?.();
50
+ unsubscribeRef.current = null;
51
+ cancelFlush();
52
+ }, [cancelFlush]);
53
+ const start = useCallback(async () => {
54
+ detach();
55
+ bufferRef.current = "";
56
+ lastFlushRef.current = 0;
57
+ terminalRef.current = false;
58
+ setStatus("running");
59
+ setResult("");
60
+ setError(null);
61
+ setJobId(null);
62
+ let jobIdResolved;
63
+ try {
64
+ jobIdResolved = await transportRef.current.start();
65
+ } catch (startError) {
66
+ setError(startError instanceof Error ? startError.message : String(startError));
67
+ setStatus("error");
68
+ return;
69
+ }
70
+ setJobId(jobIdResolved);
71
+ unsubscribeRef.current = transportRef.current.subscribe(jobIdResolved, {
72
+ onDelta: (text) => {
73
+ if (terminalRef.current) {
74
+ return;
75
+ }
76
+ bufferRef.current += text;
77
+ scheduleFlush();
78
+ },
79
+ onDone: (finalResult) => {
80
+ if (terminalRef.current) {
81
+ return;
82
+ }
83
+ terminalRef.current = true;
84
+ bufferRef.current = "";
85
+ flush();
86
+ setResult(finalResult);
87
+ setStatus("done");
88
+ },
89
+ onError: (message) => {
90
+ if (terminalRef.current) {
91
+ return;
92
+ }
93
+ terminalRef.current = true;
94
+ bufferRef.current = "";
95
+ flush();
96
+ setError(message);
97
+ setStatus("error");
98
+ }
99
+ });
100
+ }, [detach, flush, scheduleFlush]);
101
+ const stop = useCallback(async () => {
102
+ const currentJobId = jobId;
103
+ terminalRef.current = true;
104
+ if (currentJobId !== null) {
105
+ detach();
106
+ await transportRef.current.cancel?.(currentJobId).catch(() => void 0);
107
+ }
108
+ setStatus("cancelled");
109
+ }, [detach, jobId]);
110
+ const reset = useCallback(() => {
111
+ terminalRef.current = false;
112
+ detach();
113
+ setJobId(null);
114
+ setResult("");
115
+ setError(null);
116
+ setStatus("idle");
117
+ }, [detach]);
118
+ useEffect(() => {
119
+ if (status !== "running" || jobId === null || transportRef.current.poll === void 0) {
120
+ return;
121
+ }
122
+ const poll = () => {
123
+ transportRef.current.poll(jobId).then((job) => {
124
+ if (job.status === "done") {
125
+ terminalRef.current = true;
126
+ bufferRef.current = "";
127
+ cancelFlush();
128
+ setResult(job.result ?? "");
129
+ setStatus("done");
130
+ } else if (job.status === "error") {
131
+ terminalRef.current = true;
132
+ setError(job.error ?? "AI transform failed");
133
+ setStatus("error");
134
+ } else if (job.status === "cancelled") {
135
+ terminalRef.current = true;
136
+ setStatus("cancelled");
137
+ }
138
+ }).catch(() => void 0);
139
+ };
140
+ const timer = window.setInterval(poll, pollIntervalMs);
141
+ const timeout = window.setTimeout(() => {
142
+ setError("AI transform timed out");
143
+ setStatus("error");
144
+ }, timeoutMs);
145
+ return () => {
146
+ window.clearInterval(timer);
147
+ window.clearTimeout(timeout);
148
+ };
149
+ }, [status, jobId, pollIntervalMs, timeoutMs, cancelFlush]);
150
+ useEffect(() => detach, [detach]);
151
+ return { status, result, error, start, stop, reset };
152
+ }
153
+
154
+ export { useAiTextTransform };
155
+ //# sourceMappingURL=chunk-BKAO7BTU.js.map
156
+ //# sourceMappingURL=chunk-BKAO7BTU.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/ai-text-transform/useAiTextTransform.ts"],"names":[],"mappings":"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","file":"chunk-BKAO7BTU.js","sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react'\n\nexport type AiTextTransformStatus = 'idle' | 'running' | 'done' | 'error' | 'cancelled'\n\nexport interface AiTextTransformEventHandlers {\n onDelta: (text: string) => void\n onDone: (result: string) => void\n onError: (message: string) => void\n}\n\nexport interface AiTextTransformTransport {\n /** Begin the job and resolve with its handle (e.g. a job id). */\n start: () => Promise<string>\n /** Subscribe to a job's events; returns an unsubscribe function. */\n subscribe: (jobId: string, handlers: AiTextTransformEventHandlers) => () => void\n cancel?: (jobId: string) => Promise<void>\n /** Optional status fallback when events may be missed. */\n poll?: (\n jobId: string,\n ) => Promise<{\n status: 'running' | 'done' | 'error' | 'cancelled'\n result?: string\n error?: string\n }>\n}\n\nexport interface UseAiTextTransformOptions {\n transport: AiTextTransformTransport\n /** Status-fallback interval when `poll` is provided. Default 800 ms. */\n pollIntervalMs?: number\n /** Hard timeout for a running job. Default 90 000 ms. */\n timeoutMs?: number\n /** Streaming delta coalescing window. Default 50 ms. */\n flushMs?: number\n}\n\n/**\n * Streaming text-transform state machine (idle → running → done/error/\n * cancelled). Transport-injected: the app provides start/subscribe/cancel/\n * poll closures over its own gateway; this hook owns status transitions,\n * delta coalescing, the poll fallback and the hard timeout.\n */\nexport function useAiTextTransform(options: UseAiTextTransformOptions) {\n const {\n transport,\n pollIntervalMs = 800,\n timeoutMs = 90_000,\n flushMs = 50,\n } = options\n const [status, setStatus] = useState<AiTextTransformStatus>('idle')\n const [jobId, setJobId] = useState<string | null>(null)\n const [result, setResult] = useState('')\n const [error, setError] = useState<string | null>(null)\n\n const transportRef = useRef(transport)\n transportRef.current = transport\n\n const unsubscribeRef = useRef<(() => void) | null>(null)\n const bufferRef = useRef('')\n const flushTimerRef = useRef<number | null>(null)\n const lastFlushRef = useRef(0)\n const terminalRef = useRef(false)\n\n const cancelFlush = useCallback(() => {\n if (flushTimerRef.current !== null) {\n window.clearTimeout(flushTimerRef.current)\n flushTimerRef.current = null\n }\n }, [])\n\n const flush = useCallback(() => {\n cancelFlush()\n lastFlushRef.current = Date.now()\n if (bufferRef.current !== '') {\n const chunk = bufferRef.current\n bufferRef.current = ''\n setResult((current) => current + chunk)\n }\n }, [cancelFlush])\n\n const scheduleFlush = useCallback(() => {\n if (flushTimerRef.current !== null) {\n return\n }\n const elapsed = Date.now() - lastFlushRef.current\n const delay = Math.max(0, flushMs - elapsed)\n flushTimerRef.current = window.setTimeout(() => {\n flushTimerRef.current = null\n flush()\n }, delay)\n }, [flush, flushMs])\n\n const detach = useCallback(() => {\n unsubscribeRef.current?.()\n unsubscribeRef.current = null\n cancelFlush()\n }, [cancelFlush])\n\n const start = useCallback(async () => {\n detach()\n bufferRef.current = ''\n lastFlushRef.current = 0\n terminalRef.current = false\n setStatus('running')\n setResult('')\n setError(null)\n setJobId(null)\n let jobIdResolved: string\n try {\n jobIdResolved = await transportRef.current.start()\n } catch (startError) {\n setError(startError instanceof Error ? startError.message : String(startError))\n setStatus('error')\n return\n }\n setJobId(jobIdResolved)\n unsubscribeRef.current = transportRef.current.subscribe(jobIdResolved, {\n onDelta: (text) => {\n if (terminalRef.current) {\n return\n }\n bufferRef.current += text\n scheduleFlush()\n },\n onDone: (finalResult) => {\n if (terminalRef.current) {\n return\n }\n terminalRef.current = true\n bufferRef.current = ''\n flush()\n setResult(finalResult)\n setStatus('done')\n },\n onError: (message) => {\n if (terminalRef.current) {\n return\n }\n terminalRef.current = true\n bufferRef.current = ''\n flush()\n setError(message)\n setStatus('error')\n },\n })\n }, [detach, flush, scheduleFlush])\n\n const stop = useCallback(async () => {\n const currentJobId = jobId\n terminalRef.current = true\n if (currentJobId !== null) {\n detach()\n await transportRef.current.cancel?.(currentJobId).catch(() => undefined)\n }\n setStatus('cancelled')\n }, [detach, jobId])\n\n const reset = useCallback(() => {\n terminalRef.current = false\n detach()\n setJobId(null)\n setResult('')\n setError(null)\n setStatus('idle')\n }, [detach])\n\n useEffect(() => {\n if (status !== 'running' || jobId === null || transportRef.current.poll === undefined) {\n return\n }\n const poll = () => {\n transportRef.current\n .poll!(jobId)\n .then((job) => {\n if (job.status === 'done') {\n terminalRef.current = true\n bufferRef.current = ''\n cancelFlush()\n setResult(job.result ?? '')\n setStatus('done')\n } else if (job.status === 'error') {\n terminalRef.current = true\n setError(job.error ?? 'AI transform failed')\n setStatus('error')\n } else if (job.status === 'cancelled') {\n terminalRef.current = true\n setStatus('cancelled')\n }\n })\n .catch(() => undefined)\n }\n const timer = window.setInterval(poll, pollIntervalMs)\n const timeout = window.setTimeout(() => {\n setError('AI transform timed out')\n setStatus('error')\n }, timeoutMs)\n return () => {\n window.clearInterval(timer)\n window.clearTimeout(timeout)\n }\n }, [status, jobId, pollIntervalMs, timeoutMs, cancelFlush])\n\n useEffect(() => detach, [detach])\n\n return { status, result, error, start, stop, reset }\n}\n"]}
@@ -0,0 +1,362 @@
1
+ import { cn } from './chunk-BLJWR4ZV.js';
2
+ import * as React from 'react';
3
+ import { useState, useRef, useCallback, useEffect } from 'react';
4
+ import { Mic, X, Square, Loader2 } from 'lucide-react';
5
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
6
+
7
+ var BAR_WEIGHTS = [0.45, 0.62, 0.8, 0.92, 1.05];
8
+ function DictationButton({
9
+ status,
10
+ onStart,
11
+ label = "Dictate",
12
+ recordingLabel,
13
+ className
14
+ }) {
15
+ return /* @__PURE__ */ jsxs(
16
+ "button",
17
+ {
18
+ type: "button",
19
+ title: label,
20
+ "aria-label": label,
21
+ "aria-pressed": status === "recording" ? true : status === "transcribing" ? void 0 : false,
22
+ disabled: status === "transcribing",
23
+ "data-as": "dictation-button",
24
+ className: cn(
25
+ "rounded p-1.5 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--as-focus-ring)]",
26
+ status === "recording" ? "animate-pulse bg-[var(--as-danger)]/10 text-[var(--as-danger)]" : "text-[var(--as-muted-fg)] hover:text-[var(--as-fg)]",
27
+ className
28
+ ),
29
+ onClick: onStart,
30
+ children: [
31
+ /* @__PURE__ */ jsx(Mic, { className: "size-4", "aria-hidden": true }),
32
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: recordingLabel ?? label })
33
+ ]
34
+ }
35
+ );
36
+ }
37
+ function LevelBars({
38
+ levelRef,
39
+ active
40
+ }) {
41
+ const barsRef = React.useRef([]);
42
+ React.useEffect(() => {
43
+ if (!active) {
44
+ return;
45
+ }
46
+ let frame = requestAnimationFrame(function tick() {
47
+ const level = Math.min(1, levelRef.current ?? 0);
48
+ barsRef.current.forEach((bar, index) => {
49
+ if (bar !== null) {
50
+ const weight = BAR_WEIGHTS[index] ?? 1;
51
+ const height = Math.max(0.15, Math.min(1, level * weight));
52
+ bar.style.transform = `scaleY(${height})`;
53
+ }
54
+ });
55
+ frame = requestAnimationFrame(tick);
56
+ });
57
+ return () => cancelAnimationFrame(frame);
58
+ }, [active, levelRef]);
59
+ return /* @__PURE__ */ jsx("span", { className: "flex h-4 items-end gap-0.5", "aria-hidden": true, children: BAR_WEIGHTS.map((_, index) => /* @__PURE__ */ jsx(
60
+ "span",
61
+ {
62
+ ref: (element) => {
63
+ barsRef.current[index] = element;
64
+ },
65
+ className: "h-4 w-1 origin-bottom rounded-full bg-[var(--as-danger)] opacity-40"
66
+ },
67
+ index
68
+ )) });
69
+ }
70
+ var DEFAULT_STRIP_LABELS = {
71
+ recording: "Recording\u2026",
72
+ transcribing: "Transcribing\u2026",
73
+ stop: "Stop",
74
+ cancel: "Cancel",
75
+ dismissError: "Dismiss",
76
+ unsupported: "Speech input is not supported in this browser.",
77
+ denied: "Microphone access was denied.",
78
+ unassigned: "No speech-to-text model is assigned.",
79
+ failed: "Transcription failed. {detail}"
80
+ };
81
+ function DictationStrip({
82
+ status,
83
+ seconds,
84
+ levelRef,
85
+ error,
86
+ labels,
87
+ onStop,
88
+ onCancel,
89
+ onDismissError,
90
+ className
91
+ }) {
92
+ const merged = { ...DEFAULT_STRIP_LABELS, ...labels };
93
+ const formatTime = (total) => {
94
+ const minutes = Math.floor(total / 60);
95
+ const padded = String(total % 60).padStart(2, "0");
96
+ return `${String(minutes).padStart(2, "0")}:${padded}`;
97
+ };
98
+ const errorText = error === null ? "" : error.kind === "unsupported" ? merged.unsupported : error.kind === "denied" ? merged.denied : error.kind === "unassigned" ? merged.unassigned : merged.failed.replace("{detail}", error.detail ?? "");
99
+ if (error !== null) {
100
+ return /* @__PURE__ */ jsxs(
101
+ "div",
102
+ {
103
+ "data-as": "dictation-strip",
104
+ className: cn(
105
+ "flex items-center gap-2 rounded-md border border-dashed border-[var(--as-warning)] px-2.5 py-1.5 text-xs text-[var(--as-warning)]",
106
+ className
107
+ ),
108
+ role: "alert",
109
+ children: [
110
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 break-words", children: errorText }),
111
+ /* @__PURE__ */ jsx(
112
+ "button",
113
+ {
114
+ type: "button",
115
+ "aria-label": merged.dismissError,
116
+ title: merged.dismissError,
117
+ className: "rounded-full p-0.5 hover:opacity-70",
118
+ onClick: onDismissError,
119
+ children: /* @__PURE__ */ jsx(X, { className: "size-3.5", "aria-hidden": true })
120
+ }
121
+ )
122
+ ]
123
+ }
124
+ );
125
+ }
126
+ if (status === "idle") {
127
+ return null;
128
+ }
129
+ return /* @__PURE__ */ jsx(
130
+ "div",
131
+ {
132
+ "data-as": "dictation-strip",
133
+ className: cn(
134
+ "flex items-center gap-2 rounded-md border border-[var(--as-border)] bg-[var(--as-surface)] px-2.5 py-1.5 text-xs",
135
+ className
136
+ ),
137
+ role: "status",
138
+ "aria-label": merged.recording,
139
+ children: status === "recording" ? /* @__PURE__ */ jsxs(Fragment, { children: [
140
+ /* @__PURE__ */ jsx(
141
+ "span",
142
+ {
143
+ className: "size-2 shrink-0 animate-pulse rounded-full bg-[var(--as-danger)]",
144
+ "aria-hidden": true
145
+ }
146
+ ),
147
+ /* @__PURE__ */ jsx("span", { className: "tabular-nums font-medium text-[var(--as-fg)]", children: formatTime(seconds) }),
148
+ /* @__PURE__ */ jsx(LevelBars, { levelRef, active: true }),
149
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate text-[var(--as-muted-fg)]", children: merged.recording }),
150
+ /* @__PURE__ */ jsx(
151
+ "button",
152
+ {
153
+ type: "button",
154
+ "aria-label": merged.cancel,
155
+ title: merged.cancel,
156
+ className: "rounded p-1 text-[var(--as-muted-fg)] hover:text-[var(--as-fg)]",
157
+ onClick: onCancel,
158
+ children: /* @__PURE__ */ jsx(X, { className: "size-3.5", "aria-hidden": true })
159
+ }
160
+ ),
161
+ /* @__PURE__ */ jsxs(
162
+ "button",
163
+ {
164
+ type: "button",
165
+ title: merged.stop,
166
+ "aria-label": merged.stop,
167
+ className: "flex items-center gap-1 rounded bg-[var(--as-danger)] px-2 py-1 font-medium",
168
+ onClick: onStop,
169
+ children: [
170
+ /* @__PURE__ */ jsx(Square, { className: "size-3", "aria-hidden": true }),
171
+ merged.stop
172
+ ]
173
+ }
174
+ )
175
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
176
+ /* @__PURE__ */ jsx(
177
+ Loader2,
178
+ {
179
+ className: "size-3.5 shrink-0 animate-spin text-[var(--as-muted-fg)]",
180
+ "aria-hidden": true
181
+ }
182
+ ),
183
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 text-[var(--as-muted-fg)]", children: merged.transcribing })
184
+ ] })
185
+ }
186
+ );
187
+ }
188
+ var PREFERRED_MIME_TYPES = [
189
+ "audio/webm;codecs=opus",
190
+ "audio/webm",
191
+ "audio/ogg;codecs=opus",
192
+ "audio/mp4"
193
+ ];
194
+ var MAX_LEVEL = 1;
195
+ var LEVEL_BOOST = 4;
196
+ var LEVEL_DECAY = 0.85;
197
+ function pickMimeType() {
198
+ if (typeof MediaRecorder === "undefined") {
199
+ return null;
200
+ }
201
+ for (const mimeType of PREFERRED_MIME_TYPES) {
202
+ if (MediaRecorder.isTypeSupported(mimeType)) {
203
+ return mimeType;
204
+ }
205
+ }
206
+ return null;
207
+ }
208
+ function useDictation(options) {
209
+ const [status, setStatus] = useState("idle");
210
+ const [seconds, setSeconds] = useState(0);
211
+ const [error, setError] = useState(null);
212
+ const optionsRef = useRef(options);
213
+ optionsRef.current = options;
214
+ const recorderRef = useRef(null);
215
+ const streamRef = useRef(null);
216
+ const chunksRef = useRef([]);
217
+ const audioContextRef = useRef(null);
218
+ const rafRef = useRef(null);
219
+ const timerRef = useRef(null);
220
+ const levelRef = useRef(0);
221
+ const teardown = useCallback(() => {
222
+ if (rafRef.current !== null) {
223
+ cancelAnimationFrame(rafRef.current);
224
+ rafRef.current = null;
225
+ }
226
+ if (timerRef.current !== null) {
227
+ window.clearInterval(timerRef.current);
228
+ timerRef.current = null;
229
+ }
230
+ audioContextRef.current?.close().catch(() => void 0);
231
+ audioContextRef.current = null;
232
+ streamRef.current?.getTracks().forEach((track) => track.stop());
233
+ streamRef.current = null;
234
+ recorderRef.current = null;
235
+ levelRef.current = 0;
236
+ }, []);
237
+ const startMeter = useCallback((stream) => {
238
+ if (typeof AudioContext === "undefined") {
239
+ return;
240
+ }
241
+ const context = new AudioContext();
242
+ audioContextRef.current = context;
243
+ const analyser = context.createAnalyser();
244
+ analyser.fftSize = 512;
245
+ context.createMediaStreamSource(stream).connect(analyser);
246
+ const buffer = new Uint8Array(analyser.fftSize);
247
+ const tick = () => {
248
+ analyser.getByteTimeDomainData(buffer);
249
+ let sum = 0;
250
+ for (const value of buffer) {
251
+ const centered = (value - 128) / 128;
252
+ sum += centered * centered;
253
+ }
254
+ const rms = Math.sqrt(sum / buffer.length);
255
+ levelRef.current = Math.min(
256
+ MAX_LEVEL,
257
+ Math.max(rms * LEVEL_BOOST, levelRef.current * LEVEL_DECAY)
258
+ );
259
+ rafRef.current = requestAnimationFrame(tick);
260
+ };
261
+ rafRef.current = requestAnimationFrame(tick);
262
+ }, []);
263
+ const start = useCallback(async () => {
264
+ if (status !== "idle") {
265
+ return;
266
+ }
267
+ setError(null);
268
+ if (typeof navigator === "undefined" || !navigator.mediaDevices?.getUserMedia || typeof MediaRecorder === "undefined") {
269
+ setError({ kind: "unsupported" });
270
+ return;
271
+ }
272
+ let stream;
273
+ try {
274
+ stream = await navigator.mediaDevices.getUserMedia({ audio: true });
275
+ } catch (requestError) {
276
+ const name = requestError instanceof DOMException ? requestError.name : "";
277
+ setError(
278
+ name === "NotAllowedError" || name === "SecurityError" || name === "NotFoundError" ? { kind: "denied" } : {
279
+ kind: "failed",
280
+ detail: requestError instanceof Error ? requestError.message : String(requestError)
281
+ }
282
+ );
283
+ return;
284
+ }
285
+ const mimeType = pickMimeType();
286
+ const recorder = new MediaRecorder(stream, mimeType ? { mimeType } : void 0);
287
+ const chunks = [];
288
+ recorder.ondataavailable = (event) => {
289
+ if (event.data.size > 0) {
290
+ chunks.push(event.data);
291
+ }
292
+ };
293
+ recorderRef.current = recorder;
294
+ streamRef.current = stream;
295
+ chunksRef.current = chunks;
296
+ recorder.start(250);
297
+ setSeconds(0);
298
+ setStatus("recording");
299
+ startMeter(stream);
300
+ timerRef.current = window.setInterval(() => {
301
+ setSeconds((current) => current + 1);
302
+ }, 1e3);
303
+ }, [startMeter, status]);
304
+ const cancel = useCallback(() => {
305
+ const recorder = recorderRef.current;
306
+ if (recorder !== null && recorder.state !== "inactive") {
307
+ recorder.onstop = null;
308
+ recorder.stop();
309
+ }
310
+ teardown();
311
+ setSeconds(0);
312
+ setStatus("idle");
313
+ }, [teardown]);
314
+ const stop = useCallback(async () => {
315
+ const recorder = recorderRef.current;
316
+ if (recorder === null || recorder.state === "inactive") {
317
+ return;
318
+ }
319
+ const mimeType = recorder.mimeType || "audio/webm";
320
+ const chunks = chunksRef.current;
321
+ const stopped = new Promise((resolve) => {
322
+ recorder.onstop = () => resolve();
323
+ });
324
+ recorder.stop();
325
+ await stopped;
326
+ teardown();
327
+ setSeconds(0);
328
+ setStatus("transcribing");
329
+ try {
330
+ const blob = new Blob(chunks, { type: mimeType });
331
+ const result = await optionsRef.current.transcribe(blob);
332
+ setStatus("idle");
333
+ optionsRef.current.onResult?.(result.text);
334
+ } catch (transcribeError) {
335
+ const classified = optionsRef.current.classifyError?.(transcribeError) ?? {
336
+ kind: "failed",
337
+ detail: transcribeError instanceof Error ? transcribeError.message : String(transcribeError)
338
+ };
339
+ setError(classified);
340
+ setStatus("idle");
341
+ }
342
+ }, [teardown]);
343
+ const dismissError = useCallback(() => {
344
+ setError(null);
345
+ }, []);
346
+ useEffect(
347
+ () => () => {
348
+ const recorder = recorderRef.current;
349
+ if (recorder !== null && recorder.state !== "inactive") {
350
+ recorder.onstop = null;
351
+ recorder.stop();
352
+ }
353
+ teardown();
354
+ },
355
+ [teardown]
356
+ );
357
+ return { status, seconds, error, levelRef, start, stop, cancel, dismissError };
358
+ }
359
+
360
+ export { DictationButton, DictationStrip, useDictation };
361
+ //# sourceMappingURL=chunk-KAC2DOLH.js.map
362
+ //# sourceMappingURL=chunk-KAC2DOLH.js.map