feat: add web terminal, improve README, fix node-pty and i18n issues

- Add web terminal view with xterm.js and node-pty WebSocket backend
- Rewrite README with badges, feature table, mobile demo video
- Add package keywords and improved description for npm/GitHub SEO
- Fix node-pty spawn-helper missing execute permission after npm install -g
- Auto-fix node-pty permissions on CLI startup
- Fix duplicate 'error' key in en.ts and zh.ts i18n files
- Remove nested NSpin in PlatformSettings (causes invisible loading spinner)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
ekko
2026-04-15 16:36:04 +08:00
parent d258875cef
commit 71c7f25f4b
25 changed files with 1367 additions and 244 deletions
+5 -5
View File
@@ -83,7 +83,7 @@ function mapHermesMessages(msgs: HermesMessage[]): Message[] {
role: 'tool',
content: '',
timestamp: Math.round(msg.timestamp * 1000),
toolName: tc.function?.name || 'Tool',
toolName: tc.function?.name || 'tool',
toolArgs: tc.function?.arguments || undefined,
toolStatus: 'done',
})
@@ -94,7 +94,7 @@ function mapHermesMessages(msgs: HermesMessage[]): Message[] {
// Tool result messages
if (msg.role === 'tool') {
const tcId = msg.tool_call_id || ''
const toolName = msg.tool_name || toolNameMap.get(tcId) || 'Tool'
const toolName = msg.tool_name || toolNameMap.get(tcId) || 'tool'
const toolArgs = toolArgsMap.get(tcId) || undefined
// Extract a short preview from the content
let preview = ''
@@ -141,7 +141,7 @@ function mapHermesMessages(msgs: HermesMessage[]): Message[] {
function mapHermesSession(s: SessionSummary): Session {
return {
id: s.id,
title: s.title || 'New Chat',
title: s.title || '',
source: s.source || undefined,
messages: [],
createdAt: Math.round(s.started_at * 1000),
@@ -190,7 +190,7 @@ export const useChatStore = defineStore('chat', () => {
function createSession(): Session {
const session: Session = {
id: uid(),
title: 'New Chat',
title: '',
source: 'api_server',
messages: [],
createdAt: Date.now(),
@@ -289,7 +289,7 @@ export const useChatStore = defineStore('chat', () => {
function updateSessionTitle(sessionId: string) {
const target = sessions.value.find(s => s.id === sessionId)
if (!target) return
if (target.title === 'New Chat') {
if (!target.title) {
const firstUser = target.messages.find(m => m.role === 'user')
if (firstUser) {
const title = firstUser.attachments?.length