@oh-my-pi/pi-coding-agent 5.8.0 → 6.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -0
- package/README.md +70 -91
- package/docs/sdk.md +8 -8
- package/package.json +6 -7
- package/src/core/python-prelude.py +45 -2
- package/src/core/tools/lsp/client.ts +10 -2
- package/src/core/tools/lsp/defaults.json +2 -11
- package/src/core/tools/lsp/index.ts +11 -1
- package/src/core/tools/lsp/lspmux.ts +249 -0
- package/src/core/tools/task/executor.ts +57 -1
- package/src/core/tools/task/worker-protocol.ts +23 -2
- package/src/core/tools/task/worker.ts +139 -4
- package/src/modes/interactive/components/settings-defs.ts +11 -6
- package/src/modes/interactive/components/settings-selector.ts +1 -0
- package/scripts/generate-wasm-b64.ts +0 -13
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,33 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [6.1.0] - 2026-01-19
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Added lspmux integration for LSP server multiplexing to reduce startup time and memory usage
|
|
10
|
+
- Added LSP tool proxy support for subagent workers
|
|
11
|
+
- Updated LSP status command to show lspmux connection state
|
|
12
|
+
- Added maxdepth and mindepth parameters to find function for depth-controlled file search
|
|
13
|
+
- Added counter function to count occurrences and sort by frequency
|
|
14
|
+
- Added basenames function to extract base names from paths
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- Simplified rust-analyzer default configuration by removing custom initOptions and settings
|
|
19
|
+
|
|
20
|
+
## [6.0.0] - 2026-01-19
|
|
21
|
+
|
|
22
|
+
### Added
|
|
23
|
+
|
|
24
|
+
- Added Cursor and OpenAI Codex OAuth providers
|
|
25
|
+
- Added Windows installer bash shell auto-configuration
|
|
26
|
+
- Added dedicated TTSR settings tab (separated from Voice/TTS)
|
|
27
|
+
|
|
28
|
+
### Fixed
|
|
29
|
+
|
|
30
|
+
- Fixed TTSR abbreviation expansion from TTSR to Time Traveling Stream Rules
|
|
31
|
+
|
|
5
32
|
## [5.8.0] - 2026-01-19
|
|
6
33
|
### Changed
|
|
7
34
|
|
package/README.md
CHANGED
|
@@ -57,24 +57,23 @@ npm install -g @oh-my-pi/pi-coding-agent
|
|
|
57
57
|
|
|
58
58
|
**Standalone binary:**
|
|
59
59
|
|
|
60
|
-
Download from [GitHub Releases](https://github.com/
|
|
60
|
+
Download from [GitHub Releases](https://github.com/can1357/oh-my-pi/releases):
|
|
61
61
|
|
|
62
|
-
| Platform |
|
|
62
|
+
| Platform | Binary |
|
|
63
63
|
| ------------------- | ------------------------ |
|
|
64
|
-
| macOS Apple Silicon | `omp-darwin-arm64
|
|
65
|
-
| macOS Intel | `omp-darwin-x64
|
|
66
|
-
| Linux x64 | `omp-linux-x64
|
|
67
|
-
| Linux ARM64 | `omp-linux-arm64
|
|
68
|
-
| Windows x64 | `omp-windows-x64.
|
|
64
|
+
| macOS Apple Silicon | `omp-darwin-arm64` |
|
|
65
|
+
| macOS Intel | `omp-darwin-x64` |
|
|
66
|
+
| Linux x64 | `omp-linux-x64` |
|
|
67
|
+
| Linux ARM64 | `omp-linux-arm64` |
|
|
68
|
+
| Windows x64 | `omp-windows-x64.exe` |
|
|
69
69
|
|
|
70
70
|
```bash
|
|
71
71
|
# macOS/Linux
|
|
72
|
-
|
|
73
|
-
./omp
|
|
72
|
+
chmod +x omp-darwin-arm64
|
|
73
|
+
./omp-darwin-arm64
|
|
74
74
|
|
|
75
75
|
# Windows
|
|
76
|
-
|
|
77
|
-
omp.exe
|
|
76
|
+
omp-windows-x64.exe
|
|
78
77
|
```
|
|
79
78
|
|
|
80
79
|
**macOS note:** The binary is unsigned. If blocked, run: `xattr -c ./omp`
|
|
@@ -133,24 +132,7 @@ return config
|
|
|
133
132
|
|
|
134
133
|
### API Keys & OAuth
|
|
135
134
|
|
|
136
|
-
**Option 1:
|
|
137
|
-
|
|
138
|
-
Add API keys to `~/.omp/agent/auth.json`:
|
|
139
|
-
|
|
140
|
-
```json
|
|
141
|
-
{
|
|
142
|
-
"anthropic": [
|
|
143
|
-
{ "type": "api_key", "key": "sk-ant-..." },
|
|
144
|
-
{ "type": "api_key", "key": "sk-ant-..." }
|
|
145
|
-
],
|
|
146
|
-
"openai": { "type": "api_key", "key": "sk-..." },
|
|
147
|
-
"google": { "type": "api_key", "key": "..." }
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
If a provider has multiple credentials, new sessions round robin across them and stay sticky per session.
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
**Option 2: Environment variables**
|
|
135
|
+
**Option 1: Environment variables** (recommended)
|
|
154
136
|
|
|
155
137
|
| Provider | Auth Key | Environment Variable |
|
|
156
138
|
| ---------- | ------------ | -------------------- |
|
|
@@ -164,16 +146,16 @@ If a provider has multiple credentials, new sessions round robin across them and
|
|
|
164
146
|
| OpenRouter | `openrouter` | `OPENROUTER_API_KEY` |
|
|
165
147
|
| ZAI | `zai` | `ZAI_API_KEY` |
|
|
166
148
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
**OAuth Providers:**
|
|
149
|
+
**Option 2: OAuth**
|
|
170
150
|
|
|
171
151
|
Use `/login` to authenticate with subscription-based or free-tier providers:
|
|
172
152
|
|
|
173
153
|
| Provider | Models | Cost |
|
|
174
154
|
| -------------------------- | ----------------------------------------------- | --------------------- |
|
|
175
155
|
| Anthropic (Claude Pro/Max) | Claude models via your subscription | Subscription |
|
|
156
|
+
| Cursor | Claude, GPT-4o via Cursor Pro subscription | Subscription |
|
|
176
157
|
| GitHub Copilot | GPT-4o, Claude, Gemini via Copilot subscription | Subscription |
|
|
158
|
+
| OpenAI Codex | o3, o4-mini via ChatGPT Plus/Pro subscription | Subscription |
|
|
177
159
|
| Google Gemini CLI | Gemini 2.0/2.5 models | Free (Google account) |
|
|
178
160
|
| Google Antigravity | Gemini 3, Claude, GPT-OSS | Free (Google account) |
|
|
179
161
|
|
|
@@ -182,7 +164,7 @@ omp
|
|
|
182
164
|
/login # Select provider, authorize in browser
|
|
183
165
|
```
|
|
184
166
|
|
|
185
|
-
**Note:** `/login` replaces any existing API keys for that provider with OAuth credentials
|
|
167
|
+
**Note:** `/login` replaces any existing API keys for that provider with OAuth credentials. If OAuth credentials already exist, `/login` appends another entry.
|
|
186
168
|
|
|
187
169
|
**GitHub Copilot notes:**
|
|
188
170
|
|
|
@@ -196,7 +178,7 @@ omp
|
|
|
196
178
|
- Both are free with any Google account, subject to rate limits
|
|
197
179
|
- Paid Cloud Code Assist subscriptions: set `GOOGLE_CLOUD_PROJECT` or `GOOGLE_CLOUD_PROJECT_ID` env var to your project ID
|
|
198
180
|
|
|
199
|
-
Credentials stored in `~/.omp/agent/
|
|
181
|
+
Credentials stored in `~/.omp/agent/agent.db`. Use `/logout` to clear.
|
|
200
182
|
|
|
201
183
|
### Quick Start
|
|
202
184
|
|
|
@@ -281,10 +263,10 @@ The agent reads, writes, and edits files, and executes commands via bash.
|
|
|
281
263
|
| Ctrl+D | Exit (when editor is empty) |
|
|
282
264
|
| Ctrl+Z | Suspend to background (use `fg` in shell to resume) |
|
|
283
265
|
| Shift+Tab | Cycle thinking level |
|
|
284
|
-
| Ctrl+P / Shift+Ctrl+P | Cycle models
|
|
266
|
+
| Ctrl+P / Shift+Ctrl+P | Cycle role models (slow/default/smol) |
|
|
285
267
|
| Ctrl+L | Open model selector |
|
|
286
268
|
| Ctrl+O | Toggle tool output expansion |
|
|
287
|
-
| Ctrl+T | Toggle
|
|
269
|
+
| Ctrl+T | Toggle todo list expansion |
|
|
288
270
|
| Ctrl+G | Edit message in external editor (`$VISUAL` or `$EDITOR`) |
|
|
289
271
|
|
|
290
272
|
### Bash Mode
|
|
@@ -489,7 +471,7 @@ Add custom models (Ollama, vLLM, LM Studio, etc.) via `~/.omp/agent/models.json`
|
|
|
489
471
|
}
|
|
490
472
|
```
|
|
491
473
|
|
|
492
|
-
**Supported APIs:** `openai-completions`, `openai-responses`, `anthropic-messages`, `google-generative-ai`
|
|
474
|
+
**Supported APIs:** `openai-completions`, `openai-responses`, `openai-codex-responses`, `anthropic-messages`, `google-generative-ai`, `google-vertex`
|
|
493
475
|
|
|
494
476
|
**API key resolution:** The `apiKey` field is checked as environment variable name first, then used as literal value.
|
|
495
477
|
|
|
@@ -523,7 +505,6 @@ Add custom models (Ollama, vLLM, LM Studio, etc.) via `~/.omp/agent/models.json`
|
|
|
523
505
|
| `supportsStore` | Whether provider supports `store` field |
|
|
524
506
|
| `supportsDeveloperRole` | Use `developer` vs `system` role |
|
|
525
507
|
| `supportsReasoningEffort` | Support for `reasoning_effort` parameter |
|
|
526
|
-
| `supportsUsageInStreaming` | Whether provider supports `stream_options: { include_usage: true }`. Default: `true` |
|
|
527
508
|
| `maxTokensField` | Use `max_completion_tokens` or `max_tokens` |
|
|
528
509
|
|
|
529
510
|
**Live reload:** The file reloads each time you open `/model`. Edit during session; no restart needed.
|
|
@@ -552,8 +533,9 @@ Global `~/.omp/agent/settings.json` stores persistent preferences:
|
|
|
552
533
|
```json
|
|
553
534
|
{
|
|
554
535
|
"theme": "dark",
|
|
555
|
-
"
|
|
556
|
-
|
|
536
|
+
"modelRoles": {
|
|
537
|
+
"default": "anthropic/claude-sonnet-4-20250514"
|
|
538
|
+
},
|
|
557
539
|
"defaultThinkingLevel": "medium",
|
|
558
540
|
"enabledModels": ["anthropic/*", "*gpt*", "gemini-2.5-pro:high"],
|
|
559
541
|
"queueMode": "one-at-a-time",
|
|
@@ -575,22 +557,19 @@ Global `~/.omp/agent/settings.json` stores persistent preferences:
|
|
|
575
557
|
},
|
|
576
558
|
"terminal": {
|
|
577
559
|
"showImages": true
|
|
578
|
-
}
|
|
579
|
-
"hooks": ["/path/to/hook.ts"],
|
|
580
|
-
"customTools": ["/path/to/tool.ts"]
|
|
560
|
+
}
|
|
581
561
|
}
|
|
582
562
|
```
|
|
583
563
|
|
|
584
564
|
| Setting | Description | Default |
|
|
585
565
|
| ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | --------------- |
|
|
586
566
|
| `theme` | Color theme name | auto-detected |
|
|
587
|
-
| `
|
|
588
|
-
| `defaultModel` | Default model ID | - |
|
|
567
|
+
| `modelRoles` | Model assignments by role (e.g., `{"default": "anthropic/claude-sonnet-4-20250514", "slow": "...", "smol": "..."}`) | - |
|
|
589
568
|
| `defaultThinkingLevel` | Thinking level: `off`, `minimal`, `low`, `medium`, `high`, `xhigh` | - |
|
|
590
569
|
| `enabledModels` | Model patterns for cycling. Supports glob patterns (`github-copilot/*`, `*sonnet*`) and fuzzy matching. Same as `--models` CLI flag | - |
|
|
591
570
|
| `queueMode` | Message queue mode: `all` or `one-at-a-time` | `one-at-a-time` |
|
|
592
571
|
| `shellPath` | Custom bash path (Windows) | auto-detected |
|
|
593
|
-
| `hideThinkingBlock` | Hide thinking blocks in output
|
|
572
|
+
| `hideThinkingBlock` | Hide thinking blocks in output | `false` |
|
|
594
573
|
| `collapseChangelog` | Show condensed changelog after update | `false` |
|
|
595
574
|
| `compaction.enabled` | Enable auto-compaction | `true` |
|
|
596
575
|
| `compaction.reserveTokens` | Tokens to reserve before compaction triggers | `16384` |
|
|
@@ -600,8 +579,6 @@ Global `~/.omp/agent/settings.json` stores persistent preferences:
|
|
|
600
579
|
| `retry.maxRetries` | Maximum retry attempts | `3` |
|
|
601
580
|
| `retry.baseDelayMs` | Base delay for exponential backoff | `2000` |
|
|
602
581
|
| `terminal.showImages` | Render images inline (supported terminals) | `true` |
|
|
603
|
-
| `hooks` | Additional hook file paths | `[]` |
|
|
604
|
-
| `customTools` | Additional custom tool file paths | `[]` |
|
|
605
582
|
|
|
606
583
|
---
|
|
607
584
|
|
|
@@ -685,10 +662,10 @@ A skill provides specialized workflows, setup instructions, helper scripts, and
|
|
|
685
662
|
|
|
686
663
|
**Skill locations:**
|
|
687
664
|
|
|
688
|
-
- Omp user: `~/.omp/agent/skills
|
|
689
|
-
- Omp project: `.omp/skills
|
|
665
|
+
- Omp user: `~/.omp/agent/skills/*/SKILL.md`
|
|
666
|
+
- Omp project: `.omp/skills/*/SKILL.md`
|
|
690
667
|
- Claude Code: `~/.claude/skills/*/SKILL.md` and `.claude/skills/*/SKILL.md`
|
|
691
|
-
- Codex CLI: `~/.codex/skills
|
|
668
|
+
- Codex CLI: `~/.codex/skills/*/SKILL.md`
|
|
692
669
|
|
|
693
670
|
**Format:**
|
|
694
671
|
|
|
@@ -733,8 +710,8 @@ Hooks are TypeScript modules that extend omp's behavior by subscribing to lifecy
|
|
|
733
710
|
|
|
734
711
|
**Hook locations:**
|
|
735
712
|
|
|
736
|
-
- Global: `~/.omp/agent/hooks/*.ts`
|
|
737
|
-
- Project: `.omp/hooks/*.ts`
|
|
713
|
+
- Global: `~/.omp/agent/hooks/pre/*.ts`, `~/.omp/agent/hooks/post/*.ts`
|
|
714
|
+
- Project: `.omp/hooks/pre/*.ts`, `.omp/hooks/post/*.ts`
|
|
738
715
|
- CLI: `--hook <path>` (for debugging)
|
|
739
716
|
|
|
740
717
|
**Quick example** (permission gate):
|
|
@@ -849,7 +826,7 @@ omp [options] [@files...] [messages...]
|
|
|
849
826
|
|
|
850
827
|
| Option | Description |
|
|
851
828
|
| ------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
852
|
-
| `--provider <name>` | Provider: `anthropic`, `openai`, `google`, `mistral`, `xai`, `groq`, `cerebras`, `openrouter`, `zai`, `github-copilot`, `google-gemini-cli`, `google-antigravity`, or custom |
|
|
829
|
+
| `--provider <name>` | Provider: `anthropic`, `openai`, `google`, `mistral`, `xai`, `groq`, `cerebras`, `openrouter`, `zai`, `cursor`, `github-copilot`, `openai-codex`, `google-gemini-cli`, `google-antigravity`, or custom |
|
|
853
830
|
| `--model <id>` | Model ID |
|
|
854
831
|
| `--api-key <key>` | API key (overrides environment) |
|
|
855
832
|
| `--system-prompt <text\|file>` | Custom system prompt (text or file path) |
|
|
@@ -861,14 +838,16 @@ omp [options] [@files...] [messages...]
|
|
|
861
838
|
| `--session-dir <dir>` | Directory for session storage and lookup |
|
|
862
839
|
| `--continue`, `-c` | Continue most recent session |
|
|
863
840
|
| `--resume`, `-r` | Select session to resume |
|
|
864
|
-
| `--models <patterns>` | Comma-separated patterns for
|
|
841
|
+
| `--models <patterns>` | Comma-separated patterns for model role cycling. Supports glob patterns (e.g., `anthropic/*`, `*sonnet*:high`) and fuzzy matching (e.g., `sonnet,haiku:low`) |
|
|
865
842
|
| `--no-tools` | Disable all built-in tools |
|
|
866
|
-
| `--tools <tools>` |
|
|
867
|
-
| `--thinking <level>` | Thinking level: `off`, `minimal`, `low`, `medium`, `high`
|
|
843
|
+
| `--tools <tools>` | Restrict to comma-separated tool list (default: all tools enabled) |
|
|
844
|
+
| `--thinking <level>` | Thinking level: `off`, `minimal`, `low`, `medium`, `high`, `xhigh` |
|
|
868
845
|
| `--extension <path>`, `-e` | Load an extension file (can be used multiple times) |
|
|
869
846
|
| `--no-extensions` | Disable extension discovery (explicit `-e` paths still work) |
|
|
870
847
|
| `--no-skills` | Disable skills discovery and loading |
|
|
871
848
|
| `--skills <patterns>` | Comma-separated glob patterns to filter skills (e.g., `git-*,docker`) |
|
|
849
|
+
| `--no-lsp` | Disable LSP integration |
|
|
850
|
+
| `--hook <path>` | Load a hook file (for debugging) |
|
|
872
851
|
| `--export <file> [output]` | Export session to HTML |
|
|
873
852
|
| `--help`, `-h` | Show help |
|
|
874
853
|
| `--version`, `-v` | Show version |
|
|
@@ -930,34 +909,40 @@ omp --export session.jsonl output.html
|
|
|
930
909
|
| Variable | Description |
|
|
931
910
|
|----------|-------------|
|
|
932
911
|
| `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, etc. | API keys for providers (see [API Keys & OAuth](#api-keys--oauth)) |
|
|
933
|
-
| `
|
|
934
|
-
| `PI_SKIP_VERSION_CHECK` | Skip new version check at startup (useful for Nix or other package manager installs) |
|
|
912
|
+
| `OMP_CODING_AGENT_DIR` | Override the agent config directory (default: `~/.omp/agent`) |
|
|
935
913
|
| `VISUAL`, `EDITOR` | External editor for Ctrl+G (e.g., `vim`, `code --wait`) |
|
|
936
914
|
|
|
937
915
|
---
|
|
938
916
|
|
|
939
917
|
## Tools
|
|
940
918
|
|
|
941
|
-
|
|
919
|
+
All tools are enabled by default. Use `--tools <list>` to restrict to a subset.
|
|
942
920
|
|
|
943
|
-
|
|
944
|
-
| ------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
|
|
945
|
-
| `read` | Read file contents. Images sent as attachments. Text: first 2000 lines, lines truncated at 2000 chars. Use offset/limit for large files. |
|
|
946
|
-
| `write` | Write/overwrite file. Creates parent directories. |
|
|
947
|
-
| `edit` | Replace exact text in file. Must match exactly including whitespace. Fails if text appears multiple times or not found. |
|
|
948
|
-
| `bash` | Execute command. Returns stdout/stderr. Optional `timeout` parameter. |
|
|
921
|
+
### Core Tools
|
|
949
922
|
|
|
950
|
-
|
|
923
|
+
| Tool | Description |
|
|
924
|
+
| ------- | --------------------------------------------------------------------------------------------------------------- |
|
|
925
|
+
| `read` | Read file contents. Images sent as attachments. Text: first 2000 lines. Use offset/limit for large files. |
|
|
926
|
+
| `write` | Write/overwrite file. Creates parent directories. |
|
|
927
|
+
| `edit` | Replace text in file with fuzzy whitespace matching. Fails if text appears multiple times or not found. |
|
|
928
|
+
| `bash` | Execute command. Returns stdout/stderr. Optional `timeout` parameter. |
|
|
929
|
+
| `grep` | Search file contents (regex or literal). Respects `.gitignore`. |
|
|
930
|
+
| `find` | Search for files by glob pattern. Respects `.gitignore`. |
|
|
931
|
+
| `ls` | List directory contents. Includes dotfiles. |
|
|
951
932
|
|
|
952
|
-
|
|
933
|
+
### Additional Built-in Tools
|
|
953
934
|
|
|
954
|
-
| Tool
|
|
955
|
-
|
|
|
956
|
-
| `
|
|
957
|
-
| `
|
|
958
|
-
| `
|
|
935
|
+
| Tool | Description |
|
|
936
|
+
| ------------- | ----------------------------------------------------- |
|
|
937
|
+
| `task` | Spawn sub-agents for complex multi-step tasks |
|
|
938
|
+
| `lsp` | Language Server Protocol queries (go-to-definition, references, hover) |
|
|
939
|
+
| `todo_write` | Track task progress during sessions |
|
|
940
|
+
| `web_search` | Search the web |
|
|
941
|
+
| `web_fetch` | Fetch and render URLs |
|
|
942
|
+
| `python` | Execute Python code in IPython kernel |
|
|
943
|
+
| `notebook` | Edit Jupyter notebook cells |
|
|
959
944
|
|
|
960
|
-
Example: `--tools read,grep,find,ls` for code review
|
|
945
|
+
Example: `--tools read,grep,find,ls` for read-only code review.
|
|
961
946
|
|
|
962
947
|
For adding new tools, see [Custom Tools](#custom-tools) in the Configuration section.
|
|
963
948
|
|
|
@@ -972,8 +957,8 @@ For embedding omp in Node.js/TypeScript applications, use the SDK:
|
|
|
972
957
|
```typescript
|
|
973
958
|
import { createAgentSession, discoverAuthStorage, discoverModels, SessionManager } from "@oh-my-pi/pi-coding-agent";
|
|
974
959
|
|
|
975
|
-
const authStorage = discoverAuthStorage();
|
|
976
|
-
const modelRegistry = discoverModels(authStorage);
|
|
960
|
+
const authStorage = await discoverAuthStorage();
|
|
961
|
+
const modelRegistry = await discoverModels(authStorage);
|
|
977
962
|
|
|
978
963
|
const { session } = await createAgentSession({
|
|
979
964
|
sessionManager: SessionManager.inMemory(),
|
|
@@ -1035,21 +1020,15 @@ Works with both session files and streaming event logs from `--mode json`.
|
|
|
1035
1020
|
|
|
1036
1021
|
## Philosophy
|
|
1037
1022
|
|
|
1038
|
-
Omp is
|
|
1039
|
-
|
|
1040
|
-
**No MCP.** Build CLI tools with READMEs (see [Skills](#skills)). The agent reads them on demand. [Would you like to know more?](https://mariozechner.at/posts/2025-11-02-what-if-you-dont-need-mcp/)
|
|
1041
|
-
|
|
1042
|
-
**No sub-agents.** Spawn omp instances via tmux, or [build your own sub-agent tool](examples/custom-tools/subagent/) with [custom tools](#custom-tools). Full observability and steerability.
|
|
1043
|
-
|
|
1044
|
-
**No permission popups.** Security theater. Run in a container or build your own with [Hooks](#hooks).
|
|
1023
|
+
Omp is a fork of [Pi](https://github.com/badlogic/pi) by [Mario Zechner](https://github.com/badlogic). Pi is intentionally minimal—no MCP, no sub-agents, no built-in todos. Omp is the opposite: batteries included.
|
|
1045
1024
|
|
|
1046
|
-
**
|
|
1025
|
+
**Yin to Pi's Yang.** Same foundation, different philosophy. Pi strips away; omp adds on. Both are valid approaches—pick what fits your workflow.
|
|
1047
1026
|
|
|
1048
|
-
**
|
|
1027
|
+
**Full toolset by default.** Sub-agents, MCP, LSP, web search, Python execution, todo tracking—all enabled out of the box. Use `--tools` to restrict when needed.
|
|
1049
1028
|
|
|
1050
|
-
**
|
|
1029
|
+
**Agent orchestration built-in.** The Task tool spawns specialized sub-agents (explore, plan, reviewer, task) for complex multi-step work. Parallelism and delegation, not just chat.
|
|
1051
1030
|
|
|
1052
|
-
|
|
1031
|
+
**Multiple extension points.** [Skills](#skills) for on-demand capabilities, [Hooks](#hooks) for lifecycle control, [Custom Tools](#custom-tools) for new abilities, MCP for existing integrations.
|
|
1053
1032
|
|
|
1054
1033
|
---
|
|
1055
1034
|
|
|
@@ -1074,10 +1053,10 @@ Change `name`, `configDir`, and `bin` field for your fork. Affects CLI banner, c
|
|
|
1074
1053
|
|
|
1075
1054
|
Three execution modes: npm install, standalone binary, tsx from source.
|
|
1076
1055
|
|
|
1077
|
-
**Always use `src/
|
|
1056
|
+
**Always use `src/config.ts`** for package assets:
|
|
1078
1057
|
|
|
1079
1058
|
```typescript
|
|
1080
|
-
import { getPackageDir
|
|
1059
|
+
import { getPackageDir } from "./config.js";
|
|
1081
1060
|
```
|
|
1082
1061
|
|
|
1083
1062
|
Never use `__dirname` directly for package assets.
|
|
@@ -1096,5 +1075,5 @@ MIT
|
|
|
1096
1075
|
|
|
1097
1076
|
## See Also
|
|
1098
1077
|
|
|
1099
|
-
- [@oh-my-pi/
|
|
1100
|
-
- [@oh-my-pi/
|
|
1078
|
+
- [@oh-my-pi/pi-ai](https://www.npmjs.com/package/@oh-my-pi/pi-ai): Core LLM toolkit
|
|
1079
|
+
- [@oh-my-pi/pi-agent-core](https://www.npmjs.com/package/@oh-my-pi/pi-agent-core): Agent framework
|
package/docs/sdk.md
CHANGED
|
@@ -20,8 +20,8 @@ See [examples/sdk/](../examples/sdk/) for working examples from minimal to full
|
|
|
20
20
|
import { createAgentSession, discoverAuthStorage, discoverModels, SessionManager } from "@oh-my-pi/pi-coding-agent";
|
|
21
21
|
|
|
22
22
|
// Set up credential storage and model registry
|
|
23
|
-
const authStorage = discoverAuthStorage();
|
|
24
|
-
const modelRegistry = discoverModels(authStorage);
|
|
23
|
+
const authStorage = await discoverAuthStorage();
|
|
24
|
+
const modelRegistry = await discoverModels(authStorage);
|
|
25
25
|
|
|
26
26
|
const { session } = await createAgentSession({
|
|
27
27
|
sessionManager: SessionManager.inMemory(),
|
|
@@ -251,8 +251,8 @@ const { session } = await createAgentSession({
|
|
|
251
251
|
import { getModel } from "@oh-my-pi/pi-ai";
|
|
252
252
|
import { discoverAuthStorage, discoverModels } from "@oh-my-pi/pi-coding-agent";
|
|
253
253
|
|
|
254
|
-
const authStorage = discoverAuthStorage();
|
|
255
|
-
const modelRegistry = discoverModels(authStorage);
|
|
254
|
+
const authStorage = await discoverAuthStorage();
|
|
255
|
+
const modelRegistry = await discoverModels(authStorage);
|
|
256
256
|
|
|
257
257
|
// Find specific built-in model (doesn't check if API key exists)
|
|
258
258
|
const opus = getModel("anthropic", "claude-opus-4-5");
|
|
@@ -301,8 +301,8 @@ API key resolution priority (handled by AuthStorage):
|
|
|
301
301
|
import { AuthStorage, ModelRegistry, discoverAuthStorage, discoverModels } from "@oh-my-pi/pi-coding-agent";
|
|
302
302
|
|
|
303
303
|
// Default: uses ~/.omp/agent/auth.json and ~/.omp/agent/models.json
|
|
304
|
-
const authStorage = discoverAuthStorage();
|
|
305
|
-
const modelRegistry = discoverModels(authStorage);
|
|
304
|
+
const authStorage = await discoverAuthStorage();
|
|
305
|
+
const modelRegistry = await discoverModels(authStorage);
|
|
306
306
|
|
|
307
307
|
const { session } = await createAgentSession({
|
|
308
308
|
sessionManager: SessionManager.inMemory(),
|
|
@@ -742,8 +742,8 @@ import {
|
|
|
742
742
|
} from "@oh-my-pi/pi-coding-agent";
|
|
743
743
|
|
|
744
744
|
// Auth and Models
|
|
745
|
-
const authStorage = discoverAuthStorage(); // ~/.omp/agent/
|
|
746
|
-
const modelRegistry = discoverModels(authStorage); // + ~/.omp/agent/models.json
|
|
745
|
+
const authStorage = await discoverAuthStorage(); // ~/.omp/agent/agent.db
|
|
746
|
+
const modelRegistry = await discoverModels(authStorage); // + ~/.omp/agent/models.json
|
|
747
747
|
const allModels = modelRegistry.getAll(); // All models (built-in + custom)
|
|
748
748
|
const available = await modelRegistry.getAvailable(); // Only models with API keys
|
|
749
749
|
const model = modelRegistry.find("provider", "id"); // Find specific model
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oh-my-pi/pi-coding-agent",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.1.0",
|
|
4
4
|
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"ompConfig": {
|
|
@@ -34,17 +34,16 @@
|
|
|
34
34
|
"clean": "rm -rf dist",
|
|
35
35
|
"build": "tsgo -p tsconfig.build.json && chmod +x dist/cli.js",
|
|
36
36
|
"build:binary": "bun run generate-wasm-b64 && bun build --compile ./src/cli.ts --outfile dist/omp",
|
|
37
|
-
"generate-wasm-b64": "bun scripts/generate-wasm-b64.ts",
|
|
38
37
|
"generate-template": "bun scripts/generate-template.ts",
|
|
39
|
-
"postinstall": "
|
|
38
|
+
"postinstall": "bun run generate-template || true",
|
|
40
39
|
"test": "bun test",
|
|
41
40
|
"prepublishOnly": "bun run generate-template && bun run clean && bun run build"
|
|
42
41
|
},
|
|
43
42
|
"dependencies": {
|
|
44
|
-
"@oh-my-pi/pi-agent-core": "
|
|
45
|
-
"@oh-my-pi/pi-ai": "
|
|
46
|
-
"@oh-my-pi/pi-git-tool": "
|
|
47
|
-
"@oh-my-pi/pi-tui": "
|
|
43
|
+
"@oh-my-pi/pi-agent-core": "6.1.0",
|
|
44
|
+
"@oh-my-pi/pi-ai": "6.1.0",
|
|
45
|
+
"@oh-my-pi/pi-git-tool": "6.1.0",
|
|
46
|
+
"@oh-my-pi/pi-tui": "6.1.0",
|
|
48
47
|
"@openai/agents": "^0.3.7",
|
|
49
48
|
"@sinclair/typebox": "^0.34.46",
|
|
50
49
|
"ajv": "^8.17.1",
|
|
@@ -191,14 +191,26 @@ if "__omp_prelude_loaded__" not in globals():
|
|
|
191
191
|
limit: int = 1000,
|
|
192
192
|
hidden: bool = False,
|
|
193
193
|
sort_by_mtime: bool = False,
|
|
194
|
+
maxdepth: int | None = None,
|
|
195
|
+
mindepth: int | None = None,
|
|
194
196
|
) -> list[Path]:
|
|
195
|
-
"""Recursive glob find. Respects .gitignore.
|
|
196
|
-
|
|
197
|
+
"""Recursive glob find. Respects .gitignore.
|
|
198
|
+
|
|
199
|
+
maxdepth/mindepth are relative to path (0 = path itself, 1 = direct children).
|
|
200
|
+
"""
|
|
201
|
+
p = Path(path).resolve()
|
|
202
|
+
base_depth = len(p.parts)
|
|
197
203
|
ignore_patterns = _load_gitignore_patterns(p)
|
|
198
204
|
matches: list[Path] = []
|
|
199
205
|
for m in p.rglob(pattern):
|
|
200
206
|
if len(matches) >= limit:
|
|
201
207
|
break
|
|
208
|
+
# Check depth constraints
|
|
209
|
+
rel_depth = len(m.resolve().parts) - base_depth
|
|
210
|
+
if maxdepth is not None and rel_depth > maxdepth:
|
|
211
|
+
continue
|
|
212
|
+
if mindepth is not None and rel_depth < mindepth:
|
|
213
|
+
continue
|
|
202
214
|
# Skip hidden files unless requested
|
|
203
215
|
if not hidden and any(part.startswith(".") for part in m.parts):
|
|
204
216
|
continue
|
|
@@ -485,6 +497,30 @@ if "__omp_prelude_loaded__" not in globals():
|
|
|
485
497
|
return groups
|
|
486
498
|
return "\n".join(line for _, line in groups)
|
|
487
499
|
|
|
500
|
+
@_category("Text")
|
|
501
|
+
def counter(
|
|
502
|
+
items: str | list,
|
|
503
|
+
*,
|
|
504
|
+
limit: int | None = None,
|
|
505
|
+
reverse: bool = True,
|
|
506
|
+
) -> list[tuple[int, str]]:
|
|
507
|
+
"""Count occurrences and sort by frequency. Like sort | uniq -c | sort -rn.
|
|
508
|
+
|
|
509
|
+
items: text (splits into lines) or list of strings
|
|
510
|
+
reverse: True for descending (most common first), False for ascending
|
|
511
|
+
Returns: [(count, item), ...] sorted by count
|
|
512
|
+
"""
|
|
513
|
+
from collections import Counter
|
|
514
|
+
if isinstance(items, str):
|
|
515
|
+
items = items.splitlines()
|
|
516
|
+
counts = Counter(items)
|
|
517
|
+
sorted_items = sorted(counts.items(), key=lambda x: (x[1], x[0]), reverse=reverse)
|
|
518
|
+
if limit is not None:
|
|
519
|
+
sorted_items = sorted_items[:limit]
|
|
520
|
+
result = [(count, item) for item, count in sorted_items]
|
|
521
|
+
_emit_status("counter", unique=len(counts), total=sum(counts.values()), top=result[:10])
|
|
522
|
+
return result
|
|
523
|
+
|
|
488
524
|
@_category("Text")
|
|
489
525
|
def cols(text: str, *indices: int, sep: str | None = None) -> str:
|
|
490
526
|
"""Extract columns from text (0-indexed). Like cut."""
|
|
@@ -497,6 +533,13 @@ if "__omp_prelude_loaded__" not in globals():
|
|
|
497
533
|
_emit_status("cols", lines=len(result_lines), columns=list(indices))
|
|
498
534
|
return out
|
|
499
535
|
|
|
536
|
+
@_category("Navigation")
|
|
537
|
+
def basenames(paths: list[str | Path]) -> list[str]:
|
|
538
|
+
"""Extract basename from each path. Like: sed 's|.*/||'."""
|
|
539
|
+
names = [Path(p).name for p in paths]
|
|
540
|
+
_emit_status("basenames", count=len(names), sample=names[:10])
|
|
541
|
+
return names
|
|
542
|
+
|
|
500
543
|
@_category("Navigation")
|
|
501
544
|
def tree(path: str | Path = ".", *, max_depth: int = 3, show_hidden: bool = False) -> str:
|
|
502
545
|
"""Return directory tree."""
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import { logger } from "../../logger";
|
|
3
3
|
import { applyWorkspaceEdit } from "./edits";
|
|
4
|
+
import { getLspmuxCommand, isLspmuxSupported } from "./lspmux";
|
|
4
5
|
import type {
|
|
5
6
|
Diagnostic,
|
|
6
7
|
LspClient,
|
|
@@ -400,13 +401,20 @@ export async function getOrCreateClient(config: ServerConfig, cwd: string, initT
|
|
|
400
401
|
|
|
401
402
|
// Create new client with lock
|
|
402
403
|
const clientPromise = (async () => {
|
|
403
|
-
const
|
|
404
|
-
const
|
|
404
|
+
const baseCommand = config.resolvedCommand ?? config.command;
|
|
405
|
+
const baseArgs = config.args ?? [];
|
|
406
|
+
|
|
407
|
+
// Wrap with lspmux if available and supported
|
|
408
|
+
const { command, args, env } = isLspmuxSupported(baseCommand)
|
|
409
|
+
? await getLspmuxCommand(baseCommand, baseArgs)
|
|
410
|
+
: { command: baseCommand, args: baseArgs };
|
|
411
|
+
|
|
405
412
|
const proc = Bun.spawn([command, ...args], {
|
|
406
413
|
cwd,
|
|
407
414
|
stdin: "pipe",
|
|
408
415
|
stdout: "pipe",
|
|
409
416
|
stderr: "pipe",
|
|
417
|
+
env: env ? { ...process.env, ...env } : undefined,
|
|
410
418
|
});
|
|
411
419
|
|
|
412
420
|
const client: LspClient = {
|
|
@@ -4,17 +4,8 @@
|
|
|
4
4
|
"args": [],
|
|
5
5
|
"fileTypes": [".rs"],
|
|
6
6
|
"rootMarkers": ["Cargo.toml", "rust-analyzer.toml"],
|
|
7
|
-
"initOptions": {
|
|
8
|
-
|
|
9
|
-
"cargo": { "allFeatures": true },
|
|
10
|
-
"procMacro": { "enable": true }
|
|
11
|
-
},
|
|
12
|
-
"settings": {
|
|
13
|
-
"rust-analyzer": {
|
|
14
|
-
"diagnostics": { "enable": true },
|
|
15
|
-
"inlayHints": { "enable": true }
|
|
16
|
-
}
|
|
17
|
-
},
|
|
7
|
+
"initOptions": {},
|
|
8
|
+
"settings": {},
|
|
18
9
|
"capabilities": {
|
|
19
10
|
"flycheck": true,
|
|
20
11
|
"ssr": true,
|
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
import { getLinterClient } from "./clients";
|
|
26
26
|
import { getServersForFile, hasCapability, type LspConfig, loadConfig } from "./config";
|
|
27
27
|
import { applyTextEditsToString, applyWorkspaceEdit } from "./edits";
|
|
28
|
+
import { detectLspmux } from "./lspmux";
|
|
28
29
|
import { renderCall, renderResult } from "./render";
|
|
29
30
|
import * as rustAnalyzer from "./rust-analyzer";
|
|
30
31
|
import {
|
|
@@ -798,10 +799,19 @@ export function createLspTool(session: ToolSession): AgentTool<typeof lspSchema,
|
|
|
798
799
|
// Status action doesn't need a file
|
|
799
800
|
if (action === "status") {
|
|
800
801
|
const servers = Object.keys(config.servers);
|
|
801
|
-
const
|
|
802
|
+
const lspmuxState = await detectLspmux();
|
|
803
|
+
const lspmuxStatus = lspmuxState.available
|
|
804
|
+
? lspmuxState.running
|
|
805
|
+
? "lspmux: active (multiplexing enabled)"
|
|
806
|
+
: "lspmux: installed but server not running"
|
|
807
|
+
: "";
|
|
808
|
+
|
|
809
|
+
const serverStatus =
|
|
802
810
|
servers.length > 0
|
|
803
811
|
? `Active language servers: ${servers.join(", ")}`
|
|
804
812
|
: "No language servers configured for this project";
|
|
813
|
+
|
|
814
|
+
const output = lspmuxStatus ? `${serverStatus}\n${lspmuxStatus}` : serverStatus;
|
|
805
815
|
return {
|
|
806
816
|
content: [{ type: "text", text: output }],
|
|
807
817
|
details: { action, success: true },
|