@mariozechner/pi-coding-agent 0.30.2 → 0.31.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.
Files changed (297) hide show
  1. package/CHANGELOG.md +244 -1
  2. package/README.md +105 -84
  3. package/dist/cli/args.d.ts.map +1 -1
  4. package/dist/cli/args.js +5 -1
  5. package/dist/cli/args.js.map +1 -1
  6. package/dist/cli/file-processor.d.ts +3 -3
  7. package/dist/cli/file-processor.d.ts.map +1 -1
  8. package/dist/cli/file-processor.js +7 -10
  9. package/dist/cli/file-processor.js.map +1 -1
  10. package/dist/config.d.ts +9 -0
  11. package/dist/config.d.ts.map +1 -1
  12. package/dist/config.js +18 -0
  13. package/dist/config.js.map +1 -1
  14. package/dist/core/agent-session.d.ts +73 -34
  15. package/dist/core/agent-session.d.ts.map +1 -1
  16. package/dist/core/agent-session.js +464 -210
  17. package/dist/core/agent-session.js.map +1 -1
  18. package/dist/core/auth-storage.d.ts +2 -2
  19. package/dist/core/auth-storage.d.ts.map +1 -1
  20. package/dist/core/auth-storage.js +2 -2
  21. package/dist/core/auth-storage.js.map +1 -1
  22. package/dist/core/bash-executor.d.ts +2 -2
  23. package/dist/core/bash-executor.d.ts.map +1 -1
  24. package/dist/core/bash-executor.js +2 -2
  25. package/dist/core/bash-executor.js.map +1 -1
  26. package/dist/core/compaction/branch-summarization.d.ts +84 -0
  27. package/dist/core/compaction/branch-summarization.d.ts.map +1 -0
  28. package/dist/core/compaction/branch-summarization.js +233 -0
  29. package/dist/core/compaction/branch-summarization.js.map +1 -0
  30. package/dist/core/{compaction.d.ts → compaction/compaction.d.ts} +38 -19
  31. package/dist/core/compaction/compaction.d.ts.map +1 -0
  32. package/dist/core/compaction/compaction.js +558 -0
  33. package/dist/core/compaction/compaction.js.map +1 -0
  34. package/dist/core/compaction/index.d.ts +7 -0
  35. package/dist/core/compaction/index.d.ts.map +1 -0
  36. package/dist/core/compaction/index.js +7 -0
  37. package/dist/core/compaction/index.js.map +1 -0
  38. package/dist/core/compaction/utils.d.ts +35 -0
  39. package/dist/core/compaction/utils.d.ts.map +1 -0
  40. package/dist/core/compaction/utils.js +138 -0
  41. package/dist/core/compaction/utils.js.map +1 -0
  42. package/dist/core/custom-tools/index.d.ts +2 -1
  43. package/dist/core/custom-tools/index.d.ts.map +1 -1
  44. package/dist/core/custom-tools/index.js +1 -0
  45. package/dist/core/custom-tools/index.js.map +1 -1
  46. package/dist/core/custom-tools/loader.d.ts.map +1 -1
  47. package/dist/core/custom-tools/loader.js +13 -80
  48. package/dist/core/custom-tools/loader.js.map +1 -1
  49. package/dist/core/custom-tools/types.d.ts +84 -59
  50. package/dist/core/custom-tools/types.d.ts.map +1 -1
  51. package/dist/core/custom-tools/types.js.map +1 -1
  52. package/dist/core/custom-tools/wrapper.d.ts +15 -0
  53. package/dist/core/custom-tools/wrapper.d.ts.map +1 -0
  54. package/dist/core/custom-tools/wrapper.js +23 -0
  55. package/dist/core/custom-tools/wrapper.js.map +1 -0
  56. package/dist/core/exec.d.ts +29 -0
  57. package/dist/core/exec.d.ts.map +1 -0
  58. package/dist/core/exec.js +71 -0
  59. package/dist/core/exec.js.map +1 -0
  60. package/dist/core/export-html/index.d.ts +17 -0
  61. package/dist/core/export-html/index.d.ts.map +1 -0
  62. package/dist/core/export-html/index.js +171 -0
  63. package/dist/core/export-html/index.js.map +1 -0
  64. package/dist/core/export-html/template.css +781 -0
  65. package/dist/core/export-html/template.html +54 -0
  66. package/dist/core/export-html/template.js +1185 -0
  67. package/dist/core/export-html/vendor/highlight.min.js +1213 -0
  68. package/dist/core/export-html/vendor/marked.min.js +6 -0
  69. package/dist/core/hooks/index.d.ts +4 -4
  70. package/dist/core/hooks/index.d.ts.map +1 -1
  71. package/dist/core/hooks/index.js +3 -3
  72. package/dist/core/hooks/index.js.map +1 -1
  73. package/dist/core/hooks/loader.d.ts +40 -5
  74. package/dist/core/hooks/loader.d.ts.map +1 -1
  75. package/dist/core/hooks/loader.js +43 -10
  76. package/dist/core/hooks/loader.js.map +1 -1
  77. package/dist/core/hooks/runner.d.ts +94 -18
  78. package/dist/core/hooks/runner.d.ts.map +1 -1
  79. package/dist/core/hooks/runner.js +199 -120
  80. package/dist/core/hooks/runner.js.map +1 -1
  81. package/dist/core/hooks/tool-wrapper.d.ts +1 -1
  82. package/dist/core/hooks/tool-wrapper.d.ts.map +1 -1
  83. package/dist/core/hooks/tool-wrapper.js +36 -19
  84. package/dist/core/hooks/tool-wrapper.js.map +1 -1
  85. package/dist/core/hooks/types.d.ts +407 -96
  86. package/dist/core/hooks/types.d.ts.map +1 -1
  87. package/dist/core/hooks/types.js.map +1 -1
  88. package/dist/core/index.d.ts +4 -3
  89. package/dist/core/index.d.ts.map +1 -1
  90. package/dist/core/index.js.map +1 -1
  91. package/dist/core/messages.d.ts +44 -12
  92. package/dist/core/messages.d.ts.map +1 -1
  93. package/dist/core/messages.js +82 -34
  94. package/dist/core/messages.js.map +1 -1
  95. package/dist/core/model-registry.d.ts +5 -5
  96. package/dist/core/model-registry.d.ts.map +1 -1
  97. package/dist/core/model-registry.js +7 -7
  98. package/dist/core/model-registry.js.map +1 -1
  99. package/dist/core/model-resolver.d.ts +7 -7
  100. package/dist/core/model-resolver.d.ts.map +1 -1
  101. package/dist/core/model-resolver.js +45 -14
  102. package/dist/core/model-resolver.js.map +1 -1
  103. package/dist/core/sdk.d.ts +7 -10
  104. package/dist/core/sdk.d.ts.map +1 -1
  105. package/dist/core/sdk.js +88 -32
  106. package/dist/core/sdk.js.map +1 -1
  107. package/dist/core/session-manager.d.ts +202 -36
  108. package/dist/core/session-manager.d.ts.map +1 -1
  109. package/dist/core/session-manager.js +565 -133
  110. package/dist/core/session-manager.js.map +1 -1
  111. package/dist/core/settings-manager.d.ts +9 -3
  112. package/dist/core/settings-manager.d.ts.map +1 -1
  113. package/dist/core/settings-manager.js +13 -12
  114. package/dist/core/settings-manager.js.map +1 -1
  115. package/dist/core/system-prompt.d.ts.map +1 -1
  116. package/dist/core/system-prompt.js +6 -3
  117. package/dist/core/system-prompt.js.map +1 -1
  118. package/dist/core/tools/bash.d.ts +1 -1
  119. package/dist/core/tools/bash.d.ts.map +1 -1
  120. package/dist/core/tools/bash.js.map +1 -1
  121. package/dist/core/tools/edit-diff.d.ts +33 -0
  122. package/dist/core/tools/edit-diff.d.ts.map +1 -0
  123. package/dist/core/tools/edit-diff.js +171 -0
  124. package/dist/core/tools/edit-diff.js.map +1 -0
  125. package/dist/core/tools/edit.d.ts +7 -1
  126. package/dist/core/tools/edit.d.ts.map +1 -1
  127. package/dist/core/tools/edit.js +20 -95
  128. package/dist/core/tools/edit.js.map +1 -1
  129. package/dist/core/tools/find.d.ts +1 -1
  130. package/dist/core/tools/find.d.ts.map +1 -1
  131. package/dist/core/tools/find.js.map +1 -1
  132. package/dist/core/tools/grep.d.ts +1 -1
  133. package/dist/core/tools/grep.d.ts.map +1 -1
  134. package/dist/core/tools/grep.js.map +1 -1
  135. package/dist/core/tools/index.d.ts +1 -1
  136. package/dist/core/tools/index.d.ts.map +1 -1
  137. package/dist/core/tools/index.js.map +1 -1
  138. package/dist/core/tools/ls.d.ts +1 -1
  139. package/dist/core/tools/ls.d.ts.map +1 -1
  140. package/dist/core/tools/ls.js.map +1 -1
  141. package/dist/core/tools/read.d.ts +1 -1
  142. package/dist/core/tools/read.d.ts.map +1 -1
  143. package/dist/core/tools/read.js.map +1 -1
  144. package/dist/core/tools/write.d.ts +1 -1
  145. package/dist/core/tools/write.d.ts.map +1 -1
  146. package/dist/core/tools/write.js.map +1 -1
  147. package/dist/index.d.ts +8 -7
  148. package/dist/index.d.ts.map +1 -1
  149. package/dist/index.js +5 -5
  150. package/dist/index.js.map +1 -1
  151. package/dist/main.d.ts.map +1 -1
  152. package/dist/main.js +22 -21
  153. package/dist/main.js.map +1 -1
  154. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  155. package/dist/modes/interactive/components/assistant-message.js +3 -4
  156. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  157. package/dist/modes/interactive/components/bash-execution.d.ts +1 -1
  158. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  159. package/dist/modes/interactive/components/bash-execution.js +6 -2
  160. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  161. package/dist/modes/interactive/components/bordered-loader.d.ts +12 -0
  162. package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -0
  163. package/dist/modes/interactive/components/bordered-loader.js +30 -0
  164. package/dist/modes/interactive/components/bordered-loader.js.map +1 -0
  165. package/dist/modes/interactive/components/branch-summary-message.d.ts +14 -0
  166. package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -0
  167. package/dist/modes/interactive/components/branch-summary-message.js +35 -0
  168. package/dist/modes/interactive/components/branch-summary-message.js.map +1 -0
  169. package/dist/modes/interactive/components/compaction-summary-message.d.ts +14 -0
  170. package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -0
  171. package/dist/modes/interactive/components/compaction-summary-message.js +36 -0
  172. package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -0
  173. package/dist/modes/interactive/components/dynamic-border.d.ts +5 -1
  174. package/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
  175. package/dist/modes/interactive/components/dynamic-border.js +5 -1
  176. package/dist/modes/interactive/components/dynamic-border.js.map +1 -1
  177. package/dist/modes/interactive/components/footer.d.ts +12 -6
  178. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  179. package/dist/modes/interactive/components/footer.js +57 -25
  180. package/dist/modes/interactive/components/footer.js.map +1 -1
  181. package/dist/modes/interactive/components/hook-editor.d.ts +15 -0
  182. package/dist/modes/interactive/components/hook-editor.d.ts.map +1 -0
  183. package/dist/modes/interactive/components/hook-editor.js +95 -0
  184. package/dist/modes/interactive/components/hook-editor.js.map +1 -0
  185. package/dist/modes/interactive/components/hook-message.d.ts +18 -0
  186. package/dist/modes/interactive/components/hook-message.d.ts.map +1 -0
  187. package/dist/modes/interactive/components/hook-message.js +80 -0
  188. package/dist/modes/interactive/components/hook-message.js.map +1 -0
  189. package/dist/modes/interactive/components/model-selector.d.ts +3 -3
  190. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  191. package/dist/modes/interactive/components/model-selector.js +1 -1
  192. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  193. package/dist/modes/interactive/components/tool-execution.d.ts +15 -2
  194. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  195. package/dist/modes/interactive/components/tool-execution.js +70 -21
  196. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  197. package/dist/modes/interactive/components/tree-selector.d.ts +52 -0
  198. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -0
  199. package/dist/modes/interactive/components/tree-selector.js +745 -0
  200. package/dist/modes/interactive/components/tree-selector.js.map +1 -0
  201. package/dist/modes/interactive/components/user-message-selector.d.ts +3 -3
  202. package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -1
  203. package/dist/modes/interactive/components/user-message-selector.js +1 -1
  204. package/dist/modes/interactive/components/user-message-selector.js.map +1 -1
  205. package/dist/modes/interactive/components/user-message.d.ts +1 -1
  206. package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  207. package/dist/modes/interactive/components/user-message.js +2 -5
  208. package/dist/modes/interactive/components/user-message.js.map +1 -1
  209. package/dist/modes/interactive/interactive-mode.d.ts +29 -12
  210. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  211. package/dist/modes/interactive/interactive-mode.js +589 -208
  212. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  213. package/dist/modes/interactive/theme/dark.json +13 -1
  214. package/dist/modes/interactive/theme/light.json +13 -1
  215. package/dist/modes/interactive/theme/theme-schema.json +34 -0
  216. package/dist/modes/interactive/theme/theme.d.ts +20 -2
  217. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  218. package/dist/modes/interactive/theme/theme.js +135 -2
  219. package/dist/modes/interactive/theme/theme.js.map +1 -1
  220. package/dist/modes/print-mode.d.ts +3 -3
  221. package/dist/modes/print-mode.d.ts.map +1 -1
  222. package/dist/modes/print-mode.js +26 -20
  223. package/dist/modes/print-mode.js.map +1 -1
  224. package/dist/modes/rpc/rpc-client.d.ts +13 -10
  225. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  226. package/dist/modes/rpc/rpc-client.js +11 -10
  227. package/dist/modes/rpc/rpc-client.js.map +1 -1
  228. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  229. package/dist/modes/rpc/rpc-mode.js +88 -35
  230. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  231. package/dist/modes/rpc/rpc-types.d.ts +30 -11
  232. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  233. package/dist/modes/rpc/rpc-types.js.map +1 -1
  234. package/dist/utils/shell.d.ts +4 -2
  235. package/dist/utils/shell.d.ts.map +1 -1
  236. package/dist/utils/shell.js +36 -7
  237. package/dist/utils/shell.js.map +1 -1
  238. package/dist/utils/tools-manager.d.ts +1 -1
  239. package/dist/utils/tools-manager.d.ts.map +1 -1
  240. package/dist/utils/tools-manager.js +2 -2
  241. package/dist/utils/tools-manager.js.map +1 -1
  242. package/docs/compaction.md +388 -0
  243. package/docs/custom-tools.md +146 -43
  244. package/docs/extension-loading.md +1004 -0
  245. package/docs/hooks.md +562 -596
  246. package/docs/rpc.md +33 -19
  247. package/docs/sdk.md +93 -21
  248. package/docs/session-tree-plan.md +441 -0
  249. package/docs/session.md +172 -21
  250. package/docs/skills.md +2 -0
  251. package/docs/theme.md +31 -2
  252. package/docs/tree.md +197 -0
  253. package/docs/tui.md +343 -0
  254. package/examples/README.md +1 -9
  255. package/examples/custom-tools/hello/index.ts +4 -3
  256. package/examples/custom-tools/question/index.ts +4 -4
  257. package/examples/custom-tools/subagent/index.ts +7 -6
  258. package/examples/custom-tools/todo/index.ts +11 -5
  259. package/examples/hooks/README.md +29 -71
  260. package/examples/hooks/auto-commit-on-exit.ts +8 -9
  261. package/examples/hooks/confirm-destructive.ts +29 -30
  262. package/examples/hooks/custom-compaction.ts +20 -21
  263. package/examples/hooks/dirty-repo-guard.ts +41 -40
  264. package/examples/hooks/file-trigger.ts +10 -5
  265. package/examples/hooks/git-checkpoint.ts +16 -12
  266. package/examples/hooks/handoff.ts +150 -0
  267. package/examples/hooks/permission-gate.ts +1 -1
  268. package/examples/hooks/protected-paths.ts +1 -1
  269. package/examples/hooks/qna.ts +119 -0
  270. package/examples/hooks/snake.ts +343 -0
  271. package/examples/hooks/status-line.ts +40 -0
  272. package/examples/sdk/01-minimal.ts +1 -1
  273. package/examples/sdk/02-custom-model.ts +1 -1
  274. package/examples/sdk/03-custom-prompt.ts +1 -1
  275. package/examples/sdk/04-skills.ts +1 -1
  276. package/examples/sdk/05-tools.ts +4 -4
  277. package/examples/sdk/06-hooks.ts +1 -1
  278. package/examples/sdk/07-context-files.ts +1 -1
  279. package/examples/sdk/08-slash-commands.ts +6 -1
  280. package/examples/sdk/09-api-keys-and-oauth.ts +1 -1
  281. package/examples/sdk/10-settings.ts +1 -1
  282. package/examples/sdk/11-sessions.ts +1 -1
  283. package/examples/sdk/12-full-control.ts +4 -7
  284. package/package.json +6 -6
  285. package/dist/core/compaction.d.ts.map +0 -1
  286. package/dist/core/compaction.js +0 -412
  287. package/dist/core/compaction.js.map +0 -1
  288. package/dist/core/export-html.d.ts +0 -23
  289. package/dist/core/export-html.d.ts.map +0 -1
  290. package/dist/core/export-html.js +0 -1185
  291. package/dist/core/export-html.js.map +0 -1
  292. package/dist/modes/interactive/components/compaction.d.ts +0 -15
  293. package/dist/modes/interactive/components/compaction.d.ts.map +0 -1
  294. package/dist/modes/interactive/components/compaction.js +0 -41
  295. package/dist/modes/interactive/components/compaction.js.map +0 -1
  296. package/docs/hooks-v2.md +0 -385
  297. package/docs/session-tree.md +0 -452
package/docs/session.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Session File Format
2
2
 
3
- Sessions are stored as JSONL (JSON Lines) files. Each line is a JSON object with a `type` field.
3
+ Sessions are stored as JSONL (JSON Lines) files. Each line is a JSON object with a `type` field. Session entries form a tree structure via `id`/`parentId` fields, enabling in-place branching without creating new files.
4
4
 
5
5
  ## File Location
6
6
 
@@ -10,47 +10,66 @@ Sessions are stored as JSONL (JSON Lines) files. Each line is a JSON object with
10
10
 
11
11
  Where `<path>` is the working directory with `/` replaced by `-`.
12
12
 
13
+ ## Session Version
14
+
15
+ Sessions have a version field in the header:
16
+
17
+ - **Version 1**: Linear entry sequence (legacy, auto-migrated on load)
18
+ - **Version 2**: Tree structure with `id`/`parentId` linking
19
+
20
+ Existing v1 sessions are automatically migrated to v2 when loaded.
21
+
13
22
  ## Type Definitions
14
23
 
15
- - [`src/session-manager.ts`](../src/session-manager.ts) - Session entry types (`SessionHeader`, `SessionMessageEntry`, etc.)
16
- - [`packages/agent/src/types.ts`](../../agent/src/types.ts) - `AppMessage`, `Attachment`, `ThinkingLevel`
24
+ - [`src/core/session-manager.ts`](../src/core/session-manager.ts) - Session entry types
25
+ - [`packages/agent/src/types.ts`](../../agent/src/types.ts) - `AgentMessage`, `Attachment`, `ThinkingLevel`
17
26
  - [`packages/ai/src/types.ts`](../../ai/src/types.ts) - `UserMessage`, `AssistantMessage`, `ToolResultMessage`, `Usage`, `ToolCall`
18
27
 
28
+ ## Entry Base
29
+
30
+ All entries (except `SessionHeader`) extend `SessionEntryBase`:
31
+
32
+ ```typescript
33
+ interface SessionEntryBase {
34
+ type: string;
35
+ id: string; // 8-char hex ID
36
+ parentId: string | null; // Parent entry ID (null for first entry)
37
+ timestamp: string; // ISO timestamp
38
+ }
39
+ ```
40
+
19
41
  ## Entry Types
20
42
 
21
43
  ### SessionHeader
22
44
 
23
- First line of the file. Defines session metadata.
45
+ First line of the file. Metadata only, not part of the tree (no `id`/`parentId`).
24
46
 
25
47
  ```json
26
- {"type":"session","id":"uuid","timestamp":"2024-12-03T14:00:00.000Z","cwd":"/path/to/project","provider":"anthropic","modelId":"claude-sonnet-4-5","thinkingLevel":"off"}
48
+ {"type":"session","version":2,"id":"uuid","timestamp":"2024-12-03T14:00:00.000Z","cwd":"/path/to/project"}
27
49
  ```
28
50
 
29
- For branched sessions, includes the source session path:
51
+ For sessions with a parent (created via `/branch` or `newSession({ parentSession })`):
30
52
 
31
53
  ```json
32
- {"type":"session","id":"uuid","timestamp":"2024-12-03T14:00:00.000Z","cwd":"/path/to/project","provider":"anthropic","modelId":"claude-sonnet-4-5","thinkingLevel":"off","branchedFrom":"/path/to/original/session.jsonl"}
54
+ {"type":"session","version":2,"id":"uuid","timestamp":"2024-12-03T14:00:00.000Z","cwd":"/path/to/project","parentSession":"/path/to/original/session.jsonl"}
33
55
  ```
34
56
 
35
57
  ### SessionMessageEntry
36
58
 
37
- A message in the conversation. The `message` field contains an `AppMessage` (see [rpc.md](./rpc.md#message-types)).
59
+ A message in the conversation. The `message` field contains an `AgentMessage`.
38
60
 
39
61
  ```json
40
- {"type":"message","timestamp":"2024-12-03T14:00:01.000Z","message":{"role":"user","content":"Hello","timestamp":1733234567890}}
41
- {"type":"message","timestamp":"2024-12-03T14:00:02.000Z","message":{"role":"assistant","content":[{"type":"text","text":"Hi!"}],"api":"anthropic-messages","provider":"anthropic","model":"claude-sonnet-4-5","usage":{...},"stopReason":"stop","timestamp":1733234567891}}
42
- {"type":"message","timestamp":"2024-12-03T14:00:03.000Z","message":{"role":"toolResult","toolCallId":"call_123","toolName":"bash","content":[{"type":"text","text":"output"}],"isError":false,"timestamp":1733234567900}}
43
- {"type":"message","timestamp":"2024-12-03T14:00:04.000Z","message":{"role":"bashExecution","command":"ls -la","output":"total 48\n...","exitCode":0,"cancelled":false,"truncated":false,"timestamp":1733234567950}}
62
+ {"type":"message","id":"a1b2c3d4","parentId":"prev1234","timestamp":"2024-12-03T14:00:01.000Z","message":{"role":"user","content":"Hello"}}
63
+ {"type":"message","id":"b2c3d4e5","parentId":"a1b2c3d4","timestamp":"2024-12-03T14:00:02.000Z","message":{"role":"assistant","content":[{"type":"text","text":"Hi!"}],"provider":"anthropic","model":"claude-sonnet-4-5","usage":{...},"stopReason":"stop"}}
64
+ {"type":"message","id":"c3d4e5f6","parentId":"b2c3d4e5","timestamp":"2024-12-03T14:00:03.000Z","message":{"role":"toolResult","toolCallId":"call_123","toolName":"bash","content":[{"type":"text","text":"output"}],"isError":false}}
44
65
  ```
45
66
 
46
- The `bashExecution` role is a custom message type for user-executed bash commands (via `!` in TUI or `bash` RPC command). See [rpc.md](./rpc.md#bashexecutionmessage) for the full schema.
47
-
48
67
  ### ModelChangeEntry
49
68
 
50
69
  Emitted when the user switches models mid-session.
51
70
 
52
71
  ```json
53
- {"type":"model_change","timestamp":"2024-12-03T14:05:00.000Z","provider":"openai","modelId":"gpt-4o"}
72
+ {"type":"model_change","id":"d4e5f6g7","parentId":"c3d4e5f6","timestamp":"2024-12-03T14:05:00.000Z","provider":"openai","modelId":"gpt-4o"}
54
73
  ```
55
74
 
56
75
  ### ThinkingLevelChangeEntry
@@ -58,9 +77,92 @@ Emitted when the user switches models mid-session.
58
77
  Emitted when the user changes the thinking/reasoning level.
59
78
 
60
79
  ```json
61
- {"type":"thinking_level_change","timestamp":"2024-12-03T14:06:00.000Z","thinkingLevel":"high"}
80
+ {"type":"thinking_level_change","id":"e5f6g7h8","parentId":"d4e5f6g7","timestamp":"2024-12-03T14:06:00.000Z","thinkingLevel":"high"}
81
+ ```
82
+
83
+ ### CompactionEntry
84
+
85
+ Created when context is compacted. Stores a summary of earlier messages.
86
+
87
+ ```json
88
+ {"type":"compaction","id":"f6g7h8i9","parentId":"e5f6g7h8","timestamp":"2024-12-03T14:10:00.000Z","summary":"User discussed X, Y, Z...","firstKeptEntryId":"c3d4e5f6","tokensBefore":50000}
89
+ ```
90
+
91
+ Optional fields:
92
+ - `details`: Compaction-implementation specific data (e.g., file operations for default implementation, or custom data for custom hook implementations)
93
+ - `fromHook`: `true` if generated by a hook, `false`/`undefined` if pi-generated
94
+
95
+ ### BranchSummaryEntry
96
+
97
+ Created when switching branches via `/tree` with an LLM generated summary of the left branch up to the common ancestor. Captures context from the abandoned path.
98
+
99
+ ```json
100
+ {"type":"branch_summary","id":"g7h8i9j0","parentId":"a1b2c3d4","timestamp":"2024-12-03T14:15:00.000Z","fromId":"f6g7h8i9","summary":"Branch explored approach A..."}
101
+ ```
102
+
103
+ Optional fields:
104
+ - `details`: File tracking data (`{ readFiles: string[], modifiedFiles: string[] }`) for default implementation, arbitrary for custom implementation
105
+ - `fromHook`: `true` if generated by a hook
106
+
107
+ ### CustomEntry
108
+
109
+ Hook state persistence. Does NOT participate in LLM context.
110
+
111
+ ```json
112
+ {"type":"custom","id":"h8i9j0k1","parentId":"g7h8i9j0","timestamp":"2024-12-03T14:20:00.000Z","customType":"my-hook","data":{"count":42}}
62
113
  ```
63
114
 
115
+ Use `customType` to identify your hook's entries on reload.
116
+
117
+ ### CustomMessageEntry
118
+
119
+ Hook-injected messages that DO participate in LLM context.
120
+
121
+ ```json
122
+ {"type":"custom_message","id":"i9j0k1l2","parentId":"h8i9j0k1","timestamp":"2024-12-03T14:25:00.000Z","customType":"my-hook","content":"Injected context...","display":true}
123
+ ```
124
+
125
+ Fields:
126
+ - `content`: String or `(TextContent | ImageContent)[]` (same as UserMessage)
127
+ - `display`: `true` = show in TUI with purple styling, `false` = hidden
128
+ - `details`: Optional hook-specific metadata (not sent to LLM)
129
+
130
+ ### LabelEntry
131
+
132
+ User-defined bookmark/marker on an entry.
133
+
134
+ ```json
135
+ {"type":"label","id":"j0k1l2m3","parentId":"i9j0k1l2","timestamp":"2024-12-03T14:30:00.000Z","targetId":"a1b2c3d4","label":"checkpoint-1"}
136
+ ```
137
+
138
+ Set `label` to `undefined` to clear a label.
139
+
140
+ ## Tree Structure
141
+
142
+ Entries form a tree:
143
+ - First entry has `parentId: null`
144
+ - Each subsequent entry points to its parent via `parentId`
145
+ - Branching creates new children from an earlier entry
146
+ - The "leaf" is the current position in the tree
147
+
148
+ ```
149
+ [user msg] ─── [assistant] ─── [user msg] ─── [assistant] ─┬─ [user msg] ← current leaf
150
+
151
+ └─ [branch_summary] ─── [user msg] ← alternate branch
152
+ ```
153
+
154
+ ## Context Building
155
+
156
+ `buildSessionContext()` walks from the current leaf to the root, producing the message list for the LLM:
157
+
158
+ 1. Collects all entries on the path
159
+ 2. Extracts current model and thinking level settings
160
+ 3. If a `CompactionEntry` is on the path:
161
+ - Emits the summary first
162
+ - Then messages from `firstKeptEntryId` to compaction
163
+ - Then messages after compaction
164
+ 4. Converts `BranchSummaryEntry` and `CustomMessageEntry` to appropriate message formats
165
+
64
166
  ## Parsing Example
65
167
 
66
168
  ```typescript
@@ -70,20 +172,69 @@ const lines = readFileSync("session.jsonl", "utf8").trim().split("\n");
70
172
 
71
173
  for (const line of lines) {
72
174
  const entry = JSON.parse(line);
73
-
175
+
74
176
  switch (entry.type) {
75
177
  case "session":
76
- console.log(`Session: ${entry.id}, Model: ${entry.provider}/${entry.modelId}`);
178
+ console.log(`Session v${entry.version ?? 1}: ${entry.id}`);
77
179
  break;
78
180
  case "message":
79
- console.log(`${entry.message.role}: ${JSON.stringify(entry.message.content)}`);
181
+ console.log(`[${entry.id}] ${entry.message.role}: ${JSON.stringify(entry.message.content)}`);
182
+ break;
183
+ case "compaction":
184
+ console.log(`[${entry.id}] Compaction: ${entry.tokensBefore} tokens summarized`);
185
+ break;
186
+ case "branch_summary":
187
+ console.log(`[${entry.id}] Branch from ${entry.fromId}`);
188
+ break;
189
+ case "custom":
190
+ console.log(`[${entry.id}] Custom (${entry.customType}): ${JSON.stringify(entry.data)}`);
191
+ break;
192
+ case "custom_message":
193
+ console.log(`[${entry.id}] Hook message (${entry.customType}): ${entry.content}`);
194
+ break;
195
+ case "label":
196
+ console.log(`[${entry.id}] Label "${entry.label}" on ${entry.targetId}`);
80
197
  break;
81
198
  case "model_change":
82
- console.log(`Switched to: ${entry.provider}/${entry.modelId}`);
199
+ console.log(`[${entry.id}] Model: ${entry.provider}/${entry.modelId}`);
83
200
  break;
84
201
  case "thinking_level_change":
85
- console.log(`Thinking: ${entry.thinkingLevel}`);
202
+ console.log(`[${entry.id}] Thinking: ${entry.thinkingLevel}`);
86
203
  break;
87
204
  }
88
205
  }
89
206
  ```
207
+
208
+ ## SessionManager API
209
+
210
+ Key methods for working with sessions programmatically:
211
+
212
+ ### Creation
213
+ - `SessionManager.create(cwd, sessionDir?)` - New session
214
+ - `SessionManager.open(path, sessionDir?)` - Open existing
215
+ - `SessionManager.continueRecent(cwd, sessionDir?)` - Continue most recent or create new
216
+ - `SessionManager.inMemory(cwd?)` - No file persistence
217
+
218
+ ### Appending (all return entry ID)
219
+ - `appendMessage(message)` - Add message
220
+ - `appendThinkingLevelChange(level)` - Record thinking change
221
+ - `appendModelChange(provider, modelId)` - Record model change
222
+ - `appendCompaction(summary, firstKeptEntryId, tokensBefore, details?, fromHook?)` - Add compaction
223
+ - `appendCustomEntry(customType, data?)` - Hook state (not in context)
224
+ - `appendCustomMessageEntry(customType, content, display, details?)` - Hook message (in context)
225
+ - `appendLabelChange(targetId, label)` - Set/clear label
226
+
227
+ ### Tree Navigation
228
+ - `getLeafId()` - Current position
229
+ - `getEntry(id)` - Get entry by ID
230
+ - `getPath(fromId?)` - Walk from entry to root
231
+ - `getTree()` - Get full tree structure
232
+ - `getChildren(parentId)` - Get direct children
233
+ - `getLabel(id)` - Get label for entry
234
+ - `branch(entryId)` - Move leaf to earlier entry
235
+ - `branchWithSummary(entryId, summary, details?, fromHook?)` - Branch with context summary
236
+
237
+ ### Context
238
+ - `buildSessionContext()` - Get messages for LLM
239
+ - `getEntries()` - All entries (excluding header)
240
+ - `getHeader()` - Session metadata
package/docs/skills.md CHANGED
@@ -1,3 +1,5 @@
1
+ > pi can create skills. Ask it to build one for your use case.
2
+
1
3
  # Skills
2
4
 
3
5
  Skills are self-contained capability packages that the agent loads on-demand. A skill provides specialized workflows, setup instructions, helper scripts, and reference documentation for specific tasks.
package/docs/theme.md CHANGED
@@ -1,3 +1,5 @@
1
+ > pi can create themes. Ask it to build one for your use case.
2
+
1
3
  # Pi Coding Agent Themes
2
4
 
3
5
  Themes allow you to customize the colors used throughout the coding agent TUI.
@@ -20,13 +22,18 @@ Every theme must define all color tokens. There are no optional colors.
20
22
  | `muted` | Secondary/dimmed text | Metadata, descriptions, output |
21
23
  | `dim` | Very dimmed text | Less important info, placeholders |
22
24
  | `text` | Default text color | Main content (usually `""`) |
25
+ | `thinkingText` | Thinking block text | Assistant reasoning traces |
23
26
 
24
- ### Backgrounds & Content Text (7 colors)
27
+ ### Backgrounds & Content Text (11 colors)
25
28
 
26
29
  | Token | Purpose |
27
30
  |-------|---------|
31
+ | `selectedBg` | Selected/active line background (e.g., tree selector) |
28
32
  | `userMessageBg` | User message background |
29
33
  | `userMessageText` | User message text color |
34
+ | `customMessageBg` | Hook custom message background |
35
+ | `customMessageText` | Hook custom message text color |
36
+ | `customMessageLabel` | Hook custom message label/type text |
30
37
  | `toolPendingBg` | Tool execution box (pending state) |
31
38
  | `toolSuccessBg` | Tool execution box (success state) |
32
39
  | `toolErrorBg` | Tool execution box (error state) |
@@ -95,7 +102,28 @@ These create a visual hierarchy: off → minimal → low → medium → high →
95
102
  |-------|---------|
96
103
  | `bashMode` | Editor border color when in bash mode (! prefix) |
97
104
 
98
- **Total: 46 color tokens** (all required)
105
+ **Total: 50 color tokens** (all required)
106
+
107
+ ### HTML Export Colors (optional)
108
+
109
+ The `export` section is optional and controls colors used when exporting sessions to HTML via `/export`. If not specified, these colors are automatically derived from `userMessageBg` based on luminance detection.
110
+
111
+ | Token | Purpose |
112
+ |-------|---------|
113
+ | `pageBg` | Page background color |
114
+ | `cardBg` | Card/container background (headers, stats boxes) |
115
+ | `infoBg` | Info sections background (system prompt, notices, compaction) |
116
+
117
+ Example:
118
+ ```json
119
+ {
120
+ "export": {
121
+ "pageBg": "#18181e",
122
+ "cardBg": "#1e1e24",
123
+ "infoBg": "#3c3728"
124
+ }
125
+ }
126
+ ```
99
127
 
100
128
  ## Theme Format
101
129
 
@@ -113,6 +141,7 @@ Themes are defined in JSON files with the following structure:
113
141
  "colors": {
114
142
  "accent": "blue",
115
143
  "muted": "gray",
144
+ "thinkingText": "gray",
116
145
  "text": "",
117
146
  ...
118
147
  }
package/docs/tree.md ADDED
@@ -0,0 +1,197 @@
1
+ # Session Tree Navigation
2
+
3
+ The `/tree` command provides tree-based navigation of the session history.
4
+
5
+ ## Overview
6
+
7
+ Sessions are stored as trees where each entry has an `id` and `parentId`. The "leaf" pointer tracks the current position. `/tree` lets you navigate to any point and optionally summarize the branch you're leaving.
8
+
9
+ ### Comparison with `/branch`
10
+
11
+ | Feature | `/branch` | `/tree` |
12
+ |---------|-----------|---------|
13
+ | View | Flat list of user messages | Full tree structure |
14
+ | Action | Extracts path to **new session file** | Changes leaf in **same session** |
15
+ | Summary | Never | Optional (user prompted) |
16
+ | Events | `session_before_branch` / `session_branch` | `session_before_tree` / `session_tree` |
17
+
18
+ ## Tree UI
19
+
20
+ ```
21
+ ├─ user: "Hello, can you help..."
22
+ │ └─ assistant: "Of course! I can..."
23
+ │ ├─ user: "Let's try approach A..."
24
+ │ │ └─ assistant: "For approach A..."
25
+ │ │ └─ [compaction: 12k tokens]
26
+ │ │ └─ user: "That worked..." ← active
27
+ │ └─ user: "Actually, approach B..."
28
+ │ └─ assistant: "For approach B..."
29
+ ```
30
+
31
+ ### Controls
32
+
33
+ | Key | Action |
34
+ |-----|--------|
35
+ | ↑/↓ | Navigate (depth-first order) |
36
+ | Enter | Select node |
37
+ | Escape/Ctrl+C | Cancel |
38
+ | Ctrl+U | Toggle: user messages only |
39
+ | Ctrl+O | Toggle: show all (including custom/label entries) |
40
+
41
+ ### Display
42
+
43
+ - Height: half terminal height
44
+ - Current leaf marked with `← active`
45
+ - Labels shown inline: `[label-name]`
46
+ - Default filter hides `label` and `custom` entries (shown in Ctrl+O mode)
47
+ - Children sorted by timestamp (oldest first)
48
+
49
+ ## Selection Behavior
50
+
51
+ ### User Message or Custom Message
52
+ 1. Leaf set to **parent** of selected node (or `null` if root)
53
+ 2. Message text placed in **editor** for re-submission
54
+ 3. User edits and submits, creating a new branch
55
+
56
+ ### Non-User Message (assistant, compaction, etc.)
57
+ 1. Leaf set to **selected node**
58
+ 2. Editor stays empty
59
+ 3. User continues from that point
60
+
61
+ ### Selecting Root User Message
62
+ If user selects the very first message (has no parent):
63
+ 1. Leaf reset to `null` (empty conversation)
64
+ 2. Message text placed in editor
65
+ 3. User effectively restarts from scratch
66
+
67
+ ## Branch Summarization
68
+
69
+ When switching, user is prompted: "Summarize the branch you're leaving?"
70
+
71
+ ### What Gets Summarized
72
+
73
+ Path from old leaf back to common ancestor with target:
74
+
75
+ ```
76
+ A → B → C → D → E → F ← old leaf
77
+ ↘ G → H ← target
78
+ ```
79
+
80
+ Abandoned path: D → E → F (summarized)
81
+
82
+ Summarization stops at:
83
+ 1. Common ancestor (always)
84
+ 2. Compaction node (if encountered first)
85
+
86
+ ### Summary Storage
87
+
88
+ Stored as `BranchSummaryEntry`:
89
+
90
+ ```typescript
91
+ interface BranchSummaryEntry {
92
+ type: "branch_summary";
93
+ id: string;
94
+ parentId: string; // New leaf position
95
+ timestamp: string;
96
+ fromId: string; // Old leaf we abandoned
97
+ summary: string; // LLM-generated summary
98
+ details?: unknown; // Optional hook data
99
+ }
100
+ ```
101
+
102
+ ## Implementation
103
+
104
+ ### AgentSession.navigateTree()
105
+
106
+ ```typescript
107
+ async navigateTree(
108
+ targetId: string,
109
+ options?: { summarize?: boolean; customInstructions?: string }
110
+ ): Promise<{ editorText?: string; cancelled: boolean }>
111
+ ```
112
+
113
+ Flow:
114
+ 1. Validate target, check no-op (target === current leaf)
115
+ 2. Find common ancestor between old leaf and target
116
+ 3. Collect entries to summarize (if requested)
117
+ 4. Fire `session_before_tree` event (hook can cancel or provide summary)
118
+ 5. Run default summarizer if needed
119
+ 6. Switch leaf via `branch()` or `branchWithSummary()`
120
+ 7. Update agent: `agent.replaceMessages(sessionManager.buildSessionContext().messages)`
121
+ 8. Fire `session_tree` event
122
+ 9. Notify custom tools via session event
123
+ 10. Return result with `editorText` if user message was selected
124
+
125
+ ### SessionManager
126
+
127
+ - `getLeafUuid(): string | null` - Current leaf (null if empty)
128
+ - `resetLeaf(): void` - Set leaf to null (for root user message navigation)
129
+ - `getTree(): SessionTreeNode[]` - Full tree with children sorted by timestamp
130
+ - `branch(id)` - Change leaf pointer
131
+ - `branchWithSummary(id, summary)` - Change leaf and create summary entry
132
+
133
+ ### InteractiveMode
134
+
135
+ `/tree` command shows `TreeSelectorComponent`, then:
136
+ 1. Prompt for summarization
137
+ 2. Call `session.navigateTree()`
138
+ 3. Clear and re-render chat
139
+ 4. Set editor text if applicable
140
+
141
+ ## Hook Events
142
+
143
+ ### `session_before_tree`
144
+
145
+ ```typescript
146
+ interface TreePreparation {
147
+ targetId: string;
148
+ oldLeafId: string | null;
149
+ commonAncestorId: string | null;
150
+ entriesToSummarize: SessionEntry[];
151
+ userWantsSummary: boolean;
152
+ }
153
+
154
+ interface SessionBeforeTreeEvent {
155
+ type: "session_before_tree";
156
+ preparation: TreePreparation;
157
+ model: Model;
158
+ signal: AbortSignal;
159
+ }
160
+
161
+ interface SessionBeforeTreeResult {
162
+ cancel?: boolean;
163
+ summary?: { summary: string; details?: unknown };
164
+ }
165
+ ```
166
+
167
+ ### `session_tree`
168
+
169
+ ```typescript
170
+ interface SessionTreeEvent {
171
+ type: "session_tree";
172
+ newLeafId: string | null;
173
+ oldLeafId: string | null;
174
+ summaryEntry?: BranchSummaryEntry;
175
+ fromHook?: boolean;
176
+ }
177
+ ```
178
+
179
+ ### Example: Custom Summarizer
180
+
181
+ ```typescript
182
+ export default function(pi: HookAPI) {
183
+ pi.on("session_before_tree", async (event, ctx) => {
184
+ if (!event.preparation.userWantsSummary) return;
185
+ if (event.preparation.entriesToSummarize.length === 0) return;
186
+
187
+ const summary = await myCustomSummarizer(event.preparation.entriesToSummarize);
188
+ return { summary: { summary, details: { custom: true } } };
189
+ });
190
+ }
191
+ ```
192
+
193
+ ## Error Handling
194
+
195
+ - Summarization failure: cancels navigation, shows error
196
+ - User abort (Escape): cancels navigation
197
+ - Hook returns `cancel: true`: cancels navigation silently