@heyhuynhgiabuu/pi-task 0.1.5 → 0.2.0
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 +116 -4
- package/README.md +16 -11
- package/dist/constants.d.ts +4 -0
- package/dist/constants.js +4 -0
- package/dist/conversation.d.ts +76 -21
- package/dist/conversation.js +280 -70
- package/dist/helpers.d.ts +8 -8
- package/dist/helpers.js +34 -15
- package/dist/index.d.ts +6 -23
- package/dist/index.js +233 -634
- package/dist/lifecycle/completion.d.ts +3 -0
- package/dist/lifecycle/completion.js +50 -0
- package/dist/lifecycle/index.d.ts +5 -0
- package/dist/lifecycle/index.js +5 -0
- package/dist/lifecycle/polling.d.ts +16 -0
- package/dist/lifecycle/polling.js +61 -0
- package/dist/lifecycle/restore.d.ts +2 -0
- package/dist/lifecycle/restore.js +34 -0
- package/dist/lifecycle/toolStats.d.ts +2 -0
- package/dist/lifecycle/toolStats.js +17 -0
- package/dist/lifecycle/widget.d.ts +8 -0
- package/dist/lifecycle/widget.js +75 -0
- package/dist/session-text.d.ts +11 -2
- package/dist/session-text.js +78 -2
- package/dist/subagent/buildArgv.d.ts +1 -0
- package/dist/subagent/buildArgv.js +1 -1
- package/dist/subagent/runSdk.js +50 -26
- package/dist/subagent/tmux.d.ts +12 -9
- package/dist/subagent/tmux.js +107 -44
- package/dist/subagent/waitCompletion.d.ts +5 -5
- package/dist/subagent/waitCompletion.js +32 -41
- package/dist/task-widget.d.ts +21 -0
- package/dist/task-widget.js +122 -0
- package/dist/tool/index.d.ts +5 -0
- package/dist/tool/index.js +5 -0
- package/dist/tool/prompt.d.ts +8 -0
- package/dist/tool/prompt.js +17 -0
- package/dist/tool/renderCall.d.ts +3 -0
- package/dist/tool/renderCall.js +12 -0
- package/dist/tool/renderResult.d.ts +8 -0
- package/dist/tool/renderResult.js +51 -0
- package/dist/tool/schema.d.ts +8 -0
- package/dist/tool/schema.js +24 -0
- package/dist/tool/taskComplete.d.ts +8 -0
- package/dist/tool/taskComplete.js +65 -0
- package/dist/types.d.ts +54 -0
- package/dist/types.js +1 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,114 @@ All notable changes to `@heyhuynhgiabuu/pi-task` are documented here.
|
|
|
4
4
|
The format is based on [Keep a Changelog](https://keepachangelog.com/),
|
|
5
5
|
and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
6
6
|
|
|
7
|
+
## [0.2.0] — 2026-06-25
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- **Modular refactor of `src/`.** The single-file `index.ts` is now a thin
|
|
12
|
+
wiring layer; the implementation is split across focused modules:
|
|
13
|
+
- `src/tool/` — `renderCall`, `renderResult`, `taskComplete`, `prompt`,
|
|
14
|
+
`schema`.
|
|
15
|
+
- `src/lifecycle/` — `polling`, `completion`, `toolStats`, `widget`,
|
|
16
|
+
`restore`.
|
|
17
|
+
- `src/subagent/` — `buildArgv`, `runSdk`, `tmux`, `waitCompletion`.
|
|
18
|
+
- `src/conversation.ts` — `findJsonlSessionByName`, registry and
|
|
19
|
+
`task-session-history` helpers.
|
|
20
|
+
- `src/constants.ts` — `BACKGROUND_CHECK_MS`, `COUNT_POLL_MS`,
|
|
21
|
+
`TASK_TIMEOUT_MS`, `MAX_POLL_ERRORS`.
|
|
22
|
+
- `src/types.ts` — `BackgroundTask`, `RegistryEntry`,
|
|
23
|
+
`TaskSessionHistoryEntry`, `TaskDetails`.
|
|
24
|
+
- **Session JSONL is now the single source of truth for task results.**
|
|
25
|
+
`RESULT.md` is no longer read for completion detection or result text —
|
|
26
|
+
the final assistant message in `~/.pi/agent/sessions/.../<id>.jsonl`
|
|
27
|
+
is the authoritative result. This removes mid-write `EACCES` and
|
|
28
|
+
"stale truncated `RESULT.md`" failure modes entirely.
|
|
29
|
+
- **Completion detection is gated on `stopReason`.** `hasAgentFinished()`
|
|
30
|
+
in `src/session-text.ts` only treats an assistant message as final when
|
|
31
|
+
its `stopReason` is `stop`, `endTurn`, `length`, `error`, or `aborted`.
|
|
32
|
+
`toolUse` mid-turn streaming text is correctly ignored.
|
|
33
|
+
- **Background polling is hardened.**
|
|
34
|
+
- `checkInFlight` guard prevents overlapping poll ticks (no more
|
|
35
|
+
double-completion races on the `backgroundTasks` map).
|
|
36
|
+
- `MAX_POLL_ERRORS = 3` per-task counter absorbs transient filesystem
|
|
37
|
+
errors; a single rejected `readFile` no longer orphans a task.
|
|
38
|
+
- Try/catch around `checkTaskCompletion()` keeps the interval alive on
|
|
39
|
+
one-off failures.
|
|
40
|
+
- **Reordered completion check flow.** Session JSONL is consulted before
|
|
41
|
+
pane liveness, so `remain-on-exit` panes no longer block detection.
|
|
42
|
+
|
|
43
|
+
### Added
|
|
44
|
+
|
|
45
|
+
- `renderCall` / `renderResult` / task-complete renderers with **Ctrl+O
|
|
46
|
+
expand/collapse** (via `keyHint("app.tools.expand")`) on the `task`
|
|
47
|
+
tool. Foreground results show stats + preview; expanded shows the full
|
|
48
|
+
result text. The keybinding hint falls back to `Ctrl+O` if the
|
|
49
|
+
`app.tools.expand` keybinding is not registered.
|
|
50
|
+
- **Foreground real-time tool-call progress.** The foreground `execute`
|
|
51
|
+
path now polls the session file and emits `_onUpdate` callbacks while
|
|
52
|
+
waiting, so the parent pane shows a live `${n} tool calls` count
|
|
53
|
+
alongside the spawned subagent pane.
|
|
54
|
+
|
|
55
|
+
### Fixed
|
|
56
|
+
|
|
57
|
+
- The "scout - Description" / "scout — Description" duplicate header in
|
|
58
|
+
foreground results: `renderResult` no longer re-renders the header
|
|
59
|
+
that `renderCall` already rendered.
|
|
60
|
+
- The `( to expand)` empty-keybinding hint: now falls back to a plain
|
|
61
|
+
`Ctrl+O to expand` label when `keyText("app.tools.expand")` is empty.
|
|
62
|
+
|
|
63
|
+
### Verified
|
|
64
|
+
|
|
65
|
+
- `npm run typecheck` passes
|
|
66
|
+
- `npm run build` passes
|
|
67
|
+
- `npm run smoke` passes
|
|
68
|
+
- `npm pack --dry-run` succeeds
|
|
69
|
+
|
|
70
|
+
## [0.1.6] — 2026-06-25
|
|
71
|
+
|
|
72
|
+
### Changed
|
|
73
|
+
|
|
74
|
+
- Per-task data is now in flat files at the top of `.pi/artifacts/`.
|
|
75
|
+
No per-task subdirs, no `<task-id>` paths. The pikit canonical
|
|
76
|
+
files (TODO.md, PLAN.md, PROGRESS.md, DECISIONS.md) are flat at the
|
|
77
|
+
same level; pi-task files now sit alongside them.
|
|
78
|
+
- Refined the task TUI widget and background completion rendering:
|
|
79
|
+
foreground/background task stats now use consistent colors, background
|
|
80
|
+
completion summaries use a padded themed result block, completed
|
|
81
|
+
background widgets no longer duplicate the main-pane completion, and
|
|
82
|
+
final tool-call counts now match the live widget count.
|
|
83
|
+
|
|
84
|
+
### Layout
|
|
85
|
+
|
|
86
|
+
- `.pi/artifacts/TASKS.md` — one `### <task-id>` block per task, with
|
|
87
|
+
H4 subsections for `#### Metadata` (JSON) and `#### Result`.
|
|
88
|
+
- `.pi/artifacts/task-sessions.json` — registry mapping
|
|
89
|
+
`conversation_id` to `{ task_id, session_file }`. Renamed from
|
|
90
|
+
the v0.1.5 `task-conversations.json`.
|
|
91
|
+
- The subagent's session is auto-saved by pi at
|
|
92
|
+
`~/.pi/agent/sessions/<cwd>/<session-id>.jsonl`. pi-task reads
|
|
93
|
+
the last assistant message from there to populate `#### Result`
|
|
94
|
+
in `TASKS.md`. The subagent's final assistant message IS the
|
|
95
|
+
result; no separate result file is required.
|
|
96
|
+
|
|
97
|
+
### Removed
|
|
98
|
+
|
|
99
|
+
- `.pi/artifacts/task-<id>/` per-task subdirs (and the
|
|
100
|
+
`metadata.json` + `SESSION.md` + `sessions/` files inside them).
|
|
101
|
+
All per-task data lives in `TASKS.md` blocks now.
|
|
102
|
+
- `.pi/artifacts/task-conversations.json` — replaced by
|
|
103
|
+
`task-sessions.json`.
|
|
104
|
+
- The `taskArtifactName(taskId)` / `taskIdFromArtifactName(name)`
|
|
105
|
+
helpers and the `getArtifactsDir(piDir)` / `getTaskDir(piDir)` /
|
|
106
|
+
`getTaskRunsDir(piDir)` helpers.
|
|
107
|
+
|
|
108
|
+
### Verified
|
|
109
|
+
|
|
110
|
+
- `npm test` passes
|
|
111
|
+
- `npm run typecheck` passes
|
|
112
|
+
- `npm run build` passes
|
|
113
|
+
- `npm run smoke` passes
|
|
114
|
+
|
|
7
115
|
## [0.1.4] — 2026-06-21
|
|
8
116
|
|
|
9
117
|
### Fixed
|
|
@@ -76,7 +184,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
|
76
184
|
- `npm view @heyhuynhgiabuu/pi-task@0.1.2 pi` returns
|
|
77
185
|
`{ extensions: [ './dist/index.js' ] }`
|
|
78
186
|
|
|
79
|
-
[0.1.2]: https://github.com/
|
|
187
|
+
[0.1.2]: https://github.com/heyhuynhgiabuu/pi-task/releases/tag/v0.1.2
|
|
80
188
|
|
|
81
189
|
## [0.1.1] — 2025
|
|
82
190
|
|
|
@@ -116,6 +224,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
|
116
224
|
|
|
117
225
|
See the git history: `git log --oneline -- CHANGELOG.md`.
|
|
118
226
|
|
|
119
|
-
[0.1.1]: https://github.com/
|
|
120
|
-
[
|
|
121
|
-
[
|
|
227
|
+
[0.1.1]: https://github.com/heyhuynhgiabuu/pi-task/releases/tag/v0.1.1
|
|
228
|
+
[0.1.4]: https://github.com/heyhuynhgiabuu/pi-task/releases/tag/v0.1.4
|
|
229
|
+
[0.1.5]: https://github.com/heyhuynhgiabuu/pi-task/releases/tag/v0.1.5
|
|
230
|
+
[0.2.0]: https://github.com/heyhuynhgiabuu/pi-task/releases/tag/v0.2.0
|
|
231
|
+
[0.1.6]: https://github.com/heyhuynhgiabuu/pi-task/releases/tag/v0.1.6
|
|
232
|
+
[Keep a Changelog]: https://keepachangelog.com/
|
|
233
|
+
[Semantic Versioning]: https://semver.org/
|
package/README.md
CHANGED
|
@@ -66,20 +66,25 @@ Durable specialist conversation:
|
|
|
66
66
|
}
|
|
67
67
|
```
|
|
68
68
|
|
|
69
|
-
`conversation_id` maps to
|
|
69
|
+
`conversation_id` maps to a durable subagent run. Reused across calls
|
|
70
|
+
to keep specialist memory, e.g. a reusable research assistant.
|
|
71
|
+
Use `/task-sessions` to list known durable conversations.
|
|
70
72
|
|
|
71
|
-
Stored files
|
|
73
|
+
Stored files (all flat at the top of `.pi/artifacts/`, no
|
|
74
|
+
per-task subdirs):
|
|
72
75
|
|
|
73
|
-
```
|
|
74
|
-
.pi/artifacts/task-
|
|
75
|
-
.pi/artifacts/task
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
76
|
+
```
|
|
77
|
+
.pi/artifacts/TASKS.md # one ### <task-id> block per task
|
|
78
|
+
.pi/artifacts/task-sessions.json # conversation_id -> { task_id, session_file }
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
The subagent's session is auto-saved by pi at
|
|
82
|
+
`~/.pi/agent/sessions/<cwd>/<session-id>.jsonl`. pi-task reads
|
|
83
|
+
the last assistant message from there to populate
|
|
84
|
+
`#### Result` in `TASKS.md`. The subagent's final message IS
|
|
85
|
+
the result; no separate result file is required.
|
|
81
86
|
|
|
82
|
-
Note: true conversation resume requires the tmux/CLI backend so Pi can reopen the saved subagent session. SDK fallback can run one-shot tasks, but it cannot resume a prior Pi session.
|
|
87
|
+
Note: true conversation resume requires the tmux/CLI backend so Pi can reopen the saved subagent session. SDK fallback can run one-shot tasks, but it cannot resume a prior Pi session.
|
|
83
88
|
|
|
84
89
|
## Agent precedence
|
|
85
90
|
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export const BACKGROUND_CHECK_MS = 10_000; // poll every 10 sec
|
|
2
|
+
export const COUNT_POLL_MS = 3_000; // update toolcall counts every 3 sec
|
|
3
|
+
export const TASK_TIMEOUT_MS = 30 * 60 * 1_000; // 30 minutes
|
|
4
|
+
export const MAX_POLL_ERRORS = 3; // consecutive poll failures before giving up on a task
|
package/dist/conversation.d.ts
CHANGED
|
@@ -1,39 +1,94 @@
|
|
|
1
|
+
import type { RegistryEntry, TaskSessionHistoryEntry } from "./types.js";
|
|
1
2
|
/**
|
|
2
3
|
* Conversational subagent helpers.
|
|
3
4
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* `conversation_id`
|
|
5
|
+
* Per-task data lives in `.pi/artifacts/TASKS.md` as `### <task-id>` blocks.
|
|
6
|
+
* A small `task-sessions.json` registry in the same directory maps
|
|
7
|
+
* `conversation_id` to the auto-saved session file path so the
|
|
8
|
+
* subagent can be resumed later.
|
|
9
|
+
*
|
|
10
|
+
* The subagent's session is auto-saved by pi at
|
|
11
|
+
* `~/.pi/agent/sessions/<cwd>/<session-id>.jsonl`. pi-task does not
|
|
12
|
+
* maintain its own session storage.
|
|
13
|
+
*
|
|
14
|
+
* All artifacts live flat at the top of `.pi/artifacts/`, alongside the
|
|
15
|
+
* pikit canonical files (TODO.md, PLAN.md, PROGRESS.md, DECISIONS.md).
|
|
16
|
+
* No subdirs. No per-task paths.
|
|
7
17
|
*/
|
|
18
|
+
export declare const TASKS_FILE = "TASKS.md";
|
|
19
|
+
export declare const TASK_SESSIONS_REGISTRY_FILE = "task-sessions.json";
|
|
8
20
|
export interface ConversationMetadata {
|
|
9
21
|
conversation_id: string;
|
|
10
22
|
task_id: string;
|
|
11
|
-
artifact: string;
|
|
12
23
|
agent_type: string;
|
|
13
|
-
|
|
14
|
-
session_name: string;
|
|
24
|
+
session_file: string;
|
|
15
25
|
created_at: string;
|
|
16
26
|
last_used_at: string;
|
|
17
27
|
last_prompt?: string;
|
|
18
28
|
}
|
|
19
|
-
export type
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
export declare function
|
|
24
|
-
export declare function
|
|
29
|
+
export type TaskSessionsRegistry = Record<string, {
|
|
30
|
+
task_id: string;
|
|
31
|
+
session_file: string;
|
|
32
|
+
}>;
|
|
33
|
+
export declare function getTasksFilePath(piDir: string): string;
|
|
34
|
+
export declare function getTaskSessionsRegistryPath(piDir: string): string;
|
|
35
|
+
export declare function readRegistry(piDir: string): RegistryEntry[];
|
|
36
|
+
export declare function writeRegistry(piDir: string, entries: RegistryEntry[]): void;
|
|
37
|
+
export declare function readTaskSessionHistory(piDir: string): TaskSessionHistoryEntry[];
|
|
38
|
+
export declare function writeTaskSessionHistory(piDir: string, entries: TaskSessionHistoryEntry[]): void;
|
|
39
|
+
export declare function upsertTaskSessionHistory(piDir: string, entry: TaskSessionHistoryEntry): void;
|
|
40
|
+
export declare function findTaskSessionHistory(piDir: string, idOrSessionName: string): TaskSessionHistoryEntry | undefined;
|
|
41
|
+
export declare function findJsonlSessionByName(piDir: string, sessionName: string, agentType: string): TaskSessionHistoryEntry | undefined;
|
|
25
42
|
export declare function normalizeConversationId(value: unknown): string | undefined;
|
|
26
|
-
export declare function
|
|
27
|
-
export declare function
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
43
|
+
export declare function readTaskSessionsRegistry(piDir: string): TaskSessionsRegistry;
|
|
44
|
+
export declare function writeTaskSessionsRegistry(piDir: string, registry: TaskSessionsRegistry): void;
|
|
45
|
+
/**
|
|
46
|
+
* Find a `### <task-id>` block in TASKS.md. Returns the block content
|
|
47
|
+
* (everything between the heading and the next H3 or EOF) plus the
|
|
48
|
+
* status line if present. Returns undefined if no block exists.
|
|
49
|
+
*/
|
|
50
|
+
export declare function readTaskBlock(piDir: string, taskId: string): {
|
|
51
|
+
status: string | null;
|
|
52
|
+
body: string;
|
|
53
|
+
} | undefined;
|
|
54
|
+
export declare function listTaskBlocks(piDir: string): Map<string, {
|
|
55
|
+
status: string | null;
|
|
56
|
+
body: string;
|
|
57
|
+
}>;
|
|
58
|
+
/**
|
|
59
|
+
* Append or update a `### <task-id>` block in TASKS.md. If the block
|
|
60
|
+
* already exists, its body is replaced. Otherwise, the block is
|
|
61
|
+
* appended at the end of the file.
|
|
62
|
+
*/
|
|
63
|
+
export declare function writeTaskBlock(options: {
|
|
64
|
+
piDir: string;
|
|
65
|
+
taskId: string;
|
|
66
|
+
status: "active" | "done" | "abandoned";
|
|
67
|
+
updated: string;
|
|
68
|
+
body: string;
|
|
69
|
+
}): void;
|
|
70
|
+
export declare function parseMetadataFromBody(body: string | undefined): {
|
|
71
|
+
created_at?: string;
|
|
72
|
+
last_used_at?: string;
|
|
73
|
+
agent_type?: string;
|
|
74
|
+
session_file?: string;
|
|
75
|
+
conversation_id?: string;
|
|
76
|
+
last_prompt?: string;
|
|
77
|
+
} | undefined;
|
|
78
|
+
export interface WriteTaskBlockInput {
|
|
79
|
+
piDir: string;
|
|
32
80
|
taskId: string;
|
|
33
81
|
conversationId: string;
|
|
34
82
|
agentType: string;
|
|
35
|
-
|
|
36
|
-
sessionName: string;
|
|
83
|
+
sessionFile: string;
|
|
37
84
|
prompt: string;
|
|
38
|
-
|
|
85
|
+
result: string;
|
|
86
|
+
resultLabel?: string;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Persist a completed task: write (or update) the `### <task-id>` block
|
|
90
|
+
* in TASKS.md with metadata and result as H4 subsections. Also updates
|
|
91
|
+
* the task-sessions registry.
|
|
92
|
+
*/
|
|
93
|
+
export declare function writeConversationArtifacts(input: WriteTaskBlockInput): ConversationMetadata;
|
|
39
94
|
export declare function renderConversationSessions(piDir: string): string;
|