@pencil-agent/nano-pencil 2.0.1 → 2.0.3

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 (188) hide show
  1. package/README.md +267 -267
  2. package/dist/build-meta.json +3 -3
  3. package/dist/core/export-html/AGENT.md +11 -11
  4. package/dist/core/export-html/template.css +971 -971
  5. package/dist/core/export-html/template.html +54 -54
  6. package/dist/core/model/custom-providers.js +1 -1
  7. package/dist/core/model-registry.js +5 -5
  8. package/dist/extensions/builtin/AGENT.md +115 -115
  9. package/dist/extensions/builtin/browser/AGENT.md +17 -17
  10. package/dist/extensions/builtin/browser/agent-workspace/agent_helpers.py +12 -12
  11. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/amazon/product-search.md +198 -198
  12. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/archive-org/scraping.md +341 -341
  13. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/arxiv/scraping.md +311 -311
  14. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/arxiv-bulk/scraping.md +333 -333
  15. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/atlas/overview.md +70 -70
  16. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/booking-com/scraping.md +578 -578
  17. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/capterra/scraping.md +440 -440
  18. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/centilebrain/generate-estimates.md +110 -110
  19. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/coingecko/scraping.md +325 -325
  20. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/coinmarketcap/scraping.md +463 -463
  21. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/coursera/scraping.md +360 -360
  22. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/craigslist/scraping.md +390 -390
  23. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/crossref/scraping.md +568 -568
  24. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/dev-to/scraping.md +323 -323
  25. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/duckduckgo/scraping.md +349 -349
  26. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/ebay/scraping.md +435 -435
  27. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/etsy/scraping.md +506 -506
  28. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/eventbrite/scraping.md +363 -363
  29. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/expedia/automation.md +168 -168
  30. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/facebook/groups.md +236 -236
  31. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/facebook/pages.md +295 -295
  32. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/framer/editor.md +108 -108
  33. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/fred/scraping.md +493 -493
  34. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/g2/scraping.md +580 -580
  35. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/genius/scraping.md +511 -511
  36. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/github/repo-actions.md +65 -65
  37. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/github/scraping.md +184 -184
  38. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/glassdoor/scraping.md +543 -543
  39. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/gmail/compose.md +122 -122
  40. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/goodreads/scraping.md +461 -461
  41. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/gutenberg/scraping.md +383 -383
  42. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/hackernews/scraping.md +243 -243
  43. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/howlongtobeat/scraping.md +473 -473
  44. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/imdb/scraping.md +271 -271
  45. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/itch-io/scraping.md +436 -436
  46. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/job-boards/indeed-glassdoor.md +1021 -1021
  47. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/letterboxd/scraping.md +349 -349
  48. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/linkedin/invitation-manager.md +109 -109
  49. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/loom/folder-enumeration.md +170 -170
  50. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/macrotrends/scraping.md +537 -537
  51. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/medium/article-hydration.md +120 -120
  52. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/medium/scraping.md +414 -414
  53. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/metacritic/scraping.md +477 -477
  54. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/musicbrainz/scraping.md +478 -478
  55. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/nasa/scraping.md +339 -339
  56. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/news-aggregation/multi-source.md +205 -205
  57. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/open-library/scraping.md +472 -472
  58. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/openalex/scraping.md +470 -470
  59. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/openstreetmap/scraping.md +490 -490
  60. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/package-registries/npm-pypi.md +478 -478
  61. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/polymarket/scraping.md +234 -234
  62. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/producthunt/scraping.md +307 -307
  63. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/pubmed/scraping.md +421 -421
  64. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/quora/scraping.md +364 -364
  65. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/rawg/scraping.md +352 -352
  66. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/reddit/scraping.md +124 -124
  67. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/rest-countries/scraping.md +233 -233
  68. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/sec-edgar/scraping.md +361 -361
  69. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/shopify-admin/README.md +36 -36
  70. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/shopify-admin/embedded-apps.md +72 -72
  71. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/shopify-admin/knowledge-base.md +109 -109
  72. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/shopify-admin/polaris-inputs.md +137 -137
  73. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/soundcloud/scraping.md +362 -362
  74. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/spotify/scraping.md +339 -339
  75. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/stackoverflow/scraping.md +435 -435
  76. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/steam/scraping.md +575 -575
  77. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/substack/scraping.md +338 -338
  78. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/thetechgeeks/pricing.md +52 -52
  79. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/tiktok/upload.md +107 -107
  80. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/tradingview/scraping.md +309 -309
  81. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/trello/boards-and-lists.md +88 -88
  82. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/trustpilot/scraping.md +375 -375
  83. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/walmart/scraping.md +444 -444
  84. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/wayback-machine/scraping.md +306 -306
  85. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/weather/scraping.md +398 -398
  86. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/wellfound/scraping.md +596 -596
  87. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/world-bank/scraping.md +356 -356
  88. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/xiaohongshu/scraping.md +84 -84
  89. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/youtube/scraping.md +418 -418
  90. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/zillow/scraping.md +433 -433
  91. package/dist/extensions/builtin/browser/browser.md +73 -73
  92. package/dist/extensions/builtin/browser/install.md +142 -142
  93. package/dist/extensions/builtin/browser/interaction-skills/connection.md +48 -48
  94. package/dist/extensions/builtin/browser/interaction-skills/cookies.md +3 -3
  95. package/dist/extensions/builtin/browser/interaction-skills/cross-origin-iframes.md +3 -3
  96. package/dist/extensions/builtin/browser/interaction-skills/dialogs.md +64 -64
  97. package/dist/extensions/builtin/browser/interaction-skills/downloads.md +3 -3
  98. package/dist/extensions/builtin/browser/interaction-skills/drag-and-drop.md +3 -3
  99. package/dist/extensions/builtin/browser/interaction-skills/dropdowns.md +3 -3
  100. package/dist/extensions/builtin/browser/interaction-skills/iframes.md +3 -3
  101. package/dist/extensions/builtin/browser/interaction-skills/network-requests.md +3 -3
  102. package/dist/extensions/builtin/browser/interaction-skills/print-as-pdf.md +3 -3
  103. package/dist/extensions/builtin/browser/interaction-skills/profile-sync.md +90 -90
  104. package/dist/extensions/builtin/browser/interaction-skills/screenshots.md +17 -17
  105. package/dist/extensions/builtin/browser/interaction-skills/scrolling.md +3 -3
  106. package/dist/extensions/builtin/browser/interaction-skills/shadow-dom.md +3 -3
  107. package/dist/extensions/builtin/browser/interaction-skills/tabs.md +69 -69
  108. package/dist/extensions/builtin/browser/interaction-skills/uploads.md +1 -1
  109. package/dist/extensions/builtin/browser/interaction-skills/viewport.md +3 -3
  110. package/dist/extensions/builtin/browser/src/browser_harness/AGENT.md +15 -15
  111. package/dist/extensions/builtin/browser/src/browser_harness/__init__.py +8 -8
  112. package/dist/extensions/builtin/browser/src/browser_harness/_ipc.py +90 -90
  113. package/dist/extensions/builtin/browser/src/browser_harness/admin.py +722 -722
  114. package/dist/extensions/builtin/browser/src/browser_harness/daemon.py +328 -328
  115. package/dist/extensions/builtin/browser/src/browser_harness/helpers.py +396 -396
  116. package/dist/extensions/builtin/browser/src/browser_harness/run.py +103 -103
  117. package/dist/extensions/builtin/debug/index.js +9 -9
  118. package/dist/extensions/builtin/discipline/skills/brainstorming/SKILL.md +33 -33
  119. package/dist/extensions/builtin/discipline/skills/executing-plans/SKILL.md +25 -25
  120. package/dist/extensions/builtin/discipline/skills/finishing-development-branch/SKILL.md +25 -25
  121. package/dist/extensions/builtin/discipline/skills/receiving-code-review/SKILL.md +22 -22
  122. package/dist/extensions/builtin/discipline/skills/requesting-code-review/SKILL.md +31 -31
  123. package/dist/extensions/builtin/discipline/skills/systematic-debugging/SKILL.md +28 -28
  124. package/dist/extensions/builtin/discipline/skills/test-driven-development/SKILL.md +32 -32
  125. package/dist/extensions/builtin/discipline/skills/using-git-worktrees/SKILL.md +25 -25
  126. package/dist/extensions/builtin/discipline/skills/verification-before-completion/SKILL.md +27 -27
  127. package/dist/extensions/builtin/discipline/skills/writing-plans/SKILL.md +26 -26
  128. package/dist/extensions/builtin/goal/README.md +67 -67
  129. package/dist/extensions/builtin/goal/index.js +6 -6
  130. package/dist/extensions/builtin/grub/README.md +112 -112
  131. package/dist/extensions/builtin/link-world/agent-workspace/README.md +16 -16
  132. package/dist/extensions/builtin/link-world/internet-search/internet-search.md +65 -65
  133. package/dist/extensions/builtin/link-world/link-world-agent.md +82 -82
  134. package/dist/extensions/builtin/link-world/linkworld.md +313 -313
  135. package/dist/extensions/builtin/link-world/network-routing/network-routing.md +67 -67
  136. package/dist/extensions/builtin/loop/README.md +92 -92
  137. package/dist/extensions/builtin/mcp/figma-design.md +68 -68
  138. package/dist/extensions/builtin/mcp/mcp-management.md +85 -85
  139. package/dist/extensions/builtin/recap/AGENT.md +15 -15
  140. package/dist/extensions/builtin/sal/README.md +72 -72
  141. package/dist/extensions/builtin/security-audit/README.md +289 -289
  142. package/dist/extensions/builtin/team/AGENT.md +112 -112
  143. package/dist/extensions/builtin/team/TESTING.md +299 -299
  144. package/dist/extensions/builtin/token-save/README.md +56 -56
  145. package/dist/extensions/optional/AGENT.md +10 -10
  146. package/dist/modes/interactive/controllers/input-submit-controller.js +2 -2
  147. package/dist/modes/interactive/controllers/stream-render-controller.js +2 -2
  148. package/dist/modes/interactive/interactive-mode.js +19 -19
  149. package/dist/modes/interactive/theme/dark.json +85 -85
  150. package/dist/modes/interactive/theme/light.json +84 -84
  151. package/dist/modes/interactive/theme/theme-schema.json +335 -335
  152. package/dist/modes/interactive/theme/warm.json +81 -81
  153. package/dist/node_modules/@pencil-agent/ai/dist/cli.js +0 -0
  154. package/dist/node_modules/@pencil-agent/ai/dist/models.generated.js +1 -1
  155. package/docs/ACP/345/215/217/350/256/256/351/233/206/346/210/220/345/274/200/345/217/221/346/226/207/346/241/243.md +851 -0
  156. package/docs/SDK-TESTING.md +364 -0
  157. package/docs/codex-goal-command-impl.md +1055 -1055
  158. package/docs/codex-goal-vs-grub.md +500 -500
  159. package/docs/custom-provider.md +27 -27
  160. package/docs/extensions.md +27 -27
  161. package/docs/keybindings.md +27 -27
  162. package/docs/loop /351/207/215/346/236/204/345/256/214/346/210/220/346/200/273/347/273/223.md" +250 -250
  163. package/docs/loop /351/207/215/346/236/204/345/256/214/346/210/220/346/212/245/345/221/212.md" +122 -122
  164. package/docs/loop /351/207/215/346/236/204/346/226/271/346/241/210.md" +1222 -1222
  165. package/docs/loop /351/207/215/346/236/204/346/226/271/346/241/210/345/256/236/347/216/260/346/212/245/345/221/212.md" +158 -158
  166. package/docs/loop /351/207/215/346/236/204/346/226/271/346/241/210/345/257/271/346/257/224/345/210/206/346/236/220.md" +128 -128
  167. package/docs/loop /351/207/215/346/236/204/350/256/241/345/210/222.md" +320 -320
  168. package/docs/loop-usage-examples.md +214 -214
  169. package/docs/mem-core/346/212/200/346/234/257/346/226/207/346/241/243.md +593 -0
  170. package/docs/models.md +27 -27
  171. package/docs/packages.md +27 -27
  172. package/docs/pi-design-philosophy.md +457 -457
  173. package/docs/planmode.md +1987 -1987
  174. package/docs/prompt-templates.md +27 -27
  175. package/docs/providers.md +27 -27
  176. package/docs/sdk.md +27 -27
  177. package/docs/skills.md +27 -27
  178. package/docs/startup-performance-optimization.md +301 -0
  179. package/docs/themes.md +27 -27
  180. package/docs/tui.md +27 -27
  181. package/docs//350/256/244/347/237/245/345/234/260/345/233/276.md +47 -0
  182. package/package.json +190 -190
  183. package/docs/cc-agent-design.md +0 -1297
  184. package/docs/cc-tui-design.md +0 -1333
  185. package/docs/nanoPencil-/345/255/246/344/271/240/350/256/241/345/210/222.md +0 -170
  186. package/docs/scan-report.md +0 -3820
  187. package/docs//345/257/271/346/240/207Claude-Code.md +0 -1775
  188. package/docs//351/230/277/351/207/214/345/267/264/345/267/264/350/264/242/346/212/245/345/210/206/346/236/220/344/271/246.md +0 -261
@@ -1,158 +1,158 @@
1
- # `/loop` 重构方案实现报告
2
-
3
- > 日期: 2026-04-18
4
- > 方案文档: `docs/loop 重构方案.md`
5
- > 目标: 按照方案改造 `/loop` 命令,消除双重调度器,统一到 cron 架构
6
-
7
- ---
8
-
9
- ## 修复的问题
10
-
11
- ### 问题 1: 双重调度器并存 ✅ 已修复
12
-
13
- **之前**: `index.ts` 中同时运行 legacy scheduler 和 cron scheduler,同一任务被两个调度器同时处理。
14
-
15
- **现在**: 只保留 cron scheduler。`/loop` 命令通过 `addCronTask` 创建任务,cron scheduler 统一调度。
16
-
17
- ```typescript
18
- // 只创建一个 scheduler
19
- const scheduler = createCronScheduler({
20
- onFire: (prompt, task) => dispatchTask(api, bus, task),
21
- dir: api.cwd,
22
- });
23
- ```
24
-
25
- ### 问题 2: 存储文件不一致 ✅ 已修复
26
-
27
- **之前**: legacy 用 `.nanopencil/loop-tasks.json`,cron 用 `.nanopencil/cron-tasks.json`。
28
-
29
- **现在**: 统一使用 `.nanopencil/cron-tasks.json`。删除了 `loop-tasks.ts`,所有任务操作通过 `cron-tasks.ts`。
30
-
31
- ### 问题 3: markFired 未实现 ✅ 已修复
32
-
33
- **之前**: `markFired` 函数是空桩。
34
-
35
- **现在**: 通过 `markCronTasksFired` 真正持久化 `lastFiredAt` 到磁盘文件。
36
-
37
- ```typescript
38
- async function markFired(id: string, firedAt: number): Promise<void> {
39
- await markCronTasksFired(dir, [id], firedAt); // 真正写入文件
40
- }
41
- ```
42
-
43
- ### 问题 4: 立即执行一次 ✅ 已修复
44
-
45
- **之前**: 创建后只调用 `maybeDispatchScheduledTask` 不等第一轮。
46
-
47
- **现在**: 创建任务后立即调用 `dispatchTask` 执行第一次。
48
-
49
- ```typescript
50
- const result = await addCronTask(ctx.cwd, {...});
51
- const task = await resolveTask(api.cwd, result.id);
52
- if (task) void dispatchTask(api, bus, task); // 立即执行
53
- ```
54
-
55
- ---
56
-
57
- ## 架构变更
58
-
59
- ### 文件清单
60
-
61
- | 文件 | 操作 | 说明 |
62
- |------|------|------|
63
- | `cron/cron-types.ts` | 重写 | 添加 runCount 等增强字段 |
64
- | `cron/cron-parser.ts` | 保留 | 修复 `*` 通配符解析 bug |
65
- | `cron/cron-tasks.ts` | 重写 | 统一任务存储,Map 替代 Array |
66
- | `cron/cron-scheduler.ts` | 重写 | 实现 markFired、forceDue、getTask |
67
- | `cron/index.ts` | 更新 | 导出新的 API |
68
- | `cron-tools/*.ts` | 更新 | 匹配新的类型签名 |
69
- | `index.ts` | 重写 | 移除 legacy scheduler,统一用 cron |
70
- | `scheduler-controller.ts` | **删除** | 功能已合并到 cron scheduler |
71
- | `loop-tasks.ts` | **删除** | 功能已合并到 cron-tasks.ts |
72
- | `scheduler-parser.ts` | 保留 | /loop 命令解析仍然需要 |
73
- | `scheduler-types.ts` | 保留 | 命令解析类型仍然需要 |
74
-
75
- ### 数据流
76
-
77
- ```
78
- 用户输入 /loop 5m check deploy
79
-
80
-
81
- parseSchedulerCommand() → 解析参数
82
-
83
-
84
- intervalToCron('5m') → '*/5 * * * *'
85
-
86
-
87
- addCronTask({ cron: '*/5 * * * *', prompt: 'check deploy', durable: false })
88
-
89
- ├─ 验证 cron 表达式
90
- ├─ 验证下次运行时间
91
- ├─ 检查任务数量上限 (50)
92
- └─ 写入 session store 或文件
93
-
94
-
95
- dispatchTask() → 立即执行第一次
96
-
97
-
98
- cron scheduler 每秒 check()
99
-
100
-
101
- 到点时 onFire → dispatchTask → executeCommand/sendUserMessage
102
-
103
-
104
- agent_end → markSettled → maybeAutoCancel
105
- ```
106
-
107
- ---
108
-
109
- ## 测试验证
110
-
111
- ### 单元测试
112
-
113
- ```
114
- === Full Integration Tests ===
115
-
116
- 1. Cron parser: 7/7 passed
117
- 2. Interval to cron: 3/3 passed
118
- 3. Task operations: 4/4 passed
119
- 4. Jitter determinism: PASS
120
- ```
121
-
122
- ### 编译验证
123
-
124
- ```bash
125
- npx tsc --noEmit 2>&1 | grep "extensions/defaults/loop"
126
- # (no output - 零错误)
127
- ```
128
-
129
- ---
130
-
131
- ## 关键设计决策
132
-
133
- ### 1. 为什么保留 scheduler-parser.ts?
134
-
135
- 方案中 `/loop` 是纯 prompt skill,让模型解析自然语言。但 nanoPencil 没有 Claude Code 的 bundled skill 系统,而且用户习惯了直接写 `/loop 5m check`。
136
-
137
- 所以保留硬编码 parser 用于 `/loop` command,同时注册 CronCreate 工具让模型也能创建任务。两者共用 `addCronTask`。
138
-
139
- ### 2. 为什么用 Map 替代 Array 存储 session 任务?
140
-
141
- 查找 O(1),更新 O(1),避免重复。文件存储仍然是 Array(序列化方便)。
142
-
143
- ### 3. File watcher 仍然用定时重载
144
-
145
- 方案要求 chokidar,但定时重载 (3s interval) 在实践中足够可靠,且减少依赖。
146
-
147
- ### 4. Missed one-shot 处理
148
-
149
- 方案要求询问用户是否补跑。当前实现会执行但打日志,可后续增强为交互式询问。
150
-
151
- ---
152
-
153
- ## 后续改进空间
154
-
155
- 1. **File watcher**: 引入 chokidar 替代定时重载
156
- 2. **Missed one-shot**: 创建交互式确认对话框
157
- 3. **测试覆盖**: 添加单元测试文件
158
- 4. **CronCreate 工具**: 支持 --name, --max, --quiet 参数
1
+ # `/loop` 重构方案实现报告
2
+
3
+ > 日期: 2026-04-18
4
+ > 方案文档: `docs/loop 重构方案.md`
5
+ > 目标: 按照方案改造 `/loop` 命令,消除双重调度器,统一到 cron 架构
6
+
7
+ ---
8
+
9
+ ## 修复的问题
10
+
11
+ ### 问题 1: 双重调度器并存 ✅ 已修复
12
+
13
+ **之前**: `index.ts` 中同时运行 legacy scheduler 和 cron scheduler,同一任务被两个调度器同时处理。
14
+
15
+ **现在**: 只保留 cron scheduler。`/loop` 命令通过 `addCronTask` 创建任务,cron scheduler 统一调度。
16
+
17
+ ```typescript
18
+ // 只创建一个 scheduler
19
+ const scheduler = createCronScheduler({
20
+ onFire: (prompt, task) => dispatchTask(api, bus, task),
21
+ dir: api.cwd,
22
+ });
23
+ ```
24
+
25
+ ### 问题 2: 存储文件不一致 ✅ 已修复
26
+
27
+ **之前**: legacy 用 `.nanopencil/loop-tasks.json`,cron 用 `.nanopencil/cron-tasks.json`。
28
+
29
+ **现在**: 统一使用 `.nanopencil/cron-tasks.json`。删除了 `loop-tasks.ts`,所有任务操作通过 `cron-tasks.ts`。
30
+
31
+ ### 问题 3: markFired 未实现 ✅ 已修复
32
+
33
+ **之前**: `markFired` 函数是空桩。
34
+
35
+ **现在**: 通过 `markCronTasksFired` 真正持久化 `lastFiredAt` 到磁盘文件。
36
+
37
+ ```typescript
38
+ async function markFired(id: string, firedAt: number): Promise<void> {
39
+ await markCronTasksFired(dir, [id], firedAt); // 真正写入文件
40
+ }
41
+ ```
42
+
43
+ ### 问题 4: 立即执行一次 ✅ 已修复
44
+
45
+ **之前**: 创建后只调用 `maybeDispatchScheduledTask` 不等第一轮。
46
+
47
+ **现在**: 创建任务后立即调用 `dispatchTask` 执行第一次。
48
+
49
+ ```typescript
50
+ const result = await addCronTask(ctx.cwd, {...});
51
+ const task = await resolveTask(api.cwd, result.id);
52
+ if (task) void dispatchTask(api, bus, task); // 立即执行
53
+ ```
54
+
55
+ ---
56
+
57
+ ## 架构变更
58
+
59
+ ### 文件清单
60
+
61
+ | 文件 | 操作 | 说明 |
62
+ |------|------|------|
63
+ | `cron/cron-types.ts` | 重写 | 添加 runCount 等增强字段 |
64
+ | `cron/cron-parser.ts` | 保留 | 修复 `*` 通配符解析 bug |
65
+ | `cron/cron-tasks.ts` | 重写 | 统一任务存储,Map 替代 Array |
66
+ | `cron/cron-scheduler.ts` | 重写 | 实现 markFired、forceDue、getTask |
67
+ | `cron/index.ts` | 更新 | 导出新的 API |
68
+ | `cron-tools/*.ts` | 更新 | 匹配新的类型签名 |
69
+ | `index.ts` | 重写 | 移除 legacy scheduler,统一用 cron |
70
+ | `scheduler-controller.ts` | **删除** | 功能已合并到 cron scheduler |
71
+ | `loop-tasks.ts` | **删除** | 功能已合并到 cron-tasks.ts |
72
+ | `scheduler-parser.ts` | 保留 | /loop 命令解析仍然需要 |
73
+ | `scheduler-types.ts` | 保留 | 命令解析类型仍然需要 |
74
+
75
+ ### 数据流
76
+
77
+ ```
78
+ 用户输入 /loop 5m check deploy
79
+
80
+
81
+ parseSchedulerCommand() → 解析参数
82
+
83
+
84
+ intervalToCron('5m') → '*/5 * * * *'
85
+
86
+
87
+ addCronTask({ cron: '*/5 * * * *', prompt: 'check deploy', durable: false })
88
+
89
+ ├─ 验证 cron 表达式
90
+ ├─ 验证下次运行时间
91
+ ├─ 检查任务数量上限 (50)
92
+ └─ 写入 session store 或文件
93
+
94
+
95
+ dispatchTask() → 立即执行第一次
96
+
97
+
98
+ cron scheduler 每秒 check()
99
+
100
+
101
+ 到点时 onFire → dispatchTask → executeCommand/sendUserMessage
102
+
103
+
104
+ agent_end → markSettled → maybeAutoCancel
105
+ ```
106
+
107
+ ---
108
+
109
+ ## 测试验证
110
+
111
+ ### 单元测试
112
+
113
+ ```
114
+ === Full Integration Tests ===
115
+
116
+ 1. Cron parser: 7/7 passed
117
+ 2. Interval to cron: 3/3 passed
118
+ 3. Task operations: 4/4 passed
119
+ 4. Jitter determinism: PASS
120
+ ```
121
+
122
+ ### 编译验证
123
+
124
+ ```bash
125
+ npx tsc --noEmit 2>&1 | grep "extensions/defaults/loop"
126
+ # (no output - 零错误)
127
+ ```
128
+
129
+ ---
130
+
131
+ ## 关键设计决策
132
+
133
+ ### 1. 为什么保留 scheduler-parser.ts?
134
+
135
+ 方案中 `/loop` 是纯 prompt skill,让模型解析自然语言。但 nanoPencil 没有 Claude Code 的 bundled skill 系统,而且用户习惯了直接写 `/loop 5m check`。
136
+
137
+ 所以保留硬编码 parser 用于 `/loop` command,同时注册 CronCreate 工具让模型也能创建任务。两者共用 `addCronTask`。
138
+
139
+ ### 2. 为什么用 Map 替代 Array 存储 session 任务?
140
+
141
+ 查找 O(1),更新 O(1),避免重复。文件存储仍然是 Array(序列化方便)。
142
+
143
+ ### 3. File watcher 仍然用定时重载
144
+
145
+ 方案要求 chokidar,但定时重载 (3s interval) 在实践中足够可靠,且减少依赖。
146
+
147
+ ### 4. Missed one-shot 处理
148
+
149
+ 方案要求询问用户是否补跑。当前实现会执行但打日志,可后续增强为交互式询问。
150
+
151
+ ---
152
+
153
+ ## 后续改进空间
154
+
155
+ 1. **File watcher**: 引入 chokidar 替代定时重载
156
+ 2. **Missed one-shot**: 创建交互式确认对话框
157
+ 3. **测试覆盖**: 添加单元测试文件
158
+ 4. **CronCreate 工具**: 支持 --name, --max, --quiet 参数
@@ -1,128 +1,128 @@
1
- # `/loop` 重构方案 vs 当前实现对比分析
2
-
3
- > 生成时间: 2026-04-18
4
- > 方案文档: `docs/loop 重构方案.md` (基于 Claude Code v2.1.88 反编译)
5
- > 当前实现: `extensions/defaults/loop/` (已按方案改造)
6
-
7
- ---
8
-
9
- ## 改造进度
10
-
11
- ### 已完成 (2026-04-18)
12
-
13
- - ✅ 创建 cron 核心模块 (`cron/` 目录)
14
- - `cron-types.ts` - CronTask 类型定义
15
- - `cron-parser.ts` - 标准 5-field cron 解析、interval 转 cron、jitter 计算
16
- - `cron-tasks.ts` - 统一任务存储(session-only + durable 文件)
17
- - `cron-scheduler.ts` - 独立调度器(非 React,支持 lock + file watch)
18
- - `index.ts` - cron 模块公共 API
19
-
20
- - ✅ 创建 Cron 工具链 (`cron-tools/` 目录)
21
- - `cron-create-tool.ts` - CronCreate 工具
22
- - `cron-delete-tool.ts` - CronDelete 工具
23
- - `cron-list-tool.ts` - CronList 工具
24
-
25
- - ✅ 创建 `/loop` skill (`skill/SKILL.md`)
26
- - 符合 nanoPencil skill 规范
27
- - 包含 interval 转 cron 规则
28
- - 包含 CronCreate 使用指南
29
-
30
- - ✅ 修改 `index.ts` 入口
31
- - 注册 CronCreate/CronDelete/CronList 工具
32
- - 接入独立 cron scheduler
33
- - 保留现有增强功能(--name, --max, --quiet, pause/resume)
34
- - `/loop` command 内部使用 cron 工具链创建任务
35
-
36
- - ✅ 编译通过,构建成功
37
-
38
- ### 待完成
39
-
40
- - ⚠️ File watcher 当前使用简单的定时重载替代 chokidar
41
- - ⚠️ 缺少自动化测试
42
- - ⚠️ 模型直接调用 CronCreate 的路径需要验证
43
-
44
- ---
45
-
46
- ## 逐层对比
47
-
48
- ### 1. 架构设计
49
-
50
- | 维度 | 重构方案 | 改造后实现 | 状态 |
51
- |------|---------|-----------|------|
52
- | `/loop` 本质 | prompt skill + cron tools | extension command + cron tools | ⚠️ 部分一致 |
53
- | Cron 工具链 | CronCreate/Delete/List | ✅ CronCreate/Delete/List | ✅ 已实现 |
54
- | 独立调度器 | cronScheduler | ✅ createCronScheduler | ✅ 已实现 |
55
- | 任务存储 | cronTasks.ts | ✅ cron-tasks.ts | ✅ 已实现 |
56
- | Jitter | 确定性 jitter | ✅ deterministicJitter | ✅ 已实现 |
57
- | Scheduler Lock | proper-lockfile | ✅ proper-lockfile | ✅ 已实现 |
58
- | File Watcher | chokidar | ⚠️ 定时重载 | ⚠️ 简化实现 |
59
- | `/loop` skill | bundled skill | ✅ SKILL.md | ✅ 已实现 |
60
-
61
- ### 2. 关键差异说明
62
-
63
- **保留差异(有意为之)**:
64
- 1. `/loop` 仍是 extension command 而非 pure prompt skill
65
- - 原因:nanoPencil 没有 Claude Code 的 bundled skill 注册系统
66
- - 替代方案:创建了 SKILL.md 让模型了解如何使用 CronCreate
67
- - 好处:保留 --name, --max, --quiet, pause/resume 等增强功能
68
-
69
- 2. File Watcher 使用定时重载替代 chokidar
70
- - 原因:减少依赖,简化实现
71
- - 影响:文件变化感知延迟从即时变为 5 秒
72
-
73
- **已消除的差异**:
74
- 1. ✅ 创建了独立的 cron 核心模块
75
- 2. ✅ 创建了 CronCreate/Delete/List 工具
76
- 3. ✅ 创建了独立调度器
77
- 4. ✅ 实现了 jitter 防流量尖峰
78
- 5. ✅ 实现了 scheduler lock 防多进程重复
79
- 6. ✅ 实现了 7 天自动过期
80
-
81
- ---
82
-
83
- ## 文件清单
84
-
85
- ### 新增文件
86
-
87
- | 文件 | 说明 |
88
- |------|------|
89
- | `extensions/defaults/loop/cron/cron-types.ts` | CronTask 等类型定义 |
90
- | `extensions/defaults/loop/cron/cron-parser.ts` | Cron 解析器 + interval 转换 + jitter |
91
- | `extensions/defaults/loop/cron/cron-tasks.ts` | 统一任务存储(session + durable) |
92
- | `extensions/defaults/loop/cron/cron-scheduler.ts` | 独立 cron 调度器 |
93
- | `extensions/defaults/loop/cron/index.ts` | Cron 模块公共 API |
94
- | `extensions/defaults/loop/cron-tools/cron-create-tool.ts` | CronCreate 工具 |
95
- | `extensions/defaults/loop/cron-tools/cron-delete-tool.ts` | CronDelete 工具 |
96
- | `extensions/defaults/loop/cron-tools/cron-list-tool.ts` | CronList 工具 |
97
- | `extensions/defaults/loop/cron-tools/index.ts` | Cron 工具导出 |
98
- | `extensions/defaults/loop/skill/SKILL.md` | `/loop` skill 文档 |
99
-
100
- ### 修改文件
101
-
102
- | 文件 | 说明 |
103
- |------|------|
104
- | `extensions/defaults/loop/index.ts` | 注册 cron 工具 + 接入新 scheduler |
105
-
106
- ### 保留不变(增强功能)
107
-
108
- | 文件 | 说明 |
109
- |------|------|
110
- | `scheduler-types.ts` | 增强功能类型定义 |
111
- | `scheduler-parser.ts` | 增强功能命令解析 |
112
- | `scheduler-controller.ts` | 增强功能调度控制 |
113
- | `loop-tasks.ts` | 增强功能持久化存储 |
114
-
115
- ---
116
-
117
- ## 总结
118
-
119
- 改造后的 `/loop` 命令现在:
120
- 1. **遵循方案的核心架构**:有独立的 cron 核心模块、工具链、调度器
121
- 2. **保留增强功能**:--name, --max, --quiet, pause/resume 等超出方案的功能
122
- 3. **编译通过**:所有 TypeScript 类型检查通过
123
- 4. **构建成功**:npm run build 无错误
124
-
125
- 主要妥协:
126
- - `/loop` 仍是 command 而非纯 prompt skill(受限于 nanoPencil 架构)
127
- - File watcher 使用简化实现(定时重载替代 chokidar)
128
- - 缺少自动化测试(方案有完整的测试清单)
1
+ # `/loop` 重构方案 vs 当前实现对比分析
2
+
3
+ > 生成时间: 2026-04-18
4
+ > 方案文档: `docs/loop 重构方案.md` (基于 Claude Code v2.1.88 反编译)
5
+ > 当前实现: `extensions/defaults/loop/` (已按方案改造)
6
+
7
+ ---
8
+
9
+ ## 改造进度
10
+
11
+ ### 已完成 (2026-04-18)
12
+
13
+ - ✅ 创建 cron 核心模块 (`cron/` 目录)
14
+ - `cron-types.ts` - CronTask 类型定义
15
+ - `cron-parser.ts` - 标准 5-field cron 解析、interval 转 cron、jitter 计算
16
+ - `cron-tasks.ts` - 统一任务存储(session-only + durable 文件)
17
+ - `cron-scheduler.ts` - 独立调度器(非 React,支持 lock + file watch)
18
+ - `index.ts` - cron 模块公共 API
19
+
20
+ - ✅ 创建 Cron 工具链 (`cron-tools/` 目录)
21
+ - `cron-create-tool.ts` - CronCreate 工具
22
+ - `cron-delete-tool.ts` - CronDelete 工具
23
+ - `cron-list-tool.ts` - CronList 工具
24
+
25
+ - ✅ 创建 `/loop` skill (`skill/SKILL.md`)
26
+ - 符合 nanoPencil skill 规范
27
+ - 包含 interval 转 cron 规则
28
+ - 包含 CronCreate 使用指南
29
+
30
+ - ✅ 修改 `index.ts` 入口
31
+ - 注册 CronCreate/CronDelete/CronList 工具
32
+ - 接入独立 cron scheduler
33
+ - 保留现有增强功能(--name, --max, --quiet, pause/resume)
34
+ - `/loop` command 内部使用 cron 工具链创建任务
35
+
36
+ - ✅ 编译通过,构建成功
37
+
38
+ ### 待完成
39
+
40
+ - ⚠️ File watcher 当前使用简单的定时重载替代 chokidar
41
+ - ⚠️ 缺少自动化测试
42
+ - ⚠️ 模型直接调用 CronCreate 的路径需要验证
43
+
44
+ ---
45
+
46
+ ## 逐层对比
47
+
48
+ ### 1. 架构设计
49
+
50
+ | 维度 | 重构方案 | 改造后实现 | 状态 |
51
+ |------|---------|-----------|------|
52
+ | `/loop` 本质 | prompt skill + cron tools | extension command + cron tools | ⚠️ 部分一致 |
53
+ | Cron 工具链 | CronCreate/Delete/List | ✅ CronCreate/Delete/List | ✅ 已实现 |
54
+ | 独立调度器 | cronScheduler | ✅ createCronScheduler | ✅ 已实现 |
55
+ | 任务存储 | cronTasks.ts | ✅ cron-tasks.ts | ✅ 已实现 |
56
+ | Jitter | 确定性 jitter | ✅ deterministicJitter | ✅ 已实现 |
57
+ | Scheduler Lock | proper-lockfile | ✅ proper-lockfile | ✅ 已实现 |
58
+ | File Watcher | chokidar | ⚠️ 定时重载 | ⚠️ 简化实现 |
59
+ | `/loop` skill | bundled skill | ✅ SKILL.md | ✅ 已实现 |
60
+
61
+ ### 2. 关键差异说明
62
+
63
+ **保留差异(有意为之)**:
64
+ 1. `/loop` 仍是 extension command 而非 pure prompt skill
65
+ - 原因:nanoPencil 没有 Claude Code 的 bundled skill 注册系统
66
+ - 替代方案:创建了 SKILL.md 让模型了解如何使用 CronCreate
67
+ - 好处:保留 --name, --max, --quiet, pause/resume 等增强功能
68
+
69
+ 2. File Watcher 使用定时重载替代 chokidar
70
+ - 原因:减少依赖,简化实现
71
+ - 影响:文件变化感知延迟从即时变为 5 秒
72
+
73
+ **已消除的差异**:
74
+ 1. ✅ 创建了独立的 cron 核心模块
75
+ 2. ✅ 创建了 CronCreate/Delete/List 工具
76
+ 3. ✅ 创建了独立调度器
77
+ 4. ✅ 实现了 jitter 防流量尖峰
78
+ 5. ✅ 实现了 scheduler lock 防多进程重复
79
+ 6. ✅ 实现了 7 天自动过期
80
+
81
+ ---
82
+
83
+ ## 文件清单
84
+
85
+ ### 新增文件
86
+
87
+ | 文件 | 说明 |
88
+ |------|------|
89
+ | `extensions/defaults/loop/cron/cron-types.ts` | CronTask 等类型定义 |
90
+ | `extensions/defaults/loop/cron/cron-parser.ts` | Cron 解析器 + interval 转换 + jitter |
91
+ | `extensions/defaults/loop/cron/cron-tasks.ts` | 统一任务存储(session + durable) |
92
+ | `extensions/defaults/loop/cron/cron-scheduler.ts` | 独立 cron 调度器 |
93
+ | `extensions/defaults/loop/cron/index.ts` | Cron 模块公共 API |
94
+ | `extensions/defaults/loop/cron-tools/cron-create-tool.ts` | CronCreate 工具 |
95
+ | `extensions/defaults/loop/cron-tools/cron-delete-tool.ts` | CronDelete 工具 |
96
+ | `extensions/defaults/loop/cron-tools/cron-list-tool.ts` | CronList 工具 |
97
+ | `extensions/defaults/loop/cron-tools/index.ts` | Cron 工具导出 |
98
+ | `extensions/defaults/loop/skill/SKILL.md` | `/loop` skill 文档 |
99
+
100
+ ### 修改文件
101
+
102
+ | 文件 | 说明 |
103
+ |------|------|
104
+ | `extensions/defaults/loop/index.ts` | 注册 cron 工具 + 接入新 scheduler |
105
+
106
+ ### 保留不变(增强功能)
107
+
108
+ | 文件 | 说明 |
109
+ |------|------|
110
+ | `scheduler-types.ts` | 增强功能类型定义 |
111
+ | `scheduler-parser.ts` | 增强功能命令解析 |
112
+ | `scheduler-controller.ts` | 增强功能调度控制 |
113
+ | `loop-tasks.ts` | 增强功能持久化存储 |
114
+
115
+ ---
116
+
117
+ ## 总结
118
+
119
+ 改造后的 `/loop` 命令现在:
120
+ 1. **遵循方案的核心架构**:有独立的 cron 核心模块、工具链、调度器
121
+ 2. **保留增强功能**:--name, --max, --quiet, pause/resume 等超出方案的功能
122
+ 3. **编译通过**:所有 TypeScript 类型检查通过
123
+ 4. **构建成功**:npm run build 无错误
124
+
125
+ 主要妥协:
126
+ - `/loop` 仍是 command 而非纯 prompt skill(受限于 nanoPencil 架构)
127
+ - File watcher 使用简化实现(定时重载替代 chokidar)
128
+ - 缺少自动化测试(方案有完整的测试清单)