@oh-my-pi/pi-coding-agent 15.7.6 → 15.8.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 +172 -198
- package/dist/types/async/job-manager.d.ts +3 -3
- package/dist/types/cli/args.d.ts +1 -0
- package/dist/types/cli/claude-trace-cli.d.ts +54 -0
- package/dist/types/cli/session-picker.d.ts +10 -3
- package/dist/types/cli/update-cli.d.ts +17 -0
- package/dist/types/commands/launch.d.ts +3 -0
- package/dist/types/config/keybindings.d.ts +10 -1
- package/dist/types/config/settings-schema.d.ts +2 -2
- package/dist/types/config/settings.d.ts +13 -0
- package/dist/types/edit/index.d.ts +6 -0
- package/dist/types/edit/streaming.d.ts +8 -0
- package/dist/types/eval/concurrency-bridge.d.ts +26 -0
- package/dist/types/eval/js/tool-bridge.d.ts +2 -1
- package/dist/types/export/ttsr.d.ts +9 -0
- package/dist/types/extensibility/plugins/legacy-pi-compat.d.ts +11 -0
- package/dist/types/main.d.ts +5 -0
- package/dist/types/mcp/transports/stdio.d.ts +19 -0
- package/dist/types/modes/components/custom-editor.d.ts +3 -1
- package/dist/types/modes/components/hook-selector.d.ts +3 -0
- package/dist/types/modes/components/session-selector.d.ts +32 -5
- package/dist/types/modes/components/tool-execution.d.ts +8 -0
- package/dist/types/modes/controllers/extension-ui-controller.d.ts +2 -2
- package/dist/types/modes/controllers/input-controller.d.ts +1 -0
- package/dist/types/modes/interactive-mode.d.ts +9 -2
- package/dist/types/modes/types.d.ts +4 -2
- package/dist/types/registry/agent-registry.d.ts +1 -1
- package/dist/types/sdk.d.ts +2 -2
- package/dist/types/session/agent-session.d.ts +4 -2
- package/dist/types/session/history-storage.d.ts +16 -1
- package/dist/types/session/session-manager.d.ts +4 -0
- package/dist/types/task/output-manager.d.ts +6 -15
- package/dist/types/tools/find.d.ts +0 -9
- package/dist/types/tools/index.d.ts +1 -1
- package/dist/types/tools/path-utils.d.ts +16 -0
- package/dist/types/tools/sqlite-reader.d.ts +25 -8
- package/dist/types/tools/write.d.ts +2 -0
- package/dist/types/utils/clipboard.d.ts +4 -0
- package/dist/types/utils/jj.d.ts +49 -0
- package/dist/types/web/kagi.d.ts +76 -0
- package/dist/types/web/search/providers/exa.d.ts +7 -1
- package/dist/types/web/search/providers/kagi.d.ts +1 -0
- package/package.json +9 -9
- package/src/async/job-manager.ts +3 -3
- package/src/cli/args.ts +6 -2
- package/src/cli/claude-trace-cli.ts +783 -0
- package/src/cli/session-picker.ts +36 -10
- package/src/cli/update-cli.ts +35 -2
- package/src/commands/launch.ts +3 -0
- package/src/config/keybindings.ts +14 -1
- package/src/config/model-registry.ts +18 -7
- package/src/config/settings-schema.ts +2 -2
- package/src/config/settings.ts +23 -0
- package/src/discovery/builtin-rules/index.ts +2 -0
- package/src/discovery/builtin-rules/ts-no-deprecated-leftovers.md +44 -0
- package/src/discovery/claude-plugins.ts +7 -9
- package/src/edit/index.ts +10 -0
- package/src/edit/streaming.ts +65 -0
- package/src/eval/__tests__/agent-bridge.test.ts +58 -4
- package/src/eval/concurrency-bridge.ts +34 -0
- package/src/eval/js/shared/prelude.txt +20 -17
- package/src/eval/js/tool-bridge.ts +5 -0
- package/src/eval/py/prelude.py +23 -15
- package/src/export/ttsr.ts +18 -1
- package/src/extensibility/custom-commands/bundled/review/index.ts +74 -45
- package/src/extensibility/plugins/legacy-pi-compat.ts +115 -131
- package/src/extensibility/skills.ts +0 -1
- package/src/internal-urls/docs-index.generated.ts +12 -11
- package/src/main.ts +92 -24
- package/src/mcp/transports/stdio.ts +55 -22
- package/src/modes/acp/acp-event-mapper.ts +54 -4
- package/src/modes/components/custom-editor.ts +10 -0
- package/src/modes/components/hook-selector.ts +89 -31
- package/src/modes/components/oauth-selector.ts +12 -6
- package/src/modes/components/session-selector.ts +179 -24
- package/src/modes/components/tool-execution.ts +16 -3
- package/src/modes/controllers/command-controller.ts +2 -11
- package/src/modes/controllers/extension-ui-controller.ts +3 -2
- package/src/modes/controllers/input-controller.ts +19 -1
- package/src/modes/controllers/selector-controller.ts +61 -21
- package/src/modes/interactive-mode.ts +125 -15
- package/src/modes/types.ts +5 -2
- package/src/prompts/agents/reviewer.md +2 -2
- package/src/prompts/review-request.md +1 -1
- package/src/prompts/system/empty-stop-retry.md +6 -0
- package/src/prompts/system/orchestrate-notice.md +5 -3
- package/src/prompts/system/workflow-notice.md +2 -2
- package/src/prompts/tools/eval.md +5 -5
- package/src/prompts/tools/find.md +1 -1
- package/src/prompts/tools/irc.md +6 -6
- package/src/prompts/tools/search-tool-bm25.md +9 -2
- package/src/prompts/tools/search.md +1 -1
- package/src/prompts/tools/task.md +1 -1
- package/src/registry/agent-registry.ts +1 -1
- package/src/sdk.ts +85 -31
- package/src/session/agent-session.ts +209 -54
- package/src/session/history-storage.ts +56 -12
- package/src/session/session-manager.ts +34 -0
- package/src/task/output-manager.ts +40 -48
- package/src/task/render.ts +3 -8
- package/src/tools/browser/tab-worker.ts +8 -5
- package/src/tools/find.ts +5 -29
- package/src/tools/index.ts +1 -1
- package/src/tools/path-utils.ts +144 -1
- package/src/tools/read.ts +47 -0
- package/src/tools/search-tool-bm25.ts +7 -1
- package/src/tools/search.ts +2 -27
- package/src/tools/sqlite-reader.ts +92 -9
- package/src/tools/write.ts +6 -0
- package/src/utils/clipboard.ts +38 -1
- package/src/utils/git.ts +19 -23
- package/src/utils/jj.ts +225 -0
- package/src/utils/open.ts +37 -2
- package/src/web/kagi.ts +168 -49
- package/src/web/search/providers/anthropic.ts +1 -1
- package/src/web/search/providers/exa.ts +20 -86
- package/src/web/search/providers/kagi.ts +4 -0
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { type AuthStorage, getEnvApiKey } from "@oh-my-pi/pi-ai";
|
|
10
10
|
import { settings } from "../../../config/settings";
|
|
11
|
-
import { callExaTool, findApiKey, isSearchResponse } from "../../../exa/mcp-client";
|
|
12
11
|
|
|
13
12
|
import type { SearchResponse, SearchSource } from "../../../web/search/types";
|
|
14
13
|
import { SearchProviderError } from "../../../web/search/types";
|
|
@@ -32,6 +31,12 @@ export interface ExaSearchParams {
|
|
|
32
31
|
start_published_date?: string;
|
|
33
32
|
end_published_date?: string;
|
|
34
33
|
signal?: AbortSignal;
|
|
34
|
+
/**
|
|
35
|
+
* Credential source. Resolved before falling back to `EXA_API_KEY` so
|
|
36
|
+
* Exa works when the key is stored via the broker/auth pipeline.
|
|
37
|
+
*/
|
|
38
|
+
authStorage?: AuthStorage;
|
|
39
|
+
sessionId?: string;
|
|
35
40
|
}
|
|
36
41
|
|
|
37
42
|
interface ExaSearchResult {
|
|
@@ -52,72 +57,6 @@ interface ExaSearchResponse {
|
|
|
52
57
|
searchTime?: number;
|
|
53
58
|
}
|
|
54
59
|
|
|
55
|
-
function asRecord(value: unknown): Record<string, unknown> | null {
|
|
56
|
-
if (typeof value !== "object" || value === null) return null;
|
|
57
|
-
return value as Record<string, unknown>;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function parseOptionalField(section: string, label: string): string | null | undefined {
|
|
61
|
-
const regex = new RegExp(`(?:^|\\n)${label}:\\s*([^\\n]*)`);
|
|
62
|
-
const match = section.match(regex);
|
|
63
|
-
if (!match) return undefined;
|
|
64
|
-
const value = match[1].trim();
|
|
65
|
-
return value.length > 0 ? value : null;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
function parseTextField(section: string): string | null | undefined {
|
|
69
|
-
const match = section.match(/(?:^|\n)Text:\s*([\s\S]*)$/);
|
|
70
|
-
if (!match) return undefined;
|
|
71
|
-
const value = match[1].trim();
|
|
72
|
-
return value.length > 0 ? value : null;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
function parseExaMcpTextPayload(payload: unknown): ExaSearchResponse | null {
|
|
76
|
-
const root = asRecord(payload);
|
|
77
|
-
if (!root) return null;
|
|
78
|
-
|
|
79
|
-
const content = root.content;
|
|
80
|
-
if (!Array.isArray(content)) return null;
|
|
81
|
-
|
|
82
|
-
const textBlocks = content
|
|
83
|
-
.map(item => {
|
|
84
|
-
const part = asRecord(item);
|
|
85
|
-
const text = typeof part?.text === "string" ? part.text : "";
|
|
86
|
-
return text.replace(/\r\n?/g, "\n").trim();
|
|
87
|
-
})
|
|
88
|
-
.filter(text => text.length > 0);
|
|
89
|
-
|
|
90
|
-
if (textBlocks.length === 0) return null;
|
|
91
|
-
|
|
92
|
-
const sections = textBlocks
|
|
93
|
-
.join("\n\n")
|
|
94
|
-
.split(/\n{2,}(?=Title:\s*[^\n]*(?:\n(?:URL|Author|Published Date|Text):))/)
|
|
95
|
-
.map(section => section.trim())
|
|
96
|
-
.filter(section => section.startsWith("Title:"));
|
|
97
|
-
|
|
98
|
-
const results: ExaSearchResult[] = [];
|
|
99
|
-
for (const section of sections) {
|
|
100
|
-
const title = parseOptionalField(section, "Title");
|
|
101
|
-
const url = parseOptionalField(section, "URL");
|
|
102
|
-
const author = parseOptionalField(section, "Author");
|
|
103
|
-
const publishedDate = parseOptionalField(section, "Published Date");
|
|
104
|
-
const text = parseTextField(section);
|
|
105
|
-
|
|
106
|
-
if (!title && !url && !text) continue;
|
|
107
|
-
|
|
108
|
-
results.push({
|
|
109
|
-
title: title ?? undefined,
|
|
110
|
-
url: url ?? undefined,
|
|
111
|
-
author: author ?? undefined,
|
|
112
|
-
publishedDate: publishedDate ?? undefined,
|
|
113
|
-
text: text ?? undefined,
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
if (results.length === 0) return null;
|
|
118
|
-
return { results };
|
|
119
|
-
}
|
|
120
|
-
|
|
121
60
|
export function normalizeSearchType(type: ExaSearchParamType | undefined): ExaSearchType {
|
|
122
61
|
if (!type) return "auto";
|
|
123
62
|
if (type === "keyword") return "fast";
|
|
@@ -195,24 +134,17 @@ async function callExaSearch(apiKey: string, params: ExaSearchParams): Promise<E
|
|
|
195
134
|
return response.json() as Promise<ExaSearchResponse>;
|
|
196
135
|
}
|
|
197
136
|
|
|
198
|
-
async function callExaMcpSearch(params: ExaSearchParams): Promise<ExaSearchResponse> {
|
|
199
|
-
const response = await callExaTool("web_search_exa", { ...params }, findApiKey());
|
|
200
|
-
if (isSearchResponse(response)) {
|
|
201
|
-
return response as ExaSearchResponse;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
const parsed = parseExaMcpTextPayload(response);
|
|
205
|
-
if (parsed) {
|
|
206
|
-
return parsed;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
throw new Error("Exa MCP search returned unexpected response shape.");
|
|
210
|
-
}
|
|
211
|
-
|
|
212
137
|
/** Execute Exa web search */
|
|
213
138
|
export async function searchExa(params: ExaSearchParams): Promise<SearchResponse> {
|
|
214
|
-
const
|
|
215
|
-
|
|
139
|
+
const storedKey = params.authStorage
|
|
140
|
+
? await params.authStorage.getApiKey("exa", params.sessionId, { signal: params.signal })
|
|
141
|
+
: undefined;
|
|
142
|
+
const apiKey = storedKey ?? getEnvApiKey("exa");
|
|
143
|
+
if (!apiKey) {
|
|
144
|
+
throw new Error("Exa credentials not found. Set EXA_API_KEY or login with 'omp /login exa'.");
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const response = await callExaSearch(apiKey, params);
|
|
216
148
|
|
|
217
149
|
// Convert to unified SearchResponse
|
|
218
150
|
const sources: SearchSource[] = [];
|
|
@@ -250,15 +182,15 @@ export class ExaProvider extends SearchProvider {
|
|
|
250
182
|
readonly id = "exa";
|
|
251
183
|
readonly label = "Exa";
|
|
252
184
|
|
|
253
|
-
isAvailable(
|
|
185
|
+
isAvailable(authStorage: AuthStorage): boolean {
|
|
254
186
|
try {
|
|
255
187
|
if (settings.get("exa.enabled") === false || settings.get("exa.enableSearch") === false) {
|
|
256
188
|
return false;
|
|
257
189
|
}
|
|
258
190
|
} catch {
|
|
259
|
-
// Settings
|
|
191
|
+
// Settings may be unavailable before CLI initialization; credential availability is still authoritative.
|
|
260
192
|
}
|
|
261
|
-
return
|
|
193
|
+
return authStorage.hasAuth("exa");
|
|
262
194
|
}
|
|
263
195
|
|
|
264
196
|
search(params: SearchParams): Promise<SearchResponse> {
|
|
@@ -266,6 +198,8 @@ export class ExaProvider extends SearchProvider {
|
|
|
266
198
|
query: params.query,
|
|
267
199
|
num_results: params.numSearchResults ?? params.limit,
|
|
268
200
|
signal: params.signal,
|
|
201
|
+
authStorage: params.authStorage,
|
|
202
|
+
sessionId: params.sessionId,
|
|
269
203
|
});
|
|
270
204
|
}
|
|
271
205
|
}
|
|
@@ -19,6 +19,7 @@ const MAX_NUM_RESULTS = 40;
|
|
|
19
19
|
export async function searchKagi(params: {
|
|
20
20
|
query: string;
|
|
21
21
|
num_results?: number;
|
|
22
|
+
recency?: SearchParams["recency"];
|
|
22
23
|
signal?: AbortSignal;
|
|
23
24
|
authStorage: AuthStorage;
|
|
24
25
|
sessionId?: string;
|
|
@@ -30,6 +31,7 @@ export async function searchKagi(params: {
|
|
|
30
31
|
params.query,
|
|
31
32
|
{
|
|
32
33
|
limit: numResults,
|
|
34
|
+
recency: params.recency,
|
|
33
35
|
sessionId: params.sessionId,
|
|
34
36
|
signal: params.signal,
|
|
35
37
|
},
|
|
@@ -41,6 +43,7 @@ export async function searchKagi(params: {
|
|
|
41
43
|
sources: toSearchSources(result.sources, numResults),
|
|
42
44
|
relatedQuestions: result.relatedQuestions.length > 0 ? result.relatedQuestions : undefined,
|
|
43
45
|
requestId: result.requestId,
|
|
46
|
+
answer: result.answer,
|
|
44
47
|
};
|
|
45
48
|
} catch (err) {
|
|
46
49
|
if (err instanceof KagiApiError) {
|
|
@@ -67,6 +70,7 @@ export class KagiProvider extends SearchProvider {
|
|
|
67
70
|
return searchKagi({
|
|
68
71
|
query: params.query,
|
|
69
72
|
num_results: params.numSearchResults ?? params.limit,
|
|
73
|
+
recency: params.recency,
|
|
70
74
|
signal: params.signal,
|
|
71
75
|
authStorage: params.authStorage,
|
|
72
76
|
sessionId: params.sessionId,
|