Files
maestro/src/store/mappers.ts
T
wangjia fe7923a618 feat(agent): L2/L4 记忆注入——项目规范 + 全局规范文件喂进 4 处 prompt
- 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>
2026-06-24 22:29:29 +08:00

117 lines
5.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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,
};
}