oh-my-agent-web 0.2.0 → 0.4.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.
Files changed (250) hide show
  1. package/README.md +86 -447
  2. package/dist/server/approval/read-only.js +107 -0
  3. package/dist/server/approval/rules.js +85 -0
  4. package/dist/server/approval/scope.js +150 -0
  5. package/dist/server/brand.js +2 -0
  6. package/dist/server/cli-config.js +52 -0
  7. package/dist/server/cli-info.js +101 -0
  8. package/dist/server/cli.js +304 -0
  9. package/dist/server/engine/builtin.js +61 -0
  10. package/dist/server/engine/catalog.js +8 -0
  11. package/dist/server/engine/codex-approvals.js +45 -0
  12. package/dist/server/engine/codex-map.js +298 -0
  13. package/dist/server/engine/codex-sessions.js +159 -0
  14. package/dist/server/engine/codex-transport.js +49 -0
  15. package/dist/server/engine/codex.js +314 -0
  16. package/dist/server/engine/dsh-history.js +195 -0
  17. package/dist/server/engine/dsh-log.js +245 -0
  18. package/dist/server/engine/dsh-map.js +221 -0
  19. package/dist/server/engine/dsh-sessions.js +207 -0
  20. package/dist/server/engine/dsh-transport.js +37 -0
  21. package/dist/server/engine/dsh.js +284 -0
  22. package/dist/server/engine/fake.js +231 -0
  23. package/dist/server/engine/jsonrpc-stdio.js +241 -0
  24. package/dist/server/engine/model-registry-reload.js +115 -0
  25. package/dist/server/engine/pi-events.js +148 -0
  26. package/dist/server/engine/pi-rename.js +14 -0
  27. package/dist/server/engine/pi-sdk.js +343 -0
  28. package/dist/server/engine/pi-session-model.js +23 -0
  29. package/dist/server/engine/pi-thinking.js +34 -0
  30. package/dist/server/engine/pi-transcript.js +225 -0
  31. package/dist/server/engine/pi-version.js +11 -0
  32. package/dist/server/engine/port.js +1 -0
  33. package/dist/server/engine/registry.js +47 -0
  34. package/dist/server/engine/scratch.js +13 -0
  35. package/dist/server/engine/suggestion-guidance.js +9 -0
  36. package/dist/server/engine/switchable.js +22 -0
  37. package/dist/server/engine/wiring.js +107 -0
  38. package/dist/server/files/dir-routes.js +40 -0
  39. package/dist/server/files/file-search.js +63 -0
  40. package/dist/server/files/file-service.js +232 -0
  41. package/dist/server/files/files-routes.js +182 -0
  42. package/dist/server/files/git-info.js +186 -0
  43. package/dist/server/http/auth-routes.js +99 -0
  44. package/dist/server/http/auth.js +191 -0
  45. package/dist/server/http/aux-routes.js +24 -0
  46. package/dist/server/http/compress.js +75 -0
  47. package/dist/server/http/health-and-static.js +33 -0
  48. package/dist/server/http/live-routes.js +113 -0
  49. package/dist/server/http/login-page.js +200 -0
  50. package/dist/server/index.js +342 -520
  51. package/dist/server/markers/actions.js +262 -0
  52. package/dist/server/protocol-parse.js +201 -0
  53. package/dist/server/protocol-settings.js +1 -0
  54. package/dist/server/protocol.js +6 -0
  55. package/dist/server/providers/catalog-store.js +85 -0
  56. package/dist/server/providers/catalog-writes.js +197 -0
  57. package/dist/server/providers/catalog.js +77 -0
  58. package/dist/server/providers/enabled-models.js +118 -0
  59. package/dist/server/providers/import-models.js +69 -0
  60. package/dist/server/providers/import-routes.js +136 -0
  61. package/dist/server/providers/model-test.js +52 -0
  62. package/dist/server/providers/probe.js +64 -0
  63. package/dist/server/providers/provider-handlers.js +203 -0
  64. package/dist/server/providers/provider-store.js +327 -0
  65. package/dist/server/providers/request-headers.js +7 -0
  66. package/dist/server/providers/validate.js +241 -0
  67. package/dist/server/push/push-routes.js +114 -0
  68. package/dist/server/push/push.js +120 -0
  69. package/dist/server/session/approval-bridge.js +103 -0
  70. package/dist/server/session/attachment-resolve.js +21 -0
  71. package/dist/server/session/client-view.js +82 -0
  72. package/dist/server/session/conversation-create.js +65 -0
  73. package/dist/server/session/delete-session.js +84 -0
  74. package/dist/server/session/engine-switch.js +108 -0
  75. package/dist/server/session/lock.js +82 -0
  76. package/dist/server/session/model-controller.js +111 -0
  77. package/dist/server/session/notices.js +31 -0
  78. package/dist/server/session/pi-opener.js +123 -0
  79. package/dist/server/session/pi-refresh.js +51 -0
  80. package/dist/server/session/pi-sessions-provider.js +46 -0
  81. package/dist/server/session/pi-sessions.js +272 -0
  82. package/dist/server/session/refresh-actions.js +42 -0
  83. package/dist/server/session/rename-session.js +23 -0
  84. package/dist/server/session/runtime-services.js +28 -0
  85. package/dist/server/session/runtime-types.js +1 -0
  86. package/dist/server/session/runtime.js +358 -0
  87. package/dist/server/session/session-stats.js +88 -0
  88. package/dist/server/session/settings.js +367 -0
  89. package/dist/server/session/snapshot-for.js +7 -0
  90. package/dist/server/session/stats-refresher.js +50 -0
  91. package/dist/server/session/switch-conversation.js +86 -0
  92. package/dist/server/session/throttle.js +14 -0
  93. package/dist/server/session/turn-events.js +126 -0
  94. package/dist/server/session/turn-finish.js +79 -0
  95. package/dist/server/session/turn-markers.js +26 -0
  96. package/dist/server/session/turn-queue.js +111 -0
  97. package/dist/server/session/turn-send.js +88 -0
  98. package/dist/server/session/turn-watchdog.js +77 -0
  99. package/dist/server/sessions/session-routes.js +17 -0
  100. package/dist/server/skills/skill-routes.js +28 -0
  101. package/dist/server/skills/skill-store.js +134 -0
  102. package/dist/server/snapshot/fan-out.js +10 -0
  103. package/dist/server/snapshot/messages.js +75 -0
  104. package/dist/server/snapshot/sender.js +62 -0
  105. package/dist/server/snapshot/state.js +193 -0
  106. package/dist/server/terminal/terminal-routes.js +176 -0
  107. package/dist/server/terminal/terminal-session.js +140 -0
  108. package/dist/server/uploads/upload-routes.js +64 -0
  109. package/dist/server/uploads/upload-store.js +115 -0
  110. package/dist/server/util/data-dir.js +36 -0
  111. package/dist/server/util/env.js +140 -0
  112. package/dist/server/util/ids.js +28 -0
  113. package/dist/server/util/log-file.js +67 -0
  114. package/dist/server/util/log.js +52 -0
  115. package/dist/server/util/origin.js +75 -0
  116. package/dist/server/util/paths.js +60 -0
  117. package/dist/server/util/pricing-index.js +121 -0
  118. package/dist/server/util/pricing.js +214 -0
  119. package/dist/server/util/startup.js +34 -0
  120. package/dist/server/util/upstream-version.js +140 -0
  121. package/dist/server/util/usage.js +19 -0
  122. package/dist/server/util/version.js +50 -0
  123. package/dist/server/ws/handle-message.js +95 -0
  124. package/package.json +49 -63
  125. package/web/dist/apple-touch-icon-precomposed.png +0 -0
  126. package/web/dist/apple-touch-icon.png +0 -0
  127. package/web/dist/assets/abnfDiagram-WEYOIA3C-NLp09iEC.js +1 -0
  128. package/web/dist/assets/arc-DviL9o3c.js +1 -0
  129. package/web/dist/assets/architecture-WOLXFQ4H-fjsM_Sy3.js +1 -0
  130. package/web/dist/assets/architectureDiagram-ZHVYKT53-Cn3B4TE8.js +36 -0
  131. package/web/dist/assets/array-BifhSqXX.js +1 -0
  132. package/web/dist/assets/blockDiagram-RJAE7QA3-CIuvxWvi.js +140 -0
  133. package/web/dist/assets/c4Diagram-XDPPPE54-DvdKmEpF.js +38 -0
  134. package/web/dist/assets/channel-C3AQ6nAs.js +1 -0
  135. package/web/dist/assets/chunk-2E7WHVMD-HNNASGCS.js +88 -0
  136. package/web/dist/assets/chunk-2Q5K7J3B-C1jixKkw.js +1 -0
  137. package/web/dist/assets/chunk-4EMNKR2T-Cg-eRwBE.js +1 -0
  138. package/web/dist/assets/chunk-55XCU76K-BweiisZL.js +1 -0
  139. package/web/dist/assets/chunk-5VM5RSS4-ZNzvKenW.js +15 -0
  140. package/web/dist/assets/chunk-7S6XSTFO-BCzIiP-6.js +2 -0
  141. package/web/dist/assets/chunk-AQDTSKZB-Dl0NRFuU.js +72 -0
  142. package/web/dist/assets/chunk-DSNLSHJZ-zhHCjjN9.js +129 -0
  143. package/web/dist/assets/chunk-DUW6YSOI-Dgx8z5s3.js +1 -0
  144. package/web/dist/assets/chunk-HAGFOTED-BDQqU2EH.js +62 -0
  145. package/web/dist/assets/chunk-HNE4Q36P-B-qRzMjX.js +1 -0
  146. package/web/dist/assets/chunk-J5ZVWO5B-oDCd-gWO.js +1 -0
  147. package/web/dist/assets/chunk-JWPE2WC7-DVXcaiue.js +1 -0
  148. package/web/dist/assets/chunk-NGNAAXSQ-C2Wy9Xmz.js +136 -0
  149. package/web/dist/assets/chunk-NQOKRVIF-CNcvhMn_.js +213 -0
  150. package/web/dist/assets/chunk-UHW7PFBP-Dwr8LUzr.js +1 -0
  151. package/web/dist/assets/chunk-VQ5W62QI-O8sN6jJu.js +1 -0
  152. package/web/dist/assets/chunk-WQQL4CDK-B6-59Zg2.js +10 -0
  153. package/web/dist/assets/chunk-XXDRQBXY-DvSbeUlZ.js +1 -0
  154. package/web/dist/assets/chunk-Y2CYZVJY-DsF7k-Jl.js +1 -0
  155. package/web/dist/assets/chunk-YZO67HFG-BXpKYKsw.js +1 -0
  156. package/web/dist/assets/chunk-ZAUX2LTX-B1Z5VSkz.js +1 -0
  157. package/web/dist/assets/chunk-ZCHMQSOR-h_5mBLIA.js +2 -0
  158. package/web/dist/assets/classDiagram-v2-4MYWR3UA-Dr6JnaaV.js +217 -0
  159. package/web/dist/assets/cose-bilkent-JH36ORCC-36ShkR7R.js +1 -0
  160. package/web/dist/assets/cynefin-EF2NZ3EQ-Dg6bI7pC.js +1 -0
  161. package/web/dist/assets/cynefinDiagram-WF24UDRP-B0YHpBlR.js +62 -0
  162. package/web/dist/assets/cytoscape.esm-BegBNzOV.js +321 -0
  163. package/web/dist/assets/dagre-NK4GIZVX-Cx3mn7YS.js +4 -0
  164. package/web/dist/assets/defaultLocale-BFoDCU3G.js +1 -0
  165. package/web/dist/assets/diagram-CBK3MWTC-l8aZG_Bm.js +24 -0
  166. package/web/dist/assets/diagram-I5XIIV2D-Bd5f14_h.js +24 -0
  167. package/web/dist/assets/diagram-ODIL2UCW-hBsxCYUj.js +30 -0
  168. package/web/dist/assets/diagram-PFBEJUXE-BgpIBUYl.js +3 -0
  169. package/web/dist/assets/diagram-RJA3I4VV-CDU1gUVD.js +41 -0
  170. package/web/dist/assets/diagram-TYUNFSNR-Iuxh7Tqf.js +200 -0
  171. package/web/dist/assets/dist-C86cKTuE.js +1 -0
  172. package/web/dist/assets/ebnfDiagram-V4P3TTPT-Cms0HFKh.js +1 -0
  173. package/web/dist/assets/elk-QONTBCTQ-B7yEy0PQ.js +27 -0
  174. package/web/dist/assets/erDiagram-KYQIGQAA-CL48j4aU.js +99 -0
  175. package/web/dist/assets/eventmodeling-K75KTNOO-CFvkaejh.js +1 -0
  176. package/web/dist/assets/flowDiagram-IUGLLWBU-6UyKXpqG.js +1 -0
  177. package/web/dist/assets/ganttDiagram-R7GPNTJY-vdMr-0ZV.js +292 -0
  178. package/web/dist/assets/gitGraph-VSP46ZUC-2z85Wuwo.js +1 -0
  179. package/web/dist/assets/gitGraphDiagram-PDYL7XHY-BY4GPiqC.js +106 -0
  180. package/web/dist/assets/graphlib-DS17s2tU.js +1 -0
  181. package/web/dist/assets/index-Bjn56a2i.js +76 -0
  182. package/web/dist/assets/index-Drp6e5iU.css +1 -0
  183. package/web/dist/assets/info-OHQRW6UA-ECzkYTx-.js +1 -0
  184. package/web/dist/assets/infoDiagram-MVDRKAX5-DDk5EAeb.js +2 -0
  185. package/web/dist/assets/init-C-OQMol4.js +1 -0
  186. package/web/dist/assets/ishikawaDiagram-HPEHV2GE-9yPH4J94.js +70 -0
  187. package/web/dist/assets/journeyDiagram-BOSHW7O7-BPTIap3l.js +139 -0
  188. package/web/dist/assets/kanban-definition-FNSA4HC5-BbADHrA8.js +89 -0
  189. package/web/dist/assets/katex-B_JcIwqj.js +257 -0
  190. package/web/dist/assets/line-CHV9_4lL.js +1 -0
  191. package/web/dist/assets/linear-C-eZsBTv.js +1 -0
  192. package/web/dist/assets/mermaid-parser.core-BiAhX1l1.js +7 -0
  193. package/web/dist/assets/mermaid.core-BxP_A_zj.js +44 -0
  194. package/web/dist/assets/mindmap-definition-6OY57UG3-BMWlit95.js +98 -0
  195. package/web/dist/assets/ordinal-BDEzSJ7C.js +1 -0
  196. package/web/dist/assets/packet-JDAUHWVQ-FVApuKOp.js +1 -0
  197. package/web/dist/assets/path-fybaL0A-.js +1 -0
  198. package/web/dist/assets/pegDiagram-ECIUJNBX-WjWJvDHM.js +1 -0
  199. package/web/dist/assets/pie-XZMESJXO-BGCZnvhp.js +1 -0
  200. package/web/dist/assets/pieDiagram-GNMPY74T-DJpAC_JC.js +39 -0
  201. package/web/dist/assets/quadrantDiagram-D57K4MC3-hxx5c7oq.js +7 -0
  202. package/web/dist/assets/radar-ABXABTNO-BU9Shc-O.js +1 -0
  203. package/web/dist/assets/railroad-I3PHUGI6-pWj8d-G4.js +1 -0
  204. package/web/dist/assets/railroad-abnf-LNEFI6M7-D7HZBTAj.js +1 -0
  205. package/web/dist/assets/railroad-ebnf-DWYD2UWJ-CKiXJSuM.js +1 -0
  206. package/web/dist/assets/railroad-peg-JR7BVNR7-DB3VJHgR.js +1 -0
  207. package/web/dist/assets/railroadDiagram-Y72NRBL7-Cev7Y65k.js +1 -0
  208. package/web/dist/assets/requirementDiagram-EQYSW5RA-CqbwMLD8.js +84 -0
  209. package/web/dist/assets/rough.esm-Dy-Kn_BL.js +1 -0
  210. package/web/dist/assets/sankeyDiagram-SY24JHO5-V2cyVi8q.js +40 -0
  211. package/web/dist/assets/sequenceDiagram-BLEHNHQU-By6NJOPM.js +169 -0
  212. package/web/dist/assets/sizeCapture-INFHLROL-3uHXrFqA.js +1 -0
  213. package/web/dist/assets/src-Da91fG3g.js +1 -0
  214. package/web/dist/assets/stateDiagram-v2-A6IESKWZ-BnPGX5UI.js +291 -0
  215. package/web/dist/assets/swimlanes-B3ENRKFQ-C58BpIpm.js +1 -0
  216. package/web/dist/assets/swimlanesDiagram-AYQRV4AK-RaivxSsc.js +8 -0
  217. package/web/dist/assets/timeline-definition-JXYKGLGB-Hgo1DhnS.js +120 -0
  218. package/web/dist/assets/treeView-D4JQ5SDB-DF0dfjqB.js +1 -0
  219. package/web/dist/assets/treemap-SAJKECNS-CSSM5FqB.js +1 -0
  220. package/web/dist/assets/usecaseDiagram-WPOLBNNX-BkBBD1NY.js +328 -0
  221. package/web/dist/assets/vennDiagram-Q3Y3IDCW-Bm28keX_.js +34 -0
  222. package/web/dist/assets/wardley-7MLQ67FV-By7KgEQX.js +1 -0
  223. package/web/dist/assets/wardleyDiagram-IVAIDKWA-oVtIrnGa.js +78 -0
  224. package/web/dist/assets/xychartDiagram-4URNHDU4-aI8FH4g2.js +7 -0
  225. package/web/dist/favicon-32.png +0 -0
  226. package/web/dist/favicon.ico +0 -0
  227. package/web/dist/favicon.svg +20 -8
  228. package/web/dist/icons/apple-touch-icon-180.png +0 -0
  229. package/web/dist/icons/icon-192.png +0 -0
  230. package/web/dist/icons/icon-512.png +0 -0
  231. package/web/dist/icons/icon-maskable-512.png +0 -0
  232. package/web/dist/index.html +21 -27
  233. package/web/dist/manifest.webmanifest +17 -0
  234. package/web/dist/maskable.svg +25 -0
  235. package/web/dist/sw.js +40 -0
  236. package/bin/oh-my-agent-web-ps.mjs +0 -203
  237. package/bin/oh-my-agent-web-ws.mjs +0 -593
  238. package/bin/oh-my-agent-web.mjs +0 -321
  239. package/bin/update-check.mjs +0 -142
  240. package/dist/server/codex-client.js +0 -310
  241. package/dist/server/codex-supervisor.js +0 -446
  242. package/dist/server/fs-service.js +0 -144
  243. package/dist/server/request-inspector.js +0 -458
  244. package/dist/shared/protocol.js +0 -112
  245. package/scripts/manage-server.mjs +0 -155
  246. package/scripts/omaw.mjs +0 -74
  247. package/shared/protocol.ts +0 -228
  248. package/web/dist/assets/index-B8-VzDf2.css +0 -1
  249. package/web/dist/assets/index-DeC2eiiq.js +0 -42
  250. package/web/dist/assets/markdown-CYXe6JZx.js +0 -55
@@ -1,155 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * npm run stop / npm run restart helper for the local oh-my-agent-web service.
4
- * It only targets a oh-my-agent-web process listening on OMAW_PORT.
5
- */
6
- import { execFileSync, spawn } from "node:child_process";
7
-
8
- const port = Number(process.env.OMAW_PORT || 25257);
9
- const command = process.argv[2] || "stop";
10
- const extraArgs = process.argv.slice(3);
11
-
12
- function commandForPid(pid) {
13
- if (process.platform === "win32") {
14
- try {
15
- return execFileSync("wmic", ["process", "where", `ProcessId=${pid}`, "get", "CommandLine", "/value"], {
16
- encoding: "utf8",
17
- stdio: ["ignore", "pipe", "ignore"],
18
- }).trim();
19
- } catch {
20
- return "";
21
- }
22
- }
23
- try {
24
- return execFileSync("ps", ["-p", String(pid), "-o", "command="], {
25
- encoding: "utf8",
26
- stdio: ["ignore", "pipe", "ignore"],
27
- }).trim();
28
- } catch {
29
- return "";
30
- }
31
- }
32
-
33
- function listeningPids() {
34
- if (process.platform === "win32") {
35
- try {
36
- const output = execFileSync("netstat", ["-ano", "-p", "tcp"], { encoding: "utf8" });
37
- const pids = new Set();
38
- for (const line of output.split(/\r?\n/)) {
39
- if (!line.includes(`:${port}`) || !/LISTENING/i.test(line)) continue;
40
- const match = /\s+(\d+)\s*$/.exec(line);
41
- if (match) pids.add(Number(match[1]));
42
- }
43
- return [...pids];
44
- } catch {
45
- return [];
46
- }
47
- }
48
- try {
49
- const output = execFileSync("lsof", [`-tiTCP:${port}`, "-sTCP:LISTEN"], {
50
- encoding: "utf8",
51
- stdio: ["ignore", "pipe", "ignore"],
52
- });
53
- return [...new Set(output.split(/\s+/).filter(Boolean).map(Number).filter(Number.isInteger))];
54
- } catch {
55
- return [];
56
- }
57
- }
58
-
59
- /**
60
- * Is this pid one of ours?
61
- *
62
- * Matched against the **command line**, which differs by how the server was
63
- * started:
64
- * - global install: `…/bin/oh-my-agent-web.mjs` (or `…/bin/omaw` via the alias)
65
- * - repo, dev: `tsx watch server/index.ts` → the listener child runs
66
- * `node --require …/tsx … server/index.ts`
67
- * - repo, built: `node …/dist/server/index.js`
68
- *
69
- * The checkout folder name is deliberately NOT used: it can be anything, and
70
- * matching it only ever worked by accident (when the folder happened to be named
71
- * after the package).
72
- */
73
- function isProjectProcess(pid) {
74
- const cmd = commandForPid(pid);
75
- if (/oh-my-agent-web|bin[\\/](?:oh-my-agent-web|omaw)/.test(cmd)) return true;
76
- // Dev / built entry point, however the runner was invoked. The path is
77
- // relative in the child's argv (`… tsx/dist/loader.mjs server/index.ts`), so
78
- // match on a word boundary rather than a preceding slash.
79
- return /\bserver[\\/]index\.(?:ts|js)\b/.test(cmd) && /\b(?:node|tsx)\b/.test(cmd);
80
- }
81
-
82
- function isAlive(pid) {
83
- try {
84
- process.kill(pid, 0);
85
- return true;
86
- } catch {
87
- return false;
88
- }
89
- }
90
-
91
- function sleep(ms) {
92
- return new Promise((resolve) => setTimeout(resolve, ms));
93
- }
94
-
95
- async function stop() {
96
- const pids = listeningPids();
97
- if (pids.length === 0) {
98
- console.log(`oh-my-agent-web 未运行(端口 ${port})。`);
99
- return true;
100
- }
101
-
102
- const owned = pids.filter(isProjectProcess);
103
- const foreign = pids.filter((pid) => !owned.includes(pid));
104
- if (foreign.length > 0) {
105
- console.error(`端口 ${port} 被其他进程占用,未执行停止:${foreign.join(", ")}`);
106
- return false;
107
- }
108
- if (owned.length === 0) {
109
- console.error(`端口 ${port} 被占用,但不是 oh-my-agent-web 进程,未执行停止。`);
110
- return false;
111
- }
112
-
113
- for (const pid of owned) {
114
- console.log(`正在停止 oh-my-agent-web (pid ${pid})…`);
115
- try {
116
- process.kill(pid, "SIGTERM");
117
- } catch (error) {
118
- if (error?.code !== "ESRCH") throw error;
119
- }
120
- }
121
-
122
- const deadline = Date.now() + 8_000;
123
- while (Date.now() < deadline && owned.some(isAlive)) await sleep(200);
124
- const stuck = owned.filter(isAlive);
125
- for (const pid of stuck) {
126
- console.warn(`pid ${pid} 未退出,发送 SIGKILL…`);
127
- try {
128
- process.kill(pid, "SIGKILL");
129
- } catch {
130
- /* already gone */
131
- }
132
- }
133
- console.log("oh-my-agent-web 已停止。");
134
- return true;
135
- }
136
-
137
- if (command === "stop") {
138
- process.exitCode = (await stop()) ? 0 : 1;
139
- } else if (command === "restart") {
140
- if (!(await stop())) process.exit(1);
141
- const npm = process.platform === "win32" ? "npm.cmd" : "npm";
142
- const args = extraArgs.length > 0 ? ["start", "--", ...extraArgs] : ["start"];
143
- console.log("正在重新启动 oh-my-agent-web…");
144
- const child = spawn(npm, args, { stdio: "inherit", env: process.env });
145
- child.on("error", (error) => {
146
- console.error(`启动失败:${error.message}`);
147
- process.exitCode = 1;
148
- });
149
- child.on("exit", (code, signal) => {
150
- process.exitCode = code ?? (signal ? 1 : 0);
151
- });
152
- } else {
153
- console.error(`未知命令:${command}。可用命令:stop、restart`);
154
- process.exitCode = 2;
155
- }
package/scripts/omaw.mjs DELETED
@@ -1,74 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * `npm run omaw` — 仓库内的一条总入口,行为取决于有没有参数:
4
- *
5
- * npm run omaw 起本地开发栈(源码直跑,2 个进程)
6
- * = `npm run dev`:单进程、单端口 :25257,Vite 在进程内当中间件
7
- * npm run omaw -- ps 转发给 CLI:进程 / 端口巡检
8
- * npm run omaw -- stop 转发给 CLI:停掉监听 UI 端口的服务
9
- * npm run omaw -- restart 转发给 CLI:停掉后重新起(前台)
10
- * npm run omaw -- ws -p 25268 转发给 CLI:用 WS 客户端临时接入指定地址的 app-server
11
- * npm run omaw -- --port 3000 转发给 CLI:直接起后端(源码直跑,不做 Vite)
12
- * npm run omaw -- --help CLI 帮助
13
- *
14
- * ⚠️ 参数必须写在 `--` 之后。
15
- *
16
- * npm(≥7)会先把 `-p` / `--port` / `--url` 这类 flag 当成*自己的*配置吃掉,
17
- * 剩下的位置参数才给脚本。实测 npm 11:
18
- *
19
- * npm run omaw ws -p 25268 → 收到 ["ws", "25268"] (-p 丢失,25268 被当成聊天消息)
20
- * npm run omaw -- ws -p 25268 → 收到 ["ws", "-p", "25268"] ✅
21
- *
22
- * 这是 npm 的行为,脚本侧无法挽回(`npm_config_argv` 在 npm 7 已被移除),
23
- * 所以这里不去猜、也不做兜底,只负责老老实实转发。
24
- */
25
- import { spawn } from "node:child_process";
26
- import { dirname, join, resolve } from "node:path";
27
- import { fileURLToPath } from "node:url";
28
-
29
- const here = dirname(fileURLToPath(import.meta.url));
30
- const repoRoot = resolve(here, "..");
31
- const cliEntry = join(repoRoot, "bin", "oh-my-agent-web.mjs");
32
-
33
- const args = process.argv.slice(2);
34
- const isWindows = process.platform === "win32";
35
- const npmBin = isWindows ? "npm.cmd" : "npm";
36
-
37
- /** 无参数 → 复用 `npm run dev`,避免把 dev 的命令行在这里抄一遍。 */
38
- function childFor() {
39
- if (args.length === 0) {
40
- // 端口与 dev 保持一致:OMAW_PORT 未设时默认 25257。
41
- const port = Number(process.env.OMAW_PORT) || 25257;
42
- const host = process.env.OMAW_HOST ?? "127.0.0.1";
43
- return {
44
- command: npmBin,
45
- argv: ["run", "dev"],
46
- note: `dev stack → http://${host}:${port} (源码模式,Vite 在进程内,无需 build)`,
47
- };
48
- }
49
- return { command: process.execPath, argv: [cliEntry, ...args], note: null };
50
- }
51
-
52
- const { command, argv, note } = childFor();
53
- if (note) console.error(`[omaw] ${note}`);
54
-
55
- const child = spawn(command, argv, {
56
- cwd: repoRoot,
57
- stdio: "inherit",
58
- // Windows 上 npm.cmd 需要 shell 才能被 spawn。
59
- shell: isWindows,
60
- });
61
-
62
- child.on("error", (err) => {
63
- console.error(`[omaw] failed to start: ${err.message}`);
64
- process.exit(1);
65
- });
66
-
67
- child.on("exit", (code, signal) => {
68
- // Ctrl-C 会同时发给整个前台进程组,这里只需要把退出状态如实传出去。
69
- if (signal) {
70
- process.kill(process.pid, signal);
71
- return;
72
- }
73
- process.exit(code ?? 0);
74
- });
@@ -1,228 +0,0 @@
1
- /**
2
- * oh-my-agent-web — browser <-> server wire protocol.
3
- *
4
- * The browser talks to OUR server (not directly to codex). Our server is a thin,
5
- * transparent proxy in front of `codex app-server --listen ws://127.0.0.1:25258`:
6
- *
7
- * browser <--ws /ws--> oh-my-agent-web server <--ws--> codex app-server
8
- *
9
- * Because the proxy is transparent, the browser may invoke ANY codex app-server
10
- * JSON-RPC method by name (`thread/start`, `turn/start`, `model/list`, ...) and
11
- * receives every codex notification verbatim. The names/types below therefore
12
- * mirror codex's own protocol; only the *envelope* is ours.
13
- *
14
- * Codex types can be regenerated with:
15
- * codex app-server generate-ts --out shared/codex-ts
16
- *
17
- * Envelope rules
18
- * --------------
19
- * client -> server:
20
- * { type: "rpc", requestId, method, params } invoke a codex method (or `omaw/*`)
21
- * { type: "reply", id, result } answer a serverRequest (approval, user input)
22
- * { type: "reply", id, error } reject a serverRequest
23
- * { type: "ping" }
24
- *
25
- * server -> client:
26
- * { type: "welcome", ... } handshake, sent once per connection
27
- * { type: "status", codex } supervisor state, on change
28
- * { type: "rpcResult", requestId, ok, ... } answer to our rpc
29
- * { type: "event", method, params } codex notification (verbatim)
30
- * { type: "serverRequest", id, method, params }codex -> client request (verbatim)
31
- * { type: "pong" }
32
- */
33
-
34
- export const PROTOCOL_VERSION = 1;
35
-
36
- /** JSON-RPC id as used by codex (`RequestId` in the generated bindings). */
37
- export type RequestId = number | string;
38
-
39
- export interface JsonRpcError {
40
- code: number;
41
- message: string;
42
- data?: unknown;
43
- }
44
-
45
- /* ------------------------------------------------------------------ */
46
- /* client -> server */
47
- /* ------------------------------------------------------------------ */
48
-
49
- export type ClientMessage =
50
- | { type: "rpc"; requestId: string; method: string; params?: unknown }
51
- | { type: "reply"; id: RequestId; result: unknown }
52
- | { type: "reply"; id: RequestId; error: JsonRpcError }
53
- | { type: "ping" };
54
-
55
- /* ------------------------------------------------------------------ */
56
- /* server -> client */
57
- /* ------------------------------------------------------------------ */
58
-
59
- /** Lifecycle of the managed `codex app-server` child process. */
60
- export type CodexPhase = "starting" | "ready" | "stopped" | "error";
61
-
62
- export interface CodexStatus {
63
- phase: CodexPhase;
64
- /** ws:// endpoint the app-server listens on. */
65
- url: string;
66
- pid: number | null;
67
- /** True once initialize + WS handshake completed. */
68
- connected: boolean;
69
- /** Last supervisor error, if any. */
70
- error: string | null;
71
- /** ms timestamp of the last successful (re)connect. */
72
- since: number | null;
73
- /** Restart counter — grows on every respawn. */
74
- restarts: number;
75
- }
76
-
77
- export interface ServerInfo {
78
- version: string;
79
- protocolVersion: number;
80
- cwd: string;
81
- codexUrl: string;
82
- codexVersion: string | null;
83
- platform: NodeJS.Platform;
84
- }
85
-
86
- export type ServerMessage =
87
- | { type: "welcome"; info: ServerInfo }
88
- | { type: "status"; codex: CodexStatus }
89
- | { type: "rpcResult"; requestId: string; ok: true; result: unknown }
90
- | { type: "rpcResult"; requestId: string; ok: false; error: JsonRpcError }
91
- | { type: "event"; method: string; params: unknown }
92
- | { type: "serverRequest"; id: RequestId; method: string; params: unknown }
93
- | { type: "pong" };
94
-
95
- /* ------------------------------------------------------------------ */
96
- /* local (`omaw/*`) methods — handled by OUR server, not proxied */
97
- /* ------------------------------------------------------------------ */
98
-
99
- export const LOCAL_METHODS = {
100
- /** -> { status: CodexStatus } */
101
- codexStatus: "omaw/codex/status",
102
- /** -> { ok: true } — kill + respawn the app-server */
103
- codexRestart: "omaw/codex/restart",
104
- /** -> { lines: string[] } — tail of the app-server log */
105
- codexLog: "omaw/codex/log",
106
- /** { threadId?: string, limit?: number } -> request/response summaries */
107
- requestLogsList: "omaw/request-logs/list",
108
- /** { id: string } -> one full request/response exchange */
109
- requestLogsDetail: "omaw/request-logs/detail",
110
- /** { path?: string } -> { path, entries: [{name,path,kind,size,mtime}] } */
111
- fsList: "omaw/fs/list",
112
- /** { path: string, maxBytes?: number } -> { path, text, truncated } */
113
- fsRead: "omaw/fs/read",
114
- /** -> { cwd, home, codexHome } */
115
- paths: "omaw/paths",
116
- } as const;
117
-
118
- export interface FsEntry {
119
- name: string;
120
- path: string;
121
- kind: "file" | "directory" | "symlink" | "other";
122
- size: number;
123
- mtime: number;
124
- }
125
-
126
- export interface CwPaths {
127
- cwd: string;
128
- home: string;
129
- codexHome: string;
130
- }
131
-
132
- export interface RequestLogSummary {
133
- id: string;
134
- startedAt: string;
135
- status: number | null;
136
- model: string | null;
137
- durationMs: number | null;
138
- requestBytes: number;
139
- responseBytes: number;
140
- error: string | null;
141
- threadId: string;
142
- turnId: string;
143
- source: string;
144
- trigger: string;
145
- internal: boolean;
146
- question: string;
147
- answer: string;
148
- reasoning: string;
149
- tools: string[];
150
- usage: Record<string, unknown> | null;
151
- tokens: {
152
- input: number;
153
- cached: number;
154
- cacheWrite: number;
155
- output: number;
156
- reasoning: number;
157
- };
158
- }
159
-
160
- export interface RequestLogDetail extends RequestLogSummary {
161
- requestHeaders: Record<string, string>;
162
- responseHeaders: Record<string, string>;
163
- requestBody: string;
164
- responseBody: string;
165
- responseTruncated: boolean;
166
- }
167
-
168
- /* ------------------------------------------------------------------ */
169
- /* codex method names we rely on — kept loose on purpose */
170
- /* ------------------------------------------------------------------ */
171
-
172
- export const CODEX = {
173
- initialize: "initialize",
174
- threadStart: "thread/start",
175
- threadResume: "thread/resume",
176
- threadRead: "thread/read",
177
- threadList: "thread/list",
178
- threadDelete: "thread/delete",
179
- threadArchive: "thread/archive",
180
- threadUnarchive: "thread/unarchive",
181
- threadFork: "thread/fork",
182
- threadSetName: "thread/name/set",
183
- threadTurnsList: "thread/turns/list",
184
- threadItemsList: "thread/items/list",
185
- turnStart: "turn/start",
186
- turnSteer: "turn/steer",
187
- turnInterrupt: "turn/interrupt",
188
- modelList: "model/list",
189
- accountRead: "account/read",
190
- accountRateLimits: "account/rateLimits/read",
191
- getAuthStatus: "getAuthStatus",
192
- configRead: "config/read",
193
- fsReadFile: "fs/readFile",
194
- fsReadDirectory: "fs/readDirectory",
195
- fuzzyFileSearch: "fuzzyFileSearch",
196
- } as const;
197
-
198
- /** codex notification methods that the UI cares about most. */
199
- export const CODEX_EVENTS = {
200
- threadStarted: "thread/started",
201
- threadStatusChanged: "thread/status/changed",
202
- threadNameUpdated: "thread/name/updated",
203
- turnStarted: "turn/started",
204
- turnCompleted: "turn/completed",
205
- turnDiffUpdated: "turn/diff/updated",
206
- turnPlanUpdated: "turn/plan/updated",
207
- itemStarted: "item/started",
208
- itemCompleted: "item/completed",
209
- agentMessageDelta: "item/agentMessage/delta",
210
- reasoningSummaryDelta: "item/reasoning/summaryTextDelta",
211
- reasoningTextDelta: "item/reasoning/textDelta",
212
- planDelta: "item/plan/delta",
213
- commandOutputDelta: "item/commandExecution/outputDelta",
214
- fileChangeDelta: "item/fileChange/outputDelta",
215
- mcpProgress: "item/mcpToolCall/progress",
216
- tokenUsage: "thread/tokenUsage/updated",
217
- error: "error",
218
- } as const;
219
-
220
- /** codex server -> client request methods (need a `reply`). */
221
- export const CODEX_REQUESTS = {
222
- commandApproval: "item/commandExecution/requestApproval",
223
- fileChangeApproval: "item/fileChange/requestApproval",
224
- permissionsApproval: "item/permissions/requestApproval",
225
- toolInput: "item/tool/requestUserInput",
226
- elicitation: "mcpServer/elicitation/request",
227
- dynamicToolCall: "item/tool/call",
228
- } as const;
@@ -1 +0,0 @@
1
- :root,[data-theme=dark]{--bg: #0a0b0e;--bg-elev: #101218;--bg-elev2: #161923;--bg-inset: #0c0e13;--border: #232733;--border-soft: #1b1f29;--text: #e7e9ef;--text-dim: #9aa1b1;--text-faint: #666d7e;--accent: #8b7bff;--accent-soft: rgba(139, 123, 255, .14);--accent-strong: #a99cff;--green: #3ecf8e;--green-soft: rgba(62, 207, 142, .14);--red: #f16a6a;--red-soft: rgba(241, 106, 106, .14);--amber: #f0b429;--amber-soft: rgba(240, 180, 41, .14);--blue: #4c8dff;--blue-soft: rgba(76, 141, 255, .14);--code-bg: #0b0d12;--code-border: #1e2230;--user-bg: #1c1f2a;--shadow: 0 12px 40px rgba(0, 0, 0, .45);--shadow-soft: 0 4px 16px rgba(0, 0, 0, .3);--scroll-thumb: #2a2f3c;--scroll-thumb-hover: #3a4152;--sans: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", Roboto, Helvetica, Arial, sans-serif;--mono: "SF Mono", "JetBrains Mono", ui-monospace, Menlo, Consolas, monospace}[data-theme=light]{color-scheme:light;--bg: #ffffff;--bg-elev: #f6f8fa;--bg-elev2: #eaeef2;--bg-inset: #f6f8fa;--border: #d0d7de;--border-soft: #e4e8ed;--text: #1f2328;--text-dim: #59636e;--text-faint: #8c959f;--accent: #0969da;--accent-soft: rgba(9, 105, 218, .1);--accent-strong: #0550ae;--green: #1a7f37;--green-soft: rgba(26, 127, 55, .1);--red: #cf222e;--red-soft: rgba(207, 34, 46, .09);--amber: #9a6700;--amber-soft: rgba(154, 103, 0, .14);--blue: #0969da;--blue-soft: rgba(9, 105, 218, .1);--code-bg: #f6f8fa;--code-border: #e4e8ed;--user-bg: #ddf4ff;--shadow: 0 12px 32px rgba(31, 35, 40, .13);--shadow-soft: 0 3px 12px rgba(31, 35, 40, .07);--scroll-thumb: #c9d1d9;--scroll-thumb-hover: #afb8c1}[data-theme=paper]{color-scheme:light;--bg: #f7f1e3;--bg-elev: #fffdf6;--bg-elev2: #efe7d3;--bg-inset: #fffdf6;--border: #ddcfae;--border-soft: #e7dcc3;--text: #3f372c;--text-dim: #6f6250;--text-faint: #9c8b70;--accent: #b45309;--accent-soft: rgba(180, 83, 9, .12);--accent-strong: #92400e;--green: #15803d;--green-soft: rgba(21, 128, 61, .12);--red: #b91c1c;--red-soft: rgba(185, 28, 28, .1);--amber: #a16207;--amber-soft: rgba(161, 98, 7, .14);--blue: #1d4ed8;--blue-soft: rgba(29, 78, 216, .1);--code-bg: #efe7d3;--code-border: #e0d3b8;--user-bg: #f3e6c9;--shadow: 0 12px 32px rgba(80, 60, 20, .16);--shadow-soft: 0 3px 12px rgba(80, 60, 20, .09);--scroll-thumb: #d3c4a3;--scroll-thumb-hover: #b8a67f}[data-theme=mist]{color-scheme:light;--bg: #f4f8f7;--bg-elev: #e9f0ee;--bg-elev2: #dde8e4;--bg-inset: #eef4f2;--border: #bfd0c8;--border-soft: #d5e2dc;--text: #202e2b;--text-dim: #4a6159;--text-faint: #7b918a;--accent: #0f766e;--accent-soft: rgba(15, 118, 110, .11);--accent-strong: #115e59;--green: #15803d;--green-soft: rgba(21, 128, 61, .12);--red: #b91c1c;--red-soft: rgba(185, 28, 28, .1);--amber: #a16207;--amber-soft: rgba(161, 98, 7, .14);--blue: #0e7490;--blue-soft: rgba(14, 116, 144, .11);--code-bg: #e9f0ee;--code-border: #d5e2dc;--user-bg: #d8ebe7;--shadow: 0 12px 32px rgba(20, 50, 45, .15);--shadow-soft: 0 3px 12px rgba(20, 50, 45, .08);--scroll-thumb: #b4c8c1;--scroll-thumb-hover: #9bb3ab}*{box-sizing:border-box}html,body,#root{height:100%;margin:0}body{background:var(--bg);color:var(--text);font-family:var(--sans);font-size:14px;line-height:1.5;-webkit-font-smoothing:antialiased}button,input,select,textarea{font:inherit;color:inherit}button{cursor:pointer}::-webkit-scrollbar{width:10px;height:10px}::-webkit-scrollbar-thumb{background:var(--scroll-thumb);border-radius:6px;border:2px solid transparent;background-clip:padding-box}::-webkit-scrollbar-thumb:hover{background:var(--scroll-thumb-hover);background-clip:padding-box}.muted{color:var(--text-dim)}.small{font-size:12px}.pad{padding:10px 12px}.spacer{flex:1}.error-text{color:var(--red)}.mono{font-family:var(--mono)}.btn{display:inline-flex;align-items:center;gap:6px;border:1px solid var(--border);background:var(--bg-elev2);color:var(--text);border-radius:8px;padding:7px 12px;font-size:13px;font-weight:500;transition:background .12s ease,border-color .12s ease,transform .05s ease}.btn:hover:not(:disabled){background:var(--bg-elev);border-color:var(--text-faint)}.btn:active:not(:disabled){transform:translateY(1px)}.btn:disabled{opacity:.45;cursor:not-allowed}.btn.primary{background:var(--accent);border-color:var(--accent);color:#fff}.btn.primary:hover:not(:disabled){background:var(--accent-strong);border-color:var(--accent-strong)}.btn.danger{background:var(--red-soft);border-color:var(--red);color:var(--red)}.btn.ghost{background:transparent}.btn.small{padding:5px 9px;font-size:12px}.icon-btn{display:inline-flex;align-items:center;justify-content:center;width:30px;height:30px;border-radius:8px;border:1px solid transparent;background:transparent;color:var(--text-dim)}.icon-btn:hover{background:var(--bg-elev2);color:var(--text)}.icon-btn.tiny{width:24px;height:24px}.icon-btn.active{background:var(--accent-soft);color:var(--accent-strong)}.kbd{border:1px solid var(--border);border-radius:5px;padding:1px 5px;font-size:11px;color:var(--text-faint);background:var(--bg)}.app{display:flex;height:100%;overflow:hidden}.sidebar-container{width:var(--sidebar-w, 288px);flex:0 0 var(--sidebar-w, 288px);border-right:1px solid var(--border);background:var(--bg-elev);height:100%;z-index:30;position:relative}.sidebar-container.dragging{border-right-color:var(--accent)}.app.sidebar-collapsed .sidebar-container{display:none}.sidebar-rail{display:flex;align-items:flex-start;justify-content:center;padding-top:14px;width:30px;flex:0 0 30px;border:none;border-right:1px solid var(--border);background:var(--bg-elev);color:var(--text-faint);cursor:pointer}.sidebar-rail:hover{background:var(--bg-elev2);color:var(--text)}.resize-handle{position:absolute;z-index:45;touch-action:none}.resize-handle:after{content:"";position:absolute;background:transparent;transition:background .12s ease}.resize-handle.vertical{top:0;bottom:0;width:11px;cursor:col-resize}.resize-handle.vertical:after{top:0;bottom:0;left:5px;width:2px}.resize-handle.vertical.left{left:-6px}.resize-handle.vertical:not(.left){right:-6px}.resize-handle:hover:after,.dragging>.resize-handle:after{background:var(--accent)}.main{display:flex;flex-direction:column;flex:1;min-width:0;height:100%;background:var(--bg)}.sidebar{display:flex;flex-direction:column;height:100%;padding:12px;gap:10px}.sidebar-head{display:flex;align-items:center;justify-content:space-between;padding:2px 2px 4px}.brand{display:flex;align-items:center;gap:9px;font-weight:650;letter-spacing:-.01em}.brand-mark{display:inline-flex;width:26px;height:26px;align-items:center;justify-content:center;border-radius:8px;background:linear-gradient(135deg,var(--accent-strong),var(--accent));color:#fff}.brand-name{font-size:15px}.new-thread{width:100%;justify-content:center}.search-box{display:flex;align-items:center;gap:8px;background:var(--bg);border:1px solid var(--border);border-radius:9px;padding:6px 9px;color:var(--text-faint)}.search-box:focus-within{border-color:var(--accent)}.search-box input{flex:1;min-width:0;border:none;background:transparent;outline:none;color:var(--text);font-size:13px}.sidebar-section-head{display:flex;align-items:center;gap:8px;padding:2px 10px 4px}.sidebar-section-label{font-size:11px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:var(--text-faint)}.thread-count{margin-left:auto;font-size:11px}.sidebar-scroll{flex:1;overflow-y:auto;margin:0 -4px;padding:0 4px}.thread-list{display:flex;flex-direction:column;gap:2px}.list-empty,.list-error{padding:16px 8px;font-size:13px;text-align:center;display:flex;flex-direction:column;gap:8px;align-items:center}.thread-row{display:flex;align-items:center;border-radius:8px;position:relative}.thread-row:hover{background:var(--bg-elev2)}.thread-row.active{background:var(--accent-soft)}.thread-main{flex:1;min-width:0;display:flex;align-items:center;gap:9px;border:none;background:transparent;text-align:left;padding:7px 8px;border-radius:8px}.thread-texts{display:flex;flex-direction:column;min-width:0;gap:1px}.thread-title{font-size:13px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.thread-row.active .thread-title{color:var(--accent-strong)}.thread-sub{font-size:11.5px;color:var(--text-faint);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.status-dot{width:8px;height:8px;border-radius:50%;flex:0 0 8px;background:var(--text-faint)}.dot-idle{background:var(--text-faint)}.dot-active{background:var(--green);box-shadow:0 0 0 3px var(--green-soft);animation:pulse 1.6s infinite}.dot-error{background:var(--red)}.dot-faint{background:var(--border)}@keyframes pulse{0%,to{opacity:1}50%{opacity:.4}}.thread-menu-btn{opacity:0;margin-right:4px}.thread-row:hover .thread-menu-btn,.thread-row.active .thread-menu-btn{opacity:1}.thread-rename{flex:1;margin:4px;padding:5px 8px;border-radius:7px;border:1px solid var(--accent);background:var(--bg);outline:none;font-size:13px}.load-more{margin:8px 4px;justify-content:center}.menu{position:absolute;top:calc(100% + 2px);right:4px;z-index:40;min-width:168px;background:var(--bg-elev2);border:1px solid var(--border);border-radius:10px;box-shadow:var(--shadow);padding:5px;display:flex;flex-direction:column}.menu button{display:flex;align-items:center;gap:9px;border:none;background:transparent;color:var(--text);text-align:left;padding:7px 9px;border-radius:7px;font-size:13px}.menu button:hover{background:var(--bg-elev)}.menu button.danger{color:var(--red)}.menu-sep{height:1px;background:var(--border-soft);margin:4px 6px}.header{display:flex;align-items:center;gap:12px;padding:9px 14px;border-bottom:1px solid var(--border);background:var(--bg-elev);min-height:52px}.header-left{display:flex;align-items:center;gap:8px;min-width:0;flex:1}.header-title{display:flex;flex-direction:column;min-width:0}.header-title-text{font-weight:600;font-size:14px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.header-title-btn{appearance:none;border:0;background:none;padding:0;margin:0;color:inherit;font:inherit;text-align:left;cursor:text;max-width:42vw}.header-title-btn:hover{text-decoration:underline dotted;text-decoration-color:var(--text-faint);text-underline-offset:3px}.header-title-input{font-weight:600;font-size:14px;font-family:inherit;color:var(--text);background:var(--bg);border:1px solid var(--accent);border-radius:7px;padding:1px 6px;outline:none;max-width:42vw;min-width:14ch}.header-cwd{font-size:11.5px;color:var(--text-faint);font-family:var(--mono);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:42vw}.header-right{display:flex;align-items:center;gap:8px}.inline-select select,.popover select,.popover .text-input{border:1px solid var(--border);background:var(--bg);border-radius:8px;padding:5px 8px;font-size:12.5px;outline:none;max-width:190px}.inline-select select:focus,.popover select:focus,.text-input:focus{border-color:var(--accent)}.popover-wrap{position:relative}.theme-grid{display:grid;grid-template-columns:1fr 1fr;gap:6px}.theme-option{display:flex;align-items:center;gap:8px;padding:6px 7px;border:1px solid var(--border);border-radius:9px;background:var(--bg);color:var(--text-dim);font-size:12.5px;text-align:left}.theme-option:hover{border-color:var(--text-faint);color:var(--text)}.theme-option.active{border-color:var(--accent);background:var(--accent-soft);color:var(--accent-strong);font-weight:600}.theme-swatch{position:relative;width:20px;height:20px;flex:0 0 20px;border-radius:6px;border:1.5px solid;overflow:hidden}.theme-swatch i{position:absolute;left:0;bottom:0;width:100%;height:44%}.theme-option-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.project-picker{position:relative}.project-btn{display:flex;align-items:center;gap:8px;width:100%;padding:7px 10px;border:1px solid var(--border);border-radius:10px;background:var(--bg);color:var(--text);font-size:13px;text-align:left}.project-btn:hover{border-color:var(--text-faint)}.project-btn.open{border-color:var(--accent)}.project-btn-path{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.project-btn .project-dot{width:9px;height:9px;border-radius:50%;background:var(--accent)}.project-btn .project-dot.busy{animation:project-pulse 1s ease-in-out infinite}@keyframes project-pulse{0%,to{opacity:.35}50%{opacity:1}}.project-menu{position:absolute;top:calc(100% + 6px);left:0;right:0;z-index:60;background:var(--bg-elev);border:1px solid var(--border);border-radius:12px;box-shadow:var(--shadow);padding:6px;display:flex;flex-direction:column;gap:4px}.project-filter{display:flex;align-items:center;gap:7px;padding:6px 8px;border:1px solid var(--border);border-radius:8px;color:var(--text-faint)}.project-filter:focus-within{border-color:var(--accent)}.project-filter input{flex:1;min-width:0;border:none;background:transparent;outline:none;color:var(--text);font-size:12.5px}.project-list{max-height:47vh;overflow-y:auto;display:flex;flex-direction:column}.project-item{display:flex;align-items:center;gap:8px;width:100%;padding:7px 8px;border:none;border-radius:8px;background:transparent;color:var(--text-dim);font-size:13px;text-align:left}.project-item:hover:not(:disabled){background:var(--bg-elev2);color:var(--text)}.project-item.active{color:var(--accent-strong);font-weight:600}.project-item:disabled{opacity:.45}.project-check{display:flex;align-items:center;justify-content:center;width:14px;flex:0 0 14px;color:var(--accent)}.project-item-path{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.project-count{display:inline-flex;align-items:center;gap:5px;font-size:12px;color:var(--text-faint);flex:0 0 auto}.project-count.active{color:var(--accent-strong)}.project-item .project-dot{width:7px;height:7px;border-radius:50%;background:var(--text-faint)}.project-count.active .project-dot{background:var(--accent)}.project-empty{padding:10px 8px}.project-footer{border-top:1px solid var(--border-soft);padding-top:4px;display:flex;flex-direction:column}.project-custom{display:flex;flex-direction:column;gap:8px;padding:4px}.project-custom .text-input{width:100%;max-width:none}.project-custom-actions{display:flex;justify-content:flex-end;gap:6px}.popover{position:absolute;top:calc(100% + 8px);right:0;z-index:60;width:320px;background:var(--bg-elev2);border:1px solid var(--border);border-radius:12px;box-shadow:var(--shadow);padding:14px;display:flex;flex-direction:column;gap:14px}.popover-section{display:flex;flex-direction:column;gap:6px}.popover-title{font-size:12px;font-weight:600;color:var(--text-dim);text-transform:uppercase;letter-spacing:.04em}.text-input{width:100%;padding:7px 9px;border:1px solid var(--border);background:var(--bg);border-radius:8px;outline:none;font-size:12.5px;font-family:var(--mono)}.hint{font-size:11.5px;color:var(--text-faint)}.path-static{padding:5px 8px;border:1px solid var(--border);border-radius:8px;background:var(--bg);color:var(--text-dim);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.hint.block{display:block;margin-top:2px}.toggle-row{display:flex;gap:10px;align-items:flex-start;font-size:13px;cursor:pointer}.toggle-row input{margin-top:2px;accent-color:var(--accent)}.popover-actions{display:flex;gap:8px;border-top:1px solid var(--border-soft);padding-top:12px}.status-pill{display:inline-flex;align-items:center;gap:6px;padding:4px 9px;border-radius:999px;border:1px solid var(--border);background:var(--bg);font-size:12px;color:var(--text-dim);white-space:nowrap}.status-pill .status-dot{width:7px;height:7px;flex-basis:7px}.pill-ready .status-dot{background:var(--green)}.pill-ready{color:var(--green);border-color:var(--green-soft)}.pill-warn .status-dot{background:var(--amber)}.pill-warn{color:var(--amber)}.pill-error .status-dot,.pill-offline .status-dot{background:var(--red)}.pill-error,.pill-offline{color:var(--red)}.pill-unknown .status-dot{background:var(--text-faint)}.token-meter{display:flex;align-items:center;gap:7px;padding:3px 8px;border:1px solid var(--border);border-radius:999px;background:var(--bg)}.token-bar{width:56px;height:5px;border-radius:3px;background:var(--bg-elev2);overflow:hidden}.token-fill{height:100%;background:var(--blue);border-radius:3px;transition:width .3s ease}.token-meter.warm .token-fill{background:var(--amber)}.token-meter.hot .token-fill{background:var(--red)}.token-label{font-size:11px;color:var(--text-dim);font-variant-numeric:tabular-nums}.chat-wrap,.chat{flex:1;min-height:0;position:relative}.chat{overflow-y:auto;padding:20px 0 8px;scroll-behavior:auto}.chat-wrap{display:flex;flex-direction:column}.chat>.turn,.chat>.inline-error,.chat>.empty-state{max-width:none;margin:0;padding-left:10px;padding-right:10px}.chat-bottom-pad{height:20px}.jump-bottom{position:absolute;bottom:16px;left:50%;transform:translate(-50%);width:34px;height:34px;border-radius:50%;border:1px solid var(--border);background:var(--bg-elev2);color:var(--text);box-shadow:var(--shadow-soft);display:flex;align-items:center;justify-content:center;z-index:10}.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;text-align:center;padding:80px 24px;color:var(--text-dim)}.empty-state.compact{padding:60px 24px}.empty-state h2{margin:0;color:var(--text);font-size:20px;letter-spacing:-.01em}.empty-mark{display:flex;width:58px;height:58px;align-items:center;justify-content:center;border-radius:16px;background:linear-gradient(135deg,var(--accent-strong),var(--accent));color:#fff;box-shadow:var(--shadow-soft)}.empty-state code{font-family:var(--mono);background:var(--bg-elev2);padding:1px 5px;border-radius:5px}.inline-error{display:flex;align-items:flex-start;gap:8px;margin-top:10px;padding:10px 12px;border-radius:10px;border:1px solid var(--red);background:var(--red-soft);color:var(--red);font-size:13px}.connection-banner{display:flex;align-items:center;gap:10px;padding:8px 14px;background:var(--amber-soft);border-bottom:1px solid var(--amber);color:var(--amber);font-size:13px}.connection-banner .btn{margin-left:auto;color:var(--text)}.turn{padding-top:10px}.turn-divider{display:flex;align-items:center;gap:8px;margin:10px 0 4px}.turn-status-dot{width:7px;height:7px;border-radius:50%;background:var(--text-faint)}.turn-status-dot.inProgress{background:var(--green);animation:pulse 1.6s infinite}.turn-status-dot.failed{background:var(--red)}.turn-status-dot.interrupted{background:var(--amber)}.turn-meta{font-size:11.5px;color:var(--text-faint);text-transform:uppercase;letter-spacing:.05em}.turn-items{display:flex;flex-direction:column;gap:10px}.turn-details{margin-top:2px}.turn-details-summary{display:flex;align-items:center;gap:7px;min-width:0;color:var(--text-dim);font-size:12.5px}.turn-details-label{font-weight:600;color:var(--text)}.turn-details-count{color:var(--text-faint);white-space:nowrap}.turn-details-items{display:flex;flex-direction:column;gap:10px}.item{position:relative}.item-user{display:flex;gap:10px;justify-content:flex-end}.user-avatar{order:2;display:flex;width:26px;height:26px;flex:0 0 26px;align-items:center;justify-content:center;border-radius:8px;background:var(--bg-elev2);color:var(--text-dim)}.user-bubble{order:1;max-width:82%;background:var(--user-bg);border:1px solid var(--border-soft);border-radius:12px 12px 4px;padding:9px 12px;display:flex;flex-direction:column;gap:8px}.user-text{white-space:pre-wrap;word-break:break-word}.user-image img,.generated-image{max-width:100%;border-radius:8px;border:1px solid var(--border)}.input-chip{display:inline-flex;align-items:center;gap:6px;font-size:12px;background:var(--bg);border:1px solid var(--border);border-radius:999px;padding:3px 9px;color:var(--text-dim);max-width:100%}.input-chip span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.input-chip.clickable:hover{border-color:var(--accent);color:var(--accent-strong)}.item-agent{display:flex;gap:10px}.agent-avatar{display:flex;width:26px;height:26px;flex:0 0 26px;align-items:center;justify-content:center;border-radius:8px;background:var(--accent-soft);color:var(--accent-strong)}.agent-body{flex:1;min-width:0}.agent-toolbar{display:flex;align-items:center;gap:8px;margin-bottom:2px;opacity:.9}.agent-toolbar .icon-btn{opacity:0;width:24px;height:24px}.item-agent:hover .agent-toolbar .icon-btn{opacity:1}.phase-badge{font-size:10.5px;text-transform:uppercase;letter-spacing:.05em;color:var(--text-faint);border:1px solid var(--border);border-radius:999px;padding:1px 7px}.typing{display:inline-flex;gap:4px;align-items:center;padding:4px 0}.typing .dot{width:6px;height:6px;border-radius:50%;background:var(--text-faint);animation:blink 1.2s infinite}.typing .dot:nth-child(2){animation-delay:.2s}.typing .dot:nth-child(3){animation-delay:.4s}@keyframes blink{0%,to{opacity:.3}50%{opacity:1}}.caret{display:inline-block;width:7px;height:15px;margin-left:2px;background:var(--accent);vertical-align:text-bottom;animation:blink 1s steps(2) infinite}.agent-questions{margin-top:8px;display:flex;flex-direction:column;gap:6px}.agent-question{border:1px solid var(--border);border-radius:9px;padding:8px 10px;background:var(--bg-elev)}.agent-question-title{display:flex;align-items:center;gap:6px;font-size:12.5px;font-weight:600}.agent-question-options{display:flex;flex-wrap:wrap;gap:6px;margin-top:6px}.disclosure{border:1px solid var(--border-soft);border-radius:11px;background:var(--bg-elev);overflow:hidden}.disclosure-head{display:flex;align-items:center}.disclosure-toggle{flex:1;min-width:0;display:flex;align-items:center;gap:6px;border:none;background:transparent;color:var(--text);text-align:left;padding:9px 11px;font-size:13px}.disclosure-toggle:hover{background:var(--bg-elev2)}.disclosure-caret{display:inline-flex;color:var(--text-faint)}.disclosure-summary{flex:1;min-width:0;display:flex;align-items:center;gap:8px}.disclosure-actions{display:flex;align-items:center;gap:4px;padding-right:8px}.disclosure-body{padding:0 11px 11px}.item-reasoning .disclosure{background:transparent;border-style:dashed}.reasoning-summary{display:flex;align-items:center;gap:8px;color:var(--text-dim);font-size:12.5px;min-width:0}.reasoning-label{font-style:italic}.reasoning-preview{color:var(--text-faint);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-style:italic}.reasoning-content{display:flex;flex-direction:column;gap:10px;color:var(--text-dim);font-size:13px}.reasoning-block p{margin:0 0 8px;white-space:pre-wrap}.reasoning-raw{border-left:2px solid var(--border);padding-left:10px;font-size:12.5px}.command-summary{display:flex;align-items:center;gap:9px;min-width:0;flex:1}.command-text{font-family:var(--mono);font-size:12.5px;white-space:pre-wrap;overflow-wrap:anywhere;background:var(--code-bg);padding:2px 7px;border-radius:6px;border:1px solid var(--code-border)}.command-actions{display:flex;gap:6px;flex-wrap:wrap}.command-action{display:inline-flex;align-items:center;gap:4px;font-size:11px;color:var(--text-faint)}.command-meta{display:flex;align-items:center;gap:6px}.command-body{display:flex;flex-direction:column;gap:6px}.command-cwd{display:flex;align-items:center;gap:6px;font-size:11.5px;color:var(--text-faint);font-family:var(--mono);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.command-output{margin:0;max-height:340px;overflow:auto;background:var(--code-bg);border:1px solid var(--code-border);border-radius:8px;padding:10px 12px;font-family:var(--mono);font-size:12px;line-height:1.5;white-space:pre-wrap;word-break:break-word}.filechange-summary{display:flex;align-items:center;gap:9px}.filechange-title{font-weight:500}.filechange-body{display:flex;flex-direction:column;gap:12px}.file-change-head{display:flex;align-items:center;gap:8px;flex-wrap:wrap}.file-change-path{font-family:var(--mono);font-size:12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0}.file-change-move{font-size:11.5px;color:var(--text-faint)}.badge{display:inline-flex;align-items:center;gap:4px;font-size:10.5px;font-weight:600;padding:1px 7px;border-radius:999px;border:1px solid var(--border);color:var(--text-dim);white-space:nowrap}.badge-success,.kind-add{background:var(--green-soft);color:var(--green);border-color:var(--green)}.badge-error,.kind-del{background:var(--red-soft);color:var(--red);border-color:var(--red)}.badge-warn{background:var(--amber-soft);color:var(--amber);border-color:var(--amber)}.kind-update{background:var(--blue-soft);color:var(--blue);border-color:var(--blue)}.badge-running{background:var(--accent-soft);color:var(--accent-strong);border-color:var(--accent)}.chip{display:inline-flex;align-items:center;gap:5px;font-size:11.5px;background:var(--bg);border:1px solid var(--border);border-radius:999px;padding:2px 8px;color:var(--text-dim)}.chip.tiny{font-size:10.5px;padding:1px 6px}.path-chip{font-family:var(--mono);font-size:11.5px;background:var(--bg);border:1px solid var(--border);border-radius:6px;padding:1px 6px;color:var(--text-dim);max-width:320px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tool-summary{display:flex;align-items:center;gap:9px;min-width:0;flex:1}.tool-name{display:inline-flex;align-items:center;gap:6px;font-family:var(--mono);font-size:12.5px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.tool-sep{color:var(--text-faint)}.tool-body{display:flex;flex-direction:column;gap:12px}.tool-section{display:flex;flex-direction:column;gap:5px}.tool-section-title{font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--text-faint)}.item-generic .disclosure,.item-tool .disclosure,.item-websearch .disclosure,.item-collab .disclosure{background:var(--bg-elev)}.item-head{display:flex;align-items:center;gap:8px;padding:2px 0}.item-icon{display:inline-flex;color:var(--text-dim)}.item-icon-error{color:var(--red)}.item-title{font-weight:500;font-size:13px}.item-subtitle{color:var(--text-faint);font-size:12px}.item-function-output{border:1px solid var(--border-soft);border-radius:10px;padding:9px 11px;background:var(--bg-elev);display:flex;flex-direction:column;gap:8px}.code-block{margin:0;background:var(--code-bg);border:1px solid var(--code-border);border-radius:8px;padding:10px 12px;font-family:var(--mono);font-size:12px;line-height:1.5;overflow:auto;max-height:300px;white-space:pre-wrap;word-break:break-word}.code-block.small{font-size:11.5px;padding:8px 10px}.code-block.max-h{max-height:360px}.item-error-card{border:1px solid var(--red);border-radius:10px;padding:10px 12px;background:var(--red-soft)}.item-plan{border:1px solid var(--border-soft);border-radius:11px;background:var(--bg-elev);padding:11px 13px}.plan-explanation{font-size:12.5px;margin:4px 0 8px}.plan-steps{list-style:none;margin:6px 0 0;padding:0;display:flex;flex-direction:column;gap:6px}.plan-step{display:flex;align-items:flex-start;gap:8px;font-size:13px;color:var(--text-dim)}.plan-step-icon{display:inline-flex;margin-top:2px}.plan-step.status-completed .plan-step-text{text-decoration:line-through;color:var(--text-faint)}.plan-step.status-completed .plan-step-icon{color:var(--green)}.plan-step.status-inProgress .plan-step-icon{color:var(--accent)}.plan-step.status-inProgress .plan-step-text{color:var(--text)}.item-compaction,.item-sleep,.item-subagent{display:flex;align-items:center;gap:8px;color:var(--text-faint);font-size:12.5px}.compaction-line{display:flex;align-items:center;gap:8px;width:100%}.compaction-line:before,.compaction-line:after{content:"";flex:1;height:1px;background:var(--border-soft)}.item-imageview{display:inline-flex;align-items:center;gap:8px;border:1px solid var(--border);background:var(--bg-elev);border-radius:9px;padding:7px 10px;color:var(--text)}.item-imageview:hover{border-color:var(--accent)}.item-imagegen{border:1px solid var(--border-soft);border-radius:11px;background:var(--bg-elev);padding:11px;display:flex;flex-direction:column;gap:8px}.item-review{border:1px solid var(--amber);background:var(--amber-soft);border-radius:10px;padding:10px 12px}.review-line{display:flex;align-items:center;gap:8px;color:var(--amber);font-size:12.5px;font-weight:600}.markdown{overflow-wrap:anywhere}.markdown>*:first-child{margin-top:0}.markdown>*:last-child{margin-bottom:0}.markdown p{margin:0 0 10px}.markdown h1,.markdown h2,.markdown h3,.markdown h4{margin:16px 0 8px;line-height:1.3}.markdown h1{font-size:19px}.markdown h2{font-size:17px}.markdown h3{font-size:15px}.markdown ul,.markdown ol{margin:0 0 10px;padding-left:22px}.markdown li{margin:2px 0}.markdown a{color:var(--accent-strong);text-decoration:none}.markdown a:hover{text-decoration:underline}.md-file-link{border:none;background:var(--accent-soft);color:var(--accent-strong);border-radius:5px;padding:0 4px;font-family:var(--mono);font-size:12.5px}.md-file-link:hover{text-decoration:underline}.markdown code{font-family:var(--mono);font-size:12.5px;background:var(--code-bg);border:1px solid var(--code-border);border-radius:5px;padding:1px 5px}.markdown pre{margin:0;background:var(--code-bg);border:1px solid var(--code-border);border-radius:9px;padding:11px 13px;overflow:auto;max-height:420px}.markdown pre code{background:transparent;border:none;padding:0;font-size:12px;line-height:1.55}.md-pre-wrap{position:relative;margin:0 0 10px}.md-pre-bar{position:absolute;top:6px;right:8px;z-index:2;opacity:0;transition:opacity .12s ease}.md-pre-wrap:hover .md-pre-bar{opacity:1}.markdown blockquote{margin:0 0 10px;padding:2px 0 2px 12px;border-left:3px solid var(--border);color:var(--text-dim)}.markdown table{border-collapse:collapse;margin:0 0 10px;font-size:13px;display:block;overflow-x:auto}.markdown th,.markdown td{border:1px solid var(--border);padding:5px 9px;text-align:left}.markdown th{background:var(--bg-elev2)}.markdown img{max-width:100%;border-radius:8px}.markdown hr{border:none;border-top:1px solid var(--border);margin:16px 0}.hljs{color:var(--text)}.hljs-comment,.hljs-quote{color:var(--text-faint);font-style:italic}.hljs-keyword,.hljs-selector-tag,.hljs-doctag,.hljs-formula{color:#c084fc}.hljs-string,.hljs-regexp,.hljs-addition,.hljs-attribute,.hljs-meta .hljs-string{color:#3ecf8e}.hljs-number,.hljs-literal,.hljs-variable,.hljs-template-variable,.hljs-type,.hljs-selector-attr,.hljs-selector-pseudo{color:#f0b429}.hljs-title,.hljs-title.function_,.hljs-section,.hljs-name{color:#4c8dff}.hljs-attr,.hljs-selector-class,.hljs-selector-id,.hljs-property{color:#7db8ff}.hljs-built_in,.hljs-symbol,.hljs-bullet,.hljs-link{color:#f16a6a}.hljs-deletion{color:var(--red)}.hljs-addition{color:var(--green)}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}[data-scheme=light] .hljs-comment,[data-scheme=light] .hljs-quote{color:#6e7781}[data-scheme=light] .hljs-keyword,[data-scheme=light] .hljs-selector-tag,[data-scheme=light] .hljs-doctag,[data-scheme=light] .hljs-template-tag,[data-scheme=light] .hljs-template-variable,[data-scheme=light] .hljs-type{color:#cf222e}[data-scheme=light] .hljs-title,[data-scheme=light] .hljs-title.class_,[data-scheme=light] .hljs-title.function_,[data-scheme=light] .hljs-section{color:#8250df}[data-scheme=light] .hljs-attr,[data-scheme=light] .hljs-attribute,[data-scheme=light] .hljs-literal,[data-scheme=light] .hljs-meta,[data-scheme=light] .hljs-number,[data-scheme=light] .hljs-operator,[data-scheme=light] .hljs-variable,[data-scheme=light] .hljs-selector-attr,[data-scheme=light] .hljs-selector-class,[data-scheme=light] .hljs-selector-id,[data-scheme=light] .hljs-property{color:#0550ae}[data-scheme=light] .hljs-regexp,[data-scheme=light] .hljs-string,[data-scheme=light] .hljs-meta .hljs-string{color:#0a3069}[data-scheme=light] .hljs-built_in,[data-scheme=light] .hljs-symbol,[data-scheme=light] .hljs-bullet,[data-scheme=light] .hljs-link{color:#953800}[data-scheme=light] .hljs-name,[data-scheme=light] .hljs-selector-pseudo,[data-scheme=light] .hljs-title.class_.inherited__{color:#116329}[data-scheme=light] .hljs-subst{color:#1f2328}[data-scheme=light] .hljs-addition{color:#116329;background:#dafbe1}[data-scheme=light] .hljs-deletion{color:#82071e;background:#ffebe9}.diff-view{display:flex;flex-direction:column;gap:12px}.diff-file{border:1px solid var(--code-border);border-radius:9px;overflow:hidden}.diff-file-head{display:flex;align-items:center;gap:10px;padding:6px 10px;background:var(--bg-elev2);border-bottom:1px solid var(--code-border)}.diff-file-path{font-family:var(--mono);font-size:12px;flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.diff-stats{display:flex;gap:8px;font-size:11.5px;font-family:var(--mono)}.diff-stats .add{color:var(--green)}.diff-stats .del{color:var(--red)}.diff-body{margin:0;overflow-x:auto;background:var(--code-bg);font-family:var(--mono);font-size:11.5px;line-height:1.5;padding:4px 0}.diff-line{display:flex;gap:8px;padding:0 10px;white-space:pre}.diff-line.add{background:var(--green-soft)}.diff-line.del{background:var(--red-soft)}.diff-line.hunk{color:var(--blue);background:var(--blue-soft)}.diff-line.meta{color:var(--text-faint)}.diff-no{width:38px;flex:0 0 38px;text-align:right;color:var(--text-faint);user-select:none}.diff-sign{width:10px;flex:0 0 10px}.diff-code{flex:1}.diff-view-actions{display:flex;justify-content:flex-end}.diff-empty{padding:8px;font-size:12.5px}.turn-diff{margin-top:8px}.turn-diff-summary{display:inline-flex;align-items:center;gap:7px;font-weight:500}.composer-wrap{border-top:1px solid var(--border);background:var(--bg-elev);padding:10px 10px 12px}.composer{margin:0;border:1px solid var(--border);border-radius:13px;background:var(--bg);padding:5px 9px;box-shadow:var(--shadow-soft)}.composer:focus-within{border-color:var(--accent)}.composer-row{display:flex;align-items:center;gap:8px}.composer-input{position:relative;flex:1;min-width:0}.composer textarea{display:block;width:100%;resize:none;border:none;background:transparent;outline:none;font-size:14px;line-height:21px;padding:5px 0;max-height:200px;font-family:var(--sans)}.composer-actions{display:flex;align-items:center;gap:8px;flex:0 0 auto}.composer-actions .btn{padding:6px 12px}.composer-hint{display:flex;gap:12px;margin:6px 0 0;font-size:11.5px}.running-hint{margin-left:auto;color:var(--accent-strong)}.attach-row{display:flex;flex-wrap:wrap;gap:6px;padding:2px 2px 6px}.attach-chip{display:inline-flex;align-items:center;gap:6px;font-size:12px;background:var(--bg-elev2);border:1px solid var(--border);border-radius:8px;padding:3px 6px;max-width:260px}.attach-chip.image img{width:26px;height:26px;object-fit:cover;border-radius:5px}.attach-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.chip-x{display:inline-flex;align-items:center;justify-content:center;border:none;background:transparent;color:var(--text-faint);padding:1px;border-radius:4px}.chip-x:hover{color:var(--red)}.queue-bar{margin:0 0 8px;display:flex;align-items:center;gap:8px;font-size:12px;color:var(--accent-strong)}.mention-menu{position:absolute;bottom:calc(100% + 6px);left:0;right:0;z-index:50;background:var(--bg-elev2);border:1px solid var(--border);border-radius:10px;box-shadow:var(--shadow);max-height:260px;overflow-y:auto;padding:4px}.mention-item{display:flex;flex-direction:column;width:100%;border:none;background:transparent;color:var(--text);text-align:left;padding:6px 9px;border-radius:7px}.mention-item.active,.mention-item:hover{background:var(--accent-soft)}.mention-name{font-size:13px;font-family:var(--mono)}.mention-path{font-size:11px;color:var(--text-faint);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.modal-backdrop{position:fixed;inset:0;background:#00000080;display:flex;align-items:center;justify-content:center;z-index:100;padding:20px;backdrop-filter:blur(2px)}.modal{width:100%;background:var(--bg-elev);border:1px solid var(--border);border-radius:14px;box-shadow:var(--shadow);display:flex;flex-direction:column;max-height:86vh;overflow:hidden}.modal-head{display:flex;align-items:center;justify-content:space-between;padding:12px 14px;border-bottom:1px solid var(--border-soft)}.modal-title{font-weight:600}.modal-body{padding:14px;overflow-y:auto;display:flex;flex-direction:column;gap:10px}.modal-foot{display:flex;justify-content:flex-end;gap:8px;padding:12px 14px;border-top:1px solid var(--border-soft);flex-wrap:wrap}.modal-body .modal-foot{padding:12px 0 0}.approval-title{display:inline-flex;align-items:center;gap:8px;color:var(--amber)}.approval-method{font-family:var(--mono)}.approval-reason{margin:0}.approval-command{display:flex;align-items:flex-start;gap:8px;background:var(--code-bg);border:1px solid var(--code-border);border-radius:8px;padding:9px 11px}.approval-command code{font-family:var(--mono);font-size:12.5px;white-space:pre-wrap;word-break:break-word}.approval-cwd{display:flex;align-items:center;gap:6px;font-size:12px;color:var(--text-faint);font-family:var(--mono)}.approval-actions{display:flex;flex-wrap:wrap;gap:6px}.question-form{display:flex;flex-direction:column;gap:14px}.question{display:flex;flex-direction:column;gap:7px}.question-head{font-weight:600;font-size:13px}.question-text{font-size:13px;color:var(--text-dim)}.question-options{display:flex;flex-direction:column;gap:6px}.question-option{display:flex;gap:9px;align-items:flex-start;border:1px solid var(--border);border-radius:8px;padding:7px 9px;cursor:pointer}.question-option:hover{background:var(--bg-elev2)}.question-option input{margin-top:2px;accent-color:var(--accent)}.option-label{display:block;font-size:13px}.option-desc{display:block;font-size:11.5px}.file-panel{position:relative;width:var(--file-panel-w, 560px);border-left:1px solid var(--border);background:var(--bg-elev);display:flex;flex-direction:column;height:100%;z-index:20}.file-panel.dragging{border-left-color:var(--accent)}.file-panel-head{display:flex;align-items:center;gap:8px;padding:9px 12px;border-bottom:1px solid var(--border);min-height:50px}.file-panel-title{display:flex;flex-direction:column;min-width:0;flex:1}.file-name{font-weight:600;font-size:13px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.file-dir{font-size:11px;color:var(--text-faint);font-family:var(--mono);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.file-panel-actions{display:flex;align-items:center;gap:2px}.file-tree{border-bottom:1px solid var(--border);max-height:40%;display:flex;flex-direction:column}.file-tree-head{display:flex;align-items:center;justify-content:space-between;padding:6px 10px;border-bottom:1px solid var(--border-soft)}.file-tree-body{overflow:auto;padding:4px 0 8px}.tree-row{display:flex;align-items:center;gap:6px;width:100%;border:none;background:transparent;color:var(--text);text-align:left;padding:4px 8px;font-size:12.5px}.tree-row:hover{background:var(--bg-elev2)}.tree-row.selected{background:var(--accent-soft);color:var(--accent-strong)}.tree-caret{display:inline-flex;width:12px;color:var(--text-faint)}.tree-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-family:var(--mono)}.tree-loading{padding:2px 8px 2px 30px;font-size:11.5px}.file-content{flex:1;overflow:auto}.file-truncated{padding:6px 12px;background:var(--amber-soft);color:var(--amber)}.file-code{margin:0;padding:14px;font-family:var(--mono);font-size:12.5px;line-height:1.55;background:transparent;white-space:pre}.file-code code{display:block}.toasts{position:fixed;bottom:18px;right:18px;display:flex;flex-direction:column;gap:8px;z-index:200;max-width:380px}.toast{display:flex;align-items:flex-start;gap:9px;background:var(--bg-elev2);border:1px solid var(--border);border-radius:10px;box-shadow:var(--shadow);padding:10px 12px;font-size:13px;animation:toast-in .2s ease}@keyframes toast-in{0%{opacity:0;transform:translateY(6px)}}.toast-error{border-color:var(--red)}.toast-error .toast-icon{color:var(--red)}.toast-success .toast-icon{color:var(--green)}.toast-msg{flex:1;word-break:break-word}.drawer-backdrop{position:fixed;inset:0;background:#00000073;z-index:120;display:flex;align-items:flex-end;justify-content:center}.drawer{width:100%;max-width:900px;height:60vh;background:var(--bg-elev);border:1px solid var(--border);border-bottom:none;border-radius:14px 14px 0 0;display:flex;flex-direction:column;box-shadow:var(--shadow)}.drawer-head{display:flex;align-items:center;gap:10px;padding:11px 14px;border-bottom:1px solid var(--border-soft);font-weight:600}.drawer-body{margin:0;padding:12px 14px;overflow:auto;font-family:var(--mono);font-size:11.5px;line-height:1.5;white-space:pre-wrap;flex:1}.session-log-drawer{width:min(1180px,calc(100vw - 28px));height:min(84vh,900px);background:var(--bg-elev);border:1px solid var(--border);border-radius:14px;display:flex;flex-direction:column;box-shadow:var(--shadow);overflow:hidden}.session-log-head{flex:0 0 auto}.session-log-layout{min-height:0;flex:1;display:grid;grid-template-columns:minmax(340px,.9fr) minmax(0,1.4fr)}.session-log-list{min-width:0;overflow:auto;border-right:1px solid var(--border-soft);padding:10px}.session-log-list-title{padding:2px 4px 8px;font-size:11px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--text-faint)}.session-log-group{border:1px solid var(--border-soft);border-radius:9px;overflow:hidden;margin-bottom:8px}.session-log-group.open{border-color:var(--border)}.session-log-group-head{width:100%;display:flex;align-items:flex-start;gap:7px;padding:9px;border:0;border-radius:0;background:var(--bg);text-align:left}.session-log-group-head:hover{background:var(--bg-elev2)}.session-log-caret{color:var(--text-faint);padding-top:1px}.session-log-group-main{min-width:0;flex:1;display:flex;flex-direction:column;gap:3px}.session-log-group-main strong,.session-log-group-main span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.session-log-group-main strong{font-size:12.5px}.session-log-group-main span{font-size:11.5px;color:var(--text-dim)}.session-log-group-stats{flex:0 0 auto;display:flex;align-items:flex-end;flex-direction:column;gap:2px;font-size:10.5px;color:var(--text-faint);white-space:nowrap}.session-log-group-rows{border-top:1px solid var(--border-soft);background:var(--bg-inset)}.session-log-row{width:100%;display:grid;grid-template-columns:30px 62px 54px minmax(70px,120px) auto;align-items:center;gap:6px;padding:7px 9px;border:0;border-bottom:1px solid var(--border-soft);border-radius:0;background:transparent;text-align:left;font-size:10.5px;color:var(--text-dim)}.session-log-row:last-child{border-bottom:0}.session-log-row:hover,.session-log-row.selected{background:var(--accent-soft);color:var(--text)}.session-log-row-index{color:var(--text-faint)}.session-log-row-model,.session-log-row-preview{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.session-log-detail{min-width:0;display:flex;flex-direction:column;background:var(--bg)}.session-log-detail-head{display:flex;align-items:center;gap:8px;padding:11px 14px 8px;border-bottom:1px solid var(--border-soft)}.session-log-tabs{display:flex;gap:5px;padding:8px 14px;border-bottom:1px solid var(--border-soft);overflow-x:auto}.session-log-tabs .btn.active{background:var(--accent-soft);border-color:var(--accent);color:var(--accent-strong)}.session-log-detail-body{min-height:0;flex:1;overflow:auto;padding:12px 14px}.session-log-section{margin-bottom:14px}.session-log-section h3{margin:0 0 6px;font-size:11px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;color:var(--text-faint)}.session-log-box{background:var(--bg-inset);border:1px solid var(--border-soft);border-radius:8px}.session-log-text{padding:9px 10px;white-space:pre-wrap;word-break:break-word;font-size:12.5px}.session-log-code{margin:0 0 14px;padding:10px;max-height:58vh;overflow:auto;background:var(--code-bg);border:1px solid var(--code-border);border-radius:8px;font-family:var(--mono);font-size:11px;line-height:1.5;white-space:pre-wrap;word-break:break-word}.session-log-code.compact{max-height:30vh}.log-status{font-size:10px;line-height:1.2;padding:2px 6px;border:1px solid var(--border);border-radius:999px;white-space:nowrap}.log-status.ok{color:var(--green);border-color:var(--green)}.log-status.bad{color:var(--red);border-color:var(--red)}.log-status.live{color:var(--amber);border-color:var(--amber)}.session-log-empty{padding:24px 10px;color:var(--text-dim);font-size:12px;line-height:1.6}.drawer-scrim{display:none}@media(max-width:900px){.file-panel{position:fixed;right:0;top:0;bottom:0;width:min(92vw,640px)}}@media(max-width:768px){.sidebar-container{position:fixed;top:0;bottom:0;left:0;width:min(86vw,320px);flex:0 0 auto;transform:translate(-100%);transition:transform .2s ease;box-shadow:var(--shadow)}.sidebar-container.open{transform:translate(0)}.sidebar-rail,.sidebar-container>.resize-handle{display:none}.drawer-scrim{display:block;position:fixed;inset:0;background:#00000080;z-index:25}.session-log-drawer{width:calc(100vw - 12px);height:calc(100vh - 12px);border-radius:12px}.session-log-layout{display:flex;flex-direction:column}.session-log-list{flex:0 0 42%;border-right:0;border-bottom:1px solid var(--border-soft)}.session-log-detail{flex:1}.header-cwd{max-width:32vw}.inline-select{display:none}.composer-wrap{padding:10px 10px 12px}.chat>.turn,.chat>.inline-error,.chat>.empty-state{padding-left:12px;padding-right:12px}.token-meter .token-label{display:none}}