pi-roundtable-web 0.23.1 → 0.24.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 +61 -0
- package/README.md +90 -16
- package/dist/chunk-action-menu-7v5fce2v.js +1 -0
- package/dist/chunk-agent-2rw4ydw2.js +1 -0
- package/dist/chunk-agent-sheet-2q24dkkf.js +3 -0
- package/dist/chunk-character-creator-8q6ympxj.js +1 -0
- package/dist/chunk-codeeditor-fgmq298t.js +2 -0
- package/dist/chunk-connectors-mr53r7fh.js +1 -0
- package/dist/chunk-conversations-4vy2z6w9.js +1 -0
- package/dist/chunk-entry-jg1eem82.js +1 -0
- package/dist/chunk-group-scene-na95b1te.js +1 -0
- package/dist/chunk-index-11rjg8a8.js +1 -0
- package/dist/chunk-index-1y50d6sj.js +2 -0
- package/dist/chunk-index-5y2r0eaj.js +47 -0
- package/dist/chunk-index-6t68gbex.js +2 -0
- package/dist/chunk-index-7fphxxzd.js +14 -0
- package/dist/chunk-index-80f1zkp6.css +1 -0
- package/dist/chunk-index-87h45frg.js +2 -0
- package/dist/chunk-index-bnwmssyn.js +2 -0
- package/dist/chunk-index-ckgbszwt.js +51 -0
- package/dist/chunk-index-fmjjekhd.js +2 -0
- package/dist/chunk-index-mpm90318.js +2 -0
- package/dist/chunk-index-t1m65yn6.js +13 -0
- package/dist/chunk-index-t711t17m.js +2 -0
- package/dist/chunk-index-txv7qvyy.js +2 -0
- package/dist/chunk-index-wr3dg24d.js +2 -0
- package/dist/chunk-index-yx683d5n.js +2 -0
- package/dist/chunk-lang-css-fkdg3x8x.js +1 -0
- package/dist/chunk-lang-dockerfile-ey0nvhhm.js +1 -0
- package/dist/chunk-lang-go-403qsw9f.js +7 -0
- package/dist/chunk-lang-html-v8h9g977.js +1 -0
- package/dist/chunk-lang-javascript-ykb2vhaa.js +1 -0
- package/dist/chunk-lang-json-2rze3rpy.js +1 -0
- package/dist/chunk-lang-markdown-6w2htnfc.js +6 -0
- package/dist/chunk-lang-python-9jk5a49y.js +3 -0
- package/dist/chunk-lang-rust-24fggcqx.js +1 -0
- package/dist/chunk-lang-shell-cgq6q0kj.js +1 -0
- package/dist/chunk-lang-sql-gjywb9ke.js +2 -0
- package/dist/chunk-lang-toml-xh45nm68.js +1 -0
- package/dist/chunk-lang-typescript-qh6rebyb.js +1 -0
- package/dist/chunk-lang-xml-1mh879j9.js +1 -0
- package/dist/chunk-lang-yaml-jac98srt.js +1 -0
- package/dist/chunk-menu-items-zjpyj51b.js +2 -0
- package/dist/chunk-notes-sjba7kw3.js +1 -0
- package/dist/chunk-overview-26r77kb6.js +1 -0
- package/dist/chunk-room-confirms-851184ep.js +1 -0
- package/dist/chunk-room-menu-8y9c026y.js +1 -0
- package/dist/chunk-skills-56s4hdbn.js +1 -0
- package/dist/chunk-table-qykpvp32.js +1 -0
- package/dist/chunk-table2d-k60ressj.js +1 -0
- package/dist/chunk-table3d-bv2ajk39.js +4220 -0
- package/dist/chunk-transcript-vekz1mh6.js +1 -0
- package/dist/chunk-workspace-hevefd0d.js +1 -0
- package/dist/chunk-zh-tw-5r2wjre0.js +1 -0
- package/dist/index.html +2 -1
- package/dist/sw.js +1 -1
- package/package.json +21 -3
- package/src/api-types.ts +161 -0
- package/src/app/app.ts +28 -0
- package/src/app/rooms.ts +7 -1
- package/src/app/routes.ts +223 -1
- package/src/app/workspace-files.ts +1485 -0
- package/src/console-api.ts +5 -0
- package/src/i18n/zh-tw.ts +185 -24
- package/src/options.ts +182 -5
- package/src/push/mutes.ts +68 -0
- package/src/push/quiet-hours.ts +60 -0
- package/src/push/triggers.ts +40 -9
- package/src/web-plugin.ts +46 -2
- package/dist/chunk-character-creator-660d2t6p.js +0 -1
- package/dist/chunk-connectors-d19v8cjc.js +0 -1
- package/dist/chunk-conversations-4cmexmqq.js +0 -1
- package/dist/chunk-entry-8xpx35ef.js +0 -1
- package/dist/chunk-index-19g8jmr8.js +0 -2
- package/dist/chunk-index-362dfedj.js +0 -1
- package/dist/chunk-index-6g69tqt0.js +0 -47
- package/dist/chunk-index-89q2qdkj.css +0 -1
- package/dist/chunk-index-9tvf6es7.js +0 -41
- package/dist/chunk-index-p8h0e861.js +0 -2
- package/dist/chunk-index-xw5hhmfq.js +0 -2
- package/dist/chunk-notes-fefwds14.js +0 -1
- package/dist/chunk-overview-bxpwpmn6.js +0 -1
- package/dist/chunk-skills-pce3zgxy.js +0 -1
- package/dist/chunk-table-zmpbrfvz.js +0 -1
- package/dist/chunk-table2d-ac2gez71.js +0 -1
- package/dist/chunk-table3d-g258jemr.js +0 -4229
- package/dist/chunk-transcript-yhtjp3pd.js +0 -1
- package/dist/chunk-zh-tw-anqhqpaz.js +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,67 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
5
5
|
|
|
6
|
+
## [Unreleased]
|
|
7
|
+
|
|
8
|
+
## [0.24.0] - 2026-10-29
|
|
9
|
+
|
|
10
|
+
The core peer range is now `>=0.24.0 <0.25.0`.
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- The files pane (`workspace`, called Files). The owner browses the agents' workspace, reads files highlighted by CodeMirror 6, and edits, creates, renames and deletes them, on a phone (drill-down, a bottom bar above the keyboard, 16 px editor font) and on a desktop (a resizable tree that remembers its open folders, breadcrumbs, Cmd/Ctrl+S and Cmd/Ctrl+F). It shows `AGENTS.workspace`, the agents' working directory (`agents`) and scratch directory (`scratch`), and `workspace.roots` adds more places: `{ id, label, dir, writable? }`, with `writable` false unless set; `workspace.agents` and `workspace.scratch` set to `false` leave the two out, and a root that is or contains `dataDir` stops the start. The pane is in the default `panes` only when there is a place to show, and a default place that holds `dataDir` is left out with a warning instead of stopping the start; listing the pane without one, or without `rooms`, stops the start. See [the README](README.md#the-files-pane).
|
|
15
|
+
- Saves that cannot overwrite a partner's change. A file is read with its SHA-256 hash and saved with it as `baseHash`; the server compares again just before replacing the file and answers `409` with the file as it is (or `gone`) and writes nothing. The page opens a dialog with Copy my text, Reload and Save mine anyway (confirmed a second time), and looks at an open file on focus and every 5 s, with a banner while an edit is open. A save writes a temporary file beside the original with its mode, flushes, re-checks that the directory is still the one inside the place and the file still regular, and renames it; it keeps the line separator, a byte order mark and the final newline.
|
|
16
|
+
- New file, New folder, Rename and Delete. None replaces something that exists (`409 exists`); Delete moves to `.rt-trash` at the top of the place, which Trash lists with Restore (never over an existing file) and Delete for good. A link is deleted as a link.
|
|
17
|
+
- The rules that keep it inside the places. Every call, a read too, needs an owner and a change needs the console's `Origin`; a path is `400` for a NUL, a leading `/`, a `.`, `..` or empty segment, or more than 4,096 bytes; each directory on the way is resolved with `realpath` and must be inside the place, and a place's own real directory is fixed where it is first seen; a symlink is listed with whether its target is inside, opened as its target when inside, shown and never read or written when outside, and never written through; pipes, sockets and devices are never opened; a file is opened without following a link and its handle compared with what was checked. `.git` (any case) is read-only at any depth and in any place, a place that is not writable refuses every change, a file over 2 MiB is metadata and a download, over 1 MiB is not edited, a text over 1 MiB is `413`, a download is at most 50 MiB, and a directory lists 2,000 entries. NUL bytes or invalid UTF-8 make a file read-only; a picture, PDF, sound or video previews only when its extension is on the allowlist and its bytes agree (PNG, JPEG, GIF, WebP, SVG, PDF, MP3, WAV, OGG, MP4, WebM); it is served inline with its own type, `nosniff`, `frame-ancestors 'self'`, a strong ETag, byte ranges and `Cache-Control: no-store`, under a `sandbox` policy that loads nothing (a PDF has none, because a browser's viewer does not draw under one). An SVG is served inline and sandboxed, and the page shows it only through `<img>`; HTML and XML are always downloads. Saves, creations, renames, deletions and restores are logged with who, where and short hashes, never contents, and refused escapes as warnings. The REST is under `api/workspace`.
|
|
18
|
+
- The editor is CodeMirror 6 (state 6.7.6, view 6.43.15, language 6.13.1, commands 6.11.1, search 6.7.2, and languages for TypeScript and JavaScript, JSON, Markdown, CSS, HTML, Python, YAML, Go, Rust, SQL, XML, shell, TOML and Dockerfile), pinned exactly as development dependencies like React. It and each language are chunks of their own that load when a file first opens; the service worker caches them when fetched and does not precache them (the code they share is left to the browser's cache), and never caches `api/workspace`. The editor sits in a shadow root with adopted stylesheets so the page's Content-Security-Policy, which does not apply a `<style>` element, stays as it is. Its colors are the `--code-*` CSS variables in `tokens.css` and, for Camelot, `styles/camelot.css`, so a look or a light/dark switch recolors it at once.
|
|
19
|
+
- Traditional Chinese for the new wording, and `WorkspaceRootView`, `WorkspaceFileView`, `WorkspaceListView`, `WorkspaceSaved`, `WorkspaceConflict` and the other types of the pane's API in `src/api-types.ts`.
|
|
20
|
+
|
|
21
|
+
- Skin tones from the host. `GET api/config` carries `characterSkins`, the six `#rrggbb` colors of the host's `characters.skins` (the character kit's own by default), and the page draws every character, the creator's skin swatches and the round table's seats with them, so a stored look keeps its skin index and takes the new tones as they are. Pass `characters: { skins: EAST_ASIAN_SKINS }` (from `pi-roundtable/characters`) for light East Asian tones. Needs `pi-roundtable` with the option (`HostEnv.characterSkins`).
|
|
22
|
+
- A room switcher on phones (screens under 1024 px wide). A swipe right over the messages pulls in a drawer of rooms that follows the finger and snaps open past 40 % of its width or on a fast flick; a tap on the header picture opens the same drawer. Swiping left, tapping outside, Escape or the system Back closes it: opening pushes a history entry, so Back closes the drawer before it leaves the room.
|
|
23
|
+
- The drawer lists each room with its picture, name and status (working, cards waiting, yolo, long-running); rooms with a card waiting come first under "Waiting for you", the rest follow by latest activity, and a search field narrows the list. A tap on a row opens that room in place, with no list page in between.
|
|
24
|
+
- A room keeps the text typed in its message box and not yet sent while the person is in another room (kept for the page's lifetime; attached files are not kept).
|
|
25
|
+
- The swipe never starts from a screen edge: a touch that begins within 32 px of the left or right edge is ignored and left to the system, since many phones use an edge swipe for Back. It also needs mostly horizontal motion (|dx| > 1.5·|dy|, at least 24 px) and ignores touches that begin in a field, a code block or table that scrolls sideways, or a card's option row (`data-swipe-ignore`). It slides with the console's motion lengths, which go to zero under `prefers-reduced-motion`.
|
|
26
|
+
- Traditional Chinese for the new wording ("Switch rooms").
|
|
27
|
+
- One action menu for a long press, a right click and the keyboard. A touch that rests 450 ms (and moves under 10 px, and does not scroll) opens it with a short vibration where the phone has one; a right click opens it at the pointer (Android's own `contextmenu` after a long press is answered once); the Menu key and Shift+F10 open it from the focused row. On a phone width (under 720 px) it is a bottom sheet that Back, Escape, a tap outside and a drag down close, like the drawer; elsewhere it is a popover at the pointer that keeps inside the window, takes focus, moves it with the arrow keys, Home and End, keeps Tab inside and closes on Escape, a press outside, the person's own scrolling or a resize. The lift that ends a hold does not also follow the row's link. Rows are not selectable and show no system callout while a message's words stay selectable.
|
|
28
|
+
- Where the menu opens: an agent's or group's row in the room list and in the drawer (Edit agent, Change look, Yolo mode and Long-running mode as switches, Start over with its confirm; a group has no edit or look, a dispatch thread has no menu); a message (Copy, Copy as Markdown, Quote reply, Select text, and Share where the browser can; Copy takes what is selected inside the message when something is); a message's picture (Agent profile); a card (Copy details: title, text, tool, action, input and files); a file or picture (Download, and Share where the browser can, sending the file itself where the browser allows it and its address otherwise). The innermost target answers, so a file chip's menu opens instead of its message's.
|
|
29
|
+
- Edit agent opens the agent's profile, and Change look opens it at the character creator. From the phone drawer the drawer closes first, so Back does not return to it. Quote reply puts the message as a Markdown quote into the room's message box below what is typed, and keeps it in the room's draft when the box is not open.
|
|
30
|
+
- A message takes focus (a tab stop) so the Menu key can open its menu.
|
|
31
|
+
- Traditional Chinese for the new wording.
|
|
32
|
+
- The agent sheet. Tapping the room header's name (an agent's room; a group has none) opens it, and so do Edit agent and Change look in the menus, the room's ⋯ menu and an agent's picture in a message. It is a wide sheet on a desktop and a bottom sheet on a phone. The header's picture stays the switcher's button on a phone, so each tap target has one meaning. It holds what the old profile page edited (display name, prompt, model, thinking level, and the character creator, which Change look scrolls to) and:
|
|
33
|
+
- A prompt editor with a Full screen button that opens the text in a window-sized sheet, and, when the prompt changed, a Review changes step before the save: the changed fields, then the prompt as a line diff with added and removed lines marked. A save that leaves the prompt alone goes straight through.
|
|
34
|
+
- Model and thinking level as chips (the saved choice is pressed) in place of two drop-downs; the thinking levels read in the console's language.
|
|
35
|
+
- A Notifications switch. Off mutes the room's push for every owner and device.
|
|
36
|
+
- Per-room push mute. `PUT rooms/<key>/mute` with `{muted: boolean}` (an agent's or group's room, an owner, the console's own Origin, like the other writes; `404` for a room that is not the app's or is a thread, `400` for a body without a boolean) stores the room in a new table, `web_push_muted_rooms` (created idempotently by the web plugin's migration), and tells every open page to read the room list again. The room list gives a muted room `muted: true`. An agent's post in a muted room, or in a thread under it, is not pushed; a waiting card, the long-running cap and a notice (which always names the home room) still are. The quiet hours still hold a notice. A mute that cannot be read does not silence the owner, and logs a warning. Muting is the owners' choice for the room, not a device's. A muted room shows a bell-slash in the list, the drawer and the header, and Notifications is an item of the room menu, the row and drawer menus (a checked item means pushes are on) and the room's ⋯ menu.
|
|
37
|
+
- The router's `navigate` takes `{ replace: true }` for a step that stands in for another.
|
|
38
|
+
- Traditional Chinese for the new wording.
|
|
39
|
+
|
|
40
|
+
### Changed
|
|
41
|
+
|
|
42
|
+
- The characters' parts are drawn medieval (the core's change): the creator's strips show a biretta, a chaperon, a pilgrim hat, an iron skullcap, a mail hauberk, a doublet, an astrolabe, dividers and the like in place of the modern ones, under the same part ids. The English names are in `character-labels.ts` and the zh-TW names in the built-in catalog (`character.hat.mortar`, `character.hat.goggcap`, `character.hat.beret`, `character.hat.goggles`, `character.hat.tallcap`, `character.hat.tricorn`, `character.hat.hardhat`, `character.hat.toque`, `character.hat.cavalier`, `character.hat.fcap`, `character.hat.sailor`, `character.outfit.armor`, `.apron`, `.chef`, `.coat`, `.overalls`, `.vest`, `.sailor`, `character.prop.flask`, `.map`, `.telescope` and `.wrench`); a host that words them itself keeps its wording.
|
|
43
|
+
- The test that holds the characters to their share of the first load allows 16 KB gzipped (was 15 KB), for the skin tones the page now reads.
|
|
44
|
+
- The agent's own page is gone. `#/agent/<name>`, from a bookmark or an installed app's history, opens the agent's room with the agent sheet on top, in place of its own history entry, so Back goes where it would have gone from the room; a name that is not in the room list goes to the list. The wish "open at the creator" that Change look made is now a flag of the sheet.
|
|
45
|
+
- `Sheet` and `Dialog` take `size: "full"`, a window-sized panel. A sheet inside a sheet closes alone: its `cancel` (Escape) and `close` events no longer reach the sheet around it. Text that is visually hidden inside a sheet is positioned against the sheet's body, so a scroll to an element no longer scrolls the sheet's header out of sight.
|
|
46
|
+
- The room's menu (the ⋯ button) loads when it is first opened instead of with the page.
|
|
47
|
+
- A history step that lands on the page already shown no longer redraws the page or scrolls it to the top.
|
|
48
|
+
- `Dialog` is now a thin wrapper over `Sheet`, with an optional `size: "wide"` for documents. The panel has a padded header (title truncating with an ellipsis, an icon close button labelled "Close"), a hairline divider, a body that scrolls under a fixed header, and a uniform border; on phones it is a bottom sheet with a grab handle that can be dragged down. The Skills page's SKILL.md view uses the wide size and lists the frontmatter as a two-column key/value list (leaving out a `name` that repeats the title) above Markdown with a 72-character measure, where code blocks and tables scroll inside themselves. The fixture app now serves the Notes and Skills panes.
|
|
49
|
+
- The questions "Turn on yolo mode?" and "Start over?" are drawn by one host for the whole app, so the room menu, a row's menu and the drawer ask the same question in the same words.
|
|
50
|
+
- The round table is a council hall drawn in one style. The scene is the same flat, cel-shaded illustration as the characters (a stepped tone gradient on every surface and a dark outline round every solid shape, no photographic textures): a night stone hall of slate and navy with a teal rune circle on the floor, banners, torches with a flat flame, a stained-glass window with moonlight, and a ring of tall dark-wood podiums with a gold nameplate on the front and back. Light is the same hall by day (warmer stone, sun through the window); the Camelot look recolours the banners and the trim and leaves the hall alone. An agent stands behind its podium as a waist-up standee: the character without its frame, cut out along its outline with a thin light rim, turning to the camera within limits. A thinking seat shows a "…" badge and bobs, a waiting seat a gold "!", a speaking seat a light on its podium; a "done" and an "error" seat have a tick and a cross. The owner's own podium is the camera's home, and a ring of more than twelve agents shows twelve and a "+N" podium. Names are drawn through a font stack that carries Chinese (`system-ui`, PingFang TC, Noto Sans TC, Microsoft JhengHei), so a zh-TW name is lettered as the page shows it; the old 3D labels printed boxes.
|
|
51
|
+
- The table has two cameras. The overview stands behind the owner's podium, raised, and a drag or swipe turns it round the ring and snaps to a podium; a wheel turn or a pinch moves in on the podium across the ring and back out. The close-up of a speaker stands low inside the ring, tilted a little, with the speaker large and the others soft behind it, and thin speed lines flash for 400 ms on a new speaker. A turn follows the ring the shorter way and takes 450 to 650 ms. Under `prefers-reduced-motion` the camera cuts, and there are no speed lines, bob or flicker. A swipe never starts within 32 px of the screen's edge. The scene stops drawing while the page is hidden or the table is off screen, draws a few frames a second while nothing moves (so a torch flickers without keeping the GPU busy), and caps the pixel ratio at 2 (1.5 on phones). three.js stays a lazy chunk of its own.
|
|
52
|
+
- The names of the seats are page elements laid over the podiums, not a texture: at least 12 px on the screen at any distance, in a font stack that carries Chinese, and each is a button for the seat, so a name can be tapped and a keyboard reaches every seat. The agents stand side by side across the ring from the owner's own podium, which sits low at the near edge so the rune circle and the other podiums are in view, and the standees stand about half as large again, chest and hands over the desk. The standee's board has a dark line outside its light rim and a thickness in a mid tone of the seat's colour, so it reads on the fairest skin. A speaking seat gets the concept art's three gold emphasis strokes beside its head, which pop in with a small bounce.
|
|
53
|
+
- A dialogue box on the Round table page. Tapping a podium (or its name) turns the camera to that agent, and a box slides up as the camera arrives, with a nameplate tab in the speaker's colour and picture, the line being said (Markdown, typed out while it streams, a tap or Enter shows it whole, no typing under reduced motion), the cards waiting for an answer in the room's own card components, and the room's message box beneath, with its unsent text kept per room. A Log button opens the room's whole message list as a sheet over the scene; a "back" button returns to the whole ring. The address is `#/table/<agent>` (an agent's name or the key of its room): Back returns to the whole ring, a link opens the scene at that agent, moving from one agent to another replaces the address, and an address that names nobody seated goes back to `#/table` in place. Traditional Chinese for the new wording.
|
|
54
|
+
- A group room's "Table" button now switches the room between its list and the scene, and the choice is kept per room (it opened a panel or sheet with the members' table before). In the scene the whole group conversation runs in the dialogue box, the camera turns to whoever replies and rests on the whole ring while the owner speaks, a seat tapped by hand holds until the next line, and a speaker change never takes the focus from the message box. Under Camelot the compact strip of the members still stands under the header in the list view.
|
|
55
|
+
- On a phone held upright the scene fills the top 55 % and the dialogue box the rest, and the box collapses to its nameplate line; on its side the scene is whole and the box lies over its bottom third.
|
|
56
|
+
- The no-WebGL table (and the compact strip) draws the same hall in SVG: podiums with gold plates that letter Chinese, standees cut out with a rim and a dark line, the owner's low desk, the focused seat marked, the same palette and the same dialogue box over it.
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
## [0.23.2] - 2026-10-29
|
|
60
|
+
|
|
61
|
+
### Added
|
|
62
|
+
|
|
63
|
+
- Quiet hours for Web Push, 23:00 to 08:00 by default. In the window an agent's post and a notice (the `notify` tool, and a notice another channel delivered) are not pushed, so a night report waits in its room; a card (one waiting, or "Long-running cap reached") is still pushed. The window is read on the console's time zone, through `Intl`, and may cross midnight.
|
|
64
|
+
- The option `push.quietHours`: `{ start: "HH:MM", end: "HH:MM" }` (two different times on a 24-hour clock) or `false` for no quiet hours. Anything else stops the start, like the other options.
|
|
65
|
+
- Settings shows the window and its time zone to the owner, read-only, in English and Traditional Chinese (`SessionView.quietHours`).
|
|
66
|
+
|
|
6
67
|
## [0.23.1] - 2026-10-29
|
|
7
68
|
|
|
8
69
|
### Added
|
package/README.md
CHANGED
|
@@ -11,6 +11,7 @@ The plugin is a chat surface of its own (`app`), so a team of agents can live in
|
|
|
11
11
|
- **Cards.** Approvals, questions, questionnaires and the card at a turn's time limit appear in the room, and any owner's device can answer them.
|
|
12
12
|
- **Modes.** Yolo mode approves the held actions a rule allows without asking; long-running mode lets a turn go past its time limit. Each is a switch per room, and a banner shows while one is on.
|
|
13
13
|
- **An app.** A web app manifest, a service worker and Web Push make it installable and let a card wake the phone.
|
|
14
|
+
- **Files.** The owner browses the agents' workspace, reads files with syntax highlighting, and edits, creates, renames and deletes them (to a restorable trash), with a check on every save that a partner did not change the file meanwhile.
|
|
14
15
|
- **Looks.** Agents are drawn as characters; the page has a Modern and a Camelot look, light and dark, and a round table that seats the whole team.
|
|
15
16
|
|
|
16
17
|
Who may enter is the host's `access` configuration plus an authentication mode you choose: `none`, `password` or `verifier` (see [Authentication](#authentication)), and the plugin refuses to start without one.
|
|
@@ -19,7 +20,7 @@ Then only a person whose principal holds the owner role gets in.
|
|
|
19
20
|
## Contents
|
|
20
21
|
|
|
21
22
|
- [Requirements](#requirements) and [Install](#install)
|
|
22
|
-
- [The owner app](#the-owner-app): rooms, cards, [modes](#modes-yolo-and-long-running), [dispatch threads](#dispatch-threads), [uploads](#uploads), [characters](#characters-in-the-page), [the Camelot look](#the-camelot-look), [the round table](#the-round-table)
|
|
23
|
+
- [The owner app](#the-owner-app): rooms, cards, [modes](#modes-yolo-and-long-running), [dispatch threads](#dispatch-threads), [uploads](#uploads), [characters](#characters-in-the-page), [the Camelot look](#the-camelot-look), [the round table](#the-round-table), [the files pane](#the-files-pane)
|
|
23
24
|
- [Install on a device](#install-on-a-device) and [Notifications](#notifications)
|
|
24
25
|
- [Authentication](#authentication) and the [threat model](#threat-model)
|
|
25
26
|
- [Options](#options), [the console's panes](#the-consoles-panes) and [host feature ports](#host-feature-ports)
|
|
@@ -27,7 +28,7 @@ Then only a person whose principal holds the owner role gets in.
|
|
|
27
28
|
|
|
28
29
|
## Requirements
|
|
29
30
|
|
|
30
|
-
- Bun 1.4.4 or later, and pi-roundtable `>=0.
|
|
31
|
+
- Bun 1.4.4 or later, and pi-roundtable `>=0.24.0 <0.25.0` as a peer dependency.
|
|
31
32
|
- The host must run on the machine that holds its data directory: the console reads `<dataDir>/sessions` from disk, and the app keeps its files and keys under `<dataDir>/web/`.
|
|
32
33
|
- An agent team: `agents` in the configuration, with or without `discord`. Without Discord the host also needs a surface that hosts rooms, and this plugin is one; the start fails otherwise, naming the fix.
|
|
33
34
|
- A way to authenticate the owners (see [Authentication](#authentication)): a password, Cloudflare Access or a verifier of your own in front of the listener, or `none` on a listener only the owner reaches.
|
|
@@ -109,6 +110,7 @@ The page is built for a phone first: a bottom tab bar under 720 px, a side rail
|
|
|
109
110
|
| **Agent profile** | Display name, prompt, model and thinking level, and the character creator (see [Characters in the page](#characters-in-the-page)). |
|
|
110
111
|
| **Schedules** | Every schedule of the team, labelled by room or channel, with a confirmed cancel. |
|
|
111
112
|
| **Table** | The round table (see [The round table](#the-round-table)). |
|
|
113
|
+
| **Files** | The agents' workspace: a tree, highlighted files and an editor (see [The files pane](#the-files-pane)). |
|
|
112
114
|
| **Settings** | Color scheme and look, install, notifications for this device, and Log out (password mode). |
|
|
113
115
|
|
|
114
116
|
**Sending and stopping.** A message goes to the agent as the owner's. **Stop** ends the turn.
|
|
@@ -157,7 +159,7 @@ An owner may send a file of any kind in a room, up to four to a message: the but
|
|
|
157
159
|
|
|
158
160
|
### Characters in the page
|
|
159
161
|
|
|
160
|
-
Every agent is drawn as its composed character (`pi-roundtable/characters`). The page draws it from the spec the server sends, after a strict `parseCharacter` check: a spec that does not parse is logged and replaced by the look the agent's name suggests. The drawing is `composeSvg`'s output, the only markup the page injects, and it holds no inline style, so the content security policy is unchanged. The composer is a chunk of its own (about 19 KB gzipped) that starts loading with the page and is cached by the service worker.
|
|
162
|
+
Every agent is drawn as its composed character (`pi-roundtable/characters`). The page draws it from the spec the server sends, after a strict `parseCharacter` check: a spec that does not parse is logged and replaced by the look the agent's name suggests. The drawing is `composeSvg`'s output, the only markup the page injects, and it holds no inline style, so the content security policy is unchanged. The skin tones come from the host: `GET api/config` carries `characterSkins`, the six `#rrggbb` colors of the host's `characters.skins` (the character kit's own by default, `EAST_ASIAN_SKINS` for light East Asian tones), and every drawing, the creator's skin swatches and the round table use them, so a stored look keeps its skin index and takes the new tones as they are. The composer is a chunk of its own (about 19 KB gzipped) that starts loading with the page and is cached by the service worker.
|
|
161
163
|
|
|
162
164
|
- **Where.** The room list, the room's header and the agent's profile show the character live, the room list only while its agent is not idle; messages, the room switcher and a group's stack of up to three members stand still. The owner has no picture.
|
|
163
165
|
- **State.** `thinking`, `working`, `waiting` (a card is open), `done`, `error` and `sleepy` come from the `activity`, `presence` and prompt frames; `working` elsewhere (Discord, another room) counts, `done` lasts 2.5 s, a failed turn stays `error` until the next turn or the room is opened (at most ten minutes), and an agent quiet for eight hours, or between 01:00 and 06:00 local time with nothing in the last hour, is `sleepy`. Under `prefers-reduced-motion` the characters stand still and the state shows as a badge.
|
|
@@ -176,19 +178,79 @@ Every agent is drawn as its composed character (`pi-roundtable/characters`). The
|
|
|
176
178
|
|
|
177
179
|
### The round table
|
|
178
180
|
|
|
179
|
-
The `table` pane
|
|
180
|
-
|
|
181
|
-
- **
|
|
182
|
-
- **
|
|
183
|
-
-
|
|
184
|
-
- **
|
|
181
|
+
The `table` pane is a council hall: a ring of tall dark-wood podiums, one for each active agent (the coordinator first) and one low lip at the near edge for you, under torches, banners and a stained-glass window, around a glowing rune circle. The hall is drawn in the characters' own flat, outlined style (a stepped tone gradient and a dark line round every shape, no photographic textures). Dark is the hall at night, light the same hall by day; the Modern and Camelot looks change the banners and the trim, not the hall. Each agent stands behind its podium as a waist-up standee: the character without its frame, cut out with a thin light rim, a dark line and a visible board thickness, turning to the camera within limits. A seat's state comes from the same rules as the room list (`sleepy` sits as `idle`): a thinking seat shows a "…" badge and bobs, a seat with a card waiting a gold "!", a speaking seat has a light on its podium and the concept art's three gold emphasis strokes beside its head; a change of face redraws that one picture once it has stood for 300 ms. More than twelve agents show twelve and a "+N" podium that opens the list.
|
|
182
|
+
|
|
183
|
+
- **Cameras.** The overview stands behind your podium, raised. A drag or swipe turns it round the ring and snaps to a podium; the wheel or a pinch moves in on the podium across the ring and back out. A close-up of a speaker stands low inside the ring, tilted a little, with thin speed lines flashing for 400 ms on a new speaker. A turn follows the ring the shorter way and takes 450 to 650 ms. A swipe never starts within 32 px of the screen's edge. Under `prefers-reduced-motion` the camera cuts, with no speed lines, bob or flicker.
|
|
184
|
+
- **Talking in the scene.** A tap on a podium (or on its name, a button over the plate) turns the camera to that agent and slides up a dialogue box on the agent's own room: a nameplate tab in the agent's color with its picture, the line being said (Markdown, typed out while it streams, a tap shows it whole), the cards waiting for an answer, and the room's own message box, with its unsent text kept per room. **Log** opens the room's whole message list as a sheet over the scene. The address is `#/table/<agent>` (the agent's name or the key of its room): Back returns to the whole ring, a link opens the scene at that agent, and an address that names nobody seated goes back to `#/table`.
|
|
185
|
+
- **Names.** A seat's name is a button laid over its podium's nameplate, at least 12 px on the screen at any distance, in a font stack that carries Chinese (`system-ui`, PingFang TC, Noto Sans TC, Microsoft JhengHei); the podium's own plate is lettered the same way. The seat's full name and state are its accessible name. Where the names stand over each other (many seats on a phone) the agents are also listed as buttons under the scene.
|
|
186
|
+
- **Phones.** Held upright, the scene fills the top 55 % and the dialogue box the rest, and the box collapses to its nameplate line; on its side the scene is whole and the box lies over its bottom third. The seats are also listed as buttons with more than ten seats.
|
|
187
|
+
- **Fallback.** Without WebGL (or after a lost context) the same ring is drawn as SVG in the same palette, with the same standees, plates and dialogue box, never a blank pane. `?nogl` in the page address (`/console/?nogl`, or `#/table?nogl`) draws it on a browser that has WebGL, to try that path; `nogl=0` and `nogl=false` leave the choice to the browser.
|
|
188
|
+
- **Performance.** The WebGL scene is a chunk of its own, fetched when the view first opens and cached by the service worker, never precached. It stops drawing while the page is hidden or the table is off screen, draws a few frames a second while nothing moves (so a torch flickers without keeping the GPU busy), and caps the pixel ratio at 2 (1.5 on phones).
|
|
189
|
+
- **Group rooms.** A group room's header has a "Table" button that switches the room between its list and the scene; the choice is kept per room. In the scene the whole conversation runs in the dialogue box, the camera turns to whoever replies, and it rests on the whole ring while you speak; a member that starts thinking shows its badge wherever the camera is, and a speaker change never takes the focus from your message box. Under the Camelot look a compact strip of the members stands under the header in the list, with the speaker lit.
|
|
190
|
+
|
|
191
|
+
### The files pane
|
|
192
|
+
|
|
193
|
+
The `workspace` pane (called Files) shows the directories the agents work in and lets the owner edit what they find there, from a phone or a desktop.
|
|
194
|
+
It is for reading a file an agent wrote, fixing a line, and keeping a note beside the work, not for running code.
|
|
195
|
+
|
|
196
|
+
**What it shows.** Two places are on without being named when the agent server is present, from `AGENTS.workspace`: `agents`, the shared working directory every agent's shell and file tools run in, and `scratch`, the agents' scratch directory when the host sets one.
|
|
197
|
+
Both are writable, which adds nothing the agents lack: they write there without a hold.
|
|
198
|
+
`workspace.roots` adds more, each `{ id, label, dir, writable? }` with `writable` false unless said, and `workspace.agents: false` or `workspace.scratch: false` leaves one of the two out.
|
|
199
|
+
A root is refused at the start when it is, or contains, the host's `dataDir` (sessions, the session key and the VAPID keys live there) or Pi's agent directory in its default place, `<dataDir>/pi` (`auth.json`), once symlinks are resolved.
|
|
200
|
+
A root whose directory does not exist yet lists as empty and is never created by the app.
|
|
201
|
+
The pane is in the default list only when there is a place to show; a list that names `workspace` without one stops the start and says so.
|
|
202
|
+
|
|
203
|
+
**On a desktop** (720 px and wider) the tree stands on the left, resizable and remembering which folders were open per place, and the file or folder on the right, under a header with a place picker and breadcrumbs.
|
|
204
|
+
**On a phone** the pane drills down one level at a time: the places, then a folder, then a file, with the breadcrumbs as a row of chips that scrolls sideways and a Back button.
|
|
205
|
+
A file opens in read mode, so no keyboard rises; Edit switches to the editor, whose bottom bar sits above the keyboard with Save, Undo, Redo, Find and Tab, the font is 16 px so the page does not zoom on focus, and lines wrap.
|
|
206
|
+
Cmd/Ctrl+S saves, Cmd/Ctrl+F finds, and Esc leaves the editor (and asks first when there are unsaved edits).
|
|
207
|
+
`.git` and `node_modules` are listed but dimmed.
|
|
208
|
+
|
|
209
|
+
**Highlighting and editing** are CodeMirror 6, one engine for both, so the read view and the editor look the same and switching is instant.
|
|
210
|
+
The editor and each language are separate chunks that load the first time they are needed (the editor about 100 KB gzipped, a language 1 to 70 KB), so none of it is in the page's first download. The service worker caches the editor's and each language's chunk when it is fetched and never precaches them; the code they share is left to the browser's own cache, which keeps a hashed file for good.
|
|
211
|
+
The editor lives in a shadow root and takes its styles as constructed stylesheets, because the page's Content-Security-Policy (`default-src 'self'`) does not apply a `<style>` element a library adds; the policy is not loosened. A browser without constructed stylesheets (before Safari 16.4) shows the editor in the page, where it is unstyled.
|
|
212
|
+
TypeScript and JavaScript, JSON, Markdown, CSS, HTML, Python, YAML, Go, Rust, SQL, XML, shell, TOML and Dockerfile are highlighted; any other file is plain text.
|
|
213
|
+
The colors are CSS variables (`--code-*` in `tokens.css`, set again for Camelot), each at least 4.5:1 on the editor's background, so the Modern and Camelot looks and light and dark recolor an open editor with nothing rebuilt.
|
|
214
|
+
There is no autocomplete and no auto-closing of brackets, which fight phone keyboards, and Tab inserts indentation.
|
|
215
|
+
|
|
216
|
+
**Saving.** A file is read with its SHA-256 hash, and a save carries it back as `baseHash`.
|
|
217
|
+
The server reads the file again and compares just before it replaces it, and a mismatch answers `409` with the file as it is now and writes nothing; so does a file that was deleted meanwhile.
|
|
218
|
+
The page then opens a dialog: Copy my text, Reload (discard my edits), and Save mine anyway, which asks a second time and then writes with the hash the conflict named.
|
|
219
|
+
While a file is open the page looks at it again on focus and every 5 seconds; in read mode it reloads silently, and in edit mode a banner says a partner is changing the file.
|
|
220
|
+
A save writes a temporary file beside the original, with the original's mode, flushes it, checks again that the directory is still the one inside the root and the file is still a regular file, and renames it over the original.
|
|
221
|
+
It keeps the file's line separator (`\r\n` or `\n`), a leading byte order mark and whether the file ends with a newline.
|
|
222
|
+
A save gives the file a new inode and the server's user as its owner, so a hard link to the old file keeps the old text.
|
|
223
|
+
The checks are made with the paths the host gives and resolve the path again for each call, as Node has no `openat`: a process that can rewrite a directory inside a place while a call runs can steer that call. Agents run as the server's own user, so they gain nothing from this, but the place is not a boundary against a separate hostile user.
|
|
224
|
+
|
|
225
|
+
**Making and removing.** New file, New folder and Rename never replace something that exists (a clash is `409 exists`).
|
|
226
|
+
Delete moves the file or folder into `.rt-trash` at the top of its place, which the tree does not list; Trash lists what is there with Restore, which never overwrites, and Delete for good.
|
|
227
|
+
A link is deleted as a link, never as what it points to.
|
|
228
|
+
|
|
229
|
+
**What it refuses.** Every call, a read too, needs an owner, whose tier is read again, and a change needs the console's own `Origin` like every write.
|
|
230
|
+
The client names a place by id and a path relative to it; a NUL byte, a leading `/`, a `.` or `..` or empty segment, or more than 4,096 bytes is `400`.
|
|
231
|
+
Each directory on the way is resolved with `realpath` and must be inside the place's real directory, and a place's own real directory is fixed where it is first seen: one that is later replaced by a link elsewhere is refused.
|
|
232
|
+
`.git` and the trash are guarded by name without regard to case, as a volume that ignores case takes `.GIT` for `.git`.
|
|
233
|
+
A symlink is listed with whether its target is inside; inside it opens as its target, outside it is shown and neither read nor written, and a save never writes through one.
|
|
234
|
+
A pipe, socket or device is listed as other and never opened; a file is opened without following a link and its handle compared with what was checked.
|
|
235
|
+
`.git` is read-only everywhere, because a hook or a config there runs code the next time an agent uses `git`; a place that is not writable refuses every change.
|
|
236
|
+
A file over 2 MiB gives its metadata and a download only, over 1 MiB it is shown and not edited, a download is at most 50 MiB and streamed, a directory lists 2,000 entries and says so, and a saved text is at most 1 MiB (`413`).
|
|
237
|
+
A file with a NUL byte in its first 8 KiB, or that is not valid UTF-8, is read-only.
|
|
238
|
+
A picture, PDF, sound or video previews only when its extension is on the allowlist and its bytes agree (PNG, JPEG, GIF, WebP, SVG, PDF, MP3, WAV, OGG, MP4, WebM); it is served inline with its own type, `nosniff`, `frame-ancestors 'self'`, a strong ETag, byte ranges and `Cache-Control: no-store`, under a `sandbox` policy that loads nothing (a PDF has none, because a browser's viewer does not draw under one). An SVG is served inline and sandboxed, and the page shows it only through `<img>`; HTML and XML are always downloads. Text is served as `text/plain`.
|
|
239
|
+
Each save and each rename, deletion, creation and restore is logged with who, the place, the path and short hashes, never the contents; each refused escape is logged as a warning.
|
|
240
|
+
|
|
241
|
+
**Holds do not apply.** A hold asks the owner before an agent's tool call; here the owner is the one acting and is already authenticated, and the places are those where the agents may write without a hold.
|
|
242
|
+
Under `auth: none` or `password` an agent with a shell can call this API as the owner, as it can for cards and yolo already; within the default places that grants nothing it lacks.
|
|
243
|
+
A host that adds a root the agents cannot reach should authenticate with a verifier (`cloudflareAccess`), as the [threat model](#threat-model) advises for anything an agent's shell must not reach.
|
|
244
|
+
|
|
245
|
+
The REST is `GET api/workspace`, `GET api/workspace/<place>/list?path=`, `file?path=` (the text, `hash`, `editable` and, when not, `reason`), `raw?path=` (bytes, `no-store`, `&download=1` forces a download), `PUT file?path=` (`{ text, baseHash }`), `POST new?path=` (`{ kind: "file" | "dir", text? }`), `POST rename` (`{ from, to }`), `DELETE entry?path=`, `GET trash`, `POST trash/<id>/restore` and `DELETE trash/<id>`.
|
|
246
|
+
The service worker never caches `api/workspace`.
|
|
185
247
|
|
|
186
248
|
## Install on a device
|
|
187
249
|
|
|
188
250
|
The app is a progressive web app, installable on a phone, tablet or desktop and opened in its own window.
|
|
189
251
|
|
|
190
252
|
- `<mount>/manifest.webmanifest` is generated for the mount: its `id`, `start_url` and `scope` are all `<mount>/`, `display` is `standalone`, the name is `title`, and the theme and splash colors follow `appearance.look`. The page links it with `crossorigin="use-credentials"`, so a proxy such as Cloudflare Access that sets a cookie sees it.
|
|
191
|
-
- `<mount>/sw.js` is the service worker, served `no-cache` and scoped to the mount. It precaches the page's hashed assets and `index.html`, serves assets cache-first and navigations network-first with the cached shell as the offline fallback. It never touches `api/`, `auth/`, `login`, `files/` or `avatars/`, and returns a redirect (a proxy's login) as it came. It caches the shell only, never data, so a shared device keeps nothing after you log out. The round table's 3D scene
|
|
253
|
+
- `<mount>/sw.js` is the service worker, served `no-cache` and scoped to the mount. It precaches the page's hashed assets and `index.html`, serves assets cache-first and navigations network-first with the cached shell as the offline fallback. It never touches `api/`, `auth/`, `login`, `files/` or `avatars/`, and returns a redirect (a proxy's login) as it came. It caches the shell only, never data, so a shared device keeps nothing after you log out. The round table's 3D scene and the files pane's editor and languages are fetched the first time they are needed and are not precached.
|
|
192
254
|
- `<mount>/icons/` serves `192.png`, `512.png`, `maskable-512.png`, `apple-180.png` and `badge-96.png`. The package ships a set; `icons.dir` replaces it with a directory that has the same five names.
|
|
193
255
|
|
|
194
256
|
To install: open the page over HTTPS in Chrome, Edge or Safari and use the browser's Install option, or press **Install the app** in Settings where the browser offers it.
|
|
@@ -207,6 +269,15 @@ A push goes out when:
|
|
|
207
269
|
- a notice reaches the owner: `notify` through the app's direct channel writes a line in Home and pushes it, and a notice that Discord (or another channel) delivered is pushed too, through the core's `mirror` hook.
|
|
208
270
|
|
|
209
271
|
Discord's own cards are not pushed.
|
|
272
|
+
|
|
273
|
+
**Quiet hours.** From 23:00 to 08:00 by default, the second and third kinds of push are held back: an agent's post and a notice are not pushed, so a report that arrives at night waits in its room until the owner looks.
|
|
274
|
+
A card (one waiting, or the long-running cap) is still pushed, since work stops until someone answers it.
|
|
275
|
+
The hours are read on the console's time zone (`env.timeZone` of the host, the zone the page shows times in), and a window that ends before it starts crosses midnight.
|
|
276
|
+
`push.quietHours` sets them as `{ start: "22:30", end: "07:00" }` (two different `HH:MM` times on a 24-hour clock), or `false` to push at any hour; anything else stops the start.
|
|
277
|
+
**Settings** shows the window and its time zone to every owner, read-only: only the server sets it.
|
|
278
|
+
|
|
279
|
+
**Muting a room.** An owner turns a room's Notifications off in the agent sheet, the room's ⋯ menu or the long-press menu of its row. The mute belongs to the room: it holds for every owner and every device, and is kept in the database (`web_push_muted_rooms`). A muted room is held back like the quiet hours: an agent's post in it is not pushed, while a waiting card, the long-running cap and a notice still are; a thread under the room follows the room's mute. A bell-slash marks the room in the list, the drawer and the header.
|
|
280
|
+
|
|
210
281
|
With `push.preview` on (the default) a notification shows the first 120 characters of the message; with `push.preview: false` it says only that something waits and where.
|
|
211
282
|
Tapping a notification focuses the app or opens it at the room.
|
|
212
283
|
|
|
@@ -464,7 +535,8 @@ Every option is checked when the plugin is created, so a bad setting stops the h
|
|
|
464
535
|
| `mountPath` | `/console` | The path the app is served under: one or more segments of letters, digits, `.`, `_`, `~`, and `-`. |
|
|
465
536
|
| `listener` | `public` | The id of the listener whose address serves the app. |
|
|
466
537
|
| `routing` | `hash` | `path` retains links such as `/console/skills`, with history navigation and an authenticated page fallback. |
|
|
467
|
-
| `panes` | `rooms`, `table`, `overview`, `schedules`, `conversations`, `notes` | Ordered subset of those panes plus `skills` and `connectors`. `schedules` and `
|
|
538
|
+
| `panes` | `rooms`, `table`, `workspace`, `overview`, `schedules`, `conversations`, `notes` | Ordered subset of those panes plus `skills` and `connectors`. `schedules`, `table` and `workspace` need `rooms`, and `workspace` needs a place to show (below). Disabled panes answer 404. `skills` and `connectors` require their feature ports at setup. An explicit list is kept as written, so a host that listed its panes before 0.23 adds `rooms`, `table` and `schedules` by hand, and one that listed them before 0.24 adds `workspace`. |
|
|
539
|
+
| `workspace` | the agents' directories | What the [files pane](#the-files-pane) shows: `workspace.roots` adds places, each with an `id` (`workspace.roots.id`, a lower-case word other than `agents` and `scratch`), a `label` (`workspace.roots.label`), an absolute `dir` (`workspace.roots.dir`) and `writable` (`workspace.roots.writable`, false unless set), and `workspace.agents` / `workspace.scratch` set to `false` leave the agents' working directory or scratch directory out. A `dir` that is or contains `dataDir` stops the start. |
|
|
468
540
|
| `surface` | `app` | The key prefix of the app's rooms, a lower-case word that is not `discord`. Rooms keep their conversations under it, so changing it starts every room over. |
|
|
469
541
|
| `cardGraceSeconds` | `120` | How long a turn waits on an approval or question card before it goes on without the answer, above 0 and at most 3600. The card stays open for a day. |
|
|
470
542
|
| `uploadMaxBytes` | `104857600` (100 MiB) | The most bytes of one file a person may upload, from 1 to 4 GiB; the agent takes files up to it too. It raises the listener's request body limit. See [Uploads](#uploads). |
|
|
@@ -494,17 +566,18 @@ The `push` keys:
|
|
|
494
566
|
| Key | Default | What it does |
|
|
495
567
|
|---|---|---|
|
|
496
568
|
| `push.preview` | `true` | Whether a notification shows the first 120 characters of the message. With `false` it says only that something waits, and where. |
|
|
569
|
+
| `push.quietHours` | `{ start: "23:00", end: "08:00" }` | The hours when an agent's post and a notice are not pushed, as two different `HH:MM` times on the console's time zone; an `end` before the `start` crosses midnight. Cards are always pushed. `false` turns quiet hours off. |
|
|
497
570
|
| `push.endpointHosts` | none | Push services to post to besides the browsers' own (Google, Mozilla, Apple, Microsoft), as host names; a leading `*.` allows every subdomain. Endpoints must still be `https`. |
|
|
498
571
|
| `push.subject` | `origin`, when it is `https` | The contact a push service may use about this server (the VAPID `sub`): a `mailto:` or `https:` URL. With an `http` origin push stays off until it is set. |
|
|
499
572
|
|
|
500
|
-
The bad settings that stop the host at startup are: no `auth` or `verifier`, both of them, an unknown `auth.mode`, a password shorter than 12 characters, `none` on a listener that reaches beyond the machine, an `origin` with a path, a `mountPath` of `/` or with `..` in it, an unknown or repeated pane, `schedules` or `
|
|
573
|
+
The bad settings that stop the host at startup are: no `auth` or `verifier`, both of them, an unknown `auth.mode`, a password shorter than 12 characters, `none` on a listener that reaches beyond the machine, an `origin` with a path, a `mountPath` of `/` or with `..` in it, an unknown or repeated pane, `schedules`, `table` or `workspace` without `rooms`, a `workspace` pane with no place to show, a `workspace.roots` entry that is malformed, reuses an id, or is or contains `dataDir`, a `surface` that is not a lower-case word or is `discord`, an empty `ownerId`, a `uploadMaxBytes` out of range, and a `push.subject` that is neither a `mailto:` address nor an `https:` URL, and a `push.quietHours` that is neither `false` nor two different `HH:MM` times.
|
|
501
574
|
|
|
502
|
-
The plugin needs, for the panes you serve: the agent server (`AGENTS`) for Overview and Rooms, the modes service (`MODES`) for Rooms, the schedule store (`SCHEDULES`) for Schedules, and the memory addon for Notes.
|
|
575
|
+
The plugin needs, for the panes you serve: the agent server (`AGENTS`) for Overview and Rooms (and for the files pane's default places), the modes service (`MODES`) for Rooms, the schedule store (`SCHEDULES`) for Schedules, and the memory addon for Notes.
|
|
503
576
|
The host refuses to start with a message naming the missing service when one of them is absent.
|
|
504
577
|
|
|
505
578
|
## The console's panes
|
|
506
579
|
|
|
507
|
-
The page has
|
|
580
|
+
The page has nine panes; `panes` chooses which ones a host serves.
|
|
508
581
|
Rooms and Schedules belong to the [owner app](#the-owner-app), and the Round table to [its own section](#the-round-table); the rest are the console that came first, which reads what the host already stores: the conversation files under the data directory, the memory addon, and the agent team.
|
|
509
582
|
|
|
510
583
|
| Pane | What it shows |
|
|
@@ -516,7 +589,8 @@ Rooms and Schedules belong to the [owner app](#the-owner-app), and the Round tab
|
|
|
516
589
|
| Notes | A principal's memory in three tabs, core, notes, and events, with search: the signed-in owner's own by default, and any principal's the host knows through a picker that appears when there is more than one. The owner can add a note, edit its text, kind, and date, and delete it after a confirmation, in whichever memory is shown. The memory addon's own validation applies, so a refusal shows its reason and saves nothing. |
|
|
517
590
|
| Skills | The full host catalog, source, groups and carriers; each available skill opens its ordered frontmatter and Markdown body. |
|
|
518
591
|
| Connectors | Upstream gateway enabled/reachable/tool status, virtual-server tool lists, and the agents or profiles that use them; an optional administration link. |
|
|
519
|
-
|
|
|
592
|
+
| Files | The agents' workspace: a tree, highlighted files, an editor with conflict-checked saves, and a restorable trash (see [The files pane](#the-files-pane)). Needs `rooms` and a place to show. |
|
|
593
|
+
| Round table | Every active agent at a podium of one council hall, the coordinator first, each in the state its room is in; a seat turns the camera to its agent and opens a dialogue box on the agent's room (see [The round table](#the-round-table)). Needs `rooms`. |
|
|
520
594
|
|
|
521
595
|
Opening a conversation shows its **transcript**: the user's and the assistant's messages, the tools the assistant called with a short preview of their arguments, and each tool's result (collapsed).
|
|
522
596
|
A conversation that was started over keeps its archives, and the page can show any of them.
|
|
@@ -596,7 +670,7 @@ The `rooms` pane's page and any client of your own talk to the host in this prot
|
|
|
596
670
|
|
|
597
671
|
- Page to server: `hello {visible, focus?}`, `visibility`, `focus {room?}`, `send {id, room, text, uploads?}`, `stop {room}`, `approval {prompt, approved}`, `answer {prompt, answer}`, `answers {prompt, answers, note?}`, `cancel {prompt}`.
|
|
598
672
|
- Server to page: `ready {protocol, principal, name, uploads: {perMessage, maxBytes}}` (then every open card), `accepted`, `refused {id?, prompt?, code}` (`id` names a refused `send`, `prompt` a refused answer to a card), `message`, `progress` (only for the focused room), `activity {room, typing, stoppable, phase?, agent?, outcome?}` (`phase` is `working` during a tool call and `thinking` otherwise; `agent` names the member speaking in a group round; `outcome` is `done` or `failed` and comes only on the frame where `typing` turns false), `presence {agents: {<name>: {busy}}}` (after `ready` and when it changes; `busy` includes work in Discord channels), `edited` (a stored message changed its text, such as a thread's start line once the thread exists), `prompt`, `prompt_closed {prompt, outcome, note?, by?, answer?, closedAt?}`, `mode`, `auto_approved`, `changed`.
|
|
599
|
-
- REST under `<mount>/api/`: `session`, `rooms`, `rooms/<key>/messages?before=&limit=` (`{messages, more, cards}`: the cards of the room that opened within the page's span, from the first message's time on, or from the beginning when `more` is false, and before the first message of the next page), `PUT rooms/<key>/mode`, `POST rooms/<key>/start-over`, `POST uploads`, `DELETE uploads/<id>`, `files/<id>`, `schedules` (`GET`, and `DELETE schedules/<id>`), `agents/<name>` (`GET`, `PATCH`), `PUT agents/<name>/character` (body `{character}`, at most 4 KiB; `400 {error, field}` for a look that is not a character), `models`, and for push `GET push/key`, `GET`, `POST` and `DELETE push/subscriptions` and `DELETE push/subscriptions/<id>`. The agents' pictures are at `<mount>/avatars/<hash>.png`.
|
|
673
|
+
- REST under `<mount>/api/`: `session`, `rooms`, `rooms/<key>/messages?before=&limit=` (`{messages, more, cards}`: the cards of the room that opened within the page's span, from the first message's time on, or from the beginning when `more` is false, and before the first message of the next page), `PUT rooms/<key>/mode`, `PUT rooms/<key>/mute` (body `{muted: boolean}`; the room's push is off for every owner while true; a waiting card still pushes), `POST rooms/<key>/start-over`, `POST uploads`, `DELETE uploads/<id>`, `files/<id>`, `schedules` (`GET`, and `DELETE schedules/<id>`), `agents/<name>` (`GET`, `PATCH`), `PUT agents/<name>/character` (body `{character}`, at most 4 KiB; `400 {error, field}` for a look that is not a character), `models`, `workspace` (the [files pane](#the-files-pane)'s calls), and for push `GET push/key`, `GET`, `POST` and `DELETE push/subscriptions` and `DELETE push/subscriptions/<id>`. The agents' pictures are at `<mount>/avatars/<hash>.png`.
|
|
600
674
|
- Beside the API: `<mount>/manifest.webmanifest`, `<mount>/sw.js`, `<mount>/icons/<name>.png`, `<mount>/theme-init.js`, and in password mode `<mount>/login`, `POST <mount>/auth/login` and `POST <mount>/auth/logout`.
|
|
601
675
|
|
|
602
676
|
A room key from a page must be one of the app's rooms whose agent or group exists; every other key, Discord's included, is refused. Every write needs an owner, whose tier is read again, and REST writes also need the console's `Origin`. A card can be answered by any owner, except a card that is the speaker's alone, which only the speaker's principal answers. After `cardGraceSeconds` (default 120) a turn goes on without the answer and the card stays open for a day; an answer then starts a new turn in the room. The types are in `src/api-types.ts`.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{o,yt,c,r,m,e,i,l,W,pt,En}from"./chunk-index-ckgbszwt.js";var k=()=>typeof matchMedia==="function"&&matchMedia("(max-width: 719px)").matches,x={rtMenu:!0},g=()=>Boolean(window.history.state?.rtMenu),E=8,y=(n)=>n?.isConnected?n:null;function b(n){return n.items.map((t)=>i("button",{type:"button",role:t.checked===void 0?"menuitem":"menuitemcheckbox",...t.checked===void 0?{}:{"aria-checked":t.checked},className:"menu-item menu-link","data-tone":t.tone,onClick:()=>n.onChoose(t),children:[t.icon?e("span",{className:"menu-icon","data-tone":t.tone,children:e(l,{name:t.icon,size:18})}):null,e("span",{className:"menu-text",children:e("strong",{children:t.label})}),t.checked?e(l,{name:"check",size:18,className:"menu-check"}):null]},t.id))}function H({menu:n}){let t=c(void 0);if(n)t.current=n;let u=t.current,f=c(!1),v=c(void 0),p=n?.serial;return o(()=>{if(p===void 0)return;return window.history.pushState(x,"",window.location.href),f.current=!0,()=>{if(f.current)f.current=!1,window.history.back()}},[p]),o(()=>{let h=()=>{if(!f.current||g())return;f.current=!1,pt();let M=v.current;v.current=void 0,M?.()};return window.addEventListener("popstate",h),()=>window.removeEventListener("popstate",h)},[]),e(W,{open:n!==void 0,title:u?.title??"",onClose:pt,restoreFocus:()=>y(u?.source??null),children:u?e("div",{className:"menu action-items",role:"menu","aria-label":u.title,children:e(b,{items:u.items,onChoose:(h)=>{if(!f.current){pt(),h.run();return}v.current=h.run,window.history.back()}})}):null})}function T({menu:n}){let t=c(null),[u,f]=r(n.at),{source:v}=n,p=(s)=>{y(v)?.focus(),pt(),s?.()},h=c(p);h.current=p,yt(()=>{let s=t.current;if(!s)return;let a=s.getBoundingClientRect();f({x:Math.max(E,Math.min(n.at.x,window.innerWidth-a.width-E)),y:Math.max(E,Math.min(n.at.y,window.innerHeight-a.height-E))}),s.querySelector('[role^="menuitem"]')?.focus()},[n.serial]),o(()=>{let s=(d)=>{if(d.target instanceof Node&&t.current?.contains(d.target))return;pt()},a=()=>pt();return document.addEventListener("pointerdown",s,!0),document.addEventListener("wheel",s,{capture:!0,passive:!0}),document.addEventListener("touchmove",s,{capture:!0,passive:!0}),window.addEventListener("resize",a),()=>{document.removeEventListener("pointerdown",s,!0),document.removeEventListener("wheel",s,!0),document.removeEventListener("touchmove",s,!0),window.removeEventListener("resize",a)}},[]);let M=(s)=>{let a=[...t.current?.querySelectorAll('[role^="menuitem"]')??[]],d=a.indexOf(document.activeElement),w=(L)=>{s.preventDefault(),a[(L+a.length)%a.length]?.focus()};switch(s.key){case"Escape":s.preventDefault(),s.stopPropagation(),h.current();return;case"ArrowDown":return w(d+1);case"ArrowUp":return w(d<0?-1:d-1);case"Tab":return w(s.shiftKey?d<0?-1:d-1:d+1);case"Home":return w(0);case"End":return w(-1)}};return e("div",{ref:t,className:"action-popover",role:"menu","aria-label":n.title,tabIndex:-1,style:{left:`${u.x}px`,top:`${u.y}px`},onKeyDown:M,children:e(b,{items:n.items,onChoose:(s)=>p(s.run)})})}function I(){let n=En(),t=c(void 0);if(n&&t.current?.serial!==n.serial)t.current={serial:n.serial,sheet:k()};let u=Boolean(n&&t.current?.sheet);return i(m,{children:[e(H,{menu:u?n:void 0}),n&&!u?e(T,{menu:n},n.serial):null]})}export{I as ActionMenuHost};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{o,e,re,f,P,Re}from"./chunk-index-ckgbszwt.js";function g({name:r}){let m=f((i)=>i.listed),t=f((i)=>Object.values(i.rooms).find((n)=>n.view?.kind==="agent"&&n.view.name===r)?.view?.key,r);return o(()=>{if(t)re("room",t,{replace:!0}),Re(r);else if(m)re("rooms",void 0,{replace:!0})},[t,m,r]),e("div",{className:"page",children:e(P,{})})}export{g as AgentPage};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import{Q,Ge,ie,o,Oe,q,c,r,t,s,e,i,l,f,ae,W,P,S,y,d,b,vt,on,Cn,An}from"./chunk-index-ckgbszwt.js";import{lt}from"./chunk-index-mpm90318.js";import{st}from"./chunk-index-87h45frg.js";function U(n,m){let a=n.split(`
|
|
2
|
+
`),k=m.split(`
|
|
3
|
+
`),h=0;while(h<a.length&&h<k.length&&a[h]===k[h])h++;let g=0;while(g<a.length-h&&g<k.length-h&&a[a.length-1-g]===k[k.length-1-g])g++;let N=a.slice(h,a.length-g),w=k.slice(h,k.length-g),u=a.slice(0,h).map((v)=>({kind:"same",text:v}));return u.push(...me(N,w)),u.push(...a.slice(a.length-g).map((v)=>({kind:"same",text:v}))),u}function me(n,m){let a=(v)=>v.map((L)=>({kind:"del",text:L})),k=(v)=>v.map((L)=>({kind:"add",text:L}));if(n.length===0)return k(m);if(m.length===0)return a(n);if(n.length*m.length>4000000)return[...a(n),...k(m)];let h=m.length+1,g=new Uint32Array((n.length+1)*h);for(let v=n.length-1;v>=0;v--)for(let L=m.length-1;L>=0;L--)g[v*h+L]=n[v]===m[L]?(g[(v+1)*h+L+1]??0)+1:Math.max(g[(v+1)*h+L]??0,g[v*h+L+1]??0);let N=[],w=0,u=0;while(w<n.length&&u<m.length)if(n[w]===m[u])N.push({kind:"same",text:n[w]}),w++,u++;else if((g[(w+1)*h+u]??0)>=(g[w*h+u+1]??0))N.push({kind:"del",text:n[w]}),w++;else N.push({kind:"add",text:m[u]}),u++;return N.push(...a(n.slice(w)),...k(m.slice(u))),N}function X(n){return{added:n.filter((m)=>m.kind==="add").length,removed:n.filter((m)=>m.kind==="del").length}}var ce=ie(()=>(Q("8q6ympxj"),import("./chunk-character-creator-8q6ympxj.js")).then((n)=>({default:n.CharacterCreator}))),fe=["default","off","minimal","low","medium","high","xhigh"],ee={default:s("Follow the assistant (automatic)"),off:s("Off"),minimal:s("Minimal"),low:s("Low"),medium:s("Medium"),high:s("High"),xhigh:s("Very high")},C="default",E=(n)=>t(ee[n]??n),J=(n)=>({displayName:n.displayName,prompt:n.prompt,model:n.model??C,thinking:n.thinking??C});function Y(n,m){return{...m.displayName!==n.displayName?{displayName:m.displayName}:{},...m.prompt!==n.prompt?{prompt:m.prompt}:{},...m.model!==(n.model??C)?{model:m.model}:{},...m.thinking!==(n.thinking??C)?{thinking:m.thinking}:{}}}function Ee(){let n=An(),m=c(n);if(n)m.current=n;let a=m.current,k=n!==void 0;if(o(()=>{if(!k)return;let h=window.location.href,g=()=>{if(window.location.href!==h)on()};return window.addEventListener("popstate",g),window.addEventListener("hashchange",g),()=>{window.removeEventListener("popstate",g),window.removeEventListener("hashchange",g)}},[k]),!a)return null;return e(W,{open:n!==void 0,title:t("Edit agent"),size:"wide",onClose:on,children:e(ue,{name:a.name,opened:a.id},a.name)})}function ue({name:n,opened:m}){let[a,k]=r(),[h,g]=r([]),[N,w]=r(),[u,v]=r(),[L,R]=r(!1),[te,x]=r(!1),[ne,F]=r(!1),se=vt(a?.room??""),M=c(null),T=a!==void 0,V=f((p)=>a?p.rooms[a.room]?.view?.muted===!0:!1,a?.room??""),[oe,H]=r(!1),O=Oe(),B=Oe(),K=Oe();o(()=>{if(!T||!Cn()?.look)return;M.current?.scrollIntoView({block:"start"}),M.current?.focus({preventScroll:!0})},[T,m]);let _=c({});_.current={profile:a,draft:u},o(()=>{let p=!0;return Promise.all([d.agent(n),d.models()]).then(([D,re])=>{if(!p)return;let{profile:G,draft:I}=_.current,de=G&&I&&Object.keys(Y(G,I)).length>0;k(D),g(re.models),v(de?I:J(D))},(D)=>p&&w(b(D))),()=>{p=!1}},[n,m]);let A=q(()=>a&&u?Y(a,u):{},[a,u]);if(N)return e(S,{message:N});if(!a||!u)return e(P,{});let j=Object.keys(A).length>0,le=Array.from(new Set([C,...h,u.model])),z=async()=>{R(!0);try{let p=await d.updateAgent(n,A);k(p),v(J(p)),x(!1),y(t("Saved."))}catch(p){y(b(p),"danger")}finally{R(!1)}};return i("div",{className:"stack agent-sheet",children:[i("header",{className:"profile-head",children:[e(ae,{spec:a.character,name:a.name,size:72,state:se,label:a.displayName}),i("div",{children:[e("h3",{children:a.displayName}),e("p",{className:"meta",children:t("Runs on {model}, thinking {thinking}",{model:a.effective.model,thinking:E(a.effective.thinking)})})]})]}),e("ul",{className:"menu",children:e("li",{children:i("label",{className:"menu-item menu-toggle",htmlFor:K,children:[e("span",{className:"menu-icon",children:e(l,{name:V?"bell-off":"bell"})}),i("span",{className:"menu-text",children:[e("strong",{children:t("Notifications")}),e("span",{className:"meta",children:t("Push this room's posts to every owner's devices. A card that waits for you is always pushed.")})]}),e(lt,{id:K,checked:!V,label:t("Notifications"),busy:oe,onChange:async(p)=>{H(!0),await st(a.room,!p),H(!1)}})]})})}),te?e(ge,{profile:a,draft:u,saving:L,onBack:()=>x(!1),onSave:z}):i("form",{className:"stack form",onSubmit:(p)=>{if(p.preventDefault(),!j)return;if(A.prompt!==void 0)x(!0);else z()},children:[i("label",{htmlFor:B,children:[t("Name"),e("input",{id:B,value:u.displayName,onChange:(p)=>v({...u,displayName:p.target.value})})]}),i("div",{className:"field",children:[i("div",{className:"field-head",children:[e("label",{htmlFor:O,children:t("Prompt")}),i("button",{type:"button",className:"secondary compact","aria-haspopup":"dialog",onClick:()=>F(!0),children:[e(pe,{}),t("Full screen")]})]}),e("textarea",{id:O,rows:8,value:u.prompt,onChange:(p)=>v({...u,prompt:p.target.value})})]}),e(Z,{label:t("Model"),value:u.model,onChange:(p)=>v({...u,model:p}),options:le.map((p)=>({value:p,label:p===C?t("Follow the assistant"):p}))}),e(Z,{label:t("Thinking level"),value:u.thinking,onChange:(p)=>v({...u,thinking:p}),options:fe.map((p)=>({value:p,label:t(ee[p])}))}),e("div",{className:"actions",children:e("button",{type:"submit",disabled:!j||L,children:L?t("Saving…"):A.prompt!==void 0?t("Review changes"):t("Save")})})]}),i("section",{className:"card stack",ref:M,tabIndex:-1,children:[e("h3",{children:t("Look")}),e("p",{className:"meta",children:t("Class, colors and parts. The picture here, in the rooms and in Discord all follow it.")}),e(Ge,{fallback:e(P,{}),children:e(ce,{name:a.name,displayName:a.displayName,prompt:a.prompt,character:a.character,onSaved:(p)=>k(p)})})]}),e(W,{open:ne,title:t("Prompt"),size:"full",onClose:()=>F(!1),children:e("textarea",{className:"prompt-full","aria-label":t("Prompt"),value:u.prompt,onChange:(p)=>v({...u,prompt:p.target.value})})})]})}var pe=()=>e("svg",{viewBox:"0 0 24 24",width:16,height:16,fill:"none",stroke:"currentColor",strokeWidth:1.8,strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",focusable:"false",children:e("path",{d:"M4 9V4h5M20 9V4h-5M4 15v5h5M20 15v5h-5"})});function Z(n){return i("fieldset",{className:"field",children:[e("legend",{children:n.label}),e("div",{className:"option-chips",children:n.options.map((m)=>e("button",{type:"button","aria-pressed":m.value===n.value,className:"option-chip",onClick:()=>n.onChange(m.value),children:m.label},m.value))})]})}var he={same:" ",add:"+",del:"−"};function ge(n){let{profile:m,draft:a}=n,k=c(null);o(()=>k.current?.focus(),[]);let h=q(()=>U(m.prompt,a.prompt),[m.prompt,a.prompt]),g=X(h),N=[];if(a.displayName!==m.displayName)N.push({label:t("Name"),before:m.displayName,after:a.displayName});let w=(u)=>u===C?t("Follow the assistant"):u;if(a.model!==(m.model??C))N.push({label:t("Model"),before:w(m.model??C),after:w(a.model)});if(a.thinking!==(m.thinking??C))N.push({label:t("Thinking level"),before:E(m.thinking??C),after:E(a.thinking)});return i("section",{ref:k,className:"stack review",tabIndex:-1,"aria-label":t("Review changes"),children:[e("h3",{children:t("Review changes")}),N.length?e("ul",{className:"review-fields",children:N.map((u)=>i("li",{children:[e("strong",{children:u.label}),e("span",{className:"review-before",children:u.before}),e("span",{"aria-hidden":"true",children:"→"}),e("span",{className:"review-after",children:u.after})]},u.label))}):null,i("div",{className:"field",children:[i("span",{className:"field-label",children:[t("Prompt")," ·"," ",t("Lines: {added} added, {removed} removed",{added:g.added,removed:g.removed})]}),e("pre",{className:"diff",children:h.map((u,v)=>i("span",{className:"diff-line","data-kind":u.kind,children:[e("span",{className:"diff-mark","aria-hidden":"true",children:he[u.kind]}),u.kind==="add"||u.kind==="del"?i("span",{className:"visually-hidden",children:[u.kind==="add"?t("Added"):t("Removed"),":"," "]}):null,u.text||" "]},v))})]}),i("div",{className:"actions",children:[e("button",{type:"button",className:"secondary",disabled:n.saving,onClick:n.onBack,children:t("Back to editing")}),e("button",{type:"button",disabled:n.saving,onClick:n.onSave,children:n.saving?t("Saving…"):t("Save")})]})]})}export{Ee as AgentSheetHost};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{_e,rt,X,Lt,jt}from"./chunk-index-5y2r0eaj.js";import{ce,an,o,Oe,q,c,r,t,s,m,e,i,Ct,bt,ae,W,y,ht,d,b,Pe,Me,ge}from"./chunk-index-ckgbszwt.js";var le={"hat.none":"No hat","hat.goggcap":"Leather cap","hat.tallcap":"Burgundian felt cap","hat.softcap":"Soft cap","hat.hardhat":"Iron skullcap","hat.fcap":"Hunter's cap","hat.winghelm":"Winged helm","hat.helm":"Helm","hat.mortar":"Biretta","hat.beret":"Chaperon","hat.goggles":"Pointed cap","hat.tricorn":"Pilgrim hat","hat.sailor":"Straw hat","hat.kettle":"Kettle hat","hat.cavalier":"Feathered hat","hat.toque":"Linen cook's cap","hair.none":"No hair","beard.none":"No beard","accessory.none":"No accessory","prop.beads":"Prayer beads","prop.marotte":"Marotte","prop.map":"Chart","prop.flask":"Alchemist's phial","prop.telescope":"Astrolabe","prop.wrench":"Dividers","outfit.surplice":"Surplice","outfit.overalls":"Work jerkin","outfit.armor":"Mail hauberk","outfit.apron":"Smith's apron","outfit.chef":"Cook's tunic","outfit.coat":"Doublet","outfit.vest":"Pourpoint","outfit.sailor":"Mariner's tunic","hair.bob":"Bob","hair.bun":"Bun","hair.ponytail":"Ponytail"},U=(a)=>a.charAt(0).toUpperCase()+a.slice(1);function N(a,l){let h=`character.${a}.${l}`,p=t(h);if(p!==h)return p;if(a==="class")return X.classes[l]?.label??U(l);return le[`${a}.${l}`]??U(l)}function V(a){let l=`character.jobs.${a}`,h=t(l);return h!==l?h:X.classes[a]?.jobs??""}var H=[{field:"hat",title:s("Hat"),ids:X.hats},{field:"outfit",title:s("Outfit"),ids:X.outfits},{field:"prop",title:s("Prop"),ids:X.props},{field:"hair",title:s("Hair"),ids:X.hair},{field:"beard",title:s("Beard"),ids:["none",...X.beards]},{field:"accessory",title:s("Accessory"),ids:["none",...X.accessories]}],de=new Set(["class","colors","palette","build","skin","hairColor",...H.map((a)=>a.field)]),Z=Object.keys(X.palettes),x={idle:s("Idle"),thinking:s("Thinking"),working:s("Working"),waiting:s("Waiting for you"),done:s("Done"),error:s("Error"),sleepy:s("Sleepy")},ue={slim:s("Slim"),regular:s("Regular"),stout:s("Stout")};function ee(a){return{class:a.class,outfit:a.outfit,hat:a.hat,prop:a.prop,hair:a.hair,beard:a.beard,accessory:a.accessory,build:a.build,skin:a.skin,hairColor:a.hairColor,colors:{...a.colors}}}var Q=(a)=>JSON.stringify(ee(a)),v=(a)=>a[Math.floor(Math.random()*a.length)];function fe(){return{class:v(_e),outfit:v(X.outfits),hat:v(X.hats),prop:v(X.props),hair:v(X.hair),beard:v(["none",...X.beards]),accessory:v(["none",...X.accessories]),build:v(["slim","regular","stout"]),skin:v([0,1,2,3,4,5]),hairColor:v(X.hairColors),palette:v(Z)}}var te=ce(function(l){return i("button",{type:"button",className:"creator-tile","aria-pressed":l.pressed,title:l.hint?`${l.label} — ${l.hint}`:l.label,onClick:l.onPick,...l.data,children:[e(ae,{spec:l.spec,size:l.size,live:!1}),e("span",{children:l.label})]})});function me(a,l,h){let p=JSON.stringify({...a,[l]:0});return q(()=>h.map((u)=>({...a,[l]:u})),[p,l,h])}function he(){let a=c(null),[l,h]=r();return o(()=>{let p=a.current;if(!p)return;let u=()=>{let S=p.scrollLeft>1,P=p.scrollLeft+p.clientWidth<p.scrollWidth-1;h(S&&P?"both":P?"end":S?"start":void 0)};u(),p.addEventListener("scroll",u,{passive:!0});let g=typeof ResizeObserver>"u"?void 0:new ResizeObserver(u);return g?.observe(p),()=>{p.removeEventListener("scroll",u),g?.disconnect()}},[]),[a,l]}function pe(a){let{part:l}=a,h=me(a.shown,l.field,l.ids),[p,u]=he();return e("div",{className:"creator-strip",ref:p,"data-more":u,children:l.ids.map((g,S)=>e(te,{data:{[`data-${l.field}`]:g},spec:h[S],size:44,label:N(l.field,g),pressed:a.draft[l.field]===g,onPick:()=>a.onPick(g)},g))})}function B(a){return e("button",{type:"button",className:"creator-swatch","aria-pressed":a.pressed,"aria-label":a.label,title:a.label,style:{background:a.background},onClick:a.onPick,...a.data})}function L(a){return i("div",{className:"creator-field","data-field":a.field,children:[a.title?e("h3",{children:a.title}):null,a.children,a.error?e("p",{className:"field-error",role:"alert",children:a.error}):null]})}function He(a){let[l,h]=r(a.character),p=an(l),[u,g]=r({}),[S,P]=r(!1),[T,re]=r("idle"),[K,E]=r(),[R,M]=r(),O=Pe("(max-width: 719px)"),z=c(null),I=Oe(),ie=Me(l),ne=bt(),w=Q(l)!==Q(a.character);o(()=>h(a.character),[a.character]),o(()=>{if(!w)return;let n=(k)=>k.preventDefault(),f=(k)=>{if(k.button!==0||k.metaKey||k.ctrlKey||k.shiftKey||k.altKey)return;let A=k.target instanceof Element?k.target.closest("a"):null;if(!A||A.target||A.hasAttribute("download"))return;if(z.current?.contains(A))return;k.preventDefault(),k.stopPropagation(),E({kind:"link",anchor:A})},F=Ct((k)=>E({kind:"navigate",proceed:k}));return window.addEventListener("beforeunload",n),document.addEventListener("click",f,!0),()=>{F(),window.removeEventListener("beforeunload",n),document.removeEventListener("click",f,!0)}},[w]);let C=(n)=>{g({}),h((f)=>Lt(n,f))},oe=async()=>{P(!0),g({});try{let n=await d.setCharacter(a.name,ee(l));a.onSaved(n),y(t("Saved."))}catch(n){let f=n instanceof ht&&n.field?n.field.split(".")[0]:void 0,F=f&&de.has(f)?f:"*";g({[F]:b(n)})}finally{P(!1)}},se=async()=>{let n=K;if(h(a.character),g({}),n?.kind==="link")setTimeout(()=>n.anchor.click(),0);else if(n?.kind==="navigate")n.proceed()},_=e(L,{field:"class",title:t("Class"),error:u.class,children:e("div",{className:"creator-grid",children:_e.map((n)=>e(be,{id:n,base:p,pressed:l.class===n,onPick:()=>C({class:n,colors:l.colors})},n))})}),j=i(L,{field:"colors",title:t("Colors"),error:u.colors??u.palette,children:[i("fieldset",{className:"creator-swatches",children:[e("legend",{className:"visually-hidden",children:t("Palette")}),Z.map((n)=>{let f=X.palettes[n];return e(B,{data:{"data-palette":n},label:N("palette",n),pressed:l.palette===n,background:`linear-gradient(135deg, ${f.primary} 52%, ${f.trim} 52%)`,onPick:()=>C({palette:n})},n)})]}),e("div",{className:"creator-custom",children:["primary","secondary","trim"].map((n)=>i("label",{children:[e("span",{children:n==="primary"?t("Primary (the accent)"):n==="secondary"?t("Secondary"):t("Trim")}),e("input",{type:"color",value:l.colors[n],onChange:(f)=>C({colors:{[n]:f.target.value}})})]},n))})]}),G=H.map((n)=>e(L,{field:n.field,title:t(n.title),error:u[n.field],children:e(pe,{part:n,draft:l,shown:p,onPick:(f)=>C({[n.field]:f})})},n.field)),J=i(m,{children:[e(L,{field:"build",title:t("Build"),error:u.build,children:i("fieldset",{className:"segmented",children:[e("legend",{className:"visually-hidden",children:t("Build")}),["slim","regular","stout"].map((n)=>i("label",{"data-checked":l.build===n,children:[e("input",{type:"radio",name:`${I}-build`,checked:l.build===n,onChange:()=>C({build:n})}),Y(n)]},n))]})}),e(L,{field:"skin",title:t("Skin tone"),error:u.skin,children:i("fieldset",{className:"creator-swatches",children:[e("legend",{className:"visually-hidden",children:t("Skin tone")}),(ne??X.skins).map((n,f)=>e(B,{data:{"data-skin":String(f)},label:t("Skin tone {n}",{n:f+1}),pressed:l.skin===f,background:n,onPick:()=>C({skin:f})},f))]})}),e(L,{field:"hairColor",title:t("Hair color"),error:u.hairColor,children:i("fieldset",{className:"creator-swatches",children:[e("legend",{className:"visually-hidden",children:t("Hair color")}),X.hairColors.map((n,f)=>e(B,{data:{"data-hair-color":n},label:t("Hair color {n}",{n:f+1}),pressed:l.hairColor===n,background:n,onPick:()=>C({hairColor:n})},n)),e("input",{type:"color","aria-label":t("Hair color"),value:l.hairColor,onChange:(n)=>C({hairColor:n.target.value})})]})})]}),D=[{id:"class",title:t("Class"),summary:N("class",l.class),error:u.class,node:_},{id:"colors",title:t("Colors"),summary:l.palette?N("palette",l.palette):l.colors.primary,error:u.colors??u.palette,node:j},...H.map((n,f)=>({id:n.field,title:t(n.title),summary:N(n.field,l[n.field]),error:u[n.field],node:G[f]})),{id:"body",title:t("Body"),summary:Y(l.build),error:u.build??u.skin??u.hairColor,node:J}];return i("form",{ref:z,className:"creator",style:ie,"aria-labelledby":I,onSubmit:(n)=>{if(n.preventDefault(),w&&!S)oe()},children:[e("h2",{id:I,className:"visually-hidden",children:t("Character of {name}",{name:a.displayName})}),i("div",{className:"creator-preview",children:[e(ae,{spec:l,name:a.name,state:T,size:176,label:t("{name}, {state}",{name:a.displayName,state:t(x[T])})}),e("button",{type:"button",className:"secondary","data-action":"cycle",onClick:()=>re((n)=>rt[(rt.indexOf(n)+1)%rt.length]??"idle"),children:t("Preview states")}),e("span",{className:"meta","aria-live":"polite",children:t(x[T])})]}),i("div",{className:"creator-body",children:[u["*"]?e("p",{className:"field-error",role:"alert","data-field":"*",children:u["*"]}):null,O?e("ul",{className:"creator-sections",children:D.map((n)=>e("li",{children:i("button",{type:"button",className:"creator-section secondary",onClick:()=>M(n.id),children:[e("strong",{children:n.title}),e("span",{className:"meta",children:n.summary}),n.error?e("span",{className:"field-error",role:"alert",children:n.error}):null]})},n.id))}):i(m,{children:[_,j,G,J]}),i("div",{className:"actions creator-actions",children:[e("button",{type:"button",className:"secondary","data-action":"suggest",onClick:()=>{g({}),h(jt({name:a.name,displayName:a.displayName,prompt:a.prompt}))},children:t("Suggest from role")}),e("button",{type:"button",className:"secondary","data-action":"randomize",onClick:()=>C(fe()),children:t("Randomize")}),e("button",{type:"button",className:"secondary","data-action":"cancel",onClick:()=>{if(w)E({kind:"cancel"})},children:t("Cancel")}),e("button",{type:"submit","data-action":"save",disabled:!w||S,children:S?t("Saving…"):t("Save")})]})]}),e(W,{open:O&&R!==void 0,title:D.find((n)=>n.id===R)?.title??"",onClose:()=>M(void 0),children:e("div",{className:"stack",children:D.find((n)=>n.id===R)?.node})}),e(ge,{open:K!==void 0,title:t("Discard your changes?"),confirmLabel:t("Discard"),cancelLabel:t("Keep editing"),tone:"danger",onClose:()=>E(void 0),onConfirm:se,children:e("p",{children:t("The new look for {name} has not been saved.",{name:a.displayName})})})]})}var Y=(a)=>t(ue[a]);function be(a){let l=a.base.colors,h=q(()=>Lt({class:a.id,colors:l}),[a.id,l]);return e(te,{data:{"data-class":a.id},spec:h,size:56,label:N("class",a.id),hint:V(a.id),pressed:a.pressed,onPick:a.onPick})}export{He as CharacterCreator};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{M,J,It,gn,Dt,Xe,ee,a,h,de,ye,Je,be,C,Y,H,T,Ie,De,ve,te,v,F,fe,u,Fe,yn,bn,vn,Ut,Tt,xn,Sn,wn,_n,p,n,x,Qe,nt,Mt,nn,mt,Ot,Qn,Pn,Ne}from"./chunk-index-t1m65yn6.js";import{Q}from"./chunk-index-ckgbszwt.js";var hn=(e)=>{let{state:t}=e,r=t.doc.lineAt(t.selection.main.from),o=Ee(e.state,r.from);return o.line?fn(e):o.block?mn(e):!1};function Be(e,t){return({state:r,dispatch:o})=>{if(r.readOnly)return!1;let l=e(t,r);if(!l)return!1;return o(r.update(l)),!0}}var fn=Be(Cn,0);var dn=Be(lt,0);var mn=Be((e,t)=>lt(e,t,kn(t)),0);function Ee(e,t){let r=e.languageDataAt("commentTokens",t,1);return r.length?r[0]:{}}var U=50;function pn(e,{open:t,close:r},o,l){let i=e.sliceDoc(o-U,o),s=e.sliceDoc(l,l+U),c=/\s*$/.exec(i)[0].length,f=/^\s*/.exec(s)[0].length,m=i.length-c;if(i.slice(m-t.length,m)==t&&s.slice(f,f+r.length)==r)return{open:{pos:o-c,margin:c&&1},close:{pos:l+f,margin:f&&1}};let d,g;if(l-o<=2*U)d=g=e.sliceDoc(o,l);else d=e.sliceDoc(o,o+U),g=e.sliceDoc(l-U,l);let y=/^\s*/.exec(d)[0].length,W=/\s*$/.exec(g)[0].length,B=g.length-W-r.length;if(d.slice(y,y+t.length)==t&&g.slice(B,B+r.length)==r)return{open:{pos:o+y+t.length,margin:/\s/.test(d.charAt(y+t.length))?1:0},close:{pos:l-W-r.length,margin:/\s/.test(g.charAt(B-1))?1:0}};return null}function kn(e){let t=[];for(let r of e.selection.ranges){let o=e.doc.lineAt(r.from),l=r.to<=o.to?o:e.doc.lineAt(r.to);if(l.from>o.from&&l.from==r.to)l=r.to==o.to+1?o:e.doc.lineAt(r.to-1);let i=t.length-1;if(i>=0&&t[i].to>o.from)t[i].to=l.to;else t.push({from:o.from+/^\s*/.exec(o.text)[0].length,to:l.to})}return t}function lt(e,t,r=t.selection.ranges){let o=r.map((i)=>Ee(t,i.from).block);if(!o.every((i)=>i))return null;let l=r.map((i,s)=>pn(t,o[s],i.from,i.to));if(e!=2&&!l.every((i)=>i))return{changes:t.changes(r.map((i,s)=>{if(l[s])return[];return[{from:i.from,insert:o[s].open+" "},{from:i.to,insert:" "+o[s].close}]}))};else if(e!=1&&l.some((i)=>i)){let i=[];for(let s=0,c;s<l.length;s++)if(c=l[s]){let f=o[s],{open:m,close:d}=c;i.push({from:m.pos-f.open.length,to:m.pos+m.margin},{from:d.pos-d.margin,to:d.pos+f.close.length})}return{changes:i}}return null}function Cn(e,t,r=t.selection.ranges){let o=[],l=-1;e:for(let{from:i,to:s}of r){let c=o.length,f=1e9,m;for(let d=i;d<=s;){let g=t.doc.lineAt(d);if(m==null){if(m=Ee(t,g.from).line,!m)continue e}if(g.from>l&&(i==s||s>g.from)){l=g.from;let y=/^\s*/.exec(g.text)[0].length,W=y==g.length,B=g.text.slice(y,y+m.length)==m?y:-1;if(y<g.text.length&&y<f)f=y;o.push({line:g,comment:B,token:m,indent:y,empty:W,single:!1})}d=g.to+1}if(f<1e9){for(let d=c;d<o.length;d++)if(o[d].indent<o[d].line.text.length)o[d].indent=f}if(o.length==c+1)o[c].single=!0}if(e!=2&&o.some((i)=>i.comment<0&&(!i.empty||i.single))){let i=[];for(let{line:c,token:f,indent:m,empty:d,single:g}of o)if(g||!d)i.push({from:c.from+m,insert:f+" "});let s=t.changes(i);return{changes:s,selection:t.selection.map(s,1)}}else if(e!=1&&o.some((i)=>i.comment>=0)){let i=[];for(let{line:s,comment:c,token:f}of o)if(c>=0){let m=s.from+c,d=m+f.length;if(s.text[d-s.from]==" ")d++;i.push({from:m,to:d})}return{changes:i}}return null}var Me=be.define(),Mn=be.define(),An=h.define(),it=h.define({combine(e){return Ie(e,{minDepth:100,newGroupDelay:500,joinToEvent:(t,r)=>r},{minDepth:Math.max,newGroupDelay:Math.min,joinToEvent:(t,r)=>(o,l)=>t(o,l)||r(o,l)})}}),st=de.define({create(){return w.empty},update(e,t){let r=t.state.facet(it),o=t.annotation(Me);if(o){let f=k.fromTransaction(t,o.selection),m=o.side,d=m==0?e.undone:e.done;if(f)d=Z(d,d.length,r.minDepth,f);else d=ut(d,t.startState.selection);return new w(m==0?o.rest:d,m==0?d:o.rest)}let l=t.annotation(Mn);if(l=="full"||l=="before")e=e.isolate();if(t.annotation(Y.addToHistory)===!1)return!t.changes.empty?e.addMapping(t.changes.desc):e;let i=k.fromTransaction(t),s=t.annotation(Y.time),c=t.annotation(Y.userEvent);if(i)e=e.addChanges(i,s,c,r,t);else if(t.selection)e=e.addSelection(t.startState.selection,s,c,r.newGroupDelay);if(l=="full"||l=="after")e=e.isolate();return e},toJSON(e){return{done:e.done.map((t)=>t.toJSON()),undone:e.undone.map((t)=>t.toJSON())}},fromJSON(e){return new w(e.done.map(k.fromJSON),e.undone.map(k.fromJSON))}});function ct(e={}){return[st,it.of(e),u.domEventHandlers({beforeinput(t,r){let o=t.inputType=="historyUndo"?re:t.inputType=="historyRedo"?z:null;if(!o)return!1;return t.preventDefault(),o(r)}})]}function ne(e,t){return function({state:r,dispatch:o}){if(!t&&r.readOnly)return!1;let l=r.field(st,!1);if(!l)return!1;let i=l.pop(e,r,t);if(!i)return!1;return o(i),!0}}var re=ne(0,!1),z=ne(1,!1),Ln=ne(0,!0),Bn=ne(1,!0);class k{constructor(e,t,r,o,l){this.changes=e,this.effects=t,this.mapped=r,this.startSelection=o,this.selectionsAfter=l}setSelAfter(e){return new k(this.changes,this.effects,this.mapped,this.startSelection,e)}toJSON(){var e,t,r;return{changes:(e=this.changes)===null||e===void 0?void 0:e.toJSON(),mapped:(t=this.mapped)===null||t===void 0?void 0:t.toJSON(),startSelection:(r=this.startSelection)===null||r===void 0?void 0:r.toJSON(),selectionsAfter:this.selectionsAfter.map((o)=>o.toJSON())}}static fromJSON(e){return new k(e.changes&&ee.fromJSON(e.changes),[],e.mapped&&Xe.fromJSON(e.mapped),e.startSelection&&a.fromJSON(e.startSelection),e.selectionsAfter.map(a.fromJSON))}static fromTransaction(e,t){let r=A;for(let o of e.startState.facet(An)){let l=o(e);if(l.length)r=r.concat(l)}if(!r.length&&e.changes.empty)return null;return new k(e.changes.invert(e.startState.doc),r,void 0,t||e.startState.selection,A)}static selection(e){return new k(void 0,A,void 0,void 0,e)}}function Z(e,t,r,o){let l=t+1>r+20?t-r-1:0,i=e.slice(l,t);return i.push(o),i}function Dn(e,t){let r=[],o=!1;return e.iterChangedRanges((l,i)=>r.push(l,i)),t.iterChangedRanges((l,i,s,c)=>{for(let f=0;f<r.length;){let m=r[f++],d=r[f++];if(c>=m&&s<=d)o=!0}}),o}function En(e,t){return e.ranges.length==t.ranges.length&&e.ranges.filter((r,o)=>r.empty!=t.ranges[o].empty).length===0}function at(e,t){return!e.length?t:!t.length?e:e.concat(t)}var A=[],Tn=200;function ut(e,t){if(!e.length)return[k.selection([t])];else{let r=e[e.length-1],o=r.selectionsAfter.slice(Math.max(0,r.selectionsAfter.length-Tn));if(o.length&&o[o.length-1].eq(t))return e;return o.push(t),Z(e,e.length-1,1e9,r.setSelAfter(o))}}function Wn(e){let t=e[e.length-1],r=e.slice();return r[e.length-1]=t.setSelAfter(t.selectionsAfter.slice(0,t.selectionsAfter.length-1)),r}function Ce(e,t){if(!e.length)return e;let r=e.length,o=A;while(r){let l=Rn(e[r-1],t,o);if(l.changes&&!l.changes.empty||l.effects.length){let i=e.slice(0,r);return i[r-1]=l,i}else t=l.mapped,r--,o=l.selectionsAfter}return o.length?[k.selection(o)]:A}function Rn(e,t,r){let o=at(e.selectionsAfter.length?e.selectionsAfter.map((c)=>c.map(t)):A,r);if(!e.changes)return k.selection(o);let l=e.changes.map(t),i=t.mapDesc(e.changes,!0),s=e.mapped?e.mapped.composeDesc(i):i;return new k(l,C.mapEffects(e.effects,t),s,e.startSelection.map(i),o)}var On=/^(input\.type|delete)($|\.)/;class w{constructor(e,t,r=0,o=void 0){this.done=e,this.undone=t,this.prevTime=r,this.prevUserEvent=o}isolate(){return this.prevTime?new w(this.done,this.undone):this}addChanges(e,t,r,o,l){let i=this.done,s=i[i.length-1];if(s&&s.changes&&!s.changes.empty&&e.changes&&(!r||On.test(r))&&(!s.selectionsAfter.length&&t-this.prevTime<o.newGroupDelay&&o.joinToEvent(l,Dn(s.changes,e.changes))||r=="input.type.compose"))i=Z(i,i.length-1,o.minDepth,new k(e.changes.compose(s.changes),at(C.mapEffects(e.effects,s.changes),s.effects),s.mapped,s.startSelection,A));else i=Z(i,i.length,o.minDepth,e);return new w(i,A,t,r)}addSelection(e,t,r,o){let l=this.done.length?this.done[this.done.length-1].selectionsAfter:A;if(l.length>0&&t-this.prevTime<o&&r==this.prevUserEvent&&r&&/^select($|\.)/.test(r)&&En(l[l.length-1],e))return this;return new w(ut(this.done,e),this.undone,t,r)}addMapping(e){return new w(Ce(this.done,e),Ce(this.undone,e),this.prevTime,this.prevUserEvent)}pop(e,t,r){let o=e==0?this.done:this.undone;if(o.length==0)return null;let l=o[o.length-1],i=l.selectionsAfter[0]||(l.startSelection?l.startSelection.map(l.changes.invertedDesc,1):t.selection);if(r&&l.selectionsAfter.length)return t.update({selection:l.selectionsAfter[l.selectionsAfter.length-1],annotations:Me.of({side:e,rest:Wn(o),selection:i}),userEvent:e==0?"select.undo":"select.redo",scrollIntoView:!0});else if(!l.changes)return null;else{let s=o.length==1?A:o.slice(0,o.length-1);if(l.mapped)s=Ce(s,l.mapped);return t.update({changes:l.changes,selection:l.startSelection,effects:l.effects,annotations:Me.of({side:e,rest:s,selection:i}),filter:!1,userEvent:e==0?"undo":"redo",scrollIntoView:!0})}}}w.empty=new w(A,A);var ht=[{key:"Mod-z",run:re,preventDefault:!0},{key:"Mod-y",mac:"Mod-Shift-z",run:z,preventDefault:!0},{linux:"Ctrl-Shift-z",run:z,preventDefault:!0},{key:"Mod-u",run:Ln,preventDefault:!0},{key:"Alt-u",mac:"Mod-Shift-u",run:Bn,preventDefault:!0}];function N(e,t){return a.create(e.ranges.map(t),e.mainIndex)}function D(e,t){return e.update({selection:t,scrollIntoView:!0,userEvent:"select"})}function E({state:e,dispatch:t},r){let o=N(e.selection,r);if(o.eq(e.selection,!0))return!1;return t(D(e,o)),!0}function oe(e,t){return a.cursor(t?e.to:e.from)}function ft(e,t){return E(e,(r)=>r.empty?e.moveByChar(r,t):oe(r,t))}function S(e){return e.textDirectionAt(e.state.selection.main.head)==F.LTR}var dt=(e)=>ft(e,!S(e)),pt=(e)=>ft(e,S(e));function gt(e,t){return E(e,(r)=>r.empty?e.moveByGroup(r,t):oe(r,t))}var Fn=(e)=>gt(e,!S(e)),In=(e)=>gt(e,S(e));var io=typeof Intl<"u"&&Intl.Segmenter?new Intl.Segmenter(void 0,{granularity:"word"}):null;function Nn(e,t,r){if(t.type.prop(r))return!0;let o=t.to-t.from;return o&&(o>2||/[^\s,.;:]/.test(e.sliceDoc(t.from,t.to)))||t.firstChild}function le(e,t,r){let o=x(e).resolveInner(t.head),l=r?p.closedBy:p.openedBy;for(let f=t.head;;){let m=r?o.childAfter(f):o.childBefore(f);if(!m)break;if(Nn(e,m,l))o=m;else f=r?m.to:m.from}let i=o.type.prop(l),s,c;if(i&&(s=r?Ne(e,o.from,1):Ne(e,o.to,-1))&&s.matched)c=r?s.end.to:s.end.from;else c=r?o.to:o.from;return a.cursor(c,r?-1:1)}var qn=(e)=>E(e,(t)=>le(e.state,t,!S(e))),Vn=(e)=>E(e,(t)=>le(e.state,t,S(e)));function yt(e,t){return E(e,(r)=>{if(!r.empty)return oe(r,t);let o=e.moveVertically(r,t);return o.head!=r.head?o:e.moveToLineBoundary(r,t)})}var xt=(e)=>yt(e,!1),St=(e)=>yt(e,!0);function kt(e){let t=e.scrollDOM.clientHeight<e.scrollDOM.scrollHeight-2,r=0,o=0,l;if(t){for(let i of e.state.facet(u.scrollMargins)){let s=i(e);if(s===null||s===void 0?void 0:s.top)r=Math.max(s===null||s===void 0?void 0:s.top,r);if(s===null||s===void 0?void 0:s.bottom)o=Math.max(s===null||s===void 0?void 0:s.bottom,o)}l=e.scrollDOM.clientHeight-r-o}else l=(e.dom.ownerDocument.defaultView||window).innerHeight;return{marginTop:r,marginBottom:o,selfScroll:t,height:Math.max(e.defaultLineHeight,l-5)}}function vt(e,t){let r=kt(e),{state:o}=e,l=N(o.selection,(s)=>s.empty?e.moveVertically(s,t,r.height):oe(s,t));if(l.eq(o.selection))return!1;let i;if(r.selfScroll){let s=e.coordsAtPos(o.selection.main.head),c=e.scrollDOM.getBoundingClientRect(),f=c.top+r.marginTop,m=c.bottom-r.marginBottom;if(s&&s.top>f&&s.bottom<m)i=u.scrollIntoView(l.main.head,{y:"start",yMargin:s.top-f})}return e.dispatch(D(o,l),{effects:i}),!0}var He=(e)=>vt(e,!1),Ae=(e)=>vt(e,!0);function R(e,t,r){let o=e.lineBlockAt(t.head),l=e.moveToLineBoundary(t,r);if(l.head==t.head&&l.head!=(r?o.to:o.from))l=e.moveToLineBoundary(t,r,!1);if(!r&&l.head==o.from&&o.length){let i=/^\s*/.exec(e.state.sliceDoc(o.from,Math.min(o.from+100,o.to)))[0].length;if(i&&t.head!=o.from+i)l=a.cursor(o.from+i)}return l}var Gn=(e)=>E(e,(t)=>R(e,t,!0)),Un=(e)=>E(e,(t)=>R(e,t,!1)),zn=(e)=>E(e,(t)=>R(e,t,!S(e))),Jn=(e)=>E(e,(t)=>R(e,t,S(e))),$n=(e)=>E(e,(t)=>e.moveToLineBoundary(t,!1,!1)),Kn=(e)=>E(e,(t)=>e.moveToLineBoundary(t,!0,!1));function Hn(e,t,r){let o=!1,l=N(e.selection,(i)=>{let s=Ne(e,i.head,-1)||Ne(e,i.head,1)||i.head>0&&Ne(e,i.head-1,1)||i.head<e.doc.length&&Ne(e,i.head+1,-1);if(!s||!s.end)return i;o=!0;let c=s.start.from==i.head?s.end.to:s.end.from;return r?a.range(i.anchor,c):a.cursor(c)});if(!o)return!1;return t(D(e,l)),!0}var jn=({state:e,dispatch:t})=>Hn(e,t,!1);function L(e,t,r){let o=N(e.state.selection,(l)=>{if(l.undirectional&&l.head>=l.anchor!=t)l=a.range(l.head,l.anchor);let i=r(l);return a.range(l.anchor,i.head,i.goalColumn,i.bidiLevel||void 0,i.assoc)});if(o.eq(e.state.selection))return!1;return e.dispatch(D(e.state,o)),!0}function bt(e,t){return L(e,t,(r)=>e.moveByChar(r,t))}var Ct=(e)=>bt(e,!S(e)),At=(e)=>bt(e,S(e));function Lt(e,t){return L(e,t,(r)=>e.moveByGroup(r,t))}var Xn=(e)=>Lt(e,!S(e)),Yn=(e)=>Lt(e,S(e));var Zn=(e)=>{let t=!S(e);return L(e,t,(r)=>le(e.state,r,t))},er=(e)=>{let t=S(e);return L(e,t,(r)=>le(e.state,r,t))};function Bt(e,t){return L(e,t,(r)=>e.moveVertically(r,t))}var Et=(e)=>Bt(e,!1),wt=(e)=>Bt(e,!0);function Wt(e,t){return L(e,t,(r)=>e.moveVertically(r,t,kt(e).height))}var je=(e)=>Wt(e,!1),Ye=(e)=>Wt(e,!0),tr=(e)=>L(e,!0,(t)=>R(e,t,!0)),nr=(e)=>L(e,!1,(t)=>R(e,t,!1)),rr=(e)=>{let t=!S(e);return L(e,t,(r)=>R(e,r,t))},or=(e)=>{let t=S(e);return L(e,t,(r)=>R(e,r,t))},lr=(e)=>L(e,!1,(t)=>a.cursor(e.lineBlockAt(t.head).from)),ir=(e)=>L(e,!0,(t)=>a.cursor(e.lineBlockAt(t.head).to)),Ze=({state:e,dispatch:t})=>(t(D(e,{anchor:0})),!0),et=({state:e,dispatch:t})=>(t(D(e,{anchor:e.doc.length})),!0),tt=({state:e,dispatch:t})=>(t(D(e,{anchor:e.selection.main.anchor,head:0})),!0),rt=({state:e,dispatch:t})=>(t(D(e,{anchor:e.selection.main.anchor,head:e.doc.length})),!0),sr=({state:e,dispatch:t})=>(t(e.update({selection:{anchor:0,head:e.doc.length},userEvent:"select"})),!0),cr=({state:e,dispatch:t})=>{let r=ie(e).map(({from:o,to:l})=>a.undirectionalRange(o,Math.min(l+1,e.doc.length)));return t(e.update({selection:a.create(r),userEvent:"select"})),!0},ar=({state:e,dispatch:t})=>{let r=N(e.selection,(o)=>{let l=x(e),i=l.resolveStack(o.from,1);if(o.empty){let s=l.resolveStack(o.from,-1);if(s.node.from>=i.node.from&&s.node.to<=i.node.to)i=s}for(let s=i;s;s=s.next){let{node:c}=s;if((c.from<o.from&&c.to>=o.to||c.to>o.to&&c.from<=o.from)&&s.next)return a.undirectionalRange(c.from,c.to)}return o});if(r.eq(e.selection))return!1;return t(D(e,r)),!0};function Rt(e,t){let{state:r}=e,o=r.selection,l=r.selection.ranges.slice();for(let i of r.selection.ranges){let s=r.doc.lineAt(i.head);if(t?s.to<e.state.doc.length:s.from>0)for(let c=i;;){let f=e.moveVertically(c,t);if(f.head<s.from||f.head>s.to){if(!l.some((m)=>m.head==f.head))l.push(f);break}else if(f.head==c.head)break;else c=f}}if(l.length==o.ranges.length)return!1;return e.dispatch(D(r,a.create(l,l.length-1))),!0}var ur=(e)=>Rt(e,!1),hr=(e)=>Rt(e,!0),fr=({state:e,dispatch:t})=>{let r=e.selection,o=null;if(r.ranges.length>1)o=a.create([r.main]);else if(!r.main.empty)o=a.create([a.cursor(r.main.head)]);if(!o)return!1;return t(D(e,o)),!0};function _(e,t){if(e.state.readOnly)return!1;let r="delete.selection",{state:o}=e,l=o.changeByRange((i)=>{let{from:s,to:c}=i;if(s==c){let f=t(i);if(f<s)r="delete.backward",f=X(e,f,!1);else if(f>s)r="delete.forward",f=X(e,f,!0);s=Math.min(s,f),c=Math.max(c,f)}else s=X(e,s,!1),c=X(e,c,!0);return s==c?{range:i}:{changes:{from:s,to:c},range:a.cursor(s,s<i.head?-1:1)}});if(l.changes.empty)return!1;return e.dispatch(o.update(l,{scrollIntoView:!0,userEvent:r,effects:r=="delete.selection"?u.announce.of(o.phrase("Selection deleted")):void 0})),!0}function X(e,t,r){if(e instanceof u)for(let o of e.state.facet(u.atomicRanges).map((l)=>l(e)))o.between(t,t,(l,i)=>{if(l<t&&i>t)t=r?i:l});return t}var Ft=(e,t,r)=>_(e,(o)=>{let l=o.from,{state:i}=e,s=i.doc.lineAt(l),c,f;if(r&&!t&&l>s.from&&l<s.from+200&&!/[^ \t]/.test(c=s.text.slice(0,l-s.from))){if(c[c.length-1]=="\t")return l-1;let m=ve(c,i.tabSize),d=m%nt(i)||nt(i);for(let g=0;g<d&&c[c.length-1-g]==" ";g++)l--;f=l}else if(f=J(s.text,l-s.from,t,t)+s.from,f==l&&s.number!=(t?i.doc.lines:1))f+=t?1:-1;else if(!t&&/[\ufe00-\ufe0f]/.test(s.text.slice(f-s.from,l-s.from)))f=J(s.text,f-s.from,!1,!1)+s.from;return f}),Le=(e)=>Ft(e,!1,!0);var Pt=(e)=>Ft(e,!0,!1),Nt=(e,t)=>_(e,(r)=>{let o=r.head,{state:l}=e,i=l.doc.lineAt(o),s=l.charCategorizer(o);for(let c=null;;){if(o==(t?i.to:i.from)){if(o==r.head&&i.number!=(t?l.doc.lines:1))o+=t?1:-1;break}let f=J(i.text,o-i.from,t)+i.from,m=i.text.slice(Math.min(o,f)-i.from,Math.max(o,f)-i.from),d=s(m);if(c!=null&&d!=c)break;if(m!=" "||o!=r.head)c=d;o=f}return o}),qt=(e)=>Nt(e,!1),dr=(e)=>Nt(e,!0);var mr=(e)=>_(e,(t)=>{let r=e.lineBlockAt(t.head).to;return t.head<r?r:Math.min(e.state.doc.length,t.head+1)});var pr=(e)=>_(e,(t)=>{let r=e.moveToLineBoundary(t,!1).head;return t.head>r?r:Math.max(0,t.head-1)}),gr=(e)=>_(e,(t)=>{let r=e.moveToLineBoundary(t,!0).head;return t.head<r?r:Math.min(e.state.doc.length,t.head+1)});var yr=({state:e,dispatch:t})=>{if(e.readOnly)return!1;let r=e.changeByRange((o)=>({changes:{from:o.from,to:o.to,insert:M.of(["",""])},range:a.cursor(o.from)}));return t(e.update(r,{scrollIntoView:!0,userEvent:"input"})),!0},xr=({state:e,dispatch:t})=>{if(e.readOnly)return!1;let r=e.changeByRange((o)=>{if(!o.empty||o.from==0||o.from==e.doc.length)return{range:o};let l=o.from,i=e.doc.lineAt(l),s=l==i.from?l-1:J(i.text,l-i.from,!1)+i.from,c=l==i.to?l+1:J(i.text,l-i.from,!0)+i.from;return{changes:{from:s,to:c,insert:e.doc.slice(l,c).append(e.doc.slice(s,l))},range:a.cursor(c)}});if(r.changes.empty)return!1;return t(e.update(r,{scrollIntoView:!0,userEvent:"move.character"})),!0};function ie(e){let t=[],r=-1;for(let o of e.selection.ranges){let l=e.doc.lineAt(o.from),i=e.doc.lineAt(o.to);if(!o.empty&&o.to==i.from)i=e.doc.lineAt(o.to-1);if(r>=l.number){let s=t[t.length-1];s.to=i.to,s.ranges.push(o)}else t.push({from:l.from,to:i.to,ranges:[o]});r=i.number+1}return t}function Vt(e,t,r){if(e.readOnly)return!1;let o=[],l=[];for(let i of ie(e)){if(r?i.to==e.doc.length:i.from==0)continue;let s=e.doc.lineAt(r?i.to+1:i.from-1),c=s.length+1;if(r){o.push({from:i.to,to:s.to},{from:i.from,insert:s.text+e.lineBreak});for(let f of i.ranges)l.push(a.range(Math.min(e.doc.length,f.anchor+c),Math.min(e.doc.length,f.head+c)))}else{o.push({from:s.from,to:i.from},{from:i.to,insert:e.lineBreak+s.text});for(let f of i.ranges)l.push(a.range(f.anchor-c,f.head-c))}}if(!o.length)return!1;return t(e.update({changes:o,scrollIntoView:!0,selection:a.create(l,e.selection.mainIndex),userEvent:"move.line"})),!0}var Sr=({state:e,dispatch:t})=>Vt(e,t,!1),kr=({state:e,dispatch:t})=>Vt(e,t,!0);function Gt(e,t,r){if(e.readOnly)return!1;let o=[];for(let i of ie(e))if(r)o.push({from:i.from,insert:e.doc.slice(i.from,i.to)+e.lineBreak});else o.push({from:i.to,insert:e.lineBreak+e.doc.slice(i.from,i.to)});let l=e.changes(o);return t(e.update({changes:l,selection:e.selection.map(l,r?1:-1),scrollIntoView:!0,userEvent:"input.copyline"})),!0}var vr=({state:e,dispatch:t})=>Gt(e,t,!1),br=({state:e,dispatch:t})=>Gt(e,t,!0),Cr=(e)=>{if(e.state.readOnly)return!1;let{state:t}=e,r=t.changes(ie(t).map(({from:l,to:i})=>{if(l>0)l--;else if(i<t.doc.length)i++;return{from:l,to:i}})),o=N(t.selection,(l)=>{let i=void 0;if(e.lineWrapping){let s=e.lineBlockAt(l.head),c=e.coordsAtPos(l.head,l.assoc||1);if(c)i=s.bottom+e.documentTop-c.bottom+e.defaultLineHeight/2}return e.moveVertically(l,!0,i)}).map(r);return e.dispatch({changes:r,selection:o,scrollIntoView:!0,userEvent:"delete.line"}),!0};function Mr(e,t){if(/\(\)|\[\]|\{\}/.test(e.sliceDoc(t-1,t+1)))return{from:t,to:t};let r=x(e).resolveInner(t),o=r.childBefore(t),l=r.childAfter(t),i;if(o&&l&&o.to<=t&&l.from>=t&&(i=o.type.prop(p.closedBy))&&i.indexOf(l.name)>-1&&e.doc.lineAt(o.to).from==e.doc.lineAt(l.from).from&&!/\S/.test(e.sliceDoc(o.to,l.from)))return{from:o.to,to:l.from};return null}var ot=zt(!1),Ar=zt(!0);function zt(e){return({state:t,dispatch:r})=>{if(t.readOnly)return!1;let o=t.changeByRange((l)=>{let{from:i,to:s}=l,c=t.doc.lineAt(i),f=!e&&i==s&&Mr(t,i);if(e)i=s=(s<=c.to?c:t.doc.lineAt(s)).to;let m=new mt(t,{simulateBreak:i,simulateDoubleBreak:!!f}),d=nn(m,i);if(d==null)d=ve(/^\s*/.exec(t.doc.lineAt(i).text)[0],t.tabSize);while(s<c.to&&/\s/.test(c.text[s-c.from]))s++;if(f)({from:i,to:s}=f);else if(i>c.from&&i<c.from+100&&!/\S/.test(c.text.slice(0,i)))i=c.from;let g=["",Mt(t,d)];if(f)g.push(Mt(t,m.lineIndent(c.from,-1)));return{changes:{from:i,to:s,insert:M.of(g)},range:a.cursor(i+1+g[1].length)}});return r(t.update(o,{scrollIntoView:!0,userEvent:"input"})),!0}}function Te(e,t){let r=-1;return e.changeByRange((o)=>{let l=[];for(let s=o.from;s<=o.to;){let c=e.doc.lineAt(s);if(c.number>r&&(o.empty||o.to>c.from))t(c,l,o),r=c.number;s=c.to+1}let i=e.changes(l);return{changes:l,range:a.range(i.mapPos(o.anchor,1),i.mapPos(o.head,1))}})}var Lr=({state:e,dispatch:t})=>{if(e.readOnly)return!1;let r=Object.create(null),o=new mt(e,{overrideIndentation:(i)=>{let s=r[i];return s==null?-1:s}}),l=Te(e,(i,s,c)=>{let f=nn(o,i.from);if(f==null)return;if(!/\S/.test(i.text))f=0;let m=/^\s*/.exec(i.text)[0],d=Mt(e,f);if(m!=d||c.from<i.from+m.length)r[i.from]=f,s.push({from:i.from,to:i.from+m.length,insert:d})});if(!l.changes.empty)t(e.update(l,{userEvent:"indent"}));return!0},se=({state:e,dispatch:t})=>{if(e.readOnly)return!1;return t(e.update(Te(e,(r,o)=>{o.push({from:r.from,insert:e.facet(Qe)})}),{userEvent:"input.indent"})),!0},_t=({state:e,dispatch:t})=>{if(e.readOnly)return!1;return t(e.update(Te(e,(r,o)=>{let l=/^\s*/.exec(r.text)[0];if(!l)return;let i=ve(l,e.tabSize),s=0,c=Mt(e,Math.max(0,i-nt(e)));while(s<l.length&&s<c.length&&l.charCodeAt(s)==c.charCodeAt(s))s++;o.push({from:r.from+s,to:r.from+l.length,insert:c.slice(s)})}),{userEvent:"delete.dedent"})),!0},Br=(e)=>(e.setTabFocusMode(),!0);var Dr=[{key:"Ctrl-b",run:dt,shift:Ct,preventDefault:!0},{key:"Ctrl-f",run:pt,shift:At},{key:"Ctrl-p",run:xt,shift:Et},{key:"Ctrl-n",run:St,shift:wt},{key:"Ctrl-a",run:$n,shift:lr},{key:"Ctrl-e",run:Kn,shift:ir},{key:"Ctrl-d",run:Pt},{key:"Ctrl-h",run:Le},{key:"Ctrl-k",run:mr},{key:"Ctrl-Alt-h",run:qt},{key:"Ctrl-o",run:yr},{key:"Ctrl-t",run:xr},{key:"Ctrl-v",run:Ae}],Er=[{key:"ArrowLeft",run:dt,shift:Ct,preventDefault:!0},{key:"Mod-ArrowLeft",mac:"Alt-ArrowLeft",run:Fn,shift:Xn,preventDefault:!0},{mac:"Cmd-ArrowLeft",run:zn,shift:rr,preventDefault:!0},{key:"ArrowRight",run:pt,shift:At,preventDefault:!0},{key:"Mod-ArrowRight",mac:"Alt-ArrowRight",run:In,shift:Yn,preventDefault:!0},{mac:"Cmd-ArrowRight",run:Jn,shift:or,preventDefault:!0},{key:"ArrowUp",run:xt,shift:Et,preventDefault:!0},{mac:"Cmd-ArrowUp",run:Ze,shift:tt},{mac:"Ctrl-ArrowUp",run:He,shift:je},{key:"ArrowDown",run:St,shift:wt,preventDefault:!0},{mac:"Cmd-ArrowDown",run:et,shift:rt},{mac:"Ctrl-ArrowDown",run:Ae,shift:Ye},{key:"PageUp",run:He,shift:je},{key:"PageDown",run:Ae,shift:Ye},{key:"Home",run:Un,shift:nr,preventDefault:!0},{key:"Mod-Home",run:Ze,shift:tt},{key:"End",run:Gn,shift:tr,preventDefault:!0},{key:"Mod-End",run:et,shift:rt},{key:"Enter",run:ot,shift:ot},{key:"Mod-a",run:sr},{key:"Backspace",run:Le,shift:Le,preventDefault:!0},{key:"Delete",run:Pt,preventDefault:!0},{key:"Mod-Backspace",mac:"Alt-Backspace",run:qt,preventDefault:!0},{key:"Mod-Delete",mac:"Alt-Delete",run:dr,preventDefault:!0},{mac:"Mod-Backspace",run:pr,preventDefault:!0},{mac:"Mod-Delete",run:gr,preventDefault:!0}].concat(Dr.map((e)=>({mac:e.key,run:e.run,shift:e.shift}))),Jt=[{key:"Alt-ArrowLeft",mac:"Ctrl-ArrowLeft",run:qn,shift:Zn},{key:"Alt-ArrowRight",mac:"Ctrl-ArrowRight",run:Vn,shift:er},{key:"Alt-ArrowUp",run:Sr},{key:"Shift-Alt-ArrowUp",run:vr},{key:"Alt-ArrowDown",run:kr},{key:"Shift-Alt-ArrowDown",run:br},{key:"Mod-Alt-ArrowUp",run:ur},{key:"Mod-Alt-ArrowDown",run:hr},{key:"Escape",run:fr},{key:"Mod-Enter",run:Ar},{key:"Alt-l",mac:"Ctrl-l",run:cr},{key:"Mod-i",run:ar,preventDefault:!0},{key:"Mod-[",run:_t},{key:"Mod-]",run:se},{key:"Mod-Alt-\\",run:Lr},{key:"Shift-Mod-k",run:Cr},{key:"Shift-Mod-\\",run:jn},{key:"Mod-/",run:hn},{key:"Alt-A",mac:"Ctrl-A",run:dn},{key:"Ctrl-m",mac:"Shift-Alt-m",run:Br}].concat(Er),$t={key:"Tab",run:se,shift:_t};var Kt=typeof String.prototype.normalize=="function"?(e)=>e.normalize("NFKD"):(e)=>e;class I{constructor(e,t,r=0,o=e.length,l,i){this.test=i,this.value={from:0,to:0,precise:!1},this.done=!1,this.matches=[],this.buffer="",this.bufferPos=0,this.iter=e.iterRange(r,o),this.bufferStart=r,this.normalize=l?(s)=>l(Kt(s)):Kt,this.query=this.normalize(t)}peek(){if(this.bufferPos==this.buffer.length){if(this.bufferStart+=this.buffer.length,this.iter.next(),this.iter.done)return-1;this.bufferPos=0,this.buffer=this.iter.value}return It(this.buffer,this.bufferPos)}next(){while(this.matches.length)this.matches.pop();return this.nextOverlapping()}nextOverlapping(){for(;;){let e=this.peek();if(e<0)return this.done=!0,this;let t=gn(e),r=this.bufferStart+this.bufferPos;this.bufferPos+=Dt(e);let o=this.normalize(t);if(o.length)for(let l=0,i=r,s=!0;;l++){let c=o.charCodeAt(l),f=this.match(c,i,s,this.bufferPos+this.bufferStart,l==o.length-1);if(f)return this.value=f,this;if(l==o.length-1)break;if(s&&l<t.length&&t.charCodeAt(l)==c)i++;else s=!1}}}match(e,t,r,o,l){let i=null;for(let s=0;s<this.matches.length;){let c=this.matches[s],f=!1;if(this.query.charCodeAt(c.index)==e)if(c.index==this.query.length-1)i={from:c.from,to:o,precise:l&&c.precise};else c.index++,f=!0;if(f)s++;else this.matches.splice(s,1)}if(this.query.charCodeAt(0)==e)if(this.query.length==1)i={from:t,to:o,precise:r&&l};else this.matches.push({from:t,index:1,precise:r});if(i&&this.test&&!this.test(i.from,i.to,this.buffer,this.bufferStart))i=null;return i}}if(typeof Symbol<"u")I.prototype[Symbol.iterator]=function(){return this};var jt={from:-1,to:-1,match:/.*/.exec(""),precise:!0},Oe="gm"+(/x/.unicode==null?"":"u");class Pe{constructor(e,t,r,o=0,l=e.length){if(this.text=e,this.to=l,this.curLine="",this.done=!1,this.value=jt,/\\[sWDnr]|\n|\r|\[\^/.test(t))return new qe(e,t,r,o,l);this.re=new RegExp(t,Oe+((r===null||r===void 0?void 0:r.ignoreCase)?"i":"")),this.test=r===null||r===void 0?void 0:r.test,this.iter=e.iter();let i=e.lineAt(o);this.curLineStart=i.from,this.matchPos=he(e,o),this.getLine(this.curLineStart)}getLine(e){if(this.iter.next(e),this.iter.lineBreak)this.curLine="";else{if(this.curLine=this.iter.value,this.curLineStart+this.curLine.length>this.to)this.curLine=this.curLine.slice(0,this.to-this.curLineStart);this.iter.next()}}nextLine(){if(this.curLineStart=this.curLineStart+this.curLine.length+1,this.curLineStart>this.to)this.curLine="";else this.getLine(0)}next(){for(let e=this.matchPos-this.curLineStart;;){this.re.lastIndex=e;let t=this.matchPos<=this.to&&this.re.exec(this.curLine);if(t){let r=this.curLineStart+t.index,o=r+t[0].length;if(this.matchPos=he(this.text,o+(r==o?1:0)),r==this.curLineStart+this.curLine.length)this.nextLine();if((r<o||r>this.value.to)&&(!this.test||this.test(r,o,t)))return this.value={from:r,to:o,precise:!0,match:t},this;e=this.matchPos-this.curLineStart}else if(this.curLineStart+this.curLine.length<this.to)this.nextLine(),e=0;else return this.done=!0,this}}}var we=new WeakMap;class G{constructor(e,t){this.from=e,this.text=t}get to(){return this.from+this.text.length}static get(e,t,r){let o=we.get(e);if(!o||o.from>=r||o.to<=t){let s=new G(t,e.sliceString(t,r));return we.set(e,s),s}if(o.from==t&&o.to==r)return o;let{text:l,from:i}=o;if(i>t)l=e.sliceString(t,i)+l,i=t;if(o.to<r)l+=e.sliceString(o.to,r);return we.set(e,new G(i,l)),new G(t,l.slice(t-i,r-i))}}class qe{constructor(e,t,r,o,l){this.text=e,this.to=l,this.done=!1,this.value=jt,this.matchPos=he(e,o),this.re=new RegExp(t,Oe+((r===null||r===void 0?void 0:r.ignoreCase)?"i":"")),this.test=r===null||r===void 0?void 0:r.test,this.flat=G.get(e,o,this.chunkEnd(o+5000))}chunkEnd(e){return e>=this.to?this.to:this.text.lineAt(e).to}next(){for(;;){let e=this.re.lastIndex=this.matchPos-this.flat.from,t=this.re.exec(this.flat.text);if(t&&!t[0]&&t.index==e)this.re.lastIndex=e+1,t=this.re.exec(this.flat.text);if(t){let r=this.flat.from+t.index,o=r+t[0].length;if((this.flat.to>=this.to||t.index+t[0].length<=this.flat.text.length-10)&&(!this.test||this.test(r,o,t)))return this.value={from:r,to:o,precise:!0,match:t},this.matchPos=he(this.text,o+(r==o?1:0)),this}if(this.flat.to==this.to)return this.done=!0,this;this.flat=G.get(this.text,this.flat.from,this.chunkEnd(this.flat.from+this.flat.text.length*2))}}}if(typeof Symbol<"u")Pe.prototype[Symbol.iterator]=qe.prototype[Symbol.iterator]=function(){return this};function Tr(e){try{return new RegExp(e,Oe),!0}catch(t){return!1}}function he(e,t){if(t>=e.length)return t;let r=e.lineAt(t),o;while(t<r.to&&(o=r.text.charCodeAt(t-r.from))>=56320&&o<57344)t++;return t}var wr=(e)=>{let t=Sn(e,"cm-goto-line");if(t){let s=t.dom.querySelector("input[type=text]");if(s)s.select();return!0}let{state:r}=e,o=String(r.doc.lineAt(e.state.selection.main.head).number),{close:l,result:i}=xn(e,{class:"cm-goto-line",label:r.phrase("Go to line"),input:{type:"text",name:"line",value:o},focus:!0,submitLabel:r.phrase("go")});return i.then((s)=>{let c=s&&/^([+-])?(\d+)?(:\d+)?(%)?$/.exec(s.elements.line.value);if(!c){e.dispatch({effects:l});return}let f=r.doc.lineAt(r.selection.main.head),[,m,d,g,y]=c,W=g?+g.slice(1):0,B=d?+d:f.number;if(d&&y){let ke=B/100;if(m)ke=ke*(m=="-"?-1:1)+f.number/r.doc.lines;B=Math.round(r.doc.lines*ke)}else if(d&&m)B=B*(m=="-"?-1:1)+f.number;let $e=r.doc.line(Math.max(1,Math.min(r.doc.lines,B))),Ke=a.cursor($e.from+Math.max(0,Math.min(W,$e.length)));e.dispatch({effects:[l,u.scrollIntoView(Ke.from,{y:"center"})],selection:Ke})}),!0},Wr={highlightWordAroundCursor:!1,minSelectionLength:1,maxMatches:100,wholeWords:!1},Xt=h.define({combine(e){return Ie(e,Wr,{highlightWordAroundCursor:(t,r)=>t||r,minSelectionLength:Math.min,maxMatches:Math.min})}});function Yt(e){let t=[Pr,Ir];if(e)t.push(Xt.of(e));return t}var Rr=v.mark({class:"cm-selectionMatch"}),Or=v.mark({class:"cm-selectionMatch cm-selectionMatch-main"});function Ht(e,t,r,o){return(r==0||e(t.sliceDoc(r-1,r))!=H.Word)&&(o==t.doc.length||e(t.sliceDoc(o,o+1))!=H.Word)}function Fr(e,t,r,o){return e(t.sliceDoc(r,r+1))==H.Word&&e(t.sliceDoc(o-1,o))==H.Word}var Ir=fe.fromClass(class{constructor(e){this.decorations=this.getDeco(e)}update(e){if(e.selectionSet||e.docChanged||e.viewportChanged)this.decorations=this.getDeco(e.view)}getDeco(e){let t=e.state.facet(Xt),{state:r}=e,o=r.selection;if(o.ranges.length>1)return v.none;let l=o.main,i,s=null;if(l.empty){if(!t.highlightWordAroundCursor)return v.none;let f=r.wordAt(l.head);if(!f)return v.none;s=r.charCategorizer(l.head),i=r.sliceDoc(f.from,f.to)}else{let f=l.to-l.from;if(f<t.minSelectionLength||f>200)return v.none;if(t.wholeWords){if(i=r.sliceDoc(l.from,l.to),s=r.charCategorizer(l.head),!(Ht(s,r,l.from,l.to)&&Fr(s,r,l.from,l.to)))return v.none}else if(i=r.sliceDoc(l.from,l.to),!i)return v.none}let c=[];for(let f of e.visibleRanges){let m=new I(r.doc,i,f.from,f.to);while(!m.next().done){let{from:d,to:g}=m.value;if(!s||Ht(s,r,d,g)){if(l.empty&&d<=l.from&&g>=l.to)c.push(Or.range(d,g));else if(d>=l.to||g<=l.from)c.push(Rr.range(d,g));if(c.length>t.maxMatches)return v.none}}}return v.set(c)}},{decorations:(e)=>e.decorations}),Pr=u.baseTheme({".cm-selectionMatch":{backgroundColor:"#99ff7780"},".cm-searchMatch .cm-selectionMatch":{backgroundColor:"transparent"}}),Nr=({state:e,dispatch:t})=>{let{selection:r}=e,o=a.create(r.ranges.map((l)=>e.wordAt(l.head)||a.cursor(l.head)),r.mainIndex);if(o.eq(r))return!1;return t(e.update({selection:o})),!0};function qr(e,t){let{main:r,ranges:o}=e.selection,l=e.wordAt(r.head),i=l&&l.from==r.from&&l.to==r.to;for(let s=!1,c=new I(e.doc,t,o[o.length-1].to);;)if(c.next(),c.done){if(s)return null;c=new I(e.doc,t,0,Math.max(0,o[o.length-1].from-1)),s=!0}else{if(s&&o.some((f)=>f.from==c.value.from))continue;if(i){let f=e.wordAt(c.value.from);if(!f||f.from!=c.value.from||f.to!=c.value.to)continue}return c.value}}var Vr=({state:e,dispatch:t})=>{let{ranges:r}=e.selection;if(r.some((i)=>i.from===i.to))return Nr({state:e,dispatch:t});let o=e.sliceDoc(r[0].from,r[0].to);if(e.selection.ranges.some((i)=>e.sliceDoc(i.from,i.to)!=o))return!1;let l=qr(e,o);if(!l)return!1;return t(e.update({selection:e.selection.addRange(a.range(l.from,l.to),!1),effects:u.scrollIntoView(l.to)})),!0},P=h.define({combine(e){return Ie(e,{top:!1,caseSensitive:!1,literal:!1,regexp:!1,wholeWord:!1,createPanel:(t)=>new cn(t),scrollToMatch:(t)=>u.scrollIntoView(t)})}});function Zt(e){return e?[P.of(e),Re]:Re}class Ve{constructor(e){this.search=e.search,this.caseSensitive=!!e.caseSensitive,this.literal=!!e.literal,this.regexp=!!e.regexp,this.replace=e.replace||"",this.valid=!!this.search&&(!this.regexp||Tr(this.search)),this.unquoted=this.unquote(this.search),this.wholeWord=!!e.wholeWord,this.test=e.test}unquote(e){return this.literal?e:e.replace(/\\([nrt\\])/g,(t,r)=>r=="n"?`
|
|
2
|
+
`:r=="r"?"\r":r=="t"?"\t":"\\")}eq(e){return this.search==e.search&&this.replace==e.replace&&this.caseSensitive==e.caseSensitive&&this.regexp==e.regexp&&this.wholeWord==e.wholeWord&&this.test==e.test}create(){return this.regexp?new tn(this):new en(this)}getCursor(e,t=0,r){let o=e.doc?e:T.create({doc:e});if(r==null)r=o.doc.length;return this.regexp?V(this,o,t,r):q(this,o,t,r)}}class Ge{constructor(e){this.spec=e}}function Gr(e,t,r){return(o,l,i,s)=>{if(r&&!r(o,l,i,s))return!1;let c=o>=s&&l<=s+i.length?i.slice(o-s,l-s):t.doc.sliceString(o,l);return e(c,t,o,l)}}function q(e,t,r,o){let l;if(e.wholeWord)l=Ur(t.doc,t.charCategorizer(t.selection.main.head));if(e.test)l=Gr(e.test,t,l);return new I(t.doc,e.unquoted,r,o,e.caseSensitive?void 0:(i)=>i.toLowerCase(),l)}function Ur(e,t){return(r,o,l,i)=>{if(i>r||i+l.length<o)i=Math.max(0,r-2),l=e.sliceString(i,Math.min(e.length,o+2));return(t(me(l,r-i))!=H.Word||t(pe(l,r-i))!=H.Word)&&(t(pe(l,o-i))!=H.Word||t(me(l,o-i))!=H.Word)}}class en extends Ge{constructor(e){super(e)}nextMatch(e,t,r){let o=q(this.spec,e,r,e.doc.length).nextOverlapping();if(o.done){let l=Math.min(e.doc.length,t+this.spec.unquoted.length);o=q(this.spec,e,0,l).nextOverlapping()}return o.done||o.value.from==t&&o.value.to==r?null:o.value}prevMatchInRange(e,t,r){for(let o=r;;){let l=Math.max(t,o-1e4-this.spec.unquoted.length),i=q(this.spec,e,l,o),s=null;while(!i.nextOverlapping().done)s=i.value;if(s)return s;if(l==t)return null;o-=1e4}}prevMatch(e,t,r){let o=this.prevMatchInRange(e,0,t);if(!o)o=this.prevMatchInRange(e,Math.max(0,r-this.spec.unquoted.length),e.doc.length);return o&&(o.from!=t||o.to!=r)?o:null}getReplacement(e){return this.spec.unquote(this.spec.replace)}matchAll(e,t){let r=q(this.spec,e,0,e.doc.length),o=[];while(!r.next().done){if(o.length>=t)return null;o.push(r.value)}return o}highlight(e,t,r,o){let l=q(this.spec,e,Math.max(0,t-this.spec.unquoted.length),Math.min(r+this.spec.unquoted.length,e.doc.length));while(!l.next().done)o(l.value.from,l.value.to)}}function zr(e,t,r){return(o,l,i)=>(!r||r(o,l,i))&&e(i[0],t,o,l)}function V(e,t,r,o){let l;if(e.wholeWord)l=_r(t.charCategorizer(t.selection.main.head));if(e.test)l=zr(e.test,t,l);return new Pe(t.doc,e.search,{ignoreCase:!e.caseSensitive,test:l},r,o)}function me(e,t){return e.slice(J(e,t,!1),t)}function pe(e,t){return e.slice(t,J(e,t))}function _r(e){return(t,r,o)=>!o[0].length||(e(me(o.input,o.index))!=H.Word||e(pe(o.input,o.index))!=H.Word)&&(e(pe(o.input,o.index+o[0].length))!=H.Word||e(me(o.input,o.index+o[0].length))!=H.Word)}class tn extends Ge{nextMatch(e,t,r){let o=V(this.spec,e,r,e.doc.length).next();if(o.done)o=V(this.spec,e,0,t).next();return o.done?null:o.value}prevMatchInRange(e,t,r){for(let o=1;;o++){let l=Math.max(t,r-o*1e4),i=V(this.spec,e,l,r),s=null;while(!i.next().done)s=i.value;if(s&&(l==t||s.from>l+10))return s;if(l==t)return null}}prevMatch(e,t,r){return this.prevMatchInRange(e,0,t)||this.prevMatchInRange(e,r,e.doc.length)}getReplacement(e){return this.spec.unquote(this.spec.replace).replace(/\$([$&]|\d+)/g,(t,r)=>{if(r=="&")return e.match[0];if(r=="$")return"$";for(let o=r.length;o>0;o--){let l=+r.slice(0,o);if(l>0&&l<e.match.length)return e.match[l]+r.slice(o)}return t})}matchAll(e,t){let r=V(this.spec,e,0,e.doc.length),o=[];while(!r.next().done){if(o.length>=t)return null;o.push(r.value)}return o}highlight(e,t,r,o){let l=V(this.spec,e,Math.max(0,t-250),Math.min(r+250,e.doc.length));while(!l.next().done)o(l.value.from,l.value.to)}}var K=C.define(),Ue=C.define(),O=de.define({create(e){return new ue(We(e).create(),null)},update(e,t){for(let r of t.effects)if(r.is(K))e=new ue(r.value.create(),e.panel);else if(r.is(Ue))e=new ue(e.query,r.value?ze:null);return e},provide:(e)=>Tt.from(e,(t)=>t.panel)});class ue{constructor(e,t){this.query=e,this.panel=t}}var Jr=v.mark({class:"cm-searchMatch"}),$r=v.mark({class:"cm-searchMatch cm-searchMatch-selected"}),Kr=fe.fromClass(class{constructor(e){this.view=e,this.decorations=this.highlight(e.state.field(O))}update(e){let t=e.state.field(O);if(t!=e.startState.field(O)||e.docChanged||e.selectionSet||e.viewportChanged)this.decorations=this.highlight(t)}highlight({query:e,panel:t}){if(!t||!e.spec.valid)return v.none;let{view:r}=this,o=new De;for(let l=0,i=r.visibleRanges,s=i.length;l<s;l++){let{from:c,to:f}=i[l];while(l<s-1&&f>i[l+1].from-500)f=i[++l].to;e.highlight(r.state,c,f,(m,d)=>{let g=r.state.selection.ranges.some((y)=>y.from==m&&y.to==d);o.add(m,d,g?$r:Jr)})}return o.finish()}},{decorations:(e)=>e.decorations});function j(e){return(t)=>{let r=t.state.field(O,!1);return r&&r.query.spec.valid?e(t,r):Se(t)}}var ge=j((e,{query:t})=>{let{to:r}=e.state.selection.main,o=t.nextMatch(e.state,r,r);if(!o)return!1;let l=a.single(o.from,o.to),i=e.state.facet(P);return e.dispatch({selection:l,effects:[_e(e,o),i.scrollToMatch(l.main,e)],userEvent:"select.search"}),on(e),!0}),xe=j((e,{query:t})=>{let{state:r}=e,{from:o}=r.selection.main,l=t.prevMatch(r,o,o);if(!l)return!1;let i=a.single(l.from,l.to),s=e.state.facet(P);return e.dispatch({selection:i,effects:[_e(e,l),s.scrollToMatch(i.main,e)],userEvent:"select.search"}),on(e),!0}),Hr=j((e,{query:t})=>{let r=t.matchAll(e.state,1000);if(!r||!r.length)return!1;return e.dispatch({selection:a.create(r.map((o)=>a.range(o.from,o.to))),userEvent:"select.search.matches"}),!0}),Qr=({state:e,dispatch:t})=>{let r=e.selection;if(r.ranges.length>1||r.main.empty)return!1;let{from:o,to:l}=r.main,i=[],s=0;for(let c=new I(e.doc,e.sliceDoc(o,l));!c.next().done;){if(i.length>1000)return!1;if(c.value.from==o)s=i.length;i.push(a.range(c.value.from,c.value.to))}return t(e.update({selection:a.create(i,s),userEvent:"select.search.matches"})),!0},Qt=j((e,{query:t})=>{let{state:r}=e,{from:o,to:l}=r.selection.main;if(r.readOnly)return!1;let i=t.nextMatch(r,o,o);if(!i)return!1;let s=i,c=[],f,m,d=[];if(!s.precise)s=t.nextMatch(r,s.from,s.to);else if(s.from==o&&s.to==l)m=r.toText(t.getReplacement(s)),c.push({from:s.from,to:s.to,insert:m}),s=t.nextMatch(r,s.from,s.to),d.push(u.announce.of(r.phrase("replaced match on line $",r.doc.lineAt(o).number)+"."));let g=e.state.changes(c);if(s)f=a.single(s.from,s.to).map(g),d.push(_e(e,s)),d.push(r.facet(P).scrollToMatch(f.main,e));return e.dispatch({changes:g,selection:f,effects:d,userEvent:"input.replace"}),!0}),jr=j((e,{query:t})=>{if(e.state.readOnly)return!1;let r=[];for(let l of t.matchAll(e.state,1e9)){let{from:i,to:s,precise:c}=l;if(c)r.push({from:i,to:s,insert:t.getReplacement(l)})}if(!r.length)return!1;let o=e.state.phrase("replaced $ matches",r.length)+".";return e.dispatch({changes:r,effects:u.announce.of(o),userEvent:"input.replace.all"}),!0});function ze(e){return e.state.facet(P).createPanel(e)}function We(e,t){var r,o,l,i,s;let c=e.selection.main,f=c.empty||c.to>c.from+100?"":e.sliceDoc(c.from,c.to);if(t&&!f)return t;let m=e.facet(P);return new Ve({search:((r=t===null||t===void 0?void 0:t.literal)!==null&&r!==void 0?r:m.literal)?f:f.replace(/\n/g,"\\n"),caseSensitive:(o=t===null||t===void 0?void 0:t.caseSensitive)!==null&&o!==void 0?o:m.caseSensitive,literal:(l=t===null||t===void 0?void 0:t.literal)!==null&&l!==void 0?l:m.literal,regexp:(i=t===null||t===void 0?void 0:t.regexp)!==null&&i!==void 0?i:m.regexp,wholeWord:(s=t===null||t===void 0?void 0:t.wholeWord)!==null&&s!==void 0?s:m.wholeWord})}function rn(e){let t=Ut(e,ze);return t&&t.dom.querySelector("[main-field]")}function on(e){let t=rn(e);if(t&&t==e.root.activeElement)t.select()}var Se=(e)=>{let t=e.state.field(O,!1);if(t&&t.panel){let r=rn(e);if(r&&r!=e.root.activeElement){let o=We(e.state,t.query.spec);if(o.valid)e.dispatch({effects:K.of(o)});r.focus(),r.select()}}else e.dispatch({effects:[Ue.of(!0),t?K.of(We(e.state,t.query.spec)):C.appendConfig.of(Re)]});return!0},ln=(e)=>{let t=e.state.field(O,!1);if(!t||!t.panel)return!1;let r=Ut(e,ze);if(r&&r.dom.contains(e.root.activeElement))e.focus();return e.dispatch({effects:Ue.of(!1)}),!0},sn=[{key:"Mod-f",run:Se,scope:"editor search-panel"},{key:"F3",run:ge,shift:xe,scope:"editor search-panel",preventDefault:!0},{key:"Mod-g",run:ge,shift:xe,scope:"editor search-panel",preventDefault:!0},{key:"Escape",run:ln,scope:"editor search-panel"},{key:"Mod-Shift-l",run:Qr},{key:"Mod-Alt-g",run:wr},{key:"Mod-d",run:Vr,preventDefault:!0}];class cn{constructor(e){this.view=e;let t=this.query=e.state.field(O).query.spec;this.commit=this.commit.bind(this),this.searchField=te("input",{value:t.search,placeholder:b(e,"Find"),"aria-label":b(e,"Find"),class:"cm-textfield",name:"search",form:"","main-field":"true",onchange:this.commit,onkeyup:this.commit}),this.replaceField=te("input",{value:t.replace,placeholder:b(e,"Replace"),"aria-label":b(e,"Replace"),class:"cm-textfield",name:"replace",form:"",onchange:this.commit,onkeyup:this.commit}),this.caseField=te("input",{type:"checkbox",name:"case",form:"",checked:t.caseSensitive,onchange:this.commit}),this.reField=te("input",{type:"checkbox",name:"re",form:"",checked:t.regexp,onchange:this.commit}),this.wordField=te("input",{type:"checkbox",name:"word",form:"",checked:t.wholeWord,onchange:this.commit});function r(o,l,i){return te("button",{class:"cm-button",name:o,onclick:l,type:"button"},i)}this.dom=te("div",{onkeydown:(o)=>this.keydown(o),class:"cm-search"},[this.searchField,r("next",()=>ge(e),[b(e,"next")]),r("prev",()=>xe(e),[b(e,"previous")]),r("select",()=>Hr(e),[b(e,"all")]),te("label",null,[this.caseField,b(e,"match case")]),te("label",null,[this.reField,b(e,"regexp")]),te("label",null,[this.wordField,b(e,"by word")]),...e.state.readOnly?[]:[te("br"),this.replaceField,r("replace",()=>Qt(e),[b(e,"replace")]),r("replaceAll",()=>jr(e),[b(e,"replace all")])],te("button",{name:"close",onclick:()=>ln(e),"aria-label":b(e,"close"),type:"button"},["×"])])}commit(){let e=new Ve({search:this.searchField.value,caseSensitive:this.caseField.checked,regexp:this.reField.checked,wholeWord:this.wordField.checked,replace:this.replaceField.value});if(!e.eq(this.query))this.query=e,this.view.dispatch({effects:K.of(e)})}keydown(e){if(yn(this.view,e,"search-panel"))e.preventDefault();else if(e.keyCode==13&&e.target==this.searchField)e.preventDefault(),(e.shiftKey?xe:ge)(this.view);else if(e.keyCode==13&&e.target==this.replaceField)e.preventDefault(),Qt(this.view)}update(e){for(let t of e.transactions)for(let r of t.effects)if(r.is(K)&&!r.value.eq(this.query))this.setQuery(r.value)}setQuery(e){this.query=e,this.searchField.value=e.search,this.replaceField.value=e.replace,this.caseField.checked=e.caseSensitive,this.reField.checked=e.regexp,this.wordField.checked=e.wholeWord}mount(){this.searchField.select()}get pos(){return 80}get top(){return this.view.state.facet(P).top}}function b(e,t){return e.state.phrase(t)}var ce=30,ae=/[\s\.,:;?!]/;function _e(e,{from:t,to:r}){let o=e.state.doc.lineAt(t),l=e.state.doc.lineAt(r).to,i=Math.max(o.from,t-ce),s=Math.min(l,r+ce),c=e.state.sliceDoc(i,s);if(i!=o.from){for(let f=0;f<ce;f++)if(!ae.test(c[f+1])&&ae.test(c[f])){c=c.slice(f);break}}if(s!=l){for(let f=c.length-1;f>c.length-ce;f--)if(!ae.test(c[f-1])&&ae.test(c[f])){c=c.slice(0,f);break}}return u.announce.of(`${e.state.phrase("current match")}. ${c} ${e.state.phrase("on line")} ${o.number}.`)}var Xr=u.baseTheme({".cm-panel.cm-search":{padding:"2px 6px 4px",position:"relative","& [name=close]":{position:"absolute",top:"0",right:"4px",backgroundColor:"inherit",border:"none",font:"inherit",padding:0,margin:0},"& input, & button, & label":{margin:".2em .6em .2em 0"},"& input[type=checkbox]":{marginRight:".2em"},"& label":{fontSize:"80%",whiteSpace:"pre"}},"&light .cm-searchMatch":{backgroundColor:"#ffff0054"},"&dark .cm-searchMatch":{backgroundColor:"#00ffff8a"},"&light .cm-searchMatch-selected":{backgroundColor:"#ff6a0054"},"&dark .cm-searchMatch-selected":{backgroundColor:"#ff00ff8a"}}),Re=[O,ye.low(Kr),Xr];var Yr=u.theme({"&":{color:"var(--code-fg)",backgroundColor:"var(--code-bg)",height:"100%",fontSize:"var(--code-size, 13px)"},"&.cm-focused":{outline:"none"},".cm-scroller":{fontFamily:"var(--font-mono)",lineHeight:"1.55",overflow:"auto"},".cm-content":{caretColor:"var(--code-fg)",padding:"0.5rem 0"},".cm-line":{padding:"0 0.75rem"},".cm-cursor, .cm-dropCursor":{borderLeftColor:"var(--code-fg)"},"&.cm-focused .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection":{backgroundColor:"var(--code-selection)"},".cm-activeLine":{backgroundColor:"var(--code-active-line)"},".cm-gutters":{backgroundColor:"var(--code-gutter-bg)",color:"var(--code-gutter)",border:"none",borderRight:"1px solid var(--border)"},".cm-activeLineGutter":{backgroundColor:"var(--code-active-line)",color:"var(--code-fg)"},".cm-lineNumbers .cm-gutterElement":{padding:"0 0.5rem 0 0.5rem",minWidth:"2.25rem"},".cm-matchingBracket, .cm-nonmatchingBracket":{backgroundColor:"var(--code-selection)",outline:"1px solid var(--border-strong)"},".cm-searchMatch":{backgroundColor:"var(--warn-soft)",outline:"1px solid var(--warn)"},".cm-searchMatch.cm-searchMatch-selected":{backgroundColor:"var(--accent-soft)",outline:"1px solid var(--accent)"},".cm-panels":{backgroundColor:"var(--surface-2)",color:"var(--text)",borderColor:"var(--border)",fontFamily:"var(--font)"},".cm-panels-top":{borderBottom:"1px solid var(--border)"},".cm-panel.cm-search":{padding:"0.5rem 2rem 0.5rem 0.5rem"},".cm-panel.cm-search input, .cm-panel.cm-search button, .cm-panel.cm-search label":{fontSize:"0.875rem"},".cm-panel.cm-search input[type=text]":{backgroundColor:"var(--surface)",color:"var(--text)",border:"1px solid var(--control-border)",borderRadius:"var(--radius-sm)",padding:"0.25rem 0.5rem"},".cm-panel.cm-search button":{backgroundColor:"var(--surface-3)",color:"var(--text)",border:"1px solid var(--border-strong)",borderRadius:"var(--radius-sm)",backgroundImage:"none",padding:"0.25rem 0.625rem"},".cm-panel.cm-search [name=close]":{color:"var(--muted)"}}),Zr=Ot.define([{tag:[n.keyword,n.modifier,n.operatorKeyword,n.controlKeyword],color:"var(--code-keyword)"},{tag:[n.string,n.regexp,n.special(n.string),n.inserted],color:"var(--code-string)"},{tag:[n.number,n.bool,n.null,n.atom,n.literal],color:"var(--code-number)"},{tag:[n.comment,n.lineComment,n.blockComment,n.docComment],color:"var(--code-comment)",fontStyle:"italic"},{tag:[n.typeName,n.className,n.namespace,n.tagName,n.standard(n.tagName)],color:"var(--code-type)"},{tag:[n.function(n.variableName),n.function(n.propertyName),n.definition(n.variableName),n.labelName],color:"var(--code-function)"},{tag:[n.meta,n.processingInstruction,n.annotation,n.attributeName,n.propertyName,n.heading],color:"var(--code-meta)"},{tag:n.heading,fontWeight:"bold"},{tag:n.strong,fontWeight:"bold"},{tag:n.emphasis,fontStyle:"italic"},{tag:n.strikethrough,textDecoration:"line-through"},{tag:n.link,color:"var(--code-function)",textDecoration:"underline"},{tag:n.url,color:"var(--code-function)"},{tag:n.invalid,color:"var(--danger)"},{tag:n.deleted,color:"var(--danger)"}]),an=[Yr,Qn(Zr)];var eo={typescript:()=>(Q("qh6rebyb"),import("./chunk-lang-typescript-qh6rebyb.js")),javascript:()=>(Q("ykb2vhaa"),import("./chunk-lang-javascript-ykb2vhaa.js")),json:()=>(Q("2rze3rpy"),import("./chunk-lang-json-2rze3rpy.js")),markdown:()=>(Q("6w2htnfc"),import("./chunk-lang-markdown-6w2htnfc.js")),css:()=>(Q("fkdg3x8x"),import("./chunk-lang-css-fkdg3x8x.js")),html:()=>(Q("v8h9g977"),import("./chunk-lang-html-v8h9g977.js")),python:()=>(Q("9jk5a49y"),import("./chunk-lang-python-9jk5a49y.js")),yaml:()=>(Q("jac98srt"),import("./chunk-lang-yaml-jac98srt.js")),go:()=>(Q("403qsw9f"),import("./chunk-lang-go-403qsw9f.js")),rust:()=>(Q("24fggcqx"),import("./chunk-lang-rust-24fggcqx.js")),sql:()=>(Q("gjywb9ke"),import("./chunk-lang-sql-gjywb9ke.js")),xml:()=>(Q("1mh879j9"),import("./chunk-lang-xml-1mh879j9.js")),shell:()=>(Q("cgq6q0kj"),import("./chunk-lang-shell-cgq6q0kj.js")),toml:()=>(Q("xh45nm68"),import("./chunk-lang-toml-xh45nm68.js")),dockerfile:()=>(Q("ey0nvhhm"),import("./chunk-lang-dockerfile-ey0nvhhm.js"))};async function un(e){if(e==="plain")return;try{return(await eo[e]()).language()}catch(t){console.warn("a language for the editor failed to load",t);return}}function to(e){if(typeof e.attachShadow!=="function"||typeof CSSStyleSheet>"u"||!("adoptedStyleSheets"in Document.prototype))return{parent:e,root:void 0};let t=e.shadowRoot??e.attachShadow({mode:"open"}),r=new CSSStyleSheet;return r.replaceSync(":host{display:flex;flex-direction:column;min-height:0}.cm-editor{flex:1;min-height:0}"),t.adoptedStyleSheets=[...t.adoptedStyleSheets,r],{parent:t,root:t}}async function Ao(e){let t=new Je,r=new Je,o=new Je,l=await un(e.language),i=(g)=>[T.readOnly.of(!g),u.editable.of(g)],s={editable:e.editable,wrap:e.wrap,language:l??[]},c,f=(g)=>[wn(),vn(),_n(),ct(),bn(),Pn(),Yt(),Zt({top:!0}),Qe.of(" "),T.phrases.of(e.phrases),an,Fe.of([{key:"Mod-s",preventDefault:!0,run:()=>(e.onSave(),!0)},{key:"Escape",run:()=>(e.onEscape(),!0)},$t,...sn,...ht,...Jt]),T.lineSeparator.of(g),t.of(i(s.editable)),r.of(s.wrap?u.lineWrapping:[]),o.of(s.language),u.updateListener.of((y)=>{if(y.docChanged)e.onChange()})],m=to(e.parent),d=new u({parent:m.parent,root:m.root,state:T.create({doc:e.text,extensions:f(e.eol)})});return c=d.state.doc,{text:()=>d.state.doc.sliceString(0,void 0,d.state.lineBreak),dirty:()=>c===void 0||!d.state.doc.eq(c),snapshot:()=>d.state.doc,markSaved:(g)=>{c=g??d.state.doc},replace:(g,y)=>{let W=d.scrollDOM.scrollTop;d.setState(T.create({doc:g,extensions:f(y)})),c=d.state.doc,d.scrollDOM.scrollTop=W},setEditable:(g)=>{s.editable=g,d.dispatch({effects:t.reconfigure(i(g))})},setWrap:(g)=>{s.wrap=g,d.dispatch({effects:r.reconfigure(g?u.lineWrapping:[])})},setLanguage:async(g)=>{s.language=await un(g)??[],d.dispatch({effects:o.reconfigure(s.language)})},undo:()=>{re(d)},redo:()=>{z(d)},find:()=>{Se(d)},tab:()=>{se(d)},focus:()=>d.focus(),scrollTop:()=>d.scrollDOM.scrollTop,scrollTo:(g)=>{d.scrollDOM.scrollTop=g},destroy:()=>d.destroy()}}export{Ao as createEditor};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{t,m,e,i,P,S,I,V,d,A,oe}from"./chunk-index-ckgbszwt.js";function g(){let{connectorAdminUrl:n}=A(),{data:r,error:s}=oe(()=>d.connectors(),"connectors");return i("section",{className:"stack",children:[i("div",{className:"card-head",children:[i("div",{children:[e("h2",{children:t("Connectors")}),e("p",{className:"hint",children:t("Upstream MCP gateways and virtual servers used by the assistant.")})]}),n?e("a",{href:n,target:"_blank",rel:"noreferrer",children:t("Open connector admin")}):null]}),s?e(S,{message:s}):null,!r&&!s?e(P,{}):null,r?i(m,{children:[e("h3",{children:t("Upstream gateways")}),r.gateways.length===0?e(I,{children:t("No gateways.")}):null,r.gateways.map((a)=>e("article",{className:"card",children:i("div",{className:"card-head",children:[e("strong",{children:a.name}),e(V,{children:a.enabled?t("Enabled"):t("Disabled")}),e(V,{tone:a.reachable?"plain":"warn",children:a.reachable?t("Reachable"):t("Unreachable")}),e(V,{children:t("{count} tools",{count:a.tools})})]})},a.name)),e("h3",{children:t("Virtual servers")}),r.servers.length===0?e(I,{children:t("No virtual servers.")}):null,r.servers.map((a)=>i("article",{className:"card",children:[i("div",{className:"card-head",children:[e("strong",{children:a.name}),e(V,{children:t("{count} tools",{count:a.tools.length})})]}),i("p",{children:[t("Used by"),": ",a.usedBy.join(", ")||t("None")]}),i("details",{children:[e("summary",{children:t("Tool list")}),e("ul",{children:a.tools.map((o)=>e("li",{children:o},o))})]})]},a.name))]}):null]})}export{g as ConnectorsPage};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{t,s,m,e,i,R,P,S,I,V,d,A,ue,ze,se,pe,dt,$t,oe}from"./chunk-index-ckgbszwt.js";var g=[{kind:"owner",title:s("Owner channels"),note:s("Direct messages and channels where the owner talks to the assistant.")},{kind:"agent",title:s("Agent channels"),note:s("The agent server's one-to-one channels.")},{kind:"group",title:s("Group channels"),note:s("The agent server's group channels.")},{kind:"outside",title:s("Outside agents"),note:s("Conversations an agent outside Discord holds over MCP.")},{kind:"plugin",title:s("Plugin conversations"),note:s("Conversations a plugin runs, such as a web chat, as the host recorded them.")}];function B(){let{timeZone:o}=A(),{now:n}=ue(),{data:r,error:a}=oe(()=>d.conversations(),"conversations"),h=r?.conversations;if(!h)return a?e(S,{message:a}):e(P,{});return i(m,{children:[a?e(S,{message:a}):null,g.map((l)=>{let u=h.filter((c)=>c.kind===l.kind);return i("section",{className:"stack",children:[e("h2",{children:t(l.title)}),e("p",{className:"hint",children:t(l.note)}),u.length===0?e(I,{children:t("None stored.")}):null,u.map((c)=>e(p,{item:c,now:n,timeZone:o},c.key))]},l.kind)})]})}function p(o){let{item:n}=o,r=dt(n.channel,n.id),a=$t(n);return i("a",{className:"card card-link",href:R("conversations",n.key),children:[i("div",{className:"card-head",children:[e("strong",{children:a}),n.busy>0?e(V,{tone:"busy",children:t("running")}):null,n.liveBytes===0?e(V,{children:t("archived only")}):null]}),i("p",{className:"meta",children:[(n.kind==="outside"||n.kind==="plugin")&&n.startedAt?`${t("Started")} ${se(n.startedAt,o.timeZone)} · `:r.detail?`${r.detail} · `:"",n.principal?`${n.visibility==="private"?t("Private to {name}",{name:n.principal.name}):t("Shared · {name}",{name:n.principal.name})} · `:"",t("Last active")," ",ze(n.lastActive,o.now,o.timeZone)," ·"," ",pe(n.liveBytes)," ·"," ",t("{count} archived",{count:n.archives})]})]})}export{B as ConversationsPage};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{Q}from"./chunk-index-ckgbszwt.js";import{at}from"./chunk-index-1y50d6sj.js";function w(){try{let c=document.createElement("canvas");return!!(c.getContext("webgl2")||c.getContext("webgl"))}catch{return!1}}function L(c,a){return[c,a.includes("?")?a.slice(a.indexOf("?")):""].some((d)=>{let i=new URLSearchParams(d).get("nogl");return i!==null&&i!=="0"&&i!=="false"})}async function A(c,a,g){let d=a.variant==="compact",i=a.labels??at,s=new Map,v=(e)=>{s.clear();for(let t of e)s.set(t.id,{...t})};v(a.seats);let u={t:a.theme,s:a.scheme},n=null,o=document.createElement("div");o.className="rt-table",o.dataset.variant=d?"compact":"full";let b=document.createElement("div");b.className="rt-table-stage",o.appendChild(b);let r=null,T=!1,y=()=>!d&&(Boolean(a.listBelow)||T);c.appendChild(o);let m=new Map,f=()=>{if(!y()){r?.remove(),r=null,m.clear(),delete o.dataset.list;return}if(!r)r=document.createElement("ul"),r.className="rt-table-list",r.setAttribute("aria-label",i.table),o.appendChild(r),o.dataset.list="";for(let e of[...m.keys()])if(!s.has(e))m.delete(e);for(let e of s.values()){let t=m.get(e.id);if(!t){t=document.createElement("button"),t.type="button";let l=e.id;t.addEventListener("click",()=>{let S=s.get(l);if(S)a.onSeatClick({id:S.id,name:S.name})}),m.set(e.id,t)}t.textContent=i.seat(e.name,e.state??"idle"),t.style.setProperty("--seat",e.color)}r.replaceChildren(...[...s.values()].map((e)=>{let t=document.createElement("li"),l=m.get(e.id);if(l)t.appendChild(l);return t}))};f();let h=(e)=>{T=!e,f(),a.onNames?.(e)},p=async()=>{let{createTable2D:e}=await (Q("k60ressj"),import("./chunk-table2d-k60ressj.js"));n=e(b,{...a,theme:u.t,scheme:u.s,seats:[...s.values()]}),h(!0)},E=async()=>{let{createTable3D:e}=await (Q("bv2ajk39"),import("./chunk-table3d-bv2ajk39.js"));n=e(b,{...a,theme:u.t,scheme:u.s,seats:[...s.values()],onNames:h},()=>{n?.dispose(),p()})};if(d||g==="svg"||g!=="webgl"&&(L(location.search,location.hash)||!w()))await p();else try{await E()}catch{await p()}return{get kind(){return n.kind},setTheme(e,t){u={t:e,s:t},n.setTheme(e,t)},setSeats(e){v(e),f(),n.setSeats(e)},setState(e,t){let l=s.get(e);if(l)l.state=t;f(),n.setState(e,t)},setAvatar(e,t){let l=s.get(e);if(l)l.avatarSvg=t;return n.setAvatar(e,t)},setReducedMotion:(e)=>n.setReducedMotion(e),resetCamera:()=>n.resetCamera(),focus:(e,t)=>n.focus(e,t),focused:()=>n.focused(),getStats:()=>n.getStats(),dispose(){n?.dispose(),o.remove()}}}export{A as mountRoundTable};
|