/** * Calvana Ship Log Extension * * Automatically tracks what you're shipping and updates the live Calvana site. * * Tools (LLM-callable): * - calvana_ship: Add/update/complete shipping log entries * - calvana_oops: Log mistakes and fixes * - calvana_deploy: Push changes to the live site * * Commands (user): * /ships — View current shipping log * /ship-deploy — Force deploy to calvana.quikcue.com * * How it works: * 1. When you work on tasks, the LLM uses calvana_ship to track progress * 2. If something breaks, calvana_oops logs it * 3. calvana_deploy rebuilds the /live page HTML and pushes it to the server * 4. The extension auto-injects context so the LLM knows to track ships * * Edit the SSH/deploy config in the DEPLOY_CONFIG section below. */ import { StringEnum } from "@mariozechner/pi-ai"; import type { ExtensionAPI, ExtensionContext, Theme } from "@mariozechner/pi-coding-agent"; import { Text, truncateToWidth, matchesKey } from "@mariozechner/pi-tui"; import { Type } from "@sinclair/typebox"; // ════════════════════════════════════════════════════════════════════ // CONFIGURATION — Edit these to change deploy target, copy, links // ════════════════════════════════════════════════════════════════════ const DEPLOY_CONFIG = { sshHost: "root@159.195.60.33", sshPort: "22", container: "qc-server-new", sitePath: "/opt/calvana/html", domain: "calvana.quikcue.com", }; const SITE_CONFIG = { title: "Calvana", tagline: "I break rules. Not production.", email: "omair@quikcue.com", referralLine: "PS — Umar pointed me here. If this turns into a hire, I want him to get paid.", }; // ════════════════════════════════════════════════════════════════════ // TYPES // ════════════════════════════════════════════════════════════════════ type ShipStatus = "planned" | "shipping" | "shipped"; interface ShipEntry { id: number; title: string; status: ShipStatus; timestamp: string; metric: string; prLink: string; deployLink: string; loomLink: string; } interface OopsEntry { id: number; description: string; fixTime: string; commitLink: string; timestamp: string; } interface ShipLogState { ships: ShipEntry[]; oops: OopsEntry[]; nextShipId: number; nextOopsId: number; lastDeployed: string | null; } // ════════════════════════════════════════════════════════════════════ // TOOL SCHEMAS // ════════════════════════════════════════════════════════════════════ const ShipParams = Type.Object({ action: StringEnum(["add", "update", "list"] as const), title: Type.Optional(Type.String({ description: "Ship title (for add)" })), id: Type.Optional(Type.Number({ description: "Ship ID (for update)" })), status: Type.Optional(StringEnum(["planned", "shipping", "shipped"] as const)), metric: Type.Optional(Type.String({ description: "What moved — metric line" })), prLink: Type.Optional(Type.String({ description: "PR link" })), deployLink: Type.Optional(Type.String({ description: "Deploy link" })), loomLink: Type.Optional(Type.String({ description: "Loom clip link" })), }); const OopsParams = Type.Object({ action: StringEnum(["add", "list"] as const), description: Type.Optional(Type.String({ description: "What broke and how it was fixed" })), fixTime: Type.Optional(Type.String({ description: "Time to fix, e.g. '3 min'" })), commitLink: Type.Optional(Type.String({ description: "Link to the fix commit" })), }); const DeployParams = Type.Object({ dryRun: Type.Optional(Type.Boolean({ description: "If true, generate HTML but don't deploy" })), }); // ════════════════════════════════════════════════════════════════════ // EXTENSION // ════════════════════════════════════════════════════════════════════ export default function (pi: ExtensionAPI) { // ── State ── let state: ShipLogState = { ships: [], oops: [], nextShipId: 1, nextOopsId: 1, lastDeployed: null, }; // ── State reconstruction from session ── const reconstructState = (ctx: ExtensionContext) => { state = { ships: [], oops: [], nextShipId: 1, nextOopsId: 1, lastDeployed: null }; for (const entry of ctx.sessionManager.getBranch()) { if (entry.type !== "message") continue; const msg = entry.message; if (msg.role !== "toolResult") continue; if (msg.toolName === "calvana_ship" || msg.toolName === "calvana_oops" || msg.toolName === "calvana_deploy") { const details = msg.details as { state?: ShipLogState } | undefined; if (details?.state) { state = details.state; } } } }; pi.on("session_start", async (_event, ctx) => { reconstructState(ctx); if (ctx.hasUI) { const theme = ctx.ui.theme; const shipCount = state.ships.length; const shipped = state.ships.filter(s => s.status === "shipped").length; ctx.ui.setStatus("calvana", theme.fg("dim", `🚀 ${shipped}/${shipCount} shipped`)); } }); pi.on("session_switch", async (_event, ctx) => reconstructState(ctx)); pi.on("session_fork", async (_event, ctx) => reconstructState(ctx)); pi.on("session_tree", async (_event, ctx) => reconstructState(ctx)); // ── Inject context so LLM knows about ship tracking ── pi.on("before_agent_start", async (event, _ctx) => { const shipContext = ` [Calvana Ship Log Extension Active] You have access to these tools for tracking work: - calvana_ship: Track shipping progress (add/update/list entries) - calvana_oops: Log mistakes and fixes - calvana_deploy: Push updates to the live site at https://${DEPLOY_CONFIG.domain}/live When you START working on a task, use calvana_ship to add or update it to "shipping". When you COMPLETE a task, update it to "shipped" with a metric. If something BREAKS, log it with calvana_oops. After significant changes, use calvana_deploy to push updates live. Current ships: ${state.ships.length} (${state.ships.filter(s => s.status === "shipped").length} shipped) Current oops: ${state.oops.length} `; return { systemPrompt: event.systemPrompt + shipContext, }; }); // ── Update status bar on turn end ── pi.on("turn_end", async (_event, ctx) => { if (ctx.hasUI) { const theme = ctx.ui.theme; const shipped = state.ships.filter(s => s.status === "shipped").length; const shipping = state.ships.filter(s => s.status === "shipping").length; const total = state.ships.length; let statusText = `🚀 ${shipped}/${total} shipped`; if (shipping > 0) statusText += ` · ${shipping} in flight`; if (state.lastDeployed) statusText += ` · last deploy ${state.lastDeployed}`; ctx.ui.setStatus("calvana", theme.fg("dim", statusText)); } }); // ════════════════════════════════════════════════════════════════ // TOOL: calvana_ship // ════════════════════════════════════════════════════════════════ pi.registerTool({ name: "calvana_ship", label: "Ship Log", description: "Track shipping progress. Actions: add (new entry), update (change status/links), list (show all). Use this whenever you start, progress, or finish a task.", parameters: ShipParams, async execute(_toolCallId, params, _signal, _onUpdate, _ctx) { const now = new Date().toISOString().replace("T", " ").slice(0, 19) + " GMT+8"; switch (params.action) { case "add": { if (!params.title) { return { content: [{ type: "text", text: "Error: title required" }], details: { state: { ...state }, error: "title required" }, }; } const entry: ShipEntry = { id: state.nextShipId++, title: params.title, status: (params.status as ShipStatus) || "planned", timestamp: now, metric: params.metric || "—", prLink: params.prLink || "#pr", deployLink: params.deployLink || "#deploy", loomLink: params.loomLink || "#loomclip", }; state.ships.push(entry); return { content: [{ type: "text", text: `Ship #${entry.id} added: "${entry.title}" [${entry.status}]` }], details: { state: { ...state, ships: [...state.ships] } }, }; } case "update": { if (params.id === undefined) { return { content: [{ type: "text", text: "Error: id required for update" }], details: { state: { ...state }, error: "id required" }, }; } const ship = state.ships.find(s => s.id === params.id); if (!ship) { return { content: [{ type: "text", text: `Ship #${params.id} not found` }], details: { state: { ...state }, error: `#${params.id} not found` }, }; } if (params.status) ship.status = params.status as ShipStatus; if (params.metric) ship.metric = params.metric; if (params.prLink) ship.prLink = params.prLink; if (params.deployLink) ship.deployLink = params.deployLink; if (params.loomLink) ship.loomLink = params.loomLink; ship.timestamp = now; return { content: [{ type: "text", text: `Ship #${ship.id} updated: "${ship.title}" [${ship.status}]` }], details: { state: { ...state, ships: [...state.ships] } }, }; } case "list": { if (state.ships.length === 0) { return { content: [{ type: "text", text: "No ships logged yet." }], details: { state: { ...state } }, }; } const lines = state.ships.map(s => `#${s.id} [${s.status.toUpperCase()}] ${s.title} (${s.timestamp}) — ${s.metric}` ); return { content: [{ type: "text", text: lines.join("\n") }], details: { state: { ...state } }, }; } default: return { content: [{ type: "text", text: `Unknown action: ${params.action}` }], details: { state: { ...state } }, }; } }, renderCall(args, theme) { let text = theme.fg("toolTitle", theme.bold("🚀 ship ")); text += theme.fg("muted", args.action || ""); if (args.title) text += " " + theme.fg("dim", `"${args.title}"`); if (args.id !== undefined) text += " " + theme.fg("accent", `#${args.id}`); if (args.status) text += " → " + theme.fg("accent", args.status); return new Text(text, 0, 0); }, renderResult(result, { expanded }, theme) { const details = result.details as { state?: ShipLogState; error?: string } | undefined; if (details?.error) return new Text(theme.fg("error", `Error: ${details.error}`), 0, 0); const st = details?.state; if (!st || st.ships.length === 0) return new Text(theme.fg("dim", "No ships"), 0, 0); const shipped = st.ships.filter(s => s.status === "shipped").length; const total = st.ships.length; let text = theme.fg("success", `${shipped}/${total} shipped`); if (expanded) { for (const s of st.ships) { const badge = s.status === "shipped" ? theme.fg("success", "✓") : s.status === "shipping" ? theme.fg("warning", "●") : theme.fg("dim", "○"); text += `\n ${badge} ${theme.fg("accent", `#${s.id}`)} ${theme.fg("muted", s.title)}`; } } return new Text(text, 0, 0); }, }); // ════════════════════════════════════════════════════════════════ // TOOL: calvana_oops // ════════════════════════════════════════════════════════════════ pi.registerTool({ name: "calvana_oops", label: "Oops Log", description: "Log mistakes and fixes. Actions: add (new oops entry), list (show all). Use when something breaks during a task.", parameters: OopsParams, async execute(_toolCallId, params, _signal, _onUpdate, _ctx) { const now = new Date().toISOString().replace("T", " ").slice(0, 19) + " GMT+8"; switch (params.action) { case "add": { if (!params.description) { return { content: [{ type: "text", text: "Error: description required" }], details: { state: { ...state }, error: "description required" }, }; } const entry: OopsEntry = { id: state.nextOopsId++, description: params.description, fixTime: params.fixTime || "—", commitLink: params.commitLink || "#commit", timestamp: now, }; state.oops.push(entry); return { content: [{ type: "text", text: `Oops #${entry.id}: "${entry.description}" (fixed in ${entry.fixTime})` }], details: { state: { ...state, oops: [...state.oops] } }, }; } case "list": { if (state.oops.length === 0) { return { content: [{ type: "text", text: "No oops entries. Clean run so far." }], details: { state: { ...state } }, }; } const lines = state.oops.map(o => `#${o.id} ${o.description} — fixed in ${o.fixTime}` ); return { content: [{ type: "text", text: lines.join("\n") }], details: { state: { ...state } }, }; } default: return { content: [{ type: "text", text: `Unknown action: ${params.action}` }], details: { state: { ...state } }, }; } }, renderCall(args, theme) { let text = theme.fg("toolTitle", theme.bold("💥 oops ")); text += theme.fg("muted", args.action || ""); if (args.description) text += " " + theme.fg("dim", `"${args.description}"`); return new Text(text, 0, 0); }, renderResult(result, _options, theme) { const details = result.details as { state?: ShipLogState; error?: string } | undefined; if (details?.error) return new Text(theme.fg("error", `Error: ${details.error}`), 0, 0); const text = result.content[0]; return new Text(theme.fg("warning", text?.type === "text" ? text.text : ""), 0, 0); }, }); // ════════════════════════════════════════════════════════════════ // TOOL: calvana_deploy // ════════════════════════════════════════════════════════════════ pi.registerTool({ name: "calvana_deploy", label: "Deploy Calvana", description: `Regenerate the /live page with current ship log and deploy to https://${DEPLOY_CONFIG.domain}. Call this after adding/updating ships or oops entries to push changes live.`, parameters: DeployParams, async execute(_toolCallId, params, signal, onUpdate, _ctx) { onUpdate?.({ content: [{ type: "text", text: "Generating HTML..." }] }); const liveHtml = generateLivePageHtml(state); if (params.dryRun) { return { content: [{ type: "text", text: `Dry run — generated ${liveHtml.length} bytes of HTML.\n\n${liveHtml.slice(0, 500)}...` }], details: { state: { ...state }, dryRun: true }, }; } onUpdate?.({ content: [{ type: "text", text: "Deploying to server..." }] }); try { // Write HTML to server via SSH + incus exec const escapedHtml = liveHtml.replace(/'/g, "'\\''"); const sshCmd = `ssh -o ConnectTimeout=10 -p ${DEPLOY_CONFIG.sshPort} ${DEPLOY_CONFIG.sshHost}`; const writeCmd = `${sshCmd} "incus exec ${DEPLOY_CONFIG.container} -- bash -c 'cat > ${DEPLOY_CONFIG.sitePath}/live/index.html << '\\''HTMLEOF'\\'' ${liveHtml} HTMLEOF '"`; // Use base64 to avoid all escaping nightmares const b64Html = Buffer.from(liveHtml).toString("base64"); const deployResult = await pi.exec("bash", ["-c", `ssh -o ConnectTimeout=10 -p ${DEPLOY_CONFIG.sshPort} ${DEPLOY_CONFIG.sshHost} "incus exec ${DEPLOY_CONFIG.container} -- bash -c 'echo ${b64Html} | base64 -d > ${DEPLOY_CONFIG.sitePath}/live/index.html'"` ], { signal, timeout: 30000 }); if (deployResult.code !== 0) { return { content: [{ type: "text", text: `Deploy failed: ${deployResult.stderr}` }], details: { state: { ...state }, error: deployResult.stderr }, isError: true, }; } // Rebuild and update docker service const rebuildResult = await pi.exec("bash", ["-c", `ssh -o ConnectTimeout=10 -p ${DEPLOY_CONFIG.sshPort} ${DEPLOY_CONFIG.sshHost} "incus exec ${DEPLOY_CONFIG.container} -- bash -c 'cd /opt/calvana && docker build -t calvana:latest . 2>&1 | tail -2 && docker service update --force calvana 2>&1 | tail -2'"` ], { signal, timeout: 60000 }); const now = new Date().toISOString().replace("T", " ").slice(0, 19); state.lastDeployed = now; return { content: [{ type: "text", text: `✓ Deployed to https://${DEPLOY_CONFIG.domain}/live\n${rebuildResult.stdout}` }], details: { state: { ...state, lastDeployed: now } }, }; } catch (err: any) { return { content: [{ type: "text", text: `Deploy error: ${err.message}` }], details: { state: { ...state }, error: err.message }, isError: true, }; } }, renderCall(_args, theme) { return new Text(theme.fg("toolTitle", theme.bold("🌐 deploy calvana")), 0, 0); }, renderResult(result, _options, theme) { const details = result.details as { error?: string } | undefined; if (details?.error) return new Text(theme.fg("error", `✗ ${details.error}`), 0, 0); return new Text(theme.fg("success", `✓ Live at https://${DEPLOY_CONFIG.domain}/live`), 0, 0); }, }); // ════════════════════════════════════════════════════════════════ // COMMAND: /ships // ════════════════════════════════════════════════════════════════ pi.registerCommand("ships", { description: "View current Calvana shipping log", handler: async (_args, ctx) => { if (!ctx.hasUI) { ctx.ui.notify("Requires interactive mode", "error"); return; } await ctx.ui.custom((_tui, theme, _kb, done) => { return new ShipLogComponent(state, theme, () => done()); }); }, }); // ════════════════════════════════════════════════════════════════ // COMMAND: /ship-deploy // ════════════════════════════════════════════════════════════════ pi.registerCommand("ship-deploy", { description: "Force deploy the Calvana site with current ship log", handler: async (_args, ctx) => { const ok = await ctx.ui.confirm("Deploy?", `Push ship log to https://${DEPLOY_CONFIG.domain}/live?`); if (!ok) return; // Queue a deploy via the LLM pi.sendUserMessage("Use calvana_deploy to push the current ship log to the live site.", { deliverAs: "followUp" }); }, }); } // ════════════════════════════════════════════════════════════════════ // UI COMPONENT: /ships viewer // ════════════════════════════════════════════════════════════════════ class ShipLogComponent { private state: ShipLogState; private theme: Theme; private onClose: () => void; private cachedWidth?: number; private cachedLines?: string[]; constructor(state: ShipLogState, theme: Theme, onClose: () => void) { this.state = state; this.theme = theme; this.onClose = onClose; } handleInput(data: string): void { if (matchesKey(data, "escape") || matchesKey(data, "ctrl+c")) { this.onClose(); } } render(width: number): string[] { if (this.cachedLines && this.cachedWidth === width) return this.cachedLines; const lines: string[] = []; const th = this.theme; lines.push(""); lines.push(truncateToWidth( th.fg("borderMuted", "─".repeat(3)) + th.fg("accent", " 🚀 Calvana Ship Log ") + th.fg("borderMuted", "─".repeat(Math.max(0, width - 26))), width )); lines.push(""); // Ships if (this.state.ships.length === 0) { lines.push(truncateToWidth(` ${th.fg("dim", "No ships yet.")}`, width)); } else { const shipped = this.state.ships.filter(s => s.status === "shipped").length; lines.push(truncateToWidth( ` ${th.fg("muted", `${shipped}/${this.state.ships.length} shipped`)}`, width )); lines.push(""); for (const s of this.state.ships) { const badge = s.status === "shipped" ? th.fg("success", "✓ SHIPPED ") : s.status === "shipping" ? th.fg("warning", "● SHIPPING") : th.fg("dim", "○ PLANNED "); lines.push(truncateToWidth( ` ${badge} ${th.fg("accent", `#${s.id}`)} ${th.fg("text", s.title)}`, width )); lines.push(truncateToWidth( ` ${th.fg("dim", s.timestamp)} · ${th.fg("dim", s.metric)}`, width )); } } // Oops if (this.state.oops.length > 0) { lines.push(""); lines.push(truncateToWidth(` ${th.fg("warning", "💥 Oops Log")}`, width)); for (const o of this.state.oops) { lines.push(truncateToWidth( ` ${th.fg("error", "─")} ${th.fg("muted", o.description)} ${th.fg("dim", `(${o.fixTime})`)}`, width )); } } lines.push(""); if (this.state.lastDeployed) { lines.push(truncateToWidth(` ${th.fg("dim", `Last deployed: ${this.state.lastDeployed}`)}`, width)); } lines.push(truncateToWidth(` ${th.fg("dim", "Press Escape to close")}`, width)); lines.push(""); this.cachedWidth = width; this.cachedLines = lines; return lines; } invalidate(): void { this.cachedWidth = undefined; this.cachedLines = undefined; } } // ════════════════════════════════════════════════════════════════════ // HTML GENERATOR — Builds the /live page from current state // ════════════════════════════════════════════════════════════════════ function generateLivePageHtml(state: ShipLogState): string { const now = new Date().toISOString(); const shipCards = state.ships.map(s => { const badgeClass = s.status === "shipped" ? "badge-shipped" : s.status === "shipping" ? "badge-shipping" : "badge-planned"; const badgeLabel = s.status.charAt(0).toUpperCase() + s.status.slice(1); const titleSuffix = s.status === "shipped" ? " ✓" : ""; return `
${escapeHtml(s.title)}${titleSuffix} ${badgeLabel}

⏱ ${escapeHtml(s.timestamp)}

What moved: ${escapeHtml(s.metric)}

`; }).join("\n"); const oopsEntries = state.oops.map(o => { return `
${escapeHtml(o.description)}${o.fixTime !== "—" ? ` Fixed in ${escapeHtml(o.fixTime)}.` : ""} → commit
`; }).join("\n"); // If no ships yet, show placeholder const shipsSection = state.ships.length > 0 ? shipCards : `
Warming up... Planned

⏱ —

What moved: —

`; const oopsSection = state.oops.length > 0 ? oopsEntries : `
Nothing broken yet. Give it time. → waiting
`; return ` Calvana — Live Shipping Log

Live Shipping Log

Intentional chaos. Full receipts.

Today's Ships

${shipsSection}

Rules I broke today

  • Didn't ask permission
  • Didn't wait for alignment
  • Didn't write a PRD
  • Didn't submit a normal application

Rules I refuse to break

  • No silent failures
  • No unbounded AI spend
  • No hallucinations shipped to users
  • No deploy without rollback path

Oops Log

If it's not here, I haven't broken it yet.

${oopsSection}
`; } function escapeHtml(str: string): string { return str .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """) .replace(/'/g, "'"); }