@zhushanwen/pi-scheduler 0.8.0 → 0.8.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.
- package/README.md +3 -3
- package/package.json +4 -4
- package/skills/scheduler-ext-config/SKILL.md +3 -3
- package/src/importer.ts +2 -2
- package/vitest.config.ts +2 -4
package/README.md
CHANGED
|
@@ -14,11 +14,11 @@ pi-scheduler 是 **session 存活期间的 AI 提醒器**——在 pi 进程运
|
|
|
14
14
|
|
|
15
15
|
**任务归属创建它的 session**:任务物理存储在创建它的 session 的 JSONL 文件内,**只在 owner session 打开(继续对话 / resume)时才触发**。
|
|
16
16
|
|
|
17
|
-
> **这是设计决策,不是 bug(D9
|
|
17
|
+
> **这是设计决策,不是 bug(D9)**:本扩展定位是 **session 级 AI 提醒器**——任务归属创建它的 session,只在 owner session 存活时触发。如果你每天开新 session,昨天建的"明早检查 CI"任务今天不会响,除非你 resume 昨天创建该任务的那个 session。这不是"任务丢了":任务随 session 持久化,session 不打开就不调度。**用户若发现「昨天建的任务今天没响」,这是预期行为**,请 resume 创建该任务的 session。
|
|
18
18
|
|
|
19
19
|
## 简介与安装
|
|
20
20
|
|
|
21
|
-
pi-scheduler 是
|
|
21
|
+
pi-scheduler 是 taiji 的 **mandatory 扩展**(`packages/shared/src/mandatory-extensions.json`,tier: `feature`)——taiji 启动时自动安装并启用,无需手动操作。
|
|
22
22
|
|
|
23
23
|
独立 pi 环境手动安装:
|
|
24
24
|
|
|
@@ -228,7 +228,7 @@ npx vitest run src/__tests__/<file>.test.ts # 单个文件
|
|
|
228
228
|
|
|
229
229
|
测试策略:
|
|
230
230
|
|
|
231
|
-
- **依赖反转**:`SchedulerRuntime` 只依赖 `SchedulerBackend` 接口(`sendMessage` / `appendEntry` / `now`),不触碰 FS/pi。测试注入 `MockSchedulerBackend`(`src/__tests__/mock-backend.ts
|
|
231
|
+
- **依赖反转**:`SchedulerRuntime` 只依赖 `SchedulerBackend` 接口(`sendMessage` / `appendEntry` / `now`),不触碰 FS/pi。测试注入 `MockSchedulerBackend`(`src/__tests__/mock-backend.ts` 测试专用实现)实现零副作用测试
|
|
232
232
|
- **纯函数**:`parseDuration` / `formatDuration` / `parseSchedule` / `computeNextRunAt` / `computeNextRuns`(`src/parsing.ts`)无副作用,可直接断言
|
|
233
233
|
- **重放折叠**:custom entry 折叠协议(upsert / advance / toggle / delete,含 nextRunAt 重放恢复、fork owner 过滤)
|
|
234
234
|
- **旧 store 导入**:rename `.imported` 原子收敛(单成功者、崩溃恢复)
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhushanwen/pi-scheduler",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "index.ts",
|
|
6
|
-
"
|
|
6
|
+
"taiji": {
|
|
7
7
|
"role": "universal"
|
|
8
8
|
},
|
|
9
9
|
"pi": {
|
|
@@ -42,8 +42,8 @@
|
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"croner": "^9.0.0",
|
|
45
|
-
"@zhushanwen/pi-ext-guards": "0.4.
|
|
46
|
-
"@zhushanwen/pi-extension-logger": "0.6.
|
|
45
|
+
"@zhushanwen/pi-ext-guards": "0.4.1",
|
|
46
|
+
"@zhushanwen/pi-extension-logger": "0.6.1"
|
|
47
47
|
},
|
|
48
48
|
"scripts": {
|
|
49
49
|
"test": "vitest run",
|
|
@@ -72,7 +72,7 @@ description: "使用或排查 @zhushanwen/pi-scheduler(定时任务调度)
|
|
|
72
72
|
- 调用 `pi.appendEntry('pi-scheduler:task', op)`,`customType` 固定为 `pi-scheduler:task`。
|
|
73
73
|
- op 有四种:`upsert`(创建,携带全量 `TaskSnapshot`)、`advance`(recurring dispatch 成功后推进 `nextRunAt`)、`toggle`(启用/禁用)、`delete`(删除 / once 执行后 / 过期清理)。
|
|
74
74
|
- session 启动时(`session_start` 事件),`PiSchedulerBackend.loadTasks()` 调 `replayFoldEntries` 折叠当前 session 的全部 `pi-scheduler:task` custom entries,重放出当前任务状态。**append-only 不做全量 persist**——没有「保存」动作,每次操作即时 append。
|
|
75
|
-
- 因此「任务存哪」的答案是:**创建它的那个 session 的 JSONL 文件**。该文件位于 pi agent 目录下(`getAgentDir()` 读 `PI_CODING_AGENT_DIR`,默认 `~/.pi/agent`;
|
|
75
|
+
- 因此「任务存哪」的答案是:**创建它的那个 session 的 JSONL 文件**。该文件位于 pi agent 目录下(`getAgentDir()` 读 `PI_CODING_AGENT_DIR`,默认 `~/.pi/agent`;taiji 数据目录隔离时指向隔离目录如 `~/.taiji/...`)。
|
|
76
76
|
|
|
77
77
|
### owner 隔离(fork 行为)
|
|
78
78
|
|
|
@@ -99,7 +99,7 @@ description: "使用或排查 @zhushanwen/pi-scheduler(定时任务调度)
|
|
|
99
99
|
|
|
100
100
|
**迁移机制**(`importLegacyStore`,session_start 时自动执行,无需用户介入):
|
|
101
101
|
|
|
102
|
-
1. 双候选探测:优先 `getAgentDir()` 路径,不存在则 fallback `~/.pi/agent/scheduler/...`(兼容
|
|
102
|
+
1. 双候选探测:优先 `getAgentDir()` 路径,不存在则 fallback `~/.pi/agent/scheduler/...`(兼容 taiji 数据目录隔离前的旧版写入位置)。
|
|
103
103
|
2. 原子 rename `scheduler.json` → `scheduler.json.imported` 独占迁移;rename 抛 ENOENT 说明并发/崩溃已被别人处理,走 `.imported` 残留恢复。
|
|
104
104
|
3. 读取 `.imported`,逐任务 `appendEntry('pi-scheduler:task', upsert)` 写入当前 session(owner 归属当前 session)。
|
|
105
105
|
4. 删除 `.imported`:**新 session 首次 flush 前(尚未收到 assistant 消息)延迟删除**,由首个 `turn_end` / `session_shutdown` 确认 flush 后再删(防未 flush 即退出导致任务永久丢失 + 源文件已毁)。
|
|
@@ -186,6 +186,6 @@ schedule({ prompt: "...", schedule: "1h", kind: "recurring", force: true, expire
|
|
|
186
186
|
## 备注
|
|
187
187
|
|
|
188
188
|
- **croner 依赖**:cron 模式依赖 `croner`(dependencies,随包自动安装 + 静态 import,2026-09 0.6.0 起;此前为 optional peer,独立安装形态下 cron 任务会静默失败)。cron 解析失败(`INVALID_SCHEDULE`)= 表达式无效,不存在「解析器未安装」形态。
|
|
189
|
-
- **数据目录隔离**:任务存储在 `getAgentDir()` 指向的 session JSONL。
|
|
189
|
+
- **数据目录隔离**:任务存储在 `getAgentDir()` 指向的 session JSONL。taiji 通过 `TAIJI_AGENT_DATA_DIR` / `PI_CODING_AGENT_DIR` 隔离实例时,任务随 session 落在隔离目录,与 `~/.pi/agent` 互不干扰。
|
|
190
190
|
- **无配置 schema 可编辑**:scheduler 的所有状态都由运行时命令产生,没有可手动编辑的配置文件。要「批量预置任务」只能在 session 内逐条创建(或迁移旧 store)。
|
|
191
191
|
- **TUI 管理器未实现**:无参 `/schedule` 当前只返回提示,任务管理请用 `list`/`on`/`off`/`rm`/`run` 子命令或 `schedule_control` 工具。
|
package/src/importer.ts
CHANGED
|
@@ -21,7 +21,7 @@ const logger = getLogger('scheduler')
|
|
|
21
21
|
* export 供测试推导期望路径(断言 renameSync/unlinkSync 参数)。
|
|
22
22
|
*
|
|
23
23
|
* 双候选探测(合并 feat-auto-name-session-refactor 分支 4b5513b5e 后落实):
|
|
24
|
-
* 候选 1 用 pi 的 getAgentDir()(读 PI_CODING_AGENT_DIR,
|
|
24
|
+
* 候选 1 用 pi 的 getAgentDir()(读 PI_CODING_AGENT_DIR,taiji 数据目录隔离时指向隔离目录),
|
|
25
25
|
* 候选 2 是已发布版(npm 0.1.1)store.ts 的硬编码 `~/.pi/agent/scheduler/`。探测规则:
|
|
26
26
|
* 候选 1 存在则用候选 1(隔离实例的旧任务),否则 fallback 候选 2(0.1.1 版写入的真实数据源,
|
|
27
27
|
* 必须按此路径探测才能迁移)。getAgentDir() 未设置 env 时默认 ~/.pi/agent,两候选同路径,探测无副作用。
|
|
@@ -73,7 +73,7 @@ function normalizeLegacyTask(t: Partial<ScheduledTask>): ScheduledTask {
|
|
|
73
73
|
* ⚠️ unlink 时机(IMPORT-FLUSH-GUARD,MF-1 修复):pi SessionManager._persist 延迟写入——
|
|
74
74
|
* 新 session(sessionFile 尚不存在 → flushed=false)的 appendEntry 只进内存 fileEntries,
|
|
75
75
|
* 首个 assistant message 到达才 flush 落盘(openSync "wx" 全量写 fileEntries)。若紧随 append
|
|
76
|
-
* 循环 unlink,未 flush 即退出(打开未发消息即关闭、
|
|
76
|
+
* 循环 unlink,未 flush 即退出(打开未发消息即关闭、taiji 自动打开/恢复的 session)→
|
|
77
77
|
* 全部旧任务永久丢失且源文件已销毁,崩溃恢复路径(.imported 残留)同时失效。
|
|
78
78
|
* resumed session(sessionFile 已存在 → _setSessionFile 载入时 flushed=true)每次 append
|
|
79
79
|
* 即时写盘,unlink 安全。
|
package/vitest.config.ts
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { taijiTestConfig } from '../../../test-guard/factory.ts'
|
|
2
2
|
|
|
3
|
-
export default
|
|
3
|
+
export default taijiTestConfig({
|
|
4
4
|
test: {
|
|
5
|
-
reporters: ['default', 'junit'],
|
|
6
|
-
outputFile: { junit: './test-results/vitest-junit.xml' },
|
|
7
5
|
include: ['src/__tests__/**/*.test.ts'],
|
|
8
6
|
},
|
|
9
7
|
})
|