@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.
- package/CHANGELOG.md +136 -0
- package/dist/types/cli/args.d.ts +1 -1
- package/dist/types/cli/dry-balance-cli.d.ts +15 -1
- package/dist/types/cli/gallery-cli.d.ts +43 -0
- package/dist/types/cli/gallery-fixtures/agentic.d.ts +2 -0
- package/dist/types/cli/gallery-fixtures/codeintel.d.ts +3 -0
- package/dist/types/cli/gallery-fixtures/edit.d.ts +3 -0
- package/dist/types/cli/gallery-fixtures/fs.d.ts +2 -0
- package/dist/types/cli/gallery-fixtures/index.d.ts +4 -0
- package/dist/types/cli/gallery-fixtures/interaction.d.ts +3 -0
- package/dist/types/cli/gallery-fixtures/memory.d.ts +2 -0
- package/dist/types/cli/gallery-fixtures/misc.d.ts +3 -0
- package/dist/types/cli/gallery-fixtures/search.d.ts +3 -0
- package/dist/types/cli/gallery-fixtures/shell.d.ts +3 -0
- package/dist/types/cli/gallery-fixtures/types.d.ts +44 -0
- package/dist/types/cli/gallery-fixtures/web.d.ts +2 -0
- package/dist/types/cli/gallery-screenshot.d.ts +35 -0
- package/dist/types/commands/gallery.d.ts +47 -0
- package/dist/types/commit/analysis/conventional.d.ts +2 -2
- package/dist/types/commit/analysis/summary.d.ts +2 -2
- package/dist/types/commit/changelog/generate.d.ts +2 -2
- package/dist/types/commit/changelog/index.d.ts +2 -2
- package/dist/types/commit/map-reduce/index.d.ts +3 -3
- package/dist/types/commit/map-reduce/map-phase.d.ts +2 -2
- package/dist/types/commit/map-reduce/reduce-phase.d.ts +2 -2
- package/dist/types/commit/model-selection.d.ts +10 -4
- package/dist/types/config/api-key-resolver.d.ts +34 -0
- package/dist/types/config/keybindings.d.ts +6 -1
- package/dist/types/config/model-id-affixes.d.ts +2 -0
- package/dist/types/config/model-registry.d.ts +25 -2
- package/dist/types/config/settings-schema.d.ts +41 -6
- package/dist/types/dap/config.d.ts +14 -1
- package/dist/types/dap/types.d.ts +10 -0
- package/dist/types/extensibility/plugins/marketplace-auto-update.d.ts +8 -0
- package/dist/types/lsp/types.d.ts +10 -0
- package/dist/types/lsp/utils.d.ts +3 -2
- package/dist/types/main.d.ts +3 -2
- package/dist/types/memory-backend/index.d.ts +2 -1
- package/dist/types/memory-backend/resolve.d.ts +1 -1
- package/dist/types/memory-backend/types.d.ts +1 -1
- package/dist/types/modes/components/chat-block.d.ts +64 -0
- package/dist/types/modes/components/custom-editor.d.ts +5 -1
- package/dist/types/modes/components/overlay-box.d.ts +17 -0
- package/dist/types/modes/components/plan-review-overlay.d.ts +59 -0
- package/dist/types/modes/components/plan-toc.d.ts +41 -0
- package/dist/types/modes/components/read-tool-group.d.ts +2 -0
- package/dist/types/modes/components/tool-execution.d.ts +18 -0
- package/dist/types/modes/components/transcript-container.d.ts +11 -0
- package/dist/types/modes/controllers/command-controller.d.ts +1 -0
- package/dist/types/modes/controllers/event-controller.d.ts +0 -1
- package/dist/types/modes/controllers/extension-ui-controller.d.ts +0 -1
- package/dist/types/modes/controllers/input-controller.d.ts +1 -1
- package/dist/types/modes/controllers/selector-controller.d.ts +1 -1
- package/dist/types/modes/controllers/streaming-reveal.d.ts +22 -0
- package/dist/types/modes/controllers/tan-command-controller.d.ts +6 -0
- package/dist/types/modes/index.d.ts +5 -4
- package/dist/types/modes/interactive-mode.d.ts +16 -6
- package/dist/types/modes/setup-version.d.ts +11 -0
- package/dist/types/modes/setup-wizard/index.d.ts +2 -1
- package/dist/types/modes/setup-wizard/scenes/web-search.d.ts +2 -1
- package/dist/types/modes/theme/theme.d.ts +1 -1
- package/dist/types/modes/types.d.ts +19 -6
- package/dist/types/modes/utils/copy-targets.d.ts +21 -1
- package/dist/types/plan-mode/approved-plan.d.ts +27 -8
- package/dist/types/plan-mode/plan-protection.d.ts +4 -4
- package/dist/types/sdk.d.ts +3 -1
- package/dist/types/session/agent-session.d.ts +21 -0
- package/dist/types/session/messages.d.ts +12 -0
- package/dist/types/session/session-manager.d.ts +3 -1
- package/dist/types/slash-commands/types.d.ts +4 -6
- package/dist/types/task/executor.d.ts +14 -0
- package/dist/types/task/index.d.ts +1 -0
- package/dist/types/task/render.d.ts +3 -2
- package/dist/types/telemetry-export.d.ts +1 -1
- package/dist/types/tools/archive-reader.d.ts +5 -0
- package/dist/types/tools/ast-edit.d.ts +3 -0
- package/dist/types/tools/ast-grep.d.ts +3 -0
- package/dist/types/tools/bash.d.ts +1 -0
- package/dist/types/tools/eval-render.d.ts +1 -8
- package/dist/types/tools/fetch.d.ts +15 -7
- package/dist/types/tools/find.d.ts +8 -4
- package/dist/types/tools/grouped-file-output.d.ts +95 -12
- package/dist/types/tools/memory-render.d.ts +4 -1
- package/dist/types/tools/plan-mode-guard.d.ts +8 -9
- package/dist/types/tools/render-utils.d.ts +13 -9
- package/dist/types/tools/renderers.d.ts +16 -2
- package/dist/types/tools/search.d.ts +5 -1
- package/dist/types/tools/sqlite-reader.d.ts +1 -0
- package/dist/types/tools/todo.d.ts +3 -2
- package/dist/types/tools/write.d.ts +5 -0
- package/dist/types/tui/output-block.d.ts +16 -4
- package/dist/types/tui/status-line.d.ts +3 -0
- package/dist/types/utils/enhanced-paste.d.ts +20 -0
- package/dist/types/web/scrapers/github.d.ts +22 -0
- package/dist/types/web/search/providers/kimi.d.ts +1 -1
- package/dist/types/web/search/providers/perplexity.d.ts +8 -1
- package/dist/types/web/search/types.d.ts +1 -1
- package/package.json +9 -9
- package/scripts/dev-launch +42 -0
- package/scripts/dev-launch-preload.ts +19 -0
- package/src/auto-thinking/classifier.ts +5 -1
- package/src/cli/args.ts +2 -2
- package/src/cli/dry-balance-cli.ts +52 -17
- package/src/cli/gallery-cli.ts +226 -0
- package/src/cli/gallery-fixtures/agentic.ts +292 -0
- package/src/cli/gallery-fixtures/codeintel.ts +188 -0
- package/src/cli/gallery-fixtures/edit.ts +194 -0
- package/src/cli/gallery-fixtures/fs.ts +153 -0
- package/src/cli/gallery-fixtures/index.ts +40 -0
- package/src/cli/gallery-fixtures/interaction.ts +49 -0
- package/src/cli/gallery-fixtures/memory.ts +81 -0
- package/src/cli/gallery-fixtures/misc.ts +250 -0
- package/src/cli/gallery-fixtures/search.ts +213 -0
- package/src/cli/gallery-fixtures/shell.ts +167 -0
- package/src/cli/gallery-fixtures/types.ts +41 -0
- package/src/cli/gallery-fixtures/web.ts +158 -0
- package/src/cli/gallery-screenshot.ts +279 -0
- package/src/cli-commands.ts +1 -0
- package/src/commands/gallery.ts +52 -0
- package/src/commands/launch.ts +1 -1
- package/src/commit/analysis/conventional.ts +2 -2
- package/src/commit/analysis/summary.ts +2 -2
- package/src/commit/changelog/generate.ts +2 -2
- package/src/commit/changelog/index.ts +2 -2
- package/src/commit/map-reduce/index.ts +3 -3
- package/src/commit/map-reduce/map-phase.ts +2 -2
- package/src/commit/map-reduce/reduce-phase.ts +2 -2
- package/src/commit/model-selection.ts +33 -9
- package/src/commit/pipeline.ts +4 -4
- package/src/config/api-key-resolver.ts +58 -0
- package/src/config/keybindings.ts +15 -6
- package/src/config/model-equivalence.ts +35 -12
- package/src/config/model-id-affixes.ts +39 -22
- package/src/config/model-registry.ts +41 -18
- package/src/config/settings-schema.ts +28 -5
- package/src/config/settings.ts +31 -2
- package/src/dap/client.ts +14 -16
- package/src/dap/config.ts +41 -2
- package/src/dap/defaults.json +1 -0
- package/src/dap/session.ts +1 -0
- package/src/dap/types.ts +10 -0
- package/src/debug/index.ts +40 -54
- package/src/edit/renderer.ts +111 -119
- package/src/eval/__tests__/agent-bridge.test.ts +75 -32
- package/src/eval/__tests__/llm-bridge.test.ts +90 -31
- package/src/eval/agent-bridge.ts +34 -7
- package/src/eval/llm-bridge.ts +8 -3
- package/src/extensibility/extensions/runner.ts +1 -0
- package/src/extensibility/plugins/doctor.ts +0 -1
- package/src/extensibility/plugins/marketplace-auto-update.ts +49 -0
- package/src/goals/tools/goal-tool.ts +37 -27
- package/src/internal-urls/docs-index.generated.ts +10 -10
- package/src/lsp/client.ts +104 -55
- package/src/lsp/types.ts +10 -0
- package/src/lsp/utils.ts +3 -2
- package/src/main.ts +53 -56
- package/src/memories/index.ts +12 -5
- package/src/memory-backend/index.ts +13 -1
- package/src/memory-backend/resolve.ts +3 -5
- package/src/memory-backend/types.ts +1 -1
- package/src/mnemopi/backend.ts +5 -1
- package/src/modes/acp/acp-agent.ts +33 -26
- package/src/modes/components/assistant-message.ts +2 -9
- package/src/modes/components/chat-block.ts +111 -0
- package/src/modes/components/copy-selector.ts +1 -44
- package/src/modes/components/custom-editor.ts +33 -1
- package/src/modes/components/custom-message.ts +1 -3
- package/src/modes/components/execution-shared.ts +1 -2
- package/src/modes/components/hook-message.ts +1 -3
- package/src/modes/components/overlay-box.ts +108 -0
- package/src/modes/components/plan-review-overlay.ts +799 -0
- package/src/modes/components/plan-toc.ts +138 -0
- package/src/modes/components/read-tool-group.ts +20 -4
- package/src/modes/components/skill-message.ts +0 -1
- package/src/modes/components/status-line.ts +3 -5
- package/src/modes/components/tips.txt +1 -0
- package/src/modes/components/todo-reminder.ts +0 -2
- package/src/modes/components/tool-execution.ts +115 -90
- package/src/modes/components/transcript-container.ts +84 -24
- package/src/modes/components/user-message.ts +1 -2
- package/src/modes/controllers/command-controller-shared.ts +7 -6
- package/src/modes/controllers/command-controller.ts +70 -57
- package/src/modes/controllers/event-controller.ts +41 -40
- package/src/modes/controllers/extension-ui-controller.ts +10 -73
- package/src/modes/controllers/input-controller.ts +135 -122
- package/src/modes/controllers/mcp-command-controller.ts +69 -60
- package/src/modes/controllers/selector-controller.ts +25 -27
- package/src/modes/controllers/streaming-reveal.ts +212 -0
- package/src/modes/controllers/tan-command-controller.ts +173 -0
- package/src/modes/index.ts +5 -4
- package/src/modes/interactive-mode.ts +171 -82
- package/src/modes/setup-version.ts +11 -0
- package/src/modes/setup-wizard/index.ts +3 -2
- package/src/modes/setup-wizard/scenes/web-search.ts +3 -2
- package/src/modes/setup-wizard/wizard-overlay.ts +1 -1
- package/src/modes/theme/theme-schema.json +1 -1
- package/src/modes/theme/theme.ts +8 -4
- package/src/modes/types.ts +19 -8
- package/src/modes/utils/context-usage.ts +10 -6
- package/src/modes/utils/copy-targets.ts +133 -27
- package/src/modes/utils/hotkeys-markdown.ts +1 -0
- package/src/modes/utils/ui-helpers.ts +44 -46
- package/src/plan-mode/approved-plan.ts +66 -43
- package/src/plan-mode/plan-protection.ts +4 -4
- package/src/prompts/system/background-tan-dispatch.md +8 -0
- package/src/prompts/system/plan-mode-active.md +67 -58
- package/src/prompts/system/plan-mode-approved.md +1 -1
- package/src/sdk.ts +32 -60
- package/src/session/agent-session.ts +89 -13
- package/src/session/messages.ts +26 -0
- package/src/session/session-manager.ts +13 -5
- package/src/slash-commands/builtin-registry.ts +37 -10
- package/src/slash-commands/helpers/usage-report.ts +2 -0
- package/src/slash-commands/types.ts +4 -6
- package/src/task/executor.ts +25 -4
- package/src/task/index.ts +4 -0
- package/src/task/render.ts +212 -148
- package/src/telemetry-export.ts +25 -7
- package/src/tools/archive-reader.ts +64 -0
- package/src/tools/ask.ts +119 -164
- package/src/tools/ast-edit.ts +98 -71
- package/src/tools/ast-grep.ts +37 -43
- package/src/tools/bash.ts +50 -6
- package/src/tools/debug.ts +20 -8
- package/src/tools/eval-backends.ts +6 -17
- package/src/tools/eval-render.ts +21 -18
- package/src/tools/eval.ts +5 -4
- package/src/tools/fetch.ts +391 -91
- package/src/tools/find.ts +44 -30
- package/src/tools/gh-renderer.ts +81 -42
- package/src/tools/grouped-file-output.ts +272 -48
- package/src/tools/image-gen.ts +150 -103
- package/src/tools/inspect-image-renderer.ts +63 -41
- package/src/tools/inspect-image.ts +8 -1
- package/src/tools/job.ts +3 -4
- package/src/tools/memory-render.ts +4 -1
- package/src/tools/plan-mode-guard.ts +21 -39
- package/src/tools/read.ts +23 -16
- package/src/tools/render-utils.ts +38 -40
- package/src/tools/renderers.ts +16 -1
- package/src/tools/report-tool-issue.ts +1 -1
- package/src/tools/resolve.ts +14 -0
- package/src/tools/search-tool-bm25.ts +36 -23
- package/src/tools/search.ts +189 -95
- package/src/tools/sqlite-reader.ts +9 -12
- package/src/tools/todo.ts +138 -59
- package/src/tools/write.ts +100 -60
- package/src/tui/output-block.ts +60 -13
- package/src/tui/status-line.ts +5 -1
- package/src/utils/commit-message-generator.ts +9 -1
- package/src/utils/enhanced-paste.ts +202 -0
- package/src/utils/title-generator.ts +2 -1
- package/src/web/scrapers/github.ts +255 -3
- package/src/web/scrapers/youtube.ts +3 -2
- package/src/web/search/providers/anthropic.ts +25 -19
- package/src/web/search/providers/exa.ts +11 -3
- package/src/web/search/providers/kimi.ts +28 -17
- package/src/web/search/providers/parallel.ts +35 -24
- package/src/web/search/providers/perplexity.ts +199 -51
- package/src/web/search/providers/synthetic.ts +8 -6
- package/src/web/search/providers/tavily.ts +9 -8
- package/src/web/search/providers/zai.ts +8 -6
- package/src/web/search/render.ts +39 -54
- package/src/web/search/types.ts +5 -1
- package/dist/types/eval/__tests__/shared-executors.test.d.ts +0 -1
- package/src/eval/__tests__/shared-executors.test.ts +0 -609
package/src/debug/index.ts
CHANGED
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
} from "@oh-my-pi/pi-tui";
|
|
20
20
|
import { getSessionsDir } from "@oh-my-pi/pi-utils";
|
|
21
21
|
import { DynamicBorder } from "../modes/components/dynamic-border";
|
|
22
|
+
import { TranscriptBlock } from "../modes/components/transcript-container";
|
|
22
23
|
import { getSelectListTheme, getSymbolTheme, theme } from "../modes/theme/theme";
|
|
23
24
|
import type { InteractiveModeContext } from "../modes/types";
|
|
24
25
|
import { formatBytes } from "../tools/render-utils";
|
|
@@ -150,13 +151,13 @@ export class DebugSelectorComponent extends Container {
|
|
|
150
151
|
}
|
|
151
152
|
|
|
152
153
|
// Show message and wait for keypress
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
154
|
+
const block = new TranscriptBlock();
|
|
155
|
+
block.addChild(new Text(theme.fg("accent", `${theme.status.info} CPU profiling started`), 1, 0));
|
|
156
|
+
block.addChild(new Spacer(1));
|
|
157
|
+
block.addChild(
|
|
157
158
|
new Text(theme.fg("muted", "Reproduce the performance issue, then press Enter to stop profiling."), 1, 0),
|
|
158
159
|
);
|
|
159
|
-
this.ctx.
|
|
160
|
+
this.ctx.present(block);
|
|
160
161
|
|
|
161
162
|
// Wait for Enter keypress
|
|
162
163
|
const { promise, resolve } = Promise.withResolvers<void>();
|
|
@@ -201,19 +202,16 @@ export class DebugSelectorComponent extends Container {
|
|
|
201
202
|
loader.stop();
|
|
202
203
|
this.ctx.statusContainer.clear();
|
|
203
204
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
);
|
|
208
|
-
this.ctx.
|
|
209
|
-
this.ctx.chatContainer.addChild(new Text(theme.fg("dim", `Files: ${result.files.length}`), 1, 0));
|
|
205
|
+
const block = new TranscriptBlock();
|
|
206
|
+
block.addChild(new Text(theme.fg("success", `${theme.status.success} Performance report saved`), 1, 0));
|
|
207
|
+
block.addChild(new Text(theme.fg("dim", formatFileHyperlink(result.path)), 1, 0));
|
|
208
|
+
block.addChild(new Text(theme.fg("dim", `Files: ${result.files.length}`), 1, 0));
|
|
209
|
+
this.ctx.present(block);
|
|
210
210
|
} catch (err) {
|
|
211
211
|
loader.stop();
|
|
212
212
|
this.ctx.statusContainer.clear();
|
|
213
213
|
this.ctx.showError(`Failed to create report: ${err instanceof Error ? err.message : String(err)}`);
|
|
214
214
|
}
|
|
215
|
-
|
|
216
|
-
this.ctx.ui.requestRender();
|
|
217
215
|
}
|
|
218
216
|
|
|
219
217
|
async #handleWorkReport(): Promise<void> {
|
|
@@ -231,15 +229,13 @@ export class DebugSelectorComponent extends Container {
|
|
|
231
229
|
|
|
232
230
|
openPath(tmpPath);
|
|
233
231
|
|
|
234
|
-
this.ctx.
|
|
235
|
-
|
|
232
|
+
this.ctx.present([
|
|
233
|
+
new Spacer(1),
|
|
236
234
|
new Text(theme.fg("dim", `Opened flamegraph (${workProfile.sampleCount} samples)`), 1, 0),
|
|
237
|
-
);
|
|
235
|
+
]);
|
|
238
236
|
} catch (err) {
|
|
239
237
|
this.ctx.showError(`Failed to open profile: ${err instanceof Error ? err.message : String(err)}`);
|
|
240
238
|
}
|
|
241
|
-
|
|
242
|
-
this.ctx.ui.requestRender();
|
|
243
239
|
}
|
|
244
240
|
|
|
245
241
|
async #handleDumpReport(): Promise<void> {
|
|
@@ -262,19 +258,16 @@ export class DebugSelectorComponent extends Container {
|
|
|
262
258
|
loader.stop();
|
|
263
259
|
this.ctx.statusContainer.clear();
|
|
264
260
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
);
|
|
269
|
-
this.ctx.
|
|
270
|
-
this.ctx.chatContainer.addChild(new Text(theme.fg("dim", `Files: ${result.files.length}`), 1, 0));
|
|
261
|
+
const block = new TranscriptBlock();
|
|
262
|
+
block.addChild(new Text(theme.fg("success", `${theme.status.success} Report bundle saved`), 1, 0));
|
|
263
|
+
block.addChild(new Text(theme.fg("dim", formatFileHyperlink(result.path)), 1, 0));
|
|
264
|
+
block.addChild(new Text(theme.fg("dim", `Files: ${result.files.length}`), 1, 0));
|
|
265
|
+
this.ctx.present(block);
|
|
271
266
|
} catch (err) {
|
|
272
267
|
loader.stop();
|
|
273
268
|
this.ctx.statusContainer.clear();
|
|
274
269
|
this.ctx.showError(`Failed to create report: ${err instanceof Error ? err.message : String(err)}`);
|
|
275
270
|
}
|
|
276
|
-
|
|
277
|
-
this.ctx.ui.requestRender();
|
|
278
271
|
}
|
|
279
272
|
|
|
280
273
|
async #handleMemoryReport(): Promise<void> {
|
|
@@ -301,19 +294,16 @@ export class DebugSelectorComponent extends Container {
|
|
|
301
294
|
loader.stop();
|
|
302
295
|
this.ctx.statusContainer.clear();
|
|
303
296
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
);
|
|
308
|
-
this.ctx.
|
|
309
|
-
this.ctx.chatContainer.addChild(new Text(theme.fg("dim", `Files: ${result.files.length}`), 1, 0));
|
|
297
|
+
const block = new TranscriptBlock();
|
|
298
|
+
block.addChild(new Text(theme.fg("success", `${theme.status.success} Memory report saved`), 1, 0));
|
|
299
|
+
block.addChild(new Text(theme.fg("dim", formatFileHyperlink(result.path)), 1, 0));
|
|
300
|
+
block.addChild(new Text(theme.fg("dim", `Files: ${result.files.length}`), 1, 0));
|
|
301
|
+
this.ctx.present(block);
|
|
310
302
|
} catch (err) {
|
|
311
303
|
loader.stop();
|
|
312
304
|
this.ctx.statusContainer.clear();
|
|
313
305
|
this.ctx.showError(`Failed to create report: ${err instanceof Error ? err.message : String(err)}`);
|
|
314
306
|
}
|
|
315
|
-
|
|
316
|
-
this.ctx.ui.requestRender();
|
|
317
307
|
}
|
|
318
308
|
|
|
319
309
|
async #handleViewLogs(): Promise<void> {
|
|
@@ -365,15 +355,14 @@ export class DebugSelectorComponent extends Container {
|
|
|
365
355
|
const info = await collectSystemInfo();
|
|
366
356
|
const formatted = formatSystemInfo(info);
|
|
367
357
|
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
358
|
+
const block = new TranscriptBlock();
|
|
359
|
+
block.addChild(new DynamicBorder());
|
|
360
|
+
block.addChild(new Text(formatted, 1, 0));
|
|
361
|
+
block.addChild(new DynamicBorder());
|
|
362
|
+
this.ctx.present(block);
|
|
372
363
|
} catch (err) {
|
|
373
364
|
this.ctx.showError(`Failed to collect system info: ${err instanceof Error ? err.message : String(err)}`);
|
|
374
365
|
}
|
|
375
|
-
|
|
376
|
-
this.ctx.ui.requestRender();
|
|
377
366
|
}
|
|
378
367
|
|
|
379
368
|
async #handleViewTerminalState(): Promise<void> {
|
|
@@ -384,11 +373,11 @@ export class DebugSelectorComponent extends Container {
|
|
|
384
373
|
});
|
|
385
374
|
const formatted = formatTerminalState(info);
|
|
386
375
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
this.ctx.
|
|
376
|
+
const block = new TranscriptBlock();
|
|
377
|
+
block.addChild(new DynamicBorder());
|
|
378
|
+
block.addChild(new Text(formatted, 1, 0));
|
|
379
|
+
block.addChild(new DynamicBorder());
|
|
380
|
+
this.ctx.present(block);
|
|
392
381
|
}
|
|
393
382
|
|
|
394
383
|
async #handleViewProtocols(): Promise<void> {
|
|
@@ -407,15 +396,14 @@ export class DebugSelectorComponent extends Container {
|
|
|
407
396
|
TERMINAL.sendNotification(notification);
|
|
408
397
|
}
|
|
409
398
|
|
|
410
|
-
this.ctx.
|
|
411
|
-
|
|
399
|
+
this.ctx.present([
|
|
400
|
+
new Spacer(1),
|
|
412
401
|
new ProtocolProbeComponent({
|
|
413
402
|
image: buildSampleImage(),
|
|
414
403
|
imageBudget: this.ctx.ui.imageBudget,
|
|
415
404
|
notificationSuppressed: suppressed,
|
|
416
405
|
}),
|
|
417
|
-
);
|
|
418
|
-
this.ctx.ui.requestRender();
|
|
406
|
+
]);
|
|
419
407
|
}
|
|
420
408
|
|
|
421
409
|
async #handleTranscriptExport(): Promise<void> {
|
|
@@ -487,21 +475,19 @@ export class DebugSelectorComponent extends Container {
|
|
|
487
475
|
loader.stop();
|
|
488
476
|
this.ctx.statusContainer.clear();
|
|
489
477
|
|
|
490
|
-
this.ctx.
|
|
491
|
-
|
|
478
|
+
this.ctx.present([
|
|
479
|
+
new Spacer(1),
|
|
492
480
|
new Text(
|
|
493
481
|
theme.fg("success", `${theme.status.success} Cleared ${result.removed} artifact directories`),
|
|
494
482
|
1,
|
|
495
483
|
0,
|
|
496
484
|
),
|
|
497
|
-
);
|
|
485
|
+
]);
|
|
498
486
|
} catch (err) {
|
|
499
487
|
loader.stop();
|
|
500
488
|
this.ctx.statusContainer.clear();
|
|
501
489
|
this.ctx.showError(`Failed to clear cache: ${err instanceof Error ? err.message : String(err)}`);
|
|
502
490
|
}
|
|
503
|
-
|
|
504
|
-
this.ctx.ui.requestRender();
|
|
505
491
|
}
|
|
506
492
|
|
|
507
493
|
#getResolvedSettings(): Record<string, unknown> {
|
package/src/edit/renderer.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import { HL_FILE_PREFIX, HL_FILE_SUFFIX } from "@oh-my-pi/hashline";
|
|
6
6
|
import type { Component } from "@oh-my-pi/pi-tui";
|
|
7
|
-
import {
|
|
7
|
+
import { visibleWidth, wrapTextWithAnsi } from "@oh-my-pi/pi-tui";
|
|
8
8
|
import { sanitizeText } from "@oh-my-pi/pi-utils";
|
|
9
9
|
import type { RenderResultOptions } from "../extensibility/custom-tools/types";
|
|
10
10
|
import type { FileDiagnosticsResult } from "../lsp";
|
|
@@ -16,7 +16,6 @@ import {
|
|
|
16
16
|
formatDiffStats,
|
|
17
17
|
formatExpandHint,
|
|
18
18
|
formatStatusIcon,
|
|
19
|
-
formatTitle,
|
|
20
19
|
getDiffStats,
|
|
21
20
|
getLspBatchRequest,
|
|
22
21
|
type LspBatchRequest,
|
|
@@ -25,7 +24,7 @@ import {
|
|
|
25
24
|
shortenPath,
|
|
26
25
|
truncateDiffByHunk,
|
|
27
26
|
} from "../tools/render-utils";
|
|
28
|
-
import { fileHyperlink, Hasher, type RenderCache, renderStatusLine, truncateToWidth } from "../tui";
|
|
27
|
+
import { fileHyperlink, framedBlock, Hasher, type RenderCache, renderStatusLine, truncateToWidth } from "../tui";
|
|
29
28
|
import type { EditMode } from "../utils/edit-mode";
|
|
30
29
|
import type { DiffError, DiffResult } from "./diff";
|
|
31
30
|
import { type ApplyPatchEntry, expandApplyPatchToEntries, expandApplyPatchToPreviewEntries } from "./modes/apply-patch";
|
|
@@ -179,11 +178,6 @@ function countEditFiles(edits: EditRenderEntry[]): number {
|
|
|
179
178
|
return new Set(edits.map(edit => filePathFromEditEntry(edit.path)).filter(Boolean)).size;
|
|
180
179
|
}
|
|
181
180
|
|
|
182
|
-
function countLines(text: string): number {
|
|
183
|
-
if (!text) return 0;
|
|
184
|
-
return text.split("\n").length;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
181
|
function getOperationTitle(op: Operation | undefined): string {
|
|
188
182
|
return op === "create" ? "Create" : op === "delete" ? "Delete" : "Edit";
|
|
189
183
|
}
|
|
@@ -191,10 +185,14 @@ function getOperationTitle(op: Operation | undefined): string {
|
|
|
191
185
|
function formatEditPathDisplay(
|
|
192
186
|
rawPath: string,
|
|
193
187
|
uiTheme: Theme,
|
|
194
|
-
options?: { rename?: string; firstChangedLine?: number },
|
|
188
|
+
options?: { rename?: string; firstChangedLine?: number; linkPath?: string; renameLinkPath?: string },
|
|
195
189
|
): string {
|
|
190
|
+
// `rawPath`/`rename` are shown (cwd-relative) but the OSC 8 link targets the
|
|
191
|
+
// absolute path when known — a relative `rawPath` would yield a `file:///rel`
|
|
192
|
+
// URI that resolves against filesystem root instead of cwd.
|
|
193
|
+
const linkTarget = options?.linkPath || rawPath;
|
|
196
194
|
let pathDisplay = rawPath
|
|
197
|
-
? fileHyperlink(
|
|
195
|
+
? fileHyperlink(linkTarget, uiTheme.fg("accent", shortenPath(rawPath)))
|
|
198
196
|
: uiTheme.fg("toolOutput", "…");
|
|
199
197
|
|
|
200
198
|
if (options?.firstChangedLine) {
|
|
@@ -202,7 +200,8 @@ function formatEditPathDisplay(
|
|
|
202
200
|
}
|
|
203
201
|
|
|
204
202
|
if (options?.rename) {
|
|
205
|
-
|
|
203
|
+
const renameTarget = options.renameLinkPath || options.rename;
|
|
204
|
+
pathDisplay += ` ${uiTheme.fg("dim", "→")} ${fileHyperlink(renameTarget, uiTheme.fg("accent", shortenPath(options.rename)))}`;
|
|
206
205
|
}
|
|
207
206
|
|
|
208
207
|
return pathDisplay;
|
|
@@ -211,7 +210,7 @@ function formatEditPathDisplay(
|
|
|
211
210
|
function formatEditDescription(
|
|
212
211
|
rawPath: string,
|
|
213
212
|
uiTheme: Theme,
|
|
214
|
-
options?: { rename?: string; firstChangedLine?: number },
|
|
213
|
+
options?: { rename?: string; firstChangedLine?: number; linkPath?: string; renameLinkPath?: string },
|
|
215
214
|
): { language: string; description: string } {
|
|
216
215
|
const language = getLanguageFromPath(rawPath) ?? "text";
|
|
217
216
|
const icon = uiTheme.fg("muted", uiTheme.getLangIcon(language));
|
|
@@ -233,19 +232,22 @@ function renderPlainTextPreview(text: string, uiTheme: Theme, filePath?: string)
|
|
|
233
232
|
return preview.trimEnd();
|
|
234
233
|
}
|
|
235
234
|
|
|
236
|
-
function formatStreamingDiff(
|
|
235
|
+
function formatStreamingDiff(
|
|
236
|
+
diff: string,
|
|
237
|
+
rawPath: string,
|
|
238
|
+
uiTheme: Theme,
|
|
239
|
+
expanded: boolean,
|
|
240
|
+
label = "streaming",
|
|
241
|
+
): string {
|
|
237
242
|
if (!diff) return "";
|
|
238
|
-
// "Cursor" tail window: pin the last
|
|
239
|
-
//
|
|
240
|
-
//
|
|
241
|
-
//
|
|
242
|
-
//
|
|
243
|
-
//
|
|
244
|
-
// stuttered, and the earlier high-water fix traded that for a half-empty
|
|
245
|
-
// rectangle. A strict fixed-height window keeps the box steady and always
|
|
246
|
-
// full of real diff context instead of blank padding.
|
|
243
|
+
// Collapsed uses a "Cursor" tail window: pin the last
|
|
244
|
+
// EDIT_STREAMING_PREVIEW_LINES rows to the bottom so freshly streamed changes
|
|
245
|
+
// stay on screen. The whole-file diff is recomputed on every streamed chunk
|
|
246
|
+
// and its Myers alignment is not monotonic in payload length, so a hunk-aware
|
|
247
|
+
// window stutters as rows move between hunks. Expanded deliberately lifts that
|
|
248
|
+
// cap for the approval-time full view.
|
|
247
249
|
const allLines = diff.replace(/\n+$/u, "").split("\n");
|
|
248
|
-
const hiddenLines = Math.max(0, allLines.length - EDIT_STREAMING_PREVIEW_LINES);
|
|
250
|
+
const hiddenLines = expanded ? 0 : Math.max(0, allLines.length - EDIT_STREAMING_PREVIEW_LINES);
|
|
249
251
|
const visible = hiddenLines > 0 ? allLines.slice(hiddenLines) : allLines;
|
|
250
252
|
let text = "\n\n";
|
|
251
253
|
if (hiddenLines > 0) {
|
|
@@ -256,19 +258,11 @@ function formatStreamingDiff(diff: string, rawPath: string, uiTheme: Theme, labe
|
|
|
256
258
|
text += `${uiTheme.fg("dim", `… (${remainder.join(", ")} above)`)}\n`;
|
|
257
259
|
}
|
|
258
260
|
text += renderDiffColored(visible.join("\n"), { filePath: rawPath });
|
|
259
|
-
text += uiTheme.fg("dim", `\n(${label})`);
|
|
261
|
+
if (!expanded || label !== "preview") text += uiTheme.fg("dim", `\n(${label})`);
|
|
260
262
|
return text;
|
|
261
263
|
}
|
|
262
264
|
|
|
263
|
-
function
|
|
264
|
-
const icon = uiTheme.getLangIcon(language);
|
|
265
|
-
if (lineCount !== null) {
|
|
266
|
-
return uiTheme.fg("dim", `${icon} ${lineCount} lines`);
|
|
267
|
-
}
|
|
268
|
-
return uiTheme.fg("dim", `${icon}`);
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
function formatMultiFileStreamingDiff(previews: PerFileDiffPreview[], uiTheme: Theme): string {
|
|
265
|
+
function formatMultiFileStreamingDiff(previews: PerFileDiffPreview[], uiTheme: Theme, expanded: boolean): string {
|
|
272
266
|
const parts: string[] = [];
|
|
273
267
|
for (const preview of previews) {
|
|
274
268
|
if (!preview.diff && !preview.error) continue;
|
|
@@ -278,7 +272,7 @@ function formatMultiFileStreamingDiff(previews: PerFileDiffPreview[], uiTheme: T
|
|
|
278
272
|
continue;
|
|
279
273
|
}
|
|
280
274
|
if (preview.diff) {
|
|
281
|
-
parts.push(`${header}${formatStreamingDiff(preview.diff, preview.path, uiTheme, "preview")}`);
|
|
275
|
+
parts.push(`${header}${formatStreamingDiff(preview.diff, preview.path, uiTheme, expanded, "preview")}`);
|
|
282
276
|
}
|
|
283
277
|
}
|
|
284
278
|
return parts.join("");
|
|
@@ -289,16 +283,17 @@ function getCallPreview(
|
|
|
289
283
|
rawPath: string,
|
|
290
284
|
uiTheme: Theme,
|
|
291
285
|
renderContext: EditRenderContext | undefined,
|
|
286
|
+
expanded: boolean,
|
|
292
287
|
): string {
|
|
293
288
|
const multi = renderContext?.perFileDiffPreview;
|
|
294
289
|
if (multi && multi.length > 1 && multi.some(p => p.diff || p.error)) {
|
|
295
|
-
return formatMultiFileStreamingDiff(multi, uiTheme);
|
|
290
|
+
return formatMultiFileStreamingDiff(multi, uiTheme, expanded);
|
|
296
291
|
}
|
|
297
292
|
if (args.previewDiff) {
|
|
298
|
-
return formatStreamingDiff(args.previewDiff, rawPath, uiTheme, "preview");
|
|
293
|
+
return formatStreamingDiff(args.previewDiff, rawPath, uiTheme, expanded, "preview");
|
|
299
294
|
}
|
|
300
295
|
if (args.diff && args.op) {
|
|
301
|
-
return formatStreamingDiff(args.diff, rawPath, uiTheme);
|
|
296
|
+
return formatStreamingDiff(args.diff, rawPath, uiTheme, expanded);
|
|
302
297
|
}
|
|
303
298
|
if (args.diff) {
|
|
304
299
|
return renderPlainTextPreview(args.diff, uiTheme, rawPath);
|
|
@@ -383,6 +378,13 @@ function getApplyPatchRenderSummary(
|
|
|
383
378
|
}
|
|
384
379
|
}
|
|
385
380
|
|
|
381
|
+
function formatDiffStatsSuffix(diff: string, uiTheme: Theme): string {
|
|
382
|
+
const { added, removed, hunks } = getDiffStats(diff);
|
|
383
|
+
const stats = formatDiffStats(added, removed, hunks, uiTheme);
|
|
384
|
+
if (!stats) return "";
|
|
385
|
+
return ` ${uiTheme.fg("dim", uiTheme.format.bracketLeft)}${stats}${uiTheme.fg("dim", uiTheme.format.bracketRight)}`;
|
|
386
|
+
}
|
|
387
|
+
|
|
386
388
|
function renderDiffSection(
|
|
387
389
|
diff: string,
|
|
388
390
|
rawPath: string,
|
|
@@ -390,15 +392,6 @@ function renderDiffSection(
|
|
|
390
392
|
uiTheme: Theme,
|
|
391
393
|
renderDiffFn: (t: string, o?: { filePath?: string }) => string,
|
|
392
394
|
): string {
|
|
393
|
-
let text = "";
|
|
394
|
-
const diffStats = getDiffStats(diff);
|
|
395
|
-
text += `\n${uiTheme.fg("dim", uiTheme.format.bracketLeft)}${formatDiffStats(
|
|
396
|
-
diffStats.added,
|
|
397
|
-
diffStats.removed,
|
|
398
|
-
diffStats.hunks,
|
|
399
|
-
uiTheme,
|
|
400
|
-
)}${uiTheme.fg("dim", uiTheme.format.bracketRight)}`;
|
|
401
|
-
|
|
402
395
|
const {
|
|
403
396
|
text: truncatedDiff,
|
|
404
397
|
hiddenHunks,
|
|
@@ -407,7 +400,7 @@ function renderDiffSection(
|
|
|
407
400
|
? { text: diff, hiddenHunks: 0, hiddenLines: 0 }
|
|
408
401
|
: truncateDiffByHunk(diff, PREVIEW_LIMITS.DIFF_COLLAPSED_HUNKS, PREVIEW_LIMITS.DIFF_COLLAPSED_LINES);
|
|
409
402
|
|
|
410
|
-
text
|
|
403
|
+
let text = `\n${renderDiffFn(truncatedDiff, { filePath: rawPath })}`;
|
|
411
404
|
if (!expanded && (hiddenHunks > 0 || hiddenLines > 0)) {
|
|
412
405
|
const remainder: string[] = [];
|
|
413
406
|
if (hiddenHunks > 0) remainder.push(`${hiddenHunks} more hunks`);
|
|
@@ -470,23 +463,31 @@ export const editToolRenderer = {
|
|
|
470
463
|
const rename = editArgs.rename || firstEdit?.rename || firstEdit?.move || firstApplyPatchEntry?.rename;
|
|
471
464
|
const op = editArgs.op || firstEdit?.op || firstApplyPatchEntry?.op;
|
|
472
465
|
const { description } = formatEditDescription(rawPath, uiTheme, { rename });
|
|
473
|
-
const spinner =
|
|
474
|
-
options?.spinnerFrame !== undefined ? formatStatusIcon("running", uiTheme, options.spinnerFrame) : "";
|
|
475
|
-
let text = `${formatTitle(getOperationTitle(op), uiTheme)} ${spinner ? `${spinner} ` : ""}${description}`;
|
|
476
|
-
// Show file count hint for multi-file edits
|
|
477
466
|
let fileCount = hashlineInputSummary?.entries.length ?? applyPatchSummary?.entries.length ?? 0;
|
|
478
467
|
if (Array.isArray(editArgs.edits)) {
|
|
479
468
|
fileCount = countEditFiles(editArgs.edits);
|
|
480
469
|
}
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
470
|
+
return framedBlock(uiTheme, width => {
|
|
471
|
+
let header = renderStatusLine(
|
|
472
|
+
{ icon: "pending", spinnerFrame: options?.spinnerFrame, title: getOperationTitle(op), description },
|
|
473
|
+
uiTheme,
|
|
474
|
+
);
|
|
475
|
+
if (fileCount > 1) header += uiTheme.fg("dim", ` (+${fileCount - 1} more)`);
|
|
476
|
+
let body = getCallPreview(editArgs, rawPath, uiTheme, renderContext, options.expanded);
|
|
477
|
+
if (applyPatchSummary?.error) {
|
|
478
|
+
body += `\n${uiTheme.fg("error", truncateToWidth(replaceTabs(applyPatchSummary.error, rawPath), Math.max(1, width - 2)))}`;
|
|
479
|
+
}
|
|
480
|
+
const bodyLines = body ? body.split("\n") : [];
|
|
481
|
+
while (bodyLines.length > 0 && bodyLines[0].trim() === "") bodyLines.shift();
|
|
482
|
+
return {
|
|
483
|
+
header,
|
|
484
|
+
sections: bodyLines.length > 0 ? [{ lines: bodyLines }] : [],
|
|
485
|
+
state: applyPatchSummary?.error ? "error" : "pending",
|
|
486
|
+
borderColor: applyPatchSummary?.error ? "error" : "borderMuted",
|
|
487
|
+
width,
|
|
488
|
+
contentPaddingLeft: 0,
|
|
489
|
+
};
|
|
490
|
+
});
|
|
490
491
|
},
|
|
491
492
|
|
|
492
493
|
renderResult(
|
|
@@ -528,11 +529,6 @@ function renderSingleFileResult(
|
|
|
528
529
|
"";
|
|
529
530
|
const op = args?.op || firstEdit?.op || details?.op;
|
|
530
531
|
const rename = args?.rename || firstEdit?.rename || firstEdit?.move || details?.move;
|
|
531
|
-
const { language } = formatEditDescription(rawPath, uiTheme, { rename });
|
|
532
|
-
|
|
533
|
-
const editTextSource = args?.newText ?? args?.oldText ?? args?.diff ?? args?.patch;
|
|
534
|
-
const metadataLineCount = editTextSource ? countLines(editTextSource) : null;
|
|
535
|
-
const metadataLine = op !== "delete" ? `\n${formatMetadataLine(metadataLineCount, language, uiTheme)}` : "";
|
|
536
532
|
|
|
537
533
|
const displayErrorText = isError && details && "displayErrorText" in details ? details.displayErrorText : undefined;
|
|
538
534
|
const errorText = isError
|
|
@@ -541,61 +537,57 @@ function renderSingleFileResult(
|
|
|
541
537
|
(result.content?.find(c => c.type === "text")?.text ?? "")
|
|
542
538
|
: "";
|
|
543
539
|
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
540
|
+
return framedBlock(uiTheme, width => {
|
|
541
|
+
const { expanded, renderContext } = options;
|
|
542
|
+
const editDiffPreview = renderContext?.editDiffPreview;
|
|
543
|
+
const renderDiffFn = renderContext?.renderDiff ?? ((t: string) => t);
|
|
544
|
+
|
|
545
|
+
const firstChangedLine =
|
|
546
|
+
(editDiffPreview && "firstChangedLine" in editDiffPreview ? editDiffPreview.firstChangedLine : undefined) ||
|
|
547
|
+
(details && !isError ? details.firstChangedLine : undefined);
|
|
548
|
+
const linkPath = details && "path" in details ? details.path : undefined;
|
|
549
|
+
const { description } = formatEditDescription(rawPath, uiTheme, { rename, firstChangedLine, linkPath });
|
|
550
|
+
|
|
551
|
+
// Change stats ride inline on the header bar next to the path.
|
|
552
|
+
const previewDiff = editDiffPreview && !("error" in editDiffPreview) ? editDiffPreview.diff : undefined;
|
|
553
|
+
const headerDiff = isError ? undefined : details?.diff || previewDiff;
|
|
554
|
+
const statsSuffix = headerDiff ? formatDiffStatsSuffix(headerDiff, uiTheme) : "";
|
|
555
|
+
const header =
|
|
556
|
+
renderStatusLine({ icon: isError ? "error" : "success", title: getOperationTitle(op), description }, uiTheme) +
|
|
557
|
+
statsSuffix;
|
|
558
|
+
|
|
559
|
+
let body = "";
|
|
560
|
+
if (isError) {
|
|
561
|
+
if (errorText) body = uiTheme.fg("error", replaceTabs(errorText, rawPath));
|
|
562
|
+
} else if (details?.diff) {
|
|
563
|
+
body = renderDiffSection(details.diff, rawPath, expanded, uiTheme, renderDiffFn);
|
|
564
|
+
} else if (editDiffPreview) {
|
|
565
|
+
if ("error" in editDiffPreview) body = uiTheme.fg("error", replaceTabs(editDiffPreview.error, rawPath));
|
|
566
|
+
else if (editDiffPreview.diff)
|
|
567
|
+
body = renderDiffSection(editDiffPreview.diff, rawPath, expanded, uiTheme, renderDiffFn);
|
|
568
|
+
}
|
|
569
|
+
if (details?.diagnostics) {
|
|
570
|
+
body += formatDiagnostics(details.diagnostics, expanded, uiTheme, (fp: string) =>
|
|
571
|
+
uiTheme.getLangIcon(getLanguageFromPath(fp)),
|
|
566
572
|
);
|
|
567
|
-
|
|
568
|
-
text += metadataLine;
|
|
569
|
-
|
|
570
|
-
if (isError) {
|
|
571
|
-
if (errorText) {
|
|
572
|
-
text += `\n\n${uiTheme.fg("error", replaceTabs(errorText, rawPath))}`;
|
|
573
|
-
}
|
|
574
|
-
} else if (details?.diff) {
|
|
575
|
-
text += renderDiffSection(details.diff, rawPath, expanded, uiTheme, renderDiffFn);
|
|
576
|
-
} else if (editDiffPreview) {
|
|
577
|
-
if ("error" in editDiffPreview) {
|
|
578
|
-
text += `\n\n${uiTheme.fg("error", replaceTabs(editDiffPreview.error, rawPath))}`;
|
|
579
|
-
} else if (editDiffPreview.diff) {
|
|
580
|
-
text += renderDiffSection(editDiffPreview.diff, rawPath, expanded, uiTheme, renderDiffFn);
|
|
581
|
-
}
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
if (details?.diagnostics) {
|
|
585
|
-
text += formatDiagnostics(details.diagnostics, expanded, uiTheme, (fp: string) =>
|
|
586
|
-
uiTheme.getLangIcon(getLanguageFromPath(fp)),
|
|
587
|
-
);
|
|
588
|
-
}
|
|
573
|
+
}
|
|
589
574
|
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
575
|
+
// Diff lines self-wrap with a continuation gutter; pre-wrap to the frame's
|
|
576
|
+
// inner width so renderOutputBlock's generic wrap is a no-op. Edit frames
|
|
577
|
+
// use a flush left border because code-frame gutters already provide padding.
|
|
578
|
+
const innerWidth = Math.max(1, width - 2);
|
|
579
|
+
const bodyLines = body.length > 0 ? body.split("\n").flatMap(line => wrapEditRendererLine(line, innerWidth)) : [];
|
|
580
|
+
while (bodyLines.length > 0 && bodyLines[0].trim() === "") bodyLines.shift();
|
|
581
|
+
|
|
582
|
+
return {
|
|
583
|
+
header,
|
|
584
|
+
sections: bodyLines.length > 0 ? [{ lines: bodyLines }] : [],
|
|
585
|
+
state: isError ? "error" : options.isPartial ? "pending" : "success",
|
|
586
|
+
borderColor: isError ? "error" : "borderMuted",
|
|
587
|
+
width,
|
|
588
|
+
contentPaddingLeft: 0,
|
|
589
|
+
};
|
|
590
|
+
});
|
|
599
591
|
}
|
|
600
592
|
|
|
601
593
|
function renderMultiFileResult(
|
|
@@ -650,7 +642,7 @@ function renderMultiFileResult(
|
|
|
650
642
|
},
|
|
651
643
|
invalidate() {
|
|
652
644
|
cached = undefined;
|
|
653
|
-
for (const c of fileComponents) c.invalidate();
|
|
645
|
+
for (const c of fileComponents) c.invalidate?.();
|
|
654
646
|
},
|
|
655
647
|
};
|
|
656
648
|
}
|