@timurproko/a1 0.2.7-dev.1232 → 0.2.7-dev.1234
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/dist/composition/owned-ui.js +13 -79
- package/dist/composition/release-update-observation.d.ts +22 -0
- package/dist/composition/release-update-observation.js +91 -0
- package/dist/composition/resident-tab-bridge.d.ts +16 -0
- package/dist/composition/resident-tab-bridge.js +45 -16
- package/dist/composition/startup-route.d.ts +8 -0
- package/dist/composition/startup-route.js +20 -0
- package/dist/contracts/owned-ui/session-workflows.d.ts +3 -0
- package/dist/foundation/release/bootstrap.js +46 -36
- package/dist/foundation/release/progress-palette.generated.d.ts +1 -1
- package/dist/foundation/release/progress-palette.generated.js +1 -1
- package/dist/foundation/release/update-activation.js +8 -2
- package/dist/foundation/resident-tabs/bridge-client.d.ts +3 -0
- package/dist/foundation/resident-tabs/bridge-client.js +7 -1
- package/dist/foundation/resident-tabs/continuity.d.ts +12 -0
- package/dist/foundation/resident-tabs/continuity.js +55 -0
- package/dist/foundation/resident-tabs/index.d.ts +3 -0
- package/dist/foundation/resident-tabs/index.js +4 -0
- package/dist/foundation/resident-tabs/maintenance.d.ts +1 -1
- package/dist/foundation/resident-tabs/release-holds.js +11 -8
- package/dist/foundation/resident-tabs/runtime-control.d.ts +38 -0
- package/dist/foundation/resident-tabs/runtime-control.js +73 -0
- package/dist/foundation/startup/startup-descriptor.js +2 -2
- package/dist/integrations/pi/components/resources/builtin-themes.d.ts +2 -2
- package/dist/integrations/pi/components/resources/builtin-themes.js +2 -2
- package/dist/integrations/pi/components/upstream/adjacent/core/keybindings.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/adjacent/core/keybindings.js +1 -1
- package/dist/integrations/pi/components/upstream/assets/earendil-image.json +2 -2
- package/dist/integrations/pi/components/upstream/components/countdown-timer.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/earendil-announcement.js +1 -1
- package/dist/integrations/pi/components/upstream/components/extension-editor.d.ts +3 -3
- package/dist/integrations/pi/components/upstream/components/extension-editor.js +4 -1
- package/dist/integrations/pi/components/upstream/components/extension-input.js +1 -1
- package/dist/integrations/pi/components/upstream/components/extension-selector.js +1 -1
- package/dist/integrations/pi/components/upstream/components/mermaid.js +1 -1
- package/dist/integrations/pi/components/upstream/components/owned-editor.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/owned-editor.js +8 -1
- package/dist/integrations/pi/components/upstream/components/pi-logo.js +1 -1
- package/dist/integrations/pi/components/upstream/components/scoped-models-selector.d.ts +2 -1
- package/dist/integrations/pi/components/upstream/components/scoped-models-selector.js +14 -3
- package/dist/integrations/pi/components/upstream/components/session-footer.js +1 -1
- package/dist/integrations/pi/components/upstream/components/session-selector-search.d.ts +4 -0
- package/dist/integrations/pi/components/upstream/components/session-selector-search.js +87 -23
- package/dist/integrations/pi/components/upstream/components/session-selector.d.ts +3 -2
- package/dist/integrations/pi/components/upstream/components/session-selector.js +18 -13
- package/dist/integrations/pi/components/upstream/components/skill-invocation-message.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/skill-invocation-message.js +1 -1
- package/dist/integrations/pi/components/upstream/components/status-indicator.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/status-indicator.js +1 -1
- package/dist/integrations/pi/components/upstream/components/themed-text.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/themed-text.js +1 -1
- package/dist/integrations/pi/components/upstream/components/thinking-selector.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/thinking-selector.js +1 -1
- package/dist/integrations/pi/components/upstream/components/tool-execution.d.ts +6 -0
- package/dist/integrations/pi/components/upstream/components/tool-execution.js +14 -2
- package/dist/integrations/pi/components/upstream/components/tree-selector.d.ts +2 -1
- package/dist/integrations/pi/components/upstream/components/tree-selector.js +5 -4
- package/dist/integrations/pi/components/upstream/components/trust-selector.js +1 -1
- package/dist/integrations/pi/components/upstream/external-editor.d.ts +1 -0
- package/dist/integrations/pi/components/upstream/external-editor.js +13 -6
- package/dist/integrations/pi/components/upstream/history/editor-core.d.ts +3 -1
- package/dist/integrations/pi/components/upstream/history/editor-core.js +9 -2
- package/dist/integrations/pi/components/upstream/history/kill-ring.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/history/kill-ring.js +1 -1
- package/dist/integrations/pi/components/upstream/history/printable-key.js +1 -1
- package/dist/integrations/pi/components/upstream/history/text-helpers.js +1 -1
- package/dist/integrations/pi/components/upstream/history/undo-stack.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/history/undo-stack.js +1 -1
- package/dist/integrations/pi/components/upstream/history/word-navigation.js +1 -1
- package/dist/integrations/pi/components/upstream/model-search.d.ts +11 -1
- package/dist/integrations/pi/components/upstream/model-search.js +21 -0
- package/dist/integrations/pi/components/upstream/program-status-reporter.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/theme/theme-controller.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/theme/theme.js +1 -1
- package/dist/integrations/pi/engine/adapter.js +6 -1
- package/dist/integrations/pi/engine/diagnostics-state.d.ts +9 -0
- package/dist/integrations/pi/engine/diagnostics-state.js +34 -0
- package/dist/integrations/pi/engine/resources/changelog.json +4 -4
- package/dist/integrations/pi/engine/view-state.d.ts +2 -1
- package/dist/integrations/pi/engine/view-state.js +4 -16
- package/dist/integrations/pi/startup-public.js +324 -309
- package/dist/integrations/pi/startup-public.manifest.json +1156 -846
- package/dist/integrations/pi/tui-runtime/damage-aware-terminal.d.ts +1 -1
- package/dist/integrations/pi/tui-runtime/damage-aware-terminal.js +1 -1
- package/dist/native/darwin-arm64/manifest.json +1 -1
- package/dist/native/darwin-arm64/terminal-host.manifest.json +3 -3
- package/dist/native/darwin-arm64/terminal-host.node +0 -0
- package/dist/native/darwin-x64/manifest.json +1 -1
- package/dist/native/darwin-x64/terminal-host.manifest.json +3 -3
- package/dist/native/darwin-x64/terminal-host.node +0 -0
- package/dist/native/linux-x64/manifest.json +1 -1
- package/dist/native/linux-x64/terminal-host.manifest.json +3 -3
- package/dist/native/linux-x64/terminal-host.node +0 -0
- package/dist/native/win32-x64/manifest.json +2 -2
- package/dist/native/win32-x64/process-guardian.node +0 -0
- package/dist/native/win32-x64/terminal-host.manifest.json +3 -3
- package/dist/native/win32-x64/terminal-host.node +0 -0
- package/dist/runtime-payload-inventory.json +8178 -5237
- package/dist/ui/settings/progress-palette.generated.d.ts +1 -1
- package/dist/ui/settings/progress-palette.generated.js +1 -1
- package/docs/architecture/native-fixture-isolation.md +23 -0
- package/docs/architecture/resident-tabs.md +23 -4
- package/package.json +10 -5
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Provenance: @earendil-works/pi-coding-agent 1.
|
|
2
|
+
* Provenance: @earendil-works/pi-coding-agent 1.5.0 (MIT), commit f9a26365568127461c47a07a37dcb42c140a3ac5,
|
|
3
3
|
* packages/coding-agent/src/modes/interactive/components/session-selector-search.ts.
|
|
4
4
|
* Modifications: Source-synchronized session search port with only the public SessionInfo type import
|
|
5
5
|
* remapped.
|
|
@@ -9,8 +9,79 @@ import { fuzzyMatch } from "@earendil-works/pi-tui";
|
|
|
9
9
|
function normalizeWhitespaceLower(text) {
|
|
10
10
|
return text.toLowerCase().replace(/\s+/g, " ").trim();
|
|
11
11
|
}
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Match tiers, best first. Each token is scored by the best field it matches; tiers dominate
|
|
14
|
+
* fuzzy scores so an exact hit anywhere beats a scattered subsequence in a short field.
|
|
15
|
+
*/
|
|
16
|
+
const TIER_NAME = 0; // query text appears in the session name
|
|
17
|
+
const TIER_TEXT = 1; // query text appears in the session id, messages, or cwd
|
|
18
|
+
const TIER_FUZZY = 2; // query characters appear scattered in the session name or cwd
|
|
19
|
+
const TIER_WEIGHT = 1_000_000;
|
|
20
|
+
/**
|
|
21
|
+
* Lowercased message text per session. allMessagesText holds every user/assistant message and
|
|
22
|
+
* can be megabytes, so lowercase it once instead of on every keystroke.
|
|
23
|
+
*/
|
|
24
|
+
const messageTextCache = new WeakMap();
|
|
25
|
+
function getMessageText(session) {
|
|
26
|
+
let cached = messageTextCache.get(session);
|
|
27
|
+
if (!cached || cached.source !== session.allMessagesText) {
|
|
28
|
+
cached = { source: session.allMessagesText, lower: session.allMessagesText.toLowerCase() };
|
|
29
|
+
messageTextCache.set(session, cached);
|
|
30
|
+
}
|
|
31
|
+
return cached;
|
|
32
|
+
}
|
|
33
|
+
function getNormalizedMessageText(session) {
|
|
34
|
+
const cached = getMessageText(session);
|
|
35
|
+
cached.normalized ??= cached.lower.replace(/\s+/g, " ").trim();
|
|
36
|
+
return cached.normalized;
|
|
37
|
+
}
|
|
38
|
+
function tierScore(tier, score = 0) {
|
|
39
|
+
return tier * TIER_WEIGHT + score;
|
|
40
|
+
}
|
|
41
|
+
/** Exact (case-insensitive) text match. Messages and ids are only matched exactly: scattered matches in them are noise. */
|
|
42
|
+
function matchLiteralToken(session, value) {
|
|
43
|
+
const name = session.name?.toLowerCase() ?? "";
|
|
44
|
+
if (name.includes(value))
|
|
45
|
+
return tierScore(TIER_NAME, fuzzyMatch(value, name).score);
|
|
46
|
+
if (session.id.toLowerCase().includes(value))
|
|
47
|
+
return tierScore(TIER_TEXT);
|
|
48
|
+
if (getMessageText(session).lower.includes(value))
|
|
49
|
+
return tierScore(TIER_TEXT);
|
|
50
|
+
if (session.cwd.toLowerCase().includes(value))
|
|
51
|
+
return tierScore(TIER_TEXT);
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
54
|
+
function matchFuzzyToken(session, value) {
|
|
55
|
+
const literal = matchLiteralToken(session, value.toLowerCase());
|
|
56
|
+
if (literal !== undefined)
|
|
57
|
+
return literal;
|
|
58
|
+
let best;
|
|
59
|
+
for (const field of [session.name ?? "", session.cwd]) {
|
|
60
|
+
const m = fuzzyMatch(value, field);
|
|
61
|
+
if (m.matches && (best === undefined || m.score < best))
|
|
62
|
+
best = m.score;
|
|
63
|
+
}
|
|
64
|
+
return best === undefined ? undefined : tierScore(TIER_FUZZY, best);
|
|
65
|
+
}
|
|
66
|
+
function matchPhraseToken(session, phrase) {
|
|
67
|
+
const name = normalizeWhitespaceLower(session.name ?? "");
|
|
68
|
+
if (name.includes(phrase))
|
|
69
|
+
return tierScore(TIER_NAME, fuzzyMatch(phrase, name).score);
|
|
70
|
+
if (session.id.toLowerCase().includes(phrase))
|
|
71
|
+
return tierScore(TIER_TEXT);
|
|
72
|
+
if (getNormalizedMessageText(session).includes(phrase))
|
|
73
|
+
return tierScore(TIER_TEXT);
|
|
74
|
+
if (normalizeWhitespaceLower(session.cwd).includes(phrase))
|
|
75
|
+
return tierScore(TIER_TEXT);
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
function matchRegex(session, regex) {
|
|
79
|
+
if (session.name && regex.test(session.name))
|
|
80
|
+
return tierScore(TIER_NAME);
|
|
81
|
+
if (regex.test(session.id) || regex.test(session.allMessagesText) || regex.test(session.cwd)) {
|
|
82
|
+
return tierScore(TIER_TEXT);
|
|
83
|
+
}
|
|
84
|
+
return undefined;
|
|
14
85
|
}
|
|
15
86
|
export function hasSessionName(session) {
|
|
16
87
|
return Boolean(session.name?.trim());
|
|
@@ -89,40 +160,33 @@ export function parseSearchQuery(query) {
|
|
|
89
160
|
flush(inQuote ? "phrase" : "fuzzy");
|
|
90
161
|
return { mode: "tokens", tokens, regex: null };
|
|
91
162
|
}
|
|
163
|
+
/**
|
|
164
|
+
* Each field is matched separately, so a token never matches across field boundaries.
|
|
165
|
+
* Different tokens may match different fields.
|
|
166
|
+
*/
|
|
92
167
|
export function matchSession(session, parsed) {
|
|
93
|
-
const text = getSessionSearchText(session);
|
|
94
168
|
if (parsed.mode === "regex") {
|
|
95
169
|
if (!parsed.regex) {
|
|
96
170
|
return { matches: false, score: 0 };
|
|
97
171
|
}
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
return { matches: false, score: 0 };
|
|
101
|
-
return { matches: true, score: idx * 0.1 };
|
|
102
|
-
}
|
|
103
|
-
if (parsed.tokens.length === 0) {
|
|
104
|
-
return { matches: true, score: 0 };
|
|
172
|
+
const score = matchRegex(session, parsed.regex);
|
|
173
|
+
return score === undefined ? { matches: false, score: 0 } : { matches: true, score };
|
|
105
174
|
}
|
|
106
175
|
let totalScore = 0;
|
|
107
|
-
let normalizedText = null;
|
|
108
176
|
for (const token of parsed.tokens) {
|
|
177
|
+
let score;
|
|
109
178
|
if (token.kind === "phrase") {
|
|
110
|
-
if (normalizedText === null) {
|
|
111
|
-
normalizedText = normalizeWhitespaceLower(text);
|
|
112
|
-
}
|
|
113
179
|
const phrase = normalizeWhitespaceLower(token.value);
|
|
114
180
|
if (!phrase)
|
|
115
181
|
continue;
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
continue;
|
|
182
|
+
score = matchPhraseToken(session, phrase);
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
score = matchFuzzyToken(session, token.value);
|
|
121
186
|
}
|
|
122
|
-
|
|
123
|
-
if (!m.matches)
|
|
187
|
+
if (score === undefined)
|
|
124
188
|
return { matches: false, score: 0 };
|
|
125
|
-
totalScore +=
|
|
189
|
+
totalScore += score;
|
|
126
190
|
}
|
|
127
191
|
return { matches: true, score: totalScore };
|
|
128
192
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { type Component, Container, type Focusable } from "@earendil-works/pi-tui";
|
|
2
2
|
import { KeybindingsManager } from "../adjacent/core/keybindings.js";
|
|
3
3
|
import { type SessionInfo } from "@earendil-works/pi-coding-agent";
|
|
4
|
+
import { type NameFilter, type SortMode } from "./session-selector-search.js";
|
|
4
5
|
type SessionListProgress = (loaded: number, total: number,
|
|
5
6
|
/** Sessions loaded so far, sorted by activity. Present on periodic updates. */
|
|
6
7
|
partialSessions?: readonly SessionInfo[]) => void;
|
|
7
|
-
import { type NameFilter, type SortMode } from "./session-selector-search.js";
|
|
8
8
|
/**
|
|
9
9
|
* Custom session list component with multi-line items and search
|
|
10
10
|
*/
|
|
@@ -21,7 +21,7 @@ declare class SessionList implements Component, Focusable {
|
|
|
21
21
|
private keybindings;
|
|
22
22
|
private showPath;
|
|
23
23
|
private confirmingDeletePath;
|
|
24
|
-
private
|
|
24
|
+
private currentSessionPathKey;
|
|
25
25
|
onSelect?: (sessionPath: string) => void;
|
|
26
26
|
onCancel?: () => void;
|
|
27
27
|
onExit: () => void;
|
|
@@ -56,6 +56,7 @@ type SessionsLoader = (onProgress?: SessionListProgress, signal?: AbortSignal) =
|
|
|
56
56
|
* Component that renders a session selector
|
|
57
57
|
*/
|
|
58
58
|
export declare class SessionSelectorComponent extends Container implements Focusable {
|
|
59
|
+
get capturesViewportInput(): boolean;
|
|
59
60
|
handleInput(data: string): void;
|
|
60
61
|
private canRename;
|
|
61
62
|
private sessionList;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Provenance: @earendil-works/pi-coding-agent 1.
|
|
2
|
+
* Provenance: @earendil-works/pi-coding-agent 1.5.0 (MIT), commit f9a26365568127461c47a07a37dcb42c140a3ac5,
|
|
3
3
|
* packages/coding-agent/src/modes/interactive/components/session-selector.ts.
|
|
4
4
|
* Modifications: Source-synchronized session selector port: preserve threaded/current/all scope,
|
|
5
5
|
* search, sort, named/path filters, rename, delete confirmation, active-session protection,
|
|
@@ -23,6 +23,7 @@ import { KeybindingsManager } from "../adjacent/core/keybindings.js";
|
|
|
23
23
|
import { DynamicBorder } from "../../../startup-public.js";
|
|
24
24
|
import { addPiModalHeader, adoptPiModalFrame, renderPiModalSearchInput } from "../../modal-frame.js";
|
|
25
25
|
import { DIALOG_CLOSE_SHORTCUT_HINT, paintPiBorder, piTheme, renderPiModalShortcutHints } from "../../theme.js";
|
|
26
|
+
import { filterAndSortSessions, hasSessionName } from "./session-selector-search.js";
|
|
26
27
|
const theme = new Proxy({}, {
|
|
27
28
|
get(_target, property) {
|
|
28
29
|
const active = piTheme();
|
|
@@ -46,15 +47,11 @@ function withCloseHint(content, width) {
|
|
|
46
47
|
const body = truncateToWidth(content, bodyWidth, "…");
|
|
47
48
|
return body.length === 0 ? close : `${body} ${close}`;
|
|
48
49
|
}
|
|
49
|
-
import { filterAndSortSessions, hasSessionName } from "./session-selector-search.js";
|
|
50
50
|
function shortenPath(path) {
|
|
51
51
|
const home = os.homedir();
|
|
52
52
|
if (!path)
|
|
53
53
|
return path;
|
|
54
|
-
|
|
55
|
-
return `~${path.slice(home.length)}`;
|
|
56
|
-
}
|
|
57
|
-
return path;
|
|
54
|
+
return path.startsWith(home) ? `~${path.slice(home.length)}` : path;
|
|
58
55
|
}
|
|
59
56
|
function formatSessionDate(date) {
|
|
60
57
|
const now = new Date();
|
|
@@ -107,6 +104,11 @@ function canonicalizePath(path) {
|
|
|
107
104
|
return path;
|
|
108
105
|
}
|
|
109
106
|
}
|
|
107
|
+
/** Comparison key for a session file path; follows symlinks and ignores case on Windows. */
|
|
108
|
+
function getSessionPathKey(path) {
|
|
109
|
+
const canonical = canonicalizePath(path) ?? path;
|
|
110
|
+
return process.platform === "win32" ? canonical.toLocaleLowerCase("en-US") : canonical;
|
|
111
|
+
}
|
|
110
112
|
class SessionSelectorHeader {
|
|
111
113
|
scope;
|
|
112
114
|
sortMode;
|
|
@@ -219,14 +221,14 @@ class SessionSelectorFooter {
|
|
|
219
221
|
function buildSessionTree(sessions) {
|
|
220
222
|
const byPath = new Map();
|
|
221
223
|
for (const session of sessions) {
|
|
222
|
-
const sessionPath =
|
|
224
|
+
const sessionPath = getSessionPathKey(session.path);
|
|
223
225
|
byPath.set(sessionPath, { session, children: [], latestActivity: session.modified.getTime() });
|
|
224
226
|
}
|
|
225
227
|
const roots = [];
|
|
226
228
|
for (const session of sessions) {
|
|
227
|
-
const sessionPath =
|
|
229
|
+
const sessionPath = getSessionPathKey(session.path);
|
|
228
230
|
const node = byPath.get(sessionPath);
|
|
229
|
-
const parentPath =
|
|
231
|
+
const parentPath = session.parentSessionPath ? getSessionPathKey(session.parentSessionPath) : undefined;
|
|
230
232
|
if (parentPath && byPath.has(parentPath)) {
|
|
231
233
|
byPath.get(parentPath).children.push(node);
|
|
232
234
|
}
|
|
@@ -293,7 +295,7 @@ class SessionList {
|
|
|
293
295
|
keybindings;
|
|
294
296
|
showPath = false;
|
|
295
297
|
confirmingDeletePath = null;
|
|
296
|
-
|
|
298
|
+
currentSessionPathKey;
|
|
297
299
|
onSelect;
|
|
298
300
|
onCancel;
|
|
299
301
|
onExit = () => { };
|
|
@@ -326,7 +328,7 @@ class SessionList {
|
|
|
326
328
|
this.sortMode = sortMode;
|
|
327
329
|
this.nameFilter = nameFilter;
|
|
328
330
|
this.keybindings = keybindings;
|
|
329
|
-
this.
|
|
331
|
+
this.currentSessionPathKey = currentSessionFilePath ? getSessionPathKey(currentSessionFilePath) : undefined;
|
|
330
332
|
this.filterSessions("");
|
|
331
333
|
// Handle Enter in search input - select current item
|
|
332
334
|
this.searchInput.onSubmit = () => {
|
|
@@ -396,9 +398,9 @@ class SessionList {
|
|
|
396
398
|
this.setConfirmingDeletePath(selected.session.path);
|
|
397
399
|
}
|
|
398
400
|
isCurrentSessionPath(path) {
|
|
399
|
-
if (!this.
|
|
401
|
+
if (!this.currentSessionPathKey)
|
|
400
402
|
return false;
|
|
401
|
-
return (
|
|
403
|
+
return getSessionPathKey(path) === this.currentSessionPathKey;
|
|
402
404
|
}
|
|
403
405
|
sessionPathText(session) {
|
|
404
406
|
if (this.showPath)
|
|
@@ -644,6 +646,9 @@ async function deleteSessionFile(sessionPath) {
|
|
|
644
646
|
* Component that renders a session selector
|
|
645
647
|
*/
|
|
646
648
|
export class SessionSelectorComponent extends Container {
|
|
649
|
+
get capturesViewportInput() {
|
|
650
|
+
return this.mode !== "rename";
|
|
651
|
+
}
|
|
647
652
|
handleInput(data) {
|
|
648
653
|
if (this.mode === "rename") {
|
|
649
654
|
const kb = getKeybindings();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Provenance: @earendil-works/pi-coding-agent 1.
|
|
2
|
+
* Provenance: @earendil-works/pi-coding-agent 1.5.0 (MIT), commit f9a26365568127461c47a07a37dcb42c140a3ac5,
|
|
3
3
|
* packages/coding-agent/src/modes/interactive/components/skill-invocation-message.ts.
|
|
4
4
|
* Modifications: Mechanical port uses A1's public pi-tui instance, owned theme boundary, and
|
|
5
5
|
* root-instance keybinding registry because the public coding-agent component closes over a second
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Provenance: @earendil-works/pi-coding-agent 1.
|
|
2
|
+
* Provenance: @earendil-works/pi-coding-agent 1.5.0 (MIT), commit f9a26365568127461c47a07a37dcb42c140a3ac5,
|
|
3
3
|
* packages/coding-agent/src/modes/interactive/components/skill-invocation-message.ts.
|
|
4
4
|
* Modifications: Mechanical port uses A1's public pi-tui instance, owned theme boundary, and
|
|
5
5
|
* root-instance keybinding registry because the public coding-agent component closes over a second
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Provenance: @earendil-works/pi-coding-agent 1.
|
|
2
|
+
* Provenance: @earendil-works/pi-coding-agent 1.5.0 (MIT), commit f9a26365568127461c47a07a37dcb42c140a3ac5,
|
|
3
3
|
* packages/coding-agent/src/modes/interactive/components/status-indicator.ts.
|
|
4
4
|
* Modifications: Mechanical source port with public package-root keybinding, Loader, and owned
|
|
5
5
|
* theme/countdown imports plus ECMAScript private fields.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Provenance: @earendil-works/pi-coding-agent 1.
|
|
2
|
+
* Provenance: @earendil-works/pi-coding-agent 1.5.0 (MIT), commit f9a26365568127461c47a07a37dcb42c140a3ac5,
|
|
3
3
|
* packages/coding-agent/src/modes/interactive/components/status-indicator.ts.
|
|
4
4
|
* Modifications: Mechanical source port with public package-root keybinding, Loader, and owned
|
|
5
5
|
* theme/countdown imports plus ECMAScript private fields.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Provenance: @earendil-works/pi-coding-agent 1.
|
|
2
|
+
* Provenance: @earendil-works/pi-coding-agent 1.5.0 (MIT), commit f9a26365568127461c47a07a37dcb42c140a3ac5,
|
|
3
3
|
* packages/coding-agent/src/modes/interactive/components/themed-text.ts.
|
|
4
4
|
* Modifications: Integrated invalidation-aware text into A1's owned startup header and notices;
|
|
5
5
|
* repository formatting only.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Provenance: @earendil-works/pi-coding-agent 1.
|
|
2
|
+
* Provenance: @earendil-works/pi-coding-agent 1.5.0 (MIT), commit f9a26365568127461c47a07a37dcb42c140a3ac5,
|
|
3
3
|
* packages/coding-agent/src/modes/interactive/components/themed-text.ts.
|
|
4
4
|
* Modifications: Integrated invalidation-aware text into A1's owned startup header and notices;
|
|
5
5
|
* repository formatting only.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Provenance: @earendil-works/pi-coding-agent 1.
|
|
2
|
+
* Provenance: @earendil-works/pi-coding-agent 1.5.0 (MIT), commit f9a26365568127461c47a07a37dcb42c140a3ac5,
|
|
3
3
|
* packages/coding-agent/src/modes/interactive/components/thinking-selector.ts.
|
|
4
4
|
* Modifications: Preserve the searchable thinking-level selector, current/default semantics,
|
|
5
5
|
* selection, and focus while accepting the active bare-A1 cycle-key label from the shell, styling the
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Provenance: @earendil-works/pi-coding-agent 1.
|
|
2
|
+
* Provenance: @earendil-works/pi-coding-agent 1.5.0 (MIT), commit f9a26365568127461c47a07a37dcb42c140a3ac5,
|
|
3
3
|
* packages/coding-agent/src/modes/interactive/components/thinking-selector.ts.
|
|
4
4
|
* Modifications: Preserve the searchable thinking-level selector, current/default semantics,
|
|
5
5
|
* selection, and focus while accepting the active bare-A1 cycle-key label from the shell, styling the
|
|
@@ -38,6 +38,8 @@ export declare class ToolExecutionComponent extends Container {
|
|
|
38
38
|
private cwd;
|
|
39
39
|
private executionStarted;
|
|
40
40
|
private argsComplete;
|
|
41
|
+
/** `updateArgs()` ran since the last display update; the next render applies it. */
|
|
42
|
+
private argsPending;
|
|
41
43
|
private result;
|
|
42
44
|
private hideComponent;
|
|
43
45
|
constructor(toolName: string, toolCallId: string, args: any, options: ToolExecutionOptions | undefined, toolDefinition: ToolRenderers | ToolDefinition<any, any, any> | undefined, ui: TUI, cwd: string);
|
|
@@ -46,6 +48,10 @@ export declare class ToolExecutionComponent extends Container {
|
|
|
46
48
|
private createCallFallback;
|
|
47
49
|
private createResultFallback;
|
|
48
50
|
private createResultRegion;
|
|
51
|
+
/**
|
|
52
|
+
* Show new partial arguments. Applied at the next render, so a call streaming many argument deltas between two
|
|
53
|
+
* frames runs its renderer once per frame, not once per delta (#9265).
|
|
54
|
+
*/
|
|
49
55
|
updateArgs(args: any): void;
|
|
50
56
|
markExecutionStarted(): void;
|
|
51
57
|
setArgsComplete(): void;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Provenance: @earendil-works/pi-coding-agent 1.
|
|
2
|
+
* Provenance: @earendil-works/pi-coding-agent 1.5.0 (MIT), commit f9a26365568127461c47a07a37dcb42c140a3ac5,
|
|
3
3
|
* packages/coding-agent/src/modes/interactive/components/tool-execution.ts.
|
|
4
4
|
* Modifications: Retain pinned shell/public renderers. Own image conversion; replace private APIs with
|
|
5
5
|
* public/local equivalents. Use bare-A1 secondary-accent read ranges and concise collapse shortcut
|
|
@@ -122,6 +122,8 @@ export class ToolExecutionComponent extends Container {
|
|
|
122
122
|
cwd;
|
|
123
123
|
executionStarted = false;
|
|
124
124
|
argsComplete = false;
|
|
125
|
+
/** `updateArgs()` ran since the last display update; the next render applies it. */
|
|
126
|
+
argsPending = false;
|
|
125
127
|
result;
|
|
126
128
|
hideComponent = false;
|
|
127
129
|
constructor(toolName, toolCallId, args, options = {}, toolDefinition, ui, cwd) {
|
|
@@ -179,6 +181,8 @@ export class ToolExecutionComponent extends Container {
|
|
|
179
181
|
isError: this.result?.isError ?? false,
|
|
180
182
|
durationMs: this.isPartial ? undefined : this.result?.durationMs,
|
|
181
183
|
outputPad: this.outputPad,
|
|
184
|
+
keyText,
|
|
185
|
+
keyHint,
|
|
182
186
|
};
|
|
183
187
|
}
|
|
184
188
|
createCallFallback() {
|
|
@@ -206,9 +210,14 @@ export class ToolExecutionComponent extends Container {
|
|
|
206
210
|
return { handled: true };
|
|
207
211
|
});
|
|
208
212
|
}
|
|
213
|
+
/**
|
|
214
|
+
* Show new partial arguments. Applied at the next render, so a call streaming many argument deltas between two
|
|
215
|
+
* frames runs its renderer once per frame, not once per delta (#9265).
|
|
216
|
+
*/
|
|
209
217
|
updateArgs(args) {
|
|
210
218
|
this.args = args;
|
|
211
|
-
this.
|
|
219
|
+
this.argsPending = true;
|
|
220
|
+
this.ui.requestRender();
|
|
212
221
|
}
|
|
213
222
|
markExecutionStarted() {
|
|
214
223
|
this.executionStarted = true;
|
|
@@ -257,6 +266,8 @@ export class ToolExecutionComponent extends Container {
|
|
|
257
266
|
this.updateDisplay();
|
|
258
267
|
}
|
|
259
268
|
render(width) {
|
|
269
|
+
if (this.argsPending)
|
|
270
|
+
this.updateDisplay();
|
|
260
271
|
if (this.hideComponent) {
|
|
261
272
|
return [];
|
|
262
273
|
}
|
|
@@ -336,6 +347,7 @@ export class ToolExecutionComponent extends Container {
|
|
|
336
347
|
}
|
|
337
348
|
composeDisplay() {
|
|
338
349
|
const theme = piTheme();
|
|
350
|
+
this.argsPending = false;
|
|
339
351
|
const bgFn = enclosingToolBackground(theme, this.isPartial ? "toolPendingBg"
|
|
340
352
|
: this.result?.isError ? "toolErrorBg" : "toolSuccessBg");
|
|
341
353
|
let hasContent = false;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Provenance: @earendil-works/pi-coding-agent 1.
|
|
2
|
+
* Provenance: @earendil-works/pi-coding-agent 1.5.0 (MIT), commit f9a26365568127461c47a07a37dcb42c140a3ac5,
|
|
3
3
|
* packages/coding-agent/src/modes/interactive/components/tree-selector.ts.
|
|
4
4
|
* Modifications: Port remaps public types/components plus owned keybindings/theme helpers while
|
|
5
5
|
* preserving tree behavior; bare A1 uses compact modal chrome and label editing, four-mode
|
|
@@ -106,6 +106,7 @@ export declare class TreeSelectorComponent extends Container implements Focusabl
|
|
|
106
106
|
private restoreTreeContent;
|
|
107
107
|
private showLabelInput;
|
|
108
108
|
private hideLabelInput;
|
|
109
|
+
get capturesViewportInput(): boolean;
|
|
109
110
|
handleInput(keyData: string): void;
|
|
110
111
|
getTreeList(): TreeList;
|
|
111
112
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Provenance: @earendil-works/pi-coding-agent 1.
|
|
2
|
+
* Provenance: @earendil-works/pi-coding-agent 1.5.0 (MIT), commit f9a26365568127461c47a07a37dcb42c140a3ac5,
|
|
3
3
|
* packages/coding-agent/src/modes/interactive/components/tree-selector.ts.
|
|
4
4
|
* Modifications: Port remaps public types/components plus owned keybindings/theme helpers while
|
|
5
5
|
* preserving tree behavior; bare A1 uses compact modal chrome and label editing, four-mode
|
|
@@ -807,9 +807,7 @@ class TreeList {
|
|
|
807
807
|
formatToolCall(name, args) {
|
|
808
808
|
const shortenPath = (p) => {
|
|
809
809
|
const home = process.env.HOME || process.env.USERPROFILE || "";
|
|
810
|
-
|
|
811
|
-
return `~${p.slice(home.length)}`;
|
|
812
|
-
return p;
|
|
810
|
+
return home && p.startsWith(home) ? `~${p.slice(home.length)}` : p;
|
|
813
811
|
};
|
|
814
812
|
switch (name) {
|
|
815
813
|
case "read": {
|
|
@@ -1322,6 +1320,9 @@ export class TreeSelectorComponent extends Container {
|
|
|
1322
1320
|
this.labelInputContainer.clear();
|
|
1323
1321
|
this.restoreTreeContent();
|
|
1324
1322
|
}
|
|
1323
|
+
get capturesViewportInput() {
|
|
1324
|
+
return this.labelInput === null;
|
|
1325
|
+
}
|
|
1325
1326
|
handleInput(keyData) {
|
|
1326
1327
|
if (this.labelInput) {
|
|
1327
1328
|
this.labelInput.handleInput(keyData);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Provenance: @earendil-works/pi-coding-agent 1.
|
|
2
|
+
* Provenance: @earendil-works/pi-coding-agent 1.5.0 (MIT), commit f9a26365568127461c47a07a37dcb42c140a3ac5,
|
|
3
3
|
* packages/coding-agent/src/modes/interactive/components/trust-selector.ts.
|
|
4
4
|
* Modifications: Mechanical source-synchronized trust selector port with injected public
|
|
5
5
|
* ProjectTrustStore-derived options, remapped owned theme imports, the shared bare-A1 modal shortcut
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Provenance: @earendil-works/pi-coding-agent 1.
|
|
2
|
+
* Provenance: @earendil-works/pi-coding-agent 1.5.0 (MIT), commit f9a26365568127461c47a07a37dcb42c140a3ac5,
|
|
3
3
|
* packages/coding-agent/src/modes/interactive/external-editor.ts.
|
|
4
4
|
* Modifications: Mechanical port: retain temporary prompt file, asynchronous inherited-stdio editor
|
|
5
5
|
* process, completion readback, and best-effort cleanup behind the owned extension-editor component.
|
|
@@ -16,18 +16,25 @@ export async function editInExternalEditor(options) {
|
|
|
16
16
|
writeFileSync(filePath, options.content, "utf-8");
|
|
17
17
|
const [editor, ...editorArgs] = options.command.split(" ");
|
|
18
18
|
if (!editor)
|
|
19
|
-
return { status: "failed" };
|
|
19
|
+
return { status: "failed", message: "No external editor command is configured" };
|
|
20
20
|
process.stdout.write(`Launching external editor: ${options.command}\nPi will resume when the editor exits.\n`);
|
|
21
|
-
const
|
|
21
|
+
const exit = await new Promise(resolve => {
|
|
22
22
|
const child = spawn(editor, [...editorArgs, filePath], {
|
|
23
23
|
stdio: "inherit",
|
|
24
24
|
shell: process.platform === "win32",
|
|
25
25
|
});
|
|
26
26
|
child.on("error", () => resolve(null));
|
|
27
|
-
child.on("close", code => resolve(code));
|
|
27
|
+
child.on("close", (code, signal) => resolve(code ?? signal));
|
|
28
28
|
});
|
|
29
|
-
if (
|
|
30
|
-
return { status: "failed" };
|
|
29
|
+
if (exit === null) {
|
|
30
|
+
return { status: "failed", message: `Failed to launch external editor: ${options.command}` };
|
|
31
|
+
}
|
|
32
|
+
if (exit !== 0) {
|
|
33
|
+
return {
|
|
34
|
+
status: "failed",
|
|
35
|
+
message: `External editor exited with ${typeof exit === "number" ? `code ${exit}` : exit}; prompt unchanged`,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
31
38
|
// Rationale: upstream strips the BOM through a private util the package does not export; the check lives here.
|
|
32
39
|
const edited = readFileSync(filePath, "utf-8");
|
|
33
40
|
return { status: "complete", content: (edited.startsWith("") ? edited.slice(1) : edited).replace(/\n$/, "") };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Provenance: @earendil-works/pi-tui 1.
|
|
2
|
+
* Provenance: @earendil-works/pi-tui 1.5.0 (MIT), commit f9a26365568127461c47a07a37dcb42c140a3ac5,
|
|
3
3
|
* packages/tui/src/components/editor.ts.
|
|
4
4
|
* Modifications: Owned editor core or minimal editor-local helper subset; public imports, strict
|
|
5
5
|
* types, typed persistent-history hooks, semantic border state with the user-approved numeric-only
|
|
@@ -48,6 +48,8 @@ export declare class HistoryEditorCore implements Component, Focusable {
|
|
|
48
48
|
private state;
|
|
49
49
|
/** Focusable interface - set by TUI when focus changes */
|
|
50
50
|
focused: boolean;
|
|
51
|
+
/** The open autocomplete menu receives fullscreen viewport keys, such as PageUp/PageDown. */
|
|
52
|
+
get capturesViewportInput(): boolean;
|
|
51
53
|
protected tui: TUI;
|
|
52
54
|
private theme;
|
|
53
55
|
private paddingX;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Provenance: @earendil-works/pi-tui 1.
|
|
2
|
+
* Provenance: @earendil-works/pi-tui 1.5.0 (MIT), commit f9a26365568127461c47a07a37dcb42c140a3ac5,
|
|
3
3
|
* packages/tui/src/components/editor.ts.
|
|
4
4
|
* Modifications: Owned editor core or minimal editor-local helper subset; public imports, strict
|
|
5
5
|
* types, typed persistent-history hooks, semantic border state with the user-approved numeric-only
|
|
@@ -243,6 +243,10 @@ export class HistoryEditorCore {
|
|
|
243
243
|
};
|
|
244
244
|
/** Focusable interface - set by TUI when focus changes */
|
|
245
245
|
focused = false;
|
|
246
|
+
/** The open autocomplete menu receives fullscreen viewport keys, such as PageUp/PageDown. */
|
|
247
|
+
get capturesViewportInput() {
|
|
248
|
+
return this.autocompleteState !== null;
|
|
249
|
+
}
|
|
246
250
|
tui;
|
|
247
251
|
theme;
|
|
248
252
|
paddingX = 0;
|
|
@@ -734,7 +738,10 @@ export class HistoryEditorCore {
|
|
|
734
738
|
this.cancelAutocomplete();
|
|
735
739
|
return;
|
|
736
740
|
}
|
|
737
|
-
if (kb.matches(data, "tui.select.up") ||
|
|
741
|
+
if (kb.matches(data, "tui.select.up") ||
|
|
742
|
+
kb.matches(data, "tui.select.down") ||
|
|
743
|
+
kb.matches(data, "tui.select.pageUp") ||
|
|
744
|
+
kb.matches(data, "tui.select.pageDown")) {
|
|
738
745
|
this.autocompleteList.handleInput(data);
|
|
739
746
|
return;
|
|
740
747
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Provenance: @earendil-works/pi-tui 1.
|
|
2
|
+
* Provenance: @earendil-works/pi-tui 1.5.0 (MIT), commit f9a26365568127461c47a07a37dcb42c140a3ac5,
|
|
3
3
|
* packages/tui/src/kill-ring.ts.
|
|
4
4
|
* Modifications: Owned editor core or minimal editor-local helper subset; public imports, strict
|
|
5
5
|
* types, typed persistent-history hooks, and semantic border state. Public terminal runtime/exports
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Provenance: @earendil-works/pi-tui 1.
|
|
2
|
+
* Provenance: @earendil-works/pi-tui 1.5.0 (MIT), commit f9a26365568127461c47a07a37dcb42c140a3ac5,
|
|
3
3
|
* packages/tui/src/kill-ring.ts.
|
|
4
4
|
* Modifications: Owned editor core or minimal editor-local helper subset; public imports, strict
|
|
5
5
|
* types, typed persistent-history hooks, and semantic border state. Public terminal runtime/exports
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Provenance: @earendil-works/pi-tui 1.
|
|
2
|
+
* Provenance: @earendil-works/pi-tui 1.5.0 (MIT), commit f9a26365568127461c47a07a37dcb42c140a3ac5,
|
|
3
3
|
* packages/tui/src/keys.ts.
|
|
4
4
|
* Modifications: Owned editor core or minimal editor-local helper subset; public imports, strict
|
|
5
5
|
* types, typed persistent-history hooks, and semantic border state. Public terminal runtime/exports
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Provenance: @earendil-works/pi-tui 1.
|
|
2
|
+
* Provenance: @earendil-works/pi-tui 1.5.0 (MIT), commit f9a26365568127461c47a07a37dcb42c140a3ac5,
|
|
3
3
|
* packages/tui/src/utils.ts.
|
|
4
4
|
* Modifications: Owned editor core or minimal editor-local helper subset; public imports, strict
|
|
5
5
|
* types, typed persistent-history hooks, and semantic border state. Public terminal runtime/exports
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Provenance: @earendil-works/pi-tui 1.
|
|
2
|
+
* Provenance: @earendil-works/pi-tui 1.5.0 (MIT), commit f9a26365568127461c47a07a37dcb42c140a3ac5,
|
|
3
3
|
* packages/tui/src/undo-stack.ts.
|
|
4
4
|
* Modifications: Owned editor core or minimal editor-local helper subset; public imports, strict
|
|
5
5
|
* types, typed persistent-history hooks, and semantic border state. Public terminal runtime/exports
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Provenance: @earendil-works/pi-tui 1.
|
|
2
|
+
* Provenance: @earendil-works/pi-tui 1.5.0 (MIT), commit f9a26365568127461c47a07a37dcb42c140a3ac5,
|
|
3
3
|
* packages/tui/src/undo-stack.ts.
|
|
4
4
|
* Modifications: Owned editor core or minimal editor-local helper subset; public imports, strict
|
|
5
5
|
* types, typed persistent-history hooks, and semantic border state. Public terminal runtime/exports
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Provenance: @earendil-works/pi-tui 1.
|
|
2
|
+
* Provenance: @earendil-works/pi-tui 1.5.0 (MIT), commit f9a26365568127461c47a07a37dcb42c140a3ac5,
|
|
3
3
|
* packages/tui/src/word-navigation.ts.
|
|
4
4
|
* Modifications: Owned editor core or minimal editor-local helper subset; public imports, strict
|
|
5
5
|
* types, typed persistent-history hooks, and semantic border state. Public terminal runtime/exports
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Provenance: @earendil-works/pi-coding-agent 1.
|
|
2
|
+
* Provenance: @earendil-works/pi-coding-agent 1.5.0 (MIT), commit f9a26365568127461c47a07a37dcb42c140a3ac5,
|
|
3
3
|
* packages/coding-agent/src/modes/interactive/model-search.ts.
|
|
4
4
|
* Modifications: Mechanical source-synchronized port preserving pinned model search terms for stateful
|
|
5
5
|
* scoped-model filtering.
|
|
@@ -11,6 +11,16 @@ export interface ModelSearchItem {
|
|
|
11
11
|
name?: string;
|
|
12
12
|
}
|
|
13
13
|
export declare function getModelSearchText(item: ModelSearchItem): string;
|
|
14
|
+
/**
|
|
15
|
+
* Returns the model name when it has words the ID does not, e.g. a renamed override like
|
|
16
|
+
* "MiniMax M3 [rasmus@openrouter, parasail]" for "minimax/minimax-m3". Names that only
|
|
17
|
+
* restate the ID with different casing, separators, or a dropped namespace/version suffix
|
|
18
|
+
* ("Claude Sonnet 4.5 (EU)" for "eu.anthropic.claude-sonnet-4-5-20250929-v1:0") return undefined.
|
|
19
|
+
*/
|
|
20
|
+
export declare function getDistinctModelName(item: {
|
|
21
|
+
id: string;
|
|
22
|
+
name?: string;
|
|
23
|
+
}): string | undefined;
|
|
14
24
|
/**
|
|
15
25
|
* The /model selector search should rank exact provider-prefixed queries before proxy-provider IDs
|
|
16
26
|
* like openrouter/openai/gpt-5, so keep the bare model ID out of the leading position.
|