app/cli/commands/ladder-edit.ts
zzmq.dev@gmail.com/zz / app / cli / commands / ladder-edit.ts
@ 3fddbaf9
Download
Ladder Summary
- file This module implements the **`zz ladder edit`** CLI command: it builds a single “ladder rung” (a structured note) for a specified repository path, gathers the commit metadata to use as the rung’s source (defaulting to the current HEAD), authenticates as the chosen identity, sends the rung to the remote `ladder_write_rung` tool, and ensures the identity is released on completion or interruption. **Exports** - `ladderEdit(slug: string, path: string, opts: LadderEditOptions): Promise<void>` – the command handler that creates and writes the rung. - `LadderEditOptions` – the option shape (`kind`, `summary`, optional `commit`, optional `as`).
// `zz ladder edit <owner/repo> <path>`: writes one Ladder rung by hand
// -- the human-contributor counterpart to a model's own
// `ladder_write_rung` call in agent/scriptedWork.ts. Anchors to a real
// commit (defaulting to the current directory's HEAD), same cwd-git
// convention cli/commands/repo-submit.ts already uses, since
// repo/file/changeset/release kinds all require a real commit source
// to anchor their note to (agent/tools.ts's validateAnchorSources).
// One rung per call, not a batch -- the demo narrates writing the
// repo rung, then each file rung, as separate, visible steps.
import { execFileSync } from "node:child_process";
import { resolveIdentity, releaseIdentity } from "../lib/identity.js";
import { setActiveToken } from "../lib/api.js";
import { callRemoteTool } from "../lib/remoteTools.js";
import type { RungKind, RungSource } from "../../engine/ladder.js";
export interface LadderEditOptions {
kind: string;
summary: string;
/** Defaults to the current directory's HEAD. */
commit?: string;
/** --as <name>: write as a managed agent instead of yourself. */
as?: string;
}
function commitSource(sha?: string): RungSource {
const ref = sha ?? execFileSync("git", ["rev-parse", "HEAD"], { encoding: "utf8" }).trim();
const [title, author, at] = execFileSync("git", ["log", "-1", "--format=%s%x1f%an%x1f%aI", ref], { encoding: "utf8" }).trim().split("\x1f");
return { kind: "commit", ref, title, author, at };
}
export async function ladderEdit(slug: string, path: string, opts: LadderEditOptions): Promise<void> {
const identity = await resolveIdentity(opts.as);
setActiveToken(identity.token);
let cleanedUp = false;
const cleanup = async (): Promise<void> => {
if (cleanedUp) return;
cleanedUp = true;
await releaseIdentity(identity);
};
process.on("SIGINT", () => void cleanup().then(() => process.exit(0)));
process.on("SIGTERM", () => void cleanup().then(() => process.exit(0)));
try {
const rung = {
path,
kind: opts.kind as RungKind,
summary: opts.summary,
sources: [commitSource(opts.commit)],
children: [],
};
await callRemoteTool(slug, "ladder_write_rung", { rung });
console.log(`Wrote the "${path}" (${opts.kind}) rung on ${slug}.`);
} finally {
await cleanup();
}
}