Ship Paseo-equivalent provider snapshot, AgentComposerBar, ACP dispatch rewrite with streaming/persist, permission prompts, and agent commands. Follow-up: pane-scoped chat resolution, CoderMessageList tool timeline, WS user-delta replace, and inference orphan tool_call stripping. Archive openspec v2-2; update CHANGELOG and CURRENT. Co-authored-by: Cursor <cursoragent@cursor.com>
36 lines
1.3 KiB
TypeScript
36 lines
1.3 KiB
TypeScript
import { promises as fs } from 'node:fs';
|
|
import { dirname, isAbsolute, join, resolve } from 'node:path';
|
|
|
|
/** Resolve an ACP path against the agent worktree and read a slice of lines. */
|
|
export async function readWorktreeTextFile(
|
|
worktreePath: string,
|
|
filePath: string,
|
|
line?: number | null,
|
|
limit?: number | null,
|
|
): Promise<string> {
|
|
const absolute = isAbsolute(filePath) ? filePath : resolve(worktreePath, filePath);
|
|
if (!absolute.startsWith(resolve(worktreePath))) {
|
|
throw new Error(`path escapes worktree: ${filePath}`);
|
|
}
|
|
const raw = await fs.readFile(absolute, 'utf8');
|
|
if (!line && !limit) return raw;
|
|
const lines = raw.split(/\r?\n/);
|
|
const start = Math.max((line ?? 1) - 1, 0);
|
|
const end = limit ? start + limit : undefined;
|
|
return lines.slice(start, end).join('\n');
|
|
}
|
|
|
|
/** Write a file inside the worktree (creates parent dirs). */
|
|
export async function writeWorktreeTextFile(
|
|
worktreePath: string,
|
|
filePath: string,
|
|
content: string,
|
|
): Promise<void> {
|
|
const absolute = isAbsolute(filePath) ? filePath : resolve(worktreePath, filePath);
|
|
if (!absolute.startsWith(resolve(worktreePath))) {
|
|
throw new Error(`path escapes worktree: ${filePath}`);
|
|
}
|
|
await fs.mkdir(dirname(absolute), { recursive: true });
|
|
await fs.writeFile(absolute, content, 'utf8');
|
|
}
|