@oh-my-pi/pi-tui 18.2.11 → 18.3.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 +20 -0
- package/THIRD-PARTY-NOTICES.txt +1 -1
- package/dist/types/apps/ps-data.d.ts +1 -1
- package/dist/types/apps/ps-top.d.ts +1 -1
- package/dist/types/chat/chat-transcript-builder.d.ts +1 -1
- package/dist/types/overlays/annotation-overlay.d.ts +30 -0
- package/dist/types/overlays/annotation-types.d.ts +84 -0
- package/dist/types/overlays/copy-selector.d.ts +30 -2
- package/dist/types/overlays/copy-targets.d.ts +2 -0
- package/dist/types/overlays/model-hub.d.ts +2 -2
- package/dist/types/overlays/oauth-selector.d.ts +3 -6
- package/dist/types/overlays/usage-dashboard.d.ts +2 -0
- package/dist/types/prompt/image-source.d.ts +9 -8
- package/dist/types/status-line/context-usage.d.ts +3 -1
- package/dist/types/theme/mermaid-cache.d.ts +4 -6
- package/dist/types/tools/bash.d.ts +7 -0
- package/dist/types/tools/daemon.d.ts +46 -0
- package/dist/types/tools/irc.d.ts +30 -0
- package/dist/types/tools/line-ranges.d.ts +1 -1
- package/dist/types/tools/proc-render.d.ts +34 -0
- package/dist/types/tools/read.d.ts +4 -1
- package/dist/types/tools/wait.d.ts +131 -0
- package/dist/types/tools/write.d.ts +4 -0
- package/dist/types/tools/xd-url.d.ts +8 -0
- package/dist/types/windows-altgr.d.ts +54 -0
- package/package.json +13 -10
- package/src/apps/debug/protocol-probe.ts +1 -1
- package/src/apps/ps-data.ts +1 -1
- package/src/apps/ps-top.ts +1 -1
- package/src/chat/chat-transcript-builder.ts +4 -4
- package/src/chat/tool-execution.ts +8 -8
- package/src/chat/transcript-render-helpers.ts +3 -3
- package/src/components/markdown.ts +1 -1
- package/src/desktop-notify.ts +1 -1
- package/src/overlays/annotation-overlay.ts +1145 -0
- package/src/overlays/annotation-types.ts +78 -0
- package/src/overlays/copy-selector.ts +45 -19
- package/src/overlays/copy-targets.ts +3 -3
- package/src/overlays/model-hub.ts +5 -4
- package/src/overlays/oauth-selector.ts +8 -12
- package/src/overlays/plan-review-overlay.ts +213 -40
- package/src/overlays/usage-dashboard.ts +22 -1
- package/src/prompt/image-source.ts +9 -8
- package/src/setup/scenes/sign-in.ts +1 -1
- package/src/status-line/context-usage.ts +15 -3
- package/src/terminal-capabilities.ts +2 -2
- package/src/terminal.ts +8 -1
- package/src/theme/mermaid-cache.ts +83 -25
- package/src/tools/bash.ts +14 -1
- package/src/tools/daemon.ts +51 -0
- package/src/tools/index.ts +2 -2
- package/src/tools/irc.ts +33 -0
- package/src/tools/line-ranges.ts +13 -3
- package/src/tools/proc-render.ts +294 -0
- package/src/tools/read.ts +22 -1
- package/src/tools/wait.ts +595 -0
- package/src/tools/write.ts +76 -0
- package/src/tools/xd-url.ts +9 -0
- package/src/windows-altgr.ts +227 -0
- package/dist/types/tools/hub.d.ts +0 -342
- package/src/tools/hub.ts +0 -1492
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { HighlightStream } from "@oh-my-pi/pi-natives";
|
|
2
2
|
import type { Component } from "../tui.js";
|
|
3
3
|
import { type Theme } from "../theme/theme.js";
|
|
4
|
+
import type { CoordinationDetails } from "./wait.js";
|
|
5
|
+
import { type ProcWriteDetails } from "./proc-render.js";
|
|
4
6
|
import type { FileDiagnosticsResult } from "./lsp.js";
|
|
5
7
|
import type { OutputMeta } from "./output-meta.js";
|
|
6
8
|
import type { RenderResultOptions, ToolActivityContext, ToolActivitySummary } from "./renderer.js";
|
|
@@ -16,6 +18,8 @@ export interface WriteToolDetails {
|
|
|
16
18
|
resolvedPath?: string;
|
|
17
19
|
/** Set when the write dispatched an `xd://` tool device; drives renderer delegation. */
|
|
18
20
|
xdev?: XdevRenderDispatch;
|
|
21
|
+
message?: CoordinationDetails;
|
|
22
|
+
proc?: ProcWriteDetails;
|
|
19
23
|
}
|
|
20
24
|
interface WriteRenderArgs {
|
|
21
25
|
path?: unknown;
|
|
@@ -9,5 +9,13 @@ export declare function stripXdUrlPrefix(name: string): string;
|
|
|
9
9
|
export declare function parseXdUrl(input: string): {
|
|
10
10
|
name: string | null;
|
|
11
11
|
} | null;
|
|
12
|
+
/**
|
|
13
|
+
* Parse a read-only `xd://<tool>/<topic>` documentation URL.
|
|
14
|
+
* Returns `null` for anything else, including bare device URLs.
|
|
15
|
+
*/
|
|
16
|
+
export declare function parseXdTopicUrl(input: string): {
|
|
17
|
+
name: string;
|
|
18
|
+
topic: string;
|
|
19
|
+
} | null;
|
|
12
20
|
/** Whether a streaming path prefix could still become an `xd://` URL. */
|
|
13
21
|
export declare function couldBecomeXdUrl(partialPath: string): boolean;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recover AltGr text that Windows console hosts drop under the kitty keyboard protocol.
|
|
3
|
+
*
|
|
4
|
+
* The kitty encoder shipped in Windows Terminal / OpenConsole before
|
|
5
|
+
* microsoft/terminal#20052 reports AltGr+key as Alt (or Ctrl+Alt) plus the
|
|
6
|
+
* layout's *unmodified* base key, without the produced text: Hungarian
|
|
7
|
+
* AltGr+F arrives as `CSI 102;3u` instead of `[`. The byte stream is then
|
|
8
|
+
* indistinguishable from a real Alt+F shortcut, so the character is lost and
|
|
9
|
+
* the chord fires `alt+f` bindings instead.
|
|
10
|
+
*
|
|
11
|
+
* Recovery reads two pieces of local state the bytes lack:
|
|
12
|
+
* - whether Right Alt (AltGr) is physically held, via `GetAsyncKeyState`;
|
|
13
|
+
* - what the active keyboard layout's AltGr layer produces for the base key,
|
|
14
|
+
* via `ToUnicodeEx`.
|
|
15
|
+
*
|
|
16
|
+
* Layouts without an AltGr layer (US, UK, ...) resolve to an empty table once and
|
|
17
|
+
* short-circuit every later event. The per-layout table is built once and cached;
|
|
18
|
+
* it is rebuilt only when the foreground window reports a different layout handle.
|
|
19
|
+
*
|
|
20
|
+
* Known limitation: AltGr keys that produce a dead key on the active layout have no
|
|
21
|
+
* table entry (`ToUnicodeEx` reports them as pending composition, not text), so those
|
|
22
|
+
* chords keep reaching Alt bindings.
|
|
23
|
+
*/
|
|
24
|
+
import { type Pointer } from "bun:ffi";
|
|
25
|
+
/** Keyboard layout handle (`HKL`) as `bun:ffi` surfaces pointer-sized values. */
|
|
26
|
+
export type KeyboardLayoutHandle = Pointer | bigint;
|
|
27
|
+
/**
|
|
28
|
+
* AltGr layer of an explicit layout handle (`HKL`), keyed `"<baseCodepoint>:<shift 0|1>"`.
|
|
29
|
+
* Test seam: lets a harness inspect a loaded layout without making it the active one.
|
|
30
|
+
*/
|
|
31
|
+
export declare function readAltGrLayer(hkl: KeyboardLayoutHandle): ReadonlyMap<string, string>;
|
|
32
|
+
/** Local keyboard state the translator reads; injectable so tests need no live desktop. */
|
|
33
|
+
export interface AltGrHost {
|
|
34
|
+
/** AltGr layer of the layout that produced the keystroke, keyed like {@link readAltGrLayer}. */
|
|
35
|
+
activeLayer(): ReadonlyMap<string, string>;
|
|
36
|
+
/** Whether Right Alt (AltGr) is held, or was within the last {@link RIGHT_ALT_LATCH_MS}. */
|
|
37
|
+
isRightAltDown(): boolean;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* How long an observed Right Alt press keeps counting as held. Key state is sampled
|
|
41
|
+
* at processing time, and one stdin read can carry several queued AltGr repeats that
|
|
42
|
+
* are dispatched synchronously after the key is released; the latch keeps that tail
|
|
43
|
+
* typing text. Far shorter than any release-then-Left-Alt chord a person can press.
|
|
44
|
+
*/
|
|
45
|
+
export declare const RIGHT_ALT_LATCH_MS = 30;
|
|
46
|
+
/** Wrap a raw Right Alt probe so a press stays observed for {@link RIGHT_ALT_LATCH_MS}. */
|
|
47
|
+
export declare function createRightAltLatch(isDownNow: () => boolean, now: () => number): () => boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Translate a kitty CSI-u Alt/Ctrl+Alt chord into the text AltGr produced, or
|
|
50
|
+
* `undefined` when the sequence is not an AltGr keystroke on the active layout.
|
|
51
|
+
*
|
|
52
|
+
* Only call this on native Windows ConPTY hosts with the kitty protocol active.
|
|
53
|
+
*/
|
|
54
|
+
export declare function translateWindowsAltGrSequence(data: string, host?: AltGrHost): string | undefined;
|
package/package.json
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@oh-my-pi/pi-tui",
|
|
4
|
-
"version": "18.
|
|
4
|
+
"version": "18.3.0",
|
|
5
5
|
"description": "Terminal User Interface library with differential rendering for efficient text-based applications",
|
|
6
6
|
"homepage": "https://omp.sh",
|
|
7
|
-
"author":
|
|
7
|
+
"author": {
|
|
8
|
+
"name": "Stencil Labs, Inc.",
|
|
9
|
+
"url": "https://stencil.so"
|
|
10
|
+
},
|
|
8
11
|
"contributors": [
|
|
9
12
|
"Mario Zechner"
|
|
10
13
|
],
|
|
@@ -37,14 +40,14 @@
|
|
|
37
40
|
"fmt": "oxfmt --no-error-on-unmatched-pattern 'src/**/*.{ts,tsx}' '{test,bench,examples,scripts}/**/*.ts' '*.ts'"
|
|
38
41
|
},
|
|
39
42
|
"dependencies": {
|
|
40
|
-
"@oh-my-pi/omptype": "18.
|
|
41
|
-
"@oh-my-pi/pi-agent-core": "18.
|
|
42
|
-
"@oh-my-pi/pi-ai": "18.
|
|
43
|
-
"@oh-my-pi/pi-catalog": "18.
|
|
44
|
-
"@oh-my-pi/pi-natives": "18.
|
|
45
|
-
"@oh-my-pi/pi-utils": "18.
|
|
46
|
-
"@oh-my-pi/pi-wire": "18.
|
|
47
|
-
"@oh-my-pi/snapcompact": "18.
|
|
43
|
+
"@oh-my-pi/omptype": "18.3.0",
|
|
44
|
+
"@oh-my-pi/pi-agent-core": "18.3.0",
|
|
45
|
+
"@oh-my-pi/pi-ai": "18.3.0",
|
|
46
|
+
"@oh-my-pi/pi-catalog": "18.3.0",
|
|
47
|
+
"@oh-my-pi/pi-natives": "18.3.0",
|
|
48
|
+
"@oh-my-pi/pi-utils": "18.3.0",
|
|
49
|
+
"@oh-my-pi/pi-wire": "18.3.0",
|
|
50
|
+
"@oh-my-pi/snapcompact": "18.3.0"
|
|
48
51
|
},
|
|
49
52
|
"devDependencies": {
|
|
50
53
|
"kitty-vt-wasm": "^0.2.0"
|
|
@@ -217,7 +217,7 @@ export class ProtocolProbeComponent extends Container {
|
|
|
217
217
|
new Text(
|
|
218
218
|
[
|
|
219
219
|
`${theme.fg("muted", "Hyperlinks (OSC 8)")} — ${yesNo(hyperlinksOn)}`,
|
|
220
|
-
` \x1b]8;;https://github.com/can1357/oh-my-pi\
|
|
220
|
+
` \x1b]8;;https://github.com/can1357/oh-my-pi\x07omp repo\x1b]8;;\x07`,
|
|
221
221
|
].join("\n"),
|
|
222
222
|
1,
|
|
223
223
|
0,
|
package/src/apps/ps-data.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as path from "node:path";
|
|
2
2
|
import { formatDuration } from "@oh-my-pi/pi-utils";
|
|
3
3
|
import chalk from "@oh-my-pi/pi-utils/chalk";
|
|
4
|
-
import type { DaemonSnapshot, DaemonSpec, DaemonState } from "../tools/
|
|
4
|
+
import type { DaemonSnapshot, DaemonSpec, DaemonState } from "../tools/daemon";
|
|
5
5
|
|
|
6
6
|
/** One broker scope: a project runtime dir or a machine-global service dir. */
|
|
7
7
|
export interface PsScope {
|
package/src/apps/ps-top.ts
CHANGED
|
@@ -15,7 +15,7 @@ import { type Component, TUI } from "../tui";
|
|
|
15
15
|
import { truncateToWidth } from "../utils";
|
|
16
16
|
import { formatDuration } from "@oh-my-pi/pi-utils";
|
|
17
17
|
import chalk from "@oh-my-pi/pi-utils/chalk";
|
|
18
|
-
import type { DaemonSnapshot, DaemonSpec } from "../tools/
|
|
18
|
+
import type { DaemonSnapshot, DaemonSpec } from "../tools/daemon";
|
|
19
19
|
import {
|
|
20
20
|
collapseCommand,
|
|
21
21
|
daemonLabel,
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* viewer ({@link AgentTranscriptViewer}) to render a parked subagent / advisor /
|
|
6
6
|
* collab-guest transcript that has no live session.
|
|
7
7
|
*
|
|
8
|
-
* Unlike
|
|
8
|
+
* Unlike incremental transcript sync, {@link ChatTranscriptBuilder.rebuild}
|
|
9
9
|
* always discards prior components and rebuilds the whole transcript from the
|
|
10
10
|
* supplied entries. Re-rendering a growing transcript is therefore O(n) in the
|
|
11
11
|
* entry count, but it cannot duplicate or misorder rows the way incremental
|
|
@@ -184,12 +184,12 @@ export class ChatTranscriptBuilder {
|
|
|
184
184
|
this.#expandables.push(component);
|
|
185
185
|
}
|
|
186
186
|
|
|
187
|
-
/** A `
|
|
187
|
+
/** A `wait` showing all-running is displaced by the next `wait` call. */
|
|
188
188
|
#resolveWaitingPoll(nextToolName?: string): void {
|
|
189
189
|
const previous = this.#waitingPoll;
|
|
190
190
|
if (!previous) return;
|
|
191
191
|
this.#waitingPoll = null;
|
|
192
|
-
if (nextToolName === "
|
|
192
|
+
if (nextToolName === "wait" && previous.isDisplaceableBlock() && this.container.canRemoveBlock(previous)) {
|
|
193
193
|
this.container.removeChild(previous);
|
|
194
194
|
}
|
|
195
195
|
previous.seal();
|
|
@@ -517,7 +517,7 @@ export class ChatTranscriptBuilder {
|
|
|
517
517
|
if (!pending) return;
|
|
518
518
|
pending.updateResult(message, false, message.toolCallId);
|
|
519
519
|
this.#pendingTools.delete(message.toolCallId);
|
|
520
|
-
if (message.toolName === "
|
|
520
|
+
if (message.toolName === "wait" && pending instanceof ToolExecutionComponent && pending.isDisplaceableBlock()) {
|
|
521
521
|
this.#waitingPoll = pending;
|
|
522
522
|
} else if (
|
|
523
523
|
message.toolName === "todo" &&
|
|
@@ -22,7 +22,7 @@ import { type EditMode, type PerFileDiffPreview, renderStreamingFallback } from
|
|
|
22
22
|
import { EVAL_DEFAULT_PREVIEW_LINES } from "../tools/eval";
|
|
23
23
|
import { taskCardAgentIds } from "../tools/task";
|
|
24
24
|
import { TODO_STRIKE_TOTAL_FRAMES, type TodoToolDetails } from "../tools/todo";
|
|
25
|
-
import { isWaitingPollDetails } from "../tools/
|
|
25
|
+
import { isWaitingPollDetails } from "../tools/wait";
|
|
26
26
|
import { formatStatusIcon, replaceTabs, resolveImageOptions } from "../render/render-utils";
|
|
27
27
|
import type { XdevMountedState } from "../tools/xdev";
|
|
28
28
|
import { isFramedBlockComponent, markFramedBlockComponent, renderStatusLine, WidthAwareText } from "../render/index";
|
|
@@ -35,7 +35,7 @@ import { type AnimationFrame, trimBlankEdges } from "../chrome/transcript-contai
|
|
|
35
35
|
export function toolRenderName(wireName: string, tool: AgentTool | undefined): string {
|
|
36
36
|
return tool?.name ?? wireName;
|
|
37
37
|
}
|
|
38
|
-
type DisplaceableToolName = "
|
|
38
|
+
type DisplaceableToolName = "wait" | "todo";
|
|
39
39
|
|
|
40
40
|
function isTodoToolDetails(details: unknown): details is TodoToolDetails {
|
|
41
41
|
return (
|
|
@@ -67,7 +67,7 @@ function displaceableToolName(
|
|
|
67
67
|
isPartial: boolean,
|
|
68
68
|
): DisplaceableToolName | undefined {
|
|
69
69
|
if (result.isError === true) return undefined;
|
|
70
|
-
if (toolName === "
|
|
70
|
+
if (toolName === "wait" && isWaitingPollDetails(result.details)) return "wait";
|
|
71
71
|
if (toolName === "todo" && !isPartial && isTodoToolDetails(result.details)) return "todo";
|
|
72
72
|
return undefined;
|
|
73
73
|
}
|
|
@@ -311,7 +311,7 @@ export class ToolExecutionComponent extends Container {
|
|
|
311
311
|
// late result can update its streaming preview.
|
|
312
312
|
#sealed = false;
|
|
313
313
|
// Tool result snapshots that may be superseded by a later same-tool call
|
|
314
|
-
// while still in the mutable viewport. `
|
|
314
|
+
// while still in the mutable viewport. `wait` uses this for repeated all-running polls; `todo` uses
|
|
315
315
|
// it for per-turn state snapshots so only the latest list remains visible.
|
|
316
316
|
#displaceableByToolName: DisplaceableToolName | undefined;
|
|
317
317
|
// Execution start on the presentation clock (performance.now domain, the
|
|
@@ -605,7 +605,7 @@ export class ToolExecutionComponent extends Container {
|
|
|
605
605
|
this.#toolName !== "todo" &&
|
|
606
606
|
!isBackgroundAsyncRunning &&
|
|
607
607
|
(pendingCallConsumesSpinner || partialResultConsumesSpinner);
|
|
608
|
-
const needsSpinner = isStreamingArgs || isLivePartialTool || this.#displaceableByToolName === "
|
|
608
|
+
const needsSpinner = isStreamingArgs || isLivePartialTool || this.#displaceableByToolName === "wait";
|
|
609
609
|
if (needsSpinner && !this.#spinnerActive) {
|
|
610
610
|
const frameCount = theme.spinnerFrames.length;
|
|
611
611
|
const frame = sharedSpinnerFrame(frameCount);
|
|
@@ -845,8 +845,8 @@ export class ToolExecutionComponent extends Container {
|
|
|
845
845
|
if (this.#allocation < 3) {
|
|
846
846
|
// A squeezed allocation degrades only blocks that genuinely overflow it.
|
|
847
847
|
// The allocator measures blocks by trimmed height and never squeezes one
|
|
848
|
-
// below that, so inline tools whose real content is 1-2 rows (
|
|
849
|
-
//
|
|
848
|
+
// below that, so inline tools whose real content is 1-2 rows (wait
|
|
849
|
+
// results, one-line receipts) keep that content instead of an equally
|
|
850
850
|
// tall but contentless frame.
|
|
851
851
|
const trimmed = trimBlankEdges(lines);
|
|
852
852
|
if (trimmed.length > this.#allocation) return this.#renderCompact(width);
|
|
@@ -891,7 +891,7 @@ export class ToolExecutionComponent extends Container {
|
|
|
891
891
|
});
|
|
892
892
|
if (summary !== undefined) {
|
|
893
893
|
if (summary.detail) return summary;
|
|
894
|
-
// A detail-less custom summary (e.g.
|
|
894
|
+
// A detail-less custom summary (e.g. wait before its result
|
|
895
895
|
// parse) must not fold to a bare `╭─ Label` frame under viewport
|
|
896
896
|
// pressure — keep the generic liveness hint for in-flight calls.
|
|
897
897
|
return this.#isRunning() ? { ...summary, detail: "running" } : summary;
|
|
@@ -7,10 +7,10 @@
|
|
|
7
7
|
import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
|
|
8
8
|
import { type Component } from "../tui";
|
|
9
9
|
import { formatBytes, formatDuration } from "@oh-my-pi/pi-utils";
|
|
10
|
-
import type { JobSnapshot } from "../tools/
|
|
11
|
-
import type { DaemonSnapshot } from "../tools/
|
|
10
|
+
import type { JobSnapshot } from "../tools/wait";
|
|
11
|
+
import type { DaemonSnapshot } from "../tools/daemon";
|
|
12
12
|
import { type CustomMessage, type FileMentionMessage, resolveAbortLabel, shouldRenderAbortReason } from "./messages";
|
|
13
|
-
import { createIrcMessageCard } from "../tools/
|
|
13
|
+
import { createIrcMessageCard } from "../tools/wait";
|
|
14
14
|
import { formatArtifactErrorNotice, type OutputMeta } from "../tools/output-meta";
|
|
15
15
|
import { replaceTabs, TRUNCATE_LENGTHS, truncateToWidth } from "../render/render-utils";
|
|
16
16
|
import { canonicalizeMessage } from "./thinking-display";
|
|
@@ -2955,7 +2955,7 @@ export class Markdown implements Component {
|
|
|
2955
2955
|
// resolver. The art is preformatted, so clip each row to the content
|
|
2956
2956
|
// width: the later wrap pass would otherwise fragment the box-drawing
|
|
2957
2957
|
// canvas. truncateToWidth is ANSI- and wide-char-aware, and the
|
|
2958
|
-
// resolver
|
|
2958
|
+
// resolver picks the shortest orientation that fits this width.
|
|
2959
2959
|
if (token.lang === "mermaid" && this.#theme.resolveMermaidAscii) {
|
|
2960
2960
|
const ascii = this.#theme.resolveMermaidAscii(token.text, width);
|
|
2961
2961
|
if (ascii) {
|
package/src/desktop-notify.ts
CHANGED
|
@@ -26,7 +26,7 @@ import { $which } from "@oh-my-pi/pi-utils";
|
|
|
26
26
|
import type { TerminalId, TerminalNotification } from "./terminal-capabilities";
|
|
27
27
|
|
|
28
28
|
/** Application name surfaced as the notification source. */
|
|
29
|
-
const APP_NAME = "
|
|
29
|
+
const APP_NAME = "omp";
|
|
30
30
|
|
|
31
31
|
/** Resolved notifier binary used to fan a notification out to D-Bus. */
|
|
32
32
|
export type DesktopNotifierKind = "notify-send" | "gdbus";
|