feat(v2): builder-agent self-modification WIP + container-config as per-group file
Checkpoints the builder-agent dev-agent/worktree/swap flow (create_dev_agent, request_swap, classifier, deadman, promote) before pivoting to a unified draft-activate approach with OS-level RO enforcement. Lifts container_config out of the agent_groups row into groups/<folder>/container.json so install_packages, add_mcp_server, and rebuild flows can eventually route through the same draft path as source edits. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -12,7 +12,6 @@ export const migration001: Migration = {
|
||||
name TEXT NOT NULL,
|
||||
folder TEXT NOT NULL UNIQUE,
|
||||
agent_provider TEXT,
|
||||
container_config TEXT,
|
||||
created_at TEXT NOT NULL
|
||||
);
|
||||
|
||||
|
||||
44
src/db/migrations/006-pending-swaps.ts
Normal file
44
src/db/migrations/006-pending-swaps.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import type { Migration } from './index.js';
|
||||
|
||||
/**
|
||||
* `pending_swaps` — backs the builder-agent self-modification flow. One row
|
||||
* per in-flight swap request from a dev agent. Everything swap-lifecycle fits
|
||||
* on one row: approval state, classification, pre-swap git SHA for rollback,
|
||||
* DB snapshot path, deadman timer, handshake state.
|
||||
*
|
||||
* Status transitions: pending_approval → awaiting_confirmation →
|
||||
* (finalized | rolled_back | rejected).
|
||||
*
|
||||
* Handshake state (only meaningful while status = awaiting_confirmation):
|
||||
* pending_restart → message1_sent → confirmed | rolled_back.
|
||||
*/
|
||||
export const migration006: Migration = {
|
||||
version: 6,
|
||||
name: 'pending-swaps',
|
||||
up(db) {
|
||||
db.exec(`
|
||||
CREATE TABLE pending_swaps (
|
||||
request_id TEXT PRIMARY KEY,
|
||||
dev_agent_id TEXT NOT NULL REFERENCES agent_groups(id),
|
||||
originating_group_id TEXT NOT NULL REFERENCES agent_groups(id),
|
||||
dev_branch TEXT NOT NULL,
|
||||
commit_sha TEXT NOT NULL,
|
||||
classification TEXT NOT NULL,
|
||||
status TEXT NOT NULL DEFAULT 'pending_approval',
|
||||
summary_json TEXT NOT NULL,
|
||||
pre_swap_sha TEXT,
|
||||
db_snapshot_path TEXT,
|
||||
deadman_started_at TEXT,
|
||||
deadman_expires_at TEXT,
|
||||
handshake_state TEXT,
|
||||
created_at TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX idx_pending_swaps_originating_status
|
||||
ON pending_swaps(originating_group_id, status);
|
||||
|
||||
CREATE INDEX idx_pending_swaps_status
|
||||
ON pending_swaps(status);
|
||||
`);
|
||||
},
|
||||
};
|
||||
43
src/db/migrations/007-pending-approvals-title-options.ts
Normal file
43
src/db/migrations/007-pending-approvals-title-options.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import type { Migration } from './index.js';
|
||||
|
||||
/**
|
||||
* Retroactive schema fix: earlier migration 003 was edited after it had
|
||||
* already been applied in the wild, adding `title` and `options_json`
|
||||
* columns to its CREATE TABLE statement. Installs that ran 003 before the
|
||||
* edit don't have those columns, and `createPendingApproval` (which
|
||||
* inserts into both) fails with "no such column" at runtime.
|
||||
*
|
||||
* This migration adds the missing columns via ALTER TABLE so old installs
|
||||
* catch up. On a fresh install that runs 003 at its current definition,
|
||||
* the ALTER statements will fail harmlessly (column already exists) and
|
||||
* we swallow the error per-column.
|
||||
*/
|
||||
export const migration007: Migration = {
|
||||
version: 7,
|
||||
name: 'pending-approvals-title-options',
|
||||
up(db) {
|
||||
const addIfMissing = (col: string, sql: string): void => {
|
||||
try {
|
||||
db.exec(sql);
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
if (msg.includes('duplicate column') || msg.includes('already exists')) {
|
||||
// Fresh install — column already added by the current 003
|
||||
// definition. Nothing to do.
|
||||
return;
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
void col;
|
||||
};
|
||||
|
||||
addIfMissing(
|
||||
'title',
|
||||
`ALTER TABLE pending_approvals ADD COLUMN title TEXT NOT NULL DEFAULT ''`,
|
||||
);
|
||||
addIfMissing(
|
||||
'options_json',
|
||||
`ALTER TABLE pending_approvals ADD COLUMN options_json TEXT NOT NULL DEFAULT '[]'`,
|
||||
);
|
||||
},
|
||||
};
|
||||
@@ -6,6 +6,8 @@ import { migration002 } from './002-chat-sdk-state.js';
|
||||
import { migration003 } from './003-pending-approvals.js';
|
||||
import { migration004 } from './004-agent-destinations.js';
|
||||
import { migration005 } from './005-pending-credentials.js';
|
||||
import { migration006 } from './006-pending-swaps.js';
|
||||
import { migration007 } from './007-pending-approvals-title-options.js';
|
||||
|
||||
export interface Migration {
|
||||
version: number;
|
||||
@@ -13,7 +15,15 @@ export interface Migration {
|
||||
up: (db: Database.Database) => void;
|
||||
}
|
||||
|
||||
const migrations: Migration[] = [migration001, migration002, migration003, migration004, migration005];
|
||||
const migrations: Migration[] = [
|
||||
migration001,
|
||||
migration002,
|
||||
migration003,
|
||||
migration004,
|
||||
migration005,
|
||||
migration006,
|
||||
migration007,
|
||||
];
|
||||
|
||||
export function runMigrations(db: Database.Database): void {
|
||||
db.exec(`
|
||||
|
||||
Reference in New Issue
Block a user