Commit Graph

62 Commits

Author SHA1 Message Date
wangjia a8f75cf10a fix(store): reconcileInterrupted 跳过已终态任务,避免 cancelled→failed 让 daemon 启动崩溃
执行中的任务被 cancel 后仍挂 started run;daemon 重启时 reconcileInterrupted 对它调 failTaskAttempt → transition(cancelled→failed) 非法 → 启动抛错退出(整个 daemon 起不来)。修:终态(cancelled/done)任务只 finishRun 收尾,不再 fail*Attempt。含回归测试(202 全绿)。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 23:27:53 +08:00
wangjia d1862efb4b merge: planner runs — 编排器自动拆解 hard / 自动写方案 medium [planner; tsk_1dkswD5Ub7gT]
部署 planner 功能(此前实现在 planner 分支、测试绿,未合):编排器把 analyzing/speccing 也当可执行,派 planner run 自动拆解(hard→子任务+plan_review)/写方案(medium→spec+spec_review);in-flight 从 status 泛化为'有 started run';reap 区分 executor/planner。与 main 干净合并,typecheck + 201 测试全绿。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 23:10:12 +08:00
wangjia 645d36323e merge: worker 池化 + SDK resume 抗抖动 [tsk_74Acz1Nh4K1J]
手工正确合并(破除补救死循环):带上 src/executor/cc.ts 池化 + SDK resume + test/cc.test.ts(typecheck + 189 测试全绿)。DESIGN.md 冲突取 main 新版(多进程 re-adopt / worker 不碰 DB 描述),保留 246 行 SDK-resume 新增条目,丢弃分支过时描述。

此前补救任务只啃了 DESIGN.md 冲突文件、没带 cc.ts 代码,导致真代码一直没落地、原任务卡 exec_review、每次重试又生新补救(xbtd6GpS4NYg→Yb8eFAX2VUxZ)的死循环,至此终结。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 20:32:10 +08:00
wangjia d1e256b960 merge: 合并失败补救完成后自动收口原任务 [tsk_BagzbKZNAHXV]
手工解决 src/api/server.ts 冲突(keep-both):main 的 cleanupTaskRunArtifacts(合并后回收 run 目录)与分支的 findMergeOriginTask/remediateOrigin(补救任务合并成功后自动把原任务标 done)互补,均保留;ensureMergeRemediationTask 调用补 conflictFiles。其余文件(store.ts/types.ts/merge.ts/web/test)自动合并。typecheck + 183 测试全绿。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 20:10:00 +08:00
maestro 3d73b0cd85 merge: maestro/tsk_xbtd6GpS4NYg [tsk_xbtd6GpS4NYg] 2026-06-13 20:01:05 +08:00
wangjia 8392944877 feat(planner): 编排器把 analyzing/speccing 也当可执行——派 planner run 自动拆解/写方案
修复"hard/medium 任务建后永远停在 analyzing/speccing"的缺口:编排器现在对 analyzing(hard)
派 planner-decompose、对 speccing(medium) 派 planner-spec(auto-approved 下;auto-easy 仍只执行 easy),
planner 只读跑 CC(无 worktree/无写)产出 → daemon 落库 + 自动提交到 plan_review/spec_review 闸(仍人审)。

- protocol: JobSpec.runKind + spec-result/decompose-result 两型 outbox + DecomposeResult
- runner: runPlanner(只读 Read/Glob/Grep 跑在 repo,opus 档)+ buildPlannerPrompt
- pipeline: runKind 分支 + parseDecompose(取末尾 fenced JSON,非法→failed)
- orchestrator: claimable 纳入 analyzing/speccing + 排除在途;并发/in-flight 从 countExecuting 泛化为
  inflightTaskIds(有 started run 的任务,executor+planner 通用);claimOne 按状态分 executor/planner
  (planner 不转状态);reap 泛化(死 planner→failPlanAttempt)
- ingest: ingestAll 覆盖所有 started run;spec-result→setSpec+spec_review;decompose-result→setPlan+建子任务+plan_review;
  failed 按 kind 分流(planner→failPlanAttempt 退避留态、超限→needs_attention)
- store: inflightTaskIds / liveRunsWithTask / failPlanAttempt;reconcile 泛化到所有 started run
- status: analyzing/speccing 加 →needs_attention(planner 失败超限升级)
- models: planner 角色(opus);status: RunKind 已含 planner
- 测试 +12(pipeline 5 / ingest 3 / orchestrator 4),194 全绿

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 16:59:30 +08:00
wangjia 724cebb653 merge: 合并冲突解决 —— worker 池化评估 + SDK resume 抗抖动 [tsk_xbtd6GpS4NYg]
将 maestro/tsk_74Acz1Nh4K1J 分支的 DESIGN.md 改动手动合并:
1. §19 分期状态:新增「🟡 worker 池化(已评估,暂缓)」说明
2. §20 风险与注意事项:新增「SDK 抖动 → resume 续跑」条目

保留了 HEAD 中已有的更详细版本的「自动执行安全」和「中断恢复(多进程 re-adopt)」条目。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 16:46:50 +08:00
maestro 0ed4f73106 merge: maestro/tsk_3uhHOGU0qzj0 [tsk_3uhHOGU0qzj0] 2026-06-13 15:51:39 +08:00
maestro dcf610f6fd merge: maestro/tsk_oTFzOMeAU20D [tsk_oTFzOMeAU20D] 2026-06-13 15:51:31 +08:00
maestro 4d5344ef63 merge: maestro/tsk_6uziW1Dg-ftQ [tsk_6uziW1Dg-ftQ] 2026-06-13 15:50:53 +08:00
maestro d4580ab32d merge: maestro/tsk_-HYVwxzHIbrS [tsk_-HYVwxzHIbrS] 2026-06-13 15:50:42 +08:00
wangjia 1c4a81b3f3 feat(web): SVG 图标集替换 Unicode —— tsk_3uhHOGU0qzj0
用 design/assets/icons/ 的 15 个双色 SVG 图标替换现网纯 Unicode 图标:

• 拷贝 design/assets/icons/*.svg → web/assets/icons/(15 个)
• app.js 顶部新增 ICONS 对象 + icon() 内联 helper
• index.html:徽章组(gate/ready/running/deps)、配置按钮(config)、
  同步按钮(sync)、搜索输入框(search + filter-search-wrap 包装)、
  清除筛选按钮(close)、「新建」/「新建任务」按钮(add)
  各区块头加语义图标:project/task/gate/running/flow
• app.js 模板字符串:⛓→deps、✕→close(任务行取消/预览关闭/归档关闭)、
  依赖等待标签、ap-reason→reason SVG、分支显示→git、事件项 ev-type→event
• style.css:新增 svg.icon 基础尺寸规则、filter-search-wrap 布局、
  各语义上下文 --icon-accent 注入(暗/浅主题均用 CSS 变量自动适配)、
  .ap-reason::before 移除 content:'↳' 改用 SVG
• 品牌字符保留不动:▍▮→·— 及状态 CSS 圆点

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 15:08:53 +08:00
wangjia d0b807460e feat(executor): worker OS 级沙箱 + 资源限额(sandbox-exec / ulimit)[tsk_oTFzOMeAU20D]
进程隔离之上再加一层 OS 级硬隔离,默认关闭,便于先在一个项目灰度:

- 新增 src/executor/sandbox.ts:
  - macOS sandbox-exec 写围栏 profile(allow default 基线 + deny file-write* 收口
    + 逐条放行 worktree/主仓.git/node_modules/runs/transcripts/tmp/工具缓存)。
    不 deny default 全围栏——合法 git/npm/go/node 需读海量系统路径,写才是破坏向量。
  - ulimit 资源上限(CPU 时间/虚拟内存/打开文件数/单文件大小),经 sh -c 下发,
    exec 链保证 pid 不变(daemon 记录的 workerPid 仍是真 worker)。
  - 全部由 env 解析(MAESTRO_SANDBOX*),网络默认放行(SDK 连 Anthropic)。
- orchestrator.defaultSpawnWorker 接入:开启时把命令包成
  sh -c 'ulimit…; exec sandbox-exec -f profile <原命令>';关闭时行为零变化。
  startOrchestrator 启动时打印生效策略,每个 run 的 profile 落 runs/<runId>/sandbox.sb。
- README 增补环境变量与「worker 沙箱」说明。
- 新增 test/sandbox.test.ts(18 例:config 解析 / profile 生成 / ulimit / 包装 / 预建目录)。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 15:08:18 +08:00
wangjia b1d881a4b4 feat: 合并失败→补救→完成 全程事件轨迹与自动收口 [tsk_BagzbKZNAHXV]
不新增顶层状态,用 events + result 字段记录完整轨迹:
- 新增 merge.failed / merge.remediated 两类事件
- merge 失败时在原任务时间线记 merge.failed 节点(结构化冲突文件 + 补救任务链接)
- 补救任务成功合并后,findMergeOriginTask 反查原任务,remediateOrigin 自动把原任务标 done
  并记 merge.remediated 节点,无需人工 merge:false
- 看板:归档时间线渲染失败/补救节点;结果评审闸显示「合并失败 → 补救任务」横幅

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 15:04:39 +08:00
wangjia 53efe32a6e feat(executor): SDK 抖动 resume 续跑 + worker 池化评估暂缓 [tsk_74Acz1Nh4K1J]
可选优化任务,先评估收益再做:

- worker 池化:评估后暂缓。当前「一 run ↔ 一 pid」模型干净(判活/回收/
  re-adopt 全靠每 run 一 pid+心跳,worker 与 DB 隔离 + 重启 re-adopt 天然
  崩溃恢复),池化会打破该不变量且只在高并发量下兑现收益。现规模保持
  「每任务一进程 + 失败从头重跑」简单模型,仅记入 DESIGN.md。

- SDK resume:实现 worker 内部健壮性小优化。cc.ts 单次会话因流式异常中断
  (流断/没收到 result,非超时取消、非 max_turns 终态)且已拿到 sessionId 时,
  用 resume 接着原会话续跑一次(保留已干的活,不从头重来),剩余预算不足留 60s。
  与「重启 re-adopt / 整体失败 daemon 从头重跑」正交不替代;与模型回退互斥;
  MAESTRO_SDK_RESUME=0 可关闭。query 改为可注入便于单测。

测试:新增 test/cc.test.ts(6 例:续跑成功/终态不续/无 session 不续/
开关关闭/超时不续/模型回退)。npm test 全绿 163/163。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 15:03:25 +08:00
wangjia a365aaf06a feat(cleanup): exec_review 合并后回收 runs/<runId>/ 工作目录 + 定期扫尾 [tsk_6uziW1Dg-ftQ]
每个 run 在 ~/.maestro/runs/<runId>/ 留下 job.json/outbox.ndjson/heartbeat,
合并(exec_review accept)后不再需要,需回收避免无限堆积。

- protocol.ts:新增 removeRunDir / isPlainRunId(幂等删 runDir,runId 白名单防越界)
- cleanup.ts(新):
  - cleanupTaskRunArtifacts:合并/接受后即时回收某任务全部 run 工作目录
  - sweepRunArtifacts:周期扫尾终态/孤儿 runDir 与(可选)转录,按保留天数
  - isRunCleanable:仅终态(done/cancelled)/孤儿可回收,活跃/在途一律保留
  - 双保险:任务状态判定 + heartbeat 新鲜则跳过,绝不误删活跃 run
  - 保留策略可配:MAESTRO_RUN_RETENTION_DAYS(默认3) /
    MAESTRO_TRANSCRIPT_RETENTION_DAYS(默认0=永久保留,便于排查)
- server.ts:exec_review accept 合并成功后即时清 runDir(与 removeWorktree 同处)
- index.ts:startCleanupLoop 定时扫尾(MAESTRO_CLEANUP_INTERVAL 秒,默认3600,0=关闭)
- test/cleanup.test.ts:终态清/在途留/孤儿清/保留期/heartbeat 兜底/转录开关/配置

测试:npm test → 164 passed;npm run typecheck → clean

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 15:02:23 +08:00
wangjia 52c053baf4 docs: 更新 DESIGN.md/README 到 Phase 3 多进程执行架构 [tsk_-HYVwxzHIbrS]
- 写清工作模式:daemon=唯一 DB 写者+监工;worker=哑执行器(不碰 DB)
- 通讯协议:job.json / outbox.ndjson(幂等 ingest)/ heartbeat / SIGTERM
- 重启语义:reconcile 按 worker_pid+心跳判活 → re-adopt 或回收重试 + 持久化退避
- 同步更新系统总览图、数据模型(worker_pid/last_seq/next_eligible_at)、后端架构、风险、Phase 进度、env 表

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 15:00:42 +08:00
maestro f020e15137 merge: maestro/tsk_KhcaF4zoESVe [tsk_KhcaF4zoESVe] 2026-06-13 14:53:40 +08:00
wangjia 10f881130b style(web): 小圆角 + 审批闸琥珀→紫 + 组件样式对齐 design [tsk_KhcaF4zoESVe]
看板重构 B2:对照 design/components 与 design/tokens 精修 web 组件样式。

圆角(采用 --radius-* 令牌,状态点保持正圆):
- xs(3) chip/徽章:StatusChip(.chip)、ComplexityBadge(.cplx)、CountBadge 顶栏 count、
  .verdict/.fchip/.fgroup/.gate-kind/.run-st/.t-badge/.t-deps-wait/.agent-run-kind/
  .gate-stripe/.metric-model-bar/.gate-count/.ready-count/.doc.md code
- sm(4) 按钮/输入/doc 块:.btn、input/select/textarea、.seg、.bdg、pre.doc、.doc.md、
  codeblock、.t-pre、.dep-item/.dep-pick、.detail-action-confirm、archive-size select、
  .doc-pending
- md(6) 面板/卡片/toast:.panel、.gate-card、.toast、.filter-bar、.agent-flex/.agent-empty、
  .tree-empty、.metric-card/.metric-models、.run-item、.cplx-pop
- lg(10) 模态/预览浮层:.modal、.preview-panel

审批闸 琥珀→紫(--violet/--violet-dim),与 MED(--amber) 区分:
- gate-stripe 斜纹条、gate-head/gate-section 区块头、gate-card 边框、gate-kind 徽章、
  bdg-gate 待审批徽章、chip-gate 待审/合状态 chip、gate-count、ev-gatewait 事件、
  is-gate 行底色、preview-panel 边框;index.html 审批闸 head-mark 改 violet
- MED 保持琥珀:cplx-medium / seg-m / fc-medium / bdg-blocked / t-deps-wait / dep-item

组件对齐 design 卡片:GateCard 加 overflow:hidden + body 字号 12.5px、gate-title 13px;
浮层阴影统一走 --shadow-pop/modal/toast 令牌;EventItem 圆点 1.5px 微圆角。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 14:45:03 +08:00
wangjia d160d27645 fix(merge): in-place 合并脏树守卫忽略未跟踪文件(--untracked-files=no)
之前 mergeInPrimaryCheckout 用 git status --porcelain 判脏,未跟踪文件(GEMINI.md/.claude/
本地杂物)也算进去 → 误判拒绝合并(jiu/dudu 等带未跟踪文件的项目「通过并合并」必失败)。
改为 --untracked-files=no 只看已跟踪改动;未跟踪文件不挡合并(真要被覆盖时 git merge 自报错走 catch)。
测试加:仅未跟踪文件 → 仍 in-place 合并成功。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 14:40:31 +08:00
maestro c1cdcc7e5e merge: maestro/tsk_pusPU3oCPVfc [tsk_pusPU3oCPVfc] 2026-06-13 14:36:22 +08:00
wangjia 4be02cbf0f feat(tokens): 设计令牌落地 + 浅色主题骨架 [tsk_pusPU3oCPVfc]
在 web/style.css :root 补全缺失令牌:
- --violet / --violet-dim(磷光紫,审批闸色)
- --glow-green/violet/cyan/red(辉光 shadow 值)
- --radius-xs/sm/md/lg/dot(圆角阶梯)
- --space-1..9(间距阶)
- --pad-btn/btn-xs/input/chip/card(控件内边距)
- --shadow-pop/modal/toast(浮层阴影)
- --surface-*/--text-*/--border-*/--accent*/--status-go|gate|bad|run(语义别名)

新增 [data-theme="light"] 完整块,覆盖全部底色、文字、
信号色与辉光变量,确保浅色切换不崩版。

现有 --green/amber/red/cyan 及 @keyframes blink/pulse/rise
均未改动,暗色主题视觉零影响。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 14:32:29 +08:00
wangjia 5a1e185b1a docs(design): 解压 Maestro Design System 到 design/(重构参照材料)
phosphor console v1.1 设计系统(从现网 web/style.css 演化):tokens(colors/effects/
typography/fonts) + components(core/forms/surfaces .jsx) + ui_kits(console + console_mobile)
+ assets/icons(15 双色 SVG) + guidelines + CLAUDE/SKILL/readme。供 B1–B6 重构任务对照实现。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 14:29:07 +08:00
wangjia 0b3ebbd569 feat(api): DELETE /api/projects/:id + store.deleteProject(连带 tasks/runs/events)
新增项目删除能力:store.deleteProject 事务内删 events(无 FK,手动)+ projects(tasks/runs/
approvals 经 schema ON DELETE CASCADE 连带清);DELETE /api/projects/:id 暴露之。
store.test 覆盖连带清除 + 重复删报错。用于清理 cutover 测试遗留的一次性 smoke-test 项目
(本次经直连 DB 删除,未重启打断在跑的 worker;端点下次重启生效)。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 14:15:38 +08:00
wangjia 0d45de4507 fix(worker): env 收敛改黑名单 + 不 detached —— 修 worker 'Not logged in'
cutover 实测:worker 起的 claude 报 Not logged in。根因:① 严格 env allowlist 把 macOS
keychain/Security 访问所需的会话变量(USER/LOGNAME/__CF_USER_TEXT_ENCODING/TMPDIR/XPC_* 等,
均非密钥)也滤掉了;本机鉴权走 keychain(无 API_KEY/凭证文件) → 读不到。
② detached(setsid)另起会话也不利于沿用 daemon 鉴权上下文。
修:workerEnv 改黑名单(会话变量透传保 keychain,仅剥 *_SECRET/*_TOKEN/*_KEY/AWS_/CF_ 等密钥,
ANTHROPIC_/CLAUDE_ 始终留);spawn 不 detached(同会话,unref 后孤儿仍被 init 收养存活)。
实测:smoke 任务 worker 真建文件+提交、双复审 approve、到 exec_review。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 13:26:17 +08:00
wangjia 7d3946dc97 merge phase3: 多进程执行解耦(daemon 监工 + worker 进程 + 文件通讯 + 重启 re-adopt) 2026-06-13 13:13:34 +08:00
wangjia 70d996110d phase3(集成测试): 真 worker 进程 spawn → 重启 re-adopt 存活 worker → ingest;死亡→回收重试
用假 worker(走 outbox 协议、不烧 SDK token)验证 daemon↔worker 真进程 seam:
- 头条: spawn 真进程→等 started→换 Store 重连 reconcile(真判活)→re-adopt(任务仍 executing 不重跑)
  →finish 哨兵→ingest 到 exec_review(四字段 + reviewer/security/executor run 就位)
- 回收: 杀进程组 + 心跳调陈旧→reconcile 回收→failTaskAttempt 退避重入队

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 13:07:42 +08:00
wangjia adf88e82cd merge phase3-C: daemon 侧(监工 + ingest + 接线 + 测试) 2026-06-13 13:02:13 +08:00
wangjia b0ef60ab58 merge phase3-B: worker 侧(pipeline + worker + 测试) 2026-06-13 13:02:13 +08:00
wangjia da7c93105c phase3(daemon): 监工 tick(spawn worker)+ ingest(outbox→DB)+ reaper + reconcile 接真判活
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 13:00:50 +08:00
wangjia d8f8b5da1e phase3(worker): pipeline.ts 纯执行管线 + worker.ts 进程入口(不碰 DB,经 outbox 文件汇报)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 12:56:50 +08:00
wangjia 007dffac39 phase3(契约层): protocol.ts + 落盘状态 + store 失败策略/判活原语
多进程执行解耦的 Phase 0 共享契约(worker 与 daemon 都 import 它):
- executor/protocol.ts: JobSpec(daemon→worker 唯一输入) + OutboxRecord(worker→daemon) +
  文件 IO(job/outbox/heartbeat) + isWorkerAlive(心跳为主/boot 窗口 pid 兜底/防 pid 复用)
- schema+db+types+mappers: runs.worker_pid/last_seq、tasks.next_eligible_at(持久化退避)
- store: failTaskAttempt(失败/重试策略唯一落点) + setNextEligibleAt/setWorkerPid/setLastSeq +
  countExecuting + executingWithLatestExecutorRun + reconcileInterrupted(isAlive 注入,默认保守回收)

纯增量,140 测试全绿。worker.ts/pipeline.ts(worker 侧) 与 orchestrator/ingest/index(daemon 侧) 待接。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 12:51:09 +08:00
wangjia d49192344f merge: maestro/tsk_lDx6zd-EbA00 [指标统计:执行时长 / 成功率 / 额度消耗估算]
# Conflicts:
#	web/style.css
2026-06-13 12:01:18 +08:00
maestro d82e07902f merge: maestro/tsk_zacmwH3chZpG [tsk_zacmwH3chZpG] 2026-06-13 11:35:53 +08:00
maestro f70004af11 merge: maestro/tsk_O9q0_u78_NPo [tsk_O9q0_u78_NPo] 2026-06-13 11:35:20 +08:00
maestro 3ad4ca2cc0 merge: maestro/tsk_sjzC4B9ctg6W [tsk_sjzC4B9ctg6W] 2026-06-13 11:35:00 +08:00
maestro 6b64037216 merge: maestro/tsk_UQ7sNRM0Yi1L [tsk_UQ7sNRM0Yi1L] 2026-06-13 11:34:51 +08:00
wangjia 3696604e13 feat: 指标统计(执行时长/成功率/复审通过率/重试率/额度估算)tsk_lDx6zd-EbA00
从 runs/tasks/events 聚合健康度与成本指标,看板新增指标小面板。

- Store.metrics(projectId?):执行时长(avg/p50/p95,未结束与负时长不计)、
  executor 成功率、复审/安全 verdict 通过率、failed→queued 重试率 +
  needs_attention、按模型额度粗估(时长×档位权重,标注估算)
- src/model/metrics.ts:类型 + 纯函数(percentile/ratio/estimateCostUnits/emptyMetrics)
- API:GET /api/metrics?project=
- web:归档区上方指标面板(数字卡 + 按模型分布),失败/空数据静默隐藏
- test/metrics.test.ts:9 个用例(纯函数/空数据/时长/成功率/复审/重试/按模型/项目过滤)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 10:55:56 +08:00
wangjia 13572a5416 feat(complexity): 新增 AUTO·由模型判断 复杂度档位 (tsk_zacmwH3chZpG)
新建任务时除手选 hard/medium/easy 外,新增 AUTO 档:先以 medium 落库
占位,建任务后异步用 sonnet 起一次轻量分类调用回填三档结果并记录理由,
不阻塞建任务返回;模型不可用/解析失败一律兜底 medium,绝不报错。

- web 看板:复杂度 seg 增加第四档 AUTO(默认选中,cyan 样式),提交 complexity='auto'
- src/api/server.ts:POST tasks 接受 'auto' → medium 占位 + 异步 classify 回填(可注入 classify 测试)
- src/executor/classify.ts(新增):buildClassifyPrompt/parseClassification/classifyComplexity
  复用 cc.ts/models.ts,sonnet 省额度,无工具、限轮限时
- src/executor/models.ts:pickClassifierModel(复用 executor easy 档 + MAESTRO_MODEL_EASY 覆盖)
- src/store/store.ts:applyAutoComplexity 回填复杂度+重置状态+理由入产出字段+广播 task.updated
- test/classify.test.ts:解析映射/兜底、prompt、回填、建任务集成(13 例)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 10:46:37 +08:00
wangjia 0957a9049a feat(transcript): 归档详情内回放执行/复审转录 (tsk_O9q0_u78_NPo)
- API:新增 GET /api/runs/:id/transcript,读 run.transcriptRef 指向的
  jsonl,逐行解析成脱敏后的结构化消息数组。校验 runId 合法且关联任务/
  项目存在;路径只允许在 transcriptDir 下(防目录穿越)。
- 脱敏:只透传 assistant 文本 / tool_use(名+摘要参数) / tool_result(截断)
  / 结论 / 模型回退;命中 secret/token/env 等敏感键名的值剔除为 [已脱敏]。
- 看板 archiveModal:执行历史从"文件路径"换成可展开的消息流,按 type
  分类渲染(文本/工具调用/工具结果/结论/回退),长内容折叠,复用 mdToHtml。
  executor 与 reviewer/security run 并列可回放。
- Store:新增 getRun(runId)。
- 测试:transcript 解析(样例 jsonl/脱敏/截断/坏行容错/路径穿越)+ 端点
  inject(合法/未知 runId/无转录/越界路径)。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 10:42:57 +08:00
wangjia 60265656e2 feat: MCP/CLI 追平 Phase 2 后端能力(score/复审/合并/额度/归档)
任务 ID:tsk_sjzC4B9ctg6W

MCP(src/mcp/index.ts,重构为可测的 createTools(apiFn)):
- 读:新增 get_agents(自治/并发/调度/模型/在途)、get_usage(订阅额度)、
  list_archived(终态分页);get_task 补 score(自身分+链条惯性+解锁加权)
  与 review(summary/verdict/securitySummary/securityVerdict)显式字段。
- 写:新增 patch_task(复用 store.patchTask 校验)、patch_project、sync_project、
  decide(action + merge:通过并合并 / 仅通过;reject 必带 reason)。
- 复核全部工具 description 与状态机语义一致;entry-guard 便于 import 测试。

CLI(src/cli/index.ts)对齐子命令:
- project set / task patch / decide <id> accept|reject [--no-merge] /
  agents / usage / archive。两端均薄封装走 REST,不重复实现。

API(src/api/server.ts):新增 GET /api/usage 单独透传订阅额度。

测试:新增 test/mcp.test.ts(zod schema 边界 + 对 mock api 的 method/path/body
断言 + score/分页/错误透传),npm test 103 全过、typecheck/build 通过。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 10:35:34 +08:00
wangjia 72b174fd44 feat: 支持依赖(deps)创建后编辑 (tsk_UQ7sNRM0Yi1L)
deps 此前仅建任务时可设,本次让 PATCH /api/tasks/:id 受理 deps,
拆解后可随时调整任务依赖,无需删重建。

- API:PATCH /api/tasks/:id 受理 deps:string[](类型校验)
- Store.patchTask:写 deps 前复用建任务校验(存在/同项目/非自身)
  并加 DFS 环检测(拒绝 A→B→A);越权/缺失/成环 → StoreError(400)
- 仅允许在未进入执行链路的状态改 deps(与 complexity 同一组守卫)
- 写后调 reconcileDeps 重算:未满足 ready→blocked、刚补全 blocked→ready,
  广播 status.changed
- 看板:任务详情加依赖编辑器(多选当前项目其它任务,排除自身与会成环者),
  保存走 PATCH
- 测试:加/删 dep、已 done 依赖放行、环检测、跨项目/缺失拒绝、
  执行链路状态拒绝、status.changed 重算(test/patch.test.ts)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 10:33:39 +08:00
maestro 872354cf7c merge: maestro/tsk_nqvOyIZkd1Dn [tsk_nqvOyIZkd1Dn] 2026-06-13 10:26:42 +08:00
wangjia a00091329d merge: maestro/tsk_N5wO3Armums2 [重试与超时策略细化(可配 + 退避)]
# Conflicts:
#	src/api/server.ts
#	test/store.test.ts
2026-06-13 10:20:20 +08:00
wangjia d56b0641c5 merge: maestro/tsk_PbcHccuPmwxV [任务取消/删除的 UI 入口]
# Conflicts:
#	web/style.css
2026-06-13 10:16:48 +08:00
wangjia 3fc19e47c4 fix(web): 任务树/父任务下拉对异常 depth/id 加固,避免整页崩溃
renderParentOptions 的 '· '.repeat(depth-1) 在 depth=0 时抛 RangeError(Invalid count value)、
renderNode 的 t.id.slice(-6) 在 id 缺失时抛 TypeError——任一都会让看板整页崩。
改为 repeat(Math.max(0,(depth||1)-1)) 与 String(t.id||'').slice。
(node:vm + 最小 DOM harness 复现并验证)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 09:40:55 +08:00
wangjia 2c4140a1a2 feat(daemon): launchd plist + install/uninstall 脚本(tsk_nqvOyIZkd1Dn)
提供三个文件让 maestrod 作为 macOS User Agent 开机自启、崩溃自拉:

- scripts/com.maestro.maestrod.plist  — launchd plist 模板
    KeepAlive=true(崩溃自拉)、RunAtLoad=true(登录即启)
    stdout+stderr 统一写入 ~/.maestro/maestrod.log
    ThrottleInterval=10s 防崩溃风暴;ProcessType=Background
    占位符:__NODE__ / __PROJ_DIR__ / __HOME__ / __PATH__

- scripts/install-daemon.sh  — 安装脚本
    1. 检测 node(>= 20)
    2. npm run build 构建项目
    3. sed 替换占位符,生成真实 plist 并用 plutil 校验
    4. launchctl bootstrap gui/$UID(回退 load -w)加载服务

- scripts/uninstall-daemon.sh  — 卸载脚本
    launchctl bootout / unload -w 卸载,删除 plist

shellcheck 通过(两个脚本);现有 77 个单元测试全部通过。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 09:24:04 +08:00
maestro ac0d5b7b77 merge: maestro/tsk_ExRzLoBj12Fr [tsk_ExRzLoBj12Fr] 2026-06-13 09:22:35 +08:00
wangjia fcca3f95e0 fix(executor): node_modules 软链写入仓库本地 exclude,杜绝被提交进历史
上一版软链修复有回归:.gitignore 的 `node_modules/`(带斜杠)只匹配目录不匹配软链,
导致 agent 的 `git add -A` 把 `node_modules -> /abs/path` 软链提交进分支,泄露本机绝对路径
(code review + 安全审计已正确 reject)。改为建软链前先把 node_modules 写进共享
<repo>/.git/info/exclude(git 的 info/exclude 取 common dir,worktree 也读它;untracked、幂等、
不动 tracked 的 .gitignore)。测试加回归断言:git add -A 后软链不出现在 status。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 09:18:18 +08:00
wangjia 217eb6aa1f feat(merge): 自动合并失败时建最高优先级补救任务来完成合并
decide 端 exec_review accept→merge 冲突失败时,不再只是报错留在闸:
自动建一个 P0 easy 补救任务(operations 写明分支/目标/冲突详情与解冲突步骤),
自治项目会自动领取去解决。幂等:补救任务 id 记到原任务 result.mergeTaskId,
已有未结束补救任务则复用不重复建;结束(done/cancelled)后允许新建。

- model/types: TaskResult 加 mergeTaskId 字段
- mappers/orchestrator: 同步透传/补 null
- store.ensureMergeRemediationTask + store.test 覆盖(P0/easy/ready/operations/幂等/可重建)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 09:13:30 +08:00