cli-claw-kit 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +245 -0
- package/config/default-groups.json +1 -0
- package/config/global-agents-md.template.md +37 -0
- package/config/mount-allowlist.json +11 -0
- package/container/Dockerfile +160 -0
- package/container/agent-runner/dist/.tsbuildinfo +1 -0
- package/container/agent-runner/dist/agent-definitions.js +22 -0
- package/container/agent-runner/dist/channel-prefixes.js +16 -0
- package/container/agent-runner/dist/codex-config.js +29 -0
- package/container/agent-runner/dist/image-detector.js +96 -0
- package/container/agent-runner/dist/index.js +2587 -0
- package/container/agent-runner/dist/mcp-tools.js +1076 -0
- package/container/agent-runner/dist/stream-event.types.js +5 -0
- package/container/agent-runner/dist/stream-processor.js +867 -0
- package/container/agent-runner/dist/types.js +6 -0
- package/container/agent-runner/dist/utils.js +115 -0
- package/container/agent-runner/package.json +36 -0
- package/container/agent-runner/prompts/security-rules.md +31 -0
- package/container/agent-runner/src/agent-definitions.ts +27 -0
- package/container/agent-runner/src/channel-prefixes.ts +16 -0
- package/container/agent-runner/src/codex-config.ts +40 -0
- package/container/agent-runner/src/image-detector.ts +116 -0
- package/container/agent-runner/src/index.ts +3107 -0
- package/container/agent-runner/src/mcp-tools.ts +1295 -0
- package/container/agent-runner/src/stream-event.types.ts +10 -0
- package/container/agent-runner/src/stream-processor.ts +932 -0
- package/container/agent-runner/src/types.ts +75 -0
- package/container/agent-runner/src/utils.ts +114 -0
- package/container/agent-runner/tsconfig.json +17 -0
- package/container/build.sh +28 -0
- package/container/entrypoint.sh +64 -0
- package/container/skills/agent-browser/SKILL.md +159 -0
- package/container/skills/install-skill/SKILL.md +64 -0
- package/container/skills/post-test-cleanup/SKILL.md +121 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/agent-output-parser.js +459 -0
- package/dist/app-root.js +52 -0
- package/dist/assistant-meta-footer.js +1 -0
- package/dist/auth.js +91 -0
- package/dist/billing.js +694 -0
- package/dist/channel-prefixes.js +16 -0
- package/dist/cli.js +86 -0
- package/dist/commands.js +79 -0
- package/dist/config.js +120 -0
- package/dist/container-runner.js +981 -0
- package/dist/daily-summary.js +210 -0
- package/dist/db.js +3683 -0
- package/dist/dingtalk.js +1347 -0
- package/dist/feishu-markdown-style.js +97 -0
- package/dist/feishu-streaming-card.js +1875 -0
- package/dist/feishu.js +1628 -0
- package/dist/file-manager.js +270 -0
- package/dist/group-queue.js +1070 -0
- package/dist/group-runtime.js +35 -0
- package/dist/host-workspace-cwd.js +85 -0
- package/dist/im-channel.js +384 -0
- package/dist/im-command-utils.js +142 -0
- package/dist/im-downloader.js +45 -0
- package/dist/im-manager.js +527 -0
- package/dist/im-utils.js +53 -0
- package/dist/image-detector.js +96 -0
- package/dist/index.js +5828 -0
- package/dist/logger.js +22 -0
- package/dist/mcp-utils.js +66 -0
- package/dist/message-attachments.js +69 -0
- package/dist/message-notifier.js +36 -0
- package/dist/middleware/auth.js +85 -0
- package/dist/mount-security.js +315 -0
- package/dist/permissions.js +67 -0
- package/dist/project-memory.js +6 -0
- package/dist/provider-pool.js +189 -0
- package/dist/qq.js +826 -0
- package/dist/reset-admin.js +42 -0
- package/dist/routes/admin.js +543 -0
- package/dist/routes/agent-definitions.js +241 -0
- package/dist/routes/agents.js +533 -0
- package/dist/routes/auth.js +675 -0
- package/dist/routes/billing.js +490 -0
- package/dist/routes/browse.js +210 -0
- package/dist/routes/bug-report.js +387 -0
- package/dist/routes/config.js +1868 -0
- package/dist/routes/files.js +671 -0
- package/dist/routes/groups.js +1367 -0
- package/dist/routes/mcp-servers.js +320 -0
- package/dist/routes/memory.js +523 -0
- package/dist/routes/monitor.js +307 -0
- package/dist/routes/skills.js +777 -0
- package/dist/routes/tasks.js +509 -0
- package/dist/routes/usage.js +64 -0
- package/dist/routes/workspace-config.js +458 -0
- package/dist/runtime-build.js +112 -0
- package/dist/runtime-command-handler.js +189 -0
- package/dist/runtime-command-registry.js +1 -0
- package/dist/runtime-config.js +1777 -0
- package/dist/runtime-identity.js +52 -0
- package/dist/schemas.js +590 -0
- package/dist/script-runner.js +64 -0
- package/dist/sdk-query.js +82 -0
- package/dist/skill-utils.js +145 -0
- package/dist/sqlite-compat.js +19 -0
- package/dist/stream-event.types.js +5 -0
- package/dist/streaming-runtime-meta.js +29 -0
- package/dist/task-scheduler.js +695 -0
- package/dist/task-utils.js +13 -0
- package/dist/telegram-pairing.js +59 -0
- package/dist/telegram.js +897 -0
- package/dist/terminal-manager.js +307 -0
- package/dist/tool-step-display.js +1 -0
- package/dist/types.js +1 -0
- package/dist/utils.js +85 -0
- package/dist/web-context.js +161 -0
- package/dist/web.js +1377 -0
- package/dist/wechat-crypto.js +182 -0
- package/dist/wechat.js +589 -0
- package/dist/workspace-runtime-reset.js +35 -0
- package/package.json +107 -0
- package/shared/assistant-meta-footer.ts +127 -0
- package/shared/channel-prefixes.ts +16 -0
- package/shared/dist/assistant-meta-footer.d.ts +29 -0
- package/shared/dist/assistant-meta-footer.js +85 -0
- package/shared/dist/channel-prefixes.d.ts +4 -0
- package/shared/dist/channel-prefixes.js +16 -0
- package/shared/dist/image-detector.d.ts +20 -0
- package/shared/dist/image-detector.js +96 -0
- package/shared/dist/runtime-command-registry.d.ts +38 -0
- package/shared/dist/runtime-command-registry.js +185 -0
- package/shared/dist/stream-event.d.ts +65 -0
- package/shared/dist/stream-event.js +8 -0
- package/shared/dist/tool-step-display.d.ts +4 -0
- package/shared/dist/tool-step-display.js +11 -0
- package/shared/image-detector.ts +116 -0
- package/shared/runtime-command-registry.ts +252 -0
- package/shared/stream-event.ts +67 -0
- package/shared/tool-step-display.ts +21 -0
- package/shared/tsconfig.json +24 -0
- package/web/dist/assets/BillingPage-B1wBR_o-.js +52 -0
- package/web/dist/assets/ChatPage-6GBZ9nXN.css +32 -0
- package/web/dist/assets/ChatPage-BOJcXtaj.js +161 -0
- package/web/dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- package/web/dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- package/web/dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- package/web/dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- package/web/dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- package/web/dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- package/web/dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- package/web/dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- package/web/dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- package/web/dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- package/web/dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- package/web/dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- package/web/dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- package/web/dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- package/web/dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- package/web/dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- package/web/dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- package/web/dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- package/web/dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- package/web/dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- package/web/dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- package/web/dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- package/web/dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- package/web/dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- package/web/dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- package/web/dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- package/web/dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- package/web/dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- package/web/dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- package/web/dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- package/web/dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- package/web/dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- package/web/dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- package/web/dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- package/web/dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- package/web/dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- package/web/dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- package/web/dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- package/web/dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- package/web/dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- package/web/dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- package/web/dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- package/web/dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- package/web/dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- package/web/dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- package/web/dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- package/web/dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- package/web/dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- package/web/dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- package/web/dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- package/web/dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- package/web/dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- package/web/dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- package/web/dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- package/web/dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- package/web/dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- package/web/dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- package/web/dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- package/web/dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- package/web/dist/assets/SettingsPage-DoY7FoZ_.js +153 -0
- package/web/dist/assets/ShareImageDialog-C1ga8b7l.js +22 -0
- package/web/dist/assets/TasksPage-CRivnNsx.js +14 -0
- package/web/dist/assets/_basePickBy-Bf-bSoS9.js +1 -0
- package/web/dist/assets/_baseUniq-zAOaCuKw.js +1 -0
- package/web/dist/assets/arc-Dm9mVQ9U.js +1 -0
- package/web/dist/assets/architectureDiagram-2XIMDMQ5-BLmzX1wr.js +36 -0
- package/web/dist/assets/band-CquvqAHh.js +1 -0
- package/web/dist/assets/blockDiagram-WCTKOSBZ-B9pcqm3j.js +132 -0
- package/web/dist/assets/c4Diagram-IC4MRINW-Cytx1q3b.js +10 -0
- package/web/dist/assets/channel-BOVj73LR.js +1 -0
- package/web/dist/assets/channel-meta-CQD0Pei-.js +41 -0
- package/web/dist/assets/chunk-4BX2VUAB-0ToDr6RE.js +1 -0
- package/web/dist/assets/chunk-55IACEB6-DQDjnXfS.js +1 -0
- package/web/dist/assets/chunk-FMBD7UC4-Di8ABm6c.js +15 -0
- package/web/dist/assets/chunk-JSJVCQXG-BZQN6rnX.js +1 -0
- package/web/dist/assets/chunk-KX2RTZJC-zBbcpaN_.js +1 -0
- package/web/dist/assets/chunk-NQ4KR5QH-BCrLoU88.js +220 -0
- package/web/dist/assets/chunk-QZHKN3VN-Bqk8juan.js +1 -0
- package/web/dist/assets/chunk-WL4C6EOR-D2YX-MHY.js +189 -0
- package/web/dist/assets/classDiagram-VBA2DB6C-DUUoMyaK.js +1 -0
- package/web/dist/assets/classDiagram-v2-RAHNMMFH-DUUoMyaK.js +1 -0
- package/web/dist/assets/clone-BmaCesfa.js +1 -0
- package/web/dist/assets/cose-bilkent-S5V4N54A-CTsv6qQA.js +1 -0
- package/web/dist/assets/cytoscape.esm-BQaXIfA_.js +331 -0
- package/web/dist/assets/dagre-KLK3FWXG-Ci4Jh9nu.js +4 -0
- package/web/dist/assets/defaultLocale-DX6XiGOO.js +1 -0
- package/web/dist/assets/diagram-E7M64L7V-BFRnfTI2.js +24 -0
- package/web/dist/assets/diagram-IFDJBPK2-B7Zhnp0b.js +43 -0
- package/web/dist/assets/diagram-P4PSJMXO-BVyP7nwq.js +24 -0
- package/web/dist/assets/erDiagram-INFDFZHY-NorKdTOF.js +70 -0
- package/web/dist/assets/error-CGD5mp5f.js +1 -0
- package/web/dist/assets/flowDiagram-PKNHOUZH-Ch97nABF.js +162 -0
- package/web/dist/assets/ganttDiagram-A5KZAMGK-BQ2pLWsy.js +292 -0
- package/web/dist/assets/gitGraphDiagram-K3NZZRJ6-bcvnBsD2.js +65 -0
- package/web/dist/assets/graph-CeAEckur.js +1 -0
- package/web/dist/assets/index-CPnL1_qC.js +768 -0
- package/web/dist/assets/index-DVevCbcO.css +10 -0
- package/web/dist/assets/infoDiagram-LFFYTUFH-CcsrFdj-.js +2 -0
- package/web/dist/assets/init-Dmth1JHB.js +1 -0
- package/web/dist/assets/ishikawaDiagram-PHBUUO56-1upyMfHN.js +70 -0
- package/web/dist/assets/journeyDiagram-4ABVD52K-CKUi-V0c.js +139 -0
- package/web/dist/assets/kanban-definition-K7BYSVSG-DOnQwXfL.js +89 -0
- package/web/dist/assets/layout-BmMMqTnJ.js +1 -0
- package/web/dist/assets/linear-DiaJloY5.js +1 -0
- package/web/dist/assets/mermaid.core-BWLV1B2v.js +254 -0
- package/web/dist/assets/mindmap-definition-YRQLILUH-BeAKHVWP.js +68 -0
- package/web/dist/assets/ordinal-DILIJJjt.js +1 -0
- package/web/dist/assets/pieDiagram-SKSYHLDU-DfiMSfWo.js +30 -0
- package/web/dist/assets/quadrantDiagram-337W2JSQ-wZxZOJxd.js +7 -0
- package/web/dist/assets/requirementDiagram-Z7DCOOCP-BK4HHm17.js +73 -0
- package/web/dist/assets/sankeyDiagram-WA2Y5GQK-BX6t2avX.js +10 -0
- package/web/dist/assets/sequenceDiagram-2WXFIKYE-BPQlkbAa.js +145 -0
- package/web/dist/assets/sheet-rI0FfB1g.js +6 -0
- package/web/dist/assets/sliders-horizontal-CuijWFNK.js +6 -0
- package/web/dist/assets/sparkles-BsMYXJoT.js +11 -0
- package/web/dist/assets/square-0CqMX1Q3.js +11 -0
- package/web/dist/assets/stateDiagram-RAJIS63D-DxkV0Vwd.js +1 -0
- package/web/dist/assets/stateDiagram-v2-FVOUBMTO-qLYoiOPe.js +1 -0
- package/web/dist/assets/step-D51IIHGA.js +1 -0
- package/web/dist/assets/tasks-D8JjBTwx.js +1 -0
- package/web/dist/assets/time-O8zIGux3.js +1 -0
- package/web/dist/assets/timeline-definition-YZTLITO2-kNp1DyFc.js +61 -0
- package/web/dist/assets/treemap-KZPCXAKY-CkrClVhk.js +162 -0
- package/web/dist/assets/utils-KGAn0XTg.js +11 -0
- package/web/dist/assets/vennDiagram-LZ73GAT5-CgdzEZz4.js +34 -0
- package/web/dist/assets/xychartDiagram-JWTSCODW-DfYGPfNB.js +7 -0
- package/web/dist/assets/zap-_hKJYy7J.js +6 -0
- package/web/dist/favicon.svg +332 -0
- package/web/dist/fonts/AlibabaPuHuiTi-3-55-Regular.woff2 +0 -0
- package/web/dist/fonts/AlibabaPuHuiTi-3-65-Medium.woff2 +0 -0
- package/web/dist/fonts/AlibabaPuHuiTi-3-75-SemiBold.woff2 +0 -0
- package/web/dist/fonts/DMSans-latin-ext.woff2 +0 -0
- package/web/dist/fonts/DMSans-latin.woff2 +0 -0
- package/web/dist/icons/README.md +20 -0
- package/web/dist/icons/apple-touch-icon-180.png +0 -0
- package/web/dist/icons/icon-128.png +0 -0
- package/web/dist/icons/icon-144.png +0 -0
- package/web/dist/icons/icon-152.png +0 -0
- package/web/dist/icons/icon-192.png +0 -0
- package/web/dist/icons/icon-192.svg +332 -0
- package/web/dist/icons/icon-384.png +0 -0
- package/web/dist/icons/icon-48.png +0 -0
- package/web/dist/icons/icon-512-maskable.png +0 -0
- package/web/dist/icons/icon-512.png +0 -0
- package/web/dist/icons/icon-512.svg +332 -0
- package/web/dist/icons/icon-72.png +0 -0
- package/web/dist/icons/icon-96.png +0 -0
- package/web/dist/icons/loading-logo.svg +332 -0
- package/web/dist/icons/logo-1024.png +0 -0
- package/web/dist/icons/logo-icon.svg +332 -0
- package/web/dist/icons/logo-text.svg +332 -0
- package/web/dist/index.html +30 -0
- package/web/dist/manifest.webmanifest +1 -0
- package/web/dist/registerSW.js +1 -0
- package/web/dist/sw.js +1 -0
- package/web/dist/workbox-08d6266a.js +1 -0
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
import { execFile, spawn } from 'child_process';
|
|
2
|
+
import readline from 'readline';
|
|
3
|
+
import { promisify } from 'util';
|
|
4
|
+
import { Hono } from 'hono';
|
|
5
|
+
import { resolveAppPath, resolvePackageDependency } from '../app-root.js';
|
|
6
|
+
import { authMiddleware, systemConfigMiddleware } from '../middleware/auth.js';
|
|
7
|
+
import { isHostExecutionGroup, hasHostExecutionPermission, canAccessGroup, getWebDeps, } from '../web-context.js';
|
|
8
|
+
import { getRegisteredGroup, getRouterState, hasContainerModeGroups, } from '../db.js';
|
|
9
|
+
import { CONTAINER_IMAGE } from '../config.js';
|
|
10
|
+
import { getSystemSettings } from '../runtime-config.js';
|
|
11
|
+
import { logger } from '../logger.js';
|
|
12
|
+
const execFileAsync = promisify(execFile);
|
|
13
|
+
let cachedVersions = null;
|
|
14
|
+
const VERSION_CACHE_TTL = 60 * 60 * 1000;
|
|
15
|
+
// Latest version cache (separate TTL, queried from npm registry)
|
|
16
|
+
let cachedLatestVersion = null;
|
|
17
|
+
const LATEST_VERSION_CACHE_TTL = 30 * 60 * 1000; // 30min
|
|
18
|
+
/** Query latest Claude Code version from npm registry */
|
|
19
|
+
async function getLatestClaudeCodeVersion() {
|
|
20
|
+
const now = Date.now();
|
|
21
|
+
if (cachedLatestVersion &&
|
|
22
|
+
now - cachedLatestVersion.fetchedAt < LATEST_VERSION_CACHE_TTL) {
|
|
23
|
+
return cachedLatestVersion.version;
|
|
24
|
+
}
|
|
25
|
+
try {
|
|
26
|
+
const { stdout } = await execFileAsync('npm', ['view', '@anthropic-ai/claude-code', 'version'], { timeout: 15000 });
|
|
27
|
+
const version = stdout.trim() || null;
|
|
28
|
+
cachedLatestVersion = { version, fetchedAt: now };
|
|
29
|
+
return version;
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
// Fallback: keep stale cache if available
|
|
33
|
+
if (cachedLatestVersion)
|
|
34
|
+
return cachedLatestVersion.version;
|
|
35
|
+
cachedLatestVersion = { version: null, fetchedAt: now };
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/** Get host Claude Code version by running SDK's built-in cli.js --version */
|
|
40
|
+
async function getHostClaudeCodeVersion() {
|
|
41
|
+
try {
|
|
42
|
+
const cliPath = resolvePackageDependency('@anthropic-ai/claude-agent-sdk/cli.js');
|
|
43
|
+
const { stdout } = await execFileAsync('node', [
|
|
44
|
+
'-e',
|
|
45
|
+
`process.argv = ['node', 'claude', '--version']; require('${cliPath}')`,
|
|
46
|
+
], { timeout: 10000 });
|
|
47
|
+
return stdout.trim() || null;
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
async function getDockerImageId() {
|
|
54
|
+
try {
|
|
55
|
+
const { stdout } = await execFileAsync('docker', ['images', CONTAINER_IMAGE, '--format', '{{.ID}}'], { timeout: 5000 });
|
|
56
|
+
return stdout.trim() || null;
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/** Get container Claude Code version from SDK's cli.js inside Docker image */
|
|
63
|
+
async function getContainerClaudeCodeVersion() {
|
|
64
|
+
try {
|
|
65
|
+
const { stdout } = await execFileAsync('docker', [
|
|
66
|
+
'run',
|
|
67
|
+
'--rm',
|
|
68
|
+
'--entrypoint',
|
|
69
|
+
'node',
|
|
70
|
+
CONTAINER_IMAGE,
|
|
71
|
+
'-e',
|
|
72
|
+
`process.argv = ['node', 'claude', '--version']; require('/app/node_modules/@anthropic-ai/claude-agent-sdk/cli.js')`,
|
|
73
|
+
], { timeout: 30000 });
|
|
74
|
+
return stdout.trim() || null;
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
async function getClaudeCodeVersions() {
|
|
81
|
+
const now = Date.now();
|
|
82
|
+
const imageId = await getDockerImageId();
|
|
83
|
+
// Return cached if same image and within TTL
|
|
84
|
+
if (cachedVersions &&
|
|
85
|
+
cachedVersions.imageId === imageId &&
|
|
86
|
+
now - cachedVersions.fetchedAt < VERSION_CACHE_TTL) {
|
|
87
|
+
return cachedVersions.info;
|
|
88
|
+
}
|
|
89
|
+
// Fetch all versions concurrently
|
|
90
|
+
const [host, container, latest] = await Promise.all([
|
|
91
|
+
getHostClaudeCodeVersion(),
|
|
92
|
+
imageId ? getContainerClaudeCodeVersion() : Promise.resolve(null),
|
|
93
|
+
getLatestClaudeCodeVersion(),
|
|
94
|
+
]);
|
|
95
|
+
const info = { host, container, latest };
|
|
96
|
+
cachedVersions = { info, fetchedAt: now, imageId };
|
|
97
|
+
return info;
|
|
98
|
+
}
|
|
99
|
+
// --- Docker build state ---
|
|
100
|
+
let buildState = {
|
|
101
|
+
building: false,
|
|
102
|
+
startedAt: null,
|
|
103
|
+
startedBy: null,
|
|
104
|
+
logs: [],
|
|
105
|
+
result: null,
|
|
106
|
+
};
|
|
107
|
+
// --- Dependency injection (avoid circular imports) ---
|
|
108
|
+
let broadcastLog = null;
|
|
109
|
+
let broadcastComplete = null;
|
|
110
|
+
export function injectMonitorDeps(deps) {
|
|
111
|
+
broadcastLog = deps.broadcastDockerBuildLog;
|
|
112
|
+
broadcastComplete = deps.broadcastDockerBuildComplete;
|
|
113
|
+
}
|
|
114
|
+
const monitorRoutes = new Hono();
|
|
115
|
+
// GET /api/health - 健康检查(无认证)
|
|
116
|
+
monitorRoutes.get('/health', async (c) => {
|
|
117
|
+
const checks = {
|
|
118
|
+
database: false,
|
|
119
|
+
queue: false,
|
|
120
|
+
uptime: 0,
|
|
121
|
+
};
|
|
122
|
+
let healthy = true;
|
|
123
|
+
// 检查数据库连通性
|
|
124
|
+
try {
|
|
125
|
+
getRouterState('last_timestamp');
|
|
126
|
+
checks.database = true;
|
|
127
|
+
}
|
|
128
|
+
catch (err) {
|
|
129
|
+
healthy = false;
|
|
130
|
+
logger.warn({ err }, '健康检查:数据库连接失败');
|
|
131
|
+
}
|
|
132
|
+
// 检查队列状态
|
|
133
|
+
try {
|
|
134
|
+
const deps = getWebDeps();
|
|
135
|
+
if (deps && deps.queue) {
|
|
136
|
+
checks.queue = true;
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
healthy = false;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
catch (err) {
|
|
143
|
+
healthy = false;
|
|
144
|
+
logger.warn({ err }, '健康检查:队列不可用');
|
|
145
|
+
}
|
|
146
|
+
// 进程运行时间
|
|
147
|
+
checks.uptime = Math.floor(process.uptime());
|
|
148
|
+
const status = healthy ? 'healthy' : 'unhealthy';
|
|
149
|
+
const statusCode = healthy ? 200 : 503;
|
|
150
|
+
return c.json({ status, checks }, statusCode);
|
|
151
|
+
});
|
|
152
|
+
async function checkDockerImageExists() {
|
|
153
|
+
// Skip Docker check entirely when no groups use container mode
|
|
154
|
+
if (!hasContainerModeGroups())
|
|
155
|
+
return false;
|
|
156
|
+
try {
|
|
157
|
+
const { stdout } = await execFileAsync('docker', ['images', CONTAINER_IMAGE, '--format', '{{.ID}}'], { timeout: 10000 });
|
|
158
|
+
return stdout.trim().length > 0;
|
|
159
|
+
}
|
|
160
|
+
catch {
|
|
161
|
+
return false;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
// GET /api/status - 获取系统状态
|
|
165
|
+
monitorRoutes.get('/status', authMiddleware, async (c) => {
|
|
166
|
+
const deps = getWebDeps();
|
|
167
|
+
if (!deps)
|
|
168
|
+
return c.json({ error: 'Server not initialized' }, 500);
|
|
169
|
+
const authUser = c.get('user');
|
|
170
|
+
const isAdmin = hasHostExecutionPermission(authUser);
|
|
171
|
+
const queueStatus = deps.queue.getStatus();
|
|
172
|
+
// 监控页面属于系统管理功能,admin 可见所有群组状态(不受工作区隔离约束)
|
|
173
|
+
const filteredGroups = isAdmin
|
|
174
|
+
? queueStatus.groups
|
|
175
|
+
: queueStatus.groups.filter((g) => {
|
|
176
|
+
const group = getRegisteredGroup(g.jid);
|
|
177
|
+
if (!group)
|
|
178
|
+
return false;
|
|
179
|
+
if (isHostExecutionGroup(group))
|
|
180
|
+
return false;
|
|
181
|
+
return canAccessGroup({ id: authUser.id, role: authUser.role }, group);
|
|
182
|
+
});
|
|
183
|
+
const dockerImageExists = await checkDockerImageExists();
|
|
184
|
+
// For non-admin users, derive aggregate metrics from their own filtered groups only
|
|
185
|
+
// to prevent leaking global system load information across users
|
|
186
|
+
let activeContainers;
|
|
187
|
+
let queueLength;
|
|
188
|
+
if (isAdmin) {
|
|
189
|
+
activeContainers = queueStatus.activeContainerCount;
|
|
190
|
+
queueLength = queueStatus.waitingCount;
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
activeContainers = filteredGroups.filter((g) => g.active).length;
|
|
194
|
+
// Filter waiting groups by user ownership
|
|
195
|
+
queueLength = queueStatus.waitingGroupJids.filter((jid) => {
|
|
196
|
+
const group = getRegisteredGroup(jid);
|
|
197
|
+
if (!group)
|
|
198
|
+
return false;
|
|
199
|
+
if (isHostExecutionGroup(group))
|
|
200
|
+
return false;
|
|
201
|
+
return canAccessGroup({ id: authUser.id, role: authUser.role }, group);
|
|
202
|
+
}).length;
|
|
203
|
+
}
|
|
204
|
+
return c.json({
|
|
205
|
+
activeContainers,
|
|
206
|
+
activeHostProcesses: isAdmin
|
|
207
|
+
? queueStatus.activeHostProcessCount
|
|
208
|
+
: undefined,
|
|
209
|
+
activeTotal: isAdmin ? queueStatus.activeCount : activeContainers,
|
|
210
|
+
maxConcurrentContainers: getSystemSettings().maxConcurrentContainers,
|
|
211
|
+
maxConcurrentHostProcesses: isAdmin
|
|
212
|
+
? getSystemSettings().maxConcurrentHostProcesses
|
|
213
|
+
: undefined,
|
|
214
|
+
queueLength,
|
|
215
|
+
uptime: Math.floor(process.uptime()),
|
|
216
|
+
groups: filteredGroups,
|
|
217
|
+
dockerImageExists,
|
|
218
|
+
dockerBuildInProgress: buildState.building,
|
|
219
|
+
claudeCodeVersions: isAdmin ? await getClaudeCodeVersions() : undefined,
|
|
220
|
+
dockerBuildLogs: isAdmin && buildState.building ? buildState.logs.slice(-50) : undefined,
|
|
221
|
+
dockerBuildResult: isAdmin ? buildState.result : undefined,
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
// POST /api/docker/build - 构建 Docker 镜像(仅 admin,异步启动 + WS 推送进度)
|
|
225
|
+
monitorRoutes.post('/docker/build', authMiddleware, systemConfigMiddleware, async (c) => {
|
|
226
|
+
if (buildState.building) {
|
|
227
|
+
return c.json({
|
|
228
|
+
error: 'Docker image build already in progress',
|
|
229
|
+
startedAt: buildState.startedAt,
|
|
230
|
+
startedBy: buildState.startedBy,
|
|
231
|
+
}, 409);
|
|
232
|
+
}
|
|
233
|
+
const authUser = c.get('user');
|
|
234
|
+
const buildScript = resolveAppPath('container', 'build.sh');
|
|
235
|
+
buildState = {
|
|
236
|
+
building: true,
|
|
237
|
+
startedAt: Date.now(),
|
|
238
|
+
startedBy: authUser.username,
|
|
239
|
+
logs: [],
|
|
240
|
+
result: null,
|
|
241
|
+
};
|
|
242
|
+
logger.info({ startedBy: authUser.username }, 'Docker image build requested via API');
|
|
243
|
+
// Spawn build process asynchronously
|
|
244
|
+
const proc = spawn('bash', [buildScript], {
|
|
245
|
+
cwd: resolveAppPath('container'),
|
|
246
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
247
|
+
});
|
|
248
|
+
// 10-minute timeout
|
|
249
|
+
const timeout = setTimeout(() => {
|
|
250
|
+
proc.kill('SIGKILL');
|
|
251
|
+
const errMsg = 'Docker build timed out after 10 minutes';
|
|
252
|
+
logger.error(errMsg);
|
|
253
|
+
buildState.building = false;
|
|
254
|
+
buildState.result = { success: false, error: errMsg };
|
|
255
|
+
broadcastLog?.(errMsg);
|
|
256
|
+
broadcastComplete?.(false, errMsg);
|
|
257
|
+
}, 10 * 60 * 1000);
|
|
258
|
+
const pushLine = (line) => {
|
|
259
|
+
buildState.logs.push(line);
|
|
260
|
+
// Keep last 200 lines in memory
|
|
261
|
+
if (buildState.logs.length > 200) {
|
|
262
|
+
buildState.logs = buildState.logs.slice(-200);
|
|
263
|
+
}
|
|
264
|
+
broadcastLog?.(line);
|
|
265
|
+
};
|
|
266
|
+
// Read stdout and stderr line by line
|
|
267
|
+
if (proc.stdout) {
|
|
268
|
+
const rl = readline.createInterface({ input: proc.stdout });
|
|
269
|
+
rl.on('line', pushLine);
|
|
270
|
+
}
|
|
271
|
+
if (proc.stderr) {
|
|
272
|
+
const rl = readline.createInterface({ input: proc.stderr });
|
|
273
|
+
rl.on('line', pushLine);
|
|
274
|
+
}
|
|
275
|
+
proc.on('close', (code) => {
|
|
276
|
+
clearTimeout(timeout);
|
|
277
|
+
const success = code === 0;
|
|
278
|
+
const error = success
|
|
279
|
+
? undefined
|
|
280
|
+
: `Build process exited with code ${code}`;
|
|
281
|
+
if (success) {
|
|
282
|
+
logger.info('Docker image build completed');
|
|
283
|
+
// Invalidate version cache so next query fetches from new image
|
|
284
|
+
cachedVersions = null;
|
|
285
|
+
}
|
|
286
|
+
else {
|
|
287
|
+
logger.error({ code }, 'Docker image build failed');
|
|
288
|
+
}
|
|
289
|
+
buildState.building = false;
|
|
290
|
+
buildState.result = { success, error };
|
|
291
|
+
broadcastComplete?.(success, error);
|
|
292
|
+
});
|
|
293
|
+
proc.on('error', (err) => {
|
|
294
|
+
clearTimeout(timeout);
|
|
295
|
+
const errorMsg = err.message;
|
|
296
|
+
logger.error({ err }, 'Docker image build process error');
|
|
297
|
+
buildState.building = false;
|
|
298
|
+
buildState.result = { success: false, error: errorMsg };
|
|
299
|
+
broadcastComplete?.(false, errorMsg);
|
|
300
|
+
});
|
|
301
|
+
// Return immediately with 202 Accepted
|
|
302
|
+
return c.json({
|
|
303
|
+
accepted: true,
|
|
304
|
+
message: 'Docker image build started. Progress will be streamed via WebSocket.',
|
|
305
|
+
}, 202);
|
|
306
|
+
});
|
|
307
|
+
export default monitorRoutes;
|