From 0320e3fe26051be6a75a505b3e456bbb4944974e Mon Sep 17 00:00:00 2001 From: ingyukoh Date: Thu, 26 Mar 2026 16:53:07 +0900 Subject: [PATCH 1/4] docs: add ingyukoh to contributors --- CONTRIBUTORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 4038595..ab29b55 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -16,3 +16,4 @@ Thanks to everyone who has contributed to NanoClaw! - [flobo3](https://github.com/flobo3) — Flo - [edwinwzhe](https://github.com/edwinwzhe) — Edwin He - [scottgl9](https://github.com/scottgl9) — Scott Glover +- [ingyukoh](https://github.com/ingyukoh) — Ingyu Koh From 58fc5728db57b16ae55f0488ca4dd28485fa92f0 Mon Sep 17 00:00:00 2001 From: javexed <7049888+javexed@users.noreply.github.com> Date: Sun, 3 May 2026 01:03:38 -0400 Subject: [PATCH 2/4] =?UTF-8?q?feat(setup):=20add=20"Other=E2=80=A6"=20opt?= =?UTF-8?q?ion=20to=20channel=20picker?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The first-time setup picker only listed seven channels with bash installers. Users wanting to install one of the other channels (matrix, github, linear, webex, etc.) had no entry point from the picker and had to know to run /add- from Claude Code afterwards. Add an "Other…" option that prompts for a free-text name, normalizes it (accepts "matrix", "add-matrix", or "/add-matrix"), and prints a hint telling the user to run /add- from Claude Code after setup finishes. The verify step's "What's left" panel already covers the empty-channels case, so the user is not left thinking the channel was wired. Co-Authored-By: Claude Opus 4.7 (1M context) --- setup/auto.ts | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/setup/auto.ts b/setup/auto.ts index 0095321..b57672f 100644 --- a/setup/auto.ts +++ b/setup/auto.ts @@ -60,7 +60,7 @@ import { isValidTimezone } from '../src/timezone.js'; const CLI_AGENT_NAME = 'Terminal Agent'; const RUN_START = Date.now(); -type ChannelChoice = 'telegram' | 'discord' | 'whatsapp' | 'signal' | 'teams' | 'slack' | 'imessage' | 'skip'; +type ChannelChoice = 'telegram' | 'discord' | 'whatsapp' | 'signal' | 'teams' | 'slack' | 'imessage' | 'other' | 'skip'; async function main(): Promise { // Make sure ~/.local/bin is on PATH for every child process we spawn. @@ -441,7 +441,7 @@ async function main(): Promise { if (!skip.has('channel')) { channelChoice = await askChannelChoice(); - if (channelChoice !== 'skip') { + if (channelChoice !== 'skip' && channelChoice !== 'other') { await resolveDisplayName(); } if (channelChoice === 'telegram') { @@ -458,6 +458,8 @@ async function main(): Promise { await runSlackChannel(displayName!); } else if (channelChoice === 'imessage') { await runIMessageChannel(displayName!); + } else if (channelChoice === 'other') { + await askOtherChannelName(); } else { p.log.info( brandBody( @@ -1076,6 +1078,7 @@ async function askChannelChoice(): Promise { hint: 'needs public URL', }, { value: 'teams', label: 'Yes, connect Microsoft Teams', hint: 'complex setup' }, + { value: 'other', label: 'Other…', hint: 'install via /add- after setup' }, { value: 'skip', label: 'Skip for now', hint: "I'll just use the terminal" }, ], }), @@ -1085,6 +1088,26 @@ async function askChannelChoice(): Promise { return choice; } +async function askOtherChannelName(): Promise { + const answer = ensureAnswer( + await p.text({ + message: 'Which channel would you like to install?', + placeholder: 'e.g. matrix, github, linear, webex', + }), + ); + const name = (answer as string).trim().toLowerCase().replace(/^\/?(add-)?/, ''); + setupLog.userInput('other_channel', name); + phEmit('channel_other_named', { channel: name }); + p.log.info( + brandBody( + wrapForGutter( + `No bash installer for ${k.bold(name)} — open Claude Code after setup and run ${k.bold(`/add-${name}`)} to install it.`, + 4, + ), + ), + ); +} + // ─── interactive / env helpers ───────────────────────────────────────── function ensureLocalBinOnPath(): void { From 0e9dadfaeef387bbfe8c2b97f2eeecbe03ec94e1 Mon Sep 17 00:00:00 2001 From: Ziv Daniel <5122000+ziv-daniel@users.noreply.github.com> Date: Sun, 3 May 2026 15:40:46 +0300 Subject: [PATCH 3/4] fix: accept media-only messages with empty text in onNewMessage /./ requires at least one character and silently drops messages with no text (e.g. Telegram photo/video/file sent without a caption). Switching to /[\s\S]*/ matches the empty string too, so media-only messages now reach the router and then the agent. --- src/channels/chat-sdk-bridge.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/channels/chat-sdk-bridge.ts b/src/channels/chat-sdk-bridge.ts index 18ab2cb..52c92ba 100644 --- a/src/channels/chat-sdk-bridge.ts +++ b/src/channels/chat-sdk-bridge.ts @@ -253,12 +253,12 @@ export function createChatSdkBridge(config: ChatSdkBridgeConfig): ChannelAdapter // Chat SDK dispatch (handling-events.mdx §"Handler dispatch order") is // exclusive: subscribed → onSubscribedMessage; unsubscribed+mention → // onNewMention; unsubscribed+pattern-match → onNewMessage. Registering - // with `/./` lets the router see every plain message on every - // unsubscribed thread the bot can see. The router short-circuits via + // with `/[\s\S]*/` lets the router see every plain message (including + // media-only messages with empty text) on every unsubscribed thread the // getMessagingGroupWithAgentCount (~1 DB read) for unwired channels, // so forwarding every one is cheap enough to not need a bridge-side // flood gate. - chat.onNewMessage(/./, async (thread, message) => { + chat.onNewMessage(/[\s\S]*/, async (thread, message) => { const channelId = adapter.channelIdFromThreadId(thread.id); await setupConfig.onInbound(channelId, thread.id, await messageToInbound(message, false, true)); }); From 7fc68a100814b21bb2adc45e43a3e021dd4927f6 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 3 May 2026 14:04:59 +0000 Subject: [PATCH 4/4] chore: bump version to 2.0.28 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 446bc1b..f305bec 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nanoclaw", - "version": "2.0.27", + "version": "2.0.28", "description": "Personal Claude assistant. Lightweight, secure, customizable.", "type": "module", "packageManager": "pnpm@10.33.0",