@cluesmith/codev 3.2.1 → 3.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dashboard-dist/assets/{index-DM7OU-EI.js → index-BZ1x7x1X.js} +34 -34
- package/dashboard-dist/assets/index-BZ1x7x1X.js.map +1 -0
- package/dashboard-dist/index.html +1 -1
- package/dist/agent-farm/cli.d.ts.map +1 -1
- package/dist/agent-farm/cli.js +17 -0
- package/dist/agent-farm/cli.js.map +1 -1
- package/dist/agent-farm/commands/architect.d.ts.map +1 -1
- package/dist/agent-farm/commands/architect.js +6 -17
- package/dist/agent-farm/commands/architect.js.map +1 -1
- package/dist/agent-farm/commands/cleanup.js +3 -2
- package/dist/agent-farm/commands/cleanup.js.map +1 -1
- package/dist/agent-farm/commands/db.d.ts +10 -0
- package/dist/agent-farm/commands/db.d.ts.map +1 -1
- package/dist/agent-farm/commands/db.js +77 -0
- package/dist/agent-farm/commands/db.js.map +1 -1
- package/dist/agent-farm/commands/send.d.ts +40 -12
- package/dist/agent-farm/commands/send.d.ts.map +1 -1
- package/dist/agent-farm/commands/send.js +101 -34
- package/dist/agent-farm/commands/send.js.map +1 -1
- package/dist/agent-farm/commands/spawn-worktree.d.ts +12 -7
- package/dist/agent-farm/commands/spawn-worktree.d.ts.map +1 -1
- package/dist/agent-farm/commands/spawn-worktree.js +40 -19
- package/dist/agent-farm/commands/spawn-worktree.js.map +1 -1
- package/dist/agent-farm/commands/spawn.d.ts +15 -6
- package/dist/agent-farm/commands/spawn.d.ts.map +1 -1
- package/dist/agent-farm/commands/spawn.js +24 -17
- package/dist/agent-farm/commands/spawn.js.map +1 -1
- package/dist/agent-farm/commands/stop.js +2 -2
- package/dist/agent-farm/commands/stop.js.map +1 -1
- package/dist/agent-farm/commands/tower.d.ts +1 -0
- package/dist/agent-farm/commands/tower.d.ts.map +1 -1
- package/dist/agent-farm/commands/tower.js +50 -0
- package/dist/agent-farm/commands/tower.js.map +1 -1
- package/dist/agent-farm/db/consolidate.d.ts +66 -0
- package/dist/agent-farm/db/consolidate.d.ts.map +1 -0
- package/dist/agent-farm/db/consolidate.js +406 -0
- package/dist/agent-farm/db/consolidate.js.map +1 -0
- package/dist/agent-farm/db/index.d.ts +13 -4
- package/dist/agent-farm/db/index.d.ts.map +1 -1
- package/dist/agent-farm/db/index.js +100 -470
- package/dist/agent-farm/db/index.js.map +1 -1
- package/dist/agent-farm/db/schema.d.ts +11 -4
- package/dist/agent-farm/db/schema.d.ts.map +1 -1
- package/dist/agent-farm/db/schema.js +91 -2
- package/dist/agent-farm/db/schema.js.map +1 -1
- package/dist/agent-farm/db/types.d.ts +2 -0
- package/dist/agent-farm/db/types.d.ts.map +1 -1
- package/dist/agent-farm/db/types.js +1 -0
- package/dist/agent-farm/db/types.js.map +1 -1
- package/dist/agent-farm/lib/builder-lookup.d.ts.map +1 -1
- package/dist/agent-farm/lib/builder-lookup.js +9 -3
- package/dist/agent-farm/lib/builder-lookup.js.map +1 -1
- package/dist/agent-farm/servers/codev-config-watcher.d.ts +37 -0
- package/dist/agent-farm/servers/codev-config-watcher.d.ts.map +1 -0
- package/dist/agent-farm/servers/{worktree-config-watcher.js → codev-config-watcher.js} +15 -14
- package/dist/agent-farm/servers/codev-config-watcher.js.map +1 -0
- package/dist/agent-farm/servers/command-relay.d.ts +54 -0
- package/dist/agent-farm/servers/command-relay.d.ts.map +1 -0
- package/dist/agent-farm/servers/command-relay.js +94 -0
- package/dist/agent-farm/servers/command-relay.js.map +1 -0
- package/dist/agent-farm/servers/overview.d.ts.map +1 -1
- package/dist/agent-farm/servers/overview.js +12 -6
- package/dist/agent-farm/servers/overview.js.map +1 -1
- package/dist/agent-farm/servers/tower-instances.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-instances.js +65 -55
- package/dist/agent-farm/servers/tower-instances.js.map +1 -1
- package/dist/agent-farm/servers/tower-messages.d.ts +9 -0
- package/dist/agent-farm/servers/tower-messages.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-messages.js +24 -0
- package/dist/agent-farm/servers/tower-messages.js.map +1 -1
- package/dist/agent-farm/servers/tower-routes.d.ts +1 -1
- package/dist/agent-farm/servers/tower-routes.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-routes.js +111 -35
- package/dist/agent-farm/servers/tower-routes.js.map +1 -1
- package/dist/agent-farm/servers/tower-server.js +41 -27
- package/dist/agent-farm/servers/tower-server.js.map +1 -1
- package/dist/agent-farm/servers/tower-terminals.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-terminals.js +22 -5
- package/dist/agent-farm/servers/tower-terminals.js.map +1 -1
- package/dist/agent-farm/servers/tower-types.d.ts +2 -0
- package/dist/agent-farm/servers/tower-types.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-utils.d.ts +50 -5
- package/dist/agent-farm/servers/tower-utils.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-utils.js +64 -14
- package/dist/agent-farm/servers/tower-utils.js.map +1 -1
- package/dist/agent-farm/state.d.ts +34 -21
- package/dist/agent-farm/state.d.ts.map +1 -1
- package/dist/agent-farm/state.js +125 -79
- package/dist/agent-farm/state.js.map +1 -1
- package/dist/agent-farm/types.d.ts +14 -0
- package/dist/agent-farm/types.d.ts.map +1 -1
- package/dist/agent-farm/utils/config.d.ts +24 -1
- package/dist/agent-farm/utils/config.d.ts.map +1 -1
- package/dist/agent-farm/utils/config.js +59 -3
- package/dist/agent-farm/utils/config.js.map +1 -1
- package/dist/agent-farm/utils/harness.d.ts +45 -2
- package/dist/agent-farm/utils/harness.d.ts.map +1 -1
- package/dist/agent-farm/utils/harness.js +21 -0
- package/dist/agent-farm/utils/harness.js.map +1 -1
- package/dist/agent-farm/utils/workspace-path.d.ts +16 -0
- package/dist/agent-farm/utils/workspace-path.d.ts.map +1 -0
- package/dist/agent-farm/utils/workspace-path.js +26 -0
- package/dist/agent-farm/utils/workspace-path.js.map +1 -0
- package/dist/agent-farm/utils/worktree-write-guard.d.ts +56 -0
- package/dist/agent-farm/utils/worktree-write-guard.d.ts.map +1 -0
- package/dist/agent-farm/utils/worktree-write-guard.js +222 -0
- package/dist/agent-farm/utils/worktree-write-guard.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +2 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/consult/index.d.ts +50 -2
- package/dist/commands/consult/index.d.ts.map +1 -1
- package/dist/commands/consult/index.js +121 -5
- package/dist/commands/consult/index.js.map +1 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +24 -2
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/porch/verdict.js +2 -2
- package/dist/commands/porch/verdict.js.map +1 -1
- package/dist/lib/config.d.ts +10 -0
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/forge-contracts.d.ts +8 -0
- package/dist/lib/forge-contracts.d.ts.map +1 -1
- package/dist/lib/forge-contracts.js.map +1 -1
- package/dist/lib/managed-block.d.ts +8 -2
- package/dist/lib/managed-block.d.ts.map +1 -1
- package/dist/lib/managed-block.js +32 -7
- package/dist/lib/managed-block.js.map +1 -1
- package/package.json +3 -3
- package/scripts/forge/gitea/issue-view.sh +4 -1
- package/scripts/forge/github/issue-view.sh +2 -2
- package/scripts/forge/gitlab/issue-view.sh +4 -1
- package/scripts/forge/linear/issue-view.sh +3 -2
- package/skeleton/resources/commands/consult.md +14 -0
- package/skeleton/roles/builder.md +21 -0
- package/skeleton/templates/AGENTS.md +16 -0
- package/skeleton/templates/CLAUDE.md +16 -0
- package/dashboard-dist/assets/index-DM7OU-EI.js.map +0 -1
- package/dist/agent-farm/db/migrate.d.ts +0 -20
- package/dist/agent-farm/db/migrate.d.ts.map +0 -1
- package/dist/agent-farm/db/migrate.js +0 -107
- package/dist/agent-farm/db/migrate.js.map +0 -1
- package/dist/agent-farm/servers/worktree-config-watcher.d.ts +0 -36
- package/dist/agent-farm/servers/worktree-config-watcher.d.ts.map +0 -1
- package/dist/agent-farm/servers/worktree-config-watcher.js.map +0 -1
|
@@ -5,15 +5,14 @@
|
|
|
5
5
|
* Uses better-sqlite3 for synchronous operations with proper concurrency handling.
|
|
6
6
|
*/
|
|
7
7
|
import Database from 'better-sqlite3';
|
|
8
|
-
import { existsSync, mkdirSync,
|
|
8
|
+
import { existsSync, mkdirSync, readdirSync, renameSync } from 'node:fs';
|
|
9
9
|
import { homedir } from 'node:os';
|
|
10
10
|
import { resolve, dirname, join } from 'node:path';
|
|
11
11
|
import { AGENT_FARM_DIR } from '../lib/tower-client.js';
|
|
12
|
-
import {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
//
|
|
16
|
-
let _localDb = null;
|
|
12
|
+
import { GLOBAL_SCHEMA } from './schema.js';
|
|
13
|
+
// Singleton instance. Issue #1118: there is now a single user-global database
|
|
14
|
+
// (~/.agent-farm/global.db). getDb() and getGlobalDb() both return it; the
|
|
15
|
+
// retired per-workspace state.db is no longer opened.
|
|
17
16
|
let _globalDb = null;
|
|
18
17
|
/**
|
|
19
18
|
* Ensure a directory exists
|
|
@@ -40,14 +39,17 @@ function configurePragmas(db) {
|
|
|
40
39
|
db.pragma('foreign_keys = ON');
|
|
41
40
|
}
|
|
42
41
|
/**
|
|
43
|
-
* Get the
|
|
44
|
-
*
|
|
42
|
+
* Get the database instance.
|
|
43
|
+
*
|
|
44
|
+
* Issue #1118: state.db is retired. getDb() now returns the single user-global
|
|
45
|
+
* global.db connection — the same instance as getGlobalDb(). Per-workspace rows
|
|
46
|
+
* (architect, builders) are disambiguated by their `workspace_path` column
|
|
47
|
+
* within the shared file, so the connection no longer depends on Tower's
|
|
48
|
+
* start-cwd. Kept as a distinct export so the many existing callsites that read
|
|
49
|
+
* dashboard state (architect/builders/utils/annotations) don't churn.
|
|
45
50
|
*/
|
|
46
51
|
export function getDb() {
|
|
47
|
-
|
|
48
|
-
_localDb = ensureLocalDatabase();
|
|
49
|
-
}
|
|
50
|
-
return _localDb;
|
|
52
|
+
return getGlobalDb();
|
|
51
53
|
}
|
|
52
54
|
/**
|
|
53
55
|
* Get the global database instance (global.db)
|
|
@@ -60,13 +62,12 @@ export function getGlobalDb() {
|
|
|
60
62
|
return _globalDb;
|
|
61
63
|
}
|
|
62
64
|
/**
|
|
63
|
-
* Close the
|
|
65
|
+
* Close the database connection.
|
|
66
|
+
* Issue #1118: getDb() aliases the global connection, so this closes the shared
|
|
67
|
+
* global.db. Kept for callsites that historically closed "the local db".
|
|
64
68
|
*/
|
|
65
69
|
export function closeDb() {
|
|
66
|
-
|
|
67
|
-
_localDb.close();
|
|
68
|
-
_localDb = null;
|
|
69
|
-
}
|
|
70
|
+
closeGlobalDb();
|
|
70
71
|
}
|
|
71
72
|
/**
|
|
72
73
|
* Close the global database connection
|
|
@@ -85,11 +86,11 @@ export function closeAllDbs() {
|
|
|
85
86
|
closeGlobalDb();
|
|
86
87
|
}
|
|
87
88
|
/**
|
|
88
|
-
* Get the path to the
|
|
89
|
+
* Get the path to the database.
|
|
90
|
+
* Issue #1118: the local db path is now the global db path.
|
|
89
91
|
*/
|
|
90
92
|
export function getDbPath() {
|
|
91
|
-
|
|
92
|
-
return resolve(config.stateDir, 'state.db');
|
|
93
|
+
return getGlobalDbPath();
|
|
93
94
|
}
|
|
94
95
|
/**
|
|
95
96
|
* Get the path to the global database.
|
|
@@ -105,455 +106,6 @@ export function getGlobalDbPath() {
|
|
|
105
106
|
}
|
|
106
107
|
return resolve(AGENT_FARM_DIR, dbName);
|
|
107
108
|
}
|
|
108
|
-
/**
|
|
109
|
-
* Initialize the local database (state.db)
|
|
110
|
-
*/
|
|
111
|
-
function ensureLocalDatabase() {
|
|
112
|
-
const config = getConfig();
|
|
113
|
-
const dbPath = resolve(config.stateDir, 'state.db');
|
|
114
|
-
const jsonPath = resolve(config.stateDir, 'state.json');
|
|
115
|
-
// Ensure directory exists
|
|
116
|
-
ensureDir(config.stateDir);
|
|
117
|
-
// Create/open database
|
|
118
|
-
const db = new Database(dbPath);
|
|
119
|
-
configurePragmas(db);
|
|
120
|
-
// Run schema (creates tables if they don't exist)
|
|
121
|
-
db.exec(LOCAL_SCHEMA);
|
|
122
|
-
// Check if migration is needed
|
|
123
|
-
const migrated = db.prepare('SELECT version FROM _migrations WHERE version = 1').get();
|
|
124
|
-
if (!migrated && existsSync(jsonPath)) {
|
|
125
|
-
// Migrate from JSON.
|
|
126
|
-
// Bugfix #826: pass workspaceRoot so the architect row gets tagged
|
|
127
|
-
// with workspace_path (the new composite-PK column).
|
|
128
|
-
migrateLocalFromJson(db, jsonPath, config.workspaceRoot);
|
|
129
|
-
// Record migration
|
|
130
|
-
db.prepare('INSERT INTO _migrations (version) VALUES (1)').run();
|
|
131
|
-
// Backup original JSON and remove it
|
|
132
|
-
copyFileSync(jsonPath, jsonPath + '.bak');
|
|
133
|
-
unlinkSync(jsonPath);
|
|
134
|
-
console.log('[info] Migrated state.json to state.db (backup at state.json.bak)');
|
|
135
|
-
}
|
|
136
|
-
else if (!migrated) {
|
|
137
|
-
// Fresh install, just mark migration as done
|
|
138
|
-
db.prepare('INSERT OR IGNORE INTO _migrations (version) VALUES (1)').run();
|
|
139
|
-
console.log('[info] Created new state.db at', dbPath);
|
|
140
|
-
}
|
|
141
|
-
// Migration v2: Add terminal_id columns (node-pty rewrite)
|
|
142
|
-
const v2 = db.prepare('SELECT version FROM _migrations WHERE version = 2').get();
|
|
143
|
-
if (!v2) {
|
|
144
|
-
// Add terminal_id to tables that may already exist without it
|
|
145
|
-
const tables = ['architect', 'builders', 'utils'];
|
|
146
|
-
for (const table of tables) {
|
|
147
|
-
try {
|
|
148
|
-
db.exec(`ALTER TABLE ${table} ADD COLUMN terminal_id TEXT`);
|
|
149
|
-
}
|
|
150
|
-
catch {
|
|
151
|
-
// Column already exists (fresh install ran full schema)
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
db.prepare('INSERT INTO _migrations (version) VALUES (2)').run();
|
|
155
|
-
}
|
|
156
|
-
// Migration v3: Remove UNIQUE constraint from utils.port (node-pty shells use port=0)
|
|
157
|
-
const v3 = db.prepare('SELECT version FROM _migrations WHERE version = 3').get();
|
|
158
|
-
if (!v3) {
|
|
159
|
-
// Check if utils table has the UNIQUE constraint on port
|
|
160
|
-
const tableInfo = db
|
|
161
|
-
.prepare("SELECT sql FROM sqlite_master WHERE type='table' AND name='utils'")
|
|
162
|
-
.get();
|
|
163
|
-
if (tableInfo?.sql?.includes('port INTEGER NOT NULL UNIQUE')) {
|
|
164
|
-
// SQLite can't drop constraints, so recreate table
|
|
165
|
-
db.exec(`
|
|
166
|
-
CREATE TABLE utils_new (
|
|
167
|
-
id TEXT PRIMARY KEY,
|
|
168
|
-
name TEXT NOT NULL,
|
|
169
|
-
port INTEGER NOT NULL DEFAULT 0,
|
|
170
|
-
pid INTEGER NOT NULL DEFAULT 0,
|
|
171
|
-
tmux_session TEXT,
|
|
172
|
-
terminal_id TEXT,
|
|
173
|
-
started_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
174
|
-
);
|
|
175
|
-
INSERT INTO utils_new SELECT id, name, port, pid, tmux_session, terminal_id, started_at FROM utils;
|
|
176
|
-
DROP TABLE utils;
|
|
177
|
-
ALTER TABLE utils_new RENAME TO utils;
|
|
178
|
-
`);
|
|
179
|
-
console.log('[info] Migrated utils table: removed UNIQUE constraint from port');
|
|
180
|
-
}
|
|
181
|
-
db.prepare('INSERT INTO _migrations (version) VALUES (3)').run();
|
|
182
|
-
}
|
|
183
|
-
// Migration v4: Remove UNIQUE constraint from builders.port (PTY-backed builders use port=0)
|
|
184
|
-
const v4 = db.prepare('SELECT version FROM _migrations WHERE version = 4').get();
|
|
185
|
-
if (!v4) {
|
|
186
|
-
const tableInfo = db
|
|
187
|
-
.prepare("SELECT sql FROM sqlite_master WHERE type='table' AND name='builders'")
|
|
188
|
-
.get();
|
|
189
|
-
if (tableInfo?.sql?.includes('port INTEGER NOT NULL UNIQUE')) {
|
|
190
|
-
// SQLite can't drop constraints, so recreate table
|
|
191
|
-
db.exec(`
|
|
192
|
-
CREATE TABLE builders_new (
|
|
193
|
-
id TEXT PRIMARY KEY,
|
|
194
|
-
name TEXT NOT NULL,
|
|
195
|
-
port INTEGER NOT NULL DEFAULT 0,
|
|
196
|
-
pid INTEGER NOT NULL DEFAULT 0,
|
|
197
|
-
status TEXT NOT NULL DEFAULT 'spawning'
|
|
198
|
-
CHECK(status IN ('spawning', 'implementing', 'blocked', 'pr', 'complete')),
|
|
199
|
-
phase TEXT NOT NULL DEFAULT '',
|
|
200
|
-
worktree TEXT NOT NULL,
|
|
201
|
-
branch TEXT NOT NULL,
|
|
202
|
-
tmux_session TEXT,
|
|
203
|
-
type TEXT NOT NULL DEFAULT 'spec'
|
|
204
|
-
CHECK(type IN ('spec', 'task', 'protocol', 'shell', 'worktree', 'bugfix')),
|
|
205
|
-
task_text TEXT,
|
|
206
|
-
protocol_name TEXT,
|
|
207
|
-
issue_number INTEGER,
|
|
208
|
-
terminal_id TEXT,
|
|
209
|
-
started_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
210
|
-
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
211
|
-
);
|
|
212
|
-
INSERT INTO builders_new SELECT * FROM builders;
|
|
213
|
-
DROP TABLE builders;
|
|
214
|
-
ALTER TABLE builders_new RENAME TO builders;
|
|
215
|
-
CREATE INDEX IF NOT EXISTS idx_builders_status ON builders(status);
|
|
216
|
-
CREATE INDEX IF NOT EXISTS idx_builders_port ON builders(port);
|
|
217
|
-
CREATE TRIGGER IF NOT EXISTS builders_updated_at
|
|
218
|
-
AFTER UPDATE ON builders
|
|
219
|
-
FOR EACH ROW
|
|
220
|
-
BEGIN
|
|
221
|
-
UPDATE builders SET updated_at = datetime('now') WHERE id = NEW.id;
|
|
222
|
-
END;
|
|
223
|
-
`);
|
|
224
|
-
console.log('[info] Migrated builders table: removed UNIQUE constraint from port');
|
|
225
|
-
}
|
|
226
|
-
db.prepare('INSERT INTO _migrations (version) VALUES (4)').run();
|
|
227
|
-
}
|
|
228
|
-
// Migration v5: Remove UNIQUE constraint from annotations.port (all annotations use port=0)
|
|
229
|
-
const v5 = db.prepare('SELECT version FROM _migrations WHERE version = 5').get();
|
|
230
|
-
if (!v5) {
|
|
231
|
-
const tableInfo = db
|
|
232
|
-
.prepare("SELECT sql FROM sqlite_master WHERE type='table' AND name='annotations'")
|
|
233
|
-
.get();
|
|
234
|
-
if (tableInfo?.sql?.includes('port INTEGER NOT NULL UNIQUE')) {
|
|
235
|
-
db.exec(`
|
|
236
|
-
CREATE TABLE annotations_new (
|
|
237
|
-
id TEXT PRIMARY KEY,
|
|
238
|
-
file TEXT NOT NULL,
|
|
239
|
-
port INTEGER NOT NULL DEFAULT 0,
|
|
240
|
-
pid INTEGER NOT NULL DEFAULT 0,
|
|
241
|
-
parent_type TEXT NOT NULL CHECK(parent_type IN ('architect', 'builder', 'util')),
|
|
242
|
-
parent_id TEXT,
|
|
243
|
-
started_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
244
|
-
);
|
|
245
|
-
INSERT INTO annotations_new SELECT id, file, port, pid, parent_type, parent_id, started_at FROM annotations;
|
|
246
|
-
DROP TABLE annotations;
|
|
247
|
-
ALTER TABLE annotations_new RENAME TO annotations;
|
|
248
|
-
`);
|
|
249
|
-
console.log('[info] Migrated annotations table: removed UNIQUE constraint from port');
|
|
250
|
-
}
|
|
251
|
-
db.prepare('INSERT INTO _migrations (version) VALUES (5)').run();
|
|
252
|
-
}
|
|
253
|
-
// Migration v6: Drop tmux_session columns (Spec 0104 - tmux replaced by shepherd)
|
|
254
|
-
const v6 = db.prepare('SELECT version FROM _migrations WHERE version = 6').get();
|
|
255
|
-
if (!v6) {
|
|
256
|
-
const tables = ['architect', 'builders', 'utils'];
|
|
257
|
-
for (const table of tables) {
|
|
258
|
-
try {
|
|
259
|
-
db.exec(`ALTER TABLE ${table} DROP COLUMN tmux_session`);
|
|
260
|
-
}
|
|
261
|
-
catch {
|
|
262
|
-
// Column may not exist (fresh install with updated schema)
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
db.prepare('INSERT INTO _migrations (version) VALUES (6)').run();
|
|
266
|
-
}
|
|
267
|
-
// Migration v7: Rename builder status 'pr-ready' → 'pr' (Bugfix #368)
|
|
268
|
-
const v7 = db.prepare('SELECT version FROM _migrations WHERE version = 7').get();
|
|
269
|
-
if (!v7) {
|
|
270
|
-
const tableInfo = db
|
|
271
|
-
.prepare("SELECT sql FROM sqlite_master WHERE type='table' AND name='builders'")
|
|
272
|
-
.get();
|
|
273
|
-
if (tableInfo?.sql?.includes('pr-ready')) {
|
|
274
|
-
// SQLite can't alter CHECK constraints, so recreate table
|
|
275
|
-
db.exec(`
|
|
276
|
-
CREATE TABLE builders_new (
|
|
277
|
-
id TEXT PRIMARY KEY,
|
|
278
|
-
name TEXT NOT NULL,
|
|
279
|
-
port INTEGER NOT NULL DEFAULT 0,
|
|
280
|
-
pid INTEGER NOT NULL DEFAULT 0,
|
|
281
|
-
status TEXT NOT NULL DEFAULT 'spawning'
|
|
282
|
-
CHECK(status IN ('spawning', 'implementing', 'blocked', 'pr', 'complete')),
|
|
283
|
-
phase TEXT NOT NULL DEFAULT '',
|
|
284
|
-
worktree TEXT NOT NULL,
|
|
285
|
-
branch TEXT NOT NULL,
|
|
286
|
-
type TEXT NOT NULL DEFAULT 'spec'
|
|
287
|
-
CHECK(type IN ('spec', 'task', 'protocol', 'shell', 'worktree', 'bugfix')),
|
|
288
|
-
task_text TEXT,
|
|
289
|
-
protocol_name TEXT,
|
|
290
|
-
issue_number INTEGER,
|
|
291
|
-
terminal_id TEXT,
|
|
292
|
-
started_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
293
|
-
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
294
|
-
);
|
|
295
|
-
INSERT INTO builders_new
|
|
296
|
-
SELECT id, name, port, pid,
|
|
297
|
-
CASE WHEN status = 'pr-ready' THEN 'pr' ELSE status END,
|
|
298
|
-
phase, worktree, branch, type, task_text, protocol_name,
|
|
299
|
-
issue_number, terminal_id, started_at, updated_at
|
|
300
|
-
FROM builders;
|
|
301
|
-
DROP TABLE builders;
|
|
302
|
-
ALTER TABLE builders_new RENAME TO builders;
|
|
303
|
-
CREATE INDEX IF NOT EXISTS idx_builders_status ON builders(status);
|
|
304
|
-
CREATE INDEX IF NOT EXISTS idx_builders_port ON builders(port);
|
|
305
|
-
CREATE TRIGGER IF NOT EXISTS builders_updated_at
|
|
306
|
-
AFTER UPDATE ON builders
|
|
307
|
-
FOR EACH ROW
|
|
308
|
-
BEGIN
|
|
309
|
-
UPDATE builders SET updated_at = datetime('now') WHERE id = NEW.id;
|
|
310
|
-
END;
|
|
311
|
-
`);
|
|
312
|
-
console.log('[info] Migrated builders table: renamed status pr-ready to pr');
|
|
313
|
-
}
|
|
314
|
-
db.prepare('INSERT INTO _migrations (version) VALUES (7)').run();
|
|
315
|
-
}
|
|
316
|
-
// Migration v8: Widen issue_number from INTEGER to TEXT (Linear identifiers like "ENG-123")
|
|
317
|
-
const v8 = db.prepare('SELECT version FROM _migrations WHERE version = 8').get();
|
|
318
|
-
if (!v8) {
|
|
319
|
-
const tableInfo = db
|
|
320
|
-
.prepare("SELECT sql FROM sqlite_master WHERE type='table' AND name='builders'")
|
|
321
|
-
.get();
|
|
322
|
-
if (tableInfo?.sql?.includes('issue_number INTEGER')) {
|
|
323
|
-
db.exec(`
|
|
324
|
-
CREATE TABLE builders_new (
|
|
325
|
-
id TEXT PRIMARY KEY,
|
|
326
|
-
name TEXT NOT NULL,
|
|
327
|
-
port INTEGER NOT NULL DEFAULT 0,
|
|
328
|
-
pid INTEGER NOT NULL DEFAULT 0,
|
|
329
|
-
status TEXT NOT NULL DEFAULT 'spawning'
|
|
330
|
-
CHECK(status IN ('spawning', 'implementing', 'blocked', 'pr', 'complete')),
|
|
331
|
-
phase TEXT NOT NULL DEFAULT '',
|
|
332
|
-
worktree TEXT NOT NULL,
|
|
333
|
-
branch TEXT NOT NULL,
|
|
334
|
-
type TEXT NOT NULL DEFAULT 'spec'
|
|
335
|
-
CHECK(type IN ('spec', 'task', 'protocol', 'shell', 'worktree', 'bugfix')),
|
|
336
|
-
task_text TEXT,
|
|
337
|
-
protocol_name TEXT,
|
|
338
|
-
issue_number TEXT,
|
|
339
|
-
terminal_id TEXT,
|
|
340
|
-
started_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
341
|
-
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
342
|
-
);
|
|
343
|
-
INSERT INTO builders_new
|
|
344
|
-
SELECT id, name, port, pid, status, phase, worktree, branch, type,
|
|
345
|
-
task_text, protocol_name, CAST(issue_number AS TEXT),
|
|
346
|
-
terminal_id, started_at, updated_at
|
|
347
|
-
FROM builders;
|
|
348
|
-
DROP TABLE builders;
|
|
349
|
-
ALTER TABLE builders_new RENAME TO builders;
|
|
350
|
-
CREATE INDEX IF NOT EXISTS idx_builders_status ON builders(status);
|
|
351
|
-
CREATE INDEX IF NOT EXISTS idx_builders_port ON builders(port);
|
|
352
|
-
CREATE TRIGGER IF NOT EXISTS builders_updated_at
|
|
353
|
-
AFTER UPDATE ON builders
|
|
354
|
-
FOR EACH ROW
|
|
355
|
-
BEGIN
|
|
356
|
-
UPDATE builders SET updated_at = datetime('now') WHERE id = NEW.id;
|
|
357
|
-
END;
|
|
358
|
-
`);
|
|
359
|
-
console.log('[info] Migrated builders table: widened issue_number to TEXT');
|
|
360
|
-
}
|
|
361
|
-
db.prepare('INSERT INTO _migrations (version) VALUES (8)').run();
|
|
362
|
-
}
|
|
363
|
-
// Migration v9: Multi-architect support (Spec 755)
|
|
364
|
-
// - Rebuild architect table: drop CHECK(id=1), change id to TEXT PRIMARY KEY.
|
|
365
|
-
// Rekey the existing singleton row's id from 1 to 'main'.
|
|
366
|
-
// - Add builders.spawned_by_architect TEXT column (nullable).
|
|
367
|
-
const v9 = db.prepare('SELECT version FROM _migrations WHERE version = 9').get();
|
|
368
|
-
if (!v9) {
|
|
369
|
-
const tableInfo = db
|
|
370
|
-
.prepare("SELECT sql FROM sqlite_master WHERE type='table' AND name='architect'")
|
|
371
|
-
.get();
|
|
372
|
-
// Architect table rebuild — only if it still has the old integer/CHECK shape.
|
|
373
|
-
// Detect via 'CHECK (id = 1)' (or normalized variants) in the stored DDL.
|
|
374
|
-
if (tableInfo?.sql && /CHECK\s*\(\s*id\s*=\s*1\s*\)/i.test(tableInfo.sql)) {
|
|
375
|
-
db.exec(`
|
|
376
|
-
CREATE TABLE architect_v9 (
|
|
377
|
-
id TEXT PRIMARY KEY,
|
|
378
|
-
pid INTEGER NOT NULL,
|
|
379
|
-
port INTEGER NOT NULL,
|
|
380
|
-
cmd TEXT NOT NULL,
|
|
381
|
-
started_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
382
|
-
terminal_id TEXT
|
|
383
|
-
);
|
|
384
|
-
INSERT INTO architect_v9 (id, pid, port, cmd, started_at, terminal_id)
|
|
385
|
-
SELECT 'main', pid, port, cmd, started_at, terminal_id FROM architect;
|
|
386
|
-
DROP TABLE architect;
|
|
387
|
-
ALTER TABLE architect_v9 RENAME TO architect;
|
|
388
|
-
`);
|
|
389
|
-
console.log('[info] Migrated architect table: multi-architect support (Spec 755)');
|
|
390
|
-
}
|
|
391
|
-
// Add spawned_by_architect column to builders if absent.
|
|
392
|
-
try {
|
|
393
|
-
db.exec(`ALTER TABLE builders ADD COLUMN spawned_by_architect TEXT`);
|
|
394
|
-
}
|
|
395
|
-
catch {
|
|
396
|
-
// Column already exists (fresh install ran the updated schema).
|
|
397
|
-
}
|
|
398
|
-
db.prepare('INSERT INTO _migrations (version) VALUES (9)').run();
|
|
399
|
-
}
|
|
400
|
-
// Migration v10: Add 'pir' to builders.type CHECK constraint (Issue 691).
|
|
401
|
-
// Reintroduced post main-merge (the original collided with main's v9).
|
|
402
|
-
// Drift-robust: derive builders_new from the LIVE builders DDL (only the
|
|
403
|
-
// table name + the type CHECK literal are rewritten), so `SELECT *` can
|
|
404
|
-
// never column-mismatch regardless of columns earlier migrations added
|
|
405
|
-
// (e.g. v9's spawned_by_architect). Idempotent: skips if 'pir' is already
|
|
406
|
-
// in the constraint (covers fresh installs and DBs that ran the old v9).
|
|
407
|
-
const v10 = db.prepare('SELECT version FROM _migrations WHERE version = 10').get();
|
|
408
|
-
if (!v10) {
|
|
409
|
-
const builders = db
|
|
410
|
-
.prepare("SELECT sql FROM sqlite_master WHERE type='table' AND name='builders'")
|
|
411
|
-
.get();
|
|
412
|
-
if (builders?.sql && !builders.sql.includes("'pir'")) {
|
|
413
|
-
const newSql = builders.sql
|
|
414
|
-
.replace(/^CREATE TABLE\s+(?:IF NOT EXISTS\s+)?["'`]?builders["'`]?/i, 'CREATE TABLE builders_new')
|
|
415
|
-
.replace(/(CHECK\s*\(\s*type\s+IN\s*\([^)]*)\)/i, "$1, 'pir')");
|
|
416
|
-
db.exec(`
|
|
417
|
-
${newSql};
|
|
418
|
-
INSERT INTO builders_new SELECT * FROM builders;
|
|
419
|
-
DROP TABLE builders;
|
|
420
|
-
ALTER TABLE builders_new RENAME TO builders;
|
|
421
|
-
CREATE INDEX IF NOT EXISTS idx_builders_status ON builders(status);
|
|
422
|
-
CREATE INDEX IF NOT EXISTS idx_builders_port ON builders(port);
|
|
423
|
-
CREATE TRIGGER IF NOT EXISTS builders_updated_at
|
|
424
|
-
AFTER UPDATE ON builders
|
|
425
|
-
FOR EACH ROW
|
|
426
|
-
BEGIN
|
|
427
|
-
UPDATE builders SET updated_at = datetime('now') WHERE id = NEW.id;
|
|
428
|
-
END;
|
|
429
|
-
`);
|
|
430
|
-
console.log("[info] Migrated builders table: added 'pir' to type CHECK constraint (v10)");
|
|
431
|
-
}
|
|
432
|
-
db.prepare('INSERT INTO _migrations (version) VALUES (10)').run();
|
|
433
|
-
}
|
|
434
|
-
// Migration v11: Workspace-scoped architect rows (Bugfix #826).
|
|
435
|
-
//
|
|
436
|
-
// The architect table was global per Tower process, anchored to Tower's
|
|
437
|
-
// startup CWD. With multi-architect (Spec 755 / 786), this meant siblings
|
|
438
|
-
// registered in workspace A were re-spawned into workspace B at the next
|
|
439
|
-
// launchInstance(B) — a real PTY leak. Fix by construction: add
|
|
440
|
-
// `workspace_path` as part of the primary key so rows are explicitly scoped.
|
|
441
|
-
//
|
|
442
|
-
// Backfill source: global.db.terminal_sessions has per-architect rows with
|
|
443
|
-
// workspace_path (its `role_id` column holds the architect name). We ATTACH
|
|
444
|
-
// global.db and copy that mapping into the new architect rows. Architects
|
|
445
|
-
// with no current terminal_session row are orphans (their PTY died and was
|
|
446
|
-
// cleaned up before this migration ran) — they are dropped.
|
|
447
|
-
//
|
|
448
|
-
// Idempotent: skips when workspace_path column already exists (handles fresh
|
|
449
|
-
// installs that ran the updated schema, and re-runs after partial failure).
|
|
450
|
-
const v11 = db.prepare('SELECT version FROM _migrations WHERE version = 11').get();
|
|
451
|
-
if (!v11) {
|
|
452
|
-
// Check if workspace_path column already exists (fresh install via LOCAL_SCHEMA).
|
|
453
|
-
const cols = db.prepare('PRAGMA table_info(architect)').all();
|
|
454
|
-
const alreadyMigrated = cols.some(c => c.name === 'workspace_path');
|
|
455
|
-
if (!alreadyMigrated) {
|
|
456
|
-
const globalDbPath = getGlobalDbPath();
|
|
457
|
-
// Step 1: rebuild table with composite PK (workspace_path, id).
|
|
458
|
-
// - Create _v11 table with the new shape.
|
|
459
|
-
// - Backfill workspace_path from global.db.terminal_sessions via ATTACH.
|
|
460
|
-
// Use LIMIT 1 to handle the (rare) case where multiple rows match.
|
|
461
|
-
// - Drop orphans (workspace_path IS NULL).
|
|
462
|
-
// - DETACH global.db before swapping table names.
|
|
463
|
-
// - Atomic swap: DROP architect, RENAME _v11 → architect.
|
|
464
|
-
db.exec(`
|
|
465
|
-
CREATE TABLE architect_v11 (
|
|
466
|
-
workspace_path TEXT NOT NULL,
|
|
467
|
-
id TEXT NOT NULL,
|
|
468
|
-
pid INTEGER NOT NULL,
|
|
469
|
-
port INTEGER NOT NULL,
|
|
470
|
-
cmd TEXT NOT NULL,
|
|
471
|
-
started_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
472
|
-
terminal_id TEXT,
|
|
473
|
-
PRIMARY KEY (workspace_path, id)
|
|
474
|
-
);
|
|
475
|
-
`);
|
|
476
|
-
try {
|
|
477
|
-
// ATTACH global.db so we can read terminal_sessions for the backfill.
|
|
478
|
-
db.prepare("ATTACH DATABASE ? AS globaldb").run(globalDbPath);
|
|
479
|
-
try {
|
|
480
|
-
// Backfill: for each architect row, look up its workspace_path in
|
|
481
|
-
// global.db.terminal_sessions.
|
|
482
|
-
//
|
|
483
|
-
// Disambiguation (Bugfix #826 iter-5): for users already hit by the
|
|
484
|
-
// leak, the same architect NAME can appear in MULTIPLE workspaces'
|
|
485
|
-
// terminal_sessions rows. Matching by `role_id` alone with `LIMIT 1`
|
|
486
|
-
// would pick non-deterministically and could migrate ob-refine to
|
|
487
|
-
// the wrong workspace. Use `terminal_id` as the primary disambiguator
|
|
488
|
-
// — it's the stable session UUID and uniquely identifies one
|
|
489
|
-
// terminal_session row. Fall back to `role_id` only when
|
|
490
|
-
// `terminal_id` doesn't match (legacy rows where terminal_id is NULL
|
|
491
|
-
// or its target row has been cleaned up).
|
|
492
|
-
db.exec(`
|
|
493
|
-
INSERT INTO architect_v11 (workspace_path, id, pid, port, cmd, started_at, terminal_id)
|
|
494
|
-
SELECT
|
|
495
|
-
COALESCE(
|
|
496
|
-
(SELECT ts.workspace_path
|
|
497
|
-
FROM globaldb.terminal_sessions ts
|
|
498
|
-
WHERE ts.id = a.terminal_id
|
|
499
|
-
AND ts.type = 'architect'),
|
|
500
|
-
(SELECT ts.workspace_path
|
|
501
|
-
FROM globaldb.terminal_sessions ts
|
|
502
|
-
WHERE ts.role_id = a.id
|
|
503
|
-
AND ts.type = 'architect'
|
|
504
|
-
LIMIT 1)
|
|
505
|
-
) AS workspace_path,
|
|
506
|
-
a.id,
|
|
507
|
-
a.pid,
|
|
508
|
-
a.port,
|
|
509
|
-
a.cmd,
|
|
510
|
-
a.started_at,
|
|
511
|
-
a.terminal_id
|
|
512
|
-
FROM architect a
|
|
513
|
-
WHERE EXISTS (
|
|
514
|
-
SELECT 1 FROM globaldb.terminal_sessions ts
|
|
515
|
-
WHERE (ts.id = a.terminal_id OR ts.role_id = a.id)
|
|
516
|
-
AND ts.type = 'architect'
|
|
517
|
-
);
|
|
518
|
-
`);
|
|
519
|
-
}
|
|
520
|
-
finally {
|
|
521
|
-
db.prepare('DETACH DATABASE globaldb').run();
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
catch (err) {
|
|
525
|
-
// If global.db can't be opened (e.g. doesn't exist yet in a fresh
|
|
526
|
-
// install where Tower hasn't started), the architect table must be
|
|
527
|
-
// empty for the migration to succeed. Verify and proceed; if there
|
|
528
|
-
// are pre-existing architect rows we genuinely can't backfill, drop
|
|
529
|
-
// them — they correspond to a never-started workspace.
|
|
530
|
-
const remaining = db.prepare('SELECT COUNT(*) AS n FROM architect').get();
|
|
531
|
-
if (remaining.n > 0) {
|
|
532
|
-
console.log(`[warn] Migration v11: dropping ${remaining.n} architect row(s) — global.db unavailable for backfill: ${err.message}`);
|
|
533
|
-
}
|
|
534
|
-
// architect_v11 is empty in this path; carry on.
|
|
535
|
-
}
|
|
536
|
-
// Step 2: atomic swap.
|
|
537
|
-
db.exec(`
|
|
538
|
-
DROP TABLE architect;
|
|
539
|
-
ALTER TABLE architect_v11 RENAME TO architect;
|
|
540
|
-
`);
|
|
541
|
-
console.log('[info] Migrated architect table: workspace-scoped rows (Bugfix #826)');
|
|
542
|
-
}
|
|
543
|
-
// Bugfix #826 iter-7: create the workspace_path index here, OUTSIDE the
|
|
544
|
-
// alreadyMigrated guard. The index is NOT in LOCAL_SCHEMA because
|
|
545
|
-
// db.exec(LOCAL_SCHEMA) runs before migrations on every open — and on a
|
|
546
|
-
// pre-v11 install the architect table lacks workspace_path, so CREATE
|
|
547
|
-
// INDEX would throw 'no such column' and abort ensureLocalDatabase before
|
|
548
|
-
// v11 can run. Placing it here ensures the index is created on both
|
|
549
|
-
// upgrade installs (after the migration body) and fresh installs (where
|
|
550
|
-
// LOCAL_SCHEMA already created the v11 table shape and the inner block
|
|
551
|
-
// was skipped). `IF NOT EXISTS` makes the second-open case a no-op.
|
|
552
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_architect_workspace ON architect(workspace_path);');
|
|
553
|
-
db.prepare('INSERT INTO _migrations (version) VALUES (11)').run();
|
|
554
|
-
}
|
|
555
|
-
return db;
|
|
556
|
-
}
|
|
557
109
|
/**
|
|
558
110
|
* Initialize the global database (global.db)
|
|
559
111
|
*/
|
|
@@ -566,7 +118,7 @@ function ensureGlobalDatabase() {
|
|
|
566
118
|
const db = new Database(dbPath);
|
|
567
119
|
configurePragmas(db);
|
|
568
120
|
// Current migration version — bump when adding new migrations
|
|
569
|
-
const GLOBAL_CURRENT_VERSION =
|
|
121
|
+
const GLOBAL_CURRENT_VERSION = 14;
|
|
570
122
|
// Detect fresh vs existing database by checking if content tables exist.
|
|
571
123
|
// On existing databases, GLOBAL_SCHEMA must NOT run because it references column names
|
|
572
124
|
// (workspace_path) that don't exist until migration v9 renames them from project_path.
|
|
@@ -866,6 +418,84 @@ function ensureGlobalDatabase() {
|
|
|
866
418
|
db.prepare('INSERT INTO _migrations (version) VALUES (13)').run();
|
|
867
419
|
console.log('[info] Backfilled architect role_id with \'main\' (Spec 755)');
|
|
868
420
|
}
|
|
421
|
+
// Migration v14: Absorb the retired state.db tables (Issue #1118).
|
|
422
|
+
// Creates architect/builders/utils/annotations in global.db at their final
|
|
423
|
+
// shape. architect/utils/annotations move as-is; builders is RESHAPED with a
|
|
424
|
+
// workspace_path column + composite PK (workspace_path, id) so the same
|
|
425
|
+
// builder id can exist in multiple workspaces. Idempotent via
|
|
426
|
+
// `CREATE TABLE IF NOT EXISTS`. The one-time data migration of legacy
|
|
427
|
+
// state.db files is a separate, marker-gated step run at Tower boot
|
|
428
|
+
// (db/consolidate.ts) — NOT here — so opening global.db never moves data.
|
|
429
|
+
const v14 = db.prepare('SELECT version FROM _migrations WHERE version = 14').get();
|
|
430
|
+
if (!v14) {
|
|
431
|
+
db.exec(`
|
|
432
|
+
CREATE TABLE IF NOT EXISTS architect (
|
|
433
|
+
workspace_path TEXT NOT NULL,
|
|
434
|
+
id TEXT NOT NULL,
|
|
435
|
+
pid INTEGER NOT NULL,
|
|
436
|
+
port INTEGER NOT NULL,
|
|
437
|
+
cmd TEXT NOT NULL,
|
|
438
|
+
started_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
439
|
+
terminal_id TEXT,
|
|
440
|
+
session_id TEXT,
|
|
441
|
+
PRIMARY KEY (workspace_path, id)
|
|
442
|
+
);
|
|
443
|
+
CREATE INDEX IF NOT EXISTS idx_architect_workspace ON architect(workspace_path);
|
|
444
|
+
|
|
445
|
+
CREATE TABLE IF NOT EXISTS builders (
|
|
446
|
+
workspace_path TEXT NOT NULL,
|
|
447
|
+
id TEXT NOT NULL,
|
|
448
|
+
name TEXT NOT NULL,
|
|
449
|
+
port INTEGER NOT NULL DEFAULT 0,
|
|
450
|
+
pid INTEGER NOT NULL DEFAULT 0,
|
|
451
|
+
status TEXT NOT NULL DEFAULT 'spawning'
|
|
452
|
+
CHECK(status IN ('spawning', 'implementing', 'blocked', 'pr', 'complete')),
|
|
453
|
+
phase TEXT NOT NULL DEFAULT '',
|
|
454
|
+
worktree TEXT NOT NULL,
|
|
455
|
+
branch TEXT NOT NULL,
|
|
456
|
+
type TEXT NOT NULL DEFAULT 'spec'
|
|
457
|
+
CHECK(type IN ('spec', 'task', 'protocol', 'shell', 'worktree', 'bugfix', 'pir')),
|
|
458
|
+
task_text TEXT,
|
|
459
|
+
protocol_name TEXT,
|
|
460
|
+
issue_number TEXT,
|
|
461
|
+
terminal_id TEXT,
|
|
462
|
+
spawned_by_architect TEXT,
|
|
463
|
+
started_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
464
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
465
|
+
PRIMARY KEY (workspace_path, id)
|
|
466
|
+
);
|
|
467
|
+
CREATE INDEX IF NOT EXISTS idx_builders_status ON builders(status);
|
|
468
|
+
CREATE INDEX IF NOT EXISTS idx_builders_port ON builders(port);
|
|
469
|
+
CREATE TRIGGER IF NOT EXISTS builders_updated_at
|
|
470
|
+
AFTER UPDATE ON builders
|
|
471
|
+
FOR EACH ROW
|
|
472
|
+
BEGIN
|
|
473
|
+
UPDATE builders SET updated_at = datetime('now')
|
|
474
|
+
WHERE workspace_path = NEW.workspace_path AND id = NEW.id;
|
|
475
|
+
END;
|
|
476
|
+
|
|
477
|
+
CREATE TABLE IF NOT EXISTS utils (
|
|
478
|
+
id TEXT PRIMARY KEY,
|
|
479
|
+
name TEXT NOT NULL,
|
|
480
|
+
port INTEGER NOT NULL DEFAULT 0,
|
|
481
|
+
pid INTEGER NOT NULL DEFAULT 0,
|
|
482
|
+
terminal_id TEXT,
|
|
483
|
+
started_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
484
|
+
);
|
|
485
|
+
|
|
486
|
+
CREATE TABLE IF NOT EXISTS annotations (
|
|
487
|
+
id TEXT PRIMARY KEY,
|
|
488
|
+
file TEXT NOT NULL,
|
|
489
|
+
port INTEGER NOT NULL DEFAULT 0,
|
|
490
|
+
pid INTEGER NOT NULL DEFAULT 0,
|
|
491
|
+
parent_type TEXT NOT NULL CHECK(parent_type IN ('architect', 'builder', 'util')),
|
|
492
|
+
parent_id TEXT,
|
|
493
|
+
started_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
494
|
+
);
|
|
495
|
+
`);
|
|
496
|
+
db.prepare('INSERT INTO _migrations (version) VALUES (14)').run();
|
|
497
|
+
console.log('[info] Absorbed state.db tables into global.db (Issue #1118)');
|
|
498
|
+
}
|
|
869
499
|
return db;
|
|
870
500
|
}
|
|
871
501
|
// Re-export types and utilities
|