@oh-my-pi/pi-coding-agent 3.32.0 → 3.34.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 (74) hide show
  1. package/CHANGELOG.md +49 -9
  2. package/README.md +12 -0
  3. package/docs/custom-tools.md +1 -1
  4. package/docs/extensions.md +4 -4
  5. package/docs/hooks.md +2 -2
  6. package/docs/sdk.md +4 -8
  7. package/examples/custom-tools/README.md +2 -2
  8. package/examples/extensions/README.md +1 -1
  9. package/examples/extensions/todo.ts +1 -1
  10. package/examples/hooks/custom-compaction.ts +4 -2
  11. package/examples/hooks/handoff.ts +1 -1
  12. package/examples/hooks/qna.ts +1 -1
  13. package/examples/sdk/02-custom-model.ts +1 -1
  14. package/examples/sdk/README.md +1 -1
  15. package/package.json +5 -5
  16. package/src/capability/ssh.ts +42 -0
  17. package/src/cli/file-processor.ts +1 -1
  18. package/src/cli/list-models.ts +1 -1
  19. package/src/core/agent-session.ts +21 -6
  20. package/src/core/auth-storage.ts +1 -1
  21. package/src/core/compaction/branch-summarization.ts +2 -2
  22. package/src/core/compaction/compaction.ts +2 -2
  23. package/src/core/compaction/utils.ts +1 -1
  24. package/src/core/custom-tools/types.ts +1 -1
  25. package/src/core/extensions/runner.ts +1 -1
  26. package/src/core/extensions/types.ts +1 -1
  27. package/src/core/extensions/wrapper.ts +1 -1
  28. package/src/core/file-mentions.ts +147 -5
  29. package/src/core/hooks/runner.ts +2 -2
  30. package/src/core/hooks/types.ts +1 -1
  31. package/src/core/index.ts +11 -0
  32. package/src/core/messages.ts +1 -1
  33. package/src/core/model-registry.ts +1 -1
  34. package/src/core/model-resolver.ts +9 -4
  35. package/src/core/sdk.ts +26 -2
  36. package/src/core/session-manager.ts +3 -2
  37. package/src/core/settings-manager.ts +70 -0
  38. package/src/core/ssh/connection-manager.ts +466 -0
  39. package/src/core/ssh/ssh-executor.ts +190 -0
  40. package/src/core/ssh/sshfs-mount.ts +162 -0
  41. package/src/core/ssh-executor.ts +5 -0
  42. package/src/core/system-prompt.ts +424 -1
  43. package/src/core/title-generator.ts +109 -55
  44. package/src/core/tools/index.test.ts +1 -0
  45. package/src/core/tools/index.ts +3 -0
  46. package/src/core/tools/output.ts +37 -2
  47. package/src/core/tools/read.ts +24 -11
  48. package/src/core/tools/renderers.ts +2 -0
  49. package/src/core/tools/ssh.ts +302 -0
  50. package/src/core/tools/task/index.ts +1 -1
  51. package/src/core/tools/task/render.ts +10 -16
  52. package/src/core/tools/task/types.ts +1 -1
  53. package/src/core/tools/task/worker.ts +1 -1
  54. package/src/core/voice.ts +1 -1
  55. package/src/discovery/index.ts +3 -0
  56. package/src/discovery/ssh.ts +162 -0
  57. package/src/main.ts +2 -1
  58. package/src/modes/interactive/components/assistant-message.ts +1 -1
  59. package/src/modes/interactive/components/bash-execution.ts +9 -10
  60. package/src/modes/interactive/components/custom-message.ts +1 -1
  61. package/src/modes/interactive/components/footer.ts +1 -1
  62. package/src/modes/interactive/components/hook-message.ts +1 -1
  63. package/src/modes/interactive/components/model-selector.ts +1 -1
  64. package/src/modes/interactive/components/oauth-selector.ts +1 -1
  65. package/src/modes/interactive/components/status-line.ts +1 -1
  66. package/src/modes/interactive/components/tree-selector.ts +9 -12
  67. package/src/modes/interactive/interactive-mode.ts +5 -2
  68. package/src/modes/interactive/theme/theme.ts +2 -2
  69. package/src/modes/print-mode.ts +1 -1
  70. package/src/modes/rpc/rpc-client.ts +1 -1
  71. package/src/modes/rpc/rpc-types.ts +1 -1
  72. package/src/prompts/system-prompt.md +4 -0
  73. package/src/prompts/tools/ssh.md +74 -0
  74. package/src/utils/image-resize.ts +1 -1
package/CHANGELOG.md CHANGED
@@ -2,7 +2,44 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [3.34.0] - 2026-01-09
6
+
7
+ ### Added
8
+
9
+ - Added caching for system environment detection to improve startup performance
10
+ - Added disk usage information to automatic environment detection in system prompt
11
+ - Added `compat` option for SSH hosts to wrap commands in a POSIX shell on Windows systems
12
+ - Added automatic working directory handling for PowerShell and cmd.exe on Windows SSH hosts
13
+ - Added automatic environment detection to system prompt including OS, distro, kernel, CPU, GPU, shell, terminal, desktop environment, and window manager information
14
+ - Added SSH tool with project ssh.json/.ssh.json discovery, persistent connections, and optional sshfs mounts
15
+ - Added SSH host OS/shell detection with compat mode and persistent host info cache
16
+
17
+ ### Changed
18
+
19
+ - Changed GPU detection on Linux to prioritize discrete GPUs (NVIDIA, AMD) over integrated graphics and skip server management adapters
20
+ - Changed SSH host info cache to use versioned format for automatic refresh on schema changes
21
+ - Changed SSH compat shell detection to actively probe for bash/sh availability on Windows hosts
22
+ - Changed SSH tool description to show detected shell type and available commands per host
23
+
24
+ ## [3.33.0] - 2026-01-08
25
+
26
+ ### Added
27
+
28
+ - Added `env` support in `settings.json` for automatically setting environment variables on startup
29
+ - Added environment variable management methods to SettingsManager (get/set/clear)
30
+
31
+ ### Fixed
32
+
33
+ - Fixed bash output previews to recompute on resize, preventing TUI line width overflow crashes
34
+ - Fixed session title generation to retry alternate smol models when the primary model errors or is rate-limited
35
+ - Fixed file mentions to resolve extensionless paths and directories, using read tool truncation limits for injected content
36
+ - Fixed interactive UI to show auto-read file mention indicators
37
+ - Fixed task tool tree rendering to use consistent tree connectors for progress, findings, and results
38
+ - Fixed last-branch tree connector symbol in the TUI
39
+ - Fixed output tool previews to use compact JSON when outputs are formatted with leading braces
40
+
5
41
  ## [3.32.0] - 2026-01-08
42
+
6
43
  ### Added
7
44
 
8
45
  - Added progress indicator when starting LSP servers at session startup
@@ -88,6 +125,7 @@
88
125
  - Fixed byte counting in task output truncation to handle multi-byte Unicode characters correctly
89
126
 
90
127
  ## [3.30.0] - 2026-01-07
128
+
91
129
  ### Added
92
130
 
93
131
  - Added environment variable configuration for task limits: `OMP_TASK_MAX_PARALLEL`, `OMP_TASK_MAX_CONCURRENCY`, `OMP_TASK_MAX_OUTPUT_BYTES`, `OMP_TASK_MAX_OUTPUT_LINES`, and `OMP_TASK_MAX_AGENTS_IN_DESCRIPTION`
@@ -107,6 +145,7 @@
107
145
  - Fixed markitdown tool installation to use automatic tool installer instead of requiring manual installation
108
146
 
109
147
  ## [3.25.0] - 2026-01-07
148
+
110
149
  ### Added
111
150
 
112
151
  - Added `complete` tool for structured subagent output with JSON schema validation
@@ -122,6 +161,7 @@
122
161
  - Simplified worker agent system prompt to be more concise and focused
123
162
 
124
163
  ## [3.24.0] - 2026-01-07
164
+
125
165
  ### Added
126
166
 
127
167
  - Added `ToolSession` interface to unify tool creation with session context including cwd, UI availability, and rulebook rules
@@ -164,7 +204,7 @@
164
204
 
165
205
  ### Changed
166
206
 
167
- - Switched from local `@oh-my-pi/pi-ai` to upstream `@mariozechner/pi-ai` package
207
+ - Switched from local `@oh-my-pi/pi-ai` to upstream `@oh-my-pi/pi-ai` package
168
208
 
169
209
  ### Added
170
210
 
@@ -805,7 +845,7 @@ See [docs/custom-tools.md](docs/custom-tools.md) and [examples/custom-tools/](ex
805
845
  - `AppMessage` → `AgentMessage`
806
846
  - `sessionFile` returns `string | undefined` (was `string | null`)
807
847
  - `model` returns `Model | undefined` (was `Model | null`)
808
- - `Attachment` type removed. Use `ImageContent` from `@mariozechner/pi-ai` instead. Add images directly to message content arrays.
848
+ - `Attachment` type removed. Use `ImageContent` from `@oh-my-pi/pi-ai` instead. Add images directly to message content arrays.
809
849
 
810
850
  **AgentSession API:**
811
851
 
@@ -1031,7 +1071,7 @@ Total color count increased from 46 to 50. See [docs/theme.md](docs/theme.md) fo
1031
1071
  - `createAgentSession()` now accepts `authStorage` and `modelRegistry` options
1032
1072
  - Removed `configureOAuthStorage()`, `defaultGetApiKey()`, `findModel()`, `discoverAvailableModels()`
1033
1073
  - Removed `getApiKey` callback option (use `AuthStorage.setRuntimeApiKey()` for runtime overrides)
1034
- - Use `getModel()` from `@mariozechner/pi-ai` for built-in models, `modelRegistry.find()` for custom models + built-in models
1074
+ - Use `getModel()` from `@oh-my-pi/pi-ai` for built-in models, `modelRegistry.find()` for custom models + built-in models
1035
1075
  - See updated [SDK documentation](docs/sdk.md) and [README](README.md)
1036
1076
 
1037
1077
  - **Settings changes**: Removed `apiKeys` from `settings.json`. Use `auth.json` instead. ([#296](https://github.com/badlogic/pi-mono/issues/296))
@@ -1334,7 +1374,7 @@ Total color count increased from 46 to 50. See [docs/theme.md](docs/theme.md) fo
1334
1374
  - `rpc.md`: Added missing `hook_error` event documentation
1335
1375
  - `README.md`: Complete settings table, condensed philosophy section, standardized OAuth docs
1336
1376
 
1337
- - Hooks loader now supports same import aliases as custom tools (`@sinclair/typebox`, `@mariozechner/pi-ai`, `@oh-my-pi/pi-tui`, `@oh-my-pi/pi-coding-agent`).
1377
+ - Hooks loader now supports same import aliases as custom tools (`@sinclair/typebox`, `@oh-my-pi/pi-ai`, `@oh-my-pi/pi-tui`, `@oh-my-pi/pi-coding-agent`).
1338
1378
 
1339
1379
  ### Breaking Changes
1340
1380
 
@@ -1356,7 +1396,7 @@ Total color count increased from 46 to 50. See [docs/theme.md](docs/theme.md) fo
1356
1396
 
1357
1397
  - Fixed TUI performance regression caused by Box component lacking render caching. Built-in tools now use Text directly (like v0.22.5), and Box has proper caching for custom tool rendering.
1358
1398
 
1359
- - Fixed custom tools failing to load from `~/.omp/agent/tools/` when omp is installed globally. Module imports (`@sinclair/typebox`, `@oh-my-pi/pi-tui`, `@mariozechner/pi-ai`) are now resolved via aliases.
1399
+ - Fixed custom tools failing to load from `~/.omp/agent/tools/` when omp is installed globally. Module imports (`@sinclair/typebox`, `@oh-my-pi/pi-tui`, `@oh-my-pi/pi-ai`) are now resolved via aliases.
1360
1400
 
1361
1401
  ## [0.23.0] - 2025-12-17
1362
1402
 
@@ -1396,7 +1436,7 @@ Total color count increased from 46 to 50. See [docs/theme.md](docs/theme.md) fo
1396
1436
 
1397
1437
  - **Tool output display**: When collapsed, tool output now shows the last N lines instead of the first N lines, making streaming output more useful.
1398
1438
 
1399
- - Updated `@mariozechner/pi-ai` with X-Initiator header support for GitHub Copilot, ensuring agent calls are not deducted from quota. ([#200](https://github.com/badlogic/pi-mono/pull/200) by [@kim0](https://github.com/kim0))
1439
+ - Updated `@oh-my-pi/pi-ai` with X-Initiator header support for GitHub Copilot, ensuring agent calls are not deducted from quota. ([#200](https://github.com/badlogic/pi-mono/pull/200) by [@kim0](https://github.com/kim0))
1400
1440
 
1401
1441
  ### Fixed
1402
1442
 
@@ -1408,7 +1448,7 @@ Total color count increased from 46 to 50. See [docs/theme.md](docs/theme.md) fo
1408
1448
 
1409
1449
  ### Changed
1410
1450
 
1411
- - Updated `@mariozechner/pi-ai` with interleaved thinking enabled by default for Anthropic Claude 4 models.
1451
+ - Updated `@oh-my-pi/pi-ai` with interleaved thinking enabled by default for Anthropic Claude 4 models.
1412
1452
 
1413
1453
  ## [0.22.1] - 2025-12-15
1414
1454
 
@@ -1416,7 +1456,7 @@ _Dedicated to Peter's shoulder ([@steipete](https://twitter.com/steipete))_
1416
1456
 
1417
1457
  ### Changed
1418
1458
 
1419
- - Updated `@mariozechner/pi-ai` with interleaved thinking support for Anthropic models.
1459
+ - Updated `@oh-my-pi/pi-ai` with interleaved thinking support for Anthropic models.
1420
1460
 
1421
1461
  ## [0.22.0] - 2025-12-15
1422
1462
 
@@ -1914,4 +1954,4 @@ Initial public release.
1914
1954
  - Git branch display in footer
1915
1955
  - Message queueing during streaming responses
1916
1956
  - OAuth integration for Gmail and Google Calendar access
1917
- - HTML export with syntax highlighting and collapsible sections
1957
+ - HTML export with syntax highlighting and collapsible sections
package/README.md CHANGED
@@ -338,10 +338,22 @@ When disabled, neither case triggers automatic compaction (use `/compact` manual
338
338
  "enabled": true,
339
339
  "reserveTokens": 16384,
340
340
  "keepRecentTokens": 20000
341
+ },
342
+ "env": {
343
+ "ANTHROPIC_API_KEY": "sk-ant-...",
344
+ "OPENAI_API_KEY": "sk-proj-...",
345
+ "GEMINI_API_KEY": "AIzaSyD...",
346
+ "CUSTOM_VAR": "custom-value"
341
347
  }
342
348
  }
343
349
  ```
344
350
 
351
+ **Environment Variables (`env`):**
352
+ - Automatically sets environment variables when the application starts
353
+ - Only sets variables that aren't already present in `process.env`
354
+ - Supports any environment variable, not just API keys
355
+ - Order of precedence: existing env vars > settings.json env vars > auth.json env vars
356
+
345
357
  > **Note:** Compaction is lossy. The agent loses full conversation access afterward. Size tasks to avoid context limits when possible. For critical context, ask the agent to write a summary to a file, iterate on it until it covers everything, then start a new session with that file. The full session history is preserved in the JSONL file; use `/tree` to revisit any previous point.
346
358
 
347
359
  See [docs/compaction.md](docs/compaction.md) for how compaction works internally and how to customize it via hooks.
@@ -94,7 +94,7 @@ Custom tools can import from these packages:
94
94
  | --------------------------- | --------------------------------------------------------- | --------------------------------------------------- |
95
95
  | `@sinclair/typebox` | Schema definitions (`Type.Object`, `Type.String`, etc.) | Via `pi.typebox.*` (injected) |
96
96
  | `@oh-my-pi/pi-coding-agent` | Types and utilities | Via `pi.pi.*` (injected) or direct import for types |
97
- | `@mariozechner/pi-ai` | AI utilities (`StringEnum` for Google-compatible enums) | Via `pi.pi.*` (re-exported through coding-agent) |
97
+ | `@oh-my-pi/pi-ai` | AI utilities (`StringEnum` for Google-compatible enums) | Via `pi.pi.*` (re-exported through coding-agent) |
98
98
  | `@oh-my-pi/pi-tui` | TUI components (`Text`, `Box`, etc. for custom rendering) | Via `pi.pi.*` (re-exported through coding-agent) |
99
99
 
100
100
  Node.js built-in modules (`node:fs`, `node:path`, etc.) are also available.
@@ -167,7 +167,7 @@ The `package.json` approach enables:
167
167
  | --------------------------- | ------------------------------------------------------------ |
168
168
  | `@oh-my-pi/pi-coding-agent` | Extension types (`ExtensionAPI`, `ExtensionContext`, events) |
169
169
  | `@sinclair/typebox` | Schema definitions for tool parameters |
170
- | `@mariozechner/pi-ai` | AI utilities (`StringEnum` for Google-compatible enums) |
170
+ | `@oh-my-pi/pi-ai` | AI utilities (`StringEnum` for Google-compatible enums) |
171
171
  | `@oh-my-pi/pi-tui` | TUI components for custom rendering |
172
172
 
173
173
  npm dependencies work too. Add a `package.json` next to your extension (or in a parent directory), run `npm install`, and imports from `node_modules/` are resolved automatically.
@@ -608,7 +608,7 @@ Register a custom tool callable by the LLM. See [Custom Tools](#custom-tools) fo
608
608
 
609
609
  ```typescript
610
610
  import { Type } from "@sinclair/typebox";
611
- import { StringEnum } from "@mariozechner/pi-ai";
611
+ import { StringEnum } from "@oh-my-pi/pi-ai";
612
612
 
613
613
  pi.registerTool({
614
614
  name: "my_tool",
@@ -793,7 +793,7 @@ Register tools the LLM can call via `pi.registerTool()`. Tools appear in the sys
793
793
 
794
794
  ```typescript
795
795
  import { Type } from "@sinclair/typebox";
796
- import { StringEnum } from "@mariozechner/pi-ai";
796
+ import { StringEnum } from "@oh-my-pi/pi-ai";
797
797
  import { Text } from "@oh-my-pi/pi-tui";
798
798
 
799
799
  pi.registerTool({
@@ -833,7 +833,7 @@ pi.registerTool({
833
833
  });
834
834
  ```
835
835
 
836
- **Important:** Use `StringEnum` from `@mariozechner/pi-ai` for string enums. `Type.Union`/`Type.Literal` doesn't work with Google's API.
836
+ **Important:** Use `StringEnum` from `@oh-my-pi/pi-ai` for string enums. `Type.Union`/`Type.Literal` doesn't work with Google's API.
837
837
 
838
838
  ### Multiple Tools
839
839
 
package/docs/hooks.md CHANGED
@@ -72,7 +72,7 @@ Additional paths via `settings.json`:
72
72
  | --------------------------------- | --------------------------------------------- |
73
73
  | `@oh-my-pi/pi-coding-agent/hooks` | Hook types (`HookAPI`, `HookContext`, events) |
74
74
  | `@oh-my-pi/pi-coding-agent` | Additional types if needed |
75
- | `@mariozechner/pi-ai` | AI utilities |
75
+ | `@oh-my-pi/pi-ai` | AI utilities |
76
76
  | `@oh-my-pi/pi-tui` | TUI components |
77
77
 
78
78
  Node.js built-ins (`node:fs`, `node:path`, etc.) are also available.
@@ -548,7 +548,7 @@ Current model, or `undefined` if none selected yet. Use for LLM calls in hooks:
548
548
  ```typescript
549
549
  if (ctx.model) {
550
550
  const apiKey = await ctx.modelRegistry.getApiKey(ctx.model);
551
- // Use with @mariozechner/pi-ai complete()
551
+ // Use with @oh-my-pi/pi-ai complete()
552
552
  }
553
553
  ```
554
554
 
package/docs/sdk.md CHANGED
@@ -248,7 +248,7 @@ const { session } = await createAgentSession({
248
248
  ### Model
249
249
 
250
250
  ```typescript
251
- import { getModel } from "@mariozechner/pi-ai";
251
+ import { getModel } from "@oh-my-pi/pi-ai";
252
252
  import { discoverAuthStorage, discoverModels } from "@oh-my-pi/pi-coding-agent";
253
253
 
254
254
  const authStorage = discoverAuthStorage();
@@ -385,11 +385,7 @@ All tools are defined in `BUILTIN_TOOLS`:
385
385
  For advanced use cases, you can create tools directly using `createTools`:
386
386
 
387
387
  ```typescript
388
- import {
389
- BUILTIN_TOOLS,
390
- createTools,
391
- type ToolSession,
392
- } from "@oh-my-pi/pi-coding-agent";
388
+ import { BUILTIN_TOOLS, createTools, type ToolSession } from "@oh-my-pi/pi-coding-agent";
393
389
 
394
390
  const session: ToolSession = {
395
391
  cwd: "/path/to/project",
@@ -733,7 +729,7 @@ Project overrides global. Nested objects merge keys. Setters only modify global
733
729
  All discovery functions accept optional `cwd` and `agentDir` parameters.
734
730
 
735
731
  ```typescript
736
- import { getModel } from "@mariozechner/pi-ai";
732
+ import { getModel } from "@oh-my-pi/pi-ai";
737
733
  import {
738
734
  AuthStorage,
739
735
  ModelRegistry,
@@ -806,7 +802,7 @@ interface CreateAgentSessionResult {
806
802
  ## Complete Example
807
803
 
808
804
  ```typescript
809
- import { getModel } from "@mariozechner/pi-ai";
805
+ import { getModel } from "@oh-my-pi/pi-ai";
810
806
  import { Type } from "@sinclair/typebox";
811
807
  import {
812
808
  AuthStorage,
@@ -48,7 +48,7 @@ See [docs/custom-tools.md](../../docs/custom-tools.md) for full documentation.
48
48
 
49
49
  ```typescript
50
50
  import { Type } from "@sinclair/typebox";
51
- import { StringEnum } from "@mariozechner/pi-ai";
51
+ import { StringEnum } from "@oh-my-pi/pi-ai";
52
52
  import { Text } from "@oh-my-pi/pi-tui";
53
53
  import type { CustomToolFactory } from "@oh-my-pi/pi-coding-agent";
54
54
 
@@ -99,7 +99,7 @@ renderResult(result, { expanded, isPartial }, theme) {
99
99
  **Use StringEnum for string parameters** (required for Google API compatibility):
100
100
 
101
101
  ```typescript
102
- import { StringEnum } from "@mariozechner/pi-ai";
102
+ import { StringEnum } from "@oh-my-pi/pi-ai";
103
103
 
104
104
  // Good
105
105
  action: StringEnum(["list", "add"] as const);
@@ -113,7 +113,7 @@ export default function (pi: ExtensionAPI) {
113
113
  **Use StringEnum for string parameters** (required for Google API compatibility):
114
114
 
115
115
  ```typescript
116
- import { StringEnum } from "@mariozechner/pi-ai";
116
+ import { StringEnum } from "@oh-my-pi/pi-ai";
117
117
 
118
118
  // Good
119
119
  action: StringEnum(["list", "add"] as const);
@@ -10,7 +10,7 @@
10
10
  * correct for that point in history.
11
11
  */
12
12
 
13
- import { StringEnum } from "@mariozechner/pi-ai";
13
+ import { StringEnum } from "@oh-my-pi/pi-ai";
14
14
  import type { ExtensionAPI, ExtensionContext, Theme } from "@oh-my-pi/pi-coding-agent";
15
15
  import { matchesKey, Text, truncateToWidth } from "@oh-my-pi/pi-tui";
16
16
  import { Type } from "@sinclair/typebox";
@@ -13,7 +13,7 @@
13
13
  * omp --hook examples/hooks/custom-compaction.ts
14
14
  */
15
15
 
16
- import { complete, getModel } from "@mariozechner/pi-ai";
16
+ import { complete, getModel } from "@oh-my-pi/pi-ai";
17
17
  import type { HookAPI } from "@oh-my-pi/pi-coding-agent";
18
18
  import { convertToLlm, serializeConversation } from "@oh-my-pi/pi-coding-agent";
19
19
 
@@ -42,7 +42,9 @@ export default function (pi: HookAPI) {
42
42
  const allMessages = [...messagesToSummarize, ...turnPrefixMessages];
43
43
 
44
44
  ctx.ui.notify(
45
- `Custom compaction: summarizing ${allMessages.length} messages (${tokensBefore.toLocaleString()} tokens) with ${model.id}...`,
45
+ `Custom compaction: summarizing ${allMessages.length} messages (${tokensBefore.toLocaleString()} tokens) with ${
46
+ model.id
47
+ }...`,
46
48
  "info",
47
49
  );
48
50
 
@@ -12,7 +12,7 @@
12
12
  * The generated prompt appears as a draft in the editor for review/editing.
13
13
  */
14
14
 
15
- import { complete, type Message } from "@mariozechner/pi-ai";
15
+ import { complete, type Message } from "@oh-my-pi/pi-ai";
16
16
  import type { HookAPI, SessionEntry } from "@oh-my-pi/pi-coding-agent";
17
17
  import { BorderedLoader, convertToLlm, serializeConversation } from "@oh-my-pi/pi-coding-agent";
18
18
 
@@ -7,7 +7,7 @@
7
7
  * 3. Loads the result into the editor for user to fill in answers
8
8
  */
9
9
 
10
- import { complete, type UserMessage } from "@mariozechner/pi-ai";
10
+ import { complete, type UserMessage } from "@oh-my-pi/pi-ai";
11
11
  import type { HookAPI } from "@oh-my-pi/pi-coding-agent";
12
12
  import { BorderedLoader } from "@oh-my-pi/pi-coding-agent";
13
13
 
@@ -4,7 +4,7 @@
4
4
  * Shows how to select a specific model and thinking level.
5
5
  */
6
6
 
7
- import { getModel } from "@mariozechner/pi-ai";
7
+ import { getModel } from "@oh-my-pi/pi-ai";
8
8
  import { createAgentSession, discoverAuthStorage, discoverModels } from "@oh-my-pi/pi-coding-agent";
9
9
 
10
10
  // Set up auth storage and model registry
@@ -29,7 +29,7 @@ npx tsx examples/sdk/01-minimal.ts
29
29
  ## Quick Reference
30
30
 
31
31
  ```typescript
32
- import { getModel } from "@mariozechner/pi-ai";
32
+ import { getModel } from "@oh-my-pi/pi-ai";
33
33
  import {
34
34
  AuthStorage,
35
35
  createAgentSession,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oh-my-pi/pi-coding-agent",
3
- "version": "3.32.0",
3
+ "version": "3.34.0",
4
4
  "description": "Coding agent CLI with read, bash, edit, write tools and session management",
5
5
  "type": "module",
6
6
  "ompConfig": {
@@ -39,10 +39,10 @@
39
39
  "prepublishOnly": "bun run generate-template && bun run clean && bun run build"
40
40
  },
41
41
  "dependencies": {
42
- "@mariozechner/pi-ai": "^0.37.8",
43
- "@oh-my-pi/pi-agent-core": "3.32.0",
44
- "@oh-my-pi/pi-git-tool": "3.32.0",
45
- "@oh-my-pi/pi-tui": "3.32.0",
42
+ "@oh-my-pi/pi-ai": "3.34.0",
43
+ "@oh-my-pi/pi-agent-core": "3.34.0",
44
+ "@oh-my-pi/pi-git-tool": "3.34.0",
45
+ "@oh-my-pi/pi-tui": "3.34.0",
46
46
  "@openai/agents": "^0.3.7",
47
47
  "@sinclair/typebox": "^0.34.46",
48
48
  "ajv": "^8.17.1",
@@ -0,0 +1,42 @@
1
+ /**
2
+ * SSH Hosts Capability
3
+ *
4
+ * Canonical shape for SSH host entries, regardless of source format.
5
+ */
6
+
7
+ import { defineCapability } from "./index";
8
+ import type { SourceMeta } from "./types";
9
+
10
+ /**
11
+ * Canonical SSH host entry.
12
+ */
13
+ export interface SSHHost {
14
+ /** Host name (config key) */
15
+ name: string;
16
+ /** Host address or DNS name */
17
+ host: string;
18
+ /** Optional username override */
19
+ username?: string;
20
+ /** Optional port override */
21
+ port?: number;
22
+ /** Optional identity key path */
23
+ keyPath?: string;
24
+ /** Optional host description */
25
+ description?: string;
26
+ /** Optional compatibility mode flag */
27
+ compat?: boolean;
28
+ /** Source metadata (added by loader) */
29
+ _source: SourceMeta;
30
+ }
31
+
32
+ export const sshCapability = defineCapability<SSHHost>({
33
+ id: "ssh",
34
+ displayName: "SSH Hosts",
35
+ description: "SSH host entries for remote command execution",
36
+ key: (host) => host.name,
37
+ validate: (host) => {
38
+ if (!host.name) return "Missing name";
39
+ if (!host.host) return "Missing host";
40
+ return undefined;
41
+ },
42
+ });
@@ -4,7 +4,7 @@
4
4
 
5
5
  import { existsSync, readFileSync, statSync } from "node:fs";
6
6
  import { resolve } from "node:path";
7
- import type { ImageContent } from "@mariozechner/pi-ai";
7
+ import type { ImageContent } from "@oh-my-pi/pi-ai";
8
8
  import chalk from "chalk";
9
9
  import { resolveReadPath } from "../core/tools/path-utils";
10
10
  import { formatDimensionNote, resizeImage } from "../utils/image-resize";
@@ -2,7 +2,7 @@
2
2
  * List available models with optional fuzzy search
3
3
  */
4
4
 
5
- import type { Api, Model } from "@mariozechner/pi-ai";
5
+ import type { Api, Model } from "@oh-my-pi/pi-ai";
6
6
  import type { ModelRegistry } from "../core/model-registry";
7
7
  import { fuzzyFilter } from "../utils/fuzzy";
8
8
 
@@ -13,9 +13,9 @@
13
13
  * Modes use this class and add their own I/O layer on top.
14
14
  */
15
15
 
16
- import type { AssistantMessage, ImageContent, Message, Model, TextContent, Usage } from "@mariozechner/pi-ai";
17
- import { isContextOverflow, modelsAreEqual, supportsXhigh } from "@mariozechner/pi-ai";
18
16
  import type { Agent, AgentEvent, AgentMessage, AgentState, AgentTool, ThinkingLevel } from "@oh-my-pi/pi-agent-core";
17
+ import type { AssistantMessage, ImageContent, Message, Model, TextContent, Usage } from "@oh-my-pi/pi-ai";
18
+ import { isContextOverflow, modelsAreEqual, supportsXhigh } from "@oh-my-pi/pi-ai";
19
19
  import type { Rule } from "../capability/rule";
20
20
  import { getAuthPath } from "../config";
21
21
  import { theme } from "../modes/interactive/theme/theme";
@@ -45,6 +45,7 @@ import type {
45
45
  } from "./extensions";
46
46
  import { extractFileMentions, generateFileMentionMessages } from "./file-mentions";
47
47
  import type { HookCommandContext } from "./hooks/types";
48
+ import { logger } from "./logger";
48
49
  import type { BashExecutionMessage, CustomMessage } from "./messages";
49
50
  import type { ModelRegistry } from "./model-registry";
50
51
  import { parseModelString } from "./model-resolver";
@@ -52,6 +53,8 @@ import { expandPromptTemplate, type PromptTemplate, parseCommandArgs } from "./p
52
53
  import type { BranchSummaryEntry, CompactionEntry, NewSessionOptions, SessionManager } from "./session-manager";
53
54
  import type { SettingsManager, SkillsSettings } from "./settings-manager";
54
55
  import { expandSlashCommand, type FileSlashCommand } from "./slash-commands";
56
+ import { closeAllConnections } from "./ssh/connection-manager";
57
+ import { unmountAll } from "./ssh/sshfs-mount";
55
58
  import type { TtsrManager } from "./ttsr";
56
59
 
57
60
  /** Session-specific events that extend the core AgentEvent */
@@ -167,6 +170,15 @@ const noOpUIContext: ExtensionUIContext = {
167
170
  },
168
171
  };
169
172
 
173
+ async function cleanupSshResources(): Promise<void> {
174
+ const results = await Promise.allSettled([closeAllConnections(), unmountAll()]);
175
+ for (const result of results) {
176
+ if (result.status === "rejected") {
177
+ logger.warn("SSH cleanup failed", { error: String(result.reason) });
178
+ }
179
+ }
180
+ }
181
+
170
182
  // ============================================================================
171
183
  // AgentSession Class
172
184
  // ============================================================================
@@ -377,7 +389,8 @@ export class AgentSession {
377
389
  } else if (
378
390
  event.message.role === "user" ||
379
391
  event.message.role === "assistant" ||
380
- event.message.role === "toolResult"
392
+ event.message.role === "toolResult" ||
393
+ event.message.role === "fileMention"
381
394
  ) {
382
395
  // Regular LLM message - persist as SessionMessageEntry
383
396
  this.sessionManager.appendMessage(event.message);
@@ -533,6 +546,7 @@ export class AgentSession {
533
546
  */
534
547
  async dispose(): Promise<void> {
535
548
  await this.sessionManager.flush();
549
+ await cleanupSshResources();
536
550
  this._disconnectFromAgent();
537
551
  this._eventListeners = [];
538
552
  }
@@ -2471,9 +2485,10 @@ export class AgentSession {
2471
2485
  * Emit a custom tool session event (backwards compatibility for older callers).
2472
2486
  */
2473
2487
  async emitCustomToolSessionEvent(reason: "start" | "switch" | "branch" | "tree" | "shutdown"): Promise<void> {
2474
- if (!this._extensionRunner) return;
2475
2488
  if (reason !== "shutdown") return;
2476
- if (!this._extensionRunner.hasHandlers("session_shutdown")) return;
2477
- await this._extensionRunner.emit({ type: "session_shutdown" });
2489
+ if (this._extensionRunner?.hasHandlers("session_shutdown")) {
2490
+ await this._extensionRunner.emit({ type: "session_shutdown" });
2491
+ }
2492
+ await cleanupSshResources();
2478
2493
  }
2479
2494
  }
@@ -15,7 +15,7 @@ import {
15
15
  loginOpenAICodex,
16
16
  type OAuthCredentials,
17
17
  type OAuthProvider,
18
- } from "@mariozechner/pi-ai";
18
+ } from "@oh-my-pi/pi-ai";
19
19
  import { logger } from "./logger";
20
20
 
21
21
  export type ApiKeyCredential = {
@@ -5,9 +5,9 @@
5
5
  * a summary of the branch being left so context isn't lost.
6
6
  */
7
7
 
8
- import type { Model } from "@mariozechner/pi-ai";
9
- import { completeSimple } from "@mariozechner/pi-ai";
10
8
  import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
9
+ import type { Model } from "@oh-my-pi/pi-ai";
10
+ import { completeSimple } from "@oh-my-pi/pi-ai";
11
11
  import branchSummaryPrompt from "../../prompts/branch-summary.md" with { type: "text" };
12
12
  import branchSummaryPreamble from "../../prompts/branch-summary-preamble.md" with { type: "text" };
13
13
  import {
@@ -5,9 +5,9 @@
5
5
  * and after compaction the session is reloaded.
6
6
  */
7
7
 
8
- import type { AssistantMessage, Model, Usage } from "@mariozechner/pi-ai";
9
- import { complete, completeSimple } from "@mariozechner/pi-ai";
10
8
  import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
9
+ import type { AssistantMessage, Model, Usage } from "@oh-my-pi/pi-ai";
10
+ import { complete, completeSimple } from "@oh-my-pi/pi-ai";
11
11
  import compactionSummaryPrompt from "../../prompts/compaction-summary.md" with { type: "text" };
12
12
  import compactionTurnPrefixPrompt from "../../prompts/compaction-turn-prefix.md" with { type: "text" };
13
13
  import compactionUpdateSummaryPrompt from "../../prompts/compaction-update-summary.md" with { type: "text" };
@@ -2,8 +2,8 @@
2
2
  * Shared utilities for compaction and branch summarization.
3
3
  */
4
4
 
5
- import type { Message } from "@mariozechner/pi-ai";
6
5
  import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
6
+ import type { Message } from "@oh-my-pi/pi-ai";
7
7
  import summarizationSystemPrompt from "../../prompts/summarization-system.md" with { type: "text" };
8
8
 
9
9
  // ============================================================================
@@ -5,8 +5,8 @@
5
5
  * They can provide custom rendering for tool calls and results in the TUI.
6
6
  */
7
7
 
8
- import type { Model } from "@mariozechner/pi-ai";
9
8
  import type { AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
9
+ import type { Model } from "@oh-my-pi/pi-ai";
10
10
  import type { Component } from "@oh-my-pi/pi-tui";
11
11
  import type { Static, TSchema } from "@sinclair/typebox";
12
12
  import type { Theme } from "../../modes/interactive/theme/theme";
@@ -2,8 +2,8 @@
2
2
  * Extension runner - executes extensions and manages their lifecycle.
3
3
  */
4
4
 
5
- import type { ImageContent, Model } from "@mariozechner/pi-ai";
6
5
  import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
6
+ import type { ImageContent, Model } from "@oh-my-pi/pi-ai";
7
7
  import type { KeyId } from "@oh-my-pi/pi-tui";
8
8
  import { theme } from "../../modes/interactive/theme/theme";
9
9
  import type { ModelRegistry } from "../model-registry";
@@ -8,8 +8,8 @@
8
8
  * - Interact with the user via UI primitives
9
9
  */
10
10
 
11
- import type { ImageContent, Model, TextContent, ToolResultMessage } from "@mariozechner/pi-ai";
12
11
  import type { AgentMessage, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
12
+ import type { ImageContent, Model, TextContent, ToolResultMessage } from "@oh-my-pi/pi-ai";
13
13
  import type { Component, KeyId, TUI } from "@oh-my-pi/pi-tui";
14
14
  import type { Static, TSchema } from "@sinclair/typebox";
15
15
  import type { Theme } from "../../modes/interactive/theme/theme";
@@ -2,8 +2,8 @@
2
2
  * Tool wrappers for extensions.
3
3
  */
4
4
 
5
- import type { ImageContent, TextContent } from "@mariozechner/pi-ai";
6
5
  import type { AgentTool, AgentToolContext, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
6
+ import type { ImageContent, TextContent } from "@oh-my-pi/pi-ai";
7
7
  import type { Theme } from "../../modes/interactive/theme/theme";
8
8
  import type { ExtensionRunner } from "./runner";
9
9
  import type { ExtensionContext, RegisteredTool, ToolCallEventResult, ToolResultEventResult } from "./types";