Commit Graph

213 Commits

Author SHA1 Message Date
gavrielc
c31bb02c06 v2 phase 5: pending questions with interactive cards
End-to-end ask_user_question flow:
- Agent MCP tool writes question card to messages_out
- Host delivery creates pending_questions row, delivers as Discord Card with buttons
- Local webhook server receives Gateway INTERACTION_CREATE events
- Acknowledges interaction + updates card to show selected answer
- Routes response back to session DB as system message
- MCP tool poll picks up response and returns to agent

Key fixes:
- Poll loop now skips system messages (reserved for MCP tool responses)
- Gateway listener uses webhookUrl forwarding mode for interaction support
- Button custom_id encodes questionId + option text for self-contained routing

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 03:26:16 +03:00
gavrielc
c348fabf22 v2 phase 5: scheduling fixes, media handling, command processing
- Host sweep: fix DELETE journal mode, busy_timeout, seq in recurrence INSERT
- Outbound files: delivery reads from outbox dir, passes buffers to adapter,
  cleans up after delivery. Chat SDK bridge sends files via postMessage.
- Inbound attachments: formatter includes attachment info in prompts
- Commands: categorize /commands as admin, filtered, or passthrough.
  Admin commands check sender against NANOCLAW_ADMIN_USER_ID.
  Filtered commands silently dropped. Passthrough sent raw to agent.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 02:59:33 +03:00
gavrielc
afbc20a6c4 v2 phase 4+5: Discord via Chat SDK, expanded MCP tools, message seq IDs
- Chat SDK bridge + Discord adapter (gateway listener, message routing)
- MCP tools refactored into modular structure: core (send_message, send_file,
  edit_message, add_reaction), scheduling (schedule/list/cancel/pause/resume
  tasks), interactive (ask_user_question, send_card), agents (send_to_agent)
- Message seq IDs: shared integer sequence across messages_in/out so agents
  see small numeric IDs instead of platform snowflakes
- busy_timeout=5000 for session DB (poll loop + MCP server concurrent access)
- Always copy agent-runner source to fix stale cache when non-index files change
- Seed script for Discord testing, e2e test script

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 02:53:39 +03:00
gavrielc
b36f127acc style: prettier formatting fixes
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 01:40:52 +03:00
gavrielc
6f2a7314d0 v2: fix agent-runner lifecycle and session DB reliability
- Use DELETE journal mode for session DBs instead of WAL. WAL doesn't
  sync reliably across Docker volume mounts (VirtioFS), causing dropped
  writes and duplicate deliveries.
- Add 20s idle detection to end the query stream. The concurrent poll
  tracks SDK activity via a new 'activity' provider event. When no SDK
  events arrive for 20s and no messages are pending, the stream ends
  and the poll loop continues.
- Add touchProcessing heartbeat so the host can distinguish active
  agents from idle ones by checking status_changed recency.
- Catch query errors in the poll loop and write error responses to
  messages_out instead of crashing the process.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 01:34:59 +03:00
gavrielc
7201fe5032 v2 phase 4: channel adapter interface, registry, and host wiring
ChannelAdapter interface with setup/deliver/teardown/setTyping lifecycle.
Self-registration pattern via channel-registry. Host wiring in index-v2
bridges inbound messages to routeInbound and outbound delivery to adapters.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 00:10:46 +03:00
gavrielc
d35386a46e style: apply prettier formatting to v2 source files
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 23:59:08 +03:00
gavrielc
03c4e3b672 v2: fix container launch for v2 agent-runner
- Override entrypoint to compile and run index-v2.js (no stdin)
- Add better-sqlite3 + @types to agent-runner dependencies
- Exclude test files from agent-runner tsconfig (Docker build)
- Add real e2e test script (host → container → Claude → session DB)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 23:49:30 +03:00
gavrielc
8535875d0c v2: add host core integration tests
Tests for session manager (folder/DB creation, shared vs per-thread
resolution, message writing), router (end-to-end routing, auto-create
messaging groups), and delivery (undelivered message detection).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 23:44:26 +03:00
gavrielc
d7c68e04b1 v2 phase 3: host core — router, session manager, delivery, sweep
Host orchestrator connecting channel events to session DBs and
delivering responses back through channel adapters.

- session-manager.ts: session folder/DB lifecycle, message writing
- container-runner-v2.ts: Docker spawn with session + agent group
  mounts, OneCLI, idle timeout, agent-runner recompilation
- router-v2.ts: inbound routing (channel → messaging group → agent
  group → session → messages_in → wake container)
- delivery.ts: two-tier polling (1s active, 60s sweep) for
  messages_out, channel adapter delivery
- host-sweep.ts: stale detection with backoff, recurrence, wake
  containers for due messages
- index-v2.ts: thin entry point wiring everything together
- scripts/test-v2-agent.ts: real Claude provider integration test

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 23:43:13 +03:00
gavrielc
3f0451b7b0 v2 phase 1: foundation — types, DB layer, logging
Add the v2 data layer: typed interfaces, central DB with migration
runner, per-entity CRUD, and agent-runner session DB operations.

- src/log.ts: concise message-first logging API
- src/types-v2.ts: AgentGroup, MessagingGroup, Session, MessageIn/Out
- src/db/: connection (WAL), migration runner, 001-initial schema,
  CRUD for agent_groups, messaging_groups, sessions, pending_questions
- container/agent-runner/src/db/: session DB connection, messages_in
  reads + status transitions, messages_out writes
- 31 new tests, all 277 tests pass

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 23:34:09 +03:00
gavrielc
90acff28ad chore: set printWidth to 120 and reformat
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 23:34:03 +03:00
gavrielc
5702760206 Merge pull request #1644 from sargunv/fix/global-memory-path
Fix global memory for main agent: correct path and add writable mount
2026-04-05 22:33:23 +03:00
Guy Ben Aharon
19ce90c663 fix 2026-04-05 21:36:42 +03:00
Guy Ben-Aharon
0918f78a0c fix 2026-04-05 20:01:46 +03:00
gavrielc
f77f9ce2c4 feat: set auto-compact threshold to 165k tokens
Compact earlier to preserve more context fidelity before the window fills.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 16:15:56 +03:00
Sargun Vohra
1488c5b251 fix: add writable global memory mount for main agent
Main group had no mount for the global memory directory
(/workspace/global), so it could only reach it through the read-only
project root. This meant the main agent couldn't write to global
memory despite groups/main/CLAUDE.md instructing it to do so.

Add a writable mount at /workspace/global for the isMain branch,
matching the read-only mount that non-main groups already have.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 21:11:48 -07:00
Gavriel Cohen
67020f9fbf feat: auto-prune stale session artifacts on startup + daily
Session files (JSONLs, debug logs, todos, telemetry, group logs) accumulate
unboundedly — especially from daily cron tasks. This adds a cleanup script
that prunes old artifacts while protecting active sessions (read from DB),
and wires it into the main process on a 24h interval.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 00:03:00 +03:00
gavrielc
032ba77a7f feat: mount store rw for main agent and add requiresTrigger to register_group
- Mount store/ separately as read-write so the main agent can access
  the SQLite database directly.
- Add requiresTrigger parameter to the register_group MCP tool
  (host IPC already supported it, but the tool never exposed it).
  Defaults to false (no trigger).
- Update group registration instructions to ask user about trigger.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 16:17:57 +03:00
exe.dev user
ee599b9f0c feat: add reply/quoted message context support
Add generic reply context fields to NewMessage (reply_to_message_id,
reply_to_message_content, reply_to_sender_name) so any channel can
pass quoted message context to the agent.

- Add thread_id and reply_to_* fields to NewMessage interface
- Add DB migration for reply context columns on messages table
- Update storeMessage/getMessagesSince/getNewMessages to persist and
  retrieve reply fields
- Render reply context as <quoted_message> XML in formatMessages
- Add DB and formatting tests

Co-Authored-By: Alfred-the-buttler <leon.alfred.bot@gmail.com>
Co-Authored-By: moktamd <moktamd@users.noreply.github.com>
Co-Authored-By: gurixs-carson <gurixs-carson@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 17:05:24 +00:00
gavrielc
468c6170a0 style: run prettier and eslint on src/
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 21:50:59 +03:00
gavrielc
001ee6ec48 fix: correct stale session regex and remove duplicate retry logic
The original regex didn't match the actual error ("No conversation
found with session ID: ..."). Added `no conversation found` pattern.

Removed the inline retry — clearing the session and returning 'error'
lets the existing group-queue.ts backoff loop retry with a fresh
session naturally. Simpler, no duplicate error paths.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 01:17:27 +03:00
Gary Walker
38009be263 fix: auto-recover from stale Claude Code session on exit code 1
When Claude Code exits with code 1 during a session resume because the
session transcript file no longer exists (ENOENT on .jsonl), clear the
stale session from SQLite and retry once with a fresh session.

Detection is targeted: only triggers on ENOENT referencing a .jsonl
file or explicit "session not found" errors. Transient failures
(network, API) fall through to the normal backoff retry path.

Also removes unrelated ollama files that were mixed in during rebase.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 23:03:44 +11:00
gavrielc
3098f28b74 Merge branch 'main' into fix/stale-session-recovery 2026-03-30 10:59:57 +03:00
Gary Walker
474346e214 fix: recover from stale Claude Code session IDs instead of retrying infinitely
When Claude Code exits with code 1 during a session resume, the group's
session ID is now cleared from the database and the query is retried with
a fresh session. This prevents the infinite retry loop that occurred when
a stale/corrupt session ID was stored in SQLite.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 16:09:56 +11:00
gavrielc
90af26a6b1 chore: remove claw skill test
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 14:23:01 +03:00
gavrielc
acb0abaf8b fix: broken tests and stale .env.example
- Fix container-runner bug: stopContainer() returns void but was
  passed to exec() as a command string. Replace with direct call
  and try/catch.
- Mock container-runtime in tests so they don't need Docker running.
- Increase claw-skill test timeout to handle slower python startup.
- Clear .env.example (telegram token was added by mistake).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 23:19:07 +03:00
gavrielc
e73bf2f324 Merge branch 'main' into fix/message-history-overflow 2026-03-27 21:39:41 +03:00
exe.dev user
c98205ca0d fix: prevent full message history from being sent to container agents
When lastAgentTimestamp was missing (new group, corrupted state, or
startup recovery), the empty-string fallback caused getMessagesSince to
return up to 200 messages — the entire group history. This sent a
massive prompt to the container agent instead of just recent messages.

Fix: recover the cursor from the last bot reply timestamp in the DB
(proof of what we already processed), and cap all prompt queries to a
configurable MAX_MESSAGES_PER_PROMPT (default 10). Covers all three
call sites: processGroupMessages, the piping path, and
recoverPendingMessages.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 18:38:40 +00:00
gavrielc
bd94c8144a Merge branch 'main' into fix/security-stopcontainer-mount 2026-03-27 17:15:06 +03:00
gavrielc
fee05f7ee8 Merge branch 'main' into ipc-fix 2026-03-27 17:10:13 +03:00
gavrielc
f138f25c79 Merge branch 'main' into fix/env-parser-single-char 2026-03-27 17:09:38 +03:00
gavrielc
e9e9e05290 Merge branch 'main' into ipc-fix 2026-03-27 17:02:42 +03:00
gavrielc
7e7492ebba style: apply prettier formatting to logger
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 15:13:39 +03:00
gavrielc
7b22e23761 chore: replace pino/pino-pretty with built-in logger
Drop 23 transitive dependencies by replacing pino + pino-pretty with a
~70-line logger that matches the same output format and API. All 80+
call sites work unchanged. Production deps now: @onecli-sh/sdk,
better-sqlite3, cron-parser.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 15:13:34 +03:00
snw35
f5375972c4 Preserve isMain on IPC updates 2026-03-26 23:20:30 +00:00
root
0f01fe2c07 fix(env): prevent crash on single-character .env values
A value like `X=a` would pass the startsWith/endsWith quote check
(both `"` and `'` are single chars), then slice(1, -1) would produce
an empty string, silently dropping the value. Add length >= 2 guard
before checking for surrounding quotes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 19:01:17 -03:00
root
a4fd4f2a2f fix(security): prevent command injection in stopContainer and mount path injection
**stopContainer (container-runtime.ts):**
- Validate container name against `^[a-zA-Z0-9][a-zA-Z0-9_.-]*$` before
  passing to shell command. Rejects names with shell metacharacters
  (`;`, `$()`, backticks, etc.) that could execute arbitrary commands.
- Changed return type from string to void — callers no longer build
  shell commands from the return value.

**mount-security.ts:**
- Reject container paths containing `:` to prevent Docker `-v` option
  injection (e.g., `repo:rw` could override readonly flags).
- Don't permanently cache "file not found" for mount allowlist — the
  file may be created later without requiring a service restart. Only
  parse/structural errors are permanently cached.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 19:00:28 -03:00
NanoClaw User
eda14f472b fix: include script field in task snapshot for current_tasks.json
The task snapshot mappings in index.ts were omitting the script field,
making it appear that scheduled tasks had no script even when one was
stored in the database.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 13:20:24 +00:00
gavrielc
c16d70cdf7 Merge branch 'main' into fix/1272-telegram-dm-backfill 2026-03-25 23:28:35 +02:00
gavrielc
3699363eb7 Merge branch 'main' into fix/claw-mounts 2026-03-25 22:47:14 +02:00
gavrielc
23e9e1c150 Merge branch 'main' into codex/fix-issue-1141-per-group-trigger 2026-03-25 22:38:04 +02:00
gavrielc
89681a6d0d Merge branch 'main' into fix/ismain-template-selection 2026-03-25 17:36:27 +02:00
gavrielc
115b0a3167 Merge branch 'main' into fix/ipc-register-group-claude-md 2026-03-25 17:36:01 +02:00
gavrielc
deece6bf35 Merge branch 'main' into feat/scheduled-task-scripts-clean 2026-03-25 17:27:59 +02:00
gavrielc
b112fafff4 Merge branch 'main' into fix/agent-runner-cache-refresh 2026-03-25 17:27:23 +02:00
Ken Bolton
300dcda9c9 Merge branch 'main' into fix/claw-mounts 2026-03-25 11:13:16 -04:00
NanoClaw User
0240f48751 fix: use main template for isMain groups in runtime registration
Main groups (e.g. telegram_main) should get the full main template
with Admin Context section, not the minimal global template.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 14:43:08 +00:00
Gabi Simons
15b9aa99ff Merge branch 'main' into feat/scheduled-task-scripts-clean 2026-03-25 06:58:09 -07:00
NanoClaw User
80f6fb2b9a style: fix prettier formatting in registerGroup template copy
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 13:37:01 +00:00