github lukilabs/craft-agents-oss v0.9.0

7 hours ago

v0.9.0 — Claude Agent SDK runtime uplift, Lark / Feishu messaging, Telegram supergroup topics

Features

  • Claude Agent SDK uplifted to the native-binary distribution (0.2.123) — SDK 0.2.113 split the package into a thin core (@anthropic-ai/claude-agent-sdk) plus a per-platform optional dependency carrying the native claude binary. Craft Agent now resolves the binary via the build-script alias @anthropic-ai/claude-agent-sdk-binary/claude (with a per-arch package fallback in dev mode), and ripgrep moves from the deprecated SDK-bundled vendor copy to a top-level @vscode/ripgrep dep. electron-builder.yml now bundles the thin core, the binary alias, and @vscode/ripgrep as extraResources on macOS, Linux, and Windows; the build scripts cross-fetch the target arch's binary package via npm pack when the host arch differs. Bundle size grows ~210 MB per platform — intrinsic to the new SDK packaging model. (9ae87dc1)

  • Lark / Feishu messaging adapter (Phase 1 + Phase 2) — A third messaging platform alongside Telegram and WhatsApp. Connect a Lark Custom App via the Open Platform — open.larksuite.com (international) or open.feishu.cn (China) — through the same /pair flow as Telegram, with no public webhook URL required (long-connection WebSocket transport). Phase 1 covers App ID + App Secret + region selector in Settings → Messaging → Lark / Feishu, text in/out for DMs, @mentions in groups, and session pairing. Phase 2 adds live message editing (single message that streams), interactive cards for plan accept / Allow / Deny buttons (schema 2.0, max 10 buttons, 30-char labels), bidirectional image and file attachments, and Markdown rendering via Lark's post message type for bold/italic/strikethrough/links/code blocks (plain replies stay on the lighter text type). 24 new i18n keys per locale across all 7 supported locales. Closes #583, partially addresses #639 and #584. (5443aa41, e56862e4)

  • Telegram supergroup pairing and per-automation topic routing — Pair a Telegram supergroup to a workspace from Settings → Messaging → Telegram → Pair Supergroup; the bot captures the supergroup's chat.id after you type /pair <code> in any topic. Pairing requires chat.type === 'supergroup' AND is_forum === true so DMs, basic groups, and regular supergroups can't be registered as the workspace supergroup. Bound bindings render as Group › Topic #N in Settings and list_messaging_channels. Add the optional telegramTopic field to any automation matcher in automations.json and the spawned session is bound to a forum topic of that name (created on first use, reused thereafter; matchers sharing a value share one topic). Env-var expansion is supported on the topic value (e.g. "Reports: $LABEL"). (77e1f5f1, dd22996e)

    {
      "matcher": "^urgent$",
      "telegramTopic": "Urgent Alerts",
      "actions": [
        { "type": "prompt", "prompt": "Investigate the urgent issue: $LABEL" }
      ]
    }
  • Group by Unread mode in All Sessions view — A third grouping option alongside Group by Date and Group by Status splits the session list into two fixed buckets: Unread (N) on top, Read (N) below, sorted by lastMessageAt within each. Both buckets always render even when empty, so the active mode is always visible; empty groups suppress the collapse caret. The mode is disabled in state sub-views (Inbox, Flagged, etc.) where status filtering already constrains the list — those fall back to Group by Date. Collapse state is per-mode, so collapsing the Read group in Unread mode doesn't bleed into other modes. (59b826a2)

  • Telegram messaging settings rework promoted to production — The Settings → Messaging → Telegram card now splits bindings into a Direct session row (DM-paired) and a Supergroup section (collapsible chevron when paired, "Pair Supergroup" CTA when not), mirroring the WorkspaceOverrideCard pattern from AI Settings. Topic-bound bindings render as Title / # TopicName · Topic #N rows. WhatsApp and Lark cards keep the existing flat layout — they have no supergroup/topic concept. (312016a3, 7e235f8e)

Improvements

  • Resilient session message loading with a retry control — Session message loading had two failure modes that left users staring at infinite spinners: stale loaded flags after metadata refresh, and lost transport replies. A new replaceLoadedSessionAtom performs authoritative full-session updates that mark the session as loaded and update metadata in one transaction, eliminating the previous updateSessionDirect + sessionMetaMapAtom.set divergence risk. A new deriveSessionMessagesLoadState helper distinguishes in-memory ready vs stale loaded-flag, known-empty vs not-yet-loaded, and load failures vs still loading — used by ChatDisplay to surface a Retry control instead of spinning forever when a transport hiccup loses the load reply. The loading AnimatePresence switches to mode="sync" so a stale loading exit can't briefly mask ready content during recovery. (d8262fab)
  • bunfig.toml linker pinned to hoisted — Bun 1.3 changed the default to isolated, but Vite + esbuild bundling in this monorepo expects the hoisted layout (i18next, croner, pdfjs-dist, @tiptap/* must resolve at top-level node_modules). The Windows build script was already using --linker=hoisted for the same reason; codifying it in bunfig.toml removes the platform-specific divergence. (9ae87dc1)
  • Docker image now copies bunfig.toml — Without it the container was using Bun's default isolated linker, which broke the Vite build. (cbed3061, 1e85b5a2)
  • webui runtime npm deps and workspace deps now declared explicitlyapps/webui was implicitly inheriting deps via the hoisted node_modules layout. Declaring @craft-agent/{shared,ui} as workspace deps and listing every runtime npm package the source actually imports keeps the package self-contained and Docker builds reproducible. (7fd8177f, 9c9eb073)

Bug Fixes

  • Loopback custom-endpoint API keys are now sent on requests — Custom OpenAI-compatible endpoints configured against a loopback host (localhost, 127.0.0.1) had the API key silently stripped from outgoing requests, returning 401 from any local proxy that required auth. The key now flows through unchanged. Fixes #636. (62c65169)
  • Vision overrides on custom endpoints are preserved end-to-end — Custom endpoint model capabilities can now keep explicit per-model supportsImages: true / supportsImages: false overrides through scrolling and prompt changes. In particular, supportsImages: false remains available to override a global endpoint image default. (81259d0b)
  • Mermaid validation aligned with the renderermermaid_validate and the in-app diagram renderer use the same parser configuration, so a diagram that validates clean now actually renders, and validation errors mirror the renderer's error reporting. (8b39c84c)
  • Stale reconnect no longer leaves the session list unrefreshed — After a reconnect, the session list could remain bound to pre-disconnect state until the user manually refreshed. The list now refreshes authoritatively on reconnect. (3a2f7b6b)
  • Lark interactive cards render reliably — A series of fixes to the new Lark adapter: the card builder's schema-2.0 wrapper (elements under body instead of top-level), button schema (behaviors[] instead of legacy action wrapper), error extraction from axios response.data (so Lark's error code/message surface in logs instead of opaque axios fields), and WS lifecycle + event-arrival diagnostic logging. The flattened-event-payload code path from the SDK dispatcher is now handled. Plan submission, Allow/Deny buttons, and Accept Plan buttons all work end-to-end. (d47b6648, 8cc5fb3f, 23576f15, d7126b80, 1273a1d0, b958ae4f)
  • Lark connect dialog auto-dismisses on bind — After a successful pair, the connect dialog now auto-dismisses and shows confirmation copy, matching the Telegram flow. The session-menu connect submenu now lists Lark / Feishu alongside Telegram and WhatsApp. (ef8884f5, 6e3455f7)
  • WebUI OAuth popups work on iOS Safari — iOS Safari's strict popup-blocker semantics required the OAuth popup to be opened synchronously inside the user-gesture handler. The flow now reuses a pre-opened window and navigates it after the auth URL is computed, instead of opening from inside an async callback. (5e0e7d1d)

Breaking Changes

  • None for users. The Claude SDK runtime change is internal — no config changes required. Custom endpoint configs, automations, and messaging bindings continue to work unchanged.

Notes

  • Workspaces upgrading from 0.8.13 will see the bundled app size grow by ~210 MB per platform on next install — this is intrinsic to the new Claude Agent SDK packaging (the native claude binary now ships per-platform instead of a cli.js script). No action required.
  • The full Lark setup walkthrough lives at docs.craft.do/messaging/lark. When configuring the Custom App, leave the Encrypt Key field blank — long-connection mode doesn't use webhook payload encryption, and filling it in silently breaks inbound events.

Don't miss a new craft-agents-oss release

NewReleases is sending notifications on new releases.