@oh-my-pi/pi-coding-agent 15.11.6 → 15.11.8
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 +57 -1
- package/dist/cli.js +431 -381
- package/dist/types/cli/args.d.ts +2 -0
- package/dist/types/cli/bench-cli.d.ts +78 -0
- package/dist/types/collab/crypto.d.ts +12 -0
- package/dist/types/collab/guest.d.ts +21 -0
- package/dist/types/collab/host.d.ts +13 -0
- package/dist/types/collab/protocol.d.ts +100 -0
- package/dist/types/collab/relay-client.d.ts +22 -0
- package/dist/types/commands/bench.d.ts +29 -0
- package/dist/types/commands/join.d.ts +12 -0
- package/dist/types/config/model-resolver.d.ts +3 -2
- package/dist/types/config/settings-schema.d.ts +93 -1
- package/dist/types/edit/renderer.d.ts +1 -0
- package/dist/types/extensibility/slash-commands.d.ts +1 -11
- package/dist/types/modes/components/agent-hub.d.ts +13 -0
- package/dist/types/modes/components/collab-prompt-message.d.ts +10 -0
- package/dist/types/modes/components/hook-selector.d.ts +4 -6
- package/dist/types/modes/components/oauth-selector.d.ts +10 -1
- package/dist/types/modes/components/segment-track.d.ts +11 -6
- package/dist/types/modes/components/settings-selector.d.ts +8 -1
- package/dist/types/modes/components/snapcompact-shape-preview.d.ts +31 -0
- package/dist/types/modes/components/status-line/component.d.ts +4 -1
- package/dist/types/modes/components/status-line/types.d.ts +9 -0
- package/dist/types/modes/components/tool-execution.d.ts +13 -9
- package/dist/types/modes/interactive-mode.d.ts +7 -0
- package/dist/types/modes/setup-wizard/scenes/sign-in.d.ts +3 -0
- package/dist/types/modes/setup-wizard/scenes/types.d.ts +10 -1
- package/dist/types/modes/setup-wizard/scenes/web-search.d.ts +3 -0
- package/dist/types/modes/types.d.ts +8 -0
- package/dist/types/session/agent-session.d.ts +11 -0
- package/dist/types/session/session-manager.d.ts +21 -0
- package/dist/types/session/snapcompact-inline.d.ts +8 -3
- package/dist/types/slash-commands/builtin-registry.d.ts +9 -0
- package/dist/types/tools/bash.d.ts +2 -0
- package/dist/types/tools/eval-render.d.ts +1 -0
- package/dist/types/tools/renderers.d.ts +13 -0
- package/dist/types/tools/ssh.d.ts +1 -0
- package/package.json +14 -12
- package/scripts/bench-guard.ts +71 -0
- package/src/cli/args.ts +2 -0
- package/src/cli/bench-cli.ts +437 -0
- package/src/cli-commands.ts +2 -0
- package/src/collab/crypto.ts +57 -0
- package/src/collab/guest.ts +421 -0
- package/src/collab/host.ts +494 -0
- package/src/collab/protocol.ts +191 -0
- package/src/collab/relay-client.ts +216 -0
- package/src/commands/bench.ts +42 -0
- package/src/commands/join.ts +39 -0
- package/src/config/model-registry.ts +74 -19
- package/src/config/model-resolver.ts +36 -5
- package/src/config/settings-schema.ts +119 -1
- package/src/edit/renderer.ts +5 -0
- package/src/extensibility/slash-commands.ts +1 -97
- package/src/hindsight/client.ts +26 -1
- package/src/hindsight/state.ts +6 -2
- package/src/internal-urls/docs-index.generated.ts +4 -3
- package/src/main.ts +11 -2
- package/src/mcp/transports/stdio.ts +81 -7
- package/src/modes/components/agent-hub.ts +119 -22
- package/src/modes/components/assistant-message.ts +126 -6
- package/src/modes/components/collab-prompt-message.ts +30 -0
- package/src/modes/components/hook-selector.ts +4 -5
- package/src/modes/components/oauth-selector.ts +67 -7
- package/src/modes/components/segment-track.ts +44 -7
- package/src/modes/components/settings-selector.ts +27 -0
- package/src/modes/components/snapcompact-shape-preview-doc.md +11 -0
- package/src/modes/components/snapcompact-shape-preview.ts +192 -0
- package/src/modes/components/status-line/component.ts +21 -1
- package/src/modes/components/status-line/presets.ts +1 -1
- package/src/modes/components/status-line/segments.ts +13 -0
- package/src/modes/components/status-line/types.ts +10 -0
- package/src/modes/components/tips.txt +2 -1
- package/src/modes/components/tool-execution.ts +18 -10
- package/src/modes/controllers/input-controller.ts +80 -12
- package/src/modes/controllers/selector-controller.ts +6 -2
- package/src/modes/controllers/streaming-reveal.ts +7 -0
- package/src/modes/interactive-mode.ts +36 -4
- package/src/modes/setup-wizard/index.ts +1 -0
- package/src/modes/setup-wizard/scenes/glyph.ts +24 -6
- package/src/modes/setup-wizard/scenes/providers.ts +36 -2
- package/src/modes/setup-wizard/scenes/sign-in.ts +10 -1
- package/src/modes/setup-wizard/scenes/theme.ts +28 -1
- package/src/modes/setup-wizard/scenes/types.ts +10 -1
- package/src/modes/setup-wizard/scenes/web-search.ts +22 -6
- package/src/modes/setup-wizard/wizard-overlay.ts +38 -1
- package/src/modes/types.ts +8 -0
- package/src/modes/utils/context-usage.ts +1 -1
- package/src/modes/utils/ui-helpers.ts +7 -0
- package/src/prompts/bench.md +7 -0
- package/src/sdk.ts +240 -36
- package/src/session/agent-session.ts +22 -0
- package/src/session/session-manager.ts +44 -0
- package/src/session/snapcompact-inline.ts +20 -22
- package/src/slash-commands/builtin-registry.ts +210 -0
- package/src/tools/bash.ts +3 -0
- package/src/tools/eval-render.ts +4 -0
- package/src/tools/read.ts +38 -5
- package/src/tools/renderers.ts +13 -0
- package/src/tools/ssh.ts +3 -0
- package/src/tools/write.ts +13 -42
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type Component } from "@oh-my-pi/pi-tui";
|
|
2
2
|
import type { AgentSession } from "../../../session/agent-session";
|
|
3
|
-
import type { EffectiveStatusLineSettings, StatusLineSettings } from "./types";
|
|
3
|
+
import type { CollabStatus, EffectiveStatusLineSettings, StatusLineSettings } from "./types";
|
|
4
4
|
export declare class StatusLineComponent implements Component {
|
|
5
5
|
#private;
|
|
6
6
|
private readonly session;
|
|
@@ -9,6 +9,8 @@ export declare class StatusLineComponent implements Component {
|
|
|
9
9
|
getEffectiveSettingsForTest(): EffectiveStatusLineSettings;
|
|
10
10
|
setAutoCompactEnabled(enabled: boolean): void;
|
|
11
11
|
setSubagentCount(count: number): void;
|
|
12
|
+
/** Active subagent count as currently displayed (collab state mirroring). */
|
|
13
|
+
get subagentCount(): number;
|
|
12
14
|
setSessionStartTime(time: number): void;
|
|
13
15
|
setPlanModeStatus(status: {
|
|
14
16
|
enabled: boolean;
|
|
@@ -21,6 +23,7 @@ export declare class StatusLineComponent implements Component {
|
|
|
21
23
|
enabled: boolean;
|
|
22
24
|
paused: boolean;
|
|
23
25
|
} | undefined): void;
|
|
26
|
+
setCollabStatus(status: CollabStatus | null): void;
|
|
24
27
|
setHookStatus(key: string, text: string | undefined): void;
|
|
25
28
|
watchBranch(onBranchChange: () => void): void;
|
|
26
29
|
dispose(): void;
|
|
@@ -1,6 +1,14 @@
|
|
|
1
|
+
import type { CollabSessionState } from "../../../collab/protocol";
|
|
1
2
|
import type { StatusLinePreset, StatusLineSegmentId, StatusLineSeparatorStyle } from "../../../config/settings-schema";
|
|
2
3
|
import type { AgentSession } from "../../../session/agent-session";
|
|
3
4
|
export type { StatusLinePreset, StatusLineSegmentId, StatusLineSeparatorStyle };
|
|
5
|
+
/** Collab session indicator + (guest-only) host-state override for segments. */
|
|
6
|
+
export interface CollabStatus {
|
|
7
|
+
role: "host" | "guest";
|
|
8
|
+
participantCount: number;
|
|
9
|
+
/** Guest only: host footer snapshot that overrides locally computed values. */
|
|
10
|
+
stateOverride?: CollabSessionState | null;
|
|
11
|
+
}
|
|
4
12
|
export interface StatusLineSegmentOptions {
|
|
5
13
|
model?: {
|
|
6
14
|
showThinkingLevel?: boolean;
|
|
@@ -50,6 +58,7 @@ export interface SegmentContext {
|
|
|
50
58
|
enabled: boolean;
|
|
51
59
|
paused: boolean;
|
|
52
60
|
} | null;
|
|
61
|
+
collab: CollabStatus | null;
|
|
53
62
|
usageStats: {
|
|
54
63
|
input: number;
|
|
55
64
|
output: number;
|
|
@@ -74,15 +74,19 @@ export declare class ToolExecutionComponent extends Container {
|
|
|
74
74
|
isTranscriptBlockFinalized(): boolean;
|
|
75
75
|
/**
|
|
76
76
|
* Whether this still-live block's settled rows may enter native scrollback
|
|
77
|
-
* (see `FinalizableBlock.isTranscriptBlockCommitStable`).
|
|
78
|
-
*
|
|
79
|
-
* (edit
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
77
|
+
* (see `FinalizableBlock.isTranscriptBlockCommitStable`). Classification is
|
|
78
|
+
* per renderer (`ToolRenderer.provisionalPendingPreview`): tail-window
|
|
79
|
+
* streaming views (edit's streamed-diff tail, bash/ssh command caps, eval
|
|
80
|
+
* cells) are re-anchored top-first by the result render, so promoting
|
|
81
|
+
* their visually static head — e.g. an edit preview idling on its last
|
|
82
|
+
* frame while the apply + LSP pass runs — would strand a stale copy of
|
|
83
|
+
* the call box above the final block the moment the result lands. Every
|
|
84
|
+
* other pending preview streams top-anchored append-shaped rows the
|
|
85
|
+
* result render preserves (a task call's context/assignment markdown, a
|
|
86
|
+
* write's content), so it stays commit-eligible — a call taller than the
|
|
87
|
+
* viewport scrolls into native history mid-stream instead of reading as
|
|
88
|
+
* cut off until the result. Expanded blocks always stream top-anchored
|
|
89
|
+
* (the over-tall write/eval scrollback contract). Displaceable waiting
|
|
86
90
|
* polls are removed wholesale by the next poll and must never commit.
|
|
87
91
|
*/
|
|
88
92
|
isTranscriptBlockCommitStable(): boolean;
|
|
@@ -3,6 +3,8 @@ import type { CompactionOutcome } from "@oh-my-pi/pi-agent-core/compaction";
|
|
|
3
3
|
import type { AssistantMessage, ImageContent, Message, UsageReport } from "@oh-my-pi/pi-ai";
|
|
4
4
|
import type { Component, EditorTheme } from "@oh-my-pi/pi-tui";
|
|
5
5
|
import { Container, Loader, Spacer, Text, TUI } from "@oh-my-pi/pi-tui";
|
|
6
|
+
import type { CollabGuestLink } from "../collab/guest";
|
|
7
|
+
import type { CollabHost } from "../collab/host";
|
|
6
8
|
import { KeybindingsManager } from "../config/keybindings";
|
|
7
9
|
import { Settings } from "../config/settings";
|
|
8
10
|
import type { ExtensionUIContext, ExtensionUIDialogOptions, ExtensionUISelectItem, ExtensionWidgetContent, ExtensionWidgetOptions } from "../extensibility/extensions";
|
|
@@ -25,6 +27,7 @@ import type { HookSelectorComponent, HookSelectorSlider } from "./components/hoo
|
|
|
25
27
|
import { StatusLineComponent } from "./components/status-line";
|
|
26
28
|
import type { ToolExecutionHandle } from "./components/tool-execution";
|
|
27
29
|
import { TranscriptContainer } from "./components/transcript-container";
|
|
30
|
+
import { EventController } from "./controllers/event-controller";
|
|
28
31
|
import { type LoopLimitRuntime } from "./loop-limit";
|
|
29
32
|
import { OAuthManualInputManager } from "./oauth-manual-input";
|
|
30
33
|
import type { ObservableSession } from "./session-observer-registry";
|
|
@@ -119,8 +122,12 @@ export declare class InteractiveMode implements InteractiveModeContext {
|
|
|
119
122
|
fileSlashCommands: Set<string>;
|
|
120
123
|
skillCommands: Map<string, string>;
|
|
121
124
|
oauthManualInput: OAuthManualInputManager;
|
|
125
|
+
collabHost?: CollabHost;
|
|
126
|
+
collabGuest?: CollabGuestLink;
|
|
122
127
|
readonly lspServers: LspStartupServerInfo[] | undefined;
|
|
123
128
|
mcpManager?: MCPManager;
|
|
129
|
+
get eventController(): EventController;
|
|
130
|
+
get eventBus(): EventBus | undefined;
|
|
124
131
|
constructor(session: AgentSession, version: string, changelogMarkdown?: string | undefined, setToolUIContext?: (uiContext: ExtensionUIContext, hasUI: boolean) => void, lspServers?: LspStartupServerInfo[] | undefined, mcpManager?: MCPManager, eventBus?: EventBus, titleSystemPrompt?: string);
|
|
125
132
|
playWelcomeIntro(): void;
|
|
126
133
|
init(options?: InteractiveModeInitOptions): Promise<void>;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type SgrMouseEvent } from "@oh-my-pi/pi-tui";
|
|
1
2
|
import type { SetupSceneHost, SetupTab } from "./types";
|
|
2
3
|
/**
|
|
3
4
|
* "Sign in" panel: lets the user authenticate one or more model providers via
|
|
@@ -15,5 +16,7 @@ export declare class SignInTab implements SetupTab {
|
|
|
15
16
|
dispose(): void;
|
|
16
17
|
invalidate(): void;
|
|
17
18
|
handleInput(data: string): void;
|
|
19
|
+
/** Forward mouse to the provider selector; pointer is inert during an active login or code prompt. */
|
|
20
|
+
routeMouse(event: SgrMouseEvent, line: number, col: number): void;
|
|
18
21
|
render(width: number): readonly string[];
|
|
19
22
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Component } from "@oh-my-pi/pi-tui";
|
|
1
|
+
import type { Component, SgrMouseEvent } from "@oh-my-pi/pi-tui";
|
|
2
2
|
import type { InteractiveModeContext } from "../../types";
|
|
3
3
|
export type SetupSceneResult = "done" | "skipped";
|
|
4
4
|
export interface SetupSceneHost {
|
|
@@ -14,6 +14,13 @@ export interface SetupSceneController extends Component {
|
|
|
14
14
|
onMount?(): void | Promise<void>;
|
|
15
15
|
onUnmount?(): void;
|
|
16
16
|
dispose?(): void;
|
|
17
|
+
/**
|
|
18
|
+
* Route an SGR mouse report (tracking is on while the wizard holds the
|
|
19
|
+
* alternate screen). `line`/`col` are 0-based within this controller's
|
|
20
|
+
* last rendered output. When absent, the wizard falls back to synthesizing
|
|
21
|
+
* arrow keys from wheel notches.
|
|
22
|
+
*/
|
|
23
|
+
routeMouse?(event: SgrMouseEvent, line: number, col: number): void;
|
|
17
24
|
}
|
|
18
25
|
/**
|
|
19
26
|
* A single panel inside a tabbed setup scene. The host scene owns the tab bar
|
|
@@ -32,6 +39,8 @@ export interface SetupTab {
|
|
|
32
39
|
invalidate(): void;
|
|
33
40
|
/** Called when the tab becomes active (including initial mount). */
|
|
34
41
|
onActivate?(): void;
|
|
42
|
+
/** Mouse routing at tab-local coordinates; see {@link SetupSceneController.routeMouse}. */
|
|
43
|
+
routeMouse?(event: SgrMouseEvent, line: number, col: number): void;
|
|
35
44
|
dispose(): void;
|
|
36
45
|
}
|
|
37
46
|
export interface SetupScene {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type SgrMouseEvent } from "@oh-my-pi/pi-tui";
|
|
1
2
|
import type { SetupSceneHost, SetupTab } from "./types";
|
|
2
3
|
/**
|
|
3
4
|
* "Web search" panel: picks the provider the web_search tool should prefer and
|
|
@@ -14,6 +15,8 @@ export declare class WebSearchTab implements SetupTab {
|
|
|
14
15
|
constructor(host: SetupSceneHost);
|
|
15
16
|
onActivate(): void;
|
|
16
17
|
handleInput(data: string): void;
|
|
18
|
+
/** Wheel moves the highlight; hover lights the row under the pointer; click confirms it. */
|
|
19
|
+
routeMouse(event: SgrMouseEvent, line: number, _col: number): void;
|
|
17
20
|
invalidate(): void;
|
|
18
21
|
dispose(): void;
|
|
19
22
|
render(width: number): readonly string[];
|
|
@@ -2,6 +2,8 @@ import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
|
|
|
2
2
|
import type { CompactionOutcome } from "@oh-my-pi/pi-agent-core/compaction";
|
|
3
3
|
import type { AssistantMessage, ImageContent, Message, UsageReport } from "@oh-my-pi/pi-ai";
|
|
4
4
|
import type { Component, Container, EditorTheme, Loader, Spacer, Text, TUI } from "@oh-my-pi/pi-tui";
|
|
5
|
+
import type { CollabGuestLink } from "../collab/guest";
|
|
6
|
+
import type { CollabHost } from "../collab/host";
|
|
5
7
|
import type { KeybindingsManager } from "../config/keybindings";
|
|
6
8
|
import type { Settings } from "../config/settings";
|
|
7
9
|
import type { ExtensionUIContext, ExtensionUIDialogOptions, ExtensionUISelectItem, ExtensionWidgetContent, ExtensionWidgetOptions } from "../extensibility/extensions";
|
|
@@ -13,6 +15,7 @@ import type { HistoryStorage } from "../session/history-storage";
|
|
|
13
15
|
import type { SessionContext, SessionManager } from "../session/session-manager";
|
|
14
16
|
import type { ShakeMode } from "../session/shake-types";
|
|
15
17
|
import type { LspStartupServerInfo } from "../tools";
|
|
18
|
+
import type { EventBus } from "../utils/event-bus";
|
|
16
19
|
import type { AssistantMessageComponent } from "./components/assistant-message";
|
|
17
20
|
import type { BashExecutionComponent } from "./components/bash-execution";
|
|
18
21
|
import type { CustomEditor } from "./components/custom-editor";
|
|
@@ -23,6 +26,7 @@ import type { HookSelectorComponent, HookSelectorOptions } from "./components/ho
|
|
|
23
26
|
import type { StatusLineComponent } from "./components/status-line";
|
|
24
27
|
import type { ToolExecutionHandle } from "./components/tool-execution";
|
|
25
28
|
import type { TranscriptContainer } from "./components/transcript-container";
|
|
29
|
+
import type { EventController } from "./controllers/event-controller";
|
|
26
30
|
import type { LoopLimitRuntime } from "./loop-limit";
|
|
27
31
|
import type { OAuthManualInputManager } from "./oauth-manual-input";
|
|
28
32
|
import type { Theme } from "./theme/theme";
|
|
@@ -84,6 +88,10 @@ export interface InteractiveModeContext {
|
|
|
84
88
|
mcpManager?: MCPManager;
|
|
85
89
|
lspServers?: LspStartupServerInfo[];
|
|
86
90
|
titleSystemPrompt?: string;
|
|
91
|
+
collabHost?: CollabHost;
|
|
92
|
+
collabGuest?: CollabGuestLink;
|
|
93
|
+
eventController: EventController;
|
|
94
|
+
eventBus?: EventBus;
|
|
87
95
|
isInitialized: boolean;
|
|
88
96
|
isBashMode: boolean;
|
|
89
97
|
toolOutputExpanded: boolean;
|
|
@@ -385,6 +385,9 @@ export declare class AgentSession {
|
|
|
385
385
|
*/
|
|
386
386
|
subscribe(listener: AgentSessionEventListener): () => void;
|
|
387
387
|
subscribeCommandMetadataChanged(listener: CommandMetadataChangedListener): () => void;
|
|
388
|
+
/** True once dispose() has begun; deferred background work (e.g. the deferred
|
|
389
|
+
* MCP discovery task in sdk.ts) must not touch the session past this point. */
|
|
390
|
+
get isDisposed(): boolean;
|
|
388
391
|
/**
|
|
389
392
|
* Synchronously mark the session as disposing so new work is rejected
|
|
390
393
|
* immediately: Python/eval starts throw, queued asides are dropped, and the
|
|
@@ -443,6 +446,14 @@ export declare class AgentSession {
|
|
|
443
446
|
*/
|
|
444
447
|
getAllToolNames(): string[];
|
|
445
448
|
isMCPDiscoveryEnabled(): boolean;
|
|
449
|
+
/**
|
|
450
|
+
* Flip MCP discovery on after deferred discovery learns the real tool count.
|
|
451
|
+
* UI sessions resolve `tools.discoveryMode: "auto"` before MCP servers
|
|
452
|
+
* connect, so a large MCP toolset discovered later must be able to upgrade
|
|
453
|
+
* the session from the force-activate path to the discovery path. One-way:
|
|
454
|
+
* discovery is never downgraded mid-session.
|
|
455
|
+
*/
|
|
456
|
+
enableMCPDiscovery(): void;
|
|
446
457
|
getSelectedMCPToolNames(): string[];
|
|
447
458
|
activateDiscoveredMCPTools(toolNames: string[]): Promise<string[]>;
|
|
448
459
|
isToolDiscoveryEnabled(): boolean;
|
|
@@ -309,6 +309,12 @@ export declare class SessionManager {
|
|
|
309
309
|
private sessionDir;
|
|
310
310
|
private readonly persist;
|
|
311
311
|
private readonly storage;
|
|
312
|
+
/**
|
|
313
|
+
* Collab replication tap: invoked for every appended entry with the
|
|
314
|
+
* in-memory (pre-blob-externalization) entry, so inline images survive.
|
|
315
|
+
* Failures are swallowed — a broadcast error must never break persistence.
|
|
316
|
+
*/
|
|
317
|
+
onEntryAppended?: (entry: SessionEntry) => void;
|
|
312
318
|
private constructor();
|
|
313
319
|
/** Puts a binary blob into the blob store and returns the blob reference */
|
|
314
320
|
putBlob(data: Buffer, options?: BlobPutOptions): Promise<BlobPutResult>;
|
|
@@ -434,6 +440,21 @@ export declare class SessionManager {
|
|
|
434
440
|
*/
|
|
435
441
|
setSessionName(name: string, source?: "auto" | "user"): Promise<boolean>;
|
|
436
442
|
_persist(entry: SessionEntry): void;
|
|
443
|
+
/**
|
|
444
|
+
* Append a foreign (host-authored) entry verbatim, preserving its
|
|
445
|
+
* `id`/`parentId` — no id minting. Used by collab guests to mirror the
|
|
446
|
+
* host session into the local replica file.
|
|
447
|
+
*/
|
|
448
|
+
ingestReplicatedEntry(entry: SessionEntry): void;
|
|
449
|
+
/**
|
|
450
|
+
* Snapshot the session for collab replication: the live header plus a deep
|
|
451
|
+
* copy of every entry (the host mutates entries in place on
|
|
452
|
+
* truncation/rewrite paths, so guests must not share references).
|
|
453
|
+
*/
|
|
454
|
+
snapshotForReplication(): {
|
|
455
|
+
header: SessionHeader;
|
|
456
|
+
entries: SessionEntry[];
|
|
457
|
+
};
|
|
437
458
|
/** Append a message as child of current leaf, then advance leaf. Returns entry id.
|
|
438
459
|
* Does not allow writing CompactionSummaryMessage and BranchSummaryMessage directly.
|
|
439
460
|
* Reason: we want these to be top-level entries in the session, not message session entries,
|
|
@@ -19,17 +19,21 @@ export type SnapcompactSystemPromptMode = "none" | "agents-md" | "all";
|
|
|
19
19
|
export interface SnapcompactInlineOptions {
|
|
20
20
|
renderSystemPrompt: SnapcompactSystemPromptMode;
|
|
21
21
|
renderToolResults: boolean;
|
|
22
|
+
/** Frame variant override; `"auto"`/omitted picks the provider's eval winner. */
|
|
23
|
+
shape?: snapcompact.ShapeVariantName | "auto";
|
|
22
24
|
}
|
|
23
25
|
/** Tool-result swap candidate, in context order. */
|
|
24
26
|
export interface InlineToolResultCandidate {
|
|
25
|
-
/**
|
|
27
|
+
/** Stable identifier for rendering cache key and applying the swap. */
|
|
26
28
|
id: string;
|
|
27
|
-
/** Token count of the joined text blocks (0
|
|
29
|
+
/** Token count of the joined text blocks (0 for empty or image-carrying). */
|
|
28
30
|
textTokens: number;
|
|
29
|
-
/** Frames needed to render the text (0 = empty
|
|
31
|
+
/** Frames needed to render the text (0 = empty, below floor, image-carrying, or error). */
|
|
30
32
|
frames: number;
|
|
31
33
|
/** Already carries an image (screenshot etc.) — never re-imaged. */
|
|
32
34
|
hasImage: boolean;
|
|
35
|
+
/** Error tool results must stay text-only for provider API validation. */
|
|
36
|
+
isError?: boolean;
|
|
33
37
|
}
|
|
34
38
|
export interface InlineSystemPromptCandidate {
|
|
35
39
|
textTokens: number;
|
|
@@ -71,6 +75,7 @@ export interface InlineMessageView {
|
|
|
71
75
|
role: string;
|
|
72
76
|
toolCallId?: string;
|
|
73
77
|
content?: unknown;
|
|
78
|
+
isError?: boolean;
|
|
74
79
|
}
|
|
75
80
|
export interface SnapcompactSavingsEstimate {
|
|
76
81
|
/** Frames only ship on models that accept image input. */
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { AutocompleteItem } from "@oh-my-pi/pi-tui";
|
|
1
2
|
import type { BuiltinSlashCommand, ParsedSlashCommand, SlashCommandResult, SlashCommandRuntime, SlashCommandSpec, TuiSlashCommandRuntime } from "./types";
|
|
2
3
|
export type { BuiltinSlashCommand, SubcommandDef } from "./types";
|
|
3
4
|
/** TUI-specific runtime accepted by `executeBuiltinSlashCommand`. */
|
|
@@ -5,6 +6,14 @@ export type BuiltinSlashCommandRuntime = TuiSlashCommandRuntime;
|
|
|
5
6
|
export declare const BUILTIN_SLASH_COMMAND_RESERVED_NAMES: ReadonlySet<string>;
|
|
6
7
|
/** Builtin command metadata used for slash-command autocomplete and help text. */
|
|
7
8
|
export declare const BUILTIN_SLASH_COMMAND_DEFS: ReadonlyArray<BuiltinSlashCommand>;
|
|
9
|
+
/**
|
|
10
|
+
* Materialized builtin slash commands with completion functions derived from
|
|
11
|
+
* declarative subcommand/hint definitions.
|
|
12
|
+
*/
|
|
13
|
+
export declare const BUILTIN_SLASH_COMMANDS: ReadonlyArray<BuiltinSlashCommand & {
|
|
14
|
+
getArgumentCompletions?: (prefix: string) => AutocompleteItem[] | null;
|
|
15
|
+
getInlineHint?: (argumentText: string) => string | null;
|
|
16
|
+
}>;
|
|
8
17
|
/**
|
|
9
18
|
* Unified registry exposed for cross-mode tooling. Each spec carries at least
|
|
10
19
|
* one of `handle` / `handleTui`. The TUI dispatcher prefers `handleTui`; the
|
|
@@ -124,6 +124,7 @@ export declare function createShellRenderer<TArgs>(config: ShellRendererConfig<T
|
|
|
124
124
|
}, uiTheme: Theme, args?: TArgs): Component;
|
|
125
125
|
mergeCallAndResult: boolean;
|
|
126
126
|
inline: boolean;
|
|
127
|
+
provisionalPendingPreview: boolean;
|
|
127
128
|
};
|
|
128
129
|
export declare const bashToolRenderer: {
|
|
129
130
|
renderCall(args: BashRenderArgs, options: RenderResultOptions, uiTheme: Theme): Component;
|
|
@@ -139,5 +140,6 @@ export declare const bashToolRenderer: {
|
|
|
139
140
|
}, uiTheme: Theme, args?: BashRenderArgs | undefined): Component;
|
|
140
141
|
mergeCallAndResult: boolean;
|
|
141
142
|
inline: boolean;
|
|
143
|
+
provisionalPendingPreview: boolean;
|
|
142
144
|
};
|
|
143
145
|
export {};
|
|
@@ -21,5 +21,18 @@ export type ToolRenderer = {
|
|
|
21
21
|
mergeCallAndResult?: boolean;
|
|
22
22
|
/** Render without background box, inline in the response flow */
|
|
23
23
|
inline?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Collapsed pending preview is provisional — a tail-window or otherwise
|
|
26
|
+
* re-anchored view the result render replaces wholesale (an edit's
|
|
27
|
+
* streamed-diff tail, bash/ssh command caps, eval cells whose outputs
|
|
28
|
+
* interleave under each cell). Its rows must never commit to native
|
|
29
|
+
* scrollback mid-run; see
|
|
30
|
+
* `ToolExecutionComponent.isTranscriptBlockCommitStable`. Absent = the
|
|
31
|
+
* pending preview streams top-anchored append-shaped rows the result
|
|
32
|
+
* render preserves (task context/assignment, write content), which stay
|
|
33
|
+
* commit-eligible so a call taller than the viewport scrolls into history
|
|
34
|
+
* instead of reading as cut off.
|
|
35
|
+
*/
|
|
36
|
+
provisionalPendingPreview?: boolean;
|
|
24
37
|
};
|
|
25
38
|
export declare const toolRenderers: Record<string, ToolRenderer>;
|
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.11.
|
|
4
|
+
"version": "15.11.8",
|
|
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",
|
|
@@ -41,22 +41,24 @@
|
|
|
41
41
|
"format-prompts": "bun scripts/format-prompts.ts",
|
|
42
42
|
"generate-docs-index": "bun scripts/generate-docs-index.ts",
|
|
43
43
|
"prepack": "bun scripts/generate-docs-index.ts && bun scripts/bundle-dist.ts",
|
|
44
|
-
"generate-template": "bun scripts/generate-template.ts"
|
|
44
|
+
"generate-template": "bun scripts/generate-template.ts",
|
|
45
|
+
"bench:guard": "bun scripts/bench-guard.ts"
|
|
45
46
|
},
|
|
46
47
|
"dependencies": {
|
|
47
48
|
"@agentclientprotocol/sdk": "0.22.1",
|
|
48
49
|
"@babel/parser": "^7.29.7",
|
|
49
50
|
"@mozilla/readability": "^0.6.0",
|
|
50
|
-
"@oh-my-pi/hashline": "15.11.
|
|
51
|
-
"@oh-my-pi/omp-stats": "15.11.
|
|
52
|
-
"@oh-my-pi/pi-agent-core": "15.11.
|
|
53
|
-
"@oh-my-pi/pi-ai": "15.11.
|
|
54
|
-
"@oh-my-pi/pi-catalog": "15.11.
|
|
55
|
-
"@oh-my-pi/pi-mnemopi": "15.11.
|
|
56
|
-
"@oh-my-pi/pi-natives": "15.11.
|
|
57
|
-
"@oh-my-pi/pi-tui": "15.11.
|
|
58
|
-
"@oh-my-pi/pi-utils": "15.11.
|
|
59
|
-
"@oh-my-pi/
|
|
51
|
+
"@oh-my-pi/hashline": "15.11.8",
|
|
52
|
+
"@oh-my-pi/omp-stats": "15.11.8",
|
|
53
|
+
"@oh-my-pi/pi-agent-core": "15.11.8",
|
|
54
|
+
"@oh-my-pi/pi-ai": "15.11.8",
|
|
55
|
+
"@oh-my-pi/pi-catalog": "15.11.8",
|
|
56
|
+
"@oh-my-pi/pi-mnemopi": "15.11.8",
|
|
57
|
+
"@oh-my-pi/pi-natives": "15.11.8",
|
|
58
|
+
"@oh-my-pi/pi-tui": "15.11.8",
|
|
59
|
+
"@oh-my-pi/pi-utils": "15.11.8",
|
|
60
|
+
"@oh-my-pi/pi-wire": "15.11.8",
|
|
61
|
+
"@oh-my-pi/snapcompact": "15.11.8",
|
|
60
62
|
"@opentelemetry/api": "^1.9.1",
|
|
61
63
|
"@opentelemetry/context-async-hooks": "^2.7.1",
|
|
62
64
|
"@opentelemetry/exporter-trace-otlp-proto": "^0.218.0",
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* Boot-time regression guard (Phase A1 of the boot/TUI perf work).
|
|
4
|
+
*
|
|
5
|
+
* Re-runs the `PI_TIMING=x` cold-boot benchmark under hyperfine and fails when
|
|
6
|
+
* the median regresses past `baseline * THRESHOLD`. `PI_TIMING=x` runs the full
|
|
7
|
+
* pre-paint chain in `runRootCommand` and then `process.exit(0)`, so the
|
|
8
|
+
* never-exiting interactive launch becomes a terminating, benchmarkable boot.
|
|
9
|
+
*
|
|
10
|
+
* Boot wall-clock is MACHINE-RELATIVE: a baseline captured on one machine is
|
|
11
|
+
* meaningless on another (and on CI). This is a LOCAL guard — regenerate the
|
|
12
|
+
* baseline on the machine you measure on, then compare on that same machine.
|
|
13
|
+
* It is intentionally NOT wired into CI for that reason.
|
|
14
|
+
*
|
|
15
|
+
* bun scripts/bench-guard.ts --update # capture/refresh the baseline
|
|
16
|
+
* bun scripts/bench-guard.ts # measure + compare; exit 1 on regression
|
|
17
|
+
*
|
|
18
|
+
* Requires `hyperfine` on PATH.
|
|
19
|
+
*/
|
|
20
|
+
import * as fs from "node:fs";
|
|
21
|
+
import * as path from "node:path";
|
|
22
|
+
|
|
23
|
+
const THRESHOLD = 1.05; // 5% regression budget
|
|
24
|
+
const BASELINE_PATH = path.join(import.meta.dir, "..", "bench", "boot-baseline.json");
|
|
25
|
+
const BENCH_COMMAND = "PI_TIMING=x bun src/cli.ts";
|
|
26
|
+
const cwd = path.join(import.meta.dir, "..");
|
|
27
|
+
|
|
28
|
+
function medianOf(hyperfineJson: string): number {
|
|
29
|
+
const parsed = JSON.parse(hyperfineJson) as { results: Array<{ mean: number; median?: number }> };
|
|
30
|
+
const result = parsed.results[0];
|
|
31
|
+
if (!result) throw new Error("hyperfine produced no result");
|
|
32
|
+
return result.median ?? result.mean;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async function measure(): Promise<{ seconds: number; raw: string }> {
|
|
36
|
+
const tmp = path.join(import.meta.dir, "..", "bench", `.boot-run-${Date.now()}.json`);
|
|
37
|
+
const proc = Bun.spawn(["hyperfine", "--warmup", "3", "--min-runs", "10", "--export-json", tmp, BENCH_COMMAND], {
|
|
38
|
+
cwd,
|
|
39
|
+
stdout: "inherit",
|
|
40
|
+
stderr: "inherit",
|
|
41
|
+
});
|
|
42
|
+
const code = await proc.exited;
|
|
43
|
+
if (code !== 0) throw new Error(`hyperfine exited ${code}`);
|
|
44
|
+
const raw = await Bun.file(tmp).text();
|
|
45
|
+
fs.rmSync(tmp, { force: true });
|
|
46
|
+
return { seconds: medianOf(raw), raw };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const update = process.argv.includes("--update");
|
|
50
|
+
const { seconds, raw } = await measure();
|
|
51
|
+
|
|
52
|
+
if (update) {
|
|
53
|
+
fs.mkdirSync(path.dirname(BASELINE_PATH), { recursive: true });
|
|
54
|
+
await Bun.write(BASELINE_PATH, raw);
|
|
55
|
+
console.log(`Baseline updated: ${(seconds * 1000).toFixed(0)}ms median -> ${BASELINE_PATH}`);
|
|
56
|
+
process.exit(0);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (!fs.existsSync(BASELINE_PATH)) {
|
|
60
|
+
console.error("No baseline found. Run `bun scripts/bench-guard.ts --update` on this machine first.");
|
|
61
|
+
process.exit(2);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const baseline = medianOf(await Bun.file(BASELINE_PATH).text());
|
|
65
|
+
const ratio = seconds / baseline;
|
|
66
|
+
const verdict = ratio > THRESHOLD ? "REGRESSION" : "ok";
|
|
67
|
+
console.log(
|
|
68
|
+
`boot median: ${(seconds * 1000).toFixed(0)}ms vs baseline ${(baseline * 1000).toFixed(0)}ms ` +
|
|
69
|
+
`(${((ratio - 1) * 100).toFixed(1)}%, budget ${((THRESHOLD - 1) * 100).toFixed(0)}%) -> ${verdict}`,
|
|
70
|
+
);
|
|
71
|
+
process.exit(ratio > THRESHOLD ? 1 : 0);
|
package/src/cli/args.ts
CHANGED
|
@@ -32,6 +32,8 @@ export interface Args {
|
|
|
32
32
|
sessionDir?: string;
|
|
33
33
|
providerSessionId?: string;
|
|
34
34
|
fork?: string;
|
|
35
|
+
/** Collab link to join at startup (set by the `join` subcommand; no CLI flag). */
|
|
36
|
+
join?: string;
|
|
35
37
|
models?: string[];
|
|
36
38
|
tools?: string[];
|
|
37
39
|
noTools?: boolean;
|