v2: SQLite state adapter, admin commands, compact feedback

- Replace in-memory Chat SDK state with SqliteStateAdapter — thread
  subscriptions now persist across restarts
- Add migration 002 for chat_sdk_kv, subscriptions, locks, lists tables
- Handle /clear in agent-runner (reset sessionId) — SDK has
  supportsNonInteractive:false for this command
- Pass /compact, /context, /cost, /files through to SDK as admin commands
- Skip admin commands in follow-up poll so they start fresh queries
- Emit compact_boundary events as user-visible feedback messages
- Pass NANOCLAW_ADMIN_USER_ID and NANOCLAW_ASSISTANT_NAME to containers

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
gavrielc
2026-04-09 03:58:35 +03:00
parent c31bb02c06
commit 8a06b01646
10 changed files with 283 additions and 47 deletions

View File

@@ -62,7 +62,7 @@ describe('migrations', () => {
const db = initTestDb();
runMigrations(db);
const row = db.prepare('SELECT MAX(version) as v FROM schema_version').get() as { v: number };
expect(row.v).toBe(1);
expect(row.v).toBe(2);
});
});

View File

@@ -0,0 +1,36 @@
import type Database from 'better-sqlite3';
import type { Migration } from './index.js';
export const migration002: Migration = {
version: 2,
name: 'chat-sdk-state',
up(db: Database.Database) {
db.exec(`
CREATE TABLE chat_sdk_kv (
key TEXT PRIMARY KEY,
value TEXT NOT NULL,
expires_at INTEGER
);
CREATE TABLE chat_sdk_subscriptions (
thread_id TEXT PRIMARY KEY,
subscribed_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE chat_sdk_locks (
thread_id TEXT PRIMARY KEY,
token TEXT NOT NULL,
expires_at INTEGER NOT NULL
);
CREATE TABLE chat_sdk_lists (
key TEXT NOT NULL,
idx INTEGER NOT NULL,
value TEXT NOT NULL,
expires_at INTEGER,
PRIMARY KEY (key, idx)
);
`);
},
};

View File

@@ -2,6 +2,7 @@ import type Database from 'better-sqlite3';
import { log } from '../../log.js';
import { migration001 } from './001-initial.js';
import { migration002 } from './002-chat-sdk-state.js';
export interface Migration {
version: number;
@@ -9,7 +10,7 @@ export interface Migration {
up: (db: Database.Database) => void;
}
const migrations: Migration[] = [migration001];
const migrations: Migration[] = [migration001, migration002];
export function runMigrations(db: Database.Database): void {
db.exec(`