@oh-my-pi/pi-coding-agent 15.8.3 → 15.9.1

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 (172) hide show
  1. package/CHANGELOG.md +113 -31
  2. package/dist/types/capability/skill.d.ts +7 -0
  3. package/dist/types/cli/update-cli.d.ts +15 -1
  4. package/dist/types/config/append-only-context-mode.d.ts +8 -0
  5. package/dist/types/config/model-registry.d.ts +3 -0
  6. package/dist/types/config/models-config-schema.d.ts +15 -0
  7. package/dist/types/config/settings-schema.d.ts +38 -24
  8. package/dist/types/debug/protocol-probe.d.ts +38 -0
  9. package/dist/types/debug/terminal-info.d.ts +34 -0
  10. package/dist/types/exa/mcp-client.d.ts +2 -1
  11. package/dist/types/export/html/template.generated.d.ts +1 -1
  12. package/dist/types/extensibility/custom-tools/types.d.ts +1 -1
  13. package/dist/types/extensibility/extensions/types.d.ts +11 -0
  14. package/dist/types/extensibility/shared-events.d.ts +1 -1
  15. package/dist/types/index.d.ts +1 -0
  16. package/dist/types/mcp/json-rpc.d.ts +6 -1
  17. package/dist/types/mcp/tool-bridge.d.ts +4 -0
  18. package/dist/types/mcp/transports/stdio.d.ts +16 -7
  19. package/dist/types/mnemopi/state.d.ts +2 -2
  20. package/dist/types/modes/components/agent-dashboard.d.ts +1 -0
  21. package/dist/types/modes/components/assistant-message.d.ts +3 -2
  22. package/dist/types/modes/components/extensions/extension-dashboard.d.ts +1 -0
  23. package/dist/types/modes/components/hook-selector.d.ts +11 -0
  24. package/dist/types/modes/components/plugin-settings.d.ts +40 -8
  25. package/dist/types/modes/components/session-selector.d.ts +8 -3
  26. package/dist/types/modes/components/settings-selector.d.ts +1 -1
  27. package/dist/types/modes/components/todo-reminder.d.ts +1 -1
  28. package/dist/types/modes/components/transcript-container.d.ts +36 -0
  29. package/dist/types/modes/interactive-mode.d.ts +2 -1
  30. package/dist/types/modes/rpc/rpc-types.d.ts +1 -1
  31. package/dist/types/modes/theme/theme.d.ts +20 -1
  32. package/dist/types/modes/utils/keybinding-matchers.d.ts +4 -0
  33. package/dist/types/plan-mode/plan-handoff.d.ts +20 -0
  34. package/dist/types/session/agent-session.d.ts +5 -2
  35. package/dist/types/session/history-storage.d.ts +3 -4
  36. package/dist/types/session/indexed-session-storage.d.ts +59 -0
  37. package/dist/types/session/messages.d.ts +1 -0
  38. package/dist/types/session/redis-session-storage.d.ts +12 -85
  39. package/dist/types/session/session-manager.d.ts +21 -0
  40. package/dist/types/session/session-storage.d.ts +5 -7
  41. package/dist/types/session/sql-session-storage.d.ts +16 -85
  42. package/dist/types/slash-commands/types.d.ts +17 -4
  43. package/dist/types/task/executor.d.ts +9 -0
  44. package/dist/types/task/index.d.ts +3 -1
  45. package/dist/types/telemetry-export.d.ts +19 -0
  46. package/dist/types/tiny/compiled-runtime.d.ts +35 -0
  47. package/dist/types/tiny/text.d.ts +17 -0
  48. package/dist/types/tools/ask.d.ts +1 -0
  49. package/dist/types/tools/index.d.ts +4 -2
  50. package/dist/types/tools/path-utils.d.ts +1 -1
  51. package/dist/types/tools/search.d.ts +2 -2
  52. package/dist/types/tools/{todo-write.d.ts → todo.d.ts} +18 -18
  53. package/dist/types/utils/session-color.d.ts +7 -2
  54. package/dist/types/web/search/index.d.ts +1 -1
  55. package/dist/types/web/search/provider.d.ts +2 -2
  56. package/dist/types/web/search/providers/base.d.ts +14 -0
  57. package/dist/types/web/search/providers/exa.d.ts +9 -0
  58. package/dist/types/web/search/providers/perplexity.d.ts +2 -2
  59. package/dist/types/web/search/types.d.ts +66 -1
  60. package/package.json +15 -9
  61. package/scripts/build-binary.ts +12 -0
  62. package/src/capability/skill.ts +7 -0
  63. package/src/cli/args.ts +1 -1
  64. package/src/cli/session-picker.ts +1 -0
  65. package/src/cli/update-cli.ts +54 -2
  66. package/src/commands/completions.ts +1 -1
  67. package/src/config/append-only-context-mode.ts +37 -0
  68. package/src/config/models-config-schema.ts +1 -0
  69. package/src/config/settings-schema.ts +24 -57
  70. package/src/debug/index.ts +67 -1
  71. package/src/debug/protocol-probe.ts +267 -0
  72. package/src/debug/terminal-info.ts +127 -0
  73. package/src/exa/mcp-client.ts +11 -5
  74. package/src/export/html/template.generated.ts +1 -1
  75. package/src/export/html/template.js +3 -3
  76. package/src/extensibility/custom-tools/types.ts +1 -1
  77. package/src/extensibility/extensions/types.ts +11 -0
  78. package/src/extensibility/shared-events.ts +1 -1
  79. package/src/extensibility/skills.ts +3 -3
  80. package/src/index.ts +1 -0
  81. package/src/internal-urls/docs-index.generated.ts +7 -7
  82. package/src/main.ts +16 -2
  83. package/src/mcp/json-rpc.ts +8 -0
  84. package/src/mcp/render.ts +3 -0
  85. package/src/mcp/tool-bridge.ts +10 -2
  86. package/src/mcp/transports/http.ts +33 -16
  87. package/src/mcp/transports/stdio.ts +37 -12
  88. package/src/mnemopi/state.ts +4 -4
  89. package/src/modes/acp/acp-agent.ts +168 -3
  90. package/src/modes/acp/acp-event-mapper.ts +7 -7
  91. package/src/modes/components/agent-dashboard.ts +103 -31
  92. package/src/modes/components/assistant-message.ts +3 -2
  93. package/src/modes/components/extensions/extension-dashboard.ts +56 -10
  94. package/src/modes/components/history-search.ts +128 -14
  95. package/src/modes/components/hook-selector.ts +149 -14
  96. package/src/modes/components/plugin-settings.ts +270 -36
  97. package/src/modes/components/session-selector.ts +81 -19
  98. package/src/modes/components/settings-selector.ts +1 -1
  99. package/src/modes/components/status-line/segments.ts +2 -1
  100. package/src/modes/components/status-line.ts +1 -1
  101. package/src/modes/components/tips.txt +6 -2
  102. package/src/modes/components/todo-reminder.ts +1 -1
  103. package/src/modes/components/tool-execution.ts +9 -4
  104. package/src/modes/components/transcript-container.ts +109 -0
  105. package/src/modes/controllers/command-controller.ts +4 -3
  106. package/src/modes/controllers/event-controller.ts +12 -7
  107. package/src/modes/controllers/extension-ui-controller.ts +3 -0
  108. package/src/modes/controllers/input-controller.ts +10 -5
  109. package/src/modes/controllers/selector-controller.ts +30 -19
  110. package/src/modes/controllers/todo-command-controller.ts +1 -1
  111. package/src/modes/interactive-mode.ts +56 -9
  112. package/src/modes/print-mode.ts +5 -0
  113. package/src/modes/rpc/rpc-types.ts +1 -1
  114. package/src/modes/theme/theme.ts +48 -8
  115. package/src/modes/utils/keybinding-matchers.ts +10 -0
  116. package/src/modes/utils/ui-helpers.ts +1 -0
  117. package/src/plan-mode/plan-handoff.ts +37 -0
  118. package/src/priority.json +4 -0
  119. package/src/prompts/goals/goal-continuation.md +1 -1
  120. package/src/prompts/steering/user-interjection.md +10 -0
  121. package/src/prompts/system/agent-creation-architect.md +1 -26
  122. package/src/prompts/system/eager-todo.md +3 -3
  123. package/src/prompts/system/orchestrate-notice.md +5 -5
  124. package/src/prompts/system/plan-mode-approved.md +14 -17
  125. package/src/prompts/system/plan-mode-reference.md +3 -6
  126. package/src/prompts/system/subagent-system-prompt.md +11 -0
  127. package/src/prompts/system/system-prompt.md +143 -145
  128. package/src/prompts/system/title-system.md +3 -2
  129. package/src/prompts/system/workflow-notice.md +1 -1
  130. package/src/prompts/tools/browser.md +33 -30
  131. package/src/prompts/tools/render-mermaid.md +2 -2
  132. package/src/prompts/tools/search.md +1 -1
  133. package/src/prompts/tools/task.md +3 -1
  134. package/src/prompts/tools/{todo-write.md → todo.md} +5 -5
  135. package/src/sdk.ts +6 -21
  136. package/src/session/agent-session.ts +44 -21
  137. package/src/session/history-storage.ts +11 -18
  138. package/src/session/indexed-session-storage.ts +430 -0
  139. package/src/session/messages.ts +80 -0
  140. package/src/session/redis-session-storage.ts +66 -377
  141. package/src/session/session-manager.ts +109 -23
  142. package/src/session/session-storage.ts +148 -68
  143. package/src/session/sql-session-storage.ts +131 -382
  144. package/src/slash-commands/helpers/todo.ts +2 -2
  145. package/src/slash-commands/types.ts +27 -10
  146. package/src/task/executor.ts +9 -1
  147. package/src/task/index.ts +51 -1
  148. package/src/telemetry-export.ts +126 -0
  149. package/src/tiny/compiled-runtime.ts +179 -0
  150. package/src/tiny/text.ts +112 -1
  151. package/src/tiny/worker.ts +24 -2
  152. package/src/tools/ask.ts +133 -87
  153. package/src/tools/fetch.ts +17 -4
  154. package/src/tools/find.ts +2 -2
  155. package/src/tools/index.ts +6 -4
  156. package/src/tools/memory-recall.ts +1 -1
  157. package/src/tools/memory-reflect.ts +1 -1
  158. package/src/tools/path-utils.ts +16 -7
  159. package/src/tools/renderers.ts +2 -2
  160. package/src/tools/search.ts +6 -3
  161. package/src/tools/ssh.ts +26 -10
  162. package/src/tools/{todo-write.ts → todo.ts} +32 -35
  163. package/src/tools/write.ts +14 -2
  164. package/src/tui/status-line.ts +15 -4
  165. package/src/utils/session-color.ts +39 -14
  166. package/src/utils/title-generator.ts +9 -2
  167. package/src/web/search/index.ts +4 -2
  168. package/src/web/search/provider.ts +19 -35
  169. package/src/web/search/providers/base.ts +17 -0
  170. package/src/web/search/providers/exa.ts +111 -7
  171. package/src/web/search/providers/perplexity.ts +8 -4
  172. package/src/web/search/types.ts +74 -32
@@ -1,8 +1,13 @@
1
1
  /**
2
2
  * Derive a stable CSS hex accent color from a session name.
3
- * High saturation, vivid — suitable for both status bar text and border coloring.
3
+ *
4
+ * On dark themes (`surfaceLuminance` undefined) the accent is vivid (high
5
+ * saturation, high lightness). On light themes the lightness is reduced until the
6
+ * accent's perceived luminance clears {@link ACCENT_MIN_CONTRAST} against the
7
+ * actual surface it renders on — so it stays legible on near-white *and* mid-light
8
+ * backgrounds — while keeping the same per-session hue.
4
9
  */
5
- export declare function getSessionAccentHex(name: string): string;
10
+ export declare function getSessionAccentHex(name: string, surfaceLuminance?: number): string;
6
11
  /**
7
12
  * Convert a hex accent color to an ANSI-16m foreground escape sequence.
8
13
  * Returns `undefined` if `hex` is nullish or Bun.color conversion fails.
@@ -50,7 +50,7 @@ export declare function runSearchQuery(params: SearchQueryParams, options?: {
50
50
  /**
51
51
  * Web search tool implementation.
52
52
  *
53
- * Supports Anthropic, Perplexity, Exa, Brave, Jina, Kimi, Gemini, Codex, Z.AI, SearXNG, and Synthetic providers with automatic fallback.
53
+ * Supports the configured web-search provider chain with automatic fallback.
54
54
  */
55
55
  export declare class WebSearchTool implements AgentTool<typeof webSearchSchema, SearchRenderDetails> {
56
56
  #private;
@@ -1,8 +1,9 @@
1
1
  import type { AuthStorage } from "@oh-my-pi/pi-ai";
2
2
  import type { SearchProvider } from "./providers/base";
3
- import type { SearchProviderId } from "./types";
3
+ import { type SearchProviderId } from "./types";
4
4
  export type { SearchParams } from "./providers/base";
5
5
  export { SearchProvider } from "./providers/base";
6
+ export { SEARCH_PROVIDER_ORDER } from "./types";
6
7
  /** Cheap, sync metadata accessor — never triggers a provider load. */
7
8
  export declare function getSearchProviderLabel(id: SearchProviderId): string;
8
9
  /**
@@ -10,7 +11,6 @@ export declare function getSearchProviderLabel(id: SearchProviderId): string;
10
11
  * underlying module; subsequent calls return the cached singleton.
11
12
  */
12
13
  export declare function getSearchProvider(id: SearchProviderId): Promise<SearchProvider>;
13
- export declare const SEARCH_PROVIDER_ORDER: SearchProviderId[];
14
14
  /** Set the preferred web search provider from settings */
15
15
  export declare function setPreferredSearchProvider(provider: SearchProviderId | "auto"): void;
16
16
  /**
@@ -58,8 +58,22 @@ export declare abstract class SearchProvider {
58
58
  * Indicates whether this provider has the credentials/config it needs to
59
59
  * service a request right now. Implementations consult the passed
60
60
  * {@link AuthStorage} — never a sibling store.
61
+ *
62
+ * Drives auto-chain admission: providers that return `false` are skipped
63
+ * when {@link resolveProviderChain} walks the order. Explicit selection
64
+ * uses {@link isExplicitlyAvailable} instead.
61
65
  */
62
66
  abstract isAvailable(authStorage: AuthStorage): Promise<boolean> | boolean;
67
+ /**
68
+ * Returns `true` when this provider should run when the user explicitly
69
+ * selects it, even if {@link isAvailable} would reject it for the auto
70
+ * chain. Providers that ship an unauthenticated fallback (e.g. Exa's
71
+ * public MCP) override this so explicit selection still routes through
72
+ * the fallback rather than silently falling back to another provider.
73
+ *
74
+ * Defaults to mirroring {@link isAvailable}.
75
+ */
76
+ isExplicitlyAvailable(authStorage: AuthStorage): Promise<boolean> | boolean;
63
77
  /**
64
78
  * Execute a search. Credentials MUST be resolved through `params.authStorage`.
65
79
  */
@@ -50,9 +50,18 @@ export declare function buildExaRequestBody(params: ExaSearchParams): Record<str
50
50
  export declare function searchExa(params: ExaSearchParams): Promise<SearchResponse>;
51
51
  /** Search provider for Exa. */
52
52
  export declare class ExaProvider extends SearchProvider {
53
+ #private;
53
54
  readonly id = "exa";
54
55
  readonly label = "Exa";
55
56
  isAvailable(authStorage: AuthStorage): boolean;
57
+ /**
58
+ * Exa ships an unauthenticated public MCP fallback, so an explicit
59
+ * selection (programmatic or via `providers.webSearch: exa`) routes
60
+ * through MCP even when no credential is configured. The auto chain
61
+ * still uses {@link isAvailable} so an unrelated configured provider
62
+ * keeps priority over the public fallback.
63
+ */
64
+ isExplicitlyAvailable(_authStorage: AuthStorage): boolean;
56
65
  search(params: SearchParams): Promise<SearchResponse>;
57
66
  }
58
67
  export {};
@@ -16,11 +16,11 @@ export interface PerplexitySearchParams {
16
16
  system_prompt?: string;
17
17
  search_recency_filter?: "hour" | "day" | "week" | "month" | "year";
18
18
  num_results?: number;
19
- /** Maximum output tokens. Defaults to 4096. */
19
+ /** Maximum output tokens. Defaults to 8192. */
20
20
  max_tokens?: number;
21
21
  /** Sampling temperature (0–1). Lower = more focused/factual. Defaults to 0.2. */
22
22
  temperature?: number;
23
- /** Number of search results to retrieve. Defaults to 10. */
23
+ /** Number of search results to retrieve. Defaults to 20. */
24
24
  num_search_results?: number;
25
25
  authStorage: AuthStorage;
26
26
  sessionId?: string;
@@ -3,8 +3,72 @@
3
3
  *
4
4
  * Unified types for web search responses across supported providers.
5
5
  */
6
+ export declare const SEARCH_PROVIDER_ORDER: readonly ["tavily", "perplexity", "brave", "jina", "kimi", "anthropic", "gemini", "codex", "zai", "exa", "parallel", "kagi", "synthetic", "searxng"];
6
7
  /** Supported web search providers */
7
- export type SearchProviderId = "exa" | "brave" | "jina" | "kimi" | "zai" | "anthropic" | "perplexity" | "gemini" | "codex" | "tavily" | "parallel" | "kagi" | "synthetic" | "searxng";
8
+ export type SearchProviderId = (typeof SEARCH_PROVIDER_ORDER)[number];
9
+ export declare const SEARCH_PROVIDER_PREFERENCES: readonly ["auto", "tavily", "perplexity", "brave", "jina", "kimi", "anthropic", "gemini", "codex", "zai", "exa", "parallel", "kagi", "synthetic", "searxng"];
10
+ export declare const SEARCH_PROVIDER_OPTIONS: readonly [{
11
+ readonly value: "auto";
12
+ readonly label: "Auto";
13
+ readonly description: "Automatically uses the first configured web-search provider";
14
+ }, {
15
+ readonly value: "tavily";
16
+ readonly label: "Tavily";
17
+ readonly description: "Requires TAVILY_API_KEY";
18
+ }, {
19
+ readonly value: "perplexity";
20
+ readonly label: "Perplexity";
21
+ readonly description: "Requires PERPLEXITY_COOKIES or PERPLEXITY_API_KEY";
22
+ }, {
23
+ readonly value: "brave";
24
+ readonly label: "Brave";
25
+ readonly description: "Requires BRAVE_API_KEY";
26
+ }, {
27
+ readonly value: "jina";
28
+ readonly label: "Jina";
29
+ readonly description: "Requires JINA_API_KEY";
30
+ }, {
31
+ readonly value: "kimi";
32
+ readonly label: "Kimi";
33
+ readonly description: "Requires MOONSHOT_SEARCH_API_KEY or MOONSHOT_API_KEY";
34
+ }, {
35
+ readonly value: "anthropic";
36
+ readonly label: "Anthropic";
37
+ readonly description: "Claude's native web_search tool (uses Anthropic OAuth or ANTHROPIC_API_KEY)";
38
+ }, {
39
+ readonly value: "gemini";
40
+ readonly label: "Gemini";
41
+ readonly description: "Google Search grounding via Gemini (uses google-gemini-cli or google-antigravity OAuth)";
42
+ }, {
43
+ readonly value: "codex";
44
+ readonly label: "OpenAI";
45
+ readonly description: "OpenAI's native web_search (uses ChatGPT OAuth via /login openai-codex)";
46
+ }, {
47
+ readonly value: "zai";
48
+ readonly label: "Z.AI";
49
+ readonly description: "Calls Z.AI webSearchPrime MCP";
50
+ }, {
51
+ readonly value: "exa";
52
+ readonly label: "Exa";
53
+ readonly description: "Uses Exa API when EXA_API_KEY is set; falls back to Exa MCP";
54
+ }, {
55
+ readonly value: "parallel";
56
+ readonly label: "Parallel";
57
+ readonly description: "Requires PARALLEL_API_KEY";
58
+ }, {
59
+ readonly value: "kagi";
60
+ readonly label: "Kagi";
61
+ readonly description: "Requires KAGI_API_KEY and Kagi Search API beta access";
62
+ }, {
63
+ readonly value: "synthetic";
64
+ readonly label: "Synthetic";
65
+ readonly description: "Requires SYNTHETIC_API_KEY";
66
+ }, {
67
+ readonly value: "searxng";
68
+ readonly label: "SearXNG";
69
+ readonly description: "Requires SEARXNG_ENDPOINT or searxng.endpoint";
70
+ }];
71
+ export declare const SEARCH_PROVIDER_LABELS: Record<SearchProviderId, string>;
8
72
  export declare function isSearchProviderId(value: string): value is SearchProviderId;
9
73
  export declare function isSearchProviderPreference(value: string): value is SearchProviderId | "auto";
10
74
  /** Source returned by search (all providers) */
@@ -339,6 +403,7 @@ export interface PerplexityResponse {
339
403
  choices: PerplexityChoice[];
340
404
  citations?: string[] | null;
341
405
  search_results?: PerplexitySearchResult[] | null;
406
+ related_questions?: string[] | null;
342
407
  type?: PerplexityCompletionResponseType | null;
343
408
  status?: PerplexityCompletionResponseStatus | null;
344
409
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@oh-my-pi/pi-coding-agent",
4
- "version": "15.8.3",
4
+ "version": "15.9.1",
5
5
  "description": "Coding agent CLI with read, bash, edit, write tools and session management",
6
6
  "homepage": "https://omp.sh",
7
7
  "author": "Can Boluk",
@@ -47,14 +47,20 @@
47
47
  "@agentclientprotocol/sdk": "0.22.1",
48
48
  "@babel/parser": "^7.29.7",
49
49
  "@mozilla/readability": "^0.6.0",
50
- "@oh-my-pi/hashline": "15.8.3",
51
- "@oh-my-pi/omp-stats": "15.8.3",
52
- "@oh-my-pi/pi-agent-core": "15.8.3",
53
- "@oh-my-pi/pi-ai": "15.8.3",
54
- "@oh-my-pi/pi-mnemopi": "15.8.3",
55
- "@oh-my-pi/pi-natives": "15.8.3",
56
- "@oh-my-pi/pi-tui": "15.8.3",
57
- "@oh-my-pi/pi-utils": "15.8.3",
50
+ "@oh-my-pi/hashline": "15.9.1",
51
+ "@oh-my-pi/omp-stats": "15.9.1",
52
+ "@oh-my-pi/pi-agent-core": "15.9.1",
53
+ "@oh-my-pi/pi-ai": "15.9.1",
54
+ "@oh-my-pi/pi-mnemopi": "15.9.1",
55
+ "@oh-my-pi/pi-natives": "15.9.1",
56
+ "@oh-my-pi/pi-tui": "15.9.1",
57
+ "@oh-my-pi/pi-utils": "15.9.1",
58
+ "@opentelemetry/api": "^1.9.1",
59
+ "@opentelemetry/context-async-hooks": "^2.7.1",
60
+ "@opentelemetry/exporter-trace-otlp-proto": "^0.218.0",
61
+ "@opentelemetry/resources": "^2.7.1",
62
+ "@opentelemetry/sdk-trace-base": "^2.7.1",
63
+ "@opentelemetry/sdk-trace-node": "^2.7.1",
58
64
  "@puppeteer/browsers": "^3.0.4",
59
65
  "@types/turndown": "5.0.6",
60
66
  "@xterm/headless": "^6.0.0",
@@ -1,10 +1,20 @@
1
1
  #!/usr/bin/env bun
2
2
 
3
+ import { createRequire } from "node:module";
3
4
  import * as path from "node:path";
4
5
 
5
6
  const packageDir = path.join(import.meta.dir, "..");
6
7
  const outputPath = path.join(packageDir, "dist", "omp");
7
8
 
9
+ // Transformers.js is an optional, native-heavy dependency that is never bundled
10
+ // into the binary; the tiny-model worker `bun install`s it into a runtime cache
11
+ // on first use. The `catalog:` spec cannot be resolved from inside the compiled
12
+ // bunfs (issue #1763), so embed the concrete installed version here for the
13
+ // worker to pin its runtime install against.
14
+ const transformersVersion = (
15
+ createRequire(import.meta.url)("@huggingface/transformers/package.json") as { version: string }
16
+ ).version;
17
+
8
18
  function shouldAdhocSignDarwinBinary(): boolean {
9
19
  return process.platform === "darwin";
10
20
  }
@@ -40,6 +50,8 @@ async function main(): Promise<void> {
40
50
  "--keep-names",
41
51
  "--define",
42
52
  'process.env.PI_COMPILED="true"',
53
+ "--define",
54
+ `process.env.PI_TINY_TRANSFORMERS_VERSION=${JSON.stringify(transformersVersion)}`,
43
55
  "--external",
44
56
  "mupdf",
45
57
  "--root",
@@ -21,6 +21,13 @@ export interface SkillFrontmatter {
21
21
  * rather than ones the model should auto-discover.
22
22
  */
23
23
  hide?: boolean;
24
+ /**
25
+ * Agent Skills standard equivalent of `hide`.
26
+ * When `true`, the skill is excluded from the system prompt listing.
27
+ * Normalized from kebab-case `disable-model-invocation` in YAML frontmatter.
28
+ * @see https://agentskills.io/specification
29
+ */
30
+ disableModelInvocation?: boolean;
24
31
  [key: string]: unknown;
25
32
  }
26
33
 
package/src/cli/args.ts CHANGED
@@ -313,7 +313,7 @@ ${chalk.bold("Available Tools (default-enabled unless noted):")}
313
313
  inspect_image - Analyze images with a vision model
314
314
  browser - Browser automation (Puppeteer)
315
315
  task - Launch sub-agents for parallel tasks
316
- todo_write - Manage todo/task lists
316
+ todo - Manage todo/task lists
317
317
  web_search - Search the web
318
318
  ask - Ask user questions (interactive mode only)
319
319
 
@@ -64,6 +64,7 @@ export async function selectSession(
64
64
  loadAllSessions: () => SessionManager.listAll(storage),
65
65
  allSessions: options?.allSessions,
66
66
  startInAllScope: options?.startInAllScope,
67
+ getTerminalRows: () => ui.terminal.rows,
67
68
  },
68
69
  );
69
70
  return selector;
@@ -27,6 +27,33 @@ const PACKAGE = "@oh-my-pi/pi-coding-agent";
27
27
  */
28
28
  const NPM_REGISTRY = "https://registry.npmjs.org/";
29
29
 
30
+ /**
31
+ * Core native addon package. Bumped in lock-step with {@link PACKAGE} so the
32
+ * version sentinel the loader looks up at runtime matches the `.node` on
33
+ * disk; see {@link buildBunInstallArgs} for why this must be installed
34
+ * explicitly rather than inherited as a transitive dependency.
35
+ */
36
+ const NATIVES_PACKAGE = "@oh-my-pi/pi-natives";
37
+
38
+ /**
39
+ * Platform tags the release pipeline publishes as
40
+ * `@oh-my-pi/pi-natives-<tag>` leaves. Mirrors `SUPPORTED_PLATFORMS` in
41
+ * `packages/natives/native/loader-state.js` and `LEAF_TARGETS` in
42
+ * `packages/natives/scripts/gen-npm-packages.ts`; kept here as the local
43
+ * source of truth so the update path stays free of cross-package imports.
44
+ */
45
+ const SUPPORTED_NATIVE_TAGS: ReadonlySet<string> = new Set([
46
+ "linux-x64",
47
+ "linux-arm64",
48
+ "darwin-x64",
49
+ "darwin-arm64",
50
+ "win32-x64",
51
+ ]);
52
+
53
+ function currentNativeTag(): string {
54
+ return `${process.platform}-${process.arch}`;
55
+ }
56
+
30
57
  interface ReleaseInfo {
31
58
  tag: string;
32
59
  version: string;
@@ -319,9 +346,34 @@ export async function replaceBinaryForUpdate(options: BinaryReplacementOptions):
319
346
  *
320
347
  * Together these two flags make `omp update` produce exactly the registry
321
348
  * lookup the version check just performed. See #1686.
349
+ *
350
+ * Also pins {@link NATIVES_PACKAGE} and the platform-specific
351
+ * `@oh-my-pi/pi-natives-<tag>` leaf to `expectedVersion`. `bun install -g`
352
+ * does not reliably refresh transitive `optionalDependencies` when the
353
+ * top-level package is the only one bumped, so the native addon and its
354
+ * version sentinel can drift out of sync with the freshly installed
355
+ * `@oh-my-pi/pi-coding-agent` and the loader aborts at
356
+ * `validateLoadedBindings` on the next launch
357
+ * (`The .node file on disk is from a different release than this loader`).
358
+ * Listing the natives explicitly forces bun to replace them in lock-step.
359
+ * The leaf is added only on tags the release pipeline actually publishes
360
+ * ({@link SUPPORTED_NATIVE_TAGS}) so unsupported platforms still fail with
361
+ * the original "no matching version" message instead of `EBADPLATFORM`.
362
+ * See #1824.
322
363
  */
323
- export function buildBunInstallArgs(expectedVersion: string): string[] {
324
- return ["install", "-g", "--no-cache", `--registry=${NPM_REGISTRY}`, `${PACKAGE}@${expectedVersion}`];
364
+ export function buildBunInstallArgs(expectedVersion: string, nativeTag: string = currentNativeTag()): string[] {
365
+ const args = [
366
+ "install",
367
+ "-g",
368
+ "--no-cache",
369
+ `--registry=${NPM_REGISTRY}`,
370
+ `${PACKAGE}@${expectedVersion}`,
371
+ `${NATIVES_PACKAGE}@${expectedVersion}`,
372
+ ];
373
+ if (SUPPORTED_NATIVE_TAGS.has(nativeTag)) {
374
+ args.push(`${NATIVES_PACKAGE}-${nativeTag}@${expectedVersion}`);
375
+ }
376
+ return args;
325
377
  }
326
378
 
327
379
  /**
@@ -51,7 +51,7 @@ export default class Completions extends Command {
51
51
 
52
52
  const config: CliConfig = { bin: APP_NAME, version: VERSION, commands: map };
53
53
  const spec = buildSpec(config, ROOT_COMMAND, aliasMap);
54
- process.stdout.write(generateCompletion(shell, spec));
54
+ await Bun.write(Bun.stdout, generateCompletion(shell, spec));
55
55
  }
56
56
  }
57
57
 
@@ -0,0 +1,37 @@
1
+ /** Provider metadata needed to resolve append-only context mode. */
2
+ export interface AppendOnlyContextModel {
3
+ provider: string;
4
+ baseUrl: string;
5
+ compat?: object;
6
+ }
7
+
8
+ function isXiaomiHost(baseUrl: string): boolean {
9
+ try {
10
+ const host = new URL(baseUrl).hostname;
11
+ return host === "xiaomimimo.com" || host.endsWith(".xiaomimimo.com");
12
+ } catch {
13
+ return false;
14
+ }
15
+ }
16
+
17
+ function shouldAutoEnableAppendOnlyContext(model: AppendOnlyContextModel | null | undefined): boolean {
18
+ if (!model) return false;
19
+ if (model.provider === "deepseek") return true;
20
+ if (isXiaomiHost(model.baseUrl)) return true;
21
+ return !!model.compat && "supportsStore" in model.compat && model.compat.supportsStore === true;
22
+ }
23
+
24
+ /** Resolves whether append-only context should be active for a model and setting. */
25
+ export function shouldEnableAppendOnlyContext(
26
+ setting: "auto" | "on" | "off" | undefined,
27
+ model: AppendOnlyContextModel | null | undefined,
28
+ ): boolean {
29
+ switch (setting ?? "auto") {
30
+ case "on":
31
+ return true;
32
+ case "off":
33
+ return false;
34
+ default:
35
+ return shouldAutoEnableAppendOnlyContext(model);
36
+ }
37
+ }
@@ -41,6 +41,7 @@ export const OpenAICompatSchema = z.object({
41
41
  openRouterRouting: OpenRouterRoutingSchema.optional(),
42
42
  vercelGatewayRouting: VercelGatewayRoutingSchema.optional(),
43
43
  extraBody: z.record(z.string(), z.unknown()).optional(),
44
+ cacheControlFormat: z.enum(["anthropic"]).optional(),
44
45
  supportsStrictMode: z.boolean().optional(),
45
46
  toolStrictMode: z.enum(["all_strict", "none"]).optional(),
46
47
  });
@@ -23,6 +23,7 @@ import {
23
23
  TINY_TITLE_MODEL_VALUES,
24
24
  } from "../tiny/models";
25
25
  import { EDIT_MODES } from "../utils/edit-mode";
26
+ import { SEARCH_PROVIDER_OPTIONS, SEARCH_PROVIDER_PREFERENCES } from "../web/search/types";
26
27
 
27
28
  /** Unified settings schema - single source of truth for all settings.
28
29
  * Unified settings schema - single source of truth for all settings.
@@ -608,6 +609,24 @@ export const SETTINGS_SCHEMA = {
608
609
  "Maximum height in terminal rows for inline images (default 20). Set to 0 to use only the viewport-based limit (60% of terminal height).",
609
610
  },
610
611
 
612
+ "tui.maxInlineImages": {
613
+ type: "number",
614
+ default: 8,
615
+ description:
616
+ "Maximum number of inline images kept as live terminal graphics (default 8). Older images fall back to a text placeholder via a full redraw once the limit is exceeded. Set to 0 to keep every image (no limit).",
617
+ },
618
+
619
+ "tui.textSizing": {
620
+ type: "boolean",
621
+ default: false,
622
+ ui: {
623
+ tab: "appearance",
624
+ label: "Large Headings (Kitty)",
625
+ description:
626
+ "Render Markdown H1 headings at 2x scale using Kitty's OSC 66 text-sizing protocol. Only takes effect on Kitty terminals; ignored everywhere else. Off by default.",
627
+ },
628
+ },
629
+
611
630
  "tui.hyperlinks": {
612
631
  type: "enum",
613
632
  values: ["off", "auto", "always"] as const,
@@ -2104,7 +2123,7 @@ export const SETTINGS_SCHEMA = {
2104
2123
  "todo.enabled": {
2105
2124
  type: "boolean",
2106
2125
  default: true,
2107
- ui: { tab: "tools", label: "Todos", description: "Enable the todo_write tool for task tracking" },
2126
+ ui: { tab: "tools", label: "Todos", description: "Enable the todo tool for task tracking" },
2108
2127
  },
2109
2128
 
2110
2129
  "todo.reminders": {
@@ -2866,65 +2885,13 @@ export const SETTINGS_SCHEMA = {
2866
2885
  // Provider selection
2867
2886
  "providers.webSearch": {
2868
2887
  type: "enum",
2869
- values: [
2870
- "auto",
2871
- "exa",
2872
- "brave",
2873
- "jina",
2874
- "kimi",
2875
- "zai",
2876
- "perplexity",
2877
- "anthropic",
2878
- "gemini",
2879
- "codex",
2880
- "tavily",
2881
- "kagi",
2882
- "synthetic",
2883
- "parallel",
2884
- "searxng",
2885
- ] as const,
2888
+ values: SEARCH_PROVIDER_PREFERENCES,
2886
2889
  default: "auto",
2887
2890
  ui: {
2888
2891
  tab: "providers",
2889
2892
  label: "Web Search Provider",
2890
2893
  description: "Provider for web search tool",
2891
- options: [
2892
- {
2893
- value: "auto",
2894
- label: "Auto",
2895
- description: "Preferred web-search provider",
2896
- },
2897
- { value: "exa", label: "Exa", description: "Requires EXA_API_KEY" },
2898
- { value: "brave", label: "Brave", description: "Requires BRAVE_API_KEY" },
2899
- { value: "jina", label: "Jina", description: "Requires JINA_API_KEY" },
2900
- { value: "kimi", label: "Kimi", description: "Requires MOONSHOT_SEARCH_API_KEY or MOONSHOT_API_KEY" },
2901
- {
2902
- value: "perplexity",
2903
- label: "Perplexity",
2904
- description: "Requires PERPLEXITY_COOKIES or PERPLEXITY_API_KEY",
2905
- },
2906
- {
2907
- value: "anthropic",
2908
- label: "Anthropic",
2909
- description: "Claude's native web_search tool (uses Anthropic OAuth or ANTHROPIC_API_KEY)",
2910
- },
2911
- {
2912
- value: "codex",
2913
- label: "OpenAI",
2914
- description: "OpenAI's native web_search (uses ChatGPT OAuth via /login openai-codex)",
2915
- },
2916
- {
2917
- value: "gemini",
2918
- label: "Gemini",
2919
- description: "Google Search grounding via Gemini (uses google-gemini-cli or google-antigravity OAuth)",
2920
- },
2921
- { value: "zai", label: "Z.AI", description: "Calls Z.AI webSearchPrime MCP" },
2922
- { value: "tavily", label: "Tavily", description: "Requires TAVILY_API_KEY" },
2923
- { value: "kagi", label: "Kagi", description: "Requires KAGI_API_KEY (Kagi V1 Search API)" },
2924
- { value: "synthetic", label: "Synthetic", description: "Requires SYNTHETIC_API_KEY" },
2925
- { value: "parallel", label: "Parallel", description: "Requires PARALLEL_API_KEY" },
2926
- { value: "searxng", label: "SearXNG", description: "Requires SEARXNG_ENDPOINT or searxng.endpoint" },
2927
- ],
2894
+ options: SEARCH_PROVIDER_OPTIONS,
2928
2895
  },
2929
2896
  },
2930
2897
  "providers.image": {
@@ -3090,9 +3057,9 @@ export const SETTINGS_SCHEMA = {
3090
3057
  tab: "providers",
3091
3058
  label: "Append-Only Context",
3092
3059
  description:
3093
- "Cache system prompt + tool specs and keep an append-only message log so provider prefix caches (DeepSeek, Anthropic) hit at maximum rate. Auto enables for DeepSeek.",
3060
+ "Cache system prompt + tool specs and keep an append-only message log so provider prefix caches (DeepSeek, Xiaomi/SGLang, Anthropic) hit at maximum rate. Auto enables for known prefix-cache providers.",
3094
3061
  options: [
3095
- { value: "auto", label: "Auto", description: "Enable for DeepSeek (recommended)" },
3062
+ { value: "auto", label: "Auto", description: "Enable for known prefix-cache providers (recommended)" },
3096
3063
  { value: "on", label: "On", description: "Always enable append-only context" },
3097
3064
  { value: "off", label: "Off", description: "Disable append-only context" },
3098
3065
  ],
@@ -6,7 +6,17 @@
6
6
  import * as fs from "node:fs/promises";
7
7
  import * as url from "node:url";
8
8
  import { getWorkProfile } from "@oh-my-pi/pi-natives";
9
- import { Container, Loader, type SelectItem, SelectList, Spacer, Text } from "@oh-my-pi/pi-tui";
9
+ import {
10
+ Container,
11
+ isNotificationSuppressed,
12
+ Loader,
13
+ type SelectItem,
14
+ SelectList,
15
+ Spacer,
16
+ TERMINAL,
17
+ type TerminalNotification,
18
+ Text,
19
+ } from "@oh-my-pi/pi-tui";
10
20
  import { getSessionsDir } from "@oh-my-pi/pi-utils";
11
21
  import { DynamicBorder } from "../modes/components/dynamic-border";
12
22
  import { getSelectListTheme, getSymbolTheme, theme } from "../modes/theme/theme";
@@ -15,10 +25,12 @@ import { formatBytes } from "../tools/render-utils";
15
25
  import { openPath } from "../utils/open";
16
26
  import { DebugLogViewerComponent } from "./log-viewer";
17
27
  import { generateHeapSnapshotData, type ProfilerSession, startCpuProfile } from "./profiler";
28
+ import { buildSampleImage, ProtocolProbeComponent } from "./protocol-probe";
18
29
  import { RawSseViewerComponent } from "./raw-sse";
19
30
  import { resolveRawSseDebugBuffer } from "./raw-sse-buffer";
20
31
  import { clearArtifactCache, createDebugLogSource, createReportBundle, getArtifactCacheStats } from "./report-bundle";
21
32
  import { collectSystemInfo, formatSystemInfo } from "./system-info";
33
+ import { collectTerminalState, formatTerminalState } from "./terminal-info";
22
34
 
23
35
  /** Debug menu options */
24
36
  const DEBUG_MENU_ITEMS: SelectItem[] = [
@@ -29,6 +41,12 @@ const DEBUG_MENU_ITEMS: SelectItem[] = [
29
41
  { value: "memory", label: "Report: memory issue", description: "Heap snapshot + bundle" },
30
42
  { value: "logs", label: "View: recent logs", description: "Show last 50 log entries" },
31
43
  { value: "system", label: "View: system info", description: "Show environment details" },
44
+ { value: "terminal", label: "View: terminal state", description: "Subprotocols, geometry, scrollback strategy" },
45
+ {
46
+ value: "protocols",
47
+ label: "Test: terminal protocols",
48
+ description: "Styling, links, text sizing, graphics, notify",
49
+ },
32
50
  { value: "raw-sse", label: "View: raw SSE stream", description: "Show live provider SSE frames" },
33
51
  {
34
52
  value: "transcript",
@@ -106,6 +124,12 @@ export class DebugSelectorComponent extends Container {
106
124
  case "system":
107
125
  await this.#handleViewSystemInfo();
108
126
  break;
127
+ case "terminal":
128
+ await this.#handleViewTerminalState();
129
+ break;
130
+ case "protocols":
131
+ await this.#handleViewProtocols();
132
+ break;
109
133
  case "transcript":
110
134
  await this.#handleTranscriptExport();
111
135
  break;
@@ -352,6 +376,48 @@ export class DebugSelectorComponent extends Container {
352
376
  this.ctx.ui.requestRender();
353
377
  }
354
378
 
379
+ async #handleViewTerminalState(): Promise<void> {
380
+ const info = collectTerminalState({
381
+ columns: this.ctx.ui.terminal.columns,
382
+ rows: this.ctx.ui.terminal.rows,
383
+ synchronizedOutput: this.ctx.ui.synchronizedOutput,
384
+ });
385
+ const formatted = formatTerminalState(info);
386
+
387
+ this.ctx.chatContainer.addChild(new Spacer(1));
388
+ this.ctx.chatContainer.addChild(new DynamicBorder());
389
+ this.ctx.chatContainer.addChild(new Text(formatted, 1, 0));
390
+ this.ctx.chatContainer.addChild(new DynamicBorder());
391
+ this.ctx.ui.requestRender();
392
+ }
393
+
394
+ async #handleViewProtocols(): Promise<void> {
395
+ // Fire the desktop notification as a real side effect, then render a
396
+ // panel that samples every other special protocol and reports the
397
+ // notification outcome.
398
+ const suppressed = isNotificationSuppressed();
399
+ if (!suppressed) {
400
+ const sessionName = this.ctx.sessionManager.getSessionName();
401
+ const notification: TerminalNotification = {
402
+ title: sessionName || "Oh My Pi",
403
+ body: "Terminal protocol test",
404
+ type: "test",
405
+ actions: "focus",
406
+ };
407
+ TERMINAL.sendNotification(notification);
408
+ }
409
+
410
+ this.ctx.chatContainer.addChild(new Spacer(1));
411
+ this.ctx.chatContainer.addChild(
412
+ new ProtocolProbeComponent({
413
+ image: buildSampleImage(),
414
+ imageBudget: this.ctx.ui.imageBudget,
415
+ notificationSuppressed: suppressed,
416
+ }),
417
+ );
418
+ this.ctx.ui.requestRender();
419
+ }
420
+
355
421
  async #handleTranscriptExport(): Promise<void> {
356
422
  await this.ctx.handleDebugTranscriptCommand();
357
423
  }