@oh-my-pi/pi-coding-agent 15.9.67 → 15.10.0
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 +63 -1
- package/dist/types/cli/args.d.ts +1 -1
- package/dist/types/cli/gallery-cli.d.ts +43 -0
- package/dist/types/cli/gallery-fixtures/agentic.d.ts +2 -0
- package/dist/types/cli/gallery-fixtures/codeintel.d.ts +3 -0
- package/dist/types/cli/gallery-fixtures/edit.d.ts +3 -0
- package/dist/types/cli/gallery-fixtures/fs.d.ts +2 -0
- package/dist/types/cli/gallery-fixtures/index.d.ts +4 -0
- package/dist/types/cli/gallery-fixtures/interaction.d.ts +3 -0
- package/dist/types/cli/gallery-fixtures/memory.d.ts +2 -0
- package/dist/types/cli/gallery-fixtures/misc.d.ts +3 -0
- package/dist/types/cli/gallery-fixtures/search.d.ts +3 -0
- package/dist/types/cli/gallery-fixtures/shell.d.ts +3 -0
- package/dist/types/cli/gallery-fixtures/types.d.ts +44 -0
- package/dist/types/cli/gallery-fixtures/web.d.ts +2 -0
- package/dist/types/cli/gallery-screenshot.d.ts +35 -0
- package/dist/types/commands/gallery.d.ts +47 -0
- package/dist/types/config/keybindings.d.ts +6 -1
- package/dist/types/config/model-id-affixes.d.ts +2 -0
- package/dist/types/config/model-registry.d.ts +8 -1
- package/dist/types/config/settings-schema.d.ts +32 -6
- package/dist/types/extensibility/plugins/marketplace-auto-update.d.ts +8 -0
- package/dist/types/lsp/types.d.ts +10 -0
- package/dist/types/main.d.ts +3 -2
- package/dist/types/memory-backend/index.d.ts +2 -1
- package/dist/types/memory-backend/resolve.d.ts +1 -1
- package/dist/types/memory-backend/types.d.ts +1 -1
- package/dist/types/modes/components/custom-editor.d.ts +2 -1
- package/dist/types/modes/components/tool-execution.d.ts +18 -0
- package/dist/types/modes/controllers/selector-controller.d.ts +1 -1
- package/dist/types/modes/index.d.ts +5 -4
- package/dist/types/modes/interactive-mode.d.ts +1 -1
- package/dist/types/modes/setup-version.d.ts +11 -0
- package/dist/types/modes/setup-wizard/index.d.ts +2 -1
- package/dist/types/modes/setup-wizard/scenes/web-search.d.ts +2 -1
- package/dist/types/modes/types.d.ts +1 -1
- package/dist/types/sdk.d.ts +1 -1
- package/dist/types/task/executor.d.ts +7 -0
- package/dist/types/telemetry-export.d.ts +1 -1
- package/dist/types/tools/eval-render.d.ts +1 -8
- package/dist/types/tools/fetch.d.ts +15 -7
- package/dist/types/tools/render-utils.d.ts +8 -0
- package/dist/types/tools/renderers.d.ts +16 -2
- package/dist/types/tools/search.d.ts +1 -1
- package/dist/types/tools/write.d.ts +2 -0
- package/dist/types/web/scrapers/github.d.ts +22 -0
- package/dist/types/web/search/providers/perplexity.d.ts +8 -1
- package/dist/types/web/search/types.d.ts +1 -1
- package/package.json +9 -9
- package/scripts/dev-launch +42 -0
- package/scripts/dev-launch-preload.ts +19 -0
- package/src/cli/args.ts +2 -2
- package/src/cli/gallery-cli.ts +223 -0
- package/src/cli/gallery-fixtures/agentic.ts +292 -0
- package/src/cli/gallery-fixtures/codeintel.ts +188 -0
- package/src/cli/gallery-fixtures/edit.ts +194 -0
- package/src/cli/gallery-fixtures/fs.ts +153 -0
- package/src/cli/gallery-fixtures/index.ts +40 -0
- package/src/cli/gallery-fixtures/interaction.ts +49 -0
- package/src/cli/gallery-fixtures/memory.ts +81 -0
- package/src/cli/gallery-fixtures/misc.ts +221 -0
- package/src/cli/gallery-fixtures/search.ts +213 -0
- package/src/cli/gallery-fixtures/shell.ts +167 -0
- package/src/cli/gallery-fixtures/types.ts +41 -0
- package/src/cli/gallery-fixtures/web.ts +158 -0
- package/src/cli/gallery-screenshot.ts +279 -0
- package/src/cli-commands.ts +1 -0
- package/src/commands/gallery.ts +52 -0
- package/src/commands/launch.ts +1 -1
- package/src/config/keybindings.ts +15 -6
- package/src/config/model-equivalence.ts +35 -12
- package/src/config/model-id-affixes.ts +39 -22
- package/src/config/model-registry.ts +16 -16
- package/src/config/settings-schema.ts +18 -5
- package/src/config/settings.ts +11 -0
- package/src/dap/client.ts +14 -16
- package/src/edit/renderer.ts +36 -48
- package/src/eval/__tests__/agent-bridge.test.ts +75 -32
- package/src/eval/agent-bridge.ts +34 -7
- package/src/extensibility/extensions/runner.ts +1 -0
- package/src/extensibility/plugins/doctor.ts +0 -1
- package/src/extensibility/plugins/marketplace-auto-update.ts +49 -0
- package/src/goals/tools/goal-tool.ts +2 -2
- package/src/internal-urls/docs-index.generated.ts +5 -5
- package/src/lsp/client.ts +104 -55
- package/src/lsp/types.ts +10 -0
- package/src/main.ts +44 -49
- package/src/memory-backend/index.ts +13 -1
- package/src/memory-backend/resolve.ts +3 -5
- package/src/memory-backend/types.ts +1 -1
- package/src/modes/components/custom-editor.ts +10 -1
- package/src/modes/components/status-line.ts +3 -5
- package/src/modes/components/tool-execution.ts +61 -16
- package/src/modes/controllers/command-controller.ts +13 -2
- package/src/modes/controllers/input-controller.ts +11 -3
- package/src/modes/controllers/selector-controller.ts +2 -2
- package/src/modes/index.ts +5 -4
- package/src/modes/interactive-mode.ts +17 -3
- package/src/modes/setup-version.ts +11 -0
- package/src/modes/setup-wizard/index.ts +3 -2
- package/src/modes/setup-wizard/scenes/web-search.ts +3 -2
- package/src/modes/types.ts +1 -1
- package/src/modes/utils/context-usage.ts +10 -6
- package/src/modes/utils/hotkeys-markdown.ts +1 -0
- package/src/sdk.ts +21 -23
- package/src/session/agent-session.ts +7 -7
- package/src/slash-commands/builtin-registry.ts +1 -1
- package/src/slash-commands/helpers/usage-report.ts +2 -0
- package/src/task/executor.ts +20 -2
- package/src/task/render.ts +1 -2
- package/src/telemetry-export.ts +25 -7
- package/src/tools/eval-backends.ts +6 -17
- package/src/tools/eval-render.ts +21 -18
- package/src/tools/eval.ts +5 -4
- package/src/tools/fetch.ts +94 -84
- package/src/tools/render-utils.ts +17 -3
- package/src/tools/renderers.ts +16 -1
- package/src/tools/report-tool-issue.ts +1 -1
- package/src/tools/search.ts +173 -81
- package/src/tools/todo.ts +20 -7
- package/src/tools/write.ts +22 -1
- package/src/web/scrapers/github.ts +255 -3
- package/src/web/scrapers/youtube.ts +3 -2
- package/src/web/search/providers/perplexity.ts +199 -51
- package/src/web/search/render.ts +39 -54
- package/src/web/search/types.ts +5 -1
- package/dist/types/eval/__tests__/shared-executors.test.d.ts +0 -1
- package/src/eval/__tests__/shared-executors.test.ts +0 -609
|
@@ -2,7 +2,8 @@ import type { SetupSceneHost, SetupTab } from "./types";
|
|
|
2
2
|
/**
|
|
3
3
|
* "Web search" panel: picks the provider the web_search tool should prefer and
|
|
4
4
|
* reports whether the highlighted provider is ready to use given current
|
|
5
|
-
* credentials (env keys or OAuth sign-ins from the Sign in tab)
|
|
5
|
+
* credentials (env keys or OAuth sign-ins from the Sign in tab) or an
|
|
6
|
+
* unauthenticated fallback.
|
|
6
7
|
*/
|
|
7
8
|
export declare class WebSearchTab implements SetupTab {
|
|
8
9
|
#private;
|
|
@@ -241,7 +241,7 @@ export interface InteractiveModeContext {
|
|
|
241
241
|
handleSessionDeleteCommand(): Promise<void>;
|
|
242
242
|
showOAuthSelector(mode: "login" | "logout", providerId?: string): Promise<void>;
|
|
243
243
|
showHookConfirm(title: string, message: string): Promise<boolean>;
|
|
244
|
-
showDebugSelector(): void
|
|
244
|
+
showDebugSelector(): Promise<void>;
|
|
245
245
|
showSessionObserver(): void;
|
|
246
246
|
resetObserverRegistry(): void;
|
|
247
247
|
handleCtrlC(): void;
|
package/dist/types/sdk.d.ts
CHANGED
|
@@ -13,7 +13,7 @@ import { type FileSlashCommand } from "./extensibility/slash-commands";
|
|
|
13
13
|
import type { HindsightSessionState } from "./hindsight/state";
|
|
14
14
|
import { type LocalProtocolOptions } from "./internal-urls";
|
|
15
15
|
import { MCPManager, type MCPToolsLoadResult } from "./mcp";
|
|
16
|
-
import {
|
|
16
|
+
import type { MnemopiSessionState } from "./mnemopi/state";
|
|
17
17
|
import { AgentRegistry } from "./registry/agent-registry";
|
|
18
18
|
import { AgentSession } from "./session/agent-session";
|
|
19
19
|
import { AuthStorage } from "./session/auth-storage";
|
|
@@ -48,6 +48,13 @@ export interface ExecutorOptions {
|
|
|
48
48
|
outputSchema?: unknown;
|
|
49
49
|
/** Parent task recursion depth (0 = top-level, 1 = first child, etc.) */
|
|
50
50
|
taskDepth?: number;
|
|
51
|
+
/**
|
|
52
|
+
* Override the `task.maxRuntimeMs` wall-clock cap for this run. When provided
|
|
53
|
+
* it wins over the settings value; `0` disables the per-subagent wall-clock
|
|
54
|
+
* limit entirely. Used by the eval `agent()` bridge, whose parent cell
|
|
55
|
+
* watchdog is already suspended for the call's duration.
|
|
56
|
+
*/
|
|
57
|
+
maxRuntimeMs?: number;
|
|
51
58
|
enableLsp?: boolean;
|
|
52
59
|
signal?: AbortSignal;
|
|
53
60
|
onProgress?: (progress: AgentProgress) => void;
|
|
@@ -10,7 +10,7 @@ export declare function isTelemetryExportEnabled(): boolean;
|
|
|
10
10
|
* the OTEL kill-switches are engaged), so it is safe to call unconditionally at
|
|
11
11
|
* startup.
|
|
12
12
|
*/
|
|
13
|
-
export declare function initTelemetryExport(): void
|
|
13
|
+
export declare function initTelemetryExport(): Promise<void>;
|
|
14
14
|
/**
|
|
15
15
|
* Flush any buffered spans to the exporter. No-op when export is disabled.
|
|
16
16
|
* Hosts embedding the agent can call this at natural boundaries (e.g. the end
|
|
@@ -13,14 +13,6 @@ import type { EvalStatusEvent, EvalToolDetails } from "../eval/types";
|
|
|
13
13
|
import type { RenderResultOptions } from "../extensibility/custom-tools/types";
|
|
14
14
|
import { type Theme } from "../modes/theme/theme";
|
|
15
15
|
export declare const EVAL_DEFAULT_PREVIEW_LINES = 10;
|
|
16
|
-
/**
|
|
17
|
-
* Rows of source kept in the *pending* eval preview. The window follows the
|
|
18
|
-
* streaming edge (newest lines pinned to the bottom) so you can watch the code
|
|
19
|
-
* being written, while staying bounded — a volatile tool block taller than the
|
|
20
|
-
* viewport would otherwise strand its scrolled-off head out of native scrollback
|
|
21
|
-
* on ED3-risk terminals. Matches the streaming windows used by edit/write.
|
|
22
|
-
*/
|
|
23
|
-
export declare const EVAL_STREAMING_PREVIEW_LINES = 12;
|
|
24
16
|
interface EvalRenderCellArg {
|
|
25
17
|
language?: string;
|
|
26
18
|
code?: string;
|
|
@@ -54,6 +46,7 @@ export declare const evalToolRenderer: {
|
|
|
54
46
|
}, options: RenderResultOptions & {
|
|
55
47
|
renderContext?: EvalRenderContext;
|
|
56
48
|
}, uiTheme: Theme, _args?: EvalRenderArgs): Component;
|
|
49
|
+
isStreamingPreviewAppendOnly(_args: EvalRenderArgs, _options: RenderResultOptions, result?: unknown): boolean;
|
|
57
50
|
mergeCallAndResult: boolean;
|
|
58
51
|
inline: boolean;
|
|
59
52
|
};
|
|
@@ -17,14 +17,22 @@ export interface ParsedReadUrlTarget {
|
|
|
17
17
|
ranges?: readonly LineRange[];
|
|
18
18
|
}
|
|
19
19
|
export declare function parseReadUrlTarget(readPath: string): ParsedReadUrlTarget | null;
|
|
20
|
+
/** Reader backends for {@link renderHtmlToText}, in default priority order. */
|
|
21
|
+
export type FetchProvider = "native" | "trafilatura" | "lynx" | "parallel" | "jina";
|
|
20
22
|
/**
|
|
21
|
-
* Render HTML to markdown
|
|
22
|
-
* in-process
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
23
|
+
* Render HTML to markdown by trying reader backends in priority order: native
|
|
24
|
+
* (in-process), trafilatura, lynx, Parallel, then Jina. The `providers.fetch`
|
|
25
|
+
* setting picks the order — `auto` uses the default above; any specific backend
|
|
26
|
+
* is tried first, then the remaining backends as fallbacks. Every backend's
|
|
27
|
+
* output must clear the same quality gate (>100 non-whitespace chars and not
|
|
28
|
+
* {@link isLowQualityOutput}) before it is accepted, otherwise the next backend
|
|
29
|
+
* is tried.
|
|
30
|
+
*
|
|
31
|
+
* The overall `timeout` budget bounds the whole call; remote backends (Parallel,
|
|
32
|
+
* Jina) are additionally capped at `REMOTE_READER_MAX_MS` so a hung endpoint
|
|
33
|
+
* cannot starve later renderers — especially the purely-local native converter,
|
|
34
|
+
* which always works on already-loaded HTML. Only a real `userSignal`
|
|
35
|
+
* cancellation aborts the chain (#1449).
|
|
28
36
|
*/
|
|
29
37
|
export declare function renderHtmlToText(url: string, html: string, timeout: number, settings: Settings, userSignal: AbortSignal | undefined, storage: AgentStorage | null): Promise<{
|
|
30
38
|
content: string;
|
|
@@ -103,6 +103,14 @@ export declare function capPreviewLines(lines: string[], theme: Theme, options?:
|
|
|
103
103
|
}): string[];
|
|
104
104
|
export declare function formatMeta(meta: string[], theme: Theme): string;
|
|
105
105
|
export declare function formatErrorMessage(message: string | undefined, theme: Theme): string;
|
|
106
|
+
/**
|
|
107
|
+
* Error message rendered as a subordinate detail line beneath a status header
|
|
108
|
+
* that already carries the error icon (e.g. `✘ Write: <path>`). The header's
|
|
109
|
+
* icon already signals failure, so this omits the redundant error symbol and
|
|
110
|
+
* "Error:" prefix that `formatErrorMessage` adds for standalone single-line
|
|
111
|
+
* errors, indenting two columns to sit under the header title instead.
|
|
112
|
+
*/
|
|
113
|
+
export declare function formatErrorDetail(message: string | undefined, theme: Theme): string;
|
|
106
114
|
export declare function formatEmptyMessage(message: string, theme: Theme): string;
|
|
107
115
|
export type CodeFrameMarker = "" | " " | "*" | "+" | "-" | ">";
|
|
108
116
|
export declare function formatCodeFrameLine(marker: CodeFrameMarker, lineNumber: string | number, content: string, lineNumberWidth: number): string;
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import type { Component } from "@oh-my-pi/pi-tui";
|
|
7
7
|
import type { RenderResultOptions } from "../extensibility/custom-tools/types";
|
|
8
8
|
import type { Theme } from "../modes/theme/theme";
|
|
9
|
-
type ToolRenderer = {
|
|
9
|
+
export type ToolRenderer = {
|
|
10
10
|
renderCall: (args: unknown, options: RenderResultOptions, theme: Theme) => Component;
|
|
11
11
|
renderResult: (result: {
|
|
12
12
|
content: Array<{
|
|
@@ -19,8 +19,22 @@ type ToolRenderer = {
|
|
|
19
19
|
renderContext?: Record<string, unknown>;
|
|
20
20
|
}, theme: Theme, args?: unknown) => Component;
|
|
21
21
|
mergeCallAndResult?: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* While a tool's preview is still streaming, report whether the
|
|
24
|
+
* currently-rendered preview is append-only: its rows only grow at the bottom
|
|
25
|
+
* and never re-layout above the bottom live region (a full, top-anchored
|
|
26
|
+
* content/code preview). The transcript reports this up to the TUI so a
|
|
27
|
+
* streaming preview taller than the viewport commits its scrolled-off head to
|
|
28
|
+
* native scrollback instead of dropping it (see
|
|
29
|
+
* `ToolExecutionComponent.isTranscriptBlockAppendOnly`). `result` is the
|
|
30
|
+
* latest (possibly partial) tool result, or `undefined` before one exists —
|
|
31
|
+
* `eval`/`bash` use its presence to defer committing until the streamed input
|
|
32
|
+
* (code) has finalized. Omit (or return `false`) for previews that slide a
|
|
33
|
+
* tail window or later collapse to a compact result — committing their head
|
|
34
|
+
* would strand stale rows.
|
|
35
|
+
*/
|
|
36
|
+
isStreamingPreviewAppendOnly?: (args: unknown, options: RenderResultOptions, result?: unknown) => boolean;
|
|
22
37
|
/** Render without background box, inline in the response flow */
|
|
23
38
|
inline?: boolean;
|
|
24
39
|
};
|
|
25
40
|
export declare const toolRenderers: Record<string, ToolRenderer>;
|
|
26
|
-
export {};
|
|
@@ -5,7 +5,7 @@ import type { RenderResultOptions } from "../extensibility/custom-tools/types";
|
|
|
5
5
|
import type { Theme } from "../modes/theme/theme";
|
|
6
6
|
import { type TruncationResult } from "../session/streaming-output";
|
|
7
7
|
import type { ToolSession } from ".";
|
|
8
|
-
import {
|
|
8
|
+
import type { OutputMeta } from "./output-meta";
|
|
9
9
|
declare const searchSchema: z.ZodObject<{
|
|
10
10
|
pattern: z.ZodString;
|
|
11
11
|
paths: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
@@ -53,12 +53,14 @@ interface WriteRenderArgs {
|
|
|
53
53
|
}
|
|
54
54
|
export declare const writeToolRenderer: {
|
|
55
55
|
renderCall(args: WriteRenderArgs, options: RenderResultOptions, uiTheme: Theme): Component;
|
|
56
|
+
isStreamingPreviewAppendOnly(args: WriteRenderArgs, options: RenderResultOptions, _result?: unknown): boolean;
|
|
56
57
|
renderResult(result: {
|
|
57
58
|
content: Array<{
|
|
58
59
|
type: string;
|
|
59
60
|
text?: string;
|
|
60
61
|
}>;
|
|
61
62
|
details?: WriteToolDetails;
|
|
63
|
+
isError?: boolean;
|
|
62
64
|
}, options: RenderResultOptions, uiTheme: Theme, args?: WriteRenderArgs): Component;
|
|
63
65
|
mergeCallAndResult: boolean;
|
|
64
66
|
};
|
|
@@ -1,4 +1,18 @@
|
|
|
1
1
|
import type { SpecialHandler } from "./types";
|
|
2
|
+
interface GitHubUrl {
|
|
3
|
+
type: "blob" | "tree" | "repo" | "issue" | "issues" | "pull" | "pulls" | "discussion" | "discussions" | "actions-run" | "actions-job" | "other";
|
|
4
|
+
owner: string;
|
|
5
|
+
repo: string;
|
|
6
|
+
ref?: string;
|
|
7
|
+
path?: string;
|
|
8
|
+
number?: number;
|
|
9
|
+
runId?: number;
|
|
10
|
+
jobId?: number;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Parse GitHub URL into components
|
|
14
|
+
*/
|
|
15
|
+
export declare function parseGitHubUrl(url: string): GitHubUrl | null;
|
|
2
16
|
/**
|
|
3
17
|
* Fetch from GitHub API
|
|
4
18
|
*/
|
|
@@ -6,7 +20,15 @@ export declare function fetchGitHubApi(endpoint: string, timeout: number, signal
|
|
|
6
20
|
data: unknown;
|
|
7
21
|
ok: boolean;
|
|
8
22
|
}>;
|
|
23
|
+
/**
|
|
24
|
+
* Strip the per-line ISO-8601 timestamp prefix GitHub prepends to every job log line.
|
|
25
|
+
* Cuts ~28 bytes/line of noise while preserving the message text. Also drops the leading
|
|
26
|
+
* UTF-8 BOM GitHub puts at the start of the log file (otherwise the first line's timestamp
|
|
27
|
+
* survives because `^` no longer sits before a digit).
|
|
28
|
+
*/
|
|
29
|
+
export declare function stripActionsLogTimestamps(logs: string): string;
|
|
9
30
|
/**
|
|
10
31
|
* Handle GitHub URLs specially
|
|
11
32
|
*/
|
|
12
33
|
export declare const handleGitHub: SpecialHandler;
|
|
34
|
+
export {};
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Perplexity Web Search Provider
|
|
3
3
|
*
|
|
4
|
-
* Supports
|
|
4
|
+
* Supports four auth modes:
|
|
5
5
|
* - Cookies (`PERPLEXITY_COOKIES`) via `www.perplexity.ai/rest/sse/perplexity_ask`
|
|
6
6
|
* - OAuth/session bearer via `AuthStorage` and `www.perplexity.ai/rest/sse/perplexity_ask`
|
|
7
7
|
* - API key (`PERPLEXITY_API_KEY`) via `api.perplexity.ai/chat/completions`
|
|
8
|
+
* - Anonymous via `www.perplexity.ai/rest/sse/perplexity_ask`
|
|
8
9
|
*/
|
|
9
10
|
import { type AuthStorage } from "@oh-my-pi/pi-ai";
|
|
10
11
|
import type { SearchResponse } from "../../../web/search/types";
|
|
@@ -34,5 +35,11 @@ export declare class PerplexityProvider extends SearchProvider {
|
|
|
34
35
|
readonly id = "perplexity";
|
|
35
36
|
readonly label = "Perplexity";
|
|
36
37
|
isAvailable(authStorage: AuthStorage): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Perplexity accepts anonymous browser-style ask requests, but keep auto
|
|
40
|
+
* provider selection credential-gated so a configured provider keeps priority
|
|
41
|
+
* over the anonymous fallback.
|
|
42
|
+
*/
|
|
43
|
+
isExplicitlyAvailable(_authStorage: AuthStorage): boolean;
|
|
37
44
|
search(params: SearchParams): Promise<SearchResponse>;
|
|
38
45
|
}
|
|
@@ -18,7 +18,7 @@ export declare const SEARCH_PROVIDER_OPTIONS: readonly [{
|
|
|
18
18
|
}, {
|
|
19
19
|
readonly value: "perplexity";
|
|
20
20
|
readonly label: "Perplexity";
|
|
21
|
-
readonly description: "
|
|
21
|
+
readonly description: "Uses auth when configured; explicit selection falls back to anonymous search";
|
|
22
22
|
}, {
|
|
23
23
|
readonly value: "brave";
|
|
24
24
|
readonly label: "Brave";
|
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.10.0",
|
|
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,14 +47,14 @@
|
|
|
47
47
|
"@agentclientprotocol/sdk": "0.22.1",
|
|
48
48
|
"@babel/parser": "^7.29.7",
|
|
49
49
|
"@mozilla/readability": "^0.6.0",
|
|
50
|
-
"@oh-my-pi/hashline": "15.
|
|
51
|
-
"@oh-my-pi/omp-stats": "15.
|
|
52
|
-
"@oh-my-pi/pi-agent-core": "15.
|
|
53
|
-
"@oh-my-pi/pi-ai": "15.
|
|
54
|
-
"@oh-my-pi/pi-mnemopi": "15.
|
|
55
|
-
"@oh-my-pi/pi-natives": "15.
|
|
56
|
-
"@oh-my-pi/pi-tui": "15.
|
|
57
|
-
"@oh-my-pi/pi-utils": "15.
|
|
50
|
+
"@oh-my-pi/hashline": "15.10.0",
|
|
51
|
+
"@oh-my-pi/omp-stats": "15.10.0",
|
|
52
|
+
"@oh-my-pi/pi-agent-core": "15.10.0",
|
|
53
|
+
"@oh-my-pi/pi-ai": "15.10.0",
|
|
54
|
+
"@oh-my-pi/pi-mnemopi": "15.10.0",
|
|
55
|
+
"@oh-my-pi/pi-natives": "15.10.0",
|
|
56
|
+
"@oh-my-pi/pi-tui": "15.10.0",
|
|
57
|
+
"@oh-my-pi/pi-utils": "15.10.0",
|
|
58
58
|
"@opentelemetry/api": "^1.9.1",
|
|
59
59
|
"@opentelemetry/context-async-hooks": "^2.7.1",
|
|
60
60
|
"@opentelemetry/exporter-trace-otlp-proto": "^0.218.0",
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# Dev launcher for the omp CLI, installed by `bun run install:dev`.
|
|
3
|
+
#
|
|
4
|
+
# Problem it solves: Bun reads `bunfig.toml` from the *current working
|
|
5
|
+
# directory* at startup and evaluates its `preload` entries before running the
|
|
6
|
+
# script. A bun-shebang bin (what `bun link` creates for `src/cli.ts`)
|
|
7
|
+
# therefore inherits whatever `preload` the directory you happen to be in
|
|
8
|
+
# declares. Running `omp`/`pi` inside an unrelated Bun project can execute — and
|
|
9
|
+
# crash on — that project's preload, e.g.
|
|
10
|
+
# error: Cannot find module '@v12sh/utils/frontmatter' from '.../loader.ts'
|
|
11
|
+
#
|
|
12
|
+
# Bun only reads the *exact* cwd (it does not walk parents) and ignores
|
|
13
|
+
# `--config`/`BUN_BE_BUN` for this, so the fix is to launch Bun from an empty,
|
|
14
|
+
# bunfig-free directory and restore the real cwd inside the process via the
|
|
15
|
+
# preload shim alongside this file.
|
|
16
|
+
set -e
|
|
17
|
+
|
|
18
|
+
# Resolve this script's real location even when invoked through a symlink
|
|
19
|
+
# (`$HOME/.bun/bin/omp` -> this file).
|
|
20
|
+
self=$0
|
|
21
|
+
while [ -L "$self" ]; do
|
|
22
|
+
link=$(readlink "$self")
|
|
23
|
+
case $link in
|
|
24
|
+
/*) self=$link ;;
|
|
25
|
+
*) self=$(dirname "$self")/$link ;;
|
|
26
|
+
esac
|
|
27
|
+
done
|
|
28
|
+
scripts_dir=$(CDPATH= cd -- "$(dirname -- "$self")" && pwd -P)
|
|
29
|
+
cli=$scripts_dir/../src/cli.ts
|
|
30
|
+
preload=$scripts_dir/dev-launch-preload.ts
|
|
31
|
+
timing_preload=$scripts_dir/../../utils/src/module-timer.ts
|
|
32
|
+
|
|
33
|
+
launch_dir=${OMP_DEV_LAUNCH_DIR:-${HOME}/.omp/.dev-cwd}
|
|
34
|
+
mkdir -p "$launch_dir"
|
|
35
|
+
|
|
36
|
+
OMP_LAUNCH_CWD=$PWD
|
|
37
|
+
export OMP_LAUNCH_CWD
|
|
38
|
+
cd "$launch_dir"
|
|
39
|
+
if [ -n "${PI_TIMING:-}" ]; then
|
|
40
|
+
exec bun --preload "$preload" --preload "$timing_preload" "$cli" "$@"
|
|
41
|
+
fi
|
|
42
|
+
exec bun --preload "$preload" "$cli" "$@"
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bun `--preload` shim for the omp dev launcher (`scripts/dev-launch`).
|
|
3
|
+
*
|
|
4
|
+
* The launcher starts Bun from an empty, bunfig-free directory so a foreign
|
|
5
|
+
* project's `bunfig.toml` `preload` cannot run inside the omp CLI: Bun reads
|
|
6
|
+
* `bunfig.toml` from the *current working directory* on startup and evaluates
|
|
7
|
+
* its `preload` entries before the entrypoint, so a bun-shebang bin inherits
|
|
8
|
+
* whatever `preload` the directory you launched from declares (and crashes if
|
|
9
|
+
* that preload can't resolve). This shim is loaded before the entrypoint's
|
|
10
|
+
* imports run, so it restores the user's real working directory in time for
|
|
11
|
+
* import-time snapshots (e.g. `getProjectDir()` in `@oh-my-pi/pi-utils/dirs`).
|
|
12
|
+
*/
|
|
13
|
+
const launchCwd = process.env.OMP_LAUNCH_CWD;
|
|
14
|
+
if (launchCwd) {
|
|
15
|
+
delete process.env.OMP_LAUNCH_CWD;
|
|
16
|
+
try {
|
|
17
|
+
process.chdir(launchCwd);
|
|
18
|
+
} catch {}
|
|
19
|
+
}
|
package/src/cli/args.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* CLI argument parsing and help display
|
|
3
3
|
*/
|
|
4
|
-
import { type Effort, THINKING_EFFORTS } from "@oh-my-pi/pi-ai";
|
|
4
|
+
import { type Effort, THINKING_EFFORTS } from "@oh-my-pi/pi-ai/effort";
|
|
5
5
|
import { APP_NAME, CONFIG_DIR_NAME, logger } from "@oh-my-pi/pi-utils";
|
|
6
6
|
import chalk from "chalk";
|
|
7
7
|
import { parseEffort } from "../thinking";
|
|
@@ -284,7 +284,7 @@ export function getExtraHelpText(): string {
|
|
|
284
284
|
${chalk.dim("# Search & Tools")}
|
|
285
285
|
EXA_API_KEY - Exa web search
|
|
286
286
|
BRAVE_API_KEY - Brave web search
|
|
287
|
-
PERPLEXITY_API_KEY - Perplexity web search (
|
|
287
|
+
PERPLEXITY_API_KEY - Perplexity web search API key (optional; anonymous fallback)
|
|
288
288
|
PERPLEXITY_COOKIES - Perplexity web search (session cookie)
|
|
289
289
|
TAVILY_API_KEY - Tavily web search
|
|
290
290
|
ANTHROPIC_SEARCH_API_KEY - Anthropic web search (override; isolates search from main ANTHROPIC_API_KEY)
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `omp gallery` — render every built-in tool's renderer across its lifecycle.
|
|
3
|
+
*
|
|
4
|
+
* For each tool with a registered renderer, the gallery drives a real
|
|
5
|
+
* {@link ToolExecutionComponent} through four states — streaming arguments,
|
|
6
|
+
* arguments complete (in progress), success, and failure — and prints the
|
|
7
|
+
* rendered output to stdout. It exists for visual QA of tool renderers without
|
|
8
|
+
* having to provoke each state through a live agent session.
|
|
9
|
+
*/
|
|
10
|
+
import type { AgentTool } from "@oh-my-pi/pi-agent-core";
|
|
11
|
+
import type { TUI } from "@oh-my-pi/pi-tui";
|
|
12
|
+
import { getProjectDir } from "@oh-my-pi/pi-utils";
|
|
13
|
+
import { Settings } from "../config/settings";
|
|
14
|
+
import { ToolExecutionComponent } from "../modes/components/tool-execution";
|
|
15
|
+
import { initTheme, theme } from "../modes/theme/theme";
|
|
16
|
+
import { toolRenderers } from "../tools/renderers";
|
|
17
|
+
import { type GalleryFixture, type GalleryResult, galleryFixtures } from "./gallery-fixtures";
|
|
18
|
+
import { captureGalleryScreenshots } from "./gallery-screenshot";
|
|
19
|
+
|
|
20
|
+
/** Lifecycle states the gallery renders, in display order. */
|
|
21
|
+
export const GALLERY_STATES = ["streaming", "progress", "success", "error"] as const;
|
|
22
|
+
export type GalleryState = (typeof GALLERY_STATES)[number];
|
|
23
|
+
|
|
24
|
+
const STATE_LABELS: Record<GalleryState, string> = {
|
|
25
|
+
streaming: "streaming args",
|
|
26
|
+
progress: "in progress",
|
|
27
|
+
success: "done",
|
|
28
|
+
error: "failed",
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export interface GalleryCommandArgs {
|
|
32
|
+
/** Render width in columns (defaults to terminal width, clamped). */
|
|
33
|
+
width?: number;
|
|
34
|
+
/** Restrict to a single tool name. */
|
|
35
|
+
tool?: string;
|
|
36
|
+
/** Restrict to specific lifecycle states. */
|
|
37
|
+
states?: GalleryState[];
|
|
38
|
+
/** Render the expanded variant of each renderer. */
|
|
39
|
+
expanded?: boolean;
|
|
40
|
+
/** Strip ANSI styling from the output (useful when redirecting to a file). */
|
|
41
|
+
plain?: boolean;
|
|
42
|
+
/** Capture the rendered gallery as PNG screenshot(s) via VHS instead of printing ANSI. */
|
|
43
|
+
screenshot?: boolean;
|
|
44
|
+
/** Screenshot output path (single image) or base path (suffixed when split across images). */
|
|
45
|
+
out?: string;
|
|
46
|
+
/** Font family for screenshots (must be installed; Nerd Font recommended for icon glyphs). */
|
|
47
|
+
font?: string;
|
|
48
|
+
/** Font size in points for screenshots. */
|
|
49
|
+
fontSize?: number;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** One tool's rendered lifecycle, as ANSI lines: a leading blank, the section rule, then each state. */
|
|
53
|
+
export interface GallerySection {
|
|
54
|
+
heading: string;
|
|
55
|
+
lines: string[];
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const GENERIC_ERROR: GalleryResult = {
|
|
59
|
+
content: [{ type: "text", text: "Error: operation failed" }],
|
|
60
|
+
isError: true,
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Build the fake `AgentTool` the component needs for its label, edit mode, and —
|
|
65
|
+
* for `customRendered` fixtures — the renderer functions that route it through
|
|
66
|
+
* the same custom-tool branch production uses (see {@link GalleryFixture}).
|
|
67
|
+
*/
|
|
68
|
+
function fakeToolFor(name: string, fixture: GalleryFixture | undefined): AgentTool | undefined {
|
|
69
|
+
if (!fixture?.label && !fixture?.editMode && !fixture?.customRendered) return undefined;
|
|
70
|
+
const tool: Record<string, unknown> = { name, label: fixture.label ?? name, mode: fixture.editMode };
|
|
71
|
+
if (fixture.customRendered) {
|
|
72
|
+
const renderer = toolRenderers[name] as
|
|
73
|
+
| { renderCall?: unknown; renderResult?: unknown; mergeCallAndResult?: unknown; inline?: unknown }
|
|
74
|
+
| undefined;
|
|
75
|
+
if (renderer) {
|
|
76
|
+
tool.renderCall = renderer.renderCall;
|
|
77
|
+
tool.renderResult = renderer.renderResult;
|
|
78
|
+
tool.mergeCallAndResult = renderer.mergeCallAndResult;
|
|
79
|
+
tool.inline = renderer.inline;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return tool as unknown as AgentTool;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** The curated fixture for a tool, or a generic one for registry tools lacking sample data. */
|
|
86
|
+
export function resolveFixture(name: string): GalleryFixture {
|
|
87
|
+
return (
|
|
88
|
+
galleryFixtures[name] ??
|
|
89
|
+
({
|
|
90
|
+
args: { note: `sample ${name} call` },
|
|
91
|
+
result: { content: [{ type: "text", text: `${name} completed` }] },
|
|
92
|
+
} satisfies GalleryFixture)
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Render a single tool/state pair to lines. Builds a fresh component, drives it
|
|
98
|
+
* to the requested state, settles any async edit preview, then snapshots the
|
|
99
|
+
* render and stops all animation timers.
|
|
100
|
+
*/
|
|
101
|
+
export async function renderGalleryState(
|
|
102
|
+
name: string,
|
|
103
|
+
fixture: GalleryFixture,
|
|
104
|
+
state: GalleryState,
|
|
105
|
+
width: number,
|
|
106
|
+
expanded = false,
|
|
107
|
+
): Promise<string[]> {
|
|
108
|
+
const tool = fakeToolFor(name, fixture);
|
|
109
|
+
const streamingArgs = state === "streaming" ? (fixture.streamingArgs ?? fixture.args) : fixture.args;
|
|
110
|
+
// The component only calls `requestRender` during a static render;
|
|
111
|
+
// `imageBudget` is consulted solely when images render, which the gallery
|
|
112
|
+
// disables. A cast avoids constructing a real terminal.
|
|
113
|
+
const ui = { requestRender() {} } as unknown as TUI;
|
|
114
|
+
const component = new ToolExecutionComponent(name, streamingArgs, { showImages: false }, tool, ui, getProjectDir());
|
|
115
|
+
component.setExpanded(expanded);
|
|
116
|
+
|
|
117
|
+
if (state !== "streaming") {
|
|
118
|
+
component.setArgsComplete();
|
|
119
|
+
}
|
|
120
|
+
if (state === "success") {
|
|
121
|
+
component.updateResult(fixture.result, false);
|
|
122
|
+
} else if (state === "error") {
|
|
123
|
+
component.updateResult(fixture.errorResult ?? GENERIC_ERROR, false);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Edit-like renderers compute their diff preview off the render path; wait
|
|
127
|
+
// for it to settle so the snapshot is deterministic instead of racing a tick.
|
|
128
|
+
await component.whenPreviewSettled();
|
|
129
|
+
|
|
130
|
+
const lines = component.render(width);
|
|
131
|
+
component.stopAnimation();
|
|
132
|
+
return lines;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function resolveWidth(requested: number | undefined): number {
|
|
136
|
+
const fallback = process.stdout.columns ?? 100;
|
|
137
|
+
const width = requested ?? fallback;
|
|
138
|
+
return Math.max(40, Math.min(200, width));
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function sectionRule(label: string, width: number): string {
|
|
142
|
+
const prefix = `── ${label} `;
|
|
143
|
+
const fill = Math.max(0, width - prefix.length);
|
|
144
|
+
return theme.fg("accent", theme.bold(`${prefix}${"─".repeat(fill)}`));
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Render each requested tool's lifecycle into ANSI section blocks. The block
|
|
149
|
+
* layout (leading blank, section rule, then a blank + dim label + body per
|
|
150
|
+
* state) is shared by the stdout and screenshot paths so both stay identical.
|
|
151
|
+
*/
|
|
152
|
+
async function renderGallerySections(
|
|
153
|
+
names: string[],
|
|
154
|
+
states: GalleryState[],
|
|
155
|
+
width: number,
|
|
156
|
+
expanded: boolean,
|
|
157
|
+
): Promise<GallerySection[]> {
|
|
158
|
+
const sections: GallerySection[] = [];
|
|
159
|
+
for (const name of names) {
|
|
160
|
+
const fixture = resolveFixture(name);
|
|
161
|
+
const heading = fixture.label && fixture.label !== name ? `${name} — ${fixture.label}` : name;
|
|
162
|
+
const lines: string[] = ["", sectionRule(heading, width)];
|
|
163
|
+
for (const state of states) {
|
|
164
|
+
lines.push("", theme.fg("dim", ` · ${STATE_LABELS[state]}`));
|
|
165
|
+
try {
|
|
166
|
+
for (const line of await renderGalleryState(name, fixture, state, width, expanded)) lines.push(line);
|
|
167
|
+
} catch (err) {
|
|
168
|
+
lines.push(theme.fg("error", ` render failed: ${String(err)}`));
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
sections.push({ heading, lines });
|
|
172
|
+
}
|
|
173
|
+
return sections;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Render the gallery. Iterates the renderer registry (or a single tool),
|
|
178
|
+
* printing each requested lifecycle state under a labeled section — or, with
|
|
179
|
+
* `screenshot`, capturing the rendered output as PNG(s) via VHS.
|
|
180
|
+
*/
|
|
181
|
+
export async function runGalleryCommand(args: GalleryCommandArgs): Promise<void> {
|
|
182
|
+
const settingsInstance = await Settings.init();
|
|
183
|
+
// Screenshots must carry exact theme RGB regardless of how the invoking
|
|
184
|
+
// terminal advertises its color support, so force truecolor before the theme
|
|
185
|
+
// (and therefore every SGR escape it emits) is built.
|
|
186
|
+
if (args.screenshot) process.env.COLORTERM = "truecolor";
|
|
187
|
+
await initTheme(
|
|
188
|
+
false,
|
|
189
|
+
settingsInstance.get("symbolPreset"),
|
|
190
|
+
settingsInstance.get("colorBlindMode"),
|
|
191
|
+
settingsInstance.get("theme.dark"),
|
|
192
|
+
settingsInstance.get("theme.light"),
|
|
193
|
+
);
|
|
194
|
+
|
|
195
|
+
const width = resolveWidth(args.width);
|
|
196
|
+
const expanded = args.expanded ?? false;
|
|
197
|
+
const states = args.states && args.states.length > 0 ? args.states : [...GALLERY_STATES];
|
|
198
|
+
|
|
199
|
+
const allNames = Object.keys(toolRenderers).sort();
|
|
200
|
+
const names = args.tool ? allNames.filter(name => name === args.tool) : allNames;
|
|
201
|
+
if (args.tool && names.length === 0) {
|
|
202
|
+
process.stdout.write(`Unknown tool '${args.tool}'. Known tools: ${allNames.join(", ")}\n`);
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const sections = await renderGallerySections(names, states, width, expanded);
|
|
207
|
+
|
|
208
|
+
if (args.screenshot) {
|
|
209
|
+
const paths = await captureGalleryScreenshots(sections, {
|
|
210
|
+
width,
|
|
211
|
+
font: args.font,
|
|
212
|
+
fontSize: args.fontSize,
|
|
213
|
+
out: args.out,
|
|
214
|
+
});
|
|
215
|
+
process.stdout.write(`${paths.join("\n")}\n`);
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const lines = sections.flatMap(section => section.lines);
|
|
220
|
+
lines.push("");
|
|
221
|
+
const text = lines.map(line => (args.plain ? Bun.stripANSI(line) : line)).join("\n");
|
|
222
|
+
process.stdout.write(`${text}\n`);
|
|
223
|
+
}
|