@pencil-agent/nano-pencil 2.0.0 → 2.0.1

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 (195) 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/mcp/mcp-client.d.ts +3 -1
  7. package/dist/core/mcp/mcp-client.js +6 -6
  8. package/dist/core/mcp/mcp-config.d.ts +3 -3
  9. package/dist/core/mcp/mcp-config.js +1 -1
  10. package/dist/core/mcp/mcp-manager.d.ts +5 -1
  11. package/dist/core/mcp/mcp-manager.js +1 -1
  12. package/dist/core/platform/config/resource-loader.d.ts +2 -0
  13. package/dist/core/platform/config/resource-loader.js +2 -2
  14. package/dist/core/runtime/agent-session.d.ts +12 -0
  15. package/dist/core/runtime/agent-session.js +8 -8
  16. package/dist/core/runtime/sdk.d.ts +8 -0
  17. package/dist/core/runtime/sdk.js +1 -1
  18. package/dist/extensions/builtin/AGENT.md +115 -115
  19. package/dist/extensions/builtin/browser/AGENT.md +17 -17
  20. package/dist/extensions/builtin/browser/agent-workspace/agent_helpers.py +12 -12
  21. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/amazon/product-search.md +198 -198
  22. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/archive-org/scraping.md +341 -341
  23. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/arxiv/scraping.md +311 -311
  24. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/arxiv-bulk/scraping.md +333 -333
  25. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/atlas/overview.md +70 -70
  26. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/booking-com/scraping.md +578 -578
  27. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/capterra/scraping.md +440 -440
  28. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/centilebrain/generate-estimates.md +110 -110
  29. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/coingecko/scraping.md +325 -325
  30. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/coinmarketcap/scraping.md +463 -463
  31. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/coursera/scraping.md +360 -360
  32. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/craigslist/scraping.md +390 -390
  33. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/crossref/scraping.md +568 -568
  34. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/dev-to/scraping.md +323 -323
  35. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/duckduckgo/scraping.md +349 -349
  36. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/ebay/scraping.md +435 -435
  37. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/etsy/scraping.md +506 -506
  38. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/eventbrite/scraping.md +363 -363
  39. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/expedia/automation.md +168 -168
  40. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/facebook/groups.md +236 -236
  41. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/facebook/pages.md +295 -295
  42. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/framer/editor.md +108 -108
  43. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/fred/scraping.md +493 -493
  44. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/g2/scraping.md +580 -580
  45. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/genius/scraping.md +511 -511
  46. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/github/repo-actions.md +65 -65
  47. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/github/scraping.md +184 -184
  48. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/glassdoor/scraping.md +543 -543
  49. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/gmail/compose.md +122 -122
  50. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/goodreads/scraping.md +461 -461
  51. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/gutenberg/scraping.md +383 -383
  52. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/hackernews/scraping.md +243 -243
  53. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/howlongtobeat/scraping.md +473 -473
  54. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/imdb/scraping.md +271 -271
  55. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/itch-io/scraping.md +436 -436
  56. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/job-boards/indeed-glassdoor.md +1021 -1021
  57. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/letterboxd/scraping.md +349 -349
  58. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/linkedin/invitation-manager.md +109 -109
  59. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/loom/folder-enumeration.md +170 -170
  60. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/macrotrends/scraping.md +537 -537
  61. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/medium/article-hydration.md +120 -120
  62. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/medium/scraping.md +414 -414
  63. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/metacritic/scraping.md +477 -477
  64. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/musicbrainz/scraping.md +478 -478
  65. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/nasa/scraping.md +339 -339
  66. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/news-aggregation/multi-source.md +205 -205
  67. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/open-library/scraping.md +472 -472
  68. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/openalex/scraping.md +470 -470
  69. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/openstreetmap/scraping.md +490 -490
  70. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/package-registries/npm-pypi.md +478 -478
  71. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/polymarket/scraping.md +234 -234
  72. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/producthunt/scraping.md +307 -307
  73. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/pubmed/scraping.md +421 -421
  74. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/quora/scraping.md +364 -364
  75. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/rawg/scraping.md +352 -352
  76. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/reddit/scraping.md +124 -124
  77. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/rest-countries/scraping.md +233 -233
  78. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/sec-edgar/scraping.md +361 -361
  79. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/shopify-admin/README.md +36 -36
  80. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/shopify-admin/embedded-apps.md +72 -72
  81. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/shopify-admin/knowledge-base.md +109 -109
  82. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/shopify-admin/polaris-inputs.md +137 -137
  83. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/soundcloud/scraping.md +362 -362
  84. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/spotify/scraping.md +339 -339
  85. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/stackoverflow/scraping.md +435 -435
  86. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/steam/scraping.md +575 -575
  87. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/substack/scraping.md +338 -338
  88. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/thetechgeeks/pricing.md +52 -52
  89. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/tiktok/upload.md +107 -107
  90. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/tradingview/scraping.md +309 -309
  91. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/trello/boards-and-lists.md +88 -88
  92. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/trustpilot/scraping.md +375 -375
  93. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/walmart/scraping.md +444 -444
  94. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/wayback-machine/scraping.md +306 -306
  95. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/weather/scraping.md +398 -398
  96. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/wellfound/scraping.md +596 -596
  97. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/world-bank/scraping.md +356 -356
  98. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/xiaohongshu/scraping.md +84 -84
  99. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/youtube/scraping.md +418 -418
  100. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/zillow/scraping.md +433 -433
  101. package/dist/extensions/builtin/browser/browser.md +73 -73
  102. package/dist/extensions/builtin/browser/install.md +142 -142
  103. package/dist/extensions/builtin/browser/interaction-skills/connection.md +48 -48
  104. package/dist/extensions/builtin/browser/interaction-skills/cookies.md +3 -3
  105. package/dist/extensions/builtin/browser/interaction-skills/cross-origin-iframes.md +3 -3
  106. package/dist/extensions/builtin/browser/interaction-skills/dialogs.md +64 -64
  107. package/dist/extensions/builtin/browser/interaction-skills/downloads.md +3 -3
  108. package/dist/extensions/builtin/browser/interaction-skills/drag-and-drop.md +3 -3
  109. package/dist/extensions/builtin/browser/interaction-skills/dropdowns.md +3 -3
  110. package/dist/extensions/builtin/browser/interaction-skills/iframes.md +3 -3
  111. package/dist/extensions/builtin/browser/interaction-skills/network-requests.md +3 -3
  112. package/dist/extensions/builtin/browser/interaction-skills/print-as-pdf.md +3 -3
  113. package/dist/extensions/builtin/browser/interaction-skills/profile-sync.md +90 -90
  114. package/dist/extensions/builtin/browser/interaction-skills/screenshots.md +17 -17
  115. package/dist/extensions/builtin/browser/interaction-skills/scrolling.md +3 -3
  116. package/dist/extensions/builtin/browser/interaction-skills/shadow-dom.md +3 -3
  117. package/dist/extensions/builtin/browser/interaction-skills/tabs.md +69 -69
  118. package/dist/extensions/builtin/browser/interaction-skills/uploads.md +1 -1
  119. package/dist/extensions/builtin/browser/interaction-skills/viewport.md +3 -3
  120. package/dist/extensions/builtin/browser/src/browser_harness/AGENT.md +15 -15
  121. package/dist/extensions/builtin/browser/src/browser_harness/__init__.py +8 -8
  122. package/dist/extensions/builtin/browser/src/browser_harness/_ipc.py +90 -90
  123. package/dist/extensions/builtin/browser/src/browser_harness/admin.py +722 -722
  124. package/dist/extensions/builtin/browser/src/browser_harness/daemon.py +328 -328
  125. package/dist/extensions/builtin/browser/src/browser_harness/helpers.py +396 -396
  126. package/dist/extensions/builtin/browser/src/browser_harness/run.py +103 -103
  127. package/dist/extensions/builtin/discipline/skills/brainstorming/SKILL.md +33 -33
  128. package/dist/extensions/builtin/discipline/skills/executing-plans/SKILL.md +25 -25
  129. package/dist/extensions/builtin/discipline/skills/finishing-development-branch/SKILL.md +25 -25
  130. package/dist/extensions/builtin/discipline/skills/receiving-code-review/SKILL.md +22 -22
  131. package/dist/extensions/builtin/discipline/skills/requesting-code-review/SKILL.md +31 -31
  132. package/dist/extensions/builtin/discipline/skills/systematic-debugging/SKILL.md +28 -28
  133. package/dist/extensions/builtin/discipline/skills/test-driven-development/SKILL.md +32 -32
  134. package/dist/extensions/builtin/discipline/skills/using-git-worktrees/SKILL.md +25 -25
  135. package/dist/extensions/builtin/discipline/skills/verification-before-completion/SKILL.md +27 -27
  136. package/dist/extensions/builtin/discipline/skills/writing-plans/SKILL.md +26 -26
  137. package/dist/extensions/builtin/goal/README.md +67 -67
  138. package/dist/extensions/builtin/grub/README.md +112 -112
  139. package/dist/extensions/builtin/link-world/agent-workspace/README.md +16 -16
  140. package/dist/extensions/builtin/link-world/internet-search/internet-search.md +65 -65
  141. package/dist/extensions/builtin/link-world/link-world-agent.md +82 -82
  142. package/dist/extensions/builtin/link-world/linkworld.md +313 -313
  143. package/dist/extensions/builtin/link-world/network-routing/network-routing.md +67 -67
  144. package/dist/extensions/builtin/loop/README.md +92 -92
  145. package/dist/extensions/builtin/mcp/figma-design.md +68 -68
  146. package/dist/extensions/builtin/mcp/mcp-management.md +85 -85
  147. package/dist/extensions/builtin/recap/AGENT.md +15 -15
  148. package/dist/extensions/builtin/sal/README.md +72 -72
  149. package/dist/extensions/builtin/security-audit/README.md +289 -289
  150. package/dist/extensions/builtin/team/AGENT.md +112 -112
  151. package/dist/extensions/builtin/team/TESTING.md +299 -299
  152. package/dist/extensions/builtin/token-save/README.md +56 -56
  153. package/dist/extensions/optional/AGENT.md +10 -10
  154. package/dist/modes/interactive/interactive-mode.js +36 -36
  155. package/dist/modes/interactive/theme/dark.json +85 -85
  156. package/dist/modes/interactive/theme/light.json +84 -84
  157. package/dist/modes/interactive/theme/theme-schema.json +335 -335
  158. package/dist/modes/interactive/theme/warm.json +81 -81
  159. package/dist/node_modules/@pencil-agent/agent-core/dist/agent-loop.js +3 -2
  160. package/dist/node_modules/@pencil-agent/agent-core/dist/structured-adaptive-agent-loop.js +2 -1
  161. package/dist/node_modules/@pencil-agent/ai/dist/cli.js +0 -0
  162. package/docs/cc-agent-design.md +1297 -0
  163. package/docs/cc-tui-design.md +1333 -0
  164. package/docs/codex-goal-command-impl.md +1055 -1055
  165. package/docs/codex-goal-vs-grub.md +500 -500
  166. package/docs/custom-provider.md +27 -27
  167. package/docs/extensions.md +27 -27
  168. package/docs/keybindings.md +27 -27
  169. package/docs/loop /351/207/215/346/236/204/345/256/214/346/210/220/346/200/273/347/273/223.md" +250 -250
  170. package/docs/loop /351/207/215/346/236/204/345/256/214/346/210/220/346/212/245/345/221/212.md" +122 -122
  171. package/docs/loop /351/207/215/346/236/204/346/226/271/346/241/210.md" +1222 -1222
  172. 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
  173. 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
  174. package/docs/loop /351/207/215/346/236/204/350/256/241/345/210/222.md" +320 -320
  175. package/docs/loop-usage-examples.md +214 -214
  176. package/docs/models.md +27 -27
  177. package/docs/nanoPencil-/345/255/246/344/271/240/350/256/241/345/210/222.md +170 -0
  178. package/docs/packages.md +27 -27
  179. package/docs/pi-design-philosophy.md +457 -457
  180. package/docs/planmode.md +1987 -1987
  181. package/docs/prompt-templates.md +27 -27
  182. package/docs/providers.md +27 -27
  183. package/docs/scan-report.md +3820 -0
  184. package/docs/sdk.md +27 -27
  185. package/docs/skills.md +27 -27
  186. package/docs/themes.md +27 -27
  187. package/docs/tui.md +27 -27
  188. package/docs//345/257/271/346/240/207Claude-Code.md +1775 -0
  189. 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 +261 -0
  190. package/package.json +190 -190
  191. 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 +0 -851
  192. package/docs/SDK-TESTING.md +0 -364
  193. package/docs/mem-core/346/212/200/346/234/257/346/226/207/346/241/243.md +0 -593
  194. package/docs/startup-performance-optimization.md +0 -301
  195. package/docs//350/256/244/347/237/245/345/234/260/345/233/276.md +0 -47
@@ -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
+ - 缺少自动化测试(方案有完整的测试清单)