@agnishc/edb-todo 0.8.1 → 0.10.3

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/CHANGELOG.md CHANGED
@@ -1,5 +1,55 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.10.3] - 2026-05-15
4
+
5
+ ## [0.9.0] - 2026-05-15
6
+
7
+ ### Added
8
+ - `todo_create` tool — create individual tasks with `content`, `description`, `priority`, `activeForm`, and `metadata`
9
+ - `todo_get` tool — retrieve full task details: description, dependencies (`blocks`/`blockedBy`), metadata
10
+ - `todo_update` tool — update individual tasks (status, content, description, priority, owner); add dependency edges (`addBlocks`/`addBlockedBy`); `status: "deleted"` permanently removes the task
11
+ - **File-backed storage** — tasks now persist to disk with file locking and atomic writes
12
+ - `memory`: in-memory only (lost on session end)
13
+ - `session` *(default)*: per-session file at `<cwd>/.pi/tasks/tasks-<sessionId>.json`
14
+ - `project`: shared across all sessions at `<cwd>/.pi/tasks/tasks.json`
15
+ - **Dependency management** — bidirectional `blocks`/`blockedBy` edges with cycle detection and warnings
16
+ - **Auto-clear completed tasks** — configurable via settings: `never` / `on_list_complete` *(default)* / `on_task_complete`; turn-based delay so completions linger briefly before disappearing
17
+ - **Settings panel** — `/todos → ⚙ Settings` opens a native TUI settings panel (taskScope + autoClearCompleted); saved to `<cwd>/.pi/tasks-config.json`
18
+ - **System-reminder injection** — periodic `<system-reminder>` nudges appended to non-task tool results after `REMINDER_INTERVAL` turns of inactivity, encouraging the model to keep tasks up to date
19
+ - **Enhanced widget** — animated star spinner (✳✴✵…) for in-progress tasks, elapsed time display (e.g. `42s`, `2m 5s`), blocked-by hints inline
20
+ - `PI_TODO` environment variable override: `off` (memory only), named list (`~/.pi/tasks/<name>.json`), or absolute/relative path
21
+ - `/todos` command now shows a select-based menu with View / Clear completed / Clear all / Settings
22
+
23
+ ### Changed
24
+ - Widget placement changed from status bar to **above editor** (persistent, always visible)
25
+ - Session state no longer reconstructed from tool-result branch entries — file-backed store is the source of truth
26
+ - `todo_write` now merges `blocks`, `blockedBy`, and `metadata` from existing tasks when a task ID is reused (non-destructive for dependency edges)
27
+ - System prompt injection now includes task IDs and blocked-by info
28
+ - `priorityLabel` now correctly outputs `High`/`Medium`/`Low`
29
+
30
+ ## [0.8.2] - 2026-05-11
31
+
32
+ ### Added
33
+ - `todo_remove` tool — permanently remove tasks by ID
34
+ - Interactive keyboard navigation in `/todos` viewer (↑↓/jk, g/G, Home/End)
35
+ - Toggle completed task visibility with `c` key in `/todos` viewer
36
+ - Timestamps on tasks: `createdAt`, `startedAt`, `completedAt`
37
+ - Status transition tracking — timestamps update automatically when tasks move between states
38
+ - Percentage display in progress bar
39
+
40
+ ### Changed
41
+ - Replaced module-level mutable globals (`tasks`, `idCounter`) with `TodoStore` class
42
+ - Deduplicated rendering logic — shared `priorityColor()`, `priorityLabel()` helpers used everywhere
43
+ - Priority labels now display as `High`/`Medium`/`Low` instead of `HIG`/`MED`/`LOW`
44
+ - In-progress icon changed from `→` to `●` for visual consistency
45
+ - `/todos` viewer now shows cursor indicator (`❯`) on focused task
46
+ - Section headers show task counts
47
+ - Updated widget status bar to use `●` for active count
48
+ - `todo_write` prompt guidelines now explicitly state completed tasks are never auto-deleted
49
+
50
+ ### Fixed
51
+ - Rendering inconsistency between widget, viewer, and tool results — all now use the same styling
52
+
3
53
  ## [0.8.1] - 2026-05-11
4
54
 
5
55
  ## [0.6.0] - 2026-05-11
package/README.md CHANGED
@@ -2,38 +2,171 @@
2
2
 
3
3
  A Pi CLI extension that gives the agent a structured task list to prevent **goal drift** — the tendency for agents to lose track of the original plan as context grows and tool calls accumulate.
4
4
 
5
+ ## Features
6
+
7
+ - **6 LLM tools** — `TaskCreate`, `TaskList`, `TaskGet`, `TaskUpdate`, `TaskOutput`, `TaskStop` — matching pi-tasks behavior
8
+ - **Persistent widget** — live task list above the editor with animated spinner (✳✽), elapsed time, and blocked-by hints
9
+ - **File-backed storage** — memory / session / project scope with file locking and atomic writes
10
+ - **Dependency management** — bidirectional `blocks` / `blockedBy` edges with cycle detection
11
+ - **Auto-clear completed tasks** — configurable: never / on_list_complete / on_task_complete
12
+ - **System-reminder injection** — periodic nudges when task tools haven't been used recently
13
+ - **Settings panel** — `/todos → ⚙ Settings` (task storage + auto-clear, saved to `tasks-config.json`)
14
+ - **Priority system** — high / medium / low with color coding (Red / Yellow / Dim)
15
+
5
16
  ## How it works
6
17
 
7
- 1. The agent calls `todo_write` to plan multi-step work as an explicit task list
8
- 2. Before every agent turn, active tasks are injected into the system prompt so the model always knows what remains and what it's currently doing
9
- 3. A live widget above the editor shows the current task list at all times
10
- 4. State is reconstructed from the session branch, so `/tree` navigation and forking work correctly
18
+ 1. The agent uses `TaskCreate` to plan multi-step work as a structured task list
19
+ 2. Before every agent turn, active tasks are injected into the system prompt
20
+ 3. A live widget above the editor shows tasks with status icons and elapsed time for active tasks
21
+ 4. Tasks persist to disk per-session (or project-wide) and survive session resume
22
+ 5. Completed tasks remain visible until auto-cleared or manually removed
11
23
 
12
24
  ## Tools
13
25
 
14
- | Tool | Description |
15
- |------|-------------|
16
- | `todo_write` | Replace the entire task list (atomic update) — always pass all tasks |
17
- | `todo_read` | Read the current task list and statuses |
26
+ ### `TaskCreate`
18
27
 
19
- ## Task statuses
28
+ Create a structured task. Used proactively for complex multi-step work.
20
29
 
21
- | Status | Icon | Meaning |
22
- |--------|------|---------|
23
- | `pending` | `○` | Not started |
24
- | `in_progress` | `→` | Actively working only one at a time |
25
- | `completed` | `✓` | Done |
30
+ | Parameter | Type | Required | Description |
31
+ |-----------|------|----------|-------------|
32
+ | `content` | string | | Brief actionable title in imperative form |
33
+ | `description` | string | | Detailed context and acceptance criteria |
34
+ | `priority` | `high` \| `medium` \| `low` | | Default: `medium` |
35
+ | `activeForm` | string | | Spinner text when in_progress (e.g., "Running tests") |
36
+ | `metadata` | object | | Arbitrary key-value pairs |
26
37
 
27
- ## Install
38
+ ### `TaskList`
39
+
40
+ List all tasks sorted by status (pending first, then in_progress, then completed) and ID.
41
+
42
+ Returns each task's id, content, status, priority, and open blockedBy entries.
43
+
44
+ ### `TaskGet`
45
+
46
+ Get full details for a specific task by ID — including description, dependencies, and metadata.
47
+
48
+ | Parameter | Type | Description |
49
+ |-----------|------|-------------|
50
+ | `id` | string | The task ID |
51
+
52
+ ### `TaskUpdate`
53
+
54
+ Update task fields, status, and dependencies.
55
+
56
+ | Parameter | Type | Description |
57
+ |-----------|------|-------------|
58
+ | `id` | string | Task ID (required) |
59
+ | `status` | `pending` \| `in_progress` \| `completed` \| `deleted` | New status (`deleted` permanently removes) |
60
+ | `content` | string | New title |
61
+ | `description` | string | New description |
62
+ | `priority` | `high` \| `medium` \| `low` | New priority |
63
+ | `activeForm` | string | Spinner text |
64
+ | `owner` | string | Agent/owner name |
65
+ | `metadata` | object | Shallow merge (set key to `null` to delete) |
66
+ | `addBlocks` | string[] | Task IDs this task blocks |
67
+ | `addBlockedBy` | string[] | Task IDs that block this task |
68
+
69
+ Setting `status: "deleted"` permanently removes the task and cleans up all dependency edges.
70
+
71
+ Dependencies are bidirectional — `addBlocks: ["t2"]` on task `t1` also adds `blockedBy: ["t1"]` to task `t2`.
72
+
73
+ ### `TaskOutput`
74
+
75
+ Retrieve output from a running or completed background task process.
76
+
77
+ | Parameter | Type | Default | Description |
78
+ |-----------|------|---------|-------------|
79
+ | `task_id` | string | — | Task ID (required) |
80
+ | `block` | boolean | `true` | Wait for completion |
81
+ | `timeout` | number | `30000` | Max wait time in ms (max 600000) |
82
+
83
+ ### `TaskStop`
84
+
85
+ Stop a running background task process. Sends SIGTERM, waits 5 seconds, then SIGKILL. Marks the task as completed.
86
+
87
+ | Parameter | Type | Description |
88
+ |-----------|------|-------------|
89
+ | `task_id` | string | Task ID to stop |
90
+
91
+ ## Task lifecycle
92
+
93
+ ```
94
+ pending → in_progress → completed
95
+ → deleted (permanently removed)
96
+ ```
97
+
98
+ ## Dependency management
28
99
 
29
100
  ```bash
30
- pi install npm:@agnishc/edb-todo
101
+ # Task t2 cannot start until t1 is completed
102
+ TaskUpdate { id: "t2", addBlockedBy: ["t1"] }
31
103
  ```
32
104
 
33
- ## Usage
105
+ Edges are bidirectional. The widget and `TaskList` show open blockers inline (`› blocked by #t1`). Cycles and self-dependencies produce warnings but are stored.
106
+
107
+ ## Task storage
108
+
109
+ Configured via `/todos → ⚙ Settings` or the `PI_TODO` environment variable:
110
+
111
+ | Mode | File | Behaviour |
112
+ |------|------|-----------|
113
+ | `memory` | *(none)* | In-memory only — tasks lost when session ends |
114
+ | `session` *(default)* | `<cwd>/.pi/tasks/tasks-<sessionId>.json` | Per-session, survives resume |
115
+ | `project` | `<cwd>/.pi/tasks/tasks.json` | Shared across all sessions in the project |
116
+
117
+ Settings are saved to `<cwd>/.pi/tasks-config.json`.
118
+
119
+ ### Environment variable override
34
120
 
121
+ | Variable | Value | Behaviour |
122
+ |----------|-------|-----------|
123
+ | `PI_TODO` | `off` | In-memory only (CI/automation) |
124
+ | `PI_TODO` | `sprint-1` | Named shared list at `~/.pi/tasks/sprint-1.json` |
125
+ | `PI_TODO` | `/abs/path.json` | Explicit absolute file path |
126
+
127
+ ## Auto-clear completed tasks
128
+
129
+ | Mode | Behaviour |
130
+ |------|-----------|
131
+ | `never` | Completed tasks stay visible until manually cleared |
132
+ | `on_list_complete` *(default)* | Cleared after all tasks complete and a few idle turns pass |
133
+ | `on_task_complete` | Each task cleared individually a few turns after completion |
134
+
135
+ ## Widget
136
+
137
+ Persistent task list rendered above the editor:
138
+
139
+ ```
140
+ ● 4 tasks (1 done, 1 in progress, 2 open)
141
+ ✔ Design the API
142
+ ✳ Implementing auth… (42s)
143
+ ◻ Write tests › blocked by #t2
144
+ ◻ Update docs
35
145
  ```
36
- /todos — open the interactive full-screen task viewer
146
+
147
+ | Icon | Meaning |
148
+ |------|---------|
149
+ | `✔` | Completed (strikethrough + dim) |
150
+ | `◼` | In-progress |
151
+ | `✳`/`✽` | Animated spinner — actively executing (shows elapsed time) |
152
+ | `◻` | Pending |
153
+
154
+ ## `/todos` command
155
+
156
+ ```
157
+ /todos — open the interactive task manager
158
+ ```
159
+
160
+ Menu options:
161
+ - **View all tasks** — select a task to start / complete / delete it
162
+ - **Clear completed** — remove all completed tasks
163
+ - **Clear all** — remove all tasks
164
+ - **⚙ Settings** — configure task storage and auto-clear
165
+
166
+ ## Install
167
+
168
+ ```bash
169
+ pi install npm:@agnishc/edb-todo
37
170
  ```
38
171
 
39
172
  ## License
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agnishc/edb-todo",
3
- "version": "0.8.1",
3
+ "version": "0.10.3",
4
4
  "description": "Pi extension: structured task list with live widget and system-prompt injection to prevent goal drift",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -0,0 +1,87 @@
1
+ /**
2
+ * auto-clear.ts — Turn-based auto-clearing of completed tasks.
3
+ *
4
+ * Two modes:
5
+ * - "on_task_complete": each completed task gets its own countdown, deleted individually
6
+ * - "on_list_complete": countdown starts when ALL tasks are completed, cleared as a batch
7
+ */
8
+
9
+ import type { FileTaskStore } from "./file-store.js";
10
+
11
+ export type AutoClearMode = "never" | "on_list_complete" | "on_task_complete";
12
+
13
+ export class AutoClearManager {
14
+ /** Per-task: turn when task was marked completed ("on_task_complete" mode). */
15
+ private completedAtTurn = new Map<string, number>();
16
+ /** Turn when ALL tasks became completed ("on_list_complete" mode). */
17
+ private allCompletedAtTurn: number | null = null;
18
+
19
+ constructor(
20
+ public getStore: () => FileTaskStore,
21
+ private getMode: () => AutoClearMode,
22
+ /** How many turns completed tasks linger before auto-clearing. */
23
+ private clearDelayTurns = 4,
24
+ ) {}
25
+
26
+ /** Record a task completion. Call after updating status. */
27
+ trackCompletion(taskId: string, currentTurn: number): void {
28
+ const mode = this.getMode();
29
+ if (mode === "never") return;
30
+
31
+ if (mode === "on_task_complete") {
32
+ this.completedAtTurn.set(taskId, currentTurn);
33
+ } else if (mode === "on_list_complete") {
34
+ this.checkAllCompleted(currentTurn);
35
+ }
36
+ }
37
+
38
+ private checkAllCompleted(currentTurn: number): void {
39
+ const tasks = this.getStore().list();
40
+ if (tasks.length > 0 && tasks.every((t) => t.status === "completed")) {
41
+ if (this.allCompletedAtTurn === null) this.allCompletedAtTurn = currentTurn;
42
+ } else {
43
+ this.allCompletedAtTurn = null;
44
+ }
45
+ }
46
+
47
+ /** Reset batch countdown (e.g., when a new task is created). */
48
+ resetBatchCountdown(): void {
49
+ this.allCompletedAtTurn = null;
50
+ }
51
+
52
+ /** Reset all tracking state (e.g., on new session). */
53
+ reset(): void {
54
+ this.completedAtTurn.clear();
55
+ this.allCompletedAtTurn = null;
56
+ }
57
+
58
+ /**
59
+ * Called on each turn start. Deletes tasks whose linger period has expired.
60
+ * Returns true if any tasks were cleared.
61
+ */
62
+ onTurnStart(currentTurn: number): boolean {
63
+ const mode = this.getMode();
64
+ let cleared = false;
65
+
66
+ if (mode === "on_task_complete") {
67
+ for (const [taskId, turn] of this.completedAtTurn) {
68
+ const task = this.getStore().get(taskId);
69
+ if (!task || task.status !== "completed") {
70
+ this.completedAtTurn.delete(taskId);
71
+ } else if (currentTurn - turn >= this.clearDelayTurns) {
72
+ this.getStore().delete(taskId);
73
+ this.completedAtTurn.delete(taskId);
74
+ cleared = true;
75
+ }
76
+ }
77
+ } else if (mode === "on_list_complete" && this.allCompletedAtTurn !== null) {
78
+ if (currentTurn - this.allCompletedAtTurn >= this.clearDelayTurns) {
79
+ this.getStore().clearCompleted();
80
+ this.allCompletedAtTurn = null;
81
+ cleared = true;
82
+ }
83
+ }
84
+
85
+ return cleared;
86
+ }
87
+ }