@huseynsnmz/pi-board 0.15.3 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (211) hide show
  1. package/CHANGELOG.md +13 -4
  2. package/CONTRIBUTING.md +7 -0
  3. package/README.md +53 -419
  4. package/SECURITY.md +19 -0
  5. package/docs/how-it-works.md +31 -0
  6. package/docs/reference.md +276 -0
  7. package/package.json +5 -11
  8. package/src/index.ts +1 -1
  9. package/src/runtime/service.mjs +12 -0
  10. package/src/ui/dashboard.ts +14 -8
  11. package/IMPLEMENTATION_PLAN.md +0 -920
  12. package/PRD.md +0 -484
  13. package/PROGRESS.md +0 -142
  14. package/VERIFY.md +0 -115
  15. package/docs/BATCH_SELECTION_READ_FLOW.md +0 -277
  16. package/docs/EXPLORATION.md +0 -187
  17. package/docs/PTY_ATTACH_IMPLEMENTATION_PLAN.md +0 -581
  18. package/docs/RELEASE.md +0 -148
  19. package/docs/superpowers/plans/2026-08-15-screenlog-gc.md +0 -704
  20. package/docs/superpowers/plans/2026-08-16-attach-double-cursor-jiggle-retry.md +0 -499
  21. package/docs/superpowers/plans/2026-08-21-attach-coldstart-jiggle-rearm.md +0 -797
  22. package/docs/superpowers/plans/2026-08-21-dashboard-keypress-lag.md +0 -366
  23. package/docs/superpowers/plans/2026-08-21-issue-14-needs-input-no-auto-done.md +0 -576
  24. package/docs/superpowers/plans/2026-08-22-jiggle-shrink-and-hold.md +0 -337
  25. package/docs/superpowers/plans/2026-08-22-launch-cwd-favorites.md +0 -916
  26. package/docs/superpowers/plans/2026-08-22-question-tool-grouping.md +0 -211
  27. package/docs/superpowers/plans/2026-08-22-rename-state-labels.md +0 -182
  28. package/docs/superpowers/plans/2026-08-22-stable-list-order.md +0 -51
  29. package/docs/superpowers/plans/2026-08-27-locks-acquirelock-spin.md +0 -614
  30. package/docs/superpowers/plans/2026-08-27-pty-runner-test-flaky.md +0 -32
  31. package/docs/superpowers/plans/2026-08-29-code-refs-badges.md +0 -223
  32. package/docs/superpowers/plans/2026-08-30-circular-navigation.md +0 -308
  33. package/docs/superpowers/plans/2026-08-30-post-exit-timing-fix.md +0 -37
  34. package/docs/superpowers/plans/2026-08-30-pty-attach-quality-debt.md +0 -311
  35. package/docs/superpowers/plans/2026-08-30-readme-v2.md +0 -294
  36. package/docs/superpowers/plans/2026-09-01-attach-detach-gate-cursor-anchor.md +0 -284
  37. package/docs/superpowers/plans/2026-09-02-attach-detach-editor-state.md +0 -722
  38. package/docs/superpowers/plans/2026-09-03-code-refs-pr-backlink-narrow.md +0 -551
  39. package/docs/superpowers/plans/2026-09-03-detach-gate-glyph-fallback.md +0 -146
  40. package/docs/superpowers/plans/2026-09-04-evidence-outputpreview.md +0 -209
  41. package/docs/superpowers/plans/2026-09-04-warm-host-reclaim.md +0 -796
  42. package/docs/superpowers/plans/2026-09-05-issue-13-drainnextfollowup-pty-probe.md +0 -114
  43. package/docs/superpowers/plans/2026-09-05-issue-38-windows-wezterm-ime-cursor.md +0 -73
  44. package/docs/superpowers/plans/2026-09-05-issue-39-truncate-codepoint-boundary.md +0 -143
  45. package/docs/superpowers/plans/2026-09-05-issue-61-mention-fallback-guards.md +0 -226
  46. package/docs/superpowers/plans/2026-09-05-issue-63-flaky-manual-completion.md +0 -87
  47. package/docs/superpowers/plans/2026-09-05-issue-64-changelog-release-helper.md +0 -53
  48. package/docs/superpowers/plans/2026-09-05-pty-host-stacking-sock-race.md +0 -731
  49. package/docs/superpowers/plans/2026-09-08-attach-ctrl-left-detach.md +0 -30
  50. package/docs/superpowers/plans/2026-09-08-dashboard-shrink-repaint.md +0 -68
  51. package/docs/superpowers/plans/2026-09-08-issue-11-attach-runtime-desync-heal.md +0 -917
  52. package/docs/superpowers/plans/2026-09-08-legacy-stale-host-recovery.md +0 -125
  53. package/docs/superpowers/plans/2026-09-08-spawn-async-error-swallow.md +0 -56
  54. package/docs/superpowers/plans/2026-09-08-stale-model-attach-guard.md +0 -96
  55. package/docs/superpowers/plans/2026-09-09-claimpid-blocks-replace.md +0 -267
  56. package/docs/superpowers/plans/2026-09-09-harden-runner-architecture.md +0 -603
  57. package/docs/superpowers/plans/2026-09-09-single-writer-completion.md +0 -252
  58. package/docs/superpowers/plans/2026-09-10-reader-consistency.md +0 -115
  59. package/docs/superpowers/plans/2026-09-14-attach-cursor-dectcem-gate.md +0 -469
  60. package/docs/superpowers/plans/2026-09-14-attach-snapshot.md +0 -92
  61. package/docs/superpowers/plans/2026-09-14-host-meta-orphan-lock.md +0 -771
  62. package/docs/superpowers/plans/2026-09-14-issue-106-terminal-frame-cognition.md +0 -299
  63. package/docs/superpowers/plans/2026-09-14-issue-113-foreground-preview-race.md +0 -609
  64. package/docs/superpowers/plans/2026-09-14-terminal-model.md +0 -145
  65. package/docs/superpowers/plans/2026-09-15-coordinator-pipe-root-normalize.md +0 -224
  66. package/docs/superpowers/plans/2026-09-15-lease-publish-eprem-reclaim.md +0 -341
  67. package/docs/superpowers/plans/2026-09-18-detach-anchor-reporter-endpoint.md +0 -875
  68. package/docs/superpowers/plans/2026-09-20-control-lifecycle.md +0 -116
  69. package/docs/superpowers/plans/2026-09-20-issue-121-perf-gate-out-of-coverage.md +0 -517
  70. package/docs/superpowers/plans/2026-09-23-a5-mid-stream-assertion.md +0 -25
  71. package/docs/superpowers/plans/2026-09-23-cwd-browse-tab-drill.md +0 -393
  72. package/docs/superpowers/plans/2026-09-23-terminal-query-forwarding.md +0 -51
  73. package/docs/superpowers/plans/2026-09-23-unconditional-detach-key.md +0 -58
  74. package/docs/superpowers/plans/2026-09-24-control-reconcile-flake.md +0 -698
  75. package/docs/superpowers/plans/2026-09-24-probe-attached-clients.md +0 -605
  76. package/docs/superpowers/plans/2026-09-29-issue-145-holding-semantic-state.md +0 -1183
  77. package/docs/superpowers/plans/2026-09-29-issue-145-user-verification.md +0 -66
  78. package/docs/superpowers/plans/2026-09-30-board-delete-key-x-y-confirm.md +0 -649
  79. package/docs/superpowers/plans/2026-09-30-issue-153-runner-stop-boot-window.md +0 -618
  80. package/docs/superpowers/plans/2026-09-30-issue-95-test-discipline.md +0 -555
  81. package/docs/superpowers/plans/2026-09-30-publish-dispatch-tag-check.md +0 -259
  82. package/docs/superpowers/plans/2026-10-06-attach-settle-scheme-delivery.md +0 -751
  83. package/docs/superpowers/plans/2026-10-09-issue-167-attach-middle-paste.md +0 -509
  84. package/docs/superpowers/plans/2026-10-09-issue-169-fullscreen-mouse-ownership.md +0 -346
  85. package/docs/superpowers/plans/2026-10-10-attach-delete-in-place.md +0 -832
  86. package/docs/superpowers/plans/2026-10-10-issue-174-selection-mirror-paste-source.md +0 -510
  87. package/docs/superpowers/plans/2026-10-14-issue-170-attach-reply-guard.md +0 -771
  88. package/docs/superpowers/plans/2026-10-14-issue-178-accept-registration-race.md +0 -1257
  89. package/docs/superpowers/plans/2026-10-14-issue-184-snapshot-window-contract.md +0 -657
  90. package/docs/superpowers/plans/2026-10-14-issue-185-attach-wheel-alt-screen.md +0 -47
  91. package/docs/superpowers/plans/2026-10-14-issue-187-motionless-drag.md +0 -931
  92. package/docs/superpowers/plans/2026-10-14-issue-189-mixed-input-segments.md +0 -823
  93. package/docs/superpowers/plans/2026-10-15-issue-188-x10-mouse-release.md +0 -526
  94. package/docs/superpowers/plans/2026-10-16-issue-198-attach-wheel-forward-fallback.md +0 -32
  95. package/docs/superpowers/plans/2026-10-18-attach-wheel-replay-pseudo-scrollback.md +0 -437
  96. package/docs/superpowers/plans/2026-10-19-issue-213-reply-guard-csi-key.md +0 -257
  97. package/docs/superpowers/plans/2026-10-19-issue-214-attach-forward-alt-modifier.md +0 -202
  98. package/docs/superpowers/plans/2026-10-21-issue-221-ask-user-question.md +0 -198
  99. package/docs/superpowers/plans/2026-10-23-issue-222-attach-ready.md +0 -290
  100. package/docs/superpowers/plans/2026-10-23-issue-225-monotonic-foreground-state.md +0 -450
  101. package/docs/superpowers/plans/2026-10-23-issue-229-vim-jkl.md +0 -449
  102. package/docs/superpowers/plans/2026-10-23-issue-232-attach-bg-only-cells.md +0 -153
  103. package/docs/superpowers/plans/2026-10-23-lease-heartbeat-staleness.md +0 -537
  104. package/docs/superpowers/plans/2026-10-23-selected-row-highlight.md +0 -405
  105. package/docs/superpowers/plans/2026-10-24-issue-217-windows-pid-reuse-stopping.md +0 -367
  106. package/docs/superpowers/plans/2026-10-24-issue-230-warm-host-background-runs.md +0 -806
  107. package/docs/superpowers/plans/2026-10-24-issue-238-windows-process-identity-token.md +0 -490
  108. package/docs/superpowers/plans/2026-10-24-issue-241-coordinator-root-exit.md +0 -461
  109. package/docs/superpowers/plans/2026-10-25-issue-239-coordinator-replacement-identity.md +0 -504
  110. package/docs/superpowers/plans/2026-10-26-issue-245-key-hints-doc-sync.md +0 -244
  111. package/docs/superpowers/plans/2026-10-27-issue-172-fullscreen-selection-clear.md +0 -344
  112. package/docs/superpowers/plans/2026-10-27-issue-252-select-key-hints.md +0 -209
  113. package/docs/superpowers/plans/2026-10-28-issue-255-coordinator-endpoint-zombie.md +0 -442
  114. package/docs/superpowers/plans/2026-10-28-issue-257-legacy-pty-runner-endpoint-cleanup.md +0 -256
  115. package/docs/superpowers/plans/2026-11-03-cwd-favorites-full-pool.md +0 -266
  116. package/docs/superpowers/specs/2026-08-15-screenlog-gc-design.md +0 -105
  117. package/docs/superpowers/specs/2026-08-16-attach-double-cursor-jiggle-retry-design.md +0 -142
  118. package/docs/superpowers/specs/2026-08-21-attach-coldstart-jiggle-rearm-design.md +0 -110
  119. package/docs/superpowers/specs/2026-08-21-dashboard-keypress-lag-design.md +0 -59
  120. package/docs/superpowers/specs/2026-08-21-issue-14-needs-input-no-auto-done-design.md +0 -109
  121. package/docs/superpowers/specs/2026-08-22-cwd-favorites-design.md +0 -131
  122. package/docs/superpowers/specs/2026-08-22-jiggle-shrink-and-hold-design.md +0 -111
  123. package/docs/superpowers/specs/2026-08-22-question-tool-grouping-design.md +0 -114
  124. package/docs/superpowers/specs/2026-08-22-rename-state-labels-design.md +0 -80
  125. package/docs/superpowers/specs/2026-08-27-locks-acquirelock-spin-design.md +0 -97
  126. package/docs/superpowers/specs/2026-08-27-pty-runner-test-flaky-design.md +0 -35
  127. package/docs/superpowers/specs/2026-08-29-code-refs-badges-design.md +0 -128
  128. package/docs/superpowers/specs/2026-08-30-circular-navigation-design.md +0 -47
  129. package/docs/superpowers/specs/2026-08-30-eprm-atomicwrite-race-design.md +0 -77
  130. package/docs/superpowers/specs/2026-08-30-post-exit-timing-fix-design.md +0 -80
  131. package/docs/superpowers/specs/2026-08-30-pty-attach-quality-debt-design.md +0 -105
  132. package/docs/superpowers/specs/2026-08-30-readme-v2-design.md +0 -115
  133. package/docs/superpowers/specs/2026-09-01-attach-detach-gate-cursor-anchor-design.md +0 -78
  134. package/docs/superpowers/specs/2026-09-02-attach-detach-editor-state-design.md +0 -120
  135. package/docs/superpowers/specs/2026-09-03-code-refs-pr-backlink-narrow-design.md +0 -92
  136. package/docs/superpowers/specs/2026-09-03-detach-gate-glyph-fallback-design.md +0 -99
  137. package/docs/superpowers/specs/2026-09-04-evidence-outputpreview-design.md +0 -50
  138. package/docs/superpowers/specs/2026-09-04-warm-host-reclaim-design.md +0 -106
  139. package/docs/superpowers/specs/2026-09-05-issue-13-drainnextfollowup-pty-probe-design.md +0 -64
  140. package/docs/superpowers/specs/2026-09-05-issue-38-windows-wezterm-ime-design.md +0 -48
  141. package/docs/superpowers/specs/2026-09-05-issue-39-truncate-codepoint-boundary-design.md +0 -64
  142. package/docs/superpowers/specs/2026-09-05-issue-61-mention-fallback-design.md +0 -71
  143. package/docs/superpowers/specs/2026-09-05-issue-63-flaky-manual-completion-design.md +0 -49
  144. package/docs/superpowers/specs/2026-09-05-issue-64-changelog-helper-design.md +0 -76
  145. package/docs/superpowers/specs/2026-09-05-pty-host-stacking-sock-race-design.md +0 -510
  146. package/docs/superpowers/specs/2026-09-07-issue-11-attach-runtime-desync-heal-design.md +0 -130
  147. package/docs/superpowers/specs/2026-09-08-attach-ctrl-left-detach-design.md +0 -58
  148. package/docs/superpowers/specs/2026-09-08-dashboard-shrink-repaint-design.md +0 -52
  149. package/docs/superpowers/specs/2026-09-08-legacy-stale-host-recovery-design.md +0 -87
  150. package/docs/superpowers/specs/2026-09-08-spawn-async-error-swallow-design.md +0 -56
  151. package/docs/superpowers/specs/2026-09-08-stale-model-attach-guard-design.md +0 -79
  152. package/docs/superpowers/specs/2026-09-09-claimpid-blocks-replace-design.md +0 -147
  153. package/docs/superpowers/specs/2026-09-09-harden-runner-architecture-design.md +0 -304
  154. package/docs/superpowers/specs/2026-09-14-attach-cursor-dectcem-gate-design.md +0 -114
  155. package/docs/superpowers/specs/2026-09-14-host-meta-orphan-lock-design.md +0 -120
  156. package/docs/superpowers/specs/2026-09-14-issue-106-terminal-frame-cognition-design.md +0 -146
  157. package/docs/superpowers/specs/2026-09-14-issue-113-foreground-preview-race-design.md +0 -116
  158. package/docs/superpowers/specs/2026-09-15-coordinator-pipe-root-normalize-design.md +0 -84
  159. package/docs/superpowers/specs/2026-09-15-lease-publish-eprem-reclaim-design.md +0 -92
  160. package/docs/superpowers/specs/2026-09-18-detach-anchor-reporter-endpoint-design.md +0 -123
  161. package/docs/superpowers/specs/2026-09-20-issue-121-perf-gate-out-of-coverage-design.md +0 -204
  162. package/docs/superpowers/specs/2026-09-23-a5-mid-stream-assertion-design.md +0 -43
  163. package/docs/superpowers/specs/2026-09-23-cwd-browse-tab-drill-design.md +0 -95
  164. package/docs/superpowers/specs/2026-09-23-terminal-query-forwarding-design.md +0 -63
  165. package/docs/superpowers/specs/2026-09-23-unconditional-detach-key-design.md +0 -57
  166. package/docs/superpowers/specs/2026-09-24-control-reconcile-flake-design.md +0 -98
  167. package/docs/superpowers/specs/2026-09-24-probe-attached-clients-design.md +0 -190
  168. package/docs/superpowers/specs/2026-09-29-issue-145-holding-semantic-state-design.md +0 -394
  169. package/docs/superpowers/specs/2026-09-30-board-delete-key-x-y-confirm-design.md +0 -86
  170. package/docs/superpowers/specs/2026-09-30-issue-153-runner-stop-boot-window-design.md +0 -75
  171. package/docs/superpowers/specs/2026-09-30-issue-95-test-discipline-design.md +0 -226
  172. package/docs/superpowers/specs/2026-09-30-publish-dispatch-tag-check-design.md +0 -129
  173. package/docs/superpowers/specs/2026-10-06-attach-settle-scheme-delivery-design.md +0 -196
  174. package/docs/superpowers/specs/2026-10-09-issue-167-attach-middle-paste-design.md +0 -125
  175. package/docs/superpowers/specs/2026-10-09-issue-169-fullscreen-mouse-ownership-design.md +0 -130
  176. package/docs/superpowers/specs/2026-10-10-attach-delete-in-place-design.md +0 -224
  177. package/docs/superpowers/specs/2026-10-10-issue-174-selection-mirror-paste-source-design.md +0 -154
  178. package/docs/superpowers/specs/2026-10-14-issue-170-attach-reply-guard-design.md +0 -195
  179. package/docs/superpowers/specs/2026-10-14-issue-178-accept-registration-race-design.md +0 -287
  180. package/docs/superpowers/specs/2026-10-14-issue-184-snapshot-window-contract-design.md +0 -288
  181. package/docs/superpowers/specs/2026-10-14-issue-185-attach-wheel-alt-screen-design.md +0 -126
  182. package/docs/superpowers/specs/2026-10-14-issue-187-motionless-drag-design.md +0 -269
  183. package/docs/superpowers/specs/2026-10-14-issue-189-mixed-input-segments-design.md +0 -369
  184. package/docs/superpowers/specs/2026-10-15-issue-188-x10-mouse-release-design.md +0 -252
  185. package/docs/superpowers/specs/2026-10-16-issue-198-attach-wheel-forward-fallback-design.md +0 -67
  186. package/docs/superpowers/specs/2026-10-18-attach-wheel-replay-pseudo-scrollback-design.md +0 -250
  187. package/docs/superpowers/specs/2026-10-19-issue-213-reply-guard-csi-key-design.md +0 -165
  188. package/docs/superpowers/specs/2026-10-19-issue-214-attach-forward-alt-modifier-design.md +0 -131
  189. package/docs/superpowers/specs/2026-10-20-issue-221-ask-user-question-design.md +0 -270
  190. package/docs/superpowers/specs/2026-10-22-issue-225-monotonic-foreground-state-design.md +0 -225
  191. package/docs/superpowers/specs/2026-10-23-issue-222-attach-ready-design.md +0 -204
  192. package/docs/superpowers/specs/2026-10-23-issue-229-vim-jkl-design.md +0 -90
  193. package/docs/superpowers/specs/2026-10-23-issue-232-attach-bg-only-cells-design.md +0 -146
  194. package/docs/superpowers/specs/2026-10-23-lease-heartbeat-staleness-design.md +0 -271
  195. package/docs/superpowers/specs/2026-10-23-selected-row-highlight-design.md +0 -191
  196. package/docs/superpowers/specs/2026-10-24-issue-217-windows-pid-reuse-stopping-design.md +0 -334
  197. package/docs/superpowers/specs/2026-10-24-issue-230-warm-host-background-runs-design.md +0 -283
  198. package/docs/superpowers/specs/2026-10-24-issue-238-windows-process-identity-token-design.md +0 -286
  199. package/docs/superpowers/specs/2026-10-24-issue-241-coordinator-root-exit-design.md +0 -381
  200. package/docs/superpowers/specs/2026-10-25-issue-239-coordinator-replacement-identity-design.md +0 -331
  201. package/docs/superpowers/specs/2026-10-26-issue-245-key-hints-doc-sync-design.md +0 -72
  202. package/docs/superpowers/specs/2026-10-27-issue-172-fullscreen-selection-clear-design.md +0 -248
  203. package/docs/superpowers/specs/2026-10-27-issue-252-select-key-hints-design.md +0 -95
  204. package/docs/superpowers/specs/2026-10-28-issue-255-coordinator-endpoint-zombie-design.md +0 -380
  205. package/docs/superpowers/specs/2026-10-28-issue-257-legacy-pty-runner-endpoint-cleanup-design.md +0 -197
  206. package/docs/superpowers/specs/2026-11-03-cwd-favorites-full-pool-design.md +0 -106
  207. package/scripts/budget-audit.mjs +0 -135
  208. package/scripts/release.mjs +0 -446
  209. package/scripts/release_helper.mjs +0 -309
  210. package/scripts/run-perf-gate.mjs +0 -40
  211. package/scripts/run-tests.mjs +0 -375
@@ -1,576 +0,0 @@
1
- # Issue #14: Needs-input While Running + No Auto-Done Implementation Plan
2
-
3
- > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
4
-
5
- **Goal:** 运行中(alive)session 的文本提问归类 `needs_input`;auto-state 永不自动归类 `completed`(开关可回退)。
6
-
7
- **Architecture:** 纯函数级改动。`events.mjs` `reduceEvent()` 的 `message_end` 分支按 `detectNeedsInput` 结果设 semanticState;`auto-state.mjs` 内新增 `autoStateDoneDisabled(env)` 开关(`AGENT_BOARD_AUTO_STATE_NO_DONE`,默认禁用自动 done),启发式与模型分类统一降级为 `in_progress`;`applyAutoState*` 增加 completed guard 保护手动标记。
8
-
9
- **Tech Stack:** Node.js (>=20), node:test, plain .mjs modules, JSDoc typedefs(无 TypeScript 构建)。
10
-
11
- ## Global Constraints
12
-
13
- - 所有测试用 `node --test`,断言库 `node:assert/strict`(与现有 test/*.test.mjs 一致)。
14
- - 不改 UI 显示/分组/排序;不改 detached 回复路径;不改 alive guard。
15
- - 环境变量名:`AGENT_BOARD_AUTO_STATE_NO_DONE`(默认未设置 = 禁用自动 done;`0`/`false`/`off`/`no` = 恢复自动 done)。
16
- - 复用 `isOff()` 语义(`/^(0|false|off|no)$/i`)。
17
- - 所有改动在 worktree `/home/elling/git-repo/github/pi-agent-board/.pi/worktrees/issue-14-needs-input-no-auto-done` 内,禁止碰 main checkout。
18
-
19
- ---
20
-
21
- ### Task 1: 运行中文本提问 → needs_input(events.mjs)
22
-
23
- **Files:**
24
- - Modify: `src/core/events.mjs`(`reduceEvent()` 的 `message_end` 分支,约 L121-139)
25
- - Test: `test/events.test.mjs`(新增 2 用例)
26
-
27
- **Interfaces:**
28
- - Consumes: `detectNeedsInput(text)` → `{ needsInput: boolean, question: string|null }`(`src/core/heuristics.mjs` 已有,勿改)。
29
- - Produces: 运行中 `status.semanticState` 可为 `"needs_input"`;`projectViewState().needsInput` 联动(已有逻辑,勿改)。
30
-
31
- - [ ] **Step 1: 写失败测试(在 `test("message_end assistant updates preview and detects question"` 用例之后追加)**
32
-
33
- ```js
34
- test("message_end text ending with a question moves alive run to needs_input", () => {
35
- const s = createRunStatus(cfg(), 1, 1000);
36
- reduceEvent(
37
- s,
38
- { type: "message_end", message: { role: "assistant", content: [{ type: "text", text: "Should I continue with option A?" }] } },
39
- 2000,
40
- );
41
- assert.equal(s.semanticState, "needs_input");
42
- assert.match(s.question, /option A/);
43
- assert.equal(projectViewState(s, 2100).needsInput, true);
44
- });
45
-
46
- test("alive run returns to working after a following message without a question", () => {
47
- const s = createRunStatus(cfg(), 1, 1000);
48
- reduceEvent(
49
- s,
50
- { type: "message_end", message: { role: "assistant", content: [{ type: "text", text: "Which target should I use?" }] } },
51
- 2000,
52
- );
53
- assert.equal(s.semanticState, "needs_input");
54
- reduceEvent(
55
- s,
56
- { type: "message_end", message: { role: "assistant", content: [{ type: "text", text: "Proceeding with the default target." }] } },
57
- 2500,
58
- );
59
- assert.equal(s.semanticState, "working");
60
- assert.equal(s.question, null);
61
- });
62
- ```
63
-
64
- - [ ] **Step 2: 运行测试验证失败**
65
-
66
- Run: `cd /home/elling/git-repo/github/pi-agent-board/.pi/worktrees/issue-14-needs-input-no-auto-done && node --test test/events.test.mjs`
67
- Expected: 2 个新用例 FAIL(`assert.equal(s.semanticState, "needs_input")` 实际为 `"working"`)。
68
-
69
- - [ ] **Step 3: 最小实现(`src/core/events.mjs` `message_end` 分支)**
70
-
71
- 将现有:
72
-
73
- ```js
74
- if (msg?.role === "assistant") {
75
- status.turns += 1;
76
- if (msg.model && !status.model) status.model = msg.model;
77
- if (msg.stopReason) status.stopReason = msg.stopReason;
78
- if (msg.errorMessage) status.error = msg.errorMessage;
79
- else if (msg.stopReason === "stop") status.error = null;
80
- const text = assistantText(msg);
81
- if (text) {
82
- // Store the full latest text (truncated) so peek shows meaningful output;
83
- // deriveSummary() condenses it to a first sentence for the row.
84
- status.latestAssistantPreview = truncate(text, PREVIEW_MAX);
85
- const nb = detectNeedsInput(text);
86
- status.question = nb.question;
87
- }
88
- status.semanticState = "working";
89
- preservePendingQuestion(status);
90
- ```
91
-
92
- 改为:
93
-
94
- ```js
95
- if (msg?.role === "assistant") {
96
- status.turns += 1;
97
- if (msg.model && !status.model) status.model = msg.model;
98
- if (msg.stopReason) status.stopReason = msg.stopReason;
99
- if (msg.errorMessage) status.error = msg.errorMessage;
100
- else if (msg.stopReason === "stop") status.error = null;
101
- const text = assistantText(msg);
102
- let nb = { needsInput: false, question: null };
103
- if (text) {
104
- // Store the full latest text (truncated) so peek shows meaningful output;
105
- // deriveSummary() condenses it to a first sentence for the row.
106
- status.latestAssistantPreview = truncate(text, PREVIEW_MAX);
107
- nb = detectNeedsInput(text);
108
- status.question = nb.question;
109
- }
110
- status.semanticState = nb.needsInput ? "needs_input" : "working";
111
- preservePendingQuestion(status);
112
- ```
113
-
114
- 注意:`preservePendingQuestion(status)` 保持在最后一行,保证 pending question 优先语义不变。
115
-
116
- - [ ] **Step 4: 运行测试验证通过**
117
-
118
- Run: `node --test test/events.test.mjs`
119
- Expected: 全部 PASS(含既有 "interactive ask_questions waits for input" 与 "interactive questions remain visible across parallel activity until each call ends" 回归绿)。
120
-
121
- - [ ] **Step 5: Commit**
122
-
123
- ```bash
124
- cd /home/elling/git-repo/github/pi-agent-board/.pi/worktrees/issue-14-needs-input-no-auto-done
125
- git add test/events.test.mjs src/core/events.mjs
126
- git commit -m "feat: classify running text questions as needs_input (issue #14)"
127
- ```
128
-
129
- ---
130
-
131
- ### Task 2: heuristicAutoState 永不自动 done + env 开关(auto-state.mjs)
132
-
133
- **Files:**
134
- - Modify: `src/core/auto-state.mjs`(新增 `autoStateDoneDisabled()`;改 `heuristicAutoState()`)
135
- - Test: `test/auto-state.test.mjs`(更新 1 断言 + 新增 1 用例)
136
-
137
- **Interfaces:**
138
- - Produces: `export function autoStateDoneDisabled(env = process.env) → boolean`(默认 true;`AGENT_BOARD_AUTO_STATE_NO_DONE` 为 `0/false/off/no` 时返回 false)。
139
- - `heuristicAutoState(latestAssistantText, opts)` 的 `opts` 新增可选 `env`(默认 `process.env`)。既有调用点不传 env,行为自动跟随进程环境。
140
-
141
- - [ ] **Step 1: 写失败测试**
142
-
143
- 在 `test/auto-state.test.mjs` 顶部 import 行追加 `autoStateDoneDisabled`:
144
-
145
- ```js
146
- import { applyAutoStateToStatus, autoStateDoneDisabled, autoStateFromModelOrHeuristic, heuristicAutoState, parseAutoStateModelOutput } from "../src/core/auto-state.mjs";
147
- ```
148
-
149
- 将既有断言:
150
-
151
- ```js
152
- test("heuristicAutoState detects done and in-progress turns", () => {
153
- assert.equal(heuristicAutoState("Done. Fixed the bug and tests pass.").kind, "done");
154
- assert.equal(heuristicAutoState("I updated one file. Next step is to add tests.").kind, "in_progress");
155
- });
156
- ```
157
-
158
- 改为(默认不再 done):
159
-
160
- ```js
161
- test("heuristicAutoState detects done and in-progress turns", () => {
162
- assert.equal(heuristicAutoState("Done. Fixed the bug and tests pass.").kind, "in_progress");
163
- assert.equal(heuristicAutoState("I updated one file. Next step is to add tests.").kind, "in_progress");
164
- });
165
-
166
- test("heuristicAutoState restores done classification when auto-done flag is off", () => {
167
- assert.equal(
168
- heuristicAutoState("Done. Fixed the bug and tests pass.", { env: { AGENT_BOARD_AUTO_STATE_NO_DONE: "0" } }).kind,
169
- "done",
170
- );
171
- assert.equal(autoStateDoneDisabled({}), true);
172
- assert.equal(autoStateDoneDisabled({ AGENT_BOARD_AUTO_STATE_NO_DONE: "0" }), false);
173
- assert.equal(autoStateDoneDisabled({ AGENT_BOARD_AUTO_STATE_NO_DONE: "off" }), false);
174
- });
175
- ```
176
-
177
- - [ ] **Step 2: 运行测试验证失败**
178
-
179
- Run: `node --test test/auto-state.test.mjs`
180
- Expected: `heuristicAutoState detects done and in-progress turns` FAIL(实际 `"done"` 不等于 `"in_progress"`);新增用例 FAIL(`autoStateDoneDisabled` 未导出)。
181
-
182
- - [ ] **Step 3: 最小实现(`src/core/auto-state.mjs`)**
183
-
184
- 在 `autoStateModel()` 函数之后、`isOff()` 之前插入:
185
-
186
- ```js
187
- /**
188
- * Whether automatic `done` classification is disabled.
189
- * Default (env unset): disabled — completed is only ever set by the user.
190
- * Set AGENT_BOARD_AUTO_STATE_NO_DONE to 0/false/off/no to restore auto-done.
191
- * @param {NodeJS.ProcessEnv|Record<string,string|undefined>} [env]
192
- */
193
- export function autoStateDoneDisabled(env = process.env) {
194
- const raw = env.AGENT_BOARD_AUTO_STATE_NO_DONE;
195
- if (typeof raw !== "string" || !raw.trim()) return true;
196
- return !isOff(raw);
197
- }
198
- ```
199
-
200
- `heuristicAutoState` 的 done 分支(现有代码):
201
-
202
- ```js
203
- const lower = text.toLowerCase();
204
- const pending = hasPendingSignal(lower);
205
- const done = hasDoneSignal(lower);
206
- if (done && !pending) {
207
- return makeClassification("done", {
208
- source: "heuristic",
209
- confidence: hasStrongDoneSignal(lower) ? "high" : "medium",
210
- reason: "Assistant reported the work is complete",
211
- now: opts.now,
212
- lastAgentActivityAt: opts.lastAgentActivityAt ?? null,
213
- latestAssistantText: text,
214
- });
215
- }
216
- ```
217
-
218
- 改为:
219
-
220
- ```js
221
- const lower = text.toLowerCase();
222
- const pending = hasPendingSignal(lower);
223
- const done = hasDoneSignal(lower);
224
- const env = opts.env ?? process.env;
225
- if (done && !pending && !autoStateDoneDisabled(env)) {
226
- return makeClassification("done", {
227
- source: "heuristic",
228
- confidence: hasStrongDoneSignal(lower) ? "high" : "medium",
229
- reason: "Assistant reported the work is complete",
230
- now: opts.now,
231
- lastAgentActivityAt: opts.lastAgentActivityAt ?? null,
232
- latestAssistantText: text,
233
- });
234
- }
235
- if (done && !pending) {
236
- // Auto-done disabled: completion signals stay out of the completed bucket;
237
- // the user marks completed manually from the dashboard.
238
- return makeClassification("in_progress", {
239
- source: "heuristic",
240
- confidence: hasStrongDoneSignal(lower) ? "medium" : "low",
241
- reason: "Assistant reported completion but auto-done is disabled",
242
- now: opts.now,
243
- lastAgentActivityAt: opts.lastAgentActivityAt ?? null,
244
- latestAssistantText: text,
245
- });
246
- }
247
- ```
248
-
249
- 同时更新 `heuristicAutoState` 的 JSDoc opts 行:`@param {{ now?: number, lastAgentActivityAt?: number|null, env?: NodeJS.ProcessEnv|Record<string,string|undefined> }} [opts]`。
250
-
251
- - [ ] **Step 4: 运行测试验证通过**
252
-
253
- Run: `node --test test/auto-state.test.mjs`
254
- Expected: 全部 PASS。
255
-
256
- - [ ] **Step 5: Commit**
257
-
258
- ```bash
259
- git add test/auto-state.test.mjs src/core/auto-state.mjs
260
- git commit -m "feat: disable auto-done in heuristic classifier by default (issue #14)"
261
- ```
262
-
263
- ---
264
-
265
- ### Task 3: 模型输出 done 降级 + prompt 两态化(auto-state.mjs)
266
-
267
- **Files:**
268
- - Modify: `src/core/auto-state.mjs`(`parseAutoStateModelOutput()`、`buildAutoStatePrompt()`)
269
- - Test: `test/auto-state.test.mjs`(更新 1 断言 + 新增 1 用例)
270
-
271
- **Interfaces:**
272
- - `parseAutoStateModelOutput(raw, opts)` 的 `opts` 新增可选 `env`;`buildAutoStatePrompt(latestAssistantText, env = process.env)` 新增第二参数(既有调用点不传,兼容)。
273
- - 调用点(`runner/job-runner.mjs`、`runner/state-runner.mjs`)无需改动。
274
-
275
- - [ ] **Step 1: 写失败测试**
276
-
277
- 将既有断言:
278
-
279
- ```js
280
- test("parseAutoStateModelOutput normalizes model JSON", () => {
281
- const c = parseAutoStateModelOutput('{"state":"done","confidence":"high","reason":"tests passed","question":null}', {
282
- latestAssistantText: "Done. Tests passed.",
283
- lastAgentActivityAt: 42,
284
- });
285
- assert.equal(c.kind, "done");
286
- assert.equal(c.semanticState, "completed");
287
- ```
288
-
289
- 改为:
290
-
291
- ```js
292
- test("parseAutoStateModelOutput normalizes model JSON", () => {
293
- const c = parseAutoStateModelOutput('{"state":"done","confidence":"high","reason":"tests passed","question":null}', {
294
- latestAssistantText: "Done. Tests passed.",
295
- lastAgentActivityAt: 42,
296
- });
297
- assert.equal(c.kind, "in_progress");
298
- assert.equal(c.semanticState, "idle");
299
- assert.match(c.reason, /auto-done is disabled/i);
300
- ```
301
-
302
- (其余 `source/confidence/lastAgentActivityAt` 断言保留。)
303
-
304
- 在文件末尾追加:
305
-
306
- ```js
307
- test("parseAutoStateModelOutput keeps done when auto-done flag is off", () => {
308
- const c = parseAutoStateModelOutput('{"state":"done","confidence":"high","reason":"tests passed","question":null}', {
309
- latestAssistantText: "Done. Tests passed.",
310
- lastAgentActivityAt: 42,
311
- env: { AGENT_BOARD_AUTO_STATE_NO_DONE: "0" },
312
- });
313
- assert.equal(c.kind, "done");
314
- assert.equal(c.semanticState, "completed");
315
- });
316
-
317
- test("buildAutoStatePrompt omits done option by default and restores it when flag off", () => {
318
- assert.ok(!/^- done:/m.test(buildAutoStatePrompt("Fix the bug.")));
319
- assert.ok(/^- done:/m.test(buildAutoStatePrompt("Fix the bug.", { AGENT_BOARD_AUTO_STATE_NO_DONE: "0" })));
320
- });
321
- ```
322
-
323
- (import 行追加 `buildAutoStatePrompt`。)
324
-
325
- - [ ] **Step 2: 运行测试验证失败**
326
-
327
- Run: `node --test test/auto-state.test.mjs`
328
- Expected: 3 个用例 FAIL(kind 为 `"done"` 而非 `"in_progress"`;prompt 仍含 done 行)。
329
-
330
- - [ ] **Step 3: 最小实现**
331
-
332
- `buildAutoStatePrompt` 现有实现:
333
-
334
- ```js
335
- export function buildAutoStatePrompt(latestAssistantText) {
336
- const text = truncate(String(latestAssistantText || "").trim(), 6000);
337
- return `Classify the LAST assistant response for a coding-agent dashboard.\n\nChoose exactly one state:\n- needs_input: the assistant asks the user for a decision, clarification, approval, credentials, or is blocked waiting for the user.\n- in_progress: work is partial, next steps remain, verification is pending/failed, or the assistant says it will continue later.\n- done: the requested work is complete, final answer given, no user input required.\n\nReturn ONLY minified JSON with this shape:\n{"state":"needs_input|in_progress|done","confidence":"high|medium|low","reason":"short reason <=18 words","question":"user-facing question or null"}\n\nLast assistant response:\n${text}`;
338
- }
339
- ```
340
-
341
- 改为:
342
-
343
- ```js
344
- export function buildAutoStatePrompt(latestAssistantText, env = process.env) {
345
- const text = truncate(String(latestAssistantText || "").trim(), 6000);
346
- const doneLine = autoStateDoneDisabled(env)
347
- ? ""
348
- : "- done: the requested work is complete, final answer given, no user input required.\n";
349
- const doneNote = autoStateDoneDisabled(env)
350
- ? "The user marks completed manually in the dashboard, so completion signals (done/completed/finished) must be classified as in_progress.\n"
351
- : "";
352
- const states = autoStateDoneDisabled(env) ? "needs_input|in_progress" : "needs_input|in_progress|done";
353
- return `Classify the LAST assistant response for a coding-agent dashboard.\n\nChoose exactly one state:\n- needs_input: the assistant asks the user for a decision, clarification, approval, credentials, or is blocked waiting for the user.\n- in_progress: work is partial, next steps remain, verification is pending/failed, or the assistant says it will continue later.\n${doneLine}${doneNote}\nReturn ONLY minified JSON with this shape:\n{"state":"${states}","confidence":"high|medium|low","reason":"short reason <=18 words","question":"user-facing question or null"}\n\nLast assistant response:\n${text}`;
354
- }
355
- ```
356
-
357
- `parseAutoStateModelOutput` 现有代码:
358
-
359
- ```js
360
- const obj = extractJsonObject(raw);
361
- if (!obj) return null;
362
- const kind = normalizeKind(obj.state ?? obj.kind ?? obj.status);
363
- if (!kind) return null;
364
- ```
365
-
366
- 改为:
367
-
368
- ```js
369
- const obj = extractJsonObject(raw);
370
- if (!obj) return null;
371
- let kind = normalizeKind(obj.state ?? obj.kind ?? obj.status);
372
- if (!kind) return null;
373
- if (kind === "done" && autoStateDoneDisabled(opts.env ?? process.env)) {
374
- kind = "in_progress";
375
- }
376
- ```
377
-
378
- 并在 `makeClassification(kind, {...})` 的调用中把 reason 兜底交给 `defaultReason(kind)`(已有逻辑),另在 opts 里透传降级提示:把
379
-
380
- ```js
381
- return makeClassification(kind, {
382
- source: "model",
383
- confidence,
384
- reason: cleanReason(obj.reason) || defaultReason(kind),
385
- ```
386
-
387
- 改为:
388
-
389
- ```js
390
- return makeClassification(kind, {
391
- source: "model",
392
- confidence,
393
- reason: kind === "in_progress" && autoStateDoneDisabled(opts.env ?? process.env)
394
- ? "Model reported done but auto-done is disabled"
395
- : cleanReason(obj.reason) || defaultReason(kind),
396
- ```
397
-
398
- 并更新 `parseAutoStateModelOutput` 的 JSDoc:`opts` 增加 `env?: NodeJS.ProcessEnv|Record<string,string|undefined>`。
399
-
400
- - [ ] **Step 4: 运行测试验证通过**
401
-
402
- Run: `node --test test/auto-state.test.mjs`
403
- Expected: 全部 PASS。
404
-
405
- - [ ] **Step 5: Commit**
406
-
407
- ```bash
408
- git add test/auto-state.test.mjs src/core/auto-state.mjs
409
- git commit -m "feat: downgrade model done output and two-state prompt when auto-done disabled (issue #14)"
410
- ```
411
-
412
- ---
413
-
414
- ### Task 4: applyAutoState* completed guard(保护手动标记)
415
-
416
- **Files:**
417
- - Modify: `src/core/auto-state.mjs`(`applyAutoStateToStatus()`、`applyAutoStateToViewState()`)
418
- - Test: `test/auto-state.test.mjs`(新增 1 用例)
419
-
420
- **Interfaces:**
421
- - 不变更签名。行为:`semanticState === "completed"` 时直接 `return false`(与 failed/stopped 同列)。
422
-
423
- - [ ] **Step 1: 写失败测试**
424
-
425
- 追加:
426
-
427
- ```js
428
- test("applyAutoStateToStatus never overwrites a manually completed row", () => {
429
- const status = {
430
- processState: "exited",
431
- semanticState: "completed",
432
- currentTool: null,
433
- question: null,
434
- error: null,
435
- latestAssistantPreview: "Done. Fixed the bug and tests pass.",
436
- summary: "Done.",
437
- };
438
- const changed = applyAutoStateToStatus(status, heuristicAutoState(status.latestAssistantPreview), 100);
439
- assert.equal(changed, false);
440
- assert.equal(status.semanticState, "completed");
441
- assert.equal(status.autoState, undefined);
442
- });
443
- ```
444
-
445
- - [ ] **Step 2: 运行测试验证失败**
446
-
447
- Run: `node --test test/auto-state.test.mjs`
448
- Expected: 新用例 FAIL(`changed` 为 `true`,semanticState 被改为 `"idle"`)。
449
-
450
- - [ ] **Step 3: 最小实现**
451
-
452
- `applyAutoStateToStatus` 的 guard 行:
453
-
454
- ```js
455
- if (!classification || status.processState === "alive") return false;
456
- if (status.semanticState === "failed" || status.semanticState === "stopped") return false;
457
- ```
458
-
459
- 改为:
460
-
461
- ```js
462
- if (!classification || status.processState === "alive") return false;
463
- if (status.semanticState === "failed" || status.semanticState === "stopped" || status.semanticState === "completed") return false;
464
- ```
465
-
466
- `applyAutoStateToViewState` 的 guard 行做同样修改(`failed`/`stopped` 之后追加 `|| state.semanticState === "completed"`)。
467
-
468
- - [ ] **Step 4: 运行测试验证通过**
469
-
470
- Run: `node --test test/auto-state.test.mjs`
471
- Expected: 全部 PASS。
472
-
473
- - [ ] **Step 5: Commit**
474
-
475
- ```bash
476
- git add test/auto-state.test.mjs src/core/auto-state.mjs
477
- git commit -m "fix: never overwrite manual completed state in auto-state (issue #14)"
478
- ```
479
-
480
- ---
481
-
482
- ### Task 5: 集成测试同步 + 全量验证 + 收尾 commit
483
-
484
- **Files:**
485
- - Modify: `test/runner.integration.test.mjs`(L45-80、L114-126 两处 completed 断言)
486
- - Test: 同文件新增 1 用例(默认无自动 done)
487
-
488
- **Interfaces:**
489
- - fake worker 由 `process.env.FAKE_PI_MODE = "completed"` 驱动;job-runner 子进程继承父进程 env,所以 `AGENT_BOARD_AUTO_STATE_NO_DONE` 在 spawn 前设置即可生效。
490
-
491
- - [ ] **Step 1: 更新既有断言(两处)**
492
-
493
- `test("runner auto-classifies a completed fake worker and writes durable artifacts"` 用例(L45-80)的 env 设置块:
494
-
495
- ```js
496
- const root = mkdtempSync(join(tmpdir(), "agentview-run-"));
497
- const env = { ...process.env };
498
- process.env.FAKE_PI_MODE = "completed";
499
- process.env.AGENT_BOARD_SUMMARY_MODEL = "off";
500
- ```
501
-
502
- 改为:
503
-
504
- ```js
505
- const root = mkdtempSync(join(tmpdir(), "agentview-run-"));
506
- const env = { ...process.env };
507
- process.env.FAKE_PI_MODE = "completed";
508
- process.env.AGENT_BOARD_SUMMARY_MODEL = "off";
509
- process.env.AGENT_BOARD_AUTO_STATE_NO_DONE = "0";
510
- ```
511
-
512
- 其 finally 块在 `delete process.env.AGENT_BOARD_SUMMARY_MODEL;` 之后追加:
513
-
514
- ```js
515
- delete process.env.AGENT_BOARD_AUTO_STATE_NO_DONE;
516
- ```
517
-
518
- `test("runner protects dash-prefixed prompts passed via argv"` 用例(L114-126)同样:`process.env.AGENT_BOARD_SUMMARY_MODEL = "off";` 之后追加 `process.env.AGENT_BOARD_AUTO_STATE_NO_DONE = "0";`,finally 块同步 delete。
519
-
520
- - [ ] **Step 2: 新增默认行为用例(在 "runner protects dash-prefixed prompts" 用例之后追加)**
521
-
522
- ```js
523
- test("runner keeps a completed fake worker idle when auto-done is disabled", { timeout: 20000 }, async () => {
524
- const root = mkdtempSync(join(tmpdir(), "agentview-run-nodone-"));
525
- process.env.FAKE_PI_MODE = "completed";
526
- process.env.AGENT_BOARD_SUMMARY_MODEL = "off";
527
- delete process.env.AGENT_BOARD_AUTO_STATE_NO_DONE;
528
- try {
529
- const meta = createView(root, { id: "view_1", name: "fix", cwd: root });
530
- const config = makeConfig(root, "view_1", "run_1", meta.sessionFile, root, "fix the bug");
531
- const st = readState(root, "view_1");
532
- st.currentRunId = "run_1";
533
- const { writeState } = await import("../src/core/store.mjs");
534
- writeState(root, st);
535
- const { pid } = launchRun(root, config, { runnerScript: RUNNER });
536
- assert.ok(pid && pid > 0, "runner spawned");
537
- const status = await waitFor(() => {
538
- const s = readStatus(root, "view_1", "run_1");
539
- return s && s.endedAt ? s : null;
540
- });
541
- assert.ok(status, "status reached terminal state");
542
- assert.equal(status.semanticState, "idle");
543
- assert.equal(status.processState, "exited");
544
- assert.equal(status.autoState?.kind, "in_progress");
545
- } finally {
546
- delete process.env.FAKE_PI_MODE;
547
- delete process.env.AGENT_BOARD_SUMMARY_MODEL;
548
- rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 50 });
549
- }
550
- });
551
- ```
552
-
553
- - [ ] **Step 3: 运行集成测试**
554
-
555
- Run: `node --test test/runner.integration.test.mjs`
556
- Expected: 全部 PASS。若个别用例因 pre-existing flaky(并行全量偶发)失败,单文件重跑确认。
557
-
558
- - [ ] **Step 4: 全量验证**
559
-
560
- Run: `npm run verify`(= typecheck + test + pack:dry)
561
- Expected: 全绿。
562
-
563
- - [ ] **Step 5: Commit**
564
-
565
- ```bash
566
- git add test/runner.integration.test.mjs
567
- git commit -m "test: keep auto-done off by default in runner integration (issue #14)"
568
- ```
569
-
570
- ---
571
-
572
- ## Self-Review(对照 spec)
573
-
574
- 1. **Spec coverage**:变更 1(events.mjs)→ Task 1;变更 2 启发式 → Task 2;模型降级+prompt → Task 3;completed guard → Task 4;测试同步+全量验证 → Task 5;开关回退 → Task 2/3 测试均有 env-off 断言。✅
575
- 2. **Placeholder scan**:已把 Task 5 的省略注释落实为具体代码(Step 1/2 完整代码块)。其余任务无 TBD/TODO/省略。✅
576
- 3. **Type consistency**:`autoStateDoneDisabled(env)` 在各任务签名一致;`heuristicAutoState` opts.env、`parseAutoStateModelOutput` opts.env、`buildAutoStatePrompt(text, env)` 一致。✅