@oh-my-pi/pi-coding-agent 11.14.4 → 12.0.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 +17 -0
- package/package.json +7 -7
- package/src/cli.ts +6 -0
- package/src/commands/setup.ts +6 -3
- package/src/config/settings-schema.ts +2 -2
- package/src/mcp/manager.ts +9 -0
- package/src/modes/components/model-selector.ts +28 -2
- package/src/modes/controllers/mcp-command-controller.ts +48 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [12.0.0] - 2026-02-12
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Added `getAllServerNames()` method to MCPManager for enumerating all known servers
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- Changed default edit mode from `patch` to `hashline` for more precise code modifications
|
|
14
|
+
- Changed `readHashLines` setting default from false to true to enable hash line reading by default
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
- Fixed `omp setup` crashing with uncaught exception when no component argument provided; now shows help ([#35](https://github.com/can1357/oh-my-pi/issues/35))
|
|
19
|
+
- Fixed `/mcp list` showing "No MCP servers configured" when servers are loaded from discovery sources like `.claude.json`, `.cursor/mcp.json`, `.vscode/mcp.json` ([#34](https://github.com/can1357/oh-my-pi/issues/34))
|
|
20
|
+
- Fixed model selector sorting to show newest models first within each provider instead of alphabetical; `-latest` aliases now appear before dated versions ([#37](https://github.com/can1357/oh-my-pi/issues/37))
|
|
21
|
+
|
|
5
22
|
## [11.14.4] - 2026-02-12
|
|
6
23
|
|
|
7
24
|
### Added
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oh-my-pi/pi-coding-agent",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "12.0.0",
|
|
4
4
|
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"ompConfig": {
|
|
@@ -88,12 +88,12 @@
|
|
|
88
88
|
},
|
|
89
89
|
"dependencies": {
|
|
90
90
|
"@mozilla/readability": "0.6.0",
|
|
91
|
-
"@oh-my-pi/omp-stats": "
|
|
92
|
-
"@oh-my-pi/pi-agent-core": "
|
|
93
|
-
"@oh-my-pi/pi-ai": "
|
|
94
|
-
"@oh-my-pi/pi-natives": "
|
|
95
|
-
"@oh-my-pi/pi-tui": "
|
|
96
|
-
"@oh-my-pi/pi-utils": "
|
|
91
|
+
"@oh-my-pi/omp-stats": "12.0.0",
|
|
92
|
+
"@oh-my-pi/pi-agent-core": "12.0.0",
|
|
93
|
+
"@oh-my-pi/pi-ai": "12.0.0",
|
|
94
|
+
"@oh-my-pi/pi-natives": "12.0.0",
|
|
95
|
+
"@oh-my-pi/pi-tui": "12.0.0",
|
|
96
|
+
"@oh-my-pi/pi-utils": "12.0.0",
|
|
97
97
|
"@sinclair/typebox": "^0.34.48",
|
|
98
98
|
"@xterm/headless": "^6.0.0",
|
|
99
99
|
"ajv": "^8.17.1",
|
package/src/cli.ts
CHANGED
|
@@ -6,6 +6,12 @@
|
|
|
6
6
|
import { type CommandEntry, run } from "@oh-my-pi/pi-utils/cli";
|
|
7
7
|
import { APP_NAME, VERSION } from "./config";
|
|
8
8
|
|
|
9
|
+
// Detect known Bun errata that cause TUI crashes (e.g. Bun.stringWidth mishandling OSC sequences).
|
|
10
|
+
if (Bun.stringWidth("\x1b[0m\x1b]8;;\x07") !== 0) {
|
|
11
|
+
process.stderr.write(`error: Bun runtime errata detected (v${Bun.version}). Please update Bun: bun upgrade\n`);
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
|
|
9
15
|
process.title = APP_NAME;
|
|
10
16
|
|
|
11
17
|
const commands: CommandEntry[] = [
|
package/src/commands/setup.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Install dependencies for optional features.
|
|
3
3
|
*/
|
|
4
|
-
import { Args, Command, Flags } from "@oh-my-pi/pi-utils/cli";
|
|
4
|
+
import { Args, Command, Flags, renderCommandHelp } from "@oh-my-pi/pi-utils/cli";
|
|
5
5
|
import { runSetupCommand, type SetupCommandArgs, type SetupComponent } from "../cli/setup-cli";
|
|
6
6
|
import { initTheme } from "../modes/theme/theme";
|
|
7
7
|
|
|
@@ -13,7 +13,7 @@ export default class Setup extends Command {
|
|
|
13
13
|
static args = {
|
|
14
14
|
component: Args.string({
|
|
15
15
|
description: "Component to install",
|
|
16
|
-
required:
|
|
16
|
+
required: false,
|
|
17
17
|
options: COMPONENTS,
|
|
18
18
|
}),
|
|
19
19
|
};
|
|
@@ -25,6 +25,10 @@ export default class Setup extends Command {
|
|
|
25
25
|
|
|
26
26
|
async run(): Promise<void> {
|
|
27
27
|
const { args, flags } = await this.parse(Setup);
|
|
28
|
+
if (!args.component) {
|
|
29
|
+
renderCommandHelp("omp", "setup", Setup);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
28
32
|
const cmd: SetupCommandArgs = {
|
|
29
33
|
component: args.component as SetupComponent,
|
|
30
34
|
flags: {
|
|
@@ -32,7 +36,6 @@ export default class Setup extends Command {
|
|
|
32
36
|
check: flags.check,
|
|
33
37
|
},
|
|
34
38
|
};
|
|
35
|
-
|
|
36
39
|
await initTheme();
|
|
37
40
|
await runSetupCommand(cmd);
|
|
38
41
|
}
|
|
@@ -249,7 +249,7 @@ export const SETTINGS_SCHEMA = {
|
|
|
249
249
|
},
|
|
250
250
|
readHashLines: {
|
|
251
251
|
type: "boolean",
|
|
252
|
-
default:
|
|
252
|
+
default: true,
|
|
253
253
|
ui: {
|
|
254
254
|
tab: "config",
|
|
255
255
|
label: "Read hash lines",
|
|
@@ -743,7 +743,7 @@ export const SETTINGS_SCHEMA = {
|
|
|
743
743
|
"edit.mode": {
|
|
744
744
|
type: "enum",
|
|
745
745
|
values: ["replace", "patch", "hashline"] as const,
|
|
746
|
-
default: "
|
|
746
|
+
default: "hashline",
|
|
747
747
|
ui: {
|
|
748
748
|
tab: "config",
|
|
749
749
|
label: "Edit mode",
|
package/src/mcp/manager.ts
CHANGED
|
@@ -343,6 +343,15 @@ export class MCPManager {
|
|
|
343
343
|
return Array.from(this.#connections.keys());
|
|
344
344
|
}
|
|
345
345
|
|
|
346
|
+
/**
|
|
347
|
+
* Get all known server names (connected, connecting, or discovered).
|
|
348
|
+
*/
|
|
349
|
+
getAllServerNames(): string[] {
|
|
350
|
+
return Array.from(
|
|
351
|
+
new Set([...this.#sources.keys(), ...this.#connections.keys(), ...this.#pendingConnections.keys()]),
|
|
352
|
+
);
|
|
353
|
+
}
|
|
354
|
+
|
|
346
355
|
/**
|
|
347
356
|
* Disconnect from a specific server.
|
|
348
357
|
*/
|
|
@@ -203,6 +203,9 @@ export class ModelSelectorComponent extends Container {
|
|
|
203
203
|
return i;
|
|
204
204
|
};
|
|
205
205
|
|
|
206
|
+
const dateRe = /-(\d{8})$/;
|
|
207
|
+
const latestRe = /-latest$/;
|
|
208
|
+
|
|
206
209
|
models.sort((a, b) => {
|
|
207
210
|
const aKey = `${a.provider}/${a.id}`;
|
|
208
211
|
const bKey = `${b.provider}/${b.id}`;
|
|
@@ -216,10 +219,33 @@ export class ModelSelectorComponent extends Container {
|
|
|
216
219
|
const bMru = mruIndex.get(bKey) ?? Number.MAX_SAFE_INTEGER;
|
|
217
220
|
if (aMru !== bMru) return aMru - bMru;
|
|
218
221
|
|
|
219
|
-
//
|
|
222
|
+
// By provider, then recency within provider
|
|
220
223
|
const providerCmp = a.provider.localeCompare(b.provider);
|
|
221
224
|
if (providerCmp !== 0) return providerCmp;
|
|
222
|
-
|
|
225
|
+
|
|
226
|
+
const aIsLatest = latestRe.test(a.id);
|
|
227
|
+
const bIsLatest = latestRe.test(b.id);
|
|
228
|
+
const aDate = a.id.match(dateRe)?.[1] ?? "";
|
|
229
|
+
const bDate = b.id.match(dateRe)?.[1] ?? "";
|
|
230
|
+
|
|
231
|
+
// Both have dates or latest tags — sort by recency
|
|
232
|
+
const aHasRecency = aIsLatest || aDate !== "";
|
|
233
|
+
const bHasRecency = bIsLatest || bDate !== "";
|
|
234
|
+
|
|
235
|
+
// Models with recency info come before those without
|
|
236
|
+
if (aHasRecency !== bHasRecency) return aHasRecency ? -1 : 1;
|
|
237
|
+
|
|
238
|
+
// If neither has recency info, fall back to alphabetical
|
|
239
|
+
if (!aHasRecency) return a.id.localeCompare(b.id);
|
|
240
|
+
|
|
241
|
+
// -latest always sorts first within recency group
|
|
242
|
+
if (aIsLatest !== bIsLatest) return aIsLatest ? -1 : 1;
|
|
243
|
+
|
|
244
|
+
// Both have dates — descending (newest first)
|
|
245
|
+
if (aDate && bDate) return bDate.localeCompare(aDate);
|
|
246
|
+
|
|
247
|
+
// One has date, other is latest — latest first
|
|
248
|
+
return aIsLatest ? -1 : bIsLatest ? 1 : a.id.localeCompare(b.id);
|
|
223
249
|
});
|
|
224
250
|
}
|
|
225
251
|
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Handles /mcp subcommands for managing MCP servers.
|
|
5
5
|
*/
|
|
6
6
|
import { Spacer, Text } from "@oh-my-pi/pi-tui";
|
|
7
|
+
import type { SourceMeta } from "../../capability/types";
|
|
7
8
|
import { analyzeAuthError, discoverOAuthEndpoints, MCPManager } from "../../mcp";
|
|
8
9
|
import { connectToServer, disconnectServer, listTools } from "../../mcp/client";
|
|
9
10
|
import {
|
|
@@ -765,7 +766,20 @@ export class MCPCommandController {
|
|
|
765
766
|
const userServers = Object.keys(userConfig.mcpServers ?? {});
|
|
766
767
|
const projectServers = Object.keys(projectConfig.mcpServers ?? {});
|
|
767
768
|
|
|
768
|
-
|
|
769
|
+
// Collect runtime-discovered servers not in config files
|
|
770
|
+
const configServerNames = new Set([...userServers, ...projectServers]);
|
|
771
|
+
const discoveredServers: { name: string; source: SourceMeta }[] = [];
|
|
772
|
+
if (this.ctx.mcpManager) {
|
|
773
|
+
for (const name of this.ctx.mcpManager.getAllServerNames()) {
|
|
774
|
+
if (configServerNames.has(name)) continue;
|
|
775
|
+
const source = this.ctx.mcpManager.getSource(name);
|
|
776
|
+
if (source) {
|
|
777
|
+
discoveredServers.push({ name, source });
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
if (userServers.length === 0 && projectServers.length === 0 && discoveredServers.length === 0) {
|
|
769
783
|
this.#showMessage(
|
|
770
784
|
[
|
|
771
785
|
"",
|
|
@@ -826,6 +840,39 @@ export class MCPCommandController {
|
|
|
826
840
|
lines.push("");
|
|
827
841
|
}
|
|
828
842
|
|
|
843
|
+
// Show discovered servers (from .claude.json, .cursor/mcp.json, .vscode/mcp.json, etc.)
|
|
844
|
+
if (discoveredServers.length > 0) {
|
|
845
|
+
// Group by source display name + path
|
|
846
|
+
const bySource = new Map<string, typeof discoveredServers>();
|
|
847
|
+
for (const entry of discoveredServers) {
|
|
848
|
+
const key = `${entry.source.providerName}|${entry.source.path}`;
|
|
849
|
+
let group = bySource.get(key);
|
|
850
|
+
if (!group) {
|
|
851
|
+
group = [];
|
|
852
|
+
bySource.set(key, group);
|
|
853
|
+
}
|
|
854
|
+
group.push(entry);
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
for (const [key, entries] of bySource) {
|
|
858
|
+
const sepIdx = key.indexOf("|");
|
|
859
|
+
const providerName = key.slice(0, sepIdx);
|
|
860
|
+
const sourcePath = key.slice(sepIdx + 1);
|
|
861
|
+
const shortPath = sourcePath.replace(process.env.HOME ?? "", "~");
|
|
862
|
+
lines.push(theme.fg("accent", providerName) + theme.fg("muted", ` (${shortPath}):`));
|
|
863
|
+
for (const { name } of entries) {
|
|
864
|
+
const state = this.ctx.mcpManager!.getConnectionStatus(name);
|
|
865
|
+
const status =
|
|
866
|
+
state === "connected"
|
|
867
|
+
? theme.fg("success", " ● connected")
|
|
868
|
+
: state === "connecting"
|
|
869
|
+
? theme.fg("muted", " ◌ connecting")
|
|
870
|
+
: theme.fg("muted", " ○ not connected");
|
|
871
|
+
lines.push(` ${theme.fg("accent", name)}${status}`);
|
|
872
|
+
}
|
|
873
|
+
lines.push("");
|
|
874
|
+
}
|
|
875
|
+
}
|
|
829
876
|
this.#showMessage(lines.join("\n"));
|
|
830
877
|
} catch (error) {
|
|
831
878
|
this.ctx.showError(`Failed to list servers: ${error instanceof Error ? error.message : String(error)}`);
|