refactor: remove legacy container and non-discord remnants

This commit is contained in:
Eyejoker
2026-03-20 01:07:46 +09:00
parent ea09560128
commit bb0628e8f4
82 changed files with 2712 additions and 10523 deletions

View File

@@ -1,135 +1,46 @@
---
name: add-compact
description: Add /compact command for manual context compaction. Solves context rot in long sessions by forwarding the SDK's built-in /compact slash command. Main-group or trusted sender only.
description: Verify or port the existing /compact session command in current NanoClaw.
---
# Add /compact Command
Adds a `/compact` session command that compacts conversation history to fight context rot in long-running sessions. Uses the Claude Agent SDK's built-in `/compact` slash command — no synthetic system prompts.
현재 NanoClaw에는 `/compact`가 이미 들어 있습니다. 이 스킬은 새로 브랜치를 머지하는 용도보다, 오래된 포크에 같은 기능을 옮기거나 리팩터링 뒤 동작을 검증하는 체크리스트로 씁니다.
**Session contract:** `/compact` keeps the same logical session alive. The SDK returns a new session ID after compaction (via the `init` system message), which the agent-runner forwards to the orchestrator as `newSessionId`. No destructive reset occurs — the agent retains summarized context.
## 관련 파일
## Phase 1: Pre-flight
- `src/session-commands.ts` - 명령 파싱, 권한 검사, pre-compact 처리
- `src/index.ts` - 메시지 루프에서 세션 명령을 가로채는 호출부
- `runners/agent-runner/src/index.ts` - Claude Code 쪽 compaction 처리
- `runners/codex-runner/src/index.ts` - Codex 쪽 compaction 처리
Check if `src/session-commands.ts` exists:
```bash
test -f src/session-commands.ts && echo "Already applied" || echo "Not applied"
```
If already applied, skip to Phase 3 (Verify).
## Phase 2: Apply Code Changes
Merge the skill branch:
```bash
git fetch upstream skill/compact
git merge upstream/skill/compact
```
> **Note:** `upstream` is the remote pointing to `qwibitai/nanoclaw`. If using a different remote name, substitute accordingly.
This adds:
- `src/session-commands.ts` (extract and authorize session commands)
- `src/session-commands.test.ts` (unit tests for command parsing and auth)
- Session command interception in `src/index.ts` (both `processGroupMessages` and `startMessageLoop`)
- Slash command handling in `container/agent-runner/src/index.ts`
### Validate
## 확인할 동작
1. `/compact`가 정확히 명령으로 인식되는지
2. 메인 그룹 또는 admin/trusted sender만 허용되는지
3. `/compact` 전에 들어온 메시지를 먼저 세션에 반영하는지
4. compaction 후 세션이 이어지고 `newSessionId`가 갱신되는지
5. 대화 아카이브가 `groups/<folder>/conversations/`에 남는지
## 포팅할 때 원칙
- 예전 skill branch를 다시 머지하지 말고 현재 트리의 관련 파일을 기준으로 옮깁니다
- Claude 러너와 Codex 러너 양쪽을 같이 봅니다
- `/clear``/compact`의 의미를 섞지 않습니다
## 검증
```bash
npm run typecheck
npm test
npm run build:runners
npm run build
```
### Rebuild container
그 다음 디스코드에서 확인합니다.
```bash
./container/build.sh
```
- 메인 채널에서 `/compact`
- 비메인 채널에서 일반 사용자 `/compact` 또는 멘션 포함 `/compact`
- 비메인 채널에서 admin/trusted sender의 `/compact`
### Restart service
```bash
launchctl kickstart -k gui/$(id -u)/com.nanoclaw # macOS
# Linux: systemctl --user restart nanoclaw
```
## Phase 3: Verify
### Integration Test
1. Start NanoClaw in dev mode: `npm run dev`
2. From the **main group** (self-chat), send exactly: `/compact`
3. Verify:
- The agent acknowledges compaction (e.g., "Conversation compacted.")
- The session continues — send a follow-up message and verify the agent responds coherently
- A conversation archive is written to `groups/{folder}/conversations/` (by the PreCompact hook)
- Container logs show `Compact boundary observed` (confirms SDK actually compacted)
- If `compact_boundary` was NOT observed, the response says "compact_boundary was not observed"
4. From a **non-main group** as a non-admin user, send: `@<assistant> /compact`
5. Verify:
- The bot responds with "Session commands require admin access."
- No compaction occurs, no container is spawned for the command
6. From a **non-main group** as the admin (device owner / `is_from_me`), send: `@<assistant> /compact`
7. Verify:
- Compaction proceeds normally (same behavior as main group)
8. While an **active container** is running for the main group, send `/compact`
9. Verify:
- The active container is signaled to close (authorized senders only — untrusted senders cannot kill in-flight work)
- Compaction proceeds via a new container once the active one exits
- The command is not dropped (no cursor race)
10. Send a normal message, then `/compact`, then another normal message in quick succession (same polling batch):
11. Verify:
- Pre-compact messages are sent to the agent first (check container logs for two `runAgent` calls)
- Compaction proceeds after pre-compact messages are processed
- Messages **after** `/compact` in the batch are preserved (cursor advances to `/compact`'s timestamp only) and processed on the next poll cycle
12. From a **non-main group** as a non-admin user, send `@<assistant> /compact`:
13. Verify:
- Denial message is sent ("Session commands require admin access.")
- The `/compact` is consumed (cursor advanced) — it does NOT replay on future polls
- Other messages in the same batch are also consumed (cursor is a high-water mark — this is an accepted tradeoff for the narrow edge case of denied `/compact` + other messages in the same polling interval)
- No container is killed or interrupted
14. From a **non-main group** (with `requiresTrigger` enabled) as a non-admin user, send bare `/compact` (no trigger prefix):
15. Verify:
- No denial message is sent (trigger policy prevents untrusted bot responses)
- The `/compact` is consumed silently
- Note: in groups where `requiresTrigger` is `false`, a denial message IS sent because the sender is considered reachable
16. After compaction, verify **no auto-compaction** behavior — only manual `/compact` triggers it
### Validation on Fresh Clone
```bash
git clone <your-fork> /tmp/nanoclaw-test
cd /tmp/nanoclaw-test
claude # then run /add-compact
npm run build
npm test
./container/build.sh
# Manual: send /compact from main group, verify compaction + continuation
# Manual: send @<assistant> /compact from non-main as non-admin, verify denial
# Manual: send @<assistant> /compact from non-main as admin, verify allowed
# Manual: verify no auto-compaction behavior
```
## Security Constraints
- **Main-group or trusted/admin sender only.** The main group is the user's private self-chat and is trusted (see `docs/SECURITY.md`). Non-main groups are untrusted — a careless or malicious user could wipe the agent's short-term memory. However, the device owner (`is_from_me`) is always trusted and can compact from any group.
- **No auto-compaction.** This skill implements manual compaction only. Automatic threshold-based compaction is a separate concern and should be a separate skill.
- **No config file.** NanoClaw's philosophy is customization through code changes, not configuration sprawl.
- **Transcript archived before compaction.** The existing `PreCompact` hook in the agent-runner archives the full transcript to `conversations/` before the SDK compacts it.
- **Session continues after compaction.** This is not a destructive reset. The conversation continues with summarized context.
## What This Does NOT Do
- No automatic compaction threshold (add separately if desired)
- No `/clear` command (separate skill, separate semantics — `/clear` is a destructive reset)
- No cross-group compaction (each group's session is isolated)
- No changes to the container image, Dockerfile, or build script
## Troubleshooting
- **"Session commands require admin access"**: Only the device owner (`is_from_me`) or main-group senders can use `/compact`. Other users are denied.
- **No compact_boundary in logs**: The SDK may not emit this event in all versions. Check the agent-runner logs for the warning message. Compaction may still have succeeded.
- **Pre-compact failure**: If messages before `/compact` fail to process, the error message says "Failed to process messages before /compact." The cursor advances past sent output to prevent duplicates; `/compact` remains pending for the next attempt.
정상이라면 비권한 사용자는 거부되고, 권한 있는 쪽은 세션이 압축된 뒤 계속 이어집니다.