@oh-my-pi/pi-coding-agent 15.3.2 → 15.4.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 +110 -0
- package/dist/types/cli/file-processor.d.ts +1 -1
- package/dist/types/config/settings-schema.d.ts +45 -3
- package/dist/types/config/settings.d.ts +1 -1
- package/dist/types/debug/raw-sse.d.ts +2 -0
- package/dist/types/edit/file-read-cache.d.ts +15 -4
- package/dist/types/edit/index.d.ts +3 -8
- package/dist/types/edit/renderer.d.ts +1 -2
- package/dist/types/eval/__tests__/shared-executors.test.d.ts +1 -0
- package/dist/types/eval/js/shared/local-module-loader.d.ts +16 -0
- package/dist/types/eval/js/shared/rewrite-imports.d.ts +4 -0
- package/dist/types/eval/js/shared/runtime.d.ts +14 -8
- package/dist/types/eval/py/executor.d.ts +1 -2
- package/dist/types/eval/py/kernel.d.ts +6 -0
- package/dist/types/eval/py/tool-bridge.d.ts +1 -5
- package/dist/types/eval/session-id.d.ts +3 -0
- package/dist/types/extensibility/extensions/types.d.ts +1 -3
- package/dist/types/hashline/anchors.d.ts +15 -9
- package/dist/types/hashline/constants.d.ts +0 -2
- package/dist/types/hashline/diff.d.ts +1 -2
- package/dist/types/hashline/executor.d.ts +52 -0
- package/dist/types/hashline/hash.d.ts +44 -93
- package/dist/types/hashline/index.d.ts +2 -1
- package/dist/types/hashline/input.d.ts +2 -9
- package/dist/types/hashline/recovery.d.ts +3 -9
- package/dist/types/hashline/tokenizer.d.ts +91 -0
- package/dist/types/hashline/types.d.ts +5 -7
- package/dist/types/modes/components/extensions/types.d.ts +0 -4
- package/dist/types/modes/types.d.ts +1 -0
- package/dist/types/modes/utils/ui-helpers.d.ts +1 -0
- package/dist/types/sdk.d.ts +2 -0
- package/dist/types/session/agent-session.d.ts +11 -15
- package/dist/types/session/agent-storage.d.ts +11 -10
- package/dist/types/slash-commands/acp-builtins.d.ts +3 -3
- package/dist/types/slash-commands/types.d.ts +0 -5
- package/dist/types/task/executor.d.ts +2 -0
- package/dist/types/tool-discovery/tool-index.d.ts +0 -50
- package/dist/types/tools/index.d.ts +2 -8
- package/dist/types/tools/match-line-format.d.ts +4 -4
- package/dist/types/tools/output-schema-validator.d.ts +64 -0
- package/dist/types/tools/review.d.ts +13 -0
- package/dist/types/tools/search-tool-bm25.d.ts +1 -1
- package/dist/types/tools/search.d.ts +4 -3
- package/dist/types/utils/edit-mode.d.ts +1 -1
- package/dist/types/web/kagi.d.ts +4 -2
- package/dist/types/web/parallel.d.ts +4 -3
- package/dist/types/web/scrapers/types.d.ts +2 -1
- package/dist/types/web/search/index.d.ts +12 -4
- package/dist/types/web/search/provider.d.ts +2 -1
- package/dist/types/web/search/providers/anthropic.d.ts +9 -4
- package/dist/types/web/search/providers/base.d.ts +34 -2
- package/dist/types/web/search/providers/brave.d.ts +8 -1
- package/dist/types/web/search/providers/codex.d.ts +13 -9
- package/dist/types/web/search/providers/exa.d.ts +10 -1
- package/dist/types/web/search/providers/gemini.d.ts +20 -23
- package/dist/types/web/search/providers/jina.d.ts +2 -1
- package/dist/types/web/search/providers/kagi.d.ts +4 -1
- package/dist/types/web/search/providers/kimi.d.ts +10 -1
- package/dist/types/web/search/providers/parallel.d.ts +3 -2
- package/dist/types/web/search/providers/perplexity.d.ts +5 -2
- package/dist/types/web/search/providers/searxng.d.ts +2 -1
- package/dist/types/web/search/providers/synthetic.d.ts +5 -8
- package/dist/types/web/search/providers/tavily.d.ts +11 -4
- package/dist/types/web/search/providers/utils.d.ts +8 -6
- package/dist/types/web/search/providers/zai.d.ts +12 -3
- package/package.json +7 -7
- package/src/cli/file-processor.ts +12 -2
- package/src/cli.ts +0 -8
- package/src/commands/commit.ts +8 -8
- package/src/config/prompt-templates.ts +6 -6
- package/src/config/settings-schema.ts +47 -3
- package/src/config/settings.ts +5 -5
- package/src/debug/raw-sse.ts +68 -3
- package/src/edit/file-read-cache.ts +68 -25
- package/src/edit/index.ts +6 -37
- package/src/edit/renderer.ts +9 -47
- package/src/edit/streaming.ts +43 -56
- package/src/eval/__tests__/shared-executors.test.ts +520 -0
- package/src/eval/js/context-manager.ts +64 -53
- package/src/eval/js/shared/local-module-loader.ts +265 -0
- package/src/eval/js/shared/prelude.txt +4 -0
- package/src/eval/js/shared/rewrite-imports.ts +85 -0
- package/src/eval/js/shared/runtime.ts +129 -86
- package/src/eval/js/worker-core.ts +23 -38
- package/src/eval/py/executor.ts +155 -84
- package/src/eval/py/kernel.ts +10 -1
- package/src/eval/py/prelude.py +22 -24
- package/src/eval/py/runner.py +203 -85
- package/src/eval/py/tool-bridge.ts +17 -10
- package/src/eval/session-id.ts +8 -0
- package/src/exec/bash-executor.ts +27 -16
- package/src/extensibility/extensions/runner.ts +0 -1
- package/src/extensibility/extensions/types.ts +1 -3
- package/src/hashline/anchors.ts +56 -65
- package/src/hashline/apply.ts +29 -31
- package/src/hashline/constants.ts +0 -3
- package/src/hashline/diff-preview.ts +4 -5
- package/src/hashline/diff.ts +30 -4
- package/src/hashline/execute.ts +91 -26
- package/src/hashline/executor.ts +239 -0
- package/src/hashline/grammar.lark +12 -10
- package/src/hashline/hash.ts +69 -114
- package/src/hashline/index.ts +2 -1
- package/src/hashline/input.ts +48 -41
- package/src/hashline/prefixes.ts +21 -11
- package/src/hashline/recovery.ts +63 -71
- package/src/hashline/stream.ts +2 -2
- package/src/hashline/tokenizer.ts +467 -0
- package/src/hashline/types.ts +6 -8
- package/src/internal-urls/docs-index.generated.ts +7 -7
- package/src/modes/components/extensions/types.ts +0 -5
- package/src/modes/components/session-observer-overlay.ts +11 -2
- package/src/modes/components/settings-selector.ts +10 -1
- package/src/modes/components/tree-selector.ts +10 -2
- package/src/modes/controllers/command-controller.ts +1 -3
- package/src/modes/controllers/extension-ui-controller.ts +10 -11
- package/src/modes/controllers/selector-controller.ts +5 -5
- package/src/modes/theme/theme.ts +4 -2
- package/src/modes/types.ts +4 -1
- package/src/modes/utils/ui-helpers.ts +4 -0
- package/src/prompts/agents/explore.md +1 -1
- package/src/prompts/tools/ast-edit.md +1 -1
- package/src/prompts/tools/ast-grep.md +1 -1
- package/src/prompts/tools/eval.md +1 -1
- package/src/prompts/tools/hashline.md +73 -94
- package/src/prompts/tools/read.md +4 -4
- package/src/prompts/tools/search.md +3 -3
- package/src/sdk.ts +33 -26
- package/src/session/agent-session.ts +59 -66
- package/src/session/agent-storage.ts +13 -14
- package/src/slash-commands/acp-builtins.ts +3 -3
- package/src/slash-commands/types.ts +0 -6
- package/src/task/executor.ts +26 -57
- package/src/task/index.ts +8 -4
- package/src/tool-discovery/tool-index.ts +0 -134
- package/src/tools/ast-edit.ts +36 -13
- package/src/tools/ast-grep.ts +45 -4
- package/src/tools/browser/tab-worker.ts +3 -2
- package/src/tools/eval.ts +2 -1
- package/src/tools/fetch.ts +23 -14
- package/src/tools/index.ts +2 -8
- package/src/tools/irc.ts +59 -5
- package/src/tools/match-line-format.ts +5 -7
- package/src/tools/output-schema-validator.ts +132 -0
- package/src/tools/read.ts +142 -31
- package/src/tools/review.ts +23 -0
- package/src/tools/search-tool-bm25.ts +3 -30
- package/src/tools/search.ts +48 -16
- package/src/tools/write.ts +3 -3
- package/src/tools/yield.ts +32 -41
- package/src/utils/edit-mode.ts +1 -2
- package/src/utils/file-mentions.ts +2 -2
- package/src/web/kagi.ts +15 -6
- package/src/web/parallel.ts +9 -6
- package/src/web/scrapers/types.ts +7 -1
- package/src/web/scrapers/youtube.ts +13 -7
- package/src/web/search/index.ts +37 -11
- package/src/web/search/provider.ts +5 -3
- package/src/web/search/providers/anthropic.ts +30 -21
- package/src/web/search/providers/base.ts +35 -2
- package/src/web/search/providers/brave.ts +4 -4
- package/src/web/search/providers/codex.ts +118 -89
- package/src/web/search/providers/exa.ts +3 -2
- package/src/web/search/providers/gemini.ts +58 -155
- package/src/web/search/providers/jina.ts +4 -4
- package/src/web/search/providers/kagi.ts +17 -11
- package/src/web/search/providers/kimi.ts +29 -13
- package/src/web/search/providers/parallel.ts +171 -23
- package/src/web/search/providers/perplexity.ts +38 -37
- package/src/web/search/providers/searxng.ts +3 -1
- package/src/web/search/providers/synthetic.ts +16 -19
- package/src/web/search/providers/tavily.ts +23 -18
- package/src/web/search/providers/utils.ts +11 -17
- package/src/web/search/providers/zai.ts +16 -8
- package/dist/types/hashline/parser.d.ts +0 -7
- package/dist/types/mcp/discoverable-tool-metadata.d.ts +0 -7
- package/dist/types/tools/vim.d.ts +0 -58
- package/dist/types/vim/buffer.d.ts +0 -41
- package/dist/types/vim/commands.d.ts +0 -6
- package/dist/types/vim/engine.d.ts +0 -47
- package/dist/types/vim/parser.d.ts +0 -3
- package/dist/types/vim/render.d.ts +0 -25
- package/dist/types/vim/types.d.ts +0 -182
- package/src/hashline/parser.ts +0 -246
- package/src/mcp/discoverable-tool-metadata.ts +0 -24
- package/src/prompts/tools/vim.md +0 -98
- package/src/tools/vim.ts +0 -949
- package/src/vim/buffer.ts +0 -309
- package/src/vim/commands.ts +0 -382
- package/src/vim/engine.ts +0 -2409
- package/src/vim/parser.ts +0 -134
- package/src/vim/render.ts +0 -252
- package/src/vim/types.ts +0 -197
|
@@ -143,11 +143,6 @@ export interface DashboardState {
|
|
|
143
143
|
selected: Extension | null;
|
|
144
144
|
}
|
|
145
145
|
|
|
146
|
-
/**
|
|
147
|
-
* @deprecated Use FocusRegion instead
|
|
148
|
-
*/
|
|
149
|
-
export type FocusPane = "sidebar" | "main" | "inspector";
|
|
150
|
-
|
|
151
146
|
/**
|
|
152
147
|
* Callbacks from dashboard to parent.
|
|
153
148
|
*/
|
|
@@ -22,6 +22,7 @@ import { isSilentAbort } from "../../session/messages";
|
|
|
22
22
|
import type { SessionMessageEntry } from "../../session/session-manager";
|
|
23
23
|
import { parseSessionEntries } from "../../session/session-manager";
|
|
24
24
|
import { PREVIEW_LIMITS, replaceTabs, TRUNCATE_LENGTHS, truncateToWidth } from "../../tools/render-utils";
|
|
25
|
+
import { toPathList } from "../../tools/search";
|
|
25
26
|
import type { ObservableSession, SessionObserverRegistry } from "../session-observer-registry";
|
|
26
27
|
import { getMarkdownTheme, theme } from "../theme/theme";
|
|
27
28
|
import { DynamicBorder } from "./dynamic-border";
|
|
@@ -533,13 +534,21 @@ export class SessionObserverOverlayComponent extends Container {
|
|
|
533
534
|
case "write":
|
|
534
535
|
case "edit":
|
|
535
536
|
return args.path ? `path: ${args.path}` : "";
|
|
536
|
-
case "search":
|
|
537
|
+
case "search": {
|
|
538
|
+
const searchPathsInput =
|
|
539
|
+
typeof args.paths === "string" || Array.isArray(args.paths)
|
|
540
|
+
? args.paths
|
|
541
|
+
: typeof args.path === "string"
|
|
542
|
+
? args.path
|
|
543
|
+
: undefined;
|
|
544
|
+
const searchPaths = toPathList(searchPathsInput);
|
|
537
545
|
return [
|
|
538
546
|
args.pattern ? `pattern: ${args.pattern}` : "",
|
|
539
|
-
|
|
547
|
+
searchPaths.length > 0 ? `paths: ${searchPaths.join(", ")}` : "",
|
|
540
548
|
]
|
|
541
549
|
.filter(Boolean)
|
|
542
550
|
.join(", ");
|
|
551
|
+
}
|
|
543
552
|
case "find":
|
|
544
553
|
return Array.isArray(args.paths) ? `paths: ${args.paths.join(", ")}` : "";
|
|
545
554
|
case "bash": {
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
TabBar,
|
|
14
14
|
Text,
|
|
15
15
|
} from "@oh-my-pi/pi-tui";
|
|
16
|
-
import { type SettingPath, settings } from "../../config/settings";
|
|
16
|
+
import { getDefault, type SettingPath, settings } from "../../config/settings";
|
|
17
17
|
import type {
|
|
18
18
|
SettingTab,
|
|
19
19
|
StatusLinePreset,
|
|
@@ -294,6 +294,7 @@ export class SettingsSelectorComponent extends Container {
|
|
|
294
294
|
}
|
|
295
295
|
|
|
296
296
|
const currentValue = this.#getCurrentValue(def);
|
|
297
|
+
const changed = this.#isChanged(def, currentValue);
|
|
297
298
|
|
|
298
299
|
switch (def.type) {
|
|
299
300
|
case "boolean":
|
|
@@ -303,6 +304,7 @@ export class SettingsSelectorComponent extends Container {
|
|
|
303
304
|
description: def.description,
|
|
304
305
|
currentValue: currentValue ? "true" : "false",
|
|
305
306
|
values: ["true", "false"],
|
|
307
|
+
changed,
|
|
306
308
|
};
|
|
307
309
|
|
|
308
310
|
case "enum":
|
|
@@ -312,6 +314,7 @@ export class SettingsSelectorComponent extends Container {
|
|
|
312
314
|
description: def.description,
|
|
313
315
|
currentValue: currentValue as string,
|
|
314
316
|
values: [...def.values],
|
|
317
|
+
changed,
|
|
315
318
|
};
|
|
316
319
|
|
|
317
320
|
case "submenu":
|
|
@@ -321,6 +324,7 @@ export class SettingsSelectorComponent extends Container {
|
|
|
321
324
|
description: def.description,
|
|
322
325
|
currentValue: this.#getSubmenuCurrentValue(def.path, currentValue),
|
|
323
326
|
submenu: (cv, done) => this.#createSubmenu(def, cv, done),
|
|
327
|
+
changed,
|
|
324
328
|
};
|
|
325
329
|
|
|
326
330
|
case "text":
|
|
@@ -330,6 +334,7 @@ export class SettingsSelectorComponent extends Container {
|
|
|
330
334
|
description: def.description,
|
|
331
335
|
currentValue: (currentValue as string) ?? "",
|
|
332
336
|
submenu: (cv, done) => this.#createTextInput(def, cv, done),
|
|
337
|
+
changed,
|
|
333
338
|
};
|
|
334
339
|
}
|
|
335
340
|
}
|
|
@@ -341,6 +346,10 @@ export class SettingsSelectorComponent extends Container {
|
|
|
341
346
|
return settings.get(def.path);
|
|
342
347
|
}
|
|
343
348
|
|
|
349
|
+
#isChanged(def: SettingDef, currentValue: unknown): boolean {
|
|
350
|
+
return !Object.is(currentValue, getDefault(def.path));
|
|
351
|
+
}
|
|
352
|
+
|
|
344
353
|
#getSubmenuCurrentValue(path: SettingPath, value: unknown): string {
|
|
345
354
|
const rawValue = String(value ?? "");
|
|
346
355
|
if (path === "compaction.thresholdPercent" && (rawValue === "-1" || rawValue === "")) {
|
|
@@ -15,6 +15,7 @@ import { theme } from "../../modes/theme/theme";
|
|
|
15
15
|
import { matchesAppInterrupt } from "../../modes/utils/keybinding-matchers";
|
|
16
16
|
import type { SessionTreeNode } from "../../session/session-manager";
|
|
17
17
|
import { shortenPath } from "../../tools/render-utils";
|
|
18
|
+
import { toPathList } from "../../tools/search";
|
|
18
19
|
import { DynamicBorder } from "./dynamic-border";
|
|
19
20
|
|
|
20
21
|
/** Gutter info: position (displayIndent where connector was) and whether to show │ */
|
|
@@ -690,8 +691,15 @@ class TreeList implements Component {
|
|
|
690
691
|
}
|
|
691
692
|
case "search": {
|
|
692
693
|
const pattern = String(args.pattern || "");
|
|
693
|
-
const
|
|
694
|
-
|
|
694
|
+
const searchPathsInput =
|
|
695
|
+
typeof args.paths === "string" || Array.isArray(args.paths)
|
|
696
|
+
? args.paths
|
|
697
|
+
: typeof args.path === "string"
|
|
698
|
+
? args.path
|
|
699
|
+
: undefined;
|
|
700
|
+
const paths = toPathList(searchPathsInput);
|
|
701
|
+
const scope = paths.length > 0 ? paths.join(", ") : ".";
|
|
702
|
+
return `[search: /${pattern}/ in ${shortenPath(scope)}]`;
|
|
695
703
|
}
|
|
696
704
|
case "find": {
|
|
697
705
|
const paths = Array.isArray(args.paths) ? args.paths.join(", ") : String(args.pattern || ".");
|
|
@@ -894,8 +894,6 @@ export class CommandController {
|
|
|
894
894
|
this.ctx.statusLine.setSessionStartTime(Date.now());
|
|
895
895
|
this.ctx.updateEditorTopBorder();
|
|
896
896
|
this.ctx.updateEditorBorderColor();
|
|
897
|
-
this.ctx.ui.requestRender();
|
|
898
|
-
|
|
899
897
|
this.ctx.chatContainer.clear();
|
|
900
898
|
this.ctx.pendingMessagesContainer.clear();
|
|
901
899
|
this.ctx.compactionQueuedMessages = [];
|
|
@@ -906,7 +904,7 @@ export class CommandController {
|
|
|
906
904
|
this.ctx.chatContainer.addChild(new Spacer(1));
|
|
907
905
|
this.ctx.chatContainer.addChild(new Text(`${theme.fg("accent", `${theme.status.success} ${label}`)}`, 1, 1));
|
|
908
906
|
await this.ctx.reloadTodos();
|
|
909
|
-
this.ctx.ui.requestRender();
|
|
907
|
+
this.ctx.ui.requestRender(true, { clearScrollback: true });
|
|
910
908
|
}
|
|
911
909
|
|
|
912
910
|
async handleClearCommand(): Promise<void> {
|
|
@@ -135,7 +135,7 @@ export class ExtensionUiController {
|
|
|
135
135
|
reload: async () => {
|
|
136
136
|
await this.ctx.session.reload();
|
|
137
137
|
this.ctx.chatContainer.clear();
|
|
138
|
-
this.ctx.renderInitialMessages();
|
|
138
|
+
this.ctx.renderInitialMessages(undefined, { clearTerminalHistory: true });
|
|
139
139
|
await this.ctx.reloadTodos();
|
|
140
140
|
this.ctx.showStatus("Reloaded session");
|
|
141
141
|
},
|
|
@@ -180,7 +180,7 @@ export class ExtensionUiController {
|
|
|
180
180
|
new Text(`${theme.fg("accent", `${theme.status.success} New session started`)}`, 1, 1),
|
|
181
181
|
);
|
|
182
182
|
await this.ctx.reloadTodos();
|
|
183
|
-
this.ctx.ui.requestRender();
|
|
183
|
+
this.ctx.ui.requestRender(true, { clearScrollback: true });
|
|
184
184
|
|
|
185
185
|
return { cancelled: false };
|
|
186
186
|
},
|
|
@@ -192,7 +192,7 @@ export class ExtensionUiController {
|
|
|
192
192
|
|
|
193
193
|
// Update UI
|
|
194
194
|
this.ctx.chatContainer.clear();
|
|
195
|
-
this.ctx.renderInitialMessages();
|
|
195
|
+
this.ctx.renderInitialMessages(undefined, { clearTerminalHistory: true });
|
|
196
196
|
await this.ctx.reloadTodos();
|
|
197
197
|
this.ctx.editor.setText(result.selectedText);
|
|
198
198
|
this.ctx.showStatus("Branched to new session");
|
|
@@ -207,7 +207,7 @@ export class ExtensionUiController {
|
|
|
207
207
|
|
|
208
208
|
// Update UI
|
|
209
209
|
this.ctx.chatContainer.clear();
|
|
210
|
-
this.ctx.renderInitialMessages();
|
|
210
|
+
this.ctx.renderInitialMessages(undefined, { clearTerminalHistory: true });
|
|
211
211
|
await this.ctx.reloadTodos();
|
|
212
212
|
if (result.editorText && !this.ctx.editor.getText().trim()) {
|
|
213
213
|
this.ctx.editor.setText(result.editorText);
|
|
@@ -225,7 +225,7 @@ export class ExtensionUiController {
|
|
|
225
225
|
}
|
|
226
226
|
setSessionTerminalTitle(this.ctx.sessionManager.getSessionName(), this.ctx.sessionManager.getCwd());
|
|
227
227
|
this.ctx.chatContainer.clear();
|
|
228
|
-
this.ctx.renderInitialMessages();
|
|
228
|
+
this.ctx.renderInitialMessages(undefined, { clearTerminalHistory: true });
|
|
229
229
|
await this.ctx.reloadTodos();
|
|
230
230
|
return { cancelled: false };
|
|
231
231
|
},
|
|
@@ -378,7 +378,7 @@ export class ExtensionUiController {
|
|
|
378
378
|
}
|
|
379
379
|
await this.ctx.session.reload();
|
|
380
380
|
this.ctx.chatContainer.clear();
|
|
381
|
-
this.ctx.renderInitialMessages();
|
|
381
|
+
this.ctx.renderInitialMessages(undefined, { clearTerminalHistory: true });
|
|
382
382
|
await this.ctx.reloadTodos();
|
|
383
383
|
this.ctx.showStatus("Reloaded session");
|
|
384
384
|
},
|
|
@@ -419,7 +419,7 @@ export class ExtensionUiController {
|
|
|
419
419
|
new Text(`${theme.fg("accent", `${theme.status.success} New session started`)}`, 1, 1),
|
|
420
420
|
);
|
|
421
421
|
await this.ctx.reloadTodos();
|
|
422
|
-
this.ctx.ui.requestRender();
|
|
422
|
+
this.ctx.ui.requestRender(true, { clearScrollback: true });
|
|
423
423
|
|
|
424
424
|
return { cancelled: false };
|
|
425
425
|
},
|
|
@@ -434,7 +434,7 @@ export class ExtensionUiController {
|
|
|
434
434
|
|
|
435
435
|
// Update UI
|
|
436
436
|
this.ctx.chatContainer.clear();
|
|
437
|
-
this.ctx.renderInitialMessages();
|
|
437
|
+
this.ctx.renderInitialMessages(undefined, { clearTerminalHistory: true });
|
|
438
438
|
await this.ctx.reloadTodos();
|
|
439
439
|
this.ctx.editor.setText(result.selectedText);
|
|
440
440
|
this.ctx.showStatus("Branched to new session");
|
|
@@ -452,7 +452,7 @@ export class ExtensionUiController {
|
|
|
452
452
|
|
|
453
453
|
// Update UI
|
|
454
454
|
this.ctx.chatContainer.clear();
|
|
455
|
-
this.ctx.renderInitialMessages();
|
|
455
|
+
this.ctx.renderInitialMessages(undefined, { clearTerminalHistory: true });
|
|
456
456
|
await this.ctx.reloadTodos();
|
|
457
457
|
if (result.editorText && !this.ctx.editor.getText().trim()) {
|
|
458
458
|
this.ctx.editor.setText(result.editorText);
|
|
@@ -472,7 +472,7 @@ export class ExtensionUiController {
|
|
|
472
472
|
return { cancelled: true };
|
|
473
473
|
}
|
|
474
474
|
this.ctx.chatContainer.clear();
|
|
475
|
-
this.ctx.renderInitialMessages();
|
|
475
|
+
this.ctx.renderInitialMessages(undefined, { clearTerminalHistory: true });
|
|
476
476
|
await this.ctx.reloadTodos();
|
|
477
477
|
return { cancelled: false };
|
|
478
478
|
},
|
|
@@ -537,7 +537,6 @@ export class ExtensionUiController {
|
|
|
537
537
|
model: this.ctx.session.model,
|
|
538
538
|
isIdle: () => !this.ctx.session.isStreaming,
|
|
539
539
|
hasPendingMessages: () => this.ctx.session.queuedMessageCount > 0,
|
|
540
|
-
hasQueuedMessages: () => this.ctx.session.queuedMessageCount > 0,
|
|
541
540
|
abort: () => {
|
|
542
541
|
this.ctx.session.abort();
|
|
543
542
|
},
|
|
@@ -553,7 +553,7 @@ export class SelectorController {
|
|
|
553
553
|
}
|
|
554
554
|
|
|
555
555
|
this.ctx.chatContainer.clear();
|
|
556
|
-
this.ctx.renderInitialMessages();
|
|
556
|
+
this.ctx.renderInitialMessages(undefined, { clearTerminalHistory: true });
|
|
557
557
|
this.ctx.editor.setText(result.selectedText);
|
|
558
558
|
done();
|
|
559
559
|
this.ctx.showStatus("Branched to new session");
|
|
@@ -664,7 +664,7 @@ export class SelectorController {
|
|
|
664
664
|
|
|
665
665
|
// Update UI — pass the context built by navigateTree to skip a second O(N) walk.
|
|
666
666
|
this.ctx.chatContainer.clear();
|
|
667
|
-
this.ctx.renderInitialMessages(result.sessionContext);
|
|
667
|
+
this.ctx.renderInitialMessages(result.sessionContext, { clearTerminalHistory: true });
|
|
668
668
|
await this.ctx.reloadTodos();
|
|
669
669
|
if (result.editorText && !this.ctx.editor.getText().trim()) {
|
|
670
670
|
this.ctx.editor.setText(result.editorText);
|
|
@@ -772,9 +772,9 @@ export class SelectorController {
|
|
|
772
772
|
this.ctx.statusLine.setSessionStartTime(Date.now());
|
|
773
773
|
this.ctx.updateEditorTopBorder();
|
|
774
774
|
this.ctx.updateEditorBorderColor();
|
|
775
|
-
this.ctx.renderInitialMessages();
|
|
775
|
+
this.ctx.renderInitialMessages(undefined, { clearTerminalHistory: true });
|
|
776
776
|
await this.ctx.reloadTodos();
|
|
777
|
-
this.ctx.ui.requestRender();
|
|
777
|
+
this.ctx.ui.requestRender(true, { clearScrollback: true });
|
|
778
778
|
return true;
|
|
779
779
|
}
|
|
780
780
|
|
|
@@ -788,7 +788,7 @@ export class SelectorController {
|
|
|
788
788
|
|
|
789
789
|
// Clear and re-render the chat
|
|
790
790
|
this.ctx.chatContainer.clear();
|
|
791
|
-
this.ctx.renderInitialMessages();
|
|
791
|
+
this.ctx.renderInitialMessages(undefined, { clearTerminalHistory: true });
|
|
792
792
|
await this.ctx.reloadTodos();
|
|
793
793
|
this.ctx.showStatus("Resumed session");
|
|
794
794
|
}
|
package/src/modes/theme/theme.ts
CHANGED
|
@@ -2404,8 +2404,10 @@ export function getEditorTheme(): EditorTheme {
|
|
|
2404
2404
|
|
|
2405
2405
|
export function getSettingsListTheme(): import("@oh-my-pi/pi-tui").SettingsListTheme {
|
|
2406
2406
|
return {
|
|
2407
|
-
label: (text: string, selected: boolean
|
|
2408
|
-
|
|
2407
|
+
label: (text: string, selected: boolean, changed: boolean) =>
|
|
2408
|
+
changed ? theme.fg("statusLineGitDirty", text) : selected ? theme.fg("accent", text) : text,
|
|
2409
|
+
value: (text: string, selected: boolean, changed: boolean) =>
|
|
2410
|
+
selected ? theme.fg("accent", text) : changed ? theme.fg("statusLineGitDirty", text) : theme.fg("muted", text),
|
|
2409
2411
|
description: (text: string) => theme.fg("dim", text),
|
|
2410
2412
|
cursor: theme.fg("accent", `${theme.nav.cursor} `),
|
|
2411
2413
|
hint: (text: string) => theme.fg("dim", text),
|
package/src/modes/types.ts
CHANGED
|
@@ -186,7 +186,10 @@ export interface InteractiveModeContext {
|
|
|
186
186
|
sessionContext: SessionContext,
|
|
187
187
|
options?: { updateFooter?: boolean; populateHistory?: boolean },
|
|
188
188
|
): void;
|
|
189
|
-
renderInitialMessages(
|
|
189
|
+
renderInitialMessages(
|
|
190
|
+
prebuiltContext?: SessionContext,
|
|
191
|
+
options?: { preserveExistingChat?: boolean; clearTerminalHistory?: boolean },
|
|
192
|
+
): void;
|
|
190
193
|
getUserMessageText(message: Message): string;
|
|
191
194
|
findLastAssistantMessage(): AssistantMessage | undefined;
|
|
192
195
|
extractAssistantText(message: AssistantMessage): string;
|
|
@@ -31,6 +31,7 @@ import { formatBytes, formatDuration } from "../../tools/render-utils";
|
|
|
31
31
|
type TextBlock = { type: "text"; text: string };
|
|
32
32
|
interface RenderInitialMessagesOptions {
|
|
33
33
|
preserveExistingChat?: boolean;
|
|
34
|
+
clearTerminalHistory?: boolean;
|
|
34
35
|
}
|
|
35
36
|
|
|
36
37
|
type QueuedMessages = {
|
|
@@ -490,6 +491,9 @@ export class UiHelpers {
|
|
|
490
491
|
const times = compactionCount === 1 ? "1 time" : `${compactionCount} times`;
|
|
491
492
|
this.ctx.showStatus(`Session compacted ${times}`);
|
|
492
493
|
}
|
|
494
|
+
if (options.clearTerminalHistory) {
|
|
495
|
+
this.ctx.ui.requestRender(true, { clearScrollback: true });
|
|
496
|
+
}
|
|
493
497
|
if (preservedChatChildren && preservedChatChildren.length > 0) {
|
|
494
498
|
for (const child of preservedChatChildren) {
|
|
495
499
|
this.ctx.chatContainer.addChild(child);
|
|
@@ -15,7 +15,7 @@ output:
|
|
|
15
15
|
description: Files examined with relevant code references
|
|
16
16
|
elements:
|
|
17
17
|
properties:
|
|
18
|
-
|
|
18
|
+
path:
|
|
19
19
|
metadata:
|
|
20
20
|
description: Project-relative path or paths to the most relevant code reference(s), optionally suffixed with line ranges like `:12-34` when relevant
|
|
21
21
|
type: string
|
|
@@ -14,7 +14,7 @@ Performs structural AST-aware rewrites via native ast-grep.
|
|
|
14
14
|
</instruction>
|
|
15
15
|
|
|
16
16
|
<output>
|
|
17
|
-
- Replacement summary, per-file replacement counts, and change diffs as `-
|
|
17
|
+
- Replacement summary, per-file replacement counts, and change diffs as `¶src/foo.ts#1a2b`, `-12:before`, `+12:after` lines in hashline mode
|
|
18
18
|
- Parse issues when files cannot be processed
|
|
19
19
|
</output>
|
|
20
20
|
|
|
@@ -18,7 +18,7 @@ Performs structural code search using AST matching via native ast-grep.
|
|
|
18
18
|
|
|
19
19
|
<output>
|
|
20
20
|
- Grouped matches with file path, byte range, line/column ranges, metavariable captures
|
|
21
|
-
- Match lines are
|
|
21
|
+
- Match lines are numbered under a file-hash header in hashline mode: `¶src/foo.ts#1a2b`, `*42:content` for the matched line, ` 43:content` for context
|
|
22
22
|
- Summary counts (`totalMatches`, `filesWithMatches`, `filesSearched`) and parse issues when present
|
|
23
23
|
</output>
|
|
24
24
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Run code in a persistent kernel using a list of cells.
|
|
2
2
|
|
|
3
3
|
<instruction>
|
|
4
|
-
Each call submits one or more cells. Cells run in array order. State persists within each language across cells
|
|
4
|
+
Each call submits one or more cells. Cells run in array order. State persists within each language across cells, tool calls, and subagents spawned with `task`; variables a parent or subagent declares are visible to the other on the same shared executor.
|
|
5
5
|
|
|
6
6
|
Cell fields:
|
|
7
7
|
|
|
@@ -1,130 +1,109 @@
|
|
|
1
1
|
Your patch language is a compact, line-anchored edit format.
|
|
2
2
|
|
|
3
|
-
A patch contains one or more file sections.
|
|
4
|
-
Operations reference lines in the file by their line number and hash, called "Anchors", e.g. `5th`, `123ab`.
|
|
5
|
-
You MUST copy them verbatim from the latest output for the file you're editing.
|
|
3
|
+
A patch contains one or more file sections. Each anchored section starts with `¶PATH#HASH`, copied verbatim from the latest `read`/`search` output. `HASH` is a 4-hex file hash; `¶PATH` without `#HASH` is allowed only for new-file / `BOF` / `EOF` boundary inserts.
|
|
6
4
|
|
|
7
|
-
|
|
5
|
+
Operations reference lines by bare line number (`5`, `123`). Payload text is verbatim — NEVER escape unicode. The tool has NO awareness of language, indentation, brackets, fences, or table widths. Emit valid syntax in replacements/insertions.
|
|
8
6
|
|
|
9
7
|
<ops>
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
8
|
+
¶PATH#HASH header: subsequent anchored ops apply to PATH at file hash HASH
|
|
9
|
+
¶PATH unbound header: only BOF/EOF boundary inserts
|
|
10
|
+
LINE↑PAYLOAD insert ABOVE the anchored line (or BOF)
|
|
11
|
+
LINE↓PAYLOAD insert BELOW the anchored line (or EOF)
|
|
12
|
+
A-B:PAYLOAD replace the inclusive range A..B with PAYLOAD
|
|
13
|
+
A:PAYLOAD shorthand for A-A:PAYLOAD
|
|
14
|
+
A-B! delete the inclusive range A..B (payload forbidden)
|
|
15
|
+
A! shorthand for A-A!
|
|
16
16
|
</ops>
|
|
17
17
|
|
|
18
|
+
<payload>
|
|
19
|
+
- The first payload line is whatever follows the sigil on the op line. Additional payload lines follow on the next lines and append after the first.
|
|
20
|
+
- An empty inline IS an empty first line. So bare `A↓` / `A↑` insert one blank line; bare `A:` / `A-B:` replace with one blank line. `A↓\nfoo` inserts blank-then-`foo`, NOT just `foo`.
|
|
21
|
+
- Payload ends at the next op, next `¶PATH`, envelope marker, or EOF. Blank lines immediately before a next op or `¶PATH` are dropped; blank lines between content lines are preserved.
|
|
22
|
+
</payload>
|
|
23
|
+
|
|
18
24
|
<rules>
|
|
19
|
-
-
|
|
20
|
-
- Payload
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
-
|
|
24
|
-
- `»`/`«` adds at the anchor; NEVER repeat line A or neighbors.
|
|
25
|
-
- Payload matching nearby content duplicates — drop it or widen.
|
|
26
|
-
- **Pick a self-contained unit first.** Touching a multiline construct? Widen to the whole thing.
|
|
27
|
-
- Then smallest op: add → `»`/`«`; delete/replace → `≔`.
|
|
25
|
+
- The sigil tells where content lands: `↑` above, `↓` below, `:` replaces, `!` deletes.
|
|
26
|
+
- **Payload is only what's NEW relative to your range.** `:` replaces inside; `↑`/`↓` add at anchor. NEVER repeat the anchor line or neighbors — that duplicates them.
|
|
27
|
+
- **Pick a self-contained unit.** Touching a multiline construct (return, array, brace block, JSX element)? Widen the range to span it. Don't bisect.
|
|
28
|
+
- Smallest op wins: add with `↑`/`↓`; replace with `:`; delete with `!`.
|
|
29
|
+
- Anchors reference the file as last read. ONE patch, ONE coordinate space — later ops still use original line numbers.
|
|
28
30
|
</rules>
|
|
29
31
|
|
|
30
|
-
<brace-shapes>
|
|
31
|
-
When braces bound your edit, you SHOULD prefer these shapes:
|
|
32
|
-
- **Whole block**: range spans `{` through matching `}`.
|
|
33
|
-
- **Signature only**: one-line `≔` on the opener; body untouched.
|
|
34
|
-
- **Insert inside**: anchor on `{` or last interior line; NEVER repeat the braces.
|
|
35
|
-
- **End on `}`**: only when that `}` is part of the change. Otherwise extend or stop earlier.
|
|
36
|
-
</brace-shapes>
|
|
37
|
-
|
|
38
32
|
<common-failures>
|
|
39
33
|
- **NEVER replay past your range.** Stop before B+1; extend B if it must go.
|
|
40
|
-
- **NEVER duplicate chunks inside one payload.**
|
|
41
|
-
- **
|
|
42
|
-
- **
|
|
43
|
-
-
|
|
44
|
-
- **One `»`/`«` op per block, NOT per line.** N lines = ONE op, N payloads. Collapse adjacent ops.
|
|
45
|
-
- **NEVER fabricate anchor hashes.** Missing? Re-`read`.
|
|
34
|
+
- **NEVER duplicate chunks inside one payload.**
|
|
35
|
+
- **Read lines look like replace ops.** `84:content` already means "make line 84 equal to content" — don't echo a context line before it.
|
|
36
|
+
- **NEVER fabricate file hashes.** Missing? Re-`read`.
|
|
37
|
+
- **`A!` deletes silently.** Deleting a line that closes/opens a block (`}`, `} else {`, `})`, `*/`) breaks structure with no parse error.
|
|
46
38
|
</common-failures>
|
|
47
39
|
|
|
48
40
|
<case file="mod.ts">
|
|
49
|
-
|
|
50
|
-
{{hline
|
|
51
|
-
{{hline
|
|
52
|
-
{{hline
|
|
53
|
-
{{hline
|
|
54
|
-
{{hline
|
|
41
|
+
¶mod.ts#1a2b
|
|
42
|
+
{{hline 1 'const TITLE = "Mr";'}}
|
|
43
|
+
{{hline 2 'export function greet(name) {'}}
|
|
44
|
+
{{hline 3 ' return ['}}
|
|
45
|
+
{{hline 4 ' TITLE,'}}
|
|
46
|
+
{{hline 5 ' name?.trim() || "guest",'}}
|
|
47
|
+
{{hline 6 ' ].join(" ");'}}
|
|
55
48
|
{{hline 7 "}"}}
|
|
56
49
|
</case>
|
|
57
50
|
|
|
58
51
|
<examples>
|
|
59
|
-
# Replace one line (
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
#
|
|
65
|
-
|
|
66
|
-
≔{{hrefr 3}}..{{hrefr 6}}
|
|
67
|
-
return [
|
|
52
|
+
# Replace one line (inline payload preserves original indentation)
|
|
53
|
+
¶mod.ts#1a2b
|
|
54
|
+
{{hrefr 1}}:const TITLE = "Mrs";
|
|
55
|
+
|
|
56
|
+
# Replace a multiline statement — first line inline, rest below
|
|
57
|
+
¶mod.ts#1a2b
|
|
58
|
+
{{hrefr 3}}-{{hrefr 6}}: return [
|
|
68
59
|
"Mrs",
|
|
69
60
|
name?.trim() || "guest",
|
|
70
61
|
].join(" ");
|
|
71
62
|
|
|
72
|
-
# Insert
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
"Dr",
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
63
|
+
# Insert ABOVE / BELOW a line
|
|
64
|
+
¶mod.ts#1a2b
|
|
65
|
+
{{hrefr 4}}↓ "Dr",
|
|
66
|
+
{{hrefr 5}}↑ "Dr",
|
|
67
|
+
|
|
68
|
+
# Delete one line / blank a line / insert a blank line
|
|
69
|
+
¶mod.ts#1a2b
|
|
70
|
+
{{hrefr 5}}!
|
|
71
|
+
{{hrefr 6}}:
|
|
72
|
+
{{hrefr 7}}↑
|
|
73
|
+
|
|
74
|
+
# Create a file / append to one (hash optional for boundary-only inserts)
|
|
75
|
+
¶new.ts
|
|
76
|
+
BOF↓export const done = true;
|
|
77
|
+
¶mod.ts
|
|
78
|
+
EOF↓export const done = true;
|
|
79
|
+
|
|
80
|
+
# Multi-file patch
|
|
81
|
+
¶src/a.ts#1a2b
|
|
82
|
+
12:const enabled = true;
|
|
83
|
+
¶src/b.ts#3c4d
|
|
84
|
+
20!
|
|
94
85
|
</examples>
|
|
95
86
|
|
|
96
87
|
<anti-pattern>
|
|
97
88
|
# WRONG — replaces 2 lines just to add one.
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
const TITLE = "Mr";
|
|
89
|
+
¶mod.ts#1a2b
|
|
90
|
+
{{hrefr 1}}-{{hrefr 2}}:const TITLE = "Mr";
|
|
101
91
|
const DEBUG = false;
|
|
102
92
|
export function greet(name) {
|
|
103
|
-
# RIGHT — same effect, one-line insert
|
|
104
|
-
§mod.ts
|
|
105
|
-
»{{hrefr 1}}
|
|
106
|
-
const DEBUG = false;
|
|
107
93
|
|
|
108
|
-
#
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
94
|
+
# RIGHT — one-line insert
|
|
95
|
+
¶mod.ts#1a2b
|
|
96
|
+
{{hrefr 1}}↓const DEBUG = false;
|
|
97
|
+
|
|
98
|
+
# WRONG — bisects a multiline statement
|
|
99
|
+
¶mod.ts#1a2b
|
|
100
|
+
{{hrefr 4}}-{{hrefr 5}}: "Dr",
|
|
112
101
|
name?.trim() || "guest",
|
|
102
|
+
|
|
113
103
|
# RIGHT — widen to the full statement
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
return [
|
|
104
|
+
¶mod.ts#1a2b
|
|
105
|
+
{{hrefr 3}}-{{hrefr 6}}: return [
|
|
117
106
|
"Dr",
|
|
118
107
|
name?.trim() || "guest",
|
|
119
108
|
].join(" ");
|
|
120
109
|
</anti-pattern>
|
|
121
|
-
|
|
122
|
-
<critical>
|
|
123
|
-
- Copy anchors verbatim (line number + 2-char hash); NEVER include the `|TEXT` body.
|
|
124
|
-
- NEVER write unified diff syntax. Headers are `§PATH`; ops are `»`/`«`/`≔`.
|
|
125
|
-
- `≔A..B` deletes the range when no payload follows. To keep a blank line, include one explicit empty payload line.
|
|
126
|
-
- `≔A..B` with payload writes exactly that payload. Edge line matches just outside? Widen, or it duplicates.
|
|
127
|
-
- Multiple ops are cheap. SHOULD prefer two narrow ops over one wide `≔`.
|
|
128
|
-
- Before `≔A..B`, mentally delete A..B. Splits an unclosed bracket/brace/string from above, or orphans a closer inside? You're bisecting a construct.
|
|
129
|
-
- NEVER use this tool to reformat code (indentation, whitespace, line wrapping, style). Run the project's formatter instead.
|
|
130
|
-
</critical>
|
|
@@ -28,17 +28,17 @@ Append `:<sel>` to `path`. The bare path falls back to the default mode.
|
|
|
28
28
|
|
|
29
29
|
- Reading a directory path returns a depth-limited dirent listing.
|
|
30
30
|
{{#if IS_HL_MODE}}
|
|
31
|
-
- Reading a file with an explicit selector
|
|
31
|
+
- Reading a file with an explicit selector emits a file-hash header and numbered lines: `¶src/foo.ts#1a2b` then `41:def alpha():`. Copy the `¶PATH#HASH` header for anchored edits; ops use bare line numbers. NEVER fabricate the hash.
|
|
32
32
|
{{else}}
|
|
33
33
|
{{#if IS_LINE_NUMBER_MODE}}
|
|
34
34
|
- Reading a file with an explicit selector returns lines prefixed with line numbers: `41|def alpha():`.
|
|
35
35
|
{{/if}}
|
|
36
36
|
{{/if}}
|
|
37
|
-
- Parseable code without a selector returns a **structural summary**: declarations kept, large bodies collapsed to `..` (merged brace pair) or `…` (standalone). Summarized output ends with a footer
|
|
37
|
+
- Parseable code without a selector returns a **structural summary**: declarations kept, large bodies collapsed to `..` (merged brace pair) or `…` (standalone). Summarized output ends with a footer demonstrating the multi-range selector you can use to recover the elided bodies, e.g.:
|
|
38
38
|
|
|
39
|
-
`[NN lines
|
|
39
|
+
`[NN lines elided; re-read needed ranges, e.g. <path>:5-16,40-80]`
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
Re-issue **only the relevant range(s)** using the multi-range selector (e.g. `<path>:5-16,120-200`). NEVER guess what's inside `..` / `…` — those markers carry no content. NEVER re-read the whole file or use `:raw` when targeted ranges suffice.
|
|
42
42
|
|
|
43
43
|
# Documents & Notebooks
|
|
44
44
|
|
|
@@ -2,14 +2,14 @@ Searches files using powerful regex matching.
|
|
|
2
2
|
|
|
3
3
|
<instruction>
|
|
4
4
|
- Supports Rust regex syntax (RE2-style — no lookaround or backreferences). Use line anchors or post-filters instead of (?!…)/(?<!…)
|
|
5
|
-
- `paths` is required and accepts an array of files, directories, globs, or internal URLs
|
|
6
|
-
-
|
|
5
|
+
- `paths` is required and accepts either one string or an array of files, directories, globs, or internal URLs
|
|
6
|
+
- For multiple targets, pass an array with one target per element. Do not comma-join targets inside one string: pass `["src", "tests"]`, not `"src,tests"` or `["src,tests"]`.
|
|
7
7
|
- Cross-line patterns are detected from literal `\n` or escaped `\\n` in `pattern`
|
|
8
8
|
</instruction>
|
|
9
9
|
|
|
10
10
|
<output>
|
|
11
11
|
{{#if IS_HL_MODE}}
|
|
12
|
-
- Text output
|
|
12
|
+
- Text output emits a file-hash header per matched file plus numbered lines: `¶src/login.ts#3c4d`, `*42:if (user.id) {` (match), ` 43:return user;` (context). Copy the header for anchored edits; ops use bare line numbers.
|
|
13
13
|
{{else}}
|
|
14
14
|
{{#if IS_LINE_NUMBER_MODE}}
|
|
15
15
|
- Text output is line-number-prefixed
|