@oh-my-pi/pi-coding-agent 14.9.9 → 15.0.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 +123 -0
- package/examples/extensions/plan-mode.ts +0 -1
- package/package.json +9 -9
- package/scripts/build-binary.ts +5 -0
- package/scripts/format-prompts.ts +1 -1
- package/src/autoresearch/helpers.ts +17 -0
- package/src/autoresearch/tools/log-experiment.ts +9 -17
- package/src/autoresearch/tools/run-experiment.ts +2 -17
- package/src/capability/skill.ts +7 -0
- package/src/cli/args.ts +2 -2
- package/src/cli/list-models.ts +1 -1
- package/src/cli/shell-cli.ts +3 -13
- package/src/cli/update-cli.ts +1 -1
- package/src/cli.ts +11 -29
- package/src/commands/acp.ts +24 -0
- package/src/commands/launch.ts +6 -4
- package/src/commit/agentic/prompts/system.md +1 -1
- package/src/commit/agentic/tools/propose-changelog.ts +8 -1
- package/src/commit/analysis/conventional.ts +8 -66
- package/src/commit/map-reduce/reduce-phase.ts +6 -65
- package/src/commit/pipeline.ts +2 -2
- package/src/commit/shared-llm.ts +89 -0
- package/src/config/config-file.ts +210 -0
- package/src/config/model-equivalence.ts +8 -11
- package/src/config/model-registry.ts +13 -2
- package/src/config/model-resolver.ts +31 -4
- package/src/config/settings-schema.ts +102 -1
- package/src/config/settings.ts +1 -1
- package/src/config.ts +3 -219
- package/src/edit/index.ts +22 -1
- package/src/edit/modes/patch.ts +10 -0
- package/src/edit/modes/replace.ts +3 -0
- package/src/edit/renderer.ts +17 -1
- package/src/eval/js/context-manager.ts +1 -1
- package/src/eval/js/executor.ts +3 -0
- package/src/eval/js/shared/rewrite-imports.ts +122 -50
- package/src/eval/js/shared/runtime.ts +31 -4
- package/src/eval/js/tool-bridge.ts +43 -21
- package/src/eval/py/executor.ts +5 -0
- package/src/exa/factory.ts +2 -2
- package/src/exa/mcp-client.ts +74 -1
- package/src/exec/bash-executor.ts +5 -1
- package/src/export/html/template.generated.ts +1 -1
- package/src/export/html/template.js +0 -11
- package/src/extensibility/extensions/runner.ts +55 -2
- package/src/extensibility/extensions/types.ts +98 -221
- package/src/extensibility/hooks/types.ts +89 -314
- package/src/extensibility/shared-events.ts +343 -0
- package/src/extensibility/skills.ts +42 -1
- package/src/goals/index.ts +3 -0
- package/src/goals/runtime.ts +500 -0
- package/src/goals/state.ts +37 -0
- package/src/goals/tools/goal-tool.ts +237 -0
- package/src/hashline/anchors.ts +2 -2
- package/src/hindsight/mental-models.ts +1 -1
- package/src/internal-urls/agent-protocol.ts +1 -20
- package/src/internal-urls/artifact-protocol.ts +1 -19
- package/src/internal-urls/docs-index.generated.ts +9 -10
- package/src/internal-urls/index.ts +1 -0
- package/src/internal-urls/issue-pr-protocol.ts +577 -0
- package/src/internal-urls/registry-helpers.ts +25 -0
- package/src/internal-urls/router.ts +6 -3
- package/src/internal-urls/types.ts +22 -1
- package/src/main.ts +24 -11
- package/src/mcp/oauth-flow.ts +20 -0
- package/src/modes/acp/acp-agent.ts +412 -71
- package/src/modes/acp/acp-client-bridge.ts +152 -0
- package/src/modes/acp/acp-event-mapper.ts +180 -15
- package/src/modes/acp/terminal-auth.ts +37 -0
- package/src/modes/components/assistant-message.ts +14 -8
- package/src/modes/components/bash-execution.ts +24 -63
- package/src/modes/components/custom-message.ts +14 -40
- package/src/modes/components/eval-execution.ts +27 -57
- package/src/modes/components/execution-shared.ts +102 -0
- package/src/modes/components/hook-message.ts +17 -49
- package/src/modes/components/mcp-add-wizard.ts +26 -5
- package/src/modes/components/message-frame.ts +88 -0
- package/src/modes/components/model-selector.ts +1 -1
- package/src/modes/components/read-tool-group.ts +29 -1
- package/src/modes/components/session-observer-overlay.ts +6 -2
- package/src/modes/components/session-selector.ts +1 -1
- package/src/modes/components/status-line/segments.ts +55 -4
- package/src/modes/components/status-line/types.ts +4 -0
- package/src/modes/components/status-line.ts +28 -10
- package/src/modes/components/tool-execution.ts +7 -8
- package/src/modes/controllers/command-controller-shared.ts +108 -0
- package/src/modes/controllers/command-controller.ts +27 -10
- package/src/modes/controllers/event-controller.ts +60 -18
- package/src/modes/controllers/extension-ui-controller.ts +8 -2
- package/src/modes/controllers/input-controller.ts +85 -39
- package/src/modes/controllers/mcp-command-controller.ts +56 -61
- package/src/modes/controllers/ssh-command-controller.ts +18 -57
- package/src/modes/interactive-mode.ts +675 -39
- package/src/modes/print-mode.ts +16 -86
- package/src/modes/rpc/rpc-mode.ts +30 -88
- package/src/modes/runtime-init.ts +115 -0
- package/src/modes/theme/defaults/dark-poimandres.json +2 -0
- package/src/modes/theme/defaults/light-poimandres.json +2 -0
- package/src/modes/theme/theme.ts +18 -6
- package/src/modes/types.ts +20 -5
- package/src/modes/utils/context-usage.ts +13 -13
- package/src/modes/utils/ui-helpers.ts +25 -6
- package/src/plan-mode/approved-plan.ts +35 -1
- package/src/prompts/agents/designer.md +5 -5
- package/src/prompts/agents/explore.md +7 -7
- package/src/prompts/agents/init.md +9 -9
- package/src/prompts/agents/librarian.md +14 -14
- package/src/prompts/agents/plan.md +4 -4
- package/src/prompts/agents/reviewer.md +5 -5
- package/src/prompts/agents/task.md +10 -10
- package/src/prompts/commands/orchestrate.md +2 -2
- package/src/prompts/compaction/branch-summary.md +3 -3
- package/src/prompts/compaction/compaction-short-summary.md +7 -7
- package/src/prompts/compaction/compaction-summary-context.md +1 -1
- package/src/prompts/compaction/compaction-summary.md +5 -5
- package/src/prompts/compaction/compaction-turn-prefix.md +3 -3
- package/src/prompts/compaction/compaction-update-summary.md +11 -11
- package/src/prompts/goals/goal-budget-limit.md +16 -0
- package/src/prompts/goals/goal-continuation.md +28 -0
- package/src/prompts/goals/goal-mode-active.md +23 -0
- package/src/prompts/memories/consolidation.md +2 -2
- package/src/prompts/memories/read-path.md +1 -1
- package/src/prompts/memories/stage_one_input.md +1 -1
- package/src/prompts/memories/stage_one_system.md +5 -5
- package/src/prompts/review-request.md +4 -4
- package/src/prompts/system/agent-creation-architect.md +17 -17
- package/src/prompts/system/agent-creation-user.md +2 -2
- package/src/prompts/system/commit-message-system.md +2 -2
- package/src/prompts/system/custom-system-prompt.md +2 -2
- package/src/prompts/system/eager-todo.md +6 -6
- package/src/prompts/system/handoff-document.md +1 -1
- package/src/prompts/system/plan-mode-active.md +25 -24
- package/src/prompts/system/plan-mode-approved.md +4 -4
- package/src/prompts/system/plan-mode-compact-instructions.md +16 -0
- package/src/prompts/system/plan-mode-reference.md +2 -2
- package/src/prompts/system/plan-mode-subagent.md +8 -8
- package/src/prompts/system/plan-mode-tool-decision-reminder.md +3 -3
- package/src/prompts/system/project-prompt.md +4 -4
- package/src/prompts/system/subagent-system-prompt.md +7 -7
- package/src/prompts/system/subagent-yield-reminder.md +4 -4
- package/src/prompts/system/system-prompt.md +72 -71
- package/src/prompts/system/ttsr-interrupt.md +1 -1
- package/src/prompts/tools/apply-patch.md +1 -1
- package/src/prompts/tools/ast-edit.md +3 -3
- package/src/prompts/tools/ast-grep.md +3 -3
- package/src/prompts/tools/bash.md +6 -0
- package/src/prompts/tools/browser.md +3 -3
- package/src/prompts/tools/checkpoint.md +3 -3
- package/src/prompts/tools/find.md +3 -3
- package/src/prompts/tools/github.md +2 -5
- package/src/prompts/tools/goal.md +13 -0
- package/src/prompts/tools/hashline.md +104 -116
- package/src/prompts/tools/image-gen.md +3 -3
- package/src/prompts/tools/irc.md +1 -1
- package/src/prompts/tools/lsp.md +2 -2
- package/src/prompts/tools/patch.md +6 -6
- package/src/prompts/tools/read.md +8 -7
- package/src/prompts/tools/replace.md +5 -5
- package/src/prompts/tools/resolve.md +6 -5
- package/src/prompts/tools/retain.md +1 -1
- package/src/prompts/tools/rewind.md +2 -2
- package/src/prompts/tools/search.md +2 -2
- package/src/prompts/tools/ssh.md +2 -2
- package/src/prompts/tools/task.md +12 -6
- package/src/prompts/tools/web-search.md +2 -2
- package/src/prompts/tools/write.md +3 -3
- package/src/sdk.ts +81 -17
- package/src/session/agent-session.ts +656 -125
- package/src/session/blob-store.ts +36 -3
- package/src/session/client-bridge.ts +81 -0
- package/src/session/compaction/errors.ts +31 -0
- package/src/session/compaction/index.ts +1 -0
- package/src/session/messages.ts +67 -2
- package/src/session/session-manager.ts +131 -12
- package/src/session/session-storage.ts +33 -15
- package/src/session/streaming-output.ts +309 -13
- package/src/slash-commands/acp-builtins.ts +46 -0
- package/src/slash-commands/builtin-registry.ts +717 -116
- package/src/slash-commands/helpers/context-report.ts +39 -0
- package/src/slash-commands/helpers/format.ts +23 -0
- package/src/slash-commands/helpers/marketplace-manager.ts +25 -0
- package/src/slash-commands/helpers/mcp.ts +532 -0
- package/src/slash-commands/helpers/parse.ts +85 -0
- package/src/slash-commands/helpers/ssh.ts +193 -0
- package/src/slash-commands/helpers/todo.ts +279 -0
- package/src/slash-commands/helpers/usage-report.ts +91 -0
- package/src/slash-commands/types.ts +126 -0
- package/src/ssh/ssh-executor.ts +5 -0
- package/src/system-prompt.ts +4 -2
- package/src/task/executor.ts +27 -10
- package/src/task/index.ts +20 -1
- package/src/task/render.ts +27 -18
- package/src/task/types.ts +4 -0
- package/src/tools/ast-edit.ts +21 -120
- package/src/tools/ast-grep.ts +21 -119
- package/src/tools/bash-interactive.ts +9 -1
- package/src/tools/bash.ts +203 -6
- package/src/tools/browser/attach.ts +3 -3
- package/src/tools/browser/launch.ts +81 -18
- package/src/tools/browser/registry.ts +1 -5
- package/src/tools/browser/tab-supervisor.ts +51 -14
- package/src/tools/conflict-detect.ts +21 -10
- package/src/tools/eval.ts +3 -1
- package/src/tools/fetch.ts +15 -4
- package/src/tools/find.ts +39 -39
- package/src/tools/gh-renderer.ts +0 -12
- package/src/tools/gh.ts +689 -182
- package/src/tools/github-cache.ts +548 -0
- package/src/tools/index.ts +25 -11
- package/src/tools/inspect-image.ts +3 -10
- package/src/tools/output-meta.ts +176 -37
- package/src/tools/path-utils.ts +125 -2
- package/src/tools/read.ts +605 -239
- package/src/tools/render-utils.ts +92 -0
- package/src/tools/renderers.ts +2 -0
- package/src/tools/resolve.ts +72 -44
- package/src/tools/search.ts +120 -186
- package/src/tools/write.ts +67 -10
- package/src/tui/code-cell.ts +70 -2
- package/src/utils/file-mentions.ts +1 -1
- package/src/utils/image-loading.ts +7 -3
- package/src/utils/image-resize.ts +32 -43
- package/src/vim/parser.ts +0 -17
- package/src/vim/render.ts +1 -1
- package/src/vim/types.ts +1 -1
- package/src/web/search/providers/gemini.ts +35 -95
- package/src/prompts/tools/exit-plan-mode.md +0 -6
- package/src/tools/exit-plan-mode.ts +0 -97
- package/src/utils/fuzzy.ts +0 -108
- package/src/utils/image-convert.ts +0 -27
|
@@ -3,7 +3,7 @@ import * as os from "node:os";
|
|
|
3
3
|
import * as path from "node:path";
|
|
4
4
|
import { $which, getPuppeteerDir, logger } from "@oh-my-pi/pi-utils";
|
|
5
5
|
import * as browsers from "@puppeteer/browsers";
|
|
6
|
-
import type { Browser, CDPSession, Page, default as Puppeteer } from "puppeteer-core";
|
|
6
|
+
import type { Browser, CDPSession, Page, default as Puppeteer, Target } from "puppeteer-core";
|
|
7
7
|
import { PUPPETEER_REVISIONS } from "puppeteer-core/internal/revisions.js";
|
|
8
8
|
import stealthTamperingScript from "../puppeteer/00_stealth_tampering.txt" with { type: "text" };
|
|
9
9
|
import stealthActivityScript from "../puppeteer/01_stealth_activity.txt" with { type: "text" };
|
|
@@ -30,13 +30,15 @@ export const DEFAULT_VIEWPORT = { width: 1365, height: 768, deviceScaleFactor: 1
|
|
|
30
30
|
* connection dropped, etc.).
|
|
31
31
|
*/
|
|
32
32
|
export const BROWSER_PROTOCOL_TIMEOUT_MS = 60_000;
|
|
33
|
-
|
|
33
|
+
const STEALTH_IGNORE_DEFAULT_ARGS = [
|
|
34
34
|
"--disable-extensions",
|
|
35
35
|
"--disable-default-apps",
|
|
36
36
|
"--disable-component-extensions-with-background-pages",
|
|
37
37
|
];
|
|
38
|
-
|
|
38
|
+
const STEALTH_ACCEPT_LANGUAGE = "en-US,en";
|
|
39
39
|
|
|
40
|
+
const USER_AGENT_TARGET_TIMEOUT_MS = 5_000;
|
|
41
|
+
const USER_AGENT_TARGET_TYPES = new Set(["page", "webview", "background_page"]);
|
|
40
42
|
const PUPPETEER_SOURCE_URL_SUFFIX = "//# sourceURL=__puppeteer_evaluation_script__";
|
|
41
43
|
|
|
42
44
|
/**
|
|
@@ -82,7 +84,7 @@ export async function loadPuppeteerInWorker(safeDir: string): Promise<typeof Pup
|
|
|
82
84
|
* The browser is cached under ~/.omp/puppeteer (getPuppeteerDir).
|
|
83
85
|
*/
|
|
84
86
|
let chromiumExecutablePromise: Promise<string | undefined> | undefined;
|
|
85
|
-
|
|
87
|
+
async function ensureChromiumExecutable(): Promise<string | undefined> {
|
|
86
88
|
const sysChrome = resolveSystemChromium();
|
|
87
89
|
if (sysChrome) return sysChrome;
|
|
88
90
|
const envPath = process.env.PUPPETEER_EXECUTABLE_PATH;
|
|
@@ -138,7 +140,7 @@ export async function ensureChromiumExecutable(): Promise<string | undefined> {
|
|
|
138
140
|
return chromiumExecutablePromise;
|
|
139
141
|
}
|
|
140
142
|
|
|
141
|
-
let
|
|
143
|
+
let resolvedChromium: string | null | undefined; // undefined = unchecked; null = not found
|
|
142
144
|
|
|
143
145
|
function isExecutableFile(p: string): boolean {
|
|
144
146
|
try {
|
|
@@ -209,19 +211,19 @@ function systemChromiumCandidates(): string[] {
|
|
|
209
211
|
return candidates;
|
|
210
212
|
}
|
|
211
213
|
|
|
212
|
-
|
|
213
|
-
if (
|
|
214
|
+
function resolveSystemChromium(): string | undefined {
|
|
215
|
+
if (resolvedChromium !== undefined) return resolvedChromium ?? undefined;
|
|
214
216
|
const seen = new Set<string>();
|
|
215
217
|
for (const candidate of systemChromiumCandidates()) {
|
|
216
218
|
if (!candidate || seen.has(candidate)) continue;
|
|
217
219
|
seen.add(candidate);
|
|
218
220
|
if (isExecutableFile(candidate)) {
|
|
219
|
-
|
|
221
|
+
resolvedChromium = candidate;
|
|
220
222
|
logger.debug("Using system Chrome/Chromium", { path: candidate });
|
|
221
223
|
return candidate;
|
|
222
224
|
}
|
|
223
225
|
}
|
|
224
|
-
|
|
226
|
+
resolvedChromium = null;
|
|
225
227
|
return undefined;
|
|
226
228
|
}
|
|
227
229
|
|
|
@@ -463,6 +465,7 @@ export interface UserAgentSession {
|
|
|
463
465
|
async function configureUserAgentTargets(
|
|
464
466
|
browser: Browser,
|
|
465
467
|
state: { browserSession: CDPSession | null; override: UserAgentOverride },
|
|
468
|
+
targetTimeoutMs = USER_AGENT_TARGET_TIMEOUT_MS,
|
|
466
469
|
): Promise<void> {
|
|
467
470
|
if (!state.browserSession) {
|
|
468
471
|
state.browserSession = await browser.target().createCDPSession();
|
|
@@ -471,23 +474,72 @@ async function configureUserAgentTargets(
|
|
|
471
474
|
waitForDebuggerOnStart: false,
|
|
472
475
|
flatten: true,
|
|
473
476
|
});
|
|
474
|
-
state.browserSession.on(
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
477
|
+
state.browserSession.on(
|
|
478
|
+
"Target.attachedToTarget",
|
|
479
|
+
async (event: { sessionId: string; targetInfo?: { type?: string } }) => {
|
|
480
|
+
if (!targetInfoSupportsUserAgentOverride(event.targetInfo)) return;
|
|
481
|
+
const connection = state.browserSession?.connection();
|
|
482
|
+
const session = connection?.session(event.sessionId);
|
|
483
|
+
if (!session) return;
|
|
484
|
+
await withSoftTimeout(
|
|
485
|
+
sendUserAgentOverride(wrapSession(session), state.override),
|
|
486
|
+
targetTimeoutMs,
|
|
487
|
+
"new target user-agent override",
|
|
488
|
+
);
|
|
489
|
+
},
|
|
490
|
+
);
|
|
480
491
|
}
|
|
481
492
|
|
|
482
|
-
const targets = browser.targets();
|
|
493
|
+
const targets = browser.targets().filter(targetSupportsUserAgentOverride);
|
|
483
494
|
await Promise.all(
|
|
484
495
|
targets.map(async target => {
|
|
485
|
-
|
|
486
|
-
|
|
496
|
+
await withSoftTimeout(
|
|
497
|
+
applyTargetUserAgentOverride(target, state.override),
|
|
498
|
+
targetTimeoutMs,
|
|
499
|
+
"target user-agent override",
|
|
500
|
+
);
|
|
487
501
|
}),
|
|
488
502
|
);
|
|
489
503
|
}
|
|
490
504
|
|
|
505
|
+
function targetSupportsUserAgentOverride(target: Target): boolean {
|
|
506
|
+
return targetInfoSupportsUserAgentOverride({ type: target.type() });
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
function targetInfoSupportsUserAgentOverride(targetInfo: { type?: string } | undefined): boolean {
|
|
510
|
+
return Boolean(targetInfo?.type && USER_AGENT_TARGET_TYPES.has(targetInfo.type));
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
async function applyTargetUserAgentOverride(target: Target, override: UserAgentOverride): Promise<void> {
|
|
514
|
+
const session = await target.createCDPSession();
|
|
515
|
+
try {
|
|
516
|
+
await sendUserAgentOverride(wrapSession(session), override);
|
|
517
|
+
} finally {
|
|
518
|
+
await session.detach().catch(() => undefined);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
async function withSoftTimeout<T>(promise: Promise<T>, timeoutMs: number, label: string): Promise<T | undefined> {
|
|
523
|
+
let timeout: NodeJS.Timeout | undefined;
|
|
524
|
+
const timeoutPromise = new Promise<undefined>(resolve => {
|
|
525
|
+
timeout = setTimeout(() => {
|
|
526
|
+
logger.debug(`Timed out applying ${label}`);
|
|
527
|
+
resolve(undefined);
|
|
528
|
+
}, timeoutMs);
|
|
529
|
+
});
|
|
530
|
+
try {
|
|
531
|
+
return await Promise.race([
|
|
532
|
+
promise.catch(error => {
|
|
533
|
+
logger.debug(`Failed to apply ${label}`, { error: error instanceof Error ? error.message : String(error) });
|
|
534
|
+
return undefined;
|
|
535
|
+
}),
|
|
536
|
+
timeoutPromise,
|
|
537
|
+
]);
|
|
538
|
+
} finally {
|
|
539
|
+
if (timeout) clearTimeout(timeout);
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
|
|
491
543
|
async function injectStealthScripts(page: Page): Promise<void> {
|
|
492
544
|
const scripts = [
|
|
493
545
|
stealthTamperingScript,
|
|
@@ -574,3 +626,14 @@ export async function applyStealthPatches(
|
|
|
574
626
|
state.browserSession = targetState.browserSession;
|
|
575
627
|
await injectStealthScripts(page);
|
|
576
628
|
}
|
|
629
|
+
|
|
630
|
+
export function targetSupportsUserAgentOverrideForTest(target: Target): boolean {
|
|
631
|
+
return targetSupportsUserAgentOverride(target);
|
|
632
|
+
}
|
|
633
|
+
export async function configureUserAgentTargetsForTest(
|
|
634
|
+
browser: Browser,
|
|
635
|
+
state: { browserSession: CDPSession | null; override: UserAgentOverride },
|
|
636
|
+
targetTimeoutMs?: number,
|
|
637
|
+
): Promise<void> {
|
|
638
|
+
await configureUserAgentTargets(browser, state, targetTimeoutMs);
|
|
639
|
+
}
|
|
@@ -26,10 +26,6 @@ export interface BrowserHandle {
|
|
|
26
26
|
|
|
27
27
|
const browsers = new Map<string, BrowserHandle>();
|
|
28
28
|
|
|
29
|
-
export function listBrowsers(): BrowserHandle[] {
|
|
30
|
-
return [...browsers.values()];
|
|
31
|
-
}
|
|
32
|
-
|
|
33
29
|
function browserKey(kind: BrowserKind): string {
|
|
34
30
|
switch (kind.kind) {
|
|
35
31
|
case "headless":
|
|
@@ -166,7 +162,7 @@ export async function releaseBrowser(handle: BrowserHandle, opts: { kill: boolea
|
|
|
166
162
|
}
|
|
167
163
|
}
|
|
168
164
|
|
|
169
|
-
|
|
165
|
+
async function disposeBrowserHandle(handle: BrowserHandle, opts: { kill: boolean }): Promise<void> {
|
|
170
166
|
if (handle.kind.kind === "headless") {
|
|
171
167
|
if (handle.browser.connected) {
|
|
172
168
|
try {
|
|
@@ -30,6 +30,7 @@ import type {
|
|
|
30
30
|
interface WorkerHandle {
|
|
31
31
|
send(msg: WorkerInbound, transferList?: Transferable[]): void;
|
|
32
32
|
onMessage(handler: (msg: WorkerOutbound) => void): () => void;
|
|
33
|
+
onError(handler: (error: Error) => void): () => void;
|
|
33
34
|
terminate(): Promise<void>;
|
|
34
35
|
readonly mode: "worker" | "inline";
|
|
35
36
|
}
|
|
@@ -89,10 +90,6 @@ export function getTab(name: string): TabSession | undefined {
|
|
|
89
90
|
return tabs.get(name);
|
|
90
91
|
}
|
|
91
92
|
|
|
92
|
-
export function listTabs(): TabSession[] {
|
|
93
|
-
return [...tabs.values()];
|
|
94
|
-
}
|
|
95
|
-
|
|
96
93
|
export async function acquireTab(
|
|
97
94
|
name: string,
|
|
98
95
|
browser: BrowserHandle,
|
|
@@ -124,23 +121,14 @@ export async function acquireTab(
|
|
|
124
121
|
|
|
125
122
|
const initPayload = await buildInitPayload(browser, opts);
|
|
126
123
|
const worker = await spawnTabWorker();
|
|
127
|
-
const { promise, resolve, reject } = Promise.withResolvers<ReadyInfo>();
|
|
128
|
-
const unlisten = worker.onMessage(msg => {
|
|
129
|
-
if (msg.type === "ready") resolve(msg.info);
|
|
130
|
-
else if (msg.type === "init-failed") reject(errorFromPayload(msg.error));
|
|
131
|
-
else if (msg.type === "log") logWorkerMessage(msg);
|
|
132
|
-
});
|
|
133
124
|
let info: ReadyInfo;
|
|
134
125
|
try {
|
|
135
|
-
|
|
136
|
-
info = await raceWithTimeout(promise, opts.timeoutMs + GRACE_MS, "Timed out initializing browser tab worker");
|
|
126
|
+
info = await initializeTabWorker(worker, initPayload, opts.timeoutMs + GRACE_MS);
|
|
137
127
|
} catch (error) {
|
|
138
|
-
unlisten();
|
|
139
128
|
await worker.terminate().catch(() => undefined);
|
|
140
129
|
if (browser.refCount === 0) await releaseBrowser(browser, { kill: false });
|
|
141
130
|
throw error;
|
|
142
131
|
}
|
|
143
|
-
unlisten();
|
|
144
132
|
|
|
145
133
|
holdBrowser(browser);
|
|
146
134
|
const tab: TabSession = {
|
|
@@ -477,6 +465,17 @@ function wrapBunWorker(worker: Worker): WorkerHandle {
|
|
|
477
465
|
worker.addEventListener("message", wrap);
|
|
478
466
|
return () => worker.removeEventListener("message", wrap);
|
|
479
467
|
},
|
|
468
|
+
onError(handler) {
|
|
469
|
+
const onError = (event: ErrorEvent): void => handler(errorFromWorkerEvent(event));
|
|
470
|
+
const onMessageError = (event: MessageEvent): void =>
|
|
471
|
+
handler(new ToolError(`Tab worker message error: ${String(event.data)}`));
|
|
472
|
+
worker.addEventListener("error", onError);
|
|
473
|
+
worker.addEventListener("messageerror", onMessageError);
|
|
474
|
+
return () => {
|
|
475
|
+
worker.removeEventListener("error", onError);
|
|
476
|
+
worker.removeEventListener("messageerror", onMessageError);
|
|
477
|
+
};
|
|
478
|
+
},
|
|
480
479
|
async terminate() {
|
|
481
480
|
worker.terminate();
|
|
482
481
|
},
|
|
@@ -515,6 +514,44 @@ async function spawnInlineWorker(): Promise<WorkerHandle> {
|
|
|
515
514
|
hostListeners.add(handler);
|
|
516
515
|
return () => hostListeners.delete(handler);
|
|
517
516
|
},
|
|
517
|
+
onError: () => () => {},
|
|
518
518
|
async terminate() {},
|
|
519
519
|
};
|
|
520
520
|
}
|
|
521
|
+
|
|
522
|
+
async function initializeTabWorker(
|
|
523
|
+
worker: WorkerHandle,
|
|
524
|
+
payload: WorkerInitPayload,
|
|
525
|
+
timeoutMs: number,
|
|
526
|
+
): Promise<ReadyInfo> {
|
|
527
|
+
const { promise, resolve, reject } = Promise.withResolvers<ReadyInfo>();
|
|
528
|
+
const unlisten = worker.onMessage(msg => {
|
|
529
|
+
if (msg.type === "ready") resolve(msg.info);
|
|
530
|
+
else if (msg.type === "init-failed") reject(errorFromPayload(msg.error));
|
|
531
|
+
else if (msg.type === "log") logWorkerMessage(msg);
|
|
532
|
+
});
|
|
533
|
+
const unlistenError = worker.onError(error => {
|
|
534
|
+
reject(new ToolError(`Tab worker failed during startup: ${error.message}`));
|
|
535
|
+
});
|
|
536
|
+
try {
|
|
537
|
+
worker.send({ type: "init", payload });
|
|
538
|
+
return await raceWithTimeout(promise, timeoutMs, "Timed out initializing browser tab worker");
|
|
539
|
+
} finally {
|
|
540
|
+
unlisten();
|
|
541
|
+
unlistenError();
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
export function initializeTabWorkerForTest(
|
|
546
|
+
worker: WorkerHandle,
|
|
547
|
+
payload: WorkerInitPayload,
|
|
548
|
+
timeoutMs: number,
|
|
549
|
+
): Promise<ReadyInfo> {
|
|
550
|
+
return initializeTabWorker(worker, payload, timeoutMs);
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
function errorFromWorkerEvent(event: ErrorEvent): Error {
|
|
554
|
+
if (event.error instanceof Error) return event.error;
|
|
555
|
+
if (event.message) return new Error(event.message);
|
|
556
|
+
return new Error("Unknown tab worker error");
|
|
557
|
+
}
|
|
@@ -240,7 +240,7 @@ export function getConflictHistory(session: ToolSession): ConflictHistory {
|
|
|
240
240
|
return session.conflictHistory;
|
|
241
241
|
}
|
|
242
242
|
|
|
243
|
-
/** A side of a conflict block that `read conflict://N/<scope
|
|
243
|
+
/** A side of a conflict block that the `read` tool can render via `conflict://N/<scope>`. */
|
|
244
244
|
export type ConflictScope = "ours" | "theirs" | "base";
|
|
245
245
|
|
|
246
246
|
const CONFLICT_SCOPES = new Set<ConflictScope>(["ours", "theirs", "base"]);
|
|
@@ -250,9 +250,19 @@ export interface ParsedConflictUri {
|
|
|
250
250
|
/** `"*"` selects every currently-registered conflict (bulk write only). */
|
|
251
251
|
id: number | "*";
|
|
252
252
|
scope?: ConflictScope;
|
|
253
|
+
/**
|
|
254
|
+
* When `raw` was a malformed `<file-prefix>:conflict://…` path, the
|
|
255
|
+
* stripped prefix is preserved here so callers can surface a gentle
|
|
256
|
+
* "you don't need the file path" note. `undefined` for clean URIs.
|
|
257
|
+
*/
|
|
258
|
+
recoveredPrefix?: string;
|
|
253
259
|
}
|
|
254
260
|
|
|
255
|
-
|
|
261
|
+
// Accept an optional `<prefix>:` before the scheme so paths like
|
|
262
|
+
// `path/to/file.ts:conflict://3` (where the agent mixed the `:conflicts`
|
|
263
|
+
// read selector with the `conflict://` scheme) still resolve. The prefix
|
|
264
|
+
// is greedy so the LAST `:conflict://` wins for multi-colon inputs.
|
|
265
|
+
const CONFLICT_URI_RE = /^(?:(.+):)?conflict:\/\/(.+)$/;
|
|
256
266
|
|
|
257
267
|
/**
|
|
258
268
|
* Parse a `conflict://<N>`, `conflict://<N>/<scope>`, or `conflict://*` URI.
|
|
@@ -269,7 +279,8 @@ const CONFLICT_URI_RE = /^conflict:\/\/(.+)$/;
|
|
|
269
279
|
export function parseConflictUri(raw: string): ParsedConflictUri | null {
|
|
270
280
|
const match = raw.match(CONFLICT_URI_RE);
|
|
271
281
|
if (!match) return null;
|
|
272
|
-
const
|
|
282
|
+
const recoveredPrefix = match[1];
|
|
283
|
+
const tail = match[2];
|
|
273
284
|
const slashIdx = tail.indexOf("/");
|
|
274
285
|
const idPart = slashIdx === -1 ? tail : tail.slice(0, slashIdx);
|
|
275
286
|
const scopePart = slashIdx === -1 ? undefined : tail.slice(slashIdx + 1);
|
|
@@ -280,7 +291,7 @@ export function parseConflictUri(raw: string): ParsedConflictUri | null {
|
|
|
280
291
|
`Invalid conflict URI '${raw}': wildcard 'conflict://*' does not accept a scope segment. Drop '/${scopePart}' or use a numeric id.`,
|
|
281
292
|
);
|
|
282
293
|
}
|
|
283
|
-
return { id: "*" };
|
|
294
|
+
return recoveredPrefix !== undefined ? { id: "*", recoveredPrefix } : { id: "*" };
|
|
284
295
|
}
|
|
285
296
|
|
|
286
297
|
if (!/^\d+$/.test(idPart)) {
|
|
@@ -303,7 +314,7 @@ export function parseConflictUri(raw: string): ParsedConflictUri | null {
|
|
|
303
314
|
scope = scopePart as ConflictScope;
|
|
304
315
|
}
|
|
305
316
|
|
|
306
|
-
return { id, scope };
|
|
317
|
+
return recoveredPrefix !== undefined ? { id, scope, recoveredPrefix } : { id, scope };
|
|
307
318
|
}
|
|
308
319
|
|
|
309
320
|
/**
|
|
@@ -440,7 +451,7 @@ function markerLine(prefix: string, label: string | undefined): string {
|
|
|
440
451
|
}
|
|
441
452
|
|
|
442
453
|
/**
|
|
443
|
-
* Materialise a conflict block for `
|
|
454
|
+
* Materialise a conflict block for `conflict://<N>` reads (and their
|
|
444
455
|
* `/ours` / `/theirs` / `/base` scopes).
|
|
445
456
|
*
|
|
446
457
|
* Returns:
|
|
@@ -534,7 +545,7 @@ export function formatConflictWarning(
|
|
|
534
545
|
if (partial) {
|
|
535
546
|
const hintPath = options.displayPath ?? "<file>";
|
|
536
547
|
out.push(
|
|
537
|
-
`⚠ ${entries.length} of ${total} unresolved ${word} visible in this window (
|
|
548
|
+
`⚠ ${entries.length} of ${total} unresolved ${word} visible in this window (read \`${hintPath}:conflicts\` for the full list).`,
|
|
538
549
|
);
|
|
539
550
|
} else {
|
|
540
551
|
out.push(`⚠ ${total} unresolved ${word} detected`);
|
|
@@ -551,7 +562,7 @@ export function formatConflictWarning(
|
|
|
551
562
|
if (theirsLabel) out.push(`- theirs = ${theirsLabel}`);
|
|
552
563
|
if (anyBase) out.push(`- base = ${baseLabel ?? "(no label)"}`);
|
|
553
564
|
out.push(
|
|
554
|
-
'NOTICE: Inspect a block
|
|
565
|
+
'NOTICE: Inspect a block by reading `conflict://<N>` (add `/ours` / `/theirs` / `/base` to render a single side). Resolve with `write({ path: "conflict://<N>", content })`, or bulk-resolve every registered conflict with `write({ path: "conflict://*", content })`. Writes replace the whole conflict region (markers + all sides).',
|
|
555
566
|
);
|
|
556
567
|
out.push(
|
|
557
568
|
'`content` shorthand: a line that is exactly `@ours` / `@theirs` / `@base` / `@both` expands to that recorded section. `@both` is ours-then-theirs with no separator. Lines that are not a token pass through verbatim, so `"// keep both\\n@ours\\n@theirs"` literally writes the comment, then ours, then theirs.',
|
|
@@ -592,7 +603,7 @@ export function formatConflictWarning(
|
|
|
592
603
|
|
|
593
604
|
/**
|
|
594
605
|
* Render a single-line-per-block index of every conflict in a file.
|
|
595
|
-
* Used by
|
|
606
|
+
* Used by the `<path>:conflicts` read selector to give the agent a cheap overview
|
|
596
607
|
* of a heavily-conflicted file without dumping every body.
|
|
597
608
|
*/
|
|
598
609
|
export function formatConflictSummary(
|
|
@@ -614,7 +625,7 @@ export function formatConflictSummary(
|
|
|
614
625
|
if (theirsLabel) lines.push(`- theirs = ${theirsLabel}`);
|
|
615
626
|
if (anyBase) lines.push(`- base = ${baseLabel ?? "(no label)"}`);
|
|
616
627
|
lines.push(
|
|
617
|
-
'NOTICE: Bulk-resolve with `write({ path: "conflict://*", content })`, or address a single block with `write({ path: "conflict://<N>", content })`. Inspect a block
|
|
628
|
+
'NOTICE: Bulk-resolve with `write({ path: "conflict://*", content })`, or address a single block with `write({ path: "conflict://<N>", content })`. Inspect a block by reading `conflict://<N>` (add `/ours` / `/theirs` / `/base` for a single side).',
|
|
618
629
|
);
|
|
619
630
|
lines.push(
|
|
620
631
|
"`content` shorthand: `@ours` / `@theirs` / `@base` / `@both` lines expand to the recorded sections; `@both` = ours-then-theirs. Non-token lines pass through verbatim.",
|
package/src/tools/eval.ts
CHANGED
|
@@ -16,7 +16,7 @@ import evalDescription from "../prompts/tools/eval.md" with { type: "text" };
|
|
|
16
16
|
import { DEFAULT_MAX_BYTES, OutputSink, type OutputSummary, TailBuffer } from "../session/streaming-output";
|
|
17
17
|
import { getTreeBranch, getTreeContinuePrefix, renderCodeCell } from "../tui";
|
|
18
18
|
import { resolveEvalBackends, type ToolSession } from ".";
|
|
19
|
-
import { formatStyledTruncationWarning } from "./output-meta";
|
|
19
|
+
import { formatStyledTruncationWarning, resolveOutputMaxColumns, resolveOutputSinkHeadBytes } from "./output-meta";
|
|
20
20
|
import { formatTitle, replaceTabs, shortenPath, truncateToWidth, wrapBrackets } from "./render-utils";
|
|
21
21
|
import { ToolAbortError, ToolError } from "./tool-errors";
|
|
22
22
|
import { toolResult } from "./tool-result";
|
|
@@ -358,6 +358,8 @@ export class EvalTool implements AgentTool<typeof evalSchema> {
|
|
|
358
358
|
outputSink = new OutputSink({
|
|
359
359
|
artifactPath,
|
|
360
360
|
artifactId,
|
|
361
|
+
headBytes: resolveOutputSinkHeadBytes(session.settings),
|
|
362
|
+
maxColumns: resolveOutputMaxColumns(session.settings),
|
|
361
363
|
onChunk: chunk => {
|
|
362
364
|
appendTail(chunk);
|
|
363
365
|
pushUpdate();
|
package/src/tools/fetch.ts
CHANGED
|
@@ -22,7 +22,7 @@ import { finalizeOutput, loadPage, looksLikeHtml, MAX_OUTPUT_CHARS } from "../we
|
|
|
22
22
|
import { convertWithMarkit, fetchBinary } from "../web/scrapers/utils";
|
|
23
23
|
import { applyListLimit } from "./list-limit";
|
|
24
24
|
import { formatStyledArtifactReference, type OutputMeta } from "./output-meta";
|
|
25
|
-
import { formatExpandHint, getDomain } from "./render-utils";
|
|
25
|
+
import { formatExpandHint, getDomain, replaceTabs } from "./render-utils";
|
|
26
26
|
import { ToolAbortError, ToolError } from "./tool-errors";
|
|
27
27
|
import { toolResult } from "./tool-result";
|
|
28
28
|
import { clampTimeout } from "./tool-timeouts";
|
|
@@ -1362,14 +1362,25 @@ export function renderReadUrlCall(
|
|
|
1362
1362
|
|
|
1363
1363
|
/** Render URL read result with tree-based layout */
|
|
1364
1364
|
export function renderReadUrlResult(
|
|
1365
|
-
result: { content: Array<{ type: string; text?: string }>; details?: ReadUrlToolDetails },
|
|
1365
|
+
result: { content: Array<{ type: string; text?: string }>; details?: ReadUrlToolDetails; isError?: boolean },
|
|
1366
1366
|
options: RenderResultOptions,
|
|
1367
1367
|
uiTheme: Theme = theme,
|
|
1368
1368
|
): Component {
|
|
1369
1369
|
const details = result.details;
|
|
1370
1370
|
|
|
1371
|
-
if (!details) {
|
|
1372
|
-
|
|
1371
|
+
if (result.isError || !details) {
|
|
1372
|
+
const rawErrorText = result.content?.find(c => c.type === "text")?.text ?? "";
|
|
1373
|
+
const errorText = (rawErrorText || "No response data").replace(/^Error:\s*/, "");
|
|
1374
|
+
const urlText = details?.finalUrl ?? details?.url ?? "";
|
|
1375
|
+
const description = urlText ? `${getDomain(urlText)}${urlText.replace(/^https?:\/\/[^/]+/, "")}` : undefined;
|
|
1376
|
+
const header = renderStatusLine({ icon: "error", title: "Read", description }, uiTheme);
|
|
1377
|
+
const errorLines = errorText.split("\n").map(line => uiTheme.fg("error", replaceTabs(line)));
|
|
1378
|
+
const outputBlock = new CachedOutputBlock();
|
|
1379
|
+
return {
|
|
1380
|
+
render: (width: number) =>
|
|
1381
|
+
outputBlock.render({ header, state: "error", sections: [{ lines: errorLines }], width }, uiTheme),
|
|
1382
|
+
invalidate: () => outputBlock.invalidate(),
|
|
1383
|
+
};
|
|
1373
1384
|
}
|
|
1374
1385
|
|
|
1375
1386
|
const domain = getDomain(details.finalUrl);
|
package/src/tools/find.ts
CHANGED
|
@@ -8,30 +8,30 @@ import { isEnoent, prompt, untilAborted } from "@oh-my-pi/pi-utils";
|
|
|
8
8
|
import type { Static } from "@sinclair/typebox";
|
|
9
9
|
import { Type } from "@sinclair/typebox";
|
|
10
10
|
import type { RenderResultOptions } from "../extensibility/custom-tools/types";
|
|
11
|
+
import { InternalUrlRouter } from "../internal-urls";
|
|
11
12
|
import type { Theme } from "../modes/theme/theme";
|
|
12
13
|
import findDescription from "../prompts/tools/find.md" with { type: "text" };
|
|
13
14
|
import { type TruncationResult, truncateHead } from "../session/streaming-output";
|
|
14
|
-
import {
|
|
15
|
-
Ellipsis,
|
|
16
|
-
Hasher,
|
|
17
|
-
type RenderCache,
|
|
18
|
-
renderFileList,
|
|
19
|
-
renderStatusLine,
|
|
20
|
-
renderTreeList,
|
|
21
|
-
truncateToWidth,
|
|
22
|
-
} from "../tui";
|
|
15
|
+
import { Ellipsis, renderFileList, renderStatusLine, renderTreeList, truncateToWidth } from "../tui";
|
|
23
16
|
import type { ToolSession } from ".";
|
|
24
17
|
import { applyListLimit } from "./list-limit";
|
|
25
18
|
import { formatFullOutputReference, type OutputMeta } from "./output-meta";
|
|
26
19
|
import {
|
|
27
20
|
formatPathRelativeToCwd,
|
|
21
|
+
hasGlobPathChars,
|
|
28
22
|
normalizePathLikeInput,
|
|
29
23
|
parseFindPattern,
|
|
30
24
|
partitionExistingPaths,
|
|
31
25
|
resolveExplicitFindPatterns,
|
|
32
26
|
resolveToCwd,
|
|
33
27
|
} from "./path-utils";
|
|
34
|
-
import {
|
|
28
|
+
import {
|
|
29
|
+
createCachedComponent,
|
|
30
|
+
formatCount,
|
|
31
|
+
formatEmptyMessage,
|
|
32
|
+
formatErrorMessage,
|
|
33
|
+
PREVIEW_LIMITS,
|
|
34
|
+
} from "./render-utils";
|
|
35
35
|
import { ToolAbortError, ToolError, throwIfAborted } from "./tool-errors";
|
|
36
36
|
import { toolResult } from "./tool-result";
|
|
37
37
|
|
|
@@ -116,7 +116,23 @@ export class FindTool implements AgentTool<typeof findSchema, FindToolDetails> {
|
|
|
116
116
|
|
|
117
117
|
return untilAborted(signal, async () => {
|
|
118
118
|
const formatScopePath = (targetPath: string): string => formatPathRelativeToCwd(targetPath, this.session.cwd);
|
|
119
|
-
const
|
|
119
|
+
const rawPatterns = paths.map(input => normalizePathLikeInput(input).replace(/\\/g, "/"));
|
|
120
|
+
const internalRouter = InternalUrlRouter.instance();
|
|
121
|
+
const normalizedPatterns: string[] = [];
|
|
122
|
+
for (const rawPattern of rawPatterns) {
|
|
123
|
+
if (!internalRouter.canHandle(rawPattern)) {
|
|
124
|
+
normalizedPatterns.push(rawPattern);
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
if (hasGlobPathChars(rawPattern)) {
|
|
128
|
+
throw new ToolError(`Glob patterns are not supported for internal URLs: ${rawPattern}`);
|
|
129
|
+
}
|
|
130
|
+
const resource = await internalRouter.resolve(rawPattern);
|
|
131
|
+
if (!resource.sourcePath) {
|
|
132
|
+
throw new ToolError(`Cannot find internal URL without a backing file: ${rawPattern}`);
|
|
133
|
+
}
|
|
134
|
+
normalizedPatterns.push(resource.sourcePath);
|
|
135
|
+
}
|
|
120
136
|
if (normalizedPatterns.some(pattern => pattern.length === 0)) {
|
|
121
137
|
throw new ToolError("`paths` must contain non-empty globs or paths");
|
|
122
138
|
}
|
|
@@ -383,30 +399,22 @@ export const findToolRenderer = {
|
|
|
383
399
|
},
|
|
384
400
|
uiTheme,
|
|
385
401
|
);
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
const { expanded } = options;
|
|
390
|
-
const key = new Hasher().bool(expanded).u32(width).digest();
|
|
391
|
-
if (cached?.key === key) return cached.lines;
|
|
402
|
+
return createCachedComponent(
|
|
403
|
+
() => options.expanded,
|
|
404
|
+
width => {
|
|
392
405
|
const listLines = renderTreeList(
|
|
393
406
|
{
|
|
394
407
|
items: lines,
|
|
395
|
-
expanded,
|
|
408
|
+
expanded: options.expanded,
|
|
396
409
|
maxCollapsed: COLLAPSED_LIST_LIMIT,
|
|
397
410
|
itemType: "file",
|
|
398
411
|
renderItem: line => uiTheme.fg("accent", line),
|
|
399
412
|
},
|
|
400
413
|
uiTheme,
|
|
401
414
|
);
|
|
402
|
-
|
|
403
|
-
cached = { key, lines: result };
|
|
404
|
-
return result;
|
|
405
|
-
},
|
|
406
|
-
invalidate() {
|
|
407
|
-
cached = undefined;
|
|
415
|
+
return [header, ...listLines].map(l => truncateToWidth(l, width, Ellipsis.Omit));
|
|
408
416
|
},
|
|
409
|
-
|
|
417
|
+
);
|
|
410
418
|
}
|
|
411
419
|
|
|
412
420
|
const fileCount = details?.fileCount ?? 0;
|
|
@@ -449,28 +457,20 @@ export const findToolRenderer = {
|
|
|
449
457
|
}
|
|
450
458
|
if (missingNote) extraLines.push(missingNote);
|
|
451
459
|
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
const { expanded } = options;
|
|
456
|
-
const key = new Hasher().bool(expanded).u32(width).digest();
|
|
457
|
-
if (cached?.key === key) return cached.lines;
|
|
460
|
+
return createCachedComponent(
|
|
461
|
+
() => options.expanded,
|
|
462
|
+
width => {
|
|
458
463
|
const fileLines = renderFileList(
|
|
459
464
|
{
|
|
460
465
|
files: files.map(entry => ({ path: entry, isDirectory: entry.endsWith("/") })),
|
|
461
|
-
expanded,
|
|
466
|
+
expanded: options.expanded,
|
|
462
467
|
maxCollapsed: COLLAPSED_LIST_LIMIT,
|
|
463
468
|
},
|
|
464
469
|
uiTheme,
|
|
465
470
|
);
|
|
466
|
-
|
|
467
|
-
cached = { key, lines: result };
|
|
468
|
-
return result;
|
|
469
|
-
},
|
|
470
|
-
invalidate() {
|
|
471
|
-
cached = undefined;
|
|
471
|
+
return [header, ...fileLines, ...extraLines].map(l => truncateToWidth(l, width, Ellipsis.Omit));
|
|
472
472
|
},
|
|
473
|
-
|
|
473
|
+
);
|
|
474
474
|
},
|
|
475
475
|
mergeCallAndResult: true,
|
|
476
476
|
};
|
package/src/tools/gh-renderer.ts
CHANGED
|
@@ -27,7 +27,6 @@ type GithubToolRenderArgs = {
|
|
|
27
27
|
run?: string;
|
|
28
28
|
branch?: string;
|
|
29
29
|
repo?: string;
|
|
30
|
-
issue?: string;
|
|
31
30
|
pr?: string | string[];
|
|
32
31
|
query?: string;
|
|
33
32
|
};
|
|
@@ -40,9 +39,6 @@ const FALLBACK_WIDTH = 80;
|
|
|
40
39
|
|
|
41
40
|
const OP_TITLES: Record<string, string> = {
|
|
42
41
|
repo_view: "GitHub Repo",
|
|
43
|
-
issue_view: "GitHub Issue",
|
|
44
|
-
pr_view: "GitHub PR",
|
|
45
|
-
pr_diff: "GitHub PR Diff",
|
|
46
42
|
pr_checkout: "GitHub PR Checkout",
|
|
47
43
|
pr_push: "GitHub PR Push",
|
|
48
44
|
search_issues: "GitHub Search Issues",
|
|
@@ -85,14 +81,6 @@ function buildOpMeta(args: GithubToolRenderArgs): string[] {
|
|
|
85
81
|
const meta: string[] = [];
|
|
86
82
|
const op = args.op;
|
|
87
83
|
switch (op) {
|
|
88
|
-
case "issue_view": {
|
|
89
|
-
const id = extractIssueId(args.issue);
|
|
90
|
-
if (id) meta.push(id);
|
|
91
|
-
if (args.repo) meta.push(args.repo);
|
|
92
|
-
break;
|
|
93
|
-
}
|
|
94
|
-
case "pr_view":
|
|
95
|
-
case "pr_diff":
|
|
96
84
|
case "pr_checkout":
|
|
97
85
|
case "pr_push": {
|
|
98
86
|
const id = formatPrIdentifier(args.pr);
|