Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 9 additions & 2 deletions packages/pi-kit/extensions/compact-tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@ function firstLine(text: string): string {
return idx === -1 ? text : text.slice(0, idx);
}

/** Logical line count: a single trailing newline does not add a line. */
function countLines(text: string): number {
if (text.length === 0) return 0;
const body = text.endsWith("\n") ? text.slice(0, -1) : text;
return body.split("\n").length;
}

function clip(text: string, width: number): string {
return truncateToWidth(text, width, "…");
}
Expand Down Expand Up @@ -102,7 +109,7 @@ export default function compactTools(pi: ExtensionAPI) {
if (content?.type !== "text") return new Text(theme.fg("error", "✖ no content"), 0, 0);

const details = result.details as ReadToolDetails | undefined;
const lineCount = content.text.split("\n").length;
const lineCount = countLines(content.text);
let text = theme.fg("success", "✔ ") + theme.fg("muted", `${lineCount} lines`);
if (details?.truncation?.truncated) {
text += theme.fg("warning", ` of ${details.truncation.totalLines}`);
Expand Down Expand Up @@ -173,7 +180,7 @@ export default function compactTools(pi: ExtensionAPI) {
pi.registerTool({
...write,
renderCall(args, theme) {
const lineCount = args.content.split("\n").length;
const lineCount = countLines(args.content);
return new Text(
`${theme.fg("accent", "▸")} ${theme.fg("toolTitle", "write")} ${theme.fg("text", shortPath(args.path))} ${theme.fg("dim", `(${lineCount} lines)`)}`,
0,
Expand Down
22 changes: 19 additions & 3 deletions packages/pi-kit/extensions/lanes.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
import { Type } from "typebox";
import { appendEvent, newRunId } from "../src/journal-core.ts";
import { appendEvent, newRunId, rawRunDir } from "../src/journal-core.ts";
import { LanesTuiComponent } from "../src/lanes-tui.ts";
import { LaneRunner } from "../src/runner.ts";
import type { LaneProjection, LaneSpec, RunProjection } from "../src/schema.ts";
import { MODEL_TABLE, validateLaneSpec } from "../src/table.ts";
Expand Down Expand Up @@ -217,6 +218,7 @@ export default function lanesExtension(pi: ExtensionAPI): void {
const activeRunner = new LaneRunner({
runId,
append: appendEvent,
rawDir: rawRunDir(runId),
onUpdate() {
if (view && lastRun === view) renderWidget(ctx, view);
},
Expand Down Expand Up @@ -427,9 +429,23 @@ export default function lanesExtension(pi: ExtensionAPI): void {
});

pi.registerCommand("lanes", {
description: "Show, hide, summarize, or abandon lanes",
description: "Show, hide, summarize, abandon lanes, or open the full-screen TUI",
handler: async (args, ctx) => {
const [command = "show", lane] = (args.trim() || "show").split(/\s+/, 2);
if (command === "tui") {
if (!ctx.hasUI) {
ctx.ui.notify("lanes tui requires interactive mode", "warning");
return;
}
await ctx.ui.custom<void>(
(tui, theme, _keybindings, done) => new LanesTuiComponent(tui, theme, () => done(undefined), lastRun?.id),
{
overlay: true,
overlayOptions: { width: "100%", maxHeight: "100%", anchor: "top-left", row: 0, col: 0 },
},
);
return;
}
if (command === "hide") {
if (lastRun) lastRun.hidden = true;
ctx.ui.setWidget("pi-lanes", undefined);
Expand Down Expand Up @@ -467,7 +483,7 @@ export default function lanesExtension(pi: ExtensionAPI): void {
renderWidget(ctx, lastRun);
return;
}
ctx.ui.notify("Usage: /lanes [show|hide|last|abandon <lane|all>]", "warning");
ctx.ui.notify("Usage: /lanes [show|hide|last|tui|abandon <lane|all>]", "warning");
},
});
}
17 changes: 16 additions & 1 deletion packages/pi-kit/src/journal-core.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { appendFileSync, mkdirSync, readFileSync } from "node:fs";
import { appendFileSync, mkdirSync, readdirSync, readFileSync } from "node:fs";
import { homedir } from "node:os";
import { join } from "node:path";
import { randomBytes } from "node:crypto";
Expand All @@ -19,6 +19,21 @@ export function journalDir(): string {
return runsDir;
}

/** Directory holding raw per-lane JSONL transcripts for a run. */
export function rawRunDir(runId: string): string {
const dataDir = process.env[DATA_DIR_ENV] ?? join(homedir(), ".pickforge", "pi-kit");
return join(dataDir, "raw", runId);
}

/** All journaled run ids, newest first. */
export function listRuns(): string[] {
return readdirSync(journalDir())
.filter((name) => name.endsWith(".jsonl"))
.map((name) => name.slice(0, -".jsonl".length))
.sort()
.reverse();
}

export function appendEvent(ev: KitEvent): void {
const event = {
...ev,
Expand Down
Loading