@oh-my-pi/pi-coding-agent 15.10.11 → 15.11.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 +103 -2
- package/dist/cli.js +5790 -5731
- package/dist/types/async/index.d.ts +0 -1
- package/dist/types/cli/args.d.ts +1 -0
- package/dist/types/cli/gallery-fixtures/types.d.ts +5 -0
- package/dist/types/cli-commands.d.ts +12 -0
- package/dist/types/commands/launch.d.ts +4 -0
- package/dist/types/config/api-key-resolver.d.ts +3 -0
- package/dist/types/config/keybindings.d.ts +6 -1
- package/dist/types/config/model-registry.d.ts +1 -0
- package/dist/types/config/model-resolver.d.ts +18 -0
- package/dist/types/config/settings-schema.d.ts +85 -34
- package/dist/types/config/settings.d.ts +7 -0
- package/dist/types/edit/hashline/noop-loop-guard.d.ts +72 -0
- package/dist/types/eval/py/executor.d.ts +5 -0
- package/dist/types/eval/py/kernel.d.ts +6 -1
- package/dist/types/eval/py/runtime.d.ts +9 -0
- package/dist/types/exec/bash-executor.d.ts +2 -0
- package/dist/types/export/html/template.generated.d.ts +1 -1
- package/dist/types/extensibility/custom-tools/types.d.ts +2 -2
- package/dist/types/extensibility/extensions/runner.d.ts +3 -2
- package/dist/types/extensibility/extensions/types.d.ts +3 -0
- package/dist/types/extensibility/shared-events.d.ts +2 -2
- package/dist/types/internal-urls/history-protocol.d.ts +14 -0
- package/dist/types/internal-urls/index.d.ts +1 -0
- package/dist/types/internal-urls/types.d.ts +1 -1
- package/dist/types/irc/bus.d.ts +66 -0
- package/dist/types/memory-backend/index.d.ts +1 -0
- package/dist/types/memory-backend/runtime.d.ts +4 -0
- package/dist/types/memory-backend/types.d.ts +66 -1
- package/dist/types/modes/components/agent-hub.d.ts +30 -0
- package/dist/types/modes/components/compaction-summary-message.d.ts +10 -4
- package/dist/types/modes/components/custom-editor.d.ts +2 -0
- package/dist/types/modes/components/tool-execution.d.ts +8 -0
- package/dist/types/modes/components/ttsr-notification.d.ts +5 -1
- package/dist/types/modes/components/welcome.d.ts +3 -9
- package/dist/types/modes/controllers/selector-controller.d.ts +1 -1
- package/dist/types/modes/index.d.ts +3 -3
- package/dist/types/modes/interactive-mode.d.ts +10 -4
- package/dist/types/modes/oauth-manual-input.d.ts +7 -0
- package/dist/types/modes/rpc/rpc-client.d.ts +39 -2
- package/dist/types/modes/rpc/rpc-mode.d.ts +31 -2
- package/dist/types/modes/rpc/rpc-subagents.d.ts +24 -0
- package/dist/types/modes/rpc/rpc-types.d.ts +75 -1
- package/dist/types/modes/setup-wizard/index.d.ts +5 -1
- package/dist/types/modes/setup-wizard/lazy.d.ts +2 -0
- package/dist/types/modes/theme/theme.d.ts +2 -1
- package/dist/types/modes/types.d.ts +5 -2
- package/dist/types/modes/utils/ui-helpers.d.ts +1 -1
- package/dist/types/registry/agent-lifecycle.d.ts +51 -0
- package/dist/types/registry/agent-registry.d.ts +16 -5
- package/dist/types/secrets/index.d.ts +1 -1
- package/dist/types/secrets/obfuscator.d.ts +8 -2
- package/dist/types/session/agent-session.d.ts +49 -32
- package/dist/types/session/messages.d.ts +2 -4
- package/dist/types/session/session-history-format.d.ts +12 -0
- package/dist/types/session/session-manager.d.ts +21 -3
- package/dist/types/session/streaming-output.d.ts +46 -0
- package/dist/types/slash-commands/acp-builtins.d.ts +16 -0
- package/dist/types/slash-commands/builtin-registry.d.ts +1 -0
- package/dist/types/slash-commands/types.d.ts +1 -1
- package/dist/types/system-prompt.d.ts +2 -0
- package/dist/types/task/executor.d.ts +12 -2
- package/dist/types/task/index.d.ts +13 -6
- package/dist/types/task/output-manager.d.ts +0 -7
- package/dist/types/task/repair-args.d.ts +8 -7
- package/dist/types/task/types.d.ts +63 -51
- package/dist/types/thinking.d.ts +4 -0
- package/dist/types/tiny/title-client.d.ts +11 -0
- package/dist/types/tiny/title-protocol.d.ts +1 -0
- package/dist/types/tools/browser/tab-worker.d.ts +3 -1
- package/dist/types/tools/find.d.ts +0 -11
- package/dist/types/tools/grouped-file-output.d.ts +0 -49
- package/dist/types/tools/index.d.ts +7 -3
- package/dist/types/tools/irc.d.ts +76 -38
- package/dist/types/tools/job.d.ts +7 -1
- package/dist/types/utils/git.d.ts +15 -2
- package/dist/types/utils/title-generator.d.ts +3 -2
- package/examples/extensions/with-deps/package.json +1 -0
- package/package.json +11 -10
- package/scripts/bundle-dist.ts +28 -19
- package/src/async/index.ts +0 -1
- package/src/auto-thinking/classifier.ts +1 -0
- package/src/cli/args.ts +3 -0
- package/src/cli/gallery-cli.ts +1 -1
- package/src/cli/gallery-fixtures/agentic.ts +230 -115
- package/src/cli/gallery-fixtures/types.ts +5 -0
- package/src/cli-commands.ts +29 -0
- package/src/cli.ts +28 -15
- package/src/commands/launch.ts +4 -0
- package/src/commit/agentic/tools/analyze-file.ts +38 -19
- package/src/commit/model-selection.ts +3 -2
- package/src/config/api-key-resolver.ts +8 -6
- package/src/config/keybindings.ts +6 -1
- package/src/config/model-registry.ts +97 -30
- package/src/config/model-resolver.ts +60 -0
- package/src/config/settings-schema.ts +99 -55
- package/src/config/settings.ts +68 -3
- package/src/edit/hashline/execute.ts +39 -2
- package/src/edit/hashline/noop-loop-guard.ts +99 -0
- package/src/eval/__tests__/agent-bridge.test.ts +5 -3
- package/src/eval/agent-bridge.ts +3 -16
- package/src/eval/completion-bridge.ts +1 -0
- package/src/eval/js/shared/prelude.txt +1 -1
- package/src/eval/py/executor.ts +29 -7
- package/src/eval/py/index.ts +6 -1
- package/src/eval/py/kernel.ts +31 -11
- package/src/eval/py/prelude.py +5 -6
- package/src/eval/py/runtime.ts +37 -0
- package/src/exec/bash-executor.ts +82 -3
- package/src/export/html/template.generated.ts +1 -1
- package/src/export/html/template.js +38 -13
- package/src/extensibility/custom-tools/types.ts +2 -2
- package/src/extensibility/extensions/get-commands-handler.ts +2 -1
- package/src/extensibility/extensions/runner.ts +6 -1
- package/src/extensibility/extensions/types.ts +3 -0
- package/src/extensibility/shared-events.ts +2 -2
- package/src/hindsight/bank.ts +17 -2
- package/src/internal-urls/docs-index.generated.ts +11 -11
- package/src/internal-urls/history-protocol.ts +113 -0
- package/src/internal-urls/index.ts +1 -0
- package/src/internal-urls/router.ts +3 -1
- package/src/internal-urls/types.ts +1 -1
- package/src/irc/bus.ts +292 -0
- package/src/main.ts +26 -66
- package/src/memories/index.ts +2 -0
- package/src/memory-backend/index.ts +1 -0
- package/src/memory-backend/local-backend.ts +9 -0
- package/src/memory-backend/off-backend.ts +9 -0
- package/src/memory-backend/runtime.ts +66 -0
- package/src/memory-backend/types.ts +81 -1
- package/src/mnemopi/backend.ts +151 -4
- package/src/modes/acp/acp-agent.ts +119 -11
- package/src/modes/components/{session-observer-overlay.ts → agent-hub.ts} +586 -367
- package/src/modes/components/assistant-message.ts +19 -21
- package/src/modes/components/compaction-summary-message.ts +68 -32
- package/src/modes/components/custom-editor.ts +10 -0
- package/src/modes/components/footer.ts +3 -1
- package/src/modes/components/status-line/component.ts +118 -34
- package/src/modes/components/tool-execution.ts +31 -1
- package/src/modes/components/ttsr-notification.ts +72 -30
- package/src/modes/components/welcome.ts +9 -33
- package/src/modes/controllers/command-controller.ts +1 -1
- package/src/modes/controllers/event-controller.ts +65 -0
- package/src/modes/controllers/extension-ui-controller.ts +8 -8
- package/src/modes/controllers/input-controller.ts +19 -2
- package/src/modes/controllers/mcp-command-controller.ts +38 -3
- package/src/modes/controllers/selector-controller.ts +21 -17
- package/src/modes/index.ts +3 -21
- package/src/modes/interactive-mode.ts +47 -22
- package/src/modes/oauth-manual-input.ts +30 -3
- package/src/modes/rpc/rpc-client.ts +154 -3
- package/src/modes/rpc/rpc-mode.ts +97 -12
- package/src/modes/rpc/rpc-subagents.ts +265 -0
- package/src/modes/rpc/rpc-types.ts +81 -1
- package/src/modes/setup-wizard/index.ts +12 -2
- package/src/modes/setup-wizard/lazy.ts +16 -0
- package/src/modes/theme/theme.ts +18 -5
- package/src/modes/types.ts +5 -5
- package/src/modes/utils/hotkeys-markdown.ts +1 -0
- package/src/modes/utils/ui-helpers.ts +51 -49
- package/src/prompts/system/irc-incoming.md +3 -4
- package/src/prompts/system/orchestrate-notice.md +2 -2
- package/src/prompts/system/subagent-system-prompt.md +0 -5
- package/src/prompts/system/system-prompt.md +1 -0
- package/src/prompts/system/workflow-notice.md +2 -2
- package/src/prompts/tools/eval.md +3 -3
- package/src/prompts/tools/irc.md +29 -19
- package/src/prompts/tools/read.md +2 -2
- package/src/prompts/tools/task-summary.md +5 -16
- package/src/prompts/tools/task.md +38 -29
- package/src/registry/agent-lifecycle.ts +218 -0
- package/src/registry/agent-registry.ts +16 -5
- package/src/sdk.ts +37 -10
- package/src/secrets/index.ts +8 -1
- package/src/secrets/obfuscator.ts +39 -18
- package/src/session/agent-session.ts +422 -291
- package/src/session/messages.ts +11 -78
- package/src/session/session-history-format.ts +246 -0
- package/src/session/session-manager.ts +59 -5
- package/src/session/streaming-output.ts +226 -10
- package/src/slash-commands/acp-builtins.ts +24 -0
- package/src/slash-commands/builtin-registry.ts +20 -0
- package/src/slash-commands/types.ts +1 -1
- package/src/system-prompt.ts +14 -0
- package/src/task/executor.ts +851 -461
- package/src/task/index.ts +721 -796
- package/src/task/output-manager.ts +0 -11
- package/src/task/render.ts +148 -63
- package/src/task/repair-args.ts +21 -9
- package/src/task/types.ts +82 -66
- package/src/thinking.ts +7 -0
- package/src/tiny/title-client.ts +34 -5
- package/src/tiny/title-protocol.ts +1 -1
- package/src/tiny/worker.ts +6 -4
- package/src/tools/ask.ts +4 -2
- package/src/tools/bash.ts +61 -10
- package/src/tools/browser/tab-worker.ts +26 -7
- package/src/tools/browser.ts +28 -1
- package/src/tools/find.ts +2 -27
- package/src/tools/grouped-file-output.ts +1 -118
- package/src/tools/image-gen.ts +11 -4
- package/src/tools/index.ts +17 -13
- package/src/tools/inspect-image.ts +1 -0
- package/src/tools/irc.ts +596 -171
- package/src/tools/job.ts +41 -7
- package/src/tools/read.ts +57 -1
- package/src/tools/renderers.ts +2 -0
- package/src/tools/resolve.ts +4 -1
- package/src/utils/commit-message-generator.ts +1 -0
- package/src/utils/git.ts +267 -13
- package/src/utils/title-generator.ts +24 -5
- package/dist/types/async/support.d.ts +0 -2
- package/dist/types/modes/components/session-observer-overlay.d.ts +0 -11
- package/dist/types/task/simple-mode.d.ts +0 -8
- package/src/async/support.ts +0 -5
- package/src/task/simple-mode.ts +0 -27
|
@@ -40,6 +40,7 @@ import { shortenPath } from "../../tools/render-utils";
|
|
|
40
40
|
import { copyToClipboard } from "../../utils/clipboard";
|
|
41
41
|
import { setSessionTerminalTitle } from "../../utils/title-generator";
|
|
42
42
|
import { AgentDashboard } from "../components/agent-dashboard";
|
|
43
|
+
import { AgentHubOverlayComponent } from "../components/agent-hub";
|
|
43
44
|
import { AssistantMessageComponent } from "../components/assistant-message";
|
|
44
45
|
import { CopySelectorComponent } from "../components/copy-selector";
|
|
45
46
|
import { ExtensionDashboard } from "../components/extensions";
|
|
@@ -47,7 +48,6 @@ import { HistorySearchComponent } from "../components/history-search";
|
|
|
47
48
|
import { ModelSelectorComponent } from "../components/model-selector";
|
|
48
49
|
import { OAuthSelectorComponent } from "../components/oauth-selector";
|
|
49
50
|
import { PluginSelectorComponent } from "../components/plugin-selector";
|
|
50
|
-
import { SessionObserverOverlayComponent } from "../components/session-observer-overlay";
|
|
51
51
|
import { SessionSelectorComponent } from "../components/session-selector";
|
|
52
52
|
import { SettingsSelectorComponent } from "../components/settings-selector";
|
|
53
53
|
import { ToolExecutionComponent } from "../components/tool-execution";
|
|
@@ -578,7 +578,7 @@ export class SelectorController {
|
|
|
578
578
|
}
|
|
579
579
|
|
|
580
580
|
this.ctx.chatContainer.clear();
|
|
581
|
-
this.ctx.renderInitialMessages(
|
|
581
|
+
this.ctx.renderInitialMessages({ clearTerminalHistory: true });
|
|
582
582
|
this.ctx.editor.setText(result.selectedText);
|
|
583
583
|
done();
|
|
584
584
|
this.ctx.showStatus("Branched to new session");
|
|
@@ -719,9 +719,10 @@ export class SelectorController {
|
|
|
719
719
|
return;
|
|
720
720
|
}
|
|
721
721
|
|
|
722
|
-
// Update UI —
|
|
722
|
+
// Update UI — rebuild the display transcript for the new leaf (the
|
|
723
|
+
// context from navigateTree is the LLM context, not the transcript).
|
|
723
724
|
this.ctx.chatContainer.clear();
|
|
724
|
-
this.ctx.renderInitialMessages(
|
|
725
|
+
this.ctx.renderInitialMessages({ clearTerminalHistory: true });
|
|
725
726
|
await this.ctx.reloadTodos();
|
|
726
727
|
if (result.editorText && !this.ctx.editor.getText().trim()) {
|
|
727
728
|
this.ctx.editor.setText(result.editorText);
|
|
@@ -846,7 +847,7 @@ export class SelectorController {
|
|
|
846
847
|
this.ctx.statusLine.setSessionStartTime(Date.now());
|
|
847
848
|
this.ctx.updateEditorTopBorder();
|
|
848
849
|
this.ctx.updateEditorBorderColor();
|
|
849
|
-
this.ctx.renderInitialMessages(
|
|
850
|
+
this.ctx.renderInitialMessages({ clearTerminalHistory: true });
|
|
850
851
|
await this.ctx.reloadTodos();
|
|
851
852
|
this.ctx.ui.requestRender(true, { clearScrollback: true });
|
|
852
853
|
return true;
|
|
@@ -871,7 +872,7 @@ export class SelectorController {
|
|
|
871
872
|
|
|
872
873
|
// Clear and re-render the chat
|
|
873
874
|
this.ctx.chatContainer.clear();
|
|
874
|
-
this.ctx.renderInitialMessages(
|
|
875
|
+
this.ctx.renderInitialMessages({ clearTerminalHistory: true });
|
|
875
876
|
await this.ctx.reloadTodos();
|
|
876
877
|
this.ctx.showStatus(movedProject ? `Resumed session in ${shortenPath(newCwd)}` : "Resumed session");
|
|
877
878
|
}
|
|
@@ -1074,31 +1075,34 @@ export class SelectorController {
|
|
|
1074
1075
|
});
|
|
1075
1076
|
}
|
|
1076
1077
|
|
|
1077
|
-
|
|
1078
|
-
const
|
|
1079
|
-
|
|
1078
|
+
showAgentHub(observers: SessionObserverRegistry): void {
|
|
1079
|
+
const hubKeys = [
|
|
1080
|
+
...this.ctx.keybindings.getKeys("app.agents.hub"),
|
|
1081
|
+
...this.ctx.keybindings.getKeys("app.session.observe"),
|
|
1082
|
+
];
|
|
1083
|
+
let hub: AgentHubOverlayComponent | undefined;
|
|
1080
1084
|
let overlayHandle: OverlayHandle | undefined;
|
|
1081
1085
|
|
|
1082
1086
|
const done = () => {
|
|
1083
|
-
|
|
1087
|
+
hub?.dispose();
|
|
1084
1088
|
overlayHandle?.hide();
|
|
1085
1089
|
this.ctx.ui.requestRender();
|
|
1086
1090
|
};
|
|
1087
1091
|
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
this.ctx.ui.requestRender()
|
|
1092
|
+
hub = new AgentHubOverlayComponent({
|
|
1093
|
+
observers,
|
|
1094
|
+
hubKeys,
|
|
1095
|
+
onDone: done,
|
|
1096
|
+
requestRender: () => this.ctx.ui.requestRender(),
|
|
1093
1097
|
});
|
|
1094
1098
|
|
|
1095
|
-
overlayHandle = this.ctx.ui.showOverlay(
|
|
1099
|
+
overlayHandle = this.ctx.ui.showOverlay(hub, {
|
|
1096
1100
|
anchor: "bottom-center",
|
|
1097
1101
|
width: "100%",
|
|
1098
1102
|
maxHeight: "100%",
|
|
1099
1103
|
margin: 0,
|
|
1100
1104
|
});
|
|
1101
|
-
this.ctx.ui.setFocus(
|
|
1105
|
+
this.ctx.ui.setFocus(hub);
|
|
1102
1106
|
this.ctx.ui.requestRender();
|
|
1103
1107
|
}
|
|
1104
1108
|
}
|
package/src/modes/index.ts
CHANGED
|
@@ -8,27 +8,9 @@ import { postmortem } from "@oh-my-pi/pi-utils";
|
|
|
8
8
|
* barrel does not pull print, RPC server, or ACP server mode into the normal
|
|
9
9
|
* TUI graph.
|
|
10
10
|
*/
|
|
11
|
-
export
|
|
12
|
-
export
|
|
13
|
-
|
|
14
|
-
type ModelInfo,
|
|
15
|
-
RpcClient,
|
|
16
|
-
type RpcClientCustomTool,
|
|
17
|
-
type RpcClientOptions,
|
|
18
|
-
type RpcClientToolContext,
|
|
19
|
-
type RpcClientToolResult,
|
|
20
|
-
type RpcEventListener,
|
|
21
|
-
} from "./rpc/rpc-client";
|
|
22
|
-
export type {
|
|
23
|
-
RpcCommand,
|
|
24
|
-
RpcHostToolCallRequest,
|
|
25
|
-
RpcHostToolCancelRequest,
|
|
26
|
-
RpcHostToolDefinition,
|
|
27
|
-
RpcHostToolResult,
|
|
28
|
-
RpcHostToolUpdate,
|
|
29
|
-
RpcResponse,
|
|
30
|
-
RpcSessionState,
|
|
31
|
-
} from "./rpc/rpc-types";
|
|
11
|
+
export * from "./interactive-mode";
|
|
12
|
+
export * from "./rpc/rpc-client";
|
|
13
|
+
export * from "./rpc/rpc-types";
|
|
32
14
|
|
|
33
15
|
postmortem.register("terminal-restore", () => {
|
|
34
16
|
emergencyTerminalRestore();
|
|
@@ -59,6 +59,7 @@ import { BUILTIN_SLASH_COMMANDS, loadSlashCommands } from "../extensibility/slas
|
|
|
59
59
|
import type { Goal, GoalModeState } from "../goals/state";
|
|
60
60
|
import { resolveLocalUrlToPath } from "../internal-urls";
|
|
61
61
|
import { LSP_STARTUP_EVENT_CHANNEL, type LspStartupEvent } from "../lsp/startup-events";
|
|
62
|
+
import type { MCPManager } from "../mcp";
|
|
62
63
|
import {
|
|
63
64
|
humanizePlanTitle,
|
|
64
65
|
type PlanApprovalDetails,
|
|
@@ -74,8 +75,10 @@ import { HistoryStorage } from "../session/history-storage";
|
|
|
74
75
|
import type { SessionContext, SessionManager } from "../session/session-manager";
|
|
75
76
|
import { getRecentSessions } from "../session/session-manager";
|
|
76
77
|
import type { ShakeMode } from "../session/shake-types";
|
|
78
|
+
import { BUILTIN_SLASH_COMMAND_RESERVED_NAMES } from "../slash-commands/builtin-registry";
|
|
77
79
|
import { formatDuration } from "../slash-commands/helpers/format";
|
|
78
80
|
import { STTController, type SttState } from "../stt";
|
|
81
|
+
import { discoverTitleSystemPromptFile, resolvePromptInput } from "../system-prompt";
|
|
79
82
|
import type { LspStartupServerInfo } from "../tools";
|
|
80
83
|
import { normalizeLocalScheme } from "../tools/path-utils";
|
|
81
84
|
import { setAutoQaConsentHandler } from "../tools/report-tool-issue";
|
|
@@ -123,6 +126,7 @@ import {
|
|
|
123
126
|
} from "./loop-limit";
|
|
124
127
|
import { OAuthManualInputManager } from "./oauth-manual-input";
|
|
125
128
|
import { SessionObserverRegistry } from "./session-observer-registry";
|
|
129
|
+
import { runProviderSetupWizard } from "./setup-wizard/lazy";
|
|
126
130
|
import { interruptHint } from "./shared";
|
|
127
131
|
import { type ShimmerPalette, shimmerEnabled, shimmerSegments, shimmerText } from "./theme/shimmer";
|
|
128
132
|
import type { Theme } from "./theme/theme";
|
|
@@ -260,6 +264,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
260
264
|
keybindings: KeybindingsManager;
|
|
261
265
|
agent: Agent;
|
|
262
266
|
historyStorage?: HistoryStorage;
|
|
267
|
+
titleSystemPrompt?: string;
|
|
263
268
|
|
|
264
269
|
ui: TUI;
|
|
265
270
|
chatContainer: TranscriptContainer;
|
|
@@ -322,6 +327,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
322
327
|
#pendingSubmissionDispose: (() => void) | undefined;
|
|
323
328
|
lastSigintTime = 0;
|
|
324
329
|
lastEscapeTime = 0;
|
|
330
|
+
lastLeftTapTime = 0;
|
|
325
331
|
shutdownRequested = false;
|
|
326
332
|
#isShuttingDown = false;
|
|
327
333
|
hookSelector: HookSelectorComponent | undefined = undefined;
|
|
@@ -349,7 +355,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
349
355
|
#planReviewOverlay: PlanReviewOverlay | undefined;
|
|
350
356
|
#planReviewOverlayHandle: OverlayHandle | undefined;
|
|
351
357
|
readonly lspServers: LspStartupServerInfo[] | undefined = undefined;
|
|
352
|
-
mcpManager?:
|
|
358
|
+
mcpManager?: MCPManager;
|
|
353
359
|
readonly #toolUiContextSetter: (uiContext: ExtensionUIContext, hasUI: boolean) => void;
|
|
354
360
|
|
|
355
361
|
readonly #btwController: BtwController;
|
|
@@ -380,8 +386,9 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
380
386
|
changelogMarkdown: string | undefined = undefined,
|
|
381
387
|
setToolUIContext: (uiContext: ExtensionUIContext, hasUI: boolean) => void = () => {},
|
|
382
388
|
lspServers: LspStartupServerInfo[] | undefined = undefined,
|
|
383
|
-
mcpManager?:
|
|
389
|
+
mcpManager?: MCPManager,
|
|
384
390
|
eventBus?: EventBus,
|
|
391
|
+
titleSystemPrompt?: string,
|
|
385
392
|
) {
|
|
386
393
|
this.session = session;
|
|
387
394
|
this.sessionManager = session.sessionManager;
|
|
@@ -394,6 +401,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
394
401
|
this.lspServers = lspServers;
|
|
395
402
|
this.mcpManager = mcpManager;
|
|
396
403
|
this.#eventBus = eventBus;
|
|
404
|
+
this.titleSystemPrompt = titleSystemPrompt;
|
|
397
405
|
if (eventBus) {
|
|
398
406
|
this.#eventBusUnsubscribers.push(
|
|
399
407
|
eventBus.on(LSP_STARTUP_EVENT_CHANNEL, data => {
|
|
@@ -447,9 +455,8 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
447
455
|
|
|
448
456
|
this.hideThinkingBlock = settings.get("hideThinkingBlock");
|
|
449
457
|
|
|
450
|
-
const builtinCommandNames = new Set(BUILTIN_SLASH_COMMANDS.map(c => c.name));
|
|
451
458
|
const hookCommands: SlashCommand[] = (
|
|
452
|
-
this.session.extensionRunner?.getRegisteredCommands(
|
|
459
|
+
this.session.extensionRunner?.getRegisteredCommands(BUILTIN_SLASH_COMMAND_RESERVED_NAMES) ?? []
|
|
453
460
|
).map(cmd => ({
|
|
454
461
|
name: cmd.name,
|
|
455
462
|
description: cmd.description ?? "(hook command)",
|
|
@@ -679,6 +686,13 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
679
686
|
this.updateEditorTopBorder();
|
|
680
687
|
}
|
|
681
688
|
|
|
689
|
+
/** Reload the title-generation system prompt override for the provided working directory. */
|
|
690
|
+
async refreshTitleSystemPrompt(cwd?: string): Promise<void> {
|
|
691
|
+
const basePath = cwd ?? this.sessionManager.getCwd();
|
|
692
|
+
const titleSystemPromptSource = discoverTitleSystemPromptFile(basePath);
|
|
693
|
+
this.titleSystemPrompt = await resolvePromptInput(titleSystemPromptSource, "title system prompt");
|
|
694
|
+
}
|
|
695
|
+
|
|
682
696
|
/** Reload slash commands and autocomplete for the provided working directory. */
|
|
683
697
|
async refreshSlashCommandState(cwd?: string): Promise<void> {
|
|
684
698
|
const basePath = cwd ?? this.sessionManager.getCwd();
|
|
@@ -713,6 +727,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
713
727
|
// Re-warm plugin roots, capabilities, slash commands, and the ssh tool so
|
|
714
728
|
// the next prompt sees everything scoped to the new project directory.
|
|
715
729
|
clearClaudePluginRootsCache();
|
|
730
|
+
await this.refreshTitleSystemPrompt(newCwd);
|
|
716
731
|
resetCapabilities();
|
|
717
732
|
await this.refreshSlashCommandState(newCwd);
|
|
718
733
|
await this.session.refreshSshTool({ activateIfAvailable: true });
|
|
@@ -1074,7 +1089,9 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
1074
1089
|
|
|
1075
1090
|
rebuildChatFromMessages(): void {
|
|
1076
1091
|
this.chatContainer.clear();
|
|
1077
|
-
|
|
1092
|
+
// Full-history transcript: compactions render as inline dividers instead
|
|
1093
|
+
// of restarting the visible conversation (the LLM context still resets).
|
|
1094
|
+
const context = this.session.buildTranscriptSessionContext();
|
|
1078
1095
|
this.renderSessionContext(context);
|
|
1079
1096
|
}
|
|
1080
1097
|
|
|
@@ -1694,6 +1711,15 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
1694
1711
|
}
|
|
1695
1712
|
}
|
|
1696
1713
|
|
|
1714
|
+
async #hasPlanModeDraftContent(planFilePath: string): Promise<boolean> {
|
|
1715
|
+
const candidates = new Set<string>([planFilePath, ...(await this.#listLocalPlanFiles())]);
|
|
1716
|
+
for (const candidate of candidates) {
|
|
1717
|
+
const content = await this.#readPlanFile(candidate);
|
|
1718
|
+
if (content !== null && content.trim().length > 0) return true;
|
|
1719
|
+
}
|
|
1720
|
+
return false;
|
|
1721
|
+
}
|
|
1722
|
+
|
|
1697
1723
|
/** `local://` URLs of plan files in the session-local root, newest first.
|
|
1698
1724
|
* A fallback for `resolveApprovedPlan` when the agent dropped `extra.title`,
|
|
1699
1725
|
* so the plan it wrote is still found by scanning recent `*-plan.md` files. */
|
|
@@ -1998,11 +2024,14 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
1998
2024
|
return;
|
|
1999
2025
|
}
|
|
2000
2026
|
if (this.planModeEnabled) {
|
|
2001
|
-
const
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2027
|
+
const planFilePath = this.planModePlanFilePath ?? (await this.#getPlanFilePath());
|
|
2028
|
+
if (await this.#hasPlanModeDraftContent(planFilePath)) {
|
|
2029
|
+
const confirmed = await this.showHookConfirm(
|
|
2030
|
+
"Exit plan mode?",
|
|
2031
|
+
"This exits plan mode without approving a plan.",
|
|
2032
|
+
);
|
|
2033
|
+
if (!confirmed) return;
|
|
2034
|
+
}
|
|
2006
2035
|
await this.#exitPlanMode({ paused: true });
|
|
2007
2036
|
return;
|
|
2008
2037
|
}
|
|
@@ -2854,11 +2883,8 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2854
2883
|
this.#uiHelpers.renderSessionContext(sessionContext, options);
|
|
2855
2884
|
}
|
|
2856
2885
|
|
|
2857
|
-
renderInitialMessages(
|
|
2858
|
-
|
|
2859
|
-
options?: { preserveExistingChat?: boolean; clearTerminalHistory?: boolean },
|
|
2860
|
-
): void {
|
|
2861
|
-
this.#uiHelpers.renderInitialMessages(prebuiltContext, options);
|
|
2886
|
+
renderInitialMessages(options?: { preserveExistingChat?: boolean; clearTerminalHistory?: boolean }): void {
|
|
2887
|
+
this.#uiHelpers.renderInitialMessages(options);
|
|
2862
2888
|
}
|
|
2863
2889
|
|
|
2864
2890
|
getUserMessageText(message: Message): string {
|
|
@@ -3042,13 +3068,8 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
3042
3068
|
await this.#selectorController.showDebugSelector();
|
|
3043
3069
|
}
|
|
3044
3070
|
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
if (sessions.length <= 1) {
|
|
3048
|
-
this.showStatus("No active subagent sessions");
|
|
3049
|
-
return;
|
|
3050
|
-
}
|
|
3051
|
-
this.#selectorController.showSessionObserver(this.#observerRegistry);
|
|
3071
|
+
showAgentHub(): void {
|
|
3072
|
+
this.#selectorController.showAgentHub(this.#observerRegistry);
|
|
3052
3073
|
}
|
|
3053
3074
|
|
|
3054
3075
|
resetObserverRegistry(): void {
|
|
@@ -3153,6 +3174,10 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
3153
3174
|
return this.#selectorController.showOAuthSelector(mode, providerId);
|
|
3154
3175
|
}
|
|
3155
3176
|
|
|
3177
|
+
showProviderSetup(): Promise<void> {
|
|
3178
|
+
return runProviderSetupWizard(this);
|
|
3179
|
+
}
|
|
3180
|
+
|
|
3156
3181
|
showHookConfirm(title: string, message: string): Promise<boolean> {
|
|
3157
3182
|
return this.#extensionUiController.showHookConfirm(title, message);
|
|
3158
3183
|
}
|
|
@@ -3,6 +3,10 @@ type PendingInput = {
|
|
|
3
3
|
resolve: (value: string) => void;
|
|
4
4
|
reject: (error: Error) => void;
|
|
5
5
|
};
|
|
6
|
+
type ClaimedInput = {
|
|
7
|
+
promise: Promise<string>;
|
|
8
|
+
clear: (reason?: string) => void;
|
|
9
|
+
};
|
|
6
10
|
|
|
7
11
|
export class OAuthManualInputManager {
|
|
8
12
|
#pending?: PendingInput;
|
|
@@ -12,9 +16,27 @@ export class OAuthManualInputManager {
|
|
|
12
16
|
this.clear("Manual OAuth input superseded by a new login");
|
|
13
17
|
}
|
|
14
18
|
|
|
15
|
-
const
|
|
16
|
-
this.#pending =
|
|
17
|
-
return promise;
|
|
19
|
+
const pending = this.#createPending(providerId);
|
|
20
|
+
this.#pending = pending;
|
|
21
|
+
return pending.promise;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
tryWaitForInput(providerId: string): Promise<string> | undefined {
|
|
25
|
+
if (this.#pending) return undefined;
|
|
26
|
+
return this.waitForInput(providerId);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
tryClaimInput(providerId: string): ClaimedInput | undefined {
|
|
30
|
+
if (this.#pending) return undefined;
|
|
31
|
+
const pending = this.#createPending(providerId);
|
|
32
|
+
this.#pending = pending;
|
|
33
|
+
return {
|
|
34
|
+
promise: pending.promise,
|
|
35
|
+
clear: (reason?: string) => {
|
|
36
|
+
if (this.#pending !== pending) return;
|
|
37
|
+
this.clear(reason);
|
|
38
|
+
},
|
|
39
|
+
};
|
|
18
40
|
}
|
|
19
41
|
|
|
20
42
|
submit(input: string): boolean {
|
|
@@ -39,4 +61,9 @@ export class OAuthManualInputManager {
|
|
|
39
61
|
get pendingProviderId(): string | undefined {
|
|
40
62
|
return this.#pending?.providerId;
|
|
41
63
|
}
|
|
64
|
+
|
|
65
|
+
#createPending(providerId: string): PendingInput & { promise: Promise<string> } {
|
|
66
|
+
const { promise, resolve, reject } = Promise.withResolvers<string>();
|
|
67
|
+
return { providerId, resolve, reject, promise };
|
|
68
|
+
}
|
|
42
69
|
}
|
|
@@ -9,8 +9,9 @@ import type { AgentEvent, AgentMessage, AgentToolResult, ThinkingLevel } from "@
|
|
|
9
9
|
import type { CompactionResult } from "@oh-my-pi/pi-agent-core/compaction";
|
|
10
10
|
import type { ImageContent, Model } from "@oh-my-pi/pi-ai";
|
|
11
11
|
import { isRecord, ptree, readJsonl } from "@oh-my-pi/pi-utils";
|
|
12
|
+
import type { FileSink } from "bun";
|
|
12
13
|
import type { BashResult } from "../../exec/bash-executor";
|
|
13
|
-
import type { SessionStats } from "../../session/agent-session";
|
|
14
|
+
import type { AgentSessionEvent, SessionStats } from "../../session/agent-session";
|
|
14
15
|
import type {
|
|
15
16
|
RpcCommand,
|
|
16
17
|
RpcExtensionUIRequest,
|
|
@@ -22,6 +23,12 @@ import type {
|
|
|
22
23
|
RpcHostToolUpdate,
|
|
23
24
|
RpcResponse,
|
|
24
25
|
RpcSessionState,
|
|
26
|
+
RpcSubagentEventFrame,
|
|
27
|
+
RpcSubagentLifecycleFrame,
|
|
28
|
+
RpcSubagentMessagesResult,
|
|
29
|
+
RpcSubagentProgressFrame,
|
|
30
|
+
RpcSubagentSnapshot,
|
|
31
|
+
RpcSubagentSubscriptionLevel,
|
|
25
32
|
} from "./rpc-types";
|
|
26
33
|
|
|
27
34
|
/** Distributive Omit that works with union types */
|
|
@@ -52,6 +59,10 @@ export interface RpcClientOptions {
|
|
|
52
59
|
export type ModelInfo = Pick<Model, "provider" | "id" | "contextWindow" | "reasoning" | "thinking">;
|
|
53
60
|
|
|
54
61
|
export type RpcEventListener = (event: AgentEvent) => void;
|
|
62
|
+
export type RpcSessionEventListener = (event: AgentSessionEvent) => void;
|
|
63
|
+
export type RpcSubagentLifecycleListener = (payload: RpcSubagentLifecycleFrame["payload"]) => void;
|
|
64
|
+
export type RpcSubagentProgressListener = (payload: RpcSubagentProgressFrame["payload"]) => void;
|
|
65
|
+
export type RpcSubagentEventListener = (payload: RpcSubagentEventFrame["payload"]) => void;
|
|
55
66
|
|
|
56
67
|
export interface RpcClientToolContext<TDetails = unknown> {
|
|
57
68
|
toolCallId: string;
|
|
@@ -92,6 +103,23 @@ const agentEventTypes = new Set<AgentEvent["type"]>([
|
|
|
92
103
|
"tool_execution_end",
|
|
93
104
|
]);
|
|
94
105
|
|
|
106
|
+
const sessionEventTypes = new Set<AgentSessionEvent["type"]>([
|
|
107
|
+
...agentEventTypes,
|
|
108
|
+
"auto_compaction_start",
|
|
109
|
+
"auto_compaction_end",
|
|
110
|
+
"auto_retry_start",
|
|
111
|
+
"auto_retry_end",
|
|
112
|
+
"retry_fallback_applied",
|
|
113
|
+
"retry_fallback_succeeded",
|
|
114
|
+
"ttsr_triggered",
|
|
115
|
+
"todo_reminder",
|
|
116
|
+
"todo_auto_clear",
|
|
117
|
+
"irc_message",
|
|
118
|
+
"notice",
|
|
119
|
+
"thinking_level_changed",
|
|
120
|
+
"goal_updated",
|
|
121
|
+
]);
|
|
122
|
+
|
|
95
123
|
function isRpcResponse(value: unknown): value is RpcResponse {
|
|
96
124
|
if (!isRecord(value)) return false;
|
|
97
125
|
if (value.type !== "response") return false;
|
|
@@ -111,6 +139,28 @@ function isAgentEvent(value: unknown): value is AgentEvent {
|
|
|
111
139
|
return agentEventTypes.has(type as AgentEvent["type"]);
|
|
112
140
|
}
|
|
113
141
|
|
|
142
|
+
function isAgentSessionEvent(value: unknown): value is AgentSessionEvent {
|
|
143
|
+
if (!isRecord(value)) return false;
|
|
144
|
+
const type = value.type;
|
|
145
|
+
if (typeof type !== "string") return false;
|
|
146
|
+
return sessionEventTypes.has(type as AgentSessionEvent["type"]);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function isRpcSubagentLifecycleFrame(value: unknown): value is RpcSubagentLifecycleFrame {
|
|
150
|
+
if (!isRecord(value)) return false;
|
|
151
|
+
return value.type === "subagent_lifecycle" && isRecord(value.payload);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function isRpcSubagentProgressFrame(value: unknown): value is RpcSubagentProgressFrame {
|
|
155
|
+
if (!isRecord(value)) return false;
|
|
156
|
+
return value.type === "subagent_progress" && isRecord(value.payload);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function isRpcSubagentEventFrame(value: unknown): value is RpcSubagentEventFrame {
|
|
160
|
+
if (!isRecord(value)) return false;
|
|
161
|
+
return value.type === "subagent_event" && isRecord(value.payload);
|
|
162
|
+
}
|
|
163
|
+
|
|
114
164
|
function isRpcHostToolCallRequest(value: unknown): value is RpcHostToolCallRequest {
|
|
115
165
|
if (!isRecord(value)) return false;
|
|
116
166
|
return (
|
|
@@ -148,6 +198,10 @@ function normalizeToolResult<TDetails>(result: RpcClientToolResult<TDetails>): A
|
|
|
148
198
|
export class RpcClient {
|
|
149
199
|
#process: ptree.ChildProcess | null = null;
|
|
150
200
|
#eventListeners: RpcEventListener[] = [];
|
|
201
|
+
#sessionEventListeners: RpcSessionEventListener[] = [];
|
|
202
|
+
#subagentLifecycleListeners = new Set<RpcSubagentLifecycleListener>();
|
|
203
|
+
#subagentProgressListeners = new Set<RpcSubagentProgressListener>();
|
|
204
|
+
#subagentEventListeners = new Set<RpcSubagentEventListener>();
|
|
151
205
|
#pendingRequests: Map<string, { resolve: (response: RpcResponse) => void; reject: (error: Error) => void }> =
|
|
152
206
|
new Map();
|
|
153
207
|
#customTools: RpcClientCustomTool[] = [];
|
|
@@ -286,6 +340,43 @@ export class RpcClient {
|
|
|
286
340
|
};
|
|
287
341
|
}
|
|
288
342
|
|
|
343
|
+
/**
|
|
344
|
+
* Subscribe to all top-level session events, including non-core session state events.
|
|
345
|
+
*/
|
|
346
|
+
onSessionEvent(listener: RpcSessionEventListener): () => void {
|
|
347
|
+
this.#sessionEventListeners.push(listener);
|
|
348
|
+
return () => {
|
|
349
|
+
const index = this.#sessionEventListeners.indexOf(listener);
|
|
350
|
+
if (index !== -1) {
|
|
351
|
+
this.#sessionEventListeners.splice(index, 1);
|
|
352
|
+
}
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Subscribe to subagent lifecycle frames after setSubagentSubscription("progress" | "events").
|
|
358
|
+
*/
|
|
359
|
+
onSubagentLifecycle(listener: RpcSubagentLifecycleListener): () => void {
|
|
360
|
+
this.#subagentLifecycleListeners.add(listener);
|
|
361
|
+
return () => this.#subagentLifecycleListeners.delete(listener);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Subscribe to aggregated subagent progress frames after setSubagentSubscription("progress" | "events").
|
|
366
|
+
*/
|
|
367
|
+
onSubagentProgress(listener: RpcSubagentProgressListener): () => void {
|
|
368
|
+
this.#subagentProgressListeners.add(listener);
|
|
369
|
+
return () => this.#subagentProgressListeners.delete(listener);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Subscribe to raw subagent session events. Call setSubagentSubscription(\"events\") to enable them server-side.
|
|
374
|
+
*/
|
|
375
|
+
onSubagentEvent(listener: RpcSubagentEventListener): () => void {
|
|
376
|
+
this.#subagentEventListeners.add(listener);
|
|
377
|
+
return () => this.#subagentEventListeners.delete(listener);
|
|
378
|
+
}
|
|
379
|
+
|
|
289
380
|
/**
|
|
290
381
|
* Get collected stderr output (useful for debugging).
|
|
291
382
|
*/
|
|
@@ -358,6 +449,40 @@ export class RpcClient {
|
|
|
358
449
|
return this.#getData(response);
|
|
359
450
|
}
|
|
360
451
|
|
|
452
|
+
/**
|
|
453
|
+
* Configure subagent frames emitted by the RPC server. Servers default to "off".
|
|
454
|
+
* "progress" emits lifecycle/progress frames; "events" additionally emits raw subagent session events.
|
|
455
|
+
*/
|
|
456
|
+
async setSubagentSubscription(level: RpcSubagentSubscriptionLevel): Promise<RpcSubagentSubscriptionLevel> {
|
|
457
|
+
const response = await this.#send({ type: "set_subagent_subscription", level });
|
|
458
|
+
return this.#getData<{ level: RpcSubagentSubscriptionLevel }>(response).level;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
/**
|
|
462
|
+
* Return the RPC server's current subagent snapshot.
|
|
463
|
+
*/
|
|
464
|
+
async getSubagents(): Promise<RpcSubagentSnapshot[]> {
|
|
465
|
+
const response = await this.#send({ type: "get_subagents" });
|
|
466
|
+
return this.#getData<{ subagents: RpcSubagentSnapshot[] }>(response).subagents;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
/**
|
|
470
|
+
* Read persisted transcript entries for a tracked subagent session.
|
|
471
|
+
*/
|
|
472
|
+
async getSubagentMessages(selector: {
|
|
473
|
+
subagentId?: string;
|
|
474
|
+
sessionFile?: string;
|
|
475
|
+
fromByte?: number;
|
|
476
|
+
}): Promise<RpcSubagentMessagesResult> {
|
|
477
|
+
const response = await this.#send({
|
|
478
|
+
type: "get_subagent_messages",
|
|
479
|
+
subagentId: selector.subagentId,
|
|
480
|
+
sessionFile: selector.sessionFile,
|
|
481
|
+
fromByte: selector.fromByte,
|
|
482
|
+
});
|
|
483
|
+
return this.#getData<RpcSubagentMessagesResult>(response);
|
|
484
|
+
}
|
|
485
|
+
|
|
361
486
|
/**
|
|
362
487
|
* Set model by provider and ID.
|
|
363
488
|
*/
|
|
@@ -679,9 +804,35 @@ export class RpcClient {
|
|
|
679
804
|
return;
|
|
680
805
|
}
|
|
681
806
|
|
|
807
|
+
if (isRpcSubagentLifecycleFrame(data)) {
|
|
808
|
+
for (const listener of this.#subagentLifecycleListeners) {
|
|
809
|
+
listener(data.payload);
|
|
810
|
+
}
|
|
811
|
+
return;
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
if (isRpcSubagentProgressFrame(data)) {
|
|
815
|
+
for (const listener of this.#subagentProgressListeners) {
|
|
816
|
+
listener(data.payload);
|
|
817
|
+
}
|
|
818
|
+
return;
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
if (isRpcSubagentEventFrame(data)) {
|
|
822
|
+
for (const listener of this.#subagentEventListeners) {
|
|
823
|
+
listener(data.payload);
|
|
824
|
+
}
|
|
825
|
+
return;
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
if (!isAgentSessionEvent(data)) return;
|
|
829
|
+
|
|
830
|
+
for (const listener of this.#sessionEventListeners) {
|
|
831
|
+
listener(data);
|
|
832
|
+
}
|
|
833
|
+
|
|
682
834
|
if (!isAgentEvent(data)) return;
|
|
683
835
|
|
|
684
|
-
// Otherwise it's an event
|
|
685
836
|
for (const listener of this.#eventListeners) {
|
|
686
837
|
listener(data);
|
|
687
838
|
}
|
|
@@ -789,7 +940,7 @@ export class RpcClient {
|
|
|
789
940
|
if (!this.#process?.stdin) {
|
|
790
941
|
throw new Error("Client not started");
|
|
791
942
|
}
|
|
792
|
-
const stdin = this.#process.stdin as
|
|
943
|
+
const stdin = this.#process.stdin as FileSink;
|
|
793
944
|
stdin.write(`${JSON.stringify(frame)}\n`);
|
|
794
945
|
const flushResult = stdin.flush();
|
|
795
946
|
if (isPromise(flushResult)) {
|