pi-roundtable-web 0.26.3 → 0.27.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/CHANGELOG.md +29 -0
- package/README.md +18 -11
- package/dist/chunk-account-1ecx5kt7.js +1 -0
- package/dist/chunk-action-menu-zh2n0ahf.js +1 -0
- package/dist/chunk-agent-ynm2tcbx.js +1 -0
- package/dist/chunk-arranged-rooms-qnz8vese.js +1 -0
- package/dist/chunk-bulk-actions-pr0mw0kc.js +1 -0
- package/dist/chunk-character-creator-caj4pmg4.js +1 -0
- package/dist/{chunk-codeeditor-6xavqntt.js → chunk-codeeditor-dga6s78p.js} +2 -2
- package/dist/chunk-confirm-g76v5d9r.js +1 -0
- package/dist/{chunk-connectors-7xqsg5q5.js → chunk-connectors-j79ze3j1.js} +1 -1
- package/dist/{chunk-conversations-zc4mv6vj.js → chunk-conversations-2farn72g.js} +1 -1
- package/dist/chunk-council-sheet-s9sz1bzf.js +2 -0
- package/dist/{chunk-drag-0mefcvp3.js → chunk-drag-45e8222r.js} +1 -1
- package/dist/chunk-entry-q11n47h9.js +1 -0
- package/dist/chunk-folder-list-4gcj7g7h.js +1 -0
- package/dist/chunk-folds-ten4ykfw.js +1 -0
- package/dist/{chunk-gate-86r8a2vf.js → chunk-gate-kcv1a4t0.js} +1 -1
- package/dist/chunk-group-scene-12ghcvzd.js +1 -0
- package/dist/chunk-group-table-t458kdgn.js +1 -0
- package/dist/chunk-host-icons-h1k9k96a.js +1 -0
- package/dist/chunk-host-picture-3p0wzn3v.js +1 -0
- package/dist/chunk-host-state-7mdve7cb.js +1 -0
- package/dist/chunk-host-ui-bdgwa6sf.js +1 -0
- package/dist/chunk-index-02vfshtt.js +2 -0
- package/dist/chunk-index-0a81da8z.js +2 -0
- package/dist/{chunk-index-8eexybcx.js → chunk-index-0w4bfjb5.js} +2 -2
- package/dist/{chunk-index-1fn8q4ps.js → chunk-index-12zyshae.js} +2 -2
- package/dist/chunk-index-18pgxxw3.js +2 -0
- package/dist/chunk-index-2e4am3hw.js +50 -0
- package/dist/{chunk-index-agrvqf5b.js → chunk-index-2fdns8tn.js} +2 -2
- package/dist/{chunk-index-84wbc80d.js → chunk-index-2t30xwed.js} +2 -2
- package/dist/{chunk-index-jq970hsd.js → chunk-index-31x6krbs.js} +3 -3
- package/dist/{chunk-index-eh0wb6g0.js → chunk-index-3d8s3565.js} +2 -2
- package/dist/chunk-index-5bfqek1d.js +2 -0
- package/dist/chunk-index-64rsz6pf.js +2 -0
- package/dist/chunk-index-6bkcq9ka.js +2 -0
- package/dist/{chunk-index-47yspxa4.js → chunk-index-8d81qy69.js} +1 -1
- package/dist/chunk-index-92zgb7my.js +2 -0
- package/dist/chunk-index-aamhjg5n.js +2 -0
- package/dist/{chunk-index-r1v895tj.js → chunk-index-ac1ktr56.js} +2 -2
- package/dist/{chunk-index-hc0dgmrs.js → chunk-index-ak6ecqy3.js} +2 -2
- package/dist/{chunk-index-eyc2rkq5.js → chunk-index-b73y2gc0.js} +2 -2
- package/dist/chunk-index-b8cpvr7y.js +2 -0
- package/dist/{chunk-index-3aa5czxj.js → chunk-index-bhqczxr3.js} +2 -2
- package/dist/{chunk-index-6c8mewwy.js → chunk-index-cbqhzf40.js} +12 -12
- package/dist/chunk-index-cdctnw71.js +2 -0
- package/dist/chunk-index-dj0tbfyb.js +2 -0
- package/dist/chunk-index-dnjftvtq.js +2 -0
- package/dist/chunk-index-e2dqjde8.js +1 -0
- package/dist/{chunk-index-tsxsy4qs.js → chunk-index-ebg48jgy.js} +2 -2
- package/dist/{chunk-index-rcxz5w5d.js → chunk-index-ek5mek4j.js} +3 -3
- package/dist/chunk-index-f6q0stqx.js +2 -0
- package/dist/{chunk-index-67p2sc14.js → chunk-index-ffbrm6tr.js} +3 -3
- package/dist/chunk-index-g1awv7rk.js +2 -0
- package/dist/chunk-index-g3wrs02w.js +1 -0
- package/dist/chunk-index-j0m16cj1.js +2 -0
- package/dist/chunk-index-j4kk1m59.js +2 -0
- package/dist/chunk-index-j4x9dq30.css +1 -0
- package/dist/{chunk-index-3wbyq10m.js → chunk-index-jgzygbt8.js} +1 -1
- package/dist/chunk-index-kb3w11mn.js +7 -0
- package/dist/{chunk-index-raf772z6.js → chunk-index-kbrg32sx.js} +2 -2
- package/dist/chunk-index-msqhgvfx.js +2 -0
- package/dist/chunk-index-pefwfm26.js +2 -0
- package/dist/chunk-index-pyfx77cj.js +2 -0
- package/dist/{chunk-index-30vw4nhh.js → chunk-index-q7g62sgm.js} +3 -3
- package/dist/chunk-index-qfgkfq86.js +2 -0
- package/dist/chunk-index-rh0x9rzf.js +2 -0
- package/dist/{chunk-index-m65cv329.js → chunk-index-sm7m4fej.js} +2 -2
- package/dist/chunk-index-sv9qpmhv.js +1 -0
- package/dist/chunk-index-t998yg8y.js +2 -0
- package/dist/{chunk-index-e90kztkx.js → chunk-index-tk4se135.js} +3 -3
- package/dist/chunk-index-v6smgw77.js +2 -0
- package/dist/chunk-index-w42rcbx1.js +2 -0
- package/dist/chunk-index-x4enmj72.js +2 -0
- package/dist/chunk-index-xq84gg8w.js +2 -0
- package/dist/{chunk-index-gt42wjby.js → chunk-index-xxeb2xp0.js} +3 -3
- package/dist/{chunk-index-hczrjnky.js → chunk-index-zyvwhxga.js} +1 -1
- package/dist/chunk-lang-css-y9133ktr.js +1 -0
- package/dist/{chunk-lang-dockerfile-tjxsnhr9.js → chunk-lang-dockerfile-cnwqn660.js} +1 -1
- package/dist/{chunk-lang-go-drmfa25k.js → chunk-lang-go-yy6kgsxv.js} +2 -2
- package/dist/chunk-lang-html-r2xmryek.js +1 -0
- package/dist/chunk-lang-javascript-1r6wd177.js +1 -0
- package/dist/{chunk-lang-json-790swysy.js → chunk-lang-json-dx56g11y.js} +1 -1
- package/dist/{chunk-lang-markdown-483dkxcq.js → chunk-lang-markdown-fpcf2dfq.js} +5 -5
- package/dist/{chunk-lang-python-v9s40bzj.js → chunk-lang-python-zzp95955.js} +2 -2
- package/dist/{chunk-lang-rust-z4gry1bf.js → chunk-lang-rust-214fh7sp.js} +1 -1
- package/dist/{chunk-lang-shell-egsvk8rj.js → chunk-lang-shell-1rpgtepw.js} +1 -1
- package/dist/{chunk-lang-sql-75j3denr.js → chunk-lang-sql-vvp46hpj.js} +2 -2
- package/dist/{chunk-lang-toml-7dbjvhex.js → chunk-lang-toml-tbj7467c.js} +1 -1
- package/dist/chunk-lang-typescript-y5w4tt4g.js +1 -0
- package/dist/{chunk-lang-xml-jg1sv4h2.js → chunk-lang-xml-tbcqmedk.js} +1 -1
- package/dist/{chunk-lang-yaml-g3v7s5je.js → chunk-lang-yaml-jh56t3sv.js} +1 -1
- package/dist/chunk-layout-actions-y73mpsh1.js +1 -0
- package/dist/chunk-menu-items-bza16bw6.js +2 -0
- package/dist/chunk-mode-toggle-nj9gnt3b.js +1 -0
- package/dist/chunk-note-row-6fmhrdng.js +75 -0
- package/dist/chunk-notes-wv0e6ssf.js +1 -0
- package/dist/{chunk-notice-bell-jehad6sx.js → chunk-notice-bell-9z27epd2.js} +1 -1
- package/dist/{chunk-notices-prqkv7ge.js → chunk-notices-fte9f196.js} +1 -1
- package/dist/chunk-onboarding-c5twahc3.js +1 -0
- package/dist/{chunk-overview-2j1s6kqg.js → chunk-overview-k4ccprax.js} +1 -1
- package/dist/{chunk-palette-4qt6ewem.js → chunk-palette-9rbp2fab.js} +1 -1
- package/dist/chunk-placement-items-me598wsb.js +1 -0
- package/dist/{chunk-profile-pfzyc04p.js → chunk-profile-s7r7fcvz.js} +1 -1
- package/dist/{chunk-prompt-history-2bcp2rky.js → chunk-prompt-history-hf296e7v.js} +1 -1
- package/dist/chunk-prompts-c8s0nhkm.js +1 -0
- package/dist/chunk-room-confirms-ga2sbvhc.js +1 -0
- package/dist/chunk-room-menu-7h4jym2b.js +1 -0
- package/dist/chunk-rooms-menu-button-pgtaanb6.js +1 -0
- package/dist/{chunk-schedules-64h9gfwn.js → chunk-schedules-mbnwcxpc.js} +1 -1
- package/dist/{chunk-seat-menu-vrpc40v9.js → chunk-seat-menu-r0k0eawr.js} +1 -1
- package/dist/chunk-sheet-hosts-a5dfevy9.js +1 -0
- package/dist/{chunk-shortcut-help-bdbkdcs9.js → chunk-shortcut-help-a6pkjcq7.js} +2 -2
- package/dist/{chunk-shortcuts-qft33r8t.js → chunk-shortcuts-cgt87jkz.js} +1 -1
- package/dist/chunk-skill-editor-67yk4x7t.js +8 -0
- package/dist/chunk-skills-rewemey4.js +1 -0
- package/dist/chunk-switcher-list-t8rbay2y.js +1 -0
- package/dist/{chunk-tab-dot-1p68ybf8.js → chunk-tab-dot-vr11dfrw.js} +1 -1
- package/dist/chunk-table-52nh0azk.js +1 -0
- package/dist/chunk-table2d-g57vr6h0.js +1 -0
- package/dist/chunk-table3d-rp0w6kt4.js +4220 -0
- package/dist/chunk-thread-actions-qcxt1y1g.js +1 -0
- package/dist/{chunk-thread-cards-t794fp4d.js → chunk-thread-cards-c2mrp2gj.js} +1 -1
- package/dist/chunk-thread-list-0071q455.js +217 -0
- package/dist/{chunk-transcript-km4e3aey.js → chunk-transcript-789yqysq.js} +1 -1
- package/dist/chunk-where-hmwmme9e.js +1 -0
- package/dist/{chunk-workspace-d064v56e.js → chunk-workspace-wr1qrtsh.js} +2 -2
- package/dist/chunk-zh-tw-z5p5mpph.js +1 -0
- package/dist/index.html +1 -1
- package/dist/sw.js +1 -1
- package/package.json +3 -3
- package/src/api-types.ts +51 -0
- package/src/app/app.ts +38 -4
- package/src/app/helper-routes.ts +106 -0
- package/src/app/rooms.ts +18 -3
- package/src/app/routes.ts +20 -0
- package/src/app/surface.ts +18 -1
- package/src/app/team-routes.ts +21 -1
- package/src/i18n/zh-tw.ts +46 -9
- package/dist/chunk-account-hck7mhf8.js +0 -1
- package/dist/chunk-action-menu-beqh40k6.js +0 -1
- package/dist/chunk-agent-znnth24t.js +0 -1
- package/dist/chunk-arranged-rooms-wfakrddk.js +0 -1
- package/dist/chunk-bulk-actions-c4tkvk9g.js +0 -1
- package/dist/chunk-character-creator-qwcsdytw.js +0 -1
- package/dist/chunk-confirm-z95j9jt3.js +0 -1
- package/dist/chunk-entry-hrt97qed.js +0 -1
- package/dist/chunk-folder-list-nemtqbnc.js +0 -1
- package/dist/chunk-folds-xpg9qcwf.js +0 -1
- package/dist/chunk-group-scene-g24kxz6f.js +0 -1
- package/dist/chunk-group-table-851jm8ef.js +0 -1
- package/dist/chunk-host-icons-23zhqpmc.js +0 -1
- package/dist/chunk-host-picture-8tnh2wam.js +0 -1
- package/dist/chunk-host-state-j41sp065.js +0 -1
- package/dist/chunk-host-ui-cje7a9t9.js +0 -1
- package/dist/chunk-index-3k7sdph2.js +0 -1
- package/dist/chunk-index-4jf4jvfd.css +0 -1
- package/dist/chunk-index-4s1qj9we.js +0 -2
- package/dist/chunk-index-5fz5e1ct.js +0 -2
- package/dist/chunk-index-azrnzgev.js +0 -2
- package/dist/chunk-index-c2ag3qw2.js +0 -2
- package/dist/chunk-index-efgm0066.js +0 -2
- package/dist/chunk-index-fe0m5mht.js +0 -2
- package/dist/chunk-index-hrtyanda.js +0 -2
- package/dist/chunk-index-j479p62w.js +0 -2
- package/dist/chunk-index-kankja6p.js +0 -50
- package/dist/chunk-index-kb44jp50.js +0 -2
- package/dist/chunk-index-mnwdbb4n.js +0 -2
- package/dist/chunk-index-n6zrc05a.js +0 -2
- package/dist/chunk-index-n93wqszt.js +0 -8
- package/dist/chunk-index-nrexxkar.js +0 -2
- package/dist/chunk-index-pgxgq61x.js +0 -2
- package/dist/chunk-index-q5vzjqr5.js +0 -2
- package/dist/chunk-index-qqwk157d.js +0 -2
- package/dist/chunk-index-r3tqhew8.js +0 -2
- package/dist/chunk-index-rg9vh59e.js +0 -1
- package/dist/chunk-index-sxq69p1f.js +0 -2
- package/dist/chunk-index-taq2psr6.js +0 -2
- package/dist/chunk-index-wc83vb0a.js +0 -2
- package/dist/chunk-index-xbs8q4kn.js +0 -2
- package/dist/chunk-index-xxbveevc.js +0 -2
- package/dist/chunk-index-zx6yka30.js +0 -2
- package/dist/chunk-lang-css-yrc25qk9.js +0 -1
- package/dist/chunk-lang-html-rwe8epvf.js +0 -1
- package/dist/chunk-lang-javascript-d6x6qjtg.js +0 -1
- package/dist/chunk-lang-typescript-1rv9vdcz.js +0 -1
- package/dist/chunk-layout-actions-6assr93n.js +0 -1
- package/dist/chunk-menu-items-9szcza00.js +0 -2
- package/dist/chunk-mode-toggle-bzbq7ycq.js +0 -1
- package/dist/chunk-note-row-g20h11pm.js +0 -75
- package/dist/chunk-notes-gc8bssxn.js +0 -1
- package/dist/chunk-onboarding-mdtc2mb7.js +0 -1
- package/dist/chunk-placement-items-2eect825.js +0 -1
- package/dist/chunk-prompts-052mb05y.js +0 -1
- package/dist/chunk-room-confirms-asvmjh5s.js +0 -1
- package/dist/chunk-room-menu-dm2r2hk6.js +0 -1
- package/dist/chunk-rooms-menu-button-32hemzxc.js +0 -1
- package/dist/chunk-sheet-hosts-jaqx490x.js +0 -1
- package/dist/chunk-skill-editor-z3dx2895.js +0 -8
- package/dist/chunk-skills-4jfcv39n.js +0 -1
- package/dist/chunk-switcher-list-xysjd4tw.js +0 -1
- package/dist/chunk-table-0v4q4dx3.js +0 -1
- package/dist/chunk-table-seats-f683hx8k.js +0 -1
- package/dist/chunk-table2d-1a6atjhj.js +0 -1
- package/dist/chunk-table3d-k0ffeffj.js +0 -4220
- package/dist/chunk-thread-actions-4rpfg4fq.js +0 -1
- package/dist/chunk-thread-list-1pcygpka.js +0 -1
- package/dist/chunk-where-phjwqggy.js +0 -1
- package/dist/chunk-zh-tw-qf18hcxc.js +0 -1
package/dist/index.html
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
<link rel="stylesheet" crossorigin href="./chunk-index-
|
|
12
|
+
<link rel="stylesheet" crossorigin href="./chunk-index-j4x9dq30.css"><script type="module" crossorigin src="./chunk-index-2e4am3hw.js"></script></head>
|
|
13
13
|
<body>
|
|
14
14
|
<div id="root"></div>
|
|
15
15
|
|
package/dist/sw.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var o=self,i=new URL(o.registration.scope);var d=new URL("index.html",i).href,h=new Set(["index.html","account-zk4efb87.css","chunk-account-
|
|
1
|
+
var o=self,i=new URL(o.registration.scope);var d=new URL("index.html",i).href,h=new Set(["index.html","account-zk4efb87.css","chunk-account-1ecx5kt7.js","chunk-action-menu-zh2n0ahf.js","chunk-agent-ynm2tcbx.js","chunk-arranged-rooms-qnz8vese.js","chunk-bulk-actions-pr0mw0kc.js","chunk-character-creator-caj4pmg4.js","chunk-confirm-g76v5d9r.js","chunk-connectors-j79ze3j1.js","chunk-conversations-2farn72g.js","chunk-council-sheet-s9sz1bzf.js","chunk-drag-45e8222r.js","chunk-entry-q11n47h9.js","chunk-folder-list-4gcj7g7h.js","chunk-folds-ten4ykfw.js","chunk-gate-kcv1a4t0.js","chunk-group-scene-12ghcvzd.js","chunk-group-table-t458kdgn.js","chunk-host-icons-h1k9k96a.js","chunk-host-picture-3p0wzn3v.js","chunk-host-state-7mdve7cb.js","chunk-host-ui-bdgwa6sf.js","chunk-index-02vfshtt.js","chunk-index-0a81da8z.js","chunk-index-0q15ysrb.js","chunk-index-0w4bfjb5.js","chunk-index-12zyshae.js","chunk-index-18pgxxw3.js","chunk-index-2e4am3hw.js","chunk-index-2fdns8tn.js","chunk-index-2t30xwed.js","chunk-index-31x6krbs.js","chunk-index-3d8s3565.js","chunk-index-5bfqek1d.js","chunk-index-64rsz6pf.js","chunk-index-6bkcq9ka.js","chunk-index-8d81qy69.js","chunk-index-92zgb7my.js","chunk-index-aamhjg5n.js","chunk-index-ac1ktr56.js","chunk-index-ak6ecqy3.js","chunk-index-b73y2gc0.js","chunk-index-b8cpvr7y.js","chunk-index-bhqczxr3.js","chunk-index-cdctnw71.js","chunk-index-dj0tbfyb.js","chunk-index-dnjftvtq.js","chunk-index-e2dqjde8.js","chunk-index-ebg48jgy.js","chunk-index-ek5mek4j.js","chunk-index-f6q0stqx.js","chunk-index-ffbrm6tr.js","chunk-index-g1awv7rk.js","chunk-index-g3wrs02w.js","chunk-index-j0m16cj1.js","chunk-index-j4kk1m59.js","chunk-index-j4x9dq30.css","chunk-index-jgzygbt8.js","chunk-index-kb3w11mn.js","chunk-index-kbrg32sx.js","chunk-index-msqhgvfx.js","chunk-index-pefwfm26.js","chunk-index-pyfx77cj.js","chunk-index-q7g62sgm.js","chunk-index-qfgkfq86.js","chunk-index-rh0x9rzf.js","chunk-index-sm7m4fej.js","chunk-index-sv9qpmhv.js","chunk-index-t998yg8y.js","chunk-index-tk4se135.js","chunk-index-v6smgw77.js","chunk-index-w42rcbx1.js","chunk-index-x4enmj72.js","chunk-index-xq84gg8w.js","chunk-index-xxeb2xp0.js","chunk-index-zyvwhxga.js","chunk-layout-actions-y73mpsh1.js","chunk-menu-items-bza16bw6.js","chunk-mode-toggle-nj9gnt3b.js","chunk-note-row-6fmhrdng.js","chunk-notes-wv0e6ssf.js","chunk-notice-bell-9z27epd2.js","chunk-notices-fte9f196.js","chunk-onboarding-c5twahc3.js","chunk-overview-k4ccprax.js","chunk-palette-9rbp2fab.js","chunk-placement-items-me598wsb.js","chunk-profile-s7r7fcvz.js","chunk-prompt-history-hf296e7v.js","chunk-prompts-c8s0nhkm.js","chunk-room-confirms-ga2sbvhc.js","chunk-room-menu-7h4jym2b.js","chunk-rooms-menu-button-pgtaanb6.js","chunk-schedules-mbnwcxpc.js","chunk-seat-menu-r0k0eawr.js","chunk-sheet-hosts-a5dfevy9.js","chunk-shortcut-help-a6pkjcq7.js","chunk-shortcuts-cgt87jkz.js","chunk-skill-editor-67yk4x7t.js","chunk-skills-rewemey4.js","chunk-switcher-list-t8rbay2y.js","chunk-tab-dot-vr11dfrw.js","chunk-table-52nh0azk.js","chunk-table2d-g57vr6h0.js","chunk-thread-actions-qcxt1y1g.js","chunk-thread-cards-c2mrp2gj.js","chunk-thread-list-0071q455.js","chunk-transcript-789yqysq.js","chunk-where-hmwmme9e.js","chunk-workspace-wr1qrtsh.js","chunk-zh-tw-z5p5mpph.js"].map((e)=>new URL(e,i).href)),w=/\/chunk-table3d-[a-z0-9]+\.js$/,g=/\/chunk-(?:codeeditor|lang-[a-z]+)-[a-z0-9]+\.js$/,k=["api/","auth/","login","files/","avatars/"],m=(e)=>{let n=e.pathname.slice(i.pathname.length);return k.some((t)=>n.startsWith(t))};async function v(e){let n=await caches.open("roundtable-web-7a28cdb79a14");try{let t=await fetch(e);if(t.ok&&new URL(e.url).href===i.href)await n.put(d,t.clone());return t}catch{let t=await n.match(d);if(t)return t;throw Error("offline and the shell is not cached")}}async function W(e){let n=await caches.open("roundtable-web-7a28cdb79a14"),t=await n.match(e);if(t)return t;let a=await fetch(e);if(a.ok)await n.put(e,a.clone());return a}var r=(e,n)=>typeof e==="string"&&e?e.slice(0,n):void 0;function l(e){if(typeof e!=="string")return i.href;let n=URL.parse(e,i);return n&&n.origin===i.origin&&n.pathname.startsWith(i.pathname)?n.href:i.href}var E=new Set(["notice","test"]);async function u(e,n){if(!e?.tag||!e.kind||!E.has(e.kind))return;try{await fetch(new URL("api/push/receipts",i),{method:"POST",credentials:"include",headers:{"content-type":"application/json"},body:JSON.stringify({tag:e.tag,event:n})})}catch{}}async function y(e){if(typeof e!=="number"||!Number.isSafeInteger(e)||e<0)return;try{if(e>0)await o.navigator.setAppBadge?.(e);else await o.navigator.clearAppBadge?.()}catch{}}async function P(e){let n={};try{let s=e.data?.json();if(typeof s==="object"&&s!==null)n=s}catch{}let t=r(n.tag,200),a=r(n.kind,16);if(await y(n.badge),a==="clear"){if(t)for(let s of await o.registration.getNotifications({tag:t}))s.close();return}await o.registration.showNotification(r(n.title,120)??"Roundtable",{body:r(n.body,240),icon:new URL("icons/192.png",i).href,badge:new URL("icons/badge-96.png",i).href,...t?{tag:t,renotify:!0}:{},...n.urgency==="high"?{requireInteraction:!0}:{},data:{url:l(n.url),...t?{tag:t}:{},...a?{kind:a}:{}}}),await u({...t?{tag:t}:{},...a?{kind:a}:{}},"received")}async function b(e){e.notification.close();let n=e.notification.data,t=l(n?.url),a=r(n?.tag,200),s=r(n?.kind,16),f=u({...a?{tag:a}:{},...s?{kind:s}:{}},"opened"),c=(await o.clients.matchAll({type:"window",includeUncontrolled:!0})).find((p)=>p.url.startsWith(i.href));if(c)await c.focus(),c.postMessage({type:"roundtable:open",url:t});else await o.clients.openWindow(t);await f}o.addEventListener("install",(e)=>{e.waitUntil(caches.open("roundtable-web-7a28cdb79a14").then((n)=>n.addAll([...h])).then(()=>o.skipWaiting()))});o.addEventListener("activate",(e)=>{e.waitUntil(caches.keys().then((n)=>Promise.all(n.filter((t)=>t.startsWith("roundtable-web-")&&t!=="roundtable-web-7a28cdb79a14").map((t)=>caches.delete(t)))).then(()=>o.clients.claim()))});o.addEventListener("fetch",(e)=>{let{request:n}=e;if(n.method!=="GET")return;let t=new URL(n.url);if(t.origin!==i.origin||!t.pathname.startsWith(i.pathname))return;if(m(t))return;if(n.mode==="navigate")e.respondWith(v(n));else if(h.has(t.origin+t.pathname)||w.test(t.pathname)||g.test(t.pathname))e.respondWith(W(n))});o.addEventListener("push",(e)=>{e.waitUntil(P(e))});o.addEventListener("notificationclick",(e)=>{e.waitUntil(b(e))});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-roundtable-web",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.27.0",
|
|
4
4
|
"description": "A web console for the owners of a pi-roundtable host: conversations, transcripts, and memory notes, with live updates",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"jose": "6.2.12"
|
|
44
44
|
},
|
|
45
45
|
"peerDependencies": {
|
|
46
|
-
"pi-roundtable": ">=0.
|
|
46
|
+
"pi-roundtable": ">=0.27.0 <0.28.0"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"@biomejs/biome": "2.5.15",
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
"@types/react": "19.3.0",
|
|
71
71
|
"@types/react-dom": "19.3.0",
|
|
72
72
|
"@types/three": "0.186.0",
|
|
73
|
-
"pi-roundtable": "0.
|
|
73
|
+
"pi-roundtable": "0.27.0",
|
|
74
74
|
"react": "19.3.0",
|
|
75
75
|
"react-dom": "19.3.0",
|
|
76
76
|
"react-markdown": "10.1.0",
|
package/src/api-types.ts
CHANGED
|
@@ -507,6 +507,11 @@ export interface RoomView {
|
|
|
507
507
|
members?: string[];
|
|
508
508
|
/** A thread's parent room. */
|
|
509
509
|
parent?: string;
|
|
510
|
+
/**
|
|
511
|
+
* A temp knight's room: `parent` is the room of the knight that made it, and `finished` is set
|
|
512
|
+
* when it has nothing running, queued or waiting. Absent on every permanent knight.
|
|
513
|
+
*/
|
|
514
|
+
helper?: { parent: string; parentName: string; finished?: true };
|
|
510
515
|
/** A thread's room takes no messages from the page. */
|
|
511
516
|
readOnly: boolean;
|
|
512
517
|
/**
|
|
@@ -528,6 +533,8 @@ export interface RoomView {
|
|
|
528
533
|
agent?: string;
|
|
529
534
|
/** A turn runs that Stop would end. */
|
|
530
535
|
stoppable: boolean;
|
|
536
|
+
/** A group room: the round running now, who has spoken and who is next; absent when none runs. */
|
|
537
|
+
round?: RoundView;
|
|
531
538
|
/** The newest stored message, if any. */
|
|
532
539
|
last?: RoomMessage;
|
|
533
540
|
/** Messages past this person's read cursor; absent when none. */
|
|
@@ -578,6 +585,22 @@ export interface ThreadsDismissedAll extends ThreadsDismissed {
|
|
|
578
585
|
threads: Record<string, string[]>;
|
|
579
586
|
}
|
|
580
587
|
|
|
588
|
+
/**
|
|
589
|
+
* What a system line of a room starts with when its knight cleared its temp knights: the rest is a
|
|
590
|
+
* JSON list of `{ name, displayName }`, which the page words and offers the undo of.
|
|
591
|
+
*/
|
|
592
|
+
export const HELPERS_ENDED = "Temp knights archived: ";
|
|
593
|
+
|
|
594
|
+
/** `POST api/rooms/archive-finished-helpers`: the temp knights archived, by the room of the knight that made them. */
|
|
595
|
+
export interface HelpersArchived {
|
|
596
|
+
archived: { room: string; names: string[] }[];
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
/** `POST api/rooms/restore-helpers`: the temp knights that came back; a name no longer archived is passed over. */
|
|
600
|
+
export interface HelpersRestored {
|
|
601
|
+
restored: string[];
|
|
602
|
+
}
|
|
603
|
+
|
|
581
604
|
/** A cursor that marking rooms read moved: where it was (0 for a room never read) and where it is. */
|
|
582
605
|
export interface ReadMove {
|
|
583
606
|
room: string;
|
|
@@ -783,6 +806,8 @@ export interface AgentProfileView {
|
|
|
783
806
|
avatar: string;
|
|
784
807
|
character: CharacterSpec;
|
|
785
808
|
room: string;
|
|
809
|
+
/** A temp knight's profile: the room of the knight that made it, and its name. */
|
|
810
|
+
helper?: { parent: string; parentName: string };
|
|
786
811
|
}
|
|
787
812
|
|
|
788
813
|
export interface ModelsView {
|
|
@@ -977,6 +1002,8 @@ export interface ArchivedEntry {
|
|
|
977
1002
|
character?: CharacterSpec;
|
|
978
1003
|
/** A group's members that are still on the team. */
|
|
979
1004
|
members?: string[];
|
|
1005
|
+
/** A temp knight's parent, by name; the archive page groups it under that knight. */
|
|
1006
|
+
parent?: string;
|
|
980
1007
|
}
|
|
981
1008
|
|
|
982
1009
|
/** `GET api/archive`. */
|
|
@@ -1181,6 +1208,28 @@ export type ClientFrame =
|
|
|
1181
1208
|
| { type: "cancel"; prompt: string };
|
|
1182
1209
|
|
|
1183
1210
|
/** What the server sends: one JSON object per WebSocket text message. */
|
|
1211
|
+
/**
|
|
1212
|
+
* Where a group's round stands: the members' answers to one owner message, one after another.
|
|
1213
|
+
* `id` is the group message that opened the round, so a new round is told from the last one.
|
|
1214
|
+
*/
|
|
1215
|
+
export interface RoundView {
|
|
1216
|
+
id: number;
|
|
1217
|
+
state: "running" | "ended";
|
|
1218
|
+
/** The member speaking now, by name. */
|
|
1219
|
+
current?: string;
|
|
1220
|
+
/** The members still to speak, in order, a handoff appended. */
|
|
1221
|
+
next: string[];
|
|
1222
|
+
/** The members who have replied so far, in order. */
|
|
1223
|
+
spoken: string[];
|
|
1224
|
+
/** The replies made so far, and the most a round holds. */
|
|
1225
|
+
replies: number;
|
|
1226
|
+
limit: number;
|
|
1227
|
+
/** Why the round ended: every member spoke, it reached its limit, or the owner stopped it. */
|
|
1228
|
+
ended?: "done" | "limit" | "stopped";
|
|
1229
|
+
/** The owner's messages waiting in the room for the next round. */
|
|
1230
|
+
queued?: number;
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1184
1233
|
export type ServerFrame =
|
|
1185
1234
|
/** The socket is authenticated; sent first, and followed by every open card. */
|
|
1186
1235
|
| {
|
|
@@ -1215,6 +1264,8 @@ export type ServerFrame =
|
|
|
1215
1264
|
/** Only on the frame where `typing` turns false. */
|
|
1216
1265
|
outcome?: "done" | "failed";
|
|
1217
1266
|
}
|
|
1267
|
+
/** Where a group room's round stands; sent at each step and when it ends. */
|
|
1268
|
+
| { type: "round"; room: string; round: RoundView }
|
|
1218
1269
|
/** Which agents work now, anywhere (Discord included); sent after `ready` and when it changes. */
|
|
1219
1270
|
| { type: "presence"; agents: Record<string, { busy: boolean }> }
|
|
1220
1271
|
| { type: "prompt"; room: string; prompt: PromptFrame }
|
package/src/app/app.ts
CHANGED
|
@@ -13,8 +13,8 @@ import type {
|
|
|
13
13
|
ScheduleStore,
|
|
14
14
|
WebSocketRoute,
|
|
15
15
|
} from "pi-roundtable";
|
|
16
|
-
import { channelKey } from "pi-roundtable";
|
|
17
|
-
import { APP_CLOSE_EXPIRED } from "../api-types.ts";
|
|
16
|
+
import { agentRoomKey, channelKey, isHelper, roomOf } from "pi-roundtable";
|
|
17
|
+
import { APP_CLOSE_EXPIRED, HELPERS_ENDED } from "../api-types.ts";
|
|
18
18
|
import type { Authenticated, Authenticator } from "../auth/authenticator.ts";
|
|
19
19
|
import type { ConsolePresentation } from "../features.ts";
|
|
20
20
|
import type { Gate } from "../gate.ts";
|
|
@@ -209,6 +209,11 @@ export class OwnerApp {
|
|
|
209
209
|
const quiet = quietClock
|
|
210
210
|
? (at: number) => quietClock.quietAt(at)
|
|
211
211
|
: undefined;
|
|
212
|
+
const held = roomMuted(
|
|
213
|
+
mutes,
|
|
214
|
+
threads,
|
|
215
|
+
channelKey(options.surface, "thread."),
|
|
216
|
+
);
|
|
212
217
|
const mounted = mountNotices({
|
|
213
218
|
database: options.database,
|
|
214
219
|
logger,
|
|
@@ -246,7 +251,16 @@ export class OwnerApp {
|
|
|
246
251
|
visible: (principalId) => sockets.anyVisible(principalId),
|
|
247
252
|
preview: options.push.preview,
|
|
248
253
|
...(quiet ? { quiet } : {}),
|
|
249
|
-
muted:
|
|
254
|
+
muted: async (room) => {
|
|
255
|
+
const named = roomOf(room as ChannelKey, [options.surface]);
|
|
256
|
+
// A temp knight's answers reach its knight's room, which pushes; its own room stays quiet.
|
|
257
|
+
if (
|
|
258
|
+
named?.kind === "agent" &&
|
|
259
|
+
isHelper(agents.directory.agent(named.name))
|
|
260
|
+
)
|
|
261
|
+
return true;
|
|
262
|
+
return held(room);
|
|
263
|
+
},
|
|
250
264
|
urlOf: options.push.urlOf,
|
|
251
265
|
logger,
|
|
252
266
|
});
|
|
@@ -334,7 +348,10 @@ export class OwnerApp {
|
|
|
334
348
|
log,
|
|
335
349
|
modes,
|
|
336
350
|
mutes,
|
|
337
|
-
activity: (room) =>
|
|
351
|
+
activity: (room) => {
|
|
352
|
+
const round = surface.roundOf(room);
|
|
353
|
+
return { ...surface.activityOf(room), ...(round ? { round } : {}) };
|
|
354
|
+
},
|
|
338
355
|
// The agent rooms are the owners'; where there are several, they can leave each other notes.
|
|
339
356
|
readers: async () => (await identity.owners()).length > 1,
|
|
340
357
|
});
|
|
@@ -398,6 +415,23 @@ export class OwnerApp {
|
|
|
398
415
|
},
|
|
399
416
|
push,
|
|
400
417
|
});
|
|
418
|
+
// A knight clearing its own temp knights leaves a line in its room, with the undo.
|
|
419
|
+
agents.team.onHelpersEnded((event) => {
|
|
420
|
+
const named = event.names.map((name) => ({
|
|
421
|
+
name,
|
|
422
|
+
displayName: agents.directory.agent(name)?.displayName ?? name,
|
|
423
|
+
}));
|
|
424
|
+
void surface
|
|
425
|
+
.publish({
|
|
426
|
+
room: agentRoomKey(options.surface, event.parent),
|
|
427
|
+
kind: "system",
|
|
428
|
+
author: "Notice",
|
|
429
|
+
text: `${HELPERS_ENDED}${JSON.stringify(named)}`,
|
|
430
|
+
})
|
|
431
|
+
.catch((error) =>
|
|
432
|
+
logger.warn({ err: error }, "the temp knights' line was not posted"),
|
|
433
|
+
);
|
|
434
|
+
});
|
|
401
435
|
this.#api = new AppApi({
|
|
402
436
|
...(options.presentation ? { presentation: options.presentation } : {}),
|
|
403
437
|
surface,
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AgentDirectory,
|
|
3
|
+
AgentTeam,
|
|
4
|
+
ChannelKey,
|
|
5
|
+
Speaker,
|
|
6
|
+
} from "pi-roundtable";
|
|
7
|
+
import { agentRoomKey, isHelper, roomOf } from "pi-roundtable";
|
|
8
|
+
import type { HelpersArchived, HelpersRestored } from "../api-types.ts";
|
|
9
|
+
import { json } from "../http.ts";
|
|
10
|
+
import { bad, bodyOf } from "./api-http.ts";
|
|
11
|
+
|
|
12
|
+
/** The most rooms or names one request of these routes names. */
|
|
13
|
+
const MAX_NAMED = 500;
|
|
14
|
+
|
|
15
|
+
export interface HelperRoutesOptions {
|
|
16
|
+
surface: string;
|
|
17
|
+
directory: Pick<AgentDirectory, "agent" | "agents">;
|
|
18
|
+
team: Pick<
|
|
19
|
+
AgentTeam,
|
|
20
|
+
"finishedHelpers" | "archiveHelpers" | "restoreHelpers"
|
|
21
|
+
>;
|
|
22
|
+
changed(): void;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** A list of at most 500 strings, or undefined when the body leaves it out. */
|
|
26
|
+
function listOf(value: unknown, field: string): string[] | undefined {
|
|
27
|
+
if (value === undefined) return undefined;
|
|
28
|
+
if (
|
|
29
|
+
!Array.isArray(value) ||
|
|
30
|
+
value.length > MAX_NAMED ||
|
|
31
|
+
!value.every((one) => typeof one === "string" && one.length <= 300)
|
|
32
|
+
)
|
|
33
|
+
throw bad(`${field} must be a list of at most ${MAX_NAMED} strings.`);
|
|
34
|
+
return value;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* The two bulk calls on temp knights, for owners: archiving the finished ones of some knights (or
|
|
39
|
+
* of every knight) and putting back the ones an archive took. They reach the same team operations
|
|
40
|
+
* as the knight's own `helper_end`.
|
|
41
|
+
*/
|
|
42
|
+
export class HelperRoutes {
|
|
43
|
+
readonly #options: HelperRoutesOptions;
|
|
44
|
+
|
|
45
|
+
constructor(options: HelperRoutesOptions) {
|
|
46
|
+
this.#options = options;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* `POST api/rooms/archive-finished-helpers`: archives the finished temp knights of the named
|
|
51
|
+
* knights' rooms, or of every knight when none is named. Answers what it archived by room.
|
|
52
|
+
*/
|
|
53
|
+
async archiveFinished(request: Request, owner: Speaker): Promise<Response> {
|
|
54
|
+
const { surface, directory, team } = this.#options;
|
|
55
|
+
const keys = listOf((await bodyOf(request)).rooms, "rooms");
|
|
56
|
+
let parents: string[] | undefined;
|
|
57
|
+
if (keys) {
|
|
58
|
+
parents = [];
|
|
59
|
+
for (const key of new Set(keys)) {
|
|
60
|
+
const named = roomOf(key as ChannelKey, [surface]);
|
|
61
|
+
const agent =
|
|
62
|
+
named?.kind === "agent" ? directory.agent(named.name) : undefined;
|
|
63
|
+
if (!agent || isHelper(agent))
|
|
64
|
+
throw bad(`"${key}" is not the room of a knight.`);
|
|
65
|
+
parents.push(agent.name);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
const finished = team.finishedHelpers(parents);
|
|
69
|
+
const byParent = new Map<string, string[]>();
|
|
70
|
+
for (const helper of finished)
|
|
71
|
+
byParent.set(helper.parent as string, [
|
|
72
|
+
...(byParent.get(helper.parent as string) ?? []),
|
|
73
|
+
helper.name,
|
|
74
|
+
]);
|
|
75
|
+
const done = new Set(
|
|
76
|
+
await team.archiveHelpers(
|
|
77
|
+
finished.map((helper) => helper.name),
|
|
78
|
+
owner.principalId ?? owner.name,
|
|
79
|
+
),
|
|
80
|
+
);
|
|
81
|
+
const archived = [...byParent]
|
|
82
|
+
.map(([parent, names]) => ({
|
|
83
|
+
room: agentRoomKey(surface, parent),
|
|
84
|
+
names: names.filter((name) => done.has(name)),
|
|
85
|
+
}))
|
|
86
|
+
.filter((entry) => entry.names.length > 0);
|
|
87
|
+
if (archived.length > 0) this.#options.changed();
|
|
88
|
+
return json({ archived } satisfies HelpersArchived);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* `POST api/rooms/restore-helpers`: puts back archived temp knights, the undo of an archive. A
|
|
93
|
+
* name that is not a temp knight is refused by name; one no longer archived is passed over.
|
|
94
|
+
*/
|
|
95
|
+
async restore(request: Request): Promise<Response> {
|
|
96
|
+
const { directory, team } = this.#options;
|
|
97
|
+
const names = listOf((await bodyOf(request)).names, "names");
|
|
98
|
+
if (!names) throw bad("Give names, the temp knights to restore.");
|
|
99
|
+
for (const name of names)
|
|
100
|
+
if (!isHelper(directory.agent(name)))
|
|
101
|
+
throw bad(`"${name}" is not a temp knight.`);
|
|
102
|
+
const restored = await team.restoreHelpers([...new Set(names)]);
|
|
103
|
+
if (restored.length > 0) this.#options.changed();
|
|
104
|
+
return json({ restored } satisfies HelpersRestored);
|
|
105
|
+
}
|
|
106
|
+
}
|
package/src/app/rooms.ts
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
channelKey,
|
|
13
13
|
characterOf,
|
|
14
14
|
groupRoomKey,
|
|
15
|
+
isHelper,
|
|
15
16
|
roomOf,
|
|
16
17
|
} from "pi-roundtable";
|
|
17
18
|
import type { RoomKind, RoomView } from "../api-types.ts";
|
|
@@ -44,7 +45,7 @@ export interface RoomsOptions {
|
|
|
44
45
|
mutes: Pick<PushMutes, "all">;
|
|
45
46
|
activity(
|
|
46
47
|
room: ChannelKey,
|
|
47
|
-
): Pick<RoomView, "typing" | "stoppable" | "phase" | "agent">;
|
|
48
|
+
): Pick<RoomView, "typing" | "stoppable" | "phase" | "agent" | "round">;
|
|
48
49
|
/**
|
|
49
50
|
* Whether more than one person reads the agent and group rooms, so a message may be an
|
|
50
51
|
* internal note. Absent: one person does, and a room takes only turns.
|
|
@@ -127,7 +128,9 @@ export class Rooms {
|
|
|
127
128
|
const coordinator = team.coordinator();
|
|
128
129
|
const home =
|
|
129
130
|
(coordinator ? directory.agent(coordinator) : undefined) ??
|
|
130
|
-
directory
|
|
131
|
+
directory
|
|
132
|
+
.agents()
|
|
133
|
+
.find((agent) => agent.status === "active" && !isHelper(agent));
|
|
131
134
|
return home?.status === "active"
|
|
132
135
|
? agentRoomKey(surface, home.name)
|
|
133
136
|
: undefined;
|
|
@@ -144,7 +147,7 @@ export class Rooms {
|
|
|
144
147
|
[
|
|
145
148
|
...directory
|
|
146
149
|
.agents()
|
|
147
|
-
.filter((agent) => agent.status === "active")
|
|
150
|
+
.filter((agent) => agent.status === "active" && !isHelper(agent))
|
|
148
151
|
.map((agent) => agentRoomKey(surface, agent.name)),
|
|
149
152
|
...directory
|
|
150
153
|
.groups()
|
|
@@ -225,6 +228,18 @@ export class Rooms {
|
|
|
225
228
|
avatar: this.avatarOf(agent),
|
|
226
229
|
character: characterOf(agent),
|
|
227
230
|
...(agent.name === coordinator ? { coordinator: true as const } : {}),
|
|
231
|
+
...(agent.parent
|
|
232
|
+
? {
|
|
233
|
+
helper: {
|
|
234
|
+
parent: agentRoomKey(surface, agent.parent),
|
|
235
|
+
parentName:
|
|
236
|
+
directory.agent(agent.parent)?.displayName ?? agent.parent,
|
|
237
|
+
...(agent.finishedAt ? { finished: true as const } : {}),
|
|
238
|
+
},
|
|
239
|
+
// A temp knight's answers reach its knight's room, which pushes; its cards still do.
|
|
240
|
+
muted: true as const,
|
|
241
|
+
}
|
|
242
|
+
: {}),
|
|
228
243
|
}),
|
|
229
244
|
),
|
|
230
245
|
...groups.map((group: AgentGroup) =>
|
package/src/app/routes.ts
CHANGED
|
@@ -51,6 +51,7 @@ import { viewerOf, type WebAppRegistry } from "../web-app.ts";
|
|
|
51
51
|
import { bad, bodyOf, HttpError, notFound } from "./api-http.ts";
|
|
52
52
|
import type { CardLog } from "./card-log.ts";
|
|
53
53
|
import { type FileDir, fileResponse, isFileId } from "./files.ts";
|
|
54
|
+
import { HelperRoutes } from "./helper-routes.ts";
|
|
54
55
|
import type { LayoutStore } from "./layout.ts";
|
|
55
56
|
import { LayoutRoutes } from "./layout-routes.ts";
|
|
56
57
|
import { PromptApi, type PromptApiOptions } from "./prompt-routes.ts";
|
|
@@ -118,6 +119,9 @@ export interface AppApiOptions {
|
|
|
118
119
|
| "remove"
|
|
119
120
|
| "createGroup"
|
|
120
121
|
| "updateGroup"
|
|
122
|
+
| "finishedHelpers"
|
|
123
|
+
| "archiveHelpers"
|
|
124
|
+
| "restoreHelpers"
|
|
121
125
|
>;
|
|
122
126
|
/** Present when the host has the skills addon: the catalog an agent's skills are chosen from, and the change of what it carries. */
|
|
123
127
|
skills?: {
|
|
@@ -272,6 +276,7 @@ export class AppApi {
|
|
|
272
276
|
readonly #options: AppApiOptions;
|
|
273
277
|
readonly #team: TeamApi;
|
|
274
278
|
readonly #layout: LayoutRoutes;
|
|
279
|
+
readonly #helpers: HelperRoutes;
|
|
275
280
|
readonly #prompts: PromptApi | undefined;
|
|
276
281
|
readonly #skillDocs: SkillDocApi | undefined;
|
|
277
282
|
|
|
@@ -285,6 +290,12 @@ export class AppApi {
|
|
|
285
290
|
owner: (admission) => this.#owner(admission),
|
|
286
291
|
changed: () => options.changed(),
|
|
287
292
|
});
|
|
293
|
+
this.#helpers = new HelperRoutes({
|
|
294
|
+
surface: options.surface.surface,
|
|
295
|
+
directory: options.directory,
|
|
296
|
+
team: options.team,
|
|
297
|
+
changed: () => options.changed(),
|
|
298
|
+
});
|
|
288
299
|
this.#prompts = options.prompts
|
|
289
300
|
? new PromptApi({ prompts: options.prompts })
|
|
290
301
|
: undefined;
|
|
@@ -536,6 +547,15 @@ export class AppApi {
|
|
|
536
547
|
return this.#readAll(request, admission);
|
|
537
548
|
if (key === "dismiss-finished-threads" && !action && method === "POST")
|
|
538
549
|
return this.#dismissAllFinished(request, admission);
|
|
550
|
+
if (key === "archive-finished-helpers" && !action && method === "POST")
|
|
551
|
+
return this.#helpers.archiveFinished(
|
|
552
|
+
request,
|
|
553
|
+
await this.#owner(admission),
|
|
554
|
+
);
|
|
555
|
+
if (key === "restore-helpers" && !action && method === "POST") {
|
|
556
|
+
await this.#owner(admission);
|
|
557
|
+
return this.#helpers.restore(request);
|
|
558
|
+
}
|
|
539
559
|
const room = await rooms.resolve(key);
|
|
540
560
|
if (!room) throw notFound();
|
|
541
561
|
if (!action && method === "GET") {
|
package/src/app/surface.ts
CHANGED
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
roomOf,
|
|
15
15
|
type TurnProgress,
|
|
16
16
|
} from "pi-roundtable";
|
|
17
|
-
import type { RoomFile, RoomMessage } from "../api-types.ts";
|
|
17
|
+
import type { RoomFile, RoomMessage, RoundView } from "../api-types.ts";
|
|
18
18
|
import type { OwnerDesk } from "./desk.ts";
|
|
19
19
|
import { type FileBinding, type FileDir, typeByName } from "./files.ts";
|
|
20
20
|
import type { NewRoomMessage, RoomLog } from "./room-log.ts";
|
|
@@ -115,6 +115,8 @@ export class AppSurface implements ChatSurface {
|
|
|
115
115
|
readonly threads: AppSurfaceThreads;
|
|
116
116
|
readonly #options: AppSurfaceOptions;
|
|
117
117
|
readonly #activity = new Map<ChannelKey, Activity>();
|
|
118
|
+
/** The round each group room runs now; an ended round is dropped, since the page keeps what it was told. */
|
|
119
|
+
readonly #rounds = new Map<ChannelKey, RoundView>();
|
|
118
120
|
/** When a page last sent a message to each room. */
|
|
119
121
|
readonly #askedAt = new Map<ChannelKey, number>();
|
|
120
122
|
/** The turns running in each room that a page's message started. */
|
|
@@ -196,6 +198,21 @@ export class AppSurface implements ChatSurface {
|
|
|
196
198
|
};
|
|
197
199
|
}
|
|
198
200
|
|
|
201
|
+
/** Where the group room's running round stands, for a page that opens mid-round. */
|
|
202
|
+
roundOf(room: ChannelKey): RoundView | undefined {
|
|
203
|
+
return this.#rounds.get(room);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/** Shows a group round's step to the sockets that may have the room. */
|
|
207
|
+
groupRound(channel: ChannelKey, round: RoundView): void {
|
|
208
|
+
if (round.state === "ended") this.#rounds.delete(channel);
|
|
209
|
+
else this.#rounds.set(channel, round);
|
|
210
|
+
this.#options.sockets.deliver(
|
|
211
|
+
{ type: "round", room: channel, round },
|
|
212
|
+
this.#options.audienceOf(channel),
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
|
|
199
216
|
/** The agents with a turn working in an app room now: a room's own agent, or a group's speaker. */
|
|
200
217
|
workingAgents(): Set<string> {
|
|
201
218
|
const names = new Set<string>();
|
package/src/app/team-routes.ts
CHANGED
|
@@ -133,7 +133,17 @@ export class TeamApi {
|
|
|
133
133
|
// The app's part runs inside the delete, after its checks and before the row goes: a
|
|
134
134
|
// cleanup that fails leaves the agent there to delete again.
|
|
135
135
|
const room = agentRoomKey(this.#options.surface, name);
|
|
136
|
-
await this.#options.team.remove(name, () =>
|
|
136
|
+
await this.#options.team.remove(name, async () => {
|
|
137
|
+
// Its archived temp knights go with it, and so does what the app kept of their rooms.
|
|
138
|
+
for (const helper of this.#options.directory
|
|
139
|
+
.agents()
|
|
140
|
+
.filter((one) => one.parent === name))
|
|
141
|
+
await this.#forget(
|
|
142
|
+
agentRoomKey(this.#options.surface, helper.name),
|
|
143
|
+
by,
|
|
144
|
+
);
|
|
145
|
+
await this.#forget(room, by);
|
|
146
|
+
});
|
|
137
147
|
this.#options.changed();
|
|
138
148
|
return json({ ok: true });
|
|
139
149
|
}
|
|
@@ -311,6 +321,15 @@ export class TeamApi {
|
|
|
311
321
|
avatar: rooms.avatarOf(agent),
|
|
312
322
|
character: characterOf(agent),
|
|
313
323
|
room: agentRoomKey(surface, agent.name),
|
|
324
|
+
...(agent.parent
|
|
325
|
+
? {
|
|
326
|
+
helper: {
|
|
327
|
+
parent: agentRoomKey(surface, agent.parent),
|
|
328
|
+
parentName:
|
|
329
|
+
directory.agent(agent.parent)?.displayName ?? agent.parent,
|
|
330
|
+
},
|
|
331
|
+
}
|
|
332
|
+
: {}),
|
|
314
333
|
};
|
|
315
334
|
}
|
|
316
335
|
|
|
@@ -412,6 +431,7 @@ export class TeamApi {
|
|
|
412
431
|
displayName: agent.displayName,
|
|
413
432
|
avatar: rooms.avatarOf(agent),
|
|
414
433
|
character: characterOf(agent),
|
|
434
|
+
...(agent.parent ? { parent: agent.parent } : {}),
|
|
415
435
|
}),
|
|
416
436
|
),
|
|
417
437
|
...directory
|
package/src/i18n/zh-tw.ts
CHANGED
|
@@ -282,16 +282,38 @@ export const ZH_TW: Readonly<Record<string, string>> = {
|
|
|
282
282
|
"Reply to the knight that started this thread.": "回覆開啟這個討論串的騎士。",
|
|
283
283
|
"Yolo mode": "Yolo 模式",
|
|
284
284
|
"No knights are seated yet.": "圓桌上還沒有騎士入座。",
|
|
285
|
-
"Who's at the table": "誰上桌",
|
|
286
|
-
"Off the table": "離席中",
|
|
287
|
-
"Leave the table": "離席",
|
|
288
|
-
"{name} left the table": "{name}已離席",
|
|
289
285
|
"The table is empty": "圓桌空了",
|
|
290
286
|
"There are no rooms to seat yet.": "還沒有可以入座的聊天室。",
|
|
291
|
-
"
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
287
|
+
"All rooms": "所有聊天室",
|
|
288
|
+
"Council: {name} ▾": "評議會:{name} ▾",
|
|
289
|
+
Council: "評議會",
|
|
290
|
+
Councils: "評議會",
|
|
291
|
+
"{count} knights": "{count} 位騎士",
|
|
292
|
+
"Pick who sits": "選誰上桌",
|
|
293
|
+
"No council yet": "還沒有評議會",
|
|
294
|
+
"The council is empty": "評議會沒有人了",
|
|
295
|
+
"Every member of this council is gone. Edit who sits.":
|
|
296
|
+
"這個評議會的成員都不在了。請重新選誰上桌。",
|
|
297
|
+
"A council is a group of up to {max} knights who answer in turn. Pick who sits.":
|
|
298
|
+
"評議會是最多 {max} 位騎士組成的群組,他們輪流發言。請選誰上桌。",
|
|
299
|
+
"Edit this council": "編輯這個評議會",
|
|
300
|
+
"{count} of {max} picked": "已選 {count}/{max}",
|
|
301
|
+
"At most {max} knights": "最多 {max} 位",
|
|
302
|
+
"A council needs at least {min} knights.": "評議會至少要有 {min} 位騎士。",
|
|
303
|
+
"Council name": "評議會名稱",
|
|
304
|
+
"Save as a new council": "另存為新評議會",
|
|
305
|
+
"Make council": "建立評議會",
|
|
306
|
+
"Private chat": "私下對話",
|
|
307
|
+
"Remove from the council": "移出評議會",
|
|
308
|
+
"{name} left the council": "{name}已移出評議會",
|
|
309
|
+
"Speaking order": "發言順序",
|
|
310
|
+
"has spoken": "已發言",
|
|
311
|
+
"Reply {n} of {limit}": "第 {n}/{limit} 則",
|
|
312
|
+
"{count} of {limit} replies": "{count}/{limit} 則回覆",
|
|
313
|
+
"Limit reached": "已達上限",
|
|
314
|
+
"Round stopped": "本輪已停止",
|
|
315
|
+
"Stop the round": "停止本輪",
|
|
316
|
+
"Your message waits for the next round": "你的訊息排在下一輪",
|
|
295
317
|
|
|
296
318
|
// 通知
|
|
297
319
|
"A file is no longer available. Attach it again.":
|
|
@@ -542,7 +564,7 @@ export const ZH_TW: Readonly<Record<string, string>> = {
|
|
|
542
564
|
"Edit group": "編輯群組",
|
|
543
565
|
"Name, members and host": "名稱、成員與主持人",
|
|
544
566
|
Members: "成員",
|
|
545
|
-
"Pick 2 to
|
|
567
|
+
"Pick 2 to 8 knights. They take turns in the order picked.":
|
|
546
568
|
"選 2 到 6 位騎士。他們依選取的順序輪流發言。",
|
|
547
569
|
Host: "主持人",
|
|
548
570
|
"It stops answering. The history is kept and it can be restored.":
|
|
@@ -598,6 +620,20 @@ export const ZH_TW: Readonly<Record<string, string>> = {
|
|
|
598
620
|
"Clear finished": "清除已完成",
|
|
599
621
|
Finished: "已完成",
|
|
600
622
|
"In progress": "進行中",
|
|
623
|
+
Ended: "已結束",
|
|
624
|
+
"Temp knight": "臨時騎士",
|
|
625
|
+
"{count} temp knight": "{count} 位臨時騎士",
|
|
626
|
+
"{count} temp knights": "{count} 位臨時騎士",
|
|
627
|
+
"Made by {name}": "隸屬 {name}",
|
|
628
|
+
"Temp knight of {name}": "{name} 的臨時騎士",
|
|
629
|
+
"Clear finished temp knights": "清除已結束的臨時騎士",
|
|
630
|
+
"Archived {count} temp knight": "已封存 {count} 位臨時騎士",
|
|
631
|
+
"Archived {count} temp knights": "已封存 {count} 位臨時騎士",
|
|
632
|
+
"Archive this temp knight": "封存這位臨時騎士",
|
|
633
|
+
"{name} archived {count} temp knight: {names}":
|
|
634
|
+
"{name}封存了 {count} 位臨時騎士:{names}",
|
|
635
|
+
"{name} archived {count} temp knights: {names}":
|
|
636
|
+
"{name}封存了 {count} 位臨時騎士:{names}",
|
|
601
637
|
"More actions for {name}": "{name} 的更多動作",
|
|
602
638
|
"Cleared “{name}”": "已清除「{name}」",
|
|
603
639
|
"Cleared {count} finished thread": "已清除 {count} 個已完成的討論串",
|
|
@@ -605,6 +641,7 @@ export const ZH_TW: Readonly<Record<string, string>> = {
|
|
|
605
641
|
"The thread is still open.": "這個討論串還在進行中。",
|
|
606
642
|
"threads must be a list of at most 100 keys.":
|
|
607
643
|
"threads 必須是最多 100 個鍵的清單。",
|
|
644
|
+
"Give names, the temp knights to restore.": "請提供要復原的臨時騎士名稱。",
|
|
608
645
|
"rooms must be a list of at most 500 keys.":
|
|
609
646
|
"rooms 必須是最多 500 個鍵的清單。",
|
|
610
647
|
"restore must be a list of at most 500 moves.":
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{h,Q,S,e,w}from"./chunk-index-kankja6p.js";var a={profile:S(()=>(h("pfzyc04p"),import("./chunk-profile-pfzyc04p.js")).then((o)=>({default:o.ProfilePage}))),notices:S(()=>(h("prqkv7ge"),import("./chunk-notices-prqkv7ge.js")).then((o)=>({default:o.NoticesPage}))),onboarding:S(()=>(h("mdtc2mb7"),import("./chunk-onboarding-mdtc2mb7.js")).then((o)=>({default:o.OnboardingPage})))};function n({pane:o}){let t=a[o];return t?e(Q,{fallback:e(w,{}),children:e(t,{})}):null}export{n as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{s,Fe,a,r,g,e,n,o,kt,zo}from"./chunk-index-kankja6p.js";import{L}from"./chunk-index-47yspxa4.js";var k=()=>typeof matchMedia==="function"&&matchMedia("(max-width: 719px)").matches,x={rtMenu:!0},H=()=>Boolean(window.history.state?.rtMenu),w=8,M=(t)=>t?.isConnected?t:null;function y(t){return t.items.map((u)=>n("button",{type:"button",role:u.checked===void 0?"menuitem":"menuitemcheckbox",...u.checked===void 0?{}:{"aria-checked":u.checked},className:"menu-item menu-link","data-tone":u.tone,onClick:()=>t.onChoose(u),children:[u.icon?e("span",{className:"menu-icon","data-tone":u.tone,children:e(o,{name:u.icon,size:18})}):null,e("span",{className:"menu-text",children:e("strong",{children:u.label})}),u.checked?e(o,{name:"check",size:18,className:"menu-check"}):null]},u.id))}function T({menu:t}){let u=a(void 0);if(t)u.current=t;let c=u.current,m=a(!1),p=a(void 0),h=t?.serial;return s(()=>{if(h===void 0)return;return window.history.pushState(x,"",window.location.href),m.current=!0,()=>{if(m.current)m.current=!1,window.history.back()}},[h]),s(()=>{let f=()=>{if(!m.current||H())return;m.current=!1,kt();let E=p.current;p.current=void 0,E?.()};return window.addEventListener("popstate",f),()=>window.removeEventListener("popstate",f)},[]),e(L,{open:t!==void 0,title:c?.title??"",onClose:kt,restoreFocus:()=>M(c?.source??null),children:c?e("div",{className:"menu action-items",role:"menu","aria-label":c.title,children:e(y,{items:c.items,onChoose:(f)=>{if(!m.current){kt(),f.run();return}p.current=f.run,window.history.back()}})}):null})}function C({menu:t}){let u=a(null),[c,m]=r(t.at),{source:p}=t,h=(i)=>{M(p)?.focus(),kt(),i?.()},f=a(h);f.current=h,Fe(()=>{let i=u.current;if(!i)return;let d=i.getBoundingClientRect();m({x:Math.max(w,Math.min(t.at.x,window.innerWidth-d.width-w)),y:Math.max(w,Math.min(t.at.y,window.innerHeight-d.height-w))}),i.querySelector('[role^="menuitem"]')?.focus()},[t.serial]),s(()=>{let i=(l)=>{if(l.target instanceof Node&&u.current?.contains(l.target))return;kt()},d=()=>kt();return document.addEventListener("pointerdown",i,!0),document.addEventListener("wheel",i,{capture:!0,passive:!0}),document.addEventListener("touchmove",i,{capture:!0,passive:!0}),window.addEventListener("resize",d),()=>{document.removeEventListener("pointerdown",i,!0),document.removeEventListener("wheel",i,!0),document.removeEventListener("touchmove",i,!0),window.removeEventListener("resize",d)}},[]);let E=(i)=>{let d=[...u.current?.querySelectorAll('[role^="menuitem"]')??[]],l=d.indexOf(document.activeElement),v=(b)=>{i.preventDefault(),d[(b+d.length)%d.length]?.focus()};switch(i.key){case"Escape":i.preventDefault(),i.stopPropagation(),f.current();return;case"ArrowDown":return v(l+1);case"ArrowUp":return v(l<0?-1:l-1);case"Tab":return v(i.shiftKey?l<0?-1:l-1:l+1);case"Home":return v(0);case"End":return v(-1)}};return e("div",{ref:u,className:"action-popover",role:"menu","aria-label":t.title,tabIndex:-1,style:{left:`${c.x}px`,top:`${c.y}px`},onKeyDown:E,children:e(y,{items:t.items,onChoose:(i)=>h(i.run)})})}function O(){let t=zo(),u=a(void 0);if(t&&u.current?.serial!==t.serial)u.current={serial:t.serial,sheet:k()};let c=Boolean(t&&u.current?.sheet);return n(g,{children:[e(T,{menu:c?t:void 0}),t&&!c?e(C,{menu:t},t.serial):null]})}export{O as ActionMenuHost};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{s,e,F,d,w,tt}from"./chunk-index-kankja6p.js";function g({name:o}){let i=d((t)=>t.listed),r=d((t)=>Object.values(t.rooms).find((m)=>m.view?.kind==="agent"&&m.view.name===o)?.view?.key,o);return s(()=>{if(r)F("room",r,{replace:!0}),tt(o);else if(i)F("rooms",void 0,{replace:!0})},[r,i,o]),e("div",{className:"page",children:e(w,{})})}export{g as AgentPage};
|