@oh-my-pi/pi-coding-agent 16.3.0 → 16.3.2

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 (86) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/dist/cli.js +3610 -3566
  3. package/dist/types/config/settings-schema.d.ts +10 -0
  4. package/dist/types/discovery/helpers.d.ts +2 -0
  5. package/dist/types/irc/bus.d.ts +5 -4
  6. package/dist/types/session/agent-session.d.ts +13 -13
  7. package/dist/types/task/discovery.d.ts +5 -2
  8. package/dist/types/task/renderer.d.ts +1 -0
  9. package/dist/types/tools/ast-grep.d.ts +4 -2
  10. package/dist/types/tools/browser/render.d.ts +2 -0
  11. package/dist/types/tools/debug.d.ts +1 -0
  12. package/dist/types/tools/eval-render.d.ts +2 -0
  13. package/dist/types/tools/glob.d.ts +4 -2
  14. package/dist/types/tools/grep.d.ts +4 -3
  15. package/dist/types/tools/path-utils.d.ts +7 -0
  16. package/dist/types/tools/renderers.d.ts +11 -0
  17. package/dist/types/tools/ssh.d.ts +2 -1
  18. package/dist/types/tts/index.d.ts +2 -0
  19. package/dist/types/tts/speakable.d.ts +47 -0
  20. package/dist/types/tts/speech-enhancer.d.ts +46 -0
  21. package/dist/types/tts/streaming-player.d.ts +1 -2
  22. package/dist/types/tts/tts-client.d.ts +11 -10
  23. package/dist/types/tts/tts-protocol.d.ts +7 -0
  24. package/dist/types/tts/vocalizer.d.ts +15 -8
  25. package/dist/types/utils/git.d.ts +2 -0
  26. package/package.json +12 -12
  27. package/src/advisor/__tests__/advisor.test.ts +1 -1
  28. package/src/cli/gallery-fixtures/fs.ts +2 -2
  29. package/src/cli/gallery-fixtures/search.ts +2 -2
  30. package/src/cli.ts +27 -5
  31. package/src/config/model-resolver.ts +31 -10
  32. package/src/config/settings-schema.ts +11 -0
  33. package/src/cursor.ts +1 -1
  34. package/src/discovery/helpers.ts +8 -0
  35. package/src/export/html/tool-views.generated.js +34 -34
  36. package/src/extensibility/custom-tools/loader.ts +3 -3
  37. package/src/extensibility/extensions/loader.ts +10 -3
  38. package/src/extensibility/legacy-pi-coding-agent-shim.ts +2 -2
  39. package/src/extensibility/plugins/legacy-pi-compat.ts +87 -11
  40. package/src/extensibility/plugins/loader.ts +30 -1
  41. package/src/irc/bus.ts +5 -4
  42. package/src/modes/components/__tests__/move-overlay.test.ts +72 -1
  43. package/src/modes/components/assistant-message.ts +1 -1
  44. package/src/modes/components/move-overlay.ts +35 -23
  45. package/src/modes/components/tool-execution.ts +45 -12
  46. package/src/modes/components/tree-selector.ts +10 -3
  47. package/src/modes/controllers/event-controller.ts +16 -0
  48. package/src/prompts/goals/goal-mode-context.md +4 -0
  49. package/src/prompts/goals/goal-todo-context.md +10 -2
  50. package/src/prompts/system/speech-rewrite.md +15 -0
  51. package/src/prompts/system/tiny-title-system.md +1 -1
  52. package/src/prompts/system/title-system-marker.md +2 -1
  53. package/src/prompts/system/title-system.md +2 -1
  54. package/src/prompts/tools/ast-grep.md +3 -3
  55. package/src/prompts/tools/glob.md +1 -1
  56. package/src/prompts/tools/grep.md +1 -1
  57. package/src/sdk.ts +8 -5
  58. package/src/session/agent-session.ts +163 -49
  59. package/src/session/session-history-format.ts +6 -2
  60. package/src/task/discovery.ts +25 -2
  61. package/src/task/executor.ts +24 -4
  62. package/src/task/render.ts +26 -12
  63. package/src/task/renderer.ts +1 -0
  64. package/src/task/worktree.ts +144 -16
  65. package/src/tiny/text.ts +109 -17
  66. package/src/tools/ast-grep.ts +20 -17
  67. package/src/tools/bash.ts +16 -8
  68. package/src/tools/browser/render.ts +2 -0
  69. package/src/tools/debug.ts +1 -0
  70. package/src/tools/eval-render.ts +5 -2
  71. package/src/tools/gh-renderer.ts +3 -0
  72. package/src/tools/glob.ts +24 -20
  73. package/src/tools/grep.ts +18 -36
  74. package/src/tools/path-utils.ts +55 -10
  75. package/src/tools/read.ts +9 -2
  76. package/src/tools/renderers.ts +11 -0
  77. package/src/tools/ssh.ts +17 -7
  78. package/src/tts/index.ts +2 -0
  79. package/src/tts/speakable.ts +382 -0
  80. package/src/tts/speech-enhancer.ts +204 -0
  81. package/src/tts/streaming-player.ts +71 -16
  82. package/src/tts/tts-client.ts +11 -10
  83. package/src/tts/tts-protocol.ts +14 -5
  84. package/src/tts/tts-worker.ts +52 -49
  85. package/src/tts/vocalizer.ts +277 -46
  86. package/src/utils/git.ts +8 -0
@@ -630,7 +630,8 @@ function matchModel(
630
630
  // fuzzy matching so raw IDs that contain slashes (for example OpenRouter model
631
631
  // IDs like "openai/gpt-4o:extended") still resolve as IDs instead of being
632
632
  // misread as a provider-qualified selector.
633
- const exactMatches = availableModels.filter(m => m.id.toLowerCase() === modelPattern.toLowerCase());
633
+ const lowerPattern = modelPattern.toLowerCase();
634
+ const exactMatches = availableModels.filter(m => m.id.toLowerCase() === lowerPattern);
634
635
  if (exactMatches.length > 0) {
635
636
  return pickPreferredModel(exactMatches, context);
636
637
  }
@@ -647,7 +648,8 @@ function matchModel(
647
648
  const bareAlias = resolveBareVariantAlias(modelPattern);
648
649
  const bareAliasTargetId = bareAlias?.id ?? stripThinkingVariantToken(modelPattern);
649
650
  if (bareAliasTargetId) {
650
- const aliasMatches = availableModels.filter(m => m.id.toLowerCase() === bareAliasTargetId.toLowerCase());
651
+ const lowerAliasTarget = bareAliasTargetId.toLowerCase();
652
+ const aliasMatches = availableModels.filter(m => m.id.toLowerCase() === lowerAliasTarget);
651
653
  if (aliasMatches.length > 0) {
652
654
  const preferred = bareAlias ? aliasMatches.filter(m => bareAlias.providers.includes(m.provider)) : [];
653
655
  return pickPreferredModel(preferred.length > 0 ? preferred : aliasMatches, context);
@@ -658,7 +660,8 @@ function matchModel(
658
660
  if (slashIndex !== -1) {
659
661
  const provider = modelPattern.substring(0, slashIndex);
660
662
  const modelId = modelPattern.substring(slashIndex + 1);
661
- const providerModels = availableModels.filter(m => m.provider.toLowerCase() === provider.toLowerCase());
663
+ const lowerProvider = provider.toLowerCase();
664
+ const providerModels = availableModels.filter(m => m.provider.toLowerCase() === lowerProvider);
662
665
  if (providerModels.length === 0) {
663
666
  // The prefix is not a known provider in this candidate set, so treat the
664
667
  // slash as part of the raw model ID and continue with generic matching.
@@ -699,9 +702,7 @@ function matchModel(
699
702
 
700
703
  // No exact match - fall back to partial matching
701
704
  const matches = availableModels.filter(
702
- m =>
703
- m.id.toLowerCase().includes(modelPattern.toLowerCase()) ||
704
- m.name?.toLowerCase().includes(modelPattern.toLowerCase()),
705
+ m => m.id.toLowerCase().includes(lowerPattern) || m.name?.toLowerCase().includes(lowerPattern),
705
706
  );
706
707
 
707
708
  if (matches.length === 0) {
@@ -808,13 +809,15 @@ function parseModelPatternWithContext(
808
809
  return result;
809
810
  }
810
811
 
811
- export function parseModelPattern(
812
+ /** Match a single pattern with a pre-built preference context (direct match plus
813
+ * the `@upstream` routing fallback), so role resolution can reuse one context
814
+ * across every fallback pattern instead of rebuilding it per pattern. */
815
+ function matchPatternWithContext(
812
816
  pattern: string,
813
817
  availableModels: Model<Api>[],
814
- preferences?: ModelMatchPreferences,
818
+ context: ModelPreferenceContext,
815
819
  options?: { allowInvalidThinkingSelectorFallback?: boolean },
816
820
  ): ParsedModelResult {
817
- const context = buildPreferenceContext(availableModels, preferences);
818
821
  const direct = parseModelPatternWithContext(pattern, availableModels, context, options);
819
822
  if (direct.model) return direct;
820
823
 
@@ -831,6 +834,20 @@ export function parseModelPattern(
831
834
  return direct;
832
835
  }
833
836
 
837
+ export function parseModelPattern(
838
+ pattern: string,
839
+ availableModels: Model<Api>[],
840
+ preferences?: ModelMatchPreferences,
841
+ options?: { allowInvalidThinkingSelectorFallback?: boolean },
842
+ ): ParsedModelResult {
843
+ return matchPatternWithContext(
844
+ pattern,
845
+ availableModels,
846
+ buildPreferenceContext(availableModels, preferences),
847
+ options,
848
+ );
849
+ }
850
+
834
851
  const PREFIX_MODEL_ROLE = "pi/";
835
852
  const DEFAULT_MODEL_ROLE = "default";
836
853
 
@@ -1035,8 +1052,12 @@ export function resolveModelRoleValue(
1035
1052
 
1036
1053
  let warning: string | undefined;
1037
1054
  const matchPreferences = mergeModelMatchPreferences(options?.settings, options?.matchPreferences);
1055
+ // Build the O(n) preference context (model-order map over all available
1056
+ // models) once and reuse it across every fallback pattern instead of
1057
+ // rebuilding it per pattern inside parseModelPattern.
1058
+ const preferenceContext = buildPreferenceContext(availableModels, matchPreferences);
1038
1059
  for (const effectivePattern of effectivePatterns) {
1039
- const resolved = parseModelPattern(effectivePattern, availableModels, matchPreferences);
1060
+ const resolved = matchPatternWithContext(effectivePattern, availableModels, preferenceContext);
1040
1061
  if (resolved.model) {
1041
1062
  return {
1042
1063
  model: resolved.model,
@@ -4491,6 +4491,17 @@ export const SETTINGS_SCHEMA = {
4491
4491
  ],
4492
4492
  },
4493
4493
  },
4494
+ "speech.enhanced": {
4495
+ type: "boolean",
4496
+ default: false,
4497
+ ui: {
4498
+ tab: "providers",
4499
+ group: "Services",
4500
+ label: "Enhanced Speech Rewriting",
4501
+ description:
4502
+ "Rewrite assistant output into natural spoken prose with the tiny/smol model before synthesis (describes code, drops links and markdown). Falls back to mechanical cleanup on failure",
4503
+ },
4504
+ },
4494
4505
  "speech.voice": {
4495
4506
  type: "enum",
4496
4507
  values: TTS_LOCAL_VOICE_VALUES,
package/src/cursor.ts CHANGED
@@ -180,7 +180,7 @@ export class CursorExecHandlers implements ICursorExecHandlers {
180
180
  const searchPath = args.glob ? `${args.path || "."}/${args.glob}` : args.path || ".";
181
181
  const toolResultMessage = await executeTool(this.options, "grep", toolCallId, {
182
182
  pattern: args.pattern,
183
- paths: [searchPath],
183
+ path: searchPath,
184
184
  case: args.caseInsensitive === true ? false : undefined,
185
185
  });
186
186
  return toolResultMessage;
@@ -830,6 +830,13 @@ export async function resolveOrDefaultProjectRegistryPath(cwd: string): Promise<
830
830
 
831
831
  const pluginRootsCache = new Map<string, { roots: ClaudePluginRoot[]; warnings: string[] }>();
832
832
 
833
+ const pluginCacheInvalidators = new Set<() => void>();
834
+
835
+ /** Register a process-global plugin cache invalidator called whenever plugin roots are cleared. */
836
+ export function registerPluginCacheInvalidator(invalidator: () => void): void {
837
+ pluginCacheInvalidators.add(invalidator);
838
+ }
839
+
833
840
  /**
834
841
  * List all installed Claude Code plugin roots from the plugin cache.
835
842
  * Reads ~/.claude/plugins/installed_plugins.json and ~/.omp/plugins/installed_plugins.json,
@@ -1009,6 +1016,7 @@ export async function listClaudePluginRoots(
1009
1016
  */
1010
1017
  export function clearClaudePluginRootsCache(): void {
1011
1018
  pluginRootsCache.clear();
1019
+ for (const invalidate of pluginCacheInvalidators) invalidate();
1012
1020
  preloadedPluginRoots = [...injectedPluginDirRoots];
1013
1021
  // Re-warm preloaded roots asynchronously so sync LSP config reads stay valid
1014
1022
  if (lastPreloadHome) {