refactor(db): add findAgent/findConnector; wrap linkManyTasksToApproval in tx; collapse saveAgent IIFEs (P1-28, P1-29)
This commit is contained in:
1 parent
a05885c0ff
commit
821855931d
5 files changed
+38
-30
No files matched your search
@@ -197,12 +197,14 @@ export class AppDatabaseBase {
|
||||
saveConnector(input: { id: ConnectorId; command: string; model: string | null; envBindingText: string; notes: string }) { this.connectorsCrud.saveConnector(input); }
|
||||
updateConnectorHealth(input: { id: ConnectorId; status: string; authState: string; version: string | null; lastError: string | null }) { this.connectorsCrud.updateConnectorHealth(input); }
|
||||
getConnector(id: ConnectorId) { return this.connectorsCrud.getConnector(id); }
|
||||
findConnector(id: ConnectorId) { return this.connectorsCrud.findConnector(id); }
|
||||
|
||||
// ─── Agents ────────────────────────────────────────────────────────────────
|
||||
|
||||
saveAgent(input: { id?: string | null; companyId: string; name: string; role: string; title: string; department?: string | null; status: AgentStatus; reportsTo?: string | null; connectorId: ConnectorId; workspaceId?: string | null; model?: string | null; metadataJson?: string; capabilities: string; budgetMonthlyUsd: number }) { return this.agents.saveAgent(input); }
|
||||
deleteAgent(id: string, companyId: string) { return this.agents.deleteAgent(id, companyId); }
|
||||
getAgent(id: string) { return this.entityCrud.getAgent(id); }
|
||||
findAgent(id: string) { return this.entityCrud.findAgent(id); }
|
||||
setHeartbeat(agentId: string, enabled: boolean, intervalSec: number) { return this.agents.setHeartbeat(agentId, enabled, intervalSec); }
|
||||
markHeartbeatAt(agentId: string) { return this.agents.markHeartbeatAt(agentId); }
|
||||
resetMonthlyBudgets(companyId: string) { return this.agents.resetMonthlyBudgets(companyId); }
|
||||
|
||||
@@ -335,12 +335,16 @@ export function buildApprovalMethods(
|
||||
},
|
||||
|
||||
linkManyTasksToApproval(approvalId: string, taskIds: string[], companyId: string, linkedByAgentId?: string | null): void {
|
||||
if (taskIds.length === 0) return;
|
||||
const ts = nowIso();
|
||||
for (const taskId of taskIds) {
|
||||
getDb().prepare(
|
||||
transaction(() => {
|
||||
const stmt = getDb().prepare(
|
||||
"INSERT OR IGNORE INTO task_approval_links (task_id, approval_id, company_id, linked_by_agent_id, created_at) VALUES (?, ?, ?, ?, ?)",
|
||||
).run(taskId, approvalId, companyId, linkedByAgentId ?? null, ts);
|
||||
}
|
||||
);
|
||||
for (const taskId of taskIds) {
|
||||
stmt.run(taskId, approvalId, companyId, linkedByAgentId ?? null, ts);
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -79,7 +79,7 @@ export function buildConnectorMethods(
|
||||
.run(input.status, input.authState, input.version, nowIso(), input.lastError, nowIso(), input.id);
|
||||
},
|
||||
|
||||
getConnector(id: ConnectorId): ConnectorRecord {
|
||||
findConnector(id: ConnectorId): ConnectorRecord | null {
|
||||
const row = getDb()
|
||||
.prepare(
|
||||
"select id, label, description, status, command, version, auth_state, last_checked_at, last_error, model, env_binding_text, notes from connectors where id = ?",
|
||||
@@ -100,8 +100,13 @@ export function buildConnectorMethods(
|
||||
notes: string;
|
||||
}
|
||||
| undefined;
|
||||
if (!row) throw new Error(`Connector not found: ${id}`);
|
||||
const definition = getConnectorDefinition(row.id as ConnectorId);
|
||||
if (!row) return null;
|
||||
let definition;
|
||||
try {
|
||||
definition = getConnectorDefinition(row.id as ConnectorId);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
id: row.id as ConnectorId,
|
||||
label: row.label,
|
||||
@@ -120,6 +125,12 @@ export function buildConnectorMethods(
|
||||
};
|
||||
},
|
||||
|
||||
getConnector(id: ConnectorId): ConnectorRecord {
|
||||
const result = this.findConnector(id);
|
||||
if (!result) throw new Error(`Connector not found: ${id}`);
|
||||
return result;
|
||||
},
|
||||
|
||||
seedConnectors() {
|
||||
getDb().prepare("delete from connectors where id not in ('codex_local', 'claude_local', 'gemini_local') and id not like 'claude_compat%'").run();
|
||||
const currentRows = readAll<Partial<ConnectorRecord>>(
|
||||
|
||||
@@ -71,6 +71,17 @@ export function buildEntityCrudMethods(
|
||||
return row;
|
||||
},
|
||||
|
||||
findAgent(id: string): AgentRecord | null {
|
||||
const row = getDb()
|
||||
.prepare(
|
||||
"select id, company_id as companyId, name, role, title, department, status, reports_to as reportsTo, connector_id as connectorId, workspace_id as workspaceId, model, capabilities, budget_monthly_usd as budgetMonthlyUsd, spent_monthly_usd as spentMonthlyUsd, metadata_json as metadataJson, heartbeat_enabled as heartbeatEnabled, heartbeat_interval_sec as heartbeatIntervalSec, last_heartbeat_at as lastHeartbeatAt, created_at as createdAt, updated_at as updatedAt from agents where id = ?",
|
||||
)
|
||||
.get(id) as AgentRecord | undefined;
|
||||
if (!row) return null;
|
||||
row.heartbeatEnabled = Boolean(row.heartbeatEnabled);
|
||||
return row;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns all goals for a company. Used by GET /api/companies/:id/goals.
|
||||
*/
|
||||
|
||||
@@ -61,15 +61,7 @@ export function registerCoreAgentGraphHandlers({
|
||||
"Create new agents through the hiring workflow so approval, onboarding, and org state stay synchronized.",
|
||||
);
|
||||
}
|
||||
const existingAgent = (() => {
|
||||
try {
|
||||
const agentId = parsed.id;
|
||||
if (!agentId) return null;
|
||||
return db.getAgent(agentId);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
})();
|
||||
const existingAgent = parsed.id ? db.findAgent(parsed.id) : null;
|
||||
if (!existingAgent || existingAgent.companyId !== parsed.companyId) {
|
||||
return fail("AGENT_NOT_FOUND", "Agent not found in the current company.");
|
||||
}
|
||||
@@ -92,13 +84,7 @@ export function registerCoreAgentGraphHandlers({
|
||||
if (invalidReference) {
|
||||
return fail("INVALID_COMPANY_REFERENCE", `The selected ${invalidReference.label} does not belong to the current company.`);
|
||||
}
|
||||
const connectorRecord = (() => {
|
||||
try {
|
||||
return db.getConnector(parsed.connectorId);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
})();
|
||||
const connectorRecord = db.findConnector(parsed.connectorId);
|
||||
if (!connectorRecord) {
|
||||
return fail("CONNECTOR_NOT_FOUND", "The selected connector does not exist.");
|
||||
}
|
||||
@@ -162,13 +148,7 @@ export function registerCoreAgentGraphHandlers({
|
||||
if (invalidReference) {
|
||||
return fail("INVALID_COMPANY_REFERENCE", `The selected ${invalidReference.label} does not belong to the current company.`);
|
||||
}
|
||||
const connectorRecord = (() => {
|
||||
try {
|
||||
return db.getConnector(parsed.connectorId);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
})();
|
||||
const connectorRecord = db.findConnector(parsed.connectorId);
|
||||
if (!connectorRecord) {
|
||||
return fail("CONNECTOR_NOT_FOUND", "The selected connector does not exist.");
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user