Merge branch 'openclaw:main' into qianfan
This commit is contained in:
@@ -8,98 +8,63 @@ Input
|
||||
- If missing: use the most recent PR mentioned in the conversation.
|
||||
- If ambiguous: ask.
|
||||
|
||||
Do (review-only)
|
||||
Goal: produce a thorough review and a clear recommendation (READY for /landpr vs NEEDS WORK). Do NOT merge, do NOT push, do NOT make changes in the repo as part of this command.
|
||||
Do (end-to-end)
|
||||
Goal: PR must end in GitHub state = MERGED (never CLOSED). Use `gh pr merge` with `--rebase` or `--squash`.
|
||||
|
||||
1. Identify PR meta + context
|
||||
1. Repo clean: `git status`.
|
||||
2. Identify PR meta (author + head branch):
|
||||
|
||||
```sh
|
||||
gh pr view <PR> --json number,title,state,isDraft,author,baseRefName,headRefName,headRepository,url,body,labels,assignees,reviewRequests,files,additions,deletions --jq '{number,title,url,state,isDraft,author:.author.login,base:.baseRefName,head:.headRefName,headRepo:.headRepository.nameWithOwner,additions,deletions,files:.files|length}'
|
||||
gh pr view <PR> --json number,title,author,headRefName,baseRefName,headRepository --jq '{number,title,author:.author.login,head:.headRefName,base:.baseRefName,headRepo:.headRepository.nameWithOwner}'
|
||||
contrib=$(gh pr view <PR> --json author --jq .author.login)
|
||||
head=$(gh pr view <PR> --json headRefName --jq .headRefName)
|
||||
head_repo_url=$(gh pr view <PR> --json headRepository --jq .headRepository.url)
|
||||
```
|
||||
|
||||
2. Read the PR description carefully
|
||||
- Summarize the stated goal, scope, and any “why now?” rationale.
|
||||
- Call out any missing context: motivation, alternatives considered, rollout/compat notes, risk.
|
||||
3. Fast-forward base:
|
||||
- `git checkout main`
|
||||
- `git pull --ff-only`
|
||||
4. Create temp base branch from main:
|
||||
- `git checkout -b temp/landpr-<ts-or-pr>`
|
||||
5. Check out PR branch locally:
|
||||
- `gh pr checkout <PR>`
|
||||
6. Rebase PR branch onto temp base:
|
||||
- `git rebase temp/landpr-<ts-or-pr>`
|
||||
- Fix conflicts; keep history tidy.
|
||||
7. Fix + tests + changelog:
|
||||
- Implement fixes + add/adjust tests
|
||||
- Update `CHANGELOG.md` and mention `#<PR>` + `@$contrib`
|
||||
8. Decide merge strategy:
|
||||
- Rebase if we want to preserve commit history
|
||||
- Squash if we want a single clean commit
|
||||
- If unclear, ask
|
||||
9. Full gate (BEFORE commit):
|
||||
- `pnpm lint && pnpm build && pnpm test`
|
||||
10. Commit via committer (include # + contributor in commit message):
|
||||
- `committer "fix: <summary> (#<PR>) (thanks @$contrib)" CHANGELOG.md <changed files>`
|
||||
- `land_sha=$(git rev-parse HEAD)`
|
||||
11. Push updated PR branch (rebase => usually needs force):
|
||||
|
||||
3. Read the diff thoroughly (prefer full diff)
|
||||
```sh
|
||||
git remote add prhead "$head_repo_url.git" 2>/dev/null || git remote set-url prhead "$head_repo_url.git"
|
||||
git push --force-with-lease prhead HEAD:$head
|
||||
```
|
||||
|
||||
```sh
|
||||
gh pr diff <PR>
|
||||
# If you need more surrounding context for files:
|
||||
gh pr checkout <PR> # optional; still review-only
|
||||
git show --stat
|
||||
```
|
||||
12. Merge PR (must show MERGED on GitHub):
|
||||
- Rebase: `gh pr merge <PR> --rebase`
|
||||
- Squash: `gh pr merge <PR> --squash`
|
||||
- Never `gh pr close` (closing is wrong)
|
||||
13. Sync main:
|
||||
- `git checkout main`
|
||||
- `git pull --ff-only`
|
||||
14. Comment on PR with what we did + SHAs + thanks:
|
||||
|
||||
4. Validate the change is needed / valuable
|
||||
- What user/customer/dev pain does this solve?
|
||||
- Is this change the smallest reasonable fix?
|
||||
- Are we introducing complexity for marginal benefit?
|
||||
- Are we changing behavior/contract in a way that needs docs or a release note?
|
||||
```sh
|
||||
merge_sha=$(gh pr view <PR> --json mergeCommit --jq '.mergeCommit.oid')
|
||||
gh pr comment <PR> --body "Landed via temp rebase onto main.\n\n- Gate: pnpm lint && pnpm build && pnpm test\n- Land commit: $land_sha\n- Merge commit: $merge_sha\n\nThanks @$contrib!"
|
||||
```
|
||||
|
||||
5. Evaluate implementation quality + optimality
|
||||
- Correctness: edge cases, error handling, null/undefined, concurrency, ordering.
|
||||
- Design: is the abstraction/architecture appropriate or over/under-engineered?
|
||||
- Performance: hot paths, allocations, queries, network, N+1s, caching.
|
||||
- Security/privacy: authz/authn, input validation, secrets, logging PII.
|
||||
- Backwards compatibility: public APIs, config, migrations.
|
||||
- Style consistency: formatting, naming, patterns used elsewhere.
|
||||
|
||||
6. Tests & verification
|
||||
- Identify what’s covered by tests (unit/integration/e2e).
|
||||
- Are there regression tests for the bug fixed / scenario added?
|
||||
- Missing tests? Call out exact cases that should be added.
|
||||
- If tests are present, do they actually assert the important behavior (not just snapshots / happy path)?
|
||||
|
||||
7. Follow-up refactors / cleanup suggestions
|
||||
- Any code that should be simplified before merge?
|
||||
- Any TODOs that should be tickets vs addressed now?
|
||||
- Any deprecations, docs, types, or lint rules we should adjust?
|
||||
|
||||
8. Key questions to answer explicitly
|
||||
- Can we fix everything ourselves in a follow-up, or does the contributor need to update this PR?
|
||||
- Any blocking concerns (must-fix before merge)?
|
||||
- Is this PR ready to land, or does it need work?
|
||||
|
||||
9. Output (structured)
|
||||
Produce a review with these sections:
|
||||
|
||||
A) TL;DR recommendation
|
||||
|
||||
- One of: READY FOR /landpr | NEEDS WORK | NEEDS DISCUSSION
|
||||
- 1–3 sentence rationale.
|
||||
|
||||
B) What changed
|
||||
|
||||
- Brief bullet summary of the diff/behavioral changes.
|
||||
|
||||
C) What’s good
|
||||
|
||||
- Bullets: correctness, simplicity, tests, docs, ergonomics, etc.
|
||||
|
||||
D) Concerns / questions (actionable)
|
||||
|
||||
- Numbered list.
|
||||
- Mark each item as:
|
||||
- BLOCKER (must fix before merge)
|
||||
- IMPORTANT (should fix before merge)
|
||||
- NIT (optional)
|
||||
- For each: point to the file/area and propose a concrete fix or alternative.
|
||||
|
||||
E) Tests
|
||||
|
||||
- What exists.
|
||||
- What’s missing (specific scenarios).
|
||||
|
||||
F) Follow-ups (optional)
|
||||
|
||||
- Non-blocking refactors/tickets to open later.
|
||||
|
||||
G) Suggested PR comment (optional)
|
||||
|
||||
- Offer: “Want me to draft a PR comment to the author?”
|
||||
- If yes, provide a ready-to-paste comment summarizing the above, with clear asks.
|
||||
|
||||
Rules / Guardrails
|
||||
|
||||
- Review only: do not merge (`gh pr merge`), do not push branches, do not edit code.
|
||||
- If you need clarification, ask questions rather than guessing.
|
||||
15. Verify PR state == MERGED:
|
||||
- `gh pr view <PR> --json state --jq .state`
|
||||
16. Delete temp branch:
|
||||
- `git branch -D temp/landpr-<ts-or-pr>`
|
||||
|
||||
15
CHANGELOG.md
15
CHANGELOG.md
@@ -6,9 +6,14 @@ Docs: https://docs.openclaw.ai
|
||||
|
||||
### Changes
|
||||
|
||||
- Telegram: remove last `@ts-nocheck` from `bot-handlers.ts`, use Grammy types directly, deduplicate `StickerMetadata`. Zero `@ts-nocheck` remaining in `src/telegram/`. (#9206)
|
||||
- Telegram: remove `@ts-nocheck` from `bot-message.ts`, type deps via `Omit<BuildTelegramMessageContextParams>`, widen `allMedia` to `TelegramMediaRef[]`. (#9180)
|
||||
- Telegram: remove `@ts-nocheck` from `bot.ts`, fix duplicate `bot.catch` error handler (Grammy overrides), remove dead reaction `message_thread_id` routing, harden sticker cache guard. (#9077)
|
||||
- Onboarding: add Cloudflare AI Gateway provider setup and docs. (#7914) Thanks @roerohan.
|
||||
- Onboarding: add Moonshot (.cn) auth choice and keep the China base URL when preserving defaults. (#7180) Thanks @waynelwz.
|
||||
- Docs: clarify tmux send-keys for TUI by splitting text and Enter. (#7737) Thanks @Wangnov.
|
||||
- Docs: mirror the landing page revamp for zh-CN (features, quickstart, docs directory, network model, credits). (#8994) Thanks @joshp123.
|
||||
- Messages: add per-channel and per-account responsePrefix overrides across channels. (#9001) Thanks @mudrii.
|
||||
- Cron: add announce delivery mode for isolated jobs (CLI + Control UI) and delivery mode config.
|
||||
- Cron: default isolated jobs to announce delivery; accept ISO 8601 `schedule.at` in tool inputs.
|
||||
- Cron: hard-migrate isolated jobs to announce/none delivery; drop legacy post-to-main/payload delivery fields and `atMs` inputs.
|
||||
@@ -18,15 +23,25 @@ Docs: https://docs.openclaw.ai
|
||||
|
||||
### Fixes
|
||||
|
||||
- Heartbeat: allow explicit accountId routing for multi-account channels. (#8702) Thanks @lsh411.
|
||||
- TUI/Gateway: handle non-streaming finals, refresh history for non-local chat runs, and avoid event gap warnings for targeted tool streams. (#8432) Thanks @gumadeiras.
|
||||
- Shell completion: auto-detect and migrate slow dynamic patterns to cached files for faster terminal startup; add completion health checks to doctor/update/onboard.
|
||||
- Telegram: honor session model overrides in inline model selection. (#8193) Thanks @gildo.
|
||||
- Web UI: fix agent model selection saves for default/non-default agents and wrap long workspace paths. Thanks @Takhoffman.
|
||||
- Web UI: resolve header logo path when `gateway.controlUi.basePath` is set. (#7178) Thanks @Yeom-JinHo.
|
||||
- Web UI: apply button styling to the new-messages indicator.
|
||||
- Onboarding: infer auth choice from non-interactive API key flags. (#8484) Thanks @f-trycua.
|
||||
- Security: keep untrusted channel metadata out of system prompts (Slack/Discord). Thanks @KonstantinMirin.
|
||||
- Security: enforce sandboxed media paths for message tool attachments. (#9182) Thanks @victormier.
|
||||
- Security: require explicit credentials for gateway URL overrides to prevent credential leakage. (#8113) Thanks @victormier.
|
||||
- Security: gate `whatsapp_login` tool to owner senders and default-deny non-owner contexts. (#8768) Thanks @victormier.
|
||||
- Voice call: harden webhook verification with host allowlists/proxy trust and keep ngrok loopback bypass.
|
||||
- Voice call: add regression coverage for anonymous inbound caller IDs with allowlist policy. (#8104) Thanks @victormier.
|
||||
- Cron: accept epoch timestamps and 0ms durations in CLI `--at` parsing.
|
||||
- Cron: reload store data when the store file is recreated or mtime changes.
|
||||
- Cron: deliver announce runs directly, honor delivery mode, and respect wakeMode for summaries. (#8540) Thanks @tyler6204.
|
||||
- Telegram: include forward_from_chat metadata in forwarded messages and harden cron delivery target checks. (#8392) Thanks @Glucksberg.
|
||||
- macOS: fix cron payload summary rendering and ISO 8601 formatter concurrency safety.
|
||||
|
||||
## 2026.2.2-3
|
||||
|
||||
|
||||
95
appcast.xml
95
appcast.xml
@@ -2,6 +2,56 @@
|
||||
<rss xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle" version="2.0">
|
||||
<channel>
|
||||
<title>OpenClaw</title>
|
||||
<item>
|
||||
<title>2026.2.3</title>
|
||||
<pubDate>Wed, 04 Feb 2026 17:47:10 -0800</pubDate>
|
||||
<link>https://raw.githubusercontent.com/openclaw/openclaw/main/appcast.xml</link>
|
||||
<sparkle:version>8900</sparkle:version>
|
||||
<sparkle:shortVersionString>2026.2.3</sparkle:shortVersionString>
|
||||
<sparkle:minimumSystemVersion>15.0</sparkle:minimumSystemVersion>
|
||||
<description><![CDATA[<h2>OpenClaw 2026.2.3</h2>
|
||||
<h3>Changes</h3>
|
||||
<ul>
|
||||
<li>Telegram: remove last <code>@ts-nocheck</code> from <code>bot-handlers.ts</code>, use Grammy types directly, deduplicate <code>StickerMetadata</code>. Zero <code>@ts-nocheck</code> remaining in <code>src/telegram/</code>. (#9206)</li>
|
||||
<li>Telegram: remove <code>@ts-nocheck</code> from <code>bot-message.ts</code>, type deps via <code>Omit<BuildTelegramMessageContextParams></code>, widen <code>allMedia</code> to <code>TelegramMediaRef[]</code>. (#9180)</li>
|
||||
<li>Telegram: remove <code>@ts-nocheck</code> from <code>bot.ts</code>, fix duplicate <code>bot.catch</code> error handler (Grammy overrides), remove dead reaction <code>message_thread_id</code> routing, harden sticker cache guard. (#9077)</li>
|
||||
<li>Onboarding: add Cloudflare AI Gateway provider setup and docs. (#7914) Thanks @roerohan.</li>
|
||||
<li>Onboarding: add Moonshot (.cn) auth choice and keep the China base URL when preserving defaults. (#7180) Thanks @waynelwz.</li>
|
||||
<li>Docs: clarify tmux send-keys for TUI by splitting text and Enter. (#7737) Thanks @Wangnov.</li>
|
||||
<li>Docs: mirror the landing page revamp for zh-CN (features, quickstart, docs directory, network model, credits). (#8994) Thanks @joshp123.</li>
|
||||
<li>Messages: add per-channel and per-account responsePrefix overrides across channels. (#9001) Thanks @mudrii.</li>
|
||||
<li>Cron: add announce delivery mode for isolated jobs (CLI + Control UI) and delivery mode config.</li>
|
||||
<li>Cron: default isolated jobs to announce delivery; accept ISO 8601 <code>schedule.at</code> in tool inputs.</li>
|
||||
<li>Cron: hard-migrate isolated jobs to announce/none delivery; drop legacy post-to-main/payload delivery fields and <code>atMs</code> inputs.</li>
|
||||
<li>Cron: delete one-shot jobs after success by default; add <code>--keep-after-run</code> for CLI.</li>
|
||||
<li>Cron: suppress messaging tools during announce delivery so summaries post consistently.</li>
|
||||
<li>Cron: avoid duplicate deliveries when isolated runs send messages directly.</li>
|
||||
</ul>
|
||||
<h3>Fixes</h3>
|
||||
<ul>
|
||||
<li>Heartbeat: allow explicit accountId routing for multi-account channels. (#8702) Thanks @lsh411.</li>
|
||||
<li>TUI/Gateway: handle non-streaming finals, refresh history for non-local chat runs, and avoid event gap warnings for targeted tool streams. (#8432) Thanks @gumadeiras.</li>
|
||||
<li>Shell completion: auto-detect and migrate slow dynamic patterns to cached files for faster terminal startup; add completion health checks to doctor/update/onboard.</li>
|
||||
<li>Telegram: honor session model overrides in inline model selection. (#8193) Thanks @gildo.</li>
|
||||
<li>Web UI: fix agent model selection saves for default/non-default agents and wrap long workspace paths. Thanks @Takhoffman.</li>
|
||||
<li>Web UI: resolve header logo path when <code>gateway.controlUi.basePath</code> is set. (#7178) Thanks @Yeom-JinHo.</li>
|
||||
<li>Web UI: apply button styling to the new-messages indicator.</li>
|
||||
<li>Security: keep untrusted channel metadata out of system prompts (Slack/Discord). Thanks @KonstantinMirin.</li>
|
||||
<li>Security: enforce sandboxed media paths for message tool attachments. (#9182) Thanks @victormier.</li>
|
||||
<li>Security: require explicit credentials for gateway URL overrides to prevent credential leakage. (#8113) Thanks @victormier.</li>
|
||||
<li>Security: gate <code>whatsapp_login</code> tool to owner senders and default-deny non-owner contexts. (#8768) Thanks @victormier.</li>
|
||||
<li>Voice call: harden webhook verification with host allowlists/proxy trust and keep ngrok loopback bypass.</li>
|
||||
<li>Voice call: add regression coverage for anonymous inbound caller IDs with allowlist policy. (#8104) Thanks @victormier.</li>
|
||||
<li>Cron: accept epoch timestamps and 0ms durations in CLI <code>--at</code> parsing.</li>
|
||||
<li>Cron: reload store data when the store file is recreated or mtime changes.</li>
|
||||
<li>Cron: deliver announce runs directly, honor delivery mode, and respect wakeMode for summaries. (#8540) Thanks @tyler6204.</li>
|
||||
<li>Telegram: include forward_from_chat metadata in forwarded messages and harden cron delivery target checks. (#8392) Thanks @Glucksberg.</li>
|
||||
<li>macOS: fix cron payload summary rendering and ISO 8601 formatter concurrency safety.</li>
|
||||
</ul>
|
||||
<p><a href="https://github.com/openclaw/openclaw/blob/main/CHANGELOG.md">View full changelog</a></p>
|
||||
]]></description>
|
||||
<enclosure url="https://github.com/openclaw/openclaw/releases/download/v2026.2.3/OpenClaw-2026.2.3.zip" length="22530161" type="application/octet-stream" sparkle:edSignature="7eHUaQC6cx87HWbcaPh9T437+LqfE9VtQBf4p9JBjIyBrqGYxxp9KPvI5unEjg55j9j2djCXhseSMeyyRmvYBg=="/>
|
||||
</item>
|
||||
<item>
|
||||
<title>2026.2.2</title>
|
||||
<pubDate>Tue, 03 Feb 2026 17:04:17 -0800</pubDate>
|
||||
@@ -112,50 +162,5 @@
|
||||
]]></description>
|
||||
<enclosure url="https://github.com/openclaw/openclaw/releases/download/v2026.2.1/OpenClaw-2026.2.1.zip" length="22458919" type="application/octet-stream" sparkle:edSignature="kA/8VQlVdtYphcB1iuFrhWczwWKgkVZMfDfQ7T9WD405D8JKTv5CZ1n8lstIVkpk4xog3UhrfaaoTG8Bf8DMAQ=="/>
|
||||
</item>
|
||||
<item>
|
||||
<title>2026.1.30</title>
|
||||
<pubDate>Sat, 31 Jan 2026 14:29:57 +0100</pubDate>
|
||||
<link>https://raw.githubusercontent.com/openclaw/openclaw/main/appcast.xml</link>
|
||||
<sparkle:version>8469</sparkle:version>
|
||||
<sparkle:shortVersionString>2026.1.30</sparkle:shortVersionString>
|
||||
<sparkle:minimumSystemVersion>15.0</sparkle:minimumSystemVersion>
|
||||
<description><![CDATA[<h2>OpenClaw 2026.1.30</h2>
|
||||
<h3>Changes</h3>
|
||||
<ul>
|
||||
<li>CLI: add <code>completion</code> command (Zsh/Bash/PowerShell/Fish) and auto-setup during postinstall/onboarding.</li>
|
||||
<li>CLI: add per-agent <code>models status</code> (<code>--agent</code> filter). (#4780) Thanks @jlowin.</li>
|
||||
<li>Agents: add Kimi K2.5 to the synthetic model catalog. (#4407) Thanks @manikv12.</li>
|
||||
<li>Auth: switch Kimi Coding to built-in provider; normalize OAuth profile email.</li>
|
||||
<li>Auth: add MiniMax OAuth plugin + onboarding option. (#4521) Thanks @Maosghoul.</li>
|
||||
<li>Agents: update pi SDK/API usage and dependencies.</li>
|
||||
<li>Web UI: refresh sessions after chat commands and improve session display names.</li>
|
||||
<li>Build: move TypeScript builds to <code>tsdown</code> + <code>tsgo</code> (faster builds, CI typechecks), update tsconfig target, and clean up lint rules.</li>
|
||||
<li>Build: align npm tar override and bin metadata so the <code>openclaw</code> CLI entrypoint is preserved in npm publishes.</li>
|
||||
<li>Docs: add pi/pi-dev docs and update OpenClaw branding + install links.</li>
|
||||
</ul>
|
||||
<h3>Fixes</h3>
|
||||
<ul>
|
||||
<li>Security: restrict local path extraction in media parser to prevent LFI. (#4880)</li>
|
||||
<li>Gateway: prevent token defaults from becoming the literal "undefined". (#4873) Thanks @Hisleren.</li>
|
||||
<li>Control UI: fix assets resolution for npm global installs. (#4909) Thanks @YuriNachos.</li>
|
||||
<li>macOS: avoid stderr pipe backpressure in gateway discovery. (#3304) Thanks @abhijeet117.</li>
|
||||
<li>Telegram: normalize account token lookup for non-normalized IDs. (#5055) Thanks @jasonsschin.</li>
|
||||
<li>Telegram: preserve delivery thread fallback and fix threadId handling in delivery context.</li>
|
||||
<li>Telegram: fix HTML nesting for overlapping styles/links. (#4578) Thanks @ThanhNguyxn.</li>
|
||||
<li>Telegram: accept numeric messageId/chatId in react actions. (#4533) Thanks @Ayush10.</li>
|
||||
<li>Telegram: honor per-account proxy dispatcher via undici fetch. (#4456) Thanks @spiceoogway.</li>
|
||||
<li>Telegram: scope skill commands to bound agent per bot. (#4360) Thanks @robhparker.</li>
|
||||
<li>BlueBubbles: debounce by messageId to preserve attachments in text+image messages. (#4984)</li>
|
||||
<li>Routing: prefer requesterOrigin over stale session entries for sub-agent announce delivery. (#4957)</li>
|
||||
<li>Extensions: restore embedded extension discovery typings.</li>
|
||||
<li>CLI: fix <code>tui:dev</code> port resolution.</li>
|
||||
<li>LINE: fix status command TypeError. (#4651)</li>
|
||||
<li>OAuth: skip expired-token warnings when refresh tokens are still valid. (#4593)</li>
|
||||
<li>Build: skip redundant UI install step in Dockerfile. (#4584) Thanks @obviyus.</li>
|
||||
</ul>
|
||||
<p><a href="https://github.com/openclaw/openclaw/blob/main/CHANGELOG.md">View full changelog</a></p>
|
||||
]]></description>
|
||||
<enclosure url="https://github.com/openclaw/openclaw/releases/download/v2026.1.30/OpenClaw-2026.1.30.zip" length="22458594" type="application/octet-stream" sparkle:edSignature="77/GuEcruKGgu2CJyMq+OVwzaJ2v1VzRQC9NmOirKO3uH5Nn5HaoouwrOHnOanrzlD4OvPW0FS5GH2E4Ntu4CQ=="/>
|
||||
</item>
|
||||
</channel>
|
||||
</rss>
|
||||
@@ -97,25 +97,21 @@ enum CronSchedule: Codable, Equatable {
|
||||
static func parseAtDate(_ value: String) -> Date? {
|
||||
let trimmed = value.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
if trimmed.isEmpty { return nil }
|
||||
if let date = isoFormatterWithFractional.date(from: trimmed) { return date }
|
||||
return isoFormatter.date(from: trimmed)
|
||||
if let date = makeIsoFormatter(withFractional: true).date(from: trimmed) { return date }
|
||||
return makeIsoFormatter(withFractional: false).date(from: trimmed)
|
||||
}
|
||||
|
||||
static func formatIsoDate(_ date: Date) -> String {
|
||||
isoFormatter.string(from: date)
|
||||
makeIsoFormatter(withFractional: false).string(from: date)
|
||||
}
|
||||
|
||||
private static let isoFormatter: ISO8601DateFormatter = {
|
||||
private static func makeIsoFormatter(withFractional: Bool) -> ISO8601DateFormatter {
|
||||
let formatter = ISO8601DateFormatter()
|
||||
formatter.formatOptions = [.withInternetDateTime]
|
||||
formatter.formatOptions = withFractional
|
||||
? [.withInternetDateTime, .withFractionalSeconds]
|
||||
: [.withInternetDateTime]
|
||||
return formatter
|
||||
}()
|
||||
|
||||
private static let isoFormatterWithFractional: ISO8601DateFormatter = {
|
||||
let formatter = ISO8601DateFormatter()
|
||||
formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
|
||||
return formatter
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
enum CronPayload: Codable, Equatable {
|
||||
|
||||
@@ -207,7 +207,7 @@ extension CronSettings {
|
||||
|
||||
func payloadSummary(_ job: CronJob) -> some View {
|
||||
let payload = job.payload
|
||||
VStack(alignment: .leading, spacing: 6) {
|
||||
return VStack(alignment: .leading, spacing: 6) {
|
||||
Text("Payload")
|
||||
.font(.caption.weight(.semibold))
|
||||
.foregroundStyle(.secondary)
|
||||
|
||||
@@ -39,6 +39,26 @@
|
||||
"source": "Getting started",
|
||||
"target": "入门指南"
|
||||
},
|
||||
{
|
||||
"source": "Quick start",
|
||||
"target": "快速开始"
|
||||
},
|
||||
{
|
||||
"source": "Quick Start",
|
||||
"target": "快速开始"
|
||||
},
|
||||
{
|
||||
"source": "Docs directory",
|
||||
"target": "文档目录"
|
||||
},
|
||||
{
|
||||
"source": "Credits",
|
||||
"target": "致谢"
|
||||
},
|
||||
{
|
||||
"source": "Features",
|
||||
"target": "功能"
|
||||
},
|
||||
{
|
||||
"source": "DMs",
|
||||
"target": "私信"
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
title: "OpenClaw Docs"
|
||||
description: "A TypeScript/Node gateway + macOS/iOS/Android companions for WhatsApp (web) and Telegram (bot)."
|
||||
markdown: kramdown
|
||||
highlighter: rouge
|
||||
|
||||
# Keep GitHub Pages' default page URLs (e.g. /gateway.html). Many docs links
|
||||
# are written as relative *.md links and are rewritten during the build.
|
||||
|
||||
plugins:
|
||||
- jekyll-relative-links
|
||||
|
||||
relative_links:
|
||||
enabled: true
|
||||
collections: true
|
||||
|
||||
defaults:
|
||||
- scope:
|
||||
path: ""
|
||||
values:
|
||||
layout: default
|
||||
|
||||
nav:
|
||||
- title: "Home"
|
||||
url: "/"
|
||||
- title: "OpenClaw Assistant"
|
||||
url: "/start/openclaw/"
|
||||
- title: "Gateway"
|
||||
url: "/gateway/"
|
||||
- title: "Remote"
|
||||
url: "/gateway/remote/"
|
||||
- title: "Discovery"
|
||||
url: "/gateway/discovery/"
|
||||
- title: "Configuration"
|
||||
url: "/gateway/configuration/"
|
||||
- title: "WebChat"
|
||||
url: "/web/webchat/"
|
||||
- title: "macOS App"
|
||||
url: "/platforms/macos/"
|
||||
- title: "iOS App"
|
||||
url: "/platforms/ios/"
|
||||
- title: "Android App"
|
||||
url: "/platforms/android/"
|
||||
- title: "Telegram"
|
||||
url: "/channels/telegram/"
|
||||
- title: "Security"
|
||||
url: "/gateway/security/"
|
||||
- title: "Troubleshooting"
|
||||
url: "/gateway/troubleshooting/"
|
||||
|
||||
kramdown:
|
||||
input: GFM
|
||||
hard_wrap: false
|
||||
syntax_highlighter: rouge
|
||||
@@ -1,145 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="en" data-theme="auto">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="color-scheme" content="light dark" />
|
||||
<title>
|
||||
{% if page.url == "/" %}{{ site.title }}{% else %}{{ page.title | default: page.path | split: "/" | last | replace: ".md", "" }} · {{ site.title }}{% endif %}
|
||||
</title>
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Pixelify+Sans:wght@400..700&family=Fragment+Mono:ital,wght@0,400;0,700;1,400;1,700&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<script>
|
||||
(() => {
|
||||
try {
|
||||
const stored = localStorage.getItem("openclaw:theme");
|
||||
if (stored === "light" || stored === "dark") document.documentElement.dataset.theme = stored;
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
<link rel="stylesheet" href="{{ "/assets/terminal.css" | relative_url }}" />
|
||||
<link rel="stylesheet" href="{{ "/assets/markdown.css" | relative_url }}" />
|
||||
<script defer src="{{ "/assets/theme.js" | relative_url }}"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<a class="skip-link" href="#content">Skip to content</a>
|
||||
|
||||
<header class="shell">
|
||||
<div class="shell__frame" role="banner">
|
||||
<div class="shell__titlebar">
|
||||
<div class="brand" aria-label="OpenClaw docs terminal">
|
||||
<img
|
||||
class="brand__logo"
|
||||
src="{{ "/assets/pixel-lobster.svg" | relative_url }}"
|
||||
alt=""
|
||||
width="40"
|
||||
height="40"
|
||||
decoding="async"
|
||||
/>
|
||||
<div class="brand__text">
|
||||
<div class="brand__name">OpenClaw</div>
|
||||
<div class="brand__hint">docs // lobster terminal</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="titlebar__actions">
|
||||
<a class="titlebar__cta" href="https://github.com/openclaw/openclaw">
|
||||
<span class="titlebar__cta-label">GitHub</span>
|
||||
<span class="titlebar__cta-meta">repo</span>
|
||||
</a>
|
||||
<a class="titlebar__cta titlebar__cta--accent" href="https://github.com/openclaw/openclaw/releases/latest">
|
||||
<span class="titlebar__cta-label">Download</span>
|
||||
<span class="titlebar__cta-meta">latest</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="shell__nav" aria-label="Primary">
|
||||
<nav class="nav">
|
||||
{% assign nav = site.nav | default: empty %}
|
||||
{% for item in nav %}
|
||||
{% assign item_url = item.url | relative_url %}
|
||||
<a class="nav__link" href="{{ item_url }}">
|
||||
<span class="nav__chev">›</span>{{ item.title }}
|
||||
</a>
|
||||
{% endfor %}
|
||||
</nav>
|
||||
|
||||
<div class="shell__status" aria-hidden="true">
|
||||
<span class="status__dot"></span>
|
||||
<span class="status__text">
|
||||
{% if page.url == "/" %}
|
||||
ready
|
||||
{% else %}
|
||||
viewing: {{ page.path }}
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main id="content" class="content" role="main">
|
||||
<div class="terminal">
|
||||
<div class="terminal__prompt" aria-hidden="true">
|
||||
<span class="prompt__user">openclaw</span>@<span class="prompt__host">openclaw</span>:<span class="prompt__path">~/docs</span>$<span class="prompt__cmd">
|
||||
{% if page.url == "/" %}cat index.md{% else %}less {{ page.path }}{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{% if page.summary %}
|
||||
<p class="terminal__summary">{{ page.summary }}</p>
|
||||
{% endif %}
|
||||
|
||||
{% if page.read_when %}
|
||||
<details class="terminal__meta">
|
||||
<summary>Read when…</summary>
|
||||
<ul>
|
||||
{% for hint in page.read_when %}
|
||||
<li>{{ hint }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</details>
|
||||
{% endif %}
|
||||
|
||||
<article class="markdown">
|
||||
{{ content }}
|
||||
</article>
|
||||
|
||||
<footer class="terminal__footer" role="contentinfo">
|
||||
<div class="footer__line">
|
||||
<span class="footer__sig">openclaw.ai</span>
|
||||
<span class="footer__sep">·</span>
|
||||
<a href="https://github.com/openclaw/openclaw">source</a>
|
||||
<span class="footer__sep">·</span>
|
||||
<a href="https://github.com/openclaw/openclaw/releases">releases</a>
|
||||
</div>
|
||||
<div class="footer__hint" aria-hidden="true">
|
||||
tip: press <kbd>F2</kbd> (Mac: <kbd>fn</kbd>+<kbd>F2</kbd>) to flip
|
||||
the universe
|
||||
</div>
|
||||
<div class="footer__actions">
|
||||
<button
|
||||
class="theme-toggle"
|
||||
type="button"
|
||||
data-theme-toggle
|
||||
aria-label="Toggle theme (F2; on Mac: fn+F2)"
|
||||
aria-pressed="false"
|
||||
>
|
||||
<span class="theme-toggle__key">F2</span>
|
||||
<span class="theme-toggle__label" data-theme-label>theme</span>
|
||||
</button>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,179 +0,0 @@
|
||||
.markdown {
|
||||
margin-top: 18px;
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
.mdx-content > h1:first-of-type {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.markdown h1,
|
||||
.markdown h2,
|
||||
.markdown h3,
|
||||
.markdown h4 {
|
||||
font-family: var(--font-pixel);
|
||||
letter-spacing: 0.04em;
|
||||
line-height: 1.15;
|
||||
}
|
||||
|
||||
.markdown h1 {
|
||||
font-size: clamp(28px, 4vw, 44px);
|
||||
margin: 26px 0 10px;
|
||||
}
|
||||
|
||||
.markdown h2 {
|
||||
font-size: 22px;
|
||||
margin: 26px 0 10px;
|
||||
}
|
||||
|
||||
.markdown h3 {
|
||||
font-size: 18px;
|
||||
margin: 22px 0 8px;
|
||||
}
|
||||
|
||||
.markdown p {
|
||||
margin: 0 0 14px;
|
||||
}
|
||||
|
||||
.markdown a {
|
||||
color: var(--link);
|
||||
text-decoration: none;
|
||||
border-bottom: 1px dotted color-mix(in oklab, var(--link) 65%, transparent);
|
||||
}
|
||||
|
||||
.markdown a:hover {
|
||||
color: var(--link2);
|
||||
border-bottom-color: color-mix(in oklab, var(--link2) 75%, transparent);
|
||||
}
|
||||
|
||||
.markdown hr {
|
||||
border: 0;
|
||||
height: 1px;
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
transparent,
|
||||
color-mix(in oklab, var(--frame-border) 30%, transparent),
|
||||
transparent
|
||||
);
|
||||
margin: 26px 0;
|
||||
}
|
||||
|
||||
.markdown blockquote {
|
||||
margin: 18px 0;
|
||||
padding: 14px 14px;
|
||||
border-radius: var(--radius-sm);
|
||||
background: color-mix(in oklab, var(--panel) 70%, transparent);
|
||||
border-left: 6px solid color-mix(in oklab, var(--accent) 60%, transparent);
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.markdown ul,
|
||||
.markdown ol {
|
||||
margin: 0 0 14px 22px;
|
||||
}
|
||||
|
||||
.markdown li {
|
||||
margin: 4px 0;
|
||||
}
|
||||
|
||||
.markdown img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
border-radius: 12px;
|
||||
border: 1px solid color-mix(in oklab, var(--frame-border) 20%, transparent);
|
||||
box-shadow: 0 12px 0 -8px rgba(0, 0, 0, 0.18);
|
||||
}
|
||||
|
||||
.showcase-link {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.showcase-preview {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 100%;
|
||||
width: min(420px, 80vw);
|
||||
padding: 8px;
|
||||
border-radius: 14px;
|
||||
background: color-mix(in oklab, var(--panel) 92%, transparent);
|
||||
border: 1px solid color-mix(in oklab, var(--frame-border) 30%, transparent);
|
||||
box-shadow: 0 18px 40px -18px rgba(0, 0, 0, 0.55);
|
||||
transform: translate(-50%, 10px) scale(0.98);
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
pointer-events: none;
|
||||
z-index: 20;
|
||||
transition: opacity 0.18s ease, transform 0.18s ease, visibility 0.18s ease;
|
||||
}
|
||||
|
||||
.showcase-preview img {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
border-radius: 10px;
|
||||
border: 1px solid color-mix(in oklab, var(--frame-border) 25%, transparent);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.showcase-link:hover .showcase-preview,
|
||||
.showcase-link:focus-within .showcase-preview {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
transform: translate(-50%, 6px) scale(1);
|
||||
}
|
||||
|
||||
@media (hover: none) {
|
||||
.showcase-preview {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.markdown code {
|
||||
font-family: var(--font-body);
|
||||
font-size: 0.95em;
|
||||
padding: 0.15em 0.35em;
|
||||
border-radius: 8px;
|
||||
background: color-mix(in oklab, var(--panel) 70%, var(--code-bg));
|
||||
border: 1px solid color-mix(in oklab, var(--frame-border) 18%, transparent);
|
||||
}
|
||||
|
||||
.markdown pre {
|
||||
background: var(--code-bg);
|
||||
color: var(--code-fg);
|
||||
padding: 14px 14px;
|
||||
border-radius: var(--radius-sm);
|
||||
border: 1px solid color-mix(in oklab, var(--frame-border) 18%, transparent);
|
||||
overflow-x: auto;
|
||||
box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--code-accent) 12%, transparent);
|
||||
}
|
||||
|
||||
.markdown pre code {
|
||||
background: transparent;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.markdown table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin: 16px 0 22px;
|
||||
border: 1px solid color-mix(in oklab, var(--frame-border) 20%, transparent);
|
||||
border-radius: var(--radius-sm);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.markdown th,
|
||||
.markdown td {
|
||||
padding: 10px 10px;
|
||||
border-bottom: 1px solid color-mix(in oklab, var(--frame-border) 15%, transparent);
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.markdown th {
|
||||
background: color-mix(in oklab, var(--panel2) 85%, transparent);
|
||||
font-family: var(--font-pixel);
|
||||
letter-spacing: 0.06em;
|
||||
}
|
||||
@@ -1,473 +0,0 @@
|
||||
:root {
|
||||
--font-body: "Fragment Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||
--font-pixel: "Pixelify Sans", system-ui, sans-serif;
|
||||
--radius: 14px;
|
||||
--radius-sm: 10px;
|
||||
--border: 2px;
|
||||
--shadow-px: 0 0 0 var(--border) var(--frame-border), 0 12px 0 -4px rgba(0, 0, 0, 0.25);
|
||||
--scanline-size: 6px;
|
||||
--scanline-opacity: 0.08;
|
||||
}
|
||||
|
||||
html[data-theme="light"],
|
||||
html[data-theme="auto"] {
|
||||
--bg0: #fbf4e7;
|
||||
--bg1: #fffaf0;
|
||||
--panel: #fffdf8;
|
||||
--panel2: #fff6e5;
|
||||
--text: #10221c;
|
||||
--muted: #3e5a50;
|
||||
--faint: #6b7f77;
|
||||
--link: #0f6b4c;
|
||||
--link2: #ff4f40;
|
||||
--accent: #ff4f40;
|
||||
--accent2: #00b88a;
|
||||
--frame-border: #1b2e27;
|
||||
--code-bg: #0b1713;
|
||||
--code-fg: #eafff6;
|
||||
--code-accent: #67ff9b;
|
||||
}
|
||||
|
||||
html[data-theme="dark"] {
|
||||
--bg0: #0b1a22;
|
||||
--bg1: #0a1720;
|
||||
--panel: #0e231f;
|
||||
--panel2: #102a24;
|
||||
--text: #c9eadc;
|
||||
--muted: #8ab8aa;
|
||||
--faint: #699b8d;
|
||||
--link: #6fe8c7;
|
||||
--link2: #ff7b63;
|
||||
--accent: #ff4f40;
|
||||
--accent2: #5fdfa2;
|
||||
--frame-border: #6fbfa8;
|
||||
--code-bg: #091814;
|
||||
--code-fg: #d7f5e8;
|
||||
--code-accent: #5fdfa2;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
html[data-theme="auto"] {
|
||||
--bg0: #0b1a22;
|
||||
--bg1: #0a1720;
|
||||
--panel: #0e231f;
|
||||
--panel2: #102a24;
|
||||
--text: #c9eadc;
|
||||
--muted: #8ab8aa;
|
||||
--faint: #699b8d;
|
||||
--link: #6fe8c7;
|
||||
--link2: #ff7b63;
|
||||
--accent: #ff4f40;
|
||||
--accent2: #5fdfa2;
|
||||
--frame-border: #6fbfa8;
|
||||
--code-bg: #091814;
|
||||
--code-fg: #d7f5e8;
|
||||
--code-accent: #5fdfa2;
|
||||
}
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: var(--font-body);
|
||||
color: var(--text);
|
||||
background:
|
||||
radial-gradient(1100px 700px at 20% -10%, color-mix(in oklab, var(--accent) 18%, transparent), transparent 55%),
|
||||
radial-gradient(900px 600px at 95% 10%, color-mix(in oklab, var(--accent2) 14%, transparent), transparent 60%),
|
||||
radial-gradient(900px 600px at 50% 120%, color-mix(in oklab, var(--link) 10%, transparent), transparent 55%),
|
||||
linear-gradient(180deg, var(--bg0), var(--bg1));
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
body::before,
|
||||
body::after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.skip-link {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
z-index: 10;
|
||||
padding: 10px 12px;
|
||||
border-radius: 999px;
|
||||
background: var(--panel);
|
||||
color: var(--text);
|
||||
text-decoration: none;
|
||||
transform: translateY(-130%);
|
||||
box-shadow: var(--shadow-px);
|
||||
}
|
||||
|
||||
.skip-link:focus {
|
||||
transform: translateY(0);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.shell {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 100;
|
||||
padding: 22px 16px 10px;
|
||||
}
|
||||
|
||||
.shell__frame {
|
||||
max-width: 1120px;
|
||||
margin: 0 auto;
|
||||
border-radius: var(--radius);
|
||||
background:
|
||||
linear-gradient(180deg, color-mix(in oklab, var(--panel2) 88%, transparent), color-mix(in oklab, var(--panel) 92%, transparent));
|
||||
box-shadow: var(--shadow-px);
|
||||
border: var(--border) solid var(--frame-border);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.shell__titlebar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
padding: 14px 14px 12px;
|
||||
background:
|
||||
linear-gradient(90deg, color-mix(in oklab, var(--accent) 26%, transparent), transparent 42%),
|
||||
linear-gradient(180deg, color-mix(in oklab, var(--panel) 90%, #000 10%), color-mix(in oklab, var(--panel2) 90%, #000 10%));
|
||||
}
|
||||
|
||||
.brand {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.brand__logo {
|
||||
flex: 0 0 auto;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
image-rendering: pixelated;
|
||||
filter: drop-shadow(0 2px 0 color-mix(in oklab, var(--frame-border) 80%, transparent));
|
||||
}
|
||||
|
||||
.brand__text {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.brand__name {
|
||||
font-family: var(--font-pixel);
|
||||
letter-spacing: 0.14em;
|
||||
font-weight: 700;
|
||||
font-size: 18px;
|
||||
line-height: 1.1;
|
||||
text-shadow: 0 1px 0 color-mix(in oklab, var(--frame-border) 55%, transparent);
|
||||
}
|
||||
|
||||
.brand__hint {
|
||||
margin-top: 2px;
|
||||
font-size: 12px;
|
||||
color: var(--muted);
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.titlebar__actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.titlebar__cta {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 8px 12px 8px 10px;
|
||||
border-radius: 12px;
|
||||
background:
|
||||
linear-gradient(140deg, color-mix(in oklab, var(--accent) 10%, transparent), transparent 60%),
|
||||
color-mix(in oklab, var(--panel) 92%, transparent);
|
||||
border: var(--border) solid color-mix(in oklab, var(--frame-border) 80%, transparent);
|
||||
color: var(--text);
|
||||
text-decoration: none;
|
||||
box-shadow:
|
||||
0 6px 0 -3px rgba(0, 0, 0, 0.25),
|
||||
inset 0 0 0 1px color-mix(in oklab, var(--panel2) 55%, transparent);
|
||||
}
|
||||
|
||||
.titlebar__cta:hover {
|
||||
border-color: color-mix(in oklab, var(--accent2) 45%, transparent);
|
||||
box-shadow:
|
||||
0 0 0 2px color-mix(in oklab, var(--accent2) 30%, transparent),
|
||||
0 6px 0 -3px rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
.titlebar__cta:active {
|
||||
transform: translateY(1px);
|
||||
box-shadow: 0 4px 0 -3px rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
.titlebar__cta:focus-visible {
|
||||
outline: 3px solid color-mix(in oklab, var(--accent2) 60%, transparent);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
.titlebar__cta--accent {
|
||||
background:
|
||||
linear-gradient(120deg, color-mix(in oklab, var(--accent) 22%, transparent), transparent 70%),
|
||||
color-mix(in oklab, var(--panel) 88%, transparent);
|
||||
border-color: color-mix(in oklab, var(--accent) 60%, var(--frame-border));
|
||||
}
|
||||
|
||||
.titlebar__cta-label {
|
||||
font-family: var(--font-pixel);
|
||||
letter-spacing: 0.12em;
|
||||
font-size: 12px;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.titlebar__cta-meta {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 20px;
|
||||
padding: 0 8px;
|
||||
border-radius: 999px;
|
||||
font-size: 11px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
background: var(--code-bg);
|
||||
color: var(--code-accent);
|
||||
border: 1px solid color-mix(in oklab, var(--code-accent) 30%, transparent);
|
||||
box-shadow: inset 0 0 12px color-mix(in oklab, var(--code-accent) 25%, transparent);
|
||||
}
|
||||
|
||||
.theme-toggle {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 9px 10px;
|
||||
border-radius: 12px;
|
||||
background: color-mix(in oklab, var(--panel) 92%, transparent);
|
||||
border: var(--border) solid var(--frame-border);
|
||||
color: var(--text);
|
||||
cursor: pointer;
|
||||
box-shadow: 0 6px 0 -3px rgba(0, 0, 0, 0.25);
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.theme-toggle:active {
|
||||
transform: translateY(1px);
|
||||
box-shadow: 0 4px 0 -3px rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
.theme-toggle__key {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 36px;
|
||||
height: 28px;
|
||||
border-radius: 9px;
|
||||
background: var(--code-bg);
|
||||
color: var(--code-accent);
|
||||
border: 1px solid color-mix(in oklab, var(--code-accent) 30%, transparent);
|
||||
font-weight: 700;
|
||||
font-size: 12px;
|
||||
letter-spacing: 0.06em;
|
||||
text-shadow: 0 0 14px color-mix(in oklab, var(--code-accent) 55%, transparent);
|
||||
}
|
||||
|
||||
.theme-toggle__label {
|
||||
font-family: var(--font-pixel);
|
||||
letter-spacing: 0.12em;
|
||||
font-size: 12px;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.theme-toggle:focus-visible {
|
||||
outline: 3px solid color-mix(in oklab, var(--accent2) 60%, transparent);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
.shell__nav {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 10px;
|
||||
padding: 10px 14px 12px;
|
||||
border-top: 1px solid color-mix(in oklab, var(--frame-border) 25%, transparent);
|
||||
background: linear-gradient(180deg, transparent, color-mix(in oklab, var(--panel2) 78%, transparent));
|
||||
}
|
||||
|
||||
.nav {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.nav__link {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 6px 10px;
|
||||
border-radius: 999px;
|
||||
text-decoration: none;
|
||||
color: var(--text);
|
||||
background: color-mix(in oklab, var(--panel) 85%, transparent);
|
||||
border: 1px solid color-mix(in oklab, var(--frame-border) 20%, transparent);
|
||||
}
|
||||
|
||||
.nav__link:hover {
|
||||
border-color: color-mix(in oklab, var(--accent2) 45%, transparent);
|
||||
box-shadow: 0 0 0 2px color-mix(in oklab, var(--accent2) 30%, transparent);
|
||||
}
|
||||
|
||||
.nav__chev {
|
||||
color: var(--accent);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.shell__status {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
color: var(--muted);
|
||||
font-size: 12px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.status__dot {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 999px;
|
||||
background: radial-gradient(circle at 30% 30%, var(--accent2), color-mix(in oklab, var(--accent2) 30%, #000));
|
||||
box-shadow: 0 0 0 2px color-mix(in oklab, var(--accent2) 18%, transparent), 0 0 18px color-mix(in oklab, var(--accent2) 50%, transparent);
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 18px 16px 48px;
|
||||
}
|
||||
|
||||
.terminal {
|
||||
position: relative;
|
||||
max-width: 1120px;
|
||||
margin: 0 auto;
|
||||
border-radius: var(--radius);
|
||||
border: var(--border) solid var(--frame-border);
|
||||
background: linear-gradient(180deg, color-mix(in oklab, var(--panel) 92%, transparent), color-mix(in oklab, var(--panel2) 86%, transparent));
|
||||
box-shadow: var(--shadow-px);
|
||||
padding: 18px 16px 16px;
|
||||
}
|
||||
|
||||
.terminal__prompt {
|
||||
display: block;
|
||||
padding: 10px 12px;
|
||||
border-radius: var(--radius-sm);
|
||||
background: var(--code-bg);
|
||||
color: var(--code-fg);
|
||||
border: 1px solid color-mix(in oklab, var(--frame-border) 18%, transparent);
|
||||
overflow-x: auto;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.prompt__user {
|
||||
color: var(--code-accent);
|
||||
text-shadow: 0 0 16px color-mix(in oklab, var(--code-accent) 52%, transparent);
|
||||
}
|
||||
|
||||
.prompt__host {
|
||||
color: color-mix(in oklab, var(--code-fg) 92%, var(--accent2));
|
||||
}
|
||||
|
||||
.prompt__path {
|
||||
color: color-mix(in oklab, var(--code-fg) 78%, var(--link));
|
||||
}
|
||||
|
||||
.prompt__cmd {
|
||||
margin-left: 8px;
|
||||
color: color-mix(in oklab, var(--code-fg) 90%, var(--accent));
|
||||
}
|
||||
|
||||
.terminal__summary {
|
||||
margin: 12px 2px 0;
|
||||
color: var(--muted);
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.terminal__meta {
|
||||
margin: 12px 2px 0;
|
||||
padding: 12px 12px;
|
||||
border-radius: var(--radius-sm);
|
||||
border: 1px dashed color-mix(in oklab, var(--frame-border) 25%, transparent);
|
||||
background: color-mix(in oklab, var(--panel) 76%, transparent);
|
||||
color: var(--faint);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.terminal__meta summary {
|
||||
cursor: pointer;
|
||||
font-family: var(--font-pixel);
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.terminal__meta ul {
|
||||
margin: 10px 0 0 18px;
|
||||
}
|
||||
|
||||
.terminal__footer {
|
||||
margin-top: 22px;
|
||||
padding-top: 16px;
|
||||
border-top: 1px solid color-mix(in oklab, var(--frame-border) 20%, transparent);
|
||||
color: var(--muted);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.footer__actions {
|
||||
margin-top: 14px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.terminal__footer a {
|
||||
color: var(--link);
|
||||
text-decoration: none;
|
||||
border-bottom: 1px dotted color-mix(in oklab, var(--link) 55%, transparent);
|
||||
}
|
||||
|
||||
.terminal__footer a:hover {
|
||||
color: var(--link2);
|
||||
border-bottom-color: color-mix(in oklab, var(--link2) 75%, transparent);
|
||||
}
|
||||
|
||||
.footer__hint {
|
||||
margin-top: 8px;
|
||||
color: var(--faint);
|
||||
}
|
||||
|
||||
kbd {
|
||||
font-family: var(--font-body);
|
||||
font-size: 0.9em;
|
||||
padding: 2px 6px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid color-mix(in oklab, var(--frame-border) 18%, transparent);
|
||||
background: color-mix(in oklab, var(--panel) 65%, transparent);
|
||||
box-shadow: 0 6px 0 -4px rgba(0, 0, 0, 0.18);
|
||||
}
|
||||
|
||||
@supports not (color: color-mix(in oklab, black, white)) {
|
||||
body::before,
|
||||
body::after {
|
||||
opacity: 0.2;
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
const THEME_STORAGE_KEY = "openclaw:theme";
|
||||
|
||||
function safeGet(key) {
|
||||
try {
|
||||
return localStorage.getItem(key);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function safeSet(key, value) {
|
||||
try {
|
||||
localStorage.setItem(key, value);
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
function preferredTheme() {
|
||||
const stored = safeGet(THEME_STORAGE_KEY);
|
||||
if (stored === "light" || stored === "dark") return stored;
|
||||
return window.matchMedia?.("(prefers-color-scheme: dark)").matches ? "dark" : "light";
|
||||
}
|
||||
|
||||
function applyTheme(theme) {
|
||||
document.documentElement.dataset.theme = theme;
|
||||
|
||||
const toggle = document.querySelector("[data-theme-toggle]");
|
||||
const label = document.querySelector("[data-theme-label]");
|
||||
|
||||
if (toggle instanceof HTMLButtonElement) toggle.setAttribute("aria-pressed", theme === "dark" ? "true" : "false");
|
||||
if (label) label.textContent = theme === "dark" ? "dark" : "light";
|
||||
}
|
||||
|
||||
function toggleTheme() {
|
||||
const current = document.documentElement.dataset.theme === "dark" ? "dark" : "light";
|
||||
const next = current === "dark" ? "light" : "dark";
|
||||
safeSet(THEME_STORAGE_KEY, next);
|
||||
applyTheme(next);
|
||||
}
|
||||
|
||||
applyTheme(preferredTheme());
|
||||
|
||||
document.addEventListener("click", (event) => {
|
||||
const target = event.target;
|
||||
const button = target instanceof Element ? target.closest("[data-theme-toggle]") : null;
|
||||
if (button) toggleTheme();
|
||||
});
|
||||
|
||||
document.addEventListener("keydown", (event) => {
|
||||
if (event.key === "F2") {
|
||||
event.preventDefault();
|
||||
toggleTheme();
|
||||
}
|
||||
});
|
||||
@@ -61,6 +61,9 @@ openclaw devices revoke --device <deviceId> --role node
|
||||
- `--timeout <ms>`: RPC timeout.
|
||||
- `--json`: JSON output (recommended for scripting).
|
||||
|
||||
Note: when you set `--url`, the CLI does not fall back to config or environment credentials.
|
||||
Pass `--token` or `--password` explicitly. Missing explicit credentials is an error.
|
||||
|
||||
## Notes
|
||||
|
||||
- Token rotation returns a new token (sensitive). Treat it like a secret.
|
||||
|
||||
@@ -78,6 +78,9 @@ Shared options (where supported):
|
||||
- `--timeout <ms>`: timeout/budget (varies per command).
|
||||
- `--expect-final`: wait for a “final” response (agent calls).
|
||||
|
||||
Note: when you set `--url`, the CLI does not fall back to config or environment credentials.
|
||||
Pass `--token` or `--password` explicitly. Missing explicit credentials is an error.
|
||||
|
||||
### `gateway health`
|
||||
|
||||
```bash
|
||||
|
||||
@@ -715,6 +715,8 @@ openclaw logs --no-color
|
||||
### `gateway <subcommand>`
|
||||
|
||||
Gateway CLI helpers (use `--url`, `--token`, `--password`, `--timeout`, `--expect-final` for RPC subcommands).
|
||||
When you pass `--url`, the CLI does not auto-apply config or environment credentials.
|
||||
Include `--token` or `--password` explicitly. Missing explicit credentials is an error.
|
||||
|
||||
Subcommands:
|
||||
|
||||
|
||||
53
docs/concepts/features.md
Normal file
53
docs/concepts/features.md
Normal file
@@ -0,0 +1,53 @@
|
||||
---
|
||||
summary: "OpenClaw capabilities across channels, routing, media, and UX."
|
||||
read_when:
|
||||
- You want a full list of what OpenClaw supports
|
||||
title: "Features"
|
||||
---
|
||||
|
||||
## Highlights
|
||||
|
||||
<Columns>
|
||||
<Card title="Channels" icon="message-square">
|
||||
WhatsApp, Telegram, Discord, and iMessage with a single Gateway.
|
||||
</Card>
|
||||
<Card title="Plugins" icon="plug">
|
||||
Add Mattermost and more with extensions.
|
||||
</Card>
|
||||
<Card title="Routing" icon="route">
|
||||
Multi-agent routing with isolated sessions.
|
||||
</Card>
|
||||
<Card title="Media" icon="image">
|
||||
Images, audio, and documents in and out.
|
||||
</Card>
|
||||
<Card title="Apps and UI" icon="monitor">
|
||||
Web Control UI and macOS companion app.
|
||||
</Card>
|
||||
<Card title="Mobile nodes" icon="smartphone">
|
||||
iOS and Android nodes with Canvas support.
|
||||
</Card>
|
||||
</Columns>
|
||||
|
||||
## Full list
|
||||
|
||||
- WhatsApp integration via WhatsApp Web (Baileys)
|
||||
- Telegram bot support (grammY)
|
||||
- Discord bot support (channels.discord.js)
|
||||
- Mattermost bot support (plugin)
|
||||
- iMessage integration via local imsg CLI (macOS)
|
||||
- Agent bridge for Pi in RPC mode with tool streaming
|
||||
- Streaming and chunking for long responses
|
||||
- Multi-agent routing for isolated sessions per workspace or sender
|
||||
- Subscription auth for Anthropic and OpenAI via OAuth
|
||||
- Sessions: direct chats collapse into shared `main`; groups are isolated
|
||||
- Group chat support with mention based activation
|
||||
- Media support for images, audio, and documents
|
||||
- Optional voice note transcription hook
|
||||
- WebChat and macOS menu bar app
|
||||
- iOS node with pairing and Canvas surface
|
||||
- Android node with pairing, Canvas, chat, and camera
|
||||
|
||||
<Note>
|
||||
Legacy Claude, Codex, Gemini, and Opencode paths have been removed. Pi is the only
|
||||
coding agent path.
|
||||
</Note>
|
||||
@@ -148,7 +148,7 @@ Details: [Thinking + reasoning directives](/tools/thinking) and [Token use](/tok
|
||||
|
||||
Outbound message formatting is centralized in `messages`:
|
||||
|
||||
- `messages.responsePrefix` (outbound prefix) and `channels.whatsapp.messagePrefix` (WhatsApp inbound prefix)
|
||||
- `messages.responsePrefix`, `channels.<channel>.responsePrefix`, and `channels.<channel>.accounts.<id>.responsePrefix` (outbound prefix cascade), plus `channels.whatsapp.messagePrefix` (WhatsApp inbound prefix)
|
||||
- Reply threading via `replyToMode` and per-channel defaults
|
||||
|
||||
Details: [Configuration](/gateway/configuration#messages) and channel docs.
|
||||
|
||||
4
docs/custom.css
Normal file
4
docs/custom.css
Normal file
@@ -0,0 +1,4 @@
|
||||
#content-area h1:first-of-type,
|
||||
.prose h1:first-of-type {
|
||||
display: none !important;
|
||||
}
|
||||
@@ -2,28 +2,41 @@
|
||||
"$schema": "https://mintlify.com/docs.json",
|
||||
"name": "OpenClaw",
|
||||
"theme": "mint",
|
||||
"icons": {
|
||||
"library": "lucide"
|
||||
},
|
||||
"logo": {
|
||||
"light": "/assets/pixel-lobster.svg",
|
||||
"dark": "/assets/pixel-lobster.svg"
|
||||
},
|
||||
"fonts": {
|
||||
"body": {
|
||||
"family": "Fragment Mono"
|
||||
},
|
||||
"heading": {
|
||||
"family": "DM Sans"
|
||||
}
|
||||
},
|
||||
"favicon": "/assets/pixel-lobster.svg",
|
||||
"colors": {
|
||||
"primary": "#FF5A36"
|
||||
"primary": "#FF5A36",
|
||||
"dark": "#FF5A36",
|
||||
"light": "#FF8A6B"
|
||||
},
|
||||
"navbar": {
|
||||
"links": [
|
||||
{
|
||||
"label": "GitHub",
|
||||
"href": "https://github.com/openclaw/openclaw",
|
||||
"icon": "github"
|
||||
},
|
||||
{
|
||||
"label": "Releases",
|
||||
"href": "https://github.com/openclaw/openclaw/releases",
|
||||
"icon": "package"
|
||||
}
|
||||
]
|
||||
},
|
||||
"topbarLinks": [
|
||||
{
|
||||
"name": "中文",
|
||||
"url": "/zh-CN"
|
||||
},
|
||||
{
|
||||
"name": "GitHub",
|
||||
"url": "https://github.com/openclaw/openclaw"
|
||||
},
|
||||
{
|
||||
"name": "Releases",
|
||||
"url": "https://github.com/openclaw/openclaw/releases"
|
||||
}
|
||||
],
|
||||
"redirects": [
|
||||
{
|
||||
"source": "/cron",
|
||||
@@ -720,7 +733,7 @@
|
||||
"groups": [
|
||||
{
|
||||
"group": "Overview",
|
||||
"pages": ["index", "start/showcase", "start/lore"]
|
||||
"pages": ["index", "concepts/features", "start/showcase", "start/lore"]
|
||||
},
|
||||
{
|
||||
"group": "Installation",
|
||||
@@ -740,12 +753,14 @@
|
||||
"group": "Setup",
|
||||
"pages": [
|
||||
"start/getting-started",
|
||||
"start/quickstart",
|
||||
"start/wizard",
|
||||
"start/setup",
|
||||
"start/onboarding",
|
||||
"start/pairing",
|
||||
"start/openclaw",
|
||||
"start/hubs"
|
||||
"start/hubs",
|
||||
"start/docs-directory"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -988,7 +1003,12 @@
|
||||
},
|
||||
{
|
||||
"group": "Networking and discovery",
|
||||
"pages": ["gateway/pairing", "gateway/discovery", "gateway/bonjour"]
|
||||
"pages": [
|
||||
"gateway/network-model",
|
||||
"gateway/pairing",
|
||||
"gateway/discovery",
|
||||
"gateway/bonjour"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -1114,6 +1134,10 @@
|
||||
"token-use"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Project",
|
||||
"pages": ["reference/credits"]
|
||||
},
|
||||
{
|
||||
"group": "Release notes",
|
||||
"pages": ["reference/RELEASING", "reference/test"]
|
||||
|
||||
@@ -1517,6 +1517,25 @@ See [Messages](/concepts/messages) for queueing, sessions, and streaming context
|
||||
`responsePrefix` is applied to **all outbound replies** (tool summaries, block
|
||||
streaming, final replies) across channels unless already present.
|
||||
|
||||
Overrides can be configured per channel and per account:
|
||||
|
||||
- `channels.<channel>.responsePrefix`
|
||||
- `channels.<channel>.accounts.<id>.responsePrefix`
|
||||
|
||||
Resolution order (most specific wins):
|
||||
|
||||
1. `channels.<channel>.accounts.<id>.responsePrefix`
|
||||
2. `channels.<channel>.responsePrefix`
|
||||
3. `messages.responsePrefix`
|
||||
|
||||
Semantics:
|
||||
|
||||
- `undefined` falls through to the next level.
|
||||
- `""` explicitly disables the prefix and stops the cascade.
|
||||
- `"auto"` derives `[{identity.name}]` for the routed agent.
|
||||
|
||||
Overrides apply to all channels, including extensions, and to every outbound reply kind.
|
||||
|
||||
If `messages.responsePrefix` is unset, no prefix is applied by default. WhatsApp self-chat
|
||||
replies are the exception: they default to `[{identity.name}]` when set, otherwise
|
||||
`[openclaw]`, so same-phone conversations stay legible.
|
||||
|
||||
@@ -87,6 +87,7 @@ and logged; a message that is only `HEARTBEAT_OK` is dropped.
|
||||
includeReasoning: false, // default: false (deliver separate Reasoning: message when available)
|
||||
target: "last", // last | none | <channel id> (core or plugin, e.g. "bluebubbles")
|
||||
to: "+15551234567", // optional channel-specific override
|
||||
accountId: "ops-bot", // optional multi-account channel id
|
||||
prompt: "Read HEARTBEAT.md if it exists (workspace context). Follow it strictly. Do not infer or repeat old tasks from prior chats. If nothing needs attention, reply HEARTBEAT_OK.",
|
||||
ackMaxChars: 300, // max chars allowed after HEARTBEAT_OK
|
||||
},
|
||||
@@ -136,6 +137,35 @@ Example: two agents, only the second agent runs heartbeats.
|
||||
}
|
||||
```
|
||||
|
||||
### Multi account example
|
||||
|
||||
Use `accountId` to target a specific account on multi-account channels like Telegram:
|
||||
|
||||
```json5
|
||||
{
|
||||
agents: {
|
||||
list: [
|
||||
{
|
||||
id: "ops",
|
||||
heartbeat: {
|
||||
every: "1h",
|
||||
target: "telegram",
|
||||
to: "12345678",
|
||||
accountId: "ops-bot",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
channels: {
|
||||
telegram: {
|
||||
accounts: {
|
||||
"ops-bot": { botToken: "YOUR_TELEGRAM_BOT_TOKEN" },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### Field notes
|
||||
|
||||
- `every`: heartbeat interval (duration string; default unit = minutes).
|
||||
@@ -150,6 +180,7 @@ Example: two agents, only the second agent runs heartbeats.
|
||||
- explicit channel: `whatsapp` / `telegram` / `discord` / `googlechat` / `slack` / `msteams` / `signal` / `imessage`.
|
||||
- `none`: run the heartbeat but **do not deliver** externally.
|
||||
- `to`: optional recipient override (channel-specific id, e.g. E.164 for WhatsApp or a Telegram chat id).
|
||||
- `accountId`: optional account id for multi-account channels. When `target: "last"`, the account id applies to the resolved last channel if it supports accounts; otherwise it is ignored. If the account id does not match a configured account for the resolved channel, delivery is skipped.
|
||||
- `prompt`: overrides the default prompt body (not merged).
|
||||
- `ackMaxChars`: max chars allowed after `HEARTBEAT_OK` before delivery.
|
||||
|
||||
|
||||
17
docs/gateway/network-model.md
Normal file
17
docs/gateway/network-model.md
Normal file
@@ -0,0 +1,17 @@
|
||||
---
|
||||
summary: "How the Gateway, nodes, and canvas host connect."
|
||||
read_when:
|
||||
- You want a concise view of the Gateway networking model
|
||||
title: "Network model"
|
||||
---
|
||||
|
||||
Most operations flow through the Gateway (`openclaw gateway`), a single long-running
|
||||
process that owns channel connections and the WebSocket control plane.
|
||||
|
||||
## Core rules
|
||||
|
||||
- One Gateway per host is recommended. It is the only process allowed to own the WhatsApp Web session. For rescue bots or strict isolation, run multiple gateways with isolated profiles and ports. See [Multiple gateways](/gateway/multiple-gateways).
|
||||
- Loopback first: the Gateway WS defaults to `ws://127.0.0.1:18789`. The wizard generates a gateway token by default, even for loopback. For tailnet access, run `openclaw gateway --bind tailnet --token ...` because tokens are required for non-loopback binds.
|
||||
- Nodes connect to the Gateway WS over LAN, tailnet, or SSH as needed. The legacy TCP bridge is deprecated.
|
||||
- Canvas host is an HTTP file server on `canvasHost.port` (default `18793`) serving `/__openclaw__/canvas/` for node WebViews. See [Gateway configuration](/gateway/configuration) (`canvasHost`).
|
||||
- Remote use is typically SSH tunnel or tailnet VPN. See [Remote access](/gateway/remote) and [Discovery](/gateway/discovery).
|
||||
@@ -80,6 +80,8 @@ With the tunnel up:
|
||||
- `openclaw gateway {status,health,send,agent,call}` can also target the forwarded URL via `--url` when needed.
|
||||
|
||||
Note: replace `18789` with your configured `gateway.port` (or `--port`/`OPENCLAW_GATEWAY_PORT`).
|
||||
Note: when you pass `--url`, the CLI does not fall back to config or environment credentials.
|
||||
Include `--token` or `--password` explicitly. Missing explicit credentials is an error.
|
||||
|
||||
## CLI remote defaults
|
||||
|
||||
|
||||
315
docs/index.md
315
docs/index.md
@@ -1,5 +1,5 @@
|
||||
---
|
||||
summary: "Top-level overview of OpenClaw, features, and purpose"
|
||||
summary: "OpenClaw is a multi-channel gateway for AI agents that runs on any OS."
|
||||
read_when:
|
||||
- Introducing OpenClaw to newcomers
|
||||
title: "OpenClaw"
|
||||
@@ -7,8 +7,6 @@ title: "OpenClaw"
|
||||
|
||||
# OpenClaw 🦞
|
||||
|
||||
> _"EXFOLIATE! EXFOLIATE!"_ — A space lobster, probably
|
||||
|
||||
<p align="center">
|
||||
<img
|
||||
src="/assets/openclaw-logo-text-dark.png"
|
||||
@@ -24,143 +22,98 @@ title: "OpenClaw"
|
||||
/>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<strong>Any OS + WhatsApp/Telegram/Discord/iMessage gateway for AI agents (Pi).</strong><br />
|
||||
Plugins add Mattermost and more.
|
||||
Send a message, get an agent response — from your pocket.
|
||||
</p>
|
||||
> _"EXFOLIATE! EXFOLIATE!"_ — A space lobster, probably
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/openclaw/openclaw">GitHub</a> ·
|
||||
<a href="https://github.com/openclaw/openclaw/releases">Releases</a> ·
|
||||
<a href="/">Docs</a> ·
|
||||
<a href="/start/openclaw">OpenClaw assistant setup</a>
|
||||
<strong>Any OS gateway for AI agents across WhatsApp, Telegram, Discord, iMessage, and more.</strong><br />
|
||||
Send a message, get an agent response from your pocket. Plugins add Mattermost and more.
|
||||
</p>
|
||||
|
||||
OpenClaw bridges WhatsApp (via WhatsApp Web / Baileys), Telegram (Bot API / grammY), Discord (Bot API / channels.discord.js), and iMessage (imsg CLI) to coding agents like [Pi](https://github.com/badlogic/pi-mono). Plugins add Mattermost (Bot API + WebSocket) and more.
|
||||
OpenClaw also powers the OpenClaw assistant.
|
||||
<Columns>
|
||||
<Card title="Get Started" href="/start/getting-started" icon="rocket">
|
||||
Install OpenClaw and bring up the Gateway in minutes.
|
||||
</Card>
|
||||
<Card title="Run the Wizard" href="/start/wizard" icon="sparkles">
|
||||
Guided setup with `openclaw onboard` and pairing flows.
|
||||
</Card>
|
||||
<Card title="Open the Control UI" href="/web/control-ui" icon="layout-dashboard">
|
||||
Launch the browser dashboard for chat, config, and sessions.
|
||||
</Card>
|
||||
</Columns>
|
||||
|
||||
## Start here
|
||||
OpenClaw connects chat apps to coding agents like Pi through a single Gateway process. It powers the OpenClaw assistant and supports local or remote setups.
|
||||
|
||||
- **New install from zero:** [Getting Started](/start/getting-started)
|
||||
- **Guided setup (recommended):** [Wizard](/start/wizard) (`openclaw onboard`)
|
||||
- **Open the dashboard (local Gateway):** http://127.0.0.1:18789/ (or http://localhost:18789/)
|
||||
## How it works
|
||||
|
||||
If the Gateway is running on the same computer, that link opens the browser Control UI
|
||||
immediately. If it fails, start the Gateway first: `openclaw gateway`.
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A["Chat apps + plugins"] --> B["Gateway"]
|
||||
B --> C["Pi agent"]
|
||||
B --> D["CLI"]
|
||||
B --> E["Web Control UI"]
|
||||
B --> F["macOS app"]
|
||||
B --> G["iOS and Android nodes"]
|
||||
```
|
||||
|
||||
## Dashboard (browser Control UI)
|
||||
The Gateway is the single source of truth for sessions, routing, and channel connections.
|
||||
|
||||
The dashboard is the browser Control UI for chat, config, nodes, sessions, and more.
|
||||
Local default: http://127.0.0.1:18789/
|
||||
Remote access: [Web surfaces](/web) and [Tailscale](/gateway/tailscale)
|
||||
## Key capabilities
|
||||
|
||||
<Columns>
|
||||
<Card title="Multi-channel gateway" icon="network">
|
||||
WhatsApp, Telegram, Discord, and iMessage with a single Gateway process.
|
||||
</Card>
|
||||
<Card title="Plugin channels" icon="plug">
|
||||
Add Mattermost and more with extension packages.
|
||||
</Card>
|
||||
<Card title="Multi-agent routing" icon="route">
|
||||
Isolated sessions per agent, workspace, or sender.
|
||||
</Card>
|
||||
<Card title="Media support" icon="image">
|
||||
Send and receive images, audio, and documents.
|
||||
</Card>
|
||||
<Card title="Web Control UI" icon="monitor">
|
||||
Browser dashboard for chat, config, sessions, and nodes.
|
||||
</Card>
|
||||
<Card title="Mobile nodes" icon="smartphone">
|
||||
Pair iOS and Android nodes with Canvas support.
|
||||
</Card>
|
||||
</Columns>
|
||||
|
||||
## Quick start
|
||||
|
||||
<Steps>
|
||||
<Step title="Install OpenClaw">
|
||||
```bash
|
||||
npm install -g openclaw@latest
|
||||
```
|
||||
</Step>
|
||||
<Step title="Onboard and install the service">
|
||||
```bash
|
||||
openclaw onboard --install-daemon
|
||||
```
|
||||
</Step>
|
||||
<Step title="Pair WhatsApp and start the Gateway">
|
||||
```bash
|
||||
openclaw channels login
|
||||
openclaw gateway --port 18789
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
Need the full install and dev setup? See [Quick start](/start/quickstart).
|
||||
|
||||
## Dashboard
|
||||
|
||||
Open the browser Control UI after the Gateway starts.
|
||||
|
||||
- Local default: http://127.0.0.1:18789/
|
||||
- Remote access: [Web surfaces](/web) and [Tailscale](/gateway/tailscale)
|
||||
|
||||
<p align="center">
|
||||
<img src="whatsapp-openclaw.jpg" alt="OpenClaw" width="420" />
|
||||
</p>
|
||||
|
||||
## How it works
|
||||
|
||||
```
|
||||
WhatsApp / Telegram / Discord / iMessage (+ plugins)
|
||||
│
|
||||
▼
|
||||
┌───────────────────────────┐
|
||||
│ Gateway │ ws://127.0.0.1:18789 (loopback-only)
|
||||
│ (single source) │
|
||||
│ │ http://<gateway-host>:18793
|
||||
│ │ /__openclaw__/canvas/ (Canvas host)
|
||||
└───────────┬───────────────┘
|
||||
│
|
||||
├─ Pi agent (RPC)
|
||||
├─ CLI (openclaw …)
|
||||
├─ Chat UI (SwiftUI)
|
||||
├─ macOS app (OpenClaw.app)
|
||||
├─ iOS node via Gateway WS + pairing
|
||||
└─ Android node via Gateway WS + pairing
|
||||
```
|
||||
|
||||
Most operations flow through the **Gateway** (`openclaw gateway`), a single long-running process that owns channel connections and the WebSocket control plane.
|
||||
|
||||
## Network model
|
||||
|
||||
- **One Gateway per host (recommended)**: it is the only process allowed to own the WhatsApp Web session. If you need a rescue bot or strict isolation, run multiple gateways with isolated profiles and ports; see [Multiple gateways](/gateway/multiple-gateways).
|
||||
- **Loopback-first**: Gateway WS defaults to `ws://127.0.0.1:18789`.
|
||||
- The wizard now generates a gateway token by default (even for loopback).
|
||||
- For Tailnet access, run `openclaw gateway --bind tailnet --token ...` (token is required for non-loopback binds).
|
||||
- **Nodes**: connect to the Gateway WebSocket (LAN/tailnet/SSH as needed); legacy TCP bridge is deprecated/removed.
|
||||
- **Canvas host**: HTTP file server on `canvasHost.port` (default `18793`), serving `/__openclaw__/canvas/` for node WebViews; see [Gateway configuration](/gateway/configuration) (`canvasHost`).
|
||||
- **Remote use**: SSH tunnel or tailnet/VPN; see [Remote access](/gateway/remote) and [Discovery](/gateway/discovery).
|
||||
|
||||
## Features (high level)
|
||||
|
||||
- 📱 **WhatsApp Integration** — Uses Baileys for WhatsApp Web protocol
|
||||
- ✈️ **Telegram Bot** — DMs + groups via grammY
|
||||
- 🎮 **Discord Bot** — DMs + guild channels via channels.discord.js
|
||||
- 🧩 **Mattermost Bot (plugin)** — Bot token + WebSocket events
|
||||
- 💬 **iMessage** — Local imsg CLI integration (macOS)
|
||||
- 🤖 **Agent bridge** — Pi (RPC mode) with tool streaming
|
||||
- ⏱️ **Streaming + chunking** — Block streaming + Telegram draft streaming details ([/concepts/streaming](/concepts/streaming))
|
||||
- 🧠 **Multi-agent routing** — Route provider accounts/peers to isolated agents (workspace + per-agent sessions)
|
||||
- 🔐 **Subscription auth** — Anthropic (Claude Pro/Max) + OpenAI (ChatGPT/Codex) via OAuth
|
||||
- 💬 **Sessions** — Direct chats collapse into shared `main` (default); groups are isolated
|
||||
- 👥 **Group Chat Support** — Mention-based by default; owner can toggle `/activation always|mention`
|
||||
- 📎 **Media Support** — Send and receive images, audio, documents
|
||||
- 🎤 **Voice notes** — Optional transcription hook
|
||||
- 🖥️ **WebChat + macOS app** — Local UI + menu bar companion for ops and voice wake
|
||||
- 📱 **iOS node** — Pairs as a node and exposes a Canvas surface
|
||||
- 📱 **Android node** — Pairs as a node and exposes Canvas + Chat + Camera
|
||||
|
||||
Note: legacy Claude/Codex/Gemini/Opencode paths have been removed; Pi is the only coding-agent path.
|
||||
|
||||
## Quick start
|
||||
|
||||
Runtime requirement: **Node ≥ 22**.
|
||||
|
||||
```bash
|
||||
# Recommended: global install (npm/pnpm)
|
||||
npm install -g openclaw@latest
|
||||
# or: pnpm add -g openclaw@latest
|
||||
|
||||
# Onboard + install the service (launchd/systemd user service)
|
||||
openclaw onboard --install-daemon
|
||||
|
||||
# Pair WhatsApp Web (shows QR)
|
||||
openclaw channels login
|
||||
|
||||
# Gateway runs via the service after onboarding; manual run is still possible:
|
||||
openclaw gateway --port 18789
|
||||
```
|
||||
|
||||
Switching between npm and git installs later is easy: install the other flavor and run `openclaw doctor` to update the gateway service entrypoint.
|
||||
|
||||
From source (development):
|
||||
|
||||
```bash
|
||||
git clone https://github.com/openclaw/openclaw.git
|
||||
cd openclaw
|
||||
pnpm install
|
||||
pnpm ui:build # auto-installs UI deps on first run
|
||||
pnpm build
|
||||
openclaw onboard --install-daemon
|
||||
```
|
||||
|
||||
If you don’t have a global install yet, run the onboarding step via `pnpm openclaw ...` from the repo.
|
||||
|
||||
Multi-instance quickstart (optional):
|
||||
|
||||
```bash
|
||||
OPENCLAW_CONFIG_PATH=~/.openclaw/a.json \
|
||||
OPENCLAW_STATE_DIR=~/.openclaw-a \
|
||||
openclaw gateway --port 19001
|
||||
```
|
||||
|
||||
Send a test message (requires a running Gateway):
|
||||
|
||||
```bash
|
||||
openclaw message send --target +15555550123 --message "Hello from OpenClaw"
|
||||
```
|
||||
|
||||
## Configuration (optional)
|
||||
|
||||
Config lives at `~/.openclaw/openclaw.json`.
|
||||
@@ -182,77 +135,45 @@ Example:
|
||||
}
|
||||
```
|
||||
|
||||
## Docs
|
||||
## Start here
|
||||
|
||||
- Start here:
|
||||
- [Docs hubs (all pages linked)](/start/hubs)
|
||||
- [Help](/help) ← _common fixes + troubleshooting_
|
||||
- [Configuration](/gateway/configuration)
|
||||
- [Configuration examples](/gateway/configuration-examples)
|
||||
- [Slash commands](/tools/slash-commands)
|
||||
- [Multi-agent routing](/concepts/multi-agent)
|
||||
- [Updating / rollback](/install/updating)
|
||||
- [Pairing (DM + nodes)](/start/pairing)
|
||||
- [Nix mode](/install/nix)
|
||||
- [OpenClaw assistant setup](/start/openclaw)
|
||||
- [Skills](/tools/skills)
|
||||
- [Skills config](/tools/skills-config)
|
||||
- [Workspace templates](/reference/templates/AGENTS)
|
||||
- [RPC adapters](/reference/rpc)
|
||||
- [Gateway runbook](/gateway)
|
||||
- [Nodes (iOS/Android)](/nodes)
|
||||
- [Web surfaces (Control UI)](/web)
|
||||
- [Discovery + transports](/gateway/discovery)
|
||||
- [Remote access](/gateway/remote)
|
||||
- Providers and UX:
|
||||
- [WebChat](/web/webchat)
|
||||
- [Control UI (browser)](/web/control-ui)
|
||||
- [Telegram](/channels/telegram)
|
||||
- [Discord](/channels/discord)
|
||||
- [Mattermost (plugin)](/channels/mattermost)
|
||||
- [BlueBubbles (iMessage)](/channels/bluebubbles)
|
||||
- [iMessage (legacy)](/channels/imessage)
|
||||
- [Groups](/concepts/groups)
|
||||
- [WhatsApp group messages](/concepts/group-messages)
|
||||
- [Media: images](/nodes/images)
|
||||
- [Media: audio](/nodes/audio)
|
||||
- Companion apps:
|
||||
- [macOS app](/platforms/macos)
|
||||
- [iOS app](/platforms/ios)
|
||||
- [Android app](/platforms/android)
|
||||
- [Windows (WSL2)](/platforms/windows)
|
||||
- [Linux app](/platforms/linux)
|
||||
- Ops and safety:
|
||||
- [Sessions](/concepts/session)
|
||||
- [Cron jobs](/automation/cron-jobs)
|
||||
- [Webhooks](/automation/webhook)
|
||||
- [Gmail hooks (Pub/Sub)](/automation/gmail-pubsub)
|
||||
- [Security](/gateway/security)
|
||||
- [Troubleshooting](/gateway/troubleshooting)
|
||||
<Columns>
|
||||
<Card title="Docs hubs" href="/start/hubs" icon="book-open">
|
||||
All docs and guides, organized by use case.
|
||||
</Card>
|
||||
<Card title="Configuration" href="/gateway/configuration" icon="settings">
|
||||
Core Gateway settings, tokens, and provider config.
|
||||
</Card>
|
||||
<Card title="Remote access" href="/gateway/remote" icon="globe">
|
||||
SSH and tailnet access patterns.
|
||||
</Card>
|
||||
<Card title="Channels" href="/channels/telegram" icon="message-square">
|
||||
Channel-specific setup for WhatsApp, Telegram, Discord, and more.
|
||||
</Card>
|
||||
<Card title="Nodes" href="/nodes" icon="smartphone">
|
||||
iOS and Android nodes with pairing and Canvas.
|
||||
</Card>
|
||||
<Card title="Help" href="/help" icon="life-buoy">
|
||||
Common fixes and troubleshooting entry point.
|
||||
</Card>
|
||||
</Columns>
|
||||
|
||||
## The name
|
||||
## Learn more
|
||||
|
||||
**OpenClaw = CLAW + TARDIS** — because every space lobster needs a time-and-space machine.
|
||||
|
||||
---
|
||||
|
||||
_"We're all just playing with our own prompts."_ — an AI, probably high on tokens
|
||||
|
||||
## Credits
|
||||
|
||||
- **Peter Steinberger** ([@steipete](https://x.com/steipete)) — Creator, lobster whisperer
|
||||
- **Mario Zechner** ([@badlogicc](https://x.com/badlogicgames)) — Pi creator, security pen-tester
|
||||
- **Clawd** — The space lobster who demanded a better name
|
||||
|
||||
## Core Contributors
|
||||
|
||||
- **Maxim Vovshin** (@Hyaxia, 36747317+Hyaxia@users.noreply.github.com) — Blogwatcher skill
|
||||
- **Nacho Iacovino** (@nachoiacovino, nacho.iacovino@gmail.com) — Location parsing (Telegram + WhatsApp)
|
||||
|
||||
## License
|
||||
|
||||
MIT — Free as a lobster in the ocean 🦞
|
||||
|
||||
---
|
||||
|
||||
_"We're all just playing with our own prompts."_ — An AI, probably high on tokens
|
||||
<Columns>
|
||||
<Card title="Full feature list" href="/concepts/features" icon="list">
|
||||
Complete channel, routing, and media capabilities.
|
||||
</Card>
|
||||
<Card title="Multi-agent routing" href="/concepts/multi-agent" icon="route">
|
||||
Workspace isolation and per-agent sessions.
|
||||
</Card>
|
||||
<Card title="Security" href="/gateway/security" icon="shield">
|
||||
Tokens, allowlists, and safety controls.
|
||||
</Card>
|
||||
<Card title="Troubleshooting" href="/gateway/troubleshooting" icon="wrench">
|
||||
Gateway diagnostics and common errors.
|
||||
</Card>
|
||||
<Card title="About and credits" href="/reference/credits" icon="info">
|
||||
Project origins, contributors, and license.
|
||||
</Card>
|
||||
</Columns>
|
||||
|
||||
27
docs/reference/credits.md
Normal file
27
docs/reference/credits.md
Normal file
@@ -0,0 +1,27 @@
|
||||
---
|
||||
summary: "Project origin, contributors, and license."
|
||||
read_when:
|
||||
- You want the project backstory or contributor credits
|
||||
title: "Credits"
|
||||
---
|
||||
|
||||
## The name
|
||||
|
||||
OpenClaw = CLAW + TARDIS, because every space lobster needs a time and space machine.
|
||||
|
||||
## Credits
|
||||
|
||||
- **Peter Steinberger** ([@steipete](https://x.com/steipete)) - Creator, lobster whisperer
|
||||
- **Mario Zechner** ([@badlogicc](https://x.com/badlogicgames)) - Pi creator, security pen tester
|
||||
- **Clawd** - The space lobster who demanded a better name
|
||||
|
||||
## Core contributors
|
||||
|
||||
- **Maxim Vovshin** (@Hyaxia, 36747317+Hyaxia@users.noreply.github.com) - Blogwatcher skill
|
||||
- **Nacho Iacovino** (@nachoiacovino, nacho.iacovino@gmail.com) - Location parsing (Telegram and WhatsApp)
|
||||
|
||||
## License
|
||||
|
||||
MIT - Free as a lobster in the ocean.
|
||||
|
||||
> "We are all just playing with our own prompts." (An AI, probably high on tokens)
|
||||
63
docs/start/docs-directory.md
Normal file
63
docs/start/docs-directory.md
Normal file
@@ -0,0 +1,63 @@
|
||||
---
|
||||
summary: "Curated links to the most used OpenClaw docs."
|
||||
read_when:
|
||||
- You want quick access to key docs pages
|
||||
title: "Docs directory"
|
||||
---
|
||||
|
||||
<Note>
|
||||
For a complete map of the docs, see [Docs hubs](/start/hubs).
|
||||
</Note>
|
||||
|
||||
## Start here
|
||||
|
||||
- [Docs hubs (all pages linked)](/start/hubs)
|
||||
- [Help](/help)
|
||||
- [Configuration](/gateway/configuration)
|
||||
- [Configuration examples](/gateway/configuration-examples)
|
||||
- [Slash commands](/tools/slash-commands)
|
||||
- [Multi-agent routing](/concepts/multi-agent)
|
||||
- [Updating and rollback](/install/updating)
|
||||
- [Pairing (DM and nodes)](/start/pairing)
|
||||
- [Nix mode](/install/nix)
|
||||
- [OpenClaw assistant setup](/start/openclaw)
|
||||
- [Skills](/tools/skills)
|
||||
- [Skills config](/tools/skills-config)
|
||||
- [Workspace templates](/reference/templates/AGENTS)
|
||||
- [RPC adapters](/reference/rpc)
|
||||
- [Gateway runbook](/gateway)
|
||||
- [Nodes (iOS and Android)](/nodes)
|
||||
- [Web surfaces (Control UI)](/web)
|
||||
- [Discovery and transports](/gateway/discovery)
|
||||
- [Remote access](/gateway/remote)
|
||||
|
||||
## Providers and UX
|
||||
|
||||
- [WebChat](/web/webchat)
|
||||
- [Control UI (browser)](/web/control-ui)
|
||||
- [Telegram](/channels/telegram)
|
||||
- [Discord](/channels/discord)
|
||||
- [Mattermost (plugin)](/channels/mattermost)
|
||||
- [BlueBubbles (iMessage)](/channels/bluebubbles)
|
||||
- [iMessage (legacy)](/channels/imessage)
|
||||
- [Groups](/concepts/groups)
|
||||
- [WhatsApp group messages](/concepts/group-messages)
|
||||
- [Media images](/nodes/images)
|
||||
- [Media audio](/nodes/audio)
|
||||
|
||||
## Companion apps
|
||||
|
||||
- [macOS app](/platforms/macos)
|
||||
- [iOS app](/platforms/ios)
|
||||
- [Android app](/platforms/android)
|
||||
- [Windows (WSL2)](/platforms/windows)
|
||||
- [Linux app](/platforms/linux)
|
||||
|
||||
## Operations and safety
|
||||
|
||||
- [Sessions](/concepts/session)
|
||||
- [Cron jobs](/automation/cron-jobs)
|
||||
- [Webhooks](/automation/webhook)
|
||||
- [Gmail hooks (Pub/Sub)](/automation/gmail-pubsub)
|
||||
- [Security](/gateway/security)
|
||||
- [Troubleshooting](/gateway/troubleshooting)
|
||||
@@ -13,11 +13,13 @@ Use these hubs to discover every page, including deep dives and reference docs t
|
||||
|
||||
- [Index](/)
|
||||
- [Getting Started](/start/getting-started)
|
||||
- [Quick start](/start/quickstart)
|
||||
- [Onboarding](/start/onboarding)
|
||||
- [Wizard](/start/wizard)
|
||||
- [Setup](/start/setup)
|
||||
- [Dashboard (local Gateway)](http://127.0.0.1:18789/)
|
||||
- [Help](/help)
|
||||
- [Docs directory](/start/docs-directory)
|
||||
- [Configuration](/gateway/configuration)
|
||||
- [Configuration examples](/gateway/configuration-examples)
|
||||
- [OpenClaw assistant](/start/openclaw)
|
||||
@@ -34,6 +36,7 @@ Use these hubs to discover every page, including deep dives and reference docs t
|
||||
## Core concepts
|
||||
|
||||
- [Architecture](/concepts/architecture)
|
||||
- [Features](/concepts/features)
|
||||
- [Network hub](/network)
|
||||
- [Agent runtime](/concepts/agent)
|
||||
- [Agent workspace](/concepts/agent-workspace)
|
||||
@@ -81,6 +84,7 @@ Use these hubs to discover every page, including deep dives and reference docs t
|
||||
## Gateway + operations
|
||||
|
||||
- [Gateway runbook](/gateway)
|
||||
- [Network model](/gateway/network-model)
|
||||
- [Gateway pairing](/gateway/pairing)
|
||||
- [Gateway lock](/gateway/gateway-lock)
|
||||
- [Background process](/gateway/background-process)
|
||||
@@ -178,6 +182,10 @@ Use these hubs to discover every page, including deep dives and reference docs t
|
||||
- [Research: memory](/experiments/research/memory)
|
||||
- [Model config exploration](/experiments/proposals/model-config)
|
||||
|
||||
## Project
|
||||
|
||||
- [Credits](/reference/credits)
|
||||
|
||||
## Testing + release
|
||||
|
||||
- [Testing](/reference/test)
|
||||
|
||||
81
docs/start/quickstart.md
Normal file
81
docs/start/quickstart.md
Normal file
@@ -0,0 +1,81 @@
|
||||
---
|
||||
summary: "Install OpenClaw, onboard the Gateway, and pair your first channel."
|
||||
read_when:
|
||||
- You want the fastest path from install to a working Gateway
|
||||
title: "Quick start"
|
||||
---
|
||||
|
||||
<Note>
|
||||
OpenClaw requires Node 22 or newer.
|
||||
</Note>
|
||||
|
||||
## Install
|
||||
|
||||
<Tabs>
|
||||
<Tab title="npm">
|
||||
```bash
|
||||
npm install -g openclaw@latest
|
||||
```
|
||||
</Tab>
|
||||
<Tab title="pnpm">
|
||||
```bash
|
||||
pnpm add -g openclaw@latest
|
||||
```
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
## Onboard and run the Gateway
|
||||
|
||||
<Steps>
|
||||
<Step title="Onboard and install the service">
|
||||
```bash
|
||||
openclaw onboard --install-daemon
|
||||
```
|
||||
</Step>
|
||||
<Step title="Pair WhatsApp">
|
||||
```bash
|
||||
openclaw channels login
|
||||
```
|
||||
</Step>
|
||||
<Step title="Start the Gateway">
|
||||
```bash
|
||||
openclaw gateway --port 18789
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
After onboarding, the Gateway runs via the user service. You can still run it manually with `openclaw gateway`.
|
||||
|
||||
<Info>
|
||||
Switching between npm and git installs later is easy. Install the other flavor and run
|
||||
`openclaw doctor` to update the gateway service entrypoint.
|
||||
</Info>
|
||||
|
||||
## From source (development)
|
||||
|
||||
```bash
|
||||
git clone https://github.com/openclaw/openclaw.git
|
||||
cd openclaw
|
||||
pnpm install
|
||||
pnpm ui:build # auto-installs UI deps on first run
|
||||
pnpm build
|
||||
openclaw onboard --install-daemon
|
||||
```
|
||||
|
||||
If you do not have a global install yet, run onboarding via `pnpm openclaw ...` from the repo.
|
||||
|
||||
## Multi instance quickstart (optional)
|
||||
|
||||
```bash
|
||||
OPENCLAW_CONFIG_PATH=~/.openclaw/a.json \
|
||||
OPENCLAW_STATE_DIR=~/.openclaw-a \
|
||||
openclaw gateway --port 19001
|
||||
```
|
||||
|
||||
## Send a test message
|
||||
|
||||
Requires a running Gateway.
|
||||
|
||||
```bash
|
||||
openclaw message send --target +15555550123 --message "Hello from OpenClaw"
|
||||
```
|
||||
@@ -465,6 +465,9 @@ Gateway-backed tools (`canvas`, `nodes`, `cron`):
|
||||
- `gatewayToken` (if auth enabled)
|
||||
- `timeoutMs`
|
||||
|
||||
Note: when `gatewayUrl` is set, include `gatewayToken` explicitly. Tools do not inherit config
|
||||
or environment credentials for overrides, and missing explicit credentials is an error.
|
||||
|
||||
Browser tool:
|
||||
|
||||
- `profile` (optional; defaults to `browser.defaultProfile`)
|
||||
|
||||
@@ -142,6 +142,9 @@ Other Gateway slash commands (for example, `/context`) are forwarded to the Gate
|
||||
- `--thinking <level>`: Override thinking level for sends
|
||||
- `--timeout-ms <ms>`: Agent timeout in ms (defaults to `agents.defaults.timeoutSeconds`)
|
||||
|
||||
Note: when you set `--url`, the TUI does not fall back to config or environment credentials.
|
||||
Pass `--token` or `--password` explicitly. Missing explicit credentials is an error.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
No output after sending a message:
|
||||
|
||||
@@ -201,6 +201,8 @@ Notes:
|
||||
|
||||
- `gatewayUrl` is stored in localStorage after load and removed from the URL.
|
||||
- `token` is stored in localStorage; `password` is kept in memory only.
|
||||
- When `gatewayUrl` is set, the UI does not fall back to config or environment credentials.
|
||||
Provide `token` (or `password`) explicitly. Missing explicit credentials is an error.
|
||||
- Use `wss://` when the Gateway is behind TLS (Tailscale Serve, HTTPS proxy, etc.).
|
||||
- `gatewayUrl` is only accepted in a top-level window (not embedded) to prevent clickjacking.
|
||||
- For cross-origin dev setups (e.g. `pnpm ui:dev` to a remote Gateway), add the UI
|
||||
|
||||
59
docs/zh-CN/concepts/features.md
Normal file
59
docs/zh-CN/concepts/features.md
Normal file
@@ -0,0 +1,59 @@
|
||||
---
|
||||
read_when:
|
||||
- 你想了解 OpenClaw 支持的完整功能列表
|
||||
summary: OpenClaw 在渠道、路由、媒体和用户体验方面的功能。
|
||||
title: 功能
|
||||
x-i18n:
|
||||
generated_at: "2026-02-04T17:53:22Z"
|
||||
model: claude-opus-4-5
|
||||
provider: pi
|
||||
source_hash: 1b6aee0bfda751824cb6b3a99080b4c80c00ffb355a96f9cff1b596d55d15ed4
|
||||
source_path: concepts/features.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
## 亮点
|
||||
|
||||
<Columns>
|
||||
<Card title="渠道" icon="message-square">
|
||||
通过单个 Gateway 网关支持 WhatsApp、Telegram、Discord 和 iMessage。
|
||||
</Card>
|
||||
<Card title="插件" icon="plug">
|
||||
通过扩展添加 Mattermost 等更多平台。
|
||||
</Card>
|
||||
<Card title="路由" icon="route">
|
||||
多智能体路由,支持隔离会话。
|
||||
</Card>
|
||||
<Card title="媒体" icon="image">
|
||||
支持图片、音频和文档的收发。
|
||||
</Card>
|
||||
<Card title="应用与界面" icon="monitor">
|
||||
Web 控制界面和 macOS 配套应用。
|
||||
</Card>
|
||||
<Card title="移动节点" icon="smartphone">
|
||||
iOS 和 Android 节点,支持 Canvas。
|
||||
</Card>
|
||||
</Columns>
|
||||
|
||||
## 完整列表
|
||||
|
||||
- 通过 WhatsApp Web(Baileys)集成 WhatsApp
|
||||
- Telegram 机器人支持(grammY)
|
||||
- Discord 机器人支持(channels.discord.js)
|
||||
- Mattermost 机器人支持(插件)
|
||||
- 通过本地 imsg CLI 集成 iMessage(macOS)
|
||||
- Pi 的智能体桥接,支持 RPC 模式和工具流式传输
|
||||
- 长响应的流式传输和分块处理
|
||||
- 多智能体路由,按工作区或发送者隔离会话
|
||||
- 通过 OAuth 进行 Anthropic 和 OpenAI 的订阅认证
|
||||
- 会话:私信合并为共享的 `main`;群组相互隔离
|
||||
- 群聊支持,通过提及激活
|
||||
- 图片、音频和文档的媒体支持
|
||||
- 可选的语音消息转录钩子
|
||||
- WebChat 和 macOS 菜单栏应用
|
||||
- iOS 节点,支持配对和 Canvas 界面
|
||||
- Android 节点,支持配对、Canvas、聊天和相机
|
||||
|
||||
<Note>
|
||||
旧版 Claude、Codex、Gemini 和 Opencode 路径已被移除。Pi 是唯一的编程智能体路径。
|
||||
</Note>
|
||||
23
docs/zh-CN/gateway/network-model.md
Normal file
23
docs/zh-CN/gateway/network-model.md
Normal file
@@ -0,0 +1,23 @@
|
||||
---
|
||||
read_when:
|
||||
- 你想要简要了解 Gateway 网关的网络模型
|
||||
summary: Gateway 网关、节点和 canvas 主机如何连接。
|
||||
title: 网络模型
|
||||
x-i18n:
|
||||
generated_at: "2026-02-04T17:53:21Z"
|
||||
model: claude-opus-4-5
|
||||
provider: pi
|
||||
source_hash: e3508b884757ef19f425c82e891e2b07e7fd7d985413d569e55ae9b175c91f0f
|
||||
source_path: gateway/network-model.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
大多数操作通过 Gateway 网关(`openclaw gateway`)进行,它是一个长期运行的单一进程,负责管理渠道连接和 WebSocket 控制平面。
|
||||
|
||||
## 核心规则
|
||||
|
||||
- 建议每台主机运行一个 Gateway 网关。它是唯一允许拥有 WhatsApp Web 会话的进程。对于救援机器人或严格隔离的场景,可以使用隔离的配置文件和端口运行多个 Gateway 网关。参见[多 Gateway 网关](/gateway/multiple-gateways)。
|
||||
- 优先使用回环地址:Gateway 网关的 WS 默认为 `ws://127.0.0.1:18789`。即使是回环连接,向导也会默认生成 gateway token。若需通过 tailnet 访问,请运行 `openclaw gateway --bind tailnet --token ...`,因为非回环绑定必须使用 token。
|
||||
- 节点根据需要通过局域网、tailnet 或 SSH 连接到 Gateway 网关的 WS。旧版 TCP 桥接已弃用。
|
||||
- Canvas 主机是一个 HTTP 文件服务器,运行在 `canvasHost.port`(默认 `18793`)上,提供 `/__openclaw__/canvas/` 路径供节点 WebView 使用。参见 [Gateway 网关配置](/gateway/configuration)(`canvasHost`)。
|
||||
- 远程使用通常通过 SSH 隧道或 Tailscale VPN。参见[远程访问](/gateway/remote)和[设备发现](/gateway/discovery)。
|
||||
@@ -1,21 +1,19 @@
|
||||
---
|
||||
read_when:
|
||||
- 向新用户介绍 OpenClaw
|
||||
summary: OpenClaw 的顶层概述、功能和用途
|
||||
summary: OpenClaw 是一个多渠道 AI 智能体 Gateway 网关,可在任何操作系统上运行。
|
||||
title: OpenClaw
|
||||
x-i18n:
|
||||
generated_at: "2026-02-03T10:07:04Z"
|
||||
generated_at: "2026-02-04T17:53:40Z"
|
||||
model: claude-opus-4-5
|
||||
provider: pi
|
||||
source_hash: 1e0923d87f184a7d8b16afa0d0d0214ce27aec0c3e6ffb359e6226f8e5f1a152
|
||||
source_hash: fc8babf7885ef91d526795051376d928599c4cf8aff75400138a0d7d9fa3b75f
|
||||
source_path: index.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
# OpenClaw 🦞
|
||||
|
||||
> _"EXFOLIATE! EXFOLIATE!"_ — 大概是一只太空龙虾说的
|
||||
|
||||
<p align="center">
|
||||
<img
|
||||
src="/assets/openclaw-logo-text-dark.png"
|
||||
@@ -31,149 +29,104 @@ x-i18n:
|
||||
/>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<strong>适用于任何操作系统的 WhatsApp/Telegram/Discord/iMessage AI 智能体(Pi)Gateway 网关。</strong><br />
|
||||
插件可添加 Mattermost 等更多渠道。
|
||||
发送消息,获取智能体响应——尽在口袋中。
|
||||
</p>
|
||||
> _"去壳!去壳!"_ — 大概是一只太空龙虾说的
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/openclaw/openclaw">GitHub</a> ·
|
||||
<a href="https://github.com/openclaw/openclaw/releases">发布版本</a> ·
|
||||
<a href="/">文档</a> ·
|
||||
<a href="/start/openclaw">OpenClaw 助手设置</a>
|
||||
<strong>适用于任何操作系统的 AI 智能体 Gateway 网关,支持 WhatsApp、Telegram、Discord、iMessage 等。</strong><br />
|
||||
发送消息,随时随地获取智能体响应。通过插件可添加 Mattermost 等更多渠道。
|
||||
</p>
|
||||
|
||||
OpenClaw 将 WhatsApp(通过 WhatsApp Web / Baileys)、Telegram(Bot API / grammY)、Discord(Bot API / channels.discord.js)和 iMessage(imsg CLI)桥接到像 [Pi](https://github.com/badlogic/pi-mono) 这样的编程智能体。插件可添加 Mattermost(Bot API + WebSocket)等更多渠道。
|
||||
OpenClaw 也为 OpenClaw 助手提供支持。
|
||||
<Columns>
|
||||
<Card title="入门指南" href="/start/getting-started" icon="rocket">
|
||||
安装 OpenClaw 并在几分钟内启动 Gateway 网关。
|
||||
</Card>
|
||||
<Card title="运行向导" href="/start/wizard" icon="sparkles">
|
||||
通过 `openclaw onboard` 和配对流程进行引导式设置。
|
||||
</Card>
|
||||
<Card title="打开控制界面" href="/web/control-ui" icon="layout-dashboard">
|
||||
启动浏览器仪表板,管理聊天、配置和会话。
|
||||
</Card>
|
||||
</Columns>
|
||||
|
||||
## 从这里开始
|
||||
OpenClaw 通过单个 Gateway 网关进程将聊天应用连接到 Pi 等编程智能体。它为 OpenClaw 助手提供支持,并支持本地或远程部署。
|
||||
|
||||
- **从零开始新安装:** [入门指南](/start/getting-started)
|
||||
- **引导式设置(推荐):** [向导](/start/wizard)(`openclaw onboard`)
|
||||
- **打开仪表板(本地 Gateway 网关):** http://127.0.0.1:18789/(或 http://localhost:18789/)
|
||||
## 工作原理
|
||||
|
||||
如果 Gateway 网关运行在同一台计算机上,该链接会立即打开浏览器控制 UI。
|
||||
如果失败,请先启动 Gateway 网关:`openclaw gateway`。
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A["Chat apps + plugins"] --> B["Gateway"]
|
||||
B --> C["Pi agent"]
|
||||
B --> D["CLI"]
|
||||
B --> E["Web Control UI"]
|
||||
B --> F["macOS app"]
|
||||
B --> G["iOS and Android nodes"]
|
||||
```
|
||||
|
||||
## 仪表板(浏览器控制 UI)
|
||||
Gateway 网关是会话、路由和渠道连接的唯一事实来源。
|
||||
|
||||
仪表板是用于聊天、配置、节点、会话等的浏览器控制 UI。
|
||||
本地默认:http://127.0.0.1:18789/
|
||||
远程访问:[Web 界面](/web) 和 [Tailscale](/gateway/tailscale)
|
||||
## 核心功能
|
||||
|
||||
<Columns>
|
||||
<Card title="多渠道 Gateway 网关" icon="network">
|
||||
通过单个 Gateway 网关进程连接 WhatsApp、Telegram、Discord 和 iMessage。
|
||||
</Card>
|
||||
<Card title="插件渠道" icon="plug">
|
||||
通过扩展包添加 Mattermost 等更多渠道。
|
||||
</Card>
|
||||
<Card title="多智能体路由" icon="route">
|
||||
按智能体、工作区或发送者隔离会话。
|
||||
</Card>
|
||||
<Card title="媒体支持" icon="image">
|
||||
发送和接收图片、音频和文档。
|
||||
</Card>
|
||||
<Card title="Web 控制界面" icon="monitor">
|
||||
浏览器仪表板,用于聊天、配置、会话和节点管理。
|
||||
</Card>
|
||||
<Card title="移动节点" icon="smartphone">
|
||||
配对 iOS 和 Android 节点,支持 Canvas。
|
||||
</Card>
|
||||
</Columns>
|
||||
|
||||
## 快速开始
|
||||
|
||||
<Steps>
|
||||
<Step title="安装 OpenClaw">
|
||||
```bash
|
||||
npm install -g openclaw@latest
|
||||
```
|
||||
</Step>
|
||||
<Step title="新手引导并安装服务">
|
||||
```bash
|
||||
openclaw onboard --install-daemon
|
||||
```
|
||||
</Step>
|
||||
<Step title="配对 WhatsApp 并启动 Gateway 网关">
|
||||
```bash
|
||||
openclaw channels login
|
||||
openclaw gateway --port 18789
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
需要完整的安装和开发环境设置?请参阅[快速开始](/start/quickstart)。
|
||||
|
||||
## 仪表板
|
||||
|
||||
Gateway 网关启动后,打开浏览器控制界面。
|
||||
|
||||
- 本地默认地址:http://127.0.0.1:18789/
|
||||
- 远程访问:[Web 界面](/web)和 [Tailscale](/gateway/tailscale)
|
||||
|
||||
<p align="center">
|
||||
<img src="whatsapp-openclaw.jpg" alt="OpenClaw" width="420" />
|
||||
</p>
|
||||
|
||||
## 工作原理
|
||||
|
||||
```
|
||||
WhatsApp / Telegram / Discord / iMessage(+ 插件)
|
||||
│
|
||||
▼
|
||||
┌───────────────────────────┐
|
||||
│ Gateway 网关 │ ws://127.0.0.1:18789(仅 loopback)
|
||||
│ (单一来源) │
|
||||
│ │ http://<gateway-host>:18793
|
||||
│ │ /__openclaw__/canvas/(Canvas 主机)
|
||||
└───────────┬───────────────┘
|
||||
│
|
||||
├─ Pi 智能体(RPC)
|
||||
├─ CLI(openclaw …)
|
||||
├─ 聊天 UI(SwiftUI)
|
||||
├─ macOS 应用(OpenClaw.app)
|
||||
├─ iOS 节点,通过 Gateway WS + 配对
|
||||
└─ Android 节点,通过 Gateway WS + 配对
|
||||
```
|
||||
|
||||
大多数操作通过 **Gateway 网关**(`openclaw gateway`)进行,这是一个长期运行的单一进程,拥有渠道连接和 WebSocket 控制平面。
|
||||
|
||||
## 网络模型
|
||||
|
||||
- **每台主机一个 Gateway 网关(推荐)**:它是唯一允许拥有 WhatsApp Web 会话的进程。如果你需要救援机器人或严格隔离,请使用隔离的配置文件和端口运行多个 Gateway 网关;参见[多 Gateway 网关](/gateway/multiple-gateways)。
|
||||
- **loopback 优先**:Gateway 网关 WS 默认为 `ws://127.0.0.1:18789`。
|
||||
- 向导现在默认生成 Gateway 网关令牌(即使是 loopback)。
|
||||
- 对于 Tailnet 访问,运行 `openclaw gateway --bind tailnet --token ...`(非 loopback 绑定需要令牌)。
|
||||
- **节点**:连接到 Gateway 网关 WebSocket(根据需要通过 LAN/tailnet/SSH);旧版 TCP 桥接已弃用/移除。
|
||||
- **Canvas 主机**:在 `canvasHost.port`(默认 `18793`)上的 HTTP 文件服务器,为节点 WebView 提供 `/__openclaw__/canvas/`;参见 [Gateway 网关配置](/gateway/configuration)(`canvasHost`)。
|
||||
- **远程使用**:SSH 隧道或 tailnet/VPN;参见[远程访问](/gateway/remote)和[设备发现](/gateway/discovery)。
|
||||
|
||||
## 功能(高级概述)
|
||||
|
||||
- 📱 **WhatsApp 集成** — 使用 Baileys 实现 WhatsApp Web 协议
|
||||
- ✈️ **Telegram 机器人** — 通过 grammY 支持私信 + 群组
|
||||
- 🎮 **Discord 机器人** — 通过 channels.discord.js 支持私信 + 服务器频道
|
||||
- 🧩 **Mattermost 机器人(插件)** — 机器人令牌 + WebSocket 事件
|
||||
- 💬 **iMessage** — 本地 imsg CLI 集成(macOS)
|
||||
- 🤖 **智能体桥接** — Pi(RPC 模式)支持工具流式传输
|
||||
- ⏱️ **流式传输 + 分块** — 分块流式传输 + Telegram 草稿流式传输详情([/concepts/streaming](/concepts/streaming))
|
||||
- 🧠 **多智能体路由** — 将提供商账户/对等方路由到隔离的智能体(工作区 + 每智能体会话)
|
||||
- 🔐 **订阅认证** — 通过 OAuth 支持 Anthropic(Claude Pro/Max)+ OpenAI(ChatGPT/Codex)
|
||||
- 💬 **会话** — 私聊折叠到共享的 `main`(默认);群组是隔离的
|
||||
- 👥 **群聊支持** — 默认基于提及;所有者可切换 `/activation always|mention`
|
||||
- 📎 **媒体支持** — 发送和接收图片、音频、文档
|
||||
- 🎤 **语音消息** — 可选的转录钩子
|
||||
- 🖥️ **WebChat + macOS 应用** — 本地 UI + 用于操作和语音唤醒的菜单栏配套应用
|
||||
- 📱 **iOS 节点** — 作为节点配对并暴露 Canvas 界面
|
||||
- 📱 **Android 节点** — 作为节点配对并暴露 Canvas + 聊天 + 相机
|
||||
|
||||
注意:旧版 Claude/Codex/Gemini/Opencode 路径已移除;Pi 是唯一的编程智能体路径。
|
||||
|
||||
## 快速开始
|
||||
|
||||
运行时要求:**Node ≥ 22**。
|
||||
|
||||
```bash
|
||||
# 推荐:全局安装(npm/pnpm)
|
||||
npm install -g openclaw@latest
|
||||
# 或:pnpm add -g openclaw@latest
|
||||
|
||||
# 新手引导 + 安装服务(launchd/systemd 用户服务)
|
||||
openclaw onboard --install-daemon
|
||||
|
||||
# 配对 WhatsApp Web(显示二维码)
|
||||
openclaw channels login
|
||||
|
||||
# 新手引导后 Gateway 网关通过服务运行;手动运行仍然可行:
|
||||
openclaw gateway --port 18789
|
||||
```
|
||||
|
||||
之后在 npm 和 git 安装之间切换很简单:安装另一种方式并运行 `openclaw doctor` 来更新 Gateway 网关服务入口点。
|
||||
|
||||
从源代码(开发):
|
||||
|
||||
```bash
|
||||
git clone https://github.com/openclaw/openclaw.git
|
||||
cd openclaw
|
||||
pnpm install
|
||||
pnpm ui:build # 首次运行时自动安装 UI 依赖
|
||||
pnpm build
|
||||
openclaw onboard --install-daemon
|
||||
```
|
||||
|
||||
如果你还没有全局安装,请从仓库通过 `pnpm openclaw ...` 运行新手引导步骤。
|
||||
|
||||
多实例快速开始(可选):
|
||||
|
||||
```bash
|
||||
OPENCLAW_CONFIG_PATH=~/.openclaw/a.json \
|
||||
OPENCLAW_STATE_DIR=~/.openclaw-a \
|
||||
openclaw gateway --port 19001
|
||||
```
|
||||
|
||||
发送测试消息(需要运行中的 Gateway 网关):
|
||||
|
||||
```bash
|
||||
openclaw message send --target +15555550123 --message "Hello from OpenClaw"
|
||||
```
|
||||
|
||||
## 配置(可选)
|
||||
|
||||
配置位于 `~/.openclaw/openclaw.json`。
|
||||
配置文件位于 `~/.openclaw/openclaw.json`。
|
||||
|
||||
- 如果你**什么都不做**,OpenClaw 会使用内置的 Pi 二进制文件以 RPC 模式运行,按发送者分会话。
|
||||
- 如果你想锁定它,从 `channels.whatsapp.allowFrom` 开始,以及(对于群组)提及规则。
|
||||
- 如果你**不做任何修改**,OpenClaw 将使用内置的 Pi 二进制文件以 RPC 模式运行,并按发送者创建独立会话。
|
||||
- 如果你想要限制访问,可以从 `channels.whatsapp.allowFrom` 和(针对群组的)提及规则开始配置。
|
||||
|
||||
示例:
|
||||
|
||||
@@ -189,76 +142,45 @@ openclaw message send --target +15555550123 --message "Hello from OpenClaw"
|
||||
}
|
||||
```
|
||||
|
||||
## 文档
|
||||
## 从这里开始
|
||||
|
||||
- 从这里开始:
|
||||
- [文档中心(所有页面链接)](/start/hubs)
|
||||
- [帮助](/help) ← _常见修复 + 故障排除_
|
||||
- [配置](/gateway/configuration)
|
||||
- [配置示例](/gateway/configuration-examples)
|
||||
- [斜杠命令](/tools/slash-commands)
|
||||
- [多智能体路由](/concepts/multi-agent)
|
||||
- [更新/回滚](/install/updating)
|
||||
- [配对(私信 + 节点)](/start/pairing)
|
||||
- [Nix 模式](/install/nix)
|
||||
- [OpenClaw 助手设置](/start/openclaw)
|
||||
- [Skills](/tools/skills)
|
||||
- [Skills 配置](/tools/skills-config)
|
||||
- [工作区模板](/reference/templates/AGENTS)
|
||||
- [RPC 适配器](/reference/rpc)
|
||||
- [Gateway 网关运维手册](/gateway)
|
||||
- [节点(iOS/Android)](/nodes)
|
||||
- [Web 界面(控制 UI)](/web)
|
||||
- [设备发现 + 传输协议](/gateway/discovery)
|
||||
- [远程访问](/gateway/remote)
|
||||
- 提供商和用户体验:
|
||||
- [WebChat](/web/webchat)
|
||||
- [控制 UI(浏览器)](/web/control-ui)
|
||||
- [Telegram](/channels/telegram)
|
||||
- [Discord](/channels/discord)
|
||||
- [Mattermost(插件)](/channels/mattermost)
|
||||
- [iMessage](/channels/imessage)
|
||||
- [群组](/concepts/groups)
|
||||
- [WhatsApp 群组消息](/concepts/group-messages)
|
||||
- [媒体:图片](/nodes/images)
|
||||
- [媒体:音频](/nodes/audio)
|
||||
- 配套应用:
|
||||
- [macOS 应用](/platforms/macos)
|
||||
- [iOS 应用](/platforms/ios)
|
||||
- [Android 应用](/platforms/android)
|
||||
- [Windows(WSL2)](/platforms/windows)
|
||||
- [Linux 应用](/platforms/linux)
|
||||
- 运维和安全:
|
||||
- [会话](/concepts/session)
|
||||
- [定时任务](/automation/cron-jobs)
|
||||
- [Webhooks](/automation/webhook)
|
||||
- [Gmail 钩子(Pub/Sub)](/automation/gmail-pubsub)
|
||||
- [安全性](/gateway/security)
|
||||
- [故障排除](/gateway/troubleshooting)
|
||||
<Columns>
|
||||
<Card title="文档中心" href="/start/hubs" icon="book-open">
|
||||
所有文档和指南,按用例分类。
|
||||
</Card>
|
||||
<Card title="配置" href="/gateway/configuration" icon="settings">
|
||||
核心 Gateway 网关设置、令牌和提供商配置。
|
||||
</Card>
|
||||
<Card title="远程访问" href="/gateway/remote" icon="globe">
|
||||
SSH 和 tailnet 访问模式。
|
||||
</Card>
|
||||
<Card title="渠道" href="/channels/telegram" icon="message-square">
|
||||
WhatsApp、Telegram、Discord 等渠道的具体设置。
|
||||
</Card>
|
||||
<Card title="节点" href="/nodes" icon="smartphone">
|
||||
iOS 和 Android 节点的配对与 Canvas 功能。
|
||||
</Card>
|
||||
<Card title="帮助" href="/help" icon="life-buoy">
|
||||
常见修复方法和故障排除入口。
|
||||
</Card>
|
||||
</Columns>
|
||||
|
||||
## 名称由来
|
||||
## 了解更多
|
||||
|
||||
**OpenClaw = CLAW + TARDIS** — 因为每只太空龙虾都需要一台时空机器。
|
||||
|
||||
---
|
||||
|
||||
_"我们都只是在玩弄自己的提示词。"_ — 一个 AI,可能正处于 token 兴奋状态
|
||||
|
||||
## 致谢
|
||||
|
||||
- **Peter Steinberger**([@steipete](https://x.com/steipete))— 创建者,龙虾低语者
|
||||
- **Mario Zechner**([@badlogicc](https://x.com/badlogicgames))— Pi 创建者,安全渗透测试员
|
||||
- **Clawd** — 那只要求更好名字的太空龙虾
|
||||
|
||||
## 核心贡献者
|
||||
|
||||
- **Maxim Vovshin**(@Hyaxia, 36747317+Hyaxia@users.noreply.github.com)— Blogwatcher skill
|
||||
- **Nacho Iacovino**(@nachoiacovino, nacho.iacovino@gmail.com)— 位置解析(Telegram + WhatsApp)
|
||||
|
||||
## 许可证
|
||||
|
||||
MIT — 像海洋中的龙虾一样自由 🦞
|
||||
|
||||
---
|
||||
|
||||
_"我们都只是在玩弄自己的提示词。"_ — 一个 AI,可能正处于 token 兴奋状态
|
||||
<Columns>
|
||||
<Card title="完整功能列表" href="/concepts/features" icon="list">
|
||||
全部渠道、路由和媒体功能。
|
||||
</Card>
|
||||
<Card title="多智能体路由" href="/concepts/multi-agent" icon="route">
|
||||
工作区隔离和按智能体的会话管理。
|
||||
</Card>
|
||||
<Card title="安全" href="/gateway/security" icon="shield">
|
||||
令牌、白名单和安全控制。
|
||||
</Card>
|
||||
<Card title="故障排除" href="/gateway/troubleshooting" icon="wrench">
|
||||
Gateway 网关诊断和常见错误。
|
||||
</Card>
|
||||
<Card title="关于与致谢" href="/reference/credits" icon="info">
|
||||
项目起源、贡献者和许可证。
|
||||
</Card>
|
||||
</Columns>
|
||||
|
||||
34
docs/zh-CN/reference/credits.md
Normal file
34
docs/zh-CN/reference/credits.md
Normal file
@@ -0,0 +1,34 @@
|
||||
---
|
||||
read_when:
|
||||
- 你想了解项目背景故事或贡献者致谢信息
|
||||
summary: 项目起源、贡献者和许可证。
|
||||
title: 致谢
|
||||
x-i18n:
|
||||
generated_at: "2026-02-04T17:53:19Z"
|
||||
model: claude-opus-4-5
|
||||
provider: pi
|
||||
source_hash: d55e520313e131025b22cb20b3d2fbd44619e1668d09b5bd9d56d7df019bc46c
|
||||
source_path: reference/credits.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
## 名称由来
|
||||
|
||||
OpenClaw = CLAW + TARDIS,因为每只太空龙虾都需要一台时空机器。
|
||||
|
||||
## 致谢
|
||||
|
||||
- **Peter Steinberger** ([@steipete](https://x.com/steipete)) - 创建者,龙虾语者
|
||||
- **Mario Zechner** ([@badlogicc](https://x.com/badlogicgames)) - Pi 创建者,安全渗透测试员
|
||||
- **Clawd** - 那只要求取个更好名字的太空龙虾
|
||||
|
||||
## 核心贡献者
|
||||
|
||||
- **Maxim Vovshin** (@Hyaxia, 36747317+Hyaxia@users.noreply.github.com) - Blogwatcher skill
|
||||
- **Nacho Iacovino** (@nachoiacovino, nacho.iacovino@gmail.com) - 位置解析(Telegram 和 WhatsApp)
|
||||
|
||||
## 许可证
|
||||
|
||||
MIT - 像海洋中的龙虾一样自由。
|
||||
|
||||
> "我们都只是在玩自己的提示词而已。"(某个 AI,大概是 token 吸多了)
|
||||
70
docs/zh-CN/start/docs-directory.md
Normal file
70
docs/zh-CN/start/docs-directory.md
Normal file
@@ -0,0 +1,70 @@
|
||||
---
|
||||
read_when:
|
||||
- 你想快速访问关键文档页面
|
||||
summary: 精选的常用 OpenClaw 文档链接。
|
||||
title: 文档目录
|
||||
x-i18n:
|
||||
generated_at: "2026-02-04T17:53:20Z"
|
||||
model: claude-opus-4-5
|
||||
provider: pi
|
||||
source_hash: 489085dae583ba0690b1b972f037610313973df95813283069c95a06bdc949fa
|
||||
source_path: start/docs-directory.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
<Note>
|
||||
如需查看完整的文档地图,请参阅[文档中心](/start/hubs)。
|
||||
</Note>
|
||||
|
||||
## 从这里开始
|
||||
|
||||
- [文档中心(所有页面链接)](/start/hubs)
|
||||
- [帮助](/help)
|
||||
- [配置](/gateway/configuration)
|
||||
- [配置示例](/gateway/configuration-examples)
|
||||
- [斜杠命令](/tools/slash-commands)
|
||||
- [多智能体路由](/concepts/multi-agent)
|
||||
- [更新与回滚](/install/updating)
|
||||
- [配对(私信和节点)](/start/pairing)
|
||||
- [Nix 模式](/install/nix)
|
||||
- [OpenClaw 助手设置](/start/openclaw)
|
||||
- [Skills](/tools/skills)
|
||||
- [Skills 配置](/tools/skills-config)
|
||||
- [工作区模板](/reference/templates/AGENTS)
|
||||
- [RPC 适配器](/reference/rpc)
|
||||
- [Gateway 网关运维手册](/gateway)
|
||||
- [节点(iOS 和 Android)](/nodes)
|
||||
- [Web 界面(控制面板 UI)](/web)
|
||||
- [设备发现与传输协议](/gateway/discovery)
|
||||
- [远程访问](/gateway/remote)
|
||||
|
||||
## 提供商与用户体验
|
||||
|
||||
- [WebChat](/web/webchat)
|
||||
- [控制面板 UI(浏览器)](/web/control-ui)
|
||||
- [Telegram](/channels/telegram)
|
||||
- [Discord](/channels/discord)
|
||||
- [Mattermost(插件)](/channels/mattermost)
|
||||
- [BlueBubbles (iMessage)](/channels/bluebubbles)
|
||||
- [iMessage(旧版)](/channels/imessage)
|
||||
- [群组](/concepts/groups)
|
||||
- [WhatsApp 群消息](/concepts/group-messages)
|
||||
- [媒体图片](/nodes/images)
|
||||
- [媒体音频](/nodes/audio)
|
||||
|
||||
## 配套应用
|
||||
|
||||
- [macOS 应用](/platforms/macos)
|
||||
- [iOS 应用](/platforms/ios)
|
||||
- [Android 应用](/platforms/android)
|
||||
- [Windows (WSL2)](/platforms/windows)
|
||||
- [Linux 应用](/platforms/linux)
|
||||
|
||||
## 运维与安全
|
||||
|
||||
- [会话](/concepts/session)
|
||||
- [定时任务](/automation/cron-jobs)
|
||||
- [Webhooks](/automation/webhook)
|
||||
- [Gmail 钩子(Pub/Sub)](/automation/gmail-pubsub)
|
||||
- [安全](/gateway/security)
|
||||
- [故障排除](/gateway/troubleshooting)
|
||||
@@ -1,35 +1,37 @@
|
||||
---
|
||||
read_when:
|
||||
- 你想要文档的完整地图
|
||||
summary: 链接到每个 OpenClaw 文档的中心页
|
||||
title: 文档中心
|
||||
- 你想要一份完整的文档地图
|
||||
summary: 链接到每篇 OpenClaw 文档的导航中心
|
||||
title: 文档导航中心
|
||||
x-i18n:
|
||||
generated_at: "2026-02-03T10:10:07Z"
|
||||
generated_at: "2026-02-04T17:55:29Z"
|
||||
model: claude-opus-4-5
|
||||
provider: pi
|
||||
source_hash: 2635f570266e9c4b13436a684eea0819ed10a6276a8ab6caf4f9764c60093a1a
|
||||
source_hash: c4b4572b64d36c9690988b8f964b0712f551ee6491b18a493701a17d2d352cb4
|
||||
source_path: start/hubs.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
# 文档中心
|
||||
# 文档导航中心
|
||||
|
||||
使用这些中心页发现每个页面,包括左侧导航中未显示的深入指南和参考文档。
|
||||
使用这些导航中心发现每一个页面,包括深入解析和参考文档——它们不一定出现在左侧导航栏中。
|
||||
|
||||
## 从这里开始
|
||||
|
||||
- [索引](/)
|
||||
- [入门指南](/start/getting-started)
|
||||
- [快速开始](/start/quickstart)
|
||||
- [新手引导](/start/onboarding)
|
||||
- [向导](/start/wizard)
|
||||
- [设置](/start/setup)
|
||||
- [仪表板(本地 Gateway 网关)](http://127.0.0.1:18789/)
|
||||
- [安装配置](/start/setup)
|
||||
- [仪表盘(本地 Gateway 网关)](http://127.0.0.1:18789/)
|
||||
- [帮助](/help)
|
||||
- [文档目录](/start/docs-directory)
|
||||
- [配置](/gateway/configuration)
|
||||
- [配置示例](/gateway/configuration-examples)
|
||||
- [OpenClaw 助手](/start/openclaw)
|
||||
- [展示案例](/start/showcase)
|
||||
- [传说](/start/lore)
|
||||
- [展示](/start/showcase)
|
||||
- [背景故事](/start/lore)
|
||||
|
||||
## 安装 + 更新
|
||||
|
||||
@@ -41,6 +43,7 @@ x-i18n:
|
||||
## 核心概念
|
||||
|
||||
- [架构](/concepts/architecture)
|
||||
- [功能](/concepts/features)
|
||||
- [网络中心](/network)
|
||||
- [智能体运行时](/concepts/agent)
|
||||
- [智能体工作区](/concepts/agent-workspace)
|
||||
@@ -73,12 +76,13 @@ x-i18n:
|
||||
- [模型提供商中心](/providers/models)
|
||||
- [WhatsApp](/channels/whatsapp)
|
||||
- [Telegram](/channels/telegram)
|
||||
- [Telegram(grammY 笔记)](/channels/grammy)
|
||||
- [Telegram(grammY 注意事项)](/channels/grammy)
|
||||
- [Slack](/channels/slack)
|
||||
- [Discord](/channels/discord)
|
||||
- [Mattermost](/channels/mattermost)(插件)
|
||||
- [Signal](/channels/signal)
|
||||
- [iMessage](/channels/imessage)
|
||||
- [BlueBubbles (iMessage)](/channels/bluebubbles)
|
||||
- [iMessage(旧版)](/channels/imessage)
|
||||
- [位置解析](/channels/location)
|
||||
- [WebChat](/web/webchat)
|
||||
- [Webhooks](/automation/webhook)
|
||||
@@ -87,6 +91,7 @@ x-i18n:
|
||||
## Gateway 网关 + 运维
|
||||
|
||||
- [Gateway 网关运维手册](/gateway)
|
||||
- [网络模型](/gateway/network-model)
|
||||
- [Gateway 网关配对](/gateway/pairing)
|
||||
- [Gateway 网关锁](/gateway/gateway-lock)
|
||||
- [后台进程](/gateway/background-process)
|
||||
@@ -95,8 +100,8 @@ x-i18n:
|
||||
- [Doctor](/gateway/doctor)
|
||||
- [日志](/gateway/logging)
|
||||
- [沙箱隔离](/gateway/sandboxing)
|
||||
- [仪表板](/web/dashboard)
|
||||
- [Control UI](/web/control-ui)
|
||||
- [仪表盘](/web/dashboard)
|
||||
- [控制界面](/web/control-ui)
|
||||
- [远程访问](/gateway/remote)
|
||||
- [远程 Gateway 网关 README](/gateway/remote-gateway-readme)
|
||||
- [Tailscale](/gateway/tailscale)
|
||||
@@ -105,27 +110,27 @@ x-i18n:
|
||||
|
||||
## 工具 + 自动化
|
||||
|
||||
- [工具接口](/tools)
|
||||
- [工具概览](/tools)
|
||||
- [OpenProse](/prose)
|
||||
- [CLI 参考](/cli)
|
||||
- [Exec 工具](/tools/exec)
|
||||
- [提升模式](/tools/elevated)
|
||||
- [提权模式](/tools/elevated)
|
||||
- [定时任务](/automation/cron-jobs)
|
||||
- [Cron vs 心跳](/automation/cron-vs-heartbeat)
|
||||
- [思考 + 详细模式](/tools/thinking)
|
||||
- [定时任务 vs 心跳](/automation/cron-vs-heartbeat)
|
||||
- [思考 + 详细输出](/tools/thinking)
|
||||
- [模型](/concepts/models)
|
||||
- [子智能体](/tools/subagents)
|
||||
- [Agent send CLI](/tools/agent-send)
|
||||
- [终端 UI](/tui)
|
||||
- [终端界面](/tui)
|
||||
- [浏览器控制](/tools/browser)
|
||||
- [浏览器(Linux 故障排除)](/tools/browser-linux-troubleshooting)
|
||||
- [投票](/automation/poll)
|
||||
- [轮询](/automation/poll)
|
||||
|
||||
## 节点、媒体、语音
|
||||
|
||||
- [节点概述](/nodes)
|
||||
- [节点概览](/nodes)
|
||||
- [摄像头](/nodes/camera)
|
||||
- [图像](/nodes/images)
|
||||
- [图片](/nodes/images)
|
||||
- [音频](/nodes/audio)
|
||||
- [位置命令](/nodes/location-command)
|
||||
- [语音唤醒](/nodes/voicewake)
|
||||
@@ -133,22 +138,22 @@ x-i18n:
|
||||
|
||||
## 平台
|
||||
|
||||
- [平台概述](/platforms)
|
||||
- [平台概览](/platforms)
|
||||
- [macOS](/platforms/macos)
|
||||
- [iOS](/platforms/ios)
|
||||
- [Android](/platforms/android)
|
||||
- [Windows(WSL2)](/platforms/windows)
|
||||
- [Windows (WSL2)](/platforms/windows)
|
||||
- [Linux](/platforms/linux)
|
||||
- [Web 界面](/web)
|
||||
|
||||
## macOS 配套应用(高级)
|
||||
|
||||
- [macOS 开发设置](/platforms/mac/dev-setup)
|
||||
- [macOS 开发环境配置](/platforms/mac/dev-setup)
|
||||
- [macOS 菜单栏](/platforms/mac/menu-bar)
|
||||
- [macOS 语音唤醒](/platforms/mac/voicewake)
|
||||
- [macOS 语音悬浮窗](/platforms/mac/voice-overlay)
|
||||
- [macOS WebChat](/platforms/mac/webchat)
|
||||
- [macOS 画布](/platforms/mac/canvas)
|
||||
- [macOS Canvas](/platforms/mac/canvas)
|
||||
- [macOS 子进程](/platforms/mac/child-process)
|
||||
- [macOS 健康检查](/platforms/mac/health)
|
||||
- [macOS 图标](/platforms/mac/icon)
|
||||
@@ -157,7 +162,7 @@ x-i18n:
|
||||
- [macOS 远程](/platforms/mac/remote)
|
||||
- [macOS 签名](/platforms/mac/signing)
|
||||
- [macOS 发布](/platforms/mac/release)
|
||||
- [macOS Gateway 网关(launchd)](/platforms/mac/bundled-gateway)
|
||||
- [macOS Gateway 网关 (launchd)](/platforms/mac/bundled-gateway)
|
||||
- [macOS XPC](/platforms/mac/xpc)
|
||||
- [macOS Skills](/platforms/mac/skills)
|
||||
- [macOS Peekaboo](/platforms/mac/peekaboo)
|
||||
@@ -179,13 +184,17 @@ x-i18n:
|
||||
## 实验(探索性)
|
||||
|
||||
- [新手引导配置协议](/experiments/onboarding-config-protocol)
|
||||
- [Cron 加固笔记](/experiments/plans/cron-add-hardening)
|
||||
- [定时任务加固笔记](/experiments/plans/cron-add-hardening)
|
||||
- [群组策略加固笔记](/experiments/plans/group-policy-hardening)
|
||||
- [研究:记忆](/experiments/research/memory)
|
||||
- [模型配置探索](/experiments/proposals/model-config)
|
||||
|
||||
## 项目
|
||||
|
||||
- [致谢](/reference/credits)
|
||||
|
||||
## 测试 + 发布
|
||||
|
||||
- [测试](/reference/test)
|
||||
- [发布清单](/reference/RELEASING)
|
||||
- [发布检查清单](/reference/RELEASING)
|
||||
- [设备型号](/reference/device-models)
|
||||
|
||||
88
docs/zh-CN/start/quickstart.md
Normal file
88
docs/zh-CN/start/quickstart.md
Normal file
@@ -0,0 +1,88 @@
|
||||
---
|
||||
read_when:
|
||||
- 你希望以最快的方式从安装到运行一个可用的 Gateway 网关
|
||||
summary: 安装 OpenClaw,完成 Gateway 网关新手引导,并配对你的第一个渠道。
|
||||
title: 快速开始
|
||||
x-i18n:
|
||||
generated_at: "2026-02-04T17:53:21Z"
|
||||
model: claude-opus-4-5
|
||||
provider: pi
|
||||
source_hash: 3c5da65996f89913cd115279ae21dcab794eadd14595951b676d8f7864fbbe2d
|
||||
source_path: start/quickstart.md
|
||||
workflow: 15
|
||||
---
|
||||
|
||||
<Note>
|
||||
OpenClaw 需要 Node 22 或更新版本。
|
||||
</Note>
|
||||
|
||||
## 安装
|
||||
|
||||
<Tabs>
|
||||
<Tab title="npm">
|
||||
```bash
|
||||
npm install -g openclaw@latest
|
||||
```
|
||||
</Tab>
|
||||
<Tab title="pnpm">
|
||||
```bash
|
||||
pnpm add -g openclaw@latest
|
||||
```
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
## 新手引导并运行 Gateway 网关
|
||||
|
||||
<Steps>
|
||||
<Step title="新手引导并安装服务">
|
||||
```bash
|
||||
openclaw onboard --install-daemon
|
||||
```
|
||||
</Step>
|
||||
<Step title="配对 WhatsApp">
|
||||
```bash
|
||||
openclaw channels login
|
||||
```
|
||||
</Step>
|
||||
<Step title="启动 Gateway 网关">
|
||||
```bash
|
||||
openclaw gateway --port 18789
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
完成新手引导后,Gateway 网关将通过用户服务运行。你也可以使用 `openclaw gateway` 手动启动。
|
||||
|
||||
<Info>
|
||||
之后在 npm 安装和 git 安装之间切换非常简单。安装另一种方式后,运行
|
||||
`openclaw doctor` 即可更新 Gateway 网关服务入口点。
|
||||
</Info>
|
||||
|
||||
## 从源码安装(开发)
|
||||
|
||||
```bash
|
||||
git clone https://github.com/openclaw/openclaw.git
|
||||
cd openclaw
|
||||
pnpm install
|
||||
pnpm ui:build # 首次运行时会自动安装 UI 依赖
|
||||
pnpm build
|
||||
openclaw onboard --install-daemon
|
||||
```
|
||||
|
||||
如果你还没有全局安装,可以在仓库目录中通过 `pnpm openclaw ...` 运行新手引导。
|
||||
|
||||
## 多实例快速开始(可选)
|
||||
|
||||
```bash
|
||||
OPENCLAW_CONFIG_PATH=~/.openclaw/a.json \
|
||||
OPENCLAW_STATE_DIR=~/.openclaw-a \
|
||||
openclaw gateway --port 19001
|
||||
```
|
||||
|
||||
## 发送测试消息
|
||||
|
||||
需要一个正在运行的 Gateway 网关。
|
||||
|
||||
```bash
|
||||
openclaw message send --target +15555550123 --message "Hello from OpenClaw"
|
||||
```
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@openclaw/bluebubbles",
|
||||
"version": "2026.2.2",
|
||||
"version": "2026.2.3",
|
||||
"description": "OpenClaw BlueBubbles channel plugin",
|
||||
"type": "module",
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { IncomingMessage, ServerResponse } from "node:http";
|
||||
import type { OpenClawConfig } from "openclaw/plugin-sdk";
|
||||
import {
|
||||
createReplyPrefixOptions,
|
||||
logAckFailure,
|
||||
logInboundDrop,
|
||||
logTypingFailure,
|
||||
@@ -2173,10 +2174,17 @@ async function processMessage(
|
||||
}, typingRestartDelayMs);
|
||||
};
|
||||
try {
|
||||
const { onModelSelected, ...prefixOptions } = createReplyPrefixOptions({
|
||||
cfg: config,
|
||||
agentId: route.agentId,
|
||||
channel: "bluebubbles",
|
||||
accountId: account.accountId,
|
||||
});
|
||||
await core.channel.reply.dispatchReplyWithBufferedBlockDispatcher({
|
||||
ctx: ctxPayload,
|
||||
cfg: config,
|
||||
dispatcherOptions: {
|
||||
...prefixOptions,
|
||||
deliver: async (payload, info) => {
|
||||
const rawReplyToId =
|
||||
typeof payload.replyToId === "string" ? payload.replyToId.trim() : "";
|
||||
@@ -2288,6 +2296,7 @@ async function processMessage(
|
||||
},
|
||||
},
|
||||
replyOptions: {
|
||||
onModelSelected,
|
||||
disableBlockStreaming:
|
||||
typeof account.config.blockStreaming === "boolean"
|
||||
? !account.config.blockStreaming
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@openclaw/copilot-proxy",
|
||||
"version": "2026.2.2",
|
||||
"version": "2026.2.3",
|
||||
"description": "OpenClaw Copilot Proxy provider plugin",
|
||||
"type": "module",
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@openclaw/diagnostics-otel",
|
||||
"version": "2026.2.2",
|
||||
"version": "2026.2.3",
|
||||
"description": "OpenClaw diagnostics OpenTelemetry exporter",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@openclaw/discord",
|
||||
"version": "2026.2.2",
|
||||
"version": "2026.2.3",
|
||||
"description": "OpenClaw Discord channel plugin",
|
||||
"type": "module",
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@openclaw/feishu",
|
||||
"version": "2026.2.2",
|
||||
"version": "2026.2.3",
|
||||
"description": "OpenClaw Feishu channel plugin",
|
||||
"type": "module",
|
||||
"devDependencies": {
|
||||
|
||||
@@ -37,6 +37,7 @@ const FeishuAccountSchema = z
|
||||
blockStreaming: z.boolean().optional(),
|
||||
streaming: z.boolean().optional(),
|
||||
mediaMaxMb: z.number().optional(),
|
||||
responsePrefix: z.string().optional(),
|
||||
groups: z.record(z.string(), FeishuGroupSchema.optional()).optional(),
|
||||
})
|
||||
.strict();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@openclaw/google-antigravity-auth",
|
||||
"version": "2026.2.2",
|
||||
"version": "2026.2.3",
|
||||
"description": "OpenClaw Google Antigravity OAuth provider plugin",
|
||||
"type": "module",
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@openclaw/google-gemini-cli-auth",
|
||||
"version": "2026.2.2",
|
||||
"version": "2026.2.3",
|
||||
"description": "OpenClaw Gemini CLI OAuth provider plugin",
|
||||
"type": "module",
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@openclaw/googlechat",
|
||||
"version": "2026.2.2",
|
||||
"version": "2026.2.3",
|
||||
"description": "OpenClaw Google Chat channel plugin",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { IncomingMessage, ServerResponse } from "node:http";
|
||||
import type { OpenClawConfig } from "openclaw/plugin-sdk";
|
||||
import { resolveMentionGatingWithBypass } from "openclaw/plugin-sdk";
|
||||
import { createReplyPrefixOptions, resolveMentionGatingWithBypass } from "openclaw/plugin-sdk";
|
||||
import type {
|
||||
GoogleChatAnnotation,
|
||||
GoogleChatAttachment,
|
||||
@@ -725,10 +725,18 @@ async function processMessageWithPipeline(params: {
|
||||
}
|
||||
}
|
||||
|
||||
const { onModelSelected, ...prefixOptions } = createReplyPrefixOptions({
|
||||
cfg: config,
|
||||
agentId: route.agentId,
|
||||
channel: "googlechat",
|
||||
accountId: route.accountId,
|
||||
});
|
||||
|
||||
await core.channel.reply.dispatchReplyWithBufferedBlockDispatcher({
|
||||
ctx: ctxPayload,
|
||||
cfg: config,
|
||||
dispatcherOptions: {
|
||||
...prefixOptions,
|
||||
deliver: async (payload) => {
|
||||
await deliverGoogleChatReply({
|
||||
payload,
|
||||
@@ -749,6 +757,9 @@ async function processMessageWithPipeline(params: {
|
||||
);
|
||||
},
|
||||
},
|
||||
replyOptions: {
|
||||
onModelSelected,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@openclaw/imessage",
|
||||
"version": "2026.2.2",
|
||||
"version": "2026.2.3",
|
||||
"description": "OpenClaw iMessage channel plugin",
|
||||
"type": "module",
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@openclaw/line",
|
||||
"version": "2026.2.2",
|
||||
"version": "2026.2.3",
|
||||
"description": "OpenClaw LINE channel plugin",
|
||||
"type": "module",
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@openclaw/llm-task",
|
||||
"version": "2026.2.2",
|
||||
"version": "2026.2.3",
|
||||
"description": "OpenClaw JSON-only LLM task plugin",
|
||||
"type": "module",
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@openclaw/lobster",
|
||||
"version": "2026.2.2",
|
||||
"version": "2026.2.3",
|
||||
"description": "Lobster workflow tool plugin (typed pipelines + resumable approvals)",
|
||||
"type": "module",
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# Changelog
|
||||
|
||||
## 2026.2.3
|
||||
|
||||
### Changes
|
||||
|
||||
- Version alignment with core OpenClaw release numbers.
|
||||
|
||||
## 2026.2.2
|
||||
|
||||
### Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@openclaw/matrix",
|
||||
"version": "2026.2.2",
|
||||
"version": "2026.2.3",
|
||||
"description": "OpenClaw Matrix channel plugin",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
|
||||
@@ -51,6 +51,7 @@ export const MatrixConfigSchema = z.object({
|
||||
threadReplies: z.enum(["off", "inbound", "always"]).optional(),
|
||||
textChunkLimit: z.number().optional(),
|
||||
chunkMode: z.enum(["length", "newline"]).optional(),
|
||||
responsePrefix: z.string().optional(),
|
||||
mediaMaxMb: z.number().optional(),
|
||||
autoJoin: z.enum(["always", "allowlist", "off"]).optional(),
|
||||
autoJoinAllowlist: z.array(allowFromEntry).optional(),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { LocationMessageEventContent, MatrixClient } from "@vector-im/matrix-bot-sdk";
|
||||
import {
|
||||
createReplyPrefixContext,
|
||||
createReplyPrefixOptions,
|
||||
createTypingCallbacks,
|
||||
formatAllowlistMatchMeta,
|
||||
logInboundDrop,
|
||||
@@ -579,7 +579,12 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam
|
||||
channel: "matrix",
|
||||
accountId: route.accountId,
|
||||
});
|
||||
const prefixContext = createReplyPrefixContext({ cfg, agentId: route.agentId });
|
||||
const { onModelSelected, ...prefixOptions } = createReplyPrefixOptions({
|
||||
cfg,
|
||||
agentId: route.agentId,
|
||||
channel: "matrix",
|
||||
accountId: route.accountId,
|
||||
});
|
||||
const typingCallbacks = createTypingCallbacks({
|
||||
start: () => sendTypingMatrix(roomId, true, undefined, client),
|
||||
stop: () => sendTypingMatrix(roomId, false, undefined, client),
|
||||
@@ -604,8 +609,7 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam
|
||||
});
|
||||
const { dispatcher, replyOptions, markDispatchIdle } =
|
||||
core.channel.reply.createReplyDispatcherWithTyping({
|
||||
responsePrefix: prefixContext.responsePrefix,
|
||||
responsePrefixContextProvider: prefixContext.responsePrefixContextProvider,
|
||||
...prefixOptions,
|
||||
humanDelay: core.channel.reply.resolveHumanDelayConfig(cfg, route.agentId),
|
||||
deliver: async (payload) => {
|
||||
await deliverMatrixReplies({
|
||||
@@ -635,7 +639,7 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam
|
||||
replyOptions: {
|
||||
...replyOptions,
|
||||
skillFilter: roomConfig?.skills,
|
||||
onModelSelected: prefixContext.onModelSelected,
|
||||
onModelSelected,
|
||||
},
|
||||
});
|
||||
markDispatchIdle();
|
||||
|
||||
@@ -71,6 +71,8 @@ export type MatrixConfig = {
|
||||
textChunkLimit?: number;
|
||||
/** Chunking mode: "length" (default) splits by size; "newline" splits on every newline. */
|
||||
chunkMode?: "length" | "newline";
|
||||
/** Outbound response prefix override for this channel/account. */
|
||||
responsePrefix?: string;
|
||||
/** Max outbound media size in MB. */
|
||||
mediaMaxMb?: number;
|
||||
/** Auto-join invites (always|allowlist|off). Default: always. */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@openclaw/mattermost",
|
||||
"version": "2026.2.2",
|
||||
"version": "2026.2.3",
|
||||
"description": "OpenClaw Mattermost channel plugin",
|
||||
"type": "module",
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import type { OpenClawConfig } from "openclaw/plugin-sdk";
|
||||
import { createReplyPrefixOptions } from "openclaw/plugin-sdk";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { mattermostPlugin } from "./channel.js";
|
||||
|
||||
@@ -44,5 +46,27 @@ describe("mattermostPlugin", () => {
|
||||
});
|
||||
expect(formatted).toEqual(["@alice", "user123", "bot999"]);
|
||||
});
|
||||
|
||||
it("uses account responsePrefix overrides", () => {
|
||||
const cfg: OpenClawConfig = {
|
||||
channels: {
|
||||
mattermost: {
|
||||
responsePrefix: "[Channel]",
|
||||
accounts: {
|
||||
default: { responsePrefix: "[Account]" },
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const prefixContext = createReplyPrefixOptions({
|
||||
cfg,
|
||||
agentId: "main",
|
||||
channel: "mattermost",
|
||||
accountId: "default",
|
||||
});
|
||||
|
||||
expect(prefixContext.responsePrefix).toBe("[Account]");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -27,6 +27,7 @@ const MattermostAccountSchemaBase = z
|
||||
chunkMode: z.enum(["length", "newline"]).optional(),
|
||||
blockStreaming: z.boolean().optional(),
|
||||
blockStreamingCoalesce: BlockStreamingCoalesceSchema.optional(),
|
||||
responsePrefix: z.string().optional(),
|
||||
})
|
||||
.strict();
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import type {
|
||||
RuntimeEnv,
|
||||
} from "openclaw/plugin-sdk";
|
||||
import {
|
||||
createReplyPrefixContext,
|
||||
createReplyPrefixOptions,
|
||||
createTypingCallbacks,
|
||||
logInboundDrop,
|
||||
logTypingFailure,
|
||||
@@ -760,7 +760,12 @@ export async function monitorMattermostProvider(opts: MonitorMattermostOpts = {}
|
||||
accountId: account.accountId,
|
||||
});
|
||||
|
||||
const prefixContext = createReplyPrefixContext({ cfg, agentId: route.agentId });
|
||||
const { onModelSelected, ...prefixOptions } = createReplyPrefixOptions({
|
||||
cfg,
|
||||
agentId: route.agentId,
|
||||
channel: "mattermost",
|
||||
accountId: account.accountId,
|
||||
});
|
||||
|
||||
const typingCallbacks = createTypingCallbacks({
|
||||
start: () => sendTypingIndicator(channelId, threadRootId),
|
||||
@@ -775,8 +780,7 @@ export async function monitorMattermostProvider(opts: MonitorMattermostOpts = {}
|
||||
});
|
||||
const { dispatcher, replyOptions, markDispatchIdle } =
|
||||
core.channel.reply.createReplyDispatcherWithTyping({
|
||||
responsePrefix: prefixContext.responsePrefix,
|
||||
responsePrefixContextProvider: prefixContext.responsePrefixContextProvider,
|
||||
...prefixOptions,
|
||||
humanDelay: core.channel.reply.resolveHumanDelayConfig(cfg, route.agentId),
|
||||
deliver: async (payload: ReplyPayload) => {
|
||||
const mediaUrls = payload.mediaUrls ?? (payload.mediaUrl ? [payload.mediaUrl] : []);
|
||||
@@ -825,7 +829,7 @@ export async function monitorMattermostProvider(opts: MonitorMattermostOpts = {}
|
||||
...replyOptions,
|
||||
disableBlockStreaming:
|
||||
typeof account.blockStreaming === "boolean" ? !account.blockStreaming : undefined,
|
||||
onModelSelected: prefixContext.onModelSelected,
|
||||
onModelSelected,
|
||||
},
|
||||
});
|
||||
markDispatchIdle();
|
||||
|
||||
@@ -42,6 +42,8 @@ export type MattermostAccountConfig = {
|
||||
blockStreaming?: boolean;
|
||||
/** Merge streamed block replies before sending. */
|
||||
blockStreamingCoalesce?: BlockStreamingCoalesceConfig;
|
||||
/** Outbound response prefix override for this channel/account. */
|
||||
responsePrefix?: string;
|
||||
};
|
||||
|
||||
export type MattermostConfig = {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@openclaw/memory-core",
|
||||
"version": "2026.2.2",
|
||||
"version": "2026.2.3",
|
||||
"description": "OpenClaw core memory search plugin",
|
||||
"type": "module",
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@openclaw/memory-lancedb",
|
||||
"version": "2026.2.2",
|
||||
"version": "2026.2.3",
|
||||
"description": "OpenClaw LanceDB-backed long-term memory plugin with auto-recall/capture",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@openclaw/minimax-portal-auth",
|
||||
"version": "2026.2.2",
|
||||
"version": "2026.2.3",
|
||||
"description": "OpenClaw MiniMax Portal OAuth provider plugin",
|
||||
"type": "module",
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# Changelog
|
||||
|
||||
## 2026.2.3
|
||||
|
||||
### Changes
|
||||
|
||||
- Version alignment with core OpenClaw release numbers.
|
||||
|
||||
## 2026.2.2
|
||||
|
||||
### Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@openclaw/msteams",
|
||||
"version": "2026.2.2",
|
||||
"version": "2026.2.3",
|
||||
"description": "OpenClaw Microsoft Teams channel plugin",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
|
||||
@@ -493,6 +493,7 @@ export function createMSTeamsMessageHandler(deps: MSTeamsMessageHandlerDeps) {
|
||||
const { dispatcher, replyOptions, markDispatchIdle } = createMSTeamsReplyDispatcher({
|
||||
cfg,
|
||||
agentId: route.agentId,
|
||||
accountId: route.accountId,
|
||||
runtime,
|
||||
log,
|
||||
adapter,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {
|
||||
createReplyPrefixContext,
|
||||
createReplyPrefixOptions,
|
||||
createTypingCallbacks,
|
||||
logTypingFailure,
|
||||
resolveChannelMediaMaxBytes,
|
||||
@@ -26,6 +26,7 @@ import { getMSTeamsRuntime } from "./runtime.js";
|
||||
export function createMSTeamsReplyDispatcher(params: {
|
||||
cfg: OpenClawConfig;
|
||||
agentId: string;
|
||||
accountId?: string;
|
||||
runtime: RuntimeEnv;
|
||||
log: MSTeamsMonitorLogger;
|
||||
adapter: MSTeamsAdapter;
|
||||
@@ -55,16 +56,17 @@ export function createMSTeamsReplyDispatcher(params: {
|
||||
});
|
||||
},
|
||||
});
|
||||
const prefixContext = createReplyPrefixContext({
|
||||
const { onModelSelected, ...prefixOptions } = createReplyPrefixOptions({
|
||||
cfg: params.cfg,
|
||||
agentId: params.agentId,
|
||||
channel: "msteams",
|
||||
accountId: params.accountId,
|
||||
});
|
||||
const chunkMode = core.channel.text.resolveChunkMode(params.cfg, "msteams");
|
||||
|
||||
const { dispatcher, replyOptions, markDispatchIdle } =
|
||||
core.channel.reply.createReplyDispatcherWithTyping({
|
||||
responsePrefix: prefixContext.responsePrefix,
|
||||
responsePrefixContextProvider: prefixContext.responsePrefixContextProvider,
|
||||
...prefixOptions,
|
||||
humanDelay: core.channel.reply.resolveHumanDelayConfig(params.cfg, params.agentId),
|
||||
deliver: async (payload) => {
|
||||
const tableMode = core.channel.text.resolveMarkdownTableMode({
|
||||
@@ -124,7 +126,7 @@ export function createMSTeamsReplyDispatcher(params: {
|
||||
|
||||
return {
|
||||
dispatcher,
|
||||
replyOptions: { ...replyOptions, onModelSelected: prefixContext.onModelSelected },
|
||||
replyOptions: { ...replyOptions, onModelSelected },
|
||||
markDispatchIdle,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@openclaw/nextcloud-talk",
|
||||
"version": "2026.2.2",
|
||||
"version": "2026.2.3",
|
||||
"description": "OpenClaw Nextcloud Talk channel plugin",
|
||||
"type": "module",
|
||||
"devDependencies": {
|
||||
|
||||
@@ -47,6 +47,7 @@ export const NextcloudTalkAccountSchemaBase = z
|
||||
chunkMode: z.enum(["length", "newline"]).optional(),
|
||||
blockStreaming: z.boolean().optional(),
|
||||
blockStreamingCoalesce: BlockStreamingCoalesceSchema.optional(),
|
||||
responsePrefix: z.string().optional(),
|
||||
mediaMaxMb: z.number().positive().optional(),
|
||||
})
|
||||
.strict();
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import {
|
||||
createReplyPrefixOptions,
|
||||
logInboundDrop,
|
||||
resolveControlCommandGate,
|
||||
type OpenClawConfig,
|
||||
@@ -285,10 +286,18 @@ export async function handleNextcloudTalkInbound(params: {
|
||||
},
|
||||
});
|
||||
|
||||
const { onModelSelected, ...prefixOptions } = createReplyPrefixOptions({
|
||||
cfg: config as OpenClawConfig,
|
||||
agentId: route.agentId,
|
||||
channel: CHANNEL_ID,
|
||||
accountId: account.accountId,
|
||||
});
|
||||
|
||||
await core.channel.reply.dispatchReplyWithBufferedBlockDispatcher({
|
||||
ctx: ctxPayload,
|
||||
cfg: config as OpenClawConfig,
|
||||
dispatcherOptions: {
|
||||
...prefixOptions,
|
||||
deliver: async (payload) => {
|
||||
await deliverNextcloudTalkReply({
|
||||
payload: payload as {
|
||||
@@ -308,6 +317,7 @@ export async function handleNextcloudTalkInbound(params: {
|
||||
},
|
||||
replyOptions: {
|
||||
skillFilter: roomConfig?.skills,
|
||||
onModelSelected,
|
||||
disableBlockStreaming:
|
||||
typeof account.config.blockStreaming === "boolean"
|
||||
? !account.config.blockStreaming
|
||||
|
||||
@@ -68,6 +68,8 @@ export type NextcloudTalkAccountConfig = {
|
||||
blockStreaming?: boolean;
|
||||
/** Merge streamed block replies before sending. */
|
||||
blockStreamingCoalesce?: BlockStreamingCoalesceConfig;
|
||||
/** Outbound response prefix override for this channel/account. */
|
||||
responsePrefix?: string;
|
||||
/** Media upload max size in MB. */
|
||||
mediaMaxMb?: number;
|
||||
};
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# Changelog
|
||||
|
||||
## 2026.2.3
|
||||
|
||||
### Changes
|
||||
|
||||
- Version alignment with core OpenClaw release numbers.
|
||||
|
||||
## 2026.2.2
|
||||
|
||||
### Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@openclaw/nostr",
|
||||
"version": "2026.2.2",
|
||||
"version": "2026.2.3",
|
||||
"description": "OpenClaw Nostr channel plugin for NIP-04 encrypted DMs",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@openclaw/open-prose",
|
||||
"version": "2026.2.2",
|
||||
"version": "2026.2.3",
|
||||
"description": "OpenProse VM skill pack plugin (slash command + telemetry).",
|
||||
"type": "module",
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@openclaw/signal",
|
||||
"version": "2026.2.2",
|
||||
"version": "2026.2.3",
|
||||
"description": "OpenClaw Signal channel plugin",
|
||||
"type": "module",
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@openclaw/slack",
|
||||
"version": "2026.2.2",
|
||||
"version": "2026.2.3",
|
||||
"description": "OpenClaw Slack channel plugin",
|
||||
"type": "module",
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@openclaw/telegram",
|
||||
"version": "2026.2.2",
|
||||
"version": "2026.2.3",
|
||||
"description": "OpenClaw Telegram channel plugin",
|
||||
"type": "module",
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@openclaw/tlon",
|
||||
"version": "2026.2.2",
|
||||
"version": "2026.2.3",
|
||||
"description": "OpenClaw Tlon/Urbit channel plugin",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
|
||||
@@ -23,6 +23,7 @@ export const TlonAccountSchema = z.object({
|
||||
dmAllowlist: z.array(ShipSchema).optional(),
|
||||
autoDiscoverChannels: z.boolean().optional(),
|
||||
showModelSignature: z.boolean().optional(),
|
||||
responsePrefix: z.string().optional(),
|
||||
});
|
||||
|
||||
export const TlonConfigSchema = z.object({
|
||||
@@ -35,6 +36,7 @@ export const TlonConfigSchema = z.object({
|
||||
dmAllowlist: z.array(ShipSchema).optional(),
|
||||
autoDiscoverChannels: z.boolean().optional(),
|
||||
showModelSignature: z.boolean().optional(),
|
||||
responsePrefix: z.string().optional(),
|
||||
authorization: TlonAuthorizationSchema.optional(),
|
||||
defaultAuthorizedShips: z.array(ShipSchema).optional(),
|
||||
accounts: z.record(z.string(), TlonAccountSchema).optional(),
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { RuntimeEnv, ReplyPayload, OpenClawConfig } from "openclaw/plugin-sdk";
|
||||
import { format } from "node:util";
|
||||
import { createReplyPrefixOptions } from "openclaw/plugin-sdk";
|
||||
import { getTlonRuntime } from "../runtime.js";
|
||||
import { normalizeShip, parseChannelNest } from "../targets.js";
|
||||
import { resolveTlonAccount } from "../types.js";
|
||||
@@ -28,6 +29,29 @@ type ChannelAuthorization = {
|
||||
allowedShips?: string[];
|
||||
};
|
||||
|
||||
type UrbitMemo = {
|
||||
author?: string;
|
||||
content?: unknown;
|
||||
sent?: number;
|
||||
};
|
||||
|
||||
type UrbitUpdate = {
|
||||
id?: string | number;
|
||||
response?: {
|
||||
add?: { memo?: UrbitMemo };
|
||||
post?: {
|
||||
id?: string | number;
|
||||
"r-post"?: {
|
||||
set?: { essay?: UrbitMemo };
|
||||
reply?: {
|
||||
id?: string | number;
|
||||
"r-reply"?: { set?: { memo?: UrbitMemo } };
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
function resolveChannelAuthorization(
|
||||
cfg: OpenClawConfig,
|
||||
channelNest: string,
|
||||
@@ -120,15 +144,14 @@ export async function monitorTlonProvider(opts: MonitorTlonOpts = {}): Promise<v
|
||||
runtime.log?.("[tlon] No group channels to monitor (DMs only)");
|
||||
}
|
||||
|
||||
// oxlint-disable-next-line typescript/no-explicit-any
|
||||
const handleIncomingDM = async (update: any) => {
|
||||
const handleIncomingDM = async (update: UrbitUpdate) => {
|
||||
try {
|
||||
const memo = update?.response?.add?.memo;
|
||||
if (!memo) {
|
||||
return;
|
||||
}
|
||||
|
||||
const messageId = update.id as string | undefined;
|
||||
const messageId = update.id != null ? String(update.id) : undefined;
|
||||
if (!processedTracker.mark(messageId)) {
|
||||
return;
|
||||
}
|
||||
@@ -160,25 +183,24 @@ export async function monitorTlonProvider(opts: MonitorTlonOpts = {}): Promise<v
|
||||
}
|
||||
};
|
||||
|
||||
// oxlint-disable-next-line typescript/no-explicit-any
|
||||
const handleIncomingGroupMessage = (channelNest: string) => async (update: any) => {
|
||||
const handleIncomingGroupMessage = (channelNest: string) => async (update: UrbitUpdate) => {
|
||||
try {
|
||||
const parsed = parseChannelNest(channelNest);
|
||||
if (!parsed) {
|
||||
return;
|
||||
}
|
||||
|
||||
const essay = update?.response?.post?.["r-post"]?.set?.essay;
|
||||
const memo = update?.response?.post?.["r-post"]?.reply?.["r-reply"]?.set?.memo;
|
||||
const post = update?.response?.post?.["r-post"];
|
||||
const essay = post?.set?.essay;
|
||||
const memo = post?.reply?.["r-reply"]?.set?.memo;
|
||||
if (!essay && !memo) {
|
||||
return;
|
||||
}
|
||||
|
||||
const content = memo || essay;
|
||||
const isThreadReply = Boolean(memo);
|
||||
const messageId = isThreadReply
|
||||
? update?.response?.post?.["r-post"]?.reply?.id
|
||||
: update?.response?.post?.id;
|
||||
const rawMessageId = isThreadReply ? post?.reply?.id : update?.response?.post?.id;
|
||||
const messageId = rawMessageId != null ? String(rawMessageId) : undefined;
|
||||
|
||||
if (!processedTracker.mark(messageId)) {
|
||||
return;
|
||||
@@ -355,17 +377,19 @@ export async function monitorTlonProvider(opts: MonitorTlonOpts = {}): Promise<v
|
||||
|
||||
const dispatchStartTime = Date.now();
|
||||
|
||||
const responsePrefix = core.channel.reply.resolveEffectiveMessagesConfig(
|
||||
const { onModelSelected, ...prefixOptions } = createReplyPrefixOptions({
|
||||
cfg,
|
||||
route.agentId,
|
||||
).responsePrefix;
|
||||
agentId: route.agentId,
|
||||
channel: "tlon",
|
||||
accountId: route.accountId,
|
||||
});
|
||||
const humanDelay = core.channel.reply.resolveHumanDelayConfig(cfg, route.agentId);
|
||||
|
||||
await core.channel.reply.dispatchReplyWithBufferedBlockDispatcher({
|
||||
ctx: ctxPayload,
|
||||
cfg,
|
||||
dispatcherOptions: {
|
||||
responsePrefix,
|
||||
...prefixOptions,
|
||||
humanDelay,
|
||||
deliver: async (payload: ReplyPayload) => {
|
||||
let replyText = payload.text;
|
||||
@@ -408,6 +432,9 @@ export async function monitorTlonProvider(opts: MonitorTlonOpts = {}): Promise<v
|
||||
);
|
||||
},
|
||||
},
|
||||
replyOptions: {
|
||||
onModelSelected,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# Changelog
|
||||
|
||||
## 2026.2.3
|
||||
|
||||
### Changes
|
||||
|
||||
- Version alignment with core OpenClaw release numbers.
|
||||
|
||||
## 2026.2.2
|
||||
|
||||
### Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@openclaw/twitch",
|
||||
"version": "2026.2.2",
|
||||
"version": "2026.2.3",
|
||||
"description": "OpenClaw Twitch channel plugin",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
|
||||
@@ -26,6 +26,8 @@ const TwitchAccountSchema = z.object({
|
||||
allowedRoles: z.array(TwitchRoleSchema).optional(),
|
||||
/** Require @mention to trigger bot responses */
|
||||
requireMention: z.boolean().optional(),
|
||||
/** Outbound response prefix override for this channel/account. */
|
||||
responsePrefix: z.string().optional(),
|
||||
/** Twitch client secret (required for token refresh via RefreshingAuthProvider) */
|
||||
clientSecret: z.string().optional(),
|
||||
/** Refresh token (required for automatic token refresh) */
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
import type { ReplyPayload, OpenClawConfig } from "openclaw/plugin-sdk";
|
||||
import { createReplyPrefixOptions } from "openclaw/plugin-sdk";
|
||||
import type { TwitchAccountConfig, TwitchChatMessage } from "./types.js";
|
||||
import { checkTwitchAccessControl } from "./access-control.js";
|
||||
import { getOrCreateClientManager } from "./client-manager-registry.js";
|
||||
@@ -103,11 +104,18 @@ async function processTwitchMessage(params: {
|
||||
channel: "twitch",
|
||||
accountId,
|
||||
});
|
||||
const { onModelSelected, ...prefixOptions } = createReplyPrefixOptions({
|
||||
cfg,
|
||||
agentId: route.agentId,
|
||||
channel: "twitch",
|
||||
accountId,
|
||||
});
|
||||
|
||||
await core.channel.reply.dispatchReplyWithBufferedBlockDispatcher({
|
||||
ctx: ctxPayload,
|
||||
cfg,
|
||||
dispatcherOptions: {
|
||||
...prefixOptions,
|
||||
deliver: async (payload) => {
|
||||
await deliverTwitchReply({
|
||||
payload,
|
||||
@@ -121,6 +129,9 @@ async function processTwitchMessage(params: {
|
||||
});
|
||||
},
|
||||
},
|
||||
replyOptions: {
|
||||
onModelSelected,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -55,6 +55,8 @@ export interface TwitchAccountConfig {
|
||||
allowedRoles?: TwitchRole[];
|
||||
/** Require @mention to trigger bot responses */
|
||||
requireMention?: boolean;
|
||||
/** Outbound response prefix override for this channel/account. */
|
||||
responsePrefix?: string;
|
||||
/** Twitch client secret (required for token refresh via RefreshingAuthProvider) */
|
||||
clientSecret?: string;
|
||||
/** Refresh token (required for automatic token refresh) */
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# Changelog
|
||||
|
||||
## 2026.2.3
|
||||
|
||||
### Changes
|
||||
|
||||
- Version alignment with core OpenClaw release numbers.
|
||||
|
||||
## 2026.2.2
|
||||
|
||||
### Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@openclaw/voice-call",
|
||||
"version": "2026.2.2",
|
||||
"version": "2026.2.3",
|
||||
"description": "OpenClaw voice-call plugin",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
|
||||
@@ -135,6 +135,36 @@ describe("CallManager", () => {
|
||||
expect(provider.hangupCalls[0]?.providerCallId).toBe("provider-missing");
|
||||
});
|
||||
|
||||
it("rejects inbound calls with anonymous caller ID when allowlist enabled", () => {
|
||||
const config = VoiceCallConfigSchema.parse({
|
||||
enabled: true,
|
||||
provider: "plivo",
|
||||
fromNumber: "+15550000000",
|
||||
inboundPolicy: "allowlist",
|
||||
allowFrom: ["+15550001234"],
|
||||
});
|
||||
|
||||
const storePath = path.join(os.tmpdir(), `openclaw-voice-call-test-${Date.now()}`);
|
||||
const provider = new FakeProvider();
|
||||
const manager = new CallManager(config, storePath);
|
||||
manager.initialize(provider, "https://example.com/voice/webhook");
|
||||
|
||||
manager.processEvent({
|
||||
id: "evt-allowlist-anon",
|
||||
type: "call.initiated",
|
||||
callId: "call-anon",
|
||||
providerCallId: "provider-anon",
|
||||
timestamp: Date.now(),
|
||||
direction: "inbound",
|
||||
from: "anonymous",
|
||||
to: "+15550000000",
|
||||
});
|
||||
|
||||
expect(manager.getCallByProviderCallId("provider-anon")).toBeUndefined();
|
||||
expect(provider.hangupCalls).toHaveLength(1);
|
||||
expect(provider.hangupCalls[0]?.providerCallId).toBe("provider-anon");
|
||||
});
|
||||
|
||||
it("rejects inbound calls that only match allowlist suffixes", () => {
|
||||
const config = VoiceCallConfigSchema.parse({
|
||||
enabled: true,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@openclaw/whatsapp",
|
||||
"version": "2026.2.2",
|
||||
"version": "2026.2.3",
|
||||
"description": "OpenClaw WhatsApp channel plugin",
|
||||
"type": "module",
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# Changelog
|
||||
|
||||
## 2026.2.3
|
||||
|
||||
### Changes
|
||||
|
||||
- Version alignment with core OpenClaw release numbers.
|
||||
|
||||
## 2026.2.2
|
||||
|
||||
### Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@openclaw/zalo",
|
||||
"version": "2026.2.2",
|
||||
"version": "2026.2.3",
|
||||
"description": "OpenClaw Zalo channel plugin",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
|
||||
@@ -16,6 +16,7 @@ const zaloAccountSchema = z.object({
|
||||
allowFrom: z.array(allowFromEntry).optional(),
|
||||
mediaMaxMb: z.number().optional(),
|
||||
proxy: z.string().optional(),
|
||||
responsePrefix: z.string().optional(),
|
||||
});
|
||||
|
||||
export const ZaloConfigSchema = zaloAccountSchema.extend({
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { IncomingMessage, ServerResponse } from "node:http";
|
||||
import type { OpenClawConfig, MarkdownTableMode } from "openclaw/plugin-sdk";
|
||||
import { createReplyPrefixOptions } from "openclaw/plugin-sdk";
|
||||
import type { ResolvedZaloAccount } from "./accounts.js";
|
||||
import {
|
||||
ZaloApiError,
|
||||
@@ -583,11 +584,18 @@ async function processMessageWithPipeline(params: {
|
||||
channel: "zalo",
|
||||
accountId: account.accountId,
|
||||
});
|
||||
const { onModelSelected, ...prefixOptions } = createReplyPrefixOptions({
|
||||
cfg: config,
|
||||
agentId: route.agentId,
|
||||
channel: "zalo",
|
||||
accountId: account.accountId,
|
||||
});
|
||||
|
||||
await core.channel.reply.dispatchReplyWithBufferedBlockDispatcher({
|
||||
ctx: ctxPayload,
|
||||
cfg: config,
|
||||
dispatcherOptions: {
|
||||
...prefixOptions,
|
||||
deliver: async (payload) => {
|
||||
await deliverZaloReply({
|
||||
payload,
|
||||
@@ -606,6 +614,9 @@ async function processMessageWithPipeline(params: {
|
||||
runtime.error?.(`[${account.accountId}] Zalo ${info.kind} reply failed: ${String(err)}`);
|
||||
},
|
||||
},
|
||||
replyOptions: {
|
||||
onModelSelected,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,8 @@ export type ZaloAccountConfig = {
|
||||
mediaMaxMb?: number;
|
||||
/** Proxy URL for API requests. */
|
||||
proxy?: string;
|
||||
/** Outbound response prefix override for this channel/account. */
|
||||
responsePrefix?: string;
|
||||
};
|
||||
|
||||
export type ZaloConfig = {
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# Changelog
|
||||
|
||||
## 2026.2.3
|
||||
|
||||
### Changes
|
||||
|
||||
- Version alignment with core OpenClaw release numbers.
|
||||
|
||||
## 2026.2.2
|
||||
|
||||
### Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@openclaw/zalouser",
|
||||
"version": "2026.2.2",
|
||||
"version": "2026.2.3",
|
||||
"description": "OpenClaw Zalo Personal Account plugin via zca-cli",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
|
||||
@@ -19,6 +19,7 @@ const zalouserAccountSchema = z.object({
|
||||
groupPolicy: z.enum(["disabled", "allowlist", "open"]).optional(),
|
||||
groups: z.object({}).catchall(groupConfigSchema).optional(),
|
||||
messagePrefix: z.string().optional(),
|
||||
responsePrefix: z.string().optional(),
|
||||
});
|
||||
|
||||
export const ZalouserConfigSchema = zalouserAccountSchema.extend({
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { ChildProcess } from "node:child_process";
|
||||
import type { OpenClawConfig, MarkdownTableMode, RuntimeEnv } from "openclaw/plugin-sdk";
|
||||
import { mergeAllowlist, summarizeMapping } from "openclaw/plugin-sdk";
|
||||
import { createReplyPrefixOptions, mergeAllowlist, summarizeMapping } from "openclaw/plugin-sdk";
|
||||
import type { ResolvedZalouserAccount, ZcaFriend, ZcaGroup, ZcaMessage } from "./types.js";
|
||||
import { getZalouserRuntime } from "./runtime.js";
|
||||
import { sendMessageZalouser } from "./send.js";
|
||||
@@ -334,10 +334,18 @@ async function processMessage(
|
||||
},
|
||||
});
|
||||
|
||||
const { onModelSelected, ...prefixOptions } = createReplyPrefixOptions({
|
||||
cfg: config,
|
||||
agentId: route.agentId,
|
||||
channel: "zalouser",
|
||||
accountId: account.accountId,
|
||||
});
|
||||
|
||||
await core.channel.reply.dispatchReplyWithBufferedBlockDispatcher({
|
||||
ctx: ctxPayload,
|
||||
cfg: config,
|
||||
dispatcherOptions: {
|
||||
...prefixOptions,
|
||||
deliver: async (payload) => {
|
||||
await deliverZalouserReply({
|
||||
payload: payload as { text?: string; mediaUrls?: string[]; mediaUrl?: string },
|
||||
@@ -360,6 +368,9 @@ async function processMessage(
|
||||
runtime.error(`[${account.accountId}] Zalouser ${info.kind} reply failed: ${String(err)}`);
|
||||
},
|
||||
},
|
||||
replyOptions: {
|
||||
onModelSelected,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user