@oh-my-pi/pi-coding-agent 15.3.2 → 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 +104 -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/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 +17 -23
- 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
|
@@ -4,21 +4,18 @@
|
|
|
4
4
|
* Uses Synthetic's zero-data-retention web search API for coding agents.
|
|
5
5
|
* Endpoint: POST https://api.synthetic.new/v2/search
|
|
6
6
|
*/
|
|
7
|
+
import { type AuthStorage } from "@oh-my-pi/pi-ai";
|
|
7
8
|
import type { SearchResponse } from "../../../web/search/types";
|
|
8
9
|
import type { SearchParams } from "./base";
|
|
9
10
|
import { SearchProvider } from "./base";
|
|
10
|
-
/**
|
|
11
|
-
export declare function findApiKey(): Promise<string |
|
|
11
|
+
/** Resolve Synthetic API key through the shared auth storage pipeline. */
|
|
12
|
+
export declare function findApiKey(authStorage: AuthStorage, sessionId?: string, signal?: AbortSignal): Promise<string | undefined>;
|
|
12
13
|
/** Execute Synthetic web search. */
|
|
13
|
-
export declare function searchSynthetic(params:
|
|
14
|
-
query: string;
|
|
15
|
-
num_results?: number;
|
|
16
|
-
signal?: AbortSignal;
|
|
17
|
-
}): Promise<SearchResponse>;
|
|
14
|
+
export declare function searchSynthetic(params: SearchParams): Promise<SearchResponse>;
|
|
18
15
|
/** Search provider for Synthetic. */
|
|
19
16
|
export declare class SyntheticProvider extends SearchProvider {
|
|
20
17
|
readonly id = "synthetic";
|
|
21
18
|
readonly label = "Synthetic";
|
|
22
|
-
isAvailable():
|
|
19
|
+
isAvailable(authStorage: AuthStorage): boolean;
|
|
23
20
|
search(params: SearchParams): Promise<SearchResponse>;
|
|
24
21
|
}
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tavily Web Search Provider
|
|
3
|
+
*
|
|
4
|
+
* Uses Tavily's agent-focused search API to return structured results with an
|
|
5
|
+
* optional synthesized answer.
|
|
6
|
+
*/
|
|
7
|
+
import { type AuthStorage } from "@oh-my-pi/pi-ai";
|
|
1
8
|
import type { SearchResponse } from "../../../web/search/types";
|
|
2
9
|
import type { SearchParams } from "./base";
|
|
3
10
|
import { SearchProvider } from "./base";
|
|
@@ -7,16 +14,16 @@ export interface TavilySearchParams {
|
|
|
7
14
|
recency?: "day" | "week" | "month" | "year";
|
|
8
15
|
signal?: AbortSignal;
|
|
9
16
|
}
|
|
10
|
-
/** Find Tavily API key
|
|
11
|
-
export declare function findApiKey(): Promise<string | null>;
|
|
17
|
+
/** Find Tavily API key through AuthStorage's unified refresh pipeline. */
|
|
18
|
+
export declare function findApiKey(authStorage: AuthStorage, sessionId: string | undefined, signal: AbortSignal | undefined): Promise<string | null>;
|
|
12
19
|
/** Exported for testing. Builds the Tavily request body from unified params. */
|
|
13
20
|
export declare function buildRequestBody(params: TavilySearchParams): Record<string, unknown>;
|
|
14
21
|
/** Execute Tavily web search. */
|
|
15
|
-
export declare function searchTavily(params:
|
|
22
|
+
export declare function searchTavily(params: SearchParams): Promise<SearchResponse>;
|
|
16
23
|
/** Search provider for Tavily web search. */
|
|
17
24
|
export declare class TavilyProvider extends SearchProvider {
|
|
18
25
|
readonly id = "tavily";
|
|
19
26
|
readonly label = "Tavily";
|
|
20
|
-
isAvailable():
|
|
27
|
+
isAvailable(authStorage: AuthStorage): boolean;
|
|
21
28
|
search(params: SearchParams): Promise<SearchResponse>;
|
|
22
29
|
}
|
|
@@ -1,17 +1,19 @@
|
|
|
1
|
+
import type { AgentStorage } from "../../../session/agent-storage";
|
|
1
2
|
import { SearchProviderError, type SearchProviderId, type SearchSource } from "../../../web/search/types";
|
|
2
3
|
/**
|
|
3
4
|
* Search for an API credential by checking an env-derived key first,
|
|
4
5
|
* then falling back to agent.db stored credentials for the given providers.
|
|
5
6
|
*
|
|
7
|
+
* The caller MUST supply an open {@link AgentStorage} handle so the helper
|
|
8
|
+
* never reaches out to global filesystem state; both the unified web_search
|
|
9
|
+
* chain and one-shot CLI calls open storage exactly once and thread it
|
|
10
|
+
* through every provider.
|
|
11
|
+
*
|
|
12
|
+
* @param storage - Open agent storage handle
|
|
6
13
|
* @param envKey - Pre-resolved environment variable value (or null)
|
|
7
14
|
* @param storageProviders - Provider names to look up in AgentStorage
|
|
8
15
|
*/
|
|
9
|
-
export declare function findCredential(envKey: string | null | undefined, ...storageProviders: string[]):
|
|
10
|
-
/**
|
|
11
|
-
* Probe whether a provider's API key lookup resolves to a truthy value.
|
|
12
|
-
* Swallows lookup errors and reports unavailability.
|
|
13
|
-
*/
|
|
14
|
-
export declare function isApiKeyAvailable(findApiKey: () => string | null | Promise<string | null>): Promise<boolean>;
|
|
16
|
+
export declare function findCredential(storage: AgentStorage | null | undefined, envKey: string | null | undefined, ...storageProviders: string[]): string | null;
|
|
15
17
|
/**
|
|
16
18
|
* Default hard ceiling for a single web-search round-trip. 60s tolerates
|
|
17
19
|
* legitimate slow LLM-mediated responses (anthropic web_search_20250305,
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Z.AI Web Search Provider
|
|
3
|
+
*
|
|
4
|
+
* Calls Z.AI's remote MCP server (`webSearchPrime`) and adapts results into
|
|
5
|
+
* the unified SearchResponse shape used by the web search tool.
|
|
6
|
+
*/
|
|
7
|
+
import { type AuthStorage } from "@oh-my-pi/pi-ai";
|
|
1
8
|
import type { SearchResponse } from "../../../web/search/types";
|
|
2
9
|
import type { SearchParams } from "./base";
|
|
3
10
|
import { SearchProvider } from "./base";
|
|
@@ -5,15 +12,17 @@ export interface ZaiSearchParams {
|
|
|
5
12
|
query: string;
|
|
6
13
|
num_results?: number;
|
|
7
14
|
signal?: AbortSignal;
|
|
15
|
+
authStorage: AuthStorage;
|
|
16
|
+
sessionId?: string;
|
|
8
17
|
}
|
|
9
|
-
/**
|
|
10
|
-
export declare function findApiKey(): Promise<string | null>;
|
|
18
|
+
/** Resolve Z.AI API credentials through the unified auth storage pipeline. */
|
|
19
|
+
export declare function findApiKey(authStorage: AuthStorage, sessionId?: string, signal?: AbortSignal): Promise<string | null>;
|
|
11
20
|
/** Execute Z.AI web search via remote MCP endpoint. */
|
|
12
21
|
export declare function searchZai(params: ZaiSearchParams): Promise<SearchResponse>;
|
|
13
22
|
/** Search provider for Z.AI web search MCP. */
|
|
14
23
|
export declare class ZaiProvider extends SearchProvider {
|
|
15
24
|
readonly id = "zai";
|
|
16
25
|
readonly label = "Z.AI";
|
|
17
|
-
isAvailable(): Promise<boolean
|
|
26
|
+
isAvailable(authStorage: AuthStorage): Promise<boolean> | boolean;
|
|
18
27
|
search(params: SearchParams): Promise<SearchResponse>;
|
|
19
28
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@oh-my-pi/pi-coding-agent",
|
|
4
|
-
"version": "15.
|
|
4
|
+
"version": "15.4.1",
|
|
5
5
|
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
|
6
6
|
"homepage": "https://omp.sh",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -47,12 +47,12 @@
|
|
|
47
47
|
"@agentclientprotocol/sdk": "0.21.0",
|
|
48
48
|
"@babel/parser": "^7.29.3",
|
|
49
49
|
"@mozilla/readability": "^0.6.0",
|
|
50
|
-
"@oh-my-pi/omp-stats": "15.
|
|
51
|
-
"@oh-my-pi/pi-agent-core": "15.
|
|
52
|
-
"@oh-my-pi/pi-ai": "15.
|
|
53
|
-
"@oh-my-pi/pi-natives": "15.
|
|
54
|
-
"@oh-my-pi/pi-tui": "15.
|
|
55
|
-
"@oh-my-pi/pi-utils": "15.
|
|
50
|
+
"@oh-my-pi/omp-stats": "15.4.1",
|
|
51
|
+
"@oh-my-pi/pi-agent-core": "15.4.1",
|
|
52
|
+
"@oh-my-pi/pi-ai": "15.4.1",
|
|
53
|
+
"@oh-my-pi/pi-natives": "15.4.1",
|
|
54
|
+
"@oh-my-pi/pi-tui": "15.4.1",
|
|
55
|
+
"@oh-my-pi/pi-utils": "15.4.1",
|
|
56
56
|
"@puppeteer/browsers": "^2.13.0",
|
|
57
57
|
"@types/turndown": "5.0.6",
|
|
58
58
|
"@xterm/headless": "^6.0.0",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Process @file CLI arguments into text content and image attachments
|
|
2
|
+
* Process @file CLI arguments into text, document content, and image attachments
|
|
3
3
|
*/
|
|
4
4
|
import * as fs from "node:fs";
|
|
5
5
|
import * as path from "node:path";
|
|
@@ -9,11 +9,13 @@ import chalk from "chalk";
|
|
|
9
9
|
import { resolveReadPath } from "../tools/path-utils";
|
|
10
10
|
import { formatBytes } from "../tools/render-utils";
|
|
11
11
|
import { formatDimensionNote, resizeImage } from "../utils/image-resize";
|
|
12
|
+
import { convertFileWithMarkit } from "../utils/markit";
|
|
12
13
|
|
|
13
14
|
// Keep CLI startup responsive and avoid OOM when users pass huge files.
|
|
14
15
|
// If a file exceeds these limits, we include it as a path-only <file/> block.
|
|
15
16
|
const MAX_CLI_TEXT_BYTES = 5 * 1024 * 1024; // 5MB
|
|
16
17
|
const MAX_CLI_IMAGE_BYTES = 25 * 1024 * 1024; // 25MB
|
|
18
|
+
const CONVERTIBLE_EXTENSIONS = new Set([".pdf", ".doc", ".docx", ".ppt", ".pptx", ".xls", ".xlsx", ".rtf", ".epub"]);
|
|
17
19
|
|
|
18
20
|
export interface ProcessedFiles {
|
|
19
21
|
text: string;
|
|
@@ -25,7 +27,7 @@ export interface ProcessFileOptions {
|
|
|
25
27
|
autoResizeImages?: boolean;
|
|
26
28
|
}
|
|
27
29
|
|
|
28
|
-
/** Process @file arguments into text content and image attachments */
|
|
30
|
+
/** Process @file arguments into text, document content, and image attachments */
|
|
29
31
|
export async function processFileArguments(fileArgs: string[], options?: ProcessFileOptions): Promise<ProcessedFiles> {
|
|
30
32
|
const autoResizeImages = options?.autoResizeImages ?? true;
|
|
31
33
|
let text = "";
|
|
@@ -43,6 +45,7 @@ export async function processFileArguments(fileArgs: string[], options?: Process
|
|
|
43
45
|
|
|
44
46
|
const imageMetadata = await readImageMetadata(absolutePath);
|
|
45
47
|
const mimeType = imageMetadata?.mimeType;
|
|
48
|
+
const ext = path.extname(absolutePath).toLowerCase();
|
|
46
49
|
const maxBytes = mimeType ? MAX_CLI_IMAGE_BYTES : MAX_CLI_TEXT_BYTES;
|
|
47
50
|
if (stat.size > maxBytes) {
|
|
48
51
|
console.error(
|
|
@@ -106,6 +109,13 @@ export async function processFileArguments(fileArgs: string[], options?: Process
|
|
|
106
109
|
} else {
|
|
107
110
|
text += `<file name="${absolutePath}"></file>\n`;
|
|
108
111
|
}
|
|
112
|
+
} else if (CONVERTIBLE_EXTENSIONS.has(ext)) {
|
|
113
|
+
const result = await convertFileWithMarkit(absolutePath);
|
|
114
|
+
if (result.ok) {
|
|
115
|
+
text += `<file name="${absolutePath}">\n${result.content}\n</file>\n`;
|
|
116
|
+
} else {
|
|
117
|
+
text += `<file name="${absolutePath}">[Cannot read ${ext} file: ${result.error || "conversion failed"}]</file>\n`;
|
|
118
|
+
}
|
|
109
119
|
} else {
|
|
110
120
|
// Handle text file
|
|
111
121
|
try {
|
package/src/cli.ts
CHANGED
|
@@ -1,14 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
-
import { installH2Fetch } from "@oh-my-pi/pi-ai";
|
|
3
2
|
import { APP_NAME, MIN_BUN_VERSION, procmgr, VERSION } from "@oh-my-pi/pi-utils";
|
|
4
3
|
|
|
5
|
-
// Activate HTTP/2 for all `fetch()` calls (provider streams, OAuth, model
|
|
6
|
-
// discovery, web tools). Bun's HTTP/2 client is gated on a startup flag we
|
|
7
|
-
// can't toggle from JS, so we patch globalThis.fetch to pass
|
|
8
|
-
// `protocol: "http2"` per request, with transparent HTTP/1.1 fallback on
|
|
9
|
-
// `HTTP2Unsupported`. See @oh-my-pi/pi-ai/utils/h2-fetch for details.
|
|
10
|
-
installH2Fetch();
|
|
11
|
-
|
|
12
4
|
// Strip macOS malloc-stack-logging env vars before any subprocess is spawned.
|
|
13
5
|
// Otherwise every child bun process (subagents, plugin installs, ptree spawns,
|
|
14
6
|
// etc.) prints a `MallocStackLogging: can't turn off …` warning to stderr.
|
package/src/commands/commit.ts
CHANGED
|
@@ -32,14 +32,14 @@ export default class Commit extends Command {
|
|
|
32
32
|
};
|
|
33
33
|
|
|
34
34
|
await initTheme();
|
|
35
|
-
// The agentic commit flow opens
|
|
36
|
-
//
|
|
37
|
-
//
|
|
38
|
-
//
|
|
39
|
-
//
|
|
40
|
-
//
|
|
41
|
-
// `
|
|
42
|
-
//
|
|
35
|
+
// The agentic commit flow opens keep-alive sockets to the model provider
|
|
36
|
+
// and spins up an AgentSession with background async-job + extension
|
|
37
|
+
// machinery. `session.dispose()` releases what it can, but Bun's fetch
|
|
38
|
+
// keeps idle connections warm and a few timers (Settings autosave, OAuth
|
|
39
|
+
// refresh) stay armed long enough to pin the event loop after the commit
|
|
40
|
+
// is already written. Mirror the `runPrintMode` exit pattern from
|
|
41
|
+
// `main.ts` so the CLI returns to the shell instead of stranding the user
|
|
42
|
+
// on Ctrl+C (issue #1041).
|
|
43
43
|
await runCommitCommand(cmd);
|
|
44
44
|
await postmortem.quit(0);
|
|
45
45
|
}
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
parseFrontmatter,
|
|
9
9
|
prompt,
|
|
10
10
|
} from "@oh-my-pi/pi-utils";
|
|
11
|
-
import {
|
|
11
|
+
import { HL_LINE_BODY_SEP } from "../hashline/hash";
|
|
12
12
|
import { jtdToTypeScript } from "../tools/jtd-to-typescript";
|
|
13
13
|
import { parseCommandArgs, substituteArgs } from "../utils/command-args";
|
|
14
14
|
|
|
@@ -34,7 +34,7 @@ function formatHashlineRef(lineNum: unknown, content: unknown): { num: number; t
|
|
|
34
34
|
const num = typeof lineNum === "number" ? lineNum : Number.parseInt(String(lineNum), 10);
|
|
35
35
|
const raw = typeof content === "string" ? content : String(content ?? "");
|
|
36
36
|
const text = raw.replace(/\\t/g, "\t").replace(/\\n/g, "\n").replace(/\\r/g, "\r");
|
|
37
|
-
const ref = `${num}
|
|
37
|
+
const ref = `${num}`;
|
|
38
38
|
return { num, text, ref };
|
|
39
39
|
}
|
|
40
40
|
|
|
@@ -124,11 +124,11 @@ function resolveHashlineRef(state: HashlineHelperState, args: unknown[]): string
|
|
|
124
124
|
}
|
|
125
125
|
|
|
126
126
|
/**
|
|
127
|
-
* {{href lineNum "content"}} — compute a
|
|
127
|
+
* {{href lineNum "content"}} — compute a hashline line ref for prompt examples.
|
|
128
128
|
* {{href lineNum}} — quote the ref remembered by the earlier {{hline lineNum "..."}}
|
|
129
129
|
* {{href}} — quote the ref from the previous {{hline}} call.
|
|
130
130
|
* {{href "[" "]"}} — wrap the previous {{hline}} ref with pre/post chars.
|
|
131
|
-
* Returns `"
|
|
131
|
+
* Returns `"lineNum"` (e.g., `"42"`), or `"[42]"` when pre/post are supplied.
|
|
132
132
|
*/
|
|
133
133
|
prompt.registerHelper("href", function (this: unknown, ...args: unknown[]): string {
|
|
134
134
|
const { positional, options } = splitHelperArgs(args);
|
|
@@ -143,7 +143,7 @@ prompt.registerHelper("hrefr", function (this: unknown, ...args: unknown[]): str
|
|
|
143
143
|
|
|
144
144
|
/**
|
|
145
145
|
* {{hline lineNum "content"}} — format a full read-style line with prefix.
|
|
146
|
-
* Returns `"
|
|
146
|
+
* Returns `"lineNum:content"` (colon between line number and content).
|
|
147
147
|
*/
|
|
148
148
|
prompt.registerHelper("hline", function (this: unknown, ...args: unknown[]): string {
|
|
149
149
|
const { positional, options } = splitHelperArgs(args);
|
|
@@ -151,7 +151,7 @@ prompt.registerHelper("hline", function (this: unknown, ...args: unknown[]): str
|
|
|
151
151
|
const { num, ref, text } = formatHashlineRef(lineNum, content);
|
|
152
152
|
const state = getHashlineHelperState(this, options);
|
|
153
153
|
rememberHashlineRef(state, num, ref);
|
|
154
|
-
return `${ref}${
|
|
154
|
+
return `${ref}${HL_LINE_BODY_SEP}${text}`;
|
|
155
155
|
});
|
|
156
156
|
|
|
157
157
|
const INLINE_ARG_SHELL_PATTERN = /\$(?:ARGUMENTS|@(?:\[\d+(?::\d*)?\])?|\d+)/;
|
|
@@ -1528,7 +1528,7 @@ export const SETTINGS_SCHEMA = {
|
|
|
1528
1528
|
ui: {
|
|
1529
1529
|
tab: "editing",
|
|
1530
1530
|
label: "Edit Mode",
|
|
1531
|
-
description: "Select the edit tool variant (replace, patch, hashline,
|
|
1531
|
+
description: "Select the edit tool variant (replace, patch, hashline, or apply_patch)",
|
|
1532
1532
|
},
|
|
1533
1533
|
},
|
|
1534
1534
|
|
|
@@ -1603,7 +1603,8 @@ export const SETTINGS_SCHEMA = {
|
|
|
1603
1603
|
ui: {
|
|
1604
1604
|
tab: "editing",
|
|
1605
1605
|
label: "Hash Lines",
|
|
1606
|
-
description:
|
|
1606
|
+
description:
|
|
1607
|
+
"Include file-hash headers and line numbers in read output for hashline edit mode (¶PATH#hash plus LINE:content)",
|
|
1607
1608
|
},
|
|
1608
1609
|
},
|
|
1609
1610
|
|
|
@@ -1905,6 +1906,24 @@ export const SETTINGS_SCHEMA = {
|
|
|
1905
1906
|
},
|
|
1906
1907
|
},
|
|
1907
1908
|
|
|
1909
|
+
"irc.timeoutMs": {
|
|
1910
|
+
type: "number",
|
|
1911
|
+
default: 120_000,
|
|
1912
|
+
ui: {
|
|
1913
|
+
tab: "tools",
|
|
1914
|
+
label: "IRC Timeout",
|
|
1915
|
+
description:
|
|
1916
|
+
"Drop IRC messages whose recipient does not respond within this many milliseconds (0 disables the timeout)",
|
|
1917
|
+
options: [
|
|
1918
|
+
{ value: "0", label: "Disabled" },
|
|
1919
|
+
{ value: "30000", label: "30 seconds" },
|
|
1920
|
+
{ value: "60000", label: "1 minute" },
|
|
1921
|
+
{ value: "120000", label: "2 minutes" },
|
|
1922
|
+
{ value: "300000", label: "5 minutes" },
|
|
1923
|
+
],
|
|
1924
|
+
},
|
|
1925
|
+
},
|
|
1926
|
+
|
|
1908
1927
|
// Optional tools
|
|
1909
1928
|
|
|
1910
1929
|
"renderMermaid.enabled": {
|
|
@@ -2383,6 +2402,17 @@ export const SETTINGS_SCHEMA = {
|
|
|
2383
2402
|
},
|
|
2384
2403
|
},
|
|
2385
2404
|
|
|
2405
|
+
"task.enableLsp": {
|
|
2406
|
+
type: "boolean",
|
|
2407
|
+
default: false,
|
|
2408
|
+
ui: {
|
|
2409
|
+
tab: "tasks",
|
|
2410
|
+
label: "LSP in Subagents",
|
|
2411
|
+
description:
|
|
2412
|
+
"Allow subagents spawned via the task tool to use the lsp tool. Off by default to keep subagents cheap; enable when LSP-aware delegation is worth the extra tokens.",
|
|
2413
|
+
},
|
|
2414
|
+
},
|
|
2415
|
+
|
|
2386
2416
|
"task.maxRecursionDepth": {
|
|
2387
2417
|
type: "number",
|
|
2388
2418
|
default: 2,
|
|
@@ -2552,7 +2582,21 @@ export const SETTINGS_SCHEMA = {
|
|
|
2552
2582
|
label: "Perplexity",
|
|
2553
2583
|
description: "Requires PERPLEXITY_COOKIES or PERPLEXITY_API_KEY",
|
|
2554
2584
|
},
|
|
2555
|
-
{
|
|
2585
|
+
{
|
|
2586
|
+
value: "anthropic",
|
|
2587
|
+
label: "Anthropic",
|
|
2588
|
+
description: "Claude's native web_search tool (uses Anthropic OAuth or ANTHROPIC_API_KEY)",
|
|
2589
|
+
},
|
|
2590
|
+
{
|
|
2591
|
+
value: "codex",
|
|
2592
|
+
label: "OpenAI",
|
|
2593
|
+
description: "OpenAI's native web_search (uses ChatGPT OAuth via /login openai-codex)",
|
|
2594
|
+
},
|
|
2595
|
+
{
|
|
2596
|
+
value: "gemini",
|
|
2597
|
+
label: "Gemini",
|
|
2598
|
+
description: "Google Search grounding via Gemini (uses google-gemini-cli or google-antigravity OAuth)",
|
|
2599
|
+
},
|
|
2556
2600
|
{ value: "zai", label: "Z.AI", description: "Calls Z.AI webSearchPrime MCP" },
|
|
2557
2601
|
{ value: "tavily", label: "Tavily", description: "Requires TAVILY_API_KEY" },
|
|
2558
2602
|
{ value: "kagi", label: "Kagi", description: "Requires KAGI_API_KEY and Kagi Search API beta access" },
|
package/src/config/settings.ts
CHANGED
|
@@ -408,7 +408,7 @@ export class Settings {
|
|
|
408
408
|
|
|
409
409
|
/**
|
|
410
410
|
* Get the edit variant for a specific model.
|
|
411
|
-
* Returns "patch", "replace", "hashline", "
|
|
411
|
+
* Returns "patch", "replace", "hashline", "apply_patch", or null (use global default).
|
|
412
412
|
*/
|
|
413
413
|
getEditVariantForModel(model: string | undefined): EditMode | null {
|
|
414
414
|
if (!model) return null;
|
|
@@ -643,22 +643,22 @@ export class Settings {
|
|
|
643
643
|
}
|
|
644
644
|
}
|
|
645
645
|
|
|
646
|
-
// edit.mode: removed "atom"
|
|
646
|
+
// edit.mode: removed "atom" and "vim" variants map back to "hashline"
|
|
647
647
|
const editObj = raw.edit as Record<string, unknown> | undefined;
|
|
648
648
|
if (editObj) {
|
|
649
|
-
if (editObj.mode === "atom") {
|
|
649
|
+
if (editObj.mode === "atom" || editObj.mode === "vim") {
|
|
650
650
|
editObj.mode = "hashline";
|
|
651
651
|
}
|
|
652
652
|
const modelVariants = editObj.modelVariants as Record<string, unknown> | undefined;
|
|
653
653
|
if (modelVariants && typeof modelVariants === "object" && !Array.isArray(modelVariants)) {
|
|
654
654
|
for (const [pattern, variant] of Object.entries(modelVariants)) {
|
|
655
|
-
if (variant === "atom") {
|
|
655
|
+
if (variant === "atom" || variant === "vim") {
|
|
656
656
|
modelVariants[pattern] = "hashline";
|
|
657
657
|
}
|
|
658
658
|
}
|
|
659
659
|
}
|
|
660
660
|
}
|
|
661
|
-
if (raw["edit.mode"] === "atom") {
|
|
661
|
+
if (raw["edit.mode"] === "atom" || raw["edit.mode"] === "vim") {
|
|
662
662
|
raw["edit.mode"] = "hashline";
|
|
663
663
|
}
|
|
664
664
|
|
package/src/debug/raw-sse.ts
CHANGED
|
@@ -2,15 +2,56 @@ import { type Component, matchesKey, padding, replaceTabs, truncateToWidth, visi
|
|
|
2
2
|
import { sanitizeText } from "@oh-my-pi/pi-utils";
|
|
3
3
|
import { theme } from "../modes/theme/theme";
|
|
4
4
|
import { copyToClipboard } from "../utils/clipboard";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
formatRawSseIsoTime,
|
|
7
|
+
type RawSseDebugBuffer,
|
|
8
|
+
type RawSseDebugRecord,
|
|
9
|
+
rawSseRecordLines,
|
|
10
|
+
} from "./raw-sse-buffer";
|
|
6
11
|
|
|
7
12
|
const MIN_VIEWER_WIDTH = 20;
|
|
8
13
|
const VIEWER_FRAME_LINES = 5;
|
|
14
|
+
// `data:` lines below this width render fine on a single row; anything wider gets pretty-printed
|
|
15
|
+
// across multiple `data:` lines so streamed JSON blobs stop getting clipped by `truncateToWidth`.
|
|
16
|
+
const PRETTY_PRINT_DATA_THRESHOLD = 100;
|
|
9
17
|
|
|
10
18
|
function sanitizeFrameLine(line: string, width: number): string {
|
|
11
19
|
return truncateToWidth(replaceTabs(sanitizeText(line)), width);
|
|
12
20
|
}
|
|
13
21
|
|
|
22
|
+
// Walks the SSE wire lines and replaces single-line `data: <json>` payloads with
|
|
23
|
+
// multi-line `data: <indented-json>` entries when the JSON is wide enough to clip.
|
|
24
|
+
// Multi-line `data:` is still valid SSE (the spec joins lines with `\n`), so the
|
|
25
|
+
// transformed view round-trips back to the same event when copied.
|
|
26
|
+
/** @internal Exported for tests. */
|
|
27
|
+
export function expandPrettyDataLines(raw: readonly string[]): string[] {
|
|
28
|
+
const out: string[] = [];
|
|
29
|
+
for (const line of raw) {
|
|
30
|
+
if (!line.startsWith("data: ") || line.length <= PRETTY_PRINT_DATA_THRESHOLD) {
|
|
31
|
+
out.push(line);
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
const body = line.slice("data: ".length);
|
|
35
|
+
const trimmed = body.trim();
|
|
36
|
+
if (trimmed.length === 0 || (trimmed[0] !== "{" && trimmed[0] !== "[")) {
|
|
37
|
+
out.push(line);
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
let parsed: unknown;
|
|
41
|
+
try {
|
|
42
|
+
parsed = JSON.parse(trimmed);
|
|
43
|
+
} catch {
|
|
44
|
+
out.push(line);
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
const pretty = JSON.stringify(parsed, null, 2);
|
|
48
|
+
for (const prettyLine of pretty.split("\n")) {
|
|
49
|
+
out.push(`data: ${prettyLine}`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return out;
|
|
53
|
+
}
|
|
54
|
+
|
|
14
55
|
export interface RawSseViewerOptions {
|
|
15
56
|
buffer: RawSseDebugBuffer;
|
|
16
57
|
terminalRows: number;
|
|
@@ -30,6 +71,12 @@ export class RawSseViewerComponent implements Component {
|
|
|
30
71
|
#followTail = true;
|
|
31
72
|
#lastRenderWidth = MIN_VIEWER_WIDTH;
|
|
32
73
|
#statusMessage: string | undefined;
|
|
74
|
+
// Pretty-printed wire lines keyed by `record.sequence`. Pretty-printing is
|
|
75
|
+
// the JSON.parse + JSON.stringify per `data:` line, so we cache the result —
|
|
76
|
+
// the render path runs on every keypress and from `#maxScrollOffset()`.
|
|
77
|
+
// Sequences are monotonic; we prune entries below the oldest live record
|
|
78
|
+
// after each render so the cache tracks the buffer's eviction window.
|
|
79
|
+
readonly #prettyLinesCache = new Map<number, string[]>();
|
|
33
80
|
|
|
34
81
|
constructor(options: RawSseViewerOptions) {
|
|
35
82
|
this.#buffer = options.buffer;
|
|
@@ -131,8 +178,9 @@ export class RawSseViewerComponent implements Component {
|
|
|
131
178
|
);
|
|
132
179
|
lines.push("");
|
|
133
180
|
}
|
|
181
|
+
const firstSequence = snapshot.records[0]?.sequence;
|
|
134
182
|
for (const record of snapshot.records) {
|
|
135
|
-
for (const line of
|
|
183
|
+
for (const line of this.#prettyLinesFor(record)) {
|
|
136
184
|
lines.push(sanitizeFrameLine(line, innerWidth));
|
|
137
185
|
}
|
|
138
186
|
if (record.kind === "event" && record.truncated) {
|
|
@@ -140,14 +188,31 @@ export class RawSseViewerComponent implements Component {
|
|
|
140
188
|
}
|
|
141
189
|
lines.push("");
|
|
142
190
|
}
|
|
191
|
+
if (firstSequence !== undefined) this.#pruneCache(firstSequence);
|
|
143
192
|
return lines;
|
|
144
193
|
}
|
|
145
194
|
|
|
195
|
+
#prettyLinesFor(record: RawSseDebugRecord): string[] {
|
|
196
|
+
const cached = this.#prettyLinesCache.get(record.sequence);
|
|
197
|
+
if (cached) return cached;
|
|
198
|
+
const expanded = expandPrettyDataLines(rawSseRecordLines(record));
|
|
199
|
+
this.#prettyLinesCache.set(record.sequence, expanded);
|
|
200
|
+
return expanded;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
#pruneCache(firstSequence: number): void {
|
|
204
|
+
// Bounded by the buffer eviction rate; with `MAX_RAW_SSE_EVENTS = 1000`
|
|
205
|
+
// this rarely runs and only walks freshly-evicted entries.
|
|
206
|
+
for (const key of this.#prettyLinesCache.keys()) {
|
|
207
|
+
if (key < firstSequence) this.#prettyLinesCache.delete(key);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
146
211
|
#summaryText(): string {
|
|
147
212
|
const snapshot = this.#buffer.snapshot();
|
|
148
213
|
const last = snapshot.lastUpdatedAt ? ` last=${formatRawSseIsoTime(snapshot.lastUpdatedAt)}` : "";
|
|
149
214
|
const follow = this.#followTail ? "follow:on" : "follow:off";
|
|
150
|
-
return ` # raw SSE | events=${snapshot.totalEvents} records=${snapshot.records.length}${last} | ${follow} | Esc back Ctrl+C copy End follow`;
|
|
215
|
+
return ` # raw provider stream (SSE + WS) | events=${snapshot.totalEvents} records=${snapshot.records.length}${last} | ${follow} | Esc back Ctrl+C copy End follow`;
|
|
151
216
|
}
|
|
152
217
|
|
|
153
218
|
#statusText(): string {
|