@zhushanwen/pi-todo 0.1.1 → 0.1.2
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 +45 -0
- package/package.json +8 -2
- package/src/index.ts +12 -12
package/README.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# todo
|
|
2
|
+
|
|
3
|
+
轻量级 AI 任务清单 — 三态(pending / in_progress / completed),支持 session 持久化、状态栏、批量操作。
|
|
4
|
+
|
|
5
|
+
## 功能
|
|
6
|
+
|
|
7
|
+
- **三态任务**:`pending` → `in_progress` → `completed`
|
|
8
|
+
- **批量操作**:add / update / delete / clear
|
|
9
|
+
- **Session 持久化**:任务状态保存在 session entries 中,重启后恢复
|
|
10
|
+
- **状态栏**:底部显示任务进度(如 `2/5 done`)
|
|
11
|
+
- **自动清理**:所有任务完成后自动清空
|
|
12
|
+
|
|
13
|
+
## 安装
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# symlink 方式(开发推荐)
|
|
17
|
+
ln -s /path/to/xyz-pi-extensions-workspace/main/packages/todo \
|
|
18
|
+
~/.pi/agent/extensions/todo
|
|
19
|
+
|
|
20
|
+
# npm 方式(正式)
|
|
21
|
+
pi install npm:@zhushanwen/pi-todo
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## 使用
|
|
25
|
+
|
|
26
|
+
AI 可调用 `todo` 工具:
|
|
27
|
+
|
|
28
|
+
| Action | 说明 |
|
|
29
|
+
|--------|------|
|
|
30
|
+
| `list` | 查看所有 todo |
|
|
31
|
+
| `add` | 批量添加 todo |
|
|
32
|
+
| `update` | 更新 todo(状态/文本) |
|
|
33
|
+
| `delete` | 批量删除 |
|
|
34
|
+
| `clear` | 清空所有 |
|
|
35
|
+
|
|
36
|
+
用户命令:`/todos` 交互式面板。
|
|
37
|
+
|
|
38
|
+
## 文件结构
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
todo/
|
|
42
|
+
├── index.ts
|
|
43
|
+
└── src/
|
|
44
|
+
└── index.ts # 入口 — 工具、命令、事件、状态栏
|
|
45
|
+
```
|
package/package.json
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhushanwen/pi-todo",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "AI-driven todo list for Pi — stateful task management with session persistence and /todos command.",
|
|
5
|
+
"type": "module",
|
|
5
6
|
"main": "src/index.ts",
|
|
7
|
+
"pi": {
|
|
8
|
+
"extensions": [
|
|
9
|
+
"./src/index.ts"
|
|
10
|
+
]
|
|
11
|
+
},
|
|
6
12
|
"keywords": [
|
|
7
|
-
"pi",
|
|
13
|
+
"pi-package",
|
|
8
14
|
"extension",
|
|
9
15
|
"todo",
|
|
10
16
|
"task",
|
package/src/index.ts
CHANGED
|
@@ -10,9 +10,9 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import { StringEnum } from "@mariozechner/pi-ai";
|
|
13
|
-
import type { ExtensionAPI, ExtensionContext, Theme } from "@mariozechner/pi-coding-agent";
|
|
13
|
+
import type { ExtensionAPI, ExtensionCommandContext, ExtensionContext, Theme } from "@mariozechner/pi-coding-agent";
|
|
14
14
|
import { matchesKey, Text, truncateToWidth } from "@mariozechner/pi-tui";
|
|
15
|
-
import { Type } from "typebox";
|
|
15
|
+
import { Type, type Static } from "typebox";
|
|
16
16
|
|
|
17
17
|
// ── 数据模型 ─────────────────────────────────────────
|
|
18
18
|
|
|
@@ -603,22 +603,22 @@ export default function (pi: ExtensionAPI) {
|
|
|
603
603
|
}
|
|
604
604
|
};
|
|
605
605
|
|
|
606
|
-
pi.on("session_start", async (_event, ctx) => {
|
|
606
|
+
pi.on("session_start", async (_event: any, ctx: ExtensionContext) => {
|
|
607
607
|
reconstructState(ctx);
|
|
608
608
|
refreshDisplay(ctx);
|
|
609
609
|
});
|
|
610
|
-
pi.on("session_tree", async (_event, ctx) => {
|
|
610
|
+
pi.on("session_tree", async (_event: any, ctx: ExtensionContext) => {
|
|
611
611
|
reconstructState(ctx);
|
|
612
612
|
refreshDisplay(ctx);
|
|
613
613
|
});
|
|
614
614
|
|
|
615
615
|
// v3: 追踪用户消息轮数
|
|
616
|
-
pi.on("agent_start", async (_event, _ctx) => {
|
|
616
|
+
pi.on("agent_start", async (_event: any, _ctx: ExtensionContext) => {
|
|
617
617
|
userMessageCount++;
|
|
618
618
|
});
|
|
619
619
|
|
|
620
620
|
// v3: 自动清空与提醒检查
|
|
621
|
-
pi.on("before_agent_start", async (_event, ctx) => {
|
|
621
|
+
pi.on("before_agent_start", async (_event: any, ctx: ExtensionContext) => {
|
|
622
622
|
try {
|
|
623
623
|
// 1. 自动清空:全部完成后经过 2 轮用户消息
|
|
624
624
|
if (allCompletedAtCount !== null && userMessageCount - allCompletedAtCount >= AUTO_CLEAR_DELAY_ROUNDS) {
|
|
@@ -700,8 +700,8 @@ export default function (pi: ExtensionAPI) {
|
|
|
700
700
|
],
|
|
701
701
|
parameters: TodoParams,
|
|
702
702
|
|
|
703
|
-
async execute(_toolCallId, params
|
|
704
|
-
const result = await executeTodoAction(params, ctx);
|
|
703
|
+
async execute(_toolCallId: string, params: Static<typeof TodoParams>, _signal: AbortSignal | undefined, _onUpdate: any, ctx: ExtensionContext) {
|
|
704
|
+
const result = await executeTodoAction(params as any, ctx);
|
|
705
705
|
// Append input params to error results for debugging
|
|
706
706
|
const details = result.details as { error?: string } | undefined;
|
|
707
707
|
if (details?.error) {
|
|
@@ -714,7 +714,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
714
714
|
return result;
|
|
715
715
|
},
|
|
716
716
|
|
|
717
|
-
renderCall(args, theme, _context) {
|
|
717
|
+
renderCall(args: any, theme: Theme, _context?: any) {
|
|
718
718
|
let text = theme.fg("toolTitle", theme.bold("todo ")) + theme.fg("muted", args.action);
|
|
719
719
|
if (args.texts && args.texts.length > 0) text += ` ${theme.fg("dim", `(${args.texts.length} items)`)}`;
|
|
720
720
|
if (args.ids && args.ids.length > 0) text += ` ${theme.fg("accent", `#${args.ids.join(", #")}`)}`;
|
|
@@ -724,20 +724,20 @@ export default function (pi: ExtensionAPI) {
|
|
|
724
724
|
return new Text(text, 0, 0);
|
|
725
725
|
},
|
|
726
726
|
|
|
727
|
-
renderResult(result, options, theme, _context) {
|
|
727
|
+
renderResult(result: any, options: any, theme: Theme, _context?: any) {
|
|
728
728
|
return renderTodoResult(result, options, theme);
|
|
729
729
|
},
|
|
730
730
|
});
|
|
731
731
|
|
|
732
732
|
pi.registerCommand("todos", {
|
|
733
733
|
description: "\u67e5\u770b\u5f53\u524d\u5206\u652f\u7684\u6240\u6709 todo",
|
|
734
|
-
handler: async (_args, ctx) => {
|
|
734
|
+
handler: async (_args: string | undefined, ctx: ExtensionCommandContext) => {
|
|
735
735
|
if (!ctx.hasUI) {
|
|
736
736
|
ctx.ui.notify("/todos \u9700\u8981\u4ea4\u4e92\u6a21\u5f0f", "error");
|
|
737
737
|
return;
|
|
738
738
|
}
|
|
739
739
|
|
|
740
|
-
await ctx.ui.custom
|
|
740
|
+
await ctx.ui.custom((_tui: any, theme: Theme, _kb: any, done: () => void) => {
|
|
741
741
|
return new TodoListComponent(todos, theme, () => done());
|
|
742
742
|
});
|
|
743
743
|
},
|