@mariozechner/pi-coding-agent 0.60.0 → 0.61.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 (181) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/README.md +1 -1
  3. package/dist/bun/cli.d.ts.map +1 -1
  4. package/dist/bun/cli.js +1 -0
  5. package/dist/bun/cli.js.map +1 -1
  6. package/dist/bun/register-bedrock.d.ts.map +1 -1
  7. package/dist/bun/register-bedrock.js +3 -84
  8. package/dist/bun/register-bedrock.js.map +1 -1
  9. package/dist/cli/session-picker.d.ts.map +1 -1
  10. package/dist/cli/session-picker.js +2 -1
  11. package/dist/cli/session-picker.js.map +1 -1
  12. package/dist/cli.d.ts.map +1 -1
  13. package/dist/cli.js +1 -0
  14. package/dist/cli.js.map +1 -1
  15. package/dist/core/agent-session.d.ts +17 -2
  16. package/dist/core/agent-session.d.ts.map +1 -1
  17. package/dist/core/agent-session.js +61 -6
  18. package/dist/core/agent-session.js.map +1 -1
  19. package/dist/core/exec.d.ts.map +1 -1
  20. package/dist/core/exec.js +7 -3
  21. package/dist/core/exec.js.map +1 -1
  22. package/dist/core/export-html/template.css +43 -13
  23. package/dist/core/export-html/template.html +1 -0
  24. package/dist/core/export-html/template.js +107 -0
  25. package/dist/core/extensions/index.d.ts +1 -1
  26. package/dist/core/extensions/index.d.ts.map +1 -1
  27. package/dist/core/extensions/index.js.map +1 -1
  28. package/dist/core/extensions/loader.d.ts.map +1 -1
  29. package/dist/core/extensions/loader.js +4 -4
  30. package/dist/core/extensions/loader.js.map +1 -1
  31. package/dist/core/extensions/runner.d.ts +1 -1
  32. package/dist/core/extensions/runner.d.ts.map +1 -1
  33. package/dist/core/extensions/runner.js +45 -33
  34. package/dist/core/extensions/runner.js.map +1 -1
  35. package/dist/core/extensions/types.d.ts +4 -3
  36. package/dist/core/extensions/types.d.ts.map +1 -1
  37. package/dist/core/extensions/types.js.map +1 -1
  38. package/dist/core/footer-data-provider.d.ts +9 -2
  39. package/dist/core/footer-data-provider.d.ts.map +1 -1
  40. package/dist/core/footer-data-provider.js +85 -13
  41. package/dist/core/footer-data-provider.js.map +1 -1
  42. package/dist/core/keybindings.d.ts +268 -51
  43. package/dist/core/keybindings.d.ts.map +1 -1
  44. package/dist/core/keybindings.js +221 -143
  45. package/dist/core/keybindings.js.map +1 -1
  46. package/dist/core/model-registry.d.ts +1 -0
  47. package/dist/core/model-registry.d.ts.map +1 -1
  48. package/dist/core/model-registry.js +23 -14
  49. package/dist/core/model-registry.js.map +1 -1
  50. package/dist/core/sdk.d.ts +2 -2
  51. package/dist/core/sdk.d.ts.map +1 -1
  52. package/dist/core/sdk.js +2 -2
  53. package/dist/core/sdk.js.map +1 -1
  54. package/dist/core/slash-commands.d.ts.map +1 -1
  55. package/dist/core/slash-commands.js +2 -1
  56. package/dist/core/slash-commands.js.map +1 -1
  57. package/dist/core/tools/bash.d.ts.map +1 -1
  58. package/dist/core/tools/bash.js +12 -10
  59. package/dist/core/tools/bash.js.map +1 -1
  60. package/dist/core/tools/edit.d.ts.map +1 -1
  61. package/dist/core/tools/edit.js +3 -2
  62. package/dist/core/tools/edit.js.map +1 -1
  63. package/dist/core/tools/file-mutation-queue.d.ts +6 -0
  64. package/dist/core/tools/file-mutation-queue.d.ts.map +1 -0
  65. package/dist/core/tools/file-mutation-queue.js +37 -0
  66. package/dist/core/tools/file-mutation-queue.js.map +1 -0
  67. package/dist/core/tools/index.d.ts +1 -0
  68. package/dist/core/tools/index.d.ts.map +1 -1
  69. package/dist/core/tools/index.js +1 -0
  70. package/dist/core/tools/index.js.map +1 -1
  71. package/dist/core/tools/write.d.ts.map +1 -1
  72. package/dist/core/tools/write.js +6 -3
  73. package/dist/core/tools/write.js.map +1 -1
  74. package/dist/index.d.ts +3 -3
  75. package/dist/index.d.ts.map +1 -1
  76. package/dist/index.js +2 -2
  77. package/dist/index.js.map +1 -1
  78. package/dist/main.d.ts.map +1 -1
  79. package/dist/main.js +10 -5
  80. package/dist/main.js.map +1 -1
  81. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  82. package/dist/modes/interactive/components/bash-execution.js +4 -4
  83. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  84. package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -1
  85. package/dist/modes/interactive/components/bordered-loader.js +1 -1
  86. package/dist/modes/interactive/components/bordered-loader.js.map +1 -1
  87. package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
  88. package/dist/modes/interactive/components/branch-summary-message.js +2 -2
  89. package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
  90. package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
  91. package/dist/modes/interactive/components/compaction-summary-message.js +2 -2
  92. package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
  93. package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
  94. package/dist/modes/interactive/components/config-selector.js +8 -8
  95. package/dist/modes/interactive/components/config-selector.js.map +1 -1
  96. package/dist/modes/interactive/components/custom-editor.d.ts +3 -3
  97. package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
  98. package/dist/modes/interactive/components/custom-editor.js +6 -6
  99. package/dist/modes/interactive/components/custom-editor.js.map +1 -1
  100. package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
  101. package/dist/modes/interactive/components/extension-editor.js +9 -9
  102. package/dist/modes/interactive/components/extension-editor.js.map +1 -1
  103. package/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
  104. package/dist/modes/interactive/components/extension-input.js +5 -5
  105. package/dist/modes/interactive/components/extension-input.js.map +1 -1
  106. package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
  107. package/dist/modes/interactive/components/extension-selector.js +8 -8
  108. package/dist/modes/interactive/components/extension-selector.js.map +1 -1
  109. package/dist/modes/interactive/components/index.d.ts +1 -1
  110. package/dist/modes/interactive/components/index.d.ts.map +1 -1
  111. package/dist/modes/interactive/components/index.js +1 -1
  112. package/dist/modes/interactive/components/index.js.map +1 -1
  113. package/dist/modes/interactive/components/keybinding-hints.d.ts +3 -36
  114. package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
  115. package/dist/modes/interactive/components/keybinding-hints.js +5 -44
  116. package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
  117. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  118. package/dist/modes/interactive/components/login-dialog.js +6 -6
  119. package/dist/modes/interactive/components/login-dialog.js.map +1 -1
  120. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  121. package/dist/modes/interactive/components/model-selector.js +12 -8
  122. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  123. package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
  124. package/dist/modes/interactive/components/oauth-selector.js +6 -6
  125. package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
  126. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  127. package/dist/modes/interactive/components/scoped-models-selector.js +4 -4
  128. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  129. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  130. package/dist/modes/interactive/components/session-selector.js +32 -35
  131. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  132. package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
  133. package/dist/modes/interactive/components/skill-invocation-message.js +2 -2
  134. package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
  135. package/dist/modes/interactive/components/tool-execution.d.ts +7 -0
  136. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  137. package/dist/modes/interactive/components/tool-execution.js +51 -6
  138. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  139. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  140. package/dist/modes/interactive/components/tree-selector.js +15 -15
  141. package/dist/modes/interactive/components/tree-selector.js.map +1 -1
  142. package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -1
  143. package/dist/modes/interactive/components/user-message-selector.js +6 -6
  144. package/dist/modes/interactive/components/user-message-selector.js.map +1 -1
  145. package/dist/modes/interactive/interactive-mode.d.ts +1 -0
  146. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  147. package/dist/modes/interactive/interactive-mode.js +140 -87
  148. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  149. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  150. package/dist/modes/interactive/theme/theme.js +49 -37
  151. package/dist/modes/interactive/theme/theme.js.map +1 -1
  152. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  153. package/dist/modes/rpc/rpc-mode.js +4 -1
  154. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  155. package/dist/utils/child-process.d.ts +11 -0
  156. package/dist/utils/child-process.d.ts.map +1 -0
  157. package/dist/utils/child-process.js +78 -0
  158. package/dist/utils/child-process.js.map +1 -0
  159. package/dist/utils/clipboard-native.d.ts +1 -0
  160. package/dist/utils/clipboard-native.d.ts.map +1 -1
  161. package/dist/utils/clipboard-native.js.map +1 -1
  162. package/dist/utils/clipboard.d.ts +1 -1
  163. package/dist/utils/clipboard.d.ts.map +1 -1
  164. package/dist/utils/clipboard.js +11 -1
  165. package/dist/utils/clipboard.js.map +1 -1
  166. package/docs/extensions.md +44 -7
  167. package/docs/keybindings.md +101 -112
  168. package/docs/providers.md +7 -0
  169. package/docs/rpc.md +4 -4
  170. package/docs/sdk.md +2 -2
  171. package/examples/extensions/antigravity-image-gen.ts +5 -3
  172. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  173. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  174. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  175. package/examples/extensions/custom-provider-qwen-cli/package.json +1 -1
  176. package/examples/extensions/subagent/index.ts +7 -5
  177. package/examples/extensions/tool-override.ts +9 -7
  178. package/examples/extensions/truncated-tool.ts +6 -3
  179. package/examples/extensions/with-deps/package-lock.json +2 -2
  180. package/examples/extensions/with-deps/package.json +1 -1
  181. package/package.json +4 -4
@@ -2,6 +2,10 @@
2
2
 
3
3
  All keyboard shortcuts can be customized via `~/.pi/agent/keybindings.json`. Each action can be bound to one or more keys.
4
4
 
5
+ The config file uses the same namespaced keybinding ids that pi uses internally and that extension authors use in `keyHint()` and injected `keybindings` managers.
6
+
7
+ Older configs using pre-namespaced ids such as `cursorUp` or `expandTools` are migrated automatically to the namespaced ids on startup.
8
+
5
9
  After editing `keybindings.json`, run `/reload` in pi to apply the changes without restarting the session.
6
10
 
7
11
  ## Key Format
@@ -18,127 +22,112 @@ Modifier combinations: `ctrl+shift+x`, `alt+ctrl+x`, `ctrl+shift+alt+x`, `ctrl+1
18
22
 
19
23
  ## All Actions
20
24
 
21
- ### Cursor Movement
25
+ ### TUI Editor Cursor Movement
22
26
 
23
- | Action | Default | Description |
27
+ | Keybinding id | Default | Description |
24
28
  |--------|---------|-------------|
25
- | `cursorUp` | `up` | Move cursor up |
26
- | `cursorDown` | `down` | Move cursor down |
27
- | `cursorLeft` | `left`, `ctrl+b` | Move cursor left |
28
- | `cursorRight` | `right`, `ctrl+f` | Move cursor right |
29
- | `cursorWordLeft` | `alt+left`, `ctrl+left`, `alt+b` | Move cursor word left |
30
- | `cursorWordRight` | `alt+right`, `ctrl+right`, `alt+f` | Move cursor word right |
31
- | `cursorLineStart` | `home`, `ctrl+a` | Move to line start |
32
- | `cursorLineEnd` | `end`, `ctrl+e` | Move to line end |
33
- | `jumpForward` | `ctrl+]` | Jump forward to character |
34
- | `jumpBackward` | `ctrl+alt+]` | Jump backward to character |
35
- | `pageUp` | `pageUp` | Scroll up by page |
36
- | `pageDown` | `pageDown` | Scroll down by page |
37
-
38
- ### Deletion
39
-
40
- | Action | Default | Description |
29
+ | `tui.editor.cursorUp` | `up` | Move cursor up |
30
+ | `tui.editor.cursorDown` | `down` | Move cursor down |
31
+ | `tui.editor.cursorLeft` | `left`, `ctrl+b` | Move cursor left |
32
+ | `tui.editor.cursorRight` | `right`, `ctrl+f` | Move cursor right |
33
+ | `tui.editor.cursorWordLeft` | `alt+left`, `ctrl+left`, `alt+b` | Move cursor word left |
34
+ | `tui.editor.cursorWordRight` | `alt+right`, `ctrl+right`, `alt+f` | Move cursor word right |
35
+ | `tui.editor.cursorLineStart` | `home`, `ctrl+a` | Move to line start |
36
+ | `tui.editor.cursorLineEnd` | `end`, `ctrl+e` | Move to line end |
37
+ | `tui.editor.jumpForward` | `ctrl+]` | Jump forward to character |
38
+ | `tui.editor.jumpBackward` | `ctrl+alt+]` | Jump backward to character |
39
+ | `tui.editor.pageUp` | `pageUp` | Scroll up by page |
40
+ | `tui.editor.pageDown` | `pageDown` | Scroll down by page |
41
+
42
+ ### TUI Editor Deletion
43
+
44
+ | Keybinding id | Default | Description |
41
45
  |--------|---------|-------------|
42
- | `deleteCharBackward` | `backspace` | Delete character backward |
43
- | `deleteCharForward` | `delete`, `ctrl+d` | Delete character forward |
44
- | `deleteWordBackward` | `ctrl+w`, `alt+backspace` | Delete word backward |
45
- | `deleteWordForward` | `alt+d`, `alt+delete` | Delete word forward |
46
- | `deleteToLineStart` | `ctrl+u` | Delete to line start |
47
- | `deleteToLineEnd` | `ctrl+k` | Delete to line end |
46
+ | `tui.editor.deleteCharBackward` | `backspace` | Delete character backward |
47
+ | `tui.editor.deleteCharForward` | `delete`, `ctrl+d` | Delete character forward |
48
+ | `tui.editor.deleteWordBackward` | `ctrl+w`, `alt+backspace` | Delete word backward |
49
+ | `tui.editor.deleteWordForward` | `alt+d`, `alt+delete` | Delete word forward |
50
+ | `tui.editor.deleteToLineStart` | `ctrl+u` | Delete to line start |
51
+ | `tui.editor.deleteToLineEnd` | `ctrl+k` | Delete to line end |
48
52
 
49
- ### Text Input
53
+ ### TUI Input
50
54
 
51
- | Action | Default | Description |
55
+ | Keybinding id | Default | Description |
52
56
  |--------|---------|-------------|
53
- | `newLine` | `shift+enter` | Insert new line |
54
- | `submit` | `enter` | Submit input |
55
- | `tab` | `tab` | Tab / autocomplete |
57
+ | `tui.input.newLine` | `shift+enter` | Insert new line |
58
+ | `tui.input.submit` | `enter` | Submit input |
59
+ | `tui.input.tab` | `tab` | Tab / autocomplete |
56
60
 
57
- ### Kill Ring
61
+ ### TUI Kill Ring
58
62
 
59
- | Action | Default | Description |
63
+ | Keybinding id | Default | Description |
60
64
  |--------|---------|-------------|
61
- | `yank` | `ctrl+y` | Paste most recently deleted text |
62
- | `yankPop` | `alt+y` | Cycle through deleted text after yank |
63
- | `undo` | `ctrl+-` | Undo last edit |
65
+ | `tui.editor.yank` | `ctrl+y` | Paste most recently deleted text |
66
+ | `tui.editor.yankPop` | `alt+y` | Cycle through deleted text after yank |
67
+ | `tui.editor.undo` | `ctrl+-` | Undo last edit |
64
68
 
65
- ### Clipboard
69
+ ### TUI Clipboard and Selection
66
70
 
67
- | Action | Default | Description |
71
+ | Keybinding id | Default | Description |
68
72
  |--------|---------|-------------|
69
- | `copy` | `ctrl+c` | Copy selection |
70
- | `pasteImage` | `ctrl+v` | Paste image from clipboard |
73
+ | `tui.input.copy` | `ctrl+c` | Copy selection |
74
+ | `tui.select.up` | `up` | Move selection up |
75
+ | `tui.select.down` | `down` | Move selection down |
76
+ | `tui.select.pageUp` | `pageUp` | Page up in list |
77
+ | `tui.select.pageDown` | `pageDown` | Page down in list |
78
+ | `tui.select.confirm` | `enter` | Confirm selection |
79
+ | `tui.select.cancel` | `escape`, `ctrl+c` | Cancel selection |
71
80
 
72
81
  ### Application
73
82
 
74
- | Action | Default | Description |
83
+ | Keybinding id | Default | Description |
75
84
  |--------|---------|-------------|
76
- | `interrupt` | `escape` | Cancel / abort |
77
- | `clear` | `ctrl+c` | Clear editor |
78
- | `exit` | `ctrl+d` | Exit (when editor empty) |
79
- | `suspend` | `ctrl+z` | Suspend to background |
80
- | `externalEditor` | `ctrl+g` | Open in external editor (`$VISUAL` or `$EDITOR`) |
85
+ | `app.interrupt` | `escape` | Cancel / abort |
86
+ | `app.clear` | `ctrl+c` | Clear editor |
87
+ | `app.exit` | `ctrl+d` | Exit (when editor empty) |
88
+ | `app.suspend` | `ctrl+z` | Suspend to background |
89
+ | `app.editor.external` | `ctrl+g` | Open in external editor (`$VISUAL` or `$EDITOR`) |
90
+ | `app.clipboard.pasteImage` | `ctrl+v` (`alt+v` on Windows) | Paste image from clipboard |
81
91
 
82
- ### Session
92
+ ### Sessions
83
93
 
84
- | Action | Default | Description |
94
+ | Keybinding id | Default | Description |
85
95
  |--------|---------|-------------|
86
- | `newSession` | *(none)* | Start a new session (`/new`) |
87
- | `tree` | *(none)* | Open session tree navigator (`/tree`) |
88
- | `fork` | *(none)* | Fork current session (`/fork`) |
89
- | `resume` | *(none)* | Open session resume picker (`/resume`) |
90
-
91
- ### Models & Thinking
92
-
93
- | Action | Default | Description |
94
- |--------|---------|-------------|
95
- | `selectModel` | `ctrl+l` | Open model selector |
96
- | `cycleModelForward` | `ctrl+p` | Cycle to next model |
97
- | `cycleModelBackward` | `shift+ctrl+p` | Cycle to previous model |
98
- | `cycleThinkingLevel` | `shift+tab` | Cycle thinking level |
99
-
100
- ### Display
101
-
102
- | Action | Default | Description |
96
+ | `app.session.new` | *(none)* | Start a new session (`/new`) |
97
+ | `app.session.tree` | *(none)* | Open session tree navigator (`/tree`) |
98
+ | `app.session.fork` | *(none)* | Fork current session (`/fork`) |
99
+ | `app.session.resume` | *(none)* | Open session resume picker (`/resume`) |
100
+ | `app.session.togglePath` | `ctrl+p` | Toggle path display |
101
+ | `app.session.toggleSort` | `ctrl+s` | Toggle sort mode |
102
+ | `app.session.toggleNamedFilter` | `ctrl+n` | Toggle named-only filter |
103
+ | `app.session.rename` | `ctrl+r` | Rename session |
104
+ | `app.session.delete` | `ctrl+d` | Delete session |
105
+ | `app.session.deleteNoninvasive` | `ctrl+backspace` | Delete session when query is empty |
106
+
107
+ ### Models and Thinking
108
+
109
+ | Keybinding id | Default | Description |
103
110
  |--------|---------|-------------|
104
- | `expandTools` | `ctrl+o` | Collapse/expand tool output |
105
- | `toggleThinking` | `ctrl+t` | Collapse/expand thinking blocks |
111
+ | `app.model.select` | `ctrl+l` | Open model selector |
112
+ | `app.model.cycleForward` | `ctrl+p` | Cycle to next model |
113
+ | `app.model.cycleBackward` | `shift+ctrl+p` | Cycle to previous model |
114
+ | `app.thinking.cycle` | `shift+tab` | Cycle thinking level |
115
+ | `app.thinking.toggle` | `ctrl+t` | Collapse or expand thinking blocks |
106
116
 
107
- ### Message Queue
117
+ ### Display and Message Queue
108
118
 
109
- | Action | Default | Description |
119
+ | Keybinding id | Default | Description |
110
120
  |--------|---------|-------------|
111
- | `followUp` | `alt+enter` | Queue follow-up message |
112
- | `dequeue` | `alt+up` | Restore queued messages to editor |
113
-
114
- ### Selection (Lists, Pickers)
115
-
116
- | Action | Default | Description |
117
- |--------|---------|-------------|
118
- | `selectUp` | `up` | Move selection up |
119
- | `selectDown` | `down` | Move selection down |
120
- | `selectPageUp` | `pageUp` | Page up in list |
121
- | `selectPageDown` | `pageDown` | Page down in list |
122
- | `selectConfirm` | `enter` | Confirm selection |
123
- | `selectCancel` | `escape`, `ctrl+c` | Cancel selection |
121
+ | `app.tools.expand` | `ctrl+o` | Collapse or expand tool output |
122
+ | `app.message.followUp` | `alt+enter` | Queue follow-up message |
123
+ | `app.message.dequeue` | `alt+up` | Restore queued messages to editor |
124
124
 
125
125
  ### Tree Navigation
126
126
 
127
- | Action | Default | Description |
128
- |--------|---------|-------------|
129
- | `treeFoldOrUp` | `ctrl+left`, `alt+left` | Fold current branch segment, or jump to the previous segment start |
130
- | `treeUnfoldOrDown` | `ctrl+right`, `alt+right` | Unfold current branch segment, or jump to the next segment start or branch end |
131
-
132
- ### Session Picker
133
-
134
- | Action | Default | Description |
127
+ | Keybinding id | Default | Description |
135
128
  |--------|---------|-------------|
136
- | `toggleSessionPath` | `ctrl+p` | Toggle path display |
137
- | `toggleSessionSort` | `ctrl+s` | Toggle sort mode |
138
- | `toggleSessionNamedFilter` | `ctrl+n` | Toggle named-only filter |
139
- | `renameSession` | `ctrl+r` | Rename session |
140
- | `deleteSession` | `ctrl+d` | Delete session |
141
- | `deleteSessionNoninvasive` | `ctrl+backspace` | Delete session (when query empty) |
129
+ | `app.tree.foldOrUp` | `ctrl+left`, `alt+left` | Fold current branch segment, or jump to the previous segment start |
130
+ | `app.tree.unfoldOrDown` | `ctrl+right`, `alt+right` | Unfold current branch segment, or jump to the next segment start or branch end |
142
131
 
143
132
  ## Custom Configuration
144
133
 
@@ -146,9 +135,9 @@ Create `~/.pi/agent/keybindings.json`:
146
135
 
147
136
  ```json
148
137
  {
149
- "cursorUp": ["up", "ctrl+p"],
150
- "cursorDown": ["down", "ctrl+n"],
151
- "deleteWordBackward": ["ctrl+w", "alt+backspace"]
138
+ "tui.editor.cursorUp": ["up", "ctrl+p"],
139
+ "tui.editor.cursorDown": ["down", "ctrl+n"],
140
+ "tui.editor.deleteWordBackward": ["ctrl+w", "alt+backspace"]
152
141
  }
153
142
  ```
154
143
 
@@ -158,15 +147,15 @@ Each action can have a single key or an array of keys. User config overrides def
158
147
 
159
148
  ```json
160
149
  {
161
- "cursorUp": ["up", "ctrl+p"],
162
- "cursorDown": ["down", "ctrl+n"],
163
- "cursorLeft": ["left", "ctrl+b"],
164
- "cursorRight": ["right", "ctrl+f"],
165
- "cursorWordLeft": ["alt+left", "alt+b"],
166
- "cursorWordRight": ["alt+right", "alt+f"],
167
- "deleteCharForward": ["delete", "ctrl+d"],
168
- "deleteCharBackward": ["backspace", "ctrl+h"],
169
- "newLine": ["shift+enter", "ctrl+j"]
150
+ "tui.editor.cursorUp": ["up", "ctrl+p"],
151
+ "tui.editor.cursorDown": ["down", "ctrl+n"],
152
+ "tui.editor.cursorLeft": ["left", "ctrl+b"],
153
+ "tui.editor.cursorRight": ["right", "ctrl+f"],
154
+ "tui.editor.cursorWordLeft": ["alt+left", "alt+b"],
155
+ "tui.editor.cursorWordRight": ["alt+right", "alt+f"],
156
+ "tui.editor.deleteCharForward": ["delete", "ctrl+d"],
157
+ "tui.editor.deleteCharBackward": ["backspace", "ctrl+h"],
158
+ "tui.input.newLine": ["shift+enter", "ctrl+j"]
170
159
  }
171
160
  ```
172
161
 
@@ -174,11 +163,11 @@ Each action can have a single key or an array of keys. User config overrides def
174
163
 
175
164
  ```json
176
165
  {
177
- "cursorUp": ["up", "alt+k"],
178
- "cursorDown": ["down", "alt+j"],
179
- "cursorLeft": ["left", "alt+h"],
180
- "cursorRight": ["right", "alt+l"],
181
- "cursorWordLeft": ["alt+left", "alt+b"],
182
- "cursorWordRight": ["alt+right", "alt+w"]
166
+ "tui.editor.cursorUp": ["up", "alt+k"],
167
+ "tui.editor.cursorDown": ["down", "alt+j"],
168
+ "tui.editor.cursorLeft": ["left", "alt+h"],
169
+ "tui.editor.cursorRight": ["right", "alt+l"],
170
+ "tui.editor.cursorWordLeft": ["alt+left", "alt+b"],
171
+ "tui.editor.cursorWordRight": ["alt+right", "alt+w"]
183
172
  }
184
173
  ```
package/docs/providers.md CHANGED
@@ -147,6 +147,13 @@ Also supports ECS task roles (`AWS_CONTAINER_CREDENTIALS_*`) and IRSA (`AWS_WEB_
147
147
  pi --provider amazon-bedrock --model us.anthropic.claude-sonnet-4-20250514-v1:0
148
148
  ```
149
149
 
150
+ Prompt caching is enabled automatically for Claude models whose ID contains a recognizable model name (base models and system-defined inference profiles). For application inference profiles (whose ARNs don't contain the model name), set `AWS_BEDROCK_FORCE_CACHE=1` to enable cache points:
151
+
152
+ ```bash
153
+ export AWS_BEDROCK_FORCE_CACHE=1
154
+ pi --provider amazon-bedrock --model arn:aws:bedrock:us-east-1:123456789012:application-inference-profile/abc123
155
+ ```
156
+
150
157
  If you are connecting to a Bedrock API proxy, the following environment variables can be used:
151
158
 
152
159
  ```bash
package/docs/rpc.md CHANGED
@@ -58,7 +58,7 @@ With images:
58
58
  {"type": "prompt", "message": "New instruction", "streamingBehavior": "steer"}
59
59
  ```
60
60
 
61
- - `"steer"`: Interrupt the agent mid-run. Message is delivered after current tool execution, remaining tools are skipped.
61
+ - `"steer"`: Queue the message while the agent is running. It is delivered after the current assistant turn finishes executing its tool calls, before the next LLM call.
62
62
  - `"followUp"`: Wait until the agent finishes. Message is delivered only when agent stops.
63
63
 
64
64
  If the agent is streaming and no `streamingBehavior` is specified, the command returns an error.
@@ -76,7 +76,7 @@ The `images` field is optional. Each image uses `ImageContent` format: `{"type":
76
76
 
77
77
  #### steer
78
78
 
79
- Queue a steering message to interrupt the agent mid-run. Delivered after current tool execution, remaining tools are skipped. Skill commands and prompt templates are expanded. Extension commands are not allowed (use `prompt` instead).
79
+ Queue a steering message while the agent is running. It is delivered after the current assistant turn finishes executing its tool calls, before the next LLM call. Skill commands and prompt templates are expanded. Extension commands are not allowed (use `prompt` instead).
80
80
 
81
81
  ```json
82
82
  {"type": "steer", "message": "Stop and do this instead"}
@@ -321,8 +321,8 @@ Control how steering messages (from `steer`) are delivered.
321
321
  ```
322
322
 
323
323
  Modes:
324
- - `"all"`: Deliver all steering messages at the next interruption point
325
- - `"one-at-a-time"`: Deliver one steering message per interruption (default)
324
+ - `"all"`: Deliver all steering messages after the current assistant turn finishes executing its tool calls
325
+ - `"one-at-a-time"`: Deliver one steering message per completed assistant turn (default)
326
326
 
327
327
  Response:
328
328
  ```json
package/docs/sdk.md CHANGED
@@ -78,7 +78,7 @@ interface AgentSession {
78
78
  prompt(text: string, options?: PromptOptions): Promise<void>;
79
79
 
80
80
  // Queue messages during streaming
81
- steer(text: string): Promise<void>; // Interrupt: delivered after current tool, skips remaining
81
+ steer(text: string): Promise<void>; // Queue for delivery after the current assistant turn finishes its tool calls
82
82
  followUp(text: string): Promise<void>; // Wait: delivered only when agent finishes
83
83
 
84
84
  // Subscribe to events (returns unsubscribe function)
@@ -150,7 +150,7 @@ await session.prompt("After you're done, also check X", { streamingBehavior: "fo
150
150
  For explicit queueing during streaming:
151
151
 
152
152
  ```typescript
153
- // Interrupt the agent (delivered after current tool, skips remaining tools)
153
+ // Queue a steering message for delivery after the current assistant turn finishes its tool calls
154
154
  await session.steer("New instruction");
155
155
 
156
156
  // Wait for agent to finish (delivered only when agent stops)
@@ -30,7 +30,7 @@ import { existsSync, readFileSync } from "node:fs";
30
30
  import { mkdir, writeFile } from "node:fs/promises";
31
31
  import { join } from "node:path";
32
32
  import { StringEnum } from "@mariozechner/pi-ai";
33
- import { type ExtensionAPI, getAgentDir } from "@mariozechner/pi-coding-agent";
33
+ import { type ExtensionAPI, getAgentDir, withFileMutationQueue } from "@mariozechner/pi-coding-agent";
34
34
  import { type Static, Type } from "@sinclair/typebox";
35
35
 
36
36
  const PROVIDER = "google-antigravity";
@@ -228,12 +228,14 @@ function imageExtension(mimeType: string): string {
228
228
  }
229
229
 
230
230
  async function saveImage(base64Data: string, mimeType: string, outputDir: string): Promise<string> {
231
- await mkdir(outputDir, { recursive: true });
232
231
  const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
233
232
  const ext = imageExtension(mimeType);
234
233
  const filename = `image-${timestamp}-${randomUUID().slice(0, 8)}.${ext}`;
235
234
  const filePath = join(outputDir, filename);
236
- await writeFile(filePath, Buffer.from(base64Data, "base64"));
235
+ await withFileMutationQueue(filePath, async () => {
236
+ await mkdir(outputDir, { recursive: true });
237
+ await writeFile(filePath, Buffer.from(base64Data, "base64"));
238
+ });
237
239
  return filePath;
238
240
  }
239
241
 
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "pi-extension-custom-provider",
3
- "version": "1.11.0",
3
+ "version": "1.12.0",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "pi-extension-custom-provider",
9
- "version": "1.11.0",
9
+ "version": "1.12.0",
10
10
  "dependencies": {
11
11
  "@anthropic-ai/sdk": "^0.52.0"
12
12
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pi-extension-custom-provider-anthropic",
3
3
  "private": true,
4
- "version": "1.11.0",
4
+ "version": "1.12.0",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "clean": "echo 'nothing to clean'",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pi-extension-custom-provider-gitlab-duo",
3
3
  "private": true,
4
- "version": "1.11.0",
4
+ "version": "1.12.0",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "clean": "echo 'nothing to clean'",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pi-extension-custom-provider-qwen-cli",
3
3
  "private": true,
4
- "version": "1.10.0",
4
+ "version": "1.11.0",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "clean": "echo 'nothing to clean'",
@@ -19,7 +19,7 @@ import * as path from "node:path";
19
19
  import type { AgentToolResult } from "@mariozechner/pi-agent-core";
20
20
  import type { Message } from "@mariozechner/pi-ai";
21
21
  import { StringEnum } from "@mariozechner/pi-ai";
22
- import { type ExtensionAPI, getMarkdownTheme } from "@mariozechner/pi-coding-agent";
22
+ import { type ExtensionAPI, getMarkdownTheme, withFileMutationQueue } from "@mariozechner/pi-coding-agent";
23
23
  import { Container, Markdown, Spacer, Text } from "@mariozechner/pi-tui";
24
24
  import { Type } from "@sinclair/typebox";
25
25
  import { type AgentConfig, type AgentScope, discoverAgents } from "./agents.js";
@@ -207,11 +207,13 @@ async function mapWithConcurrencyLimit<TIn, TOut>(
207
207
  return results;
208
208
  }
209
209
 
210
- function writePromptToTempFile(agentName: string, prompt: string): { dir: string; filePath: string } {
211
- const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-subagent-"));
210
+ async function writePromptToTempFile(agentName: string, prompt: string): Promise<{ dir: string; filePath: string }> {
211
+ const tmpDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), "pi-subagent-"));
212
212
  const safeName = agentName.replace(/[^\w.-]+/g, "_");
213
213
  const filePath = path.join(tmpDir, `prompt-${safeName}.md`);
214
- fs.writeFileSync(filePath, prompt, { encoding: "utf-8", mode: 0o600 });
214
+ await withFileMutationQueue(filePath, async () => {
215
+ await fs.promises.writeFile(filePath, prompt, { encoding: "utf-8", mode: 0o600 });
216
+ });
215
217
  return { dir: tmpDir, filePath };
216
218
  }
217
219
 
@@ -274,7 +276,7 @@ async function runSingleAgent(
274
276
 
275
277
  try {
276
278
  if (agent.systemPrompt.trim()) {
277
- const tmp = writePromptToTempFile(agent.name, agent.systemPrompt);
279
+ const tmp = await writePromptToTempFile(agent.name, agent.systemPrompt);
278
280
  tmpPromptDir = tmp.dir;
279
281
  tmpPromptPath = tmp.filePath;
280
282
  args.push("--append-system-prompt", tmpPromptPath);
@@ -21,10 +21,10 @@
21
21
  */
22
22
 
23
23
  import type { TextContent } from "@mariozechner/pi-ai";
24
- import { type ExtensionAPI, getAgentDir } from "@mariozechner/pi-coding-agent";
24
+ import { type ExtensionAPI, getAgentDir, withFileMutationQueue } from "@mariozechner/pi-coding-agent";
25
25
  import { Type } from "@sinclair/typebox";
26
- import { appendFileSync, constants, readFileSync } from "fs";
27
- import { access, readFile } from "fs/promises";
26
+ import { constants, readFileSync } from "fs";
27
+ import { access, appendFile, readFile } from "fs/promises";
28
28
  import { join, resolve } from "path";
29
29
 
30
30
  const LOG_FILE = join(getAgentDir(), "read-access.log");
@@ -44,14 +44,16 @@ function isBlockedPath(path: string): boolean {
44
44
  return BLOCKED_PATTERNS.some((pattern) => pattern.test(path));
45
45
  }
46
46
 
47
- function logAccess(path: string, allowed: boolean, reason?: string) {
47
+ async function logAccess(path: string, allowed: boolean, reason?: string) {
48
48
  const timestamp = new Date().toISOString();
49
49
  const status = allowed ? "ALLOWED" : "BLOCKED";
50
50
  const msg = reason ? ` (${reason})` : "";
51
51
  const line = `[${timestamp}] ${status}: ${path}${msg}\n`;
52
52
 
53
53
  try {
54
- appendFileSync(LOG_FILE, line);
54
+ await withFileMutationQueue(LOG_FILE, async () => {
55
+ await appendFile(LOG_FILE, line);
56
+ });
55
57
  } catch {
56
58
  // Ignore logging errors
57
59
  }
@@ -77,7 +79,7 @@ export default function (pi: ExtensionAPI) {
77
79
 
78
80
  // Check if path is blocked
79
81
  if (isBlockedPath(absolutePath)) {
80
- logAccess(absolutePath, false, "matches blocked pattern");
82
+ await logAccess(absolutePath, false, "matches blocked pattern");
81
83
  return {
82
84
  content: [
83
85
  {
@@ -90,7 +92,7 @@ export default function (pi: ExtensionAPI) {
90
92
  }
91
93
 
92
94
  // Log allowed access
93
- logAccess(absolutePath, true);
95
+ await logAccess(absolutePath, true);
94
96
 
95
97
  // Perform the actual read (simplified implementation)
96
98
  try {
@@ -14,6 +14,7 @@
14
14
  * built-in `grep` tool in src/core/tools/grep.ts for a more complete implementation.
15
15
  */
16
16
 
17
+ import { mkdtemp, writeFile } from "node:fs/promises";
17
18
  import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
18
19
  import {
19
20
  DEFAULT_MAX_BYTES,
@@ -21,11 +22,11 @@ import {
21
22
  formatSize,
22
23
  type TruncationResult,
23
24
  truncateHead,
25
+ withFileMutationQueue,
24
26
  } from "@mariozechner/pi-coding-agent";
25
27
  import { Text } from "@mariozechner/pi-tui";
26
28
  import { Type } from "@sinclair/typebox";
27
29
  import { execSync } from "child_process";
28
- import { mkdtempSync, writeFileSync } from "fs";
29
30
  import { tmpdir } from "os";
30
31
  import { join } from "path";
31
32
 
@@ -108,9 +109,11 @@ export default function (pi: ExtensionAPI) {
108
109
 
109
110
  if (truncation.truncated) {
110
111
  // Save full output to a temp file so LLM can access it if needed
111
- const tempDir = mkdtempSync(join(tmpdir(), "pi-rg-"));
112
+ const tempDir = await mkdtemp(join(tmpdir(), "pi-rg-"));
112
113
  const tempFile = join(tempDir, "output.txt");
113
- writeFileSync(tempFile, output);
114
+ await withFileMutationQueue(tempFile, async () => {
115
+ await writeFile(tempFile, output, "utf8");
116
+ });
114
117
 
115
118
  details.truncation = truncation;
116
119
  details.fullOutputPath = tempFile;
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "pi-extension-with-deps",
3
- "version": "1.24.0",
3
+ "version": "1.25.0",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "pi-extension-with-deps",
9
- "version": "1.24.0",
9
+ "version": "1.25.0",
10
10
  "dependencies": {
11
11
  "ms": "^2.1.3"
12
12
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pi-extension-with-deps",
3
3
  "private": true,
4
- "version": "1.24.0",
4
+ "version": "1.25.0",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "clean": "echo 'nothing to clean'",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mariozechner/pi-coding-agent",
3
- "version": "0.60.0",
3
+ "version": "0.61.0",
4
4
  "description": "Coding agent CLI with read, bash, edit, write tools and session management",
5
5
  "type": "module",
6
6
  "piConfig": {
@@ -40,9 +40,9 @@
40
40
  },
41
41
  "dependencies": {
42
42
  "@mariozechner/jiti": "^2.6.2",
43
- "@mariozechner/pi-agent-core": "^0.60.0",
44
- "@mariozechner/pi-ai": "^0.60.0",
45
- "@mariozechner/pi-tui": "^0.60.0",
43
+ "@mariozechner/pi-agent-core": "^0.61.0",
44
+ "@mariozechner/pi-ai": "^0.61.0",
45
+ "@mariozechner/pi-tui": "^0.61.0",
46
46
  "@silvia-odwyer/photon-node": "^0.3.4",
47
47
  "chalk": "^5.5.0",
48
48
  "cli-highlight": "^2.1.11",