update
This commit is contained in:
1 parent
2ab001b18a
commit
810e2d5967
28 files changed
+1015
-85
No files matched your search
@@ -0,0 +1,130 @@
|
||||
import type { DatabaseSync } from "node:sqlite";
|
||||
import { nowIso, tableExists } from "./types";
|
||||
|
||||
export const FILESYSTEM_TASK_WORKSPACES_SCHEMA_VERSION = 60;
|
||||
export const FILESYSTEM_TASK_WORKSPACES_SCHEMA_NAME = "filesystem_task_workspaces";
|
||||
|
||||
const ACTIVE_TASK_STATUSES = "'backlog', 'todo', 'in_progress', 'blocked'";
|
||||
|
||||
export function migrateFilesystemTaskWorkspacesV60(db: DatabaseSync): void {
|
||||
backfillProjectWorkspaces(db);
|
||||
backfillAssigneeWorkspaces(db);
|
||||
backfillSingleCompanyWorkspaces(db);
|
||||
db
|
||||
.prepare("insert or replace into schema_migrations (version, name, applied_at) values (?, ?, ?)")
|
||||
.run(FILESYSTEM_TASK_WORKSPACES_SCHEMA_VERSION, FILESYSTEM_TASK_WORKSPACES_SCHEMA_NAME, nowIso());
|
||||
assertFilesystemTaskWorkspacesV60(db);
|
||||
}
|
||||
|
||||
export function assertFilesystemTaskWorkspacesV60(db: DatabaseSync): void {
|
||||
if (!tableExists(db, "tasks") || !tableExists(db, "workspaces")) {
|
||||
throw new Error("Schema v60 drift: tasks/workspaces tables are missing.");
|
||||
}
|
||||
const unresolved = db
|
||||
.prepare(
|
||||
`select count(*) as count
|
||||
from tasks t
|
||||
where t.requires_filesystem = 1
|
||||
and t.workspace_id is null
|
||||
and t.status in (${ACTIVE_TASK_STATUSES})
|
||||
and (
|
||||
select count(*)
|
||||
from workspaces w
|
||||
where w.company_id = t.company_id
|
||||
) = 1`,
|
||||
)
|
||||
.get() as { count: number } | undefined;
|
||||
if ((unresolved?.count ?? 0) > 0) {
|
||||
throw new Error("Schema v60 drift: single-workspace companies still have unresolved filesystem tasks.");
|
||||
}
|
||||
}
|
||||
|
||||
function backfillProjectWorkspaces(db: DatabaseSync): void {
|
||||
if (!hasRequiredTables(db)) return;
|
||||
db
|
||||
.prepare(
|
||||
`update tasks
|
||||
set workspace_id = (
|
||||
select w.id
|
||||
from workspaces w
|
||||
where w.company_id = tasks.company_id
|
||||
and w.project_id = tasks.project_id
|
||||
order by w.is_primary desc, w.created_at asc
|
||||
limit 1
|
||||
),
|
||||
updated_at = ?
|
||||
where requires_filesystem = 1
|
||||
and workspace_id is null
|
||||
and status in (${ACTIVE_TASK_STATUSES})
|
||||
and project_id is not null
|
||||
and exists (
|
||||
select 1
|
||||
from workspaces w
|
||||
where w.company_id = tasks.company_id
|
||||
and w.project_id = tasks.project_id
|
||||
)`,
|
||||
)
|
||||
.run(nowIso());
|
||||
}
|
||||
|
||||
function backfillAssigneeWorkspaces(db: DatabaseSync): void {
|
||||
if (!hasRequiredTables(db) || !tableExists(db, "agents")) return;
|
||||
db
|
||||
.prepare(
|
||||
`update tasks
|
||||
set workspace_id = (
|
||||
select a.workspace_id
|
||||
from agents a
|
||||
join workspaces w
|
||||
on w.id = a.workspace_id
|
||||
and w.company_id = a.company_id
|
||||
where a.id = tasks.assignee_agent_id
|
||||
and a.company_id = tasks.company_id
|
||||
limit 1
|
||||
),
|
||||
updated_at = ?
|
||||
where requires_filesystem = 1
|
||||
and workspace_id is null
|
||||
and status in (${ACTIVE_TASK_STATUSES})
|
||||
and assignee_agent_id is not null
|
||||
and exists (
|
||||
select 1
|
||||
from agents a
|
||||
join workspaces w
|
||||
on w.id = a.workspace_id
|
||||
and w.company_id = a.company_id
|
||||
where a.id = tasks.assignee_agent_id
|
||||
and a.company_id = tasks.company_id
|
||||
)`,
|
||||
)
|
||||
.run(nowIso());
|
||||
}
|
||||
|
||||
function backfillSingleCompanyWorkspaces(db: DatabaseSync): void {
|
||||
if (!hasRequiredTables(db)) return;
|
||||
db
|
||||
.prepare(
|
||||
`update tasks
|
||||
set workspace_id = (
|
||||
select w.id
|
||||
from workspaces w
|
||||
where w.company_id = tasks.company_id
|
||||
order by w.is_primary desc, w.created_at asc
|
||||
limit 1
|
||||
),
|
||||
updated_at = ?
|
||||
where requires_filesystem = 1
|
||||
and workspace_id is null
|
||||
and status in (${ACTIVE_TASK_STATUSES})
|
||||
and (
|
||||
select count(*)
|
||||
from workspaces w
|
||||
where w.company_id = tasks.company_id
|
||||
) = 1`,
|
||||
)
|
||||
.run(nowIso());
|
||||
}
|
||||
|
||||
function hasRequiredTables(db: DatabaseSync): boolean {
|
||||
return tableExists(db, "tasks") && tableExists(db, "workspaces");
|
||||
}
|
||||
@@ -92,12 +92,27 @@ export function buildModelCapabilityMethods(
|
||||
*/
|
||||
function seedModelCapabilities(rows: Array<Omit<ModelCapability, "updatedAt">>): number {
|
||||
return transaction(() => {
|
||||
const existing = readAll<{ cnt: number }>(
|
||||
"SELECT COUNT(*) AS cnt FROM model_capabilities",
|
||||
)[0]?.cnt ?? 0;
|
||||
if (existing > 0) return 0;
|
||||
for (const row of rows) upsertModelCapability(row);
|
||||
return rows.length;
|
||||
let inserted = 0;
|
||||
const ts = nowIso();
|
||||
const stmt = getDb().prepare(
|
||||
`INSERT OR IGNORE INTO model_capabilities (
|
||||
provider, model_id, reasoning, coding, writing, tier, cost_per_mtok_out, updated_at
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
);
|
||||
for (const row of rows) {
|
||||
const result = stmt.run(
|
||||
row.provider,
|
||||
row.modelId,
|
||||
row.reasoning,
|
||||
row.coding,
|
||||
row.writing,
|
||||
row.tier,
|
||||
row.costPerMtokOut,
|
||||
ts,
|
||||
);
|
||||
inserted += Number(result.changes ?? 0);
|
||||
}
|
||||
return inserted;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -24,12 +24,17 @@ import {
|
||||
assertSocialCompanyScopeV59,
|
||||
migrateSocialCompanyScopeV59,
|
||||
} from "./migrations/v59-social-company-scope";
|
||||
import {
|
||||
FILESYSTEM_TASK_WORKSPACES_SCHEMA_VERSION,
|
||||
assertFilesystemTaskWorkspacesV60,
|
||||
migrateFilesystemTaskWorkspacesV60,
|
||||
} from "./migrations/v60-filesystem-task-workspaces";
|
||||
import {
|
||||
type ReadAll,
|
||||
type Transaction,
|
||||
} from "./migrations/types";
|
||||
|
||||
const LATEST_SCHEMA_VERSION = SOCIAL_COMPANY_SCOPE_SCHEMA_VERSION;
|
||||
const LATEST_SCHEMA_VERSION = FILESYSTEM_TASK_WORKSPACES_SCHEMA_VERSION;
|
||||
|
||||
export function initializeDatabase(
|
||||
db: DatabaseSync,
|
||||
@@ -50,6 +55,18 @@ export function initializeDatabase(
|
||||
assertTaskLeasesV57(db);
|
||||
assertApprovalPoliciesV58(db);
|
||||
assertSocialCompanyScopeV59(db);
|
||||
assertFilesystemTaskWorkspacesV60(db);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentVersion === SOCIAL_COMPANY_SCOPE_SCHEMA_VERSION) {
|
||||
tx(() => {
|
||||
seedSettings(db);
|
||||
assertTaskLeasesV57(db);
|
||||
assertApprovalPoliciesV58(db);
|
||||
assertSocialCompanyScopeV59(db);
|
||||
migrateFilesystemTaskWorkspacesV60(db);
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -60,6 +77,7 @@ export function initializeDatabase(
|
||||
assertTaskLeasesV57(db);
|
||||
assertApprovalPoliciesV58(db);
|
||||
migrateSocialCompanyScopeV59(db);
|
||||
migrateFilesystemTaskWorkspacesV60(db);
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -70,6 +88,7 @@ export function initializeDatabase(
|
||||
assertTaskLeasesV57(db);
|
||||
migrateApprovalPoliciesV58(db);
|
||||
migrateSocialCompanyScopeV59(db);
|
||||
migrateFilesystemTaskWorkspacesV60(db);
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -83,6 +102,7 @@ export function initializeDatabase(
|
||||
migrateTaskLeasesV57(db);
|
||||
migrateApprovalPoliciesV58(db);
|
||||
migrateSocialCompanyScopeV59(db);
|
||||
migrateFilesystemTaskWorkspacesV60(db);
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -97,6 +117,7 @@ export function initializeDatabase(
|
||||
migrateTaskLeasesV57(db);
|
||||
migrateApprovalPoliciesV58(db);
|
||||
migrateSocialCompanyScopeV59(db);
|
||||
migrateFilesystemTaskWorkspacesV60(db);
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -109,6 +130,7 @@ export function initializeDatabase(
|
||||
migrateTaskLeasesV57(db);
|
||||
migrateApprovalPoliciesV58(db);
|
||||
migrateSocialCompanyScopeV59(db);
|
||||
migrateFilesystemTaskWorkspacesV60(db);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user