ompchamber 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +253 -0
- package/dist/client/apple-touch-icon.png +0 -0
- package/dist/client/icon-192x192.png +0 -0
- package/dist/client/icon-512x512.png +0 -0
- package/dist/client/icon-maskable-512x512.png +0 -0
- package/dist/client/icon.svg +60 -0
- package/dist/client/index.html +41 -0
- package/dist/client/manifest.webmanifest +38 -0
- package/dist/client/static/css/g.f36aa429fa.css +1 -0
- package/dist/client/static/css/index.a0f07455bd.css +2 -0
- package/dist/client/static/css/katex-vendor.ca3a0600e8.css +1 -0
- package/dist/client/static/font/KaTeX_AMS-Regular.1608a09b4a.woff +0 -0
- package/dist/client/static/font/KaTeX_AMS-Regular.4aafdb685c.ttf +0 -0
- package/dist/client/static/font/KaTeX_AMS-Regular.a79f1c3119.woff2 +0 -0
- package/dist/client/static/font/KaTeX_Caligraphic-Bold.b67709187b.woff +0 -0
- package/dist/client/static/font/KaTeX_Caligraphic-Bold.cce5b8ecea.ttf +0 -0
- package/dist/client/static/font/KaTeX_Caligraphic-Bold.ec17d13264.woff2 +0 -0
- package/dist/client/static/font/KaTeX_Caligraphic-Regular.07ef19e7b0.ttf +0 -0
- package/dist/client/static/font/KaTeX_Caligraphic-Regular.55fac25845.woff2 +0 -0
- package/dist/client/static/font/KaTeX_Caligraphic-Regular.dad44a7fc6.woff +0 -0
- package/dist/client/static/font/KaTeX_Fraktur-Bold.9f256b8593.woff +0 -0
- package/dist/client/static/font/KaTeX_Fraktur-Bold.b18f59e1d1.ttf +0 -0
- package/dist/client/static/font/KaTeX_Fraktur-Bold.d42a5579b0.woff2 +0 -0
- package/dist/client/static/font/KaTeX_Fraktur-Regular.7c1871215e.woff +0 -0
- package/dist/client/static/font/KaTeX_Fraktur-Regular.d3c882a649.woff2 +0 -0
- package/dist/client/static/font/KaTeX_Fraktur-Regular.ed38e79f57.ttf +0 -0
- package/dist/client/static/font/KaTeX_Main-Bold.b74a1a8b2c.ttf +0 -0
- package/dist/client/static/font/KaTeX_Main-Bold.c3fb5ac22f.woff2 +0 -0
- package/dist/client/static/font/KaTeX_Main-Bold.d181c4650d.woff +0 -0
- package/dist/client/static/font/KaTeX_Main-BoldItalic.6f2bb1dff2.woff2 +0 -0
- package/dist/client/static/font/KaTeX_Main-BoldItalic.70d8b0a530.ttf +0 -0
- package/dist/client/static/font/KaTeX_Main-BoldItalic.e3f82f9d27.woff +0 -0
- package/dist/client/static/font/KaTeX_Main-Italic.47373d1e51.ttf +0 -0
- package/dist/client/static/font/KaTeX_Main-Italic.8916142bec.woff2 +0 -0
- package/dist/client/static/font/KaTeX_Main-Italic.9024d815ba.woff +0 -0
- package/dist/client/static/font/KaTeX_Main-Regular.0462f03bdf.woff2 +0 -0
- package/dist/client/static/font/KaTeX_Main-Regular.7f51fe0340.woff +0 -0
- package/dist/client/static/font/KaTeX_Main-Regular.b7f8fe9b5f.ttf +0 -0
- package/dist/client/static/font/KaTeX_Math-BoldItalic.572d331f69.woff2 +0 -0
- package/dist/client/static/font/KaTeX_Math-BoldItalic.a879cf8383.ttf +0 -0
- package/dist/client/static/font/KaTeX_Math-BoldItalic.f1035d8d5d.woff +0 -0
- package/dist/client/static/font/KaTeX_Math-Italic.5295ba483a.woff +0 -0
- package/dist/client/static/font/KaTeX_Math-Italic.939bc64440.ttf +0 -0
- package/dist/client/static/font/KaTeX_Math-Italic.f28c23acad.woff2 +0 -0
- package/dist/client/static/font/KaTeX_SansSerif-Bold.8c5b5494b6.woff2 +0 -0
- package/dist/client/static/font/KaTeX_SansSerif-Bold.94e1e8dc5f.ttf +0 -0
- package/dist/client/static/font/KaTeX_SansSerif-Bold.bf59d231c3.woff +0 -0
- package/dist/client/static/font/KaTeX_SansSerif-Italic.3b1e59b3ba.woff2 +0 -0
- package/dist/client/static/font/KaTeX_SansSerif-Italic.7c9bc82b17.woff +0 -0
- package/dist/client/static/font/KaTeX_SansSerif-Italic.b4c20c84d8.ttf +0 -0
- package/dist/client/static/font/KaTeX_SansSerif-Regular.740484788f.woff +0 -0
- package/dist/client/static/font/KaTeX_SansSerif-Regular.ba21ed5f84.woff2 +0 -0
- package/dist/client/static/font/KaTeX_SansSerif-Regular.d4d7ba4804.ttf +0 -0
- package/dist/client/static/font/KaTeX_Script-Regular.03e9641d6f.woff2 +0 -0
- package/dist/client/static/font/KaTeX_Script-Regular.0750571032.woff +0 -0
- package/dist/client/static/font/KaTeX_Script-Regular.fe9cbbe1a0.ttf +0 -0
- package/dist/client/static/font/KaTeX_Size1-Regular.e1e279cbdd.woff +0 -0
- package/dist/client/static/font/KaTeX_Size1-Regular.eae34984b3.woff2 +0 -0
- package/dist/client/static/font/KaTeX_Size1-Regular.fabc004aab.ttf +0 -0
- package/dist/client/static/font/KaTeX_Size2-Regular.577270225e.woff +0 -0
- package/dist/client/static/font/KaTeX_Size2-Regular.5916a24fa3.woff2 +0 -0
- package/dist/client/static/font/KaTeX_Size2-Regular.d6b476ecd3.ttf +0 -0
- package/dist/client/static/font/KaTeX_Size3-Regular.9acaf01c64.woff +0 -0
- package/dist/client/static/font/KaTeX_Size3-Regular.a144ef5840.ttf +0 -0
- package/dist/client/static/font/KaTeX_Size4-Regular.10d95fd3a2.woff2 +0 -0
- package/dist/client/static/font/KaTeX_Size4-Regular.7a996c9da2.woff +0 -0
- package/dist/client/static/font/KaTeX_Size4-Regular.fbccdabe0a.ttf +0 -0
- package/dist/client/static/font/KaTeX_Typewriter-Regular.6258592bdc.woff +0 -0
- package/dist/client/static/font/KaTeX_Typewriter-Regular.a8709e3622.woff2 +0 -0
- package/dist/client/static/font/KaTeX_Typewriter-Regular.d97aaf4a1e.ttf +0 -0
- package/dist/client/static/font/fira-code-cyrillic-400-normal.5971438a4a.woff2 +0 -0
- package/dist/client/static/font/fira-code-cyrillic-400-normal.9bb7bfea9c.woff +0 -0
- package/dist/client/static/font/fira-code-cyrillic-500-normal.5486265b18.woff2 +0 -0
- package/dist/client/static/font/fira-code-cyrillic-500-normal.89f92bfb31.woff +0 -0
- package/dist/client/static/font/fira-code-cyrillic-600-normal.2805b497e5.woff +0 -0
- package/dist/client/static/font/fira-code-cyrillic-600-normal.86e0df22a3.woff2 +0 -0
- package/dist/client/static/font/fira-code-cyrillic-700-normal.505a88f22a.woff +0 -0
- package/dist/client/static/font/fira-code-cyrillic-700-normal.76f5e8d2e2.woff2 +0 -0
- package/dist/client/static/font/fira-code-cyrillic-ext-400-normal.3c4b15e57d.woff2 +0 -0
- package/dist/client/static/font/fira-code-cyrillic-ext-400-normal.61323debaa.woff +0 -0
- package/dist/client/static/font/fira-code-cyrillic-ext-500-normal.0f34210f2a.woff2 +0 -0
- package/dist/client/static/font/fira-code-cyrillic-ext-500-normal.2497cfa1aa.woff +0 -0
- package/dist/client/static/font/fira-code-cyrillic-ext-600-normal.40fce94af9.woff2 +0 -0
- package/dist/client/static/font/fira-code-cyrillic-ext-600-normal.6c8774b829.woff +0 -0
- package/dist/client/static/font/fira-code-cyrillic-ext-700-normal.4b742eb865.woff +0 -0
- package/dist/client/static/font/fira-code-cyrillic-ext-700-normal.e75eb4fccc.woff2 +0 -0
- package/dist/client/static/font/fira-code-greek-400-normal.bb900468b6.woff2 +0 -0
- package/dist/client/static/font/fira-code-greek-400-normal.be76e699ba.woff +0 -0
- package/dist/client/static/font/fira-code-greek-500-normal.176c9fb001.woff2 +0 -0
- package/dist/client/static/font/fira-code-greek-500-normal.d2c596136b.woff +0 -0
- package/dist/client/static/font/fira-code-greek-600-normal.490c3deed7.woff +0 -0
- package/dist/client/static/font/fira-code-greek-600-normal.7df14376d9.woff2 +0 -0
- package/dist/client/static/font/fira-code-greek-700-normal.c82b6072fc.woff2 +0 -0
- package/dist/client/static/font/fira-code-greek-700-normal.d5f2b2917b.woff +0 -0
- package/dist/client/static/font/fira-code-greek-ext-400-normal.4849a79781.woff +0 -0
- package/dist/client/static/font/fira-code-greek-ext-400-normal.7f5bfc4538.woff2 +0 -0
- package/dist/client/static/font/fira-code-greek-ext-500-normal.aaccca4075.woff2 +0 -0
- package/dist/client/static/font/fira-code-greek-ext-500-normal.e383181256.woff +0 -0
- package/dist/client/static/font/fira-code-greek-ext-600-normal.78cb4bff8e.woff +0 -0
- package/dist/client/static/font/fira-code-greek-ext-600-normal.d6c93d54f9.woff2 +0 -0
- package/dist/client/static/font/fira-code-greek-ext-700-normal.57ec7c92d9.woff +0 -0
- package/dist/client/static/font/fira-code-greek-ext-700-normal.8fafdae5e8.woff2 +0 -0
- package/dist/client/static/font/fira-code-latin-400-normal.2655b10c55.woff2 +0 -0
- package/dist/client/static/font/fira-code-latin-400-normal.973295532b.woff +0 -0
- package/dist/client/static/font/fira-code-latin-500-normal.7ae2be8fb8.woff +0 -0
- package/dist/client/static/font/fira-code-latin-500-normal.92a991f204.woff2 +0 -0
- package/dist/client/static/font/fira-code-latin-600-normal.1dbbe5bc27.woff +0 -0
- package/dist/client/static/font/fira-code-latin-600-normal.43788eb7f1.woff2 +0 -0
- package/dist/client/static/font/fira-code-latin-700-normal.2667215d33.woff2 +0 -0
- package/dist/client/static/font/fira-code-latin-700-normal.497a70148b.woff +0 -0
- package/dist/client/static/font/fira-code-latin-ext-400-normal.9dfae29aaf.woff +0 -0
- package/dist/client/static/font/fira-code-latin-ext-400-normal.e534ae46e2.woff2 +0 -0
- package/dist/client/static/font/fira-code-latin-ext-500-normal.24c7b781b0.woff +0 -0
- package/dist/client/static/font/fira-code-latin-ext-500-normal.aad44ab072.woff2 +0 -0
- package/dist/client/static/font/fira-code-latin-ext-600-normal.7bed0f2f7e.woff +0 -0
- package/dist/client/static/font/fira-code-latin-ext-600-normal.c509a7c9f1.woff2 +0 -0
- package/dist/client/static/font/fira-code-latin-ext-700-normal.6c66c8b0a9.woff2 +0 -0
- package/dist/client/static/font/fira-code-latin-ext-700-normal.88f64e2822.woff +0 -0
- package/dist/client/static/font/fira-code-symbols2-400-normal.97d3f4b17c.woff +0 -0
- package/dist/client/static/font/fira-code-symbols2-500-normal.b06f1a06e4.woff +0 -0
- package/dist/client/static/font/fira-code-symbols2-600-normal.304b653b93.woff +0 -0
- package/dist/client/static/font/fira-code-symbols2-700-normal.d8ce0ad586.woff +0 -0
- package/dist/client/static/js/async/0.8e59f2eb5b.js +1 -0
- package/dist/client/static/js/async/0k.5852e6b4fa.js +1 -0
- package/dist/client/static/js/async/0w.9ed36d5860.js +1 -0
- package/dist/client/static/js/async/1.f387c12b63.js +1 -0
- package/dist/client/static/js/async/12.d091f91c99.js +1 -0
- package/dist/client/static/js/async/13.8f810a8a6c.js +1 -0
- package/dist/client/static/js/async/19.6fe909d55a.js +160 -0
- package/dist/client/static/js/async/1b.23f1141a38.js +1 -0
- package/dist/client/static/js/async/1k.544adbf77d.js +2 -0
- package/dist/client/static/js/async/1k.544adbf77d.js.LICENSE.txt +6 -0
- package/dist/client/static/js/async/1p.0d5cddda96.js +1 -0
- package/dist/client/static/js/async/2.b589f1733b.js +1 -0
- package/dist/client/static/js/async/2v.96165101de.js +1 -0
- package/dist/client/static/js/async/3.0cacc08423.js +1 -0
- package/dist/client/static/js/async/37.b28b2f61cd.js +1 -0
- package/dist/client/static/js/async/3d.5085fb913f.js +1 -0
- package/dist/client/static/js/async/3j.a2fcea99be.js +2 -0
- package/dist/client/static/js/async/3j.a2fcea99be.js.LICENSE.txt +11 -0
- package/dist/client/static/js/async/3p.bcf32a0983.js +1 -0
- package/dist/client/static/js/async/3r.3a69e98ee0.js +64 -0
- package/dist/client/static/js/async/3u.1228460e2a.js +1 -0
- package/dist/client/static/js/async/3y.22075aa079.js +198 -0
- package/dist/client/static/js/async/3y.22075aa079.js.LICENSE.txt +5 -0
- package/dist/client/static/js/async/4.9442eeb472.js +1 -0
- package/dist/client/static/js/async/4e.678285ca55.js +1 -0
- package/dist/client/static/js/async/4k.33a0c7eeb4.js +1 -0
- package/dist/client/static/js/async/4q.aad20dab25.js +1 -0
- package/dist/client/static/js/async/5.ebaf8b89cc.js +36 -0
- package/dist/client/static/js/async/51.1938cec320.js +2 -0
- package/dist/client/static/js/async/51.1938cec320.js.LICENSE.txt +6 -0
- package/dist/client/static/js/async/5b.d88304bc13.js +1 -0
- package/dist/client/static/js/async/5j.d6407c4248.js +287 -0
- package/dist/client/static/js/async/5o.88316d4460.js +62 -0
- package/dist/client/static/js/async/6.7929428505.js +1 -0
- package/dist/client/static/js/async/66.5dfa29f957.js +93 -0
- package/dist/client/static/js/async/69.a18a10882f.js +1 -0
- package/dist/client/static/js/async/6o.5b1a06a382.js +1 -0
- package/dist/client/static/js/async/7.e4a9288dd0.js +1 -0
- package/dist/client/static/js/async/73.50280ce58d.js +1 -0
- package/dist/client/static/js/async/7e.a1cc9bfd88.js +1 -0
- package/dist/client/static/js/async/7l.7a6a377ecc.js +1 -0
- package/dist/client/static/js/async/8.5067439d8c.js +1 -0
- package/dist/client/static/js/async/8j.ea110663fb.js +1 -0
- package/dist/client/static/js/async/a.bce4542392.js +1 -0
- package/dist/client/static/js/async/aa.65d3852576.js +1 -0
- package/dist/client/static/js/async/ar.9dc8b1992a.js +2 -0
- package/dist/client/static/js/async/ar.9dc8b1992a.js.LICENSE.txt +6 -0
- package/dist/client/static/js/async/az.d656062b0f.js +1 -0
- package/dist/client/static/js/async/b.b4f6f06515.js +1 -0
- package/dist/client/static/js/async/bi.cbfe8eaa8e.js +1 -0
- package/dist/client/static/js/async/bq.586bc738d1.js +1 -0
- package/dist/client/static/js/async/c.cd45b0ac45.js +1 -0
- package/dist/client/static/js/async/c0.0af1e640d3.js +24 -0
- package/dist/client/static/js/async/ca.8a52cfd447.js +1 -0
- package/dist/client/static/js/async/cf.d34fff5d67.js +1 -0
- package/dist/client/static/js/async/ct.38d9da8a5a.js +1 -0
- package/dist/client/static/js/async/cx.ca5feec570.js +226 -0
- package/dist/client/static/js/async/d.a5fc8fe1b3.js +1 -0
- package/dist/client/static/js/async/da.f62c70f6c8.js +1 -0
- package/dist/client/static/js/async/dp.1725d6432c.js +1 -0
- package/dist/client/static/js/async/e.93214d622b.js +79 -0
- package/dist/client/static/js/async/f.ab50467719.js +19 -0
- package/dist/client/static/js/async/f.ab50467719.js.LICENSE.txt +12 -0
- package/dist/client/static/js/async/f8.bbf0dbae70.js +1 -0
- package/dist/client/static/js/async/fw.fb1a08b92d.js +6 -0
- package/dist/client/static/js/async/fw.fb1a08b92d.js.LICENSE.txt +6 -0
- package/dist/client/static/js/async/h.4e790471e4.js +27 -0
- package/dist/client/static/js/async/h1.e8d5aa8e80.js +1 -0
- package/dist/client/static/js/async/h3.216e9798ab.js +148 -0
- package/dist/client/static/js/async/hd.0da931b622.js +1 -0
- package/dist/client/static/js/async/hk.ba7fb04d41.js +1 -0
- package/dist/client/static/js/async/hn.7568bdb58b.js +1 -0
- package/dist/client/static/js/async/ho.475a5e1ae4.js +1 -0
- package/dist/client/static/js/async/hp.e9fe2e395a.js +2 -0
- package/dist/client/static/js/async/hp.e9fe2e395a.js.LICENSE.txt +17 -0
- package/dist/client/static/js/async/hs.6d480d0ded.js +41 -0
- package/dist/client/static/js/async/i.7c148e8440.js +1 -0
- package/dist/client/static/js/async/id.573df20f29.js +1 -0
- package/dist/client/static/js/async/j.ab925882d8.js +1 -0
- package/dist/client/static/js/async/jd.63886a1f09.js +1 -0
- package/dist/client/static/js/async/jg.69a4beade8.js +86 -0
- package/dist/client/static/js/async/jl.874d352278.js +1 -0
- package/dist/client/static/js/async/jll.11313b455a.js +1 -0
- package/dist/client/static/js/async/js.67182759ef.js +1 -0
- package/dist/client/static/js/async/jsc.23b70d6f40.js +1 -0
- package/dist/client/static/js/async/jse.334588ff5d.js +1 -0
- package/dist/client/static/js/async/jz.72eb929106.js +77 -0
- package/dist/client/static/js/async/k.e878dd350f.js +217 -0
- package/dist/client/static/js/async/ka.c1990ecaa3.js +115 -0
- package/dist/client/static/js/async/ku.29c8a59d0c.js +1 -0
- package/dist/client/static/js/async/ky.8dab1dade0.js +1 -0
- package/dist/client/static/js/async/l.102a97fce6.js +104 -0
- package/dist/client/static/js/async/l6.45f3b62e15.js +1 -0
- package/dist/client/static/js/async/l9.949710adaf.js +83 -0
- package/dist/client/static/js/async/l9.949710adaf.js.LICENSE.txt +13 -0
- package/dist/client/static/js/async/m.3fc017a055.js +28 -0
- package/dist/client/static/js/async/m.3fc017a055.js.LICENSE.txt +6 -0
- package/dist/client/static/js/async/me.8ace414f80.js +23 -0
- package/dist/client/static/js/async/mt.0352e976d8.js +1 -0
- package/dist/client/static/js/async/n.a9f1c51701.js +1 -0
- package/dist/client/static/js/async/na.a36cd532d6.js +1 -0
- package/dist/client/static/js/async/nk.6de011832e.js +1 -0
- package/dist/client/static/js/async/o.36353dfb88.js +1 -0
- package/dist/client/static/js/async/oc.9c060c9779.js +8 -0
- package/dist/client/static/js/async/og.ae7acf03ac.js +193 -0
- package/dist/client/static/js/async/p.48ecfcd14e.js +1 -0
- package/dist/client/static/js/async/px.783b6f91f2.js +1 -0
- package/dist/client/static/js/async/q.0b6fb9bf8d.js +21 -0
- package/dist/client/static/js/async/q.0b6fb9bf8d.js.LICENSE.txt +6 -0
- package/dist/client/static/js/async/q5.e683f7c26e.js +286 -0
- package/dist/client/static/js/async/qs.2a9ddb3c72.js +1 -0
- package/dist/client/static/js/async/r.51010ad87c.js +1 -0
- package/dist/client/static/js/async/rd.b77011ab7f.js +2 -0
- package/dist/client/static/js/async/rd.b77011ab7f.js.LICENSE.txt +4 -0
- package/dist/client/static/js/async/rf.cfbde7f744.js +2 -0
- package/dist/client/static/js/async/rf.cfbde7f744.js.LICENSE.txt +6 -0
- package/dist/client/static/js/async/s.c7d521a8ae.js +2 -0
- package/dist/client/static/js/async/s.c7d521a8ae.js.LICENSE.txt +6 -0
- package/dist/client/static/js/async/sy.7345abcd67.js +94 -0
- package/dist/client/static/js/async/t.0dcb01dfde.js +1 -0
- package/dist/client/static/js/async/t9.d44f57d518.js +1 -0
- package/dist/client/static/js/async/ta.973534bbec.js +1 -0
- package/dist/client/static/js/async/ty.3d93cf5f5f.js +1 -0
- package/dist/client/static/js/async/u.0871ac5b22.js +1 -0
- package/dist/client/static/js/async/up.ea990da0ff.js +32 -0
- package/dist/client/static/js/async/uw.8890abbabc.js +1 -0
- package/dist/client/static/js/async/v.5c7a4b087b.js +1 -0
- package/dist/client/static/js/async/vn.e98e2f3b61.js +309 -0
- package/dist/client/static/js/async/vp.9b13bf8610.js +1 -0
- package/dist/client/static/js/async/vu.311f1d202c.js +34 -0
- package/dist/client/static/js/async/w.08ac210f60.js +1 -0
- package/dist/client/static/js/async/wt.ad92393a90.js +1 -0
- package/dist/client/static/js/async/x.563f72ca6b.js +1 -0
- package/dist/client/static/js/async/x0.475516418f.js +1 -0
- package/dist/client/static/js/async/x1.da8687159b.js +90 -0
- package/dist/client/static/js/async/xl.a3c562a58c.js +1 -0
- package/dist/client/static/js/async/xn.afecebbbd9.js +2 -0
- package/dist/client/static/js/async/xn.afecebbbd9.js.LICENSE.txt +12 -0
- package/dist/client/static/js/async/y.1a9ed7a5d8.js +1 -0
- package/dist/client/static/js/async/y6.43c57defe4.js +1 -0
- package/dist/client/static/js/async/yb.8c1342401d.js +1 -0
- package/dist/client/static/js/async/ybq.4491f2f2dc.js +1 -0
- package/dist/client/static/js/async/yg.9bd4e09ecb.js +149 -0
- package/dist/client/static/js/async/yq.917ddd7ba2.js +1 -0
- package/dist/client/static/js/async/ys.00687cf82d.js +38 -0
- package/dist/client/static/js/async/yv.593a3f7d54.js +1 -0
- package/dist/client/static/js/async/z.56f61a4374.js +1 -0
- package/dist/client/static/js/async/zi.5fdb07b86a.js +24 -0
- package/dist/client/static/js/async/zj.654f37e8ff.js +1 -0
- package/dist/client/static/js/async/zn.966d6f1cc6.js +1 -0
- package/dist/client/static/js/async/zo.26213b40c0.js +1 -0
- package/dist/client/static/js/async/zx.e9f4105e00.js +1 -0
- package/dist/client/static/js/g.124fba0826.js +139 -0
- package/dist/client/static/js/g.124fba0826.js.LICENSE.txt +8 -0
- package/dist/client/static/js/index.907fd4670e.js +68 -0
- package/dist/client/static/js/index.907fd4670e.js.LICENSE.txt +4 -0
- package/dist/client/static/js/katex-vendor.95e48cf65a.js +1 -0
- package/dist/client/static/js/markdown-vendor.9da142c67b.js +144 -0
- package/dist/client/static/js/shiki-vendor.cb8452ddcd.js +1 -0
- package/dist/client/sw.js +15 -0
- package/package.json +75 -0
- package/src/cli/lib/args.js +233 -0
- package/src/cli/lib/commands/logs.js +108 -0
- package/src/cli/lib/commands/restart.js +28 -0
- package/src/cli/lib/commands/serve.js +109 -0
- package/src/cli/lib/commands/status.js +63 -0
- package/src/cli/lib/commands/stop.js +63 -0
- package/src/cli/lib/commands/update.js +120 -0
- package/src/cli/lib/output.js +136 -0
- package/src/cli/lib/path-utils.js +48 -0
- package/src/cli/lib/path-utils.test.js +71 -0
- package/src/cli/lib/paths.js +60 -0
- package/src/cli/lib/process-lifecycle.js +110 -0
- package/src/cli/lib/runtime.js +280 -0
- package/src/cli/ompchamber.js +56 -0
- package/src/client/App.tsx +95 -0
- package/src/client/bootstrap.d.ts +12 -0
- package/src/client/components/common/ComposerPicker.tsx +116 -0
- package/src/client/components/common/ComposerTextarea.tsx +131 -0
- package/src/client/components/common/CopyButton.tsx +73 -0
- package/src/client/components/common/FolderPicker.tsx +270 -0
- package/src/client/components/common/MarkdownRenderer.tsx +107 -0
- package/src/client/components/common/Modal.tsx +75 -0
- package/src/client/components/common/PWAInstallButton.tsx +113 -0
- package/src/client/components/common/StatCard.tsx +52 -0
- package/src/client/components/common/StreamStatusDot.tsx +28 -0
- package/src/client/components/common/SubagentStatusIcon.tsx +27 -0
- package/src/client/components/common/Toast.tsx +79 -0
- package/src/client/components/common/ToastStack.tsx +18 -0
- package/src/client/components/common/ViewportSelector.tsx +206 -0
- package/src/client/components/common/code-editor/index.tsx +343 -0
- package/src/client/components/common/code-surface/index.tsx +75 -0
- package/src/client/components/common/file-icon/brand-paths.ts +62 -0
- package/src/client/components/common/file-icon/index.tsx +127 -0
- package/src/client/components/common/lazy-panels.tsx +80 -0
- package/src/client/components/common/session-state-provider/index.tsx +55 -0
- package/src/client/components/common/sort-menu/index.tsx +63 -0
- package/src/client/components/common/sort-menu/options.ts +24 -0
- package/src/client/components/common/viewport.ts +21 -0
- package/src/client/components/common/workspace-options-menu/index.tsx +84 -0
- package/src/client/components/layout/RightActivityBar.tsx +95 -0
- package/src/client/components/layout/desktop-layout/ResizeHandle.tsx +10 -0
- package/src/client/components/layout/desktop-layout/TopNavbar.tsx +94 -0
- package/src/client/components/layout/desktop-layout/WorkspacePanels.tsx +175 -0
- package/src/client/components/layout/desktop-layout/index.tsx +280 -0
- package/src/client/components/layout/desktop-layout/resizer/index.tsx +344 -0
- package/src/client/components/layout/session-sidebar/CategoryItem.tsx +264 -0
- package/src/client/components/layout/session-sidebar/Footer.tsx +28 -0
- package/src/client/components/layout/session-sidebar/Header.tsx +29 -0
- package/src/client/components/layout/session-sidebar/Modals.tsx +209 -0
- package/src/client/components/layout/session-sidebar/SessionItem.tsx +145 -0
- package/src/client/components/layout/session-sidebar/SessionList.tsx +52 -0
- package/src/client/components/layout/session-sidebar/Skeleton.tsx +36 -0
- package/src/client/components/layout/session-sidebar/SubagentList.tsx +152 -0
- package/src/client/components/layout/session-sidebar/Toolbar.tsx +123 -0
- package/src/client/components/layout/session-sidebar/about-modal/SocialLinks.tsx +43 -0
- package/src/client/components/layout/session-sidebar/about-modal/UpdateSection.tsx +172 -0
- package/src/client/components/layout/session-sidebar/about-modal/index.tsx +63 -0
- package/src/client/components/layout/session-sidebar/index.tsx +174 -0
- package/src/client/components/mobile/LayoutWrapper.tsx +221 -0
- package/src/client/components/mobile/MainView.tsx +68 -0
- package/src/client/components/mobile/RightSidebar.tsx +217 -0
- package/src/client/components/mobile/SessionSidebar.tsx +175 -0
- package/src/client/components/mobile/mobile-main-view/Header.tsx +264 -0
- package/src/client/components/mobile/mobile-right-sidebar/FullDiff.tsx +80 -0
- package/src/client/components/mobile/mobile-right-sidebar/FullEditor.tsx +141 -0
- package/src/client/components/mobile/mobile-right-sidebar/Header.tsx +121 -0
- package/src/client/components/mobile/mobile-session-sidebar/Footer.tsx +69 -0
- package/src/client/components/mobile/mobile-session-sidebar/Header.tsx +34 -0
- package/src/client/components/mobile/mobile-session-sidebar/Item.tsx +168 -0
- package/src/client/components/mobile/mobile-session-sidebar/List.tsx +53 -0
- package/src/client/components/mobile/mobile-session-sidebar/SessionRow.tsx +99 -0
- package/src/client/components/mobile/mobile-session-sidebar/Skeleton.tsx +36 -0
- package/src/client/components/mobile/mobile-session-sidebar/Toolbar.tsx +176 -0
- package/src/client/components/settings/LoadingState.tsx +22 -0
- package/src/client/components/settings/Modal.tsx +277 -0
- package/src/client/components/settings/ProjectSelectorDropdown.tsx +142 -0
- package/src/client/components/settings/SettingsSidebarList.tsx +122 -0
- package/src/client/components/settings/Sidebar.tsx +153 -0
- package/src/client/components/settings/categories/AgentSettings.tsx +84 -0
- package/src/client/components/settings/categories/AppearanceSettings.tsx +50 -0
- package/src/client/components/settings/categories/BehaviorSettings.tsx +73 -0
- package/src/client/components/settings/categories/ChatSettings.tsx +24 -0
- package/src/client/components/settings/categories/CommandSettings.tsx +81 -0
- package/src/client/components/settings/categories/McpSettings.tsx +142 -0
- package/src/client/components/settings/categories/NotificationSettings.tsx +97 -0
- package/src/client/components/settings/categories/OmpSettings.tsx +312 -0
- package/src/client/components/settings/categories/OtherSettings.tsx +16 -0
- package/src/client/components/settings/categories/ProjectSettings.tsx +176 -0
- package/src/client/components/settings/categories/ProviderSettings.tsx +146 -0
- package/src/client/components/settings/categories/SkillCatalogSettings.tsx +309 -0
- package/src/client/components/settings/categories/SkillSettings.tsx +69 -0
- package/src/client/components/settings/categories/TokenUsageSettings.tsx +264 -0
- package/src/client/components/settings/categories/UsageSettings.tsx +77 -0
- package/src/client/components/settings/categories/agent-settings/DetailPane.tsx +333 -0
- package/src/client/components/settings/categories/agent-settings/SidebarList.tsx +42 -0
- package/src/client/components/settings/categories/behavior-settings/Editor.tsx +244 -0
- package/src/client/components/settings/categories/chat-settings/FollowUpSection.tsx +120 -0
- package/src/client/components/settings/categories/chat-settings/KeybindingsSection.tsx +107 -0
- package/src/client/components/settings/categories/chat-settings/TransportSection.tsx +101 -0
- package/src/client/components/settings/categories/command-settings/DetailPane.tsx +292 -0
- package/src/client/components/settings/categories/command-settings/SidebarList.tsx +39 -0
- package/src/client/components/settings/categories/mcp-settings/ConnectionTest.tsx +89 -0
- package/src/client/components/settings/categories/mcp-settings/DetailPane.tsx +311 -0
- package/src/client/components/settings/categories/mcp-settings/ImportModal.tsx +161 -0
- package/src/client/components/settings/categories/mcp-settings/SidebarList.tsx +120 -0
- package/src/client/components/settings/categories/omp-settings/ConfigTabs.tsx +243 -0
- package/src/client/components/settings/categories/omp-settings/ExtensionsPanel.tsx +61 -0
- package/src/client/components/settings/categories/omp-settings/RoleEditor.tsx +66 -0
- package/src/client/components/settings/categories/omp-settings/RowEditor.tsx +337 -0
- package/src/client/components/settings/categories/project-settings/AccentPalette.tsx +76 -0
- package/src/client/components/settings/categories/project-settings/DetailsForm.tsx +71 -0
- package/src/client/components/settings/categories/project-settings/DetailsHeader.tsx +38 -0
- package/src/client/components/settings/categories/project-settings/IconGrid.tsx +152 -0
- package/src/client/components/settings/categories/project-settings/ModelDropdown.tsx +95 -0
- package/src/client/components/settings/categories/project-settings/NameInput.tsx +26 -0
- package/src/client/components/settings/categories/project-settings/SidebarList.tsx +100 -0
- package/src/client/components/settings/categories/provider-settings/AddProviderModal.tsx +201 -0
- package/src/client/components/settings/categories/provider-settings/AuthSection.tsx +121 -0
- package/src/client/components/settings/categories/provider-settings/Header.tsx +22 -0
- package/src/client/components/settings/categories/provider-settings/Icons.tsx +35 -0
- package/src/client/components/settings/categories/provider-settings/LoginModal.tsx +224 -0
- package/src/client/components/settings/categories/provider-settings/ModelCapabilitiesModal.tsx +114 -0
- package/src/client/components/settings/categories/provider-settings/ModelConfigModal.tsx +155 -0
- package/src/client/components/settings/categories/provider-settings/ModelsList.tsx +191 -0
- package/src/client/components/settings/categories/provider-settings/ReconnectModal.tsx +163 -0
- package/src/client/components/settings/categories/provider-settings/SidebarList.tsx +133 -0
- package/src/client/components/settings/categories/skill-catalog/AddSourceModal.tsx +133 -0
- package/src/client/components/settings/categories/skill-settings/DetailPane.tsx +210 -0
- package/src/client/components/settings/categories/skill-settings/SidebarList.tsx +164 -0
- package/src/client/components/settings/categories/token-usage-settings/Breakdown.tsx +127 -0
- package/src/client/components/settings/categories/token-usage-settings/Chart.tsx +74 -0
- package/src/client/components/settings/categories/token-usage-settings/MetricsGrid.tsx +44 -0
- package/src/client/components/settings/categories/usage-settings/DeepSeekCard.tsx +66 -0
- package/src/client/components/settings/categories/usage-settings/KenariCard.tsx +68 -0
- package/src/client/components/settings/categories/usage-settings/ProviderCard.tsx +52 -0
- package/src/client/components/settings/categories/usage-settings/ProviderDetail.tsx +39 -0
- package/src/client/components/settings/categories/usage-settings/QuotaSection.tsx +93 -0
- package/src/client/components/settings/categories/usage-settings/SidebarList.tsx +77 -0
- package/src/client/components/settings/categories/usage-settings/UsageTable.tsx +66 -0
- package/src/client/components/settings/categories/usage-settings/format.ts +63 -0
- package/src/client/components/settings/categories/usage-settings/providers.ts +45 -0
- package/src/client/components/workspace/SearchPanel.tsx +259 -0
- package/src/client/components/workspace/browser-panel/ActivityToasts.tsx +46 -0
- package/src/client/components/workspace/browser-panel/AddressBar.tsx +84 -0
- package/src/client/components/workspace/browser-panel/Screencast.tsx +109 -0
- package/src/client/components/workspace/browser-panel/index.tsx +69 -0
- package/src/client/components/workspace/browser-toolbar/ZoomControls.tsx +48 -0
- package/src/client/components/workspace/browser-toolbar/index.tsx +140 -0
- package/src/client/components/workspace/chat-timeline/AiMessageFooter.tsx +250 -0
- package/src/client/components/workspace/chat-timeline/AttachmentChips.tsx +119 -0
- package/src/client/components/workspace/chat-timeline/ComposerDock.tsx +121 -0
- package/src/client/components/workspace/chat-timeline/EmptyWorkspacePrompt.tsx +220 -0
- package/src/client/components/workspace/chat-timeline/GeneratingIndicator.tsx +94 -0
- package/src/client/components/workspace/chat-timeline/MessageItem.tsx +321 -0
- package/src/client/components/workspace/chat-timeline/MessageList.tsx +122 -0
- package/src/client/components/workspace/chat-timeline/MinimapShortcuts.tsx +47 -0
- package/src/client/components/workspace/chat-timeline/NewChatModal.tsx +69 -0
- package/src/client/components/workspace/chat-timeline/QueueList.tsx +94 -0
- package/src/client/components/workspace/chat-timeline/SessionSkeleton.tsx +89 -0
- package/src/client/components/workspace/chat-timeline/SubagentView.tsx +148 -0
- package/src/client/components/workspace/chat-timeline/SystemNotice.tsx +209 -0
- package/src/client/components/workspace/chat-timeline/TaskResultContent.tsx +175 -0
- package/src/client/components/workspace/chat-timeline/ThinkingSection.tsx +130 -0
- package/src/client/components/workspace/chat-timeline/TimelineBody.tsx +130 -0
- package/src/client/components/workspace/chat-timeline/ToolCallCard.tsx +291 -0
- package/src/client/components/workspace/chat-timeline/ToolCallingSection.tsx +96 -0
- package/src/client/components/workspace/chat-timeline/UndoConfirmModal.tsx +83 -0
- package/src/client/components/workspace/chat-timeline/chat-input/AccessDropdown.tsx +53 -0
- package/src/client/components/workspace/chat-timeline/chat-input/AttachmentToolbar.tsx +63 -0
- package/src/client/components/workspace/chat-timeline/chat-input/ThinkingLevelDropdown.tsx +49 -0
- package/src/client/components/workspace/chat-timeline/chat-input/Toolbar.tsx +108 -0
- package/src/client/components/workspace/chat-timeline/chat-input/access-levels.ts +14 -0
- package/src/client/components/workspace/chat-timeline/chat-input/index.tsx +341 -0
- package/src/client/components/workspace/chat-timeline/index.tsx +290 -0
- package/src/client/components/workspace/chat-timeline/tool-renderers/ask-dialog/Footer.tsx +97 -0
- package/src/client/components/workspace/chat-timeline/tool-renderers/ask-dialog/Header.tsx +52 -0
- package/src/client/components/workspace/chat-timeline/tool-renderers/ask-dialog/Lazy.tsx +24 -0
- package/src/client/components/workspace/chat-timeline/tool-renderers/ask-dialog/SelectBody.tsx +110 -0
- package/src/client/components/workspace/chat-timeline/tool-renderers/ask-dialog/index.tsx +321 -0
- package/src/client/components/workspace/chat-timeline/tool-renderers/hashline-patch/index.tsx +92 -0
- package/src/client/components/workspace/chat-timeline/tool-renderers/index.tsx +160 -0
- package/src/client/components/workspace/chat-timeline/tool-renderers/panels/Ask.tsx +205 -0
- package/src/client/components/workspace/chat-timeline/tool-renderers/panels/AstEdit.tsx +202 -0
- package/src/client/components/workspace/chat-timeline/tool-renderers/panels/Bash.tsx +223 -0
- package/src/client/components/workspace/chat-timeline/tool-renderers/panels/Checkpoint.tsx +49 -0
- package/src/client/components/workspace/chat-timeline/tool-renderers/panels/ContextNotes.tsx +66 -0
- package/src/client/components/workspace/chat-timeline/tool-renderers/panels/Debug.tsx +91 -0
- package/src/client/components/workspace/chat-timeline/tool-renderers/panels/Edit.tsx +288 -0
- package/src/client/components/workspace/chat-timeline/tool-renderers/panels/Eval.tsx +202 -0
- package/src/client/components/workspace/chat-timeline/tool-renderers/panels/Github.tsx +91 -0
- package/src/client/components/workspace/chat-timeline/tool-renderers/panels/Goal.tsx +247 -0
- package/src/client/components/workspace/chat-timeline/tool-renderers/panels/Hub.tsx +273 -0
- package/src/client/components/workspace/chat-timeline/tool-renderers/panels/Lsp.tsx +276 -0
- package/src/client/components/workspace/chat-timeline/tool-renderers/panels/ManageSkill.tsx +93 -0
- package/src/client/components/workspace/chat-timeline/tool-renderers/panels/Mcp.tsx +143 -0
- package/src/client/components/workspace/chat-timeline/tool-renderers/panels/Memory.tsx +93 -0
- package/src/client/components/workspace/chat-timeline/tool-renderers/panels/Read.tsx +246 -0
- package/src/client/components/workspace/chat-timeline/tool-renderers/panels/Resolve.tsx +96 -0
- package/src/client/components/workspace/chat-timeline/tool-renderers/panels/SearchFs.tsx +132 -0
- package/src/client/components/workspace/chat-timeline/tool-renderers/panels/SearchTool.tsx +317 -0
- package/src/client/components/workspace/chat-timeline/tool-renderers/panels/SecurityScan.tsx +102 -0
- package/src/client/components/workspace/chat-timeline/tool-renderers/panels/TaskResult.tsx +240 -0
- package/src/client/components/workspace/chat-timeline/tool-renderers/panels/Think.tsx +52 -0
- package/src/client/components/workspace/chat-timeline/tool-renderers/panels/Todo.tsx +141 -0
- package/src/client/components/workspace/chat-timeline/tool-renderers/panels/WebSearch.tsx +118 -0
- package/src/client/components/workspace/chat-timeline/tool-renderers/shared/DiffView.tsx +150 -0
- package/src/client/components/workspace/chat-timeline/tool-renderers/shared/FallbackOutput.tsx +107 -0
- package/src/client/components/workspace/chat-timeline/tool-renderers/shared/JsonCodeBlock.tsx +79 -0
- package/src/client/components/workspace/chat-timeline/tool-renderers/shared/ToolCardShell.tsx +151 -0
- package/src/client/components/workspace/chat-timeline/tool-renderers/shared/read-line-meta.ts +95 -0
- package/src/client/components/workspace/chat-timeline/tool-renderers/shared/tool-input.ts +18 -0
- package/src/client/components/workspace/chat-timeline/tool-renderers/shared/truncate.ts +18 -0
- package/src/client/components/workspace/context-panel/CostBreakdownPopover.tsx +74 -0
- package/src/client/components/workspace/context-panel/LastMessageCard.tsx +34 -0
- package/src/client/components/workspace/context-panel/RawJsonViewer.tsx +94 -0
- package/src/client/components/workspace/context-panel/RawMessagesList.tsx +293 -0
- package/src/client/components/workspace/context-panel/StatsGrid.tsx +64 -0
- package/src/client/components/workspace/context-panel/TokenDistributionBar.tsx +62 -0
- package/src/client/components/workspace/context-panel/WindowCard.tsx +35 -0
- package/src/client/components/workspace/context-panel/index.tsx +142 -0
- package/src/client/components/workspace/context-panel/raw-messages.ts +54 -0
- package/src/client/components/workspace/diff-panel/SplitView.tsx +165 -0
- package/src/client/components/workspace/diff-panel/Toolbar.tsx +177 -0
- package/src/client/components/workspace/diff-panel/UnifiedView.tsx +117 -0
- package/src/client/components/workspace/diff-panel/index.tsx +213 -0
- package/src/client/components/workspace/editor/Tabs.tsx +149 -0
- package/src/client/components/workspace/editor/Toolbar.tsx +90 -0
- package/src/client/components/workspace/editor/index.tsx +189 -0
- package/src/client/components/workspace/file-explorer/GitRepoDropdown.tsx +143 -0
- package/src/client/components/workspace/file-explorer/Modals.tsx +236 -0
- package/src/client/components/workspace/file-explorer/TreeItem.tsx +289 -0
- package/src/client/components/workspace/file-explorer/index.tsx +193 -0
- package/src/client/components/workspace/git-panel/BranchToolbar.tsx +188 -0
- package/src/client/components/workspace/git-panel/ChangesList.tsx +168 -0
- package/src/client/components/workspace/git-panel/CommitBox.tsx +48 -0
- package/src/client/components/workspace/git-panel/FileItem.tsx +91 -0
- package/src/client/components/workspace/git-panel/Modals.tsx +97 -0
- package/src/client/components/workspace/git-panel/RepoHeader.tsx +137 -0
- package/src/client/components/workspace/git-panel/TreeItem.tsx +186 -0
- package/src/client/components/workspace/git-panel/TreeView.tsx +36 -0
- package/src/client/components/workspace/git-panel/commit-modal/CommitActions.tsx +97 -0
- package/src/client/components/workspace/git-panel/commit-modal/CommitDiffViewer.tsx +205 -0
- package/src/client/components/workspace/git-panel/commit-modal/CommitRow.tsx +179 -0
- package/src/client/components/workspace/git-panel/commit-modal/GraphCanvas.tsx +164 -0
- package/src/client/components/workspace/git-panel/commit-modal/Header.tsx +127 -0
- package/src/client/components/workspace/git-panel/commit-modal/index.tsx +269 -0
- package/src/client/components/workspace/git-panel/index.tsx +326 -0
- package/src/client/components/workspace/model-dropdown/Footer.tsx +21 -0
- package/src/client/components/workspace/model-dropdown/Header.tsx +50 -0
- package/src/client/components/workspace/model-dropdown/Item.tsx +137 -0
- package/src/client/components/workspace/model-dropdown/Panel.tsx +146 -0
- package/src/client/components/workspace/model-dropdown/Section.tsx +87 -0
- package/src/client/components/workspace/model-dropdown/Skeleton.tsx +39 -0
- package/src/client/components/workspace/model-dropdown/SpecsTooltip.tsx +91 -0
- package/src/client/components/workspace/model-dropdown/groups.ts +62 -0
- package/src/client/components/workspace/model-dropdown/index.tsx +245 -0
- package/src/client/components/workspace/model-dropdown/use-catalog.ts +111 -0
- package/src/client/components/workspace/terminal-panel/Header.tsx +50 -0
- package/src/client/components/workspace/terminal-panel/InputBar.tsx +82 -0
- package/src/client/components/workspace/terminal-panel/LogEntry.tsx +70 -0
- package/src/client/components/workspace/terminal-panel/QuickActions.tsx +39 -0
- package/src/client/components/workspace/terminal-panel/RealtimeXtermView.tsx +340 -0
- package/src/client/components/workspace/terminal-panel/index.tsx +110 -0
- package/src/client/components/workspace/usage-panel/ProviderSelect.tsx +208 -0
- package/src/client/components/workspace/usage-panel/index.tsx +98 -0
- package/src/client/components/workspace/user-browser-panel/AddressBar.tsx +134 -0
- package/src/client/components/workspace/user-browser-panel/Frame.tsx +72 -0
- package/src/client/components/workspace/user-browser-panel/index.tsx +87 -0
- package/src/client/data/agent-data/builtin.ts +31 -0
- package/src/client/data/agent-data/index.ts +10 -0
- package/src/client/data/agent-data/orchestrator.ts +113 -0
- package/src/client/data/agent-data/specialist.ts +245 -0
- package/src/client/data/context-data/index.test.ts +88 -0
- package/src/client/data/context-data/index.ts +310 -0
- package/src/client/data/context-data/presets.ts +128 -0
- package/src/client/data/mock/chat.ts +236 -0
- package/src/client/data/mock/git-commits.ts +304 -0
- package/src/client/data/mock/subagents.ts +212 -0
- package/src/client/data/mock/token-usage.ts +129 -0
- package/src/client/data/models/catalog.ts +293 -0
- package/src/client/data/samples/dialogue-session.ts +285 -0
- package/src/client/data/samples/sample-subagents/scout-raw.ts +341 -0
- package/src/client/data/samples/sample-subagents/sleeper-raw.ts +294 -0
- package/src/client/data/samples/sample-tools/built-in-part1.ts +265 -0
- package/src/client/data/samples/sample-tools/built-in-part2.ts +180 -0
- package/src/client/data/samples/sample-tools/other.ts +162 -0
- package/src/client/data/samples/subagent-session.ts +99 -0
- package/src/client/data/samples/tools-session.ts +85 -0
- package/src/client/data/samples/virtual-devices-session.ts +333 -0
- package/src/client/data/settings/behavior.ts +12 -0
- package/src/client/data/settings/command.ts +188 -0
- package/src/client/data/settings/mcp.ts +28 -0
- package/src/client/data/settings/omp-schema.json +1 -0
- package/src/client/data/settings/project.ts +58 -0
- package/src/client/data/settings/provider.ts +185 -0
- package/src/client/data/settings/skill.ts +340 -0
- package/src/client/data/theme/terminal.ts +150 -0
- package/src/client/hooks/browser/use-screencast.ts +178 -0
- package/src/client/hooks/browser/use-user-browser.ts +105 -0
- package/src/client/hooks/chat/composer/index.ts +181 -0
- package/src/client/hooks/chat/composer/items.ts +47 -0
- package/src/client/hooks/chat/omp/index.ts +348 -0
- package/src/client/hooks/chat/omp/revalidation-throttle.ts +71 -0
- package/src/client/hooks/chat/omp/session-list.tsx +148 -0
- package/src/client/hooks/chat/omp/session-sidebar-controller.ts +249 -0
- package/src/client/hooks/chat/omp/session-statuses.ts +83 -0
- package/src/client/hooks/chat/omp/status.ts +31 -0
- package/src/client/hooks/chat/omp/stream-poll.ts +37 -0
- package/src/client/hooks/chat/omp/stream.ts +108 -0
- package/src/client/hooks/chat/stream.ts +228 -0
- package/src/client/hooks/chat/subagent/index.ts +290 -0
- package/src/client/hooks/chat/timeline/actions.ts +322 -0
- package/src/client/hooks/chat/timeline/auto-scroll.ts +58 -0
- package/src/client/hooks/chat/timeline/browser-context.ts +40 -0
- package/src/client/hooks/chat/timeline/extension-dialog.ts +56 -0
- package/src/client/hooks/chat/timeline/index.ts +333 -0
- package/src/client/hooks/chat/timeline/queue.ts +87 -0
- package/src/client/hooks/chat/timeline/scroll.ts +134 -0
- package/src/client/hooks/chat/timeline/send.ts +348 -0
- package/src/client/hooks/chat/timeline/session-load.ts +334 -0
- package/src/client/hooks/chat/timeline/session-title.ts +40 -0
- package/src/client/hooks/chat/timeline/subagent-view.ts +92 -0
- package/src/client/hooks/chat/timeline/undo-confirmation.ts +29 -0
- package/src/client/hooks/editor/use-file-editor.ts +302 -0
- package/src/client/hooks/models/use-model-names.ts +17 -0
- package/src/client/hooks/models/use-models-catalog.ts +45 -0
- package/src/client/hooks/models/use-provider-names.ts +18 -0
- package/src/client/hooks/settings/crud-list.ts +187 -0
- package/src/client/hooks/settings/instruction-file.ts +91 -0
- package/src/client/hooks/settings/providers.ts +295 -0
- package/src/client/hooks/settings/skill-catalog.ts +37 -0
- package/src/client/hooks/settings/use-chamber-setting.ts +12 -0
- package/src/client/hooks/settings/useUsageReport.ts +41 -0
- package/src/client/hooks/ui/clipboard.ts +33 -0
- package/src/client/hooks/ui/copy-flag.ts +27 -0
- package/src/client/hooks/ui/inline-rename.ts +93 -0
- package/src/client/hooks/ui/notification-sound.ts +108 -0
- package/src/client/hooks/ui/on-click-outside.ts +22 -0
- package/src/client/hooks/ui/open-file.ts +42 -0
- package/src/client/hooks/ui/scrollbar-fade.ts +33 -0
- package/src/client/hooks/ui/show-more.ts +23 -0
- package/src/client/hooks/ui/syntax-ready.ts +17 -0
- package/src/client/hooks/ui/theme.ts +76 -0
- package/src/client/hooks/ui/toasts.ts +22 -0
- package/src/client/hooks/ui/updates.ts +108 -0
- package/src/client/hooks/ui/visibility-refresh.ts +66 -0
- package/src/client/hooks/ui/window-event.ts +52 -0
- package/src/client/hooks/workspace/commit-interactions.ts +111 -0
- package/src/client/hooks/workspace/commit-pagination.ts +106 -0
- package/src/client/hooks/workspace/file-tabs.ts +136 -0
- package/src/client/hooks/workspace/git-status.ts +89 -0
- package/src/client/hooks/workspace/git-tree.ts +146 -0
- package/src/client/hooks/workspace/panel-refresh.ts +72 -0
- package/src/client/hooks/workspace/panel-widths.ts +59 -0
- package/src/client/hooks/workspace/search-stream.ts +76 -0
- package/src/client/hooks/workspace/session-state/context.ts +15 -0
- package/src/client/hooks/workspace/session-state/index.ts +62 -0
- package/src/client/hooks/workspace/terminal-output.ts +66 -0
- package/src/client/hooks/workspace/terminal.ts +283 -0
- package/src/client/hooks/workspace/workspace-folder-actions.ts +110 -0
- package/src/client/lib/router/fetcher.ts +100 -0
- package/src/client/lib/router/search-params.ts +82 -0
- package/src/client/main.tsx +23 -0
- package/src/client/tailwind.css +364 -0
- package/src/server/db.server.ts +338 -0
- package/src/server/index.ts +19 -0
- package/src/server/lib/browser/runtime.test.ts +110 -0
- package/src/server/lib/browser/runtime.ts +160 -0
- package/src/server/lib/chat/session-store.server.ts +61 -0
- package/src/server/lib/db/client.ts +55 -0
- package/src/server/lib/db/settings-store.ts +148 -0
- package/src/server/lib/fs/atomic-write.ts +27 -0
- package/src/server/lib/fs/git-diff.ts +116 -0
- package/src/server/lib/fs/git-log.ts +174 -0
- package/src/server/lib/fs/repo-scope.ts +14 -0
- package/src/server/lib/fs/root.ts +77 -0
- package/src/server/lib/fs/shell.ts +71 -0
- package/src/server/lib/fs/terminal-cwd.ts +49 -0
- package/src/server/lib/models/provider-registry.server.ts +269 -0
- package/src/server/lib/omp/config/agents.ts +162 -0
- package/src/server/lib/omp/config/behavior.ts +113 -0
- package/src/server/lib/omp/config/config-cli.ts +94 -0
- package/src/server/lib/omp/config/disabled-providers.ts +68 -0
- package/src/server/lib/omp/config/extensions.ts +90 -0
- package/src/server/lib/omp/config/instructions.ts +81 -0
- package/src/server/lib/omp/config/mcp-test.ts +346 -0
- package/src/server/lib/omp/config/mcp.ts +258 -0
- package/src/server/lib/omp/config/providers.ts +276 -0
- package/src/server/lib/omp/config/roles.ts +46 -0
- package/src/server/lib/omp/config/skills-catalog.ts +93 -0
- package/src/server/lib/omp/config/skills.ts +118 -0
- package/src/server/lib/omp/config/yaml.ts +48 -0
- package/src/server/lib/omp/core/auth-credentials.ts +87 -0
- package/src/server/lib/omp/core/cli.ts +69 -0
- package/src/server/lib/omp/core/paths.ts +154 -0
- package/src/server/lib/omp/core/registry.ts +140 -0
- package/src/server/lib/omp/core/worktree.ts +106 -0
- package/src/server/lib/omp/rpc/constants.ts +185 -0
- package/src/server/lib/omp/rpc/errors.ts +27 -0
- package/src/server/lib/omp/rpc/kill-tree.ts +49 -0
- package/src/server/lib/omp/rpc/lines.ts +38 -0
- package/src/server/lib/omp/rpc/manager.ts +310 -0
- package/src/server/lib/omp/rpc/pending-ui-dialogs.ts +55 -0
- package/src/server/lib/omp/rpc/process-helpers.ts +82 -0
- package/src/server/lib/omp/rpc/process.ts +319 -0
- package/src/server/lib/omp/rpc/session-commands.ts +218 -0
- package/src/server/lib/omp/rpc/session-registry.ts +300 -0
- package/src/server/lib/omp/rpc/utility.ts +199 -0
- package/src/server/lib/omp/rpc/web-state.ts +94 -0
- package/src/server/lib/omp/session/files.ts +282 -0
- package/src/server/lib/omp/session/locator.ts +60 -0
- package/src/server/lib/omp/session/messages.ts +222 -0
- package/src/server/lib/omp/session/reader.ts +150 -0
- package/src/server/lib/omp/session/sidebar-data.server.ts +195 -0
- package/src/server/lib/omp/session/stats.ts +85 -0
- package/src/server/lib/omp/session/subagent-presence.ts +74 -0
- package/src/server/lib/omp/session/telemetry/compute.ts +188 -0
- package/src/server/lib/omp/session/telemetry/format.ts +110 -0
- package/src/server/lib/omp/session/telemetry/index.ts +4 -0
- package/src/server/lib/omp/session/telemetry/scan.ts +21 -0
- package/src/server/lib/omp/session/telemetry-raw.ts +96 -0
- package/src/server/lib/omp/session/telemetry.test.ts +154 -0
- package/src/server/lib/omp/session/title-slot.ts +203 -0
- package/src/server/lib/omp/session/usage.ts +298 -0
- package/src/server/lib/omp/subagent/history/fold.ts +196 -0
- package/src/server/lib/omp/subagent/history/index.ts +110 -0
- package/src/server/lib/omp/subagent/history/paths.ts +29 -0
- package/src/server/lib/omp/subagent/history/transcript.test.ts +87 -0
- package/src/server/lib/omp/subagent/history/transcript.ts +122 -0
- package/src/server/lib/remix-compat.ts +29 -0
- package/src/server/lib/route-adapter.ts +144 -0
- package/src/server/lib/sse.ts +248 -0
- package/src/server/lib/updates/apply.ts +46 -0
- package/src/server/lib/updates/check.ts +41 -0
- package/src/server/lib/updates/github.ts +71 -0
- package/src/server/lib/updates/install-method.ts +73 -0
- package/src/server/lib/updates/install.test.ts +74 -0
- package/src/server/lib/updates/install.ts +294 -0
- package/src/server/lib/updates/omp.ts +86 -0
- package/src/server/lib/usage/deepseek.ts +59 -0
- package/src/server/lib/usage/kenari.ts +251 -0
- package/src/server/lib/usage/provider-key.ts +83 -0
- package/src/server/mock.server.ts +33 -0
- package/src/server/plugins/compress.ts +51 -0
- package/src/server/plugins/dev-assets.ts +49 -0
- package/src/server/plugins/ssr.ts +100 -0
- package/src/server/plugins/static.ts +81 -0
- package/src/server/routes/agent/command.ts +81 -0
- package/src/server/routes/agent/events.ts +56 -0
- package/src/server/routes/agent/index.ts +12 -0
- package/src/server/routes/agent/new.ts +83 -0
- package/src/server/routes/agent/prewarm.ts +27 -0
- package/src/server/routes/agent/ws.ts +168 -0
- package/src/server/routes/browser/index.ts +6 -0
- package/src/server/routes/browser/stream.ts +217 -0
- package/src/server/routes/chat/index.ts +12 -0
- package/src/server/routes/chat/rewind.ts +162 -0
- package/src/server/routes/chat/root.ts +78 -0
- package/src/server/routes/chat/session.ts +339 -0
- package/src/server/routes/chat/stream.ts +111 -0
- package/src/server/routes/files/index.ts +10 -0
- package/src/server/routes/files/root.ts +29 -0
- package/src/server/routes/files/toggle.ts +20 -0
- package/src/server/routes/folders/create.ts +98 -0
- package/src/server/routes/folders/folder.ts +78 -0
- package/src/server/routes/folders/index.ts +16 -0
- package/src/server/routes/fs/action.ts +84 -0
- package/src/server/routes/fs/git.ts +334 -0
- package/src/server/routes/fs/index.ts +19 -0
- package/src/server/routes/fs/read.ts +258 -0
- package/src/server/routes/fs/replace.ts +69 -0
- package/src/server/routes/fs/search.ts +135 -0
- package/src/server/routes/fs/validate.ts +61 -0
- package/src/server/routes/health/index.ts +6 -0
- package/src/server/routes/health/probe.ts +27 -0
- package/src/server/routes/index.ts +38 -0
- package/src/server/routes/models/index.ts +8 -0
- package/src/server/routes/models/roles.ts +31 -0
- package/src/server/routes/models/root.ts +328 -0
- package/src/server/routes/omp/commands.ts +29 -0
- package/src/server/routes/omp/extensions.ts +34 -0
- package/src/server/routes/omp/index.ts +20 -0
- package/src/server/routes/omp/login.ts +112 -0
- package/src/server/routes/omp/plugins.ts +82 -0
- package/src/server/routes/omp/pricing.ts +65 -0
- package/src/server/routes/omp/session-stats.ts +30 -0
- package/src/server/routes/omp/sidebar.ts +40 -0
- package/src/server/routes/omp/state.ts +22 -0
- package/src/server/routes/sessions/folder.ts +16 -0
- package/src/server/routes/sessions/index.ts +25 -0
- package/src/server/routes/sessions/list.ts +23 -0
- package/src/server/routes/sessions/session.ts +331 -0
- package/src/server/routes/sessions/subagents.ts +82 -0
- package/src/server/routes/settings/agents.ts +128 -0
- package/src/server/routes/settings/behavior.ts +125 -0
- package/src/server/routes/settings/commands.ts +89 -0
- package/src/server/routes/settings/index.ts +28 -0
- package/src/server/routes/settings/mcp-test.ts +71 -0
- package/src/server/routes/settings/mcp.ts +261 -0
- package/src/server/routes/settings/omp-config.ts +47 -0
- package/src/server/routes/settings/projects.ts +84 -0
- package/src/server/routes/settings/provider-models.ts +278 -0
- package/src/server/routes/settings/providers.ts +137 -0
- package/src/server/routes/settings/root.ts +40 -0
- package/src/server/routes/settings/skills.ts +175 -0
- package/src/server/routes/settings/usage.ts +81 -0
- package/src/server/routes/telemetry/context.ts +52 -0
- package/src/server/routes/telemetry/index.ts +10 -0
- package/src/server/routes/telemetry/raw-messages.ts +80 -0
- package/src/server/routes/telemetry/tokens.ts +163 -0
- package/src/server/routes/terminal/index.ts +8 -0
- package/src/server/routes/terminal/run.ts +135 -0
- package/src/server/routes/terminal/stream.ts +100 -0
- package/src/server/routes/updates/apply.ts +25 -0
- package/src/server/routes/updates/check.ts +27 -0
- package/src/server/routes/updates/index.ts +8 -0
- package/src/server/routes/well-known/devtools.ts +9 -0
- package/src/server/routes/well-known/index.ts +6 -0
- package/src/shared/lib/browser/activity.ts +115 -0
- package/src/shared/lib/browser/cdp.ts +201 -0
- package/src/shared/lib/browser/connection.ts +81 -0
- package/src/shared/lib/browser/observer.ts +129 -0
- package/src/shared/lib/browser/page-context.ts +20 -0
- package/src/shared/lib/browser/targets.test.ts +45 -0
- package/src/shared/lib/browser/targets.ts +74 -0
- package/src/shared/lib/browser/url.ts +21 -0
- package/src/shared/lib/browser/util.ts +20 -0
- package/src/shared/lib/browser/viewer.ts +303 -0
- package/src/shared/lib/browser/watcher.ts +75 -0
- package/src/shared/lib/chat/attachments.ts +62 -0
- package/src/shared/lib/chat/capitalize.ts +9 -0
- package/src/shared/lib/chat/composer/client.ts +210 -0
- package/src/shared/lib/chat/composer/filter.ts +62 -0
- package/src/shared/lib/chat/composer/translate.ts +103 -0
- package/src/shared/lib/chat/composer/trigger.ts +53 -0
- package/src/shared/lib/chat/detect-format.ts +38 -0
- package/src/shared/lib/chat/duration.ts +82 -0
- package/src/shared/lib/chat/omp/agent-events.test.ts +152 -0
- package/src/shared/lib/chat/omp/agent-events.ts +347 -0
- package/src/shared/lib/chat/omp/file-mutations.ts +42 -0
- package/src/shared/lib/chat/omp/socket.ts +95 -0
- package/src/shared/lib/chat/omp/sse.ts +53 -0
- package/src/shared/lib/chat/omp/status.ts +45 -0
- package/src/shared/lib/chat/omp/transport.ts +50 -0
- package/src/shared/lib/chat/order.ts +40 -0
- package/src/shared/lib/chat/read-sse.ts +99 -0
- package/src/shared/lib/chat/stream-service.ts +273 -0
- package/src/shared/lib/chat/task-result-parser.ts +166 -0
- package/src/shared/lib/chat/timeline/omp-callbacks.ts +293 -0
- package/src/shared/lib/chat/timeline/stream-callbacks.ts +202 -0
- package/src/shared/lib/chat/timeline/stream-raf.ts +59 -0
- package/src/shared/lib/chat/timeline/tool-phrases.ts +224 -0
- package/src/shared/lib/chat/timeline/tool-verbs.ts +160 -0
- package/src/shared/lib/chat/timeline/turns.ts +30 -0
- package/src/shared/lib/chat/title-case.ts +293 -0
- package/src/shared/lib/chat/todo-parser.ts +257 -0
- package/src/shared/lib/chat/tool-status.ts +20 -0
- package/src/shared/lib/code/ansi.ts +24 -0
- package/src/shared/lib/code/editor-utils.ts +16 -0
- package/src/shared/lib/code/format.ts +17 -0
- package/src/shared/lib/code/highlighter.ts +135 -0
- package/src/shared/lib/code/parser.ts +237 -0
- package/src/shared/lib/code/shiki-langs.ts +93 -0
- package/src/shared/lib/code/shiki-themes.ts +14 -0
- package/src/shared/lib/code/syntax-highlight.test.ts +153 -0
- package/src/shared/lib/code/syntax-highlight.ts +290 -0
- package/src/shared/lib/db/transaction.server.ts +20 -0
- package/src/shared/lib/format/number.ts +69 -0
- package/src/shared/lib/format/time.ts +39 -0
- package/src/shared/lib/fs/diff-parser.ts +135 -0
- package/src/shared/lib/fs/file-tree.ts +26 -0
- package/src/shared/lib/fs/git-graph.ts +184 -0
- package/src/shared/lib/fs/git-status.ts +161 -0
- package/src/shared/lib/markdown/marked.ts +228 -0
- package/src/shared/lib/markdown/mermaid.ts +153 -0
- package/src/shared/lib/markdown/sanitize.ts +138 -0
- package/src/shared/lib/models/catalog.ts +88 -0
- package/src/shared/lib/models/client.ts +51 -0
- package/src/shared/lib/models/identity.ts +21 -0
- package/src/shared/lib/models/provider-cleanup.ts +20 -0
- package/src/shared/lib/models/provider-connection.ts +41 -0
- package/src/shared/lib/models/provider-label.ts +40 -0
- package/src/shared/lib/models/provider-models.ts +97 -0
- package/src/shared/lib/models/provider-presets.ts +29 -0
- package/src/shared/lib/models/remote-list.ts +125 -0
- package/src/shared/lib/models/server-cache.ts +27 -0
- package/src/shared/lib/models/thinking-levels.ts +68 -0
- package/src/shared/lib/omp/config/access-mode.server.ts +27 -0
- package/src/shared/lib/omp/config/access-mode.ts +31 -0
- package/src/shared/lib/omp/config/schema-extras.ts +230 -0
- package/src/shared/lib/omp/config/schema-types.ts +49 -0
- package/src/shared/lib/omp/config/schema.ts +81 -0
- package/src/shared/lib/omp/rpc/frame.ts +134 -0
- package/src/shared/lib/omp/session/default-title.test.ts +50 -0
- package/src/shared/lib/omp/session/default-title.ts +51 -0
- package/src/shared/lib/omp/session/hashline-patch.test.ts +89 -0
- package/src/shared/lib/omp/session/hashline-patch.ts +134 -0
- package/src/shared/lib/omp/session/jsonl.ts +197 -0
- package/src/shared/lib/omp/session/mapper.ts +145 -0
- package/src/shared/lib/omp/session/messages-map.ts +179 -0
- package/src/shared/lib/omp/session/messages-parse.ts +69 -0
- package/src/shared/lib/omp/session/parse-message-blocks.ts +223 -0
- package/src/shared/lib/omp/session/prewarm.ts +41 -0
- package/src/shared/lib/omp/session/sidebar.ts +77 -0
- package/src/shared/lib/omp/session/stream-state.server.ts +106 -0
- package/src/shared/lib/omp/session/telemetry-blocks.ts +60 -0
- package/src/shared/lib/omp/session/timestamps.ts +20 -0
- package/src/shared/lib/omp/session/turn-error.ts +40 -0
- package/src/shared/lib/omp/subagent/history/client.ts +76 -0
- package/src/shared/lib/omp/subagent/history/settlement.ts +113 -0
- package/src/shared/lib/omp/subagent/history/status.ts +40 -0
- package/src/shared/lib/omp/subagent/parse.ts +284 -0
- package/src/shared/lib/omp/subagent/result-details.ts +53 -0
- package/src/shared/lib/omp/subagent/transcript-client.ts +178 -0
- package/src/shared/lib/settings/client.test.ts +62 -0
- package/src/shared/lib/settings/client.ts +96 -0
- package/src/shared/lib/updates/semver.ts +34 -0
- package/src/shared/lib/util/guards.ts +14 -0
- package/src/shared/lib/workspace/active-project.ts +42 -0
- package/src/shared/lib/workspace/panel-widths.test.ts +72 -0
- package/src/shared/lib/workspace/panel-widths.ts +79 -0
- package/src/shared/lib/workspace/project-icon.ts +29 -0
- package/src/shared/lib/workspace/project-settings-migration.ts +62 -0
- package/src/shared/lib/workspace/project-settings.ts +139 -0
- package/src/shared/lib/workspace/refresh-cadence.ts +128 -0
- package/src/shared/lib/workspace/relative-time.ts +25 -0
- package/src/shared/lib/workspace/right-panels.ts +51 -0
- package/src/shared/lib/workspace/schema-migrations.ts +19 -0
- package/src/shared/lib/workspace/session-state/store.ts +267 -0
- package/src/shared/lib/workspace/sidebar-expanded.ts +23 -0
- package/src/shared/lib/workspace/sidebar-sort.test.ts +200 -0
- package/src/shared/lib/workspace/sidebar-sort.ts +131 -0
- package/src/shared/types/browser.ts +58 -0
- package/src/shared/types/chat.ts +289 -0
- package/src/shared/types/context.ts +87 -0
- package/src/shared/types/fs.ts +36 -0
- package/src/shared/types/git.ts +60 -0
- package/src/shared/types/index.ts +22 -0
- package/src/shared/types/omp/agent.ts +109 -0
- package/src/shared/types/omp/instructions.ts +38 -0
- package/src/shared/types/omp/session.ts +153 -0
- package/src/shared/types/omp/subagent.ts +176 -0
- package/src/shared/types/settings/agent.ts +16 -0
- package/src/shared/types/settings/command.ts +12 -0
- package/src/shared/types/settings/mcp.ts +22 -0
- package/src/shared/types/settings/project.ts +18 -0
- package/src/shared/types/settings/provider.ts +42 -0
- package/src/shared/types/settings/skill.ts +35 -0
- package/src/shared/types/settings/state.ts +59 -0
- package/src/shared/types/settings/usage.ts +99 -0
- package/src/shared/types/terminal.ts +19 -0
- package/src/shared/types/tokenUsage.ts +44 -0
- package/src/shared/types/updates.ts +38 -0
- package/src/shared/types/workspace.ts +56 -0
- package/tsconfig.json +26 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { DbClient } from '@/server/lib/db/client';
|
|
2
|
+
|
|
3
|
+
async function addColumn(db: DbClient, statement: string): Promise<void> {
|
|
4
|
+
try {
|
|
5
|
+
await db.exec(statement);
|
|
6
|
+
} catch (error) {
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export async function migrateWorkspaceFolderColumns(db: DbClient): Promise<void> {
|
|
12
|
+
await addColumn(db, 'ALTER TABLE workspace_folders ADD COLUMN is_expanded BOOLEAN DEFAULT 0;');
|
|
13
|
+
await addColumn(db, 'ALTER TABLE workspace_folders ADD COLUMN project_path TEXT;');
|
|
14
|
+
await addColumn(db, 'ALTER TABLE workspace_folders ADD COLUMN is_pinned BOOLEAN DEFAULT 0;');
|
|
15
|
+
await addColumn(db, "ALTER TABLE workspace_folders ADD COLUMN model TEXT DEFAULT 'Not selected';");
|
|
16
|
+
await addColumn(db, "ALTER TABLE workspace_folders ADD COLUMN accent_color TEXT DEFAULT '';");
|
|
17
|
+
await addColumn(db, "ALTER TABLE workspace_folders ADD COLUMN icon TEXT DEFAULT 'default';");
|
|
18
|
+
await addColumn(db, 'ALTER TABLE workspace_folders ADD COLUMN custom_icon_url TEXT;');
|
|
19
|
+
}
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-session UI state store (module singleton).
|
|
3
|
+
*
|
|
4
|
+
* UI state that should survive session switches (and full page reloads) is
|
|
5
|
+
* kept here in an in-memory cache keyed by the session id and persisted as
|
|
6
|
+
* one JSON blob per session into the `session_ui_state` SQLite table via
|
|
7
|
+
* `GET/POST /api/sessions/:sessionId/state`. Session ids are the URL
|
|
8
|
+
* `sessionId` param values: numeric in mock mode, omp UUID strings in real
|
|
9
|
+
* mode, plus transient `new-…` ids for pending chats (migrated to the real
|
|
10
|
+
* id on spawn adoption).
|
|
11
|
+
*
|
|
12
|
+
* Key namespace contract (dot-prefixed by owning panel):
|
|
13
|
+
* - layout.activeRightPanel RightPanelType
|
|
14
|
+
* - layout.showRightPanel boolean
|
|
15
|
+
* - layout.openedFiles editor file entries array
|
|
16
|
+
* - layout.activeFileId number | null
|
|
17
|
+
* - editor.previewMode Record<fileId, boolean>
|
|
18
|
+
* - editor.wordWrap boolean
|
|
19
|
+
* - editor.zoomLevel number
|
|
20
|
+
* - files.expandedPaths string[]
|
|
21
|
+
* - files.searchQuery string
|
|
22
|
+
* - files.activeRepo string
|
|
23
|
+
* - browser.viewportMode string
|
|
24
|
+
* - browser.zoomLevel number
|
|
25
|
+
* - userBrowser.history string[]
|
|
26
|
+
* - userBrowser.historyIndex number
|
|
27
|
+
* - userBrowser.inputUrl string
|
|
28
|
+
* - userBrowser.viewportMode string
|
|
29
|
+
* - userBrowser.zoomLevel number
|
|
30
|
+
* - terminal.activeRepo string
|
|
31
|
+
* - terminal.cwd string
|
|
32
|
+
* - terminal.commandHistory string[]
|
|
33
|
+
* - terminal.input string
|
|
34
|
+
* - terminal.output string (trimmed tail)
|
|
35
|
+
* - git.viewMode 'flat' | 'tree'
|
|
36
|
+
* - git.commitDraft string
|
|
37
|
+
* - git.stagedExpanded boolean
|
|
38
|
+
* - git.unstagedExpanded boolean
|
|
39
|
+
* - git.expandedFolders string[]
|
|
40
|
+
* - git.repoQuery string
|
|
41
|
+
* - search.query string
|
|
42
|
+
* - search.replaceQuery string
|
|
43
|
+
* - search.matchCase boolean
|
|
44
|
+
* - search.wholeWord boolean
|
|
45
|
+
* - search.useRegex boolean
|
|
46
|
+
* - search.includeFiles string
|
|
47
|
+
* - search.showIncludeField boolean
|
|
48
|
+
* - search.activeRepo string
|
|
49
|
+
* - context.rawExpandedIds Record<string, boolean>
|
|
50
|
+
* - context.rawFilterRole 'all' | 'assistant' | 'user'
|
|
51
|
+
* - usage.selectedProviderId 'kenari' | 'deepseek'
|
|
52
|
+
* - chat.draft string
|
|
53
|
+
* - chat.draftAttachments attachment metadata array
|
|
54
|
+
*/
|
|
55
|
+
|
|
56
|
+
type SessionState = Record<string, unknown>;
|
|
57
|
+
|
|
58
|
+
const cache = new Map<string, SessionState>();
|
|
59
|
+
/** Epoch ms of the last user-driven access per session (get/set/hydrate). */
|
|
60
|
+
const lastTouched = new Map<string, number>();
|
|
61
|
+
const readySessions = new Set<string>();
|
|
62
|
+
const dirtySessions = new Map<string, boolean>();
|
|
63
|
+
const persistTimers = new Map<string, ReturnType<typeof setTimeout>>();
|
|
64
|
+
|
|
65
|
+
const PERSIST_DEBOUNCE_MS = 600;
|
|
66
|
+
|
|
67
|
+
// Bounded LRU cache: cap the number of sessions kept in memory so the tab
|
|
68
|
+
// doesn't grow unboundedly as the user visits more sessions.
|
|
69
|
+
const MAX_CACHED_SESSIONS = 10;
|
|
70
|
+
/** A session whose last user access is older than this is evicted regardless
|
|
71
|
+
* of the size cap, so stale per-session UI state (drafts, panel layouts)
|
|
72
|
+
* stops occupying memory 10 minutes after the user last opened it. */
|
|
73
|
+
const SESSION_IDLE_TTL_MS = 10 * 60 * 1000;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Reorder a cache entry to the end of the Map's iteration order (the
|
|
77
|
+
* most-recently-used position) via delete-then-set. Map.set on an existing
|
|
78
|
+
* key updates the value but keeps its original position, so the explicit
|
|
79
|
+
* delete is required for true LRU semantics.
|
|
80
|
+
*/
|
|
81
|
+
function touchCacheEntry(sessionId: string): void {
|
|
82
|
+
const value = cache.get(sessionId);
|
|
83
|
+
if (value !== undefined) {
|
|
84
|
+
cache.delete(sessionId);
|
|
85
|
+
cache.set(sessionId, value);
|
|
86
|
+
}
|
|
87
|
+
lastTouched.set(sessionId, Date.now());
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Evict the oldest clean sessions until the cache is within bounds.
|
|
92
|
+
*
|
|
93
|
+
* Dirty-safety rule: a session with unsaved writes (`dirtySessions.get(id) ===
|
|
94
|
+
* true`) must never be evicted, or the user's drafts and editor state would be
|
|
95
|
+
* silently lost. If every candidate is dirty (or is the protected id currently
|
|
96
|
+
* being written), stop evicting rather than lose data.
|
|
97
|
+
*
|
|
98
|
+
* Entries idle past SESSION_IDLE_TTL_MS are evicted first — even when the
|
|
99
|
+
* cache is under the size cap — so long-unused sessions drop out on schedule.
|
|
100
|
+
*/
|
|
101
|
+
function evictIfNeeded(protectedId: string | null): void {
|
|
102
|
+
const now = Date.now();
|
|
103
|
+
const evict = (id: string): void => {
|
|
104
|
+
cache.delete(id);
|
|
105
|
+
readySessions.delete(id);
|
|
106
|
+
dirtySessions.delete(id);
|
|
107
|
+
lastTouched.delete(id);
|
|
108
|
+
const timer = persistTimers.get(id);
|
|
109
|
+
if (timer) {
|
|
110
|
+
clearTimeout(timer);
|
|
111
|
+
persistTimers.delete(id);
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
// TTL pass: safe to skip only while the timer still holds the unsaved state
|
|
115
|
+
// or the session is the one currently being written.
|
|
116
|
+
for (const [id, touched] of lastTouched) {
|
|
117
|
+
if (now - touched <= SESSION_IDLE_TTL_MS) continue;
|
|
118
|
+
if (id === protectedId) continue;
|
|
119
|
+
if (dirtySessions.get(id)) continue;
|
|
120
|
+
evict(id);
|
|
121
|
+
}
|
|
122
|
+
while (cache.size > MAX_CACHED_SESSIONS) {
|
|
123
|
+
let evicted = false;
|
|
124
|
+
for (const id of cache.keys()) {
|
|
125
|
+
if (id === protectedId) continue;
|
|
126
|
+
if (dirtySessions.get(id)) continue;
|
|
127
|
+
evict(id);
|
|
128
|
+
evicted = true;
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
if (!evicted) break;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export function getSessionValue<T>(sessionId: string | null, key: string): T | undefined {
|
|
136
|
+
if (!sessionId) return undefined;
|
|
137
|
+
touchCacheEntry(sessionId);
|
|
138
|
+
return cache.get(sessionId)?.[key] as T | undefined;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export function setSessionKey(sessionId: string | null, key: string, value: unknown): void {
|
|
142
|
+
if (!sessionId) return;
|
|
143
|
+
const state = cache.get(sessionId) ?? {};
|
|
144
|
+
state[key] = value;
|
|
145
|
+
cache.set(sessionId, state);
|
|
146
|
+
touchCacheEntry(sessionId);
|
|
147
|
+
dirtySessions.set(sessionId, true);
|
|
148
|
+
schedulePersist(sessionId);
|
|
149
|
+
evictIfNeeded(sessionId);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function schedulePersist(sessionId: string): void {
|
|
153
|
+
const existing = persistTimers.get(sessionId);
|
|
154
|
+
if (existing) clearTimeout(existing);
|
|
155
|
+
persistTimers.set(
|
|
156
|
+
sessionId,
|
|
157
|
+
setTimeout(() => {
|
|
158
|
+
persistTimers.delete(sessionId);
|
|
159
|
+
void persistSession(sessionId);
|
|
160
|
+
}, PERSIST_DEBOUNCE_MS),
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
async function persistSession(sessionId: string): Promise<void> {
|
|
165
|
+
if (typeof window === 'undefined' || !sessionId) return;
|
|
166
|
+
if (!dirtySessions.get(sessionId)) return;
|
|
167
|
+
dirtySessions.set(sessionId, false);
|
|
168
|
+
const state = cache.get(sessionId) ?? {};
|
|
169
|
+
try {
|
|
170
|
+
await fetch(`/api/sessions/${encodeURIComponent(sessionId)}/state`, {
|
|
171
|
+
method: 'POST',
|
|
172
|
+
headers: { 'Content-Type': 'application/json' },
|
|
173
|
+
body: JSON.stringify({ state }),
|
|
174
|
+
});
|
|
175
|
+
} catch (err) {
|
|
176
|
+
console.warn('session-state persist failed:', err);
|
|
177
|
+
dirtySessions.set(sessionId, true);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/** Immediately persist any pending writes for a session (used on switch). */
|
|
182
|
+
export function flushSession(sessionId: string | null): Promise<void> {
|
|
183
|
+
if (!sessionId || typeof window === 'undefined') return Promise.resolve();
|
|
184
|
+
const timer = persistTimers.get(sessionId);
|
|
185
|
+
if (timer) {
|
|
186
|
+
clearTimeout(timer);
|
|
187
|
+
persistTimers.delete(sessionId);
|
|
188
|
+
}
|
|
189
|
+
return persistSession(sessionId);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/** Fetch a session's stored blob and merge it under any local writes. */
|
|
193
|
+
export async function loadSession(sessionId: string): Promise<void> {
|
|
194
|
+
if (!sessionId) return;
|
|
195
|
+
if (typeof window === 'undefined') {
|
|
196
|
+
readySessions.add(sessionId);
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
try {
|
|
200
|
+
const res = await fetch(`/api/sessions/${encodeURIComponent(sessionId)}/state`);
|
|
201
|
+
if (res.ok) {
|
|
202
|
+
const data = (await res.json()) as { state?: SessionState };
|
|
203
|
+
const incoming = data.state && typeof data.state === 'object' ? data.state : {};
|
|
204
|
+
const existing = cache.get(sessionId) ?? {};
|
|
205
|
+
// Only keys written locally while the fetch was in flight win over the
|
|
206
|
+
// stored blob. Merging the WHOLE local cache over the blob (the old
|
|
207
|
+
// behavior) resurrected stale values on every tab: a second browser
|
|
208
|
+
// opening the session had cached the pre-write blob, and its stale
|
|
209
|
+
// copy clobbered another tab's fresh writes — queue items written in
|
|
210
|
+
// one tab never appeared in the other.
|
|
211
|
+
const dirty = dirtySessions.get(sessionId) === true;
|
|
212
|
+
const merged = dirty ? { ...incoming, ...existing } : incoming;
|
|
213
|
+
cache.set(sessionId, merged);
|
|
214
|
+
touchCacheEntry(sessionId);
|
|
215
|
+
}
|
|
216
|
+
} catch (err) {
|
|
217
|
+
console.warn('session-state load failed:', err);
|
|
218
|
+
}
|
|
219
|
+
readySessions.add(sessionId);
|
|
220
|
+
evictIfNeeded(sessionId);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/** Seed the cache synchronously (e.g. from SSR-provided data). */
|
|
224
|
+
export function hydrateSession(sessionId: string | null, state: SessionState): void {
|
|
225
|
+
if (!sessionId) return;
|
|
226
|
+
cache.set(sessionId, { ...(cache.get(sessionId) ?? {}), ...state });
|
|
227
|
+
touchCacheEntry(sessionId);
|
|
228
|
+
readySessions.add(sessionId);
|
|
229
|
+
evictIfNeeded(sessionId);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/** Mark a session as loaded without fetching (fresh / ephemeral sessions). */
|
|
233
|
+
export function markSessionReady(sessionId: string | null): void {
|
|
234
|
+
if (sessionId) readySessions.add(sessionId);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Record that the user opened this session now. Drives the mobile header's
|
|
239
|
+
* recent-session picker and the cache TTL: a session is "recent" only while
|
|
240
|
+
* its last open is within SESSION_IDLE_TTL_MS.
|
|
241
|
+
*/
|
|
242
|
+
export function recordSessionOpen(sessionId: string | null): void {
|
|
243
|
+
if (sessionId) lastTouched.set(sessionId, Date.now());
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/** Epoch ms of the user's last open of this session in this tab, if any. */
|
|
247
|
+
export function getLastOpenedAt(sessionId: string): number | undefined {
|
|
248
|
+
return lastTouched.get(sessionId);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Move a pending `new-…` session's state onto the real session id adopted
|
|
253
|
+
* by a spawn, then discard the transient slot.
|
|
254
|
+
*/
|
|
255
|
+
export function migrateSessionState(fromId: string, toId: string): void {
|
|
256
|
+
const from = cache.get(fromId);
|
|
257
|
+
if (from) cache.set(toId, { ...from, ...(cache.get(toId) ?? {}) });
|
|
258
|
+
touchCacheEntry(toId);
|
|
259
|
+
readySessions.add(toId);
|
|
260
|
+
dirtySessions.set(toId, true);
|
|
261
|
+
schedulePersist(toId);
|
|
262
|
+
cache.delete(fromId);
|
|
263
|
+
readySessions.delete(fromId);
|
|
264
|
+
dirtySessions.delete(fromId);
|
|
265
|
+
lastTouched.delete(fromId);
|
|
266
|
+
evictIfNeeded(toId);
|
|
267
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Persistence for the sidebar's expanded-session rows.
|
|
3
|
+
*
|
|
4
|
+
* This is cross-session UI state (which session rows show their live subagent
|
|
5
|
+
* roster), stored in `app_settings` under its own key. The save path caps the
|
|
6
|
+
* array so it cannot grow without bound.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { readChamberSetting, writeSetting } from '@/shared/lib/settings/client';
|
|
10
|
+
|
|
11
|
+
const SETTINGS_KEY = 'omp_sidebar_expanded_sessions';
|
|
12
|
+
/** Beyond this many ids the oldest are dropped on save. */
|
|
13
|
+
const MAX_IDS = 50;
|
|
14
|
+
|
|
15
|
+
export function loadExpandedSessionIds(): Set<string> {
|
|
16
|
+
const parsed = readChamberSetting<unknown>(SETTINGS_KEY);
|
|
17
|
+
if (!Array.isArray(parsed)) return new Set();
|
|
18
|
+
return new Set(parsed.filter((id): id is string => typeof id === 'string'));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function saveExpandedSessionIds(ids: Set<string>): void {
|
|
22
|
+
writeSetting(SETTINGS_KEY, [...ids].slice(-MAX_IDS));
|
|
23
|
+
}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { describe, expect, test } from 'bun:test';
|
|
7
|
+
|
|
8
|
+
import { compareFolders, isValidSessionSortOption, sortFolders } from '@/shared/lib/workspace/sidebar-sort';
|
|
9
|
+
import type { SessionItemData, SessionSortOption, WorkspaceFolderData } from '@/shared/types';
|
|
10
|
+
|
|
11
|
+
/** Minimal session factory — only the fields the comparator reads. */
|
|
12
|
+
function makeSession(
|
|
13
|
+
id: number | string,
|
|
14
|
+
createdAt?: string,
|
|
15
|
+
updatedAt?: string,
|
|
16
|
+
): SessionItemData {
|
|
17
|
+
return {
|
|
18
|
+
id,
|
|
19
|
+
folder_id: 0,
|
|
20
|
+
title: `session-${id}`,
|
|
21
|
+
...(createdAt !== undefined ? { created_at: createdAt } : {}),
|
|
22
|
+
...(updatedAt !== undefined ? { updated_at: updatedAt } : {}),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Minimal folder factory — fills the fields the comparator ignores. */
|
|
27
|
+
function makeFolder(
|
|
28
|
+
id: number,
|
|
29
|
+
name: string,
|
|
30
|
+
sessions: SessionItemData[] = [],
|
|
31
|
+
isPinned = false,
|
|
32
|
+
): WorkspaceFolderData {
|
|
33
|
+
return {
|
|
34
|
+
id,
|
|
35
|
+
name,
|
|
36
|
+
isPinned,
|
|
37
|
+
isExpanded: false,
|
|
38
|
+
sessions,
|
|
39
|
+
hasMore: false,
|
|
40
|
+
totalSessions: sessions.length,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const ALL_OPTIONS: readonly SessionSortOption[] = [
|
|
45
|
+
'A-Z',
|
|
46
|
+
'Z-A',
|
|
47
|
+
'LATEST_SESSION',
|
|
48
|
+
'LATEST_ADDED',
|
|
49
|
+
];
|
|
50
|
+
|
|
51
|
+
describe('sidebar-sort', () => {
|
|
52
|
+
test('A-Z sorts folder names ascending', () => {
|
|
53
|
+
const folders = [makeFolder(1, 'zeta'), makeFolder(2, 'alpha'), makeFolder(3, 'mid')];
|
|
54
|
+
const sorted = sortFolders(folders, 'A-Z');
|
|
55
|
+
expect(sorted.map((f) => f.name)).toEqual(['alpha', 'mid', 'zeta']);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test('Z-A sorts folder names descending', () => {
|
|
59
|
+
const folders = [makeFolder(1, 'alpha'), makeFolder(2, 'zeta'), makeFolder(3, 'mid')];
|
|
60
|
+
const sorted = sortFolders(folders, 'Z-A');
|
|
61
|
+
expect(sorted.map((f) => f.name)).toEqual(['zeta', 'mid', 'alpha']);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test('A-Z puts pinned folders first even when their name sorts last', () => {
|
|
65
|
+
const folders = [
|
|
66
|
+
makeFolder(1, 'alpha'),
|
|
67
|
+
makeFolder(2, 'zeta', [], true),
|
|
68
|
+
makeFolder(3, 'mid'),
|
|
69
|
+
];
|
|
70
|
+
const sorted = sortFolders(folders, 'A-Z');
|
|
71
|
+
expect(sorted.map((f) => f.name)).toEqual(['zeta', 'alpha', 'mid']);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test('LATEST_SESSION orders by newest updated_at desc with omp UUID string ids', () => {
|
|
75
|
+
const alpha = makeFolder(1, 'alpha', [
|
|
76
|
+
makeSession('ses_alpha', undefined, '2024-01-01T00:00:00.000Z'),
|
|
77
|
+
]);
|
|
78
|
+
const beta = makeFolder(2, 'beta', [
|
|
79
|
+
makeSession('ses_beta', undefined, '2024-06-01T00:00:00.000Z'),
|
|
80
|
+
]);
|
|
81
|
+
// Regression: comparing UUID strings numerically produced NaN -> no-op sort.
|
|
82
|
+
expect(Number.isNaN(compareFolders(alpha, beta, 'LATEST_SESSION'))).toBe(false);
|
|
83
|
+
const sorted = sortFolders([alpha, beta], 'LATEST_SESSION');
|
|
84
|
+
expect(sorted.map((f) => f.name)).toEqual(['beta', 'alpha']);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test('LATEST_SESSION falls back to created_at when updated_at is absent', () => {
|
|
88
|
+
const older = makeFolder(1, 'older', [
|
|
89
|
+
makeSession('ses_old', '2024-02-01T00:00:00.000Z'),
|
|
90
|
+
]);
|
|
91
|
+
const newer = makeFolder(2, 'newer', [
|
|
92
|
+
makeSession('ses_new', '2024-09-01T00:00:00.000Z'),
|
|
93
|
+
]);
|
|
94
|
+
const sorted = sortFolders([older, newer], 'LATEST_SESSION');
|
|
95
|
+
expect(sorted.map((f) => f.name)).toEqual(['newer', 'older']);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
test('LATEST_SESSION breaks identical timestamps by highest numeric session id desc', () => {
|
|
99
|
+
const shared = '2024-03-03T00:00:00.000Z';
|
|
100
|
+
const low = makeFolder(1, 'low', [
|
|
101
|
+
makeSession(5, shared, shared),
|
|
102
|
+
makeSession(9, shared, shared),
|
|
103
|
+
]);
|
|
104
|
+
const high = makeFolder(2, 'high', [makeSession(42, shared, shared)]);
|
|
105
|
+
const sorted = sortFolders([low, high], 'LATEST_SESSION');
|
|
106
|
+
expect(sorted.map((f) => f.name)).toEqual(['high', 'low']);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
test('LATEST_SESSION puts a folder with no sessions after folders with activity', () => {
|
|
110
|
+
const empty = makeFolder(1, 'empty', []);
|
|
111
|
+
const active = makeFolder(2, 'active', [
|
|
112
|
+
makeSession('ses_x', undefined, '2024-05-05T00:00:00.000Z'),
|
|
113
|
+
]);
|
|
114
|
+
const sorted = sortFolders([empty, active], 'LATEST_SESSION');
|
|
115
|
+
expect(sorted.map((f) => f.name)).toEqual(['active', 'empty']);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
test('LATEST_SESSION puts a folder carrying a fresh pending session first', () => {
|
|
119
|
+
const pending = makeFolder(1, 'pending', [
|
|
120
|
+
makeSession('new-1737000000000', undefined, '2025-01-16T04:00:00.000Z'),
|
|
121
|
+
]);
|
|
122
|
+
const settled = makeFolder(2, 'settled', [
|
|
123
|
+
makeSession('ses_settled', undefined, '2024-01-01T00:00:00.000Z'),
|
|
124
|
+
]);
|
|
125
|
+
const sorted = sortFolders([settled, pending], 'LATEST_SESSION');
|
|
126
|
+
expect(sorted.map((f) => f.name)).toEqual(['pending', 'settled']);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
test('LATEST_ADDED puts the highest numeric folder id first', () => {
|
|
130
|
+
const folders = [makeFolder(7, 'seven'), makeFolder(3, 'three'), makeFolder(20, 'twenty')];
|
|
131
|
+
const sorted = sortFolders(folders, 'LATEST_ADDED');
|
|
132
|
+
expect(sorted.map((f) => f.name)).toEqual(['twenty', 'seven', 'three']);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
test('compareFolders returns a finite number for every option with UUID ids and no timestamps', () => {
|
|
136
|
+
const a = makeFolder(1, 'a', [makeSession('ses_alpha')]);
|
|
137
|
+
const b = makeFolder(2, 'b', [makeSession('ses_beta')]);
|
|
138
|
+
for (const option of ALL_OPTIONS) {
|
|
139
|
+
expect(Number.isNaN(compareFolders(a, b, option))).toBe(false);
|
|
140
|
+
expect(Number.isNaN(compareFolders(b, a, option))).toBe(false);
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
test('sortFolders does not mutate its input array', () => {
|
|
145
|
+
const folders = [makeFolder(1, 'zeta'), makeFolder(2, 'alpha'), makeFolder(3, 'mid')];
|
|
146
|
+
const before = folders.map((f) => f.name);
|
|
147
|
+
sortFolders(folders, 'A-Z');
|
|
148
|
+
expect(folders.map((f) => f.name)).toEqual(before);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
test('sessions inside a folder are left untouched after sorting', () => {
|
|
152
|
+
const sessions = [
|
|
153
|
+
makeSession('ses_one', undefined, '2024-01-01T00:00:00.000Z'),
|
|
154
|
+
makeSession('ses_two', undefined, '2024-02-01T00:00:00.000Z'),
|
|
155
|
+
];
|
|
156
|
+
const folder = makeFolder(1, 'keep', sessions);
|
|
157
|
+
const other = makeFolder(2, 'other', []);
|
|
158
|
+
const sorted = sortFolders([other, folder], 'LATEST_SESSION');
|
|
159
|
+
const kept = sorted.find((f) => f.name === 'keep');
|
|
160
|
+
expect(kept?.sessions).toBe(sessions);
|
|
161
|
+
expect(kept?.sessions.map((s) => s.id)).toEqual(['ses_one', 'ses_two']);
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
describe('isValidSessionSortOption', () => {
|
|
166
|
+
test('returns true for all four supported options', () => {
|
|
167
|
+
for (const option of ALL_OPTIONS) {
|
|
168
|
+
expect(isValidSessionSortOption(option)).toBe(true);
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
test('returns false for non-options and mistyped values', () => {
|
|
173
|
+
const invalid: unknown[] = [
|
|
174
|
+
undefined,
|
|
175
|
+
null,
|
|
176
|
+
'',
|
|
177
|
+
'latest_session',
|
|
178
|
+
'LATEST',
|
|
179
|
+
42,
|
|
180
|
+
{},
|
|
181
|
+
[],
|
|
182
|
+
true,
|
|
183
|
+
'A-Z ',
|
|
184
|
+
];
|
|
185
|
+
for (const value of invalid) {
|
|
186
|
+
expect(isValidSessionSortOption(value)).toBe(false);
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
test('narrows the value so sortFolders accepts it without a cast', () => {
|
|
191
|
+
const folders = [makeFolder(1, 'zeta'), makeFolder(2, 'alpha')];
|
|
192
|
+
const candidate: unknown = 'A-Z';
|
|
193
|
+
if (isValidSessionSortOption(candidate)) {
|
|
194
|
+
const sorted = sortFolders(folders, candidate);
|
|
195
|
+
expect(sorted.map((f) => f.name)).toEqual(['alpha', 'zeta']);
|
|
196
|
+
} else {
|
|
197
|
+
throw new Error('expected the guard to narrow "A-Z"');
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
});
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Sidebar workspace ordering, shared by the desktop and mobile session
|
|
8
|
+
* sidebars. One implementation is deliberate: the two sidebars used to carry
|
|
9
|
+
* their own comparators, and the mobile copy silently dropped both time-based
|
|
10
|
+
* options while the desktop copy compared omp session UUIDs numerically
|
|
11
|
+
* (Math.max over strings -> NaN -> a no-op sort).
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import type { SessionSortOption, WorkspaceFolderData } from '@/shared/types';
|
|
15
|
+
|
|
16
|
+
/** Epoch ms of an ISO timestamp; NaN when missing or unparseable. */
|
|
17
|
+
function parseTime(value?: string | null): number {
|
|
18
|
+
if (!value) return Number.NaN;
|
|
19
|
+
const parsed = Date.parse(value);
|
|
20
|
+
return Number.isFinite(parsed) ? parsed : Number.NaN;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Epoch ms of a folder's newest session; -Infinity when it has none. */
|
|
24
|
+
function latestSessionTime(folder: WorkspaceFolderData): number {
|
|
25
|
+
let latest = Number.NEGATIVE_INFINITY;
|
|
26
|
+
for (const session of folder.sessions ?? []) {
|
|
27
|
+
const time = parseTime(session.updated_at ?? session.created_at);
|
|
28
|
+
if (time > latest) latest = time;
|
|
29
|
+
}
|
|
30
|
+
return latest;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Highest numeric session id in a folder (demo/mock ids are SQLite
|
|
35
|
+
* AUTOINCREMENT; real omp ids are UUIDs and yield -Infinity). Only a
|
|
36
|
+
* tiebreaker for equal timestamps — the norm in demo mode, where every seeded
|
|
37
|
+
* row shares one CURRENT_TIMESTAMP.
|
|
38
|
+
*/
|
|
39
|
+
function latestSessionSeq(folder: WorkspaceFolderData): number {
|
|
40
|
+
let latest = Number.NEGATIVE_INFINITY;
|
|
41
|
+
for (const session of folder.sessions ?? []) {
|
|
42
|
+
const id = Number(session.id);
|
|
43
|
+
if (Number.isFinite(id) && id > latest) latest = id;
|
|
44
|
+
}
|
|
45
|
+
return latest;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Numeric folder id, or -Infinity for a non-numeric id. */
|
|
49
|
+
function folderId(folder: WorkspaceFolderData): number {
|
|
50
|
+
const id = Number(folder.id);
|
|
51
|
+
return Number.isFinite(id) ? id : Number.NEGATIVE_INFINITY;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Descending compare that is safe for -Infinity/-Infinity (never NaN). */
|
|
55
|
+
function compareDesc(a: number, b: number): number {
|
|
56
|
+
if (a === b) return 0;
|
|
57
|
+
return a > b ? -1 : 1;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Ascending compare that is safe for -Infinity/-Infinity (never NaN). */
|
|
61
|
+
function compareAsc(a: number, b: number): number {
|
|
62
|
+
if (a === b) return 0;
|
|
63
|
+
return a > b ? 1 : -1;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Order two sidebar workspaces. Pinned workspaces always lead; every option
|
|
68
|
+
* then falls back to a deterministic tiebreaker so equal keys never leave the
|
|
69
|
+
* order to chance.
|
|
70
|
+
*
|
|
71
|
+
* - `A-Z` / `Z-A` — folder name, then folder id asc.
|
|
72
|
+
* - `LATEST_SESSION` — newest session activity in the folder
|
|
73
|
+
* (updated_at, else created_at), then highest
|
|
74
|
+
* numeric session id (demo mode), then folder id
|
|
75
|
+
* desc. Folders without sessions sort last.
|
|
76
|
+
* - `LATEST_ADDED` — newest folder first (folder id desc), then name.
|
|
77
|
+
*/
|
|
78
|
+
export function compareFolders(
|
|
79
|
+
a: WorkspaceFolderData,
|
|
80
|
+
b: WorkspaceFolderData,
|
|
81
|
+
sortOption: SessionSortOption,
|
|
82
|
+
): number {
|
|
83
|
+
const pinnedA = Boolean(a.isPinned);
|
|
84
|
+
const pinnedB = Boolean(b.isPinned);
|
|
85
|
+
if (pinnedA !== pinnedB) return pinnedA ? -1 : 1;
|
|
86
|
+
|
|
87
|
+
switch (sortOption) {
|
|
88
|
+
case 'Z-A': {
|
|
89
|
+
const byName = b.name.localeCompare(a.name);
|
|
90
|
+
return byName !== 0 ? byName : compareAsc(folderId(a), folderId(b));
|
|
91
|
+
}
|
|
92
|
+
case 'LATEST_SESSION': {
|
|
93
|
+
const byTime = compareDesc(latestSessionTime(a), latestSessionTime(b));
|
|
94
|
+
if (byTime !== 0) return byTime;
|
|
95
|
+
const bySeq = compareDesc(latestSessionSeq(a), latestSessionSeq(b));
|
|
96
|
+
if (bySeq !== 0) return bySeq;
|
|
97
|
+
const byId = compareDesc(folderId(a), folderId(b));
|
|
98
|
+
return byId !== 0 ? byId : a.name.localeCompare(b.name);
|
|
99
|
+
}
|
|
100
|
+
case 'LATEST_ADDED': {
|
|
101
|
+
const byId = compareDesc(folderId(a), folderId(b));
|
|
102
|
+
return byId !== 0 ? byId : a.name.localeCompare(b.name);
|
|
103
|
+
}
|
|
104
|
+
case 'A-Z':
|
|
105
|
+
default: {
|
|
106
|
+
const byName = a.name.localeCompare(b.name);
|
|
107
|
+
return byName !== 0 ? byName : compareAsc(folderId(a), folderId(b));
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** Non-mutating workspace sort — returns a new array, never reorders in place. */
|
|
113
|
+
export function sortFolders(
|
|
114
|
+
folders: WorkspaceFolderData[],
|
|
115
|
+
sortOption: SessionSortOption,
|
|
116
|
+
): WorkspaceFolderData[] {
|
|
117
|
+
return [...folders].sort((a, b) => compareFolders(a, b, sortOption));
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** All supported workspace sort options, in menu order. */
|
|
121
|
+
const SESSION_SORT_OPTIONS: readonly SessionSortOption[] = ['A-Z', 'Z-A', 'LATEST_SESSION', 'LATEST_ADDED'];
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Narrow an untrusted value (a DB-stored preference, a URL param) to a sort
|
|
125
|
+
* option. The loader and both sidebars must agree on what counts as a valid
|
|
126
|
+
* preference, so the guard lives next to the comparator instead of being
|
|
127
|
+
* re-implemented per call site.
|
|
128
|
+
*/
|
|
129
|
+
export function isValidSessionSortOption(value: unknown): value is SessionSortOption {
|
|
130
|
+
return typeof value === 'string' && (SESSION_SORT_OPTIONS as readonly string[]).includes(value);
|
|
131
|
+
}
|