pi2web 0.2.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/ANDROID_APP_FEATURES.md +256 -0
- package/LICENSE +21 -0
- package/README.md +194 -0
- package/VOICE_SERVER_SETUP.md +393 -0
- package/dist/agents.js +123 -0
- package/dist/auth.js +31 -0
- package/dist/mail-notifier.js +132 -0
- package/dist/main.js +90 -0
- package/dist/metadata-store.js +139 -0
- package/dist/sdk-backend.js +85 -0
- package/dist/server.js +419 -0
- package/dist/terminals.js +70 -0
- package/dist/voice.js +322 -0
- package/dist/workspaces.js +60 -0
- package/package.json +79 -0
- package/packages/edge-tts-server/README.md +68 -0
- package/packages/edge-tts-server/pyproject.toml +19 -0
- package/packages/edge-tts-server/src/remote_pi_edge_tts/__init__.py +3 -0
- package/packages/edge-tts-server/src/remote_pi_edge_tts/__main__.py +77 -0
- package/packages/protocol/openapi.yaml +38 -0
- package/packages/protocol/websocket.schema.json +17 -0
- package/web/app.js +544 -0
- package/web/icon.svg +19 -0
- package/web/index.html +84 -0
- package/web/styles.css +29 -0
package/web/icon.svg
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" role="img" aria-label="Remote Pi">
|
|
2
|
+
<defs>
|
|
3
|
+
<linearGradient id="bg" x1="10" y1="7" x2="54" y2="59" gradientUnits="userSpaceOnUse">
|
|
4
|
+
<stop stop-color="#8fbcff"/>
|
|
5
|
+
<stop offset="1" stop-color="#5e81ac"/>
|
|
6
|
+
</linearGradient>
|
|
7
|
+
<linearGradient id="mark" x1="18" y1="17" x2="47" y2="47" gradientUnits="userSpaceOnUse">
|
|
8
|
+
<stop stop-color="#ffffff"/>
|
|
9
|
+
<stop offset="1" stop-color="#b8f3ff"/>
|
|
10
|
+
</linearGradient>
|
|
11
|
+
</defs>
|
|
12
|
+
<rect x="3" y="3" width="58" height="58" rx="15" fill="url(#bg)"/>
|
|
13
|
+
<rect x="4" y="4" width="56" height="56" rx="14" fill="none" stroke="#d8f7ff" stroke-opacity=".72" stroke-width="2"/>
|
|
14
|
+
<path d="M23 17.5a13.4 13.4 0 0 1 18 0M27.5 22a7 7 0 0 1 9 0" fill="none" stroke="#c8ff9b" stroke-width="3" stroke-linecap="round"/>
|
|
15
|
+
<circle cx="32" cy="26" r="2.3" fill="#c8ff9b"/>
|
|
16
|
+
<path d="M17 31c8-3.6 22-3.6 30 0M25 29v17M40 29v10.5c0 4.4 2.1 6.5 6 6.5" fill="none" stroke="url(#mark)" stroke-width="5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
17
|
+
<circle cx="17" cy="31" r="3" fill="#b8f3ff"/>
|
|
18
|
+
<circle cx="47" cy="31" r="3" fill="#b8f3ff"/>
|
|
19
|
+
</svg>
|
package/web/index.html
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="zh-CN">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
6
|
+
<meta name="color-scheme" content="dark">
|
|
7
|
+
<meta name="theme-color" content="#2b303b">
|
|
8
|
+
<title>Remote Pi</title>
|
|
9
|
+
<link rel="icon" href="/icon.svg" type="image/svg+xml">
|
|
10
|
+
<link rel="stylesheet" href="/styles.css">
|
|
11
|
+
<link rel="stylesheet" href="/vendor/xterm.css">
|
|
12
|
+
</head>
|
|
13
|
+
<body>
|
|
14
|
+
<header>
|
|
15
|
+
<div class="brand"><img src="/icon.svg" alt="" width="32" height="32"><h1>Remote Pi</h1></div>
|
|
16
|
+
<label class="api-field">服务地址 <input id="api" placeholder="http://127.0.0.1:11318"></label>
|
|
17
|
+
<button id="openConfig" title="连接、通知与语音设置">配置</button>
|
|
18
|
+
<span id="status" class="muted">未配对</span>
|
|
19
|
+
<span id="serverInfo" class="muted"></span>
|
|
20
|
+
</header>
|
|
21
|
+
<main>
|
|
22
|
+
<aside>
|
|
23
|
+
<section id="workspaceSection">
|
|
24
|
+
<div class="section-title"><div class="section-heading"><button id="workspaceBack" class="mobile-only" title="返回主页" aria-label="返回主页">←</button><h2 id="workspaceHeading">Workspace</h2></div><span class="workspace-home-actions"><button id="refreshWs" title="刷新">↻</button><button id="addWs">添加</button></span></div>
|
|
25
|
+
<select id="workspaces" size="3" aria-label="Workspace"></select>
|
|
26
|
+
<div id="mobileWorkspaces" class="mobile-only" aria-label="Workspaces"></div>
|
|
27
|
+
<div id="workspaceBrowser">
|
|
28
|
+
<div class="pathbar"><button id="treeUp" title="上级目录">↑</button><button id="treeRoot" title="根目录">⌂</button><button id="mentionCurrent" title="引用当前目录">@</button><button id="terminalCurrent" title="在当前目录启动 Terminal" aria-label="在当前目录启动 Terminal">>_</button><span id="treePath">.</span></div>
|
|
29
|
+
<div id="tree"></div>
|
|
30
|
+
<div id="filePanel" hidden><div class="filebar"><div class="file-title"><button id="fileBack" class="mobile-only" title="返回目录" aria-label="返回目录">←</button><b id="fileName"></b></div><span><button id="filePrev">上一页</button><button id="fileNext">下一页</button></span></div><pre id="file"></pre><small id="filePage" class="muted"></small></div>
|
|
31
|
+
</div>
|
|
32
|
+
</section>
|
|
33
|
+
<section id="agentsSection">
|
|
34
|
+
<div class="section-title"><h2>Agents & Terminals</h2><span class="agent-create-actions"><button id="newAgent" title="新建 Agent" aria-label="新建 Agent">+A</button><button id="newTerminal" title="新建 Terminal" aria-label="新建 Terminal">>_</button></span></div>
|
|
35
|
+
<label class="cwd-field">工作路径<input id="agentCwd" value="." title="相对于 Workspace"></label>
|
|
36
|
+
<div id="agents"></div>
|
|
37
|
+
<div id="agentListControls" class="list-controls"><label>每次加载 <select id="agentPageSize" aria-label="每次加载的 Session 数量"><option value="10" selected>10</option><option value="25">25</option><option value="50">50</option></select> 条</label><span id="agentListCount" class="muted"></span><button id="loadMoreAgents" type="button">加载更多</button></div>
|
|
38
|
+
</section>
|
|
39
|
+
</aside>
|
|
40
|
+
<article>
|
|
41
|
+
<div id="agentToolbar" class="toolbar">
|
|
42
|
+
<button id="agentBack" class="mobile-only" title="返回主页" aria-label="返回主页">←</button>
|
|
43
|
+
<div class="title-wrap"><div class="agent-heading"><strong id="agentTitle">请选择 Agent</strong><span id="agentStateBadge" class="state-badge state-none">未选择</span></div><small id="agentStatus" class="muted"></small><div id="contextUsage" class="context-usage" hidden><div class="context-track"><i id="contextBar"></i></div><small id="contextText"></small></div></div>
|
|
44
|
+
<button id="mobileAgentActions" class="mobile-only" title="更多操作" aria-label="更多操作">⋮</button>
|
|
45
|
+
<button id="sessionName" class="agent-action" title="修改 Session 名称">命名</button>
|
|
46
|
+
<button id="undo" class="agent-action" title="在 Session Tree 中回退输入或 Agent 输出">Undo</button>
|
|
47
|
+
<button id="sessionTree" class="agent-action">Session</button>
|
|
48
|
+
<button id="controls" class="agent-action">模型</button>
|
|
49
|
+
<button id="compact" class="agent-action">Compact</button>
|
|
50
|
+
<button id="stop" class="agent-action">停止</button>
|
|
51
|
+
<button id="abort" class="agent-action danger-action">Abort</button>
|
|
52
|
+
</div>
|
|
53
|
+
<div id="terminalToolbar" class="toolbar" hidden>
|
|
54
|
+
<button id="terminalBack" class="mobile-only" title="返回主页" aria-label="返回主页">←</button>
|
|
55
|
+
<div class="title-wrap"><div class="agent-heading"><strong id="terminalTitle">Terminal</strong><span id="terminalStateBadge" class="state-badge state-idle">running</span></div><small id="terminalStatus" class="muted"></small></div>
|
|
56
|
+
<button id="terminalClear">清屏</button><button id="terminalClose" class="danger-action">关闭 Terminal</button>
|
|
57
|
+
</div>
|
|
58
|
+
<div id="terminalView" hidden><div id="terminal"></div></div>
|
|
59
|
+
<div id="widgets"></div>
|
|
60
|
+
<div id="messages" aria-live="polite"><div class="empty">选择或创建 Agent 开始对话</div></div>
|
|
61
|
+
<form id="prompt">
|
|
62
|
+
<div id="mentionPicker" hidden><div class="picker-head"><button type="button" id="mentionUp">↑</button><b id="mentionPath">.</b><button type="button" id="mentionClose">×</button></div><div id="mentionItems"></div></div>
|
|
63
|
+
<div class="composer-row">
|
|
64
|
+
<select id="sendMode" title="发送方式"><option value="prompt">Prompt</option><option value="steer">Steer</option><option value="follow-up">Follow-up</option></select>
|
|
65
|
+
<textarea id="input" placeholder="输入 @ 引用文件;Ctrl/⌘+Enter 发送"></textarea>
|
|
66
|
+
<button id="voiceInput" type="button" title="开始语音输入" hidden>🎙</button>
|
|
67
|
+
<button type="submit">发送</button>
|
|
68
|
+
</div>
|
|
69
|
+
</form>
|
|
70
|
+
</article>
|
|
71
|
+
</main>
|
|
72
|
+
<div id="contextMenu" class="context-menu" hidden><button id="menuStartAgent">启动 Agent</button><button id="menuOpenTerminal">在 Terminal 中打开</button><button id="menuSetCwd">设为 Agent 工作路径</button><button id="menuMention">在输入框中引用</button></div>
|
|
73
|
+
<dialog id="configDialog"><form method="dialog" id="configForm"><h2>Remote Pi 配置</h2><section class="config-section"><h3>连接</h3><button id="connect" type="button">输入配对码</button><small id="configConnectionStatus" class="muted"></small></section><section class="config-section"><h3>浏览器通知与语音</h3><div class="config-actions"><button id="notifications" type="button" title="启用所有 Agent 的完成通知">启用通知</button><button id="voicePlayback" type="button" title="启用 Agent 语音摘要播放" hidden>启用语音</button></div><small id="browserNotificationStatus" class="muted"></small></section><section class="config-section"><h3>邮件通知</h3><p id="mailNotificationAvailability" class="muted"></p><label class="toggle-row"><input id="mailNotificationEnabled" type="checkbox">启动邮件通知</label><label>邮件通知聚合时间(秒)<input id="mailAggregationDelay" type="number" min="0" max="86400" step="1" value="0"><small class="muted">首个任务完成后等待这段时间,期间完成的其他任务合并到同一封邮件;0 表示立即发送。</small></label><label class="toggle-row"><input id="mailIncludeResponse" type="checkbox" checked>包含 Agent 回复内容</label><label class="toggle-row"><input id="mailIncludeSessionDetails" type="checkbox" checked>包含 Session 名称和路径</label><small class="muted">如果回复内容和 Session 信息都不包含,邮件只会说明有任务完成。</small></section><div class="dialog-actions"><button id="configClose" type="button">关闭</button><button id="configSave" type="button">保存邮件设置</button></div></form></dialog>
|
|
74
|
+
<dialog id="pairDialog"><form method="dialog" id="pairForm"><h2>连接 Remote Pi</h2><p class="muted">连接成功后可选择是否将配对码保存到浏览器本地存储。请仅在可信设备上保存。</p><label>服务地址<input id="pairBase" required></label><label>配对码<input id="pairToken" type="password" autocomplete="off" required autofocus></label><div class="dialog-actions"><button id="pairCancel" type="button">取消</button><button id="pairSubmit" type="submit" value="default">连接</button></div></form></dialog>
|
|
75
|
+
<div id="agentContextMenu" class="context-menu" hidden><button id="menuArchiveAgent">Archive</button><button id="menuCloseTerminal" hidden>关闭 Terminal</button></div>
|
|
76
|
+
<dialog id="modal"><form method="dialog"><h2 id="modalTitle"></h2><div id="modalBody"></div><div class="dialog-actions"><button id="modalCancel" type="button">取消</button><button id="modalOk" type="submit" value="default">确定</button></div></form></dialog>
|
|
77
|
+
<div id="toast" hidden></div>
|
|
78
|
+
<script src="/vendor/xterm.js"></script>
|
|
79
|
+
<script src="/vendor/addon-fit.js"></script>
|
|
80
|
+
<script src="/vendor/marked.js"></script>
|
|
81
|
+
<script src="/vendor/dompurify.js"></script>
|
|
82
|
+
<script src="/app.js"></script>
|
|
83
|
+
</body>
|
|
84
|
+
</html>
|
package/web/styles.css
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
*{box-sizing:border-box}:root{--bg:#20232b;--panel:#2b303b;--input:#303642;--line:#454b58;--text:#d8dee9;--muted:#9da7b9;--blue:#88c0d0;--green:#a3be8c;--yellow:#ebcb8b;--red:#bf616a}body{margin:0;font:14px system-ui,sans-serif;color:var(--text);background:var(--bg)}header{height:58px;padding:10px 18px;display:flex;align-items:center;gap:12px;background:var(--panel);border-bottom:1px solid var(--line)}.brand{display:flex;align-items:center;gap:9px;margin-right:20px;white-space:nowrap}.brand img{display:block;width:32px;height:32px;border-radius:9px;box-shadow:0 3px 10px #0004}h1{font-size:20px;margin:0}h2{font-size:15px;margin:8px 0}input,textarea,select,button{font:inherit;color:inherit;background:var(--input);border:1px solid #586174;border-radius:5px;padding:7px}button{cursor:pointer}button:hover:not(:disabled){background:#424b5d}button:disabled{opacity:.45;cursor:not-allowed}.muted{color:var(--muted)}#status.ok{color:var(--green)}#status.bad{color:var(--red)}#serverInfo{margin-left:auto}main{height:calc(100vh - 58px);min-height:0;overflow:hidden;display:grid;grid-template-columns:340px minmax(0,1fr)}aside{min-height:0;overflow:auto;padding:12px;border-right:1px solid var(--line)}section+section{margin-top:18px}.section-title,.toolbar,.filebar,.picker-head,.composer-row{display:flex;gap:8px;align-items:center}.section-title{justify-content:space-between}.section-title span{display:flex;gap:5px}.section-title button{padding:4px 8px}#agentsSection .section-title{flex-wrap:wrap}.agent-create-actions{margin-left:auto;justify-content:flex-end;flex-wrap:wrap}#workspaces{width:100%;min-height:68px}.pathbar{display:flex;align-items:center;gap:5px;margin-top:9px}.pathbar button{padding:3px 8px}.pathbar span{min-width:0;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:#b8c2d5}#tree{margin-top:5px;max-height:28vh;overflow:auto}.entry{padding:6px;cursor:pointer;border-radius:4px}.entry:hover{background:#353c4a}.dir{color:var(--yellow)}.file-entry{color:var(--blue)}#filePanel{margin-top:8px}.filebar{justify-content:space-between}.filebar span{display:flex;gap:4px}.filebar button{font-size:11px;padding:3px 6px}#file{white-space:pre-wrap;word-break:break-word;max-height:28vh;overflow:auto;background:#292d36;padding:8px;border-radius:4px;margin:5px 0}.cwd-field{display:block;margin:6px 0;color:#aeb8ca}.cwd-field input{display:block;width:100%;margin-top:4px}.list-controls{display:flex;align-items:center;gap:7px;margin-top:8px}.list-controls label{display:flex;align-items:center;gap:5px;color:var(--muted);white-space:nowrap}.list-controls select{padding:4px}.list-controls #agentListCount{flex:1;font-size:11px}.list-controls button{padding:5px 8px}.agent{padding:9px;margin:6px 0;background:var(--input);border:1px solid transparent;border-radius:7px;cursor:pointer;transition:border-color .15s,background .15s}.agent:hover{background:#383f4e}.agent.selected{border-color:var(--blue);box-shadow:0 0 0 1px #88c0d044}.agent.streaming{border-left:4px solid var(--yellow)}.agent.idle{border-left:4px solid var(--green)}.agent.unloaded{border-left:4px solid var(--muted)}.agent.stopped,.agent.error,.agent.exited{border-left:4px solid var(--red)}.agent.running{border-left:4px solid var(--blue)}.agent-top{display:flex;align-items:center;gap:7px}.agent-top b{flex:1}.agent b,.agent small{display:block;overflow:hidden;text-overflow:ellipsis}.agent small{color:var(--muted);margin-top:3px}.agent-context{display:flex;align-items:center;gap:7px;margin-top:7px;font-size:11px;color:var(--muted)}.mini-track{height:5px;flex:1;overflow:hidden;background:#20242d;border-radius:9px}.mini-track i,.context-track i{display:block;height:100%;width:0;background:var(--green);border-radius:inherit;transition:width .25s}.usage-warning i{background:var(--yellow)}.usage-danger i{background:var(--red)}article{height:100%;min-width:0;min-height:0;overflow:hidden;display:flex;flex-direction:column}.toolbar{flex:0 0 auto;padding:10px;border-bottom:1px solid var(--line);flex-wrap:wrap}.title-wrap{flex:1;min-width:220px}.agent-heading{display:flex;align-items:center;gap:9px}.agent-heading strong{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.title-wrap>small{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.state-badge{flex:0 0 auto;padding:3px 8px;border-radius:999px;font-size:11px;font-weight:700;text-transform:uppercase;background:#444;color:#ddd}.state-streaming{color:#201b0d;background:var(--yellow);box-shadow:0 0 0 3px #ebcb8b22}.state-idle,.state-running{color:#15200f;background:var(--green)}.state-unloaded{color:#fff;background:#667085}.state-error,.state-stopped,.state-exited{color:#fff;background:var(--red)}.state-waiting_for_user{color:#161c24;background:var(--blue)}.context-usage{display:flex;align-items:center;gap:8px;margin-top:5px}.context-track{width:min(260px,65%);height:7px;overflow:hidden;background:#171a20;border-radius:9px}.context-usage small{color:var(--muted);white-space:nowrap}.toolbar button{padding:5px 8px}#widgets{flex:0 0 auto;max-height:25%;overflow:auto;padding:0 18px}.widget{margin-top:8px;padding:8px;background:#343a47;border-left:3px solid var(--yellow);white-space:pre-wrap}#messages{flex:1 1 0;min-height:0;overflow-y:auto;overscroll-behavior:contain;padding:18px;scrollbar-gutter:stable}.message-history-controls{display:flex;justify-content:center;gap:8px;margin:0 auto 12px}.message-history-controls button{padding:6px 12px}.empty{text-align:center;color:var(--muted);margin-top:18vh}.msg{margin:8px 0;border-radius:7px;word-break:break-word;background:var(--panel);border-left:3px solid var(--blue);overflow:hidden}.msg.user{background:#3b4252;border-left-color:var(--green)}.msg.thinking{border-left-color:#b48ead}.msg.tool{border-left-color:var(--yellow)}.msg.system{border-left-color:#667085;color:#b5bdca}.msg.error{border-left-color:var(--red)}.msg summary{cursor:pointer;padding:10px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;list-style:none}.msg summary::-webkit-details-marker{display:none}.msg summary:before{content:'▸';margin-right:7px;color:var(--muted)}.msg[open] summary:before{content:'▾'}.msg-content{padding:0 12px 12px;white-space:pre-wrap}.msg pre{white-space:pre-wrap;margin:5px 0;font:12px ui-monospace,monospace}.event-time{float:right;font-size:11px;color:var(--muted)}#prompt{position:relative;z-index:5;flex:0 0 auto;padding:12px;border-top:1px solid var(--line);background:var(--bg);box-shadow:0 -4px 12px #0003}.composer-row textarea{resize:vertical;min-height:62px;max-height:30vh;flex:1}.composer-row #sendMode{width:100px}.composer-row>button{align-self:stretch}#voiceInput.recording{color:#fff;background:var(--red);border-color:#d9828a}#mentionPicker{position:absolute;left:115px;right:80px;bottom:88px;max-height:330px;overflow:auto;background:#252a33;border:1px solid #667085;border-radius:7px;box-shadow:0 8px 24px #0008;z-index:15}.picker-head{position:sticky;top:0;padding:7px;background:#252a33;border-bottom:1px solid var(--line)}.picker-head b{flex:1;overflow:hidden;text-overflow:ellipsis}.picker-item{padding:8px;cursor:pointer}.picker-item:hover,.picker-item.selected{background:#424b5d}.picker-item.selected{box-shadow:inset 3px 0 var(--blue)}.picker-empty{padding:12px;text-align:center}.context-menu{position:fixed;z-index:20;min-width:190px;padding:5px;background:#252a33;border:1px solid #667085;border-radius:6px;box-shadow:0 8px 24px #0008}.context-menu button{display:block;width:100%;border:0;text-align:left;background:transparent}dialog{color:var(--text);background:var(--panel);border:1px solid #667085;border-radius:8px;min-width:min(460px,90vw);max-width:min(700px,94vw);max-height:85vh}dialog::backdrop{background:#0009}dialog label{display:block;margin:12px 0}dialog label input,dialog label select,dialog textarea{display:block;width:100%;margin-top:5px}.dialog-actions{display:flex;justify-content:flex-end;gap:8px;margin-top:18px}.modal-list{max-height:55vh;overflow:auto}.choice{display:block;width:100%;text-align:left;margin:5px 0;padding:9px}.choice.selected{background:#3b4658;border-color:var(--blue);box-shadow:0 0 0 1px #88c0d055}.choice.selected:before{content:'✓ ';color:var(--blue);font-weight:700}.choice small{display:block;color:var(--muted)}#toast{position:fixed;right:18px;bottom:18px;z-index:50;padding:11px 16px;background:#3b4252;border:1px solid #67738a;border-radius:6px;box-shadow:0 5px 20px #0008}.status-row{padding:7px 18px;color:var(--muted);font-size:12px}@media(max-width:850px){main{grid-template-columns:260px 1fr}.api-field{display:none}.toolbar button{font-size:12px}#serverInfo{display:none}}@media(max-width:620px){body{height:100dvh;overflow:hidden;display:flex;flex-direction:column}header{height:auto;min-height:58px;flex:0 0 auto;flex-wrap:wrap}main{height:auto;min-height:0;flex:1 1 auto;display:flex;flex-direction:column;overflow:hidden}aside{flex:0 0 36%;min-height:0;border-right:0;border-bottom:1px solid var(--line)}article{flex:1 1 auto;height:auto;min-height:0}#mentionPicker{left:10px;right:10px}.toolbar{max-height:100px;overflow:auto}}
|
|
2
|
+
.mobile-only{display:none}.section-heading,.file-title{display:flex;align-items:center;gap:8px}.workspace-card{display:block;width:100%;margin:6px 0;padding:12px;text-align:left;background:var(--input);border:1px solid var(--line);border-radius:8px}.workspace-card b,.workspace-card small{display:block;overflow:hidden;text-overflow:ellipsis}.workspace-card small{margin-top:4px;color:var(--muted);white-space:nowrap}
|
|
3
|
+
@media(max-width:700px){body{height:100dvh;overflow:hidden;display:flex;flex-direction:column}header{height:auto;min-height:52px;flex:0 0 auto;padding:8px 12px;gap:8px;flex-wrap:nowrap}header .brand{margin-right:auto;gap:8px}header .brand img{width:30px;height:30px}header h1{font-size:18px}header .api-field,#serverInfo{display:none}#openConfig{padding:6px 8px}#status{max-width:92px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}main{height:auto;min-height:0;flex:1 1 auto;display:block;overflow:hidden}.mobile-only{display:inline-flex}aside,article{height:100%;min-height:0;border:0}aside{padding:10px;overflow-y:auto}article{display:none}.section-title{position:sticky;top:-10px;z-index:4;margin:-10px -10px 6px;padding:10px;background:var(--bg);border-bottom:1px solid var(--line)}.section-title h2{font-size:17px}.section-title button,.pathbar button,.filebar button{min-width:42px;min-height:40px}.entry{min-height:44px;padding:11px 8px}#workspaces{display:none}#mobileWorkspaces{display:block}#workspaceBrowser{display:none}#tree{max-height:none;overflow:visible}#filePanel{margin:0}#file{max-height:none;overflow:visible;padding:12px}#agentsSection{margin-top:18px}.agent{min-height:58px;padding:12px;margin:8px 0}.cwd-field input{min-height:42px}body[data-mobile-view="home"] #workspaceBack{display:none}body[data-mobile-view="workspace"] #agentsSection,body[data-mobile-view="file"] #agentsSection{display:none}body[data-mobile-view="workspace"] #workspaces,body[data-mobile-view="file"] #workspaces,body[data-mobile-view="workspace"] #mobileWorkspaces,body[data-mobile-view="file"] #mobileWorkspaces,body[data-mobile-view="workspace"] .workspace-home-actions,body[data-mobile-view="file"] .workspace-home-actions{display:none}body[data-mobile-view="workspace"] #workspaceBrowser,body[data-mobile-view="file"] #workspaceBrowser{display:block}body[data-mobile-view="workspace"] #filePanel{display:none}body[data-mobile-view="file"] #workspaceSection>.section-title,body[data-mobile-view="file"] .pathbar,body[data-mobile-view="file"] #tree{display:none}body[data-mobile-view="file"] #filePanel:not([hidden]){display:block}body[data-mobile-view="agent"] aside{display:none}body[data-mobile-view="agent"] article{display:flex}.toolbar{max-height:none;overflow:visible;padding:8px;flex-wrap:wrap;position:relative}.toolbar .title-wrap{min-width:0}.toolbar .agent-heading strong{font-size:15px}.toolbar .agent-action{display:none}.toolbar.actions-open .agent-action{display:inline-block}.toolbar #agentBack,.toolbar #mobileAgentActions{flex:0 0 auto;min-width:40px;min-height:40px}.toolbar .title-wrap{flex:1 1 160px}.context-track{width:min(180px,55%)}#messages{padding:10px}.msg{margin:7px 0}#prompt{padding:8px;padding-bottom:max(8px,env(safe-area-inset-bottom))}.composer-row{display:grid;grid-template-columns:minmax(0,1fr) auto auto;align-items:stretch}.composer-row #sendMode{grid-column:1/-1;width:100%;min-height:38px}.composer-row textarea{min-height:58px;max-height:24vh;resize:none}.composer-row>button{min-width:58px}#mentionPicker{left:8px;right:8px;bottom:116px;max-height:45vh}#toast{left:12px;right:12px;bottom:max(12px,env(safe-area-inset-bottom));text-align:center}dialog{min-width:0;width:calc(100vw - 24px);max-height:88dvh}body[data-mobile-view="file"] aside{padding-bottom:max(12px,env(safe-area-inset-bottom))}.long-press-menu{-webkit-touch-callout:none;user-select:none}.long-press-pending{background:#424b5d}}
|
|
4
|
+
.config-section{margin:14px 0;padding:12px;background:#252a33;border:1px solid var(--line);border-radius:7px}.config-section h3{margin:0 0 10px;font-size:14px}.config-section>small,.config-section>p{display:block;margin:7px 0}.config-actions{display:flex;gap:8px;flex-wrap:wrap}.toggle-row{display:flex!important;align-items:center;gap:9px}.toggle-row input{display:inline-block!important;width:auto!important;margin:0!important}.config-section label small{display:block;margin-top:5px;line-height:1.4}.config-section input[type="number"]{max-width:180px}#configConnectionStatus{margin-left:8px}@media(max-width:700px){#configDialog .config-actions button{flex:1}#configConnectionStatus{display:block;margin:8px 0 0}}
|
|
5
|
+
[hidden]{display:none!important}#terminalView{flex:1 1 0;min-height:0;overflow:hidden;background:#111;padding:8px}#terminal{width:100%;height:100%}#terminal .xterm{height:100%}#terminal .xterm-viewport{overscroll-behavior:contain}.terminal-kind{color:var(--blue);font:700 12px ui-monospace,monospace}.danger-action{border-color:#8b4b53}@media(max-width:700px){#terminalToolbar #terminalBack{display:inline-flex;min-width:40px;min-height:40px}#terminalView{padding:4px}}
|
|
6
|
+
|
|
7
|
+
/* Conversation previews keep the complete source text in the DOM and let CSS
|
|
8
|
+
truncate only the collapsed presentation. */
|
|
9
|
+
.msg summary{display:flex;align-items:center;gap:0;min-width:0}
|
|
10
|
+
.msg summary::before{flex:0 0 auto}
|
|
11
|
+
.msg summary .summary-text{min-width:0;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
12
|
+
.msg summary .event-time{float:none;flex:0 0 auto;margin-left:10px}
|
|
13
|
+
.msg-content.markdown{white-space:normal;line-height:1.55}
|
|
14
|
+
.msg-content.markdown>:first-child{margin-top:0}
|
|
15
|
+
.msg-content.markdown>:last-child{margin-bottom:0}
|
|
16
|
+
.msg-content.markdown p,.msg-content.markdown ul,.msg-content.markdown ol,.msg-content.markdown blockquote{margin:.65em 0}
|
|
17
|
+
.msg-content.markdown h1,.msg-content.markdown h2,.msg-content.markdown h3,.msg-content.markdown h4{margin:1em 0 .5em;line-height:1.25}
|
|
18
|
+
.msg-content.markdown h1{font-size:1.45em}.msg-content.markdown h2{font-size:1.3em}.msg-content.markdown h3{font-size:1.15em}
|
|
19
|
+
.msg-content.markdown code{padding:.12em .35em;border-radius:4px;background:#1d2129;font:12px ui-monospace,monospace}
|
|
20
|
+
.msg-content.markdown pre{overflow:auto;padding:10px;border-radius:5px;background:#1d2129;white-space:pre}
|
|
21
|
+
.msg-content.markdown pre code{padding:0;background:transparent}
|
|
22
|
+
.msg-content.markdown blockquote{padding-left:10px;border-left:3px solid var(--line);color:var(--muted)}
|
|
23
|
+
.msg-content.markdown table{display:block;max-width:100%;overflow:auto;border-collapse:collapse}
|
|
24
|
+
.msg-content.markdown th,.msg-content.markdown td{padding:5px 8px;border:1px solid var(--line)}
|
|
25
|
+
.msg-content.markdown a{color:var(--blue)}
|
|
26
|
+
.msg-content.markdown img{max-width:100%;height:auto}
|
|
27
|
+
.msg summary .summary-label{display:none;min-width:0;flex:1}
|
|
28
|
+
.msg.derived-title[open] summary .summary-text{display:none}
|
|
29
|
+
.msg.derived-title[open] summary .summary-label{display:block}
|