Remove final AppDatabase pass-through methods with ESLint guard (C1 part 3/3)
Migrate all remaining pass-through call sites (social, skills, budget,
entityCrud, documents, knowledge, automation, wakeup, backup, threads,
settings, snapshot, connectors, workspaces, activity) to their owning
domain modules. `AppDatabase` now carries only three methods:
- createHireRequest (multi-module composite: agents + approvalsMod)
- rollbackConfigRevision (multi-module composite: documents + entityCrud)
- queryAll (raw-SQL escape hatch, @internal)
The vault/env-binding infrastructure previously passed argument-by-
argument into `entityCrud.saveSecret`/`resolveSecretEnv` now binds at
module construction, letting callers invoke `db.entityCrud.saveSecret({...})`
without carrying vault plumbing.
Structural types that narrowed AppDatabase to a bag of flat methods
(`ConnectorModelPolicyDeps` callers, `CapabilityMatchDb`, test mocks in
budget-enforcement / budget-incidents / task-quality-gates /
failure-escalation / task-quality-gates-sweep) are reshaped to the new
namespace. `connectorPolicyDepsFromDb` replaces the old pattern of
handing the whole AppDatabase to `validateConnectorModelSelection`.
A new ESLint rule in eslint.config.mjs blocks new top-level methods on
AppDatabase so the pass-through layer cannot silently grow back.
`AppDatabase.ts` dropped from 193 lines to 58; `AppDatabaseBase` lost
the 270-line trailing pass-through block.
This commit is contained in:
1 parent
a69fbb053b
commit
118e3d8795
120 files changed
+838
-933
No files matched your search
@@ -81,7 +81,7 @@ export function executeAutomationAction(
|
||||
wakeAgentIfPossible(assignedId, ctx.companyId, "assignment");
|
||||
}
|
||||
} else if (ctx.agentId) {
|
||||
const snapshot = db.listSnapshot();
|
||||
const snapshot = db.snap.listSnapshot();
|
||||
const unassigned = snapshot.tasks
|
||||
.filter((task) => task.companyId === ctx.companyId && !task.assigneeAgentId && ["backlog", "todo"].includes(task.status))
|
||||
.sort((a, b) => {
|
||||
@@ -310,7 +310,7 @@ export function executeAutomationAction(
|
||||
// Default to +60min only when the rule specifies no time at all.
|
||||
const offsetMinutes = cfg.scheduleOffsetMinutes ?? 60;
|
||||
const scheduledAt = cfg.scheduledAt ?? new Date(Date.now() + offsetMinutes * 60_000).toISOString();
|
||||
db.saveMeeting({
|
||||
db.knowledgeMod.saveMeeting({
|
||||
companyId: ctx.companyId,
|
||||
type: meetingType,
|
||||
title,
|
||||
@@ -324,7 +324,7 @@ export function executeAutomationAction(
|
||||
case "create_document": {
|
||||
const documentType = (config.documentType as string) ?? "status_report";
|
||||
const title = (config.title as string) ?? "Auto-generated document";
|
||||
db.saveDocument({
|
||||
db.documentsMod.saveDocument({
|
||||
companyId: ctx.companyId,
|
||||
type: documentType,
|
||||
title,
|
||||
@@ -335,7 +335,7 @@ export function executeAutomationAction(
|
||||
break;
|
||||
}
|
||||
case "auto_approve": {
|
||||
const snapshot = db.listSnapshot();
|
||||
const snapshot = db.snap.listSnapshot();
|
||||
const pendingApprovals = snapshot.approvals.filter(
|
||||
(approval) => approval.companyId === ctx.companyId && approval.state === "pending",
|
||||
);
|
||||
|
||||
@@ -39,7 +39,7 @@ function recordReviewFeedbackKnowledge(
|
||||
"Use this review guidance to improve future deliverables for similar work.",
|
||||
].join("\n");
|
||||
|
||||
db.saveKnowledgeEntry({
|
||||
db.knowledgeMod.saveKnowledgeEntry({
|
||||
companyId: approval.companyId,
|
||||
category: "lesson_learned",
|
||||
topic,
|
||||
@@ -84,7 +84,7 @@ export function handleApprovalResolved(
|
||||
const { db, logger, publishDomainChanged, notify, wakeAgentIfPossible, dispatchBrowserAction } = deps;
|
||||
const { dispatchAutomation, handleTaskStatusChange, runWorkflowPipeline, trackTimer } = callbacks;
|
||||
|
||||
const snapshot = db.listSnapshot();
|
||||
const snapshot = db.snap.listSnapshot();
|
||||
const approval = snapshot.approvals.find((entry) => entry.id === approvalId);
|
||||
if (!approval) return;
|
||||
|
||||
@@ -111,7 +111,7 @@ export function handleApprovalResolved(
|
||||
department: agent.department,
|
||||
});
|
||||
if (assignedSkillIds.length > 0) {
|
||||
db.addActivity({
|
||||
db.activityMod.addActivity({
|
||||
companyId,
|
||||
actor: "system",
|
||||
action: "agent.skills_defaulted",
|
||||
@@ -121,7 +121,7 @@ export function handleApprovalResolved(
|
||||
});
|
||||
}
|
||||
|
||||
db.addActivity({
|
||||
db.activityMod.addActivity({
|
||||
companyId,
|
||||
actor: "system",
|
||||
action: "agent.hired",
|
||||
@@ -142,7 +142,7 @@ export function handleApprovalResolved(
|
||||
}
|
||||
|
||||
publishDomainChanged();
|
||||
const hireLocale = db.listSnapshot().locale;
|
||||
const hireLocale = db.snap.listSnapshot().locale;
|
||||
notify({
|
||||
title: localizeNotification(hireLocale, "Agent Hired", "新员工入职"),
|
||||
body: localizeNotification(hireLocale, `${agent.name} joined as ${agent.role}`, `${agent.name} 已加入,职位:${agent.role}`),
|
||||
@@ -170,7 +170,7 @@ export function handleApprovalResolved(
|
||||
? "draft"
|
||||
: "in_review";
|
||||
for (const docId of documentIds) {
|
||||
db.updateDocumentStatus(docId, companyId, docStatus);
|
||||
db.documentsMod.updateDocumentStatus(docId, companyId, docStatus);
|
||||
}
|
||||
|
||||
if (approval.relatedTaskId) {
|
||||
@@ -185,7 +185,7 @@ export function handleApprovalResolved(
|
||||
if (decision === "approved") {
|
||||
db.tasks.advanceTaskStatus(task.id, "done", "Board approved deliverable.");
|
||||
handleTaskStatusChange(task.id, companyId, task.status, "done");
|
||||
db.addActivity({ companyId, actor: "board", action: "deliverable.approved", entityType: "task", entityId: task.id, detail: approval.decisionNote || "Deliverable approved by board." });
|
||||
db.activityMod.addActivity({ companyId, actor: "board", action: "deliverable.approved", entityType: "task", entityId: task.id, detail: approval.decisionNote || "Deliverable approved by board." });
|
||||
} else if (decision === "rejected") {
|
||||
recordReviewFeedbackKnowledge(db, approval, decision);
|
||||
db.tasks.advanceTaskStatus(task.id, "in_progress", `Board rejected deliverable: ${approval.decisionNote || "No reason given."}`);
|
||||
@@ -219,7 +219,7 @@ export function handleApprovalResolved(
|
||||
const documentIds = extractApprovalDocumentIds(approval.payloadJson);
|
||||
const docStatus = decision === "approved" ? "approved" : "draft";
|
||||
for (const docId of documentIds) {
|
||||
db.updateDocumentStatus(docId, companyId, docStatus);
|
||||
db.documentsMod.updateDocumentStatus(docId, companyId, docStatus);
|
||||
}
|
||||
publishDomainChanged();
|
||||
}
|
||||
@@ -235,8 +235,8 @@ export function handleApprovalResolved(
|
||||
};
|
||||
if (payload.policyId) {
|
||||
// Resolve the budget incident that triggered this approval
|
||||
db.resolveBudgetIncident(payload.policyId, companyId);
|
||||
db.addActivity({
|
||||
db.budget.resolveBudgetIncident(payload.policyId, companyId);
|
||||
db.activityMod.addActivity({
|
||||
companyId,
|
||||
actor: "board",
|
||||
action: "budget.override_approved",
|
||||
@@ -250,10 +250,10 @@ export function handleApprovalResolved(
|
||||
}
|
||||
}
|
||||
|
||||
const browserAction = db.getBrowserActionByApprovalId(approvalId, companyId);
|
||||
const browserAction = db.social.getBrowserActionByApprovalId(approvalId, companyId);
|
||||
if (browserAction) {
|
||||
if (decision === "approved") {
|
||||
db.updateBrowserAction(browserAction.id, {
|
||||
db.social.updateBrowserAction(browserAction.id, {
|
||||
status: "queued",
|
||||
resultSummary: "Approval granted. Dispatching browser action.",
|
||||
errorMessage: null,
|
||||
@@ -263,7 +263,7 @@ export function handleApprovalResolved(
|
||||
logger.error(`[browser] Failed to dispatch approved browser action ${browserAction.id}: ${error instanceof Error ? error.message : String(error)}`);
|
||||
});
|
||||
} else if (decision === "rejected") {
|
||||
db.updateBrowserAction(browserAction.id, {
|
||||
db.social.updateBrowserAction(browserAction.id, {
|
||||
status: "cancelled",
|
||||
resultSummary: "Browser action was rejected during approval.",
|
||||
errorMessage: "Approval rejected by board.",
|
||||
@@ -271,7 +271,7 @@ export function handleApprovalResolved(
|
||||
});
|
||||
publishDomainChanged();
|
||||
} else if (decision === "revision_requested") {
|
||||
db.updateBrowserAction(browserAction.id, {
|
||||
db.social.updateBrowserAction(browserAction.id, {
|
||||
status: "approval_required",
|
||||
resultSummary: "Board requested revisions before execution.",
|
||||
errorMessage: "Approval requires revisions before the browser action can run.",
|
||||
@@ -291,7 +291,7 @@ export function handleApprovalResolved(
|
||||
};
|
||||
|
||||
const dispatchSocialAction = () => {
|
||||
const actionId = db.saveBrowserAction({
|
||||
const actionId = db.social.saveBrowserAction({
|
||||
companyId: approval.companyId,
|
||||
socialAccountId: draft.socialAccountId,
|
||||
agentId: approval.requestedByAgentId ?? "",
|
||||
@@ -333,14 +333,14 @@ export function handleApprovalResolved(
|
||||
const payload = workflowApprovalPayloadSchema.safeParse(JSON.parse(approval.payloadJson));
|
||||
if (payload.success && payload.data.workflowId && payload.data.stepId) {
|
||||
const { workflowId, stepId } = payload.data;
|
||||
const workflow = db.getWorkflowRecord(workflowId, companyId);
|
||||
const workflow = db.automationMod.getWorkflowRecord(workflowId, companyId);
|
||||
if (workflow) {
|
||||
const steps = normalizeWorkflowSteps(JSON.parse(workflow.stepsJson || "[]"));
|
||||
const stepIndex = steps.findIndex((step) => step.id === stepId);
|
||||
if (stepIndex >= 0) {
|
||||
if (decision === "approved") {
|
||||
steps[stepIndex]!.status = "pending";
|
||||
db.updateWorkflowExecution({
|
||||
db.automationMod.updateWorkflowExecution({
|
||||
id: workflow.id,
|
||||
companyId,
|
||||
status: "paused",
|
||||
@@ -354,7 +354,7 @@ export function handleApprovalResolved(
|
||||
});
|
||||
} else {
|
||||
steps[stepIndex]!.status = decision === "revision_requested" ? "pending" : "failed";
|
||||
db.updateWorkflowExecution({
|
||||
db.automationMod.updateWorkflowExecution({
|
||||
id: workflow.id,
|
||||
companyId,
|
||||
status: decision === "revision_requested" ? "paused" : "failed",
|
||||
|
||||
@@ -50,7 +50,7 @@ export function handleTaskStatusChange(
|
||||
}
|
||||
if (!task) return;
|
||||
|
||||
db.addActivity({
|
||||
db.activityMod.addActivity({
|
||||
companyId,
|
||||
actor: task.assigneeAgentId ?? "board",
|
||||
action: "task.status_changed",
|
||||
|
||||
@@ -151,7 +151,7 @@ function checkRunProducedDeliverable(
|
||||
taskId: string,
|
||||
taskType: string,
|
||||
): boolean {
|
||||
const signals = db.collectRunDeliverableSignals(runId, companyId, taskId);
|
||||
const signals = db.knowledgeMod.collectRunDeliverableSignals(runId, companyId, taskId);
|
||||
return hasValidDeliverableFor(taskType, signals);
|
||||
}
|
||||
|
||||
@@ -274,7 +274,7 @@ function advanceToInReview(
|
||||
}
|
||||
db.tasks.advanceTaskStatus(taskId, "in_review", statusMessage);
|
||||
callbacks.handleTaskStatusChange(taskId, run.companyId, "in_progress", "in_review");
|
||||
const company = db.listSnapshot().companies.find((c) => c.id === run.companyId);
|
||||
const company = db.snap.listSnapshot().companies.find((c) => c.id === run.companyId);
|
||||
if (company?.reviewDeliverables) {
|
||||
const importantDocs = findImportantDocsForRun(db, run.id, run.companyId);
|
||||
if (importantDocs.length > 0) {
|
||||
@@ -462,7 +462,7 @@ export function processRunCompletion(
|
||||
});
|
||||
}
|
||||
}
|
||||
const budgetLocale = db.listSnapshot().locale;
|
||||
const budgetLocale = db.snap.listSnapshot().locale;
|
||||
checkBudgetThreshold(
|
||||
agent,
|
||||
notify,
|
||||
|
||||
@@ -73,7 +73,7 @@ export function resolveWorkflowStepActor(
|
||||
}
|
||||
}
|
||||
|
||||
const snapshot = db.listSnapshot();
|
||||
const snapshot = db.snap.listSnapshot();
|
||||
return snapshot.agents.find((agent) => agent.companyId === companyId && !agent.reportsTo && agent.status !== "terminated") ?? null;
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@ export async function runWorkflowPipeline(
|
||||
): Promise<void> {
|
||||
const { db, publishDomainChanged } = deps;
|
||||
|
||||
const workflow = db.getWorkflowRecord(workflowId, companyId);
|
||||
const workflow = db.automationMod.getWorkflowRecord(workflowId, companyId);
|
||||
if (!workflow) {
|
||||
throw new Error("Workflow not found.");
|
||||
}
|
||||
@@ -132,7 +132,7 @@ export async function runWorkflowPipeline(
|
||||
return step;
|
||||
});
|
||||
|
||||
db.updateWorkflowExecution({
|
||||
db.automationMod.updateWorkflowExecution({
|
||||
id: workflowId,
|
||||
companyId,
|
||||
status: "active",
|
||||
@@ -146,7 +146,7 @@ export async function runWorkflowPipeline(
|
||||
for (let index = resumeFrom; index < steps.length; index += 1) {
|
||||
const step = steps[index]!;
|
||||
step.status = "running";
|
||||
db.updateWorkflowExecution({
|
||||
db.automationMod.updateWorkflowExecution({
|
||||
id: workflowId,
|
||||
companyId,
|
||||
status: "active",
|
||||
@@ -170,7 +170,7 @@ export async function runWorkflowPipeline(
|
||||
payloadJson: JSON.stringify({ workflowId, stepId: step.id, stepName: step.name }),
|
||||
});
|
||||
step.status = "pending";
|
||||
db.updateWorkflowExecution({
|
||||
db.automationMod.updateWorkflowExecution({
|
||||
id: workflowId,
|
||||
companyId,
|
||||
status: "paused",
|
||||
@@ -178,7 +178,7 @@ export async function runWorkflowPipeline(
|
||||
stepsJson: JSON.stringify(steps),
|
||||
lastRunAt: new Date().toISOString(),
|
||||
});
|
||||
db.addActivity({
|
||||
db.activityMod.addActivity({
|
||||
companyId,
|
||||
actor: actor?.id ?? "system",
|
||||
action: "workflow.paused_for_approval",
|
||||
@@ -203,7 +203,7 @@ export async function runWorkflowPipeline(
|
||||
ctx,
|
||||
);
|
||||
step.status = "completed";
|
||||
db.addActivity({
|
||||
db.activityMod.addActivity({
|
||||
companyId,
|
||||
actor: actor?.id ?? "system",
|
||||
action: "workflow.step_completed",
|
||||
@@ -213,7 +213,7 @@ export async function runWorkflowPipeline(
|
||||
});
|
||||
const isLastStep = index === steps.length - 1;
|
||||
const completionStatus = isLastStep ? "completed" : "active";
|
||||
db.updateWorkflowExecution({
|
||||
db.automationMod.updateWorkflowExecution({
|
||||
id: workflowId,
|
||||
companyId,
|
||||
status: completionStatus,
|
||||
@@ -224,7 +224,7 @@ export async function runWorkflowPipeline(
|
||||
publishDomainChanged();
|
||||
} catch (error) {
|
||||
step.status = "failed";
|
||||
db.updateWorkflowExecution({
|
||||
db.automationMod.updateWorkflowExecution({
|
||||
id: workflowId,
|
||||
companyId,
|
||||
status: "failed",
|
||||
@@ -232,7 +232,7 @@ export async function runWorkflowPipeline(
|
||||
stepsJson: JSON.stringify(steps),
|
||||
lastRunAt: new Date().toISOString(),
|
||||
});
|
||||
db.addActivity({
|
||||
db.activityMod.addActivity({
|
||||
companyId,
|
||||
actor: actor?.id ?? "system",
|
||||
action: "workflow.step_failed",
|
||||
|
||||
@@ -107,7 +107,7 @@ export function createAutomationService({
|
||||
|
||||
function evaluateAutomationRules(trigger: string, ctx: AutomationEventContext) {
|
||||
try {
|
||||
const rules = db.listActiveAutomationRules(ctx.companyId, trigger);
|
||||
const rules = db.automationMod.listActiveAutomationRules(ctx.companyId, trigger);
|
||||
for (const rule of rules) {
|
||||
if (!matchesConditions(db, rule, ctx, logger)) continue;
|
||||
const executionKey = JSON.stringify({
|
||||
@@ -127,7 +127,7 @@ export function createAutomationService({
|
||||
activeAutomationExecutions.add(executionKey);
|
||||
try {
|
||||
executeAutomationAction(actionDeps, actionCallbacks, rule, ctx);
|
||||
db.recordAutomationExecution(
|
||||
db.automationMod.recordAutomationExecution(
|
||||
rule.id,
|
||||
ctx.companyId,
|
||||
rule.name,
|
||||
@@ -145,7 +145,7 @@ export function createAutomationService({
|
||||
logger.info(`[automation] Fired rule "${rule.name}" (${trigger} → ${rule.action})`);
|
||||
} catch (error) {
|
||||
logger.error(`[automation] Failed to execute action for rule "${rule.name}": ${error instanceof Error ? error.message : String(error)}`);
|
||||
db.recordAutomationExecution(
|
||||
db.automationMod.recordAutomationExecution(
|
||||
rule.id,
|
||||
ctx.companyId,
|
||||
rule.name,
|
||||
@@ -164,7 +164,7 @@ export function createAutomationService({
|
||||
|
||||
function evaluateWorkflowTriggers(trigger: string, ctx: AutomationEventContext) {
|
||||
try {
|
||||
const workflows = db.listTriggerableWorkflows(ctx.companyId, trigger);
|
||||
const workflows = db.automationMod.listTriggerableWorkflows(ctx.companyId, trigger);
|
||||
for (const workflow of workflows) {
|
||||
if (!matchesEventConfig(db, workflow.triggerConfigJson, null, ctx, logger)) continue;
|
||||
const executionKey = JSON.stringify({
|
||||
|
||||
Reference in new issue
Block a user