@oh-my-pi/pi-coding-agent 16.0.4 → 16.0.6

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 (270) hide show
  1. package/CHANGELOG.md +94 -0
  2. package/dist/cli.js +2027 -1396
  3. package/dist/types/advisor/advise-tool.d.ts +31 -19
  4. package/dist/types/autoresearch/tools/init-experiment.d.ts +13 -17
  5. package/dist/types/autoresearch/tools/log-experiment.d.ts +17 -19
  6. package/dist/types/autoresearch/tools/run-experiment.d.ts +3 -4
  7. package/dist/types/autoresearch/tools/update-notes.d.ts +4 -5
  8. package/dist/types/cli/args.d.ts +1 -0
  9. package/dist/types/cli/bench-cli.d.ts +6 -0
  10. package/dist/types/cli/ttsr-cli.d.ts +39 -0
  11. package/dist/types/commands/launch.d.ts +3 -0
  12. package/dist/types/commands/ttsr.d.ts +57 -0
  13. package/dist/types/commit/agentic/tools/analyze-file.d.ts +4 -5
  14. package/dist/types/commit/agentic/tools/git-file-diff.d.ts +4 -5
  15. package/dist/types/commit/agentic/tools/git-hunk.d.ts +5 -6
  16. package/dist/types/commit/agentic/tools/git-overview.d.ts +4 -5
  17. package/dist/types/commit/agentic/tools/propose-changelog.d.ts +23 -24
  18. package/dist/types/commit/agentic/tools/propose-commit.d.ts +11 -32
  19. package/dist/types/commit/agentic/tools/recent-commits.d.ts +3 -4
  20. package/dist/types/commit/agentic/tools/schemas.d.ts +6 -27
  21. package/dist/types/commit/agentic/tools/split-commit.d.ts +28 -49
  22. package/dist/types/commit/changelog/generate.d.ts +12 -13
  23. package/dist/types/commit/shared-llm.d.ts +10 -37
  24. package/dist/types/config/config-file.d.ts +4 -4
  25. package/dist/types/config/keybindings.d.ts +5 -0
  26. package/dist/types/config/models-config-schema.d.ts +625 -990
  27. package/dist/types/config/models-config.d.ts +229 -217
  28. package/dist/types/config/settings-schema.d.ts +144 -25
  29. package/dist/types/edit/hashline/params.d.ts +7 -11
  30. package/dist/types/edit/index.d.ts +2 -1
  31. package/dist/types/edit/modes/apply-patch.d.ts +4 -5
  32. package/dist/types/edit/modes/patch.d.ts +15 -24
  33. package/dist/types/edit/modes/replace.d.ts +16 -17
  34. package/dist/types/eval/js/index.d.ts +1 -0
  35. package/dist/types/extensibility/custom-commands/types.d.ts +6 -3
  36. package/dist/types/extensibility/custom-tools/types.d.ts +8 -5
  37. package/dist/types/extensibility/extensions/runner.d.ts +5 -2
  38. package/dist/types/extensibility/extensions/types.d.ts +14 -10
  39. package/dist/types/extensibility/hooks/types.d.ts +7 -4
  40. package/dist/types/extensibility/legacy-pi-ai-shim.d.ts +13 -5
  41. package/dist/types/extensibility/legacy-pi-coding-agent-shim.d.ts +17 -0
  42. package/dist/types/extensibility/shared-events.d.ts +22 -1
  43. package/dist/types/extensibility/typebox.d.ts +80 -58
  44. package/dist/types/goals/tools/goal-tool.d.ts +11 -24
  45. package/dist/types/index.d.ts +2 -0
  46. package/dist/types/lsp/index.d.ts +11 -26
  47. package/dist/types/lsp/types.d.ts +12 -28
  48. package/dist/types/main.d.ts +1 -0
  49. package/dist/types/mcp/client.d.ts +8 -0
  50. package/dist/types/modes/components/btw-panel.d.ts +1 -0
  51. package/dist/types/modes/components/custom-editor.d.ts +3 -1
  52. package/dist/types/modes/components/status-line/component.d.ts +1 -1
  53. package/dist/types/modes/components/status-line/context-thresholds.d.ts +0 -1
  54. package/dist/types/modes/controllers/btw-controller.d.ts +2 -0
  55. package/dist/types/modes/controllers/input-controller.d.ts +1 -0
  56. package/dist/types/modes/interactive-mode.d.ts +3 -0
  57. package/dist/types/modes/rpc/rpc-types.d.ts +1 -1
  58. package/dist/types/modes/setup-wizard/index.d.ts +1 -0
  59. package/dist/types/modes/setup-wizard/startup-splash.d.ts +7 -0
  60. package/dist/types/modes/theme/theme.d.ts +1 -1
  61. package/dist/types/modes/types.d.ts +3 -0
  62. package/dist/types/modes/utils/context-usage.d.ts +12 -0
  63. package/dist/types/sdk.d.ts +8 -1
  64. package/dist/types/session/agent-session.d.ts +24 -0
  65. package/dist/types/session/session-persistence.d.ts +4 -0
  66. package/dist/types/startup-splash.d.ts +12 -0
  67. package/dist/types/task/types.d.ts +47 -48
  68. package/dist/types/tools/ask.d.ts +26 -27
  69. package/dist/types/tools/ast-edit.d.ts +17 -17
  70. package/dist/types/tools/ast-grep.d.ts +12 -13
  71. package/dist/types/tools/bash.d.ts +20 -17
  72. package/dist/types/tools/browser.d.ts +46 -71
  73. package/dist/types/tools/checkpoint.d.ts +14 -15
  74. package/dist/types/tools/debug.d.ts +82 -145
  75. package/dist/types/tools/eval.d.ts +30 -40
  76. package/dist/types/tools/find.d.ts +17 -18
  77. package/dist/types/tools/gh.d.ts +49 -78
  78. package/dist/types/tools/image-gen.d.ts +20 -36
  79. package/dist/types/tools/inspect-image.d.ts +10 -11
  80. package/dist/types/tools/irc.d.ts +22 -33
  81. package/dist/types/tools/job.d.ts +11 -12
  82. package/dist/types/tools/learn.d.ts +21 -28
  83. package/dist/types/tools/manage-skill.d.ts +13 -22
  84. package/dist/types/tools/memory-edit.d.ts +15 -24
  85. package/dist/types/tools/memory-recall.d.ts +7 -8
  86. package/dist/types/tools/memory-reflect.d.ts +9 -10
  87. package/dist/types/tools/memory-retain.d.ts +13 -14
  88. package/dist/types/tools/read.d.ts +8 -8
  89. package/dist/types/tools/resolve.d.ts +11 -18
  90. package/dist/types/tools/review.d.ts +9 -15
  91. package/dist/types/tools/search-tool-bm25.d.ts +9 -10
  92. package/dist/types/tools/search.d.ts +16 -17
  93. package/dist/types/tools/ssh.d.ts +14 -15
  94. package/dist/types/tools/todo.d.ts +27 -43
  95. package/dist/types/tools/tts.d.ts +8 -9
  96. package/dist/types/tools/write.d.ts +9 -10
  97. package/dist/types/tui/code-cell.d.ts +2 -0
  98. package/dist/types/tui/index.d.ts +1 -0
  99. package/dist/types/tui/width-aware-text.d.ts +23 -0
  100. package/dist/types/utils/image-vision-fallback.d.ts +28 -0
  101. package/dist/types/utils/markit.d.ts +10 -1
  102. package/dist/types/web/search/index.d.ts +17 -28
  103. package/dist/types/web/search/providers/base.d.ts +1 -0
  104. package/dist/types/web/search/providers/gemini.d.ts +1 -0
  105. package/dist/types/web/search/providers/perplexity.d.ts +0 -2
  106. package/dist/types/web/search/types.d.ts +32 -26
  107. package/package.json +14 -13
  108. package/scripts/omp +1 -1
  109. package/src/advisor/__tests__/advisor.test.ts +103 -1
  110. package/src/advisor/advise-tool.ts +47 -11
  111. package/src/autoresearch/tools/init-experiment.ts +13 -16
  112. package/src/autoresearch/tools/log-experiment.ts +15 -18
  113. package/src/autoresearch/tools/run-experiment.ts +3 -3
  114. package/src/autoresearch/tools/update-notes.ts +4 -4
  115. package/src/cli/args.ts +1 -0
  116. package/src/cli/bench-cli.ts +30 -7
  117. package/src/cli/flag-tables.ts +8 -0
  118. package/src/cli/ttsr-cli.ts +995 -0
  119. package/src/cli-commands.ts +1 -0
  120. package/src/cli.ts +7 -1
  121. package/src/collab/host.ts +2 -2
  122. package/src/commands/launch.ts +3 -0
  123. package/src/commands/ttsr.ts +125 -0
  124. package/src/commit/agentic/tools/analyze-file.ts +4 -4
  125. package/src/commit/agentic/tools/git-file-diff.ts +4 -4
  126. package/src/commit/agentic/tools/git-hunk.ts +7 -5
  127. package/src/commit/agentic/tools/git-overview.ts +4 -4
  128. package/src/commit/agentic/tools/propose-changelog.ts +18 -15
  129. package/src/commit/agentic/tools/propose-commit.ts +6 -6
  130. package/src/commit/agentic/tools/recent-commits.ts +3 -3
  131. package/src/commit/agentic/tools/schemas.ts +8 -20
  132. package/src/commit/agentic/tools/split-commit.ts +19 -23
  133. package/src/commit/analysis/summary.ts +7 -5
  134. package/src/commit/changelog/generate.ts +15 -11
  135. package/src/commit/shared-llm.ts +17 -24
  136. package/src/config/config-file.ts +13 -15
  137. package/src/config/keybindings.ts +6 -0
  138. package/src/config/models-config-schema.ts +206 -179
  139. package/src/config/settings-schema.ts +118 -2
  140. package/src/discovery/builtin-rules/index.ts +2 -0
  141. package/src/discovery/builtin-rules/ts-import-type.md +2 -2
  142. package/src/discovery/builtin-rules/ts-no-any.md +11 -2
  143. package/src/discovery/builtin-rules/ts-no-inline-cast-access.md +55 -0
  144. package/src/edit/hashline/params.ts +12 -11
  145. package/src/edit/index.ts +5 -4
  146. package/src/edit/modes/apply-patch.ts +4 -4
  147. package/src/edit/modes/patch.ts +15 -18
  148. package/src/edit/modes/replace.ts +13 -17
  149. package/src/edit/renderer.ts +0 -1
  150. package/src/eval/agent-bridge.ts +11 -13
  151. package/src/eval/completion-bridge.ts +25 -17
  152. package/src/eval/js/context-manager.ts +17 -2
  153. package/src/eval/js/index.ts +1 -1
  154. package/src/eval/py/executor.ts +2 -2
  155. package/src/eval/py/runner.py +44 -0
  156. package/src/extensibility/custom-commands/loader.ts +5 -3
  157. package/src/extensibility/custom-commands/types.ts +6 -3
  158. package/src/extensibility/custom-tools/loader.ts +4 -2
  159. package/src/extensibility/custom-tools/types.ts +8 -5
  160. package/src/extensibility/extensions/loader.ts +4 -2
  161. package/src/extensibility/extensions/runner.ts +20 -2
  162. package/src/extensibility/extensions/types.ts +22 -8
  163. package/src/extensibility/hooks/loader.ts +5 -2
  164. package/src/extensibility/hooks/types.ts +7 -4
  165. package/src/extensibility/legacy-pi-ai-shim.ts +42 -5
  166. package/src/extensibility/legacy-pi-coding-agent-shim.ts +113 -0
  167. package/src/extensibility/plugins/legacy-pi-compat.ts +13 -13
  168. package/src/extensibility/shared-events.ts +24 -0
  169. package/src/extensibility/tool-proxy.ts +4 -1
  170. package/src/extensibility/typebox.ts +778 -251
  171. package/src/goals/guided-setup.ts +12 -3
  172. package/src/goals/tools/goal-tool.ts +6 -6
  173. package/src/index.ts +2 -0
  174. package/src/internal-urls/docs-index.generated.ts +15 -13
  175. package/src/lsp/types.ts +13 -27
  176. package/src/main.ts +29 -21
  177. package/src/mcp/client.ts +38 -13
  178. package/src/mcp/render.ts +102 -89
  179. package/src/modes/components/agent-hub.ts +11 -4
  180. package/src/modes/components/branch-summary-message.ts +1 -0
  181. package/src/modes/components/btw-panel.ts +5 -1
  182. package/src/modes/components/collab-prompt-message.ts +9 -7
  183. package/src/modes/components/compaction-summary-message.ts +1 -0
  184. package/src/modes/components/custom-editor.ts +18 -0
  185. package/src/modes/components/custom-message.ts +1 -0
  186. package/src/modes/components/footer.ts +6 -5
  187. package/src/modes/components/hook-message.ts +1 -0
  188. package/src/modes/components/read-tool-group.ts +9 -3
  189. package/src/modes/components/skill-message.ts +1 -0
  190. package/src/modes/components/status-line/component.ts +139 -15
  191. package/src/modes/components/status-line/context-thresholds.ts +0 -1
  192. package/src/modes/components/todo-reminder.ts +1 -0
  193. package/src/modes/components/tool-execution.ts +17 -10
  194. package/src/modes/components/ttsr-notification.ts +1 -0
  195. package/src/modes/components/user-message.ts +6 -6
  196. package/src/modes/controllers/btw-controller.ts +69 -1
  197. package/src/modes/controllers/event-controller.ts +2 -7
  198. package/src/modes/controllers/input-controller.ts +29 -0
  199. package/src/modes/controllers/selector-controller.ts +10 -3
  200. package/src/modes/interactive-mode.ts +42 -10
  201. package/src/modes/rpc/rpc-types.ts +1 -1
  202. package/src/modes/setup-wizard/index.ts +1 -0
  203. package/src/modes/setup-wizard/scenes/sign-in.ts +77 -5
  204. package/src/modes/setup-wizard/startup-splash.ts +107 -0
  205. package/src/modes/theme/theme.ts +133 -143
  206. package/src/modes/types.ts +3 -0
  207. package/src/modes/utils/context-usage.ts +37 -20
  208. package/src/modes/utils/hotkeys-markdown.ts +1 -0
  209. package/src/prompts/system/system-prompt.md +1 -0
  210. package/src/prompts/tools/image-attachment-describe-system.md +8 -0
  211. package/src/prompts/tools/image-attachment-describe.md +10 -0
  212. package/src/sdk.ts +35 -22
  213. package/src/session/agent-session.ts +715 -255
  214. package/src/session/session-history-format.ts +11 -2
  215. package/src/session/session-loader.ts +19 -32
  216. package/src/session/session-persistence.ts +27 -11
  217. package/src/session/snapcompact-inline.ts +1 -1
  218. package/src/slash-commands/builtin-registry.ts +4 -11
  219. package/src/ssh/connection-manager.ts +3 -2
  220. package/src/startup-splash.ts +19 -0
  221. package/src/task/executor.ts +12 -7
  222. package/src/task/types.ts +44 -41
  223. package/src/tool-discovery/tool-index.ts +17 -4
  224. package/src/tools/ask.ts +14 -14
  225. package/src/tools/ast-edit.ts +17 -14
  226. package/src/tools/ast-grep.ts +10 -9
  227. package/src/tools/bash.ts +15 -10
  228. package/src/tools/browser/launch.ts +13 -0
  229. package/src/tools/browser.ts +26 -32
  230. package/src/tools/checkpoint.ts +7 -7
  231. package/src/tools/debug.ts +72 -69
  232. package/src/tools/eval.ts +18 -19
  233. package/src/tools/find.ts +20 -13
  234. package/src/tools/gh.ts +29 -49
  235. package/src/tools/image-gen.ts +94 -57
  236. package/src/tools/inspect-image.ts +8 -9
  237. package/src/tools/irc.ts +12 -12
  238. package/src/tools/job.ts +6 -6
  239. package/src/tools/learn.ts +11 -14
  240. package/src/tools/manage-skill.ts +19 -23
  241. package/src/tools/memory-edit.ts +8 -8
  242. package/src/tools/memory-recall.ts +4 -4
  243. package/src/tools/memory-reflect.ts +5 -5
  244. package/src/tools/memory-retain.ts +9 -11
  245. package/src/tools/puppeteer/02_stealth_hairline.txt +1 -1
  246. package/src/tools/puppeteer/04_stealth_iframe.txt +4 -4
  247. package/src/tools/puppeteer/05_stealth_webgl.txt +1 -1
  248. package/src/tools/puppeteer/10_stealth_plugins.txt +6 -4
  249. package/src/tools/puppeteer/12_stealth_codecs.txt +2 -2
  250. package/src/tools/puppeteer/13_stealth_worker.txt +1 -1
  251. package/src/tools/read.ts +197 -19
  252. package/src/tools/report-tool-issue.ts +6 -6
  253. package/src/tools/resolve.ts +6 -6
  254. package/src/tools/review.ts +10 -12
  255. package/src/tools/search-tool-bm25.ts +5 -5
  256. package/src/tools/search.ts +20 -29
  257. package/src/tools/ssh.ts +8 -8
  258. package/src/tools/todo.ts +16 -19
  259. package/src/tools/tts.ts +16 -15
  260. package/src/tools/write.ts +5 -5
  261. package/src/tui/code-cell.ts +44 -3
  262. package/src/tui/index.ts +1 -0
  263. package/src/tui/width-aware-text.ts +58 -0
  264. package/src/utils/image-vision-fallback.ts +197 -0
  265. package/src/utils/markit.ts +17 -2
  266. package/src/web/search/index.ts +21 -9
  267. package/src/web/search/providers/base.ts +1 -0
  268. package/src/web/search/providers/gemini.ts +56 -18
  269. package/src/web/search/providers/perplexity.ts +373 -126
  270. package/src/web/search/types.ts +28 -48
@@ -11,9 +11,9 @@ import {
11
11
  } from "@oh-my-pi/pi-natives";
12
12
  import type { EditorTheme, MarkdownTheme, SelectListTheme, SettingsListTheme, SymbolTheme } from "@oh-my-pi/pi-tui";
13
13
  import { adjustHsv, colorLuma, getCustomThemesDir, isEnoent, logger, relativeLuminance } from "@oh-my-pi/pi-utils";
14
+ import { type } from "arktype";
14
15
  import chalk from "chalk";
15
16
  import { LRUCache } from "lru-cache/raw";
16
- import { z } from "zod/v4";
17
17
  // Embed theme JSON files at build time
18
18
  import darkThemeJson from "./dark.json" with { type: "json" };
19
19
  import { defaultThemes } from "./defaults";
@@ -972,125 +972,117 @@ function normalizeSpinnerFramesOverride(
972
972
  // Types & Schema
973
973
  // ============================================================================
974
974
 
975
- const colorValueSchema = z.union([
976
- z.string(), // hex "#ff0000", var ref "primary", or empty ""
977
- z.number().int().min(0).max(255), // 256-color index
978
- ]);
979
-
980
- type ColorValue = z.infer<typeof colorValueSchema>;
981
-
982
- const THEME_COLOR_KEYS = [
983
- "accent",
984
- "border",
985
- "borderAccent",
986
- "borderMuted",
987
- "success",
988
- "error",
989
- "warning",
990
- "muted",
991
- "dim",
992
- "text",
993
- "thinkingText",
994
- "selectedBg",
995
- "userMessageBg",
996
- "userMessageText",
997
- "customMessageBg",
998
- "customMessageText",
999
- "customMessageLabel",
1000
- "toolPendingBg",
1001
- "toolSuccessBg",
1002
- "toolErrorBg",
1003
- "toolTitle",
1004
- "toolOutput",
1005
- "mdHeading",
1006
- "mdLink",
1007
- "mdLinkUrl",
1008
- "mdCode",
1009
- "mdCodeBlock",
1010
- "mdCodeBlockBorder",
1011
- "mdQuote",
1012
- "mdQuoteBorder",
1013
- "mdHr",
1014
- "mdListBullet",
1015
- "toolDiffAdded",
1016
- "toolDiffRemoved",
1017
- "toolDiffContext",
1018
- "syntaxComment",
1019
- "syntaxKeyword",
1020
- "syntaxFunction",
1021
- "syntaxVariable",
1022
- "syntaxString",
1023
- "syntaxNumber",
1024
- "syntaxType",
1025
- "syntaxOperator",
1026
- "syntaxPunctuation",
1027
- "thinkingOff",
1028
- "thinkingMinimal",
1029
- "thinkingLow",
1030
- "thinkingMedium",
1031
- "thinkingHigh",
1032
- "thinkingXhigh",
1033
- "bashMode",
1034
- "pythonMode",
1035
- "statusLineBg",
1036
- "statusLineSep",
1037
- "statusLineModel",
1038
- "statusLinePath",
1039
- "statusLineGitClean",
1040
- "statusLineGitDirty",
1041
- "statusLineContext",
1042
- "statusLineSpend",
1043
- "statusLineStaged",
1044
- "statusLineDirty",
1045
- "statusLineUntracked",
1046
- "statusLineOutput",
1047
- "statusLineCost",
1048
- "statusLineSubagents",
1049
- ] as const;
1050
-
1051
- const themeColorsSchema = z.object(
1052
- Object.fromEntries(THEME_COLOR_KEYS.map(key => [key, colorValueSchema])) as unknown as {
1053
- [K in (typeof THEME_COLOR_KEYS)[number]]: typeof colorValueSchema;
1054
- },
1055
- );
1056
-
1057
- const spinnerFramesArraySchema = z.array(z.string().min(1)).min(1);
1058
- const spinnerFramesSchema = z.union([
1059
- spinnerFramesArraySchema,
1060
- z
1061
- .object({
1062
- status: spinnerFramesArraySchema.optional(),
1063
- activity: spinnerFramesArraySchema.optional(),
1064
- })
1065
- .refine(value => value.status !== undefined || value.activity !== undefined, {
1066
- message: "spinnerFrames object must define `status` and/or `activity`",
1067
- }),
1068
- ]);
1069
-
1070
- const symbolPresetSchema = z.enum(["unicode", "nerd", "ascii"]);
1071
-
1072
- const themeJsonSchema = z.object({
1073
- $schema: z.string().optional(),
1074
- name: z.string(),
1075
- vars: z.record(z.string(), colorValueSchema).optional(),
975
+ type ColorValue = string | number;
976
+
977
+ const themeColorsSchema = type({
978
+ accent: "string | number",
979
+ border: "string | number",
980
+ borderAccent: "string | number",
981
+ borderMuted: "string | number",
982
+ success: "string | number",
983
+ error: "string | number",
984
+ warning: "string | number",
985
+ muted: "string | number",
986
+ dim: "string | number",
987
+ text: "string | number",
988
+ thinkingText: "string | number",
989
+ selectedBg: "string | number",
990
+ userMessageBg: "string | number",
991
+ userMessageText: "string | number",
992
+ customMessageBg: "string | number",
993
+ customMessageText: "string | number",
994
+ customMessageLabel: "string | number",
995
+ toolPendingBg: "string | number",
996
+ toolSuccessBg: "string | number",
997
+ toolErrorBg: "string | number",
998
+ toolTitle: "string | number",
999
+ toolOutput: "string | number",
1000
+ mdHeading: "string | number",
1001
+ mdLink: "string | number",
1002
+ mdLinkUrl: "string | number",
1003
+ mdCode: "string | number",
1004
+ mdCodeBlock: "string | number",
1005
+ mdCodeBlockBorder: "string | number",
1006
+ mdQuote: "string | number",
1007
+ mdQuoteBorder: "string | number",
1008
+ mdHr: "string | number",
1009
+ mdListBullet: "string | number",
1010
+ toolDiffAdded: "string | number",
1011
+ toolDiffRemoved: "string | number",
1012
+ toolDiffContext: "string | number",
1013
+ syntaxComment: "string | number",
1014
+ syntaxKeyword: "string | number",
1015
+ syntaxFunction: "string | number",
1016
+ syntaxVariable: "string | number",
1017
+ syntaxString: "string | number",
1018
+ syntaxNumber: "string | number",
1019
+ syntaxType: "string | number",
1020
+ syntaxOperator: "string | number",
1021
+ syntaxPunctuation: "string | number",
1022
+ thinkingOff: "string | number",
1023
+ thinkingMinimal: "string | number",
1024
+ thinkingLow: "string | number",
1025
+ thinkingMedium: "string | number",
1026
+ thinkingHigh: "string | number",
1027
+ thinkingXhigh: "string | number",
1028
+ bashMode: "string | number",
1029
+ pythonMode: "string | number",
1030
+ statusLineBg: "string | number",
1031
+ statusLineSep: "string | number",
1032
+ statusLineModel: "string | number",
1033
+ statusLinePath: "string | number",
1034
+ statusLineGitClean: "string | number",
1035
+ statusLineGitDirty: "string | number",
1036
+ statusLineContext: "string | number",
1037
+ statusLineSpend: "string | number",
1038
+ statusLineStaged: "string | number",
1039
+ statusLineDirty: "string | number",
1040
+ statusLineUntracked: "string | number",
1041
+ statusLineOutput: "string | number",
1042
+ statusLineCost: "string | number",
1043
+ statusLineSubagents: "string | number",
1044
+ });
1045
+ const spinnerFramesSchema = type("unknown").narrow((value): value is SpinnerFramesOverride => {
1046
+ if (Array.isArray(value)) {
1047
+ return value.length >= 1 && value.every(item => typeof item === "string");
1048
+ }
1049
+ if (value && typeof value === "object") {
1050
+ const obj = value as Record<string, unknown>;
1051
+ const status = obj.status;
1052
+ const activity = obj.activity;
1053
+ if (status === undefined && activity === undefined) return false;
1054
+ if (status !== undefined) {
1055
+ if (!Array.isArray(status) || status.length < 1 || !status.every(item => typeof item === "string")) {
1056
+ return false;
1057
+ }
1058
+ }
1059
+ if (activity !== undefined) {
1060
+ if (!Array.isArray(activity) || activity.length < 1 || !activity.every(item => typeof item === "string")) {
1061
+ return false;
1062
+ }
1063
+ }
1064
+ return true;
1065
+ }
1066
+ return false;
1067
+ });
1068
+ const themeJsonSchema = type({
1069
+ "$schema?": "string",
1070
+ name: "string",
1071
+ "vars?": "Record<string, string | number>",
1076
1072
  colors: themeColorsSchema,
1077
- export: z
1078
- .object({
1079
- pageBg: colorValueSchema.optional(),
1080
- cardBg: colorValueSchema.optional(),
1081
- infoBg: colorValueSchema.optional(),
1082
- })
1083
- .optional(),
1084
- symbols: z
1085
- .object({
1086
- preset: symbolPresetSchema.optional(),
1087
- overrides: z.record(z.string(), z.string()).optional(),
1088
- spinnerFrames: spinnerFramesSchema.optional(),
1089
- })
1090
- .optional(),
1073
+ "export?": {
1074
+ "pageBg?": "string | number",
1075
+ "cardBg?": "string | number",
1076
+ "infoBg?": "string | number",
1077
+ },
1078
+ "symbols?": {
1079
+ "preset?": "'unicode' | 'nerd' | 'ascii'",
1080
+ "overrides?": "Record<string, string>",
1081
+ "spinnerFrames?": spinnerFramesSchema,
1082
+ },
1091
1083
  });
1092
1084
 
1093
- type ThemeJson = z.infer<typeof themeJsonSchema>;
1085
+ type ThemeJson = typeof themeJsonSchema.infer;
1094
1086
 
1095
1087
  export type ThemeColor =
1096
1088
  | "accent"
@@ -1952,37 +1944,30 @@ async function loadThemeJson(name: string): Promise<ThemeJson> {
1952
1944
  } catch (error) {
1953
1945
  throw new Error(`Failed to parse theme ${name}: ${error}`);
1954
1946
  }
1955
- const parsed = themeJsonSchema.safeParse(json);
1956
- if (!parsed.success) {
1957
- const missingColors: string[] = [];
1958
- const otherErrors: string[] = [];
1959
-
1960
- for (const issue of parsed.error.issues) {
1961
- const parts = issue.path;
1962
- const colorKey = parts.length === 2 && parts[0] === "colors" && typeof parts[1] === "string" ? parts[1] : null;
1963
-
1964
- if (colorKey && issue.code === "invalid_type" && (issue as { received?: unknown }).received === undefined) {
1965
- missingColors.push(colorKey);
1966
- } else {
1967
- const pathStr = parts.length === 0 ? "/" : `/${parts.map(String).join("/")}`;
1968
- otherErrors.push(` - ${pathStr}: ${issue.message}`);
1969
- }
1947
+ let parsed: ThemeJson;
1948
+ try {
1949
+ parsed = themeJsonSchema(json) as ThemeJson;
1950
+ if (parsed instanceof type.errors) {
1951
+ throw new Error(parsed.summary);
1970
1952
  }
1953
+ } catch (error) {
1954
+ const errorMessage = error instanceof Error ? error.message : String(error);
1955
+ // Extract color key information if available
1956
+ const missingColorMatch = errorMessage.match(/missing keys: (.+)/i);
1957
+ const missingColors: string[] = missingColorMatch ? missingColorMatch[1].split(",").map(s => s.trim()) : [];
1971
1958
 
1972
- let errorMessage = `Invalid theme "${name}":\n`;
1959
+ let fullErrorMessage = `Invalid theme "${name}":\n`;
1973
1960
  if (missingColors.length > 0) {
1974
- errorMessage += `\nMissing required color tokens:\n`;
1975
- errorMessage += missingColors.map(c => ` - ${c}`).join("\n");
1976
- errorMessage += `\n\nPlease add these colors to your theme's "colors" object.`;
1977
- errorMessage += `\nSee the built-in themes (dark.json, light.json) for reference values.`;
1978
- }
1979
- if (otherErrors.length > 0) {
1980
- errorMessage += `\n\nOther errors:\n${otherErrors.join("\n")}`;
1961
+ fullErrorMessage += `\nMissing required color tokens:\n`;
1962
+ fullErrorMessage += missingColors.map(c => ` - ${c}`).join("\n");
1963
+ fullErrorMessage += `\n\nPlease add these colors to your theme's "colors" object.`;
1964
+ fullErrorMessage += `\nSee the built-in themes (dark.json, light.json) for reference values.`;
1981
1965
  }
1966
+ fullErrorMessage += `\n\nValidation error:\n - ${errorMessage}`;
1982
1967
 
1983
- throw new Error(errorMessage);
1968
+ throw new Error(fullErrorMessage);
1984
1969
  }
1985
- return parsed.data;
1970
+ return parsed;
1986
1971
  }
1987
1972
 
1988
1973
  interface CreateThemeOptions {
@@ -2302,8 +2287,13 @@ export function getColorBlindMode(): boolean {
2302
2287
  return currentColorBlindMode;
2303
2288
  }
2304
2289
 
2305
- export function onThemeChange(callback: () => void): void {
2290
+ export function onThemeChange(callback: () => void): () => void {
2306
2291
  onThemeChangeCallback = callback;
2292
+ return () => {
2293
+ if (onThemeChangeCallback === callback) {
2294
+ onThemeChangeCallback = undefined;
2295
+ }
2296
+ };
2307
2297
  }
2308
2298
 
2309
2299
  /**
@@ -339,6 +339,9 @@ export interface InteractiveModeContext {
339
339
  handleTanCommand(work: string): Promise<void>;
340
340
  hasActiveBtw(): boolean;
341
341
  handleBtwEscape(): boolean;
342
+ handleBtwBranchKey(): Promise<boolean>;
343
+ canBranchBtw(): boolean;
344
+ handleBtwBranch(question: string, assistantMessage: AssistantMessage): Promise<void>;
342
345
  handleOmfgCommand(complaint: string): Promise<void>;
343
346
  hasActiveOmfg(): boolean;
344
347
  handleOmfgEscape(): boolean;
@@ -1,8 +1,8 @@
1
+ import { countTokens } from "@oh-my-pi/pi-agent-core";
1
2
  import type { CompactionSettings } from "@oh-my-pi/pi-agent-core/compaction";
2
3
  import { effectiveReserveTokens, estimateTokens, resolveThresholdTokens } from "@oh-my-pi/pi-agent-core/compaction";
3
- import type { Model } from "@oh-my-pi/pi-ai";
4
- import { isZodSchema, zodToWireSchema } from "@oh-my-pi/pi-ai/utils/schema";
5
- import { countTokens } from "@oh-my-pi/pi-natives";
4
+ import type { Tool as AiTool, Model } from "@oh-my-pi/pi-ai";
5
+ import { toolWireSchema } from "@oh-my-pi/pi-ai/utils/schema";
6
6
  import { formatNumber } from "@oh-my-pi/pi-utils";
7
7
  import type { Skill } from "../../extensibility/skills";
8
8
  import type { AgentSession } from "../../session/agent-session";
@@ -61,8 +61,12 @@ export function estimateToolSchemaTokens(
61
61
  for (const tool of tools) {
62
62
  fragments.push(tool.name, tool.description);
63
63
  try {
64
- const params = tool.parameters;
65
- fragments.push(JSON.stringify((isZodSchema(params) ? zodToWireSchema(params) : params) ?? {}));
64
+ const wireTool: AiTool = {
65
+ name: tool.name,
66
+ description: tool.description,
67
+ parameters: tool.parameters as AiTool["parameters"],
68
+ };
69
+ fragments.push(JSON.stringify(toolWireSchema(wireTool) ?? {}));
66
70
  } catch {
67
71
  // Schema may contain functions or cycles; ignore.
68
72
  }
@@ -94,7 +98,7 @@ export function computeNonMessageTokens(session: AgentSession): number {
94
98
  * the status-line fast path intentionally uses the equivalent collapsed total
95
99
  * in `computeNonMessageTokens`.
96
100
  */
97
- function computeNonMessageBreakdown(session: AgentSession): {
101
+ export function computeNonMessageBreakdown(session: AgentSession): {
98
102
  skillsTokens: number;
99
103
  toolsTokens: number;
100
104
  systemContextTokens: number;
@@ -119,22 +123,37 @@ export function computeContextBreakdown(
119
123
  const model = session.model;
120
124
  const contextWindow = model?.contextWindow ?? 0;
121
125
 
126
+ const breakdown = typeof session.getContextBreakdown === "function" ? session.getContextBreakdown() : undefined;
127
+
122
128
  let messagesTokens = 0;
123
- const convo = session.messages;
124
- if (convo) {
125
- for (const message of convo) {
126
- messagesTokens += estimateTokens(message);
129
+ let skillsTokens = 0;
130
+ let toolsTokens = 0;
131
+ let systemContextTokens = 0;
132
+ let systemPromptTokens = 0;
133
+ let usedTokens = 0;
134
+
135
+ if (breakdown) {
136
+ messagesTokens = breakdown.messagesTokens;
137
+ skillsTokens = breakdown.skillsTokens;
138
+ toolsTokens = breakdown.systemToolsTokens;
139
+ systemContextTokens = breakdown.systemContextTokens;
140
+ systemPromptTokens = breakdown.systemPromptTokens;
141
+ usedTokens = breakdown.usedTokens;
142
+ } else {
143
+ const convo = session.messages;
144
+ if (convo) {
145
+ for (const message of convo) {
146
+ messagesTokens += estimateTokens(message);
147
+ }
127
148
  }
149
+ const nonMessage = computeNonMessageBreakdown(session);
150
+ skillsTokens = nonMessage.skillsTokens;
151
+ toolsTokens = nonMessage.toolsTokens;
152
+ systemContextTokens = nonMessage.systemContextTokens;
153
+ systemPromptTokens = nonMessage.systemPromptTokens;
154
+ usedTokens = skillsTokens + toolsTokens + systemContextTokens + systemPromptTokens + messagesTokens;
128
155
  }
129
156
 
130
- // The rendered system prompt already contains the skill descriptions and the
131
- // markdown tool descriptions. To present a non-overlapping breakdown:
132
- // System prompt = total system prompt text - skills section (tool descriptions stay)
133
- // Tools = JSON tool schema sent separately on the wire
134
- // Skills = the skill list embedded in the system prompt
135
- // Messages = conversation messages
136
- const { skillsTokens, toolsTokens, systemContextTokens, systemPromptTokens } = computeNonMessageBreakdown(session);
137
-
138
157
  const categories: CategoryInfo[] = [
139
158
  { id: "systemPrompt", label: "System prompt", tokens: systemPromptTokens, color: "accent", glyph: CELL_FILLED },
140
159
  { id: "systemTools", label: "System tools", tokens: toolsTokens, color: "warning", glyph: CELL_FILLED },
@@ -155,8 +174,6 @@ export function computeContextBreakdown(
155
174
  },
156
175
  ];
157
176
 
158
- const usedTokens = categories.reduce((sum, c) => sum + c.tokens, 0);
159
-
160
177
  let autoCompactBufferTokens = 0;
161
178
  if (contextWindow > 0) {
162
179
  const compactionSettings = session.settings.getGroup("compaction") as CompactionSettings;
@@ -48,6 +48,7 @@ export function buildHotkeysMarkdown(bindings: HotkeysMarkdownBindings): string
48
48
  `| \`${appKey(bindings, "app.tools.expand")}\` | Toggle tool output expansion |`,
49
49
  `| \`${appKey(bindings, "app.thinking.toggle")}\` | Toggle thinking block visibility |`,
50
50
  `| \`${appKey(bindings, "app.editor.external")}\` | Edit message in external editor |`,
51
+ `| \`${appKey(bindings, "app.retry")}\` | Retry last failed assistant turn |`,
51
52
  `| \`${appKey(bindings, "app.clipboard.pasteImage")}\` | Paste image or text from clipboard |`,
52
53
  "| Hold `Space` | Speech-to-text (push-to-talk): hold to record, release to transcribe |",
53
54
  `| \`${appKey(bindings, "app.agents.hub")}\` / \`${appKey(bindings, "app.session.observe")}\` / double-tap \`←\` (empty editor) | Open the agent hub |`,
@@ -15,6 +15,7 @@ You are a helpful assistant the team trusts with load-bearing changes, operating
15
15
  - You are not alone in this repository. You SHOULD treat unexpected changes as the user's work and adapt.
16
16
  - In user-visible terminal prose and final chat, you MAY use LaTeX math delimiters (such as $ or $$) and LaTeX math commands (such as \text, \times) to format equations, as well as (`\textcolor`, `\colorbox`, `\fcolorbox`) to colorize the output.
17
17
  - To show the user a diagram (flowchart, sequence, state, ER, etc.), you MAY emit a fenced ` ```mermaid ` code block in your final chat — the terminal renders Mermaid source as an ASCII diagram. Keep it for genuine structure/flow; prefer prose for trivial points.
18
+ - When you need a visual separator between sections of prose / sections of code, you MUST use `─` (U+2500).
18
19
 
19
20
  TOOLS
20
21
  ===================================
@@ -0,0 +1,8 @@
1
+ You are an image-analysis assistant. The user attached an image to a model that cannot see images, so your description is injected into that model's context in place of the image. The downstream model relies entirely on your text — it never sees the pixels.
2
+
3
+ Core behavior:
4
+ - Be faithful and evidence-first: distinguish direct observations from inferences.
5
+ - Transcribe ALL visible text verbatim, preserving casing, punctuation, and layout order. Mark unreadable segments explicitly rather than guessing.
6
+ - NEVER fabricate occluded, blurry, or uncertain details — say what is uncertain.
7
+ - Be thorough but compact: prefer dense, information-rich prose over filler.
8
+ - Do not add meta commentary, preambles ("This image shows…"), or closing remarks. Output only the description.
@@ -0,0 +1,10 @@
1
+ Describe this image in enough detail that a model which cannot see it can reason about its content.
2
+
3
+ Cover, where present:
4
+ - The overall scene, subject, and what is happening.
5
+ - People, objects, and their relationships, positions, colors, and counts.
6
+ - All visible text, transcribed verbatim (OCR).
7
+ - UI/screenshot elements: labels, buttons, inputs, states, errors, highlighted or disabled controls.
8
+ - Diagrams, charts, tables: structure, axes, series, and the values they encode.
9
+
10
+ Flag anything ambiguous or unreadable. Output the description as plain prose only.
package/src/sdk.ts CHANGED
@@ -21,6 +21,7 @@ import {
21
21
  getOpenAICodexTransportDetails,
22
22
  prewarmOpenAICodexResponses,
23
23
  } from "@oh-my-pi/pi-ai/providers/openai-codex-responses";
24
+ import { FALLBACK_DIALECT, preferredDialect } from "@oh-my-pi/pi-catalog/identity";
24
25
  import type { Component } from "@oh-my-pi/pi-tui";
25
26
  import {
26
27
  $env,
@@ -40,7 +41,6 @@ import { AutoLearnController, buildAutoLearnInstructions } from "./autolearn/con
40
41
  import { loadCapability } from "./capability";
41
42
  import { type Rule, ruleCapability, setActiveRules } from "./capability/rule";
42
43
  import { bucketRules } from "./capability/rule-buckets";
43
- import { createApiKeyResolver } from "./config/api-key-resolver";
44
44
  import { shouldEnableAppendOnlyContext } from "./config/append-only-context-mode";
45
45
  import { ModelRegistry } from "./config/model-registry";
46
46
  import {
@@ -415,6 +415,8 @@ export interface CreateAgentSessionOptions {
415
415
  providerSessionId?: string;
416
416
  /** Optional provider-facing prompt cache key, distinct from request lineage. */
417
417
  providerPromptCacheKey?: string;
418
+ /** Absolute wall-clock deadline in Unix epoch milliseconds. */
419
+ deadline?: number;
418
420
 
419
421
  /** Custom tools to register (in addition to built-in tools). Accepts both CustomTool and ToolDefinition. */
420
422
  customTools?: (CustomTool | ToolDefinition)[];
@@ -526,6 +528,11 @@ export interface CreateAgentSessionOptions {
526
528
 
527
529
  /** Settings instance. Default: Settings.init({ cwd, agentDir }) */
528
530
  settings?: Settings;
531
+ /**
532
+ * Legacy alias for `settings`. Older Pi extensions pass SettingsManager.create(...)
533
+ * through this field; accept it so their SDK calls keep the configured settings.
534
+ */
535
+ settingsManager?: Settings | Promise<Settings>;
529
536
 
530
537
  /** Whether UI is available (enables interactive tools like ask). Default: false */
531
538
  hasUI?: boolean;
@@ -567,10 +574,15 @@ export type DialectFormat = "auto" | "native" | Dialect;
567
574
 
568
575
  export function resolveDialect(
569
576
  format: DialectFormat,
570
- model: Pick<Model, "supportsTools"> | undefined,
577
+ model: (Pick<Model, "supportsTools"> & Partial<Pick<Model, "id">>) | undefined,
571
578
  ): Dialect | undefined {
572
579
  if (format === "native") return undefined;
573
- if (format === "auto") return model?.supportsTools === false ? "glm" : undefined;
580
+ if (format === "auto") {
581
+ if (model?.supportsTools !== false) return undefined;
582
+ if (!model.id) return "glm";
583
+ const preferred = preferredDialect(model.id);
584
+ return preferred === FALLBACK_DIALECT ? "glm" : preferred;
585
+ }
574
586
  return format;
575
587
  }
576
588
 
@@ -867,6 +879,10 @@ function isCustomTool(tool: CustomTool | ToolDefinition): tool is CustomTool {
867
879
  return !(tool as any).__isToolDefinition;
868
880
  }
869
881
 
882
+ function isLegacyBuiltinToolDefinition(tool: CustomTool | ToolDefinition): boolean {
883
+ return !isCustomTool(tool) && "__ompLegacyBuiltinTool" in tool && tool.__ompLegacyBuiltinTool === true;
884
+ }
885
+
870
886
  const TOOL_DEFINITION_MARKER = Symbol("__isToolDefinition");
871
887
 
872
888
  /** Matches the truncation applied to per-server instructions inside `rebuildSystemPrompt`. */
@@ -1131,7 +1147,9 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
1131
1147
  startupCredentialDisabledEvents.push(event);
1132
1148
  }
1133
1149
  });
1134
- const settings = options.settings ?? (await logger.time("settings", Settings.init, { cwd, agentDir }));
1150
+ const settings = await (options.settings ??
1151
+ options.settingsManager ??
1152
+ logger.time("settings", Settings.init, { cwd, agentDir }));
1135
1153
  logger.time("initializeWithSettings", initializeWithSettings, settings);
1136
1154
  if (!options.modelRegistry) {
1137
1155
  modelRegistry.refreshInBackground();
@@ -2001,12 +2019,13 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
2001
2019
  const toolContextStore = new ToolContextStore(getSessionContext);
2002
2020
 
2003
2021
  const registeredTools = extensionRunner.getAllRegisteredTools();
2022
+ const sdkCustomTools = options.customTools?.filter(tool => !isLegacyBuiltinToolDefinition(tool)) ?? [];
2004
2023
  const allCustomTools = [
2005
2024
  ...registeredTools,
2006
- ...(options.customTools?.map(tool => {
2025
+ ...sdkCustomTools.map(tool => {
2007
2026
  const definition = isCustomTool(tool) ? customToolToDefinition(tool) : tool;
2008
2027
  return { definition, extensionPath: "<sdk>" };
2009
- }) ?? []),
2028
+ }),
2010
2029
  ];
2011
2030
  // `wrapToolWithMetaNotice` runs the centralized large-output → artifact spill.
2012
2031
  // Built-in tools get it in `createTools`; extension, SDK-custom, image-gen,
@@ -2284,7 +2303,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
2284
2303
 
2285
2304
  // Custom tools and extension-registered tools are always included regardless of toolNames filter
2286
2305
  const alwaysInclude: string[] = [
2287
- ...(options.customTools?.map(t => (isCustomTool(t) ? t.name : t.name)) ?? []),
2306
+ ...sdkCustomTools.map(t => (isCustomTool(t) ? t.name : t.name)),
2288
2307
  ...registeredTools.filter(t => !t.definition.defaultInactive).map(t => t.definition.name),
2289
2308
  ];
2290
2309
  for (const name of alwaysInclude) {
@@ -2458,6 +2477,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
2458
2477
  onResponse,
2459
2478
  sessionId: providerSessionId,
2460
2479
  promptCacheKey: options.providerPromptCacheKey,
2480
+ deadline: options.deadline,
2461
2481
  transformContext,
2462
2482
  transformProviderContext,
2463
2483
  steeringMode: settings.get("steeringMode") ?? "one-at-a-time",
@@ -2475,28 +2495,21 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
2475
2495
  kimiApiFormat: settings.get("providers.kimiApiFormat") ?? "anthropic",
2476
2496
  preferWebsockets: preferOpenAICodexWebsockets,
2477
2497
  getToolContext: tc => toolContextStore.getContext(tc),
2478
- getApiKey: async (provider, ctx) => {
2479
- // Read agent.sessionId at call time so credential selection stays aligned
2480
- // with metadataResolver after /new, fork, resume, or branch switches.
2481
- // Retry steps (ctx carries an auth error) drive the central a/b/c
2482
- // policy — force-refresh the same account, then rotate to a sibling —
2483
- // and may legitimately yield no key when every account is exhausted.
2484
- if (ctx?.error !== undefined) {
2485
- return createApiKeyResolver(modelRegistry, provider, { sessionId: agent.sessionId })(ctx);
2486
- }
2487
- const key = await modelRegistry.getApiKeyForProvider(provider, agent.sessionId);
2488
- if (!key) {
2489
- throw new Error(`No API key found for provider "${provider}"`);
2490
- }
2491
- return key;
2492
- },
2498
+ getApiKey: requestModel => modelRegistry.resolver(requestModel, agent.sessionId),
2493
2499
  streamFn: (streamModel, context, streamOptions) => {
2494
2500
  const openrouterRoutingPreset = settings.get("providers.openrouterVariant");
2495
2501
  const openrouterVariant =
2496
2502
  openrouterRoutingPreset && openrouterRoutingPreset !== "default" ? openrouterRoutingPreset : undefined;
2503
+ const antigravityEndpointMode = settings.get("providers.antigravityEndpoint");
2497
2504
  return streamSimple(streamModel, context, {
2498
2505
  ...streamOptions,
2499
2506
  openrouterVariant: streamOptions?.openrouterVariant ?? openrouterVariant,
2507
+ antigravityEndpointMode: streamOptions?.antigravityEndpointMode ?? antigravityEndpointMode,
2508
+ loopGuard: {
2509
+ enabled: settings.get("model.loopGuard.enabled"),
2510
+ checkAssistantContent: settings.get("model.loopGuard.checkAssistantContent"),
2511
+ ...streamOptions?.loopGuard,
2512
+ },
2500
2513
  });
2501
2514
  },
2502
2515
  cursorExecHandlers,