/** * Sender-cwd anchoring (P1-D): one HTML comment on the first line of every * agent-originated handoff doc, naming the sender's working directory so the * receiving agent edits inside the sender's project instead of its own cwd. * * * * Written by both send tools (tmp doc for `xfer_to`, inline doc for * `xfer_mesh_to`) and read back by `controller.deliverInbound` to build the * envelope instruction. Formatting is pure; the only I/O is two bounded file * reads (`.git/HEAD`, the head of the doc) — never a subprocess. * * `project` + `machine` are always present: they are the cross-machine anchor * when `cwd` does not exist on the receiver (worktrees of one repo at different * paths). Web-picker docs get no stamp — a browser, not a working directory. */ import * as fs from "node:fs"; import * as path from "node:path"; /** Working-directory anchor carried by a handoff doc. */ export interface SenderCwdStamp { /** Absolute sender working directory. */ cwd: string; /** Basename of `cwd` — the human-facing project label. */ project: string; /** Hostname of the sending machine. */ machine: string; /** Current git branch, when `/.git/HEAD` names one. */ branch?: string; } /** First-line stamp grammar. `cwd` is non-greedy so paths may contain spaces. */ const STAMP_LINE = /^$/; /** Enough head bytes to cover any stamp line; the doc body is never read. */ const HEAD_CHUNK_BYTES = 4096; /** Render the stamp as a single-line HTML comment (no trailing newline). */ export function formatSenderCwdStamp(stamp: SenderCwdStamp): string { const branch = stamp.branch ? ` branch=${stamp.branch}` : ""; return ``; } /** Parse the stamp off a doc's first line; null when the doc carries none. */ export function parseSenderCwdStamp(document: string): SenderCwdStamp | null { const firstLine = document.split("\n", 1)[0]?.trim() ?? ""; const match = STAMP_LINE.exec(firstLine); if (!match) return null; const [, cwd, project, machine, branch] = match; return { cwd: cwd!, project: project!, machine: machine!, ...(branch ? { branch } : {}) }; } /** Read the stamp of a doc on disk; null when unreadable, unstamped, or short. */ export function readSenderCwdStamp(file: string): SenderCwdStamp | null { const chunk = Buffer.alloc(HEAD_CHUNK_BYTES); let fd: number | undefined; try { fd = fs.openSync(file, "r"); const read = fs.readSync(fd, chunk, 0, chunk.length, 0); return parseSenderCwdStamp(chunk.subarray(0, read).toString("utf-8")); } catch { return null; } finally { if (fd !== undefined) { try { fs.closeSync(fd); } catch { /* best effort */ } } } } /** * Prepend the stamp line to a doc. A doc already carrying one is re-stamped in * place, so re-sending a quoted handoff never stacks anchor comments. */ export function stampDocument(document: string, stamp: SenderCwdStamp): string { const line = formatSenderCwdStamp(stamp); return parseSenderCwdStamp(document) ? document.replace(/^[^\n]*/, line) : `${line}\n${document}`; } /** * Branch name from `/.git/HEAD` by plain file read. Handles `.git` as a * directory (plain checkout) and as a `gitdir:` pointer file (worktrees, * submodules); null for non-git trees, detached HEAD, and any read failure. */ export function readGitBranch(cwd: string): string | null { try { const git = path.join(cwd, ".git"); let headPath = path.join(git, "HEAD"); if (!fs.statSync(git).isDirectory()) { const pointer = /^gitdir:\s*(.+)$/m.exec(fs.readFileSync(git, "utf-8")); if (!pointer) return null; headPath = path.join(pointer[1]!.trim(), "HEAD"); } const ref = /^ref:\s*refs\/heads\/(.+)$/.exec(fs.readFileSync(headPath, "utf-8").trim()); return ref?.[1]!.trim() || null; } catch { return null; } } /** Build the stamp for a sending process: cwd + project label + host + branch. */ export function senderCwdStampFor(cwd: string, machine: string): SenderCwdStamp { const branch = readGitBranch(cwd); return { cwd, project: path.basename(cwd) || cwd, machine, ...(branch ? { branch } : {}), }; } /** * Envelope line telling the receiver where to edit. Non-local senders (mesh, or * a host we cannot match) also get the fallback: the path may not exist here. */ export function senderCwdInstruction(stamp: SenderCwdStamp, options: { local: boolean }): string { const anchor = `**Sender cwd**: \`${stamp.cwd}\` (project ${stamp.project} on machine ${stamp.machine}) — ` + `make all file edits here unless the doc says otherwise.`; if (options.local) return anchor; return ( anchor + ` If that path does not exist on this machine, locate the project` + ` (and worktree/branch if given) before editing — ask the user only if ambiguous.` ); }