@oh-my-pi/pi-coding-agent 11.0.0 → 11.0.2

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 CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [11.0.2] - 2026-02-05
6
+
7
+ ### Fixed
8
+
9
+ - Fixed role model cycling to expand role aliases (e.g., roles pointing at `pi/plan`) so slow/default/smol cycles resolve correctly
10
+
5
11
  ## [11.0.0] - 2026-02-05
6
12
 
7
13
  ### Added
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oh-my-pi/pi-coding-agent",
3
- "version": "11.0.0",
3
+ "version": "11.0.2",
4
4
  "description": "Coding agent CLI with read, bash, edit, write tools and session management",
5
5
  "type": "module",
6
6
  "ompConfig": {
@@ -80,12 +80,12 @@
80
80
  },
81
81
  "dependencies": {
82
82
  "@mozilla/readability": "0.6.0",
83
- "@oh-my-pi/omp-stats": "11.0.0",
84
- "@oh-my-pi/pi-agent-core": "11.0.0",
85
- "@oh-my-pi/pi-ai": "11.0.0",
86
- "@oh-my-pi/pi-natives": "11.0.0",
87
- "@oh-my-pi/pi-tui": "11.0.0",
88
- "@oh-my-pi/pi-utils": "11.0.0",
83
+ "@oh-my-pi/omp-stats": "11.0.2",
84
+ "@oh-my-pi/pi-agent-core": "11.0.2",
85
+ "@oh-my-pi/pi-ai": "11.0.2",
86
+ "@oh-my-pi/pi-natives": "11.0.2",
87
+ "@oh-my-pi/pi-tui": "11.0.2",
88
+ "@oh-my-pi/pi-utils": "11.0.2",
89
89
  "@openai/agents": "^0.4.5",
90
90
  "@sinclair/typebox": "^0.34.48",
91
91
  "ajv": "^8.17.1",
@@ -33,7 +33,7 @@ import { YAML } from "bun";
33
33
  import type { Rule } from "../capability/rule";
34
34
  import { getAgentDbPath } from "../config";
35
35
  import { MODEL_ROLE_IDS, type ModelRegistry, type ModelRole } from "../config/model-registry";
36
- import { parseModelString } from "../config/model-resolver";
36
+ import { expandRoleAlias, parseModelString } from "../config/model-resolver";
37
37
  import {
38
38
  expandPromptTemplate,
39
39
  type PromptTemplate,
@@ -1871,13 +1871,14 @@ export class AgentSession {
1871
1871
  : this.settings.getModelRole(role);
1872
1872
  if (!roleModelStr) continue;
1873
1873
 
1874
- const parsed = parseModelString(roleModelStr);
1874
+ const expandedRoleModelStr = expandRoleAlias(roleModelStr, this.settings);
1875
+ const parsed = parseModelString(expandedRoleModelStr);
1875
1876
  let match: Model | undefined;
1876
1877
  if (parsed) {
1877
1878
  match = availableModels.find(m => m.provider === parsed.provider && m.id === parsed.id);
1878
1879
  }
1879
1880
  if (!match) {
1880
- match = availableModels.find(m => m.id.toLowerCase() === roleModelStr.toLowerCase());
1881
+ match = availableModels.find(m => m.id.toLowerCase() === expandedRoleModelStr.toLowerCase());
1881
1882
  }
1882
1883
  if (!match) continue;
1883
1884
 
@@ -579,23 +579,22 @@ function extractFirstUserPrompt(entries: Array<Record<string, unknown>>): string
579
579
  async function getSortedSessions(sessionDir: string, storage: SessionStorage): Promise<RecentSessionInfo[]> {
580
580
  try {
581
581
  const files: string[] = storage.listFilesSync(sessionDir, "*.jsonl");
582
- const results = await Promise.all(
582
+ const sessions: RecentSessionInfo[] = [];
583
+ await Promise.all(
583
584
  files.map(async (path: string) => {
584
585
  try {
585
586
  const content = await storage.readTextPrefix(path, 4096);
586
587
  const entries = parseJsonlEntries<Record<string, unknown>>(content);
587
- if (entries.length === 0) return null;
588
+ if (entries.length === 0) return;
588
589
  const header = entries[0] as Record<string, unknown>;
589
- if (header.type !== "session" || typeof header.id !== "string") return null;
590
+ if (header.type !== "session" || typeof header.id !== "string") return;
590
591
  const mtime = storage.statSync(path).mtimeMs;
591
592
  const firstPrompt = header.title ? undefined : extractFirstUserPrompt(entries);
592
- return new RecentSessionInfo(path, mtime, header, firstPrompt);
593
- } catch {
594
- return null;
595
- }
593
+ sessions.push(new RecentSessionInfo(path, mtime, header, firstPrompt));
594
+ } catch {}
596
595
  }),
597
596
  );
598
- return results.filter((item): item is RecentSessionInfo => item !== null).sort((a, b) => b.mtime - a.mtime);
597
+ return sessions.sort((a, b) => b.mtime - a.mtime);
599
598
  } catch {
600
599
  return [];
601
600
  }
@@ -908,62 +907,65 @@ function extractTextFromContent(content: Message["content"]): string {
908
907
  async function collectSessionsFromFiles(files: string[], storage: SessionStorage): Promise<SessionInfo[]> {
909
908
  const sessions: SessionInfo[] = [];
910
909
 
911
- for (const file of files) {
912
- try {
913
- const content = await storage.readText(file);
914
- const entries = parseJsonlEntries<Record<string, unknown>>(content);
915
- if (entries.length === 0) continue;
916
-
917
- // Check first entry for valid session header
918
- type SessionHeaderShape = { type: string; id: string; cwd?: string; title?: string; timestamp: string };
919
- const header = entries[0] as SessionHeaderShape;
920
- if (header.type !== "session" || !header.id) continue;
921
-
922
- const stats = storage.statSync(file);
923
- let messageCount = 0;
924
- let firstMessage = "";
925
- const allMessages: string[] = [];
926
- let shortSummary: string | undefined;
927
-
928
- for (let i = 1; i < entries.length; i++) {
929
- const entry = entries[i] as { type?: string; message?: Message; shortSummary?: string };
930
-
931
- if (entry.type === "compaction" && typeof entry.shortSummary === "string") {
932
- shortSummary = entry.shortSummary;
933
- }
910
+ // Collect session info for all files in parallel
911
+ await Promise.all(
912
+ files.map(async file => {
913
+ try {
914
+ const content = await storage.readText(file);
915
+ const entries = parseJsonlEntries<Record<string, unknown>>(content);
916
+ if (entries.length === 0) return;
917
+
918
+ // Check first entry for valid session header
919
+ type SessionHeaderShape = { type: string; id: string; cwd?: string; title?: string; timestamp: string };
920
+ const header = entries[0] as SessionHeaderShape;
921
+ if (header.type !== "session" || !header.id) return;
922
+
923
+ let messageCount = 0;
924
+ let firstMessage = "";
925
+ const allMessages: string[] = [];
926
+ let shortSummary: string | undefined;
927
+
928
+ for (let i = 1; i < entries.length; i++) {
929
+ const entry = entries[i] as { type?: string; message?: Message; shortSummary?: string };
930
+
931
+ if (entry.type === "compaction" && typeof entry.shortSummary === "string") {
932
+ shortSummary = entry.shortSummary;
933
+ }
934
934
 
935
- if (entry.type === "message" && entry.message) {
936
- messageCount++;
935
+ if (entry.type === "message" && entry.message) {
936
+ messageCount++;
937
937
 
938
- if (entry.message.role === "user" || entry.message.role === "assistant") {
939
- const textContent = extractTextFromContent(entry.message.content);
938
+ if (entry.message.role === "user" || entry.message.role === "assistant") {
939
+ const textContent = extractTextFromContent(entry.message.content);
940
940
 
941
- if (textContent) {
942
- allMessages.push(textContent);
941
+ if (textContent) {
942
+ allMessages.push(textContent);
943
943
 
944
- if (!firstMessage && entry.message.role === "user") {
945
- firstMessage = textContent;
944
+ if (!firstMessage && entry.message.role === "user") {
945
+ firstMessage = textContent;
946
+ }
946
947
  }
947
948
  }
948
949
  }
949
950
  }
950
- }
951
951
 
952
- sessions.push({
953
- path: file,
954
- id: header.id,
955
- cwd: typeof header.cwd === "string" ? header.cwd : "",
956
- title: header.title ?? shortSummary,
957
- created: new Date(header.timestamp),
958
- modified: stats.mtime,
959
- messageCount,
960
- firstMessage: firstMessage || "(no messages)",
961
- allMessagesText: allMessages.join(" "),
962
- });
963
- } catch {
964
- // Skip files that can't be read
965
- }
966
- }
952
+ if (messageCount) {
953
+ const stats = storage.statSync(file);
954
+ sessions.push({
955
+ path: file,
956
+ id: header.id,
957
+ cwd: typeof header.cwd === "string" ? header.cwd : "",
958
+ title: header.title ?? shortSummary,
959
+ created: new Date(header.timestamp),
960
+ modified: stats.mtime,
961
+ messageCount,
962
+ firstMessage: firstMessage || "(no messages)",
963
+ allMessagesText: allMessages.join(" "),
964
+ });
965
+ }
966
+ } catch {}
967
+ }),
968
+ );
967
969
 
968
970
  sessions.sort((a, b) => b.modified.getTime() - a.modified.getTime());
969
971
  return sessions;