@pencil-agent/nano-pencil 2.0.0-beta.8 → 2.0.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 (241) 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/extensions-host/index.d.ts +1 -1
  7. package/dist/core/extensions-host/loader.js +1 -1
  8. package/dist/core/extensions-host/runner.d.ts +1 -0
  9. package/dist/core/extensions-host/runner.js +2 -2
  10. package/dist/core/extensions-host/types.d.ts +17 -22
  11. package/dist/core/lib/ai/src/types.d.ts +12 -2
  12. package/dist/core/persona/persona-manager.js +5 -2
  13. package/dist/core/runtime/agent-session.js +3 -3
  14. package/dist/core/runtime/extension-core-bindings.d.ts +1 -0
  15. package/dist/core/runtime/extension-core-bindings.js +2 -2
  16. package/dist/extensions/builtin/AGENT.md +115 -115
  17. package/dist/extensions/builtin/browser/AGENT.md +17 -17
  18. package/dist/extensions/builtin/browser/agent-workspace/agent_helpers.py +12 -12
  19. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/amazon/product-search.md +198 -198
  20. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/archive-org/scraping.md +341 -341
  21. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/arxiv/scraping.md +311 -311
  22. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/arxiv-bulk/scraping.md +333 -333
  23. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/atlas/overview.md +70 -70
  24. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/booking-com/scraping.md +578 -578
  25. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/capterra/scraping.md +440 -440
  26. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/centilebrain/generate-estimates.md +110 -110
  27. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/coingecko/scraping.md +325 -325
  28. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/coinmarketcap/scraping.md +463 -463
  29. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/coursera/scraping.md +360 -360
  30. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/craigslist/scraping.md +390 -390
  31. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/crossref/scraping.md +568 -568
  32. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/dev-to/scraping.md +323 -323
  33. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/duckduckgo/scraping.md +349 -349
  34. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/ebay/scraping.md +435 -435
  35. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/etsy/scraping.md +506 -506
  36. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/eventbrite/scraping.md +363 -363
  37. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/expedia/automation.md +168 -168
  38. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/facebook/groups.md +236 -236
  39. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/facebook/pages.md +295 -295
  40. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/framer/editor.md +108 -108
  41. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/fred/scraping.md +493 -493
  42. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/g2/scraping.md +580 -580
  43. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/genius/scraping.md +511 -511
  44. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/github/repo-actions.md +65 -65
  45. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/github/scraping.md +184 -184
  46. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/glassdoor/scraping.md +543 -543
  47. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/gmail/compose.md +122 -122
  48. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/goodreads/scraping.md +461 -461
  49. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/gutenberg/scraping.md +383 -383
  50. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/hackernews/scraping.md +243 -243
  51. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/howlongtobeat/scraping.md +473 -473
  52. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/imdb/scraping.md +271 -271
  53. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/itch-io/scraping.md +436 -436
  54. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/job-boards/indeed-glassdoor.md +1021 -1021
  55. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/letterboxd/scraping.md +349 -349
  56. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/linkedin/invitation-manager.md +109 -109
  57. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/loom/folder-enumeration.md +170 -170
  58. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/macrotrends/scraping.md +537 -537
  59. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/medium/article-hydration.md +120 -120
  60. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/medium/scraping.md +414 -414
  61. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/metacritic/scraping.md +477 -477
  62. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/musicbrainz/scraping.md +478 -478
  63. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/nasa/scraping.md +339 -339
  64. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/news-aggregation/multi-source.md +205 -205
  65. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/open-library/scraping.md +472 -472
  66. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/openalex/scraping.md +470 -470
  67. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/openstreetmap/scraping.md +490 -490
  68. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/package-registries/npm-pypi.md +478 -478
  69. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/polymarket/scraping.md +234 -234
  70. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/producthunt/scraping.md +307 -307
  71. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/pubmed/scraping.md +421 -421
  72. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/quora/scraping.md +364 -364
  73. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/rawg/scraping.md +352 -352
  74. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/reddit/scraping.md +124 -124
  75. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/rest-countries/scraping.md +233 -233
  76. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/sec-edgar/scraping.md +361 -361
  77. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/shopify-admin/README.md +36 -36
  78. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/shopify-admin/embedded-apps.md +72 -72
  79. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/shopify-admin/knowledge-base.md +109 -109
  80. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/shopify-admin/polaris-inputs.md +137 -137
  81. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/soundcloud/scraping.md +362 -362
  82. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/spotify/scraping.md +339 -339
  83. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/stackoverflow/scraping.md +435 -435
  84. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/steam/scraping.md +575 -575
  85. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/substack/scraping.md +338 -338
  86. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/thetechgeeks/pricing.md +52 -52
  87. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/tiktok/upload.md +107 -107
  88. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/tradingview/scraping.md +309 -309
  89. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/trello/boards-and-lists.md +88 -88
  90. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/trustpilot/scraping.md +375 -375
  91. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/walmart/scraping.md +444 -444
  92. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/wayback-machine/scraping.md +306 -306
  93. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/weather/scraping.md +398 -398
  94. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/wellfound/scraping.md +596 -596
  95. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/world-bank/scraping.md +356 -356
  96. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/xiaohongshu/scraping.md +84 -84
  97. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/youtube/scraping.md +418 -418
  98. package/dist/extensions/builtin/browser/agent-workspace/domain-skills/zillow/scraping.md +433 -433
  99. package/dist/extensions/builtin/browser/browser.md +73 -73
  100. package/dist/extensions/builtin/browser/install.md +142 -142
  101. package/dist/extensions/builtin/browser/interaction-skills/connection.md +48 -48
  102. package/dist/extensions/builtin/browser/interaction-skills/cookies.md +3 -3
  103. package/dist/extensions/builtin/browser/interaction-skills/cross-origin-iframes.md +3 -3
  104. package/dist/extensions/builtin/browser/interaction-skills/dialogs.md +64 -64
  105. package/dist/extensions/builtin/browser/interaction-skills/downloads.md +3 -3
  106. package/dist/extensions/builtin/browser/interaction-skills/drag-and-drop.md +3 -3
  107. package/dist/extensions/builtin/browser/interaction-skills/dropdowns.md +3 -3
  108. package/dist/extensions/builtin/browser/interaction-skills/iframes.md +3 -3
  109. package/dist/extensions/builtin/browser/interaction-skills/network-requests.md +3 -3
  110. package/dist/extensions/builtin/browser/interaction-skills/print-as-pdf.md +3 -3
  111. package/dist/extensions/builtin/browser/interaction-skills/profile-sync.md +90 -90
  112. package/dist/extensions/builtin/browser/interaction-skills/screenshots.md +17 -17
  113. package/dist/extensions/builtin/browser/interaction-skills/scrolling.md +3 -3
  114. package/dist/extensions/builtin/browser/interaction-skills/shadow-dom.md +3 -3
  115. package/dist/extensions/builtin/browser/interaction-skills/tabs.md +69 -69
  116. package/dist/extensions/builtin/browser/interaction-skills/uploads.md +1 -1
  117. package/dist/extensions/builtin/browser/interaction-skills/viewport.md +3 -3
  118. package/dist/extensions/builtin/browser/src/browser_harness/AGENT.md +15 -15
  119. package/dist/extensions/builtin/browser/src/browser_harness/__init__.py +8 -8
  120. package/dist/extensions/builtin/browser/src/browser_harness/_ipc.py +90 -90
  121. package/dist/extensions/builtin/browser/src/browser_harness/admin.py +722 -722
  122. package/dist/extensions/builtin/browser/src/browser_harness/daemon.py +328 -328
  123. package/dist/extensions/builtin/browser/src/browser_harness/helpers.py +396 -396
  124. package/dist/extensions/builtin/browser/src/browser_harness/run.py +103 -103
  125. package/dist/extensions/builtin/discipline/skills/brainstorming/SKILL.md +33 -33
  126. package/dist/extensions/builtin/discipline/skills/executing-plans/SKILL.md +25 -25
  127. package/dist/extensions/builtin/discipline/skills/finishing-development-branch/SKILL.md +25 -25
  128. package/dist/extensions/builtin/discipline/skills/receiving-code-review/SKILL.md +22 -22
  129. package/dist/extensions/builtin/discipline/skills/requesting-code-review/SKILL.md +31 -31
  130. package/dist/extensions/builtin/discipline/skills/systematic-debugging/SKILL.md +28 -28
  131. package/dist/extensions/builtin/discipline/skills/test-driven-development/SKILL.md +32 -32
  132. package/dist/extensions/builtin/discipline/skills/using-git-worktrees/SKILL.md +25 -25
  133. package/dist/extensions/builtin/discipline/skills/verification-before-completion/SKILL.md +27 -27
  134. package/dist/extensions/builtin/discipline/skills/writing-plans/SKILL.md +26 -26
  135. package/dist/extensions/builtin/goal/README.md +67 -67
  136. package/dist/extensions/builtin/goal/goal-controller.d.ts +39 -10
  137. package/dist/extensions/builtin/goal/goal-controller.js +1 -1
  138. package/dist/extensions/builtin/goal/goal-format.js +1 -1
  139. package/dist/extensions/builtin/goal/goal-prompts.d.ts +2 -0
  140. package/dist/extensions/builtin/goal/goal-prompts.js +5 -4
  141. package/dist/extensions/builtin/goal/goal-store.js +1 -1
  142. package/dist/extensions/builtin/goal/index.d.ts +1 -1
  143. package/dist/extensions/builtin/goal/index.js +10 -7
  144. package/dist/extensions/builtin/grub/README.md +112 -112
  145. package/dist/extensions/builtin/link-world/agent-workspace/README.md +16 -16
  146. package/dist/extensions/builtin/link-world/index.js +6 -6
  147. package/dist/extensions/builtin/link-world/internet-search/internet-search.md +65 -65
  148. package/dist/extensions/builtin/link-world/link-world-agent.md +82 -82
  149. package/dist/extensions/builtin/link-world/linkworld.md +313 -313
  150. package/dist/extensions/builtin/link-world/{network-routing.md → network-routing/network-routing.md} +67 -67
  151. package/dist/extensions/builtin/loop/README.md +92 -92
  152. package/dist/extensions/builtin/mcp/figma-design.md +68 -68
  153. package/dist/extensions/builtin/mcp/mcp-management.md +85 -85
  154. package/dist/extensions/builtin/plan/index.js +1 -1
  155. package/dist/extensions/builtin/recap/AGENT.md +15 -15
  156. package/dist/extensions/builtin/sal/README.md +72 -72
  157. package/dist/extensions/builtin/security-audit/README.md +289 -289
  158. package/dist/extensions/builtin/task/task-store.d.ts +4 -0
  159. package/dist/extensions/builtin/task/task-store.js +1 -1
  160. package/dist/extensions/builtin/team/AGENT.md +112 -112
  161. package/dist/extensions/builtin/team/TESTING.md +299 -299
  162. package/dist/extensions/builtin/token-save/README.md +56 -56
  163. package/dist/extensions/optional/AGENT.md +10 -10
  164. package/dist/index.d.ts +5 -30
  165. package/dist/index.js +1 -1
  166. package/dist/models.d.ts +7 -0
  167. package/dist/models.js +1 -0
  168. package/dist/modes/interactive/components/footer.js +1 -1
  169. package/dist/modes/interactive/components/task-status-panel.d.ts +36 -0
  170. package/dist/modes/interactive/components/task-status-panel.js +1 -0
  171. package/dist/modes/interactive/controllers/stream-render-controller.d.ts +7 -0
  172. package/dist/modes/interactive/controllers/stream-render-controller.js +2 -2
  173. package/dist/modes/interactive/interactive-mode.js +40 -40
  174. package/dist/modes/interactive/state/interactive-state.d.ts +2 -0
  175. package/dist/modes/interactive/state/interactive-state.js +1 -1
  176. package/dist/modes/interactive/theme/dark.json +85 -85
  177. package/dist/modes/interactive/theme/light.json +84 -84
  178. package/dist/modes/interactive/theme/theme-schema.json +335 -335
  179. package/dist/modes/interactive/theme/warm.json +81 -81
  180. package/dist/node_modules/@pencil-agent/ai/dist/cli.js +0 -0
  181. package/dist/node_modules/@pencil-agent/ai/dist/models.generated.js +1 -1
  182. package/dist/node_modules/@pencil-agent/ai/dist/providers/anthropic.js +2 -2
  183. package/dist/node_modules/@pencil-agent/ai/dist/providers/openai-completions.js +5 -5
  184. package/dist/node_modules/@pencil-agent/ai/dist/providers/openai-responses.js +1 -1
  185. package/dist/node_modules/@pencil-agent/ai/dist/stream.js +1 -1
  186. package/dist/packages/protocol/src/commands.d.ts +33 -0
  187. package/dist/packages/protocol/src/flags.d.ts +20 -0
  188. package/dist/packages/protocol/src/hooks.d.ts +17 -0
  189. package/dist/packages/protocol/src/hooks.js +0 -0
  190. package/dist/packages/{extension-sdk → protocol}/src/index.d.ts +7 -4
  191. package/dist/packages/protocol/src/index.js +1 -0
  192. package/dist/packages/{extension-sdk → protocol}/src/lifecycle.d.ts +15 -27
  193. package/dist/packages/protocol/src/lifecycle.js +0 -0
  194. package/dist/packages/{extension-sdk → protocol}/src/tools.d.ts +1 -1
  195. package/dist/packages/protocol/src/tools.js +0 -0
  196. package/dist/public-config.d.ts +12 -0
  197. package/dist/public-config.js +1 -0
  198. package/dist/runtime.d.ts +9 -0
  199. package/dist/runtime.js +1 -0
  200. package/dist/session-compaction.d.ts +7 -0
  201. package/dist/session-compaction.js +1 -0
  202. package/dist/session.d.ts +7 -0
  203. package/dist/session.js +1 -0
  204. package/dist/skills.d.ts +7 -0
  205. package/dist/skills.js +1 -0
  206. package/dist/tools.d.ts +7 -0
  207. package/dist/tools.js +1 -0
  208. 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
  209. package/docs/SDK-TESTING.md +364 -0
  210. package/docs/codex-goal-command-impl.md +1055 -1055
  211. package/docs/codex-goal-vs-grub.md +500 -500
  212. package/docs/custom-provider.md +27 -27
  213. package/docs/extensions.md +27 -27
  214. package/docs/keybindings.md +27 -27
  215. package/docs/loop /351/207/215/346/236/204/345/256/214/346/210/220/346/200/273/347/273/223.md" +250 -250
  216. package/docs/loop /351/207/215/346/236/204/345/256/214/346/210/220/346/212/245/345/221/212.md" +122 -122
  217. package/docs/loop /351/207/215/346/236/204/346/226/271/346/241/210.md" +1222 -1222
  218. 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
  219. 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
  220. package/docs/loop /351/207/215/346/236/204/350/256/241/345/210/222.md" +320 -320
  221. package/docs/loop-usage-examples.md +214 -214
  222. package/docs/mem-core/346/212/200/346/234/257/346/226/207/346/241/243.md +593 -0
  223. package/docs/models.md +27 -27
  224. package/docs/packages.md +27 -27
  225. package/docs/pi-design-philosophy.md +457 -457
  226. package/docs/planmode.md +1987 -1987
  227. package/docs/prompt-templates.md +27 -27
  228. package/docs/providers.md +27 -27
  229. package/docs/sdk.md +27 -27
  230. package/docs/skills.md +27 -27
  231. package/docs/startup-performance-optimization.md +301 -0
  232. package/docs/themes.md +27 -27
  233. package/docs/tui.md +27 -27
  234. package/docs//350/256/244/347/237/245/345/234/260/345/233/276.md +47 -0
  235. package/package.json +190 -162
  236. package/dist/packages/extension-sdk/src/index.js +0 -1
  237. package/docs/cc-agent-design.md +0 -1297
  238. package/docs/cc-tui-design.md +0 -1333
  239. package/docs//345/257/271/346/240/207Claude-Code.md +0 -1775
  240. /package/dist/packages/{extension-sdk/src/lifecycle.js → protocol/src/commands.js} +0 -0
  241. /package/dist/packages/{extension-sdk/src/tools.js → protocol/src/flags.js} +0 -0
@@ -1,321 +1,321 @@
1
- # `/loop` 命令重构计划
2
-
3
- > 基于 Claude Code v2.1.88 逆向分析文档的重构方案
4
- > 日期:2026-04-18
5
-
6
- ## 当前状态分析
7
-
8
- ### 现有实现
9
-
10
- nanoPencil 当前已经有工作的 loop 实现:
11
-
12
- - **核心文件**:
13
- - `extensions/defaults/loop/index.ts` (363行) - 主扩展逻辑
14
- - `scheduler-controller.ts` (155行) - 任务控制器
15
- - `scheduler-parser.ts` (246行) - 命令解析器
16
- - `scheduler-types.ts` (49行) - 类型定义
17
-
18
- - **已支持功能**:
19
- - 定时调度(s/m/h/d间隔)
20
- - 暂停/恢复/取消/运行
21
- - maxRuns自动取消
22
- - quiet模式
23
- - 命名任务
24
- - session-scoped(会话关闭清除)
25
- - slash command和prompt支持
26
-
27
- ### 架构对比
28
-
29
- | 特性 | Claude Code (文档) | nanoPencil 当前 | 差距 |
30
- |------|-------------------|-----------------|------|
31
- | 任务存储 | session + durable 文件 | 仅 session | ❌ 缺少持久化 |
32
- | 多进程支持 | scheduler lock | 无 | ❌ 缺少锁机制 |
33
- | 调度器设计 | 独立cronScheduler | 集成在扩展中 | ⚠️ 架构不同 |
34
- | jitter机制 | 有 | 无 | ❌ 缺少流量控制 |
35
- | 参数解析 | prompt-based (skill) | 直接解析 | ⚠️ 设计哲学不同 |
36
- | teammate支持 | agentId路由 | 无 | ❌ 缺少多Agent支持 |
37
- | 自动过期 | 7天recurring过期 | maxRuns | ⚠️ 机制不同 |
38
-
39
- ## 重构目标
40
-
41
- ### 阶段一:核心功能补全(必须)
42
-
43
- #### 目标1.1:添加 durable 持久化存储
44
-
45
- **当前问题**:
46
- - loop任务只保存在内存中,会话关闭后丢失
47
- - 无法跨session保持loop任务
48
-
49
- **实施方案**:
50
- 1. 创建 `loop-tasks.ts` 文件存储模块
51
- 2. 在项目目录创建 `.nanopencil/loop-tasks.json`
52
- 3. 支持 `--durable` 或 `-d` flag
53
- 4. 任务启动时自动恢复durable任务
54
-
55
- **文件变更**:
56
- - 新建 `extensions/defaults/loop/loop-tasks.ts`
57
- - 修改 `scheduler-types.ts` 增加 `durable` 字段
58
- - 修改 `scheduler-controller.ts` 支持durable读写
59
- - 修改 `index.ts` 在session_start时恢复durable任务
60
-
61
- #### 目标1.2:添加 scheduler lock
62
-
63
- **当前问题**:
64
- - 多个nanoPencil实例共享项目目录时,可能重复触发任务
65
- - durable任务需要确保只被一个实例执行
66
-
67
- **实施方案**:
68
- 1. 使用 `proper-lockfile` 包(已存在依赖)
69
- 2. 创建 `.nanopencil/loop-scheduler.lock`
70
- 3. 调度器启动时获取锁
71
- 4. 失败时降级为非owner模式(不触发durable任务)
72
-
73
- **文件变更**:
74
- - 修改 `scheduler-controller.ts` 增加锁管理
75
- - 修改 `index.ts` 启动时获取锁
76
-
77
- ### 阶段二:架构优化(推荐)
78
-
79
- #### 目标2.1:独立调度器模块
80
-
81
- **当前问题**:
82
- - 调度逻辑混合在扩展代码中
83
- - 难以独立测试和复用
84
-
85
- **实施方案**:
86
- 1. 提取 `loop-scheduler.ts` 独立调度器
87
- 2. 使用回调接口(`onFire`, `isLoading`等)
88
- 3. 支持外部测试和mock
89
-
90
- **文件变更**:
91
- - 新建 `extensions/defaults/loop/loop-scheduler.ts`
92
- - 修改 `scheduler-controller.ts` 瘦身为数据管理器
93
- - 修改 `index.ts` 使用独立调度器
94
-
95
- #### 目标2.2:添加 jitter 机制
96
-
97
- **当前问题**:
98
- - 所有任务都在整点触发
99
- - 可能造成流量尖峰
100
-
101
- **实施方案**:
102
- 1. 为每个任务添加确定性jitter
103
- 2. 基于taskId计算jitter值
104
- 3. 避免流量尖峰
105
-
106
- **文件变更**:
107
- - 修改 `scheduler-controller.ts` 计算jitter
108
- - 修改 `loop-tasks.ts` 保存jitter偏移
109
-
110
- ### 阶段三:高级特性(可选)
111
-
112
- #### 目标3.1:teammate 路由支持
113
-
114
- **实施方案**:
115
- - 增加任务的 `agentId` 字段
116
- - 集成 subagent/team 扩展路由逻辑
117
-
118
- #### 目标3.2:自动过期机制
119
-
120
- **实施方案**:
121
- - recurring任务默认7天后自动删除
122
- - 在 `markDispatched` 中检查过期时间
123
-
124
- ## 重构步骤
125
-
126
- ### 第一阶段:durable 持久化
127
-
128
- #### 步骤1.1:创建 loop-tasks.ts
129
-
130
- ```typescript
131
- // extensions/defaults/loop/loop-tasks.ts
132
- import { randomBytes } from "node:crypto";
133
- import { promises as fs } from "node:fs";
134
- import { join } from "node:path";
135
-
136
- const LOOP_TASKS_FILE = ".nanopencil/loop-tasks.json";
137
-
138
- export async function readLoopTasks(projectRoot: string): Promise<ScheduledLoopTask[]> {
139
- // 实现读取逻辑,处理文件不存在、JSON错误等
140
- }
141
-
142
- export async function writeLoopTasks(projectRoot: string, tasks: ScheduledLoopTask[]): Promise<void> {
143
- // 实现写入逻辑,创建目录,原子写入
144
- }
145
-
146
- export async function addDurableLoopTask(
147
- projectRoot: string,
148
- task: ScheduledLoopTask,
149
- ): Promise<string> {
150
- // 实现添加durable任务
151
- }
152
- ```
153
-
154
- #### 步骤1.2:修改类型定义
155
-
156
- ```typescript
157
- // scheduler-types.ts
158
- export interface ScheduledLoopTask {
159
- // 现有字段...
160
- durable?: boolean; // 新增
161
- agentId?: string; // 为teammate预留
162
- }
163
- ```
164
-
165
- #### 步骤1.3:修改 controller 支持durable
166
-
167
- ```typescript
168
- // scheduler-controller.ts
169
- export class SchedulerController {
170
- private projectRoot?: string;
171
-
172
- setProjectRoot(root: string): void {
173
- this.projectRoot = root;
174
- }
175
-
176
- async loadDurableTasks(): Promise<void> {
177
- // 从文件加载durable任务
178
- }
179
-
180
- async saveDurableTasks(): Promise<void> {
181
- // 保存durable任务到文件
182
- }
183
- }
184
- ```
185
-
186
- #### 步骤1.4:修改扩展初始化
187
-
188
- ```typescript
189
- // index.ts
190
- api.on("session_start", async () => {
191
- if (ctx.projectRoot) {
192
- controller.setProjectRoot(ctx.projectRoot);
193
- await controller.loadDurableTasks();
194
- }
195
- ensureSchedulerTicker(api, bus);
196
- });
197
- ```
198
-
199
- ### 第二阶段:scheduler lock
200
-
201
- #### 步骤2.1:添加锁管理
202
-
203
- ```typescript
204
- // scheduler-controller.ts
205
- import lockfile from "proper-lockfile";
206
-
207
- export class SchedulerController {
208
- private lock?: lockfile.Lock;
209
-
210
- async acquireSchedulerLock(): Promise<boolean> {
211
- try {
212
- this.lock = await lockfile.lock(this.getLockPath());
213
- return true;
214
- } catch {
215
- return false;
216
- }
217
- }
218
-
219
- releaseSchedulerLock(): void {
220
- if (this.lock) {
221
- lockfile.unlock(this.lock);
222
- this.lock = undefined;
223
- }
224
- }
225
- }
226
- ```
227
-
228
- #### 步骤2.2:修改调度逻辑
229
-
230
- ```typescript
231
- // 只有lock owner才触发durable任务
232
- if (isDurableTask(task) && !isLockOwner) {
233
- return; // 跳过
234
- }
235
- ```
236
-
237
- ### 第三阶段:独立调度器(可选)
238
-
239
- #### 步骤3.1:提取调度器
240
-
241
- ```typescript
242
- // loop-scheduler.ts
243
- export interface LoopSchedulerOptions {
244
- onFire: (task: ScheduledLoopTask) => void;
245
- isLoading: () => boolean;
246
- isKilled?: () => boolean;
247
- }
248
-
249
- export function createLoopScheduler(options: LoopSchedulerOptions): LoopScheduler {
250
- // 独立的调度器实现
251
- }
252
- ```
253
-
254
- ## 验证计划
255
-
256
- ### 功能测试
257
-
258
- 1. **durable持久化**
259
- - 创建durable任务,关闭会话,重新打开,任务仍在
260
- - 多个会话共享同一目录,只有一个会话触发任务
261
-
262
- 2. **scheduler lock**
263
- - 启动两个nanoPencil实例,观察任务执行情况
264
- - 只有lock owner触发durable任务
265
-
266
- 3. **向后兼容**
267
- - 现有session-only任务不受影响
268
- - 命令接口保持不变
269
-
270
- ### 性能测试
271
-
272
- 1. **文件IO性能**
273
- - 50个durable任务的读写性能
274
- - 频繁调度的性能影响
275
-
276
- 2. **并发安全**
277
- - 多进程同时创建任务
278
- - 文件损坏恢复能力
279
-
280
- ## 风险与缓解
281
-
282
- | 风险 | 缓解措施 |
283
- |------|----------|
284
- | 文件IO阻塞主线程 | 使用异步API,限制文件大小 |
285
- | 锁机制死锁 | 设置锁超时,提供手动清理 |
286
- | 文件损坏 | 容错读取,备份机制 |
287
- | 向后兼容性 | 保留现有接口,增量添加 |
288
-
289
- ## 交付标准
290
-
291
- - [x] durable任务支持完成,测试通过
292
- - [x] scheduler lock实现,测试通过
293
- - [x] auto-expiry自动过期实现,测试通过
294
- - [x] 向后兼容,现有功能不受影响
295
- - [x] 文档更新(README.md)
296
- - [x] 单元测试通过(5个测试全部通过)
297
- - [x] 使用示例文档
298
- - [ ] 手动集成测试
299
-
300
- ## 时间估算
301
-
302
- - 阶段一(核心功能):2-3天
303
- - 阶段二(架构优化):1-2天
304
- - 阶段三(高级特性):按需
305
-
306
- ## 优先级建议
307
-
308
- **建议执行顺序**:
309
- 1. **必须**:阶段一.1(durable持久化)- 解决主要痛点
310
- 2. **强烈推荐**:阶段一.2(scheduler lock)- 保证多进程安全
311
- 3. **可选**:阶段二(架构优化)- 提升代码质量
312
- 4. **未来考虑**:阶段三(高级特性)- 根据实际需求
313
-
314
- ## 结论
315
-
316
- 当前nanoPencil的loop实现已经具备基本功能,主要缺失的是:
317
-
318
- 1. **持久化存储** - 用户最常要求的功能
319
- 2. **多进程安全** - 生产环境必需
320
-
1
+ # `/loop` 命令重构计划
2
+
3
+ > 基于 Claude Code v2.1.88 逆向分析文档的重构方案
4
+ > 日期:2026-04-18
5
+
6
+ ## 当前状态分析
7
+
8
+ ### 现有实现
9
+
10
+ nanoPencil 当前已经有工作的 loop 实现:
11
+
12
+ - **核心文件**:
13
+ - `extensions/defaults/loop/index.ts` (363行) - 主扩展逻辑
14
+ - `scheduler-controller.ts` (155行) - 任务控制器
15
+ - `scheduler-parser.ts` (246行) - 命令解析器
16
+ - `scheduler-types.ts` (49行) - 类型定义
17
+
18
+ - **已支持功能**:
19
+ - 定时调度(s/m/h/d间隔)
20
+ - 暂停/恢复/取消/运行
21
+ - maxRuns自动取消
22
+ - quiet模式
23
+ - 命名任务
24
+ - session-scoped(会话关闭清除)
25
+ - slash command和prompt支持
26
+
27
+ ### 架构对比
28
+
29
+ | 特性 | Claude Code (文档) | nanoPencil 当前 | 差距 |
30
+ |------|-------------------|-----------------|------|
31
+ | 任务存储 | session + durable 文件 | 仅 session | ❌ 缺少持久化 |
32
+ | 多进程支持 | scheduler lock | 无 | ❌ 缺少锁机制 |
33
+ | 调度器设计 | 独立cronScheduler | 集成在扩展中 | ⚠️ 架构不同 |
34
+ | jitter机制 | 有 | 无 | ❌ 缺少流量控制 |
35
+ | 参数解析 | prompt-based (skill) | 直接解析 | ⚠️ 设计哲学不同 |
36
+ | teammate支持 | agentId路由 | 无 | ❌ 缺少多Agent支持 |
37
+ | 自动过期 | 7天recurring过期 | maxRuns | ⚠️ 机制不同 |
38
+
39
+ ## 重构目标
40
+
41
+ ### 阶段一:核心功能补全(必须)
42
+
43
+ #### 目标1.1:添加 durable 持久化存储
44
+
45
+ **当前问题**:
46
+ - loop任务只保存在内存中,会话关闭后丢失
47
+ - 无法跨session保持loop任务
48
+
49
+ **实施方案**:
50
+ 1. 创建 `loop-tasks.ts` 文件存储模块
51
+ 2. 在项目目录创建 `.nanopencil/loop-tasks.json`
52
+ 3. 支持 `--durable` 或 `-d` flag
53
+ 4. 任务启动时自动恢复durable任务
54
+
55
+ **文件变更**:
56
+ - 新建 `extensions/defaults/loop/loop-tasks.ts`
57
+ - 修改 `scheduler-types.ts` 增加 `durable` 字段
58
+ - 修改 `scheduler-controller.ts` 支持durable读写
59
+ - 修改 `index.ts` 在session_start时恢复durable任务
60
+
61
+ #### 目标1.2:添加 scheduler lock
62
+
63
+ **当前问题**:
64
+ - 多个nanoPencil实例共享项目目录时,可能重复触发任务
65
+ - durable任务需要确保只被一个实例执行
66
+
67
+ **实施方案**:
68
+ 1. 使用 `proper-lockfile` 包(已存在依赖)
69
+ 2. 创建 `.nanopencil/loop-scheduler.lock`
70
+ 3. 调度器启动时获取锁
71
+ 4. 失败时降级为非owner模式(不触发durable任务)
72
+
73
+ **文件变更**:
74
+ - 修改 `scheduler-controller.ts` 增加锁管理
75
+ - 修改 `index.ts` 启动时获取锁
76
+
77
+ ### 阶段二:架构优化(推荐)
78
+
79
+ #### 目标2.1:独立调度器模块
80
+
81
+ **当前问题**:
82
+ - 调度逻辑混合在扩展代码中
83
+ - 难以独立测试和复用
84
+
85
+ **实施方案**:
86
+ 1. 提取 `loop-scheduler.ts` 独立调度器
87
+ 2. 使用回调接口(`onFire`, `isLoading`等)
88
+ 3. 支持外部测试和mock
89
+
90
+ **文件变更**:
91
+ - 新建 `extensions/defaults/loop/loop-scheduler.ts`
92
+ - 修改 `scheduler-controller.ts` 瘦身为数据管理器
93
+ - 修改 `index.ts` 使用独立调度器
94
+
95
+ #### 目标2.2:添加 jitter 机制
96
+
97
+ **当前问题**:
98
+ - 所有任务都在整点触发
99
+ - 可能造成流量尖峰
100
+
101
+ **实施方案**:
102
+ 1. 为每个任务添加确定性jitter
103
+ 2. 基于taskId计算jitter值
104
+ 3. 避免流量尖峰
105
+
106
+ **文件变更**:
107
+ - 修改 `scheduler-controller.ts` 计算jitter
108
+ - 修改 `loop-tasks.ts` 保存jitter偏移
109
+
110
+ ### 阶段三:高级特性(可选)
111
+
112
+ #### 目标3.1:teammate 路由支持
113
+
114
+ **实施方案**:
115
+ - 增加任务的 `agentId` 字段
116
+ - 集成 subagent/team 扩展路由逻辑
117
+
118
+ #### 目标3.2:自动过期机制
119
+
120
+ **实施方案**:
121
+ - recurring任务默认7天后自动删除
122
+ - 在 `markDispatched` 中检查过期时间
123
+
124
+ ## 重构步骤
125
+
126
+ ### 第一阶段:durable 持久化
127
+
128
+ #### 步骤1.1:创建 loop-tasks.ts
129
+
130
+ ```typescript
131
+ // extensions/defaults/loop/loop-tasks.ts
132
+ import { randomBytes } from "node:crypto";
133
+ import { promises as fs } from "node:fs";
134
+ import { join } from "node:path";
135
+
136
+ const LOOP_TASKS_FILE = ".nanopencil/loop-tasks.json";
137
+
138
+ export async function readLoopTasks(projectRoot: string): Promise<ScheduledLoopTask[]> {
139
+ // 实现读取逻辑,处理文件不存在、JSON错误等
140
+ }
141
+
142
+ export async function writeLoopTasks(projectRoot: string, tasks: ScheduledLoopTask[]): Promise<void> {
143
+ // 实现写入逻辑,创建目录,原子写入
144
+ }
145
+
146
+ export async function addDurableLoopTask(
147
+ projectRoot: string,
148
+ task: ScheduledLoopTask,
149
+ ): Promise<string> {
150
+ // 实现添加durable任务
151
+ }
152
+ ```
153
+
154
+ #### 步骤1.2:修改类型定义
155
+
156
+ ```typescript
157
+ // scheduler-types.ts
158
+ export interface ScheduledLoopTask {
159
+ // 现有字段...
160
+ durable?: boolean; // 新增
161
+ agentId?: string; // 为teammate预留
162
+ }
163
+ ```
164
+
165
+ #### 步骤1.3:修改 controller 支持durable
166
+
167
+ ```typescript
168
+ // scheduler-controller.ts
169
+ export class SchedulerController {
170
+ private projectRoot?: string;
171
+
172
+ setProjectRoot(root: string): void {
173
+ this.projectRoot = root;
174
+ }
175
+
176
+ async loadDurableTasks(): Promise<void> {
177
+ // 从文件加载durable任务
178
+ }
179
+
180
+ async saveDurableTasks(): Promise<void> {
181
+ // 保存durable任务到文件
182
+ }
183
+ }
184
+ ```
185
+
186
+ #### 步骤1.4:修改扩展初始化
187
+
188
+ ```typescript
189
+ // index.ts
190
+ api.on("session_start", async () => {
191
+ if (ctx.projectRoot) {
192
+ controller.setProjectRoot(ctx.projectRoot);
193
+ await controller.loadDurableTasks();
194
+ }
195
+ ensureSchedulerTicker(api, bus);
196
+ });
197
+ ```
198
+
199
+ ### 第二阶段:scheduler lock
200
+
201
+ #### 步骤2.1:添加锁管理
202
+
203
+ ```typescript
204
+ // scheduler-controller.ts
205
+ import lockfile from "proper-lockfile";
206
+
207
+ export class SchedulerController {
208
+ private lock?: lockfile.Lock;
209
+
210
+ async acquireSchedulerLock(): Promise<boolean> {
211
+ try {
212
+ this.lock = await lockfile.lock(this.getLockPath());
213
+ return true;
214
+ } catch {
215
+ return false;
216
+ }
217
+ }
218
+
219
+ releaseSchedulerLock(): void {
220
+ if (this.lock) {
221
+ lockfile.unlock(this.lock);
222
+ this.lock = undefined;
223
+ }
224
+ }
225
+ }
226
+ ```
227
+
228
+ #### 步骤2.2:修改调度逻辑
229
+
230
+ ```typescript
231
+ // 只有lock owner才触发durable任务
232
+ if (isDurableTask(task) && !isLockOwner) {
233
+ return; // 跳过
234
+ }
235
+ ```
236
+
237
+ ### 第三阶段:独立调度器(可选)
238
+
239
+ #### 步骤3.1:提取调度器
240
+
241
+ ```typescript
242
+ // loop-scheduler.ts
243
+ export interface LoopSchedulerOptions {
244
+ onFire: (task: ScheduledLoopTask) => void;
245
+ isLoading: () => boolean;
246
+ isKilled?: () => boolean;
247
+ }
248
+
249
+ export function createLoopScheduler(options: LoopSchedulerOptions): LoopScheduler {
250
+ // 独立的调度器实现
251
+ }
252
+ ```
253
+
254
+ ## 验证计划
255
+
256
+ ### 功能测试
257
+
258
+ 1. **durable持久化**
259
+ - 创建durable任务,关闭会话,重新打开,任务仍在
260
+ - 多个会话共享同一目录,只有一个会话触发任务
261
+
262
+ 2. **scheduler lock**
263
+ - 启动两个nanoPencil实例,观察任务执行情况
264
+ - 只有lock owner触发durable任务
265
+
266
+ 3. **向后兼容**
267
+ - 现有session-only任务不受影响
268
+ - 命令接口保持不变
269
+
270
+ ### 性能测试
271
+
272
+ 1. **文件IO性能**
273
+ - 50个durable任务的读写性能
274
+ - 频繁调度的性能影响
275
+
276
+ 2. **并发安全**
277
+ - 多进程同时创建任务
278
+ - 文件损坏恢复能力
279
+
280
+ ## 风险与缓解
281
+
282
+ | 风险 | 缓解措施 |
283
+ |------|----------|
284
+ | 文件IO阻塞主线程 | 使用异步API,限制文件大小 |
285
+ | 锁机制死锁 | 设置锁超时,提供手动清理 |
286
+ | 文件损坏 | 容错读取,备份机制 |
287
+ | 向后兼容性 | 保留现有接口,增量添加 |
288
+
289
+ ## 交付标准
290
+
291
+ - [x] durable任务支持完成,测试通过
292
+ - [x] scheduler lock实现,测试通过
293
+ - [x] auto-expiry自动过期实现,测试通过
294
+ - [x] 向后兼容,现有功能不受影响
295
+ - [x] 文档更新(README.md)
296
+ - [x] 单元测试通过(5个测试全部通过)
297
+ - [x] 使用示例文档
298
+ - [ ] 手动集成测试
299
+
300
+ ## 时间估算
301
+
302
+ - 阶段一(核心功能):2-3天
303
+ - 阶段二(架构优化):1-2天
304
+ - 阶段三(高级特性):按需
305
+
306
+ ## 优先级建议
307
+
308
+ **建议执行顺序**:
309
+ 1. **必须**:阶段一.1(durable持久化)- 解决主要痛点
310
+ 2. **强烈推荐**:阶段一.2(scheduler lock)- 保证多进程安全
311
+ 3. **可选**:阶段二(架构优化)- 提升代码质量
312
+ 4. **未来考虑**:阶段三(高级特性)- 根据实际需求
313
+
314
+ ## 结论
315
+
316
+ 当前nanoPencil的loop实现已经具备基本功能,主要缺失的是:
317
+
318
+ 1. **持久化存储** - 用户最常要求的功能
319
+ 2. **多进程安全** - 生产环境必需
320
+
321
321
  建议优先实现这两个核心功能,其他优化可以根据实际使用情况逐步迭代。