@xynogen/pix-todo 0.1.8 → 0.1.10
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 +16 -0
- package/package.json +1 -1
- package/src/todo.test.ts +5 -3
- package/src/todo.ts +57 -4
package/README.md
CHANGED
|
@@ -6,6 +6,22 @@ Pi tool — durable execution checklist (`todo`).
|
|
|
6
6
|
|
|
7
7
|
Registers the `todo` tool, which gives the agent a persistent task checklist that survives context compaction and session restore. The checklist is seeded by the model via the `set` action and tracks items through four statuses: `pending` (○), `in_progress` (◐), `done` (●), and `blocked` (⊘). State is persisted via Pi's `appendEntry("todo-state")` so the agent can recover its position after long runs or compaction events. The agent calls `todo(action:"list")` to resume where it left off. Actions: `list`, `set`, `add`, `update`, `clear`.
|
|
8
8
|
|
|
9
|
+
## Auto-collapse
|
|
10
|
+
|
|
11
|
+
The checklist card auto-collapses after a configurable delay (default 10 seconds, previously hardcoded). The delay and the per-tool toggle are read from `~/.pi/agent/pix.json`:
|
|
12
|
+
|
|
13
|
+
```jsonc
|
|
14
|
+
{
|
|
15
|
+
"collapse": {
|
|
16
|
+
"enabled": true,
|
|
17
|
+
"delayMs": 10000,
|
|
18
|
+
"tools": { "todo": true }
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Set `collapse.tools.todo: false` to keep the checklist always expanded. See `@xynogen/pix-data/collapse` for the full API.
|
|
24
|
+
|
|
9
25
|
## Install
|
|
10
26
|
|
|
11
27
|
```bash
|
package/package.json
CHANGED
package/src/todo.test.ts
CHANGED
|
@@ -504,6 +504,7 @@ describe("todo actions", () => {
|
|
|
504
504
|
// ─── Persistence ────────────────────────────────────────────────────────────
|
|
505
505
|
|
|
506
506
|
describe("persistence", () => {
|
|
507
|
+
type AppendCall = { type: string; data: unknown };
|
|
507
508
|
test("set persists todos", async () => {
|
|
508
509
|
const host = makeHost();
|
|
509
510
|
registerTodo(host.pi);
|
|
@@ -515,8 +516,9 @@ describe("persistence", () => {
|
|
|
515
516
|
host.appendCalls.length = 0;
|
|
516
517
|
await run(host.execute, { action: "set", items: "alpha\nbravo" });
|
|
517
518
|
expect(host.appendCalls.length).toBe(1);
|
|
518
|
-
|
|
519
|
-
|
|
519
|
+
const ac0 = host.appendCalls[0] as AppendCall;
|
|
520
|
+
expect(ac0.type).toBe("todo-state");
|
|
521
|
+
const data = ac0.data as {
|
|
520
522
|
todos: Array<{ id: number; text: string; status: string }>;
|
|
521
523
|
nextTodoId: number;
|
|
522
524
|
};
|
|
@@ -564,7 +566,7 @@ describe("persistence", () => {
|
|
|
564
566
|
host.appendCalls.length = 0;
|
|
565
567
|
await run(host.execute, { action: "clear" });
|
|
566
568
|
expect(host.appendCalls.length).toBe(1);
|
|
567
|
-
const data = host.appendCalls[0].data as {
|
|
569
|
+
const data = (host.appendCalls[0] as AppendCall).data as {
|
|
568
570
|
todos: Array<unknown>;
|
|
569
571
|
nextTodoId: number;
|
|
570
572
|
};
|
package/src/todo.ts
CHANGED
|
@@ -9,14 +9,66 @@
|
|
|
9
9
|
* checklist is seeded by the model via the tool's `set` action.
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
13
|
+
import { join } from "node:path";
|
|
12
14
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
13
15
|
import { Text } from "@earendil-works/pi-tui";
|
|
14
16
|
import { Type } from "typebox";
|
|
15
17
|
|
|
16
18
|
import { once } from "./once.ts";
|
|
17
19
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
+
// ── Collapse config from ~/.pi/agent/pix.json ────────────────────────────────
|
|
21
|
+
|
|
22
|
+
interface CollapseConf {
|
|
23
|
+
enabled: boolean;
|
|
24
|
+
delaySec: number;
|
|
25
|
+
tools: Record<string, boolean | undefined>;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const DEFAULT_COLLAPSE: CollapseConf = {
|
|
29
|
+
enabled: true,
|
|
30
|
+
delaySec: 10,
|
|
31
|
+
tools: {},
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
function readCollapseConfig(): CollapseConf {
|
|
35
|
+
try {
|
|
36
|
+
const home = process.env.HOME ?? "";
|
|
37
|
+
if (!home) return DEFAULT_COLLAPSE;
|
|
38
|
+
const p = join(home, ".pi/agent", "pix.json");
|
|
39
|
+
if (!existsSync(p)) return DEFAULT_COLLAPSE;
|
|
40
|
+
const raw = JSON.parse(readFileSync(p, "utf-8")) as Record<string, unknown>;
|
|
41
|
+
const c = raw?.collapse as Record<string, unknown> | undefined;
|
|
42
|
+
if (!c || typeof c !== "object") return DEFAULT_COLLAPSE;
|
|
43
|
+
return {
|
|
44
|
+
enabled: typeof c.enabled === "boolean" ? c.enabled : true,
|
|
45
|
+
delaySec:
|
|
46
|
+
typeof c.delaySec === "number" && c.delaySec > 0 ? c.delaySec : 10,
|
|
47
|
+
tools:
|
|
48
|
+
c.tools && typeof c.tools === "object"
|
|
49
|
+
? (c.tools as Record<string, boolean | undefined>)
|
|
50
|
+
: {},
|
|
51
|
+
};
|
|
52
|
+
} catch {
|
|
53
|
+
return DEFAULT_COLLAPSE;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
let collapseConf: CollapseConf | null = null;
|
|
58
|
+
function getCollapseConfig(): CollapseConf {
|
|
59
|
+
if (!collapseConf) collapseConf = readCollapseConfig();
|
|
60
|
+
return collapseConf;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function shouldCollapseTodo(): boolean {
|
|
64
|
+
const c = getCollapseConfig();
|
|
65
|
+
const perTool = c.tools.todo;
|
|
66
|
+
return typeof perTool === "boolean" ? perTool : c.enabled;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function collapseDelayMs(): number {
|
|
70
|
+
return getCollapseConfig().delaySec * 1000;
|
|
71
|
+
}
|
|
20
72
|
|
|
21
73
|
export type TodoStatus = "pending" | "in_progress" | "done" | "blocked";
|
|
22
74
|
|
|
@@ -161,11 +213,12 @@ export default function registerTodo(pi: ExtensionAPI): void {
|
|
|
161
213
|
};
|
|
162
214
|
if (!state.snapshot) state.snapshot = todos.map((t) => ({ ...t }));
|
|
163
215
|
// Start the collapse timer once per row; invalidate() triggers rerender.
|
|
164
|
-
|
|
216
|
+
// Config-driven: reads from ~/.pi/agent/pix.json collapse section.
|
|
217
|
+
if (shouldCollapseTodo() && !state.collapsed && !state.timer) {
|
|
165
218
|
state.timer = setTimeout(() => {
|
|
166
219
|
state.collapsed = true;
|
|
167
220
|
context.invalidate();
|
|
168
|
-
},
|
|
221
|
+
}, collapseDelayMs());
|
|
169
222
|
}
|
|
170
223
|
const render = state.collapsed
|
|
171
224
|
? renderTodoSummaryLine
|