@oh-my-pi/pi-coding-agent 3.20.0 → 3.21.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 (95) hide show
  1. package/CHANGELOG.md +78 -8
  2. package/docs/custom-tools.md +3 -3
  3. package/docs/extensions.md +226 -220
  4. package/docs/hooks.md +2 -2
  5. package/docs/sdk.md +3 -3
  6. package/examples/custom-tools/README.md +2 -2
  7. package/examples/custom-tools/subagent/index.ts +1 -1
  8. package/examples/extensions/README.md +76 -74
  9. package/examples/extensions/todo.ts +2 -5
  10. package/examples/hooks/custom-compaction.ts +1 -1
  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/12-full-control.ts +1 -1
  15. package/examples/sdk/README.md +1 -1
  16. package/package.json +5 -5
  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 +13 -2
  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/hooks/runner.ts +2 -2
  29. package/src/core/hooks/types.ts +1 -1
  30. package/src/core/messages.ts +1 -1
  31. package/src/core/model-registry.ts +1 -1
  32. package/src/core/model-resolver.ts +1 -1
  33. package/src/core/sdk.ts +33 -4
  34. package/src/core/session-manager.ts +11 -22
  35. package/src/core/settings-manager.ts +66 -1
  36. package/src/core/slash-commands.ts +12 -5
  37. package/src/core/system-prompt.ts +27 -3
  38. package/src/core/title-generator.ts +2 -2
  39. package/src/core/tools/ask.ts +88 -1
  40. package/src/core/tools/bash-interceptor.ts +7 -0
  41. package/src/core/tools/bash.ts +106 -0
  42. package/src/core/tools/edit-diff.ts +73 -24
  43. package/src/core/tools/edit.ts +214 -20
  44. package/src/core/tools/find.ts +162 -1
  45. package/src/core/tools/gemini-image.ts +279 -56
  46. package/src/core/tools/git.ts +4 -0
  47. package/src/core/tools/grep.ts +191 -0
  48. package/src/core/tools/index.ts +3 -6
  49. package/src/core/tools/ls.ts +142 -2
  50. package/src/core/tools/lsp/render.ts +34 -14
  51. package/src/core/tools/notebook.ts +110 -0
  52. package/src/core/tools/output.ts +179 -7
  53. package/src/core/tools/read.ts +122 -9
  54. package/src/core/tools/render-utils.ts +241 -0
  55. package/src/core/tools/renderers.ts +40 -828
  56. package/src/core/tools/review.ts +26 -7
  57. package/src/core/tools/rulebook.ts +3 -1
  58. package/src/core/tools/task/index.ts +18 -3
  59. package/src/core/tools/task/render.ts +7 -2
  60. package/src/core/tools/task/types.ts +1 -1
  61. package/src/core/tools/truncate.ts +27 -1
  62. package/src/core/tools/web-fetch.ts +23 -15
  63. package/src/core/tools/web-search/index.ts +130 -45
  64. package/src/core/tools/web-search/providers/anthropic.ts +7 -2
  65. package/src/core/tools/web-search/providers/exa.ts +2 -1
  66. package/src/core/tools/web-search/providers/perplexity.ts +6 -1
  67. package/src/core/tools/web-search/render.ts +5 -0
  68. package/src/core/tools/web-search/types.ts +13 -0
  69. package/src/core/tools/write.ts +90 -0
  70. package/src/core/voice.ts +1 -1
  71. package/src/lib/worktree/constants.ts +6 -6
  72. package/src/main.ts +1 -1
  73. package/src/modes/interactive/components/assistant-message.ts +1 -1
  74. package/src/modes/interactive/components/custom-message.ts +1 -1
  75. package/src/modes/interactive/components/extensions/inspector-panel.ts +25 -22
  76. package/src/modes/interactive/components/extensions/state-manager.ts +12 -0
  77. package/src/modes/interactive/components/footer.ts +1 -1
  78. package/src/modes/interactive/components/hook-message.ts +1 -1
  79. package/src/modes/interactive/components/model-selector.ts +1 -1
  80. package/src/modes/interactive/components/oauth-selector.ts +1 -1
  81. package/src/modes/interactive/components/settings-defs.ts +49 -0
  82. package/src/modes/interactive/components/status-line.ts +1 -1
  83. package/src/modes/interactive/components/tool-execution.ts +93 -538
  84. package/src/modes/interactive/interactive-mode.ts +19 -7
  85. package/src/modes/print-mode.ts +1 -1
  86. package/src/modes/rpc/rpc-client.ts +1 -1
  87. package/src/modes/rpc/rpc-types.ts +1 -1
  88. package/src/prompts/system-prompt.md +4 -0
  89. package/src/prompts/tools/gemini-image.md +5 -1
  90. package/src/prompts/tools/output.md +4 -0
  91. package/src/prompts/tools/web-fetch.md +1 -0
  92. package/src/prompts/tools/web-search.md +2 -0
  93. package/src/utils/image-convert.ts +8 -2
  94. package/src/utils/image-magick.ts +247 -0
  95. package/src/utils/image-resize.ts +53 -13
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
- | `@oh-my-pi/pi-ai` | AI utilities |
75
+ | `@mariozechner/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 @oh-my-pi/pi-ai complete()
551
+ // Use with @mariozechner/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 "@oh-my-pi/pi-ai";
251
+ import { getModel } from "@mariozechner/pi-ai";
252
252
  import { discoverAuthStorage, discoverModels } from "@oh-my-pi/pi-coding-agent";
253
253
 
254
254
  const authStorage = discoverAuthStorage();
@@ -733,7 +733,7 @@ Project overrides global. Nested objects merge keys. Setters only modify global
733
733
  All discovery functions accept optional `cwd` and `agentDir` parameters.
734
734
 
735
735
  ```typescript
736
- import { getModel } from "@oh-my-pi/pi-ai";
736
+ import { getModel } from "@mariozechner/pi-ai";
737
737
  import {
738
738
  AuthStorage,
739
739
  ModelRegistry,
@@ -806,7 +806,7 @@ interface CreateAgentSessionResult {
806
806
  ## Complete Example
807
807
 
808
808
  ```typescript
809
- import { getModel } from "@oh-my-pi/pi-ai";
809
+ import { getModel } from "@mariozechner/pi-ai";
810
810
  import { Type } from "@sinclair/typebox";
811
811
  import {
812
812
  AuthStorage,
@@ -63,7 +63,7 @@ See [docs/custom-tools.md](../../docs/custom-tools.md) for full documentation.
63
63
 
64
64
  ```typescript
65
65
  import { Type } from "@sinclair/typebox";
66
- import { StringEnum } from "@oh-my-pi/pi-ai";
66
+ import { StringEnum } from "@mariozechner/pi-ai";
67
67
  import { Text } from "@oh-my-pi/pi-tui";
68
68
  import type { CustomToolFactory } from "@oh-my-pi/pi-coding-agent";
69
69
 
@@ -114,7 +114,7 @@ renderResult(result, { expanded, isPartial }, theme) {
114
114
  **Use StringEnum for string parameters** (required for Google API compatibility):
115
115
 
116
116
  ```typescript
117
- import { StringEnum } from "@oh-my-pi/pi-ai";
117
+ import { StringEnum } from "@mariozechner/pi-ai";
118
118
 
119
119
  // Good
120
120
  action: StringEnum(["list", "add"] as const);
@@ -15,8 +15,8 @@
15
15
  import * as fs from "node:fs";
16
16
  import * as os from "node:os";
17
17
  import * as path from "node:path";
18
+ import type { Message } from "@mariozechner/pi-ai";
18
19
  import type { AgentToolResult } from "@oh-my-pi/pi-agent-core";
19
- import type { Message } from "@oh-my-pi/pi-ai";
20
20
  import type { CustomTool, CustomToolAPI, CustomToolFactory } from "@oh-my-pi/pi-coding-agent";
21
21
  import { type AgentConfig, type AgentScope, discoverAgents, formatAgentList } from "./agents";
22
22
 
@@ -16,54 +16,54 @@ cp permission-gate.ts ~/.omp/agent/extensions/
16
16
 
17
17
  ### Lifecycle & Safety
18
18
 
19
- | Extension | Description |
20
- |-----------|-------------|
21
- | `permission-gate.ts` | Prompts for confirmation before dangerous bash commands (rm -rf, sudo, etc.) |
22
- | `protected-paths.ts` | Blocks writes to protected paths (.env, .git/, node_modules/) |
23
- | `confirm-destructive.ts` | Confirms before destructive session actions (clear, switch, branch) |
24
- | `dirty-repo-guard.ts` | Prevents session changes with uncommitted git changes |
19
+ | Extension | Description |
20
+ | ------------------------ | ---------------------------------------------------------------------------- |
21
+ | `permission-gate.ts` | Prompts for confirmation before dangerous bash commands (rm -rf, sudo, etc.) |
22
+ | `protected-paths.ts` | Blocks writes to protected paths (.env, .git/, node_modules/) |
23
+ | `confirm-destructive.ts` | Confirms before destructive session actions (clear, switch, branch) |
24
+ | `dirty-repo-guard.ts` | Prevents session changes with uncommitted git changes |
25
25
 
26
26
  ### Custom Tools
27
27
 
28
- | Extension | Description |
29
- |-----------|-------------|
30
- | `todo.ts` | Todo list tool + `/todos` command with custom rendering and state persistence |
31
- | `hello.ts` | Minimal custom tool example |
32
- | `question.ts` | Demonstrates `ctx.ui.select()` for asking the user questions |
33
- | `subagent/` | Delegate tasks to specialized subagents with isolated context windows |
28
+ | Extension | Description |
29
+ | ------------- | ----------------------------------------------------------------------------- |
30
+ | `todo.ts` | Todo list tool + `/todos` command with custom rendering and state persistence |
31
+ | `hello.ts` | Minimal custom tool example |
32
+ | `question.ts` | Demonstrates `ctx.ui.select()` for asking the user questions |
33
+ | `subagent/` | Delegate tasks to specialized subagents with isolated context windows |
34
34
 
35
35
  ### Commands & UI
36
36
 
37
- | Extension | Description |
38
- |-----------|-------------|
39
- | `plan-mode.ts` | Claude Code-style plan mode for read-only exploration with `/plan` command |
40
- | `tools.ts` | Interactive `/tools` command to enable/disable tools with session persistence |
41
- | `handoff.ts` | Transfer context to a new focused session via `/handoff <goal>` |
42
- | `qna.ts` | Extracts questions from last response into editor via `ctx.ui.setEditorText()` |
43
- | `status-line.ts` | Shows turn progress in footer via `ctx.ui.setStatus()` with themed colors |
44
- | `snake.ts` | Snake game with custom UI, keyboard handling, and session persistence |
37
+ | Extension | Description |
38
+ | ---------------- | ------------------------------------------------------------------------------ |
39
+ | `plan-mode.ts` | Claude Code-style plan mode for read-only exploration with `/plan` command |
40
+ | `tools.ts` | Interactive `/tools` command to enable/disable tools with session persistence |
41
+ | `handoff.ts` | Transfer context to a new focused session via `/handoff <goal>` |
42
+ | `qna.ts` | Extracts questions from last response into editor via `ctx.ui.setEditorText()` |
43
+ | `status-line.ts` | Shows turn progress in footer via `ctx.ui.setStatus()` with themed colors |
44
+ | `snake.ts` | Snake game with custom UI, keyboard handling, and session persistence |
45
45
 
46
46
  ### Git Integration
47
47
 
48
- | Extension | Description |
49
- |-----------|-------------|
50
- | `git-checkpoint.ts` | Creates git stash checkpoints at each turn for code restoration on branch |
51
- | `auto-commit-on-exit.ts` | Auto-commits on exit using last assistant message for commit message |
48
+ | Extension | Description |
49
+ | ------------------------ | ------------------------------------------------------------------------- |
50
+ | `git-checkpoint.ts` | Creates git stash checkpoints at each turn for code restoration on branch |
51
+ | `auto-commit-on-exit.ts` | Auto-commits on exit using last assistant message for commit message |
52
52
 
53
53
  ### System Prompt & Compaction
54
54
 
55
- | Extension | Description |
56
- |-----------|-------------|
57
- | `pirate.ts` | Demonstrates `systemPromptAppend` to dynamically modify system prompt |
58
- | `custom-compaction.ts` | Custom compaction that summarizes entire conversation |
55
+ | Extension | Description |
56
+ | ---------------------- | --------------------------------------------------------------------- |
57
+ | `pirate.ts` | Demonstrates `systemPromptAppend` to dynamically modify system prompt |
58
+ | `custom-compaction.ts` | Custom compaction that summarizes entire conversation |
59
59
 
60
60
  ### External Dependencies
61
61
 
62
- | Extension | Description |
63
- |-----------|-------------|
62
+ | Extension | Description |
63
+ | ----------------- | ------------------------------------------------------------------------- |
64
64
  | `chalk-logger.ts` | Uses chalk from parent node_modules (demonstrates jiti module resolution) |
65
- | `with-deps/` | Extension with its own package.json and dependencies |
66
- | `file-trigger.ts` | Watches a trigger file and injects contents into conversation |
65
+ | `with-deps/` | Extension with its own package.json and dependencies |
66
+ | `file-trigger.ts` | Watches a trigger file and injects contents into conversation |
67
67
 
68
68
  ## Writing Extensions
69
69
 
@@ -74,68 +74,70 @@ import type { ExtensionAPI } from "@oh-my-pi/pi-coding-agent";
74
74
  import { Type } from "@sinclair/typebox";
75
75
 
76
76
  export default function (pi: ExtensionAPI) {
77
- // Subscribe to lifecycle events
78
- pi.on("tool_call", async (event, ctx) => {
79
- if (event.toolName === "bash" && event.input.command?.includes("rm -rf")) {
80
- const ok = await ctx.ui.confirm("Dangerous!", "Allow rm -rf?");
81
- if (!ok) return { block: true, reason: "Blocked by user" };
82
- }
83
- });
84
-
85
- // Register custom tools
86
- pi.registerTool({
87
- name: "greet",
88
- label: "Greeting",
89
- description: "Generate a greeting",
90
- parameters: Type.Object({
91
- name: Type.String({ description: "Name to greet" }),
92
- }),
93
- async execute(toolCallId, params, onUpdate, ctx, signal) {
94
- return {
95
- content: [{ type: "text", text: `Hello, ${params.name}!` }],
96
- details: {},
97
- };
98
- },
99
- });
100
-
101
- // Register commands
102
- pi.registerCommand("hello", {
103
- description: "Say hello",
104
- handler: async (args, ctx) => {
105
- ctx.ui.notify("Hello!", "info");
106
- },
107
- });
77
+ // Subscribe to lifecycle events
78
+ pi.on("tool_call", async (event, ctx) => {
79
+ if (event.toolName === "bash" && event.input.command?.includes("rm -rf")) {
80
+ const ok = await ctx.ui.confirm("Dangerous!", "Allow rm -rf?");
81
+ if (!ok) return { block: true, reason: "Blocked by user" };
82
+ }
83
+ });
84
+
85
+ // Register custom tools
86
+ pi.registerTool({
87
+ name: "greet",
88
+ label: "Greeting",
89
+ description: "Generate a greeting",
90
+ parameters: Type.Object({
91
+ name: Type.String({ description: "Name to greet" }),
92
+ }),
93
+ async execute(toolCallId, params, onUpdate, ctx, signal) {
94
+ return {
95
+ content: [{ type: "text", text: `Hello, ${params.name}!` }],
96
+ details: {},
97
+ };
98
+ },
99
+ });
100
+
101
+ // Register commands
102
+ pi.registerCommand("hello", {
103
+ description: "Say hello",
104
+ handler: async (args, ctx) => {
105
+ ctx.ui.notify("Hello!", "info");
106
+ },
107
+ });
108
108
  }
109
109
  ```
110
110
 
111
111
  ## Key Patterns
112
112
 
113
113
  **Use StringEnum for string parameters** (required for Google API compatibility):
114
+
114
115
  ```typescript
115
- import { StringEnum } from "@oh-my-pi/pi-ai";
116
+ import { StringEnum } from "@mariozechner/pi-ai";
116
117
 
117
118
  // Good
118
- action: StringEnum(["list", "add"] as const)
119
+ action: StringEnum(["list", "add"] as const);
119
120
 
120
121
  // Bad - doesn't work with Google
121
- action: Type.Union([Type.Literal("list"), Type.Literal("add")])
122
+ action: Type.Union([Type.Literal("list"), Type.Literal("add")]);
122
123
  ```
123
124
 
124
125
  **State persistence via details:**
126
+
125
127
  ```typescript
126
128
  // Store state in tool result details for proper branching support
127
129
  return {
128
- content: [{ type: "text", text: "Done" }],
129
- details: { todos: [...todos], nextId }, // Persisted in session
130
+ content: [{ type: "text", text: "Done" }],
131
+ details: { todos: [...todos], nextId }, // Persisted in session
130
132
  };
131
133
 
132
134
  // Reconstruct on session events
133
135
  pi.on("session_start", async (_event, ctx) => {
134
- for (const entry of ctx.sessionManager.getBranch()) {
135
- if (entry.type === "message" && entry.message.toolName === "my_tool") {
136
- const details = entry.message.details;
137
- // Reconstruct state from details
138
- }
139
- }
136
+ for (const entry of ctx.sessionManager.getBranch()) {
137
+ if (entry.type === "message" && entry.message.toolName === "my_tool") {
138
+ const details = entry.message.details;
139
+ // Reconstruct state from details
140
+ }
141
+ }
140
142
  });
141
143
  ```
@@ -10,7 +10,7 @@
10
10
  * correct for that point in history.
11
11
  */
12
12
 
13
- import { StringEnum } from "@oh-my-pi/pi-ai";
13
+ import { StringEnum } from "@mariozechner/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";
@@ -261,10 +261,7 @@ export default function (pi: ExtensionAPI) {
261
261
  case "add": {
262
262
  const added = todoList[todoList.length - 1];
263
263
  return new Text(
264
- theme.fg("success", "✓ Added ") +
265
- theme.fg("accent", `#${added.id}`) +
266
- " " +
267
- theme.fg("muted", added.text),
264
+ `${theme.fg("success", "✓ Added ") + theme.fg("accent", `#${added.id}`)} ${theme.fg("muted", added.text)}`,
268
265
  0,
269
266
  0,
270
267
  );
@@ -13,7 +13,7 @@
13
13
  * omp --hook examples/hooks/custom-compaction.ts
14
14
  */
15
15
 
16
- import { complete, getModel } from "@oh-my-pi/pi-ai";
16
+ import { complete, getModel } from "@mariozechner/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
 
@@ -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 "@oh-my-pi/pi-ai";
15
+ import { complete, type Message } from "@mariozechner/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 "@oh-my-pi/pi-ai";
10
+ import { complete, type UserMessage } from "@mariozechner/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 "@oh-my-pi/pi-ai";
7
+ import { getModel } from "@mariozechner/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
@@ -8,7 +8,7 @@
8
8
  * paths relative to your cwd.
9
9
  */
10
10
 
11
- import { getModel } from "@oh-my-pi/pi-ai";
11
+ import { getModel } from "@mariozechner/pi-ai";
12
12
  import {
13
13
  AuthStorage,
14
14
  type CustomTool,
@@ -29,7 +29,7 @@ npx tsx examples/sdk/01-minimal.ts
29
29
  ## Quick Reference
30
30
 
31
31
  ```typescript
32
- import { getModel } from "@oh-my-pi/pi-ai";
32
+ import { getModel } from "@mariozechner/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.20.0",
3
+ "version": "3.21.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
- "@oh-my-pi/pi-agent-core": "3.20.0",
43
- "@oh-my-pi/pi-ai": "3.20.0",
44
- "@oh-my-pi/pi-git-tool": "3.20.0",
45
- "@oh-my-pi/pi-tui": "3.20.0",
42
+ "@mariozechner/pi-ai": "^0.37.4",
43
+ "@oh-my-pi/pi-agent-core": "3.21.0",
44
+ "@oh-my-pi/pi-git-tool": "3.21.0",
45
+ "@oh-my-pi/pi-tui": "3.21.0",
46
46
  "@openai/agents": "^0.3.7",
47
47
  "@sinclair/typebox": "^0.34.46",
48
48
  "ajv": "^8.17.1",
@@ -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 "@oh-my-pi/pi-ai";
7
+ import type { ImageContent } from "@mariozechner/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 "@oh-my-pi/pi-ai";
5
+ import type { Api, Model } from "@mariozechner/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";
16
18
  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";
@@ -51,6 +51,7 @@ import { parseModelString } from "./model-resolver";
51
51
  import { expandPromptTemplate, type PromptTemplate, parseCommandArgs } from "./prompt-templates";
52
52
  import type { BranchSummaryEntry, CompactionEntry, NewSessionOptions, SessionManager } from "./session-manager";
53
53
  import type { SettingsManager, SkillsSettings } from "./settings-manager";
54
+ import { expandSlashCommand, type FileSlashCommand } from "./slash-commands";
54
55
  import type { TtsrManager } from "./ttsr";
55
56
 
56
57
  /** Session-specific events that extend the core AgentEvent */
@@ -77,6 +78,8 @@ export interface AgentSessionConfig {
77
78
  scopedModels?: Array<{ model: Model<any>; thinkingLevel: ThinkingLevel }>;
78
79
  /** Prompt templates for expansion */
79
80
  promptTemplates?: PromptTemplate[];
81
+ /** File-based slash commands for expansion */
82
+ slashCommands?: FileSlashCommand[];
80
83
  /** Extension runner (created in main.ts with wrapped tools) */
81
84
  extensionRunner?: ExtensionRunner;
82
85
  /** Custom commands (TypeScript slash commands) */
@@ -175,6 +178,7 @@ export class AgentSession {
175
178
 
176
179
  private _scopedModels: Array<{ model: Model<any>; thinkingLevel: ThinkingLevel }>;
177
180
  private _promptTemplates: PromptTemplate[];
181
+ private _slashCommands: FileSlashCommand[];
178
182
 
179
183
  // Event subscription state
180
184
  private _unsubscribeAgent?: () => void;
@@ -232,6 +236,7 @@ export class AgentSession {
232
236
  this.settingsManager = config.settingsManager;
233
237
  this._scopedModels = config.scopedModels ?? [];
234
238
  this._promptTemplates = config.promptTemplates ?? [];
239
+ this._slashCommands = config.slashCommands ?? [];
235
240
  this._extensionRunner = config.extensionRunner;
236
241
  this._customCommands = config.customCommands ?? [];
237
242
  this._skillsSettings = config.skillsSettings;
@@ -684,6 +689,12 @@ export class AgentSession {
684
689
  }
685
690
  text = customResult;
686
691
  }
692
+
693
+ // Try file-based slash commands (markdown files from commands/ directories)
694
+ // Only if text still starts with "/" (wasn't transformed by custom command)
695
+ if (text.startsWith("/")) {
696
+ text = expandSlashCommand(text, this._slashCommands);
697
+ }
687
698
  }
688
699
 
689
700
  // Expand file-based prompt templates if requested
@@ -15,7 +15,7 @@ import {
15
15
  loginOpenAICodex,
16
16
  type OAuthCredentials,
17
17
  type OAuthProvider,
18
- } from "@oh-my-pi/pi-ai";
18
+ } from "@mariozechner/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";
8
10
  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";
8
10
  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";
5
6
  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";
8
9
  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";
5
6
  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";
11
12
  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";
5
6
  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";
@@ -2,8 +2,8 @@
2
2
  * Hook runner - executes hooks and manages their lifecycle.
3
3
  */
4
4
 
5
+ import type { Model } from "@mariozechner/pi-ai";
5
6
  import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
6
- import type { Model } from "@oh-my-pi/pi-ai";
7
7
  import { theme } from "../../modes/interactive/theme/theme";
8
8
  import type { ModelRegistry } from "../model-registry";
9
9
  import type { SessionManager } from "../session-manager";
@@ -400,7 +400,7 @@ export class HookRunner {
400
400
  */
401
401
  async emitBeforeAgentStart(
402
402
  prompt: string,
403
- images?: import("@oh-my-pi/pi-ai").ImageContent[],
403
+ images?: import("@mariozechner/pi-ai").ImageContent[],
404
404
  ): Promise<BeforeAgentStartEventResult | undefined> {
405
405
  const ctx = this.createContext();
406
406
  let result: BeforeAgentStartEventResult | undefined;
@@ -5,8 +5,8 @@
5
5
  * and interact with the user via UI primitives.
6
6
  */
7
7
 
8
+ import type { ImageContent, Message, Model, TextContent, ToolResultMessage } from "@mariozechner/pi-ai";
8
9
  import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
9
- import type { ImageContent, Message, Model, TextContent, ToolResultMessage } from "@oh-my-pi/pi-ai";
10
10
  import type { Component, TUI } from "@oh-my-pi/pi-tui";
11
11
  import type { Theme } from "../../modes/interactive/theme/theme";
12
12
  import type { CompactionPreparation, CompactionResult } from "../compaction/index";
@@ -5,8 +5,8 @@
5
5
  * and provides a transformer to convert them to LLM-compatible messages.
6
6
  */
7
7
 
8
+ import type { ImageContent, Message, TextContent } from "@mariozechner/pi-ai";
8
9
  import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
9
- import type { ImageContent, Message, TextContent } from "@oh-my-pi/pi-ai";
10
10
 
11
11
  export const COMPACTION_SUMMARY_PREFIX = `The conversation history before this point was compacted into the following summary:
12
12
 
@@ -11,7 +11,7 @@ import {
11
11
  type KnownProvider,
12
12
  type Model,
13
13
  normalizeDomain,
14
- } from "@oh-my-pi/pi-ai";
14
+ } from "@mariozechner/pi-ai";
15
15
  import { type Static, Type } from "@sinclair/typebox";
16
16
  import AjvModule from "ajv";
17
17
  import type { AuthStorage } from "./auth-storage";
@@ -2,8 +2,8 @@
2
2
  * Model resolution, scoping, and initial selection
3
3
  */
4
4
 
5
+ import { type Api, type KnownProvider, type Model, modelsAreEqual } from "@mariozechner/pi-ai";
5
6
  import type { ThinkingLevel } from "@oh-my-pi/pi-agent-core";
6
- import { type Api, type KnownProvider, type Model, modelsAreEqual } from "@oh-my-pi/pi-ai";
7
7
  import chalk from "chalk";
8
8
  import { minimatch } from "minimatch";
9
9
  import { isValidThinkingLevel } from "../cli/args";