fix(coding-agent): restore /import error flow and document throws

This commit is contained in:
Mario Zechner
2026-04-17 00:59:53 +02:00
parent 3ba0d85fa2
commit 36bffc1d13
3 changed files with 30 additions and 17 deletions

View File

@@ -7,6 +7,7 @@
- Fixed missing root exports for `RpcClient` and RPC protocol types from `@mariozechner/pi-coding-agent`, so ESM consumers can import them from the main package entrypoint ([#3275](https://github.com/badlogic/pi-mono/issues/3275)) - Fixed missing root exports for `RpcClient` and RPC protocol types from `@mariozechner/pi-coding-agent`, so ESM consumers can import them from the main package entrypoint ([#3275](https://github.com/badlogic/pi-mono/issues/3275))
- Fixed Bun binary asset path resolution to honor `PI_PACKAGE_DIR` for built-in themes, HTML export templates, and interactive bundled assets ([#3074](https://github.com/badlogic/pi-mono/issues/3074)) - Fixed Bun binary asset path resolution to honor `PI_PACKAGE_DIR` for built-in themes, HTML export templates, and interactive bundled assets ([#3074](https://github.com/badlogic/pi-mono/issues/3074))
- Fixed user-message turn spacing in interactive mode by restoring an inter-message spacer before user turns (except the first user message), preventing assistant and user blocks from rendering flush together. - Fixed user-message turn spacing in interactive mode by restoring an inter-message spacer before user turns (except the first user message), preventing assistant and user blocks from rendering flush together.
- Fixed interactive `/import` handling to route missing JSONL files through the non-fatal `SessionImportFileNotFoundError` path, and documented the `importFromJsonl()` exceptions (`SessionImportFileNotFoundError`, `MissingSessionCwdError`).
## [0.67.6] - 2026-04-16 ## [0.67.6] - 2026-04-16

View File

@@ -33,6 +33,9 @@ export type CreateAgentSessionRuntimeFactory = (options: {
sessionStartEvent?: SessionStartEvent; sessionStartEvent?: SessionStartEvent;
}) => Promise<CreateAgentSessionRuntimeResult>; }) => Promise<CreateAgentSessionRuntimeResult>;
/**
* Thrown when /import references a JSONL file path that does not exist.
*/
export class SessionImportFileNotFoundError extends Error { export class SessionImportFileNotFoundError extends Error {
readonly filePath: string; readonly filePath: string;
@@ -258,6 +261,13 @@ export class AgentSessionRuntime {
return { cancelled: false, selectedText }; return { cancelled: false, selectedText };
} }
/**
* Import a session JSONL file and switch runtime state to the imported session.
*
* @returns `{ cancelled: true }` when cancelled by `session_before_switch`, otherwise `{ cancelled: false }`.
* @throws {SessionImportFileNotFoundError} When the input path does not exist.
* @throws {MissingSessionCwdError} When the imported session cwd cannot be resolved and no override is provided.
*/
async importFromJsonl(inputPath: string, cwdOverride?: string): Promise<{ cancelled: boolean }> { async importFromJsonl(inputPath: string, cwdOverride?: string): Promise<{ cancelled: boolean }> {
const resolvedPath = resolve(inputPath); const resolvedPath = resolve(inputPath);
if (!existsSync(resolvedPath)) { if (!existsSync(resolvedPath)) {

View File

@@ -47,7 +47,7 @@ import {
VERSION, VERSION,
} from "../../config.js"; } from "../../config.js";
import { type AgentSession, type AgentSessionEvent, parseSkillBlock } from "../../core/agent-session.js"; import { type AgentSession, type AgentSessionEvent, parseSkillBlock } from "../../core/agent-session.js";
import type { AgentSessionRuntime } from "../../core/agent-session-runtime.js"; import { type AgentSessionRuntime, SessionImportFileNotFoundError } from "../../core/agent-session-runtime.js";
import type { import type {
ExtensionContext, ExtensionContext,
ExtensionRunner, ExtensionRunner,
@@ -4417,20 +4417,6 @@ export class InteractiveMode {
return; return;
} }
const handleImportResult = async (result: "ok" | "cancelled" | "not_found"): Promise<void> => {
if (result === "cancelled") {
this.showStatus("Import cancelled");
return;
}
if (result === "not_found") {
this.showError(`Failed to import session: File not found: ${path.resolve(inputPath)}`);
return;
}
await this.handleRuntimeSessionChange();
this.renderCurrentSessionState();
this.showStatus(`Session imported from: ${inputPath}`);
};
try { try {
if (this.loadingAnimation) { if (this.loadingAnimation) {
this.loadingAnimation.stop(); this.loadingAnimation.stop();
@@ -4438,7 +4424,13 @@ export class InteractiveMode {
} }
this.statusContainer.clear(); this.statusContainer.clear();
const result = await this.runtimeHost.importFromJsonl(inputPath); const result = await this.runtimeHost.importFromJsonl(inputPath);
await handleImportResult(result); if (result.cancelled) {
this.showStatus("Import cancelled");
return;
}
await this.handleRuntimeSessionChange();
this.renderCurrentSessionState();
this.showStatus(`Session imported from: ${inputPath}`);
} catch (error: unknown) { } catch (error: unknown) {
if (error instanceof MissingSessionCwdError) { if (error instanceof MissingSessionCwdError) {
const selectedCwd = await this.promptForMissingSessionCwd(error); const selectedCwd = await this.promptForMissingSessionCwd(error);
@@ -4447,7 +4439,17 @@ export class InteractiveMode {
return; return;
} }
const result = await this.runtimeHost.importFromJsonl(inputPath, selectedCwd); const result = await this.runtimeHost.importFromJsonl(inputPath, selectedCwd);
await handleImportResult(result); if (result.cancelled) {
this.showStatus("Import cancelled");
return;
}
await this.handleRuntimeSessionChange();
this.renderCurrentSessionState();
this.showStatus(`Session imported from: ${inputPath}`);
return;
}
if (error instanceof SessionImportFileNotFoundError) {
this.showError(`Failed to import session: ${error.message}`);
return; return;
} }
await this.handleFatalRuntimeError("Failed to import session", error); await this.handleFatalRuntimeError("Failed to import session", error);