@mariozechner/pi-coding-agent 0.64.0 → 0.65.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.
Files changed (119) hide show
  1. package/CHANGELOG.md +96 -0
  2. package/README.md +11 -5
  3. package/dist/cli/args.d.ts +7 -4
  4. package/dist/cli/args.d.ts.map +1 -1
  5. package/dist/cli/args.js +37 -15
  6. package/dist/cli/args.js.map +1 -1
  7. package/dist/core/agent-session-runtime.d.ts +83 -0
  8. package/dist/core/agent-session-runtime.d.ts.map +1 -0
  9. package/dist/core/agent-session-runtime.js +232 -0
  10. package/dist/core/agent-session-runtime.js.map +1 -0
  11. package/dist/core/agent-session-services.d.ts +86 -0
  12. package/dist/core/agent-session-services.d.ts.map +1 -0
  13. package/dist/core/agent-session-services.js +116 -0
  14. package/dist/core/agent-session-services.js.map +1 -0
  15. package/dist/core/agent-session.d.ts +5 -42
  16. package/dist/core/agent-session.d.ts.map +1 -1
  17. package/dist/core/agent-session.js +46 -237
  18. package/dist/core/agent-session.js.map +1 -1
  19. package/dist/core/export-html/tool-renderer.d.ts +2 -0
  20. package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
  21. package/dist/core/export-html/tool-renderer.js +2 -2
  22. package/dist/core/export-html/tool-renderer.js.map +1 -1
  23. package/dist/core/extensions/index.d.ts +2 -2
  24. package/dist/core/extensions/index.d.ts.map +1 -1
  25. package/dist/core/extensions/index.js +1 -1
  26. package/dist/core/extensions/index.js.map +1 -1
  27. package/dist/core/extensions/types.d.ts +16 -28
  28. package/dist/core/extensions/types.d.ts.map +1 -1
  29. package/dist/core/extensions/types.js +10 -0
  30. package/dist/core/extensions/types.js.map +1 -1
  31. package/dist/core/footer-data-provider.d.ts +5 -1
  32. package/dist/core/footer-data-provider.d.ts.map +1 -1
  33. package/dist/core/footer-data-provider.js +70 -8
  34. package/dist/core/footer-data-provider.js.map +1 -1
  35. package/dist/core/index.d.ts +3 -1
  36. package/dist/core/index.d.ts.map +1 -1
  37. package/dist/core/index.js +3 -1
  38. package/dist/core/index.js.map +1 -1
  39. package/dist/core/keybindings.d.ts +14 -1
  40. package/dist/core/keybindings.d.ts.map +1 -1
  41. package/dist/core/keybindings.js +13 -14
  42. package/dist/core/keybindings.js.map +1 -1
  43. package/dist/core/package-manager.d.ts +20 -0
  44. package/dist/core/package-manager.d.ts.map +1 -1
  45. package/dist/core/package-manager.js +32 -0
  46. package/dist/core/package-manager.js.map +1 -1
  47. package/dist/core/resource-loader.d.ts.map +1 -1
  48. package/dist/core/resource-loader.js +21 -0
  49. package/dist/core/resource-loader.js.map +1 -1
  50. package/dist/core/sdk.d.ts +4 -1
  51. package/dist/core/sdk.d.ts.map +1 -1
  52. package/dist/core/sdk.js +4 -1
  53. package/dist/core/sdk.js.map +1 -1
  54. package/dist/core/session-manager.d.ts +3 -0
  55. package/dist/core/session-manager.d.ts.map +1 -1
  56. package/dist/core/session-manager.js +13 -6
  57. package/dist/core/session-manager.js.map +1 -1
  58. package/dist/core/settings-manager.d.ts +1 -1
  59. package/dist/core/settings-manager.d.ts.map +1 -1
  60. package/dist/core/settings-manager.js +2 -1
  61. package/dist/core/settings-manager.js.map +1 -1
  62. package/dist/index.d.ts +3 -3
  63. package/dist/index.d.ts.map +1 -1
  64. package/dist/index.js +3 -3
  65. package/dist/index.js.map +1 -1
  66. package/dist/main.d.ts.map +1 -1
  67. package/dist/main.js +205 -427
  68. package/dist/main.js.map +1 -1
  69. package/dist/migrations.d.ts.map +1 -1
  70. package/dist/migrations.js +20 -0
  71. package/dist/migrations.js.map +1 -1
  72. package/dist/modes/interactive/components/footer.d.ts +1 -0
  73. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  74. package/dist/modes/interactive/components/footer.js +4 -1
  75. package/dist/modes/interactive/components/footer.js.map +1 -1
  76. package/dist/modes/interactive/components/tree-selector.d.ts +4 -2
  77. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  78. package/dist/modes/interactive/components/tree-selector.js +48 -15
  79. package/dist/modes/interactive/components/tree-selector.js.map +1 -1
  80. package/dist/modes/interactive/interactive-mode.d.ts +9 -4
  81. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  82. package/dist/modes/interactive/interactive-mode.js +124 -94
  83. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  84. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  85. package/dist/modes/interactive/theme/theme.js +6 -11
  86. package/dist/modes/interactive/theme/theme.js.map +1 -1
  87. package/dist/modes/print-mode.d.ts +2 -2
  88. package/dist/modes/print-mode.d.ts.map +1 -1
  89. package/dist/modes/print-mode.js +41 -36
  90. package/dist/modes/print-mode.js.map +1 -1
  91. package/dist/modes/rpc/rpc-mode.d.ts +2 -2
  92. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  93. package/dist/modes/rpc/rpc-mode.js +92 -64
  94. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  95. package/dist/package-manager-cli.d.ts +4 -0
  96. package/dist/package-manager-cli.d.ts.map +1 -0
  97. package/dist/package-manager-cli.js +234 -0
  98. package/dist/package-manager-cli.js.map +1 -0
  99. package/docs/extensions.md +72 -40
  100. package/docs/keybindings.md +2 -0
  101. package/docs/sdk.md +227 -74
  102. package/docs/settings.md +1 -1
  103. package/docs/tree.md +6 -3
  104. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  105. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  106. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  107. package/examples/extensions/custom-provider-qwen-cli/package.json +1 -1
  108. package/examples/extensions/hello.ts +18 -17
  109. package/examples/extensions/hidden-thinking-label.ts +0 -4
  110. package/examples/extensions/rpc-demo.ts +3 -9
  111. package/examples/extensions/status-line.ts +0 -8
  112. package/examples/extensions/todo.ts +0 -2
  113. package/examples/extensions/tools.ts +0 -5
  114. package/examples/extensions/widget-placement.ts +4 -12
  115. package/examples/extensions/with-deps/package-lock.json +2 -2
  116. package/examples/extensions/with-deps/package.json +1 -1
  117. package/examples/sdk/13-session-runtime.ts +67 -0
  118. package/examples/sdk/README.md +4 -1
  119. package/package.json +4 -4
@@ -48,13 +48,13 @@ import { ToolExecutionComponent } from "./components/tool-execution.js";
48
48
  import { TreeSelectorComponent } from "./components/tree-selector.js";
49
49
  import { UserMessageComponent } from "./components/user-message.js";
50
50
  import { UserMessageSelectorComponent } from "./components/user-message-selector.js";
51
- import { getAvailableThemes, getAvailableThemesWithPaths, getEditorTheme, getMarkdownTheme, getThemeByName, initTheme, onThemeChange, setRegisteredThemes, setTheme, setThemeInstance, Theme, theme, } from "./theme/theme.js";
51
+ import { getAvailableThemes, getAvailableThemesWithPaths, getEditorTheme, getMarkdownTheme, getThemeByName, initTheme, onThemeChange, setRegisteredThemes, setTheme, setThemeInstance, stopThemeWatcher, Theme, theme, } from "./theme/theme.js";
52
52
  function isExpandable(obj) {
53
53
  return typeof obj === "object" && obj !== null && "setExpanded" in obj && typeof obj.setExpanded === "function";
54
54
  }
55
55
  export class InteractiveMode {
56
56
  options;
57
- session;
57
+ runtimeHost;
58
58
  ui;
59
59
  chatContainer;
60
60
  pendingMessagesContainer;
@@ -130,6 +130,9 @@ export class InteractiveMode {
130
130
  // Custom header from extension (undefined = use built-in header)
131
131
  customHeader = undefined;
132
132
  // Convenience accessors
133
+ get session() {
134
+ return this.runtimeHost.session;
135
+ }
133
136
  get agent() {
134
137
  return this.session.agent;
135
138
  }
@@ -139,9 +142,9 @@ export class InteractiveMode {
139
142
  get settingsManager() {
140
143
  return this.session.settingsManager;
141
144
  }
142
- constructor(session, options = {}) {
145
+ constructor(runtimeHost, options = {}) {
143
146
  this.options = options;
144
- this.session = session;
147
+ this.runtimeHost = runtimeHost;
145
148
  this.version = VERSION;
146
149
  this.ui = new TUI(new ProcessTerminal(), this.settingsManager.getShowHardwareCursor());
147
150
  this.ui.setClearOnShrink(this.settingsManager.getClearOnShrink());
@@ -162,9 +165,9 @@ export class InteractiveMode {
162
165
  this.editor = this.defaultEditor;
163
166
  this.editorContainer = new Container();
164
167
  this.editorContainer.addChild(this.editor);
165
- this.footerDataProvider = new FooterDataProvider();
166
- this.footer = new FooterComponent(session, this.footerDataProvider);
167
- this.footer.setAutoCompactEnabled(session.autoCompactionEnabled);
168
+ this.footerDataProvider = new FooterDataProvider(this.sessionManager.getCwd());
169
+ this.footer = new FooterComponent(this.session, this.footerDataProvider);
170
+ this.footer.setAutoCompactEnabled(this.session.autoCompactionEnabled);
168
171
  // Load hide thinking block setting
169
172
  this.hideThinkingBlock = this.settingsManager.getHideThinkingBlock();
170
173
  // Register themes from resource loader and initialize
@@ -271,7 +274,7 @@ export class InteractiveMode {
271
274
  }
272
275
  }
273
276
  // Setup autocomplete
274
- this.autocompleteProvider = new CombinedAutocompleteProvider([...slashCommands, ...templateCommands, ...extensionCommands, ...skillCommandList], process.cwd(), fdPath);
277
+ this.autocompleteProvider = new CombinedAutocompleteProvider([...slashCommands, ...templateCommands, ...extensionCommands, ...skillCommandList], this.sessionManager.getCwd(), fdPath);
275
278
  this.defaultEditor.setAutocompleteProvider(this.autocompleteProvider);
276
279
  if (this.editor !== this.defaultEditor) {
277
280
  this.editor.setAutocompleteProvider?.(this.autocompleteProvider);
@@ -366,7 +369,7 @@ export class InteractiveMode {
366
369
  this.ui.start();
367
370
  this.isInitialized = true;
368
371
  // Initialize extensions first so resources are shown before messages
369
- await this.initExtensions();
372
+ await this.bindCurrentSessionExtensions();
370
373
  // Render initial messages AFTER showing loaded resources
371
374
  this.renderInitialMessages();
372
375
  // Set terminal title
@@ -390,7 +393,7 @@ export class InteractiveMode {
390
393
  * Update terminal title with session name and cwd.
391
394
  */
392
395
  updateTerminalTitle() {
393
- const cwdBasename = path.basename(process.cwd());
396
+ const cwdBasename = path.basename(this.sessionManager.getCwd());
394
397
  const sessionName = this.sessionManager.getSessionName();
395
398
  if (sessionName) {
396
399
  this.ui.terminal.setTitle(`π - ${sessionName} - ${cwdBasename}`);
@@ -497,7 +500,7 @@ export class InteractiveMode {
497
500
  }
498
501
  try {
499
502
  const packageManager = new DefaultPackageManager({
500
- cwd: process.cwd(),
503
+ cwd: this.sessionManager.getCwd(),
501
504
  agentDir: getAgentDir(),
502
505
  settingsManager: this.settingsManager,
503
506
  });
@@ -885,7 +888,7 @@ export class InteractiveMode {
885
888
  /**
886
889
  * Initialize the extension system with TUI-based UI context.
887
890
  */
888
- async initExtensions() {
891
+ async bindCurrentSessionExtensions() {
889
892
  const uiContext = this.createExtensionUIContext();
890
893
  await this.session.bindExtensions({
891
894
  uiContext,
@@ -897,33 +900,33 @@ export class InteractiveMode {
897
900
  this.loadingAnimation = undefined;
898
901
  }
899
902
  this.statusContainer.clear();
900
- // Delegate to AgentSession (handles setup + agent state sync)
901
- const success = await this.session.newSession(options);
902
- if (!success) {
903
- return { cancelled: true };
903
+ try {
904
+ const result = await this.runtimeHost.newSession(options);
905
+ if (!result.cancelled) {
906
+ await this.handleRuntimeSessionChange();
907
+ this.renderCurrentSessionState();
908
+ this.ui.requestRender();
909
+ }
910
+ return result;
911
+ }
912
+ catch (error) {
913
+ return this.handleFatalRuntimeError("Failed to create session", error);
904
914
  }
905
- // Clear UI state
906
- this.chatContainer.clear();
907
- this.pendingMessagesContainer.clear();
908
- this.compactionQueuedMessages = [];
909
- this.streamingComponent = undefined;
910
- this.streamingMessage = undefined;
911
- this.pendingTools.clear();
912
- // Render any messages added via setup, or show empty session
913
- this.renderInitialMessages();
914
- this.ui.requestRender();
915
- return { cancelled: false };
916
915
  },
917
916
  fork: async (entryId) => {
918
- const result = await this.session.fork(entryId);
919
- if (result.cancelled) {
920
- return { cancelled: true };
917
+ try {
918
+ const result = await this.runtimeHost.fork(entryId);
919
+ if (!result.cancelled) {
920
+ await this.handleRuntimeSessionChange();
921
+ this.renderCurrentSessionState();
922
+ this.editor.setText(result.selectedText ?? "");
923
+ this.showStatus("Forked to new session");
924
+ }
925
+ return { cancelled: result.cancelled };
926
+ }
927
+ catch (error) {
928
+ return this.handleFatalRuntimeError("Failed to fork session", error);
921
929
  }
922
- this.chatContainer.clear();
923
- this.renderInitialMessages();
924
- this.editor.setText(result.selectedText);
925
- this.showStatus("Forked to new session");
926
- return { cancelled: false };
927
930
  },
928
931
  navigateTree: async (targetId, options) => {
929
932
  const result = await this.session.navigateTree(targetId, {
@@ -971,6 +974,49 @@ export class InteractiveMode {
971
974
  this.setupExtensionShortcuts(extensionRunner);
972
975
  this.showLoadedResources({ force: false });
973
976
  }
977
+ applyRuntimeSettings() {
978
+ this.footer.setSession(this.session);
979
+ this.footer.setAutoCompactEnabled(this.session.autoCompactionEnabled);
980
+ this.footerDataProvider.setCwd(this.sessionManager.getCwd());
981
+ this.hideThinkingBlock = this.settingsManager.getHideThinkingBlock();
982
+ this.ui.setShowHardwareCursor(this.settingsManager.getShowHardwareCursor());
983
+ this.ui.setClearOnShrink(this.settingsManager.getClearOnShrink());
984
+ const editorPaddingX = this.settingsManager.getEditorPaddingX();
985
+ const autocompleteMaxVisible = this.settingsManager.getAutocompleteMaxVisible();
986
+ this.defaultEditor.setPaddingX(editorPaddingX);
987
+ this.defaultEditor.setAutocompleteMaxVisible(autocompleteMaxVisible);
988
+ if (this.editor !== this.defaultEditor) {
989
+ this.editor.setPaddingX?.(editorPaddingX);
990
+ this.editor.setAutocompleteMaxVisible?.(autocompleteMaxVisible);
991
+ }
992
+ }
993
+ async handleRuntimeSessionChange() {
994
+ this.resetExtensionUI();
995
+ this.unsubscribe?.();
996
+ this.unsubscribe = undefined;
997
+ this.applyRuntimeSettings();
998
+ await this.bindCurrentSessionExtensions();
999
+ this.subscribeToAgent();
1000
+ await this.updateAvailableProviderCount();
1001
+ this.updateEditorBorderColor();
1002
+ this.updateTerminalTitle();
1003
+ }
1004
+ async handleFatalRuntimeError(prefix, error) {
1005
+ const message = error instanceof Error ? error.message : String(error);
1006
+ this.showError(`${prefix}: ${message}`);
1007
+ stopThemeWatcher();
1008
+ this.stop();
1009
+ process.exit(1);
1010
+ }
1011
+ renderCurrentSessionState() {
1012
+ this.chatContainer.clear();
1013
+ this.pendingMessagesContainer.clear();
1014
+ this.compactionQueuedMessages = [];
1015
+ this.streamingComponent = undefined;
1016
+ this.streamingMessage = undefined;
1017
+ this.pendingTools.clear();
1018
+ this.renderInitialMessages();
1019
+ }
974
1020
  /**
975
1021
  * Get a registered tool definition by name (for custom rendering).
976
1022
  */
@@ -988,7 +1034,7 @@ export class InteractiveMode {
988
1034
  const createContext = () => ({
989
1035
  ui: this.createExtensionUIContext(),
990
1036
  hasUI: true,
991
- cwd: process.cwd(),
1037
+ cwd: this.sessionManager.getCwd(),
992
1038
  sessionManager: this.sessionManager,
993
1039
  modelRegistry: this.session.modelRegistry,
994
1040
  model: this.session.model,
@@ -1884,7 +1930,7 @@ export class InteractiveMode {
1884
1930
  if (!this.pendingTools.has(content.id)) {
1885
1931
  const component = new ToolExecutionComponent(content.name, content.id, content.arguments, {
1886
1932
  showImages: this.settingsManager.getShowImages(),
1887
- }, this.getRegisteredToolDefinition(content.name), this.ui);
1933
+ }, this.getRegisteredToolDefinition(content.name), this.ui, this.sessionManager.getCwd());
1888
1934
  component.setExpanded(this.toolOutputExpanded);
1889
1935
  this.chatContainer.addChild(component);
1890
1936
  this.pendingTools.set(content.id, component);
@@ -1944,7 +1990,7 @@ export class InteractiveMode {
1944
1990
  if (!component) {
1945
1991
  component = new ToolExecutionComponent(event.toolName, event.toolCallId, event.args, {
1946
1992
  showImages: this.settingsManager.getShowImages(),
1947
- }, this.getRegisteredToolDefinition(event.toolName), this.ui);
1993
+ }, this.getRegisteredToolDefinition(event.toolName), this.ui, this.sessionManager.getCwd());
1948
1994
  component.setExpanded(this.toolOutputExpanded);
1949
1995
  this.chatContainer.addChild(component);
1950
1996
  this.pendingTools.set(event.toolCallId, component);
@@ -2198,7 +2244,7 @@ export class InteractiveMode {
2198
2244
  // Render tool call components
2199
2245
  for (const content of message.content) {
2200
2246
  if (content.type === "toolCall") {
2201
- const component = new ToolExecutionComponent(content.name, content.id, content.arguments, { showImages: this.settingsManager.getShowImages() }, this.getRegisteredToolDefinition(content.name), this.ui);
2247
+ const component = new ToolExecutionComponent(content.name, content.id, content.arguments, { showImages: this.settingsManager.getShowImages() }, this.getRegisteredToolDefinition(content.name), this.ui, this.sessionManager.getCwd());
2202
2248
  component.setExpanded(this.toolOutputExpanded);
2203
2249
  this.chatContainer.addChild(component);
2204
2250
  if (message.stopReason === "aborted" || message.stopReason === "error") {
@@ -2291,13 +2337,7 @@ export class InteractiveMode {
2291
2337
  if (this.isShuttingDown)
2292
2338
  return;
2293
2339
  this.isShuttingDown = true;
2294
- // Emit shutdown event to extensions
2295
- const extensionRunner = this.session.extensionRunner;
2296
- if (extensionRunner?.hasHandlers("session_shutdown")) {
2297
- await extensionRunner.emit({
2298
- type: "session_shutdown",
2299
- });
2300
- }
2340
+ await this.runtimeHost.dispose();
2301
2341
  // Wait for any pending renders to complete
2302
2342
  // requestRender() uses process.nextTick(), so we wait one tick
2303
2343
  await new Promise((resolve) => process.nextTick(resolve));
@@ -2767,7 +2807,7 @@ export class InteractiveMode {
2767
2807
  },
2768
2808
  onTransportChange: (transport) => {
2769
2809
  this.settingsManager.setTransport(transport);
2770
- this.session.agent.setTransport(transport);
2810
+ this.session.agent.transport = transport;
2771
2811
  },
2772
2812
  onThinkingLevelChange: (level) => {
2773
2813
  this.session.setThinkingLevel(level);
@@ -3023,16 +3063,15 @@ export class InteractiveMode {
3023
3063
  }
3024
3064
  this.showSelector((done) => {
3025
3065
  const selector = new UserMessageSelectorComponent(userMessages.map((m) => ({ id: m.entryId, text: m.text })), async (entryId) => {
3026
- const result = await this.session.fork(entryId);
3066
+ const result = await this.runtimeHost.fork(entryId);
3027
3067
  if (result.cancelled) {
3028
- // Extension cancelled the fork
3029
3068
  done();
3030
3069
  this.ui.requestRender();
3031
3070
  return;
3032
3071
  }
3033
- this.chatContainer.clear();
3034
- this.renderInitialMessages();
3035
- this.editor.setText(result.selectedText);
3072
+ await this.handleRuntimeSessionChange();
3073
+ this.renderCurrentSessionState();
3074
+ this.editor.setText(result.selectedText ?? "");
3036
3075
  done();
3037
3076
  this.showStatus("Branched to new session");
3038
3077
  }, () => {
@@ -3168,24 +3207,23 @@ export class InteractiveMode {
3168
3207
  });
3169
3208
  }
3170
3209
  async handleResumeSession(sessionPath) {
3171
- // Stop loading animation
3172
3210
  if (this.loadingAnimation) {
3173
3211
  this.loadingAnimation.stop();
3174
3212
  this.loadingAnimation = undefined;
3175
3213
  }
3176
3214
  this.statusContainer.clear();
3177
- // Clear UI state
3178
- this.pendingMessagesContainer.clear();
3179
- this.compactionQueuedMessages = [];
3180
- this.streamingComponent = undefined;
3181
- this.streamingMessage = undefined;
3182
- this.pendingTools.clear();
3183
- // Switch session via AgentSession (emits extension session events)
3184
- await this.session.switchSession(sessionPath);
3185
- // Clear and re-render the chat
3186
- this.chatContainer.clear();
3187
- this.renderInitialMessages();
3188
- this.showStatus("Resumed session");
3215
+ try {
3216
+ const result = await this.runtimeHost.switchSession(sessionPath);
3217
+ if (result.cancelled) {
3218
+ return;
3219
+ }
3220
+ await this.handleRuntimeSessionChange();
3221
+ this.renderCurrentSessionState();
3222
+ this.showStatus("Resumed session");
3223
+ }
3224
+ catch (error) {
3225
+ await this.handleFatalRuntimeError("Failed to resume session", error);
3226
+ }
3189
3227
  }
3190
3228
  async showOAuthSelector(mode) {
3191
3229
  if (mode === "logout") {
@@ -3403,30 +3441,22 @@ export class InteractiveMode {
3403
3441
  return;
3404
3442
  }
3405
3443
  try {
3406
- // Stop loading animation
3407
3444
  if (this.loadingAnimation) {
3408
3445
  this.loadingAnimation.stop();
3409
3446
  this.loadingAnimation = undefined;
3410
3447
  }
3411
3448
  this.statusContainer.clear();
3412
- // Clear UI state
3413
- this.pendingMessagesContainer.clear();
3414
- this.compactionQueuedMessages = [];
3415
- this.streamingComponent = undefined;
3416
- this.streamingMessage = undefined;
3417
- this.pendingTools.clear();
3418
- const success = await this.session.importFromJsonl(inputPath);
3419
- if (!success) {
3420
- this.showWarning("Import cancelled");
3449
+ const result = await this.runtimeHost.importFromJsonl(inputPath);
3450
+ if (result.cancelled) {
3451
+ this.showStatus("Import cancelled");
3421
3452
  return;
3422
3453
  }
3423
- // Clear and re-render the chat
3424
- this.chatContainer.clear();
3425
- this.renderInitialMessages();
3454
+ await this.handleRuntimeSessionChange();
3455
+ this.renderCurrentSessionState();
3426
3456
  this.showStatus(`Session imported from: ${inputPath}`);
3427
3457
  }
3428
3458
  catch (error) {
3429
- this.showError(`Failed to import session: ${error instanceof Error ? error.message : "Unknown error"}`);
3459
+ await this.handleFatalRuntimeError("Failed to import session", error);
3430
3460
  }
3431
3461
  }
3432
3462
  async handleShareCommand() {
@@ -3736,25 +3766,25 @@ export class InteractiveMode {
3736
3766
  this.ui.requestRender();
3737
3767
  }
3738
3768
  async handleClearCommand() {
3739
- // Stop loading animation
3740
3769
  if (this.loadingAnimation) {
3741
3770
  this.loadingAnimation.stop();
3742
3771
  this.loadingAnimation = undefined;
3743
3772
  }
3744
3773
  this.statusContainer.clear();
3745
- // New session via session (emits extension session events)
3746
- await this.session.newSession();
3747
- // Clear UI state
3748
- this.headerContainer.clear();
3749
- this.chatContainer.clear();
3750
- this.pendingMessagesContainer.clear();
3751
- this.compactionQueuedMessages = [];
3752
- this.streamingComponent = undefined;
3753
- this.streamingMessage = undefined;
3754
- this.pendingTools.clear();
3755
- this.chatContainer.addChild(new Spacer(1));
3756
- this.chatContainer.addChild(new Text(`${theme.fg("accent", "✓ New session started")}`, 1, 1));
3757
- this.ui.requestRender();
3774
+ try {
3775
+ const result = await this.runtimeHost.newSession();
3776
+ if (result.cancelled) {
3777
+ return;
3778
+ }
3779
+ await this.handleRuntimeSessionChange();
3780
+ this.renderCurrentSessionState();
3781
+ this.chatContainer.addChild(new Spacer(1));
3782
+ this.chatContainer.addChild(new Text(`${theme.fg("accent", "✓ New session started")}`, 1, 1));
3783
+ this.ui.requestRender();
3784
+ }
3785
+ catch (error) {
3786
+ await this.handleFatalRuntimeError("Failed to create session", error);
3787
+ }
3758
3788
  }
3759
3789
  handleDebugCommand() {
3760
3790
  const width = this.ui.terminal.columns;
@@ -3806,7 +3836,7 @@ export class InteractiveMode {
3806
3836
  type: "user_bash",
3807
3837
  command,
3808
3838
  excludeFromContext,
3809
- cwd: process.cwd(),
3839
+ cwd: this.sessionManager.getCwd(),
3810
3840
  })
3811
3841
  : undefined;
3812
3842
  // If extension returned a full result, use it directly