Initial commit: Hermes Agent skills collection
- Trading skills (OKX, dividend, lottery, quantitative) - Creative skills (ASCII art, diagrams, video) - Development skills (GitHub, debugging, TDD) - Research skills (arXiv, blog monitoring) - Productivity skills (email, documents, notes) - MCP integration skills - Custom user skills
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"version": 1,
|
||||
"registry": "https://clawhub.ai",
|
||||
"slug": "1password",
|
||||
"installedVersion": "1.0.1",
|
||||
"installedAt": 1777394360169
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
---
|
||||
name: 1password
|
||||
description: Set up and use 1Password CLI (op). Use when installing the CLI, enabling desktop app integration, signing in (single or multi-account), or reading/injecting/running secrets via op.
|
||||
homepage: https://developer.1password.com/docs/cli/get-started/
|
||||
metadata: {"clawdbot":{"emoji":"🔐","requires":{"bins":["op"]},"install":[{"id":"brew","kind":"brew","formula":"1password-cli","bins":["op"],"label":"Install 1Password CLI (brew)"}]}}
|
||||
---
|
||||
|
||||
# 1Password CLI
|
||||
|
||||
Follow the official CLI get-started steps. Don't guess install commands.
|
||||
|
||||
## References
|
||||
|
||||
- `references/get-started.md` (install + app integration + sign-in flow)
|
||||
- `references/cli-examples.md` (real `op` examples)
|
||||
|
||||
## Workflow
|
||||
|
||||
1. Check OS + shell.
|
||||
2. Verify CLI present: `op --version`.
|
||||
3. Confirm desktop app integration is enabled (per get-started) and the app is unlocked.
|
||||
4. REQUIRED: create a fresh tmux session for all `op` commands (no direct `op` calls outside tmux).
|
||||
5. Sign in / authorize inside tmux: `op signin` (expect app prompt).
|
||||
6. Verify access inside tmux: `op whoami` (must succeed before any secret read).
|
||||
7. If multiple accounts: use `--account` or `OP_ACCOUNT`.
|
||||
|
||||
## REQUIRED tmux session (T-Max)
|
||||
|
||||
The shell tool uses a fresh TTY per command. To avoid re-prompts and failures, always run `op` inside a dedicated tmux session with a fresh socket/session name.
|
||||
|
||||
Example (see `tmux` skill for socket conventions, do not reuse old session names):
|
||||
|
||||
```bash
|
||||
SOCKET_DIR="${CLAWDBOT_TMUX_SOCKET_DIR:-${TMPDIR:-/tmp}/clawdbot-tmux-sockets}"
|
||||
mkdir -p "$SOCKET_DIR"
|
||||
SOCKET="$SOCKET_DIR/clawdbot-op.sock"
|
||||
SESSION="op-auth-$(date +%Y%m%d-%H%M%S)"
|
||||
|
||||
tmux -S "$SOCKET" new -d -s "$SESSION" -n shell
|
||||
tmux -S "$SOCKET" send-keys -t "$SESSION":0.0 -- "op signin --account my.1password.com" Enter
|
||||
tmux -S "$SOCKET" send-keys -t "$SESSION":0.0 -- "op whoami" Enter
|
||||
tmux -S "$SOCKET" send-keys -t "$SESSION":0.0 -- "op vault list" Enter
|
||||
tmux -S "$SOCKET" capture-pane -p -J -t "$SESSION":0.0 -S -200
|
||||
tmux -S "$SOCKET" kill-session -t "$SESSION"
|
||||
```
|
||||
|
||||
## Guardrails
|
||||
|
||||
- Never paste secrets into logs, chat, or code.
|
||||
- Prefer `op run` / `op inject` over writing secrets to disk.
|
||||
- If sign-in without app integration is needed, use `op account add`.
|
||||
- If a command returns "account is not signed in", re-run `op signin` inside tmux and authorize in the app.
|
||||
- Do not run `op` outside tmux; stop and ask if tmux is unavailable.
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"ownerId": "kn70pywhg0fyz996kpa8xj89s57yhv26",
|
||||
"slug": "1password",
|
||||
"version": "1.0.1",
|
||||
"publishedAt": 1767814883922
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
# op CLI examples (from op help)
|
||||
|
||||
## Sign in
|
||||
|
||||
- `op signin`
|
||||
- `op signin --account <shorthand|signin-address|account-id|user-id>`
|
||||
|
||||
## Read
|
||||
|
||||
- `op read op://app-prod/db/password`
|
||||
- `op read "op://app-prod/db/one-time password?attribute=otp"`
|
||||
- `op read "op://app-prod/ssh key/private key?ssh-format=openssh"`
|
||||
- `op read --out-file ./key.pem op://app-prod/server/ssh/key.pem`
|
||||
|
||||
## Run
|
||||
|
||||
- `export DB_PASSWORD="op://app-prod/db/password"`
|
||||
- `op run --no-masking -- printenv DB_PASSWORD`
|
||||
- `op run --env-file="./.env" -- printenv DB_PASSWORD`
|
||||
|
||||
## Inject
|
||||
|
||||
- `echo "db_password: {{ op://app-prod/db/password }}" | op inject`
|
||||
- `op inject -i config.yml.tpl -o config.yml`
|
||||
|
||||
## Whoami / accounts
|
||||
|
||||
- `op whoami`
|
||||
- `op account list`
|
||||
@@ -0,0 +1,17 @@
|
||||
# 1Password CLI get-started (summary)
|
||||
|
||||
- Works on macOS, Windows, and Linux.
|
||||
- macOS/Linux shells: bash, zsh, sh, fish.
|
||||
- Windows shell: PowerShell.
|
||||
- Requires a 1Password subscription and the desktop app to use app integration.
|
||||
- macOS requirement: Big Sur 11.0.0 or later.
|
||||
- Linux app integration requires PolKit + an auth agent.
|
||||
- Install the CLI per the official doc for your OS.
|
||||
- Enable desktop app integration in the 1Password app:
|
||||
- Open and unlock the app, then select your account/collection.
|
||||
- macOS: Settings > Developer > Integrate with 1Password CLI (Touch ID optional).
|
||||
- Windows: turn on Windows Hello, then Settings > Developer > Integrate.
|
||||
- Linux: Settings > Security > Unlock using system authentication, then Settings > Developer > Integrate.
|
||||
- After integration, run any command to sign in (example in docs: `op vault list`).
|
||||
- If multiple accounts: use `op signin` to pick one, or `--account` / `OP_ACCOUNT`.
|
||||
- For non-integration auth, use `op account add`.
|
||||
@@ -0,0 +1 @@
|
||||
Skills migrated from an OpenClaw workspace.
|
||||
@@ -0,0 +1,18 @@
|
||||
# Changelog
|
||||
|
||||
## v2.1.0 (2026-04-11)
|
||||
- Version bump to 2.1.0
|
||||
|
||||
## v2.0.1 (2026-02-06)
|
||||
- Simplified documentation
|
||||
- Removed gov-related content
|
||||
- Optimized for ClawHub publishing
|
||||
|
||||
## v2.0.0 (2026-02-06)
|
||||
- Added 9 international search engines
|
||||
- Enhanced advanced search capabilities
|
||||
- Added DuckDuckGo Bangs support
|
||||
- Added WolframAlpha knowledge queries
|
||||
|
||||
## v1.0.0 (2026-02-04)
|
||||
- Initial release with 8 domestic search engines
|
||||
@@ -0,0 +1,48 @@
|
||||
# Multi Search Engine
|
||||
|
||||
## 基本信息
|
||||
|
||||
- **名称**: multi-search-engine
|
||||
- **版本**: v2.0.1
|
||||
- **描述**: 集成16个搜索引擎(7国内+9国际),支持高级搜索语法
|
||||
- **发布时间**: 2026-02-06
|
||||
|
||||
## 搜索引擎
|
||||
|
||||
**国内(7个)**: 百度、必应CN、必应INT、360、搜狗、微信、神马
|
||||
**国际(9个)**: Google、Google HK、DuckDuckGo、Yahoo、Startpage、Brave、Ecosia、Qwant、WolframAlpha
|
||||
|
||||
## 核心功能
|
||||
|
||||
- 高级搜索操作符(site:, filetype:, intitle:等)
|
||||
- DuckDuckGo Bangs快捷命令
|
||||
- 时间筛选(小时/天/周/月/年)
|
||||
- 隐私保护搜索
|
||||
- WolframAlpha知识计算
|
||||
|
||||
## 更新记录
|
||||
|
||||
### v2.0.1 (2026-02-06)
|
||||
- 精简文档,优化发布
|
||||
|
||||
### v2.0.0 (2026-02-06)
|
||||
- 新增9个国际搜索引擎
|
||||
- 强化深度搜索能力
|
||||
|
||||
### v1.0.0 (2026-02-04)
|
||||
- 初始版本:8个国内搜索引擎
|
||||
|
||||
## 使用示例
|
||||
|
||||
```javascript
|
||||
// Google搜索
|
||||
web_fetch({"url": "https://www.google.com/search?q=python"})
|
||||
|
||||
// 隐私搜索
|
||||
web_fetch({"url": "https://duckduckgo.com/html/?q=privacy"})
|
||||
|
||||
// 站内搜索
|
||||
web_fetch({"url": "https://www.google.com/search?q=site:github.com+python"})
|
||||
```
|
||||
|
||||
MIT License
|
||||
@@ -0,0 +1,5 @@
|
||||
## Self-Improving Check
|
||||
|
||||
- Read `./skills/self-improving/heartbeat-rules.md`
|
||||
- Use `~/self-improving/heartbeat-state.md` for last-run markers and action notes
|
||||
- If no file inside `~/self-improving/` changed since the last reviewed change, return `HEARTBEAT_OK`
|
||||
@@ -0,0 +1,250 @@
|
||||
---
|
||||
name: Self-Improving + Proactive Agent
|
||||
slug: self-improving
|
||||
version: 1.2.16
|
||||
homepage: https://clawic.com/skills/self-improving
|
||||
description: "Self-reflection + Self-criticism + Self-learning + Self-organizing memory. Agent evaluates its own work, catches mistakes, and improves permanently. Use when (1) a command, tool, API, or operation fails; (2) the user corrects you or rejects your work; (3) you realize your knowledge is outdated or incorrect; (4) you discover a better approach; (5) the user explicitly installs or references the skill for the current task."
|
||||
changelog: "Clarifies the setup flow for proactive follow-through and safer installation behavior."
|
||||
metadata: {"clawdbot":{"emoji":"🧠","requires":{"bins":[]},"os":["linux","darwin","win32"],"configPaths":["~/self-improving/"],"configPaths.optional":["./AGENTS.md","./SOUL.md","./HEARTBEAT.md"]}}
|
||||
---
|
||||
|
||||
## When to Use
|
||||
|
||||
User corrects you or points out mistakes. You complete significant work and want to evaluate the outcome. You notice something in your own output that could be better. Knowledge should compound over time without manual maintenance.
|
||||
|
||||
## Architecture
|
||||
|
||||
Memory lives in `~/self-improving/` with tiered structure. If `~/self-improving/` does not exist, run `setup.md`.
|
||||
Workspace setup should add the standard self-improving steering to the workspace AGENTS, SOUL, and `HEARTBEAT.md` files, with recurring maintenance routed through `heartbeat-rules.md`.
|
||||
|
||||
```
|
||||
~/self-improving/
|
||||
├── memory.md # HOT: ≤100 lines, always loaded
|
||||
├── index.md # Topic index with line counts
|
||||
├── heartbeat-state.md # Heartbeat state: last run, reviewed change, action notes
|
||||
├── projects/ # Per-project learnings
|
||||
├── domains/ # Domain-specific (code, writing, comms)
|
||||
├── archive/ # COLD: decayed patterns
|
||||
└── corrections.md # Last 50 corrections log
|
||||
```
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Topic | File |
|
||||
|-------|------|
|
||||
| Setup guide | `setup.md` |
|
||||
| Heartbeat state template | `heartbeat-state.md` |
|
||||
| Memory template | `memory-template.md` |
|
||||
| Workspace heartbeat snippet | `HEARTBEAT.md` |
|
||||
| Heartbeat rules | `heartbeat-rules.md` |
|
||||
| Learning mechanics | `learning.md` |
|
||||
| Security boundaries | `boundaries.md` |
|
||||
| Scaling rules | `scaling.md` |
|
||||
| Memory operations | `operations.md` |
|
||||
| Self-reflection log | `reflections.md` |
|
||||
| OpenClaw HEARTBEAT seed | `openclaw-heartbeat.md` |
|
||||
|
||||
## Requirements
|
||||
|
||||
- No credentials required
|
||||
- No extra binaries required
|
||||
- Optional installation of the `Proactivity` skill may require network access
|
||||
|
||||
## Learning Signals
|
||||
|
||||
Log automatically when you notice these patterns:
|
||||
|
||||
**Corrections** → add to `corrections.md`, evaluate for `memory.md`:
|
||||
- "No, that's not right..."
|
||||
- "Actually, it should be..."
|
||||
- "You're wrong about..."
|
||||
- "I prefer X, not Y"
|
||||
- "Remember that I always..."
|
||||
- "I told you before..."
|
||||
- "Stop doing X"
|
||||
- "Why do you keep..."
|
||||
|
||||
**Preference signals** → add to `memory.md` if explicit:
|
||||
- "I like when you..."
|
||||
- "Always do X for me"
|
||||
- "Never do Y"
|
||||
- "My style is..."
|
||||
- "For [project], use..."
|
||||
|
||||
**Pattern candidates** → track, promote after 3x:
|
||||
- Same instruction repeated 3+ times
|
||||
- Workflow that works well repeatedly
|
||||
- User praises specific approach
|
||||
|
||||
**Ignore** (don't log):
|
||||
- One-time instructions ("do X now")
|
||||
- Context-specific ("in this file...")
|
||||
- Hypotheticals ("what if...")
|
||||
|
||||
## Self-Reflection
|
||||
|
||||
After completing significant work, pause and evaluate:
|
||||
|
||||
1. **Did it meet expectations?** — Compare outcome vs intent
|
||||
2. **What could be better?** — Identify improvements for next time
|
||||
3. **Is this a pattern?** — If yes, log to `corrections.md`
|
||||
|
||||
**When to self-reflect:**
|
||||
- After completing a multi-step task
|
||||
- After receiving feedback (positive or negative)
|
||||
- After fixing a bug or mistake
|
||||
- When you notice your output could be better
|
||||
|
||||
**Log format:**
|
||||
```
|
||||
CONTEXT: [type of task]
|
||||
REFLECTION: [what I noticed]
|
||||
LESSON: [what to do differently]
|
||||
```
|
||||
|
||||
**Example:**
|
||||
```
|
||||
CONTEXT: Building Flutter UI
|
||||
REFLECTION: Spacing looked off, had to redo
|
||||
LESSON: Check visual spacing before showing user
|
||||
```
|
||||
|
||||
Self-reflection entries follow the same promotion rules: 3x applied successfully → promote to HOT.
|
||||
|
||||
## Quick Queries
|
||||
|
||||
| User says | Action |
|
||||
|-----------|--------|
|
||||
| "What do you know about X?" | Search all tiers for X |
|
||||
| "What have you learned?" | Show last 10 from `corrections.md` |
|
||||
| "Show my patterns" | List `memory.md` (HOT) |
|
||||
| "Show [project] patterns" | Load `projects/{name}.md` |
|
||||
| "What's in warm storage?" | List files in `projects/` + `domains/` |
|
||||
| "Memory stats" | Show counts per tier |
|
||||
| "Forget X" | Remove from all tiers (confirm first) |
|
||||
| "Export memory" | ZIP all files |
|
||||
|
||||
## Memory Stats
|
||||
|
||||
On "memory stats" request, report:
|
||||
|
||||
```
|
||||
📊 Self-Improving Memory
|
||||
|
||||
HOT (always loaded):
|
||||
memory.md: X entries
|
||||
|
||||
WARM (load on demand):
|
||||
projects/: X files
|
||||
domains/: X files
|
||||
|
||||
COLD (archived):
|
||||
archive/: X files
|
||||
|
||||
Recent activity (7 days):
|
||||
Corrections logged: X
|
||||
Promotions to HOT: X
|
||||
Demotions to WARM: X
|
||||
```
|
||||
|
||||
## Common Traps
|
||||
|
||||
| Trap | Why It Fails | Better Move |
|
||||
|------|--------------|-------------|
|
||||
| Learning from silence | Creates false rules | Wait for explicit correction or repeated evidence |
|
||||
| Promoting too fast | Pollutes HOT memory | Keep new lessons tentative until repeated |
|
||||
| Reading every namespace | Wastes context | Load only HOT plus the smallest matching files |
|
||||
| Compaction by deletion | Loses trust and history | Merge, summarize, or demote instead |
|
||||
|
||||
## Core Rules
|
||||
|
||||
### 1. Learn from Corrections and Self-Reflection
|
||||
- Log when user explicitly corrects you
|
||||
- Log when you identify improvements in your own work
|
||||
- Never infer from silence alone
|
||||
- After 3 identical lessons → ask to confirm as rule
|
||||
|
||||
### 2. Tiered Storage
|
||||
| Tier | Location | Size Limit | Behavior |
|
||||
|------|----------|------------|----------|
|
||||
| HOT | memory.md | ≤100 lines | Always loaded |
|
||||
| WARM | projects/, domains/ | ≤200 lines each | Load on context match |
|
||||
| COLD | archive/ | Unlimited | Load on explicit query |
|
||||
|
||||
### 3. Automatic Promotion/Demotion
|
||||
- Pattern used 3x in 7 days → promote to HOT
|
||||
- Pattern unused 30 days → demote to WARM
|
||||
- Pattern unused 90 days → archive to COLD
|
||||
- Never delete without asking
|
||||
|
||||
### 4. Namespace Isolation
|
||||
- Project patterns stay in `projects/{name}.md`
|
||||
- Global preferences in HOT tier (memory.md)
|
||||
- Domain patterns (code, writing) in `domains/`
|
||||
- Cross-namespace inheritance: global → domain → project
|
||||
|
||||
### 5. Conflict Resolution
|
||||
When patterns contradict:
|
||||
1. Most specific wins (project > domain > global)
|
||||
2. Most recent wins (same level)
|
||||
3. If ambiguous → ask user
|
||||
|
||||
### 6. Compaction
|
||||
When file exceeds limit:
|
||||
1. Merge similar corrections into single rule
|
||||
2. Archive unused patterns
|
||||
3. Summarize verbose entries
|
||||
4. Never lose confirmed preferences
|
||||
|
||||
### 7. Transparency
|
||||
- Every action from memory → cite source: "Using X (from projects/foo.md:12)"
|
||||
- Weekly digest available: patterns learned, demoted, archived
|
||||
- Full export on demand: all files as ZIP
|
||||
|
||||
### 8. Security Boundaries
|
||||
See `boundaries.md` — never store credentials, health data, third-party info.
|
||||
|
||||
### 9. Graceful Degradation
|
||||
If context limit hit:
|
||||
1. Load only memory.md (HOT)
|
||||
2. Load relevant namespace on demand
|
||||
3. Never fail silently — tell user what's not loaded
|
||||
|
||||
## Scope
|
||||
|
||||
This skill ONLY:
|
||||
- Learns from user corrections and self-reflection
|
||||
- Stores preferences in local files (`~/self-improving/`)
|
||||
- Maintains heartbeat state in `~/self-improving/heartbeat-state.md` when the workspace integrates heartbeat
|
||||
- Reads its own memory files on activation
|
||||
|
||||
This skill NEVER:
|
||||
- Accesses calendar, email, or contacts
|
||||
- Makes network requests
|
||||
- Reads files outside `~/self-improving/`
|
||||
- Infers preferences from silence or observation
|
||||
- Deletes or blindly rewrites self-improving memory during heartbeat cleanup
|
||||
- Modifies its own SKILL.md
|
||||
|
||||
## Data Storage
|
||||
|
||||
Local state lives in `~/self-improving/`:
|
||||
|
||||
- `memory.md` for HOT rules and confirmed preferences
|
||||
- `corrections.md` for explicit corrections and reusable lessons
|
||||
- `projects/` and `domains/` for scoped patterns
|
||||
- `archive/` for decayed or inactive patterns
|
||||
- `heartbeat-state.md` for recurring maintenance markers
|
||||
|
||||
## Related Skills
|
||||
Install with `clawhub install <slug>` if user confirms:
|
||||
|
||||
- `memory` — Long-term memory patterns for agents
|
||||
- `learning` — Adaptive teaching and explanation
|
||||
- `decide` — Auto-learn decision patterns
|
||||
- `escalate` — Know when to ask vs act autonomously
|
||||
|
||||
## Feedback
|
||||
|
||||
- If useful: `clawhub star self-improving`
|
||||
- Stay updated: `clawhub sync`
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"ownerId": "kn73vp5rarc3b14rc7wjcw8f8580t5d1",
|
||||
"slug": "self-improving",
|
||||
"version": "1.2.16",
|
||||
"publishedAt": 1773329327755
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
# Security Boundaries
|
||||
|
||||
## Never Store
|
||||
|
||||
| Category | Examples | Why |
|
||||
|----------|----------|-----|
|
||||
| Credentials | Passwords, API keys, tokens, SSH keys | Security breach risk |
|
||||
| Financial | Card numbers, bank accounts, crypto seeds | Fraud risk |
|
||||
| Medical | Diagnoses, medications, conditions | Privacy, HIPAA |
|
||||
| Biometric | Voice patterns, behavioral fingerprints | Identity theft |
|
||||
| Third parties | Info about other people | No consent obtained |
|
||||
| Location patterns | Home/work addresses, routines | Physical safety |
|
||||
| Access patterns | What systems user has access to | Privilege escalation |
|
||||
|
||||
## Store with Caution
|
||||
|
||||
| Category | Rules |
|
||||
|----------|-------|
|
||||
| Work context | Decay after project ends, never share cross-project |
|
||||
| Emotional states | Only if user explicitly shares, never infer |
|
||||
| Relationships | Roles only ("manager", "client"), no personal details |
|
||||
| Schedules | General patterns OK ("busy mornings"), not specific times |
|
||||
|
||||
## Transparency Requirements
|
||||
|
||||
1. **Audit on demand** — User asks "what do you know about me?" → full export
|
||||
2. **Source tracking** — Every item tagged with when/how learned
|
||||
3. **Explain actions** — "I did X because you said Y on [date]"
|
||||
4. **No hidden state** — If it affects behavior, it must be visible
|
||||
5. **Deletion verification** — Confirm item removed, show updated state
|
||||
|
||||
## Red Flags to Catch
|
||||
|
||||
If you find yourself doing any of these, STOP:
|
||||
|
||||
- Storing something "just in case it's useful later"
|
||||
- Inferring sensitive info from non-sensitive data
|
||||
- Keeping data after user asked to forget
|
||||
- Applying personal context to work (or vice versa)
|
||||
- Learning what makes user comply faster
|
||||
- Building psychological profile
|
||||
- Retaining third-party information
|
||||
|
||||
## Kill Switch
|
||||
|
||||
User says "forget everything":
|
||||
1. Export current memory to file (so they can review)
|
||||
2. Wipe all learned data
|
||||
3. Confirm: "Memory cleared. Starting fresh."
|
||||
4. Do not retain "ghost patterns" in behavior
|
||||
|
||||
## Consent Model
|
||||
|
||||
| Data Type | Consent Level |
|
||||
|-----------|---------------|
|
||||
| Explicit corrections | Implied by correction itself |
|
||||
| Inferred preferences | Ask after 3 observations |
|
||||
| Context/project data | Ask when first detected |
|
||||
| Cross-session patterns | Explicit opt-in required |
|
||||
@@ -0,0 +1,85 @@
|
||||
{
|
||||
"name": "multi-search-engine",
|
||||
"engines": [
|
||||
{
|
||||
"name": "Baidu",
|
||||
"url": "https://www.baidu.com/s?wd={keyword}",
|
||||
"region": "cn"
|
||||
},
|
||||
{
|
||||
"name": "Bing CN",
|
||||
"url": "https://cn.bing.com/search?q={keyword}&ensearch=0",
|
||||
"region": "cn"
|
||||
},
|
||||
{
|
||||
"name": "Bing INT",
|
||||
"url": "https://cn.bing.com/search?q={keyword}&ensearch=1",
|
||||
"region": "cn"
|
||||
},
|
||||
{
|
||||
"name": "360",
|
||||
"url": "https://www.so.com/s?q={keyword}",
|
||||
"region": "cn"
|
||||
},
|
||||
{
|
||||
"name": "Sogou",
|
||||
"url": "https://sogou.com/web?query={keyword}",
|
||||
"region": "cn"
|
||||
},
|
||||
{
|
||||
"name": "WeChat",
|
||||
"url": "https://wx.sogou.com/weixin?type=2&query={keyword}",
|
||||
"region": "cn"
|
||||
},
|
||||
{
|
||||
"name": "Shenma",
|
||||
"url": "https://m.sm.cn/s?q={keyword}",
|
||||
"region": "cn"
|
||||
},
|
||||
{
|
||||
"name": "Google",
|
||||
"url": "https://www.google.com/search?q={keyword}",
|
||||
"region": "global"
|
||||
},
|
||||
{
|
||||
"name": "Google HK",
|
||||
"url": "https://www.google.com.hk/search?q={keyword}",
|
||||
"region": "global"
|
||||
},
|
||||
{
|
||||
"name": "DuckDuckGo",
|
||||
"url": "https://duckduckgo.com/html/?q={keyword}",
|
||||
"region": "global"
|
||||
},
|
||||
{
|
||||
"name": "Yahoo",
|
||||
"url": "https://search.yahoo.com/search?p={keyword}",
|
||||
"region": "global"
|
||||
},
|
||||
{
|
||||
"name": "Startpage",
|
||||
"url": "https://www.startpage.com/sp/search?query={keyword}",
|
||||
"region": "global"
|
||||
},
|
||||
{
|
||||
"name": "Brave",
|
||||
"url": "https://search.brave.com/search?q={keyword}",
|
||||
"region": "global"
|
||||
},
|
||||
{
|
||||
"name": "Ecosia",
|
||||
"url": "https://www.ecosia.org/search?q={keyword}",
|
||||
"region": "global"
|
||||
},
|
||||
{
|
||||
"name": "Qwant",
|
||||
"url": "https://www.qwant.com/?q={keyword}",
|
||||
"region": "global"
|
||||
},
|
||||
{
|
||||
"name": "WolframAlpha",
|
||||
"url": "https://www.wolframalpha.com/input?i={keyword}",
|
||||
"region": "global"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
# Corrections Log — Template
|
||||
|
||||
> This file is created in `~/self-improving/corrections.md` when you first use the skill.
|
||||
> Keeps the last 50 corrections. Older entries are evaluated for promotion or archived.
|
||||
|
||||
## Example Entries
|
||||
|
||||
```markdown
|
||||
## 2026-02-19
|
||||
|
||||
### 14:32 — Code style
|
||||
- **Correction:** "Use 2-space indentation, not 4"
|
||||
- **Context:** Editing TypeScript file
|
||||
- **Count:** 1 (first occurrence)
|
||||
|
||||
### 16:15 — Communication
|
||||
- **Correction:** "Don't start responses with 'Great question!'"
|
||||
- **Context:** Chat response
|
||||
- **Count:** 3 → **PROMOTED to memory.md**
|
||||
|
||||
## 2026-02-18
|
||||
|
||||
### 09:00 — Project: website
|
||||
- **Correction:** "For this project, always use Tailwind"
|
||||
- **Context:** CSS discussion
|
||||
- **Action:** Added to projects/website.md
|
||||
```
|
||||
|
||||
## Log Format
|
||||
|
||||
Each entry includes:
|
||||
- **Timestamp** — When the correction happened
|
||||
- **Correction** — What the user said
|
||||
- **Context** — What triggered it
|
||||
- **Count** — How many times (for promotion tracking)
|
||||
- **Action** — Where it was stored (if promoted)
|
||||
@@ -0,0 +1,54 @@
|
||||
# Heartbeat Rules
|
||||
|
||||
Use heartbeat to keep `~/self-improving/` organized without creating churn or losing data.
|
||||
|
||||
## Source of Truth
|
||||
|
||||
Keep the workspace `HEARTBEAT.md` snippet minimal.
|
||||
Treat this file as the stable contract for self-improving heartbeat behavior.
|
||||
Store mutable run state only in `~/self-improving/heartbeat-state.md`.
|
||||
|
||||
## Start of Every Heartbeat
|
||||
|
||||
1. Ensure `~/self-improving/heartbeat-state.md` exists.
|
||||
2. Write `last_heartbeat_started_at` immediately in ISO 8601.
|
||||
3. Read the previous `last_reviewed_change_at`.
|
||||
4. Scan `~/self-improving/` for files changed after that moment, excluding `heartbeat-state.md` itself.
|
||||
|
||||
## If Nothing Changed
|
||||
|
||||
- Set `last_heartbeat_result: HEARTBEAT_OK`
|
||||
- Append a short "no material change" note if you keep an action log
|
||||
- Return `HEARTBEAT_OK`
|
||||
|
||||
## If Something Changed
|
||||
|
||||
Only do conservative organization:
|
||||
|
||||
- refresh `index.md` if counts or file references drift
|
||||
- compact oversized files by merging duplicates or summarizing repetitive entries
|
||||
- move clearly misplaced notes to the right namespace only when the target is unambiguous
|
||||
- preserve confirmed rules and explicit corrections exactly
|
||||
- update `last_reviewed_change_at` only after the review finishes cleanly
|
||||
|
||||
## Safety Rules
|
||||
|
||||
- Most heartbeat runs should do nothing
|
||||
- Prefer append, summarize, or index fixes over large rewrites
|
||||
- Never delete data, empty files, or overwrite uncertain text
|
||||
- Never reorganize files outside `~/self-improving/`
|
||||
- If scope is ambiguous, leave files untouched and record a suggested follow-up instead
|
||||
|
||||
## State Fields
|
||||
|
||||
Keep `~/self-improving/heartbeat-state.md` simple:
|
||||
|
||||
- `last_heartbeat_started_at`
|
||||
- `last_reviewed_change_at`
|
||||
- `last_heartbeat_result`
|
||||
- `last_actions`
|
||||
|
||||
## Behavior Standard
|
||||
|
||||
Heartbeat exists to keep the memory system tidy and trustworthy.
|
||||
If no rule is clearly violated, do nothing.
|
||||
@@ -0,0 +1,22 @@
|
||||
# Heartbeat State Template
|
||||
|
||||
Use this file as the baseline for `~/self-improving/heartbeat-state.md`.
|
||||
It stores only lightweight run markers and maintenance notes.
|
||||
|
||||
```markdown
|
||||
# Self-Improving Heartbeat State
|
||||
|
||||
last_heartbeat_started_at: never
|
||||
last_reviewed_change_at: never
|
||||
last_heartbeat_result: never
|
||||
|
||||
## Last actions
|
||||
- none yet
|
||||
```
|
||||
|
||||
## Rules
|
||||
|
||||
- update `last_heartbeat_started_at` at the beginning of every heartbeat
|
||||
- update `last_reviewed_change_at` only after a clean review of changed files
|
||||
- keep `last_actions` short and factual
|
||||
- never turn this file into another memory log
|
||||
@@ -0,0 +1,106 @@
|
||||
# Learning Mechanics
|
||||
|
||||
## What Triggers Learning
|
||||
|
||||
| Trigger | Confidence | Action |
|
||||
|---------|------------|--------|
|
||||
| "No, do X instead" | High | Log correction immediately |
|
||||
| "I told you before..." | High | Flag as repeated, bump priority |
|
||||
| "Always/Never do X" | Confirmed | Promote to preference |
|
||||
| User edits your output | Medium | Log as tentative pattern |
|
||||
| Same correction 3x | Confirmed | Ask to make permanent |
|
||||
| "For this project..." | Scoped | Write to project namespace |
|
||||
|
||||
## What Does NOT Trigger Learning
|
||||
|
||||
- Silence (not confirmation)
|
||||
- Single instance of anything
|
||||
- Hypothetical discussions
|
||||
- Third-party preferences ("John likes...")
|
||||
- Group chat patterns (unless user confirms)
|
||||
- Implied preferences (never infer)
|
||||
|
||||
## Correction Classification
|
||||
|
||||
### By Type
|
||||
| Type | Example | Namespace |
|
||||
|------|---------|-----------|
|
||||
| Format | "Use bullets not prose" | global |
|
||||
| Technical | "SQLite not Postgres" | domain/code |
|
||||
| Communication | "Shorter messages" | global |
|
||||
| Project-specific | "This repo uses Tailwind" | projects/{name} |
|
||||
| Person-specific | "Marcus wants BLUF" | domains/comms |
|
||||
|
||||
### By Scope
|
||||
```
|
||||
Global: applies everywhere
|
||||
└── Domain: applies to category (code, writing, comms)
|
||||
└── Project: applies to specific context
|
||||
└── Temporary: applies to this session only
|
||||
```
|
||||
|
||||
## Confirmation Flow
|
||||
|
||||
After 3 similar corrections:
|
||||
```
|
||||
Agent: "I've noticed you prefer X over Y (corrected 3 times).
|
||||
Should I always do this?
|
||||
- Yes, always
|
||||
- Only in [context]
|
||||
- No, case by case"
|
||||
|
||||
User: "Yes, always"
|
||||
|
||||
Agent: → Moves to Confirmed Preferences
|
||||
→ Removes from correction counter
|
||||
→ Cites source on future use
|
||||
```
|
||||
|
||||
## Pattern Evolution
|
||||
|
||||
### Stages
|
||||
1. **Tentative** — Single correction, watch for repetition
|
||||
2. **Emerging** — 2 corrections, likely pattern
|
||||
3. **Pending** — 3 corrections, ask for confirmation
|
||||
4. **Confirmed** — User approved, permanent unless reversed
|
||||
5. **Archived** — Unused 90+ days, preserved but inactive
|
||||
|
||||
### Reversal
|
||||
User can always reverse:
|
||||
```
|
||||
User: "Actually, I changed my mind about X"
|
||||
|
||||
Agent:
|
||||
1. Archive old pattern (keep history)
|
||||
2. Log reversal with timestamp
|
||||
3. Add new preference as tentative
|
||||
4. "Got it. I'll do Y now. (Previous: X, archived)"
|
||||
```
|
||||
|
||||
## Anti-Patterns
|
||||
|
||||
### Never Learn
|
||||
- What makes user comply faster (manipulation)
|
||||
- Emotional triggers or vulnerabilities
|
||||
- Patterns from other users (even if shared device)
|
||||
- Anything that feels "creepy" to surface
|
||||
|
||||
### Avoid
|
||||
- Over-generalizing from single instance
|
||||
- Learning style over substance
|
||||
- Assuming preference stability
|
||||
- Ignoring context shifts
|
||||
|
||||
## Quality Signals
|
||||
|
||||
### Good Learning
|
||||
- User explicitly states preference
|
||||
- Pattern consistent across contexts
|
||||
- Correction improves outcomes
|
||||
- User confirms when asked
|
||||
|
||||
### Bad Learning
|
||||
- Inferred from silence
|
||||
- Contradicts recent behavior
|
||||
- Only works in narrow context
|
||||
- User never confirmed
|
||||
@@ -0,0 +1,75 @@
|
||||
# Memory Template
|
||||
|
||||
Copy this structure to `~/self-improving/memory.md` on first use.
|
||||
|
||||
```markdown
|
||||
# Self-Improving Memory
|
||||
|
||||
## Confirmed Preferences
|
||||
<!-- Patterns confirmed by user, never decay -->
|
||||
|
||||
## Active Patterns
|
||||
<!-- Patterns observed 3+ times, subject to decay -->
|
||||
|
||||
## Recent (last 7 days)
|
||||
<!-- New corrections pending confirmation -->
|
||||
```
|
||||
|
||||
## Initial Directory Structure
|
||||
|
||||
Create on first activation:
|
||||
|
||||
```bash
|
||||
mkdir -p ~/self-improving/{projects,domains,archive}
|
||||
touch ~/self-improving/{memory.md,index.md,corrections.md,heartbeat-state.md}
|
||||
```
|
||||
|
||||
## Index Template
|
||||
|
||||
For `~/self-improving/index.md`:
|
||||
|
||||
```markdown
|
||||
# Memory Index
|
||||
|
||||
## HOT
|
||||
- memory.md: 0 lines
|
||||
|
||||
## WARM
|
||||
- (no namespaces yet)
|
||||
|
||||
## COLD
|
||||
- (no archives yet)
|
||||
|
||||
Last compaction: never
|
||||
```
|
||||
|
||||
## Corrections Log Template
|
||||
|
||||
For `~/self-improving/corrections.md`:
|
||||
|
||||
```markdown
|
||||
# Corrections Log
|
||||
|
||||
<!-- Format:
|
||||
## YYYY-MM-DD
|
||||
- [HH:MM] Changed X → Y
|
||||
Type: format|technical|communication|project
|
||||
Context: where correction happened
|
||||
Confirmed: pending (N/3) | yes | no
|
||||
-->
|
||||
```
|
||||
|
||||
## Heartbeat State Template
|
||||
|
||||
For `~/self-improving/heartbeat-state.md`:
|
||||
|
||||
```markdown
|
||||
# Self-Improving Heartbeat State
|
||||
|
||||
last_heartbeat_started_at: never
|
||||
last_reviewed_change_at: never
|
||||
last_heartbeat_result: never
|
||||
|
||||
## Last actions
|
||||
- none yet
|
||||
```
|
||||
@@ -0,0 +1,30 @@
|
||||
# HOT Memory — Template
|
||||
|
||||
> This file is created in `~/self-improving/memory.md` when you first use the skill.
|
||||
> Keep it ≤100 lines. Most-used patterns live here.
|
||||
|
||||
## Example Entries
|
||||
|
||||
```markdown
|
||||
## Preferences
|
||||
- Code style: Prefer explicit over implicit
|
||||
- Communication: Direct, no fluff
|
||||
- Time zone: Europe/Madrid
|
||||
|
||||
## Patterns (promoted from corrections)
|
||||
- Always use TypeScript strict mode
|
||||
- Prefer pnpm over npm
|
||||
- Format: ISO 8601 for dates
|
||||
|
||||
## Project defaults
|
||||
- Tests: Jest with coverage >80%
|
||||
- Commits: Conventional commits format
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
The agent will:
|
||||
1. Load this file on every session
|
||||
2. Add entries when patterns are used 3x in 7 days
|
||||
3. Demote unused entries to WARM after 30 days
|
||||
4. Never exceed 100 lines (compacts automatically)
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "multi-search-engine",
|
||||
"version": "2.1.0",
|
||||
"description": "Multi search engine with 16 engines (7 CN + 9 Global). Supports advanced operators, time filters, privacy engines.",
|
||||
"engines": 16,
|
||||
"requires_api_key": false
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
## Self-Improving Check
|
||||
|
||||
- Read `./skills/self-improving/heartbeat-rules.md`
|
||||
- Use `~/self-improving/heartbeat-state.md` for last-run markers and action notes
|
||||
- If no file inside `~/self-improving/` changed since the last reviewed change, return `HEARTBEAT_OK`
|
||||
@@ -0,0 +1,144 @@
|
||||
# Memory Operations
|
||||
|
||||
## User Commands
|
||||
|
||||
| Command | Action |
|
||||
|---------|--------|
|
||||
| "What do you know about X?" | Search all tiers, return matches with sources |
|
||||
| "Show my memory" | Display memory.md contents |
|
||||
| "Show [project] patterns" | Load and display specific namespace |
|
||||
| "Forget X" | Remove from all tiers, confirm deletion |
|
||||
| "Forget everything" | Full wipe with export option |
|
||||
| "What changed recently?" | Show last 20 corrections |
|
||||
| "Export memory" | Generate downloadable archive |
|
||||
| "Memory status" | Show tier sizes, last compaction, health |
|
||||
|
||||
## Automatic Operations
|
||||
|
||||
### On Session Start
|
||||
1. Load memory.md (HOT tier)
|
||||
2. Check index.md for context hints
|
||||
3. If project detected → preload relevant namespace
|
||||
|
||||
### On Correction Received
|
||||
```
|
||||
1. Parse correction type (preference, pattern, override)
|
||||
2. Check if duplicate (exists in any tier)
|
||||
3. If new:
|
||||
- Add to corrections.md with timestamp
|
||||
- Increment correction counter
|
||||
4. If duplicate:
|
||||
- Bump counter, update timestamp
|
||||
- If counter >= 3: ask to confirm as rule
|
||||
5. Determine namespace (global, domain, project)
|
||||
6. Write to appropriate file
|
||||
7. Update index.md line counts
|
||||
```
|
||||
|
||||
### On Pattern Match
|
||||
When applying learned pattern:
|
||||
```
|
||||
1. Find pattern source (file:line)
|
||||
2. Apply pattern
|
||||
3. Cite source: "Using X (from memory.md:15)"
|
||||
4. Log usage for decay tracking
|
||||
```
|
||||
|
||||
### Weekly Maintenance (Cron)
|
||||
```
|
||||
1. Scan all files for decay candidates
|
||||
2. Move unused >30 days to WARM
|
||||
3. Archive unused >90 days to COLD
|
||||
4. Run compaction if any file >limit
|
||||
5. Update index.md
|
||||
6. Generate weekly digest (optional)
|
||||
```
|
||||
|
||||
## File Formats
|
||||
|
||||
### memory.md (HOT)
|
||||
```markdown
|
||||
# Self-Improving Memory
|
||||
|
||||
## Confirmed Preferences
|
||||
- format: bullet points over prose (confirmed 2026-01)
|
||||
- tone: direct, no hedging (confirmed 2026-01)
|
||||
|
||||
## Active Patterns
|
||||
- "looks good" = approval to proceed (used 15x)
|
||||
- single emoji = acknowledged (used 8x)
|
||||
|
||||
## Recent (last 7 days)
|
||||
- prefer SQLite for MVPs (corrected 02-14)
|
||||
```
|
||||
|
||||
### corrections.md
|
||||
```markdown
|
||||
# Corrections Log
|
||||
|
||||
## 2026-02-15
|
||||
- [14:32] Changed verbose explanation → bullet summary
|
||||
Type: communication
|
||||
Context: Telegram response
|
||||
Confirmed: pending (1/3)
|
||||
|
||||
## 2026-02-14
|
||||
- [09:15] Use SQLite not Postgres for MVP
|
||||
Type: technical
|
||||
Context: database discussion
|
||||
Confirmed: yes (said "always")
|
||||
```
|
||||
|
||||
### projects/{name}.md
|
||||
```markdown
|
||||
# Project: my-app
|
||||
|
||||
Inherits: global, domains/code
|
||||
|
||||
## Patterns
|
||||
- Use Tailwind (project standard)
|
||||
- No Prettier (eslint only)
|
||||
- Deploy via GitLab CI
|
||||
|
||||
## Overrides
|
||||
- semicolons: yes (overrides global no-semi)
|
||||
|
||||
## History
|
||||
- Created: 2026-01-15
|
||||
- Last active: 2026-02-15
|
||||
- Corrections: 12
|
||||
```
|
||||
|
||||
## Edge Case Handling
|
||||
|
||||
### Contradiction Detected
|
||||
```
|
||||
Pattern A: "Use tabs" (global, confirmed)
|
||||
Pattern B: "Use spaces" (project, corrected today)
|
||||
|
||||
Resolution:
|
||||
1. Project overrides global → use spaces for this project
|
||||
2. Log conflict in corrections.md
|
||||
3. Ask: "Should spaces apply only to this project or everywhere?"
|
||||
```
|
||||
|
||||
### User Changes Mind
|
||||
```
|
||||
Old: "Always use formal tone"
|
||||
New: "Actually, casual is fine"
|
||||
|
||||
Action:
|
||||
1. Archive old pattern with timestamp
|
||||
2. Add new pattern as tentative
|
||||
3. Keep archived for reference ("You previously preferred formal")
|
||||
```
|
||||
|
||||
### Context Ambiguity
|
||||
```
|
||||
User says: "Remember I like X"
|
||||
|
||||
But which namespace?
|
||||
1. Check current context (project? domain?)
|
||||
2. If unclear, ask: "Should this apply globally or just here?"
|
||||
3. Default to most specific active context
|
||||
```
|
||||
@@ -0,0 +1,146 @@
|
||||
# 国内搜索引擎深度搜索指南
|
||||
|
||||
## 🔍 百度 (Baidu)
|
||||
|
||||
### 特色功能
|
||||
|
||||
| 功能 | 说明 | URL |
|
||||
|------|------|-----|
|
||||
| **中文优化** | 中文内容索引最全 | `https://www.baidu.com/s?wd={keyword}` |
|
||||
| **百度学术** | 学术资源搜索 | `https://xueshu.baidu.com/s?wd={keyword}` |
|
||||
| **百度新闻** | 新闻聚合 | `https://news.baidu.com/` |
|
||||
|
||||
### 搜索示例
|
||||
|
||||
```javascript
|
||||
// 1. 基础搜索
|
||||
web_fetch({"url": "https://www.baidu.com/s?wd=Python教程"})
|
||||
|
||||
// 2. 站内搜索
|
||||
web_fetch({"url": "https://www.baidu.com/s?wd=site:github.com+python"})
|
||||
|
||||
// 3. 文件类型搜索
|
||||
web_fetch({"url": "https://www.baidu.com/s?wd=机器学习+filetype:pdf"})
|
||||
|
||||
// 4. 学术搜索
|
||||
web_fetch({"url": "https://xueshu.baidu.com/s?wd=深度学习+图像识别"})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔎 必应中国版 (Bing CN/INT)
|
||||
|
||||
### 特色功能
|
||||
|
||||
| 功能 | 说明 | URL |
|
||||
|------|------|-----|
|
||||
| **中文优化** | `ensearch=0` 中文结果 | `https://cn.bing.com/search?q={keyword}&ensearch=0` |
|
||||
| **国际版** | `ensearch=1` 英文结果 | `https://cn.bing.com/search?q={keyword}&ensearch=1` |
|
||||
| **学术搜索** | 学术资源 | `https://cn.bing.com/academic/search?q={keyword}` |
|
||||
|
||||
### 搜索示例
|
||||
|
||||
```javascript
|
||||
// 1. 中文搜索结果
|
||||
web_fetch({"url": "https://cn.bing.com/search?q=人工智能技术&ensearch=0"})
|
||||
|
||||
// 2. 英文搜索结果(使用中国服务器)
|
||||
web_fetch({"url": "https://cn.bing.com/search?q=artificial+intelligence&ensearch=1"})
|
||||
|
||||
// 3. 学术搜索
|
||||
web_fetch({"url": "https://cn.bing.com/academic/search?q=机器学习算法"})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔍 360搜索
|
||||
|
||||
### 特色功能
|
||||
|
||||
| 功能 | 说明 | URL |
|
||||
|------|------|-----|
|
||||
| **安全搜索** | 内置安全防护 | 默认开启 |
|
||||
| **基础搜索** | 网页搜索 | `https://www.so.com/s?q={keyword}` |
|
||||
|
||||
### 搜索示例
|
||||
|
||||
```javascript
|
||||
// 1. 基础搜索
|
||||
web_fetch({"url": "https://www.so.com/s?q=网络安全"})
|
||||
|
||||
// 2. 站内搜索
|
||||
web_fetch({"url": "https://www.so.com/s?q=site:zhihu.com+python"})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔍 搜狗 (Sogou) + 微信搜索
|
||||
|
||||
### 特色功能
|
||||
|
||||
| 功能 | 说明 | URL |
|
||||
|------|------|-----|
|
||||
| **网页搜索** | 通用搜索 | `https://sogou.com/web?query={keyword}` |
|
||||
| **微信公众号** | 搜公众号文章(唯一渠道) | `https://wx.sogou.com/weixin?type=2&query={keyword}` |
|
||||
| **知乎优化** | 知乎内容索引好 | `site:zhihu.com` 配合使用 |
|
||||
|
||||
### 搜索示例
|
||||
|
||||
```javascript
|
||||
// 1. 网页搜索
|
||||
web_fetch({"url": "https://sogou.com/web?query=python教程"})
|
||||
|
||||
// 2. 微信公众号文章搜索
|
||||
web_fetch({"url": "https://wx.sogou.com/weixin?type=2&query=Python编程"})
|
||||
|
||||
// 3. 搜索特定公众号
|
||||
web_fetch({"url": "https://wx.sogou.com/weixin?type=2&query=公众号:机器之心"})
|
||||
|
||||
// 4. 知乎内容搜索
|
||||
web_fetch({"url": "https://www.sogou.com/web?query=site:zhihu.com+机器学习"})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📱 神马搜索 (Shenma)
|
||||
|
||||
### 特色功能
|
||||
|
||||
| 功能 | 说明 | URL |
|
||||
|------|------|-----|
|
||||
| **移动优化** | 专注移动端搜索 | `https://m.sm.cn/s?q={keyword}` |
|
||||
| **阿里生态** | 整合阿里系内容 | UC浏览器默认搜索 |
|
||||
|
||||
### 搜索示例
|
||||
|
||||
```javascript
|
||||
// 1. 移动端搜索
|
||||
web_fetch({"url": "https://m.sm.cn/s?q=python入门教程"})
|
||||
|
||||
// 2. 移动网站点搜索
|
||||
web_fetch({"url": "https://m.sm.cn/s?q=site:zhuanlan.zhihu.com+AI"})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🌍 国内搜索策略
|
||||
|
||||
### 按搜索目标选择引擎
|
||||
|
||||
| 搜索目标 | 首选引擎 | 原因 |
|
||||
|---------|---------|------|
|
||||
| **综合中文内容** | 百度 | 中文索引最全 |
|
||||
| **微信公众号** | 搜狗微信 | 唯一支持公众号搜索 |
|
||||
| **知乎内容** | 搜狗 | 知乎优化好 |
|
||||
| **移动端内容** | 神马 | 移动端优化 |
|
||||
| **学术资源** | 必应学术 | 学术索引 |
|
||||
| **中英文双语** | 必应中国/国际版 | enswitch切换 |
|
||||
| **新闻资讯** | 百度新闻 | 新闻聚合 |
|
||||
|
||||
---
|
||||
|
||||
## 📚 参考资料
|
||||
|
||||
- [百度搜索高级语法](https://baike.baidu.com/item/搜索语法)
|
||||
- [必应搜索技巧](https://cn.bing.com/tips)
|
||||
- [搜狗搜索帮助](https://help.sogou.com/)
|
||||
@@ -0,0 +1,29 @@
|
||||
# op CLI examples (from op help)
|
||||
|
||||
## Sign in
|
||||
|
||||
- `op signin`
|
||||
- `op signin --account <shorthand|signin-address|account-id|user-id>`
|
||||
|
||||
## Read
|
||||
|
||||
- `op read op://app-prod/db/password`
|
||||
- `op read "op://app-prod/db/one-time password?attribute=otp"`
|
||||
- `op read "op://app-prod/ssh key/private key?ssh-format=openssh"`
|
||||
- `op read --out-file ./key.pem op://app-prod/server/ssh/key.pem`
|
||||
|
||||
## Run
|
||||
|
||||
- `export DB_PASSWORD="op://app-prod/db/password"`
|
||||
- `op run --no-masking -- printenv DB_PASSWORD`
|
||||
- `op run --env-file="./.env" -- printenv DB_PASSWORD`
|
||||
|
||||
## Inject
|
||||
|
||||
- `echo "db_password: {{ op://app-prod/db/password }}" | op inject`
|
||||
- `op inject -i config.yml.tpl -o config.yml`
|
||||
|
||||
## Whoami / accounts
|
||||
|
||||
- `op whoami`
|
||||
- `op account list`
|
||||
@@ -0,0 +1,17 @@
|
||||
# 1Password CLI get-started (summary)
|
||||
|
||||
- Works on macOS, Windows, and Linux.
|
||||
- macOS/Linux shells: bash, zsh, sh, fish.
|
||||
- Windows shell: PowerShell.
|
||||
- Requires a 1Password subscription and the desktop app to use app integration.
|
||||
- macOS requirement: Big Sur 11.0.0 or later.
|
||||
- Linux app integration requires PolKit + an auth agent.
|
||||
- Install the CLI per the official doc for your OS.
|
||||
- Enable desktop app integration in the 1Password app:
|
||||
- Open and unlock the app, then select your account/collection.
|
||||
- macOS: Settings > Developer > Integrate with 1Password CLI (Touch ID optional).
|
||||
- Windows: turn on Windows Hello, then Settings > Developer > Integrate.
|
||||
- Linux: Settings > Security > Unlock using system authentication, then Settings > Developer > Integrate.
|
||||
- After integration, run any command to sign in (example in docs: `op vault list`).
|
||||
- If multiple accounts: use `op signin` to pick one, or `--account` / `OP_ACCOUNT`.
|
||||
- For non-integration auth, use `op account add`.
|
||||
@@ -0,0 +1,398 @@
|
||||
# 国际搜索引擎深度搜索指南
|
||||
|
||||
## 🔍 Google 深度搜索
|
||||
|
||||
### 1.1 基础高级搜索操作符
|
||||
|
||||
| 操作符 | 功能 | 示例 | URL |
|
||||
|--------|------|------|-----|
|
||||
| `""` | 精确匹配 | `"machine learning"` | `https://www.google.com/search?q=%22machine+learning%22` |
|
||||
| `-` | 排除关键词 | `python -snake` | `https://www.google.com/search?q=python+-snake` |
|
||||
| `OR` | 或运算 | `machine learning OR deep learning` | `https://www.google.com/search?q=machine+learning+OR+deep+learning` |
|
||||
| `*` | 通配符 | `machine * algorithms` | `https://www.google.com/search?q=machine+*+algorithms` |
|
||||
| `()` | 分组 | `(apple OR microsoft) phones` | `https://www.google.com/search?q=(apple+OR+microsoft)+phones` |
|
||||
| `..` | 数字范围 | `laptop $500..$1000` | `https://www.google.com/search?q=laptop+%24500..%241000` |
|
||||
|
||||
### 1.2 站点与文件搜索
|
||||
|
||||
| 操作符 | 功能 | 示例 |
|
||||
|--------|------|------|
|
||||
| `site:` | 站内搜索 | `site:github.com python projects` |
|
||||
| `filetype:` | 文件类型 | `filetype:pdf annual report` |
|
||||
| `inurl:` | URL包含 | `inurl:login admin` |
|
||||
| `intitle:` | 标题包含 | `intitle:"index of" mp3` |
|
||||
| `intext:` | 正文包含 | `intext:password filetype:txt` |
|
||||
| `cache:` | 查看缓存 | `cache:example.com` |
|
||||
| `related:` | 相关网站 | `related:github.com` |
|
||||
| `info:` | 网站信息 | `info:example.com` |
|
||||
|
||||
### 1.3 时间筛选参数
|
||||
|
||||
| 参数 | 含义 | URL示例 |
|
||||
|------|------|---------|
|
||||
| `tbs=qdr:h` | 过去1小时 | `https://www.google.com/search?q=news&tbs=qdr:h` |
|
||||
| `tbs=qdr:d` | 过去24小时 | `https://www.google.com/search?q=news&tbs=qdr:d` |
|
||||
| `tbs=qdr:w` | 过去1周 | `https://www.google.com/search?q=news&tbs=qdr:w` |
|
||||
| `tbs=qdr:m` | 过去1月 | `https://www.google.com/search?q=news&tbs=qdr:m` |
|
||||
| `tbs=qdr:y` | 过去1年 | `https://www.google.com/search?q=news&tbs=qdr:y` |
|
||||
| `tbs=cdr:1,cd_min:1/1/2024,cd_max:12/31/2024` | 自定义日期范围 | 2024年全年 |
|
||||
|
||||
### 1.4 语言和地区筛选
|
||||
|
||||
| 参数 | 功能 | 示例 |
|
||||
|------|------|------|
|
||||
| `hl=en` | 界面语言 | `https://www.google.com/search?q=test&hl=en` |
|
||||
| `lr=lang_zh-CN` | 搜索结果语言 | `https://www.google.com/search?q=test&lr=lang_zh-CN` |
|
||||
| `cr=countryCN` | 国家/地区 | `https://www.google.com/search?q=test&cr=countryCN` |
|
||||
| `gl=us` | 地理位置 | `https://www.google.com/search?q=test&gl=us` |
|
||||
|
||||
### 1.5 特殊搜索类型
|
||||
|
||||
| 类型 | URL | 说明 |
|
||||
|------|-----|------|
|
||||
| 图片搜索 | `https://www.google.com/search?q={keyword}&tbm=isch` | `tbm=isch` 表示图片 |
|
||||
| 新闻搜索 | `https://www.google.com/search?q={keyword}&tbm=nws` | `tbm=nws` 表示新闻 |
|
||||
| 视频搜索 | `https://www.google.com/search?q={keyword}&tbm=vid` | `tbm=vid` 表示视频 |
|
||||
| 地图搜索 | `https://www.google.com/search?q={keyword}&tbm=map` | `tbm=map` 表示地图 |
|
||||
| 购物搜索 | `https://www.google.com/search?q={keyword}&tbm=shop` | `tbm=shop` 表示购物 |
|
||||
| 图书搜索 | `https://www.google.com/search?q={keyword}&tbm=bks` | `tbm=bks` 表示图书 |
|
||||
| 学术搜索 | `https://scholar.google.com/scholar?q={keyword}` | Google Scholar |
|
||||
|
||||
### 1.6 Google 深度搜索示例
|
||||
|
||||
```javascript
|
||||
// 1. 搜索GitHub上的Python机器学习项目
|
||||
web_fetch({"url": "https://www.google.com/search?q=site:github.com+python+machine+learning"})
|
||||
|
||||
// 2. 搜索2024年的PDF格式机器学习教程
|
||||
web_fetch({"url": "https://www.google.com/search?q=machine+learning+tutorial+filetype:pdf&tbs=cdr:1,cd_min:1/1/2024"})
|
||||
|
||||
// 3. 搜索标题包含"tutorial"的Python相关页面
|
||||
web_fetch({"url": "https://www.google.com/search?q=intitle:tutorial+python"})
|
||||
|
||||
// 4. 搜索过去一周的新闻
|
||||
web_fetch({"url": "https://www.google.com/search?q=AI+breakthrough&tbs=qdr:w&tbm=nws"})
|
||||
|
||||
// 5. 搜索中文内容(界面英文,结果中文)
|
||||
web_fetch({"url": "https://www.google.com/search?q=人工智能&lr=lang_zh-CN&hl=en"})
|
||||
|
||||
// 6. 搜索特定价格范围的笔记本电脑
|
||||
web_fetch({"url": "https://www.google.com/search?q=laptop+%241000..%242000+best+rating"})
|
||||
|
||||
// 7. 搜索排除Wikipedia的结果
|
||||
web_fetch({"url": "https://www.google.com/search?q=python+programming+-wikipedia"})
|
||||
|
||||
// 8. 搜索学术文献
|
||||
web_fetch({"url": "https://scholar.google.com/scholar?q=deep+learning+optimization"})
|
||||
|
||||
// 9. 搜索缓存页面(查看已删除内容)
|
||||
web_fetch({"url": "https://webcache.googleusercontent.com/search?q=cache:example.com"})
|
||||
|
||||
// 10. 搜索相关网站
|
||||
web_fetch({"url": "https://www.google.com/search?q=related:stackoverflow.com"})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🦆 DuckDuckGo 深度搜索
|
||||
|
||||
### 2.1 DuckDuckGo 特色功能
|
||||
|
||||
| 功能 | 语法 | 示例 |
|
||||
|------|------|------|
|
||||
| **Bangs 快捷** | `!缩写` | `!g python` → Google搜索 |
|
||||
| **密码生成** | `password` | `https://duckduckgo.com/?q=password+20` |
|
||||
| **颜色转换** | `color` | `https://duckduckgo.com/?q=+%23FF5733` |
|
||||
| **短链接** | `shorten` | `https://duckduckgo.com/?q=shorten+example.com` |
|
||||
| **二维码生成** | `qr` | `https://duckduckgo.com/?q=qr+hello+world` |
|
||||
| **生成UUID** | `uuid` | `https://duckduckgo.com/?q=uuid` |
|
||||
| **Base64编解码** | `base64` | `https://duckduckgo.com/?q=base64+hello` |
|
||||
|
||||
### 2.2 DuckDuckGo Bangs 完整列表
|
||||
|
||||
#### 搜索引擎
|
||||
|
||||
| Bang | 跳转目标 | 示例 |
|
||||
|------|---------|------|
|
||||
| `!g` | Google | `!g python tutorial` |
|
||||
| `!b` | Bing | `!b weather` |
|
||||
| `!y` | Yahoo | `!y finance` |
|
||||
| `!sp` | Startpage | `!sp privacy` |
|
||||
| `!brave` | Brave Search | `!brave tech` |
|
||||
|
||||
#### 编程开发
|
||||
|
||||
| Bang | 跳转目标 | 示例 |
|
||||
|------|---------|------|
|
||||
| `!gh` | GitHub | `!gh tensorflow` |
|
||||
| `!so` | Stack Overflow | `!so javascript error` |
|
||||
| `!npm` | npmjs.com | `!npm express` |
|
||||
| `!pypi` | PyPI | `!pypi requests` |
|
||||
| `!mdn` | MDN Web Docs | `!mdn fetch api` |
|
||||
| `!docs` | DevDocs | `!docs python` |
|
||||
| `!docker` | Docker Hub | `!docker nginx` |
|
||||
|
||||
#### 知识百科
|
||||
|
||||
| Bang | 跳转目标 | 示例 |
|
||||
|------|---------|------|
|
||||
| `!w` | Wikipedia | `!w machine learning` |
|
||||
| `!wen` | Wikipedia英文 | `!wen artificial intelligence` |
|
||||
| `!wt` | Wiktionary | `!wt serendipity` |
|
||||
| `!imdb` | IMDb | `!imdb inception` |
|
||||
|
||||
#### 购物价格
|
||||
|
||||
| Bang | 跳转目标 | 示例 |
|
||||
|------|---------|------|
|
||||
| `!a` | Amazon | `!a wireless headphones` |
|
||||
| `!e` | eBay | `!e vintage watch` |
|
||||
| `!ali` | AliExpress | `!ali phone case` |
|
||||
|
||||
#### 地图位置
|
||||
|
||||
| Bang | 跳转目标 | 示例 |
|
||||
|------|---------|------|
|
||||
| `!m` | Google Maps | `!m Beijing` |
|
||||
| `!maps` | OpenStreetMap | `!maps Paris` |
|
||||
|
||||
### 2.3 DuckDuckGo 搜索参数
|
||||
|
||||
| 参数 | 功能 | 示例 |
|
||||
|------|------|------|
|
||||
| `kp=1` | 严格安全搜索 | `https://duckduckgo.com/html/?q=test&kp=1` |
|
||||
| `kp=-1` | 关闭安全搜索 | `https://duckduckgo.com/html/?q=test&kp=-1` |
|
||||
| `kl=cn` | 中国区域 | `https://duckduckgo.com/html/?q=news&kl=cn` |
|
||||
| `kl=us-en` | 美国英文 | `https://duckduckgo.com/html/?q=news&kl=us-en` |
|
||||
| `ia=web` | 网页结果 | `https://duckduckgo.com/?q=test&ia=web` |
|
||||
| `ia=images` | 图片结果 | `https://duckduckgo.com/?q=test&ia=images` |
|
||||
| `ia=news` | 新闻结果 | `https://duckduckgo.com/?q=test&ia=news` |
|
||||
| `ia=videos` | 视频结果 | `https://duckduckgo.com/?q=test&ia=videos` |
|
||||
|
||||
### 2.4 DuckDuckGo 深度搜索示例
|
||||
|
||||
```javascript
|
||||
// 1. 使用Bang跳转到Google搜索
|
||||
web_fetch({"url": "https://duckduckgo.com/html/?q=!g+machine+learning"})
|
||||
|
||||
// 2. 直接搜索GitHub上的项目
|
||||
web_fetch({"url": "https://duckduckgo.com/html/?q=!gh+react"})
|
||||
|
||||
// 3. 查找Stack Overflow答案
|
||||
web_fetch({"url": "https://duckduckgo.com/html/?q=!so+python+list+comprehension"})
|
||||
|
||||
// 4. 生成密码
|
||||
web_fetch({"url": "https://duckduckgo.com/?q=password+16"})
|
||||
|
||||
// 5. Base64编码
|
||||
web_fetch({"url": "https://duckduckgo.com/?q=base64+hello+world"})
|
||||
|
||||
// 6. 颜色代码转换
|
||||
web_fetch({"url": "https://duckduckgo.com/?q=%23FF5733"})
|
||||
|
||||
// 7. 搜索YouTube视频
|
||||
web_fetch({"url": "https://duckduckgo.com/html/?q=!yt+python+tutorial"})
|
||||
|
||||
// 8. 查看Wikipedia
|
||||
web_fetch({"url": "https://duckduckgo.com/html/?q=!w+artificial+intelligence"})
|
||||
|
||||
// 9. 亚马逊商品搜索
|
||||
web_fetch({"url": "https://duckduckgo.com/html/?q=!a+laptop"})
|
||||
|
||||
// 10. 生成二维码
|
||||
web_fetch({"url": "https://duckduckgo.com/?q=qr+https://github.com"})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔎 Brave Search 深度搜索
|
||||
|
||||
### 3.1 Brave Search 特色功能
|
||||
|
||||
| 功能 | 参数 | 示例 |
|
||||
|------|------|------|
|
||||
| **独立索引** | 无依赖Google/Bing | 自有爬虫索引 |
|
||||
| **Goggles** | 自定义搜索规则 | 创建个性化过滤器 |
|
||||
| **Discussions** | 论坛讨论搜索 | 聚合Reddit等论坛 |
|
||||
| **News** | 新闻聚合 | 独立新闻索引 |
|
||||
|
||||
### 3.2 Brave Search 参数
|
||||
|
||||
| 参数 | 功能 | 示例 |
|
||||
|------|------|------|
|
||||
| `tf=pw` | 本周 | `https://search.brave.com/search?q=news&tf=pw` |
|
||||
| `tf=pm` | 本月 | `https://search.brave.com/search?q=tech&tf=pm` |
|
||||
| `tf=py` | 本年 | `https://search.brave.com/search?q=AI&tf=py` |
|
||||
| `safesearch=strict` | 严格安全 | `https://search.brave.com/search?q=test&safesearch=strict` |
|
||||
| `source=web` | 网页搜索 | 默认 |
|
||||
| `source=news` | 新闻搜索 | `https://search.brave.com/search?q=tech&source=news` |
|
||||
| `source=images` | 图片搜索 | `https://search.brave.com/search?q=cat&source=images` |
|
||||
| `source=videos` | 视频搜索 | `https://search.brave.com/search?q=music&source=videos` |
|
||||
|
||||
### 3.3 Brave Search Goggles(自定义过滤器)
|
||||
|
||||
Goggles 允许创建自定义搜索规则:
|
||||
|
||||
```
|
||||
$discard // 丢弃所有
|
||||
$boost,site=stackoverflow.com // 提升Stack Overflow
|
||||
$boost,site=github.com // 提升GitHub
|
||||
$boost,site=docs.python.org // 提升Python文档
|
||||
```
|
||||
|
||||
### 3.4 Brave Search 深度搜索示例
|
||||
|
||||
```javascript
|
||||
// 1. 本周科技新闻
|
||||
web_fetch({"url": "https://search.brave.com/search?q=technology&tf=pw&source=news"})
|
||||
|
||||
// 2. 本月AI发展
|
||||
web_fetch({"url": "https://search.brave.com/search?q=artificial+intelligence&tf=pm"})
|
||||
|
||||
// 3. 图片搜索
|
||||
web_fetch({"url": "https://search.brave.com/search?q=machine+learning&source=images"})
|
||||
|
||||
// 4. 视频教程
|
||||
web_fetch({"url": "https://search.brave.com/search?q=python+tutorial&source=videos"})
|
||||
|
||||
// 5. 使用独立索引搜索
|
||||
web_fetch({"url": "https://search.brave.com/search?q=privacy+tools"})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 WolframAlpha 知识计算搜索
|
||||
|
||||
### 4.1 WolframAlpha 数据类型
|
||||
|
||||
| 类型 | 查询示例 | URL |
|
||||
|------|---------|-----|
|
||||
| **数学计算** | `integrate x^2 dx` | `https://www.wolframalpha.com/input?i=integrate+x%5E2+dx` |
|
||||
| **单位换算** | `100 miles to km` | `https://www.wolframalpha.com/input?i=100+miles+to+km` |
|
||||
| **货币转换** | `100 USD to CNY` | `https://www.wolframalpha.com/input?i=100+USD+to+CNY` |
|
||||
| **股票数据** | `AAPL stock` | `https://www.wolframalpha.com/input?i=AAPL+stock` |
|
||||
| **天气查询** | `weather in Beijing` | `https://www.wolframalpha.com/input?i=weather+in+Beijing` |
|
||||
| **人口数据** | `population of China` | `https://www.wolframalpha.com/input?i=population+of+China` |
|
||||
| **化学元素** | `properties of gold` | `https://www.wolframalpha.com/input?i=properties+of+gold` |
|
||||
| **营养成分** | `nutrition of apple` | `https://www.wolframalpha.com/input?i=nutrition+of+apple` |
|
||||
| **日期计算** | `days between Jan 1 2020 and Dec 31 2024` | 日期间隔计算 |
|
||||
| **时区转换** | `10am Beijing to New York` | 时区转换 |
|
||||
| **IP地址** | `8.8.8.8` | IP信息查询 |
|
||||
| **条形码** | `scan barcode 123456789` | 条码信息 |
|
||||
| **飞机航班** | `flight AA123` | 航班信息 |
|
||||
|
||||
### 4.2 WolframAlpha 深度搜索示例
|
||||
|
||||
```javascript
|
||||
// 1. 计算积分
|
||||
web_fetch({"url": "https://www.wolframalpha.com/input?i=integrate+sin%28x%29+from+0+to+pi"})
|
||||
|
||||
// 2. 解方程
|
||||
web_fetch({"url": "https://www.wolframalpha.com/input?i=solve+x%5E2-5x%2B6%3D0"})
|
||||
|
||||
// 3. 货币实时汇率
|
||||
web_fetch({"url": "https://www.wolframalpha.com/input?i=100+USD+to+CNY"})
|
||||
|
||||
// 4. 股票实时数据
|
||||
web_fetch({"url": "https://www.wolframalpha.com/input?i=Apple+stock+price"})
|
||||
|
||||
// 5. 城市天气
|
||||
web_fetch({"url": "https://www.wolframalpha.com/input?i=weather+in+Shanghai+tomorrow"})
|
||||
|
||||
// 6. 国家统计信息
|
||||
web_fetch({"url": "https://www.wolframalpha.com/input?i=GDP+of+China+vs+USA"})
|
||||
|
||||
// 7. 化学计算
|
||||
web_fetch({"url": "https://www.wolframalpha.com/input?i=molar+mass+of+H2SO4"})
|
||||
|
||||
// 8. 物理常数
|
||||
web_fetch({"url": "https://www.wolframalpha.com/input?i=speed+of+light"})
|
||||
|
||||
// 9. 营养信息
|
||||
web_fetch({"url": "https://www.wolframalpha.com/input?i=calories+in+banana"})
|
||||
|
||||
// 10. 历史日期
|
||||
web_fetch({"url": "https://www.wolframalpha.com/input?i=events+on+July+20+1969"})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Startpage 隐私搜索
|
||||
|
||||
### 5.1 Startpage 特色功能
|
||||
|
||||
| 功能 | 说明 | URL |
|
||||
|------|------|-----|
|
||||
| **代理浏览** | 匿名访问搜索结果 | 点击"匿名查看" |
|
||||
| **无追踪** | 不记录搜索历史 | 默认开启 |
|
||||
| **EU服务器** | 受欧盟隐私法保护 | 数据在欧洲 |
|
||||
| **代理图片** | 图片代理加载 | 隐藏IP |
|
||||
|
||||
### 5.2 Startpage 参数
|
||||
|
||||
| 参数 | 功能 | 示例 |
|
||||
|------|------|------|
|
||||
| `cat=web` | 网页搜索 | 默认 |
|
||||
| `cat=images` | 图片搜索 | `...&cat=images` |
|
||||
| `cat=video` | 视频搜索 | `...&cat=video` |
|
||||
| `cat=news` | 新闻搜索 | `...&cat=news` |
|
||||
| `language=english` | 英文结果 | `...&language=english` |
|
||||
| `time=day` | 过去24小时 | `...&time=day` |
|
||||
| `time=week` | 过去一周 | `...&time=week` |
|
||||
| `time=month` | 过去一月 | `...&time=month` |
|
||||
| `time=year` | 过去一年 | `...&time=year` |
|
||||
| `nj=0` | 关闭 family filter | `...&nj=0` |
|
||||
|
||||
### 5.3 Startpage 深度搜索示例
|
||||
|
||||
```javascript
|
||||
// 1. 隐私搜索
|
||||
web_fetch({"url": "https://www.startpage.com/sp/search?query=privacy+tools"})
|
||||
|
||||
// 2. 图片隐私搜索
|
||||
web_fetch({"url": "https://www.startpage.com/sp/search?query=nature&cat=images"})
|
||||
|
||||
// 3. 本周新闻(隐私模式)
|
||||
web_fetch({"url": "https://www.startpage.com/sp/search?query=tech+news&time=week&cat=news"})
|
||||
|
||||
// 4. 英文结果搜索
|
||||
web_fetch({"url": "https://www.startpage.com/sp/search?query=machine+learning&language=english"})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🌐 其他国际搜索引擎
|
||||
|
||||
### Yahoo
|
||||
|
||||
```javascript
|
||||
web_fetch({"url": "https://search.yahoo.com/search?p={keyword}"})
|
||||
```
|
||||
|
||||
### Ecosia(环保搜索)
|
||||
|
||||
```javascript
|
||||
web_fetch({"url": "https://www.ecosia.org/search?q={keyword}"})
|
||||
```
|
||||
|
||||
### Qwant(欧盟隐私搜索)
|
||||
|
||||
```javascript
|
||||
web_fetch({"url": "https://www.qwant.com/?q={keyword}"})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🌍 国际搜索策略
|
||||
|
||||
### 按搜索目标选择引擎
|
||||
|
||||
| 搜索目标 | 首选引擎 | 原因 |
|
||||
|---------|---------|------|
|
||||
| **学术研究** | Google Scholar | 学术资源索引最全 |
|
||||
| **编程开发** | Google + DuckDuckGo Bangs | 技术文档全面 |
|
||||
| **隐私敏感** | DuckDuckGo / Brave | 不追踪用户 |
|
||||
| **实时新闻** | Brave News | 独立新闻索引 |
|
||||
| **知识计算** | WolframAlpha | 结构化数据计算 |
|
||||
| **隐私+Google结果** | Startpage | Google结果+隐私保护 |
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
# Self-Reflections Log
|
||||
|
||||
Track self-reflections from completed work. Each entry captures what the agent learned from evaluating its own output.
|
||||
|
||||
## Format
|
||||
|
||||
```
|
||||
## [Date] — [Task Type]
|
||||
|
||||
**What I did:** Brief description
|
||||
**Outcome:** What happened (success, partial, failed)
|
||||
**Reflection:** What I noticed about my work
|
||||
**Lesson:** What to do differently next time
|
||||
**Status:** ⏳ candidate | ✅ promoted | 📦 archived
|
||||
```
|
||||
|
||||
## Example Entry
|
||||
|
||||
```
|
||||
## 2026-02-25 — Flutter UI Build
|
||||
|
||||
**What I did:** Built a settings screen with toggle switches
|
||||
**Outcome:** User said "spacing looks off"
|
||||
**Reflection:** I focused on functionality, didn't visually check the result
|
||||
**Lesson:** Always take a screenshot and evaluate visual balance before showing user
|
||||
**Status:** ✅ promoted to domains/flutter.md
|
||||
```
|
||||
|
||||
## Entries
|
||||
|
||||
(New entries appear here)
|
||||
@@ -0,0 +1,125 @@
|
||||
# Scaling Patterns
|
||||
|
||||
## Volume Thresholds
|
||||
|
||||
| Scale | Entries | Strategy |
|
||||
|-------|---------|----------|
|
||||
| Small | <100 | Single memory.md, no namespacing |
|
||||
| Medium | 100-500 | Split into domains/, basic indexing |
|
||||
| Large | 500-2000 | Full namespace hierarchy, aggressive compaction |
|
||||
| Massive | >2000 | Archive yearly, summary-only HOT tier |
|
||||
|
||||
## When to Split
|
||||
|
||||
Create new namespace file when:
|
||||
- Single file exceeds 200 lines
|
||||
- Topic has 10+ distinct corrections
|
||||
- User explicitly separates contexts ("for work...", "in this project...")
|
||||
|
||||
## Compaction Rules
|
||||
|
||||
### Merge Similar Corrections
|
||||
```
|
||||
BEFORE (3 entries):
|
||||
- [02-01] Use tabs not spaces
|
||||
- [02-03] Indent with tabs
|
||||
- [02-05] Tab indentation please
|
||||
|
||||
AFTER (1 entry):
|
||||
- Indentation: tabs (confirmed 3x, 02-01 to 02-05)
|
||||
```
|
||||
|
||||
### Summarize Verbose Patterns
|
||||
```
|
||||
BEFORE:
|
||||
- When writing emails to Marcus, use bullet points, keep under 5 items,
|
||||
no jargon, bottom-line first, he prefers morning sends
|
||||
|
||||
AFTER:
|
||||
- Marcus emails: bullets ≤5, no jargon, BLUF, AM preferred
|
||||
```
|
||||
|
||||
### Archive with Context
|
||||
When moving to COLD:
|
||||
```
|
||||
## Archived 2026-02
|
||||
|
||||
### Project: old-app (inactive since 2025-08)
|
||||
- Used Vue 2 patterns
|
||||
- Preferred Vuex over Pinia
|
||||
- CI on Jenkins (deprecated)
|
||||
|
||||
Reason: Project completed, patterns unlikely to apply
|
||||
```
|
||||
|
||||
## Index Maintenance
|
||||
|
||||
`index.md` tracks all namespaces:
|
||||
```markdown
|
||||
# Memory Index
|
||||
|
||||
## HOT (always loaded)
|
||||
- memory.md: 87 lines, updated 2026-02-15
|
||||
|
||||
## WARM (load on match)
|
||||
- projects/current-app.md: 45 lines
|
||||
- projects/side-project.md: 23 lines
|
||||
- domains/code.md: 112 lines
|
||||
- domains/writing.md: 34 lines
|
||||
|
||||
## COLD (archive)
|
||||
- archive/2025.md: 234 lines
|
||||
- archive/2024.md: 189 lines
|
||||
|
||||
Last compaction: 2026-02-01
|
||||
Next scheduled: 2026-03-01
|
||||
```
|
||||
|
||||
## Multi-Project Patterns
|
||||
|
||||
### Inheritance Chain
|
||||
```
|
||||
global (memory.md)
|
||||
└── domain (domains/code.md)
|
||||
└── project (projects/app.md)
|
||||
```
|
||||
|
||||
### Override Syntax
|
||||
In project file:
|
||||
```markdown
|
||||
## Overrides
|
||||
- indentation: spaces (overrides global tabs)
|
||||
- Reason: Project eslint config requires spaces
|
||||
```
|
||||
|
||||
### Conflict Detection
|
||||
When loading, check for conflicts:
|
||||
1. Build inheritance chain
|
||||
2. Detect contradictions
|
||||
3. Most specific wins
|
||||
4. Log conflict for later review
|
||||
|
||||
## User Type Adaptations
|
||||
|
||||
| User Type | Memory Strategy |
|
||||
|-----------|-----------------|
|
||||
| Power user | Aggressive learning, minimal confirmation |
|
||||
| Casual | Conservative learning, frequent confirmation |
|
||||
| Team shared | Per-user namespaces, shared project space |
|
||||
| Privacy-focused | Local-only, explicit consent per category |
|
||||
|
||||
## Recovery Patterns
|
||||
|
||||
### Context Lost
|
||||
If agent loses context mid-session:
|
||||
1. Re-read memory.md
|
||||
2. Check index.md for relevant namespaces
|
||||
3. Load active project namespace
|
||||
4. Continue with restored patterns
|
||||
|
||||
### Corruption Recovery
|
||||
If memory file corrupted:
|
||||
1. Check archive/ for recent backup
|
||||
2. Rebuild from corrections.md
|
||||
3. Ask user to re-confirm critical preferences
|
||||
4. Log incident for debugging
|
||||
@@ -0,0 +1,196 @@
|
||||
# Setup — Self-Improving Agent
|
||||
|
||||
## First-Time Setup
|
||||
|
||||
### 1. Create Memory Structure
|
||||
|
||||
```bash
|
||||
mkdir -p ~/self-improving/{projects,domains,archive}
|
||||
```
|
||||
|
||||
### 2. Initialize Core Files
|
||||
|
||||
Create `~/self-improving/memory.md` using `memory-template.md`:
|
||||
|
||||
```markdown
|
||||
Copy the structure from `memory-template.md` into `~/self-improving/memory.md`.
|
||||
```
|
||||
|
||||
Memory file baseline:
|
||||
```markdown
|
||||
# Memory (HOT Tier)
|
||||
|
||||
## Preferences
|
||||
|
||||
## Patterns
|
||||
|
||||
## Rules
|
||||
```
|
||||
|
||||
Create `~/self-improving/corrections.md`:
|
||||
```markdown
|
||||
# Corrections Log
|
||||
|
||||
| Date | What I Got Wrong | Correct Answer | Status |
|
||||
|------|-----------------|----------------|--------|
|
||||
```
|
||||
|
||||
Create `~/self-improving/index.md`:
|
||||
```markdown
|
||||
# Memory Index
|
||||
|
||||
| File | Lines | Last Updated |
|
||||
|------|-------|--------------|
|
||||
| memory.md | 0 | — |
|
||||
| corrections.md | 0 | — |
|
||||
```
|
||||
|
||||
Create `~/self-improving/heartbeat-state.md`:
|
||||
```markdown
|
||||
# Self-Improving Heartbeat State
|
||||
|
||||
last_heartbeat_started_at: never
|
||||
last_reviewed_change_at: never
|
||||
last_heartbeat_result: never
|
||||
|
||||
## Last actions
|
||||
- none yet
|
||||
```
|
||||
|
||||
### 3. Choose Operating Mode
|
||||
|
||||
Add to your AGENTS.md or workspace config:
|
||||
|
||||
```markdown
|
||||
## Self-Improving Mode
|
||||
|
||||
Current mode: Passive
|
||||
|
||||
Available modes:
|
||||
- Passive: Only learn from explicit corrections
|
||||
- Active: Suggest patterns after 3x repetition
|
||||
- Strict: Require confirmation for every entry
|
||||
```
|
||||
|
||||
### 4. Add SOUL.md Steering
|
||||
|
||||
Add this section to your `SOUL.md`:
|
||||
|
||||
```markdown
|
||||
**Self-Improving**
|
||||
Compounding execution quality is part of the job.
|
||||
Before non-trivial work, load `~/self-improving/memory.md` and only the smallest relevant domain or project files.
|
||||
After corrections, failed attempts, or reusable lessons, write one concise entry to the correct self-improving file immediately.
|
||||
Prefer learned rules when relevant, but keep self-inferred rules revisable.
|
||||
Do not skip retrieval just because the task feels familiar.
|
||||
```
|
||||
|
||||
### 5. Add the Proactivity Companion as Part of Setup
|
||||
|
||||
At the end of setup, briefly tell the user that you are going to add characteristics so the agent is more proactive:
|
||||
|
||||
- noticing missing next steps
|
||||
- verifying outcomes instead of assuming they landed
|
||||
- recovering context better after long or interrupted threads
|
||||
- keeping the right level of initiative
|
||||
|
||||
Then say that, for this, you are going to install the `Proactivity` skill.
|
||||
Only install it after the user explicitly agrees.
|
||||
|
||||
If the user agrees:
|
||||
|
||||
1. Run `clawhub install proactivity`
|
||||
2. Read the installed `proactivity` skill
|
||||
3. Continue into its setup flow immediately so the skill is active for this workspace
|
||||
|
||||
If the user says no, skip it cleanly and continue with self-improving only.
|
||||
|
||||
### 6. Refine AGENTS.md Memory Section (Non-Destructive)
|
||||
|
||||
Update `AGENTS.md` by complementing the existing `## Memory` section. Do not replace the whole section and do not remove existing lines.
|
||||
|
||||
If your `## Memory` block differs from the default template, insert the same additions in equivalent places so existing information is preserved.
|
||||
|
||||
Add this line in the continuity list (next to Daily notes and Long-term):
|
||||
|
||||
```markdown
|
||||
- **Self-improving:** `~/self-improving/` (via `self-improving` skill) — execution-improvement memory (preferences, workflows, style patterns, what improved/worsened outcomes)
|
||||
```
|
||||
|
||||
Right after the sentence "Capture what matters...", add:
|
||||
|
||||
```markdown
|
||||
Use `memory/YYYY-MM-DD.md` and `MEMORY.md` for factual continuity (events, context, decisions).
|
||||
Use `~/self-improving/` for compounding execution quality across tasks.
|
||||
For compounding quality, read `~/self-improving/memory.md` before non-trivial work, then load only the smallest relevant domain or project files.
|
||||
If in doubt, store factual history in `memory/YYYY-MM-DD.md` / `MEMORY.md`, and store reusable performance lessons in `~/self-improving/` (tentative until human validation).
|
||||
```
|
||||
|
||||
Before the "Write It Down" subsection, add:
|
||||
|
||||
```markdown
|
||||
Before any non-trivial task:
|
||||
- Read `~/self-improving/memory.md`
|
||||
- List available files first:
|
||||
```bash
|
||||
for d in ~/self-improving/domains ~/self-improving/projects; do
|
||||
[ -d "$d" ] && find "$d" -maxdepth 1 -type f -name "*.md"
|
||||
done | sort
|
||||
```
|
||||
- Read up to 3 matching files from `~/self-improving/domains/`
|
||||
- If a project is clearly active, also read `~/self-improving/projects/<project>.md`
|
||||
- Do not read unrelated domains "just in case"
|
||||
|
||||
If inferring a new rule, keep it tentative until human validation.
|
||||
```
|
||||
|
||||
Inside the "Write It Down" bullets, refine the behavior (non-destructive):
|
||||
- Keep existing intent, but route execution-improvement content to `~/self-improving/`.
|
||||
- If the exact bullets exist, replace only these lines; if wording differs, apply equivalent edits without removing unrelated guidance.
|
||||
|
||||
Use this target wording:
|
||||
|
||||
```markdown
|
||||
- When someone says "remember this" → if it's factual context/event, update `memory/YYYY-MM-DD.md`; if it's a correction, preference, workflow/style choice, or performance lesson, log it in `~/self-improving/`
|
||||
- Explicit user correction → append to `~/self-improving/corrections.md` immediately
|
||||
- Reusable global rule or preference → append to `~/self-improving/memory.md`
|
||||
- Domain-specific lesson → append to `~/self-improving/domains/<domain>.md`
|
||||
- Project-only override → append to `~/self-improving/projects/<project>.md`
|
||||
- Keep entries short, concrete, and one lesson per bullet; if scope is ambiguous, default to domain rather than global
|
||||
- After a correction or strong reusable lesson, write it before the final response
|
||||
```
|
||||
|
||||
## Verification
|
||||
|
||||
Run "memory stats" to confirm setup:
|
||||
|
||||
```
|
||||
📊 Self-Improving Memory
|
||||
|
||||
🔥 HOT (always loaded):
|
||||
memory.md: 0 entries
|
||||
|
||||
🌡️ WARM (load on demand):
|
||||
projects/: 0 files
|
||||
domains/: 0 files
|
||||
|
||||
❄️ COLD (archived):
|
||||
archive/: 0 files
|
||||
|
||||
⚙️ Mode: Passive
|
||||
```
|
||||
|
||||
### 7. Add HEARTBEAT.md Steering
|
||||
|
||||
Add this section to your `HEARTBEAT.md`:
|
||||
|
||||
```markdown
|
||||
## Self-Improving Check
|
||||
|
||||
- Read `./skills/self-improving/heartbeat-rules.md`
|
||||
- Use `~/self-improving/heartbeat-state.md` for last-run markers and action notes
|
||||
- If no file inside `~/self-improving/` changed since the last reviewed change, return `HEARTBEAT_OK`
|
||||
```
|
||||
|
||||
Keep this in the same default setup flow as the AGENTS and SOUL additions so recurring maintenance is installed consistently.
|
||||
If your installed skills path differs, keep the same three lines but point the first line at the installed copy of `heartbeat-rules.md`.
|
||||
@@ -0,0 +1,92 @@
|
||||
# Deep Agents CLI Skills
|
||||
|
||||
A curated pack of skills designed to empower your agent's **long-term memory** and **autonomy**. These skills act as middleware, letting your main session's agent decide when to delegate sub-tasks or manage its own context.
|
||||
|
||||
---
|
||||
|
||||
## Core Skill: `autosubagents` (Sub-Agent Orchestrator)
|
||||
|
||||
Delegate complex, one-off tasks to a persistent sub-agent (often called the "Admin" or "Runner" session).
|
||||
|
||||
**Trigger:** User sends a direct message or spawns a session.
|
||||
**Outcome:** Agent creates an isolated sub-agent session (`runtime="subagent"`) and sends it the task.
|
||||
|
||||
### When to Use
|
||||
- When the current session gets too chatty and you need to "offload" work.
|
||||
- For tasks that need multiple tools or a dedicated context window.
|
||||
|
||||
**Example Flow:**
|
||||
1. User sends: "Let's do that."
|
||||
2. Agent triggers: `deepagents autosubagent "That's the task."`
|
||||
3. Agent listens: Spawns sub-agent, waits for response.
|
||||
4. User gets: The sub-agent's finished summary.
|
||||
|
||||
### Skills Packaged
|
||||
- **`context-compress`** (Autonomous Context Compression): Automatically summarize past messages when the session gets heavy.
|
||||
- **`session-history`** (Text-Based Fetch): Quickly grab the last N messages from another session.
|
||||
|
||||
### How It Works
|
||||
```bash
|
||||
deepagents autosubagent --task "Summarize the last 5 chats"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Core Skill: `compact` (Context Compactor)
|
||||
|
||||
A standalone tool that takes a "summary" session and injects its condensed message back into the parent session, effectively **compressing** the parent's history.
|
||||
|
||||
**Trigger:** The parent session has received 3+ sub-agent responses.
|
||||
**Action:** Fetches the sub-agent's history, pulls out the "summary" payload, and pings it back.
|
||||
|
||||
### How It Works
|
||||
1. **Parent** sends a task to **Sub-Agent**.
|
||||
2. **Sub-Agent** runs and uses `context-compress` to condense the chat.
|
||||
3. **Parent** receives the summary via a new message.
|
||||
|
||||
### CLI Usage
|
||||
```bash
|
||||
deepagents compact --parent "main-session" --target "sub-session-name"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Setup Instructions
|
||||
|
||||
### 1. Install the CLI
|
||||
```bash
|
||||
npm install -g deepagents
|
||||
```
|
||||
|
||||
### 2. Configure in OpenClaw
|
||||
Point your OpenClaw `runtime` to a path where the CLI lives:
|
||||
```yaml
|
||||
# ~/.openclaw/env.d/
|
||||
deepagents:
|
||||
runtime: acp
|
||||
cwd: /path/to/deepagents-bin
|
||||
```
|
||||
|
||||
### 3. Link the Skills Folder
|
||||
```bash
|
||||
ln -s ~/.openclaw/workspace/skills/deepagents ~/.deepagents/deep-organizer
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Usage Patterns
|
||||
|
||||
### Pattern A: "Set and Forget" (Best for one-off tasks)
|
||||
```bash
|
||||
deepagents autosubagent --task "Research this topic"
|
||||
```
|
||||
*The Agent will spawn a sub-agent, let it run its course, and return the results.*
|
||||
|
||||
### Pattern B: "The Deep Work Loop"
|
||||
1. **Setup Phase:** Have the sub-agent pre-loaded with its own skills (`context-compress` + `session-history`).
|
||||
2. **Task Phase:** Spawn a new `autosubagent` instance for the day's main task.
|
||||
3. **Compression Phase:** Let the sub-agent do its thing. If the conversation gets long, have the sub-agent call `context-compress` automatically.
|
||||
|
||||
---
|
||||
|
||||
*Version: 1.0 — *Refined for OpenClaw's sub-agent ecosystem*.*
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"version": 1,
|
||||
"registry": "https://clawhub.ai",
|
||||
"slug": "elite-longterm-memory-lobster",
|
||||
"installedVersion": "1.0.0",
|
||||
"installedAt": 1775613906665
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
# Elite Longterm Memory 🧠
|
||||
|
||||
**The ultimate memory system for AI agents.** Never lose context again.
|
||||
|
||||
[](https://www.npmjs.com/package/elite-longterm-memory)
|
||||
[](https://www.npmjs.com/package/elite-longterm-memory)
|
||||
[](https://opensource.org/licenses/MIT)
|
||||
|
||||
---
|
||||
|
||||
## Works With
|
||||
|
||||
<p align="center">
|
||||
<img src="https://img.shields.io/badge/Claude-AI-orange?style=for-the-badge&logo=anthropic" alt="Claude AI" />
|
||||
<img src="https://img.shields.io/badge/GPT-OpenAI-412991?style=for-the-badge&logo=openai" alt="GPT" />
|
||||
<img src="https://img.shields.io/badge/Cursor-IDE-000000?style=for-the-badge" alt="Cursor" />
|
||||
<img src="https://img.shields.io/badge/LangChain-Framework-1C3C3C?style=for-the-badge" alt="LangChain" />
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<strong>Built for:</strong> Clawdbot • Moltbot • Claude Code • Any AI Agent
|
||||
</p>
|
||||
|
||||
---
|
||||
|
||||
Combines 7 proven memory approaches into one bulletproof architecture:
|
||||
|
||||
- ✅ **Bulletproof WAL Protocol** — Write-ahead logging survives compaction
|
||||
- ✅ **LanceDB Vector Search** — Semantic recall of relevant memories
|
||||
- ✅ **Git-Notes Knowledge Graph** — Structured decisions, branch-aware
|
||||
- ✅ **File-Based Archives** — Human-readable MEMORY.md + daily logs
|
||||
- ✅ **Cloud Backup** — Optional SuperMemory sync
|
||||
- ✅ **Memory Hygiene** — Keep vectors lean, prevent token waste
|
||||
- ✅ **Mem0 Auto-Extraction** — Automatic fact extraction, 80% token reduction
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
# Initialize in your workspace
|
||||
npx elite-longterm-memory init
|
||||
|
||||
# Check status
|
||||
npx elite-longterm-memory status
|
||||
|
||||
# Create today's log
|
||||
npx elite-longterm-memory today
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────┐
|
||||
│ ELITE LONGTERM MEMORY │
|
||||
├─────────────────────────────────────────────────────┤
|
||||
│ HOT RAM WARM STORE COLD STORE │
|
||||
│ SESSION-STATE.md → LanceDB → Git-Notes │
|
||||
│ (survives (semantic (permanent │
|
||||
│ compaction) search) decisions) │
|
||||
│ │ │ │ │
|
||||
│ └──────────────┼────────────────┘ │
|
||||
│ ▼ │
|
||||
│ MEMORY.md │
|
||||
│ (curated archive) │
|
||||
└─────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## The 5 Memory Layers
|
||||
|
||||
| Layer | File/System | Purpose | Persistence |
|
||||
|-------|-------------|---------|-------------|
|
||||
| 1. Hot RAM | SESSION-STATE.md | Active task context | Survives compaction |
|
||||
| 2. Warm Store | LanceDB | Semantic search | Auto-recall |
|
||||
| 3. Cold Store | Git-Notes | Structured decisions | Permanent |
|
||||
| 4. Archive | MEMORY.md + daily/ | Human-readable | Curated |
|
||||
| 5. Cloud | SuperMemory | Cross-device sync | Optional |
|
||||
|
||||
## The WAL Protocol
|
||||
|
||||
**Critical insight:** Write state BEFORE responding, not after.
|
||||
|
||||
```
|
||||
User: "Let's use Tailwind for this project"
|
||||
|
||||
Agent (internal):
|
||||
1. Write to SESSION-STATE.md → "Decision: Use Tailwind"
|
||||
2. THEN respond → "Got it — Tailwind it is..."
|
||||
```
|
||||
|
||||
If you respond first and crash before saving, context is lost. WAL ensures durability.
|
||||
|
||||
## Why Memory Fails (And How to Fix It)
|
||||
|
||||
| Problem | Cause | Fix |
|
||||
|---------|-------|-----|
|
||||
| Forgets everything | memory_search disabled | Enable + add OpenAI key |
|
||||
| Repeats mistakes | Lessons not logged | Write to memory/lessons.md |
|
||||
| Sub-agents isolated | No context inheritance | Pass context in task prompt |
|
||||
| Facts not captured | No auto-extraction | Use Mem0 (see below) |
|
||||
|
||||
## Mem0 Integration (Recommended)
|
||||
|
||||
Auto-extract facts from conversations. 80% token reduction.
|
||||
|
||||
```bash
|
||||
npm install mem0ai
|
||||
export MEM0_API_KEY="your-key"
|
||||
```
|
||||
|
||||
```javascript
|
||||
const { MemoryClient } = require('mem0ai');
|
||||
const client = new MemoryClient({ apiKey: process.env.MEM0_API_KEY });
|
||||
|
||||
// Auto-extracts facts from messages
|
||||
await client.add(messages, { user_id: "user123" });
|
||||
|
||||
// Retrieve relevant memories
|
||||
const memories = await client.search(query, { user_id: "user123" });
|
||||
```
|
||||
|
||||
## For Clawdbot/Moltbot Users
|
||||
|
||||
Add to `~/.clawdbot/clawdbot.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"memorySearch": {
|
||||
"enabled": true,
|
||||
"provider": "openai",
|
||||
"sources": ["memory"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Files Created
|
||||
|
||||
```
|
||||
workspace/
|
||||
├── SESSION-STATE.md # Hot RAM (active context)
|
||||
├── MEMORY.md # Curated long-term memory
|
||||
└── memory/
|
||||
├── 2026-01-30.md # Daily logs
|
||||
└── ...
|
||||
```
|
||||
|
||||
## Commands
|
||||
|
||||
```bash
|
||||
elite-memory init # Initialize memory system
|
||||
elite-memory status # Check health
|
||||
elite-memory today # Create today's log
|
||||
elite-memory help # Show help
|
||||
```
|
||||
|
||||
## Links
|
||||
|
||||
- [Full Documentation (SKILL.md)](./SKILL.md)
|
||||
- [ClawdHub](https://clawdhub.com/skills/elite-longterm-memory)
|
||||
- [GitHub](https://github.com/NextFrontierBuilds/elite-longterm-memory)
|
||||
|
||||
---
|
||||
|
||||
Built by [@NextXFrontier](https://x.com/NextXFrontier)
|
||||
@@ -0,0 +1,409 @@
|
||||
---
|
||||
name: elite-longterm-memory
|
||||
version: 1.2.0
|
||||
description: "Ultimate AI agent memory system. Combines bulletproof WAL protocol, vector search, git-based knowledge graphs, cloud backup, and maintenance hygiene. Never lose context again. For Clawdbot, Moltbot, Claude, GPT agents."
|
||||
author: NextFrontierBuilds
|
||||
keywords: [memory, ai-agent, long-term-memory, vector-search, lancedb, git-notes, wal, persistent-context, claude, gpt, clawdbot, moltbot]
|
||||
metadata:
|
||||
clawdbot:
|
||||
emoji: "🧠"
|
||||
requires:
|
||||
env:
|
||||
- OPENAI_API_KEY
|
||||
plugins:
|
||||
- memory-lancedb
|
||||
---
|
||||
|
||||
# Elite Longterm Memory 🧠
|
||||
|
||||
**The ultimate memory system for AI agents.** Combines 6 proven approaches into one bulletproof architecture.
|
||||
|
||||
Never lose context. Never forget decisions. Never repeat mistakes.
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ ELITE LONGTERM MEMORY │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
|
||||
│ │ HOT RAM │ │ WARM STORE │ │ COLD STORE │ │
|
||||
│ │ │ │ │ │ │ │
|
||||
│ │ SESSION- │ │ LanceDB │ │ Git-Notes │ │
|
||||
│ │ STATE.md │ │ Vectors │ │ Knowledge │ │
|
||||
│ │ │ │ │ │ Graph │ │
|
||||
│ │ (survives │ │ (semantic │ │ (permanent │ │
|
||||
│ │ compaction)│ │ search) │ │ decisions) │ │
|
||||
│ └─────────────┘ └─────────────┘ └─────────────┘ │
|
||||
│ │ │ │ │
|
||||
│ └────────────────┼────────────────┘ │
|
||||
│ ▼ │
|
||||
│ ┌─────────────┐ │
|
||||
│ │ MEMORY.md │ ← Curated long-term │
|
||||
│ │ + daily/ │ (human-readable) │
|
||||
│ └─────────────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌─────────────┐ │
|
||||
│ │ SuperMemory │ ← Cloud backup (optional) │
|
||||
│ │ API │ │
|
||||
│ └─────────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## The 5 Memory Layers
|
||||
|
||||
### Layer 1: HOT RAM (SESSION-STATE.md)
|
||||
**From: bulletproof-memory**
|
||||
|
||||
Active working memory that survives compaction. Write-Ahead Log protocol.
|
||||
|
||||
```markdown
|
||||
# SESSION-STATE.md — Active Working Memory
|
||||
|
||||
## Current Task
|
||||
[What we're working on RIGHT NOW]
|
||||
|
||||
## Key Context
|
||||
- User preference: ...
|
||||
- Decision made: ...
|
||||
- Blocker: ...
|
||||
|
||||
## Pending Actions
|
||||
- [ ] ...
|
||||
```
|
||||
|
||||
**Rule:** Write BEFORE responding. Triggered by user input, not agent memory.
|
||||
|
||||
### Layer 2: WARM STORE (LanceDB Vectors)
|
||||
**From: lancedb-memory**
|
||||
|
||||
Semantic search across all memories. Auto-recall injects relevant context.
|
||||
|
||||
```bash
|
||||
# Auto-recall (happens automatically)
|
||||
memory_recall query="project status" limit=5
|
||||
|
||||
# Manual store
|
||||
memory_store text="User prefers dark mode" category="preference" importance=0.9
|
||||
```
|
||||
|
||||
### Layer 3: COLD STORE (Git-Notes Knowledge Graph)
|
||||
**From: git-notes-memory**
|
||||
|
||||
Structured decisions, learnings, and context. Branch-aware.
|
||||
|
||||
```bash
|
||||
# Store a decision (SILENT - never announce)
|
||||
python3 memory.py -p $DIR remember '{"type":"decision","content":"Use React for frontend"}' -t tech -i h
|
||||
|
||||
# Retrieve context
|
||||
python3 memory.py -p $DIR get "frontend"
|
||||
```
|
||||
|
||||
### Layer 4: CURATED ARCHIVE (MEMORY.md + daily/)
|
||||
**From: Clawdbot native**
|
||||
|
||||
Human-readable long-term memory. Daily logs + distilled wisdom.
|
||||
|
||||
```
|
||||
workspace/
|
||||
├── MEMORY.md # Curated long-term (the good stuff)
|
||||
└── memory/
|
||||
├── 2026-01-30.md # Daily log
|
||||
├── 2026-01-29.md
|
||||
└── topics/ # Topic-specific files
|
||||
```
|
||||
|
||||
### Layer 5: CLOUD BACKUP (SuperMemory) — Optional
|
||||
**From: supermemory**
|
||||
|
||||
Cross-device sync. Chat with your knowledge base.
|
||||
|
||||
```bash
|
||||
export SUPERMEMORY_API_KEY="your-key"
|
||||
supermemory add "Important context"
|
||||
supermemory search "what did we decide about..."
|
||||
```
|
||||
|
||||
### Layer 6: AUTO-EXTRACTION (Mem0) — Recommended
|
||||
**NEW: Automatic fact extraction**
|
||||
|
||||
Mem0 automatically extracts facts from conversations. 80% token reduction.
|
||||
|
||||
```bash
|
||||
npm install mem0ai
|
||||
export MEM0_API_KEY="your-key"
|
||||
```
|
||||
|
||||
```javascript
|
||||
const { MemoryClient } = require('mem0ai');
|
||||
const client = new MemoryClient({ apiKey: process.env.MEM0_API_KEY });
|
||||
|
||||
// Conversations auto-extract facts
|
||||
await client.add(messages, { user_id: "user123" });
|
||||
|
||||
// Retrieve relevant memories
|
||||
const memories = await client.search(query, { user_id: "user123" });
|
||||
```
|
||||
|
||||
Benefits:
|
||||
- Auto-extracts preferences, decisions, facts
|
||||
- Deduplicates and updates existing memories
|
||||
- 80% reduction in tokens vs raw history
|
||||
- Works across sessions automatically
|
||||
|
||||
## Quick Setup
|
||||
|
||||
### 1. Create SESSION-STATE.md (Hot RAM)
|
||||
|
||||
```bash
|
||||
cat > SESSION-STATE.md << 'EOF'
|
||||
# SESSION-STATE.md — Active Working Memory
|
||||
|
||||
This file is the agent's "RAM" — survives compaction, restarts, distractions.
|
||||
|
||||
## Current Task
|
||||
[None]
|
||||
|
||||
## Key Context
|
||||
[None yet]
|
||||
|
||||
## Pending Actions
|
||||
- [ ] None
|
||||
|
||||
## Recent Decisions
|
||||
[None yet]
|
||||
|
||||
---
|
||||
*Last updated: [timestamp]*
|
||||
EOF
|
||||
```
|
||||
|
||||
### 2. Enable LanceDB (Warm Store)
|
||||
|
||||
In `~/.clawdbot/clawdbot.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"memorySearch": {
|
||||
"enabled": true,
|
||||
"provider": "openai",
|
||||
"sources": ["memory"],
|
||||
"minScore": 0.3,
|
||||
"maxResults": 10
|
||||
},
|
||||
"plugins": {
|
||||
"entries": {
|
||||
"memory-lancedb": {
|
||||
"enabled": true,
|
||||
"config": {
|
||||
"autoCapture": false,
|
||||
"autoRecall": true,
|
||||
"captureCategories": ["preference", "decision", "fact"],
|
||||
"minImportance": 0.7
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Initialize Git-Notes (Cold Store)
|
||||
|
||||
```bash
|
||||
cd ~/clawd
|
||||
git init # if not already
|
||||
python3 skills/git-notes-memory/memory.py -p . sync --start
|
||||
```
|
||||
|
||||
### 4. Verify MEMORY.md Structure
|
||||
|
||||
```bash
|
||||
# Ensure you have:
|
||||
# - MEMORY.md in workspace root
|
||||
# - memory/ folder for daily logs
|
||||
mkdir -p memory
|
||||
```
|
||||
|
||||
### 5. (Optional) Setup SuperMemory
|
||||
|
||||
```bash
|
||||
export SUPERMEMORY_API_KEY="your-key"
|
||||
# Add to ~/.zshrc for persistence
|
||||
```
|
||||
|
||||
## Agent Instructions
|
||||
|
||||
### On Session Start
|
||||
1. Read SESSION-STATE.md — this is your hot context
|
||||
2. Run `memory_search` for relevant prior context
|
||||
3. Check memory/YYYY-MM-DD.md for recent activity
|
||||
|
||||
### During Conversation
|
||||
1. **User gives concrete detail?** → Write to SESSION-STATE.md BEFORE responding
|
||||
2. **Important decision made?** → Store in Git-Notes (SILENTLY)
|
||||
3. **Preference expressed?** → `memory_store` with importance=0.9
|
||||
|
||||
### On Session End
|
||||
1. Update SESSION-STATE.md with final state
|
||||
2. Move significant items to MEMORY.md if worth keeping long-term
|
||||
3. Create/update daily log in memory/YYYY-MM-DD.md
|
||||
|
||||
### Memory Hygiene (Weekly)
|
||||
1. Review SESSION-STATE.md — archive completed tasks
|
||||
2. Check LanceDB for junk: `memory_recall query="*" limit=50`
|
||||
3. Clear irrelevant vectors: `memory_forget id=<id>`
|
||||
4. Consolidate daily logs into MEMORY.md
|
||||
|
||||
## The WAL Protocol (Critical)
|
||||
|
||||
**Write-Ahead Log:** Write state BEFORE responding, not after.
|
||||
|
||||
| Trigger | Action |
|
||||
|---------|--------|
|
||||
| User states preference | Write to SESSION-STATE.md → then respond |
|
||||
| User makes decision | Write to SESSION-STATE.md → then respond |
|
||||
| User gives deadline | Write to SESSION-STATE.md → then respond |
|
||||
| User corrects you | Write to SESSION-STATE.md → then respond |
|
||||
|
||||
**Why?** If you respond first and crash/compact before saving, context is lost. WAL ensures durability.
|
||||
|
||||
## Example Workflow
|
||||
|
||||
```
|
||||
User: "Let's use Tailwind for this project, not vanilla CSS"
|
||||
|
||||
Agent (internal):
|
||||
1. Write to SESSION-STATE.md: "Decision: Use Tailwind, not vanilla CSS"
|
||||
2. Store in Git-Notes: decision about CSS framework
|
||||
3. memory_store: "User prefers Tailwind over vanilla CSS" importance=0.9
|
||||
4. THEN respond: "Got it — Tailwind it is..."
|
||||
```
|
||||
|
||||
## Maintenance Commands
|
||||
|
||||
```bash
|
||||
# Audit vector memory
|
||||
memory_recall query="*" limit=50
|
||||
|
||||
# Clear all vectors (nuclear option)
|
||||
rm -rf ~/.clawdbot/memory/lancedb/
|
||||
clawdbot gateway restart
|
||||
|
||||
# Export Git-Notes
|
||||
python3 memory.py -p . export --format json > memories.json
|
||||
|
||||
# Check memory health
|
||||
du -sh ~/.clawdbot/memory/
|
||||
wc -l MEMORY.md
|
||||
ls -la memory/
|
||||
```
|
||||
|
||||
## Why Memory Fails
|
||||
|
||||
Understanding the root causes helps you fix them:
|
||||
|
||||
| Failure Mode | Cause | Fix |
|
||||
|--------------|-------|-----|
|
||||
| Forgets everything | `memory_search` disabled | Enable + add OpenAI key |
|
||||
| Files not loaded | Agent skips reading memory | Add to AGENTS.md rules |
|
||||
| Facts not captured | No auto-extraction | Use Mem0 or manual logging |
|
||||
| Sub-agents isolated | Don't inherit context | Pass context in task prompt |
|
||||
| Repeats mistakes | Lessons not logged | Write to memory/lessons.md |
|
||||
|
||||
## Solutions (Ranked by Effort)
|
||||
|
||||
### 1. Quick Win: Enable memory_search
|
||||
|
||||
If you have an OpenAI key, enable semantic search:
|
||||
|
||||
```bash
|
||||
clawdbot configure --section web
|
||||
```
|
||||
|
||||
This enables vector search over MEMORY.md + memory/*.md files.
|
||||
|
||||
### 2. Recommended: Mem0 Integration
|
||||
|
||||
Auto-extract facts from conversations. 80% token reduction.
|
||||
|
||||
```bash
|
||||
npm install mem0ai
|
||||
```
|
||||
|
||||
```javascript
|
||||
const { MemoryClient } = require('mem0ai');
|
||||
|
||||
const client = new MemoryClient({ apiKey: process.env.MEM0_API_KEY });
|
||||
|
||||
// Auto-extract and store
|
||||
await client.add([
|
||||
{ role: "user", content: "I prefer Tailwind over vanilla CSS" }
|
||||
], { user_id: "ty" });
|
||||
|
||||
// Retrieve relevant memories
|
||||
const memories = await client.search("CSS preferences", { user_id: "ty" });
|
||||
```
|
||||
|
||||
### 3. Better File Structure (No Dependencies)
|
||||
|
||||
```
|
||||
memory/
|
||||
├── projects/
|
||||
│ ├── strykr.md
|
||||
│ └── taska.md
|
||||
├── people/
|
||||
│ └── contacts.md
|
||||
├── decisions/
|
||||
│ └── 2026-01.md
|
||||
├── lessons/
|
||||
│ └── mistakes.md
|
||||
└── preferences.md
|
||||
```
|
||||
|
||||
Keep MEMORY.md as a summary (<5KB), link to detailed files.
|
||||
|
||||
## Immediate Fixes Checklist
|
||||
|
||||
| Problem | Fix |
|
||||
|---------|-----|
|
||||
| Forgets preferences | Add `## Preferences` section to MEMORY.md |
|
||||
| Repeats mistakes | Log every mistake to `memory/lessons.md` |
|
||||
| Sub-agents lack context | Include key context in spawn task prompt |
|
||||
| Forgets recent work | Strict daily file discipline |
|
||||
| Memory search not working | Check `OPENAI_API_KEY` is set |
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**Agent keeps forgetting mid-conversation:**
|
||||
→ SESSION-STATE.md not being updated. Check WAL protocol.
|
||||
|
||||
**Irrelevant memories injected:**
|
||||
→ Disable autoCapture, increase minImportance threshold.
|
||||
|
||||
**Memory too large, slow recall:**
|
||||
→ Run hygiene: clear old vectors, archive daily logs.
|
||||
|
||||
**Git-Notes not persisting:**
|
||||
→ Run `git notes push` to sync with remote.
|
||||
|
||||
**memory_search returns nothing:**
|
||||
→ Check OpenAI API key: `echo $OPENAI_API_KEY`
|
||||
→ Verify memorySearch enabled in clawdbot.json
|
||||
|
||||
---
|
||||
|
||||
## Links
|
||||
|
||||
- bulletproof-memory: https://clawdhub.com/skills/bulletproof-memory
|
||||
- lancedb-memory: https://clawdhub.com/skills/lancedb-memory
|
||||
- git-notes-memory: https://clawdhub.com/skills/git-notes-memory
|
||||
- memory-hygiene: https://clawdhub.com/skills/memory-hygiene
|
||||
- supermemory: https://clawdhub.com/skills/supermemory
|
||||
|
||||
---
|
||||
|
||||
*Built by [@NextXFrontier](https://x.com/NextXFrontier) — Part of the Next Frontier AI toolkit*
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"ownerId": "kn72je8kwsp9fkwdv3va6ay4n582g9k5",
|
||||
"slug": "elite-longterm-memory-lobster",
|
||||
"version": "1.0.0",
|
||||
"publishedAt": 1772988214705
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const TEMPLATES = {
|
||||
'session-state': `# SESSION-STATE.md — Active Working Memory
|
||||
|
||||
This file is the agent's "RAM" — survives compaction, restarts, distractions.
|
||||
Chat history is a BUFFER. This file is STORAGE.
|
||||
|
||||
## Current Task
|
||||
[None]
|
||||
|
||||
## Key Context
|
||||
[None yet]
|
||||
|
||||
## Pending Actions
|
||||
- [ ] None
|
||||
|
||||
## Recent Decisions
|
||||
[None yet]
|
||||
|
||||
---
|
||||
*Last updated: ${new Date().toISOString()}*
|
||||
`,
|
||||
|
||||
'memory-md': `# MEMORY.md — Long-Term Memory
|
||||
|
||||
## About the User
|
||||
[Add user preferences, communication style, etc.]
|
||||
|
||||
## Projects
|
||||
[Active projects and their status]
|
||||
|
||||
## Decisions Log
|
||||
[Important decisions and why they were made]
|
||||
|
||||
## Lessons Learned
|
||||
[Mistakes to avoid, patterns that work]
|
||||
|
||||
## Preferences
|
||||
[Tools, frameworks, workflows the user prefers]
|
||||
|
||||
---
|
||||
*Curated memory — distill insights from daily logs here*
|
||||
`,
|
||||
|
||||
'daily-template': `# {{DATE}} — Daily Log
|
||||
|
||||
## Tasks Completed
|
||||
-
|
||||
|
||||
## Decisions Made
|
||||
-
|
||||
|
||||
## Lessons Learned
|
||||
-
|
||||
|
||||
## Tomorrow
|
||||
-
|
||||
`
|
||||
};
|
||||
|
||||
const commands = {
|
||||
init: () => {
|
||||
console.log('🧠 Initializing Elite Longterm Memory...\n');
|
||||
|
||||
// Create SESSION-STATE.md
|
||||
if (!fs.existsSync('SESSION-STATE.md')) {
|
||||
fs.writeFileSync('SESSION-STATE.md', TEMPLATES['session-state']);
|
||||
console.log('✓ Created SESSION-STATE.md (Hot RAM)');
|
||||
} else {
|
||||
console.log('• SESSION-STATE.md already exists');
|
||||
}
|
||||
|
||||
// Create MEMORY.md
|
||||
if (!fs.existsSync('MEMORY.md')) {
|
||||
fs.writeFileSync('MEMORY.md', TEMPLATES['memory-md']);
|
||||
console.log('✓ Created MEMORY.md (Curated Archive)');
|
||||
} else {
|
||||
console.log('• MEMORY.md already exists');
|
||||
}
|
||||
|
||||
// Create memory directory
|
||||
if (!fs.existsSync('memory')) {
|
||||
fs.mkdirSync('memory', { recursive: true });
|
||||
console.log('✓ Created memory/ directory');
|
||||
} else {
|
||||
console.log('• memory/ directory already exists');
|
||||
}
|
||||
|
||||
// Create today's log
|
||||
const today = new Date().toISOString().split('T')[0];
|
||||
const todayFile = `memory/${today}.md`;
|
||||
if (!fs.existsSync(todayFile)) {
|
||||
const content = TEMPLATES['daily-template'].replace('{{DATE}}', today);
|
||||
fs.writeFileSync(todayFile, content);
|
||||
console.log(`✓ Created ${todayFile}`);
|
||||
}
|
||||
|
||||
console.log('\n🎉 Elite Longterm Memory initialized!');
|
||||
console.log('\nNext steps:');
|
||||
console.log('1. Add SESSION-STATE.md to your agent context');
|
||||
console.log('2. Configure LanceDB plugin in clawdbot.json');
|
||||
console.log('3. Review SKILL.md for full setup guide');
|
||||
},
|
||||
|
||||
today: () => {
|
||||
const today = new Date().toISOString().split('T')[0];
|
||||
const todayFile = `memory/${today}.md`;
|
||||
|
||||
if (!fs.existsSync('memory')) {
|
||||
fs.mkdirSync('memory', { recursive: true });
|
||||
}
|
||||
|
||||
if (!fs.existsSync(todayFile)) {
|
||||
const content = TEMPLATES['daily-template'].replace('{{DATE}}', today);
|
||||
fs.writeFileSync(todayFile, content);
|
||||
console.log(`✓ Created ${todayFile}`);
|
||||
} else {
|
||||
console.log(`• ${todayFile} already exists`);
|
||||
}
|
||||
},
|
||||
|
||||
status: () => {
|
||||
console.log('🧠 Elite Longterm Memory Status\n');
|
||||
|
||||
// Check SESSION-STATE.md
|
||||
if (fs.existsSync('SESSION-STATE.md')) {
|
||||
const stat = fs.statSync('SESSION-STATE.md');
|
||||
console.log(`✓ SESSION-STATE.md (${(stat.size / 1024).toFixed(1)}KB, modified ${stat.mtime.toLocaleString()})`);
|
||||
} else {
|
||||
console.log('✗ SESSION-STATE.md missing');
|
||||
}
|
||||
|
||||
// Check MEMORY.md
|
||||
if (fs.existsSync('MEMORY.md')) {
|
||||
const stat = fs.statSync('MEMORY.md');
|
||||
const lines = fs.readFileSync('MEMORY.md', 'utf8').split('\n').length;
|
||||
console.log(`✓ MEMORY.md (${lines} lines, ${(stat.size / 1024).toFixed(1)}KB)`);
|
||||
} else {
|
||||
console.log('✗ MEMORY.md missing');
|
||||
}
|
||||
|
||||
// Check memory directory
|
||||
if (fs.existsSync('memory')) {
|
||||
const files = fs.readdirSync('memory').filter(f => f.endsWith('.md'));
|
||||
console.log(`✓ memory/ (${files.length} daily logs)`);
|
||||
} else {
|
||||
console.log('✗ memory/ directory missing');
|
||||
}
|
||||
|
||||
// Check LanceDB
|
||||
const lancedbPath = path.join(process.env.HOME, '.clawdbot/memory/lancedb');
|
||||
if (fs.existsSync(lancedbPath)) {
|
||||
console.log('✓ LanceDB vectors initialized');
|
||||
} else {
|
||||
console.log('• LanceDB not initialized (optional)');
|
||||
}
|
||||
},
|
||||
|
||||
help: () => {
|
||||
console.log(`
|
||||
🧠 Elite Longterm Memory CLI
|
||||
|
||||
Commands:
|
||||
init Initialize memory system in current directory
|
||||
today Create today's daily log file
|
||||
status Check memory system health
|
||||
help Show this help
|
||||
|
||||
Usage:
|
||||
npx elite-longterm-memory init
|
||||
npx elite-longterm-memory status
|
||||
`);
|
||||
}
|
||||
};
|
||||
|
||||
const command = process.argv[2] || 'help';
|
||||
|
||||
if (commands[command]) {
|
||||
commands[command]();
|
||||
} else {
|
||||
console.log(`Unknown command: ${command}`);
|
||||
commands.help();
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"name": "elite-longterm-memory",
|
||||
"version": "1.2.0",
|
||||
"description": "Ultimate AI agent memory system. Combines bulletproof WAL protocol, vector search, git-based knowledge graphs, cloud backup, and maintenance hygiene. Never lose context again.",
|
||||
"keywords": [
|
||||
"memory",
|
||||
"ai-agent",
|
||||
"long-term-memory",
|
||||
"vector-search",
|
||||
"lancedb",
|
||||
"git-notes",
|
||||
"wal",
|
||||
"persistent-context",
|
||||
"claude",
|
||||
"gpt",
|
||||
"clawdbot",
|
||||
"moltbot",
|
||||
"cursor",
|
||||
"copilot",
|
||||
"ai",
|
||||
"llm",
|
||||
"automation",
|
||||
"context-management",
|
||||
"mem0",
|
||||
"auto-extraction",
|
||||
"fact-extraction"
|
||||
],
|
||||
"optionalDependencies": {
|
||||
"mem0ai": "^1.0.0"
|
||||
},
|
||||
"author": "NextFrontierBuilds",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/NextFrontierBuilds/elite-longterm-memory"
|
||||
},
|
||||
"homepage": "https://github.com/NextFrontierBuilds/elite-longterm-memory",
|
||||
"bugs": {
|
||||
"url": "https://github.com/NextFrontierBuilds/elite-longterm-memory/issues"
|
||||
},
|
||||
"bin": {
|
||||
"elite-memory": "./bin/elite-memory.js"
|
||||
},
|
||||
"files": [
|
||||
"SKILL.md",
|
||||
"bin/",
|
||||
"templates/",
|
||||
"README.md"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"version": 1,
|
||||
"registry": "https://clawhub.ai",
|
||||
"slug": "elite-longterm-memory",
|
||||
"installedVersion": "1.2.3",
|
||||
"installedAt": 1777467793883
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
# Elite Longterm Memory 🧠
|
||||
|
||||
**The ultimate memory system for AI agents.** Never lose context again.
|
||||
|
||||
[](https://www.npmjs.com/package/elite-longterm-memory)
|
||||
[](https://www.npmjs.com/package/elite-longterm-memory)
|
||||
[](https://opensource.org/licenses/MIT)
|
||||
|
||||
---
|
||||
|
||||
## Works With
|
||||
|
||||
<p align="center">
|
||||
<img src="https://img.shields.io/badge/Claude-AI-orange?style=for-the-badge&logo=anthropic" alt="Claude AI" />
|
||||
<img src="https://img.shields.io/badge/GPT-OpenAI-412991?style=for-the-badge&logo=openai" alt="GPT" />
|
||||
<img src="https://img.shields.io/badge/Cursor-IDE-000000?style=for-the-badge" alt="Cursor" />
|
||||
<img src="https://img.shields.io/badge/LangChain-Framework-1C3C3C?style=for-the-badge" alt="LangChain" />
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<strong>Built for:</strong> Clawdbot • Moltbot • Claude Code • Any AI Agent
|
||||
</p>
|
||||
|
||||
---
|
||||
|
||||
Combines 7 proven memory approaches into one bulletproof architecture:
|
||||
|
||||
- ✅ **Bulletproof WAL Protocol** — Write-ahead logging survives compaction
|
||||
- ✅ **LanceDB Vector Search** — Semantic recall of relevant memories
|
||||
- ✅ **Git-Notes Knowledge Graph** — Structured decisions, branch-aware
|
||||
- ✅ **File-Based Archives** — Human-readable MEMORY.md + daily logs
|
||||
- ✅ **Cloud Backup** — Optional SuperMemory sync
|
||||
- ✅ **Memory Hygiene** — Keep vectors lean, prevent token waste
|
||||
- ✅ **Mem0 Auto-Extraction** — Automatic fact extraction, 80% token reduction
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
# Initialize in your workspace
|
||||
npx elite-longterm-memory init
|
||||
|
||||
# Check status
|
||||
npx elite-longterm-memory status
|
||||
|
||||
# Create today's log
|
||||
npx elite-longterm-memory today
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────┐
|
||||
│ ELITE LONGTERM MEMORY │
|
||||
├─────────────────────────────────────────────────────┤
|
||||
│ HOT RAM WARM STORE COLD STORE │
|
||||
│ SESSION-STATE.md → LanceDB → Git-Notes │
|
||||
│ (survives (semantic (permanent │
|
||||
│ compaction) search) decisions) │
|
||||
│ │ │ │ │
|
||||
│ └──────────────┼────────────────┘ │
|
||||
│ ▼ │
|
||||
│ MEMORY.md │
|
||||
│ (curated archive) │
|
||||
└─────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## The 5 Memory Layers
|
||||
|
||||
| Layer | File/System | Purpose | Persistence |
|
||||
|-------|-------------|---------|-------------|
|
||||
| 1. Hot RAM | SESSION-STATE.md | Active task context | Survives compaction |
|
||||
| 2. Warm Store | LanceDB | Semantic search | Auto-recall |
|
||||
| 3. Cold Store | Git-Notes | Structured decisions | Permanent |
|
||||
| 4. Archive | MEMORY.md + daily/ | Human-readable | Curated |
|
||||
| 5. Cloud | SuperMemory | Cross-device sync | Optional |
|
||||
|
||||
## The WAL Protocol
|
||||
|
||||
**Critical insight:** Write state BEFORE responding, not after.
|
||||
|
||||
```
|
||||
User: "Let's use Tailwind for this project"
|
||||
|
||||
Agent (internal):
|
||||
1. Write to SESSION-STATE.md → "Decision: Use Tailwind"
|
||||
2. THEN respond → "Got it — Tailwind it is..."
|
||||
```
|
||||
|
||||
If you respond first and crash before saving, context is lost. WAL ensures durability.
|
||||
|
||||
## Why Memory Fails (And How to Fix It)
|
||||
|
||||
| Problem | Cause | Fix |
|
||||
|---------|-------|-----|
|
||||
| Forgets everything | memory_search disabled | Enable + add OpenAI key |
|
||||
| Repeats mistakes | Lessons not logged | Write to memory/lessons.md |
|
||||
| Sub-agents isolated | No context inheritance | Pass context in task prompt |
|
||||
| Facts not captured | No auto-extraction | Use Mem0 (see below) |
|
||||
|
||||
## Mem0 Integration (Recommended)
|
||||
|
||||
Auto-extract facts from conversations. 80% token reduction.
|
||||
|
||||
```bash
|
||||
npm install mem0ai
|
||||
export MEM0_API_KEY="your-key"
|
||||
```
|
||||
|
||||
```javascript
|
||||
const { MemoryClient } = require('mem0ai');
|
||||
const client = new MemoryClient({ apiKey: process.env.MEM0_API_KEY });
|
||||
|
||||
// Auto-extracts facts from messages
|
||||
await client.add(messages, { user_id: "user123" });
|
||||
|
||||
// Retrieve relevant memories
|
||||
const memories = await client.search(query, { user_id: "user123" });
|
||||
```
|
||||
|
||||
## For Clawdbot/Moltbot Users
|
||||
|
||||
Add to `~/.clawdbot/clawdbot.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"memorySearch": {
|
||||
"enabled": true,
|
||||
"provider": "openai",
|
||||
"sources": ["memory"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Files Created
|
||||
|
||||
```
|
||||
workspace/
|
||||
├── SESSION-STATE.md # Hot RAM (active context)
|
||||
├── MEMORY.md # Curated long-term memory
|
||||
└── memory/
|
||||
├── 2026-01-30.md # Daily logs
|
||||
└── ...
|
||||
```
|
||||
|
||||
## Commands
|
||||
|
||||
```bash
|
||||
elite-memory init # Initialize memory system
|
||||
elite-memory status # Check health
|
||||
elite-memory today # Create today's log
|
||||
elite-memory help # Show help
|
||||
```
|
||||
|
||||
## Links
|
||||
|
||||
- [Full Documentation (SKILL.md)](./SKILL.md)
|
||||
- [ClawdHub](https://clawdhub.com/skills/elite-longterm-memory)
|
||||
- [GitHub](https://github.com/NextFrontierBuilds/elite-longterm-memory)
|
||||
|
||||
---
|
||||
|
||||
Built by [@NextXFrontier](https://x.com/NextXFrontier)
|
||||
@@ -0,0 +1,409 @@
|
||||
---
|
||||
name: elite-longterm-memory
|
||||
version: 1.2.3
|
||||
description: "Ultimate AI agent memory system for Cursor, Claude, ChatGPT & Copilot. WAL protocol + vector search + git-notes + cloud backup. Never lose context again. Vibe-coding ready."
|
||||
author: NextFrontierBuilds
|
||||
keywords: [memory, ai-agent, ai-coding, long-term-memory, vector-search, lancedb, git-notes, wal, persistent-context, claude, claude-code, gpt, chatgpt, cursor, copilot, github-copilot, openclaw, moltbot, vibe-coding, agentic, ai-tools, developer-tools, devtools, typescript, llm, automation]
|
||||
metadata:
|
||||
openclaw:
|
||||
emoji: "🧠"
|
||||
requires:
|
||||
env:
|
||||
- OPENAI_API_KEY
|
||||
plugins:
|
||||
- memory-lancedb
|
||||
---
|
||||
|
||||
# Elite Longterm Memory 🧠
|
||||
|
||||
**The ultimate memory system for AI agents.** Combines 6 proven approaches into one bulletproof architecture.
|
||||
|
||||
Never lose context. Never forget decisions. Never repeat mistakes.
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ ELITE LONGTERM MEMORY │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
|
||||
│ │ HOT RAM │ │ WARM STORE │ │ COLD STORE │ │
|
||||
│ │ │ │ │ │ │ │
|
||||
│ │ SESSION- │ │ LanceDB │ │ Git-Notes │ │
|
||||
│ │ STATE.md │ │ Vectors │ │ Knowledge │ │
|
||||
│ │ │ │ │ │ Graph │ │
|
||||
│ │ (survives │ │ (semantic │ │ (permanent │ │
|
||||
│ │ compaction)│ │ search) │ │ decisions) │ │
|
||||
│ └─────────────┘ └─────────────┘ └─────────────┘ │
|
||||
│ │ │ │ │
|
||||
│ └────────────────┼────────────────┘ │
|
||||
│ ▼ │
|
||||
│ ┌─────────────┐ │
|
||||
│ │ MEMORY.md │ ← Curated long-term │
|
||||
│ │ + daily/ │ (human-readable) │
|
||||
│ └─────────────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌─────────────┐ │
|
||||
│ │ SuperMemory │ ← Cloud backup (optional) │
|
||||
│ │ API │ │
|
||||
│ └─────────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## The 5 Memory Layers
|
||||
|
||||
### Layer 1: HOT RAM (SESSION-STATE.md)
|
||||
**From: bulletproof-memory**
|
||||
|
||||
Active working memory that survives compaction. Write-Ahead Log protocol.
|
||||
|
||||
```markdown
|
||||
# SESSION-STATE.md — Active Working Memory
|
||||
|
||||
## Current Task
|
||||
[What we're working on RIGHT NOW]
|
||||
|
||||
## Key Context
|
||||
- User preference: ...
|
||||
- Decision made: ...
|
||||
- Blocker: ...
|
||||
|
||||
## Pending Actions
|
||||
- [ ] ...
|
||||
```
|
||||
|
||||
**Rule:** Write BEFORE responding. Triggered by user input, not agent memory.
|
||||
|
||||
### Layer 2: WARM STORE (LanceDB Vectors)
|
||||
**From: lancedb-memory**
|
||||
|
||||
Semantic search across all memories. Auto-recall injects relevant context.
|
||||
|
||||
```bash
|
||||
# Auto-recall (happens automatically)
|
||||
memory_recall query="project status" limit=5
|
||||
|
||||
# Manual store
|
||||
memory_store text="User prefers dark mode" category="preference" importance=0.9
|
||||
```
|
||||
|
||||
### Layer 3: COLD STORE (Git-Notes Knowledge Graph)
|
||||
**From: git-notes-memory**
|
||||
|
||||
Structured decisions, learnings, and context. Branch-aware.
|
||||
|
||||
```bash
|
||||
# Store a decision (SILENT - never announce)
|
||||
python3 memory.py -p $DIR remember '{"type":"decision","content":"Use React for frontend"}' -t tech -i h
|
||||
|
||||
# Retrieve context
|
||||
python3 memory.py -p $DIR get "frontend"
|
||||
```
|
||||
|
||||
### Layer 4: CURATED ARCHIVE (MEMORY.md + daily/)
|
||||
**From: OpenClaw native**
|
||||
|
||||
Human-readable long-term memory. Daily logs + distilled wisdom.
|
||||
|
||||
```
|
||||
workspace/
|
||||
├── MEMORY.md # Curated long-term (the good stuff)
|
||||
└── memory/
|
||||
├── 2026-01-30.md # Daily log
|
||||
├── 2026-01-29.md
|
||||
└── topics/ # Topic-specific files
|
||||
```
|
||||
|
||||
### Layer 5: CLOUD BACKUP (SuperMemory) — Optional
|
||||
**From: supermemory**
|
||||
|
||||
Cross-device sync. Chat with your knowledge base.
|
||||
|
||||
```bash
|
||||
export SUPERMEMORY_API_KEY="your-key"
|
||||
supermemory add "Important context"
|
||||
supermemory search "what did we decide about..."
|
||||
```
|
||||
|
||||
### Layer 6: AUTO-EXTRACTION (Mem0) — Recommended
|
||||
**NEW: Automatic fact extraction**
|
||||
|
||||
Mem0 automatically extracts facts from conversations. 80% token reduction.
|
||||
|
||||
```bash
|
||||
npm install mem0ai
|
||||
export MEM0_API_KEY="your-key"
|
||||
```
|
||||
|
||||
```javascript
|
||||
const { MemoryClient } = require('mem0ai');
|
||||
const client = new MemoryClient({ apiKey: process.env.MEM0_API_KEY });
|
||||
|
||||
// Conversations auto-extract facts
|
||||
await client.add(messages, { user_id: "user123" });
|
||||
|
||||
// Retrieve relevant memories
|
||||
const memories = await client.search(query, { user_id: "user123" });
|
||||
```
|
||||
|
||||
Benefits:
|
||||
- Auto-extracts preferences, decisions, facts
|
||||
- Deduplicates and updates existing memories
|
||||
- 80% reduction in tokens vs raw history
|
||||
- Works across sessions automatically
|
||||
|
||||
## Quick Setup
|
||||
|
||||
### 1. Create SESSION-STATE.md (Hot RAM)
|
||||
|
||||
```bash
|
||||
cat > SESSION-STATE.md << 'EOF'
|
||||
# SESSION-STATE.md — Active Working Memory
|
||||
|
||||
This file is the agent's "RAM" — survives compaction, restarts, distractions.
|
||||
|
||||
## Current Task
|
||||
[None]
|
||||
|
||||
## Key Context
|
||||
[None yet]
|
||||
|
||||
## Pending Actions
|
||||
- [ ] None
|
||||
|
||||
## Recent Decisions
|
||||
[None yet]
|
||||
|
||||
---
|
||||
*Last updated: [timestamp]*
|
||||
EOF
|
||||
```
|
||||
|
||||
### 2. Enable LanceDB (Warm Store)
|
||||
|
||||
In `~/.openclaw/openclaw.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"memorySearch": {
|
||||
"enabled": true,
|
||||
"provider": "openai",
|
||||
"sources": ["memory"],
|
||||
"minScore": 0.3,
|
||||
"maxResults": 10
|
||||
},
|
||||
"plugins": {
|
||||
"entries": {
|
||||
"memory-lancedb": {
|
||||
"enabled": true,
|
||||
"config": {
|
||||
"autoCapture": false,
|
||||
"autoRecall": true,
|
||||
"captureCategories": ["preference", "decision", "fact"],
|
||||
"minImportance": 0.7
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Initialize Git-Notes (Cold Store)
|
||||
|
||||
```bash
|
||||
cd ~/clawd
|
||||
git init # if not already
|
||||
python3 skills/git-notes-memory/memory.py -p . sync --start
|
||||
```
|
||||
|
||||
### 4. Verify MEMORY.md Structure
|
||||
|
||||
```bash
|
||||
# Ensure you have:
|
||||
# - MEMORY.md in workspace root
|
||||
# - memory/ folder for daily logs
|
||||
mkdir -p memory
|
||||
```
|
||||
|
||||
### 5. (Optional) Setup SuperMemory
|
||||
|
||||
```bash
|
||||
export SUPERMEMORY_API_KEY="your-key"
|
||||
# Add to ~/.zshrc for persistence
|
||||
```
|
||||
|
||||
## Agent Instructions
|
||||
|
||||
### On Session Start
|
||||
1. Read SESSION-STATE.md — this is your hot context
|
||||
2. Run `memory_search` for relevant prior context
|
||||
3. Check memory/YYYY-MM-DD.md for recent activity
|
||||
|
||||
### During Conversation
|
||||
1. **User gives concrete detail?** → Write to SESSION-STATE.md BEFORE responding
|
||||
2. **Important decision made?** → Store in Git-Notes (SILENTLY)
|
||||
3. **Preference expressed?** → `memory_store` with importance=0.9
|
||||
|
||||
### On Session End
|
||||
1. Update SESSION-STATE.md with final state
|
||||
2. Move significant items to MEMORY.md if worth keeping long-term
|
||||
3. Create/update daily log in memory/YYYY-MM-DD.md
|
||||
|
||||
### Memory Hygiene (Weekly)
|
||||
1. Review SESSION-STATE.md — archive completed tasks
|
||||
2. Check LanceDB for junk: `memory_recall query="*" limit=50`
|
||||
3. Clear irrelevant vectors: `memory_forget id=<id>`
|
||||
4. Consolidate daily logs into MEMORY.md
|
||||
|
||||
## The WAL Protocol (Critical)
|
||||
|
||||
**Write-Ahead Log:** Write state BEFORE responding, not after.
|
||||
|
||||
| Trigger | Action |
|
||||
|---------|--------|
|
||||
| User states preference | Write to SESSION-STATE.md → then respond |
|
||||
| User makes decision | Write to SESSION-STATE.md → then respond |
|
||||
| User gives deadline | Write to SESSION-STATE.md → then respond |
|
||||
| User corrects you | Write to SESSION-STATE.md → then respond |
|
||||
|
||||
**Why?** If you respond first and crash/compact before saving, context is lost. WAL ensures durability.
|
||||
|
||||
## Example Workflow
|
||||
|
||||
```
|
||||
User: "Let's use Tailwind for this project, not vanilla CSS"
|
||||
|
||||
Agent (internal):
|
||||
1. Write to SESSION-STATE.md: "Decision: Use Tailwind, not vanilla CSS"
|
||||
2. Store in Git-Notes: decision about CSS framework
|
||||
3. memory_store: "User prefers Tailwind over vanilla CSS" importance=0.9
|
||||
4. THEN respond: "Got it — Tailwind it is..."
|
||||
```
|
||||
|
||||
## Maintenance Commands
|
||||
|
||||
```bash
|
||||
# Audit vector memory
|
||||
memory_recall query="*" limit=50
|
||||
|
||||
# Clear all vectors (nuclear option)
|
||||
rm -rf ~/.openclaw/memory/lancedb/
|
||||
openclaw gateway restart
|
||||
|
||||
# Export Git-Notes
|
||||
python3 memory.py -p . export --format json > memories.json
|
||||
|
||||
# Check memory health
|
||||
du -sh ~/.openclaw/memory/
|
||||
wc -l MEMORY.md
|
||||
ls -la memory/
|
||||
```
|
||||
|
||||
## Why Memory Fails
|
||||
|
||||
Understanding the root causes helps you fix them:
|
||||
|
||||
| Failure Mode | Cause | Fix |
|
||||
|--------------|-------|-----|
|
||||
| Forgets everything | `memory_search` disabled | Enable + add OpenAI key |
|
||||
| Files not loaded | Agent skips reading memory | Add to AGENTS.md rules |
|
||||
| Facts not captured | No auto-extraction | Use Mem0 or manual logging |
|
||||
| Sub-agents isolated | Don't inherit context | Pass context in task prompt |
|
||||
| Repeats mistakes | Lessons not logged | Write to memory/lessons.md |
|
||||
|
||||
## Solutions (Ranked by Effort)
|
||||
|
||||
### 1. Quick Win: Enable memory_search
|
||||
|
||||
If you have an OpenAI key, enable semantic search:
|
||||
|
||||
```bash
|
||||
openclaw configure --section web
|
||||
```
|
||||
|
||||
This enables vector search over MEMORY.md + memory/*.md files.
|
||||
|
||||
### 2. Recommended: Mem0 Integration
|
||||
|
||||
Auto-extract facts from conversations. 80% token reduction.
|
||||
|
||||
```bash
|
||||
npm install mem0ai
|
||||
```
|
||||
|
||||
```javascript
|
||||
const { MemoryClient } = require('mem0ai');
|
||||
|
||||
const client = new MemoryClient({ apiKey: process.env.MEM0_API_KEY });
|
||||
|
||||
// Auto-extract and store
|
||||
await client.add([
|
||||
{ role: "user", content: "I prefer Tailwind over vanilla CSS" }
|
||||
], { user_id: "ty" });
|
||||
|
||||
// Retrieve relevant memories
|
||||
const memories = await client.search("CSS preferences", { user_id: "ty" });
|
||||
```
|
||||
|
||||
### 3. Better File Structure (No Dependencies)
|
||||
|
||||
```
|
||||
memory/
|
||||
├── projects/
|
||||
│ ├── strykr.md
|
||||
│ └── taska.md
|
||||
├── people/
|
||||
│ └── contacts.md
|
||||
├── decisions/
|
||||
│ └── 2026-01.md
|
||||
├── lessons/
|
||||
│ └── mistakes.md
|
||||
└── preferences.md
|
||||
```
|
||||
|
||||
Keep MEMORY.md as a summary (<5KB), link to detailed files.
|
||||
|
||||
## Immediate Fixes Checklist
|
||||
|
||||
| Problem | Fix |
|
||||
|---------|-----|
|
||||
| Forgets preferences | Add `## Preferences` section to MEMORY.md |
|
||||
| Repeats mistakes | Log every mistake to `memory/lessons.md` |
|
||||
| Sub-agents lack context | Include key context in spawn task prompt |
|
||||
| Forgets recent work | Strict daily file discipline |
|
||||
| Memory search not working | Check `OPENAI_API_KEY` is set |
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**Agent keeps forgetting mid-conversation:**
|
||||
→ SESSION-STATE.md not being updated. Check WAL protocol.
|
||||
|
||||
**Irrelevant memories injected:**
|
||||
→ Disable autoCapture, increase minImportance threshold.
|
||||
|
||||
**Memory too large, slow recall:**
|
||||
→ Run hygiene: clear old vectors, archive daily logs.
|
||||
|
||||
**Git-Notes not persisting:**
|
||||
→ Run `git notes push` to sync with remote.
|
||||
|
||||
**memory_search returns nothing:**
|
||||
→ Check OpenAI API key: `echo $OPENAI_API_KEY`
|
||||
→ Verify memorySearch enabled in openclaw.json
|
||||
|
||||
---
|
||||
|
||||
## Links
|
||||
|
||||
- bulletproof-memory: https://clawdhub.com/skills/bulletproof-memory
|
||||
- lancedb-memory: https://clawdhub.com/skills/lancedb-memory
|
||||
- git-notes-memory: https://clawdhub.com/skills/git-notes-memory
|
||||
- memory-hygiene: https://clawdhub.com/skills/memory-hygiene
|
||||
- supermemory: https://clawdhub.com/skills/supermemory
|
||||
|
||||
---
|
||||
|
||||
*Built by [@NextXFrontier](https://x.com/NextXFrontier) — Part of the Next Frontier AI toolkit*
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"ownerId": "kn7ewywaj7mf48drbjw1baa5298016yv",
|
||||
"slug": "elite-longterm-memory",
|
||||
"version": "1.2.3",
|
||||
"publishedAt": 1770799020241
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const TEMPLATES = {
|
||||
'session-state': `# SESSION-STATE.md — Active Working Memory
|
||||
|
||||
This file is the agent's "RAM" — survives compaction, restarts, distractions.
|
||||
Chat history is a BUFFER. This file is STORAGE.
|
||||
|
||||
## Current Task
|
||||
[None]
|
||||
|
||||
## Key Context
|
||||
[None yet]
|
||||
|
||||
## Pending Actions
|
||||
- [ ] None
|
||||
|
||||
## Recent Decisions
|
||||
[None yet]
|
||||
|
||||
---
|
||||
*Last updated: ${new Date().toISOString()}*
|
||||
`,
|
||||
|
||||
'memory-md': `# MEMORY.md — Long-Term Memory
|
||||
|
||||
## About the User
|
||||
[Add user preferences, communication style, etc.]
|
||||
|
||||
## Projects
|
||||
[Active projects and their status]
|
||||
|
||||
## Decisions Log
|
||||
[Important decisions and why they were made]
|
||||
|
||||
## Lessons Learned
|
||||
[Mistakes to avoid, patterns that work]
|
||||
|
||||
## Preferences
|
||||
[Tools, frameworks, workflows the user prefers]
|
||||
|
||||
---
|
||||
*Curated memory — distill insights from daily logs here*
|
||||
`,
|
||||
|
||||
'daily-template': `# {{DATE}} — Daily Log
|
||||
|
||||
## Tasks Completed
|
||||
-
|
||||
|
||||
## Decisions Made
|
||||
-
|
||||
|
||||
## Lessons Learned
|
||||
-
|
||||
|
||||
## Tomorrow
|
||||
-
|
||||
`
|
||||
};
|
||||
|
||||
const commands = {
|
||||
init: () => {
|
||||
console.log('🧠 Initializing Elite Longterm Memory...\n');
|
||||
|
||||
// Create SESSION-STATE.md
|
||||
if (!fs.existsSync('SESSION-STATE.md')) {
|
||||
fs.writeFileSync('SESSION-STATE.md', TEMPLATES['session-state']);
|
||||
console.log('✓ Created SESSION-STATE.md (Hot RAM)');
|
||||
} else {
|
||||
console.log('• SESSION-STATE.md already exists');
|
||||
}
|
||||
|
||||
// Create MEMORY.md
|
||||
if (!fs.existsSync('MEMORY.md')) {
|
||||
fs.writeFileSync('MEMORY.md', TEMPLATES['memory-md']);
|
||||
console.log('✓ Created MEMORY.md (Curated Archive)');
|
||||
} else {
|
||||
console.log('• MEMORY.md already exists');
|
||||
}
|
||||
|
||||
// Create memory directory
|
||||
if (!fs.existsSync('memory')) {
|
||||
fs.mkdirSync('memory', { recursive: true });
|
||||
console.log('✓ Created memory/ directory');
|
||||
} else {
|
||||
console.log('• memory/ directory already exists');
|
||||
}
|
||||
|
||||
// Create today's log
|
||||
const today = new Date().toISOString().split('T')[0];
|
||||
const todayFile = `memory/${today}.md`;
|
||||
if (!fs.existsSync(todayFile)) {
|
||||
const content = TEMPLATES['daily-template'].replace('{{DATE}}', today);
|
||||
fs.writeFileSync(todayFile, content);
|
||||
console.log(`✓ Created ${todayFile}`);
|
||||
}
|
||||
|
||||
console.log('\n🎉 Elite Longterm Memory initialized!');
|
||||
console.log('\nNext steps:');
|
||||
console.log('1. Add SESSION-STATE.md to your agent context');
|
||||
console.log('2. Configure LanceDB plugin in clawdbot.json');
|
||||
console.log('3. Review SKILL.md for full setup guide');
|
||||
},
|
||||
|
||||
today: () => {
|
||||
const today = new Date().toISOString().split('T')[0];
|
||||
const todayFile = `memory/${today}.md`;
|
||||
|
||||
if (!fs.existsSync('memory')) {
|
||||
fs.mkdirSync('memory', { recursive: true });
|
||||
}
|
||||
|
||||
if (!fs.existsSync(todayFile)) {
|
||||
const content = TEMPLATES['daily-template'].replace('{{DATE}}', today);
|
||||
fs.writeFileSync(todayFile, content);
|
||||
console.log(`✓ Created ${todayFile}`);
|
||||
} else {
|
||||
console.log(`• ${todayFile} already exists`);
|
||||
}
|
||||
},
|
||||
|
||||
status: () => {
|
||||
console.log('🧠 Elite Longterm Memory Status\n');
|
||||
|
||||
// Check SESSION-STATE.md
|
||||
if (fs.existsSync('SESSION-STATE.md')) {
|
||||
const stat = fs.statSync('SESSION-STATE.md');
|
||||
console.log(`✓ SESSION-STATE.md (${(stat.size / 1024).toFixed(1)}KB, modified ${stat.mtime.toLocaleString()})`);
|
||||
} else {
|
||||
console.log('✗ SESSION-STATE.md missing');
|
||||
}
|
||||
|
||||
// Check MEMORY.md
|
||||
if (fs.existsSync('MEMORY.md')) {
|
||||
const stat = fs.statSync('MEMORY.md');
|
||||
const lines = fs.readFileSync('MEMORY.md', 'utf8').split('\n').length;
|
||||
console.log(`✓ MEMORY.md (${lines} lines, ${(stat.size / 1024).toFixed(1)}KB)`);
|
||||
} else {
|
||||
console.log('✗ MEMORY.md missing');
|
||||
}
|
||||
|
||||
// Check memory directory
|
||||
if (fs.existsSync('memory')) {
|
||||
const files = fs.readdirSync('memory').filter(f => f.endsWith('.md'));
|
||||
console.log(`✓ memory/ (${files.length} daily logs)`);
|
||||
} else {
|
||||
console.log('✗ memory/ directory missing');
|
||||
}
|
||||
|
||||
// Check LanceDB
|
||||
const lancedbPath = path.join(process.env.HOME, '.clawdbot/memory/lancedb');
|
||||
if (fs.existsSync(lancedbPath)) {
|
||||
console.log('✓ LanceDB vectors initialized');
|
||||
} else {
|
||||
console.log('• LanceDB not initialized (optional)');
|
||||
}
|
||||
},
|
||||
|
||||
help: () => {
|
||||
console.log(`
|
||||
🧠 Elite Longterm Memory CLI
|
||||
|
||||
Commands:
|
||||
init Initialize memory system in current directory
|
||||
today Create today's daily log file
|
||||
status Check memory system health
|
||||
help Show this help
|
||||
|
||||
Usage:
|
||||
npx elite-longterm-memory init
|
||||
npx elite-longterm-memory status
|
||||
`);
|
||||
}
|
||||
};
|
||||
|
||||
const command = process.argv[2] || 'help';
|
||||
|
||||
if (commands[command]) {
|
||||
commands[command]();
|
||||
} else {
|
||||
console.log(`Unknown command: ${command}`);
|
||||
commands.help();
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
{
|
||||
"name": "elite-longterm-memory",
|
||||
"version": "1.2.3",
|
||||
"description": "Ultimate AI agent memory system for Cursor, Claude, ChatGPT & Copilot. WAL protocol, vector search, git-based knowledge graphs, cloud backup. Never lose context again.",
|
||||
"keywords": [
|
||||
"memory",
|
||||
"ai-agent",
|
||||
"long-term-memory",
|
||||
"vector-search",
|
||||
"lancedb",
|
||||
"git-notes",
|
||||
"wal",
|
||||
"persistent-context",
|
||||
"claude",
|
||||
"gpt",
|
||||
"chatgpt",
|
||||
"openclaw",
|
||||
"moltbot",
|
||||
"cursor",
|
||||
"copilot",
|
||||
"github-copilot",
|
||||
"ai",
|
||||
"llm",
|
||||
"automation",
|
||||
"context-management",
|
||||
"mem0",
|
||||
"auto-extraction",
|
||||
"fact-extraction",
|
||||
"vibe-coding",
|
||||
"ai-tools",
|
||||
"developer-tools",
|
||||
"devtools",
|
||||
"typescript"
|
||||
],
|
||||
"optionalDependencies": {
|
||||
"mem0ai": "^1.0.0"
|
||||
},
|
||||
"author": "NextFrontierBuilds",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/NextFrontierBuilds/elite-longterm-memory"
|
||||
},
|
||||
"homepage": "https://github.com/NextFrontierBuilds/elite-longterm-memory",
|
||||
"bugs": {
|
||||
"url": "https://github.com/NextFrontierBuilds/elite-longterm-memory/issues"
|
||||
},
|
||||
"bin": {
|
||||
"elite-memory": "./bin/elite-memory.js"
|
||||
},
|
||||
"files": [
|
||||
"SKILL.md",
|
||||
"bin/",
|
||||
"templates/",
|
||||
"README.md"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"version": 1,
|
||||
"registry": "https://clawhub.ai",
|
||||
"slug": "healthcheck",
|
||||
"installedVersion": "1.0.2",
|
||||
"installedAt": 1774073423128
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
---
|
||||
name: healthcheck
|
||||
description: Track water and sleep with JSON file storage
|
||||
version: 1.0.2
|
||||
tags: health, tracking
|
||||
---
|
||||
|
||||
# Health Tracker
|
||||
|
||||
Simple tracking for water intake and sleep using JSON file.
|
||||
|
||||
## Data Format
|
||||
|
||||
File: `{baseDir}/health-data.json`
|
||||
|
||||
```json
|
||||
{
|
||||
"water": [{"time": "ISO8601", "cups": 2}],
|
||||
"sleep": [{"time": "ISO8601", "action": "sleep|wake"}]
|
||||
}
|
||||
```
|
||||
|
||||
## Add Water Record
|
||||
|
||||
When user says "uống X cốc" or "uống nước X cốc":
|
||||
|
||||
```bash
|
||||
node -e "const fs=require('fs');const f='{baseDir}/health-data.json';let d={water:[],sleep:[]};try{d=JSON.parse(fs.readFileSync(f))}catch(e){}d.water.push({time:new Date().toISOString(),cups:CUPS});fs.writeFileSync(f,JSON.stringify(d));console.log('Da ghi: '+CUPS+' coc')"
|
||||
```
|
||||
|
||||
Replace `CUPS` with number from user input.
|
||||
|
||||
## Add Sleep Record
|
||||
|
||||
When user says "đi ngủ":
|
||||
|
||||
```bash
|
||||
node -e "const fs=require('fs');const f='{baseDir}/health-data.json';let d={water:[],sleep:[]};try{d=JSON.parse(fs.readFileSync(f))}catch(e){}d.sleep.push({time:new Date().toISOString(),action:'sleep'});fs.writeFileSync(f,JSON.stringify(d));console.log('Da ghi: di ngu')"
|
||||
```
|
||||
|
||||
## Add Wake Record
|
||||
|
||||
When user says "thức dậy" or "dậy rồi":
|
||||
|
||||
```bash
|
||||
node -e "const fs=require('fs');const f='{baseDir}/health-data.json';let d={water:[],sleep:[]};try{d=JSON.parse(fs.readFileSync(f))}catch(e){}const last=d.sleep.filter(s=>s.action==='sleep').pop();d.sleep.push({time:new Date().toISOString(),action:'wake'});fs.writeFileSync(f,JSON.stringify(d));if(last){const h=((new Date()-new Date(last.time))/3600000).toFixed(1);console.log('Da ngu: '+h+' gio')}else{console.log('Da ghi: thuc day')}"
|
||||
```
|
||||
|
||||
## View Stats
|
||||
|
||||
When user says "thống kê" or "xem thống kê":
|
||||
|
||||
```bash
|
||||
node -e "const fs=require('fs');const f='{baseDir}/health-data.json';let d={water:[],sleep:[]};try{d=JSON.parse(fs.readFileSync(f))}catch(e){}console.log('Water:',d.water.length,'records');console.log('Sleep:',d.sleep.length,'records');const today=d.water.filter(w=>new Date(w.time).toDateString()===new Date().toDateString());console.log('Today:',today.reduce((s,w)=>s+w.cups,0),'cups')"
|
||||
```
|
||||
|
||||
## Update Record
|
||||
|
||||
To update last water entry:
|
||||
|
||||
```bash
|
||||
node -e "const fs=require('fs');const f='{baseDir}/health-data.json';let d=JSON.parse(fs.readFileSync(f));d.water[d.water.length-1].cups=NEW_CUPS;fs.writeFileSync(f,JSON.stringify(d));console.log('Updated')"
|
||||
```
|
||||
|
||||
## Delete Record
|
||||
|
||||
To delete last water entry:
|
||||
|
||||
```bash
|
||||
node -e "const fs=require('fs');const f='{baseDir}/health-data.json';let d=JSON.parse(fs.readFileSync(f));d.water.pop();fs.writeFileSync(f,JSON.stringify(d));console.log('Deleted')"
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Uses Node.js built-in modules only
|
||||
- File auto-created if missing
|
||||
- All timestamps in ISO8601 format
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"ownerId": "kn7129pr4xtrwpbxszgx6bmfjx80a9pz",
|
||||
"slug": "healthcheck",
|
||||
"version": "1.0.2",
|
||||
"publishedAt": 1769965007932
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"version": 1,
|
||||
"registry": "https://clawhub.ai",
|
||||
"slug": "longbridge-kit",
|
||||
"installedVersion": "1.0.2",
|
||||
"installedAt": 1774800584243
|
||||
}
|
||||
@@ -0,0 +1,530 @@
|
||||
# longbridge
|
||||
|
||||
English | [中文](#中文)
|
||||
|
||||
---
|
||||
|
||||
## English
|
||||
|
||||
A command-line tool built on the [LongPort OpenAPI](https://open.longportapp.com/) Python SDK. Supports real-time quotes, account positions, order management, and market data. Ships with a `SKILL.md` for direct integration as a Claude Code Skill.
|
||||
|
||||
---
|
||||
|
||||
### Features
|
||||
|
||||
- **Quotes**: Real-time prices, order book, trade ticks, candlesticks, static info
|
||||
- **Account**: Balance & net assets, stock positions, fund positions
|
||||
- **Orders**: Today's / historical orders (read-only); limit buy/sell, cancel (requires trade permission)
|
||||
- **Market**: Market temperature, capital flow, capital distribution, option chain
|
||||
|
||||
---
|
||||
|
||||
### Authentication
|
||||
|
||||
Apply for an API Key at [open.longportapp.com](https://open.longportapp.com/), then configure credentials using either method below.
|
||||
|
||||
#### Method 1: .env file (recommended)
|
||||
|
||||
Create a `.env` file in the current directory or home directory (`~/.env`):
|
||||
|
||||
```bash
|
||||
LONGBRIDGE_APP_KEY=your_app_key
|
||||
LONGBRIDGE_APP_SECRET=your_app_secret
|
||||
LONGBRIDGE_ACCESS_TOKEN=your_access_token
|
||||
|
||||
# Optional: enable trading (default is read-only)
|
||||
LONGBRIDGE_TRADE_ENABLED=true
|
||||
```
|
||||
|
||||
Search order: **current directory** → **home directory**. Values in `.env` do **not** override existing system environment variables (system env takes precedence).
|
||||
|
||||
#### Method 3: Multiple accounts with `--profile`
|
||||
|
||||
Use named profile files to switch between accounts (e.g., paper trading vs live):
|
||||
|
||||
```bash
|
||||
# Create .paper.env and .live.env in the current or home directory
|
||||
# Each file contains the credentials for that account
|
||||
|
||||
longbridge --profile paper balance
|
||||
longbridge --profile live positions
|
||||
```
|
||||
|
||||
The `--profile paper` flag loads `.paper.env` instead of `.env`. If the file is not found, an error is raised.
|
||||
|
||||
#### Method 2: Shell environment variables
|
||||
|
||||
```bash
|
||||
export LONGBRIDGE_APP_KEY="your_app_key"
|
||||
export LONGBRIDGE_APP_SECRET="your_app_secret"
|
||||
export LONGBRIDGE_ACCESS_TOKEN="your_access_token"
|
||||
```
|
||||
|
||||
Add to `~/.zshrc` or `~/.bashrc` for persistence.
|
||||
|
||||
| Variable | Required | Description |
|
||||
|----------|----------|-------------|
|
||||
| `LONGBRIDGE_APP_KEY` | ✅ | App Key |
|
||||
| `LONGBRIDGE_APP_SECRET` | ✅ | App Secret |
|
||||
| `LONGBRIDGE_ACCESS_TOKEN` | ✅ | Access Token |
|
||||
| `LONGBRIDGE_TRADE_ENABLED` | Optional | Set to `true` to enable trading (default: read-only) |
|
||||
|
||||
---
|
||||
|
||||
### Read-only Mode & Trade Permission
|
||||
|
||||
**Default is read-only**: `buy`, `sell`, `cancel` are disabled unless `LONGBRIDGE_TRADE_ENABLED=true` is set:
|
||||
|
||||
```
|
||||
Error: 当前为只读模式,下单/撤单操作已禁用。
|
||||
如需开启交易权限,请设置环境变量:
|
||||
export LONGBRIDGE_TRADE_ENABLED=true
|
||||
⚠️ 开启后请确保操作正确,下单指令将直接提交至长桥交易系统。
|
||||
```
|
||||
|
||||
Read commands (`orders`, `history-orders`, `positions`, etc.) are always available without extra configuration.
|
||||
|
||||
---
|
||||
|
||||
### Usage
|
||||
|
||||
All commands support `--json` for machine-readable output.
|
||||
|
||||
#### Quotes
|
||||
|
||||
```bash
|
||||
# Real-time quotes (multiple symbols)
|
||||
longbridge quote AAPL.US 700.HK
|
||||
longbridge quote AAPL.US --json
|
||||
|
||||
# Order book (top 5 bid/ask)
|
||||
longbridge depth 700.HK
|
||||
|
||||
# Trade ticks
|
||||
longbridge trades 700.HK --count 20
|
||||
|
||||
# Candlesticks
|
||||
# period: 1m 5m 15m 30m 60m day week month quarter year
|
||||
longbridge candlesticks AAPL.US day --count 30
|
||||
longbridge candlesticks 700.HK 60m --count 100 --json
|
||||
|
||||
# Static security info
|
||||
longbridge info AAPL.US 700.HK
|
||||
```
|
||||
|
||||
#### Account & Positions
|
||||
|
||||
```bash
|
||||
longbridge balance
|
||||
longbridge balance --json
|
||||
|
||||
longbridge positions
|
||||
|
||||
longbridge funds
|
||||
```
|
||||
|
||||
#### Order Management
|
||||
|
||||
```bash
|
||||
# Read-only — no trade permission required
|
||||
longbridge orders
|
||||
longbridge history-orders --start 2026-01-01 --end 2026-03-14
|
||||
|
||||
# Requires LONGBRIDGE_TRADE_ENABLED=true
|
||||
|
||||
# Limit buy (confirmation prompt before execution)
|
||||
longbridge buy AAPL.US --qty 100 --price 180.0
|
||||
|
||||
# Limit sell (confirmation prompt)
|
||||
longbridge sell 700.HK --qty 500 --price 320.0
|
||||
|
||||
# Cancel order (confirmation prompt)
|
||||
longbridge cancel 701234567890
|
||||
|
||||
# Skip confirmation for programmatic / scripted use
|
||||
longbridge buy AAPL.US --qty 100 --price 180.0 --yes
|
||||
longbridge sell 700.HK --qty 500 --price 320.0 -y
|
||||
```
|
||||
|
||||
#### Market Data
|
||||
|
||||
```bash
|
||||
# Market temperature (US / HK / CN / SG)
|
||||
longbridge temperature US
|
||||
|
||||
# Capital flow
|
||||
longbridge capital-flow 700.HK
|
||||
|
||||
# Capital distribution (large / medium / small orders)
|
||||
longbridge capital-dist 700.HK
|
||||
|
||||
# Option chain expiry dates
|
||||
longbridge option-chain AAPL.US
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### AI Agent Integration
|
||||
|
||||
#### OpenClaw Skill
|
||||
|
||||
Copy `SKILL.md` to your OpenClaw skills directory to register it as a Clawdbot Skill:
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.openclaw/skills/longbridge-cli
|
||||
cp SKILL.md ~/.openclaw/skills/longbridge-cli/SKILL.md
|
||||
```
|
||||
|
||||
Once installed, Claude can invoke longbridge-cli commands automatically when you ask about account balances, positions, quotes, or orders.
|
||||
|
||||
#### Usage as a Skill
|
||||
|
||||
This project includes `SKILL.md` and can be registered as a Clawdbot Skill for AI-driven workflows. All commands support `--json` for structured output:
|
||||
|
||||
```bash
|
||||
longbridge positions --json
|
||||
longbridge quote AAPL.US 700.HK --json
|
||||
longbridge orders --json
|
||||
```
|
||||
|
||||
Example JSON output (`longbridge quote AAPL.US --json`):
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"symbol": "AAPL.US",
|
||||
"last_done": 213.49,
|
||||
"open": 211.50,
|
||||
"high": 214.20,
|
||||
"low": 210.30,
|
||||
"volume": 52345678,
|
||||
"turnover": 11162345678.0,
|
||||
"change_rate": 0.94,
|
||||
"prev_close": 211.51
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Symbol Format
|
||||
|
||||
| Market | Format | Examples |
|
||||
|--------|--------|---------|
|
||||
| US | `TICKER.US` | `AAPL.US`, `NVDA.US` |
|
||||
| HK | `4-digit code.HK` | `0700.HK`, `9988.HK` |
|
||||
|
||||
---
|
||||
|
||||
### Project Structure
|
||||
|
||||
```
|
||||
longbridge-cli/
|
||||
├── longbridge_cli/
|
||||
│ ├── __init__.py
|
||||
│ ├── __main__.py # python -m entry point
|
||||
│ ├── cli.py # Click root command group
|
||||
│ ├── config.py # Config initialization
|
||||
│ ├── formatters.py # Unified text/json output
|
||||
│ └── commands/
|
||||
│ ├── quote.py # Quote commands
|
||||
│ ├── account.py # Account & positions
|
||||
│ ├── order.py # Order management
|
||||
│ └── market.py # Market data
|
||||
├── SKILL.md # Claude Code Skill document
|
||||
├── _meta.json # Skill registration
|
||||
├── LICENSE
|
||||
├── requirements.txt
|
||||
└── pyproject.toml
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Dependencies
|
||||
|
||||
```
|
||||
longbridge # LongPort official Python SDK
|
||||
click>=8.0 # CLI framework
|
||||
rich>=13.0 # Terminal output formatting
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Notes
|
||||
|
||||
- **Read-only mode**: `buy`/`sell`/`cancel` require `LONGBRIDGE_TRADE_ENABLED=true`
|
||||
- **Trade confirmation**: Even with trade permission enabled, all write commands prompt for confirmation before executing. Use `--yes` / `-y` to skip the prompt for scripted or programmatic use
|
||||
- **Multi-account profiles**: Use `longbridge --profile <name>` to load `.<name>.env` credentials (e.g., `--profile paper` loads `.paper.env`). Useful for switching between paper trading and live accounts
|
||||
- **HK symbol format**: Must use 4-digit format, e.g. `0700.HK` (leading zero required)
|
||||
- **Error handling**: SDK exceptions are caught and displayed as friendly messages
|
||||
- **Decimal serialization**: Decimal values are automatically converted to float in JSON output
|
||||
- **.env precedence**: System environment variables take precedence over `.env` file values (system env is not overwritten)
|
||||
|
||||
---
|
||||
|
||||
### License
|
||||
|
||||
MIT
|
||||
|
||||
---
|
||||
|
||||
## 中文
|
||||
|
||||
基于[长桥 LongPort OpenAPI](https://open.longportapp.com/) Python SDK 的命令行工具,支持行情查询、账户持仓、订单管理、市场数据。封装为 Claude Code Skill,可直接被 AI Agent 调用。
|
||||
|
||||
---
|
||||
|
||||
### 功能概览
|
||||
|
||||
- **行情**:实时报价、盘口、逐笔成交、K 线、标的信息
|
||||
- **账户**:余额净资产、股票持仓、基金持仓
|
||||
- **订单**:今日/历史订单查询(只读);限价买入/卖出、撤单(需开启交易权限)
|
||||
- **市场**:市场温度、资金流向、资金分布、期权链
|
||||
|
||||
---
|
||||
|
||||
### 认证配置
|
||||
|
||||
在长桥开放平台 [open.longportapp.com](https://open.longportapp.com/) 申请 API Key 后,通过以下任一方式配置凭证。
|
||||
|
||||
#### 方式 1:.env 文件(推荐)
|
||||
|
||||
在当前目录或用户主目录创建 `.env` 文件:
|
||||
|
||||
```bash
|
||||
LONGBRIDGE_APP_KEY=your_app_key
|
||||
LONGBRIDGE_APP_SECRET=your_app_secret
|
||||
LONGBRIDGE_ACCESS_TOKEN=your_access_token
|
||||
|
||||
# 可选:开启交易权限,默认为只读模式,不允许交易下单
|
||||
LONGBRIDGE_TRADE_ENABLED=true
|
||||
```
|
||||
|
||||
查找顺序:**当前工作目录** → **用户主目录**,`.env` 中的值**不会**覆盖已有的系统环境变量(系统环境变量优先)。
|
||||
|
||||
#### 方式 3:多账户 `--profile` 切换
|
||||
|
||||
使用具名 profile 文件切换账户(如模拟盘与实盘):
|
||||
|
||||
```bash
|
||||
# 在当前目录或主目录分别创建 .paper.env 和 .live.env
|
||||
# 每个文件填写对应账户的凭证
|
||||
|
||||
longbridge --profile paper balance
|
||||
longbridge --profile live positions
|
||||
```
|
||||
|
||||
`--profile paper` 会加载 `.paper.env` 而不是 `.env`。若文件不存在则报错。
|
||||
|
||||
#### 方式 2:Shell 环境变量
|
||||
|
||||
```bash
|
||||
export LONGBRIDGE_APP_KEY="your_app_key"
|
||||
export LONGBRIDGE_APP_SECRET="your_app_secret"
|
||||
export LONGBRIDGE_ACCESS_TOKEN="your_access_token"
|
||||
```
|
||||
|
||||
写入 `~/.zshrc` 或 `~/.bashrc` 永久生效。
|
||||
|
||||
| 环境变量 | 必填 | 说明 |
|
||||
|----------|------|------|
|
||||
| `LONGBRIDGE_APP_KEY` | ✅ | 应用 App Key |
|
||||
| `LONGBRIDGE_APP_SECRET` | ✅ | 应用 App Secret |
|
||||
| `LONGBRIDGE_ACCESS_TOKEN` | ✅ | 用户访问 Token |
|
||||
| `LONGBRIDGE_TRADE_ENABLED` | 可选 | 设为 `true` 开启交易权限(默认只读) |
|
||||
|
||||
---
|
||||
|
||||
### 只读模式与交易权限
|
||||
|
||||
**默认为只读模式**:`buy`、`sell`、`cancel` 命令在未配置交易权限时会被拒绝:
|
||||
|
||||
```
|
||||
Error: 当前为只读模式,下单/撤单操作已禁用。
|
||||
如需开启交易权限,请设置环境变量:
|
||||
export LONGBRIDGE_TRADE_ENABLED=true
|
||||
⚠️ 开启后请确保操作正确,下单指令将直接提交至长桥交易系统。
|
||||
```
|
||||
|
||||
查询类命令(`orders`、`history-orders`、`positions` 等)不受限制,无需额外配置。
|
||||
|
||||
---
|
||||
|
||||
### 使用方法
|
||||
|
||||
所有命令均支持 `--json` 选项输出机器可读的 JSON 格式。
|
||||
|
||||
#### 行情
|
||||
|
||||
```bash
|
||||
# 实时报价(支持批量)
|
||||
longbridge quote AAPL.US 700.HK
|
||||
longbridge quote AAPL.US --json
|
||||
|
||||
# 盘口(买5卖5)
|
||||
longbridge depth 700.HK
|
||||
|
||||
# 逐笔成交
|
||||
longbridge trades 700.HK --count 20
|
||||
|
||||
# K 线(period 可选:1m 5m 15m 30m 60m day week month quarter year)
|
||||
longbridge candlesticks AAPL.US day --count 30
|
||||
longbridge candlesticks 700.HK 60m --count 100 --json
|
||||
|
||||
# 标的静态信息
|
||||
longbridge info AAPL.US 700.HK
|
||||
```
|
||||
|
||||
#### 账户与持仓
|
||||
|
||||
```bash
|
||||
longbridge balance
|
||||
longbridge balance --json
|
||||
|
||||
longbridge positions
|
||||
|
||||
longbridge funds
|
||||
```
|
||||
|
||||
#### 订单管理
|
||||
|
||||
```bash
|
||||
# 只读,无需交易权限
|
||||
longbridge orders
|
||||
longbridge history-orders --start 2026-01-01 --end 2026-03-14
|
||||
|
||||
# 以下命令需设置 LONGBRIDGE_TRADE_ENABLED=true
|
||||
|
||||
# 限价买入(执行前有确认提示)
|
||||
longbridge buy AAPL.US --qty 100 --price 180.0
|
||||
|
||||
# 限价卖出(执行前有确认提示)
|
||||
longbridge sell 700.HK --qty 500 --price 320.0
|
||||
|
||||
# 撤销订单(执行前有确认提示)
|
||||
longbridge cancel 701234567890
|
||||
|
||||
# 跳过确认提示(程序化/脚本调用时使用)
|
||||
longbridge buy AAPL.US --qty 100 --price 180.0 --yes
|
||||
longbridge sell 700.HK --qty 500 --price 320.0 -y
|
||||
```
|
||||
|
||||
#### 市场数据
|
||||
|
||||
```bash
|
||||
# 市场温度(US / HK / CN / SG)
|
||||
longbridge temperature US
|
||||
|
||||
# 资金流向
|
||||
longbridge capital-flow 700.HK
|
||||
|
||||
# 资金分布(大单/中单/小单)
|
||||
longbridge capital-dist 700.HK
|
||||
|
||||
# 期权链到期日
|
||||
longbridge option-chain AAPL.US
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### AI Agent 集成
|
||||
|
||||
#### OpenClaw Skill 接入
|
||||
|
||||
将 `SKILL.md` 复制到 OpenClaw skills 目录,即可注册为 Clawdbot Skill:
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.openclaw/skills/longbridge-cli
|
||||
cp SKILL.md ~/.openclaw/skills/longbridge-cli/SKILL.md
|
||||
```
|
||||
|
||||
安装后,当你询问账户余额、持仓、行情、订单等问题时,Claude 会自动调用 longbridge-cli 命令。
|
||||
|
||||
#### 作为 Skill 使用
|
||||
|
||||
本项目包含 `SKILL.md`,可直接注册为 Clawdbot Skill 供 AI 调用。所有命令均支持 `--json`,输出结构化数据,方便 AI 解析:
|
||||
|
||||
```bash
|
||||
longbridge positions --json
|
||||
longbridge quote AAPL.US 700.HK --json
|
||||
longbridge orders --json
|
||||
```
|
||||
|
||||
JSON 输出示例(`longbridge quote AAPL.US --json`):
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"symbol": "AAPL.US",
|
||||
"last_done": 213.49,
|
||||
"open": 211.50,
|
||||
"high": 214.20,
|
||||
"low": 210.30,
|
||||
"volume": 52345678,
|
||||
"turnover": 11162345678.0,
|
||||
"change_rate": 0.94,
|
||||
"prev_close": 211.51
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 代码标的格式
|
||||
|
||||
| 市场 | 格式 | 示例 |
|
||||
|------|------|------|
|
||||
| 美股 | `代码.US` | `AAPL.US`, `NVDA.US` |
|
||||
| 港股 | `4位代码.HK` | `0700.HK`, `9988.HK` |
|
||||
|
||||
---
|
||||
|
||||
### 项目结构
|
||||
|
||||
```
|
||||
longbridge-cli/
|
||||
├── longbridge_cli/
|
||||
│ ├── __init__.py
|
||||
│ ├── __main__.py # python -m 入口
|
||||
│ ├── cli.py # Click 根命令组
|
||||
│ ├── config.py # Config 初始化
|
||||
│ ├── formatters.py # text/json 统一输出
|
||||
│ └── commands/
|
||||
│ ├── quote.py # 行情命令
|
||||
│ ├── account.py # 账户与持仓
|
||||
│ ├── order.py # 订单管理
|
||||
│ └── market.py # 市场数据
|
||||
├── SKILL.md # Claude Code Skill 文档
|
||||
├── _meta.json # Skill 注册信息
|
||||
├── LICENSE
|
||||
├── requirements.txt
|
||||
└── pyproject.toml
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 依赖
|
||||
|
||||
```
|
||||
longbridge # 长桥官方 Python SDK
|
||||
click>=8.0 # CLI 框架
|
||||
rich>=13.0 # 终端美化输出
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 注意事项
|
||||
|
||||
- **只读模式**:默认禁止 `buy`/`sell`/`cancel`,需设置 `LONGBRIDGE_TRADE_ENABLED=true` 才能下单
|
||||
- **下单/撤单**:开启交易权限后,执行前仍有二次确认提示,防止误操作。脚本/程序化调用可加 `--yes` 或 `-y` 跳过确认
|
||||
- **多账户切换**:使用 `longbridge --profile <名称>` 加载 `.<名称>.env` 凭证文件(如 `--profile paper` 加载 `.paper.env`),方便在模拟盘与实盘之间切换
|
||||
- **港股代码**:必须使用 4 位格式,如 `0700.HK`(不能省略前导零)
|
||||
- **错误处理**:SDK 异常会转换为友好提示,不暴露原始堆栈
|
||||
- **Decimal 序列化**:JSON 输出中 Decimal 类型自动转为 float
|
||||
- **.env 优先级**:系统环境变量优先级高于 `.env` 文件,已存在的环境变量不会被 `.env` 覆盖
|
||||
|
||||
---
|
||||
|
||||
### License
|
||||
|
||||
MIT
|
||||
@@ -0,0 +1,149 @@
|
||||
---
|
||||
name: longbridge
|
||||
version: 1.0.2
|
||||
description: |
|
||||
长桥 LongPort OpenAPI CLI 工具,提供股票行情查询、账户持仓、订单管理、市场数据四大功能。
|
||||
当用户提到"长桥"、"LongPort"、"longbridge",或要求查看股票报价、实时行情、K线、盘口、
|
||||
逐笔成交、账户余额、持仓、基金持仓、下单、买入、卖出、撤单、今日订单、历史订单、
|
||||
资金流向、资金分布、市场温度、期权链时,使用此 skill。即使用户只是随口问"看看苹果股价"、
|
||||
"我的持仓怎么样"、"帮我下个单",也应触发此 skill。
|
||||
metadata: {"clawdbot":{"emoji":"📊","os":["darwin","linux"],"requires":{"bins":["python3","uv"],"env":["LONGBRIDGE_APP_KEY","LONGBRIDGE_APP_SECRET","LONGBRIDGE_ACCESS_TOKEN"]}}}
|
||||
---
|
||||
|
||||
# 长桥 OpenAPI CLI 工具
|
||||
|
||||
通过 `longbridge` CLI 命令调用长桥 OpenAPI,覆盖行情查询、账户持仓、订单管理、市场数据四大模块。
|
||||
|
||||
## 前置条件
|
||||
|
||||
### 环境变量
|
||||
|
||||
需设置以下环境变量(可在 `~/.zshrc` 或 `~/.bashrc` 中配置):
|
||||
|
||||
```bash
|
||||
export LONGBRIDGE_APP_KEY="your_app_key"
|
||||
export LONGBRIDGE_APP_SECRET="your_app_secret"
|
||||
export LONGBRIDGE_ACCESS_TOKEN="your_access_token"
|
||||
|
||||
# 可选:开启交易权限(默认只读,禁止 buy/sell/cancel)
|
||||
# export LONGBRIDGE_TRADE_ENABLED=false
|
||||
```
|
||||
|
||||
也可以在当前目录或主目录创建 `.env` 文件(系统环境变量优先级更高,不会被 `.env` 覆盖)。
|
||||
|
||||
多账户切换:使用 `--profile <名称>` 加载 `.<名称>.env` 文件,例如:
|
||||
|
||||
```bash
|
||||
longbridge --profile paper balance # 加载 .paper.env
|
||||
longbridge --profile live positions # 加载 .live.env
|
||||
```
|
||||
|
||||
### 安装
|
||||
|
||||
先检测是否已安装:
|
||||
|
||||
```bash
|
||||
which longbridge
|
||||
```
|
||||
|
||||
- 若输出路径(如 `/Users/xxx/.local/bin/longbridge`),说明已安装,跳过安装步骤。
|
||||
- 若未找到,从本 skill 目录安装(`SKILL_DIR` 为本文件所在目录):
|
||||
|
||||
```bash
|
||||
uv tool install "$SKILL_DIR"
|
||||
```
|
||||
|
||||
验证安装:
|
||||
|
||||
```bash
|
||||
longbridge --help
|
||||
```
|
||||
|
||||
## 使用方式
|
||||
|
||||
所有命令均支持 `--json` 选项输出 JSON 格式。
|
||||
|
||||
### 行情模块
|
||||
|
||||
```bash
|
||||
# 实时报价(支持多个标的)
|
||||
longbridge quote AAPL.US 700.HK
|
||||
longbridge quote AAPL.US --json
|
||||
|
||||
# 盘口(买5卖5)
|
||||
longbridge depth 700.HK
|
||||
|
||||
# 逐笔成交
|
||||
longbridge trades 700.HK --count 20
|
||||
|
||||
# K 线(period 可选:1m 5m 15m 30m 60m day week month quarter year)
|
||||
longbridge candlesticks AAPL.US day --count 30
|
||||
longbridge candlesticks 700.HK 60m --count 100
|
||||
|
||||
# 标的静态信息
|
||||
longbridge info 700.HK AAPL.US
|
||||
```
|
||||
|
||||
### 账户模块
|
||||
|
||||
```bash
|
||||
# 账户余额与净资产
|
||||
longbridge balance
|
||||
|
||||
# 股票持仓
|
||||
longbridge positions
|
||||
longbridge positions --json
|
||||
|
||||
# 基金持仓
|
||||
longbridge funds
|
||||
```
|
||||
|
||||
### 订单模块
|
||||
|
||||
```bash
|
||||
# 今日订单(只读,无需交易权限)
|
||||
longbridge orders
|
||||
|
||||
# 历史订单(只读,无需交易权限)
|
||||
longbridge history-orders --start 2026-01-01 --end 2026-03-14
|
||||
|
||||
# 以下命令需设置 LONGBRIDGE_TRADE_ENABLED=true
|
||||
|
||||
# 限价买入(会有确认提示,防止误操作)
|
||||
longbridge buy AAPL.US --qty 100 --price 180.0
|
||||
|
||||
# 限价卖出(会有确认提示)
|
||||
longbridge sell 700.HK --qty 500 --price 320.0
|
||||
|
||||
# 撤销订单(会有确认提示)
|
||||
longbridge cancel 701234567890
|
||||
|
||||
# 跳过确认提示(AI Agent 程序化调用时推荐加 --yes)
|
||||
longbridge buy AAPL.US --qty 100 --price 180.0 --yes
|
||||
longbridge sell 700.HK --qty 500 --price 320.0 -y
|
||||
```
|
||||
|
||||
### 市场数据模块
|
||||
|
||||
```bash
|
||||
# 市场温度(US/HK/CN/SG)
|
||||
longbridge temperature US
|
||||
longbridge temperature HK
|
||||
|
||||
# 资金流向
|
||||
longbridge capital-flow 700.HK
|
||||
|
||||
# 资金分布(大单/中单/小单)
|
||||
longbridge capital-dist 700.HK
|
||||
|
||||
# 期权链到期日列表
|
||||
longbridge option-chain AAPL.US
|
||||
```
|
||||
|
||||
## 注意事项
|
||||
|
||||
- **下单/撤单命令**:`buy`、`sell`、`cancel` 均有确认提示,确认后才会执行,防止误操作。AI Agent 程序化调用时请加 `--yes` 或 `-y` 跳过确认
|
||||
- **港股代码格式**:使用 4 位 + `.HK` 后缀,如 `0700.HK`、`9988.HK`
|
||||
- **美股代码格式**:使用股票代码 + `.US` 后缀,如 `AAPL.US`、`NVDA.US`
|
||||
- **JSON 输出**:所有命令加 `--json` 可输出机器可读的 JSON 格式,便于 AI 解析
|
||||
- **错误处理**:SDK 异常会输出友好提示,不暴露原始堆栈
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"ownerId": "kn710bpt2w6p9mw4nm8g03f82582w94c",
|
||||
"slug": "longbridge-kit",
|
||||
"version": "1.0.2",
|
||||
"publishedAt": 1774793905098
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
"""longbridge_cli 包初始化"""
|
||||
@@ -0,0 +1,5 @@
|
||||
"""支持 python -m longbridge_cli 调用"""
|
||||
from longbridge_cli.cli import cli
|
||||
|
||||
if __name__ == "__main__":
|
||||
cli()
|
||||
@@ -0,0 +1,69 @@
|
||||
"""longbridge-cli 根命令组"""
|
||||
import click
|
||||
|
||||
from longbridge_cli.commands.quote import (
|
||||
quote_cmd,
|
||||
depth_cmd,
|
||||
trades_cmd,
|
||||
candlesticks_cmd,
|
||||
info_cmd,
|
||||
)
|
||||
from longbridge_cli.commands.account import balance_cmd, positions_cmd, funds_cmd
|
||||
from longbridge_cli.commands.order import (
|
||||
orders_cmd,
|
||||
history_orders_cmd,
|
||||
buy_cmd,
|
||||
sell_cmd,
|
||||
cancel_cmd,
|
||||
)
|
||||
from longbridge_cli.commands.market import (
|
||||
temperature_cmd,
|
||||
capital_flow_cmd,
|
||||
capital_dist_cmd,
|
||||
option_chain_cmd,
|
||||
)
|
||||
|
||||
|
||||
@click.group()
|
||||
@click.version_option("1.0.0", prog_name="longbridge")
|
||||
@click.option("--profile", default=None, help="账户 profile(如 paper),加载 .{profile}.env 凭证文件")
|
||||
@click.pass_context
|
||||
def cli(ctx, profile):
|
||||
"""长桥 LongPort OpenAPI CLI 工具
|
||||
|
||||
\b
|
||||
行情: quote depth trades candlesticks info
|
||||
账户: balance positions funds
|
||||
订单: orders history-orders buy sell cancel
|
||||
市场: temperature capital-flow capital-dist option-chain
|
||||
|
||||
所有命令支持 --json 输出 JSON 格式。
|
||||
"""
|
||||
ctx.ensure_object(dict)
|
||||
ctx.obj["profile"] = profile
|
||||
|
||||
|
||||
# 行情
|
||||
cli.add_command(quote_cmd, name="quote")
|
||||
cli.add_command(depth_cmd, name="depth")
|
||||
cli.add_command(trades_cmd, name="trades")
|
||||
cli.add_command(candlesticks_cmd, name="candlesticks")
|
||||
cli.add_command(info_cmd, name="info")
|
||||
|
||||
# 账户
|
||||
cli.add_command(balance_cmd, name="balance")
|
||||
cli.add_command(positions_cmd, name="positions")
|
||||
cli.add_command(funds_cmd, name="funds")
|
||||
|
||||
# 订单
|
||||
cli.add_command(orders_cmd, name="orders")
|
||||
cli.add_command(history_orders_cmd, name="history-orders")
|
||||
cli.add_command(buy_cmd, name="buy")
|
||||
cli.add_command(sell_cmd, name="sell")
|
||||
cli.add_command(cancel_cmd, name="cancel")
|
||||
|
||||
# 市场
|
||||
cli.add_command(temperature_cmd, name="temperature")
|
||||
cli.add_command(capital_flow_cmd, name="capital-flow")
|
||||
cli.add_command(capital_dist_cmd, name="capital-dist")
|
||||
cli.add_command(option_chain_cmd, name="option-chain")
|
||||
@@ -0,0 +1,147 @@
|
||||
"""账户与持仓命令模块"""
|
||||
import click
|
||||
from longbridge.openapi import TradeContext
|
||||
|
||||
from longbridge_cli.config import get_config
|
||||
from longbridge_cli.formatters import print_table, print_json, print_error
|
||||
|
||||
|
||||
@click.command("balance")
|
||||
@click.option("--json", "output_json", is_flag=True, help="以 JSON 格式输出")
|
||||
@click.pass_context
|
||||
def balance_cmd(ctx, output_json):
|
||||
"""查看账户余额与净资产
|
||||
|
||||
示例:longbridge balance
|
||||
"""
|
||||
try:
|
||||
trade_ctx = TradeContext(get_config(ctx.obj.get("profile")))
|
||||
resp = trade_ctx.account_balance()
|
||||
except Exception as e:
|
||||
print_error(str(e))
|
||||
|
||||
if output_json:
|
||||
data = [
|
||||
{
|
||||
"currency": b.currency,
|
||||
"total_cash": float(b.total_cash),
|
||||
"max_finance_amount": float(b.max_finance_amount),
|
||||
"remaining_finance_amount": float(b.remaining_finance_amount),
|
||||
"risk_level": b.risk_level,
|
||||
"margin_call": float(b.margin_call),
|
||||
"net_assets": float(b.net_assets),
|
||||
"init_margin": float(b.init_margin),
|
||||
"maintenance_margin": float(b.maintenance_margin),
|
||||
}
|
||||
for b in resp
|
||||
]
|
||||
print_json(data)
|
||||
else:
|
||||
headers = ["币种", "现金余额", "净资产", "最大融资额", "剩余融资额", "风险等级"]
|
||||
rows = [
|
||||
[
|
||||
b.currency,
|
||||
f"{float(b.total_cash):,.2f}",
|
||||
f"{float(b.net_assets):,.2f}",
|
||||
f"{float(b.max_finance_amount):,.2f}",
|
||||
f"{float(b.remaining_finance_amount):,.2f}",
|
||||
str(b.risk_level),
|
||||
]
|
||||
for b in resp
|
||||
]
|
||||
print_table(headers, rows, title="账户余额")
|
||||
|
||||
|
||||
@click.command("positions")
|
||||
@click.option("--json", "output_json", is_flag=True, help="以 JSON 格式输出")
|
||||
@click.pass_context
|
||||
def positions_cmd(ctx, output_json):
|
||||
"""查看股票持仓
|
||||
|
||||
示例:longbridge positions
|
||||
"""
|
||||
try:
|
||||
trade_ctx = TradeContext(get_config(ctx.obj.get("profile")))
|
||||
resp = trade_ctx.stock_positions()
|
||||
except Exception as e:
|
||||
print_error(str(e))
|
||||
|
||||
channels = resp.channels if resp else []
|
||||
|
||||
if output_json:
|
||||
data = []
|
||||
for ch in channels:
|
||||
for p in ch.positions:
|
||||
data.append({
|
||||
"symbol": p.symbol,
|
||||
"symbol_name": p.symbol_name,
|
||||
"quantity": p.quantity,
|
||||
"available_quantity": p.available_quantity,
|
||||
"currency": p.currency,
|
||||
"cost_price": float(p.cost_price),
|
||||
"init_quantity": p.init_quantity,
|
||||
"market": str(p.market),
|
||||
})
|
||||
print_json(data)
|
||||
else:
|
||||
headers = ["标的", "名称", "持仓", "可卖", "成本价", "初始持仓", "市场", "币种"]
|
||||
rows = []
|
||||
for ch in channels:
|
||||
for p in ch.positions:
|
||||
rows.append([
|
||||
p.symbol,
|
||||
p.symbol_name,
|
||||
str(p.quantity),
|
||||
str(p.available_quantity),
|
||||
f"{float(p.cost_price):.3f}",
|
||||
str(p.init_quantity),
|
||||
str(p.market),
|
||||
p.currency,
|
||||
])
|
||||
print_table(headers, rows, title="股票持仓")
|
||||
|
||||
|
||||
@click.command("funds")
|
||||
@click.option("--json", "output_json", is_flag=True, help="以 JSON 格式输出")
|
||||
@click.pass_context
|
||||
def funds_cmd(ctx, output_json):
|
||||
"""查看基金持仓
|
||||
|
||||
示例:longbridge funds
|
||||
"""
|
||||
try:
|
||||
trade_ctx = TradeContext(get_config(ctx.obj.get("profile")))
|
||||
resp = trade_ctx.fund_positions()
|
||||
except Exception as e:
|
||||
print_error(str(e))
|
||||
|
||||
channels = resp.channels if resp else []
|
||||
|
||||
if output_json:
|
||||
data = []
|
||||
for ch in channels:
|
||||
for f in ch.positions:
|
||||
data.append({
|
||||
"symbol": f.symbol,
|
||||
"symbol_name": f.symbol_name,
|
||||
"holding_units": float(f.holding_units),
|
||||
"current_net_asset_value": float(f.current_net_asset_value),
|
||||
"cost_net_asset_value": float(f.cost_net_asset_value),
|
||||
"net_asset_value_day": f.net_asset_value_day.isoformat() if f.net_asset_value_day else None,
|
||||
"market_value": float(f.market_value) if hasattr(f, "market_value") else None,
|
||||
})
|
||||
print_json(data)
|
||||
else:
|
||||
headers = ["基金代码", "名称", "持有份额", "当前净值", "成本净值", "净值日期"]
|
||||
rows = []
|
||||
for ch in channels:
|
||||
for f in ch.positions:
|
||||
rows.append([
|
||||
f.symbol,
|
||||
f.symbol_name,
|
||||
f"{float(f.holding_units):.4f}",
|
||||
f"{float(f.current_net_asset_value):.4f}",
|
||||
f"{float(f.cost_net_asset_value):.4f}",
|
||||
f.net_asset_value_day.strftime("%Y-%m-%d") if f.net_asset_value_day else "-",
|
||||
])
|
||||
print_table(headers, rows, title="基金持仓")
|
||||
@@ -0,0 +1,162 @@
|
||||
"""市场数据命令模块"""
|
||||
import click
|
||||
from longbridge.openapi import QuoteContext, Market
|
||||
|
||||
from longbridge_cli.config import get_config
|
||||
from longbridge_cli.formatters import print_table, print_json, print_kv, print_error
|
||||
|
||||
MARKET_MAP = {
|
||||
"US": Market.US,
|
||||
"HK": Market.HK,
|
||||
"CN": Market.CN,
|
||||
"SG": Market.SG,
|
||||
}
|
||||
|
||||
|
||||
@click.command("temperature")
|
||||
@click.argument("market", type=click.Choice(["US", "HK", "CN", "SG"]))
|
||||
@click.option("--json", "output_json", is_flag=True, help="以 JSON 格式输出")
|
||||
@click.pass_context
|
||||
def temperature_cmd(ctx, market, output_json):
|
||||
"""查看市场温度
|
||||
|
||||
MARKET 可选:US HK CN SG
|
||||
|
||||
示例:longbridge temperature US
|
||||
"""
|
||||
try:
|
||||
quote_ctx = QuoteContext(get_config(ctx.obj.get("profile")))
|
||||
resp = quote_ctx.market_temperature(MARKET_MAP[market])
|
||||
except Exception as e:
|
||||
print_error(str(e))
|
||||
|
||||
if output_json:
|
||||
data = {
|
||||
"market": market,
|
||||
"temperature": resp.temperature,
|
||||
"description": resp.description,
|
||||
"valuation": float(resp.valuation) if hasattr(resp, "valuation") else None,
|
||||
}
|
||||
print_json(data)
|
||||
else:
|
||||
pairs = [
|
||||
("市场", market),
|
||||
("温度", resp.temperature),
|
||||
("描述", resp.description),
|
||||
]
|
||||
if hasattr(resp, "valuation"):
|
||||
pairs.append(("估值", float(resp.valuation)))
|
||||
print_kv(pairs, title=f"市场温度 - {market}")
|
||||
|
||||
|
||||
@click.command("capital-flow")
|
||||
@click.argument("symbol")
|
||||
@click.option("--json", "output_json", is_flag=True, help="以 JSON 格式输出")
|
||||
@click.pass_context
|
||||
def capital_flow_cmd(ctx, symbol, output_json):
|
||||
"""查看资金流向
|
||||
|
||||
示例:longbridge capital-flow 700.HK
|
||||
"""
|
||||
try:
|
||||
quote_ctx = QuoteContext(get_config(ctx.obj.get("profile")))
|
||||
resp = quote_ctx.capital_flow(symbol)
|
||||
except Exception as e:
|
||||
print_error(str(e))
|
||||
|
||||
if output_json:
|
||||
data = [
|
||||
{
|
||||
"timestamp": item.timestamp.isoformat() if item.timestamp else None,
|
||||
"inflow": float(item.inflow),
|
||||
}
|
||||
for item in resp
|
||||
]
|
||||
print_json(data)
|
||||
else:
|
||||
headers = ["时间", "净流入"]
|
||||
rows = [
|
||||
[
|
||||
item.timestamp.strftime("%Y-%m-%d %H:%M") if item.timestamp else "-",
|
||||
f"{float(item.inflow):+,.0f}",
|
||||
]
|
||||
for item in resp
|
||||
]
|
||||
print_table(headers, rows, title=f"资金流向 - {symbol}")
|
||||
|
||||
|
||||
@click.command("capital-dist")
|
||||
@click.argument("symbol")
|
||||
@click.option("--json", "output_json", is_flag=True, help="以 JSON 格式输出")
|
||||
@click.pass_context
|
||||
def capital_dist_cmd(ctx, symbol, output_json):
|
||||
"""查看资金分布
|
||||
|
||||
示例:longbridge capital-dist 700.HK
|
||||
"""
|
||||
try:
|
||||
quote_ctx = QuoteContext(get_config(ctx.obj.get("profile")))
|
||||
resp = quote_ctx.capital_distribution(symbol)
|
||||
except Exception as e:
|
||||
print_error(str(e))
|
||||
|
||||
if output_json:
|
||||
data = {
|
||||
"symbol": symbol,
|
||||
"timestamp": resp.timestamp.isoformat() if resp.timestamp else None,
|
||||
"capital_in": {
|
||||
"large": float(resp.capital_in.large),
|
||||
"medium": float(resp.capital_in.medium),
|
||||
"small": float(resp.capital_in.small),
|
||||
},
|
||||
"capital_out": {
|
||||
"large": float(resp.capital_out.large),
|
||||
"medium": float(resp.capital_out.medium),
|
||||
"small": float(resp.capital_out.small),
|
||||
},
|
||||
}
|
||||
print_json(data)
|
||||
else:
|
||||
headers = ["方向", "大单", "中单", "小单"]
|
||||
rows = [
|
||||
[
|
||||
"流入",
|
||||
f"{float(resp.capital_in.large):,.0f}",
|
||||
f"{float(resp.capital_in.medium):,.0f}",
|
||||
f"{float(resp.capital_in.small):,.0f}",
|
||||
],
|
||||
[
|
||||
"流出",
|
||||
f"{float(resp.capital_out.large):,.0f}",
|
||||
f"{float(resp.capital_out.medium):,.0f}",
|
||||
f"{float(resp.capital_out.small):,.0f}",
|
||||
],
|
||||
]
|
||||
print_table(headers, rows, title=f"资金分布 - {symbol}")
|
||||
|
||||
|
||||
@click.command("option-chain")
|
||||
@click.argument("symbol")
|
||||
@click.option("--json", "output_json", is_flag=True, help="以 JSON 格式输出")
|
||||
@click.pass_context
|
||||
def option_chain_cmd(ctx, symbol, output_json):
|
||||
"""查看期权链到期日列表
|
||||
|
||||
示例:longbridge option-chain AAPL.US
|
||||
"""
|
||||
try:
|
||||
quote_ctx = QuoteContext(get_config(ctx.obj.get("profile")))
|
||||
resp = quote_ctx.option_chain_expiry_date_list(symbol)
|
||||
except Exception as e:
|
||||
print_error(str(e))
|
||||
|
||||
if output_json:
|
||||
data = {
|
||||
"symbol": symbol,
|
||||
"expiry_dates": [d.isoformat() for d in resp],
|
||||
}
|
||||
print_json(data)
|
||||
else:
|
||||
headers = ["序号", "到期日"]
|
||||
rows = [[str(i + 1), d.strftime("%Y-%m-%d")] for i, d in enumerate(resp)]
|
||||
print_table(headers, rows, title=f"期权链到期日 - {symbol}")
|
||||
@@ -0,0 +1,188 @@
|
||||
"""订单管理命令模块"""
|
||||
from datetime import datetime
|
||||
from decimal import Decimal
|
||||
|
||||
import click
|
||||
from longbridge.openapi import (
|
||||
TradeContext,
|
||||
OrderType,
|
||||
OrderSide,
|
||||
TimeInForceType,
|
||||
)
|
||||
|
||||
from longbridge_cli.config import get_config, require_trade_enabled
|
||||
from longbridge_cli.formatters import print_table, print_json, print_error
|
||||
|
||||
|
||||
@click.command("orders")
|
||||
@click.option("--json", "output_json", is_flag=True, help="以 JSON 格式输出")
|
||||
@click.pass_context
|
||||
def orders_cmd(ctx, output_json):
|
||||
"""查看今日订单
|
||||
|
||||
示例:longbridge orders
|
||||
"""
|
||||
try:
|
||||
trade_ctx = TradeContext(get_config(ctx.obj.get("profile")))
|
||||
resp = trade_ctx.today_orders()
|
||||
except Exception as e:
|
||||
print_error(str(e))
|
||||
|
||||
_print_orders(resp, output_json, "今日订单")
|
||||
|
||||
|
||||
@click.command("history-orders")
|
||||
@click.option("--start", required=True, help="开始日期 (YYYY-MM-DD)")
|
||||
@click.option("--end", required=True, help="结束日期 (YYYY-MM-DD)")
|
||||
@click.option("--json", "output_json", is_flag=True, help="以 JSON 格式输出")
|
||||
@click.pass_context
|
||||
def history_orders_cmd(ctx, start, end, output_json):
|
||||
"""查看历史订单
|
||||
|
||||
示例:longbridge history-orders --start 2026-01-01 --end 2026-03-14
|
||||
"""
|
||||
try:
|
||||
start_dt = datetime.strptime(start, "%Y-%m-%d")
|
||||
end_dt = datetime.strptime(end, "%Y-%m-%d")
|
||||
trade_ctx = TradeContext(get_config(ctx.obj.get("profile")))
|
||||
resp = trade_ctx.history_orders(start_at=start_dt, end_at=end_dt)
|
||||
except ValueError:
|
||||
print_error("日期格式错误,请使用 YYYY-MM-DD")
|
||||
return
|
||||
except Exception as e:
|
||||
print_error(str(e))
|
||||
|
||||
_print_orders(resp, output_json, f"历史订单 ({start} ~ {end})")
|
||||
|
||||
|
||||
@click.command("buy")
|
||||
@click.argument("symbol")
|
||||
@click.option("--qty", required=True, type=int, help="买入数量")
|
||||
@click.option("--price", required=True, type=float, help="限价价格")
|
||||
@click.option("--json", "output_json", is_flag=True, help="以 JSON 格式输出")
|
||||
@click.option("--yes", "-y", is_flag=True, help="跳过交互确认(程序化调用时使用)")
|
||||
@click.pass_context
|
||||
def buy_cmd(ctx, symbol, qty, price, output_json, yes):
|
||||
"""限价买入
|
||||
|
||||
示例:longbridge buy AAPL.US --qty 100 --price 180.0
|
||||
"""
|
||||
require_trade_enabled()
|
||||
if not yes:
|
||||
click.confirm(f"确认买入 {symbol} 数量 {qty} 限价 {price}?", abort=True)
|
||||
try:
|
||||
trade_ctx = TradeContext(get_config(ctx.obj.get("profile")))
|
||||
resp = trade_ctx.submit_order(
|
||||
symbol,
|
||||
OrderType.LO,
|
||||
OrderSide.Buy,
|
||||
qty,
|
||||
TimeInForceType.Day,
|
||||
submitted_price=Decimal(str(price)),
|
||||
)
|
||||
except Exception as e:
|
||||
print_error(str(e))
|
||||
return
|
||||
|
||||
if output_json:
|
||||
print_json({"order_id": resp.order_id})
|
||||
else:
|
||||
click.echo(f"下单成功,订单号:{resp.order_id}")
|
||||
|
||||
|
||||
@click.command("sell")
|
||||
@click.argument("symbol")
|
||||
@click.option("--qty", required=True, type=int, help="卖出数量")
|
||||
@click.option("--price", required=True, type=float, help="限价价格")
|
||||
@click.option("--json", "output_json", is_flag=True, help="以 JSON 格式输出")
|
||||
@click.option("--yes", "-y", is_flag=True, help="跳过交互确认(程序化调用时使用)")
|
||||
@click.pass_context
|
||||
def sell_cmd(ctx, symbol, qty, price, output_json, yes):
|
||||
"""限价卖出
|
||||
|
||||
示例:longbridge sell 700.HK --qty 500 --price 320.0
|
||||
"""
|
||||
require_trade_enabled()
|
||||
if not yes:
|
||||
click.confirm(f"确认卖出 {symbol} 数量 {qty} 限价 {price}?", abort=True)
|
||||
try:
|
||||
trade_ctx = TradeContext(get_config(ctx.obj.get("profile")))
|
||||
resp = trade_ctx.submit_order(
|
||||
symbol,
|
||||
OrderType.LO,
|
||||
OrderSide.Sell,
|
||||
qty,
|
||||
TimeInForceType.Day,
|
||||
submitted_price=Decimal(str(price)),
|
||||
)
|
||||
except Exception as e:
|
||||
print_error(str(e))
|
||||
return
|
||||
|
||||
if output_json:
|
||||
print_json({"order_id": resp.order_id})
|
||||
else:
|
||||
click.echo(f"下单成功,订单号:{resp.order_id}")
|
||||
|
||||
|
||||
@click.command("cancel")
|
||||
@click.argument("order_id")
|
||||
@click.option("--json", "output_json", is_flag=True, help="以 JSON 格式输出")
|
||||
@click.pass_context
|
||||
def cancel_cmd(ctx, order_id, output_json):
|
||||
"""撤销订单
|
||||
|
||||
示例:longbridge cancel 701234567890
|
||||
"""
|
||||
require_trade_enabled()
|
||||
click.confirm(f"确认撤销订单 {order_id}?", abort=True)
|
||||
try:
|
||||
trade_ctx = TradeContext(get_config(ctx.obj.get("profile")))
|
||||
trade_ctx.cancel_order(order_id)
|
||||
except Exception as e:
|
||||
print_error(str(e))
|
||||
|
||||
if output_json:
|
||||
print_json({"order_id": order_id, "status": "cancelled"})
|
||||
else:
|
||||
click.echo(f"订单 {order_id} 已撤销")
|
||||
|
||||
|
||||
def _print_orders(orders, output_json: bool, title: str) -> None:
|
||||
"""内部辅助:统一输出订单列表"""
|
||||
if output_json:
|
||||
data = [
|
||||
{
|
||||
"order_id": o.order_id,
|
||||
"symbol": o.symbol,
|
||||
"side": str(o.side),
|
||||
"order_type": str(o.order_type),
|
||||
"quantity": o.quantity,
|
||||
"executed_quantity": o.executed_quantity,
|
||||
"price": float(o.price) if o.price else None,
|
||||
"executed_price": float(o.executed_price) if o.executed_price else None,
|
||||
"status": str(o.status),
|
||||
"submitted_at": o.submitted_at.isoformat() if o.submitted_at else None,
|
||||
"updated_at": o.updated_at.isoformat() if o.updated_at else None,
|
||||
}
|
||||
for o in orders
|
||||
]
|
||||
print_json(data)
|
||||
else:
|
||||
headers = ["订单号", "标的", "方向", "类型", "数量", "已成交", "委托价", "成交价", "状态", "提交时间"]
|
||||
rows = [
|
||||
[
|
||||
o.order_id,
|
||||
o.symbol,
|
||||
str(o.side),
|
||||
str(o.order_type),
|
||||
str(o.quantity),
|
||||
str(o.executed_quantity),
|
||||
f"{float(o.price):.3f}" if o.price else "-",
|
||||
f"{float(o.executed_price):.3f}" if o.executed_price else "-",
|
||||
str(o.status),
|
||||
o.submitted_at.strftime("%Y-%m-%d %H:%M:%S") if o.submitted_at else "-",
|
||||
]
|
||||
for o in orders
|
||||
]
|
||||
print_table(headers, rows, title=title)
|
||||
@@ -0,0 +1,239 @@
|
||||
"""行情命令模块"""
|
||||
import click
|
||||
from longbridge.openapi import QuoteContext, Period, AdjustType
|
||||
|
||||
from longbridge_cli.config import get_config
|
||||
from longbridge_cli.formatters import print_table, print_json, print_error
|
||||
|
||||
PERIOD_MAP = {
|
||||
"1m": Period.Min_1,
|
||||
"5m": Period.Min_5,
|
||||
"15m": Period.Min_15,
|
||||
"30m": Period.Min_30,
|
||||
"60m": Period.Min_60,
|
||||
"day": Period.Day,
|
||||
"week": Period.Week,
|
||||
"month": Period.Month,
|
||||
"quarter": Period.Quarter,
|
||||
"year": Period.Year,
|
||||
}
|
||||
|
||||
|
||||
@click.command("quote")
|
||||
@click.argument("symbols", nargs=-1, required=True)
|
||||
@click.option("--json", "output_json", is_flag=True, help="以 JSON 格式输出")
|
||||
@click.pass_context
|
||||
def quote_cmd(ctx, symbols, output_json):
|
||||
"""获取实时报价(支持多个标的)
|
||||
|
||||
示例:longbridge quote AAPL.US 700.HK
|
||||
"""
|
||||
try:
|
||||
quote_ctx = QuoteContext(get_config(ctx.obj.get("profile")))
|
||||
resp = quote_ctx.quote(list(symbols))
|
||||
except Exception as e:
|
||||
print_error(str(e))
|
||||
|
||||
if output_json:
|
||||
data = [
|
||||
{
|
||||
"symbol": q.symbol,
|
||||
"last_done": float(q.last_done),
|
||||
"open": float(q.open),
|
||||
"high": float(q.high),
|
||||
"low": float(q.low),
|
||||
"volume": q.volume,
|
||||
"turnover": float(q.turnover),
|
||||
"change_rate": round(float(q.last_done / q.prev_close - 1) * 100, 2) if q.prev_close else None,
|
||||
"prev_close": float(q.prev_close),
|
||||
}
|
||||
for q in resp
|
||||
]
|
||||
print_json(data)
|
||||
else:
|
||||
headers = ["标的", "最新价", "涨跌幅", "开盘", "最高", "最低", "成交量", "成交额"]
|
||||
rows = []
|
||||
for q in resp:
|
||||
change_rate = round(float(q.last_done / q.prev_close - 1) * 100, 2) if q.prev_close else "-"
|
||||
change_str = f"{change_rate:+.2f}%" if isinstance(change_rate, float) else change_rate
|
||||
rows.append([
|
||||
q.symbol,
|
||||
f"{float(q.last_done):.3f}",
|
||||
change_str,
|
||||
f"{float(q.open):.3f}",
|
||||
f"{float(q.high):.3f}",
|
||||
f"{float(q.low):.3f}",
|
||||
f"{q.volume:,}",
|
||||
f"{float(q.turnover):,.0f}",
|
||||
])
|
||||
print_table(headers, rows, title="实时报价")
|
||||
|
||||
|
||||
@click.command("depth")
|
||||
@click.argument("symbol")
|
||||
@click.option("--json", "output_json", is_flag=True, help="以 JSON 格式输出")
|
||||
@click.pass_context
|
||||
def depth_cmd(ctx, symbol, output_json):
|
||||
"""查看盘口(买5卖5)
|
||||
|
||||
示例:longbridge depth 700.HK
|
||||
"""
|
||||
try:
|
||||
quote_ctx = QuoteContext(get_config(ctx.obj.get("profile")))
|
||||
resp = quote_ctx.depth(symbol)
|
||||
except Exception as e:
|
||||
print_error(str(e))
|
||||
|
||||
if output_json:
|
||||
data = {
|
||||
"symbol": symbol,
|
||||
"asks": [{"position": a.position, "price": float(a.price), "volume": a.volume} for a in resp.asks],
|
||||
"bids": [{"position": b.position, "price": float(b.price), "volume": b.volume} for b in resp.bids],
|
||||
}
|
||||
print_json(data)
|
||||
else:
|
||||
headers = ["方向", "档位", "价格", "数量"]
|
||||
rows = []
|
||||
for a in reversed(resp.asks):
|
||||
rows.append(["卖", str(a.position), f"{float(a.price):.3f}", f"{a.volume:,}"])
|
||||
for b in resp.bids:
|
||||
rows.append(["买", str(b.position), f"{float(b.price):.3f}", f"{b.volume:,}"])
|
||||
print_table(headers, rows, title=f"盘口 - {symbol}")
|
||||
|
||||
|
||||
@click.command("trades")
|
||||
@click.argument("symbol")
|
||||
@click.option("--count", default=20, show_default=True, help="返回条数(最多 1000)")
|
||||
@click.option("--json", "output_json", is_flag=True, help="以 JSON 格式输出")
|
||||
@click.pass_context
|
||||
def trades_cmd(ctx, symbol, count, output_json):
|
||||
"""查看最近逐笔成交
|
||||
|
||||
示例:longbridge trades 700.HK --count 20
|
||||
"""
|
||||
try:
|
||||
quote_ctx = QuoteContext(get_config(ctx.obj.get("profile")))
|
||||
resp = quote_ctx.trades(symbol, count)
|
||||
except Exception as e:
|
||||
print_error(str(e))
|
||||
|
||||
if output_json:
|
||||
data = [
|
||||
{
|
||||
"price": float(t.price),
|
||||
"volume": t.volume,
|
||||
"timestamp": t.timestamp.isoformat() if t.timestamp else None,
|
||||
"direction": str(t.trade_type),
|
||||
}
|
||||
for t in resp
|
||||
]
|
||||
print_json(data)
|
||||
else:
|
||||
headers = ["时间", "价格", "数量", "类型"]
|
||||
rows = [
|
||||
[
|
||||
t.timestamp.strftime("%H:%M:%S") if t.timestamp else "-",
|
||||
f"{float(t.price):.3f}",
|
||||
f"{t.volume:,}",
|
||||
str(t.trade_type),
|
||||
]
|
||||
for t in resp
|
||||
]
|
||||
print_table(headers, rows, title=f"逐笔成交 - {symbol}")
|
||||
|
||||
|
||||
@click.command("candlesticks")
|
||||
@click.argument("symbol")
|
||||
@click.argument("period", type=click.Choice(list(PERIOD_MAP.keys())))
|
||||
@click.option("--count", default=30, show_default=True, help="返回K线条数(最多 1000)")
|
||||
@click.option("--json", "output_json", is_flag=True, help="以 JSON 格式输出")
|
||||
@click.pass_context
|
||||
def candlesticks_cmd(ctx, symbol, period, count, output_json):
|
||||
"""查看 K 线数据
|
||||
|
||||
PERIOD 可选:1m 5m 15m 30m 60m day week month quarter year
|
||||
|
||||
示例:longbridge candlesticks AAPL.US day --count 30
|
||||
"""
|
||||
try:
|
||||
quote_ctx = QuoteContext(get_config(ctx.obj.get("profile")))
|
||||
resp = quote_ctx.candlesticks(symbol, PERIOD_MAP[period], count, AdjustType.NoAdjust)
|
||||
except Exception as e:
|
||||
print_error(str(e))
|
||||
|
||||
if output_json:
|
||||
data = [
|
||||
{
|
||||
"timestamp": c.timestamp.isoformat() if c.timestamp else None,
|
||||
"open": float(c.open),
|
||||
"high": float(c.high),
|
||||
"low": float(c.low),
|
||||
"close": float(c.close),
|
||||
"volume": c.volume,
|
||||
"turnover": float(c.turnover),
|
||||
}
|
||||
for c in resp
|
||||
]
|
||||
print_json(data)
|
||||
else:
|
||||
headers = ["时间", "开盘", "最高", "最低", "收盘", "成交量"]
|
||||
rows = [
|
||||
[
|
||||
c.timestamp.strftime("%Y-%m-%d %H:%M") if c.timestamp else "-",
|
||||
f"{float(c.open):.3f}",
|
||||
f"{float(c.high):.3f}",
|
||||
f"{float(c.low):.3f}",
|
||||
f"{float(c.close):.3f}",
|
||||
f"{c.volume:,}",
|
||||
]
|
||||
for c in resp
|
||||
]
|
||||
print_table(headers, rows, title=f"K线 - {symbol} ({period})")
|
||||
|
||||
|
||||
@click.command("info")
|
||||
@click.argument("symbols", nargs=-1, required=True)
|
||||
@click.option("--json", "output_json", is_flag=True, help="以 JSON 格式输出")
|
||||
@click.pass_context
|
||||
def info_cmd(ctx, symbols, output_json):
|
||||
"""查看标的静态基本信息(名称、交易所、类型等)
|
||||
|
||||
示例:longbridge info 700.HK AAPL.US
|
||||
"""
|
||||
try:
|
||||
quote_ctx = QuoteContext(get_config(ctx.obj.get("profile")))
|
||||
resp = quote_ctx.static_info(list(symbols))
|
||||
except Exception as e:
|
||||
print_error(str(e))
|
||||
|
||||
if output_json:
|
||||
data = [
|
||||
{
|
||||
"symbol": s.symbol,
|
||||
"name_cn": s.name_cn,
|
||||
"name_en": s.name_en,
|
||||
"exchange": s.exchange,
|
||||
"currency": s.currency,
|
||||
"lot_size": s.lot_size,
|
||||
"total_shares": s.total_shares,
|
||||
"circulating_shares": s.circulating_shares,
|
||||
"board": str(s.board),
|
||||
}
|
||||
for s in resp
|
||||
]
|
||||
print_json(data)
|
||||
else:
|
||||
headers = ["标的", "中文名", "英文名", "交易所", "币种", "手数", "板块"]
|
||||
rows = [
|
||||
[
|
||||
s.symbol,
|
||||
s.name_cn,
|
||||
s.name_en,
|
||||
s.exchange,
|
||||
s.currency,
|
||||
str(s.lot_size),
|
||||
str(s.board),
|
||||
]
|
||||
for s in resp
|
||||
]
|
||||
print_table(headers, rows, title="标的信息")
|
||||
@@ -0,0 +1,87 @@
|
||||
"""长桥 OpenAPI 配置初始化"""
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
import click
|
||||
from longbridge.openapi import Config
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# .env 加载(CLI 包自包含,不依赖 trader 包)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def _load_dotenv_for_profile(profile: str | None = None) -> None:
|
||||
"""Load .env (or .{profile}.env) into os.environ.
|
||||
|
||||
查找顺序: cwd → home dir。
|
||||
profile=None + 文件不存在 → 静默跳过(向后兼容)。
|
||||
profile 非空 + 文件不存在 → 抛 FileNotFoundError。
|
||||
已存在的环境变量不会被覆盖。
|
||||
"""
|
||||
filename = f".{profile}.env" if profile else ".env"
|
||||
env_path: Path | None = None
|
||||
for base in [Path.cwd(), Path.home()]:
|
||||
candidate = base / filename
|
||||
if candidate.is_file():
|
||||
env_path = candidate
|
||||
break
|
||||
|
||||
if env_path is None:
|
||||
if profile is not None:
|
||||
raise FileNotFoundError(
|
||||
f"Profile '{profile}' 的 env 文件未找到。"
|
||||
f"请在当前目录或主目录创建 {filename}"
|
||||
)
|
||||
return
|
||||
|
||||
with open(env_path, encoding="utf-8") as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if not line or line.startswith("#") or "=" not in line:
|
||||
continue
|
||||
key, _, value = line.partition("=")
|
||||
key = key.strip()
|
||||
value = value.strip().strip('"').strip("'")
|
||||
if key and key not in os.environ:
|
||||
os.environ[key] = value
|
||||
|
||||
|
||||
# 下单权限控制:设置 LONGBRIDGE_TRADE_ENABLED=true 才允许 buy/sell/cancel
|
||||
_TRADE_ENV_VAR = "LONGBRIDGE_TRADE_ENABLED"
|
||||
|
||||
|
||||
def is_trade_enabled() -> bool:
|
||||
"""返回是否已开启交易权限(默认关闭,只读模式)"""
|
||||
return os.environ.get(_TRADE_ENV_VAR, "").strip().lower() == "true"
|
||||
|
||||
|
||||
def require_trade_enabled() -> None:
|
||||
"""若未开启交易权限,抛出友好错误并提示配置方式"""
|
||||
if not is_trade_enabled():
|
||||
raise click.ClickException(
|
||||
"当前为只读模式,下单/撤单操作已禁用。\n"
|
||||
f"如需开启交易权限,请设置环境变量:\n"
|
||||
f" export {_TRADE_ENV_VAR}=true\n"
|
||||
"⚠️ 开启后请确保操作正确,下单指令将直接提交至长桥交易系统。"
|
||||
)
|
||||
|
||||
|
||||
def get_config(profile: str | None = None) -> Config:
|
||||
"""从环境变量初始化长桥配置。支持 --profile 切换账户。
|
||||
|
||||
需要设置以下环境变量:
|
||||
LONGBRIDGE_APP_KEY
|
||||
LONGBRIDGE_APP_SECRET
|
||||
LONGBRIDGE_ACCESS_TOKEN
|
||||
"""
|
||||
_load_dotenv_for_profile(profile)
|
||||
try:
|
||||
return Config.from_apikey_env()
|
||||
except Exception as e:
|
||||
raise click.ClickException(
|
||||
"无法初始化长桥配置,请确认已设置以下环境变量:\n"
|
||||
" LONGBRIDGE_APP_KEY\n"
|
||||
" LONGBRIDGE_APP_SECRET\n"
|
||||
" LONGBRIDGE_ACCESS_TOKEN\n"
|
||||
f"错误详情:{e}"
|
||||
)
|
||||
@@ -0,0 +1,56 @@
|
||||
"""统一输出格式模块(text/json)"""
|
||||
import json
|
||||
import sys
|
||||
from decimal import Decimal
|
||||
from typing import Any
|
||||
|
||||
import click
|
||||
from rich.console import Console
|
||||
from rich.table import Table
|
||||
|
||||
console = Console()
|
||||
|
||||
|
||||
class _DecimalEncoder(json.JSONEncoder):
|
||||
"""将 Decimal 序列化为 float"""
|
||||
|
||||
def default(self, obj: Any) -> Any:
|
||||
if isinstance(obj, Decimal):
|
||||
return float(obj)
|
||||
return super().default(obj)
|
||||
|
||||
|
||||
def print_json(data: Any) -> None:
|
||||
"""以 JSON 格式输出数据"""
|
||||
click.echo(json.dumps(data, ensure_ascii=False, indent=2, cls=_DecimalEncoder))
|
||||
|
||||
|
||||
def print_table(headers: list[str], rows: list[list[Any]], title: str = "") -> None:
|
||||
"""用 rich 表格输出数据
|
||||
|
||||
Args:
|
||||
headers: 列标题列表
|
||||
rows: 数据行列表(每行为与 headers 对应的值列表)
|
||||
title: 可选表格标题
|
||||
"""
|
||||
table = Table(title=title, show_header=True, header_style="bold cyan")
|
||||
for h in headers:
|
||||
table.add_column(h, style="white")
|
||||
for row in rows:
|
||||
table.add_row(*[str(v) if v is not None else "-" for v in row])
|
||||
console.print(table)
|
||||
|
||||
|
||||
def print_kv(pairs: list[tuple[str, Any]], title: str = "") -> None:
|
||||
"""以键值对形式输出(用于单条记录)"""
|
||||
if title:
|
||||
console.print(f"[bold cyan]{title}[/bold cyan]")
|
||||
for k, v in pairs:
|
||||
v_str = str(v) if v is not None else "-"
|
||||
console.print(f" [bold]{k}[/bold]: {v_str}")
|
||||
|
||||
|
||||
def print_error(msg: str) -> None:
|
||||
"""输出错误信息到 stderr"""
|
||||
click.echo(f"错误:{msg}", err=True)
|
||||
sys.exit(1)
|
||||
@@ -0,0 +1,8 @@
|
||||
Metadata-Version: 2.4
|
||||
Name: longbridge-cli
|
||||
Version: 1.0.0
|
||||
Summary: 长桥 LongPort OpenAPI CLI 工具
|
||||
Requires-Python: >=3.9
|
||||
Requires-Dist: longbridge
|
||||
Requires-Dist: click>=8.0
|
||||
Requires-Dist: rich>=13.0
|
||||
@@ -0,0 +1,18 @@
|
||||
README.md
|
||||
pyproject.toml
|
||||
longbridge_cli/__init__.py
|
||||
longbridge_cli/__main__.py
|
||||
longbridge_cli/cli.py
|
||||
longbridge_cli/config.py
|
||||
longbridge_cli/formatters.py
|
||||
longbridge_cli.egg-info/PKG-INFO
|
||||
longbridge_cli.egg-info/SOURCES.txt
|
||||
longbridge_cli.egg-info/dependency_links.txt
|
||||
longbridge_cli.egg-info/entry_points.txt
|
||||
longbridge_cli.egg-info/requires.txt
|
||||
longbridge_cli.egg-info/top_level.txt
|
||||
longbridge_cli/commands/__init__.py
|
||||
longbridge_cli/commands/account.py
|
||||
longbridge_cli/commands/market.py
|
||||
longbridge_cli/commands/order.py
|
||||
longbridge_cli/commands/quote.py
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
[console_scripts]
|
||||
longbridge = longbridge_cli.cli:cli
|
||||
@@ -0,0 +1,3 @@
|
||||
longbridge
|
||||
click>=8.0
|
||||
rich>=13.0
|
||||
@@ -0,0 +1 @@
|
||||
longbridge_cli
|
||||
@@ -0,0 +1 @@
|
||||
"""longbridge_cli 包初始化"""
|
||||
@@ -0,0 +1,5 @@
|
||||
"""支持 python -m longbridge_cli 调用"""
|
||||
from longbridge_cli.cli import cli
|
||||
|
||||
if __name__ == "__main__":
|
||||
cli()
|
||||
@@ -0,0 +1,69 @@
|
||||
"""longbridge-cli 根命令组"""
|
||||
import click
|
||||
|
||||
from longbridge_cli.commands.quote import (
|
||||
quote_cmd,
|
||||
depth_cmd,
|
||||
trades_cmd,
|
||||
candlesticks_cmd,
|
||||
info_cmd,
|
||||
)
|
||||
from longbridge_cli.commands.account import balance_cmd, positions_cmd, funds_cmd
|
||||
from longbridge_cli.commands.order import (
|
||||
orders_cmd,
|
||||
history_orders_cmd,
|
||||
buy_cmd,
|
||||
sell_cmd,
|
||||
cancel_cmd,
|
||||
)
|
||||
from longbridge_cli.commands.market import (
|
||||
temperature_cmd,
|
||||
capital_flow_cmd,
|
||||
capital_dist_cmd,
|
||||
option_chain_cmd,
|
||||
)
|
||||
|
||||
|
||||
@click.group()
|
||||
@click.version_option("1.0.0", prog_name="longbridge")
|
||||
@click.option("--profile", default=None, help="账户 profile(如 paper),加载 .{profile}.env 凭证文件")
|
||||
@click.pass_context
|
||||
def cli(ctx, profile):
|
||||
"""长桥 LongPort OpenAPI CLI 工具
|
||||
|
||||
\b
|
||||
行情: quote depth trades candlesticks info
|
||||
账户: balance positions funds
|
||||
订单: orders history-orders buy sell cancel
|
||||
市场: temperature capital-flow capital-dist option-chain
|
||||
|
||||
所有命令支持 --json 输出 JSON 格式。
|
||||
"""
|
||||
ctx.ensure_object(dict)
|
||||
ctx.obj["profile"] = profile
|
||||
|
||||
|
||||
# 行情
|
||||
cli.add_command(quote_cmd, name="quote")
|
||||
cli.add_command(depth_cmd, name="depth")
|
||||
cli.add_command(trades_cmd, name="trades")
|
||||
cli.add_command(candlesticks_cmd, name="candlesticks")
|
||||
cli.add_command(info_cmd, name="info")
|
||||
|
||||
# 账户
|
||||
cli.add_command(balance_cmd, name="balance")
|
||||
cli.add_command(positions_cmd, name="positions")
|
||||
cli.add_command(funds_cmd, name="funds")
|
||||
|
||||
# 订单
|
||||
cli.add_command(orders_cmd, name="orders")
|
||||
cli.add_command(history_orders_cmd, name="history-orders")
|
||||
cli.add_command(buy_cmd, name="buy")
|
||||
cli.add_command(sell_cmd, name="sell")
|
||||
cli.add_command(cancel_cmd, name="cancel")
|
||||
|
||||
# 市场
|
||||
cli.add_command(temperature_cmd, name="temperature")
|
||||
cli.add_command(capital_flow_cmd, name="capital-flow")
|
||||
cli.add_command(capital_dist_cmd, name="capital-dist")
|
||||
cli.add_command(option_chain_cmd, name="option-chain")
|
||||
@@ -0,0 +1,147 @@
|
||||
"""账户与持仓命令模块"""
|
||||
import click
|
||||
from longbridge.openapi import TradeContext
|
||||
|
||||
from longbridge_cli.config import get_config
|
||||
from longbridge_cli.formatters import print_table, print_json, print_error
|
||||
|
||||
|
||||
@click.command("balance")
|
||||
@click.option("--json", "output_json", is_flag=True, help="以 JSON 格式输出")
|
||||
@click.pass_context
|
||||
def balance_cmd(ctx, output_json):
|
||||
"""查看账户余额与净资产
|
||||
|
||||
示例:longbridge balance
|
||||
"""
|
||||
try:
|
||||
trade_ctx = TradeContext(get_config(ctx.obj.get("profile")))
|
||||
resp = trade_ctx.account_balance()
|
||||
except Exception as e:
|
||||
print_error(str(e))
|
||||
|
||||
if output_json:
|
||||
data = [
|
||||
{
|
||||
"currency": b.currency,
|
||||
"total_cash": float(b.total_cash),
|
||||
"max_finance_amount": float(b.max_finance_amount),
|
||||
"remaining_finance_amount": float(b.remaining_finance_amount),
|
||||
"risk_level": b.risk_level,
|
||||
"margin_call": float(b.margin_call),
|
||||
"net_assets": float(b.net_assets),
|
||||
"init_margin": float(b.init_margin),
|
||||
"maintenance_margin": float(b.maintenance_margin),
|
||||
}
|
||||
for b in resp
|
||||
]
|
||||
print_json(data)
|
||||
else:
|
||||
headers = ["币种", "现金余额", "净资产", "最大融资额", "剩余融资额", "风险等级"]
|
||||
rows = [
|
||||
[
|
||||
b.currency,
|
||||
f"{float(b.total_cash):,.2f}",
|
||||
f"{float(b.net_assets):,.2f}",
|
||||
f"{float(b.max_finance_amount):,.2f}",
|
||||
f"{float(b.remaining_finance_amount):,.2f}",
|
||||
str(b.risk_level),
|
||||
]
|
||||
for b in resp
|
||||
]
|
||||
print_table(headers, rows, title="账户余额")
|
||||
|
||||
|
||||
@click.command("positions")
|
||||
@click.option("--json", "output_json", is_flag=True, help="以 JSON 格式输出")
|
||||
@click.pass_context
|
||||
def positions_cmd(ctx, output_json):
|
||||
"""查看股票持仓
|
||||
|
||||
示例:longbridge positions
|
||||
"""
|
||||
try:
|
||||
trade_ctx = TradeContext(get_config(ctx.obj.get("profile")))
|
||||
resp = trade_ctx.stock_positions()
|
||||
except Exception as e:
|
||||
print_error(str(e))
|
||||
|
||||
channels = resp.channels if resp else []
|
||||
|
||||
if output_json:
|
||||
data = []
|
||||
for ch in channels:
|
||||
for p in ch.positions:
|
||||
data.append({
|
||||
"symbol": p.symbol,
|
||||
"symbol_name": p.symbol_name,
|
||||
"quantity": p.quantity,
|
||||
"available_quantity": p.available_quantity,
|
||||
"currency": p.currency,
|
||||
"cost_price": float(p.cost_price),
|
||||
"init_quantity": p.init_quantity,
|
||||
"market": str(p.market),
|
||||
})
|
||||
print_json(data)
|
||||
else:
|
||||
headers = ["标的", "名称", "持仓", "可卖", "成本价", "初始持仓", "市场", "币种"]
|
||||
rows = []
|
||||
for ch in channels:
|
||||
for p in ch.positions:
|
||||
rows.append([
|
||||
p.symbol,
|
||||
p.symbol_name,
|
||||
str(p.quantity),
|
||||
str(p.available_quantity),
|
||||
f"{float(p.cost_price):.3f}",
|
||||
str(p.init_quantity),
|
||||
str(p.market),
|
||||
p.currency,
|
||||
])
|
||||
print_table(headers, rows, title="股票持仓")
|
||||
|
||||
|
||||
@click.command("funds")
|
||||
@click.option("--json", "output_json", is_flag=True, help="以 JSON 格式输出")
|
||||
@click.pass_context
|
||||
def funds_cmd(ctx, output_json):
|
||||
"""查看基金持仓
|
||||
|
||||
示例:longbridge funds
|
||||
"""
|
||||
try:
|
||||
trade_ctx = TradeContext(get_config(ctx.obj.get("profile")))
|
||||
resp = trade_ctx.fund_positions()
|
||||
except Exception as e:
|
||||
print_error(str(e))
|
||||
|
||||
channels = resp.channels if resp else []
|
||||
|
||||
if output_json:
|
||||
data = []
|
||||
for ch in channels:
|
||||
for f in ch.positions:
|
||||
data.append({
|
||||
"symbol": f.symbol,
|
||||
"symbol_name": f.symbol_name,
|
||||
"holding_units": float(f.holding_units),
|
||||
"current_net_asset_value": float(f.current_net_asset_value),
|
||||
"cost_net_asset_value": float(f.cost_net_asset_value),
|
||||
"net_asset_value_day": f.net_asset_value_day.isoformat() if f.net_asset_value_day else None,
|
||||
"market_value": float(f.market_value) if hasattr(f, "market_value") else None,
|
||||
})
|
||||
print_json(data)
|
||||
else:
|
||||
headers = ["基金代码", "名称", "持有份额", "当前净值", "成本净值", "净值日期"]
|
||||
rows = []
|
||||
for ch in channels:
|
||||
for f in ch.positions:
|
||||
rows.append([
|
||||
f.symbol,
|
||||
f.symbol_name,
|
||||
f"{float(f.holding_units):.4f}",
|
||||
f"{float(f.current_net_asset_value):.4f}",
|
||||
f"{float(f.cost_net_asset_value):.4f}",
|
||||
f.net_asset_value_day.strftime("%Y-%m-%d") if f.net_asset_value_day else "-",
|
||||
])
|
||||
print_table(headers, rows, title="基金持仓")
|
||||
@@ -0,0 +1,162 @@
|
||||
"""市场数据命令模块"""
|
||||
import click
|
||||
from longbridge.openapi import QuoteContext, Market
|
||||
|
||||
from longbridge_cli.config import get_config
|
||||
from longbridge_cli.formatters import print_table, print_json, print_kv, print_error
|
||||
|
||||
MARKET_MAP = {
|
||||
"US": Market.US,
|
||||
"HK": Market.HK,
|
||||
"CN": Market.CN,
|
||||
"SG": Market.SG,
|
||||
}
|
||||
|
||||
|
||||
@click.command("temperature")
|
||||
@click.argument("market", type=click.Choice(["US", "HK", "CN", "SG"]))
|
||||
@click.option("--json", "output_json", is_flag=True, help="以 JSON 格式输出")
|
||||
@click.pass_context
|
||||
def temperature_cmd(ctx, market, output_json):
|
||||
"""查看市场温度
|
||||
|
||||
MARKET 可选:US HK CN SG
|
||||
|
||||
示例:longbridge temperature US
|
||||
"""
|
||||
try:
|
||||
quote_ctx = QuoteContext(get_config(ctx.obj.get("profile")))
|
||||
resp = quote_ctx.market_temperature(MARKET_MAP[market])
|
||||
except Exception as e:
|
||||
print_error(str(e))
|
||||
|
||||
if output_json:
|
||||
data = {
|
||||
"market": market,
|
||||
"temperature": resp.temperature,
|
||||
"description": resp.description,
|
||||
"valuation": float(resp.valuation) if hasattr(resp, "valuation") else None,
|
||||
}
|
||||
print_json(data)
|
||||
else:
|
||||
pairs = [
|
||||
("市场", market),
|
||||
("温度", resp.temperature),
|
||||
("描述", resp.description),
|
||||
]
|
||||
if hasattr(resp, "valuation"):
|
||||
pairs.append(("估值", float(resp.valuation)))
|
||||
print_kv(pairs, title=f"市场温度 - {market}")
|
||||
|
||||
|
||||
@click.command("capital-flow")
|
||||
@click.argument("symbol")
|
||||
@click.option("--json", "output_json", is_flag=True, help="以 JSON 格式输出")
|
||||
@click.pass_context
|
||||
def capital_flow_cmd(ctx, symbol, output_json):
|
||||
"""查看资金流向
|
||||
|
||||
示例:longbridge capital-flow 700.HK
|
||||
"""
|
||||
try:
|
||||
quote_ctx = QuoteContext(get_config(ctx.obj.get("profile")))
|
||||
resp = quote_ctx.capital_flow(symbol)
|
||||
except Exception as e:
|
||||
print_error(str(e))
|
||||
|
||||
if output_json:
|
||||
data = [
|
||||
{
|
||||
"timestamp": item.timestamp.isoformat() if item.timestamp else None,
|
||||
"inflow": float(item.inflow),
|
||||
}
|
||||
for item in resp
|
||||
]
|
||||
print_json(data)
|
||||
else:
|
||||
headers = ["时间", "净流入"]
|
||||
rows = [
|
||||
[
|
||||
item.timestamp.strftime("%Y-%m-%d %H:%M") if item.timestamp else "-",
|
||||
f"{float(item.inflow):+,.0f}",
|
||||
]
|
||||
for item in resp
|
||||
]
|
||||
print_table(headers, rows, title=f"资金流向 - {symbol}")
|
||||
|
||||
|
||||
@click.command("capital-dist")
|
||||
@click.argument("symbol")
|
||||
@click.option("--json", "output_json", is_flag=True, help="以 JSON 格式输出")
|
||||
@click.pass_context
|
||||
def capital_dist_cmd(ctx, symbol, output_json):
|
||||
"""查看资金分布
|
||||
|
||||
示例:longbridge capital-dist 700.HK
|
||||
"""
|
||||
try:
|
||||
quote_ctx = QuoteContext(get_config(ctx.obj.get("profile")))
|
||||
resp = quote_ctx.capital_distribution(symbol)
|
||||
except Exception as e:
|
||||
print_error(str(e))
|
||||
|
||||
if output_json:
|
||||
data = {
|
||||
"symbol": symbol,
|
||||
"timestamp": resp.timestamp.isoformat() if resp.timestamp else None,
|
||||
"capital_in": {
|
||||
"large": float(resp.capital_in.large),
|
||||
"medium": float(resp.capital_in.medium),
|
||||
"small": float(resp.capital_in.small),
|
||||
},
|
||||
"capital_out": {
|
||||
"large": float(resp.capital_out.large),
|
||||
"medium": float(resp.capital_out.medium),
|
||||
"small": float(resp.capital_out.small),
|
||||
},
|
||||
}
|
||||
print_json(data)
|
||||
else:
|
||||
headers = ["方向", "大单", "中单", "小单"]
|
||||
rows = [
|
||||
[
|
||||
"流入",
|
||||
f"{float(resp.capital_in.large):,.0f}",
|
||||
f"{float(resp.capital_in.medium):,.0f}",
|
||||
f"{float(resp.capital_in.small):,.0f}",
|
||||
],
|
||||
[
|
||||
"流出",
|
||||
f"{float(resp.capital_out.large):,.0f}",
|
||||
f"{float(resp.capital_out.medium):,.0f}",
|
||||
f"{float(resp.capital_out.small):,.0f}",
|
||||
],
|
||||
]
|
||||
print_table(headers, rows, title=f"资金分布 - {symbol}")
|
||||
|
||||
|
||||
@click.command("option-chain")
|
||||
@click.argument("symbol")
|
||||
@click.option("--json", "output_json", is_flag=True, help="以 JSON 格式输出")
|
||||
@click.pass_context
|
||||
def option_chain_cmd(ctx, symbol, output_json):
|
||||
"""查看期权链到期日列表
|
||||
|
||||
示例:longbridge option-chain AAPL.US
|
||||
"""
|
||||
try:
|
||||
quote_ctx = QuoteContext(get_config(ctx.obj.get("profile")))
|
||||
resp = quote_ctx.option_chain_expiry_date_list(symbol)
|
||||
except Exception as e:
|
||||
print_error(str(e))
|
||||
|
||||
if output_json:
|
||||
data = {
|
||||
"symbol": symbol,
|
||||
"expiry_dates": [d.isoformat() for d in resp],
|
||||
}
|
||||
print_json(data)
|
||||
else:
|
||||
headers = ["序号", "到期日"]
|
||||
rows = [[str(i + 1), d.strftime("%Y-%m-%d")] for i, d in enumerate(resp)]
|
||||
print_table(headers, rows, title=f"期权链到期日 - {symbol}")
|
||||
@@ -0,0 +1,188 @@
|
||||
"""订单管理命令模块"""
|
||||
from datetime import datetime
|
||||
from decimal import Decimal
|
||||
|
||||
import click
|
||||
from longbridge.openapi import (
|
||||
TradeContext,
|
||||
OrderType,
|
||||
OrderSide,
|
||||
TimeInForceType,
|
||||
)
|
||||
|
||||
from longbridge_cli.config import get_config, require_trade_enabled
|
||||
from longbridge_cli.formatters import print_table, print_json, print_error
|
||||
|
||||
|
||||
@click.command("orders")
|
||||
@click.option("--json", "output_json", is_flag=True, help="以 JSON 格式输出")
|
||||
@click.pass_context
|
||||
def orders_cmd(ctx, output_json):
|
||||
"""查看今日订单
|
||||
|
||||
示例:longbridge orders
|
||||
"""
|
||||
try:
|
||||
trade_ctx = TradeContext(get_config(ctx.obj.get("profile")))
|
||||
resp = trade_ctx.today_orders()
|
||||
except Exception as e:
|
||||
print_error(str(e))
|
||||
|
||||
_print_orders(resp, output_json, "今日订单")
|
||||
|
||||
|
||||
@click.command("history-orders")
|
||||
@click.option("--start", required=True, help="开始日期 (YYYY-MM-DD)")
|
||||
@click.option("--end", required=True, help="结束日期 (YYYY-MM-DD)")
|
||||
@click.option("--json", "output_json", is_flag=True, help="以 JSON 格式输出")
|
||||
@click.pass_context
|
||||
def history_orders_cmd(ctx, start, end, output_json):
|
||||
"""查看历史订单
|
||||
|
||||
示例:longbridge history-orders --start 2026-01-01 --end 2026-03-14
|
||||
"""
|
||||
try:
|
||||
start_dt = datetime.strptime(start, "%Y-%m-%d")
|
||||
end_dt = datetime.strptime(end, "%Y-%m-%d")
|
||||
trade_ctx = TradeContext(get_config(ctx.obj.get("profile")))
|
||||
resp = trade_ctx.history_orders(start_at=start_dt, end_at=end_dt)
|
||||
except ValueError:
|
||||
print_error("日期格式错误,请使用 YYYY-MM-DD")
|
||||
return
|
||||
except Exception as e:
|
||||
print_error(str(e))
|
||||
|
||||
_print_orders(resp, output_json, f"历史订单 ({start} ~ {end})")
|
||||
|
||||
|
||||
@click.command("buy")
|
||||
@click.argument("symbol")
|
||||
@click.option("--qty", required=True, type=int, help="买入数量")
|
||||
@click.option("--price", required=True, type=float, help="限价价格")
|
||||
@click.option("--json", "output_json", is_flag=True, help="以 JSON 格式输出")
|
||||
@click.option("--yes", "-y", is_flag=True, help="跳过交互确认(程序化调用时使用)")
|
||||
@click.pass_context
|
||||
def buy_cmd(ctx, symbol, qty, price, output_json, yes):
|
||||
"""限价买入
|
||||
|
||||
示例:longbridge buy AAPL.US --qty 100 --price 180.0
|
||||
"""
|
||||
require_trade_enabled()
|
||||
if not yes:
|
||||
click.confirm(f"确认买入 {symbol} 数量 {qty} 限价 {price}?", abort=True)
|
||||
try:
|
||||
trade_ctx = TradeContext(get_config(ctx.obj.get("profile")))
|
||||
resp = trade_ctx.submit_order(
|
||||
symbol,
|
||||
OrderType.LO,
|
||||
OrderSide.Buy,
|
||||
qty,
|
||||
TimeInForceType.Day,
|
||||
submitted_price=Decimal(str(price)),
|
||||
)
|
||||
except Exception as e:
|
||||
print_error(str(e))
|
||||
return
|
||||
|
||||
if output_json:
|
||||
print_json({"order_id": resp.order_id})
|
||||
else:
|
||||
click.echo(f"下单成功,订单号:{resp.order_id}")
|
||||
|
||||
|
||||
@click.command("sell")
|
||||
@click.argument("symbol")
|
||||
@click.option("--qty", required=True, type=int, help="卖出数量")
|
||||
@click.option("--price", required=True, type=float, help="限价价格")
|
||||
@click.option("--json", "output_json", is_flag=True, help="以 JSON 格式输出")
|
||||
@click.option("--yes", "-y", is_flag=True, help="跳过交互确认(程序化调用时使用)")
|
||||
@click.pass_context
|
||||
def sell_cmd(ctx, symbol, qty, price, output_json, yes):
|
||||
"""限价卖出
|
||||
|
||||
示例:longbridge sell 700.HK --qty 500 --price 320.0
|
||||
"""
|
||||
require_trade_enabled()
|
||||
if not yes:
|
||||
click.confirm(f"确认卖出 {symbol} 数量 {qty} 限价 {price}?", abort=True)
|
||||
try:
|
||||
trade_ctx = TradeContext(get_config(ctx.obj.get("profile")))
|
||||
resp = trade_ctx.submit_order(
|
||||
symbol,
|
||||
OrderType.LO,
|
||||
OrderSide.Sell,
|
||||
qty,
|
||||
TimeInForceType.Day,
|
||||
submitted_price=Decimal(str(price)),
|
||||
)
|
||||
except Exception as e:
|
||||
print_error(str(e))
|
||||
return
|
||||
|
||||
if output_json:
|
||||
print_json({"order_id": resp.order_id})
|
||||
else:
|
||||
click.echo(f"下单成功,订单号:{resp.order_id}")
|
||||
|
||||
|
||||
@click.command("cancel")
|
||||
@click.argument("order_id")
|
||||
@click.option("--json", "output_json", is_flag=True, help="以 JSON 格式输出")
|
||||
@click.pass_context
|
||||
def cancel_cmd(ctx, order_id, output_json):
|
||||
"""撤销订单
|
||||
|
||||
示例:longbridge cancel 701234567890
|
||||
"""
|
||||
require_trade_enabled()
|
||||
click.confirm(f"确认撤销订单 {order_id}?", abort=True)
|
||||
try:
|
||||
trade_ctx = TradeContext(get_config(ctx.obj.get("profile")))
|
||||
trade_ctx.cancel_order(order_id)
|
||||
except Exception as e:
|
||||
print_error(str(e))
|
||||
|
||||
if output_json:
|
||||
print_json({"order_id": order_id, "status": "cancelled"})
|
||||
else:
|
||||
click.echo(f"订单 {order_id} 已撤销")
|
||||
|
||||
|
||||
def _print_orders(orders, output_json: bool, title: str) -> None:
|
||||
"""内部辅助:统一输出订单列表"""
|
||||
if output_json:
|
||||
data = [
|
||||
{
|
||||
"order_id": o.order_id,
|
||||
"symbol": o.symbol,
|
||||
"side": str(o.side),
|
||||
"order_type": str(o.order_type),
|
||||
"quantity": o.quantity,
|
||||
"executed_quantity": o.executed_quantity,
|
||||
"price": float(o.price) if o.price else None,
|
||||
"executed_price": float(o.executed_price) if o.executed_price else None,
|
||||
"status": str(o.status),
|
||||
"submitted_at": o.submitted_at.isoformat() if o.submitted_at else None,
|
||||
"updated_at": o.updated_at.isoformat() if o.updated_at else None,
|
||||
}
|
||||
for o in orders
|
||||
]
|
||||
print_json(data)
|
||||
else:
|
||||
headers = ["订单号", "标的", "方向", "类型", "数量", "已成交", "委托价", "成交价", "状态", "提交时间"]
|
||||
rows = [
|
||||
[
|
||||
o.order_id,
|
||||
o.symbol,
|
||||
str(o.side),
|
||||
str(o.order_type),
|
||||
str(o.quantity),
|
||||
str(o.executed_quantity),
|
||||
f"{float(o.price):.3f}" if o.price else "-",
|
||||
f"{float(o.executed_price):.3f}" if o.executed_price else "-",
|
||||
str(o.status),
|
||||
o.submitted_at.strftime("%Y-%m-%d %H:%M:%S") if o.submitted_at else "-",
|
||||
]
|
||||
for o in orders
|
||||
]
|
||||
print_table(headers, rows, title=title)
|
||||
@@ -0,0 +1,239 @@
|
||||
"""行情命令模块"""
|
||||
import click
|
||||
from longbridge.openapi import QuoteContext, Period, AdjustType
|
||||
|
||||
from longbridge_cli.config import get_config
|
||||
from longbridge_cli.formatters import print_table, print_json, print_error
|
||||
|
||||
PERIOD_MAP = {
|
||||
"1m": Period.Min_1,
|
||||
"5m": Period.Min_5,
|
||||
"15m": Period.Min_15,
|
||||
"30m": Period.Min_30,
|
||||
"60m": Period.Min_60,
|
||||
"day": Period.Day,
|
||||
"week": Period.Week,
|
||||
"month": Period.Month,
|
||||
"quarter": Period.Quarter,
|
||||
"year": Period.Year,
|
||||
}
|
||||
|
||||
|
||||
@click.command("quote")
|
||||
@click.argument("symbols", nargs=-1, required=True)
|
||||
@click.option("--json", "output_json", is_flag=True, help="以 JSON 格式输出")
|
||||
@click.pass_context
|
||||
def quote_cmd(ctx, symbols, output_json):
|
||||
"""获取实时报价(支持多个标的)
|
||||
|
||||
示例:longbridge quote AAPL.US 700.HK
|
||||
"""
|
||||
try:
|
||||
quote_ctx = QuoteContext(get_config(ctx.obj.get("profile")))
|
||||
resp = quote_ctx.quote(list(symbols))
|
||||
except Exception as e:
|
||||
print_error(str(e))
|
||||
|
||||
if output_json:
|
||||
data = [
|
||||
{
|
||||
"symbol": q.symbol,
|
||||
"last_done": float(q.last_done),
|
||||
"open": float(q.open),
|
||||
"high": float(q.high),
|
||||
"low": float(q.low),
|
||||
"volume": q.volume,
|
||||
"turnover": float(q.turnover),
|
||||
"change_rate": round(float(q.last_done / q.prev_close - 1) * 100, 2) if q.prev_close else None,
|
||||
"prev_close": float(q.prev_close),
|
||||
}
|
||||
for q in resp
|
||||
]
|
||||
print_json(data)
|
||||
else:
|
||||
headers = ["标的", "最新价", "涨跌幅", "开盘", "最高", "最低", "成交量", "成交额"]
|
||||
rows = []
|
||||
for q in resp:
|
||||
change_rate = round(float(q.last_done / q.prev_close - 1) * 100, 2) if q.prev_close else "-"
|
||||
change_str = f"{change_rate:+.2f}%" if isinstance(change_rate, float) else change_rate
|
||||
rows.append([
|
||||
q.symbol,
|
||||
f"{float(q.last_done):.3f}",
|
||||
change_str,
|
||||
f"{float(q.open):.3f}",
|
||||
f"{float(q.high):.3f}",
|
||||
f"{float(q.low):.3f}",
|
||||
f"{q.volume:,}",
|
||||
f"{float(q.turnover):,.0f}",
|
||||
])
|
||||
print_table(headers, rows, title="实时报价")
|
||||
|
||||
|
||||
@click.command("depth")
|
||||
@click.argument("symbol")
|
||||
@click.option("--json", "output_json", is_flag=True, help="以 JSON 格式输出")
|
||||
@click.pass_context
|
||||
def depth_cmd(ctx, symbol, output_json):
|
||||
"""查看盘口(买5卖5)
|
||||
|
||||
示例:longbridge depth 700.HK
|
||||
"""
|
||||
try:
|
||||
quote_ctx = QuoteContext(get_config(ctx.obj.get("profile")))
|
||||
resp = quote_ctx.depth(symbol)
|
||||
except Exception as e:
|
||||
print_error(str(e))
|
||||
|
||||
if output_json:
|
||||
data = {
|
||||
"symbol": symbol,
|
||||
"asks": [{"position": a.position, "price": float(a.price), "volume": a.volume} for a in resp.asks],
|
||||
"bids": [{"position": b.position, "price": float(b.price), "volume": b.volume} for b in resp.bids],
|
||||
}
|
||||
print_json(data)
|
||||
else:
|
||||
headers = ["方向", "档位", "价格", "数量"]
|
||||
rows = []
|
||||
for a in reversed(resp.asks):
|
||||
rows.append(["卖", str(a.position), f"{float(a.price):.3f}", f"{a.volume:,}"])
|
||||
for b in resp.bids:
|
||||
rows.append(["买", str(b.position), f"{float(b.price):.3f}", f"{b.volume:,}"])
|
||||
print_table(headers, rows, title=f"盘口 - {symbol}")
|
||||
|
||||
|
||||
@click.command("trades")
|
||||
@click.argument("symbol")
|
||||
@click.option("--count", default=20, show_default=True, help="返回条数(最多 1000)")
|
||||
@click.option("--json", "output_json", is_flag=True, help="以 JSON 格式输出")
|
||||
@click.pass_context
|
||||
def trades_cmd(ctx, symbol, count, output_json):
|
||||
"""查看最近逐笔成交
|
||||
|
||||
示例:longbridge trades 700.HK --count 20
|
||||
"""
|
||||
try:
|
||||
quote_ctx = QuoteContext(get_config(ctx.obj.get("profile")))
|
||||
resp = quote_ctx.trades(symbol, count)
|
||||
except Exception as e:
|
||||
print_error(str(e))
|
||||
|
||||
if output_json:
|
||||
data = [
|
||||
{
|
||||
"price": float(t.price),
|
||||
"volume": t.volume,
|
||||
"timestamp": t.timestamp.isoformat() if t.timestamp else None,
|
||||
"direction": str(t.trade_type),
|
||||
}
|
||||
for t in resp
|
||||
]
|
||||
print_json(data)
|
||||
else:
|
||||
headers = ["时间", "价格", "数量", "类型"]
|
||||
rows = [
|
||||
[
|
||||
t.timestamp.strftime("%H:%M:%S") if t.timestamp else "-",
|
||||
f"{float(t.price):.3f}",
|
||||
f"{t.volume:,}",
|
||||
str(t.trade_type),
|
||||
]
|
||||
for t in resp
|
||||
]
|
||||
print_table(headers, rows, title=f"逐笔成交 - {symbol}")
|
||||
|
||||
|
||||
@click.command("candlesticks")
|
||||
@click.argument("symbol")
|
||||
@click.argument("period", type=click.Choice(list(PERIOD_MAP.keys())))
|
||||
@click.option("--count", default=30, show_default=True, help="返回K线条数(最多 1000)")
|
||||
@click.option("--json", "output_json", is_flag=True, help="以 JSON 格式输出")
|
||||
@click.pass_context
|
||||
def candlesticks_cmd(ctx, symbol, period, count, output_json):
|
||||
"""查看 K 线数据
|
||||
|
||||
PERIOD 可选:1m 5m 15m 30m 60m day week month quarter year
|
||||
|
||||
示例:longbridge candlesticks AAPL.US day --count 30
|
||||
"""
|
||||
try:
|
||||
quote_ctx = QuoteContext(get_config(ctx.obj.get("profile")))
|
||||
resp = quote_ctx.candlesticks(symbol, PERIOD_MAP[period], count, AdjustType.NoAdjust)
|
||||
except Exception as e:
|
||||
print_error(str(e))
|
||||
|
||||
if output_json:
|
||||
data = [
|
||||
{
|
||||
"timestamp": c.timestamp.isoformat() if c.timestamp else None,
|
||||
"open": float(c.open),
|
||||
"high": float(c.high),
|
||||
"low": float(c.low),
|
||||
"close": float(c.close),
|
||||
"volume": c.volume,
|
||||
"turnover": float(c.turnover),
|
||||
}
|
||||
for c in resp
|
||||
]
|
||||
print_json(data)
|
||||
else:
|
||||
headers = ["时间", "开盘", "最高", "最低", "收盘", "成交量"]
|
||||
rows = [
|
||||
[
|
||||
c.timestamp.strftime("%Y-%m-%d %H:%M") if c.timestamp else "-",
|
||||
f"{float(c.open):.3f}",
|
||||
f"{float(c.high):.3f}",
|
||||
f"{float(c.low):.3f}",
|
||||
f"{float(c.close):.3f}",
|
||||
f"{c.volume:,}",
|
||||
]
|
||||
for c in resp
|
||||
]
|
||||
print_table(headers, rows, title=f"K线 - {symbol} ({period})")
|
||||
|
||||
|
||||
@click.command("info")
|
||||
@click.argument("symbols", nargs=-1, required=True)
|
||||
@click.option("--json", "output_json", is_flag=True, help="以 JSON 格式输出")
|
||||
@click.pass_context
|
||||
def info_cmd(ctx, symbols, output_json):
|
||||
"""查看标的静态基本信息(名称、交易所、类型等)
|
||||
|
||||
示例:longbridge info 700.HK AAPL.US
|
||||
"""
|
||||
try:
|
||||
quote_ctx = QuoteContext(get_config(ctx.obj.get("profile")))
|
||||
resp = quote_ctx.static_info(list(symbols))
|
||||
except Exception as e:
|
||||
print_error(str(e))
|
||||
|
||||
if output_json:
|
||||
data = [
|
||||
{
|
||||
"symbol": s.symbol,
|
||||
"name_cn": s.name_cn,
|
||||
"name_en": s.name_en,
|
||||
"exchange": s.exchange,
|
||||
"currency": s.currency,
|
||||
"lot_size": s.lot_size,
|
||||
"total_shares": s.total_shares,
|
||||
"circulating_shares": s.circulating_shares,
|
||||
"board": str(s.board),
|
||||
}
|
||||
for s in resp
|
||||
]
|
||||
print_json(data)
|
||||
else:
|
||||
headers = ["标的", "中文名", "英文名", "交易所", "币种", "手数", "板块"]
|
||||
rows = [
|
||||
[
|
||||
s.symbol,
|
||||
s.name_cn,
|
||||
s.name_en,
|
||||
s.exchange,
|
||||
s.currency,
|
||||
str(s.lot_size),
|
||||
str(s.board),
|
||||
]
|
||||
for s in resp
|
||||
]
|
||||
print_table(headers, rows, title="标的信息")
|
||||
@@ -0,0 +1,87 @@
|
||||
"""长桥 OpenAPI 配置初始化"""
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
import click
|
||||
from longbridge.openapi import Config
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# .env 加载(CLI 包自包含,不依赖 trader 包)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def _load_dotenv_for_profile(profile: str | None = None) -> None:
|
||||
"""Load .env (or .{profile}.env) into os.environ.
|
||||
|
||||
查找顺序: cwd → home dir。
|
||||
profile=None + 文件不存在 → 静默跳过(向后兼容)。
|
||||
profile 非空 + 文件不存在 → 抛 FileNotFoundError。
|
||||
已存在的环境变量不会被覆盖。
|
||||
"""
|
||||
filename = f".{profile}.env" if profile else ".env"
|
||||
env_path: Path | None = None
|
||||
for base in [Path.cwd(), Path.home()]:
|
||||
candidate = base / filename
|
||||
if candidate.is_file():
|
||||
env_path = candidate
|
||||
break
|
||||
|
||||
if env_path is None:
|
||||
if profile is not None:
|
||||
raise FileNotFoundError(
|
||||
f"Profile '{profile}' 的 env 文件未找到。"
|
||||
f"请在当前目录或主目录创建 {filename}"
|
||||
)
|
||||
return
|
||||
|
||||
with open(env_path, encoding="utf-8") as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if not line or line.startswith("#") or "=" not in line:
|
||||
continue
|
||||
key, _, value = line.partition("=")
|
||||
key = key.strip()
|
||||
value = value.strip().strip('"').strip("'")
|
||||
if key and key not in os.environ:
|
||||
os.environ[key] = value
|
||||
|
||||
|
||||
# 下单权限控制:设置 LONGBRIDGE_TRADE_ENABLED=true 才允许 buy/sell/cancel
|
||||
_TRADE_ENV_VAR = "LONGBRIDGE_TRADE_ENABLED"
|
||||
|
||||
|
||||
def is_trade_enabled() -> bool:
|
||||
"""返回是否已开启交易权限(默认关闭,只读模式)"""
|
||||
return os.environ.get(_TRADE_ENV_VAR, "").strip().lower() == "true"
|
||||
|
||||
|
||||
def require_trade_enabled() -> None:
|
||||
"""若未开启交易权限,抛出友好错误并提示配置方式"""
|
||||
if not is_trade_enabled():
|
||||
raise click.ClickException(
|
||||
"当前为只读模式,下单/撤单操作已禁用。\n"
|
||||
f"如需开启交易权限,请设置环境变量:\n"
|
||||
f" export {_TRADE_ENV_VAR}=true\n"
|
||||
"⚠️ 开启后请确保操作正确,下单指令将直接提交至长桥交易系统。"
|
||||
)
|
||||
|
||||
|
||||
def get_config(profile: str | None = None) -> Config:
|
||||
"""从环境变量初始化长桥配置。支持 --profile 切换账户。
|
||||
|
||||
需要设置以下环境变量:
|
||||
LONGBRIDGE_APP_KEY
|
||||
LONGBRIDGE_APP_SECRET
|
||||
LONGBRIDGE_ACCESS_TOKEN
|
||||
"""
|
||||
_load_dotenv_for_profile(profile)
|
||||
try:
|
||||
return Config.from_apikey_env()
|
||||
except Exception as e:
|
||||
raise click.ClickException(
|
||||
"无法初始化长桥配置,请确认已设置以下环境变量:\n"
|
||||
" LONGBRIDGE_APP_KEY\n"
|
||||
" LONGBRIDGE_APP_SECRET\n"
|
||||
" LONGBRIDGE_ACCESS_TOKEN\n"
|
||||
f"错误详情:{e}"
|
||||
)
|
||||
@@ -0,0 +1,56 @@
|
||||
"""统一输出格式模块(text/json)"""
|
||||
import json
|
||||
import sys
|
||||
from decimal import Decimal
|
||||
from typing import Any
|
||||
|
||||
import click
|
||||
from rich.console import Console
|
||||
from rich.table import Table
|
||||
|
||||
console = Console()
|
||||
|
||||
|
||||
class _DecimalEncoder(json.JSONEncoder):
|
||||
"""将 Decimal 序列化为 float"""
|
||||
|
||||
def default(self, obj: Any) -> Any:
|
||||
if isinstance(obj, Decimal):
|
||||
return float(obj)
|
||||
return super().default(obj)
|
||||
|
||||
|
||||
def print_json(data: Any) -> None:
|
||||
"""以 JSON 格式输出数据"""
|
||||
click.echo(json.dumps(data, ensure_ascii=False, indent=2, cls=_DecimalEncoder))
|
||||
|
||||
|
||||
def print_table(headers: list[str], rows: list[list[Any]], title: str = "") -> None:
|
||||
"""用 rich 表格输出数据
|
||||
|
||||
Args:
|
||||
headers: 列标题列表
|
||||
rows: 数据行列表(每行为与 headers 对应的值列表)
|
||||
title: 可选表格标题
|
||||
"""
|
||||
table = Table(title=title, show_header=True, header_style="bold cyan")
|
||||
for h in headers:
|
||||
table.add_column(h, style="white")
|
||||
for row in rows:
|
||||
table.add_row(*[str(v) if v is not None else "-" for v in row])
|
||||
console.print(table)
|
||||
|
||||
|
||||
def print_kv(pairs: list[tuple[str, Any]], title: str = "") -> None:
|
||||
"""以键值对形式输出(用于单条记录)"""
|
||||
if title:
|
||||
console.print(f"[bold cyan]{title}[/bold cyan]")
|
||||
for k, v in pairs:
|
||||
v_str = str(v) if v is not None else "-"
|
||||
console.print(f" [bold]{k}[/bold]: {v_str}")
|
||||
|
||||
|
||||
def print_error(msg: str) -> None:
|
||||
"""输出错误信息到 stderr"""
|
||||
click.echo(f"错误:{msg}", err=True)
|
||||
sys.exit(1)
|
||||
@@ -0,0 +1,21 @@
|
||||
[build-system]
|
||||
requires = ["setuptools>=42", "wheel"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "longbridge-cli"
|
||||
version = "1.0.0"
|
||||
description = "长桥 LongPort OpenAPI CLI 工具"
|
||||
requires-python = ">=3.9"
|
||||
dependencies = [
|
||||
"longbridge",
|
||||
"click>=8.0",
|
||||
"rich>=13.0",
|
||||
]
|
||||
|
||||
[project.scripts]
|
||||
longbridge = "longbridge_cli.cli:cli"
|
||||
|
||||
[tool.setuptools.packages.find]
|
||||
where = ["."]
|
||||
include = ["longbridge_cli*"]
|
||||
@@ -0,0 +1,3 @@
|
||||
longbridge
|
||||
click>=8.0
|
||||
rich>=13.0
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"version": 1,
|
||||
"registry": "https://clawhub.ai",
|
||||
"slug": "multi-search-engine",
|
||||
"installedVersion": "2.1.3",
|
||||
"installedAt": 1777467938642
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
# Changelog
|
||||
|
||||
## v2.1.0 (2026-04-11)
|
||||
- Version bump to 2.1.0
|
||||
|
||||
## v2.0.1 (2026-02-06)
|
||||
- Simplified documentation
|
||||
- Removed gov-related content
|
||||
- Optimized for ClawHub publishing
|
||||
|
||||
## v2.0.0 (2026-02-06)
|
||||
- Added 9 international search engines
|
||||
- Enhanced advanced search capabilities
|
||||
- Added DuckDuckGo Bangs support
|
||||
- Added WolframAlpha knowledge queries
|
||||
|
||||
## v1.0.0 (2026-02-04)
|
||||
- Initial release with 8 domestic search engines
|
||||
@@ -0,0 +1,48 @@
|
||||
# Multi Search Engine
|
||||
|
||||
## 基本信息
|
||||
|
||||
- **名称**: multi-search-engine
|
||||
- **版本**: v2.0.1
|
||||
- **描述**: 集成16个搜索引擎(7国内+9国际),支持高级搜索语法
|
||||
- **发布时间**: 2026-02-06
|
||||
|
||||
## 搜索引擎
|
||||
|
||||
**国内(7个)**: 百度、必应CN、必应INT、360、搜狗、微信、神马
|
||||
**国际(9个)**: Google、Google HK、DuckDuckGo、Yahoo、Startpage、Brave、Ecosia、Qwant、WolframAlpha
|
||||
|
||||
## 核心功能
|
||||
|
||||
- 高级搜索操作符(site:, filetype:, intitle:等)
|
||||
- DuckDuckGo Bangs快捷命令
|
||||
- 时间筛选(小时/天/周/月/年)
|
||||
- 隐私保护搜索
|
||||
- WolframAlpha知识计算
|
||||
|
||||
## 更新记录
|
||||
|
||||
### v2.0.1 (2026-02-06)
|
||||
- 精简文档,优化发布
|
||||
|
||||
### v2.0.0 (2026-02-06)
|
||||
- 新增9个国际搜索引擎
|
||||
- 强化深度搜索能力
|
||||
|
||||
### v1.0.0 (2026-02-04)
|
||||
- 初始版本:8个国内搜索引擎
|
||||
|
||||
## 使用示例
|
||||
|
||||
```javascript
|
||||
// Google搜索
|
||||
web_fetch({"url": "https://www.google.com/search?q=python"})
|
||||
|
||||
// 隐私搜索
|
||||
web_fetch({"url": "https://duckduckgo.com/html/?q=privacy"})
|
||||
|
||||
// 站内搜索
|
||||
web_fetch({"url": "https://www.google.com/search?q=site:github.com+python"})
|
||||
```
|
||||
|
||||
MIT License
|
||||
@@ -0,0 +1,154 @@
|
||||
---
|
||||
name: "multi-search-engine"
|
||||
description: "Multi search engine integration with 16 engines (7 CN + 9 Global). Supports advanced search operators, time filters, site search, privacy engines, and WolframAlpha knowledge queries. No API keys required."
|
||||
---
|
||||
|
||||
# Multi Search Engine
|
||||
|
||||
Integration of 16 search engines for web crawling without API keys.
|
||||
|
||||
## Workflow
|
||||
|
||||
1. **Preparation**: AI Agent initializes an empty in-memory cookie store. Cookies are only acquired dynamically during search operations when access is denied
|
||||
|
||||
2. **Language Evaluation**: Detect the language attribute of the search query. If the query is in Chinese, use Domestic search engines (Baidu, Bing CN, Bing INT, 360, Sogou, WeChat, Shenma). If the query is non-Chinese, use International search engines (Google, Google HK, DuckDuckGo, Yahoo, Startpage, Brave, Ecosia, Qwant, WolframAlpha). Select engines based on query relevance and availability.
|
||||
|
||||
3. **Controlled Search**: Use web_fetch to execute search requests with rate limiting:
|
||||
- Add 1-2 second delay between requests to respect server load
|
||||
- Batch requests in groups of 3-4 engines with sequential execution between batches
|
||||
- Include standard browser headers to identify as legitimate user agent
|
||||
- If access is denied (403/429), fetch engine homepage to obtain fresh session cookies
|
||||
|
||||
4. **Cookie Management**:
|
||||
- Cookies are stored ONLY in memory during runtime
|
||||
- Cookies are acquired on-demand when search requests fail
|
||||
- No cookies are read from or written to config.json or any file
|
||||
- Cookies are cleared after search session completes
|
||||
- Only session cookies from search engine domains are captured
|
||||
|
||||
5. **Retry Mechanism**: If a search fails due to cookie/session issues, retry once with freshly acquired cookies after a 2-second delay
|
||||
|
||||
6. **Result Aggregation**: Consolidate successful results from search engines, organize and summarize them to output a core search report
|
||||
|
||||
## Search Engines
|
||||
|
||||
### Domestic (7)
|
||||
- **Baidu**: `https://www.baidu.com/s?wd={keyword}`
|
||||
- **Bing CN**: `https://cn.bing.com/search?q={keyword}&ensearch=0`
|
||||
- **Bing INT**: `https://cn.bing.com/search?q={keyword}&ensearch=1`
|
||||
- **360**: `https://www.so.com/s?q={keyword}`
|
||||
- **Sogou**: `https://sogou.com/web?query={keyword}`
|
||||
- **WeChat**: `https://wx.sogou.com/weixin?type=2&query={keyword}`
|
||||
- **Shenma**: `https://m.sm.cn/s?q={keyword}`
|
||||
|
||||
### International (9)
|
||||
- **Google**: `https://www.google.com/search?q={keyword}`
|
||||
- **Google HK**: `https://www.google.com.hk/search?q={keyword}`
|
||||
- **DuckDuckGo**: `https://duckduckgo.com/html/?q={keyword}`
|
||||
- **Yahoo**: `https://search.yahoo.com/search?p={keyword}`
|
||||
- **Startpage**: `https://www.startpage.com/sp/search?query={keyword}`
|
||||
- **Brave**: `https://search.brave.com/search?q={keyword}`
|
||||
- **Ecosia**: `https://www.ecosia.org/search?q={keyword}`
|
||||
- **Qwant**: `https://www.qwant.com/?q={keyword}`
|
||||
- **WolframAlpha**: `https://www.wolframalpha.com/input?i={keyword}`
|
||||
|
||||
## Quick Examples
|
||||
|
||||
```javascript
|
||||
// Basic search
|
||||
web_fetch({"url": "https://www.google.com/search?q=python+tutorial"})
|
||||
|
||||
// Site-specific
|
||||
web_fetch({"url": "https://www.google.com/search?q=site:github.com+react"})
|
||||
|
||||
// File type
|
||||
web_fetch({"url": "https://www.google.com/search?q=machine+learning+filetype:pdf"})
|
||||
|
||||
// Time filter (past week)
|
||||
web_fetch({"url": "https://www.google.com/search?q=ai+news&tbs=qdr:w"})
|
||||
|
||||
// Privacy search
|
||||
web_fetch({"url": "https://duckduckgo.com/html/?q=privacy+tools"})
|
||||
|
||||
// DuckDuckGo Bangs
|
||||
web_fetch({"url": "https://duckduckgo.com/html/?q=!gh+tensorflow"})
|
||||
|
||||
// Knowledge calculation
|
||||
web_fetch({"url": "https://www.wolframalpha.com/input?i=100+USD+to+CNY"})
|
||||
```
|
||||
|
||||
## Advanced Operators
|
||||
|
||||
| Operator | Example | Description |
|
||||
|----------|---------|-------------|
|
||||
| `site:` | `site:github.com python` | Search within site |
|
||||
| `filetype:` | `filetype:pdf report` | Specific file type |
|
||||
| `""` | `"machine learning"` | Exact match |
|
||||
| `-` | `python -snake` | Exclude term |
|
||||
| `OR` | `cat OR dog` | Either term |
|
||||
|
||||
## Time Filters
|
||||
|
||||
| Parameter | Description |
|
||||
|-----------|-------------|
|
||||
| `tbs=qdr:h` | Past hour |
|
||||
| `tbs=qdr:d` | Past day |
|
||||
| `tbs=qdr:w` | Past week |
|
||||
| `tbs=qdr:m` | Past month |
|
||||
| `tbs=qdr:y` | Past year |
|
||||
|
||||
## Privacy Engines
|
||||
|
||||
- **DuckDuckGo**: No tracking
|
||||
- **Startpage**: Google results + privacy
|
||||
- **Brave**: Independent index
|
||||
- **Qwant**: EU GDPR compliant
|
||||
|
||||
## Bangs Shortcuts (DuckDuckGo)
|
||||
|
||||
| Bang | Destination |
|
||||
|------|-------------|
|
||||
| `!g` | Google |
|
||||
| `!gh` | GitHub |
|
||||
| `!so` | Stack Overflow |
|
||||
| `!w` | Wikipedia |
|
||||
| `!yt` | YouTube |
|
||||
|
||||
## WolframAlpha Queries
|
||||
|
||||
- Math: `integrate x^2 dx`
|
||||
- Conversion: `100 USD to CNY`
|
||||
- Stocks: `AAPL stock`
|
||||
- Weather: `weather in Beijing`
|
||||
|
||||
## Documentation
|
||||
|
||||
- `references/advanced-search.md` - Domestic search guide
|
||||
- `references/international-search.md` - International search guide
|
||||
- `CHANGELOG.md` - Version history
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
|
||||
## Security & Privacy Notice
|
||||
|
||||
### Cookie Handling
|
||||
- **Purpose**: Cookies are used ONLY to maintain search session state when access is denied (403/429 errors)
|
||||
- **Storage**: Cookies are kept STRICTLY in memory during runtime - NEVER persisted to disk or config files
|
||||
- **Acquisition**: Cookies are acquired on-demand from search engine homepages only when search requests fail
|
||||
- **Scope**: Only session cookies from the specific search engine domain are captured
|
||||
- **Lifecycle**: Cookies are cleared immediately after the search session completes
|
||||
- **No Pre-configuration**: No cookies are loaded from config.json or any external file at startup
|
||||
- **No API Keys**: This tool uses standard web search URLs, no authentication required
|
||||
|
||||
### Crawling Ethics
|
||||
- **Rate Limiting**: Implement reasonable delays between requests (recommend 1-2 seconds)
|
||||
- **Respect robots.txt**: Honor search engine crawling policies
|
||||
- **Terms of Service**: Users are responsible for complying with search engine ToS
|
||||
- **Purpose**: Designed for legitimate search aggregation, not mass data scraping
|
||||
|
||||
### Data Handling
|
||||
- **No Personal Data**: Tool does not collect or transmit user personal information
|
||||
- **Local Execution**: All operations run locally, no external data transmission
|
||||
- **Session Isolation**: Cookies are session-specific and cleared after use
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"ownerId": "kn79j8kk7fb9w10jh83803j7f180a44m",
|
||||
"slug": "multi-search-engine",
|
||||
"version": "2.1.3",
|
||||
"publishedAt": 1775879953831
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
{
|
||||
"name": "multi-search-engine",
|
||||
"engines": [
|
||||
{
|
||||
"name": "Baidu",
|
||||
"url": "https://www.baidu.com/s?wd={keyword}",
|
||||
"region": "cn"
|
||||
},
|
||||
{
|
||||
"name": "Bing CN",
|
||||
"url": "https://cn.bing.com/search?q={keyword}&ensearch=0",
|
||||
"region": "cn"
|
||||
},
|
||||
{
|
||||
"name": "Bing INT",
|
||||
"url": "https://cn.bing.com/search?q={keyword}&ensearch=1",
|
||||
"region": "cn"
|
||||
},
|
||||
{
|
||||
"name": "360",
|
||||
"url": "https://www.so.com/s?q={keyword}",
|
||||
"region": "cn"
|
||||
},
|
||||
{
|
||||
"name": "Sogou",
|
||||
"url": "https://sogou.com/web?query={keyword}",
|
||||
"region": "cn"
|
||||
},
|
||||
{
|
||||
"name": "WeChat",
|
||||
"url": "https://wx.sogou.com/weixin?type=2&query={keyword}",
|
||||
"region": "cn"
|
||||
},
|
||||
{
|
||||
"name": "Shenma",
|
||||
"url": "https://m.sm.cn/s?q={keyword}",
|
||||
"region": "cn"
|
||||
},
|
||||
{
|
||||
"name": "Google",
|
||||
"url": "https://www.google.com/search?q={keyword}",
|
||||
"region": "global"
|
||||
},
|
||||
{
|
||||
"name": "Google HK",
|
||||
"url": "https://www.google.com.hk/search?q={keyword}",
|
||||
"region": "global"
|
||||
},
|
||||
{
|
||||
"name": "DuckDuckGo",
|
||||
"url": "https://duckduckgo.com/html/?q={keyword}",
|
||||
"region": "global"
|
||||
},
|
||||
{
|
||||
"name": "Yahoo",
|
||||
"url": "https://search.yahoo.com/search?p={keyword}",
|
||||
"region": "global"
|
||||
},
|
||||
{
|
||||
"name": "Startpage",
|
||||
"url": "https://www.startpage.com/sp/search?query={keyword}",
|
||||
"region": "global"
|
||||
},
|
||||
{
|
||||
"name": "Brave",
|
||||
"url": "https://search.brave.com/search?q={keyword}",
|
||||
"region": "global"
|
||||
},
|
||||
{
|
||||
"name": "Ecosia",
|
||||
"url": "https://www.ecosia.org/search?q={keyword}",
|
||||
"region": "global"
|
||||
},
|
||||
{
|
||||
"name": "Qwant",
|
||||
"url": "https://www.qwant.com/?q={keyword}",
|
||||
"region": "global"
|
||||
},
|
||||
{
|
||||
"name": "WolframAlpha",
|
||||
"url": "https://www.wolframalpha.com/input?i={keyword}",
|
||||
"region": "global"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "multi-search-engine",
|
||||
"version": "2.1.0",
|
||||
"description": "Multi search engine with 16 engines (7 CN + 9 Global). Supports advanced operators, time filters, privacy engines.",
|
||||
"engines": 16,
|
||||
"requires_api_key": false
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
# 国内搜索引擎深度搜索指南
|
||||
|
||||
## 🔍 百度 (Baidu)
|
||||
|
||||
### 特色功能
|
||||
|
||||
| 功能 | 说明 | URL |
|
||||
|------|------|-----|
|
||||
| **中文优化** | 中文内容索引最全 | `https://www.baidu.com/s?wd={keyword}` |
|
||||
| **百度学术** | 学术资源搜索 | `https://xueshu.baidu.com/s?wd={keyword}` |
|
||||
| **百度新闻** | 新闻聚合 | `https://news.baidu.com/` |
|
||||
|
||||
### 搜索示例
|
||||
|
||||
```javascript
|
||||
// 1. 基础搜索
|
||||
web_fetch({"url": "https://www.baidu.com/s?wd=Python教程"})
|
||||
|
||||
// 2. 站内搜索
|
||||
web_fetch({"url": "https://www.baidu.com/s?wd=site:github.com+python"})
|
||||
|
||||
// 3. 文件类型搜索
|
||||
web_fetch({"url": "https://www.baidu.com/s?wd=机器学习+filetype:pdf"})
|
||||
|
||||
// 4. 学术搜索
|
||||
web_fetch({"url": "https://xueshu.baidu.com/s?wd=深度学习+图像识别"})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔎 必应中国版 (Bing CN/INT)
|
||||
|
||||
### 特色功能
|
||||
|
||||
| 功能 | 说明 | URL |
|
||||
|------|------|-----|
|
||||
| **中文优化** | `ensearch=0` 中文结果 | `https://cn.bing.com/search?q={keyword}&ensearch=0` |
|
||||
| **国际版** | `ensearch=1` 英文结果 | `https://cn.bing.com/search?q={keyword}&ensearch=1` |
|
||||
| **学术搜索** | 学术资源 | `https://cn.bing.com/academic/search?q={keyword}` |
|
||||
|
||||
### 搜索示例
|
||||
|
||||
```javascript
|
||||
// 1. 中文搜索结果
|
||||
web_fetch({"url": "https://cn.bing.com/search?q=人工智能技术&ensearch=0"})
|
||||
|
||||
// 2. 英文搜索结果(使用中国服务器)
|
||||
web_fetch({"url": "https://cn.bing.com/search?q=artificial+intelligence&ensearch=1"})
|
||||
|
||||
// 3. 学术搜索
|
||||
web_fetch({"url": "https://cn.bing.com/academic/search?q=机器学习算法"})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔍 360搜索
|
||||
|
||||
### 特色功能
|
||||
|
||||
| 功能 | 说明 | URL |
|
||||
|------|------|-----|
|
||||
| **安全搜索** | 内置安全防护 | 默认开启 |
|
||||
| **基础搜索** | 网页搜索 | `https://www.so.com/s?q={keyword}` |
|
||||
|
||||
### 搜索示例
|
||||
|
||||
```javascript
|
||||
// 1. 基础搜索
|
||||
web_fetch({"url": "https://www.so.com/s?q=网络安全"})
|
||||
|
||||
// 2. 站内搜索
|
||||
web_fetch({"url": "https://www.so.com/s?q=site:zhihu.com+python"})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔍 搜狗 (Sogou) + 微信搜索
|
||||
|
||||
### 特色功能
|
||||
|
||||
| 功能 | 说明 | URL |
|
||||
|------|------|-----|
|
||||
| **网页搜索** | 通用搜索 | `https://sogou.com/web?query={keyword}` |
|
||||
| **微信公众号** | 搜公众号文章(唯一渠道) | `https://wx.sogou.com/weixin?type=2&query={keyword}` |
|
||||
| **知乎优化** | 知乎内容索引好 | `site:zhihu.com` 配合使用 |
|
||||
|
||||
### 搜索示例
|
||||
|
||||
```javascript
|
||||
// 1. 网页搜索
|
||||
web_fetch({"url": "https://sogou.com/web?query=python教程"})
|
||||
|
||||
// 2. 微信公众号文章搜索
|
||||
web_fetch({"url": "https://wx.sogou.com/weixin?type=2&query=Python编程"})
|
||||
|
||||
// 3. 搜索特定公众号
|
||||
web_fetch({"url": "https://wx.sogou.com/weixin?type=2&query=公众号:机器之心"})
|
||||
|
||||
// 4. 知乎内容搜索
|
||||
web_fetch({"url": "https://www.sogou.com/web?query=site:zhihu.com+机器学习"})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📱 神马搜索 (Shenma)
|
||||
|
||||
### 特色功能
|
||||
|
||||
| 功能 | 说明 | URL |
|
||||
|------|------|-----|
|
||||
| **移动优化** | 专注移动端搜索 | `https://m.sm.cn/s?q={keyword}` |
|
||||
| **阿里生态** | 整合阿里系内容 | UC浏览器默认搜索 |
|
||||
|
||||
### 搜索示例
|
||||
|
||||
```javascript
|
||||
// 1. 移动端搜索
|
||||
web_fetch({"url": "https://m.sm.cn/s?q=python入门教程"})
|
||||
|
||||
// 2. 移动网站点搜索
|
||||
web_fetch({"url": "https://m.sm.cn/s?q=site:zhuanlan.zhihu.com+AI"})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🌍 国内搜索策略
|
||||
|
||||
### 按搜索目标选择引擎
|
||||
|
||||
| 搜索目标 | 首选引擎 | 原因 |
|
||||
|---------|---------|------|
|
||||
| **综合中文内容** | 百度 | 中文索引最全 |
|
||||
| **微信公众号** | 搜狗微信 | 唯一支持公众号搜索 |
|
||||
| **知乎内容** | 搜狗 | 知乎优化好 |
|
||||
| **移动端内容** | 神马 | 移动端优化 |
|
||||
| **学术资源** | 必应学术 | 学术索引 |
|
||||
| **中英文双语** | 必应中国/国际版 | enswitch切换 |
|
||||
| **新闻资讯** | 百度新闻 | 新闻聚合 |
|
||||
|
||||
---
|
||||
|
||||
## 📚 参考资料
|
||||
|
||||
- [百度搜索高级语法](https://baike.baidu.com/item/搜索语法)
|
||||
- [必应搜索技巧](https://cn.bing.com/tips)
|
||||
- [搜狗搜索帮助](https://help.sogou.com/)
|
||||
@@ -0,0 +1,398 @@
|
||||
# 国际搜索引擎深度搜索指南
|
||||
|
||||
## 🔍 Google 深度搜索
|
||||
|
||||
### 1.1 基础高级搜索操作符
|
||||
|
||||
| 操作符 | 功能 | 示例 | URL |
|
||||
|--------|------|------|-----|
|
||||
| `""` | 精确匹配 | `"machine learning"` | `https://www.google.com/search?q=%22machine+learning%22` |
|
||||
| `-` | 排除关键词 | `python -snake` | `https://www.google.com/search?q=python+-snake` |
|
||||
| `OR` | 或运算 | `machine learning OR deep learning` | `https://www.google.com/search?q=machine+learning+OR+deep+learning` |
|
||||
| `*` | 通配符 | `machine * algorithms` | `https://www.google.com/search?q=machine+*+algorithms` |
|
||||
| `()` | 分组 | `(apple OR microsoft) phones` | `https://www.google.com/search?q=(apple+OR+microsoft)+phones` |
|
||||
| `..` | 数字范围 | `laptop $500..$1000` | `https://www.google.com/search?q=laptop+%24500..%241000` |
|
||||
|
||||
### 1.2 站点与文件搜索
|
||||
|
||||
| 操作符 | 功能 | 示例 |
|
||||
|--------|------|------|
|
||||
| `site:` | 站内搜索 | `site:github.com python projects` |
|
||||
| `filetype:` | 文件类型 | `filetype:pdf annual report` |
|
||||
| `inurl:` | URL包含 | `inurl:login admin` |
|
||||
| `intitle:` | 标题包含 | `intitle:"index of" mp3` |
|
||||
| `intext:` | 正文包含 | `intext:password filetype:txt` |
|
||||
| `cache:` | 查看缓存 | `cache:example.com` |
|
||||
| `related:` | 相关网站 | `related:github.com` |
|
||||
| `info:` | 网站信息 | `info:example.com` |
|
||||
|
||||
### 1.3 时间筛选参数
|
||||
|
||||
| 参数 | 含义 | URL示例 |
|
||||
|------|------|---------|
|
||||
| `tbs=qdr:h` | 过去1小时 | `https://www.google.com/search?q=news&tbs=qdr:h` |
|
||||
| `tbs=qdr:d` | 过去24小时 | `https://www.google.com/search?q=news&tbs=qdr:d` |
|
||||
| `tbs=qdr:w` | 过去1周 | `https://www.google.com/search?q=news&tbs=qdr:w` |
|
||||
| `tbs=qdr:m` | 过去1月 | `https://www.google.com/search?q=news&tbs=qdr:m` |
|
||||
| `tbs=qdr:y` | 过去1年 | `https://www.google.com/search?q=news&tbs=qdr:y` |
|
||||
| `tbs=cdr:1,cd_min:1/1/2024,cd_max:12/31/2024` | 自定义日期范围 | 2024年全年 |
|
||||
|
||||
### 1.4 语言和地区筛选
|
||||
|
||||
| 参数 | 功能 | 示例 |
|
||||
|------|------|------|
|
||||
| `hl=en` | 界面语言 | `https://www.google.com/search?q=test&hl=en` |
|
||||
| `lr=lang_zh-CN` | 搜索结果语言 | `https://www.google.com/search?q=test&lr=lang_zh-CN` |
|
||||
| `cr=countryCN` | 国家/地区 | `https://www.google.com/search?q=test&cr=countryCN` |
|
||||
| `gl=us` | 地理位置 | `https://www.google.com/search?q=test&gl=us` |
|
||||
|
||||
### 1.5 特殊搜索类型
|
||||
|
||||
| 类型 | URL | 说明 |
|
||||
|------|-----|------|
|
||||
| 图片搜索 | `https://www.google.com/search?q={keyword}&tbm=isch` | `tbm=isch` 表示图片 |
|
||||
| 新闻搜索 | `https://www.google.com/search?q={keyword}&tbm=nws` | `tbm=nws` 表示新闻 |
|
||||
| 视频搜索 | `https://www.google.com/search?q={keyword}&tbm=vid` | `tbm=vid` 表示视频 |
|
||||
| 地图搜索 | `https://www.google.com/search?q={keyword}&tbm=map` | `tbm=map` 表示地图 |
|
||||
| 购物搜索 | `https://www.google.com/search?q={keyword}&tbm=shop` | `tbm=shop` 表示购物 |
|
||||
| 图书搜索 | `https://www.google.com/search?q={keyword}&tbm=bks` | `tbm=bks` 表示图书 |
|
||||
| 学术搜索 | `https://scholar.google.com/scholar?q={keyword}` | Google Scholar |
|
||||
|
||||
### 1.6 Google 深度搜索示例
|
||||
|
||||
```javascript
|
||||
// 1. 搜索GitHub上的Python机器学习项目
|
||||
web_fetch({"url": "https://www.google.com/search?q=site:github.com+python+machine+learning"})
|
||||
|
||||
// 2. 搜索2024年的PDF格式机器学习教程
|
||||
web_fetch({"url": "https://www.google.com/search?q=machine+learning+tutorial+filetype:pdf&tbs=cdr:1,cd_min:1/1/2024"})
|
||||
|
||||
// 3. 搜索标题包含"tutorial"的Python相关页面
|
||||
web_fetch({"url": "https://www.google.com/search?q=intitle:tutorial+python"})
|
||||
|
||||
// 4. 搜索过去一周的新闻
|
||||
web_fetch({"url": "https://www.google.com/search?q=AI+breakthrough&tbs=qdr:w&tbm=nws"})
|
||||
|
||||
// 5. 搜索中文内容(界面英文,结果中文)
|
||||
web_fetch({"url": "https://www.google.com/search?q=人工智能&lr=lang_zh-CN&hl=en"})
|
||||
|
||||
// 6. 搜索特定价格范围的笔记本电脑
|
||||
web_fetch({"url": "https://www.google.com/search?q=laptop+%241000..%242000+best+rating"})
|
||||
|
||||
// 7. 搜索排除Wikipedia的结果
|
||||
web_fetch({"url": "https://www.google.com/search?q=python+programming+-wikipedia"})
|
||||
|
||||
// 8. 搜索学术文献
|
||||
web_fetch({"url": "https://scholar.google.com/scholar?q=deep+learning+optimization"})
|
||||
|
||||
// 9. 搜索缓存页面(查看已删除内容)
|
||||
web_fetch({"url": "https://webcache.googleusercontent.com/search?q=cache:example.com"})
|
||||
|
||||
// 10. 搜索相关网站
|
||||
web_fetch({"url": "https://www.google.com/search?q=related:stackoverflow.com"})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🦆 DuckDuckGo 深度搜索
|
||||
|
||||
### 2.1 DuckDuckGo 特色功能
|
||||
|
||||
| 功能 | 语法 | 示例 |
|
||||
|------|------|------|
|
||||
| **Bangs 快捷** | `!缩写` | `!g python` → Google搜索 |
|
||||
| **密码生成** | `password` | `https://duckduckgo.com/?q=password+20` |
|
||||
| **颜色转换** | `color` | `https://duckduckgo.com/?q=+%23FF5733` |
|
||||
| **短链接** | `shorten` | `https://duckduckgo.com/?q=shorten+example.com` |
|
||||
| **二维码生成** | `qr` | `https://duckduckgo.com/?q=qr+hello+world` |
|
||||
| **生成UUID** | `uuid` | `https://duckduckgo.com/?q=uuid` |
|
||||
| **Base64编解码** | `base64` | `https://duckduckgo.com/?q=base64+hello` |
|
||||
|
||||
### 2.2 DuckDuckGo Bangs 完整列表
|
||||
|
||||
#### 搜索引擎
|
||||
|
||||
| Bang | 跳转目标 | 示例 |
|
||||
|------|---------|------|
|
||||
| `!g` | Google | `!g python tutorial` |
|
||||
| `!b` | Bing | `!b weather` |
|
||||
| `!y` | Yahoo | `!y finance` |
|
||||
| `!sp` | Startpage | `!sp privacy` |
|
||||
| `!brave` | Brave Search | `!brave tech` |
|
||||
|
||||
#### 编程开发
|
||||
|
||||
| Bang | 跳转目标 | 示例 |
|
||||
|------|---------|------|
|
||||
| `!gh` | GitHub | `!gh tensorflow` |
|
||||
| `!so` | Stack Overflow | `!so javascript error` |
|
||||
| `!npm` | npmjs.com | `!npm express` |
|
||||
| `!pypi` | PyPI | `!pypi requests` |
|
||||
| `!mdn` | MDN Web Docs | `!mdn fetch api` |
|
||||
| `!docs` | DevDocs | `!docs python` |
|
||||
| `!docker` | Docker Hub | `!docker nginx` |
|
||||
|
||||
#### 知识百科
|
||||
|
||||
| Bang | 跳转目标 | 示例 |
|
||||
|------|---------|------|
|
||||
| `!w` | Wikipedia | `!w machine learning` |
|
||||
| `!wen` | Wikipedia英文 | `!wen artificial intelligence` |
|
||||
| `!wt` | Wiktionary | `!wt serendipity` |
|
||||
| `!imdb` | IMDb | `!imdb inception` |
|
||||
|
||||
#### 购物价格
|
||||
|
||||
| Bang | 跳转目标 | 示例 |
|
||||
|------|---------|------|
|
||||
| `!a` | Amazon | `!a wireless headphones` |
|
||||
| `!e` | eBay | `!e vintage watch` |
|
||||
| `!ali` | AliExpress | `!ali phone case` |
|
||||
|
||||
#### 地图位置
|
||||
|
||||
| Bang | 跳转目标 | 示例 |
|
||||
|------|---------|------|
|
||||
| `!m` | Google Maps | `!m Beijing` |
|
||||
| `!maps` | OpenStreetMap | `!maps Paris` |
|
||||
|
||||
### 2.3 DuckDuckGo 搜索参数
|
||||
|
||||
| 参数 | 功能 | 示例 |
|
||||
|------|------|------|
|
||||
| `kp=1` | 严格安全搜索 | `https://duckduckgo.com/html/?q=test&kp=1` |
|
||||
| `kp=-1` | 关闭安全搜索 | `https://duckduckgo.com/html/?q=test&kp=-1` |
|
||||
| `kl=cn` | 中国区域 | `https://duckduckgo.com/html/?q=news&kl=cn` |
|
||||
| `kl=us-en` | 美国英文 | `https://duckduckgo.com/html/?q=news&kl=us-en` |
|
||||
| `ia=web` | 网页结果 | `https://duckduckgo.com/?q=test&ia=web` |
|
||||
| `ia=images` | 图片结果 | `https://duckduckgo.com/?q=test&ia=images` |
|
||||
| `ia=news` | 新闻结果 | `https://duckduckgo.com/?q=test&ia=news` |
|
||||
| `ia=videos` | 视频结果 | `https://duckduckgo.com/?q=test&ia=videos` |
|
||||
|
||||
### 2.4 DuckDuckGo 深度搜索示例
|
||||
|
||||
```javascript
|
||||
// 1. 使用Bang跳转到Google搜索
|
||||
web_fetch({"url": "https://duckduckgo.com/html/?q=!g+machine+learning"})
|
||||
|
||||
// 2. 直接搜索GitHub上的项目
|
||||
web_fetch({"url": "https://duckduckgo.com/html/?q=!gh+react"})
|
||||
|
||||
// 3. 查找Stack Overflow答案
|
||||
web_fetch({"url": "https://duckduckgo.com/html/?q=!so+python+list+comprehension"})
|
||||
|
||||
// 4. 生成密码
|
||||
web_fetch({"url": "https://duckduckgo.com/?q=password+16"})
|
||||
|
||||
// 5. Base64编码
|
||||
web_fetch({"url": "https://duckduckgo.com/?q=base64+hello+world"})
|
||||
|
||||
// 6. 颜色代码转换
|
||||
web_fetch({"url": "https://duckduckgo.com/?q=%23FF5733"})
|
||||
|
||||
// 7. 搜索YouTube视频
|
||||
web_fetch({"url": "https://duckduckgo.com/html/?q=!yt+python+tutorial"})
|
||||
|
||||
// 8. 查看Wikipedia
|
||||
web_fetch({"url": "https://duckduckgo.com/html/?q=!w+artificial+intelligence"})
|
||||
|
||||
// 9. 亚马逊商品搜索
|
||||
web_fetch({"url": "https://duckduckgo.com/html/?q=!a+laptop"})
|
||||
|
||||
// 10. 生成二维码
|
||||
web_fetch({"url": "https://duckduckgo.com/?q=qr+https://github.com"})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔎 Brave Search 深度搜索
|
||||
|
||||
### 3.1 Brave Search 特色功能
|
||||
|
||||
| 功能 | 参数 | 示例 |
|
||||
|------|------|------|
|
||||
| **独立索引** | 无依赖Google/Bing | 自有爬虫索引 |
|
||||
| **Goggles** | 自定义搜索规则 | 创建个性化过滤器 |
|
||||
| **Discussions** | 论坛讨论搜索 | 聚合Reddit等论坛 |
|
||||
| **News** | 新闻聚合 | 独立新闻索引 |
|
||||
|
||||
### 3.2 Brave Search 参数
|
||||
|
||||
| 参数 | 功能 | 示例 |
|
||||
|------|------|------|
|
||||
| `tf=pw` | 本周 | `https://search.brave.com/search?q=news&tf=pw` |
|
||||
| `tf=pm` | 本月 | `https://search.brave.com/search?q=tech&tf=pm` |
|
||||
| `tf=py` | 本年 | `https://search.brave.com/search?q=AI&tf=py` |
|
||||
| `safesearch=strict` | 严格安全 | `https://search.brave.com/search?q=test&safesearch=strict` |
|
||||
| `source=web` | 网页搜索 | 默认 |
|
||||
| `source=news` | 新闻搜索 | `https://search.brave.com/search?q=tech&source=news` |
|
||||
| `source=images` | 图片搜索 | `https://search.brave.com/search?q=cat&source=images` |
|
||||
| `source=videos` | 视频搜索 | `https://search.brave.com/search?q=music&source=videos` |
|
||||
|
||||
### 3.3 Brave Search Goggles(自定义过滤器)
|
||||
|
||||
Goggles 允许创建自定义搜索规则:
|
||||
|
||||
```
|
||||
$discard // 丢弃所有
|
||||
$boost,site=stackoverflow.com // 提升Stack Overflow
|
||||
$boost,site=github.com // 提升GitHub
|
||||
$boost,site=docs.python.org // 提升Python文档
|
||||
```
|
||||
|
||||
### 3.4 Brave Search 深度搜索示例
|
||||
|
||||
```javascript
|
||||
// 1. 本周科技新闻
|
||||
web_fetch({"url": "https://search.brave.com/search?q=technology&tf=pw&source=news"})
|
||||
|
||||
// 2. 本月AI发展
|
||||
web_fetch({"url": "https://search.brave.com/search?q=artificial+intelligence&tf=pm"})
|
||||
|
||||
// 3. 图片搜索
|
||||
web_fetch({"url": "https://search.brave.com/search?q=machine+learning&source=images"})
|
||||
|
||||
// 4. 视频教程
|
||||
web_fetch({"url": "https://search.brave.com/search?q=python+tutorial&source=videos"})
|
||||
|
||||
// 5. 使用独立索引搜索
|
||||
web_fetch({"url": "https://search.brave.com/search?q=privacy+tools"})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 WolframAlpha 知识计算搜索
|
||||
|
||||
### 4.1 WolframAlpha 数据类型
|
||||
|
||||
| 类型 | 查询示例 | URL |
|
||||
|------|---------|-----|
|
||||
| **数学计算** | `integrate x^2 dx` | `https://www.wolframalpha.com/input?i=integrate+x%5E2+dx` |
|
||||
| **单位换算** | `100 miles to km` | `https://www.wolframalpha.com/input?i=100+miles+to+km` |
|
||||
| **货币转换** | `100 USD to CNY` | `https://www.wolframalpha.com/input?i=100+USD+to+CNY` |
|
||||
| **股票数据** | `AAPL stock` | `https://www.wolframalpha.com/input?i=AAPL+stock` |
|
||||
| **天气查询** | `weather in Beijing` | `https://www.wolframalpha.com/input?i=weather+in+Beijing` |
|
||||
| **人口数据** | `population of China` | `https://www.wolframalpha.com/input?i=population+of+China` |
|
||||
| **化学元素** | `properties of gold` | `https://www.wolframalpha.com/input?i=properties+of+gold` |
|
||||
| **营养成分** | `nutrition of apple` | `https://www.wolframalpha.com/input?i=nutrition+of+apple` |
|
||||
| **日期计算** | `days between Jan 1 2020 and Dec 31 2024` | 日期间隔计算 |
|
||||
| **时区转换** | `10am Beijing to New York` | 时区转换 |
|
||||
| **IP地址** | `8.8.8.8` | IP信息查询 |
|
||||
| **条形码** | `scan barcode 123456789` | 条码信息 |
|
||||
| **飞机航班** | `flight AA123` | 航班信息 |
|
||||
|
||||
### 4.2 WolframAlpha 深度搜索示例
|
||||
|
||||
```javascript
|
||||
// 1. 计算积分
|
||||
web_fetch({"url": "https://www.wolframalpha.com/input?i=integrate+sin%28x%29+from+0+to+pi"})
|
||||
|
||||
// 2. 解方程
|
||||
web_fetch({"url": "https://www.wolframalpha.com/input?i=solve+x%5E2-5x%2B6%3D0"})
|
||||
|
||||
// 3. 货币实时汇率
|
||||
web_fetch({"url": "https://www.wolframalpha.com/input?i=100+USD+to+CNY"})
|
||||
|
||||
// 4. 股票实时数据
|
||||
web_fetch({"url": "https://www.wolframalpha.com/input?i=Apple+stock+price"})
|
||||
|
||||
// 5. 城市天气
|
||||
web_fetch({"url": "https://www.wolframalpha.com/input?i=weather+in+Shanghai+tomorrow"})
|
||||
|
||||
// 6. 国家统计信息
|
||||
web_fetch({"url": "https://www.wolframalpha.com/input?i=GDP+of+China+vs+USA"})
|
||||
|
||||
// 7. 化学计算
|
||||
web_fetch({"url": "https://www.wolframalpha.com/input?i=molar+mass+of+H2SO4"})
|
||||
|
||||
// 8. 物理常数
|
||||
web_fetch({"url": "https://www.wolframalpha.com/input?i=speed+of+light"})
|
||||
|
||||
// 9. 营养信息
|
||||
web_fetch({"url": "https://www.wolframalpha.com/input?i=calories+in+banana"})
|
||||
|
||||
// 10. 历史日期
|
||||
web_fetch({"url": "https://www.wolframalpha.com/input?i=events+on+July+20+1969"})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Startpage 隐私搜索
|
||||
|
||||
### 5.1 Startpage 特色功能
|
||||
|
||||
| 功能 | 说明 | URL |
|
||||
|------|------|-----|
|
||||
| **代理浏览** | 匿名访问搜索结果 | 点击"匿名查看" |
|
||||
| **无追踪** | 不记录搜索历史 | 默认开启 |
|
||||
| **EU服务器** | 受欧盟隐私法保护 | 数据在欧洲 |
|
||||
| **代理图片** | 图片代理加载 | 隐藏IP |
|
||||
|
||||
### 5.2 Startpage 参数
|
||||
|
||||
| 参数 | 功能 | 示例 |
|
||||
|------|------|------|
|
||||
| `cat=web` | 网页搜索 | 默认 |
|
||||
| `cat=images` | 图片搜索 | `...&cat=images` |
|
||||
| `cat=video` | 视频搜索 | `...&cat=video` |
|
||||
| `cat=news` | 新闻搜索 | `...&cat=news` |
|
||||
| `language=english` | 英文结果 | `...&language=english` |
|
||||
| `time=day` | 过去24小时 | `...&time=day` |
|
||||
| `time=week` | 过去一周 | `...&time=week` |
|
||||
| `time=month` | 过去一月 | `...&time=month` |
|
||||
| `time=year` | 过去一年 | `...&time=year` |
|
||||
| `nj=0` | 关闭 family filter | `...&nj=0` |
|
||||
|
||||
### 5.3 Startpage 深度搜索示例
|
||||
|
||||
```javascript
|
||||
// 1. 隐私搜索
|
||||
web_fetch({"url": "https://www.startpage.com/sp/search?query=privacy+tools"})
|
||||
|
||||
// 2. 图片隐私搜索
|
||||
web_fetch({"url": "https://www.startpage.com/sp/search?query=nature&cat=images"})
|
||||
|
||||
// 3. 本周新闻(隐私模式)
|
||||
web_fetch({"url": "https://www.startpage.com/sp/search?query=tech+news&time=week&cat=news"})
|
||||
|
||||
// 4. 英文结果搜索
|
||||
web_fetch({"url": "https://www.startpage.com/sp/search?query=machine+learning&language=english"})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🌐 其他国际搜索引擎
|
||||
|
||||
### Yahoo
|
||||
|
||||
```javascript
|
||||
web_fetch({"url": "https://search.yahoo.com/search?p={keyword}"})
|
||||
```
|
||||
|
||||
### Ecosia(环保搜索)
|
||||
|
||||
```javascript
|
||||
web_fetch({"url": "https://www.ecosia.org/search?q={keyword}"})
|
||||
```
|
||||
|
||||
### Qwant(欧盟隐私搜索)
|
||||
|
||||
```javascript
|
||||
web_fetch({"url": "https://www.qwant.com/?q={keyword}"})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🌍 国际搜索策略
|
||||
|
||||
### 按搜索目标选择引擎
|
||||
|
||||
| 搜索目标 | 首选引擎 | 原因 |
|
||||
|---------|---------|------|
|
||||
| **学术研究** | Google Scholar | 学术资源索引最全 |
|
||||
| **编程开发** | Google + DuckDuckGo Bangs | 技术文档全面 |
|
||||
| **隐私敏感** | DuckDuckGo / Brave | 不追踪用户 |
|
||||
| **实时新闻** | Brave News | 独立新闻索引 |
|
||||
| **知识计算** | WolframAlpha | 结构化数据计算 |
|
||||
| **隐私+Google结果** | Startpage | Google结果+隐私保护 |
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"version": 1,
|
||||
"registry": "https://clawhub.ai",
|
||||
"slug": "powerpoint-pptx",
|
||||
"installedVersion": "1.0.1",
|
||||
"installedAt": 1777430400378
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
---
|
||||
name: Powerpoint / PPTX
|
||||
slug: powerpoint-pptx
|
||||
version: 1.0.1
|
||||
homepage: https://clawic.com/skills/powerpoint-pptx
|
||||
description: "Create, inspect, and edit Microsoft PowerPoint presentations and PPTX decks with reliable layouts, templates, placeholders, notes, charts, and visual QA. Use when (1) the task is about PowerPoint or `.pptx`; (2) layouts, placeholders, notes, charts, comments, or template fidelity matter; (3) the deck must render cleanly after edits."
|
||||
changelog: Rebalanced the skill toward template inventory, layout mapping, and higher-signal QA after a stricter external audit.
|
||||
metadata: {"clawdbot":{"emoji":"📊","requires":{"bins":[]},"os":["linux","darwin","win32"]}}
|
||||
---
|
||||
|
||||
## When to Use
|
||||
|
||||
Use when the main artifact is a Microsoft PowerPoint presentation or `.pptx` deck, especially when layouts, templates, placeholders, notes, comments, charts, extraction, editing, or final visual quality matter.
|
||||
|
||||
## Core Rules
|
||||
|
||||
### 1. Choose the workflow before touching the deck
|
||||
|
||||
- Reading text, editing an existing deck, rebuilding from a template, and creating from scratch are different jobs with different failure modes.
|
||||
- For text extraction or inspection, read the deck before editing it.
|
||||
- Text extraction plus thumbnail-style visual inspection is safer than editing from shape assumptions alone.
|
||||
- For template-driven work, inventory the deck before replacing content.
|
||||
- For deep edits, remember a `.pptx` file is OOXML with separate parts for slides, layouts, masters, media, notes, and comments.
|
||||
- If a template exists, template fidelity beats generic slide-design instincts.
|
||||
- Reusing or duplicating a good existing slide is often safer than rebuilding it and hoping the theme still matches.
|
||||
|
||||
### 2. Inventory the deck before replacing content
|
||||
|
||||
- Count the reusable layouts, real placeholders, notes, comments, media, and recurring typography or color patterns first.
|
||||
- Placeholder indexes and layout indexes are not portable assumptions.
|
||||
- Inspect the actual slide or template before targeting title, body, chart, or image shapes.
|
||||
- Speaker notes, comments, and linked assets can live outside the visible slide surface.
|
||||
- A missing or wrong placeholder target can silently land content in the wrong box or wrong layer.
|
||||
- Master and layout settings can override local slide edits, so the visible problem is not always on the slide you are editing.
|
||||
|
||||
### 3. Match content to the actual placeholders
|
||||
|
||||
- Count the actual content pieces before choosing a layout.
|
||||
- Pick layouts based on the real number of ideas, columns, images, or charts the slide needs.
|
||||
- Do not force two ideas into a three-column slide or cram dense text under a chart.
|
||||
- Category counts and data series lengths must match or charts will break in ugly ways.
|
||||
- Explicit sizing beats wishful thinking: text boxes, images, and charts need real space, not "it should fit".
|
||||
- Do not choose a layout with more placeholders than the content can meaningfully fill.
|
||||
- Quote layouts are for real quotes, and image-led layouts are for slides that actually have images.
|
||||
- For chart-, table-, or image-heavy slides, full-slide or two-column layouts are usually safer than stacking dense text above the visual.
|
||||
|
||||
### 4. Preserve the deck's visual language
|
||||
|
||||
- Theme, master, and layout files usually decide fonts, colors, and hierarchy more than any one slide does.
|
||||
- Start from the deck's actual theme, fonts, spacing, and aspect ratio instead of improvising a new style.
|
||||
- Reuse the deck's own alignment and spacing system instead of inventing a second visual language.
|
||||
- Use common fonts for portability and strong contrast for readability.
|
||||
- Preserve the template's visual logic first; originality matters less than not breaking the deck's existing language.
|
||||
- Combining slides from multiple sources requires normalizing themes, masters, and alignment afterward.
|
||||
|
||||
### 5. Run content QA and visual QA separately
|
||||
|
||||
- Text overflow, bad alignment, clipped shapes, weak contrast, and placeholder leftovers are normal first-pass failures.
|
||||
- Run both content QA and visual QA; missing text and broken layout are different failure classes.
|
||||
- Render or inspect the actual deck output before delivery when layout matters.
|
||||
- Search for leftover template junk, sample labels, and placeholder text before calling the deck finished.
|
||||
- Check notes, comments, labels, legends, and chart/table semantics separately from the visual pass.
|
||||
- A deck can pass text extraction and still fail on overlap, clipping, wrong theme inheritance, or broken notes.
|
||||
- Thumbnail grids and rendered slides usually reveal layout bugs faster than code or text inspection.
|
||||
- Assume the first render is wrong and do at least one fix-and-verify cycle before calling the deck finished.
|
||||
- Re-check affected slides after each fix because one spacing change often creates another issue.
|
||||
|
||||
### 6. Keep decks portable and review-safe
|
||||
|
||||
- Template masters can override direct edits in surprising ways.
|
||||
- Complex effects may degrade across PowerPoint, LibreOffice, and conversion pipelines, so keep important content robust without them.
|
||||
- Image sizing, font substitution, and placeholder mismatch are common reasons a deck looks good in code and bad on screen.
|
||||
- Notes, comments, linked media, and merged decks can stay broken even when the visible slide looks fine.
|
||||
|
||||
## Common Traps
|
||||
|
||||
- Placeholder text and sample charts often survive template reuse if not explicitly replaced.
|
||||
- Directly editing one slide can fail if the real issue lives in the master or layout.
|
||||
- Charts, icons, and text boxes need enough space; near-collisions are usually visible only after rendering.
|
||||
- Layout indexes vary by template, so built-in assumptions from one deck often break in another.
|
||||
- A missing placeholder or wrong shape target can silently put content in the wrong place.
|
||||
- Counting the text ideas after choosing the layout usually leads to empty placeholders, weak hierarchy, or leftover template junk.
|
||||
- Font substitution can move line breaks and wreck careful spacing.
|
||||
- Speaker notes, comments, and linked media can stay broken even when the visible slide looks fine.
|
||||
- A deck can pass text inspection and still fail visually because of overlap, contrast, or edge clipping.
|
||||
- Editing from one slide alone can miss the real source of truth in the theme, master, or layout definitions.
|
||||
- Choosing a quote, comparison, or multi-column layout without matching content usually makes the deck look templated rather than intentional.
|
||||
- Combining or duplicating slides without checking masters and themes can create subtle inconsistency slide by slide.
|
||||
- Aspect-ratio mismatches like `16:9` versus `4:3` can shift every placement decision even when each slide looks locally reasonable.
|
||||
|
||||
## Related Skills
|
||||
Install with `clawhub install <slug>` if user confirms:
|
||||
- `documents` — Document workflows that often feed presentation content.
|
||||
- `design` — Visual direction and layout decisions.
|
||||
- `brief` — Concise business messaging for slide narratives.
|
||||
|
||||
## Feedback
|
||||
|
||||
- If useful: `clawhub star powerpoint-pptx`
|
||||
- Stay updated: `clawhub sync`
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"ownerId": "kn73vp5rarc3b14rc7wjcw8f8580t5d1",
|
||||
"slug": "powerpoint-pptx",
|
||||
"version": "1.0.1",
|
||||
"publishedAt": 1773243205254
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"version": 1,
|
||||
"registry": "https://clawhub.ai",
|
||||
"slug": "ppt-generator",
|
||||
"installedVersion": "1.0.0",
|
||||
"installedAt": 1777392917742
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
---
|
||||
name: ppt-generator
|
||||
description: 将用户讲稿一键生成乔布斯风极简科技感竖屏HTML演示稿。当用户需要生成PPT、演示文稿、Slides、幻灯片,或要求科技风/极简风/乔布斯风格的演示时触发此技能。输出为单个可直接运行的HTML文件。
|
||||
---
|
||||
|
||||
# PPT Generator
|
||||
|
||||
将讲稿转换为乔布斯风极简科技感竖屏HTML演示稿。
|
||||
|
||||
## 设计哲学
|
||||
|
||||
- **极简主义** - 一屏只讲一件事
|
||||
- **强视觉对比** - 深色背景 + 白色文字
|
||||
- **高留白** - 禁止密集排版
|
||||
- **强节奏感** - 让观众想继续看
|
||||
|
||||
## 生成流程(必须严格遵循)
|
||||
|
||||
### Step 1: 读取讲稿
|
||||
读取用户原始讲稿,不修改原稿内容。
|
||||
|
||||
### Step 2: 生成提炼版讲稿
|
||||
将内容精简、增强冲击力、适配演示场景,输出 Markdown 格式。
|
||||
|
||||
### Step 3: 生成乔布斯风标题
|
||||
为每个章节生成标题,必须满足:
|
||||
- ≤12 字
|
||||
- 采用以下形式之一:对比式、问题式、断言式、数字式、比喻式
|
||||
- 自检:是否让人想继续听?
|
||||
|
||||
### Step 4: 设计幻灯片结构
|
||||
规划页面顺序和类型,参考 [references/slide-types.md](references/slide-types.md)。
|
||||
|
||||
### Step 5: 生成HTML
|
||||
使用 [assets/template.html](assets/template.html) 作为基础模板生成完整HTML。
|
||||
|
||||
### Step 6: 填充内容
|
||||
添加动态背景光斑、交互逻辑、平滑切换动画。
|
||||
|
||||
## 输出顺序(必须依次输出)
|
||||
|
||||
1. **提炼后的讲稿**(Markdown)
|
||||
2. **幻灯片结构大纲**
|
||||
3. **完整HTML代码**
|
||||
|
||||
## 视觉规范速查
|
||||
|
||||
| 项目 | 规范 |
|
||||
|------|------|
|
||||
| 比例 | 9:16 竖屏 |
|
||||
| 背景 | #000000 或 #0a0a0a + 模糊光斑动画 |
|
||||
| 主文字 | #ffffff |
|
||||
| 辅助文字 | #9ca3af |
|
||||
| 中文字体 | HarmonyOS Sans SC / 思源黑体 |
|
||||
| 英文字体 | Inter / Roboto |
|
||||
| 标题字重 | font-black / font-bold |
|
||||
| 正文字重 | font-light / font-normal |
|
||||
|
||||
详细规范见 [references/design-spec.md](references/design-spec.md)。
|
||||
|
||||
## 交互要求
|
||||
|
||||
- 键盘 ← → 翻页
|
||||
- 底部进度导航条
|
||||
- 平滑切换动画
|
||||
|
||||
## 技术栈
|
||||
|
||||
- TailwindCSS(国内CDN)
|
||||
- 复杂页面使用 Vue3(CDN)
|
||||
- 单个HTML文件,可直接打开运行
|
||||
|
||||
## 严禁行为
|
||||
|
||||
- 堆字 / 密集排版
|
||||
- 花哨配色
|
||||
- 复杂图表
|
||||
- 横屏比例
|
||||
- 偏离极简科技风
|
||||
|
||||
## 默认规则
|
||||
|
||||
- 未指定页数:自动生成 8~20 页
|
||||
- 未指定风格:默认乔布斯风
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"ownerId": "kn72d2hfv2jvd8n0f7hc8rsbj180hn1v",
|
||||
"slug": "ppt-generator",
|
||||
"version": "1.0.0",
|
||||
"publishedAt": 1770200473886
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
interface:
|
||||
display_name: "PPT Generator"
|
||||
short_description: "将讲稿一键生成乔布斯风极简科技感竖屏HTML演示稿"
|
||||
default_prompt: "请根据我的讲稿生成科技风PPT"
|
||||
@@ -0,0 +1,304 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>演示文稿</title>
|
||||
|
||||
<!-- TailwindCSS CDN -->
|
||||
<script src="https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/tailwindcss/3.0.23/tailwind.min.js"></script>
|
||||
|
||||
<!-- 字体 -->
|
||||
<link href="https://fonts.loli.net/css2?family=Inter:wght@300;400;700;900&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.loli.net/css2?family=Noto+Sans+SC:wght@300;400;700;900&display=swap" rel="stylesheet">
|
||||
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Noto Sans SC', 'Inter', sans-serif;
|
||||
background: #000;
|
||||
color: #fff;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* 幻灯片容器 */
|
||||
.slides-container {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #0a0a0a;
|
||||
}
|
||||
|
||||
/* 单个幻灯片 */
|
||||
.slide {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
max-width: 450px;
|
||||
max-height: 800px;
|
||||
aspect-ratio: 9/16;
|
||||
position: absolute;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 2rem;
|
||||
opacity: 0;
|
||||
transform: translateX(100%);
|
||||
transition: all 0.5s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
overflow: hidden;
|
||||
background: linear-gradient(180deg, #0a0a0a 0%, #000000 100%);
|
||||
}
|
||||
|
||||
.slide.active {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
.slide.prev {
|
||||
opacity: 0;
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
|
||||
/* 动态光斑 */
|
||||
.light-spot {
|
||||
position: absolute;
|
||||
border-radius: 50%;
|
||||
filter: blur(100px);
|
||||
opacity: 0.3;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.light-spot-1 {
|
||||
width: 300px;
|
||||
height: 300px;
|
||||
background: #3b82f6;
|
||||
top: -100px;
|
||||
right: -100px;
|
||||
animation: float1 20s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.light-spot-2 {
|
||||
width: 250px;
|
||||
height: 250px;
|
||||
background: #8b5cf6;
|
||||
bottom: -80px;
|
||||
left: -80px;
|
||||
animation: float2 25s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.light-spot-3 {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
background: #06b6d4;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
animation: float3 18s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes float1 {
|
||||
0%, 100% { transform: translate(0, 0); }
|
||||
25% { transform: translate(-50px, 30px); }
|
||||
50% { transform: translate(30px, 50px); }
|
||||
75% { transform: translate(50px, -20px); }
|
||||
}
|
||||
|
||||
@keyframes float2 {
|
||||
0%, 100% { transform: translate(0, 0); }
|
||||
33% { transform: translate(40px, -40px); }
|
||||
66% { transform: translate(-30px, 30px); }
|
||||
}
|
||||
|
||||
@keyframes float3 {
|
||||
0%, 100% { transform: translate(-50%, -50%) scale(1); }
|
||||
50% { transform: translate(-50%, -50%) scale(1.2); }
|
||||
}
|
||||
|
||||
/* 内容层 */
|
||||
.slide-content {
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* 进度条 */
|
||||
.progress-bar {
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.progress-dot {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
background: rgba(255,255,255,0.3);
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.progress-dot.active {
|
||||
background: #fff;
|
||||
transform: scale(1.3);
|
||||
}
|
||||
|
||||
.progress-dot:hover {
|
||||
background: rgba(255,255,255,0.6);
|
||||
}
|
||||
|
||||
/* 页码 */
|
||||
.page-number {
|
||||
position: fixed;
|
||||
bottom: 50px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
font-size: 0.875rem;
|
||||
color: rgba(255,255,255,0.4);
|
||||
z-index: 100;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="slides-container">
|
||||
|
||||
<!-- 幻灯片 1: 封面页 -->
|
||||
<div class="slide active">
|
||||
<div class="light-spot light-spot-1"></div>
|
||||
<div class="light-spot light-spot-2"></div>
|
||||
<div class="slide-content">
|
||||
<h1 class="text-5xl font-black mb-6 leading-tight">主标题</h1>
|
||||
<p class="text-xl font-light text-gray-400">副标题</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 幻灯片 2: 标题冲击页 -->
|
||||
<div class="slide">
|
||||
<div class="light-spot light-spot-2"></div>
|
||||
<div class="light-spot light-spot-3"></div>
|
||||
<div class="slide-content">
|
||||
<h1 class="text-4xl font-black leading-tight">
|
||||
冲击力标题<br>第二行
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 幻灯片 3: 金句强调页 -->
|
||||
<div class="slide">
|
||||
<div class="light-spot light-spot-1"></div>
|
||||
<div class="light-spot light-spot-3"></div>
|
||||
<div class="slide-content">
|
||||
<span class="text-6xl text-gray-600 block mb-2">"</span>
|
||||
<p class="text-2xl font-bold mb-6">金句内容</p>
|
||||
<span class="text-lg font-light text-gray-500">— 来源</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 幻灯片 4: 结尾行动页 -->
|
||||
<div class="slide">
|
||||
<div class="light-spot light-spot-1"></div>
|
||||
<div class="light-spot light-spot-2"></div>
|
||||
<div class="light-spot light-spot-3"></div>
|
||||
<div class="slide-content">
|
||||
<h1 class="text-3xl font-bold mb-8">总结金句</h1>
|
||||
<p class="text-xl font-light text-gray-400">行动号召</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- 进度条 -->
|
||||
<div class="progress-bar" id="progressBar"></div>
|
||||
|
||||
<!-- 页码 -->
|
||||
<div class="page-number" id="pageNumber">1 / 4</div>
|
||||
|
||||
<script>
|
||||
const slides = document.querySelectorAll('.slide');
|
||||
const progressBar = document.getElementById('progressBar');
|
||||
const pageNumber = document.getElementById('pageNumber');
|
||||
let currentSlide = 0;
|
||||
|
||||
// 初始化进度条
|
||||
slides.forEach((_, index) => {
|
||||
const dot = document.createElement('div');
|
||||
dot.className = `progress-dot ${index === 0 ? 'active' : ''}`;
|
||||
dot.addEventListener('click', () => goToSlide(index));
|
||||
progressBar.appendChild(dot);
|
||||
});
|
||||
|
||||
function updateSlides() {
|
||||
slides.forEach((slide, index) => {
|
||||
slide.classList.remove('active', 'prev');
|
||||
if (index === currentSlide) {
|
||||
slide.classList.add('active');
|
||||
} else if (index < currentSlide) {
|
||||
slide.classList.add('prev');
|
||||
}
|
||||
});
|
||||
|
||||
// 更新进度条
|
||||
document.querySelectorAll('.progress-dot').forEach((dot, index) => {
|
||||
dot.classList.toggle('active', index === currentSlide);
|
||||
});
|
||||
|
||||
// 更新页码
|
||||
pageNumber.textContent = `${currentSlide + 1} / ${slides.length}`;
|
||||
}
|
||||
|
||||
function nextSlide() {
|
||||
if (currentSlide < slides.length - 1) {
|
||||
currentSlide++;
|
||||
updateSlides();
|
||||
}
|
||||
}
|
||||
|
||||
function prevSlide() {
|
||||
if (currentSlide > 0) {
|
||||
currentSlide--;
|
||||
updateSlides();
|
||||
}
|
||||
}
|
||||
|
||||
function goToSlide(index) {
|
||||
currentSlide = index;
|
||||
updateSlides();
|
||||
}
|
||||
|
||||
// 键盘控制
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'ArrowRight' || e.key === ' ') {
|
||||
nextSlide();
|
||||
} else if (e.key === 'ArrowLeft') {
|
||||
prevSlide();
|
||||
}
|
||||
});
|
||||
|
||||
// 触摸滑动支持
|
||||
let touchStartX = 0;
|
||||
document.addEventListener('touchstart', (e) => {
|
||||
touchStartX = e.touches[0].clientX;
|
||||
});
|
||||
|
||||
document.addEventListener('touchend', (e) => {
|
||||
const touchEndX = e.changedTouches[0].clientX;
|
||||
const diff = touchStartX - touchEndX;
|
||||
if (Math.abs(diff) > 50) {
|
||||
if (diff > 0) nextSlide();
|
||||
else prevSlide();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,116 @@
|
||||
# 设计规范详细文档
|
||||
|
||||
## 背景效果
|
||||
|
||||
### 主背景
|
||||
- 主色:#000000 或 #0a0a0a
|
||||
- 深色渐变底色
|
||||
|
||||
### 动态光斑(必须包含)
|
||||
每页必须包含 1~3 个模糊光斑:
|
||||
|
||||
```css
|
||||
.light-spot {
|
||||
position: absolute;
|
||||
width: 300px;
|
||||
height: 300px;
|
||||
border-radius: 50%;
|
||||
filter: blur(100px);
|
||||
opacity: 0.3;
|
||||
animation: float 20s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.light-spot-1 { background: #3b82f6; } /* 蓝色 */
|
||||
.light-spot-2 { background: #8b5cf6; } /* 紫色 */
|
||||
.light-spot-3 { background: #06b6d4; } /* 青色 */
|
||||
|
||||
@keyframes float {
|
||||
0%, 100% { transform: translate(0, 0); }
|
||||
25% { transform: translate(50px, -30px); }
|
||||
50% { transform: translate(-30px, 50px); }
|
||||
75% { transform: translate(-50px, -20px); }
|
||||
}
|
||||
```
|
||||
|
||||
## 字体加载(国内CDN)
|
||||
|
||||
```html
|
||||
<!-- HarmonyOS Sans SC -->
|
||||
<link href="https://s1.hdslb.com/bfs/static/jinkela/long/font/regular.css" rel="stylesheet">
|
||||
|
||||
<!-- 思源黑体备选 -->
|
||||
<link href="https://fonts.loli.net/css2?family=Noto+Sans+SC:wght@300;400;700;900&display=swap" rel="stylesheet">
|
||||
|
||||
<!-- Inter 英文字体 -->
|
||||
<link href="https://fonts.loli.net/css2?family=Inter:wght@300;400;700;900&display=swap" rel="stylesheet">
|
||||
```
|
||||
|
||||
## 排版层级
|
||||
|
||||
```css
|
||||
/* H1 超大标题 */
|
||||
.slide-title {
|
||||
font-size: 3rem; /* 48px */
|
||||
font-weight: 900; /* font-black */
|
||||
line-height: 1.2;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
/* H2 副标题 */
|
||||
.slide-subtitle {
|
||||
font-size: 1.5rem; /* 24px */
|
||||
font-weight: 700; /* font-bold */
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
/* P 说明文字 */
|
||||
.slide-text {
|
||||
font-size: 1.125rem; /* 18px */
|
||||
font-weight: 300; /* font-light */
|
||||
color: #9ca3af;
|
||||
}
|
||||
```
|
||||
|
||||
## 间距规范
|
||||
|
||||
- 元素间距:space-y-8 以上(32px+)
|
||||
- 页面内边距:p-8 或 p-12
|
||||
- 内容居中:flex items-center justify-center
|
||||
|
||||
## 页面容器
|
||||
|
||||
```css
|
||||
.slide {
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
aspect-ratio: 9/16;
|
||||
max-width: 450px; /* 竖屏限制 */
|
||||
margin: 0 auto;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 2rem;
|
||||
}
|
||||
```
|
||||
|
||||
## 切换动画
|
||||
|
||||
```css
|
||||
.slide {
|
||||
opacity: 0;
|
||||
transform: translateX(100%);
|
||||
transition: all 0.5s ease-out;
|
||||
}
|
||||
|
||||
.slide.active {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
.slide.prev {
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,184 @@
|
||||
# 幻灯片页面类型
|
||||
|
||||
## 1. 封面页
|
||||
|
||||
用于演示开场。
|
||||
|
||||
**结构:**
|
||||
- 超大主标题(font-black,居中)
|
||||
- 副标语(font-light,灰色)
|
||||
- 系列标识/Logo(可选)
|
||||
|
||||
**示例:**
|
||||
```html
|
||||
<div class="slide cover">
|
||||
<h1 class="text-5xl font-black text-white mb-6">重新定义效率</h1>
|
||||
<p class="text-xl font-light text-gray-400">AI时代的工作方式</p>
|
||||
</div>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 标题冲击页
|
||||
|
||||
用于章节开始或重点强调。
|
||||
|
||||
**结构:**
|
||||
- 单行/双行大标题
|
||||
- 几乎无正文(最多一行辅助文字)
|
||||
|
||||
**示例:**
|
||||
```html
|
||||
<div class="slide impact">
|
||||
<h1 class="text-4xl font-black text-white text-center">
|
||||
不是更努力<br>而是更聪明
|
||||
</h1>
|
||||
</div>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 金句强调页
|
||||
|
||||
用于引用、名言、核心观点。
|
||||
|
||||
**结构:**
|
||||
- 大引号装饰
|
||||
- 金句内容(font-bold)
|
||||
- 来源/出处(font-light,灰色)
|
||||
|
||||
**示例:**
|
||||
```html
|
||||
<div class="slide quote">
|
||||
<span class="text-6xl text-gray-600">"</span>
|
||||
<p class="text-2xl font-bold text-white my-6">
|
||||
简单比复杂更难
|
||||
</p>
|
||||
<span class="text-lg font-light text-gray-500">— Steve Jobs</span>
|
||||
</div>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 步骤说明页
|
||||
|
||||
用于流程、方法、操作指南。
|
||||
|
||||
**结构:**
|
||||
- 动词型大标题
|
||||
- 简洁说明(1-2行)
|
||||
- 可选:步骤编号
|
||||
|
||||
**示例:**
|
||||
```html
|
||||
<div class="slide step">
|
||||
<span class="text-6xl font-black text-blue-500 mb-4">01</span>
|
||||
<h2 class="text-3xl font-bold text-white mb-4">明确目标</h2>
|
||||
<p class="text-lg font-light text-gray-400">
|
||||
先问自己:这件事最重要的结果是什么?
|
||||
</p>
|
||||
</div>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 对比页
|
||||
|
||||
用于展示变化、差异、前后对比。
|
||||
|
||||
**结构:**
|
||||
- 左右或上下分栏
|
||||
- 对比元素使用不同颜色标识
|
||||
- 简洁文字说明
|
||||
|
||||
**示例:**
|
||||
```html
|
||||
<div class="slide compare">
|
||||
<div class="text-center mb-8">
|
||||
<span class="text-red-400 line-through text-xl">传统方式</span>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<span class="text-green-400 text-3xl font-bold">全新体验</span>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 数据展示页
|
||||
|
||||
用于关键数字、统计、成果。
|
||||
|
||||
**结构:**
|
||||
- 超大数字(font-black)
|
||||
- 单位/说明(font-light)
|
||||
- 简短解释
|
||||
|
||||
**示例:**
|
||||
```html
|
||||
<div class="slide data">
|
||||
<span class="text-7xl font-black text-white">10x</span>
|
||||
<p class="text-xl font-light text-gray-400 mt-4">效率提升</p>
|
||||
</div>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. 列表页
|
||||
|
||||
用于多点说明,但必须保持极简。
|
||||
|
||||
**结构:**
|
||||
- 标题
|
||||
- 3-5 个要点(不能更多)
|
||||
- 每个要点 ≤10 字
|
||||
|
||||
**示例:**
|
||||
```html
|
||||
<div class="slide list">
|
||||
<h2 class="text-2xl font-bold text-white mb-8">三个原则</h2>
|
||||
<ul class="space-y-6 text-xl">
|
||||
<li class="text-gray-300">• 少即是多</li>
|
||||
<li class="text-gray-300">• 专注核心</li>
|
||||
<li class="text-gray-300">• 持续迭代</li>
|
||||
</ul>
|
||||
</div>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. 结尾行动页
|
||||
|
||||
用于演示结束,呼吁行动。
|
||||
|
||||
**结构:**
|
||||
- 总结金句
|
||||
- 行动号召(CTA)
|
||||
- 联系方式/二维码(可选)
|
||||
|
||||
**示例:**
|
||||
```html
|
||||
<div class="slide ending">
|
||||
<h1 class="text-3xl font-bold text-white mb-8">
|
||||
现在就开始改变
|
||||
</h1>
|
||||
<p class="text-xl font-light text-gray-400">
|
||||
扫码获取更多信息
|
||||
</p>
|
||||
</div>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 页面选择指南
|
||||
|
||||
| 内容类型 | 推荐页面类型 |
|
||||
|---------|-------------|
|
||||
| 演示开场 | 封面页 |
|
||||
| 章节分隔 | 标题冲击页 |
|
||||
| 核心观点 | 金句强调页 |
|
||||
| 操作步骤 | 步骤说明页 |
|
||||
| 前后对比 | 对比页 |
|
||||
| 关键数据 | 数据展示页 |
|
||||
| 多点说明 | 列表页(≤5点)|
|
||||
| 演示结束 | 结尾行动页 |
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"version": 1,
|
||||
"registry": "https://clawhub.ai",
|
||||
"slug": "self-improving-proactive-agent",
|
||||
"installedVersion": "1.0.0",
|
||||
"installedAt": 1774710570083
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
# Self-Improving Proactive Agent
|
||||
|
||||
A merged OpenClaw skill that combines the best parts of **self-improving** and **proactivity**.
|
||||
|
||||
## What it does
|
||||
|
||||
- learns from corrections and reflection
|
||||
- stores durable patterns separately from active task state
|
||||
- keeps momentum with proactive next moves
|
||||
- recovers context before asking the user to repeat themselves
|
||||
- uses heartbeat for useful follow-through without spamming
|
||||
- preserves hard boundaries for external actions and privacy
|
||||
|
||||
## State layout
|
||||
|
||||
- `~/self-improving/` → durable learning
|
||||
- `~/proactivity/` → active execution state
|
||||
|
||||
## Main files
|
||||
|
||||
- `SKILL.md`
|
||||
- `setup.md`
|
||||
- `boundaries.md`
|
||||
- `heartbeat-rules.md`
|
||||
- `learning.md`
|
||||
- `state.md`
|
||||
- `recovery.md`
|
||||
- `operations.md`
|
||||
|
||||
## Philosophy
|
||||
|
||||
One skill, two layers:
|
||||
- learn better
|
||||
- operate better
|
||||
|
||||
That is the whole point.
|
||||
@@ -0,0 +1,213 @@
|
||||
---
|
||||
name: Self-Improving Proactive Agent
|
||||
slug: self-improving-proactive-agent
|
||||
version: 1.0.0
|
||||
homepage: https://github.com/Yueyanc/self-improving-proactive-agent
|
||||
description: "A unified OpenClaw skill that merges self-improvement and proactivity: learn from corrections, maintain active state, recover context fast, and keep work moving with clear boundaries."
|
||||
changelog: "Initial release. Combines the strongest patterns from self-improving and proactivity into one canonical skill package."
|
||||
metadata: {"clawdbot":{"emoji":"🧠","requires":{"bins":[]},"os":["linux","darwin","win32"],"configPaths":["~/self-improving/","~/proactivity/"],"configPaths.optional":["./AGENTS.md","./SOUL.md","./HEARTBEAT.md","./TOOLS.md"]}}
|
||||
---
|
||||
|
||||
# Self-Improving Proactive Agent
|
||||
|
||||
One skill, two layers:
|
||||
|
||||
- **Self-improving**: learn from corrections, reflection, and repeated wins
|
||||
- **Proactive**: maintain momentum, recover context, and push the next useful move
|
||||
|
||||
Use this when you want an agent that does not just remember better, but also operates better.
|
||||
|
||||
## When to Use
|
||||
|
||||
Use this skill when:
|
||||
- the user corrects you or states durable preferences
|
||||
- the task is multi-step or likely to drift
|
||||
- context recovery matters
|
||||
- follow-through and heartbeat behavior should improve over time
|
||||
- the user wants a single unified behavior model instead of separate overlapping skills
|
||||
|
||||
## Unified Architecture
|
||||
|
||||
```text
|
||||
~/self-improving/
|
||||
├── memory.md # HOT: confirmed durable rules and preferences
|
||||
├── corrections.md # recent corrections and reusable lessons
|
||||
├── index.md # storage map / topic index
|
||||
├── heartbeat-state.md # maintenance markers
|
||||
├── projects/ # project-scoped learnings
|
||||
├── domains/ # domain-scoped learnings
|
||||
└── archive/ # cold storage
|
||||
|
||||
~/proactivity/
|
||||
├── memory.md # stable activation and boundary rules
|
||||
├── session-state.md # current objective, decision, blocker, next move
|
||||
├── heartbeat.md # lightweight recurring follow-through
|
||||
├── patterns.md # reusable proactive wins
|
||||
├── log.md # recent proactive actions
|
||||
└── memory/
|
||||
└── working-buffer.md # volatile breadcrumbs for long / fragile tasks
|
||||
```
|
||||
|
||||
## Core Principles
|
||||
|
||||
### 1. Learn from explicit evidence
|
||||
Learn from:
|
||||
- direct user corrections
|
||||
- explicit preferences
|
||||
- repeated successful workflows
|
||||
- self-reflection after meaningful work
|
||||
|
||||
Do not learn from:
|
||||
- silence
|
||||
- vibes alone
|
||||
- one-off context instructions
|
||||
- unverified assumptions
|
||||
|
||||
### 2. Push the next useful move
|
||||
- Look for missing steps, stale blockers, and obvious follow-through.
|
||||
- Prefer drafts, checks, patches, and prepared options.
|
||||
- Stay quiet when the value is weak.
|
||||
|
||||
### 3. Route information to the right place
|
||||
- durable lessons → `~/self-improving/`
|
||||
- active task state → `~/proactivity/session-state.md`
|
||||
- volatile breadcrumbs → `~/proactivity/memory/working-buffer.md`
|
||||
|
||||
### 4. Recover before asking
|
||||
Before asking the user to restate work:
|
||||
1. read HOT self-improving memory
|
||||
2. read proactive stable memory
|
||||
3. read session state
|
||||
4. read working buffer when needed
|
||||
5. ask only for the missing delta
|
||||
|
||||
### 5. Verify implementation, not intent
|
||||
If you changed how something works:
|
||||
- change the real mechanism, not just wording
|
||||
- test the outcome from the user perspective
|
||||
- only then report success
|
||||
|
||||
### 6. Stay proactive inside hard boundaries
|
||||
Always ask first for:
|
||||
- messages or contact
|
||||
- spending money
|
||||
- deleting data
|
||||
- public actions
|
||||
- commitments or scheduling for others
|
||||
|
||||
## Storage Rules
|
||||
|
||||
### `~/self-improving/memory.md`
|
||||
Use for durable preferences and confirmed reusable rules.
|
||||
|
||||
### `~/self-improving/corrections.md`
|
||||
Use for recent explicit corrections and lessons pending promotion.
|
||||
|
||||
### `~/proactivity/session-state.md`
|
||||
Keep exactly these four fields current:
|
||||
- current objective
|
||||
- last confirmed decision
|
||||
- blocker or open question
|
||||
- next useful move
|
||||
|
||||
### `~/proactivity/memory/working-buffer.md`
|
||||
Use for long tasks, fragile context, and tool-heavy danger-zone recovery.
|
||||
|
||||
## Learning Signals
|
||||
|
||||
### Corrections
|
||||
Examples:
|
||||
- "Use X, not Y"
|
||||
- "That’s wrong"
|
||||
- "Stop doing that"
|
||||
|
||||
Action:
|
||||
- log concisely to corrections
|
||||
- promote after repetition or explicit confirmation
|
||||
|
||||
### Preferences
|
||||
Examples:
|
||||
- "Always do X for me"
|
||||
- "Never do Y"
|
||||
- "For this project, use Z"
|
||||
|
||||
Action:
|
||||
- if durable, add to HOT memory or the matching domain/project file
|
||||
|
||||
### Reflections
|
||||
After meaningful work, log:
|
||||
```text
|
||||
CONTEXT: [task]
|
||||
REFLECTION: [what happened]
|
||||
LESSON: [what to change next time]
|
||||
```
|
||||
|
||||
### Proactive wins
|
||||
If a proactive move repeatedly helps:
|
||||
- log it to `~/proactivity/log.md`
|
||||
- promote it to `~/proactivity/patterns.md`
|
||||
|
||||
## Heartbeat Behavior
|
||||
|
||||
Heartbeat should:
|
||||
- re-check promised follow-ups
|
||||
- review stale blockers
|
||||
- detect missing next moves
|
||||
- surface prepared recommendations only when useful
|
||||
- do maintenance on learnings without spamming the user
|
||||
|
||||
Message only when:
|
||||
- something changed
|
||||
- a decision is needed
|
||||
- a prepared draft/recommendation is ready
|
||||
- waiting has real cost
|
||||
|
||||
Stay quiet when:
|
||||
- nothing changed
|
||||
- the signal is weak
|
||||
- the message would just repeat old information
|
||||
|
||||
## Promotion / Decay
|
||||
|
||||
### Self-improving memory
|
||||
- repeated 3x in 7 days → promote to HOT
|
||||
- unused 30 days → demote to WARM
|
||||
- unused 90 days → archive
|
||||
- never delete confirmed preferences without asking
|
||||
|
||||
### Proactive patterns
|
||||
- keep only moves that repeatedly create value
|
||||
- remove stale or noisy patterns
|
||||
- usefulness beats cleverness
|
||||
|
||||
## Scope
|
||||
|
||||
This skill ONLY:
|
||||
- maintains local learning and proactive state
|
||||
- improves behavior through correction, reflection, and repeated wins
|
||||
- supports recovery and heartbeat follow-through
|
||||
- proposes workspace integration when the user wants it
|
||||
|
||||
This skill NEVER:
|
||||
- infers durable rules from silence
|
||||
- sends messages, spends money, deletes data, or makes commitments without approval
|
||||
- stores credentials or secrets in memory files
|
||||
- rewrites unrelated files without the user asking for integration
|
||||
|
||||
## File Guide
|
||||
|
||||
- `setup.md` — install and integrate the skill
|
||||
- `boundaries.md` — hard safety and privacy rules
|
||||
- `heartbeat-rules.md` — proactive heartbeat standard
|
||||
- `learning.md` — how lessons are captured and promoted
|
||||
- `state.md` — where each kind of state belongs
|
||||
- `recovery.md` — context recovery flow
|
||||
- `operations.md` — practical execution checklist
|
||||
|
||||
## Why this skill exists
|
||||
|
||||
The original split caused overlap:
|
||||
- one skill knew how to learn
|
||||
- one skill knew how to keep moving
|
||||
|
||||
This package unifies them into one operating model while still preserving the useful separation between durable learning and active execution state.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user