diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 00000000..18e7130a --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,42 @@ +{ + "permissions": { + "allow": [ + "Bash(npm run:*)", + "Bash(cd client:*)", + "Bash(git add:*)", + "Bash(git:*)", + "Bash(node --test server/lib/__tests__/transcript-cache.test.js)", + "Bash(node -e \"const r = require\\(''''./server/routes/hooks''''\\); console.log\\(''''router type:'''', typeof r\\); console.log\\(''''transcriptCache exists:'''', !!r.transcriptCache\\); console.log\\(''''transcriptCache has extract:'''', typeof r.transcriptCache?.extract\\);\")", + "Bash(node -e \"const r = require\\(''''./server/routes/hooks''''\\); console.log\\(''''router type:'''', typeof r\\); console.log\\(''''transcriptCache exists:'''', Boolean\\(r.transcriptCache\\)\\); console.log\\(''''transcriptCache has extract:'''', typeof \\(r.transcriptCache && r.transcriptCache.extract\\)\\);\")", + "Bash(node -e \"const { transcriptCache } = require\\(''./server/routes/hooks''\\); console.log\\(''transcriptCache exists:'', Boolean\\(transcriptCache\\)\\); console.log\\(''has extract:'', typeof \\(transcriptCache && transcriptCache.extract\\)\\); console.log\\(''has extractCompactions:'', typeof \\(transcriptCache && transcriptCache.extractCompactions\\)\\); console.log\\(''has invalidate:'', typeof \\(transcriptCache && transcriptCache.invalidate\\)\\); console.log\\(''has stats:'', typeof \\(transcriptCache && transcriptCache.stats\\)\\);\")", + "Bash(npx tsc:*)", + "Bash(npx --prefix client tsc --noEmit -p client/tsconfig.json)", + "Bash(node -e \":*)", + "Bash(wc:*)", + "Bash(grep -E \"\\\\.js$\")", + "Bash(npm install:*)", + "Bash(./node_modules/.bin/tsc --noEmit)", + "Bash(npx vite:*)", + "Bash(node -e \"const p = require\\(''./package.json''\\); console.log\\(''deps:'', Object.keys\\(p.dependencies || {}\\).length\\); console.log\\(Object.keys\\(p.dependencies || {}\\).join\\('', ''\\)\\)\")", + "Bash(npx prettier:*)", + "Bash(node scripts/seed.js)", + "Bash(lsof -ti:4820)", + "Bash(xargs kill:*)", + "Bash(lsof -ti:5173)", + "Bash(lsof -ti:5174)", + "Bash(curl -s http://localhost:4820/api/health)", + "Bash(node -e \"require\\('./server/lib/transcript-cache'\\); console.log\\('transcript-cache OK'\\)\")", + "Bash(python3:*)", + "Bash(node -c scripts/import-history.js)", + "Bash(node -e \"const m = require\\('./scripts/import-history'\\); console.log\\(Object.keys\\(m\\).sort\\(\\).join\\(', '\\)\\)\")", + "Bash(node -e \"const TC = require\\('./server/lib/transcript-cache'\\); const tc = new TC\\(\\); console.log\\('transcript-cache loaded OK, methods:', Object.getOwnPropertyNames\\(TC.prototype\\).filter\\(n => n !== 'constructor'\\).join\\(', '\\)\\)\")", + "Bash(node -e \"try { require\\('./server/routes/hooks'\\); } catch\\(e\\) { console.log\\('Expected error \\(db not available in isolation\\):', e.message.slice\\(0, 100\\)\\); }\")", + "Bash(node --check server/routes/hooks.js)", + "Bash(node --check server/lib/transcript-cache.js)", + "Bash(node -e ':*)", + "Bash(node -e \"require\\('./server/lib/transcript-cache'\\); require\\('./scripts/import-history'\\); console.log\\('All modules load OK'\\)\")", + "Bash(claude --version)", + "Bash(gh pr *)" + ] + } +} diff --git a/.prettierignore b/.prettierignore index 1546f699..68872051 100644 --- a/.prettierignore +++ b/.prettierignore @@ -24,3 +24,4 @@ desktop/assets/*.icns desktop/assets/icon.iconset/ wiki/mermaid.min.js fonts/*.woff2 +monitoring/.bin/ diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 691809c1..e6ee987e 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -486,7 +486,7 @@ graph TD ### Splash & loading UX -- **`SplashScreen.tsx`** — rendered by `App.tsx` as a fixed full-screen overlay alongside the router. Shows once per browser session (`sessionStorage` gate, read synchronously so a repeat mount never flashes). Time-aware greeting + localized tagline/subtexts (`splash` i18n namespace, en/zh/vi/ko) + an animated node-graph brand mark on a dark backdrop (radial glow, drifting constellation, grain). The backdrop is **opaque from the first paint** (no entrance fade on the root) so the app rendered behind it never flashes through; only the inner content cascades in. Holds ~2.5 s, then fades out and unmounts; click-to-skip; honors `prefers-reduced-motion`. CSS-only keyframes, no added dependencies. +- **`SplashScreen.tsx`** — rendered by `App.tsx` as a fixed full-screen overlay alongside the router. Shows once per browser session (`sessionStorage` gate, read synchronously so a repeat mount never flashes). Time-aware greeting + localized tagline/subtexts (`splash` i18n namespace, en/zh/vi/ko/es) + an animated node-graph brand mark on a dark backdrop (radial glow, drifting constellation, grain). The backdrop is **opaque from the first paint** (no entrance fade on the root) so the app rendered behind it never flashes through; only the inner content cascades in. Holds ~2.5 s, then fades out and unmounts; click-to-skip; honors `prefers-reduced-motion`. CSS-only keyframes, no added dependencies. - **Loading skeletons** — the shared `Skeleton` primitive (`components/Skeleton.tsx`) uses Tailwind `animate-pulse`. `Analytics.tsx` now renders a pulsing `AnalyticsChartsSkeleton` for the whole chart region while `data` is null (previously it fell back to empty/zero charts). - **`workflows/CompactionImpact.tsx`** — redesigned from a one-bar-per-session chart into a "sessions by compaction count" histogram (D3) with axis titles, stat tiles (total / sessions affected / avg / peak), an explanatory help line, a plain-English summary, and rich React-managed hover tooltips (full-height per-bucket hit-area + bar highlight) matching the other charts. - **`Workflows.tsx` `Section`** — the right-aligned section subtitle is clamped to a single line (`truncate` + `max-w` + hover `title`) so a long translation never wraps and unbalances the header; the full text stays in the section's `i` popover. @@ -741,15 +741,15 @@ Both popover classes use the same fixed-position + viewport-clamp algorithm: anc ## Internationalization Architecture -The client localization stack is powered by `i18next` + `react-i18next` (`client/src/i18n/index.ts`) and currently supports four languages: English (`en`), Chinese (`zh`), Vietnamese (`vi`), and Korean (`ko`). Language detection prefers `localStorage` (`i18nextLng`) and falls back to the browser locale (`navigator`) with `en` as final fallback. +The client localization stack is powered by `i18next` + `react-i18next` (`client/src/i18n/index.ts`) and currently supports five languages: English (`en`), Chinese (`zh`), Vietnamese (`vi`), Korean (`ko`), and Spanish (`es`). The sidebar uses the shared custom `Select` dropdown, so locale choices remain compact as languages grow. Language detection prefers `localStorage` (`i18nextLng`) and falls back to the browser locale (`navigator`) with `en` as final fallback. ```mermaid flowchart LR A["Browser load"] --> B["LanguageDetector
localStorage -> navigator"] - B --> C["Resolved language
en | zh | vi | ko (fallback en)"] + B --> C["Resolved language
en | zh | vi | ko | es (fallback en)"] C --> D["Namespace resources
common/nav/dashboard/sessions/..."] D --> E["React pages/components
useTranslation(ns)"] - E --> F["format.ts locale mapping
en-US | zh-CN | vi-VN | ko-KR"] + E --> F["format.ts locale mapping
en-US | zh-CN | vi-VN | ko-KR | es-ES"] F --> G["Localized labels,
dates, number formatting,
and model name display"] ``` @@ -2220,7 +2220,7 @@ Tabby's only contact with the rest of the app is four light, additive touchpoint | `client/src/components/Layout.tsx` | Mounts `` once, as a sibling of ``. | | `client/src/pages/Settings.tsx` | On/off toggle wired to `tabbyPrefs` (`localStorage`). | | `client/src/pages/Run.tsx` | Reads `?prompt=` to prefill the prompt box for Tabby's Ask handoff. | -| `client/src/i18n/locales/{en,zh,vi,ko}/settings.json` | `tabby.*` strings for the Settings toggle (en / zh / vi / ko). | +| `client/src/i18n/locales/{en,zh,vi,ko,es}/settings.json` | `tabby.*` strings for the Settings toggle (en / zh / vi / ko / es). | --- diff --git a/README-CN.md b/README-CN.md index f099690a..37990426 100644 --- a/README-CN.md +++ b/README-CN.md @@ -69,9 +69,9 @@ ![Auto Release](https://img.shields.io/badge/CI-auto--release_to_GitHub-22c55e?style=flat-square&logo=githubactions&logoColor=white) ![MIT License](https://img.shields.io/badge/License-MIT-yellow?style=flat-square) -**语言支持 / Language Support**: English (`en`) · 中文 (`zh`) · 越南语 (`vi`) · 韩语 (`ko`) +**语言支持 / Language Support**: English (`en`) · 中文 (`zh`) · 越南语 (`vi`) · 韩语 (`ko`) · Español (`es`) -切换文档:[`README.md`](./README.md) · [`README-CN.md`](./README-CN.md) · [`README-VN.md`](./README-VN.md) · [`README-KO.md`](./README-KO.md) +切换文档:[`README.md`](./README.md) · [`README-CN.md`](./README-CN.md) · [`README-VN.md`](./README-VN.md) · [`README-KO.md`](./README-KO.md) · [`README-ES.md`](./README-ES.md) --- @@ -124,11 +124,11 @@ graph LR ### 多语言支持(i18n) -Dashboard 内置多语言界面,支持 `en`、`zh`、`vi`、`ko` 四种语言,适用于跨语言协作和团队共享。 +Dashboard 内置多语言界面,支持 `en`、`zh`、`vi`、`ko`、`es` 五种语言,适用于跨语言协作和团队共享。语言选择使用自定义下拉菜单,便于未来继续扩展。 ```mermaid flowchart LR - A["用户选择语言
en / zh / vi / ko"] --> B["前端 i18n 路由"] + A["用户选择语言
en / zh / vi / ko / es"] --> B["前端 i18n 路由"] B --> C["翻译字典加载"] C --> D["UI 文案与可访问性标签渲染"] D --> E["实时仪表盘 / API 文档 / 设置页"] @@ -308,7 +308,7 @@ Dashboard 提供全面的功能来监控和分析你的 Claude Code 会话和 Ag | **持续项目同步** | 启动时对 `~/.claude/projects` 的自动导入是一次性的(由标记位把关),因此在首次启动**之后**才创建的项目文件夹——其会话从不经过 Hook 流入(例如 host-only Hook 被禁用)——在手动重新扫描之前都将不可见。后台同步(`startSessionSync`)通过三个共享同一个 mtime 缓存 + 单次合并扫描的触发器弥补了这个空隙:启动时的**立即**扫描、一个去抖的 **`fs.watch`**(新会话文件 / 项目文件夹一出现就触发;在 macOS/Windows 上递归监听,在 Linux 上监听根目录 + 直接子文件夹,以规避用户态递归监听器的隐患),以及一个**周期性轮询**(`DASHBOARD_SESSION_SYNC_MS`,默认 30 秒)。每次扫描只重新解析 mtime 前进过的文件,并广播 `session_created`/`session_updated`(外加主 Agent),让 UI 实时刷新;DB 中已有且未变更的会话会被跳过、不再重新解析,因此重启成本保持为 O(新增/变更文件) | | **远程数据源** | 通过 SSH 实时从其他机器收集 Claude Code 数据。Dashboard 通过 **scp**(Windows SSH 上 WSL 托管的 Claude 使用 `wsl.exe` + `tar`)将每台机器的 `~/.claude/projects` 镜像到按源隔离的沙箱暂存目录,经与本地历史**相同的导入器**处理,并为导入会话打上来源标签(`sessions.source`)。后台轮询器(`DASHBOARD_REMOTE_SYNC_MS`,默认 15 秒;`0` 禁用)保持近实时——新增或重新启用源也会立即拉取——成功同步会广播 `remote_data.updated` 及逐会话的 `session_created` / `session_updated` 帧,打开页面无需手动 Sync 即可刷新。全局**数据范围**选择器(仅本地 / 全部 / 指定源)可收窄整个应用。在 **Settings → Remote Data Sources** 和 `ccam remote-sources` 中管理;状态经 `remote_source.status` 推送,Sessions 行显示来源徽章。远程会话**不接收本地实时 Hook**,因此被排除在所有本地存活性/过期启发式之外;其**实时状态在每次同步时依据镜像 Transcript 重新核对**——JSONL 内最新事件时间戳(回退到镜像 mtime)落在 `DASHBOARD_REMOTE_ACTIVE_WINDOW_MS`(默认 10 分钟)内则视为远程 CLI 仍在运行(⇒ `active`),镜像停止推进则核对为 `completed` | | **响应式设计** | 适配移动端的布局,堆叠网格、可滚动表格和可折叠侧边栏 | -| **界面本地化** | 内置语言切换,UI 文案与无障碍标签已覆盖英文(`en`)、中文(`zh`)、越南语(`vi`)和韩语(`ko`)。覆盖范围现已贯穿 Workflows 页面的所有 tooltip:统计卡片的计算说明与按值分桶的解读、每个图表的「此图展示什么 / 如何阅读 / 为何重要」浮层、所有图形悬停 tooltip(编排 DAG、工具流、Pipeline、模型委派、并发时间线)、Workflow Patterns 详情面板的叙述与建议、设置页 → 模型定价的信息浮层、CLAUDE_HOME 面板,以及完整的 Import History 流程 | +| **界面本地化** | 内置语言切换,UI 文案与无障碍标签已覆盖英文(`en`)、中文(`zh`)、越南语(`vi`)和韩语(`ko`)及西班牙语(`es`)。覆盖范围现已贯穿 Workflows 页面的所有 tooltip:统计卡片的计算说明与按值分桶的解读、每个图表的「此图展示什么 / 如何阅读 / 为何重要」浮层、所有图形悬停 tooltip(编排 DAG、工具流、Pipeline、模型委派、并发时间线)、Workflow Patterns 详情面板的叙述与建议、设置页 → 模型定价的信息浮层、CLAUDE_HOME 面板,以及完整的 Import History 流程 | | **种子数据** | 内置种子脚本,用于演示和开发 | | **状态栏** | 彩色编码的 CLI 状态栏,显示模型、上下文使用率、Git 分支、Token 数 | | **模型名称格式化** | 整个 UI 中使用人性化的模型名称:原始标识符如 `claude-opus-4-7-20260101` 或 `claude-opus-4-7[1m]` 显示为"Claude Opus 4.7"或"Claude Opus 4.7 (1M)"。支持 Claude、GPT 和 Gemini 家族的自动版本号点连接、日期/latest 后缀剥离、提供商前缀移除和上下文窗口标签格式化。设置页保留原始名称以配置定价规则 | @@ -317,7 +317,7 @@ Dashboard 提供全面的功能来监控和分析你的 Claude Code 会话和 Ag | **Tabby** | 固定在每个页面右下角的可爱 SVG 小猫伴侣,会订阅实时会话 WebSocket 流并据此做出反应。**会做出反应的吉祥物**:基于实时会话流呈现 8 种情绪——空闲、观察、开心、担忧、卡住、思考、睡觉、断开连接;眼睛会追踪光标,每种情绪都有专属动画。**气泡台词**在值得关注的事件发生时弹出(会话开始/结束、出现错误、运行完成),带节流且可静音。点击小猫或按 **⌘B / Ctrl+B** 打开**面板**(Esc 关闭):实时状态行(N 个进行中 · M 个出错 · 连接状态)、快捷操作(跳转到 Run Claude / 活动 / 会话 / 出错的会话,静音,清除提醒)以及一个 **Ask** 提问框。Ask 提问框在本地回答简单的状态类问题;其他问题则交给现有的 **Run Claude** 页面(`/run?prompt=...`)以启动一个真正的 Claude Code 会话——**无需新增后端、无需 API 密钥**。完全构建在现有的 WebSocket 流之上,支持无障碍(键盘、`aria-live`、尊重 `prefers-reduced-motion`),可在「设置」中开关。代码位于 `client/src/components/Tabby/` | | **告警与 Webhook** | 基于规则的告警引擎在服务端评估实时事件流,支持四种条件类型:**事件模式**(匹配事件类型 / 工具名 / 摘要子串,可选要求在时间窗口内出现 N 次匹配——例如「2 分钟内超过 5 个错误」)、**闲置**(活跃会话 N 分钟无事件)、**卡住的代理**(代理在 `working`/`waiting` 状态下 N 分钟无活动)和**令牌阈值**(会话总令牌超过上限)。每条规则都按 (规则、会话、代理) 维度做冷却去重。触发的告警显示在实时列表中(支持确认 / 全部确认),并扇出到 **14 个一等公民 Webhook 提供方**——**Slack**、**Discord**、**Microsoft Teams**(通过 Power Automate Workflows 的 Adaptive Card)、**Google Chat**、**Mattermost**、**Rocket.Chat**、**Telegram**(Bot API)、**PagerDuty**(Events API v2)、**Opsgenie**(Alert API)、**Splunk On-Call**(VictorOps)、**Zapier**、**Make**、**n8n**、**Pipedream**——以及任意通用 JSON 端点(可选 **HMAC-SHA256** 签名 + 自定义请求头)。每个提供方都有各自的原生负载格式,可按规则限定范围。投递与告警流程分离且完全失败安全:请求超时、有界重试/退避、响应体校验(Splunk On-Call 返回 200 但 `result:"failure"`)、同步的**「发送测试」**按钮以及每个目标的投递日志。URL、密钥和凭据均存储在服务端,**绝不**通过 API 返回(在所有响应中被掩码/脱敏)。规则与渠道在 **设置 → 告警** 中统一管理,每个字段都有解释性提示,并提供按提供方的设置指南(附说明:这些步骤可能已过时——请查阅官方文档) | | **Claude 配置浏览器** | `/cc-config` 上的 12 标签页检查器,涵盖 Claude Code 知道的一切:技能、子代理、斜杠命令、输出样式、插件(每个插件包含贡献计数 + 来自 `plugin.json` 的作者/许可证/主页)、市场(包含从每个 `marketplace.json` 读取的插件计数)、MCP 服务器、Hook(含 `~/.claude/hooks/` 脚本列表)、设置(一目了然的**当前配置**摘要,跨 用户/项目/项目本地 作用域解析 `/config` 控制的选项——model、verbose、主题、输出样式、effort、自动压缩、通知 ……,未设置项显示为默认值,外加按文件的结构化键值视图 + 原始 JSON 切换、密钥脱敏)、记忆(用户与项目 `CLAUDE.md` 文件,外加按项目的文件型记忆存储 —— `~/.claude/projects//memory/` 下的每个 `*.md`,即一个 `MEMORY.md` 索引加上每条记忆事实一个文件,通常 100+ 个;Memory 标签页按项目分组(可折叠)、将索引文件与逐条事实文件分开,并带搜索框,以及可点击的 `MEMORY.md` 索引链接——点击后跳转到(滚动并高亮)对应的事实文件)、快捷键(按上下文分组,使用 `` 字符)、状态行(配置 + 脚本内容)。对低风险文本文件表面(技能 / 代理 / 命令 / 输出样式 / 记忆,含按项目的 auto-memory 文件),页面支持**带强制时间戳备份的创建/编辑/删除**(auto-memory 备份落在 `/.cc-config-backups/auto-memory/`),原子写入到 Claude Code 不扫描的目录之外,加上带自动构建 `mv` 恢复命令的备份模态框。插件、MCP、settings 中的 hooks 和 `settings.json` 文件保持只读,带说明横幅 + 可复制的 CLI 命令,以便用户知道要自行运行的确切命令。**实时更新**:服务端运行的 `cc-watcher` 通过 `fs.watch` 监听 `~/.claude/`(平台支持时递归)以及 `~/.claude.json`,以 500 ms 去抖,在 Claude Code 配置变化时(无论是仪表盘修改还是外部工具如 CLI 安装插件、手动编辑 `settings.json`、放入新技能)广播 `cc_config_changed` WebSocket 消息。页面订阅并自动重新拉取;标题旁的 Live / Offline 标识显示 WebSocket 连接状态 | -| **启动画面** | 应用加载时每个浏览器会话显示一次的品牌开场画面:根据时间的问候语(早上好 / 下午好 / 晚上好 / 夜深了)、一句醒目的本地化标语与两行副文案,以及深色背景(径向光晕、星座连线、颗粒质感)上带动画的节点图品牌标记。从首帧起即**不透明**(应用内容不会闪现),停留约 2.5 秒后淡出,点击任意处可跳过,尊重 `prefers-reduced-motion`,已本地化 en/zh/vi/ko | +| **启动画面** | 应用加载时每个浏览器会话显示一次的品牌开场画面:根据时间的问候语(早上好 / 下午好 / 晚上好 / 夜深了)、一句醒目的本地化标语与两行副文案,以及深色背景(径向光晕、星座连线、颗粒质感)上带动画的节点图品牌标记。从首帧起即**不透明**(应用内容不会闪现),停留约 2.5 秒后淡出,点击任意处可跳过,尊重 `prefers-reduced-motion`,已本地化 en/zh/vi/ko/es | | **渐进式 Web 应用 (PWA)** | 三个独立的 PWA — 仪表盘、着陆页和维基 — 每个都有自己的 Web App Manifest 和 Service Worker。将任意一个安装到主屏幕/Dock,获得无浏览器边框的独立应用体验。仪表盘 SW 对 Vite 哈希化的 `/assets/*` 资源采用 cache-first(URL 每次构建都不可变,缓存命中始终正确),其他所有内容(导航、SW 自身、`manifest.json`、图标、根 `/`)采用 network-first 并以缓存兜底。配合生产环境 Express 静态中间件上的显式 `Cache-Control` 头(`/assets/*` 用 `immutable, max-age=31536000`,`index.html`、`sw.js`、`manifest.json` 用 `no-cache, must-revalidate`),重新构建后浏览器中的代码始终自动刷新,无需硬刷新;`client/src/main.tsx` 中的 `controllerchange` 监听器会在新 SW 接管已被控制的页面时恰好重新加载一次(首次安装不会)。VAPID 推送通知管道完全保留。着陆页和维基 SW 预缓存各自的 shell 并在首次访问时延迟缓存图片,单次加载后即可离线访问。所有 manifest 使用 SVG 图标(`favicon.svg`,`sizes="any"`),包含 `apple-mobile-web-app-capable` + `apple-touch-icon` meta 标签以支持 iOS 独立模式 | | **自托管资源(无 CDN)** | 所有字体与脚本均**本地托管,零第三方 CDN 请求**。React 应用通过 `@fontsource` 打包 Inter + JetBrains Mono(latin 子集;由 Vite 输出为带内容哈希的 WOFF2 至 `dist/assets/`)。着陆页与维基加载本地的 `fonts/fonts.css` `@font-face` 样式表(维基用 `../fonts/`)。维基的 Mermaid 改为本地内置(`wiki/mermaid.min.js`,`mermaid@10.9.6`)而非 jsDelivr。VS Code 扩展的错误页改用系统字体栈。移除了所有 `fonts.googleapis.com` / `gstatic` / CDN 调用,因此仪表盘与文档可**完全离线**渲染,不向第三方泄露任何信息 | | **桌面应用(macOS 与 Windows)** | 用 Electron 35 构建的可选原生桌面应用,位于 `desktop/` 工作区,与 `client/`、`server/`、`mcp/`、`vscode-extension/` 平级。以 macOS `.app`(`.dmg`)**以及** Windows `.exe`(NSIS 安装包 + 免安装便携版)形式分发。它将现有的 Express 服务器**以进程内方式嵌入**(直接 `require()` `server/index.js` —— 没有子进程、没有 IPC),并在 `BrowserWindow` 中渲染已构建的 React 客户端。新增了原生标题栏、菜单栏 / 通知区域(托盘)图标(单击其下拉菜单会显示一份在点击时从 SQLite 实时拉取的**状态快照**:会话、Agent、今日事件)、原生应用菜单、开机自启(macOS 通过 `SMAppService` 登录项;Windows 通过按用户的 `HKCU\…\Run`)、一个 **⌘Q / Ctrl+Q 确认对话框**(再按一次即跳过)、关闭窗口只隐藏但服务器继续运行、单实例锁,以及 **在浏览器中打开**、**重启服务器**、**查看日志** 等托盘操作。优先使用端口 4820(回退到 4821–4829,再到随机高位端口),若 4820 上已有健康的 dashboard 在运行则直接采用而不重复绑定,并**与 Web dashboard 共存** —— `npm run dev` 与桌面应用可同时运行,Hook 会同时分发到两者。通知以原生操作系统弹窗(toast)形式触发(Web Push 在 Electron 中无法可靠工作)。首次由应用自有的服务器启动时,它会自动安装 Claude Code Hook 并启动后台服务,因此仅安装应用的用户无需任何手动设置即可让事件流转。详见 [`DESKTOP.md`](./DESKTOP.md) 与 [`desktop/README.md`](./desktop/README.md) | diff --git a/README-ES.md b/README-ES.md new file mode 100644 index 00000000..d1f5d35d --- /dev/null +++ b/README-ES.md @@ -0,0 +1,2308 @@ +# Panel de control del agente para Claude Code + +### Plataforma de monitoreo en tiempo real para la actividad del agente Claude Code 🚀 + +Un panel profesional para rastrear y visualizar sus sesiones de agente Claude Code, el uso de herramientas y la orquestación de subagentes en tiempo real. Construido con Node.js, Express, React y SQLite, se integra directamente con Claude Code a través de su sistema de ganchos nativo para un seguimiento y análisis de sesiones sin problemas. + +![Claude Code](https://img.shields.io/badge/Claude_Code-orange?style=flat-square&logo=claude&logoColor=white) +![Claude Code Plugins](https://img.shields.io/badge/Claude_Code-Plugins_&_Skills-orange?style=flat-square&logo=anthropic&logoColor=white) +![Model Context Protocol](https://img.shields.io/badge/Model_Context_Protocol-1.0-0f766e?style=flat-square&logo=modelcontextprotocol&logoColor=white) +![Node.js](https://img.shields.io/badge/Node.js-%3E%3D20-339933?style=flat-square&logo=node.js&logoColor=white) +![Python](https://img.shields.io/badge/Python-%3E%3D3.6-3776AB?style=flat-square&logo=python&logoColor=white) +![Express](https://img.shields.io/badge/Express-4.21-000000?style=flat-square&logo=express&logoColor=white) +![ws](https://img.shields.io/badge/ws-WebSocket_server-010101?style=flat-square&logo=socketdotio&logoColor=white) +![web-push](https://img.shields.io/badge/web--push-VAPID-3b82f6?style=flat-square&logo=javascript&logoColor=white) +![swagger-ui-express](https://img.shields.io/badge/swagger--ui--express-5.0-85EA2D?style=flat-square&logo=swagger&logoColor=white) +![multer](https://img.shields.io/badge/multer-multipart_upload-FF6B6B?style=flat-square&logo=express&logoColor=white) +![adm-zip](https://img.shields.io/badge/adm--zip-archive_extract-FBBF24?style=flat-square&logo=files&logoColor=white) +![tar](https://img.shields.io/badge/tar-tgz_extract-A78BFA?style=flat-square&logo=gnu&logoColor=white) +![React](https://img.shields.io/badge/React-18.3-61DAFB?style=flat-square&logo=react&logoColor=white) +![TypeScript](https://img.shields.io/badge/TypeScript-5.7-3178C6?style=flat-square&logo=typescript&logoColor=white) +![Javascript](https://img.shields.io/badge/JavaScript-ES6-F7DF1E?style=flat-square&logo=javascript&logoColor=white) +![Vite](https://img.shields.io/badge/Vite-6.1-646CFF?style=flat-square&logo=vite&logoColor=white) +![Tailwind CSS](https://img.shields.io/badge/Tailwind_CSS-3.4-06B6D4?style=flat-square&logo=tailwindcss&logoColor=white) +![PostCSS](https://img.shields.io/badge/PostCSS-8.5-DD3A0A?style=flat-square&logo=postcss&logoColor=white) +![Autoprefixer](https://img.shields.io/badge/Autoprefixer-10.4-DD3735?style=flat-square&logo=autoprefixer&logoColor=white) +![React Router](https://img.shields.io/badge/React_Router-6.28-CA4245?style=flat-square&logo=reactrouter&logoColor=white) +![Lucide](https://img.shields.io/badge/Lucide_Icons-0.474-F56565?style=flat-square&logo=lucide&logoColor=white) +![D3.js](https://img.shields.io/badge/D3.js-7-F9A03C?style=flat-square&logo=d3&logoColor=white) +![Mermaid](https://img.shields.io/badge/Mermaid-10.2-ff3333?style=flat-square&logo=mermaid&logoColor=white) +![i18next](https://img.shields.io/badge/i18next-22.4-7A42FF?style=flat-square&logo=i18next&logoColor=white) +![i18next Language Detector](https://img.shields.io/badge/i18next_Language_Detector-6.1-7A42FF?style=flat-square&logo=i18next&logoColor=white) +![SQLite](https://img.shields.io/badge/SQLite-3-003B57?style=flat-square&logo=sqlite&logoColor=white) +![better--sqlite3](https://img.shields.io/badge/better--sqlite3-11.7-003B57?style=flat-square&logo=sqlite&logoColor=white) +![better-sqlite3 WAL](https://img.shields.io/badge/better--sqlite3-WAL_mode-003B57?style=flat-square&logo=sqlite&logoColor=white) +![WebSocket](https://img.shields.io/badge/WebSocket-RFC_6455-010101?style=flat-square&logo=socketdotio&logoColor=white) +![SSE](https://img.shields.io/badge/SSE-Server_Sent_Events-FF6600?style=flat-square&logo=googlechrome&logoColor=white) +![OpenAPI](https://img.shields.io/badge/OpenAPI-3.0-000000?style=flat-square&logo=openapiinitiative&logoColor=white) +![Swagger](https://img.shields.io/badge/Swagger-3.0-85EA2D?style=flat-square&logo=swagger&logoColor=white) +![VS Code](https://img.shields.io/badge/VS_Code-Extension-007ACC?style=flat-square&logo=vscodium&logoColor=white) +![Electron](https://img.shields.io/badge/Electron-35-47848F?style=flat-square&logo=electron&logoColor=white) +![electron-builder](https://img.shields.io/badge/electron--builder-25.1-2c2e3b?style=flat-square&logo=electron&logoColor=white) +![macOS](https://img.shields.io/badge/macOS-Desktop_App-000000?style=flat-square&logo=apple&logoColor=white) +![Windows](https://img.shields.io/badge/Windows-Desktop_App-0078D6?style=flat-square&logo=windows&logoColor=white) +![SMAppService](https://img.shields.io/badge/SMAppService-Login_Items-000000?style=flat-square&logo=apple&logoColor=white) +![macOS DMG](https://img.shields.io/badge/macOS_DMG-arm64_%2B_x64-7c3aed?style=flat-square&logo=apple&logoColor=white) +![NSIS Installer](https://img.shields.io/badge/Windows-NSIS_%2B_Portable-1f6feb?style=flat-square&logo=windows&logoColor=white) +![Vitest](https://img.shields.io/badge/Vitest-1.0-646CFF?style=flat-square&logo=vitest&logoColor=white) +![React Testing Library](https://img.shields.io/badge/React_Testing_Library-13.0-FF5733?style=flat-square&logo=testinglibrary&logoColor=white) +![ESLint](https://img.shields.io/badge/ESLint-8.44-4B32C3?style=flat-square&logo=eslint&logoColor=white) +![Prettier](https://img.shields.io/badge/Prettier-3.8-F7B93E?style=flat-square&logo=prettier&logoColor=white) +![Docker](https://img.shields.io/badge/Docker-20.10-2496ED?style=flat-square&logo=docker&logoColor=white) +![Podman](https://img.shields.io/badge/Podman-4.0-CC342D?style=flat-square&logo=podman&logoColor=white) +![Prometheus](https://img.shields.io/badge/Prometheus-2.x-E6522C?style=flat-square&logo=prometheus&logoColor=white) +![Grafana](https://img.shields.io/badge/Grafana-10.x-F46800?style=flat-square&logo=grafana&logoColor=white) +![Terraform](https://img.shields.io/badge/Terraform-%3E%3D1.5-844FBA?style=flat-square&logo=terraform&logoColor=white) +![Kubernetes](https://img.shields.io/badge/Kubernetes-%3E%3D1.24-326CE5?style=flat-square&logo=kubernetes&logoColor=white) +![Helm](https://img.shields.io/badge/Helm-3-0F1689?style=flat-square&logo=helm&logoColor=white) +![Kustomize](https://img.shields.io/badge/Kustomize-5.0-326CE5?style=flat-square&logo=kubernetes&logoColor=white) +![Nginx](https://img.shields.io/badge/Nginx-Ingress-009639?style=flat-square&logo=nginx&logoColor=white) +![Coralogix](https://img.shields.io/badge/Coralogix-Observability-1a1a2e?style=flat-square&logo=datadog&logoColor=white) +![OpenTelemetry](https://img.shields.io/badge/OpenTelemetry-Collector-4f46e5?style=flat-square&logo=opentelemetry&logoColor=white) +![AWS](https://img.shields.io/badge/AWS-ECS%20%7C%20RDS-232F3E?style=flat-square&logo=task&logoColor=white) +![Google Cloud](https://img.shields.io/badge/Google_Cloud-GKE%20%7C%20SQL-4285F4?style=flat-square&logo=googlecloud&logoColor=white) +![Azure](https://img.shields.io/badge/Azure-AKS%20%7C%20SQL-0078D4?style=flat-square&logo=cloudflare&logoColor=white) +![Oracle Cloud](https://img.shields.io/badge/Oracle_Cloud-OKE%20%7C%20DB-F80000?style=flat-square&logo=cloudways&logoColor=white) +![GitHub Actions](https://img.shields.io/badge/GitHub_Actions-pipelines-2088FF?style=flat-square&logo=githubactions&logoColor=white) +![GitLab CI](https://img.shields.io/badge/GitLab_CI-pipelines-FC6D26?style=flat-square&logo=gitlab&logoColor=white) +![Make](https://img.shields.io/badge/Make-4.3-000000?style=flat-square&logo=make&logoColor=white) +![Auto Release](https://img.shields.io/badge/CI-auto--release_to_GitHub-22c55e?style=flat-square&logo=githubactions&logoColor=white) +![MIT License](https://img.shields.io/badge/License-MIT-yellow?style=flat-square) + +> [!TIP] +> Consulta también [README.md](./README.md) (English), [README-CN.md](./README-CN.md) (中文), [README-VN.md](./README-VN.md) (Tiếng Việt) y [README-KO.md](./README-KO.md) (한국어). Este es el README en español. + +--- + +## Índice de contenidos + +- [Visión general](#resumen-general) +- [Internacionalización (i18n)](#internacionalización-i18n) +- [Funciones](#características) +- [Inicio rápido](#inicio-rápido) +- [Cómo funciona](#cómo-funciona) +- [Configuración](#configuración) +- [Scripts npm](#scripts-npm) +- [Mercado de complementos](#mercado-de-complementos) +- [Extensión de agentes](#extensión-de-agentes) +- [Integración MCP](#integración-mcp) +- [Referencia de API](#referencia-de-api) +- [Eventos de conexión](#eventos-de-enganchamiento) +- [Notificaciones del navegador](#notificaciones-del-navegador) +- [Notificador de actualización](#notificador-de-actualización) +- [Tabby — Compañero de gato flotante](#tabby--compañero-de-gato-flotante) +- [Modal de estado de conexión](#modal-de-estado-de-conexión) +- [Extensión de VS Code](#extensión-de-vs-code) +- [Aplicación para escritorio (macOS y Windows)](#aplicación-de-escritorio-macos-y-windows) +- [Almacenamiento de datos](#almacenamiento-de-datos) +- [Línea de estado](#línea-de-estado) +- [Arquitectura del servidor](#arquitectura-del-servidor) +- [Routing del cliente](#enrutamiento-del-cliente) +- [Flujo del gestor de ganchos](#flujo-del-gestor-de-ganchos) +- [Modos de despliegue](#modos-de-despliegue) +- [Estructura del proyecto](#estructura-del-proyecto) +- [Solución de problemas](#solución-de-problemas) +- [Contribuyendo](#contribuyendo) +- [Licencia](#licencia) + +--- + +## Resumen general + +Realice sesiones de seguimiento, supervise a los agentes en tiempo real, visualice el uso de las herramientas y observe la orquestación de subagentes a través de una interfaz web profesional con tema oscuro. Se integra directamente con Claude Code a través de su sistema de ganchos nativo. + +```mermaid +graph LR + A["Claude Code
Session"] -->|hooks fire on
tool use / stop| B["Hook Handler
(Node.js script)"] + B -->|HTTP POST| C["Dashboard Server
(Express + SQLite)"] + C -->|WebSocket
broadcast| D["Dashboard UI
(React + Tailwind)"] + style A fill:#6366f1,stroke:#818cf8,color:#fff + style B fill:#1a1a28,stroke:#2a2a3d,color:#e4e4ed + style C fill:#1a1a28,stroke:#2a2a3d,color:#e4e4ed + style D fill:#10b981,stroke:#34d399,color:#fff +``` + +Además del panel de control de monitoreo en tiempo real, también incluye una implementación local del servidor MCP en `mcp/` que expone un catálogo de herramientas para introspeccionar y gestionar el propio panel de control, lo que facilita la integración de las operaciones del panel de control directamente en sus flujos de trabajo de Claude Code. También hay una capa de extensión de agentes, que proporciona complementos, habilidades y subagentes de Claude Code para la interacción del panel de control, el análisis y la inteligencia de los flujos de trabajo. + +### Internacionalización (i18n) + +La interfaz de usuario incluye selección de idioma para inglés (`en`), chino (`zh`), vietnamita (`vi`), coreano (`ko`) y español (`es`). El selector personalizado en forma de menú desplegable evita que la barra lateral se sature a medida que se agregan idiomas. Los recursos se cargan por espacio de nombres y la preferencia se conserva en el almacenamiento del navegador entre actualizaciones. + +```mermaid +flowchart LR + A["El usuario selecciona un idioma
en / zh / vi / ko / es"] --> B["Detector i18next
localStorage -> navigator"] + B --> C["Idioma resuelto
alternativa: en"] + C --> D["Recursos por espacio de nombres
common/nav/dashboard/..."] + D --> E["Hooks React useTranslation"] + E --> F["IU y etiquetas de accesibilidad traducidas"] +``` + +Para obtener una guía completa de arquitectura y funcionamiento, consulte [docs/I18N.md](./docs/I18N.md). + +### Interfaz de usuario + +Vino con un elegante tema oscuro, diseño responsive y navegación intuitiva para explorar tu actividad de agente: + +

+Visión general del panel de control +
+📡 Panel de control · Monitor — estadísticas generales, tarjetas de agentes activos y feed de actividad reciente +

+ +

+Panel de control — Pestaña Estado del sistema +
+🩺 Panel de control · Salud — anillo de puntuación de salud compuesto, gráfico de donas del motor de almacenamiento, indicadores de éxito / error / éxito de la caché, barras de invocación de herramientas, eficacia del subagente, distribución de tokens del modelo y estadísticas de compactación — todo se actualiza automáticamente cada 5 s +

+ +

+Tablero Kanban — Vista de los agentes +
+📋 Tablero Kanban (agentes) — agentes agrupados por estado en 4 columnas: Trabajando / Esperando / Completado / Error. La columna amarilla Esperando muestra las sesiones bloqueadas por la entrada del usuario (peticiones de permiso, finalización de turno o en una nueva solicitud) — pasa el cursor sobre una insignia Esperando para ver por qué (Necesita entrada / Turno terminado / En solicitud / Interrumpido). Cada tarjeta muestra el modelo, el coste y la herramienta actual de un vistazo. +

+ +

+Tablero Kanban — Vista de sesiones +
+🗂️ Tablero Kanban (sesiones) — sesiones agrupadas por estado en 5 columnas: Activo / Esperando / Completado / Error / Abandonado, puede cambiarse desde la misma página. Haga clic con el botón derecho del ratón en cualquier encabezado de columna para ver una herramienta de ayuda que explica la transición del ciclo de vida. +

+ +

+Resumen de sesiones +
+📂 Sesiones — tabla de búsqueda, filtrable y paginada por servidor de todas las sesiones grabadas con costo, modelo, número de agentes y duración +

+ +

+Detalles de la sesión — Pestaña Agentes +
+🤖 Detalles de la sesión · Agentes — baldosas de visión general en tiempo real (eventos, llamadas de herramientas, subagentes, compactaciones, errores, duración), barras de uso de herramientas principales, desglose del tipo de subagente, flujo de tokens y el árbol jerárquico del agente +

+ +

+Detalles de la sesión — Pestaña Conversación +
+💬 Detalles de la sesión · Conversación — visualizador de transcripciones en vivo con renderizado de markdown, bloques de código resaltados por sintaxis (números de línea + copia), llamadas de herramientas estilizadas por herramienta, píldoras de comandos con guiones con su salida TUI capturada y marcadores de renombramiento de sesiones en línea +

+ +

+Detalles de la sesión — Pestaña Línea de tiempo +
+🔬 Detalle de sesión · Línea de tiempo — línea de tiempo cronológica de eventos con filtros multidimensionales, agrupación pre/post por `tool_use_id` y representadores de carga útiles según la herramienta +

+ +

+Resumen del feed de actividad +
+📰 Feed de actividad — registro de eventos en tiempo real con pausa / continuar, agrupación, filtros multidimensionales y un botón de salto "Sesión →" por fila +

+ +

+Visión general de análisis +
+📊 Análisis — uso de tokens por modelo, frecuencia de herramientas, mapa de calor de actividad y tendencias de sesiones con indicador en vivo / sin conexión +

+ +

+Visión general de los flujos de trabajo +
+🔀 Flujos de trabajo — DAGs de orquestación de agentes, diagramas Sankey de ejecución de herramientas, redes de colaboración y 11 secciones interactivas de inteligencia de flujo de trabajo +

+ +

+Flujo de trabajo dinámico se ejecuta en la página de flujos de trabajo +
+🧬 Ejecuciones de flujo de trabajo (página de flujos de trabajo) — "flujos de trabajo dinámicos" generados por la herramienta Workflow, reconstruidos a partir de los registros de ejecución en disco: estado, número de agentes, tokens y llamadas a la herramienta, expandibles en un desglose por agente (fase, estado, tokens, herramientas, duración) con vistas preliminares de resultados humanizados +

+ +

+Flujo de trabajo dinámico ejecutado ampliado con filtros de fase y resultados por agente +
+🧬 Ejecuciones de flujo de trabajo · expandido — una ejecución abierta: filtros de fase codificados por color interactivos, la tabla de métricas por agente y una lista completa de elementos de resultado interactivos que se expanden a la solicitud completa y el resultado de cada agente +

+ +

+Flujo de trabajo dinámico se ejecuta en la página de detalles de la sesión +
+🧬 Ejecuciones de flujo de trabajo (detalles de la sesión) - las mismas flotas vinculadas a su sesión de lanzamiento, por lo que los subagentes del flujo de trabajo dinámico de una sesión y su costo de token incorporado son visibles en línea +

+ +

+Explorador de configuración de Claude +
+🧰 Explorador de Configuración de Claude — Inspector de 12 pestañas para todo lo que Claude Code sabe: habilidades, subagentes, comandos de guión, estilos de salida, plugins (con contribuciones por plugin), mercados, servidores MCP, ganchos, configuraciones (con redacción de clave secreta), memoria (los archivos del usuario + proyecto `CLAUDE.md` más el almacenamiento de memoria basado en archivos por proyecto — cada `*.md` bajo `~/.claude/projects//memory/`, agrupados por proyecto y buscables, con enlaces de índice `MEMORY.md` clicables que saltan al archivo de hechos correspondiente), asociaciones de teclas (con un editor estructurado inline) y línea de estado. Crear / editar / eliminar en superficies de bajo riesgo — los artefactos de archivos de texto, los archivos de memoria automática por proyecto y `keybindings.json` — con copias de seguridad con hora y fecha obligatorias +

+ +

+Explorador de Configuración de Claude — Pestaña Habilidades +
+🧩 Explorador de Configuración de Claude · Habilidades — la pestaña Habilidades enumera todas las habilidades descubiertas (usuario, proyecto y complemento) con su descripción y fuente, se puede buscar en todo el conjunto y abre cualquier archivo de habilidad para una edición segura respaldada por una hora y fecha +

+ +

+Ejecutar Claude — configuración previa a la ejecución +
+▶️ Ejecuta Claude — genera subprocesos claude justo dentro del panel de control. Elige el modo (Conversación / Único disparo), la fuente (nueva sesión vs. continuar desde tu historial completo), el directorio de trabajo (completa automáticamente con los cwds recientes), el modelo, el modo de permiso y el esfuerzo de pensamiento. La guardia de origen compartido evita que el navegador genere subprocesos de forma pasiva +

+ +

+Ejecutar Claude — salida de transmisión en vivo +
+💬 Ejecuta Claude · transmisión en vivo — salida de transmisión en estilo chat con renderizado real de carácter en carácter a través de --include-partial-messages. Las herramientas de uso, los resultados de las herramientas y los bloques de pensamiento son todos colapsables. El interruptor de ejecuciones activas en el encabezado le permite dejar una ejecución en segundo plano y volver a adjuntarla más tarde. "Ver sesión →" hace un enlace profundo a la interfaz de usuario de Sesiones estándar tan pronto como se conoce el ID de la sesión +

+ +

+Visión general de la configuración +
+⚙️ Configuración — reglas de precios del modelo, estado de instalación del gancho, gestión de datos, preferencias de notificación e información del sistema +

+ +

+Configuración — Alertas y Webhooks +
+🔔 Configuración · Alertas — motor de alertas basado en reglas y webhooks de salida en un solo lugar: reglas de alerta (patrón de eventos / inactividad / agente atascado / umbral de token) con tiempo de espera por regla, un feed de alertas lanzadas en vivo y 14 proveedores de webhook de primera clase (Slack, Discord, Teams, Google Chat, Mattermost, Rocket.Chat, Telegram, PagerDuty, Opsgenie, Splunk On-Call, Zapier, Make, n8n, Pipedream) además de un punto final JSON genérico con firma HMAC opcional +

+ +

+Configuración — Fuentes de datos remotas +
+🛰️ Configuración · Fuentes de datos remotas — obtenga la actividad de Claude Code de otras máquinas a través de SSH: agregue fuentes por destino, pruebe la conectividad, sincronice manualmente o en un monitor de fondo y cambie el alcance global de los datos entre local, todas las fuentes o una máquina específica, con insignias de fuente por sesión +

+ +La barra lateral proporciona acceso rápido al Panel de control, la Tablero Kanban, la lista de Sesiones, el Feed de Actividades, las Análisis, los Flujos de trabajo y la Configuración. Cada página está diseñada para brindarle información profunda sobre la actividad de su agente Claude Code con actualizaciones en tiempo real y visualizaciones ricas. + +--- + +## Características + +El panel de control ofrece un conjunto completo de funciones para monitorear y analizar sus sesiones y agentes de Claude Code: + +> **Sesiones del cursor también (informativas):** CCAM ingiere cualquier transcripción del agente que caiga bajo `~/.claude` - en esta máquina y en los remotos sincronizados. El uso del **Cursor** se cuenta de la misma manera: el **Cursor** por casualidad almacena sus sesiones del agente en esos archivos junto con el Código Claude. CCAM no distingue qué aplicación escribió un archivo. + +| Característica | Descripción | +|------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| **Panel de control** | Dos pestañas persistieron en `localStorage`: **Monitor** — estadísticas generales (6 tarjetas estadísticas), tarjetas de agentes activos con jerarquía de subagentes colapsables y feed de actividad reciente con conteos dinámicos de elementos que llenan la altura disponible de la ventana de visualización a través de `ResizeObserver`. **Salud** — anillo de puntuación de salud del sistema compuesto (pesado: 0,4 × tasa de éxito + 0,25 × tasa de éxito de la caché + 0,25 × (100 − tasa de error) + 0,1 × (100 − % de la pila)), gráfico de donut del motor de almacenamiento con distribución de registros, medidores de rendimiento de la caché / tasa de error / tasa de éxito, gráfico de barras horizontal de invocación de herramientas (8 principales), barras de eficacia de subagentes, distribución de tokens del modelo y estadísticas de impacto de la compactación. Todas las métricas de salud se actualizan automáticamente cada 5 s desde `/api/settings/info` y `/api/workflows`. Etiquetas de herramientas de seguimiento del cursor con detección de bordes de la ventana de visualización en todos los gráficos | +| **Tablero Kanban** | Dos vistas con un alternador de encabezado (persistente en `localStorage`): **Agentes** — 4 columnas (Trabajando / Esperando / Completado / Error) — y **Sesiones** — 5 columnas (Activa / Esperando / Completado / Error / Abandonada). La columna **Esperando** se asigna directamente al estado persistente de "esperando" en los agentes, que se establece cuando Claude Code está en una solicitud (sesión nueva, entre turnos o bloqueado por una notificación de permiso) y pasa a "trabajando" en el momento en que el usuario vuelve a iniciar (UserPromptSubmit / PreToolUse). Cada encabezado de columna muestra una leyenda de herramientas `?` que explica las transiciones del ciclo de vida. Las tarjetas se obtienen por estado persistente del servidor (efectivamente ilimitadas por estado), luego se paginan en el lado del cliente a 10 tarjetas por columna con una opción "Mostrar más". Los escenarios de suscripción de WS se limitan a la vista activa (marcos `agent_*` vs `session_*`), por lo que las actualizaciones fuera de la vista no desencadenan nuevas recuperaciones. Los insignias de espera exponen el `awaiting_reason` de la fila como una leyenda de hover - **Necesita entrada** (`notification`), **Convertir a terminado** (`stop`), **En el mensaje** (`session_start`), **Interrumpido** (`interrupted`) - manteniéndose solo la leyenda de hover en las tarjetas compactas para que los títulos mantengan su espacio; las superficies más anchas (tabla de Sesiones, encabezado de detalles de sesión) además muestran la razón en línea como un chip anidado, con razones urgentes (mensajes de permiso, interrupciones) en un ámbar más cálido | +| **Sesiones** | Tabla **paginada por servidor**, buscable y filtrable de todas las sesiones registradas. Cada clic en una página hace que se acceda a `/api/sessions?status=&q=&limit=10&offset=…`, por lo que el cálculo de costos solo se realiza sobre la página visible, independientemente de cuántas sesiones existan en la base de datos. La caja de búsqueda (`q=`) realiza coincidencias insensible a mayúsculas y minúsculas entre `id` / `name` / `cwd` en el servidor con un retraso de 300 ms, y la respuesta lleva un conteo `total` para la interfaz de usuario del paginador. Composición de filtro de estado, búsqueda y paginación. El **nombre** legible por humanos de cada sesión se lee de la transcripción y se mantiene sincronizado en tiempo real, una vez que un título explícito de `/rename`, `claude -n` o el `Ctrl+R` del seleccionador (la línea `custom-title` de JSONL) siempre gana, de lo contrario el `ai-title` generado automáticamente se completa, de lo contrario el **primer mensaje de usuario** de la sesión (cortado, con el ruido del resultado de la herramienta / comando de guión roto) completa el nombre de lugar de almacenamiento y el nombre/tarea de lugar de almacenamiento del agente principal, por lo que las sesiones que nunca reciben un título (incluidas las importadas) todavía dicen lo que están haciendo; el panel de control muestra ese nombre (volviendo al ID corto) en las tarjetas, el Panel de Control, el Feed de Actividades y el seleccionador de inicio de sesión de Ejecución. | +| **Detalles de la sesión** | Panel de visión general en tiempo real por sesión con banner de agente activo (herramienta actual + tarea), seis contadores de cuadros (eventos con tasa de eventos/min, llamadas de herramientas, subagentes, compactaciones, errores, duración del tic-tac), barras de uso de herramientas principales, desglose del tipo de subagente, tira de flujo de tokens apilada y nube de píldoras de tipo de evento, todo actualizado en vivo en eventos conectados. Debajo de él: árbol jerárquico de agentes, cronología completa del evento con filtros multidimensionales (estatus, tipo de evento, herramienta, agente, búsqueda de texto, rango de fechas), agrupación Pre/Post por `tool_use_id`, bloque de resumen legible por humanos, renderizadores de entrada/respuesta conscientes de herramientas (terminal para Bash, diferencia unificada para Editar, código numerado por línea para Leer/Escribir, lista de coincidencias para Grep, tarjeta clave/valor para herramientas MCP) y una pestaña de Conversación que renderiza transcripciones, incluidas las mensajes escritos a mitad de turno (en cola mientras Claude seguía trabajando), colocados donde Claude los recibió realmente, con notificaciones de arnés atribuidas al Sistema, con markdown (encabezados, listas, citas entre comillas, tablas, listas de tareas), bloques de código resaltados por sintaxis (js/ts, python, json, bash, html, css, sql, yaml, diff) con números de línea y copia al portapapeles, y llamadas de herramientas estilizadas por herramienta (Bash → terminal, Editar → Junto a lado antiguo/nuevo, Escribir → etiqueta de archivo, Leer → chip de ruta, Grep → tarjeta de patrón). Cuando la sesión se bloquea en el humano, un banner amarillo **esperando-entrada** debajo del encabezado nombra el `awaiting_reason`, su explicación y cuánto tiempo ha estado esperando la sesión (punto pulsante + tiempo relativo); el distintivo de Esperando del encabezado lleva la misma razón que un chip anidado | +| **Feed de actividad** | Registro de eventos de transmisión en tiempo real con pausa/resume, filtros multidimensionales (mismo panel de herramientas que el Detalles de sesión más un filtro de sesión), paginación "Cargar más" impulsada por el servidor, actualización en vivo con filtro sensible a los retrasos que preserva el tamaño de la página cargada, alternancia de agrupación, prefijo de origen que muestra proyecto › sesión › subagente y un botón "Sesión →" por fila | +| **Análisis** | Uso de tokens, frecuencia de herramientas, mapa de calor de actividad (centrado, alineado con el día de la semana a partir del domingo, pestañas de herramientas con el nombre del día), tendencias de sesiones, indicador de conexión en vivo/desconectada. Mientras se carga el contenido de la carga útil de análisis, la región del gráfico (no solo las baldosas estadísticas) muestra **marcos de lugar de esqueleto pulsantes** que reflejan la disposición del gráfico, por lo que la página nunca muestra gráficos vacíos/nulos | +| **Actualizaciones en vivo** | WebSocket push -- sin consultas, actualizaciones instantáneas de la interfaz de usuario | +| **Auto-Descubrimiento** | Las sesiones y los agentes se crean automáticamente a partir de eventos de conexión | +| **Importación de historial** | Importa sesiones de `~/.claude/` al iniciar la sesión. Extracción JSONL mejorada: errores de API (cuota/tarifa/solicitud_invalida), duraciones de turno, punto de entrada (cli/sdk-ts), modos de permiso, conteos de bloqueos de pensamiento, extras de uso (servicio_tier, velocidad, inferencia_geo), errores de resultados de herramientas y archivos JSONL de subagentes (`subagents/agent-*.jsonl` con `.meta.json`). Reabastece sesiones existentes al volver a importar. Los archivos JSONL recientes (< 10 min) se importan como "activos" | +| **Hierarquía de subagentes** | Árbol de agentes padre-hijo colapsible en el Panel de control y en los Detalles de la sesión. Los agentes con subagentes muestran flechas de expansión/colapso; los agentes hojas muestran un indicador de punto. Se expande automáticamente cuando los subagentes están activos | +| **Agentes de fondo** | Rastrea correctamente a los subagentes con antecedentes sin completar prematuramente | +| **Atribución de herramientas del subagente** | Las llamadas de herramientas internas del subagente (Leer, Bash, Editar, Grep, ...) solo están disponibles en archivos JSONL por subagente, y Claude Code no emite ningún gatillo para ellas. En cada `SubagentStop`, el panel de control dispara un paso `scanAndImportSubagents` de "fuego y olvido" que analiza cada `subagents/agent-*.jsonl`, empareja los bloques `tool_use` con sus correspondientes `tool_result` por `tool_use_id`, y emite eventos `PreToolUse` + `PostToolUse` bajo el propio `agent_id` del subagente. Idempotente (`data LIKE '%"tool_use_id":"X"%'` deduplicación) y se fusiona en una fila subagente creada en vivo por un gancho cuando una coincide por tipo + hora de inicio dentro de los 30 segundos, por lo que no se crean filas paralelas `-jsonl-*`. El mismo camino se ejecuta en la importación de inicio de `npm run setup` para un relleno histórico completo: las sesiones que preceden al panel de control obtienen plazos de herramientas completos por subagente. El Feed de Actividades y los Detalles de Sesión muestran la cadena padre como `principal › codificador › explorador` para los subagentes anidados. Esa cadena se reconstruye de forma autorizada por `reconcileSubagentParents`: primero se inserta una fila de subagente plana debajo del agente principal (un solo evento de gancho o archivo JSONL no lleva identidad de generador), luego se recupera el generador del resultado de la herramienta Task de cada transcripción de subagente (`toolUseResult.agentId`, capturado como `spawnedChildren`), por lo que un subagente que genera sus propios subagentes se anida bajo su generador **real** en lugar de colapsar a un solo nivel bajo el principal. Idempotente y aditivo: solo repunta el `parent_agent_id`, nunca inserta ni elimina filas y se ejecuta en la misma escaneo de `SubagentStop`, que devuelve un conteo `reparented`, por lo que el panel de control vuelve a recuperar los datos incluso cuando la re-parentación sola cambió la forma del árbol | +| **Seguimiento de costos** | Estimación de costos por modelo con reglas de precios configurables y desgloses por sesión. Admite **tarifas introductorias con tiempo limitado** (`intro_*` + `intro_until` en una regla de precios): el uso a partir/antes de la fecha límite se cobra a la tarifa introductoria y el uso después de ella a la tarifa estándar, por lo que una promoción como el descuento de lanzamiento de Claude Sonnet 5 (hasta el 31-08-2026) se mantiene correcta para el uso histórico **y** futuro: los precios finales de costo cobran el uso de cada día a la tarifa efectiva en esa fecha. **Las tarifas introductorias son completamente editable en Configuración**: el editor de Precios del Modelo muestra una fecha límite de promoción más los precios introductorios por categoría (entrada / salida / lectura de caché / escritura de caché 5m y 1h), por lo que una promoción futura para el lanzamiento de un modelo no necesita ningún cambio de código, solo una edición. **Las tarjetas de subagentes muestran el COSTE PROPIO de cada subagente** (derivado del uso del token de transcripción de ese subagente y con un precio a las tasas actuales), no el total de la sesión, una tarjeta de agente principal representa toda la sesión y muestra el total de la sesión, mientras que una tarjeta de subagente solo muestra lo que ese subagente gastó, por lo que una tarjeta de subagente ya no se lee engañosamente como si hubiera costado toda la sesión. La contabilidad de tokens consciente de la compactación preserva los totales a través de las compresiones de contexto. Las lecturas de la transcripción se almacenan en caché con actualizaciones incrementales de desplazamiento de bytes para una extracción eficiente de tokens | +| **Cache de transcripciones** | Extracción en tiempo real de transcripciones JSONL: tokens, compactaciones, errores de API (entradas `isApiErrorMessage` almacenadas como eventos `APIError`), duraciones de turno (almacenadas como eventos `TurnDuration`), conteos de bloques de pensamiento y extras de uso (service_tier, velocidad, inference_geo). Las matrices crecientes por entrada se acaban en la cola en `TRANSCRIPT_CACHE_MAX_ARRAY_LEN` (por defecto `1000`, configurable) tanto durante la parseación como al finalizar, por lo que incluso una sesión que se ejecuta durante días no puede crecer una sola entrada de caché sin límites. Cada entrada solo almacena `{mtimeMs, size, bytesRead, result}`, por lo que no hay una copia de sombra de los mismos datos tanto en el nivel superior como dentro de `result`. Los metadatos de la sesión se enriquecen con estos campos en tiempo real | +| **Notificaciones** | Pipe de Web Push completo (VAPID) para una entrega fiable. Llegue incluso cuando la pestaña esté en segundo plano o el navegador esté cerrado. Configurado explícitamente para el soporte de audio de macOS. Intercambios configurables por evento con gestión de suscripciones | +| **Alertas** | Motor de alertas basado en reglas — configurado completamente en **Configuración → Alertas y notificaciones**, un centro de control de **Reglas / Canales / Actividad** con pestañas (sin página separada). Define reglas de alerta con cuatro tipos de condiciones: **patrón de eventos** (correspondencia con el tipo de evento / nombre de la herramienta / texto de resumen, opcionalmente requiriendo N eventos coincidentes dentro de una ventana de tiempo, por ejemplo, "más de 5 errores en 2 minutos"), **inactividad** (sesión activa sin eventos durante N minutos), **agente atascado** (agente sentado en `trabajando`/`esperando` sin actividad durante N minutos) y **umbral de tokens** (total de tokens de la sesión que superan un límite). Las reglas basadas en eventos evalúan el lado del servidor en cada ingestión de gancho (después de la transacción de ingestión, la alerta nunca puede ralentizar o fallar la entrega del gancho); las reglas basadas en el tiempo se ejecutan en un escaneo de 60 s. Las alertas lanzadas se persisten en `alert_events` con **deduplicación de tiempo de espera** por regla + por sesión (por defecto 300 s), se transmiten como mensajes WebSocket `alert_triggered` y aparecen en el feed en vivo de la pestaña **Actividad** con confirmación / confirmación-todo, un filtro solo para no confirmados y enlaces "Ver sesión" por alerta. El soporte de reglas permite habilitar/deshabilitar el alternar y cascadenar su historial al eliminarlo. Las alertas lanzadas también se extienden a **objetivos webhook universales** configurados en la pestaña **Canales**: **14 proveedores de primera clase** más un punto final genérico: **Slack**, **Discord**, **Microsoft Teams**, **Google Chat**, **Mattermost**, **Rocket.Chat** (carga útil de chat nativa); **Telegram** (API de bots), **PagerDuty** (API de eventos v2), **Opsgenie** (API de alertas + autenticación GenieKey), **Splunk On-Call** (VictorOps REST); y **Zapier**, **Make**, **n8n**, **Pipedream** o cualquier punto final **genérico** (envelope JSON limpio con firma opcional **HMAC-SHA256** y encabezados personalizados). Cada proveedor se describe por un registro del lado del servidor que declara su formateador de carga útil, cómo se resuelve su URL (algunos la derivan de las credenciales, por ejemplo Telegram del token del bot, Opsgenie de la región, y otros lo establecen por defecto), y qué campos de credenciales renderiza la interfaz de usuario. Los objetivos admiten el alcance opcional por regla, una sonda "Enviar prueba" sincrónica y un registro de entrega grabado. La entrega se ejecuta separada del camino de alerta con un tiempo de espera de solicitud y un retry/backoff limitado, por lo que nunca puede ralentizar o bloquear el monitoreo; las URL de destino, los secretos y los campos de credenciales se almacenan en el lado del servidor y nunca se devuelven por la API (ocultados/redactados en cada respuesta) | +| **Notificador de actualización** | El servidor ejecuta periódicamente un `git fetch` no bloqueante y compara la salida local con `origin/master`/`origin/main`/`origin/HEAD`. Cuando el origen está por delante, la interfaz de usuario muestra un modal con el comando exacto `git pull && npm run setup` y un botón **Copiar** con un solo clic; la barra lateral obtiene un botón persistente "Comprueba actualizaciones" con un distintivo en vivo. El panel nunca se actualiza ni se reinicia por sí mismo, ya que el usuario ejecuta el comando en un terminal, por lo que el mecanismo no puede interrumpir las sesiones de desarrollo, la supervisión de pm2/systemd/Docker ni dejar procesos huérfanos | +| **Configuración** | Información del sistema, estado del gancho, gestión de precios del modelo, preferencias de notificación, exportación **y restauración** de datos (el modo **Restaurar copia de seguridad** del panel de Historial de Importación reimporta una exportación completa `.json` — idempotente y no destructiva, por lo que puede consolidar el historial de varias máquinas en un solo panel de control), limpieza de sesiones. La sección de Precios del Modelo expone una ventana emergente de información (el icono `i` junto al título) que explica cómo funciona la búsqueda de reglas (el patrón que coincida primero gana), la sintaxis de carácter wildcard `%` al estilo SQL con ejemplos concretos (`claude-opus-4-7%`, `claude-%-haiku`, ids exactos), y que los precios deben actualizarse manualmente cuando Anthropic publique nuevas tarifas: las sesiones ya almacenadas mantienen el precio aplicado en el momento de la ingestión. El editor de cada regla también lleva un bloque **Tarifas introductorias** plegable (un límite promocional de `AAAA-MM-DD` + precios introductorios por categoría); dejar la fecha vacía significa que no hay promoción, y una fecha vacía borra cualquier tarifa introductoria almacenada. La caja CLAUDE_HOME y el panel de historial de importaciones están completamente impulsados por i18n en en/vi/zh | +| **Servidor MCP (Local)** | Servidor MCP local de grado empresarial en `mcp/` con tres modos de transporte (stdio, HTTP+SSE, REPL interactivo), 25 herramientas de tipo en 6 dominios, esquemas de entrada estrictos, retry/backoff, aplicación de la API solo en localhost y puertas de seguridad de mutación/destructiva por niveles. El modo HTTP sirve HTTP transmisible (25-11-2025) y SSE heredado (05-11-2024) en puerto configurable. El modo REPL proporciona invocación interactiva de herramientas completadas con pestañas con salida coloreada | +| **Flujos de trabajo** | Página de visualización impulsada por D3.js con 11 secciones interactivas: DAG de orquestación de agentes, diagrama Sankey de ejecución de herramientas, red de colaboración, eficacia de subagentes (sparklines del día de la semana con herramientas de ayuda renderizadas por el portal que se salen del `overflow:hidden` de la tarjeta y se ajustan a la ventana de visualización para que nunca se recorten), patrones de flujo de trabajo detectados, flujo de delegación de modelos, mapa de propagación de errores (barras horizontales con insignias de tasa, desglose del tipo de agente, tarjetas de error API/sesión), línea de tiempo de concurrencia, dispersión de complejidad de sesión, análisis de impacto de compactación (rediseñado como un histograma claro de "sesiones por número de compactación" con títulos de ejes, baldosas estadísticas: total / sesiones afectadas / promedio / pico - una línea de ayuda explicativa y herramientas de ayuda de desplazamiento sobre la barra), y análisis detallado por sesión. El subtítulo alineado a la derecha de cada sección se sujeta a una sola línea (apóstrofe + título de resaltado) para que una larga traducción nunca envuelva el encabezado. **Rich, herramientas de ayuda con i18n en todas partes:** el título de la sección de cada gráfico lleva un icono `i` que abre una ventana emergente estructurada "Qué muestra esto / Cómo leerlo / Por qué es importante"; haciendo clic con el ratón sobre nodos, bordes, barras y superficies de burbujas se muestran herramientas de ayuda multiescénicas con interpretaciones deterministas y dependientes del valor (por ejemplo, porcentajes de participación en el código fuente / en el objetivo, cuencos de salud de tasa de éxito, descripciones familiares para Opus / Sonnet / Haiku, patrones de tiempo como cargado por adelantado / en el medio de la sesión / cargado por detrás). Cada una de las seis tarjetas estadísticas principales tiene un popover de información en la parte inferior derecha que explica cómo se calcula la métrica y qué significa su valor actual en lenguaje sencillo. Las herramientas de ayuda se mutan en el DOM a través de una sola referencia por gráfico con fallback de `mouseleave` a nivel de contenedor, por lo que nunca se quedan atrás del cursor o se quedan pegados después de la re-renderización. Hacer clic en una fila en **Patrones de flujo de trabajo detectados** expande un panel de detalles en el lugar con la secuencia completa de pasos, la cuadrícula de estadísticas, una narrativa determinista (detección de bucle, cubeta de frecuencia) y una sugerencia práctica. Las pestañas de filtro de estado (Solo activo / Terminado / Todo) filtran todas las 11 secciones. Filtrado cruzado, exportación JSON y actualización automática de WebSocket en tiempo real con retraso de 3 segundos. Una superficie del panel **Workflow Runs** muestra "procesos de trabajo dinámicos", las flotas de subagentes generados por la herramienta `Workflow` (y `/loop` a ritmo propio) que no emiten ningún gancho y que se reconstruyen en su lugar a partir de los registros de ejecución en disco (`workflows/wf_.json`): cada ejecución muestra sus fases y una desglose por token / llamada de herramienta / duración por agente, con detección en vivo de `ejecución` antes de que se escriba el registro y una subsección vinculada en cada página de Detalles de Sesión | +| **Seguimiento de compactación** | Detecta eventos `/compact` de transcripciones JSONL, crea agentes y eventos de compactación. Reemplaza las compactaciones heredadas al arrancar. Un escáner periódico (cadencia derivada de `DASHBOARD_STALE_MINUTES`) capta compactaciones incluso cuando no se disparan ningún gancho. Lee el camino de transcripción de cada sesión activa directamente desde `sessions.transcript_path` (llenado por el gestor de ganchos en el primer evento que lo lleva, además de un relleno único de `events`) en lugar de hacer una `SELECT DISTINCT json_extract(events.data, '$.transcript_path')` sobre toda la tabla de eventos, por lo que la limpieza es O(sesiones activas) y se mantiene barata en una base de datos madura. Comparte la caché de transcripciones para evitar que se lean archivos duplicados. Las filas de compactación sintética están estampadas con la hora y la fecha de la transcripción tanto en `started_at` como en `ended_at`, por lo que la duración es exactamente 0 (la compactación es instantánea); una migración de reparación de inicio también cura cualquier fila preexistente donde `ended_at < started_at` (problema #156) | +| **Subsesiones/Sesiones reanudadas** | Reactiva automáticamente las sesiones cuando llegan nuevos eventos, maneja correctamente `/resume` y sesiones huérfanas. La escaneo periódico (cada ¼ de `DASHBOARD_STALE_MINUTES`, restringido a 60 s - 5 min) marca las sesiones abandonadas que pasan desapercibidas por la detección basada en eventos | +| **Detección de sesiones preexistentes** | Las sesiones que ya están en ejecución cuando se inicia el servidor se importan como "activas" (basadas en la modificación reciente del archivo JSONL). Los eventos de detención también reactivan las sesiones completadas/abandonadas importadas, por lo que el primer gancho de una sesión en progreso siempre la muestra en el panel de control | +| **Sincronización continua del proyecto** | La importación automática de inicio de sesión de `~/.claude/projects` es única (con puerta de marcador), por lo que una carpeta de proyecto creada **después** del primer lanzamiento, cuyas sesiones nunca pasan por los ganchos (por ejemplo, los ganchos solo para el host desactivados), permanecería invisible hasta una escanear manual. Una sincronización de fondo (`startSessionSync`) cierra esa brecha a través de tres desencadenantes que comparten una caché de mtime + un escaneo único coalescido: un escaneo **immediato** al inicio, un **`fs.watch`** amortiguado que dispara en el instante en que aparece un nuevo archivo de sesión/carpeta de proyecto (recursivo en macOS/Windows; raíz + hijos inmediatos en Linux para evitar el peligro del observador recursivo en el sistema de usuario) y una **petición periódica** (`DASHBOARD_SESSION_SYNC_MS`, por defecto 30 s). Cada escaneo solo reparse los archivos cuyos mtime ha avanzado y transmite `session_created`/`session_updated` (además del agente principal), por lo que la interfaz de usuario se actualiza en vivo; una sesión sin cambios ya en la base de datos se omite sin reparse, por lo que el costo de reiniciar se mantiene O(nuevos/archivos cambiados) | +| **Fuentes de datos remotas** | Recolección de datos remotos en vivo / multimáquina a través de SSH. El panel de control refleja `~/.claude/projects` de cada máquina configurada a través de **scp** (o `wsl.exe` + `tar` para Claude alojado en WSL en SSH de Windows) en una carpeta de ensayo aislada por fuente, la alimenta a través del **mismo importador** utilizado para el historial local y etiqueta las sesiones importadas con su origen (`sessions.source`). Un encuestador de fondo (`DASHBOARD_REMOTE_SYNC_MS`, por defecto 15 s; `0` desactiva) lo mantiene casi en tiempo real: agregar o volver a habilitar una fuente también desencadena una extracción inmediata, y las sincronizaciones exitosas transmiten `remote_data.updated` además de los fotogramas `session_created` / `session_updated` por sesión, por lo que las páginas abiertas se actualizan sin sincronización manual. Un selector global de **ámbito de datos** (Solo local / Todo / fuentes específicas) reduce toda la aplicación. Las fuentes se gestionan en **Configuración → Fuentes de datos remotas** (agregar / probar / sincronizar / eliminar) y a través de `ccam remote-sources`; los flujos de estado se transmiten a través de `remote_source.status`, y las filas de Sesiones muestran un distintivo de fuente para las sesiones de origen remoto. Las sesiones remotas **no tienen enlaces locales en vivo**, por lo que están excluidas de todas las heurísticas de localización/desactualización en vivo (la recolección de `ps`/`lsof`, la escanio de transcripciones del vigilante y las escaneos de arranque + abandono periódico, todo restringido en `source = 'local'`); en cambio, su **estado en vivo se reconcilia a partir de la transcripción reflejada en cada sincronización**: el timestamp del evento más reciente dentro del JSONL (volviendo al mtime del espejo) dentro de `DASHBOARD_REMOTE_ACTIVE_WINDOW_MS` (por defecto 10 min) significa que la CLI remota todavía está ejecutándose (→ `active`), y una vez que deja de avanzar, la sesión cambia a `completed`. La autenticación se deja totalmente en manos de la propia pila SSH del host (`~/.ssh/config`, ssh-agent, claves, `known_hosts`) - no se almacenan contraseñas ni secretos, los comandos externos se ejecutan a través de arreglos de argumentos (sin shell) y `StrictHostKeyChecking` se mantiene en la configuración predeterminada de SSH para que una clave de host desconocida falle en lugar de ser confiada | +| **Diseño Responsivo** | Diseños compatibles con dispositivos móviles con cuadrículas apilables, tablas desplazables y barra lateral plegable | +| **Localización de la interfaz de usuario** | Cambio de idioma integrado con copia de la interfaz de usuario traducida y etiquetas de accesibilidad para inglés (`en`), chino (`zh`), vietnamita (`vi`), coreano (`ko`) y español (`es`). La cobertura ahora se extiende de extremo a extremo a través de las miniaturas de la herramienta Workflows: cálculos de tarjetas estadísticas e interpretaciones de contenedores de valores, pestañas emergentes "¿Qué / Cómo leer / Por qué" por gráfico, miniatura de la herramienta de desplazamiento sobre cada gráfico (orquestación, flujo de herramientas, tubería, delegación de modelos, concurrencia), las narrativas y sugerencias del panel de detalles de los patrones de flujo de trabajo, la pestaña de información de Configuración → Precios del modelo, el panel CLAUDE_HOME y todo el flujo de historial de importación | +| **Datos de semilla** | Script de semilla incorporado para demostraciones y desarrollo | +| **Línea de estado** | Línea de estado CLI codificada por color que muestra el modelo, el uso del contexto, la rama de git, los tokens por dirección y el costo de la sesión (USD) | +| **Formato de nombres de modelos** | Nombres de modelos fáciles de entender para el usuario en toda la interfaz de usuario: identificadores brutos como `claude-opus-4-7-20260101` o `claude-opus-4-7[1m]` se muestran como "Claude Opus 4.7" o "Claude Opus 4.7 (1M)". Maneja las familias Claude, GPT y Gemini con uniones automáticas de puntos de versión, eliminación de sufijos de fecha/último, eliminación de prefijos del proveedor y formato de etiquetas de ventana de contexto. La página de configuración conserva los nombres brutos para la configuración de reglas de precios | +| **Mercado de plugins** | Mercado oficial de plugins de Claude Code con 10 plugins (ccam-analytics, ccam-productivity, ccam-devtools, ccam-insights, ccam-dashboard, ccam-cost-guard, ccam-sessions, ccam-workflows, ccam-quality, ccam-config). 53 habilidades, 14 agentes, 30 comandos slash, 3 herramientas CLI, 3 configuraciones de ganchos. Todo basado en un modelo de datos actual: bases de datos de tokens, motor de precios, inteligencia de flujo de trabajo (11 conjuntos de datos), metadatos de sesión. Instalar a través de `claude plugin marketplace add` | +| **Ejecutar Claude** | Crear subprocesos `claude` directamente desde el panel de control con una interfaz de usuario de streaming de estilo chat. Dos modos: **Conversación** (multi-turnos — la entrada estándar se mantiene abierta, los turnos de seguimiento se envían como paquetes stream-json) y **Una vez** (sin cabeza, solo un mensaje de inicio → solo una respuesta). El modo de conversación también admite **reanudar cualquier sesión existente** a través de `claude --resume ` - elige entre tu historial completo de sesiones con un selector de búsqueda. El modo de historial / ejecuciones activas unificado también ofrece dos botones de salto de configuración cero: **Resumen** en cualquier fila de conversación anterior genera `claude --resume ` inmediatamente y siembra el chat con la transcripción anterior para que llegues a la vista en vivo con el contexto completo (no es necesario volver a escribir un mensaje de inicio de sesión, el id de generación se queda en espera en stdin hasta que envíes un seguimiento); **Ver** en cualquier fila de una sola ejecución anterior carga la transcripción capturada directamente en el visualizador de ejecuciones como de solo lectura (sin generación, mismo panel, sin controles de Detener/seguimiento). El interruptor de carreras activas en el encabezado le permite dejar una carrera en segundo plano, iniciar otra y volver a adjuntarla más tarde. Re-attach es duradero: el cliente reconcilia el registro de sobrecargas en memoria del generador (`?envelopes=1`) con la transcripción JSONL en disco de la sesión y prefiere la que tenga más mensajes de usuario/asistente, por lo que navegar lejos de una ejecución suspendida y volver mantiene visible todo el historial anterior (el generador solo ve las vueltas posteriores a la generación; el archivo de transcripción tiene anterior + actual). Desplegable de modelos (Opus 4.7 / 1M / Sonnet 4.6 / Haiku 4.5 / personalizado), seleccionador de modo de permiso con advertencia explícita de `bypassPermissions`, campo de **efecto de pensamiento** (bajo / medio / alto - conectado a `--effort`), prelleno automático de cwd prellenado con el **directorio de inicio** del usuario - una ubicación de creación neutral que no hereda el propio contexto de proyecto `.claude` del repositorio del panel de control (agentes, habilidades, reglas, `CLAUDE.md`, `.mcp.json`); se vuelve a conectar al cwd del panel de control si no hay sugerencia de inicio disponible, con el inicio listado primero en los grupos de sugerencias (inicio → panel de control → recientes). Transmisión real de personajes por personaje a través de `--include-partial-messages`, además de una **capa de suavización de máquina de escribir** del lado del cliente que gotea cada `text_delta` / `thinking_delta` a través de `requestAnimationFrame`, por lo que incluso las respuestas cortas (donde claude empaqueta toda la respuesta en uno o dos trozos) parecen escribirse. El código de fusión mantiene intacto el indicador `_streaming` y la matriz `content` acumulada en delta cuando llega el sobre `assistant` canónico de claude a mitad del flujo, por lo que los bloques de pensamiento no se pierden al finalizar. La emisión de WebSocket envuelve cada sobre en `flushSync` para que el agrupamiento automático de React 18 no colapse los picos de deltas en una sola renderización. **Paridad TUI (Nivel 1):** un **banner de limitaciones plegable** que se minimiza a una píldora delgada (nunca desaparece) explicando lo que el modo stream-json puede y no puede hacer frente al TUI terminal; un **editor de comandos con autocompletado de comandos con guiones** con puntuación por niveles (nombre exacto → comienza con → límite de palabra → contiene → subsecuencia → contiene descripción) que enumera los comandos de usuario / proyecto / plugin (ejecutados desde el lado del cliente a través de la expansión de plantillas antes del envío) y muestra comandos de CLI integrados como `/clear`, `/model`, `/config` con un distintivo "Solo CLI, no se ejecutará desde aquí"; **referencias de archivos `@`** con búsqueda borrosa amortiguada en todo el directorio de trabajo de la ejecución (omitiendo `node_modules`, `.git`, `dist`, `build`, etc.); una **ventana de contexto en vivo / medidor de tokens** que muestra tokens de entrada + salida + lectura de caché y costo de ejecución, calculados a partir de `stream_event` y `result.usage` sobres durante la transmisión en vivo y de los bloques de `uso` del asistente finalizados (entrada / salida / lectura de caché / creación de caché) cuando se inician desde una transcripción en reiniciar / ver / volver a adjuntar, para que el medidor se llene inmediatamente en lugar de quedarse en 0/200k. La barra de progreso pasa de índigo → ámbar → rojo al 80 % / 95 % del límite de contexto del modelo; un **encabezado de estado** con el modelo activo, el esfuerzo, el modo de permiso, el directorio actual, el ID de la sesión, el número de sobres y el tiempo transcurrido. Los menús desplegables de autocompletado se abren hacia arriba para que no colisionen con el selector cwd de abajo. Indicador de en vivo / sin conexión junto al título. La guardia de origen común en la ruta evita que el navegador genere ataques de tráfico cruzado. La concurrencia no está efectivamente limitada por defecto (techo de cordura de 10000 para evitar que las pistolas de pie fork-bomb causen problemas en el cliente; la TUI terminal no tiene límite y nosotros tampoco). Establezca `RUN_MAX_CONCURRENT` si desea un techo real. Las sesiones generadas disparan los mismos ganchos que cualquier proceso `claude`, por lo que aparecen automáticamente en Sesiones / Análisis / Kanban / Flujos de trabajo, y las superficies Sesiones / Detalle de sesión muestran un distintivo / banner verde **▶ Ejecutar** que vuelve a enlazar con la página Ejecutar para cualquier sesión que se esté ejecutando actualmente desde allí | +| **Explorador de Configuración de Claude** | Un inspector de 12 pestañas en `/cc-config` para todo lo que Claude Code sabe sobre: habilidades, subagentes, comandos de guión, estilos de salida, complementos (con el conteo de contribuciones por complemento + autor/licencia/Página de inicio de `plugin.json`), mercados (con el conteo de complementos leído de cada `marketplace.json`), servidores MCP, ganchos (con la lista de scripts `~/.claude/hooks/`), configuraciones (un resumen de **Configuración actual** a un vistazo de las opciones que controlan los controles `/config` — modelo, verbose, tema, estilo de salida, esfuerzo, compactación automática, notificaciones, ... — resueltas en los ámbitos de usuario/proyecto/proyecto local con opciones no establecidas mostradas como predeterminadas, además de la vista estructurada de clave-valor por archivo + interruptor JSON bruto, redacción de clave secreta), memoria (los archivos `CLAUDE.md` del usuario + proyecto **más** el almacenamiento de memoria basado en archivos por proyecto — cada `*.md` inferior a `~/.claude/projects//memory/`, es decir, un índice `MEMORY.md` más un archivo por hecho recordado, a menudo más de 100; agrupados por proyecto en secciones colapsables que dividen los archivos de índice de los archivos por hecho, con una caja de búsqueda y enlaces de índice `MEMORY.md` interactivos que saltan a — desplazar hacia arriba + resaltar — el archivo de hecho correspondiente), atajos de teclado (agrupados por contexto con chips ``) y línea de estado (configuración + contenido del script). Para superficies de archivos de texto de bajo riesgo (habilidades / agentes / comandos / estilos de salida / memoria, incluidos los archivos de memoria automática por proyecto), la página admite **crear / editar / eliminar con copias de seguridad con hora y fecha obligatorias** escritas atómicamente fuera de los directorios que Claude Code escanea, además de una modalidad de Copias de seguridad con comandos de restauración `mv` construidos automáticamente. Los plugins, MCP, ganchos en la configuración y los archivos `settings.json` permanecen de solo lectura con banners explicativos + comandos CLI copiables para que el usuario sepa el comando exacto que debe ejecutar él mismo. **Actualizaciones en vivo**: un `cc-watcher` que se ejecuta en el servidor utiliza `fs.watch` en `~/.claude/` (recursivo donde la plataforma lo admite) además de `~/.claude.json`, retrasado a 500 ms, para transmitir un mensaje WebSocket `cc_config_changed` cada vez que cambian las configuraciones de Claude Code, ya sea a través de mutaciones del panel de control o herramientas externas (instalación de un complemento en la CLI, edición manual de `settings.json`, eliminación de una nueva habilidad). La página se suscribe y se vuelve a recuperar automáticamente; una píldora en vivo / sin conexión junto al título muestra el estado de WebSocket | +| **Tabby** | Un compañero de gato flotante atado en la esquina inferior derecha de cada página. Construido enteramente sobre el existente WebSocket `eventBus` — **sin nuevo backend, sin clave API, sin nuevas dependencias**. Una mascota SVG reactiva con ojos que rastrean el cursor y **ocho estados de ánimo** derivados del flujo de la sesión en vivo (`idle`, `watching`, `happy`, `worried`, `stuck`, `thinking`, `sleeping`, `disconnected`), cada uno con su propia animación (golpe de cola, levantamiento de orejas, movimiento de cabeza, sacudida, brillo, zzz, alerta "!"). **Bolas de diálogo automáticas** publican chistes cortos, moderados y coalescidos sobre eventos notables (sesión iniciada/terminada, errores, ejecución completada) y se pueden silenciar. Haz clic en el gato o presiona **⌘B / Ctrl+B** (Esc cierra) para abrir un **panel** con una línea de estado en vivo (`N en vivo · M con errores · estado de conexión`), acciones rápidas (salta a Ejecutar Claude / Actividad / Sesiones / sesiones con errores, silenciar burbujas, eliminar alertas) y una casilla de **Pregunta**: las preguntas de estado simples ("¿qué está ejecutando?", "algunos errores", "estado") se responden localmente a partir de datos caché, mientras que cualquier otra pregunta se envía a la página de **Ejecutar Claude** (enlaces profundos a `/run?prompt=…`) para iniciar una sesión de Claude Code real. Accesible (operable con teclado, burbujas `aria-live`, respeta `prefers-reduced-motion`), degrada de forma segura a un estado tranquilo de `desconectado` si la conexión está rota, puede activarse o desactivarse en **Configuración** (localizado en en/zh/vi/ko/es). La implementación vive en `client/src/components/Tabby/` | +| **Aplicación web progresiva (PWA)** | Tres PWAs independientes: panel de control, página de destino y wiki, cada una con su propio manifiesto de aplicación web y trabajador de servicios. Instala cualquiera de ellos en tu pantalla de inicio / dock para una experiencia independiente, sin Chrome. El SW del panel de control sirve los paquetes de contenido hashados de Vite bajo `/assets/` primero en la caché (los URL son inmutables por compilación, por lo que los accesos a la caché siempre son correctos) y trata todo lo demás, como las navegaciones, el SW en sí, `manifest.json`, los iconos, la raíz `/`, como primero en la red con fallback de caché. Combinado con encabezados explícitos de `Cache-Control` en el middleware estático de producción Express (`immutable` para `/assets/*`, `no-cache, must-revalidate` para `index.html`, `sw.js`, `manifest.json`), una reconstrucción siempre reemplaza el paquete en el navegador sin una actualización forzosa; un oyente de `controllerchange` en el cliente se carga exactamente una vez cuando un nuevo SW toma el control de una página ya controlada. El canal de notificaciones push de VAPID se conserva. La página de inicio y los SW wiki precargan sus respectivas cáscaras y imágenes de caché lento en la primera visita, lo que permite el acceso sin conexión después de una sola carga. Todas las manifestaciones utilizan iconos SVG (`favicon.svg`) con `sizes="any"` para navegadores modernos, e incluyen etiquetas meta `apple-mobile-web-app-capable` + `apple-touch-icon` para el modo independiente de iOS | +| **Aplicación de escritorio (macOS y Windows)** | Aplicación de escritorio nativa opcional construida con Electron 35, que vive en el espacio de trabajo `desktop/` junto con `client/`, `server/`, `mcp/` y `vscode-extension/`. Se envía como un `.app` (`.dmg`) de macOS **y** un `.exe` (instalador NSIS + portátil sin instalación) de Windows. Incorpora el servidor Express existente **en proceso** (`require()`s `server/index.js` - sin proceso hijo, sin IPC) y renderiza el cliente React construido en una `BrowserWindow`. Añade una barra de título nativa, un icono de barra de menú / área de notificaciones ( bandeja ) cuya lista desplegable de un solo clic muestra una **captura de estado en vivo** (sesiones, agentes, eventos de hoy) extraída de SQLite en el momento del clic, un menú de aplicación nativo, inicio automático al iniciar sesión (elementos de inicio de sesión de macOS a través de `SMAppService`; Windows `HKCU\…\Run` por usuario), un **dialog de confirmación ⌘Q / Ctrl+Q** (segundo clic por defecto), cierre de ventana que oculta pero mantiene el servidor en ejecución, bloqueo de una sola instancia y acciones de bandeja para **Abrir en el navegador**, **Reiniciar el servidor** y **Mostrar registros**. Prefiere el puerto 4820 (se vuelve al puerto 4821-4829 y luego a un puerto alto aleatorio), adopta un panel de control saludable que ya está funcionando en 4820 en lugar de doble vinculación, y **coexiste con el panel de control web**: tanto `npm run dev` como la aplicación de escritorio pueden ejecutarse juntas con ganchos que se extienden a ambas. Las notificaciones se envían cuando el sistema operativo nativo tosta (Web Push no funciona de forma fiable dentro de Electron). En el primer arranque del servidor, se instalan automáticamente los ganchos de Claude Code y se inician los servicios de fondo, por lo que un usuario que solo instale recibe eventos sin necesidad de configuración manual. Ver [`DESKTOP.md`](./DESKTOP.md) y [`desktop/README.md`](./desktop/README.md) | +| **Activos alojados por el propio usuario (sin CDN)** | Cada fuente y script se sirve localmente, por lo que el panel de control y los documentos realizan **cero solicitudes de CDN de terceros**: se renderizan completamente sin conexión y no filtran nada a los hosts externos. La aplicación React empaqueta Inter + JetBrains Mono a través de [`@fontsource`](https://fontsource.org/) (subconjunto latino; Vite emite WOFF2 con contenido hashed en `dist/assets/` en el momento de la compilación, sin `` a Google Fonts). La página de inicio y el wiki cargan una hoja `@font-face` `fonts/fonts.css` alojada por el propio usuario desde el directorio `fonts/` de la raíz del repositorio. La Mermaid del wiki se vende localmente como `wiki/mermaid.min.js` (la auténtica `mermaid@10.9.6` minificada) en lugar de jsDelivr, y la página de error de la extensión de VS Code recurre a una pila de fuentes del sistema. No quedan llamadas a `fonts.googleapis.com`, `fonts.gstatic.com` o `cdn.jsdelivr.net` en ningún lugar | +| **Pantalla de inicio de sesión** | Un breve mensaje de marca al cargar la aplicación (una vez por sesión de navegador): un **saludo con tiempo** (Buenos días / tarde / noche / Trabajando tarde), un lema llamativo, dos subtítulos y una marca de marca gráfica de nodo animada sobre un fondo atmosférico oscuro (luz radial + constelación flotante + grano). Totalmente localizado (en/zh/vi/ko/es). La superposición es **opaca desde el primer pincelazo**, por lo que la aplicación nunca parpadea, permanece unos 2,5 segundos y luego se desvanece; haga clic en cualquier lugar para saltar y respeta `prefers-reduced-motion`. Animaciones solo CSS, sin dependencias adicionales | + +--- + +## Inicio rápido + +### Prerequisitos + +- **Node.js** >= 20.0.0 (22+ recomendado) +- **npm** >= 9.0.0 + +### 1. instalar + +```bash +git clone https://github.com/hoangsonww/Claude-Code-Agent-Monitor.git +cd Claude-Code-Agent-Monitor +npm run setup +``` + +### 2. Configurar los ganchos de código de Claude + +```bash +npm run install-hooks +``` + +Esto agrega entradas de gancho a `~/.claude/settings.json` que reenvían eventos al panel de control. Los ganchos existentes se conservan. + +### 3. inicio + +```bash +# Development (hot reload on both server and client) +npm run dev + +# Production (single process, built client) +npm run build && npm start +``` + +> [¡CONSEJO!] +> **Alternativa de Makefile** - todos los comandos también están disponibles a través de `make` si lo tienes instalado en tu sistema. Ejecuta `make help` para ver todos los destinos, o usa atajos como `make dev`, `make build`, `make test`, etc. + +### 4. aire libre + +| Modo | URL | +| ----------- | ----------------------- | +| Desarrollo | `http://localhost:5173` | +| Producción | `http://localhost:4820` | + +### 5. Opcional: Construir y ejecutar el servidor MCP local + +```bash +npm run mcp:install +npm run mcp:build +npm run mcp:start # stdio (default — for MCP host integration) +npm run mcp:start:http # HTTP + SSE server on port 8819 +npm run mcp:start:repl # interactive CLI with tab completion +``` + +Para el modo stdio, configure su host MCP (Claude Code / Claude Desktop / otros clientes MCP): + +- comando: `node` +- argumentos: `["/mcp/build/index.js"]` + +Para el modo HTTP, dirija a los clientes MCP remotos a `http://127.0.0.1:8819/mcp` (HTTP transmisible por flujo) o `http://127.0.0.1:8819/sse` (SSE heredado). + +Consulte [mcp/README.md](./mcp/README.md) para obtener la configuración completa del host, los detalles del transporte, las banderas de seguridad y el catálogo de herramientas. + +### Opcional: Datos de demostración de semillas + +```bash +npm run seed +``` + +Crea 8 sesiones de muestra, 23 agentes y 106 eventos para que puedas explorar la interfaz de usuario inmediatamente. + +### Alternativa: Aplicación para escritorio (macOS y Windows) + +Si prefieres no mantener un terminal abierto, instala la aplicación de escritorio **opcional nativa**. Incorpora el servidor en el proceso, agrega un icono de barra de menú / área de notificaciones ( bandeja) y admite el inicio automático al iniciar sesión (elementos de inicio de sesión de macOS / inicio de sesión de Windows). + +El camino más rápido es **descargar un instalador precompilado** desde la [última versión de GitHub](https://github.com/hoangsonww/Claude-Code-Agent-Monitor/releases/latest) (CI publica automáticamente una `vX.Y.Z` cada vez que `package.json` se actualiza en `master`): + +- **macOS** — agarra `ClaudeCodeMonitor--arm64.dmg` (Apple Silicon) o `-x64.dmg` (Intel) y arrastra **Claude Code Monitor.app** a `/Applications`. +- **Windows** — obtenga `ClaudeCodeMonitor-Setup--x64.exe` (instalador) o `ClaudeCodeMonitor--x64-portable.exe` (sin instalar) y ejecútelo. + +Para construirlos tú mismo en su lugar: + +```bash +npm run desktop:install # install Electron + electron-builder into desktop/ (preflights native deps; prints setup help on failure) +npm run desktop:dmg:arm64 # macOS: fast single-arch DMG (Apple Silicon) +npm run desktop:win # Windows: NSIS installer .exe (run on Windows) +``` + +La cobertura completa de la aplicación de escritorio, incluida la descarga, la instalación, las funciones de bandeja/menú, los comandos de construcción y la firma, se encuentra en la sección [Aplicación de escritorio (macOS y Windows)](#aplicación-de-escritorio-macos-y-windows) a continuación. Consulte también [`DESKTOP.md`](./DESKTOP.md) (guía del usuario) y [`desktop/README.md`](./desktop/README.md) (arquitectura). + +### Alternativa: Docker / Podman + +Se incluyen un `Dockerfile` y un `docker-compose.yml`. Tanto Docker como Podman son compatibles. + +**Con Docker Compose:** + +```bash +docker compose up -d --build +``` + +**Con Podman Compose:** + +```bash +CLAUDE_HOME="$HOME/.claude" podman compose up -d --build +``` + +**Con Docker o Podman simples (sin Compose):** + +```bash +# Docker +docker build -t agent-monitor . +docker run -d --name agent-monitor \ + -p 127.0.0.1:4820:4820 \ + -v "$HOME/.claude:/root/.claude:ro" \ + -v "$HOME/.claude/agent-dashboard:/app/data" \ + agent-monitor + +# Podman +podman build -t agent-monitor . +podman run -d --name agent-monitor \ + -p 127.0.0.1:4820:4820 \ + -v "$HOME/.claude:/root/.claude:ro" \ + -v "$HOME/.claude/agent-dashboard:/app/data" \ + agent-monitor +``` + +El panel de control está disponible en `http://localhost:4820`. La imagen vincula `0.0.0.0` **dentro del contenedor** (`DASHBOARD_HOST`) y escribe SQLite en `/app/data` (`DASHBOARD_DATA_DIR`) —ambos integrados en el `Dockerfile` para que Compose y el sencillo `docker run` funcionen tal cual. Compose y los ejemplos a continuación vinculan y montan **el mismo** directorio de host que `npm start` / `npm run dev` (`~/.claude/agent-dashboard`), por lo que Docker, nativo y dev comparten una base de datos. El límite de confianza es el puerto de publicación del **host**: los ejemplos solo publican en `127.0.0.1`, por lo que el panel de control no es accesible desde la LAN de fábrica. Para exponerlo en una LAN, publique en `0.0.0.0` (elimine el prefijo `127.0.0.1:`, por ejemplo, `-p 4820:4820`) **y** establezca `DASHBOARD_TOKEN` (consulte [Configuración](#configuración) y [`.github/SECURITY.md`](./.github/SECURITY.md)). + +**Montajes de volumen:** + +| Montaje | Propósito | +|---|---| +| `~/.claude:/root/.claude:ro` | Leer el historial de sesiones heredadas para la importación | +| `~/.claude/agent-dashboard:/app/data` | **Base de datos SQLite canónica** (compartida con las instalaciones nativas) | + +> [!NOTA] +> Si anteriormente usaste el antiguo volumen de Compose llamado (`dashboard-data`), copia cualquier dato que necesites en `~/.claude/agent-dashboard/` una vez, luego elimina el volumen no utilizado: `docker volume rm claude-code-agent-monitor_dashboard-data` (el nombre puede variar). + +> [¡IMPORTANTE!] +> **Nota:** Los ganchos de Claude Code todavía deben apuntar a un proceso de manejador de ganchos en ejecución en el host. El propio contenedor no recibe ganchos, ejecute `npm run install-hooks` **en el host** para configurar ganchos que POSTen a `http://localhost:4820`. Ejecutar el instalador dentro de un contenedor está **rechazado** (problema #193), por lo que no puede escribir una ruta de manejador interna del contenedor en un host montado mediante vinculación `~/.claude`; sobrescriba con `CCAM_ALLOW_CONTAINER_HOOKS=1` solo si realmente ejecuta Claude Code dentro del mismo contenedor. + +--- + +## Cómo funciona + +El panel de control se integra con Claude Code a través de su sistema de ganchos nativo para proporcionar un monitoreo en tiempo real de la actividad del agente. Aquí hay una descripción general de la arquitectura y el flujo de datos: + +```mermaid +sequenceDiagram + participant CC as Claude Code + participant HH as Hook Handler + participant API as Express Server + participant DB as SQLite + participant WS as WebSocket + participant UI as React Client + + CC->>HH: stdin (JSON event) + HH->>API: POST /api/hooks/event + API->>DB: Insert/update records + API->>WS: Broadcast update + WS->>UI: Push message + UI->>UI: Re-render component + + Note over CC,HH: Hooks fire on SessionStart,
PreToolUse, PostToolUse,
Stop, SubagentStop,
SessionEnd, Notification.
Compaction detected from JSONL + Note over API,DB: Transactional writes
with auto session/agent creation + Note over WS,UI: ~0ms latency,
no polling +``` + +> [¡IMPORTANTE!] +> Consulte [ARCHITECTURE.md](./ARCHITECTURE.md) para una inmersión profunda en la arquitectura del servidor, el esquema de la base de datos, las rutas de la API, el diseño de WebSocket, la enrutación de clientes, el flujo del gestor de ganchos, los modos de despliegue y los diagramas detallados del ciclo de vida para sesiones y agentes. + +### Ciclo de vida del gancho + +1. **Claude Code** dispara un gancho al inicio de la sesión, al uso de la herramienta, al final de la vuelta, al final de la finalización del subagente y al final de la sesión. +2. **Hook Handler** (`scripts/hook-handler.js`) lee el evento JSON desde stdin, resuelve los paneles de control en vivo a través de `~/.claude/.agent-dashboard.json` (o `CLAUDE_DASHBOARD_PORT` si está configurado), y POSTa la misma carga útil a **un solo destino de ingestión por directorio de datos SQLite único** (el puerto más bajo gana cuando Docker y `npm run dev` comparten `~/.claude/agent-dashboard`, por lo que los eventos nunca se ingieren dos veces). Los servidores con bases de datos **diferentes** (por ejemplo, la aplicación de escritorio que utiliza su propia carpeta de Soporte de Aplicaciones junto con `npm run dev`) todavía reciben cada uno los ganchos. Falla silenciosamente con un tiempo de espera de red de seguridad de 5 s, por lo que nunca bloquea el Código Claude, y las promesas por destino nunca se rechazan, por lo que un único oyente muerto no puede hacer que los demás se mueran de hambre. +3. **Servidor** procesa el evento dentro de una transacción SQLite: +- Crea automáticamente sesiones y agentes principales en el primer contacto +- Detecta las llamadas de la herramienta `Agent` para rastrear la creación de subagentes +- En `SessionStart`, marca la sesión y el `awaiting_input_since` del agente principal para que una nueva CLI que se encuentra en el prompt aterrice inmediatamente en **Esperando**. +- En `UserPromptSubmit` (el usuario presiona enter), borra la bandera de espera y promueve al agente principal a `working` (en funcionamiento): la única señal fiable de que los turnos de asistente de texto han comenzado, ya que no emiten `PreToolUse`. +- Establece al agente como "en funcionamiento" en `PreToolUse` (también borra la bandera de espera), lo mantiene funcionando a través de `PostToolUse` +- En "Detener" (Claude termina de responder), el agente principal va a "esperar" - Claude terminó su turno, la pelota está en el campo del usuario. Los subagentes de fondo continúan corriendo. La sesión permanece "activa". Detener con "stop_reason=error" marca al agente como "error" y a la sesión como "error" +- En una "notificación de permiso" (correspondiente al patrón de mensaje: `permiso`, `esperando entrada`, `necesita su aprobación`, ...), establece al agente como `esperando` y marca `awaiting_input_since` +- `SubagentStop` deliberadamente NO borra la bandera de espera (un subagente en segundo plano que termina no nos dice nada sobre el humano) +- Marca los subagentes completados individualmente a través de `SubagentStop`. Después de que `res.json()` devuelva, dispara un paso `scanAndImportSubagents` de "fire-and-forget" que recorre los archivos `subagents/agent-*.jsonl` de la sesión, empareja los bloques `tool_use` ↔ `tool_result` por `tool_use_id` y emite eventos `PreToolUse` + `PostToolUse` bajo el propio `agent_id` de cada subagente, cerrando la brecha donde las llamadas internas de herramientas de subagentes de otro modo serían invisibles en el panel de control. +- En `SessionEnd` (salida del proceso CLI), elimina la bandera de espera. Si la sesión está en `error`, el estado de error se preserva; de lo contrario, marca a todos los agentes + la sesión como `completada` +- En `SessionStart`, cualquier otra sesión activa sin actividad durante `DASHBOARD_STALE_MINUTES` (por defecto 180 = 3 h, superable por el entorno) se marca automáticamente como "abandonada" con sus agentes completados. Esto maneja `/resume` dentro de una sesión, Ctrl+C, y otros escenarios donde una sesión queda huérfana sin un `SessionEnd` limpio. +- Reactiva las sesiones completadas/erróneas/abandonadas cuando llegan nuevos eventos de trabajo (sesión reanudada). Los eventos Stop y SubagentStop también reactivan las sesiones completadas/abandonadas, lo que se encarga de las sesiones preexistentes importadas antes de que el servidor se iniciara, donde el primer evento de gancho puede ser un Stop +- **Recuperación de errores**: solo `UserPromptSubmit` y `PreToolUse` pueden recuperar una sesión de `error` a `active` — indicando que el usuario intentó activamente de nuevo +- Detecta la compactación de la conversación (entradas `isCompactSummary` en la transcripción JSONL) y crea agentes + eventos de `Compactación`. Las bases de tokens se conservan a lo largo de las compactaciones, por lo que no se pierde ningún uso. Las lecturas de la transcripción utilizan una caché compartida basada en estadísticas con lecturas de desplazamiento de bytes incrementales, solo se analizan los nuevos bytes añadidos desde la última lectura, lo que da una velocidad de ~50 veces mayor para sesiones largas. +- Extrae errores de la API (entradas de `isApiErrorMessage: límites de cuota, límites de tasa, solicitud inválida`) y respuestas brutas de `type: "error"` de transcripciones JSONL, almacenadas como eventos `APIError`. Las duraciones (subtipo `system` `turn_duration`) se almacenan como eventos `TurnDuration`. Los errores de resultado de la herramienta (`toolUseResult.is_error`) se rastrean como eventos `ToolError`. +- **Supervisor de detección de errores**: un temporizador en segundo plano se ejecuta cada 15 segundos, escaneando las sesiones activas sin eventos de conexión recientes (>10 s caducados). Relee sus archivos de transcripción buscando errores de API (fallos de autenticación, límites de tasa, agotamiento de cuotas), deriva los rutas de transcripción desde el directorio actual de la sesión para las sesiones importadas sin `transcript_path` en los datos del evento y marca las sesiones/agentes como `error` cuando se encuentran errores de API. Esto captura casos en los que la CLI de Claude no dispara un gatillo después de un error de API (por ejemplo, 401 fallos de autenticación donde la CLI muestra el error y espera) +- **Recuperación por interrupción del usuario (Esc)**: cancelar un turno con `Esc` no dispara **ningún gatillo** (una limitación documentada del Código Claude), por lo que sin intervención el agente principal se quedaría atascado en `trabajando` para siempre. El mismo vigilante de 15 s recupera estas dos formas: (1) cuando el cancelar deja un marcador `[Solicitud interrumpida por el usuario]` en la transcripción (Esc *después* de alguna salida), la caché de transcripción lo marca a través de `pendingInterrupt` - derivado puramente del ordenamiento de la transcripción (interrupción más reciente vs última actividad real de la ronda, mismo reloj, por lo que funciona incluso para un cancelar de subsegundos) - y la sesión se mueve a **Esperando** dentro de ~15 s; (2) cuando Esc se presiona *antes de cualquier salida*, Claude Code no escribe ningún marcador en absoluto, por lo que se aplica un fallback de tiempo de espera inactivo - si el agente principal ha estado `trabajando` con **sin herramienta en vuelo** y **ni un evento de gancho ni la transcripción han avanzado** durante `DASHBOARD_WORKING_IDLE_SECONDS` (por defecto `120`), la ronda se trata como muerta y la sesión se mueve a **Esperando**. Ambos caminos registran un evento "Interrumpido" y ponen la sesión en el mismo estado de espera que produce una "Detener" normal. La salida de transmisión en vivo (la transcripción sigue creciendo) y las llamadas de herramientas en vuelo (el conjunto `current_tool`) están exentos; un raro falso flip se cura automáticamente en el próximo gancho real +- **Recolección de la vitalidad de la sesión muerta**: salir de Claude Code (Ctrl+C, cerrar el terminal) dispara un gancho `SessionEnd`, pero si el panel de control no está ejecutándose en ese momento, el evento se pierde para siempre y la sesión permanecerá en **Esperando** hasta la limpieza de datos obsoletos (3 horas por defecto). El mismo vigilante de 15 s cierra la brecha con una **probe de vitalidad del proceso**: enumera los procesos CLI de `claude` en ejecución (`ps` + `lsof` en macOS, `/proc` en Linux) y completa cualquier sesión `activa` cuya `cwd` no tenga un proceso claude en vivo, lo que lo lleva al mismo estado `completado` que produce un verdadero `SessionEnd`, con un evento `SessionEnd` sintético en la línea de tiempo. Guardias: en watchdog, el transcurso de la sesión no debe haber sido escrito durante al menos `DASHBOARD_LIVENESS_IDLE_SECONDS` (por defecto `60`; la última escritura del gancho es el reloj de respaldo cuando no existe un transcurso en el disco) — los **pasos de arranque saltan completamente este umbral**, por lo que una sesión que se cierra incluso un segundo antes del lanzamiento se limpia inmediatamente — y la sonda informa de "sin respuesta" (sin cambiar nada) en Windows, dentro de contenedores (los procesos del host son invisibles allí), cuando `ps`/`lsof` fallan, o cuando se deshabilita explícitamente a través de `DASHBOARD_LIVENESS_PROBE=0`. En un despliegue **mezclado**, la cosecha también omite automáticamente cualquier sesión cuyo `cwd` no es absoluto POSIX: una sesión enviada desde otra máquina a través de ganchos domésticos informa del propio camino de la fuente (por ejemplo, un `D:\Git\ai-deck` de Windows) que una escaneo local de `ps`/`lsof`/`/proc` nunca puede igualar, por lo que las sesiones remotas están protegidas sin desactivar la sonda para las genuinamente locales. **Las sesiones de fuente de datos remota** (`sessions.source` ≠ `local`) también se saltan siempre; su `cwd` es legítimamente absoluto POSIX en otra máquina, por lo que la sonda del proceso local no dice nada sobre ellas; su ciclo de vida es completamente propiedad de la reconciliación de sincronización remota descrita anteriormente. Una falsa finalización se auto-curará: el siguiente evento de conexión reactiva la sesión. Además de la cadencia de vigilancia de 15 s, la recolección se ejecuta **inmediatamente al arrancar** (limpiando las sesiones inactivas ya en la base de datos de una ejecución anterior antes de que se rendericen) y **de nuevo ~5 s después** (cubriendo las sesiones que la sincronización de arranque acababa de importar), por lo que una sesión que murió mientras el panel de control estaba inactivo nunca aparece como Esperando. +- Una escaneo periódico del servidor captura sesiones abandonadas y nuevas compactaciones que se han escapado de la detección basada en eventos (por ejemplo, `/compact` no dispara ningún gancho, `/resume` dentro de segundos de la creación de la sesión). La cadencia se deriva de `DASHBOARD_STALE_MINUTES` (¼ del umbral, atado a 60 s - 5 min). La escaneo lee `transcript_path` directamente de cada fila de sesión activa (una pequeña búsqueda de índice) en lugar de escanear la tabla de eventos para ello; la columna se llena por el gestor de ganchos la primera vez que ve un camino de transcripción y se rellena una sola vez desde los eventos existentes por la migración `db.js`, con un índice parcial `idx_sessions_active_tp` que cubre exactamente las filas que lee el escaneo. La limpieza comparte la caché de transcripciones con el gestor de ganchos, evitando la I/O duplicada. La limpieza de sesiones abandonadas también expulsa la entrada de la caché de transcripciones a la memoria vinculada. Tanto esta limpieza como la limpieza inicial de 1 hora saltan las sesiones de **Fuente de datos remota** (`source` ≠ `local`): su `updated_at` rastrea la cadencia de sincronización en lugar de la actividad real de la CLI remota, por lo que su estado se reconcilia desde el espejo por la sincronización en su lugar. +- **Sincronización continua del proyecto** (`startSessionSync`) mantiene `~/.claude/projects` descubrible más allá del relleno de inicio único, con marcadores: un proyecto agregado más tarde cuyas sesiones nunca pasan por los ganchos de otro modo permanecería invisible hasta una escanear manual. Una escanear de inicio inmediata, un `fs.watch` amortiguado (recursivo en macOS/Windows; raíz + hijos inmediatos en Linux) y una consulta `DASHBOARD_SESSION_SYNC_MS` (por defecto 30 s; `0` desactiva la consulta, el observador permanece) comparten una caché de mtime y una escanear coalescida que solo reinterpreta los archivos cuyos mtime ha avanzado — y omite una sesión ya importada e inalterada sin reinterpretar, por lo que el costo de reiniciar se mantiene O(nuevos/archivos cambiados). Cada sesión recién descubierta/crecida emite `session_created`/`session_updated` además de su agente principal, los mismos ganchos de cuadros emiten +4. **WebSocket** transmite el cambio a todos los clientes conectados +5. **UI** recibe la actualización y vuelve a renderizar los componentes afectados en tiempo real sin necesidad de consultar. + +### Máquina de Estado del Agente + +Estados persistentes: `trabajando | esperando | completado | error`. el +La columna `awaiting_input_since` es suplementaria, rastrea cuándo el agente +Empezó a esperar y se utiliza para la visualización de la duración, pero `esperando` ahora es un +Estado real persistente. + +```mermaid +stateDiagram-v2 + [*] --> waiting: ensureSession (first hook) + waiting --> working: PreToolUse / UserPromptSubmit + working --> working: PostToolUse (tool completed) + working --> waiting: Stop, non-error + working --> waiting: Notification (input prompt) + working --> waiting: Esc cancel (watchdog marker or idle timeout) + waiting --> error: Stop with error + working --> error: Stop with error + waiting --> error: API error detected (watchdog) + working --> error: API error detected (watchdog) + error --> working: UserPromptSubmit / PreToolUse (recovery) + working --> completed: SessionEnd + waiting --> completed: SessionEnd + + note right of waiting + Agent is between turns or + awaiting user input + end note +``` + +### Máquina de estado de sesión + +Estados persistentes: `activo | completado | error | abandonado`. el +El estado de la sesión **esperando** es una superposición de interfaz de usuario (estado=`activo` con +`awaiting_input_since` establecido). + +```mermaid +stateDiagram-v2 + [*] --> waiting: SessionStart startup/resume/clear (status=active + flag) + active --> active: SessionStart compact (mid-turn — state preserved, no flag) + waiting --> active: UserPromptSubmit / PreToolUse / PostToolUse + active --> waiting: Stop, non-error (flag re-stamped) + active --> waiting: Permission Notification (agent → waiting) + active --> waiting: Esc cancel (watchdog marker or idle timeout) + active --> error: Stop, stop_reason=error + active --> error: API error detected (watchdog) + waiting --> error: API error detected (watchdog) + error --> active: UserPromptSubmit / PreToolUse (recovery) + waiting --> completed: SessionEnd (CLI exited) + active --> completed: SessionEnd (CLI exited) + error --> error: SessionEnd (preserves error) + waiting --> abandoned: Stale > DASHBOARD_STALE_MINUTES (default 180) + active --> abandoned: Stale > DASHBOARD_STALE_MINUTES + completed --> active: Session resumed (new work event) + error --> active: Session resumed (new work event) + abandoned --> active: Session resumed (new work event) + completed --> [*] + error --> [*] + abandoned --> [*] +``` + +### Flujo de cálculo de costos + +```mermaid +flowchart LR + TU["token_usage rows
(per session × model)"] --> GROUP["Group by model"] + PR["model_pricing rules
(pattern-based)"] --> SORT["Sort by specificity
(longest pattern first)"] + GROUP --> MATCH{"Match model
to pricing rule"} + SORT --> MATCH + MATCH --> CALC["cost = Σ (tokens / 1M) × rate
for input, output, cache_read, cache_write"] + CALC --> RESULT["{ total_cost, breakdown[] }"] + style TU fill:#003B57,stroke:#005f8a,color:#fff + style PR fill:#6366f1,stroke:#818cf8,color:#fff + style RESULT fill:#10b981,stroke:#34d399,color:#fff +``` + +> [¡IMPORTANTE!] +> El flujo de cálculo de costos se basa en el uso de tokens y las reglas de precios del modelo. Asegúrese de que sus reglas de precios estén actualizadas para reflejar costos precisos. Actualice la tabla de precios del modelo a través de la página de Configuración para mantener un seguimiento preciso de los costos, ya que el panel de control no obtiene automáticamente actualizaciones de precios de fuentes externas. Una vez que haya establecido las reglas de precios, el panel de control las aplica retroactivamente a todas las sesiones para un informe de costos consistente. + +--- + +## Configuración + +| Variable de entorno | Valor predeterminado | Descripción | +| ----------------------- | ------------- | --------------------------------------------- | +| `DASHBOARD_PORT` | `4820` | Puerto para el servidor Express | +| `CLAUDE_DASHBOARD_PORT` | `4820` | Puerto utilizado por el gestor de ganchos para llegar al servidor | +| `NODE_ENV` | `desarrollo` | Configurado en `producción` para servir al cliente construido | +| `DASHBOARD_UPDATE_CHECK` | _(activado)_ | Establecido en `0` / `falso` / `desactivado` para desactivar las comprobaciones periódicas de git upstream | +| `DASHBOARD_UPDATE_CHECK_INTERVAL_MS` | `300000` (5 min) | Intervalo entre las comprobaciones automáticas; piso 60 000 ms. Los usuarios también pueden hacer clic en **Comprobar ahora** en la modalidad de actualización o en la barra lateral para ejecutarla a demanda. | +| `DASHBOARD_STALE_MINUTES` | `180` (3 h) | Minutos de inactividad antes de una sesión aún `activa` (incluyendo una sesión en **Esperando** la entrada del usuario — "Esperando" es una superposición de interfaz de usuario en una fila `activa`, no un estado almacenado) se marca automáticamente como **abandonada** y se elimina de la lista activa. Impulsado por el rastreador de 15 s y la limpieza periódica de mantenimiento (que se ejecuta cada ¼ de este valor, restringido a 60 s - 5 min). Baja el valor (por ejemplo, `60`) para un tiempo de espera de inactividad más corto | +| `DASHBOARD_WORKING_IDLE_SECONDS` | `120` | Tiempo de espera de inactividad para recuperar un turno cancelado con `Esc` **antes de cualquier salida** (lo que no deja ningún marcador de transcripción). Cuando el agente principal ha estado `trabajando` sin herramienta en vuelo y ni un evento de gancho ni la transcripción han avanzado tanto tiempo, el vigilante mueve la sesión a **Esperando**. Baja el tiempo para una recuperación más rápida a costa de ocasionales vuelcos falsos en giros largos de pensamiento silencioso (que se auto-curan) | +| `DASHBOARD_LIVENESS_PROBE` | `1` (activado) | Ajustado a `0` para desactivar el **reap de vitalidad de sesiones muertas** del vigilante (la sonda basada en `ps`/`lsof` que completa las sesiones `activas` cuyo proceso `claude` ya no existe, recuperando un `SessionEnd` perdido mientras el panel estaba inactivo). Las sesiones enviadas desde **otra máquina** (enlaces domésticos) informan de un `cwd` no POSIX y son omitidas automáticamente por el reap, por lo que una implementación local + enviada mixta ya no necesita esto desactivado; desactívalo solo para una configuración puramente remota donde los procesos locales no demuestren nada. Desactivado automáticamente en Windows y dentro de contenedores | +| `DASHBOARD_LIVENESS_IDLE_SECONDS` | `60` | Puerta de inactividad para la cosecha de vitalidad del **tiempo de muestreo del vigilante**: una sesión solo se completa cuando su transcripción no se ha escrito durante al menos este tiempo (la última escritura del gancho es el reloj de respaldo cuando no existe una transcripción en el disco), por lo que una sesión a mitad de turno o recién reanudada nunca se apaga en una falta de prueba transitoria. El arranque pasa por alto esta puerta: al arrancar, la prueba sola decide, por lo que las sesiones se cierran momentos antes del lanzamiento, se limpia inmediatamente | +| `DASHBOARD_SESSION_SYNC_MS` | `30000` | Intervalo de encuesta (ms) para la sincronización continua de fondo `~/.claude/projects` que muestra los proyectos añadidos después del inicio que nunca pasan por los ganchos. El observador `fs.watch` dispara casi instantáneamente independientemente; esta encuesta es la red de seguridad (los observadores pueden perder eventos / no disparar en los sistemas de archivos de red). Ajustado a `0` para desactivar la encuesta mientras deja que el observador funcione | +| `DASHBOARD_REMOTE_SYNC_MS` | `15000` (15 s) | Intervalo de encuesta (ms) para la sincronización de fondo de **Fuentes de datos remotas** que carga `~/.claude/projects` de cada remoto habilitado a través de SSH e lo reimporta a través del importador local. Las fuentes nuevas/habilitadas también se sincronizan inmediatamente. Ajustado a `0` para desactivar el encuestador (las sincronizaciones manuales/a pedido todavía funcionan) | +| `DASHBOARD_REMOTE_ACTIVE_WINDOW_MS` | `600000` (10 min) | Ventana de frescura para el estado en vivo de una sesión de **Fuente de datos remota**. En cada sincronización, una sesión remota cuya transcripción reflejada tiene un **último evento JSONL** dentro de esta ventana se trata como si aún estuviera en ejecución (`activa`); una vez que el espejo deja de avanzar durante más tiempo de lo normal, la sesión se reconcilia con `completada`. Las sesiones remotas no reciben ningún gancho en vivo, por lo que esto reemplaza las escaneos locales de actividad/desactualización (que las omiten). Aumente esto para enlaces lentos o giros de inactividad muy largos | +| `DASHBOARD_REMOTE_SYNC_TIMEOUT_MS` | `600000` (10 min) | Tiempo de espera por fuente (ms) para una sincronización remota única (`scp` pull + importación) antes de que se aborte | +| `DASHBOARD_REMOTE_TEST_TIMEOUT_MS` | `15000` (15 s) | Tiempo de espera (ms) para la sonda SSH de **Prueba** (`POST /api/remote-sources/:id/test`) que verifica que una fuente remota es accesible | +| `DASHBOARD_HOST` | `127.0.0.1` | Interfaz a la que el servidor se vincula. Retroceso por defecto (no accesible desde la red). Ajustado a `0.0.0.0` para exponerse en una LAN (registra una advertencia de inicio) | +| `DASHBOARD_TOKEN` | _(no establecido)_ | Cuando está establecido, cada solicitud `/api/*` y el WebSocket deben presentar el token (`Autorización: Portador `, encabezado `x-dashboard-token` o `?token=`). Desactivado por defecto, la vinculación de bucle es el límite de confianza | +| `DASHBOARD_ALLOWED_HOSTS` | _(loopback)_ | Se permiten valores adicionales de `Host` separados por coma en las actualizaciones de HTTP + WebSocket (guarda de rebinde DNS). Añada sus nombres de host LAN aquí cuando se vincule más allá del loopback | + +> [¡IMPORTANTE!] +> **Seguro por defecto.** El servidor vincula `127.0.0.1` y **no** es alcanzable desde la red de fábrica ([GHSA-gr74-4xfh-6jw9](./.github/SECURITY.md)). Para exponerlo en una LAN, configure **ambos** `DASHBOARD_HOST` (por ejemplo, `0.0.0.0`) **y** `DASHBOARD_TOKEN` (que luego bloquea `/api/*` y el WebSocket), y enumere los nombres de host de su LAN en `DASHBOARD_ALLOWED_HOSTS`. Consulte [`.env.example`](./.env.example) y [`.github/SECURITY.md`](./.github/SECURITY.md) para obtener más detalles. + +Para los clones de git, el servidor `git fetch` periódicamente `origin` y compara tu salida con `origin/master`, `origin/main` o `origin/HEAD`. Cuando estás atrasado, aparece un mensaje en el terminal del servidor y aparece una modal en la interfaz de usuario con el comando exacto para ejecutar. El panel nunca se carga ni se reinicia por sí mismo: copias el comando, lo ejecutas en un terminal y luego reinicias el servidor de la misma manera en que lo iniciaste. + +--- + +## CLI `ccam` + +La superficie completa de funciones del panel de control también está disponible desde cualquier terminal a través de la CLI **`ccam`** sin dependencias (`bin/ccam.js`). Se vincula automáticamente por `npm run setup` (a través de `npm link`), después de lo cual `ccam ` funciona desde cualquier directorio. Descubre el panel de control en ejecución a través de `~/.claude/.agent-dashboard.json` (el mismo registro de servidor en vivo que utiliza el gestor de ganchos), con las sobrepasadas de las variables de entorno `CLAUDE_DASHBOARD_PORT` / `DASHBOARD_PORT`, cayendo en `http://127.0.0.1:4820`. + +```bash +# Server +ccam status # ● running / ○ not running indicator +ccam start [--port N] # start the server in the background (detached) +ccam repl # interactive shell (also: shell, i) + +# Monitoring +ccam health # is the dashboard up? +ccam stats # totals, today's events, status distributions +ccam kanban # sessions + agents grouped by status columns +ccam tail [--session ] # live event feed in the terminal (Ctrl+C stops) + +# Data +ccam sessions [--status s] [--q text] [--limit n] +ccam session # detail: agent tree, cost, recent events +ccam agents [--status s] [--session id] +ccam events [--session id] [--limit n] + +# Insights +ccam analytics # token totals, top tools, agent types +ccam workflows [--session id] # workflow intelligence stats and patterns +ccam runs [--session id] # dynamic Workflow-tool runs +ccam cost [--session ] # total estimated cost with per-model breakdown + # (--session scopes to one; shows tool surcharges; + # warns about models with usage but no pricing rule) + +# Alerts & webhooks +ccam alerts [--unacked] # fired-alert feed +ccam alerts ack | ack-all # acknowledge alerts +ccam rules # list alert rules +ccam webhooks # list webhook targets +ccam webhooks test # send a synthetic test alert + +# Pricing +ccam pricing # list model pricing rules (incl. fast-mode & intro columns) +ccam pricing set --input N --output N [--cache-read N --cache-write N] + [--cache-write-1h N] [--fast-input N --fast-output N] + [--intro-input N --intro-output N … --intro-until YYYY-MM-DD] +ccam pricing delete +ccam pricing reset + +# Import +ccam import rescan # re-scan ~/.claude/projects +ccam import path # import every .jsonl under a directory + +# Administration +ccam doctor # connectivity, hooks, and database diagnosis +ccam info # raw system info JSON +ccam export [file.json] # full JSON data export +ccam import-data # restore an export (idempotent, non-destructive) +ccam cleanup --hours N --days M # abandon stale / purge old sessions +ccam reinstall-hooks # reinstall Claude Code hooks +ccam update-check # is the checkout behind upstream? (prints the update command) +ccam clear-data --yes # delete ALL data (requires --yes) +ccam open # open the dashboard in your browser +ccam version # print the CLI version (also --version / -v) +``` + +Los comandos respaldados por API necesitan que el servidor esté en ejecución, cuando no lo está, **los comandos de solo lectura recurren a la lectura directa de `data/dashboard.db`** (con un banner explícito de `⚠ Modo sin conexión`, y las sesiones `activas` almacenadas pero inactivas corregidas por el mismo proceso de detección de actividad que utiliza el rastreador del servidor), mientras que los comandos que no pueden ejecutarse correctamente sin el servidor (`tail` en vivo, análisis/matemáticas de costos, mutaciones) imprimen el indicador `○ El servidor del panel de control NO está en ejecución` con la razón específica y los comandos de inicio; `ccam start` inicia un servidor de producción en segundo plano. Los comandos de lectura siempre son seguros; el único comando destructivo (`clear-data`) se niega a ejecutarse sin un explícito `--yes`. La salida es una interfaz de usuario completa del terminal: tablas dibujadas en cuadrados con columnas numéricas alineadas a la derecha, iconos de estado (`● activo`, `○ esperando`, `✔ completado`, `✖ error`), gráficos de barras en línea para estadísticas/análisis/costes y árboles de agentes reales `├─`/`└─`: con los colores ANSI habilitados automáticamente en un TTY, desactivados cuando se canalizan y controlables a través de `--no-color` / `NO_COLOR` / `FORCE_COLOR`. Para una sesión de monitoreo en vivo, **`ccam repl`** (alias `shell` / `i`) abre un shell interactivo donde escribes comandos sin el prefijo `ccam` — con un banner de bienvenida CCAM, completado de pestañas, historial persistente de teclas de flecha, una solicitud de estado del servidor en vivo (`● host` arriba / `○ offline` abajo), un menú `help` / `help ` agrupado y un `watch [secs] ` incorporado que actualiza automáticamente cualquier comando (por ejemplo, `watch 5 kanban`); cada línea se ejecuta como un proceso hijo aislado, por lo que una negativa fuera de línea o un `tail` bloqueante nunca derriba el shell. Si `ccam` no está en tu PATH (por ejemplo, Se necesitan permisos elevados para `npm link`, ejecute `npm link` una vez desde la raíz del repositorio. Referencia completa: banderas, orden de descubrimiento, el REPL, modelo de seguridad, scripts/códigos de salida, resolución de problemas, en [docs/CLI.md](./docs/CLI.md). + +## Scripts npm + +| Comando | Descripción | +| ----------------------- | ---------------------------------------------------------- | +| `npm run setup` | Instalar las dependencias del servidor y del cliente | +| `npm run update:pull-setup` | `git pull --ff-only` luego `npm run setup` (actualización manual) | +| `npm run dev` | Iniciar el servidor (modo de observación) + el cliente (Vite HMR) de forma concurrente | +| `npm run dev:server` | Inicia solo el servidor Express con `--watch` | +| `npm run dev:client` | Iniciar solo el servidor de desarrollo Vite | +| `npm run build` | Construir el cliente React en `client/dist/` | +| `npm start` | Iniciar el servidor de producción (sirve al cliente construido) | +| `npm test` | Ejecuta la suite completa (servidor `node --test` + cliente Vitest) | +| `npm run test:server` | Ejecutar pruebas de backend (`node --test server/__tests__/`) | +| `npm run test:client` | Ejecuta las pruebas de Vitest de la interfaz de usuario, incluidas **capturas de pantalla de renderizado para cada pantalla** (`client/src/pages/__tests__/screens.snapshot.test.tsx`); regenera las líneas de base después de cambios intencionados en la interfaz de usuario con `cd client && npx vitest run -u` | +| `npm run install-hooks` | Configurar los ganchos de código Claude en `~/.claude/settings.json` | +| `npm run seed` | Rellenar la base de datos con datos de muestra | +| `npm run import-history`| Importar sesiones heredadas desde `~/.claude/` (también se ejecuta al iniciar la sesión) | +| `npm run clear-data` | Eliminar todas las sesiones, agentes, eventos y uso de tokens | +| `npm run mcp:install` | Instalar dependencias para el paquete MCP local (`mcp/`) | +| `npm run mcp:build` | Construir el servidor MCP TypeScript en `mcp/build/` | +| `npm run mcp:start` | Iniciar el servidor MCP (transporte stdio — para hosts MCP) | +| `npm run mcp:start:http`| Iniciar el servidor MCP (transporte HTTP + SSE en el puerto 8819) | +| `npm run mcp:start:repl`| Iniciar el servidor MCP (REPL interactivo con completación de pestañas) | +| `npm run mcp:dev` | Ejecutar el servidor MCP en modo dev (`tsx`, stdio) | +| `npm run mcp:dev:http` | Ejecutar el servidor MCP en modo de desarrollo (`tsx`, HTTP + SSE) | +| `npm run mcp:dev:repl` | Ejecutar el servidor MCP en modo de desarrollo (`tsx`, REPL interactivo) | +| `npm run mcp:typecheck` | Verificar el tipo de la fuente MCP sin emitir la salida de la compilación | +| `npm run mcp:docker:build` | Construir la imagen del contenedor MCP con Docker (`agent-dashboard-mcp:local`) | +| `npm run mcp:podman:build` | Construir la imagen del contenedor MCP con Podman (`localhost/agent-dashboard-mcp:local`) | +| `npm run desktop:install` | Instala Electron + electron-builder en el espacio de trabajo `desktop/` (reconstruye `better-sqlite3` para la ABI de Electron); realiza pruebas preliminares de la construcción nativa de `better-sqlite3` e imprime ayuda de configuración factible (incluyendo una alternativa sin cadena de herramientas) en caso de fallo | +| `npm run desktop:dev` | Construye y lanza la aplicación Electron para escritorio para iteraciones locales | +| `npm run desktop:build` | Compila las fuentes TypeScript del escritorio en `desktop/out/` | +| `npm run desktop:test` | Ejecuta la prueba de humo del escritorio (inicia Electron, prueba `/api/health`) | +| `npm run desktop:dmg` | Construir **ambos** DMG de macOS (arm64 + x64) - correctos para la versión, **más lentos** (paquetes para cada arquitectura) | +| `npm run desktop:dmg:arm64` | Construye un DMG solo de Apple-Silicona - **rápido**, recomendado para tu propio Mac | +| `npm run desktop:dmg:x64` | Construye un DMG solo para Intel — **rápido** | +| `npm run desktop:dmg:universal` | Construye un DMG **universal** fusionado (arm64 + x86_64) - opcional, **más lento**, no es lo que se envía con la versión | +| `npm run desktop:win` | Construir un instalador **NSIS** para Windows `.exe` (x64) — ejecutar en Windows | +| `npm run desktop:win:portable` | Construir un **portátil** de Windows (sin instalar) `.exe` (x64) — ejecutar en Windows | +| `npm run monitoring:install` | Ejecuta `npm install` en `monitoring/` — descarga Prometheus + Grafana a través de `postinstall` | +| `npm run monitoring:setup` | Alias para `monitoring:install` | +| `npm run monitoring:up` | Iniciar Prometheus (:9090) + Grafana (:3000) en segundo plano (sin Docker) | +| `npm run monitoring:down` | Detener la pila de monitoreo gestionada por npm | +| `npm run monitoring:start` | Pilas de monitoreo en primer plano (Ctrl+C detiene ambas) | +| `npm run monitoring:docker:up` | Iniciar Prometheus + Grafana a través de Docker Compose | +| `npm run monitoring:docker:down` | Desmontar la pila de monitoreo de Docker | +| `npm run monitoring:verify` | Panel de control de verificación de salud, Prometheus, Grafana y scraping de destino | +| `npm run docker:up` | Iniciar el panel de control en Docker (`docker compose up -d --build`) | +| `npm run docker:down` | Detener el contenedor del panel de control | +| `npm run docker:full:up` | Panel de control + Prometheus + Grafana, todo en Docker | +| `npm run docker:full:down` | Desmontar la pila Docker completa | + +--- + +## Extensión de agentes + +Este repositorio incluye una capa de extensión integral tanto para Claude Code como para Codex: + +- Código Claude: `CLAUDE.md`, `.claude/rules/`, `.claude/skills/` +- Subagentes de Claude: `.claude/agents/` +- Codex: `AGENTS.md`, `.codex/rules/`, `.codex/agents/`, `.codex/skills/` + +### Arquitectura de extensión + +```mermaid +graph TD + USER["Developer"] + CLAUDE["Claude Code"] + CODEX["Codex"] + MEMORY["CLAUDE.md + .claude/rules/*"] + C_SKILLS[".claude/skills/*"] + AGENTS_MD["AGENTS.md"] + X_RULES[".codex/rules/*.rules"] + X_AGENTS[".codex/agents/*.toml"] + X_SKILLS[".codex/skills/*"] + + USER --> CLAUDE + USER --> CODEX + CLAUDE --> MEMORY + CLAUDE --> C_SKILLS + CODEX --> AGENTS_MD + CODEX --> X_RULES + CODEX --> X_AGENTS + CODEX --> X_SKILLS +``` + +### Capa de código Claude + +- Contexto persistente: +- [`CLAUDE.md`](./CLAUDE.md) +- Reglas de alcance de ruta: +- [`.claude/rules/backend-node.md`](./.claude/rules/backend-node.md) +- [`.claude/rules/frontend-react.md`](./.claude/rules/frontend-react.md) +- [`.claude/rules/mcp-typescript.md`](./.claude/rules/mcp-typescript.md) +- [`.claude/rules/docs-markdown.md`](./.claude/rules/docs-markdown.md) +- Habilidades: +- `repo-onboarding` +- `característica de envío` +- `mcp-operaciones` +- `debug-live-issue` +- Subagentes: +- `revisor de backend` +- `revisor de frontend` +- `mcp-revisor` + +### Capa del Codex + +- Contexto persistente: +- [`AGENTES.md`](./AGENTES.md) +- Política de ejecución: +- [`.codex/rules/default.rules`](./.codex/rules/default.rules) +- Plantillas de subagentes personalizadas: +- [`.codex/agents/`](./.codex/agents) +- Habilidades: +- [`.codex/skills/`](./.codex/skills) +- Configuración: +- [`.codex/README.md`](./.codex/README.md) + +--- + +## Integración MCP + +Este proyecto incluye un servidor MCP local de grado de producción en `mcp/` que expone las operaciones del panel de control como herramientas para agentes de IA. Soporta tres modos de transporte para adaptarse a diferentes escenarios de integración. + +### Modos de transporte MCP + +```mermaid +flowchart LR + subgraph Transports["Transport Modes"] + STDIO["stdio\n(default)"] + HTTP["HTTP + SSE\n(port 8819)"] + REPL["Interactive REPL\n(terminal CLI)"] + end + + subgraph Protocols["Wire Protocols"] + P1["JSON-RPC\nstdin/stdout"] + P2["Streamable HTTP (2025-11-25)\nLegacy SSE (2024-11-05)"] + P3["Direct invocation\ntab completion + colored output"] + end + + STDIO --> P1 + HTTP --> P2 + REPL --> P3 + + style STDIO fill:#6366f1,stroke:#818cf8,color:#fff + style HTTP fill:#f59e0b,stroke:#fbbf24,color:#000 + style REPL fill:#a855f7,stroke:#c084fc,color:#fff +``` + +| Modo | Comando | Caso de uso | +| --- | --- | --- | +| **stdio** | `npm run mcp:start` | Código Claude, Claude Desktop, hosts IDE MCP | +| **HTTP** | `npm run mcp:start:http` | Clientes MCP remotos, integraciones web, múltiples sesiones | +| **REPL** | `npm run mcp:start:repl` | Debug de operaciones, invocación manual de herramientas, administrador local | + +

+MCP REPL +

+ +### Arquitectura MCP + +```mermaid +graph LR + HOST["MCP Host
(Claude Code / Claude Desktop)"] + HTTP_CLIENT["Remote MCP Client"] + OPERATOR["Operator CLI"] + + MCP_STDIO["MCP Server
stdio"] + MCP_HTTP["MCP Server
HTTP :8819"] + MCP_REPL["MCP Server
REPL"] + + API["Dashboard API
Express /api/*"] + DB["SQLite
data/dashboard.db"] + + HOST -->|"stdin/stdout"| MCP_STDIO + HTTP_CLIENT -->|"POST /mcp · GET /sse"| MCP_HTTP + OPERATOR -->|"interactive CLI"| MCP_REPL + + MCP_STDIO --> API + MCP_HTTP --> API + MCP_REPL --> API + API --> DB + + style HOST fill:#6366f1,stroke:#818cf8,color:#fff + style HTTP_CLIENT fill:#f59e0b,stroke:#fbbf24,color:#000 + style OPERATOR fill:#a855f7,stroke:#c084fc,color:#fff + style MCP_STDIO fill:#0f766e,stroke:#14b8a6,color:#fff + style MCP_HTTP fill:#0f766e,stroke:#14b8a6,color:#fff + style MCP_REPL fill:#0f766e,stroke:#14b8a6,color:#fff + style API fill:#339933,stroke:#5cb85c,color:#fff + style DB fill:#003B57,stroke:#005f8a,color:#fff +``` + +### Superficie de la herramienta MCP + +```mermaid +graph TD + ROOT["MCP Tools"] + OBS["Observability
health, stats, analytics,
system info, export, snapshot"] + SES["Sessions
list/get/create/update"] + AGT["Agents
list/get/create/update"] + EVT["Events & Hooks
list events, ingest hook events"] + PRC["Pricing & Cost
rules CRUD, total/session cost, reset defaults"] + MNT["Maintenance
cleanup, reimport, reinstall hooks, clear-all (guarded)"] + + ROOT --> OBS + ROOT --> SES + ROOT --> AGT + ROOT --> EVT + ROOT --> PRC + ROOT --> MNT +``` + +### Modelo de seguridad MCP + +```mermaid +flowchart TD + CALL["tools/call"] --> VALIDATE["zod input validation"] + VALIDATE --> TYPE{"Tool type?"} + TYPE -->|Read-only| EXEC["Execute"] + TYPE -->|Mutation| M_FLAG{"ALLOW_MUTATIONS?"} + M_FLAG -->|No| DENY1["❌ Reject"] + M_FLAG -->|Yes| DEST{"Destructive?"} + DEST -->|No| EXEC + DEST -->|Yes| D_FLAG{"ALLOW_DESTRUCTIVE?"} + D_FLAG -->|No| DENY2["❌ Reject"] + D_FLAG -->|Yes| TOKEN{"confirmation_token?"} + TOKEN -->|Invalid| DENY3["❌ Reject"] + TOKEN -->|Valid| EXEC + EXEC --> RESULT["Return tool result"] + + style EXEC fill:#339933,stroke:#5cb85c,color:#fff + style DENY1 fill:#dc2626,stroke:#f87171,color:#fff + style DENY2 fill:#dc2626,stroke:#f87171,color:#fff + style DENY3 fill:#dc2626,stroke:#f87171,color:#fff +``` + +### Modos operativos del MCP + +- Modo de lectura única (por defecto): `MCP_DASHBOARD_ALLOW_MUTATIONS=false` +- Modo de administrador: `MCP_DASHBOARD_ALLOW_MUTATIONS=true` +- Modo destructivo: requiere ambos: +- `MCP_DASHBOARD_ALLOW_MUTATIONS=true` +- `MCP_DASHBOARD_ALLOW_DESTRUCTIVE=true` +- entrada de la herramienta `confirmation_token: "CLEAR_ALL_DATA"` + +Detalles completos: [mcp/README.md](./mcp/README.md) + +--- + +## Referencia de API + +Todos los puntos finales devuelven JSON. Las respuestas de error siguen la forma `{ error: { código, mensaje } }`. + +### OpenAPI / Swagger / ReDoc + +Hay tres maneras de explorar la API HTTP, todas impulsadas por una sola especificación OpenAPI 3.0.3 (Puerto de servidor predeterminado `4820`): + +| Método | Camino | Descripción | +| ------ | ------------------------------- | ------------------------------------------------------------------------------------------------- | +| `GET` | `/api/openapi.json` | Especificación JSON Raw OpenAPI 3.0.3 | +| `GET` | `/api/docs` | **Interactiva interfaz de usuario Swagger** — ejecución de la solicitud de prueba | +| `GET` | `/api/redoc` | Referencia de **ReDoc**: una renderización limpia y optimizada para lectura de tres paneles de la misma especificación | +| `GET` | `/api/redoc/redoc.standalone.js` | Paquete ReDoc alojado por sí mismo (servido localmente a través de la dependencia `redoc`, nunca un CDN, funciona sin conexión) | + +El documento OpenAPI se genera desde `server/openapi.js` (`createOpenApiSpec()`), fusionado con fragmentos suplementarios en `server/openapi-extra/`. Tanto la interfaz de usuario Swagger como ReDoc son servidas directamente por el backend; el paquete ReDoc se sirve localmente (`GET /api/redoc/redoc.standalone.js`), por lo que la referencia funciona completamente sin conexión a Internet, consistente con la política del proyecto de no tener recursos externos. + +La cobertura es completa: cada ruta de backend está documentada (82 entradas de ruta) en estas etiquetas: Salud, Sesiones, Agentes, Eventos, Estadísticas, Métricas, Análisis, Ganchos, Precios, Flujos de trabajo, Configuración, Actualizaciones, Alertas, Webhooks, Push, CcConfig (explorador de configuración de Claude Code), Ejecución (ejecuciones iniciadas por el panel de control) y Documentación, cada una con parámetros, esquemas de solicitud/respuesta, descripciones a nivel de campo y ejemplos realistas. + +Un **`openapi.yaml`** comprometido en la raíz del repositorio refleja la especificación en vivo. Se genera a partir de `server/openapi.js` (nunca editado manualmente) - regeneréalo después de los cambios en la API con: + +```bash +npm run openapi:yaml +``` + +### Métricas de Prometheus y Grafana + +`GET /api/metrics` expone los contadores en vivo del panel de control: sesiones/agentes por estado, totales de eventos y tokens, clientes conectados en tiempo real, fuentes remotas configuradas, tiempo de actividad del proceso/memoria y versión de la compilación, en el formato de exposición de texto de Prometheus, para que CCAM pueda ser raspado en su propia pila de observabilidad. Una pila Prometheus + Grafana lista para usar con **cuatro paneles de control auto-provisionados** (página de inicio predeterminada: **CCAM - Visión general**) se encuentra en [`monitoring/`](./monitoring/README.md). + +**npm (sin Docker - macOS, Linux o Windows):** + +```bash +npm start # dashboard on :4820 +npm run monitoring:install # one-time: npm postinstall pulls binaries +npm run monitoring:up # Grafana on :3000 (login: admin / admin), auto-provisioned +``` + +**Docker / Podman** (cuando el panel de control se ejecuta en un contenedor o prefieres Compose): + +```bash +# Dashboard only +npm run docker:up + +# Dashboard + Prometheus + Grafana (one command) +npm run docker:full:up + +# Or mix: native/docker dashboard + docker monitoring +DASHBOARD_ALLOWED_HOSTS=host.docker.internal npm start # or docker:up with same env +npm run monitoring:docker:up +npm run monitoring:verify +``` + +

+Grafana CCAM — Panel de control general con sesión en vivo, métricas de eventos y tokens +
+📊 Grafana · CCAM — Descripción general — panel de control principal predeterminado (cuatro tableros provistos automáticamente): instantánea de la flota, totales de la base de datos, gráficos de desglose y tarifas — todo desde raspados en vivo de /api/metrics +

+ +

+Consola Prometheus CCAM con tarjetas métricas y tablas de sesiones +
+🔥 Prometheus · Consola CCAM — página de inicio preconstruida en /consoles/index.html que consulta directamente a Prometheus para obtener la salud de la escraping, los totales de sesiones, los eventos, los tokens y los enlaces de gráfico para profundizar +

+ +

+Interfaz de usuario gráfica de Prometheus con consulta CCAM PromQL +
+📈 Prometheus · Gráfico — ejecute PromQL contra métricas CCAM raspadas (por ejemplo, sum(ccam_sessions), ccam_events_total, rate(ccam_tokens_total[5m])) con enlaces de inicio desde la consola CCAM y monitoring/README.md +

+ +Consulte [docs/API.md → Metricas](./docs/API.md#metrics) para obtener la lista completa de métricas y los detalles de scraping/autenticación. + +

+Interfaz de usuario de Swagger +

+ +

+ReDoc UI +

+ +### Salud + +| Método | Camino | Descripción | +| ------ | ------------- | ------------------------------------- | +| `GET` | `/api/health` | Devuelve `{ status: "ok", timestamp }` | + +### Sesiones + +| Método | Ruta | Parámetros de la consulta | Descripción | +| ------- | ------------------------------- | ---------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | +| `GET` | `/api/sessions` | `status`, `q`, `limit`, `offset` | Lista las sesiones con el número de agentes y el costo por sesión. `q` realiza una búsqueda insensible a mayúsculas y minúsculas en `id` / `name` / `cwd`. `limit` por defecto es 50, máximo 10000. La respuesta incluye `total` para los paginadores. | +| `GET` | `/api/sessions/:id` | -- | Detalles de la sesión con agentes y eventos | +| `GET` | `/api/sessions/:id/stats` | -- | Contas agregadas que alimentan el panel de resumen de detalles de la sesión: eventos, eventos por tipo, uso principal de las herramientas, número de errores, contadores de tipo/estatus del agente, desglose del tipo de subagente, totales de tokens, rango de tiempo | +| `GET` | `/api/sessions/:id/transcripts` | -- | Lista de transcripciones JSONL disponibles para la sesión (principales + subagentes + compactaciones) | +| `GET` | `/api/sessions/:id/transcript` | `agent_id`, `limit`, `offset`, `after`, `before` | Transmite mensajes de un transcripción específica con paginación basada en el cursor. El `uso` del asistente incluye `input_tokens`, `output_tokens`, `cache_read_input_tokens`, `cache_creation_input_tokens`, por lo que el medidor de la página de Ejecución puede hidratarse completamente al reiniciar / volver a adjuntar | +| `POST` | `/api/sessions` | -- | Crear sesión (idempotente en `id`) | +| `PATCH` | `/api/sessions/:id` | -- | Actualizar el estado/metadata de la sesión | + +### Agentes + +| Método | Ruta | Parámetros de la consulta | Descripción | +| ------- | ----------------- | ----------------------------------------- | ----------------------------- | +| `GET` | `/api/agents` | `status`, `session_id`, `limit`, `offset` | Lista de agentes con filtros | +| `GET` | `/api/agents/:id` | -- | Detalles de un solo agente | +| `POST` | `/api/agents` | -- | Crear agente | +| `PATCH` | `/api/agents/:id` | -- | Actualizar el estado/tarea/herramienta del agente | + +### Eventos + +| Método | Ruta | Parámetros de la consulta | Descripción | +| ------ | ------------- | ------------------------------- | -------------------------- | +| `GET` | `/api/events` | `session_id`, `limit`, `offset` | Lista de eventos (los más recientes primero) | + +### Estadísticas + +| Método | Camino | Descripción | +| ------ | ------------ | ------------------------------------------------------ | +| `GET` | `/api/stats` | Contas agregadas, distribuciones de estado, conexiones WS | + +### Análisis + +| Método | Camino | Descripción | +| ------ | ---------------- | ---------------------------------------------------------- | +| `GET` | `/api/analytics` | Agregados de tokens/herramientas/sesiones para gráficos y vistas de tendencias | + +### Fuentes de datos remotas + +| Método | Ruta | Parámetros de la consulta | Descripción | +| -------- | ------------------------------- | ------------ | ------------------------------------------------------------------------------------------- | +| `GET` | `/api/remote-sources` | -- | Lista de fuentes remotas configuradas con estado, último error y conteos de última sincronización | +| `POST` | `/api/remote-sources` | -- | Crear una fuente. Cuerpo: `{ label, host, ssh_port?, identity_file?, remote_home?, enabled? }` | +| `PATCH` | `/api/remote-sources/:id` | -- | Actualizar una fuente (etiqueta, campos de conexión, habilitado) | +| `ELIMINAR` | `/api/remote-sources/:id` | `purge` | Eliminar una fuente; `?purge=true` también elimina las sesiones importadas de esa fuente' | +| `POST` | `/api/remote-sources/:id/test` | -- | Probar la conectividad SSH a la fuente | +| `POST` | `/api/remote-sources/:id/sync` | -- | Extraiga e importe de nuevo desde la fuente ahora | + +`GET /api/sessions`, `/api/events`, `/api/agents`, `/api/stats`, y `/api/analytics` también aceptan un parámetro de consulta opcional `sources` (ids de fuente separados por coma; omitir para todos) para restringir los resultados por origen, y `GET /api/sessions/facets` devuelve una matriz `sources` para el selector de rango de datos. + +### Ganchos + +| Método | Camino | Descripción | +| ------ | ------------------ | -------------------------------------------- | +| `POST` | `/api/hooks/event` | Recibir y procesar un evento de gancho de código Claude | + +**Peso de carga del evento de conexión:** + +```json +{ + "hook_type": "PreToolUse", + "data": { + "session_id": "abc-123", + "tool_name": "Bash", + "tool_input": { "command": "ls -la" } + } +} +``` + +### Precios + +| Método | Ruta | Descripción | +| -------- | ------------------------ | ---------------------------------------- | +| `GET` | `/api/pricing` | Lista todas las reglas de precios | +| `PUT` | `/api/pricing` | Crear o actualizar una regla de precios | +| `ELIMINAR` | `/api/pricing/:pattern` | Eliminar una regla de precios | +| `GET` | `/api/pricing/cost` | Costo total de todas las sesiones | +| `GET` | `/api/pricing/cost/:id` | Desglose de costos para una sesión específica | + +### Flujos de trabajo + +| Método | Camino | Descripción | +| ------ | ----------------------------- | ------------------------------------------------------- | +| `GET` | `/api/workflows` | Agrupa los datos del flujo de trabajo (orquestación, herramientas, patrones). El filtro opcional de la consulta `?status=active\|completed` filtra todas las 11 secciones de datos por el estado de la sesión | +| `GET` | `/api/workflows/session/:id` | Entrenamiento por sesión (árbol de agentes, cronología de herramientas, eventos) | + +### Alertas + +| Método | Ruta | Descripción | +| -------- | ------------------------ | ---------------------------------------------------------------------- | +| `GET` | `/api/alerts` | Feed de alertas de disparos, desde el más reciente primero (`?unacked=true`, `limit`, `offset`) | +| `POST` | `/api/alerts/:id/ack` | Reconocer una alerta | +| `POST` | `/api/alerts/ack-all` | Reconocer cada alerta no reconocida | +| `GET` | `/api/alerts/rules` | Lista de reglas de alertas | +| `POST` | `/api/alerts/rules` | Crear una regla (`event_pattern` \| `inactivity` \| `status_duration` \| `token_threshold`) | +| `PATCH` | `/api/alerts/rules/:id` | Actualizar nombre / configuración / habilitado / tiempo de espera (el tipo de regla es inmutable) | +| `ELIMINAR` | `/api/alerts/rules/:id` | Eliminar una regla y su historial de alertas activadas | + +### Webhooks + +| Método | Ruta | Descripción | +| -------- | --------------------------------- | ------------------------------------------------------------------------------------ | +| `GET` | `/api/webhooks/providers` | Proveedores compatibles + sus campos de configuración (ejecuta el formulario de la interfaz de usuario) | +| `GET` | `/api/webhooks` | Lista de objetivos de webhook (URLs encriptadas, secretos redactados) | +| `POST` | `/api/webhooks` | Crear un objetivo (14 proveedores de primera clase + `genérico`) | +| `PATCH` | `/api/webhooks/:id` | Actualizar nombre / URL / habilitado / secreto / encabezados / alcance de la regla (el tipo es inmutable) | +| `ELIMINAR` | `/api/webhooks/:id` | Eliminar un objetivo y su registro de entrega | +| `POST` | `/api/webhooks/:id/test` | Enviar una alerta de prueba sintética y informar el resultado de la entrega | +| `GET` | `/api/webhooks/:id/deliveries` | Registro de entregas recientes para un objetivo (`limit`, `offset`) | + +### Configuración + +| Método | Camino | Descripción | +| ------ | ------------------------------ | ------------------------------------------------ | +| `GET` | `/api/settings/info` | Información del sistema, estadísticas de la base de datos, estado del gancho | +| `POST` | `/api/settings/clear-data` | Eliminar todas las sesiones, agentes, eventos, uso de tokens | +| `POST` | `/api/settings/reimport` | Reimportar sesiones heredadas desde `~/.claude/` | +| `POST` | `/api/settings/reinstall-hooks`| Reinstalar los ganchos de código Claude | +| `POST` | `/api/settings/reset-pricing` | Restablecer los precios a los valores predeterminados | +| `GET` | `/api/settings/export` | Exportar todos los datos (sesiones, agentes, eventos, uso de tokens, flujos de trabajo, ejecuciones de panel de control, reglas de alerta, precios de modelos) como una descarga JSON versificada | +| `POST` | `/api/settings/import` | Restaurar un paquete desde `/export` (`file` multipart o `{ path }` JSON). Idóntico + no destructivo: se omiten por completo las sesiones existentes | +| `POST` | `/api/settings/cleanup` | Abandonar sesiones obsoletas, purgar datos antiguos | + +### Explorador de configuración de Claude (`/api/cc-config`) + +Inspección de lectura única de cada superficie de configuración de Claude Code, además de mutaciones cuidadosamente controladas para artefactos de archivos de texto de bajo riesgo. Todos los caminos de escritura crean copias de seguridad con hora y fecha bajo `/cc-config-backups//` antes de mutar. + +| Método | Ruta | Descripción | +| -------- | ----------------------------------- | ----------- | +| `GET` | `/api/cc-config/overview` | Raíces (claude home, proyecto .claude, raíz del proyecto, ~/.claude.json) + contadores para cada superficie | +| `GET` | `/api/cc-config/skills` | Habilidades bajo `/.claude/skills//SKILL.md` con materia principal parseada; `?scope=user\|project\|all` | +| `GET` | `/api/cc-config/agents` | Subagentes `/.claude/agents/*.md` | +| `GET` | `/api/cc-config/commands` | Comandos de guiones bajos `/.claude/commands/*.md` | +| `GET` | `/api/cc-config/output-styles` | Estilos de salida `/.claude/output-styles/*.md` | +| `GET` | `/api/cc-config/plugins` | Plugins instalados desde `~/.claude/plugins/installed_plugins.json`, unidos con `enabledPlugins` de la configuración; cada entrada incluye `contributes` (cuenta de habilidades/agentes/comandos/gatillos/estilos de salida dentro de la carpeta de instalación del plugin) más metadatos `plugin.json` | +| `GET` | `/api/cc-config/marketplaces` | Mercados registrados de `known_marketplaces.json`, enriquecidos con el propio `marketplace.json` de cada mercado (número de complementos, propietario, descripción) | +| `GET` | `/api/cc-config/mcp` | Servidores MCP desde `~/.claude.json` (nivel superior + por proyecto) y `settings.json` | +| `GET` | `/api/cc-config/hooks` | Hooks agregados en los archivos `settings.json` de usuario / proyecto / proyecto local | +| `GET` | `/api/cc-config/hook-scripts` | Archivos en `~/.claude/hooks/` (los scripts auxiliares que se refieren a `hooks..command`) | +| `GET` | `/api/cc-config/keybindings` | `~/.claude/keybindings.json` parseado en pares clave/acción agrupados por grupo de contexto | +| `PUT` | `/api/cc-config/keybindings` | Sustituye `keybindings.json` por `{ groups: [{ context, bindings: [{ key, action }] }] }`. Hace una copia de seguridad primero, preserva los metadatos de nivel superior (`$schema`/`$docs`), rechaza contextos/keys duplicados. Seguro de editar (a diferencia de `settings.json`, la CLI nunca lo vuelve a escribir en medio de la sesión) | +| `GET` | `/api/cc-config/statusline` | configuración de `settings.json.statusLine` + el contenido actual de `statusline.py` / `statusline-command.sh` si está presente | +| `GET` | `/api/cc-config/settings` | Configuración JSON de usuario / proyecto / configuración local del proyecto, con claves similares a secretos (correspondientes a `/token\|secret\|password\|api[_-]?key\|auth/i`) reemplazadas por `""` | +| `GET` | `/api/cc-config/memory` | Archivos `CLAUDE.md` en el ámbito del usuario + proyecto, además de la memoria basada en archivos por proyecto: elementos `scope:"auto-memory"` (cada uno con `project`, `name`, `isIndex` y `frontmatter` parseado) para cada `*.md` bajo `~/.claude/projects//memory/`. Mutar a través de `PUT`/`DELETE /api/cc-config/file` con `{ scope: "auto-memory", type: "auto-memory", project, name }` (las copias de seguridad se almacenan en `/.cc-config-backups/auto-memory/`) | +| `GET` | `/api/cc-config/file?path=…` | Cuerpo de un solo archivo (ruta contenida en CLAUDE_HOME / proyecto .claude / proyecto CLAUDE.md) | +| `GET` | `/api/cc-config/backups` | Lista de todas las copias de seguridad con fecha y hora, opcionalmente filtradas `?scope=&type=` | +| `PUT` | `/api/cc-config/file` | Crear o sobrescribir un artefacto de archivo de texto. Cuerpo: `{ scope, type, name?, content }`. Copia de seguridad automática si el archivo existe. Temporal atómico + renombrar. Límite de contenido de 256 KB, regex estricta de `name` | +| `ELIMINAR` | `/api/cc-config/file` | Hacer una copia de seguridad y luego eliminar un artefacto de archivo de texto. Las carpetas de habilidades se copian de seguridad enteras (preservando los activos empaquetados) antes de la eliminación recursiva | + +### Ejecutar Claude (`/api/run`) + +Superficie HTTP para iniciar y supervisar subprocesos `claude` desde el panel de control. Guardia de origen compartido en todas las rutas: las solicitudes del navegador deben provenir de un origen localhost; las solicitudes con origen faltante (CLI/curl) pasan. + +| Método | Ruta | Descripción | +| -------- | --------------------------------- | ----------- | +| `GET` | `/api/run` | Lista todas las manejadoras de ejecución en memoria (en vivo + recientemente terminadas); también devuelve `maxConcurrent` y `activeCount` | +| `GET` | `/api/run/binary` | Probar si `claude` está en `PATH` y dónde vive, utilizado por la interfaz de usuario para mostrar un error claro antes de generar | +| `GET` | `/api/run/cwds` | Directorios de trabajo sugeridos: servidor de panel de control cwd, `$HOME` y cwds recientes de la tabla de sesiones | +| `GET` | `/api/run/files?cwd=…&q=…` | Búsqueda de archivos borrosos dentro de `cwd` para el autocompletado de archivos `@` de la página de Ejecución. Saltan `node_modules`, `.git`, `dist`, `build`, `.next`, `.cache`, `coverage`, etc. Cwd es obligatorio y debe existir; los resultados están limitados y clasificados por la coincidencia del nombre raíz | +| `POST` | `/api/run` | Genera una nueva ejecución. Body: `{ prompt, mode: "headless"\|"conversation", cwd?, model?, permissionMode?, resumeSessionId?, effort? }`. Headless coloca el prompt en argv a través de `-p` y cierra stdin. Conversation canaliza el prompt a través de stdin como un paquete stream-json y mantiene stdin abierto para los siguientes pasos. `resumeSessionId` (solo para conversación) agrega `--resume `; cuando se establece, `prompt` puede estar vacío: el generador omite la escritura inicial de stdin y `claude` se queda en espera en la conversación reanudada hasta que el usuario publique un seguimiento a través de `POST /api/run/:id/message`. `effort` (`low` / `medium` / `high`) se traduce a `--effort`. El generador siempre pasa `--output-format stream-json --verbose --include-partial-messages` para que la interfaz de usuario pueda renderizar las diferencias carácter por carácter. La concurrencia no está efectivamente limitada (techo predeterminado de 10000 - sobrescribir con `RUN_MAX_CONCURRENT`) | +| `GET` | `/api/run/:id` | Estado actual del manejador. `?envelopes=1` incluye el registro de sobres en memoria para que la interfaz de usuario pueda reproducir el historial cuando se vuelva a adjuntar | +| `POST` | `/api/run/:id/message` | Enviar una ronda de seguimiento a una conversación en curso (solo modo de conversación). Texto: `{ texto }` | +| `ELIMINAR` | `/api/run/:id` | Detener una ejecución. SIGTERM, escalando a SIGKILL después de 5 s | + +Los flujos de salida sobre el WebSocket del panel de control existente se dividen en tres tipos de mensajes: `run_stream` (envelope stream-json procesado, incluyendo deltas de `stream_event` de `--include-partial-messages`), `run_status` (transiciones de estado), `run_input_ack` (escritura confirmada en stdin). La página Config Explorer se suscribe a un cuarto mensaje — `cc_config_changed` — emitido por `server/lib/cc-watcher.js` (a través de `fs.watch` en `~/.claude/`) y por `routes/cc-config.js` después de cada PUT/DELETE exitoso, con un payload `{ source: "dashboard"|"fs", action?, scope?, type?, name?, paths? }`. La lista de Sesiones y la página SessionDetail consultan `/api/run` (y escuchan por `run_status`) para marcar cualquier sesión actualmente ejecutada por una Run en vuelo con un indicador **▶ Run** interactivo que vuelve a `/run`. + +### Historial de importaciones + +Traiga las sesiones existentes de Claude Code al panel de control desde tres +Fuentes diferentes, todas canalizadas a través del mismo analizador que utiliza el servidor +Para la ingestión en vivo, por lo que los tokens importados, el costo por modelo, las compactaciones, +Los subagentes, el uso de herramientas y las duraciones de los turnos coinciden con la captura en tiempo real +Bits por bit. Las reimportaciones son idempotentes: las sesiones se codifican por ID y +Las líneas de base de compactación preservan los totales de tokens previos a la compactación, por lo que ejecutar +El importador nunca cuenta el uso o el costo dos veces. + +Un cuarto modo: **Restaurar copia de seguridad**, importa una exportación completa del panel de control. +`.json` (producido por el botón **Exportar datos**, `ccam export`, o +`GET /api/settings/export`) en lugar de transcripciones brutas de Claude. Esto es +La contraparte de ida y vuelta de Exportación: restaura cada tabla (sesiones, +Agentes, eventos, uso de tokens, flujos de trabajo, ejecuciones de panel de control, reglas de alerta, +model_pricing) y es idempotente + no destructivo, una sesión ya +El presente se omite por completo, por lo que puedes **consolidar varios de forma segura +Máquinas** en un panel de control sin duplicar ni sobrescribir +Cualquier cosa. Apoyado por `server/lib/data-transfer.js` y +`POST /api/settings/import` (también `ccam import-data `). + +```mermaid +flowchart LR + subgraph Sources + A1["Default folder
~/.claude/projects"] + A2["Custom folder
any absolute path"] + A3["Uploaded files
.jsonl / .meta.json /
.zip / .tar(.gz) / .gz"] + end + + A1 -->|POST /api/import/rescan| R["server/routes/import.js"] + A2 -->|POST /api/import/scan-path| R + A3 -->|POST /api/import/upload
multipart| R + + R -->|archive extract
+ path-traversal guard
+ zip-bomb cap| X["server/lib/archive.js"] + R -->|walks recursively| I["importFromDirectory
(scripts/import-history.js)"] + X --> I + I -->|same pipeline as live
hook ingestion| P["parseSessionFile +
importSession"] + P -->|prepared statements,
in one transaction| D[("SQLite
sessions / agents / events /
token_usage")] + I -.->|import.progress
throttled| W["WebSocket /ws"] + W -.-> U["Settings → Import History
progress bar + result card"] + + style A1 fill:#6366f1,stroke:#818cf8,color:#fff + style A2 fill:#6366f1,stroke:#818cf8,color:#fff + style A3 fill:#6366f1,stroke:#818cf8,color:#fff + style R fill:#1a1a28,stroke:#2a2a3d,color:#e4e4ed + style X fill:#1a1a28,stroke:#2a2a3d,color:#e4e4ed + style I fill:#1a1a28,stroke:#2a2a3d,color:#e4e4ed + style P fill:#f59e0b,stroke:#fbbf24,color:#000 + style D fill:#10b981,stroke:#34d399,color:#fff + style U fill:#a855f7,stroke:#c084fc,color:#fff +``` + +**Rutas** + +| Método | Camino | Descripción | +| ------ | ----------------------- | ------------------------------------------------------------------------ | +| `GET` | `/api/import/guide` | Caminos compatibles con sistemas operativos, comando de archivo, extensiones compatibles, instrucciones paso a paso | +| `POST` | `/api/import/rescan` | Recargar el directorio predeterminado `~/.claude/projects` | +| `POST` | `/api/import/scan-path` | Escanea un directorio absoluto (cuerpo `{ path }`); recorre recursivamente | +| `POST` | `/api/import/upload` | Subida multipartita de `.jsonl`, `.meta.json`, `.zip`, `.tar(.gz)`, `.gz` | + +**Entradas compatibles.** Transcripciones de sesiones JSONL sueltas (`.jsonl`), sus +Companion `.meta.json` sidecars, y archivos (`.zip`, `.tar`, +`.tar.gz`/`.tgz`, `.gz` simple) que contenga cualquier disposición de directorios anidados. +Ambos diseños del código Claude canónico se reconocen automáticamente: +`//subagents/agent-*.jsonl` (por defecto) y +`/subagents//agent-*.jsonl` (alternativo). + +**Garantías de precisión.** Las sesiones se deduplican por UUID; se repite la ejecución +el importador siempre está seguro. La compactación `baseline_input` / +`baseline_output` / `baseline_cache_read` / `baseline_cache_write` +Las columnas conservan el número de tokens de antes de que una transcripción fuera compactada, +Por lo tanto, reingestionar un JSONL posterior a la compactación nunca borra el costo histórico. +La deduplicación a nivel de evento utiliza una marca alta por tipo de evento +(`MAX(created_at) GROUP BY event_type` para la sesión): en cada +Solo se importan de nuevo las entradas JSONL con `ts > cutoff[type]` insertadas, por lo que +Sesiones de larga duración cuyas transcripciones crecen a lo largo de varios días +Continuar recibiendo Stop / PostToolUse / TurnDuration / ToolError +Eventos sin duplicar el trabajo anterior. `sessions.ended_at` se vuelve retroactivo +Avanzar a la última actividad de JSONL cuando supere la almacenada +El valor y los metadatos de número de mensajes se actualizan en cada pasada. + +**Seguridad de transcripciones enormes.** La caché compartida de transcripciones +(`server/lib/transcript-cache.js`) lee archivos JSONL en trozos de 4 MiB +y descodifica solo una línea a la vez, por lo que las transcripciones más grandes que las de V8 +Longitud máxima de cadena JS (~512 MiB en Node 20 de 64 bits) analizar sin +Abortando el proceso con `ERROR FATAL: v8::ToLocalChecked Empty +MaybeLocal`. El mismo camino fragmentado se utiliza por la ingestión de ganchos, el +Escaneo de compactación periódica y el importador de historial, ninguno de ellos +Materializar el archivo completo como una sola cadena JS. Crece de forma escalable por entrada +Arrays (`turnDurations`, `errors`, `compaction.entries`, +`usageExtras.*`) se acaban en la cola en `TRANSCRIPT_CACHE_MAX_ARRAY_LEN` +(por defecto `1000`), con recorte aplicado durante la parseo a un `2 × cap` +marca de agua para que una nueva y completa analítica de archivo en una sesión de varios días no pueda +Construir un transitorio ilimitado antes de la finalización. + +**Seguridad.** La extracción de archivos valida cada entrada contra el camino +Travesía (se rechazan los caminos absolutos y los segmentos `..`). A +Tapón de extracción configurable (`CCAM_IMPORT_MAX_EXTRACT_BYTES`, predeterminado +4 GB) detiene las bombas zip/tar/gzip. El tamaño de carga se limita por archivo +(`CCAM_IMPORT_MAX_BYTES`, por defecto 1 GB) y por solicitud +(`CCAM_IMPORT_MAX_FILES`, por defecto 2000). Todos los directorios de ensayo son +Por solicitud y recuperado en `finalmente`, incluyendo cuando multer rechaza +Todos los archivos en primer plano. + +**Progreso.** La actividad de importación se transmite a través del WebSocket existente +Como mensajes de `import.progress` (`fase`: `start` / `scan` / `extract` / +`parse` / `complete` / `error`), restringido para evitar inundar el +Canal sobre grandes importaciones. + +**UI.** Utilice el panel **Configuración → Historial de importación** para una guía, +Experiencia de arrastrar y soltar con instrucciones paso a paso, progreso en vivo, +Y un resumen posterior a la importación que muestra importado / enriquecido / omitido / +Contas de errores. + +

+Historia de importación de la interfaz de usuario +

+ +### WebSocket + +Conéctese a `ws://localhost:4820/ws` para recibir mensajes push en tiempo real: + +```json +{ + "type": "agent_updated", + "data": { "id": "...", "status": "working", "current_tool": "Edit" }, + "timestamp": "2026-03-05T15:43:01.800Z" +} +``` + +**Tipos de mensajes:** `session_created`, `session_updated`, `agent_created`, `agent_updated`, `new_event`, `alert_triggered`, `alert_updated`, `remote_source.status` (datos `{ id, status: "idle"|"syncing"|"ok"|"error"|"deleted", error?, last_sync_at? }`) + +```mermaid +stateDiagram-v2 + [*] --> Connecting: Component mounts + Connecting --> Connected: onopen + Connected --> Closed: onclose / onerror + Closed --> Connecting: setTimeout(2000ms) + Connected --> [*]: Component unmounts + Closed --> [*]: Component unmounts +``` + +--- + +## Eventos de enganchamiento + +El panel de control procesa estos tipos de ganchos de código Claude: + +| Tipo de gancho | Activador | Acción del panel de instrumentos | +| ------------------- | ------------------------------ | -------------------------------------------------------------------------------------------- | +| `SessionStart` | Comienza la sesión de Claude Code | Crea la sesión y el agente principal. Marca `awaiting_input_since` (con `awaiting_reason=session_start`) para que una nueva sesión se encuentre en **Esperando**, excepto una SessionStart de fuente `compact` (compactación automática a mitad de turno), que deja la bandera sin tocar para que una sesión activa siga **Activa**. Reactiva las sesiones suspendidas. Abandona las sesiones huérfanas sin actividad durante `DASHBOARD_STALE_MINUTES` (por defecto 180) | +| `UserPromptSubmit` | El usuario pulsa enter en una solicitud | Borra la bandera de espera y promueve al agente principal a `working` (en funcionamiento) - la única señal de que las conversaciones con el asistente de texto han comenzado, ya que no emiten `PreToolUse` | +| `PreToolUse` | El agente comienza a usar una herramienta | Borra la bandera de espera, establece al agente en `working`, establece `current_tool`. Si la herramienta es `Agent`, crea un registro de subagente | +| `PostToolUse` | Ejecución de la herramienta completada | Borra la bandera de espera (maneja las aprobaciones de solicitud de permiso donde la Notificación la estampó en medio de la herramienta). Borra `current_tool`. El agente permanece `trabajando` | +| `Stop` | Claude termina de responder | Sin error: agente principal → `esperando` — Claude terminó su turno, la pelota está en el campo del usuario. `stop_reason=error`: marca el agente y la sesión `error`. Los subagentes de fondo siguen ejecutándose | +| `SubagentStop` | Agente de fondo terminado | Encuentra y completa el subagente por descripción, tipo o tarea. No borra deliberadamente la bandera de espera, ya que el fin de un subagente no nos dice nada sobre el humano. **Activa una escaneo JSONL de "fire-and-forget"** (`scanAndImportSubagents`) que emite eventos `PreToolUse` + `PostToolUse` por herramienta bajo el propio `agent_id` del subagente, por lo que la Línea de Tiempo muestra todas las herramientas que ejecutó el subagente, no solo el marcador de aparición | +| `Notificación` | Notificación del agente | Registra el evento. Los mensajes de permiso/petición de entrada establecen al agente en `esperando` y estampan `awaiting_input_since` (con `awaiting_reason=notification`, coincidiendo con el patrón: `permission`, `waiting for input`, `needs your approval`, ...). Las notificaciones de compactación se etiquetan como eventos de `Compactación`. Desactiva una notificación del navegador si está habilitada | +| `SessionEnd` | El proceso CLI de Claude Code termina | Quita la bandera de espera. Si la sesión ya está en `error`, el estado de error se preserva; de lo contrario, marca a todos los agentes y la sesión como `completada` | +| `Compactación` | `/compact` detectado en JSONL | Crea un subagente de compactación (tipo `compactación`) y un evento de compactación. Detectado a través de las entradas `isCompactSummary` en el JSONL de la transcripción. También detectado por el escáner periódico para sesiones activas | +| `APIError` | Error API en la transcripción JSONL | Extraído de las entradas de `isApiErrorMessage` (cuota, límite de tasa, solicitud inválida) y las respuestas brutas de `type: "error"`. **Ahora marca inmediatamente la sesión y el agente como `error`**, anteriormente registrados como eventos sin cambiar el estado. Almacenado como evento con detalles de error | +| `TurnDuration` | Tiempo de giro en la transcripción JSONL | Extraído de los mensajes del subtipo `turn_duration` de `system` con `durationMs`. Almacenado como evento para el análisis del tiempo de nivel de giro | +| `ToolError` | Error de resultado de la herramienta en JSONL | Extraído de las entradas de `toolUseResult.is_error`. Registra los fallos a nivel de herramienta para el análisis de propagación de errores | +| `Interrumpido` | Turno cancelado por el usuario (Esc) | Sintetizado por el vigilante — `Esc` no dispara ningún gancho, por lo que se detecta una sesión `trabajando` atascada desde el marcador `[Solicitud interrumpida por el usuario]` de la transcripción o, cuando Esc precedió a cualquier salida, desde el tiempo de espera de `trabajo inactivo` (`DASHBOARD_WORKING_IDLE_SECONDS`). La sesión pasa a **Esperando** (mismo que un `Detener` normal) | + +--- + +## Notificaciones del navegador + +El panel de control admite notificaciones persistentes del navegador a través de Web Push (VAPID) para alertas en tiempo real incluso cuando la pestaña del panel de control no está enfocada o el navegador está en segundo plano. + +### Cómo funciona + +1. **Activar** las notificaciones en la página de Configuración a través del interruptor principal +2. **Conceder** permiso al navegador cuando se le solicite, esto registra un Servidor de Servicios y crea una suscripción push. +3. **Configurar** qué eventos desencadenan notificaciones: + +| Evento | Por defecto | Descripción | +| ---------------------------- | ------- | --------------------------------------------------------------- | +| Comienza una nueva sesión | En | Se activa cuando se crea una nueva sesión de Claude Code | +| Claude terminó de responder | Desactivado | Lanza eventos de "Detener" cuando Claude termina una ronda de respuesta | +| Sesión cerrada | Desactivada | Se cierra en `SessionEnd` cuando el proceso CLI termina | +| Errores de sesión | En | Se cierra cuando una sesión termina con un error | +| Subagente generado | Desactivado | Se dispara cuando se crea un subagente de fondo | + +Además, cualquier evento de gancho de `Notificación` de Claude Code desencadena una notificación del navegador independientemente de los interruptores por evento (siempre que el interruptor principal esté habilitado). + +### Arquitectura de notificaciones + +- **Pipeline VAPID:** Utiliza `web-push` en el servidor para la entrega segura de mensajes. Las claves VAPID se generan automáticamente y se almacenan en `data/vapid-keys.json`. +- **Trabajador de servicio:** Un trabajador dedicado (`client/public/sw.js`) maneja los eventos de `push` entrantes y muestra notificaciones con `silent: false` para garantizar la reproducción de audio en macOS. +- **Suscriptiones:** Los puntos finales específicos del navegador se almacenan en la tabla `push_subscriptions` en SQLite. +- **Persistencia:** Las notificaciones llegan incluso si el navegador está cerrado, ya que el Servidor de Servicios opera en segundo plano. +- **Notificación de prueba:** el botón en Ajustes le permite verificar el pipeline VAPID y la reproducción de audio. + +### Soporte PWA y sin conexión + +El proyecto envía tres aplicaciones web progresivas independientes: una para cada **pantalla de control**, **página de inicio** y **wiki**. Cada una tiene su propio `manifest.json` y Servidor de Servicios, por lo que el navegador las trata como aplicaciones instalables separadas. + +| Superficie | Manifestación | Trabajador de servicio | Estrategia de caché | +| --- | --- | --- | --- | +| Panel de control (`client/`) | `client/public/manifest.json` | `client/public/sw.js` | Los paquetes con contenido hash de Vite bajo `/assets/*` se sirven primero en la caché (las URL son inmutables por compilación). Todo lo demás, como las navegaciones, el propio SW, `manifest.json`, los iconos y la raíz `/`, es primero la red con fallback de caché, por lo que una reconstrucción siempre muestra la interfaz de usuario más reciente sin una actualización completa. Las solicitudes API (`/api/*`), WebSocket (`/ws`) y Vite HMR nunca se almacenan en caché. Los manejadores de notificaciones push se conservan junto con la lógica de caché. El middleware estático de Express (`server/index.js`) refuerza esto enviando `Cache-Control: public, max-age=31536000, immutable` para `/assets/*` y `Cache-Control: no-cache, must-revalidate` para `index.html`, `sw.js` y `manifest.json`. `client/src/main.tsx` escucha por `controllerchange`: cuando un nuevo SW se activa en una página ya controlada, se carga de nuevo exactamente una vez (las primeras instalaciones no lo hacen). | +| Página de inicio (raíz) | `manifest.json` | `sw.js` | Precarga la cáscara HTML, el icono de favoritos y la imagen OG. Las capturas de pantalla en formato PNG se almacenan en caché por inercia en la primera vista (caché primero) para evitar una precarga inicial pesada. La navegación es primero por red con fallback sin conexión. | +| Wiki (`wiki/`) | `wiki/manifest.json` | `wiki/sw.js` | Precarga `index.html`, `style.css`, `script.js`, manifest y favicon. Totalmente compatible con offline después de una visita. HTML primero en la red, caché primero para CSS/JS. | + +**Ciclo de vida del caché:** Los tres SW llaman a `skipWaiting()` al instalarse y eliminan los cachés obsoletos al activarse (claveados por cadenas de versión como `dashboard-v2`, `landing-v1`, `wiki-v1`). Desactivar la constante de versión fuerza una actualización limpia. + +**Soporte para iOS:** Los tres archivos HTML incluyen `` y `` para el modo de pantalla de inicio independiente en Safari. + +**Iconos:** Manifests hace referencia a `favicon.svg` con `sizes="any"` y `type="image/svg+xml"` — soportado en Chrome 107+, Firefox 110+, Edge 107+. Las iconos de Apple Touch también utilizan el favicon SVG. + +--- + +## Notificador de actualización + +El panel de control observa su propia verificación de git y muestra una modalidad cada vez que la rama predeterminada canónica tiene commits por delante de HEAD. **Conocedor de ramas y bifurcaciones:** si tiene una remota `upstream` (la convención estándar para bifurcaciones), se prefiere sobre `origin`; el `master`, `main` o `HEAD` de la remota elegida es la referencia de comparación. El `manual_command` se adapta a su situación: `git pull --ff-only` solo cuando su rama realmente rastrea la referencia canónica, de lo contrario una `git fetch` (y una fusión de avance rápido en el caso de la bifurcación) para que el comando nunca mienta. Los usuarios obtienen el comando exacto para ejecutar en un terminal: el servidor **nunca** se carga o reinicia, lo que mantiene el mecanismo portátil a través de las sesiones de desarrollo, la supervisión de pm2/systemd/launchd/Docker y las implementaciones remotas. + +

+Modal de actualización del panel de control con el comando copiar al portapapeles +

+ +### Cómo funciona + +```mermaid +flowchart LR + S["Server startup"] --> SCHED["Update scheduler
poll every 5 min"] + SCHED --> PICK["Pick canonical remote
upstream then origin"] + PICK --> FETCH["git fetch remote prune
execFile 120s timeout"] + FETCH --> CMP["rev-list HEAD vs
remote master main HEAD"] + CMP --> FP["Fingerprint changed?"] + FP -->|yes| WS["broadcast
update_status"] + FP -->|no| IDLE["skip broadcast"] + WS --> CLIENT["UpdateNotifier
+ Sidebar badge"] + + CHECK["POST updates check"] --> FETCH + STATUS["GET updates status"] -.-> CMP + + style WS fill:#6366f1,stroke:#818cf8,color:#fff + style CLIENT fill:#10b981,stroke:#34d399,color:#fff +``` + +Un solo cheque es barato (`git fetch --prune` contra el remoto canónico — `upstream` si está configurado, de lo contrario `origin`), envuelto con `execFile` (sin shell) y un tiempo de espera de 120 segundos. Los fallos — red sin conexión, instalación no git, no hay remotos configurados, referencia upstream no resoluble — todos devuelven **carga útiles suaves** (por ejemplo, `fetch_error: "..."`) en lugar de lanzar, por lo que un remoto inestable nunca bloquea el panel de control. + +### Superficies de interfaz de usuario + +| Superficie | Comportamiento | +| --- | --- | +| **Modal** (`client/src/components/UpdateNotifier.tsx`) | Aparece cuando `update_available === true` y el usuario aún no ha descartado este `remote_sha` específico. Muestra los commits-behind, la referencia rastreada, una `situacion_note` opcional (cuando está en un ramaje / bifurcación de la función, la nota explica por qué el comando difiere), el comando que se puede copiar y pegar y tres botones: **Comando de copia** (principal), **Comprueba ahora**, **Descargar**. ESC y los clics en el fondo desactivan. Se activa por `remote_sha` en `localStorage`, por lo que un commit más reciente en el origen reabre el modal automáticamente. | +| **Botón de barra lateral** (`client/src/components/Sidebar.tsx`) | Botón "Verificar actualizaciones" siempre visible en el pie de página. Bordura esmeralda + punto de distintivo verde cuando está detrás, ámbar cuando el último control ha fallado en la obtención de datos. Hacer clic en él elimina cualquier despido previo y luego dispara `POST /api/updates/check`. | +| **Terminal del servidor** | Cuando el programador cambia de "actualizado" a "desactualizado", imprime un bloque enmarcado en stdout con el comando para que los usuarios que ejecutan sin cabeza todavía lo vean. | + +### Superficie de la API + +| Punto final | Propósito | +| --- | --- | +| `GET /api/updates/status` | Comprobación de lectura única: ejecuta `git fetch` contra el remoto canónico, compara HEAD con su rama predeterminada, devuelve el payload. | +| `POST /api/updates/check` | La misma comprobación, pero también transmite `update_status` a través de WebSocket para que todos los clientes conectados se actualicen al mismo tiempo. | + +Ambos extremos devuelven la misma forma de carga útil: + +```json +{ + "git_repo": true, + "update_available": true, + "repo_root": "/Users/you/Claude-Code-Agent-Monitor", + "remote_ref": "upstream/master", + "canonical_remote": "upstream", + "current_branch": "master", + "tracking_upstream": "origin/master", + "tracks_canonical": false, + "situation": "fork_or_diverged_tracking", + "local_sha": "abc1234...", + "remote_sha": "def5678...", + "commits_behind": 3, + "manual_command": "cd \"/...\" && git fetch upstream && git merge --ff-only upstream/master && npm run setup", + "situation_note": "You're on 'master' tracking 'origin/master'. This command fast-forwards your branch from upstream/master (the canonical default).", + "message": "3 commit(s) on upstream/master not in your checkout." +} +``` + +`situación` es una de `tracking_canonical` (clon típico en la rama predeterminada, `git pull --ff-only` funciona), `fork_or_diverged_tracking` (el nombre de la rama local coincide con el canónico, pero rastrea una ubicación remota diferente, `git fetch && git merge --ff-only `), `feature_branch` (fuera de la rama predeterminada, solo se busca, la integración queda a cargo del usuario) o `detached_head`. + +### Lo que está intencionalmente **No** aquí + +No hay `POST /api/updates/apply` y no hay asistente de reinicio automático, por diseño. Actualizarse automáticamente un proceso desde dentro de sí mismo es poco fiable sin un supervisor externo: `npm run dev` (concurrentemente), `npm start`, `pm2`, `systemd`, `launchd` y Docker requieren diferentes lógica de reinicio, y los fallos de `git pull` / `npm install` en un servidor en peligro de muerte no tienen un camino de desinstalación limpio. La detección solo mantiene el comportamiento predecible en todos los supervisores, todos los sistemas operativos y todos los estados de la rama, mientras aún cierra la brecha de información de "¿cuándo necesito realizar una extracción?"; el usuario es el dueño de la actualización real en su propia shell. + +### Configuración + +| Env Var | Valor predeterminado | Notas | +| --- | --- | --- | +| `DASHBOARD_UPDATE_CHECK` | habilitado | Establecido en `0` / `false` / `off` para deshabilitar por completo el programador. | +| `DASHBOARD_UPDATE_CHECK_INTERVAL_MS` | `300000` (5 min) | Intervalo entre las comprobaciones automáticas. El piso es de 60 000 ms, los valores inferiores están atornillados. | + +--- + +## Tabby — Compañero de gato flotante + +**Tabby** es un lindo compañero de gato flotante atado en la esquina inferior derecha de cada página en el panel de control. Siempre presente, convierte el flujo de la sesión en vivo en una mascota reactiva de un vistazo con la que también puedes hablar. + +

+Tabby, la mascota del panel de control reactivo, mostrada en varios estados de ánimo y con una burbuja de diálogo +

+ +### Mascota reactiva + +Tabby es un gato SVG que rastrea el cursor con **ocho estados de ánimo** derivados del flujo de la sesión en vivo, cada uno con su propia animación: + +| Estado de ánimo | Cuando | Animación | +| --- | --- | --- | +| `idle` | Nada notable sucediendo | Golpeo de cola descansando | +| `observando` | Las sesiones están activas | La oreja se erige, los ojos siguen el cursor | +| `feliz` | Una sesión o ejecución terminada de forma limpia | Movimiento de cabeza + brillo | +| `preocupado` | Algo no parece bien | Tremor sutil | +| `atascado` | Una sesión parece estar bloqueada | Alerta "!" | +| `pensando` | Un agente está en medio del trabajo | Movimiento lento de la cabeza | +| `dormiendo` | Tranquilo por un rato | `zzz` | +| `desconectado` | WebSocket está caído | Tranquilo, mantén la postura | + +### Burbujas de diálogo + +Tabby auto-superpone breves comentarios sobre eventos notables (sesión iniciada/terminada, errores, ejecución completada). Las burbujas están **controlando el flujo** y **coalesenciadas**, por lo que un parpadeo de eventos nunca llena la pantalla de spam, utilizan `aria-live` para lectores de pantalla y se pueden **silenciar** desde el panel. + +### Panel + +Abra el panel haciendo clic en el gato o presionando **⌘B / Ctrl+B** (Esc cierra). Muestra: + +- Una **línea de estado en vivo**: `N en vivo · M con errores · estado de conexión`. +- **Acciones rápidas** - salta a Ejecutar Claude, Actividad, Sesiones o sesiones con errores; silenciar burbujas; eliminar alertas. +- Una casilla de **Preguntar** (ver abajo). + +### Caja de preguntas → Ejecutar la transferencia de manos de Claude + +La casilla **Pregunta** responde a preguntas de estado simples localmente a partir de datos almacenados en caché, por ejemplo "qué está ejecutando", "algunos errores" o "estado". Cualquier otra pregunta se pasa a la página existente de **Ejecutar Claude** (hace un enlace profundo a `/run?prompt=…`) para iniciar una sesión real de Código Claude. Tabby nunca llama a un LLM en sí mismo; simplemente reutiliza la página de Ejecutar Claude para cualquier cosa más allá de una búsqueda rápida de estado. + +### Accesibilidad y degradación segura + +Tabby es operable con el teclado, utiliza `aria-live` para sus burbujas y respeta `prefers-reduced-motion`. Si el WebSocket está inactivo, se degrada de forma segura a un estado tranquilo de `desconectado` en lugar de producir un error. Puedes activar o desactivar Tabby en **Configuración** (localizado en inglés, chino, vietnamita y coreano), y la implementación reside en `client/src/components/Tabby/`. + +--- + +## Modal de estado de conexión + +Haga clic en la píldora **En vivo** / **Desconectado** en el pie de página de la barra lateral para abrir un pequeño panel de detalles sobre el transporte WebSocket del panel de control. Muestra el extremo de destino `ws://` activo, cuánto tiempo ha estado activo el socket actual, los eventos totales recibidos, los tipos de eventos más comunes como un gráfico de barras horizontal, una línea de chispa de rendimiento de 60 segundos y los últimos 8 eventos como una lista de actividad reciente. Las estadísticas acumulativas (totales, desglose por tipo, lista reciente) persisten a través de las recargas a través de `localStorage` bajo `sidebar-connection-stats`; la línea de chispa en movimiento y el temporizador "conectado desde" son intencionalmente efímeros. Un botón **Restablecer** en el pie de página borra todo a demanda. + +

+Modal de detalles de la conexión con línea de flechas de rendimiento, tipos de eventos principales y actividad reciente +

+ +--- + +## Extensión de VS Code + +El **Monitor de Agentes del Código Claude** está disponible como una extensión de VS Code de primera clase, lo que le permite monitorear sus agentes de IA sin salir de su editor. + +

+Captura de pantalla de la extensión de VS Code +

+ +### 🚀 Características clave +- **Barra lateral en vivo**: Vista dedicada de la barra de actividad que muestra la salud real del agente en tiempo real (trabajando, esperando, completado, etc.). +- **Análisis de uso**: Realice un seguimiento del total de tokens, los costos en USD en vivo y el número de eventos directamente en la barra lateral. +- **Integración de la barra de estado**: Monitor de pulsos de visión rápida en la barra inferior que muestra las sesiones y agentes activos. +- **Navegación profunda**: Acceso con un solo clic a vistas específicas del panel de control (Kanban, Análisis, Configuración) o sesiones recientes. +- **Tabla integrada**: Abre el panel de control de monitoreo completo como una pestaña nativa de VS Code webview. + +### 📦 Instalación y configuración +1. Abre el directorio [vscode-extension](./vscode-extension). +2. Instale la extensión del Marketplace o empaquetela usted mismo usando `vsce package`. +3. Asegúrese de que su servidor de panel local esté funcionando (`npm run dev`). +4. Haga clic en el icono **Radar** en la barra de actividad de VS Code para comenzar. + +Para la configuración detallada del desarrollador, consulte los directorios [.vscode](./.vscode) y [vscode-extension](./vscode-extension). + +> [¡CONSEJO!] +> Extensión en el mercado de VS Code: [Claude Code Agent Monitor](https://marketplace.visualstudio.com/items?itemName=hoangsonw.claude-code-agent-monitor) + +--- + +## Aplicación de escritorio (macOS y Windows) + +El panel de control también se envía como una **aplicación de escritorio nativa opcional** que instales una vez y olvidas - un `.app` de macOS (distribuido como un `.dmg`) y un `.exe` de Windows (un instalador NSIS más una construcción portátil sin instalación). Vive en el espacio de trabajo `desktop/`, un hermano de `client/`, `server/`, `mcp/` y `vscode-extension/`, y está construido con **Electron 35**. + +

+Claude Code Monitor ejecutándose como una aplicación de escritorio nativa +
+🍎🪟 Aplicación para escritorio — shell nativo con una barra de menú / icono de área de notificaciones ( bandeja), Abre al iniciar sesión y un bloqueo de instancia única. El mismo panel de control, en una ventana real del sistema operativo (macOS mostrado). +

+ +

+Claude Code Monitor ejecutándose como una aplicación de escritorio nativa de Windows, mostrando el Feed de Actividad con la barra de menú de la ventana de Windows y el panel Tabby +
+🪟 El mismo panel de control que una aplicación nativa de Windows: icono de la zona de notificaciones ( bandeja), menú de ventana nativo y Abrir al iniciar sesión. +

+ +Todo lo que ves en el navegador en `localhost:4820` vive dentro de esta ventana, con el ciclo de vida nativo del sistema operativo encima: un icono de bandeja, un menú de aplicaciones nativo, integración de inicio automático y un solo botón de salida que apaga el servidor de forma limpia. + +### Cómo funciona + +A diferencia de ejecutar el panel de control desde un terminal, la aplicación de escritorio no necesita `npm start`, ni un shell abierto, ni una segunda copia del servidor. El **proceso principal** de Electron hospeda el servidor Express **en el proceso**: `require()` `server/index.js` directamente en el mismo tiempo de ejecución de Node, con **sin proceso hijo ni IPC**, y señala una `BrowserWindow` de Chromium al cliente React compilado. + +```mermaid +flowchart LR + subgraph electron["Claude Code Monitor.app — one Electron process"] + main["Electron Main Process
Node 22 / Electron 35"] + host["server-host.ts
port discovery · adoption · ABI patch"] + express["server/index.js
Express API · SQLite · WebSocket"] + win["BrowserWindow
built React client (client/dist)"] + tray["tray.ts + menu.ts
menu-bar icon · native app menu"] + login["login-item.ts
auto-start via SMAppService"] + main -->|"startEmbeddedServer()"| host + host -->|"require() in-process — no child process, no IPC"| express + main --> tray + main --> login + express -->|"http + ws on 127.0.0.1:<port>"| win + end + + hooks["Claude Code hooks
(separate node processes)"] -->|"POST /api/hooks/event"| express + sqlite[("data/dashboard.db
SQLite — closed cleanly on quit")] <--> express + + style main fill:#47848F,stroke:#2f5a62,color:#fff + style express fill:#339933,stroke:#5cb85c,color:#fff + style win fill:#61DAFB,stroke:#3aa9c9,color:#000 + style host fill:#1f6feb,stroke:#1158c7,color:#fff +``` + +Al iniciar la aplicación: + +1. Elige un puerto gratuito, prefiriendo **4820**, retrocediendo a **4821-4829**, y luego un puerto alto aleatorio si todos esos están ocupados. +2. Si un servidor de panel de control saludable ya responde a `/api/health` en `4820` (por ejemplo, has ejecutado `npm start` en un terminal), **adoptará ese servidor** en lugar de vincularlo de forma doble: sin colisión de puertos, sin competencia de SQLite. Un servidor adoptado sigue funcionando después de que cierres la aplicación. +3. De lo contrario, inicia el servidor incorporado y, en el **primer arranque del servidor propiedad**, instala automáticamente los ganchos del código Claude y inicia los servicios de fondo (programador de actualizaciones, `cc-watcher`, reconciliación de ejecución huérfana). Un usuario que solo tenga un DMG, por lo tanto, recibe eventos con **cero configuración manual**: sin realizar una compra, sin `npm run install-hooks`. +4. **(macOS)** Recupera tu **PATH de la cáscara de inicio de sesión** para que la función **Ejecutar Claude** pueda encontrar y crear la CLI `claude`: una aplicación lanzada desde Finder/Dock que de otra manera heredaría solo el PATH mínimo de launchd y perdería las CLIs en `~/.local/bin`, `/opt/homebrew/bin`, los contenedores del gestor de versiones, etc. (En Windows, el proceso ya hereda el PATH del usuario). +5. Abre la ventana del panel de control, a menos que la aplicación se haya iniciado al iniciar sesión (en macOS a través de los elementos de inicio de sesión; en Windows a través de la entrada etiquetada `HKCU\…\Run`), en cuyo caso solo se mantiene como bandeja. +6. Al salir, apaga el servidor incorporado con gracia y **cierra SQLite de forma limpia** (punto de control WAL). + +### Características + +- **Ícono de bandeja** — superficie de estado siempre activa (barra de menú de macOS / área de notificaciones de Windows). Haga clic con el botón izquierdo para alternar la ventana del panel de control; haga clic con el botón derecho para abrir un menú contextual con **Abrir panel de control**, **Abrir en el navegador**, **Reiniciar servidor**, **Mostrar registros**, **Abrir al iniciar sesión** (alternar) y **Salir**. macOS utiliza un glifo de plantilla con tono; Windows utiliza el icono `icon.ico` coloreado (una plantilla negra desaparecería en la barra de tareas oscura). +- **Icono de ventana y barra de tareas**: el `BrowserWindow` está conectado al logotipo de la aplicación de color (`icon.ico` en Windows, `icon.png` en otro lugar), por lo que la barra de título / barra de tareas muestra el verdadero icono de Claude Code Monitor: incluso una ejecución de `npm run desktop:dev` sin descomprimir ya no muestra el icono genérico de Electron. +- **Menú de aplicación nativo** — menú estándar de "Acerca de" / "Archivo" / "Editar" / "Ver" / "Ventana" / "Ayuda" con atajos de `⌘` / `Ctrl`. El elemento **Archivo → Abrir Panel de control** (`⌘1`) es **solo para macOS**: macOS mantiene una barra de menú global después de que la ventana se oculte, por lo que puede volver a abrir la ventana: en Windows/Linux el menú está adjunto a la ventana y no se puede ejecutar mientras está oculto, por lo que vuelva a abrir desde el menú **Abrir Panel de control** de la bandeja (que eleva la ventana de forma fiable incluso cuando está minimizada o detrás de otras ventanas). +- **Inicio automático al iniciar sesión** — alterna **Abrir al iniciar sesión** desde la bandeja o el menú de la aplicación. En macOS se registra a través de la moderna API `SMAppService`, por lo que la entrada aparece en **Configuración del sistema → General → Elementos de inicio de sesión**; en Windows escribe una entrada `HKCU\Software\Microsoft\Windows\CurrentVersion\Run` por usuario, visible en **Gestor de tareas → Inicio**. +- **El cierre de la ventana oculta, el servidor sigue funcionando**: cerrar la ventana solo la oculta; el servidor y la bandeja permanecen abiertos. Haga clic en la bandeja para volver a mostrar la ventana. +- **Bloqueo de una sola instancia**: el doble lanzamiento simplemente centra la ventana existente; no hay segundo servidor, no hay colisión de puertos. (Se aplica en todas las plataformas). +- **Los datos sobreviven a las reinstalaciones y actualizaciones**: la base de datos SQLite y las claves VAPID se encuentran en el directorio de datos de la aplicación por usuario **fuera del paquete de la aplicación / directorio de instalación**: `~/Biblioteca/Soporte de Aplicaciones/Claude Code Monitor/data/` en macOS, `%APPDATA%\Claude Code Monitor\data\` en Windows. Un paquete empaquetado es de solo lectura, por lo que escribir la base de datos dentro de él rompería la Importación de Historial y la persistencia de eventos; mantenerla en datos de la aplicación soluciona eso y significa que su historial importado no se ve afectado cuando reemplaza o actualiza la aplicación. (El desinstalador NSIS de Windows guarda estos datos por defecto). +- **`claude` CLI en PATH** — en macOS la aplicación recupera su `PATH` de inicio de sesión en el arranque, por lo que la función **Ejecutar Claude** funciona incluso si una aplicación lanzada desde Finder/Dock de otro modo solo heredaría el `PATH` mínimo de launchd. (En Windows el `PATH` de usuario heredado ya lo incluye). +- **Registros**: el proceso principal escribe en `~/Biblioteca/Registros/Claude Code Monitor/desktop.log` (macOS) o `%APPDATA%\Claude Code Monitor\logs\desktop.log` (Windows); accédalo desde el menú **Mostrar registros** del panel. + +### Entiéndelo + +**Opción A - descargar un instalador preconstruido (recomendado).** Desde **[Versiones → última](https://github.com/hoangsonww/Claude-Code-Agent-Monitor/releases/latest)** (público, sin inicio de sesión en GitHub). CI publica automáticamente una nueva versión `vX.Y.Z` cada vez que la versión en `package.json` se actualiza en `master`, por lo que este enlace siempre sirve para la construcción actual: + +| Plataforma | Activo | Notas | +| --- | --- | --- | +| macOS (Apple Silicon) | `ClaudeCodeMonitor--arm64.dmg` | arrastrar a `/Applications` | +| macOS (Intel) | `ClaudeCodeMonitor--x64.dmg` | arrastrar a `/Applications` | +| Windows (instalador) | `ClaudeCodeMonitor-Setup--x64.exe` | instalación por usuario, sin administrador | +| Windows (portátil) | `ClaudeCodeMonitor--x64-portable.exe` | ejecutar sin instalar | + +Las construcciones frescas por compromiso también existen como artefactos CI (se requiere inicio de sesión, retención de 14 días): `ClaudeCodeMonitor-dmg` del trabajo `🍎 macOS Desktop (DMG)` y `ClaudeCodeMonitor-win` del trabajo `🪟 Windows Desktop (EXE)`, útiles para probar `master` antes de la próxima etiqueta de lanzamiento. + +**Opción B: construíselo tú mismo.** Desde la raíz del repositorio: + +```bash +npm run setup # install root + client deps, build client, install hooks +npm run build # build the React client (client/dist) +npm run desktop:install # install Electron + electron-builder into desktop/ (preflights native deps; prints setup help on failure) +npm run desktop:dmg:arm64 # macOS: fast single-arch DMG → desktop/release/ClaudeCodeMonitor--arm64.dmg +npm run desktop:win # Windows: NSIS installer → desktop/release/ClaudeCodeMonitor-Setup--x64.exe +``` + +> [!NOTA] +> **Los DMG se construyen en macOS; los `.exe` de Windows se construyen en Windows** — paquetes electron-builder para el sistema operativo de host. El paquete de construcción `npm run desktop:dmg` de macOS construye la aplicación **dos veces** (una vez por arquitectura) y emite **ambos** DMG por arquitectura (`arm64` + `x64`) — la construcción de lanzamiento; no los fusiona en un binario universal. Para su propio Mac, utilice el `desktop:dmg:arm64` / `desktop:dmg:x64` de arquitectura única. En Windows, `better-sqlite3` se obtiene como un binario Electron preconstruido por `npm run desktop:install`, por lo que no se necesita ninguna cadena de herramientas Visual Studio C++ en el caso común. Si la construcción falla (sin binario preconstruido o cadena de herramientas C++ faltante), `desktop:install` imprime la solución exacta por sistema operativo más una alternativa sin cadena de herramientas y falla ruidosamente en lugar de dejar una instalación rota. + +### Instálalo + +**macOS:** + +1. Haga doble clic en el `.dmg` para montarlo. +2. Arrastra **Claude Code Monitor.app** a tu carpeta `/Applications`. +3. El DMG está **firmado ad hoc** por defecto, por lo que macOS Gatekeeper advierte en la primera vez que se inicia (*"Apple no pudo verificar..."*). Borra el atributo de cuarentena: + + ```bash + xattr -cr "/Applications/Claude Code Monitor.app" + ``` + +O abra **Configuración del sistema → Privacidad y seguridad** y haga clic en **Abrir de todos modos**. + +4. Inicie la aplicación. Aparece el icono de la bandeja y se abre la ventana del panel de control. + +**Ventanas:** + +1. Ejecute `ClaudeCodeMonitor-Setup--x64.exe`. Instala **por usuario** en `%LOCALAPPDATA%\Programas\Claude Code Monitor` (sin elevación de administrador) y le permite elegir el directorio de instalación; o ejecute `*-portable.exe` para iniciar sin instalar. +2. El instalador está **sin firmar** por defecto, por lo que Windows **SmartScreen** puede mostrar *"Windows protegido su PC"* en la primera vez que se inicie, haga clic en **Más información → Ejecutar de todos modos**. +3. Lanzar desde el menú Inicio / atajo del escritorio. Aparece el icono de la zona de notificaciones ( bandeja) y se abre la ventana del panel de control. + +

+Paso 1 del instalador NSIS: Elija las opciones de instalación, con selección por usuario (Solo para mí) versus selección para todos los usuarios +
+Instalador de Windows · Paso 1 — Elija las opciones de instalación (por usuario "Solo para mí" vs. todos los usuarios). +

+ +

+Paso 2 del instalador NSIS: Elija la ubicación de instalación, con la carpeta de destino %LOCALAPPDATA%\Programas por usuario +
+Instalador de Windows · Paso 2 — Elija la ubicación de instalación (por defecto es %LOCALAPPDATA%\Programas por usuario). +

+ +

+Paso 3 del instalador NSIS: completando la configuración, con la opción de terminar y ejecutar la aplicación +
+Instalador de Windows · Paso 3 — Completar la configuración (Finalizar y lanzar la aplicación). +

+ +### Comandos de construcción + +Todos los comandos se ejecutan desde la **raíz del repositorio**: + +| Comando | Lo que hace | +| --------------------------- | ---------------------------------------------------------------------------- | +| `npm run desktop:install` | Instalar Electron + electron-builder en `desktop/`; reconstruir `better-sqlite3` para la ABI de Electron; realizar pruebas preliminares de la construcción nativa de `better-sqlite3` e imprimir ayuda de configuración factible (incluyendo una alternativa sin cadena de herramientas) en caso de fallo | +| `npm run desktop:build` | Compila las fuentes TypeScript del escritorio en `desktop/out/` | +| `npm run desktop:dev` | Construye y lanza la aplicación Electron para iteraciones locales | +| `npm run desktop:test` | Ejecutar la prueba de humo (iniciar Electron, sondear `/api/health`, apagar) | +| `npm run desktop:dmg` | **macOS:** construye **ambos** DMG (arm64 + x64) — correctos para la versión, **más lentos** (paquetes para cada arquitectura) | +| `npm run desktop:dmg:arm64` | **macOS:** construye un DMG solo de Apple-Silicon — **rápido** (~1 min), recomendado para tu propio Mac | +| `npm run desktop:dmg:x64` | **macOS:** construye un DMG solo para Intel — **rápido** (~1 min) | +| `npm run desktop:dmg:universal` | **macOS:** construye un DMG **universal** fusionado (arm64 + x86_64) — opcional, **más lento**, no es lo que se envía con la versión | +| `npm run desktop:win` | **Windows:** construye el instalador NSIS `.exe` (x64) | +| `npm run desktop:win:portable` | **Windows:** construye el `.exe` portátil sin instalar (x64) | + +El DMG de macOS resultante es **~80 MB** (≈ 250 MB en el disco una vez instalado) y el instalador de Windows es comparable: el impuesto estándar del paquete Electron. + +### Firma y notariedad + +El DMG de macOS está **firmado ad hoc** por defecto, por lo que cualquiera puede crear un `.app` funcional sin una cuenta de desarrollador de Apple pagada. El script `package` establece `CSC_IDENTITY_AUTO_DISCOVERY=false`, por lo que un certificado de firma de código ya en la llave de acceso del contribuyente nunca se selecciona automáticamente. La **firma de ID de desarrollador real** es opcional a través de `CSC_LINK` (un `.p12` codificado en base64) y `CSC_KEY_PASSWORD`; la **notificación de Apple** es opcional a través de `APPLE_ID`, `APPLE_TEAM_ID` y `APPLE_APP_SPECIFIC_PASSWORD`. La construcción de **Windows** está **sin firma** por defecto (SmartScreen puede aparecer al iniciar la aplicación por primera vez; *Más información → Ejecutar de todos modos*); la firma de Authenticode solo se activa cuando se proporciona un certificado explícito a través de `CSC_LINK` + `CSC_KEY_PASSWORD`. CI recoge todo esto automáticamente cuando se proporciona, sin necesidad de cambios en el código. + +### Notas de implementación + +- **`better-sqlite3`** es el único módulo nativo en el árbol de dependencias, y un módulo nativo debe compilarse contra la ABI exacta del Nodo A en la que se ejecuta. El espacio de trabajo `desktop/` envía su **propia copia** de `better-sqlite3` reconstruida para la ABI de Electron y utiliza un redireccionamiento `require` local al proceso para apuntar a `server/db.js`; la copia de la raíz del repositorio se mantiene construida para el Nodo del sistema (por lo que `npm run test:server` sigue funcionando). +- **La construcción de un DMG reconstruye `better-sqlite3` para la arquitectura de destino**, lo que puede dejar la copia del escritorio construida para la otra arquitectura de CPU y romper `npm run desktop:dev` / `npm run desktop:test` con `ERR_DLOPEN_FAILED`. El paso de `prebuild` del escritorio ahora **auto-curará** el módulo nativo para la máquina local en la próxima construcción, por lo que los flujos de desarrollo y prueba de humo siguen funcionando después de una construcción de DMG específica de la arquitectura. El paso de `prebuild` también **falla rápidamente con ayuda de configuración** cuando el binario nativo de `better-sqlite3` falta por completo, convirtiendo un fallo de tiempo de ejecución en un error de tiempo de construcción que se puede copiar y pegar. +- El **único cambio fuera de `desktop/`** es una refactorización que preserva el comportamiento de `server/index.js`: su post-listen bootstrap (programador de actualización, `cc-watcher`, reconciliación de ejecución huérfana) se extrajo en un `startBackgroundServices()` exportado para que el servidor incorporado ejecute exactamente lo que ejecuta `node server/index.js`. El camino independiente de `node server/index.js` no ha cambiado funcionalmente; `client/`, `scripts/`, `mcp/` y `vscode-extension/` no han sido tocados. +- Dos trabajos de CI de escritorio filtrados por ruta construyen, prueban con humo y empaquetan la aplicación: **`🍎 macOS Desktop (DMG)`** en `macos-latest` (carga el artefacto `ClaudeCodeMonitor-dmg` — dos DMG de arquitectura única) y **`🪟 Windows Desktop (EXE)`** en `windows-latest` (carga el artefacto `ClaudeCodeMonitor-win` — instalador NSIS + portátil). En una actualización de versión a `master`, el trabajo de `release` adjunta **ambos** los DMG de macOS y los `.exe` de Windows a la publicación de la versión `vX.Y.Z` de GitHub. El icono de Windows (`desktop/assets/icon.ico`) se compromete al repositorio (regénéralo desde `icon.png` con `npm run build:win-icon`, PowerShell + .NET, sin herramientas adicionales). + +Para la guía completa del usuario (descargar, instalar, Gatekeeper / SmartScreen, menú de bandeja, inicio automático), consulte [`DESKTOP.md`](./DESKTOP.md); para la referencia del contribuyente / arquitectura (modelo de proceso, ciclo de vida de arranque, descubrimiento de puertos, pipeline de construcción, con diagramas de Mermaid), consulte [`desktop/README.md`](./desktop/README.md). + +--- + +## Almacenamiento de datos + +- **Motor:** SQLite 3 a través de `better-sqlite3` (opcional) o `node:sqlite` incorporado de Node.js +- **Ubicación:** `data/dashboard.db` +- **Modo de diario:** WAL (lecturas concurrentes durante las escrituras) +- **Restablecer:** Elimina `data/dashboard.db` para borrar todos los datos + +### Diagrama de relaciones de entidades + +```mermaid +erDiagram + sessions ||--o{ agents : has + sessions ||--o{ events : has + sessions ||--o{ token_usage : tracks + agents ||--o{ events : generates + agents ||--o{ agents : spawns + + sessions { + TEXT id PK "UUID" + TEXT name "Human-readable label" + TEXT status "active|completed|error|abandoned" + TEXT cwd "Working directory" + TEXT model "Claude model ID" + TEXT started_at "ISO 8601" + TEXT ended_at "ISO 8601 or NULL" + TEXT metadata "JSON blob" + TEXT awaiting_input_since "ISO 8601 or NULL — set when Waiting" + TEXT awaiting_reason "notification|stop|session_start|interrupted or NULL" + } + + agents { + TEXT id PK "UUID or session_id-main" + TEXT session_id FK + TEXT name "Main Agent — {session name} or subagent description" + TEXT type "main|subagent" + TEXT status "working|waiting|completed|error" + TEXT current_tool "Active tool or NULL" + TEXT awaiting_input_since "ISO 8601 or NULL — supplementary wait timestamp" + TEXT awaiting_reason "notification|stop|session_start|interrupted or NULL" + } + + events { + INTEGER id PK "Auto-increment" + TEXT session_id FK + TEXT agent_id FK + TEXT event_type "PreToolUse|PostToolUse|Stop|etc" + TEXT tool_name "Tool that fired the event" + TEXT created_at "ISO 8601" + } + + token_usage { + TEXT session_id PK "Composite PK with model" + TEXT model PK "Model identifier" + INTEGER input_tokens + INTEGER output_tokens + INTEGER cache_read_tokens + INTEGER cache_write_tokens + } + + model_pricing { + TEXT model_pattern PK "SQL LIKE pattern" + TEXT display_name "Human-readable name" + REAL input_per_mtok "USD per M input tokens" + REAL output_per_mtok "USD per M output tokens" + REAL cache_read_per_mtok "USD per M cache reads" + REAL cache_write_per_mtok "USD per M cache writes" + } +``` + +--- + +## Mercado de complementos + +Extiende Claude Code con los complementos oficiales de Agent Monitor: análisis, herramientas de productividad, utilidades para desarrolladores, información basada en IA, conectividad del panel de control, barreras de control de costos, forense de sesiones, orquestación de flujos de trabajo, fiabilidad/SLOs y gobernanza de configuración. 10 complementos, 53 habilidades, 14 agentes, 30 comandos de guión, 3 herramientas de CLI, 3 configuraciones de ganchos, 1 servidor MCP. + +### Agregar el mercado + +```bash +claude plugin marketplace add hoangsonww/Claude-Code-Agent-Monitor +``` + +### Plugins disponibles + +| Plugin | Comando de instalación | Habilidades | +|--------|----------------|--------| +| **ccam-analytics** | `instalar plugin claudé ccam-analytics@hoangsonww-claude-code-agent-monitor` | `reporte de sesión`, `desglose de costos`, `tendencias de uso`, `puntuación de productividad` | +| **ccam-cost-guard** | `claude plugin install ccam-cost-guard@hoangsonww-claude-code-agent-monitor` | `budget-set`, `spend-forecast`, `cost-alert`, `model-savings`, `daily-budget-check` | +| **ccam-productividad** | `instalar plugin claudec ccam-productivity@hoangsonww-claude-code-agent-monitor` | `daily-standup`, `weekly-report`, `sprint-summary`, `workflow-optimizer` | +| **ccam-devtools** | `claude plugin install ccam-devtools@hoangsonww-claude-code-agent-monitor` | `session-debug`, `hook-diagnostics`, `data-export`, `health-check` | +| **ccam-insights** | `instalar plugin claudec ccam-insights@hoangsonww-claude-code-agent-monitor` | `detectar patrones`, `alerta de anomalías`, `sugerencias de optimización`, `comparar sesiones` | +| **ccam-sessions** | `claude plugin install ccam-sessions@hoangsonww-claude-code-agent-monitor` | `session-search`, `session-timeline`, `transcript-replay`, `cwd-rollup`, `session-cleanup` | +| **ccam-workflows** | `claude plugin install ccam-workflows@hoangsonww-claude-code-agent-monitor` | `dag-map`, `delegation-audit`, `concurrency-report`, `error-propagation`, `fleet-runs` | +| **calidad ccam** | `instalar plugin claudecam-quality@hoangsonww-claude-code-agent-monitor` | `escaneo de errores`, `reporte de errores de API`, `auditoría de fallos de gancho`, `verificación slo`, `alerta de regresión` | +| **ccam-config** | `claude plugin install ccam-config@hoangsonww-claude-code-agent-monitor` | `config-audit`, `memory-review`, `skill-inventory`, `mcp-audit`, `hook-inventory` | +| **ccam-dashboard** | `claude plugin install ccam-dashboard@hoangsonww-claude-code-agent-monitor` | `dashboard-status`, `quick-stats` + servidor MCP | + +### Herramientas CLI incluidas + +- `ccam-stats` — Panel de control terminal (sesiones, costos, tokens con bases de referencia de compactación) +- `ccam-doctor` — Diagnóstico del sistema (API, base de datos, ganchos, frescura de los datos) +- `ccam-export` — Exportación de datos (JSON, CSV) para sesiones, eventos, análisis, costos + +### Ejemplo de uso + +```bash +# In Claude Code, after installing a plugin: +/ccam-analytics:session-report latest +/ccam-analytics:cost-breakdown this week +/ccam-productivity:daily-standup today +/ccam-insights:pattern-detect tools +/ccam-dashboard:quick-stats +``` + +> Una prueba del servidor (`server/__tests__/plugins-marketplace.test.js`) valida la bijectividad de la carpeta marketplace ↔ `plugins/` y el `plugin.json`, agentes, habilidades y comandos de cada plugin. + +📖 Documentación completa: [docs/plugins.md](docs/PLUGINS.md) + +--- + +## Línea de estado + +Una utilidad independiente de línea de estado CLI para Claude Code que muestra el nombre del modelo, el usuario, el directorio de trabajo, la rama de git, la barra de uso de la ventana de contexto, el número de tokens por dirección y el costo de la sesión, todo ello codificado por colores con secuencias de escape ANSI. + +``` +nguyens6@host ~/agent-dashboard/client | Sonnet 4.6 | main | ████████░░ 79% | 3↑ 2↓ 156586c | $0.4231 +``` + +| Segmento | Color | Ejemplo | +| ----------- | -------------------- | -------------------------------------------------------------- | +| Modelo | Cian | `Soneto 4.6` | +| Usuario | Verde | `nguyens6` | +| CWD | Amarillo | `~/agent-dashboard` | +| Rama de Git | Magenta | `main` | +| Barra de contexto | Verde / Amarillo / Rojo | `████████░░ 79%` | +| Tokens | Verde / Cian / Oscuro | `3↑ 2↓ 156586c` (verde `↑` entrando, cian `↓` saliendo, caché oscuro `c`) | +| Costo (USD) | Verde / Amarillo / Rojo | `0,4231 $` (total de la sesión - mostrado en la API y planes de suscripción)| + +Límites de color de costo: verde por debajo de 5 $, amarillo de 5 a 20 $, rojo de 20 $ en adelante. + +Consulte [`statusline/README.md`](statusline/README.md) para obtener instrucciones de instalación. + +

+Demostración de Statusline +

+ +--- + +## Arquitectura del servidor + +```mermaid +graph TD + INDEX["server/index.js
Express app + HTTP server"] + DB["server/db.js
SQLite + prepared statements"] + WS["server/websocket.js
WS server + broadcast"] + HOOKS["routes/hooks.js
Hook event processing"] + SESSIONS["routes/sessions.js"] + AGENTS["routes/agents.js"] + EVENTS["routes/events.js"] + STATS["routes/stats.js"] + ANALYTICS["routes/analytics.js"] + PRICING["routes/pricing.js
Cost calculation"] + SETTINGS["routes/settings.js
System management"] + WORKFLOWS["routes/workflows.js
Workflow visualizations"] + + INDEX --> DB & WS + INDEX --> HOOKS & SESSIONS & AGENTS & EVENTS & STATS & ANALYTICS & PRICING & SETTINGS & WORKFLOWS + HOOKS --> DB & WS + SESSIONS --> DB & WS + AGENTS --> DB & WS + EVENTS --> DB + STATS --> DB + ANALYTICS --> DB + PRICING --> DB + SETTINGS --> DB + WORKFLOWS --> DB + + style INDEX fill:#6366f1,stroke:#818cf8,color:#fff + style DB fill:#003B57,stroke:#005f8a,color:#fff + style WS fill:#10b981,stroke:#34d399,color:#fff +``` + +--- + +## Enrutamiento del cliente + +```mermaid +graph LR + ROOT["/ (index)"] --> DASH["Dashboard
stats + agents + events"] + K["/kanban"] --> KANBAN["KanbanBoard
agents/sessions toggle"] + S["/sessions"] --> SESS["Sessions
server-paginated table"] + D["/sessions/:id"] --> DETAIL["SessionDetail
agents + timeline + cost"] + A["/activity"] --> ACT["ActivityFeed
streaming event log"] + AN["/analytics"] --> ANALYTICS["Analytics
tokens + heatmap + trends"] + WF["/workflows"] --> WORKFLOWS["Workflows
D3 visualizations + drill-in"] + CC["/cc-config"] --> CCCONFIG["CcConfig
12-tab Claude Code config inspector + editor"] + RUN["/run"] --> RUNPAGE["Run
spawn / resume / stream Claude subprocess"] + ST["/settings"] --> SETTINGS["Settings
pricing + notifications + hooks + export"] + NF["/*"] --> NOTFOUND["NotFound
404 catch-all"] + + ALL["All routes"] --> LAYOUT["Layout wrapper
(Sidebar + Outlet)"] + + style ALL fill:#6366f1,stroke:#818cf8,color:#fff + style LAYOUT fill:#1a1a28,stroke:#2a2a3d,color:#e4e4ed +``` + +--- + +## Flujo del gestor de ganchos + +```mermaid +flowchart TD + START["Claude Code fires hook"] --> STDIN["Read stdin to EOF"] + STDIN --> PARSE{"Parse JSON?"} + PARSE -->|Success| POST["POST to 127.0.0.1:4820
/api/hooks/event"] + PARSE -->|Failure| WRAP["Wrap raw input as JSON"] + WRAP --> POST + POST --> RESP{"Response?"} + RESP -->|200 OK| EXIT0["exit(0)"] + RESP -->|Error| EXIT0 + RESP -->|Timeout 3s| DESTROY["Destroy request"] --> EXIT0 + SAFETY["Safety net: setTimeout 5s"] --> EXIT0 + + style EXIT0 fill:#10b981,stroke:#34d399,color:#fff + style START fill:#6366f1,stroke:#818cf8,color:#fff +``` + +--- + +## Modos de despliegue + +Apoyamos tanto los modos de despliegue de desarrollo como de producción con diferentes arquitecturas de procesos: + +```mermaid +graph LR + subgraph dev["Development — 2 processes"] + D_CMD["npm run dev"] --> D_SRV["Express :4820
node --watch"] + D_CMD --> D_VITE["Vite :5173
HMR"] + D_BROWSER["Browser"] --> D_VITE + D_VITE -->|"proxy /api + /ws"| D_SRV + end + + subgraph prod["Production — 1 process"] + P_BUILD["npm run build"] --> P_DIST["client/dist/"] + P_START["npm start"] --> P_SRV["Express :4820
serves static + API"] + P_BROWSER["Browser"] --> P_SRV + end + + style D_VITE fill:#646CFF,stroke:#818cf8,color:#fff + style D_SRV fill:#339933,stroke:#5cb85c,color:#fff + style P_SRV fill:#339933,stroke:#5cb85c,color:#fff + style P_DIST fill:#646CFF,stroke:#818cf8,color:#fff +``` + +Sidecar MCP local opcional (soporta transportes stdio, HTTP+SSE y REPL): + +```mermaid +graph LR + subgraph "MCP Transport Options" + M_STDIO["MCP Server (stdio)
npm run mcp:start"] + M_HTTP["MCP Server (HTTP)
npm run mcp:start:http
:8819"] + M_REPL["MCP Server (REPL)
npm run mcp:start:repl"] + end + + H["MCP Host"] -->|"stdin/stdout"| M_STDIO + RC["Remote Client"] -->|"POST /mcp · GET /sse"| M_HTTP + OP["Operator"] -->|"interactive CLI"| M_REPL + + M_STDIO --> D["Dashboard Server
:4820"] + M_HTTP --> D + M_REPL --> D + + style M_STDIO fill:#0f766e,stroke:#14b8a6,color:#fff + style M_HTTP fill:#0f766e,stroke:#14b8a6,color:#fff + style M_REPL fill:#0f766e,stroke:#14b8a6,color:#fff +``` + +Opcional **aplicación de escritorio (macOS y Windows)**: un solo proceso Electron que hospeda el servidor Express en el proceso (sin terminal, sin proceso hijo): + +```mermaid +flowchart LR + subgraph desktop["Desktop App (macOS & Windows) — 1 Electron process"] + E_MAIN["Electron Main Process
(Node 22 / Electron 35)"] + E_HOST["server-host.ts
require() server/index.js"] + E_SRV["Embedded Express :4820
API · SQLite · WebSocket"] + E_WIN["BrowserWindow
built React client"] + E_TRAY["Menu-bar (tray) icon
+ native app menu"] + E_MAIN --> E_HOST + E_HOST -->|"in-process require()"| E_SRV + E_MAIN --> E_TRAY + E_SRV -->|"http + ws on 127.0.0.1"| E_WIN + end + + E_HOOKS["Claude Code hooks"] -->|"POST /api/hooks/event"| E_SRV + + style E_MAIN fill:#47848F,stroke:#2f5a62,color:#fff + style E_SRV fill:#339933,stroke:#5cb85c,color:#fff + style E_WIN fill:#61DAFB,stroke:#3aa9c9,color:#000 +``` + +### Implementación en la nube + +La carpeta `deployments/` proporciona una infraestructura de grado empresarial sin dependencia de la nube para implementar el panel de control en producción. Soporta Helm, Kustomize y Terraform en AWS, GCP, Azure y OCI con estrategias de lanzamiento azul-verde, canario y progresivo. + +```mermaid +graph TB + subgraph "Deployment Methods" + HELM["⎈ Helm Chart
Parameterized installs"] + KUST["📦 Kustomize
Overlay-based patching"] + TF["🏗️ Terraform
Full cloud provisioning"] + end + + subgraph "Cloud Providers" + AWS["☁️ AWS
ECS Fargate + ALB"] + GCP["☁️ GCP
Cloud Run + GCLB"] + AZ["☁️ Azure
ACI + App Gateway"] + OCI["☁️ OCI
OKE + LBaaS"] + end + + subgraph "Release Strategies" + ROLL["Rolling Update"] + BG["Blue-Green"] + CAN["Canary + Analysis"] + end + + subgraph "Observability" + PROM["📊 Prometheus + Grafana"] + CX["📡 Coralogix
Logs · Metrics · Traces · SLOs"] + end + + HELM & KUST --> ROLL & BG & CAN + TF --> AWS & GCP & AZ & OCI + ROLL & BG & CAN --> PROM & CX + + style HELM fill:#0f1689,color:#fff + style KUST fill:#326ce5,color:#fff + style TF fill:#7b42bc,color:#fff + style AWS fill:#ff9900,color:#fff + style GCP fill:#4285f4,color:#fff + style AZ fill:#0078d4,color:#fff + style OCI fill:#f80000,color:#fff + style PROM fill:#e6522c,color:#fff + style CX fill:#1a1a2e,color:#fff +``` + +```bash +# Helm (recommended for Kubernetes) +helm install agent-monitor deployments/helm/agent-monitor \ + -f deployments/helm/agent-monitor/values-production.yaml \ + -n agent-monitor --create-namespace + +# Kustomize +kubectl apply -k deployments/kubernetes/overlays/production + +# Terraform (full infra + app) +cd deployments/terraform/providers/aws +terraform init && terraform apply -var-file=../../environments/production/terraform.tfvars + +# Script orchestrator +./deployments/scripts/deploy.sh --env production --method helm --strategy blue-green +``` + +La pila de despliegue incluye pipelines de CI/CD (GitHub Actions + GitLab CI), monitoreo integral (Prometheus, Grafana, Alertmanager con 13 reglas de alerta, observabilidad de pila completa de Coralogix con OpenTelemetry Collector para registros, métricas, rastros y seguimiento de SLO), scripts operativos (despliegue, deshacer, cambio de color azul-verde, copia de seguridad/restauración, desinstalación) y una postura de seguridad completa (Estándar de seguridad de pods restringido, TLS 1.3, políticas de red, escaneo de Trivy). + +> [!NOTA] +> 📘 **Guía completa de despliegue:** Consulte [DEPLOYMENT.md](DEPLOYMENT.md) para obtener instrucciones paso a paso, diagramas de arquitectura y flujos de trabajo operativos. + +--- + +## Estructura del proyecto + +``` +agent-dashboard/ +|-- CLAUDE.md # Claude Code project memory and working agreements +|-- AGENTS.md # Codex project instructions +|-- package.json # Root scripts (dashboard + MCP helpers) + server dependencies +|-- .claude/ +| +-- rules/ # Path-scoped Claude rules +| +-- skills/ # Claude reusable project skills +| +-- agents/ # Claude custom subagents +|-- .claude-plugin/ +| +-- marketplace.json # Plugin marketplace manifest (10 plugins) +|-- plugins/ +| |-- ccam-analytics/ # Analytics: session reports, cost breakdown, usage trends, productivity score +| | |-- .claude-plugin/plugin.json +| | |-- skills/ (4) # session-report, cost-breakdown, usage-trends, productivity-score +| | |-- agents/ # analytics-advisor (Sonnet model) +| | |-- hooks/hooks.json # Stop + SubagentStop event logging +| | +-- bin/ccam-stats # Terminal dashboard CLI +| |-- ccam-productivity/ # Productivity: standups, reports, sprints, workflow optimizer +| |-- ccam-devtools/ # DevTools: debug, diagnostics, export, health checks +| | +-- bin/ # ccam-doctor + ccam-export CLIs +| |-- ccam-insights/ # Insights: patterns, anomalies, optimization, comparison +| |-- ccam-cost-guard/ # Cost guardrails: budgets, spend forecast, cost alerts, model savings +| |-- ccam-sessions/ # Session forensics: search, timeline, transcript replay, cwd rollup, cleanup +| |-- ccam-workflows/ # Workflow orchestration: DAG map, delegation audit, concurrency, fleet runs +| |-- ccam-quality/ # Reliability & SLOs: error scan, API-error report, hook-failure audit, SLO check +| |-- ccam-config/ # Config & memory governance: config audit, memory review, skill/MCP/hook inventory +| +-- ccam-dashboard/ # Dashboard connector: status, quick stats, MCP integration +| +-- .mcp.json # MCP server configuration +|-- server/ +| |-- index.js # Express app, HTTP server, static serving +| |-- db.js # SQLite schema, migrations, prepared statements +| |-- websocket.js # WebSocket server with heartbeat +| +-- routes/ +| |-- hooks.js # Hook event processing (transactional) +| |-- sessions.js # Session CRUD +| |-- agents.js # Agent CRUD +| |-- events.js # Event listing +| |-- stats.js # Aggregate statistics +| |-- analytics.js # Token, tool, and trend analytics +| |-- workflows.js # Aggregate workflow data and per-session drill-in +| |-- pricing.js # Model pricing CRUD and cost calculation +| +-- settings.js # System info, data management, export, cleanup +| +-- lib/ +| +-- transcript-cache.js # Stat-based JSONL transcript cache with chunked sync byte-stream reader (4 MiB chunks, line-by-line UTF-8 decode) so files larger than V8's max string length (~512 MiB) parse without aborting Node with "FATAL ERROR: v8::ToLocalChecked Empty MaybeLocal". Extracts tokens, compactions, API errors, turn durations, thinking blocks, and usage extras (service_tier, speed, inference_geo) +| +-- compat-sqlite.js # node:sqlite compatibility wrapper (fallback for better-sqlite3) +|-- client/ +| |-- package.json # Client dependencies +| |-- index.html # HTML entry point +| |-- vite.config.ts # Vite + proxy config +| |-- tailwind.config.js # Custom dark theme +| |-- tsconfig.json # Strict TypeScript +| +-- src/ +| |-- main.tsx # React entry +| |-- App.tsx # Router + WebSocket provider +| |-- index.css # Tailwind + custom utilities +| |-- lib/ +| | |-- types.ts # Shared TypeScript interfaces +| | |-- api.ts # Typed fetch client +| | |-- format.ts # Date/time formatting utilities +| | +-- eventBus.ts # Pub/sub for WebSocket distribution +| |-- hooks/ +| | |-- useWebSocket.ts # Auto-reconnecting WebSocket hook +| | +-- useNotifications.ts # Browser notification triggers from WebSocket events +| |-- components/ +| | |-- Layout.tsx # Shell with sidebar + outlet +| | |-- Sidebar.tsx # Navigation + connection indicator +| | |-- AgentCard.tsx # Agent info card with status +| | |-- StatCard.tsx # Metric card +| | |-- StatusBadge.tsx # Color-coded status pills +| | |-- EmptyState.tsx # Placeholder for empty lists +| | +-- workflows/ # D3.js workflow visualization components +| | |-- OrchestrationDAG.tsx # Horizontal DAG of agent spawning patterns +| | |-- ToolExecutionFlow.tsx # d3-sankey diagram of tool-to-tool transitions +| | |-- AgentCollaborationNetwork.tsx # Force-directed agent pipeline graph +| | |-- SubagentEffectiveness.tsx # Scorecard grid with SVG success rings +| | |-- WorkflowPatterns.tsx # Auto-detected orchestration sequences +| | |-- ModelDelegationFlow.tsx # Model routing through agent hierarchies +| | |-- ErrorPropagationMap.tsx # Error clustering by hierarchy depth +| | |-- ConcurrencyTimeline.tsx # Swim-lane parallel agent execution +| | |-- SessionComplexityScatter.tsx # D3 bubble chart (duration vs agents vs tokens) +| | |-- CompactionImpact.tsx # Token compression events and recovery +| | |-- WorkflowStats.tsx # Aggregate workflow statistics +| | +-- SessionDrillIn.tsx # Per-session agent tree, tool timeline, events +| +-- pages/ +| |-- Dashboard.tsx # Overview page +| |-- KanbanBoard.tsx # Agents/Sessions toggle, status columns +| |-- Sessions.tsx # Server-paginated sessions table +| |-- SessionDetail.tsx # Single session deep dive +| |-- ActivityFeed.tsx # Real-time event stream +| |-- Analytics.tsx # Token usage, heatmap, trends +| |-- Workflows.tsx # D3.js workflow visualizations and session drill-in +| |-- Settings.tsx # Model pricing, notifications, hooks, export, cleanup +| +-- NotFound.tsx # 404 catch-all page +|-- scripts/ +| |-- hook-handler.js # Lightweight stdin-to-HTTP forwarder +| |-- install-hooks.js # Auto-configures ~/.claude/settings.json +| |-- import-history.js # Imports sessions from ~/.claude/ with enhanced JSONL extraction (API errors, turn durations, entrypoint, permission modes, thinking blocks, usage extras, tool errors, subagent JSONL files). Re-import is fully incremental: a per-event-type high-water mark (`MAX(created_at) GROUP BY event_type` per session) is computed up-front and only JSONL entries with `ts > cutoff[type]` are inserted, so long-running sessions whose transcripts grow across multiple days continue to receive Stop / PostToolUse / TurnDuration / ToolError events on every re-run. Also rolls `sessions.ended_at` forward when the JSONL advances past the stored value and refreshes message-count metadata on every pass +| +-- seed.js # Sample data generator +|-- mcp/ +| |-- package.json # MCP package scripts + dependencies +| |-- README.md # MCP setup, host config, tool catalog, safety model +| |-- src/ +| | |-- index.ts # MCP runtime entrypoint (transport router) +| | |-- server.ts # MCP server assembly +| | |-- clients/ # Dashboard API client with retry/backoff +| | |-- config/ # Environment/CLI config parsing +| | |-- core/ # Logger, tool registry, result helpers +| | |-- policy/ # Mutation/destructive guards +| | |-- tools/ # Domain-specific tool modules (6 domains) +| | |-- transports/ # HTTP+SSE server, REPL, tool collector +| | |-- ui/ # ANSI banner, colors, formatter, tables +| | +-- types/ # Shared MCP type definitions +| +-- build/ # Built MCP runtime output +|-- desktop/ +| |-- package.json # Electron + electron-builder dependencies and scripts +| |-- electron-builder.yml # DMG packaging config; signing/notarization hooks +| |-- tsconfig.json # Strict TypeScript (src/ -> out/) +| |-- README.md # Desktop app architecture reference (contributor docs) +| |-- assets/ # icon.svg + generated icon.icns + tray PNGs +| |-- src/ +| | |-- main.ts # Electron main process entry — lifecycle, wiring +| | |-- server-host.ts # In-process Express boot, port discovery, adoption, DB close +| | |-- window.ts # BrowserWindow + persisted window geometry +| | |-- tray.ts # Menu-bar (tray) icon + context menu +| | |-- menu.ts # Native application menu (File ▸ Open Dashboard is macOS-only) +| | |-- login-item.ts # macOS Login Items auto-start toggle (SMAppService) +| | |-- logger.ts # File logger -> ~/Library/Logs/Claude Code Monitor/desktop.log +| | |-- constants.ts # App name, ports, timeouts, window size +| | +-- preload.ts # Intentionally empty (zero renderer privilege) +| |-- scripts/ +| | |-- install.js # Preflights native deps for desktop:install; prints setup help + exits non-zero on failure +| | |-- preflight.js # Shared better-sqlite3 binary check + actionable per-OS setup help (incl. no-toolchain alternative) +| | |-- prebuild.js # Ensures root + client are built before tsc; fails fast with setup help if native binary missing +| | |-- build-icons.sh # SVG -> PNG/ICNS via qlmanage/sips/iconutil +| | +-- notarize.js # electron-builder afterSign hook (opt-in notarization) +| +-- tests/ +| +-- smoke.test.mjs # Spawn Electron + probe /api/health +|-- deployments/ +| |-- README.md # Deployment infrastructure reference +| |-- terraform/ # Cloud provisioning (AWS, GCP, Azure, OCI) +| | |-- modules/ # Reusable modules (networking, compute, db, lb, monitoring) +| | |-- providers/ # Cloud-specific implementations +| | +-- environments/ # Per-env tfvars (dev, staging, production) +| |-- kubernetes/ # Kustomize manifests +| | |-- base/ # 11 base resources (deployment, service, ingress, hpa, etc.) +| | |-- overlays/ # Environment overlays (dev, staging, production) +| | |-- components/ # Optional add-ons (mcp-sidecar, monitoring) +| | +-- strategies/ # Blue-green and canary deployment strategies +| |-- helm/agent-monitor/ # Helm chart with 12 templates and 4 value sets +| |-- scripts/ # Operational scripts (deploy, rollback, backup, teardown) +| |-- monitoring/ # Prometheus, Grafana, Alertmanager, Coralogix (OTel Collector) +| +-- ci/ # CI/CD pipelines (GitHub Actions, GitLab CI) +|-- .codex/ +| |-- config.toml # Codex runtime configuration +| |-- README.md # Codex setup guide for agents and skills +| |-- rules/ # Codex execution policy rules +| |-- agents/ # Codex custom agent templates +| +-- skills/ # Codex project skills +|-- statusline/ +| |-- README.md # Statusline installation & usage guide +| |-- statusline.py # Python script that renders the statusline +| +-- statusline-command.sh # Shell wrapper for Claude Code's statusLine config ++-- data/ + +-- dashboard.db # SQLite database (gitignored) +``` + +--- + +## Solución de problemas + +| Problema | Solución | +| --------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `better-sqlite3` no se puede instalar | Esto no es fatal: el servidor vuelve automáticamente a `node:sqlite` incorporado de Node.js (Node 22+). En versiones anteriores de Node, instale Python 3 y las herramientas de compilación de C++, y luego ejecute `npm rebuild better-sqlite3` | +| Los ganchos no están disparando | Ejecute `npm run install-hooks` y reinicie Claude Code. Verifique que los ganchos existan en `~/.claude/settings.json` | +| El panel de control no muestra ningún dato | Asegúrese de que el servidor esté funcionando (`npm run dev`) antes de iniciar una sesión de Claude Code. Verifique `http://localhost:4820/api/health` | +| WebSocket desconectado | El cliente se reconecta automáticamente cada 2 segundos. Verifique que la puerta de enlace 4820 no esté bloqueada por un cortafuegos | +| Datos anticuados después del reinicio | La base de datos persiste a través de los reinicios. Ejecute `npm run seed` para obtener datos de demostración frescos, o elimine `data/dashboard.db` para restablecer | +| Las herramientas MCP no pueden conectarse | Confirmar que la API del panel de control está activa en `MCP_DASHBOARD_BASE_URL` y reconstruir/iniciar MCP (`npm run mcp:build`, `npm run mcp:start`) | + +--- + +## Contribuyendo + +Las contribuciones son bienvenidas, consulte [`.github/CONTRIBUTING.md`](.github/CONTRIBUTING.md) para la guía completa. + +Todos los colaboradores deben firmar el [Acuerdo de Licencia del Colaborador](https://github.com/hoangsonww/Claude-Code-Agent-Monitor/blob/master/CLA.md). Esto se aplica automáticamente en cada solicitud de extracción por la Acción de GitHub `🖋️ Asistente de CLA`: la primera vez que abres una PR, un bot te pide que firmes comentando `He leído el Documento de CLA y por la presente firmo el CLA`. El control de estado del **Asistente de CLA** de la PR permanece en rojo hasta que lo hagas, y firmar una vez cubre todas las contribuciones futuras. + +--- + +## Licencia + +MIT. Consulte [LICENCIA](LICENCIA) para obtener detalles. diff --git a/README-KO.md b/README-KO.md index db469341..f4142413 100644 --- a/README-KO.md +++ b/README-KO.md @@ -70,7 +70,7 @@ Claude Code 에이전트 세션, 도구 사용, 서브에이전트 오케스트 ![MIT License](https://img.shields.io/badge/License-MIT-yellow?style=flat-square) > [!TIP] -> 참고: 영어 원문은 [README.md](./README.md), 중국어 버전은 [README-CN.md](./README-CN.md) (中文版本), 베트남어 버전은 [README-VN.md](./README-VN.md) (Phiên bản tiếng Việt)를 확인하세요. 이 문서는 한국어 버전입니다. +> 참고: 영어 원문은 [README.md](./README.md), 중국어 버전은 [README-CN.md](./README-CN.md) (中文版本), 베트남어 버전은 [README-VN.md](./README-VN.md) (Phiên bản tiếng Việt), 스페인어 버전은 [README-ES.md](./README-ES.md) (Español)를 확인하세요. 이 문서는 한국어 버전입니다. --- @@ -126,11 +126,11 @@ graph LR ### 국제화 (i18n) -UI에는 영어(`en`), 중국어(`zh`), 베트남어(`vi`), 한국어(`ko`)를 위한 내장 로케일 전환 기능이 탑재되어 있습니다. 언어 리소스는 네임스페이스별로 로드되며, 새로고침 후에도 사용자 선호가 안정적으로 유지되도록 브라우저 스토리지를 통해 저장됩니다. +UI에는 영어(`en`), 중국어(`zh`), 베트남어(`vi`), 한국어(`ko`), 스페인어(`es`)를 위한 내장 로케일 전환 기능이 탑재되어 있습니다. 언어 선택기는 향후 언어가 추가되어도 사이드바가 혼잡해지지 않도록 맞춤 드롭다운으로 제공됩니다. 언어 리소스는 네임스페이스별로 로드되며, 새로고침 후에도 사용자 선호가 안정적으로 유지되도록 브라우저 스토리지를 통해 저장됩니다. ```mermaid flowchart LR - A["User selects language
en / zh / vi / ko"] --> B["i18next detector
localStorage -> navigator"] + A["User selects language
en / zh / vi / ko / es"] --> B["i18next detector
localStorage -> navigator"] B --> C["Resolved language
fallback: en"] C --> D["Namespace resources
common/nav/dashboard/..."] D --> E["React useTranslation hooks"] @@ -307,18 +307,18 @@ flowchart LR | **지속적인 프로젝트 동기화** | `~/.claude/projects`의 시작 시 자동 가져오기는 일회성(마커로 게이트)이므로, 최초 실행 **이후** 생성된 프로젝트 폴더 — 세션이 Hook을 통해 전혀 흐르지 않는 경우(예: 호스트 전용 Hook 비활성화) — 는 수동 재스캔 전까지 보이지 않게 됩니다. 백그라운드 동기화(`startSessionSync`)가 하나의 mtime 캐시 + 하나로 합쳐진 스윕을 공유하는 세 가지 트리거로 그 간극을 메웁니다: 시작 시의 **즉시** 스윕, 새 세션 파일/프로젝트 폴더가 나타나는 즉시 발동하는 디바운스된 **`fs.watch`**(macOS/Windows에서는 재귀적; Linux에서는 사용자 공간 재귀 감시자 위험을 피하기 위해 루트 + 직계 자식만), 그리고 **주기적 폴링**(`DASHBOARD_SESSION_SYNC_MS`, 기본 30초). 각 스윕은 mtime이 증가한 파일만 다시 파싱하고 `session_created`/`session_updated`(그리고 메인 에이전트)를 브로드캐스트하여 UI가 실시간으로 새로고침됩니다; 이미 DB에 있는 변경되지 않은 세션은 재파싱 없이 건너뛰므로 재시작 비용은 O(새/변경된 파일)로 유지됩니다 | | **원격 데이터 소스** | SSH를 통한 실시간 원격/다중 머신 데이터 수집. 대시보드는 구성된 각 머신의 `~/.claude/projects`를 **scp**(Windows SSH에서 WSL Claude는 `wsl.exe` + `tar`)로 소스별 샌드박스 스테이징 디렉터리에 미러링하고, 로컬 기록과 **동일한 임포터**로 처리하며 가져온 세션에 출처(`sessions.source`)를 태그합니다. 백그라운드 폴러(`DASHBOARD_REMOTE_SYNC_MS`, 기본 15초; `0` 비활성화)가 준실시간을 유지합니다 — 소스 추가/재활성화 시 즉시 동기화 — 성공한 동기화는 `remote_data.updated`와 세션별 `session_created` / `session_updated` 프레임을 브로드캐스트해 열린 페이지가 수동 Sync 없이 새로고침됩니다. 전역 **데이터 범위** 선택기(로컬만 / 전체 / 특정 소스)로 앱 전체를 좁힙니다. **Settings → Remote Data Sources** 및 `ccam remote-sources`에서 관리하며, 상태는 `remote_source.status`로 스트리밍되고 Sessions 행에 소스 배지가 표시됩니다. 원격 세션은 **실시간 로컬 Hook을 받지 않으므로** 모든 로컬 liveness/stale 휴리스틱에서 제외되며, 대신 **매 동기화마다 미러 transcript로 실시간 상태를 조정**합니다 — JSONL 최신 이벤트 타임스탬프(미러 mtime 폴백)가 `DASHBOARD_REMOTE_ACTIVE_WINDOW_MS`(기본 10분) 이내면 원격 CLI가 아직 실행 중(⇒ `active`), 미러가 멈추면 `completed`로 전환됩니다 | | **반응형 디자인** | 쌓이는 그리드, 스크롤 가능한 테이블, 접을 수 있는 사이드바가 있는 모바일 친화적 레이아웃 | -| **UI 현지화** | 영어(`en`), 중국어(`zh`), 베트남어(`vi`), 한국어(`ko`)에 대해 번역된 UI 문구와 접근성 레이블을 갖춘 내장 언어 전환. 커버리지는 이제 워크플로 툴팁까지 엔드투엔드로 확장됩니다: 통계 카드 계산과 값 버킷 해석, 차트별 "무엇을 / 어떻게 읽는가 / 왜" 팝오버, 모든 그래프의 호버 툴팁(오케스트레이션, 도구 흐름, 파이프라인, 모델 위임, 동시성), 워크플로 패턴 상세 패널의 서사와 제안, 설정 → 모델 가격 책정 정보 팝오버, CLAUDE_HOME 패널, 전체 가져오기 기록 흐름 | +| **UI 현지화** | 영어(`en`), 중국어(`zh`), 베트남어(`vi`), 한국어(`ko`), 스페인어(`es`)에 대해 번역된 UI 문구와 접근성 레이블을 갖춘 내장 언어 전환. 커버리지는 이제 워크플로 툴팁까지 엔드투엔드로 확장됩니다: 통계 카드 계산과 값 버킷 해석, 차트별 "무엇을 / 어떻게 읽는가 / 왜" 팝오버, 모든 그래프의 호버 툴팁(오케스트레이션, 도구 흐름, 파이프라인, 모델 위임, 동시성), 워크플로 패턴 상세 패널의 서사와 제안, 설정 → 모델 가격 책정 정보 팝오버, CLAUDE_HOME 패널, 전체 가져오기 기록 흐름 | | **시드 데이터** | 데모와 개발을 위한 내장 시드 스크립트 | | **Statusline** | 모델, 컨텍스트 사용량, git 브랜치, 방향별 토큰, 세션 비용(USD)을 표시하는 색상 코드 CLI Statusline | | **모델 이름 형식화** | UI 전반의 사람 친화적인 모델 이름: `claude-opus-4-7-20260101`이나 `claude-opus-4-7[1m]` 같은 원시 식별자는 "Claude Opus 4.7" 또는 "Claude Opus 4.7 (1M)"로 표시됩니다. 자동 버전 점 결합, 날짜/latest 접미사 제거, 제공자 접두사 제거, 컨텍스트 창 태그 형식화를 통해 Claude, GPT, Gemini 제품군을 처리합니다. 설정 페이지는 가격 책정 규칙 구성을 위해 원시 이름을 유지합니다 | | **플러그인 마켓플레이스** | 10개의 플러그인(ccam-analytics, ccam-productivity, ccam-devtools, ccam-insights, ccam-dashboard, ccam-cost-guard, ccam-sessions, ccam-workflows, ccam-quality, ccam-config)이 있는 공식 Claude Code 플러그인 마켓플레이스. 53개 스킬, 14개 에이전트, 30개 슬래시 명령, 3개 CLI 도구, 3개 Hook 구성. 모두 실제 데이터 모델에 근거합니다 — 토큰 기준선, 가격 책정 엔진, 워크플로 인텔리전스(11개 데이터셋), 세션 메타데이터. `claude plugin marketplace add`로 설치 | | **Run Claude** | 채팅 스타일 스트리밍 UI로 대시보드에서 직접 `claude` 서브프로세스를 생성합니다. 두 가지 모드: **대화**(멀티턴 — stdin이 열린 상태로 유지되고 후속 턴은 stream-json 봉투로 파이프됨)와 **원샷**(헤드리스, 단일 프롬프트 → 단일 응답). 대화 모드는 `claude --resume `를 통한 **기존 세션 재개**도 지원합니다 — 검색 가능한 피커로 전체 세션 기록에서 선택하세요. 통합된 활성 실행 / 기록 모달은 설정이 필요 없는 두 개의 이동 버튼도 제공합니다: 과거 대화 행의 **재개**는 즉시 `claude --resume `를 생성하고 이전 트랜스크립트로 채팅을 시딩하여 전체 컨텍스트가 있는 라이브 뷰에 도달합니다(프롬프트를 다시 입력할 필요 없음 — 생성된 프로세스는 후속 메시지를 보낼 때까지 stdin에서 대기합니다); 과거 원샷 행의 **보기**는 캡처된 트랜스크립트를 읽기 전용으로 실행 뷰어에 인라인 로드합니다(생성 없음 — 동일한 패널, 중지/후속 컨트롤 없음). 헤더의 활성 실행 전환기로 실행을 백그라운드에 두고 다른 실행을 시작한 뒤 나중에 다시 연결할 수 있습니다. 재연결은 내구성이 있습니다: 클라이언트가 스포너의 메모리 내 봉투 로그(`?envelopes=1`)와 세션의 디스크 JSONL 트랜스크립트를 대조하여 사용자/어시스턴트 메시지가 더 많은 쪽을 선택하므로, 재개된 실행에서 벗어났다가 돌아와도 이전 전체 기록이 계속 보입니다(스포너는 생성 이후의 턴만 보고, 트랜스크립트 파일에는 이전 + 현재가 있습니다). 모델 드롭다운(Opus 4.7 / 1M / Sonnet 4.6 / Haiku 4.5 / 사용자 지정), 명시적 `bypassPermissions` 경고가 있는 권한 모드 피커, **thinking-effort** 필드(low / medium / high — `--effort`에 연결), 사용자의 **홈 디렉터리**로 미리 채워진 cwd 자동완성 — 대시보드 저장소 자체의 `.claude` 프로젝트 컨텍스트(에이전트, 스킬, 규칙, `CLAUDE.md`, `.mcp.json`)를 상속하지 않는 중립적 생성 위치입니다; 홈 제안이 없으면 대시보드 cwd로 폴백하며, 제안 그룹에서 홈이 먼저 나열됩니다(홈 → 대시보드 → 최근). `--include-partial-messages`를 통한 실제 문자 단위 스트리밍에 더해, 각 `text_delta` / `thinking_delta`를 `requestAnimationFrame`으로 흘려보내는 클라이언트 측 **타자기 스무딩 레이어**가 있어 짧은 응답(claude가 전체 답변을 한두 청크로 묶는 경우)도 타이핑되듯 나타납니다. 병합 코드는 claude의 정식 `assistant` 봉투가 스트림 도중 도착해도 `_streaming` 플래그와 델타 누적 `content` 배열을 온전히 유지하므로 완료 시 thinking 블록이 사라지지 않습니다. WebSocket 디스패치는 각 봉투를 `flushSync`로 감싸 React 18의 자동 배칭이 델타 폭주를 단일 렌더로 뭉개지 않게 합니다. **TUI 동등성(Tier 1)**: stream-json 모드가 터미널 TUI 대비 무엇을 할 수 있고 없는지 설명하는, 슬림한 필로 최소화되는(절대 사라지지 않음) 접을 수 있는 **제한 사항 배너**; 사용자 / 프로젝트 / 플러그인 명령을 나열하고(전송 전 템플릿 확장을 통해 클라이언트 측에서 실행) `/clear`, `/model`, `/config` 같은 내장 CLI 명령을 "CLI 전용 — 여기서는 실행되지 않음" 배지와 함께 표시하는, 계층적 점수(정확한 이름 → 시작 일치 → 단어 경계 → 포함 → 부분 시퀀스 → 설명 포함)의 **슬래시 명령 자동완성이 있는 프롬프트 편집기**; 실행의 cwd 전체에 걸친 디바운스된 퍼지 검색(`node_modules`, `.git`, `dist`, `build` 등은 건너뜀)이 있는 **`@` 파일 참조**; 라이브 스트리밍 중에는 `stream_event`와 `result.usage` 봉투에서, 재개 / 보기 / 재연결로 트랜스크립트에서 시딩될 때는 확정된 어시스턴트 `usage` 블록(input / output / cache-read / cache-creation)에서 계산되는, 입력 + 출력 + 캐시 읽기 토큰과 누적 비용을 보여주는 **라이브 컨텍스트 창 / 토큰 미터** — 그래서 미터는 0/200k에 머물지 않고 즉시 채워집니다. 진행 막대는 모델 컨텍스트 한도의 80% / 95%에서 인디고 → 앰버 → 레드로 바뀝니다; 활성 모델, effort, 권한 모드, cwd, 세션 ID, 봉투 수, 경과 시간이 있는 **상태 헤더**. 자동완성 드롭다운은 위쪽으로 열려 아래의 cwd 피커와 충돌하지 않습니다. 제목 옆의 라이브 / 오프라인 표시기. 라우트의 동일 출처 가드가 브라우저 드라이브바이 생성을 방지합니다. 동시성은 기본적으로 사실상 무제한입니다(버그 있는 클라이언트의 포크밤 실수를 막기 위한 10000의 안전 상한; 터미널 TUI에는 상한이 없고 우리도 마찬가지). 실제 상한을 원하면 `RUN_MAX_CONCURRENT`를 설정하세요. 생성된 세션은 다른 `claude` 프로세스와 동일한 Hook을 발생시키므로 세션 / 분석 / Kanban / 워크플로에 자동으로 나타나며 — 세션 / 세션 상세는 현재 Run 페이지에서 구동 중인 세션에 대해 Run 페이지로 다시 연결되는 녹색 **▶ Run** 배지 / 배너를 표시합니다 | | **Claude 설정 탐색기** | Claude Code가 알고 있는 모든 것을 위한 `/cc-config`의 12탭 인스펙터: 스킬, 서브에이전트, 슬래시 명령, 출력 스타일, 플러그인(`plugin.json`의 플러그인별 기여 항목 수 + 작성자/라이선스/홈페이지 포함), 마켓플레이스(각 `marketplace.json`에서 읽은 플러그인 수 포함), MCP 서버, Hook(`~/.claude/hooks/` 스크립트 목록 포함), 설정(`/config`가 제어하는 옵션 — 모델, verbose, 테마, 출력 스타일, effort, 자동 컴팩트, 알림 등 — 을 사용자/프로젝트/프로젝트 로컬 범위에 걸쳐 해석하고 설정되지 않은 옵션은 기본값으로 표시하는 한눈에 보는 **현재 구성** 요약, 그리고 파일별 구조화된 키-값 보기 + 원시 JSON 토글, 비밀 키 마스킹), 메모리(사용자 + 프로젝트 `CLAUDE.md` 파일 **그리고** 프로젝트별 파일 기반 메모리 저장소 — `~/.claude/projects//memory/` 아래의 모든 `*.md`, 즉 `MEMORY.md` 인덱스와 기억된 사실당 하나의 파일로 종종 100개 이상; 인덱스 파일과 사실별 파일을 분리하는 접을 수 있는 섹션에 프로젝트별로 그룹화되고 검색 상자와 대응하는 사실 파일로 이동(스크롤 + 강조)하는 클릭 가능한 `MEMORY.md` 인덱스 링크 제공), 키바인딩(`` 칩과 함께 컨텍스트별 그룹화), Statusline(구성 + 스크립트 내용). 저위험 텍스트 파일 표면(스킬 / 에이전트 / 명령 / 출력 스타일 / 메모리 — 프로젝트별 자동 메모리 파일 포함)에 대해 이 페이지는 Claude Code가 스캔하는 디렉터리 외부에 원자적으로 기록되는 **필수 타임스탬프 백업과 함께 생성 / 편집 / 삭제**를 지원하며, 자동 생성된 `mv` 복원 명령이 있는 백업 모달도 제공합니다. 플러그인, MCP, 설정 내 Hook, `settings.json` 파일은 설명 배너 + 복사 가능한 CLI 명령과 함께 읽기 전용으로 유지되어 사용자가 직접 실행할 정확한 명령을 알 수 있습니다. **실시간 업데이트**: 서버에서 실행되는 `cc-watcher`가 `~/.claude/`(플랫폼이 지원하는 경우 재귀적)와 `~/.claude.json`에 대해 500 ms 디바운스로 `fs.watch`를 사용하여, 대시보드 변경이든 외부 도구(플러그인을 설치하는 CLI, `settings.json` 수동 편집, 새 스킬 추가)든 Claude Code 구성이 변경될 때마다 `cc_config_changed` WebSocket 메시지를 브로드캐스트합니다. 페이지는 이를 구독하고 자동으로 다시 가져옵니다; 제목 옆의 라이브 / 오프라인 필이 WebSocket 상태를 표시합니다 | -| **Tabby** | 모든 페이지의 오른쪽 아래 모서리에 고정된 떠다니는 고양이 친구. 기존 WebSocket `eventBus` 위에 전적으로 구축 — **새 백엔드 없음, API 키 없음, 새 의존성 없음**. 커서를 추적하는 눈과 라이브 세션 스트림에서 도출되는 **8가지 기분**(`idle`, `watching`, `happy`, `worried`, `stuck`, `thinking`, `sleeping`, `disconnected`)을 가진 반응형 SVG 마스코트로, 각 기분마다 고유한 애니메이션(꼬리 흔들기, 귀 쫑긋, 고개 까딱, 떨림, 반짝임, zzz, 경고 "!")이 있습니다. **자동 표시 말풍선**은 주목할 만한 이벤트(세션 시작/종료, 오류, 실행 완료)에 대해 짧고, 스로틀되고, 합쳐진 한마디를 게시하며 음소거할 수 있습니다. 고양이를 클릭하거나 **⌘B / Ctrl+B**를 누르면(Esc로 닫기) 라이브 상태 줄(`N live · M errored · 연결 상태`), 빠른 작업(Run Claude / 활동 / 세션 / 오류 세션으로 이동, 말풍선 음소거, 알림 지우기), **Ask** 상자가 있는 **패널**이 열립니다: 간단한 상태 질문("what's running", "any errors", "status")은 캐시된 데이터에서 로컬로 답변되고, 그 외의 질문은 **Run Claude** 페이지로 넘겨(`/run?prompt=…`로 딥링크) 실제 Claude Code 세션을 생성합니다. 접근성을 갖추었고(키보드 조작 가능, `aria-live` 말풍선, `prefers-reduced-motion` 준수), 소켓이 끊기면 차분한 `disconnected` 상태로 안전하게 저하되며, **설정**에서 토글할 수 있습니다(en/zh/vi/ko로 현지화). 구현은 `client/src/components/Tabby/`에 있습니다 | +| **Tabby** | 모든 페이지의 오른쪽 아래 모서리에 고정된 떠다니는 고양이 친구. 기존 WebSocket `eventBus` 위에 전적으로 구축 — **새 백엔드 없음, API 키 없음, 새 의존성 없음**. 커서를 추적하는 눈과 라이브 세션 스트림에서 도출되는 **8가지 기분**(`idle`, `watching`, `happy`, `worried`, `stuck`, `thinking`, `sleeping`, `disconnected`)을 가진 반응형 SVG 마스코트로, 각 기분마다 고유한 애니메이션(꼬리 흔들기, 귀 쫑긋, 고개 까딱, 떨림, 반짝임, zzz, 경고 "!")이 있습니다. **자동 표시 말풍선**은 주목할 만한 이벤트(세션 시작/종료, 오류, 실행 완료)에 대해 짧고, 스로틀되고, 합쳐진 한마디를 게시하며 음소거할 수 있습니다. 고양이를 클릭하거나 **⌘B / Ctrl+B**를 누르면(Esc로 닫기) 라이브 상태 줄(`N live · M errored · 연결 상태`), 빠른 작업(Run Claude / 활동 / 세션 / 오류 세션으로 이동, 말풍선 음소거, 알림 지우기), **Ask** 상자가 있는 **패널**이 열립니다: 간단한 상태 질문("what's running", "any errors", "status")은 캐시된 데이터에서 로컬로 답변되고, 그 외의 질문은 **Run Claude** 페이지로 넘겨(`/run?prompt=…`로 딥링크) 실제 Claude Code 세션을 생성합니다. 접근성을 갖추었고(키보드 조작 가능, `aria-live` 말풍선, `prefers-reduced-motion` 준수), 소켓이 끊기면 차분한 `disconnected` 상태로 안전하게 저하되며, **설정**에서 토글할 수 있습니다(en/zh/vi/ko/es로 현지화). 구현은 `client/src/components/Tabby/`에 있습니다 | | **프로그레시브 웹 앱(PWA)** | 세 개의 독립적인 PWA — 대시보드, 랜딩 페이지, 위키 — 각각 자체 Web App Manifest와 Service Worker를 갖습니다. 어느 것이든 홈 화면 / 독에 설치하면 크롬 없는 독립 실행형 경험을 얻습니다. 대시보드 SW는 `/assets/` 아래 Vite의 콘텐츠 해시 번들을 캐시 우선으로 제공하고(URL은 빌드마다 불변이므로 캐시 적중은 항상 정확), 그 외 모든 것 — 내비게이션, SW 자체, `manifest.json`, 아이콘, 루트 `/` — 은 캐시 폴백이 있는 네트워크 우선으로 처리합니다. 프로덕션 Express 정적 미들웨어의 명시적 `Cache-Control` 헤더(`/assets/*`는 `immutable`, `index.html`, `sw.js`, `manifest.json`은 `no-cache, must-revalidate`)와 결합하여 재빌드는 하드 새로고침 없이 항상 브라우저 내 번들을 교체합니다; 클라이언트의 `controllerchange` 리스너는 이미 제어 중인 페이지를 새 SW가 인수할 때 정확히 한 번만 다시 로드합니다. VAPID 푸시 알림 파이프라인은 보존됩니다. 랜딩 페이지와 위키 SW는 각자의 셸을 프리캐시하고 첫 방문 시 이미지를 지연 캐시하여, 한 번만 로드하면 오프라인 접근이 가능합니다. 모든 매니페스트는 최신 브라우저를 위해 `sizes="any"`의 SVG 아이콘(`favicon.svg`)을 사용하고, iOS 독립 실행형 모드를 위한 `apple-mobile-web-app-capable` + `apple-touch-icon` 메타 태그를 포함합니다 | | **데스크톱 앱(macOS & Windows)** | `client/`, `server/`, `mcp/`, `vscode-extension/`과 나란히 `desktop/` 워크스페이스에 있는, Electron 35로 빌드된 선택적 네이티브 데스크톱 앱. macOS `.app`(`.dmg`) **및** Windows `.exe`(NSIS 설치 관리자 + 무설치 포터블)로 제공됩니다. 기존 Express 서버를 **인프로세스로** 임베드하고(`server/index.js`를 `require()` — 자식 프로세스 없음, IPC 없음) 빌드된 React 클라이언트를 `BrowserWindow`에 렌더링합니다. 네이티브 타이틀 바, 클릭 시점에 SQLite에서 가져온 **라이브 상태 스냅샷**(세션, 에이전트, 오늘의 이벤트)을 단일 클릭 드롭다운으로 보여주는 메뉴 바 / 알림 영역(트레이) 아이콘, 네이티브 애플리케이션 메뉴, 로그인 시 자동 시작(macOS는 `SMAppService`를 통한 로그인 항목; Windows는 사용자별 `HKCU\…\Run`), **⌘Q / Ctrl+Q 확인 대화 상자**(두 번째 누름은 우회), 창을 닫아도 서버는 계속 실행되는 동작, 단일 인스턴스 잠금, 그리고 **브라우저에서 열기**, **서버 재시작**, **로그 표시** 트레이 작업이 추가됩니다. 포트 4820을 선호하고(4821–4829, 그다음 임의의 높은 포트로 폴백), 4820에서 이미 실행 중인 정상 대시보드가 있으면 이중 바인딩하는 대신 이를 채택하며, **웹 대시보드와 공존합니다** — `npm run dev`와 데스크톱 앱을 함께 실행할 수 있고 Hook이 양쪽 모두로 전파됩니다. 알림은 네이티브 OS 토스트로 발생합니다(Electron 내부에서 Web Push는 안정적으로 작동하지 않음). 처음으로 자체 서버를 부팅할 때 Claude Code Hook을 자동 설치하고 백그라운드 서비스를 시작하므로, 설치만 한 사용자도 수동 설정 없이 이벤트가 흐릅니다. [`DESKTOP.md`](./DESKTOP.md)와 [`desktop/README.md`](./desktop/README.md)를 참조하세요 | | **자체 호스팅 자산(CDN 없음)** | 모든 폰트와 스크립트가 로컬에서 제공되므로 대시보드와 문서는 **제3자 CDN 요청을 전혀 하지 않습니다** — 완전히 오프라인으로 렌더링되며 외부 호스트에 아무것도 유출하지 않습니다. React 앱은 [`@fontsource`](https://fontsource.org/)를 통해 Inter + JetBrains Mono를 번들합니다(latin 서브셋; Vite가 빌드 시 콘텐츠 해시 WOFF2를 `dist/assets/`에 출력하며 Google Fonts로의 `` 없음). 랜딩 페이지와 위키는 저장소 루트 `fonts/` 디렉터리에서 자체 호스팅 `fonts/fonts.css` `@font-face` 시트를 로드합니다. 위키의 Mermaid는 jsDelivr 대신 `wiki/mermaid.min.js`(정품 축소판 `mermaid@10.9.6`)로 로컬 벤더링되고, VS Code 확장의 오류 페이지는 시스템 폰트 스택으로 폴백합니다. `fonts.googleapis.com`, `fonts.gstatic.com`, `cdn.jsdelivr.net` 호출은 어디에도 남아 있지 않습니다 | -| **세션 스플래시 화면** | 앱 로드 시(브라우저 세션당 한 번) 표시되는 짧은 브랜딩 스플래시: **시간 인식 인사말**(Good morning / afternoon / evening / Working late), 굵은 태그라인, 두 개의 부제 텍스트, 어두운 분위기의 배경(방사형 광채 + 떠다니는 별자리 + 그레인) 위의 애니메이션 노드 그래프 브랜드 마크. 완전히 현지화되어 있습니다(en/zh/vi/ko). 오버레이는 첫 페인트부터 **불투명**하여 앱이 절대 비쳐 보이지 않으며, 약 2.5초 유지 후 페이드아웃됩니다; 아무 곳이나 클릭하면 건너뛸 수 있고 `prefers-reduced-motion`을 준수합니다. CSS 전용 애니메이션, 추가 의존성 없음 | +| **세션 스플래시 화면** | 앱 로드 시(브라우저 세션당 한 번) 표시되는 짧은 브랜딩 스플래시: **시간 인식 인사말**(Good morning / afternoon / evening / Working late), 굵은 태그라인, 두 개의 부제 텍스트, 어두운 분위기의 배경(방사형 광채 + 떠다니는 별자리 + 그레인) 위의 애니메이션 노드 그래프 브랜드 마크. 완전히 현지화되어 있습니다(en/zh/vi/ko/es). 오버레이는 첫 페인트부터 **불투명**하여 앱이 절대 비쳐 보이지 않으며, 약 2.5초 유지 후 페이드아웃됩니다; 아무 곳이나 클릭하면 건너뛸 수 있고 `prefers-reduced-motion`을 준수합니다. CSS 전용 애니메이션, 추가 의존성 없음 | --- @@ -1504,7 +1504,7 @@ Tabby는 주목할 만한 이벤트(세션 시작/완료, 오류, 실행 완료) ### 접근성 및 안전한 성능 저하 -Tabby는 키보드로 조작할 수 있고, 말풍선에 `aria-live`를 사용하며, `prefers-reduced-motion`을 존중합니다. WebSocket이 끊기면 오류를 내는 대신 차분한 `disconnected` 상태로 안전하게 전환됩니다. **설정**에서 Tabby를 켜거나 끌 수 있으며(영어, 중국어, 베트남어, 한국어로 현지화됨), 구현은 `client/src/components/Tabby/`에 있습니다. +Tabby는 키보드로 조작할 수 있고, 말풍선에 `aria-live`를 사용하며, `prefers-reduced-motion`을 존중합니다. WebSocket이 끊기면 오류를 내는 대신 차분한 `disconnected` 상태로 안전하게 전환됩니다. **설정**에서 Tabby를 켜거나 끌 수 있으며(영어, 중국어, 베트남어, 한국어, 스페인어로 현지화됨), 구현은 `client/src/components/Tabby/`에 있습니다. --- diff --git a/README-VN.md b/README-VN.md index 4374e2f6..2a2d1d1a 100644 --- a/README-VN.md +++ b/README-VN.md @@ -69,9 +69,9 @@ Bảng điều khiển chuyên nghiệp để theo dõi và trực quan hóa cá ![Auto Release](https://img.shields.io/badge/CI-auto--release_to_GitHub-22c55e?style=flat-square&logo=githubactions&logoColor=white) ![MIT License](https://img.shields.io/badge/License-MIT-yellow?style=flat-square) -**Hỗ trợ ngôn ngữ**: Tiếng Anh (`en`) · 中文 (`zh`) · Tiếng Việt (`vi`) · Tiếng Hàn (`ko`) +**Hỗ trợ ngôn ngữ**: Tiếng Anh (`en`) · 中文 (`zh`) · Tiếng Việt (`vi`) · Tiếng Hàn (`ko`) · Tiếng Tây Ban Nha (`es`) -Tài liệu đã bản địa hóa: [`README.md`](./README.md) · [`README-CN.md`](./README-CN.md) · [`README-VN.md`](./README-VN.md) · [`README-KO.md`](./README-KO.md) +Tài liệu đã bản địa hóa: [`README.md`](./README.md) · [`README-CN.md`](./README-CN.md) · [`README-VN.md`](./README-VN.md) · [`README-KO.md`](./README-KO.md) · [`README-ES.md`](./README-ES.md) --- @@ -126,11 +126,11 @@ Ngoài bảng thông tin giám sát thời gian thực, nó còn bao gồm tri ### Quốc tế hóa (i18n) -Giao diện người dùng đi kèm với tính năng chuyển đổi ngôn ngữ tích hợp cho tiếng Anh (`en`), tiếng Trung (`zh`), tiếng Việt (`vi`) và tiếng Hàn (`ko`). Tài nguyên ngôn ngữ được tải theo không gian tên và được lưu giữ trong bộ nhớ của trình duyệt để mang lại ưu tiên người dùng ổn định trong các lần làm mới. +Giao diện người dùng đi kèm với tính năng chuyển đổi ngôn ngữ tích hợp cho tiếng Anh (`en`), tiếng Trung (`zh`), tiếng Việt (`vi`), tiếng Hàn (`ko`) và tiếng Tây Ban Nha (`es`). Bộ chọn ngôn ngữ là một menu thả xuống tùy chỉnh để không chiếm chỗ khi thêm ngôn ngữ mới. Tài nguyên ngôn ngữ được tải theo không gian tên và được lưu giữ trong bộ nhớ của trình duyệt để mang lại ưu tiên người dùng ổn định trong các lần làm mới. ```mermaid flowchart LR - A["User selects language
en / zh / vi / ko"] --> B["i18next detector
localStorage -> navigator"] + A["User selects language
en / zh / vi / ko / es"] --> B["i18next detector
localStorage -> navigator"] B --> C["Resolved language
fallback: en"] C --> D["Namespace resources
common/nav/dashboard/..."] D --> E["React useTranslation hooks"] @@ -306,7 +306,7 @@ Bảng điều khiển cung cấp một bộ tính năng toàn diện để giá | **Đồng bộ dự án liên tục** | Việc tự động nhập `~/.claude/projects` khi khởi động chỉ chạy một lần (được kiểm soát bằng marker), nên một thư mục dự án được tạo **sau** lần khởi chạy đầu tiên — mà các phiên của nó không bao giờ đi qua hook (ví dụ hook chỉ-trên-host bị tắt) — sẽ vẫn vô hình cho đến khi quét lại thủ công. Một tiến trình đồng bộ nền (`startSessionSync`) lấp khoảng trống đó qua ba kích hoạt cùng chia sẻ một mtime cache + một lần quét gộp duy nhất: một lần quét **ngay lập tức** khi khởi động, một **`fs.watch`** có debounce kích hoạt ngay khoảnh khắc một tệp phiên/thư mục dự án mới xuất hiện (đệ quy trên macOS/Windows; thư mục gốc + các thư mục con trực tiếp trên Linux để tránh rủi ro recursive-watcher ở userland), và một **lần poll định kỳ** (`DASHBOARD_SESSION_SYNC_MS`, mặc định 30 giây). Mỗi lần quét chỉ parse lại các tệp có mtime tăng lên và phát `session_created`/`session_updated` (cùng agent chính) để UI làm mới trực tiếp; một phiên đã được nhập mà không thay đổi sẽ được bỏ qua không cần parse lại, nên chi phí khởi động lại giữ ở mức O(số tệp mới/đã thay đổi) | | **Nguồn dữ liệu từ xa** | Thu thập dữ liệu Claude Code từ các máy khác qua SSH theo thời gian thực. Dashboard mirror `~/.claude/projects` của mỗi máy qua **scp** (hoặc `wsl.exe` + `tar` khi Claude chạy trong WSL trên máy chủ SSH Windows) vào thư mục dàn dựng theo từng nguồn, đưa qua **cùng bộ nhập** dùng cho lịch sử cục bộ, và gắn thẻ phiên theo nguồn (`sessions.source`). Bộ thăm dò nền (`DASHBOARD_REMOTE_SYNC_MS`, mặc định 15 giây; `0` tắt) giữ gần thời gian thực — thêm hoặc bật lại nguồn cũng kích hoạt kéo ngay — và đồng bộ thành công phát `remote_data.updated` cùng khung `session_created` / `session_updated` để trang mở tự làm mới. Bộ chọn **phạm vi dữ liệu** toàn cục (Chỉ cục bộ / Tất cả / nguồn cụ thể) thu hẹp toàn bộ ứng dụng. Quản lý trong **Settings → Remote Data Sources** và qua `ccam remote-sources`; trạng thái phát qua `remote_source.status`, và hàng Sessions hiển thị huy hiệu nguồn. Các phiên từ xa **không nhận hook cục bộ trực tiếp**, nên bị loại khỏi mọi heuristic liveness/stale cục bộ; thay vào đó **trạng thái live được đối chiếu từ transcript đã mirror ở mỗi lần đồng bộ** — dấu thời gian sự kiện JSONL mới nhất (dự phòng mtime mirror) trong `DASHBOARD_REMOTE_ACTIVE_WINDOW_MS` (mặc định 10 phút) nghĩa là CLI từ xa vẫn chạy (⇒ `active`), còn khi mirror ngừng tiến triển thì chuyển sang `completed` | | **Thiết kế đáp ứng** | Bố cục thân thiện với thiết bị di động với lưới xếp chồng, bảng có thể cuộn và thanh bên có thể thu gọn | -| **Bản địa hóa giao diện người dùng** | Chuyển đổi ngôn ngữ tích hợp với bản sao giao diện người dùng được dịch và nhãn trợ năng cho tiếng Anh (`en`), tiếng Trung (`zh`), tiếng Việt (`vi`) và tiếng Hàn (`ko`). Phạm vi đa ngôn ngữ trải dài hết toàn bộ tooltip ở trang Workflows: cách tính của các thẻ thống kê và các diễn giải theo bucket giá trị, popover "Cái gì / Cách đọc / Vì sao" cho mỗi biểu đồ, mọi tooltip hover trên đồ thị (orchestration, tool flow, pipeline, model delegation, concurrency), bảng chi tiết Workflow Patterns với mô tả và gợi ý, popover thông tin Settings → Định giá mô hình, khung CLAUDE_HOME và toàn bộ luồng Import History | +| **Bản địa hóa giao diện người dùng** | Chuyển đổi ngôn ngữ tích hợp với bản sao giao diện người dùng được dịch và nhãn trợ năng cho tiếng Anh (`en`), tiếng Trung (`zh`), tiếng Việt (`vi`) và tiếng Hàn (`ko`) và tiếng Tây Ban Nha (`es`). Phạm vi đa ngôn ngữ trải dài hết toàn bộ tooltip ở trang Workflows: cách tính của các thẻ thống kê và các diễn giải theo bucket giá trị, popover "Cái gì / Cách đọc / Vì sao" cho mỗi biểu đồ, mọi tooltip hover trên đồ thị (orchestration, tool flow, pipeline, model delegation, concurrency), bảng chi tiết Workflow Patterns với mô tả và gợi ý, popover thông tin Settings → Định giá mô hình, khung CLAUDE_HOME và toàn bộ luồng Import History | | **Dữ liệu hạt giống** | Tập lệnh hạt giống tích hợp cho các bản demo và phát triển | | **Dòng trạng thái** | Dòng trạng thái CLI được mã hóa màu hiển thị mô hình, cách sử dụng ngữ cảnh, nhánh git, mã thông báo | | **Định dạng tên mô hình** | Tên mô hình thân thiện trong toàn bộ giao diện: các định danh thô như `claude-opus-4-7-20260101` hoặc `claude-opus-4-7[1m]` hiển thị dạng "Claude Opus 4.7" hoặc "Claude Opus 4.7 (1M)". Hỗ trợ các họ Claude, GPT và Gemini với tự động nối phiên bản bằng dấu chấm, loại bỏ hậu tố ngày/latest, xóa tiền tố nhà cung cấp và định dạng thẻ cửa sổ ngữ cảnh. Trang Cài đặt giữ nguyên tên thô để cấu hình quy tắc giá | @@ -317,7 +317,7 @@ Bảng điều khiển cung cấp một bộ tính năng toàn diện để giá | **Trình khám phá cấu hình Claude** | Trình kiểm tra 12-tab tại `/cc-config` cho mọi thứ Claude Code biết: skills, subagents, lệnh slash, output styles, plugin (kèm số lượng đóng góp + author/license/homepage từ `plugin.json`), marketplaces (kèm số plugin đọc từ mỗi `marketplace.json`), máy chủ MCP, hooks (kèm danh sách script trong `~/.claude/hooks/`), settings (bản tóm tắt **Cấu hình hiện tại** xem nhanh các tuỳ chọn `/config` điều khiển — model, verbose, theme, output style, effort, auto-compact, thông báo, … — phân giải theo phạm vi user/project/project-local với tuỳ chọn chưa đặt hiển thị là mặc định, cùng chế độ key-value có cấu trúc theo từng tệp + chuyển đổi raw JSON, ẩn key bí mật), memory (các tệp `CLAUDE.md` của user + project **cùng** kho memory dựa-trên-tệp theo từng dự án — mọi `*.md` dưới `~/.claude/projects//memory/`, tức một tệp chỉ mục `MEMORY.md` cộng một tệp cho mỗi sự kiện được ghi nhớ, thường 100+; nhóm theo dự án trong các mục thu gọn được, tách tệp chỉ mục khỏi tệp từng-sự-kiện, kèm ô tìm kiếm và các liên kết chỉ mục `MEMORY.md` có thể bấm để nhảy tới — cuộn tới + làm nổi bật — tệp sự kiện tương ứng), keybindings (nhóm theo context với chip ``), và statusline (config + nội dung script). Với các bề mặt tệp văn bản rủi ro thấp (skills / agents / commands / output styles / memory — kể cả các tệp auto-memory theo từng dự án), trang hỗ trợ **tạo / sửa / xoá kèm sao lưu bắt buộc có dấu thời gian**, ghi atomically ra ngoài các thư mục Claude Code quét, kèm modal Backups với lệnh `mv` khôi phục được dựng tự động. Plugins, MCP, hooks-trong-settings và file `settings.json` vẫn chỉ-đọc với banner giải thích + lệnh CLI có thể sao chép để người dùng biết chính xác lệnh nào cần tự chạy. **Cập nhật trực tiếp**: `cc-watcher` chạy phía server dùng `fs.watch` trên `~/.claude/` (đệ quy nếu nền tảng hỗ trợ) cùng `~/.claude.json`, debounce 500 ms, để phát thông điệp WebSocket `cc_config_changed` mỗi khi cấu hình Claude Code thay đổi — qua thao tác trên dashboard hoặc công cụ ngoài (CLI cài plugin, sửa tay `settings.json`, thả skill mới). Trang đăng ký và tự fetch lại; chip Live / Offline cạnh tiêu đề cho thấy trạng thái WebSocket | | **Ứng dụng web tiến bộ (PWA)** | Ba PWA độc lập — dashboard, trang chủ và wiki — mỗi cái có Web App Manifest và Service Worker riêng. Cài đặt bất kỳ cái nào lên màn hình chính / dock để trải nghiệm standalone không thanh trình duyệt. SW của dashboard phục vụ các bundle có hash của Vite tại `/assets/*` theo kiểu cache-first (URL bất biến theo mỗi build, nên cache hit luôn đúng) và xử lý mọi thứ khác (điều hướng, chính SW, `manifest.json`, icon, root `/`) theo kiểu network-first có cache dự phòng. Kết hợp với các header `Cache-Control` rõ ràng trên Express static middleware sản phẩm (`/assets/*` dùng `immutable, max-age=31536000`; `index.html`, `sw.js`, `manifest.json` dùng `no-cache, must-revalidate`), một bản build mới luôn thay thế bundle trong trình duyệt mà không cần hard refresh; listener `controllerchange` trong `client/src/main.tsx` sẽ tự reload đúng một lần khi SW mới tiếp quản trang đang được điều khiển (lần cài đặt đầu tiên thì không reload). Pipeline thông báo đẩy VAPID được giữ nguyên. SW trang chủ và wiki precache shell tương ứng và lazy-cache hình ảnh khi truy cập lần đầu, cho phép truy cập offline sau một lần tải. Tất cả manifest dùng icon SVG (`favicon.svg`) với `sizes="any"`, kèm meta tag `apple-mobile-web-app-capable` + `apple-touch-icon` cho chế độ standalone trên iOS | | **Tài nguyên tự lưu trữ (không CDN)** | Toàn bộ font và script được phục vụ cục bộ — không có một request CDN bên thứ ba nào. Ứng dụng React đóng gói Inter + JetBrains Mono qua `@fontsource` (chỉ subset latin; WOFF2 gắn hash nội dung được Vite phát ra vào `dist/assets/` lúc build). Trang chủ và wiki nạp một bảng `@font-face` tự lưu trữ `fonts/fonts.css` (wiki dùng `../fonts/`). Mermaid của wiki được vendor cục bộ (`wiki/mermaid.min.js`, bản minified thật của `mermaid@10.9.6`) thay cho jsDelivr; trang lỗi của VS Code extension bỏ Google Fonts, lùi về font hệ thống. Loại bỏ mọi lệnh gọi tới `fonts.googleapis.com` / `gstatic` / CDN, nên dashboard và tài liệu render hoàn toàn offline và không rò rỉ gì cho bên thứ ba | -| **Màn hình splash thương hiệu** | Màn hình splash thương hiệu hiển thị một lần mỗi phiên trình duyệt khi tải ứng dụng — lời chào theo thời điểm trong ngày (Chào buổi sáng / chiều / tối), một dòng tiêu đề đậm cùng hai dòng phụ đã bản địa hóa, và một biểu tượng thương hiệu dạng đồ thị nút có hoạt ảnh trên nền tối (radial glow, chòm sao, hạt nhiễu). Đục hoàn toàn ngay từ khung hình đầu (không lóe nội dung ứng dụng phía sau), giữ ~2.5 giây rồi mờ dần, bấm để bỏ qua, tôn trọng `prefers-reduced-motion`, bản địa hóa en/zh/vi/ko | +| **Màn hình splash thương hiệu** | Màn hình splash thương hiệu hiển thị một lần mỗi phiên trình duyệt khi tải ứng dụng — lời chào theo thời điểm trong ngày (Chào buổi sáng / chiều / tối), một dòng tiêu đề đậm cùng hai dòng phụ đã bản địa hóa, và một biểu tượng thương hiệu dạng đồ thị nút có hoạt ảnh trên nền tối (radial glow, chòm sao, hạt nhiễu). Đục hoàn toàn ngay từ khung hình đầu (không lóe nội dung ứng dụng phía sau), giữ ~2.5 giây rồi mờ dần, bấm để bỏ qua, tôn trọng `prefers-reduced-motion`, bản địa hóa en/zh/vi/ko/es | | **Ứng dụng máy tính để bàn (macOS & Windows)** | Ứng dụng máy tính để bàn gốc tùy chọn xây bằng Electron 35, nằm trong workspace `desktop/` cùng với `client/`, `server/`, `mcp/` và `vscode-extension/`. Phát hành dưới dạng `.app` macOS (`.dmg`) **và** `.exe` Windows (trình cài NSIS + bản portable không cần cài). Nó **nhúng máy chủ Express hiện có ngay trong tiến trình** (`require()` trực tiếp `server/index.js` — không có tiến trình con, không có IPC) và hiển thị ứng dụng React đã build trong một `BrowserWindow`. Bổ sung thanh tiêu đề gốc, biểu tượng tray ở menu-bar / khu vực thông báo mà nhấp một lần sẽ hiện **ảnh chụp trạng thái trực tiếp** (phiên, agent, sự kiện hôm nay) lấy từ SQLite tại thời điểm nhấp, trình đơn ứng dụng gốc, tự khởi động lúc đăng nhập (macOS Login Items qua `SMAppService`; Windows theo từng người dùng qua `HKCU\…\Run`), hộp thoại xác nhận **⌘Q / Ctrl+Q** (nhấn lần hai để bỏ qua), đóng cửa sổ thì ẩn đi nhưng máy chủ vẫn chạy, khóa một-phiên-bản, cùng các lệnh tray "Open in Browser", "Restart Server" và "Show Logs". Ưu tiên cổng 4820 (lùi về 4821–4829 rồi cổng cao ngẫu nhiên), tiếp quản một máy chủ khỏe mạnh sẵn có trên 4820 thay vì bind trùng, và **cùng tồn tại với dashboard web**. Thông báo bắn ra dưới dạng toast gốc của hệ điều hành (Web Push không hoạt động ổn định bên trong Electron). Lần khởi động đầu tiên với máy chủ do ứng dụng sở hữu sẽ tự cài hook Claude Code và chạy các dịch vụ nền, nên người dùng chỉ-cài-đặt cũng có sự kiện chảy về mà không cần thiết lập thủ công. Xem [`DESKTOP.md`](./DESKTOP.md) và [`desktop/README.md`](./desktop/README.md) | --- diff --git a/README.md b/README.md index 956620ff..bfb558fa 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ A professional dashboard to track and visualize your Claude Code agent sessions, ![MIT License](https://img.shields.io/badge/License-MIT-yellow?style=flat-square) > [!TIP] -> See also: [README-CN.md](./README-CN.md) (中文版本), [README-VN.md](./README-VN.md) (Phiên bản tiếng Việt), and [README-KO.md](./README-KO.md) (한국어 버전) for localized documentation with region-specific tips and best practices. +> See also: [README-CN.md](./README-CN.md) (中文版本), [README-VN.md](./README-VN.md) (Phiên bản tiếng Việt), [README-KO.md](./README-KO.md) (한국어 버전), and [README-ES.md](./README-ES.md) (versión en español) for localized documentation with region-specific tips and best practices. --- @@ -126,11 +126,11 @@ In addition to the real-time monitoring dashboard, it also includes a local MCP ### Internationalization (i18n) -The UI ships with built-in locale switching for English (`en`), Chinese (`zh`), Vietnamese (`vi`), and Korean (`ko`). Language resources are loaded by namespace and persisted through browser storage for stable user preference across refreshes. +The UI ships with built-in locale switching for English (`en`), Chinese (`zh`), Vietnamese (`vi`), Korean (`ko`), and Spanish (`es`). A custom language dropdown prevents the selector from crowding the sidebar as more locales are added. Language resources are loaded by namespace and persisted through browser storage for stable user preference across refreshes. ```mermaid flowchart LR - A["User selects language
en / zh / vi / ko"] --> B["i18next detector
localStorage -> navigator"] + A["User selects language
en / zh / vi / ko / es"] --> B["i18next detector
localStorage -> navigator"] B --> C["Resolved language
fallback: en"] C --> D["Namespace resources
common/nav/dashboard/..."] D --> E["React useTranslation hooks"] @@ -307,18 +307,18 @@ The dashboard offers a comprehensive set of features to monitor and analyze your | **Continuous Project Sync** | The startup auto-import of `~/.claude/projects` is one-time (marker-gated), so a project folder created **after** first launch — whose sessions never flow through hooks (e.g. host-only hooks disabled) — would stay invisible until a manual rescan. A background sync (`startSessionSync`) closes that gap via three triggers sharing one mtime cache + a single coalesced sweep: an **immediate** sweep at startup, a debounced **`fs.watch`** that fires the instant a new session file/project folder appears (recursive on macOS/Windows; root + immediate children on Linux to avoid the userland recursive-watcher hazard), and a **periodic poll** (`DASHBOARD_SESSION_SYNC_MS`, default 30 s). Each sweep re-parses only files whose mtime advanced and broadcasts `session_created`/`session_updated` (plus the main agent) so the UI refreshes live; an unchanged session already in the DB is skipped without re-parsing, so restart cost stays O(new/changed files) | | **Remote Data Sources** | Live remote / multi-machine data collection over SSH. The dashboard mirrors each configured machine's `~/.claude/projects` via **scp** (or `wsl.exe` + `tar` for WSL-hosted Claude on Windows SSH) into a sandboxed per-source staging dir, feeds it through the **same importer** used for local history, and tags the imported sessions with their origin (`sessions.source`). A background poller (`DASHBOARD_REMOTE_SYNC_MS`, default 15 s; `0` disables) keeps it near-real-time — adding or re-enabling a source also triggers an immediate pull — and successful syncs broadcast `remote_data.updated` plus per-session `session_created` / `session_updated` frames so open pages refresh without manual Sync. A global **data-scope** selector (Local only / All / specific sources) narrows the whole app. Sources are managed in **Settings → Remote Data Sources** (add / test / sync / remove) and via `ccam remote-sources`; status streams over `remote_source.status`, and Sessions rows show a source badge for remote-origin sessions. Remote sessions get **no live local hooks**, so they are excluded from every local liveness/stale heuristic (the `ps`/`lsof` reap, the watchdog transcript scan, and the startup + periodic abandon sweeps — all gated on `source = 'local'`); instead their **live status is reconciled from the mirrored transcript on every sync** — the newest event timestamp inside the JSONL (falling back to mirror mtime) within `DASHBOARD_REMOTE_ACTIVE_WINDOW_MS` (default 10 min) means the remote CLI is still running (→ `active`), and once it stops advancing the session flips to `completed`. Authentication defers entirely to the host's own SSH stack (`~/.ssh/config`, ssh-agent, keys, `known_hosts`) — no passwords or secrets are stored, external commands run via arg arrays (no shell), and `StrictHostKeyChecking` stays at the SSH default so an unknown host key fails rather than being trusted | | **Responsive Design** | Mobile-friendly layouts with stacking grids, scrollable tables, and collapsible sidebar | -| **UI Localization** | Built-in language switching with translated UI copy and accessibility labels for English (`en`), Chinese (`zh`), Vietnamese (`vi`), and Korean (`ko`). Coverage now extends end-to-end through the Workflows tooltips: stat-card calculations and value-bucket interpretations, per-chart "What / How to read / Why" popovers, every graph's hover tooltip (orchestration, tool flow, pipeline, model delegation, concurrency), the Workflow Patterns detail-panel narratives and suggestions, the Settings → Model Pricing info popover, the CLAUDE_HOME panel, and the entire Import History flow | +| **UI Localization** | Built-in custom-dropdown language switching with translated UI copy and accessibility labels for English (`en`), Chinese (`zh`), Vietnamese (`vi`), Korean (`ko`), and Spanish (`es`). Coverage extends end-to-end through the Workflows tooltips: stat-card calculations and value-bucket interpretations, per-chart "What / How to read / Why" popovers, every graph's hover tooltip (orchestration, tool flow, pipeline, model delegation, concurrency), the Workflow Patterns detail-panel narratives and suggestions, the Settings → Model Pricing info popover, the CLAUDE_HOME panel, and the entire Import History flow. | | **Seed Data** | Built-in seed script for demos and development | | **Statusline** | Color-coded CLI statusline showing model, context usage, git branch, per-direction tokens, and session cost (USD) | | **Model Name Formatting** | Human-friendly model names throughout the UI: raw identifiers like `claude-opus-4-7-20260101` or `claude-opus-4-7[1m]` display as "Claude Opus 4.7" or "Claude Opus 4.7 (1M)". Handles Claude, GPT, and Gemini families with automatic version dot-joining, date/latest suffix stripping, provider prefix removal, and context-window tag formatting. Settings page retains raw names for pricing rule configuration | | **Plugin Marketplace** | Official Claude Code plugin marketplace with 10 plugins (ccam-analytics, ccam-productivity, ccam-devtools, ccam-insights, ccam-dashboard, ccam-cost-guard, ccam-sessions, ccam-workflows, ccam-quality, ccam-config). 53 skills, 14 agents, 30 slash commands, 3 CLI tools, 3 hook configs. All grounded in actual data model — token baselines, pricing engine, workflow intelligence (11 datasets), session metadata. Install via `claude plugin marketplace add` | | **Run Claude** | Spawn `claude` subprocesses directly from the dashboard with a chat-style streaming UI. Two modes: **Conversation** (multi-turn — stdin stays open, follow-up turns are piped as stream-json envelopes) and **One-shot** (headless, single prompt → single response). Conversation mode also supports **resuming any existing session** via `claude --resume ` — pick from your full sessions history with a searchable picker. The unified active-runs / history modal also offers two zero-config jump buttons: **Resume** on any past conversation row spawns `claude --resume ` immediately and seeds the chat with the prior transcript so you land in the live view with full context (no need to retype a prompt — the spawn idles on stdin until you send a follow-up); **View** on any past one-shot row loads the captured transcript inline into the run viewer as read-only (no spawn — same panel, no Stop/follow-up controls). Active runs switcher in the header lets you leave a run in the background, start another, and re-attach later. Re-attach is durable: the client reconciles the spawner's in-memory envelope log (`?envelopes=1`) with the session's on-disk JSONL transcript and prefers whichever has more user/assistant messages, so navigating away from a resumed run and coming back keeps the full prior history visible (the spawner only sees post-spawn turns; the transcript file has prior + current). Model dropdown (Opus 4.7 / 1M / Sonnet 4.6 / Haiku 4.5 / custom), permission-mode picker with explicit `bypassPermissions` warning, **thinking-effort** field (low / medium / high — wired to `--effort`), cwd autocomplete pre-filled with the user's **home directory** — a neutral spawn location that doesn't inherit the dashboard repo's own `.claude` project context (agents, skills, rules, `CLAUDE.md`, `.mcp.json`); falls back to the dashboard cwd if no home suggestion is available, with home listed first in the suggestion groups (home → dashboard → recent). Real character-by-character streaming via `--include-partial-messages`, plus a client-side **typewriter smoothing layer** that drips each `text_delta` / `thinking_delta` through `requestAnimationFrame` so even short replies (where claude bundles the whole answer into one or two chunks) appear to type in. The merge code keeps the `_streaming` flag and the delta-accumulated `content` array intact when claude's canonical `assistant` envelope arrives mid-stream, so thinking blocks aren't dropped at completion. WebSocket dispatch wraps each envelope in `flushSync` so React 18's auto-batching doesn't collapse bursts of deltas into a single render. **TUI parity (Tier 1)**: a collapsible **limitations banner** that minimizes to a slim pill (never disappears) explaining what stream-json mode can and can't do vs. the terminal TUI; a **prompt editor with slash-command autocomplete** with tiered scoring (exact name → starts-with → word-boundary → contains → subsequence → description-contains) that lists user / project / plugin commands (executed client-side via template expansion before send) and surfaces built-in CLI commands like `/clear`, `/model`, `/config` with a "CLI only — won't run from here" badge; **`@`-file references** with debounced fuzzy-search across the run's cwd (skipping `node_modules`, `.git`, `dist`, `build`, etc.); a **live context-window / token meter** showing input + output + cache-read tokens and running cost, computed from `stream_event` and `result.usage` envelopes during live streaming and from finalized assistant `usage` blocks (input / output / cache-read / cache-creation) when seeded from a transcript on resume / view / re-attach, so the meter populates immediately instead of sitting at 0/200k. Progress bar goes indigo → amber → red at 80% / 95% of the model's context cap; a **status header** with the active model, effort, permission mode, cwd, session ID, envelope count, and elapsed time. Autocomplete dropdowns open upward so they don't collide with the cwd picker below. Live / Offline indicator next to the title. Same-origin guard on the route prevents browser drive-by spawning. Concurrency is effectively uncapped by default (sanity ceiling of 10000 to prevent fork-bomb footguns from a buggy client; the terminal TUI has no cap and neither do we). Set `RUN_MAX_CONCURRENT` if you want a real ceiling. Spawned sessions fire the same hooks any `claude` process does, so they show up automatically in Sessions / Analytics / Kanban / Workflows — and Sessions / SessionDetail surface a green **▶ Run** badge / banner that links back to the Run page for any session that's currently being driven from there | | **Claude Config Explorer** | A 12-tab inspector at `/cc-config` for everything Claude Code knows about: skills, subagents, slash commands, output styles, plugins (with per-plugin contributions count + author/license/homepage from `plugin.json`), marketplaces (with plugin counts read from each `marketplace.json`), MCP servers, hooks (with `~/.claude/hooks/` script listing), settings (an at-a-glance **Current configuration** summary of the options `/config` controls — model, verbose, theme, output style, effort, auto-compact, notifications, … — resolved across user/project/project-local scopes with unset options shown as defaults, plus the per-file structured key-value view + raw JSON toggle, secret-key redaction), memory (the user + project `CLAUDE.md` files **plus** the per-project file-based memory store — every `*.md` under `~/.claude/projects//memory/`, i.e. a `MEMORY.md` index plus one file per remembered fact, often 100+; grouped by project in collapsible sections that split index files from per-fact files, with a search box and clickable `MEMORY.md` index links that jump to — scroll to + highlight — the matching fact file), keybindings (grouped by context with `` chips), and statusline (config + script content). For low-risk text-file surfaces (skills / agents / commands / output styles / memory — including the per-project auto-memory files) the page supports **create / edit / delete with mandatory timestamped backups** atomically written outside the directories Claude Code scans, plus a Backups modal with auto-built `mv` restore commands. Plugins, MCP, hooks-in-settings, and `settings.json` files stay read-only with explainer banners + copy-able CLI commands so the user knows the exact command to run themselves. **Live updates**: a `cc-watcher` running on the server uses `fs.watch` on `~/.claude/` (recursive where the platform supports it) plus `~/.claude.json`, debounced at 500 ms, to broadcast a `cc_config_changed` WebSocket message whenever Claude Code config changes — either via dashboard mutations or external tools (CLI installing a plugin, manually editing `settings.json`, dropping a new skill). The page subscribes and refetches automatically; a Live / Offline pill next to the title shows WebSocket status | -| **Tabby** | A floating cat companion pinned to the bottom-right corner of every page. Built entirely on the existing WebSocket `eventBus` — **no new backend, no API key, no new dependencies**. A reactive SVG mascot with cursor-tracking eyes and **eight moods** derived from the live session stream (`idle`, `watching`, `happy`, `worried`, `stuck`, `thinking`, `sleeping`, `disconnected`), each with its own animation (tail flick, ear perk, head bob, shake, sparkle, zzz, alert "!"). **Auto-surface speech bubbles** post short, throttled, coalesced quips on notable events (session started/finished, errors, run completed) and can be muted. Click the cat or press **⌘B / Ctrl+B** (Esc closes) to open a **panel** with a live status line (`N live · M errored · connection state`), quick actions (jump to Run Claude / Activity / Sessions / errored sessions, mute bubbles, clear alerts), and an **Ask** box: simple status questions ("what's running", "any errors", "status") are answered locally from cached data, while any other question hands off to the **Run Claude** page (deep-links to `/run?prompt=…`) to spawn a real Claude Code session. Accessible (keyboard-operable, `aria-live` bubbles, honors `prefers-reduced-motion`), degrades safe to a calm `disconnected` state if the socket is down, toggleable in **Settings** (localized in en/zh/vi/ko). Implementation lives in `client/src/components/Tabby/` | +| **Tabby** | A floating cat companion pinned to the bottom-right corner of every page. Built entirely on the existing WebSocket `eventBus` — **no new backend, no API key, no new dependencies**. A reactive SVG mascot with cursor-tracking eyes and **eight moods** derived from the live session stream (`idle`, `watching`, `happy`, `worried`, `stuck`, `thinking`, `sleeping`, `disconnected`), each with its own animation (tail flick, ear perk, head bob, shake, sparkle, zzz, alert "!"). **Auto-surface speech bubbles** post short, throttled, coalesced quips on notable events (session started/finished, errors, run completed) and can be muted. Click the cat or press **⌘B / Ctrl+B** (Esc closes) to open a **panel** with a live status line (`N live · M errored · connection state`), quick actions (jump to Run Claude / Activity / Sessions / errored sessions, mute bubbles, clear alerts), and an **Ask** box: simple status questions ("what's running", "any errors", "status") are answered locally from cached data, while any other question hands off to the **Run Claude** page (deep-links to `/run?prompt=…`) to spawn a real Claude Code session. Accessible (keyboard-operable, `aria-live` bubbles, honors `prefers-reduced-motion`), degrades safe to a calm `disconnected` state if the socket is down, toggleable in **Settings** (localized in en/zh/vi/ko/es). Implementation lives in `client/src/components/Tabby/` | | **Progressive Web App (PWA)** | Three independent PWAs — dashboard, landing page, and wiki — each with its own Web App Manifest and Service Worker. Install any of them to your home screen / dock for a standalone, chrome-less experience. The dashboard SW serves Vite's content-hashed bundles under `/assets/` cache-first (URLs are immutable per build, so cache hits are always correct) and treats everything else — navigations, the SW itself, `manifest.json`, icons, root `/` — as network-first with cache fallback. Combined with explicit `Cache-Control` headers on the production Express static middleware (`immutable` for `/assets/*`, `no-cache, must-revalidate` for `index.html`, `sw.js`, `manifest.json`), a rebuild always replaces the in-browser bundle without a hard refresh; a `controllerchange` listener in the client reloads exactly once when a new SW takes over an already-controlled page. The VAPID push-notification pipeline is preserved. The landing-page and wiki SWs precache their respective shells and lazy-cache images on first visit, enabling offline access after a single load. All manifests use SVG icons (`favicon.svg`) with `sizes="any"` for modern browsers, and include `apple-mobile-web-app-capable` + `apple-touch-icon` meta tags for iOS standalone mode | | **Desktop App (macOS & Windows)** | Optional native desktop app built with Electron 35, living in the `desktop/` workspace alongside `client/`, `server/`, `mcp/`, and `vscode-extension/`. Ships as a macOS `.app` (`.dmg`) **and** a Windows `.exe` (NSIS installer + no-install portable). It embeds the existing Express server **in-process** (`require()`s `server/index.js` — no child process, no IPC) and renders the built React client in a `BrowserWindow`. Adds a native title bar, a menu-bar / notification-area (tray) icon whose single-click dropdown shows a **live status snapshot** (sessions, agents, events today) pulled from SQLite at click time, a native application menu, auto-start at login (macOS Login Items via `SMAppService`; Windows per-user `HKCU\…\Run`), a **⌘Q / Ctrl+Q confirmation dialog** (second press bypasses), window-close-hides-but-server-keeps-running, a single-instance lock, and tray actions for **Open in Browser**, **Restart Server**, and **Show Logs**. Prefers port 4820 (falls back to 4821–4829 then a random high port), adopts a healthy dashboard already running on 4820 instead of double-binding, and **coexists with the web dashboard** — both `npm run dev` and the desktop app can run together with hooks fanning out to both. Notifications fire as native OS toasts (Web Push doesn't work reliably inside Electron). On first owned-server boot it auto-installs Claude Code hooks and starts the background services, so an install-only user gets events flowing with zero manual setup. See [`DESKTOP.md`](./DESKTOP.md) and [`desktop/README.md`](./desktop/README.md) | | **Self-hosted assets (no CDN)** | Every font and script is served locally, so the dashboard and docs make **zero third-party CDN requests** — they render fully offline and leak nothing to external hosts. The React app bundles Inter + JetBrains Mono via [`@fontsource`](https://fontsource.org/) (latin subset; Vite emits content-hashed WOFF2 into `dist/assets/` at build time, no `` to Google Fonts). The landing page and wiki load a self-hosted `fonts/fonts.css` `@font-face` sheet from the repo-root `fonts/` directory. The wiki's Mermaid is vendored locally as `wiki/mermaid.min.js` (the genuine minified `mermaid@10.9.6`) instead of jsDelivr, and the VS Code extension's error page falls back to a system font stack. No `fonts.googleapis.com`, `fonts.gstatic.com`, or `cdn.jsdelivr.net` calls remain anywhere | -| **Session splash screen** | A brief branding splash on app load (once per browser session): a **time-aware greeting** (Good morning / afternoon / evening / Working late), a bold tagline, two subtexts, and an animated node-graph brand mark over a dark atmospheric backdrop (radial glow + drifting constellation + grain). Fully localized (en/zh/vi/ko). The overlay is **opaque from the first paint** so the app never flashes through, holds ~2.5 s, then fades out; click anywhere to skip, and it honors `prefers-reduced-motion`. CSS-only animations, no added dependencies | +| **Session splash screen** | A brief branding splash on app load (once per browser session): a **time-aware greeting** (Good morning / afternoon / evening / Working late), a bold tagline, two subtexts, and an animated node-graph brand mark over a dark atmospheric backdrop (radial glow + drifting constellation + grain). Fully localized (en/zh/vi/ko/es). The overlay is **opaque from the first paint** so the app never flashes through, holds ~2.5 s, then fades out; click anywhere to skip, and it honors `prefers-reduced-motion`. CSS-only animations, no added dependencies | --- @@ -1533,7 +1533,7 @@ The **Ask** box answers simple status questions locally from cached data — for ### Accessibility & safe degradation -Tabby is keyboard-operable, uses `aria-live` for its bubbles, and honors `prefers-reduced-motion`. If the WebSocket is down it degrades safely to a calm `disconnected` state rather than erroring. You can toggle Tabby on or off in **Settings** (localized in English, Chinese, Vietnamese, and Korean), and the implementation lives in `client/src/components/Tabby/`. +Tabby is keyboard-operable, uses `aria-live` for its bubbles, and honors `prefers-reduced-motion`. If the WebSocket is down it degrades safely to a calm `disconnected` state rather than erroring. You can toggle Tabby on or off in **Settings** (localized in English, Chinese, Vietnamese, Korean, and Spanish), and the implementation lives in `client/src/components/Tabby/`. --- diff --git a/client/README.md b/client/README.md index 8981e51b..a3d0f24e 100644 --- a/client/README.md +++ b/client/README.md @@ -206,7 +206,7 @@ client/ │ │ ├── useWebSocket.ts # Auto-reconnecting WebSocket hook │ │ └── useNotifications.ts # Browser push notification triggers │ │ -│ ├── i18n/ # Internationalization (en / zh / vi / ko) +│ ├── i18n/ # Internationalization (en / zh / vi / ko / es) │ ├── App.tsx # Root component + router setup │ ├── main.tsx # Entry point │ └── index.css # Tailwind + custom utilities diff --git a/client/src/components/Sidebar.tsx b/client/src/components/Sidebar.tsx index d71ed703..37c8659b 100644 --- a/client/src/components/Sidebar.tsx +++ b/client/src/components/Sidebar.tsx @@ -74,7 +74,6 @@ import { Globe, PanelLeftClose, PanelLeftOpen, - Languages, RefreshCw, X, Plug, @@ -87,6 +86,7 @@ import type { LucideIcon } from "lucide-react"; import { api } from "../lib/api"; import { eventBus } from "../lib/eventBus"; import type { UpdateStatusPayload, WSMessage } from "../lib/types"; +import { Select } from "./Select"; function isUpdatePayload(x: unknown): x is UpdateStatusPayload { return typeof x === "object" && x !== null && "git_repo" in x && "update_available" in x; @@ -107,7 +107,7 @@ const NAV_KEYS = [ const STORAGE_KEY = "sidebar-collapsed"; const STATS_STORAGE_KEY = "sidebar-connection-stats"; const RECENT_EVENTS_CAP = 8; -const SUPPORTED_LANGUAGES = ["en", "zh", "vi", "ko"] as const; +const SUPPORTED_LANGUAGES = ["en", "zh", "vi", "ko", "es"] as const; type SupportedLanguage = (typeof SUPPORTED_LANGUAGES)[number]; interface PersistedStats { @@ -169,7 +169,7 @@ function loadStats(): PersistedStats { function normalizeLanguage(language: string): SupportedLanguage { const base = language.toLowerCase().split("-")[0]; - if (base === "zh" || base === "vi" || base === "en" || base === "ko") { + if (base === "zh" || base === "vi" || base === "en" || base === "ko" || base === "es") { return base; } return "en"; @@ -375,15 +375,11 @@ export function Sidebar({ wsConnected, collapsed, onToggle }: SidebarProps) { ? t("nav:upToDate") : t("nav:checkForUpdates"); const currentLanguage = normalizeLanguage(i18n.resolvedLanguage ?? i18n.language); - const currentIndex = SUPPORTED_LANGUAGES.indexOf(currentLanguage); - const nextLanguage = SUPPORTED_LANGUAGES[(currentIndex + 1) % SUPPORTED_LANGUAGES.length]; - const switchLanguageTitle = t("nav:switchLanguage", { - language: t(`nav:languageNames.${nextLanguage}`), - }); - - const toggleLang = () => { - i18n.changeLanguage(nextLanguage); - }; + const languageOptions = SUPPORTED_LANGUAGES.map((language) => ({ + value: language, + label: t(`nav:languageNames.${language}`), + hint: t(`nav:languageShort.${language}`), + })); const changeLanguage = (language: SupportedLanguage) => { if (language !== currentLanguage) { @@ -468,46 +464,20 @@ export function Sidebar({ wsConnected, collapsed, onToggle }: SidebarProps) { {/* Language controls */}
- {collapsed ? ( - - ) : ( -
+
+ {!collapsed && (

{t("nav:language")}

-
- {SUPPORTED_LANGUAGES.map((language) => { - const active = language === currentLanguage; - return ( - - ); - })} -
+ )} +
+ + value={currentLanguage} + onChange={changeLanguage} + options={languageOptions} + />
- )} +
{/* Collapse toggle */} diff --git a/client/src/components/__tests__/Sidebar.test.tsx b/client/src/components/__tests__/Sidebar.test.tsx index e81af677..6683bf33 100644 --- a/client/src/components/__tests__/Sidebar.test.tsx +++ b/client/src/components/__tests__/Sidebar.test.tsx @@ -4,11 +4,12 @@ * @author Son Nguyen */ -import { describe, it, expect } from "vitest"; +import { beforeEach, describe, it, expect } from "vitest"; import { render, screen, waitFor } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { MemoryRouter } from "react-router-dom"; import { Sidebar } from "../Sidebar"; +import i18n from "../../i18n"; function renderSidebar(wsConnected: boolean, collapsed = false) { return render( @@ -19,6 +20,10 @@ function renderSidebar(wsConnected: boolean, collapsed = false) { } describe("Sidebar", () => { + beforeEach(async () => { + await i18n.changeLanguage("en"); + }); + it("should render the brand name", () => { renderSidebar(true); expect(screen.getByText("Agent Dashboard")).toBeInTheDocument(); @@ -65,19 +70,25 @@ describe("Sidebar", () => { expect(hrefs).toContain("/activity"); }); - it("should render four language options in expanded mode", () => { + it("should expose all five languages through the custom dropdown", async () => { + const user = userEvent.setup(); renderSidebar(true); + expect(screen.getByRole("button", { name: "English" })).toBeInTheDocument(); - expect(screen.getByRole("button", { name: "Chinese" })).toBeInTheDocument(); - expect(screen.getByRole("button", { name: "Vietnamese" })).toBeInTheDocument(); - expect(screen.getByRole("button", { name: "Korean" })).toBeInTheDocument(); + await user.click(screen.getByRole("button", { name: "English" })); + + expect(screen.getByRole("option", { name: "Chinese 中文" })).toBeInTheDocument(); + expect(screen.getByRole("option", { name: "Vietnamese VI" })).toBeInTheDocument(); + expect(screen.getByRole("option", { name: "Korean 한국어" })).toBeInTheDocument(); + expect(screen.getByRole("option", { name: "Spanish ES" })).toBeInTheDocument(); }); it("should switch to Vietnamese when Vietnamese option is clicked", async () => { const user = userEvent.setup(); renderSidebar(true); - await user.click(screen.getByRole("button", { name: "Vietnamese" })); + await user.click(screen.getByRole("button", { name: "English" })); + await user.click(screen.getByRole("option", { name: "Vietnamese VI" })); await waitFor(() => { expect(screen.getByText("Tổng quan")).toBeInTheDocument(); @@ -89,7 +100,8 @@ describe("Sidebar", () => { const user = userEvent.setup(); renderSidebar(true); - await user.click(screen.getByRole("button", { name: "Korean" })); + await user.click(screen.getByRole("button", { name: "English" })); + await user.click(screen.getByRole("option", { name: "Korean 한국어" })); await waitFor(() => { expect(screen.getByText("대시보드")).toBeInTheDocument(); @@ -97,15 +109,16 @@ describe("Sidebar", () => { }); }); - it("should cycle language in collapsed mode", async () => { + it("should switch language from the collapsed custom dropdown", async () => { const user = userEvent.setup(); renderSidebar(true, true); - expect(screen.getByText("EN")).toBeInTheDocument(); - await user.click(screen.getByRole("button", { name: "Switch to Chinese" })); + await user.click(screen.getByRole("button", { name: "English" })); + await user.click(screen.getByRole("option", { name: "Spanish ES" })); await waitFor(() => { - expect(screen.getByText("中文")).toBeInTheDocument(); + expect(screen.getByTitle("Panel")).toBeInTheDocument(); + expect(screen.getByTitle("Tablero Kanban")).toBeInTheDocument(); }); }); }); diff --git a/client/src/i18n/__tests__/i18n.test.ts b/client/src/i18n/__tests__/i18n.test.ts index dc7b456c..9d8d520f 100644 --- a/client/src/i18n/__tests__/i18n.test.ts +++ b/client/src/i18n/__tests__/i18n.test.ts @@ -16,7 +16,7 @@ describe("i18n resources", () => { expect(i18n.t("nav:languageShort.vi")).toBe("VI"); }); - it("should keep Agent terminology untranslated in zh, vi, and ko locales", async () => { + it("should keep Agent terminology untranslated in zh, vi, ko, and es locales", async () => { await i18n.changeLanguage("zh"); expect(i18n.t("common:agent")).toBe("Agent"); expect(i18n.t("common:subagent")).toBe("Subagent"); @@ -28,6 +28,36 @@ describe("i18n resources", () => { await i18n.changeLanguage("ko"); expect(i18n.t("common:agent")).toBe("Agent"); expect(i18n.t("common:subagent")).toBe("Subagent"); + + await i18n.changeLanguage("es"); + expect(i18n.t("common:agent")).toBe("agente"); + expect(i18n.t("common:subagent")).toBe("subagente"); + }); + + it("should provide Spanish translations for navigation keys", async () => { + await i18n.changeLanguage("es"); + + expect(i18n.t("nav:dashboard")).toBe("Panel"); + expect(i18n.t("nav:agentBoard")).toBe("Tablero Kanban"); + expect(i18n.t("nav:languageShort.es")).toBe("ES"); + }); + + it("should provide Spanish translations across every feature namespace", async () => { + await i18n.changeLanguage("es"); + + expect(i18n.t("common:awaitingReason.session_start.label")).toBe("Esperando una instrucción"); + expect(i18n.t("analytics:total30d")).toBe("Total (30 días)"); + expect(i18n.t("ccConfig:tabs.skills")).toBe("Habilidades"); + expect(i18n.t("run:fields.prompt")).toBe("Instrucción"); + expect(i18n.t("settings:hooks.title")).toBe("Configuración de ganchos"); + expect(i18n.t("workflows:runs.promptLabel")).toBe("Instrucción"); + }); + + it("should support non-explicit Spanish locale tags", async () => { + await i18n.changeLanguage("es-ES"); + + expect(i18n.resolvedLanguage?.startsWith("es")).toBe(true); + expect(i18n.t("nav:dashboard")).toBe("Panel"); }); it("should support non-explicit Vietnamese locale tags", async () => { diff --git a/client/src/i18n/index.ts b/client/src/i18n/index.ts index e31b1c6b..a4b30d8e 100644 --- a/client/src/i18n/index.ts +++ b/client/src/i18n/index.ts @@ -133,6 +133,22 @@ import run_ko from "./locales/ko/run.json"; import alerts_ko from "./locales/ko/alerts.json"; import splash_ko from "./locales/ko/splash.json"; +import common_es from "./locales/es/common.json"; +import nav_es from "./locales/es/nav.json"; +import dashboard_es from "./locales/es/dashboard.json"; +import sessions_es from "./locales/es/sessions.json"; +import activity_es from "./locales/es/activity.json"; +import analytics_es from "./locales/es/analytics.json"; +import workflows_es from "./locales/es/workflows.json"; +import settings_es from "./locales/es/settings.json"; +import kanban_es from "./locales/es/kanban.json"; +import errors_es from "./locales/es/errors.json"; +import updates_es from "./locales/es/updates.json"; +import ccConfig_es from "./locales/es/ccConfig.json"; +import run_es from "./locales/es/run.json"; +import alerts_es from "./locales/es/alerts.json"; +import splash_es from "./locales/es/splash.json"; + i18n .use(LanguageDetector) .use(initReactI18next) @@ -206,8 +222,25 @@ i18n alerts: alerts_ko, splash: splash_ko, }, + es: { + common: common_es, + nav: nav_es, + dashboard: dashboard_es, + sessions: sessions_es, + activity: activity_es, + analytics: analytics_es, + workflows: workflows_es, + settings: settings_es, + kanban: kanban_es, + errors: errors_es, + updates: updates_es, + ccConfig: ccConfig_es, + run: run_es, + alerts: alerts_es, + splash: splash_es, + }, }, - supportedLngs: ["en", "zh", "vi", "ko"], + supportedLngs: ["en", "zh", "vi", "ko", "es"], nonExplicitSupportedLngs: true, fallbackLng: "en", ns: [ diff --git a/client/src/i18n/locales/en/nav.json b/client/src/i18n/locales/en/nav.json index c869b149..05aa30cd 100644 --- a/client/src/i18n/locales/en/nav.json +++ b/client/src/i18n/locales/en/nav.json @@ -58,12 +58,14 @@ "en": "English", "zh": "Chinese", "vi": "Vietnamese", - "ko": "Korean" + "ko": "Korean", + "es": "Spanish" }, "languageShort": { "en": "EN", "zh": "中文", "vi": "VI", - "ko": "한국어" + "ko": "한국어", + "es": "ES" } } diff --git a/client/src/i18n/locales/es/activity.json b/client/src/i18n/locales/es/activity.json new file mode 100644 index 00000000..0100b782 --- /dev/null +++ b/client/src/i18n/locales/es/activity.json @@ -0,0 +1,10 @@ +{ + "title": "Feed de Actividad", + "subtitle": "Flujo en tiempo real de todos los eventos de los agentes", + "paused": "(pausado - {{count}} en búfer)", + "resume": "Reanudar", + "pause": "Pausar", + "noActivity": "Sin actividad aún", + "noActivityDesc": "Los eventos se transmitirán aquí en tiempo real mientras los agentes de Claude Code trabajan.", + "viewSession": "Sesión" +} diff --git a/client/src/i18n/locales/es/alerts.json b/client/src/i18n/locales/es/alerts.json new file mode 100644 index 00000000..3201ce64 --- /dev/null +++ b/client/src/i18n/locales/es/alerts.json @@ -0,0 +1,80 @@ +{ + "title": "Alertas", + "subtitle": "Alertas basadas en reglas para sesiones, agentes, eventos y uso de tokens", + "refresh": "Actualizar", + "ackAll": "Reconocer todas ({{count}})", + "ruleTypes": { + "event_pattern": "Patrón de evento", + "inactivity": "Inactividad", + "status_duration": "Agente bloqueado", + "token_threshold": "Umbral de tokens" + }, + "ruleTypeHints": { + "event_pattern": "Se activa cuando un evento ingestado coincide con el patrón. Establece un conteo superior a 1 para requerir N eventos coincidentes dentro de una ventana de tiempo (p. ej., más de 5 errores en 2 minutos).", + "inactivity": "Se activa cuando una sesión activa no ha recibido eventos durante el número de minutos configurado.", + "status_duration": "Se activa cuando un agente ha permanecido en el estado seleccionado sin actividad durante el número de minutos configurado.", + "token_threshold": "Se activa cuando el uso total de tokens de una sesión (entrada + salida + caché) supera el umbral." + }, + "ruleDesc": { + "eventPattern": "Coincide con {{pattern}}", + "eventPatternCount": "≥{{count}} × {{pattern}} en {{window}} min", + "inactivity": "Sin actividad de sesión durante {{minutes}} min", + "statusDuration": "Agente bloqueado en {{status}} durante {{minutes}} min", + "tokenThreshold": "Tokens de sesión superan {{tokens}}" + }, + "rules": { + "title": "Reglas de alerta", + "add": "Añadir regla", + "cancel": "Cancelar", + "create": "Crear regla", + "saving": "Guardando…", + "empty": "Sin reglas de alerta aún. Añade una para comenzar a monitorear agentes bloqueados, ráfagas de errores, sesiones inactivas o picos de tokens.", + "enabled": "Habilitada", + "disabled": "Deshabilitada", + "enable": "Habilitar regla", + "disable": "Deshabilitar regla", + "delete": "Eliminar regla", + "confirmDelete": "¿Eliminar la regla \"{{name}}\" y su historial de alertas?", + "cooldown": "{{seconds}}s de tiempo de espera", + "form": { + "name": "Nombre de la regla", + "namePlaceholder": "p. ej., Ráfaga de errores", + "type": "Tipo de regla", + "eventType": "Tipo de evento (exacto)", + "toolName": "Nombre de herramienta (exacto)", + "summaryContains": "El resumen contiene", + "count": "Conteo de activación", + "windowMinutes": "Ventana (minutos)", + "agentStatus": "Estado del agente", + "minutes": "Minutos", + "totalTokens": "Total de tokens", + "cooldown": "Tiempo de espera (segundos)" + }, + "deleteTitle": "¿Eliminar regla de alerta?", + "help": { + "name": "Una etiqueta para esta regla. Aparece en el feed de alertas y se incluye en los payloads de webhook (rule_name). p. ej., 'Errores Bash repetidos'.", + "type": "Qué observa esta regla. event_pattern coincide con el flujo de eventos en vivo; inactivity = una sesión activa queda en silencio; status_duration = un agente está bloqueado en un estado; token_threshold = el uso de tokens de una sesión cruza un límite.", + "eventType": "El evento hook de Claude Code a coincidir. Dejar en blanco para coincidir con cualquier tipo de evento. Se compara de forma exacta (sensible a mayúsculas).", + "toolName": "La herramienta que invocó el agente (en eventos PreToolUse / PostToolUse). Dejar en blanco para coincidir con cualquier herramienta. Se compara de forma exacta.", + "summaryContains": "Coincidencia de subcadena insensible a mayúsculas con el texto de resumen del evento. Útil para detectar errores o frases específicas. Dejar en blanco para omitir.", + "count": "Cuántos eventos coincidentes deben ocurrir antes de que se dispare la alerta. 1 = disparar en la primera coincidencia. Establecer por encima de 1 para detectar ráfagas (p. ej., errores repetidos).", + "window": "La ventana de retroceso continua para el conteo. p. ej., conteo 5 + ventana 2 significa '5 eventos coincidentes dentro de cualquier intervalo de 2 minutos'.", + "status": "Qué estado del agente observar. 'working' detecta agentes bloqueados a mitad de tarea; 'waiting' detecta agentes bloqueados en entrada/permiso.", + "minutesInactivity": "Disparar cuando una sesión activa no ha tenido eventos durante este número de minutos (una sesión bloqueada u olvidada).", + "minutesStatus": "Disparar cuando un agente permanece en el estado seleccionado sin actividad durante este número de minutos (un agente bloqueado).", + "totalTokens": "Disparar cuando los tokens acumulados de una sesión (entrada + salida + lectura de caché + escritura de caché) superan este número. p. ej., 1000000 = 1M tokens.", + "cooldown": "Segundos mínimos entre alertas repetidas para la misma regla + sesión + agente. Evita duplicados ruidosos. Por defecto 300 (5 min); 0 = sin tiempo de espera." + } + }, + "feed": { + "title": "Feed de alertas", + "unackedCount": "{{count}} sin reconocer", + "unackedOnly": "Solo sin reconocer", + "ack": "Reconocer", + "viewSession": "Ver sesión", + "loadMore": "Cargar más ({{shown}} de {{total}})", + "emptyTitle": "Sin alertas", + "emptyDescription": "Las alertas disparadas por tus reglas aparecerán aquí en tiempo real.", + "emptyUnacked": "Todo está reconocido. Las nuevas alertas aparecerán aquí cuando se disparen." + } +} diff --git a/client/src/i18n/locales/es/analytics.json b/client/src/i18n/locales/es/analytics.json new file mode 100644 index 00000000..d5abdabf --- /dev/null +++ b/client/src/i18n/locales/es/analytics.json @@ -0,0 +1,54 @@ +{ + "title": "Analíticas", + "subtitle": "Monitoreo y analíticas en tiempo real para sesiones de Claude Code", + "export": "Exportar", + "totalSessions": "Total de Sesiones", + "totalAgents": "Total de Agentes", + "totalTokens": "Total de Tokens", + "totalCost": "Costo Total", + "totalEvents": "Total de Eventos", + "cacheHitRate": "% de tasa de aciertos de caché", + "perSession": " por sesión", + "noDataCost": "Sin datos", + "eventCountLabel_one": "{{count}} evento", + "eventCountLabel_other": "{{count}} eventos", + "tabs": { + "tokenAnalytics": "Analíticas de Tokens", + "costAnalytics": "Analíticas de Costo", + "workflowIntelligence": "Inteligencia de Flujos", + "productivityAnalytics": "Analíticas de Productividad" + }, + "eventActivity": "Actividad de Eventos - Últimas 52 Semanas", + "last30Days": "Últimos 30 Días", + "dailyEventCount": "Conteo diario de eventos", + "peakDay": "Día pico", + "total30d": "Total (30 días)", + "tokenDistribution": "Distribución de Tokens", + "tokenMix": "Mezcla de Tokens", + "cacheEfficiency": "Eficiencia de caché", + "tokenBreakdown": "Desglose de Tokens", + "tokenInfo": "Datos de tokens capturados de los eventos Stop de Claude Code.", + "costByModel": "Costo por Modelo", + "dailyCostTrends": "Tendencias de Costo Diario", + "costByWeekday": "Costo por Día de la Semana", + "costPerDay": "Costo por día", + "peakCostDay": "Día de mayor costo", + "totalCost30d": "Costo total (30 días)", + "noDailyCostData": "Sin datos de costo diario aún.", + "noCostData": "Sin datos de costo aún.", + "subagentTypes": "Tipos de Subagentes", + "noSubagentData": "Sin datos de subagentes aún.", + "agentStatus": "Estado del Agente", + "totalAgentsLabel": "Total de agentes", + "eventTypes": "Tipos de Eventos", + "noEventData": "Sin datos de eventos aún.", + "toolUsage": "Uso de Herramientas", + "noToolData": "Sin datos de uso de herramientas aún.", + "sessionOutcomes": "Resultados de Sesiones", + "totalSessionsLabel": "Total de sesiones", + "dailySessionTrends": "Tendencias de Sesiones Diarias", + "noSessionTrendData": "Sin datos de tendencias de sesiones aún.", + "last7Days": "Últimos 7 días", + "less": "Menos", + "more": "Más" +} diff --git a/client/src/i18n/locales/es/ccConfig.json b/client/src/i18n/locales/es/ccConfig.json new file mode 100644 index 00000000..1ce9d612 --- /dev/null +++ b/client/src/i18n/locales/es/ccConfig.json @@ -0,0 +1,264 @@ +{ + "title": "Explorador de configuración de Claude", + "subtitle": "Tu configuración de Claude Code de un vistazo: complementos, habilidades, subagentes, servidores MCP, ganchos y ajustes.", + "refresh": "Actualizar", + "refreshing": "Actualizando…", + "lastUpdated": "Última actualización {{time}}", + "loadError": "Error al cargar: {{message}}", + "scope": { + "all": "Todos los ámbitos", + "user": "Usuario", + "project": "Proyecto", + "projectLocal": "Proyecto (local)", + "home": "Inicio" + }, + "tabs": { + "overview": "Resumen", + "skills": "Habilidades", + "agents": "Subagentes", + "commands": "Comandos de barra", + "outputStyles": "Estilos de salida", + "plugins": "Complementos", + "marketplaces": "Mercados", + "mcp": "Servidores MCP", + "hooks": "Ganchos", + "keybindings": "Atajos de teclado", + "settings": "Configuración", + "memory": "Memoria" + }, + "overview": { + "rootsTitle": "Raíces", + "claudeHome": "Inicio de Claude", + "projectClaudeDir": "Proyecto .claude", + "projectRoot": "Raíz del proyecto", + "claudeJson": "claude.json", + "summary": "Resumen rápido", + "user": "usuario", + "project": "proyecto", + "items": "elementos" + }, + "common": { + "search": "Buscar por nombre…", + "clearSearch": "Limpiar búsqueda", + "empty": "Nada aquí aún.", + "viewSource": "Ver fuente", + "close": "Cerrar", + "copyPath": "Copiar ruta", + "copied": "Copiado", + "truncated": "(truncado para vista previa)", + "size": "Tamaño", + "modified": "Modificado", + "scopeLabel": "Ámbito", + "noFrontmatter": "Sin frontmatter", + "redactedNotice": "Los valores que coincidan con /token|secret|password|key|auth/i son ocultados en el servidor." + }, + "skills": { + "name": "Nombre", + "description": "Descripción" + }, + "agents": { + "name": "Nombre", + "model": "Modelo", + "tools": "Herramientas" + }, + "plugins": { + "manifest": "Manifiesto", + "marketplace": "Mercado", + "version": "Versión", + "installedAt": "Instalado", + "lastUpdated": "Actualizado", + "installPath": "Ruta de instalación", + "missing": "Ruta de instalación faltante", + "manifestMissing": "No se encontró installed_plugins.json en {{path}}", + "enabled": "Habilitado", + "disabled": "Deshabilitado", + "contributes": "Contribuye", + "skills_one": "{{count}} habilidad", + "skills_other": "{{count}} habilidades", + "agents_one": "{{count}} agente", + "agents_other": "{{count}} agentes", + "commands_one": "{{count}} comando", + "commands_other": "{{count}} comandos", + "outputStyles_one": "{{count}} estilo de salida", + "outputStyles_other": "{{count}} estilos de salida", + "hooks_one": "{{count}} script de gancho", + "hooks_other": "{{count}} scripts de gancho", + "author": "Autor", + "homepage": "Página de inicio", + "license": "Licencia", + "description": "Descripción" + }, + "marketplaces": { + "manifest": "Manifiesto de mercados conocidos", + "noMarketplaces": "No hay mercados registrados.", + "source": "Fuente", + "lastUpdated": "Última sincronización", + "pluginCount": "Complementos", + "owner": "Propietario", + "installLocation": "Ruta de instalación", + "addCmd": "claude plugin marketplace add " + }, + "keybindings": { + "file": "Archivo fuente", + "missing": "No se encontró keybindings.json en {{path}}", + "context": "Contexto", + "key": "Tecla", + "action": "Acción", + "docsLink": "Ver documentación de atajos", + "contextPlaceholder": "Contexto (p. ej., Global, Chat)", + "addContext": "Añadir contexto", + "removeContext": "Eliminar contexto", + "addBinding": "Añadir atajo", + "removeBinding": "Eliminar atajo", + "errContext": "Cada contexto necesita un nombre.", + "errDupContext": "Contexto duplicado: {{context}}", + "errEmpty": "Cada atajo en \"{{context}}\" necesita tanto una tecla como una acción.", + "errDupKey": "Tecla duplicada \"{{key}}\" en el contexto \"{{context}}\"." + }, + "statusline": { + "title": "Barra de estado", + "configured": "Comando de barra de estado configurado", + "scripts": "Scripts de barra de estado encontrados en CLAUDE_HOME", + "noStatusline": "No hay barra de estado configurada." + }, + "hookScripts": { + "title": "Scripts ~/.claude/hooks/", + "subtitle": "Scripts auxiliares referenciados por tus comandos de gancho. Se ejecutan cuando settings.json `hooks..hooks[].command` los invoca.", + "empty": "No hay scripts en ~/.claude/hooks/." + }, + "mcp": { + "userScope": "Servidores de ámbito de usuario", + "projectScope": "Servidores de ámbito de proyecto", + "command": "Comando", + "args": "Argumentos", + "env": "Nombres de variables de entorno", + "url": "URL", + "headers": "Nombres de cabeceras", + "kind": "Tipo", + "source": "Fuente", + "noServers": "No se encontraron servidores MCP." + }, + "hooks": { + "noHooks": "No hay ganchos configurados.", + "matcher": "Patrón", + "command": "Comando", + "type": "Tipo", + "timeout": "Tiempo de espera", + "fileMissing": "(no hay archivo de configuración en este ámbito)" + }, + "settings": { + "fileMissing": "(no hay archivo de configuración en este ámbito)" + }, + "memory": { + "userScope": "Memoria de usuario", + "projectScope": "Memoria de proyecto", + "missing": "No se encontró CLAUDE.md.", + "autoTitle": "Almacén de memoria del proyecto", + "autoSubtitle": "Memoria basada en archivos por proyecto en ~/.claude/projects//memory/ — un índice MEMORY.md más un archivo por hecho recordado. Solo lectura aquí.", + "noMatches": "Ningún archivo de memoria coincide con tu búsqueda.", + "indexFiles": "Índice", + "jumpTo": "Ir al archivo", + "fileCount_one": "{{count}} archivo", + "fileCount_other": "{{count}} archivos", + "factFiles_one": "{{count}} hecho", + "factFiles_other": "{{count}} hechos", + "newFile": "Nuevo archivo", + "newFileTitle": "Nuevo archivo de memoria en {{project}}", + "namePlaceholder": "p. ej., mi_hecho.md", + "nameHelp": "Nombre de archivo terminado en .md (.md se añade si lo omites).", + "projectLabel": "Proyecto", + "projectHelp": "Creado en el directorio de memoria de este proyecto." + }, + "edit": { + "newButton": "Nuevo", + "editButton": "Editar", + "deleteButton": "Eliminar", + "save": "Guardar", + "cancel": "Cancelar", + "saving": "Guardando…", + "deleting": "Eliminando…", + "newTitle": "Crear nuevo {{type}}", + "editTitle": "Editar {{name}}", + "namePlaceholder": "nombre (kebab-case, sin espacios)", + "nameLabel": "Nombre", + "nameHelp": "Letras, dígitos, punto, guión, guión bajo. Máx 64 caracteres.", + "contentLabel": "Contenido", + "scopePicker": "Ámbito", + "writeError": "Error al guardar: {{message}}", + "deleteError": "Error al eliminar: {{message}}", + "saveSuccess": "Guardado · copia de seguridad en {{path}}", + "saveSuccessNew": "Creado.", + "deleteSuccess": "Eliminado · copia de seguridad en {{path}}", + "confirmDelete": "¿Eliminar este elemento?", + "confirmDeleteBody": "Esto moverá el archivo (o carpeta de habilidad, incluidos los activos empaquetados) a una copia de seguridad con marca de tiempo antes de eliminarlo. La copia de seguridad vive fuera de los directorios que Claude Code escanea, por lo que la entrada desaparecerá de tu CLI.", + "confirmDeletePath": "Ruta: {{path}}", + "confirmDeleteAction": "Sí, hacer copia de seguridad y eliminar", + "templates": { + "skills": "---\nname: my-skill\ndescription: Descripción de una línea (mostrada cuando Claude elige la habilidad)\n---\n\nCuerpo: qué hace la habilidad, cuándo usarla y ejemplos.\n", + "agents": "---\nname: my-agent\ndescription: Cuándo invocar este subagente\ntools: Read, Grep\nmodel: sonnet\n---\n\nPrompt del sistema para el subagente.\n", + "commands": "---\ndescription: Descripción de una línea mostrada en el menú de barra\n---\n\nQué hace /mi-comando.\n", + "output-styles": "---\nname: my-style\ndescription: Descripción del estilo de salida\n---\n\nInstrucciones de estilo.\n", + "memory": "# Memoria del proyecto\n\nClaude lee esto al inicio de la sesión.\n", + "auto-memory": "---\nname: my-fact\ndescription: Resumen de una línea del hecho recordado\nmetadata:\n type: feedback\n---\n\nEl hecho a recordar.\n" + } + }, + "backups": { + "title": "Copias de seguridad", + "empty": "Sin copias de seguridad aún - cada edición o eliminación crea una copia con marca de tiempo que aparece aquí.", + "viewLink": "Mostrar historial de copias de seguridad", + "openButton": "Copias de seguridad", + "subtitle": "Cada guardado / eliminación en el editor escribe una copia aquí primero. Las carpetas de copia de seguridad viven fuera de los directorios que Claude Code escanea, por lo que no reaparecen como fantasmas en tu CLI.", + "restoreHint": "Restaura renombrando la copia de seguridad de vuelta a su lugar:", + "size": "Tamaño", + "created": "Creado", + "type": "Tipo", + "scopeLabel": "Ámbito", + "filterAll": "Todos los tipos" + }, + "explain": { + "hooks": { + "title": "Los ganchos son de solo lectura aquí a propósito", + "body": "Los ganchos viven en el bloque `hooks` de los archivos `settings.json` que Claude Code escribe constantemente. Editarlos desde el panel competiría con la CLI en vivo y podría romper silenciosamente la ingesta propia del panel (la entrada `hook-handler.js` abajo).", + "howTo": "Edítalos tú mismo con uno de:", + "cmd1": "claude config /hooks", + "cmd1Note": "Editor interactivo de ganchos dentro de Claude Code", + "cmd2": "$EDITOR ~/.claude/settings.json", + "cmd2Note": "Editar a mano el bloque de ganchos de nivel de usuario", + "cmd3": "$EDITOR .claude/settings.json", + "cmd3Note": "Editar a mano el bloque de ganchos de nivel de proyecto" + }, + "settings": { + "title": "La configuración es de solo lectura aquí a propósito", + "body": "Estos archivos JSON son reescritos por la CLI `claude` en vivo en cada cambio de modelo, cambio de tema, habilitación de complemento, etc. Una escritura del panel competiría con la CLI y perdería estado.", + "howTo": "Edita la configuración a través del propio Claude Code:", + "cmd1": "claude config set ", + "cmd1Note": "Establecer una clave individual de forma segura", + "cmd2": "/config", + "cmd2Note": "Abrir la UI de configuración interactiva dentro de la CLI", + "cmd3": "$EDITOR ~/.claude/settings.json", + "cmd3Note": "Editar a mano (solo cuando no haya ningún proceso `claude` en ejecución)" + }, + "plugins": { + "title": "Los complementos son gestionados por la CLI", + "body": "Los complementos son paquetes con su propio registro: `installed_plugins.json` más rutas de instalación bajo `plugins/cache/`. El panel los lee pero delega la instalación y desinstalación a `claude plugin …` para que el registro se mantenga consistente.", + "install": "Instalar un complemento:", + "installCmd": "claude plugin install /", + "uninstall": "Desinstalar este complemento:", + "uninstallButton": "Copiar comando de desinstalación" + }, + "mcp": { + "title": "Los servidores MCP son gestionados por la CLI", + "body": "La configuración del servidor MCP vive dentro de `~/.claude.json`, el mismo archivo que la CLI en vivo escribe constantemente. Las escrituras concurrentes desde el panel corromperían el estado del proyecto, por lo que el flujo de añadir/eliminar pasa por el propio Claude Code.", + "list": "Listar servidores configurados:", + "listCmd": "claude mcp list", + "add": "Añadir un servidor:", + "addCmd": "claude mcp add [args…]", + "remove": "Eliminar este servidor:", + "removeButton": "Copiar comando de eliminación" + } + }, + "snippet": { + "copy": "Copiar", + "copied": "Copiado" + } +} diff --git a/client/src/i18n/locales/es/common.json b/client/src/i18n/locales/es/common.json new file mode 100644 index 00000000..5478e9ea --- /dev/null +++ b/client/src/i18n/locales/es/common.json @@ -0,0 +1,192 @@ +{ + "refresh": "Actualizar", + "retry": "Reintentar", + "cancel": "Cancelar", + "export": "Exportar", + "loading": "Cargando...", + "noData": "Sin datos", + "total": "Total", + "active": "activo", + "total_lower": "total", + "subagent": "subagente", + "subagents": "subagentes", + "subagent_label_one": "{{count}} subagente", + "subagent_label_other": "{{count}} subagentes", + "events": "eventos", + "event": "evento", + "sessions": "sesiones", + "session": "sesión", + "agents": "agentes", + "agent": "agente", + "live": "En vivo", + "offline": "Sin conexión", + "running": "ejecutando", + "dashboardRun": "Ejecutar", + "days": "días", + "hours": "horas", + "updated": "Actualizado ", + "lastUpdated": "Última actualización: ", + "showMore": "Mostrar más ({{count}} restantes)", + "plusMore": "+{{count}} más", + "ofSessions": "% de las sesiones", + "save": "Guardar", + "edit": "Editar", + "delete": "Eliminar", + "actions": "Acciones", + "close": "Cerrar", + "unexpectedError": "Error inesperado", + "depth": "Profundidad", + "type": "Tipo", + "statusLabel": "Estado", + "status": { + "working": "Trabajando", + "waiting": "En espera", + "completed": "Completado", + "error": "Error", + "active": "Activo", + "abandoned": "Abandonado" + }, + "awaitingReason": { + "notification": { + "label": "Necesita entrada", + "desc": "Bloqueado por un aviso de permiso o una solicitud de entrada — Claude no puede continuar hasta que respondas." + }, + "stop": { + "label": "Turno terminado", + "desc": "Claude terminó su respuesta; la sesión está inactiva hasta que envíes la siguiente instrucción." + }, + "session_start": { + "label": "Esperando una instrucción", + "desc": "La sesión acaba de comenzar o reanudarse y está en una instrucción vacía; aún no se ha solicitado nada." + }, + "interrupted": { + "label": "Interrumpido", + "desc": "El último turno fue interrumpido (Esc o un hook recuperado) — Claude está esperando dirección." + } + }, + "time": { + "justNow": "ahora mismo", + "mAgo": "hace {{count}}m", + "hAgo": "hace {{count}}h", + "dAgo": "hace {{count}}d" + }, + "pagination": { + "previous": "Anterior", + "next": "Siguiente", + "showing": "Mostrando {{from}}-{{to}} de {{total}}" + }, + "token": { + "input": "Entrada", + "output": "Salida", + "cacheRead": "Lectura de Caché", + "cacheWrite": "Escritura de Caché", + "totalTokens": "Total de tokens" + }, + "cost": { + "model": "Modelo", + "cost": "Costo", + "totalCost": "Costo Total", + "totalEstimatedCost": "Costo Total Estimado" + }, + "duration": { + "h_m": "{{h}}h {{m}}m", + "m_s": "{{m}}m {{s}}s", + "s": "{{s}}s" + }, + "eventDetail": { + "summary": "Resumen", + "seeDetailsBelow": "Consulta más abajo los detalles completos en {{fields}}", + "eventId": "ID de Evento", + "recordedAt": "Registrado en", + "session": "Sesión", + "sessionId": "ID de Sesión", + "agentId": "ID de Agente", + "agent": "Agente", + "cwd": "Directorio de trabajo", + "permissionMode": "Modo de permiso", + "toolUseId": "ID de Uso de Herramienta", + "toolName": "Herramienta", + "toolInput": "Entrada de Herramienta", + "toolResponse": "Respuesta de Herramienta", + "isError": "Error", + "transcriptPath": "Ruta de Transcripción", + "agentTranscriptPath": "Ruta de Transcripción del Subagente", + "hookEventName": "Nombre del evento de gancho", + "stopReason": "Razón de Parada", + "stopHookActive": "Gancho de parada activo", + "subagentType": "Tipo de Subagente", + "agentType": "Tipo de Agente", + "notificationType": "Tipo de Notificación", + "message": "Mensaje", + "prompt": "Instrucción", + "model": "Modelo", + "reason": "Razón", + "source": "Fuente", + "imported": "Importado", + "type": "Tipo", + "timestamp": "Marca de tiempo", + "uuid": "UUID", + "durationMs": "Duración (ms)", + "compactionNumber": "Número de Compresión", + "totalCompactions": "Total de Compresiones", + "lastAssistantMessage": "Último Mensaje del Asistente", + "rawPayload": "Carga útil sin procesar", + "copy": "Copiar", + "copied": "Copiado", + "noPayload": "No se capturó payload para este evento.", + "viewDetails": "Ver detalles", + "expand": "Expandir evento", + "collapse": "Colapsar evento" + }, + "eventFilters": { + "searchPlaceholder": "Buscar resumen, herramienta, payload...", + "status": "Estado", + "eventType": "Tipo de evento", + "toolName": "Herramienta", + "agentId": "Agente", + "sessionId": "Sesión", + "from": "Desde", + "to": "Hasta", + "clearAll": "Limpiar filtros", + "noOptions": "Sin opciones", + "showing": "Mostrando {{shown}} de {{total}}", + "loadMore": "Cargar más", + "loading": "Cargando...", + "noResults": "Ningún evento coincide con los filtros actuales", + "grouped": "Agrupar por llamada de herramienta", + "flat": "Lista plana", + "groupEventCount_one": "{{count}} evento", + "groupEventCount_other": "{{count}} eventos", + "help": { + "toggle": "Ayuda", + "title": "Acerca de eventos, filtros y agrupación", + "subtitle": "Desbloquea información más profunda: insignias, ciclos de vida y mecánicas de filtros explicados.", + "valuesTitle": "Qué acepta cada filtro", + "valueStatusDesc": "Atajo preestablecido que se expande a valores de event_type (En ejecución → PreToolUse, Completado → Stop/SubagentStop/Compaction, ...).", + "valueEventTypeDesc": "Cadenas de event_type crudas de la BD. Obtenidas de /api/events/facets.", + "valueToolNameDesc": "Valores de tool_name actualmente en la BD (Bash, Edit, Read, Grep, herramientas mcp__...). Obtenidos de /api/events/facets.", + "valueAgentIdDesc": "UUIDs completos de agentes (principal + subagentes). Selecciona uno o más para acotar a agentes específicos.", + "valueSessionIdDesc": "UUIDs de sesión. Normalmente navegarías a /sessions/:id en su lugar, pero esto te permite intersectar múltiples sesiones.", + "valueSearchDesc": "Coincidencia de subcadena en resumen, tool_name y el payload JSON raw. Rebotado 300ms.", + "valueDateRangeDesc": "Límites inferior/superior de fecha y hora ISO en el created_at del evento.", + "statusesTitle": "Insignias de estado", + "statusesIntro": "El estado se deriva de event_type. Es lo que ves en cada fila.", + "statusWorkingDesc": "El agente inició una llamada de herramienta (PreToolUse). La herramienta está a punto de ejecutarse.", + "statusConnectedDesc": "La llamada de herramienta se completó y devolvió un resultado (PostToolUse).", + "statusCompletedDesc": "Límite de turno o ciclo de vida (Stop, SubagentStop, Compaction).", + "statusErrorDesc": "Se registró un error (error, APIError).", + "statusIdleDesc": "Ciclo de vida o metadatos (Notification, TurnDuration, SessionStart, SessionEnd).", + "lifecycleTitle": "Ciclo de vida del evento", + "lifecycleDesc": "Una llamada de herramienta típica emite dos eventos compartiendo el mismo tool_use_id:", + "lifecycleFlow": "PreToolUse (En ejecución) → PostToolUse (Conectado) → ... → Stop (Completado)", + "filtersTitle": "Cómo funcionan los filtros", + "filterTip1": "Los filtros se componen con AND entre categorías. Dentro de una categoría, la selección múltiple es OR.", + "filterTip2": "Estado es un atajo que se expande a valores de event_type (En ejecución → PreToolUse, Completado → Stop/SubagentStop/Compaction, ...). Estado + tipo de evento se combinan como OR en event_type.", + "filterTipGrouping": "Consejo de agrupación: una fila agrupada necesita ambos eventos Pre y Post. Si filtras por estado, elige En ejecución + Conectado para mantener los pares intactos; de lo contrario, un grupo solo mostrará la mitad de la llamada.", + "filterTip3": "La búsqueda de texto coincide con el resumen, tool_name y el payload raw (columna data).", + "filterTip4": "El rango de fechas se aplica al created_at de cada evento." + } + }, + "examples": "Ejemplos", + "help": "Ayuda" +} diff --git a/client/src/i18n/locales/es/dashboard.json b/client/src/i18n/locales/es/dashboard.json new file mode 100644 index 00000000..f0fd0ee7 --- /dev/null +++ b/client/src/i18n/locales/es/dashboard.json @@ -0,0 +1,22 @@ +{ + "title": "Panel", + "subtitle": "Resumen en tiempo real de la actividad de los agentes de Claude Code", + "totalSessions": "Total de Sesiones", + "activeAgents": "Agentes Activos", + "activeSubagents": "Subagentes Activos", + "eventsToday": "Eventos Hoy", + "totalEvents": "Total de Eventos", + "totalCost": "Costo Total", + "viewBoard": "Ver Tablero", + "viewAll": "Ver Todo", + "activeAgentsSection": "Agentes Activos", + "recentActivity": "Actividad Reciente", + "noAgents": "Sin agentes activos", + "noAgentsDesc": "Los agentes aparecerán aquí cuando haya una sesión de Claude Code en ejecución.", + "noActivity": "Sin actividad aún", + "noActivityDesc": "Los eventos de las sesiones de Claude Code se transmitirán aquí en tiempo real.", + "failedConnect": "No se pudo conectar al servidor", + "failedLoad": "No se pudieron cargar los datos", + "activeTrend": " activo", + "totalTrend": " en sesiones activas" +} diff --git a/client/src/i18n/locales/es/errors.json b/client/src/i18n/locales/es/errors.json new file mode 100644 index 00000000..afff9792 --- /dev/null +++ b/client/src/i18n/locales/es/errors.json @@ -0,0 +1,31 @@ +{ + "notFound": { + "code": "404", + "title": "Página no encontrada", + "description": "La ruta solicitada no existe. Usa la navegación para volver a una página válida.", + "goDashboard": "Ir al Panel", + "goBack": "Volver" + }, + "notifications": { + "newSession": "Nueva Sesión", + "sessionDefault": "Sesión ", + "sessionError": "Error de Sesión", + "subagentSpawned": "Subagente Iniciado", + "finishedResponding": "Claude Terminó de Responder", + "readyForInput": "Listo para entrada", + "sessionCompleted": "Sesión Completada", + "sessionClosed": "Sesión cerrada", + "defaultTitle": "Claude Code", + "defaultBody": "Notificación" + }, + "toolLegend": { + "read": "Leer", + "write": "Escribir", + "edit": "Editar", + "bash": "Bash", + "grep": "Grep", + "glob": "Glob", + "agent": "Agent", + "other": "Otro" + } +} diff --git a/client/src/i18n/locales/es/kanban.json b/client/src/i18n/locales/es/kanban.json new file mode 100644 index 00000000..39f2c4dd --- /dev/null +++ b/client/src/i18n/locales/es/kanban.json @@ -0,0 +1,45 @@ +{ + "title": "Tablero Kanban", + "subtitle": "Vista Kanban de todos los agentes por estado", + "subtitleSessions": "Vista Kanban de todas las sesiones por estado", + "viewToggle": { + "agents": "Agentes", + "sessions": "Sesiones" + }, + "noAgents": "Sin agentes rastreados aún", + "noAgentsDesc": "Inicia una sesión de Claude Code con los hooks instalados para ver los agentes aquí.", + "agentCount": "{{count}} agente rastreado", + "agentCount_plural": "{{count}} agentes rastreados", + "noAgentsInColumn": "Sin agentes", + "noSessions": "Sin sesiones rastreadas aún", + "noSessionsDesc": "Inicia una sesión de Claude Code con los hooks instalados para ver las sesiones aquí.", + "sessionCount": "{{count}} sesión rastreada", + "sessionCount_plural": "{{count}} sesiones rastreadas", + "noSessionsInColumn": "Sin sesiones", + "ran": "ejecutó ", + "running": "ejecutando ", + "session": { + "anonymous": "Sesión sin título", + "agentSummary_one": "{{count}} agente", + "agentSummary_other": "{{count}} agentes", + "subagentSummary_one": "{{count}} subagente", + "subagentSummary_other": "{{count}} subagentes", + "turnSummary_one": "{{count}} turno", + "turnSummary_other": "{{count}} turnos" + }, + "tooltip": { + "agent": { + "working": "El agente está ejecutando activamente una llamada de herramienta ahora mismo.\n\nEntra en PreToolUse o UserPromptSubmit, sale en Stop (turno finalizado).", + "waiting": "El agente terminó su turno y está bloqueado por el humano — o bien Claude está esperando el siguiente mensaje del usuario o ha solicitado permiso para usar una herramienta.\n\nSe limpia en el siguiente PreToolUse / PostToolUse, o cuando la sesión termina.", + "completed": "El agente ha finalizado completamente para esta sesión — normalmente porque se disparó SessionEnd o, para subagentes, se procesó SubagentStop.\n\nNo se registrará más actividad para este agente.", + "error": "El agente registró un error y no continuará. Para agentes principales, esto proviene de un Stop con stop_reason=error; para subagentes, de una ejecución fallida." + }, + "session": { + "active": "La sesión está a mitad de turno — Claude está ejecutándose actualmente y el usuario no bloquea nada. Breve por naturaleza: una sesión pasa por Activa durante las llamadas de herramientas y vuelve a Espera al final del turno.", + "waiting": "La sesión está esperando al usuario. O bien Claude terminó su turno (más común) o ha presentado un aviso de permiso y está bloqueado hasta que el humano responda.\n\nBusca aquí las sesiones a las que debes responder.", + "completed": "La sesión se ha cerrado completamente — se disparó SessionEnd (CLI salió limpiamente) o el usuario la cerró explícitamente.\n\nTodos los agentes en esta sesión también están completados.", + "error": "La sesión terminó con un error — Claude devolvió stop_reason=error, ocurrió un fallo irrecuperable, o un error de API upstream terminó la ejecución.", + "abandoned": "La sesión quedó sin actividad sin un SessionEnd limpio. Marcada como abandonada después de 5+ minutos sin actividad (huérfana de /resume, caída de red, o la CLI fue terminada). Distinta de Completada: nunca vimos una señal de salida real." + } + } +} diff --git a/client/src/i18n/locales/es/nav.json b/client/src/i18n/locales/es/nav.json new file mode 100644 index 00000000..a4f2c6bd --- /dev/null +++ b/client/src/i18n/locales/es/nav.json @@ -0,0 +1,71 @@ +{ + "brand": "Agent Dashboard", + "brandSub": "Claude Code Monitor", + "dashboard": "Panel", + "agentBoard": "Tablero Kanban", + "sessions": "Sesiones", + "activityFeed": "Feed de Actividad", + "analytics": "Analíticas", + "workflows": "Flujos", + "alerts": "Alertas", + "ccConfig": "Config de Claude", + "run": "Ejecutar Claude", + "settings": "Configuración", + "language": "Idioma", + "github": "GitHub", + "website": "Sitio web", + "notFound": "No encontrado", + "skipToContent": "Saltar al contenido", + "expand": "Expandir barra lateral", + "collapse": "Colapsar barra lateral", + "collapseShort": "Colapsar", + "scrollUp": "Desplazar navegación hacia arriba", + "scrollDown": "Desplazar navegación hacia abajo", + "live": "En vivo", + "disconnected": "Desconectado", + "connectionDetails": "Detalles de conexión", + "connection": "Conexión", + "wsEndpoint": "WebSocket", + "connectionUptime": "Conectado", + "notConnected": "Sin conexión", + "eventsReceived": "Eventos recibidos", + "eventsTotal": "Total", + "eventsLastMin": "Últimos 60s", + "peakRate": "Pico", + "unitEvents": "eventos", + "unitPerSec": "eventos/s", + "throughput60s": "Rendimiento · últimos 60s", + "avg": "prom", + "topEventTypes": "Principales tipos de eventos", + "recentActivity": "Actividad reciente", + "statsPersisted": "Las estadísticas persisten entre recargas", + "resetStats": "Restablecer", + "lastEvent": "Último evento", + "noEventsYet": "Sin eventos aún", + "justNow": "ahora mismo", + "secondsAgo": "hace {{count}}s", + "minutesAgo": "hace {{count}}m", + "hoursAgo": "hace {{count}}h", + "daysAgo": "hace {{count}}d", + "close": "Cerrar", + "checkForUpdates": "Buscar actualizaciones", + "checkingForUpdates": "Buscando actualizaciones...", + "updateAvailable": "Actualización disponible", + "upToDate": "Al día", + "checkFailed": "Error al buscar actualizaciones", + "switchLanguage": "Cambiar a {{language}}", + "languageNames": { + "en": "Inglés", + "zh": "Chino", + "vi": "Vietnamita", + "ko": "Coreano", + "es": "Español" + }, + "languageShort": { + "en": "EN", + "zh": "中文", + "vi": "VI", + "ko": "한국어", + "es": "ES" + } +} diff --git a/client/src/i18n/locales/es/run.json b/client/src/i18n/locales/es/run.json new file mode 100644 index 00000000..88260f32 --- /dev/null +++ b/client/src/i18n/locales/es/run.json @@ -0,0 +1,161 @@ +{ + "title": "Ejecutar Claude", + "subtitle": "Inicia una sesión de Claude Code directamente desde el panel. Salida en streaming en vivo, conversación en múltiples turnos y las mismas analíticas impulsadas por hooks que tus sesiones de terminal.", + "mode": { + "label": "Modo", + "conversation": "Conversación", + "conversationHint": "Múltiples turnos — sigue escribiendo mientras el agente trabaja.", + "headless": "Único", + "headlessHint": "Una sola instrucción, una sola respuesta. La entrada estándar se cierra tras el inicio." + }, + "fields": { + "prompt": "Instrucción", + "promptPlaceholder": "Pregúntale cualquier cosa a Claude…", + "cwd": "Directorio de trabajo", + "cwdHint": "Ruta absoluta. Por defecto el cwd del propio panel.", + "cwdPlaceholder": "Escribe para buscar o pega una ruta absoluta…", + "cwdGroups": { + "dashboard": "Servidor del panel", + "home": "Inicio", + "recent": "Recientes - usados por Claude Code" + }, + "cwdNoMatches": "Sin coincidencias. Escribe una ruta absoluta para usarla directamente.", + "model": "Modelo", + "modelInheritLabel": "Heredar de configuración", + "modelCustom": "Personalizado…", + "modelCustomPlaceholder": "id del modelo (p. ej., claude-opus-4-7-20260101)", + "permissionMode": "Modo de permiso", + "permissionAcceptEdits": "acceptEdits (recomendado)", + "permissionDefault": "default (prompts interactivos - las sesiones pueden bloquearse sin cabeza)", + "permissionPlan": "plan (planificación de solo lectura)", + "permissionBypass": "bypassPermissions (PELIGRO - permite todo sin preguntar)", + "effort": "Esfuerzo de razonamiento", + "effortHint": "Controla cuánto razona el modelo antes de responder. Mayor = más tokens de pensamiento, más lento, más profundo. Vacío hereda el valor predeterminado del modelo." + }, + "actions": { + "start": "Ejecutar", + "starting": "Iniciando…", + "send": "Enviar", + "sending": "Enviando…", + "stop": "Detener", + "stopping": "Deteniendo…", + "newRun": "Nueva ejecución", + "viewSession": "Ver sesión" + }, + "status": { + "idle": "Inactivo", + "spawning": "Iniciando…", + "running": "Ejecutando", + "completed": "Completado", + "error": "Error", + "killed": "Terminado", + "abandoned": "Abandonado" + }, + "binary": { + "missing": "La CLI `claude` no está en tu PATH. Instala Claude Code o configura el PATH para que el panel pueda iniciarlo.", + "found": "Usando {{path}}" + }, + "concurrency": { + "active_one": "{{count}} ejecución ya en curso", + "active_other": "{{count}} ejecuciones ya en curso", + "viewActive": "Ver ejecuciones activas", + "atCap": "Límite de concurrencia alcanzado ({{max}}). Detén una de las ejecuciones activas para iniciar una nueva." + }, + "hint": { + "shortcut": "Cmd+Enter / Ctrl+Enter para enviar", + "permissionWarning": "bypassPermissions permite TODAS las invocaciones de herramientas sin confirmación. Usar solo para prompts de confianza.", + "headlessExplain": "El modo sin cabeza es ideal para tareas programadas donde sabes exactamente qué quieres. La sesión no puede hacer preguntas de seguimiento y se bloqueará en prompts de permiso a menos que estés en acceptEdits." + }, + "empty": { + "title": "Nada aún", + "body": "Escribe una instrucción y haz clic en Ejecutar. La salida se transmite aquí mientras el modelo piensa, llama herramientas y responde." + }, + "events": { + "you": "Tú", + "claude": "Claude", + "tool": "Herramienta", + "toolResult": "Resultado de herramienta", + "system": "Sistema", + "thinking": "Pensando", + "expand": "Expandir", + "collapse": "Colapsar" + }, + "footer": { + "duration": "Duración", + "cost": "Costo", + "turns": "Turnos", + "exitCode": "Código de salida", + "sessionId": "ID de Sesión" + }, + "errors": { + "startFailed": "No se pudo iniciar la ejecución: {{message}}", + "sendFailed": "No se pudo enviar: {{message}}", + "killFailed": "No se pudo detener: {{message}}", + "attachFailed": "No se pudo adjuntar a la ejecución: {{message}}" + }, + "runs": { + "switcher": "Ejecuciones activas", + "switcherEmpty": "Sin ejecuciones activas", + "attached": "Adjuntado a ejecución existente", + "started": "Iniciado {{when}}", + "viewActive": "Ver ejecución activa", + "viewActive_other": "{{count}} ejecuciones activas", + "scopeNote": "Solo muestra ejecuciones que iniciaste desde este panel.", + "allSessionsLink": "Ver todas las sesiones de Claude Code →", + "viewLabel": "Ver" + }, + "resume": { + "label": "Sesión de origen", + "freshOption": "Nueva sesión", + "freshHint": "Inicia una sesión de Claude Code nueva.", + "resumeOption": "Reanudar sesión existente", + "resumeHint": "Elige una sesión de tu historial y continúa la conversación. El cwd queda bloqueado al original.", + "pickSession": "Elige una sesión…", + "search": "Buscar por ID, cwd o estado…", + "noSessions": "No se encontraron sesiones.", + "originalCwd": "Cwd original", + "preview": "Última actividad", + "selectedBadge": "Reanudando", + "clear": "Limpiar selección" + }, + "limitations": { + "title": "Ejecutar Claude en tu navegador", + "subtitle": "mismo binario, superficie diferente", + "peek": "La mayoría de las funciones TUI se transfieren. Algunas interactivas no.", + "why": "Por qué", + "intro": "Bajo el capó iniciamos el mismo binario `claude` que usa tu terminal — pero stream-json (la única interfaz programática que Claude expone) es una manguera de un solo sentido, no el TUI interactivo. Cualquier cosa que dependa de una sesión de terminal en ejecución — prompts de permiso en el lugar, la superposición de atajos de teclado, cambios de configuración a mitad de sesión — debe configurarse en el inicio en lugar de a mitad de conversación.", + "supported": "Funciona aquí", + "limited": "Solo CLI", + "tldr": "Si una función no está aquí, abre la misma sesión en tu terminal con `claude --resume ` — ambos lados comparten la misma transcripción JSONL en disco, por lo que nunca pierdes contexto al cambiar de superficie.", + "dismiss": "Entendido", + "minimize": "Minimizar", + "restore": "Mostrar notas de ejecución en navegador", + "expand": "Leer más", + "collapse": "Colapsar" + }, + "tokens": { + "label": "Contexto", + "input": "Entrada", + "output": "Salida", + "cacheRead": "Acierto de caché", + "cost": "Costo" + }, + "autocomplete": { + "slashHint": "Escribe / para comandos de barra", + "fileHint": "Escribe @ para referenciar un archivo", + "noMatches": "Sin coincidencias", + "groupBuiltin": "Integrado (solo CLI - no se ejecutará desde aquí)", + "groupUser": "Comandos de usuario", + "groupProject": "Comandos de proyecto", + "groupFiles": "Archivos en cwd" + }, + "statusHeader": { + "model": "Modelo", + "effort": "Esfuerzo", + "permissionMode": "Modo", + "cwd": "Directorio de trabajo", + "session": "Sesión", + "envelopes": "Eventos", + "duration": "Transcurrido" + } +} diff --git a/client/src/i18n/locales/es/sessions.json b/client/src/i18n/locales/es/sessions.json new file mode 100644 index 00000000..48610942 --- /dev/null +++ b/client/src/i18n/locales/es/sessions.json @@ -0,0 +1,43 @@ +{ + "title": "Sesiones", + "searchPlaceholder": "Buscar sesiones...", + "filterAll": "Todas", + "filterActive": "Activas", + "filterWaiting": "En espera", + "filterCompleted": "Completadas", + "filterError": "Error", + "filterAbandoned": "Abandonadas", + "sessionCount": "{{count}} sesión registrada", + "sessionCount_plural": "{{count}} sesiones registradas", + "noSessions": "No se encontraron sesiones", + "noSessionsDesc": "Intenta ajustar tu búsqueda o los filtros.", + "noSessionsHint": "Inicia una sesión de Claude Code con los hooks instalados para comenzar el seguimiento.", + "tableSession": "Sesión", + "tableStatus": "Estado", + "tableLastActive": "Última Actividad", + "tableDuration": "Duración", + "tableAgents": "Agentes", + "tableCost": "Costo", + "tableDirectory": "Directorio", + "defaultName": "Sesión ", + "detail": { + "waitingBanner": { + "title": "Esperando tu entrada", + "generic": "Claude Code está pausado en esta sesión hasta que respondas en la terminal." + }, + "failedLoad": "No se pudo cargar la sesión", + "loading": "Cargando sesión...", + "notFound": "Sesión no encontrada", + "backToSessions": "Volver a Sesiones", + "agents": "Agentes", + "noAgents": "No se registraron agentes.", + "unparented": "Subagentes Sin Padre", + "costBreakdown": "Desglose de Costos", + "eventTimeline": "Línea de Tiempo de Eventos", + "noEvents": "No se registraron eventos.", + "conversation": "Conversación", + "timeline": "Línea de tiempo ({{shown}}/{{total}})", + "transcriptNotFound": "No se encontró la transcripción de la conversación para este agente. El archivo de transcripción puede estar ausente o aún no vinculado." + }, + "remoteSourceBadgeTitle": "Recopilado desde una máquina remota" +} diff --git a/client/src/i18n/locales/es/settings.json b/client/src/i18n/locales/es/settings.json new file mode 100644 index 00000000..08814b18 --- /dev/null +++ b/client/src/i18n/locales/es/settings.json @@ -0,0 +1,435 @@ +{ + "title": "Configuración", + "subtitle": "Gestiona precios, notificaciones, datos y ganchos", + "exportData": "Exportar Datos", + "acrossSessions": "En todas las sesiones rastreadas", + "basedOnUsage": "Basado en el uso de tokens por modelo", + "tabby": { + "title": "Compañero Tabby", + "description": "Un gato flotante que reacciona a tus sesiones en vivo.", + "enable": "Mostrar Tabby", + "enableDesc": "Mostrar el compañero de esquina en todo el panel (⌘B para abrir)" + }, + "pricing": { + "title": "Precios de Modelos", + "description": "Tarifas por millón de tokens (USD). Usa % como comodín en los patrones. Algunos modelos tienen una tarifa introductoria por tiempo limitado (mostrada en violeta); el uso en o antes de su fecha de corte se factura a esa tarifa, y el uso posterior a la tarifa estándar.", + "introNote": "Intro ${{input}}/${{output}} hasta {{until}}", + "introRatesTitle": "Tarifas introductorias", + "introRatesHint": "Deja la fecha vacía para sin promoción", + "introUntil": "Hasta (fecha)", + "introUntilInvalid": "El corte introductorio debe ser una fecha YYYY-MM-DD", + "resetConfirm": "Confirmar Restablecimiento", + "resetDefaults": "Restablecer Valores Predeterminados", + "resetResult": "Restablecido a {{count}} reglas predeterminadas", + "addModel": "Añadir Modelo", + "pattern": "Patrón", + "patternPlaceholder": "claude-opus-4%", + "namePlaceholder": "Claude Opus 4", + "validationRequired": "El patrón y el nombre para mostrar son obligatorios", + "lastUpdated": "Última actualización: ", + "tooltip": { + "title": "Cómo funcionan los precios de los modelos", + "howItWorks": "Cómo funciona", + "howItWorksBody": "Cuando una sesión informa el uso, el panel encuentra la primera regla de precios cuyo patrón coincide con el id del modelo y multiplica (tokens de entrada / 1M) y (tokens de salida / 1M) por las tarifas a continuación para calcular el costo. Las reglas se evalúan de arriba a abajo - la primera coincidencia gana.", + "patternsTitle": "Sintaxis de patrones", + "patternsBody": "Los patrones son globs de estilo SQL. % es un comodín que coincide con cualquier carácter. Por ejemplo: claude-opus-4-7% coincide con cada id de modelo que comienza con claude-opus-4-7 (p. ej., claude-opus-4-7, claude-opus-4-7-20260101). claude-%-haiku coincide con cualquier variante haiku. Un id exacto como claude-sonnet-4-6 solo coincide consigo mismo.", + "manualUpdates": "Debes actualizar los precios manualmente", + "manualUpdatesBody": "Anthropic publica cambios de precios en su sitio web - no hay un feed en vivo. Cuando se lanza un nuevo modelo o cambian las tarifas, edita la regla coincidente (o añade una nueva encima del catch-all) para que las nuevas sesiones registradas se calculen correctamente. Las sesiones ya almacenadas conservan el precio que se aplicó en el momento de la ingesta.", + "apiPricing": "Solo de referencia - tarifas de API", + "apiPricingBody": "Estas son tarifas de API de pago por uso. Si usas Claude Code con un plan de suscripción (Pro, Max, Team o Enterprise), tu costo real es una tarifa mensual fija, no por token - por lo que estas cifras generalmente serán más altas que lo que realmente pagas. Trata los costos aquí como una estimación de uso de referencia, no una factura." + }, + "cacheWrite5m": "Escritura de Caché (5m)", + "cacheWrite1h": "Escritura de Caché (1h)", + "fastInput": "Entrada Rápida", + "fastOutput": "Salida Rápida" + }, + "claudeHome": { + "title": "CLAUDE_HOME", + "description": "Directorio raíz para los datos de sesión de Claude Code. Cambiar esto actualiza la ruta de escaneo para transcripciones e importaciones de forma inmediata.", + "save": "Guardar", + "saving": "Guardando...", + "current": "Actual:", + "placeholder": "/ruta/a/claude-home", + "saveFailed": "No se pudo actualizar CLAUDE_HOME" + }, + "hooks": { + "title": "Configuración de ganchos", + "description": "Los ganchos de Claude Code reenvían eventos al panel en tiempo real.", + "allInstalled": "Todos los ganchos instalados", + "incomplete": "Ganchos incompletos", + "reinstall": "Reinstalar ganchos", + "success": "Ganchos instalados correctamente", + "failed": "Error al instalar los ganchos" + }, + "notifications": { + "title": "Notificaciones", + "description": "Notificaciones del navegador para eventos importantes. Requiere permiso.", + "enable": "Habilitar Notificaciones del Navegador", + "granted": "Permiso concedido", + "blocked": "Permiso bloqueado", + "required": "Permiso requerido", + "notifyWhen": "Notificarme cuando...", + "newSession": "Inicia una nueva sesión", + "sessionComplete": "Se completa una sesión", + "sessionError": "Errores de sesión", + "subagentSpawned": "Se inicia un subagente", + "testTitle": "Agent Monitor", + "testBody": "¡Las notificaciones funcionan!", + "sendTest": "Enviar Notificación de Prueba", + "disabledInfo": "Las notificaciones están deshabilitadas - habilita para recibir alertas de eventos de sesión" + }, + "import": { + "title": "Importar Historial", + "description": "Trae sesiones de Claude Code existentes al panel. Los conteos de tokens, el costo por modelo, las compresiones, los subagentes, los usos de herramientas y las duraciones de turno se reconstruyen a partir de las transcripciones JSONL originales - idéntico a cómo se capturan las sesiones en vivo.", + "accuracyNote": "Volver a ejecutar es seguro. Las sesiones se deduplican por ID de sesión, y las líneas de base de compresión garantizan que los totales de tokens nunca cuenten doble.", + "supportedFiles": "Entradas admitidas: .jsonl, .meta.json, .zip, .tar, .tar.gz, .tgz, .gz", + "instructions": "Cómo recopilar tu historial", + "stepLocate": "1. Localiza tu historial de Claude Code", + "stepLocateBody": "Cada sesión de Claude Code se almacena como una transcripción JSONL bajo la carpeta de proyectos. Cada subcarpeta lleva el nombre del directorio de trabajo donde comenzó la sesión (barras reemplazadas por guiones).", + "stepArchive": "2. Empaquétalo para transferencia (opcional)", + "stepArchiveBody": "Para mover el historial desde otra máquina, archiva primero toda la carpeta, luego cópiala (AirDrop, scp, USB, almacenamiento en la nube):", + "stepChoose": "3. Elige un modo de importación abajo", + "stepChooseBody": "Vuelve a escanear la ubicación predeterminada, apunta a cualquier carpeta donde hayas extraído el historial, o sube archivos/archivos directamente.", + "stepVerify": "4. Verifica tokens y costo", + "stepVerifyBody": "Después de importar, abre Analíticas → Costo para confirmar el desglose. Volver a importar la misma sesión siempre es seguro.", + "defaultLocation": "Ubicación predeterminada en esta máquina", + "locationFound": "Carpeta encontrada", + "locationMissing": "Carpeta no encontrada", + "projectsLabel": "proyectos", + "jsonlLabel": "Archivos JSONL", + "modeRescan": "Volver a escanear carpeta predeterminada", + "modeRescanDesc": "Volver a leer ~/.claude/projects e importar cualquier cosa nueva.", + "modeFolder": "Escanear una carpeta", + "modeFolderDesc": "Escanear cualquier directorio en esta máquina en busca de transcripciones JSONL (recorre subcarpetas).", + "modeUpload": "Subir archivos", + "modeUploadDesc": "Suelta archivos JSONL o un archivo comprimido (.zip / .tar.gz) directamente en el navegador.", + "modeBackup": "Restaurar copia de seguridad", + "modeBackupDesc": "Importar una exportación del panel (.json) desde Exportar datos — combinar el historial de otra máquina.", + "backupHint": "Suelta un .json de exportación aquí o haz clic para seleccionar", + "backupSub": "El archivo producido por el botón Exportar datos (parte superior de Configuración)", + "runRestore": "Restaurar", + "backupResult": { + "title": "Restauración completa", + "sessionsImported": "Sesiones añadidas: {{count}}", + "sessionsSkipped": "Ya presentes: {{count}}", + "events": "Eventos: {{count}}", + "pricing": "Reglas de precios: {{count}}", + "detail": "{{agents}} agentes · {{workflows}} flujos · {{runs}} ejecuciones · {{rules}} reglas de alerta" + }, + "folderPlaceholder": "/ruta/absoluta/a/historial-claude", + "folderHelper": "Ruta absoluta. La tilde (~) se expande. Las subcarpetas se escanean recursivamente.", + "runRescan": "Volver a Escanear Ahora", + "runScan": "Escanear Carpeta", + "runUpload": "Subir e Importar", + "dropzoneHint": "Arrastra archivos aquí o haz clic para seleccionar", + "dropzoneSub": "Acepta .jsonl, .meta.json, .zip, .tar, .tar.gz, .tgz, .gz", + "filesSelected": "{{count}} archivo(s) seleccionado(s)", + "clearSelection": "Limpiar", + "copy": "Copiar", + "copied": "Copiado", + "progress": { + "scan": "Escaneando directorio...", + "extract": "Extrayendo archivos comprimidos ({{processed}}/{{total}})...", + "parse": "Analizando transcripciones ({{processed}}/{{total}})...", + "complete": "Importación completa", + "error": "Error en la importación" + }, + "result": { + "imported": "Importado: {{count}}", + "backfilled": "Enriquecidos existentes: {{count}}", + "skipped": "Ya actualizados: {{count}}", + "errors": "Errores: {{count}}", + "filesScanned": "Archivos escaneados: {{count}}", + "title": "Último resultado de importación" + }, + "errors": { + "noFiles": "No se seleccionaron archivos", + "noJsonl": "No se encontraron archivos .jsonl en el contenido subido", + "pathRequired": "La ruta es obligatoria", + "pathInvalid": "La ruta debe ser absoluta", + "pathNotFound": "La ruta no existe", + "pathNotDir": "La ruta no es un directorio", + "generic": "Error en la importación: {{message}}" + } + }, + "data": { + "title": "Gestión de Datos", + "description": "Información de la base de datos, importación/exportación y limpieza.", + "dbOverview": "Resumen de la Base de Datos", + "dbSize": "Tamaño de BD", + "loadingDb": "Cargando información de la base de datos...", + "sessionCleanup": "Limpieza de Sesiones", + "cleanupDesc": "Abandonar sesiones obsoletas y purgar datos antiguos", + "abandonAfter": "Abandonar sesiones activas obsoletas de más de", + "purgeAfter": "Purgar sesiones completadas/con error de más de", + "confirmCleanup": "Confirmar Limpieza", + "runCleanup": "Ejecutar Limpieza", + "nothingToClean": "Nada que limpiar", + "abandonedResult": " sesiones abandonadas", + "purgedResult": " sesiones purgadas ({{events}} eventos, {{agents}} agentes)" + }, + "danger": { + "title": "Zona de Peligro", + "description": "Acciones irreversibles que eliminan datos permanentemente", + "warning": "Esto eliminará todas las sesiones, agentes, eventos y datos de tokens. ¿Estás seguro?", + "yesClearAll": "Sí, Eliminar Todo", + "clearAllData": "Eliminar Todos los Datos", + "clearedResult": "Se eliminaron {{count}} filas" + }, + "about": { + "title": "Acerca de", + "description": "Información del runtime del servidor.", + "release": "Versión", + "uiBuild": "UI build v{{version}} (reconstruye el cliente para actualizar)", + "uptime": "Tiempo activo", + "nodejs": "Node.js", + "platform": "Plataforma", + "wsClients": "Clientes WS", + "loadingInfo": "Cargando información del servidor..." + }, + "tables": { + "sessions": "sesiones", + "agents": "agentes", + "events": "eventos", + "sessionsWithCost": "sesiones con costo", + "pricingRules": "reglas de precios" + }, + "messages": { + "failedLoad": "Error al cargar", + "failedSave": "Error al guardar", + "failedDelete": "Error al eliminar", + "unknownError": "Desconocido", + "actionFailed": "Error: {{message}}" + }, + "webhooks": { + "title": "Notificaciones por Webhook", + "description": "Reenvía alertas disparadas a Slack, Discord, Microsoft Teams, o cualquier endpoint HTTP. La entrega es automática, se reintenta en caso de fallo, y nunca bloquea el monitoreo.", + "count_one": "{{count}} destino", + "count_other": "{{count}} destinos", + "add": "Añadir Webhook", + "loading": "Cargando webhooks…", + "empty": "Sin webhooks configurados. Añade uno para reenviar alertas a Slack, Discord, Teams o un endpoint personalizado.", + "scopedTo_one": "{{count}} regla", + "scopedTo_other": "{{count}} reglas", + "enabled": "Habilitado", + "test": "Probar", + "edit": "Editar", + "delete": "Eliminar", + "confirmDelete": "Confirmar", + "testOk": "Entregado (HTTP {{status}})", + "testFail": "Falló: {{error}}", + "addTitle": "Nuevo Webhook", + "editTitle": "Editar Webhook", + "fieldName": "Nombre", + "fieldNamePlaceholder": "p. ej., Slack del equipo #alertas", + "fieldType": "Tipo", + "type": { + "slack": "Slack", + "discord": "Discord", + "teams": "Microsoft Teams", + "generic": "Genérico (JSON personalizado)" + }, + "fieldUrl": "URL del Webhook", + "urlKeepHint": "dejar en blanco para mantener el actual", + "urlKeepPlaceholder": "•••••••• (sin cambios)", + "urlPlaceholder": { + "slack": "https://hooks.slack.com/services/…", + "discord": "https://discord.com/api/webhooks/…", + "teams": "https://outlook.office.com/webhook/…", + "generic": "https://example.com/webhook" + }, + "fieldSecret": "Secreto de firma (opcional)", + "secretPlaceholder": "Secreto HMAC-SHA256", + "secretKeepPlaceholder": "•••••••• (dejar en blanco para mantener)", + "secretHint": "Cuando se establece, las solicitudes se firman con una cabecera X-Webhook-Signature.", + "fieldHeaders": "Cabeceras personalizadas (opcional)", + "replaceHeaders": "Reemplazar cabeceras", + "headerKey": "Cabecera", + "headerValue": "Valor", + "addHeader": "Añadir cabecera", + "scopeAll": "Recibir alertas de todas las reglas", + "enabledOnSave": "Habilitado", + "save": "Guardar", + "create": "Crear", + "cancel": "Cancelar", + "urlOptional": "anulación opcional", + "urlAuto": "La URL se establece automáticamente a partir de las credenciales a continuación.", + "deleteTitle": "¿Eliminar webhook?", + "deleteMessage": "¿Eliminar \"{{name}}\"? Las alertas disparadas dejarán de entregarse a este destino. Esto no se puede deshacer.", + "guideToggle": "Cómo configurar {{provider}}", + "guideDocs": "Documentos oficiales de {{provider}}", + "guideStaleNote": "Las pantallas de configuración del proveedor cambian con frecuencia, por lo que estos pasos pueden estar desactualizados - siempre confirma con la documentación oficial." + }, + "alertsHub": { + "title": "Alertas", + "description": "Define reglas de alerta, enrútalas a canales de webhook y revisa lo que se ha disparado - todo en un solo lugar.", + "tabRules": "Reglas", + "tabChannels": "Canales", + "tabActivity": "Actividad", + "rulesHint": "Condiciones que desencadenan una alerta. Evaluadas en el servidor contra el flujo de eventos en vivo.", + "rulesEmptyHint": "Añade una regla para comenzar a alertar sobre errores, inactividad, agentes bloqueados o umbrales de tokens." + }, + "jumpTo": "Ir a", + "webhookGuides": { + "slack": { + "steps": [ + "Crea o abre una app de Slack en api.slack.com/apps.", + "Activa 'Incoming Webhooks', luego haz clic en 'Add New Webhook to Workspace'.", + "Elige el canal donde publicar y autoriza.", + "Copia la URL generada (https://hooks.slack.com/services/…) y pégala arriba." + ] + }, + "discord": { + "steps": [ + "Abre tu servidor → Configuración del servidor → Integraciones → Webhooks.", + "Haz clic en 'New Webhook', elige un canal, opcionalmente renómbralo.", + "Haz clic en 'Copy Webhook URL' y pégala arriba." + ] + }, + "teams": { + "steps": [ + "En el canal de Teams de destino, haz clic en ⋯ → 'Workflows'.", + "Elige la plantilla 'Post to a channel when a webhook request is received'.", + "Termina el flujo y copia la URL HTTP POST generada.", + "Pégala arriba. (Los conectores clásicos de Office 365 fueron retirados en 2025 - usa Workflows.)" + ] + }, + "google_chat": { + "steps": [ + "Abre el espacio de Google Chat → título del espacio → 'Apps & integrations'.", + "Haz clic en 'Webhooks' → 'Add webhook' y dale un nombre.", + "Copia la URL del webhook y pégala arriba." + ] + }, + "mattermost": { + "steps": [ + "Menú principal → Integraciones → Webhooks entrantes (un administrador debe habilitar los webhooks primero).", + "Haz clic en 'Add Incoming Webhook' y elige un canal.", + "Guarda, luego copia la URL del webhook y pégala arriba." + ] + }, + "rocketchat": { + "steps": [ + "Administración → Integraciones → Nuevo → Entrante.", + "Habilítalo, elige un canal y guarda.", + "Copia la 'Webhook URL' y pégala arriba." + ] + }, + "telegram": { + "steps": [ + "Envía un mensaje a @BotFather, ejecuta /newbot y copia el token del bot.", + "Añade el bot a tu grupo/canal (o simplemente envíale un DM).", + "Encuentra el ID del chat: envía un mensaje, abre https://api.telegram.org/bot/getUpdates, lee result[].message.chat.id.", + "Ingresa el token del Bot y el ID del Chat arriba - no se necesita URL." + ] + }, + "pagerduty": { + "steps": [ + "Abre el Servicio de destino → Integraciones → 'Add integration'.", + "Elige 'Events API v2'.", + "Copia la Integration Key (la clave de enrutamiento).", + "Ingrésala como Routing key arriba - la URL de la Events API está precompletada." + ] + }, + "opsgenie": { + "steps": [ + "Configuración → Integraciones → añade una integración 'API'.", + "Copia la clave API generada.", + "Anota la región de tu cuenta (US o EU).", + "Ingresa la clave API y la región arriba - la URL de alertas se deriva de la región." + ] + }, + "splunk_oncall": { + "steps": [ + "Integraciones → REST Endpoint, y habilítalo.", + "Copia la URL REST - ya contiene tu clave API.", + "Reemplaza el '$routing_key' al final por una de tus claves de enrutamiento.", + "Pega la URL completa arriba." + ] + }, + "zapier": { + "steps": [ + "Crea un Zap con el disparador 'Webhooks by Zapier' → 'Catch Hook'.", + "Copia la URL del webhook personalizado que te proporciona.", + "Pégala arriba. La alerta llega como JSON: { event, alert }." + ] + }, + "make": { + "steps": [ + "Añade un módulo 'Webhooks' → 'Custom webhook' como primer paso de un escenario.", + "Haz clic en 'Add', crea el hook y copia su URL.", + "Pégala arriba, luego ejecuta una vez para que Make aprenda la forma del payload." + ] + }, + "n8n": { + "steps": [ + "Añade un nodo 'Webhook' a tu flujo de trabajo; establece el método en POST.", + "Copia la URL de producción.", + "Activa el flujo de trabajo y pega la URL arriba (http está permitido para auto-alojado)." + ] + }, + "pipedream": { + "steps": [ + "Crea un flujo de trabajo con un disparador 'HTTP / Webhook'.", + "Copia la URL de endpoint única.", + "Pégala arriba; inspecciona las entregas en el inspector de eventos de Pipedream." + ] + }, + "generic": { + "steps": [ + "Apunta esto a cualquier endpoint que acepte un POST JSON (https, o http para pruebas locales).", + "Forma del cuerpo: { event: 'alert.triggered', source, sent_at, alert: { … } }.", + "Opcional: establece un secreto de firma (HMAC-SHA256 sobre el cuerpo → cabecera X-Webhook-Signature) y cabeceras personalizadas.", + "Consejo: usa un inspector gratuito como webhook.site para ver el payload exacto." + ] + } + }, + "remoteSources": { + "title": "Fuentes de Datos Remotas", + "description": "Recopila el uso de Claude Code de otras máquinas por SSH - p. ej., una caja de desarrollo o VM en la nube que controlas por SSH mientras ejecutas este panel localmente. La autenticación usa tu propia configuración SSH (~/.ssh/config, claves, agente); no se almacenan contraseñas aquí.", + "scopeTitle": "Alcance de datos", + "scopeDesc": "Elige qué datos de máquinas muestra todo el panel. Los cambios se aplican inmediatamente en todas las páginas — sesiones, analíticas y costo.", + "scopeAll": "Todas las fuentes", + "scopeAllDesc": "Esta máquina más cada fuente remota configurada, combinadas.", + "scopeLocal": "Solo esta máquina", + "scopeLocalDesc": "Solo sesiones recopiladas localmente — oculta todos los datos de fuentes remotas.", + "scopeSelected": "Fuentes seleccionadas", + "scopeSelectedDesc": "Elige exactamente qué máquinas incluir, abajo.", + "scopeSelectedCount": "{{n}} de {{total}} seleccionadas", + "scopePickMachines": "Máquinas a incluir", + "thisMachine": "Esta máquina", + "listTitle": "Fuentes configuradas", + "add": "Añadir fuente", + "addTitle": "Añadir una fuente remota", + "editTitle": "Editar fuente", + "fieldLabel": "Etiqueta", + "fieldHost": "Host SSH", + "fieldPort": "Puerto (opcional)", + "fieldIdentity": "Archivo de identidad (opcional)", + "fieldRemoteHome": "Inicio de Claude remoto (opcional)", + "fieldRemoteHomeHint": "Linux/macOS: por defecto ~/.claude (o una ruta absoluta como /home/tú/.claude). Windows SSH + Claude en WSL: dejar en blanco (autodetectar) o usar wsl:~/.claude. Windows nativo: C:/Users/tú/.claude.", + "fieldEnabled": "Sincronizar automáticamente en segundo plano", + "empty": "Sin fuentes remotas aún.", + "emptyHint": "Añade una máquina a la que accedas por SSH para importar su uso de Claude Code.", + "paused": "Sincronización automática desactivada", + "sessionCount": "{{n}} sesiones", + "sessionCountLinked": "{{n}} vinculadas", + "sessionCountHint": "Sesiones vinculadas a esta fuente (no todas las sesiones visibles cuando el alcance de datos es Todo)", + "lastSync": "Última sincronización: {{when}}", + "neverSynced": "Nunca sincronizado", + "imported": "{{n}} importadas", + "syncNew": "{{n}} nuevas", + "syncOnRemote": "{{n}} en remoto", + "test": "Probar", + "syncNow": "Sincronizar", + "syncAll": "Sincronizar todo", + "enable": "Habilitar", + "disable": "Deshabilitar", + "confirmDelete": "¿Eliminar esta fuente?", + "purgeData": "También eliminar las sesiones importadas de esta fuente (no se puede deshacer)", + "deleteAndPurge": "Eliminar + borrar datos", + "removeKeep": "Eliminar (conservar datos)", + "remoteSourceBadgeTitle": "Recopilado desde una máquina remota" + }, + "cursorPathsNote": "Informativo: Las sesiones de Cursor también se cuentan aquí — Cursor usa las mismas rutas ~/.claude que Claude Code (localmente y en remotos sincronizados)." +} diff --git a/client/src/i18n/locales/es/splash.json b/client/src/i18n/locales/es/splash.json new file mode 100644 index 00000000..b8e2dd38 --- /dev/null +++ b/client/src/i18n/locales/es/splash.json @@ -0,0 +1,85 @@ +{ + "greeting": { + "morning": "Buenos días", + "afternoon": "Buenas tardes", + "evening": "Buenas noches", + "night": "Trabajando tarde" + }, + "tagline": "Nada de lo que hacen tus agentes queda en la oscuridad.", + "sub1": "Observabilidad en tiempo real para cada sesión de Claude Code.", + "sub2": "Tokens, herramientas, costos y flujos, todo en vivo.", + "brand": "Claude Code Monitor", + "taglines": [ + "Nada de lo que hacen tus agentes queda en la oscuridad.", + "Ve cada movimiento que hacen tus agentes.", + "Tus agentes, completamente observables.", + "Cada token, herramienta y turno — a plena vista.", + "Observa cómo piensa tu flota.", + "Donde las sesiones de Claude Code cobran vida.", + "Ojos en tiempo real sobre cada agente.", + "Del prompt al resultado, todo registrado.", + "La sala de control para tus agentes de IA.", + "Cada subagente contabilizado.", + "Sabe exactamente lo que cuestan tus agentes.", + "Tus flujos agénticos, hechos legibles.", + "Observa. Mide. Optimiza.", + "Control de misión para Claude Code.", + "Convierte el caos de agentes en una imagen clara.", + "Los recibos de cada ejecución." + ], + "subs": [ + [ + "Observabilidad en tiempo real para cada sesión de Claude Code.", + "Tokens, herramientas, costos y flujos, todo en vivo." + ], + [ + "Sesiones, agentes y eventos en vivo a medida que ocurren.", + "Desgloses de tokens y costos por modelo, sin suposiciones." + ], + [ + "Rastrea cada llamada de herramienta a través de tu árbol de agentes.", + "Detecta el turno lento, el modelo costoso, el fallo silencioso." + ], + [ + "Los hooks se transmiten directamente a un panel local.", + "Tus datos nunca salen de tu máquina." + ], + [ + "Observa cómo los orquestadores delegan a subagentes.", + "DAGs, concurrencia y propagación de errores, visualizados." + ], + [ + "Seguimiento de costos hasta el token de caché.", + "Precios por modelo con líneas de base conscientes de compresión." + ], + [ + "Cada sesión, agente y evento en un solo lugar.", + "Busca, reproduce e inspecciona sin salir de la sala." + ], + [ + "Desde SessionStart hasta SessionEnd, capturado.", + "Compresiones, errores de API y duraciones de turno incluidos." + ], + [ + "Sabe qué modelo hizo qué y cuánto costó.", + "Subagentes con precio a su propia tarifa, no la del orquestador." + ], + [ + "Flotas de flujos y agentes internos, a la vista.", + "Incluso las ejecuciones que nunca disparan un hook." + ], + ["Una ventana local hacia tus agentes.", "Sin nube, sin cuenta, sin telemetría."], + [ + "Mide la productividad, no las sensaciones.", + "Velocidad, eficiencia de caché y efectividad de herramientas, puntuados." + ], + [ + "Detecta la anomalía antes de que lo haga la factura.", + "Valores atípicos de costo y picos de tokens, detectados temprano." + ], + [ + "Tu configuración de Claude Code, completamente mapeada.", + "Skills, agentes, hooks, MCP y memoria de un vistazo." + ] + ] +} diff --git a/client/src/i18n/locales/es/updates.json b/client/src/i18n/locales/es/updates.json new file mode 100644 index 00000000..471b8cd6 --- /dev/null +++ b/client/src/i18n/locales/es/updates.json @@ -0,0 +1,15 @@ +{ + "title": "Actualización disponible", + "lead": "Hay una nueva versión del panel disponible. Para actualizar, ejecuta el siguiente comando en tu terminal:", + "commitsBehind": "{{count}} commit(s) detrás de {{ref}}", + "copy": "Copiar comando", + "commandLabel": "Comando de terminal para actualizar el panel", + "copied": "Copiado", + "dismiss": "Descartar", + "fetchError": "No se pudo alcanzar el repositorio remoto. Inténtalo de nuevo cuando estés en línea.", + "notGit": "Esta instalación no es un clon de git; usa una ruta de actualización manual.", + "restartNote": "Cuando termine el comando, cierra y reinicia el panel de la misma forma en que lo iniciaste: si usaste npm start, vuelve a ejecutar npm start.", + "checkNow": "Buscar ahora", + "checking": "Buscando...", + "checkError": "No se pudieron buscar actualizaciones" +} diff --git a/client/src/i18n/locales/es/workflows.json b/client/src/i18n/locales/es/workflows.json new file mode 100644 index 00000000..7fa04bd7 --- /dev/null +++ b/client/src/i18n/locales/es/workflows.json @@ -0,0 +1,468 @@ +{ + "title": "Flujos", + "subtitle": "Inteligencia de orquestación de agentes", + "failedLoad": "No se pudieron cargar los datos de flujos", + "filteredBy": "Filtrado por:", + "clearFilter": "Limpiar filtro", + "refreshData": "Actualizar datos", + "exportJson": "Exportar como JSON", + "allSessions": "Todas las Sesiones", + "activeOnly": "Solo Activas", + "completed": "Completadas", + "runs": { + "title": "Flujos Dinámicos", + "subtitle": "Flotas iniciadas por la herramienta Workflow, reconstruidas a partir de los diarios de ejecución en disco", + "sessionTitle": "Flujos Dinámicos", + "loading": "Cargando flujos dinámicos…", + "empty": "Sin flujos dinámicos aún. Las ejecuciones de la herramienta Workflow aparecen aquí una vez que se escribe su diario (al completarse).", + "noAgents": "No se registraron agentes internos para esta ejecución.", + "openSession": "Abrir sesión padre", + "filterPhase": "Filtrar por fase", + "clearFilter": "Limpiar", + "resultsLabel": "Resultados", + "promptLabel": "Instrucción", + "resultLabel": "Resultado", + "loadingFull": "Cargando texto completo…", + "tokens": "tokens", + "agents_one": "{{count}} agente", + "agents_other": "{{count}} agentes", + "tools_one": "{{count}} llamada de herramienta", + "tools_other": "{{count}} llamadas de herramienta", + "status": { + "running": "Ejecutando", + "working": "Ejecutando", + "queued": "En cola", + "completed": "Completado", + "done": "Hecho", + "success": "Hecho", + "error": "Error", + "failed": "Falló" + }, + "col": { + "agent": "Agente", + "phase": "Fase", + "state": "Estado", + "tokens": "Tokens", + "tools": "Herramientas", + "duration": "Duración" + } + }, + "chartInfo": { + "labels": { + "what": "Qué muestra esto", + "howToRead": "Cómo leerlo", + "why": "Por qué importa" + }, + "orchestration": { + "what": "Un DAG por capas de cómo las sesiones de Claude Code se expanden: desde las sesiones de origen, hacia el agente principal, hacia cada tipo de subagente, a través de cualquier compresión de contexto, y finalmente hacia los resultados terminales (completado / error / abandonado).", + "howToRead": "Cada columna es una capa. El ancho de la caja es constante; la pequeña insignia es el conteo. Los bordes fluyen de izquierda a derecha; los bordes más gruesos = transiciones más frecuentes. Pasa el cursor sobre cualquier nodo para ver estadísticas; haz clic para filtrar el resto de la página por él.", + "why": "Úsalo para responder '¿a dónde va el trabajo en mis flujos?' - qué tipos de subagentes dominan, dónde entra la compresión, y qué caminos terminan en errores vs completaciones limpias." + }, + "toolFlow": { + "what": "Un gráfico estilo Sankey de transiciones consecutivas de llamadas de herramientas en cada sesión en el alcance. Cada banda es un par (origen → destino) contado en todas las sesiones.", + "howToRead": "Las herramientas aparecen como barras de colores a la izquierda y a la derecha. Las bandas las conectan: el grosor = número de veces que el origen se ejecutó inmediatamente antes que el destino. Pasa el cursor sobre una banda para ver el porcentaje de origen y destino; pasa el cursor sobre un nodo para ver su uso total y su participación en todas las llamadas de herramientas.", + "why": "Muestra cadenas de herramientas habituales (p. ej., Read → Edit → Bash). Útil para detectar bucles, saltos desperdiciados y falta de variedad de herramientas en el comportamiento del agente." + }, + "pipeline": { + "what": "Un grafo dirigido de co-ocurrencia de tipos de agentes: qué tipos de agentes tienden a ejecutarse secuencialmente después de cuáles, y con qué frecuencia.", + "howToRead": "Los círculos son tipos de agentes; el tamaño codifica el total de inicios. Las flechas van de A → B cuando se observó que B se ejecutaba poco después de A en la misma sesión, con la etiqueta = conteo. Pasa el cursor sobre una flecha para ver la participación del origen/destino; pasa el cursor sobre un círculo para ver inicios, sesiones y tasa de éxito. Arrastra los nodos para reorganizarlos.", + "why": "Muestra pipelines de delegación reales que quizás no diseñaste intencionalmente - p. ej., un agente de revisión de código que casi siempre sigue a un agente de compilación - para que puedas codificarlos o simplificarlos." + }, + "effectiveness": { + "what": "Una tarjeta por tipo de subagente con un anillo de tasa de éxito, sesiones totales, duración promedio y un sparkline de actividad de 7 días.", + "howToRead": "El relleno del anillo es la tasa de éxito; el porcentaje en el centro es el mismo. Los dos cuadros dan conteos y duración promedio en tiempo real. El sparkline son sesiones por día durante la última semana - pasa el cursor sobre una barra para el conteo diario.", + "why": "Verificación rápida de salud por agente: cuáles son confiables, cuáles son lentos, y cuáles están tendiendo al alza o a la baja en uso." + }, + "patterns": { + "what": "Una lista clasificada de secuencias recurrentes de orquestación de agentes detectadas a partir de trazas de sesiones, más un aviso para sesiones en solitario que se ejecutaron sin subagentes.", + "howToRead": "Cada fila es una secuencia de pasos (principal → sub → sub …). El lado derecho muestra cuántas sesiones coincidieron y qué porcentaje de todas las sesiones representa. Haz clic en un patrón para resaltarlo.", + "why": "Revela las 'formas' estándar del trabajo en tu proyecto. Los patrones frecuentes son buenos candidatos para formalizarse como flujos de trabajo o skills con nombre." + }, + "modelDelegation": { + "what": "Un flujo de dos columnas que muestra qué modelos principales delegan a qué modelos de subagentes, más conteos de agentes por nodo y tokens totales.", + "howToRead": "Columna izquierda = modelos principales para sesiones; columna derecha = modelos usados dentro de subagentes. Las líneas indican emparejamientos principal → subagente observados. Pasa el cursor sobre un nodo para ver la participación de todos los agentes, sesiones, tokens totales y una descripción de la familia del modelo (Opus / Sonnet / Haiku).", + "why": "Te ayuda a confirmar la jerarquía de costo/latencia - p. ej., principal en Sonnet, subagentes en Haiku - y detectar escalaciones no deseadas a Opus." + }, + "errorPropagation": { + "what": "Dónde se agrupan los errores en la jerarquía de agentes: por profundidad (sesión/principal vs subagente directo vs anidado), por tipo de agente y por categoría de error de API/sesión.", + "howToRead": "El banner superior da la tasa de error a nivel de sesión. Las barras de profundidad muestran cuántos errores ocurrieron en cada nivel de anidamiento. La lista de tipos propensos a errores clasifica los tipos de subagentes por conteo de errores. El bloque inferior muestra resúmenes de errores de API/sesión.", + "why": "Identifica si los fallos viven en la columna vertebral de orquestación (agente principal), en subagentes específicos, o en cadenas anidadas profundas - guiando dónde invertir en reintentos, validación o reescrituras." + }, + "concurrency": { + "what": "Temporización agregada de cuándo cada tipo de agente está activo en relación con la línea de tiempo de la sesión, más cuántas sesiones lo presentan.", + "howToRead": "Cada fila es un tipo de agente. La longitud de la barra es proporcional al conteo de sesiones. Los porcentajes de la derecha muestran la posición promedio de inicio y fin dentro de una sesión (0% = inicio de sesión, 100% = fin de sesión). Pasa el cursor para ver una descripción del patrón de temporización (carga frontal, a mitad de sesión, carga trasera, etc.).", + "why": "Revela el ritmo de tus sesiones - p. ej., lint al frente, revisión de código al final - y muestra agentes que monopolizan toda la sesión." + }, + "complexity": { + "what": "Un diagrama de dispersión de cada sesión: x = duración en tiempo real, y = total de agentes involucrados, tamaño de burbuja = tokens totales, color = estado final.", + "howToRead": "Las burbujas en la parte superior derecha son sesiones largas y con muchos agentes. Las burbujas grandes quemaron la mayor cantidad de tokens. Los rojos/amarillos = resultados de error/abandonado. Pasa el cursor sobre cualquier burbuja para estadísticas completas de la sesión; haz clic para profundizar en ella abajo.", + "why": "Da una vista única de la distribución de costo/complejidad. Los valores atípicos son las sesiones que vale la pena investigar por comportamiento desbocado o picos de costo." + }, + "compaction": { + "what": "Con qué frecuencia Claude activó la compresión de contexto en las sesiones: eventos totales, tokens recuperados y una distribución por sesión.", + "howToRead": "Los dos cuadros de estadísticas muestran los eventos de compresión totales y los tokens acumulados recuperados. El gráfico de barras lista las sesiones con al menos una compresión, ordenadas de forma descendente por conteo.", + "why": "Las compresiones indican presión de contexto. Una larga cola de sesiones con alta compresión generalmente significa flujos de trabajo que deberían dividirse, resumirse o migrarse a un modelo de contexto más largo." + }, + "drillIn": { + "what": "Vista de detalle por sesión: árbol completo de agentes, línea de tiempo de llamadas de herramientas y secuencia de eventos sin procesar para la sesión que selecciones.", + "howToRead": "Elige una sesión del menú desplegable de arriba o haz clic en una burbuja en el diagrama de dispersión. Las pestañas te permiten cambiar entre vistas jerárquica (Árbol de Agentes), temporal (Línea de Tiempo de Herramientas) y cronológica (Secuencia de Eventos) de la misma sesión.", + "why": "Cuando un gráfico agregado señala una sesión sospechosa, aquí es donde vas a leer exactamente qué sucedió, en orden." + } + }, + "stats": { + "avgAgentDepth": "Profundidad Promedio de Agentes", + "avgSubagentsPerSession": "Promedio de Subagentes / Sesión", + "agentSuccessRate": "Tasa de Éxito de Agentes", + "mostCommonFlow": "Flujo Más Común", + "avgCompactions": "Promedio de Compresiones", + "avgDuration": "Duración Promedio", + "tooltip": { + "howCalc": "Cómo se calcula", + "whatItMeans": "Qué significa este número", + "moreInfo": "Explicar esta métrica", + "valueMeansFmt": "{{value}} {{phrase}} significa {{interpretation}}", + "phrase": { + "depth": "profundidad promedio de agentes", + "subagents": "subagentes por sesión", + "success": "tasa de éxito de agentes", + "topFlow": "flujo más común", + "compactions": "compresiones por sesión", + "duration": "duración promedio" + }, + "calc": { + "depth": "Para cada sesión registramos el nivel más profundo de anidamiento de agentes (principal = 0, subagente directo = 1, sub-subagente = 2, …) y promediamos esos máximos en todas las sesiones del filtro actual.", + "subagents": "Número total de invocaciones de subagentes (cada par Task / SubagentStop) dividido por el número de sesiones en el alcance. Cuenta cada ejecución de subagente, incluidas las paralelas y las reiniciadas.", + "success": "En todas las ejecuciones de agentes principales + subagentes en el alcance: ejecuciones completadas ÷ (completadas + con error + abandonadas) × 100. Una ejecución cuenta como completada cuando se observa un Stop / SubagentStop sin un evento de error en medio.", + "topFlow": "Se cuenta cada par consecutivo de llamadas de herramientas dentro de una sesión como una transición. El par que aparece con mayor frecuencia en todas las sesiones se muestra aquí como 'origen → destino'.", + "compactions": "Número total de eventos de compresión de contexto registrados por los hooks PreCompact / SessionStart(compact), dividido por el número de sesiones en el alcance.", + "duration": "Tiempo promedio en tiempo real desde el primer evento de cada sesión (SessionStart) hasta su último evento (Stop / SessionEnd / último hook), promediado en todas las sesiones en el alcance." + }, + "depth": { + "zero": "no se han observado agentes anidados. Cada sesión se ejecutó solo con el agente principal - no ocurrió ninguna delegación de subagentes.", + "rare": "el anidamiento es raro. La mayoría de las sesiones se mantienen en profundidad 0 (solo agente principal); solo una pequeña fracción alcanza subagentes.", + "single": "las sesiones típicamente delegan a una sola capa de subagentes (principal → subagente), sin mayor anidamiento.", + "multi": "la orquestación de múltiples capas es común - los subagentes frecuentemente inician más subagentes (principal → sub → sub).", + "deep": "la orquestación profunda y recursiva es la norma. Las sesiones encadenan consistentemente tres o más capas de agentes." + }, + "subagents": { + "zero": "no se han activado subagentes. Las sesiones se completaron completamente en el agente principal.", + "lowFreq": "prácticamente: aproximadamente un subagente cada ~{{count}} sesiones. La mayoría de las sesiones no inician ningún subagente.", + "moderate": "las sesiones típicamente delegan a 1-3 subagentes - uso moderado de ayudantes especializados.", + "heavy": "delegación pesada - las sesiones rutinariamente se expanden a varios subagentes.", + "veryHeavy": "muy intensivo en orquestación: las sesiones promedian 6+ ejecuciones de subagentes cada una." + }, + "success": { + "perfect": "casi perfecto. Casi cada ejecución de agente termina con un evento Stop limpio - sin errores ni abandono.", + "healthy": "saludable. La gran mayoría de las ejecuciones de agentes se completan con éxito; solo fallos esporádicos.", + "acceptable": "aceptable, pero vigila la tendencia de errores - aproximadamente 1 de cada 5-20 ejecuciones falla o se abandona.", + "concerning": "preocupante - una parte significativa de las ejecuciones de agentes está fallando. Inspecciona la página de Errores para los principales culpables.", + "critical": "crítico: la mayoría de las ejecuciones de agentes están fallando o siendo abandonadas. Revisa ErrorPropagation y los deploys recientes." + }, + "topFlow": { + "none": "aún no se han registrado suficientes llamadas de herramientas consecutivas para identificar un par dominante.", + "selfLoop": "{{tool}} se sigue a sí mismo con mayor frecuencia - típico de lecturas/ediciones repetidas o comandos shell encadenados.", + "pair": "{{source}} se ejecuta con mayor frecuencia inmediatamente antes de {{target}}. Léelo como un hábito: los agentes tienden a {{sourceLower}} y luego {{targetLower}} como su siguiente paso." + }, + "compactions": { + "zero": "no se ha observado compresión de contexto. Las sesiones se mantuvieron cómodamente dentro de la ventana de contexto del modelo.", + "lowFreq": "prácticamente: ~1 compresión cada {{count}} sesiones. Las sesiones de larga duración son la excepción.", + "moderate": "las sesiones típicamente alcanzan la compresión una o dos veces - la presión de contexto existe pero es manejable.", + "high": "alta tasa de compresión. Las sesiones rutinariamente se ejecutan lo suficientemente largo como para requerir múltiples compresiones de contexto; considera dividir el trabajo." + }, + "duration": { + "zero": "sin sesiones completadas aún - la duración es 0.", + "veryShort": "sesiones muy cortas (menos de un minuto) - probablemente llamadas de herramientas rápidas o prompts de un solo disparo.", + "short": "sesiones cortas, del orden de unos pocos minutos. Típico para trabajo enfocado en una sola función.", + "medium": "sesiones de duración media (5-30 min). Cadencia de desarrollo estándar.", + "long": "sesiones largas (30-60 min). Probablemente flujos de trabajo de múltiples pasos o ciclos de revisión más largos.", + "veryLong": "sesiones muy largas (1-3 h). Vigila la compresión y la presión de contexto.", + "marathon": "sesiones maratón (3+ horas). Considera si el trabajo podría dividirse en múltiples sesiones más cortas." + } + } + }, + "orchestration": { + "title": "Grafo de Orquestación de Agentes", + "subtitle": "Patrones de inicio agregados en todas las sesiones - Haz clic en un nodo para filtrar", + "sessions": "Sesiones", + "mainAgent": "Agente Principal", + "compactions": "Compresiones", + "noData": "Sin datos de orquestación", + "noDataDesc": "Los datos de inicio de agentes aparecerán aquí una vez que se registren sesiones con subagentes.", + "legend": "Leyenda", + "edgeWeight": "Peso del borde = frecuencia", + "count": "Conteo", + "otherTypes": "{{count}} otros tipos", + "ariaLabel": "Grafo acíclico dirigido de orquestación de agentes", + "layers": { + "origin": "Origen", + "mainAgent": "Agente Principal", + "subagentTypes": "Tipos de Subagentes", + "compactions": "Compresiones", + "outcomes": "Resultados" + }, + "tooltip": { + "tipClickToFilter": "Consejo: haz clic para filtrar el resto de la página por este nodo.", + "layer": { + "session": "Capa 0 - Origen", + "main": "Capa 1 - Agente principal", + "subagent": "Capa 2 - Tipo de subagente", + "subagentOverflow": "Capa 2 - Tipos de subagentes", + "nested": "Capa 3 - Compresiones", + "outcome": "Capa 4 - Resultado" + }, + "desc": { + "session": "Cada unidad aquí es una sesión de Claude Code que coincide con el filtro de estado actual. Los bordes salientes se expanden hacia los agentes principales que estas sesiones lanzaron.", + "main": "La ejecución Claude de nivel superior para cada sesión. Cada sesión tiene exactamente un agente principal; desde aquí el grafo se ramifica hacia los tipos de subagentes a los que delegó.", + "subagent": "Un subagente especializado al que el agente principal delegó (p. ej., a través de la herramienta Task).", + "subagentClean": " Cada ejecución de este subagente se ha completado limpiamente.", + "subagentAllError": " Cada ejecución de este subagente ha tenido error - investiga la definición del agente.", + "subagentSomeErrors": " {{count}} ejecución(es) con error - consulta la Propagación de Errores a continuación para más detalles.", + "subagentOverflow": "Todos los tipos de subagentes restantes colapsados en un nodo para que el grafo siga siendo legible. Pasa el cursor sobre cualquier otro nodo de subagente para ver estadísticas individuales.", + "nested": "Eventos de compresión de ventana de contexto. Claude activa una compresión cuando el contexto en ejecución se acerca al límite del modelo; el conteo refleja con qué frecuencia ocurrió eso en las sesiones en el alcance.", + "outcomeCompleted": "Sesiones cuyo hook final fue un evento Stop limpio. No se emitieron eventos de error antes de la terminación.", + "outcomeError": "Sesiones que emitieron al menos un evento de error (error de herramienta, error de subagente o error de sesión) antes de terminar.", + "outcomeAbandoned": "Sesiones que se detuvieron sin un evento Stop limpio y sin errores explícitos - generalmente cerradas a mitad de vuelo.", + "outcomeFallback": "El estado terminal de las sesiones en el alcance, calculado a partir del último evento hook observado para cada sesión." + } + } + }, + "toolFlow": { + "title": "Flujo de Ejecución de Herramientas", + "subtitle": "Cómo se encadenan las herramientas - Flujo dirigido estilo Sankey", + "noData": "Sin datos de flujo de herramientas", + "transitionCount_one": "{{count}} transición", + "transitionCount_other": "{{count}} transiciones", + "tooltip": { + "node": "Nodo de herramienta", + "link": "Transición de herramienta", + "totalCalls": "Total de llamadas", + "shareOfAll": "Participación de todo el uso de herramientas", + "transitionsObserved": "Transiciones observadas", + "shareOfSourceFmt": "Participación de {{source}} → siguiente", + "shareOfTargetFmt": "Participación de anterior → {{target}}", + "nodeDescFmt": "La altura de la barra muestra con qué frecuencia aparece {{name}} en todas las sesiones en el alcance. Las bandas que fluyen desde la izquierda muestran qué se ejecutó antes de {{name}}; las bandas que fluyen hacia la derecha muestran qué se ejecutó después.", + "linkDescFmt": "En cada sesión, esto cuenta con qué frecuencia {{source}} se ejecutó inmediatamente antes de {{target}}. Bandas más gruesas = transiciones más comunes; los porcentajes muestran qué tan dominante es este salto entre el flujo de salida/entrada de cada herramienta." + } + }, + "pipeline": { + "title": "Grafo de Pipeline de Agentes", + "subtitle": "Flujo de trabajo dirigido - qué tipos de agentes se ejecutan después de cuáles, con etiquetas de frecuencia", + "noData": "Sin datos de pipeline aún", + "noDataDesc": "Los bordes del flujo de trabajo dirigido aparecen una vez que los tipos de agentes se ejecutan secuencialmente en múltiples sesiones.", + "legend": "Leyenda", + "legendDesc": "A se ejecuta antes que B (conteo etiquetado)", + "frequency": "Frecuencia", + "meaning": "Significado", + "times": " veces", + "ranAfter": " se ejecutó después de ", + "spawns": " inicios", + "spawned": "Iniciado", + "inSessions": "En sesiones", + "ariaLabel": "Grafo de pipeline de agentes", + "tooltip": { + "agentType": "Tipo de agente", + "edge": "Borde secuencial", + "shareOfAllSpawns": "Participación de todos los inicios", + "sequentialPairs": "Pares secuenciales", + "totalSpawnsFmt": "{{id}} inicios totales", + "shareOfSrcFmt": "Participación de {{source}} → siguiente", + "shareOfTgtFmt": "Participación de anterior → {{target}}", + "edgeDescFmt": "{{target}} se ejecutó inmediatamente después de {{source}} {{count}} vez/veces en todas las sesiones. Cuanto más gruesa la flecha, más frecuente fue esta transferencia. Úsalo para detectar cadenas de delegación habituales en tus flujos de trabajo.", + "nodeDescFmt": "{{id}} se ejecutó {{total}} vez/veces en {{sessions}} sesión(es); su tasa de éxito es {{rate}}% ({{health}}). El tamaño del círculo codifica el total de inicios; las flechas muestran qué tipos de agentes tienden a ejecutarse antes o después.", + "health": { + "perfect": "casi perfecto", + "healthy": "saludable", + "shaky": "inestable", + "failing": "fallando con frecuencia" + } + } + }, + "effectiveness": { + "title": "Efectividad de Subagentes", + "subtitle": "Métricas de rendimiento por tipo de agente", + "success": "Éxito", + "sessions": "Sesiones", + "avgDuration": "Duración Promedio", + "weeklyActivity": "Actividad semanal", + "noData": "Sin datos de subagentes disponibles", + "successRateAria": "Tasa de éxito: {{rate}}%", + "weeklyActivityAria": "Sparkline de actividad semanal", + "sessionCount_one": "{{count}} sesión", + "sessionCount_other": "{{count}} sesiones" + }, + "patterns": { + "title": "Patrones de Flujo de Trabajo Detectados", + "subtitle": "Secuencias comunes de orquestación de agentes", + "noData": "Sin patrones detectados aún", + "noDataDesc": "Los patrones aparecen una vez que múltiples sesiones comparten la misma secuencia de agentes.", + "solo": "solitario (sin subagentes)", + "label": "Patrones de Flujo", + "detail": { + "clickHint": "Haz clic para más detalles", + "stepsHeading": "Secuencia completa de pasos", + "statsHeading": "Estadísticas", + "stepsCount_one": "{{count}} paso", + "stepsCount_other": "{{count}} pasos", + "uniqueAgents": "Tipos de agentes únicos", + "occurrences": "Sesiones que coinciden con este patrón", + "shareOfSessions": "Participación de todas las sesiones", + "narrativeHeading": "Qué significa esto", + "suggestionHeading": "Sugerencia", + "narrative": { + "soloFmt": "Sesiones que se ejecutaron solo con {{first}} - sin delegación a otros tipos de agentes.", + "twoStepFmt": "Una transferencia de dos pasos: {{first}} delega directamente a {{last}}, sin más ramificaciones.", + "shortFmt": "Una cadena de {{count}} pasos que comienza en {{first}} y termina en {{last}}.", + "longFmt": "Una larga cadena de {{count}} pasos - comienza en {{first}}, atraviesa varios agentes y aterriza en {{last}}.", + "loopHintFmt": " {{agent}} aparece más de una vez en esta secuencia - típico de un bucle de verificación o revisión.", + "dominant": " Este es el flujo de trabajo dominante en tu proyecto - más de la mitad de las sesiones lo siguen.", + "common": " Este es un flujo de trabajo común, que representa aproximadamente un cuarto de las sesiones.", + "regular": " Un flujo de trabajo reconocido, pero no el patrón mayoritario.", + "niche": " Un patrón de nicho que solo aparece ocasionalmente." + }, + "suggestion": { + "solo": "Ejecución solitaria - ¿un subagente de revisión de código o ejecutor de pruebas elevaría la calidad de estas sesiones?", + "shortChain": "Cadena corta. Si sigue recurriendo, nómbrala como un comando de barra, skill o flujo de trabajo con nombre para que sea fácil de reproducir.", + "mediumChain": "Suficientemente frecuente para formalizar. Un flujo de trabajo o plantilla con nombre haría este patrón reutilizable.", + "longChain": "Cadena larga - revisa si cada salto es necesario, o si algunos agentes podrían fusionarse u omitirse.", + "loop": "Bucle detectado. Confirma que el paso repetido es una verificación intencional en lugar de un reintento silencioso de una llamada fallida." + } + } + }, + "modelDelegation": { + "title": "Flujo de Delegación de Modelos", + "subtitle": "Cómo los modelos se enrutan a través de las jerarquías de agentes", + "mainModels": "MODELOS PRINCIPALES", + "subagentModels": "MODELOS DE SUBAGENTES", + "noData": "Sin datos de delegación de modelos disponibles", + "agentsCount_one": "{{count}} agente", + "agentsCount_other": "{{count}} agentes", + "tokensCount": "{{tokens}} tokens", + "sessionsCount_one": "{{count}} sesión", + "sessionsCount_other": "{{count}} sesiones", + "ariaLabel": "Diagrama de flujo de delegación de modelos", + "tooltip": { + "mainModel": "Modelo principal", + "subagentModel": "Modelo de subagente", + "agentRuns": "Ejecuciones de agentes", + "shareOfAll": "Participación de todos los agentes", + "sessionsOnModel": "Sesiones en este modelo", + "totalTokens": "Total de tokens", + "family": { + "opus": "Opus - nivel de mayor capacidad; mejor para razonamiento complejo, contexto más largo, más costoso por token.", + "sonnet": "Sonnet - nivel equilibrado; buen valor predeterminado para la mayoría de los flujos de trabajo de codificación y uso de herramientas.", + "haiku": "Haiku - nivel más rápido y barato; ideal para subagentes cortos y sensibles a la latencia.", + "other": "Modelo no Anthropic o no reconocido - queda fuera de las familias estándar Opus/Sonnet/Haiku." + }, + "lines": { + "main": "Las líneas de la derecha muestran los modelos de subagentes a los que este modelo principal delegó trabajo.", + "sub": "Las líneas de la izquierda muestran los modelos principales que delegaron trabajo a este modelo de subagente." + } + } + }, + "errorPropagation": { + "title": "Mapa de Propagación de Errores", + "subtitle": "Dónde se agrupan los errores en la profundidad de la jerarquía de agentes", + "noErrors": "No se registraron errores", + "allSuccess": "Todas las sesiones se completaron con éxito", + "sessionsHadErrors": " sesiones tuvieron errores", + "sessionsErrorSummary": "{{errorSessions}} de {{totalSessions}} sesiones tuvieron errores", + "agentErrors": " error(es) a nivel de agente en toda la jerarquía", + "sessionErrorsOnly": "Solo errores a nivel de sesión", + "errorsByDepth": "Errores por profundidad de jerarquía", + "errorProneTypes": "Tipos de agentes propensos a errores", + "apiSessionErrors": "Errores de API y sesión", + "depthLabels": { + "sessionMain": "Sesión / Principal", + "directSubagent": "Subagente Directo", + "nested": "Anidado (profundidad 2)", + "deep": "Profundo (profundidad 3+)" + } + }, + "concurrency": { + "title": "Línea de Tiempo de Concurrencia de Agentes", + "subtitle": "Patrones de ejecución paralela de agentes - Muestra cómo se superponen los agentes en el tiempo", + "noData": "Sin datos de concurrencia", + "noDataDesc": "Los datos de concurrencia aparecen una vez que se registren sesiones con subagentes.", + "sessions": "Sesiones", + "timing": "Temporización", + "max": " máx", + "sessionInfo_one": "{{count}} sesión - activo {{from}}%-{{to}}% de la sesión", + "sessionInfo_other": "{{count}} sesiones - activo {{from}}%-{{to}}% de la sesión", + "tooltip": { + "lane": "Carril de concurrencia", + "sessionsWith": "Sesiones con este agente", + "avgStart": "Inicio promedio en sesión", + "avgEnd": "Fin promedio en sesión", + "barHint": "La longitud de la barra es proporcional a cuántas sesiones presentan este tipo de agente. Los porcentajes de temporización son promedios de esas sesiones.", + "timing": { + "wholeSession": "Activo durante casi toda la sesión - se ejecuta desde el inicio hasta el final.", + "frontLoadedFmt": "Carga frontal: típicamente activo desde el inicio de la sesión hasta ~{{end}}% del camino.", + "backLoadedFmt": "Carga trasera: típicamente se activa alrededor del {{start}}% de la sesión y permanece hasta el final.", + "tightFmt": "Alcance estrecho: se ejecuta en una banda estrecha entre {{start}}% y {{end}}% de la línea de tiempo de la sesión.", + "midSessionFmt": "Trabajo a mitad de sesión: se ejecuta aproximadamente del {{start}}% al {{end}}% de la línea de tiempo de la sesión." + } + } + }, + "complexity": { + "title": "Dispersión de Complejidad de Sesiones", + "subtitle": "Duración vs conteo de agentes vs tokens - Tamaño de burbuja = uso de tokens", + "noData": "Sin datos de complejidad de sesiones", + "noDataDesc": "Las sesiones aparecerán aquí una vez que se completen con actividad de agentes.", + "duration": "Duración", + "agentCount": "Conteo de Agentes", + "ariaLabel": "Gráfico de dispersión de complejidad de sesiones", + "tooltip": { + "duration": "Duración:", + "agents": "Agentes:", + "subagents": "Subagentes:", + "tokens": "Tokens:", + "model": "Modelo:" + } + }, + "compaction": { + "title": "Análisis de Impacto de Compresión", + "subtitle": "Cómo se distribuye la compresión de contexto en tus sesiones", + "help": "Cuando la ventana de contexto de una sesión se llena, Claude Code comprime el historial más antiguo en un resumen. Cada compresión es uno de esos eventos.", + "noData": "Sin compresiones registradas", + "totalCompactions": "Total de compresiones", + "sessionsAffected": "Sesiones afectadas", + "ofTotal": "de {{total}}", + "avgPerSession": "Promedio / sesión afectada", + "peakSession": "Máximo en una sesión", + "tokensRecovered": "Tokens Recuperados", + "distribution": "Sesiones por conteo de compresiones", + "xAxis": "Compresiones por sesión", + "yAxis": "Sesiones", + "summary": "{{affected}} de {{total}} sesiones ({{pct}}%) usaron compresión de contexto.", + "tokensFreed": "La compresión liberó ~{{tokens}} tokens de contexto.", + "ariaLabel": "Número de sesiones por conteo de compresiones", + "tipTitle": "Comprimido {{count}}x", + "tipDetail": "{{sessions}} sesiones · {{pct}}% de las afectadas" + }, + "drillIn": { + "title": "Profundizar en Sesión", + "subtitle": "Selecciona una sesión del gráfico de dispersión o usa el menú desplegable para explorar", + "searchPlaceholder": "Buscar sesiones...", + "noSessionSelected": "Sin sesión seleccionada", + "noSessionDesc": "Busca y selecciona una sesión arriba, o haz clic en una burbuja en el gráfico de dispersión, para profundizar en su árbol de agentes, línea de tiempo de herramientas y secuencia de eventos.", + "failedLoad": "No se pudo cargar la sesión", + "loading": "Cargando...", + "loadMore": "Cargar más", + "noMatch": "Ninguna sesión coincide con tu búsqueda.", + "notFound": "No se encontraron sesiones.", + "unknownModel": "modelo desconocido", + "closePanel": "Cerrar panel de profundización", + "close": "Cerrar", + "tabs": { + "agentTree": "Árbol de Agentes", + "toolTimeline": "Línea de Tiempo de Herramientas", + "eventSequence": "Secuencia de Eventos" + }, + "noAgentTree": "Sin datos de árbol de agentes disponibles.", + "noToolEvents": "No se registraron eventos de herramientas.", + "noEvents": "No se registraron eventos para esta sesión.", + "showingOf": "Mostrando 100 de {{total}} eventos", + "sessionInfo": " sesión(es) - activo {{from}}%-{{to}}% de la sesión", + "sortedByCompaction": " sesión(es) (ordenadas por conteo de compresiones)" + } +} diff --git a/client/src/i18n/locales/ko/nav.json b/client/src/i18n/locales/ko/nav.json index d2923bcc..d35dd313 100644 --- a/client/src/i18n/locales/ko/nav.json +++ b/client/src/i18n/locales/ko/nav.json @@ -58,12 +58,14 @@ "en": "영어", "zh": "중국어", "vi": "베트남어", - "ko": "한국어" + "ko": "한국어", + "es": "스페인어" }, "languageShort": { "en": "EN", "zh": "中文", "vi": "VI", - "ko": "한국어" + "ko": "한국어", + "es": "ES" } } diff --git a/client/src/i18n/locales/vi/nav.json b/client/src/i18n/locales/vi/nav.json index 2fc01971..306f4621 100644 --- a/client/src/i18n/locales/vi/nav.json +++ b/client/src/i18n/locales/vi/nav.json @@ -58,12 +58,14 @@ "en": "English", "zh": "Tiếng Trung", "vi": "Tiếng Việt", - "ko": "Tiếng Hàn" + "ko": "Tiếng Hàn", + "es": "Tiếng Tây Ban Nha" }, "languageShort": { "en": "EN", "zh": "中文", "vi": "VI", - "ko": "한국어" + "ko": "한국어", + "es": "ES" } } diff --git a/client/src/i18n/locales/zh/nav.json b/client/src/i18n/locales/zh/nav.json index 5fb3003c..7e6a2eeb 100644 --- a/client/src/i18n/locales/zh/nav.json +++ b/client/src/i18n/locales/zh/nav.json @@ -58,12 +58,14 @@ "en": "英文", "zh": "中文", "vi": "越南语", - "ko": "韩语" + "ko": "韩语", + "es": "西班牙语" }, "languageShort": { "en": "EN", "zh": "中文", "vi": "VI", - "ko": "한국어" + "ko": "한국어", + "es": "ES" } } diff --git a/client/src/lib/__tests__/format.test.ts b/client/src/lib/__tests__/format.test.ts index b3d55c64..6ad73036 100644 --- a/client/src/lib/__tests__/format.test.ts +++ b/client/src/lib/__tests__/format.test.ts @@ -115,6 +115,9 @@ describe("locale-aware date formatting", () => { await i18n.changeLanguage("ko"); expect(getCurrentLocale()).toBe("ko-KR"); + await i18n.changeLanguage("es"); + expect(getCurrentLocale()).toBe("es-ES"); + await i18n.changeLanguage("en"); expect(getCurrentLocale()).toBe("en-US"); }); diff --git a/client/src/lib/format.ts b/client/src/lib/format.ts index 3a49591b..12d04b78 100644 --- a/client/src/lib/format.ts +++ b/client/src/lib/format.ts @@ -11,9 +11,9 @@ * value is unambiguously UTC, then relies on `toLocale*` to render it back in the * viewer's local zone. Timestamps that already carry a `Z` or `±HH:MM` offset are * parsed as-is. - * 2. **Locale awareness.** The dashboard ships four UI languages (English, Chinese, - * Vietnamese, Korean). {@link getCurrentLocale} maps the active i18next language to a - * BCP-47 tag (`en-US`, `zh-CN`, `vi-VN`, `ko-KR`) that the `Intl`/`toLocale*` APIs + * 2. **Locale awareness.** The dashboard ships five UI languages (English, Chinese, + * Vietnamese, Korean, Spanish). {@link getCurrentLocale} maps the active i18next language to a + * BCP-47 tag (`en-US`, `zh-CN`, `vi-VN`, `ko-KR`, `es-ES`) that the `Intl`/`toLocale*` APIs * understand, so month names, AM/PM vs. 24-hour clocks, digit grouping and currency * punctuation all follow the chosen language. Relative-time strings ("5m ago") are * instead produced from translated i18next keys rather than `Intl.RelativeTimeFormat`. @@ -188,13 +188,13 @@ function parseDate(iso: string): Date { return new Date(iso.replace(" ", "T") + "Z"); } -/** The four UI languages the dashboard localizes formatting for. */ -type SupportedLanguage = "en" | "zh" | "vi" | "ko"; +/** The five UI languages the dashboard localizes formatting for. */ +type SupportedLanguage = "en" | "zh" | "vi" | "ko" | "es"; /** - * Resolve the active i18next language down to one of the four {@link SupportedLanguage} + * Resolve the active i18next language down to one of the five {@link SupportedLanguage} * codes, defaulting to English for anything unrecognized. - * @returns `"en" | "zh" | "vi" | "ko"`. + * @returns `"en" | "zh" | "vi" | "ko" | "es"`. * @remarks Reads `resolvedLanguage` first (the language i18next actually settled on after * detection/fallback), then `language`, then `"en"`. The value is lowercased and its * region subtag stripped (`split("-")[0]`), so `"en-US"`, `"zh-Hans-CN"` etc. collapse @@ -202,7 +202,13 @@ type SupportedLanguage = "en" | "zh" | "vi" | "ko"; */ function getCurrentLanguage(): SupportedLanguage { const language = (i18n.resolvedLanguage ?? i18n.language ?? "en").toLowerCase().split("-")[0]; - if (language === "zh" || language === "vi" || language === "ko" || language === "en") { + if ( + language === "zh" || + language === "vi" || + language === "ko" || + language === "es" || + language === "en" + ) { return language; } return "en"; // any other/undetected language -> English @@ -212,7 +218,7 @@ function getCurrentLanguage(): SupportedLanguage { * Maps the active i18next language to a `toLocaleString` BCP-47 locale tag, * so date/number formatting matches the UI's chosen language. Falls back to * "en-US" for any language not explicitly supported. - * @returns One of `"zh-CN" | "vi-VN" | "ko-KR" | "en-US"`. + * @returns One of `"zh-CN" | "vi-VN" | "ko-KR" | "es-ES" | "en-US"`. * @remarks The region subtag matters: it drives clock convention (English/Korean use * 12-hour AM/PM here via the `hour: "2-digit"` options, Chinese/Vietnamese lean 24-hour), * month-name localization, and digit-group/decimal separators used by {@link fmtCostFull}. @@ -222,6 +228,7 @@ export function getCurrentLocale(): string { if (language === "zh") return "zh-CN"; // Simplified Chinese (mainland) if (language === "vi") return "vi-VN"; // Vietnamese if (language === "ko") return "ko-KR"; // Korean + if (language === "es") return "es-ES"; // Spanish (Spain) return "en-US"; // default: US English } diff --git a/docs/I18N.md b/docs/I18N.md index 40725b2e..3166035e 100644 --- a/docs/I18N.md +++ b/docs/I18N.md @@ -2,7 +2,7 @@ This guide documents how localization works in the Agent Dashboard, including architecture, resources, runtime behavior, testing, and rollout. -**Supported languages:** English (`en`), Chinese (`zh`), Vietnamese (`vi`), Korean (`ko`) +**Supported languages:** English (`en`), Chinese (`zh`), Vietnamese (`vi`), Korean (`ko`), Spanish (`es`) --- @@ -36,9 +36,9 @@ flowchart TB ``` **Key runtime facts** -- `supportedLngs`: `["en", "zh", "vi", "ko"]` +- `supportedLngs`: `["en", "zh", "vi", "ko", "es"]` - `fallbackLng`: `"en"` -- `nonExplicitSupportedLngs`: `true` (e.g. `vi-VN` resolves to `vi`) +- `nonExplicitSupportedLngs`: `true` (e.g. `es-ES` resolves to `es`) - Detection order: `localStorage` → `navigator` --- @@ -51,6 +51,7 @@ Translation resources are stored per language and namespace: - `client/src/i18n/locales/zh/*.json` - `client/src/i18n/locales/vi/*.json` - `client/src/i18n/locales/ko/*.json` +- `client/src/i18n/locales/es/*.json` Active namespaces: - `common` @@ -71,8 +72,8 @@ erDiagram KEY ||--o{ TRANSLATION : maps_to LANGUAGE { - string code "en|zh|vi" - string locale "en-US|zh-CN|vi-VN|ko-KR" + string code "en|zh|vi|ko|es" + string locale "en-US|zh-CN|vi-VN|ko-KR|es-ES" } NAMESPACE { string name "common|nav|dashboard|..." @@ -89,7 +90,7 @@ erDiagram **Strategy notes** - Keep namespace boundaries page/domain focused. -- Keep key parity across `en`, `zh`, `vi` files for the same namespace. +- Keep key parity across `en`, `zh`, `vi`, `ko`, and `es` files for the same namespace. - Keep fallback behavior deterministic by ensuring `en` is always complete. --- @@ -116,7 +117,7 @@ Use stable semantic keys, not English sentence literals. ```mermaid classDiagram class I18nConfig { - +supportedLngs: ["en","zh","vi"] + +supportedLngs: ["en","zh","vi","ko","es"] +fallbackLng: "en" +defaultNS: "common" +detectionOrder: ["localStorage","navigator"] @@ -159,7 +160,7 @@ classDiagram ## 4) Language Detection and Switching Flow -The sidebar language controls call `i18n.changeLanguage()` and UI updates reactively through `useTranslation`. +The sidebar language control is the shared custom `Select` dropdown used by the Run Claude page. It calls `i18n.changeLanguage()` and the UI updates reactively through `useTranslation`. ```mermaid sequenceDiagram @@ -170,8 +171,8 @@ sequenceDiagram participant NS as Locale Resources participant UI as React Components - U->>SB: Click language button (EN/ZH/VI/KO) - SB->>I: changeLanguage("vi") + U->>SB: Choose a language from the custom dropdown + SB->>I: changeLanguage("es") I->>NS: Resolve namespace bundles NS-->>I: Return translations I->>LD: Persist i18nextLng in localStorage @@ -187,6 +188,7 @@ stateDiagram-v2 Detecting --> Loaded_zh: localStorage/navigator resolves zh Detecting --> Loaded_vi: localStorage/navigator resolves vi Detecting --> Loaded_ko: localStorage/navigator resolves ko + Detecting --> Loaded_es: localStorage/navigator resolves es Detecting --> Loaded_en: unsupported locale -> fallback en Loaded_en --> Loaded_zh: user switches to zh @@ -197,6 +199,8 @@ stateDiagram-v2 Loaded_vi --> Loaded_zh: user switches to zh Loaded_en --> Loaded_ko: user switches to ko Loaded_ko --> Loaded_en: user switches to en + Loaded_en --> Loaded_es: user switches to es + Loaded_es --> Loaded_en: user switches to en ``` --- @@ -208,6 +212,8 @@ Formatting utilities are centralized in `client/src/lib/format.ts`. - `en` → `en-US` - `zh` → `zh-CN` - `vi` → `vi-VN` +- `ko` → `ko-KR` +- `es` → `es-ES` `formatTime`, `formatDateTime`, and `fmtCostFull` use locale-aware `toLocale*` APIs. Timestamp parsing normalizes timezone-less SQLite datetime strings to UTC before display formatting. @@ -222,10 +228,14 @@ flowchart LR D -->|en| E["Locale en-US"] D -->|zh| F["Locale zh-CN"] D -->|vi| G["Locale vi-VN"] - E --> H["toLocaleTimeString / toLocaleString"] - F --> H - G --> H - H --> I["Localized date/time/number output"] + D -->|ko| H["Locale ko-KR"] + D -->|es| J["Locale es-ES"] + E --> K["toLocaleTimeString / toLocaleString"] + F --> K + G --> K + H --> K + J --> K + K --> I["Localized date/time/number output"] ``` --- @@ -248,11 +258,11 @@ npm run test:client | Area | What to verify | Example | |---|---|---| -| Resource parity | Same key coverage across `en/zh/vi/ko` | Missing key detection in CI | -| Locale fallback | Unknown locales fall back to `en` | `vi-VN` resolves to `vi` | +| Resource parity | Same key coverage across `en/zh/vi/ko/es` | Missing key detection in CI | +| Locale fallback | Unknown locales fall back to `en` | `es-ES` resolves to `es` | | Terminology consistency | Canonical terms stay stable | `Agent`/`Subagent` expectations | -| Date/number formatting | Locale-specific output shape | `zh-CN`, `vi-VN`, `ko-KR` formatting | -| Runtime switching | UI rerenders without reload | Sidebar language toggle | +| Date/number formatting | Locale-specific output shape | `zh-CN`, `vi-VN`, `ko-KR`, `es-ES` formatting | +| Runtime switching | UI rerenders without reload | Sidebar custom language dropdown | --- @@ -261,7 +271,7 @@ npm run test:client | Symptom | Likely cause | Resolution | |---|---|---| | UI stays in old language after switch | Cached key or stale component state | Confirm `i18n.changeLanguage(...)` is called and component uses `useTranslation` | -| Unexpected fallback to English | Unsupported locale code | Ensure code normalizes to `en|zh|vi|ko` and key exists in target namespace | +| Unexpected fallback to English | Unsupported locale code | Ensure code normalizes to `en|zh|vi|ko|es` and key exists in target namespace | | Missing text on one page | Namespace file key missing | Add key to all language files for that namespace | | Date/time looks wrong | Locale mapping or timezone parse issue | Verify `getCurrentLocale()` and `parseDate()` behavior | | Inconsistent term translation | Manual translation drift | Enforce glossary and update locale tests | @@ -278,7 +288,7 @@ gantt section Resource Preparation Lock key inventory :a1, 2026-01-01, 3d - Fill en/zh/vi/ko namespace files :a2, after a1, 5d + Fill en/zh/vi/ko/es namespace files :a2, after a1, 5d section Runtime Integration Wire detection + persistence :b1, after a2, 2d @@ -295,10 +305,10 @@ gantt ``` ### Operational checklist -- [ ] Confirm all namespaces exist for `en`, `zh`, `vi`, `ko` +- [ ] Confirm all namespaces exist for `en`, `zh`, `vi`, `ko`, `es` - [ ] Confirm key parity across all locale JSON files - [ ] Confirm language switching works in collapsed and expanded sidebar modes -- [ ] Confirm fallback behavior for region tags (e.g., `vi-VN`, `zh-CN`) +- [ ] Confirm fallback behavior for region tags (e.g., `es-ES`, `vi-VN`, `zh-CN`) - [ ] Confirm date/time/currency formatting for all supported languages - [ ] Confirm client tests pass before release - [ ] Confirm docs references are updated (`README`, `ARCHITECTURE`, `docs/README`) diff --git a/docs/README.md b/docs/README.md index 8ee3fdf7..1c329fc0 100644 --- a/docs/README.md +++ b/docs/README.md @@ -219,11 +219,11 @@ graph TB | **Database** | SQLite 3 (better-sqlite3 or node:sqlite) | | **Integration** | Claude Code Hooks, MCP Server | -### Internationalization Support (en/zh/vi/ko) +### Internationalization Support (en/zh/vi/ko/es) ```mermaid flowchart LR - A["User language preference
en / zh / vi / ko"] --> B["i18next detector
localStorage + navigator"] + A["User language preference
en / zh / vi / ko / es"] --> B["i18next detector
localStorage + navigator"] B --> C["Namespace JSON resources"] C --> D["React useTranslation hooks"] D --> E["Localized UI + a11y labels"] @@ -231,7 +231,7 @@ flowchart LR F --> G["formatModelName() — human-friendly model display"] ``` -Supported language codes are explicitly `en`, `zh`, and `vi`. Use [I18N.md](./I18N.md) for architecture details, naming conventions, language switching flow, localization behavior, and rollout guidance. +Supported language codes are explicitly `en`, `zh`, `vi`, `ko`, and `es`. The sidebar uses a custom language dropdown that scales as locales are added. Use [I18N.md](./I18N.md) for architecture details, naming conventions, language switching flow, localization behavior, and rollout guidance. --- diff --git a/index.html b/index.html index 129152f7..d4704440 100644 --- a/index.html +++ b/index.html @@ -2573,8 +2573,8 @@

Workflow datasets

-
3
-
Languages (en/zh/vi/ko)
+
5
+
Languages (en/zh/vi/ko/es)
@@ -2755,7 +2755,7 @@

Plugin marketplace

🌐

Multi-language UI

- English, Chinese, Vietnamese, and Korean - coverage extends end-to-end through every chart + English, Chinese, Vietnamese, Korean, and Spanish - coverage extends end-to-end through every chart tooltip, Settings flow, Workflow narrative, Config Explorer tab, and Run page.

diff --git a/sw.js b/sw.js index a76e5fef..ed70cee3 100644 --- a/sw.js +++ b/sw.js @@ -4,7 +4,7 @@ * @author Son Nguyen */ -const CACHE_NAME = "landing-v1"; +const CACHE_NAME = "landing-v2"; const PRECACHE = ["./", "./index.html", "./favicon.svg", "./og-image.svg", "./manifest.json"]; self.addEventListener("install", (event) => { diff --git a/wiki/i18n-content.js b/wiki/i18n-content.js index b171f427..4f1ad457 100644 --- a/wiki/i18n-content.js +++ b/wiki/i18n-content.js @@ -1320,6 +1320,10 @@ window.__WIKI_CONTENT_I18N = { 'Prometheus 文本展示格式(v0.0.4)的实时计数器:按状态划分的 sessions 与 agents、事件总数、按种类累计的 token、已连接的 WebSocket 客户端、已配置的远程数据源、进程运行时长与 RSS,以及构建版本——以便将 CCAM 抓取到 Prometheus / Grafana。只读,且——由于位于 /api 之下——处于 DNS 重绑定 Host 头防护和可选的 DASHBOARD_TOKEN 之后:非回环抓取器(例如 Docker 中通过 host.docker.internal 访问的 Prometheus)必须用 DASHBOARD_ALLOWED_HOSTS 加入白名单,否则抓取会返回 403 EBADHOST,并且在设置了令牌时必须发送该令牌。一个开箱即用、预置了 "CCAM — Overview" 仪表盘的 Prometheus + Grafana 组合位于 monitoring/cd monitoring && docker compose up -d;Grafana 在 3000 端口)。', "Comma-separated extra Host-header names allowed past the DNS-rebinding guard — needed for a non-loopback client or scraper, such as Prometheus in Docker reaching /api/metrics via host.docker.internal; an unlisted host is rejected with 403 EBADHOST": "逗号分隔的额外 Host 头名称,允许其通过 DNS 重绑定防护——非回环客户端或抓取器需要它,例如 Docker 中通过 host.docker.internal 访问 /api/metrics 的 Prometheus;未列入的主机会被拒绝并返回 403 EBADHOST", + "The entire UI ships in five languages — English, 简体中文, Tiếng Việt, 한국어, and Español — built on i18next + react-i18next with i18next-browser-languagedetector. Coverage is end-to-end: every page, chart tooltip, Settings flow, Workflow narrative, Config Explorer tab, Run page, and the Alerts rule-help tooltips + webhook setup guides are translated. Switch languages from the sidebar's custom language dropdown — the choice persists in localStorage.": + "整个 UI 提供五种语言——English、简体中文、Tiếng Việt、한국어 和 Español,基于 i18next + react-i18nexti18next-browser-languagedetector 构建。覆盖范围端到端:每个页面、图表工具提示、Settings 流程、Workflow 叙述、Config Explorer 标签页、Run 页面,以及 Alerts 规则帮助工具提示和 webhook 设置指南均已翻译。通过侧边栏的自定义语言下拉菜单切换语言,选择会保存在 localStorage 中。", + 'Every alert-rule field has a help tooltip — the event-type, tool-name, and summary-contains fields include example chips of real hook events and built-in tool names. Each webhook provider ships a collapsible step-by-step setup guide linking to the official docs. A one-click "Send test" probe fires a synthetic alert and reports the delivery result inline, and targets can be scoped to specific rules. Fully localized (en / zh / vi / ko / es).': + "每个告警规则字段都有帮助提示——event-type、tool-name 和 summary-contains 字段包含真实 hook 事件和内置工具名称的示例标签。每个 webhook 提供方都附带一份可折叠的分步设置指南,并链接到官方文档。一键 “Send test” 探测会触发一个合成告警并就地报告投递结果,且目标可限定到特定规则。完全本地化(en / zh / vi / ko / es)。", "Server-paginated table of every recorded session — each page fetches only its slice so cost computation stays bounded no matter how many sessions exist. Case-insensitive search across id, name, and cwd runs server-side with a 300 ms debounce; the status filter composes with search for precise narrowing. A searchable checkbox project picker supports selecting multiple directories; long paths remain available in full, while compact trigger text keeps the filter bar readable. Sorting uses the same custom dropdown pattern. Each row shows the session's real name (synced live from the transcript — a /rename or claude -n title, else the auto title, else the first user prompt, with a short-ID fallback), status badge, agent count, duration, model, and estimated cost. Click any row to drill into the full session detail view with conversation transcript and agent hierarchy.": "服务端分页的表格,列出每一个已记录的会话。每一页只获取对应的数据片段,因此无论会话数量多少,成本计算都保持有界。针对 idnamecwd 的不区分大小写搜索在服务端运行,并带有 300 ms 防抖;状态过滤器可与搜索组合以精确缩小范围。可搜索的复选框项目选择器支持选择多个目录;完整长路径仍可查看,紧凑的触发器文字让筛选栏保持易读。排序使用相同的自定义下拉模式。每一行显示会话的真实名称(从 transcript 实时同步:/renameclaude -n 标题,否则使用自动标题,再否则使用首条用户 prompt,并回退到短 ID)、状态徽章、agent 数量、时长、模型和预估成本。点击任意行即可深入查看完整的会话详情视图,包含对话记录和 agent 层级。", }, @@ -2656,6 +2660,10 @@ window.__WIKI_CONTENT_I18N = { 'Các bộ đếm trực tiếp ở định dạng Prometheus text-exposition (v0.0.4): sessions và agents theo trạng thái, tổng số sự kiện, token tích lũy theo loại, số client WebSocket đang kết nối, các nguồn dữ liệu từ xa đã cấu hình, thời gian chạy tiến trình và RSS, cùng phiên bản build — để CCAM có thể được scrape vào Prometheus / Grafana. Chỉ-đọc, và — vì nằm dưới /api — nằm sau lớp bảo vệ Host-header chống DNS-rebinding và DASHBOARD_TOKEN tùy chọn: một scraper không phải loopback (ví dụ Prometheus trong Docker qua host.docker.internal) phải được đưa vào danh sách cho phép bằng DASHBOARD_ALLOWED_HOSTS nếu không lần scrape sẽ trả về 403 EBADHOST, và phải gửi token khi có đặt token. Một bộ Prometheus + Grafana chạy-ngay với bảng điều khiển "CCAM — Overview" dựng sẵn nằm trong monitoring/ (cd monitoring && docker compose up -d; Grafana ở cổng 3000).', "Comma-separated extra Host-header names allowed past the DNS-rebinding guard — needed for a non-loopback client or scraper, such as Prometheus in Docker reaching /api/metrics via host.docker.internal; an unlisted host is rejected with 403 EBADHOST": "Các tên Host-header bổ sung, phân tách bằng dấu phẩy, được cho phép vượt qua lớp bảo vệ chống DNS-rebinding — cần cho một client hoặc scraper không phải loopback, chẳng hạn Prometheus trong Docker truy cập /api/metrics qua host.docker.internal; một host không có trong danh sách sẽ bị từ chối với 403 EBADHOST", + "The entire UI ships in five languages — English, 简体中文, Tiếng Việt, 한국어, and Español — built on i18next + react-i18next with i18next-browser-languagedetector. Coverage is end-to-end: every page, chart tooltip, Settings flow, Workflow narrative, Config Explorer tab, Run page, and the Alerts rule-help tooltips + webhook setup guides are translated. Switch languages from the sidebar's custom language dropdown — the choice persists in localStorage.": + "Toàn bộ giao diện có năm ngôn ngữ — English, 简体中文, Tiếng Việt, 한국어 và Español — được xây dựng trên i18next + react-i18next cùng i18next-browser-languagedetector. Phạm vi bao phủ là đầu-cuối: mọi trang, chú giải biểu đồ, luồng Settings, tường thuật Workflow, thẻ Config Explorer, trang Run, cùng chú giải trợ giúp quy tắc Alerts và hướng dẫn thiết lập webhook đều được dịch. Chọn ngôn ngữ từ menu thả xuống tùy chỉnh ở thanh bên; lựa chọn được lưu trong localStorage.", + 'Every alert-rule field has a help tooltip — the event-type, tool-name, and summary-contains fields include example chips of real hook events and built-in tool names. Each webhook provider ships a collapsible step-by-step setup guide linking to the official docs. A one-click "Send test" probe fires a synthetic alert and reports the delivery result inline, and targets can be scoped to specific rules. Fully localized (en / zh / vi / ko / es).': + "Mỗi trường của quy tắc cảnh báo đều có chú giải trợ giúp — các trường event-type, tool-name và summary-contains bao gồm các chip ví dụ về sự kiện hook thật và tên công cụ tích hợp sẵn. Mỗi nhà cung cấp webhook đi kèm một hướng dẫn thiết lập từng bước có thể thu gọn, liên kết tới tài liệu chính thức. Một thăm dò “Send test” bằng một cú nhấp sẽ kích hoạt một cảnh báo tổng hợp và báo cáo kết quả gửi ngay tại chỗ, và các đích có thể được giới hạn theo các quy tắc cụ thể. Được bản địa hóa hoàn toàn (en / zh / vi / ko / es).", "Server-paginated table of every recorded session — each page fetches only its slice so cost computation stays bounded no matter how many sessions exist. Case-insensitive search across id, name, and cwd runs server-side with a 300 ms debounce; the status filter composes with search for precise narrowing. A searchable checkbox project picker supports selecting multiple directories; long paths remain available in full, while compact trigger text keeps the filter bar readable. Sorting uses the same custom dropdown pattern. Each row shows the session's real name (synced live from the transcript — a /rename or claude -n title, else the auto title, else the first user prompt, with a short-ID fallback), status badge, agent count, duration, model, and estimated cost. Click any row to drill into the full session detail view with conversation transcript and agent hierarchy.": "Bảng phân trang phía máy chủ liệt kê mọi phiên đã ghi. Mỗi trang chỉ lấy phần dữ liệu của mình nên việc tính chi phí luôn có giới hạn, dù có bao nhiêu phiên. Tìm kiếm không phân biệt hoa thường trên id, namecwd chạy ở phía máy chủ với độ trễ chống dội 300 ms; bộ lọc trạng thái kết hợp với tìm kiếm để thu hẹp chính xác. Bộ chọn dự án dạng hộp kiểm có thể tìm kiếm hỗ trợ chọn nhiều thư mục; đường dẫn dài vẫn có thể xem đầy đủ, còn văn bản gọn trên nút giữ thanh lọc dễ đọc. Sắp xếp dùng cùng mẫu menu tùy chỉnh. Mỗi hàng hiển thị tên thật của phiên (đồng bộ trực tiếp từ bản ghi: tiêu đề /rename hoặc claude -n, nếu không thì tiêu đề tự động, nếu vẫn không có thì prompt đầu tiên của người dùng, với dự phòng là ID ngắn), huy hiệu trạng thái, số lượng agent, thời lượng, mô hình và chi phí ước tính. Nhấp vào bất kỳ hàng nào để đi sâu vào chế độ xem chi tiết đầy đủ của phiên với bản ghi hội thoại và phân cấp agent.", }, @@ -3976,10 +3984,1976 @@ window.__WIKI_CONTENT_I18N = { 'Prometheus 텍스트 노출 형식(v0.0.4)의 실시간 카운터: 상태별 sessions 및 agents, 총 이벤트 수, 종류별 누적 token, 연결된 WebSocket 클라이언트, 구성된 원격 데이터 소스, 프로세스 가동 시간 및 RSS, 그리고 빌드 버전 — CCAM을 Prometheus / Grafana로 스크레이핑할 수 있도록 합니다. 읽기 전용이며 — /api 아래에 있으므로 — DNS 리바인딩 Host 헤더 가드와 선택적 DASHBOARD_TOKEN 뒤에 위치합니다: 루프백이 아닌 스크레이퍼(예: host.docker.internal을 통해 접근하는 Docker 내 Prometheus)는 DASHBOARD_ALLOWED_HOSTS로 허용 목록에 추가해야 하며, 그렇지 않으면 스크레이프가 403 EBADHOST를 반환하고, 토큰이 설정된 경우 해당 토큰을 함께 보내야 합니다. "CCAM — Overview" 대시보드가 미리 프로비저닝된 즉시 실행 가능한 Prometheus + Grafana 스택이 monitoring/에 있습니다(cd monitoring && docker compose up -d; Grafana는 3000 포트).', "Comma-separated extra Host-header names allowed past the DNS-rebinding guard — needed for a non-loopback client or scraper, such as Prometheus in Docker reaching /api/metrics via host.docker.internal; an unlisted host is rejected with 403 EBADHOST": "쉼표로 구분된 추가 Host 헤더 이름으로, DNS 리바인딩 가드를 통과하도록 허용합니다 — 루프백이 아닌 클라이언트나 스크레이퍼에 필요하며, 예를 들어 host.docker.internal을 통해 /api/metrics에 접근하는 Docker 내 Prometheus가 있습니다; 목록에 없는 host는 403 EBADHOST로 거부됩니다", + "The entire UI ships in five languages — English, 简体中文, Tiếng Việt, 한국어, and Español — built on i18next + react-i18next with i18next-browser-languagedetector. Coverage is end-to-end: every page, chart tooltip, Settings flow, Workflow narrative, Config Explorer tab, Run page, and the Alerts rule-help tooltips + webhook setup guides are translated. Switch languages from the sidebar's custom language dropdown — the choice persists in localStorage.": + "전체 UI는 다섯 가지 언어 — English, 简体中文, Tiếng Việt, 한국어, Español — 로 제공되며 i18next + react-i18nexti18next-browser-languagedetector를 기반으로 구축되었습니다. 모든 페이지, 차트 툴팁, Settings 흐름, Workflow 내러티브, Config Explorer 탭, Run 페이지, Alerts 규칙 도움말 툴팁과 webhook 설정 가이드까지 전 영역이 번역됩니다. 사이드바의 맞춤 언어 드롭다운에서 전환할 수 있으며 선택은 localStorage에 저장됩니다.", + 'Every alert-rule field has a help tooltip — the event-type, tool-name, and summary-contains fields include example chips of real hook events and built-in tool names. Each webhook provider ships a collapsible step-by-step setup guide linking to the official docs. A one-click "Send test" probe fires a synthetic alert and reports the delivery result inline, and targets can be scoped to specific rules. Fully localized (en / zh / vi / ko / es).': + '모든 알림 규칙 필드에는 도움말 툴팁이 있습니다 — 이벤트 유형, 도구 이름, 요약 포함 필드에는 실제 훅 이벤트와 내장 도구 이름의 예시 칩이 함께 제공됩니다. 각 웹훅 프로바이더는 공식 문서로 연결되는 접을 수 있는 단계별 설정 가이드를 제공합니다. 클릭 한 번으로 실행하는 "테스트 전송" 기능은 가상의 알림을 발생시켜 전달 결과를 즉시 표시하며, 대상을 특정 규칙으로 범위를 제한할 수도 있습니다. en / zh / vi로 완전히 현지화되어 있습니다.', + "Server-paginated table of every recorded session — each page fetches only its slice so cost computation stays bounded no matter how many sessions exist. Case-insensitive search across id, name, and cwd runs server-side with a 300 ms debounce; the status filter composes with search for precise narrowing. A searchable checkbox project picker supports selecting multiple directories; long paths remain available in full, while compact trigger text keeps the filter bar readable. Sorting uses the same custom dropdown pattern. Each row shows the session's real name (synced live from the transcript — a /rename or claude -n title, else the auto title, else the first user prompt, with a short-ID fallback), status badge, agent count, duration, model, and estimated cost. Click any row to drill into the full session detail view with conversation transcript and agent hierarchy.": + "서버 페이지네이션 테이블은 기록된 모든 세션을 보여줍니다. 각 페이지는 해당 구간만 가져오므로 세션 수와 관계없이 비용 계산 범위가 제한됩니다. id, name, cwd에 대한 대소문자 구분 없는 검색은 300 ms 디바운스와 함께 서버 측에서 실행되며 상태 필터와 조합할 수 있습니다. 검색 가능한 체크박스 프로젝트 선택기로 여러 디렉터리를 고를 수 있고, 긴 경로는 전체를 확인할 수 있으며 간결한 트리거 텍스트가 필터 바를 읽기 쉽게 유지합니다. 정렬도 같은 맞춤 드롭다운 패턴을 사용합니다. 각 행은 세션의 실제 이름(트랜스크립트에서 실시간으로 동기화됨: /rename 또는 claude -n 제목, 없으면 자동 생성된 제목, 그마저도 없으면 첫 사용자 프롬프트, 최종적으로 짧은 ID로 대체), 상태 배지, 에이전트 수, 지속 시간, 모델, 예상 비용을 표시합니다. 행을 클릭하면 대화 트랜스크립트와 에이전트 계층 구조가 포함된 전체 세션 상세 화면으로 이동합니다.", + }, + es: { + '📊 Observability · Grafana — default home dashboard CCAM — Overview (four boards auto-provisioned): live fleet snapshot, database totals, breakdown charts, and rates from /api/metrics scrapes. Login admin / admin on port 3000': + '📊 Observabilidad · Grafana — panel de control de inicio predeterminado CCAM - Visión general (cuatro tableros provistos automáticamente): instantánea de la flota en vivo, totales de la base de datos, gráficos de desglose y tarifas de /api/metrics Rasguños. acceso admin / admin En el puerto 3000', + '🔥 Observability · Prometheus console — pre-built landing page at /consoles/index.html with live metric cards, session/token tables, and drill-down links into the Graph UI (Prometheus 3.x compatible — queries the HTTP API directly)': + '🔥 Observabilidad · Consola Prometheus — página de destino preconstruida en /consoles/index.html Con tarjetas métricas en vivo, tablas de sesiones/tokens y enlaces de profundización a la interfaz de usuario gráfica (compatible con Prometheus 3.x, consulta directamente la API HTTP)', + '📈 Observability · Prometheus Graph — run PromQL against scraped CCAM series (e.g. sum(ccam_sessions), ccam_events_total, rate(ccam_tokens_total[5m])) with starter expressions from the CCAM console and recording rules in monitoring/prometheus/ccam-rules.yml': + '📈 Observabilidad · Gráfico Prometheus - Ejecute PromQL contra series CCAM raspadas (por ejemplo, sum(ccam_sessions), ccam_events_total, rate(ccam_tokens_total[5m])) con expresiones iniciales de la consola CCAM y reglas de grabación en monitoring/prometheus/ccam-rules.yml', + '📊 Grafana · CCAM — Overview — default home dashboard after login (admin / admin on port 3000): fleet snapshot, database totals, breakdown charts, and rates from live /api/metrics scrapes — no sample or synthetic data': + '📊 Grafana · CCAM - Descripción general — panel de control de la página de inicio predeterminado después de iniciar sesión (admin / admin en el puerto 3000): instantánea de la flota, totales de la base de datos, gráficos de desglose y tarifas en vivo /api/metrics rasguños - sin muestras ni datos sintéticos', + '🔥 Prometheus · CCAM console — static HTML at /consoles/index.html (Prometheus 3.x compatible): live metric cards, session/token tables, and one-click Graph drill-down links that query the Prometheus HTTP API directly': + '🔥 Prometeo · Consola CCAM — HTML estático en /consoles/index.html (Compatible con Prometheus 3.x): tarjetas métricas en vivo, tablas de sesiones/tokens y enlaces de profundización gráfica con un solo clic que consultan la API HTTP de Prometheus directamente.', + '📈 Prometheus · Graph — ad-hoc PromQL against scraped CCAM series; starter expressions ship in the CCAM console and monitoring/README.md, with derived rates in monitoring/prometheus/ccam-rules.yml': + '📈 Prometeo · Gráfico — PromQL ad hoc contra series CCAM raspadas; las expresiones iniciales se envían en la consola CCAM y monitoring/README.md, con tasas derivadas en monitoring/prometheus/ccam-rules.yml', + "CCAM exposes a read-only Prometheus text-exposition endpoint at GET /api/metrics — sessions and agents by status, cumulative events and tokens, connected WebSocket clients, configured remote sources, process uptime/RSS, and build version — so the same dashboard you use for Claude Code monitoring can be scraped into your own observability stack. A turnkey stack lives in monitoring/: npm-managed binaries (no Homebrew/apt) or optional Docker Compose, with Grafana datasource and four dashboards auto-provisioned on first start.": + "CCAM expone un solo modo de lectura Exposición textual de Prometeo Punto final en GET /api/metrics — sesiones y agentes por estado, eventos acumulativos y tokens, clientes WebSocket conectados, fuentes remotas configuradas, tiempo de actividad del proceso/RSS y versión de la compilación, para que el mismo panel de control que utiliza para el monitoreo de Claude Code pueda escrapearse en su propia pila de observabilidad. Una pila llave en mano reside en monitoring/: binarios gestionados por npm (sin Homebrew/apt) o Docker Compose opcional, con fuente de datos Grafana y cuatro paneles de control provistos automáticamente en la primera iniciación.", + "Quick start (npm): run the dashboard on loopback, then npm run monitoring:install once and npm run monitoring:up. Open Grafana at http://localhost:3000 and Prometheus at http://localhost:9090. The pre-built CCAM console is at http://localhost:9090/consoles/index.html (also reachable from the Prometheus UI under Consoles). For an all-Docker path use npm run monitoring:docker:up or npm run docker:full:up for dashboard + Prometheus + Grafana together. Verify with npm run monitoring:verify — the ccam scrape target should read UP.": + "Inicio rápido (npm): Ejecuta el panel de control en bucle, luego npm run monitoring:install Una vez y npm run monitoring:up. Grafana en http://localhost:3000 Y Prometeo en http://localhost:9090. console CCAM preconstruida está en http://localhost:9090/consoles/index.html (también accesible desde la interfaz de usuario de Prometheus en Consolas). Para un uso de ruta todo-Docker npm run monitoring:docker:up Oregón npm run docker:full:up Para panel de control + Prometheus + Grafana juntos. Verifique con npm run monitoring:verify — el ccam El objetivo de la raspadura debería leer UP.", + "Four Grafana boards": "Cuatro tableros Grafana", + "CCAM — Overview (default home), CCAM — Sessions & Agents, CCAM — Tokens & Events, and CCAM — Platform — all provisioned from monitoring/grafana/dashboards/ with PromQL against your live scrape. Credentials default to admin / admin via monitoring/grafana.defaults.env.": + "CCAM - Visión general (página de inicio predeterminada), CCAM - Sesiones y agentes, CCAM - Tokens y eventos, y CCAM — Plataforma — todo provisto de monitoring/grafana/dashboards/ Con PromQL contra tu raspado en vivo. Las credenciales por defecto son admin / admin a través de monitoring/grafana.defaults.env.", + "Prometheus console": "Consola Prometheus", + "Prometheus 3.x dropped the legacy console template libraries, so CCAM ships a static HTML console at monitoring/prometheus/consoles/index.html that fetches /api/v1/query directly — live cards, session tables, and Graph links without Go-template errors on /consoles/index.html.": + "Prometheus 3.x eliminó las bibliotecas de plantillas de consola heredadas, por lo que CCAM incluye un Consola HTML estática att monitoring/prometheus/consoles/index.html Que recoge /api/v1/query Directamente: tarjetas en vivo, tablas de sesión y enlaces a gráficos sin errores de plantilla Go en /consoles/index.html.", + "Recording rules": "Reglas de grabación", + "monitoring/prometheus/ccam-rules.yml derives convenient rates and aggregates from raw ccam_* series (e.g. rate(ccam_tokens_total[5m])) so Grafana panels and ad-hoc Graph queries stay fast without hand-rolling every expression.": + "monitoring/prometheus/ccam-rules.yml Deriva tarifas convenientes y agrupa datos brutos ccam_* Serie (por ejemplo rate(ccam_tokens_total[5m])) por lo que los paneles de Grafana y las consultas gráficas ad hoc se mantienen rápidas sin tener que ejecutar manualmente cada expresión.", + "Scrape & auth guard": "Raspar y proteger la autenticación", + "Loopback scrapes (127.0.0.1:4820) work out of the box. When Prometheus runs in Docker and reaches the host via host.docker.internal, add that host to DASHBOARD_ALLOWED_HOSTS or the scrape returns 403 EBADHOST. If DASHBOARD_TOKEN is set, scrapers must send the same bearer token.": + "Rasguños de retroceso (127.0.0.1:4820) funciona de inmediato. Cuando Prometheus se ejecuta en Docker y llega al host a través de host.docker.internal, agrega ese anfitrión a DASHBOARD_ALLOWED_HOSTS O el rasguño vuelve 403 EBADHOST. si DASHBOARD_TOKEN Está establecido, los raspadores deben enviar el mismo token portador.", + "Full reference": "Referencia completa", + 'Commands, Docker vs npm paths, dashboard UIDs, starter PromQL, and troubleshooting (Grafana login reset, target DOWN) are documented in monitoring/README.md and the API reference entry for GET /api/metrics.': + 'Los comandos, rutas de Docker vs npm, UIDs del panel de control, PromQL de inicio y resolución de problemas (restablecimiento de la sesión de Grafana, objetivo DESPUESTO) están documentados en monitoring/README.md Y el Referencia de API Entrada para GET /api/metrics.', + "Pull Claude Code history from other machines over SSH. Each remote's ~/.claude/projects tree is mirrored via scp into a sandboxed staging directory, fed through the same importer as local history, and every session is tagged with its source. A background poller keeps remote data near-real-time, a global data-scope selector (Local only / All / a specific source) narrows the whole app, and sessions from a remote show a source badge. Auth defers entirely to the host's SSH stack — no passwords or secrets are stored. Managed in Settings → Remote Data Sources.": + "Sube la historia del código Claude de otras máquinas a través de SSH. Cada máquina remota ~/.claude/projects El árbol se refleja a través de scp En una carpeta de ensayo sandbox, alimentada por el mismo importador que el historial local, y cada sesión se etiqueta con su fuente. Un monitor de fondo mantiene los datos remotos casi en tiempo real, un selector global de alcance de datos (Solo local / Todos / una fuente específica) reduce toda la aplicación, y las sesiones de un remoto muestran un distintivo de fuente. La autenticación se deja completamente en manos de la pila SSH del host, no se almacenan contraseñas ni secretos. Administrado en Configuración → Fuentes de datos remotas.", + "Remote Data Sources": "Fuentes de datos remotas", + "List, add, and test SSH data sources; sync one source (or all when no id is given); and remove a source, optionally purging the sessions it imported": + "Listar, agregar y probar fuentes de datos SSH; sincronizar una fuente (o todas cuando no se proporciona un ID); y eliminar una fuente, opcionalmente borrando las sesiones que importó.", + "Beyond local history, the dashboard can pull Claude Code activity from other machines over SSH and fold it into the same views as your local sessions. Each remote's ~/.claude/projects tree is mirrored via scp (or wsl.exe + tar when Claude runs in WSL on a Windows SSH host) into a sandboxed staging directory, fed through the exact same importer used for local history, and every imported session is tagged with the source it came from. A background poller (DASHBOARD_REMOTE_SYNC_MS, default 15000 ms) keeps remote data near-real-time — adding or re-enabling a source also triggers an immediate pull — and successful syncs broadcast remote_data.updated plus per-session session_created / session_updated frames. A global data scope selector lets you narrow the entire app to local sessions only, all sources, or a specific machine. Sources are managed in Settings → Remote Data Sources.": + "Más allá de la historia local, el panel de control puede obtener la actividad de Claude Code de Otras máquinas a través de SSH Y cómpralo en las mismas vistas que tus sesiones locales. Cada remoto ~/.claude/projects El árbol se refleja a través de scp (o wsl.exe + tar Cuando Claude se ejecuta en WSL en un host SSH de Windows) en una carpeta de ensayo sandbox, alimentada por el mismo importador exacto utilizado para el historial local, y cada sesión importada se etiqueta con la fuente de la que procede. Un píldora de seguimiento en segundo plano (DASHBOARD_REMOTE_SYNC_MS, predeterminado 15000 ms) mantiene los datos remotos en tiempo real cercano, agregar o volver a habilitar una fuente también desencadena una extracción inmediata, y las sincronizaciones exitosas transmiten remote_data.updated Más por sesión session_created / session_updated Marco. Un global Ámbito de los datos El selector te permite restringir toda la aplicación a sesiones locales solo, todas las fuentes o una máquina específica. Las fuentes se gestionan en Configuración → Fuentes de datos remotas.", + "Each remote is mirrored over SSH, imported through the local pipeline, and tagged by source — the poller (default 15 s) keeps it near-real-time": + "Cada remoto se refleja a través de SSH, se importa a través del pipeline local y se etiqueta por fuente: el poller (por defecto 15 s) lo mantiene casi en tiempo real.", + "Add a source with an SSH destination — either a user@host pair or an alias defined in your ~/.ssh/config — plus an optional port, identity file, and remote home directory. Use Test connection to verify reachability before saving, then Sync now to pull immediately, or let the background poller do it on its own schedule. Removing a source can optionally purge the sessions it imported.": + "Agregue una fuente con un destino SSH, ya sea un user@host Pareja o un alias definido en tu ~/.ssh/config — además de un puerto opcional, un archivo de identidad y una carpeta de inicio remota. uso Prueba de conexión Para verificar la accesibilidad antes de guardar, luego Sincronizar ahora Para descargar inmediatamente, o dejar que el monitor de fondo lo haga a su propio ritmo. Eliminar una fuente puede purgar opcionalmente las sesiones que importó.", + "A global data-scope selector narrows the whole app: choose Local only, All sources, or one specific machine. The scope flows into every data view through a sources query parameter on the sessions, events, agents, stats, and analytics endpoints, and sessions imported from a remote carry a source badge so their origin is always visible.": + "Un selector de alcance de datos global reduce toda la aplicación: elija Solo local, todos Fuentes, o una máquina específica. El alcance fluye a través de cada vista de datos a través de un sources Parámetro de consulta en los puntos finales de sesiones, eventos, agentes, estadísticas y análisis, y las sesiones importadas desde una ubicación remota llevan un Insignia de fuente Así que su origen siempre es visible.", + "Authentication defers entirely to the host's own SSH stack — ~/.ssh/config, ssh-agent, on-disk keys, and known_hosts. The dashboard stores no passwords or secrets; it only records the SSH destination and connection options you supply. StrictHostKeyChecking is left at its default, so the remote host must already be present in known_hosts — an unknown host fails the connection rather than being trusted blindly.": + "La autenticación se deja totalmente a la propia pila SSH del host — ~/.ssh/config, ssh-agent, claves en disco y known_hosts. del panel de instrumentos almacena Sin contraseñas ni secretos; solo registra el destino SSH y las opciones de conexión que proporcione. StrictHostKeyChecking Se deja en su configuración predeterminada, por lo que el host remoto ya debe estar presente en known_hosts — un anfitrión desconocido falla la conexión en lugar de ser confiado ciegamente.", + "Interval for the background remote poller (add/re-enable also syncs immediately); 0 disables the poller while leaving manual sync available": + "Intervalo para el recuento remoto de fondo (agregar/reactivar también se sincroniza inmediatamente); 0 Desactiva el poller mientras deja la sincronización manual disponible", + "Ceiling on a single scp-and-import run before it is aborted": + "Techo en una sola ejecución de scp-and-import antes de que se aborte", + "Timeout for the Test connection probe": + "Tiempo de espera para el Prueba de conexión catéter", + "Freshness window (10 min) for a Remote Data Source session's live status — judged from the newest JSONL event timestamp in the mirror (mtime fallback); remote sessions receive no live hooks, so this replaces the local liveness and stale sweeps (which skip them)": + "Ventana de frescura (10 min) para el estado en vivo de una sesión de Fuente de Datos Remota, evaluado por el tiempo de inicio del evento JSONL más reciente en el espejo (mtime fallback); las sesiones remotas no reciben ningún gancho en vivo, por lo que esto reemplaza la vitalidad local y las escaneos obsoletos (que los saltan)", + "Because a remote session is pulled over SSH, it never emits live hooks to this dashboard, so remote sessions (sourcelocal) are excluded from every local liveness and stale sweep — the process liveness reap, the watchdog transcript scan, the startup cleanup, and the periodic abandon sweep all skip them. Instead, a remote session's live status is reconciled from the mirrored transcript on every sync: activity is judged from the newest event timestamp inside the JSONL (falling back to mirror mtime). If the last event is within DASHBOARD_REMOTE_ACTIVE_WINDOW_MS (default 10 minutes) the session stays active; once the mirror stops advancing for longer than that window, the session is reconciled to completed. This keeps a still-running remote session from being wrongly shown as Completed.": + "Debido a que una sesión remota se ejecuta a través de SSH, nunca emite ganchos en vivo a este panel de control, por lo que las sesiones remotas (sourcelocal) están excluidos de cada limpieza local de actividad y antigüedad: la actividad de recogida del proceso, la escanear de transcripciones de vigilancia, la limpieza de inicio de sesión y la limpieza periódica de abandono todos los pasan por alto. En cambio, el estado de actividad de una sesión remota se reconcilia a partir de la transcripción reflejada en cada sincronización: la actividad se juzga a partir del Fecha y hora del último evento dentro del JSONL (volviendo al tiempo de mapeo del espejo). Si el último evento está dentro de DASHBOARD_REMOTE_ACTIVE_WINDOW_MS (por defecto 10 minutos) la sesión se mantiene active; una vez que el espejo deja de avanzar durante más tiempo que esa ventana, la sesión se reconcilia con completed. sesión remota en ejecución se muestra correctamente como completada.", + "List configured sources with their status": "Lista de fuentes configuradas con su estado", + "Add a source — SSH destination plus optional port, identity file, and remote home": + "Agregue una fuente: destino SSH más puerto opcional, archivo de identidad y hogar remoto", + "Edit an existing source": "Editar una fuente existente", + "Remove a source; optionally purge the sessions it imported": + "Eliminar una fuente; opcionalmente purgar las sesiones que importó", + "Test SSH reachability without importing anything": + "Prueba la accesibilidad SSH sin importar nada", + "Trigger an immediate scp-and-import for that source": + "Desatará un scp-y-importación inmediata para esa fuente", + "The sources query parameter is also accepted on /api/sessions, /api/events, /api/agents, /api/stats, and /api/analytics to scope any view to local, all, or a comma-separated list of source IDs.": + "el sources El parámetro de consulta también se acepta en /api/sessions, /api/events, /api/agents, /api/stats, y /api/analytics Para delimitar cualquier vista a local, all, o una lista separada por comas de identificadores de origen.", + "Sync progress and connection state broadcast on /ws as remote_source.status messages, so the Settings panel and the source badges update live as a remote connects, syncs, or fails.": + "Transmite el progreso de sincronización y el estado de conexión en /ws arsénico remote_source.status Mensajes, por lo que el panel de Configuración y las insignias de origen se actualizan en vivo a medida que se conecta, sincroniza o falla una fuente remota.", + "The same operations are available from the terminal via ccam remote-sources, with subcommands list, add, test <id>, sync [id] (all sources when no id is given), and rm <id> [--purge] to remove a source and optionally drop the sessions it imported.": + "Las mismas operaciones están disponibles desde el terminal a través de ccam remote-sources, con subcomandos list, add, test <id>, sync [id] (todas las fuentes cuando no se da un ID), y rm <id> [--purge] Para eliminar una fuente y, opcionalmente, eliminar las sesiones que importó.", + "Local-only by default": "Solo local por defecto", + "The image bakes DASHBOARD_HOST=0.0.0.0 (the server binds loopback by default, but a container's loopback is a separate namespace the published port cannot reach) and DASHBOARD_DATA_DIR=/app/data (the read-only ~/.claude mount cannot hold the SQLite data dir). The trust boundary is the host port publish: the examples use -p 127.0.0.1:4820:4820, so the dashboard is local-only. To expose it on a LAN, publish on 0.0.0.0 (-p 4820:4820) and set DASHBOARD_TOKEN.": + "La imagen se hornea DASHBOARD_HOST=0.0.0.0 (el servidor vincula el bucle de vuelta por defecto, pero el bucle de vuelta de un contenedor es un namespace separado al que la puerto publicado no puede llegar) y DASHBOARD_DATA_DIR=/app/data (el de solo lectura ~/.claude El montaje no puede mantener el directorio de datos SQLite). El límite de confianza es la publicación de la puerto del host: los ejemplos utilizan -p 127.0.0.1:4820:4820, por lo que el panel de control es solo local. Para exponerlo en una LAN, publique en 0.0.0.0 (-p 4820:4820) y establecer DASHBOARD_TOKEN.", + "The CLI also manages the server itself: ccam status shows an up/down indicator and ccam start boots a detached production server. When the server is down, read-only commands fall back to reading data/dashboard.db directly under an explicit offline banner, while live or server-computed commands refuse with the specific reason.": + "El CLI también gestiona el propio servidor: ccam status Muestra un indicador de arriba/abajo y ccam start Inicia sesión en un servidor de producción independiente. Cuando el servidor está inactivo, los comandos de solo lectura se vuelven a leer data/dashboard.db Directamente debajo de un banner explícito de modo sin conexión, mientras que los comandos en vivo o calculados por el servidor se niegan con la razón específica.", + "The full dashboard feature surface is also available from any terminal through the dependency-free ccam CLI (bin/ccam.js). It is linked automatically by npm run setup (via a fail-soft npm link), discovers the running server through the same ~/.claude/.agent-dashboard.json registry the hook handler uses (override with CLAUDE_DASHBOARD_PORT / DASHBOARD_PORT), and renders a full terminal UI — box-drawn tables, status icons, inline bar charts, and agent trees — that degrades to plain text when piped (--no-color / NO_COLOR / FORCE_COLOR respected), so it is equally at home in an interactive shell, grep pipelines, or CI.": + "La superficie completa de la función del panel de control también está disponible desde cualquier terminal a través del sin dependencias ccam CLI (bin/ccam.js). Está vinculado automáticamente por npm run setup (a través de un fallo suave npm link), descubre el servidor en ejecución a través del mismo ~/.claude/.agent-dashboard.json Registrar el gestor de ganchos que utiliza (sustituir con CLAUDE_DASHBOARD_PORT / DASHBOARD_PORT), y genera una interfaz de usuario completa para terminales: tablas dibujadas en cuadrados, iconos de estado, gráficos de barras en línea y árboles de agentes, que se degradan a texto plano cuando se canaliza (--no-color / NO_COLOR / FORCE_COLOR respetado), por lo que está igualmente en su salsa en una cáscara interactiva, grep Trenes de gas, o CI.", + "For a live monitoring session, ccam repl (aliases shell / i) opens an interactive shell where you type commands without the ccam prefix — with a CCAM welcome banner, tab-completion, persisted arrow-key history, a live server-status prompt ( up / offline), a grouped help / help <cmd> menu, and a watch [secs] <cmd> built-in that auto-refreshes any command. Each entered line runs as an isolated child process, so an offline refusal or a blocking tail never takes the shell down.": + "Para una sesión de monitoreo en vivo, ccam repl (alias shell / i) abre una cáscara interactiva donde escribes comandos sin el ccam prefijo — con un banner de bienvenida CCAM, completación de pestañas, historial persistente de teclas de flecha, una solicitud de estado del servidor en vivo ( Arriba / Desconectado), un agrupado help / help <cmd> Menú, y un watch [secs] <cmd> Instalado que se actualiza automáticamente cualquier comando. Cada línea ingresada se ejecuta como un proceso hijo aislado, por lo que una negativa sin conexión o un bloqueo tail Nunca baja la cáscara.", + Group: "grupo", + Commands: "Comandos", + "What you get": "Lo que obtienes", + Monitoring: "monitoreo", + "Reachability, totals and status distributions, the Kanban board rendered as text columns, and a live event feed that polls for new rows every 2 seconds": + "Alcance, totales y distribuciones de estado, la pizarra Kanban renderizada como columnas de texto y un feed de eventos en vivo que encuesta por nuevas filas cada 2 segundos", + "Up/down indicator, a background server start that waits for health, and the interactive ccam repl shell — tab-completion, persisted history, a live server-status prompt, and a watch auto-refresh": + "Indicador de arriba/abajo, un inicio de servidor de fondo que espera la salud, y el interactivo ccam repl Shell — completación de pestañas, historial persistente, una solicitud de estado del servidor en vivo y un watch Actualizar automático", + Data: "información", + "Filterable tables plus a per-session deep dive with an indented agent tree, per-session cost, and the most recent events": + "Tablas filtrables más un análisis profundo por sesión con un árbol de agentes hundido, costo por sesión y los eventos más recientes", + Insights: "Perspectivas", + "Token totals and top tools, workflow-intelligence stats with detected patterns, dynamic Workflow-tool runs, and the per-model cost breakdown, which can be scoped to a single session with --session, surfaces server-tool surcharges (web search / code execution), warns about models with usage but no matching pricing rule (priced at $0, excluded from the total), and points to ccam pricing set": + "Totales de tokens y herramientas principales, estadísticas de inteligencia de flujo de trabajo con patrones detectados, ejecuciones dinámicas de herramientas de flujo de trabajo y la desglose de costos por modelo, que se pueden limitar a una sola sesión con --session, muestra recargos por herramientas de servidor de las superficies (búsqueda web / ejecución de código), advierte sobre modelos con uso pero sin una regla de precios correspondiente (preciados a 0 $, excluidos del total) y señala a ccam pricing set", + "Alerts & Webhooks": "Alertas y Webhooks", + "The fired-alert feed with acknowledge / acknowledge-all, the rule list, and synthetic test deliveries against any webhook target": + "El feed de alerta de disparo con reconocimiento / reconocimiento-todo, la lista de reglas y entregas de pruebas sintéticas contra cualquier objetivo webhook", + Pricing: "fijación de precios", + "Full pricing-rule CRUD with per-mtok rates — including 1-hour cache-write, fast-tier, and time-limited intro rates — straight from the terminal, with Fast In/Out and Intro In/Out columns in the list view": + "Regla de precios completa CRUD con tarifas por mtok, incluyendo tarifas de escritura de caché de 1 hora, nivel rápido y tarifas de introducción con tiempo limitado, directamente desde el terminal, con las columnas Fast In/Out y Intro In/Out en la vista de lista.", + Import: "importación", + "The same idempotent ingestion pipeline the Settings page uses, reporting imported / backfilled / skipped / error counts": + "El mismo pipeline de ingestión idempotente que utiliza la página de Configuración, que informa de los conteos de importación / rellenado / saltos / errores", + Administration: "administración", + "Connectivity and hook diagnosis, raw system info, full JSON export, session cleanup, hook reinstallation, an update check that prints how far behind the canonical remote you are plus the copy-paste update command, and a guarded wipe that refuses to run without --yes": + "Conectividad y diagnóstico de ganchos, información del sistema bruta, exportación completa de JSON, limpieza de sesiones, reinstalación de ganchos, una comprobación de actualización que imprime cuánto estás atrasado con respecto al remoto canónico, además del comando de actualización de copia y pegar, y una borrado protegido que se niega a ejecutarse sin --yes", + "Safe by default": "Seguro por defecto", + "Read commands only issue GETs; mutating commands map one-to-one to explicit dashboard actions; and the single destructive command, clear-data, always refuses to run without an explicit --yes flag. Exit codes are script-friendly: 0 on success, 1 on any failure. See docs/CLI.md for the complete reference.": + "Los comandos de lectura solo emiten GETs; los comandos mutantes se mapean de forma uno a uno a las acciones explícitas del panel de control; y el único comando destructivo, clear-data, siempre se niega a correr sin un explícito --yes Bandera. Los códigos de salida son compatibles con scripts: 0 en caso de éxito, 1 en cualquier fallo. ver docs/CLI.md Para la referencia completa.", + "The whole dashboard as terminal commands — ccam stats, kanban, tail, session <id>, analytics, alerts, pricing, import, doctor, export and more. Zero dependencies, linked by npm run setup, auto-discovers the running server, renders a full terminal UI (box-drawn tables, status icons, inline bar charts, agent trees), and pipes cleanly (colors off when not a TTY). The one destructive command is gated behind --yes.": + "Todo el panel de control como comandos terminales — ccam stats, kanban, tail, session <id>, analytics, alerts, pricing, import, doctor, export Y más. Cero dependencias, vinculadas por npm run setup, descubre automáticamente el servidor en ejecución, genera una interfaz de usuario completa del terminal (tablas dibujadas en cuadrados, iconos de estado, gráficos de barras en línea, árboles de agentes) y canaliza de forma limpia (colores apagados cuando no es un TTY). El único comando destructivo está bloqueado detrás de --yes.", + '📡 Live dashboard — real-time agent cards, stats, and activity feed': + '📡 Panel de control en vivo: tarjetas de agentes en tiempo real, estadísticas y flujo de actividad', + "Claude Code Agent Monitor integrates with Claude Code through its native hook system. When Claude Code performs any action — tool use, session start, subagent orchestration, session end — it fires a hook that calls a small Node.js script bundled with this project. That script forwards the event over HTTP to the dashboard server, which stores it in SQLite and broadcasts it to the browser over WebSocket.": + "El Monitor de Agentes de Claude Code se integra con Claude Code a través de su sistema de ganchos nativo. Cuando Claude Code realiza cualquier acción, como el uso de herramientas, el inicio de sesión, la orquestación de subagentes o el final de sesión, dispara un gancho que llama a un pequeño script Node.js incluido en este proyecto. Ese script envia el evento por HTTP al servidor del panel de control, que lo almacena en SQLite y lo transmite al navegador a través de WebSocket.", + "End-to-end data pipeline from Claude Code to the browser": + "Pipeline de datos de extremo a extremo desde Claude Code hasta el navegador", + "Local-first by design": "Primero local por diseño", + "The server binds 127.0.0.1 (loopback) by default, so it is not network-reachable and everything runs on your machine. No data leaves your system. No API keys. No external services. Exposing it more widely is opt-in via DASHBOARD_HOST and should be paired with DASHBOARD_TOKEN.": + "El servidor se vincula 127.0.0.1 (loopback) por defecto, por lo que no es accesible desde la red y todo se ejecuta en su máquina. Ningún dato sale de su sistema. Ningunas claves API. Ningún servicio externo. Exponerlo más ampliamente es opcional a través de DASHBOARD_HOST Y debería combinarse con DASHBOARD_TOKEN.", + "Every feature is driven by real hook events — nothing is hardcoded or simulated in production mode.": + "Cada función está impulsada por eventos de conexión reales, nada está codificado de forma estática ni se simula en modo de producción.", + "Two tabs: Monitor shows overview stats, active agent cards with collapsible subagent hierarchy, and a recent activity feed whose item count fills available viewport height. Health renders a composite system health score ring, storage engine donut chart, cache/error/success gauges, tool invocation bars, subagent effectiveness ratios, model token distribution, and compaction stats. Both tabs auto-refresh every 5 seconds via WebSocket push so the view is always current without manual reload.": + "Dos pestañas: monitor muestra estadísticas generales, tarjetas de agentes activos con jerarquía de subagentes colapsable y un feed de actividad reciente cuyo número de elementos llena la altura disponible de la ventana de visualización. bienestar Genera un anillo de puntuación de salud del sistema compuesto, un gráfico de donut del motor de almacenamiento, indicadores de caché/errores/éxito, barras de invocación de herramientas, índices de eficacia de subagentes, distribución de tokens del modelo y estadísticas de compactación. Ambas pestañas se actualizan automáticamente cada 5 segundos a través de WebSocket push, por lo que la vista siempre es actual sin necesidad de recarga manual.", + "Toggle between Agents (Working / Waiting / Completed / Error) and Sessions (Active / Waiting / Completed / Error / Abandoned) swim lanes. A yellow Waiting column flags items sitting on the user — fresh prompt, between turns, or permission gate. Hover any column header for lifecycle tooltips explaining each state transition. Cards surface model name, cumulative cost, and the current tool being called. Counts update in real time via WebSocket so the board is always in sync with the live event store. Hover a Waiting badge to see why — needs input, turn done, at prompt, or interrupted.": + "Alternar entre Agentes (Trabajando / Esperando / Terminado / Error) y sesión (Lanes de natación activas / en espera / completadas / error / abandonadas). Un amarillo espera Las banderas de la columna indican los elementos que se encuentran en el usuario: mensaje de inicio de sesión actual, entre turnos o puerta de permisos. Haga clic sobre cualquier encabezado de columna para ver las herramientas de ayuda del ciclo de vida que explican cada transición de estado. Las tarjetas muestran el nombre del modelo de superficie, el costo acumulado y la herramienta actual que se está llamando. Las cuentas se actualizan en tiempo real a través de WebSocket, por lo que la tabla siempre está sincronizada con el almacén de eventos en vivo. Haga clic en un distintivo de Esperando para ver por qué: necesita entrada, turno terminado, en el mensaje de inicio de sesión o interrumpido.", + "Server-paginated table of every recorded session — each page fetches only its slice so cost computation stays bounded no matter how many sessions exist. Case-insensitive search across id, name, and cwd runs server-side with a 300 ms debounce; the status filter composes with search for precise narrowing. Each row shows the session's real name (synced live from the transcript — a /rename or claude -n title, else the auto title, else the first user prompt, with a short-ID fallback), status badge, agent count, duration, model, and estimated cost. Click any row to drill into the full session detail view with conversation transcript and agent hierarchy.": + "Paginado por servidor Tabla de cada sesión registrada: cada página solo recupera su fracción, por lo que el cálculo de costos se mantiene limitado independientemente de cuántas sesiones existan. Búsqueda insensible a mayúsculas y minúsculas en todo el id, name, y cwd Funciona en el lado del servidor con un retraso de 300 ms; el filtro de estado se compone con la búsqueda para un estrechamiento preciso. Cada fila muestra el nombre real de la sesión (sincronizado en vivo desde la transcripción, un /rename Oregón claude -n Título, de lo contrario el título automático, de lo contrario la primera solicitud del usuario, con un fallback de ID corto), distintivo de estado, número de agentes, duración, modelo y costo estimado. Haga clic en cualquier fila para profundizar en la vista detallada completa de la sesión con transcripción de la conversación y jerarquía de agentes.", + "Per-session deep dive with a collapsible agent hierarchy tree and a full chronological event timeline showing every tool call name and summary. An overview panel at the top surfaces tile counters for events, tool calls, subagents, compactions, errors, and duration. Top-tool usage bars and a subagent type breakdown give quick distribution reads. The conversation viewer renders markdown with syntax highlighting, per-tool styled blocks, slash-command pills with their captured TUI output, and inline session-rename markers. Messages typed mid-turn (queued while Claude was still working) appear where Claude actually received them, and harness notifications are attributed to System. Export the entire session as JSON or share the permalink for async review. When the session is waiting on you, a yellow banner under the header names the reason and how long it has been waiting.": + "Un análisis profundo por sesión con un árbol jerárquico de agentes colapsables y una cronología completa de eventos cronológicos que muestra el nombre y el resumen de cada llamada de herramienta. Un panel general en la parte superior muestra los contadores de superficies de los eventos, las llamadas de herramientas, los subagentes, las compresiones, los errores y la duración. Las barras de uso de las herramientas principales y la desglose del tipo de subagente proporcionan lecturas de distribución rápidas. El visualizador de conversaciones renderiza markdown con resaltado de sintaxis, bloques con estilo por herramienta, píldoras de comandos de guión con su salida TUI capturada y marcadores de renombramiento de sesión en línea. Los mensajes ingresados a mitad de turno (que se agendaron mientras Claude seguía trabajando) aparecen donde Claude los recibió realmente, y las notificaciones de gestión se atribuyen al Sistema. Exporta toda la sesión como JSON o comparte el enlace permanente para la revisión asincrónica. Cuando la sesión está esperando a que la realices, un banner amarillo debajo de los nombres del encabezado indica la razón y cuánto tiempo ha estado esperando.", + "A rules-based alerting engine evaluates the live event stream server-side: event pattern (match event type / tool / summary text, optionally N matches within a time window), inactivity, stuck agent, and token threshold — each with per-(rule, session, agent) cooldown dedup. Fired alerts surface in a live feed and fan out to 14 first-class webhook providers — Slack, Discord, Teams, Google Chat, Mattermost, Rocket.Chat, Telegram, PagerDuty, Opsgenie, Splunk On-Call, Zapier, Make, n8n, Pipedream — plus any generic JSON endpoint (with optional HMAC-SHA256 signing and custom headers). Delivery is detached and fail-safe with a request timeout, bounded retry/backoff, secret redaction, a one-click test probe, and a per-target delivery log. Rules and channels are managed together in Settings → Alerts.": + "Un motor de alerta basado en reglas evalúa el flujo de eventos en vivo desde el lado del servidor: Patrón de eventos (tipo de evento de coincidencia / herramienta / texto de resumen, opcionalmente N coincidencias dentro de un rango de tiempo), inactividad, Agente atascado, y Límite de tokens — cada uno con deduplicación de tiempo de espera por (regla, sesión, agente). Las alertas lanzadas aparecen en un feed en vivo y se extienden a 14 proveedores de webhook de primera clase — Slack, Discord, Teams, Google Chat, Mattermost, Rocket.Chat, Telegram, PagerDuty, Opsgenie, Splunk On-Call, Zapier, Make, n8n, Pipedream — además de cualquier punto final JSON genérico (con firma HMAC-SHA256 opcional y encabezados personalizados). La entrega es separada y segura con un tiempo de espera de solicitud, retiro/retraso limitado, redacción secreta, una sonda de prueba de un solo clic y un registro de entrega por objetivo. Las reglas y canales se gestionan juntos en Configuración → Alertas.", + "A native desktop app — a macOS .app (shipped as a .dmg) and a Windows .exe (NSIS installer plus a no-install portable build) — built with Electron 35. It embeds the Express server in-processrequire()-ing server/index.js directly, with no child process and no IPC — and renders the built React client in a BrowserWindow. Adds a menu-bar / notification-area (tray) icon, a native application menu, auto-start at login (macOS Login Items via SMAppService; Windows per-user HKCU\\…\\Run), and a single-instance lock. Closing the window hides it while the server keeps running, and the app auto-installs Claude Code hooks on first boot so an install-only user gets events flowing without a checkout.": + "Una aplicación nativa para escritorio, un macOS .app (enviado como un .dmg) y una ventana de Windows .exe (Instalador NSIS más una versión portátil sin instalación) - construida con Electron 35. lo Incorpora el servidor Express en el procesorequire()-ando server/index.js Directamente, sin proceso de niño ni IPC, y renderiza el cliente React construido en un BrowserWindow. eñade un icono de barra de menú / área de notificaciones ( bandeja), un menú de aplicación nativo, inicio automático al iniciar sesión (elementos de inicio de sesión de macOS a través de SMAppService; Ventanas por usuario HKCU\\…\\Run), y un bloqueo de instancia única. Cerrar la ventana lo oculta mientras el servidor sigue funcionando, y la aplicación instala automáticamente los ganchos de Claude Code en la primera iniciación, por lo que un usuario que solo instala recibe eventos sin necesidad de realizar una compra.", + "Real-time streaming event log showing tool calls, agent state changes, errors, and compaction events as they arrive. Pause/resume with automatic buffering, paginated history for scrollback, and auto-scrolling to the latest entry. Click any row to expand its full hook payload inline. A dedicated Session → button navigates directly to session detail without collapsing the expanded state. Every entry is color-coded by event type and grouped by session for quick scanning of concurrent work.": + "Registro de eventos de transmisión en tiempo real que muestra llamadas de herramientas, cambios de estado del agente, errores y eventos de compactación a medida que llegan. Pausa/resume con búferización automática, historial paginado para desplazamiento hacia atrás y desplazamiento automático hasta la última entrada. Haga clic en cualquier fila para expandir su carga útil completa de gancho en línea. Un dedicado Sesión → El botón navega directamente a los detalles de la sesión sin colapsar el estado expandido. Cada entrada está codificada por color según el tipo de evento y agrupada por sesión para una rápida escaneo del trabajo concurrente.", + "Token usage breakdown by model with stacked bar charts, tool frequency rankings, agent type distribution donuts, and session outcome pie charts. A 52-week activity heatmap aligned by day-of-week shows density with hover tooltips. 30-day sparkline trends track cost and session volume at a glance. The cost summary panel totals input, output, and cache spend across all models. A live/offline indicator and auto-refresh via WebSocket keep everything current. All charts are responsive and adapt to mobile viewports.": + "Desglose del uso de tokens por modelo con gráficos de barras apiladas, clasificaciones de frecuencia de herramientas, rosquillas de distribución de tipos de agentes y gráficos circulares de resultados de sesiones. Un mapa de calor de actividad de 52 semanas alineado por día de la semana muestra la densidad con etiquetas de herramientas flotantes. Las tendencias de sparkline de 30 días rastrean el costo y el volumen de la sesión de un vistazo. El panel de resumen de costos suma la entrada, la salida y el gasto en caché en todos los modelos. Un indicador en vivo/desconectado y la actualización automática a través de WebSocket mantienen todo actualizado. Todos los gráficos son responsivos y se adaptan a las vistas móviles.", + "Every UI update is pushed over a persistent WebSocket with sub-5 ms dispatch latency — zero polling anywhere. If the connection drops, automatic 2-second reconnect kicks in while a ping/pong heartbeat detects stale connections early. A sidebar indicator turns green/red so you always know whether you're live. The WebSocket carries typed JSON envelopes for new events, session updates, agent transitions, compaction results, and import progress — all parsed into the same eventBus the REST layer uses.": + "Cada actualización de la interfaz de usuario se envía a través de un WebSocket persistente con una latencia de despacho inferior a 5 ms, sin necesidad de consultar la conexión en ningún momento. Si la conexión se pierde, se inicia una reconectividad automática de 2 segundos mientras que un latido de ping/pong detecta temprano las conexiones obsoletas. Un indicador en la barra lateral se vuelve verde/rojo para que siempre sepa si está conectado. El WebSocket transporta envoltorios JSON escritos por teclado para nuevos eventos, actualizaciones de sesión, transiciones de agente, resultados de compactación y progreso de importación, todo ello analizado en el mismo eventBus que utiliza la capa REST.", + "Standalone CLI statusline for Claude Code that prints model name, user, working directory, git branch, and a color-coded context-window bar (green → yellow → red). Token counts show input (green ↑), output (cyan ↓), and cache (dim) separately. Session cost in USD shifts color by configurable thresholds. ANSI-colored output updates on every turn. Python-based with a thin shell wrapper — drop it into your prompt or tmux status line. Works with any terminal emulator that supports 256-color ANSI.": + "Línea de estado CLI independiente para Claude Code que imprime el nombre del modelo, el usuario, el directorio de trabajo, la rama de git y una barra de ventana de contexto codificada por colores (verde → amarillo → rojo). Los conteos de tokens muestran la entrada (verde ↑), la salida (cian ↓) y la caché (mala) por separado. El costo de la sesión en USD cambia el color según los umbrales configurables. La salida de color ANSI se actualiza en cada turno. Basado en Python con un envoltorio de cáscara delgada: simplemente colócalo en tu línea de comando o en la línea de estado de tmux. Funciona con cualquier emulador de terminal que admita ANSI de 256 colores.", + "Import existing Claude Code sessions from three sources — rescan the default ~/.claude/projects folder, scan any absolute path on disk, or drag-drop .jsonl, .zip, .tar.gz, and .gz archives through Settings → Import History. All paths funnel into the same ingestion pipeline the server uses for live hooks, so imported tokens and per-model cost match real-time capture exactly. Re-imports are idempotent via session-ID dedup, and archive extraction is guarded against path traversal and zip-bomb expansion.": + "Importar sesiones de código Claude existentes de tres fuentes: volver a escanear la predeterminada ~/.claude/projects Carpeta, escanee cualquier ruta absoluta en el disco o arrastre y suelte .jsonl, .zip, .tar.gz, y .gz Archivos a través de Configuración → Historial de importaciones. se dirigen todos los caminos a la misma tubería de ingestión que el servidor utiliza para los ganchos en vivo, por lo que los tokens importados y el costo por modelo coinciden exactamente con la captura en tiempo real. Las reimportaciones son idempotentes mediante deduplicación del ID de la sesión, y la extracción de archivos está protegida contra la travesía de caminos y la expansión de zip-bomb.", + "The startup auto-import of ~/.claude/projects is one-time and marker-gated, so a project folder created after first launch — whose sessions never flow through hooks (for example with host-only hooks disabled) — would stay invisible until a manual rescan. A background sync closes that gap with three triggers sharing one mtime cache and a single coalesced sweep: an immediate sweep at startup, a debounced fs.watch (recursive on macOS and Windows; root plus immediate child folders on Linux to avoid the userland recursive-watcher hazard) that fires the moment a new session file or project folder appears, and a periodic safety-net poll tunable via DASHBOARD_SESSION_SYNC_MS (default 30000 ms; 0 disables the poll while leaving the watcher running). Each sweep re-parses only files whose mtime advanced and broadcasts session_created / session_updated (plus the main agent) so the UI refreshes live, while an already-imported unchanged session is skipped without re-parsing.": + "La importación automática inicial de ~/.claude/projects Es único y con puerta de marcador, por lo que una carpeta de proyecto creada después del primer lanzamiento, cuyas sesiones nunca fluyen a través de ganchos (por ejemplo, con los ganchos solo para el host desactivados), permanecería invisible hasta una escanear manual. Una sincronización en segundo plano cierra esa brecha con tres desencadenantes que comparten una caché mtime y una sola escanear coalescida: una escanear inmediata al inicio, una debounced fs.watch (recursivo en macOS y Windows; directorio raíz más hijos inmediatos en Linux para evitar el peligro del observador recursivo en el sistema operativo) que dispara en el momento en que aparece un nuevo archivo de sesión o directorio de proyecto, y una encuesta periódica de red de seguridad ajustable a través de DASHBOARD_SESSION_SYNC_MS (por defecto 30000 Sra.; 0 desactiva la encuesta mientras deja que el observador siga funcionando). Cada escaneo solo reparse los archivos cuyo mtime ha avanzado y transmite session_created / session_updated (más el agente principal) por lo que la interfaz de usuario se actualiza en vivo, mientras que una sesión ya importada e inalterada se omite sin volver a analizarla.", + "Incremental JSONL reader shared across the hook handler, compaction scanner, conversation viewer, and import pipeline. Byte-offset tracking skips already-parsed content; cache hits short-circuit disk I/O so even sessions with tens of thousands of turns stay fast. It also extracts the live session title (custom-title / ai-title) so renames surface in real time, plus the first user prompt as a fallback descriptor for placeholder-named sessions and agents.": + "El lector JSONL incremental compartido entre el gestor de ganchos, el escáner de compactación, el visualizador de conversaciones y la tubería de importación. El seguimiento del desplazamiento de bytes omite el contenido ya procesado; los accesos a la caché cortocircuita la E/S del disco, por lo que incluso las sesiones con decenas de miles de giros siguen siendo rápidas. También extrae el título de la sesión en vivo (custom-title / ai-title) renombra la superficie en tiempo real, además del primer mensaje de usuario como descriptor de respaldo para sesiones y agentes con nombres de lugar de almacenamiento.", + "LRU eviction of cold session buffers plus a tail-cap on per-entry growable arrays (turn durations, API errors, compaction entries). A session that runs for days cannot grow a single cache entry without bound, and each entry stores its parsed result only once — no shadow copy.": + "Desalojo LRU de los búferes de sesiones frías, además de una tapa de cola en matrices crecientes por entrada (duraciones de turno, errores API, entradas de compactación). Una sesión que se ejecuta durante días no puede crecer una sola entrada de caché sin límites, y cada entrada almacena su resultado analizado solo una vez, sin copia de sombra.", + "The periodic compaction sweep reads each active session's transcript path directly from sessions.transcript_path (a partial index covers exactly those rows), so the work is O(active sessions) instead of a json_extract scan over the whole events table.": + "La escanearía de compactación periódica lee el camino de transcripción de cada sesión activa directamente desde sessions.transcript_path (un índice parcial cubre exactamente esas filas), por lo que el trabajo es O(sesiones activas) en lugar de un json_extract Escanee toda la tabla de eventos.", + "Collapsible parent–child agent tree rendered on both Dashboard and Session Detail. Agents with subagents display expand/collapse chevrons; leaf agents show a dot indicator. The tree auto-expands when any child transitions to active and correctly tracks backgrounded subagents without premature completion. Depth is unlimited — deeply nested chains render as indented rows with connecting lines. Each node shows model, current tool, status badge, and cumulative token cost for tracing spend down the spawn chain.": + "Árbol de agentes padre-hijo colapsable renderizado tanto en el Panel de control como en los Detalles de la sesión. Los agentes con subagentes muestran flechas de expansión/colapso; los agentes de hoja muestran un indicador de punto. El árbol se expande automáticamente cuando cualquier hijo pasa a activo y rastrea correctamente los subagentes en segundo plano sin completar prematuramente. La profundidad es ilimitada: las cadenas profundamente anidadas se muestran como filas recortadas con líneas de conexión. Cada nodo muestra el modelo, la herramienta actual, el distintivo de estado y el costo acumulativo de los tokens para rastrear el gasto a lo largo de la cadena de generación.", + "Per-model cost estimation with configurable pricing rules — set input, output, and cache-read rates per model variant through the Settings UI. View total and per-session breakdowns on Sessions, Session Detail, and Analytics. Compaction- aware token accounting preserves baselines across context compressions so no usage is silently dropped. Cost chips appear on Kanban cards, session rows, and the sidebar summary. Subagent cards show each subagent's own cost, computed from that subagent's transcript token usage priced at current rates, so a subagent card no longer misleadingly reads as if it cost the whole session; main-agent cards still show the session total. Pricing changes retroactively recalculate all stored sessions, and imports apply the same rate table.": + "Estimación de costos por modelo con reglas de precios configurables: establece tasas de entrada, salida y lectura de caché por variante de modelo a través de la interfaz de usuario de Configuración. Ve los desgloses totales y por sesión en Sesiones, Detalles de sesión y Análisis. La contabilidad de tokens consciente de la compactación preserva las bases de datos a través de las compresiones de contexto, por lo que ningún uso se elimina silenciosamente. Las fichas de costo aparecen en las tarjetas Kanban, las filas de sesión y el resumen de la barra lateral. Las tarjetas de subagente muestran el propio costo de cada subagente, calculado a partir del uso de tokens de la transcripción de ese subagente con precios a las tasas actuales, por lo que una tarjeta de subagente ya no se lee engañosamente como si costara toda la sesión; las tarjetas de agente principal todavía muestran el total de la sesión. Los cambios de precios recalculan retroactivamente todas las sesiones almacenadas y las importaciones aplican la misma tabla de tarifas.", + "Model pricing editor with per-token rate configuration for every Claude variant. Hook installation status with one-click reinstall and per-hook health checks. Full JSON data export covering sessions, agents, events, tokens, and pricing rules. Session cleanup controls to abandon stale sessions or purge old data by age. Browser notification preferences with per-event toggles. A system information panel shows database row counts, file sizes, server uptime, and WebSocket connection status at a glance.": + "Editor de precios de modelos con configuración de tasa por token para cada variante de Claude. Estado de instalación del gancho con reinstalación con un solo clic y comprobaciones de salud por gancho. Exportación completa de datos JSON que cubre sesiones, agentes, eventos, tokens y reglas de precios. Control de limpieza de sesiones para abandonar sesiones obsoletas o purgar datos antiguos por edad. Preferencias de notificación del navegador con interruptores por evento. Un panel de información del sistema muestra el número de filas de la base de datos, los tamaños de los archivos, el tiempo de actividad del servidor y el estado de la conexión WebSocket de un vistazo.", + "Local MCP sidecar with three transport modes — stdio for Claude Code native integration, HTTP+SSE for remote clients, and an interactive REPL for ad-hoc terminal queries. Exposes 25 typed tools across 6 domains: sessions, agents, events, analytics, settings, and system health. Every mutation is gated behind a tiered policy so nothing dangerous fires without opt-in. Retry-aware API access handles transient failures. Runs as a standalone Node process with no Docker or cloud dependency.": + "MCP local con tres modos de transporte: stdio para la integración nativa del código Claude, HTTP+SSE para clientes remotos y un REPL interactivo para consultas terminales ad hoc. Exponen 25 herramientas de tipo en 6 dominios: sesiones, agentes, eventos, análisis, configuración y estado del sistema. Cada mutación está bloqueada detrás de una política jerárquica, por lo que nada peligroso se activa sin consentimiento. El acceso a la API con detección de intentos de reintento maneja los fallos transitorios. Funciona como un proceso Node independiente sin dependencias de Docker ni de la nube.", + "Instruction, skills, rules, and custom-agent layers for both Claude Code and Codex. Path-scoped rules target backend, frontend, MCP, and docs directories with context-appropriate guidelines. Reusable skills cover onboarding, feature shipping, live-issue debugging, release-readiness, and MCP operations. Specialized subagents for backend, frontend, and MCP code review run in parallel with focused tooling. Everything lives in .claude/ and is version-controlled alongside the codebase.": + "Instrucciones, habilidades, reglas y capas de agente personalizado para tanto Claude Code como Codex. Las reglas de alcance de ruta apuntan a los directorios de backend, frontend, MCP y documentos con directrices apropiadas para el contexto. Las habilidades reutilizables cubren la incorporación, el envío de funciones, el depuración de problemas en vivo, la preparación para el lanzamiento y las operaciones MCP. Los subagentes especializados para la revisión de código de backend, frontend y MCP se ejecutan en paralelo con herramientas enfocadas. Todo vive en .claude/ Y está controlado por versiones junto con el código fuente.", + "D3.js-powered visualizations: an agent orchestration DAG showing spawn patterns across sessions, a tool-execution Sankey diagram mapping tool-to- tool transitions, and a directed pipeline graph with frequency labels. Every chart title carries an info icon that opens a popover explaining what it shows and how to read it. Hovering nodes, edges, and bars surfaces tooltips with share-of-source percentages, success-rate buckets, and timing patterns. All labels are translated to English, Vietnamese, and Chinese.": + "Visualizaciones impulsadas por D3.js: una DAG de orquestación de agentes que muestra patrones de generación a lo largo de las sesiones, una herramienta de mapeo de diagrama Sankey de ejecución de herramientas que muestra las transiciones de herramienta a herramienta y un gráfico de tuberías dirigidas con etiquetas de frecuencia. Cada título de gráfico lleva un icono de información que abre un popover que explica lo que muestra y cómo leerlo. Al pasar el cursor sobre nodos, bordes y superficies de barras, aparecen herramientas de información con porcentajes de participación en el código fuente, cuencos de tasa de éxito y patrones de tiempo. Todas las etiquetas se traducen al inglés, vietnamita y chino.", + "Subagent effectiveness scorecards with success-rate rings and day-of-week sparklines. Auto-detected workflow patterns expand on click into a detail panel with the full step chain, stats grid, and a narrative with loop detection. Model delegation flow, error propagation bars with API error cards, concurrency swim-lanes, and complexity bubble charts round out the view. Six headline stat cards each include an info popover explaining the metric and its current value. Status filter applies globally.": + "Tarjetas de puntuación de eficacia del subagente con anillos de tasa de éxito y líneas de chispa del día de la semana. Los patrones de flujo de trabajo detectados automáticamente se amplían al hacer clic en un panel de detalles con la cadena completa de pasos, la cuadrícula de estadísticas y una narración con detección de bucle. El flujo de delegación del modelo, las barras de propagación de errores con tarjetas de error de API, las pistas de natación de concurrencia y los gráficos de burbujas de complejidad completan la vista. Se incluyen en cada una de las seis tarjetas estadísticas principales una ventana emergente de información que explica la métrica y su valor actual. El filtro de estado se aplica globalmente.", + "Searchable session selector with pagination to explore any session's agent tree, tool-call timeline, and event sequence. The detail page opens with a live-updating overview — tile counters for events, tool calls, subagents, compactions, errors, and duration. Top-tool usage bars and subagent breakdown give quick reads. The conversation viewer renders markdown with syntax highlighting. Cross-filter from DAG nodes, run compaction analysis, or export as JSON — all with real-time WebSocket auto-refresh.": + "Selector de sesiones buscable con paginación para explorar el árbol de agentes, la línea de tiempo de llamadas de herramientas y la secuencia de eventos de cualquier sesión. La página de detalles se abre con una descripción general actualizada en tiempo real: contadores de baldosas para eventos, llamadas de herramientas, subagentes, compactaciones, errores y duración. Las barras de uso de herramientas principales y la desglose de subagentes proporcionan lecturas rápidas. El visualizador de conversaciones renderiza Markdown con resaltado de sintaxis. Filtra cruzado por nodos DAG, realiza el análisis de compactación o exporta como JSON, todo con la actualización automática de WebSocket en tiempo real.", + "Persistent browser notifications via Web Push (VAPID) for real-time alerts even when the tab is not focused or the browser is backgrounded. Includes macOS audio support so notifications are audible alongside system sounds. Per-event toggles let you choose which events fire — session starts, completions, errors, compactions, or agent spawns. Server-side subscription management ensures one push per event per browser. Works on Chrome, Edge, Firefox, and Safari 17+ with graceful degradation elsewhere.": + "Notificaciones persistentes del navegador a través de Web Push (VAPID) para alertas en tiempo real incluso cuando la pestaña no está enfocada o el navegador está en segundo plano. Incluye soporte de audio para macOS, por lo que las notificaciones son audibles junto con los sonidos del sistema. Los interruptores por evento le permiten elegir qué eventos se ejecutan: inicio, finalización, errores, compactaciones o aparecimientos de agentes de sesión. La gestión de suscripciones en el lado del servidor garantiza una notificación por evento por navegador. Funciona en Chrome, Edge, Firefox y Safari 17+ con degradación suave en otros lugares.", + "Ready-to-use Dockerfile and docker-compose.yml for one-command deployment. Supports both Docker and Podman with persistent volume mounts for the SQLite database and hook data. Configurable port mapping via environment variables and a health-check endpoint the container runtime can poll. Multi-stage build keeps the image lean — only production deps and the compiled bundle ship. Run docker compose up -d --build and the dashboard is live with zero additional setup or configuration required.": + "Dockerfile y docker-compose.yml listos para usar para el despliegue con un solo comando. Soporta tanto Docker como Podman con montajes de volumen persistentes para la base de datos SQLite y datos de gancho. Mapeo de puertos configurables a través de variables de entorno y un punto final de verificación de salud que el tiempo de ejecución del contenedor puede consultar. La construcción multiestadio mantiene la imagen ligera: solo se envían las dependencias de producción y el paquete compilado. carrera docker compose up -d --build Y el panel de control está en vivo sin necesidad de ninguna configuración o instalación adicional.", + "Official Claude Code plugin marketplace shipping 10 plugins with 53 skills, 14 agents, 30 slash commands, 3 CLI tools, 3 hook configs, and 1 MCP server. Deep analytics with compaction-aware baselines, productivity automation, developer diagnostics, AI-powered workflow intelligence, and dashboard MCP integration. Five newer plugins go further: ccam-cost-guard (budget guardrails, spend forecasts, and cost-threshold alerts), ccam-sessions (session forensics — search, timeline, and transcript replay), ccam-workflows (multi-agent orchestration and fleet intelligence), ccam-quality (reliability and SLO checks), and ccam-config (Claude Code config and memory governance). Install with claude plugin install — no restart needed. Each listing shows author, license, homepage, and per-skill contribution breakdown. The Config Explorer's Plugins tab surfaces installed plugins with live status.": + "Mercado oficial de plugins del código Claude con envío de 10 plugins con 53 habilidades, 14 agentes, 30 comandos slash, 3 herramientas CLI, 3 configuraciones de ganchos y 1 servidor MCP. Análisis profundo con bases de datos conscientes de la compactación, automatización de la productividad, diagnóstico de desarrolladores, inteligencia de flujo de trabajo impulsada por IA e integración de MCP en el panel de control. Cinco plugins más nuevos van más allá: ccam-cost-guard (barandillas de presupuesto, pronósticos de gasto y alertas de umbral de costo), ccam-sessions (forense de sesiones: búsqueda, cronología y reproducción de transcripciones), ccam-workflows (orquestación de múltiples agentes e inteligencia de flota), ccam-quality (comprobaciones de fiabilidad y SLO), y ccam-config (Configuración de Claude Code y gobernanza de la memoria). Instalar con claude plugin install — no se necesita reiniciar. Cada lista muestra el autor, la licencia, la página de inicio y la desglose de las contribuciones por habilidad. La pestaña de complementos del Explorador de Configuración muestra los complementos instalados con estado en vivo.", + "Spawn claude subprocesses straight from the dashboard with a chat-style streaming UI — multi-turn Conversation or single-shot Headless mode. One-click Resume on any past conversation spawns claude --resume seeded with the prior transcript. Re- attach reconciles in-memory logs with the on-disk JSONL so navigating away never loses history. Slash-command autocomplete, file references, live token/context-window meter, and a thinking-effort dial bring TUI parity to the browser. Same-origin guard blocks drive-by spawns.": + "desovar claude Subprocesos directamente desde el panel de control con una interfaz de usuario de streaming en estilo chat, multidireccional conversación O disparo único sin cabeza Modo. Un clic currículum En cualquier conversación pasada se generan claude --resume Semillado con la transcripción anterior. Reajusta los registros de reconciliación en memoria con el JSONL en disco para que la navegación nunca pierda el historial. Completa automáticamente el comando de guión, las referencias de archivos, el medidor de tokens/ventana de contexto en vivo y un dial de esfuerzo de pensamiento traen paridad TUI al navegador. Los bloqueos de guardia de origen compartido bloquean los spawning de paso rápido.", + "A 12-tab inspector at /cc-config for everything Claude Code knows about: skills, subagents, slash commands, output styles, plugins, marketplaces, MCP servers, hooks, settings, memory, keybindings, and statusline scripts. The Settings tab leads with a Current configuration summary of the options /config controls — model, verbose, theme, output style, auto-compact, notifications — resolved across scopes. The Memory tab surfaces both the user and project CLAUDE.md files and the per-project file-based memory store — every auto-memory *.md under ~/.claude/projects/<slug>/memory/ (a MEMORY.md index plus one file per remembered fact, often 100+), grouped by project, searchable, and editable. Create, edit, and delete the low-risk text-file surfaces with mandatory timestamped backups before every write. Plugins, MCP, hooks, and live settings stay read-only with explainer banners and copy-able CLI commands. Per-plugin contribution breakdowns show author and license.": + "Un inspector de 12 tablas en /cc-config Para todo lo que Claude Code sabe sobre: habilidades, subagentes, comandos slash, estilos de salida, complementos, mercados, servidores MCP, ganchos, configuraciones, memoria, atajos de teclado y scripts de línea de estado. La pestaña Configuración encabeza con un resumen de la configuración actual de las opciones /config Controls: modelo, verboso, tema, estilo de salida, compacto automático, notificaciones: resueltos en todos los ámbitos. La pestaña Memoria muestra tanto al usuario como al proyecto. CLAUDE.md Archivos y el almacenamiento de memoria basado en archivos por proyecto, cada memoria automática *.md bajo ~/.claude/projects/<slug>/memory/ (a MEMORY.md Índice más un archivo por hecho recordado, a menudo más de 100), agrupados por proyecto, buscables y editable. Cree, edite y elimine las superficies de archivos de texto de bajo riesgo con copias de seguridad con hora y fecha obligatorias antes de cada escritura. Los complementos, MCP, ganchos y configuraciones en vivo permanecen en modo solo lectura con banners explicativos y comandos CLI copiables. Los desgloses de contribuciones por complemento muestran el autor y la licencia.", + "Mobile-first layouts with stacking grids, horizontally scrollable tables, and a collapsible sidebar that auto-hides below 1400 px. All pages adapt from phone to ultrawide with consistent navigation and readable typography. Kanban columns stack vertically on narrow screens, analytics charts reflow to single-column, and the activity feed stays fully swipeable. Touch targets meet 44 px minimum. Dark theme renders consistently across iOS Safari, Chrome, and Firefox with no flash of unstyled content.": + "Diseños móviles primero con cuadrículas apilables, tablas que se pueden desplazar horizontalmente y una barra lateral plegable que se oculta automáticamente por debajo de 1400 píxeles. Todas las páginas se adaptan desde teléfonos hasta pantallas ultra anchas con una navegación consistente y una tipografía legible. Las columnas Kanban se apilan verticalmente en pantallas estrechas, los gráficos analíticos se rediseñan para una sola columna y el feed de actividad sigue siendo completamente deslizable. Los objetivos táctiles cumplen con un mínimo de 44 píxeles. El tema oscuro se renderiza de forma consistente en iOS Safari, Chrome y Firefox sin ningún parpadeo de contenido sin estilo.", + "Visualize parallel agent execution with a Gantt-style timeline showing overlapping subagent lifetimes, tool-call concurrency windows, and wait gaps. Color-coded bars distinguish working, waiting, and errored states so bottlenecks are immediately visible. Hover any bar for exact timestamps and duration. Zoom and pan across long-running sessions with hundreds of agents. The timeline shares the Workflows status filter so you can isolate active, completed, or errored sessions without leaving the view.": + "Visualice la ejecución paralela de agentes con una línea de tiempo en estilo Gantt que muestra las vidas útiles superpuestas de los subagentes, las ventanas de concurrencia de llamadas de herramientas y los intervalos de espera. Las barras codificadas por color distinguen los estados de trabajo, espera y error, por lo que los cuellos de botella son inmediatamente visibles. Haga clic con el ratón sobre cualquier barra para ver las fechas y horas exactas y la duración. Aproxime y desplácese por sesiones de larga duración con cientos de agentes. La línea de tiempo comparte el filtro de estado de flujos de trabajo, para que pueda aislar sesiones activas, completadas o con errores sin salir de la vista.", + "Professional VS Code extension with a real-time Activity Bar sidebar showing active sessions, agent counts, and recent events without leaving your editor. A status bar pulse monitor surfaces connection health and the latest event type at a glance. Deep navigation links open any session or analytics view directly in your browser. An embedded webview renders the full dashboard inside a VS Code tab with WebSocket push, theme sync, and responsive layout. Install from the marketplace or build from source.": + "Extensión profesional de VS Code con una barra lateral de la barra de actividad en tiempo real que muestra sesiones activas, el número de agentes y eventos recientes sin salir de su editor. Una barra de estado que muestra el pulso de la conexión y el último tipo de evento de un vistazo. Los enlaces de navegación profunda abren cualquier sesión o vista de análisis directamente en su navegador. Una vista web incorporada muestra el panel completo dentro de una pestaña de VS Code con WebSocket push, sincronización de temas y diseño responsive. Instálelo desde el mercado o construya desde la fuente.", + "Trace how errors cascade across agents and tool calls with a directed graph showing failure origins, retry paths, and recovery points. Each node displays the agent or tool that errored, the error message, and whether a retry succeeded or propagated upstream. Pinpoint root causes in deeply nested subagent chains. Horizontal bar charts rank the most error-prone tools and models. API error cards group failures by HTTP status and endpoint. Filter by session, time range, or error severity to narrow the view.": + "Rastree cómo los errores se propagan a través de los agentes y las llamadas a las herramientas con un gráfico dirigido que muestra las orígenes de los fallos, los caminos de intento de nuevo y los puntos de recuperación. Cada nodo muestra el agente o la herramienta que tuvo un error, el mensaje de error y si el intento de nuevo tuvo éxito o se propagó hacia arriba. Identifique las causas raíz en cadenas de subagentes profundamente anidadas. Los gráficos de barras horizontales clasifican las herramientas y modelos más propensos a errores. Las tarjetas de error de la API agrupan los fallos por estado HTTP y punto final. Filtre por sesión, rango de tiempo o gravedad del error para restringir la vista.", + 'Three independent PWAs — dashboard, landing page, and wiki — each with its own Web App Manifest and Service Worker. Install to your home screen or dock for a standalone, chrome-less experience. SVG icons with sizes="any" and iOS standalone meta tags included.': + 'Tres PWAs independientes: panel de control, página de destino y wiki, cada uno con su propio manifiesto de aplicaciones web y trabajador de servicios. Instálelos en su pantalla de inicio o dock para una experiencia independiente y sin Chrome. Íconos SVG con sizes="any" y etiquetas meta independientes de iOS incluidas.', + "The dashboard SW serves Vite's hashed /assets/* bundles cache-first (URLs are immutable per build) and treats everything else as network-first with cache fallback. Explicit Cache-Control headers on the production Express static middleware reinforce the policy, so a rebuild replaces the in-browser code without a hard refresh.": + "El SW del panel de control sirve a Vite's hashed /assets/* bundles almacena primero la caché (los URL son inmutables por construcción) y trata todo lo demás como primero la red con fallback de caché. explícito Cache-Control Los encabezados en el middleware estático de producción Express refuerzan la política, por lo que una reconstrucción reemplaza el código en el navegador sin una actualización forzosa.", + "A controllerchange listener in client/src/main.tsx reloads the page exactly once when a new SW takes over an already-controlled page. First installs do not reload, so the very first visit is never interrupted.": + "A controllerchange Escuchador en client/src/main.tsx Recarga la página exactamente una vez cuando un nuevo SW toma el control de una página ya controlada. Las primeras instalaciones no se recargan, por lo que la primera visita nunca se interrumpe.", + '📡 Dashboard · Monitor — live overview of active sessions and agents. Stats tiles, collapsible subagent hierarchy cards, and a recent activity feed. Auto-refreshes every 5 s via WebSocket': + '📡 Panel de control · Monitor - visión general en vivo de las sesiones activas y los agentes. Píxeles estadísticos, tarjetas de jerarquía de subagentes colapsables y un feed de actividad reciente. Se actualiza automáticamente cada 5 segundos a través de WebSocket', + '🩺 Dashboard · Health — composite health score ring, storage engine donut, cache/error/success gauges, tool invocation bars, subagent effectiveness, and model token distribution': + '🩺 Panel de control · Salud — anillo de puntuación de salud compuesta, donut de motor de almacenamiento, indicadores de caché/errores/éxito, barras de invocación de herramientas, eficacia del subagente y distribución de tokens del modelo', + '📋 Kanban Board (agents) — agents swim-laned by status: Working, Waiting, Completed, Error. Cards show model, cost, and current tool call. Yellow column flags agents waiting on user input': + '📋 Tablero Kanban (agentes) — los agentes se ubican en carriles de natación según su estado: Trabajando, Esperando, Completado, Error. Las tarjetas muestran el modelo, el costo y la llamada de herramienta actual. La columna amarilla marca a los agentes que esperan la entrada del usuario.', + '🗂️ Kanban Board (sessions) — sessions swim-laned across 5 columns: Active, Waiting, Completed, Error, Abandoned. Each card shows agent count, duration, model, and cumulative cost': + '🗂️ Tablero Kanban (sesiones) — sesiones de natación en carriles a través de 5 columnas: Activa, Esperando, Completada, Error, Abandonada. Cada tarjeta muestra el número de agentes, la duración, el modelo y el costo acumulado', + '📂 Sessions — searchable, filterable, server-paginated table. Each row shows status badge, agent count, duration, model, and cost. Click any row to drill into session detail': + '📂 sesión — tabla indexable, filtrable y paginada por servidor. Cada fila muestra el distintivo de estado, el número de agentes, la duración, el modelo y el costo. Haga clic en cualquier fila para profundizar en los detalles de la sesión.', + '🤖 Session Detail · Agents — overview tiles (events, tool calls, subagents, errors, duration), top-tool usage bars, subagent type breakdown, and a collapsible parent–child agent hierarchy tree': + '🤖 Detalles de la sesión · Agentes — baldosas de visión general (eventos, llamadas de herramientas, subagentes, errores, duración), barras de uso de herramientas principales, desglose del tipo de subagente y un árbol jerárquico de agentes padre-hijo colapsable', + '💬 Session Detail · Conversation — full transcript viewer with markdown rendering, syntax-highlighted code blocks, per-tool sections, and collapsible thinking blocks': + '💬 Detalles de la sesión · Conversación — visualizador de transcripciones completas con renderizado de markdown, bloques de código resaltados por sintaxis, secciones por herramienta y bloques de pensamiento colapsables', + '🔬 Session Detail · Timeline — chronological event timeline with multi-dimension filters, color-coded entries by type, expandable hook payloads, and direct links to the owning session and agent': + '🔬 Detalles de la sesión · Línea de tiempo — línea de tiempo cronológica de eventos con filtros multidimensionales, entradas codificadas por color por tipo, cargas útiles de ganchos expandibles y enlaces directos a la sesión y agente propietarios', + '📰 Activity Feed — real-time streaming event log with pause/resume buffering, multi-dimension filters, expandable hook payloads, color-coded entries, and per-row session navigation buttons': + '📰 Feed de actividad — registro de eventos de transmisión en tiempo real con buffer de pausa/resume, filtros multidimensionales, cargas útiles de ganchos expandibles, entradas codificadas por color y botones de navegación de sesiones por fila', + '📊 Analytics — token usage by model, tool frequency bars, 52-week activity heatmap, 30-day sparkline trends, session outcome donuts, and cost summary with WebSocket auto-refresh': + '📊 análisis — uso de tokens por modelo, barras de frecuencia de herramientas, mapa de calor de actividad de 52 semanas, tendencias de sparkline de 30 días, rosquillas de resultado de sesión y resumen de costos con actualización automática de WebSocket', + '🔀 Workflows — D3.js agent orchestration DAG, tool-execution Sankey diagram, directed pipeline graph, effectiveness scorecards, concurrency swim-lanes, and complexity bubble charts': + '🔀 Flujos de trabajo — DAG de orquestación de agentes D3.js, diagrama Sankey de ejecución de herramientas, gráfico de tuberías dirigidas, tarjetas de puntuación de eficacia, carriles de natación de concurrencia y gráficos de burbujas de complejidad', + '🧰 Claude Config Explorer — 12-tab inspector for skills, subagents, slash commands, plugins, MCP servers, hooks, settings, memory, keybindings, and statusline. Safe edits with backups': + '🧰 Explorador de configuración de Claude — Inspector de 12 pestañas para habilidades, subagentes, comandos slash, complementos, servidores MCP, ganchos, configuraciones, memoria, atajos de teclado y línea de estado. Ediciones seguras con copias de seguridad', + '▶️ Run Claude — spawn or resume Claude subprocesses from the browser. Pick Conversation or Headless mode, set cwd, model, permission level, and thinking effort. Same-origin guard included': + '▶️ Corra Claude — Crear o reanudar subprocesos de Claude desde el navegador. Elija Conversación o modo sin cabeza, establezca el directorio actual, el modelo, el nivel de permiso y el esfuerzo de pensamiento. Incluye guardia de origen compartido', + '💬 Run Claude · live stream — character-by-character streaming output. Tool uses, tool results, and thinking blocks are collapsible. Active runs switcher juggles multiple sessions': + '💬 Run Claude · transmisión en vivo - salida de streaming por carácter. Los usos de las herramientas, los resultados de las herramientas y los bloques de pensamiento son colapsables. Las ejecuciones activas del interruptor manejan múltiples sesiones', + '⚙️ Settings — model pricing editor with per-token rates, hook installation status, JSON data export, session cleanup controls, browser notification toggles, and system info panel with DB stats': + '⚙️ Configuración — editor de precios de modelos con tarifas por token, estado de instalación de los enlaces, exportación de datos JSON, controles de limpieza de sesiones, alternaciones de notificaciones del navegador y panel de información del sistema con estadísticas de la base de datos', + "This chart tracks how interest in Claude Code Agent Monitor has grown over time. The curve keeps climbing as more developers discover the project, share it, and use it in real workflows. Each new star is a small vote of confidence from the community.": + "Este gráfico rastrea cómo ha crecido el interés en Claude Code Agent Monitor con el tiempo. La curva sigue subiendo a medida que más desarrolladores descubren el proyecto, lo comparten y lo utilizan en flujos de trabajo reales. Cada nueva estrella es un pequeño voto de confianza de la comunidad.", + ' Enjoying the project? Give it a star on GitHub and help more builders discover it. ': + ' ¿Disfrutando del proyecto? Dale una estrella en GitHub Y ayudar a más constructores a descubrirlo. ', + "Hook Type": "Tipo de gancho", + Trigger: "gatillo", + "Dashboard Action": "Acción del panel de control", + "Claude Code session begins": "Comienza la sesión de Claude Code", + "Creates session and main agent. Stamps awaiting_input_since (with awaiting_reason = session_start) so the row lands in Waiting from the start (the CLI is at a prompt) — except a compact-source SessionStart (mid-turn auto-compaction), which leaves the flag untouched so a working session stays Active. Reactivates resumed sessions. Abandons orphaned sessions with no activity for DASHBOARD_STALE_MINUTES (default 180).": + "Crea sesión y agente principal. sellos awaiting_input_since (con awaiting_reason = session_start) así que la fila aterriza en espera Desde el principio (la CLI está en un mensaje de inicio de sesión) - excepto un compact-Fuente SessionStart (compactación automática a mitad de turno), que deja la bandera sin tocar para que una sesión funcional se mantenga activo. va activa las sesiones suspendidas. Abandona las sesiones huérfanas sin actividad durante DASHBOARD_STALE_MINUTES (por defecto 180).", + "User hits enter on a prompt": "El usuario pulsa enter en una solicitud", + 'Clears the waiting flag and promotes the main agent to Working. The only reliable signal that text-only assistant turns have started — they emit no PreToolUse before Stop.': + 'Borra la bandera de espera y promueve al agente principal a de trabajo. señal confiable de que los teléfonos con asistente de texto solo han comenzado a funcionar: no emiten ninguna PreToolUse antes Stop.', + "Agent begins using a tool": "El agente comienza a usar una herramienta", + 'Clears the waiting flag, sets agent → Working, current_tool set. If tool is Agent, subagent record created.': + 'Borra la bandera de espera, establece agente → de trabajo, current_tool Configurar. Si la herramienta es Agent, registro del subagente creado.', + "Tool execution completes": "La ejecución de la herramienta se completa", + 'Clears the waiting flag (covers permission-prompt approvals mid-tool). current_tool cleared. Agent stays Working.': + 'Borra la bandera de espera (cubre las aprobaciones de la solicitud de permiso a mitad de la herramienta). current_tool Liberado. El agente permanece de trabajo.', + "Claude finishes a turn": "Claude termina una vuelta", + 'Non-error: main agent → waiting — UI shows Waiting until the next user input. stop_reason=error: marks the agent and session Error. Background subagents keep running.': + 'Sin error: agente principal → waiting — Muestra de interfaz de usuario espera Hasta la próxima entrada del usuario. stop_reason=error: marca al agente y la sesión error informático. de los subagentes de fondo siguen funcionando.', + "Background agent finished": "Agente de antecedentes terminado", + "Matched subagent → Completed. Deliberately does not clear the waiting flag — a backgrounded subagent finishing tells us nothing about the human. Also kicks off a fire-and-forget JSONL scan (scanAndImportSubagents) that walks the session's subagents/agent-*.jsonl files, pairs tool_usetool_result blocks by tool_use_id, and emits per-tool PreToolUse + PostToolUse events under each subagent's own agent_id — surfaces tool calls that subagents make internally and which never fire any hooks. The same scan also rebuilds the nested-subagent hierarchy — it repoints each subagent's parent_agent_id to the true spawner recovered from the transcript's Task tool result (toolUseResult.agentId), so subagents that spawn their own subagents nest correctly instead of flattening under main.": + 'Subagente coincidente → Completado. idamente lo hace no Borrar la bandera de espera: un subagente en segundo plano que termina no nos dice nada sobre el humano. También inicia una escaneo JSONL de fuego y olvido (scanAndImportSubagents) que camina por la sesión subagents/agent-*.jsonl Archivos, pares tool_usetool_result Bloques por tool_use_id, y emite por herramienta PreToolUse + PostToolUse Eventos bajo los propios de cada subagente agent_id — las llamadas de herramientas de superficies que los subagentes realizan internamente y que nunca disparan ningún gancho. El mismo escaneo también reconstruye la jerarquía de subagentes anidados: reubica el punto de referencia de cada subagente parent_agent_id Al verdadero generador recuperado del resultado de la herramienta de tareas de la transcripción (toolUseResult.agentId), por lo que los subagentes que generan sus propios subagentes anidan correctamente en lugar de aplanarse bajo el principal.', + "Agent sends notification": "El agente envía una notificación", + 'Event logged to activity feed. Permission/input-prompt patterns (e.g. "needs your permission", "waiting for your input") set the agent to waiting and stamp awaiting_input_since (with awaiting_reason = notification). Compaction-related notifications tagged as Compaction events. Triggers a browser notification if enabled.': + 'Evento registrado en el feed de actividad. Los patrones de permiso/petición de entrada (por ejemplo, "necesita su permiso", "esperando su entrada") establecen al agente para que waiting Y sello awaiting_input_since (con awaiting_reason = notification). Notificaciones relacionadas con la compactación etiquetadas como Compaction Eventos. Desactiva una notificación del navegador si está habilitada.', + "/compact detected in JSONL": "/compact detectado en JSONL", + 'Creates a compaction subagent → Completed. Detected via isCompactSummary entries in the transcript. Token baselines preserve pre-compaction totals. Periodic scanner (cadence ~¼ of DASHBOARD_STALE_MINUTES) catches compactions when no hooks fire.': + 'Crea un subagente de compactación → Completado. detectado a través de isCompactSummary Entradas en la transcripción. Las bases de referencia de tokens conservan los totales previos a la compactación. Escáner periódico (cadencia ~¼ de DASHBOARD_STALE_MINUTES) atrapa compactaciones cuando no disparan los ganchos.', + "API error detected in transcript": "Se ha detectado un error de API en la transcripción", + "Extracted from JSONL during history import, real-time transcript scanning, or the error detection watchdog. Captures quota limits, rate limits, auth failures, and other API errors. Immediately marks sessions and agents as error — previously recorded as events without changing status.": + "Extraído de JSONL durante la importación de historial, el escaneo de transcripciones en tiempo real o el rastreador de detección de errores. Captura los límites de cuota, los límites de tasa, los fallos de autenticación y otros errores de API. Marca inmediatamente las sesiones y los agentes como errores — previamente registrados como eventos sin cambiar el estado.", + "Turn cancelled by the user (Esc)": + "Giro cancelado por el usuario (Esc)", + "Synthesized by the watchdog because pressing Esc fires no hook. Recovered either from the transcript [Request interrupted by user] marker (flagged as pendingInterrupt) or, when Esc preceded any output and left no marker, from the idle-working timeout (DASHBOARD_WORKING_IDLE_SECONDS, default 120). Moves the session to Waiting — the same state a normal Stop produces.": + "Sintetizado por el vigilante porque presionando Esc Fuegos sin gancho. Recuperado ya sea de la transcripción [Request interrupted by user] Marcador (marcado como pendingInterrupt) o, cuando Esc Precedió cualquier salida y no dejó ningún marcador, desde el tiempo de espera de trabajo inactivo (DASHBOARD_WORKING_IDLE_SECONDS, por defecto 120). Mueve la sesión a espera — el mismo estado que un normal Stop Produce.", + "Per-turn timing recorded": "Tiempo por turno registrado", + "Extracted from JSONL turn boundaries. Records the duration of each assistant turn for latency analysis.": + "Extraído de los límites de turno JSONL. Registra la duración de cada turno asistido para el análisis de latencia.", + "Claude Code CLI process exits": "Salida del proceso CLI de Claude Code", + 'Drops the waiting flag. If the session is already in Error, the error state is preserved; otherwise marks all agents and the session as Completed. Evicts the session\'s transcript from the shared cache.': + 'Deja caer la bandera de espera. Si la sesión ya está en error informático, el estado de error se preserva; de lo contrario, marca a todos los agentes y la sesión como Completado. la transcripción de la sesión del caché compartido.', + "Clone the repository to your machine": "Clona el repositorio a tu máquina", + "Run npm run setup to install all dependencies": + "carrera npm run setup Para instalar todas las dependencias", + "Run npm run dev — server + client launch automatically": + "carrera npm run dev — lanzamiento automático del servidor + cliente", + "Start a new Claude Code session — events appear in real-time": + "Inicia una nueva sesión de Claude Code: los eventos aparecen en tiempo real.", + "A multi-stage Dockerfile and docker-compose.yml are included. You can run the monitor with either Docker or Podman and keep the SQLite database in a named volume.": + "Un multiestadio Dockerfile y docker-compose.yml están incluidos. Puedes ejecutar el monitor con Docker o Podman y mantener la base de datos SQLite en un volumen con nombre.", + "Hooks auto-install in local mode": "Los ganchos se instalan automáticamente en modo local", + "When you run the server directly on the host with npm run dev or npm start, it automatically writes Claude Code hook entries to ~/.claude/settings.json. If you run the dashboard in Docker or Podman, install hooks from the host with npm run install-hooks after the container is up, then restart Claude Code. The installer refuses to run inside a container (issue #193) so it never writes a container-internal handler path into a bind-mounted host ~/.claude; override with CCAM_ALLOW_CONTAINER_HOOKS=1 only if Claude Code itself runs in the container.": + "Cuando ejecutas el servidor directamente en el host con npm run dev Oregón npm start, escribe automáticamente entradas de gancho de código Claude en ~/.claude/settings.json. es si ejecutas el panel de control en Docker o Podman, instala los ganchos del host con npm run install-hooks Después de que el contenedor esté activo, reinicie Claude Code. El instalador se niega a ejecutarse dentro de un contenedor (problema #193), por lo que nunca escribe una ruta de manejador interna del contenedor en un host montado en vinculación. ~/.claude; anular con CCAM_ALLOW_CONTAINER_HOOKS=1 Solo si Claude Code en sí mismo se ejecuta en el contenedor.", + "This repository also ships a local MCP server under mcp/ and extension scaffolding for both Claude Code and Codex. These are optional for the dashboard UI, but recommended for complete local-agent workflows. The MCP server supports stdio (for host integration), HTTP+SSE (for remote clients), and an interactive REPL (for operator debugging).": + "Este repositorio también envía un servidor MCP local bajo mcp/ Y andamios de extensión para tanto Claude Code como Codex. Estos son opcionales para la interfaz de usuario del panel de control, pero recomendados para flujos de trabajo completos de agentes locales. El servidor MCP admite stdio (para la integración del host), HTTP+SSE (para clientes remotos) y un REPL interactivo (para el depuración del operador).", + "After starting a Claude Code session, you should see:": + "Después de iniciar una sesión de Claude Code, deberías ver:", + Page: "página", + Expected: "Esperado", + Sessions: "sesión", + 'Your session listed with status Waiting (a fresh CLI is sitting at the prompt) — flips to Active the moment Claude starts a turn': + 'Su sesión listada con estado espera (una CLI nueva está en la consola de comandos) - cambia a activo En el momento en que Claude comienza una vuelta', + "Kanban Board": "Tablero Kanban", + "A Main Agent card in the Waiting column until you type your first message; flips to Working on UserPromptSubmit / PreToolUse and back to Waiting after each Stop": + "A Agente principal Tarjeta en el espera Columna hasta que escribas tu primer mensaje; se voltea a de trabajo en UserPromptSubmit / PreToolUse Y de vuelta a espera Después de cada uno Stop", + "Activity Feed": "Feed de actividad", + 'Events streaming in; click any row to expand payload, use "Session →" to drill into session details': + 'Se están transmitiendo eventos; haga clic en cualquier fila para expandir el contenido de la carga útil, use "Sesión →" para profundizar en los detalles de la sesión', + Dashboard: "panel de control", + "Stats updating in real-time": "Actualización de estadísticas en tiempo real", + "Start server before Claude Code": "Inicia el servidor antes de Claude Code", + "Hooks only fire to a running server. If Claude Code was already running when you started the dashboard, restart the Claude Code session.": + "Los ganchos solo se disparan a un servidor en ejecución. Si Claude Code ya estaba ejecutándose cuando iniciaste el panel de control, reinicia la sesión de Claude Code.", + Variable: "variable", + Default: "valor por defecto", + Description: "descripción", + "Port the Express server listens on": "Puerto en el que el servidor Express escucha", + "Port used by the hook handler to reach the server (for custom port setups)": + "Puerto utilizado por el gestor de ganchos para llegar al servidor (para configuraciones de puertos personalizadas)", + "Base URL used by the local MCP server when calling dashboard APIs": + "URL base utilizada por el servidor MCP local cuando se llaman a las API del panel de control", + "MCP transport mode: stdio, http, repl": + "Modo de transporte MCP: stdio, http, repl", + "Port for the MCP HTTP+SSE server (only when MCP_TRANSPORT=http)": + "Puerto para el servidor MCP HTTP+SSE (solo cuando MCP_TRANSPORT=http)", + "Bind address for the MCP HTTP server": "Vincular la dirección para el servidor HTTP MCP", + "Path to the SQLite database file": "Ruta al archivo de la base de datos SQLite", + "Set to 0 to disable the dead-session liveness reap — the watchdog completes active sessions with no running claude process; auto-disabled on Windows and in containers. Sessions forwarded from another machine (household hooks) report a non-POSIX cwd and are auto-skipped, so a mixed local + forwarded deployment no longer needs this off.": + "Configurado en 0 Para desactivar la recolección de actividad de sesiones inactivas, el vigilante completa las sesiones activas sin ejecución claude Proceso; desactivado automáticamente en Windows y en contenedores. Las sesiones enviadas desde otra máquina (ganchos domésticos) informan de un no POSIX cwd y se saltan automáticamente, por lo que una implementación mixta local + reenviada ya no necesita que esto esté desactivado.", + "Idle gate for watchdog-tick liveness reaps — the transcript must not have been written for at least this long (last hook write is the fallback clock); startup passes skip the gate": + "La puerta inactiva para la vigilia de la vida del reloj de pulso cosecha - la transcripción no debe haber sido escrita durante al menos tanto tiempo (la última escritura del gancho es el reloj de respaldo); las transiciones de arranque saltan la puerta", + "Idle-working timeout the watchdog uses to recover an Esc cancel that left no transcript marker": + "El tiempo de espera de trabajo inactivo que utiliza el rastreador para recuperar un Esc Cancelar eso no dejó ningún marcador de transcripción", + "Poll interval for the background sync of ~/.claude/projects; 0 disables the poll but keeps the filesystem watcher": + "Intervalo de encuesta para la sincronización de fondo de ~/.claude/projects; 0 Desactiva la encuesta pero mantiene el observador del sistema de archivos", + "Set to production to serve built client from client/dist/": + "Configurado en production Para servir clientes construidos desde client/dist/", + "The server writes the following to ~/.claude/settings.json on every startup:": + "El servidor escribe lo siguiente a ~/.claude/settings.json En cada inicio de sesión:", + "Existing hooks are preserved. The installer only adds or updates entries containing hook-handler.js.": + "Los ganchos existentes se conservan. El instalador solo agrega o actualiza entradas que contienen hook-handler.js.", + Script: "guion", + Command: "mando", + "Install all dependencies (server + client)": + "Instalar todas las dependencias (servidor + cliente)", + "Start server + client in development mode with hot reload": + "Iniciar el servidor + cliente en modo de desarrollo con carga rápida", + "Start only the Express server with --watch": + "Inicie solo el servidor Express con --watch", + "Start only the Vite dev server": "Inicie solo el servidor de desarrollo Vite", + "TypeScript check + Vite production build to client/dist/": + "Verificación de TypeScript + construcción de producción de Vite para client/dist/", + "Start Express in production mode serving built client": + "Iniciar Express en modo de producción sirviendo al cliente construido", + "Manually write Claude Code hooks to ~/.claude/settings.json": + "Escriba manualmente los ganchos del código Claude para ~/.claude/settings.json", + "Insert demo sessions, agents, and events (8 sessions / 23 agents / 106 events)": + "Insertar sesiones de demostración, agentes y eventos (8 sesiones / 23 agentes / 106 eventos)", + "Import historical Claude Code sessions from ~/.claude with deep JSONL extraction (API errors, turn durations, thinking blocks, subagent data)": + "Importar sesiones históricas del Código Claude desde ~/.claude Con extracción profunda de JSONL (errores de API, duraciones de turno, bloqueos de pensamiento, datos de subagentes)", + "Delete all data from the database (keeps schema)": + "Borrar todos los datos de la base de datos (mantiene el esquema)", + "Run all server and client tests": "Ejecutar todas las pruebas del servidor y del cliente", + "Server integration tests only (Node built-in test runner)": + "Solo pruebas de integración del servidor (ejecutador de pruebas integrado en Node)", + "Client unit tests only (Vitest + Testing Library)": + "Solo pruebas unitarias del cliente (Vitest + Biblioteca de pruebas)", + "Install dependencies for the local MCP package under mcp/": + "Instale las dependencias del paquete MCP local en mcp/", + "Type-check MCP source without emitting build output": + "Comprueba el tipo de la fuente MCP sin emitir la salida de la compilación", + "Compile MCP server into mcp/build/": + "Compilar el servidor MCP en mcp/build/", + "Start MCP server (stdio transport — for MCP hosts)": + "Iniciar el servidor MCP (transporte stdio - para hosts MCP)", + "Start MCP HTTP+SSE server on port 8819 (Streamable HTTP + legacy SSE)": + "Inicie el servidor MCP HTTP+SSE en el puerto 8819 (HTTP transmisible + SSE heredado)", + "Start interactive MCP REPL with tab completion and colored output": + "Inicie MCP REPL interactivo con completación de pestañas y salida coloreada", + "Run MCP server in dev mode with tsx (stdio)": + "Ejecute el servidor MCP en modo de desarrollo con tsx (estdio)", + "Run MCP HTTP server in dev mode with tsx": + "Ejecute el servidor HTTP MCP en modo de desarrollo con tsx", + "Run MCP REPL in dev mode with tsx": + "Ejecute MCP REPL en modo de desarrollo con tsx", + "Build MCP container image with Docker (agent-dashboard-mcp:local)": + "Construye la imagen de contenedor MCP con Docker (agent-dashboard-mcp:local)", + "Build MCP container image with Podman (localhost/agent-dashboard-mcp:local)": + "Construye la imagen de contenedor MCP con Podman (localhost/agent-dashboard-mcp:local)", + "Run MCP server unit tests": "Ejecutar pruebas unitarias del servidor MCP", + "Install Electron + electron-builder under desktop/; rebuilds better-sqlite3 for Electron's ABI. Preflights the native better-sqlite3 build; prints actionable setup help (incl. a no-toolchain alternative) on failure": + "Instala Electron + electron-builder bajo desktop/; reconstruye better-sqlite3 Para la ABI de Electron. Previa al nativo better-sqlite3 Construir; imprime ayuda de configuración factible (incluyendo una alternativa sin cadena de herramientas) en caso de fallo", + "Prebuild guard + tsc compile of the Electron main process into desktop/out/": + "Guardia preconstruida + tsc Compilación del proceso principal de Electron en desktop/out/", + "Build, then launch the desktop app against desktop/out/main.js": + "Cree, luego lance la aplicación de escritorio contra desktop/out/main.js", + "Desktop smoke test — spawn Electron and probe /api/health": + "Prueba de humo en el escritorio: genera Electron y prueba /api/health", + "Build both per-arch DMGs (arm64 + x64). Correct for release — slower (packages each arch)": + "cuerpo ambos DMG por archivo (arm64 + x64). Correcto para la versión de lanzamiento, más lento (paquetes por cada archivo)", + "Build an Apple-Silicon-only DMG — fast (~1 min), recommended for a single machine": + "Cree un DMG exclusivo de Apple-Silicona: rápido (~1 min), recomendado para una sola máquina.", + "Build an Intel-only DMG — fast (macOS host)": + "Cree un DMG exclusivo para Intel: rápido (host macOS)", + "Build one merged universal DMG (arm64 + x86_64 in a single file). Optional, slowest — not what the release ships": + "Cree un DMG universal fusionado (arm64 + x86_64 en un solo archivo). Opcional, el más lento, no es lo que se envía con la versión de lanzamiento", + "Build the Windows NSIS installer ClaudeCodeMonitor-Setup-<ver>-x64.exe (Windows host)": + "Construir el instalador NSIS de Windows ClaudeCodeMonitor-Setup-<ver>-x64.exe (Hospedador de Windows)", + "Build the no-install portable ClaudeCodeMonitor-<ver>-x64-portable.exe (Windows host)": + "Construye el portátil sin instalación ClaudeCodeMonitor-<ver>-x64-portable.exe (Hospedador de Windows)", + "Regenerate desktop/assets/icon.ico from icon.png (PowerShell + .NET; Windows host)": + "regenerar desktop/assets/icon.ico de icon.png (PowerShell + .NET; host Windows)", + "Format all files with Prettier": "Formatea todos los archivos con Prettier", + "Check formatting without writing": "Comprueba el formato sin escribir nada", + "Core dashboard telemetry is composed of three processes (Claude hook source, dashboard server, browser UI). When the local MCP sidecar is enabled, it integrates with the same dashboard API via stdio, HTTP+SSE, or interactive REPL transport.": + "La telemetría del panel de control principal está compuesta por tres procesos (fuente de gancho Claude, servidor del panel de control, interfaz de usuario del navegador). Cuando se activa el sidecar MCP local, se integra con la misma API del panel de control a través de stdio, HTTP+SSE o transporte REPL interactivo.", + "Full system architecture — Claude Code process → Hook Layer → Server → Browser": + "Arquitectura completa del sistema: proceso Claude Code → Capa de conexión → Servidor → Navegador", + "Agent status transitions driven by hook events. waiting is a real persisted status — agents start as waiting and return to it after each turn. Error recovery requires active user retry (UserPromptSubmit or PreToolUse). A background watchdog detects API errors in transcripts every 15 s. The same watchdog also recovers Esc-cancelled turns — via either the transcript [Request interrupted by user] marker or the idle-working timeout when Esc preceded any output — and moves the session to Waiting.": + "Transiciones de estado del agente impulsadas por eventos de gancho. waiting Es un estado persistente real: los agentes comienzan como waiting Y vuelva a él después de cada turno. La recuperación de errores requiere que el usuario activo intente de nuevo (UserPromptSubmit Oregón PreToolUse). Un vigilante de fondo detecta errores de API en las transcripciones cada 15 segundos. El mismo vigilante también recupera Esc-vueltas canceladas, a través de la transcripción o de otra manera. [Request interrupted by user] Marcador o el tiempo de espera de funcionamiento inactivo cuando Esc precedió cualquier salida y mueve la sesión a Esperando.", + "Session status lifecycle. waiting is a UI overlay — persisted as active with awaiting_input_since set and awaiting_reason recording why (session_start, stop, notification, or interrupted). SessionEnd preserves error state. Error recovery requires UserPromptSubmit or PreToolUse. The watchdog also recovers Esc-cancelled turns (marker or idle-timeout path) and moves the session to Waiting. The dashboard surfaces the reason on every Waiting badge (hover tooltip, plus an inline chip on the Sessions table and session detail header) and in a waiting-for-input banner on the session detail page.": + "Ciclo de vida del estado de la sesión. waiting Es una superposición de interfaz de usuario - persistente como active con awaiting_input_since Configurar y awaiting_reason Grabando por qué (session_start, stop, notification, o interrupted). SessionEnd Preserva el estado de error. La recuperación de errores requiere UserPromptSubmit Oregón PreToolUse. también recupera Esc-cancela los turnos (ruta de marcador o tiempo de espera inactivo) y mueve la sesión a Esperando. La interfaz de usuario muestra la razón en cada distintivo de Esperando (pestaña de información al pasar el cursor sobre el objeto, además de un chip inline en la tabla de Sesiones y en el encabezado de detalles de la sesión) y en un banner de espera de entrada en la página de detalles de la sesión.", + "Complete event ingestion from hook fire to browser re-render": + "Ingestión completa del evento desde el fuego del gancho hasta la re-renderización del navegador", + "Initial load + WebSocket subscription lifecycle": + "Carga inicial + ciclo de vida de la suscripción de WebSocket", + "Server module dependency graph": "Gráfico de dependencias del módulo del servidor", + Module: "circuito", + Responsibility: "responsabilidad", + "Express app setup, middleware (CORS, JSON 1MB limit), route mounting, static serving in production, HTTP server, auto-hook installation on startup": + "Configuración de la aplicación Express, middleware (CORS, límite de JSON de 1 MB), montaje de rutas, servicio estático en producción, servidor HTTP, instalación automática de ganchos al inicio de sesión", + "SQLite connection, WAL/FK pragmas, schema migrations (CREATE TABLE IF NOT EXISTS), all prepared statements as a reusable stmts object. Tries better-sqlite3 first, falls back to built-in node:sqlite via compat-sqlite.js": + "Conexión SQLite, pragmas WAL/FK, migraciones de esquema (CREATE TABLE IF NOT EXISTS), todas las declaraciones preparadas como reutilizables stmts Objeto. Intenta better-sqlite3 En primer lugar, vuelve a lo incorporado node:sqlite a través de compat-sqlite.js", + "Compatibility wrapper giving Node.js built-in node:sqlite (DatabaseSync) the same API as better-sqlite3 — pragma, transaction, prepare. Used as automatic fallback on Node 22+": + "Envoltorio de compatibilidad que da Node.js incorporado node:sqlite (DatabaseSync) la misma API que better-sqlite3 — pragma, transacción, preparar. Se utiliza como fallback automático en Node 22+", + "WebSocket server on /ws path, 30s ping/pong heartbeat, typed broadcast(type, data) function": + "Servidor WebSocket encendido /ws Camino, latido de ping/pong de 30s, escrito a mano broadcast(type, data) función", + "Core event processing inside SQLite transactions. Auto-creates sessions/agents. Switch-case dispatch by hook type. Extracts token usage from Stop events.": + "Procesamiento de eventos centrales dentro de las transacciones de SQLite. Crea automáticamente sesiones/agentes. Despacho de casos por tipo de gancho. Extrae el uso de tokens de los eventos Stop.", + "CRUD with pagination. GET includes agent count via LEFT JOIN. POST is idempotent on session ID.": + "CRUD con paginación. GET incluye el número de agentes a través de LEFT JOIN. POST es idempotente en el ID de la sesión.", + "CRUD with status/session_id filtering. PATCH broadcasts agent_updated.": + "CRUD con filtrado por estado/session_id. Transmisiones PATCH agent_updated.", + "Read-only event listing with session_id filter and pagination.": + "Lista de eventos de solo lectura con filtro session_id y paginación.", + "Single aggregate query — total/active counts, status distributions, WS connection count.": + "Consulta agregada única: conteos totales/activos, distribuciones de estado, conteo de conexiones WS.", + "Extended analytics — token totals, tool usage counts, daily event/session trends, agent type distribution, event type breakdown, average events per session.": + "Análisis extendido: totales de tokens, conteos de uso de herramientas, tendencias diarias de eventos/sesiones, distribución del tipo de agente, desglose del tipo de evento, eventos promedio por sesión.", + "Model pricing CRUD (list, upsert, delete). Per-session and global cost calculation with pattern-based model matching and specificity sorting.": + "Precio de modelos CRUD (lista, inserción, eliminación). Cálculo de costos por sesión y global con coincidencia de modelos basada en patrones y clasificación por especificidad.", + "System info (DB size, row counts, hook status, server uptime). Data export as JSON. Session cleanup (abandon stale active sessions, purge old completed sessions). Clear all data. Reset pricing to defaults. Reinstall hooks.": + "Información del sistema (tamaño de la base de datos, número de filas, estado del gancho, tiempo de actividad del servidor). Exportación de datos como JSON. Limpieza de sesiones (abandonar sesiones activas obsoletas, purgar sesiones antiguas completadas). Borrar todos los datos. Restablecer los precios a los valores predeterminados. Reinstalar los ganchos.", + "Aggregate workflow visualization data (agent orchestration, tool transitions, collaboration networks, workflow patterns, model delegation, error propagation, concurrency, session complexity, compaction impact). Accepts ?status=active|completed filter. Per-session drill-in with agent tree, tool timeline, and events.": + "Datos de visualización agregada del flujo de trabajo (orquestación de agentes, transiciones de herramientas, redes de colaboración, patrones de flujo de trabajo, delegación de modelos, propagación de errores, concurrencia, complejidad de sesiones, impacto de la compactación). Acepta ?status=active|completed Filtro. Entrenamiento detallado por sesión con árbol de agentes, línea de tiempo de herramientas y eventos.", + "React component tree": "Árbol de componentes React", + Purpose: "propósito", + "lib/api.ts": "lib/api.ts", + "Typed fetch wrapper — one method per REST endpoint. All return typed promises.": + "Envoltorio de recuperación de texto — un método por punto final REST. Todo devuelve promesas de texto.", + "lib/types.ts": "lib/types.ts", + "TypeScript interfaces: Session, Agent, DashboardEvent, Stats, Analytics, WSMessage, plus all workflow-related types (WorkflowData, SessionDrillIn, etc). Status config maps.": + "Interfaces de TypeScript: Session, Agent, DashboardEvent, Stats, Analytics, WSMessage, además de todos los tipos relacionados con el flujo de trabajo (WorkflowData, SessionDrillIn, etc). Mapa de configuración de estado.", + "lib/eventBus.ts": "lib/eventBus.ts", + "Set-based pub/sub. subscribe(fn) returns an unsubscribe function for clean useEffect teardown.": + "Pub/sub basado en conjuntos. subscribe(fn) Devuelve una función de cancelación de suscripción para la desinstalación limpia de useEffect.", + "lib/format.ts": "lib/format.ts", + "Date/time formatting helpers — relative time, duration, ISO display.": + "Ayudantes de formateo de fecha/hora: tiempo relativo, duración, visualización ISO.", + "hooks/useWebSocket.ts": "hooks/useWebSocket.ts", + "Auto-reconnecting WebSocket React hook. 2-second reconnect interval. Publishes messages to eventBus.": + "Gancho React WebSocket de reconectividad automática. Intervalo de reconectividad de 2 segundos. Publica mensajes en eventBus.", + "The dashboard is a Progressive Web App with its own manifest.json and Service Worker (client/public/sw.js). The landing page and wiki are also independent PWAs with separate manifests and service workers.": + "El panel de control es una aplicación web progresiva con su propia manifest.json Y Trabajador de Servicio (client/public/sw.js). La página de inicio y la wiki también son PWAs independientes con manifiestos y trabajadores de servicio separados.", + Surface: "superficie", + Manifest: "manifiesto", + "Service Worker": "Trabajador de servicio", + Strategy: "estrategia", + "client/public/manifest.json": "client/public/manifest.json", + "client/public/sw.js": "client/public/sw.js", + "Precaches app shell. Cache-first for static assets (JS/CSS bundles). Network-first for navigation with offline fallback. Skips /api/*, /ws, and Vite HMR. Preserves push notification handlers.": + "Precarga la cáscara de la aplicación. Cache primero para activos estáticos (paquetes JS/CSS). Red primero para la navegación con fallback sin conexión. Saltos /api/*, /ws, y Vite HMR. Preserva los manejadores de notificaciones push.", + "Landing page": "página de aterrizaje", + "manifest.json (root)": "manifest.json (raíz)", + "sw.js (root)": "sw.js (raíz)", + "Precaches HTML shell, favicon, OG image. Lazy-caches screenshot PNGs on first view. Network-first HTML, cache-first assets.": + "Precarga la cáscara HTML, el icono favorito e la imagen OG. Carga en caché las capturas de pantalla PNG en la primera vista. HTML primero en la red, activos primero en la caché.", + Wiki: "wiki", + "wiki/manifest.json": "wiki/manifest.json", + "wiki/sw.js": "wiki/sw.js", + "Precaches index.html, style.css, script.js. Fully offline after one visit.": + "Precarga index.html, style.css, script.js. completamente desactivado después de una visita.", + 'All three SWs call skipWaiting() on install and delete stale caches on activate (keyed by version strings like dashboard-v1). Manifests use SVG icons (favicon.svg) with sizes="any". iOS standalone mode is enabled via apple-mobile-web-app-capable meta tags.': + 'Los tres SW llaman skipWaiting() Al instalar y eliminar cachés obsoletos al activar (claveada por cadenas de versión como dashboard-v1). Manifesta el uso de iconos SVG (favicon.svg) con sizes="any". El modo independiente de iOS está habilitado a través de apple-mobile-web-app-capable Etiquetas meta.', + "The client deliberately avoids Redux / Zustand / Context. Each page owns its data and lifecycle. WebSocket events trigger a reload or append — no complex state merging.": + "El cliente evita deliberadamente Redux / Zustand / Context. Cada página posee sus propios datos y ciclo de vida. Los eventos WebSocket desencadenan una recarga o un apéndice, sin fusión compleja de estados.", + "No global store — by design": "Sin tienda global, por diseño", + "There is no cross-page shared state. Each page fetches and owns exactly the data it displays. This simplifies debugging and avoids stale-closure hazards that are common with global stores in long-running WebSocket apps.": + "No hay estado compartido entre páginas. Cada página recupera y posee exactamente los datos que muestra. Esto simplifica el depuración y evita los peligros de cierre obsoleto que son comunes con las almacenes globales en aplicaciones WebSocket de larga duración.", + Index: "índice", + Table: "mesa", + "Column(s)": "Columna(s)", + "Fast agent lookup by session": "Búsqueda rápida de agentes por sesión", + "Kanban column queries": "Consultas de columnas Kanban", + "Session detail event list": "Lista de eventos de detalles de la sesión", + "Filter events by type": "Filtrar eventos por tipo", + "Activity feed ordering": "Pedido de alimentación de actividad", + "Status filter on sessions page": "Filtro de estado en la página de sesiones", + "Default sort order": "Orden de clasificación predeterminado", + Pragma: "Pragma", + Value: "valor", + Rationale: "razones", + "Concurrent reads during writes. Far better for read-heavy dashboards.": + "Lecturas concurrentes durante las escrituras. Mucho mejor para paneles de control con mucha carga de lectura.", + "Referential integrity — prevents orphaned agents/events.": + "Integridad referencial: evita agentes/eventos huérfanos.", + "Wait up to 5s for write lock instead of failing immediately under load.": + "Espera hasta 5 segundos para el bloqueo de escritura en lugar de fallar inmediatamente bajo carga.", + 'All endpoints return JSON. Errors follow { "error": { "code", "message" } }. The OpenAPI 3.0 spec comprehensively documents every backend route - parameters, request/response schemas, field descriptions, and examples. It is served at /api/openapi.json (with a committed openapi.yaml mirror), rendered as interactive Swagger UI at /api/docs, and as a clean, read-optimized ReDoc reference at /api/redoc. ReDoc is self-hosted, so it works fully offline.': + 'Todos los puntos finales devuelven JSON. Seguen los errores { "error": { "code", "message" } }. API 3.0 especifica documenta de forma exhaustiva cada ruta de backend: parámetros, esquemas de solicitud/respuesta, descripciones de campos y ejemplos. Se sirve en /api/openapi.json (con un comprometido openapi.yaml Espejo), renderizado como una interfaz de usuario interactiva de Swagger en /api/docs, y como una referencia ReDoc limpia y optimizada para la lectura en /api/redoc. Doc es auto alojado, por lo que funciona completamente sin conexión.', + '📘 Swagger UI at /api/docs — auto-generated interactive playground for every REST endpoint. Try-it-out forms, request/response schema, auth headers, and curl snippets': + '📘 Interfaz de usuario Swagger en /api/docs — patio de recreo interactivo generado automáticamente para cada punto final REST. Formularios de prueba, esquema de solicitud/respuesta, encabezados de autenticación y fragmentos de curl', + Property: "propiedad", + Path: "recorrido", + Protocol: "protocolo de comunicación", + "Standard WebSocket (RFC 6455)": "WebSocket estándar (RFC 6455)", + Heartbeat: "latido", + "Server pings every 30s — clients that don't pong are terminated": + "El servidor envía ping cada 30 segundos, los clientes que no envían ping se terminan.", + Reconnect: "volver a conectar", + "Client retries every 2 seconds on disconnect": + "El cliente vuelve a intentarlo cada 2 segundos al desconectarse", + "Client WebSocket auto-reconnect state machine": + "Máquina de estado de conexión automática de WebSocket del cliente", + "scripts/hook-handler.js is a minimal, fail-safe forwarder. It always exits 0 so it can never block Claude Code regardless of server state.": + "scripts/hook-handler.js Es un reenvío mínimo y seguro de fallo. Siempre sale 0 para que nunca pueda bloquear el código Claude independientemente del estado del servidor.", + "hook-handler.js flow — always exits 0, never blocks Claude Code": + "Flow de hook-handler.js: siempre sale 0, nunca bloquea el código de Claude.", + "Hook installation is idempotent — safe to run multiple times": + "La instalación del gancho es idempotente, es decir, es segura para ejecutarse varias veces.", + '📥 Settings → Import History — rescan default paths, set a custom directory, or drag-and-drop .gz archives. Progress bar and result card show counts for every run': + '📥 Configuración → Historial de importación — volver a escanear los rutas predeterminadas, establecer una carpeta personalizada o arrastrar y soltar .gz Archivos. La barra de progreso y la tarjeta de resultados muestran los conteos para cada ejecución', + "The dashboard ships with a first-class history importer that backfills sessions, agents, events, tokens, and costs from Claude Code JSONL transcripts. Live hook ingestion and manual import share the exact same parser — parseSessionFile + importSession in scripts/import-history.js — which is the architectural contract that guarantees imported token totals and cost values are identical to those captured in real time. Re-imports are idempotent: session IDs are the dedup key and compaction baseline_* columns preserve pre-compaction token totals.": + "El panel de instrumentos viene con una primera clase Importador de historial que rellena las sesiones, agentes, eventos, tokens y costos de las transcripciones de Claude Code JSONL. La ingestión de enlaces en vivo e importación manual comparten el mismo parser exactamente - parseSessionFile + importSession indio scripts/import-history.js — que es el contrato arquitectónico que garantiza que los totales de tokens importados y los valores de costo sean idénticos a los capturados en tiempo real. Las reimportaciones son idempotentes: los ID de sesión son la clave de deduplicación y la compactación baseline_* Las columnas conservan los totales de tokens de precompactación.", + "All three modes funnel into the same parser and DB transaction — imported numbers match live capture bit-for-bit": + "Los tres modos convergen en el mismo analizador y transacción de la base de datos: los números importados coinciden bit a bit con la captura en vivo.", + "Upload path: multipart → safe extract → walk → parse → import — every temp dir reclaimed in finally": + "Ruta de subida: multipart → extracto seguro → caminar → analizar → importar, cada directorio temporal recuperado en finally", + "The baseline_* columns make cost monotonic under re-imports — compacted sessions retain pre-compaction usage for billing": + "el baseline_* Las columnas hacen que el costo sea monótono bajo las reimportaciones: las sesiones compactadas conservan el uso previo a la compactación para la facturación", + Layout: "diseño", + Example: "ejemplo", + Handling: "manipulación", + "Default Claude Code": "Código Claude predeterminado", + "Session transcript — extracts tokens, compactions, tool uses, turn durations": + "Transcripción de la sesión: extrae tokens, compactaciones, usos de herramientas, duraciones de las rondas", + "Default subagent": "Subagente predeterminado", + "Paired with parent on discovery via findSessionSubagents": + "Emparejado con el progenitor en la descubrimiento a través de findSessionSubagents", + "Alternative subagent": "Subagente alternativo", + "Paired with parent on discovery (second layout probed automatically)": + "Emparejado con el padre en la exploración (segundo diseño explorado automáticamente)", + "Orphan subagent": "Subagente huérfano", + "No parent JSONL in source, but sid exists in DB": + "No hay JSONL padre en el código fuente, pero sid existe en la BD", + "importFromDirectory probes both layouts; attaches if the parent is found": + "importFromDirectory Probará ambos diseños; se adjunta si se encuentra el padre", + "Flat JSONL drop": "Caída plana de JSONL", + "Recognized as a loose session transcript": + "Reconocido como una transcripción de sesión suelta", + Archives: "archivo", + "Extracted into a per-request temp dir, then walked by the same importer": + "Extraído en una carpeta temporal por solicitud, luego pasó por el mismo importador", + "Single-file gzip": "Gzip de archivo único", + "Gunzipped in streaming mode with running byte-counter size cap": + "Desbloqueado en modo de transmisión con límite de tamaño del contador de bytes en ejecución", + Threat: "amenaza", + Mitigation: "moderación", + "Path traversal via archive entries": + "Recorrido del camino a través de las entradas del archivo", + "archive.safeJoin resolves under the extraction root; any .. or absolute path returns null": + "archive.safeJoin Resuelve bajo la raíz de extracción; cualquier .. O devoluciones de ruta absoluta null", + "Zip / tar / gzip bombs": "Bombas Zip / tar / gzip", + "MAX_EXTRACT_BYTES (default 4 GB) enforced by running byte counter; aborts with ExtractionLimitError → HTTP 413": + "MAX_EXTRACT_BYTES (por defecto 4 GB) aplicado mediante el funcionamiento del contador de bytes; se interrumpe con ExtractionLimitError → HTTP 413", + "Per-file upload size abuse": "Abuso del tamaño de carga de archivos por archivo", + "multer limits.fileSize = MAX_UPLOAD_BYTES (default 1 GB)": + "Abusar sexualmente limits.fileSize = MAX_UPLOAD_BYTES (por defecto 1 GB)", + "Too many files per request": "Demasiados archivos por solicitud", + "multer limits.files = MAX_UPLOAD_FILES (default 2000)": + "Abusar sexualmente limits.files = MAX_UPLOAD_FILES (por defecto 2000)", + "Unsupported file types": "Tipos de archivos no compatibles", + "fileFilter drops them early and reports them in rejected_files[]": + "fileFilter Los deja temprano y los informa rejected_files[]", + "Concurrent upload temp-dir collisions": + "Colisiones temporales de directorios de carga en paralelo", + "Per-request temp dir on req._ccamUploadDir; created in multer destination, reclaimed in finally": + "Directorio temporal por solicitud activado req._ccamUploadDir; creado en multer destination, recuperado en finally", + "Arbitrary absolute path on scan-path": + "Ruta absoluta arbitraria en scan-path", + "Validated: must be absolute (after ~ expansion), exist, and be a directory": + "Validado: debe ser absoluto (después de ~ Expansión), existir y ser un directorio", + "Relative / traversal paths on scan-path": + "Rutas relativas / de recorrido en scan-path", + "Rejected with INVALID_INPUT": "Rechazado con INVALID_INPUT", + "Maximum size per uploaded file on /api/import/upload": + "Tamaño máximo por archivo cargado en /api/import/upload", + "Maximum files per upload request": "Archivos máximos por solicitud de carga", + "Ceiling on total uncompressed bytes from any single archive (zip-bomb defense)": + "Techo sobre los bytes totales no comprimidos de cualquier archivo individual (defensa contra zip-bomb)", + "Every import emits import.progress messages on /ws. Messages are throttled to at most one every ~150 ms to avoid flooding the channel on multi-thousand-session imports; the terminal complete and error frames are never throttled.": + "Cada importación emite import.progress Mensajes en /ws. se limitan a un máximo de un mensaje cada ~150 ms para evitar inundar el canal en importaciones de múltiples sesiones de miles de usuarios; el terminal complete y error Los fotogramas nunca se limitan.", + "Phases: startscanextract (upload only) → parsecomplete, with error / extract_error replacing complete on failure.": + "Fases: startscanextract (solo para subir archivos) → parsecomplete, con error / extract_error Reemplazando complete En caso de fracaso.", + "In addition to dashboard telemetry, this project includes a production-grade local MCP server and complete extension scaffolding for both Claude Code and Codex. This gives agents a richer local tool surface while keeping all execution local-first. The MCP server supports three transport modes: stdio for host integration, HTTP+SSE for remote clients, and an interactive REPL for operator debugging.": + "Además de la telemetría del panel de control, este proyecto incluye un servidor MCP local de grado de producción y una estructura de escalera de extensión completa para tanto Claude Code como Codex. Esto da a los agentes una superficie de herramienta local más rica mientras mantiene toda la ejecución local primero. El servidor MCP admite tres modos de transporte: stdio para la integración del host, HTTP+SSE para los clientes remotos y un REPL interactivo para el depuración del operador.", + '🔧 MCP Server REPL — interactive tool invocation terminal with colored JSON output, argument prompts, error formatting, and session-aware context for rapid testing': + '🔧 MCP Server REPL: terminal de invocación de herramientas interactivas con salida JSON coloreada, mensajes de inicio de sesión, formato de errores y contexto consciente de sesiones para pruebas rápidas.', + "Local extension architecture: host instructions + skills + multi-transport MCP sidecar": + "Arquitectura de extensión local: instrucciones del host + habilidades + MCP sidecar de transporte múltiple", + "The mcp/ package exposes dashboard-oriented tools for AI agents across three transport modes. Mutation and destructive operations are policy-gated by environment variables and disabled by default. HTTP mode serves both Streamable HTTP (protocol 2025-11-25) and legacy SSE (protocol 2024-11-05). REPL mode provides tab-completed interactive tool invocation with colored output and JSON syntax highlighting.": + "el mcp/ El paquete expone herramientas orientadas a la consola para agentes de IA en tres modos de transporte. Las mutaciones y las operaciones destructivas están restringidas por políticas mediante variables ambientales y están desactivadas por defecto. El modo HTTP sirve tanto para HTTP transmisible (protocolo 2025-11-25) como para SSE heredado (protocolo 2024-11-05). El modo REPL proporciona la invocación interactiva de herramientas completadas con pestañas con salida coloreada y resaltado de sintaxis JSON.", + Component: "componente", + Location: "lugar", + Notes: "Notas", + "MCP source": "Fuente MCP", + "TypeScript server, tools, policy guards, transport layer, CLI UI": + "Servidor TypeScript, herramientas, guardias de políticas, capa de transporte, interfaz de usuario de línea de comandos", + "MCP build output": "Salida de la construcción de MCP", + "Compiled JavaScript runtime for all transport modes": + "Ejecución compilada de JavaScript para todos los modos de transporte", + "MCP docs": "Documentos MCP", + "Tool catalog, architecture diagrams, host integration examples, REPL guide": + "Catálogo de herramientas, diagramas de arquitectura, ejemplos de integración de host, guía de REPL", + "Transport layer": "Nivel de transporte", + "HTTP+SSE server, interactive REPL, tool handler collector": + "Servidor HTTP+SSE, REPL interactivo, recopilador de manejadores de herramientas", + "CLI UI": "CLI UI", + "ANSI banner, colors, formatter with tables, boxes, JSON highlighting": + "Banner ANSI, colores, formateador con tablas, cajas, resaltado JSON", + "Runtime commands": "Comandos de tiempo de ejecución", + "Start MCP in stdio, HTTP+SSE, or REPL mode (production or dev)": + "Inicie MCP en modo stdio, HTTP+SSE o REPL (producción o desarrollo)", + Target: "blanco", + Files: "Archivos", + "Claude Code": "Código Claude", + "Persistent project instructions + path-scoped coding rules": + "Instrucciones persistentes del proyecto + reglas de codificación con alcance de ruta", + "Claude Code Skills": "Habilidades de código Claude", + "Reusable workflows (onboarding, shipping, MCP ops, live debugging)": + "Procesos de trabajo reutilizables (integración, envío, operaciones MCP, depuración en vivo)", + "Claude Code Subagents": "Subagentes del código Claude", + "Specialized reviewers for backend, frontend, and MCP code paths": + "Revisores especializados para rutas de código de backend, frontend y MCP", + "Codex Base Instructions": "Instrucciones básicas del Codex", + "Project-wide guidance + execution policy defaults": + "Guía general para todo el proyecto + valores predeterminados de la política de ejecución", + "Codex Skills": "Habilidades del Codex", + "Task-specific skills aligned to this repository": + "Habilidades específicas para tareas alineadas con este repositorio", + "Codex Agents": "Agentes del Codex", + "Reusable custom-agent templates for implementation and review": + "Plantillas de agentes personalizadas reutilizables para la implementación y revisión", + Role: "papel", + "Receives Claude hook payloads over stdin and forwards them to dashboard API": + "Recibe cargas útiles de gancho Claude a través de stdin y las envía a la API del panel de control", + "Writes/updates hook registration in ~/.claude/settings.json": + "Escribe/actualiza el registro del gancho en ~/.claude/settings.json", + "Batch history importer used by server startup auto-import, the /api/import/* routes, and the import-history CLI. Exposes importAllSessions() for the default projects dir and the generalized importFromDirectory(dbModule, rootDir, {onProgress}) which walks any directory recursively, classifies session vs subagent JSONLs (probes both <proj>/<sid>/subagents/* and <proj>/subagents/<sid>/* layouts), and funnels everything through the shared parseSessionFile + importSession pipeline — identical to live ingest. Re-import is fully incremental: a per-event-type high-water mark (MAX(created_at) GROUP BY event_type for the session) drives ts > cutoff[type] dedup for Stop / PostToolUse / TurnDuration / ToolError, so long-running sessions whose transcripts grow across multiple days keep receiving new events on every re-run. sessions.ended_at is rolled forward when the JSONL has progressed past the stored value, and message-count metadata is refreshed on every pass. Session-ID dedup and baseline_* preservation keep token totals stable. Extracts tokens, API errors, turn durations, thinking blocks, usage extras, and per-subagent breakdowns": + "Importador de historial de lotes utilizado por la importación automática de inicio del servidor, el /api/import/* Rutas, y el import-history CLI. Expone importAllSessions() Para la carpeta de proyectos predeterminada y la generalizada importFromDirectory(dbModule, rootDir, {onProgress}) Que recorre cualquier directorio recursivamente, clasifica JSONL de sesiones vs subagentes (probar ambos <proj>/<sid>/subagents/* y <proj>/subagents/<sid>/* Diseños de plantillas), y canaliza todo a través del compartido parseSessionFile + importSession túnel de tuberías — idéntico a la ingestión en vivo. La reimportación es totalmente incremental: un punto máximo de agua alta por tipo de evento (MAX(created_at) GROUP BY event_type Para la sesión) conduce ts > cutoff[type] Deduplicación para Stop / PostToolUse / TurnDuration / ToolError, por lo que las sesiones de larga duración cuyas transcripciones crecen a lo largo de varios días siguen recibiendo nuevos eventos en cada ejecución. sessions.ended_at Se desplaza hacia adelante cuando el JSONL ha avanzado más allá del valor almacenado, y los metadatos de contador de mensajes se actualizan en cada pasada. Deduplicación de ID de sesión y baseline_* preservación mantiene los totales de tokens estables. Extrae tokens, errores de API, duraciones de turnos, bloqueos de pensamiento, extras de uso y desgloses por subagente.", + "Express router for Import History. Four endpoints: GET /api/import/guide (OS-aware instructions + default-dir stats), POST /api/import/rescan (default ~/.claude/projects), POST /api/import/scan-path (arbitrary absolute dir with ~ expansion), POST /api/import/upload (multer multipart). Each request uses a per-request temp dir reclaimed in finally. Progress broadcast as throttled import.progress WebSocket messages. Limits tunable via CCAM_IMPORT_MAX_BYTES, CCAM_IMPORT_MAX_FILES, CCAM_IMPORT_MAX_EXTRACT_BYTES": + "Router Express para Historial de Importaciones. Cuatro puntos finales: GET /api/import/guide (Instrucciones conscientes del sistema operativo + estadísticas de la carpeta predeterminada), POST /api/import/rescan (por defecto ~/.claude/projects), POST /api/import/scan-path (dirección absoluta arbitraria con ~ Expansión), POST /api/import/upload (multipart multipart). Cada solicitud utiliza una carpeta temporal por solicitud recuperada en finally. de transmisión de progreso como restringido import.progress Mensajes WebSocket. Los límites se pueden ajustar a través de CCAM_IMPORT_MAX_BYTES, CCAM_IMPORT_MAX_FILES, CCAM_IMPORT_MAX_EXTRACT_BYTES", + "Safe archive extraction: .zip via adm-zip, .tar/.tar.gz/.tgz via tar, plain .gz streaming via zlib. Every entry validated through safeJoin which rejects absolute paths and .. traversal before any bytes are written. Enforces a hard MAX_EXTRACT_BYTES cap (default 4 GB) with ExtractionLimitError surfaced as HTTP 413 — defense against zip/tar/gzip bombs": + "Extracción segura del archivo: .zip a través de adm-zip, .tar/.tar.gz/.tgz a través de tar, simple .gz Transmisión en streaming a través de zlib. validada por cada entrada a través de safeJoin Que rechaza caminos absolutos y .. Recorrido antes de que se escriban ningún byte. Impone un duro MAX_EXTRACT_BYTES Límite de almacenamiento (por defecto 4 GB) con ExtractionLimitError Surge como HTTP 413: defensa contra bombas zip/tar/gzip.", + "Loads deterministic demo data for testing and demos": + "Carga datos de demostración deterministas para pruebas y demostraciones", + "Removes persisted rows while preserving schema": + "Elimina las filas persistentes mientras preserva el esquema", + "The Agent Monitor ships with an official Claude Code plugin marketplace containing ten production-ready plugins (53 skills, 14 agents, 30 slash commands, 3 CLI tools, 3 hook configs, and 1 MCP server). These extend Claude Code with skills, agents, hooks, CLI tools, and MCP integration — all grounded in the real data model (token tracking with compaction baselines, cost calculation via pattern-matched pricing rules, workflow intelligence with 11 datasets per session, and session metadata including thinking blocks, turn counts, and inference geography).": + "El Monitor de Agentes viene con un mercado oficial de plugins de Claude Code que contiene diez plugins listos para producción (53 habilidades, 14 agentes, 30 comandos slash, 3 herramientas CLI, 3 configuraciones de ganchos y 1 servidor MCP). Estos amplían Claude Code con habilidades, agentes, ganchos, herramientas CLI e integración MCP, todo ello basado en el modelo de datos real (seguimiento de tokens con bases de compresión, cálculo de costos a través de reglas de precios que coinciden con patrones, inteligencia de flujo de trabajo con 11 conjuntos de datos por sesión y metadatos de sesión que incluyen bloques de pensamiento, conteos de turnos y geografía de inferencia).", + Plugin: "Plugin", + Skills: "Habilidades", + Agent: "representante", + "CLI Tools": "Herramientas CLI", + Focus: "manifiesto", + "Token usage (4 types + baselines), cost via pricing engine, daily trends, productivity scoring": + "Uso de tokens (4 tipos + bases de datos), costo a través del motor de precios, tendencias diarias, puntuación de productividad", + "Standup reports, sprint tracking, workflow optimization via 11 workflow intelligence datasets": + "Informes de pie, seguimiento de sprints, optimización del flujo de trabajo a través de 11 conjuntos de datos de inteligencia de flujo de trabajo", + "Session debugging, hook diagnostics, data export (JSON/CSV), system health": + "Depuración de sesiones, diagnóstico de ganchos, exportación de datos (JSON/CSV), estado del sistema", + "Pattern detection via tool flow transitions, anomaly alerting, optimization, session comparison": + "Detección de patrones a través de transiciones de flujo de herramientas, alerta de anomalías, optimización, comparación de sesiones", + "Budget guardrails: set budgets, forecast week/month-end spend, cost-threshold alerts, model-routing savings (fail-safe Stop hook)": + "Barandas de presupuesto: establezca presupuestos, pronostique los gastos a finales de semana/mes, alertas de umbral de costo, ahorros de enrutamiento de modelos (gancho de parada de seguridad)", + "Session forensics: search, timeline, transcript replay, per-cwd rollup, cleanup": + "Perfil forense de sesiones: búsqueda, cronología, reproducción de transcripciones, agregación por directorio de trabajo, limpieza", + "Multi-agent orchestration & fleet intelligence: DAG map, delegation audit, concurrency, error propagation, fleet runs (11-dataset workflow intelligence API)": + "Orquestación multiagente e inteligencia de flota: mapa DAG, auditoría de delegación, concurrencia, propagación de errores, ejecuciones de flota (API de inteligencia de flujo de trabajo de 11 conjuntos de datos)", + "Reliability & SLOs: error scan, API-error report, hook-failure audit, SLO check, regression alert": + "Reliability & SLOs: escaneo de errores, informe de errores API, auditoría de fallos de conexión, verificación de SLOs, alerta de regresión", + "Claude Code config & memory governance: config audit, memory review, skill/MCP/hook inventory (via the Config Explorer API)": + "Configuración y gobernanza de la memoria de Claude Code: auditoría de configuración, revisión de memoria, inventario de habilidades/MCP/ganchos (a través de la API Config Explorer)", + "Dashboard connector with MCP integration and one-line metric summaries": + "Conector de panel de control con integración MCP y resúmenes métricos de una línea", + "Each plugin follows the official Claude Code plugin specification. The marketplace manifest at .claude-plugin/marketplace.json catalogs all ten plugins. Each plugin directory contains:": + "Cada complemento sigue la especificación oficial del complemento Claude Code. El manifiesto del mercado en .claude-plugin/marketplace.json catala los diez complementos. Cada directorio de complementos contiene:", + "All plugins query the Agent Monitor API at http://localhost:4820. Key capabilities they leverage:": + "Todos los complementos consultan la API del Monitor de Agentes en http://localhost:4820. capacidades clave que utilizan:", + Capability: "aptitud", + Details: "información interna", + "Token tracking": "Seguimiento de tokens", + "4 types (input, output, cache_read, cache_write) + 4 compaction baselines per model per session": + "4 tipos (entrada, salida, cache_read, cache_write) + 4 líneas de base de compactación por modelo por sesión", + "Cost calculation": "Cálculo de costos", + "(tokens / 1M) × rate_per_mtok for each type; longest pattern match wins": + "(tokens / 1M) × rate_per_mtok Para cada tipo; la coincidencia de patrones más larga gana", + "Session metadata": "Métadatos de la sesión", + "Event types": "Tipos de eventos", + "Workflow intelligence": "Inteligencia de flujo de trabajo", + "11 datasets: stats, orchestration (DAG), toolFlow, effectiveness, patterns, modelDelegation, errorPropagation, concurrency, complexity, compaction, cooccurrence": + "11 conjuntos de datos: estadísticas, orquestación (DAG), toolFlow, eficacia, patrones, modelDelegation, errorPropagation, concurrencia, complejidad, compactación, coocurrencia", + "Agent hierarchy": "Jerarquía de agentes", + "Recursive parent/child tree with subagent_type, depth tracking via recursive CTE": + "Árbol recursivo padre/hijo con subagente_type, seguimiento de profundidad a través de CTE recursivo", + '📖 Full documentation: docs/plugins.md': + '📖 Documentación completa: docs/plugins.md', + '🖥️ Statusline — always-visible bar showing context window usage, token counts, active model, git branch, and session ID. Configurable segments with theme support': + '🖥️ Línea de estado: barra siempre visible que muestra el uso de la ventana de contexto, el número de tokens, el modelo activo, la rama de git y el ID de la sesión. Segmentos configurables con soporte de tema', + "The statusline/ directory contains a standalone CLI statusline for Claude Code — completely independent of the web dashboard. It renders a color-coded bar at the bottom of the Claude Code terminal showing context window usage, per-direction token counts, session cost in USD, and git branch.": + "el statusline/ El directorio contiene una línea de estado CLI independiente para Claude Code, completamente independiente del panel de control web. Renderiza una barra codificada por colores en la parte inferior del terminal de Claude Code que muestra el uso de la ventana de contexto, el número de tokens por dirección, el costo de la sesión en USD y la rama de git.", + Segment: "segmento", + Source: "fuente", + "Color Logic": "Lógica de color", + "Always cyan": "Siempre cian", + "Always green": "Siempre verde", + "Always yellow, ~ prefix for home": + "Siempre amarillo, ~ prefijo para casa", + "Always magenta, hidden outside git repos": + "Siempre magenta, oculto fuera de los repositorios de git", + "Green < 50%, Yellow 50–79%, Red ≥ 80%": "Verde < 50 %, Amarillo 50-79 %, Rojo ≥ 80 %", + "Green input, cyan output, dim c cache reads": + "verde Entrada, cian Salida, atenuación c Lecturas de caché", + "Green < $5, Yellow $5–$20, Red ≥ $20 (shown on API and subscription plans)": + "Verde < 5 $, Amarillo 5-20 $, Rojo ≥ 20 $ (mostrado en la API y planes de suscripción)", + "Add this to ~/.claude/settings.json:": + "Agregar esto a ~/.claude/settings.json:", + "No dependencies required": "No se requieren dependencias", + "The statusline uses only Python 3.6+ stdlib (sys, json, os, subprocess). It fails silently on empty input or JSON errors and never blocks Claude Code.": + "La línea de estado solo utiliza la biblioteca estándar de Python 3.6+ (sys, json, os, subprocess). Falla silenciosamente en entradas vacías o errores JSON y nunca bloquea el código Claude.", + '🔌 Sidebar — live health, analytics, and deep navigation links': + '🔌 Barra lateral: salud en vivo, análisis y enlaces de navegación profunda', + "The Claude Code Agent Monitor is a premium, high-fidelity extension designed to minimize context switching for AI engineers. It brings the full power of the dashboard directly into VS Code, allowing you to monitor complex subagent orchestration without ever leaving your active code file.": + "el Monitor de agente de código Claude Es una extensión premium de alta fidelidad diseñada para minimizar el cambio de contexto para los ingenieros de IA. Trae toda la potencia del panel de control directamente a VS Code, lo que le permite monitorear la orquestación compleja de subagentes sin nunca salir de su archivo de código activo.", + "A dedicated Activity Bar view that performs background polling every 5 seconds. Includes a real-time Agent Health monitor tracking all 5 states (Working, Connected, Idle, Completed, Error) with native VS Code theme-aware icons and colors.": + "Una vista dedicada de la barra de actividades que realiza encuestas en segundo plano cada 5 segundos. Incluye una en tiempo real Salud del agente Monitoriza el seguimiento de los 5 estados (Trabajando, Conectado, Inactivo, Completado, Error) con iconos y colores nativos de VS Code que son conscientes del tema.", + "Aggregates data from multiple API endpoints to display high-signal metrics directly in the sidebar:
  • Token Consumption: Scaled tracking from 1k to 1.0B+ tokens.
  • Live Cost Estimates: Automatic USD cost calculation based on model pricing rules.
  • Event Frequency: Total events, daily sessions, and subagent spawning rates.
": + "Agrupa datos de múltiples puntos finales de API para mostrar métricas de alto señal directamente en la barra lateral:
  • Consumo de tokens: Seguimiento escalonado desde 1k hasta más de 1.0B tokens.
  • Estimaciones de costos en vivo: Cálculo automático del costo en USD basado en las reglas de precios del modelo.
  • Frecuencia de eventos: Total de eventos, sesiones diarias y tasas de apareamiento de subagentes.
", + "Token Consumption: Scaled tracking from 1k to 1.0B+ tokens.": + "Consumo de tokens: Seguimiento escalonado desde 1k hasta más de 1.0B tokens.", + "Live Cost Estimates: Automatic USD cost calculation based on model pricing rules.": + "Estimaciones de costos en vivo: Cálculo automático del costo en USD basado en las reglas de precios del modelo.", + "Event Frequency: Total events, daily sessions, and subagent spawning rates.": + "Frecuencia de eventos: Total de eventos, sesiones diarias y tasas de apareamiento de subagentes.", + "Renders the full React application within a native webview tab. Supports Deep Linking: one-click jump from the sidebar directly to specific views like the Kanban Board, Analytics Hub, or your Last 10 Sessions.": + "Rendiza la aplicación React completa dentro de una pestaña de webview nativa. Soporta Enlace profundo: salto de un solo clic desde la barra lateral directamente a vistas específicas como la Tablero Kanban, Centro de análisis, o tu Últimas 10 sesiones.", + "Seamlessly scans ports 5173 (Vite Dev) and 4820 (Production) on localhost. Automatically toggles between Online and Offline modes in the sidebar as you start or stop your local server.": + "Escanea puertos sin problemas 5173 (Vite Dev) y 4820 (Producción) en localhost. Cambia automáticamente entre en línea y autónomo Modos en la barra lateral a medida que inicies o detengas tu servidor local.", + "Zero-Config Setup": "Configuración de cero configuración", + "The extension is designed to be plug-and-play. Once your server is running, the extension automatically discovers the API and begins streaming telemetry — no manual URL configuration required.": + "La extensión está diseñada para ser fácil de usar. Una vez que su servidor esté en funcionamiento, la extensión descubre automáticamente la API y comienza a transmitir telemetría, sin necesidad de configuración manual de la URL.", + '📖 Full developer guide: vscode-extension/README.md': + '📖 Guía completa para desarrolladores: vscode-extension/README.md', + "The dashboard ships as an optional native desktop application — a desktop/ workspace that wraps the existing server and client into a macOS .app (distributed as a .dmg) and a Windows .exe (an NSIS installer plus a no-install portable build) you install once and forget. desktop/ is a sibling workspace to client/, server/, mcp/, and vscode-extension/, built with Electron 35. It embeds the Express server in-process — it require()s server/index.js directly in the same Node runtime as the Electron main process (no child process, no IPC) — and renders the already-built React client in a BrowserWindow. Everything you see in the browser at localhost:4820 lives inside this window, with native OS lifecycle on top.": + "El panel de instrumentos se envía como opcional Aplicación nativa para escritorio — a desktop/ Espacio de trabajo que envuelve el servidor y el cliente existentes en un macOS .app (distribuido como un .dmg) y una ventana de Windows .exe (un instalador NSIS más una construcción portátil sin instalación) lo instales una vez y olvidaslo. desktop/ Es un espacio de trabajo hermano de client/, server/, mcp/, y vscode-extension/, construido con Electrón 35. lo Incorpora el servidor Express en el proceso — eso require()s server/index.js directamente en el mismo tiempo de ejecución del Nodo que el proceso principal de Electron (sin proceso hijo, sin IPC) y renderiza el cliente React ya construido en un BrowserWindow. Todo lo que ves en el navegador en localhost:4820 Vive dentro de esta ventana, con el ciclo de vida del sistema operativo nativo encima.", + '🍎🪟 The full dashboard, natively on macOS and Windows — same React client, same Express server, real BrowserWindow. Menu-bar / notification-area (tray) icon included. Shipped as a macOS DMG and a Windows EXE (macOS shown) — see DESKTOP.md.': + '🍎🪟 El panel completo, nativo en macOS y Windows: mismo cliente React, mismo servidor Express, real BrowserWindow. - Barra de menú / icono de área de notificaciones ( bandeja) incluido. Envío como DMG de macOS y EXE de Windows (se muestra macOS) - ver DESKTOP.md.', + '🪟 The same dashboard as a native Windows app — real BrowserWindow with the native Windows window menu, live Activity Feed, and the Tabby companion. A notification-area (system tray) icon sits beside the clock for quick access.': + '🪟 El mismo panel de control que un nativo ventana Aplicación — real BrowserWindow Con el menú de ventanas nativo de Windows, el Feed de Actividades en vivo y el compañero Tabby. Un icono de área de notificaciones (mesa de inicio del sistema) se encuentra junto al reloj para un acceso rápido.', + "One-line mental model": "Modelo mental de una línea", + "Electron is a window onto the same code. The desktop app does not reimplement the dashboard — it hosts the exact server and client the standalone deployment runs. The only change outside desktop/ is a behavior-preserving refactor of server/index.js: its post-listen bootstrap was extracted into an exported startBackgroundServices() so the embedded server runs exactly what node server/index.js runs.": + "Electron es una ventana a el mismo código. La aplicación de escritorio no reimplementa el panel de control; alberga el servidor y el cliente exactos que ejecuta la implementación independiente. El único cambio fuera desktop/ Es una refactorización que preserva el comportamiento de server/index.js: su bootstrap post-escucha se extrajo en un exportado startBackgroundServices() Así que el servidor incorporado ejecuta exactamente lo que node server/index.js Corre.", + "The Electron main process hosts the embedded server and manages the window, tray, and menus. The renderer is just Chromium loading http://127.0.0.1:<port> — the same origin a normal browser would use.": + "El proceso principal de Electron alberga el servidor integrado y Gestiona la ventana, la bandeja y los menús. El renderizador solo está cargando Chromium http://127.0.0.1:<port> — la misma origen que un navegador normal usaría.", + "The desktop app embeds the Express server in-process — no child process, no IPC": + "La aplicación de escritorio incorpora el servidor Express en el proceso, sin proceso hijo, sin IPC", + "An always-on tray icon — the macOS menu bar (a tinted template glyph) or the Windows notification area (the colored icon.ico). A single click (left or right) opens a dropdown with a live status snapshot queried straight from SQLite at click time — server port, active sessions, working agents, events today — followed by Open Dashboard, Open in Browser, Restart Server, Show Logs, Open at Login (toggle), and Quit. The snapshot rows are clickable — they open the dashboard. The menu is rebuilt on each open so every value is current.": + "Un icono de bandeja siempre encendido: la barra de menú de macOS (un símbolo de plantilla con color) o el área de notificaciones de Windows (el colorido icon.ico). Un solo clic (izquierda o derecha) abre un menú desplegable con un Captura instantánea del estado en vivo Consultado directamente desde SQLite en el momento del clic: puerto del servidor, sesiones activas, agentes en funcionamiento, eventos de hoy, seguido de Abrir Panel de control, Abrir en el navegador, Reiniciar el servidor, Mostrar registros, Abrir en el inicio de sesión (alternar), y dejar. Las filas de instantáneas son clicables, abren el panel de control. El menú se reconstruye en cada apertura para que cada valor sea actual.", + "A standard native application menu — About, Open at Login, File, Edit, View, Window, Help — with ⌘R / Ctrl+R wired to View ▸ reload. External links open in the system browser, never inside Electron. The File ▸ Open Dashboard item (⌘1) is macOS-only; on Windows/Linux the window-attached menu can't reopen a hidden window, so reopen from the tray's Open Dashboard.": + "Un menú de aplicaciones nativas estándar - About, Open at Login, File, Edit, View, Window, Help — con ⌘R / Ctrl+R Conectado a Ver ▸ volver a cargar. enlaces externos se abren en el navegador del sistema, nunca dentro de Electron. el File ▸ Open Dashboard Artículo (⌘1) solo es para macOS; en Windows/Linux el menú adjunto a la ventana no puede volver a abrir una ventana oculta, así que vuelva a abrir desde la bandeja Abrir Panel de control.", + "Flip Open at Login in the tray or app menu — both platforms go through Electron's first-party app.*LoginItemSettings API. On macOS it registers via the modern SMAppService API and appears under System Settings → General → Login Items; on Windows it writes a per-user HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run entry, visible in Task Manager → Startup. When the app is launched at login it starts tray-only, with no window jumping into view (on Windows the login launch is detected via a --ccam-hidden argument).": + "ponche de huevo Abrir en el inicio de sesión en la bandeja o en el menú de la aplicación, ambas plataformas pasan por el primero de Electron app.*LoginItemSettings API. En macOS se registra a través del moderno SMAppService API y aparece debajo de Configuración del sistema → General → Elementos de inicio de sesión; en Windows escribe un por usuario HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run Entrada, visible en Gestor de tareas → Inicio de sesión. cuando la aplicación se lanza al iniciar sesión, solo se inicia en la bandeja, sin que ninguna ventana salte a la vista (en Windows, el inicio de sesión se detecta a través de un --ccam-hidden argumento).", + 'Closing the window hides it — the embedded server keeps running, the tray icon stays, and the dock / taskbar icon stays too (a clickable "still alive" indicator). Quit (⌘Q / Ctrl+Q, app menu, or tray → Quit) pops a confirmation modal — press the Quit button or hit ⌘Q / Ctrl+Q a second time to skip the prompt — and only then does the embedded server shut down, closing SQLite cleanly with a WAL checkpoint and removing this PID\'s entry from the discovery file.': + 'Cerrar la ventana lo oculta: el servidor incorporado sigue funcionando, el icono de la bandeja permanece y el icono del dock / barra de tareas también permanece (un indicador "sigue vivo" que se puede hacer clic). dejar (⌘Q / Ctrl+Q, menú de la aplicación o bandeja → Salir) aparece una modalidad de confirmación, presiona el botón Salir o pulsa ⌘Q / Ctrl+Q una segunda vez para saltar el mensaje de inicio de sesión, y solo entonces el servidor incorporado se apaga, cerrando SQLite de forma limpia con un control de punto de vista WAL y eliminando la entrada de este PID del archivo de descubrimiento.', + "Launch the desktop app and npm run dev at the same time and both stay real-time. Each server appends its {port, pid, startedAt} entry to ~/.claude/.agent-dashboard.json on startup; the Claude Code hook handler reads that list and fan-outs every event to every live entry in parallel. Stale entries self-evict via a PID liveness check on read, so a crashed server can't misroute events to a dead port.": + "Lanzar la aplicación para escritorio y npm run dev Al mismo tiempo y ambos permanecen en tiempo real. Cada aplicación del servidor añade su {port, pid, startedAt} Entrada a ~/.claude/.agent-dashboard.json Al arrancar; el gestor de enlaces del código Claude lee esa lista y distribuye cada evento a cada entrada en vivo de forma paralela. Las entradas obsoletas se desalojan automáticamente mediante una comprobación de vitalidad PID al leer, por lo que un servidor que se bloquee no puede redirigir los eventos a una puerto muerto.", + "Double-launching the app just focuses the existing window — no second server, no port collision, on every platform. The lock is acquired via requestSingleInstanceLock() before any server boots.": + "El doble lanzamiento de la aplicación solo centra la ventana existente, sin un segundo servidor, sin colisión de puertos, en todas las plataformas. El bloqueo se adquiere a través de requestSingleInstanceLock() Antes de que cualquier servidor arranque.", + "On its first owned-server boot the app auto-installs the Claude Code hooks into ~/.claude/settings.json and starts the background services (update scheduler, config watcher, orphaned-run reconciliation) — so an install-only user (DMG or EXE) gets events flowing without ever running npm run install-hooks from a checkout.": + "En su primer arranque en un servidor propio, la aplicación instala automáticamente los ganchos del código Claude en ~/.claude/settings.json y inicia los servicios de fondo (actualizador de programadores, observador de configuración, reconciliación de ejecución huérfana), por lo que un usuario que solo instala (DMG o EXE) recibe eventos sin nunca ejecutarse. npm run install-hooks Desde una caja registradora.", + "Two packaging realities — a read-only application bundle / install directory and (on macOS) the minimal PATH a Finder-launched app inherits — are handled automatically so installs survive updates and the Run Claude feature works out of the box on both macOS and Windows.": + "Dos realidades de empaquetado: un paquete de aplicaciones de lectura única / directorio de instalación y (en macOS) el mínimo PATH Una aplicación lanzada por Finder hereda - se manejan automáticamente para que las instalaciones sobrevivan a las actualizaciones y el Corra Claude La función funciona de inmediato en macOS y Windows.", + "Your data survives reinstalls and updates": + "Sus datos sobreviven a las reinstalaciones y actualizaciones", + "The SQLite database and VAPID keys live in a per-user app-data directory outside the application bundle / install dir — ~/Library/Application Support/Claude Code Monitor/data/ on macOS, %APPDATA%\\Claude Code Monitor\\data\\ on Windows. server-host.ts points DASHBOARD_DATA_DIR at that per-user directory on boot. Because a packaged, code-signed, or app-translocated bundle is read-only, older builds that stored the database inside the bundle broke History Import; with the data directory now in app-data, your imported history and events persist across app reinstalls and updates (the Windows NSIS uninstaller keeps this data by default). After upgrading from a pre-fix build, re-run Import History → Rescan once to bridge the one-time gap.": + "La base de datos SQLite y las claves VAPID viven en un directorio de datos de aplicaciones por usuario afuera El paquete de aplicaciones / directorio de instalación — ~/Library/Application Support/Claude Code Monitor/data/ En macOS, %APPDATA%\\Claude Code Monitor\\data\\ En Windows. server-host.ts Puntos DASHBOARD_DATA_DIR en ese directorio por usuario al arrancar. Debido a que un paquete empaquetado, firmado con código o trasladado de aplicación es de solo lectura, las versiones anteriores que almacenaban la base de datos dentro del paquete rompieron la Importación de Historial; con el directorio de datos ahora en datos de la aplicación, su historial e eventos importados persisten a través de las reinstalaciones y actualizaciones de la aplicación (el desinstalador de Windows NSIS guarda estos datos por defecto). Después de actualizar desde una versión con prefijo, vuelva a ejecutar Historial de importación → Recanso de escaneo Una vez para cerrar la brecha única.", + "The claude CLI is found automatically": + "el claude El CLI se encuentra automáticamente", + "A Finder- or Dock-launched macOS app inherits only launchd's minimal PATH, not your login shell's. At startup shell-path.ts recovers the user's login-shell PATH so the Run Claude feature can locate and spawn the claude CLI. (On Windows the process already inherits the user PATH, so no recovery step is needed.) If it still cannot be found, make sure claude is a real executable on your PATH — a shell alias or function cannot be spawned — and check the user PATH resolved line in the desktop log (~/Library/Logs/Claude Code Monitor/desktop.log on macOS, %APPDATA%\\Claude Code Monitor\\logs\\desktop.log on Windows).": + "Una aplicación macOS lanzada desde Finder o Dock hereda solo el mínimo de launchd PATH, no del shell de inicio de sesión. Al arrancar shell-path.ts Recupera la cáscara de inicio de sesión del usuario PATH Así que el Corra Claude La función puede localizar y generar el claude CLI. (En Windows, el proceso ya hereda al usuario PATH, por lo que no se necesita ningún paso de recuperación.) Si aún no se puede encontrar, asegúrese de claude Es un ejecutable real en tu PATH — no se puede crear un alias o función de shell — y compruebe el user PATH resolved Línea en el registro del escritorio (~/Library/Logs/Claude Code Monitor/desktop.log En macOS, %APPDATA%\\Claude Code Monitor\\logs\\desktop.log En Windows).", + "On launch the Electron main process picks a free port. If a healthy dashboard server already answers /api/health on port 4820 (for example, you ran npm start in a terminal), the app adopts that server instead of starting a second one — no double-binding, no SQLite contention. An adopted server is not owned by the app, so quitting leaves it running.": + "Al iniciar, el proceso principal de Electron selecciona un puerto libre. Si un servidor de panel de control saludable ya responde /api/health En puerto 4820 (por ejemplo, corriste npm start En un terminal), la aplicación Adopta Ese servidor en lugar de iniciar uno segundo, sin doble vinculación, sin competencia SQLite. Un servidor adoptado no es propiedad de la aplicación, por lo que salir lo deja ejecutándose.", + Step: "paso", + "Port choice": "Elección del puerto", + Adopt: "adoptar", + "A healthy server already on 4820 is adopted as-is": + "Un servidor saludable ya encendido 4820 Se adopta tal cual", + Preferred: "preferido", + "4820 when free": "4820 Cuando esté libre", + Fallback: "Alternativa de respaldo", + "The first free port in 48214829": + "El primer puerto libre en 48214829", + "Last resort": "última instancia", + "A random high port when all of the above are taken": + "Una alta de puerto aleatoria cuando se toman todos los anteriores", + "Three ways to obtain the desktop app — the latest GitHub Release (best for most users), a per-commit CI artifact (fresher than the latest release), or a local build.": + "Tres formas de obtener la aplicación para escritorio: la última versión de GitHub (la mejor para la mayoría de los usuarios), un artefacto CI por commit (más reciente que la última versión) o una compilación local.", + 'Open Releases → latest and download the asset for your platform. The macOS and Windows Desktop CI jobs auto-publish a new vX.Y.Z release every time the version in package.json is bumped on master, so this link always points at the current build. Releases are public — no GitHub sign-in required.': + 'aire libre Lanzamientos → más recientes y descargue el recurso para su plataforma. Los trabajos de CI de escritorio de macOS y Windows publican automáticamente un nuevo vX.Y.Z Lanzamiento cada vez que la versión en package.json Se golpea en master, por lo que este enlace siempre señala la versión actual. Las publicaciones son públicas, no se requiere iniciar sesión en GitHub.', + Platform: "plataforma", + Asset: "activo", + "macOS (Apple Silicon)": "macOS (Silicona de Apple)", + "ClaudeCodeMonitor-<ver>-arm64.dmg": + "ClaudeCodeMonitor-<ver>-arm64.dmg", + "Drag the .app into /Applications": + "Arrastra el .app En /Applications", + "macOS (Intel)": "macOS (Intel)", + "ClaudeCodeMonitor-<ver>-x64.dmg": + "ClaudeCodeMonitor-<ver>-x64.dmg", + "Windows (installer)": "Windows (instalador)", + "ClaudeCodeMonitor-Setup-<ver>-x64.exe": + "ClaudeCodeMonitor-Setup-<ver>-x64.exe", + "NSIS installer — per-user, no admin elevation": + "Instalador de NSIS: por usuario, sin elevación de administrador", + "Windows (portable)": "Windows (portátil)", + "ClaudeCodeMonitor-<ver>-x64-portable.exe": + "ClaudeCodeMonitor-<ver>-x64-portable.exe", + "Run without installing": "Ejecutar sin instalar", + 'Want a build straight off the tip of master, ahead of the next tagged release? Every green run of the 🍎 macOS Desktop (DMG) job on macos-latest uploads both per-arch DMGs as the ClaudeCodeMonitor-dmg workflow artifact, and the 🪟 Windows Desktop (EXE) job on windows-latest uploads the installer + portable EXEs as the ClaudeCodeMonitor-win artifact. Open the latest passing run , scroll to its Artifacts section, and download ClaudeCodeMonitor-dmg or ClaudeCodeMonitor-win. (GitHub sign-in required; 14-day retention.)': + 'Quieres una construcción directamente desde la punta de master, ¿antes del próximo lanzamiento etiquetado? Cada carrera verde del 🍎 macOS Desktop (DMG) Trabajo en curso macos-latest Sube tanto los DMG por archivo como el ClaudeCodeMonitor-dmg Artefacto del flujo de trabajo y el 🪟 Windows Desktop (EXE) Trabajo en curso windows-latest Sube el instalador + los EXEs portátiles como el ClaudeCodeMonitor-win Artefacto. Abre el Última carrera de paso , desplázate hasta la sección de Artifactos y descarga ClaudeCodeMonitor-dmg Oregón ClaudeCodeMonitor-win. (Se requiere iniciar sesión en GitHub; retención de 14 días).', + "From the project root, after git clone:": + "Desde la raíz del proyecto, después de git clone:", + "Use the arch-specific build on your own machine": + "Utilice la construcción específica del arco en su propia máquina", + "desktop:dmg is slower because it builds the full app tree twice (once per architecture) and ad-hoc-signs each — emitting two separate per-arch DMGs (…-arm64.dmg + …-x64.dmg). There is no @electron/universal merge; the release ships the two per-arch DMGs. For running on a single Mac, use desktop:dmg:arm64 (Apple Silicon) or desktop:dmg:x64 (Intel) — one architecture, finishing in roughly a minute. CI runs desktop:dmg and uploads both DMGs as ClaudeCodeMonitor-dmg, so you rarely need to build them yourself.": + "desktop:dmg Es más lento porque construye el árbol completo de la aplicación dos veces (una vez por arquitectura) y firmas ad hoc para cada una de ellas, emitiendo dos DMG separados por arquitectura (…-arm64.dmg + …-x64.dmg). No hay @electron/universal Mezclar; la versión de lanzamiento envía los dos DMG por archivo. Para ejecutar en un solo Mac, use desktop:dmg:arm64 (Silicona de Apple) o desktop:dmg:x64 (Intel) - una arquitectura, terminando en aproximadamente un minuto. CI se ejecuta desktop:dmg Y sube ambos DMG como ClaudeCodeMonitor-dmg, por lo que rara vez necesitas construirlos tú mismo.", + "Double-click the downloaded .dmg to mount it": + "Haga doble clic en el descargado .dmg Para montarlo", + "Drag Claude Code Monitor.app into your Applications folder": + "resistencia Claude Code Monitor.app En tu Applications carpeta", + "Run xattr -cr on the app to get past Gatekeeper (see below)": + "carrera xattr -cr En la aplicación para pasar por el Guardián de Puerta (ver a continuación)", + "Open the app — the tray icon appears and the dashboard window loads": + "Abre la aplicación, aparece el icono de bandeja y se carga la ventana del panel de control.", + "Gatekeeper warning on first launch": + "Advertencia del guardián de puertas en el primer lanzamiento", + 'The DMG is ad-hoc signed by default — that is all the project can offer without a paid Apple Developer ID. macOS warns the first time you open it ("Apple could not verify…"). Strip the quarantine attribute to get past it:': + 'El DMG se firma de forma ad hoc por defecto, eso es todo lo que el proyecto puede ofrecer sin un ID de desarrollador de Apple pagado. macOS advierte la primera vez que lo abres ("Apple no pudo verificar..."). Quita el atributo de cuarentena para pasarlo:', + "Alternatively, open System Settings → Privacy & Security, find the blocked app, and click Open Anyway. Code signing and Apple notarization are opt-in for the maintainer — when configured, this warning goes away for everyone.": + "Alternativamente, abrir Configuración del sistema → Privacidad y seguridad, encuentra la aplicación bloqueada y haz clic Abrir de todos modos. signing y notificación de Apple son opcionales para el mantenedor — cuando se configure, este aviso desaparece para todos.", + "Run ClaudeCodeMonitor-Setup-<ver>-x64.exe — a per-user NSIS install (no admin), or run the *-portable.exe to skip installing": + "carrera ClaudeCodeMonitor-Setup-<ver>-x64.exe — una instalación de NSIS por usuario (sin administrador), o ejecute el *-portable.exe Para saltar la instalación", + "The EXE is unsigned by default, so SmartScreen may warn — click More info → Run anyway": + "El EXE no está firmado por defecto, por lo que SmartScreen puede advertir: haga clic Más información → Corra de todos modos", + "Open from the Start menu / desktop shortcut — the notification-area (tray) icon appears and the dashboard window loads": + "Abrir desde el menú Inicio / atajo de escritorio: aparece el icono de la zona de notificaciones ( bandeja) y se carga la ventana del panel de control.", + '1️⃣ NSIS installer, step 1 — Choose Installation Options: pick per-user setup and optional shortcuts.': + '1️⃣ Instalador de NSIS, paso 1 — Elija las opciones de instalación: seleccione la configuración por usuario y las pestañas rápidas opcionales.', + '2️⃣ NSIS installer, step 2 — Choose Install Location: defaults to %LOCALAPPDATA%\\Programs\\Claude Code Monitor, or point it anywhere.': + '2️⃣ Instalador de NSIS, paso 2 — Elija la ubicación de instalación: por defecto es %LOCALAPPDATA%\\Programs\\Claude Code Monitor, o apuntarlo a cualquier lugar.', + '3️⃣ NSIS installer, step 3 — Completing Setup: click Finish to launch the app and drop the tray icon in the notification area.': + '3️⃣ Instalador de NSIS, paso 3 — Completando la configuración: hacer clic acabado Para lanzar la aplicación y dejar el icono de bandeja en la zona de notificaciones.', + "SmartScreen warning on first launch": "Advertencia de SmartScreen en el primer lanzamiento", + 'The installer and portable EXE are unsigned by default — that is all the project can offer without a paid code-signing certificate. Windows SmartScreen may show "Windows protected your PC" the first time you run it; click More info → Run anyway. The installer lays the app down per-user under %LOCALAPPDATA%\\Programs\\Claude Code Monitor (and lets you choose the install directory) and sets an AppUserModelId (com.hoangsonww.ccam.desktop) so native toast notifications are attributed correctly and the window groups under one taskbar entry.': + 'El instalador y el EXE portátil son sin firmar Por defecto, eso es todo lo que el proyecto puede ofrecer sin un certificado de firma de código pagado. ventana SmartScreen Puede mostrar "Windows protege tu PC" La primera vez que lo ejecutes; haz clic Más información → Corra de todos modos. instala la aplicación. Por usuario bajo %LOCALAPPDATA%\\Programs\\Claude Code Monitor (y te permite elegir el directorio de instalación) y establece un AppUserModelId (com.hoangsonww.ccam.desktop) para que las notificaciones nativas de Toast se atribuyan correctamente y los grupos de ventanas se encuentren bajo una entrada de barra de tareas.', + "Bundle size": "Tamaño del paquete", + "The DMG is roughly 80 MB, about 250 MB installed on disk — the standard Electron tax; the Windows installer is comparable. The app runs natively on macOS and Windows; Linux is tracked as a follow-up. Logs live at ~/Library/Logs/Claude Code Monitor/desktop.log on macOS or %APPDATA%\\Claude Code Monitor\\logs\\desktop.log on Windows (reach them from the tray menu → Show Logs).": + "El DMG tiene aproximadamente 80 MB, unos 250 MB instalados en el disco, el impuesto estándar de Electron; el instalador de Windows es comparable. La aplicación se ejecuta nativamente en macOS y Windows; Linux se rastrea como seguimiento. Los registros están disponibles en ~/Library/Logs/Claude Code Monitor/desktop.log En macOS o %APPDATA%\\Claude Code Monitor\\logs\\desktop.log En Windows (accedé a ellos desde el menú de la bandeja de inicio → Mostrar registros).", + '📖 User-facing guide: DESKTOP.md · architecture & contributor reference: desktop/README.md': + '📖 Guía para el usuario: DESKTOP.md · arquitectura y referencia del colaborador: desktop/README.md', + '⚙️ Settings — model pricing editor, hook installation toggle, JSON data export, session cleanup, browser notification preferences, and system info panel with DB stats': + '⚙️ Configuración: editor de precios de modelos, interruptor de instalación de ganchos, exportación de datos JSON, limpieza de sesiones, preferencias de notificación del navegador e información del sistema con estadísticas de la base de datos.', + "The /settings route provides a comprehensive management interface with six sections:": + "el /settings Route proporciona una interfaz de gestión integral con seis secciones:", + "Editable table of per-model pricing rules. Each Claude model variant has its own explicit pattern (e.g., claude-opus-4-6%). Rates cover input, output, cache read, and cache write tokens. Each rule's editor also has a collapsible Introductory rates block — a YYYY-MM-DD promo cutoff plus per-category intro prices (input / output / cache-read / cache-write 5m & 1h); an empty date means no promo, and any future model-launch promo needs no code change. Reset to defaults or add custom models. The section header carries an info popover (the i icon) that explains how rule lookup works (first matching pattern wins), the SQL-style % wildcard syntax with concrete examples (claude-opus-4-7%, claude-%-haiku, exact ids), and reminds the user that prices must be updated manually when Anthropic publishes new rates — already-stored sessions keep the price applied at ingest time. The CLAUDE_HOME panel and Import History flow are fully i18n-driven across en/vi/zh.": + "Tabla editable de las reglas de precios por modelo. Cada variante de modelo Claude tiene su propio patrón explícito (por ejemplo, claude-opus-4-6%). Las tarifas cubren tokens de entrada, salida, lectura de caché y escritura de caché. El editor de cada regla también tiene un colapsible Tarifas introductorias Bloqueo — un YYYY-MM-DD Límite de promoción más precios de introducción por categoría (entrada / salida / lectura de caché / escritura de caché 5 m y 1 h); una fecha vacía significa que no hay promoción, y cualquier promoción futura de lanzamiento de modelos no requiere ningún cambio de código. Reinicia a los valores predeterminados o agrega modelos personalizados. El encabezado de la sección contiene un popover de información (el i Icono) que explica cómo funciona la búsqueda de reglas (el patrón que coincida primero gana), el estilo SQL % Sintaxis de asterisco con ejemplos concretos (claude-opus-4-7%, claude-%-haiku, identificadores exactos), y recuerda al usuario que los precios deben actualizarse manualmente cuando Anthropic publique nuevas tarifas. Las sesiones almacenadas previamente mantienen el precio aplicado en el momento de la ingestión. El panel CLAUDE_HOME y el flujo de historial de importación están completamente impulsados por i18n en en/vi/zh.", + "Shows per-hook installation status (SessionStart, PreToolUse, PostToolUse, Stop, SubagentStop, Notification, SessionEnd). One-click reinstall if hooks are missing or outdated. Validates paths and permissions automatically.": + "Muestra el estado de instalación por gancho (SessionStart, PreToolUse, PostToolUse, Stop, SubagentStop, Notification, SessionEnd). Reinstalación con un solo clic si faltan o están desactualizados los ganchos. Valida automáticamente los rutas y permisos.", + "View database row counts and size. Session cleanup: abandon stale active sessions after N hours, purge old completed sessions after N days. Danger zone: clear all data with confirmation dialog to prevent accidental loss.": + "Ver el número de filas y el tamaño de la base de datos. Limpieza de sesiones: abandone las sesiones activas obsoletas después de N horas, purga las sesiones antiguas completadas después de N días. Zona de peligro: elimine todos los datos con el cuadro de diálogo de confirmación para evitar la pérdida accidental.", + "Download all sessions, agents, events, token usage, and pricing rules as a single JSON file for backup or analysis. Includes full event history, model metadata, and cost breakdowns in one portable archive.": + "Descargue todas las sesiones, agentes, eventos, uso de tokens y reglas de precios como un solo archivo JSON para respaldo o análisis. Incluye el historial completo de eventos, metadatos del modelo y desgloses de costos en un archivo portátil.", + "Dedicated Health tab on the Dashboard with a composite health score (weighted from success rate, cache hit rate, error rate, and heap usage), storage engine donut chart, tool invocation frequency bars, subagent effectiveness, model token distribution, and compaction impact — all with cursor-following tooltips and 5-second auto-refresh.": + "Pestaña de Salud dedicada en el Panel de Control con una puntuación de salud compuesta (pesada por la tasa de éxito, la tasa de éxito de la caché, la tasa de errores y el uso de la pila), gráfico de donut del motor de almacenamiento, barras de frecuencia de invocación de herramientas, eficacia del subagente, distribución de tokens del modelo e impacto de la compactación, todo con herramientas de ayuda que siguen el cursor y una actualización automática de 5 segundos.", + "Configure native browser notifications with per-event toggles for session starts, completions, errors, and subagent spawns. Automatic permission management with test-send button and graceful fallback when denied.": + "Configura las notificaciones del navegador nativo con interruptores por evento para el inicio, la finalización, los errores y el aparecimiento de subagentes de la sesión. Gestión automática de permisos con botón de envío de prueba y fallback elegante cuando se niega.", + "Per-model pricing — no catch-all grouping": "Precio por modelo: sin agrupación general", + "Each Claude model variant (e.g., Opus 4.6 vs Opus 4.1) has its own explicit pricing pattern because different model versions have different rates. The cost engine uses specificity sorting — longer patterns match before shorter ones.": + "Cada variante de modelo Claude (por ejemplo, Opus 4.6 vs Opus 4.1) tiene su propio patrón de precios explícito porque las diferentes versiones de modelos tienen diferentes tarifas. El motor de costos utiliza la clasificación por especificidad: los patrones más largos coinciden antes que los más cortos.", + "Turns the dashboard from passive viewing into active monitoring. A rules-based alerting engine evaluates the live event stream server-side, and fired alerts fan out to outbound webhook channels. Everything lives in one place — Settings → Alerts — behind a segmented control with three tabs: Rules (what triggers an alert), Channels (where alerts are delivered), and Activity (the live fired-alert feed with acknowledge / acknowledge-all).": + "Convierte el panel de instrumentos de visualización pasiva en monitoreo activo. Un motor de alertas basado en reglas evalúa el flujo de eventos en vivo Lado del servidor, y las alertas lanzadas se extienden hacia el exterior Canales webhook. todo vive en un solo lugar — Configuración → Alertas — detrás de un control segmentado con tres pestañas: Reglas (lo que desencadena una alerta), canal (donde se entregan las alertas), y actividad (el feed de alerta de disparos en vivo con reconocer / reconocer-todos).", + 'Four condition types: event pattern (match event_type / tool_name / a summary substring, optionally requiring ≥ N matches within a rolling window — e.g. "5 errors in 2 minutes"), inactivity (an active session goes quiet for N minutes), status duration (an agent is stuck in working / waiting for N minutes), and token threshold (a session\'s cumulative tokens cross a limit). Each rule has a configurable cooldown that dedups repeat alerts per (rule, session, agent).': + 'Cuatro tipos de condiciones: Patrón de eventos (partido event_type / tool_name / una subcadena resumida, opcionalmente que requiera ≥ N coincidencias dentro de una ventana móvil, por ejemplo "5 errores en 2 minutos"), inactividad (una sesión activa se queda en silencio durante N minutos), Duración del estado (un agente está atascado en working / waiting Durante N minutos), y Límite de tokens (los tokens acumulados de una sesión cruzan un límite). Cada regla tiene un configurable Descanso Que dedupe las alertas repetidas por (regla, sesión, agente).', + "Event-driven rules (event_pattern, token_threshold) run on every hook ingest — after the transaction commits and the response is sent, fully try/catch-guarded, so alerting can never slow or fail hook delivery. Time-based rules (inactivity, status_duration) run on an unref'd 60-second sweep. Enabled rules are cached in memory and invalidated on every edit. Fired alerts persist to alert_events and broadcast an alert_triggered WebSocket message.": + "Reglas basadas en eventos (event_pattern, token_threshold) se ejecuta en cada ingestión de gancho — después La transacción se compromete y la respuesta se envía, completamente protegida por try/catch, por lo que la alerta nunca puede ralentizar o fallar la entrega del gancho. Las reglas basadas en el tiempo (inactivity, status_duration) se ejecuta en una escaneo de 60 segundos sin refinar. Las reglas activadas se almacenan en caché en la memoria y se invalidan en cada edición. Las alertas emitidas persisten hasta alert_events Y transmitir un alert_triggered Mensaje WebSocket.", + "Slack, Discord, Microsoft Teams, Google Chat, Mattermost, Rocket.Chat, Telegram, PagerDuty, Opsgenie, Splunk On-Call, Zapier, Make, n8n, and Pipedream — plus a generic JSON endpoint. A declarative provider registry describes each one's payload formatter, URL resolution, auth headers, and credential fields, so adding a provider is a single server-side entry that surfaces in the UI with no front-end change.": + "Slack, Discord, Microsoft Teams, Google Chat, Mattermost, Rocket.Chat, Telegram, PagerDuty, Opsgenie, Splunk On-Call, Zapier, Make, n8n y Pipedream, además de un punto final JSON genérico. Un declarativo Registro de proveedores describe el formateador de carga útil de cada uno, la resolución de la URL, los encabezados de autenticación y los campos de credenciales, por lo que agregar un proveedor es una sola entrada del lado del servidor que aparece en la interfaz de usuario sin cambios en el frontend.", + 'Each delivery POSTs with an AbortController timeout and bounded retry/backoff (retries transport errors, 429, and 5xx — never other 4xx), then records the attempt-chain in webhook_deliveries. A provider can also veto a 2xx whose body signals failure (Splunk On-Call returns 200 with result:"failure"). Delivery is detached and fail-safe — it never throws into, slows, or blocks the alert path.': + 'Cada entrega se publica con un AbortController Tiempo de espera y intento/retraso limitado (intentos de transporte de errores, 429 y 5xx, nunca otros 4xx), luego registra la cadena de intentos en webhook_deliveries. también puede vetar un 2xx cuyo cuerpo envía señales de fallo (Splunk On-Call devuelve 200 con result:"failure"). La entrega es Desprendido y con fallo seguro — Nunca arroja, ralentiza ni bloquea el camino de alerta.', + "Target URLs are masked (host + last 4 chars), and secrets / credential fields (routing keys, API keys, bot tokens) plus custom-header values are redacted in every API response — the full URL and secrets are stored server-side and never leave it. Generic endpoints support optional HMAC-SHA256 body signing (X-Webhook-Signature + X-Webhook-Timestamp) so receivers can verify authenticity.": + "Las URL de destino están encriptadas (host + últimos 4 caracteres) y los campos de secretos / credenciales (claves de enrutamiento, claves API, tokens de bot) más los valores de encabezado personalizados están redactados en cada respuesta de la API: la URL completa y los secretos se almacenan en el lado del servidor y nunca salen de él. Los puntos finales genéricos admiten opcionales HMAC-SHA256 Firma corporal (X-Webhook-Signature + X-Webhook-Timestamp) para que los destinatarios puedan verificar la autenticidad.", + 'Every alert-rule field has a help tooltip — the event-type, tool-name, and summary-contains fields include example chips of real hook events and built-in tool names. Each webhook provider ships a collapsible step-by-step setup guide linking to the official docs. A one-click "Send test" probe fires a synthetic alert and reports the delivery result inline, and targets can be scoped to specific rules. Fully localized (en / zh / vi / ko).': + 'Cada campo de regla de alerta tiene una pestaña de ayuda - los campos tipo de evento, nombre de la herramienta y contiene resumen incluyen ejemplos de chips de eventos de gancho reales y nombres de herramientas integrados. Cada proveedor de webhook envía una guía de configuración paso a paso colapsable que enlaza con los documentos oficiales. Un clic "Enviar prueba" probe emite una alerta sintética y informa el resultado de la entrega en línea, y los objetivos pueden estar restringidos a reglas específicas. Totalmente localizado (es / zh / vi / ko).', + "Provider(s)": "Proveedor(es)", + "Payload format": "Formato de carga útil", + "URL / credentials": "URL / credenciales", + "Block Kit (header + section + context)": "Kit de bloques (encabezado + sección + contexto)", + "Rich embed": "Incorporación rica", + "Adaptive Card in a Workflows message envelope": + "Tarjeta adaptativa en flujos de trabajo message sobre", + "Power Automate Workflows URL": "URL de los flujos de trabajo de Power Automate", + "Text message (basic markdown)": "Mensaje de texto (marcado básico)", + "Space webhook URL": "URL de webhook espacial", + "Slack-style legacy attachments": "Anexos heredados de estilo Slack", + "Bot API sendMessage (HTML)": "API de bots sendMessage (HTML)", + "Bot token + chat ID (URL derived)": "Token de bot + ID de chat (derivado de la URL)", + "Events API v2 trigger (with dedup_key)": + "Despliegue de la API de eventos v2 (con dedup_key)", + "Routing key (URL prefilled)": "Clave de enrutamiento (URL prellenada)", + "Alert API": "API de alerta", + "API key (GenieKey header) + region": "Clave API (cabecera GenieKey) + región", + "VictorOps REST": "REST de VictorOps", + "REST endpoint URL (key embedded)": "URL del punto final REST (clave incorporada)", + "Stable { event, alert } JSON envelope": + "estable { event, alert } Envelope JSON", + "Endpoint URL (+ optional HMAC & headers)": + "URL del punto final (+ HMAC opcional y encabezados)", + "Additive & non-blocking by design": "Aditivo y no bloqueante por diseño", + "Two new tables — webhook_targets (config; survives Clear Data like alert rules) and webhook_deliveries (audit log) — with no changes to existing tables, response shapes, or WebSocket message types. Webhook dispatch is fire-and-forget off the alert path, so a slow or failing endpoint can never slow or break alert firing or hook ingestion.": + "Dos nuevas mesas — webhook_targets (configuración; sobrevive a la eliminación de datos como reglas de alerta) y webhook_deliveries (registro de auditoría) - sin cambios en las tablas existentes, las formas de respuesta ni los tipos de mensajes WebSocket. El envío de Webhook es automático y se realiza fuera del camino de alerta, por lo que un extremo de destino lento o fallido nunca puede ralentizar o interrumpir el disparo de alertas ni la ingestión de enlaces.", + "Provider setup steps can drift": "Los pasos de configuración del proveedor pueden variar", + "Microsoft retired classic Office 365 connectors in 2025, so Teams uses an Adaptive Card delivered via Power Automate Workflows. More broadly, provider setup UIs change often — the in-app guides say so and link to each provider's official docs. Always confirm against the source.": + "Microsoft retiró los conectores clásicos de Office 365 en 2025, por lo que Teams utiliza una Tarjeta Adaptativa entregada a través de Power Automate Flujos de trabajo. más ampliamente, las interfaces de usuario de configuración del proveedor cambian con frecuencia, lo dicen las guías de la aplicación y enlazan con los documentos oficiales de cada proveedor. Siempre confirme con la fuente.", + ' Update Notifier — version comparison modal with one-click copy of the update command. No automatic self-restart; you stay in control of when upgrades happen': + ' Notificador de actualización: modal de comparación de versiones con copia del comando de actualización con un solo clic. Sin reinicio automático automático; usted permanece al control de cuándo ocurren las actualizaciones.', + "A detection-only subsystem that tells the user when the dashboard's git checkout is behind the canonical default branch. Branch- and fork-aware: if an upstream remote is configured (the standard convention for forks), it takes priority over origin; the chosen remote's master / main / HEAD is the comparison ref. The printed command adapts to the user's situation — git pull --ff-only only when their branch actually tracks the canonical ref, otherwise git fetch (with a fast-forward merge in the fork case). The server never pulls or restarts itself — the user runs the command in a terminal — so the mechanism cannot break dev sessions, pm2/systemd/launchd/Docker supervision, or leave orphaned processes.": + "Un subsistema de detección exclusiva que informa al usuario cuando la extracción de git del panel de control está detrás de la rama predeterminada canónica. Conocedor de ramas y ramificaciones: Si un upstream El mando a distancia está configurado (la convención estándar para puentes), tiene prioridad sobre origin; el mando a distancia elegido master / main / HEAD Es la referencia de la comparación. El comando impreso se adapta a la situación del usuario — git pull --ff-only Solo cuando su rama realmente rastrea la referencia canónica, de lo contrario git fetch (con una fusión de avance rápido en el caso de bifurcación). El servidor nunca Se tira o se reinicia por sí mismo: el usuario ejecuta el comando en un terminal, por lo que el mecanismo no puede romper las sesiones de desarrollo, la supervisión de pm2/systemd/launchd/Docker o dejar procesos huérfanos.", + "The same status is available from any terminal: ccam update-check asks the server for the branch- and fork-aware comparison, prints the behind-by count and the copy-paste update command, and triggers the update_status WebSocket broadcast so any open dashboard tab refreshes at the same time.": + "El mismo estado está disponible desde cualquier terminal: ccam update-check Pide al servidor la comparación consciente de ramas y bifurcaciones, imprime el conteo de retraso y el comando de actualización de copia y pegar, y activa el update_status Transmisión WebSocket, por lo que cualquier pestaña del panel de control abierta se actualiza al mismo tiempo.", + "A shell-less git fetch with a 120-second timeout, followed by a rev-list against the tracked upstream. Each call runs from server/lib/update-check.js and returns a structured payload — never throws — so a flaky remote can't stall the dashboard.": + "Sin cáscara git fetch Con un tiempo de espera de 120 segundos, seguido de un rev-list Contra el rastreado en el curso superior. Cada llamada se ejecuta desde server/lib/update-check.js y devuelve una carga útil estructurada, nunca lanza, por lo que un control remoto inestable no puede estancar el panel de instrumentos.", + "update-scheduler.js polls every five minutes with .unref() timers so it never blocks shutdown, de-duplicates with a fingerprint over the status payload, and announces up-to-date → behind transitions in a framed stdout block. Disable entirely with DASHBOARD_UPDATE_CHECK=0.": + "update-scheduler.js Encuestas cada cinco minutos con .unref() Timer para que nunca bloquee el apagado, desduplique con una huella digital sobre el contenido de la carga útil del estado y anuncie las transiciones → atrasadas actualizadas en un bloque de stdout enmarcado. Deshabilitar completamente con DASHBOARD_UPDATE_CHECK=0.", + "Each status payload carries a manual_command shaped for the user's actual situation: git pull --ff-only on a tracked canonical branch, git fetch && git merge --ff-only for forks where local tracks the wrong remote, and a plain git fetch on a feature branch where pulling would update the wrong branch. Install / build steps are appended only when the working tree is actually being rewritten.": + "Cada carga útil de estado lleva un manual_command Diseñado para la situación actual del usuario: git pull --ff-only En una rama canónica rastreada, git fetch && git merge --ff-only Para tenedores donde la pista local sigue el mando a distancia equivocado, y un plano git fetch En una rama de características donde la extracción actualizaría la rama equivocada. Los pasos de instalación / construcción se adjuntan solo cuando el árbol de trabajo está siendo reescrito de hecho.", + "A modal opens automatically when upstream is ahead; ESC or a backdrop click dismisses it. A persistent sidebar button stays in the footer — emerald when behind, amber when the last check errored — so users can always trigger a fresh check on demand.": + "Un modal se abre automáticamente cuando upstream está por delante; ESC o un clic en el fondo desactiva el modal. Un botón persistente en la barra lateral permanece en el pie de página: es esmeralda cuando está detrás, ámbar cuando el último control ha fallado, para que los usuarios siempre puedan activar un nuevo control a demanda.", + "Non-git installs, no remotes configured, offline fetches, and unresolvable upstream refs all return tagged payloads instead of throwing. The sidebar badge turns amber on fetch errors and the modal stays suppressed until a successful check arrives — no spinners, no stuck state.": + "Las instalaciones no git, las no configuradas remotas, las consultas fuera de línea y las referencias de origen no resolubles devuelven todos los paquetes de carga etiquetados en lugar de lanzar. El distintivo de la barra lateral se vuelve ámbar en los errores de consulta y el modal se mantiene suprimido hasta que llegue una comprobación exitosa, sin carretes giratorios ni estado atascado.", + "Dismissal is keyed by the upstream SHA in localStorage, so closing the modal silences it only for that commit — a newer upstream commit re-opens it automatically. Clicking the sidebar button is an explicit intent signal and clears the stored dismissal before firing a fresh check.": + "El rechazo está controlado por el SHA de entrada en localStorage, por lo que cerrar la modalidad lo silencia solo por eso comit — un commit más reciente de arriba abre automáticamente. Hacer clic en el botón de la barra lateral es una señal de intención explícita y borra el despido almacenado antes de lanzar una verificación nueva.", + "Read-only check — runs git fetch, compares, returns the payload.": + "Comprobación de lectura única - se ejecuta git fetch, compara, devuelve la carga útil.", + "Same check, and broadcasts update_status over WebSocket so every connected client re-syncs at once.": + "Mismo cheque, y transmisiones update_status A través de WebSocket, por lo que todos los clientes conectados se sincronizan de una vez.", + "Detection-only by design": "Detección solo por diseño", + "There is no POST /api/updates/apply and no in-process restart helper. A process cannot reliably replace itself without an external supervisor, and npm run dev, npm start, pm2, systemd, launchd, and Docker each need different restart logic. Detection-only keeps the mechanism portable across every supervisor and OS, and leaves the dashboard's lifecycle owned by whatever started it. The user runs the printed command in their own shell.": + "No hay POST /api/updates/apply Y no hay asistente de reinicio en proceso. Un proceso no puede reemplazarse de forma fiable sin un supervisor externo, y npm run dev, npm start, pm2, systemd, launchd y Docker necesitan cada uno una lógica de reinicio diferente. La detección solo mantiene el mecanismo portátil en todos los supervisores y sistemas operativos, y deja que el ciclo de vida del panel de control sea propiedad de quien lo inició. El usuario ejecuta el comando impreso en su propia shell.", + ' Connection Status — sidebar-launched details modal with WebSocket endpoint, connection uptime, 60-second throughput sparkline, top event-type breakdown, and recent activity list': + ' Estado de la conexión: modal de detalles lanzada desde la barra lateral con punto final WebSocket, tiempo de actividad de la conexión, gráfico de flujo de datos de 60 segundos, desglose del tipo de evento más común y lista de actividad reciente.', + 'The Live / Disconnected pill in the sidebar footer opens a small details panel about the dashboard\'s WebSocket transport. It surfaces the active ws:// endpoint, how long the current socket has been up, total events received, the top event types as a horizontal bar chart, a 60-second throughput sparkline, and the most recent 8 events as an activity list. Cumulative stats (totals, type breakdown, recent list) persist across reloads via localStorage under sidebar-connection-stats; the rolling sparkline and "connected since" timer are intentionally ephemeral since they only make sense relative to "now". A Reset button clears everything on demand.': + 'el en vivo / desconectado La píldora en el pie de página de la barra lateral abre un pequeño panel de detalles sobre el transporte WebSocket del panel de control. Muestra el activo ws:// Punto final, cuánto tiempo ha estado activo el socket actual, los eventos totales recibidos, los tipos de eventos más comunes como un gráfico de barras horizontal, una línea de chispa de rendimiento de 60 segundos y los 8 eventos más recientes como una lista de actividades. Las estadísticas acumulativas (totales, desglose por tipo, lista reciente) persisten a través de las recargas a través de localStorage bajo sidebar-connection-stats; la línea de flechas en movimiento y el temporizador "conectado desde" son intencionalmente efímeros ya que solo tienen sentido en relación con "ahora". A volver a poner El botón borra todo a pedido.', + "Implementation note: per-event state lives in useRef buffers on the sidebar so the WS firehose never re-renders the navigation tree — the modal does its own one-second tick to sample the refs while open. Writes are throttled (single-flight timer, 2 s window) and flushed on pagehide / visibilitychange so the latest events aren't lost to the throttle window. The modal itself is portalled to document.body so the sidebar's stacking context can't trap it.": + "Nota de implementación: el estado por evento vive en useRef Bufers en la barra lateral para que el grifo de fuego WS nunca vuelva a renderizar el árbol de navegación, el modal hace su propio tic de un segundo para muestrar las referencias mientras está abierto. Las escrituras se limitan (timer de vuelo único, ventana de 2 s) y se borran en pagehide / visibilitychange Así que los últimos eventos no se pierden en la ventana de aceleración. El modal en sí se redirige a document.body Así que el contexto de empalme de la barra lateral no puede atraparlo.", + "The entire UI ships in four languages — English, 简体中文, Tiếng Việt, and 한국어 — built on i18next + react-i18next with i18next-browser-languagedetector. Coverage is end-to-end: every page, chart tooltip, Settings flow, Workflow narrative, Config Explorer tab, Run page, and the Alerts rule-help tooltips + webhook setup guides are translated. Switch languages from the sidebar (EN / 中文 / VI / 한국어) — the choice persists in localStorage.": + "Toda la interfaz de usuario se envía en Cuatro idiomas: inglés, chino simplificado, vietnamita y coreano — construido sobre i18next + react-i18next con i18next-browser-languagedetector. la cobertura es de extremo a extremo: todas las páginas, las etiquetas de herramientas de gráficos, el flujo de Configuración, la narrativa del flujo de trabajo, la pestaña Config Explorer, la página Ejecutar y las etiquetas de ayuda de las reglas de Alertas + las guías de configuración de webhook se traducen. Cambie el idioma desde la barra lateral (EN / 中文 / VI / 한국어) - la elección persiste en localStorage.", + 'Translations are split into per-area JSON namespaces (common, nav, dashboard, sessions, analytics, workflows, settings, kanban, run, ccConfig, alerts, errors, updates) under client/src/i18n/locales/<lng>/. Components load only the namespaces they need via useTranslation("…").': + 'Las traducciones se dividen en nombrespaces JSON por área (common, nav, dashboard, sessions, analytics, workflows, settings, kanban, run, ccConfig, alerts, errors, updates) debajo client/src/i18n/locales/<lng>/. Los componentes cargan solo los espacios de nombres que necesitan a través de useTranslation("…").', + "Language is detected from localStorage (i18nextLng) then the browser's navigator setting, and the choice is cached back to localStorage. fallbackLng is English and nonExplicitSupportedLngs resolves regional tags (e.g. vi-VNvi), so any unmapped key falls back gracefully rather than rendering a raw key.": + "Se detecta el idioma de localStorage (i18nextLng) entonces el del navegador navigator Configuración, y la elección se almacena en caché de vuelta a localStorage. fallbackLng Es inglés y nonExplicitSupportedLngs Resuelve etiquetas regionales (por ejemplo, vi-VNvi), por lo que cualquier clave no asignada se recupera con gracia en lugar de renderizar una clave bruta.", + "Numbers, costs, dates, and relative times format against the active locale via a shared getCurrentLocale() helper, and plurals use i18next's _one / _other suffixes. Interpolated values ({{count}}, {{provider}}, …) keep sentences natural across languages.": + "Los números, los costos, las fechas y los tiempos relativos se formatean contra el lugar de origen activo a través de un compartido getCurrentLocale() Ayudante, y los plurales usan los de i18next _one / _other Sufijos. Valores interpolados ({{count}}, {{provider}}, ...) mantenga las oraciones naturales a través de idiomas.", + "Domain terms that are proper nouns or code stay untranslated in every locale — Agent, Subagent, hook event names (PostToolUse), tool names (Bash), and webhook provider names (Slack, PagerDuty). Only the surrounding prose is localized, so instructions stay accurate.": + "Los términos de dominio que son nombres propios o códigos permanecen sin traducir en cada ubicación — representante, Subagente, conectar los nombres de los eventos (PostToolUse), nombres de herramientas (Bash), y nombres de proveedores de webhook (Slack, PagerDuty). Solo la prosa circundante se localiza, por lo que las instrucciones permanecen precisas.", + "Adding a language": "Añadir un idioma", + "Copy client/src/i18n/locales/en/ to a new locale folder, translate the JSON values (leaving keys and technical terms intact), then register the bundle and add the tag to supportedLngs in client/src/i18n/index.ts. Missing keys fall back to English automatically, so even a partial translation ships cleanly.": + "copia client/src/i18n/locales/en/ A una nueva carpeta de ubicación, traduzca los valores JSON (dejando intactas las claves y los términos técnicos), luego regístre el paquete y agregue la etiqueta a supportedLngs indio client/src/i18n/index.ts. claves faltantes se vuelven automáticamente al inglés, por lo que incluso una traducción parcial se envía sin problemas.", + "Tabby is a cute SVG cat companion pinned to the edges of every page of the dashboard. It is always present and turns the live session stream into glanceable, ambient feedback — calm when idle, alert when something needs attention, and celebratory when a run finishes. Tabby is built entirely on the existing eventBus WebSocket stream: no new backend, no API key, and no new dependencies. The component lives in client/src/components/Tabby/ and can be toggled on or off in Settings page.": + "gata Es un lindo compañero de gato SVG atado al Líneas de cada página del panel de control. Siempre está presente y convierte el flujo de la sesión en vivo en un retroalimentación ambiental que se puede ver de un vistazo: tranquilo cuando está inactivo, alerta cuando algo necesita atención y festivo cuando una carrera termina. Tabby está construido enteramente sobre el existente eventBus Stream WebSocket: Sin nuevo backend, sin clave API y sin nuevas dependencias. componente vive en client/src/components/Tabby/ y se puede activar o desactivar en la página de Configuración.", + '📥 Tabby Companion — a cute SVG cat in the edges of every page, reacting in real time to the live session stream with eight distinct moods and animations, auto-surfacing speech bubbles for notable events, and serving as the gateway to a status panel and Ask box': + '📥 Tabby Companion: un lindo gato SVG en los bordes de cada página, que reacciona en tiempo real al flujo de la sesión en vivo con ocho estados de ánimo y animaciones distintos, burbujas de diálogo que aparecen automáticamente para eventos notables y que sirve como puerta de entrada a un panel de estado y una caja de preguntas.', + "Tabby derives one of eight moods from the live session WebSocket stream, each with its own animation. The eyes track your cursor, and the active mood drives a distinct motion cue.": + "Tabby deriva uno de los ocho estados de ánimo del flujo WebSocket de la sesión en vivo, cada uno con su propia animación. Los ojos rastrean el cursor y el estado de ánimo activo impulsa una señal de movimiento distinta.", + "Notable events — session started or finished, errors, and run completed — automatically surface a speech bubble. Bubbles are throttled and coalesced so bursts of events never spam you, and they can be muted on demand. Everything reflects in real time over the existing eventBus WebSocket channel, with no polling and no extra services.": + "Los eventos notables, como el inicio o finalización de la sesión, los errores y la finalización de la ejecución, generan automáticamente una burbuja de diálogo. Las burbujas son Controlando y coalescente Así que los brotes de eventos nunca te envían spam, y puedes silenciarlos a demanda. Todo se refleja en tiempo real sobre el existente eventBus Canal WebSocket, sin consultas y sin servicios adicionales.", + "Click the cat — or press ⌘B / Ctrl+B — to open Tabby's panel (Esc closes it). The panel groups a live status line, quick actions, and an Ask box.": + "Haz clic en el gato o pulsa ⌘B / Ctrl+B — para abrir el panel de Tabby (Esc lo cierra). El panel agrupa una línea de estado en vivo, acciones rápidas y una caja de Preguntar.", + "Live status line: N live · M errored · connection state, updated from cached data.": + "Línea de estado en vivo: N en vivo · M error · estado de conexión, actualizado a partir de datos almacenados en caché.", + "Quick actions: jump to Run Claude, Activity, Sessions, or errored sessions; mute bubbles; clear alerts.": + "Acciones rápidas: Ir a Ejecutar Claude, Actividad, Sesiones o sesiones con errores; silenciar burbujas; eliminar alertas.", + "Ask box: answers simple status questions locally from cached data (“what's running”, “any errors”, “status”).": + "Caja de preguntas: Responde preguntas de estado simples localmente a partir de datos caché ("qué está ejecutando", "cuáles son los errores", "estado").", + "The Ask box answers status questions instantly and offline from cached data. For anything beyond a simple status question, Tabby hands off to the existing Run Claude page (/run?prompt=...) to spawn a real Claude Code session — so there is never a separate model call, key, or service to manage.": + "La caja de Preguntas responde instantáneamente a las preguntas de estado y sin conexión a partir de datos caché. Para cualquier cosa más allá de una simple pregunta de estado, Tabby se entrega al existente Corra Claude Página (/run?prompt=...) para crear una sesión real de Claude Code, por lo que nunca hay una llamada de modelo, clave o servicio separado que administrar.", + "Fully keyboard operable: ⌘B / Ctrl+B to open, Esc to close.": + "Totalmente operativo con teclado: ⌘B / Ctrl+B Para abrir, Esc Cerrar.", + "Status and bubbles announce via aria-live for screen readers.": + "Estado y burbujas anunciadas a través de aria-live Para lectores de pantalla.", + "Respects prefers-reduced-motion to calm animations.": + "consideración prefers-reduced-motion Para calmar las animaciones.", + "Degrades gracefully to a calm, dimmed disconnected state when offline.": + "Se degrada con gracia a un estado tranquilo, apagado y desconectado cuando está desconectado.", + Endpoint: "Punto final", + Mood: "humor", + "When it appears": "Cuando aparezca", + Animation: "animación", + Idle: "andar al ralentí", + "Nothing notable happening": "Nada notable sucediendo", + "Gentle tail flick": "Pelea suave de cola", + Watching: "Observando", + "Sessions active, observing the stream": "Sesiones activas, observando el flujo", + "Ear perk, cursor-tracking eyes": "Apertura de los oídos, ojos que rastrean el cursor", + Happy: "feliz", + "A run completed successfully": "Una carrera completada con éxito", + Sparkle: "brillo", + Worried: "preocupado", + "Something looks off": "Algo no cuadra", + "Head bob": "Sacudir la cabeza", + Stuck: "atascado", + "A session appears blocked": "Una sesión parece estar bloqueada", + "Shake + alert !": "Sacudir + alerta !", + Thinking: "pensante", + "Work in progress": "Trabajo en progreso", + Sleeping: "sueño", + "Quiet for a while": "Tranquilo por un rato", + Zzz: "zzz", + Disconnected: "desconectado", + "WebSocket offline": "WebSocket sin conexión", + "Calm, dimmed state": "Estado tranquilo y apagado", + "Development vs production deployment topology": + "Topología de despliegue de desarrollo vs producción", + Aspect: "faceta", + Development: "explotación", + Production: "creación", + Processes: "Procesos", + "2 (Express + Vite)": "2 (Expreso + Vite)", + "1 (Express only)": "1 (Solo exprés)", + "Client URL": "URL del cliente", + "API proxy": "Proxy de API", + "Vite proxies /api + /ws to :4820": + "Proxies Vite /api + /ws A: 4820", + "Same origin, no proxy": "Misma origen, sin proxy", + "File watching": "Seguimiento de archivos", + "node --watch + Vite HMR": "node --watch + Vite HMR", + None: "nona", + "Source maps": "Mapa de fuentes", + Inline: "En línea", + "External files": "Archivos externos", + "A third way to run: the Desktop App (macOS & Windows)": + "Una tercera forma de ejecutar: la aplicación de escritorio (macOS y Windows)", + 'Beyond development and standalone production, the dashboard also ships as a native desktop app — a macOS .app and a Windows .exe — that embeds the same production server in-process, no terminal required. See the Desktop App (macOS & Windows) section for download, build, and install instructions.': + 'Más allá del desarrollo y la producción independiente, el panel de control también se envía como una aplicación nativa para escritorio, una macOS. .app Y una ventana .exe — que incorpora el mismo servidor de producción en el proceso, no se requiere terminal. Consulte el Aplicación para escritorio (macOS y Windows) Sección para descargar, construir e instalar instrucciones.', + "The production image is OCI-compatible and works with both Docker and Podman. The server listens on 4820, reads legacy Claude history from a read-only mount, and persists SQLite data under /app/data.": + "La imagen de producción es compatible con OCI y funciona tanto con Docker como con Podman. El servidor escucha en 4820, lee la historia heredada de Claude desde una unidad de lectura única y persiste los datos de SQLite bajo /app/data.", + "Container image build and runtime mounts": + "Construcción de la imagen del contenedor y montajes de tiempo de ejecución", + Mount: "monte", + "Read historical Claude session files for import without modifying them": + "Lea los archivos históricos de sesiones de Claude para su importación sin modificarlos", + "Persist the SQLite database across rebuilds and container restarts": + "Persiste la base de datos SQLite a través de las reconstrucciones y reinicios de contenedores", + "Hooks still run on the host": + "Los ganchos todavía funcionan en el host", + "Claude Code fires hooks from the host machine, not from inside the container. After the container is healthy on http://localhost:4820, run npm run install-hooks on the host so hook events post back to the containerized server.": + "Claude Code dispara ganchos desde la máquina anfitriona, no desde dentro del contenedor. Después de que el contenedor esté sano en http://localhost:4820, correr npm run install-hooks en el host, así que envía los eventos de conexión de vuelta al servidor contenedorizado.", + "A multi-stage Dockerfile and docker-compose.yml are included. Both Docker and Podman are fully supported — the image is OCI-compliant.": + "Un multiestadio Dockerfile y docker-compose.yml Están incluidos. ambos estibador y Podman Son totalmente compatibles: la imagen cumple con la normativa OCI.", + "Read-only access to legacy session history for automatic import on startup": + "Acceso de lectura única al historial de sesiones heredadas para importación automática al inicio de sesión", + "Persists the SQLite database across container restarts": + "Persiste la base de datos SQLite a través de reinicios de contenedores", + "The Dockerfile uses three stages to minimize the final image size:": + "El Dockerfile utiliza tres etapas para minimizar el tamaño final de la imagen:", + Stage: "etapa", + "Installs production node_modules on node:22-alpine. better-sqlite3 is optional — if prebuilds are unavailable, the server falls back to built-in node:sqlite": + "Instala producción node_modules en node:22-alpine. better-sqlite3 Es opcional: si las construcciones preestablecidas no están disponibles, el servidor recurre a las construcciones integradas. node:sqlite", + "Runs npm ci + vite build to produce optimized static assets": + "Corre npm ci + vite build Para producir activos estáticos optimizados", + "Clean node:22-alpine with only node_modules, server code, and client/dist": + "limpio node:22-alpine Con solo node_modules, código del servidor y client/dist", + "Hook note": "Nota de gancho", + "Claude Code hooks run on the host, not inside the container. The containerized server receives hook events via HTTP on localhost:4820. Run npm run install-hooks on the host after starting the container.": + "Los ganchos de Claude Code se ejecutan en el host, no dentro del contenedor. El servidor contenedorizado recibe eventos de gancho a través de HTTP en localhost:4820. carrera npm run install-hooks En el host después de iniciar el contenedor.", + Metric: "métrico", + "Server startup": "Inicio de sesión del servidor", + "SQLite opens instantly; schema migration is idempotent": + "SQLite se abre instantáneamente; la migración del esquema es idempotente", + "Hook latency": "Latencia del gancho", + "Transaction + broadcast, no async I/O beyond SQLite": + "Transacción + transmisión, sin E/S asincrónica más allá de SQLite", + "Client JS bundle": "Paquete JS del cliente", + "WebSocket latency": "Latencia de WebSocket", + "Local loopback, JSON serialization only": "Bucle local, solo serialización JSON", + "SQLite write throughput": "Trafico de escritura de SQLite", + "WAL mode on SSD; far exceeds any hook event rate": + "Modo WAL en SSD; supera ampliamente cualquier tasa de eventos de conexión.", + "Max events before slowdown": "Máximo número de eventos antes de la ralentización", + "Pagination prevents full-table scans": "La paginación evita escaneos completos de la tabla", + "Server memory": "Memoria del servidor", + "SQLite in-process, no ORM overhead": "SQLite en proceso, sin sobrecostes de ORM", + "Client memory": "Memoria del cliente", + "React + Tailwind, minimal runtime deps": + "React + Tailwind, dependencias mínimas de tiempo de ejecución", + "Input validation": "Validación de la entrada", + "Required fields checked before DB operations; CHECK constraints on status enums": + "Campos requeridos marcados antes de las operaciones de la base de datos; CONSTRAINTES DE COMPROBACIÓN en los enums de estado", + "Hook safety": "Seguridad del gancho", + "Hook handler always exits 0; 5s max lifetime; uses 127.0.0.1 not external hosts": + "El manipulador de ganchos siempre sale 0; vida útil máxima de 5 segundos; utiliza 127.0.0.1 No hosts externos", + CORS: "CORS", + "Restricted to loopback origins, so cross-origin pages can't read responses; no-Origin clients like curl still work": + "Restringido a orígenes de retroceso, por lo que las páginas de origen cruzado no pueden leer las respuestas; los clientes sin origen como curl todavía funcionan", + Authentication: "autentificación", + "Off by default since the loopback bind is the trust boundary; set DASHBOARD_TOKEN to require a bearer token on every /api/* request and the WebSocket when exposing on a LAN.": + "Desactivado por defecto ya que el enlace de retroceso es el límite de confianza; establecer DASHBOARD_TOKEN Para requerir un token portador en cada /api/* Solicitud y el WebSocket cuando se expone en una LAN.", + Secrets: "Secretos", + "No API keys, tokens, or credentials stored or transmitted anywhere": + "No se almacenan ni transmiten claves API, tokens ni credenciales en ningún lugar.", + "Dependency surface": "Superficie de dependencia", + "5 runtime server deps, 6 runtime client deps (includes D3.js for Workflows) — minimal attack surface": + "5 dependencias del servidor de tiempo de ejecución, 6 dependencias del cliente de tiempo de ejecución (incluye D3.js para flujos de trabajo) - superficie de ataque mínima", + "Hooks only apply to sessions started after installation. Restart Claude Code after starting the dashboard.": + "Los ganchos solo se aplican a las sesiones iniciadas después Instalación. Reinicie el código Claude después de iniciar el panel de control.", + "On some systems the shell environment when Claude Code fires hooks may not include the full PATH. Test with node --version. If not found, use the absolute path to node in the hook command.": + "En algunos sistemas, el entorno de la cáscara cuando Claude Code dispara los ganchos puede no incluir el PATH completo. Pruebe con node --version. Si no se encuentra, use el camino absoluto a node En el comando de gancho.", + Problem: "problema", + Solution: "solución", + "better-sqlite3 errors during install": + "better-sqlite3 Errores durante la instalación", + "This is non-fatal — better-sqlite3 is an optional dependency. On Node 22+ the server automatically falls back to built-in node:sqlite. On older Node versions, install Python 3 + C++ build tools, then run npm rebuild better-sqlite3. For the desktop app, the desktop:install preflight prints copy-pasteable per-OS setup guidance (incl. a no-toolchain alternative) when the native build fails.": + "Esto no es mortal — better-sqlite3 Es una dependencia opcional. En Node 22+ el servidor vuelve automáticamente a los incorporados. node:sqlite. versiones de Node más antiguas, instale las herramientas de compilación de Python 3 + C++, luego ejecute npm rebuild better-sqlite3. para la aplicación de escritorio, el desktop:install Impresiones de prevolado con instrucciones de configuración copiables y pegables por sistema operativo (incluyendo una alternativa sin cadena de herramientas) cuando la construcción nativa falla.", + 'Dashboard shows "Disconnected"': 'El panel de control muestra "Desconectado"', + "Server is not running. Start it with npm run dev. Client auto-reconnects every 2s.": + "El servidor no está funcionando. Inícialo con npm run dev. se reconecta automáticamente el cliente cada 2 segundos.", + "Events Today shows 0": "Eventos de hoy muestran 0", + "Ensure you are on the latest version (timezone bug was fixed). Restart the server.": + "Asegúrese de estar en la última versión (se ha solucionado el error del huso horario). Reinicie el servidor.", + "Port 4820 already in use": "Puerto 4820 ya en uso", + "Run DASHBOARD_PORT=4821 npm run dev, update Vite proxy in client/vite.config.ts, and re-run npm run install-hooks.": + "carrera DASHBOARD_PORT=4821 npm run dev, actualizar el proxy Vite en client/vite.config.ts, y volver a ejecutar npm run install-hooks.", + "Stale seed data shown": "Se muestran datos de semillas caducas", + "Run npm run clear-data to wipe all rows, then restart.": + "carrera npm run clear-data Para borrar todas las filas, luego reinicia.", + "Hooks show validation error about matcher": + "Los ganchos muestran un error de validación sobre el coincidiente", + 'Ensure you\'re on the latest version — the hook format was updated to use matcher: "*" string (not object).': + 'Asegúrate de estar en la última versión: el formato de gancho se actualizó para usar matcher: "*" cadena (no objeto).', + '"SQLite backend not available" on startup': '"Backend SQLite no disponible" al arrancar', + "Neither better-sqlite3 nor node:sqlite could load. Upgrade to Node.js 22+ (recommended), or install Python 3 + C++ build tools and run npm rebuild better-sqlite3.": + "ninguno better-sqlite3 tampoco node:sqlite podría cargar. Actualice a Node.js 22+ (recomendado) o instale herramientas de compilación de Python 3 + C++ y ejecute npm rebuild better-sqlite3.", + "Docker container runs but no sessions appear": + "El contenedor Docker se ejecuta, pero no aparecen sesiones", + "Hooks run on the host, not inside the container. Run npm run install-hooks on the host after the container starts. Verify hooks in ~/.claude/settings.json point to localhost:4820.": + "Los ganchos funcionan en el host, no dentro del contenedor. carrera npm run install-hooks En el host después de que el contenedor comience. Verifique los ganchos en ~/.claude/settings.json Puntar a localhost:4820.", + Technology: "tecnología", + "Why This Over Alternatives": "Por qué esto sobre alternativas", + "Zero-config, embedded, no server process. WAL mode gives concurrent reads. Synchronous API is simpler than async for this use case. better-sqlite3 is preferred when prebuilds are available; falls back to Node.js built-in node:sqlite on Node 22+ when the native module cannot be compiled.": + "Configuración cero, incorporado, sin proceso de servidor. El modo WAL proporciona lecturas concurrentes. La API sincrónica es más sencilla que la asincrónica para este caso de uso. better-sqlite3 Se prefiere cuando están disponibles las precompilaciones; se recurre a la incorporación de Node.js node:sqlite en Node 22+ cuando el módulo nativo no se puede compilar.", + "Battle-tested, minimal, well-understood. Fastify would be overkill; raw http module would require too much boilerplate for routing.": + "Probado en batalla, minimalista, bien entendido. Fastify sería una exageración; crudo http El módulo requeriría demasiada plantilla para el enrutamiento.", + "Fastest, most lightweight WebSocket library for Node. No Socket.IO overhead needed — we only push typed JSON messages one-way.": + "La biblioteca WebSocket más rápida y ligera para Node. No se necesita sobrecarga de Socket.IO, solo enviamos mensajes JSON de tipo de forma bidireccional.", + "Stable, widely known, strong TypeScript support. No Server Components or RSC needed for a client-rendered local SPA.": + "Sostenible, ampliamente conocido, fuerte soporte para TypeScript. No se necesitan componentes de servidor ni RSC para un SPA local renderizado por el cliente.", + "Fast builds, native ESM, excellent dev experience. Proxy config handles the dev server split cleanly with no ejection.": + "Construcciones rápidas, ESM nativo, excelente experiencia de desarrollo. La configuración del proxy maneja la división del servidor de desarrollo de forma limpia sin expulsión.", + "Utility-first approach keeps styles colocated with markup. No CSS module boilerplate. Custom dark theme config for the dark UI.": + "El enfoque de priorizar la utilidad mantiene los estilos colocalizados con el marcado. Sin plantilla de módulo CSS. Configuración personalizada del tema oscuro para la interfaz de usuario oscura.", + "Standard routing for React SPAs. Layout routes with <Outlet> give clean shell composition without prop drilling.": + "Ruta estándar para React SPAs. Rutas de diseño con <Outlet> Dar una composición de cáscara limpia sin perforación de propósitos.", + "Tree-shakeable icon library — only imports what's used (~20 icons). No heavy icon font.": + "Biblioteca de iconos que se pueden sacudir como un árbol: solo importa lo que se utiliza (~20 iconos). Sin fuente de iconos pesada.", + "Catches null/undefined bugs at compile time. noUncheckedIndexedAccess prevents array bounds issues in analytics aggregations.": + "Captura errores nulos/indefinidos en el momento de la compilación. noUncheckedIndexedAccess previene problemas de límites de arreglo en las agregaciones analíticas.", + "Industry-standard data visualization library. Powers the Workflows page's 11 interactive sections — DAG layouts, Sankey diagrams, force-directed graphs, bubble charts, and swim-lane timelines. No wrapper libraries needed; direct SVG rendering keeps bundle impact minimal.": + "Biblioteca de visualización de datos estándar de la industria. Proporciona potencia a las 11 secciones interactivas de la página de flujos de trabajo: diseños DAG, diagramas Sankey, gráficos dirigidos por fuerza, gráficos de burbujas y cronogramas de carril de natación. No se necesitan bibliotecas de envoltorio; la renderización directa de SVG mantiene el impacto del paquete mínimo.", + "Available on virtually all systems. Handles ANSI and JSON natively with stdlib only. No install step required.": + "Disponible en prácticamente todos los sistemas. Maneja ANSI y JSON nativamente con stdlib solo. No se requiere ningún paso de instalación.", + "Local-first monitoring for Claude Code sessions, agents, and tool events. Built for real-time visibility with zero external dependencies.": + "Monitoreo local primero para sesiones de Claude Code, agentes y eventos de herramientas. Construido para visibilidad en tiempo real con cero dependencias externas.", + Install: "instalar", + Setup: "configuración", + "About the Creator": "Sobre el creador", + ' Enjoying the project? Give it a star on GitHub and help more builders discover it. ': + ' ¿Disfrutando del proyecto? Dale una estrella en GitHub Y ayudar a más constructores a descubrirlo. ', + 'Clears the waiting flag and promotes the main agent to Working. The only reliable signal that text-only assistant turns have started — they emit no PreToolUse before Stop.': + 'Borra la bandera de espera y promueve al agente principal a de trabajo. señal confiable de que los teléfonos con asistente de texto solo han comenzado a funcionar: no emiten ninguna PreToolUse antes Stop.', + 'Clears the waiting flag, sets agent → Working, current_tool set. If tool is Agent, subagent record created.': + 'Borra la bandera de espera, establece agente → de trabajo, current_tool Configurar. Si la herramienta es Agent, registro del subagente creado.', + 'Clears the waiting flag (covers permission-prompt approvals mid-tool). current_tool cleared. Agent stays Working.': + 'Borra la bandera de espera (cubre las aprobaciones de la solicitud de permiso a mitad de la herramienta). current_tool Liberado. El agente permanece de trabajo.', + 'Non-error: main agent → waiting — UI shows Waiting until the next user input. stop_reason=error: marks the agent and session Error. Background subagents keep running.': + 'Sin error: agente principal → waiting — Muestra de interfaz de usuario espera Hasta la próxima entrada del usuario. stop_reason=error: marca al agente y la sesión error informático. de los subagentes de fondo siguen funcionando.', + 'Matched subagent → Completed. Deliberately does not clear the waiting flag — a backgrounded subagent finishing tells us nothing about the human. Also kicks off a fire-and-forget JSONL scan (scanAndImportSubagents) that walks the session\'s subagents/agent-*.jsonl files, pairs tool_usetool_result blocks by tool_use_id, and emits per-tool PreToolUse + PostToolUse events under each subagent\'s own agent_id — surfaces tool calls that subagents make internally and which never fire any hooks.': + 'Subagente coincidente → Completado. idamente lo hace no Borrar la bandera de espera: un subagente en segundo plano que termina no nos dice nada sobre el humano. También inicia una escaneo JSONL de fuego y olvido (scanAndImportSubagents) que camina por la sesión subagents/agent-*.jsonl Archivos, pares tool_usetool_result Bloques por tool_use_id, y emite por herramienta PreToolUse + PostToolUse Eventos bajo los propios de cada subagente agent_id — las llamadas de herramientas de superficies que hacen los subagentes internamente y que nunca disparan ningún gancho.', + 'Creates a compaction subagent → Completed. Detected via isCompactSummary entries in the transcript. Token baselines preserve pre-compaction totals. Periodic scanner (cadence ~¼ of DASHBOARD_STALE_MINUTES) catches compactions when no hooks fire.': + 'Crea un subagente de compactación → Completado. detectado a través de isCompactSummary Entradas en la transcripción. Las bases de referencia de tokens conservan los totales previos a la compactación. Escáner periódico (cadencia ~¼ de DASHBOARD_STALE_MINUTES) atrapa compactaciones cuando no disparan los ganchos.', + 'Drops the waiting flag. If the session is already in Error, the error state is preserved; otherwise marks all agents and the session as Completed. Evicts the session\'s transcript from the shared cache.': + 'Deja caer la bandera de espera. Si la sesión ya está en error informático, el estado de error se preserva; de lo contrario, marca a todos los agentes y la sesión como Completado. la transcripción de la sesión del caché compartido.', + "SQLite connection, WAL/FK pragmas, schema migrations (CREATE TABLE IF NOT EXISTS), all prepared statements as a reusable stmts object. Tries better-sqlite3 first, falls back to built-in node:sqlite via compat-sqlite.js": + "Conexión SQLite, pragmas WAL/FK, migraciones de esquema (CREATE TABLE IF NOT EXISTS), todas las declaraciones preparadas como reutilizables stmts Objeto. Intenta better-sqlite3 En primer lugar, vuelve a lo incorporado node:sqlite a través de compat-sqlite.js", + "Each page pulls initial data from REST then subscribes to eventBus for live updates": + "Cada página obtiene los datos iniciales de REST y luego se suscribe a eventBus para recibir actualizaciones en vivo.", + "Entity Relationship Diagram — SQLite schema": + "Diagrama de relaciones de entidades - esquema SQLite", + "Working Dir": "Director de trabajo", + "Git Branch": "Ramificación de Git", + "Context Bar": "Barra de contexto", + "Token Counts": "Contas de tokens", + "Session Cost": "Costo de la sesión", + "Statusline rendering pipeline — invoked on each Claude Code update": + "Pipeline de renderizado de Statusline: invocado en cada actualización del Código Claude.", + "Aggregates data from multiple API endpoints to display high-signal metrics directly in the sidebar:": + "Agrupa datos de múltiples puntos finales de API para mostrar métricas de alto señal directamente en la barra lateral:", + "Zero-Config Setup": "Configuración de cero configuración", + "One-line mental model": "Modelo mental de una línea", + "Your data survives reinstalls and updates": + "Sus datos sobreviven a las reinstalaciones y actualizaciones", + "The claude CLI is found automatically": + "el claude El CLI se encuentra automáticamente", + 'Open Releases → latest and download the asset for your platform. The macOS and Windows Desktop CI jobs auto-publish a new vX.Y.Z release every time the version in package.json is bumped on master, so this link always points at the current build. Releases are public — no GitHub sign-in required.': + 'aire libre Lanzamientos → más recientes y descargue el recurso para su plataforma. Los trabajos de CI de escritorio de macOS y Windows publican automáticamente un nuevo vX.Y.Z Lanzamiento cada vez que la versión en package.json Se golpea en master, por lo que este enlace siempre señala la versión actual. Las publicaciones son públicas, no se requiere iniciar sesión en GitHub.', + 'Want a build straight off the tip of master, ahead of the next tagged release? Every green run of the 🍎 macOS Desktop (DMG) job on macos-latest uploads both per-arch DMGs as the ClaudeCodeMonitor-dmg workflow artifact, and the 🪟 Windows Desktop (EXE) job on windows-latest uploads the installer + portable EXEs as the ClaudeCodeMonitor-win artifact. Open the latest passing run , scroll to its Artifacts section, and download ClaudeCodeMonitor-dmg or ClaudeCodeMonitor-win. (GitHub sign-in required; 14-day retention.)': + 'Quieres una construcción directamente desde la punta de master, ¿antes del próximo lanzamiento etiquetado? Cada carrera verde del 🍎 macOS Desktop (DMG) Trabajo en curso macos-latest Sube tanto los DMG por archivo como el ClaudeCodeMonitor-dmg Artefacto del flujo de trabajo y el 🪟 Windows Desktop (EXE) Trabajo en curso windows-latest Sube el instalador + los EXEs portátiles como el ClaudeCodeMonitor-win Artefacto. Abre el Última carrera de paso , desplázate hasta la sección de Artifactos y descarga ClaudeCodeMonitor-dmg Oregón ClaudeCodeMonitor-win. (Se requiere iniciar sesión en GitHub; retención de 14 días).', + "Incoming Webhook URL": "URL de Webhook entrante", + "Webhook URL": "URL de Webhook", + "Detection pipeline from scheduler to UI": + "Pipeline de detección desde el programador hasta la interfaz de usuario", + "A shell-less git fetch with a 120-second timeout, followed by a rev-list against the tracked upstream. Each call runs from server/lib/update-check.js and returns a structured payload — never throws — so a flaky remote can't stall the dashboard.": + "Sin cáscara git fetch Con un tiempo de espera de 120 segundos, seguido de un rev-list Contra el rastreado en el curso superior. Cada llamada se ejecuta desde server/lib/update-check.js y devuelve una carga útil estructurada, nunca lanza, por lo que un control remoto inestable no puede paralizar el panel de instrumentos.", + "Detection-only by design": "Detección solo por diseño", + "Adding a language": "Añadir un idioma", + "Ask box: answers simple status questions locally from cached data (“what's running”, “any errors”, “status”).": + 'Caja de preguntas: Responde preguntas de estado simples localmente a partir de datos almacenados ("qué está ejecutando", "algunos errores", "estado").', + "A third way to run: the Desktop App (macOS & Windows)": + "Una tercera forma de ejecutar: la aplicación de escritorio (macOS y Windows)", + "Hooks still run on the host": "Los ganchos todavía funcionan en el host", + "Hook note": "Nota de gancho", + "SQL injection": "Inyección SQL", + "All queries use prepared statements with parameterized values — no string interpolation": + "Todas las consultas utilizan declaraciones preparadas con valores parametrizados, sin interpolación de cadenas", + "Request size": "Tamaño de la solicitud", + "Express JSON body parser limited to 1MB": + "El analizador de cuerpo JSON de Express está limitado a 1 MB.", + "Dashboard — stats, active agents, recent events": + "Panel de control: estadísticas, agentes activos, eventos recientes", + "KanbanBoard — agent status columns": "KanbanBoard — columnas de estado del agente", + "Sessions — searchable, filterable table": "Sesiones: tabla buscable y filtrable", + "SessionDetail — agents + full event timeline": + "Detalles de la sesión: agentes + cronología completa del evento", + "ActivityFeed — real-time streaming event log": + "ActivityFeed: registro de eventos de transmisión en tiempo real", + "Analytics — token usage, heatmap (day-of-week aligned), tool charts, donut charts": + "Análisis: uso de tokens, mapa de calor (alineado por día de la semana), gráficos de herramientas, gráficos de rosquillas", + "Workflows — D3.js visualizations, cross-filtering, status filter, session drill-in": + "Flujos de trabajo: visualizaciones D3.js, filtrado cruzado, filtro de estado, perforación de sesión", + "Settings — model pricing, hook status, data export, session cleanup": + "Configuración: precios del modelo, estado del gancho, exportación de datos, limpieza de sesiones", + 'Returns { "status": "ok", "timestamp": "..." }': + 'Devoluciones { "status": "ok", "timestamp": "..." }', + "List sessions with agent counts and per-session cost. Params: status, q (case-insensitive search across id/name/cwd), limit (default 50, max 10000), offset. Response includes total for paginators.": + "Listar sesiones con el número de agentes y el costo por sesión. Parámetros: status, q (búsqueda insensible a mayúsculas y minúsculas en todo id/name/cwd), limit (por defecto 50, máximo 10000), offset. incluye total Para paginadores.", + "Session detail with agents and events": "Detalles de la sesión con agentes y eventos", + "Create session (idempotent on id)": + "Crear sesión (idempotente en id)", + "Update session status / metadata": "Actualizar el estado de la sesión / metadatos", + "List agents — params: status, session_id, limit, offset": + "Listar agentes - parámetros: status, session_id, limit, offset", + "Single agent detail": "Detalles del agente único", + "Create agent": "Crear agente", + "Update agent status / task / current_tool": + "Actualizar el estado del agente / tarea / herramienta actual", + "List events newest-first — params: session_id, limit, offset": + "Listar eventos desde el más reciente al primero - parámetros: session_id, limit, offset", + "Aggregate counts + status distributions + WS connections": + "Contas agregadas + distribuciones de estado + conexiones WS", + "Token totals, tool usage, daily trends, agent types, event types, averages": + "Totales de tokens, uso de herramientas, tendencias diarias, tipos de agentes, tipos de eventos, promedios", + "Receive and process a Claude Code hook event (called by hook-handler.js)": + "Recibir y procesar un evento de gancho de código Claude (llamado por hook-handler.js)", + "List all model pricing rules": "Lista todas las reglas de precios de los modelos", + "Create or update a pricing rule": "Crear o actualizar una regla de precios", + "Delete a pricing rule": "Eliminar una regla de precios", + "Total cost across all sessions": "Costo total de todas las sesiones", + "Cost breakdown for a specific session": "Desglose de costos para una sesión específica", + "System info, DB stats, hook installation status": + "Información del sistema, estadísticas de la base de datos, estado de instalación del gancho", + "Delete all sessions, agents, events, token usage": + "Borrar todas las sesiones, agentes, eventos, uso de tokens", + "Reinstall Claude Code hooks": "Reinstalar los ganchos de Claude Code", + "Reset pricing rules to defaults": + "Restablecer las reglas de precios a los valores predeterminados", + "Export all data as JSON download": "Exportar todos los datos como descarga JSON", + "Abandon stale sessions (by hours), purge old data (by days)": + "Abandone sesiones obsoletas (por horas), purgue datos antiguos (por días)", + "OS-aware paths, archive command, supported extensions, step-by-step instructions; includes live stats for the default ~/.claude/projects folder": + "Rutas conscientes del sistema operativo, comando de archivo, extensiones compatibles, instrucciones paso a paso; incluye estadísticas en vivo para la predeterminada ~/.claude/projects carpeta", + "Re-scan the default ~/.claude/projects directory; safe to re-run (idempotent via session-ID dedup)": + "Reescanea el predeterminado ~/.claude/projects directorio; seguro de volver a ejecutar (identidad empotrada mediante deduplicación de ID de sesión)", + "Scan any absolute directory (body { path }); tilde (~) is expanded; walks subdirectories recursively and imports every .jsonl found": + "Escanea cualquier directorio absoluto (cuerpo { path }); tilde (~) se expande; recorre subdirectorios recursivamente e importa cada .jsonl fundador", + "Multipart upload of .jsonl, .meta.json, .zip, .tar, .tar.gz, .tgz, .gz. Per-request staging dir, path-traversal and extraction-size guards. Returns 413 EXTRACTION_LIMIT_EXCEEDED on suspected bomb archives": + "Subida multiparticular de .jsonl, .meta.json, .zip, .tar, .tar.gz, .tgz, .gz. dirección de ensayo por solicitud, recorrido de rutas y guardias de tamaño de extracción. Devuelve 413 EXTRACTION_LIMIT_EXCEEDED En archivos sospechosos de bombas", + "Aggregate workflow data — orchestration graphs, tool flows, effectiveness, patterns, model delegation, error propagation, concurrency, complexity, compaction impact. Accepts ?status=active|completed query param to filter by workflow status": + "Datos agregados del flujo de trabajo: gráficos de orquestación, flujos de herramientas, eficacia, patrones, delegación de modelos, propagación de errores, concurrencia, complejidad y impacto de la compactación. Acepta ?status=active|completed Parámetro de consulta para filtrar por estado del flujo de trabajo", + "Per-session drill-in — agent tree, tool timeline, event details": + "Entrenamiento por sesión: árbol de agentes, cronología de herramientas, detalles de eventos", + "Fired-alert feed, newest first (?unacked=true, limit, offset; carries total and unacked counts)": + "Feed de alerta de disparos, primero los más recientes (?unacked=true, limit, offset; lleva total y unacked Cuenta)", + "Acknowledge one alert": "Reconocer una alerta", + "Acknowledge every unacked alert": "Reconocer cada alerta no atendida", + "List alert rules": "Lista de reglas de alerta", + "Create a rule (event_pattern | inactivity | status_duration | token_threshold)": + "Crear una regla (event_pattern | inactivity | status_duration | token_threshold)", + "Update name / config / enabled / cooldown": + "Actualizar nombre / configuración / habilitado / tiempo de espera", + "Delete a rule and its fired-alert history": + "Borrar una regla y su historial de alertas activadas", + "Supported providers + their config fields (drives the UI form)": + "Proveedores compatibles + sus campos de configuración (dirigen el formulario de la interfaz de usuario)", + "List webhook targets (URLs masked, secrets redacted)": + "Lista de objetivos de webhook (URLs encriptadas, secretos redactados)", + "Create a target — 14 first-class providers (Slack, Discord, Teams, Google Chat, Mattermost, Rocket.Chat, Telegram, PagerDuty, Opsgenie, Splunk On-Call, Zapier, Make, n8n, Pipedream) + a generic JSON endpoint": + "Crea un objetivo: 14 proveedores de primera clase (Slack, Discord, Teams, Google Chat, Mattermost, Rocket.Chat, Telegram, PagerDuty, Opsgenie, Splunk On-Call, Zapier, Make, n8n, Pipedream) + un punto final JSON genérico", + "Update name / url / enabled / secret / headers / config / rule scope (type is immutable)": + "Actualizar nombre / url / habilitado / secreto / encabezados / configuración / alcance de la regla (type Es inmutable)", + "Delete a target and its delivery log": "Eliminar un objetivo y su registro de entrega", + "Send a synthetic test alert and report the result": + "Envíe una alerta de prueba sintética y informe el resultado", + "Recent delivery log for a target": "Registro de entregas recientes para un objetivo", + Documentation: "documentación", + Architecture: "arquitectura", + "Relevant Links": "Enlaces relevantes", + "GitHub Repo": "Repositorio de GitHub", + '🔔 Settings · Alerts — rules-based alerting engine and outbound webhooks in one place: alert rules (event pattern / inactivity / stuck agent / token threshold) with per-rule cooldown, a live fired-alert feed, and 14 first-class webhook providers plus a generic JSON endpoint with optional HMAC signing': + '🔔 Configuración · Alertas — motor de alertas basado en reglas y webhooks de salida en un solo lugar: reglas de alerta (patrón de eventos / inactividad / agente atascado / umbral de token) con tiempo de espera por regla, un feed de alertas lanzadas en vivo y 14 proveedores de webhooks de primera clase, además de un punto final JSON genérico con firma HMAC opcional', + '📗 API Docs · ReDoc — a self-hosted, read-optimized rendering of the full OpenAPI 3.0 spec at /api/redoc, served entirely offline with no CDN. Complements the interactive Swagger UI at /api/docs; every backend route is documented with parameters, schemas, and examples': + '📗 Documentación de API · ReDoc — una renderización alojada por sí misma, optimizada para la lectura, de la especificación completa de OpenAPI 3.0 en /api/redoc, servido completamente sin conexión a Internet sin CDN. Completa la interfaz de usuario interactiva de Swagger en /api/docs; cada ruta de backend está documentada con parámetros, esquemas y ejemplos', + '📘 API Docs · Swagger UI — interactive OpenAPI 3.0 playground at /api/docs: collapsible endpoint groups, request/response schemas, auth headers, and try-it-out request execution against the live local server': + '📘 Documentación de API · Interfaz de usuario Swagger — patio de recreo interactivo OpenAPI 3.0 en /api/docs: grupos de puntos finales plegables, esquemas de solicitud/respuesta, encabezados de autenticación y ejecución de solicitudes de prueba contra el servidor local en vivo', + '📗 ReDoc at /api/redoc — a self-hosted, read-optimized three-panel rendering of the same OpenAPI spec: deep-linkable sections, search, and full schema/example detail. Works entirely offline (no CDN)': + '📗 ReDoc en /api/redoc - una renderización de tres paneles alojada y optimizada para la lectura de la misma especificación OpenAPI: secciones vinculables a través de enlaces profundos, búsqueda y detalles completos del esquema/ejemplo. Funciona completamente sin conexión (sin CDN)', + '🔔 Settings · Alerts — the rules-based alerting engine, a live fired-alert feed, and outbound webhook channels (14 first-class providers + a generic JSON endpoint) managed together in one place': + '🔔 Configuración · Alertas: el motor de alertas basado en reglas, un feed de alertas en vivo y canales webhook de salida (14 proveedores de primera clase + un punto final JSON genérico) gestionados juntos en un solo lugar.', + 'Surfaces "dynamic workflows" — the fleets of sub-agents spawned by the Workflow tool and self-paced /loop runs. These emit no hooks, so they are reconstructed from the on-disk run journal written when a workflow finishes (workflows/wf_<runId>.json) plus the inner subagents/agent-*.jsonl transcripts. Each run shows its phases and a per-agent token / tool-call / duration breakdown; a running workflow is detected from its launch script before the journal exists. Runs appear in a panel on the Workflows page and as a linked subsection on each session.': + 'Superficies "trabajos de flujo dinámicos" - las flotas de subagentes generadas por el Workflow Herramienta y a ritmo propio /loop Ejecuciones. Estas no emiten enlaces, por lo que se reconstruyen a partir del diario de ejecución en el disco escrito cuando un flujo de trabajo termina (workflows/wf_<runId>.json) más el interior subagents/agent-*.jsonl transcripciones. Cada ejecución muestra sus fases y una desglose por token/llamada a herramienta/duración por agente; se detecta un flujo de trabajo en ejecución desde su script de lanzamiento antes de que el diario exista. Las ejecuciones aparecen en un panel en la página de Flujos de trabajo y como una subsección vinculada en cada sesión.', + '🧬 Workflow Runs — "dynamic workflows" spawned by the Workflow tool, reconstructed from on-disk run journals: status, agent count, tokens, and tool calls, expandable into a per-agent breakdown (phase, state, tokens, tools, duration) with humanized result previews': + '🧬 Ejecuciones del flujo de trabajo — "procesos de trabajo dinámicos" generados por la herramienta Workflow, reconstruidos a partir de los registros de ejecución en disco: estado, número de agentes, tokens y llamadas a herramientas, expandibles en una desglose por agente (fase, estado, tokens, herramientas, duración) con vistas preliminares de resultados humanizados', + '🧬 Workflow Runs · in a session — the same fleets linked to their launching session, so a session\'s dynamic-workflow sub-agents and their folded-in token cost are visible inline': + '🧬 Ejecuciones de flujo de trabajo · en una sesión — las mismas flotas vinculadas a su sesión de lanzamiento, por lo que los subagentes del flujo de trabajo dinámico de una sesión y su costo de token incorporado son visibles en línea', + '🧬 Workflow Runs · expanded — a run opened up: clickable color-coded phase filters, the per-agent metrics table, and a full list of clickable result items that expand to each agent\'s complete prompt and result': + '🧬 Ejecuciones de flujo de trabajo · expandido — se ha abierto una ejecución: filtros de fase codificados por color interactivos, la tabla de métricas por agente y una lista completa de elementos de resultado interactivos que se expanden a la solicitud completa y el resultado de cada agente.', + 'Live counters in Prometheus text-exposition format (v0.0.4): sessions and agents by status, total events, cumulative tokens by kind, connected WebSocket clients, configured remote sources, process uptime and RSS, and build version — so CCAM can be scraped into Prometheus / Grafana. Read-only, and — being under /api — behind the DNS-rebinding Host-header guard and the optional DASHBOARD_TOKEN: a non-loopback scraper (e.g. Prometheus in Docker via host.docker.internal) must be allowlisted with DASHBOARD_ALLOWED_HOSTS or the scrape returns 403 EBADHOST, and must send the token when one is set. A ready-to-run Prometheus + Grafana stack with a pre-provisioned "CCAM — Overview" dashboard lives in monitoring/ (cd monitoring && docker compose up -d; Grafana on port 3000).': + 'Mostradores en vivo en formato de exposición de texto de Prometheus (v0.0.4): sesiones y agentes por estado, eventos totales, tokens acumulativos por tipo, clientes WebSocket conectados, fuentes remotas configuradas, tiempo de actividad del proceso y RSS, y versión de la compilación, para que CCAM pueda ser extraído a Prometheus / Grafana. Solo de lectura, y - estando bajo /api — detrás de la guardia del encabezado de Host de reasignación DNS y el opcional DASHBOARD_TOKEN: un raspador sin retroceso (por ejemplo, Prometheus en Docker a través de host.docker.internal) debe estar en la lista de autorización con DASHBOARD_ALLOWED_HOSTS O el rasguño vuelve 403 EBADHOST, y debe enviar el token cuando se establece uno. Una pila Prometheus + Grafana lista para ejecutarse con un panel de control "CCAM - Visión general" preprovisionado se encuentra en monitoring/ (cd monitoring && docker compose up -d; Grafana en el puerto 3000).', + "Comma-separated extra Host-header names allowed past the DNS-rebinding guard — needed for a non-loopback client or scraper, such as Prometheus in Docker reaching /api/metrics via host.docker.internal; an unlisted host is rejected with 403 EBADHOST": + "Extra separado por coma Host-se permiten nombres de encabezados después de la guardia de reasignación de DNS, necesaria para un cliente o scraper no de bucle, como Prometheus en Docker alcanzando /api/metrics a través de host.docker.internal; un host no listado es rechazado con 403 EBADHOST", + "The entire UI ships in five languages — English, 简体中文, Tiếng Việt, 한국어, and Español — built on i18next + react-i18next with i18next-browser-languagedetector. Coverage is end-to-end: every page, chart tooltip, Settings flow, Workflow narrative, Config Explorer tab, Run page, and the Alerts rule-help tooltips + webhook setup guides are translated. Switch languages from the sidebar's custom language dropdown — the choice persists in localStorage.": + "Toda la interfaz se ofrece en cinco idiomas: English, 简体中文, Tiếng Việt, 한국어 y Español, con i18next + react-i18next e i18next-browser-languagedetector. La cobertura es integral: se traducen todas las páginas, las ayudas de los gráficos, los flujos de Settings, la narrativa de Workflow, la pestaña Config Explorer, la página Run y las ayudas de reglas de Alerts y de configuración de webhooks. Elige el idioma en el menú desplegable personalizado de la barra lateral; la preferencia se conserva en localStorage.", + 'Every alert-rule field has a help tooltip — the event-type, tool-name, and summary-contains fields include example chips of real hook events and built-in tool names. Each webhook provider ships a collapsible step-by-step setup guide linking to the official docs. A one-click "Send test" probe fires a synthetic alert and reports the delivery result inline, and targets can be scoped to specific rules. Fully localized (en / zh / vi / ko / es).': + 'Cada campo de regla de alerta tiene una pestaña de ayuda - los campos tipo de evento, nombre de la herramienta y contiene resumen incluyen ejemplos de chips de eventos de gancho reales y nombres de herramientas integrados. Cada proveedor de webhook envía una guía de configuración paso a paso colapsable que enlaza con los documentos oficiales. Un clic "Enviar prueba" probe emite una alerta sintética y informa el resultado de la entrega en línea, y los objetivos pueden estar restringidos a reglas específicas. Totalmente localizado (es / zh / vi / ko).', "Server-paginated table of every recorded session — each page fetches only its slice so cost computation stays bounded no matter how many sessions exist. Case-insensitive search across id, name, and cwd runs server-side with a 300 ms debounce; the status filter composes with search for precise narrowing. A searchable checkbox project picker supports selecting multiple directories; long paths remain available in full, while compact trigger text keeps the filter bar readable. Sorting uses the same custom dropdown pattern. Each row shows the session's real name (synced live from the transcript — a /rename or claude -n title, else the auto title, else the first user prompt, with a short-ID fallback), status badge, agent count, duration, model, and estimated cost. Click any row to drill into the full session detail view with conversation transcript and agent hierarchy.": - "서버 페이지네이션 테이블은 기록된 모든 세션을 보여줍니다. 각 페이지는 해당 구간만 가져오므로 세션 수와 관계없이 비용 계산 범위가 제한됩니다. id, name, cwd에 대한 대소문자 구분 없는 검색은 300 ms 디바운스와 함께 서버 측에서 실행되며 상태 필터와 조합할 수 있습니다. 검색 가능한 체크박스 프로젝트 선택기로 여러 디렉터리를 고를 수 있고, 긴 경로는 전체를 확인할 수 있으며 간결한 트리거 텍스트가 필터 바를 읽기 쉽게 유지합니다. 정렬도 같은 맞춤 드롭다운 패턴을 사용합니다. 각 행은 세션의 실제 이름(트랜스크립트에서 실시간으로 동기화됨: /rename 또는 claude -n 제목, 없으면 자동 생성된 제목, 그마저도 없으면 첫 사용자 프롬프트, 최종적으로 짧은 ID로 대체), 상태 배지, 에이전트 수, 지속 시간, 모델, 예상 비용을 표시합니다. 행을 클릭하면 대화 트랜스크립트와 에이전트 계층 구조가 포함된 전체 세션 상세 화면으로 이동합니다.", + "Tabla paginada en el servidor de todas las sesiones registradas: cada página obtiene solo su parte, por lo que el cálculo de costes se mantiene acotado sin importar cuántas sesiones haya. La búsqueda sin distinción entre mayúsculas y minúsculas en id, name y cwd se ejecuta del lado del servidor con una espera de 300 ms; el filtro de estado se combina con la búsqueda para acotar con precisión. Un selector de proyectos con casillas y búsqueda permite seleccionar varios directorios; las rutas largas siguen estando disponibles completas, mientras que un texto compacto mantiene legible la barra de filtros. La ordenación usa el mismo patrón de menú desplegable personalizado. Cada fila muestra el nombre real de la sesión (sincronizado en vivo desde la transcripción: un título de /rename o claude -n, de lo contrario el título automático, luego el primer prompt de usuario, con un ID corto como alternativa), la insignia de estado, el número de agentes, la duración, el modelo y el coste estimado. Haz clic en cualquier fila para abrir la vista detallada completa de la sesión, con transcripción de la conversación y jerarquía de agentes.", + 'A 12-tab inspector at /cc-config for everything Claude Code knows about: skills, subagents, slash commands, output styles, plugins, marketplaces, MCP servers, hooks, settings, memory, keybindings, and statusline scripts. The Settings tab leads with a Current configuration summary of the options /config controls — model, verbose, theme, output style, auto-compact, notifications — resolved across scopes. The Memory tab surfaces both the user and project CLAUDE.md files and the per-project file-based memory store — every auto-memory *.md under ~/.claude/projects/<slug>/memory/ (a MEMORY.md index plus one file per remembered fact, often 100+), grouped by project, searchable, and editable — the MEMORY.md index links are clickable and jump to (scroll to + highlight) the matching fact file. Create, edit, and delete the low-risk surfaces — text-file artifacts, per-project auto-memory files, and keybindings.json (structured inline editor) — with mandatory timestamped backups before every write. Plugins, MCP, hooks, and live settings stay read-only with explainer banners and copy-able CLI commands. See the dedicated Config Explorer section for the full tour. Per-plugin contribution breakdowns show author and license.': + 'Un inspector de 12 pestañas en /cc-config para todo lo que Claude Code sabe: habilidades, subagentes, comandos slash, estilos de salida, plugins, mercados, servidores MCP, ganchos, configuraciones, memoria, atajos de teclas y scripts de línea de estado. La pestaña Configuración encabeza con un resumen de la configuración actual de las opciones controladas por /config: modelo, verbose, tema, estilo de salida, compactación automática, notificaciones, resolvidos en todos los ámbitos. La pestaña Memoria muestra tanto los archivos CLAUDE.md del usuario y del proyecto como el almacenamiento de memoria basado en archivos por proyecto: cada .md de memoria automática bajo ~/.claude/projects/<slug>/memory/ (un índice MEMORY.md más un archivo por hecho recordado, a menudo más de 100), agrupados por proyecto, buscables y editable: los enlaces del índice MEMORY.md son clicables y se saltan al archivo de hecho correspondiente (desplázate hacia arriba + resaltar). Crea, edita y elimina las superficies de bajo riesgo: artefactos de archivos de texto, archivos de memoria automática por proyecto y keybindings.json (editor inline estructurado) con copias de seguridad con hora y fecha obligatorias antes de cada escritura. Los plugins, MCP, ganchos y configuraciones en vivo permanecen de solo lectura con banners explicativos y comandos CLI copiables. Consulta la sección dedicada Explorador de Configuración para un recorrido completo. Los desgloses de contribuciones por plugin muestran el autor y la licencia.', + '🧩 Claude Config Explorer · Skills — the Skills tab lists every discovered skill (user, project, and plugin) with its description and source, is searchable across the whole set, and opens any skill file for a safe, timestamp-backed edit': + '🧩 Claude Config Explorer · Habilidades — la pestaña Habilidades enumera todas las habilidades descubiertas (usuario, proyecto y complemento) con su descripción y fuente, se puede buscar en todo el conjunto y abre cualquier archivo de habilidad para una edición segura respaldada por una hora y fecha', + '🛰️ Settings · Remote Data Sources — pull Claude Code activity from other machines over SSH: add sources by destination, test connectivity, sync manually or on a background poller, and switch the global data scope between local, all sources, or a specific machine with per-session source badges': + '🛰️ Configuración · Fuentes de datos remotas — obtenga la actividad de Claude Code de otras máquinas a través de SSH: agregue fuentes por destino, pruebe la conectividad, sincronice manualmente o en un monitor de fondo y cambie el alcance global de los datos entre local, todas las fuentes o una máquina específica con insignias de fuente por sesión', + "SessionStart": "Inicio de sesión", + "UserPromptSubmit": "UserPromptSubmit", + "PreToolUse": "PreToolUse", + "PostToolUse": "PostToolUse", + "Stop": "Detener", + "SubagentStop": "SubagentStop", + "Matched subagent → Completed. Deliberately does not clear the waiting flag — a backgrounded subagent finishing tells us nothing about the human. Also kicks off a fire-and-forget JSONL scan (scanAndImportSubagents) that walks the session's subagents/agent-*.jsonl files, pairs tool_usetool_result blocks by tool_use_id, and emits per-tool PreToolUse + PostToolUse events under each subagent's own agent_id — surfaces tool calls that subagents make internally and which never fire any hooks. The same scan also rebuilds the nested-subagent hierarchy — it repoints each subagent's parent_agent_id to the true spawner recovered from the transcript's Task tool result (toolUseResult.agentId), so subagents that spawn their own subagents nest correctly instead of flattening under main.": + 'Subagente coincidente → Completado. Deliberadamente no borra la marca de espera: que un subagente en segundo plano termine no dice nada sobre la persona. También inicia un análisis JSONL sin bloqueo (scanAndImportSubagents) que recorre los archivos subagents/agent-*.jsonl de la sesión, empareja los bloques tool_usetool_result por tool_use_id y emite eventos por herramienta PreToolUse + PostToolUse con el agent_id de cada subagente. Esto muestra las llamadas de herramientas internas que nunca activan hooks. El mismo análisis también reconstruye la jerarquía de subagentes anidados: vuelve a apuntar el parent_agent_id de cada subagente al generador real recuperado del resultado de la herramienta Task del transcrito (toolUseResult.agentId), para que los subagentes que generan sus propios subagentes se aniden correctamente en vez de quedar al mismo nivel que el principal.', + "Notification": "Notificación", + "Compaction": "Compactación", + "APIError": "Error API", + "Interrupted": "Interrumpido", + "TurnDuration": "Duración de la vuelta", + "SessionEnd": "SessionEnd", + "DASHBOARD_PORT": "DASHBOARD_PORT", + "4820": "4820", + "CLAUDE_DASHBOARD_PORT": "CLAUDE_DASHBOARD_PORT", + "MCP_DASHBOARD_BASE_URL": "MCP_DASHBOARD_BASE_URL", + "http://127.0.0.1:4820": "http://127.0.0.1:4820", + "MCP_TRANSPORT": "MCP_TRANSPORT", + "stdio": "stdio", + "MCP_HTTP_PORT": "MCP_HTTP_PORT", + "8819": "8819", + "MCP_HTTP_HOST": "MCP_HTTP_HOST", + "127.0.0.1": "127.0.0.1", + "DASHBOARD_DB_PATH": "DASHBOARD_DB_PATH", + "data/dashboard.db": "data/dashboard.db", + "DASHBOARD_ALLOWED_HOSTS": "DASHBOARD_ALLOWED_HOSTS", + "(empty)": "(vacío)", + "DASHBOARD_WORKING_IDLE_SECONDS": "DASHBOARD_WORKING_IDLE_SECONDS", + "120": "120", + "DASHBOARD_LIVENESS_PROBE": "DASHBOARD_LIVENESS_PROBE", + "1": "1", + "DASHBOARD_LIVENESS_IDLE_SECONDS": "DASHBOARD_LIVENESS_IDLE_SECONDS", + "60": "60", + "DASHBOARD_SESSION_SYNC_MS": "DASHBOARD_SESSION_SYNC_MS", + "30000": "30000", + "NODE_ENV": "NODE_ENV", + "development": "desarrollo", + "setup": "configuración", + "npm run setup": "npm run setup", + "dev": "dev", + "npm run dev": "npm run dev", + "dev:server": "dev:server", + "npm run dev:server": "npm run dev:server", + "dev:client": "dev:client", + "npm run dev:client": "npm run dev:client", + "build": "construir", + "npm run build": "npm run build", + "start": "start", + "npm start": "npm start", + "install-hooks": "instalar-hooks", + "npm run install-hooks": "npm run install-hooks", + "seed": "semilla", + "npm run seed": "npm run seed", + "import-history": "import-historia", + "npm run import-history": "npm run import-history", + "clear-data": "limpiar-datos", + "npm run clear-data": "npm run clear-data", + "test": "prueba", + "npm test": "npm test", + "test:server": "test:server", + "npm run test:server": "npm run test:server", + "test:client": "test:client", + "npm run test:client": "npm run test:client", + "mcp:install": "mcp:instalar", + "npm run mcp:install": "npm run mcp:install", + "mcp:typecheck": "mcp:typecheck", + "npm run mcp:typecheck": "npm run mcp:typecheck", + "mcp:build": "mcp:build", + "npm run mcp:build": "npm run mcp:build", + "mcp:start": "mcp:start", + "npm run mcp:start": "npm run mcp:start", + "mcp:start:http": "mcp:start:http", + "npm run mcp:start:http": "npm run mcp:start:http", + "mcp:start:repl": "mcp:start:repl", + "npm run mcp:start:repl": "npm run mcp:start:repl", + "mcp:dev": "mcp:dev", + "npm run mcp:dev": "npm run mcp:dev", + "mcp:dev:http": "mcp:dev:http", + "npm run mcp:dev:http": "npm run mcp:dev:http", + "mcp:dev:repl": "mcp:dev:repl", + "npm run mcp:dev:repl": "npm run mcp:dev:repl", + "mcp:docker:build": "mcp:docker:build", + "npm run mcp:docker:build": "npm run mcp:docker:build", + "mcp:podman:build": "mcp:podman:build", + "npm run mcp:podman:build": "npm run mcp:podman:build", + "test:mcp": "test:mcp", + "npm run test:mcp": "npm run test:mcp", + "desktop:install": "desktop:install", + "npm run desktop:install": "npm run desktop:install", + "desktop:build": "desktop:build", + "npm run desktop:build": "npm run desktop:build", + "desktop:dev": "desktop:dev", + "npm run desktop:dev": "npm run desktop:dev", + "desktop:test": "desktop:test", + "npm run desktop:test": "npm run desktop:test", + "desktop:dmg": "desktop:dmg", + "npm run desktop:dmg": "npm run desktop:dmg", + "desktop:dmg:arm64": "desktop:dmg:arm64", + "npm run desktop:dmg:arm64": "npm run desktop:dmg:arm64", + "desktop:dmg:x64": "desktop:dmg:x64", + "npm run desktop:dmg:x64": "npm run desktop:dmg:x64", + "desktop:dmg:universal": "desktop:dmg:universal", + "npm run desktop:dmg:universal": "npm run desktop:dmg:universal", + "desktop:win": "desktop:win", + "npm run desktop:win": "npm run desktop:win", + "desktop:win:portable": "desktop:win:portable", + "npm run desktop:win:portable": "npm run desktop:win:portable", + "build:win-icon": "build:win-icon", + "npm run build:win-icon": "npm run build:win-icon", + "format": "format", + "npm run format": "npm run format", + "format:check": "formato:verificar", + "npm run format:check": "npm run formato:check", + Server: "servidor", + "status · start · repl": + "estado · inicio · repl", + "health · stats · kanban · tail": + "salud · estadísticas · kanban · cola", + "sessions · session <id> · agents · events": + "sessions · session <id> · agents · events", + "analytics · workflows · runs · cost": + "análisis · flujos de trabajo · ejecuciones · costo", + "alerts · alerts ack · rules · webhooks · webhooks test": + "alertas · alertas ack · reglas · webhooks · test de webhooks", + "pricing · pricing set / delete / reset": + "precios · establecer precios / eliminar / restablecer", + "import rescan · import path <dir>": + "import rescan · import path <dir>", + "remote-sources list · remote-sources add · remote-sources test <id> · remote-sources sync [id] · remote-sources rm <id> [--purge]": + "remote-sources list · remote-sources add · remote-sources test <id> · remote-sources sync [id] · remote-sources rm <id> [--purge]", + "doctor · info · export · cleanup · reinstall-hooks · update-check · clear-data --yes · open": + "doctor · info · exportar · limpiar · reinstalar-ganchos · actualizar-verificar · limpiar-datos --sí · abrir", + "server/index.js": "server/index.js", + "server/db.js": "server/db.js", + "server/compat-sqlite.js": "server/compat-sqlite.js", + "server/websocket.js": "server/websocket.js", + "routes/hooks.js": "rutas/hooks.js", + "routes/sessions.js": "rutas/sesiones.js", + "routes/agents.js": "rutas/agentes.js", + "routes/events.js": "rutas/eventos.js", + "routes/stats.js": "rutas/stats.js", + "routes/analytics.js": "rutas/analytics.js", + "routes/pricing.js": "rutas/pricing.js", + "routes/settings.js": "rutas/settings.js", + "System info (DB size, row counts, hook status, server uptime). Data export as one versioned JSON bundle and matching import/restore (POST /api/settings/import via server/lib/data-transfer.js — idempotent, session-atomic, non-destructive; consolidate machines). Session cleanup (abandon stale active sessions, purge old completed sessions). Clear all data. Reset pricing to defaults. Reinstall hooks.": + "Información del sistema (tamaño de la base de datos, número de filas, estado del gancho, tiempo de actividad del servidor). Exportación de datos como un paquete JSON con versión y importación/restauración correspondientes (POST /api/settings/import a través de server/lib/data-transfer.js - idempotente, atómico de sesión, no destructivo; consolidar máquinas). Limpieza de sesiones (abandonar sesiones activas obsoletas, purgar sesiones antiguas completadas). Borrar todos los datos. Restablecer los precios a los valores predeterminados. Reinstalar los ganchos.", + "routes/workflows.js": "rutas/workflows.js", + "idx_agents_session": "idx_agents_session", + agents: "Agentes", + "session_id": "session_id", + "idx_agents_status": "idx_agents_status", + "status": "estado", + "idx_events_session": "idx_events_session", + events: "Eventos", + "idx_events_type": "idx_events_type", + "event_type": "tipo de evento", + "idx_events_created": "idx_events_created", + "created_at DESC": "created_at DESC", + "idx_sessions_status": "idx_sessions_status", + sessions: "sesión", + "idx_sessions_started": "idx_sessions_started", + "started_at DESC": "start_at DESC", + "journal_mode": "journal_mode", + "WAL": "WAL", + "foreign_keys": "clave_externa", + "ON": "EN", + "busy_timeout": "tiempo_de_espera_ocupado", + "5000": "5000", + "Export all data (sessions, agents, events, tokens, workflows, runs, alert rules, pricing) as one versioned JSON download": + "Exporta todos los datos (sesiones, agentes, eventos, tokens, flujos de trabajo, ejecuciones, reglas de alerta, precios) como una descarga JSON versificada", + "Restore an export bundle (multipart file or JSON { path }) — idempotent, non-destructive; consolidate machines": + "Restaurar un paquete de exportación (archivo file multipart o JSON { path }) - idempotente, no destructivo; consolidar máquinas", + "ws://localhost:4820/ws": "ws://localhost:4820/ws", + "<proj>/<sid>.jsonl": "<proj>/<sid>.jsonl", + "<proj>/<sid>/subagents/agent-*.jsonl": + "<proj>/<sid>/subagents/agent-*.jsonl", + "<proj>/subagents/<sid>/agent-*.jsonl": + "<proj>/subagents/<sid>/agent-*.jsonl", + "<root>/<sid>.jsonl": "<root>/<sid>.jsonl", + ".zip, .tar, .tar.gz, .tgz": + ".zip, .tar, .tar.gz, .tgz", + "any.jsonl.gz": "any.jsonl.gz", + "CCAM_IMPORT_MAX_BYTES": "CCAM_IMPORT_MAX_BYTES", + "1 GB": "1 GB", + "CCAM_IMPORT_MAX_FILES": "CCAM_IMPORT_MAX_FILES", + "CCAM_IMPORT_MAX_EXTRACT_BYTES": "CCAM_IMPORT_MAX_EXTRACT_BYTES", + "4 GB": "4 GB", + '🛰️ Settings → Remote Data Sources — add machines by SSH destination, test connectivity, sync on demand or on a background schedule, and narrow the whole app with the global data-scope selector': + '🛰️ Configuración → Fuentes de datos remotas — agrega máquinas por destino SSH, prueba la conectividad, sincroniza bajo demanda o en un horario en segundo plano, y reduce toda la aplicación con el selector de alcance de datos global', + "DASHBOARD_REMOTE_SYNC_MS": "DASHBOARD_REMOTE_SYNC_MS", + "15000": "15000", + "DASHBOARD_REMOTE_SYNC_TIMEOUT_MS": + "DASHBOARD_REMOTE_SYNC_TIMEOUT_MS", + "600000": "600000", + "DASHBOARD_REMOTE_TEST_TIMEOUT_MS": + "DASHBOARD_REMOTE_TEST_TIMEOUT_MS", + "DASHBOARD_REMOTE_ACTIVE_WINDOW_MS": + "DASHBOARD_REMOTE_ACTIVE_WINDOW_MS", + "mcp/src/": "mcp/src/", + "mcp/build/": "mcp/build/", + "mcp/README.md": "mcp/README.md", + "mcp/src/transports/": "mcp/src/transports/", + "mcp/src/ui/": "mcp/src/ui/", + "npm run mcp:start|start:http|start:repl|dev|dev:http|dev:repl": + "npm run mcp:start|start:http|start:repl|dev|dev:http|dev:repl", + "CLAUDE.md, .claude/rules/": + "CLAUDE.md, .claude/rules/", + ".claude/skills/": ".claude/habilidades/", + ".claude/agents/": ".claude/agents/", + "AGENTS.md, .codex/rules/default.rules": + "AGENTES.md, .codex/rules/default.rules", + ".codex/skills/": ".codex/habilidades/", + ".codex/agents/": ".codex/agents/", + "scripts/hook-handler.js": "scripts/hook-handler.js", + "scripts/install-hooks.js": "scripts/install-hooks.js", + "scripts/import-history.js": "scripts/import-history.js", + "server/routes/import.js": "server/routes/import.js", + "server/lib/archive.js": "server/lib/archive.js", + "scripts/seed.js": "scripts/seed.js", + "scripts/clear-data.js": "scripts/clear-data.js", + "ccam-analytics": "ccam-analytics", + "session-report, cost-breakdown, usage-trends, productivity-score": + "Reporte de sesión, desglose de costos, tendencias de uso, puntuación de productividad", + "analytics-advisor": "Asesor de análisis", + "ccam-stats": "ccam-stats", + "ccam-cost-guard": "ccam-cost-guard", + "budget-set, spend-forecast, cost-alert, model-savings, daily-budget-check": + "Establecer presupuesto, pronosticar gastos, alertas de costos, ahorros de modelos, verificación diaria del presupuesto", + "budget-sentinel": "Sentinela del presupuesto", + "ccam-productivity": "ccam-productividad", + "daily-standup, weekly-report, sprint-summary, workflow-optimizer": + "Standup diario, informe semanal, resumen de sprint, optimizador de flujo de trabajo", + "productivity-coach": "Entrenador de productividad", + "ccam-devtools": "ccam-devtools", + "session-debug, hook-diagnostics, data-export, health-check": + "Depuración de sesiones, diagnóstico de enlaces, exportación de datos, verificación de salud", + "issue-triager": "Triagista de problemas", + "ccam-doctor, ccam-export": + "ccam-doctor, ccam-export", + "ccam-insights": "insights de ccam", + "pattern-detect, anomaly-alert, optimization-suggest, session-compare": + "Detección de patrones, alerta de anomalías, sugerencias de optimización, comparación de sesiones", + "insights-advisor": "Asesor de conocimientos", + "ccam-sessions": "sesiones ccam", + "session-search, session-timeline, transcript-replay, cwd-rollup, session-cleanup": + "Búsqueda de sesiones, cronología de sesiones, reproducción de transcripciones, acumulación de directorio actual, limpieza de sesiones", + "session-investigator": "Investigador de sesión", + "ccam-workflows": "ccam-workflows", + "dag-map, delegation-audit, concurrency-report, error-propagation, fleet-runs": + "Mapa dag, auditoría de delegación, informe de concurrencia, propagación de errores, ejecuciones de flota", + "orchestration-analyst": "Analista de orquestación", + "ccam-quality": "Calidad ccam", + "error-scan, api-error-report, hook-failure-audit, slo-check, regression-alert": + "Escaneo de errores, informe de errores API, auditoría de fallos de enlaces, verificación de SLA, alerta de regresión", + "reliability-engineer": "Ingeniero de fiabilidad", + "ccam-config": "ccam-config", + "config-audit, memory-review, skill-inventory, mcp-audit, hook-inventory": + "Auditoría de configuración, revisión de memoria, inventario de habilidades, auditoría de mcp, inventario de ganchos", + "config-auditor": "Auditor de configuración", + "ccam-dashboard": "Panel de control ccam", + "dashboard-status, quick-stats": "Estado del panel de control, estadísticas rápidas", + "thinking_blocks, turn_count, total_turn_duration_ms, usage_extras (service_tier, speed, inference_geo)": + "thinking_blocks, turn_count, total_turn_duration_ms, usage_extras (tier_de_servicio, velocidad, inference_geo)", + "PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, Notification, Compaction, APIError, TurnDuration": + "PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, Notification, Compaction, APIError, TurnDuration", + Model: "modelo", + "data.model.display_name": "data.model.display_name", + User: "usuario", + "$USERNAME / $USER": "$USERNAME / $USER", + "data.workspace.current_dir": "data.workspace.current_dir", + "git symbolic-ref --short HEAD": "git symbolic-ref --short HEAD", + "data.context_window.used_percentage": + "data.context_window.used_percentage", + "data.context_window.current_usage": + "data.context_window.current_usage", + "data.cost.total_cost_usd": "data.cost.total_cost_usd", + '🧰 Claude Config Explorer — the /cc-config page: 12 tabs (skills, subagents, slash commands, output styles, plugins, marketplaces, MCP servers, hooks, keybindings, settings, memory), a scope filter (user / project / all), search, and safe edit affordances on the low-risk surfaces': + '🧰 Claude Config Explorer — la página /cc-config: 12 pestañas (habilidades, subagentes, comandos de guión, estilos de salida, complementos, mercados, servidores MCP, ganchos, asociaciones de teclas, configuraciones, memoria), un filtro de alcance (usuario / proyecto / todo), búsqueda y posibilidades de edición segura en superficies de bajo riesgo', + '🧩 Claude Config Explorer · Skills — the Skills tab lists every discovered skill (user, project, and plugin) with description and source, is searchable, and opens any SKILL.md for a timestamp-backed edit via the shared editor modal': + '🧩 Claude Config Explorer · Habilidades — la pestaña Habilidades enumera todas las habilidades descubiertas (usuario, proyecto y complemento) con descripción y fuente, es buscable y abre cualquier SKILL.md para una edición respaldada por una hora y fecha a través del modal del editor compartido', + "A first-class configuration inspector at /cc-config that reads every surface Claude Code knows about — skills, subagents, slash commands, output styles, plugins, marketplaces, MCP servers, hooks, settings, memory, keybindings, and statusline scripts — from the same on-disk layout the CLI uses. The Overview tab summarizes counts and filesystem roots; every other tab drills into one surface with search, scope filtering (user / project / all), and — where safe — create / edit / delete with mandatory timestamped backups before every mutation. A cc-watcher on CLAUDE_HOME plus cc_config_changed WebSocket messages keep the page live when files change outside the dashboard.": + "Un inspector de configuración de primera clase en /cc-config que lee todas las superficies sobre las que Claude Code tiene conocimiento, como habilidades, subagentes, comandos de guión, estilos de salida, plugins, mercados, servidores MCP, ganchos, configuraciones, memoria, asociaciones de teclas y scripts de línea de estado, desde el mismo diseño en disco que utiliza la CLI. La pestaña Resumen resume los conteos y las raíces del sistema de archivos; cada otra pestaña profundiza en una superficie con búsqueda, filtrado de alcance (usuario / proyecto / todo) y, cuando sea seguro, crea / edita / elimina con copias de seguridad obligatorias con hora y fecha antes de cada mutación. Un cc-watcher en CLAUDE_HOME más mensajes WebSocket de cc_config_changed mantienen la página activa cuando los archivos cambian fuera del panel de control.", + "Skills, Subagents, Slash commands, Output styles, Plugins (with per-plugin contributes counts and plugin.json metadata), Marketplaces, MCP servers, Hooks (plus ~/.claude/hooks/ script listing), Keybindings, Settings (Current configuration summary + per-file JSON), and Memory (user/project CLAUDE.md + per-project auto-memory). Statusline config and script previews live under Settings.": + "Habilidades, Subagentes, Comandos de corte, Estilos de salida, Complementos (con contadores de contributes por complemento y metadatos de plugin.json), Mercados, Servidores MCP, Ganchos (además de la lista de scripts ~/.claude/hooks/), Asignaciones de teclas, Configuración (resumen de la configuración actual + JSON por archivo) y Memoria (CLAUDE.md del usuario/proyecto + memoria automática por proyecto). La configuración de la línea de estado y las vistas previas de los scripts están disponibles en Configuración.", + 'PUT / DELETE /api/cc-config/file handles skills, agents, commands, output-styles, CLAUDE.md, and per-project auto-memory (scope: "auto-memory"). Writes are atomic (temp file + rename), names are validated against a strict regex, resolved paths are containment-checked, and content is capped at 256 KiB. Every overwrite or delete creates a backup under cc-config-backups/ — outside the directories Claude Code scans — so deleted artifacts cannot reappear as ghost entries.': + 'PUT / DELETE /api/cc-config/file maneja habilidades, agentes, comandos, estilos de salida, CLAUDE.md y memoria automática por proyecto (scope: "auto-memory"). Las escrituras son atómicas (archivo temporal + renombrar), los nombres se validan contra una regla de expresión regular estricta, los rutas resueltas se verifican contra el contenedor y el contenido se limita a 256 KiB. Cada sobrescritura o eliminación crea una copia de seguridad en cc-config-backups/ — fuera de los directorios que Claude Code escanea — por lo que los artefactos eliminados no pueden reaparecer como entradas fantasma.', + "The Keybindings tab includes a structured inline editor for ~/.claude/keybindings.json. Add or remove contexts and bindings, edit keys and actions in place, and save via PUT /api/cc-config/keybindings. The server read-modify-writes the file: top-level metadata ($schema, $docs) is preserved, duplicate contexts/keys are rejected, and the file is backed up first. Unlike settings.json, the live CLI does not rewrite keybindings mid-session, so dashboard edits are safe.": + "La pestaña de Asignaciones de teclas incluye un editor estructurado inline para ~/.claude/keybindings.json. Agregue o elimine contextos y asignaciones, edite teclas y acciones en el lugar, y guarde a través de PUT /api/cc-config/keybindings. El servidor lee, modifica y escribe el archivo: se preservan los metadatos de nivel superior ($schema, $docs), se rechazan los contextos/teclas duplicados y el archivo se copia de seguridad primero. A diferencia de settings.json, la CLI en vivo no reescribe las asignaciones de teclas en medio de la sesión, por lo que las ediciones del panel de control son seguras.", + "The Memory tab surfaces user + project CLAUDE.md and the per-project file-based memory store — every *.md under ~/.claude/projects/<slug>/memory/ (a MEMORY.md index plus one file per remembered fact, often 100+). Files are grouped by project in collapsible sections, searchable, and editable. Clickable index links in MEMORY.md jump to (scroll + highlight) the matching fact file.": + "La pestaña Memoria muestra el usuario + proyecto CLAUDE.md y el almacenamiento de memoria basado en archivos por proyecto, todos los *.md bajo ~/.claude/projects/<slug>/memory/ (un índice MEMORY.md más un archivo por hecho recordado, a menudo más de 100). Los archivos se agrupan por proyecto en secciones colapsables, buscables y editable. Los enlaces de índice clicables en MEMORY.md saltan al archivo de hecho correspondiente (desplazamiento + resaltado) para buscar.", + "Plugins, MCP servers, hooks-in-settings, and live settings.json files are intentionally not writable from the dashboard — they race with the running claude CLI. Those tabs show explainer banners with copy-able claude plugin …, claude mcp …, and claude config … commands instead of edit buttons. Secret-like settings keys are redacted server-side.": + "Los complementos, los servidores MCP, los ganchos configurados y los archivos settings.json en vivo no se pueden editar intencionadamente desde el panel de control; compiten con la CLI claude en ejecución. Esas pestañas muestran banners explicativos con comandos claude plugin …, claude mcp … y claude config … que se pueden copiar en lugar de botones de edición. Las claves de configuración similares a secretos se ocultan en el servidor.", + "Successful mutations broadcast cc_config_changed over the WebSocket so every open /cc-config tab refetches without polling. A filesystem watcher on CLAUDE_HOME (cc-watcher.js) detects external edits (e.g. you changed a skill in your editor) and triggers the same refresh path. The Backups modal lists every timestamped copy and builds mv restore commands.": + "Las mutaciones exitosas transmiten cc_config_changed a través de WebSocket, por lo que cada pestaña /cc-config abierta se actualiza de nuevo sin consultar. Un observador de sistema de archivos en CLAUDE_HOME (cc-watcher.js) detecta ediciones externas (por ejemplo, has cambiado una habilidad en tu editor) y activa el mismo camino de actualización. La modalidad Copias de seguridad enumera todas las copias con fecha y hora y construye comandos de restauración mv.", + "How to change (if read-only)": "Cómo cambiar (si es de solo lectura)", + "Skills · Subagents · Commands · Output styles": + "Habilidades · Subagentes · Comandos · Estilos de salida", + "Create / edit / delete (PUT/DELETE /file)": + "Crear / editar / eliminar (PUT/DELETE /file)", + "CLAUDE.md · auto-memory *.md": + "CLAUDE.md · memoria automática *.md", + "keybindings.json": "keybindings.json", + "Structured inline editor (PUT /keybindings)": + "Editor inline estructurado (PUT /keybindings)", + "Plugins · marketplaces": "Plugins · mercados", + "Read-only inventory": "Inventario de lectura única", + "claude plugin install|uninstall …": + "instalar o desinstalar el complemento claudie...", + "MCP servers": "Servidores MCP", + "claude mcp add|remove …": "claude mcp agregar|eliminar ...", + "Hooks · settings.json": "Ganchos · settings.json", + "Read-only (redacted secrets)": "Solo de lectura (secretos redactados)", + "claude config · /config · $EDITOR": + "claude config · /config · $EDITOR", + "Filesystem roots + aggregate counts across every surface": + "Raíces del sistema de archivos + contadores agregados en todas las superficies", + "Per-tab discovery lists; most accept ?scope=user|project|all": + "Listas de descubrimiento por tabla; la mayoría acepta ?scope=user|project|all", + "Single-file viewer (path-contained to allowed roots)": + "Visualizador de archivo único (ruta contenida en las raíces permitidas)", + "Create/overwrite a text artifact — backs up first, atomic write": + "Crear/sobreescribir un artefacto de texto: haga una copia de seguridad primero, escritura atómica", + "Backup-then-delete (skill dirs backed up whole)": + "Hacer una copia de seguridad y luego eliminar (copias de seguridad completas de las carpetas de habilidades)", + "Structured overwrite of keybindings.json — preserves metadata, backs up first": + "Sobrascritura estructurada de keybindings.json — preserva los metadatos, hace una copia de seguridad primero", + "Timestamped backup listing for the recovery modal": + "Lista de copias de seguridad con hora y fecha para la modalidad de recuperación", + "Backups live outside Claude Code's scan paths": + "Las copias de seguridad están en vivo fuera de los caminos de escaneo de Claude Code", + "Every mutation writes a timestamped copy under <root>/cc-config-backups/<type>/ (or <memory-dir>/.cc-config-backups/auto-memory/ for per-project memory files) before touching the original. Skill folders are copied whole so bundled assets survive in the backup. The UI's Backups modal shows every copy and prints a one-line mv restore command.": + "Cada mutación escribe una copia con fecha y hora bajo <root>/cc-config-backups/<type>/ (o <memory-dir>/.cc-config-backups/auto-memory/ para archivos de memoria por proyecto) antes de tocar el original. Las carpetas de habilidades se copian enteras, por lo que los activos empaquetados sobreviven en la copia de seguridad. La modalidad Copias de seguridad de la interfaz de usuario muestra cada copia e imprime un comando de restauración mv de una línea.", + "Do not edit settings.json from here": "No edites settings.json desde aquí", + "The live claude process rewrites settings.json and ~/.claude.json constantly (model changes, plugin toggles, MCP registration). A dashboard write would race and lose state — or worse, break hook ingestion. Use claude config set …, /config, or hand-edit only when no claude process is running.": + "El proceso claude en vivo reescribe constantemente settings.json y ~/.claude.json (cambios de modelo, activación y desactivación de complementos, registro de MCP). Una escritura en el panel de control podría competir y perder el estado, o peor aún, romper la ingestión de ganchos. Utilice claude config set …, /config o edite manualmente solo cuando no esté ejecutando ningún proceso claude.", + Slack: "ausencia de tensión", + Discord: "discordancia", + "Microsoft Teams": "Microsoft Teams", + "Google Chat": "Chat de Google", + "Mattermost · Rocket.Chat": "Mattermost · Rocket.Chat", + Telegram: "telegrama", + PagerDuty: "PagerDuty", + Opsgenie: "Opsgenie", + "Splunk On-Call": "Splunk en servicio de emergencia", + "Zapier · Make · n8n · Pipedream · generic": "Zapier · Hacer · n8n · Pipedream · genérico", + "GET /api/updates/status": "GET /api/updates/status", + "POST /api/updates/check": "POST /api/updates/check", + "http://localhost:5173": "http://localhost:5173", + "http://localhost:4820": "http://localhost:4820", + "~/.claude:/root/.claude:ro": "~/.claude:/root/.claude:ro", + "agent-monitor-data:/app/data": "agent-monitor-data:/app/data", + "server-deps": "dependencias del servidor", + "client-build": "construcción del cliente", + "runtime": "tiempo de ejecución", + "< 200ms": "< 200 ms", + "< 50ms": "< 50 ms", + "200 KB / 63 KB gzip": "200 KB / 63 KB gzip", + "CSS: 17 KB / 4 KB gzip": "CSS: 17 KB / 4 KB gzip", + "< 5ms": "< 5 ms", + "~50,000 inserts/sec": "~50.000 inserciones/seg.", + "~1M rows": "~1M filas", + "~30 MB": "~30 MB", + "~15 MB": "~15 MB", + Area: "área", + Approach: "planteamiento", + "SQLite (better-sqlite3 / node:sqlite)": + "SQLite (better-sqlite3 / node:sqlite)", + "Express": "Expresar", + "ws": "ws", + "React 18": "React 18", + "Vite 6": "Vite 6", + "Tailwind CSS": "Tailwind CSS", + "React Router 6": "React Router 6", + "Lucide React": "Lucide React", + "TypeScript Strict": "TypeScript estricto", + "D3.js + d3-sankey": "D3.js + d3-sankey", + "Python (statusline)": "Python (statusline)", + README: "LICENCIA DE USO", }, plain: { + es: { + "ccam CLI": "CLI de ccam", + "12 discovery tabs": "12 pestañas de descubrimiento", + "Safe mutations": "Modificaciones seguras", + "Keybindings editor": "Editor de combinaciones de teclas", + "Memory store": "Almacén de memoria", + "Read-only by design": "Solo lectura por diseño", + "Live refresh": "Actualización en tiempo real", + "Editable vs read-only": "Editable frente a solo lectura", + "API endpoints": "Puntos finales de la API", + "Four Grafana boards": "Cuatro paneles de Grafana", + "Prometheus console": "Consola de Prometheus", + "Recording rules": "Reglas de registro", + "Scrape & auth guard": "Extracción y protección de autenticación", + "Remote Data Sources": "Fuentes de datos remotas", + "How It Works": "Cómo funciona", + Setup: "configuración", + "Data Scope": "Ámbito de datos", + "Live Status": "Estado en vivo", + "Security Model": "Modelo de seguridad", + "API Endpoints": "Puntos finales de API", + Metrics: "métrica", + "WebSocket Events": "Eventos WebSocket", + CLI: "CLI", + "System Overview": "Visión general del sistema", + "What's Included": "Qué está incluido", + "Live Dashboard": "Panel de control en vivo", + "Kanban Board": "Tablero Kanban", + "Sessions Table": "Tabla de sesiones", + "Session Detail": "Detalles de la sesión", + "Alerts & Webhooks": "Alertas y Webhooks", + "Desktop App (macOS & Windows)": "Aplicación para escritorio (macOS y Windows)", + "Activity Feed": "Feed de actividad", + Analytics: "análisis", + "WebSocket Push": "Push WebSocket", + Statusline: "Línea de estado", + "History Import": "Importación de historial", + "Transcript Cache": "Cache de transcripciones", + "Bounded Cache Memory": "Memoria de caché limitada", + "Constant-Time Sweep": "Recorrido de tiempo constante", + "Subagent Hierarchy": "Jerarquía de subagentes", + "Cost Tracking": "Seguimiento de costos", + "Settings & Management": "Configuración y gestión", + "Local MCP Server": "Servidor MCP local", + "Claude + Codex Extensions": "Extensión de Claude + Codex", + "Workflow Graphs": "Gráficos de flujo de trabajo", + "Workflow Analytics": "Análisis de flujo de trabajo", + "Session Drill-In": "Entrenamiento de la sesión", + "Browser Notifications": "Notificaciones del navegador", + "Docker Deployment": "Implementación de Docker", + "Plugin Marketplace": "Mercado de complementos", + "Run Claude": "Corra Claude", + "Claude Config Explorer": "Explorador de configuración de Claude", + "Responsive Design": "Diseño Responsivo", + "Concurrency Timeline": "Cronología de concurrencia", + "VS Code Extension": "Extensión de VS Code", + "Error Propagation Map": "Mapa de propagación de errores", + "Progressive Web App": "Aplicación web progresiva", + "Fresh-by-Default Caching": "Caching fresco por defecto", + "Auto-Reload on Update": "Recarga automática en la actualización", + Screenshots: "Capturas de pantalla", + "GitHub Star History": "Historial de estrellas de GitHub", + "Hook Events Captured": "Eventos de captura de gancho", + "Quick Start": "Inicio rápido", + Clone: "clon", + Install: "instalar", + Start: "inicio", + "Use Claude": "Utiliza Claude", + "Alternative: Docker / Podman": "Alternativa: Docker / Podman", + "Optional: Enable MCP and Agent Extensions": + "Opcional: Habilitar las extensiones MCP y Agent", + Verification: "constatación", + Configuration: "configuración", + "Environment Variables": "Variables del entorno", + "Hook Configuration": "Configuración del gancho", + "Scripts Reference": "Referencia de scripts", + "System Architecture": "Arquitectura del sistema", + "Agent State Machine": "Máquina de Estado del Agente", + "Session State Machine": "Máquina de estado de sesión", + "Data Flow": "Flujo de datos", + "Event Ingestion Pipeline": "Pipeline de ingestión de eventos", + "Client Data Loading Pattern": "Patrón de carga de datos del cliente", + "Server Architecture": "Arquitectura del servidor", + "Server Modules": "Módulos del servidor", + "Client Architecture": "Arquitectura del cliente", + "Client Routes": "Rutas del cliente", + "Key Client Modules": "Módulos clave del cliente", + "PWA & Service Worker": "PWA y trabajador de servicio", + "State Management": "Gestión estatal", + "Database Design": "Diseño de bases de datos", + Indexes: "Índices", + "SQLite Configuration": "Configuración de SQLite", + "API Reference": "Referencia de API", + Health: "bienestar", + Sessions: "sesión", + Agents: "Agentes", + "Events, Stats, Analytics": "Eventos, estadísticas, análisis", + "Hooks Ingestion": "Ingestión de ganchos", + Pricing: "fijación de precios", + Settings: "Configuración", + "Import History": "Historial de importaciones", + Workflows: "Flujos de trabajo", + Alerts: "Alertas", + Webhooks: "Webhooks", + "WebSocket Protocol": "Protocolo WebSocket", + "Message Envelope": "Envelope de mensaje", + "Hook Integration": "Integración de ganchos", + "Hook Handler Design": "Diseño del manipulador de ganchos", + "Hook Installation Flow": "Flujo de instalación del gancho", + "Import Pipeline": "Pipeline de importación", + "Three Modes, One Pipeline": "Tres modos, un oleoducto", + "Upload Request Sequence": "Secuencia de solicitud de carga de archivos", + "Idempotence & Cost Accuracy": "Idempotencia y precisión de costos", + "Supported Source Layouts": "Diseños de fuentes compatibles", + "Safety Model": "Modelo de seguridad", + "WebSocket Progress Events": "Eventos de progreso de WebSocket", + "MCP & Agent Extensions": "Extensión de MCP y agente", + "Local MCP Server Runtime": "Tiempo de ejecución del servidor MCP local", + "Agent Extension Layout": "Diseño de extensión del agente", + "Root Helper Scripts": "Scripts de ayuda para root", + Installation: "instalación", + "Available Plugins": "Plugins disponibles", + "Skill Usage Examples": "Ejemplos de uso de habilidades", + "CLI Tools": "Herramientas CLI", + "Plugin Architecture": "Arquitectura de plugins", + "Data Model Reference": "Referencia del modelo de datos", + "Statusline Utility": "Herramienta de línea de estado", + "Detailed Components": "Componentes detallados", + "In-Process Architecture": "Arquitectura en proceso", + "What It Adds": "Lo que agrega", + "Menu-Bar / Notification-Area (Tray) Icon": + "Icono de Barra de Menú / Área de Notificaciones ( bandeja)", + "Native Application Menu": "Menú de aplicaciones nativas", + "Auto-Start at Login": "Inicio automático al iniciar sesión", + "Close Hides, Server Stays Up": "Cerrar Oculta, el Servidor Se Mantiene Activado", + "Runs Alongside the Web Dashboard": "Funciona junto al panel de control web", + "Single-Instance Lock": "Bloqueo de instancia única", + "First-Boot Bootstrap": "Bootstrap de arranque inicial", + "Data Persistence & CLI Reliability": "Persistencia de datos y fiabilidad de la CLI", + "Port Discovery": "Descubrimiento del puerto", + "How to Get It": "Cómo conseguirlo", + "Option A — download the latest GitHub Release (recommended)": + "Opción A: descargar la última versión de GitHub (recomendada)", + "Option B — per-commit CI artifact": "Opción B: artefacto CI por compromiso", + "Option C — build locally": "Opción C: construir localmente", + macOS: "macOS", + "Open the DMG": "Abrir el DMG", + "Drag to Applications": "Arrastrar a Aplicaciones", + "Clear Quarantine": "Liberación de cuarentena", + Launch: "lanzamiento", + Windows: "ventana", + "Run the Installer": "Ejecutar el instalador", + "Clear SmartScreen": "Borrar SmartScreen", + "Settings Page": "Página de ajustes", + "Model Pricing": "Precio del modelo", + "Data Management": "gestión de datos", + "Data Export": "Exportación de datos", + "System Health": "Estado de salud del sistema", + "Notification Preferences": "Preferencias de notificaciones", + "Rule types": "Tipos de reglas", + "Evaluation engine": "Motor de evaluación", + "14 first-class providers": "14 proveedores de primera clase", + "Delivery engine": "Motor de entrega", + Security: "seguridad", + "Guided setup": "Configuración guiada", + "Provider payloads": "Carga útil del proveedor", + "Update Notifier": "Notificador de actualización", + "Non-Blocking Detection": "Detección no bloqueante", + "5-min Scheduler": "Programador de 5 minutos", + "Situation-Aware Command": "Comando con conciencia de la situación", + "Two UI Surfaces": "Dos superficies de interfaz de usuario", + "Soft Failure Semantics": "Semántica de fallos suaves", + "Dismissal Memory": "Memoria de despido", + "API Surface": "Superficie de la API", + "Connection Status": "Estado de la conexión", + "Internationalization (i18n)": "Internacionalización (i18n)", + "Namespaced resources": "Recursos con espacio de nombres", + "Detection & fallback": "Detección y fallback", + "Locale-aware formatting": "Formato con conciencia del lugar", + "Technical terms preserved": "Términos técnicos preservados", + "🐾 Tabby — Reactive Cat Companion": "🐾 Tabby — Compañero de gato reactivo", + "Reactive Mascot — Eight Moods": "Mascota Reactiva — Ocho Ámbitos de Estilo", + "Auto-Surface Speech Bubbles": "Bolas de diálogo de voz automáticas en la superficie", + "The ⌘B Panel": "El panel ⌘B", + "Ask → Run Claude Handoff": "Pregunta → Ejecuta Claude Handoff", + "Accessibility & Resilience": "Accesibilidad y resiliencia", + "Deployment Modes": "Modos de despliegue", + "Container Runtime (Docker / Podman)": "Tiempo de ejecución del contenedor (Docker / Podman)", + "Docker / Podman": "Docker / Podman", + "Plain Docker / Podman (no Compose)": "Docker / Podman simple (sin Compose)", + "Volume Mounts": "Montajes de volumen", + "Multi-Stage Build": "Construcción de múltiples etapas", + "Performance Characteristics": "Características del rendimiento", + Troubleshooting: "localización y corrección de fallos", + "No sessions appearing after starting Claude Code": + "No aparecen sesiones después de iniciar Claude Code", + "Check 1 — Is the server running?": "Verificación 1: ¿Está funcionando el servidor?", + "Check 2 — Are hooks installed?": "Verificación 2: ¿Se han instalado los ganchos?", + "Check 3 — Start a new Claude Code session": + "Verificar 3 - Iniciar una nueva sesión de Claude Code", + "Check 4 — Is Node.js in PATH?": "Verificar 4: ¿Está Node.js en PATH?", + "Common Issues": "Problemas comunes", + "Technology Choices": "Opciones tecnológicas", + "Workflow Runs": "Ejecuciones del flujo de trabajo", + }, zh: { "Remote Data Sources": "远程数据源", "How It Works": "工作原理", diff --git a/wiki/index.html b/wiki/index.html index c866c52f..1499eaa6 100644 --- a/wiki/index.html +++ b/wiki/index.html @@ -77,7 +77,7 @@ - +