@oh-my-pi/pi-coding-agent 15.3.1 → 15.4.1
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 +119 -0
- package/dist/types/cli/auth-gateway-cli.d.ts +1 -1
- 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/task/types.d.ts +8 -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/auth-gateway-cli.ts +71 -2
- package/src/cli/file-processor.ts +12 -2
- package/src/cli.ts +0 -8
- package/src/commands/auth-gateway.ts +2 -0
- 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/extensibility/plugins/marketplace/manager.ts +20 -1
- 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 +9 -8
- package/src/lsp/config.ts +87 -22
- package/src/modes/components/extensions/types.ts +0 -5
- package/src/modes/components/session-observer-overlay.ts +11 -2
- 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/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 +21 -24
- 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 +55 -57
- package/src/task/index.ts +8 -4
- package/src/task/render.ts +53 -1
- package/src/task/types.ts +8 -0
- 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/jtd-to-json-schema.ts +5 -1
- package/src/tools/match-line-format.ts +5 -7
- package/src/tools/output-schema-validator.ts +132 -0
- package/src/tools/read.ts +142 -63
- 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 -212
- 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
package/src/lsp/config.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as os from "node:os";
|
|
3
3
|
import * as path from "node:path";
|
|
4
|
-
import { $which, isRecord, logger } from "@oh-my-pi/pi-utils";
|
|
4
|
+
import { $which, isRecord, logger, pathIsWithin } from "@oh-my-pi/pi-utils";
|
|
5
5
|
import { YAML } from "bun";
|
|
6
6
|
import { getConfigDirPaths } from "../config";
|
|
7
|
-
import { getPreloadedPluginRoots } from "../discovery/helpers";
|
|
7
|
+
import { type ClaudePluginRoot, getPreloadedPluginRoots } from "../discovery/helpers";
|
|
8
8
|
import { BiomeClient } from "./clients/biome-client";
|
|
9
9
|
import { SwiftLintClient } from "./clients/swiftlint-client";
|
|
10
10
|
import DEFAULTS from "./defaults.json" with { type: "json" };
|
|
@@ -22,8 +22,13 @@ export interface LspConfig {
|
|
|
22
22
|
|
|
23
23
|
const PID_TOKEN = "$PID";
|
|
24
24
|
|
|
25
|
+
interface RawServerConfig extends Partial<ServerConfig> {
|
|
26
|
+
extensionToLanguage?: unknown;
|
|
27
|
+
initializationOptions?: unknown;
|
|
28
|
+
}
|
|
29
|
+
|
|
25
30
|
interface NormalizedConfig {
|
|
26
|
-
servers: Record<string,
|
|
31
|
+
servers: Record<string, RawServerConfig>;
|
|
27
32
|
idleTimeoutMs?: number;
|
|
28
33
|
}
|
|
29
34
|
|
|
@@ -42,12 +47,12 @@ function normalizeConfig(value: unknown): NormalizedConfig | null {
|
|
|
42
47
|
const rawServers = value.servers;
|
|
43
48
|
|
|
44
49
|
if (isRecord(rawServers)) {
|
|
45
|
-
return { servers: rawServers as Record<string,
|
|
50
|
+
return { servers: rawServers as Record<string, RawServerConfig>, idleTimeoutMs };
|
|
46
51
|
}
|
|
47
52
|
|
|
48
53
|
const servers = Object.fromEntries(Object.entries(value).filter(([key]) => key !== "idleTimeoutMs")) as Record<
|
|
49
54
|
string,
|
|
50
|
-
|
|
55
|
+
RawServerConfig
|
|
51
56
|
>;
|
|
52
57
|
|
|
53
58
|
return { servers, idleTimeoutMs };
|
|
@@ -58,11 +63,17 @@ function normalizeStringArray(value: unknown): string[] | null {
|
|
|
58
63
|
const items = value.filter((entry): entry is string => typeof entry === "string" && entry.length > 0);
|
|
59
64
|
return items.length > 0 ? items : null;
|
|
60
65
|
}
|
|
66
|
+
function normalizeExtensionToFileTypes(value: unknown): string[] | null {
|
|
67
|
+
if (!isRecord(value)) return null;
|
|
68
|
+
const extensions = Object.keys(value).filter(extension => extension.length > 0);
|
|
69
|
+
return extensions.length > 0 ? extensions : null;
|
|
70
|
+
}
|
|
61
71
|
|
|
62
|
-
function normalizeServerConfig(name: string, config:
|
|
72
|
+
function normalizeServerConfig(name: string, config: RawServerConfig): ServerConfig | null {
|
|
63
73
|
const command = typeof config.command === "string" && config.command.length > 0 ? config.command : null;
|
|
64
|
-
const fileTypes =
|
|
65
|
-
|
|
74
|
+
const fileTypes =
|
|
75
|
+
normalizeStringArray(config.fileTypes) ?? normalizeExtensionToFileTypes(config.extensionToLanguage);
|
|
76
|
+
const rootMarkers = normalizeStringArray(config.rootMarkers) ?? (config.extensionToLanguage ? ["."] : null);
|
|
66
77
|
|
|
67
78
|
if (!command || !fileTypes || !rootMarkers) {
|
|
68
79
|
logger.warn("Ignoring invalid LSP server config (missing required fields).", { name });
|
|
@@ -72,6 +83,11 @@ function normalizeServerConfig(name: string, config: Partial<ServerConfig>): Ser
|
|
|
72
83
|
const args = Array.isArray(config.args)
|
|
73
84
|
? config.args.filter((entry): entry is string => typeof entry === "string")
|
|
74
85
|
: undefined;
|
|
86
|
+
const initOptions = isRecord(config.initOptions)
|
|
87
|
+
? config.initOptions
|
|
88
|
+
: isRecord(config.initializationOptions)
|
|
89
|
+
? config.initializationOptions
|
|
90
|
+
: undefined;
|
|
75
91
|
|
|
76
92
|
return {
|
|
77
93
|
...config,
|
|
@@ -79,6 +95,7 @@ function normalizeServerConfig(name: string, config: Partial<ServerConfig>): Ser
|
|
|
79
95
|
args,
|
|
80
96
|
fileTypes,
|
|
81
97
|
rootMarkers,
|
|
98
|
+
...(initOptions ? { initOptions } : {}),
|
|
82
99
|
};
|
|
83
100
|
}
|
|
84
101
|
|
|
@@ -92,7 +109,7 @@ function readConfigFile(filePath: string): NormalizedConfig | null {
|
|
|
92
109
|
}
|
|
93
110
|
}
|
|
94
111
|
|
|
95
|
-
function coerceServerConfigs(servers: Record<string,
|
|
112
|
+
function coerceServerConfigs(servers: Record<string, RawServerConfig>): Record<string, ServerConfig> {
|
|
96
113
|
const result: Record<string, ServerConfig> = {};
|
|
97
114
|
for (const [name, config] of Object.entries(servers)) {
|
|
98
115
|
const normalized = normalizeServerConfig(name, config);
|
|
@@ -105,7 +122,7 @@ function coerceServerConfigs(servers: Record<string, Partial<ServerConfig>>): Re
|
|
|
105
122
|
|
|
106
123
|
function mergeServers(
|
|
107
124
|
base: Record<string, ServerConfig>,
|
|
108
|
-
overrides: Record<string,
|
|
125
|
+
overrides: Record<string, RawServerConfig>,
|
|
109
126
|
): Record<string, ServerConfig> {
|
|
110
127
|
const merged: Record<string, ServerConfig> = { ...base };
|
|
111
128
|
for (const [name, config] of Object.entries(overrides)) {
|
|
@@ -245,24 +262,71 @@ export function resolveCommand(command: string, cwd: string): string | null {
|
|
|
245
262
|
return $which(command);
|
|
246
263
|
}
|
|
247
264
|
|
|
265
|
+
interface ConfigSource {
|
|
266
|
+
read(): NormalizedConfig | null;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
function fileConfigSource(filePath: string): ConfigSource {
|
|
270
|
+
return {
|
|
271
|
+
read: () => readConfigFile(filePath),
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function readMarketplaceLspConfig(root: ClaudePluginRoot): NormalizedConfig | null {
|
|
276
|
+
const catalogPaths = [
|
|
277
|
+
path.resolve(root.path, "..", "..", "marketplace.json"),
|
|
278
|
+
path.resolve(root.path, "..", "..", ".claude-plugin", "marketplace.json"),
|
|
279
|
+
];
|
|
280
|
+
|
|
281
|
+
for (const catalogPath of catalogPaths) {
|
|
282
|
+
try {
|
|
283
|
+
const catalog = JSON.parse(fs.readFileSync(catalogPath, "utf-8")) as unknown;
|
|
284
|
+
if (!isRecord(catalog) || !Array.isArray(catalog.plugins)) continue;
|
|
285
|
+
|
|
286
|
+
for (const plugin of catalog.plugins) {
|
|
287
|
+
if (!isRecord(plugin) || plugin.name !== root.plugin) continue;
|
|
288
|
+
|
|
289
|
+
const lspServers = plugin.lspServers;
|
|
290
|
+
if (typeof lspServers === "string") {
|
|
291
|
+
const configPath = path.resolve(root.path, lspServers);
|
|
292
|
+
if (!pathIsWithin(root.path, configPath)) return null;
|
|
293
|
+
return readConfigFile(configPath);
|
|
294
|
+
}
|
|
295
|
+
if (isRecord(lspServers)) {
|
|
296
|
+
return normalizeConfig({ servers: lspServers });
|
|
297
|
+
}
|
|
298
|
+
return null;
|
|
299
|
+
}
|
|
300
|
+
} catch {}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
return null;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
function marketplaceConfigSource(root: ClaudePluginRoot): ConfigSource {
|
|
307
|
+
return {
|
|
308
|
+
read: () => readMarketplaceLspConfig(root),
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
|
|
248
312
|
/**
|
|
249
|
-
* Configuration
|
|
313
|
+
* Configuration sources in priority order.
|
|
250
314
|
* Supports both visible and hidden variants at each config location.
|
|
251
315
|
*/
|
|
252
|
-
function
|
|
316
|
+
function getConfigSources(cwd: string): ConfigSource[] {
|
|
253
317
|
const filenames = ["lsp.json", ".lsp.json", "lsp.yaml", ".lsp.yaml", "lsp.yml", ".lsp.yml"];
|
|
254
|
-
const
|
|
318
|
+
const sources: ConfigSource[] = [];
|
|
255
319
|
|
|
256
320
|
// Project root files (highest priority)
|
|
257
321
|
for (const filename of filenames) {
|
|
258
|
-
|
|
322
|
+
sources.push(fileConfigSource(path.join(cwd, filename)));
|
|
259
323
|
}
|
|
260
324
|
|
|
261
325
|
// Project config directories (.omp/, .pi/, .claude/)
|
|
262
326
|
const projectDirs = getConfigDirPaths("", { user: false, project: true, cwd });
|
|
263
327
|
for (const dir of projectDirs) {
|
|
264
328
|
for (const filename of filenames) {
|
|
265
|
-
|
|
329
|
+
sources.push(fileConfigSource(path.join(dir, filename)));
|
|
266
330
|
}
|
|
267
331
|
}
|
|
268
332
|
|
|
@@ -270,7 +334,7 @@ function getConfigPaths(cwd: string): string[] {
|
|
|
270
334
|
const userDirs = getConfigDirPaths("", { user: true, project: false });
|
|
271
335
|
for (const dir of userDirs) {
|
|
272
336
|
for (const filename of filenames) {
|
|
273
|
-
|
|
337
|
+
sources.push(fileConfigSource(path.join(dir, filename)));
|
|
274
338
|
}
|
|
275
339
|
}
|
|
276
340
|
|
|
@@ -278,16 +342,17 @@ function getConfigPaths(cwd: string): string[] {
|
|
|
278
342
|
const pluginRoots = getPreloadedPluginRoots();
|
|
279
343
|
for (const root of pluginRoots) {
|
|
280
344
|
for (const filename of filenames) {
|
|
281
|
-
|
|
345
|
+
sources.push(fileConfigSource(path.join(root.path, filename)));
|
|
282
346
|
}
|
|
347
|
+
sources.push(marketplaceConfigSource(root));
|
|
283
348
|
}
|
|
284
349
|
|
|
285
350
|
// User home root files (lowest priority fallback)
|
|
286
351
|
for (const filename of filenames) {
|
|
287
|
-
|
|
352
|
+
sources.push(fileConfigSource(path.join(os.homedir(), filename)));
|
|
288
353
|
}
|
|
289
354
|
|
|
290
|
-
return
|
|
355
|
+
return sources;
|
|
291
356
|
}
|
|
292
357
|
|
|
293
358
|
/**
|
|
@@ -324,12 +389,12 @@ function getConfigPaths(cwd: string): string[] {
|
|
|
324
389
|
export function loadConfig(cwd: string): LspConfig {
|
|
325
390
|
let mergedServers = coerceServerConfigs(DEFAULTS);
|
|
326
391
|
|
|
327
|
-
const
|
|
392
|
+
const configSources = getConfigSources(cwd).reverse();
|
|
328
393
|
let hasOverrides = false;
|
|
329
394
|
|
|
330
395
|
let idleTimeoutMs: number | undefined;
|
|
331
|
-
for (const
|
|
332
|
-
const parsed =
|
|
396
|
+
for (const source of configSources) {
|
|
397
|
+
const parsed = source.read();
|
|
333
398
|
if (!parsed) continue;
|
|
334
399
|
const hasServerOverrides = Object.keys(parsed.servers).length > 0;
|
|
335
400
|
if (hasServerOverrides) {
|
|
@@ -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": {
|
|
@@ -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/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
|
|