@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,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
  建议优先实现这两个核心功能,其他优化可以根据实际使用情况逐步迭代。