pi-ui-extend 0.1.9 → 0.1.13
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/README.md +23 -2
- package/dist/app/app.d.ts +4 -0
- package/dist/app/app.js +76 -7
- package/dist/app/cli/install.d.ts +16 -0
- package/dist/app/cli/install.js +34 -7
- package/dist/app/cli/startup-info.js +5 -2
- package/dist/app/cli/update.d.ts +7 -0
- package/dist/app/cli/update.js +11 -3
- package/dist/app/commands/command-controller.js +4 -0
- package/dist/app/commands/command-host.d.ts +4 -0
- package/dist/app/commands/command-model-actions.d.ts +5 -0
- package/dist/app/commands/command-model-actions.js +104 -0
- package/dist/app/commands/command-navigation-actions.d.ts +6 -1
- package/dist/app/commands/command-navigation-actions.js +37 -14
- package/dist/app/commands/command-registry.d.ts +4 -0
- package/dist/app/commands/command-registry.js +32 -0
- package/dist/app/commands/command-session-actions.d.ts +1 -0
- package/dist/app/commands/command-session-actions.js +15 -5
- package/dist/app/commands/shell-command.d.ts +7 -0
- package/dist/app/commands/shell-command.js +12 -4
- package/dist/app/commands/shell-controller.d.ts +1 -0
- package/dist/app/commands/shell-controller.js +1 -1
- package/dist/app/constants.d.ts +1 -1
- package/dist/app/constants.js +1 -1
- package/dist/app/icons.d.ts +1 -0
- package/dist/app/icons.js +3 -1
- package/dist/app/input/autocomplete-controller.d.ts +52 -0
- package/dist/app/input/autocomplete-controller.js +352 -0
- package/dist/app/input/input-action-controller.d.ts +1 -0
- package/dist/app/input/input-action-controller.js +21 -0
- package/dist/app/input/input-controller.d.ts +1 -0
- package/dist/app/input/input-controller.js +2 -0
- package/dist/app/input/input-paste-handler.d.ts +1 -0
- package/dist/app/input/input-paste-handler.js +22 -18
- package/dist/app/input/prompt-enhancer-controller.d.ts +7 -1
- package/dist/app/input/prompt-enhancer-controller.js +12 -3
- package/dist/app/input/voice-controller.d.ts +51 -1
- package/dist/app/input/voice-controller.js +42 -19
- package/dist/app/model/model-usage-status.d.ts +9 -0
- package/dist/app/model/model-usage-status.js +124 -34
- package/dist/app/popup/popup-action-controller.js +1 -1
- package/dist/app/process.d.ts +17 -0
- package/dist/app/process.js +68 -0
- package/dist/app/rendering/conversation-entry-renderer.js +8 -6
- package/dist/app/rendering/conversation-tool-renderer.js +3 -2
- package/dist/app/rendering/editor-layout-renderer.d.ts +1 -0
- package/dist/app/rendering/editor-layout-renderer.js +11 -1
- package/dist/app/rendering/message-content.js +65 -7
- package/dist/app/rendering/render-controller.js +6 -1
- package/dist/app/rendering/render-text.d.ts +3 -0
- package/dist/app/rendering/render-text.js +51 -3
- package/dist/app/rendering/status-line-renderer.d.ts +5 -1
- package/dist/app/rendering/status-line-renderer.js +61 -25
- package/dist/app/rendering/toast-renderer.js +10 -13
- package/dist/app/rendering/tool-block-renderer.d.ts +1 -0
- package/dist/app/rendering/tool-block-renderer.js +16 -33
- package/dist/app/runtime.d.ts +6 -1
- package/dist/app/runtime.js +35 -2
- package/dist/app/screen/clipboard.d.ts +11 -2
- package/dist/app/screen/clipboard.js +29 -21
- package/dist/app/screen/file-link-opener.d.ts +8 -0
- package/dist/app/screen/file-link-opener.js +11 -3
- package/dist/app/screen/file-links.js +3 -3
- package/dist/app/screen/image-opener.d.ts +12 -0
- package/dist/app/screen/image-opener.js +13 -5
- package/dist/app/screen/mouse-controller.d.ts +5 -2
- package/dist/app/screen/mouse-controller.js +16 -1
- package/dist/app/screen/screen-styler.d.ts +4 -1
- package/dist/app/screen/screen-styler.js +3 -2
- package/dist/app/screen/status-controller.d.ts +3 -0
- package/dist/app/screen/status-controller.js +23 -8
- package/dist/app/session/queued-message-controller.d.ts +7 -1
- package/dist/app/session/queued-message-controller.js +36 -21
- package/dist/app/session/resume-session-loader.d.ts +15 -0
- package/dist/app/session/resume-session-loader.js +204 -0
- package/dist/app/session/session-event-controller.d.ts +5 -1
- package/dist/app/session/session-event-controller.js +72 -5
- package/dist/app/session/session-history.js +4 -3
- package/dist/app/session/session-lifecycle-controller.d.ts +5 -0
- package/dist/app/session/session-lifecycle-controller.js +9 -1
- package/dist/app/session/tabs-controller.d.ts +10 -1
- package/dist/app/session/tabs-controller.js +101 -5
- package/dist/app/terminal/nerd-font-controller.d.ts +16 -0
- package/dist/app/terminal/nerd-font-controller.js +30 -23
- package/dist/app/terminal/terminal-controller.d.ts +1 -0
- package/dist/app/terminal/terminal-controller.js +1 -0
- package/dist/app/types.d.ts +14 -0
- package/dist/app/workspace/workspace-actions-controller.d.ts +1 -1
- package/dist/app/workspace/workspace-actions-controller.js +3 -3
- package/dist/app/workspace/workspace-undo.d.ts +1 -1
- package/dist/app/workspace/workspace-undo.js +22 -20
- package/dist/config.d.ts +27 -0
- package/dist/config.js +174 -1
- package/dist/default-pix-config.js +39 -353
- package/dist/input-editor.d.ts +7 -1
- package/dist/input-editor.js +47 -6
- package/dist/markdown-format.d.ts +1 -0
- package/dist/markdown-format.js +26 -1
- package/dist/schemas/index.d.ts +5 -0
- package/dist/schemas/index.js +5 -0
- package/dist/schemas/pi-tools-suite-schema.d.ts +177 -0
- package/dist/schemas/pi-tools-suite-schema.js +218 -0
- package/dist/schemas/pix-schema.d.ts +65 -0
- package/dist/schemas/pix-schema.js +91 -0
- package/dist/terminal-width.js +73 -56
- package/external/pi-tools-suite/src/async-subagents/async-subagents.sample.jsonc +3 -0
- package/external/pi-tools-suite/src/dcp/compression-blocks.ts +1 -0
- package/external/pi-tools-suite/src/dcp/prompts.ts +1 -0
- package/external/pi-tools-suite/src/default-pi-tools-suite-config.ts +46 -195
- package/external/pi-tools-suite/src/lib/lsp.ts +2 -1
- package/external/pi-tools-suite/src/lsp/_shared/output.ts +8 -7
- package/external/pi-tools-suite/src/lsp/manager.ts +4 -4
- package/external/pi-tools-suite/src/repo-discovery/index.ts +49 -2
- package/external/pi-tools-suite/src/todo/index.ts +4 -2
- package/external/pi-tools-suite/src/todo/state/selectors.ts +4 -0
- package/external/pi-tools-suite/src/todo/todo.ts +2 -6
- package/external/pi-tools-suite/src/todo/tool/response-envelope.ts +9 -1
- package/external/pi-tools-suite/src/tool-descriptions.ts +1 -1
- package/package.json +12 -3
- package/schemas/pi-tools-suite.json +881 -0
- package/schemas/pix.json +298 -0
|
@@ -1,4 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { commandExists, runProcess } from "../process.js";
|
|
2
|
+
type ClipboardDeps = {
|
|
3
|
+
commandExists: typeof commandExists;
|
|
4
|
+
requireResolve(specifier: string): string;
|
|
5
|
+
runProcess: typeof runProcess;
|
|
6
|
+
stdout: Pick<NodeJS.WriteStream, "destroyed" | "isTTY" | "write">;
|
|
7
|
+
};
|
|
8
|
+
export declare function setClipboardTestDeps(overrides: Partial<ClipboardDeps>): () => void;
|
|
9
|
+
export declare function copyTextToClipboard(text: string): Promise<void>;
|
|
10
|
+
export declare function clipboardSupportAvailable(env?: NodeJS.ProcessEnv): Promise<boolean>;
|
|
3
11
|
export declare function clipboardInstallHint(): string;
|
|
4
12
|
export declare function osc52ClipboardSequence(text: string, env?: NodeJS.ProcessEnv): string;
|
|
13
|
+
export {};
|
|
@@ -1,22 +1,37 @@
|
|
|
1
|
-
import { spawnSync } from "node:child_process";
|
|
2
1
|
import { createRequire } from "node:module";
|
|
2
|
+
import { commandExists, runProcess } from "../process.js";
|
|
3
3
|
const require = createRequire(import.meta.url);
|
|
4
|
-
|
|
4
|
+
let deps = {
|
|
5
|
+
commandExists,
|
|
6
|
+
requireResolve: (specifier) => require.resolve(specifier),
|
|
7
|
+
runProcess,
|
|
8
|
+
stdout: process.stdout,
|
|
9
|
+
};
|
|
10
|
+
export function setClipboardTestDeps(overrides) {
|
|
11
|
+
const previous = deps;
|
|
12
|
+
deps = { ...deps, ...overrides };
|
|
13
|
+
return () => {
|
|
14
|
+
deps = previous;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export async function copyTextToClipboard(text) {
|
|
5
18
|
const commands = clipboardCommands();
|
|
6
19
|
for (const [command, args] of commands) {
|
|
7
|
-
const result =
|
|
20
|
+
const result = await deps.runProcess(command, args, { input: text, maxBufferBytes: 1024 });
|
|
8
21
|
if (!result.error && result.status === 0)
|
|
9
22
|
return;
|
|
10
23
|
}
|
|
11
|
-
if (copyWithNativeClipboard(text))
|
|
24
|
+
if (await copyWithNativeClipboard(text))
|
|
12
25
|
return;
|
|
13
26
|
if (copyWithOsc52(text))
|
|
14
27
|
return;
|
|
15
28
|
throw new Error(`No clipboard command found. ${clipboardInstallHint()}`);
|
|
16
29
|
}
|
|
17
|
-
export function clipboardSupportAvailable(env = process.env) {
|
|
18
|
-
|
|
19
|
-
|
|
30
|
+
export async function clipboardSupportAvailable(env = process.env) {
|
|
31
|
+
for (const [command] of clipboardCommands()) {
|
|
32
|
+
if (await deps.commandExists(command, env))
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
20
35
|
return resolveNativeClipboardEntrypoint() !== undefined;
|
|
21
36
|
}
|
|
22
37
|
export function clipboardInstallHint() {
|
|
@@ -44,7 +59,7 @@ function clipboardCommands() {
|
|
|
44
59
|
];
|
|
45
60
|
}
|
|
46
61
|
}
|
|
47
|
-
function copyWithNativeClipboard(text) {
|
|
62
|
+
async function copyWithNativeClipboard(text) {
|
|
48
63
|
const entrypoint = resolveNativeClipboardEntrypoint();
|
|
49
64
|
if (!entrypoint)
|
|
50
65
|
return false;
|
|
@@ -55,17 +70,17 @@ function copyWithNativeClipboard(text) {
|
|
|
55
70
|
const clipboard = require(${JSON.stringify(entrypoint)});
|
|
56
71
|
await clipboard.setText(readFileSync(0, "utf8"));
|
|
57
72
|
`;
|
|
58
|
-
const result =
|
|
73
|
+
const result = await deps.runProcess(process.execPath, ["--input-type=module", "-e", script], {
|
|
59
74
|
input: text,
|
|
60
|
-
|
|
61
|
-
|
|
75
|
+
timeoutMs: 3_000,
|
|
76
|
+
maxBufferBytes: 1024,
|
|
62
77
|
});
|
|
63
78
|
return !result.error && result.status === 0;
|
|
64
79
|
}
|
|
65
80
|
function copyWithOsc52(text) {
|
|
66
|
-
if (
|
|
81
|
+
if (deps.stdout.destroyed || (!deps.stdout.isTTY && !process.env.TMUX && !process.env.STY))
|
|
67
82
|
return false;
|
|
68
|
-
|
|
83
|
+
deps.stdout.write(osc52ClipboardSequence(text));
|
|
69
84
|
return true;
|
|
70
85
|
}
|
|
71
86
|
export function osc52ClipboardSequence(text, env = process.env) {
|
|
@@ -78,16 +93,9 @@ export function osc52ClipboardSequence(text, env = process.env) {
|
|
|
78
93
|
}
|
|
79
94
|
function resolveNativeClipboardEntrypoint() {
|
|
80
95
|
try {
|
|
81
|
-
return
|
|
96
|
+
return deps.requireResolve("@mariozechner/clipboard");
|
|
82
97
|
}
|
|
83
98
|
catch {
|
|
84
99
|
return undefined;
|
|
85
100
|
}
|
|
86
101
|
}
|
|
87
|
-
function commandExists(command, env) {
|
|
88
|
-
const names = process.platform === "win32" ? [command, command.replace(/\.exe$/iu, ".cmd"), command.replace(/\.exe$/iu, ".bat")] : [command];
|
|
89
|
-
return names.some((name) => spawnSync(process.platform === "win32" ? "where" : "sh", process.platform === "win32" ? [name] : ["-lc", `command -v ${shellQuote(name)}`], { env, stdio: "ignore" }).status === 0);
|
|
90
|
-
}
|
|
91
|
-
function shellQuote(value) {
|
|
92
|
-
return `'${value.replaceAll("'", `'\\''`)}'`;
|
|
93
|
-
}
|
|
@@ -1,2 +1,10 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { spawn } from "node:child_process";
|
|
1
3
|
import type { RenderedLink } from "./file-links.js";
|
|
4
|
+
type FileLinkOpenerDeps = {
|
|
5
|
+
existsSync: typeof existsSync;
|
|
6
|
+
spawn: typeof spawn;
|
|
7
|
+
};
|
|
8
|
+
export declare function setFileLinkOpenerTestDeps(overrides: Partial<FileLinkOpenerDeps>): () => void;
|
|
2
9
|
export declare function openFileLink(link: RenderedLink): boolean;
|
|
10
|
+
export {};
|
|
@@ -2,6 +2,14 @@ import { existsSync } from "node:fs";
|
|
|
2
2
|
import { spawn } from "node:child_process";
|
|
3
3
|
import { delimiter, join } from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
|
+
let deps = { existsSync, spawn };
|
|
6
|
+
export function setFileLinkOpenerTestDeps(overrides) {
|
|
7
|
+
const previous = deps;
|
|
8
|
+
deps = { ...deps, ...overrides };
|
|
9
|
+
return () => {
|
|
10
|
+
deps = previous;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
5
13
|
export function openFileLink(link) {
|
|
6
14
|
const filePath = link.filePath ?? filePathFromUrl(link.url);
|
|
7
15
|
if (!filePath)
|
|
@@ -37,7 +45,7 @@ function zedCommandCandidates() {
|
|
|
37
45
|
}
|
|
38
46
|
function trySpawnCandidates(candidates, args) {
|
|
39
47
|
for (const command of candidates) {
|
|
40
|
-
if (command.includes("/") && !existsSync(command))
|
|
48
|
+
if (command.includes("/") && !deps.existsSync(command))
|
|
41
49
|
continue;
|
|
42
50
|
if (!command.includes("/") && !commandOnPath(command))
|
|
43
51
|
continue;
|
|
@@ -51,11 +59,11 @@ function commandOnPath(command) {
|
|
|
51
59
|
const extensions = process.platform === "win32"
|
|
52
60
|
? (process.env.PATHEXT?.split(";") ?? [".EXE", ".CMD", ".BAT", ".COM"])
|
|
53
61
|
: [""];
|
|
54
|
-
return pathEntries.some((entry) => extensions.some((extension) => existsSync(join(entry, `${command}${extension}`))));
|
|
62
|
+
return pathEntries.some((entry) => extensions.some((extension) => deps.existsSync(join(entry, `${command}${extension}`))));
|
|
55
63
|
}
|
|
56
64
|
function spawnDetached(command, args) {
|
|
57
65
|
try {
|
|
58
|
-
const child = spawn(command, args, { detached: true, stdio: "ignore" });
|
|
66
|
+
const child = deps.spawn(command, args, { detached: true, stdio: "ignore" });
|
|
59
67
|
child.on("error", () => { });
|
|
60
68
|
child.unref();
|
|
61
69
|
return true;
|
|
@@ -2,11 +2,11 @@ import { existsSync, statSync } from "node:fs";
|
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { isAbsolute, resolve } from "node:path";
|
|
4
4
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
5
|
-
const FILE_PATH_CANDIDATE = /(?<![\p{L}\p{N}_:])((?:file
|
|
5
|
+
const FILE_PATH_CANDIDATE = /(?<![\p{L}\p{N}_:])((?:file:\/\/\/|~[\\/]|\.{1,2}[\\/]|[A-Za-z]:[\\/]|[\\/]|[A-Za-z0-9_.@-]+[\\/])[^\s"'`<>]*)/gu;
|
|
6
6
|
const TRAILING_PUNCTUATION = new Set([".", ",", ";", ")", "]", "}"]);
|
|
7
7
|
export function detectFileLinks(text, cwd) {
|
|
8
8
|
const links = [];
|
|
9
|
-
if (!text.includes("/"))
|
|
9
|
+
if (!text.includes("/") && !text.includes("\\"))
|
|
10
10
|
return links;
|
|
11
11
|
for (const match of text.matchAll(FILE_PATH_CANDIDATE)) {
|
|
12
12
|
const raw = match[1];
|
|
@@ -89,7 +89,7 @@ function resolveLocalPath(pathText, cwd) {
|
|
|
89
89
|
return undefined;
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
|
-
if (pathText.startsWith("~/"))
|
|
92
|
+
if (pathText.startsWith("~/") || pathText.startsWith("~\\"))
|
|
93
93
|
return resolve(homedir(), pathText.slice(2));
|
|
94
94
|
if (isAbsolute(pathText))
|
|
95
95
|
return pathText;
|
|
@@ -1,2 +1,14 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
1
4
|
import type { ImageContent } from "../../input-editor.js";
|
|
5
|
+
type ImageOpenerDeps = {
|
|
6
|
+
existsSync: typeof existsSync;
|
|
7
|
+
mkdirSync: typeof mkdirSync;
|
|
8
|
+
spawn: typeof spawn;
|
|
9
|
+
tmpdir: typeof tmpdir;
|
|
10
|
+
writeFileSync: typeof writeFileSync;
|
|
11
|
+
};
|
|
12
|
+
export declare function setImageOpenerTestDeps(overrides: Partial<ImageOpenerDeps>): () => void;
|
|
2
13
|
export declare function openImageContent(image: ImageContent): boolean;
|
|
14
|
+
export {};
|
|
@@ -3,6 +3,14 @@ import { createHash } from "node:crypto";
|
|
|
3
3
|
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
import { tmpdir } from "node:os";
|
|
6
|
+
let deps = { existsSync, mkdirSync, spawn, tmpdir, writeFileSync };
|
|
7
|
+
export function setImageOpenerTestDeps(overrides) {
|
|
8
|
+
const previous = deps;
|
|
9
|
+
deps = { ...deps, ...overrides };
|
|
10
|
+
return () => {
|
|
11
|
+
deps = previous;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
6
14
|
export function openImageContent(image) {
|
|
7
15
|
const filePath = writeImageTempFile(image);
|
|
8
16
|
if (!filePath)
|
|
@@ -14,12 +22,12 @@ function writeImageTempFile(image) {
|
|
|
14
22
|
const data = Buffer.from(image.data, "base64");
|
|
15
23
|
if (data.length === 0)
|
|
16
24
|
return undefined;
|
|
17
|
-
const dir = join(tmpdir(), "pix-image-open");
|
|
18
|
-
mkdirSync(dir, { recursive: true });
|
|
25
|
+
const dir = join(deps.tmpdir(), "pix-image-open");
|
|
26
|
+
deps.mkdirSync(dir, { recursive: true });
|
|
19
27
|
const hash = createHash("sha256").update(image.mimeType).update("\0").update(data).digest("hex").slice(0, 24);
|
|
20
28
|
const filePath = join(dir, `${hash}${imageExtension(image.mimeType)}`);
|
|
21
|
-
if (!existsSync(filePath))
|
|
22
|
-
writeFileSync(filePath, data, { flag: "wx" });
|
|
29
|
+
if (!deps.existsSync(filePath))
|
|
30
|
+
deps.writeFileSync(filePath, data, { flag: "wx" });
|
|
23
31
|
return filePath;
|
|
24
32
|
}
|
|
25
33
|
catch {
|
|
@@ -53,7 +61,7 @@ function openPathWithSystemViewer(filePath) {
|
|
|
53
61
|
}
|
|
54
62
|
function spawnDetached(command, args) {
|
|
55
63
|
try {
|
|
56
|
-
const child = spawn(command, args, { detached: true, stdio: "ignore" });
|
|
64
|
+
const child = deps.spawn(command, args, { detached: true, stdio: "ignore" });
|
|
57
65
|
child.on("error", () => { });
|
|
58
66
|
child.unref();
|
|
59
67
|
return true;
|
|
@@ -6,7 +6,7 @@ import type { ToastEntry, ToastVariant } from "../../ui.js";
|
|
|
6
6
|
import type { AppPopupActionController } from "../popup/popup-action-controller.js";
|
|
7
7
|
import type { AppPopupMenuController } from "../popup/popup-menu-controller.js";
|
|
8
8
|
import type { AppScrollController } from "./scroll-controller.js";
|
|
9
|
-
import type { Entry, ImageClickTarget, MouseEvent, MouseSelection, StatusContextTarget, StatusCompactToolsTarget, StatusModelTarget, StatusModelUsageTarget, StatusPromptEnhancerTarget, StatusSessionTarget, StatusTerminalBellSoundTarget, TabLineMouseTarget, StatusThinkingExpandTarget, StatusThinkingTarget, StatusUserJumpTarget, StatusVoiceLanguageTarget, StatusVoiceMicTarget } from "../types.js";
|
|
9
|
+
import type { Entry, ImageClickTarget, MouseEvent, MouseSelection, StatusContextTarget, StatusCompactToolsTarget, StatusDraftQueueTarget, StatusModelTarget, StatusModelUsageTarget, StatusPromptEnhancerTarget, StatusSessionTarget, StatusTerminalBellSoundTarget, TabLineMouseTarget, StatusThinkingExpandTarget, StatusThinkingTarget, StatusUserJumpTarget, StatusVoiceLanguageTarget, StatusVoiceMicTarget } from "../types.js";
|
|
10
10
|
import { type RenderedLink } from "./file-links.js";
|
|
11
11
|
import type { AgentSession } from "@earendil-works/pi-coding-agent";
|
|
12
12
|
type ClickFlash = {
|
|
@@ -56,10 +56,11 @@ export type AppMouseControllerHost = {
|
|
|
56
56
|
}): void;
|
|
57
57
|
dismissToast(toastId: number): void;
|
|
58
58
|
refreshModelUsageStatus(): void | Promise<void>;
|
|
59
|
+
queueInputFromStatus?(): void | Promise<void>;
|
|
59
60
|
toggleAllThinkingExpanded?(): void;
|
|
60
61
|
toggleSuperCompactTools?(): void;
|
|
61
62
|
toggleTerminalBellSound?(): void;
|
|
62
|
-
copyTextToClipboard?(text: string): void
|
|
63
|
+
copyTextToClipboard?(text: string): void | Promise<void>;
|
|
63
64
|
handleExtensionInputMouse(event: MouseEvent & {
|
|
64
65
|
localRow: number;
|
|
65
66
|
localColumn: number;
|
|
@@ -100,6 +101,7 @@ export declare class AppMouseController {
|
|
|
100
101
|
statusContextTarget: StatusContextTarget | undefined;
|
|
101
102
|
statusModelUsageTarget: StatusModelUsageTarget | undefined;
|
|
102
103
|
statusUserJumpTarget: StatusUserJumpTarget | undefined;
|
|
104
|
+
statusDraftQueueTarget: StatusDraftQueueTarget | undefined;
|
|
103
105
|
statusThinkingExpandTarget: StatusThinkingExpandTarget | undefined;
|
|
104
106
|
statusCompactToolsTarget: StatusCompactToolsTarget | undefined;
|
|
105
107
|
statusTerminalBellSoundTarget: StatusTerminalBellSoundTarget | undefined;
|
|
@@ -153,6 +155,7 @@ export declare class AppMouseController {
|
|
|
153
155
|
private handleStatusContextClick;
|
|
154
156
|
private handleStatusModelUsageClick;
|
|
155
157
|
private handleStatusUserJumpClick;
|
|
158
|
+
private handleStatusDraftQueueClick;
|
|
156
159
|
private handleStatusThinkingExpandClick;
|
|
157
160
|
private handleStatusCompactToolsClick;
|
|
158
161
|
private handleStatusTerminalBellSoundClick;
|
|
@@ -24,6 +24,7 @@ export class AppMouseController {
|
|
|
24
24
|
statusContextTarget;
|
|
25
25
|
statusModelUsageTarget;
|
|
26
26
|
statusUserJumpTarget;
|
|
27
|
+
statusDraftQueueTarget;
|
|
27
28
|
statusThinkingExpandTarget;
|
|
28
29
|
statusCompactToolsTarget;
|
|
29
30
|
statusTerminalBellSoundTarget;
|
|
@@ -75,6 +76,8 @@ export class AppMouseController {
|
|
|
75
76
|
return;
|
|
76
77
|
if (event.button === 0 && this.withClickFlash(event, () => this.handleStatusModelUsageClick(event)))
|
|
77
78
|
return;
|
|
79
|
+
if (event.button === 0 && this.withClickFlash(event, () => this.handleStatusDraftQueueClick(event)))
|
|
80
|
+
return;
|
|
78
81
|
if (event.button === 0 && this.withClickFlash(event, () => this.handleStatusUserJumpClick(event)))
|
|
79
82
|
return;
|
|
80
83
|
if (event.button === 0 && this.withClickFlash(event, () => this.handleStatusThinkingExpandClick(event)))
|
|
@@ -286,6 +289,7 @@ export class AppMouseController {
|
|
|
286
289
|
this.statusThinkingTarget,
|
|
287
290
|
this.statusContextTarget,
|
|
288
291
|
this.statusModelUsageTarget,
|
|
292
|
+
this.statusDraftQueueTarget,
|
|
289
293
|
this.statusUserJumpTarget,
|
|
290
294
|
this.statusThinkingExpandTarget,
|
|
291
295
|
this.statusCompactToolsTarget,
|
|
@@ -509,6 +513,15 @@ export class AppMouseController {
|
|
|
509
513
|
this.host.render();
|
|
510
514
|
return true;
|
|
511
515
|
}
|
|
516
|
+
handleStatusDraftQueueClick(event) {
|
|
517
|
+
const target = this.statusDraftQueueTarget;
|
|
518
|
+
if (!target)
|
|
519
|
+
return false;
|
|
520
|
+
if (event.y !== target.row || event.x < target.startColumn || event.x >= target.endColumn)
|
|
521
|
+
return false;
|
|
522
|
+
void this.host.queueInputFromStatus?.();
|
|
523
|
+
return true;
|
|
524
|
+
}
|
|
512
525
|
handleStatusThinkingExpandClick(event) {
|
|
513
526
|
const target = this.statusThinkingExpandTarget;
|
|
514
527
|
if (!target)
|
|
@@ -769,7 +782,9 @@ export class AppMouseController {
|
|
|
769
782
|
return this.getSelectedScreenText(selection.anchor, selection.current);
|
|
770
783
|
}
|
|
771
784
|
copyTextToClipboard(text) {
|
|
772
|
-
(this.host.copyTextToClipboard ?? copyTextToClipboard)(text)
|
|
785
|
+
void Promise.resolve((this.host.copyTextToClipboard ?? copyTextToClipboard)(text)).catch((error) => {
|
|
786
|
+
this.host.showToast(error instanceof Error ? error.message : String(error), "error");
|
|
787
|
+
});
|
|
773
788
|
}
|
|
774
789
|
getSelectedScreenText(anchor, current) {
|
|
775
790
|
const range = orderedSelection(anchor, current);
|
|
@@ -24,7 +24,10 @@ export declare class ScreenStyler {
|
|
|
24
24
|
styleInputLine(row: number, text: string, tagSpans: readonly {
|
|
25
25
|
start: number;
|
|
26
26
|
end: number;
|
|
27
|
-
}[] | undefined,
|
|
27
|
+
}[] | undefined, suggestionSpans: readonly {
|
|
28
|
+
start: number;
|
|
29
|
+
end: number;
|
|
30
|
+
}[] | undefined, width: number, tagColor: string, suggestionColor: string, frameColor?: string): string;
|
|
28
31
|
private styleAnsiLine;
|
|
29
32
|
selectionRangeForRow(row: number, width: number): {
|
|
30
33
|
startIndex: number;
|
|
@@ -72,14 +72,14 @@ export class ScreenStyler {
|
|
|
72
72
|
colorize(after, options),
|
|
73
73
|
].join("");
|
|
74
74
|
}
|
|
75
|
-
styleInputLine(row, text, tagSpans, width, tagColor, frameColor) {
|
|
75
|
+
styleInputLine(row, text, tagSpans, suggestionSpans, width, tagColor, suggestionColor, frameColor) {
|
|
76
76
|
const colors = this.host.theme.colors;
|
|
77
77
|
const baseOptions = { foreground: colors.inputForeground };
|
|
78
78
|
if (this.selectionRangeForRow(row, width))
|
|
79
79
|
return this.styleLine(row, text, width, baseOptions);
|
|
80
80
|
const plain = padOrTrimPlain(text, width);
|
|
81
81
|
const frameSpans = inputFrameSpans(plain, width, frameColor);
|
|
82
|
-
if ((!tagSpans || tagSpans.length === 0) && frameSpans.length === 0) {
|
|
82
|
+
if ((!tagSpans || tagSpans.length === 0) && (!suggestionSpans || suggestionSpans.length === 0) && frameSpans.length === 0) {
|
|
83
83
|
return hasAnsi(plain) ? this.styleAnsiLine(plain, baseOptions) : colorize(plain, baseOptions);
|
|
84
84
|
}
|
|
85
85
|
const chunks = [];
|
|
@@ -88,6 +88,7 @@ export class ScreenStyler {
|
|
|
88
88
|
const spans = [
|
|
89
89
|
...frameSpans,
|
|
90
90
|
...(tagSpans ?? []).map((span) => ({ ...span, foreground: tagColor, bold: true })),
|
|
91
|
+
...(suggestionSpans ?? []).map((span) => ({ ...span, foreground: suggestionColor })),
|
|
91
92
|
].sort((a, b) => a.start - b.start || a.end - b.end);
|
|
92
93
|
for (const span of spans) {
|
|
93
94
|
const start = Math.max(offset, Math.min(endOffset, span.start));
|
|
@@ -7,12 +7,14 @@ export type AppStatusControllerHost = {
|
|
|
7
7
|
readonly theme: Theme;
|
|
8
8
|
readonly blinkController: AppBlinkController;
|
|
9
9
|
runtimeSession(): AgentSession | undefined;
|
|
10
|
+
render(): void;
|
|
10
11
|
};
|
|
11
12
|
export declare class AppStatusController {
|
|
12
13
|
private readonly host;
|
|
13
14
|
private status;
|
|
14
15
|
private statusFollowsSession;
|
|
15
16
|
private gitBranchCache;
|
|
17
|
+
private gitBranchLookupInFlight;
|
|
16
18
|
sessionActivity: SessionActivity;
|
|
17
19
|
get statusDotBright(): boolean;
|
|
18
20
|
constructor(host: AppStatusControllerHost);
|
|
@@ -31,5 +33,6 @@ export declare class AppStatusController {
|
|
|
31
33
|
roundedContextUsagePercent(session: AgentSession): number | undefined;
|
|
32
34
|
contextUsagePercentColor(percent: number): string;
|
|
33
35
|
private currentGitBranchName;
|
|
36
|
+
private refreshGitBranchName;
|
|
34
37
|
private startStatusBlink;
|
|
35
38
|
}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import { spawnSync } from "node:child_process";
|
|
2
1
|
import { basename } from "node:path";
|
|
3
2
|
import { GIT_BRANCH_CACHE_MS } from "../constants.js";
|
|
3
|
+
import { runProcess } from "../process.js";
|
|
4
4
|
const STATUS_DOT_BLINK_KEY = "status-dot";
|
|
5
5
|
export class AppStatusController {
|
|
6
6
|
host;
|
|
7
7
|
status = "starting";
|
|
8
8
|
statusFollowsSession = false;
|
|
9
9
|
gitBranchCache;
|
|
10
|
+
gitBranchLookupInFlight = false;
|
|
10
11
|
sessionActivity = "idle";
|
|
11
12
|
get statusDotBright() {
|
|
12
13
|
return this.host.blinkController.visible(STATUS_DOT_BLINK_KEY, false);
|
|
@@ -87,13 +88,27 @@ export class AppStatusController {
|
|
|
87
88
|
if (this.gitBranchCache && now - this.gitBranchCache.checkedAt < GIT_BRANCH_CACHE_MS) {
|
|
88
89
|
return this.gitBranchCache.branch;
|
|
89
90
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
91
|
+
if (!this.gitBranchLookupInFlight) {
|
|
92
|
+
this.gitBranchLookupInFlight = true;
|
|
93
|
+
void this.refreshGitBranchName();
|
|
94
|
+
}
|
|
95
|
+
return this.gitBranchCache?.branch;
|
|
96
|
+
}
|
|
97
|
+
async refreshGitBranchName() {
|
|
98
|
+
const previous = this.gitBranchCache?.branch;
|
|
99
|
+
try {
|
|
100
|
+
const result = await runProcess("git", ["-C", this.host.cwd, "branch", "--show-current"], {
|
|
101
|
+
timeoutMs: 150,
|
|
102
|
+
maxBufferBytes: 1024,
|
|
103
|
+
});
|
|
104
|
+
const branch = result.status === 0 ? result.stdout.trim() || undefined : undefined;
|
|
105
|
+
this.gitBranchCache = { checkedAt: Date.now(), branch };
|
|
106
|
+
if (branch !== previous)
|
|
107
|
+
this.host.render();
|
|
108
|
+
}
|
|
109
|
+
finally {
|
|
110
|
+
this.gitBranchLookupInFlight = false;
|
|
111
|
+
}
|
|
97
112
|
}
|
|
98
113
|
startStatusBlink() {
|
|
99
114
|
this.host.blinkController.setActive(STATUS_DOT_BLINK_KEY, true, {
|
|
@@ -19,6 +19,7 @@ export type AppQueuedMessageControllerHost = {
|
|
|
19
19
|
setInput(value: string): void;
|
|
20
20
|
insertInput(value: string): void;
|
|
21
21
|
attachImage(data: string, mimeType: string): void;
|
|
22
|
+
onDeferredUserMessagesChanged?(): void;
|
|
22
23
|
};
|
|
23
24
|
export declare class AppQueuedMessageController {
|
|
24
25
|
private readonly host;
|
|
@@ -28,6 +29,8 @@ export declare class AppQueuedMessageController {
|
|
|
28
29
|
private immediateSendInProgress;
|
|
29
30
|
constructor(host: AppQueuedMessageControllerHost);
|
|
30
31
|
reset(): void;
|
|
32
|
+
captureDeferredUserMessages(): SubmittedUserMessage[];
|
|
33
|
+
restoreDeferredUserMessages(messages: readonly SubmittedUserMessage[]): void;
|
|
31
34
|
createSubmittedUserMessage(promptText: string, displayText: string, images: ImageContent[]): SubmittedUserMessage;
|
|
32
35
|
submitUserMessage(message: SubmittedUserMessage): Promise<void>;
|
|
33
36
|
sendUserMessageToSession(message: SubmittedUserMessage, options?: {
|
|
@@ -44,11 +47,12 @@ export declare class AppQueuedMessageController {
|
|
|
44
47
|
cancelQueuedMessage(entryId: string): Promise<void>;
|
|
45
48
|
editQueuedMessage(entryId: string): Promise<void>;
|
|
46
49
|
sendQueuedMessageImmediately(entryId: string): Promise<void>;
|
|
50
|
+
private sendQueuedEntryImmediately;
|
|
47
51
|
findQueuedEntry(entryId: string): Extract<Entry, {
|
|
48
52
|
kind: "queued";
|
|
49
53
|
}> | undefined;
|
|
50
54
|
private shouldDeferUserMessage;
|
|
51
|
-
|
|
55
|
+
deferUserMessage(message: SubmittedUserMessage): void;
|
|
52
56
|
private rewriteSdkQueuedMessages;
|
|
53
57
|
private takeQueuedEntryForInterruptedSend;
|
|
54
58
|
private restoreSdkQueuedMessages;
|
|
@@ -59,4 +63,6 @@ export declare class AppQueuedMessageController {
|
|
|
59
63
|
private requeueRemovedEntry;
|
|
60
64
|
private restoreSubmittedMessageToEditor;
|
|
61
65
|
private restorableSubmittedMessageText;
|
|
66
|
+
private cloneSubmittedUserMessage;
|
|
67
|
+
private notifyDeferredUserMessagesChanged;
|
|
62
68
|
}
|
|
@@ -14,6 +14,14 @@ export class AppQueuedMessageController {
|
|
|
14
14
|
this.promptSubmissionInFlight = false;
|
|
15
15
|
this.flushingDeferredUserMessages = false;
|
|
16
16
|
}
|
|
17
|
+
captureDeferredUserMessages() {
|
|
18
|
+
return this.deferredUserMessages.map((message) => this.cloneSubmittedUserMessage(message));
|
|
19
|
+
}
|
|
20
|
+
restoreDeferredUserMessages(messages) {
|
|
21
|
+
this.deferredUserMessages.length = 0;
|
|
22
|
+
this.deferredUserMessages.push(...messages.map((message) => this.cloneSubmittedUserMessage(message)));
|
|
23
|
+
this.updateQueuedMessageStatus();
|
|
24
|
+
}
|
|
17
25
|
createSubmittedUserMessage(promptText, displayText, images) {
|
|
18
26
|
return {
|
|
19
27
|
id: createId("queued-user"),
|
|
@@ -24,6 +32,10 @@ export class AppQueuedMessageController {
|
|
|
24
32
|
}
|
|
25
33
|
async submitUserMessage(message) {
|
|
26
34
|
const session = this.host.requireRuntime().session;
|
|
35
|
+
if (session.isStreaming) {
|
|
36
|
+
await this.sendUserMessageToSession(message, { streamingBehavior: "steer" });
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
27
39
|
if (this.shouldDeferUserMessage(session)) {
|
|
28
40
|
this.deferUserMessage(message);
|
|
29
41
|
return;
|
|
@@ -55,8 +67,6 @@ export class AppQueuedMessageController {
|
|
|
55
67
|
}
|
|
56
68
|
if (this.totalQueuedMessageCount() > 0)
|
|
57
69
|
this.updateQueuedMessageStatus();
|
|
58
|
-
if (!this.flushingDeferredUserMessages)
|
|
59
|
-
void this.flushDeferredUserMessages();
|
|
60
70
|
}
|
|
61
71
|
}
|
|
62
72
|
async flushDeferredUserMessages() {
|
|
@@ -80,22 +90,14 @@ export class AppQueuedMessageController {
|
|
|
80
90
|
const message = this.deferredUserMessages.shift();
|
|
81
91
|
if (!message)
|
|
82
92
|
break;
|
|
93
|
+
this.notifyDeferredUserMessagesChanged();
|
|
83
94
|
this.updateQueuedMessageStatus();
|
|
84
|
-
if (!activeSession.isStreaming && this.deferredUserMessages.length > 0) {
|
|
85
|
-
void this.sendUserMessageToSession(message).catch((error) => {
|
|
86
|
-
this.deferredUserMessages.unshift(message);
|
|
87
|
-
this.updateQueuedMessageStatus();
|
|
88
|
-
this.host.addEntry({ id: createId("error"), kind: "error", text: `Queued message failed: ${stringifyUnknown(error)}` });
|
|
89
|
-
if (this.host.isRunning())
|
|
90
|
-
this.host.render();
|
|
91
|
-
});
|
|
92
|
-
break;
|
|
93
|
-
}
|
|
94
95
|
try {
|
|
95
96
|
await this.sendUserMessageToSession(message);
|
|
96
97
|
}
|
|
97
98
|
catch (error) {
|
|
98
99
|
this.deferredUserMessages.unshift(message);
|
|
100
|
+
this.notifyDeferredUserMessagesChanged();
|
|
99
101
|
this.updateQueuedMessageStatus();
|
|
100
102
|
this.host.addEntry({ id: createId("error"), kind: "error", text: `Queued message failed: ${stringifyUnknown(error)}` });
|
|
101
103
|
break;
|
|
@@ -103,17 +105,11 @@ export class AppQueuedMessageController {
|
|
|
103
105
|
}
|
|
104
106
|
}
|
|
105
107
|
finally {
|
|
106
|
-
const shouldRetryFlush = this.deferredUserMessages.length > 0 && Boolean(this.host.runtime()?.session) && !this.host.runtime()?.session.isCompacting;
|
|
107
108
|
this.flushingDeferredUserMessages = false;
|
|
108
109
|
if (this.totalQueuedMessageCount() > 0)
|
|
109
110
|
this.updateQueuedMessageStatus();
|
|
110
111
|
if (this.host.isRunning())
|
|
111
112
|
this.host.render();
|
|
112
|
-
if (shouldRetryFlush) {
|
|
113
|
-
queueMicrotask(() => {
|
|
114
|
-
void this.flushDeferredUserMessages();
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
113
|
}
|
|
118
114
|
}
|
|
119
115
|
queuedMessageCounts() {
|
|
@@ -135,6 +131,8 @@ export class AppQueuedMessageController {
|
|
|
135
131
|
const session = this.host.runtime()?.session;
|
|
136
132
|
const sdkQueued = session?.clearQueue() ?? { steering: [], followUp: [] };
|
|
137
133
|
const deferred = this.deferredUserMessages.splice(0);
|
|
134
|
+
if (deferred.length > 0)
|
|
135
|
+
this.notifyDeferredUserMessagesChanged();
|
|
138
136
|
const restoredTexts = [
|
|
139
137
|
...sdkQueued.steering,
|
|
140
138
|
...deferred.map((message) => this.restorableSubmittedMessageText(message)),
|
|
@@ -186,6 +184,9 @@ export class AppQueuedMessageController {
|
|
|
186
184
|
const entry = this.findQueuedEntry(entryId);
|
|
187
185
|
if (!entry)
|
|
188
186
|
throw new Error("Queued message is no longer available");
|
|
187
|
+
await this.sendQueuedEntryImmediately(entry);
|
|
188
|
+
}
|
|
189
|
+
async sendQueuedEntryImmediately(entry) {
|
|
189
190
|
const session = this.host.requireRuntime().session;
|
|
190
191
|
const shouldInterrupt = session.isStreaming || session.isCompacting;
|
|
191
192
|
const taken = shouldInterrupt
|
|
@@ -224,8 +225,6 @@ export class AppQueuedMessageController {
|
|
|
224
225
|
this.immediateSendInProgress = false;
|
|
225
226
|
if (this.totalQueuedMessageCount() > 0)
|
|
226
227
|
this.updateQueuedMessageStatus();
|
|
227
|
-
if (!this.flushingDeferredUserMessages)
|
|
228
|
-
void this.flushDeferredUserMessages();
|
|
229
228
|
}
|
|
230
229
|
}
|
|
231
230
|
findQueuedEntry(entryId) {
|
|
@@ -233,11 +232,13 @@ export class AppQueuedMessageController {
|
|
|
233
232
|
return entry?.kind === "queued" ? entry : undefined;
|
|
234
233
|
}
|
|
235
234
|
shouldDeferUserMessage(session) {
|
|
236
|
-
return session.isCompacting ||
|
|
235
|
+
return session.isCompacting || this.promptSubmissionInFlight;
|
|
237
236
|
}
|
|
238
237
|
deferUserMessage(message) {
|
|
239
238
|
this.deferredUserMessages.push(message);
|
|
239
|
+
this.notifyDeferredUserMessagesChanged();
|
|
240
240
|
this.updateQueuedMessageStatus();
|
|
241
|
+
this.host.showToast("Message queued; send it from the queue menu or status button", "info");
|
|
241
242
|
this.host.render();
|
|
242
243
|
}
|
|
243
244
|
async rewriteSdkQueuedMessages(update) {
|
|
@@ -282,6 +283,7 @@ export class AppQueuedMessageController {
|
|
|
282
283
|
if (!message)
|
|
283
284
|
throw new Error("Queued message is no longer available");
|
|
284
285
|
session.clearQueue();
|
|
286
|
+
this.notifyDeferredUserMessagesChanged();
|
|
285
287
|
return { removed: message, sdkMessagesToRestore: sdkMessages };
|
|
286
288
|
}
|
|
287
289
|
const messages = entry.queueSource === "sdk-steering" ? sdkMessages.steering : sdkMessages.followUp;
|
|
@@ -334,6 +336,7 @@ export class AppQueuedMessageController {
|
|
|
334
336
|
const [message] = this.deferredUserMessages.splice(entry.queueIndex, 1);
|
|
335
337
|
if (!message)
|
|
336
338
|
throw new Error("Queued message is no longer available");
|
|
339
|
+
this.notifyDeferredUserMessagesChanged();
|
|
337
340
|
return message;
|
|
338
341
|
}
|
|
339
342
|
const removed = await this.rewriteSdkQueuedMessages((steering, followUp) => {
|
|
@@ -350,6 +353,7 @@ export class AppQueuedMessageController {
|
|
|
350
353
|
if (typeof removed === "string")
|
|
351
354
|
return;
|
|
352
355
|
this.deferredUserMessages.splice(Math.min(entry.queueIndex, this.deferredUserMessages.length), 0, removed);
|
|
356
|
+
this.notifyDeferredUserMessagesChanged();
|
|
353
357
|
return;
|
|
354
358
|
}
|
|
355
359
|
if (typeof removed !== "string")
|
|
@@ -374,4 +378,15 @@ export class AppQueuedMessageController {
|
|
|
374
378
|
? message.promptText.replace(/\[Image \d+(?:: [^\]]+)?\]\s*/g, "").trimEnd()
|
|
375
379
|
: message.promptText.trimEnd();
|
|
376
380
|
}
|
|
381
|
+
cloneSubmittedUserMessage(message) {
|
|
382
|
+
return {
|
|
383
|
+
id: message.id,
|
|
384
|
+
promptText: message.promptText,
|
|
385
|
+
displayText: message.displayText,
|
|
386
|
+
images: message.images.map((image) => ({ ...image })),
|
|
387
|
+
};
|
|
388
|
+
}
|
|
389
|
+
notifyDeferredUserMessagesChanged() {
|
|
390
|
+
this.host.onDeferredUserMessagesChanged?.();
|
|
391
|
+
}
|
|
377
392
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type SessionInfo } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
export type ResumeSessionLoadProgress = {
|
|
3
|
+
loaded: number;
|
|
4
|
+
total: number;
|
|
5
|
+
done: boolean;
|
|
6
|
+
};
|
|
7
|
+
export type ResumeSessionLoaderOptions = {
|
|
8
|
+
cwd: string;
|
|
9
|
+
sessionDir?: string;
|
|
10
|
+
initialChunkSize?: number;
|
|
11
|
+
chunkSize?: number;
|
|
12
|
+
signal?: AbortSignal;
|
|
13
|
+
onChunk(sessions: readonly SessionInfo[], progress: ResumeSessionLoadProgress): void;
|
|
14
|
+
};
|
|
15
|
+
export declare function loadResumeSessionsInChunks(options: ResumeSessionLoaderOptions): Promise<SessionInfo[]>;
|