@vibedeckx/linux-x64 0.3.8 → 0.3.10
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/dist/bin.js +130 -7
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -185980,10 +185980,29 @@ var createCoreRepos = (kdb, h) => ({
|
|
|
185980
185980
|
const row = await readQuery.executeTakeFirst();
|
|
185981
185981
|
return row ? mapProject(row) : void 0;
|
|
185982
185982
|
},
|
|
185983
|
+
/**
|
|
185984
|
+
* Deleting a project cascades down two independent paths: to its sessions,
|
|
185985
|
+
* and to `workspaces` → `workspace_checkouts`. `remote_session_mappings`
|
|
185986
|
+
* sits on neither — it has no key to `projects` — so once a mapping's
|
|
185987
|
+
* checkout is a real foreign key, leaving those rows behind would strand
|
|
185988
|
+
* them against a checkout the same statement just deleted.
|
|
185989
|
+
*
|
|
185990
|
+
* The dependents are therefore removed explicitly, in order, inside one
|
|
185991
|
+
* transaction. The scope check happens first so an unauthorized caller
|
|
185992
|
+
* cannot delete another tenant's mappings on the way to a no-op.
|
|
185993
|
+
*/
|
|
185983
185994
|
delete: async (id, userId) => {
|
|
185984
|
-
|
|
185985
|
-
|
|
185986
|
-
|
|
185995
|
+
await kdb.transaction().execute(async (trx) => {
|
|
185996
|
+
let scope = trx.selectFrom("projects").select("id").where("id", "=", id);
|
|
185997
|
+
if (userId) scope = scope.where("user_id", "=", userId);
|
|
185998
|
+
if (!await scope.executeTakeFirst()) return;
|
|
185999
|
+
const mappings = await trx.selectFrom("remote_session_mappings").select(["remote_server_id", "remote_session_id"]).where("project_id", "=", id).execute();
|
|
186000
|
+
for (const mapping of mappings) {
|
|
186001
|
+
await trx.deleteFrom("notification_sync_cursors").where("remote_server_id", "=", mapping.remote_server_id).where("remote_session_id", "=", mapping.remote_session_id).execute();
|
|
186002
|
+
}
|
|
186003
|
+
await trx.deleteFrom("remote_session_mappings").where("project_id", "=", id).execute();
|
|
186004
|
+
await trx.deleteFrom("projects").where("id", "=", id).execute();
|
|
186005
|
+
});
|
|
185987
186006
|
},
|
|
185988
186007
|
// Deliberately unscoped: the notification importer runs without a request
|
|
185989
186008
|
// context and must DERIVE ownership from the mapped local project rather
|
|
@@ -203458,6 +203477,100 @@ var createWorkspaceRegistryRepo = (kdb, h) => ({
|
|
|
203458
203477
|
});
|
|
203459
203478
|
|
|
203460
203479
|
// src/storage/sqlite.ts
|
|
203480
|
+
var countDanglingCheckoutBindings = (db) => {
|
|
203481
|
+
const scalar = (sql2) => Number(db.prepare(sql2).get().count);
|
|
203482
|
+
return {
|
|
203483
|
+
sessions: scalar(`SELECT count(*) AS count FROM agent_sessions s
|
|
203484
|
+
LEFT JOIN workspace_checkouts c ON c.id = s.workspace_checkout_id
|
|
203485
|
+
WHERE s.workspace_checkout_id IS NOT NULL AND c.id IS NULL`),
|
|
203486
|
+
mappings: scalar(`SELECT count(*) AS count FROM remote_session_mappings m
|
|
203487
|
+
LEFT JOIN workspace_checkouts c ON c.id = m.workspace_checkout_id
|
|
203488
|
+
WHERE m.workspace_checkout_id IS NOT NULL AND c.id IS NULL`)
|
|
203489
|
+
};
|
|
203490
|
+
};
|
|
203491
|
+
var tightenWorkspaceCheckoutForeignKeys = (db) => {
|
|
203492
|
+
const ddl = (table) => db.prepare(
|
|
203493
|
+
"SELECT sql FROM sqlite_master WHERE type = 'table' AND name = ?"
|
|
203494
|
+
).get(table)?.sql ?? "";
|
|
203495
|
+
const bound = (table) => /REFERENCES\s+workspace_checkouts/i.test(ddl(table));
|
|
203496
|
+
if (bound("agent_sessions") && bound("remote_session_mappings")) return;
|
|
203497
|
+
const indexDdl = (table) => db.prepare(
|
|
203498
|
+
"SELECT sql FROM sqlite_master WHERE type = 'index' AND tbl_name = ? AND sql IS NOT NULL"
|
|
203499
|
+
).all(table).map((row) => row.sql);
|
|
203500
|
+
const dangling = countDanglingCheckoutBindings(db);
|
|
203501
|
+
if (dangling.sessions > 0 || dangling.mappings > 0) {
|
|
203502
|
+
console.warn(
|
|
203503
|
+
`[Storage] Refusing to add the workspace_checkout foreign key: ${dangling.sessions} session(s) and ${dangling.mappings} remote mapping(s) reference a checkout that no longer exists. Resolve or clear those bindings, then restart to complete the migration.`
|
|
203504
|
+
);
|
|
203505
|
+
return;
|
|
203506
|
+
}
|
|
203507
|
+
const sessionIndexes = indexDdl("agent_sessions");
|
|
203508
|
+
const mappingIndexes = indexDdl("remote_session_mappings");
|
|
203509
|
+
db.transaction(() => {
|
|
203510
|
+
if (!bound("agent_sessions")) {
|
|
203511
|
+
db.exec(`
|
|
203512
|
+
CREATE TABLE agent_sessions_fk_new (
|
|
203513
|
+
id TEXT PRIMARY KEY,
|
|
203514
|
+
project_id TEXT NOT NULL,
|
|
203515
|
+
branch TEXT NOT NULL DEFAULT '',
|
|
203516
|
+
workspace_checkout_id TEXT DEFAULT NULL,
|
|
203517
|
+
status TEXT NOT NULL DEFAULT 'running',
|
|
203518
|
+
permission_mode TEXT DEFAULT 'edit',
|
|
203519
|
+
agent_type TEXT DEFAULT 'claude-code',
|
|
203520
|
+
title TEXT DEFAULT NULL,
|
|
203521
|
+
model TEXT DEFAULT NULL,
|
|
203522
|
+
created_at TEXT DEFAULT (strftime('%Y-%m-%d %H:%M:%f', 'now')),
|
|
203523
|
+
updated_at TEXT DEFAULT (strftime('%Y-%m-%d %H:%M:%f', 'now')),
|
|
203524
|
+
activity_at INTEGER DEFAULT (cast((julianday('now') - 2440587.5) * 86400000 as integer)),
|
|
203525
|
+
last_user_message_at INTEGER DEFAULT NULL,
|
|
203526
|
+
last_completed_at INTEGER DEFAULT NULL,
|
|
203527
|
+
favorited_at INTEGER DEFAULT NULL,
|
|
203528
|
+
FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE,
|
|
203529
|
+
FOREIGN KEY (workspace_checkout_id) REFERENCES workspace_checkouts(id)
|
|
203530
|
+
DEFERRABLE INITIALLY DEFERRED
|
|
203531
|
+
);
|
|
203532
|
+
INSERT INTO agent_sessions_fk_new
|
|
203533
|
+
(id, project_id, branch, workspace_checkout_id, status, permission_mode, agent_type,
|
|
203534
|
+
title, model, created_at, updated_at, activity_at, last_user_message_at,
|
|
203535
|
+
last_completed_at, favorited_at)
|
|
203536
|
+
SELECT id, project_id, branch, workspace_checkout_id, status, permission_mode, agent_type,
|
|
203537
|
+
title, model, created_at, updated_at, activity_at, last_user_message_at,
|
|
203538
|
+
last_completed_at, favorited_at
|
|
203539
|
+
FROM agent_sessions;
|
|
203540
|
+
DROP TABLE agent_sessions;
|
|
203541
|
+
ALTER TABLE agent_sessions_fk_new RENAME TO agent_sessions;
|
|
203542
|
+
`);
|
|
203543
|
+
for (const sql2 of sessionIndexes) db.exec(sql2);
|
|
203544
|
+
}
|
|
203545
|
+
if (!bound("remote_session_mappings")) {
|
|
203546
|
+
db.exec(`
|
|
203547
|
+
CREATE TABLE remote_session_mappings_fk_new (
|
|
203548
|
+
local_session_id TEXT PRIMARY KEY,
|
|
203549
|
+
project_id TEXT NOT NULL,
|
|
203550
|
+
remote_server_id TEXT NOT NULL,
|
|
203551
|
+
remote_session_id TEXT NOT NULL,
|
|
203552
|
+
branch TEXT,
|
|
203553
|
+
workspace_checkout_id TEXT DEFAULT NULL,
|
|
203554
|
+
title_resolved INTEGER NOT NULL DEFAULT 0,
|
|
203555
|
+
notification_sync_start TEXT NOT NULL DEFAULT 'from_now',
|
|
203556
|
+
notification_watch_until INTEGER,
|
|
203557
|
+
FOREIGN KEY (workspace_checkout_id) REFERENCES workspace_checkouts(id)
|
|
203558
|
+
DEFERRABLE INITIALLY DEFERRED
|
|
203559
|
+
);
|
|
203560
|
+
INSERT INTO remote_session_mappings_fk_new
|
|
203561
|
+
(local_session_id, project_id, remote_server_id, remote_session_id, branch,
|
|
203562
|
+
workspace_checkout_id, title_resolved, notification_sync_start, notification_watch_until)
|
|
203563
|
+
SELECT local_session_id, project_id, remote_server_id, remote_session_id, branch,
|
|
203564
|
+
workspace_checkout_id, title_resolved, notification_sync_start, notification_watch_until
|
|
203565
|
+
FROM remote_session_mappings;
|
|
203566
|
+
DROP TABLE remote_session_mappings;
|
|
203567
|
+
ALTER TABLE remote_session_mappings_fk_new RENAME TO remote_session_mappings;
|
|
203568
|
+
`);
|
|
203569
|
+
for (const sql2 of mappingIndexes) db.exec(sql2);
|
|
203570
|
+
}
|
|
203571
|
+
})();
|
|
203572
|
+
console.log("[Storage] workspace_checkout foreign keys are now enforced.");
|
|
203573
|
+
};
|
|
203461
203574
|
var createDatabase = (dbPath) => {
|
|
203462
203575
|
const db = new Database(dbPath);
|
|
203463
203576
|
db.pragma("journal_mode = WAL");
|
|
@@ -204954,6 +205067,7 @@ var createDatabase = (dbPath) => {
|
|
|
204954
205067
|
}
|
|
204955
205068
|
db.exec(`CREATE INDEX IF NOT EXISTS idx_remote_session_mappings_workspace_checkout
|
|
204956
205069
|
ON remote_session_mappings(workspace_checkout_id)`);
|
|
205070
|
+
tightenWorkspaceCheckoutForeignKeys(db);
|
|
204957
205071
|
const sessionSearchCacheInfo = db.prepare("PRAGMA table_info(session_search_cache)").all();
|
|
204958
205072
|
if (!sessionSearchCacheInfo.some((col) => col.name === "written_at")) {
|
|
204959
205073
|
db.exec("ALTER TABLE session_search_cache ADD COLUMN written_at INTEGER");
|
|
@@ -207242,6 +207356,13 @@ function parseGitWorktreeList(projectPath) {
|
|
|
207242
207356
|
worktreeListCache.set(projectPath, { entries, expiresAt: now3 + WORKTREE_LIST_TTL_MS });
|
|
207243
207357
|
return entries;
|
|
207244
207358
|
}
|
|
207359
|
+
function readWorktreeListTolerant(projectPath) {
|
|
207360
|
+
try {
|
|
207361
|
+
return parseGitWorktreeList(projectPath);
|
|
207362
|
+
} catch {
|
|
207363
|
+
return [{ path: projectPath, branch: null }];
|
|
207364
|
+
}
|
|
207365
|
+
}
|
|
207245
207366
|
function pruneWorktrees(projectPath) {
|
|
207246
207367
|
try {
|
|
207247
207368
|
execSync("git worktree prune", {
|
|
@@ -207249,6 +207370,7 @@ function pruneWorktrees(projectPath) {
|
|
|
207249
207370
|
encoding: "utf-8",
|
|
207250
207371
|
stdio: ["pipe", "pipe", "pipe"]
|
|
207251
207372
|
});
|
|
207373
|
+
} catch {
|
|
207252
207374
|
} finally {
|
|
207253
207375
|
worktreeListCache.delete(projectPath);
|
|
207254
207376
|
}
|
|
@@ -207288,7 +207410,8 @@ function reconcileWorktreeBranches(projectPath, entries, sessionBranches = [], r
|
|
|
207288
207410
|
}
|
|
207289
207411
|
const rootEntry = entries[0];
|
|
207290
207412
|
const rootAnchor = rootEntry ? registryByPath.get(path6.resolve(rootEntry.path)) : void 0;
|
|
207291
|
-
const
|
|
207413
|
+
const rootDrifted = Boolean(rootAnchor) && rootEntry?.branch != null && rootEntry.branch !== rootAnchor.expectedBranch;
|
|
207414
|
+
const worktrees = [rootDrifted ? { branch: null, currentBranch: rootEntry?.branch ?? null } : { branch: null }];
|
|
207292
207415
|
for (let i = 1; i < entries.length; i++) {
|
|
207293
207416
|
const entry = entries[i];
|
|
207294
207417
|
const anchor = registryByPath.get(path6.resolve(entry.path));
|
|
@@ -207303,7 +207426,7 @@ function reconcileWorktreeBranches(projectPath, entries, sessionBranches = [], r
|
|
|
207303
207426
|
return worktrees;
|
|
207304
207427
|
}
|
|
207305
207428
|
async function getRegisteredWorktreeBranches(storage, projectId, projectPath) {
|
|
207306
|
-
const entries =
|
|
207429
|
+
const entries = readWorktreeListTolerant(projectPath);
|
|
207307
207430
|
const sessions = await storage.agentSessions.getProjectedByProjectId(projectId, "runtime");
|
|
207308
207431
|
const sessionBranches = sessions.map((session) => session.branch);
|
|
207309
207432
|
const sessionBranchByPath = /* @__PURE__ */ new Map();
|
|
@@ -207337,14 +207460,14 @@ async function getRegisteredWorktreeBranches(storage, projectId, projectPath) {
|
|
|
207337
207460
|
}
|
|
207338
207461
|
continue;
|
|
207339
207462
|
}
|
|
207340
|
-
if (registeredPaths.has(resolvedPath) || entry.branch === null) continue;
|
|
207463
|
+
if (registeredPaths.has(resolvedPath) || entry.branch === null && index > 0) continue;
|
|
207341
207464
|
const stableBranch = index === 0 ? "" : sessionBranchByPath.get(resolvedPath) ?? entry.branch;
|
|
207342
207465
|
await storage.workspaceRegistry.registerReadyCheckout({
|
|
207343
207466
|
projectId,
|
|
207344
207467
|
branch: stableBranch,
|
|
207345
207468
|
targetId: "local",
|
|
207346
207469
|
worktreePath: entry.path,
|
|
207347
|
-
expectedBranch: index === 0 ? entry.branch : stableBranch
|
|
207470
|
+
expectedBranch: index === 0 ? entry.branch ?? "" : stableBranch
|
|
207348
207471
|
});
|
|
207349
207472
|
registeredPaths.add(resolvedPath);
|
|
207350
207473
|
}
|