@oh-my-pi/pi-coding-agent 16.1.15 → 16.1.17

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 (143) hide show
  1. package/CHANGELOG.md +78 -0
  2. package/dist/cli.js +3531 -3812
  3. package/dist/types/auto-thinking/classifier.d.ts +4 -2
  4. package/dist/types/cli/args.d.ts +2 -5
  5. package/dist/types/cli/flag-tables.d.ts +2 -2
  6. package/dist/types/cli/session-picker.d.ts +4 -2
  7. package/dist/types/commands/launch.d.ts +1 -1
  8. package/dist/types/config/model-discovery.d.ts +1 -0
  9. package/dist/types/config/model-registry.d.ts +4 -0
  10. package/dist/types/config/settings-schema.d.ts +12 -1
  11. package/dist/types/eval/agent-bridge.d.ts +19 -0
  12. package/dist/types/eval/js/shared/helpers.d.ts +1 -13
  13. package/dist/types/eval/js/shared/types.d.ts +1 -1
  14. package/dist/types/eval/js/worker-protocol.d.ts +1 -1
  15. package/dist/types/eval/py/executor.d.ts +1 -1
  16. package/dist/types/extensibility/plugins/legacy-pi-compat.d.ts +22 -7
  17. package/dist/types/extensibility/plugins/loader.d.ts +16 -9
  18. package/dist/types/extensibility/tool-event-input.d.ts +2 -0
  19. package/dist/types/hindsight/content.d.ts +2 -10
  20. package/dist/types/internal-urls/local-protocol.d.ts +18 -1
  21. package/dist/types/main.d.ts +2 -0
  22. package/dist/types/modes/components/chat-transcript-builder.d.ts +2 -0
  23. package/dist/types/modes/components/custom-editor.d.ts +3 -0
  24. package/dist/types/modes/components/plugin-settings.d.ts +5 -0
  25. package/dist/types/modes/components/session-selector.d.ts +25 -0
  26. package/dist/types/modes/components/status-line/types.d.ts +1 -0
  27. package/dist/types/modes/controllers/command-controller.d.ts +2 -0
  28. package/dist/types/modes/controllers/input-controller.d.ts +14 -0
  29. package/dist/types/modes/controllers/selector-controller.d.ts +11 -0
  30. package/dist/types/session/agent-session.d.ts +6 -6
  31. package/dist/types/session/provider-image-budget.d.ts +3 -0
  32. package/dist/types/session/session-context.d.ts +6 -5
  33. package/dist/types/task/isolation-runner.d.ts +128 -0
  34. package/dist/types/task/parallel.d.ts +4 -0
  35. package/dist/types/task/worktree.d.ts +14 -1
  36. package/dist/types/thinking.d.ts +23 -1
  37. package/dist/types/tiny/title-client.d.ts +2 -2
  38. package/dist/types/tools/eval-render.d.ts +3 -0
  39. package/dist/types/tools/eval.d.ts +11 -17
  40. package/dist/types/tools/todo.d.ts +26 -28
  41. package/dist/types/tui/output-block.d.ts +8 -0
  42. package/dist/types/utils/image-resize.d.ts +2 -0
  43. package/dist/types/utils/tools-manager.d.ts +2 -0
  44. package/dist/types/web/search/providers/exa.d.ts +2 -0
  45. package/package.json +12 -12
  46. package/scripts/build-binary.ts +18 -4
  47. package/src/auto-thinking/classifier.ts +7 -2
  48. package/src/cli/args.ts +4 -5
  49. package/src/cli/flag-tables.ts +3 -3
  50. package/src/cli/gallery-fixtures/interaction.ts +6 -9
  51. package/src/cli/gallery-fixtures/shell.ts +15 -23
  52. package/src/cli/profile-alias.ts +38 -7
  53. package/src/cli/session-picker.ts +17 -3
  54. package/src/cli/usage-cli.ts +5 -1
  55. package/src/commands/launch.ts +3 -3
  56. package/src/config/model-discovery.ts +59 -8
  57. package/src/config/model-registry.ts +74 -3
  58. package/src/config/settings-schema.ts +13 -1
  59. package/src/discovery/omp-extension-roots.ts +1 -3
  60. package/src/edit/renderer.ts +34 -12
  61. package/src/eval/__tests__/agent-bridge.test.ts +462 -3
  62. package/src/eval/__tests__/helpers-local-roots.test.ts +2 -5
  63. package/src/eval/__tests__/julia-prelude.test.ts +1 -30
  64. package/src/eval/__tests__/prelude-agent.test.ts +42 -8
  65. package/src/eval/agent-bridge.ts +301 -71
  66. package/src/eval/jl/prelude.jl +32 -227
  67. package/src/eval/jl/runner.jl +38 -12
  68. package/src/eval/js/shared/helpers.ts +1 -114
  69. package/src/eval/js/shared/prelude.txt +13 -27
  70. package/src/eval/js/shared/runtime.ts +0 -6
  71. package/src/eval/js/shared/types.ts +1 -1
  72. package/src/eval/js/worker-protocol.ts +1 -1
  73. package/src/eval/py/__tests__/prelude.test.ts +13 -0
  74. package/src/eval/py/executor.ts +1 -1
  75. package/src/eval/py/prelude.py +47 -105
  76. package/src/eval/py/runner.py +0 -6
  77. package/src/eval/rb/prelude.rb +21 -189
  78. package/src/eval/rb/runner.rb +116 -9
  79. package/src/export/html/tool-views.generated.js +29 -29
  80. package/src/extensibility/extensions/wrapper.ts +3 -2
  81. package/src/extensibility/hooks/tool-wrapper.ts +4 -3
  82. package/src/extensibility/plugins/legacy-pi-compat.ts +40 -8
  83. package/src/extensibility/plugins/loader.ts +71 -23
  84. package/src/extensibility/plugins/marketplace/manager.ts +134 -0
  85. package/src/extensibility/tool-event-input.ts +57 -0
  86. package/src/hindsight/content.ts +21 -12
  87. package/src/internal-urls/docs-index.generated.txt +1 -1
  88. package/src/internal-urls/local-protocol.ts +100 -53
  89. package/src/main.ts +15 -4
  90. package/src/mcp/tool-bridge.ts +27 -2
  91. package/src/mnemopi/state.ts +5 -2
  92. package/src/modes/acp/acp-event-mapper.ts +7 -2
  93. package/src/modes/components/agent-transcript-viewer.ts +193 -41
  94. package/src/modes/components/chat-transcript-builder.ts +6 -0
  95. package/src/modes/components/custom-editor.test.ts +18 -1
  96. package/src/modes/components/custom-editor.ts +77 -45
  97. package/src/modes/components/hook-editor.ts +15 -2
  98. package/src/modes/components/plugin-settings.ts +7 -1
  99. package/src/modes/components/session-selector.ts +143 -29
  100. package/src/modes/components/settings-selector.ts +2 -2
  101. package/src/modes/components/status-line/component.ts +52 -8
  102. package/src/modes/components/status-line/segments.ts +5 -1
  103. package/src/modes/components/status-line/types.ts +1 -0
  104. package/src/modes/components/welcome.ts +12 -14
  105. package/src/modes/controllers/command-controller.ts +21 -5
  106. package/src/modes/controllers/input-controller.ts +115 -3
  107. package/src/modes/controllers/selector-controller.ts +19 -1
  108. package/src/modes/interactive-mode.ts +3 -3
  109. package/src/modes/rpc/rpc-mode.ts +6 -0
  110. package/src/modes/utils/copy-targets.ts +7 -2
  111. package/src/modes/utils/ui-helpers.ts +3 -3
  112. package/src/prompts/system/system-prompt.md +3 -3
  113. package/src/prompts/system/workflow-notice.md +3 -3
  114. package/src/prompts/tools/bash.md +16 -0
  115. package/src/prompts/tools/eval.md +19 -19
  116. package/src/prompts/tools/todo.md +1 -1
  117. package/src/sdk.ts +8 -10
  118. package/src/session/agent-session.ts +422 -97
  119. package/src/session/provider-image-budget.ts +86 -0
  120. package/src/session/session-context.ts +14 -7
  121. package/src/session/session-storage.ts +24 -2
  122. package/src/session/snapcompact-inline.ts +19 -3
  123. package/src/slash-commands/builtin-registry.ts +0 -22
  124. package/src/slash-commands/helpers/usage-report.ts +9 -1
  125. package/src/task/index.ts +61 -207
  126. package/src/task/isolation-runner.ts +354 -0
  127. package/src/task/parallel.ts +6 -1
  128. package/src/task/worktree.ts +46 -9
  129. package/src/thinking.ts +29 -2
  130. package/src/tiny/title-client.ts +75 -21
  131. package/src/tools/ask.ts +44 -38
  132. package/src/tools/bash.ts +9 -2
  133. package/src/tools/browser/tab-worker.ts +1 -1
  134. package/src/tools/eval-render.ts +34 -27
  135. package/src/tools/eval.ts +100 -103
  136. package/src/tools/index.ts +8 -1
  137. package/src/tools/read.ts +136 -60
  138. package/src/tools/todo.ts +60 -64
  139. package/src/tui/code-cell.ts +1 -1
  140. package/src/tui/output-block.ts +11 -0
  141. package/src/utils/image-resize.ts +30 -0
  142. package/src/utils/tools-manager.ts +67 -10
  143. package/src/web/search/providers/exa.ts +85 -1
@@ -1,5 +1,19 @@
1
1
  Runs bash in a shell session — terminal ops: git, bun, cargo, python.
2
2
 
3
+ # When to use bash — and when not to
4
+
5
+ Bash invokes **real binaries** with simple args. It is NOT a scripting surface.
6
+
7
+ Use bash ONLY for: a single binary call, or one short pipeline that COMPUTES a fact (`wc -l`, `sort | uniq -c`, `comm`, `diff`, a checksum, `git status`).
8
+
9
+ Anything below → `eval` cell, not bash:
10
+ - Inline interpreter scripts (`-e`/`-c`/`--eval`) when an eval runtime exists for that language
11
+ - Heredocs (`<<EOF`), `while`/`for`/`if`/`case` shell control flow
12
+ - `$(…)` command substitution nested inside another command
13
+ - Pipelines with more than two stages, or stages that need control flow or quote/JSON escaping
14
+ - Multiline commands, `&&`-chains mixing control flow
15
+ - Quote/JSON escaping that fights the shell
16
+
3
17
  <instruction>
4
18
  - `cwd` sets the working dir, not `cd dir && …`
5
19
  - `env: { NAME: "…" }` for multiline / quote-heavy / untrusted values; reference `$NAME`
@@ -14,7 +28,9 @@ Runs bash in a shell session — terminal ops: git, bun, cargo, python.
14
28
  </instruction>
15
29
 
16
30
  <critical>
31
+ - Bash invokes real binaries with simple args; it is NOT a scripting surface. Loops, conditionals, heredocs, inline interpreter scripts (`-e`/`-c`/`--eval`) when an eval runtime exists, several piped stages, or quote/JSON escaping mean you're writing a program → use `eval` cells: restartable, stateful, and free of shell-quoting traps.
17
32
  - NEVER shell out to search content or files: `grep/rg` → `search`.
33
+ - NEVER use `ls` or `find` to list or locate files — `ls` → `read` (a directory path lists entries), `find` → the `find` tool (globbing). This is non-negotiable, even for a single quick listing.
18
34
  - Avoid head/tail/redirections: stderr already merged; long output auto-truncated, FULL capture kept at `artifact://<id>`.
19
35
  </critical>
20
36
 
@@ -1,21 +1,23 @@
1
- Run code in a persistent kernel using a list of cells.
1
+ Run one step of code in a persistent kernel.
2
2
 
3
3
  <instruction>
4
- Cells run in array order. State persists per language across cells, tool calls, and `task` subagents — stage helpers/datasets/clients once, subagents reuse directly, no re-import/serialize.
4
+ **One eval call = one cell = one logical step.** State persists per language across separate eval calls, tool calls, and `task` subagents — define helpers/datasets/clients in one call, then later calls reuse them directly.
5
5
 
6
- Cell fields:
6
+ Work incrementally: imports in one call, define in the next, test, then use — each its own eval call. Re-run setup ONLY after `reset`, a kernel crash, or a `NameError`/`ReferenceError` proving the state is gone. Parallelize work *within* a cell with the `parallel(thunks)` helper, not by batching steps.
7
+
8
+ Fields:
7
9
 
8
10
  - `language` — {{#if py}}`"py"` IPython kernel{{/if}}{{#ifAll py js}}, {{/ifAll}}{{#if js}}`"js"` persistent JavaScript VM{{/if}}{{#if rb}}{{#ifAny py js}}, {{/ifAny}}`"rb"` persistent Ruby kernel{{/if}}{{#if jl}}{{#ifAny py js rb}}, {{/ifAny}}`"jl"` persistent Julia kernel{{/if}}.
9
11
  - `code` — cell body, verbatim. Newlines/quotes JSON-encoded; no fences, no headers.
10
12
  - `title` (optional) — short transcript label (e.g. `"imports"`).
11
- - `timeout` (optional) — per-cell seconds. Raise only for heavy compute or long non-agent tool calls.
12
- - `reset` (optional) — wipe this cell's language kernel first.{{#ifAll py js}} Per-language: a `py` reset never touches the JS VM.{{/ifAll}}
13
+ - `timeout` (optional) — seconds. Raise only for heavy compute or long non-agent tool calls.
14
+ - `reset` (optional) — wipe this language's kernel first.{{#ifAll py js}} Per-language: a `py` reset never touches the JS VM.{{/ifAll}}
13
15
 
14
- Work incrementally — one logical step per cell (imports, define, test, use), many small cells per call; workflow notes in the assistant message or `title`, never in cell code.
15
16
  {{#if py}}Live event loop: use top-level `await` directly; `asyncio.run(…)` raises "cannot be called from a running event loop".{{/if}}
16
- {{#if rb}}Ruby: synchronous; helper options are keyword args (e.g. `tree(".", max_depth: 2)`); the last expression auto-displays unless it is `nil`, an assignment, or a definition (like IRB).{{/if}}
17
- {{#if jl}}Julia: synchronous; helper options are standard keyword args (e.g. `tree(max_depth=2)`); the last expression auto-displays unless it is an assignment or a definition (like the Julia REPL).{{/if}}
18
- Errors name the failing cell ("Cell 3 failed") resubmit the fixed cell + any remaining.
17
+ {{#if js}}JS runs under **Bun**: Bun globals/APIs are available (`Bun.file`, `Bun.write`, `Bun.$`, `fetch`, `Buffer`); top-level `await`/`return` work directly.{{/if}}
18
+ {{#if rb}}Ruby: synchronous; helper options are keyword args (e.g. `output("id", limit: 2)`); the last expression auto-displays unless it is `nil`, an assignment, or a definition (like IRB).{{/if}}
19
+ {{#if jl}}Julia: synchronous; helper options are standard keyword args (e.g. `output("id", limit=2)`); the last expression auto-displays unless it is an assignment or a definition (like the Julia REPL).{{/if}}
20
+ On error, fix and re-run only the failing step — prior calls' state survives.
19
21
  </instruction>
20
22
 
21
23
  <prelude>
@@ -29,12 +31,6 @@ read(path, offset?=1, limit?=None) → str
29
31
  File as text; offset/limit 1-indexed lines. Accepts `local://…`.
30
32
  write(path, content) → str
31
33
  Write file (creates parents) → resolved path. `local://…` persists across turns/subagents.
32
- append(path, content) → str
33
- Append → resolved path. Accepts `local://…`.
34
- tree(path?=".", max_depth?=3, show_hidden?=False) → str
35
- Directory tree.
36
- diff(a, b) → str
37
- Unified diff of two files.
38
34
  env(key?=None, value?=None) → str | None | dict
39
35
  No args → full env dict; one → value of `key`; two → set `key=value`, return value.
40
36
  output(*ids, format?="raw", query?=None, offset?=None, limit?=None) → str | dict | list[dict]
@@ -43,9 +39,9 @@ tool.<name>(args) → unknown
43
39
  Invoke any session tool; `args` = its parameter object.
44
40
  completion(prompt, model?="default", system?=None, schema?=None) → str | dict
45
41
  Oneshot, stateless (no history/tools). `model`: "smol" fast | "default" session | "slow" most capable. `schema` (JSON-Schema) → structured output, parsed object.
46
- {{#if spawns}}agent(prompt, agent_type?="task", model?=None, label?=None, schema?=None, return_handle?=False) → str | dict
47
- Run a subagent → final output. `agent_type`/`agentType` picks another discovered agent; `schema` as in completion(). Background via `local://` files named in the prompt. `return_handle`/`returnHandle` → DAG node dict { text, output, handle: "agent://<id>", id, agent } (parsed under `data` when `schema` set).
48
- {{#if js}} JS: options are ONE trailing object — agent(prompt, { agentType, schema, returnHandle }).
42
+ {{#if spawns}}agent(prompt, agent?="task", model?=None, label?=None, schema?=None, handle?=False) → str | dict
43
+ Run a subagent → final output. `agent` picks another discovered agent; `schema` as in completion(). Background via `local://` files named in the prompt. `handle` → DAG node dict { text, output, handle: "agent://<id>", id, agent } (parsed under `data` when `schema` set).
44
+ {{#if js}} JS: options are ONE trailing object — agent(prompt, { agent, schema, handle }).
49
45
  {{/if}}
50
46
  {{/if}}
51
47
  parallel(thunks) → list
@@ -63,10 +59,14 @@ budget → per-turn token budget
63
59
  {{#if spawns}}
64
60
  <dag>
65
61
  Pipe handles through stage helpers to build a dependency graph — acyclic waves:
66
- - **Name nodes.** Capture each `agent(…, {{#if py}}return_handle=True{{/if}}{{#if js}}{ returnHandle: true }{{/if}}{{#if jl}}return_handle=true{{/if}})` result; carries `handle` (`agent://<id>`) + `output`.
62
+ - **Name nodes.** Capture each `agent(…, {{#if py}}handle=True{{/if}}{{#if js}}{ handle: true }{{/if}}{{#if jl}}handle=true{{/if}})` result; carries `handle` (`agent://<id>`) + `output`.
67
63
  - **Wire edges by reference.** Put an upstream node's `handle`/`output` in the dependent stage's prompt — large transcript never re-inlined. Bulk: `write("local://<name>.md", …)`, pass the URI.
68
64
  - **`pipeline(items, *stages)` = staged waves**, barrier between stages (every item clears stage N before any enters N+1). **`parallel(thunks)` = one wave** of independent nodes.
69
65
  - **Isolate failure.** A raising node re-raises the lowest-index error, aborts its wave; wrap risky nodes in try/except so a failure degrades only its dependent subtree, independent branches finish.
70
66
  - **Acyclic only.** A node never waits on its own descendant.
71
67
  </dag>
72
68
  {{/if}}
69
+
70
+ <critical>
71
+ Prior top-level names (`data`, `sessions`, helpers, imports) survive into the next eval call — reuse them; NEVER re-import, re-require, or re-declare a helper. Re-read a file only if it may have changed since the last read. Re-run setup only after `reset`, a crash, or a `NameError`/`ReferenceError`.
72
+ </critical>
@@ -1,6 +1,6 @@
1
1
  **Tasks referenced by verbatim content string, NEVER an auto-generated ID — no "task-1"/"task-N" exists. Pass the content text in the `task` field.**
2
2
 
3
- Manages a phased task list. Pass `ops`: flat array of operations. Next pending task auto-promotes to `in_progress` on each completion. `pending` is a status, not an `op` — leave not-yet-started tasks implicit in `init`/`append`.
3
+ Next pending task auto-promotes to `in_progress` on each completion.
4
4
 
5
5
  ## Operations
6
6
 
package/src/sdk.ts CHANGED
@@ -115,6 +115,7 @@ import {
115
115
  USER_INTERRUPT_LABEL,
116
116
  wrapSteeringForModel,
117
117
  } from "./session/messages";
118
+ import { clampProviderContextImages } from "./session/provider-image-budget";
118
119
  import { getRestorableSessionModels } from "./session/session-context";
119
120
  import { SessionManager } from "./session/session-manager";
120
121
  import { SnapcompactInlineTransformer } from "./session/snapcompact-inline";
@@ -2420,8 +2421,8 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
2420
2421
  return wrapSteeringForModel(withContext);
2421
2422
  };
2422
2423
  // Per-request provider-context transforms. Obfuscate FIRST so secrets are
2423
- // redacted from text before snapcompact rasterizes it into PNG frames.
2424
- // Both operate on the transient outgoing Context only never persisted.
2424
+ // redacted from text before snapcompact rasterizes it into PNG frames, then
2425
+ // clamp images to the active provider budget before the request is sent.
2425
2426
  const snapcompactSystemPromptMode = settings.get("snapcompact.systemPrompt");
2426
2427
  const snapcompactInline =
2427
2428
  snapcompactSystemPromptMode !== "none" || settings.get("snapcompact.toolResults")
@@ -2436,14 +2437,11 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
2436
2437
  createSnapcompactSavingsRecorder(() => sessionManager.getSessionFile() ?? null),
2437
2438
  )
2438
2439
  : undefined;
2439
- const transformProviderContext =
2440
- obfuscator || snapcompactInline
2441
- ? async (context: Context, transformModel: Model): Promise<Context> => {
2442
- let transformed = obfuscator ? obfuscateProviderContext(obfuscator, context) : context;
2443
- if (snapcompactInline) transformed = await snapcompactInline.transform(transformed, transformModel);
2444
- return transformed;
2445
- }
2446
- : undefined;
2440
+ const transformProviderContext = async (context: Context, transformModel: Model): Promise<Context> => {
2441
+ let transformed = obfuscator ? obfuscateProviderContext(obfuscator, context) : context;
2442
+ if (snapcompactInline) transformed = await snapcompactInline.transform(transformed, transformModel);
2443
+ return clampProviderContextImages(transformed, transformModel);
2444
+ };
2447
2445
  const onPayload = async (payload: unknown, _model?: Model) => {
2448
2446
  return await extensionRunner.emitBeforeProviderRequest(payload);
2449
2447
  };