@oh-my-pi/pi-coding-agent 13.14.2 → 13.15.3
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 +150 -0
- package/package.json +10 -8
- package/src/autoresearch/command-initialize.md +34 -0
- package/src/autoresearch/command-resume.md +17 -0
- package/src/autoresearch/contract.ts +332 -0
- package/src/autoresearch/dashboard.ts +447 -0
- package/src/autoresearch/git.ts +243 -0
- package/src/autoresearch/helpers.ts +458 -0
- package/src/autoresearch/index.ts +693 -0
- package/src/autoresearch/prompt.md +227 -0
- package/src/autoresearch/resume-message.md +16 -0
- package/src/autoresearch/state.ts +386 -0
- package/src/autoresearch/tools/init-experiment.ts +310 -0
- package/src/autoresearch/tools/log-experiment.ts +833 -0
- package/src/autoresearch/tools/run-experiment.ts +640 -0
- package/src/autoresearch/types.ts +218 -0
- package/src/cli/args.ts +8 -2
- package/src/cli/initial-message.ts +58 -0
- package/src/config/keybindings.ts +423 -212
- package/src/config/model-registry.ts +1 -0
- package/src/config/model-resolver.ts +57 -9
- package/src/config/settings-schema.ts +38 -10
- package/src/config/settings.ts +1 -4
- package/src/export/html/template.css +43 -13
- package/src/export/html/template.generated.ts +1 -1
- package/src/export/html/template.html +1 -0
- package/src/export/html/template.js +107 -0
- package/src/extensibility/extensions/types.ts +31 -8
- package/src/internal-urls/docs-index.generated.ts +1 -1
- package/src/lsp/index.ts +1 -1
- package/src/main.ts +44 -44
- package/src/mcp/oauth-discovery.ts +1 -1
- package/src/modes/acp/acp-agent.ts +957 -0
- package/src/modes/acp/acp-event-mapper.ts +531 -0
- package/src/modes/acp/acp-mode.ts +13 -0
- package/src/modes/acp/index.ts +2 -0
- package/src/modes/components/agent-dashboard.ts +5 -4
- package/src/modes/components/custom-editor.ts +53 -51
- package/src/modes/components/extensions/extension-dashboard.ts +2 -1
- package/src/modes/components/history-search.ts +2 -1
- package/src/modes/components/hook-editor.ts +2 -1
- package/src/modes/components/hook-input.ts +8 -7
- package/src/modes/components/hook-selector.ts +15 -10
- package/src/modes/components/keybinding-hints.ts +9 -9
- package/src/modes/components/login-dialog.ts +3 -3
- package/src/modes/components/mcp-add-wizard.ts +2 -1
- package/src/modes/components/model-selector.ts +14 -3
- package/src/modes/components/oauth-selector.ts +2 -1
- package/src/modes/components/session-selector.ts +2 -1
- package/src/modes/components/settings-selector.ts +2 -1
- package/src/modes/components/status-line-segment-editor.ts +2 -1
- package/src/modes/components/tree-selector.ts +3 -2
- package/src/modes/components/user-message-selector.ts +3 -8
- package/src/modes/components/user-message.ts +16 -0
- package/src/modes/controllers/extension-ui-controller.ts +89 -4
- package/src/modes/controllers/input-controller.ts +48 -29
- package/src/modes/controllers/mcp-command-controller.ts +1 -1
- package/src/modes/index.ts +1 -0
- package/src/modes/interactive-mode.ts +17 -5
- package/src/modes/print-mode.ts +1 -1
- package/src/modes/prompt-action-autocomplete.ts +7 -7
- package/src/modes/rpc/rpc-mode.ts +7 -2
- package/src/modes/rpc/rpc-types.ts +1 -0
- package/src/modes/theme/theme.ts +53 -44
- package/src/modes/types.ts +9 -2
- package/src/modes/utils/hotkeys-markdown.ts +20 -20
- package/src/modes/utils/keybinding-matchers.ts +21 -0
- package/src/modes/utils/ui-helpers.ts +1 -1
- package/src/patch/hashline.ts +139 -127
- package/src/patch/index.ts +77 -59
- package/src/patch/shared.ts +19 -11
- package/src/prompts/tools/hashline.md +43 -116
- package/src/sdk.ts +34 -17
- package/src/session/agent-session.ts +436 -86
- package/src/session/messages.ts +23 -0
- package/src/session/session-manager.ts +97 -31
- package/src/tools/ask.ts +56 -30
- package/src/tools/bash-interceptor.ts +1 -39
- package/src/tools/bash-skill-urls.ts +1 -1
- package/src/tools/browser.ts +1 -1
- package/src/tools/gemini-image.ts +1 -1
- package/src/tools/resolve.ts +1 -1
- package/src/utils/child-process.ts +88 -0
- package/src/utils/image-input.ts +11 -1
- package/src/web/search/providers/codex.ts +10 -3
|
@@ -141,6 +141,55 @@ function isAlias(id: string): boolean {
|
|
|
141
141
|
return !datePattern.test(id);
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
+
/**
|
|
145
|
+
* Find an exact model reference match.
|
|
146
|
+
* Supports either a bare model id or a canonical provider/modelId reference.
|
|
147
|
+
* When matching by bare id, ambiguous matches across providers are rejected.
|
|
148
|
+
*/
|
|
149
|
+
export function findExactModelReferenceMatch(
|
|
150
|
+
modelReference: string,
|
|
151
|
+
availableModels: Model<Api>[],
|
|
152
|
+
): Model<Api> | undefined {
|
|
153
|
+
const trimmedReference = modelReference.trim();
|
|
154
|
+
if (!trimmedReference) {
|
|
155
|
+
return undefined;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const normalizedReference = trimmedReference.toLowerCase();
|
|
159
|
+
|
|
160
|
+
const canonicalMatches = availableModels.filter(
|
|
161
|
+
model => `${model.provider}/${model.id}`.toLowerCase() === normalizedReference,
|
|
162
|
+
);
|
|
163
|
+
if (canonicalMatches.length === 1) {
|
|
164
|
+
return canonicalMatches[0];
|
|
165
|
+
}
|
|
166
|
+
if (canonicalMatches.length > 1) {
|
|
167
|
+
return undefined;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const slashIndex = trimmedReference.indexOf("/");
|
|
171
|
+
if (slashIndex !== -1) {
|
|
172
|
+
const provider = trimmedReference.substring(0, slashIndex).trim();
|
|
173
|
+
const modelId = trimmedReference.substring(slashIndex + 1).trim();
|
|
174
|
+
if (provider && modelId) {
|
|
175
|
+
const providerMatches = availableModels.filter(
|
|
176
|
+
model =>
|
|
177
|
+
model.provider.toLowerCase() === provider.toLowerCase() &&
|
|
178
|
+
model.id.toLowerCase() === modelId.toLowerCase(),
|
|
179
|
+
);
|
|
180
|
+
if (providerMatches.length === 1) {
|
|
181
|
+
return providerMatches[0];
|
|
182
|
+
}
|
|
183
|
+
if (providerMatches.length > 1) {
|
|
184
|
+
return undefined;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const idMatches = availableModels.filter(model => model.id.toLowerCase() === normalizedReference);
|
|
190
|
+
return idMatches.length === 1 ? idMatches[0] : undefined;
|
|
191
|
+
}
|
|
192
|
+
|
|
144
193
|
/**
|
|
145
194
|
* Try to match a pattern to a model from the available models list.
|
|
146
195
|
* Returns the matched model or undefined if no match found.
|
|
@@ -150,17 +199,17 @@ function tryMatchModel(
|
|
|
150
199
|
availableModels: Model<Api>[],
|
|
151
200
|
context: ModelPreferenceContext,
|
|
152
201
|
): Model<Api> | undefined {
|
|
153
|
-
//
|
|
202
|
+
// Try exact reference match first (handles provider/modelId and bare id with ambiguity rejection)
|
|
203
|
+
const exactRefMatch = findExactModelReferenceMatch(modelPattern, availableModels);
|
|
204
|
+
if (exactRefMatch) {
|
|
205
|
+
return exactRefMatch;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Check for provider/modelId format — fuzzy match within provider
|
|
154
209
|
const slashIndex = modelPattern.indexOf("/");
|
|
155
210
|
if (slashIndex !== -1) {
|
|
156
211
|
const provider = modelPattern.substring(0, slashIndex);
|
|
157
212
|
const modelId = modelPattern.substring(slashIndex + 1);
|
|
158
|
-
const providerMatch = availableModels.find(
|
|
159
|
-
m => m.provider.toLowerCase() === provider.toLowerCase() && m.id.toLowerCase() === modelId.toLowerCase(),
|
|
160
|
-
);
|
|
161
|
-
if (providerMatch) {
|
|
162
|
-
return providerMatch;
|
|
163
|
-
}
|
|
164
213
|
|
|
165
214
|
const providerModels = availableModels.filter(m => m.provider.toLowerCase() === provider.toLowerCase());
|
|
166
215
|
if (providerModels.length > 0) {
|
|
@@ -187,10 +236,9 @@ function tryMatchModel(
|
|
|
187
236
|
return scored[0]?.model;
|
|
188
237
|
}
|
|
189
238
|
}
|
|
190
|
-
// No exact provider/model match - fall through to other matching
|
|
191
239
|
}
|
|
192
240
|
|
|
193
|
-
//
|
|
241
|
+
// Exact ID match (case-insensitive) — with ambiguity across providers handled by preference
|
|
194
242
|
const exactMatches = availableModels.filter(m => m.id.toLowerCase() === modelPattern.toLowerCase());
|
|
195
243
|
if (exactMatches.length > 0) {
|
|
196
244
|
return pickPreferredModel(exactMatches, context);
|
|
@@ -139,6 +139,43 @@ type SettingDef =
|
|
|
139
139
|
// under `as const` while still letting SettingValue infer the correct element type.
|
|
140
140
|
const EMPTY_STRING_ARRAY: string[] = [];
|
|
141
141
|
const EMPTY_STRING_RECORD: Record<string, string> = {};
|
|
142
|
+
export const DEFAULT_BASH_INTERCEPTOR_RULES: BashInterceptorRule[] = [
|
|
143
|
+
{
|
|
144
|
+
pattern: "^\\s*(cat|head|tail|less|more)\\s+",
|
|
145
|
+
tool: "read",
|
|
146
|
+
message: "Use the `read` tool instead of cat/head/tail. It provides better context and handles binary files.",
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
pattern: "^\\s*(grep|rg|ripgrep|ag|ack)\\s+",
|
|
150
|
+
tool: "grep",
|
|
151
|
+
message: "Use the `grep` tool instead of grep/rg. It respects .gitignore and provides structured output.",
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
pattern: "^\\s*(find|fd|locate)\\s+.*(-name|-iname|-type|--type|-glob)",
|
|
155
|
+
tool: "find",
|
|
156
|
+
message: "Use the `find` tool instead of find/fd. It respects .gitignore and is faster for glob patterns.",
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
pattern: "^\\s*sed\\s+(-i|--in-place)",
|
|
160
|
+
tool: "edit",
|
|
161
|
+
message: "Use the `edit` tool instead of sed -i. It provides diff preview and fuzzy matching.",
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
pattern: "^\\s*perl\\s+.*-[pn]?i",
|
|
165
|
+
tool: "edit",
|
|
166
|
+
message: "Use the `edit` tool instead of perl -i. It provides diff preview and fuzzy matching.",
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
pattern: "^\\s*awk\\s+.*-i\\s+inplace",
|
|
170
|
+
tool: "edit",
|
|
171
|
+
message: "Use the `edit` tool instead of awk -i inplace. It provides diff preview and fuzzy matching.",
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
pattern: "^\\s*(echo|printf|cat\\s*<<)\\s+.*[^|]>\\s*\\S",
|
|
175
|
+
tool: "write",
|
|
176
|
+
message: "Use the `write` tool instead of echo/cat redirection. It handles encoding and provides confirmation.",
|
|
177
|
+
},
|
|
178
|
+
];
|
|
142
179
|
|
|
143
180
|
export const SETTINGS_SCHEMA = {
|
|
144
181
|
// ────────────────────────────────────────────────────────────────────────
|
|
@@ -943,16 +980,7 @@ export const SETTINGS_SCHEMA = {
|
|
|
943
980
|
default: false,
|
|
944
981
|
ui: { tab: "editing", label: "Bash Interceptor", description: "Block shell commands that have dedicated tools" },
|
|
945
982
|
},
|
|
946
|
-
|
|
947
|
-
"bashInterceptor.simpleLs": {
|
|
948
|
-
type: "boolean",
|
|
949
|
-
default: true,
|
|
950
|
-
ui: {
|
|
951
|
-
tab: "editing",
|
|
952
|
-
label: "Intercept `ls`",
|
|
953
|
-
description: "Intercept bare ls commands (when interceptor is enabled)",
|
|
954
|
-
},
|
|
955
|
-
},
|
|
983
|
+
"bashInterceptor.patterns": { type: "array", default: DEFAULT_BASH_INTERCEPTOR_RULES },
|
|
956
984
|
|
|
957
985
|
// Python
|
|
958
986
|
"python.toolMode": {
|
package/src/config/settings.ts
CHANGED
|
@@ -341,10 +341,7 @@ export class Settings {
|
|
|
341
341
|
* Get bash interceptor rules (typed accessor for complex array config).
|
|
342
342
|
*/
|
|
343
343
|
getBashInterceptorRules(): BashInterceptorRule[] {
|
|
344
|
-
|
|
345
|
-
if (!Array.isArray(patterns)) return [];
|
|
346
|
-
|
|
347
|
-
return patterns.filter((p): p is BashInterceptorRule => typeof p === "object" && p !== null && "pattern" in p);
|
|
344
|
+
return this.get("bashInterceptor.patterns");
|
|
348
345
|
}
|
|
349
346
|
|
|
350
347
|
/**
|
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
:root {
|
|
4
4
|
--line-height: 18px; /* 12px font * 1.5 */
|
|
5
|
+
--sidebar-width: 400px;
|
|
6
|
+
--sidebar-min-width: 240px;
|
|
7
|
+
--sidebar-max-width: 840px;
|
|
8
|
+
--sidebar-resizer-width: 6px;
|
|
5
9
|
}
|
|
6
10
|
|
|
7
11
|
body {
|
|
@@ -12,6 +16,11 @@
|
|
|
12
16
|
background: var(--body-bg);
|
|
13
17
|
}
|
|
14
18
|
|
|
19
|
+
body.sidebar-resizing {
|
|
20
|
+
cursor: col-resize;
|
|
21
|
+
user-select: none;
|
|
22
|
+
}
|
|
23
|
+
|
|
15
24
|
#app {
|
|
16
25
|
display: flex;
|
|
17
26
|
min-height: 100vh;
|
|
@@ -19,7 +28,9 @@
|
|
|
19
28
|
|
|
20
29
|
/* Sidebar */
|
|
21
30
|
#sidebar {
|
|
22
|
-
width:
|
|
31
|
+
width: var(--sidebar-width);
|
|
32
|
+
min-width: var(--sidebar-width);
|
|
33
|
+
max-width: var(--sidebar-width);
|
|
23
34
|
background: var(--container-bg);
|
|
24
35
|
flex-shrink: 0;
|
|
25
36
|
display: flex;
|
|
@@ -203,8 +214,28 @@
|
|
|
203
214
|
flex-shrink: 0;
|
|
204
215
|
}
|
|
205
216
|
|
|
217
|
+
#sidebar-resizer {
|
|
218
|
+
width: var(--sidebar-resizer-width);
|
|
219
|
+
flex-shrink: 0;
|
|
220
|
+
position: sticky;
|
|
221
|
+
top: 0;
|
|
222
|
+
height: 100vh;
|
|
223
|
+
cursor: col-resize;
|
|
224
|
+
touch-action: none;
|
|
225
|
+
background: transparent;
|
|
226
|
+
border-right: 1px solid transparent;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
#sidebar-resizer:hover,
|
|
230
|
+
body.sidebar-resizing #sidebar-resizer {
|
|
231
|
+
background: var(--selectedBg);
|
|
232
|
+
border-right-color: var(--dim);
|
|
233
|
+
}
|
|
234
|
+
|
|
206
235
|
/* Main content */
|
|
207
236
|
#content {
|
|
237
|
+
flex: 1;
|
|
238
|
+
min-width: 0;
|
|
208
239
|
flex: 1;
|
|
209
240
|
overflow-y: auto;
|
|
210
241
|
padding: var(--line-height) calc(var(--line-height) * 2);
|
|
@@ -841,17 +872,19 @@
|
|
|
841
872
|
@media (max-width: 900px) {
|
|
842
873
|
#sidebar {
|
|
843
874
|
position: fixed;
|
|
844
|
-
|
|
845
|
-
width:
|
|
875
|
+
transform: translateX(-100%);
|
|
876
|
+
width: min(var(--sidebar-width), 100vw);
|
|
877
|
+
min-width: 0;
|
|
878
|
+
max-width: 100vw;
|
|
846
879
|
top: 0;
|
|
847
880
|
bottom: 0;
|
|
848
881
|
height: 100vh;
|
|
849
882
|
z-index: 99;
|
|
850
|
-
transition:
|
|
883
|
+
transition: transform 0.3s;
|
|
851
884
|
}
|
|
852
885
|
|
|
853
886
|
#sidebar.open {
|
|
854
|
-
|
|
887
|
+
transform: translateX(0);
|
|
855
888
|
}
|
|
856
889
|
|
|
857
890
|
#sidebar-overlay.open {
|
|
@@ -866,6 +899,10 @@
|
|
|
866
899
|
display: block;
|
|
867
900
|
}
|
|
868
901
|
|
|
902
|
+
#sidebar-resizer {
|
|
903
|
+
display: none;
|
|
904
|
+
}
|
|
905
|
+
|
|
869
906
|
#content {
|
|
870
907
|
padding: var(--line-height) 16px;
|
|
871
908
|
}
|
|
@@ -875,15 +912,8 @@
|
|
|
875
912
|
}
|
|
876
913
|
}
|
|
877
914
|
|
|
878
|
-
@media (max-width: 500px) {
|
|
879
|
-
#sidebar {
|
|
880
|
-
width: 100vw;
|
|
881
|
-
left: -100vw;
|
|
882
|
-
}
|
|
883
|
-
}
|
|
884
|
-
|
|
885
915
|
@media print {
|
|
886
|
-
#sidebar, #sidebar-toggle { display: none !important; }
|
|
916
|
+
#sidebar, #sidebar-toggle, #sidebar-resizer { display: none !important; }
|
|
887
917
|
body { background: white; color: black; }
|
|
888
918
|
#content { max-width: none; }
|
|
889
919
|
}
|