@oh-my-pi/pi-coding-agent 17.1.7 → 17.2.0

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 (246) hide show
  1. package/CHANGELOG.md +127 -0
  2. package/dist/{CHANGELOG-5k4dq4g6.md → CHANGELOG-be1f2t8h.md} +127 -0
  3. package/dist/cli.js +9554 -12379
  4. package/dist/template-8vdv6xb4.js +1671 -0
  5. package/dist/template-f8wx9vfn.css +1355 -0
  6. package/dist/template-qat058wr.html +55 -0
  7. package/dist/tool-views.generated-jdfmzwmn.js +35 -0
  8. package/dist/types/advisor/advise-tool.d.ts +0 -7
  9. package/dist/types/advisor/runtime.d.ts +8 -11
  10. package/dist/types/advisor/transcript-recorder.d.ts +15 -0
  11. package/dist/types/async/job-manager.d.ts +11 -0
  12. package/dist/types/auto-thinking/classifier.d.ts +9 -2
  13. package/dist/types/cleanse/agent.d.ts +19 -0
  14. package/dist/types/cleanse/balance.d.ts +7 -0
  15. package/dist/types/cleanse/checkers.d.ts +13 -0
  16. package/dist/types/cleanse/index.d.ts +16 -0
  17. package/dist/types/cleanse/loop.d.ts +16 -0
  18. package/dist/types/cleanse/parsers.d.ts +13 -0
  19. package/dist/types/cleanse/progress.d.ts +14 -0
  20. package/dist/types/cleanse/types.d.ts +64 -0
  21. package/dist/types/cli/args.d.ts +2 -0
  22. package/dist/types/cli/session-picker.d.ts +14 -7
  23. package/dist/types/collab/guest.d.ts +21 -2
  24. package/dist/types/commands/cleanse.d.ts +23 -0
  25. package/dist/types/commands/launch.d.ts +6 -0
  26. package/dist/types/config/settings-schema.d.ts +63 -8
  27. package/dist/types/cursor-bridge-tools.d.ts +54 -0
  28. package/dist/types/cursor.d.ts +193 -8
  29. package/dist/types/edit/edit-clipboard.d.ts +19 -0
  30. package/dist/types/edit/hashline/diff.d.ts +9 -1
  31. package/dist/types/edit/index.d.ts +8 -1
  32. package/dist/types/edit/streaming.d.ts +8 -1
  33. package/dist/types/export/html/index.d.ts +2 -0
  34. package/dist/types/extensibility/extensions/runner.d.ts +19 -2
  35. package/dist/types/extensibility/extensions/types.d.ts +25 -1
  36. package/dist/types/extensibility/legacy-pi-ai-shim.d.ts +27 -1
  37. package/dist/types/extensibility/legacy-pi-coding-agent-shim.d.ts +2 -0
  38. package/dist/types/internal-urls/local-protocol.d.ts +3 -2
  39. package/dist/types/launch/terminal-output-worker-client.d.ts +5 -0
  40. package/dist/types/launch/terminal-output-worker-protocol.d.ts +14 -0
  41. package/dist/types/launch/terminal-output-worker.d.ts +1 -0
  42. package/dist/types/lsp/client.d.ts +2 -0
  43. package/dist/types/main.d.ts +2 -0
  44. package/dist/types/mcp/manager.d.ts +33 -4
  45. package/dist/types/modes/components/codex-reset-fireworks.d.ts +51 -0
  46. package/dist/types/modes/components/read-tool-group.d.ts +12 -0
  47. package/dist/types/modes/components/session-selector.d.ts +6 -0
  48. package/dist/types/modes/components/status-line/component.d.ts +23 -0
  49. package/dist/types/modes/components/tool-execution.d.ts +16 -7
  50. package/dist/types/modes/components/usage-row.d.ts +2 -0
  51. package/dist/types/modes/controllers/mcp-command-controller.d.ts +26 -1
  52. package/dist/types/modes/controllers/selector-controller.d.ts +2 -1
  53. package/dist/types/modes/interactive-mode.d.ts +8 -5
  54. package/dist/types/modes/rpc/rpc-client.d.ts +7 -0
  55. package/dist/types/modes/rpc/rpc-types.d.ts +16 -0
  56. package/dist/types/modes/theme/theme.d.ts +12 -1
  57. package/dist/types/modes/types.d.ts +2 -1
  58. package/dist/types/sdk.d.ts +1 -0
  59. package/dist/types/session/agent-session-events.d.ts +2 -0
  60. package/dist/types/session/agent-session-types.d.ts +36 -1
  61. package/dist/types/session/agent-session.d.ts +4 -2
  62. package/dist/types/session/async-job-delivery.d.ts +8 -0
  63. package/dist/types/session/claude-session-store.d.ts +13 -0
  64. package/dist/types/session/codex-session-store.d.ts +14 -0
  65. package/dist/types/session/credential-pin.d.ts +58 -0
  66. package/dist/types/session/foreign-session-import.d.ts +15 -0
  67. package/dist/types/session/foreign-session-jsonl.d.ts +9 -0
  68. package/dist/types/session/foreign-session-store.d.ts +23 -0
  69. package/dist/types/session/model-controls.d.ts +3 -3
  70. package/dist/types/session/session-advisors.d.ts +47 -2
  71. package/dist/types/session/session-entries.d.ts +19 -1
  72. package/dist/types/session/session-handoff.d.ts +4 -1
  73. package/dist/types/session/session-loader.d.ts +2 -0
  74. package/dist/types/session/session-maintenance.d.ts +1 -1
  75. package/dist/types/session/session-manager.d.ts +21 -0
  76. package/dist/types/session/session-tools.d.ts +25 -1
  77. package/dist/types/session/turn-recovery.d.ts +10 -4
  78. package/dist/types/system-prompt.d.ts +2 -1
  79. package/dist/types/task/executor.d.ts +11 -2
  80. package/dist/types/task/isolation-ownership.d.ts +34 -0
  81. package/dist/types/task/render.d.ts +7 -0
  82. package/dist/types/thinking.d.ts +18 -6
  83. package/dist/types/tools/acp-bridge.d.ts +28 -5
  84. package/dist/types/tools/browser/cmux/cmux-tab.d.ts +1 -2
  85. package/dist/types/tools/browser/tab-worker.d.ts +1 -4
  86. package/dist/types/tools/grep.d.ts +17 -1
  87. package/dist/types/tools/hub/launch.d.ts +5 -1
  88. package/dist/types/tools/index.d.ts +4 -1
  89. package/dist/types/tools/path-utils.d.ts +19 -0
  90. package/dist/types/tools/read.d.ts +2 -0
  91. package/dist/types/tools/xdev.d.ts +2 -1
  92. package/dist/types/tui/output-block.d.ts +5 -5
  93. package/dist/types/utils/changelog.d.ts +19 -0
  94. package/dist/types/utils/git.d.ts +10 -0
  95. package/dist/types/utils/jj.d.ts +11 -4
  96. package/dist/types/web/search/types.d.ts +2 -2
  97. package/package.json +16 -12
  98. package/scripts/bundle-dist.ts +3 -1
  99. package/src/advisor/advise-tool.ts +0 -11
  100. package/src/advisor/runtime.ts +138 -24
  101. package/src/advisor/transcript-recorder.ts +56 -0
  102. package/src/async/job-manager.ts +30 -7
  103. package/src/auto-thinking/classifier.ts +48 -10
  104. package/src/cleanse/agent.ts +226 -0
  105. package/src/cleanse/balance.ts +79 -0
  106. package/src/cleanse/checkers.ts +996 -0
  107. package/src/cleanse/index.ts +190 -0
  108. package/src/cleanse/loop.ts +51 -0
  109. package/src/cleanse/parsers.ts +726 -0
  110. package/src/cleanse/progress.ts +50 -0
  111. package/src/cleanse/prompts/assignment.md +47 -0
  112. package/src/cleanse/types.ts +72 -0
  113. package/src/cli/args.ts +6 -0
  114. package/src/cli/flag-tables.ts +2 -0
  115. package/src/cli/gallery-fixtures/fs.ts +25 -0
  116. package/src/cli/session-picker.ts +34 -17
  117. package/src/cli/ttsr-cli.ts +19 -1
  118. package/src/cli/update-cli.ts +3 -0
  119. package/src/cli/usage-cli.ts +29 -4
  120. package/src/cli/worktree-cli.ts +28 -11
  121. package/src/cli-commands.ts +1 -0
  122. package/src/cli.ts +11 -1
  123. package/src/collab/guest.ts +37 -4
  124. package/src/collab/host.ts +1 -0
  125. package/src/commands/cleanse.ts +45 -0
  126. package/src/commands/launch.ts +6 -0
  127. package/src/config/model-registry.ts +103 -25
  128. package/src/config/settings-schema.ts +65 -6
  129. package/src/config/settings.ts +25 -0
  130. package/src/cursor-bridge-tools.ts +81 -0
  131. package/src/cursor.ts +463 -12
  132. package/src/discovery/claude-plugins.ts +144 -34
  133. package/src/edit/edit-clipboard.ts +23 -0
  134. package/src/edit/hashline/diff.ts +49 -10
  135. package/src/edit/hashline/execute.ts +38 -6
  136. package/src/edit/hashline/filesystem.ts +27 -3
  137. package/src/edit/index.ts +12 -2
  138. package/src/edit/renderer.ts +4 -4
  139. package/src/edit/streaming.ts +17 -2
  140. package/src/export/html/index.ts +17 -10
  141. package/src/export/html/template.js +1 -1
  142. package/src/extensibility/extensions/runner.ts +70 -0
  143. package/src/extensibility/extensions/types.ts +30 -0
  144. package/src/extensibility/legacy-pi-ai-shim.ts +46 -1
  145. package/src/extensibility/legacy-pi-coding-agent-shim.ts +12 -13
  146. package/src/internal-urls/local-protocol.ts +3 -2
  147. package/src/internal-urls/mcp-protocol.ts +4 -1
  148. package/src/launch/broker.ts +14 -4
  149. package/src/launch/terminal-output-worker-client.ts +53 -0
  150. package/src/launch/terminal-output-worker-protocol.ts +11 -0
  151. package/src/launch/terminal-output-worker.ts +23 -0
  152. package/src/lsp/client.ts +18 -3
  153. package/src/lsp/index.ts +4 -0
  154. package/src/lsp/render.ts +1 -1
  155. package/src/main.ts +127 -56
  156. package/src/mcp/manager.ts +120 -18
  157. package/src/modes/acp/acp-agent.ts +27 -18
  158. package/src/modes/acp/acp-event-mapper.ts +38 -4
  159. package/src/modes/components/chat-transcript-builder.ts +30 -11
  160. package/src/modes/components/codex-reset-fireworks.ts +369 -0
  161. package/src/modes/components/read-tool-group.ts +159 -17
  162. package/src/modes/components/session-selector.ts +19 -3
  163. package/src/modes/components/settings-selector.ts +9 -1
  164. package/src/modes/components/status-line/component.ts +381 -54
  165. package/src/modes/components/tool-execution.ts +78 -31
  166. package/src/modes/components/usage-row.ts +10 -5
  167. package/src/modes/controllers/event-controller.ts +26 -4
  168. package/src/modes/controllers/mcp-command-controller.ts +68 -3
  169. package/src/modes/controllers/selector-controller.ts +94 -36
  170. package/src/modes/controllers/tan-command-controller.ts +14 -0
  171. package/src/modes/interactive-mode.ts +67 -64
  172. package/src/modes/prompt-action-autocomplete.ts +5 -3
  173. package/src/modes/rpc/rpc-client.ts +18 -0
  174. package/src/modes/rpc/rpc-mode.ts +16 -1
  175. package/src/modes/rpc/rpc-types.ts +11 -0
  176. package/src/modes/theme/theme.ts +151 -6
  177. package/src/modes/types.ts +2 -1
  178. package/src/modes/utils/ui-helpers.ts +38 -21
  179. package/src/prompts/goals/guided-goal-interview.md +41 -6
  180. package/src/prompts/system/auto-thinking-difficulty.md +4 -2
  181. package/src/prompts/system/plan-mode-active.md +2 -2
  182. package/src/prompts/system/system-prompt.md +3 -0
  183. package/src/prompts/system/vibe-mode-active.md +4 -1
  184. package/src/prompts/system/xdev-mount-notice.md +1 -1
  185. package/src/prompts/tools/bash.md +15 -17
  186. package/src/prompts/tools/browser.md +1 -0
  187. package/src/prompts/tools/checkpoint.md +1 -1
  188. package/src/prompts/tools/glob.md +7 -6
  189. package/src/prompts/tools/goal.md +1 -1
  190. package/src/prompts/tools/grep.md +7 -6
  191. package/src/sdk.ts +178 -15
  192. package/src/session/agent-session-events.ts +1 -0
  193. package/src/session/agent-session-types.ts +40 -1
  194. package/src/session/agent-session.ts +330 -179
  195. package/src/session/async-job-delivery.ts +8 -0
  196. package/src/session/claude-session-store.ts +426 -0
  197. package/src/session/codex-session-store.ts +673 -0
  198. package/src/session/credential-pin.ts +93 -0
  199. package/src/session/foreign-session-import.ts +52 -0
  200. package/src/session/foreign-session-jsonl.ts +29 -0
  201. package/src/session/foreign-session-store.ts +26 -0
  202. package/src/session/model-controls.ts +15 -7
  203. package/src/session/session-advisors.ts +142 -23
  204. package/src/session/session-entries.ts +21 -1
  205. package/src/session/session-handoff.ts +20 -3
  206. package/src/session/session-history-format.ts +31 -6
  207. package/src/session/session-loader.ts +25 -9
  208. package/src/session/session-maintenance.ts +59 -11
  209. package/src/session/session-manager.ts +61 -0
  210. package/src/session/session-tools.ts +107 -5
  211. package/src/session/settings-stream-fn.ts +1 -0
  212. package/src/session/turn-recovery.ts +97 -51
  213. package/src/slash-commands/builtin-registry.ts +136 -5
  214. package/src/system-prompt.ts +3 -2
  215. package/src/task/executor.ts +17 -4
  216. package/src/task/isolation-ownership.ts +106 -0
  217. package/src/task/render.ts +20 -4
  218. package/src/task/worktree.ts +8 -0
  219. package/src/thinking.ts +29 -10
  220. package/src/tools/acp-bridge.ts +52 -8
  221. package/src/tools/ask.ts +3 -3
  222. package/src/tools/ast-edit.ts +9 -2
  223. package/src/tools/browser/cmux/cmux-tab.ts +9 -14
  224. package/src/tools/browser/tab-worker.ts +12 -35
  225. package/src/tools/browser.ts +7 -2
  226. package/src/tools/checkpoint.ts +0 -13
  227. package/src/tools/gh-renderer.ts +3 -3
  228. package/src/tools/grep.ts +64 -8
  229. package/src/tools/hub/launch.ts +10 -15
  230. package/src/tools/index.ts +38 -5
  231. package/src/tools/path-utils.ts +88 -0
  232. package/src/tools/read.ts +3 -0
  233. package/src/tools/write.ts +44 -3
  234. package/src/tools/xdev.ts +39 -14
  235. package/src/tui/code-cell.ts +4 -4
  236. package/src/tui/output-block.ts +25 -8
  237. package/src/utils/changelog.ts +144 -4
  238. package/src/utils/git.ts +61 -14
  239. package/src/utils/jj.ts +19 -13
  240. package/src/utils/shell-snapshot-fn-env.sh +5 -2
  241. package/src/web/search/providers/codex.ts +34 -0
  242. package/src/web/search/render.ts +2 -2
  243. package/src/web/search/types.ts +1 -1
  244. package/dist/types/goals/guided-setup.d.ts +0 -30
  245. package/src/goals/guided-setup.ts +0 -171
  246. package/src/prompts/goals/guided-goal-system.md +0 -33
@@ -0,0 +1,23 @@
1
+ import type { SessionManager } from "./session-manager.js";
2
+ /** External coding-agent session source supported by OMP imports. */
3
+ export type ForeignSessionSource = "claude" | "codex";
4
+ /** Lightweight source metadata used to choose a foreign session before loading its transcript. */
5
+ export interface ForeignSessionInfo {
6
+ readonly source: ForeignSessionSource;
7
+ readonly id: string;
8
+ readonly path: string;
9
+ readonly cwd: string;
10
+ readonly title?: string;
11
+ readonly created: Date;
12
+ readonly modified: Date;
13
+ readonly messageCount?: number;
14
+ readonly firstMessage?: string;
15
+ }
16
+ /** Lists and converts sessions owned by another coding agent. */
17
+ export interface ForeignSessionStore {
18
+ readonly source: ForeignSessionSource;
19
+ /** Lists source sessions without parsing complete transcripts. */
20
+ list(): Promise<ForeignSessionInfo[]>;
21
+ /** Converts one source session into a non-persistent OMP session. */
22
+ load(session: ForeignSessionInfo): Promise<SessionManager>;
23
+ }
@@ -134,9 +134,9 @@ export declare class ModelControls {
134
134
  cycleThinkingLevel(): ConfiguredThinkingLevel | undefined;
135
135
  /**
136
136
  * Classify the current user turn and set the effective thinking level for it.
137
- * Bounded by a timeout + abort; on any failure (no smol model, timeout, parse
138
- * error) it falls back to the provisional concrete level and continues. Never
139
- * throws into the turn, and never clears `#autoThinking` (auto stays active).
137
+ * Bounded by a timeout + abort; on failure it preserves the last classified
138
+ * level, or uses the provisional concrete level before the first resolution.
139
+ * Never throws into the turn, and never clears `#autoThinking`.
140
140
  */
141
141
  applyAutoThinkingLevel(promptText: string, generation: number): Promise<void>;
142
142
  /**
@@ -1,8 +1,9 @@
1
- import { Agent, type AgentMessage, type AgentTool, type StreamFn } from "@oh-my-pi/pi-agent-core";
1
+ import { Agent, type AgentMessage, type AgentTool, type AgentToolContext, type StreamFn } from "@oh-my-pi/pi-agent-core";
2
2
  import type { CodexCompactionContext, Context, Message, Model, ProviderSessionState, ServiceTier, SimpleStreamOptions } from "@oh-my-pi/pi-ai";
3
3
  import { type AdvisorConfig, type AdvisorRuntimeStatus } from "../advisor/index.js";
4
4
  import type { ModelRegistry } from "../config/model-registry.js";
5
5
  import type { Settings } from "../config/settings.js";
6
+ import { type CursorMcpResourceAdapter } from "../cursor.js";
6
7
  import type { PlanModeState } from "../plan-mode/state.js";
7
8
  import type { SecretObfuscator } from "../secrets/obfuscator.js";
8
9
  import type { AgentSessionEvent } from "./agent-session-events.js";
@@ -51,12 +52,47 @@ export interface PerAdvisorStat {
51
52
  export interface SessionAdvisorsOptions {
52
53
  enabled: boolean;
53
54
  tools?: AgentTool[];
55
+ /**
56
+ * Build a `grep` honoring a Cursor `pi_grep` frame's own context width and
57
+ * match cap. The advisor's tools are fixed instances carrying session
58
+ * defaults, so without this an advisor running against Cursor silently
59
+ * drops both fields — the same gap the primary bridge closes.
60
+ */
61
+ createGrepTool?(options: {
62
+ context?: number;
63
+ totalMatchLimit?: number;
64
+ }): AgentTool | undefined;
65
+ /**
66
+ * Build the `replace`-mode `edit` a Cursor `pi_edit` frame needs. The
67
+ * advisor's own instance follows the configured `edit.mode` (`hashline` by
68
+ * default), whose schema the frame's `old_text`/`new_text` pairs do not
69
+ * match, so without this every native advisor edit fails validation.
70
+ */
71
+ createEditTool?(): AgentTool | undefined;
72
+ /**
73
+ * The execute-time context the bridge's tools resolve approval from.
74
+ *
75
+ * `ExtensionToolWrapper` reads the approval mode, per-tool policies and
76
+ * `autoApprove` only from here; with none it falls back to `yolo` and empty
77
+ * policies, so a native frame would run past a configured `ask` or `deny`.
78
+ */
79
+ getToolContext?: () => AgentToolContext | undefined;
80
+ /**
81
+ * The live MCP connections Cursor's resource frames answer from.
82
+ *
83
+ * Advisors share the session's connections and may hold tools from those
84
+ * same servers, so without this their frames report that every server
85
+ * advertises nothing.
86
+ */
87
+ mcpResources?: CursorMcpResourceAdapter;
54
88
  watchdogPrompt?: string;
55
89
  sharedInstructions?: string;
56
90
  contextPrompt?: string;
57
91
  configs?: AdvisorConfig[];
58
92
  streamFn?: StreamFn;
59
93
  transformProviderContext?: (context: Context, model: Model) => Context | Promise<Context>;
94
+ /** Advisor spend already persisted for this session, restored on resume. */
95
+ initialCosts?: ReadonlyMap<string, number>;
60
96
  }
61
97
  /** Options accepted when an advisor injects a primary-session message. */
62
98
  export interface AdvisorMessageDeliveryOptions {
@@ -93,7 +129,7 @@ export interface SessionAdvisorsHost {
93
129
  hasPendingNextTurnMessages(): boolean;
94
130
  convertToLlmForSideRequest(messages: AgentMessage[]): Message[];
95
131
  effectiveServiceTier(model: Model): ServiceTier | undefined;
96
- resolveContextPromotionTarget(currentModel: Model, contextWindow: number): Promise<Model | undefined>;
132
+ resolveContextPromotionTarget(currentModel: Model, contextWindow: number, signal: AbortSignal): Promise<Model | undefined>;
97
133
  resolveCompactionModelCandidates(preferredModel: Model | null | undefined, availableModels: Model[]): Model[];
98
134
  resolveRetryFallbackRole(currentSelector: string, currentModel?: Model | null): string | undefined;
99
135
  findRetryFallbackCandidates(role: string, currentSelector: string, currentModel?: Model | null): RetryFallbackSelector[];
@@ -118,14 +154,23 @@ export declare class SessionAdvisors {
118
154
  buildRuntime(seedToCurrent?: boolean): boolean;
119
155
  /** Stops every advisor runtime and starts recorder shutdown. */
120
156
  stopRuntime(): void;
157
+ /**
158
+ * Pause advisor work while old-session recorder feeds remain attached, then
159
+ * detach only after any active prompt has settled.
160
+ */
161
+ drainAndDetachRecorders(): Promise<void>;
121
162
  /** Detaches and drains recorder feeds before transcript artifacts are removed. */
122
163
  detachAndCloseRecorders(): Promise<void>;
164
+ /** Reattach recorder feeds and resume work after a rolled-back or preserving transition. */
165
+ reattachRecorderFeeds(): void;
123
166
  /** Re-primes advisor transcript views across a conversation boundary. */
124
167
  resetSessionState(options?: {
125
168
  preserveCost?: boolean;
126
169
  }): void;
127
170
  /** Drop the recorded spend once a conversation boundary has committed. */
128
171
  clearCost(): void;
172
+ /** Replace the ledger with the spend recorded for the session becoming active. */
173
+ restoreCost(costs: ReadonlyMap<string, number>): void;
129
174
  /**
130
175
  * Rebind every live advisor to the active primary conversation's provider
131
176
  * identity (session id, prompt-cache key, credential + metadata resolvers,
@@ -134,6 +134,7 @@ export interface TitleChangeEntry extends SessionEntryBase {
134
134
  declare module "@oh-my-pi/pi-agent-core/compaction/entries" {
135
135
  interface CustomCompactionSessionEntries {
136
136
  titleChange: TitleChangeEntry;
137
+ credentialPin: CredentialPinEntry;
137
138
  }
138
139
  }
139
140
  /** TTSR injection entry - tracks which time-traveling rules have been injected this session. */
@@ -142,6 +143,23 @@ export interface TtsrInjectionEntry extends SessionEntryBase {
142
143
  /** Names of rules that were injected */
143
144
  injectedRules: string[];
144
145
  }
146
+ /**
147
+ * Records which OAuth account served this session's requests for a provider.
148
+ *
149
+ * Provider prompt caches (Anthropic in particular) are account-scoped, and the
150
+ * auth store's session-sticky routing is process-local under a remote auth
151
+ * broker, so resume must re-pin the same account to reuse the warm cache
152
+ * prefix. Stores a sha-256 of the account + billing-scope tuple instead of
153
+ * the raw email/uuid/org; note an unsalted digest of a guessable email is
154
+ * still linkable, so exported sessions are pseudonymous, not anonymous.
155
+ */
156
+ export interface CredentialPinEntry extends SessionEntryBase {
157
+ type: "credential_pin";
158
+ /** Provider id the pin applies to (e.g. "anthropic"). */
159
+ provider: string;
160
+ /** `credentialPinHash()` of the serving account's identity + scope tuple. */
161
+ hash: string;
162
+ }
145
163
  /** Session init entry - captures initial context for subagent sessions (debugging/replay). */
146
164
  export interface SessionInitEntry extends SessionEntryBase {
147
165
  type: "session_init";
@@ -192,7 +210,7 @@ export interface CustomMessageEntry<T = unknown> extends SessionEntryBase {
192
210
  attribution?: MessageAttribution;
193
211
  }
194
212
  /** Session entry - has id/parentId for tree structure (returned by "read" methods in SessionManager) */
195
- export type SessionEntry = SessionMessageEntry | ThinkingLevelChangeEntry | ModelChangeEntry | ServiceTierChangeEntry | CompactionEntry | BranchSummaryEntry | CustomEntry | CustomMessageEntry | LabelEntry | TitleChangeEntry | TtsrInjectionEntry | SessionInitEntry | ModeChangeEntry;
213
+ export type SessionEntry = SessionMessageEntry | ThinkingLevelChangeEntry | ModelChangeEntry | ServiceTierChangeEntry | CompactionEntry | BranchSummaryEntry | CustomEntry | CustomMessageEntry | LabelEntry | TitleChangeEntry | TtsrInjectionEntry | SessionInitEntry | ModeChangeEntry | CredentialPinEntry;
196
214
  /** Raw logical file entry after loaders strip any fixed-width title slot. */
197
215
  export type FileEntry = SessionHeader | SessionEntry;
198
216
  /** Physical JSONL entry before slot-aware loaders fold the title slot. */
@@ -44,7 +44,10 @@ export interface SessionHandoffHost {
44
44
  clearPendingNextTurnMessages(): void;
45
45
  resetTodoCycle(): void;
46
46
  buildDisplaySessionContext(): SessionContext;
47
- resetAdvisorRuntimes(): void;
47
+ resetAdvisorSessionState(): void;
48
+ drainAndDetachAdvisorRecorders(): Promise<void>;
49
+ reattachAdvisorRecorderFeeds(): void;
50
+ clearAdvisorCost(): void;
48
51
  syncTodoPhasesFromBranch(): void;
49
52
  }
50
53
  /** Generates handoff documents and owns the handoff session transition. */
@@ -8,6 +8,8 @@ export declare function parseSessionContent(content: string): {
8
8
  entries: FileEntry[];
9
9
  titleSlot: SessionTitleUpdate | undefined;
10
10
  };
11
+ /** Parse session JSONL and visit each entry without retaining prior entries. */
12
+ export declare function visitEntriesFromFileStream(filePath: string, visit: (entry: FileEntry) => void): Promise<SessionTitleUpdate | undefined>;
11
13
  /** Exported for testing — the ≥8MiB streaming path (works on any file size). */
12
14
  export declare function loadEntriesFromFileStream(filePath: string): Promise<{
13
15
  entries: FileEntry[];
@@ -214,7 +214,7 @@ export declare class SessionMaintenance {
214
214
  * is true.
215
215
  */
216
216
  checkCompaction(assistantMessage: AssistantMessage, skipAbortedCheck?: boolean, allowDefer?: boolean, autoContinue?: boolean): Promise<CompactionCheckResult>;
217
- resolveContextPromotionTarget(currentModel: Model, contextWindow: number): Promise<Model | undefined>;
217
+ resolveContextPromotionTarget(currentModel: Model, contextWindow: number, signal?: AbortSignal): Promise<Model | undefined>;
218
218
  resolveCompactionModelCandidates(preferredModel: Model | null | undefined, availableModels: Model[], filter?: (model: Model) => boolean): Model[];
219
219
  /**
220
220
  * Internal: Run auto-compaction with events.
@@ -92,6 +92,11 @@ export declare class SessionManager {
92
92
  * session/new must create a discoverable file immediately).
93
93
  */
94
94
  ensureOnDisk(): Promise<void>;
95
+ /** Persist this session's transcript as a newly identified OMP session. */
96
+ persistCopy(options?: {
97
+ sessionDir?: string;
98
+ suppressBreadcrumb?: boolean;
99
+ }, storage?: SessionStorage): Promise<SessionManager>;
95
100
  /**
96
101
  * Stage a synchronous group of entry appends and publish the resulting full
97
102
  * journal with one atomic replace. A failed publish removes only the staged
@@ -236,6 +241,22 @@ export declare class SessionManager {
236
241
  appendTtsrInjection(ruleNames: string[]): string;
237
242
  /** All unique TTSR rule names injected on the current branch (root → leaf). */
238
243
  getInjectedTtsrRules(): string[];
244
+ /** Append a credential pin recording which OAuth account served `provider`. */
245
+ appendCredentialPin(provider: string, hash: string): string;
246
+ /**
247
+ * Latest credential pin per provider on the current branch (root → leaf),
248
+ * with the effective last-use time of the pinned account.
249
+ *
250
+ * Pins are appended only when the serving account *changes*, so a long
251
+ * session on one account carries a single old pin entry. Any assistant turn
252
+ * for the same provider after that pin was necessarily served by the pinned
253
+ * account, so its timestamp advances `lastUsedAt` — a resume seconds after
254
+ * the last turn seeds a warm sticky instead of a stale one.
255
+ */
256
+ getCredentialPins(): Map<string, {
257
+ hash: string;
258
+ lastUsedAt: number;
259
+ }>;
239
260
  getLeafId(): string | null;
240
261
  getLeafEntry(): SessionEntry | undefined;
241
262
  /**
@@ -86,6 +86,17 @@ export declare function collectMountedMCPToolRoutes(tools: Iterable<MountedMCPTo
86
86
  * rendered by the static MCP guidance prompt.
87
87
  */
88
88
  export declare function projectMountedMCPXdevGuidance(routes: Iterable<MountedMCPToolRoute>): MCPXdevGuidanceProjection;
89
+ /**
90
+ * Structured payload persisted on each {@link XDEV_MOUNT_NOTICE_MESSAGE_TYPE}
91
+ * custom message. Lets a resumed session reconstruct which dynamic devices the
92
+ * model has already been told about, so reconnecting hosts do not re-announce
93
+ * (and re-splice a redundant developer message that busts the provider
94
+ * prompt-cache prefix).
95
+ */
96
+ interface XdevMountNoticeDetails {
97
+ added: string[];
98
+ removed: string[];
99
+ }
89
100
  /** Owns tool registration, presentation, prompt rebuilding, skills, and permissions. */
90
101
  export declare class SessionTools {
91
102
  #private;
@@ -134,8 +145,21 @@ export declare class SessionTools {
134
145
  getSelectedMCPToolNames(): string[];
135
146
  /** Applies an enabled tool set and reconciles its `xd://` partition. */
136
147
  applyActiveToolsByName(toolNames: string[]): Promise<void>;
148
+ /**
149
+ * Forget the announced-mount baseline for a replaced transcript. Called when
150
+ * session history is swapped wholesale (`/new`, `switchSession`, `branch`): the
151
+ * previous transcript's persisted notices no longer apply, so the next notice
152
+ * re-seeds from the new history and a device reconnecting into it announces
153
+ * again.
154
+ *
155
+ * The pending delta is deliberately preserved: it holds mounts that are still
156
+ * live but not yet delivered to the model, and `branch()` does not rebuild the
157
+ * base system prompt, so dropping it would leave the branched transcript
158
+ * unaware of a still-mounted device that no later refresh would re-queue.
159
+ */
160
+ resetAnnouncedMounts(): void;
137
161
  /** Consumes the hidden notice for unannounced `xd://` mount changes. */
138
- takePendingXdevMountNotice(): CustomMessage | undefined;
162
+ takePendingXdevMountNotice(): CustomMessage<XdevMountNoticeDetails> | undefined;
139
163
  /** Rediscovers reloadable skills and refreshes prompt metadata. */
140
164
  refreshSkills(): Promise<void>;
141
165
  /** Selects enabled tools, ignoring names absent from the registry. */
@@ -42,6 +42,7 @@ export interface TurnRecoveryHost {
42
42
  }): void;
43
43
  waitForSessionMessagePersistence(message: AssistantMessage): Promise<void>;
44
44
  appendSessionMessage(message: AssistantMessage): void;
45
+ persistedAssistantEntryId(message: AssistantMessage): string | undefined;
45
46
  sessionMessageAlreadyPersisted(message: AssistantMessage): boolean;
46
47
  setModelWithProviderSessionReset(model: Model): Promise<void>;
47
48
  resetCurrentResponsesProviderSession(reason: string): void;
@@ -100,6 +101,12 @@ export declare class TurnRecovery {
100
101
  hardErrorFallback?: boolean;
101
102
  preserveFailedTurn?: boolean;
102
103
  }): Promise<boolean>;
104
+ /**
105
+ * Records a usage-limit failure before replay eligibility decides whether the
106
+ * failed turn may be discarded. Returns whether credential recovery switched
107
+ * the active account.
108
+ */
109
+ recordUsageLimitOutcome(message: AssistantMessage): Promise<boolean>;
103
110
  /** Prompts after transient overlap with a prior agent run. */
104
111
  promptAgentWithIdleRetry(messages: AgentMessage[], options?: {
105
112
  toolChoice?: ToolChoice;
@@ -176,8 +183,8 @@ export declare class TurnRecovery {
176
183
  * transient overload/5xx or a hard "router/model not found / unsupported" —
177
184
  * is worth retrying on the base id. Skips failures the base model shares:
178
185
  * context overflow (compaction's job), usage limits and auth errors (same
179
- * account/key), and turns that already emitted a tool call (replaying would
180
- * duplicate work). Requires the base model to exist in the registry.
186
+ * account/key), and turns that already emitted any replay-unsafe output.
187
+ * Requires the base model to exist in the registry.
181
188
  */
182
189
  isFireworksFastFallbackEligible(message: AssistantMessage): boolean;
183
190
  /**
@@ -188,8 +195,7 @@ export declare class TurnRecovery {
188
195
  * model switch cannot fix or must not replay: cancellations (abort-flavored
189
196
  * errors are not model faults), context overflow (compaction's job),
190
197
  * classifier refusals (chain consult is handled on the retryable path with
191
- * `pinFallback`), and turns that already emitted a tool call (replaying
192
- * could duplicate work).
198
+ * `pinFallback`), and turns that already emitted replay-unsafe output.
193
199
  */
194
200
  isHardErrorFallbackEligible(message: AssistantMessage): boolean;
195
201
  /**
@@ -131,10 +131,11 @@ export interface BuildSystemPromptOptions {
131
131
  renderMermaid?: boolean;
132
132
  /** Pre-resolved nested active repo context. Undefined resolves from cwd. */
133
133
  activeRepoContext?: ActiveRepoContext | null;
134
- /** Tools mounted under `xd://`; renders the protocol section when non-empty. */
134
+ /** Tools mounted under `xd://`; renders the protocol section when non-empty. `dynamic` marks external devices whose summary is third-party metadata. */
135
135
  xdevTools?: Array<{
136
136
  name: string;
137
137
  summary: string;
138
+ dynamic?: boolean;
138
139
  }>;
139
140
  /** Full docs + JSON schema for every `xd://`-mounted tool, inlined into the protocol section so no discovery `read` is needed. */
140
141
  xdevDocs?: string;
@@ -34,10 +34,19 @@ export type { YieldItem } from "./types.js";
34
34
  * agent is driven to one forced final `yield` so partial findings come back
35
35
  * as a real report; only if it still refuses to yield within
36
36
  * {@link BUDGET_STOP_GRACE_REQUESTS} more requests is the run hard-aborted.
37
- * The `default` key applies to agents without an explicit entry and can be
38
- * overridden via the `task.softRequestBudget` setting (0 disables the guard).
37
+ * Entries are ceilings, not fixed values: the `default` key applies to agents
38
+ * without an explicit entry, and the `task.softRequestBudget` setting can only
39
+ * lower an agent's budget, never raise it above its bundled entry (0 disables
40
+ * the guard entirely).
39
41
  */
40
42
  export declare const SOFT_REQUEST_BUDGET: Record<string, number>;
43
+ /**
44
+ * Resolves the effective soft request budget for an agent. The configured
45
+ * `task.softRequestBudget` and the agent's bundled entry are both upper
46
+ * bounds, so the tighter one wins; a configured budget of 0 disables the
47
+ * guard regardless of the bundled entry.
48
+ */
49
+ export declare function resolveSoftRequestBudget(agentName: string, configuredBudget: number): number;
41
50
  /** Extra requests allowed after a budget stop for the forced yield to land before the run is hard-aborted. */
42
51
  export declare const BUDGET_STOP_GRACE_REQUESTS = 5;
43
52
  /** Steering notice injected when a subagent crosses its soft request budget. */
@@ -0,0 +1,34 @@
1
+ /** Marker file written into a task-isolation base dir identifying its owner. */
2
+ export declare const ISOLATION_OWNER_FILE = ".omp-isolation-owner.json";
3
+ /** Recorded owner of a task-isolation sandbox. */
4
+ export interface IsolationOwner {
5
+ /** PID of the omp process that created and owns the sandbox. */
6
+ pid: number;
7
+ /** Task id the sandbox was materialised for. */
8
+ id: string;
9
+ /**
10
+ * Process-instance start-time token for {@link pid}, when the OS can report
11
+ * it. Distinguishes the owning process from an unrelated process that later
12
+ * inherits a recycled pid, so a crashed sandbox is never pinned live.
13
+ */
14
+ startToken?: string;
15
+ }
16
+ /**
17
+ * Record the current process as owner of the sandbox rooted at `baseDir`.
18
+ *
19
+ * Written before the isolation backend materialises `m` so a concurrent
20
+ * `omp worktree clear` never sees an owner-less sandbox mid-creation.
21
+ */
22
+ export declare function writeIsolationOwner(baseDir: string, id: string): Promise<void>;
23
+ /**
24
+ * Whether a live omp process still owns the sandbox at `baseDir`.
25
+ *
26
+ * A missing or malformed marker means no verifiable owner — a crashed run or a
27
+ * sandbox from before markers existed, both safe to reclaim. `process.kill(pid,
28
+ * 0)` can fail with `EPERM` even when the process is alive, so only an explicit
29
+ * `ESRCH` ("no such process") counts as dead; any other error is treated as
30
+ * alive to avoid deleting a sandbox that is actually in use. When the marker
31
+ * carries a {@link IsolationOwner.startToken}, a live pid whose current token no
32
+ * longer matches is a recycled pid — a different process — and counts as dead.
33
+ */
34
+ export declare function hasLiveIsolationOwner(baseDir: string): Promise<boolean>;
@@ -11,6 +11,13 @@ interface TaskRenderContext {
11
11
  * commit-eligible rows do not repaint after entering native scrollback.
12
12
  */
13
13
  frozen?: boolean;
14
+ /**
15
+ * Wall clock for time-derived rows (current-tool elapsed, retry countdown).
16
+ * The component freezes it once the block settles or any of its rows enter
17
+ * native scrollback, so identical-input rebuilds stay byte-identical with
18
+ * committed history. Absent: render with the live clock.
19
+ */
20
+ nowMs?: number;
14
21
  }
15
22
  type TaskRenderOptions = RenderResultOptions & {
16
23
  renderContext?: TaskRenderContext;
@@ -103,6 +103,12 @@ export declare function parseCliThinkingLevel(value: string | null | undefined):
103
103
  * above Low (falling back to the full supported set only when the model maxes
104
104
  * out below Low). Within that pool the request snaps to the highest level not
105
105
  * exceeding it, or the pool minimum when the request is below the pool.
106
+ * `ceiling` bounds the pool from above, so a policy ceiling survives the model
107
+ * clamp: a sparse ladder such as `["max"]` must not snap an `xhigh` request up
108
+ * to `max`. The Low floor is resolved against the model's own ladder *before*
109
+ * the ceiling applies — a ceiling that hides every tier at or above Low means
110
+ * there is nothing legal to pick (`undefined`), not a licence to fall through
111
+ * to a sub-Low tier the model happens to expose.
106
112
  *
107
113
  * Returns `undefined` for reasoning-capable models without a controllable
108
114
  * effort surface (`thinking.efforts` empty — e.g. devin-agent models, where
@@ -111,7 +117,7 @@ export declare function parseCliThinkingLevel(value: string | null | undefined):
111
117
  * forward a concrete effort that would then trip {@link requireSupportedEffort}
112
118
  * downstream.
113
119
  */
114
- export declare function clampAutoThinkingEffort(model: Model | undefined, effort: Effort): Effort | undefined;
120
+ export declare function clampAutoThinkingEffort(model: Model | undefined, effort: Effort, ceiling?: Effort): Effort | undefined;
115
121
  /** Coarse per-spawn effort selectors accepted by the task tool. */
116
122
  export declare const TASK_EFFORTS: readonly ["lo", "med", "hi"];
117
123
  /** Coarse task-spawn effort: the lowest, middle, or highest thinking level the target model supports. */
@@ -146,10 +152,16 @@ export declare function clampThinkingLevelToCeiling(model: Model | undefined, le
146
152
  export declare function modelSupportsEffortCeiling(model: Model, ceiling: Effort): boolean;
147
153
  /**
148
154
  * The provisional concrete level shown while `auto` is configured but before a
149
- * turn has been classified. Prefers the model's `defaultLevel`, otherwise High,
150
- * clamped into the auto range. Auto never provisions {@link Effort.Max} (the
151
- * classifier ceiling is XHigh; only an explicit user request reaches Max), so a
152
- * `defaultLevel` of `max` is capped at XHigh before clamping. Returns
153
- * `undefined` for non-reasoning models.
155
+ * turn has been classified, and the fallback when classification fails. Prefers
156
+ * the model's `defaultLevel`, otherwise High, clamped into the auto range.
157
+ *
158
+ * Deliberately stays below {@link Effort.Max}: the placeholder must not bill the
159
+ * top tier for a turn nobody classified, so XHigh is passed as a hard ceiling
160
+ * rather than only capping the preferred level — otherwise a sparse `["max"]`
161
+ * ladder would snap straight back up. A model whose ladder offers nothing at or
162
+ * below XHigh therefore has no provisional level, and `auto` leaves the current
163
+ * one in place. Classification itself may still resolve Max on models that
164
+ * expose the tier when the user opts in. Returns `undefined` for non-reasoning
165
+ * models.
154
166
  */
155
167
  export declare function resolveProvisionalAutoLevel(model: Model | undefined): Effort | undefined;
@@ -16,14 +16,37 @@ import type { ToolSession } from "./index.js";
16
16
  * that must stay off the editor's buffer.
17
17
  */
18
18
  export declare function shouldRouteWriteThroughBridge(session: ToolSession, requestedPath: string, absolutePath: string): boolean;
19
+ /**
20
+ * Result of a bridge-routed write: the content actually verified on disk
21
+ * after the client processed the write, plus whether that content diverges
22
+ * from what the tool asked to persist.
23
+ *
24
+ * ACP's `fs/write_text_file` has no "verbatim, no side effects" guarantee —
25
+ * a client (e.g. Zed with `format_on_save: on`) may reformat the buffer as
26
+ * part of handling the write before it settles on disk. Silently trusting
27
+ * the requested `content` as "what's now on disk" lets that drift poison
28
+ * every snapshot/tag/hash a caller derives from the write, which then reads
29
+ * back as unrelated whole-file corruption on the *next* edit. Reading the
30
+ * file back and reporting what's actually there keeps callers honest.
31
+ */
32
+ export interface BridgeWriteResult {
33
+ /** Content actually present on disk immediately after the bridge write. */
34
+ text: string;
35
+ /** `true` when `text` differs from the content the tool asked to write. */
36
+ driftedFromRequest: boolean;
37
+ }
19
38
  /**
20
39
  * Try to route a file write through the ACP client bridge.
21
40
  *
22
41
  * Performs the full guard check, bridge call (wrapped in {@link ToolError}),
23
- * FS-scan cache invalidation, and session mutation-version bump.
42
+ * a post-write read-back to detect client-side transformation (e.g.
43
+ * format-on-save), FS-scan cache invalidation, and session mutation-version
44
+ * bump.
24
45
  *
25
- * Returns `true` when the bridge was used and the caller must skip the
26
- * writethrough path. Returns `false` when the bridge is unavailable or the
27
- * path should not be routed through it.
46
+ * Returns `undefined` when the bridge is unavailable or the path should not
47
+ * be routed through it the caller must fall back to the writethrough path.
48
+ * Returns a {@link BridgeWriteResult} when the bridge was used; callers MUST
49
+ * use `result.text` (not the content they requested) for any snapshot, hash,
50
+ * or tag derived from this write.
28
51
  */
29
- export declare function routeWriteThroughBridge(session: ToolSession, requestedPath: string, absolutePath: string, content: string, signal?: AbortSignal): Promise<boolean>;
52
+ export declare function routeWriteThroughBridge(session: ToolSession, requestedPath: string, absolutePath: string, content: string, signal?: AbortSignal): Promise<BridgeWriteResult | undefined>;
@@ -8,7 +8,6 @@ import type { CmuxSocketClient } from "./socket-client.js";
8
8
  interface ScreenshotOptions {
9
9
  selector?: string;
10
10
  fullPage?: boolean;
11
- save?: string;
12
11
  silent?: boolean;
13
12
  encoding?: "base64" | "binary";
14
13
  }
@@ -101,7 +100,7 @@ export declare class CmuxTab {
101
100
  scrollIntoView(selector: string): Promise<void>;
102
101
  select(selector: string, ...values: string[]): Promise<string[]>;
103
102
  extract(format?: ReadableFormat): Promise<string>;
104
- screenshot(opts?: ScreenshotOptions): Promise<ScreenshotResult>;
103
+ screenshot(opts?: ScreenshotOptions): Promise<string>;
105
104
  waitForUrl(pattern: string | RegExp, opts?: {
106
105
  timeout?: number;
107
106
  }): Promise<string>;
@@ -1,5 +1,5 @@
1
1
  import type { HTMLElement } from "linkedom";
2
- import type { ElementHandle, ImageFormat } from "puppeteer-core";
2
+ import type { ElementHandle } from "puppeteer-core";
3
3
  import type { Transport } from "./tab-protocol.js";
4
4
  declare module "puppeteer-core" {
5
5
  interface Frame {
@@ -41,7 +41,6 @@ export declare function resolveWaitTimeout(cellTimeoutMs: number, explicit?: num
41
41
  interface ScreenshotOptions {
42
42
  selector?: string;
43
43
  fullPage?: boolean;
44
- save?: string;
45
44
  silent?: boolean;
46
45
  }
47
46
  export declare function normalizeSelector(selector: string): string;
@@ -67,8 +66,6 @@ export interface InflightOp {
67
66
  }
68
67
  /** Human-readable label for a screenshot op, used in op tracking + timeout errors. */
69
68
  export declare function describeScreenshot(opts?: ScreenshotOptions): string;
70
- /** Map an explicit save path's extension to a puppeteer capture format (default png). */
71
- export declare function imageFormatForPath(filePath: string): ImageFormat;
72
69
  /** Summarize still-running helpers (oldest first) so a cell timeout names what stalled. */
73
70
  export declare function describeInflight(inflight: Map<number, InflightOp>): string;
74
71
  export declare class WorkerCore {
@@ -55,7 +55,23 @@ export interface GrepToolDetails {
55
55
  missingPaths?: string[];
56
56
  }
57
57
  type SearchParams = typeof searchSchema.infer;
58
+ /**
59
+ * Construction-time overrides for callers that are not the model.
60
+ *
61
+ * The model-facing schema deliberately does not grow these: they exist for
62
+ * wire bridges (the Cursor `pi_grep` frame) whose protocol carries an explicit
63
+ * context width and total match cap, and which would otherwise have to drop
64
+ * them. Unset means "use the session settings / built-in caps" — the behavior
65
+ * every model-issued call keeps.
66
+ */
67
+ export interface GrepToolOptions {
68
+ /** Overrides `grep.contextBefore`/`grep.contextAfter` for every call on this instance. */
69
+ context?: number;
70
+ /** Caps total surfaced matches. Applied on top of the built-in per-file and file-window caps, never above them. */
71
+ totalMatchLimit?: number;
72
+ }
58
73
  export declare class GrepTool implements AgentTool<typeof searchSchema, GrepToolDetails> {
74
+ #private;
59
75
  private readonly session;
60
76
  readonly name = "grep";
61
77
  readonly approval: (args: unknown) => ToolTier;
@@ -71,7 +87,7 @@ export declare class GrepTool implements AgentTool<typeof searchSchema, GrepTool
71
87
  skip?: number | null | undefined;
72
88
  }, {}>;
73
89
  readonly strict = true;
74
- constructor(session: ToolSession);
90
+ constructor(session: ToolSession, options?: GrepToolOptions);
75
91
  execute(_toolCallId: string, params: SearchParams, signal?: AbortSignal, _onUpdate?: AgentToolUpdateCallback<GrepToolDetails>, _toolContext?: AgentToolContext): Promise<AgentToolResult<GrepToolDetails>>;
76
92
  }
77
93
  interface GrepRenderArgs {
@@ -7,7 +7,7 @@
7
7
  import type { AgentToolResult } from "@oh-my-pi/pi-agent-core";
8
8
  import type { Component } from "@oh-my-pi/pi-tui";
9
9
  import type { RenderResultOptions } from "../../extensibility/custom-tools/types.js";
10
- import type { DaemonSnapshot, DaemonSpec, DaemonState } from "../../launch/protocol.js";
10
+ import type { DaemonRpcResult, DaemonSnapshot, DaemonSpec, DaemonState } from "../../launch/protocol.js";
11
11
  import type { Theme } from "../../modes/theme/theme.js";
12
12
  import type { ToolSession } from "../index.js";
13
13
  /** Broker-facing launch parameters; the hub adapts its `ps` op to `list` before calling in. */
@@ -57,6 +57,10 @@ export interface LaunchToolDetails {
57
57
  /** describe: immutable launch spec backing the command/cwd detail lines. */
58
58
  spec?: DaemonSpec;
59
59
  }
60
+ /** Resolve display rows while keeping legacy raw replay outside the client process. */
61
+ export declare function renderLaunchLogTerminalRows(result: Extract<DaemonRpcResult, {
62
+ op: "logs";
63
+ }>, params: Pick<LaunchParams, "head" | "lines">): Promise<string[] | undefined>;
60
64
  /** Run one broker operation for the calling session's project. */
61
65
  export declare function executeLaunch(session: ToolSession, params: LaunchParams, signal?: AbortSignal): Promise<AgentToolResult<LaunchToolDetails>>;
62
66
  /** Args shape visible to the renderer, possibly mid-stream (every field optional). */
@@ -1,4 +1,4 @@
1
- import type { InMemorySnapshotStore } from "@oh-my-pi/hashline";
1
+ import type { Clipboard, InMemorySnapshotStore } from "@oh-my-pi/hashline";
2
2
  import type { AgentTelemetryConfig, AgentTool } from "@oh-my-pi/pi-agent-core";
3
3
  import type { FetchImpl, ImageContent, Model, ServiceTierByFamily, ToolChoice } from "@oh-my-pi/pi-ai";
4
4
  import type { AsyncJobManager } from "../async/job-manager.js";
@@ -321,6 +321,9 @@ export interface ToolSession {
321
321
  * reconstruct the version the model authored anchors against when the
322
322
  * file changed out-of-band. Lazily initialized by `getFileSnapshotStore`. */
323
323
  fileSnapshotStore?: InMemorySnapshotStore;
324
+ /** Per-session `CUT`/`PASTE` clipboard register shared across edit
325
+ * calls. Lazily initialized by `getEditClipboard`. */
326
+ editClipboard?: Clipboard;
324
327
  /** Per-session log of unresolved git merge conflict regions surfaced by
325
328
  * `read`. Each entry gets a stable id N referenced by `write conflict://N`
326
329
  * to splice the recorded region with replacement content. Lazily initialized
@@ -129,6 +129,25 @@ export declare function isReadableUrlPath(value: string): boolean;
129
129
  * filesystem root is almost never what they intended.
130
130
  */
131
131
  export declare function resolveToCwd(filePath: string, cwd: string): string;
132
+ /**
133
+ * Resolve a path that MUST stay inside `cwd`, or `null` when it would escape.
134
+ *
135
+ * {@link resolveToCwd} deliberately honors absolute paths, `~`, and `..` —
136
+ * correct for a path a user typed, wrong for one a remote peer supplied.
137
+ * Callers handling untrusted input (Cursor's `download_path`) use this instead:
138
+ * only a non-empty relative path landing under the live cwd is accepted, so
139
+ * neither `/etc/passwd` nor `../../escape` can be written through.
140
+ *
141
+ * The lexical check alone is not containment: a symlink inside the workspace
142
+ * can point anywhere, so `out/config` under a `ws/out -> /elsewhere` link is
143
+ * relative, `..`-free, and still writes outside. Both the target and its
144
+ * deepest existing ancestor are therefore realpath-resolved — the ancestor
145
+ * because a download names a file that does not exist yet, so the link in its
146
+ * path is the only thing that can be resolved before the write.
147
+ *
148
+ * The cwd itself is rejected: a download names a file, never the directory.
149
+ */
150
+ export declare function confineToWorkspace(filePath: string, cwd: string): string | null;
132
151
  export declare function formatPathRelativeToCwd(filePath: string, cwd: string, options?: {
133
152
  trailingSlash?: boolean;
134
153
  }): string;