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>
- 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>
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>
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>
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>
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>
- 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>
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>
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>
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>
**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>
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>
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>
The registerGroup() function in index.ts creates the group folder and
logs subdirectory but never copies the global CLAUDE.md template.
Agents in newly registered groups start without identity or
instructions until the container is manually fixed.
Copy groups/global/CLAUDE.md into the new group folder on registration,
substituting the assistant name if it differs from the default.
Closes#1391
POSIX-style TZ strings like IST-2 cause a hard RangeError crash in
formatMessages because Intl.DateTimeFormat only accepts IANA identifiers.
- Add isValidTimezone/resolveTimezone helpers to src/timezone.ts
- Make formatLocalTime fall back to UTC on invalid timezone
- Validate TZ candidates in config.ts before accepting
- Add timezone setup step to detect and prompt when autodetection fails
- Use node:22-slim in Dockerfile (node:24-slim Trixie package renames)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add SKILL.md for the native credential proxy feature skill.
Delete src/credential-proxy.ts and src/credential-proxy.test.ts
which became dead code after PR #1237 (OneCLI integration).
These files live on the skill/native-credential-proxy branch.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
claw was running containers with no volume mounts, so the agent
always saw an empty /workspace/group. Add build_mounts() to
replicate the same bind-mounts that container-runner.ts sets up
(group folder, .claude sessions, IPC dir, agent-runner source,
and project root for main).
Also includes upstream fix from qwibitai/nanoclaw#1368:
graceful terminate() before kill() on output sentinel, and early
return after a successful structured response so exit code stays 0.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>