Replaces legacy adapter ids (codex_local / claude_local / gemini_local / claude_compatible) across ~42 test files with pi-mono equivalents: - codex_local → openai-codex - claude_local → claude-pro - gemini_local → gemini-cli - claude_compatible → anthropic Hand-rewrites where fixture semantics changed: - connector-matching: TASK_TYPE_PREFERENCE ordering rebased (claude-pro first for code/content/management; google first for research) - connector-model-policy: getModels(provider) from pi-ai instead of the deleted adapter.module.models array - session-management + edge-case-session: adapter exemption removed; rotation now uniform under pi-mono - ipc-core-admin-handlers: CSV compat model replaced with pi-ai anthropic - connectors.spec: lookup by openai-codex id (catalog now starts with claude-pro) - onboarding-model-pool: listProviderModels(provider) helper; label text changed to "ChatGPT Plus/Pro (Codex)" - database integration: added vault insecure-fallback env + electron mock - command-paths: uses new @main/connector-helpers normalizeCommandValue - pi-mono-migrations: added `as string` casts for 3 negative-existence assertions verifying legacy ids were removed Drops: - pnpm-workspace.yaml packages: [] (was "packages/*"; directory empty) - obsolete CONNECTOR_STRENGTHS import; .module.models probing Verification: - pnpm typecheck → 0 errors - pnpm lint → 0 errors / 0 warnings - pnpm build:verify → 0 errors / 0 warnings - pnpm test:unit → 508/508 pass - pnpm test:integration → 96/96 pass - All 6 adapter hard gates pass (NOT FOUND / 0 matches / empty) - pi-ai / pi-agent-core / pi-coding-agent all resolved @0.67.6
71 lines
2.6 KiB
TypeScript
71 lines
2.6 KiB
TypeScript
import type { DatabaseSync } from "node:sqlite";
|
|
import { STALE_LOCK_TIMEOUT_MS } from "./database-base";
|
|
|
|
function nowIso(): string {
|
|
return new Date().toISOString();
|
|
}
|
|
|
|
/**
|
|
* Stale-state recovery helpers extracted from `database-base.ts` to keep that
|
|
* file under the 400-line cap. Both helpers are called by `AppDatabase.init`
|
|
* (interruptStaleRuns) and the orchestration recovery loop (recoverStaleLocks).
|
|
*/
|
|
|
|
interface InterruptDeps {
|
|
db: DatabaseSync;
|
|
transaction: <T>(op: () => T) => T;
|
|
releaseAllWorkspaceLocks: () => void;
|
|
}
|
|
|
|
export function interruptStaleRunsImpl(deps: InterruptDeps): number {
|
|
const ts = nowIso();
|
|
let interruptedCount = 0;
|
|
deps.transaction(() => {
|
|
const result = deps.db
|
|
.prepare(
|
|
"update runs set status = 'interrupted', error_message = 'AgentCompany restarted before the run could report completion.', finished_at = ?, updated_at = ? where status = 'running'",
|
|
)
|
|
.run(ts, ts);
|
|
interruptedCount = Number(result.changes);
|
|
if (interruptedCount > 0) {
|
|
deps.db
|
|
.prepare(
|
|
"update tasks set status = 'blocked', updated_at = ? where id in (select task_id from runs where status = 'interrupted' and finished_at = ?) and status in ('in_progress', 'todo')",
|
|
)
|
|
.run(ts, ts);
|
|
}
|
|
deps.db
|
|
.prepare(
|
|
"update tasks set active_run_id = null where active_run_id in (select id from runs where status = 'interrupted')",
|
|
)
|
|
.run();
|
|
deps.db.prepare("update agents set status = 'idle', updated_at = ? where status = 'running'").run(ts);
|
|
deps.releaseAllWorkspaceLocks();
|
|
});
|
|
return interruptedCount;
|
|
}
|
|
|
|
interface RecoverDeps {
|
|
db: DatabaseSync;
|
|
readAll: <T>(sql: string, ...params: import("node:sqlite").SQLInputValue[]) => T[];
|
|
}
|
|
|
|
export function recoverStaleLocksImpl(
|
|
deps: RecoverDeps,
|
|
): Array<{ taskId: string; companyId: string; title: string }> {
|
|
const cutoff = new Date(Date.now() - STALE_LOCK_TIMEOUT_MS).toISOString();
|
|
const stale = deps.readAll<{ id: string; companyId: string; title: string }>(
|
|
"SELECT id, company_id AS companyId, title FROM tasks WHERE execution_locked_at IS NOT NULL AND execution_locked_at < ? AND status = 'in_progress' AND checkout_run_id NOT IN (SELECT id FROM runs WHERE status = 'running')",
|
|
cutoff,
|
|
);
|
|
const ts = nowIso();
|
|
for (const task of stale) {
|
|
deps.db
|
|
.prepare(
|
|
"UPDATE tasks SET checkout_run_id = NULL, execution_locked_at = NULL, status = 'todo', updated_at = ? WHERE id = ?",
|
|
)
|
|
.run(ts, task.id);
|
|
}
|
|
return stale.map((t) => ({ taskId: t.id, companyId: t.companyId, title: t.title }));
|
|
}
|