@oh-my-pi/pi-coding-agent 15.9.5 → 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 +98 -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 +10 -2
- 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 +43 -7
- package/dist/types/edit/file-snapshot-store.d.ts +1 -1
- package/dist/types/eval/backend.d.ts +6 -6
- package/dist/types/eval/bridge-timeout.d.ts +27 -0
- package/dist/types/eval/idle-timeout.d.ts +16 -14
- package/dist/types/eval/js/executor.d.ts +3 -3
- package/dist/types/eval/py/executor.d.ts +2 -2
- package/dist/types/eval/py/spawn-options.d.ts +58 -0
- 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/assistant-message.d.ts +5 -0
- package/dist/types/modes/components/copy-selector.d.ts +22 -0
- package/dist/types/modes/components/custom-editor.d.ts +2 -1
- package/dist/types/modes/components/model-selector.d.ts +1 -0
- package/dist/types/modes/components/tool-execution.d.ts +18 -0
- package/dist/types/modes/controllers/command-controller.d.ts +0 -1
- package/dist/types/modes/controllers/selector-controller.d.ts +2 -1
- package/dist/types/modes/index.d.ts +5 -4
- package/dist/types/modes/interactive-mode.d.ts +2 -2
- 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 +2 -2
- package/dist/types/modes/utils/copy-targets.d.ts +53 -0
- 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 -0
- package/dist/types/tools/fetch.d.ts +15 -7
- package/dist/types/tools/render-utils.d.ts +33 -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/tui/code-cell.d.ts +6 -0
- package/dist/types/tui/output-block.d.ts +11 -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/autoresearch/dashboard.ts +11 -21
- package/src/cli/args.ts +2 -2
- package/src/cli/claude-trace-cli.ts +13 -1
- 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 +68 -2
- 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 +29 -6
- package/src/config/settings.ts +11 -0
- package/src/dap/client.ts +14 -16
- package/src/debug/raw-sse.ts +18 -4
- package/src/edit/file-snapshot-store.ts +1 -1
- package/src/edit/index.ts +1 -1
- package/src/edit/renderer.ts +43 -55
- package/src/edit/streaming.ts +1 -1
- package/src/eval/__tests__/agent-bridge.test.ts +102 -58
- package/src/eval/__tests__/bridge-timeout.test.ts +64 -0
- package/src/eval/__tests__/idle-timeout.test.ts +26 -12
- package/src/eval/__tests__/kernel-spawn.test.ts +103 -0
- package/src/eval/__tests__/llm-bridge.test.ts +10 -10
- package/src/eval/agent-bridge.ts +38 -12
- package/src/eval/backend.ts +6 -6
- package/src/eval/bridge-timeout.ts +44 -0
- package/src/eval/idle-timeout.ts +33 -15
- package/src/eval/js/executor.ts +10 -10
- package/src/eval/llm-bridge.ts +4 -5
- package/src/eval/py/executor.ts +6 -6
- package/src/eval/py/kernel.ts +11 -1
- package/src/eval/py/spawn-options.ts +126 -0
- package/src/export/ttsr.ts +9 -0
- package/src/extensibility/extensions/runner.ts +3 -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 +7 -6
- package/src/lsp/client.ts +179 -52
- package/src/lsp/index.ts +38 -4
- package/src/lsp/render.ts +3 -3
- package/src/lsp/types.ts +10 -0
- package/src/main.ts +47 -52
- 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/agent-dashboard.ts +13 -4
- package/src/modes/components/assistant-message.ts +22 -1
- package/src/modes/components/copy-selector.ts +249 -0
- package/src/modes/components/custom-editor.ts +10 -1
- package/src/modes/components/extensions/extension-list.ts +17 -8
- package/src/modes/components/history-search.ts +19 -11
- package/src/modes/components/model-selector.ts +125 -29
- package/src/modes/components/oauth-selector.ts +28 -12
- package/src/modes/components/session-observer-overlay.ts +13 -15
- package/src/modes/components/session-selector.ts +24 -13
- package/src/modes/components/status-line.ts +3 -5
- package/src/modes/components/tool-execution.ts +83 -24
- package/src/modes/components/tree-selector.ts +19 -7
- package/src/modes/components/user-message-selector.ts +25 -14
- package/src/modes/controllers/command-controller.ts +13 -118
- package/src/modes/controllers/event-controller.ts +26 -10
- package/src/modes/controllers/input-controller.ts +11 -3
- package/src/modes/controllers/selector-controller.ts +40 -3
- package/src/modes/index.ts +5 -4
- package/src/modes/interactive-mode.ts +21 -7
- 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/theme/theme.ts +46 -10
- package/src/modes/types.ts +2 -2
- package/src/modes/utils/context-usage.ts +10 -6
- package/src/modes/utils/copy-targets.ts +254 -0
- package/src/modes/utils/hotkeys-markdown.ts +1 -0
- package/src/prompts/tools/ast-edit.md +1 -1
- package/src/prompts/tools/ast-grep.md +1 -1
- package/src/prompts/tools/read.md +1 -1
- package/src/prompts/tools/search.md +1 -1
- package/src/sdk.ts +21 -23
- package/src/session/agent-session.ts +13 -9
- package/src/slash-commands/builtin-registry.ts +4 -12
- package/src/slash-commands/helpers/usage-report.ts +2 -0
- package/src/task/executor.ts +20 -2
- package/src/task/render.ts +37 -11
- package/src/telemetry-export.ts +25 -7
- package/src/tools/bash.ts +18 -8
- package/src/tools/browser/render.ts +5 -4
- package/src/tools/debug.ts +3 -3
- package/src/tools/eval-backends.ts +6 -17
- package/src/tools/eval-render.ts +28 -10
- package/src/tools/eval.ts +19 -23
- package/src/tools/fetch.ts +99 -89
- package/src/tools/read.ts +7 -7
- package/src/tools/render-utils.ts +63 -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/ssh.ts +21 -8
- package/src/tools/todo.ts +20 -7
- package/src/tools/write.ts +39 -9
- package/src/tui/code-cell.ts +19 -4
- package/src/tui/output-block.ts +14 -0
- 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 +42 -57
- package/src/web/search/types.ts +5 -1
- package/dist/types/eval/heartbeat.d.ts +0 -45
- package/src/eval/__tests__/heartbeat.test.ts +0 -84
- package/src/eval/__tests__/shared-executors.test.ts +0 -609
- package/src/eval/heartbeat.ts +0 -74
- /package/dist/types/eval/__tests__/{heartbeat.test.d.ts → bridge-timeout.test.d.ts} +0 -0
- /package/dist/types/eval/__tests__/{shared-executors.test.d.ts → kernel-spawn.test.d.ts} +0 -0
|
@@ -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
|
};
|
|
@@ -11,6 +11,12 @@ export interface CodeCellOptions {
|
|
|
11
11
|
output?: string;
|
|
12
12
|
outputMaxLines?: number;
|
|
13
13
|
codeMaxLines?: number;
|
|
14
|
+
/**
|
|
15
|
+
* Show the LAST `codeMaxLines` rows (the live streaming edge) instead of the
|
|
16
|
+
* first, with a "… N earlier lines" marker on top. Lets a pending preview
|
|
17
|
+
* follow code as it is written while staying bounded. Ignored when `expanded`.
|
|
18
|
+
*/
|
|
19
|
+
codeTail?: boolean;
|
|
14
20
|
expanded?: boolean;
|
|
15
21
|
/** Animate the cell border with a sweeping segment while pending/running. */
|
|
16
22
|
animate?: boolean;
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bordered output container with optional header and sections.
|
|
3
|
+
*/
|
|
4
|
+
import type { Component } from "@oh-my-pi/pi-tui";
|
|
1
5
|
import type { Theme } from "../modes/theme/theme";
|
|
2
6
|
import type { State } from "./types";
|
|
3
7
|
export interface OutputBlockOptions {
|
|
@@ -13,6 +17,12 @@ export interface OutputBlockOptions {
|
|
|
13
17
|
/** Animate the border with a sweeping dark segment (pending/running state). */
|
|
14
18
|
animate?: boolean;
|
|
15
19
|
}
|
|
20
|
+
declare const FRAMED_BLOCK_COMPONENT: unique symbol;
|
|
21
|
+
export type FramedBlockComponent = Component & {
|
|
22
|
+
[FRAMED_BLOCK_COMPONENT]?: true;
|
|
23
|
+
};
|
|
24
|
+
export declare function markFramedBlockComponent<T extends Component>(component: T): T & FramedBlockComponent;
|
|
25
|
+
export declare function isFramedBlockComponent(component: Component): boolean;
|
|
16
26
|
/**
|
|
17
27
|
* Monotonic frame counter for animated borders, quantized to the TUI's ~16ms
|
|
18
28
|
* render cap so the cache key advances once per ~60fps frame — fine enough for a
|
|
@@ -44,3 +54,4 @@ export declare class CachedOutputBlock {
|
|
|
44
54
|
/** Invalidate the cache, forcing a rebuild on next render. */
|
|
45
55
|
invalidate(): void;
|
|
46
56
|
}
|
|
57
|
+
export {};
|
|
@@ -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
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { matchesKey, replaceTabs, Text, truncateToWidth, visibleWidth } from "@oh-my-pi/pi-tui";
|
|
1
|
+
import { matchesKey, replaceTabs, ScrollView, Text, truncateToWidth, visibleWidth } from "@oh-my-pi/pi-tui";
|
|
2
2
|
import type { Theme } from "../modes/theme/theme";
|
|
3
3
|
import { formatElapsed, formatNum, isBetter } from "./helpers";
|
|
4
4
|
import { currentResults, findBaselineMetric, findBaselineRunNumber, findBaselineSecondary } from "./state";
|
|
@@ -76,14 +76,14 @@ export function createDashboardController(): DashboardController {
|
|
|
76
76
|
const viewportRows = Math.max(4, terminalRows - 4);
|
|
77
77
|
const maxScroll = Math.max(0, body.length - viewportRows);
|
|
78
78
|
if (scrollOffset > maxScroll) scrollOffset = maxScroll;
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
];
|
|
79
|
+
const sv = new ScrollView(body.slice(scrollOffset, scrollOffset + viewportRows), {
|
|
80
|
+
height: viewportRows,
|
|
81
|
+
scrollbar: "auto",
|
|
82
|
+
totalRows: body.length,
|
|
83
|
+
theme: { track: t => theme.fg("dim", t), thumb: t => theme.fg("accent", t) },
|
|
84
|
+
});
|
|
85
|
+
sv.setScrollOffset(scrollOffset);
|
|
86
|
+
return [header, ...sv.render(width), renderOverlayFooter(width, theme)];
|
|
87
87
|
},
|
|
88
88
|
handleInput(data: string): void {
|
|
89
89
|
const totalRows =
|
|
@@ -406,18 +406,8 @@ function renderOverlayRunningLine(
|
|
|
406
406
|
);
|
|
407
407
|
}
|
|
408
408
|
|
|
409
|
-
function renderOverlayFooter(
|
|
410
|
-
|
|
411
|
-
scrollOffset: number,
|
|
412
|
-
viewportRows: number,
|
|
413
|
-
totalRows: number,
|
|
414
|
-
theme: Theme,
|
|
415
|
-
): string {
|
|
416
|
-
const position =
|
|
417
|
-
totalRows > viewportRows
|
|
418
|
-
? ` ${scrollOffset + 1}-${Math.min(totalRows, scrollOffset + viewportRows)}/${totalRows}`
|
|
419
|
-
: "";
|
|
420
|
-
const hint = theme.fg("dim", ` up/down j/k pageup pagedown g G esc${position} `);
|
|
409
|
+
function renderOverlayFooter(width: number, theme: Theme): string {
|
|
410
|
+
const hint = theme.fg("dim", " up/down j/k pageup pagedown g G esc ");
|
|
421
411
|
const fill = Math.max(0, width - visibleWidth(hint));
|
|
422
412
|
return theme.fg("borderMuted", "-".repeat(fill)) + hint;
|
|
423
413
|
}
|
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)
|
|
@@ -380,6 +380,18 @@ function isMessagesRequest(message: ParsedHttpMessage): boolean {
|
|
|
380
380
|
return pathNameFromRequestTarget(message.path ?? "") === "/v1/messages";
|
|
381
381
|
}
|
|
382
382
|
|
|
383
|
+
// Claude Code fires a background warmup/classification call on its small fast
|
|
384
|
+
// model (a haiku variant, ANTHROPIC_SMALL_FAST_MODEL) before sending the user's
|
|
385
|
+
// real message. Skip it so the capture lands on the actual prompt.
|
|
386
|
+
function isBackgroundModelRequest(message: ParsedHttpMessage): boolean {
|
|
387
|
+
try {
|
|
388
|
+
const parsed = JSON.parse(decodeBody(message.headers, message.body)) as { model?: unknown };
|
|
389
|
+
return typeof parsed.model === "string" && parsed.model.toLowerCase().includes("haiku");
|
|
390
|
+
} catch {
|
|
391
|
+
return false;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
383
395
|
function decodeBody(headers: readonly HeaderEntry[], body: Buffer): string {
|
|
384
396
|
const encoding = headerValue(headers, "content-encoding")?.toLowerCase().trim();
|
|
385
397
|
try {
|
|
@@ -636,7 +648,7 @@ export class ClaudeMessagesProxy {
|
|
|
636
648
|
upstreamTls.write(data);
|
|
637
649
|
const messages = requestParser.push(data);
|
|
638
650
|
for (const message of messages) {
|
|
639
|
-
if (!isMessagesRequest(message)) {
|
|
651
|
+
if (!isMessagesRequest(message) || isBackgroundModelRequest(message)) {
|
|
640
652
|
responseQueue.push(null);
|
|
641
653
|
continue;
|
|
642
654
|
}
|
|
@@ -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
|
+
}
|