pi-web-ui 0.63.4 → 0.64.1

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.
@@ -47,8 +47,8 @@ export function resolveCommandCwd(cwd, pwd) {
47
47
  /** Read the command list; missing file → empty list; malformed → empty list + warning text. */
48
48
  export async function loadCommands(workspaceRoot) {
49
49
  const path = commandsFilePath(workspaceRoot);
50
- const { commands, warning } = await readCommandsFile(path);
51
- return { commands, path, warning };
50
+ const { commands, warning, warningEn } = await readCommandsFile(path);
51
+ return { commands, path, warning, warningEn };
52
52
  }
53
53
  async function readCommandsFile(path) {
54
54
  if (!existsSync(path))
@@ -61,6 +61,7 @@ async function readCommandsFile(path) {
61
61
  return {
62
62
  commands: [],
63
63
  warning: `读取命令文件失败:${err.message}`,
64
+ warningEn: `Failed to read commands file: ${err.message}`,
64
65
  };
65
66
  }
66
67
  let parsed;
@@ -68,7 +69,11 @@ async function readCommandsFile(path) {
68
69
  parsed = JSON.parse(raw);
69
70
  }
70
71
  catch {
71
- return { commands: [], warning: `命令文件不是有效 JSON:${path}` };
72
+ return {
73
+ commands: [],
74
+ warning: `命令文件不是有效 JSON:${path}`,
75
+ warningEn: `Commands file is not valid JSON: ${path}`,
76
+ };
72
77
  }
73
78
  if (Array.isArray(parsed)) {
74
79
  // Tolerate a bare array: [{name, command, cwd}]
@@ -92,7 +97,7 @@ async function readCommandsFile(path) {
92
97
  .map((c) => ({ name: c.name, command: c.command, cwd: c.cwd })),
93
98
  };
94
99
  }
95
- return { commands: [], warning: `命令文件格式不正确:${path}` };
100
+ return { commands: [], warning: `命令文件格式不正确:${path}`, warningEn: `Commands file has a bad format: ${path}` };
96
101
  }
97
102
  /** Persist the command list, creating .pi/ if needed. */
98
103
  export async function saveCommandsFile(workspaceRoot, commands) {
@@ -104,7 +109,11 @@ export async function saveCommandsFile(workspaceRoot, commands) {
104
109
  return { path };
105
110
  }
106
111
  catch (err) {
107
- return { path, error: `保存命令文件失败:${err.message}` };
112
+ return {
113
+ path,
114
+ error: `保存命令文件失败:${err.message}`,
115
+ errorEn: `Failed to save commands file: ${err.message}`,
116
+ };
108
117
  }
109
118
  }
110
119
  const isWindows = process.platform === "win32";
@@ -278,6 +287,7 @@ export function queryTerminalOutput(output, q, running = false, exitCode = null)
278
287
  .filter((l) => {
279
288
  const t = l.trim();
280
289
  return (!/^\[pi-exit:\d+\]$/.test(t) &&
290
+ !/^\[pi-term-exit:-?\d+\]$/.test(t) &&
281
291
  !t.startsWith("[进程已退出") &&
282
292
  !t.startsWith("[Process exited") &&
283
293
  !/^\[.*(已退出|exited)/.test(t));
@@ -1173,13 +1183,13 @@ export class TerminalManager {
1173
1183
  if (!entry || entry.exited)
1174
1184
  return;
1175
1185
  this.disarmIdleWatch(entry);
1176
- // Flush queued output BEFORE the exit banner so ordering is preserved.
1186
+ // Flush queued output BEFORE the exit marker so ordering is preserved.
1187
+ // Banner text is CLIENT-rendered (live locale); the stream carries only
1188
+ // a machine sentinel the client strips and replaces.
1177
1189
  this.flushPending(entry);
1178
- const banner = entry.locale === "en"
1179
- ? `\r\n\x1b[90m[Process exited with code ${exitCode}]\x1b[0m\r\n`
1180
- : `\r\n\x1b[90m[进程已退出,退出码 ${exitCode}]\x1b[0m\r\n`;
1181
- this.appendOutput(entry, banner);
1182
- this.emit({ type: "terminal_output", terminalId: id, data: banner });
1190
+ const marker = `\r\n[pi-term-exit:${exitCode}]\r\n`;
1191
+ this.appendOutput(entry, marker);
1192
+ this.emit({ type: "terminal_output", terminalId: id, data: marker });
1183
1193
  entry.exited = true;
1184
1194
  // 终端退出 → 未命中的输出观察器以 null 回调(宿主可据此通知「终端已关闭」)。
1185
1195
  const pendingWatches = entry.watches;
@@ -115,8 +115,8 @@ export class WebUIContext {
115
115
  });
116
116
  }
117
117
  // -- notifications --------------------------------------------------------
118
- notify = (message, type) => {
119
- this.emit({ type: "notice", level: type ?? "info", text: message });
118
+ notify = (message, type, messageEn) => {
119
+ this.emit({ type: "notice", level: type ?? "info", text: message, textEn: messageEn });
120
120
  };
121
121
  // -- footer status (pi-lens "LSP Inactive", pi-cache-optimizer cache stats) --
122
122
  statuses = new Map();
package/package.json CHANGED
@@ -1,109 +1,109 @@
1
- {
2
- "name": "pi-web-ui",
3
- "version": "0.63.4",
4
- "description": "Web chat interface for the pi coding agent, powered by the pi SDK (@earendil-works/pi-coding-agent) — one-command run, Docker/systemd/launchd deployable",
5
- "license": "MIT",
6
- "author": {
7
- "name": "xingshuyin",
8
- "email": "xingshuyin@users.noreply.github.com"
9
- },
10
- "type": "module",
11
- "bin": {
12
- "pi-web-ui": "bin/pi-web-ui.mjs"
13
- },
14
- "main": "bin/pi-web-ui.mjs",
15
- "files": [
16
- "bin/",
17
- "dist/",
18
- "web/dist/",
19
- "web/public/",
20
- "themes/",
21
- "deploy/",
22
- "extensions/",
23
- "README.md",
24
- "LICENSE"
25
- ],
26
- "keywords": [
27
- "pi",
28
- "pi-package",
29
- "coding-agent",
30
- "ai",
31
- "chat",
32
- "web-ui",
33
- "terminal",
34
- "llm"
35
- ],
36
- "repository": {
37
- "type": "git",
38
- "url": "git+https://github.com/xing-shuyin/pi-web-ui.git"
39
- },
40
- "pi": {
41
- "extensions": [
42
- "./extensions"
43
- ]
44
- },
45
- "engines": {
46
- "node": ">=22.19.0"
47
- },
48
- "scripts": {
49
- "prepublishOnly": "npm run build",
50
- "dev": "concurrently -k -n server,web -c blue,green \"npm:dev:server\" \"npm:dev:web\"",
51
- "dev:server": "cross-env PI_WEB_PORT=8788 PI_WEB_ALLOW_ORIGINS=http://localhost:5173,http://127.0.0.1:5173 node --watch --import tsx server/index.ts",
52
- "dev:web": "vite --config web/vite.config.ts",
53
- "build": "npm run build:web && npm run build:server && npm run build:dsh-runtime",
54
- "build:web": "vite build --config web/vite.config.ts",
55
- "build:server": "tsc -p tsconfig.server.json",
56
- "build:dsh-runtime": "node scripts/copy-dsh-runtime.mjs",
57
- "typecheck": "tsc -p tsconfig.server.json --noEmit && tsc -p web/tsconfig.json --noEmit && tsc -p tsconfig.tests.json --noEmit",
58
- "test": "vitest run",
59
- "test:unit": "vitest run",
60
- "test:smoke": "node tests/run-smoke.mjs",
61
- "check:protocol": "node scripts/check-protocol-sync.mjs",
62
- "test:freeze": "node tests/freeze-test.mjs",
63
- "start": "node dist/server/index.js",
64
- "format": "prettier --write server/ web/src/ extensions/ scripts/ bin/ tests/*.mjs tests/unit/ *.mjs",
65
- "format:check": "prettier --check server/ web/src/ extensions/ scripts/ bin/ tests/*.mjs tests/unit/ *.mjs",
66
- "lint": "oxlint server/ web/src/ extensions/ scripts/",
67
- "lint:fix": "oxlint --fix server/ web/src/ extensions/ scripts/"
68
- },
69
- "dependencies": {
70
- "@deepseek-ai/dsh-sdk-jsonrpc-server": "^0.1.1-rc.2",
71
- "@deepseek-ai/dsh-sdk-protocol": "^0.1.1-rc.2",
72
- "@earendil-works/pi-coding-agent": "^0.84.4",
73
- "@xterm/addon-fit": "^0.11.0",
74
- "@xterm/xterm": "^6.0.0",
75
- "compression": "^1.8.1",
76
- "express": "^4.21.2",
77
- "highlight.js": "^11.10.0",
78
- "node-pty": "^1.1.0",
79
- "react": "^18.3.1",
80
- "react-dom": "^18.3.1",
81
- "react-icons": "^5.7.0",
82
- "react-markdown": "^9.0.1",
83
- "rehype-highlight": "^7.0.1",
84
- "remark-gfm": "^4.0.0",
85
- "typebox": "^1.3.14",
86
- "ws": "^8.18.0"
87
- },
88
- "devDependencies": {
89
- "@types/compression": "^1.8.1",
90
- "@types/express": "^4.17.21",
91
- "@types/node": "^22.10.0",
92
- "@types/react": "^18.3.12",
93
- "@types/react-dom": "^18.3.1",
94
- "@types/ws": "^8.5.13",
95
- "@vitejs/plugin-react": "^4.3.4",
96
- "concurrently": "^9.1.0",
97
- "cross-env": "^10.1.0",
98
- "oxlint": "^1.81.0",
99
- "playwright-core": "^1.62.1",
100
- "prettier": "^3.9.6",
101
- "tsx": "^4.19.2",
102
- "typescript": "^5.7.2",
103
- "vite": "^6.0.3",
104
- "vitest": "^4.1.11"
105
- },
106
- "allowScripts": {
107
- "node-pty@1.1.0": true
108
- }
109
- }
1
+ {
2
+ "name": "pi-web-ui",
3
+ "version": "0.64.1",
4
+ "description": "Web chat interface for the pi coding agent, powered by the pi SDK (@earendil-works/pi-coding-agent) — one-command run, Docker/systemd/launchd deployable",
5
+ "license": "MIT",
6
+ "author": {
7
+ "name": "xingshuyin",
8
+ "email": "xingshuyin@users.noreply.github.com"
9
+ },
10
+ "type": "module",
11
+ "bin": {
12
+ "pi-web-ui": "bin/pi-web-ui.mjs"
13
+ },
14
+ "main": "bin/pi-web-ui.mjs",
15
+ "files": [
16
+ "bin/",
17
+ "dist/",
18
+ "web/dist/",
19
+ "web/public/",
20
+ "themes/",
21
+ "deploy/",
22
+ "extensions/",
23
+ "README.md",
24
+ "LICENSE"
25
+ ],
26
+ "keywords": [
27
+ "pi",
28
+ "pi-package",
29
+ "coding-agent",
30
+ "ai",
31
+ "chat",
32
+ "web-ui",
33
+ "terminal",
34
+ "llm"
35
+ ],
36
+ "repository": {
37
+ "type": "git",
38
+ "url": "git+https://github.com/xing-shuyin/pi-web-ui.git"
39
+ },
40
+ "pi": {
41
+ "extensions": [
42
+ "./extensions"
43
+ ]
44
+ },
45
+ "engines": {
46
+ "node": ">=22.19.0"
47
+ },
48
+ "scripts": {
49
+ "prepublishOnly": "npm run build",
50
+ "dev": "concurrently -k -n server,web -c blue,green \"npm:dev:server\" \"npm:dev:web\"",
51
+ "dev:server": "cross-env PI_WEB_PORT=8788 PI_WEB_ALLOW_ORIGINS=http://localhost:5173,http://127.0.0.1:5173 node --watch --import tsx server/index.ts",
52
+ "dev:web": "vite --config web/vite.config.ts",
53
+ "build": "npm run build:web && npm run build:server && npm run build:dsh-runtime",
54
+ "build:web": "vite build --config web/vite.config.ts",
55
+ "build:server": "tsc -p tsconfig.server.json",
56
+ "build:dsh-runtime": "node scripts/copy-dsh-runtime.mjs",
57
+ "typecheck": "tsc -p tsconfig.server.json --noEmit && tsc -p web/tsconfig.json --noEmit && tsc -p tsconfig.tests.json --noEmit",
58
+ "test": "vitest run",
59
+ "test:unit": "vitest run",
60
+ "test:smoke": "node tests/run-smoke.mjs",
61
+ "check:protocol": "node scripts/check-protocol-sync.mjs",
62
+ "test:freeze": "node tests/freeze-test.mjs",
63
+ "start": "node dist/server/index.js",
64
+ "format": "prettier --write server/ web/src/ extensions/ scripts/ bin/ tests/*.mjs tests/unit/ *.mjs",
65
+ "format:check": "prettier --check server/ web/src/ extensions/ scripts/ bin/ tests/*.mjs tests/unit/ *.mjs",
66
+ "lint": "oxlint server/ web/src/ extensions/ scripts/",
67
+ "lint:fix": "oxlint --fix server/ web/src/ extensions/ scripts/"
68
+ },
69
+ "dependencies": {
70
+ "@deepseek-ai/dsh-sdk-jsonrpc-server": "^0.1.1-rc.2",
71
+ "@deepseek-ai/dsh-sdk-protocol": "^0.1.1-rc.2",
72
+ "@earendil-works/pi-coding-agent": "^0.84.4",
73
+ "@xterm/addon-fit": "^0.11.0",
74
+ "@xterm/xterm": "^6.0.0",
75
+ "compression": "^1.8.1",
76
+ "express": "^4.21.2",
77
+ "highlight.js": "^11.10.0",
78
+ "node-pty": "^1.1.0",
79
+ "react": "^18.3.1",
80
+ "react-dom": "^18.3.1",
81
+ "react-icons": "^5.7.0",
82
+ "react-markdown": "^9.0.1",
83
+ "rehype-highlight": "^7.0.1",
84
+ "remark-gfm": "^4.0.0",
85
+ "typebox": "^1.3.14",
86
+ "ws": "^8.18.0"
87
+ },
88
+ "devDependencies": {
89
+ "@types/compression": "^1.8.1",
90
+ "@types/express": "^4.17.21",
91
+ "@types/node": "^22.10.0",
92
+ "@types/react": "^18.3.12",
93
+ "@types/react-dom": "^18.3.1",
94
+ "@types/ws": "^8.5.13",
95
+ "@vitejs/plugin-react": "^4.3.4",
96
+ "concurrently": "^9.1.0",
97
+ "cross-env": "^10.1.0",
98
+ "oxlint": "^1.81.0",
99
+ "playwright-core": "^1.62.1",
100
+ "prettier": "^3.9.6",
101
+ "tsx": "^4.19.2",
102
+ "typescript": "^5.7.2",
103
+ "vite": "^6.0.3",
104
+ "vitest": "^4.1.11"
105
+ },
106
+ "allowScripts": {
107
+ "node-pty@1.1.0": true
108
+ }
109
+ }
@@ -0,0 +1,6 @@
1
+ import{a as l,j as n}from"./markdown-DRBrS2Nf.js";import{u as O,b as M,T as z,a as W,F as Y,c as H,d as Z,e as q,f as ee,g as ne,h as te,i as se,r as ae}from"./index-BmDs6ukf.js";import{D as re,o as ie}from"./xterm-D1D2FVe3.js";import"./react-C9ovnpIm.js";function le(t){let c=null;return{clean:t.replace(/\r?\n?\[pi-term-exit:(-?\d+)\]\r?\n?/g,(a,h)=>(c=Number(h),`\r
2
+ `)).replace(/\r?\n?\x1b\[90m\[(?:进程已退出,退出码 |Process exited with code )-?\d+\]\x1b\[0m\r?\n?/g,`\r
3
+ `),exitCode:c}}function ce({conversationId:t,terminalId:c,command:f,cwd:a,title:h,active:u,running:b,exitCode:y,send:j,register:T}){const k=l.useRef(null),N=l.useRef(null),{locale:o}=O(),w=l.useRef(o);w.current=o;const F=f?JSON.stringify(f):"";l.useEffect(()=>{const m=k.current;if(!m)return;const r=new re({theme:M(),fontFamily:'"SF Mono", "JetBrains Mono", ui-monospace, Menlo, Consolas, monospace',fontSize:13,cursorBlink:!0,scrollback:8e3}),g=new ie;r.loadAddon(g),r.open(m),N.current={term:r,fit:g},u&&r.focus();const C=()=>{r.options.theme=M()};window.addEventListener(z,C),r.attachCustomKeyEventHandler(d=>{var A;if(d.type!=="keydown")return!0;const D=(A=d.key)==null?void 0:A.toLowerCase();if((d.ctrlKey||d.metaKey)&&D==="v")return!1;if(d.ctrlKey&&!d.shiftKey&&!d.altKey&&D==="c"&&r.hasSelection()){const E=r.textarea;return E&&(E.value=r.getSelection(),E.select()),!1}return!0});const _=T(t,c,{write:d=>r.write(le(d).clean),dispose:()=>r.dispose()}),$=()=>{try{g.fit(),j({type:"terminal_resize",terminalId:c,conversationId:t,cols:r.cols,rows:r.rows})}catch{}},B=requestAnimationFrame(()=>{try{g.fit()}catch{}j(f?{type:"run_command",terminalId:c,conversationId:t,command:f,cols:r.cols,rows:r.rows}:{type:"terminal_create",terminalId:c,title:h,locale:w.current,conversationId:t,cwd:a,cols:r.cols,rows:r.rows})}),S=r.onData(d=>{j({type:"terminal_input",terminalId:c,conversationId:t,data:d})});let v=null;return typeof ResizeObserver<"u"&&(v=new ResizeObserver(()=>{m.offsetWidth>0&&m.offsetHeight>0&&$()}),v.observe(m)),()=>{cancelAnimationFrame(B),S.dispose(),window.removeEventListener(z,C),v==null||v.disconnect(),_(),r.dispose(),N.current=null}},[t,c,F,j,T]),l.useEffect(()=>{if(!u)return;const m=requestAnimationFrame(()=>{const r=N.current;if(r){try{r.fit.fit(),j({type:"terminal_resize",terminalId:c,conversationId:t,cols:r.term.cols,rows:r.term.rows})}catch{}r.term.focus()}});return()=>cancelAnimationFrame(m)},[u]);const{t:R}=O(),x=l.useRef(void 0);return l.useEffect(()=>{if(b===x.current||(x.current=b,b!==!1))return;const m=N.current;m&&m.term.write(`\r
4
+ \x1B[90m${R("exitBanner",{code:y??""})}\x1B[0m\r
5
+ `)},[b,c,y]),n.jsx("div",{ref:k,className:`term-xterm ${u?"":"hidden"}`})}const G={name:"",command:"",cwd:"${pwd}"};function pe({chat:t,send:c,terminal:f}){const a=W(),[h,u]=l.useState(null),[b,y]=l.useState(!1),[j,T]=l.useState(!1),[k,N]=l.useState(null),[o,w]=l.useState(G),[F,R]=l.useState(null),x=l.useRef(null),[m,r]=l.useState(!0),[g,C]=l.useState(null),[_,$]=l.useState("");l.useEffect(()=>{t.terminals.length===0?u(null):t.terminals.some(e=>e.id===h)||u(t.terminals[t.terminals.length-1].id)},[t.terminals,h]),l.useEffect(()=>{t.terminalActiveId&&(u(t.terminalActiveId),y(!1))},[t.terminalActiveId]),l.useEffect(()=>()=>{x.current&&clearTimeout(x.current)},[]);const B=t.terminals.filter(e=>!e.agentBash),S=t.terminals.filter(e=>e.agentBash),v=e=>{var p;if(!t.ready)return;const s=ae(),i=t.activeConversationId||((p=t.state)==null?void 0:p.conversationId)||"";f.create({...e,id:s,conversationId:i,cols:e.cols??80,rows:e.rows??24,running:!0,exitCode:null}),u(s),y(!1)},d=()=>{var e;return v({title:a("terminalTitle",{n:B.length+1}),cwd:((e=t.state)==null?void 0:e.cwd)??""})},D=e=>{var p;const s=e.name||e.command,i=t.terminals.find(K=>K.title===s);if(i){f.restart(i.id),u(i.id),c({type:"run_command",terminalId:i.id,conversationId:i.conversationId,command:e,cols:80,rows:24});return}v({title:s,cwd:((p=t.state)==null?void 0:p.cwd)??"",command:e})},A=e=>{const s=t.terminals.find(i=>i.id===e);if(s&&c({type:"terminal_kill",terminalId:e,conversationId:s.conversationId}),f.close(e),h===e){const i=t.terminals.filter(p=>p.id!==e);u(i.length>0?i[i.length-1].id:null)}},E=e=>n.jsxs("div",{className:`term-tab ${e.id===h?"active":""}`,children:[n.jsxs("button",{type:"button",className:"term-tab-main",title:`${e.cwd}${e.command?`
6
+ > ${e.command.command}`:""}`,onClick:()=>{g||(u(e.id),y(!1))},children:[n.jsx("span",{className:`term-tab-dot ${e.running?"run":"exit"}`}),n.jsxs("span",{className:"term-tab-title",children:[g===e.id?n.jsx("input",{autoFocus:!0,className:"term-tab-rename-input",value:_,placeholder:e.title,onClick:s=>s.stopPropagation(),onChange:s=>$(s.target.value),onKeyDown:s=>{if(s.stopPropagation(),s.key==="Enter"&&!s.nativeEvent.isComposing){const i=_.trim();i&&c({type:"rename_terminal",terminalId:e.id,conversationId:e.conversationId,title:i}),C(null)}else s.key==="Escape"&&C(null)},onBlur:()=>C(null)}):e.title,!e.running&&n.jsx("span",{className:"term-tab-exit",children:a("exited",{code:e.exitCode===null?"":` ${e.exitCode}`})})]})]}),n.jsx("button",{type:"button",className:"term-tab-close term-tab-rename",title:a("renameTerminal"),onClick:s=>{s.stopPropagation(),$(e.title),C(e.id)},children:n.jsx(q,{})}),n.jsx("button",{type:"button",className:"term-tab-close",title:a("closeTerminal"),onClick:()=>A(e.id),children:n.jsx(se,{})})]},e.id),L=()=>{T(!0),N(null),w(G)},J=e=>{const s=t.commands[e];s&&(T(!1),N(e),w({name:s.name,command:s.command,cwd:s.cwd??""}))},P=()=>{T(!1),N(null)},I=()=>{const e=o.name.trim(),s=o.command.trim();if(!e||!s)return;const i=o.cwd.trim(),p={name:e,command:s,cwd:i||void 0},K=j?[...t.commands,p]:k!==null?t.commands.map((U,V)=>V===k?p:U):t.commands;c({type:"save_commands",commands:K}),P()},X=e=>{if(F===e){const s=t.commands.filter((i,p)=>p!==e);c({type:"save_commands",commands:s}),R(null),x.current&&clearTimeout(x.current)}else R(e),x.current&&clearTimeout(x.current),x.current=setTimeout(()=>R(null),2500)},Q=j||k!==null;return n.jsxs("div",{className:"terminal-view",children:[n.jsxs("aside",{className:`term-side term-commands ${b?"open":""}`,children:[n.jsxs("div",{className:"panel-header",children:[n.jsx("span",{className:"panel-title",children:a("commands")}),n.jsxs("div",{className:"panel-header-actions",children:[n.jsx("button",{type:"button",className:"panel-refresh",title:a("rerun"),onClick:()=>c({type:"list_commands"}),children:n.jsx(Y,{})}),n.jsx("button",{type:"button",className:"panel-new",title:a("newCommand"),onClick:L,children:n.jsx(H,{})})]})]}),n.jsx("div",{className:"panel-body",children:Q?n.jsxs("div",{className:"cmd-form",children:[n.jsx("label",{htmlFor:"cmd-name",children:a("name")}),n.jsx("input",{id:"cmd-name",className:"cmd-input",value:o.name,placeholder:a("exampleName"),autoFocus:!0,onChange:e=>w({...o,name:e.target.value})}),n.jsx("label",{htmlFor:"cmd-command",children:a("command")}),n.jsx("input",{id:"cmd-command",className:"cmd-input",value:o.command,placeholder:a("exampleCommand"),onChange:e=>w({...o,command:e.target.value}),onKeyDown:e=>{e.key==="Enter"&&!e.nativeEvent.isComposing&&I()}}),n.jsxs("label",{htmlFor:"cmd-cwd",children:[a("directory")," ",n.jsx("span",{className:"cmd-hint",children:a("cwdHint")})]}),n.jsx("input",{id:"cmd-cwd",className:"cmd-input",value:o.cwd,placeholder:"${pwd}",onChange:e=>w({...o,cwd:e.target.value}),onKeyDown:e=>{e.key==="Enter"&&!e.nativeEvent.isComposing&&I()}}),n.jsxs("div",{className:"cmd-form-actions",children:[n.jsx("button",{type:"button",className:"btn",onClick:P,children:a("cancel")}),n.jsx("button",{type:"button",className:"btn primary",disabled:!o.name.trim()||!o.command.trim(),onClick:I,children:a("save")})]})]}):n.jsxs(n.Fragment,{children:[t.commands.length===0&&n.jsx("div",{className:"panel-empty",children:a("noCommands")}),t.commands.map((e,s)=>n.jsxs("div",{className:"cmd-item",children:[n.jsx("button",{type:"button",className:"cmd-run",title:a("clickToRun"),onClick:()=>D(e),children:n.jsx(Z,{})}),n.jsxs("button",{type:"button",className:"cmd-main",title:a("clickToRun"),onClick:()=>D(e),children:[n.jsx("span",{className:"cmd-name",children:e.name}),n.jsx("span",{className:"cmd-command",children:e.command}),e.cwd&&n.jsx("span",{className:"cmd-cwd",children:e.cwd})]}),n.jsx("button",{type:"button",className:"cmd-act",title:a("edit"),onClick:()=>J(s),children:n.jsx(q,{})}),n.jsx("button",{type:"button",className:`cmd-act del ${F===s?"confirm":""}`,title:a("delete"),onClick:()=>X(s),children:F===s?a("confirmQ"):n.jsx(ee,{})})]},s))]})}),n.jsxs("div",{className:"term-tabs-block",children:[n.jsxs("div",{className:"panel-header",children:[n.jsx("span",{className:"panel-title",children:a("terminal")}),n.jsx("button",{type:"button",className:"panel-new",title:a("newTerminal"),onClick:d,children:n.jsx(H,{})})]}),n.jsxs("div",{className:"panel-body",children:[t.terminals.length===0&&n.jsx("div",{className:"panel-empty",children:a("noTerminal")}),B.map(E),S.length>0&&n.jsxs("div",{className:"term-folder",children:[n.jsxs("button",{type:"button",className:`term-folder-header ${m?"open":""}`,title:a("aiBashGroup"),onClick:()=>r(e=>!e),children:[n.jsx("span",{className:"term-folder-caret",children:m?"▾":"▸"}),n.jsx("span",{className:"term-folder-title",children:a("aiBashGroup")}),n.jsx("span",{className:"term-folder-count",children:S.length})]}),m&&n.jsx("div",{className:"term-folder-body",children:S.map(E)})]})]})]})]}),n.jsxs("div",{className:"term-main",children:[b&&n.jsx("div",{className:"drawer-backdrop",onClick:()=>y(!1)}),n.jsx("button",{type:"button",className:"term-side-toggle",title:a("commands"),onClick:()=>y(e=>!e),children:n.jsx(ne,{})}),t.terminals.length===0?n.jsxs("div",{className:"term-empty",children:[n.jsx(te,{className:"term-empty-icon"}),n.jsx("div",{className:"term-empty-title",children:a("builtinTerminal")}),n.jsx("div",{className:"term-empty-sub",children:a("termEmptySub")})]}):t.terminals.map(e=>n.jsx(ce,{conversationId:e.conversationId,terminalId:e.id,command:e.command,cwd:e.cwd,title:e.title,active:e.id===h,running:e.running,exitCode:e.exitCode,send:c,register:f.register},`${e.conversationId}:${e.id}`))]})]})}export{pe as TerminalPanel};