Merge branch 'moltbot:main' into test/add-backoff-tests
This commit is contained in:
commit
a0b74e9f59
172
CHANGELOG.md
172
CHANGELOG.md
@ -2,143 +2,61 @@
|
||||
|
||||
Docs: https://docs.molt.bot
|
||||
|
||||
## 2026.1.27-beta.1
|
||||
## 2026.1.29
|
||||
Status: beta.
|
||||
|
||||
### Highlights
|
||||
- Rebrand: rename the npm package/CLI to `moltbot`, keep a `moltbot` compatibility shim, move extensions to the `@moltbot/*` scope, and update bot.molt bundle IDs/labels/logging subsystems. Thanks @thewilloftheshadow.
|
||||
- New channels/plugins: Twitch plugin; Google Chat (beta) with Workspace Add-on events + typing indicator. (#1612, #1635) Thanks @tyler6204, @iHildy.
|
||||
- Security hardening: gateway auth defaults required, hook token query-param deprecation, Windows ACL audits, mDNS minimal discovery, and SSH target option injection fix. (#4001, #2016, #1957, #1882, #2200)
|
||||
- WebChat: image paste + image-only sends; keep sub-agent announce replies visible. (#1925, #1977)
|
||||
- Tooling: per-sender group tool policies + tools.alsoAllow additive allowlist. (#1757, #1762)
|
||||
- Memory Search: allow extra paths for memory indexing. (#3600) Thanks @kira-ariaki.
|
||||
|
||||
### Changes
|
||||
- Rebrand: rename the npm package/CLI to `moltbot`, add a `moltbot` compatibility shim, and move extensions to the `@moltbot/*` scope.
|
||||
- Commands: group /help and /commands output with Telegram paging. (#2504) Thanks @hougangdev.
|
||||
- macOS: limit project-local `node_modules/.bin` PATH preference to debug builds (reduce PATH hijacking risk).
|
||||
- macOS: finish Moltbot app rename for macOS sources, bundle identifiers, and shared kit paths. (#2844) Thanks @fal3.
|
||||
- Branding: update launchd labels, mobile bundle IDs, and logging subsystems to bot.molt (legacy com.clawdbot migrations). Thanks @thewilloftheshadow.
|
||||
- Tools: add per-sender group tool policies and fix precedence. (#1757) Thanks @adam91holt.
|
||||
- Agents: summarize dropped messages during compaction safeguard pruning. (#2509) Thanks @jogi47.
|
||||
- Memory Search: allow extra paths for memory indexing (ignores symlinks). (#3600) Thanks @kira-ariaki.
|
||||
- Skills: add multi-image input support to Nano Banana Pro skill. (#1958) Thanks @tyler6204.
|
||||
- Agents: honor tools.exec.safeBins in exec allowlist checks. (#2281)
|
||||
- Matrix: switch plugin SDK to @vector-im/matrix-bot-sdk.
|
||||
- Docs: tighten Fly private deployment steps. (#2289) Thanks @dguido.
|
||||
- Docs: add migration guide for moving to a new machine. (#2381)
|
||||
- Docs: add Northflank one-click deployment guide. (#2167) Thanks @AdeboyeDN.
|
||||
- Gateway: warn on hook tokens via query params; document header auth preference. (#2200) Thanks @YuriNachos.
|
||||
- Gateway: add dangerous Control UI device auth bypass flag + audit warnings. (#2248)
|
||||
- Providers: add Venice AI integration; update Moonshot Kimi references to kimi-k2.5; update MiniMax API endpoint/format. (#2762, #3064)
|
||||
- Telegram: quote replies, edit-message action, silent sends, sticker support + vision caching, linkPreview toggle, plugin sendPayload support. (#2900, #2394, #2382, #2548, #1700, #1917)
|
||||
- Discord: configurable privileged gateway intents for presences/members. (#2266) Thanks @kentaro.
|
||||
- Browser: route browser control via gateway/node; fallback URL matching for relay targets. (#1999)
|
||||
- macOS: add direct gateway transport; preserve custom SSH usernames for remote control; bump Textual to 0.3.1. (#2033, #2046)
|
||||
- Routing: add per-account DM session scope + guidance for multi-account setups. (#3095) Thanks @jarvis-sam.
|
||||
- Hooks: make session-memory message count configurable. (#2681)
|
||||
- Tools: honor tools.exec.safeBins in exec allowlist checks. (#2281)
|
||||
- Security: add Control UI device auth bypass flag + audit warnings; warn on hook tokens via query params; add security audit CLI surface. (#2248, #2200)
|
||||
- Doctor: warn on gateway exposure without auth. (#2016) Thanks @Alex-Alaniz.
|
||||
- Config: auto-migrate legacy state/config paths and keep config resolution consistent across legacy filenames.
|
||||
- Discord: add configurable privileged gateway intents for presences/members. (#2266) Thanks @kentaro.
|
||||
- Docs: add Vercel AI Gateway to providers sidebar. (#1901) Thanks @jerilynzheng.
|
||||
- Agents: expand cron tool description with full schema docs. (#1988) Thanks @tomascupr.
|
||||
- Skills: add missing dependency metadata for GitHub, Notion, Slack, Discord. (#1995) Thanks @jackheuberger.
|
||||
- Docs: add Render deployment guide. (#1975) Thanks @anurag.
|
||||
- Docs: add Claude Max API Proxy guide. (#1875) Thanks @atalovesyou.
|
||||
- Docs: add DigitalOcean deployment guide. (#1870) Thanks @0xJonHoldsCrypto.
|
||||
- Docs: add Oracle Cloud (OCI) platform guide + cross-links. (#2333) Thanks @hirefrank.
|
||||
- Docs: add Raspberry Pi install guide. (#1871) Thanks @0xJonHoldsCrypto.
|
||||
- Docs: add GCP Compute Engine deployment guide. (#1848) Thanks @hougangdev.
|
||||
- Docs: add LINE channel guide. Thanks @thewilloftheshadow.
|
||||
- Docs: credit both contributors for Control UI refresh. (#1852) Thanks @EnzeD.
|
||||
- Onboarding: add Venice API key to non-interactive flow. (#1893) Thanks @jonisjongithub.
|
||||
- Onboarding: strengthen security warning copy for beta + access control expectations.
|
||||
- Tlon: format thread reply IDs as @ud. (#1837) Thanks @wca4a.
|
||||
- Gateway: prefer newest session metadata when combining stores. (#1823) Thanks @emanuelst.
|
||||
- Web UI: keep sub-agent announce replies visible in WebChat. (#1977) Thanks @andrescardonas7.
|
||||
- CI: increase Node heap size for macOS checks. (#1890) Thanks @realZachi.
|
||||
- macOS: avoid crash when rendering code blocks by bumping Textual to 0.3.1. (#2033) Thanks @garricn.
|
||||
- Browser: fall back to URL matching for extension relay target resolution. (#1999) Thanks @jonit-dev.
|
||||
- Browser: route browser control via gateway/node; remove standalone browser control command and control URL config.
|
||||
- Browser: route `browser.request` via node proxies when available; honor proxy timeouts; derive browser ports from `gateway.port`.
|
||||
- Update: ignore dist/control-ui for dirty checks and restore after ui builds. (#1976) Thanks @Glucksberg.
|
||||
- Build: bundle A2UI assets during build and stop tracking generated bundles. (#2455) Thanks @0oAstro.
|
||||
- Telegram: allow caption param for media sends. (#1888) Thanks @mguellsegarra.
|
||||
- Telegram: support plugin sendPayload channelData (media/buttons) and validate plugin commands. (#1917) Thanks @JoshuaLelon.
|
||||
- Telegram: avoid block replies when streaming is disabled. (#1885) Thanks @ivancasco.
|
||||
- Docs: keep docs header sticky so navbar stays visible while scrolling. (#2445) Thanks @chenyuan99.
|
||||
- Docs: update exe.dev install instructions. (#https://github.com/moltbot/moltbot/pull/3047) Thanks @zackerthescar.
|
||||
- Security: use Windows ACLs for permission audits and fixes on Windows. (#1957)
|
||||
- Auth: show copyable Google auth URL after ASCII prompt. (#1787) Thanks @robbyczgw-cla.
|
||||
- Routing: precompile session key regexes. (#1697) Thanks @Ray0907.
|
||||
- TUI: avoid width overflow when rendering selection lists. (#1686) Thanks @mossein.
|
||||
- Telegram: keep topic IDs in restart sentinel notifications. (#1807) Thanks @hsrvc.
|
||||
- Telegram: add optional silent send flag (disable notifications). (#2382) Thanks @Suksham-sharma.
|
||||
- Telegram: support editing sent messages via message(action="edit"). (#2394) Thanks @marcelomar21.
|
||||
- Telegram: support quote replies for message tool and inbound context. (#2900) Thanks @aduk059.
|
||||
- Telegram: add sticker receive/send with vision caching. (#2629) Thanks @longjos.
|
||||
- Telegram: send sticker pixels to vision models. (#2650)
|
||||
- Config: apply config.env before ${VAR} substitution. (#1813) Thanks @spanishflu-est1918.
|
||||
- Slack: clear ack reaction after streamed replies. (#2044) Thanks @fancyboi999.
|
||||
- macOS: keep custom SSH usernames in remote target. (#2046) Thanks @algal.
|
||||
- CLI: use Node's module compile cache for faster startup. (#2808) Thanks @pi0.
|
||||
- Routing: add per-account DM session scope and document multi-account isolation. (#3095) Thanks @jarvis-sam.
|
||||
- Config: apply config.env before ${VAR} substitution. (#1813)
|
||||
- Web search: add Brave freshness filter parameter. (#1688) Thanks @JonUleis.
|
||||
- Control UI: improve chat session dropdown refresh, URL confirmation flow, config-save guardrails, and chat composer sizing. (#3682, #3578, #1707, #2950)
|
||||
- Commands: group /help and /commands output with Telegram paging. (#2504) Thanks @hougangdev.
|
||||
- CLI: use Node's compile cache for faster startup; recognize versioned node binaries (e.g., node-22). (#2808, #2490) Thanks @pi0, @David-Marsh-Photo.
|
||||
- Agents: summarize dropped messages during compaction safeguard pruning. (#2509) Thanks @jogi47.
|
||||
- Skills: add multi-image input support to Nano Banana Pro skill. (#1958) Thanks @tyler6204.
|
||||
- Matrix: switch plugin SDK to @vector-im/matrix-bot-sdk.
|
||||
- Docs: new deployment guides (Northflank, Render, Oracle, Raspberry Pi, GCP, DigitalOcean), Claude Max API Proxy, Vercel AI Gateway, migration guide, formal verification updates, and Fly private hardening. (#2167, #1975, #2333, #1871, #1848, #1870, #1875, #1901, #2381, #2289)
|
||||
- Onboarding: add Venice API key to non-interactive flow; strengthen security warning copy.
|
||||
|
||||
### Breaking
|
||||
- **BREAKING:** Gateway auth mode "none" is removed; gateway now requires token/password (Tailscale Serve identity still allowed).
|
||||
|
||||
### Fixes
|
||||
- Telegram: avoid silent empty replies by tracking normalization skips before fallback. (#3796)
|
||||
- Mentions: honor mentionPatterns even when explicit mentions are present. (#3303) Thanks @HirokiKobayashi-R.
|
||||
- Discord: restore username directory lookup in target resolution. (#3131) Thanks @bonald.
|
||||
- Agents: align MiniMax base URL test expectation with default provider config. (#3131) Thanks @bonald.
|
||||
- Agents: prevent retries on oversized image errors and surface size limits. (#2871) Thanks @Suksham-sharma.
|
||||
- Agents: inherit provider baseUrl/api for inline models. (#2740) Thanks @lploc94.
|
||||
- Memory Search: keep auto provider model defaults and only include remote when configured. (#2576) Thanks @papago2355.
|
||||
- Telegram: include AccountId in native command context for multi-agent routing. (#2942) Thanks @Chloe-VP.
|
||||
- Telegram: handle video note attachments in media extraction. (#2905) Thanks @mylukin.
|
||||
- TTS: read OPENAI_TTS_BASE_URL at runtime instead of module load to honor config.env. (#3341) Thanks @hclsys.
|
||||
- macOS: auto-scroll to bottom when sending a new message while scrolled up. (#2471) Thanks @kennyklee.
|
||||
- Web UI: auto-expand the chat compose textarea while typing (with sensible max height). (#2950) Thanks @shivamraut101.
|
||||
- Gateway: prevent crashes on transient network errors (fetch failures, timeouts, DNS). Added fatal error detection to only exit on truly critical errors. Fixes #2895, #2879, #2873. (#2980) Thanks @elliotsecops.
|
||||
- Agents: guard channel tool listActions to avoid plugin crashes. (#2859) Thanks @mbelinky.
|
||||
- Discord: stop resolveDiscordTarget from passing directory params into messaging target parsers. Fixes #3167. Thanks @thewilloftheshadow.
|
||||
- Discord: avoid resolving bare channel names to user DMs when a username matches. Thanks @thewilloftheshadow.
|
||||
- Discord: fix directory config type import for target resolution. Thanks @thewilloftheshadow.
|
||||
- Providers: update MiniMax API endpoint and compatibility mode. (#3064) Thanks @hlbbbbbbb.
|
||||
- Telegram: treat more network errors as recoverable in polling. (#3013) Thanks @ryancontent.
|
||||
- Discord: resolve usernames to user IDs for outbound messages. (#2649) Thanks @nonggialiang.
|
||||
- Providers: update Moonshot Kimi model references to kimi-k2.5. (#2762) Thanks @MarvinCui.
|
||||
- Gateway: suppress AbortError and transient network errors in unhandled rejections. (#2451) Thanks @Glucksberg.
|
||||
- TTS: keep /tts status replies on text-only commands and avoid duplicate block-stream audio. (#2451) Thanks @Glucksberg.
|
||||
- Security: pin npm overrides to keep tar@7.5.4 for install toolchains.
|
||||
- Security: properly test Windows ACL audit for config includes. (#2403) Thanks @dominicnunez.
|
||||
- CLI: recognize versioned Node executables when parsing argv. (#2490) Thanks @David-Marsh-Photo.
|
||||
- CLI: avoid prompting for gateway runtime under the spinner. (#2874)
|
||||
- BlueBubbles: coalesce inbound URL link preview messages. (#1981) Thanks @tyler6204.
|
||||
- Cron: allow payloads containing "heartbeat" in event filter. (#2219) Thanks @dwfinkelstein.
|
||||
- CLI: avoid loading config for global help/version while registering plugin commands. (#2212) Thanks @dial481.
|
||||
- Agents: include memory.md when bootstrapping memory context. (#2318) Thanks @czekaj.
|
||||
- Agents: release session locks on process termination and cover more signals. (#2483) Thanks @janeexai.
|
||||
- Agents: skip cooldowned providers during model failover. (#2143) Thanks @YiWang24.
|
||||
- Telegram: harden polling + retry behavior for transient network errors and Node 22 transport issues. (#2420) Thanks @techboss.
|
||||
- Telegram: ignore non-forum group message_thread_id while preserving DM thread sessions. (#2731) Thanks @dylanneve1.
|
||||
- Telegram: wrap reasoning italics per line to avoid raw underscores. (#2181) Thanks @YuriNachos.
|
||||
- Telegram: centralize API error logging for delivery and bot calls. (#2492) Thanks @altryne.
|
||||
- Voice Call: enforce Twilio webhook signature verification for ngrok URLs; disable ngrok free tier bypass by default.
|
||||
- Security: harden Tailscale Serve auth by validating identity via local tailscaled before trusting headers.
|
||||
- Media: fix text attachment MIME misclassification with CSV/TSV inference and UTF-16 detection; add XML attribute escaping for file output. (#3628) Thanks @frankekn.
|
||||
- Build: align memory-core peer dependency with lockfile.
|
||||
- Security: add mDNS discovery mode with minimal default to reduce information disclosure. (#1882) Thanks @orlyjamie.
|
||||
- Security: harden URL fetches with DNS pinning to reduce rebinding risk. Thanks Chris Zheng.
|
||||
- Web UI: improve WebChat image paste previews and allow image-only sends. (#1925) Thanks @smartprogrammer93.
|
||||
- Security: wrap external hook content by default with a per-hook opt-out. (#1827) Thanks @mertcicekci0.
|
||||
- Gateway: default auth now fail-closed (token/password required; Tailscale Serve identity remains allowed).
|
||||
- Gateway: treat loopback + non-local Host connections as remote unless trusted proxy headers are present.
|
||||
- Onboarding: remove unsupported gateway auth "off" choice from onboarding/configure flows and CLI flags.
|
||||
- Security: harden SSH tunnel target parsing to prevent option injection/DoS. (#4001) Thanks @YLChen-007.
|
||||
- Security: prevent PATH injection in exec sandbox; harden file serving; pin DNS in URL fetches; verify Twilio webhooks; fix LINE webhook timing-attack edge case; validate Tailscale Serve identity; flag loopback Control UI with auth disabled as critical. (#1616, #1795)
|
||||
- Gateway: prevent crashes on transient network errors, suppress AbortError/unhandled rejections, sanitize error responses, clean session locks on exit, and harden reverse proxy handling for unauthenticated proxied connects. (#2980, #2451, #2483, #1795)
|
||||
- Config: auto-migrate legacy state/config paths; honor state dir overrides.
|
||||
- Packaging: include missing dist/shared and dist/link-understanding outputs in npm tarball installs.
|
||||
- Telegram: avoid silent empty replies, improve polling/network recovery, handle video notes, keep DM thread sessions, ignore non-forum message_thread_id, centralize API error logging, include AccountId in native command context. (#3796, #3013, #2905, #2731, #2492, #2942)
|
||||
- Discord: restore username resolution, resolve outbound usernames to IDs, honor threadId replies, guard forum thread access. (#3131, #2649)
|
||||
- BlueBubbles: coalesce URL link previews, improve reaction handling, preserve reply-tag GUIDs. (#1981, #1641)
|
||||
- Voice Call: prevent TTS overlap, validate env-var config, return TwiML for conversation calls. (#1713, #1634)
|
||||
- Media: fix text attachment MIME classification + XML escaping on Windows. (#3628, #3750)
|
||||
- Models: inherit provider baseUrl/api for inline models. (#2740) Thanks @lploc94.
|
||||
- Web UI: auto-scroll on send; fix textarea sizing; improve chat session refresh. (#2471, #2950, #3682)
|
||||
- CLI/TUI: resume sessions cleanly; guard width overflow; avoid spinner prompt race. (#1921, #1686, #2874)
|
||||
- Slack: fix file downloads failing on redirects with missing auth header. (#1936)
|
||||
- iMessage: normalize messaging targets. (#1708)
|
||||
- Signal: fix reactions and add configurable startup timeout. (#1651, #1677)
|
||||
- Matrix: decrypt E2EE media with size guard. (#1744)
|
||||
|
||||
## 2026.1.24-3
|
||||
|
||||
### Fixes
|
||||
- Slack: fix image downloads failing due to missing Authorization header on cross-origin redirects. (#1936) Thanks @sanderhelgesen.
|
||||
- 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.
|
||||
- CLI: resume claude-cli sessions and stream CLI replies to TUI clients. (#1921) Thanks @rmorse.
|
||||
|
||||
## 2026.1.24-2
|
||||
|
||||
### Fixes
|
||||
- Packaging: include dist/link-understanding output in npm tarball (fixes missing apply.js import on install).
|
||||
|
||||
## 2026.1.24-1
|
||||
|
||||
### Fixes
|
||||
- Packaging: include dist/shared output in npm tarball (fixes missing reasoning-tags import on install).
|
||||
|
||||
## 2026.1.24
|
||||
|
||||
|
||||
@ -21,8 +21,8 @@ android {
|
||||
applicationId = "bot.molt.android"
|
||||
minSdk = 31
|
||||
targetSdk = 36
|
||||
versionCode = 202601260
|
||||
versionName = "2026.1.27-beta.1"
|
||||
versionCode = 202601290
|
||||
versionName = "2026.1.29"
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
|
||||
@ -19,9 +19,9 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>2026.1.27-beta.1</string>
|
||||
<string>2026.1.29</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>20260126</string>
|
||||
<string>20260129</string>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSAllowsArbitraryLoadsInWebContent</key>
|
||||
|
||||
@ -17,8 +17,8 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>BNDL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>2026.1.27-beta.1</string>
|
||||
<string>2026.1.29</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>20260126</string>
|
||||
<string>20260129</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@ -81,8 +81,8 @@ targets:
|
||||
properties:
|
||||
CFBundleDisplayName: Moltbot
|
||||
CFBundleIconName: AppIcon
|
||||
CFBundleShortVersionString: "2026.1.27-beta.1"
|
||||
CFBundleVersion: "20260126"
|
||||
CFBundleShortVersionString: "2026.1.29"
|
||||
CFBundleVersion: "20260129"
|
||||
UILaunchScreen: {}
|
||||
UIApplicationSceneManifest:
|
||||
UIApplicationSupportsMultipleScenes: false
|
||||
@ -130,5 +130,5 @@ targets:
|
||||
path: Tests/Info.plist
|
||||
properties:
|
||||
CFBundleDisplayName: MoltbotTests
|
||||
CFBundleShortVersionString: "2026.1.27-beta.1"
|
||||
CFBundleVersion: "20260126"
|
||||
CFBundleShortVersionString: "2026.1.29"
|
||||
CFBundleVersion: "20260129"
|
||||
|
||||
@ -15,9 +15,9 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>2026.1.27-beta.1</string>
|
||||
<string>2026.1.29</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>202601260</string>
|
||||
<string>202601290</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>Moltbot</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
|
||||
@ -185,7 +185,7 @@ cat > /data/moltbot.json << 'EOF'
|
||||
"bind": "auto"
|
||||
},
|
||||
"meta": {
|
||||
"lastTouchedVersion": "2026.1.27-beta.1"
|
||||
"lastTouchedVersion": "2026.1.29"
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
@ -30,17 +30,17 @@ Notes:
|
||||
# From repo root; set release IDs so Sparkle feed is enabled.
|
||||
# APP_BUILD must be numeric + monotonic for Sparkle compare.
|
||||
BUNDLE_ID=bot.molt.mac \
|
||||
APP_VERSION=2026.1.27-beta.1 \
|
||||
APP_VERSION=2026.1.29 \
|
||||
APP_BUILD="$(git rev-list --count HEAD)" \
|
||||
BUILD_CONFIG=release \
|
||||
SIGN_IDENTITY="Developer ID Application: <Developer Name> (<TEAMID>)" \
|
||||
scripts/package-mac-app.sh
|
||||
|
||||
# Zip for distribution (includes resource forks for Sparkle delta support)
|
||||
ditto -c -k --sequesterRsrc --keepParent dist/Moltbot.app dist/Moltbot-2026.1.27-beta.1.zip
|
||||
ditto -c -k --sequesterRsrc --keepParent dist/Moltbot.app dist/Moltbot-2026.1.29.zip
|
||||
|
||||
# Optional: also build a styled DMG for humans (drag to /Applications)
|
||||
scripts/create-dmg.sh dist/Moltbot.app dist/Moltbot-2026.1.27-beta.1.dmg
|
||||
scripts/create-dmg.sh dist/Moltbot.app dist/Moltbot-2026.1.29.dmg
|
||||
|
||||
# Recommended: build + notarize/staple zip + DMG
|
||||
# First, create a keychain profile once:
|
||||
@ -48,26 +48,26 @@ scripts/create-dmg.sh dist/Moltbot.app dist/Moltbot-2026.1.27-beta.1.dmg
|
||||
# --apple-id "<apple-id>" --team-id "<team-id>" --password "<app-specific-password>"
|
||||
NOTARIZE=1 NOTARYTOOL_PROFILE=moltbot-notary \
|
||||
BUNDLE_ID=bot.molt.mac \
|
||||
APP_VERSION=2026.1.27-beta.1 \
|
||||
APP_VERSION=2026.1.29 \
|
||||
APP_BUILD="$(git rev-list --count HEAD)" \
|
||||
BUILD_CONFIG=release \
|
||||
SIGN_IDENTITY="Developer ID Application: <Developer Name> (<TEAMID>)" \
|
||||
scripts/package-mac-dist.sh
|
||||
|
||||
# Optional: ship dSYM alongside the release
|
||||
ditto -c -k --keepParent apps/macos/.build/release/Moltbot.app.dSYM dist/Moltbot-2026.1.27-beta.1.dSYM.zip
|
||||
ditto -c -k --keepParent apps/macos/.build/release/Moltbot.app.dSYM dist/Moltbot-2026.1.29.dSYM.zip
|
||||
```
|
||||
|
||||
## Appcast entry
|
||||
Use the release note generator so Sparkle renders formatted HTML notes:
|
||||
```bash
|
||||
SPARKLE_PRIVATE_KEY_FILE=/path/to/ed25519-private-key scripts/make_appcast.sh dist/Moltbot-2026.1.27-beta.1.zip https://raw.githubusercontent.com/moltbot/moltbot/main/appcast.xml
|
||||
SPARKLE_PRIVATE_KEY_FILE=/path/to/ed25519-private-key scripts/make_appcast.sh dist/Moltbot-2026.1.29.zip https://raw.githubusercontent.com/moltbot/moltbot/main/appcast.xml
|
||||
```
|
||||
Generates HTML release notes from `CHANGELOG.md` (via [`scripts/changelog-to-html.sh`](https://github.com/moltbot/moltbot/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.
|
||||
|
||||
## Publish & verify
|
||||
- Upload `Moltbot-2026.1.27-beta.1.zip` (and `Moltbot-2026.1.27-beta.1.dSYM.zip`) to the GitHub release for tag `v2026.1.27-beta.1`.
|
||||
- Upload `Moltbot-2026.1.29.zip` (and `Moltbot-2026.1.29.dSYM.zip`) to the GitHub release for tag `v2026.1.29`.
|
||||
- Ensure the raw appcast URL matches the baked feed: `https://raw.githubusercontent.com/moltbot/moltbot/main/appcast.xml`.
|
||||
- Sanity checks:
|
||||
- `curl -I https://raw.githubusercontent.com/moltbot/moltbot/main/appcast.xml` returns 200.
|
||||
|
||||
@ -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.
|
||||
|
||||
1) **Version & metadata**
|
||||
- [ ] Bump `package.json` version (e.g., `2026.1.27-beta.1`).
|
||||
- [ ] Bump `package.json` version (e.g., `2026.1.29`).
|
||||
- [ ] Run `pnpm plugins:sync` to align extension package versions + changelogs.
|
||||
- [ ] Update CLI/version strings: [`src/cli/program.ts`](https://github.com/moltbot/moltbot/blob/main/src/cli/program.ts) and the Baileys user agent in [`src/provider-web.ts`](https://github.com/moltbot/moltbot/blob/main/src/provider-web.ts).
|
||||
- [ ] Confirm package metadata (name, description, repository, keywords, license) and `bin` map points to [`moltbot.mjs`](https://github.com/moltbot/moltbot/blob/main/moltbot.mjs) for `moltbot`.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@moltbot/bluebubbles",
|
||||
"version": "2026.1.27-beta.1",
|
||||
"version": "2026.1.29",
|
||||
"type": "module",
|
||||
"description": "Moltbot BlueBubbles channel plugin",
|
||||
"moltbot": {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@moltbot/copilot-proxy",
|
||||
"version": "2026.1.27-beta.1",
|
||||
"version": "2026.1.29",
|
||||
"type": "module",
|
||||
"description": "Moltbot Copilot Proxy provider plugin",
|
||||
"moltbot": {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@moltbot/diagnostics-otel",
|
||||
"version": "2026.1.27-beta.1",
|
||||
"version": "2026.1.29",
|
||||
"type": "module",
|
||||
"description": "Moltbot diagnostics OpenTelemetry exporter",
|
||||
"moltbot": {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@moltbot/discord",
|
||||
"version": "2026.1.27-beta.1",
|
||||
"version": "2026.1.29",
|
||||
"type": "module",
|
||||
"description": "Moltbot Discord channel plugin",
|
||||
"moltbot": {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@moltbot/google-antigravity-auth",
|
||||
"version": "2026.1.27-beta.1",
|
||||
"version": "2026.1.29",
|
||||
"type": "module",
|
||||
"description": "Moltbot Google Antigravity OAuth provider plugin",
|
||||
"moltbot": {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@moltbot/google-gemini-cli-auth",
|
||||
"version": "2026.1.27-beta.1",
|
||||
"version": "2026.1.29",
|
||||
"type": "module",
|
||||
"description": "Moltbot Gemini CLI OAuth provider plugin",
|
||||
"moltbot": {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@moltbot/googlechat",
|
||||
"version": "2026.1.27-beta.1",
|
||||
"version": "2026.1.29",
|
||||
"type": "module",
|
||||
"description": "Moltbot Google Chat channel plugin",
|
||||
"moltbot": {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@moltbot/imessage",
|
||||
"version": "2026.1.27-beta.1",
|
||||
"version": "2026.1.29",
|
||||
"type": "module",
|
||||
"description": "Moltbot iMessage channel plugin",
|
||||
"moltbot": {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@moltbot/line",
|
||||
"version": "2026.1.27-beta.1",
|
||||
"version": "2026.1.29",
|
||||
"type": "module",
|
||||
"description": "Moltbot LINE channel plugin",
|
||||
"moltbot": {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@moltbot/llm-task",
|
||||
"version": "2026.1.27-beta.1",
|
||||
"version": "2026.1.29",
|
||||
"type": "module",
|
||||
"description": "Moltbot JSON-only LLM task plugin",
|
||||
"moltbot": {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@moltbot/lobster",
|
||||
"version": "2026.1.27-beta.1",
|
||||
"version": "2026.1.29",
|
||||
"type": "module",
|
||||
"description": "Lobster workflow tool plugin (typed pipelines + resumable approvals)",
|
||||
"moltbot": {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
# Changelog
|
||||
|
||||
## 2026.1.27-beta.1
|
||||
## 2026.1.29
|
||||
|
||||
### Changes
|
||||
- Version alignment with core Moltbot release numbers.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@moltbot/matrix",
|
||||
"version": "2026.1.27-beta.1",
|
||||
"version": "2026.1.29",
|
||||
"type": "module",
|
||||
"description": "Moltbot Matrix channel plugin",
|
||||
"moltbot": {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@moltbot/mattermost",
|
||||
"version": "2026.1.27-beta.1",
|
||||
"version": "2026.1.29",
|
||||
"type": "module",
|
||||
"description": "Moltbot Mattermost channel plugin",
|
||||
"moltbot": {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@moltbot/memory-core",
|
||||
"version": "2026.1.27-beta.1",
|
||||
"version": "2026.1.29",
|
||||
"type": "module",
|
||||
"description": "Moltbot core memory search plugin",
|
||||
"moltbot": {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@moltbot/memory-lancedb",
|
||||
"version": "2026.1.27-beta.1",
|
||||
"version": "2026.1.29",
|
||||
"type": "module",
|
||||
"description": "Moltbot LanceDB-backed long-term memory plugin with auto-recall/capture",
|
||||
"dependencies": {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
# Changelog
|
||||
|
||||
## 2026.1.27-beta.1
|
||||
## 2026.1.29
|
||||
|
||||
### Changes
|
||||
- Version alignment with core Moltbot release numbers.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@moltbot/msteams",
|
||||
"version": "2026.1.27-beta.1",
|
||||
"version": "2026.1.29",
|
||||
"type": "module",
|
||||
"description": "Moltbot Microsoft Teams channel plugin",
|
||||
"moltbot": {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@moltbot/nextcloud-talk",
|
||||
"version": "2026.1.27-beta.1",
|
||||
"version": "2026.1.29",
|
||||
"type": "module",
|
||||
"description": "Moltbot Nextcloud Talk channel plugin",
|
||||
"moltbot": {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
# Changelog
|
||||
|
||||
## 2026.1.27-beta.1
|
||||
## 2026.1.29
|
||||
|
||||
### Changes
|
||||
- Version alignment with core Moltbot release numbers.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@moltbot/nostr",
|
||||
"version": "2026.1.27-beta.1",
|
||||
"version": "2026.1.29",
|
||||
"type": "module",
|
||||
"description": "Moltbot Nostr channel plugin for NIP-04 encrypted DMs",
|
||||
"moltbot": {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@moltbot/open-prose",
|
||||
"version": "2026.1.27-beta.1",
|
||||
"version": "2026.1.29",
|
||||
"type": "module",
|
||||
"description": "OpenProse VM skill pack plugin (slash command + telemetry).",
|
||||
"moltbot": {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@moltbot/signal",
|
||||
"version": "2026.1.27-beta.1",
|
||||
"version": "2026.1.29",
|
||||
"type": "module",
|
||||
"description": "Moltbot Signal channel plugin",
|
||||
"moltbot": {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@moltbot/slack",
|
||||
"version": "2026.1.27-beta.1",
|
||||
"version": "2026.1.29",
|
||||
"type": "module",
|
||||
"description": "Moltbot Slack channel plugin",
|
||||
"moltbot": {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@moltbot/telegram",
|
||||
"version": "2026.1.27-beta.1",
|
||||
"version": "2026.1.29",
|
||||
"type": "module",
|
||||
"description": "Moltbot Telegram channel plugin",
|
||||
"moltbot": {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@moltbot/tlon",
|
||||
"version": "2026.1.27-beta.1",
|
||||
"version": "2026.1.29",
|
||||
"type": "module",
|
||||
"description": "Moltbot Tlon/Urbit channel plugin",
|
||||
"moltbot": {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
# Changelog
|
||||
|
||||
## 2026.1.27-beta.1
|
||||
## 2026.1.29
|
||||
|
||||
### Changes
|
||||
- Version alignment with core Moltbot release numbers.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@moltbot/twitch",
|
||||
"version": "2026.1.27-beta.1",
|
||||
"version": "2026.1.29",
|
||||
"description": "Moltbot Twitch channel plugin",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
# Changelog
|
||||
|
||||
## 2026.1.27-beta.1
|
||||
## 2026.1.29
|
||||
|
||||
### Changes
|
||||
- Version alignment with core Moltbot release numbers.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@moltbot/voice-call",
|
||||
"version": "2026.1.27-beta.1",
|
||||
"version": "2026.1.29",
|
||||
"type": "module",
|
||||
"description": "Moltbot voice-call plugin",
|
||||
"dependencies": {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@moltbot/whatsapp",
|
||||
"version": "2026.1.27-beta.1",
|
||||
"version": "2026.1.29",
|
||||
"type": "module",
|
||||
"description": "Moltbot WhatsApp channel plugin",
|
||||
"moltbot": {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
# Changelog
|
||||
|
||||
## 2026.1.27-beta.1
|
||||
## 2026.1.29
|
||||
|
||||
### Changes
|
||||
- Version alignment with core Moltbot release numbers.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@moltbot/zalo",
|
||||
"version": "2026.1.27-beta.1",
|
||||
"version": "2026.1.29",
|
||||
"type": "module",
|
||||
"description": "Moltbot Zalo channel plugin",
|
||||
"moltbot": {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
# Changelog
|
||||
|
||||
## 2026.1.27-beta.1
|
||||
## 2026.1.29
|
||||
|
||||
### Changes
|
||||
- Version alignment with core Moltbot release numbers.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@moltbot/zalouser",
|
||||
"version": "2026.1.27-beta.1",
|
||||
"version": "2026.1.29",
|
||||
"type": "module",
|
||||
"description": "Moltbot Zalo Personal Account plugin via zca-cli",
|
||||
"dependencies": {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "moltbot",
|
||||
"version": "2026.1.27-beta.1",
|
||||
"version": "2026.1.29",
|
||||
"description": "WhatsApp gateway CLI (Baileys web) with Pi RPC agent",
|
||||
"type": "module",
|
||||
"main": "dist/index.js",
|
||||
|
||||
@ -192,6 +192,45 @@ describe("gateway-status command", () => {
|
||||
expect(targets.some((t) => t.kind === "sshTunnel")).toBe(true);
|
||||
});
|
||||
|
||||
it("skips invalid ssh-auto discovery targets", async () => {
|
||||
const runtimeLogs: string[] = [];
|
||||
const runtime = {
|
||||
log: (msg: string) => runtimeLogs.push(msg),
|
||||
error: (_msg: string) => {},
|
||||
exit: (code: number) => {
|
||||
throw new Error(`__exit__:${code}`);
|
||||
},
|
||||
};
|
||||
|
||||
const originalUser = process.env.USER;
|
||||
try {
|
||||
process.env.USER = "steipete";
|
||||
loadConfig.mockReturnValueOnce({
|
||||
gateway: {
|
||||
mode: "remote",
|
||||
remote: {},
|
||||
},
|
||||
});
|
||||
discoverGatewayBeacons.mockResolvedValueOnce([
|
||||
{ tailnetDns: "-V" },
|
||||
{ tailnetDns: "goodhost" },
|
||||
]);
|
||||
|
||||
startSshPortForward.mockClear();
|
||||
const { gatewayStatusCommand } = await import("./gateway-status.js");
|
||||
await gatewayStatusCommand(
|
||||
{ timeout: "1000", json: true, sshAuto: true },
|
||||
runtime as unknown as import("../runtime.js").RuntimeEnv,
|
||||
);
|
||||
|
||||
expect(startSshPortForward).toHaveBeenCalledTimes(1);
|
||||
const call = startSshPortForward.mock.calls[0]?.[0] as { target: string };
|
||||
expect(call.target).toBe("steipete@goodhost");
|
||||
} finally {
|
||||
process.env.USER = originalUser;
|
||||
}
|
||||
});
|
||||
|
||||
it("infers SSH target from gateway.remote.url and ssh config", async () => {
|
||||
const runtimeLogs: string[] = [];
|
||||
const runtime = {
|
||||
|
||||
@ -107,7 +107,9 @@ export async function gatewayStatusCommand(
|
||||
const base = user ? `${user}@${host.trim()}` : host.trim();
|
||||
return sshPort !== 22 ? `${base}:${sshPort}` : base;
|
||||
})
|
||||
.filter((x): x is string => Boolean(x));
|
||||
.filter((candidate): candidate is string =>
|
||||
Boolean(candidate && parseSshTarget(candidate)),
|
||||
);
|
||||
if (candidates.length > 0) sshTarget = candidates[0] ?? null;
|
||||
}
|
||||
|
||||
|
||||
@ -18,6 +18,7 @@ import {
|
||||
import { loadConfig } from "../config/config.js";
|
||||
import { resolveMainSessionKey } from "../config/sessions.js";
|
||||
import { logWarn } from "../logger.js";
|
||||
import { isTestDefaultMemorySlotDisabled } from "../plugins/config-state.js";
|
||||
import { getPluginToolMeta } from "../plugins/tools.js";
|
||||
import { isSubagentSessionKey } from "../routing/session-key.js";
|
||||
import { normalizeMessageChannel } from "../utils/message-channel.js";
|
||||
@ -33,6 +34,7 @@ import {
|
||||
} from "./http-common.js";
|
||||
|
||||
const DEFAULT_BODY_BYTES = 2 * 1024 * 1024;
|
||||
const MEMORY_TOOL_NAMES = new Set(["memory_search", "memory_get"]);
|
||||
|
||||
type ToolsInvokeBody = {
|
||||
tool?: unknown;
|
||||
@ -47,6 +49,26 @@ function resolveSessionKeyFromBody(body: ToolsInvokeBody): string | undefined {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function resolveMemoryToolDisableReasons(cfg: ReturnType<typeof loadConfig>): string[] {
|
||||
if (!process.env.VITEST) return [];
|
||||
const reasons: string[] = [];
|
||||
const plugins = cfg.plugins;
|
||||
const slotRaw = plugins?.slots?.memory;
|
||||
const slotDisabled =
|
||||
slotRaw === null || (typeof slotRaw === "string" && slotRaw.trim().toLowerCase() === "none");
|
||||
const pluginsDisabled = plugins?.enabled === false;
|
||||
const defaultDisabled = isTestDefaultMemorySlotDisabled(cfg);
|
||||
|
||||
if (pluginsDisabled) reasons.push("plugins.enabled=false");
|
||||
if (slotDisabled) {
|
||||
reasons.push(slotRaw === null ? "plugins.slots.memory=null" : 'plugins.slots.memory="none"');
|
||||
}
|
||||
if (!pluginsDisabled && !slotDisabled && defaultDisabled) {
|
||||
reasons.push("memory plugin disabled by test default");
|
||||
}
|
||||
return reasons;
|
||||
}
|
||||
|
||||
function mergeActionIntoArgsIfSupported(params: {
|
||||
toolSchema: unknown;
|
||||
action: string | undefined;
|
||||
@ -103,6 +125,23 @@ export async function handleToolsInvokeHttpRequest(
|
||||
return true;
|
||||
}
|
||||
|
||||
if (process.env.VITEST && MEMORY_TOOL_NAMES.has(toolName)) {
|
||||
const reasons = resolveMemoryToolDisableReasons(cfg);
|
||||
if (reasons.length > 0) {
|
||||
const suffix = reasons.length > 0 ? ` (${reasons.join(", ")})` : "";
|
||||
sendJson(res, 400, {
|
||||
ok: false,
|
||||
error: {
|
||||
type: "invalid_request",
|
||||
message:
|
||||
`memory tools are disabled in tests${suffix}. ` +
|
||||
'Enable by setting plugins.slots.memory="memory-core" (and ensure plugins.enabled is not false).',
|
||||
},
|
||||
});
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
const action = typeof body.action === "string" ? body.action.trim() : undefined;
|
||||
|
||||
const argsRaw = body.args;
|
||||
|
||||
@ -54,6 +54,8 @@ describe("ssh-config", () => {
|
||||
expect(config?.host).toBe("peters-mac-studio-1.sheep-coho.ts.net");
|
||||
expect(config?.port).toBe(2222);
|
||||
expect(config?.identityFiles).toEqual(["/tmp/id_ed25519"]);
|
||||
const args = spawnMock.mock.calls[0]?.[1] as string[] | undefined;
|
||||
expect(args?.slice(-2)).toEqual(["--", "me@alias"]);
|
||||
});
|
||||
|
||||
it("returns null when ssh -G fails", async () => {
|
||||
|
||||
@ -58,7 +58,8 @@ export async function resolveSshConfig(
|
||||
args.push("-i", opts.identity.trim());
|
||||
}
|
||||
const userHost = target.user ? `${target.user}@${target.host}` : target.host;
|
||||
args.push(userHost);
|
||||
// Use "--" so userHost can't be parsed as an ssh option.
|
||||
args.push("--", userHost);
|
||||
|
||||
return await new Promise<SshResolvedConfig | null>((resolve) => {
|
||||
const child = spawn(sshPath, args, {
|
||||
|
||||
27
src/infra/ssh-tunnel.test.ts
Normal file
27
src/infra/ssh-tunnel.test.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { parseSshTarget } from "./ssh-tunnel.js";
|
||||
|
||||
describe("parseSshTarget", () => {
|
||||
it("parses user@host:port targets", () => {
|
||||
expect(parseSshTarget("me@example.com:2222")).toEqual({
|
||||
user: "me",
|
||||
host: "example.com",
|
||||
port: 2222,
|
||||
});
|
||||
});
|
||||
|
||||
it("parses host-only targets with default port", () => {
|
||||
expect(parseSshTarget("example.com")).toEqual({
|
||||
user: undefined,
|
||||
host: "example.com",
|
||||
port: 22,
|
||||
});
|
||||
});
|
||||
|
||||
it("rejects hostnames that start with '-'", () => {
|
||||
expect(parseSshTarget("-V")).toBeNull();
|
||||
expect(parseSshTarget("me@-badhost")).toBeNull();
|
||||
expect(parseSshTarget("-oProxyCommand=echo")).toBeNull();
|
||||
});
|
||||
});
|
||||
@ -41,10 +41,14 @@ export function parseSshTarget(raw: string): SshParsedTarget | null {
|
||||
const portRaw = hostPart.slice(colonIdx + 1).trim();
|
||||
const port = Number.parseInt(portRaw, 10);
|
||||
if (!host || !Number.isFinite(port) || port <= 0) return null;
|
||||
// Security: Reject hostnames starting with '-' to prevent argument injection
|
||||
if (host.startsWith("-")) return null;
|
||||
return { user: userPart, host, port };
|
||||
}
|
||||
|
||||
if (!hostPart) return null;
|
||||
// Security: Reject hostnames starting with '-' to prevent argument injection
|
||||
if (hostPart.startsWith("-")) return null;
|
||||
return { user: userPart, host: hostPart, port: 22 };
|
||||
}
|
||||
|
||||
@ -134,7 +138,8 @@ export async function startSshPortForward(opts: {
|
||||
if (opts.identity?.trim()) {
|
||||
args.push("-i", opts.identity.trim());
|
||||
}
|
||||
args.push(userHost);
|
||||
// Security: Use '--' to prevent userHost from being interpreted as an option
|
||||
args.push("--", userHost);
|
||||
|
||||
const stderr: string[] = [];
|
||||
const child = spawn("/usr/bin/ssh", args, {
|
||||
|
||||
@ -64,6 +64,72 @@ export const normalizePluginsConfig = (
|
||||
};
|
||||
};
|
||||
|
||||
const hasExplicitMemorySlot = (plugins?: MoltbotConfig["plugins"]) =>
|
||||
Boolean(plugins?.slots && Object.prototype.hasOwnProperty.call(plugins.slots, "memory"));
|
||||
|
||||
const hasExplicitMemoryEntry = (plugins?: MoltbotConfig["plugins"]) =>
|
||||
Boolean(plugins?.entries && Object.prototype.hasOwnProperty.call(plugins.entries, "memory-core"));
|
||||
|
||||
const hasExplicitPluginConfig = (plugins?: MoltbotConfig["plugins"]) => {
|
||||
if (!plugins) return false;
|
||||
if (typeof plugins.enabled === "boolean") return true;
|
||||
if (Array.isArray(plugins.allow) && plugins.allow.length > 0) return true;
|
||||
if (Array.isArray(plugins.deny) && plugins.deny.length > 0) return true;
|
||||
if (plugins.load?.paths && Array.isArray(plugins.load.paths) && plugins.load.paths.length > 0)
|
||||
return true;
|
||||
if (plugins.slots && Object.keys(plugins.slots).length > 0) return true;
|
||||
if (plugins.entries && Object.keys(plugins.entries).length > 0) return true;
|
||||
return false;
|
||||
};
|
||||
|
||||
export function applyTestPluginDefaults(
|
||||
cfg: MoltbotConfig,
|
||||
env: NodeJS.ProcessEnv = process.env,
|
||||
): MoltbotConfig {
|
||||
if (!env.VITEST) return cfg;
|
||||
const plugins = cfg.plugins;
|
||||
const explicitConfig = hasExplicitPluginConfig(plugins);
|
||||
if (explicitConfig) {
|
||||
if (hasExplicitMemorySlot(plugins) || hasExplicitMemoryEntry(plugins)) {
|
||||
return cfg;
|
||||
}
|
||||
return {
|
||||
...cfg,
|
||||
plugins: {
|
||||
...plugins,
|
||||
slots: {
|
||||
...plugins?.slots,
|
||||
memory: "none",
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
...cfg,
|
||||
plugins: {
|
||||
...plugins,
|
||||
enabled: false,
|
||||
slots: {
|
||||
...plugins?.slots,
|
||||
memory: "none",
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function isTestDefaultMemorySlotDisabled(
|
||||
cfg: MoltbotConfig,
|
||||
env: NodeJS.ProcessEnv = process.env,
|
||||
): boolean {
|
||||
if (!env.VITEST) return false;
|
||||
const plugins = cfg.plugins;
|
||||
if (hasExplicitMemorySlot(plugins) || hasExplicitMemoryEntry(plugins)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
export function resolveEnableState(
|
||||
id: string,
|
||||
origin: PluginRecord["origin"],
|
||||
|
||||
@ -10,6 +10,7 @@ import { resolveUserPath } from "../utils.js";
|
||||
import { discoverMoltbotPlugins } from "./discovery.js";
|
||||
import { loadPluginManifestRegistry } from "./manifest-registry.js";
|
||||
import {
|
||||
applyTestPluginDefaults,
|
||||
normalizePluginsConfig,
|
||||
resolveEnableState,
|
||||
resolveMemorySlotDecision,
|
||||
@ -162,7 +163,7 @@ function pushDiagnostics(diagnostics: PluginDiagnostic[], append: PluginDiagnost
|
||||
}
|
||||
|
||||
export function loadMoltbotPlugins(options: PluginLoadOptions = {}): PluginRegistry {
|
||||
const cfg = options.config ?? {};
|
||||
const cfg = applyTestPluginDefaults(options.config ?? {});
|
||||
const logger = options.logger ?? defaultLogger();
|
||||
const validateOnly = options.mode === "validate";
|
||||
const normalized = normalizePluginsConfig(cfg.plugins);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user