Skip to content

feat(hooks): run Evolver from Cursor hooks, with nothing in the model context but the recalled steps (2.2.0) - #10

Merged
forrestlinfeng merged 7 commits into
mainfrom
feat/hook-only-context
Oct 26, 2026
Merged

forrestlinfeng merged 7 commits into
mainfrom
feat/hook-only-context

Conversation

@forrestlinfeng

@forrestlinfeng forrestlinfeng commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

Touches hot-path: yes — security-sensitive model/tool execution (hooks spawn a headless model run and the evolver CLI)
Phase: feature
Risk vector: forward

Summary

Ports the Cursor plugin to the hook-only design of dsh-evolver 0.3.0 (EvoMap/evolver-dsh-plugin#51, #52, check/correction readers from #53), matching the Claude Code (EvoMap/evolver-claude-code-mods#8), WorkBuddy (EvoMap/evolver-workbuddy-plugin#10) and Codex (EvoMap/evolver-codex-plugin#10) ports. Version 2.1.0 → 2.2.0 in plugin.json, marketplace.json (both fields) and the new package.json.

What changed:

  • Nothing of Evolver in the model's context but the recalled steps. Removed the evolver-proxy MCP server (9 tools), the evolver skill, rules/evolution-memory.mdc, the 8 tool-calling commands, the sessionStart memory-graph summary and claim nudge, the afterFileEdit [Evolution Signal] notice, and the Configure variables (they only fed the MCP server).
  • Per-prompt recall. beforeSubmitPrompt calls POST /asset/fetch {text} and returns the best strategy as additional_context, ending exactly Apply them where they fit.
  • Turn record and turn-end reports. preToolUse (Write/Delete before-hashes), postToolUse/postToolUseFailure (commands, checks, paths), afterFileEdit (written text), afterAgentResponse (answer); stop reports every injected strategy through the Proxy's /asset/reuse-result with graded evidence, task id cursor:<conversation>:<turn>.
  • Follow-ups. Aborted (chat closed mid-turn, or the owner process gone → next session start), correction/praise (:correction), retention (:retention), all through the outbox with retries.
  • Distillation. Candidate + session-end distillation in a detached worker through the Cursor agent CLI, platform: 'cursor', trigger: 'session_end'; leftovers claimed at the next session start; 3 attempts.
  • Commands run in the plugin (see host adaptations).
  • State files are all cursor--prefixed and written under the shared state lock; the turn counter survives session end (TTL-pruned).
  • Deleted: the git-diff outcome written to the local memory graph and the direct Hub POST /a2a/evolution/record (dsh keeps no equivalent); the hooks no longer run git at all.

Follow-up commits on this branch:

  • dsh #55 sync (b783935, 2ffa856): every reuse report says applied: used; a verified turn that reused a strategy is distilled too; the applied verdict and edited-text buffer are gone.
  • Tokens saved (bb87a17, e724b2d): /evolver-status opens with what reused strategies saved in this chat and in all chats (savingsCore reference-reuse estimate, only after a passing check, capped at the turn's own stop token counts), then lists this chat's reuses (turn, asset name and id, last check, saving). Cursor hooks have no user-only message, so it is shown on demand by the plugin-run command; a desktop notification and a stop follow-up were rejected.
  • 3-day state TTL (f5b3ef9): reports, injections, retention checks, chat files, per-chat savings and distillation candidates all expire after 3 days (one STATE_TTL_MS); stuck candidates included. README: Cursor 3.27 loads plugin hooks only while Include Third-Party Plugins, Skills, and Other Configs is on (loadPluginHooks returns early otherwise).
  • Sentinel advisories (52d04cc): a late sessionEnd no longer cleans up a turn a new prompt opened; hooks record only under their own generation_id; a distillation claim counts only once on disk and candidates are matched by turn as well as time; engine setup no longer delays delivery/distillation; Stripe-style keys redacted; Windows %APPDATA%\npm global root searched. Left as designed, with reasons: the unguarded update after a 2 s lock wait (spec item 9), the long beforeSubmitPrompt timeout for the 10-minute CLI commands, and dsh's correction reader.

Libraries are the reviewed Codex port's (evolver-codex-plugin @ 8ffb016), renamed to cursor-; Cursor-specific code is lib/hook-io, turn-record, verification (exit-code reader), cursor-agent, process-owner, project-dir, commands (typed-command parser), plugin-commands, recording-hook, session-state (settling) and turn-end (endOpenTurn), plus the hooks.

Host adaptations, with evidence

All "source" citations are the local Cursor 3.27.6 bundle (WB = out/vs/workbench/workbench.desktop.main.js, EXH = out/vs/workbench/api/node/extensionHostProcess.js, AX = extensions/cursor-agent-exec/dist/main.js); the full table is in the shared host-facts note used for the planned monorepo.

Adaptation Evidence Status
Recall rides beforeSubmitPrompt.additional_context, sent as a <system_reminder> with that same request WB Mr=ny?.additional_context … hookEvent:"beforeSubmitPrompt"; AX beforeSubmitPrompt response additionalContext. Not in Cursor's hook docs (docs list only continue/user_message) Verified in source; undocumented
Inline edits (Cmd-K) skipped: they send no composer_mode and ignore added context WB executeBeforeSubmitPromptHook payload has no composer_mode and reads only continue Verified in source
`/evolver-status search distill
Turn end from stop.status (completed/aborted/error) WB call sites `triggerStopHook(…,"completed" "aborted"
Answer from afterAgentResponse (stop carries none) WB triggerWakeupTurnEndHooks awaits it before stop, completed turns only Verified in source
Checks: Shell postToolUse.tool_output = {"output","exitCode"} — non-zero exit fails, else output is read; postToolUseFailure error/timeout fails, interrupt or Unknown error (backgrounded) = no verdict, permission_denied = not run AX jD/WD createSuccessOutput, getErrorMessage, isInterrupt Verified in source
Edit text from afterFileEdit new_string, before-hashes from preToolUse `Write Delete` AX KD ({file_path, content}), docs hooks "afterFileEdit"
stop is not awaited before the next prompt (a prompt typed mid-turn aborts it first), so the prompt waits ≤3 s for the turn to settle (closed+settling state); a turn with no stop is closed as error WB ER=!0,this.triggerStopHook(…) without await Verified in source
sessionEnd only writes state, waits ≤2 s for a settling stop, ends a running turn as aborted, starts the detached worker Docs: fire-and-forget; WB reasons only user_close/window_close, awaited at window shutdown Verified (docs + source)
Distillation: cursor-agent -p --output-format json --mode ask --trust --workspace <empty tmp> [--model m] <prompt>; no --force so nothing is applied; prompt as argument; no distill_usage Docs cli/reference/parameters, cli/headless, cli/reference/output-format ({type,result,is_error…}, no usage) Flags from docs; not run (no CLI installed here)
Headless self-hook guard: EVOLVER_HEADLESS=1 in the worker's env makes every hook a no-op No CLI flag/env disables hooks for one run (docs + bundle search); CLI runs plugin hooks (CLI changelog) Guard tested with a fake CLI; real CLI env inheritance unverified
Owner = nearest ancestor whose executable path matches /cursor/i (ps; /proc/<pid>/exe on Linux) EXH $executeHookDirect spawns hooks from the extension host Spawner verified; process tree unverified on Linux/CLI
hooks.json has "version": 1 and only known event names (one unknown name rejects the whole file) WB validator Unknown hook type: …; plugin loader runs the same check Verified in source; tested
Windows distillation only with cursor-agent.exe/agent.exe (no shell); .cmd shims skipped cmd.exe 8191-char line vs ~21k-char prompt Inference; stated in README

Scope and cuts

Outcome: a Cursor user with the plugin gets one recalled strategy behind each prompt and nothing else of Evolver in the model's context; every reuse is reported with graded evidence at turn end (plus aborted, correction and retention follow-ups); the chat's latest verified turn is distilled into a Gene when the chat closes; /evolver-* commands run in the plugin.

Not cut, but not verified end to end (decided by the reviewer / requester):

  • Live run in Cursor 3.27.14 (hooks registered as user hooks with the third-party setting off): beforeSubmitPrompt returned a 10-step Xiaohongshu strategy, the Hooks log shows it merged into the request, and the model followed it; postToolUse recorded the turn. Seen there too: sessionEnd at window reload failed inside Cursor (MainThreadShellExec not initialized), which the next session start's leftover claim covers.
  • Not run with the real cursor-agent (not installed here): distillation is exercised with a fake CLI only.
  • Streaming Shell executor + backgrounded command: reported as exit 0 with partial output and nothing in the payload to tell it apart, so the output alone decides there. Stated in README.
  • Windows distillation needs an .exe CLI (above).

Module boundary

Plugin-only: hooks/, lib/, scripts/background-worker.mjs, commands/, manifests, README/CHANGELOG, tests and the CI test glob (test/*.test.mjs). Talks only to the local Proxy (/asset/fetch, /asset/search, /asset/reuse-result, /conversation/distill, /proxy/status), the evolver CLI and cursor-agent. State under ~/.evolver/state/cursor-*.

Alternative considered

  • sessionStart.additional_context for recall (documented): rejected — it fires once per chat, not per prompt.
  • Markdown commands telling the model to run a script: rejected — puts Evolver into the context and goes through the model; the hook answer keeps it out.
  • Stdin for the headless prompt: not documented for cursor-agent; the documented positional argument is used.

Validation

  • npm test (node --test test/*.test.mjs): 138 pass on the final head. Covers recall text, turn-end reasons (completed/aborted/error), aborted reports (chat closed mid-turn, killed owner), candidate create/skip/replace/drop and ordering (including concurrent stop + correction), leftover claim and other-host isolation, distillation via a fake cursor-agent (args, platform: 'cursor', default model), headless self-hook guard, turn counter across a reopened chat, plugin commands, inline-edit skip, manifest/hooks.json validity.
  • Independent line-by-line review against dsh and the spec: first pass NOT ALIGNED (stop/next-prompt race, backgrounded checks, Windows CLI, default model, dead code, evolve text, late stop after sessionEnd, command errors, Linux owner) — all fixed; second pass ALIGNED.

Rollback / recovery

git revert this commit restores 2.1.0 (MCP server, skill, rule, old hooks). State written by this version lives only in ~/.evolver/state/cursor-* and is ignored by 2.1.0; deleting those files is safe. No schema or Hub contract changes.

🤖 Generated with Claude Code

… context but the recalled steps (2.2.0)

Aligns the Cursor plugin with dsh-evolver 0.3.0 (#51/#52, check readers from #53):

- beforeSubmitPrompt recalls one strategy by the prompt text and adds it as
  additional_context, ending with "Apply them where they fit."; inline edits
  (no composer_mode) are left alone.
- Tool, edit and response hooks record the turn per generation; stop reports
  every injected strategy with the turn's evidence and its own end status;
  aborted, correction and retention follow-ups go through the Proxy outbox.
- A verified turn becomes the chat's candidate, dropped by a correction, and
  is distilled at session end in a detached worker through cursor-agent,
  headless (-p --output-format json --mode ask, empty workspace), with an env
  marker that turns this plugin's own hooks off inside that run.
- /evolver-* commands are answered by the beforeSubmitPrompt hook itself
  (continue:false), before any model sees them; /evolver-evolve stays the dsh
  prompt.
- Removes the MCP server, skill, rule, Configure variables, the session-start
  memory summary, the [Evolution Signal] notice and the git-diff outcome
  posted to /a2a/evolution/record.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@evomap-aiqa-bot

evomap-aiqa-bot Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

Sentinel 已审核此变更,并发现 1 个已核验问题。

另有 35 个需要人工确认的风险;黄色 advisory 不阻塞合并,建议开发 agent review advisory 评论并逐条确认。

开发 agent 查询详情: 调用 MCP 工具 sentinel_pr_review_context,传入 owner_repo="evomap/evolver-cursor-plugin"、pr_number=10、head_sha="db810724beb0cf5d4ef58a9e0ec7050679796025",并按条目追加 finding_id 或 finding_key。

由 Sentinel 审核 · 目标提交 db810724beb0

@evomap-aiqa-bot

Copy link
Copy Markdown

Sentinel 保留了 35 个尚未确认的审核候选。这些黄色条目不阻塞合并;红色 P0/P1 与其他独立硬门禁不受影响。 单一猜测、缺少变更行证据或纯 checklist 的候选会统一降为 P3。
开发 agent:请 review 以下 advisory,并逐条给出“已验证无风险 / 已修复 / 转为后续事项”的结论;不要只做整体确认。

  • [P2] 状态落盘失败被吞掉,claim 调用仍会报告领取成功 — writeState() 捕获并忽略所有写入异常,updateState() 随后仍返回计算出的 next。claimWhere() �...(truncated) · lib/state-file.mjs · advisory_34bd3c07d65c96c80b666b7a
  • [P1] 会话结束与下一条提示并发时可能删除新会话状态 — session-end 先通过 settledSession(sessionId, STOP_WAIT_MS) 获取会话快照,随后执行 endOpenTurn、clo...(truncated) · hooks/session-end.mjs·advisory_c52243771d51b3cd3414c2e6`
  • [P2] 耗时的引擎安装阻塞其他后台任务 — worker 对引擎安装执行 await,安装完成后才开始 drainOutbox 和 distillLeftovers。代码注释明��...(truncated) · scripts/background-worker.mjs · advisory_9c9c7fae573a4ee94c998a4d
  • [P3] Cursor Agent 取消路径无法可靠清理已启动的进程树 — runCli 的取消处理只执行 child.kill('SIGTERM'),随后只对同一个根进程执行 child.kill('SIGKILL')...(truncated) · lib/cursor-agent.mjs · advisory_91b65695c5bfb871293e2749
  • [P3] Stripe API 密钥格式未被脱敏并会发送到 EvoMap 代理 — 新正则只识别 sk-、pk-、rk-,但 Stripe 的实际格式使用下划线,如 sk_live_...、sk_test_......(truncated) · lib/redact.mjs · advisory_7c80483c146e012c93074bf1
  • [P3] 四个公开 Slash Command 被重命名后未保留兼容入口 — PR 删除了四个原有命令定义,同时 README 将入口改为 /evolver-status、/evolver-search、/evolver-d...(truncated) · commands/status.md·advisory_83334eb1dc4c63114d8e9a3d`
  • [P3] 存活任务超过 60 秒会被重复领取 — “过期”仅由文件修改时间判定,未检查 .taking 文件名中记录的领取进程是否仍存活。第�...(truncated) · lib/state-file.mjs · advisory_0f6c48f511bc3e29a4e8537c
  • [P3] 召回服务异常可阻断普通提示词提交 — recalledStrategy 对网络/代理召回 hubGene(...) 直接 await,未捕获异常;而同文件的 commandAnsw...(truncated) · hooks/user-prompt-submit.mjs·advisory_edc7c6c8941c4f580bebdec8`
  • [P3] 未知结束原因仍会关闭并结算当前 turn — endOpenTurn() 先执行 closeOpenTurn();随后 closeTurn() 先取走 turn record,才检查 outcomeOfReason(re...(truncated) · lib/turn-end.mjs·advisory_b8c9e1cc2155e8876604d37c`
  • [P3] 未约束的 requestPath 可改写目标主机并携带 Proxy Token — 请求 URL 通过 base + requestPath 拼接。默认 base 为 http://127.0.0.1:19820 时,requestPath="@attacker...(truncated) · lib/proxy.mjs·advisory_c2552fd644d8fd0c90fa7422`
  • [P3] 结束回合先消费状态,后续写入失败时无法重试 — endOpenTurn 首先关闭开放回合,随后 closeTurn 又通过 takeTurnRecord 和 takeUnreported 消费记录...(truncated) · lib/turn-end.mjs · advisory_494988b7b9b04971576e33cd
  • [P3] 会话结束后仍可写回已清理会话的异步召回结果 — recalledStrategy 在 await hubGene(...) 返回后直接调用 rememberInjected(sessionId, ...),没有重新验��...(truncated) · hooks/user-prompt-submit.mjs · advisory_96f3795e7f07c4d9cc5e1490
  • [P3] 删除 Cursor 会话钩子后,启动记忆与结束记录功能完全失效 — PR 删除了 hooks/session-start.js 和 hooks/session-end.js 的全部实现。任何仍引用这些路径的 Cursor...(truncated) · hooks/session-start.js · advisory_68bf03812b100b7b3669b853
  • [P3] 删除 /solidify 命令导致升级后旧入口失效 — 当前 PR 完整删除了命令定义,且变更中没有兼容别名、迁移入口或版本门控。旧版本可识��...(truncated) · commands/solidify.md · advisory_ba4a1d8eae6ad983d476fd52
  • [P3] 撤销检查与远端持久化之间存在 stale completion 窗口 — distillCandidate() 只在发起 proxyFetch() 前检查一次 isCurrent()。候选若在检查通过后、POST 提�...(truncated) · lib/session-distill.mjs · advisory_b48864fd36b999d7c0133cea
  • [P3] 移除 /evolve 会使已有命令入口失效 — PR 删除了定义 /evolve 的 commands/evolve.md,但新增命令文件名为 commands/evolver-evolve.md,其��...(truncated) · commands/evolve.md · advisory_ff56f501acf6b31dd8315340
  • [P3] 否定性回答会被误判为已执行策略 — stepWasFollowed 会在 answer 中直接搜索策略的具体特征或词项,不区分肯定、否定或仅引用��...(truncated) · lib/applied.mjs · advisory_2650a3b840c87d8ead6246bd
  • [P3] 安装和启动失败信息绕过现有密钥脱敏 — setupErrorOutcome 明确使用 withoutSecrets,但正常控制流中的 installError、install_failed.error 和...(truncated) · lib/engine-setup.mjs · advisory_c6e93e077046520544190163
  • [P3] 成功状态写入失败会用旧快照执行覆盖式错误回写 — try 同时包裹准备操作和成功状态写入,所以写入自身的异常也进入 catch。此时代码基于�...(truncated) · lib/engine-job.mjs · advisory_03f946c901b38f2d173167c0
  • [P3] Windows 全局安装回退路径与 npm 实际目录不匹配 — Windows 分支将全局 Evolver 固定解析为 dirname(process.execPath)\node_modules\@evomap\evolver。标准 Window...(truncated) · lib/local-ledger.mjs · advisory_d31f0ab5e54fba160bb2818c

另有 15 条候选未在评论中展开;可通过下方 Sentinel PR review context 查询全部条目。

开发 agent 查询详情: 调用 MCP 工具 sentinel_pr_review_context,传入 owner_repo="evomap/evolver-cursor-plugin"、pr_number=10、head_sha="db810724beb0cf5d4ef58a9e0ec7050679796025",并按条目追加 finding_id 或 finding_key。

由 Sentinel 审核 · 目标提交 db810724beb0

Comment thread lib/state-file.mjs
} finally {
if (token) release(lockPath, token);
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

锁等待超时后无锁写入会覆盖并发状态更新

🔴 严重程度:高(P1)
acquire() 在超时时返回 null,但 updateState() 仍继续执行“读旧状态 -> mutate -> 写回”流程,失去互斥保护。两个并发写入可基于同一旧快照写回不同结果,后写者覆盖前写者。

Finding:finding_43abb78af593ad0b14931fcf

…ed one

Port of EvoMap/evolver-dsh-plugin#55. Every reuse report (turn end,
correction, retention, aborted) now says `applied: used`: the model follows
what is injected into its turn, and whether the strategy helped is left to
the outcome (last check, or how the turn ended), the next prompt and kept
edits. `tier` is L1 whenever a check ran, and the reason no longer names a
verdict.

A turn that reused an injected strategy is a distillation candidate like any
verified turn; the engine's Gene intake drops a repeat of a Gene it has.
applied.mjs and the edited-text capture existed only for the verdict and are
removed; a turn records the files it edited (afterFileEdit writes, Delete).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@evomap-aiqa-bot

evomap-aiqa-bot Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

Sentinel 正在审核此变更,尚未形成最终结论。

大 PR 拆片审核中

  • Sentinel 判断这个 PR 规模较大,已经拆成多个 slice 分别审核,所以会比普通 PR 花更久。
  • 当前 check 会保持进行中;这不是绿色通过,也不是红色阻塞。
  • Sentinel 会继续完成 slice review、Cross-Slice Verifier 和聚合;如果后续发现红区问题,会更新本 head 的审核结论。
  • 规模等级: oversize
  • Slice 数量: 26

开发 agent 查询详情: 调用 MCP 工具 sentinel_pr_review_context,传入 owner_repo="evomap/evolver-cursor-plugin"、pr_number=10、head_sha="b783935d765bc7ca5f6b5dc38f633da4886fe37d",并按条目追加 finding_id 或 finding_key。

由 Sentinel 审核 · 目标提交 b783935d765b

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@evomap-aiqa-bot

evomap-aiqa-bot Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

Sentinel 已审核此变更,并发现 2 个已核验问题。

另有 42 个需要人工确认的风险;黄色 advisory 不阻塞合并,建议开发 agent review advisory 评论并逐条确认。

开发 agent 查询详情: 调用 MCP 工具 sentinel_pr_review_context,传入 owner_repo="evomap/evolver-cursor-plugin"、pr_number=10、head_sha="2ffa85698c6726ab089ec5c2c047e76f5d8314e1",并按条目追加 finding_id 或 finding_key。

由 Sentinel 审核 · 目标提交 2ffa85698c67

@evomap-aiqa-bot

Copy link
Copy Markdown

Sentinel 保留了 42 个尚未确认的审核候选。这些黄色条目不阻塞合并;红色 P0/P1 与其他独立硬门禁不受影响。 单一猜测、缺少变更行证据或纯 checklist 的候选会统一降为 P3。
开发 agent:请 review 以下 advisory,并逐条给出“已验证无风险 / 已修复 / 转为后续事项”的结论;不要只做整体确认。

  • [P2] 缺少 generation_id 的旧事件会被归入当前 turn — isOpenTurn() 将缺失 turnId 视为匹配任意开放 turn。会话已经打开新 turn 后,来自旧 turn 且不...(truncated) · lib/session-state.mjs · advisory_c064f8151c8bb26addd5d013
  • [P1] 迟到的 sessionEnd 可能清除同 sessionId 下的新 turn — session-end 在取得 settledSession() 快照后,无条件执行 closeCandidate()、endSession() 和 forgetSe...(truncated) · hooks/session-end.mjs·advisory_9db45ace8f349a1be6b59f28`
  • [P2] 耗时的引擎安装阻塞报告投递与蒸馏 — worker 按顺序 await setUpEngine()、drainOutbox()、distillLeftovers()。代码已注明引擎安装需要数��...(truncated) · scripts/background-worker.mjs · advisory_432d50674c26af48f3cecd3d
  • [P2] 英文反问会被不可逆地标为纠错 — 英文纠错正则匹配 that's wrong,但不像中文 不行、不对 分支那样排除问号结尾的意见征...(truncated) · lib/dissatisfaction.mjs · advisory_59ca60c09118929042abeadc
  • [P2] 落盘失败仍会向 claim 调用方报告领取成功 — writeState() 吞掉所有写入异常,updateState() 仍返回计算出的 next。claimWhere() 又在 mutator �...(truncated) · lib/state-file.mjs · advisory_48829e0c5c3c8bcae6fc82fb
  • [P2] 全局安装的 Evolver 在 Windows 和自定义 npm prefix 下无法被发现 — 全局包路径仅按 process.execPath 推导。Windows 上 Node 通常位于 C:\Program Files\nodejs,npm 全局��...(truncated) · lib/local-ledger.mjs · advisory_1ec3775b538c0e2cfd0ec9d3
  • [P2] 召回请求可在会话结束后重新写入已清理状态 — recalledStrategy 在异步 hubGene 完成后无条件调用 rememberInjected(sessionId, ...)。并发的 session-...(truncated) · hooks/user-prompt-submit.mjs·advisory_c36e45768d9b1e66c31b99f0`
  • [P2] 提交提示词的同步 Hook 最长可阻塞 11 分钟 — PR 新增的提交前 Hook 将超时设置为 660 秒。该入口位于提示提交的同步关键路径;只要脚��...(truncated) · hooks/hooks.json · advisory_82116c1eedc483022faf9d04
  • [P3] Stripe 下划线格式密钥未被识别 — 专用模式只接受 sk-、pk-、rk-,不接受 Stripe 使用的 sk_live_、sk_test_ 或 rk_live_ 前缀��...(truncated) · lib/redact.mjs · advisory_1fcea1ee2771ebe4ccf234a7
  • [P3] 已中止的蒸馏仍会启动 Cursor Agent — runCli 只订阅未来的 abort 事件,未在启动子进程前检查 signal.aborted。若候选已被替换、�...(truncated) · lib/cursor-agent.mjs · advisory_6578f20fa29240eb17611d50
  • [P3] 英文疑问句会被不可逆地标记为纠正反馈 — 英文纠正关键词没有排除疑问句;包含 wrong answer、this is wrong 等短语的提问会直接返回 ...(truncated) · lib/dissatisfaction.mjs·advisory_97e0e799764381040b3b9778`
  • [P3] Delete 使用 path 时不会记录删除前快照 — PATH_KEYS 明确支持 path 和 file_path,但 editedPathOf() 只读取 input.file_path。如果 Cursor 的 ...(truncated) · ``lib/turn-record.mjs`` · advisory_759a313a07933d18c13f0fe7`
  • [P3] 删除命令定义后,README 宣称的 /evolver-* 命令菜单可能不再可用 — 本 PR 删除了 commands/distill.md、commands/run.md、commands/search.md 和 commands/status.md,但没有��...(truncated) · commands/distill.md · advisory_fdfba7d7257b1b2848681f4f
  • [P3] 旧 Slash Command 在次版本升级中被直接移除 — PR 删除了四个已发布命令的注册文件,只为新名称 /evolver-status、/evolver-search、/evolver-run...(truncated) · commands/status.md·advisory_b84a2be770693646826a2d31`
  • [P3] 旧候选通过校验后仍可在异步提交窗口被持久化 — 当前性校验发生在异步 POST 之前;候选在校验通过后被替换或删除时,旧候选仍会发送到 /...(truncated) · lib/session-distill.mjs·advisory_731c08e2ead5169eba947e7a`
  • [P3] 次版本升级直接移除 MCP、Skill、Rule 与配置接口 — PR 将版本从 2.1.0 升为 2.2.0,但同时从清单删除 mcpServers、skills、rules 和整个 variables...(truncated) · ``.cursor-plugin/plugin.json`` · advisory_a6d0e61be22177fa6986fd69`
  • [P3] 正常 turn 报告在入队前已标记完成,进程中断会永久丢失报告 — takeUnreported() 在返回待上报记录前,已经通过 withReported() 持久化 reportedAt。领取状态和�...(truncated) · lib/injected-assets.mjs · advisory_1910ce500c0fb2d357a458dc
  • [P3] 移除 /evolve 命令会使既有调用失效 — PR 删除了以 evolve.md 命名并显式声明 name: evolve 的命令,却只新增了文件名不同的 evolver-...(truncated) · commands/evolve.md·advisory_56d12ae9f8b94ef70c0d8758`
  • [P3] 缺失 generation_id 的迟到事件会作用于当前新回合 — generationIdOf() 对缺失 ID 返回 null,而 isOpenTurn() 将任何 falsy turnId 当成通配符。于是无�...(truncated) · lib/session-state.mjs · advisory_4b39e3c8e406bf1d17bf2860
  • [P3] 远端策略被直接作为 Agent 指令注入上下文 — /asset/fetch 返回的远端 strategy 只经过类型、长度、步数和相似度过滤,随后原样放入 [Evo...(truncated) · lib/prime.mjs·advisory_7978dc9c6ac44254c9f4b45a`

另有 22 条候选未在评论中展开;可通过下方 Sentinel PR review context 查询全部条目。

开发 agent 查询详情: 调用 MCP 工具 sentinel_pr_review_context,传入 owner_repo="evomap/evolver-cursor-plugin"、pr_number=10、head_sha="2ffa85698c6726ab089ec5c2c047e76f5d8314e1",并按条目追加 finding_id 或 finding_key。

由 Sentinel 审核 · 目标提交 2ffa85698c67

Comment thread lib/session-distill.mjs Resolved
Comment thread lib/state-file.mjs
*/
export function updateState(target, fallback, mutate) {
const lockPath = `${target}.lock`;
const token = acquire(lockPath, Date.now() + LOCK_WAIT_MS);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

锁等待超时后无锁读改写会覆盖并发状态

🟠 严重程度:中(P2)
获取锁超过两秒后,acquire() 返回 null,但 updateState() 仍执行读、变更和写入;两个并发调用可基于不同的旧快照覆盖彼此更新。

Finding:finding_89d4e570135304d7609d18d6

…saved

A turn that reused an injected strategy and whose last check passed adds
its saving to the chat's and to the running total in
~/.evolver/state/cursor-savings.json (chats unseen for 8 days drop out of
the per-chat map, not out of the total). The saving is savingsCore's
reference-reuse estimate, as the Claude Code and Codex plugins show it,
from the lines the turn's edits changed, capped at the turn's own tokens
from stop (input + output + cache writes). Cursor hooks have no message
for the person only, so the figures are shown by /evolver-status, which
the plugin answers without the model.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@evomap-aiqa-bot

evomap-aiqa-bot Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

Sentinel 正在审核此变更,尚未形成最终结论。

大 PR 拆片审核中

  • Sentinel 判断这个 PR 规模较大,已经拆成多个 slice 分别审核,所以会比普通 PR 花更久。
  • 当前 check 会保持进行中;这不是绿色通过,也不是红色阻塞。
  • Sentinel 会继续完成 slice review、Cross-Slice Verifier 和聚合;如果后续发现红区问题,会更新本 head 的审核结论。
  • 规模等级: oversize
  • Slice 数量: 26

开发 agent 查询详情: 调用 MCP 工具 sentinel_pr_review_context,传入 owner_repo="evomap/evolver-cursor-plugin"、pr_number=10、head_sha="bb87a17eb968a575907fd66d78f00456c09ceed0",并按条目追加 finding_id 或 finding_key。

由 Sentinel 审核 · 目标提交 bb87a17eb968

…s included

Undelivered reports, unreported injections, retention checks, chat files and
per-chat savings now live 3 days instead of 7-8 (one STATE_TTL_MS), and the
background worker drops distillation candidates older than that whoever owns
them, so a chat that never closes on a host without a process table no longer
keeps its candidate for good.

README: Cursor 3.27 loads plugin hooks only while "Include Third-Party Plugins,
Skills, and Other Configs" is on; with it off none of this plugin's hooks run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@evomap-aiqa-bot

evomap-aiqa-bot Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

Sentinel 已审核此变更,未发现已核验问题,但发现需要人工确认的风险。

另有 42 个需要人工确认的风险;黄色 advisory 不阻塞合并,建议开发 agent review advisory 评论并逐条确认。

开发 agent 查询详情: 调用 MCP 工具 sentinel_pr_review_context,传入 owner_repo="evomap/evolver-cursor-plugin"、pr_number=10、head_sha="f5b3ef9c02ad38910412c7d0606d438be6e68dfc",并按条目追加 finding_id 或 finding_key。

由 Sentinel 审核 · 目标提交 f5b3ef9c02ad

@evomap-aiqa-bot

Copy link
Copy Markdown

Sentinel 保留了 42 个尚未确认的审核候选。这些黄色条目不阻塞合并;红色 P0/P1 与其他独立硬门禁不受影响。 单一猜测、缺少变更行证据或纯 checklist 的候选会统一降为 P3。
开发 agent:请 review 以下 advisory,并逐条给出“已验证无风险 / 已修复 / 转为后续事项”的结论;不要只做整体确认。

  • [P1] 迟到的 sessionEnd 可删除同一 sessionId 下刚打开的新 turn — session-end 在获取会话快照后,无条件调用 closeCandidate()、endSession() 和 forgetSession()。这...(truncated) · hooks/session-end.mjs · advisory_b4f0a910f168923ef5b4c2ff
  • [P2] Stripe 下划线格式密钥未被脱敏 — Stripe 生产/测试密钥采用 sk_live_...、sk_test_... 等下划线分隔格式;新增规则只匹配以 sk-...(truncated) · lib/redact.mjs · advisory_2d776068d34f760ec3c45184
  • [P2] 候选领取可能在未持锁或未落盘时返回成功 — updateState() 获取锁失败后仍会无锁执行读改写;同时 writeState() 吞掉全部写入异常。claimW...(truncated) · lib/state-file.mjs·advisory_53d9a25253bd4565870e5c3f`
  • [P2] 缺少 generation_id 的旧 hook 会被归入当前 turn — isOpenTurn() 把缺失的 turnId 视为匹配任意开放 turn。若旧 turn 的延迟事件没有 generation_id��...(truncated) · lib/session-state.mjs · advisory_98fbe55604422e70208594db
  • [P2] 耗时的引擎安装会阻塞报告投递与蒸馏 — worker 在开始 drainOutbox() 和 distillLeftovers() 前同步等待 setUpEngine()。引擎安装已被代码注�...(truncated) · scripts/background-worker.mjs · advisory_0e67db805366c3b7ef18da9e
  • [P2] 锁等待超时后继续无锁更新,可能覆盖并发状态 — acquire() 等待 2 秒后返回 null,但 updateState() 仍执行完整的读取、修改和写入。此时原锁...(truncated) · lib/state-file.mjs · advisory_3147bdf028ba376979182231
  • [P2] Windows 无法使用全局安装的 Evolver Core 回退 — Windows 分支固定从 dirname(process.execPath)/node_modules/... 查找全局包;Windows 默认 npm 全局根目��...(truncated) · lib/local-ledger.mjs · advisory_f5301d58cbd70c455d299f2a
  • [P3] 蒸馏取消无法可靠终止 Cursor Agent 进程树 — runCli 只对直接启动的 cursor-agent 调用 child.kill(),没有建立 POSIX 独立进程组,也没有在 ...(truncated) · lib/cursor-agent.mjs · advisory_07ef8944a50a06d5da62900d
  • [P2] 缺失 turnId 的事件会混入同一会话的其他 turn — recordPath() 将缺失的 turnId 固定转换为空字符串。同一 sessionId 下所有未携带 turn ID 的事�...(truncated) · lib/turn-record.mjs · advisory_315ffb42a6be363de420b973
  • [P3] 破坏性插件接口删除仅提升次版本号 — PR 将版本从 2.1.0 提升到 2.2.0,同时从插件清单和命令目录删除公开入口。依赖这些入口�...(truncated) · .cursor-plugin/plugin.json · advisory_9d4c5dfe43ab27567ad2427e
  • [P3] 英文反问和普通重试请求被不可逆标为纠错 — 英文模式没有像中文 不行、不对 一样排除问号结尾的意见征询;此外,try again 被无条...(truncated) · lib/dissatisfaction.mjs · advisory_c1190fea1341453e4b3769fb
  • [P3] PATH 中未校验的 cursor-agent 可截获蒸馏内容并执行任意代码 — cursorAgentCli() 对备用名称 agent 使用 isCursorAgent() 校验真实路径,却对优先级更高的 curso...(truncated) · lib/cursor-agent.mjs·advisory_9051072a31f90c701feccb78`
  • [P3] 安装和启动失败信息绕过现有脱敏处理 — 只有 setupErrorOutcome() 对异常调用 withoutSecrets();正常失败分支直接把 install.error 和 ran.e...(truncated) · lib/engine-setup.mjs·advisory_be4f274e0e1d26527ad78df9`
  • [P3] 旧版 Slash 命令定义被删除,可能导致命令菜单和兼容入口消失 — 当前 PR 删除了 commands/search.md、commands/run.md、commands/distill.md,但没有在变更文件中添加...(truncated) · commands/search.md · advisory_a120ac4a2a85d773edda577b
  • [P3] README 声称命令文件存在,但本 PR 删除了对应的 slash command 定义 — 当前 diff 删除了 commands/search.md、commands/distill.md、commands/run.md,但新增 README 仍明确写��...(truncated) · README.md · advisory_22e7d0438bc4ff33703d3d10
  • [P3] Recall 回调可在 session 清理后重新写入 injected-assets — recalledStrategy() 在网络等待完成后直接按 sessionId 写入 injected-assets,没有 AbortSignal、turnId ...(truncated) · hooks/user-prompt-submit.mjs · advisory_914818837e479e0f473669d0
  • [P3] 删除 /sync 与 /review 破坏现有命令兼容性 — 当前 PR 直接删除了 commands/sync.md 和 commands/review.md,但没有提供同名兼容入口、别名或迁...(truncated) · commands/sync.md · advisory_5dee16533a85dc7cac4bfd10
  • [P3] 升级后的托管引擎未用于 CLI 命令 — prepareEngine() 可以安装并选择满足最低版本的 managed engine,但 runEvolverCli() 不使用该引擎��...(truncated) · lib/commands.mjs · advisory_45f64633b2b68aca809d9bbc
  • [P3] 失败或中止的 turn 仍会被计入节省量 — stop.mjs 将所有非 completed 状态映射为 aborted 或 error,并传入 endOpenTurn();但只要 ended...(truncated) · ``hooks/stop.mjs`` · advisory_03d22f0fa7311bd7fbcbd0af`
  • [P3] 次版本升级移除了既有 MCP、Skill、Rule 与配置契约 — 项目声明遵循 Semantic Versioning,但本次仅从 2.1.0 升至 2.2.0,同时从公开插件清单删除 mcp...(truncated) · ``.cursor-plugin/plugin.json`` · advisory_4dc64af66123d78071f8db2d`

另有 22 条候选未在评论中展开;可通过下方 Sentinel PR review context 查询全部条目。

开发 agent 查询详情: 调用 MCP 工具 sentinel_pr_review_context,传入 owner_repo="evomap/evolver-cursor-plugin"、pr_number=10、head_sha="f5b3ef9c02ad38910412c7d0606d438be6e68dfc",并按条目追加 finding_id 或 finding_key。

由 Sentinel 审核 · 目标提交 f5b3ef9c02ad

forrestlinfeng and others added 2 commits October 26, 2026 19:57
Each turn that reused an injected strategy is recorded with its turn
number, the asset's name and id, the turn's last check and its saving
(or none counted), and /evolver-status lists a chat's latest 20 below
the totals. The injection ledger keeps the recalled asset's name so the
turn end can show it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- sessionEnd ends only the turn it saw settle: a prompt that opened a new
  turn in the same chat meanwhile keeps its session, injections and
  candidate (endSession returns false and nothing is cleaned up).
- Tool, edit and response hooks record only under their own generation_id;
  one without it no longer lands in the current turn.
- A distillation claim counts only once it is on disk, and candidates are
  told apart by turn as well as timestamp.
- The background worker runs engine setup beside report delivery and
  distillation, so a slow install no longer holds them back.
- Stripe-style keys (sk_live_…, rk_test_…) are redacted.
- The global Evolver core is also looked for under %APPDATA%\npm on Windows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@evomap-aiqa-bot

evomap-aiqa-bot Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

Sentinel 已审核此变更,未发现已核验问题,但发现需要人工确认的风险。

另有 47 个需要人工确认的风险;黄色 advisory 不阻塞合并,建议开发 agent review advisory 评论并逐条确认。

开发 agent 查询详情: 调用 MCP 工具 sentinel_pr_review_context,传入 owner_repo="evomap/evolver-cursor-plugin"、pr_number=10、head_sha="52d04ccac657001fe21e1728d576146871390307",并按条目追加 finding_id 或 finding_key。

由 Sentinel 审核 · 目标提交 52d04ccac657

@forrestlinfeng
forrestlinfeng merged commit 0a93aaa into main Oct 26, 2026
9 checks passed
@evomap-aiqa-bot

Copy link
Copy Markdown

Sentinel 保留了 47 个尚未确认的审核候选。这些黄色条目不阻塞合并;红色 P0/P1 与其他独立硬门禁不受影响。 单一猜测、缺少变更行证据或纯 checklist 的候选会统一降为 P3。
开发 agent:请 review 以下 advisory,并逐条给出“已验证无风险 / 已修复 / 转为后续事项”的结论;不要只做整体确认。

  • [P1] 锁超时后无锁读改写会丢失候选领取状态 — acquire() 在 2 秒内无法取得活锁时返回 null,但 updateState() 仍继续执行“读取旧状态 -> mu...(truncated) · lib/state-file.mjs · advisory_8547ffff8a400913b6050330
  • [P2] 英文反问会被不可逆地标记为纠错 — 英文模式匹配 that's wrong,却没有像中文 不行、不对 模式一样排除问号结尾的意见征询...(truncated) · lib/dissatisfaction.mjs · advisory_ce97c99e22486e8b07b1dbf0
  • [P2] 先关闭 turn 再执行易失败副作用,异常后无法重试 — endOpenTurn() 首先通过 closeOpenTurn() 不可逆地关闭开放 turn,之后才执行多项可能失败的持��...(truncated) · lib/turn-end.mjs · advisory_572f5118c1557ff448323888
  • [P2] 已结束会话可被迟到的召回回调重新写入 — recalledStrategy 在最长 6 秒的异步调用后直接执行 rememberInjected,没有重新检查当前 session �...(truncated) · hooks/user-prompt-submit.mjs · advisory_6a298d17f95f9d99cc7bdf27
  • [P2] 缺失 generation ID 的迟到事件仍会命中当前 turn — recordingTurnOf() 将 (null ?? null) === session.turnId 视为精确匹配,因此当前 turn 的 turnId 也是 ...(truncated) · lib/session-state.mjs·advisory_4d981eb5b3a27b4d1ed79941`
  • [P2] 缺少 turnId 的迟到结束事件可关闭后续 turn — endOpenTurn() 将可选的 turnId 原样传给 closeOpenTurn();源码注释明确说明省略时会关闭“任�...(truncated) · lib/turn-end.mjs · advisory_a14c9cdba81b67c6cd6b141c
  • [P3] 预先取消的信号无法阻止模型子进程启动 — runCli() 启动子进程后仅注册 abort 监听器,没有先检查 signal.aborted。如果取消发生在模��...(truncated) · lib/cursor-agent.mjs · advisory_5c81f95074569cd8fefe45f6
  • [P3] fake agent 将测试参数持续写入真实用户目录,造成跨运行污染并可能泄露测��...(truncated) — 每次 fixture 运行都以追加模式写入固定的 $HOME/fake-cursor-agent.log,既不使用测试临时目录,...(truncated) · test/fixtures/fake-cursor-agent.mjs · advisory_91d31d0c7cb09e10df6e6bb2
  • [P3] 删除 /sync 与 /review 破坏现有命令调用兼容性 — PR 删除了注册 /sync、/review 的命令文件,却没有在旧名称下保留转发或弃用兼容层。新增...(truncated) · commands/sync.md · advisory_651fc00a5f4f67c2bcc6ae25
  • [P3] 状态写入失败被吞掉,且替换失败时可能先删除旧状态 — writeState() 捕获并忽略所有异常,调用方无法知道状态没有落盘。在 EEXIST/EPERM 回退中还...(truncated) · lib/state-file.mjs · advisory_fce599ef3efeee8aab944087
  • [P3] 自定义 npm 全局前缀下无法加载已安装的 Evolver Core — 全局包位置仅由 process.execPath、Windows APPDATA 推导,没有读取 npm 的实际全局 prefix。用户��...(truncated) · lib/local-ledger.mjs · advisory_537b420bcda898bfd4e11e65
  • [P3] 文件读取失败被当作文件不存在 — contentHashOf() 把所有读取异常,包括权限错误和瞬时 I/O 错误,统一转换为 ABSENT。后续保�...(truncated) · lib/retention-pending.mjs · advisory_7489bc256a94d71f9decda33
  • [P3] EvoMap 网络资产可将未受信指令原样注入代理上下文 — strategySteps() 接受 EvoMap 网络返回的 asset.strategy、payload.strategy 或 gene.strategy,之后仅检...(truncated) · lib/prime.mjs · advisory_b82f4171535e24d5b8084c5f
  • [P3] HTTP 200 的畸形响应被误报为“没有候选” — createProxyClient() 在 JSON 解析失败时仍返回 { ok: true, data: { raw: text } }。proxyJson() 因此把响...(truncated) · lib/proxy.mjs · advisory_13ae367220c5ae7bd3a7a1e3
  • [P3] Shell 验证命令中的密钥会进入远程复用报告 — checkOf() 将 Shell 命令原文截取至 200 字符后写入 check.command,没有调用提示词路径使用的��...(truncated) · lib/turn-record.mjs · advisory_ef0a4b47f40c0b7000d608ed
  • [P3] endSession 校验后仍可能清理新打开 turn 的状态 — endSession(sessionId, session.turn) 只在清理开始前校验一次 turn。返回成功后,takeUnreported()、c...(truncated) · hooks/session-end.mjs·advisory_6e53a15cbf568a11df1baf94`
  • [P3] sessionEnd 的清理可误删刚打开的新 turn 资产 — endSession(sessionId, session.turn) 只在调用瞬间校验 turn。它成功后,takeUnreported、closeCandidate...(truncated) · hooks/session-end.mjs · advisory_d44a7554b0093db68431f298
  • [P3] 候选有效性校验后仍可提交已被替换的旧候选 — isCurrent() 只在发起异步 proxyFetch() 前检查一次。检查通过后,候选仍可被新 turn 替换或因...(truncated) · lib/session-distill.mjs · advisory_5eb4190bb70234a854c76770
  • [P3] 引擎命令超时仅终止根进程,子进程可能继续运行 — execFile(..., { timeout }) 超时后只向直接子进程发送终止信号,没有在 POSIX 上创建并终止独立...(truncated) · lib/engine-runtime.mjs · advisory_a8a007900fe019ba04f471bb
  • [P3] 新文档宣称的 /evolver-* 命令没有对应的命令文件 — 本 PR 删除了 commands/distill.md、commands/run.md 和 commands/search.md,但没有在当前 diff 中新增�...(truncated) · commands/distill.md · advisory_63026e2d00a547dbeb018a90

另有 27 条候选未在评论中展开;可通过下方 Sentinel PR review context 查询全部条目。

开发 agent 查询详情: 调用 MCP 工具 sentinel_pr_review_context,传入 owner_repo="evomap/evolver-cursor-plugin"、pr_number=10、head_sha="52d04ccac657001fe21e1728d576146871390307",并按条目追加 finding_id 或 finding_key。

由 Sentinel 审核 · 目标提交 52d04ccac657

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant