@oh-my-pi/pi-coding-agent 15.9.67 → 15.10.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 (266) hide show
  1. package/CHANGELOG.md +136 -0
  2. package/dist/types/cli/args.d.ts +1 -1
  3. package/dist/types/cli/dry-balance-cli.d.ts +15 -1
  4. package/dist/types/cli/gallery-cli.d.ts +43 -0
  5. package/dist/types/cli/gallery-fixtures/agentic.d.ts +2 -0
  6. package/dist/types/cli/gallery-fixtures/codeintel.d.ts +3 -0
  7. package/dist/types/cli/gallery-fixtures/edit.d.ts +3 -0
  8. package/dist/types/cli/gallery-fixtures/fs.d.ts +2 -0
  9. package/dist/types/cli/gallery-fixtures/index.d.ts +4 -0
  10. package/dist/types/cli/gallery-fixtures/interaction.d.ts +3 -0
  11. package/dist/types/cli/gallery-fixtures/memory.d.ts +2 -0
  12. package/dist/types/cli/gallery-fixtures/misc.d.ts +3 -0
  13. package/dist/types/cli/gallery-fixtures/search.d.ts +3 -0
  14. package/dist/types/cli/gallery-fixtures/shell.d.ts +3 -0
  15. package/dist/types/cli/gallery-fixtures/types.d.ts +44 -0
  16. package/dist/types/cli/gallery-fixtures/web.d.ts +2 -0
  17. package/dist/types/cli/gallery-screenshot.d.ts +35 -0
  18. package/dist/types/commands/gallery.d.ts +47 -0
  19. package/dist/types/commit/analysis/conventional.d.ts +2 -2
  20. package/dist/types/commit/analysis/summary.d.ts +2 -2
  21. package/dist/types/commit/changelog/generate.d.ts +2 -2
  22. package/dist/types/commit/changelog/index.d.ts +2 -2
  23. package/dist/types/commit/map-reduce/index.d.ts +3 -3
  24. package/dist/types/commit/map-reduce/map-phase.d.ts +2 -2
  25. package/dist/types/commit/map-reduce/reduce-phase.d.ts +2 -2
  26. package/dist/types/commit/model-selection.d.ts +10 -4
  27. package/dist/types/config/api-key-resolver.d.ts +34 -0
  28. package/dist/types/config/keybindings.d.ts +6 -1
  29. package/dist/types/config/model-id-affixes.d.ts +2 -0
  30. package/dist/types/config/model-registry.d.ts +25 -2
  31. package/dist/types/config/settings-schema.d.ts +41 -6
  32. package/dist/types/dap/config.d.ts +14 -1
  33. package/dist/types/dap/types.d.ts +10 -0
  34. package/dist/types/extensibility/plugins/marketplace-auto-update.d.ts +8 -0
  35. package/dist/types/lsp/types.d.ts +10 -0
  36. package/dist/types/lsp/utils.d.ts +3 -2
  37. package/dist/types/main.d.ts +3 -2
  38. package/dist/types/memory-backend/index.d.ts +2 -1
  39. package/dist/types/memory-backend/resolve.d.ts +1 -1
  40. package/dist/types/memory-backend/types.d.ts +1 -1
  41. package/dist/types/modes/components/chat-block.d.ts +64 -0
  42. package/dist/types/modes/components/custom-editor.d.ts +5 -1
  43. package/dist/types/modes/components/overlay-box.d.ts +17 -0
  44. package/dist/types/modes/components/plan-review-overlay.d.ts +59 -0
  45. package/dist/types/modes/components/plan-toc.d.ts +41 -0
  46. package/dist/types/modes/components/read-tool-group.d.ts +2 -0
  47. package/dist/types/modes/components/tool-execution.d.ts +18 -0
  48. package/dist/types/modes/components/transcript-container.d.ts +11 -0
  49. package/dist/types/modes/controllers/command-controller.d.ts +1 -0
  50. package/dist/types/modes/controllers/event-controller.d.ts +0 -1
  51. package/dist/types/modes/controllers/extension-ui-controller.d.ts +0 -1
  52. package/dist/types/modes/controllers/input-controller.d.ts +1 -1
  53. package/dist/types/modes/controllers/selector-controller.d.ts +1 -1
  54. package/dist/types/modes/controllers/streaming-reveal.d.ts +22 -0
  55. package/dist/types/modes/controllers/tan-command-controller.d.ts +6 -0
  56. package/dist/types/modes/index.d.ts +5 -4
  57. package/dist/types/modes/interactive-mode.d.ts +16 -6
  58. package/dist/types/modes/setup-version.d.ts +11 -0
  59. package/dist/types/modes/setup-wizard/index.d.ts +2 -1
  60. package/dist/types/modes/setup-wizard/scenes/web-search.d.ts +2 -1
  61. package/dist/types/modes/theme/theme.d.ts +1 -1
  62. package/dist/types/modes/types.d.ts +19 -6
  63. package/dist/types/modes/utils/copy-targets.d.ts +21 -1
  64. package/dist/types/plan-mode/approved-plan.d.ts +27 -8
  65. package/dist/types/plan-mode/plan-protection.d.ts +4 -4
  66. package/dist/types/sdk.d.ts +3 -1
  67. package/dist/types/session/agent-session.d.ts +21 -0
  68. package/dist/types/session/messages.d.ts +12 -0
  69. package/dist/types/session/session-manager.d.ts +3 -1
  70. package/dist/types/slash-commands/types.d.ts +4 -6
  71. package/dist/types/task/executor.d.ts +14 -0
  72. package/dist/types/task/index.d.ts +1 -0
  73. package/dist/types/task/render.d.ts +3 -2
  74. package/dist/types/telemetry-export.d.ts +1 -1
  75. package/dist/types/tools/archive-reader.d.ts +5 -0
  76. package/dist/types/tools/ast-edit.d.ts +3 -0
  77. package/dist/types/tools/ast-grep.d.ts +3 -0
  78. package/dist/types/tools/bash.d.ts +1 -0
  79. package/dist/types/tools/eval-render.d.ts +1 -8
  80. package/dist/types/tools/fetch.d.ts +15 -7
  81. package/dist/types/tools/find.d.ts +8 -4
  82. package/dist/types/tools/grouped-file-output.d.ts +95 -12
  83. package/dist/types/tools/memory-render.d.ts +4 -1
  84. package/dist/types/tools/plan-mode-guard.d.ts +8 -9
  85. package/dist/types/tools/render-utils.d.ts +13 -9
  86. package/dist/types/tools/renderers.d.ts +16 -2
  87. package/dist/types/tools/search.d.ts +5 -1
  88. package/dist/types/tools/sqlite-reader.d.ts +1 -0
  89. package/dist/types/tools/todo.d.ts +3 -2
  90. package/dist/types/tools/write.d.ts +5 -0
  91. package/dist/types/tui/output-block.d.ts +16 -4
  92. package/dist/types/tui/status-line.d.ts +3 -0
  93. package/dist/types/utils/enhanced-paste.d.ts +20 -0
  94. package/dist/types/web/scrapers/github.d.ts +22 -0
  95. package/dist/types/web/search/providers/kimi.d.ts +1 -1
  96. package/dist/types/web/search/providers/perplexity.d.ts +8 -1
  97. package/dist/types/web/search/types.d.ts +1 -1
  98. package/package.json +9 -9
  99. package/scripts/dev-launch +42 -0
  100. package/scripts/dev-launch-preload.ts +19 -0
  101. package/src/auto-thinking/classifier.ts +5 -1
  102. package/src/cli/args.ts +2 -2
  103. package/src/cli/dry-balance-cli.ts +52 -17
  104. package/src/cli/gallery-cli.ts +226 -0
  105. package/src/cli/gallery-fixtures/agentic.ts +292 -0
  106. package/src/cli/gallery-fixtures/codeintel.ts +188 -0
  107. package/src/cli/gallery-fixtures/edit.ts +194 -0
  108. package/src/cli/gallery-fixtures/fs.ts +153 -0
  109. package/src/cli/gallery-fixtures/index.ts +40 -0
  110. package/src/cli/gallery-fixtures/interaction.ts +49 -0
  111. package/src/cli/gallery-fixtures/memory.ts +81 -0
  112. package/src/cli/gallery-fixtures/misc.ts +250 -0
  113. package/src/cli/gallery-fixtures/search.ts +213 -0
  114. package/src/cli/gallery-fixtures/shell.ts +167 -0
  115. package/src/cli/gallery-fixtures/types.ts +41 -0
  116. package/src/cli/gallery-fixtures/web.ts +158 -0
  117. package/src/cli/gallery-screenshot.ts +279 -0
  118. package/src/cli-commands.ts +1 -0
  119. package/src/commands/gallery.ts +52 -0
  120. package/src/commands/launch.ts +1 -1
  121. package/src/commit/analysis/conventional.ts +2 -2
  122. package/src/commit/analysis/summary.ts +2 -2
  123. package/src/commit/changelog/generate.ts +2 -2
  124. package/src/commit/changelog/index.ts +2 -2
  125. package/src/commit/map-reduce/index.ts +3 -3
  126. package/src/commit/map-reduce/map-phase.ts +2 -2
  127. package/src/commit/map-reduce/reduce-phase.ts +2 -2
  128. package/src/commit/model-selection.ts +33 -9
  129. package/src/commit/pipeline.ts +4 -4
  130. package/src/config/api-key-resolver.ts +58 -0
  131. package/src/config/keybindings.ts +15 -6
  132. package/src/config/model-equivalence.ts +35 -12
  133. package/src/config/model-id-affixes.ts +39 -22
  134. package/src/config/model-registry.ts +41 -18
  135. package/src/config/settings-schema.ts +28 -5
  136. package/src/config/settings.ts +31 -2
  137. package/src/dap/client.ts +14 -16
  138. package/src/dap/config.ts +41 -2
  139. package/src/dap/defaults.json +1 -0
  140. package/src/dap/session.ts +1 -0
  141. package/src/dap/types.ts +10 -0
  142. package/src/debug/index.ts +40 -54
  143. package/src/edit/renderer.ts +111 -119
  144. package/src/eval/__tests__/agent-bridge.test.ts +75 -32
  145. package/src/eval/__tests__/llm-bridge.test.ts +90 -31
  146. package/src/eval/agent-bridge.ts +34 -7
  147. package/src/eval/llm-bridge.ts +8 -3
  148. package/src/extensibility/extensions/runner.ts +1 -0
  149. package/src/extensibility/plugins/doctor.ts +0 -1
  150. package/src/extensibility/plugins/marketplace-auto-update.ts +49 -0
  151. package/src/goals/tools/goal-tool.ts +37 -27
  152. package/src/internal-urls/docs-index.generated.ts +10 -10
  153. package/src/lsp/client.ts +104 -55
  154. package/src/lsp/types.ts +10 -0
  155. package/src/lsp/utils.ts +3 -2
  156. package/src/main.ts +53 -56
  157. package/src/memories/index.ts +12 -5
  158. package/src/memory-backend/index.ts +13 -1
  159. package/src/memory-backend/resolve.ts +3 -5
  160. package/src/memory-backend/types.ts +1 -1
  161. package/src/mnemopi/backend.ts +5 -1
  162. package/src/modes/acp/acp-agent.ts +33 -26
  163. package/src/modes/components/assistant-message.ts +2 -9
  164. package/src/modes/components/chat-block.ts +111 -0
  165. package/src/modes/components/copy-selector.ts +1 -44
  166. package/src/modes/components/custom-editor.ts +33 -1
  167. package/src/modes/components/custom-message.ts +1 -3
  168. package/src/modes/components/execution-shared.ts +1 -2
  169. package/src/modes/components/hook-message.ts +1 -3
  170. package/src/modes/components/overlay-box.ts +108 -0
  171. package/src/modes/components/plan-review-overlay.ts +799 -0
  172. package/src/modes/components/plan-toc.ts +138 -0
  173. package/src/modes/components/read-tool-group.ts +20 -4
  174. package/src/modes/components/skill-message.ts +0 -1
  175. package/src/modes/components/status-line.ts +3 -5
  176. package/src/modes/components/tips.txt +1 -0
  177. package/src/modes/components/todo-reminder.ts +0 -2
  178. package/src/modes/components/tool-execution.ts +115 -90
  179. package/src/modes/components/transcript-container.ts +84 -24
  180. package/src/modes/components/user-message.ts +1 -2
  181. package/src/modes/controllers/command-controller-shared.ts +7 -6
  182. package/src/modes/controllers/command-controller.ts +70 -57
  183. package/src/modes/controllers/event-controller.ts +41 -40
  184. package/src/modes/controllers/extension-ui-controller.ts +10 -73
  185. package/src/modes/controllers/input-controller.ts +135 -122
  186. package/src/modes/controllers/mcp-command-controller.ts +69 -60
  187. package/src/modes/controllers/selector-controller.ts +25 -27
  188. package/src/modes/controllers/streaming-reveal.ts +212 -0
  189. package/src/modes/controllers/tan-command-controller.ts +173 -0
  190. package/src/modes/index.ts +5 -4
  191. package/src/modes/interactive-mode.ts +171 -82
  192. package/src/modes/setup-version.ts +11 -0
  193. package/src/modes/setup-wizard/index.ts +3 -2
  194. package/src/modes/setup-wizard/scenes/web-search.ts +3 -2
  195. package/src/modes/setup-wizard/wizard-overlay.ts +1 -1
  196. package/src/modes/theme/theme-schema.json +1 -1
  197. package/src/modes/theme/theme.ts +8 -4
  198. package/src/modes/types.ts +19 -8
  199. package/src/modes/utils/context-usage.ts +10 -6
  200. package/src/modes/utils/copy-targets.ts +133 -27
  201. package/src/modes/utils/hotkeys-markdown.ts +1 -0
  202. package/src/modes/utils/ui-helpers.ts +44 -46
  203. package/src/plan-mode/approved-plan.ts +66 -43
  204. package/src/plan-mode/plan-protection.ts +4 -4
  205. package/src/prompts/system/background-tan-dispatch.md +8 -0
  206. package/src/prompts/system/plan-mode-active.md +67 -58
  207. package/src/prompts/system/plan-mode-approved.md +1 -1
  208. package/src/sdk.ts +32 -60
  209. package/src/session/agent-session.ts +89 -13
  210. package/src/session/messages.ts +26 -0
  211. package/src/session/session-manager.ts +13 -5
  212. package/src/slash-commands/builtin-registry.ts +37 -10
  213. package/src/slash-commands/helpers/usage-report.ts +2 -0
  214. package/src/slash-commands/types.ts +4 -6
  215. package/src/task/executor.ts +25 -4
  216. package/src/task/index.ts +4 -0
  217. package/src/task/render.ts +212 -148
  218. package/src/telemetry-export.ts +25 -7
  219. package/src/tools/archive-reader.ts +64 -0
  220. package/src/tools/ask.ts +119 -164
  221. package/src/tools/ast-edit.ts +98 -71
  222. package/src/tools/ast-grep.ts +37 -43
  223. package/src/tools/bash.ts +50 -6
  224. package/src/tools/debug.ts +20 -8
  225. package/src/tools/eval-backends.ts +6 -17
  226. package/src/tools/eval-render.ts +21 -18
  227. package/src/tools/eval.ts +5 -4
  228. package/src/tools/fetch.ts +391 -91
  229. package/src/tools/find.ts +44 -30
  230. package/src/tools/gh-renderer.ts +81 -42
  231. package/src/tools/grouped-file-output.ts +272 -48
  232. package/src/tools/image-gen.ts +150 -103
  233. package/src/tools/inspect-image-renderer.ts +63 -41
  234. package/src/tools/inspect-image.ts +8 -1
  235. package/src/tools/job.ts +3 -4
  236. package/src/tools/memory-render.ts +4 -1
  237. package/src/tools/plan-mode-guard.ts +21 -39
  238. package/src/tools/read.ts +23 -16
  239. package/src/tools/render-utils.ts +38 -40
  240. package/src/tools/renderers.ts +16 -1
  241. package/src/tools/report-tool-issue.ts +1 -1
  242. package/src/tools/resolve.ts +14 -0
  243. package/src/tools/search-tool-bm25.ts +36 -23
  244. package/src/tools/search.ts +189 -95
  245. package/src/tools/sqlite-reader.ts +9 -12
  246. package/src/tools/todo.ts +138 -59
  247. package/src/tools/write.ts +100 -60
  248. package/src/tui/output-block.ts +60 -13
  249. package/src/tui/status-line.ts +5 -1
  250. package/src/utils/commit-message-generator.ts +9 -1
  251. package/src/utils/enhanced-paste.ts +202 -0
  252. package/src/utils/title-generator.ts +2 -1
  253. package/src/web/scrapers/github.ts +255 -3
  254. package/src/web/scrapers/youtube.ts +3 -2
  255. package/src/web/search/providers/anthropic.ts +25 -19
  256. package/src/web/search/providers/exa.ts +11 -3
  257. package/src/web/search/providers/kimi.ts +28 -17
  258. package/src/web/search/providers/parallel.ts +35 -24
  259. package/src/web/search/providers/perplexity.ts +199 -51
  260. package/src/web/search/providers/synthetic.ts +8 -6
  261. package/src/web/search/providers/tavily.ts +9 -8
  262. package/src/web/search/providers/zai.ts +8 -6
  263. package/src/web/search/render.ts +39 -54
  264. package/src/web/search/types.ts +5 -1
  265. package/dist/types/eval/__tests__/shared-executors.test.d.ts +0 -1
  266. package/src/eval/__tests__/shared-executors.test.ts +0 -609
@@ -13,14 +13,6 @@ import type { EvalStatusEvent, EvalToolDetails } from "../eval/types";
13
13
  import type { RenderResultOptions } from "../extensibility/custom-tools/types";
14
14
  import { type Theme } from "../modes/theme/theme";
15
15
  export declare const EVAL_DEFAULT_PREVIEW_LINES = 10;
16
- /**
17
- * Rows of source kept in the *pending* eval preview. The window follows the
18
- * streaming edge (newest lines pinned to the bottom) so you can watch the code
19
- * being written, while staying bounded — a volatile tool block taller than the
20
- * viewport would otherwise strand its scrolled-off head out of native scrollback
21
- * on ED3-risk terminals. Matches the streaming windows used by edit/write.
22
- */
23
- export declare const EVAL_STREAMING_PREVIEW_LINES = 12;
24
16
  interface EvalRenderCellArg {
25
17
  language?: string;
26
18
  code?: string;
@@ -54,6 +46,7 @@ export declare const evalToolRenderer: {
54
46
  }, options: RenderResultOptions & {
55
47
  renderContext?: EvalRenderContext;
56
48
  }, uiTheme: Theme, _args?: EvalRenderArgs): Component;
49
+ isStreamingPreviewAppendOnly(_args: EvalRenderArgs, _options: RenderResultOptions, result?: unknown): boolean;
57
50
  mergeCallAndResult: boolean;
58
51
  inline: boolean;
59
52
  };
@@ -17,14 +17,22 @@ export interface ParsedReadUrlTarget {
17
17
  ranges?: readonly LineRange[];
18
18
  }
19
19
  export declare function parseReadUrlTarget(readPath: string): ParsedReadUrlTarget | null;
20
+ /** Reader backends for {@link renderHtmlToText}, in default priority order. */
21
+ export type FetchProvider = "native" | "trafilatura" | "lynx" | "parallel" | "jina";
20
22
  /**
21
- * Render HTML to markdown using Parallel, jina, trafilatura, lynx, then the
22
- * in-process native converter. The overall `timeout` budget bounds the call,
23
- * but remote reader requests are additionally capped at `REMOTE_READER_MAX_MS`
24
- * so that a hung remote endpoint cannot prevent local fallbacks from running.
25
- * Only a real `userSignal` cancellation aborts the chain remote per-attempt
26
- * timeouts and the overall reader-mode timeout still allow later renderers
27
- * (especially the purely-local native converter) to be tried.
23
+ * Render HTML to markdown by trying reader backends in priority order: native
24
+ * (in-process), trafilatura, lynx, Parallel, then Jina. The `providers.fetch`
25
+ * setting picks the order `auto` uses the default above; any specific backend
26
+ * is tried first, then the remaining backends as fallbacks. Every backend's
27
+ * output must clear the same quality gate (>100 non-whitespace chars and not
28
+ * {@link isLowQualityOutput}) before it is accepted, otherwise the next backend
29
+ * is tried.
30
+ *
31
+ * The overall `timeout` budget bounds the whole call; remote backends (Parallel,
32
+ * Jina) are additionally capped at `REMOTE_READER_MAX_MS` so a hung endpoint
33
+ * cannot starve later renderers — especially the purely-local native converter,
34
+ * which always works on already-loaded HTML. Only a real `userSignal`
35
+ * cancellation aborts the chain (#1449).
28
36
  */
29
37
  export declare function renderHtmlToText(url: string, html: string, timeout: number, settings: Settings, userSignal: AbortSignal | undefined, storage: AgentStorage | null): Promise<{
30
38
  content: string;
@@ -15,10 +15,14 @@ declare const findSchema: z.ZodObject<{
15
15
  }, z.core.$strict>;
16
16
  export type FindToolInput = z.infer<typeof findSchema>;
17
17
  /**
18
- * Group find matches by their directory so the model doesn't pay repeated
19
- * tokens for shared path prefixes. Preserves the input order: groups appear in
20
- * the order their first member was emitted (mtime-desc for native glob), and
21
- * within a group entries keep their relative order.
18
+ * Group find matches into a multi-level directory tree so the model doesn't pay
19
+ * repeated tokens for shared path prefixes. Single-child directory chains fold
20
+ * into one header (`# a/b/c/`), so a common prefix including an absolute root
21
+ * for out-of-cwd results — collapses to a single line. Each level adds one `#`;
22
+ * files are listed bare under the deepest directory header that owns them.
23
+ *
24
+ * Order follows the input (mtime-desc for native glob): a directory appears when
25
+ * its first member is emitted, and a node's own files precede its subdirectories.
22
26
  */
23
27
  export declare function formatFindGroupedOutput(paths: readonly string[]): string;
24
28
  export interface FindToolDetails {
@@ -1,7 +1,55 @@
1
+ interface PathTreeNode {
2
+ /** Direct file leaves, in first-seen order. */
3
+ files: Array<{
4
+ name: string;
5
+ key: string;
6
+ }>;
7
+ /** Dedup set for `files` (a glob can surface the same path twice on retry). */
8
+ fileNames: Set<string>;
9
+ /** Child directories, in first-seen order. */
10
+ subdirs: Array<{
11
+ name: string;
12
+ node: PathTreeNode;
13
+ }>;
14
+ /** Dedup index for `subdirs`. */
15
+ dirIndex: Map<string, PathTreeNode>;
16
+ }
17
+ export interface PathTreeInput {
18
+ /** Path string; absolute, cwd-relative, or url-like. Backslashes are normalized. */
19
+ path: string;
20
+ /** Whether the leaf itself is a directory (trailing-slash match from find). */
21
+ isDir: boolean;
22
+ /** Opaque key carried onto file events for section lookup. Defaults to `path`. */
23
+ key?: string;
24
+ }
25
+ /** One node emitted while walking the tree: a folded directory or a file leaf. */
26
+ export interface GroupedTreeEvent {
27
+ kind: "dir" | "file";
28
+ /** 0-based nesting depth (root children are depth 0). */
29
+ depth: number;
30
+ /** Folded chain for dirs (e.g. `a/b/c`, no trailing slash); basename for files. */
31
+ name: string;
32
+ /** File key for `kind === "file"`; empty string for directories. */
33
+ key: string;
34
+ }
35
+ /**
36
+ * Build a directory tree from a flat list of paths. URL-like entries are kept
37
+ * whole as root-level file leaves (they have no meaningful directory structure).
38
+ * Absolute paths carry a leading empty segment so they share a common `/` root
39
+ * and fold like any other prefix.
40
+ */
41
+ export declare function buildPathTree(entries: Iterable<PathTreeInput>): PathTreeNode;
42
+ /**
43
+ * Depth-first walk yielding directory and file events. Directories collapse their
44
+ * single-child chains (`a` → `a/b` → `a/b/c`) so a shared prefix becomes one
45
+ * header. Each node's direct files are emitted before its subdirectories, keeping
46
+ * a file unambiguously attached to the header above it.
47
+ */
48
+ export declare function walkPathTree(node: PathTreeNode, depth?: number): Generator<GroupedTreeEvent>;
1
49
  /**
2
50
  * One file's contribution to a grouped file output. The header itself is generated
3
- * by `formatGroupedFiles` (single `#` for root files, `##` for files inside a dir);
4
- * use `headerSuffix` to tack on extras like ` (1 replacement)`.
51
+ * by `formatGroupedFiles` (one `#` per nesting level); use `headerSuffix` to tack
52
+ * on extras like ` (1 replacement)`.
5
53
  */
6
54
  export interface GroupedFileSection {
7
55
  /** Optional suffix appended to the file header. */
@@ -18,19 +66,54 @@ export interface GroupedFilesOutput {
18
66
  display: string[];
19
67
  }
20
68
  /**
21
- * Render a list of files as directory-grouped sections shared by grep, ast-grep,
22
- * ast-edit, and the LSP diagnostic formatter.
69
+ * Render a list of files as a multi-level, prefix-folded directory tree shared by
70
+ * grep, ast-grep, ast-edit, and the LSP diagnostic formatter.
23
71
  *
24
- * Layout:
25
- * # dir/
26
- * ## file.ts
72
+ * Layout (one `#` per level; the shared prefix folds into the top header):
73
+ * # packages/pkg/src/
74
+ * ## root.ts
27
75
  * …body…
28
- *
29
- * # otherdir/
30
- * ## other.ts
76
+ * ## nested/
77
+ * ### child.ts
31
78
  * …body…
32
79
  *
33
- * Files in the project root (directory `.`) become single-`#` headers without a
34
- * `## file` line, matching the existing convention.
80
+ * Files in the (folded) project root become single-`#` headers with no parent
81
+ * directory line. A blank line precedes every directory header and every
82
+ * root-level file so the renderers can split the output into collapsible groups.
35
83
  */
36
84
  export declare function formatGroupedFiles(files: string[], renderFile: (filePath: string) => GroupedFileSection): GroupedFilesOutput;
85
+ /** Per-line classification of grouped output, used by renderers for hyperlinks. */
86
+ export interface GroupedLineContext {
87
+ /** Directory header, file header, or any non-header body/content line. */
88
+ kind: "dir" | "file" | "content";
89
+ /** Number of leading `#` for headers; 0 for content lines. */
90
+ depth: number;
91
+ /** Resolved absolute path of the dir/file a header points at (when resolvable). */
92
+ headerPath?: string;
93
+ /** For content lines, the absolute path of the owning file (line hyperlinks). */
94
+ filePath?: string;
95
+ /** Header is an internal/url-like target the caller resolves itself. */
96
+ isUrl?: boolean;
97
+ }
98
+ /**
99
+ * Walk grouped output lines, tracking a directory stack keyed by header depth, so
100
+ * each header and body line can be linked back to its absolute filesystem path.
101
+ * Reconstruction is stack-based (not per-blank-group) so nested directory headers
102
+ * resolve correctly across the whole output.
103
+ *
104
+ * `headerBase` is the directory the displayed (folded) header paths are relative
105
+ * to — for grep/ast tools that is the session cwd, since display paths are
106
+ * formatted relative to cwd regardless of the (sub)directory the search was
107
+ * scoped to. `fileScope` is the initial owning file for body lines that appear
108
+ * before any header (single-file scopes have no `#` headers); it defaults to
109
+ * `headerBase` and should be passed the scoped file's absolute path.
110
+ */
111
+ export declare function classifyGroupedLines(lines: readonly string[], headerBase: string | undefined, fileScope?: string | undefined): GroupedLineContext[];
112
+ /**
113
+ * Split line indices into blank-line-separated groups, mirroring
114
+ * `splitGroupsByBlankLine`: when any blank line is present, break on runs of
115
+ * blanks; otherwise return a single group of the non-empty lines. Returning
116
+ * indices lets callers slice parallel arrays (raw lines, styled lines, contexts).
117
+ */
118
+ export declare function groupLineIndicesByBlank(rawLines: readonly string[]): number[][];
119
+ export {};
@@ -4,7 +4,10 @@
4
4
  *
5
5
  * These keep the transcript terse — one status line plus, for `retain`, one
6
6
  * `Remember: …` line per stored item — instead of the generic JSON arg tree,
7
- * which exploded multi-line memory blobs into an unreadable wall.
7
+ * which exploded multi-line memory blobs into an unreadable wall. The tool
8
+ * container is a transparent passthrough, so these renderers stay frameless:
9
+ * a status line with a couple of dim bullets reads far cleaner than boxing a
10
+ * one-line memory note.
8
11
  */
9
12
  import type { Component } from "@oh-my-pi/pi-tui";
10
13
  import type { RenderResultOptions } from "../extensibility/custom-tools/types";
@@ -1,16 +1,15 @@
1
1
  import type { ToolSession } from ".";
2
2
  /**
3
- * Resolve a write/edit target to its absolute filesystem path.
4
- *
5
- * In plan mode, transparently redirects `PLAN.md` aliases and targets whose
6
- * basename matches the plan file's basename to the canonical plan file
7
- * location at `state.planFilePath`. This lets `write` and `edit` accept the
8
- * habitual plan filename after approval even when the active artifact has a
9
- * titled path such as `local://APPROVED.md`.
10
- *
11
- * Outside plan mode (or when the basename does not match) this is a no-op.
3
+ * Resolve a write/edit target to its absolute filesystem path, honoring the
4
+ * `local://` and `vault://` schemes. Plain paths resolve against the session cwd.
12
5
  */
13
6
  export declare function resolvePlanPath(session: ToolSession, targetPath: string): string;
7
+ /**
8
+ * Plan mode keeps the working tree read-only while letting the agent draft its
9
+ * plan. Writes and edits to the `local://` artifact sandbox are allowed (that is
10
+ * where the plan and any scratch notes live); anything that would touch the
11
+ * working tree — or rename/delete a file — is rejected.
12
+ */
14
13
  export declare function enforcePlanModeWrite(session: ToolSession, targetPath: string, options?: {
15
14
  move?: string;
16
15
  op?: "create" | "update" | "delete";
@@ -46,8 +46,8 @@ export declare const TRUNCATE_LENGTHS: {
46
46
  /** Very short (task previews, badges) */
47
47
  readonly SHORT: 40;
48
48
  };
49
- /** Standard expand hint text */
50
- export declare const EXPAND_HINT = "(Ctrl+O for more)";
49
+ /** Human-readable key currently bound to tool-output expansion, e.g. `Ctrl+O`. */
50
+ export declare function expandKeyHint(): string;
51
51
  /**
52
52
  * Get first N lines of text as preview, with each line truncated.
53
53
  */
@@ -103,6 +103,14 @@ export declare function capPreviewLines(lines: string[], theme: Theme, options?:
103
103
  }): string[];
104
104
  export declare function formatMeta(meta: string[], theme: Theme): string;
105
105
  export declare function formatErrorMessage(message: string | undefined, theme: Theme): string;
106
+ /**
107
+ * Error message rendered as a subordinate detail line beneath a status header
108
+ * that already carries the error icon (e.g. `✘ Write: <path>`). The header's
109
+ * icon already signals failure, so this omits the redundant error symbol and
110
+ * "Error:" prefix that `formatErrorMessage` adds for standalone single-line
111
+ * errors, indenting two columns to sit under the header title instead.
112
+ */
113
+ export declare function formatErrorDetail(message: string | undefined, theme: Theme): string;
106
114
  export declare function formatEmptyMessage(message: string, theme: Theme): string;
107
115
  export type CodeFrameMarker = "" | " " | "*" | "+" | "-" | ">";
108
116
  export declare function formatCodeFrameLine(marker: CodeFrameMarker, lineNumber: string | number, content: string, lineNumberWidth: number): string;
@@ -155,18 +163,14 @@ export declare function capParseErrors(errors: string[] | undefined, limit?: num
155
163
  errors: string[];
156
164
  total: number;
157
165
  };
158
- /**
159
- * Group `rawLines` by blank-line separators, mirroring the historical search /
160
- * ast-grep / ast-edit renderer behavior: if any blank line is present, splits on
161
- * runs of blank lines; otherwise collapses non-empty lines into a single group.
162
- */
163
- export declare function splitGroupsByBlankLine(rawLines: string[]): string[][];
164
166
  /**
165
167
  * Standard width+expand keyed render cache used by every search-style tool
166
168
  * renderer. `compute` re-runs only when the cache key changes; the returned
167
169
  * Component is the canonical `{ render, invalidate }` pair.
168
170
  */
169
- export declare function createCachedComponent(getExpanded: () => boolean, compute: (width: number, expanded: boolean) => string[]): Component;
171
+ export declare function createCachedComponent(getExpanded: () => boolean, compute: (width: number, expanded: boolean) => string[], options?: {
172
+ paddingX?: number;
173
+ }): Component;
170
174
  /**
171
175
  * Append the indented bullet list of parse errors (capped at
172
176
  * {@link PARSE_ERRORS_LIMIT}) to `lines`, with an overflow summary line if the
@@ -6,7 +6,7 @@
6
6
  import type { Component } from "@oh-my-pi/pi-tui";
7
7
  import type { RenderResultOptions } from "../extensibility/custom-tools/types";
8
8
  import type { Theme } from "../modes/theme/theme";
9
- type ToolRenderer = {
9
+ export type ToolRenderer = {
10
10
  renderCall: (args: unknown, options: RenderResultOptions, theme: Theme) => Component;
11
11
  renderResult: (result: {
12
12
  content: Array<{
@@ -19,8 +19,22 @@ type ToolRenderer = {
19
19
  renderContext?: Record<string, unknown>;
20
20
  }, theme: Theme, args?: unknown) => Component;
21
21
  mergeCallAndResult?: boolean;
22
+ /**
23
+ * While a tool's preview is still streaming, report whether the
24
+ * currently-rendered preview is append-only: its rows only grow at the bottom
25
+ * and never re-layout above the bottom live region (a full, top-anchored
26
+ * content/code preview). The transcript reports this up to the TUI so a
27
+ * streaming preview taller than the viewport commits its scrolled-off head to
28
+ * native scrollback instead of dropping it (see
29
+ * `ToolExecutionComponent.isTranscriptBlockAppendOnly`). `result` is the
30
+ * latest (possibly partial) tool result, or `undefined` before one exists —
31
+ * `eval`/`bash` use its presence to defer committing until the streamed input
32
+ * (code) has finalized. Omit (or return `false`) for previews that slide a
33
+ * tail window or later collapse to a compact result — committing their head
34
+ * would strand stale rows.
35
+ */
36
+ isStreamingPreviewAppendOnly?: (args: unknown, options: RenderResultOptions, result?: unknown) => boolean;
22
37
  /** Render without background box, inline in the response flow */
23
38
  inline?: boolean;
24
39
  };
25
40
  export declare const toolRenderers: Record<string, ToolRenderer>;
26
- export {};
@@ -5,7 +5,7 @@ import type { RenderResultOptions } from "../extensibility/custom-tools/types";
5
5
  import type { Theme } from "../modes/theme/theme";
6
6
  import { type TruncationResult } from "../session/streaming-output";
7
7
  import type { ToolSession } from ".";
8
- import { type OutputMeta } from "./output-meta";
8
+ import type { OutputMeta } from "./output-meta";
9
9
  declare const searchSchema: z.ZodObject<{
10
10
  pattern: z.ZodString;
11
11
  paths: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
@@ -47,6 +47,10 @@ export interface SearchToolDetails {
47
47
  /** Absolute base directory used during search. Used by the renderer to resolve
48
48
  * display-relative paths to absolute paths for OSC 8 hyperlinks. */
49
49
  searchPath?: string;
50
+ /** Session cwd at search time. The renderer resolves the display-relative
51
+ * (cwd-relative) header/match paths against this for OSC 8 hyperlinks;
52
+ * `searchPath` is the scope label target, not the display-path base. */
53
+ cwd?: string;
50
54
  /** User-supplied paths whose base directory was missing on disk. The tool
51
55
  * skipped these and continued with the surviving entries; surfaced as a
52
56
  * non-fatal warning in the renderer and in the model-facing text. */
@@ -1,4 +1,5 @@
1
1
  import type { Database } from "bun:sqlite";
2
+ export declare function looksLikeSqlite(bytes: Uint8Array): boolean;
2
3
  export interface SqlitePathCandidate {
3
4
  sqlitePath: string;
4
5
  subPath: string;
@@ -146,14 +146,15 @@ export declare const TODO_STRIKE_HOLD_FRAMES = 2;
146
146
  export declare const TODO_STRIKE_REVEAL_FRAMES = 12;
147
147
  export declare const TODO_STRIKE_TOTAL_FRAMES: number;
148
148
  export declare const todoToolRenderer: {
149
- renderCall(args: TodoRenderArgs, _options: RenderResultOptions, uiTheme: Theme): Component;
149
+ renderCall(args: TodoRenderArgs, options: RenderResultOptions, uiTheme: Theme): Component;
150
150
  renderResult(result: {
151
151
  content: Array<{
152
152
  type: string;
153
153
  text?: string;
154
154
  }>;
155
155
  details?: TodoToolDetails;
156
- }, options: RenderResultOptions, uiTheme: Theme, _args?: TodoRenderArgs): Component;
156
+ isError?: boolean;
157
+ }, options: RenderResultOptions, uiTheme: Theme, args?: TodoRenderArgs): Component;
157
158
  mergeCallAndResult: boolean;
158
159
  };
159
160
  export {};
@@ -17,6 +17,9 @@ export interface WriteToolDetails {
17
17
  meta?: OutputMeta;
18
18
  /** Set when the file was auto-chmod'd because content begins with a `#!` shebang. */
19
19
  madeExecutable?: boolean;
20
+ /** Absolute filesystem path the write resolved to. Used by the renderer to wrap
21
+ * the (possibly cwd-relative) header path in an OSC 8 `file://` hyperlink. */
22
+ resolvedPath?: string;
20
23
  }
21
24
  type WriteParams = WriteToolInput;
22
25
  /**
@@ -53,12 +56,14 @@ interface WriteRenderArgs {
53
56
  }
54
57
  export declare const writeToolRenderer: {
55
58
  renderCall(args: WriteRenderArgs, options: RenderResultOptions, uiTheme: Theme): Component;
59
+ isStreamingPreviewAppendOnly(args: WriteRenderArgs, options: RenderResultOptions, _result?: unknown): boolean;
56
60
  renderResult(result: {
57
61
  content: Array<{
58
62
  type: string;
59
63
  text?: string;
60
64
  }>;
61
65
  details?: WriteToolDetails;
66
+ isError?: boolean;
62
67
  }, options: RenderResultOptions, uiTheme: Theme, args?: WriteRenderArgs): Component;
63
68
  mergeCallAndResult: boolean;
64
69
  };
@@ -2,7 +2,7 @@
2
2
  * Bordered output container with optional header and sections.
3
3
  */
4
4
  import type { Component } from "@oh-my-pi/pi-tui";
5
- import type { Theme } from "../modes/theme/theme";
5
+ import type { Theme, ThemeColor } from "../modes/theme/theme";
6
6
  import type { State } from "./types";
7
7
  export interface OutputBlockOptions {
8
8
  header?: string;
@@ -11,11 +11,16 @@ export interface OutputBlockOptions {
11
11
  sections?: Array<{
12
12
  label?: string;
13
13
  lines: string[];
14
+ separator?: boolean;
14
15
  }>;
15
16
  width: number;
16
17
  applyBg?: boolean;
18
+ contentPaddingLeft?: number;
17
19
  /** Animate the border with a sweeping dark segment (pending/running state). */
18
20
  animate?: boolean;
21
+ /** Override the state-derived border color. Used for muted "legacy" tool
22
+ * frames that should not visually compete with framed-output tools. */
23
+ borderColor?: ThemeColor;
19
24
  }
20
25
  declare const FRAMED_BLOCK_COMPONENT: unique symbol;
21
26
  export type FramedBlockComponent = Component & {
@@ -24,9 +29,9 @@ export type FramedBlockComponent = Component & {
24
29
  export declare function markFramedBlockComponent<T extends Component>(component: T): T & FramedBlockComponent;
25
30
  export declare function isFramedBlockComponent(component: Component): boolean;
26
31
  /**
27
- * Monotonic frame counter for animated borders, quantized to the TUI's ~16ms
28
- * render cap so the cache key advances once per ~60fps frame — fine enough for a
29
- * smooth segment sweep, coarse enough to coalesce multiple render passes that
32
+ * Monotonic frame counter for animated borders, quantized to the TUI's ~30fps
33
+ * render cap so the cache key advances once per animation frame — fine enough
34
+ * for a smooth segment sweep, coarse enough to coalesce multiple render passes
30
35
  * land inside the same frame.
31
36
  */
32
37
  export declare function borderShimmerTick(): number;
@@ -54,4 +59,11 @@ export declare class CachedOutputBlock {
54
59
  /** Invalidate the cache, forcing a rebuild on next render. */
55
60
  invalidate(): void;
56
61
  }
62
+ /**
63
+ * Build a self-framing tool component backed by a cached output block. The
64
+ * `build` callback returns the block options for a given width; the cache
65
+ * dedupes re-renders. Pass `borderColor: "borderMuted"` for the dim "legacy"
66
+ * look that does not compete with the state-colored framed tools.
67
+ */
68
+ export declare function framedBlock(theme: Theme, build: (width: number) => OutputBlockOptions): Component;
57
69
  export {};
@@ -5,6 +5,9 @@ import type { Theme, ThemeColor } from "../modes/theme/theme";
5
5
  import type { ToolUIStatus } from "../tools/render-utils";
6
6
  export interface StatusLineOptions {
7
7
  icon?: ToolUIStatus;
8
+ /** Pre-rendered glyph that replaces the status icon (e.g. a magnifier for
9
+ * search-family tools). Takes precedence over `icon`. */
10
+ iconOverride?: string;
8
11
  spinnerFrame?: number;
9
12
  title: string;
10
13
  titleColor?: ThemeColor;
@@ -0,0 +1,20 @@
1
+ import type { ImageContent } from "@oh-my-pi/pi-ai";
2
+ export interface Osc5522Packet {
3
+ metadata: Map<string, string>;
4
+ payload: string;
5
+ }
6
+ export interface EnhancedPasteHandlers {
7
+ write(data: string): void;
8
+ pasteText(text: string): void;
9
+ pasteImage(image: ImageContent): void | Promise<void>;
10
+ showStatus(message: string): void;
11
+ }
12
+ export declare function isOsc5522Packet(data: string): boolean;
13
+ export declare function parseOsc5522Packet(data: string): Osc5522Packet | undefined;
14
+ export declare class EnhancedPasteController {
15
+ #private;
16
+ constructor(handlers: EnhancedPasteHandlers);
17
+ enable(): void;
18
+ disable(): void;
19
+ handleInput(data: string): boolean;
20
+ }
@@ -1,4 +1,18 @@
1
1
  import type { SpecialHandler } from "./types";
2
+ interface GitHubUrl {
3
+ type: "blob" | "tree" | "repo" | "issue" | "issues" | "pull" | "pulls" | "discussion" | "discussions" | "actions-run" | "actions-job" | "other";
4
+ owner: string;
5
+ repo: string;
6
+ ref?: string;
7
+ path?: string;
8
+ number?: number;
9
+ runId?: number;
10
+ jobId?: number;
11
+ }
12
+ /**
13
+ * Parse GitHub URL into components
14
+ */
15
+ export declare function parseGitHubUrl(url: string): GitHubUrl | null;
2
16
  /**
3
17
  * Fetch from GitHub API
4
18
  */
@@ -6,7 +20,15 @@ export declare function fetchGitHubApi(endpoint: string, timeout: number, signal
6
20
  data: unknown;
7
21
  ok: boolean;
8
22
  }>;
23
+ /**
24
+ * Strip the per-line ISO-8601 timestamp prefix GitHub prepends to every job log line.
25
+ * Cuts ~28 bytes/line of noise while preserving the message text. Also drops the leading
26
+ * UTF-8 BOM GitHub puts at the start of the log file (otherwise the first line's timestamp
27
+ * survives because `^` no longer sits before a digit).
28
+ */
29
+ export declare function stripActionsLogTimestamps(logs: string): string;
9
30
  /**
10
31
  * Handle GitHub URLs specially
11
32
  */
12
33
  export declare const handleGitHub: SpecialHandler;
34
+ export {};
@@ -4,7 +4,7 @@
4
4
  * Uses Moonshot Kimi Code search API to retrieve web results.
5
5
  * Endpoint: POST https://api.kimi.com/coding/v1/search
6
6
  */
7
- import type { AuthStorage } from "@oh-my-pi/pi-ai";
7
+ import { type AuthStorage } from "@oh-my-pi/pi-ai";
8
8
  import type { SearchResponse } from "../../../web/search/types";
9
9
  import type { SearchParams } from "./base";
10
10
  import { SearchProvider } from "./base";
@@ -1,10 +1,11 @@
1
1
  /**
2
2
  * Perplexity Web Search Provider
3
3
  *
4
- * Supports three auth modes:
4
+ * Supports four auth modes:
5
5
  * - Cookies (`PERPLEXITY_COOKIES`) via `www.perplexity.ai/rest/sse/perplexity_ask`
6
6
  * - OAuth/session bearer via `AuthStorage` and `www.perplexity.ai/rest/sse/perplexity_ask`
7
7
  * - API key (`PERPLEXITY_API_KEY`) via `api.perplexity.ai/chat/completions`
8
+ * - Anonymous via `www.perplexity.ai/rest/sse/perplexity_ask`
8
9
  */
9
10
  import { type AuthStorage } from "@oh-my-pi/pi-ai";
10
11
  import type { SearchResponse } from "../../../web/search/types";
@@ -34,5 +35,11 @@ export declare class PerplexityProvider extends SearchProvider {
34
35
  readonly id = "perplexity";
35
36
  readonly label = "Perplexity";
36
37
  isAvailable(authStorage: AuthStorage): boolean;
38
+ /**
39
+ * Perplexity accepts anonymous browser-style ask requests, but keep auto
40
+ * provider selection credential-gated so a configured provider keeps priority
41
+ * over the anonymous fallback.
42
+ */
43
+ isExplicitlyAvailable(_authStorage: AuthStorage): boolean;
37
44
  search(params: SearchParams): Promise<SearchResponse>;
38
45
  }
@@ -18,7 +18,7 @@ export declare const SEARCH_PROVIDER_OPTIONS: readonly [{
18
18
  }, {
19
19
  readonly value: "perplexity";
20
20
  readonly label: "Perplexity";
21
- readonly description: "Requires PERPLEXITY_COOKIES or PERPLEXITY_API_KEY";
21
+ readonly description: "Uses auth when configured; explicit selection falls back to anonymous search";
22
22
  }, {
23
23
  readonly value: "brave";
24
24
  readonly label: "Brave";
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.9.67",
4
+ "version": "15.10.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,14 @@
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.9.67",
51
- "@oh-my-pi/omp-stats": "15.9.67",
52
- "@oh-my-pi/pi-agent-core": "15.9.67",
53
- "@oh-my-pi/pi-ai": "15.9.67",
54
- "@oh-my-pi/pi-mnemopi": "15.9.67",
55
- "@oh-my-pi/pi-natives": "15.9.67",
56
- "@oh-my-pi/pi-tui": "15.9.67",
57
- "@oh-my-pi/pi-utils": "15.9.67",
50
+ "@oh-my-pi/hashline": "15.10.1",
51
+ "@oh-my-pi/omp-stats": "15.10.1",
52
+ "@oh-my-pi/pi-agent-core": "15.10.1",
53
+ "@oh-my-pi/pi-ai": "15.10.1",
54
+ "@oh-my-pi/pi-mnemopi": "15.10.1",
55
+ "@oh-my-pi/pi-natives": "15.10.1",
56
+ "@oh-my-pi/pi-tui": "15.10.1",
57
+ "@oh-my-pi/pi-utils": "15.10.1",
58
58
  "@opentelemetry/api": "^1.9.1",
59
59
  "@opentelemetry/context-async-hooks": "^2.7.1",
60
60
  "@opentelemetry/exporter-trace-otlp-proto": "^0.218.0",
@@ -0,0 +1,42 @@
1
+ #!/bin/sh
2
+ # Dev launcher for the omp CLI, installed by `bun run install:dev`.
3
+ #
4
+ # Problem it solves: Bun reads `bunfig.toml` from the *current working
5
+ # directory* at startup and evaluates its `preload` entries before running the
6
+ # script. A bun-shebang bin (what `bun link` creates for `src/cli.ts`)
7
+ # therefore inherits whatever `preload` the directory you happen to be in
8
+ # declares. Running `omp`/`pi` inside an unrelated Bun project can execute — and
9
+ # crash on — that project's preload, e.g.
10
+ # error: Cannot find module '@v12sh/utils/frontmatter' from '.../loader.ts'
11
+ #
12
+ # Bun only reads the *exact* cwd (it does not walk parents) and ignores
13
+ # `--config`/`BUN_BE_BUN` for this, so the fix is to launch Bun from an empty,
14
+ # bunfig-free directory and restore the real cwd inside the process via the
15
+ # preload shim alongside this file.
16
+ set -e
17
+
18
+ # Resolve this script's real location even when invoked through a symlink
19
+ # (`$HOME/.bun/bin/omp` -> this file).
20
+ self=$0
21
+ while [ -L "$self" ]; do
22
+ link=$(readlink "$self")
23
+ case $link in
24
+ /*) self=$link ;;
25
+ *) self=$(dirname "$self")/$link ;;
26
+ esac
27
+ done
28
+ scripts_dir=$(CDPATH= cd -- "$(dirname -- "$self")" && pwd -P)
29
+ cli=$scripts_dir/../src/cli.ts
30
+ preload=$scripts_dir/dev-launch-preload.ts
31
+ timing_preload=$scripts_dir/../../utils/src/module-timer.ts
32
+
33
+ launch_dir=${OMP_DEV_LAUNCH_DIR:-${HOME}/.omp/.dev-cwd}
34
+ mkdir -p "$launch_dir"
35
+
36
+ OMP_LAUNCH_CWD=$PWD
37
+ export OMP_LAUNCH_CWD
38
+ cd "$launch_dir"
39
+ if [ -n "${PI_TIMING:-}" ]; then
40
+ exec bun --preload "$preload" --preload "$timing_preload" "$cli" "$@"
41
+ fi
42
+ exec bun --preload "$preload" "$cli" "$@"