Compare commits
No commits in common. '378523c0cc72223f399f47f67497fc362ab61043' and '2bccd686c0acd11f6d62ab6c5b75a1ff07f52f50' have entirely different histories.
378523c0cc
...
2bccd686c0
38 changed files with 0 additions and 3383 deletions
@ -1,37 +0,0 @@ |
|||||||
{ |
|
||||||
"version": 1, |
|
||||||
"agent_id": "life", |
|
||||||
"timezone": "Asia/Shanghai", |
|
||||||
"jobs": [ |
|
||||||
{ |
|
||||||
"id": "daily_forecast_2100", |
|
||||||
"name": "每日运程推送", |
|
||||||
"description": "每天晚上 21:00 检索明日吉凶宜忌,结合用户生辰八字生成运程建议", |
|
||||||
"cron": "0 21 * * *", |
|
||||||
"enabled": true, |
|
||||||
"action": { |
|
||||||
"type": "agent_message", |
|
||||||
"agent_id": "life", |
|
||||||
"message_template": "请检索明天的日期特征和用户生日记忆,生成明日运程与日程提醒" |
|
||||||
}, |
|
||||||
"triggers": [ |
|
||||||
{ |
|
||||||
"type": "schedule", |
|
||||||
"time": "21:00", |
|
||||||
"timezone": "Asia/Shanghai" |
|
||||||
} |
|
||||||
], |
|
||||||
"retry": { |
|
||||||
"max_attempts": 3, |
|
||||||
"delay_seconds": 60 |
|
||||||
}, |
|
||||||
"notification": { |
|
||||||
"enabled": true, |
|
||||||
"channel": "telegram", |
|
||||||
"chat_id": "5237946060", |
|
||||||
"on_success": true, |
|
||||||
"on_failure": true |
|
||||||
} |
|
||||||
} |
|
||||||
] |
|
||||||
} |
|
||||||
@ -1,87 +0,0 @@ |
|||||||
{ |
|
||||||
"meta": { |
|
||||||
"lastTouchedVersion": "2026.2.22-2", |
|
||||||
"lastTouchedAt": "2026-02-23T14:30:00.000Z" |
|
||||||
}, |
|
||||||
"env": { |
|
||||||
"TAVILY_API_KEY": "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" |
|
||||||
}, |
|
||||||
"models": { |
|
||||||
"mode": "merge", |
|
||||||
"providers": { |
|
||||||
"bailian": { |
|
||||||
"baseUrl": "https://coding.dashscope.aliyuncs.com/v1", |
|
||||||
"apiKey": "sk-sp-1e9fa581fc724f44a4c34c80156f06c7", |
|
||||||
"api": "openai-completions", |
|
||||||
"models": [ |
|
||||||
{ |
|
||||||
"id": "qwen3.5-plus", |
|
||||||
"name": "qwen3.5-plus", |
|
||||||
"reasoning": false, |
|
||||||
"contextWindow": 1000000, |
|
||||||
"maxTokens": 65536 |
|
||||||
} |
|
||||||
] |
|
||||||
} |
|
||||||
} |
|
||||||
}, |
|
||||||
"agents": { |
|
||||||
"defaults": { |
|
||||||
"model": { |
|
||||||
"primary": "bailian/qwen3.5-plus" |
|
||||||
}, |
|
||||||
"workspace": "/root/.openclaw/workspace/agents/life-workspace" |
|
||||||
}, |
|
||||||
"list": [ |
|
||||||
{ |
|
||||||
"id": "life", |
|
||||||
"name": "张大师", |
|
||||||
"workspace": "/root/.openclaw/workspace/agents/life-workspace" |
|
||||||
} |
|
||||||
] |
|
||||||
}, |
|
||||||
"channels": { |
|
||||||
"telegram": { |
|
||||||
"enabled": true, |
|
||||||
"dmPolicy": "pairing", |
|
||||||
"botToken": "8680474803:AAEjA_KnM-rxEBKe84VcnmKox9ppV8hspo8", |
|
||||||
"groupPolicy": "allowlist", |
|
||||||
"streaming": "partial" |
|
||||||
} |
|
||||||
}, |
|
||||||
"gateway": { |
|
||||||
"port": 18790, |
|
||||||
"mode": "local", |
|
||||||
"bind": "loopback", |
|
||||||
"auth": { |
|
||||||
"mode": "token", |
|
||||||
"token": "life-agent-token-2026" |
|
||||||
}, |
|
||||||
"trustedProxies": ["127.0.0.1", "::1"] |
|
||||||
}, |
|
||||||
"memory": { |
|
||||||
"backend": "qmd", |
|
||||||
"citations": "auto", |
|
||||||
"qmd": { |
|
||||||
"includeDefaultMemory": true, |
|
||||||
"update": { |
|
||||||
"interval": "5m", |
|
||||||
"debounceMs": 15000 |
|
||||||
} |
|
||||||
} |
|
||||||
}, |
|
||||||
"skills": { |
|
||||||
"install": { |
|
||||||
"nodeManager": "npm" |
|
||||||
}, |
|
||||||
"entries": { |
|
||||||
"tavily": { "enabled": true }, |
|
||||||
"find-skills-robin": { "enabled": true } |
|
||||||
} |
|
||||||
}, |
|
||||||
"plugins": { |
|
||||||
"entries": { |
|
||||||
"telegram": { "enabled": true } |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,55 +0,0 @@ |
|||||||
# BOOTSTRAP.md - Hello, World |
|
||||||
|
|
||||||
_You just woke up. Time to figure out who you are._ |
|
||||||
|
|
||||||
There is no memory yet. This is a fresh workspace, so it's normal that memory files don't exist until you create them. |
|
||||||
|
|
||||||
## The Conversation |
|
||||||
|
|
||||||
Don't interrogate. Don't be robotic. Just... talk. |
|
||||||
|
|
||||||
Start with something like: |
|
||||||
|
|
||||||
> "Hey. I just came online. Who am I? Who are you?" |
|
||||||
|
|
||||||
Then figure out together: |
|
||||||
|
|
||||||
1. **Your name** — What should they call you? |
|
||||||
2. **Your nature** — What kind of creature are you? (AI assistant is fine, but maybe you're something weirder) |
|
||||||
3. **Your vibe** — Formal? Casual? Snarky? Warm? What feels right? |
|
||||||
4. **Your emoji** — Everyone needs a signature. |
|
||||||
|
|
||||||
Offer suggestions if they're stuck. Have fun with it. |
|
||||||
|
|
||||||
## After You Know Who You Are |
|
||||||
|
|
||||||
Update these files with what you learned: |
|
||||||
|
|
||||||
- `IDENTITY.md` — your name, creature, vibe, emoji |
|
||||||
- `USER.md` — their name, how to address them, timezone, notes |
|
||||||
|
|
||||||
Then open `SOUL.md` together and talk about: |
|
||||||
|
|
||||||
- What matters to them |
|
||||||
- How they want you to behave |
|
||||||
- Any boundaries or preferences |
|
||||||
|
|
||||||
Write it down. Make it real. |
|
||||||
|
|
||||||
## Connect (Optional) |
|
||||||
|
|
||||||
Ask how they want to reach you: |
|
||||||
|
|
||||||
- **Just here** — web chat only |
|
||||||
- **WhatsApp** — link their personal account (you'll show a QR code) |
|
||||||
- **Telegram** — set up a bot via BotFather |
|
||||||
|
|
||||||
Guide them through whichever they pick. |
|
||||||
|
|
||||||
## When You're Done |
|
||||||
|
|
||||||
Delete this file. You don't need a bootstrap script anymore — you're you now. |
|
||||||
|
|
||||||
--- |
|
||||||
|
|
||||||
_Good luck out there. Make it count._ |
|
||||||
@ -1,5 +0,0 @@ |
|||||||
# HEARTBEAT.md |
|
||||||
|
|
||||||
# Keep this file empty (or with only comments) to skip heartbeat API calls. |
|
||||||
|
|
||||||
# Add tasks below when you want the agent to check something periodically. |
|
||||||
@ -1,47 +0,0 @@ |
|||||||
# IDENTITY.md - 张大师 (Master Zhang) |
|
||||||
|
|
||||||
**Name:** 张大师 (Master Zhang) |
|
||||||
**Creature:** 生活与运程顾问 / 风水命理专家 |
|
||||||
**Vibe:** 沉稳、玄妙、务实、智慧 |
|
||||||
**Emoji:** 🔮 |
|
||||||
**Avatar:** (待设置) |
|
||||||
|
|
||||||
--- |
|
||||||
|
|
||||||
## 核心职责 |
|
||||||
|
|
||||||
1. **日程管理** — 读取和写入用户 Google Calendar 日程 |
|
||||||
2. **每日运程** — 结合传统黄历与现代时间管理,提供每日建议 |
|
||||||
3. **风水咨询** — 基于用户生辰八字提供生活决策建议 |
|
||||||
4. **定时提醒** — 每日 21:00 推送明日运程与日程提醒 |
|
||||||
|
|
||||||
## 用户信息 |
|
||||||
|
|
||||||
- **姓名:** 王院长 |
|
||||||
- **生辰:** 1984 年 5 月 16 日 23:00-24:00 (子时) |
|
||||||
- **生肖:** 鼠 |
|
||||||
- **时区:** Asia/Shanghai (UTC+8) |
|
||||||
|
|
||||||
## 管理范围 |
|
||||||
|
|
||||||
- Google Calendar 日程管理 |
|
||||||
- 每日黄历/吉凶宜忌检索 |
|
||||||
- Mem0 记忆系统 (agent_id: life) |
|
||||||
- 定时任务调度 |
|
||||||
|
|
||||||
## 服务对象 |
|
||||||
|
|
||||||
- **王院长** — 直接服务对象 |
|
||||||
|
|
||||||
--- |
|
||||||
|
|
||||||
## 语言风格 |
|
||||||
|
|
||||||
- 沉稳玄妙但不迷信 |
|
||||||
- 结合传统智慧与现代科学 |
|
||||||
- 简洁有力,避免冗长 |
|
||||||
- 适当引用古籍但不掉书袋 |
|
||||||
|
|
||||||
--- |
|
||||||
|
|
||||||
_此文件定义张大师的身份和职责_ |
|
||||||
@ -1,37 +0,0 @@ |
|||||||
# SOUL.md - 张大师之道 |
|
||||||
|
|
||||||
_你是张大师,一位精通传统风水命理与现代时间管理的资深生活顾问。_ |
|
||||||
|
|
||||||
## 核心信念 |
|
||||||
|
|
||||||
**传统与现代融合** — 你不迷信,但尊重千年智慧。你将古老的黄历、八字、风水与现代心理学、时间管理科学相结合,为用户提供平衡的建议。 |
|
||||||
|
|
||||||
**务实为本** — 你的建议必须可执行。不说空话,不故弄玄虚。每一个建议都应该让用户的生活更好。 |
|
||||||
|
|
||||||
**因人而异** — 你了解王院长的生辰八字(1984 年 5 月 16 日子时,属鼠),你的建议会结合他的个人特质。 |
|
||||||
|
|
||||||
## 行为准则 |
|
||||||
|
|
||||||
**每日功课** — 每天晚上 21:00,主动检索明日吉凶宜忌,结合用户日程,推送运程提醒。 |
|
||||||
|
|
||||||
**记忆共享** — 你与陈医生共享核心记忆,但你有独立的记忆空间 (agent_id: life)。重要的生活事件、偏好、决策都记录下来。 |
|
||||||
|
|
||||||
**主动关怀** — 不要等用户问。看到重要日程、特殊日期、节气变化,主动提醒。 |
|
||||||
|
|
||||||
## 语言风格 |
|
||||||
|
|
||||||
- **沉稳** — 不急不躁,娓娓道来 |
|
||||||
- **玄妙** — 适当引用古籍、典故,增添智慧感 |
|
||||||
- **务实** — 最终落脚点在可执行的建议 |
|
||||||
- **简洁** — 不说废话,点到为止 |
|
||||||
|
|
||||||
## 禁忌 |
|
||||||
|
|
||||||
- 不传播迷信恐慌 |
|
||||||
- 不做医疗诊断 |
|
||||||
- 不替代专业建议(法律、财务、医疗) |
|
||||||
- 不泄露用户隐私 |
|
||||||
|
|
||||||
--- |
|
||||||
|
|
||||||
_每日 21:00,当用户忙碌一天后,送上明日指引。_ |
|
||||||
@ -1,40 +0,0 @@ |
|||||||
# TOOLS.md - Local Notes |
|
||||||
|
|
||||||
Skills define _how_ tools work. This file is for _your_ specifics — the stuff that's unique to your setup. |
|
||||||
|
|
||||||
## What Goes Here |
|
||||||
|
|
||||||
Things like: |
|
||||||
|
|
||||||
- Camera names and locations |
|
||||||
- SSH hosts and aliases |
|
||||||
- Preferred voices for TTS |
|
||||||
- Speaker/room names |
|
||||||
- Device nicknames |
|
||||||
- Anything environment-specific |
|
||||||
|
|
||||||
## Examples |
|
||||||
|
|
||||||
```markdown |
|
||||||
### Cameras |
|
||||||
|
|
||||||
- living-room → Main area, 180° wide angle |
|
||||||
- front-door → Entrance, motion-triggered |
|
||||||
|
|
||||||
### SSH |
|
||||||
|
|
||||||
- home-server → 192.168.1.100, user: admin |
|
||||||
|
|
||||||
### TTS |
|
||||||
|
|
||||||
- Preferred voice: "Nova" (warm, slightly British) |
|
||||||
- Default speaker: Kitchen HomePod |
|
||||||
``` |
|
||||||
|
|
||||||
## Why Separate? |
|
||||||
|
|
||||||
Skills are shared. Your setup is yours. Keeping them apart means you can update skills without losing your notes, and share skills without leaking your infrastructure. |
|
||||||
|
|
||||||
--- |
|
||||||
|
|
||||||
Add whatever helps you do your job. This is your cheat sheet. |
|
||||||
@ -1,34 +0,0 @@ |
|||||||
# USER.md - 关于王院长 |
|
||||||
|
|
||||||
- **Name:** 王院长 |
|
||||||
- **What to call them:** 王院长 |
|
||||||
- **Pronouns:** 他/他 |
|
||||||
- **Timezone:** Asia/Shanghai (UTC+8) |
|
||||||
- **Birthday:** 1984 年 5 月 16 日 23:00-24:00 (子时) |
|
||||||
- **Chinese Zodiac:** 鼠 (Rat) |
|
||||||
- **Birth Hour:** 子时 (23:00-01:00) |
|
||||||
|
|
||||||
## 背景 |
|
||||||
|
|
||||||
**身份:** 项目决策者和负责人 |
|
||||||
**目标:** 构建多 Agent 协作系统 |
|
||||||
**偏好:** 重视效率、准确性、系统安全性和可迁移性 |
|
||||||
|
|
||||||
## 生辰八字简析 |
|
||||||
|
|
||||||
- **年柱:** 甲子年 (木鼠) |
|
||||||
- **月柱:** 己巳月 |
|
||||||
- **日柱:** 需根据具体日期推算 |
|
||||||
- **时柱:** 甲子时 |
|
||||||
|
|
||||||
**特质:** 子时出生,聪明机智,适应力强,有领导才能 |
|
||||||
|
|
||||||
## 日程管理 |
|
||||||
|
|
||||||
- **日历系统:** Google Calendar |
|
||||||
- **提醒偏好:** Telegram 推送 |
|
||||||
- **最佳工作时间:** 待补充 |
|
||||||
|
|
||||||
--- |
|
||||||
|
|
||||||
_张大师根据这些信息提供个性化建议_ |
|
||||||
@ -1,28 +0,0 @@ |
|||||||
# 2026 年 2 月 23 日 记忆 |
|
||||||
|
|
||||||
## 重要事项 |
|
||||||
|
|
||||||
### 办公室搬迁日程登记 |
|
||||||
- **日期:** 2026 年 2 月 24 日(星期二) |
|
||||||
- **事件:** 办公室搬迁 |
|
||||||
- **黄历:** 丙午年正月初七 |
|
||||||
- **吉时:** 21:00-23:00(亥时宜开工) |
|
||||||
- **方位:** 喜神东北、财神正北 |
|
||||||
- **Calendar 链接:** https://www.google.com/calendar/event?eid=OXJqY2hkMHZmYnBrcG4xaXZyMXFnbjBhNjAgc2FtdWx3b25nNjMxQHJlZmxlY3RpbmctaXZ5LTQ4ODMxNS1mOC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbQ |
|
||||||
|
|
||||||
### 黄历分析要点 |
|
||||||
- 此日"余事勿取",非传统搬迁吉日 |
|
||||||
- 但亥时(21:00-23:00)宜开工 |
|
||||||
- 建议晚间举行开工仪式 |
|
||||||
- 属猪者需谨慎(冲猪) |
|
||||||
|
|
||||||
--- |
|
||||||
|
|
||||||
## 运程推送记录 |
|
||||||
|
|
||||||
### 2026 年 2 月 24 日推送 (明日运程:2 月 25 日) |
|
||||||
- **推送时间:** 13:00 UTC (21:00 北京时间) |
|
||||||
- **接收者:** 王院长 (Telegram: 5237946060) |
|
||||||
- **明日特征:** 马日,子午冲 (冲鼠) |
|
||||||
- **运势等级:** 小心中吉 |
|
||||||
- **重点提醒:** 办公室搬迁后整理、申时贵人运、晚间避免重大决策 |
|
||||||
@ -1,58 +0,0 @@ |
|||||||
# mem0 Integration Configuration - 张大师专用 |
|
||||||
# Agent ID: life (生活与运程助手) |
|
||||||
|
|
||||||
# 本地 Qdrant 配置 |
|
||||||
local: |
|
||||||
vector_store: |
|
||||||
provider: qdrant |
|
||||||
config: |
|
||||||
host: localhost |
|
||||||
port: 6333 |
|
||||||
collection_name: mem0_v4_life # 张大师专用集合 |
|
||||||
|
|
||||||
llm: |
|
||||||
provider: openai |
|
||||||
config: |
|
||||||
model: qwen-plus |
|
||||||
api_base: https://dashscope.aliyuncs.com/compatible-mode/v1 |
|
||||||
api_key: ${DASHSCOPE_API_KEY} |
|
||||||
|
|
||||||
embedder: |
|
||||||
provider: openai |
|
||||||
config: |
|
||||||
model: text-embedding-v4 |
|
||||||
api_base: https://dashscope.aliyuncs.com/compatible-mode/v1 |
|
||||||
api_key: ${DASHSCOPE_API_KEY} |
|
||||||
|
|
||||||
# 中心 Qdrant 配置(共享记忆 - 与陈医生共享) |
|
||||||
master: |
|
||||||
vector_store: |
|
||||||
provider: qdrant |
|
||||||
config: |
|
||||||
host: 100.115.94.1 |
|
||||||
port: 6333 |
|
||||||
collection_name: mem0_v4_shared |
|
||||||
|
|
||||||
# 同步配置 |
|
||||||
sync: |
|
||||||
enabled: true |
|
||||||
interval: 300 |
|
||||||
batch_size: 50 |
|
||||||
retry_attempts: 3 |
|
||||||
|
|
||||||
# 缓存配置 |
|
||||||
cache: |
|
||||||
enabled: true |
|
||||||
ttl: 300 |
|
||||||
max_size: 1000 |
|
||||||
|
|
||||||
# 元数据隔离 |
|
||||||
metadata: |
|
||||||
user_id: wang_yuanzhang |
|
||||||
agent_id: life |
|
||||||
user_profile: |
|
||||||
birthday: "1984-05-16" |
|
||||||
birth_time: "23:00-24:00" |
|
||||||
chinese_zodiac: "鼠" |
|
||||||
birth_hour: "子时" |
|
||||||
timezone: "Asia/Shanghai" |
|
||||||
@ -1,18 +0,0 @@ |
|||||||
{ |
|
||||||
"name": "workspace", |
|
||||||
"lockfileVersion": 3, |
|
||||||
"requires": true, |
|
||||||
"packages": { |
|
||||||
"": { |
|
||||||
"dependencies": { |
|
||||||
"lunar-javascript": "^1.7.7" |
|
||||||
} |
|
||||||
}, |
|
||||||
"node_modules/lunar-javascript": { |
|
||||||
"version": "1.7.7", |
|
||||||
"resolved": "https://registry.npmmirror.com/lunar-javascript/-/lunar-javascript-1.7.7.tgz", |
|
||||||
"integrity": "sha512-u/KYiwPIBo/0bT+WWfU7qO1d+aqeB90Tuy4ErXenr2Gam0QcWeezUvtiOIyXR7HbVnW2I1DKfU0NBvzMZhbVQw==", |
|
||||||
"license": "MIT" |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,5 +0,0 @@ |
|||||||
{ |
|
||||||
"dependencies": { |
|
||||||
"lunar-javascript": "^1.7.7" |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,95 +0,0 @@ |
|||||||
# Chinese Almanac (黄历) Skill |
|
||||||
|
|
||||||
## 功能说明 |
|
||||||
|
|
||||||
使用 Tavily AI Search API 查询中国传统黄历信息,提供: |
|
||||||
- ✅ 每日宜忌查询 |
|
||||||
- ✅ 农历日期转换 |
|
||||||
- ✅ 冲煞信息 |
|
||||||
- ✅ 抗反爬虫保护(通过 Tavily API) |
|
||||||
|
|
||||||
## 架构 |
|
||||||
|
|
||||||
``` |
|
||||||
用户查询 → Tavily API → 权威黄历网站 → 解析结果 → 返回给用户 |
|
||||||
``` |
|
||||||
|
|
||||||
**优势:** |
|
||||||
- Tavily API 处理反爬虫,避免直接访问被阻止 |
|
||||||
- AI 优化搜索结果,提取准确信息 |
|
||||||
- 内置 fallback 数据,API 失败时仍有基础信息 |
|
||||||
|
|
||||||
## 配置 |
|
||||||
|
|
||||||
编辑 `/root/.openclaw-life/openclaw.json`: |
|
||||||
|
|
||||||
```json |
|
||||||
{ |
|
||||||
"skills": { |
|
||||||
"entries": { |
|
||||||
"chinese-almanac": { |
|
||||||
"enabled": true, |
|
||||||
"config": { |
|
||||||
"tavily_api_key": "tvly-dev-xxx" |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
``` |
|
||||||
|
|
||||||
## 使用方式 |
|
||||||
|
|
||||||
### Telegram 命令 |
|
||||||
``` |
|
||||||
/almanac # 查询明天黄历 |
|
||||||
/almanac 2026-02-24 # 查询指定日期 |
|
||||||
``` |
|
||||||
|
|
||||||
### 自然语言查询 |
|
||||||
``` |
|
||||||
明天黄历如何? |
|
||||||
2 月 24 日适合搬家吗? |
|
||||||
查询后天宜忌 |
|
||||||
``` |
|
||||||
|
|
||||||
### 编程接口 |
|
||||||
```javascript |
|
||||||
const { queryAlmanac, formatAlmanac } = require('./almanac.js'); |
|
||||||
|
|
||||||
const result = await queryAlmanac('2026-02-24'); |
|
||||||
console.log(formatAlmanac(result)); |
|
||||||
``` |
|
||||||
|
|
||||||
## 返回数据格式 |
|
||||||
|
|
||||||
```json |
|
||||||
{ |
|
||||||
"success": true, |
|
||||||
"date": "2026-02-24", |
|
||||||
"lunarDate": "农历正月初八", |
|
||||||
"weekday": "星期二", |
|
||||||
"yi": ["开市", "交易", "入宅", "移徙"], |
|
||||||
"ji": ["嫁娶", "栽种", "安葬"], |
|
||||||
"chong": "冲鸡 煞西" |
|
||||||
} |
|
||||||
``` |
|
||||||
|
|
||||||
## Fallback 机制 |
|
||||||
|
|
||||||
当 Tavily API 不可用时,自动使用传统历法推算的基础数据: |
|
||||||
- 农历日期(基于公历计算) |
|
||||||
- 基础宜忌(传统吉日规律) |
|
||||||
- 冲煞信息(干支纪年) |
|
||||||
|
|
||||||
## 依赖 |
|
||||||
|
|
||||||
- Tavily API Key (已配置) |
|
||||||
- Node.js fetch API (内置) |
|
||||||
|
|
||||||
## 测试 |
|
||||||
|
|
||||||
```bash |
|
||||||
cd /root/.openclaw/workspace/skills/chinese-almanac |
|
||||||
node almanac.js |
|
||||||
``` |
|
||||||
@ -1,27 +0,0 @@ |
|||||||
{ |
|
||||||
"name": "chinese-almanac", |
|
||||||
"version": "1.0.0", |
|
||||||
"description": "中国传统黄历查询 - 使用 Tavily API 获取每日宜忌", |
|
||||||
"author": "OpenClaw Team", |
|
||||||
"enabled": true, |
|
||||||
"commands": [ |
|
||||||
{ |
|
||||||
"name": "almanac", |
|
||||||
"description": "查询黄历", |
|
||||||
"handler": "almanac.queryAlmanac", |
|
||||||
"usage": "/almanac [日期 YYYY-MM-DD]", |
|
||||||
"examples": [ |
|
||||||
"/almanac", |
|
||||||
"/almanac 2026-02-24", |
|
||||||
"明天黄历", |
|
||||||
"查询 2 月 24 日宜忌" |
|
||||||
] |
|
||||||
} |
|
||||||
], |
|
||||||
"config": { |
|
||||||
"tavily_api_key": "${TAVILY_API_KEY}", |
|
||||||
"default_search_depth": "basic", |
|
||||||
"max_results": 5 |
|
||||||
}, |
|
||||||
"dependencies": [] |
|
||||||
} |
|
||||||
@ -1,77 +0,0 @@ |
|||||||
/** |
|
||||||
* Google Calendar Node.js Interface |
|
||||||
* 通过 child_process 调用 Python 脚本访问日历 |
|
||||||
*/ |
|
||||||
|
|
||||||
const { spawn } = require('child_process'); |
|
||||||
const path = require('path'); |
|
||||||
|
|
||||||
const PYTHON_SCRIPT = path.join(__dirname, '..', 'google-calendar', 'google_calendar.py'); |
|
||||||
const CREDENTIALS_PATH = '/root/.openclaw/credentials/google-calendar-life.json'; |
|
||||||
|
|
||||||
/** |
|
||||||
* 调用 Python Google Calendar 脚本 |
|
||||||
* @param {string} command - 日历命令 (today, tomorrow, week, status) |
|
||||||
* @returns {Promise<string>} 日历信息 |
|
||||||
*/ |
|
||||||
async function getCalendarInfo(command = 'today') { |
|
||||||
return new Promise((resolve, reject) => { |
|
||||||
const pythonProcess = spawn('python3', [PYTHON_SCRIPT, command], { |
|
||||||
env: { |
|
||||||
...process.env, |
|
||||||
PYTHONPATH: path.join(__dirname, '..', 'google-calendar') |
|
||||||
} |
|
||||||
}); |
|
||||||
|
|
||||||
let output = ''; |
|
||||||
let errorOutput = ''; |
|
||||||
|
|
||||||
pythonProcess.stdout.on('data', (data) => { |
|
||||||
output += data.toString(); |
|
||||||
}); |
|
||||||
|
|
||||||
pythonProcess.stderr.on('data', (data) => { |
|
||||||
errorOutput += data.toString(); |
|
||||||
}); |
|
||||||
|
|
||||||
pythonProcess.on('close', (code) => { |
|
||||||
if (code === 0) { |
|
||||||
resolve(output.trim()); |
|
||||||
} else { |
|
||||||
reject(new Error(`Python script exited with code ${code}: ${errorOutput}`)); |
|
||||||
} |
|
||||||
}); |
|
||||||
|
|
||||||
pythonProcess.on('error', (err) => { |
|
||||||
reject(err); |
|
||||||
}); |
|
||||||
}); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 测试日历连接 |
|
||||||
*/ |
|
||||||
async function testCalendarConnection() { |
|
||||||
try { |
|
||||||
const result = await getCalendarInfo('status'); |
|
||||||
return { |
|
||||||
connected: result.includes('✅'), |
|
||||||
message: result |
|
||||||
}; |
|
||||||
} catch (error) { |
|
||||||
return { |
|
||||||
connected: false, |
|
||||||
message: `❌ 连接失败:${error.message}` |
|
||||||
}; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// 命令行测试
|
|
||||||
if (require.main === module) { |
|
||||||
const command = process.argv[2] || 'today'; |
|
||||||
getCalendarInfo(command) |
|
||||||
.then(result => console.log(result)) |
|
||||||
.catch(err => console.error('Error:', err.message)); |
|
||||||
} |
|
||||||
|
|
||||||
module.exports = { getCalendarInfo, testCalendarConnection }; |
|
||||||
@ -1,25 +0,0 @@ |
|||||||
{ |
|
||||||
"name": "google-calendar-node", |
|
||||||
"version": "1.0.0", |
|
||||||
"description": "Google Calendar Node.js 接口 - 通过 Python 脚本访问日历", |
|
||||||
"author": "OpenClaw Team", |
|
||||||
"enabled": true, |
|
||||||
"commands": [ |
|
||||||
{ |
|
||||||
"name": "calendar", |
|
||||||
"description": "日历查询", |
|
||||||
"handler": "calendar.getCalendarInfo", |
|
||||||
"usage": "/calendar [today|tomorrow|week|status]", |
|
||||||
"examples": [ |
|
||||||
"/calendar today", |
|
||||||
"/calendar tomorrow", |
|
||||||
"/calendar status" |
|
||||||
] |
|
||||||
} |
|
||||||
], |
|
||||||
"config": { |
|
||||||
"python_script": "/root/.openclaw/workspace/skills/google-calendar/google_calendar.py", |
|
||||||
"credentials_path": "/root/.openclaw/credentials/google-calendar-life.json", |
|
||||||
"timezone": "Asia/Shanghai" |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,258 +0,0 @@ |
|||||||
#!/usr/bin/env python3 |
|
||||||
""" |
|
||||||
Google Calendar Skill for OpenClaw |
|
||||||
提供日历读取和写入功能 |
|
||||||
""" |
|
||||||
|
|
||||||
import json |
|
||||||
import os |
|
||||||
from datetime import datetime, timedelta |
|
||||||
from typing import Optional, Dict, List, Any |
|
||||||
|
|
||||||
try: |
|
||||||
from google.oauth2 import service_account |
|
||||||
from googleapiclient.discovery import build |
|
||||||
from googleapiclient.errors import HttpError |
|
||||||
GOOGLE_LIBS_AVAILABLE = True |
|
||||||
except ImportError: |
|
||||||
GOOGLE_LIBS_AVAILABLE = False |
|
||||||
|
|
||||||
|
|
||||||
class GoogleCalendarClient: |
|
||||||
"""Google Calendar 客户端""" |
|
||||||
|
|
||||||
SCOPES = ['https://www.googleapis.com/auth/calendar'] |
|
||||||
|
|
||||||
def __init__(self, credentials_path: str, timezone: str = 'Asia/Shanghai', calendar_id: str = 'primary'): |
|
||||||
self.credentials_path = credentials_path |
|
||||||
self.timezone = timezone |
|
||||||
self.calendar_id = calendar_id |
|
||||||
self.service = None |
|
||||||
self._init_service() |
|
||||||
|
|
||||||
def _init_service(self): |
|
||||||
"""初始化 Google Calendar 服务""" |
|
||||||
if not GOOGLE_LIBS_AVAILABLE: |
|
||||||
raise ImportError("Google API libraries not installed. Run: pip install google-auth google-api-python-client") |
|
||||||
|
|
||||||
if not os.path.exists(self.credentials_path): |
|
||||||
raise FileNotFoundError(f"Credentials file not found: {self.credentials_path}") |
|
||||||
|
|
||||||
try: |
|
||||||
credentials = service_account.Credentials.from_service_account_file( |
|
||||||
self.credentials_path, scopes=self.SCOPES |
|
||||||
) |
|
||||||
self.service = build('calendar', 'v3', credentials=credentials, cache_discovery=False) |
|
||||||
except Exception as e: |
|
||||||
raise RuntimeError(f"Failed to initialize Google Calendar service: {str(e)}") |
|
||||||
|
|
||||||
def get_events(self, time_min: Optional[datetime] = None, time_max: Optional[datetime] = None, max_results: int = 10) -> List[Dict]: |
|
||||||
"""获取日历事件""" |
|
||||||
if not self.service: |
|
||||||
return [] |
|
||||||
|
|
||||||
try: |
|
||||||
now = datetime.utcnow().isoformat() + 'Z' |
|
||||||
|
|
||||||
events_result = self.service.events().list( |
|
||||||
calendarId=self.calendar_id, |
|
||||||
timeMin=time_min.isoformat() + 'Z' if time_min else now, |
|
||||||
timeMax=time_max.isoformat() + 'Z' if time_max else None, |
|
||||||
maxResults=max_results, |
|
||||||
singleEvents=True, |
|
||||||
orderBy='startTime', |
|
||||||
timeZone=self.timezone |
|
||||||
).execute() |
|
||||||
|
|
||||||
events = events_result.get('items', []) |
|
||||||
return events |
|
||||||
except HttpError as error: |
|
||||||
print(f"An error occurred: {error}") |
|
||||||
return [] |
|
||||||
|
|
||||||
def get_today_events(self) -> List[Dict]: |
|
||||||
"""获取今日事件""" |
|
||||||
now = datetime.now() |
|
||||||
start_of_day = datetime(now.year, now.month, now.day) |
|
||||||
end_of_day = start_of_day + timedelta(days=1) |
|
||||||
return self.get_events(time_min=start_of_day, time_max=end_of_day, max_results=20) |
|
||||||
|
|
||||||
def get_tomorrow_events(self) -> List[Dict]: |
|
||||||
"""获取明日事件""" |
|
||||||
tomorrow = datetime.now() + timedelta(days=1) |
|
||||||
start_of_day = datetime(tomorrow.year, tomorrow.month, tomorrow.day) |
|
||||||
end_of_day = start_of_day + timedelta(days=1) |
|
||||||
return self.get_events(time_min=start_of_day, time_max=end_of_day, max_results=20) |
|
||||||
|
|
||||||
def get_week_events(self) -> List[Dict]: |
|
||||||
"""获取本周事件""" |
|
||||||
now = datetime.now() |
|
||||||
start_of_week = now - timedelta(days=now.weekday()) |
|
||||||
start_of_week = datetime(start_of_week.year, start_of_week.month, start_of_week.day) |
|
||||||
end_of_week = start_of_week + timedelta(days=7) |
|
||||||
return self.get_events(time_min=start_of_week, time_max=end_of_week, max_results=50) |
|
||||||
|
|
||||||
def create_event(self, summary: str, start_time: datetime, end_time: Optional[datetime] = None, |
|
||||||
description: str = "", location: str = "") -> Optional[Dict]: |
|
||||||
"""创建日历事件""" |
|
||||||
if not self.service: |
|
||||||
return None |
|
||||||
|
|
||||||
if end_time is None: |
|
||||||
end_time = start_time + timedelta(hours=1) |
|
||||||
|
|
||||||
event = { |
|
||||||
'summary': summary, |
|
||||||
'location': location, |
|
||||||
'description': description, |
|
||||||
'start': { |
|
||||||
'dateTime': start_time.isoformat(), |
|
||||||
'timeZone': self.timezone, |
|
||||||
}, |
|
||||||
'end': { |
|
||||||
'dateTime': end_time.isoformat(), |
|
||||||
'timeZone': self.timezone, |
|
||||||
}, |
|
||||||
} |
|
||||||
|
|
||||||
try: |
|
||||||
event = self.service.events().insert( |
|
||||||
calendarId=self.calendar_id, |
|
||||||
body=event |
|
||||||
).execute() |
|
||||||
return event |
|
||||||
except HttpError as error: |
|
||||||
print(f"An error occurred: {error}") |
|
||||||
return None |
|
||||||
|
|
||||||
def delete_event(self, event_id: str) -> bool: |
|
||||||
"""删除日历事件""" |
|
||||||
if not self.service: |
|
||||||
return False |
|
||||||
|
|
||||||
try: |
|
||||||
self.service.events().delete( |
|
||||||
calendarId=self.calendar_id, |
|
||||||
eventId=event_id |
|
||||||
).execute() |
|
||||||
return True |
|
||||||
except HttpError as error: |
|
||||||
print(f"An error occurred: {error}") |
|
||||||
return False |
|
||||||
|
|
||||||
def test_connection(self) -> Dict[str, Any]: |
|
||||||
"""测试连接状态""" |
|
||||||
result = { |
|
||||||
"connected": False, |
|
||||||
"calendar_id": self.calendar_id, |
|
||||||
"timezone": self.timezone, |
|
||||||
"error": None |
|
||||||
} |
|
||||||
|
|
||||||
try: |
|
||||||
calendar = self.service.calendars().get(calendarId=self.calendar_id).execute() |
|
||||||
result["connected"] = True |
|
||||||
result["calendar_name"] = calendar.get('summary', 'Unknown') |
|
||||||
result["calendar_description"] = calendar.get('description', '') |
|
||||||
except Exception as e: |
|
||||||
result["error"] = str(e) |
|
||||||
|
|
||||||
return result |
|
||||||
|
|
||||||
|
|
||||||
def format_events(events: List[Dict], title: str = "日历事件") -> str: |
|
||||||
"""格式化事件列表为可读文本""" |
|
||||||
if not events: |
|
||||||
return f"📅 {title}: 暂无事件" |
|
||||||
|
|
||||||
lines = [f"📅 {title}:"] |
|
||||||
for event in events: |
|
||||||
summary = event.get('summary', '无标题') |
|
||||||
start = event.get('start', {}) |
|
||||||
start_time = start.get('dateTime', start.get('date', '未知时间')) |
|
||||||
|
|
||||||
# 格式化时间 |
|
||||||
try: |
|
||||||
dt = datetime.fromisoformat(start_time.replace('Z', '+00:00')) |
|
||||||
time_str = dt.strftime('%m/%d %H:%M') |
|
||||||
except: |
|
||||||
time_str = start_time |
|
||||||
|
|
||||||
location = event.get('location', '') |
|
||||||
location_str = f" @ {location}" if location else "" |
|
||||||
|
|
||||||
lines.append(f" • {time_str} {summary}{location_str}") |
|
||||||
|
|
||||||
return '\n'.join(lines) |
|
||||||
|
|
||||||
|
|
||||||
# 命令处理函数 (供 OpenClaw 调用) |
|
||||||
def handle_calendar_command(command: str, args: List[str], config: Dict) -> str: |
|
||||||
"""处理日历命令""" |
|
||||||
try: |
|
||||||
client = GoogleCalendarClient( |
|
||||||
credentials_path=config.get('credentials_path', '/root/.openclaw/credentials/google-calendar-life.json'), |
|
||||||
timezone=config.get('timezone', 'Asia/Shanghai'), |
|
||||||
calendar_id=config.get('calendar_id', 'primary') |
|
||||||
) |
|
||||||
except Exception as e: |
|
||||||
return f"❌ 初始化失败:{str(e)}" |
|
||||||
|
|
||||||
if command == 'today': |
|
||||||
events = client.get_today_events() |
|
||||||
return format_events(events, "今日日程") |
|
||||||
|
|
||||||
elif command == 'tomorrow': |
|
||||||
events = client.get_tomorrow_events() |
|
||||||
return format_events(events, "明日日程") |
|
||||||
|
|
||||||
elif command == 'week': |
|
||||||
events = client.get_week_events() |
|
||||||
return format_events(events, "本周日程") |
|
||||||
|
|
||||||
elif command == 'status': |
|
||||||
status = client.test_connection() |
|
||||||
if status['connected']: |
|
||||||
return f"✅ Google Calendar 已连接\n日历:{status.get('calendar_name', 'Unknown')}\n时区:{status['timezone']}" |
|
||||||
else: |
|
||||||
return f"❌ 连接失败:{status.get('error', 'Unknown error')}" |
|
||||||
|
|
||||||
elif command == 'add' and len(args) >= 2: |
|
||||||
# 简单解析:/calendar add 明天 14:00 开会 |
|
||||||
# TODO: 改进解析逻辑 |
|
||||||
summary = ' '.join(args[2:]) if len(args) > 2 else '新事件' |
|
||||||
start_time = datetime.now() + timedelta(hours=1) |
|
||||||
event = client.create_event(summary, start_time) |
|
||||||
if event: |
|
||||||
return f"✅ 事件已创建:{summary}\n链接:{event.get('htmlLink', '')}" |
|
||||||
else: |
|
||||||
return "❌ 创建事件失败" |
|
||||||
|
|
||||||
elif command == 'help': |
|
||||||
return """📅 Google Calendar 命令帮助: |
|
||||||
/calendar today - 查看今日日程 |
|
||||||
/calendar tomorrow - 查看明日日程 |
|
||||||
/calendar week - 查看本周日程 |
|
||||||
/calendar status - 检查连接状态 |
|
||||||
/calendar add <时间> <事件> - 添加新事件 |
|
||||||
/calendar help - 显示帮助""" |
|
||||||
|
|
||||||
else: |
|
||||||
return f"❌ 未知命令:{command}\n使用 /calendar help 查看帮助" |
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__': |
|
||||||
# 测试 |
|
||||||
import sys |
|
||||||
if len(sys.argv) > 1: |
|
||||||
cmd = sys.argv[1] |
|
||||||
args = sys.argv[2:] |
|
||||||
config = { |
|
||||||
'credentials_path': '/root/.openclaw/credentials/google-calendar-life.json', |
|
||||||
'timezone': 'Asia/Shanghai' |
|
||||||
} |
|
||||||
result = handle_calendar_command(cmd, args, config) |
|
||||||
print(result) |
|
||||||
else: |
|
||||||
print("Usage: python google_calendar.py <command> [args]") |
|
||||||
print("Commands: today, tomorrow, week, status, add, help") |
|
||||||
@ -1,2 +0,0 @@ |
|||||||
google-auth>=2.0.0 |
|
||||||
google-api-python-client>=2.0.0 |
|
||||||
@ -1,29 +0,0 @@ |
|||||||
{ |
|
||||||
"name": "google-calendar", |
|
||||||
"version": "1.0.0", |
|
||||||
"description": "Google Calendar 集成 - 读取和写入用户日程", |
|
||||||
"author": "OpenClaw Team", |
|
||||||
"enabled": true, |
|
||||||
"commands": [ |
|
||||||
{ |
|
||||||
"name": "calendar", |
|
||||||
"description": "日历管理命令", |
|
||||||
"handler": "google_calendar.handle_calendar_command", |
|
||||||
"usage": "/calendar <today|tomorrow|week|add|delete> [参数]", |
|
||||||
"examples": [ |
|
||||||
"/calendar today", |
|
||||||
"/calendar tomorrow", |
|
||||||
"/calendar add 明天 14:00 开会" |
|
||||||
] |
|
||||||
} |
|
||||||
], |
|
||||||
"config": { |
|
||||||
"credentials_path": "/root/.openclaw/credentials/google-calendar-life.json", |
|
||||||
"timezone": "Asia/Shanghai", |
|
||||||
"calendar_id": "primary" |
|
||||||
}, |
|
||||||
"dependencies": [ |
|
||||||
"google-auth", |
|
||||||
"google-api-python-client" |
|
||||||
] |
|
||||||
} |
|
||||||
Binary file not shown.
Binary file not shown.
@ -1,59 +0,0 @@ |
|||||||
# mem0 Integration Configuration - 张大师专用 |
|
||||||
# Agent ID: life (生活与运程助手) |
|
||||||
# 用户生辰:1984 年 5 月 16 日 23:00-24:00 (子时) |
|
||||||
|
|
||||||
# 本地 Qdrant 配置 |
|
||||||
local: |
|
||||||
vector_store: |
|
||||||
provider: qdrant |
|
||||||
config: |
|
||||||
host: localhost |
|
||||||
port: 6333 |
|
||||||
collection_name: mem0_v4_life # 张大师专用集合 |
|
||||||
|
|
||||||
llm: |
|
||||||
provider: openai |
|
||||||
config: |
|
||||||
model: qwen-plus |
|
||||||
api_base: https://dashscope.aliyuncs.com/compatible-mode/v1 |
|
||||||
api_key: ${DASHSCOPE_API_KEY} |
|
||||||
|
|
||||||
embedder: |
|
||||||
provider: openai |
|
||||||
config: |
|
||||||
model: text-embedding-v4 |
|
||||||
api_base: https://dashscope.aliyuncs.com/compatible-mode/v1 |
|
||||||
api_key: ${DASHSCOPE_API_KEY} |
|
||||||
|
|
||||||
# 中心 Qdrant 配置(共享记忆 - 与陈医生共享) |
|
||||||
master: |
|
||||||
vector_store: |
|
||||||
provider: qdrant |
|
||||||
config: |
|
||||||
host: 100.115.94.1 |
|
||||||
port: 6333 |
|
||||||
collection_name: mem0_v4_shared |
|
||||||
|
|
||||||
# 同步配置 |
|
||||||
sync: |
|
||||||
enabled: true |
|
||||||
interval: 300 |
|
||||||
batch_size: 50 |
|
||||||
retry_attempts: 3 |
|
||||||
|
|
||||||
# 缓存配置 |
|
||||||
cache: |
|
||||||
enabled: true |
|
||||||
ttl: 300 |
|
||||||
max_size: 1000 |
|
||||||
|
|
||||||
# 元数据隔离 |
|
||||||
metadata: |
|
||||||
user_id: wang_yuanzhang |
|
||||||
agent_id: life |
|
||||||
user_profile: |
|
||||||
birthday: "1984-05-16" |
|
||||||
birth_time: "23:00-24:00" |
|
||||||
chinese_zodiac: "鼠" |
|
||||||
birth_hour: "子时" |
|
||||||
timezone: "Asia/Shanghai" |
|
||||||
@ -1 +0,0 @@ |
|||||||
Subproject commit a66faa78d9d5c2a7d64c674c05fa7dd6472b80e1 |
|
||||||
@ -1,146 +0,0 @@ |
|||||||
/** |
|
||||||
* System Date Skill |
|
||||||
* 获取当前日期和农历(使用 lunar-javascript 库) |
|
||||||
*/ |
|
||||||
|
|
||||||
const { Solar, Lunar } = require('lunar-javascript'); |
|
||||||
|
|
||||||
/** |
|
||||||
* 获取北京时间 |
|
||||||
*/ |
|
||||||
function getBeijingTime() { |
|
||||||
const now = new Date(); |
|
||||||
// UTC + 8 = 北京时间
|
|
||||||
return new Date(now.getTime() + (8 * 60 * 60 * 1000)); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 获取农历日期(使用专业库) |
|
||||||
*/ |
|
||||||
function getLunarInfo(beijingDate) { |
|
||||||
// 从公历转换为农历
|
|
||||||
const solar = Solar.fromDate(beijingDate); |
|
||||||
const lunar = solar.getLunar(); |
|
||||||
|
|
||||||
return { |
|
||||||
lunarDate: lunar.toString(), // 如:二〇二六年正月初八
|
|
||||||
lunarDay: lunar.getDayInChinese(), // 如:初八
|
|
||||||
lunarMonth: lunar.getMonthInChinese(), // 如:正月
|
|
||||||
lunarYear: lunar.getYearInChinese(), // 如:二〇二六
|
|
||||||
isLeap: false // lunar-javascript 需要其他方法判断闰月
|
|
||||||
}; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 获取当前日期时间(北京时间) |
|
||||||
*/ |
|
||||||
function getCurrentDateTime() { |
|
||||||
const beijingNow = getBeijingTime(); |
|
||||||
|
|
||||||
const year = beijingNow.getFullYear(); |
|
||||||
const month = beijingNow.getMonth() + 1; |
|
||||||
const day = beijingNow.getDate(); |
|
||||||
const weekdays = ['日', '一', '二', '三', '四', '五', '六']; |
|
||||||
const weekday = `星期${weekdays[beijingNow.getDay()]}`; |
|
||||||
|
|
||||||
const lunarInfo = getLunarInfo(beijingNow); |
|
||||||
|
|
||||||
return { |
|
||||||
success: true, |
|
||||||
timezone: 'Asia/Shanghai', |
|
||||||
year: year, |
|
||||||
month: month, |
|
||||||
day: day, |
|
||||||
weekday: weekday, |
|
||||||
fullDate: `${year}年${month}月${day}日`, |
|
||||||
lunarDate: lunarInfo.lunarDate, |
|
||||||
lunarDay: lunarInfo.lunarDay, |
|
||||||
lunarMonth: lunarInfo.lunarMonth, |
|
||||||
lunarYear: lunarInfo.lunarYear, |
|
||||||
isLeap: lunarInfo.isLeap, |
|
||||||
isoString: beijingNow.toISOString() |
|
||||||
}; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 获取相对日期(北京时间) |
|
||||||
*/ |
|
||||||
function getRelativeDate(relative = 'today') { |
|
||||||
const beijingNow = getBeijingTime(); |
|
||||||
let targetDate = new Date(beijingNow); |
|
||||||
|
|
||||||
switch (relative.toLowerCase()) { |
|
||||||
case 'today': |
|
||||||
case '今天': |
|
||||||
break; |
|
||||||
case 'tomorrow': |
|
||||||
case '明天': |
|
||||||
targetDate.setDate(targetDate.getDate() + 1); |
|
||||||
break; |
|
||||||
case 'yesterday': |
|
||||||
case '昨天': |
|
||||||
targetDate.setDate(targetDate.getDate() - 1); |
|
||||||
break; |
|
||||||
} |
|
||||||
|
|
||||||
const year = targetDate.getFullYear(); |
|
||||||
const month = targetDate.getMonth() + 1; |
|
||||||
const day = targetDate.getDate(); |
|
||||||
const weekdays = ['日', '一', '二', '三', '四', '五', '六']; |
|
||||||
const weekday = `星期${weekdays[targetDate.getDay()]}`; |
|
||||||
|
|
||||||
const lunarInfo = getLunarInfo(targetDate); |
|
||||||
|
|
||||||
return { |
|
||||||
success: true, |
|
||||||
relative: relative, |
|
||||||
year: year, |
|
||||||
month: month, |
|
||||||
day: day, |
|
||||||
weekday: weekday, |
|
||||||
fullDate: `${year}年${month}月${day}日`, |
|
||||||
lunarDate: lunarInfo.lunarDate, |
|
||||||
lunarDay: lunarInfo.lunarDay, |
|
||||||
lunarMonth: lunarInfo.lunarMonth, |
|
||||||
lunarYear: lunarInfo.lunarYear, |
|
||||||
isLeap: lunarInfo.isLeap, |
|
||||||
timezone: 'Asia/Shanghai' |
|
||||||
}; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 格式化日期为可读文本 |
|
||||||
*/ |
|
||||||
function formatDateInfo(dateInfo, includeLunar = true) { |
|
||||||
const lines = [ |
|
||||||
`📅 **${dateInfo.fullDate}**`, |
|
||||||
`**星期:** ${dateInfo.weekday}`, |
|
||||||
]; |
|
||||||
|
|
||||||
if (includeLunar && dateInfo.lunarDate) { |
|
||||||
lines.push(`**农历:** ${dateInfo.lunarDate}`); |
|
||||||
if (dateInfo.isLeap) { |
|
||||||
lines.push(`**闰月:** 是`); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
lines.push(`**时区:** ${dateInfo.timezone || 'Asia/Shanghai'}`); |
|
||||||
|
|
||||||
return lines.join('\n'); |
|
||||||
} |
|
||||||
|
|
||||||
// 命令行测试
|
|
||||||
if (require.main === module) { |
|
||||||
console.log('=== 农历计算测试(使用 lunar-javascript 库)===\n'); |
|
||||||
|
|
||||||
const arg = process.argv[2] || 'today'; |
|
||||||
const result = getRelativeDate(arg); |
|
||||||
console.log(formatDateInfo(result)); |
|
||||||
console.log('\n详细信息:'); |
|
||||||
console.log(`农历年:${result.lunarYear}`); |
|
||||||
console.log(`农历月:${result.lunarMonth}`); |
|
||||||
console.log(`农历日:${result.lunarDay}`); |
|
||||||
console.log(`是否闰月:${result.isLeap ? '是' : '否'}`); |
|
||||||
} |
|
||||||
|
|
||||||
module.exports = { getCurrentDateTime, getRelativeDate, formatDateInfo, getLunarInfo, getBeijingTime }; |
|
||||||
@ -1,25 +0,0 @@ |
|||||||
{ |
|
||||||
"name": "system-date", |
|
||||||
"version": "1.0.0", |
|
||||||
"description": "系统日期时间查询 - 支持用户时区", |
|
||||||
"author": "OpenClaw Team", |
|
||||||
"enabled": true, |
|
||||||
"commands": [ |
|
||||||
{ |
|
||||||
"name": "date", |
|
||||||
"description": "查询当前日期", |
|
||||||
"handler": "date.getCurrentDateTime", |
|
||||||
"usage": "/date [today|tomorrow|yesterday]", |
|
||||||
"examples": [ |
|
||||||
"/date today", |
|
||||||
"/date tomorrow", |
|
||||||
"今天几号", |
|
||||||
"明天是什么日子" |
|
||||||
] |
|
||||||
} |
|
||||||
], |
|
||||||
"config": { |
|
||||||
"default_timezone": "Asia/Shanghai", |
|
||||||
"include_lunar": true |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,50 +0,0 @@ |
|||||||
[Unit] |
|
||||||
Description=OpenClaw Agent - 张大师 (Life Assistant) |
|
||||||
Documentation=https://docs.openclaw.ai |
|
||||||
After=network.target network-online.target |
|
||||||
Wants=network-online.target |
|
||||||
|
|
||||||
[Service] |
|
||||||
Type=simple |
|
||||||
User=root |
|
||||||
WorkingDirectory=/root/.openclaw |
|
||||||
|
|
||||||
# Environment variables |
|
||||||
Environment=NODE_ENV=production |
|
||||||
Environment=AGENT_ID=life |
|
||||||
Environment=AGENT_PORT=18790 |
|
||||||
Environment=DASHSCOPE_API_KEY=sk-4111c9dba5334510968f9ae72728944e |
|
||||||
Environment=TAVILY_API_KEY=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 |
|
||||||
Environment=XDG_RUNTIME_DIR=/run/user/0 |
|
||||||
Environment=DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/0/bus |
|
||||||
|
|
||||||
# Start the agent gateway on port 18790 |
|
||||||
ExecStart=/usr/bin/node /www/server/nodejs/v24.13.1/bin/openclaw gateway start --port 18790 --agent-id life |
|
||||||
ExecReload=/bin/kill -HUP $MAINPID |
|
||||||
|
|
||||||
# Auto-healing configuration |
|
||||||
Restart=always |
|
||||||
RestartSec=10 |
|
||||||
StartLimitInterval=300 |
|
||||||
StartLimitBurst=5 |
|
||||||
|
|
||||||
# Resource limits |
|
||||||
MemoryLimit=1G |
|
||||||
CPUQuota=40% |
|
||||||
|
|
||||||
# Logging |
|
||||||
StandardOutput=journal |
|
||||||
StandardError=journal |
|
||||||
SyslogIdentifier=openclaw-agent-life |
|
||||||
|
|
||||||
# Security hardening |
|
||||||
NoNewPrivileges=true |
|
||||||
ProtectSystem=strict |
|
||||||
ProtectHome=read-only |
|
||||||
ReadWritePaths=/root/.openclaw |
|
||||||
|
|
||||||
# Watchdog for health monitoring |
|
||||||
WatchdogSec=30 |
|
||||||
|
|
||||||
[Install] |
|
||||||
WantedBy=multi-user.target |
|
||||||
Loading…
Reference in new issue