@earendil-works/pi-coding-agent 0.79.5 → 0.79.7

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 (84) hide show
  1. package/CHANGELOG.md +34 -1
  2. package/README.md +5 -3
  3. package/dist/cli/args.d.ts.map +1 -1
  4. package/dist/cli/args.js +1 -1
  5. package/dist/cli/args.js.map +1 -1
  6. package/dist/core/http-dispatcher.d.ts.map +1 -1
  7. package/dist/core/http-dispatcher.js +10 -1
  8. package/dist/core/http-dispatcher.js.map +1 -1
  9. package/dist/core/project-trust.d.ts.map +1 -1
  10. package/dist/core/project-trust.js +2 -1
  11. package/dist/core/project-trust.js.map +1 -1
  12. package/dist/core/settings-manager.d.ts +1 -0
  13. package/dist/core/settings-manager.d.ts.map +1 -1
  14. package/dist/core/settings-manager.js +8 -1
  15. package/dist/core/settings-manager.js.map +1 -1
  16. package/dist/core/tools/edit-diff.d.ts +1 -2
  17. package/dist/core/tools/edit-diff.d.ts.map +1 -1
  18. package/dist/core/tools/edit-diff.js +1 -2
  19. package/dist/core/tools/edit-diff.js.map +1 -1
  20. package/dist/index.d.ts +2 -1
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +2 -1
  23. package/dist/index.js.map +1 -1
  24. package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
  25. package/dist/modes/interactive/components/config-selector.js +5 -5
  26. package/dist/modes/interactive/components/config-selector.js.map +1 -1
  27. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  28. package/dist/modes/interactive/components/model-selector.js +2 -1
  29. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  30. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  31. package/dist/modes/interactive/components/scoped-models-selector.js +4 -1
  32. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  33. package/dist/modes/interactive/components/settings-selector.d.ts +2 -0
  34. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  35. package/dist/modes/interactive/components/settings-selector.js +175 -15
  36. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  37. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  38. package/dist/modes/interactive/components/tree-selector.js +44 -4
  39. package/dist/modes/interactive/components/tree-selector.js.map +1 -1
  40. package/dist/modes/interactive/interactive-mode.d.ts +1 -1
  41. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  42. package/dist/modes/interactive/interactive-mode.js +24 -49
  43. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  44. package/dist/modes/interactive/model-search.d.ts +7 -0
  45. package/dist/modes/interactive/model-search.d.ts.map +1 -0
  46. package/dist/modes/interactive/model-search.js +6 -0
  47. package/dist/modes/interactive/model-search.js.map +1 -0
  48. package/dist/modes/interactive/theme/theme-controller.d.ts +30 -0
  49. package/dist/modes/interactive/theme/theme-controller.d.ts.map +1 -0
  50. package/dist/modes/interactive/theme/theme-controller.js +113 -0
  51. package/dist/modes/interactive/theme/theme-controller.js.map +1 -0
  52. package/dist/modes/interactive/theme/theme-schema.json +2 -1
  53. package/dist/modes/interactive/theme/theme.d.ts +5 -0
  54. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  55. package/dist/modes/interactive/theme/theme.js +34 -1
  56. package/dist/modes/interactive/theme/theme.js.map +1 -1
  57. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  58. package/dist/modes/rpc/rpc-mode.js +1 -1
  59. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  60. package/dist/package-manager-cli.d.ts.map +1 -1
  61. package/dist/package-manager-cli.js +42 -12
  62. package/dist/package-manager-cli.js.map +1 -1
  63. package/docs/extensions.md +14 -0
  64. package/docs/packages.md +5 -4
  65. package/docs/sdk.md +2 -1
  66. package/docs/themes.md +1 -1
  67. package/docs/tui.md +1 -1
  68. package/docs/usage.md +3 -2
  69. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  70. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  71. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  72. package/examples/extensions/gondolin/package-lock.json +2 -2
  73. package/examples/extensions/gondolin/package.json +1 -1
  74. package/examples/extensions/preset.ts +10 -4
  75. package/examples/extensions/provider-payload.ts +5 -5
  76. package/examples/extensions/sandbox/index.ts +2 -2
  77. package/examples/extensions/sandbox/package-lock.json +2 -2
  78. package/examples/extensions/sandbox/package.json +1 -1
  79. package/examples/extensions/subagent/agents.ts +2 -2
  80. package/examples/extensions/subagent/index.ts +9 -3
  81. package/examples/extensions/with-deps/package-lock.json +2 -2
  82. package/examples/extensions/with-deps/package.json +1 -1
  83. package/npm-shrinkwrap.json +12 -12
  84. package/package.json +4 -4
@@ -10,7 +10,7 @@ import { getProviders, } from "@earendil-works/pi-ai";
10
10
  import { CombinedAutocompleteProvider, Container, fuzzyFilter, getCapabilities, hyperlink, Loader, Markdown, matchesKey, ProcessTerminal, Spacer, setKeybindings, Text, TruncatedText, TUI, visibleWidth, } from "@earendil-works/pi-tui";
11
11
  import chalk from "chalk";
12
12
  import { spawn, spawnSync } from "child_process";
13
- import { APP_NAME, APP_TITLE, getAgentDir, getAuthPath, getDebugLogPath, getDocsPath, getShareViewerUrl, VERSION, } from "../../config.js";
13
+ import { APP_NAME, APP_TITLE, CONFIG_DIR_NAME, getAgentDir, getAuthPath, getDebugLogPath, getDocsPath, getShareViewerUrl, VERSION, } from "../../config.js";
14
14
  import { parseSkillBlock } from "../../core/agent-session.js";
15
15
  import { SessionImportFileNotFoundError } from "../../core/agent-session-runtime.js";
16
16
  import { FooterDataProvider } from "../../core/footer-data-provider.js";
@@ -63,7 +63,9 @@ import { TreeSelectorComponent } from "./components/tree-selector.js";
63
63
  import { TrustSelectorComponent } from "./components/trust-selector.js";
64
64
  import { UserMessageComponent } from "./components/user-message.js";
65
65
  import { UserMessageSelectorComponent } from "./components/user-message-selector.js";
66
- import { detectTerminalBackgroundTheme, getAvailableThemes, getAvailableThemesWithPaths, getEditorTheme, getMarkdownTheme, getThemeByName, initTheme, onThemeChange, setRegisteredThemes, setTheme, setThemeInstance, stopThemeWatcher, Theme, theme, } from "./theme/theme.js";
66
+ import { getModelSearchText } from "./model-search.js";
67
+ import { getAvailableThemes, getAvailableThemesWithPaths, getEditorTheme, getMarkdownTheme, getThemeByName, onThemeChange, setRegisteredThemes, stopThemeWatcher, Theme, theme, } from "./theme/theme.js";
68
+ import { InteractiveThemeController } from "./theme/theme-controller.js";
67
69
  function isExpandable(obj) {
68
70
  return typeof obj === "object" && obj !== null && "setExpanded" in obj && typeof obj.setExpanded === "function";
69
71
  }
@@ -216,6 +218,7 @@ export class InteractiveMode {
216
218
  customHeader = undefined;
217
219
  options;
218
220
  autoTrustOnReloadCwd;
221
+ themeController;
219
222
  // Convenience accessors
220
223
  get session() {
221
224
  return this.runtimeHost.session;
@@ -266,23 +269,7 @@ export class InteractiveMode {
266
269
  this.hideThinkingBlock = this.settingsManager.getHideThinkingBlock();
267
270
  // Register themes from resource loader and initialize
268
271
  setRegisteredThemes(this.session.resourceLoader.getThemes().themes);
269
- initTheme(this.settingsManager.getTheme(), true);
270
- }
271
- async detectThemeIfUnset() {
272
- if (this.settingsManager.getTheme()) {
273
- return;
274
- }
275
- const detection = await detectTerminalBackgroundTheme({ ui: this.ui, timeoutMs: 100 });
276
- const result = setTheme(detection.theme, true);
277
- if (!result.success) {
278
- return;
279
- }
280
- if (detection.confidence === "high") {
281
- this.settingsManager.setTheme(detection.theme);
282
- await this.settingsManager.flush();
283
- }
284
- this.updateEditorBorderColor();
285
- this.ui.requestRender();
272
+ this.themeController = new InteractiveThemeController(this.ui, this.settingsManager, (message) => this.showError(message), () => this.updateEditorBorderColor());
286
273
  }
287
274
  getAutocompleteSourceTag(sourceInfo) {
288
275
  if (!sourceInfo) {
@@ -342,10 +329,11 @@ export class InteractiveMode {
342
329
  const items = models.map((m) => ({
343
330
  id: m.id,
344
331
  provider: m.provider,
332
+ name: m.name,
345
333
  label: `${m.provider}/${m.id}`,
346
334
  }));
347
- // Fuzzy filter by model ID + provider (allows "opus anthropic" to match)
348
- const filtered = fuzzyFilter(items, prefix, (item) => `${item.id} ${item.provider}`);
335
+ // Fuzzy filter by model ID + provider in either order.
336
+ const filtered = fuzzyFilter(items, prefix, getModelSearchText);
349
337
  if (filtered.length === 0)
350
338
  return null;
351
339
  return filtered.map((item) => ({
@@ -467,7 +455,7 @@ export class InteractiveMode {
467
455
  // Start the UI before initializing extensions so session_start handlers can use interactive dialogs
468
456
  this.ui.start();
469
457
  this.isInitialized = true;
470
- await this.detectThemeIfUnset();
458
+ await this.themeController.applyFromSettings();
471
459
  // Add header with keybindings from config (unless silenced)
472
460
  if (this.options.verbose || !this.settingsManager.getQuietStartup()) {
473
461
  const logo = theme.bold(theme.fg("accent", APP_NAME)) + theme.fg("dim", ` v${this.version}`);
@@ -1636,16 +1624,13 @@ export class InteractiveMode {
1636
1624
  getTheme: (name) => getThemeByName(name),
1637
1625
  setTheme: (themeOrName) => {
1638
1626
  if (themeOrName instanceof Theme) {
1639
- setThemeInstance(themeOrName);
1640
- this.ui.requestRender();
1641
- return { success: true };
1627
+ return this.themeController.setThemeInstance(themeOrName);
1642
1628
  }
1643
- const result = setTheme(themeOrName, true);
1629
+ const result = this.themeController.setThemeName(themeOrName);
1644
1630
  if (result.success) {
1645
1631
  if (this.settingsManager.getTheme() !== themeOrName) {
1646
1632
  this.settingsManager.setTheme(themeOrName);
1647
1633
  }
1648
- this.ui.requestRender();
1649
1634
  }
1650
1635
  return result;
1651
1636
  },
@@ -2691,7 +2676,7 @@ export class InteractiveMode {
2691
2676
  if (this.chatContainer.children.length > 0) {
2692
2677
  this.chatContainer.addChild(new Spacer(1));
2693
2678
  }
2694
- this.chatContainer.addChild(new Text(theme.fg("warning", "This project is not trusted. Project .pi resources and packages are ignored. Use /trust to save a trust decision, then restart pi."), 1, 0));
2679
+ this.chatContainer.addChild(new Text(theme.fg("warning", `This project is not trusted. Project ${CONFIG_DIR_NAME} resources and packages are ignored. Use /trust to save a trust decision, then restart pi.`), 1, 0));
2695
2680
  }
2696
2681
  async getUserInput() {
2697
2682
  const queuedInput = this.pendingUserInputs.shift();
@@ -2749,6 +2734,7 @@ export class InteractiveMode {
2749
2734
  // which the stdout/stderr error handler turns into emergencyTerminalExit;
2750
2735
  // the render loop is already idle, so this cannot hot-spin (see #4144).
2751
2736
  await this.runtimeHost.dispose();
2737
+ this.themeController.disableAutoSync();
2752
2738
  await this.ui.terminal.drainInput(1000);
2753
2739
  this.stop();
2754
2740
  process.exit(0);
@@ -2758,6 +2744,7 @@ export class InteractiveMode {
2758
2744
  // the final frame while the process is exiting.
2759
2745
  // Drain any in-flight Kitty key release events before stopping.
2760
2746
  // This prevents escape sequences from leaking to the parent shell over slow SSH.
2747
+ this.themeController.disableAutoSync();
2761
2748
  await this.ui.terminal.drainInput(1000);
2762
2749
  this.stop();
2763
2750
  await this.runtimeHost.dispose();
@@ -3089,7 +3076,7 @@ export class InteractiveMode {
3089
3076
  this.ui.requestRender();
3090
3077
  }
3091
3078
  showPackageUpdateNotification(packages) {
3092
- const action = theme.fg("accent", `${APP_NAME} update`);
3079
+ const action = theme.fg("accent", `${APP_NAME} update --extensions`);
3093
3080
  const updateInstruction = theme.fg("muted", "Package updates are available. Run ") + action;
3094
3081
  const packageLines = packages.map((pkg) => `- ${pkg}`).join("\n");
3095
3082
  this.chatContainer.addChild(new Spacer(1));
@@ -3296,7 +3283,8 @@ export class InteractiveMode {
3296
3283
  httpIdleTimeoutMs: this.settingsManager.getHttpIdleTimeoutMs(),
3297
3284
  thinkingLevel: this.session.thinkingLevel,
3298
3285
  availableThinkingLevels: this.session.getAvailableThinkingLevels(),
3299
- currentTheme: this.settingsManager.getTheme() || "dark",
3286
+ currentTheme: this.settingsManager.getThemeSetting() || "dark",
3287
+ terminalTheme: this.themeController.getTerminalTheme(),
3300
3288
  availableThemes: getAvailableThemes(),
3301
3289
  hideThinkingBlock: this.hideThinkingBlock,
3302
3290
  collapseChangelog: this.settingsManager.getCollapseChangelog(),
@@ -3362,21 +3350,11 @@ export class InteractiveMode {
3362
3350
  this.footer.invalidate();
3363
3351
  this.updateEditorBorderColor();
3364
3352
  },
3365
- onThemeChange: (themeName) => {
3366
- const result = setTheme(themeName, true);
3367
- this.settingsManager.setTheme(themeName);
3368
- this.ui.invalidate();
3369
- if (!result.success) {
3370
- this.showError(`Failed to load theme "${themeName}": ${result.error}\nFell back to dark theme.`);
3371
- }
3372
- },
3373
- onThemePreview: (themeName) => {
3374
- const result = setTheme(themeName, true);
3375
- if (result.success) {
3376
- this.ui.invalidate();
3377
- this.ui.requestRender();
3378
- }
3353
+ onThemeChange: (themeSetting) => {
3354
+ this.settingsManager.setTheme(themeSetting);
3355
+ void this.themeController.applyFromSettings();
3379
3356
  },
3357
+ onThemePreview: (themeName) => this.themeController.preview(themeName),
3380
3358
  onHideThinkingBlockChange: (hidden) => {
3381
3359
  this.hideThinkingBlock = hidden;
3382
3360
  this.settingsManager.setHideThinkingBlock(hidden);
@@ -4231,11 +4209,7 @@ export class InteractiveMode {
4231
4209
  }
4232
4210
  setRegisteredThemes(this.session.resourceLoader.getThemes().themes);
4233
4211
  this.hideThinkingBlock = this.settingsManager.getHideThinkingBlock();
4234
- const themeName = this.settingsManager.getTheme();
4235
- const themeResult = themeName ? setTheme(themeName, true) : { success: true };
4236
- if (!themeResult.success) {
4237
- this.showError(`Failed to load theme "${themeName}": ${themeResult.error}\nFell back to dark theme.`);
4238
- }
4212
+ await this.themeController.applyFromSettings();
4239
4213
  const editorPaddingX = this.settingsManager.getEditorPaddingX();
4240
4214
  const autocompleteMaxVisible = this.settingsManager.getAutocompleteMaxVisible();
4241
4215
  this.defaultEditor.setPaddingX(editorPaddingX);
@@ -4808,6 +4782,7 @@ export class InteractiveMode {
4808
4782
  this.loadingAnimation.stop();
4809
4783
  this.loadingAnimation = undefined;
4810
4784
  }
4785
+ this.themeController.disableAutoSync();
4811
4786
  this.clearExtensionTerminalInputListeners();
4812
4787
  this.footer.dispose();
4813
4788
  this.footerDataProvider.dispose();