@xynogen/pix-todo 0.1.9 → 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.
Files changed (3) hide show
  1. package/README.md +16 -0
  2. package/package.json +1 -1
  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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xynogen/pix-todo",
3
- "version": "0.1.9",
3
+ "version": "0.1.10",
4
4
  "description": "Pi tool — durable execution checklist (todo)",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
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
- /** Seconds before a todo card collapses to a one-line dim summary. */
19
- const COLLAPSE_AFTER_SEC = 10;
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
- if (!state.collapsed && !state.timer) {
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
- }, COLLAPSE_AFTER_SEC * 1000);
221
+ }, collapseDelayMs());
169
222
  }
170
223
  const render = state.collapsed
171
224
  ? renderTodoSummaryLine