fe7923a618
- L2 projects.agent_rules 列(schema+迁移+类型+mapper+patchProject+API 透传) - L4 protocol.readGlobalAgentRules():worker 直接读 <data>/agent-global.md(非DB, 不读用户 ~/.claude/CLAUDE.md,避免个人习惯与受控执行冲突) - runner.rulesHeaderLines 注入 executor/planner/conflict;reviewer 同注入 - 顺序:全局规范(L4)→项目规范(L2)→任务内容→上次失败(L1)→执行约束 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
117 lines
5.2 KiB
TypeScript
117 lines
5.2 KiB
TypeScript
import type { Project, Task, ApprovalRecord, Run, Event, TaskResult, Autonomy } from '../model/types.js';
|
||
import type { Complexity } from '../model/complexity.js';
|
||
import type { TaskStatus, GateKind } from '../model/status.js';
|
||
import type { RunKind, RunStatus, EventType } from '../model/types.js';
|
||
|
||
/** SQLite 行类型(snake_case,文本/数字原样) */
|
||
export interface ProjectRow {
|
||
id: string; name: string; repo_path: string; default_branch: string;
|
||
verify_cmd: string | null; autonomy: string; model: string | null;
|
||
concurrency: number; max_retries: number; timeout_ms: number;
|
||
status: string; created_at: string;
|
||
last_sync_at: string | null; logo: string | null; sort_order: number;
|
||
checks: string | null; auto_approve_plan: number; auto_approve_exec: number;
|
||
budget_usd: number | null; budget_period: string | null;
|
||
agent_rules: string | null;
|
||
}
|
||
export interface TaskRow {
|
||
id: string; project_id: string; parent_id: string | null; depth: number;
|
||
title: string; complexity: string; status: string; priority: number;
|
||
deps: string; plan: string | null; spec: string | null; operations: string | null;
|
||
result: string | null; assignee: string | null; retry_baseline: number;
|
||
next_eligible_at: string | null;
|
||
created_at: string; updated_at: string;
|
||
source_ref: string | null;
|
||
attachments: string | null;
|
||
last_run_error?: string | null; // pendingApprovals 扩展字段(subquery)
|
||
}
|
||
export interface ApprovalRow {
|
||
id: string; task_id: string; gate: string; action: string;
|
||
actor: string; reason: string | null; at: string;
|
||
}
|
||
export interface RunRow {
|
||
id: string; task_id: string; kind: string; worktree: string | null; branch: string | null;
|
||
status: string; started_at: string; ended_at: string | null;
|
||
transcript_ref: string | null; claude_session_id: string | null; error: string | null;
|
||
worker_pid: number | null; last_seq: number;
|
||
usage: string | null; cost_usd: number | null;
|
||
}
|
||
export interface EventRow {
|
||
id: string; project_id: string; task_id: string | null; type: string; payload: string; at: string;
|
||
}
|
||
|
||
export function rowToProject(r: ProjectRow): Project {
|
||
return {
|
||
id: r.id, name: r.name, repoPath: r.repo_path, defaultBranch: r.default_branch,
|
||
verifyCmd: r.verify_cmd, autonomy: r.autonomy as Autonomy, model: r.model,
|
||
concurrency: r.concurrency, maxRetries: r.max_retries ?? 2, timeoutMs: r.timeout_ms ?? 1_800_000,
|
||
status: r.status as Project['status'], createdAt: r.created_at,
|
||
lastSyncAt: r.last_sync_at, logo: r.logo, sortOrder: r.sort_order,
|
||
checks: r.checks ?? null,
|
||
autoApprovePlan: Boolean(r.auto_approve_plan),
|
||
autoApproveExec: Boolean(r.auto_approve_exec),
|
||
budgetUsd: r.budget_usd ?? null,
|
||
budgetPeriod: (r.budget_period === 'day' ? 'day' : 'month'),
|
||
agentRules: r.agent_rules ?? null,
|
||
};
|
||
}
|
||
|
||
/** 旧 result JSON 兜底:summary/verdict/securitySummary/securityVerdict 是后加字段,老数据缺省补 null */
|
||
function parseResult(json: string): TaskResult {
|
||
const raw = JSON.parse(json) as Partial<TaskResult>;
|
||
const verdict = (v: unknown): TaskResult['verdict'] => (v === 'approve' || v === 'reject' ? v : null);
|
||
return {
|
||
branch: raw.branch ?? null,
|
||
worktree: raw.worktree ?? null,
|
||
diffSummary: raw.diffSummary ?? null,
|
||
commits: raw.commits ?? [],
|
||
prUrl: raw.prUrl ?? null,
|
||
summary: raw.summary ?? null,
|
||
verdict: verdict(raw.verdict),
|
||
securitySummary: raw.securitySummary ?? null,
|
||
securityVerdict: verdict(raw.securityVerdict),
|
||
mergeTaskId: raw.mergeTaskId ?? null,
|
||
};
|
||
}
|
||
|
||
export function rowToTask(r: TaskRow, approvals: ApprovalRecord[] = []): Task {
|
||
return {
|
||
id: r.id, projectId: r.project_id, parentId: r.parent_id, depth: r.depth,
|
||
title: r.title, complexity: r.complexity as Complexity, status: r.status as TaskStatus,
|
||
priority: r.priority, deps: JSON.parse(r.deps) as string[],
|
||
plan: r.plan, spec: r.spec, operations: r.operations,
|
||
approvals, result: r.result ? parseResult(r.result) : null,
|
||
assignee: r.assignee as Task['assignee'], retryBaseline: r.retry_baseline ?? 0,
|
||
nextEligibleAt: r.next_eligible_at ?? null,
|
||
lastRunError: r.last_run_error ?? null,
|
||
attachments: r.attachments ? (JSON.parse(r.attachments) as Task['attachments']) : undefined,
|
||
createdAt: r.created_at, updatedAt: r.updated_at,
|
||
};
|
||
}
|
||
|
||
export function rowToApproval(r: ApprovalRow): ApprovalRecord {
|
||
return {
|
||
gate: r.gate as GateKind, action: r.action as ApprovalRecord['action'],
|
||
actor: r.actor, reason: r.reason, at: r.at,
|
||
};
|
||
}
|
||
|
||
export function rowToRun(r: RunRow): Run {
|
||
return {
|
||
id: r.id, taskId: r.task_id, kind: r.kind as RunKind,
|
||
worktree: r.worktree, branch: r.branch, status: r.status as RunStatus,
|
||
startedAt: r.started_at, endedAt: r.ended_at,
|
||
transcriptRef: r.transcript_ref, claudeSessionId: r.claude_session_id, error: r.error,
|
||
workerPid: r.worker_pid ?? null, lastSeq: r.last_seq ?? 0,
|
||
usage: r.usage ? (JSON.parse(r.usage) as Run['usage']) : null,
|
||
costUsd: r.cost_usd ?? null,
|
||
};
|
||
}
|
||
|
||
export function rowToEvent(r: EventRow): Event {
|
||
return {
|
||
id: r.id, projectId: r.project_id, taskId: r.task_id,
|
||
type: r.type as EventType, payload: JSON.parse(r.payload) as Record<string, unknown>, at: r.at,
|
||
};
|
||
}
|