pi-straw-boss 0.67.0 → 0.69.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/NOTICE.md +1 -1
- package/README.md +3 -3
- package/README.zh-TW.md +3 -3
- package/dist/gui/assets/{allyasks-DfHkX0-2.js → allyasks-BId8RwSi.js} +1 -1
- package/dist/gui/assets/allyunits-qZ9Oi8pU.js +2 -0
- package/dist/gui/assets/{answer-D7GoQgxu.js → answer-FRBxyAhO.js} +1 -1
- package/dist/gui/assets/{ask-DPzOum6G.js → ask-hH0IsjkM.js} +1 -1
- package/dist/gui/assets/{asks-X4aU5RRr.js → asks-DfkMf5Bc.js} +1 -1
- package/dist/gui/assets/{blockschunk-B6q5CSeC.js → blockschunk-BipvfK9z.js} +81 -78
- package/dist/gui/assets/{box-CyLXzlCb.js → box--tGu5fh0.js} +1 -1
- package/dist/gui/assets/{chat-BFjmvBv0.js → chat-BUYVk40F.js} +2 -2
- package/dist/gui/assets/drawer-BIVf2qL5.js +1 -0
- package/dist/gui/assets/index-CfxTRKov.js +4 -0
- package/dist/gui/assets/index-yvAHBXVf.css +1 -0
- package/dist/gui/assets/{lanwait-B63wdx0y.js → lanwait-CfviwZ1Y.js} +1 -1
- package/dist/gui/assets/layer-CRVUNEIC.js +1 -0
- package/dist/gui/assets/{lightbox-CNFoFwaa.js → lightbox-BFWGHbQX.js} +1 -1
- package/dist/gui/assets/link-DBpoLbxE.js +1 -0
- package/dist/gui/assets/{linkdialogs-D5sjzkKE.js → linkdialogs-kpO-VkR1.js} +1 -1
- package/dist/gui/assets/mdbody-CkMZtGcN.js +2 -0
- package/dist/gui/assets/{pair-BGqZRemQ.js → pair-liBR8zqd.js} +3 -3
- package/dist/gui/assets/{picker-DykPxdsJ.js → picker-DAyj_VRn.js} +1 -1
- package/dist/gui/assets/{server-DS3AHaBj.js → server-CLOETMp5.js} +2 -2
- package/dist/gui/assets/sessionfacts-B1NCBHmm.js +1 -0
- package/dist/gui/assets/{settings-ezPHZYa0.js → settings-C6QWGWd7.js} +2 -2
- package/dist/gui/assets/spawn-UJ5hiVOr.js +1 -0
- package/dist/gui/assets/{termcard-vAqvb7Dr.js → termcard-CYpds_ge.js} +1 -1
- package/dist/gui/assets/{towerturns-D4Alw9EP.js → towerturns-D2MZjoqB.js} +1 -1
- package/dist/gui/assets/trains-_2p0835Z.js +1 -0
- package/dist/gui/assets/{trust-uj6tKfzz.js → trust-CjgWBFt5.js} +1 -1
- package/dist/gui/assets/views-sk6RtITo.js +2 -0
- package/dist/gui/assets/{waitcard-DH-kVObu.js → waitcard-BxPs1wl7.js} +1 -1
- package/dist/gui/assets/yard-B5_-7bMG.js +1 -0
- package/dist/gui/index.html +7 -5
- package/dist/gui/themes/raven/{raven-DwYlt5QU.js → raven-Brb7Uwyl.js} +2 -2
- package/dist/gui/themes/raven/raven-DTB8C7Y1.css +1 -0
- package/dist/gui/themes/zen/audiobus-DTkoiSCz.js +1 -0
- package/dist/gui/themes/zen/zen-2COoPD72.css +1 -0
- package/dist/gui/themes/zen/zen-MeIsUPGE.js +2 -0
- package/dist/gui/themes/zen/zenmusic-CyHbKU-j.js +1 -0
- package/dist/gui/themes.json +4 -4
- package/dist/server/{chunk-B2P7IQIV.mjs → chunk-6WFSA5BB.mjs} +24 -15
- package/dist/server/cli.mjs +1 -1
- package/dist/server/main.mjs +30 -23
- package/package.json +2 -2
- package/prompts/dispatch.md +3 -0
- package/prompts/duty-standing.md +6 -0
- package/prompts/graph-fan-out.md +2 -0
- package/prompts/graph-orchestrator-worker.md +2 -0
- package/prompts/integrator.md +3 -3
- package/prompts/main.md +6 -7
- package/prompts/planning.md +3 -7
- package/prompts/tower-run.md +1 -1
- package/prompts/train.md +1 -1
- package/src/activity.ts +5 -4
- package/src/answered.ts +3 -3
- package/src/boardset.ts +1 -1
- package/src/briefing.ts +47 -14
- package/src/dialogs.ts +1 -1
- package/src/docs.ts +4 -4
- package/src/documents.ts +2 -2
- package/src/duty.ts +16 -0
- package/src/endpoint.ts +1 -1
- package/src/header.ts +1 -3
- package/src/hygiene.ts +1 -1
- package/src/index.ts +9 -5
- package/src/items.ts +5 -3
- package/src/link/boardtargets.ts +1 -1
- package/src/mainduty.ts +58 -0
- package/src/net.ts +6 -6
- package/src/order.ts +5 -6
- package/src/planmsg.ts +23 -0
- package/src/presence.ts +9 -14
- package/src/roles.ts +1 -1
- package/src/server/boardpanel.ts +1 -1
- package/src/server/carnotices.ts +1 -1
- package/src/server/carops.ts +1 -1
- package/src/server/cli.ts +1 -1
- package/src/server/head.ts +1 -1
- package/src/{agent/config.ts → server/headless.ts} +1 -1
- package/src/server/headside.ts +2 -2
- package/src/server/intercom.ts +4 -4
- package/src/{agent → server}/kit.ts +5 -5
- package/src/server/main.ts +3 -3
- package/src/server/operatesanitize.ts +4 -3
- package/src/server/paths.ts +17 -0
- package/src/server/towerclient.ts +1 -1
- package/src/server/towers.ts +1 -1
- package/src/server/trainyard.ts +1 -1
- package/src/session.ts +18 -2
- package/src/state.ts +9 -3
- package/src/todo.ts +7 -3
- package/src/tools.ts +32 -2
- package/src/train/yardview.ts +2 -2
- package/src/trainguard.ts +8 -4
- package/src/trainsign.ts +2 -25
- package/dist/gui/assets/allyunits-ZoEkBMex.js +0 -2
- package/dist/gui/assets/drawer-DE1fU2oD.js +0 -1
- package/dist/gui/assets/index-BFhWoJqT.css +0 -1
- package/dist/gui/assets/index-BcIq2bw5.js +0 -4
- package/dist/gui/assets/layer-D_IqtLH8.js +0 -1
- package/dist/gui/assets/link-DCS6UqPw.js +0 -1
- package/dist/gui/assets/mdbody-BGSKc45o.js +0 -2
- package/dist/gui/assets/sessionfacts-DPWMQfvk.js +0 -1
- package/dist/gui/assets/spawn-Bcs-6KXy.js +0 -1
- package/dist/gui/assets/trains-DzNQw336.js +0 -1
- package/dist/gui/assets/views-DubKf18l.js +0 -2
- package/dist/gui/assets/yard-BikAkMcD.js +0 -1
- package/dist/gui/themes/raven/raven-D4iCVluC.css +0 -1
- package/dist/gui/themes/zen/audiobus-D2ARHGet.js +0 -1
- package/dist/gui/themes/zen/zen-DH2YhV_8.js +0 -2
- package/dist/gui/themes/zen/zen-Du35NMI0.css +0 -1
- package/dist/gui/themes/zen/zenmusic-5XvJwQvP.js +0 -1
- package/src/agent/claim.ts +0 -45
- package/src/agent/cli.ts +0 -181
- package/src/agent/legacy.ts +0 -33
- package/src/agent/paths.ts +0 -125
- package/src/agent/sidecar.ts +0 -341
package/NOTICE.md
CHANGED
|
@@ -77,7 +77,7 @@ Its three sounds are released under Creative Commons Zero (CC0 1.0), trimmed and
|
|
|
77
77
|
|
|
78
78
|
## pi-better-show (`dist/gui/assets/blockschunk-*.js`)
|
|
79
79
|
|
|
80
|
-
The GUI's block chunk bundles [pi-better-show](https://github.com/wayne930242/pi-better-show) 0.
|
|
80
|
+
The GUI's block chunk bundles [pi-better-show](https://github.com/wayne930242/pi-better-show) 0.5.0 (its parser, its answer encoding, and its fourteen elements), and with it the [yaml](https://github.com/eemeli/yaml) library 2.9.1.
|
|
81
81
|
|
|
82
82
|
pi-better-show: MIT License, Copyright (c) 2026 wayne930242
|
|
83
83
|
|
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@ English | [繁體中文](https://github.com/wayne930242/pi-straw-boss/blob/main/
|
|
|
18
18
|
|
|
19
19
|
<p align="center"><sub>A unit's comms, a question you can answer from the browser, the Geek view, the settings page where each device picks its view, and the same page on a phone. A tower's wait for you is answered in place: **Handle** in its dialog (or on the tower's card) unfolds a box, and Enter tells the tower.</sub></p>
|
|
20
20
|
|
|
21
|
-
**Zen** is the third view, for the hours when you are answering the net rather than steering it. When something waits for you, the page shows that one thing alone: no map. A card never takes the screen by itself, whatever you are doing: one quiet line (above the input on the circle, under the name beside a session) says how many wait ("1 card waits for Enter. No rush, when you're ready."), and **Enter**, or a tap on the line, takes the next, blocking questions first. Enter then presses the card's main button (Allow, Trust, Handle, the first choice, Run), but never inside a text field. A card you are on is never replaced or pulled away: if its question is answered elsewhere it stays, says so (answered elsewhere, or that its unit left), and waits for you to close it. Nothing else takes the screen from you either: a terminal opened from a card stays until you go back, a session that ended or lost control stays with a quiet note (its box read-only, Send off), a changed server default view applies at the next load, and a new version of the page loads when you are back at the breath, not under you (one quiet line says it is ready). When you answer or cancel a card you took, the next one that was already waiting when you answered is drawn right after, with no breath between (a card that arrives after your answer, a page without the focus, or a visit to Zen that begins after you left it waits for Enter; for its first 400 ms it ignores a held or doubled Enter, a tap, and Esc, so the key that answered cannot press it); the pause comes after the last card, after you skip one (Maybe later), or after you close one whose question ended elsewhere, and Zen breathes again with the others waiting for Enter. A wait a tower recorded on you (a question only you can settle) is a card of its own: **Handle** unfolds an answer box right on it, Enter or **Send** tells the tower in your words, and the card leaves with the knock; **Dismiss** drops the wait, and **Esc** folds the box with your draft kept. Four things Standard shows in the Link button, the Wi-Fi notice, and a tower's notices are cards of their own too: a **confirm** a teammate's tower asks of this computer (Allow or Deny, with the tool's full arguments), a **dialog a Straw Link box forwarded**, a **pair request** (type the number the phone shows, then Allow or Deny), and a **memory proposal** from a tower (Confirm or Reject). They answer through the same functions as Standard's rows, the server decides when one is over, and a paired phone keeps only the authority it has in Standard (no pair-request card: that is this computer's to decide). A join request stays in Standard. A dialog with several questions shows one at a time: the one you are on is open and clear, the others fold to one faded line (the question, and your answer once it has one), and a scroll or swipe, picking an answer, Tab, or a tap on a line moves on to the next. When nothing waits, a breathing circle and a short line on mindfulness or stillness, with whom it comes from (a Japanese source also has its original, small, below): every visit starts there. `[` or `]` steps to a session to keep you company, its live log and its composer, and the circle sits where the list wraps round; ⌘K's *Back to the breath* returns to it. No session, a tower included, is put there for you. One Esc cancels the question on the page, or skips the card when it cannot be cancelled; Esc twice (or the corner menu's last row) goes back to Standard. The corner menu also holds the language, the view, and the sound and
|
|
21
|
+
**Zen** is the third view, for the hours when you are answering the net rather than steering it. When something waits for you, the page shows that one thing alone: no map. A card never takes the screen by itself, whatever you are doing: one quiet line (above the input on the circle, under the name beside a session) says how many wait ("1 card waits for Enter. No rush, when you're ready."), and **Enter**, or a tap on the line, takes the next, blocking questions first. Enter then presses the card's main button (Allow, Trust, Handle, the first choice, Run), but never inside a text field. A card you are on is never replaced or pulled away: if its question is answered elsewhere it stays, says so (answered elsewhere, or that its unit left), and waits for you to close it. Nothing else takes the screen from you either: a terminal opened from a card stays until you go back, a session that ended or lost control stays with a quiet note (its box read-only, Send off), a changed server default view applies at the next load, and a new version of the page loads when you are back at the breath, not under you (one quiet line says it is ready). When you answer or cancel a card you took, the next one that was already waiting when you answered is drawn right after, with no breath between (a card that arrives after your answer, a page without the focus, or a visit to Zen that begins after you left it waits for Enter; for its first 400 ms it ignores a held or doubled Enter, a tap, and Esc, so the key that answered cannot press it); the pause comes after the last card, after you skip one (Maybe later), or after you close one whose question ended elsewhere, and Zen breathes again with the others waiting for Enter. A wait a tower recorded on you (a question only you can settle) is a card of its own: **Handle** unfolds an answer box right on it, Enter or **Send** tells the tower in your words, and the card leaves with the knock; **Dismiss** drops the wait, and **Esc** folds the box with your draft kept. Four things Standard shows in the Link button, the Wi-Fi notice, and a tower's notices are cards of their own too: a **confirm** a teammate's tower asks of this computer (Allow or Deny, with the tool's full arguments), a **dialog a Straw Link box forwarded**, a **pair request** (type the number the phone shows, then Allow or Deny), and a **memory proposal** from a tower (Confirm or Reject). They answer through the same functions as Standard's rows, the server decides when one is over, and a paired phone keeps only the authority it has in Standard (no pair-request card: that is this computer's to decide). A join request stays in Standard. A dialog with several questions shows one at a time: the one you are on is open and clear, the others fold to one faded line (the question, and your answer once it has one), and a scroll or swipe, picking an answer, Tab, or a tap on a line moves on to the next. When nothing waits, a breathing circle and a short line on mindfulness or stillness, with whom it comes from (a Japanese source also has its original, small, below): every visit starts there. `[` or `]` steps to a session to keep you company, its live log and its composer, and the circle sits where the list wraps round; ⌘K's *Back to the breath* returns to it. No session, a tower included, is put there for you. One Esc cancels the question on the page, or skips the card when it cannot be cancelled; Esc twice (or the corner menu's last row) goes back to Standard. The corner menu also holds the language, the view, and the switch and volume of the sound effects and of the background sound, and the button beside it takes the page to full screen. An answer that leaves a terminal step (robot_hand's *Put it in my prompt* or a new Herdr pane) shows a small card in ink to finish it, which stays until you go back to Zen, with a quiet line when its step is done; *Full terminal* on the card opens the whole terminal inside Zen, with *Back to Zen* in the top right corner. **Keys.** Enter or Space ends the breathing pause early (so does a tap); Esc answers or skips the card on the page, and a second Esc within 600 ms goes back to Standard (with the corner menu open, Esc only closes it; with text in a box, it only lets the box go). Inside a terminal the page does not take Esc: Shift+Esc lets the keyboard out of the terminal. **H** opens *Context* on a card, the unit's session log inside the card, read-only, and you can still answer while it is open; H or Esc closes it. `[` and `]` step the session beside you (the companion) through the sessions you can talk to. **⌘K** (Ctrl+K off a Mac) opens a command palette for the page's actions and the corner menu's choices. While nothing waits, a quiet line at the top says how many units work and how many are idle; it never counts what waits. Moving the pointer leaves faint ripples. **Sound effects** follow the settings page's Sound effects switch (off by default) and volume: a soft singing-bowl tone when an item takes the screen, a wooden-fish knock when one is done, a lower bowl on an error; the corner menu's *Try the sounds* plays them. Set it as the default with `/boss gui view zen`, or pick it on a device's settings page. Music is yours: put audio files (mp3, m4a, ogg, wav, flac, and the like) in `~/.pi/agent/straw-boss-music/` and Zen shows a ♪ in the corner that plays them on a loop, with a ⌄ to choose the track (shown when there are two or more); with no files there is no ♪. The music is background sound: it plays only while the settings page's Background sound switch is on (off by default; the corner menu has it too), at that switch's volume. The folder is read each time Zen shows, and tracks cross-fade into themselves so the loop has no gap. On a phone nothing plays before your first tap (♪ says *tap to play* until then, and again after the phone locks), the music pauses while the page is hidden, and the ringer switch mutes it. Motion stops under *reduce motion*, and the page follows the system's forced colours.
|
|
22
22
|
|
|
23
23
|
<p align="center"><img src="docs/gui-zen-item.png" width="49%" alt="The Zen view with one item: a robot_hand question from ops-main on an ink-dark page, its choices as lines of text, each with a dot, and Maybe later below"> <img src="docs/gui-zen-idle.png" width="49%" alt="The Zen view when nothing waits: a session stepped to with ], its live log and its composer"></p>
|
|
24
24
|
|
|
@@ -101,7 +101,6 @@ Each of these is optional. When it is installed, Straw Boss picks it up; without
|
|
|
101
101
|
| pi-code (hooks extension, with its dialog events) | Its hook confirmation ("Allow bash?": Allow or Deny, before any gated tool call) can be answered from the GUI. |
|
|
102
102
|
| [pi-herdr-doc-review](https://www.npmjs.com/package/pi-herdr-doc-review) 0.4.0 or newer | Documents a session shows open beside its comms: HTML in a sandboxed frame whose form answers the agent, text read-only. |
|
|
103
103
|
| [@juicesharp/rpiv-todo](https://www.npmjs.com/package/@juicesharp/rpiv-todo) 2.13 or newer | A session's todo list shows above its composer in the GUI, read from the session file. |
|
|
104
|
-
| [straw-boss](https://github.com/wayne930242/straw-boss) (Claude Code and Codex) | A Claude Code or Codex main-agent session joins the tab's net through a small sidecar process that straw-boss starts with the session: a member, or a main when it registers as an orchestrator. It shows in the tower dashboard, the sidebar, and the GUI with an agent badge (the GUI cannot type into it), calls the tower and broadcasts with `straw-net.py`, and hears net messages as `[straw net …]` lines typed into its pane ([how](docs/how-it-works.md#from-claude-code-or-codex)). |
|
|
105
104
|
|
|
106
105
|
Any extension's `select` and `confirm` (an `mp-infra` command review, say) can be answered from the GUI too, with no change to that extension: Straw Boss wraps them on pi's shared `ctx.ui`, opens pi's own dialog as always, and relays the same dialog; the first answer wins. Both can be answered from a paired device, and cancelled with the question card's Cancel button (what Escape gives in the terminal: nothing for a select, No for a confirm), except where every choice is for this computer's own page only (such as the `/boss` link approval, or `gui rotate`). `input`, `editor`, and `custom` are never touched, and they, with `ask_user` from pi-ask-user, show read-only in the GUI, with the terminal one tap away.
|
|
107
106
|
|
|
@@ -129,6 +128,7 @@ The tower only routes and coordinates, so it can run a lighter model: set `tower
|
|
|
129
128
|
| `board_set` | A tab's main: override its own board entry (one line of current work, up to 8 checklist items), `auto: true` to give it back to the auto-fill from its todo list and name, or `clear: true` to delete it when its work is finished or shelved. |
|
|
130
129
|
| `boss_broadcast` | Message a tab, a workspace, all towers, or every session (under a header). |
|
|
131
130
|
| `boss_server` | See the sb server (status works with the server down), read its log (up to 200 lines), or restart it with a reason. Refused while the boss stopped the server, once a minute at most, and never in a remote turn. |
|
|
131
|
+
| `boss_duty` | A tab's main: set its kind (`coordinator`, `integrator`, `standing`) with a reason; the kind is the prompt it runs and shows on the page. |
|
|
132
132
|
| `boss_rename` | Name this session with a short phrase for its current work; the net and the GUI show it, and a main agent's tab takes it as its label. Main agents call it when their work changes. |
|
|
133
133
|
| `/boss` | Take over as this tab's main agent. |
|
|
134
134
|
| `/boss status`, `/boss tower` | Show the status; open and focus the tower. |
|
|
@@ -242,7 +242,7 @@ Heavy-command slots, Linux cgroups and a runaway-process watchdog are planned fo
|
|
|
242
242
|
|
|
243
243
|
## Learn more
|
|
244
244
|
|
|
245
|
-
[How it works](docs/how-it-works.md) covers roles, the tower, the dashboard, the browser view, what the extension writes
|
|
245
|
+
[How it works](docs/how-it-works.md) covers roles, the tower, the dashboard, the browser view, and what the extension writes.
|
|
246
246
|
|
|
247
247
|
## License
|
|
248
248
|
|
package/README.zh-TW.md
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
|
|
19
19
|
<p align="center"><sub>單位的通訊畫面、可以直接在瀏覽器回答的問題、極客檢視、每個裝置自選檢視的設定頁,以及同一個頁面在手機上的樣子。塔台記在你身上的等待事項就在原處回覆:在它的對話框(或塔台卡片上)按「去處理」展開輸入框,按 Enter 就送給塔台。</sub></p>
|
|
20
20
|
|
|
21
|
-
**禪(Zen)** 是第三種檢視,給你在回應這張網、而不是指揮它的時候用。有東西在等你時,整個畫面只放那一件事:沒有地圖。不管你正在做什麼,卡片都不會自己搶走畫面:有一行安靜的字說有幾張在等(在圓圈上是輸入框上方,陪著某個 session 時在名字下面,「1 張卡等 Enter。不急,等你準備好。」),按 **Enter** 或點那一行才接下一張,會阻擋智慧體的問題先來。接下來 Enter 會按下卡片的主要按鈕(允許、信任、去處理、第一個選項、執行),但在文字輸入框裡不會。你正在看的卡片也不會被換掉或抽走:它的問題如果在別處被回答了(或它的單位離開了),卡片會留著、說明原因,等你自己關掉。其他東西也不會把畫面從你手上拿走:從卡片開的終端機會待到你自己回去,陪伴的 session 結束或失去控制時畫面會留著並安靜地註明(輸入框唯讀、送出關閉),伺服器預設檢視改了,也要等下次載入才套用,頁面有新版本也一樣:卡片、終端機、陪伴的 session、主塔台的對話、指令面板或選單開著時不會重新載入,只有一行安靜的字說「有新版本,回到呼吸時會更新」,回到呼吸圓圈、什麼都沒開時才載入。你回答或取消一張自己接下的卡片之後,你送出答案的當下已經在排的下一張卡片會直接接上,中間不再回到呼吸(答案送出之後才來的卡片、沒有焦點的頁面、離開禪之後才開始的新一次造訪,都改等你按 Enter;接上的前 400 毫秒內,按住或連按的 Enter、點擊和 Esc 都不會按到它,所以剛才答題的那一下不會誤按下一張);最後一張答完、跳過(「晚點再說」),或關掉一張問題已在別處結束的卡片之後,才會有一次呼吸般的停頓,回到呼吸,其餘的仍等你按 Enter。塔台記在你身上的等待事項(只有你能決定的事)自己是一張卡片:按「去處理」會在卡片上直接展開輸入框,按 Enter 或「送出」把你的話交給塔台,卡片隨一聲木魚離開;「略過」把這則等待丟掉,Esc 把輸入框收起並保留草稿。標準檢視裡放在 Link 按鈕、Wi-Fi 通知和塔台通知的四件事,在禪裡也各是一張卡片:隊友的塔台向這台電腦要的**確認**(允許或拒絕,附上工具的完整參數)、Straw Link 盒子**轉過來的對話框**、**配對請求**(輸入手機上顯示的號碼,再按允許或拒絕),以及塔台提出的**記憶提案**(確認或駁回)。它們呼叫的是和標準檢視同一組函式,什麼時候算結束由伺服器決定,已配對的手機只有它在標準檢視裡原本就有的權限(沒有配對請求卡片:那是這台電腦自己決定的事)。加入團隊的請求仍留在標準檢視。一個對話框有好幾個問題時,一次只清楚地顯示一題:你正在回答的那題展開、清晰,其餘收成一行淡淡的字(題目,答了就接著你的答案),捲動或滑動、選好答案、按 Tab 或點一下那一行就移到下一題。沒有東西在等時,畫面是一個呼吸的圓圈和一句正念的話,每次進入禪都從這裡開始。用 `[` 或 `]` 可以挑一個 session 來陪,畫面會換成它的即時紀錄和輸入框;清單繞完一圈會回到呼吸圓圈,⌘K 裡的「回到呼吸」也能隨時回去。不會自動放一個 session(包括塔台)在那裡。按一次 Esc 會取消畫面上的問題,不能取消的卡片則是跳過;連按兩次 Esc
|
|
21
|
+
**禪(Zen)** 是第三種檢視,給你在回應這張網、而不是指揮它的時候用。有東西在等你時,整個畫面只放那一件事:沒有地圖。不管你正在做什麼,卡片都不會自己搶走畫面:有一行安靜的字說有幾張在等(在圓圈上是輸入框上方,陪著某個 session 時在名字下面,「1 張卡等 Enter。不急,等你準備好。」),按 **Enter** 或點那一行才接下一張,會阻擋智慧體的問題先來。接下來 Enter 會按下卡片的主要按鈕(允許、信任、去處理、第一個選項、執行),但在文字輸入框裡不會。你正在看的卡片也不會被換掉或抽走:它的問題如果在別處被回答了(或它的單位離開了),卡片會留著、說明原因,等你自己關掉。其他東西也不會把畫面從你手上拿走:從卡片開的終端機會待到你自己回去,陪伴的 session 結束或失去控制時畫面會留著並安靜地註明(輸入框唯讀、送出關閉),伺服器預設檢視改了,也要等下次載入才套用,頁面有新版本也一樣:卡片、終端機、陪伴的 session、主塔台的對話、指令面板或選單開著時不會重新載入,只有一行安靜的字說「有新版本,回到呼吸時會更新」,回到呼吸圓圈、什麼都沒開時才載入。你回答或取消一張自己接下的卡片之後,你送出答案的當下已經在排的下一張卡片會直接接上,中間不再回到呼吸(答案送出之後才來的卡片、沒有焦點的頁面、離開禪之後才開始的新一次造訪,都改等你按 Enter;接上的前 400 毫秒內,按住或連按的 Enter、點擊和 Esc 都不會按到它,所以剛才答題的那一下不會誤按下一張);最後一張答完、跳過(「晚點再說」),或關掉一張問題已在別處結束的卡片之後,才會有一次呼吸般的停頓,回到呼吸,其餘的仍等你按 Enter。塔台記在你身上的等待事項(只有你能決定的事)自己是一張卡片:按「去處理」會在卡片上直接展開輸入框,按 Enter 或「送出」把你的話交給塔台,卡片隨一聲木魚離開;「略過」把這則等待丟掉,Esc 把輸入框收起並保留草稿。標準檢視裡放在 Link 按鈕、Wi-Fi 通知和塔台通知的四件事,在禪裡也各是一張卡片:隊友的塔台向這台電腦要的**確認**(允許或拒絕,附上工具的完整參數)、Straw Link 盒子**轉過來的對話框**、**配對請求**(輸入手機上顯示的號碼,再按允許或拒絕),以及塔台提出的**記憶提案**(確認或駁回)。它們呼叫的是和標準檢視同一組函式,什麼時候算結束由伺服器決定,已配對的手機只有它在標準檢視裡原本就有的權限(沒有配對請求卡片:那是這台電腦自己決定的事)。加入團隊的請求仍留在標準檢視。一個對話框有好幾個問題時,一次只清楚地顯示一題:你正在回答的那題展開、清晰,其餘收成一行淡淡的字(題目,答了就接著你的答案),捲動或滑動、選好答案、按 Tab 或點一下那一行就移到下一題。沒有東西在等時,畫面是一個呼吸的圓圈和一句正念的話,每次進入禪都從這裡開始。用 `[` 或 `]` 可以挑一個 session 來陪,畫面會換成它的即時紀錄和輸入框;清單繞完一圈會回到呼吸圓圈,⌘K 裡的「回到呼吸」也能隨時回去。不會自動放一個 session(包括塔台)在那裡。按一次 Esc 會取消畫面上的問題,不能取消的卡片則是跳過;連按兩次 Esc(或選單最後一列)回到標準檢視。右上角的選單還有語言、檢視,以及音效與背景音(各有開關和音量),旁邊的按鈕可以讓頁面全螢幕。回答之後留下終端機步驟的選項(robot_hand 的「放進我的 prompt」或新的 Herdr 窗格)會在禪裡面出現一張墨色的小卡片讓你完成它,它會待到你自己回到禪,步驟完成時在上方安靜地註明;卡片上的「完整終端機」會在禪裡打開整個終端機,右上角有「回到禪」。**按鍵。** Enter 或空白鍵可以提早結束呼吸停頓(點一下畫面也行);Esc 回答或跳過畫面上的卡片,600 毫秒內再按一次 Esc 回到標準檢視(選單開著時 Esc 只關選單;輸入框裡有字時只是離開輸入框)。終端機在使用中時頁面不攔 Esc,Shift+Esc 可以讓鍵盤離開終端機。**H** 在卡片上展開「前情」,也就是這個 unit 的 session 紀錄,唯讀地顯示在卡片裡,展開時仍然可以回答;再按 H 或 Esc 收起。`[` 與 `]` 在你能對話的 session 之間切換身邊陪著的那一個。**⌘K**(不在 Mac 上是 Ctrl+K)打開指令面板,列出頁面的動作和右上角選單的選項。沒有東西在等時,頂端有一行淡淡的字說明幾個 unit 在工作、幾個閒著,不會數還在等的。滑鼠移動時會留下淡淡的漣漪。**音效**跟隨設定頁的「音效」開關(預設關)與音量;音樂屬於「背景音」,要設定頁(或右上角選單)的「背景音」開關(預設關)打開才會播,音量也跟著它:待辦出現時是一聲柔和的頌缽,完成時是一聲木魚,出錯時是低一點的缽聲;選單裡的「試聽音效」可以先聽。用 `/boss gui view zen` 把它設成預設,或在裝置的設定頁自己選。音樂由你自己放:把音檔(mp3、m4a、ogg、wav、flac 等)放進 `~/.pi/agent/straw-boss-music/`,禪的右上角就會出現 ♪,循環播放,旁邊的 ⌄ 可以選曲(有兩首以上才出現);資料夾裡沒有檔案就不會出現 ♪。每次顯示禪時都會重讀資料夾,曲子播完前會與自己交叉淡入淡出,所以循環沒有空檔。手機上要先點一下才會出聲(在那之前 ♪ 寫「點一下播放」,手機鎖屏之後也會再次這樣寫),頁面被藏起來時音樂暫停,靜音開關也會讓它靜音。「減少動態效果」開啟時畫面不動,系統的強制色彩模式也會被遵守。
|
|
22
22
|
|
|
23
23
|
<p align="center"><img src="docs/gui-zen-item.png" width="49%" alt="禪檢視裡的一件待辦:墨色畫面上是 ops-main 的 robot_hand 問題,選項是一行行前面有小圓點的字,下方有「晚點再說」"> <img src="docs/gui-zen-idle.png" width="49%" alt="沒有東西在等時的禪檢視:用 ] 挑來陪的 session,有它的即時紀錄和輸入框"></p>
|
|
24
24
|
|
|
@@ -101,7 +101,6 @@ pi install npm:pi-straw-boss
|
|
|
101
101
|
| pi-code(hooks 擴充,需含它的對話框事件) | 它的 hook 確認(「Allow bash?」:允許或拒絕,在任何被攔下的工具呼叫之前)可以在 GUI 作答。 |
|
|
102
102
|
| [pi-herdr-doc-review](https://www.npmjs.com/package/pi-herdr-doc-review) 0.4.0 以上 | session 展示的文件會開在它的通訊畫面旁邊:HTML 放在沙箱框架裡,表單送出的內容會回給 agent;文字檔只能讀。 |
|
|
103
103
|
| [@juicesharp/rpiv-todo](https://www.npmjs.com/package/@juicesharp/rpiv-todo) 2.13 以上 | session 的待辦清單會顯示在 GUI 的輸入框上方,內容從 session 檔讀取。 |
|
|
104
|
-
| [straw-boss](https://github.com/wayne930242/straw-boss)(Claude Code 和 Codex) | Claude Code 或 Codex 的主智慧體 session 會透過 straw-boss 隨 session 啟動的小型 sidecar 行程加入分頁的網:預設是成員,登記成 orchestrator 後升成主智慧體。它會出現在塔台儀表板、側邊欄和 GUI(帶智慧體徽章,GUI 無法對它輸入),可以用 `straw-net.py` 呼叫塔台、廣播,網上的訊息會以 `[straw net …]` 開頭的一行打進它的 pane([說明](docs/how-it-works.md#from-claude-code-or-codex),英文)。 |
|
|
105
104
|
|
|
106
105
|
任何 extension 的 `select` 和 `confirm`(例如 `mp-infra` 的指令審查)也可以在 GUI 作答,不必改動那個 extension:Straw Boss 把它們包在 pi 共用的 `ctx.ui` 上,照常打開 pi 自己的對話框,同時轉送同一個對話框,先答的算數。`select` 和 `confirm` 都可以從配對的裝置作答,也都可以用問題卡片上的「取消」按鈕取消(效果等同終端機裡按 Escape:select 沒有選擇,confirm 回答「否」);但每個選項都只限這台電腦頁面使用的對話框(例如 `/boss` link 核准、`gui rotate`),配對的裝置不能取消。`input`、`editor`、`custom` 完全不碰,它們和 pi-ask-user 的 `ask_user` 在 GUI 裡只能看,可以一鍵切到終端機回答。
|
|
107
106
|
|
|
@@ -129,6 +128,7 @@ pi install npm:pi-straw-boss
|
|
|
129
128
|
| `board_set` | 分頁的主智慧體用:覆寫自己的看板項目(一行目前的工作,加最多 8 個清單項),用 `auto: true` 交還給依待辦清單和名稱的自動填入,或用 `clear: true` 在工作做完或擱置時刪掉它。 |
|
|
130
129
|
| `boss_broadcast` | 傳訊息給一個分頁、一個工作區、所有塔台,或所有 session(訊息開頭有標頭)。 |
|
|
131
130
|
| `boss_server` | 查看 sb 伺服器(伺服器停著時 status 也能用)、讀它的記錄(最多 200 行),或附上理由重新啟動它。你刻意停掉伺服器時會被拒絕,每分鐘最多一次,遠端回合裡也一律拒絕。 |
|
|
131
|
+
| `boss_duty` | 分頁主智慧體設定自己的種類(`coordinator`、`integrator`、`standing`)並寫理由;種類就是它執行的提示詞,也會顯示在頁面上。 |
|
|
132
132
|
| `boss_rename` | 用一個短語替這個 session 命名,說明它現在在做什麼;net 與 GUI 會顯示它,主智慧體的分頁也會改成這個名稱。主智慧體換工作時會呼叫它。 |
|
|
133
133
|
| `/boss` | 接手成為這個分頁的主智慧體。 |
|
|
134
134
|
| `/boss status`、`/boss tower` | 顯示狀態;開啟塔台並切換過去。 |
|
|
@@ -242,7 +242,7 @@ pi-herdr-agents 的 worker 會向 sb 伺服器登記;worker 結束或它的 pa
|
|
|
242
242
|
|
|
243
243
|
## 延伸閱讀
|
|
244
244
|
|
|
245
|
-
[運作方式](docs/how-it-works.md)
|
|
245
|
+
[運作方式](docs/how-it-works.md)(英文)說明角色、塔台、儀表板、瀏覽器畫面,以及這個擴充套件會寫入什麼。
|
|
246
246
|
|
|
247
247
|
## 授權
|
|
248
248
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{C as e}from"./towermodel-BpgH7epr.js";import{t}from"./runtime-ZX6HkxDa.js";import{ct as n,ft as r,ut as i}from"./index-
|
|
1
|
+
import{C as e}from"./towermodel-BpgH7epr.js";import{t}from"./runtime-ZX6HkxDa.js";import{ct as n,ft as r,ut as i}from"./index-CfxTRKov.js";import{mountDialogCards as a}from"./linkdialogs-kpO-VkR1.js";var o=t=>{let n=e(`en`,t?.count,{},!0);return n===`one`?`${t?.count} question waits for you: answer it here`:n===`other`?`${t?.count} questions wait for you: answer them here`:`ally_asks_button`},s=e=>`${e?.count} 個問題等你回答,在這裡回答`,c=((e,n={})=>(n.locale??t())===`zh-TW`?s(e):o(e)),l=e=>e.tower===`blocked`||e.tabs.some(e=>e.state===`blocked`);function u(e){let t=new Map,r=i(e?.allies??[]);for(let i of e?.alerts??[]){let e=i.kind===`dialog`?n(i):void 0;if(e!==`open`&&e!==`sent`)continue;let a=r.filter(e=>e.device===i.data.device),o=a.filter(e=>e.teams.some(e=>e.team===i.team)),s=o.length?o:a,c=s.find(l)??s[0];c&&t.set(c.id,[...t.get(c.id)??[],i])}return t}var d=`.ally-unit[data-state="blocked"], .ally-tab[data-state="blocked"]`;function f(){let e=new WeakMap,t=t=>{let i=e.get(t);if(i)return i;let o=r(`button`,{type:`button`,class:`ally-asks-btn`,"aria-expanded":`false`}),s=r(`ul`,{class:`ally-asks-list`}),c=r(`div`,{class:`ally-asks`},o,s);return i={box:c,btn:o,list:s,cards:a(),ids:``},e.set(t,i),o.onclick=()=>n(t),t.addEventListener(`click`,e=>{let r=e.target?.closest?.(d);r&&t.contains(r)&&t.dataset.asks&&!e.target.closest(`details`)&&n(t)}),t.append(c),i};function n(t){let n=e.get(t);if(!n||!t.dataset.asks)return;let r=t.dataset.asking===void 0;r?t.dataset.asking=``:delete t.dataset.asking,n.list.hidden=!r,n.btn.setAttribute(`aria-expanded`,String(r))}function i(n,r){if(!r.length&&!e.has(n))return;let i=t(n);if(i.box.hidden=!r.length,!r.length){delete n.dataset.asks,delete n.dataset.asking,i.btn.setAttribute(`aria-expanded`,`false`),i.cards.keep(new Set),i.list.replaceChildren(),i.ids=``;return}n.dataset.asks=String(r.length),i.btn.textContent=c({count:r.length}),i.list.hidden=n.dataset.asking===void 0,i.cards.keep(new Set(r.map(e=>e.id)));let a=r.map(e=>i.cards.row(e)),o=r.map(e=>e.id).join(`
|
|
2
2
|
`);o!==i.ids&&(i.list.replaceChildren(...a),i.ids=o)}return{toggle:n,fill:i,show:(e,t,n)=>i(e,u(n).get(t.id)??[])}}export{f as mountAllyAsks};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{C as e}from"./towermodel-BpgH7epr.js";import{t}from"./runtime-ZX6HkxDa.js";import{t as n}from"./sentencepack-DtYqpppS.js";import{t as r}from"./link_unit_ago-CvB9wMxM.js";import{At as i,E as a,K as o,Ot as s,T as c,W as l,dt as u,j as d,l as f,v as p,zt as m}from"./index-CfxTRKov.js";var h=e=>`by ${e?.who}`,g=e=>`派工者 ${e?.who}`,ee=((e,n={})=>(n.locale??t())===`zh-TW`?g(e):h(e)),te=((e={},n={})=>(n.locale??t())===`zh-TW`?`中斷並停止`:`Interrupt and stop`),ne=e=>`${e?.box} was not asked: ${e?.reason}`,_=e=>`沒有請 ${e?.box} 停止:${e?.reason}`,v=((e,n={})=>(n.locale??t())===`zh-TW`?_(e):ne(e)),y=((e={},n={})=>(n.locale??t())===`zh-TW`?`停止`:`Stop`),b=e=>`Stop the main ${e?.name}`,x=e=>`停止主智慧體 ${e?.name}`,S=((e,n={})=>(n.locale??t())===`zh-TW`?x(e):b(e)),C=(e,t)=>n(`link_main_stop_aria`,S,e,t),w=e=>`Ask ${e?.box} to stop the main ${e?.name}? Stop lets it quit when it is idle; Interrupt and stop aborts the turn it is in first. The box decides and tells you what happened.`,T=e=>`要請 ${e?.box} 停止主智慧體 ${e?.name} 嗎?「停止」等它閒下來才結束;「中斷並停止」會先中止它進行中的回合。由那台機器決定,結果會通知你。`,E=((e,n={})=>(n.locale??t())===`zh-TW`?T(e):w(e)),D=(e,t)=>n(`link_main_stop_ask`,E,e,t),O=e=>`Mains (${e?.count})`,k=e=>`主智慧體(${e?.count})`,A=((e,n={})=>(n.locale??t())===`zh-TW`?k(e):O(e)),j=(e,t)=>n(`link_mains`,A,e,t),M=((e={},n={})=>(n.locale??t())===`zh-TW`?`發生了什麼事`:`What happened`),N=((e={},n={})=>(n.locale??t())===`zh-TW`?`這個單位最後一次回報的時間`:`When this unit last reported`),P=t=>{let n=e(`en`,t?.count,{},!0);return n===`one`?`${t?.count} monitor`:n===`other`?`${t?.count} monitors`:`link_unit_monitors`},F=e=>`${e?.count} 個監看程序`,I=((e,n={})=>(n.locale??t())===`zh-TW`?F(e):P(e)),re=((e={},n={})=>(n.locale??t())===`zh-TW`?`最後回報`:`Last report`),L=((e={},n={})=>(n.locale??t())===`zh-TW`?`最近沒有狀態`:`no status lately`),R=((e={},n={})=>(n.locale??t())===`zh-TW`?`盒子已超過 3 分鐘沒送狀態,這是它最後一次的內容`:`The box has sent no status for 3 minutes; this is its last one`),z=((e={},n={})=>(n.locale??t())===`zh-TW`?`請在盒子的 trust.json 加入這個專案`:`Add the project to the box's trust.json`),B=((e={},n={})=>(n.locale??t())===`zh-TW`?`為什麼停了`:`Why it stopped`),V=((e={},n={})=>(n.locale??t())===`zh-TW`?`前更新`:` ago`),H=((e={},n={})=>(n.locale??t())===`zh-TW`?``:`updated `),U={choose:d,post:(e,t)=>o(e,t)},W=12e4,G=new Map,K=(e,t)=>`${e.device}/${t.handle}`,q=(e,t,n=Date.now())=>n-(G.get(K(e,t))??-1/0)<W;async function J(e,t,n){let r=await U.choose(D({box:n,name:t.name}),[{label:y(),value:`quit`},{label:te(),value:`interrupt`,tone:`danger`}]);if(!r)return!1;let a=await U.post(`link/unit-stop`,{team:t.team,device:e.device,handle:t.handle,mode:r,reason:``}).catch(()=>({ok:!1,status:0,body:{}}));return a.ok?(G.set(K(e,t),Date.now()),!0):(await U.choose(v({box:n,reason:a.body.reason??(a.status?s({status:a.status}):i())}),[]),!1)}var Y=()=>p(`<li class="ally-unit"><div class="au-head"><i class="au-dot"></i><b class="au-word"></b><span class="au-name"></span><span class="au-time" hidden><span class="au-pre"></span><span class="age"></span><span class="au-ago"></span></span><em class="au-stale" hidden></em></div><p class="au-mons" hidden><b></b><span></span></p><details class="au-mains" hidden><summary><b class="au-mains-label"></b></summary><ul class="au-main-list"></ul></details><details class="au-crash" hidden><summary><b></b><span class="au-time"><span class="age"></span><span class="au-ago"></span></span></summary><pre></pre><p class="au-hint" hidden></p></details><details class="au-report" hidden><summary><b class="au-label"></b><span class="au-peek"></span></summary><div class="md au-md"></div></details></li>`),X,Z=new WeakMap;function Q(e){let t=e.querySelector(`.au-md`),n=Z.get(e)??``;e.open&&t.dataset.report!==n&&(X?Promise.resolve(X):l(()=>import(`./markdown-Bk5NWfKQ.js`).then(e=>e.t).then(e=>X=e),[],import.meta.url)).then(({mount:r,parse:i})=>{e.open&&Z.get(e)===n&&(t.dataset.report=n,t.replaceChildren(r(i(n))))})}function $(e,t,n=``,i=r()){let a=e.querySelector(`.age`);a.dataset.since=String(t),a.textContent=f(t),e.querySelector(`.au-pre`)?.replaceChildren(n),e.querySelector(`.au-ago`).textContent=i}var ie=()=>p(`<li class="au-main"><span class="au-mdot"></span><b class="au-mname"></b><span class="au-mstate"></span><span class="au-mby" hidden></span><button type="button" class="au-stop" hidden></button></li>`);function ae(e,t,n){let r=e.querySelector(`.au-mains`);r.hidden=!t.mains.length,t.mains.length&&(a(r,`.au-mains-label`,j({count:t.mains.length})),c(r.querySelector(`.au-main-list`),t.mains.map(e=>({...e,id:e.handle})),ie,(e,r)=>{let i=r.stopping||q(t,r),o=i?m():r.word;e.dataset.tone=i?`other`:r.tone,a(e,`.au-mname`,r.name),a(e,`.au-mstate`,o);let s=e.querySelector(`.au-mby`);s.hidden=r.byLabel===void 0,s.textContent=r.byLabel===void 0?``:ee({who:r.byLabel});let c=e.querySelector(`.au-stop`);c.hidden=!r.canStop||i,c.textContent=y(),c.setAttribute(`aria-label`,C({name:r.name})),c.onclick=()=>{c.disabled=!0,J(t,r,n).then(t=>{c.disabled=!1,t&&(e.dataset.tone=`other`,a(e,`.au-mstate`,m()),c.hidden=!0)})}}))}function oe(e,t,n,r=``){c(e,t.map(e=>({...e,id:e.unit,named:n})),Y,(e,t)=>{e.dataset.state=t.state,e.dataset.tone=t.tone,e.classList.toggle(`stale`,t.stale),a(e,`.au-word`,t.word),a(e,`.au-name`,t.named?t.unit:``);let n=e.querySelector(`.au-head > .au-time`);n.hidden=!1,n.title=N(),$(n,t.at,H(),V());let i=e.querySelector(`.au-stale`);i.hidden=!t.stale,i.textContent=t.stale?L():``,i.title=t.stale?R():``;let o=e.querySelector(`.au-mons`);o.hidden=!t.monitors.length,t.monitors.length&&(a(o,`b`,I({count:t.monitors.length})),a(o,`span`,t.monitors.join(` · `)),o.title=t.monitors.join(`
|
|
2
|
+
`)),ae(e,t,r);let s=e.querySelector(`.au-crash`);if(s.hidden=!t.crash,s.toggleAttribute(`data-trust`,t.crash?.trust===!0),t.crash){a(s,`summary > b`,t.crash.trust?B():M()),$(s.querySelector(`summary > .au-time`),t.crash.at),a(s,`pre`,t.crash.text);let e=s.querySelector(`.au-hint`);e.hidden=!t.crash.trust,e.textContent=t.crash.trust?z():``}let c=e.querySelector(`.au-report`);c.hidden=!t.report,t.report&&(a(c,`.au-label`,re()),a(c,`.au-peek`,u(t.report)),Z.set(c,t.report),c.ontoggle=()=>Q(c),Q(c))})}export{oe as fillAllyUnits};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{t as e}from"./rolldown-runtime-DK3Fl9T5.js";import{t}from"./ask-
|
|
1
|
+
import{t as e}from"./rolldown-runtime-DK3Fl9T5.js";import{t}from"./ask-hH0IsjkM.js";import{K as n}from"./index-CfxTRKov.js";var r=e({answerPost:()=>i,canAnswer:()=>o,mountAnswer:()=>s,trustPost:()=>a}),i=(e,t)=>t?.(e)??((t,r)=>n(e.startsWith(`grant:`)?`panes/${encodeURIComponent(e.slice(6))}/${t}`:`sessions/${encodeURIComponent(e)}/${t}`,r)),a=e=>e??(e=>n(`trust/answer`,e)),o=(e,...t)=>e===`waiting`&&t.every(Boolean),s=(e,{key:n,show:r,post:i,remote:a,accepted:o,label:s,box:c})=>t(e,i,a,{key:n,show:r},o,s,c);export{a,s as i,r as n,o as r,i as t};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{t as e}from"./runtime-ZX6HkxDa.js";import{a as t,i as n,n as r,r as i,t as a}from"./sending-aEpvzoz2.js";import{Dt as o,Xt as s,ft as c,t as l}from"./index-BcIq2bw5.js";var u=((t={},n={})=>(n.locale??e())===`zh-TW`?`請在終端機中回答。`:`Answer it in the terminal.`),d=((t={},n={})=>(n.locale??e())===`zh-TW`?`請在終端機中回答。`:`Answer them in the terminal.`),f=((t={},n={})=>(n.locale??e())===`zh-TW`?`作用在那台機器本身畫面的選項,從這裡不能選。`:`Choices that act on the machine's own screen are not available from here.`),p=((t={},n={})=>(n.locale??e())===`zh-TW`?`下方還有 ▾`:`More below ▾`),m=((t={},n={})=>(n.locale??e())===`zh-TW`?`也可以自己輸入答案。`:`It also takes your own words.`),h=((t={},n={})=>(n.locale??e())===`zh-TW`?`可以複選。`:`It takes several choices.`),g=((t={},n={})=>(n.locale??e())===`zh-TW`?`已取消。`:`Cancelled.`),_=((t={},n={})=>(n.locale??e())===`zh-TW`?`選擇`:`Choices`),v=((t={},n={})=>(n.locale??e())===`zh-TW`?`瀏覽器拒絕存取剪貼簿。`:`The browser refused the clipboard.`),y=((t={},n={})=>(n.locale??e())===`zh-TW`?`已複製到這台裝置的剪貼簿。`:`Copied to this device's clipboard.`),ee=((t={},n={})=>(n.locale??e())===`zh-TW`?`複製指令`:`Copy command`),b=((t={},n={})=>(n.locale??e())===`zh-TW`?`這個選項有預覽;請在終端機中查看。`:`It has a preview; see it in the terminal.`),x=((t={},n={})=>(n.locale??e())===`zh-TW`?`備註`:`Note`),S=((t={},n={})=>(n.locale??e())===`zh-TW`?`備註(選填)`:`Note (optional)`),C=e=>`Opened while ${e?.tool} was running; it may not be about that call.`,w=e=>`在 ${e?.tool} 執行時開啟,不一定與該呼叫有關。`,T=((t,n={})=>(n.locale??e())===`zh-TW`?w(t):C(t)),E=((t={},n={})=>(n.locale??e())===`zh-TW`?`選項`:`Options`),D=((t={},n={})=>(n.locale??e())===`zh-TW`?`另一個答案沒有被採用;這個可以送出。`:`The other answer was not taken; this one can go.`),O=((t={},n={})=>(n.locale??e())===`zh-TW`?`你的答案`:`Your own answer`),k=((t={},n={})=>(n.locale??e())===`zh-TW`?`或自己輸入答案`:`Or type your own answer`),A=((t={},n={})=>(n.locale??e())===`zh-TW`?`問題已變更,請重新閱讀。`:`The question changed; read it again.`),j=((t={},n={})=>(n.locale??e())===`zh-TW`?`session 讀不懂這個答案。`:`The session could not read that answer.`),M=((t={},n={})=>(n.locale??e())===`zh-TW`?`這個答案不符合問題。`:`That answer does not fit the question.`),N=((t={},n={})=>(n.locale??e())===`zh-TW`?`session 拒絕了這個答案。`:`The session refused that answer.`),P=((t={},n={})=>(n.locale??e())===`zh-TW`?`安全考量,遠端不支援輸入機密。請到執行 GUI 的那台電腦的終端機中回答。`:`For security, entering a secret is not supported remotely. Answer it in the terminal on the computer the GUI runs on.`),te=((t={},n={})=>(n.locale??e())===`zh-TW`?`機密內容只能在終端機輸入,這裡不接受。請到執行 GUI 的那台電腦的終端機中回答。`:`A secret is entered in the terminal only, not here. Answer it in the terminal on the computer the GUI runs on.`),ne=((t={},n={})=>(n.locale??e())===`zh-TW`?`送出答案`:`Send answer`),re=((t={},n={})=>(n.locale??e())===`zh-TW`?`顯示終端機`:`Show terminal`),F=((t={},n={})=>(n.locale??e())===`zh-TW`?`已在終端機中關閉。`:`It was dismissed in the terminal.`),I=((t={},n={})=>(n.locale??e())===`zh-TW`?`它已不再開啟。`:`It is no longer open.`),L=((t={},n={})=>(n.locale??e())===`zh-TW`?`已在終端機中回答。`:`It was already answered in the terminal.`),R=((t={},n={})=>(n.locale??e())===`zh-TW`?`它在等待對話框。`:`It waits on a dialog.`),z={ArrowDown:1,ArrowRight:1,ArrowUp:-1,ArrowLeft:-1};function B(e,t,n,r,i){let{q:a}=n,o=r[a],s=z[e]??0,c=e===`ArrowUp`,l=c||e===`ArrowDown`,u=()=>({to:r.map((e,t)=>({q:(a+1+t)%r.length,part:`opt`})).find(e=>e.q!==a&&!i[e.q])??`send`});if(e===`Tab`){let e=r[a-1],i=n.part===`opt`?o.own||o.note:n.part===`own`&&o.note;return t?n.part===`opt`&&e?{to:{q:a-1,part:e.note?`note`:e.own?`own`:`opt`}}:void 0:i||a===r.length-1?void 0:{to:{q:a+1,part:`opt`}}}if(!t){if(n.part===`opt`){let t=n.o+s;if(s)return t>=0&&t<o.options?{to:{q:a,part:`opt`,o:t},...o.multiple?{}:{pick:t}}:{to:s>0&&o.own?{q:a,part:`own`}:n};if(e===`Enter`||e===` `&&!o.multiple)return{...u(),...o.multiple?{}:{pick:n.o}}}else if(n.part===`own`){if(e===`Enter`)return u();if(l)return{to:c?{q:a,part:`opt`,o:o.options-1}:{q:a,part:`note`}}}else if(c)return{to:{q:a,part:`own`}}}}function V(e,t,n){let r=e=>Math.max(0,e.opts.findIndex(e=>e.getAttribute(`aria-checked`)===`true`)),i=(e,t)=>e.opts.forEach((e,n)=>e.setAttribute(`tabindex`,n===t?`0`:`-1`)),a=e=>{for(let[n,r]of t.entries()){let t=r.opts.indexOf(e);if(t>=0)return{q:n,part:`opt`,o:t};if(e===r.own||e===r.note)return{q:n,part:e===r.own?`own`:`note`}}};t.forEach(e=>i(e,r(e)));let o=e=>{let n=a(e.target);n?.part===`opt`&&i(t[n.q],n.o)};e.addEventListener(`focusin`,o),e.addEventListener(`click`,o);let s=!1,c=!1;return e.addEventListener(`keydown`,i=>{i.key===` `&&(c=!0);let o=a(i.target);if(!o||i.ctrlKey||i.altKey||i.metaKey||i.isComposing)return;let l=i.target;if(o.part!==`opt`&&(i.key===`ArrowUp`?l.selectionStart!==0:i.key===`ArrowDown`&&l.selectionEnd!==l.value.length))return;let u=B(i.key,i.shiftKey,o,t.map(e=>({options:e.opts.length,multiple:e.multiple,own:!!e.own,note:!!e.note})),t.map(e=>e.answered()));if(!u||(i.preventDefault(),i.repeat&&[`Enter`,` `].includes(i.key)))return;if(s=i.key===` `,u.pick!==void 0){let e=t[o.q].opts[u.pick];e.getAttribute(`aria-checked`)!==`true`&&e.click()}let d=u.to===`send`?void 0:t[u.to.q],f=u.to===`send`?n():u.to.part===`opt`?d.opts[u.to.o??r(d)]:u.to.part===`own`?d.own:d.note;f&&!f.disabled&&(e.dispatchEvent(new CustomEvent(`ask-reveal`,{detail:f})),f.focus())}),e.addEventListener(`keyup`,e=>{e.key===` `&&((s||!c)&&e.preventDefault(),s=c=!1)}),()=>t[0]?.opts[r(t[0])]}var H=e=>e.multiple?h():e.freeform&&e.options.length?m():``,U=90,W=(e,t)=>c(`div`,{class:`ask-one`},e.header&&c(`b`,{class:`ask-head`},e.header),c(`p`,{class:`ask-q`,...e.question.length>U?{"data-long":``}:{}},e.question),e.context&&c(`div`,{class:`ask-ctx`},e.context),e.options.length>0&&c(`ol`,{class:`ask-opts`,"aria-label":E()},...e.options.map(e=>c(`li`,{class:`ask-opt`},c(`b`,null,e.title),e.description&&c(`small`,null,e.description)))),t&&H(e)&&c(`small`,{class:`ask-how`},H(e))),G=e=>e.replace(/[\u0000-\u0008\u000b-\u001f\u007f-\u009f\p{Cf}]/gu,`�`),K=e=>(e.select?.choices??[]).map((e,t)=>({...e,i:t})),q=(e,t,n)=>({...e.size?{choices:[...e].sort((e,t)=>e-t)}:{},...t.trim()?{text:t}:{},...n.trim()?{note:n}:{}}),J=(e,t,n)=>({dialog:e.dialog,digest:e.digest,answerId:n,...t}),Y=(e,t)=>({dialog:e.dialog,digest:e.digest,answerId:t,cancel:!0}),ie=(e,t)=>e.cancel===!0&&!(t&&e.select?.choices.every(e=>e.hereOnly)),X={digest:A,"not-allowed":M,malformed:j};function ae(e,i=!1){let{outcome:a,reason:s,by:c}=e.body;return a===`accepted`?[`ok`,i?g():n()]:a===`stale`?[`error`,c===`local`?L():c===`cancel`?F():I()]:a===`rejected`?[`error`,(Object.hasOwn(X,String(s))?X[String(s)]:N)()]:a===`busy`?[`error`,t()]:a===`unknown`||e.status===504?[`error`,r(),!0]:[`error`,s??o({status:e.status})]}var oe=e=>[`accepted`,`stale`,`busy`,`unknown`].includes(String(e.body.outcome))||e.status===504,Z=e=>e.answer?`d\n${e.answer.dialog}\n${e.answer.digest}`:`c\n${e.callId}\n${e.why??``}`;function se(e){if(e.dataset.cued)return;e.dataset.cued=`1`;let t=()=>{e.toggleAttribute(`data-more`,e.scrollHeight-e.scrollTop-e.clientHeight>4);for(let t of e.querySelectorAll(`.ask-acts`))t.dataset.cue=p()};for(let n of[`scroll`,`input`])e.addEventListener(n,t,{passive:!0});typeof ResizeObserver<`u`&&new ResizeObserver(t).observe(e),typeof MutationObserver<`u`&&new MutationObserver(t).observe(e,{childList:!0,subtree:!0,characterData:!0}),typeof requestAnimationFrame<`u`&&requestAnimationFrame(t)}var ce=0;function Q(e,t,n=location.hostname!==`127.0.0.1`,o,p,m=re,h=!1){let g=()=>typeof h==`function`?h():h,C=()=>n||g(),w,A,j,M=!1,N,F=!1,I;for(let e of[`focusin`,`pointerdown`])document.addEventListener(e,e=>A&&!A.el.contains(e.target)&&(A.lost=void 0));let L=(e,t,n,...r)=>(e.dataset.tone=t,e.replaceChildren(n,...r)),z=()=>{if(!A)return;let e=document.activeElement;e&&e!==document.body&&e!==A.lost&&(A.lost=void 0),A.controls.forEach(e=>e.disabled=!M||F||A.done),A.send&&(A.send.disabled=!M||F||A.done||!A.pick()),N&&!M&&!F&&!A.done&&!A.sending?(L(A.note,``,N),A.away=!0):A.away&&(L(A.note,``,``),A.away=!1),e&&A.el.contains(e)&&e.disabled&&(A.lost=e);let t=A.lost;t&&!t.disabled&&A.el.contains(t)&&(!document.activeElement||document.activeElement===document.body)&&(t.focus(),A.lost=void 0)};async function B(e,n){[e.sending,F,e.spell]=[!0,!0,!1],z(),L(e.note,``,a());let s=await t(`answer`,n).catch(()=>void 0),u=c(`button`,{type:`button`,class:`cmp-link`},i());u.onclick=()=>void B(e,n);let[d,f,m]=s?ae(s,n.cancel===!0):[`error`,r(),!0];[e.done,e.sending,F,e.busy]=[!s||oe(s),!1,!1,s?.body.outcome===`busy`],L(e.note,d,f,...m?[u]:[]);let h=s?.body.outcome===`accepted`?s.body.then:void 0,g=h&&l(h,{key:o?.key??``,command:e.copy,answerId:String(n.answerId??``)});g&&L(e.note,d,`${f} ${g}`),z(),e.note.scrollIntoView?.({block:`nearest`}),p&&s?.body.outcome===`accepted`&&setTimeout(()=>p(!!h&&!g),h&&!g?0:1200)}let X=(e,t,n,r,i)=>{let a=c(`button`,{type:`button`,class:`ask-opt`,role:e,"aria-checked":`false`},c(`b`,i?{"data-n":String(i)}:null,t),...n.filter(Boolean).map(e=>c(`small`,null,e)));return a.onclick=r,a};function Q(e,t){let n,r=K(t).map(e=>X(`radio`,G(e.label),[e.note&&G(e.note)],()=>(n=e.i,r.forEach((n,r)=>n.setAttribute(`aria-checked`,String(K(t)[r].i===e.i))),z()),e.i+1)),i=t.select?.copy!==void 0&&c(`button`,{type:`button`,class:`cmp-link`},ee());i&&(i.disabled=!navigator.clipboard,i.onclick=()=>void navigator.clipboard.writeText(t.select.copy).then(()=>L(e.note,`ok`,y()),()=>L(e.note,`error`,v())));let a=e=>C()&&e.hereOnly===!0||g()&&e.next===`pane`,o=r.filter((e,n)=>!a(K(t)[n])),s=r.filter(e=>!o.includes(e));s.forEach(e=>e.disabled=!0);let l=s.length>0?c(`p`,{class:`ask-why ask-reason`,id:`ask-why-${++ce}`},f()):void 0;return l&&s.forEach(e=>e.setAttribute(`aria-describedby`,l.id)),e.pick=()=>n===void 0?void 0:{choice:n},e.first=V(e.el,[{opts:r,multiple:!1,answered:()=>n!==void 0}],()=>e.send),e.controls=o,[c(`pre`,{class:`ask-title`},G(t.select.title)),c(`div`,{class:`ask-opts`,role:`radiogroup`,"aria-label":_()},...r),...l?[l]:[],c(`div`,{class:`ask-acts`},e.send,e.cancel,i)]}function le(e,t){let n=t.questions.map(()=>({picks:new Set,text:c(`textarea`,{rows:`1`,maxlength:`8192`,class:`ask-own`,placeholder:k(),"aria-label":O()}),note:c(`input`,{type:`text`,maxlength:`2048`,class:`ask-own ask-memo`,placeholder:S(),"aria-label":x()})})),r=[],i=t.questions.map((t,i)=>{let a=n[i],o=t.multiple?`checkbox`:`radio`,s=t.options.map((e,n)=>X(o,e.title,[e.description,e.preview&&b()],()=>{t.multiple||(a.picks.clear(),a.text.value=``),a.picks.has(n)?a.picks.delete(n):a.picks.add(n),s.forEach((e,t)=>e.setAttribute(`aria-checked`,String(a.picks.has(t)))),z()}));return a.text.oninput=()=>(t.multiple||(a.picks.clear(),s.forEach(e=>e.setAttribute(`aria-checked`,`false`))),z()),e.controls.push(...s,a.text,a.note),r.push({opts:s,multiple:!!t.multiple,own:a.text,note:a.note,answered:()=>a.picks.size>0||a.text.value.trim()!==``}),c(`div`,{class:`ask-one`},t.header&&c(`b`,{class:`ask-head`},t.header),c(`p`,{class:`ask-q`,...t.question.length>U?{"data-long":``}:{}},t.question),c(`div`,{class:`ask-opts`,role:t.multiple?`group`:`radiogroup`,"aria-label":E()},...s),a.text,a.note)});return e.pick=()=>n.every(e=>e.picks.size||e.text.value.trim())?{answers:n.map(e=>q(e.picks,e.text.value,e.note.value))}:void 0,e.first=V(e.el,r,()=>e.send),[...i,c(`div`,{class:`ask-acts`},e.send,e.cancel)]}function ue(e){let t=e.asks??(e.ask?[e.ask]:[]),n=t.length>1,r=e.answer,i={copy:r?.select?.copy,key:Z(e),el:c(`section`,{class:`ask`}),note:c(`p`,{class:`ask-note`,role:`status`,"aria-live":`polite`}),controls:[],pick:()=>void 0,done:!1,sending:!1};r&&((i.send=c(`button`,{type:`button`,class:`ask-send`},ne())).onclick=()=>void(i.pick()&&B(i,J(r,i.pick(),crypto.randomUUID()))));let a=e.tool===`secret_drop`;r&&!a&&ie(r,C())&&((i.cancel=c(`button`,{type:`button`,class:`ask-cancel`},s())).onclick=()=>void B(i,Y(r,crypto.randomUUID())));let l=c(`p`,{class:`ask-term`},e.why&&t.length?e.why:`${n?d():u()} ${n||!t[0]?``:H(t[0])}`.trim()),f=o&&e.tool!==`secret_drop`&&c(`button`,{type:`button`,class:`cmp-link`},m());f&&(f.onclick=o.show);let p=e.answer?.twin&&e.tool&&e.tool!==`dialog`?[c(`p`,{class:`ask-why`},T({tool:e.tool}))]:[];return i.el.append(...p,...r&&!a?r.select?Q(i,r):le(i,r):[...t.length?t.map(e=>W(e,n)):[c(`p`,{class:`ask-why`},a?C()?P():te():e.why??R())],c(`div`,{class:`ask-acts`},a?c(`p`,{class:`ask-term`},u()):l,f)],i.note),i.cancel&&i.controls.push(i.cancel),i}let $=(t,n)=>{let r=document.activeElement;A&&A!==n&&(A.focus=A.el.contains(r)?r:void 0),[w,A,j]=[t,n,n?.send?n:j],e.replaceChildren(...n?[n.el]:[]),n&&se(n.el),z(),n?.focus&&(!document.activeElement||document.activeElement===document.body)&&n.focus.focus()};return{enter(){let e=A&&!A.done?A.first?.():void 0;return!!(e&&!e.disabled&&(e.focus(),1))},cancel(){let e=A&&!A.done?A.cancel:void 0;return!!(e&&!e.disabled&&(e.click(),1))},sending:()=>F,update(e,t,n){[M,N]=[t,n],e&&(I=void clearTimeout(I)),!e&&(A?.done||A?.sending)?I??=setTimeout(()=>(I=void 0,$()),6e3):e?A&&(Z(e)===A.key||!e.answer&&(A.done||A.sending)&&e.callId===w?.callId)?((A.busy||A.sending)&&!e.answer?A.spell=!0:A.busy&&A.spell&&e.answer&&([A.done,A.busy]=[!1,!1],L(A.note,``,D())),w=e):$(e,j?.key===Z(e)&&!j.done?j:ue(e)):$(),z()}}}export{Q as t};
|
|
1
|
+
import{t as e}from"./runtime-ZX6HkxDa.js";import{a as t,i as n,n as r,r as i,t as a}from"./sending-aEpvzoz2.js";import{Ot as o,Qt as s,ft as c,t as l}from"./index-CfxTRKov.js";var u=((t={},n={})=>(n.locale??e())===`zh-TW`?`請在終端機中回答。`:`Answer it in the terminal.`),d=((t={},n={})=>(n.locale??e())===`zh-TW`?`請在終端機中回答。`:`Answer them in the terminal.`),f=((t={},n={})=>(n.locale??e())===`zh-TW`?`作用在那台機器本身畫面的選項,從這裡不能選。`:`Choices that act on the machine's own screen are not available from here.`),p=((t={},n={})=>(n.locale??e())===`zh-TW`?`下方還有 ▾`:`More below ▾`),m=((t={},n={})=>(n.locale??e())===`zh-TW`?`也可以自己輸入答案。`:`It also takes your own words.`),h=((t={},n={})=>(n.locale??e())===`zh-TW`?`可以複選。`:`It takes several choices.`),g=((t={},n={})=>(n.locale??e())===`zh-TW`?`已取消。`:`Cancelled.`),_=((t={},n={})=>(n.locale??e())===`zh-TW`?`選擇`:`Choices`),v=((t={},n={})=>(n.locale??e())===`zh-TW`?`瀏覽器拒絕存取剪貼簿。`:`The browser refused the clipboard.`),y=((t={},n={})=>(n.locale??e())===`zh-TW`?`已複製到這台裝置的剪貼簿。`:`Copied to this device's clipboard.`),ee=((t={},n={})=>(n.locale??e())===`zh-TW`?`複製指令`:`Copy command`),b=((t={},n={})=>(n.locale??e())===`zh-TW`?`這個選項有預覽;請在終端機中查看。`:`It has a preview; see it in the terminal.`),x=((t={},n={})=>(n.locale??e())===`zh-TW`?`備註`:`Note`),S=((t={},n={})=>(n.locale??e())===`zh-TW`?`備註(選填)`:`Note (optional)`),C=e=>`Opened while ${e?.tool} was running; it may not be about that call.`,w=e=>`在 ${e?.tool} 執行時開啟,不一定與該呼叫有關。`,T=((t,n={})=>(n.locale??e())===`zh-TW`?w(t):C(t)),E=((t={},n={})=>(n.locale??e())===`zh-TW`?`選項`:`Options`),D=((t={},n={})=>(n.locale??e())===`zh-TW`?`另一個答案沒有被採用;這個可以送出。`:`The other answer was not taken; this one can go.`),O=((t={},n={})=>(n.locale??e())===`zh-TW`?`你的答案`:`Your own answer`),k=((t={},n={})=>(n.locale??e())===`zh-TW`?`或自己輸入答案`:`Or type your own answer`),A=((t={},n={})=>(n.locale??e())===`zh-TW`?`問題已變更,請重新閱讀。`:`The question changed; read it again.`),j=((t={},n={})=>(n.locale??e())===`zh-TW`?`session 讀不懂這個答案。`:`The session could not read that answer.`),M=((t={},n={})=>(n.locale??e())===`zh-TW`?`這個答案不符合問題。`:`That answer does not fit the question.`),N=((t={},n={})=>(n.locale??e())===`zh-TW`?`session 拒絕了這個答案。`:`The session refused that answer.`),P=((t={},n={})=>(n.locale??e())===`zh-TW`?`安全考量,遠端不支援輸入機密。請到執行 GUI 的那台電腦的終端機中回答。`:`For security, entering a secret is not supported remotely. Answer it in the terminal on the computer the GUI runs on.`),te=((t={},n={})=>(n.locale??e())===`zh-TW`?`機密內容只能在終端機輸入,這裡不接受。請到執行 GUI 的那台電腦的終端機中回答。`:`A secret is entered in the terminal only, not here. Answer it in the terminal on the computer the GUI runs on.`),ne=((t={},n={})=>(n.locale??e())===`zh-TW`?`送出答案`:`Send answer`),re=((t={},n={})=>(n.locale??e())===`zh-TW`?`顯示終端機`:`Show terminal`),F=((t={},n={})=>(n.locale??e())===`zh-TW`?`已在終端機中關閉。`:`It was dismissed in the terminal.`),I=((t={},n={})=>(n.locale??e())===`zh-TW`?`它已不再開啟。`:`It is no longer open.`),L=((t={},n={})=>(n.locale??e())===`zh-TW`?`已在終端機中回答。`:`It was already answered in the terminal.`),R=((t={},n={})=>(n.locale??e())===`zh-TW`?`它在等待對話框。`:`It waits on a dialog.`),z={ArrowDown:1,ArrowRight:1,ArrowUp:-1,ArrowLeft:-1};function B(e,t,n,r,i){let{q:a}=n,o=r[a],s=z[e]??0,c=e===`ArrowUp`,l=c||e===`ArrowDown`,u=()=>({to:r.map((e,t)=>({q:(a+1+t)%r.length,part:`opt`})).find(e=>e.q!==a&&!i[e.q])??`send`});if(e===`Tab`){let e=r[a-1],i=n.part===`opt`?o.own||o.note:n.part===`own`&&o.note;return t?n.part===`opt`&&e?{to:{q:a-1,part:e.note?`note`:e.own?`own`:`opt`}}:void 0:i||a===r.length-1?void 0:{to:{q:a+1,part:`opt`}}}if(!t){if(n.part===`opt`){let t=n.o+s;if(s)return t>=0&&t<o.options?{to:{q:a,part:`opt`,o:t},...o.multiple?{}:{pick:t}}:{to:s>0&&o.own?{q:a,part:`own`}:n};if(e===`Enter`||e===` `&&!o.multiple)return{...u(),...o.multiple?{}:{pick:n.o}}}else if(n.part===`own`){if(e===`Enter`)return u();if(l)return{to:c?{q:a,part:`opt`,o:o.options-1}:{q:a,part:`note`}}}else if(c)return{to:{q:a,part:`own`}}}}function V(e,t,n){let r=e=>Math.max(0,e.opts.findIndex(e=>e.getAttribute(`aria-checked`)===`true`)),i=(e,t)=>e.opts.forEach((e,n)=>e.setAttribute(`tabindex`,n===t?`0`:`-1`)),a=e=>{for(let[n,r]of t.entries()){let t=r.opts.indexOf(e);if(t>=0)return{q:n,part:`opt`,o:t};if(e===r.own||e===r.note)return{q:n,part:e===r.own?`own`:`note`}}};t.forEach(e=>i(e,r(e)));let o=e=>{let n=a(e.target);n?.part===`opt`&&i(t[n.q],n.o)};e.addEventListener(`focusin`,o),e.addEventListener(`click`,o);let s=!1,c=!1;return e.addEventListener(`keydown`,i=>{i.key===` `&&(c=!0);let o=a(i.target);if(!o||i.ctrlKey||i.altKey||i.metaKey||i.isComposing)return;let l=i.target;if(o.part!==`opt`&&(i.key===`ArrowUp`?l.selectionStart!==0:i.key===`ArrowDown`&&l.selectionEnd!==l.value.length))return;let u=B(i.key,i.shiftKey,o,t.map(e=>({options:e.opts.length,multiple:e.multiple,own:!!e.own,note:!!e.note})),t.map(e=>e.answered()));if(!u||(i.preventDefault(),i.repeat&&[`Enter`,` `].includes(i.key)))return;if(s=i.key===` `,u.pick!==void 0){let e=t[o.q].opts[u.pick];e.getAttribute(`aria-checked`)!==`true`&&e.click()}let d=u.to===`send`?void 0:t[u.to.q],f=u.to===`send`?n():u.to.part===`opt`?d.opts[u.to.o??r(d)]:u.to.part===`own`?d.own:d.note;f&&!f.disabled&&(e.dispatchEvent(new CustomEvent(`ask-reveal`,{detail:f})),f.focus())}),e.addEventListener(`keyup`,e=>{e.key===` `&&((s||!c)&&e.preventDefault(),s=c=!1)}),()=>t[0]?.opts[r(t[0])]}var H=e=>e.multiple?h():e.freeform&&e.options.length?m():``,U=90,W=(e,t)=>c(`div`,{class:`ask-one`},e.header&&c(`b`,{class:`ask-head`},e.header),c(`p`,{class:`ask-q`,...e.question.length>U?{"data-long":``}:{}},e.question),e.context&&c(`div`,{class:`ask-ctx`},e.context),e.options.length>0&&c(`ol`,{class:`ask-opts`,"aria-label":E()},...e.options.map(e=>c(`li`,{class:`ask-opt`},c(`b`,null,e.title),e.description&&c(`small`,null,e.description)))),t&&H(e)&&c(`small`,{class:`ask-how`},H(e))),G=e=>e.replace(/[\u0000-\u0008\u000b-\u001f\u007f-\u009f\p{Cf}]/gu,`�`),K=e=>(e.select?.choices??[]).map((e,t)=>({...e,i:t})),q=(e,t,n)=>({...e.size?{choices:[...e].sort((e,t)=>e-t)}:{},...t.trim()?{text:t}:{},...n.trim()?{note:n}:{}}),J=(e,t,n)=>({dialog:e.dialog,digest:e.digest,answerId:n,...t}),Y=(e,t)=>({dialog:e.dialog,digest:e.digest,answerId:t,cancel:!0}),ie=(e,t)=>e.cancel===!0&&!(t&&e.select?.choices.every(e=>e.hereOnly)),X={digest:A,"not-allowed":M,malformed:j};function ae(e,i=!1){let{outcome:a,reason:s,by:c}=e.body;return a===`accepted`?[`ok`,i?g():n()]:a===`stale`?[`error`,c===`local`?L():c===`cancel`?F():I()]:a===`rejected`?[`error`,(Object.hasOwn(X,String(s))?X[String(s)]:N)()]:a===`busy`?[`error`,t()]:a===`unknown`||e.status===504?[`error`,r(),!0]:[`error`,s??o({status:e.status})]}var oe=e=>[`accepted`,`stale`,`busy`,`unknown`].includes(String(e.body.outcome))||e.status===504,Z=e=>e.answer?`d\n${e.answer.dialog}\n${e.answer.digest}`:`c\n${e.callId}\n${e.why??``}`;function se(e){if(e.dataset.cued)return;e.dataset.cued=`1`;let t=()=>{e.toggleAttribute(`data-more`,e.scrollHeight-e.scrollTop-e.clientHeight>4);for(let t of e.querySelectorAll(`.ask-acts`))t.dataset.cue=p()};for(let n of[`scroll`,`input`])e.addEventListener(n,t,{passive:!0});typeof ResizeObserver<`u`&&new ResizeObserver(t).observe(e),typeof MutationObserver<`u`&&new MutationObserver(t).observe(e,{childList:!0,subtree:!0,characterData:!0}),typeof requestAnimationFrame<`u`&&requestAnimationFrame(t)}var ce=0;function Q(e,t,n=location.hostname!==`127.0.0.1`,o,p,m=re,h=!1){let g=()=>typeof h==`function`?h():h,C=()=>n||g(),w,A,j,M=!1,N,F=!1,I;for(let e of[`focusin`,`pointerdown`])document.addEventListener(e,e=>A&&!A.el.contains(e.target)&&(A.lost=void 0));let L=(e,t,n,...r)=>(e.dataset.tone=t,e.replaceChildren(n,...r)),z=()=>{if(!A)return;let e=document.activeElement;e&&e!==document.body&&e!==A.lost&&(A.lost=void 0),A.controls.forEach(e=>e.disabled=!M||F||A.done),A.send&&(A.send.disabled=!M||F||A.done||!A.pick()),N&&!M&&!F&&!A.done&&!A.sending?(L(A.note,``,N),A.away=!0):A.away&&(L(A.note,``,``),A.away=!1),e&&A.el.contains(e)&&e.disabled&&(A.lost=e);let t=A.lost;t&&!t.disabled&&A.el.contains(t)&&(!document.activeElement||document.activeElement===document.body)&&(t.focus(),A.lost=void 0)};async function B(e,n){[e.sending,F,e.spell]=[!0,!0,!1],z(),L(e.note,``,a());let s=await t(`answer`,n).catch(()=>void 0),u=c(`button`,{type:`button`,class:`cmp-link`},i());u.onclick=()=>void B(e,n);let[d,f,m]=s?ae(s,n.cancel===!0):[`error`,r(),!0];[e.done,e.sending,F,e.busy]=[!s||oe(s),!1,!1,s?.body.outcome===`busy`],L(e.note,d,f,...m?[u]:[]);let h=s?.body.outcome===`accepted`?s.body.then:void 0,g=h&&l(h,{key:o?.key??``,command:e.copy,answerId:String(n.answerId??``)});g&&L(e.note,d,`${f} ${g}`),z(),e.note.scrollIntoView?.({block:`nearest`}),p&&s?.body.outcome===`accepted`&&setTimeout(()=>p(!!h&&!g),h&&!g?0:1200)}let X=(e,t,n,r,i)=>{let a=c(`button`,{type:`button`,class:`ask-opt`,role:e,"aria-checked":`false`},c(`b`,i?{"data-n":String(i)}:null,t),...n.filter(Boolean).map(e=>c(`small`,null,e)));return a.onclick=r,a};function Q(e,t){let n,r=K(t).map(e=>X(`radio`,G(e.label),[e.note&&G(e.note)],()=>(n=e.i,r.forEach((n,r)=>n.setAttribute(`aria-checked`,String(K(t)[r].i===e.i))),z()),e.i+1)),i=t.select?.copy!==void 0&&c(`button`,{type:`button`,class:`cmp-link`},ee());i&&(i.disabled=!navigator.clipboard,i.onclick=()=>void navigator.clipboard.writeText(t.select.copy).then(()=>L(e.note,`ok`,y()),()=>L(e.note,`error`,v())));let a=e=>C()&&e.hereOnly===!0||g()&&e.next===`pane`,o=r.filter((e,n)=>!a(K(t)[n])),s=r.filter(e=>!o.includes(e));s.forEach(e=>e.disabled=!0);let l=s.length>0?c(`p`,{class:`ask-why ask-reason`,id:`ask-why-${++ce}`},f()):void 0;return l&&s.forEach(e=>e.setAttribute(`aria-describedby`,l.id)),e.pick=()=>n===void 0?void 0:{choice:n},e.first=V(e.el,[{opts:r,multiple:!1,answered:()=>n!==void 0}],()=>e.send),e.controls=o,[c(`pre`,{class:`ask-title`},G(t.select.title)),c(`div`,{class:`ask-opts`,role:`radiogroup`,"aria-label":_()},...r),...l?[l]:[],c(`div`,{class:`ask-acts`},e.send,e.cancel,i)]}function le(e,t){let n=t.questions.map(()=>({picks:new Set,text:c(`textarea`,{rows:`1`,maxlength:`8192`,class:`ask-own`,placeholder:k(),"aria-label":O()}),note:c(`input`,{type:`text`,maxlength:`2048`,class:`ask-own ask-memo`,placeholder:S(),"aria-label":x()})})),r=[],i=t.questions.map((t,i)=>{let a=n[i],o=t.multiple?`checkbox`:`radio`,s=t.options.map((e,n)=>X(o,e.title,[e.description,e.preview&&b()],()=>{t.multiple||(a.picks.clear(),a.text.value=``),a.picks.has(n)?a.picks.delete(n):a.picks.add(n),s.forEach((e,t)=>e.setAttribute(`aria-checked`,String(a.picks.has(t)))),z()}));return a.text.oninput=()=>(t.multiple||(a.picks.clear(),s.forEach(e=>e.setAttribute(`aria-checked`,`false`))),z()),e.controls.push(...s,a.text,a.note),r.push({opts:s,multiple:!!t.multiple,own:a.text,note:a.note,answered:()=>a.picks.size>0||a.text.value.trim()!==``}),c(`div`,{class:`ask-one`},t.header&&c(`b`,{class:`ask-head`},t.header),c(`p`,{class:`ask-q`,...t.question.length>U?{"data-long":``}:{}},t.question),c(`div`,{class:`ask-opts`,role:t.multiple?`group`:`radiogroup`,"aria-label":E()},...s),a.text,a.note)});return e.pick=()=>n.every(e=>e.picks.size||e.text.value.trim())?{answers:n.map(e=>q(e.picks,e.text.value,e.note.value))}:void 0,e.first=V(e.el,r,()=>e.send),[...i,c(`div`,{class:`ask-acts`},e.send,e.cancel)]}function ue(e){let t=e.asks??(e.ask?[e.ask]:[]),n=t.length>1,r=e.answer,i={copy:r?.select?.copy,key:Z(e),el:c(`section`,{class:`ask`}),note:c(`p`,{class:`ask-note`,role:`status`,"aria-live":`polite`}),controls:[],pick:()=>void 0,done:!1,sending:!1};r&&((i.send=c(`button`,{type:`button`,class:`ask-send`},ne())).onclick=()=>void(i.pick()&&B(i,J(r,i.pick(),crypto.randomUUID()))));let a=e.tool===`secret_drop`;r&&!a&&ie(r,C())&&((i.cancel=c(`button`,{type:`button`,class:`ask-cancel`},s())).onclick=()=>void B(i,Y(r,crypto.randomUUID())));let l=c(`p`,{class:`ask-term`},e.why&&t.length?e.why:`${n?d():u()} ${n||!t[0]?``:H(t[0])}`.trim()),f=o&&e.tool!==`secret_drop`&&c(`button`,{type:`button`,class:`cmp-link`},m());f&&(f.onclick=o.show);let p=e.answer?.twin&&e.tool&&e.tool!==`dialog`?[c(`p`,{class:`ask-why`},T({tool:e.tool}))]:[];return i.el.append(...p,...r&&!a?r.select?Q(i,r):le(i,r):[...t.length?t.map(e=>W(e,n)):[c(`p`,{class:`ask-why`},a?C()?P():te():e.why??R())],c(`div`,{class:`ask-acts`},a?c(`p`,{class:`ask-term`},u()):l,f)],i.note),i.cancel&&i.controls.push(i.cancel),i}let $=(t,n)=>{let r=document.activeElement;A&&A!==n&&(A.focus=A.el.contains(r)?r:void 0),[w,A,j]=[t,n,n?.send?n:j],e.replaceChildren(...n?[n.el]:[]),n&&se(n.el),z(),n?.focus&&(!document.activeElement||document.activeElement===document.body)&&n.focus.focus()};return{enter(){let e=A&&!A.done?A.first?.():void 0;return!!(e&&!e.disabled&&(e.focus(),1))},cancel(){let e=A&&!A.done?A.cancel:void 0;return!!(e&&!e.disabled&&(e.click(),1))},sending:()=>F,update(e,t,n){[M,N]=[t,n],e&&(I=void clearTimeout(I)),!e&&(A?.done||A?.sending)?I??=setTimeout(()=>(I=void 0,$()),6e3):e?A&&(Z(e)===A.key||!e.answer&&(A.done||A.sending)&&e.callId===w?.callId)?((A.busy||A.sending)&&!e.answer?A.spell=!0:A.busy&&A.spell&&e.answer&&([A.done,A.busy]=[!1,!1],L(A.note,``,D())),w=e):$(e,j?.key===Z(e)&&!j.done?j:ue(e)):$(),z()}}}export{Q as t};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{t as e}from"./rolldown-runtime-DK3Fl9T5.js";import{m as t}from"./towermodel-BpgH7epr.js";import{t as n}from"./runtime-ZX6HkxDa.js";import{
|
|
1
|
+
import{t as e}from"./rolldown-runtime-DK3Fl9T5.js";import{m as t}from"./towermodel-BpgH7epr.js";import{t as n}from"./runtime-ZX6HkxDa.js";import{K as r,Ot as i}from"./index-CfxTRKov.js";var a=((e={},t={})=>(t.locale??n())===`zh-TW`?`沒有符合這個號碼的請求。`:`No request has that number.`),o=((e={},t={})=>(t.locale??n())===`zh-TW`?`這個請求已經不在了。`:`That request is gone.`),s=((e={},t={})=>(t.locale??n())===`zh-TW`?`連續輸入三次錯誤號碼,所以所有等待中的請求都已拒絕。請按「新的配對碼」重新配對。`:`Three wrong numbers in a row, so every waiting request was denied. Press New code and pair again.`),c=((e={},t={})=>(t.locale??n())===`zh-TW`?`這個請求已經變了,請重新看過。`:`That request changed. Look at it again.`),l=((e={},t={})=>(t.locale??n())===`zh-TW`?`這個請求已經不在了,或已逾時。`:`That request is gone or has timed out.`),u=((e={},t={})=>(t.locale??n())===`zh-TW`?`這個團隊沒有在這台裝置上執行。`:`That team is not running on this device.`),d=((e={},t={})=>(t.locale??n())===`zh-TW`?`已在該裝置上取消。`:`It was cancelled at the device.`),f=((e={},t={})=>(t.locale??n())===`zh-TW`?`你已從這裡回答。`:`You answered it from here.`),p=((e={},t={})=>(t.locale??n())===`zh-TW`?`已在該裝置上回答。`:`Answered at the device itself.`),m=((e={},t={})=>(t.locale??n())===`zh-TW`?`已由團隊的另一個控制端回答。`:`Answered by another controller of this team.`),h=e=>`The answer was not sent: ${e?.reason}`,g=e=>`答案沒有送出:${e?.reason}`,_=((e,t={})=>(t.locale??n())===`zh-TW`?g(e):h(e)),v=((e={},t={})=>(t.locale??n())===`zh-TW`?`問題在有人回答前就結束了。`:`It ended before anyone answered it.`),y=((e={},t={})=>(t.locale??n())===`zh-TW`?`已送出你的答案;對方裝置還沒關閉這個問題。`:`Your answer was sent; the device has not closed the question yet.`),b=((e={},t={})=>(t.locale??n())===`zh-TW`?`你已不再負責回答這台裝置的問題;問題在那邊仍未結束。`:`You no longer answer this device's questions; it is still open there.`);function x(e){switch(e){case`sent`:return y();case`done-here`:return f();case`done-other`:return m();case`done-local`:return p();case`cancelled`:return d();case`expired`:return v();case`withdrawn`:return b()}}var S=e=>typeof e==`object`&&!!e&&!Array.isArray(e),C=e=>typeof e==`string`,w=e=>Array.isArray(e)&&e.every(e=>S(e)&&C(e.title));function T(e){let{dialog:t,dialogId:n,digest:r}=e.data;if(!C(t)||!C(n)||!C(r))return;let i;try{i=JSON.parse(t)}catch{return}if(!S(i))return;let{select:a,questions:o,cancel:s}=i,c={dialog:n,digest:r,...s===!0?{cancel:!0}:{}};if(S(a)&&C(a.title)&&Array.isArray(a.choices)&&a.choices.every(e=>S(e)&&C(e.label)))return{callId:n,tool:`dialog`,answer:{...c,select:a}};if(Array.isArray(o)&&o.length>0&&o.every(e=>S(e)&&C(e.question)&&w(e.options)))return{callId:n,tool:`dialog`,answer:{...c,questions:o}}}var E=e=>e.cancel===!0?{cancel:!0}:e.choice===void 0?{answers:e.answers}:{choice:e.choice},D=e({confirmActions:()=>M,confirmWhy:()=>N,forwardedAnswer:()=>P,joined:()=>k,lanActions:()=>I,lanReading:()=>L,outcome:()=>O,proposalActions:()=>F,taken:()=>j,waitActions:()=>A}),O=e=>{let t=e.body.outcome;return t===void 0?e.status===504?`unknown`:e.ok&&(e.body.accepted===!0||Array.isArray(e.body.entries))?`accepted`:`refused`:t===`accepted`?`accepted`:t===`unknown`?`unknown`:`refused`},k=e=>e.replace(/^([A-Z])(?=[a-z])/,e=>e.toLowerCase()),A=(e,n)=>({tell:t=>n(`input`,{text:t,as:`send`,answers:e.id}),press:(n,i)=>r(`${t(e.ws)}/memory`,{op:`press`,id:e.id,act:n,...i}),read:()=>r(`${t(e.ws)}/memory`,{op:`read`}),goto:{view:`session`,ws:e.ws,key:e.tower}}),j=e=>e.ok&&e.body.outcome===void 0?{...e,body:{...e.body,outcome:`accepted`}}:e,M=e=>{let t=t=>r(`link/confirm-answer`,{dialogId:e.dialogId,digest:e.digest,allow:t}).then(j);return{allow:()=>t(!0),deny:()=>t(!1)}},N=e=>{let t=String(e.body.reason??e.body.error??``);return[[/^That request is gone/,l],[/^That team is not running/,u],[/^That request changed/,c]].find(([e])=>e.test(t))?.[1]()??(t||i({status:e.status}))},P=e=>async(t,n)=>{let a=await r(`link/dialog-answer`,{device:e.device,dialogId:e.dialogId,digest:e.digest,answer:E(n)});return a.ok?j(a):{ok:!1,status:a.status,body:{reason:_({reason:a.body.reason??i({status:a.status})})}}},F=e=>({confirm:()=>r(`${t(e.ws)}/memory`,{op:`confirm`,proposal:e.id,rev:e.rev()}),reject:()=>r(`${t(e.ws)}/memory`,{op:`reject`,proposal:e.id})}),I=e=>({approve:t=>e(`lan/approve`,{number:t}).then(j),deny:t=>e(`lan/approve`,{deny:t}).then(e=>e.ok&&e.body.denied===0?{...e,ok:!1,body:{error:`gone`,reason:o()}}:j(e)),denyAll:()=>e(`lan/approve`,{deny:`all`}).then(j)});function L(e){let t=!e.ok&&e.body.error===`no_match`&&Number(e.body.denied)>0;return{answer:e.ok||t?``:e.body.error===`no_match`?a():String(e.body.reason??i({status:e.status})),verdict:t?s():``}}export{k as a,O as c,x as d,T as f,P as i,F as l,M as n,I as o,N as r,L as s,D as t,A as u};
|