Merge branch 'main' into perplexity-search
This commit is contained in:
commit
37f1380742
@ -2,11 +2,18 @@
|
|||||||
|
|
||||||
Docs: https://docs.clawd.bot
|
Docs: https://docs.clawd.bot
|
||||||
|
|
||||||
|
## 2026.1.25
|
||||||
|
Status: unreleased.
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
- TBD.
|
||||||
|
|
||||||
## 2026.1.24-3
|
## 2026.1.24-3
|
||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
- Gateway: harden reverse proxy handling for local-client detection and unauthenticated proxied connects. (#1795) Thanks @orlyjamie.
|
- Gateway: harden reverse proxy handling for local-client detection and unauthenticated proxied connects. (#1795) Thanks @orlyjamie.
|
||||||
- Security audit: flag loopback Control UI with auth disabled as critical. (#1795) Thanks @orlyjamie.
|
- Security audit: flag loopback Control UI with auth disabled as critical. (#1795) Thanks @orlyjamie.
|
||||||
|
- CLI: resume claude-cli sessions and stream CLI replies to TUI clients. (#1921) Thanks @rmorse.
|
||||||
|
|
||||||
## 2026.1.24-2
|
## 2026.1.24-2
|
||||||
|
|
||||||
|
|||||||
@ -21,8 +21,8 @@ android {
|
|||||||
applicationId = "com.clawdbot.android"
|
applicationId = "com.clawdbot.android"
|
||||||
minSdk = 31
|
minSdk = 31
|
||||||
targetSdk = 36
|
targetSdk = 36
|
||||||
versionCode = 202601240
|
versionCode = 202601250
|
||||||
versionName = "2026.1.24"
|
versionName = "2026.1.25"
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
|
|||||||
@ -19,9 +19,9 @@
|
|||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>2026.1.24</string>
|
<string>2026.1.25</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>20260124</string>
|
<string>20260125</string>
|
||||||
<key>NSAppTransportSecurity</key>
|
<key>NSAppTransportSecurity</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>NSAllowsArbitraryLoadsInWebContent</key>
|
<key>NSAllowsArbitraryLoadsInWebContent</key>
|
||||||
|
|||||||
@ -17,8 +17,8 @@
|
|||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>BNDL</string>
|
<string>BNDL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>2026.1.24</string>
|
<string>2026.1.25</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>20260124</string>
|
<string>20260125</string>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
@ -81,8 +81,8 @@ targets:
|
|||||||
properties:
|
properties:
|
||||||
CFBundleDisplayName: Clawdbot
|
CFBundleDisplayName: Clawdbot
|
||||||
CFBundleIconName: AppIcon
|
CFBundleIconName: AppIcon
|
||||||
CFBundleShortVersionString: "2026.1.24"
|
CFBundleShortVersionString: "2026.1.25"
|
||||||
CFBundleVersion: "20260124"
|
CFBundleVersion: "20260125"
|
||||||
UILaunchScreen: {}
|
UILaunchScreen: {}
|
||||||
UIApplicationSceneManifest:
|
UIApplicationSceneManifest:
|
||||||
UIApplicationSupportsMultipleScenes: false
|
UIApplicationSupportsMultipleScenes: false
|
||||||
@ -130,5 +130,5 @@ targets:
|
|||||||
path: Tests/Info.plist
|
path: Tests/Info.plist
|
||||||
properties:
|
properties:
|
||||||
CFBundleDisplayName: ClawdbotTests
|
CFBundleDisplayName: ClawdbotTests
|
||||||
CFBundleShortVersionString: "2026.1.24"
|
CFBundleShortVersionString: "2026.1.25"
|
||||||
CFBundleVersion: "20260124"
|
CFBundleVersion: "20260125"
|
||||||
|
|||||||
@ -15,9 +15,9 @@
|
|||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>2026.1.24</string>
|
<string>2026.1.25</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>202601240</string>
|
<string>202601250</string>
|
||||||
<key>CFBundleIconFile</key>
|
<key>CFBundleIconFile</key>
|
||||||
<string>Clawdbot</string>
|
<string>Clawdbot</string>
|
||||||
<key>CFBundleURLTypes</key>
|
<key>CFBundleURLTypes</key>
|
||||||
|
|||||||
@ -182,6 +182,7 @@ Clawdbot ships a default for `claude-cli`:
|
|||||||
|
|
||||||
- `command: "claude"`
|
- `command: "claude"`
|
||||||
- `args: ["-p", "--output-format", "json", "--dangerously-skip-permissions"]`
|
- `args: ["-p", "--output-format", "json", "--dangerously-skip-permissions"]`
|
||||||
|
- `resumeArgs: ["-p", "--output-format", "json", "--dangerously-skip-permissions", "--resume", "{sessionId}"]`
|
||||||
- `modelArg: "--model"`
|
- `modelArg: "--model"`
|
||||||
- `systemPromptArg: "--append-system-prompt"`
|
- `systemPromptArg: "--append-system-prompt"`
|
||||||
- `sessionArg: "--session-id"`
|
- `sessionArg: "--session-id"`
|
||||||
|
|||||||
@ -182,7 +182,7 @@ cat > /data/clawdbot.json << 'EOF'
|
|||||||
"bind": "auto"
|
"bind": "auto"
|
||||||
},
|
},
|
||||||
"meta": {
|
"meta": {
|
||||||
"lastTouchedVersion": "2026.1.24"
|
"lastTouchedVersion": "2026.1.25"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
|
|||||||
@ -30,17 +30,17 @@ Notes:
|
|||||||
# From repo root; set release IDs so Sparkle feed is enabled.
|
# From repo root; set release IDs so Sparkle feed is enabled.
|
||||||
# APP_BUILD must be numeric + monotonic for Sparkle compare.
|
# APP_BUILD must be numeric + monotonic for Sparkle compare.
|
||||||
BUNDLE_ID=com.clawdbot.mac \
|
BUNDLE_ID=com.clawdbot.mac \
|
||||||
APP_VERSION=2026.1.24-3 \
|
APP_VERSION=2026.1.25 \
|
||||||
APP_BUILD="$(git rev-list --count HEAD)" \
|
APP_BUILD="$(git rev-list --count HEAD)" \
|
||||||
BUILD_CONFIG=release \
|
BUILD_CONFIG=release \
|
||||||
SIGN_IDENTITY="Developer ID Application: <Developer Name> (<TEAMID>)" \
|
SIGN_IDENTITY="Developer ID Application: <Developer Name> (<TEAMID>)" \
|
||||||
scripts/package-mac-app.sh
|
scripts/package-mac-app.sh
|
||||||
|
|
||||||
# Zip for distribution (includes resource forks for Sparkle delta support)
|
# Zip for distribution (includes resource forks for Sparkle delta support)
|
||||||
ditto -c -k --sequesterRsrc --keepParent dist/Clawdbot.app dist/Clawdbot-2026.1.24-3.zip
|
ditto -c -k --sequesterRsrc --keepParent dist/Clawdbot.app dist/Clawdbot-2026.1.25.zip
|
||||||
|
|
||||||
# Optional: also build a styled DMG for humans (drag to /Applications)
|
# Optional: also build a styled DMG for humans (drag to /Applications)
|
||||||
scripts/create-dmg.sh dist/Clawdbot.app dist/Clawdbot-2026.1.24-3.dmg
|
scripts/create-dmg.sh dist/Clawdbot.app dist/Clawdbot-2026.1.25.dmg
|
||||||
|
|
||||||
# Recommended: build + notarize/staple zip + DMG
|
# Recommended: build + notarize/staple zip + DMG
|
||||||
# First, create a keychain profile once:
|
# First, create a keychain profile once:
|
||||||
@ -48,26 +48,26 @@ scripts/create-dmg.sh dist/Clawdbot.app dist/Clawdbot-2026.1.24-3.dmg
|
|||||||
# --apple-id "<apple-id>" --team-id "<team-id>" --password "<app-specific-password>"
|
# --apple-id "<apple-id>" --team-id "<team-id>" --password "<app-specific-password>"
|
||||||
NOTARIZE=1 NOTARYTOOL_PROFILE=clawdbot-notary \
|
NOTARIZE=1 NOTARYTOOL_PROFILE=clawdbot-notary \
|
||||||
BUNDLE_ID=com.clawdbot.mac \
|
BUNDLE_ID=com.clawdbot.mac \
|
||||||
APP_VERSION=2026.1.24-3 \
|
APP_VERSION=2026.1.25 \
|
||||||
APP_BUILD="$(git rev-list --count HEAD)" \
|
APP_BUILD="$(git rev-list --count HEAD)" \
|
||||||
BUILD_CONFIG=release \
|
BUILD_CONFIG=release \
|
||||||
SIGN_IDENTITY="Developer ID Application: <Developer Name> (<TEAMID>)" \
|
SIGN_IDENTITY="Developer ID Application: <Developer Name> (<TEAMID>)" \
|
||||||
scripts/package-mac-dist.sh
|
scripts/package-mac-dist.sh
|
||||||
|
|
||||||
# Optional: ship dSYM alongside the release
|
# Optional: ship dSYM alongside the release
|
||||||
ditto -c -k --keepParent apps/macos/.build/release/Clawdbot.app.dSYM dist/Clawdbot-2026.1.24-3.dSYM.zip
|
ditto -c -k --keepParent apps/macos/.build/release/Clawdbot.app.dSYM dist/Clawdbot-2026.1.25.dSYM.zip
|
||||||
```
|
```
|
||||||
|
|
||||||
## Appcast entry
|
## Appcast entry
|
||||||
Use the release note generator so Sparkle renders formatted HTML notes:
|
Use the release note generator so Sparkle renders formatted HTML notes:
|
||||||
```bash
|
```bash
|
||||||
SPARKLE_PRIVATE_KEY_FILE=/path/to/ed25519-private-key scripts/make_appcast.sh dist/Clawdbot-2026.1.24-3.zip https://raw.githubusercontent.com/clawdbot/clawdbot/main/appcast.xml
|
SPARKLE_PRIVATE_KEY_FILE=/path/to/ed25519-private-key scripts/make_appcast.sh dist/Clawdbot-2026.1.25.zip https://raw.githubusercontent.com/clawdbot/clawdbot/main/appcast.xml
|
||||||
```
|
```
|
||||||
Generates HTML release notes from `CHANGELOG.md` (via [`scripts/changelog-to-html.sh`](https://github.com/clawdbot/clawdbot/blob/main/scripts/changelog-to-html.sh)) and embeds them in the appcast entry.
|
Generates HTML release notes from `CHANGELOG.md` (via [`scripts/changelog-to-html.sh`](https://github.com/clawdbot/clawdbot/blob/main/scripts/changelog-to-html.sh)) and embeds them in the appcast entry.
|
||||||
Commit the updated `appcast.xml` alongside the release assets (zip + dSYM) when publishing.
|
Commit the updated `appcast.xml` alongside the release assets (zip + dSYM) when publishing.
|
||||||
|
|
||||||
## Publish & verify
|
## Publish & verify
|
||||||
- Upload `Clawdbot-2026.1.24-3.zip` (and `Clawdbot-2026.1.24-3.dSYM.zip`) to the GitHub release for tag `v2026.1.24-3`.
|
- Upload `Clawdbot-2026.1.25.zip` (and `Clawdbot-2026.1.25.dSYM.zip`) to the GitHub release for tag `v2026.1.25`.
|
||||||
- Ensure the raw appcast URL matches the baked feed: `https://raw.githubusercontent.com/clawdbot/clawdbot/main/appcast.xml`.
|
- Ensure the raw appcast URL matches the baked feed: `https://raw.githubusercontent.com/clawdbot/clawdbot/main/appcast.xml`.
|
||||||
- Sanity checks:
|
- Sanity checks:
|
||||||
- `curl -I https://raw.githubusercontent.com/clawdbot/clawdbot/main/appcast.xml` returns 200.
|
- `curl -I https://raw.githubusercontent.com/clawdbot/clawdbot/main/appcast.xml` returns 200.
|
||||||
|
|||||||
@ -16,7 +16,7 @@ and you configure everything via the `/setup` web wizard.
|
|||||||
|
|
||||||
## One-click deploy
|
## One-click deploy
|
||||||
|
|
||||||
<a href="https://railway.app/new/template?template=https://github.com/vignesh07/clawdbot-railway-template" target="_blank" rel="noreferrer">Deploy on Railway</a>
|
<a href="https://railway.com/deploy/clawdbot-railway-template" target="_blank" rel="noreferrer">Deploy on Railway</a>
|
||||||
|
|
||||||
After deploy, find your public URL in **Railway → your service → Settings → Domains**.
|
After deploy, find your public URL in **Railway → your service → Settings → Domains**.
|
||||||
|
|
||||||
|
|||||||
@ -17,7 +17,7 @@ When the operator says “release”, immediately do this preflight (no extra qu
|
|||||||
- Use Sparkle keys from `~/Library/CloudStorage/Dropbox/Backup/Sparkle` if needed.
|
- Use Sparkle keys from `~/Library/CloudStorage/Dropbox/Backup/Sparkle` if needed.
|
||||||
|
|
||||||
1) **Version & metadata**
|
1) **Version & metadata**
|
||||||
- [ ] Bump `package.json` version (e.g., `2026.1.24`).
|
- [ ] Bump `package.json` version (e.g., `2026.1.25`).
|
||||||
- [ ] Run `pnpm plugins:sync` to align extension package versions + changelogs.
|
- [ ] Run `pnpm plugins:sync` to align extension package versions + changelogs.
|
||||||
- [ ] Update CLI/version strings: [`src/cli/program.ts`](https://github.com/clawdbot/clawdbot/blob/main/src/cli/program.ts) and the Baileys user agent in [`src/provider-web.ts`](https://github.com/clawdbot/clawdbot/blob/main/src/provider-web.ts).
|
- [ ] Update CLI/version strings: [`src/cli/program.ts`](https://github.com/clawdbot/clawdbot/blob/main/src/cli/program.ts) and the Baileys user agent in [`src/provider-web.ts`](https://github.com/clawdbot/clawdbot/blob/main/src/provider-web.ts).
|
||||||
- [ ] Confirm package metadata (name, description, repository, keywords, license) and `bin` map points to [`dist/entry.js`](https://github.com/clawdbot/clawdbot/blob/main/dist/entry.js) for `clawdbot`.
|
- [ ] Confirm package metadata (name, description, repository, keywords, license) and `bin` map points to [`dist/entry.js`](https://github.com/clawdbot/clawdbot/blob/main/dist/entry.js) for `clawdbot`.
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@clawdbot/bluebubbles",
|
"name": "@clawdbot/bluebubbles",
|
||||||
"version": "2026.1.24",
|
"version": "2026.1.25",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "Clawdbot BlueBubbles channel plugin",
|
"description": "Clawdbot BlueBubbles channel plugin",
|
||||||
"clawdbot": {
|
"clawdbot": {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@clawdbot/copilot-proxy",
|
"name": "@clawdbot/copilot-proxy",
|
||||||
"version": "2026.1.24",
|
"version": "2026.1.25",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "Clawdbot Copilot Proxy provider plugin",
|
"description": "Clawdbot Copilot Proxy provider plugin",
|
||||||
"clawdbot": {
|
"clawdbot": {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@clawdbot/diagnostics-otel",
|
"name": "@clawdbot/diagnostics-otel",
|
||||||
"version": "2026.1.24",
|
"version": "2026.1.25",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "Clawdbot diagnostics OpenTelemetry exporter",
|
"description": "Clawdbot diagnostics OpenTelemetry exporter",
|
||||||
"clawdbot": {
|
"clawdbot": {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@clawdbot/discord",
|
"name": "@clawdbot/discord",
|
||||||
"version": "2026.1.24",
|
"version": "2026.1.25",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "Clawdbot Discord channel plugin",
|
"description": "Clawdbot Discord channel plugin",
|
||||||
"clawdbot": {
|
"clawdbot": {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@clawdbot/google-antigravity-auth",
|
"name": "@clawdbot/google-antigravity-auth",
|
||||||
"version": "2026.1.24",
|
"version": "2026.1.25",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "Clawdbot Google Antigravity OAuth provider plugin",
|
"description": "Clawdbot Google Antigravity OAuth provider plugin",
|
||||||
"clawdbot": {
|
"clawdbot": {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@clawdbot/google-gemini-cli-auth",
|
"name": "@clawdbot/google-gemini-cli-auth",
|
||||||
"version": "2026.1.24",
|
"version": "2026.1.25",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "Clawdbot Gemini CLI OAuth provider plugin",
|
"description": "Clawdbot Gemini CLI OAuth provider plugin",
|
||||||
"clawdbot": {
|
"clawdbot": {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@clawdbot/googlechat",
|
"name": "@clawdbot/googlechat",
|
||||||
"version": "2026.1.24",
|
"version": "2026.1.25",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "Clawdbot Google Chat channel plugin",
|
"description": "Clawdbot Google Chat channel plugin",
|
||||||
"clawdbot": {
|
"clawdbot": {
|
||||||
@ -34,6 +34,6 @@
|
|||||||
"clawdbot": "workspace:*"
|
"clawdbot": "workspace:*"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"clawdbot": ">=2026.1.24"
|
"clawdbot": ">=2026.1.25"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@clawdbot/imessage",
|
"name": "@clawdbot/imessage",
|
||||||
"version": "2026.1.24",
|
"version": "2026.1.25",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "Clawdbot iMessage channel plugin",
|
"description": "Clawdbot iMessage channel plugin",
|
||||||
"clawdbot": {
|
"clawdbot": {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@clawdbot/line",
|
"name": "@clawdbot/line",
|
||||||
"version": "2026.1.24",
|
"version": "2026.1.25",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "Clawdbot LINE channel plugin",
|
"description": "Clawdbot LINE channel plugin",
|
||||||
"clawdbot": {
|
"clawdbot": {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@clawdbot/llm-task",
|
"name": "@clawdbot/llm-task",
|
||||||
"version": "2026.1.24",
|
"version": "2026.1.25",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "Clawdbot JSON-only LLM task plugin",
|
"description": "Clawdbot JSON-only LLM task plugin",
|
||||||
"clawdbot": {
|
"clawdbot": {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@clawdbot/lobster",
|
"name": "@clawdbot/lobster",
|
||||||
"version": "2026.1.24",
|
"version": "2026.1.25",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "Lobster workflow tool plugin (typed pipelines + resumable approvals)",
|
"description": "Lobster workflow tool plugin (typed pipelines + resumable approvals)",
|
||||||
"clawdbot": {
|
"clawdbot": {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@clawdbot/matrix",
|
"name": "@clawdbot/matrix",
|
||||||
"version": "2026.1.24",
|
"version": "2026.1.25",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "Clawdbot Matrix channel plugin",
|
"description": "Clawdbot Matrix channel plugin",
|
||||||
"clawdbot": {
|
"clawdbot": {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@clawdbot/mattermost",
|
"name": "@clawdbot/mattermost",
|
||||||
"version": "2026.1.24",
|
"version": "2026.1.25",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "Clawdbot Mattermost channel plugin",
|
"description": "Clawdbot Mattermost channel plugin",
|
||||||
"clawdbot": {
|
"clawdbot": {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@clawdbot/memory-core",
|
"name": "@clawdbot/memory-core",
|
||||||
"version": "2026.1.24",
|
"version": "2026.1.25",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "Clawdbot core memory search plugin",
|
"description": "Clawdbot core memory search plugin",
|
||||||
"clawdbot": {
|
"clawdbot": {
|
||||||
@ -9,6 +9,6 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"clawdbot": ">=2026.1.24"
|
"clawdbot": ">=2026.1.25"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@clawdbot/memory-lancedb",
|
"name": "@clawdbot/memory-lancedb",
|
||||||
"version": "2026.1.24",
|
"version": "2026.1.25",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "Clawdbot LanceDB-backed long-term memory plugin with auto-recall/capture",
|
"description": "Clawdbot LanceDB-backed long-term memory plugin with auto-recall/capture",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@clawdbot/msteams",
|
"name": "@clawdbot/msteams",
|
||||||
"version": "2026.1.24",
|
"version": "2026.1.25",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "Clawdbot Microsoft Teams channel plugin",
|
"description": "Clawdbot Microsoft Teams channel plugin",
|
||||||
"clawdbot": {
|
"clawdbot": {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@clawdbot/nextcloud-talk",
|
"name": "@clawdbot/nextcloud-talk",
|
||||||
"version": "2026.1.24",
|
"version": "2026.1.25",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "Clawdbot Nextcloud Talk channel plugin",
|
"description": "Clawdbot Nextcloud Talk channel plugin",
|
||||||
"clawdbot": {
|
"clawdbot": {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@clawdbot/nostr",
|
"name": "@clawdbot/nostr",
|
||||||
"version": "2026.1.24",
|
"version": "2026.1.25",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "Clawdbot Nostr channel plugin for NIP-04 encrypted DMs",
|
"description": "Clawdbot Nostr channel plugin for NIP-04 encrypted DMs",
|
||||||
"clawdbot": {
|
"clawdbot": {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@clawdbot/open-prose",
|
"name": "@clawdbot/open-prose",
|
||||||
"version": "2026.1.24",
|
"version": "2026.1.25",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "OpenProse VM skill pack plugin (slash command + telemetry).",
|
"description": "OpenProse VM skill pack plugin (slash command + telemetry).",
|
||||||
"clawdbot": {
|
"clawdbot": {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@clawdbot/signal",
|
"name": "@clawdbot/signal",
|
||||||
"version": "2026.1.24",
|
"version": "2026.1.25",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "Clawdbot Signal channel plugin",
|
"description": "Clawdbot Signal channel plugin",
|
||||||
"clawdbot": {
|
"clawdbot": {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@clawdbot/slack",
|
"name": "@clawdbot/slack",
|
||||||
"version": "2026.1.24",
|
"version": "2026.1.25",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "Clawdbot Slack channel plugin",
|
"description": "Clawdbot Slack channel plugin",
|
||||||
"clawdbot": {
|
"clawdbot": {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@clawdbot/telegram",
|
"name": "@clawdbot/telegram",
|
||||||
"version": "2026.1.24",
|
"version": "2026.1.25",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "Clawdbot Telegram channel plugin",
|
"description": "Clawdbot Telegram channel plugin",
|
||||||
"clawdbot": {
|
"clawdbot": {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@clawdbot/tlon",
|
"name": "@clawdbot/tlon",
|
||||||
"version": "2026.1.24",
|
"version": "2026.1.25",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "Clawdbot Tlon/Urbit channel plugin",
|
"description": "Clawdbot Tlon/Urbit channel plugin",
|
||||||
"clawdbot": {
|
"clawdbot": {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## 2026.1.24
|
## 2026.1.25
|
||||||
|
|
||||||
### Changes
|
### Changes
|
||||||
- Breaking: voice-call TTS now uses core `messages.tts` (plugin TTS config deep‑merges with core).
|
- Breaking: voice-call TTS now uses core `messages.tts` (plugin TTS config deep‑merges with core).
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@clawdbot/voice-call",
|
"name": "@clawdbot/voice-call",
|
||||||
"version": "2026.1.24",
|
"version": "2026.1.25",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "Clawdbot voice-call plugin",
|
"description": "Clawdbot voice-call plugin",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@clawdbot/whatsapp",
|
"name": "@clawdbot/whatsapp",
|
||||||
"version": "2026.1.24",
|
"version": "2026.1.25",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "Clawdbot WhatsApp channel plugin",
|
"description": "Clawdbot WhatsApp channel plugin",
|
||||||
"clawdbot": {
|
"clawdbot": {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@clawdbot/zalo",
|
"name": "@clawdbot/zalo",
|
||||||
"version": "2026.1.24",
|
"version": "2026.1.25",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "Clawdbot Zalo channel plugin",
|
"description": "Clawdbot Zalo channel plugin",
|
||||||
"clawdbot": {
|
"clawdbot": {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@clawdbot/zalouser",
|
"name": "@clawdbot/zalouser",
|
||||||
"version": "2026.1.24",
|
"version": "2026.1.25",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "Clawdbot Zalo Personal Account plugin via zca-cli",
|
"description": "Clawdbot Zalo Personal Account plugin via zca-cli",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "clawdbot",
|
"name": "clawdbot",
|
||||||
"version": "2026.1.24-3",
|
"version": "2026.1.25",
|
||||||
"description": "WhatsApp gateway CLI (Baileys web) with Pi RPC agent",
|
"description": "WhatsApp gateway CLI (Baileys web) with Pi RPC agent",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
@ -220,7 +220,7 @@
|
|||||||
"@types/proper-lockfile": "^4.1.4",
|
"@types/proper-lockfile": "^4.1.4",
|
||||||
"@types/qrcode-terminal": "^0.12.2",
|
"@types/qrcode-terminal": "^0.12.2",
|
||||||
"@types/ws": "^8.18.1",
|
"@types/ws": "^8.18.1",
|
||||||
"@typescript/native-preview": "7.0.0-dev.20260124.1",
|
"@typescript/native-preview": "7.0.0-dev.20260125.1",
|
||||||
"@vitest/coverage-v8": "^4.0.18",
|
"@vitest/coverage-v8": "^4.0.18",
|
||||||
"docx-preview": "^0.3.7",
|
"docx-preview": "^0.3.7",
|
||||||
"lit": "^3.3.2",
|
"lit": "^3.3.2",
|
||||||
|
|||||||
@ -61,7 +61,7 @@ describe("runClaudeCliAgent", () => {
|
|||||||
expect(argv).toContain("hi");
|
expect(argv).toContain("hi");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("uses provided --session-id when a claude session id is provided", async () => {
|
it("uses --resume when a claude session id is provided", async () => {
|
||||||
runCommandWithTimeoutMock.mockResolvedValueOnce({
|
runCommandWithTimeoutMock.mockResolvedValueOnce({
|
||||||
stdout: JSON.stringify({ message: "ok", session_id: "sid-2" }),
|
stdout: JSON.stringify({ message: "ok", session_id: "sid-2" }),
|
||||||
stderr: "",
|
stderr: "",
|
||||||
@ -83,7 +83,7 @@ describe("runClaudeCliAgent", () => {
|
|||||||
|
|
||||||
expect(runCommandWithTimeoutMock).toHaveBeenCalledTimes(1);
|
expect(runCommandWithTimeoutMock).toHaveBeenCalledTimes(1);
|
||||||
const argv = runCommandWithTimeoutMock.mock.calls[0]?.[0] as string[];
|
const argv = runCommandWithTimeoutMock.mock.calls[0]?.[0] as string[];
|
||||||
expect(argv).toContain("--session-id");
|
expect(argv).toContain("--resume");
|
||||||
expect(argv).toContain("c9d7b831-1c31-4d22-80b9-1e50ca207d4b");
|
expect(argv).toContain("c9d7b831-1c31-4d22-80b9-1e50ca207d4b");
|
||||||
expect(argv).toContain("hi");
|
expect(argv).toContain("hi");
|
||||||
});
|
});
|
||||||
|
|||||||
@ -28,6 +28,14 @@ const CLAUDE_MODEL_ALIASES: Record<string, string> = {
|
|||||||
const DEFAULT_CLAUDE_BACKEND: CliBackendConfig = {
|
const DEFAULT_CLAUDE_BACKEND: CliBackendConfig = {
|
||||||
command: "claude",
|
command: "claude",
|
||||||
args: ["-p", "--output-format", "json", "--dangerously-skip-permissions"],
|
args: ["-p", "--output-format", "json", "--dangerously-skip-permissions"],
|
||||||
|
resumeArgs: [
|
||||||
|
"-p",
|
||||||
|
"--output-format",
|
||||||
|
"json",
|
||||||
|
"--dangerously-skip-permissions",
|
||||||
|
"--resume",
|
||||||
|
"{sessionId}",
|
||||||
|
],
|
||||||
output: "json",
|
output: "json",
|
||||||
input: "arg",
|
input: "arg",
|
||||||
modelArg: "--model",
|
modelArg: "--model",
|
||||||
|
|||||||
@ -179,6 +179,17 @@ export async function runAgentTurnWithFallback(params: {
|
|||||||
images: params.opts?.images,
|
images: params.opts?.images,
|
||||||
})
|
})
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
|
// CLI backends don't emit streaming assistant events, so we need to
|
||||||
|
// emit one with the final text so server-chat can populate its buffer
|
||||||
|
// and send the response to TUI/WebSocket clients.
|
||||||
|
const cliText = result.payloads?.[0]?.text?.trim();
|
||||||
|
if (cliText) {
|
||||||
|
emitAgentEvent({
|
||||||
|
runId,
|
||||||
|
stream: "assistant",
|
||||||
|
data: { text: cliText },
|
||||||
|
});
|
||||||
|
}
|
||||||
emitAgentEvent({
|
emitAgentEvent({
|
||||||
runId,
|
runId,
|
||||||
stream: "lifecycle",
|
stream: "lifecycle",
|
||||||
|
|||||||
43
src/gateway/server-chat.agent-events.test.ts
Normal file
43
src/gateway/server-chat.agent-events.test.ts
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import { describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
|
import { createAgentEventHandler, createChatRunState } from "./server-chat.js";
|
||||||
|
|
||||||
|
describe("agent event handler", () => {
|
||||||
|
it("emits chat delta for assistant text-only events", () => {
|
||||||
|
const nowSpy = vi.spyOn(Date, "now").mockReturnValue(1_000);
|
||||||
|
const broadcast = vi.fn();
|
||||||
|
const nodeSendToSession = vi.fn();
|
||||||
|
const agentRunSeq = new Map<string, number>();
|
||||||
|
const chatRunState = createChatRunState();
|
||||||
|
chatRunState.registry.add("run-1", { sessionKey: "session-1", clientRunId: "client-1" });
|
||||||
|
|
||||||
|
const handler = createAgentEventHandler({
|
||||||
|
broadcast,
|
||||||
|
nodeSendToSession,
|
||||||
|
agentRunSeq,
|
||||||
|
chatRunState,
|
||||||
|
resolveSessionKeyForRun: () => undefined,
|
||||||
|
clearAgentRunContext: vi.fn(),
|
||||||
|
});
|
||||||
|
|
||||||
|
handler({
|
||||||
|
runId: "run-1",
|
||||||
|
seq: 1,
|
||||||
|
stream: "assistant",
|
||||||
|
ts: Date.now(),
|
||||||
|
data: { text: "Hello world" },
|
||||||
|
});
|
||||||
|
|
||||||
|
const chatCalls = broadcast.mock.calls.filter(([event]) => event === "chat");
|
||||||
|
expect(chatCalls).toHaveLength(1);
|
||||||
|
const payload = chatCalls[0]?.[1] as {
|
||||||
|
state?: string;
|
||||||
|
message?: { content?: Array<{ text?: string }> };
|
||||||
|
};
|
||||||
|
expect(payload.state).toBe("delta");
|
||||||
|
expect(payload.message?.content?.[0]?.text).toBe("Hello world");
|
||||||
|
const sessionChatCalls = nodeSendToSession.mock.calls.filter(([, event]) => event === "chat");
|
||||||
|
expect(sessionChatCalls).toHaveLength(1);
|
||||||
|
nowSpy.mockRestore();
|
||||||
|
});
|
||||||
|
});
|
||||||
163
src/gateway/server-methods/agent.test.ts
Normal file
163
src/gateway/server-methods/agent.test.ts
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
import { describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
|
import type { GatewayRequestContext } from "./types.js";
|
||||||
|
import { agentHandlers } from "./agent.js";
|
||||||
|
|
||||||
|
const mocks = vi.hoisted(() => ({
|
||||||
|
loadSessionEntry: vi.fn(),
|
||||||
|
updateSessionStore: vi.fn(),
|
||||||
|
agentCommand: vi.fn(),
|
||||||
|
registerAgentRunContext: vi.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("../session-utils.js", () => ({
|
||||||
|
loadSessionEntry: mocks.loadSessionEntry,
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("../../config/sessions.js", async () => {
|
||||||
|
const actual = await vi.importActual<typeof import("../../config/sessions.js")>(
|
||||||
|
"../../config/sessions.js",
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
...actual,
|
||||||
|
updateSessionStore: mocks.updateSessionStore,
|
||||||
|
resolveAgentIdFromSessionKey: () => "main",
|
||||||
|
resolveExplicitAgentSessionKey: () => undefined,
|
||||||
|
resolveAgentMainSessionKey: () => "agent:main:main",
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
vi.mock("../../commands/agent.js", () => ({
|
||||||
|
agentCommand: mocks.agentCommand,
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("../../config/config.js", () => ({
|
||||||
|
loadConfig: () => ({}),
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("../../agents/agent-scope.js", () => ({
|
||||||
|
listAgentIds: () => ["main"],
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("../../infra/agent-events.js", () => ({
|
||||||
|
registerAgentRunContext: mocks.registerAgentRunContext,
|
||||||
|
onAgentEvent: vi.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("../../sessions/send-policy.js", () => ({
|
||||||
|
resolveSendPolicy: () => "allow",
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("../../utils/delivery-context.js", async () => {
|
||||||
|
const actual = await vi.importActual<typeof import("../../utils/delivery-context.js")>(
|
||||||
|
"../../utils/delivery-context.js",
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
...actual,
|
||||||
|
normalizeSessionDeliveryFields: () => ({}),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const makeContext = (): GatewayRequestContext =>
|
||||||
|
({
|
||||||
|
dedupe: new Map(),
|
||||||
|
addChatRun: vi.fn(),
|
||||||
|
logGateway: { info: vi.fn(), error: vi.fn() },
|
||||||
|
}) as unknown as GatewayRequestContext;
|
||||||
|
|
||||||
|
describe("gateway agent handler", () => {
|
||||||
|
it("preserves cliSessionIds from existing session entry", async () => {
|
||||||
|
const existingCliSessionIds = { "claude-cli": "abc-123-def" };
|
||||||
|
const existingClaudeCliSessionId = "abc-123-def";
|
||||||
|
|
||||||
|
mocks.loadSessionEntry.mockReturnValue({
|
||||||
|
cfg: {},
|
||||||
|
storePath: "/tmp/sessions.json",
|
||||||
|
entry: {
|
||||||
|
sessionId: "existing-session-id",
|
||||||
|
updatedAt: Date.now(),
|
||||||
|
cliSessionIds: existingCliSessionIds,
|
||||||
|
claudeCliSessionId: existingClaudeCliSessionId,
|
||||||
|
},
|
||||||
|
canonicalKey: "agent:main:main",
|
||||||
|
});
|
||||||
|
|
||||||
|
let capturedEntry: Record<string, unknown> | undefined;
|
||||||
|
mocks.updateSessionStore.mockImplementation(async (_path, updater) => {
|
||||||
|
const store: Record<string, unknown> = {};
|
||||||
|
await updater(store);
|
||||||
|
capturedEntry = store["agent:main:main"] as Record<string, unknown>;
|
||||||
|
});
|
||||||
|
|
||||||
|
mocks.agentCommand.mockResolvedValue({
|
||||||
|
payloads: [{ text: "ok" }],
|
||||||
|
meta: { durationMs: 100 },
|
||||||
|
});
|
||||||
|
|
||||||
|
const respond = vi.fn();
|
||||||
|
await agentHandlers.agent({
|
||||||
|
params: {
|
||||||
|
message: "test",
|
||||||
|
agentId: "main",
|
||||||
|
sessionKey: "agent:main:main",
|
||||||
|
idempotencyKey: "test-idem",
|
||||||
|
},
|
||||||
|
respond,
|
||||||
|
context: makeContext(),
|
||||||
|
req: { type: "req", id: "1", method: "agent" },
|
||||||
|
client: null,
|
||||||
|
isWebchatConnect: () => false,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(mocks.updateSessionStore).toHaveBeenCalled();
|
||||||
|
expect(capturedEntry).toBeDefined();
|
||||||
|
expect(capturedEntry?.cliSessionIds).toEqual(existingCliSessionIds);
|
||||||
|
expect(capturedEntry?.claudeCliSessionId).toBe(existingClaudeCliSessionId);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("handles missing cliSessionIds gracefully", async () => {
|
||||||
|
mocks.loadSessionEntry.mockReturnValue({
|
||||||
|
cfg: {},
|
||||||
|
storePath: "/tmp/sessions.json",
|
||||||
|
entry: {
|
||||||
|
sessionId: "existing-session-id",
|
||||||
|
updatedAt: Date.now(),
|
||||||
|
// No cliSessionIds or claudeCliSessionId
|
||||||
|
},
|
||||||
|
canonicalKey: "agent:main:main",
|
||||||
|
});
|
||||||
|
|
||||||
|
let capturedEntry: Record<string, unknown> | undefined;
|
||||||
|
mocks.updateSessionStore.mockImplementation(async (_path, updater) => {
|
||||||
|
const store: Record<string, unknown> = {};
|
||||||
|
await updater(store);
|
||||||
|
capturedEntry = store["agent:main:main"] as Record<string, unknown>;
|
||||||
|
});
|
||||||
|
|
||||||
|
mocks.agentCommand.mockResolvedValue({
|
||||||
|
payloads: [{ text: "ok" }],
|
||||||
|
meta: { durationMs: 100 },
|
||||||
|
});
|
||||||
|
|
||||||
|
const respond = vi.fn();
|
||||||
|
await agentHandlers.agent({
|
||||||
|
params: {
|
||||||
|
message: "test",
|
||||||
|
agentId: "main",
|
||||||
|
sessionKey: "agent:main:main",
|
||||||
|
idempotencyKey: "test-idem-2",
|
||||||
|
},
|
||||||
|
respond,
|
||||||
|
context: makeContext(),
|
||||||
|
req: { type: "req", id: "2", method: "agent" },
|
||||||
|
client: null,
|
||||||
|
isWebchatConnect: () => false,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(mocks.updateSessionStore).toHaveBeenCalled();
|
||||||
|
expect(capturedEntry).toBeDefined();
|
||||||
|
// Should be undefined, not cause an error
|
||||||
|
expect(capturedEntry?.cliSessionIds).toBeUndefined();
|
||||||
|
expect(capturedEntry?.claudeCliSessionId).toBeUndefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -251,6 +251,8 @@ export const agentHandlers: GatewayRequestHandlers = {
|
|||||||
groupId: resolvedGroupId ?? entry?.groupId,
|
groupId: resolvedGroupId ?? entry?.groupId,
|
||||||
groupChannel: resolvedGroupChannel ?? entry?.groupChannel,
|
groupChannel: resolvedGroupChannel ?? entry?.groupChannel,
|
||||||
space: resolvedGroupSpace ?? entry?.space,
|
space: resolvedGroupSpace ?? entry?.space,
|
||||||
|
cliSessionIds: entry?.cliSessionIds,
|
||||||
|
claudeCliSessionId: entry?.claudeCliSessionId,
|
||||||
};
|
};
|
||||||
sessionEntry = nextEntry;
|
sessionEntry = nextEntry;
|
||||||
const sendPolicy = resolveSendPolicy({
|
const sendPolicy = resolveSendPolicy({
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user