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,210 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { TIMEZONE } from './config.js';
|
|
4
|
+
import { getGroupsByOwner, getMessagesByTimeRange, listUsers } from './db.js';
|
|
5
|
+
let lastCheckTime = 0;
|
|
6
|
+
const CHECK_INTERVAL_MS = 55 * 60 * 1000; // 55 minutes
|
|
7
|
+
/**
|
|
8
|
+
* Run daily summary generation if conditions are met.
|
|
9
|
+
* Called from the scheduler loop every 60s.
|
|
10
|
+
* Actually executes only once per hour, and only between 2:00-3:00 AM local time.
|
|
11
|
+
*/
|
|
12
|
+
export function runDailySummaryIfNeeded(deps) {
|
|
13
|
+
const now = Date.now();
|
|
14
|
+
// Throttle: skip if checked less than 55 minutes ago
|
|
15
|
+
if (now - lastCheckTime < CHECK_INTERVAL_MS)
|
|
16
|
+
return;
|
|
17
|
+
lastCheckTime = now;
|
|
18
|
+
// Only run between 2:00-3:00 AM in the configured timezone
|
|
19
|
+
const localHour = getLocalHour(now);
|
|
20
|
+
if (localHour < 2 || localHour >= 3)
|
|
21
|
+
return;
|
|
22
|
+
deps.logger.info('Daily summary: starting generation');
|
|
23
|
+
try {
|
|
24
|
+
generateSummaries(deps, now);
|
|
25
|
+
}
|
|
26
|
+
catch (err) {
|
|
27
|
+
deps.logger.error({ err }, 'Daily summary: generation failed');
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function getLocalHour(timestampMs) {
|
|
31
|
+
const formatter = new Intl.DateTimeFormat('en-US', {
|
|
32
|
+
hour: 'numeric',
|
|
33
|
+
hour12: false,
|
|
34
|
+
timeZone: TIMEZONE,
|
|
35
|
+
});
|
|
36
|
+
return parseInt(formatter.format(new Date(timestampMs)), 10);
|
|
37
|
+
}
|
|
38
|
+
function getLocalDateString(timestampMs) {
|
|
39
|
+
const formatter = new Intl.DateTimeFormat('sv-SE', {
|
|
40
|
+
year: 'numeric',
|
|
41
|
+
month: '2-digit',
|
|
42
|
+
day: '2-digit',
|
|
43
|
+
timeZone: TIMEZONE,
|
|
44
|
+
});
|
|
45
|
+
// sv-SE locale gives YYYY-MM-DD format
|
|
46
|
+
return formatter.format(new Date(timestampMs));
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Get start and end timestamps (ms) for a given local date string (YYYY-MM-DD).
|
|
50
|
+
*/
|
|
51
|
+
function getDayBounds(dateStr) {
|
|
52
|
+
// Parse date components and create timestamps in the configured timezone
|
|
53
|
+
const [year, month, day] = dateStr.split('-').map(Number);
|
|
54
|
+
// Use a trick: format a known date to find the offset, then compute bounds
|
|
55
|
+
// Create date at midnight UTC, then adjust for timezone
|
|
56
|
+
const midnightUtc = new Date(Date.UTC(year, month - 1, day, 0, 0, 0, 0));
|
|
57
|
+
// Find the timezone offset by comparing UTC and local representations
|
|
58
|
+
const localStr = midnightUtc.toLocaleString('en-US', { timeZone: TIMEZONE });
|
|
59
|
+
const localDate = new Date(localStr);
|
|
60
|
+
const offsetMs = midnightUtc.getTime() - localDate.getTime();
|
|
61
|
+
const startTs = midnightUtc.getTime() + offsetMs;
|
|
62
|
+
const endTs = startTs + 24 * 60 * 60 * 1000;
|
|
63
|
+
return { startTs, endTs };
|
|
64
|
+
}
|
|
65
|
+
function generateSummaries(deps, nowMs) {
|
|
66
|
+
// Yesterday's date in local timezone
|
|
67
|
+
const yesterdayMs = nowMs - 24 * 60 * 60 * 1000;
|
|
68
|
+
const dateStr = getLocalDateString(yesterdayMs);
|
|
69
|
+
const { startTs, endTs } = getDayBounds(dateStr);
|
|
70
|
+
// Get all active users
|
|
71
|
+
let page = 1;
|
|
72
|
+
let processedUsers = 0;
|
|
73
|
+
while (true) {
|
|
74
|
+
const result = listUsers({ status: 'active', page, pageSize: 200 });
|
|
75
|
+
for (const user of result.users) {
|
|
76
|
+
try {
|
|
77
|
+
const generated = generateUserSummary(deps, user.id, user.username, dateStr, startTs, endTs);
|
|
78
|
+
if (generated)
|
|
79
|
+
processedUsers++;
|
|
80
|
+
}
|
|
81
|
+
catch (err) {
|
|
82
|
+
deps.logger.error({ err, userId: user.id }, 'Daily summary: failed for user');
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
if (result.users.length < result.pageSize ||
|
|
86
|
+
page * result.pageSize >= result.total)
|
|
87
|
+
break;
|
|
88
|
+
page++;
|
|
89
|
+
}
|
|
90
|
+
deps.logger.info({ date: dateStr, processedUsers }, 'Daily summary: generation complete');
|
|
91
|
+
}
|
|
92
|
+
function generateUserSummary(deps, userId, username, dateStr, startTs, endTs) {
|
|
93
|
+
// Output path: ~/.cli-claw/groups/user-global/{userId}/daily-summary/YYYY-MM-DD.md
|
|
94
|
+
const summaryDir = path.join(deps.dataDir, 'groups', 'user-global', userId, 'daily-summary');
|
|
95
|
+
const summaryPath = path.join(summaryDir, `${dateStr}.md`);
|
|
96
|
+
// Idempotent: skip if already exists
|
|
97
|
+
if (fs.existsSync(summaryPath)) {
|
|
98
|
+
deps.logger.debug({ userId, date: dateStr }, 'Daily summary: already exists, skipping');
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
// Get all groups owned by this user
|
|
102
|
+
const groups = getGroupsByOwner(userId);
|
|
103
|
+
if (groups.length === 0)
|
|
104
|
+
return false;
|
|
105
|
+
// Collect all chat_jids for the user's groups
|
|
106
|
+
const chatJids = groups.map((g) => g.jid);
|
|
107
|
+
// Fetch messages for all jids in the time range
|
|
108
|
+
const sections = [];
|
|
109
|
+
let totalCount = 0;
|
|
110
|
+
for (const jid of chatJids) {
|
|
111
|
+
const messages = getMessagesByTimeRange(jid, startTs, endTs);
|
|
112
|
+
if (messages.length === 0)
|
|
113
|
+
continue;
|
|
114
|
+
totalCount += messages.length;
|
|
115
|
+
const lines = [];
|
|
116
|
+
let prevWasAgent = false;
|
|
117
|
+
for (const msg of messages) {
|
|
118
|
+
const isAgent = msg.is_from_me;
|
|
119
|
+
const sender = isAgent
|
|
120
|
+
? 'Agent'
|
|
121
|
+
: msg.sender_name || msg.sender || 'User';
|
|
122
|
+
const content = truncate(msg.content || '', 200);
|
|
123
|
+
// Merge consecutive Agent replies
|
|
124
|
+
if (isAgent && prevWasAgent)
|
|
125
|
+
continue;
|
|
126
|
+
lines.push(`- **${sender}**: ${content}`);
|
|
127
|
+
prevWasAgent = isAgent;
|
|
128
|
+
}
|
|
129
|
+
sections.push(`## ${jid}\n${lines.join('\n')}`);
|
|
130
|
+
}
|
|
131
|
+
if (totalCount === 0)
|
|
132
|
+
return false;
|
|
133
|
+
// Build markdown content
|
|
134
|
+
const md = `# ${dateStr} 对话汇总\n\n用户: ${username} | 消息数: ${totalCount}\n\n${sections.join('\n\n')}\n`;
|
|
135
|
+
// Write file
|
|
136
|
+
fs.mkdirSync(summaryDir, { recursive: true });
|
|
137
|
+
fs.writeFileSync(summaryPath, md, 'utf-8');
|
|
138
|
+
deps.logger.info({ userId, date: dateStr, messageCount: totalCount }, 'Daily summary: generated');
|
|
139
|
+
// Update HEARTBEAT.md with latest summaries
|
|
140
|
+
const userGlobalDir = path.join(deps.dataDir, 'groups', 'user-global', userId);
|
|
141
|
+
updateHeartbeat(userGlobalDir, username, deps.logger);
|
|
142
|
+
return true;
|
|
143
|
+
}
|
|
144
|
+
function truncate(text, maxLen) {
|
|
145
|
+
// Replace newlines with spaces for single-line display
|
|
146
|
+
const singleLine = text.replace(/\n/g, ' ').trim();
|
|
147
|
+
if (singleLine.length <= maxLen)
|
|
148
|
+
return singleLine;
|
|
149
|
+
return singleLine.slice(0, maxLen) + '...';
|
|
150
|
+
}
|
|
151
|
+
const HEARTBEAT_MAX_CHARS = 4096;
|
|
152
|
+
const HEARTBEAT_PER_DAY_MAX_CHARS = 1024;
|
|
153
|
+
const HEARTBEAT_DAYS = 3;
|
|
154
|
+
/**
|
|
155
|
+
* Update HEARTBEAT.md with the most recent daily summaries.
|
|
156
|
+
* Called after a daily summary is generated for a user.
|
|
157
|
+
*/
|
|
158
|
+
function updateHeartbeat(userGlobalDir, username, logger) {
|
|
159
|
+
const summaryDir = path.join(userGlobalDir, 'daily-summary');
|
|
160
|
+
if (!fs.existsSync(summaryDir))
|
|
161
|
+
return;
|
|
162
|
+
// Read all .md files sorted by name (YYYY-MM-DD.md) descending, take latest 3
|
|
163
|
+
let files;
|
|
164
|
+
try {
|
|
165
|
+
files = fs
|
|
166
|
+
.readdirSync(summaryDir)
|
|
167
|
+
.filter((f) => f.endsWith('.md'))
|
|
168
|
+
.sort()
|
|
169
|
+
.reverse()
|
|
170
|
+
.slice(0, HEARTBEAT_DAYS);
|
|
171
|
+
}
|
|
172
|
+
catch {
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
if (files.length === 0)
|
|
176
|
+
return;
|
|
177
|
+
// Reverse back to chronological order (oldest first)
|
|
178
|
+
files.reverse();
|
|
179
|
+
const now = new Date();
|
|
180
|
+
const timestamp = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')} ${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}`;
|
|
181
|
+
const sections = [];
|
|
182
|
+
for (const file of files) {
|
|
183
|
+
const dateLabel = file.replace(/\.md$/, '');
|
|
184
|
+
try {
|
|
185
|
+
let content = fs.readFileSync(path.join(summaryDir, file), 'utf-8');
|
|
186
|
+
if (content.length > HEARTBEAT_PER_DAY_MAX_CHARS) {
|
|
187
|
+
content =
|
|
188
|
+
content.slice(0, HEARTBEAT_PER_DAY_MAX_CHARS) + '\n\n[...截断]';
|
|
189
|
+
}
|
|
190
|
+
sections.push(`### ${dateLabel}\n${content}`);
|
|
191
|
+
}
|
|
192
|
+
catch {
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
if (sections.length === 0)
|
|
197
|
+
return;
|
|
198
|
+
let md = `# 近期工作摘要\n\n> 自动生成,最近更新:${timestamp}\n\n## 最近 ${files.length} 天对话汇总\n\n${sections.join('\n\n')}\n`;
|
|
199
|
+
if (md.length > HEARTBEAT_MAX_CHARS) {
|
|
200
|
+
md = md.slice(0, HEARTBEAT_MAX_CHARS) + '\n\n[...截断]';
|
|
201
|
+
}
|
|
202
|
+
const heartbeatPath = path.join(userGlobalDir, 'HEARTBEAT.md');
|
|
203
|
+
try {
|
|
204
|
+
fs.writeFileSync(heartbeatPath, md, 'utf-8');
|
|
205
|
+
logger.info({ username }, 'Daily summary: updated HEARTBEAT.md');
|
|
206
|
+
}
|
|
207
|
+
catch (err) {
|
|
208
|
+
logger.error({ err, username }, 'Daily summary: failed to write HEARTBEAT.md');
|
|
209
|
+
}
|
|
210
|
+
}
|