@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.
- package/README.md +267 -267
- package/dist/build-meta.json +3 -3
- package/dist/core/export-html/AGENT.md +11 -11
- package/dist/core/export-html/template.css +971 -971
- package/dist/core/export-html/template.html +54 -54
- package/dist/core/extensions-host/index.d.ts +1 -1
- package/dist/core/extensions-host/loader.js +1 -1
- package/dist/core/extensions-host/runner.d.ts +1 -0
- package/dist/core/extensions-host/runner.js +2 -2
- package/dist/core/extensions-host/types.d.ts +17 -22
- package/dist/core/lib/ai/src/types.d.ts +12 -2
- package/dist/core/persona/persona-manager.js +5 -2
- package/dist/core/runtime/agent-session.js +3 -3
- package/dist/core/runtime/extension-core-bindings.d.ts +1 -0
- package/dist/core/runtime/extension-core-bindings.js +2 -2
- package/dist/extensions/builtin/AGENT.md +115 -115
- package/dist/extensions/builtin/browser/AGENT.md +17 -17
- package/dist/extensions/builtin/browser/agent-workspace/agent_helpers.py +12 -12
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/amazon/product-search.md +198 -198
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/archive-org/scraping.md +341 -341
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/arxiv/scraping.md +311 -311
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/arxiv-bulk/scraping.md +333 -333
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/atlas/overview.md +70 -70
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/booking-com/scraping.md +578 -578
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/capterra/scraping.md +440 -440
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/centilebrain/generate-estimates.md +110 -110
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/coingecko/scraping.md +325 -325
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/coinmarketcap/scraping.md +463 -463
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/coursera/scraping.md +360 -360
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/craigslist/scraping.md +390 -390
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/crossref/scraping.md +568 -568
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/dev-to/scraping.md +323 -323
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/duckduckgo/scraping.md +349 -349
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/ebay/scraping.md +435 -435
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/etsy/scraping.md +506 -506
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/eventbrite/scraping.md +363 -363
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/expedia/automation.md +168 -168
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/facebook/groups.md +236 -236
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/facebook/pages.md +295 -295
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/framer/editor.md +108 -108
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/fred/scraping.md +493 -493
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/g2/scraping.md +580 -580
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/genius/scraping.md +511 -511
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/github/repo-actions.md +65 -65
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/github/scraping.md +184 -184
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/glassdoor/scraping.md +543 -543
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/gmail/compose.md +122 -122
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/goodreads/scraping.md +461 -461
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/gutenberg/scraping.md +383 -383
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/hackernews/scraping.md +243 -243
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/howlongtobeat/scraping.md +473 -473
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/imdb/scraping.md +271 -271
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/itch-io/scraping.md +436 -436
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/job-boards/indeed-glassdoor.md +1021 -1021
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/letterboxd/scraping.md +349 -349
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/linkedin/invitation-manager.md +109 -109
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/loom/folder-enumeration.md +170 -170
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/macrotrends/scraping.md +537 -537
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/medium/article-hydration.md +120 -120
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/medium/scraping.md +414 -414
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/metacritic/scraping.md +477 -477
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/musicbrainz/scraping.md +478 -478
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/nasa/scraping.md +339 -339
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/news-aggregation/multi-source.md +205 -205
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/open-library/scraping.md +472 -472
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/openalex/scraping.md +470 -470
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/openstreetmap/scraping.md +490 -490
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/package-registries/npm-pypi.md +478 -478
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/polymarket/scraping.md +234 -234
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/producthunt/scraping.md +307 -307
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/pubmed/scraping.md +421 -421
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/quora/scraping.md +364 -364
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/rawg/scraping.md +352 -352
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/reddit/scraping.md +124 -124
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/rest-countries/scraping.md +233 -233
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/sec-edgar/scraping.md +361 -361
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/shopify-admin/README.md +36 -36
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/shopify-admin/embedded-apps.md +72 -72
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/shopify-admin/knowledge-base.md +109 -109
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/shopify-admin/polaris-inputs.md +137 -137
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/soundcloud/scraping.md +362 -362
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/spotify/scraping.md +339 -339
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/stackoverflow/scraping.md +435 -435
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/steam/scraping.md +575 -575
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/substack/scraping.md +338 -338
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/thetechgeeks/pricing.md +52 -52
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/tiktok/upload.md +107 -107
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/tradingview/scraping.md +309 -309
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/trello/boards-and-lists.md +88 -88
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/trustpilot/scraping.md +375 -375
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/walmart/scraping.md +444 -444
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/wayback-machine/scraping.md +306 -306
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/weather/scraping.md +398 -398
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/wellfound/scraping.md +596 -596
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/world-bank/scraping.md +356 -356
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/xiaohongshu/scraping.md +84 -84
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/youtube/scraping.md +418 -418
- package/dist/extensions/builtin/browser/agent-workspace/domain-skills/zillow/scraping.md +433 -433
- package/dist/extensions/builtin/browser/browser.md +73 -73
- package/dist/extensions/builtin/browser/install.md +142 -142
- package/dist/extensions/builtin/browser/interaction-skills/connection.md +48 -48
- package/dist/extensions/builtin/browser/interaction-skills/cookies.md +3 -3
- package/dist/extensions/builtin/browser/interaction-skills/cross-origin-iframes.md +3 -3
- package/dist/extensions/builtin/browser/interaction-skills/dialogs.md +64 -64
- package/dist/extensions/builtin/browser/interaction-skills/downloads.md +3 -3
- package/dist/extensions/builtin/browser/interaction-skills/drag-and-drop.md +3 -3
- package/dist/extensions/builtin/browser/interaction-skills/dropdowns.md +3 -3
- package/dist/extensions/builtin/browser/interaction-skills/iframes.md +3 -3
- package/dist/extensions/builtin/browser/interaction-skills/network-requests.md +3 -3
- package/dist/extensions/builtin/browser/interaction-skills/print-as-pdf.md +3 -3
- package/dist/extensions/builtin/browser/interaction-skills/profile-sync.md +90 -90
- package/dist/extensions/builtin/browser/interaction-skills/screenshots.md +17 -17
- package/dist/extensions/builtin/browser/interaction-skills/scrolling.md +3 -3
- package/dist/extensions/builtin/browser/interaction-skills/shadow-dom.md +3 -3
- package/dist/extensions/builtin/browser/interaction-skills/tabs.md +69 -69
- package/dist/extensions/builtin/browser/interaction-skills/uploads.md +1 -1
- package/dist/extensions/builtin/browser/interaction-skills/viewport.md +3 -3
- package/dist/extensions/builtin/browser/src/browser_harness/AGENT.md +15 -15
- package/dist/extensions/builtin/browser/src/browser_harness/__init__.py +8 -8
- package/dist/extensions/builtin/browser/src/browser_harness/_ipc.py +90 -90
- package/dist/extensions/builtin/browser/src/browser_harness/admin.py +722 -722
- package/dist/extensions/builtin/browser/src/browser_harness/daemon.py +328 -328
- package/dist/extensions/builtin/browser/src/browser_harness/helpers.py +396 -396
- package/dist/extensions/builtin/browser/src/browser_harness/run.py +103 -103
- package/dist/extensions/builtin/discipline/skills/brainstorming/SKILL.md +33 -33
- package/dist/extensions/builtin/discipline/skills/executing-plans/SKILL.md +25 -25
- package/dist/extensions/builtin/discipline/skills/finishing-development-branch/SKILL.md +25 -25
- package/dist/extensions/builtin/discipline/skills/receiving-code-review/SKILL.md +22 -22
- package/dist/extensions/builtin/discipline/skills/requesting-code-review/SKILL.md +31 -31
- package/dist/extensions/builtin/discipline/skills/systematic-debugging/SKILL.md +28 -28
- package/dist/extensions/builtin/discipline/skills/test-driven-development/SKILL.md +32 -32
- package/dist/extensions/builtin/discipline/skills/using-git-worktrees/SKILL.md +25 -25
- package/dist/extensions/builtin/discipline/skills/verification-before-completion/SKILL.md +27 -27
- package/dist/extensions/builtin/discipline/skills/writing-plans/SKILL.md +26 -26
- package/dist/extensions/builtin/goal/README.md +67 -67
- package/dist/extensions/builtin/goal/goal-controller.d.ts +39 -10
- package/dist/extensions/builtin/goal/goal-controller.js +1 -1
- package/dist/extensions/builtin/goal/goal-format.js +1 -1
- package/dist/extensions/builtin/goal/goal-prompts.d.ts +2 -0
- package/dist/extensions/builtin/goal/goal-prompts.js +5 -4
- package/dist/extensions/builtin/goal/goal-store.js +1 -1
- package/dist/extensions/builtin/goal/index.d.ts +1 -1
- package/dist/extensions/builtin/goal/index.js +10 -7
- package/dist/extensions/builtin/grub/README.md +112 -112
- package/dist/extensions/builtin/link-world/agent-workspace/README.md +16 -16
- package/dist/extensions/builtin/link-world/index.js +6 -6
- package/dist/extensions/builtin/link-world/internet-search/internet-search.md +65 -65
- package/dist/extensions/builtin/link-world/link-world-agent.md +82 -82
- package/dist/extensions/builtin/link-world/linkworld.md +313 -313
- package/dist/extensions/builtin/link-world/{network-routing.md → network-routing/network-routing.md} +67 -67
- package/dist/extensions/builtin/loop/README.md +92 -92
- package/dist/extensions/builtin/mcp/figma-design.md +68 -68
- package/dist/extensions/builtin/mcp/mcp-management.md +85 -85
- package/dist/extensions/builtin/plan/index.js +1 -1
- package/dist/extensions/builtin/recap/AGENT.md +15 -15
- package/dist/extensions/builtin/sal/README.md +72 -72
- package/dist/extensions/builtin/security-audit/README.md +289 -289
- package/dist/extensions/builtin/task/task-store.d.ts +4 -0
- package/dist/extensions/builtin/task/task-store.js +1 -1
- package/dist/extensions/builtin/team/AGENT.md +112 -112
- package/dist/extensions/builtin/team/TESTING.md +299 -299
- package/dist/extensions/builtin/token-save/README.md +56 -56
- package/dist/extensions/optional/AGENT.md +10 -10
- package/dist/index.d.ts +5 -30
- package/dist/index.js +1 -1
- package/dist/models.d.ts +7 -0
- package/dist/models.js +1 -0
- package/dist/modes/interactive/components/footer.js +1 -1
- package/dist/modes/interactive/components/task-status-panel.d.ts +36 -0
- package/dist/modes/interactive/components/task-status-panel.js +1 -0
- package/dist/modes/interactive/controllers/stream-render-controller.d.ts +7 -0
- package/dist/modes/interactive/controllers/stream-render-controller.js +2 -2
- package/dist/modes/interactive/interactive-mode.js +40 -40
- package/dist/modes/interactive/state/interactive-state.d.ts +2 -0
- package/dist/modes/interactive/state/interactive-state.js +1 -1
- package/dist/modes/interactive/theme/dark.json +85 -85
- package/dist/modes/interactive/theme/light.json +84 -84
- package/dist/modes/interactive/theme/theme-schema.json +335 -335
- package/dist/modes/interactive/theme/warm.json +81 -81
- package/dist/node_modules/@pencil-agent/ai/dist/cli.js +0 -0
- package/dist/node_modules/@pencil-agent/ai/dist/models.generated.js +1 -1
- package/dist/node_modules/@pencil-agent/ai/dist/providers/anthropic.js +2 -2
- package/dist/node_modules/@pencil-agent/ai/dist/providers/openai-completions.js +5 -5
- package/dist/node_modules/@pencil-agent/ai/dist/providers/openai-responses.js +1 -1
- package/dist/node_modules/@pencil-agent/ai/dist/stream.js +1 -1
- package/dist/packages/protocol/src/commands.d.ts +33 -0
- package/dist/packages/protocol/src/flags.d.ts +20 -0
- package/dist/packages/protocol/src/hooks.d.ts +17 -0
- package/dist/packages/protocol/src/hooks.js +0 -0
- package/dist/packages/{extension-sdk → protocol}/src/index.d.ts +7 -4
- package/dist/packages/protocol/src/index.js +1 -0
- package/dist/packages/{extension-sdk → protocol}/src/lifecycle.d.ts +15 -27
- package/dist/packages/protocol/src/lifecycle.js +0 -0
- package/dist/packages/{extension-sdk → protocol}/src/tools.d.ts +1 -1
- package/dist/packages/protocol/src/tools.js +0 -0
- package/dist/public-config.d.ts +12 -0
- package/dist/public-config.js +1 -0
- package/dist/runtime.d.ts +9 -0
- package/dist/runtime.js +1 -0
- package/dist/session-compaction.d.ts +7 -0
- package/dist/session-compaction.js +1 -0
- package/dist/session.d.ts +7 -0
- package/dist/session.js +1 -0
- package/dist/skills.d.ts +7 -0
- package/dist/skills.js +1 -0
- package/dist/tools.d.ts +7 -0
- package/dist/tools.js +1 -0
- 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
- package/docs/SDK-TESTING.md +364 -0
- package/docs/codex-goal-command-impl.md +1055 -1055
- package/docs/codex-goal-vs-grub.md +500 -500
- package/docs/custom-provider.md +27 -27
- package/docs/extensions.md +27 -27
- package/docs/keybindings.md +27 -27
- package/docs/loop /351/207/215/346/236/204/345/256/214/346/210/220/346/200/273/347/273/223.md" +250 -250
- package/docs/loop /351/207/215/346/236/204/345/256/214/346/210/220/346/212/245/345/221/212.md" +122 -122
- package/docs/loop /351/207/215/346/236/204/346/226/271/346/241/210.md" +1222 -1222
- 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
- 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
- package/docs/loop /351/207/215/346/236/204/350/256/241/345/210/222.md" +320 -320
- package/docs/loop-usage-examples.md +214 -214
- package/docs/mem-core/346/212/200/346/234/257/346/226/207/346/241/243.md +593 -0
- package/docs/models.md +27 -27
- package/docs/packages.md +27 -27
- package/docs/pi-design-philosophy.md +457 -457
- package/docs/planmode.md +1987 -1987
- package/docs/prompt-templates.md +27 -27
- package/docs/providers.md +27 -27
- package/docs/sdk.md +27 -27
- package/docs/skills.md +27 -27
- package/docs/startup-performance-optimization.md +301 -0
- package/docs/themes.md +27 -27
- package/docs/tui.md +27 -27
- package/docs//350/256/244/347/237/245/345/234/260/345/233/276.md +47 -0
- package/package.json +190 -162
- package/dist/packages/extension-sdk/src/index.js +0 -1
- package/docs/cc-agent-design.md +0 -1297
- package/docs/cc-tui-design.md +0 -1333
- package/docs//345/257/271/346/240/207Claude-Code.md +0 -1775
- /package/dist/packages/{extension-sdk/src/lifecycle.js → protocol/src/commands.js} +0 -0
- /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
|
建议优先实现这两个核心功能,其他优化可以根据实际使用情况逐步迭代。
|