From 0ae003909644fed77503214f80b0206de8ffa1c8 Mon Sep 17 00:00:00 2001 From: Daniel Kumlin Date: Sat, 25 Jul 2026 20:45:24 +0200 Subject: [PATCH] Refactor Pi Herdr orchestration --- .../skills-personal/update-config/SKILL.md | 10 +- config/claude/hooks/herdr-agent-state.sh | 51 +- config/claude/settings.json | 52 +- config/codex/herdr-agent-state.sh | 45 +- config/codex/hooks.json | 38 +- config/opencode/plugins/herdr-agent-state.js | 167 +- .../pi/agent/extensions/herdr-agent-state.ts | 186 +- .../agent/extensions/pi-herdr-agent-state.ts | 285 -- config/pi/agent/extensions/pi-herdr/README.md | 14 + config/pi/agent/extensions/pi-herdr/client.ts | 104 + .../pi-herdr/generate-protocol-types.mjs | 72 + .../pi-herdr/generated/error-response.ts | 16 + .../extensions/pi-herdr/generated/request.ts | 1301 ++++++ .../pi-herdr/generated/success-response.ts | 1001 +++++ .../{pi-herdr.ts => pi-herdr/index.ts} | 596 ++- .../extensions/pi-herdr/package-lock.json | 3531 +++++++++++++++++ .../pi/agent/extensions/pi-herdr/package.json | 32 + .../agent/extensions/pi-herdr/tsconfig.json | 19 + flake.lock | 6 +- 19 files changed, 6585 insertions(+), 941 deletions(-) delete mode 100644 config/pi/agent/extensions/pi-herdr-agent-state.ts create mode 100644 config/pi/agent/extensions/pi-herdr/README.md create mode 100644 config/pi/agent/extensions/pi-herdr/client.ts create mode 100644 config/pi/agent/extensions/pi-herdr/generate-protocol-types.mjs create mode 100644 config/pi/agent/extensions/pi-herdr/generated/error-response.ts create mode 100644 config/pi/agent/extensions/pi-herdr/generated/request.ts create mode 100644 config/pi/agent/extensions/pi-herdr/generated/success-response.ts rename config/pi/agent/extensions/{pi-herdr.ts => pi-herdr/index.ts} (72%) create mode 100644 config/pi/agent/extensions/pi-herdr/package-lock.json create mode 100644 config/pi/agent/extensions/pi-herdr/package.json create mode 100644 config/pi/agent/extensions/pi-herdr/tsconfig.json diff --git a/config/agents/skills-personal/update-config/SKILL.md b/config/agents/skills-personal/update-config/SKILL.md index c387e7b..a79c11b 100644 --- a/config/agents/skills-personal/update-config/SKILL.md +++ b/config/agents/skills-personal/update-config/SKILL.md @@ -31,15 +31,15 @@ Cobb host/profile repo, when editing Cobb integration: ## Always use `traitor` for this repo -Daniel's config operations CLI is `traitor`. Prefer it over raw `nix`, `nixos-rebuild`, `darwin-rebuild`, and `home-manager` commands. +Daniel's config operations CLI is `traitor`. Prefer it over raw `nix`, `nixos-rebuild`, `darwin-rebuild`, and `home-manager` commands. Invoke `traitor` directly when it is available on `PATH`; use `./bin/traitor` only as a fallback when PATH is not loaded yet. -Use the repo-local binary if PATH is not loaded yet: +Preferred: ```bash cd ~/.config/dotfiles -./bin/traitor path -./bin/traitor check -./bin/traitor re +traitor path +traitor check +traitor re ``` Common commands: diff --git a/config/claude/hooks/herdr-agent-state.sh b/config/claude/hooks/herdr-agent-state.sh index e2a970d..cb5e840 100755 --- a/config/claude/hooks/herdr-agent-state.sh +++ b/config/claude/hooks/herdr-agent-state.sh @@ -3,7 +3,7 @@ # managed by herdr; reinstalling or updating the integration overwrites this file. # add custom hooks beside this file instead of editing it. # HERDR_INTEGRATION_ID=claude -# HERDR_INTEGRATION_VERSION=4 +# HERDR_INTEGRATION_VERSION=7 set -eu @@ -13,7 +13,7 @@ trap 'rm -f "$hook_input_file"' EXIT HUP INT TERM cat >"$hook_input_file" 2>/dev/null || true case "$action" in - working|idle|blocked|release) ;; + session) ;; *) exit 0 ;; esac @@ -50,44 +50,41 @@ if hook_input_file: hook_event_name = str(hook_input.get("hook_event_name") or "") is_subagent = bool(hook_input.get("agent_id")) +if is_subagent: + raise SystemExit(0) if hook_event_name == "SubagentStop": # SubagentStop is a completion event. Older Herdr integrations mapped it # to durable working, but Claude recap/away-summary can emit it after the # main turn has already stopped. Never let it revive an idle pane. raise SystemExit(0) -if is_subagent and action in ("idle", "release"): - # Subagent completion must not make the parent pane look done early. - raise SystemExit(0) - request_id = f"{source}:{int(time.time() * 1000)}:{random.randrange(1_000_000):06d}" report_seq = time.time_ns() session_id = hook_input.get("session_id") agent_session_id = session_id if isinstance(session_id, str) and session_id else None -if action == "release": - request = { - "id": request_id, - "method": "pane.release_agent", - "params": { - "pane_id": pane_id, - "source": source, - "agent": "claude", - "seq": report_seq, - }, +transcript_path = hook_input.get("transcript_path") +agent_session_path = transcript_path if isinstance(transcript_path, str) and transcript_path else None +session_start_source = hook_input.get("source") if hook_event_name == "SessionStart" else None +if not isinstance(session_start_source, str) or not session_start_source: + session_start_source = None +if agent_session_id: + params = { + "pane_id": pane_id, + "source": source, + "agent": "claude", + "seq": report_seq, + "agent_session_id": agent_session_id, } -else: + if agent_session_path: + params["agent_session_path"] = agent_session_path + if session_start_source: + params["session_start_source"] = session_start_source request = { "id": request_id, - "method": "pane.report_agent", - "params": { - "pane_id": pane_id, - "source": source, - "agent": "claude", - "state": action, - "seq": report_seq, - }, + "method": "pane.report_agent_session", + "params": params, } - if agent_session_id: - request["params"]["agent_session_id"] = agent_session_id +else: + raise SystemExit(0) try: client = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) diff --git a/config/claude/settings.json b/config/claude/settings.json index c1642c8..affa35e 100644 --- a/config/claude/settings.json +++ b/config/claude/settings.json @@ -27,16 +27,6 @@ } ], "matcher": "*" - }, - { - "hooks": [ - { - "command": "bash '/Users/danielkumlin/.claude/hooks/herdr-agent-state.sh' blocked", - "timeout": 10, - "type": "command" - } - ], - "matcher": "*" } ], "PostToolUse": [ @@ -71,16 +61,6 @@ } ], "matcher": "*" - }, - { - "hooks": [ - { - "command": "bash '/Users/danielkumlin/.claude/hooks/herdr-agent-state.sh' working", - "timeout": 10, - "type": "command" - } - ], - "matcher": "*" } ], "SessionEnd": [ @@ -101,16 +81,6 @@ } ], "matcher": "*" - }, - { - "hooks": [ - { - "command": "bash '/Users/danielkumlin/.claude/hooks/herdr-agent-state.sh' release", - "timeout": 10, - "type": "command" - } - ], - "matcher": "*" } ], "SessionStart": [ @@ -125,7 +95,7 @@ { "hooks": [ { - "command": "bash '/Users/danielkumlin/.claude/hooks/herdr-agent-state.sh' idle", + "command": "bash '/Users/danielkumlin/.claude/hooks/herdr-agent-state.sh' session", "timeout": 10, "type": "command" } @@ -151,16 +121,6 @@ } ], "matcher": "*" - }, - { - "hooks": [ - { - "command": "bash '/Users/danielkumlin/.claude/hooks/herdr-agent-state.sh' idle", - "timeout": 10, - "type": "command" - } - ], - "matcher": "*" } ], "UserPromptSubmit": [ @@ -181,16 +141,6 @@ } ], "matcher": "*" - }, - { - "hooks": [ - { - "command": "bash '/Users/danielkumlin/.claude/hooks/herdr-agent-state.sh' working", - "timeout": 10, - "type": "command" - } - ], - "matcher": "*" } ] }, diff --git a/config/codex/herdr-agent-state.sh b/config/codex/herdr-agent-state.sh index 5341d71..b3b08a7 100755 --- a/config/codex/herdr-agent-state.sh +++ b/config/codex/herdr-agent-state.sh @@ -3,7 +3,7 @@ # managed by herdr; reinstalling or updating the integration overwrites this file. # add custom hooks beside this file instead of editing it. # HERDR_INTEGRATION_ID=codex -# HERDR_INTEGRATION_VERSION=4 +# HERDR_INTEGRATION_VERSION=6 set -eu @@ -13,7 +13,7 @@ trap 'rm -f "$hook_input_file"' EXIT HUP INT TERM cat >"$hook_input_file" 2>/dev/null || true case "$action" in - working|idle|blocked|release) ;; + session) ;; *) exit 0 ;; esac @@ -48,35 +48,34 @@ if hook_input_file: except Exception: hook_input = {} +hook_event_name = str(hook_input.get("hook_event_name") or "") +if hook_event_name and hook_event_name != "SessionStart": + raise SystemExit(0) + request_id = f"{source}:{int(time.time() * 1000)}:{random.randrange(1_000_000):06d}" report_seq = time.time_ns() session_id = hook_input.get("session_id") agent_session_id = session_id if isinstance(session_id, str) and session_id else None -if action == "release": - request = { - "id": request_id, - "method": "pane.release_agent", - "params": { - "pane_id": pane_id, - "source": source, - "agent": "codex", - "seq": report_seq, - }, +session_start_source = hook_input.get("source") if hook_event_name == "SessionStart" else None +if not isinstance(session_start_source, str) or not session_start_source: + session_start_source = None +if agent_session_id: + params = { + "pane_id": pane_id, + "source": source, + "agent": "codex", + "seq": report_seq, + "agent_session_id": agent_session_id, } -else: + if session_start_source: + params["session_start_source"] = session_start_source request = { "id": request_id, - "method": "pane.report_agent", - "params": { - "pane_id": pane_id, - "source": source, - "agent": "codex", - "state": action, - "seq": report_seq, - }, + "method": "pane.report_agent_session", + "params": params, } - if agent_session_id: - request["params"]["agent_session_id"] = agent_session_id +else: + raise SystemExit(0) try: client = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) diff --git a/config/codex/hooks.json b/config/codex/hooks.json index ea06990..2ac18d7 100644 --- a/config/codex/hooks.json +++ b/config/codex/hooks.json @@ -18,15 +18,6 @@ "type": "command" } ] - }, - { - "hooks": [ - { - "command": "bash '/Users/danielkumlin/.codex/herdr-agent-state.sh' blocked", - "timeout": 10, - "type": "command" - } - ] } ], "PreToolUse": [ @@ -47,15 +38,6 @@ "type": "command" } ] - }, - { - "hooks": [ - { - "command": "bash '/Users/danielkumlin/.codex/herdr-agent-state.sh' working", - "timeout": 10, - "type": "command" - } - ] } ], "SessionStart": [ @@ -88,7 +70,7 @@ { "hooks": [ { - "command": "bash '/Users/danielkumlin/.codex/herdr-agent-state.sh' idle", + "command": "bash '/Users/danielkumlin/.codex/herdr-agent-state.sh' session", "timeout": 10, "type": "command" } @@ -121,15 +103,6 @@ "type": "command" } ] - }, - { - "hooks": [ - { - "command": "bash '/Users/danielkumlin/.codex/herdr-agent-state.sh' idle", - "timeout": 10, - "type": "command" - } - ] } ], "UserPromptSubmit": [ @@ -158,15 +131,6 @@ "type": "command" } ] - }, - { - "hooks": [ - { - "command": "bash '/Users/danielkumlin/.codex/herdr-agent-state.sh' working", - "timeout": 10, - "type": "command" - } - ] } ] } diff --git a/config/opencode/plugins/herdr-agent-state.js b/config/opencode/plugins/herdr-agent-state.js index ed0958f..7626505 100644 --- a/config/opencode/plugins/herdr-agent-state.js +++ b/config/opencode/plugins/herdr-agent-state.js @@ -2,12 +2,26 @@ // managed by herdr; reinstalling or updating the integration overwrites this file. // add custom hooks/plugins beside this file instead of editing it. // HERDR_INTEGRATION_ID=opencode -// HERDR_INTEGRATION_VERSION=3 +// HERDR_INTEGRATION_VERSION=9 import net from "node:net"; const SOURCE = "herdr:opencode"; +const AGENT = "opencode"; let reportSeq = Date.now() * 1000; +let requestChain = Promise.resolve(); +let reportedRootSessionID; + +// Track child sessions so their events cannot replace the pane's root session. +// Their user prompts still project state without attaching the child session id. +const childSessions = new Set(); +const CHILD_EVENT_STATES = new Map([ + ["permission.asked", "blocked"], + ["question.asked", "blocked"], + ["permission.replied", "working"], + ["question.replied", "working"], + ["question.rejected", "working"], +]); function nextReportSeq() { reportSeq += 1; @@ -20,7 +34,31 @@ function sessionIDFromProperties(properties) { : undefined; } -function reportState(action, sessionID) { +const SESSION_STATE_BY_STATUS = new Map([ + ["idle", "idle"], + ["active", "working"], + ["busy", "working"], + ["pending", "working"], + ["retry", "working"], + ["running", "working"], + ["streaming", "working"], + ["working", "working"], +]); + +function stateFromSessionStatus(status) { + const kind = typeof status === "string" ? status : status?.type; + return typeof kind === "string" + ? SESSION_STATE_BY_STATUS.get(kind.toLowerCase()) + : undefined; +} + +function request(method, params) { + const pending = requestChain.then(() => requestOnce(method, params)); + requestChain = pending.catch(() => {}); + return pending; +} + +function requestOnce(method, params) { const paneId = process.env.HERDR_PANE_ID; const socketPath = process.env.HERDR_SOCKET_PATH; @@ -28,33 +66,26 @@ function reportState(action, sessionID) { return Promise.resolve(); } + const socketEndpoint = + process.platform === "win32" ? `\\\\.\\pipe\\${socketPath}` : socketPath; + const requestId = `${SOURCE}:${Date.now()}:${Math.floor(Math.random() * 1_000_000) .toString() .padStart(6, "0")}`; - const params = - action === "release" - ? { - pane_id: paneId, - source: SOURCE, - agent: "opencode", - seq: nextReportSeq(), - } - : { - pane_id: paneId, - source: SOURCE, - agent: "opencode", - state: action, - seq: nextReportSeq(), - ...(sessionID ? { agent_session_id: sessionID } : {}), - }; const request = { id: requestId, - method: action === "release" ? "pane.release_agent" : "pane.report_agent", - params, + method, + params: { + pane_id: paneId, + source: SOURCE, + agent: AGENT, + seq: nextReportSeq(), + ...params, + }, }; return new Promise((resolve) => { - const client = net.createConnection(socketPath, () => { + const client = net.createConnection(socketEndpoint, () => { client.write(`${JSON.stringify(request)}\n`); }); @@ -71,6 +102,26 @@ function reportState(action, sessionID) { }); } +function reportSession(sessionID, sessionStartSource) { + if (!sessionID) { + return Promise.resolve(); + } + const params = { agent_session_id: sessionID }; + if (sessionStartSource) { + params.session_start_source = sessionStartSource; + } + return request("pane.report_agent_session", params); +} + +function reportState(state, sessionID) { + const params = { state }; + if (sessionID) { + reportedRootSessionID = sessionID; + params.agent_session_id = sessionID; + } + return request("pane.report_agent", params); +} + export const HerdrAgentStatePlugin = async () => { if ( process.env.HERDR_ENV !== "1" || @@ -81,54 +132,68 @@ export const HerdrAgentStatePlugin = async () => { } return { - dispose: async () => { - await reportState("release"); + "chat.message": async ({ sessionID }) => { + if (sessionID && childSessions.has(sessionID)) { + return; + } + await reportState("working", sessionID); }, event: async ({ event }) => { const type = event?.type; const properties = event?.properties ?? {}; const sessionID = sessionIDFromProperties(properties); + const info = properties.info; + if (info?.id && info.parentID) { + childSessions.add(info.id); + } + if (sessionID && childSessions.has(sessionID)) { + const state = CHILD_EVENT_STATES.get(type); + if (state) { + await reportState(state); + } + return; + } + switch (type) { - case "permission.asked": - case "question.asked": - await reportState("blocked", sessionID); + case "session.created": + // A root session.created is a genuine new-session start (subagent + // creates are dropped above). Signal it so herdr replaces the pane's + // prior session id instead of treating the change as cross-talk. + await reportSession(sessionID, "new"); break; - case "permission.replied": { - const reply = properties.reply ?? properties.response; - if (reply === "reject") { - await reportState("idle", sessionID); - } else if (reply === "once" || reply === "always") { - await reportState("working", sessionID); + case "session.updated": + if (sessionID && sessionID !== reportedRootSessionID) { + await reportSession(sessionID); + } + break; + case "session.status": { + const state = stateFromSessionStatus(properties.status); + if (state) { + await reportState(state, sessionID); + } else { + await reportSession(sessionID); } break; } + case "tool.execute.before": + case "tool.execute.after": + case "permission.replied": case "question.replied": - await reportState("working", sessionID); - break; case "question.rejected": - await reportState("idle", sessionID); - break; - case "session.created": - case "session.updated": - // session.created and session.updated are metadata events; lifecycle - // state comes from session.status and the deprecated session.idle. + case "session.compacted": + await reportState("working", sessionID); break; - case "session.status": { - const status = - typeof properties.status === "string" - ? properties.status - : properties.status?.type; - if (status === "busy" || status === "retry") { - await reportState("working", sessionID); - } else if (status === "idle") { - await reportState("idle", sessionID); - } + case "permission.asked": + case "question.asked": + case "session.error": + await reportState("blocked", sessionID); break; - } case "session.idle": await reportState("idle", sessionID); break; + case "session.deleted": + break; default: break; } diff --git a/config/pi/agent/extensions/herdr-agent-state.ts b/config/pi/agent/extensions/herdr-agent-state.ts index 6c9e1ca..2e79c7c 100644 --- a/config/pi/agent/extensions/herdr-agent-state.ts +++ b/config/pi/agent/extensions/herdr-agent-state.ts @@ -2,13 +2,15 @@ // managed by herdr; reinstalling or updating the integration overwrites this file. // add custom hooks/plugins beside this file instead of editing it. // HERDR_INTEGRATION_ID=pi -// HERDR_INTEGRATION_VERSION=3 +// HERDR_INTEGRATION_VERSION=7 // @ts-nocheck -import { createConnection } from "node:net"; +import net from "node:net"; const HERDR_ENV = process.env.HERDR_ENV; const socketPath = process.env.HERDR_SOCKET_PATH; +const socketEndpoint = + process.platform === "win32" && socketPath ? `\\\\.\\pipe\\${socketPath}` : socketPath; const paneId = process.env.HERDR_PANE_ID; const source = "herdr:pi"; @@ -16,30 +18,41 @@ function enabled() { return HERDR_ENV === "1" && !!socketPath && !!paneId; } -function sendRequest(request: unknown): Promise { +function sendRequestAttempt(request: unknown, timeoutMs: number): Promise { if (!enabled()) { - return Promise.resolve(); + return Promise.resolve(true); } return new Promise((resolve) => { let done = false; - const finish = () => { + let timeout: ReturnType | undefined; + const finish = (delivered: boolean) => { if (done) return; done = true; + if (timeout) { + clearTimeout(timeout); + } socket.destroy(); - resolve(); + resolve(delivered); }; - const socket = createConnection(socketPath!); - socket.on("error", finish); + const socket = net.createConnection(socketEndpoint!); + socket.on("error", () => finish(false)); socket.on("connect", () => socket.write(`${JSON.stringify(request)}\n`)); - socket.on("data", finish); - socket.on("end", finish); - const timeout = setTimeout(finish, 500); + socket.on("data", () => finish(true)); + socket.on("end", () => finish(false)); + timeout = setTimeout(() => finish(false), timeoutMs); timeout.unref?.(); }); } +async function sendRequest(request: unknown): Promise { + if (await sendRequestAttempt(request, 500)) { + return; + } + await sendRequestAttempt(request, 1500); +} + type AgentState = "working" | "blocked" | "idle"; type QueuedState = { @@ -48,10 +61,6 @@ type QueuedState = { seq: number; }; -const idleDebounceMs = parseDurationEnv("HERDR_PI_IDLE_DEBOUNCE_MS", 250); -const retryGraceMs = parseDurationEnv("HERDR_PI_RETRY_GRACE_MS", 2500); -const retryableErrorPattern = - /overloaded|provider.?returned.?error|rate.?limit|too many requests|429|500|502|503|504|service.?unavailable|server.?error|internal.?error|network.?error|connection.?error|connection.?refused|connection.?lost|websocket.?closed|websocket.?error|other side closed|fetch failed|upstream.?connect|reset before headers|socket hang up|ended without|http2 request did not get a response|timed? out|timeout|terminated|retry delay/i; let reportSeq = Date.now() * 1000; let currentAgentSessionId: string | undefined; let currentAgentSessionPath: string | undefined; @@ -61,18 +70,6 @@ function nextReportSeq(): number { return reportSeq; } -function parseDurationEnv(name: string, fallback: number): number { - const raw = process.env[name]; - if (!raw) { - return fallback; - } - const parsed = Number.parseInt(raw, 10); - if (!Number.isFinite(parsed) || parsed < 0) { - return fallback; - } - return parsed; -} - function updateSessionRef(ctx: any): void { try { const file = ctx?.sessionManager?.getSessionFile?.(); @@ -110,7 +107,7 @@ function currentSessionRef(): Record | undefined { return undefined; } -function reportSession(): Promise { +function reportSession(sessionStartSource?: string): Promise { const sessionRef = currentSessionRef(); if (!sessionRef) { return Promise.resolve(); @@ -124,6 +121,7 @@ function reportSession(): Promise { source, agent: "pi", seq: nextReportSeq(), + session_start_source: sessionStartSource, ...sessionRef, }, }); @@ -144,19 +142,6 @@ function sendState(state: AgentState, message?: string, seq = nextReportSeq()): }); } -function releaseAgent(): Promise { - return sendRequest({ - id: `${source}:release:${Date.now()}:${Math.random().toString(36).slice(2)}`, - method: "pane.release_agent", - params: { - pane_id: paneId, - source, - agent: "pi", - seq: nextReportSeq(), - }, - }); -} - let sendInFlight = false; let queuedState: QueuedState | undefined; @@ -187,74 +172,23 @@ async function drainStateQueue(): Promise { } } -function lastAssistantMessage(messages: unknown[]): any | undefined { - for (let i = messages.length - 1; i >= 0; i -= 1) { - const message = messages[i] as any; - if (message?.role === "assistant") { - return message; - } - } - return undefined; -} - -function retryableErrorMessage(event: any): string | undefined { - const messages = Array.isArray(event?.messages) ? event.messages : []; - const assistant = lastAssistantMessage(messages); - if (assistant?.stopReason !== "error") { - return undefined; - } - - const errorMessage = String(assistant.errorMessage ?? ""); - if (!retryableErrorPattern.test(errorMessage)) { - return undefined; - } - return errorMessage || "retryable provider error"; -} - export default function (pi) { if (!enabled()) { return; } let agentActive = false; - let retryHoldActive = false; - let failureBlocked = false; - let failureMessage: string | undefined; let blockedCount = 0; let blockedMessage: string | undefined; let lastState: AgentState | undefined; let lastMessage: string | undefined; - let idleTimer: ReturnType | undefined; - let retryTimer: ReturnType | undefined; let rootSession = false; - function clearTimer(timer: ReturnType | undefined) { - if (timer) { - clearTimeout(timer); - } - } - - function clearPendingTimers() { - clearTimer(idleTimer); - clearTimer(retryTimer); - idleTimer = undefined; - retryTimer = undefined; - } - - function clearFailureState() { - retryHoldActive = false; - failureBlocked = false; - failureMessage = undefined; - } - function desiredState() { if (blockedCount > 0) { return { state: "blocked" as const, message: blockedMessage }; } - if (failureBlocked) { - return { state: "blocked" as const, message: failureMessage }; - } - if (agentActive || retryHoldActive) { + if (agentActive) { return { state: "working" as const, message: undefined }; } return { state: "idle" as const, message: undefined }; @@ -270,32 +204,6 @@ export default function (pi) { queueState(next.state, next.message); } - function scheduleIdle() { - clearPendingTimers(); - clearFailureState(); - idleTimer = setTimeout(() => { - idleTimer = undefined; - publishState(); - }, idleDebounceMs); - idleTimer.unref?.(); - } - - function holdForRetry(message: string) { - clearPendingTimers(); - retryHoldActive = true; - failureBlocked = false; - failureMessage = message; - publishState(); - - retryTimer = setTimeout(() => { - retryTimer = undefined; - retryHoldActive = false; - failureBlocked = true; - publishState(); - }, retryGraceMs); - retryTimer.unref?.(); - } - pi.events.on("herdr:blocked", (data) => { if (!rootSession) { return; @@ -309,59 +217,39 @@ export default function (pi) { return; } - clearPendingTimers(); blockedCount += 1; blockedMessage = data.label; publishState(); }); - pi.on("session_start", (_event, ctx) => { + pi.on("session_start", async (event, ctx) => { if (ctx?.hasUI !== true) { return; } rootSession = true; updateSessionRef(ctx); - void reportSession(); + await reportSession(event?.reason); + // A reload can replace this extension mid-run without emitting another agent_start. + agentActive = ctx?.isIdle?.() === false; publishState(true); }); - pi.on("agent_start", () => { + pi.on("agent_start", (_event, ctx) => { if (!rootSession) { return; } - clearPendingTimers(); - clearFailureState(); + updateSessionRef(ctx); + void reportSession(); agentActive = true; publishState(); }); - pi.on("agent_end", (event) => { - if (!rootSession) { - return; - } - if (!agentActive) { - // Pi can emit duplicate/late end events while auto-retry is already - // holding the pane in Working. Do not let an unqualified duplicate end - // cancel the retry hold and publish a false Idle. + pi.on("agent_settled", (_event, ctx) => { + if (!rootSession || ctx?.isIdle?.() !== true) { return; } agentActive = false; - - const retryableMessage = retryableErrorMessage(event); - if (retryableMessage) { - holdForRetry(retryableMessage); - return; - } - - scheduleIdle(); - }); - - pi.on("session_shutdown", async () => { - if (!rootSession) { - return; - } - clearPendingTimers(); - await releaseAgent(); + publishState(); }); } diff --git a/config/pi/agent/extensions/pi-herdr-agent-state.ts b/config/pi/agent/extensions/pi-herdr-agent-state.ts deleted file mode 100644 index 26869f1..0000000 --- a/config/pi/agent/extensions/pi-herdr-agent-state.ts +++ /dev/null @@ -1,285 +0,0 @@ -// installed by herdr -// safe to edit. this integration only activates inside herdr-managed panes. -// HERDR_INTEGRATION_ID=pi -// HERDR_INTEGRATION_VERSION=1 -// @ts-nocheck - -import { createConnection } from "node:net"; - -const HERDR_ENV = process.env.HERDR_ENV; -const socketPath = process.env.HERDR_SOCKET_PATH; -const paneId = process.env.HERDR_PANE_ID; -const source = "herdr:pi"; - -function enabled() { - return HERDR_ENV === "1" && !!socketPath && !!paneId; -} - -function sendRequest(request: unknown): Promise { - if (!enabled()) { - return Promise.resolve(); - } - - return new Promise((resolve) => { - let done = false; - const finish = () => { - if (done) return; - done = true; - socket.destroy(); - resolve(); - }; - - const socket = createConnection(socketPath!); - socket.on("error", finish); - socket.on("connect", () => socket.write(`${JSON.stringify(request)}\n`)); - socket.on("data", finish); - socket.on("end", finish); - const timeout = setTimeout(finish, 500); - timeout.unref?.(); - }); -} - -type AgentState = "working" | "blocked" | "idle"; - -type QueuedState = { - state: AgentState; - message?: string; - seq: number; -}; - -const idleDebounceMs = parseDurationEnv("HERDR_PI_IDLE_DEBOUNCE_MS", 250); -const retryGraceMs = parseDurationEnv("HERDR_PI_RETRY_GRACE_MS", 2500); -const retryableErrorPattern = - /overloaded|provider.?returned.?error|rate.?limit|too many requests|429|500|502|503|504|service.?unavailable|server.?error|internal.?error|network.?error|connection.?error|connection.?refused|connection.?lost|websocket.?closed|websocket.?error|other side closed|fetch failed|upstream.?connect|reset before headers|socket hang up|ended without|http2 request did not get a response|timed? out|timeout|terminated|retry delay/i; -let reportSeq = Date.now() * 1000; - -function nextReportSeq(): number { - reportSeq += 1; - return reportSeq; -} - -function parseDurationEnv(name: string, fallback: number): number { - const raw = process.env[name]; - if (!raw) { - return fallback; - } - const parsed = Number.parseInt(raw, 10); - if (!Number.isFinite(parsed) || parsed < 0) { - return fallback; - } - return parsed; -} - -function sendState(state: AgentState, message?: string, seq = nextReportSeq()): Promise { - return sendRequest({ - id: `${source}:${Date.now()}:${Math.random().toString(36).slice(2)}`, - method: "pane.report_agent", - params: { - pane_id: paneId, - source, - agent: "pi", - state, - message, - seq, - }, - }); -} - -let sendInFlight = false; -let queuedState: QueuedState | undefined; - -function queueState(state: AgentState, message?: string): void { - queuedState = { state, message, seq: nextReportSeq() }; - if (!sendInFlight) { - void drainStateQueue(); - } -} - -async function drainStateQueue(): Promise { - if (sendInFlight) { - return; - } - - sendInFlight = true; - try { - while (queuedState) { - const next = queuedState; - queuedState = undefined; - await sendState(next.state, next.message, next.seq); - } - } finally { - sendInFlight = false; - if (queuedState) { - void drainStateQueue(); - } - } -} - -function lastAssistantMessage(messages: unknown[]): any | undefined { - for (let i = messages.length - 1; i >= 0; i -= 1) { - const message = messages[i] as any; - if (message?.role === "assistant") { - return message; - } - } - return undefined; -} - -function retryableErrorMessage(event: any): string | undefined { - const messages = Array.isArray(event?.messages) ? event.messages : []; - const assistant = lastAssistantMessage(messages); - if (assistant?.stopReason !== "error") { - return undefined; - } - - const errorMessage = String(assistant.errorMessage ?? ""); - if (!retryableErrorPattern.test(errorMessage)) { - return undefined; - } - return errorMessage || "retryable provider error"; -} - -function releaseAgent(): Promise { - return sendRequest({ - id: `${source}:release:${Date.now()}:${Math.random().toString(36).slice(2)}`, - method: "pane.release_agent", - params: { - pane_id: paneId, - source, - agent: "pi", - seq: nextReportSeq(), - }, - }); -} - -export default function (pi) { - if (!enabled()) { - return; - } - - let agentActive = false; - let retryHoldActive = false; - let failureBlocked = false; - let failureMessage: string | undefined; - let blockedCount = 0; - let blockedMessage: string | undefined; - let lastState: AgentState | undefined; - let lastMessage: string | undefined; - let idleTimer: ReturnType | undefined; - let retryTimer: ReturnType | undefined; - - function clearTimer(timer: ReturnType | undefined) { - if (timer) { - clearTimeout(timer); - } - } - - function clearPendingTimers() { - clearTimer(idleTimer); - clearTimer(retryTimer); - idleTimer = undefined; - retryTimer = undefined; - } - - function clearFailureState() { - retryHoldActive = false; - failureBlocked = false; - failureMessage = undefined; - } - - function desiredState() { - if (blockedCount > 0) { - return { state: "blocked" as const, message: blockedMessage }; - } - if (failureBlocked) { - return { state: "blocked" as const, message: failureMessage }; - } - if (agentActive || retryHoldActive) { - return { state: "working" as const, message: undefined }; - } - return { state: "idle" as const, message: undefined }; - } - - function publishState() { - const next = desiredState(); - if (next.state === lastState && next.message === lastMessage) { - return; - } - lastState = next.state; - lastMessage = next.message; - queueState(next.state, next.message); - } - - function scheduleIdle() { - clearPendingTimers(); - clearFailureState(); - idleTimer = setTimeout(() => { - idleTimer = undefined; - publishState(); - }, idleDebounceMs); - idleTimer.unref?.(); - } - - function holdForRetry(message: string) { - clearPendingTimers(); - retryHoldActive = true; - failureBlocked = false; - failureMessage = message; - publishState(); - - retryTimer = setTimeout(() => { - retryTimer = undefined; - retryHoldActive = false; - failureBlocked = true; - publishState(); - }, retryGraceMs); - retryTimer.unref?.(); - } - - pi.events.on("herdr:blocked", (data) => { - if (!data?.active) { - blockedCount = Math.max(0, blockedCount - 1); - if (blockedCount === 0) { - blockedMessage = undefined; - } - publishState(); - return; - } - - clearPendingTimers(); - blockedCount += 1; - blockedMessage = data.label; - publishState(); - }); - - pi.on("agent_start", () => { - clearPendingTimers(); - clearFailureState(); - agentActive = true; - publishState(); - }); - - pi.on("agent_end", (event) => { - if (!agentActive) { - // Pi can emit duplicate/late end events while auto-retry is already - // holding the pane in Working. Do not let an unqualified duplicate end - // cancel the retry hold and publish a false Idle. - return; - } - - agentActive = false; - - const retryableMessage = retryableErrorMessage(event); - if (retryableMessage) { - holdForRetry(retryableMessage); - return; - } - - scheduleIdle(); - }); - - pi.on("session_shutdown", async () => { - clearPendingTimers(); - await releaseAgent(); - }); -} diff --git a/config/pi/agent/extensions/pi-herdr/README.md b/config/pi/agent/extensions/pi-herdr/README.md new file mode 100644 index 0000000..568fa04 --- /dev/null +++ b/config/pi/agent/extensions/pi-herdr/README.md @@ -0,0 +1,14 @@ +# pi-herdr + +Pi tool for orchestrating Herdr panes, tabs, workspaces, and worktrees. + +The extension talks directly to Herdr's newline-delimited socket API. Protocol request and response types in `generated/` come from the JSON Schema bundled with the installed Herdr binary; they are not maintained by hand. + +```bash +npm install +npm run generate # refresh after updating Herdr +npm run check-generated # fail when generated types are stale +npm run typecheck +``` + +`herdr-agent-state.ts` remains a separate Herdr-managed extension at the parent `extensions/` level. It reports Pi lifecycle and session state to Herdr; this package controls Herdr from Pi. diff --git a/config/pi/agent/extensions/pi-herdr/client.ts b/config/pi/agent/extensions/pi-herdr/client.ts new file mode 100644 index 0000000..7ddf151 --- /dev/null +++ b/config/pi/agent/extensions/pi-herdr/client.ts @@ -0,0 +1,104 @@ +import net from "node:net"; + +import type { ErrorResponse } from "./generated/error-response.ts"; +import type { Request } from "./generated/request.ts"; +import type { ResponseResult, SuccessResponse } from "./generated/success-response.ts"; + +type Method = Request["method"]; +type RequestFor = Extract; +export type ParamsFor = RequestFor["params"]; +export type ResultOfType = Extract; + +interface CallOptions { + signal?: AbortSignal; + timeoutMs?: number; +} + +function isRecord(value: unknown): value is Record { + return typeof value === "object" && value !== null && !Array.isArray(value); +} + +function parseResponse(value: unknown, expectedId: string): ResponseResult { + if (!isRecord(value) || value.id !== expectedId) { + throw new Error("Herdr returned an invalid or mismatched response envelope"); + } + + if ("error" in value) { + const response = value as unknown as ErrorResponse; + throw new Error(response.error.message || response.error.code || "Herdr request failed"); + } + + const response = value as unknown as SuccessResponse; + if (!isRecord(response.result) || typeof response.result.type !== "string") { + throw new Error("Herdr returned an invalid success response"); + } + return response.result; +} + +export function expectResult( + result: ResponseResult, + expected: K, +): ResultOfType { + if (result.type !== expected) { + throw new Error(`Expected Herdr result '${expected}', received '${result.type}'`); + } + return result as ResultOfType; +} + +export class HerdrClient { + readonly #endpoint: string; + #requestId = 0; + + constructor(socketPath: string) { + this.#endpoint = process.platform === "win32" ? `\\\\.\\pipe\\${socketPath}` : socketPath; + } + + call(method: M, params: ParamsFor, options: CallOptions = {}): Promise { + const id = `pi-herdr:${process.pid}:${Date.now()}:${++this.#requestId}`; + const request = { id, method, params } as RequestFor; + + return new Promise((resolve, reject) => { + let settled = false; + let buffer = ""; + let timeout: ReturnType | undefined; + const socket = net.createConnection(this.#endpoint); + + const finish = (error?: Error, result?: ResponseResult) => { + if (settled) return; + settled = true; + if (timeout) clearTimeout(timeout); + options.signal?.removeEventListener("abort", onAbort); + socket.destroy(); + if (error) reject(error); + else resolve(result!); + }; + + const onAbort = () => finish(new Error("Aborted")); + if (options.signal?.aborted) { + finish(new Error("Aborted")); + return; + } + options.signal?.addEventListener("abort", onAbort, { once: true }); + + if (options.timeoutMs != null) { + timeout = setTimeout(() => finish(new Error(`Herdr request '${method}' timed out`)), options.timeoutMs); + timeout.unref?.(); + } + + socket.setEncoding("utf8"); + socket.on("connect", () => socket.write(`${JSON.stringify(request)}\n`)); + socket.on("data", (chunk) => { + buffer += chunk; + const newline = buffer.indexOf("\n"); + if (newline === -1) return; + try { + finish(undefined, parseResponse(JSON.parse(buffer.slice(0, newline)), id)); + } catch (error) { + finish(error instanceof Error ? error : new Error(String(error))); + } + }); + socket.on("error", (error) => finish(error)); + socket.on("end", () => finish(new Error(`Herdr closed the socket before replying to '${method}'`))); + }); + } +} diff --git a/config/pi/agent/extensions/pi-herdr/generate-protocol-types.mjs b/config/pi/agent/extensions/pi-herdr/generate-protocol-types.mjs new file mode 100644 index 0000000..3517426 --- /dev/null +++ b/config/pi/agent/extensions/pi-herdr/generate-protocol-types.mjs @@ -0,0 +1,72 @@ +#!/usr/bin/env node + +import { spawnSync } from "node:child_process"; +import { readFile, writeFile } from "node:fs/promises"; +import { dirname, join } from "node:path"; +import { fileURLToPath } from "node:url"; +import { compile } from "json-schema-to-typescript"; + +const here = dirname(fileURLToPath(import.meta.url)); +const check = process.argv.includes("--check"); +const result = spawnSync("herdr", ["api", "schema", "--json"], { + encoding: "utf8", + maxBuffer: 8 * 1024 * 1024, +}); + +if (result.status !== 0) { + process.stderr.write(result.stderr || "herdr api schema --json failed\n"); + process.exit(result.status ?? 1); +} + +const document = JSON.parse(result.stdout); +const selections = [ + ["request", "request.ts"], + ["success_response", "success-response.ts"], + ["error_response", "error-response.ts"], +]; + +function rewriteRefs(value, schemaName) { + if (Array.isArray(value)) return value.map((item) => rewriteRefs(item, schemaName)); + if (!value || typeof value !== "object") return value; + + const copy = {}; + for (const [key, child] of Object.entries(value)) { + if (key === "$ref" && typeof child === "string") { + copy[key] = child.replace(`#\/schemas\/${schemaName}\/`, "#/"); + } else { + copy[key] = rewriteRefs(child, schemaName); + } + } + return copy; +} + +let stale = false; +for (const [schemaName, outputName] of selections) { + const schema = document.schemas?.[schemaName]; + if (!schema) throw new Error(`Herdr schema is missing schemas.${schemaName}`); + + const generated = await compile(rewriteRefs(schema, schemaName), schema.title, { + bannerComment: [ + "/* eslint-disable */", + "/**", + ` * Generated from Herdr protocol ${document.protocol}, schema version ${document.schema_version}.`, + " * Run `npm run generate` after updating Herdr. Do not edit by hand.", + " */", + ].join("\n"), + style: { printWidth: 120, singleQuote: false, tabWidth: 2, useTabs: false }, + }); + const outputPath = join(here, "generated", outputName); + + if (check) { + const current = await readFile(outputPath, "utf8").catch(() => ""); + if (current !== generated) { + console.error(`${outputPath} is stale`); + stale = true; + } + } else { + await writeFile(outputPath, generated); + console.log(`generated ${outputPath}`); + } +} + +if (stale) process.exit(1); diff --git a/config/pi/agent/extensions/pi-herdr/generated/error-response.ts b/config/pi/agent/extensions/pi-herdr/generated/error-response.ts new file mode 100644 index 0000000..90211c6 --- /dev/null +++ b/config/pi/agent/extensions/pi-herdr/generated/error-response.ts @@ -0,0 +1,16 @@ +/* eslint-disable */ +/** + * Generated from Herdr protocol 18, schema version 1. + * Run `npm run generate` after updating Herdr. Do not edit by hand. + */ + +export interface ErrorResponse { + error: ErrorBody; + id: string; + [k: string]: unknown; +} +export interface ErrorBody { + code: string; + message: string; + [k: string]: unknown; +} diff --git a/config/pi/agent/extensions/pi-herdr/generated/request.ts b/config/pi/agent/extensions/pi-herdr/generated/request.ts new file mode 100644 index 0000000..d0b2a16 --- /dev/null +++ b/config/pi/agent/extensions/pi-herdr/generated/request.ts @@ -0,0 +1,1301 @@ +/* eslint-disable */ +/** + * Generated from Herdr protocol 18, schema version 1. + * Run `npm run generate` after updating Herdr. Do not edit by hand. + */ + +export type Request = { + id: string; + [k: string]: unknown; +} & ( + | { + method: "ping"; + params: PingParams; + [k: string]: unknown; + } + | { + method: "server.stop"; + params: EmptyParams; + [k: string]: unknown; + } + | { + method: "server.live_handoff"; + params: ServerLiveHandoffParams; + [k: string]: unknown; + } + | { + method: "server.reload_config"; + params: EmptyParams; + [k: string]: unknown; + } + | { + method: "server.agent_manifests"; + params: EmptyParams; + [k: string]: unknown; + } + | { + method: "server.reload_agent_manifests"; + params: EmptyParams; + [k: string]: unknown; + } + | { + method: "notification.show"; + params: NotificationShowParams; + [k: string]: unknown; + } + | { + method: "client.window_title.set"; + params: ClientWindowTitleSetParams; + [k: string]: unknown; + } + | { + method: "client.window_title.clear"; + params: EmptyParams; + [k: string]: unknown; + } + | { + method: "session.snapshot"; + params: EmptyParams; + [k: string]: unknown; + } + | { + method: "workspace.create"; + params: WorkspaceCreateParams; + [k: string]: unknown; + } + | { + method: "workspace.list"; + params: EmptyParams; + [k: string]: unknown; + } + | { + method: "workspace.get"; + params: WorkspaceTarget; + [k: string]: unknown; + } + | { + method: "workspace.focus"; + params: WorkspaceTarget; + [k: string]: unknown; + } + | { + method: "workspace.rename"; + params: WorkspaceRenameParams; + [k: string]: unknown; + } + | { + method: "workspace.move"; + params: WorkspaceMoveParams; + [k: string]: unknown; + } + | { + method: "workspace.report_metadata"; + params: WorkspaceReportMetadataParams; + [k: string]: unknown; + } + | { + method: "workspace.close"; + params: WorkspaceTarget; + [k: string]: unknown; + } + | { + method: "worktree.list"; + params: WorktreeListParams; + [k: string]: unknown; + } + | { + method: "worktree.create"; + params: WorktreeCreateParams; + [k: string]: unknown; + } + | { + method: "worktree.open"; + params: WorktreeOpenParams; + [k: string]: unknown; + } + | { + method: "worktree.remove"; + params: WorktreeRemoveParams; + [k: string]: unknown; + } + | { + method: "tab.create"; + params: TabCreateParams; + [k: string]: unknown; + } + | { + method: "tab.list"; + params: TabListParams; + [k: string]: unknown; + } + | { + method: "tab.get"; + params: TabTarget; + [k: string]: unknown; + } + | { + method: "tab.focus"; + params: TabTarget; + [k: string]: unknown; + } + | { + method: "tab.rename"; + params: TabRenameParams; + [k: string]: unknown; + } + | { + method: "tab.move"; + params: TabMoveParams; + [k: string]: unknown; + } + | { + method: "tab.close"; + params: TabTarget; + [k: string]: unknown; + } + | { + method: "agent.list"; + params: EmptyParams; + [k: string]: unknown; + } + | { + method: "agent.get"; + params: AgentTarget; + [k: string]: unknown; + } + | { + method: "agent.read"; + params: AgentReadParams; + [k: string]: unknown; + } + | { + method: "agent.explain"; + params: AgentTarget; + [k: string]: unknown; + } + | { + method: "agent.send_keys"; + params: AgentSendKeysParams; + [k: string]: unknown; + } + | { + method: "agent.rename"; + params: AgentRenameParams; + [k: string]: unknown; + } + | { + method: "agent.view.set"; + params: AgentViewSetParams; + [k: string]: unknown; + } + | { + method: "agent.view.clear"; + params: AgentViewClearParams; + [k: string]: unknown; + } + | { + method: "agent.focus"; + params: AgentTarget; + [k: string]: unknown; + } + | { + method: "agent.start"; + params: AgentStartParams; + [k: string]: unknown; + } + | { + method: "agent.prompt"; + params: AgentPromptParams; + [k: string]: unknown; + } + | { + method: "agent.wait"; + params: AgentWaitParams; + [k: string]: unknown; + } + | { + method: "pane.split"; + params: PaneSplitParams; + [k: string]: unknown; + } + | { + method: "pane.swap"; + params: PaneSwapParams; + [k: string]: unknown; + } + | { + method: "pane.move"; + params: PaneMoveParams; + [k: string]: unknown; + } + | { + method: "pane.zoom"; + params: PaneZoomParams; + [k: string]: unknown; + } + | { + method: "pane.layout"; + params: PaneLayoutParams; + [k: string]: unknown; + } + | { + method: "pane.process_info"; + params: PaneProcessInfoParams; + [k: string]: unknown; + } + | { + method: "layout.export"; + params: LayoutExportParams; + [k: string]: unknown; + } + | { + method: "layout.apply"; + params: LayoutApplyParams; + [k: string]: unknown; + } + | { + method: "layout.set_split_ratio"; + params: LayoutSetSplitRatioParams; + [k: string]: unknown; + } + | { + method: "pane.neighbor"; + params: PaneNeighborParams; + [k: string]: unknown; + } + | { + method: "pane.edges"; + params: PaneEdgesParams; + [k: string]: unknown; + } + | { + method: "pane.focus_direction"; + params: PaneFocusDirectionParams; + [k: string]: unknown; + } + | { + method: "pane.resize"; + params: PaneResizeParams; + [k: string]: unknown; + } + | { + method: "pane.list"; + params: PaneListParams; + [k: string]: unknown; + } + | { + method: "pane.current"; + params: PaneCurrentParams; + [k: string]: unknown; + } + | { + method: "pane.get"; + params: PaneTarget; + [k: string]: unknown; + } + | { + method: "pane.focus"; + params: PaneTarget; + [k: string]: unknown; + } + | { + method: "pane.rename"; + params: PaneRenameParams; + [k: string]: unknown; + } + | { + method: "pane.send_text"; + params: PaneSendTextParams; + [k: string]: unknown; + } + | { + method: "pane.send_keys"; + params: PaneSendKeysParams; + [k: string]: unknown; + } + | { + method: "pane.send_input"; + params: PaneSendInputParams; + [k: string]: unknown; + } + | { + method: "pane.read"; + params: PaneReadParams; + [k: string]: unknown; + } + | { + method: "pane.graphics.set"; + params: PaneGraphicsSetParams; + [k: string]: unknown; + } + | { + method: "pane.graphics.clear"; + params: PaneGraphicsClearParams; + [k: string]: unknown; + } + | { + method: "pane.graphics.info"; + params: PaneTarget; + [k: string]: unknown; + } + | { + method: "pane.report_agent"; + params: PaneReportAgentParams; + [k: string]: unknown; + } + | { + method: "pane.report_agent_session"; + params: PaneReportAgentSessionParams; + [k: string]: unknown; + } + | { + method: "pane.report_metadata"; + params: PaneReportMetadataParams; + [k: string]: unknown; + } + | { + method: "pane.clear_agent_authority"; + params: PaneClearAgentAuthorityParams; + [k: string]: unknown; + } + | { + method: "pane.release_agent"; + params: PaneReleaseAgentParams; + [k: string]: unknown; + } + | { + method: "pane.close"; + params: PaneTarget; + [k: string]: unknown; + } + | { + method: "popup.close"; + params: EmptyParams; + [k: string]: unknown; + } + | { + method: "events.subscribe"; + params: EventsSubscribeParams; + [k: string]: unknown; + } + | { + method: "events.wait"; + params: EventsWaitParams; + [k: string]: unknown; + } + | { + method: "pane.wait_for_output"; + params: PaneWaitForOutputParams; + [k: string]: unknown; + } + | { + method: "integration.install"; + params: IntegrationInstallParams; + [k: string]: unknown; + } + | { + method: "integration.uninstall"; + params: IntegrationUninstallParams; + [k: string]: unknown; + } + | { + method: "plugin.link"; + params: PluginLinkParams; + [k: string]: unknown; + } + | { + method: "plugin.list"; + params: PluginListParams; + [k: string]: unknown; + } + | { + method: "plugin.unlink"; + params: PluginUnlinkParams; + [k: string]: unknown; + } + | { + method: "plugin.enable"; + params: PluginSetEnabledParams; + [k: string]: unknown; + } + | { + method: "plugin.disable"; + params: PluginSetEnabledParams; + [k: string]: unknown; + } + | { + method: "plugin.action.list"; + params: PluginActionListParams; + [k: string]: unknown; + } + | { + method: "plugin.action.invoke"; + params: PluginActionInvokeParams; + [k: string]: unknown; + } + | { + method: "plugin.log.list"; + params: PluginLogListParams; + [k: string]: unknown; + } + | { + method: "plugin.pane.open"; + params: PluginPaneOpenParams; + [k: string]: unknown; + } + | { + method: "plugin.pane.focus"; + params: PluginPaneFocusParams; + [k: string]: unknown; + } + | { + method: "plugin.pane.close"; + params: PluginPaneCloseParams; + [k: string]: unknown; + } +); +export type ToastHerdrPosition = "top-left" | "top-right" | "bottom-left" | "bottom-right"; +export type NotificationShowSound = "none" | "done" | "request"; +export type ReadSource = "visible" | "recent" | "recent_unwrapped" | "detection"; +export type AgentViewFilter = + | { + filters: AgentViewFilter[]; + op: "all"; + [k: string]: unknown; + } + | { + filters: AgentViewFilter[]; + op: "any"; + [k: string]: unknown; + } + | { + filter: AgentViewFilter; + op: "not"; + [k: string]: unknown; + } + | { + field: AgentViewField; + op: "eq"; + value: AgentViewValue; + [k: string]: unknown; + } + | { + field: AgentViewField; + op: "in"; + values: AgentViewValue[]; + [k: string]: unknown; + } + | { + field: AgentViewField; + op: "exists"; + [k: string]: unknown; + }; +export type AgentViewField = + | AgentViewBuiltinField + | { + token: string; + [k: string]: unknown; + }; +export type AgentViewBuiltinField = + "status" | "workspace_id" | "tab_id" | "pane_id" | "agent" | "seen" | "state_change_seq"; +export type AgentViewValue = + | string + | boolean + | number + | { + context: AgentViewContext; + [k: string]: unknown; + }; +export type AgentViewContext = "current_workspace_id" | "current_tab_id"; +export type AgentViewSortField = + | AgentViewBuiltinSortField + | { + token: string; + [k: string]: unknown; + }; +export type AgentViewBuiltinSortField = + "workspace_order" | "tab_order" | "pane_order" | "attention" | "status" | "agent" | "seen" | "state_change_seq"; +export type AgentStatus = "idle" | "working" | "blocked" | "done" | "unknown"; +export type SplitDirection = "right" | "down"; +export type PaneDirection = "left" | "right" | "up" | "down"; +export type PaneMoveDestination = + | { + ratio?: number | null; + split: SplitDirection; + tab_id: string; + target_pane_id?: string | null; + type: "tab"; + [k: string]: unknown; + } + | { + label?: string | null; + type: "new_tab"; + workspace_id?: string | null; + [k: string]: unknown; + } + | { + label?: string | null; + tab_label?: string | null; + type: "new_workspace"; + [k: string]: unknown; + }; +export type LayoutNode = + | { + command?: string[] | null; + cwd?: string | null; + env?: { + [k: string]: string; + }; + label?: string | null; + pane_id?: string | null; + type: "pane"; + [k: string]: unknown; + } + | { + direction: SplitDirection; + first: LayoutNode; + ratio: number; + second: LayoutNode; + type: "split"; + [k: string]: unknown; + }; +export type PaneGraphicsFormat = "png" | "rgb" | "rgba"; +export type PaneAgentState = "idle" | "working" | "blocked" | "unknown"; +export type Subscription = + | { + type: "workspace.created"; + [k: string]: unknown; + } + | { + type: "workspace.updated"; + [k: string]: unknown; + } + | { + type: "workspace.metadata_updated"; + [k: string]: unknown; + } + | { + type: "workspace.renamed"; + [k: string]: unknown; + } + | { + type: "workspace.moved"; + [k: string]: unknown; + } + | { + type: "workspace.closed"; + [k: string]: unknown; + } + | { + type: "workspace.focused"; + [k: string]: unknown; + } + | { + type: "worktree.created"; + [k: string]: unknown; + } + | { + type: "worktree.opened"; + [k: string]: unknown; + } + | { + type: "worktree.removed"; + [k: string]: unknown; + } + | { + type: "tab.created"; + [k: string]: unknown; + } + | { + type: "tab.closed"; + [k: string]: unknown; + } + | { + type: "tab.focused"; + [k: string]: unknown; + } + | { + type: "tab.renamed"; + [k: string]: unknown; + } + | { + type: "tab.moved"; + [k: string]: unknown; + } + | { + type: "pane.created"; + [k: string]: unknown; + } + | { + type: "pane.closed"; + [k: string]: unknown; + } + | { + type: "pane.updated"; + [k: string]: unknown; + } + | { + type: "pane.focused"; + [k: string]: unknown; + } + | { + type: "pane.moved"; + [k: string]: unknown; + } + | { + type: "pane.exited"; + [k: string]: unknown; + } + | { + type: "pane.agent_detected"; + [k: string]: unknown; + } + | { + lines?: number | null; + match: OutputMatch; + pane_id: string; + source: ReadSource; + strip_ansi?: boolean; + type: "pane.output_matched"; + [k: string]: unknown; + } + | { + agent_status?: AgentStatus | null; + pane_id: string; + type: "pane.agent_status_changed"; + [k: string]: unknown; + } + | { + pane_id: string; + type: "pane.scroll_changed"; + [k: string]: unknown; + } + | { + type: "layout.updated"; + [k: string]: unknown; + }; +export type OutputMatch = + | { + type: "substring"; + value: string; + [k: string]: unknown; + } + | { + type: "regex"; + value: string; + [k: string]: unknown; + }; +export type EventMatch = + | { + event: "workspace_created"; + workspace_id?: string | null; + [k: string]: unknown; + } + | { + event: "workspace_updated"; + workspace_id: string; + [k: string]: unknown; + } + | { + event: "workspace_closed"; + workspace_id: string; + [k: string]: unknown; + } + | { + event: "workspace_renamed"; + label?: string | null; + workspace_id: string; + [k: string]: unknown; + } + | { + event: "workspace_moved"; + workspace_id: string; + [k: string]: unknown; + } + | { + event: "workspace_focused"; + workspace_id: string; + [k: string]: unknown; + } + | { + event: "tab_created"; + tab_id?: string | null; + workspace_id?: string | null; + [k: string]: unknown; + } + | { + event: "tab_closed"; + tab_id: string; + [k: string]: unknown; + } + | { + event: "tab_renamed"; + label?: string | null; + tab_id: string; + [k: string]: unknown; + } + | { + event: "tab_moved"; + tab_id: string; + [k: string]: unknown; + } + | { + event: "tab_focused"; + tab_id: string; + [k: string]: unknown; + } + | { + event: "pane_created"; + pane_id?: string | null; + workspace_id?: string | null; + [k: string]: unknown; + } + | { + event: "pane_closed"; + pane_id: string; + [k: string]: unknown; + } + | { + event: "pane_focused"; + pane_id: string; + [k: string]: unknown; + } + | { + event: "pane_moved"; + pane_id: string; + [k: string]: unknown; + } + | { + event: "pane_output_changed"; + min_revision?: number | null; + pane_id: string; + [k: string]: unknown; + } + | { + event: "pane_exited"; + pane_id: string; + [k: string]: unknown; + } + | { + agent?: string | null; + event: "pane_agent_detected"; + pane_id: string; + [k: string]: unknown; + } + | { + agent_status: AgentStatus; + event: "pane_agent_status_changed"; + pane_id: string; + [k: string]: unknown; + }; +export type IntegrationTarget = + | "pi" + | "omp" + | "claude" + | "codex" + | "copilot" + | "devin" + | "droid" + | "kimi" + | "opencode" + | "kilo" + | "hermes" + | "qodercli" + | "cursor" + | "mastracode" + | "grok"; +export type PopupSize = number | string; +export type PluginPanePlacement = "overlay" | "popup" | "split" | "tab" | "zoomed"; + +export interface PingParams { + [k: string]: unknown; +} +export interface EmptyParams { + [k: string]: unknown; +} +export interface ServerLiveHandoffParams { + expected_protocol?: number | null; + expected_version?: string | null; + import_exe?: string | null; + [k: string]: unknown; +} +export interface NotificationShowParams { + body?: string | null; + position?: ToastHerdrPosition | null; + sound?: NotificationShowSound; + title: string; + [k: string]: unknown; +} +export interface ClientWindowTitleSetParams { + title: string; + [k: string]: unknown; +} +export interface WorkspaceCreateParams { + cwd?: string | null; + env?: { + [k: string]: string; + }; + focus?: boolean; + label?: string | null; + [k: string]: unknown; +} +export interface WorkspaceTarget { + workspace_id: string; + [k: string]: unknown; +} +export interface WorkspaceRenameParams { + label: string; + workspace_id: string; + [k: string]: unknown; +} +export interface WorkspaceMoveParams { + insert_index: number; + workspace_id: string; + [k: string]: unknown; +} +export interface WorkspaceReportMetadataParams { + seq?: number | null; + source: string; + tokens: { + [k: string]: string | null; + }; + ttl_ms?: number | null; + workspace_id: string; + [k: string]: unknown; +} +export interface WorktreeListParams { + cwd?: string | null; + workspace_id?: string | null; + [k: string]: unknown; +} +export interface WorktreeCreateParams { + base?: string | null; + branch?: string | null; + cwd?: string | null; + focus?: boolean; + label?: string | null; + path?: string | null; + workspace_id?: string | null; + [k: string]: unknown; +} +export interface WorktreeOpenParams { + branch?: string | null; + cwd?: string | null; + focus?: boolean; + label?: string | null; + path?: string | null; + workspace_id?: string | null; + [k: string]: unknown; +} +export interface WorktreeRemoveParams { + force?: boolean; + workspace_id: string; + [k: string]: unknown; +} +export interface TabCreateParams { + cwd?: string | null; + env?: { + [k: string]: string; + }; + focus?: boolean; + label?: string | null; + workspace_id?: string | null; + [k: string]: unknown; +} +export interface TabListParams { + workspace_id?: string | null; + [k: string]: unknown; +} +export interface TabTarget { + tab_id: string; + [k: string]: unknown; +} +export interface TabRenameParams { + label: string; + tab_id: string; + [k: string]: unknown; +} +export interface TabMoveParams { + insert_index: number; + tab_id: string; + [k: string]: unknown; +} +export interface AgentTarget { + target: string; + [k: string]: unknown; +} +export interface AgentReadParams { + format?: "text" | "ansi"; + lines?: number | null; + source: ReadSource; + strip_ansi?: boolean; + target: string; + [k: string]: unknown; +} +export interface AgentSendKeysParams { + keys: string[]; + target: string; + [k: string]: unknown; +} +export interface AgentRenameParams { + name?: string | null; + target: string; + [k: string]: unknown; +} +export interface AgentViewSetParams { + filter?: AgentViewFilter | null; + label?: string | null; + sort?: AgentViewSort[]; + source: string; + [k: string]: unknown; +} +export interface AgentViewSort { + field: AgentViewSortField; + order?: "asc" | "desc"; + [k: string]: unknown; +} +export interface AgentViewClearParams { + source?: string | null; + [k: string]: unknown; +} +export interface AgentStartParams { + args?: string[]; + kind: string; + name: string; + pane_id: string; + /** + * Startup timeout in milliseconds. Values must be greater than 3000 and at most 300000. + */ + timeout_ms?: number | null; + [k: string]: unknown; +} +export interface AgentPromptParams { + target: string; + text: string; + wait?: AgentPromptWaitOptions | null; + [k: string]: unknown; +} +export interface AgentPromptWaitOptions { + timeout_ms?: number | null; + until?: AgentStatus[]; + [k: string]: unknown; +} +export interface AgentWaitParams { + target: string; + timeout_ms?: number | null; + until?: AgentStatus[]; + [k: string]: unknown; +} +export interface PaneSplitParams { + cwd?: string | null; + direction: SplitDirection; + env?: { + [k: string]: string; + }; + focus?: boolean; + ratio?: number | null; + target_pane_id?: string | null; + workspace_id?: string | null; + [k: string]: unknown; +} +export interface PaneSwapParams { + direction?: PaneDirection | null; + pane_id?: string | null; + source_pane_id?: string | null; + target_pane_id?: string | null; + [k: string]: unknown; +} +export interface PaneMoveParams { + destination: PaneMoveDestination; + focus?: boolean; + pane_id: string; + [k: string]: unknown; +} +export interface PaneZoomParams { + mode?: "toggle" | "on" | "off"; + pane_id?: string | null; + [k: string]: unknown; +} +export interface PaneLayoutParams { + pane_id?: string | null; + [k: string]: unknown; +} +export interface PaneProcessInfoParams { + pane_id?: string | null; + [k: string]: unknown; +} +export interface LayoutExportParams { + pane_id?: string | null; + tab_id?: string | null; + [k: string]: unknown; +} +export interface LayoutApplyParams { + focus?: boolean; + root: LayoutNode; + tab_id?: string | null; + tab_label?: string | null; + workspace_id?: string | null; + [k: string]: unknown; +} +export interface LayoutSetSplitRatioParams { + pane_id?: string | null; + path: boolean[]; + ratio: number; + tab_id?: string | null; + [k: string]: unknown; +} +export interface PaneNeighborParams { + direction: PaneDirection; + pane_id?: string | null; + [k: string]: unknown; +} +export interface PaneEdgesParams { + pane_id?: string | null; + [k: string]: unknown; +} +export interface PaneFocusDirectionParams { + direction: PaneDirection; + pane_id?: string | null; + [k: string]: unknown; +} +export interface PaneResizeParams { + amount?: number | null; + direction: PaneDirection; + pane_id?: string | null; + [k: string]: unknown; +} +export interface PaneListParams { + workspace_id?: string | null; + [k: string]: unknown; +} +export interface PaneCurrentParams { + caller_pane_id?: string | null; + [k: string]: unknown; +} +export interface PaneTarget { + pane_id: string; + [k: string]: unknown; +} +export interface PaneRenameParams { + label?: string | null; + pane_id: string; + [k: string]: unknown; +} +export interface PaneSendTextParams { + pane_id: string; + text: string; + [k: string]: unknown; +} +export interface PaneSendKeysParams { + keys: string[]; + pane_id: string; + [k: string]: unknown; +} +export interface PaneSendInputParams { + keys?: string[]; + pane_id: string; + text?: string; + [k: string]: unknown; +} +export interface PaneReadParams { + format?: "text" | "ansi"; + lines?: number | null; + pane_id: string; + source: ReadSource; + strip_ansi?: boolean; + [k: string]: unknown; +} +export interface PaneGraphicsSetParams { + data_base64?: string; + format: PaneGraphicsFormat; + image_height: number; + image_width: number; + pane_id: string; + placement?: PaneGraphicsPlacementParams; + [k: string]: unknown; +} +export interface PaneGraphicsPlacementParams { + grid_cols?: number; + grid_rows?: number; + viewport_col?: number; + viewport_row?: number; + [k: string]: unknown; +} +export interface PaneGraphicsClearParams { + pane_id: string; + [k: string]: unknown; +} +export interface PaneReportAgentParams { + agent: string; + agent_session_id?: string | null; + agent_session_path?: string | null; + message?: string | null; + pane_id: string; + seq?: number | null; + source: string; + state: PaneAgentState; + [k: string]: unknown; +} +export interface PaneReportAgentSessionParams { + agent: string; + agent_session_id?: string | null; + agent_session_path?: string | null; + pane_id: string; + seq?: number | null; + session_start_source?: string | null; + source: string; + [k: string]: unknown; +} +export interface PaneReportMetadataParams { + agent?: string | null; + applies_to_source?: string | null; + clear_display_agent?: boolean; + clear_state_labels?: boolean; + clear_title?: boolean; + display_agent?: string | null; + pane_id: string; + seq?: number | null; + source: string; + state_labels?: { + [k: string]: string; + }; + title?: string | null; + tokens?: { + [k: string]: string | null; + }; + ttl_ms?: number | null; + [k: string]: unknown; +} +export interface PaneClearAgentAuthorityParams { + pane_id: string; + seq?: number | null; + source?: string | null; + [k: string]: unknown; +} +export interface PaneReleaseAgentParams { + agent: string; + pane_id: string; + seq?: number | null; + source: string; + [k: string]: unknown; +} +export interface EventsSubscribeParams { + subscriptions: Subscription[]; + [k: string]: unknown; +} +export interface EventsWaitParams { + match_event: EventMatch; + timeout_ms?: number | null; + [k: string]: unknown; +} +export interface PaneWaitForOutputParams { + lines?: number | null; + match: OutputMatch; + pane_id: string; + source: ReadSource; + strip_ansi?: boolean; + timeout_ms?: number | null; + [k: string]: unknown; +} +export interface IntegrationInstallParams { + target: IntegrationTarget; + [k: string]: unknown; +} +export interface IntegrationUninstallParams { + target: IntegrationTarget; + [k: string]: unknown; +} +export interface PluginLinkParams { + enabled?: boolean; + path: string; + source?: PluginSourceInfo | null; + [k: string]: unknown; +} +export interface PluginSourceInfo { + installed_unix_ms?: number | null; + kind?: "local" | "github"; + managed_path?: string | null; + owner?: string | null; + repo?: string | null; + requested_ref?: string | null; + resolved_commit?: string | null; + subdir?: string | null; + [k: string]: unknown; +} +export interface PluginListParams { + plugin_id?: string | null; + [k: string]: unknown; +} +export interface PluginUnlinkParams { + plugin_id: string; + [k: string]: unknown; +} +export interface PluginSetEnabledParams { + plugin_id: string; + [k: string]: unknown; +} +export interface PluginActionListParams { + plugin_id?: string | null; + [k: string]: unknown; +} +export interface PluginActionInvokeParams { + action_id: string; + context?: PluginInvocationContext | null; + plugin_id?: string | null; + [k: string]: unknown; +} +export interface PluginInvocationContext { + clicked_url?: string | null; + correlation_id?: string | null; + focused_pane_agent?: string | null; + focused_pane_cwd?: string | null; + focused_pane_id?: string | null; + focused_pane_status?: AgentStatus | null; + invocation_source?: string | null; + link_handler_id?: string | null; + selected_text?: string | null; + tab_id?: string | null; + tab_label?: string | null; + workspace_cwd?: string | null; + workspace_id?: string | null; + workspace_label?: string | null; + worktree?: WorkspaceWorktreeInfo | null; + [k: string]: unknown; +} +export interface WorkspaceWorktreeInfo { + checkout_path: string; + is_linked_worktree: boolean; + repo_key: string; + repo_name: string; + repo_root: string; + [k: string]: unknown; +} +export interface PluginLogListParams { + limit?: number | null; + plugin_id?: string | null; + [k: string]: unknown; +} +export interface PluginPaneOpenParams { + cwd?: string | null; + direction?: SplitDirection | null; + entrypoint: string; + env?: { + [k: string]: string; + }; + focus?: boolean; + height?: PopupSize | null; + placement?: PluginPanePlacement | null; + plugin_id: string; + target_pane_id?: string | null; + width?: PopupSize | null; + workspace_id?: string | null; + [k: string]: unknown; +} +export interface PluginPaneFocusParams { + pane_id: string; + [k: string]: unknown; +} +export interface PluginPaneCloseParams { + pane_id: string; + [k: string]: unknown; +} diff --git a/config/pi/agent/extensions/pi-herdr/generated/success-response.ts b/config/pi/agent/extensions/pi-herdr/generated/success-response.ts new file mode 100644 index 0000000..634f876 --- /dev/null +++ b/config/pi/agent/extensions/pi-herdr/generated/success-response.ts @@ -0,0 +1,1001 @@ +/* eslint-disable */ +/** + * Generated from Herdr protocol 18, schema version 1. + * Run `npm run generate` after updating Herdr. Do not edit by hand. + */ + +export type ResponseResult = + | { + capabilities?: ServerCapabilities | null; + protocol: number; + type: "pong"; + version: string; + [k: string]: unknown; + } + | { + snapshot: SessionSnapshot; + type: "session_snapshot"; + [k: string]: unknown; + } + | { + type: "workspace_info"; + workspace: WorkspaceInfo; + [k: string]: unknown; + } + | { + root_pane: PaneInfo; + tab: TabInfo; + type: "workspace_created"; + workspace: WorkspaceInfo; + [k: string]: unknown; + } + | { + type: "workspace_list"; + workspaces: WorkspaceInfo[]; + [k: string]: unknown; + } + | { + source: WorktreeSourceInfo; + type: "worktree_list"; + worktrees: WorktreeInfo[]; + [k: string]: unknown; + } + | { + root_pane: PaneInfo; + tab: TabInfo; + type: "worktree_created"; + workspace: WorkspaceInfo; + worktree: WorktreeInfo; + [k: string]: unknown; + } + | { + already_open: boolean; + root_pane: PaneInfo; + tab: TabInfo; + type: "worktree_opened"; + workspace: WorkspaceInfo; + worktree: WorktreeInfo; + [k: string]: unknown; + } + | { + forced: boolean; + path: string; + type: "worktree_removed"; + workspace_id: string; + [k: string]: unknown; + } + | { + tab: TabInfo; + type: "tab_info"; + [k: string]: unknown; + } + | { + root_pane: PaneInfo; + tab: TabInfo; + type: "tab_created"; + [k: string]: unknown; + } + | { + tabs: TabInfo[]; + type: "tab_list"; + [k: string]: unknown; + } + | { + agent: AgentInfo; + type: "agent_info"; + [k: string]: unknown; + } + | { + agent: AgentInfo; + argv: string[]; + type: "agent_started"; + [k: string]: unknown; + } + | { + agent: AgentInfo; + type: "agent_prompted"; + [k: string]: unknown; + } + | { + agents: AgentInfo[]; + type: "agent_list"; + [k: string]: unknown; + } + | { + active: boolean; + label?: string | null; + source?: string | null; + type: "agent_view"; + [k: string]: unknown; + } + | { + pane: PaneInfo; + type: "pane_info"; + [k: string]: unknown; + } + | { + panes: PaneInfo[]; + type: "pane_list"; + [k: string]: unknown; + } + | { + pane: PaneInfo; + type: "pane_current"; + [k: string]: unknown; + } + | { + swap: PaneSwapResult; + type: "pane_swap"; + [k: string]: unknown; + } + | { + move_result: PaneMoveResult; + type: "pane_move"; + [k: string]: unknown; + } + | { + type: "pane_zoom"; + zoom: PaneZoomResult; + [k: string]: unknown; + } + | { + layout: PaneLayoutSnapshot; + type: "pane_layout"; + [k: string]: unknown; + } + | { + process_info: PaneProcessInfo; + type: "pane_process_info"; + [k: string]: unknown; + } + | { + layout: LayoutDescription; + type: "layout_export"; + [k: string]: unknown; + } + | { + layout: LayoutDescription; + type: "layout_apply"; + [k: string]: unknown; + } + | { + layout: LayoutDescription; + type: "layout_split_ratio_set"; + [k: string]: unknown; + } + | { + neighbor: PaneNeighborResult; + type: "pane_neighbor"; + [k: string]: unknown; + } + | { + edges: PaneEdgesResult; + type: "pane_edges"; + [k: string]: unknown; + } + | { + focus: PaneFocusDirectionResult; + type: "pane_focus_direction"; + [k: string]: unknown; + } + | { + resize: PaneResizeResult; + type: "pane_resize"; + [k: string]: unknown; + } + | { + read: PaneReadResult; + type: "pane_read"; + [k: string]: unknown; + } + | { + cell_height_px: number; + cell_width_px: number; + type: "pane_graphics_info"; + [k: string]: unknown; + } + | { + explain: unknown; + type: "agent_explain"; + [k: string]: unknown; + } + | { + type: "subscription_started"; + [k: string]: unknown; + } + | { + event: EventEnvelope; + type: "wait_matched"; + [k: string]: unknown; + } + | { + matched_line?: string | null; + pane_id: string; + read: PaneReadResult; + revision: number; + type: "output_matched"; + [k: string]: unknown; + } + | { + reason: NotificationShowReason; + shown: boolean; + type: "notification_show"; + [k: string]: unknown; + } + | { + changed: boolean; + reason: ClientWindowTitleReason; + type: "client_window_title"; + [k: string]: unknown; + } + | { + details: IntegrationInstallResult; + target: IntegrationTarget; + type: "integration_install"; + [k: string]: unknown; + } + | { + details: IntegrationUninstallResult; + target: IntegrationTarget; + type: "integration_uninstall"; + [k: string]: unknown; + } + | { + manifests: AgentManifestInfo[]; + type: "agent_manifest_reload"; + [k: string]: unknown; + } + | { + last_check_unix?: number | null; + last_result?: string | null; + manifests: AgentManifestInfo[]; + type: "agent_manifest_status"; + [k: string]: unknown; + } + | { + plugin: InstalledPluginInfo; + type: "plugin_linked"; + [k: string]: unknown; + } + | { + plugins: InstalledPluginInfo[]; + type: "plugin_list"; + [k: string]: unknown; + } + | { + plugin_id: string; + removed: boolean; + type: "plugin_unlinked"; + [k: string]: unknown; + } + | { + plugin: InstalledPluginInfo; + type: "plugin_enabled"; + [k: string]: unknown; + } + | { + plugin: InstalledPluginInfo; + type: "plugin_disabled"; + [k: string]: unknown; + } + | { + actions: PluginActionInfo[]; + type: "plugin_action_list"; + [k: string]: unknown; + } + | { + action: PluginActionInfo; + context: PluginInvocationContext; + log: PluginCommandLogInfo; + type: "plugin_action_invoked"; + [k: string]: unknown; + } + | { + logs: PluginCommandLogInfo[]; + type: "plugin_log_list"; + [k: string]: unknown; + } + | { + plugin_pane: PluginPaneInfo; + type: "plugin_pane_opened"; + [k: string]: unknown; + } + | { + plugin_pane: PluginPaneInfo; + type: "plugin_pane_focused"; + [k: string]: unknown; + } + | { + pane_id: string; + type: "plugin_pane_closed"; + [k: string]: unknown; + } + | { + diagnostics: string[]; + status: ConfigReloadStatus; + type: "config_reload"; + [k: string]: unknown; + } + | { + type: "ok"; + [k: string]: unknown; + }; +export type AgentSessionRefKind = "id" | "path"; +export type AgentStatus = "idle" | "working" | "blocked" | "done" | "unknown"; +export type SplitDirection = "right" | "down"; +export type PaneSwapReason = "no_neighbor" | "same_pane" | "not_found" | "cross_tab"; +export type PaneMoveReason = "same_tab" | "zoomed_tab"; +export type PaneZoomReason = "single_pane" | "already_zoomed" | "already_unzoomed"; +export type LayoutNode = + | { + command?: string[] | null; + cwd?: string | null; + env?: { + [k: string]: string; + }; + label?: string | null; + pane_id?: string | null; + type: "pane"; + [k: string]: unknown; + } + | { + direction: SplitDirection; + first: LayoutNode; + ratio: number; + second: LayoutNode; + type: "split"; + [k: string]: unknown; + }; +export type PaneDirection = "left" | "right" | "up" | "down"; +export type PaneFocusDirectionReason = "no_neighbor"; +export type PaneResizeReason = "unchanged"; +export type ReadFormat = "text" | "ansi"; +export type ReadSource = "visible" | "recent" | "recent_unwrapped" | "detection"; +export type EventData = + | { + type: "workspace_created"; + workspace: WorkspaceInfo; + [k: string]: unknown; + } + | { + type: "workspace_updated"; + workspace: WorkspaceInfo; + [k: string]: unknown; + } + | { + type: "workspace_metadata_updated"; + workspace: WorkspaceInfo; + [k: string]: unknown; + } + | { + type: "workspace_closed"; + workspace?: WorkspaceInfo | null; + workspace_id: string; + [k: string]: unknown; + } + | { + label: string; + type: "workspace_renamed"; + workspace_id: string; + [k: string]: unknown; + } + | { + insert_index: number; + type: "workspace_moved"; + workspace_id: string; + workspaces: WorkspaceInfo[]; + [k: string]: unknown; + } + | { + type: "workspace_focused"; + workspace_id: string; + [k: string]: unknown; + } + | { + type: "worktree_created"; + workspace: WorkspaceInfo; + worktree: WorktreeInfo; + [k: string]: unknown; + } + | { + already_open: boolean; + type: "worktree_opened"; + workspace: WorkspaceInfo; + worktree: WorktreeInfo; + [k: string]: unknown; + } + | { + forced: boolean; + type: "worktree_removed"; + workspace?: WorkspaceInfo | null; + workspace_id: string; + worktree: WorktreeInfo; + [k: string]: unknown; + } + | { + tab: TabInfo; + type: "tab_created"; + [k: string]: unknown; + } + | { + tab_id: string; + type: "tab_closed"; + workspace_id: string; + [k: string]: unknown; + } + | { + label: string; + tab_id: string; + type: "tab_renamed"; + workspace_id: string; + [k: string]: unknown; + } + | { + insert_index: number; + tab_id: string; + tabs: TabInfo[]; + type: "tab_moved"; + workspace_id: string; + [k: string]: unknown; + } + | { + tab_id: string; + type: "tab_focused"; + workspace_id: string; + [k: string]: unknown; + } + | { + pane: PaneInfo; + type: "pane_created"; + [k: string]: unknown; + } + | { + pane_id: string; + type: "pane_closed"; + workspace_id: string; + [k: string]: unknown; + } + | { + pane: PaneInfo; + type: "pane_updated"; + [k: string]: unknown; + } + | { + pane_id: string; + type: "pane_focused"; + workspace_id: string; + [k: string]: unknown; + } + | { + closed_tab_id?: string | null; + closed_workspace_id?: string | null; + created_tab?: TabInfo | null; + created_workspace?: WorkspaceInfo | null; + pane: PaneInfo; + previous_pane_id: string; + previous_tab_id: string; + previous_workspace_id: string; + type: "pane_moved"; + [k: string]: unknown; + } + | { + pane_id: string; + revision: number; + type: "pane_output_changed"; + workspace_id: string; + [k: string]: unknown; + } + | { + pane_id: string; + type: "pane_exited"; + workspace_id: string; + [k: string]: unknown; + } + | { + agent?: string | null; + final_status?: AgentStatus | null; + pane_id: string; + released?: boolean; + type: "pane_agent_detected"; + workspace_id: string; + [k: string]: unknown; + } + | { + agent?: string | null; + agent_status: AgentStatus; + display_agent?: string | null; + pane_id: string; + state_labels?: { + [k: string]: string; + }; + title?: string | null; + type: "pane_agent_status_changed"; + workspace_id: string; + [k: string]: unknown; + } + | { + layout: PaneLayoutSnapshot; + type: "layout_updated"; + [k: string]: unknown; + }; +export type EventKind = + | "workspace_created" + | "workspace_updated" + | "workspace_metadata_updated" + | "workspace_closed" + | "workspace_renamed" + | "workspace_moved" + | "workspace_focused" + | "worktree_created" + | "worktree_opened" + | "worktree_removed" + | "tab_created" + | "tab_closed" + | "tab_renamed" + | "tab_moved" + | "tab_focused" + | "pane_created" + | "pane_closed" + | "pane_updated" + | "pane_focused" + | "pane_moved" + | "pane_output_changed" + | "pane_exited" + | "pane_agent_detected" + | "pane_agent_status_changed" + | "layout_updated"; +export type NotificationShowReason = "shown" | "disabled" | "rate_limited" | "no_foreground_client" | "busy"; +export type ClientWindowTitleReason = "set" | "cleared" | "no_foreground_client"; +export type IntegrationTarget = + | "pi" + | "omp" + | "claude" + | "codex" + | "copilot" + | "devin" + | "droid" + | "kimi" + | "opencode" + | "kilo" + | "hermes" + | "qodercli" + | "cursor" + | "mastracode" + | "grok"; +export type PluginActionContext = "global" | "workspace" | "tab" | "pane" | "selection"; +export type PluginPlatform = "linux" | "macos" | "windows"; +export type PopupSize = number | string; +export type PluginCommandStatus = "running" | "succeeded" | "failed"; +export type ConfigReloadStatus = "applied" | "partial" | "failed"; + +export interface SuccessResponse { + id: string; + result: ResponseResult; + [k: string]: unknown; +} +export interface ServerCapabilities { + detached_server_daemon?: boolean; + live_handoff: boolean; + [k: string]: unknown; +} +export interface SessionSnapshot { + agents: AgentInfo[]; + focused_pane_id?: string | null; + focused_tab_id?: string | null; + focused_workspace_id?: string | null; + layouts: PaneLayoutSnapshot[]; + panes: PaneInfo[]; + protocol: number; + tabs: TabInfo[]; + version: string; + workspaces: WorkspaceInfo[]; + [k: string]: unknown; +} +export interface AgentInfo { + agent?: string | null; + agent_session?: AgentSessionInfo | null; + agent_status: AgentStatus; + cwd?: string | null; + display_agent?: string | null; + focused: boolean; + foreground_cwd?: string | null; + interactive_ready?: boolean; + launch_pending?: boolean; + name?: string | null; + pane_id: string; + revision: number; + screen_detection_skipped?: boolean; + state_change_seq?: number; + state_labels?: { + [k: string]: string; + }; + tab_id: string; + terminal_id: string; + terminal_title?: string | null; + terminal_title_stripped?: string | null; + title?: string | null; + tokens?: { + [k: string]: string; + }; + workspace_id: string; + [k: string]: unknown; +} +export interface AgentSessionInfo { + agent: string; + kind: AgentSessionRefKind; + source: string; + value: string; + [k: string]: unknown; +} +export interface PaneLayoutSnapshot { + area: PaneLayoutRect; + focused_pane_id: string; + panes: PaneLayoutPane[]; + splits: PaneLayoutSplit[]; + tab_id: string; + workspace_id: string; + zoomed: boolean; + [k: string]: unknown; +} +export interface PaneLayoutRect { + height: number; + width: number; + x: number; + y: number; + [k: string]: unknown; +} +export interface PaneLayoutPane { + focused: boolean; + pane_id: string; + rect: PaneLayoutRect; + [k: string]: unknown; +} +export interface PaneLayoutSplit { + direction: SplitDirection; + id: string; + ratio: number; + rect: PaneLayoutRect; + [k: string]: unknown; +} +export interface PaneInfo { + agent?: string | null; + agent_session?: AgentSessionInfo | null; + agent_status: AgentStatus; + cwd?: string | null; + display_agent?: string | null; + focused: boolean; + foreground_cwd?: string | null; + label?: string | null; + pane_id: string; + revision: number; + scroll?: PaneScrollInfo | null; + state_labels?: { + [k: string]: string; + }; + tab_id: string; + terminal_id: string; + terminal_title?: string | null; + terminal_title_stripped?: string | null; + title?: string | null; + tokens?: { + [k: string]: string; + }; + workspace_id: string; + [k: string]: unknown; +} +export interface PaneScrollInfo { + max_offset_from_bottom: number; + offset_from_bottom: number; + viewport_rows: number; + [k: string]: unknown; +} +export interface TabInfo { + agent_status: AgentStatus; + focused: boolean; + label: string; + number: number; + pane_count: number; + tab_id: string; + workspace_id: string; + [k: string]: unknown; +} +export interface WorkspaceInfo { + active_tab_id: string; + agent_status: AgentStatus; + focused: boolean; + label: string; + number: number; + pane_count: number; + tab_count: number; + tokens?: { + [k: string]: string; + }; + workspace_id: string; + worktree?: WorkspaceWorktreeInfo | null; + [k: string]: unknown; +} +export interface WorkspaceWorktreeInfo { + checkout_path: string; + is_linked_worktree: boolean; + repo_key: string; + repo_name: string; + repo_root: string; + [k: string]: unknown; +} +export interface WorktreeSourceInfo { + repo_key: string; + repo_name: string; + repo_root: string; + source_checkout_path: string; + source_workspace_id?: string | null; + [k: string]: unknown; +} +export interface WorktreeInfo { + branch?: string | null; + is_bare: boolean; + is_detached: boolean; + is_linked_worktree: boolean; + is_prunable: boolean; + label: string; + open_workspace_id?: string | null; + path: string; + [k: string]: unknown; +} +export interface PaneSwapResult { + changed: boolean; + focused_pane_id: string; + layout: PaneLayoutSnapshot; + reason?: PaneSwapReason | null; + source_pane_id: string; + target_pane_id?: string | null; + [k: string]: unknown; +} +export interface PaneMoveResult { + changed: boolean; + closed_tab_id?: string | null; + closed_workspace_id?: string | null; + created_tab?: TabInfo | null; + created_workspace?: WorkspaceInfo | null; + focused_pane_id: string; + pane: PaneInfo; + previous_pane_id: string; + previous_tab_id: string; + previous_workspace_id: string; + reason?: PaneMoveReason | null; + source_layout?: PaneLayoutSnapshot | null; + target_layout: PaneLayoutSnapshot; + [k: string]: unknown; +} +export interface PaneZoomResult { + changed: boolean; + focus_changed: boolean; + focused_pane_id: string; + layout: PaneLayoutSnapshot; + pane_id: string; + reason?: PaneZoomReason | null; + zoom_changed: boolean; + zoomed: boolean; + [k: string]: unknown; +} +export interface PaneProcessInfo { + foreground_process_group_id?: number | null; + foreground_processes?: PaneProcessInfoProcess[]; + pane_id: string; + shell_pid?: number | null; + tty?: string | null; + [k: string]: unknown; +} +export interface PaneProcessInfoProcess { + argv?: string[] | null; + argv0?: string | null; + cmdline?: string | null; + cwd?: string | null; + name: string; + pid: number; + [k: string]: unknown; +} +export interface LayoutDescription { + focused_pane_id: string; + root: LayoutNode; + tab_id: string; + workspace_id: string; + zoomed: boolean; + [k: string]: unknown; +} +export interface PaneNeighborResult { + direction: PaneDirection; + layout: PaneLayoutSnapshot; + neighbor_pane_id?: string | null; + pane_id: string; + [k: string]: unknown; +} +export interface PaneEdgesResult { + down: boolean; + layout: PaneLayoutSnapshot; + left: boolean; + pane_id: string; + right: boolean; + up: boolean; + [k: string]: unknown; +} +export interface PaneFocusDirectionResult { + changed: boolean; + focused_pane_id?: string | null; + layout: PaneLayoutSnapshot; + reason?: PaneFocusDirectionReason | null; + source_pane_id: string; + [k: string]: unknown; +} +export interface PaneResizeResult { + changed: boolean; + focused_pane_id: string; + layout: PaneLayoutSnapshot; + pane_id: string; + reason?: PaneResizeReason | null; + [k: string]: unknown; +} +export interface PaneReadResult { + format: ReadFormat; + pane_id: string; + revision: number; + source: ReadSource; + tab_id: string; + text: string; + truncated: boolean; + workspace_id: string; + [k: string]: unknown; +} +export interface EventEnvelope { + data: EventData; + event: EventKind; + [k: string]: unknown; +} +export interface IntegrationInstallResult { + messages: string[]; + [k: string]: unknown; +} +export interface IntegrationUninstallResult { + messages: string[]; + [k: string]: unknown; +} +export interface AgentManifestInfo { + active_version?: string | null; + agent: string; + cached_remote_version?: string | null; + local_override_shadowing_remote: boolean; + remote_last_checked_unix?: number | null; + remote_update_error?: string | null; + remote_update_result?: string | null; + source: string; + source_kind: string; + warning?: string | null; + [k: string]: unknown; +} +export interface InstalledPluginInfo { + actions?: PluginManifestAction[]; + build?: PluginManifestBuild[]; + description?: string | null; + enabled: boolean; + events?: PluginManifestEventHook[]; + link_handlers?: PluginManifestLinkHandler[]; + manifest_path: string; + min_herdr_version?: string; + name: string; + panes?: PluginManifestPane[]; + platforms?: PluginPlatform[] | null; + plugin_id: string; + plugin_root: string; + source?: PluginSourceInfo; + startup?: PluginManifestStartup[]; + version: string; + /** + * Warnings collected at link time or on registry load (e.g. unknown event names, + * missing manifest file). Non-fatal — the entry is kept and surfaced by plugin.list. + */ + warnings?: string[]; + [k: string]: unknown; +} +export interface PluginManifestAction { + command: string[]; + contexts?: PluginActionContext[]; + description?: string | null; + id: string; + platforms?: PluginPlatform[] | null; + title: string; + [k: string]: unknown; +} +export interface PluginManifestBuild { + command: string[]; + platforms?: PluginPlatform[] | null; + [k: string]: unknown; +} +export interface PluginManifestEventHook { + command: string[]; + on: string; + platforms?: PluginPlatform[] | null; + [k: string]: unknown; +} +export interface PluginManifestLinkHandler { + action: string; + id: string; + pattern: string; + platforms?: PluginPlatform[] | null; + title: string; + [k: string]: unknown; +} +export interface PluginManifestPane { + command: string[]; + description?: string | null; + height?: PopupSize | null; + id: string; + placement?: "overlay" | "popup" | "split" | "tab" | "zoomed"; + platforms?: PluginPlatform[] | null; + title: string; + width?: PopupSize | null; + [k: string]: unknown; +} +export interface PluginSourceInfo { + installed_unix_ms?: number | null; + kind?: "local" | "github"; + managed_path?: string | null; + owner?: string | null; + repo?: string | null; + requested_ref?: string | null; + resolved_commit?: string | null; + subdir?: string | null; + [k: string]: unknown; +} +export interface PluginManifestStartup { + command: string[]; + platforms?: PluginPlatform[] | null; + [k: string]: unknown; +} +export interface PluginActionInfo { + action_id: string; + command: string[]; + contexts?: PluginActionContext[]; + description?: string | null; + platforms?: PluginPlatform[] | null; + plugin_id: string; + title: string; + [k: string]: unknown; +} +export interface PluginInvocationContext { + clicked_url?: string | null; + correlation_id?: string | null; + focused_pane_agent?: string | null; + focused_pane_cwd?: string | null; + focused_pane_id?: string | null; + focused_pane_status?: AgentStatus | null; + invocation_source?: string | null; + link_handler_id?: string | null; + selected_text?: string | null; + tab_id?: string | null; + tab_label?: string | null; + workspace_cwd?: string | null; + workspace_id?: string | null; + workspace_label?: string | null; + worktree?: WorkspaceWorktreeInfo | null; + [k: string]: unknown; +} +export interface PluginCommandLogInfo { + action_id?: string | null; + command: string[]; + error?: string | null; + event?: string | null; + exit_code?: number | null; + finished_unix_ms?: number | null; + log_id: string; + plugin_id: string; + started_unix_ms: number; + status: PluginCommandStatus; + stderr?: string | null; + stdout?: string | null; + [k: string]: unknown; +} +export interface PluginPaneInfo { + entrypoint: string; + pane: PaneInfo; + plugin_id: string; + [k: string]: unknown; +} diff --git a/config/pi/agent/extensions/pi-herdr.ts b/config/pi/agent/extensions/pi-herdr/index.ts similarity index 72% rename from config/pi/agent/extensions/pi-herdr.ts rename to config/pi/agent/extensions/pi-herdr/index.ts index 84ab27d..1fc95dc 100644 --- a/config/pi/agent/extensions/pi-herdr.ts +++ b/config/pi/agent/extensions/pi-herdr/index.ts @@ -2,79 +2,26 @@ import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-a import { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, truncateTail } from "@earendil-works/pi-coding-agent"; import { StringEnum } from "@earendil-works/pi-ai"; import { Text } from "@earendil-works/pi-tui"; -import { Type } from "@sinclair/typebox"; - -type AgentStatus = "idle" | "working" | "blocked" | "done" | "unknown"; -type ReadSource = "visible" | "recent" | "recent-unwrapped"; - -interface WorkspaceInfo { - workspace_id: string; - number: number; - label: string; - focused: boolean; - pane_count: number; - tab_count: number; - active_tab_id: string; - agent_status: AgentStatus; -} +import { Type } from "typebox"; +import { homedir } from "node:os"; +import { resolve } from "node:path"; -interface TabInfo { - tab_id: string; - workspace_id: string; - number: number; - label: string; - focused: boolean; - pane_count: number; - agent_status: AgentStatus; -} +import { expectResult, HerdrClient } from "./client.ts"; +import type { + AgentStatus, + PaneInfo, + TabInfo, + WorkspaceInfo, + WorktreeInfo, +} from "./generated/success-response.ts"; -interface PaneInfo { - pane_id: string; - workspace_id: string; - tab_id: string; - focused: boolean; - cwd?: string; - agent?: string; - agent_status: AgentStatus; - revision: number; -} - -interface PaneReadResult { - pane_id: string; - workspace_id: string; - tab_id: string; - source: "visible" | "recent" | "recent_unwrapped"; - text: string; - revision: number; - truncated: boolean; -} - -interface WorktreeInfo { - branch?: string; - path: string; - label?: string; - open_workspace_id?: string; - is_bare?: boolean; - is_detached?: boolean; - is_linked_worktree?: boolean; - is_prunable?: boolean; - [key: string]: unknown; -} +type ToolReadSource = "visible" | "recent" | "recent-unwrapped"; interface ManagedPane { paneId: string; workspaceId: string; } -interface HerdrJsonEnvelope { - id?: string; - result?: any; - error?: { - code?: string; - message?: string; - }; -} - interface HerdrToolDetails { action?: string; aliases: Record; @@ -125,11 +72,13 @@ const WaitModeEnum = StringEnum(["all", "any"] as const, { export default function (pi: ExtensionAPI) { const herdrEnv = process.env.HERDR_ENV; + const socketPath = process.env.HERDR_SOCKET_PATH; const currentPaneTargetEnv = process.env.HERDR_PANE_ID; - if (!herdrEnv || !currentPaneTargetEnv) { + if (herdrEnv !== "1" || !socketPath || !currentPaneTargetEnv) { return; } const currentPaneTarget = currentPaneTargetEnv; + const herdr = new HerdrClient(socketPath); const managedPanes = new Map(); const aliasOrder: string[] = []; @@ -193,17 +142,6 @@ export default function (pi: ExtensionAPI) { if (index !== -1) aliasOrder.splice(index, 1); } - function parseHerdrError(output: string): string | null { - const trimmed = output.trim(); - if (!trimmed) return null; - try { - const value = JSON.parse(trimmed) as HerdrJsonEnvelope; - return value.error?.message || value.error?.code || trimmed; - } catch { - return trimmed; - } - } - function isAbortError(error: unknown, signal?: AbortSignal): boolean { return signal?.aborted === true || (error instanceof Error && error.message === "Aborted"); } @@ -223,42 +161,15 @@ export default function (pi: ExtensionAPI) { }); } - async function execHerdr(args: string[], signal?: AbortSignal) { - const result = await pi.exec("herdr", args, { signal }); - if (signal?.aborted || result.killed) { - throw new Error("Aborted"); - } - if (result.code !== 0) { - const message = - parseHerdrError(result.stderr) || - parseHerdrError(result.stdout) || - `herdr ${args.join(" ")} failed with exit code ${result.code}`; - throw new Error(message); - } - return result; + function absolutePath(value: string | undefined, cwd: string): string | undefined { + if (!value) return undefined; + if (value === "~") return homedir(); + if (value.startsWith("~/")) return resolve(homedir(), value.slice(2)); + return resolve(cwd, value); } - async function execHerdrJson(args: string[], signal?: AbortSignal): Promise { - const result = await execHerdr(args, signal); - const stdout = result.stdout.trim(); - if (!stdout) { - throw new Error(`Expected JSON output from herdr ${args.join(" ")}`); - } - let value: HerdrJsonEnvelope; - try { - value = JSON.parse(stdout) as HerdrJsonEnvelope; - } catch { - throw new Error(`Failed to parse JSON from herdr ${args.join(" ")}`); - } - if (value.error) { - throw new Error(value.error.message || value.error.code || `herdr ${args.join(" ")} failed`); - } - return value as T; - } - - async function execHerdrText(args: string[], signal?: AbortSignal): Promise { - const result = await execHerdr(args, signal); - return result.stdout; + function protocolReadSource(source: ToolReadSource | undefined): "visible" | "recent" | "recent_unwrapped" { + return source === "recent-unwrapped" ? "recent_unwrapped" : source ?? "recent"; } function shellQuote(value: string): string { @@ -288,51 +199,49 @@ export default function (pi: ExtensionAPI) { async function enterPiNetnsInPane(paneId: string, signal?: AbortSignal): Promise { const namespace = selectedPiNetns(); if (!namespace) return null; - await execHerdr(["pane", "run", paneId, buildEnterPiNetnsCommand(namespace)], signal); + expectResult( + await herdr.call( + "pane.send_input", + { pane_id: paneId, text: buildEnterPiNetnsCommand(namespace), keys: ["Enter"] }, + { signal }, + ), + "ok", + ); await sleep(800, signal); return namespace; } async function getCurrentPaneInfo(signal?: AbortSignal): Promise { - const response = await execHerdrJson<{ result: { pane: PaneInfo } }>(["pane", "get", currentPaneTarget], signal); - return response.result.pane; - } - - async function getWorkspaceInfo(workspaceId: string, signal?: AbortSignal): Promise { - const response = await execHerdrJson<{ result: { workspace: WorkspaceInfo } }>([ - "workspace", - "get", - workspaceId, - ], signal); - return response.result.workspace; + return expectResult( + await herdr.call("pane.get", { pane_id: currentPaneTarget }, { signal }), + "pane_info", + ).pane; } async function getWorkspaceList(signal?: AbortSignal): Promise { - const response = await execHerdrJson<{ result: { workspaces: WorkspaceInfo[] } }>(["workspace", "list"], signal); - return response.result.workspaces || []; + return expectResult(await herdr.call("workspace.list", {}, { signal }), "workspace_list").workspaces; } async function getWorkspacePanes(workspaceId: string, signal?: AbortSignal): Promise { - const response = await execHerdrJson<{ result: { panes: PaneInfo[] } }>([ - "pane", - "list", - "--workspace", - workspaceId, - ], signal); - return response.result.panes || []; + return expectResult( + await herdr.call("pane.list", { workspace_id: workspaceId }, { signal }), + "pane_list", + ).panes; } async function getTabList(workspaceId?: string, signal?: AbortSignal): Promise { - const args = ["tab", "list"]; - if (workspaceId) args.push("--workspace", workspaceId); - const response = await execHerdrJson<{ result: { tabs: TabInfo[] } }>(args, signal); - return response.result.tabs || []; + return expectResult( + await herdr.call("tab.list", { workspace_id: workspaceId }, { signal }), + "tab_list", + ).tabs; } async function getPaneInfo(paneId: string, signal?: AbortSignal): Promise { try { - const response = await execHerdrJson<{ result: { pane: PaneInfo } }>(["pane", "get", paneId], signal); - return response.result.pane; + return expectResult( + await herdr.call("pane.get", { pane_id: paneId }, { signal }), + "pane_info", + ).pane; } catch (error) { if (isAbortError(error, signal)) throw error; return null; @@ -390,14 +299,24 @@ export default function (pi: ExtensionAPI) { async function readPane( paneId: string, - options: { source?: ReadSource; lines?: number; raw?: boolean }, + options: { source?: ToolReadSource; lines?: number; raw?: boolean }, signal?: AbortSignal, ): Promise { - const args = ["pane", "read", paneId]; - if (options.source) args.push("--source", options.source); - if (options.lines != null) args.push("--lines", String(options.lines)); - if (options.raw) args.push("--raw"); - return execHerdrText(args, signal); + const result = expectResult( + await herdr.call( + "pane.read", + { + pane_id: paneId, + source: protocolReadSource(options.source), + lines: options.lines, + format: options.raw ? "ansi" : "text", + strip_ansi: options.raw !== true, + }, + { signal }, + ), + "pane_read", + ); + return result.read.text; } function formatReadOutput(output: string): string { @@ -475,23 +394,6 @@ export default function (pi: ExtensionAPI) { } } - function sleepWithSignal(ms: number, signal: AbortSignal | undefined) { - if (!signal) return new Promise((resolve) => setTimeout(resolve, ms)); - if (signal.aborted) return Promise.reject(new Error("wait_agent canceled.")); - return new Promise((resolve, reject) => { - const timer = setTimeout(() => { - signal.removeEventListener("abort", onAbort); - resolve(); - }, ms); - const onAbort = () => { - clearTimeout(timer); - signal.removeEventListener("abort", onAbort); - reject(new Error("wait_agent canceled.")); - }; - signal.addEventListener("abort", onAbort, { once: true }); - }); - } - function statusDot(theme: any, status: AgentStatus): string { switch (status) { case "blocked": @@ -511,14 +413,17 @@ export default function (pi: ExtensionAPI) { name: "herdr", label: "herdr", description: - "Herdr-native pane orchestration for long-running workflows. " + - "Actions: list panes, manage workspaces, Git worktrees, and tabs, split existing panes, submit lines atomically in existing panes, read output, watch readiness, wait for one or more agent panes to reach target statuses, send raw text or keys, focus contexts, and stop panes.", + "Herdr-native pane and dedicated-tab orchestration for long-running workflows. " + + "Actions: list panes, manage workspaces, Git worktrees, and tabs, split panes in dedicated work tabs, submit lines atomically, read output, watch readiness, wait for one or more agent panes to reach target statuses, send raw text or keys, focus contexts, and stop panes.", promptGuidelines: [ "Use `herdr` run for long-running processes in other panes instead of `bash`.", + "Keep the tab containing Pi dedicated to the interactive Pi session. For tests, builds, servers, watchers, or other background work in the current project, first use `tab_create` with a descriptive label and a friendly `pane` alias for its root pane, then run work there.", + "Group related processes in one dedicated work tab. If that workflow needs more panes, use `pane_split` on the root pane alias or another pane in that work tab; never split a pane in Pi's own tab.", + "Use a new workspace instead of a tab when the work needs a separate Git worktree or broader isolation.", "When you want to submit a line or prompt to a pane, prefer `run` over `send` + `Enter` so text and Enter happen atomically.", "Use `send` only for low-level literal text or key injection when you do not want command-style submission semantics.", - "Preserve the current UI focus by default. Do not change workspace or tab focus unless the user explicitly asks or the workflow truly requires visible interaction there.", - "Pane actions like run, read, watch, wait_agent, send, and stop must target pane aliases or pane ids, not tab ids. For pane_split, omit pane to split the agent's own pane, or pass a pane alias/id to split that explicit source pane.", + "Preserve the current UI focus by default. Create work tabs and panes with focus disabled unless the user explicitly asks to view them or the workflow truly requires visible interaction there.", + "Pane actions like run, read, watch, wait_agent, send, and stop must target pane aliases or pane ids, not tab ids. `pane_split` requires a source pane in a dedicated work tab.", "Use `herdr` workspace, worktree, tab, and pane_split actions to organize parallel work instead of piling everything into one pane stack.", "Use `worktree_create` to create a Git worktree checkout and open it as a Herdr workspace.", "Use `worktree_remove` to delete a Herdr-managed worktree checkout; it runs git worktree remove and does not delete the branch.", @@ -527,14 +432,14 @@ export default function (pi: ExtensionAPI) { "For agent panes, background finished panes usually become `done` while focused finished panes usually become `idle`.", "Use `recent-unwrapped` when you need log matching or reads that ignore soft wrapping.", "Pane references can be either friendly aliases you created earlier or real herdr pane ids from `list`.", - "Use `pane_split`, `tab_create`, or `workspace_create` to establish new pane targets. `pane_split` defaults to the agent's own pane when pane is omitted and splits right when direction is omitted. `run` only works with an existing pane alias or pane id.", + "Use `tab_create` with `pane` set to a friendly root-pane alias as the default way to establish a target for current-project background work. `pane_split` requires an existing pane alias/id outside Pi's tab and defaults its direction to right. `run` only works with an existing pane alias or pane id.", "When PI_NETNS_SELECTED is set, newly split panes automatically enter that network namespace before later commands are run in them.", "Use friendly pane aliases like `server`, `reviewer`, or `tests` so later reads, watches, and sends can reuse them across the session.", "When starting a fresh pi instance in another pane and the model matters, either specify `--model` explicitly or ask the user which model/provider they want.", ], parameters: Type.Object({ action: ActionEnum, - pane: Type.Optional(Type.String({ description: "Friendly pane alias or explicit pane id. For pane_split, omit to split the agent's own pane." })), + pane: Type.Optional(Type.String({ description: "Friendly pane alias or explicit pane id. For tab/workspace/worktree creation, an alias to assign to the new root pane. For pane_split, a required source pane outside Pi's tab." })), panes: Type.Optional(Type.Array(Type.String(), { description: "Pane aliases or pane ids for multi-pane waits" })), workspace: Type.Optional(Type.String({ description: "Workspace id for workspace, worktree, or tab actions" })), tab: Type.Optional(Type.String({ description: "Tab id for tab actions or focus(tab) only. Pane actions must use pane ids or aliases." })), @@ -565,7 +470,8 @@ export default function (pi: ExtensionAPI) { force: Type.Optional(Type.Boolean({ description: "Force worktree_remove when Git refuses a dirty checkout" })), }), - async execute(_toolCallId, params, signal, onUpdate, _ctx) { + async execute(_toolCallId, params, signal, onUpdate, ctx) { + const requestCwd = ctx.cwd; const currentPane = await getCurrentPaneInfo(signal); const currentPaneId = currentPane.pane_id; const currentWorkspaceId = currentPane.workspace_id; @@ -606,16 +512,16 @@ export default function (pi: ExtensionAPI) { } case "workspace_create": { - const args = ["workspace", "create"]; - if (params.cwd) args.push("--cwd", params.cwd); - if (params.label) args.push("--label", params.label); - if (params.focus !== true) args.push("--no-focus"); - const response = await execHerdrJson<{ - result: { workspace: WorkspaceInfo; root_pane?: PaneInfo }; - }>(args, signal); - const workspace = response.result.workspace; - const rootPane = - response.result.root_pane ?? (await getWorkspacePanes(workspace.workspace_id, signal))[0] ?? null; + const created = expectResult( + await herdr.call( + "workspace.create", + { cwd: absolutePath(params.cwd, requestCwd), label: params.label, focus: params.focus === true }, + { signal }, + ), + "workspace_created", + ); + const workspace = created.workspace; + const rootPane = created.root_pane; if (params.pane && rootPane) { recordAlias(params.pane, rootPane.pane_id, workspace.workspace_id); } @@ -638,86 +544,105 @@ export default function (pi: ExtensionAPI) { case "workspace_focus": { const workspaceId = params.workspace; if (!workspaceId) throw new Error("'workspace' is required for workspace_focus"); - const response = await execHerdrJson<{ result: { workspace: WorkspaceInfo } }>([ - "workspace", - "focus", - workspaceId, - ], signal); + const workspace = expectResult( + await herdr.call("workspace.focus", { workspace_id: workspaceId }, { signal }), + "workspace_info", + ).workspace; return { - content: [{ type: "text", text: `Focused workspace '${response.result.workspace.label}'` }], - details: withSnapshot({ action: "workspace_focus", workspace: response.result.workspace }), + content: [{ type: "text", text: `Focused workspace '${workspace.label}'` }], + details: withSnapshot({ action: "workspace_focus", workspace }), }; } case "worktree_list": { - const args = ["worktree", "list"]; - if (params.workspace) args.push("--workspace", params.workspace); - else if (params.cwd) args.push("--cwd", params.cwd); - const response = await execHerdrJson<{ result: { worktrees: WorktreeInfo[]; source?: Record } }>(args, signal); - const worktrees = response.result.worktrees || []; + const result = expectResult( + await herdr.call( + "worktree.list", + { workspace_id: params.workspace, cwd: params.workspace ? undefined : absolutePath(params.cwd, requestCwd) }, + { signal }, + ), + "worktree_list", + ); + const worktrees = result.worktrees; const text = worktrees.length ? worktrees.map(summarizeWorktree).join("\n") : "No worktrees."; return { content: [{ type: "text", text }], - details: withSnapshot({ action: "worktree_list", worktrees, source: response.result.source }), + details: withSnapshot({ action: "worktree_list", worktrees, source: result.source }), }; } case "worktree_create": { - const args = ["worktree", "create"]; - if (params.workspace) args.push("--workspace", params.workspace); - else if (params.cwd) args.push("--cwd", params.cwd); - if (params.branch) args.push("--branch", params.branch); - if (params.base) args.push("--base", params.base); - if (params.path) args.push("--path", params.path); - if (params.label) args.push("--label", params.label); - if (params.focus !== true) args.push("--no-focus"); - const response = await execHerdrJson<{ result: { workspace?: WorkspaceInfo; worktree?: WorktreeInfo; root_pane?: PaneInfo; [key: string]: unknown } }>(args, signal); - const workspace = response.result.workspace; - const worktree = response.result.worktree; - const rootPane = response.result.root_pane; + const created = expectResult( + await herdr.call( + "worktree.create", + { + workspace_id: params.workspace, + cwd: params.workspace ? undefined : absolutePath(params.cwd, requestCwd), + branch: params.branch, + base: params.base, + path: absolutePath(params.path, requestCwd), + label: params.label, + focus: params.focus === true, + }, + { signal }, + ), + "worktree_created", + ); + const { workspace, worktree, root_pane: rootPane } = created; if (params.pane && rootPane && workspace) recordAlias(params.pane, rootPane.pane_id, workspace.workspace_id); const label = worktree?.branch || params.branch || worktree?.path || params.path || workspace?.label || "worktree"; const workspaceText = workspace ? `, workspace ${workspace.workspace_id}` : ""; const aliasText = params.pane && rootPane ? `, root pane aliased as '${params.pane}'` : ""; return { content: [{ type: "text", text: `Created worktree '${label}'${workspaceText}${aliasText}` }], - details: withSnapshot({ action: "worktree_create", ...response.result, pane: params.pane }), + details: withSnapshot({ action: "worktree_create", ...created, pane: params.pane }), }; } case "worktree_open": { - const args = ["worktree", "open"]; - if (params.workspace) args.push("--workspace", params.workspace); - else if (params.cwd) args.push("--cwd", params.cwd); - if (params.path) args.push("--path", params.path); - else if (params.branch) args.push("--branch", params.branch); - else throw new Error("'path' or 'branch' is required for worktree_open"); - if (params.label) args.push("--label", params.label); - if (params.focus !== true) args.push("--no-focus"); - const response = await execHerdrJson<{ result: { workspace?: WorkspaceInfo; worktree?: WorktreeInfo; root_pane?: PaneInfo; [key: string]: unknown } }>(args, signal); - const workspace = response.result.workspace; - const rootPane = response.result.root_pane; + if (!params.path && !params.branch) throw new Error("'path' or 'branch' is required for worktree_open"); + const opened = expectResult( + await herdr.call( + "worktree.open", + { + workspace_id: params.workspace, + cwd: params.workspace ? undefined : absolutePath(params.cwd, requestCwd), + path: absolutePath(params.path, requestCwd), + branch: params.branch, + label: params.label, + focus: params.focus === true, + }, + { signal }, + ), + "worktree_opened", + ); + const { workspace, root_pane: rootPane } = opened; if (params.pane && rootPane && workspace) recordAlias(params.pane, rootPane.pane_id, workspace.workspace_id); - const label = response.result.worktree?.branch || params.branch || response.result.worktree?.path || params.path || workspace?.label || "worktree"; + const label = opened.worktree.branch || params.branch || opened.worktree.path || params.path || workspace.label || "worktree"; const workspaceText = workspace ? `, workspace ${workspace.workspace_id}` : ""; return { content: [{ type: "text", text: `Opened worktree '${label}'${workspaceText}` }], - details: withSnapshot({ action: "worktree_open", ...response.result, pane: params.pane }), + details: withSnapshot({ action: "worktree_open", ...opened, pane: params.pane }), }; } case "worktree_remove": { const workspaceId = params.workspace; if (!workspaceId) throw new Error("'workspace' is required for worktree_remove"); - const args = ["worktree", "remove", "--workspace", workspaceId]; - if (params.force) args.push("--force"); - const response = await execHerdrJson<{ result: Record }>(args, signal); + const removed = expectResult( + await herdr.call( + "worktree.remove", + { workspace_id: workspaceId, force: params.force === true }, + { signal }, + ), + "worktree_removed", + ); for (const [alias, managed] of [...managedPanes.entries()]) { if (managed.workspaceId === workspaceId) forgetAlias(alias); } return { content: [{ type: "text", text: `Removed worktree workspace ${workspaceId}; branch was not deleted.` }], - details: withSnapshot({ action: "worktree_remove", workspaceId, ...response.result }), + details: withSnapshot({ action: "worktree_remove", workspaceId, ...removed }), }; } @@ -733,16 +658,20 @@ export default function (pi: ExtensionAPI) { case "tab_create": { const workspaceId = params.workspace ?? currentWorkspaceId; - const args = ["tab", "create", "--workspace", workspaceId]; - if (params.cwd) args.push("--cwd", params.cwd); - if (params.label) args.push("--label", params.label); - if (params.focus !== true) args.push("--no-focus"); - const response = await execHerdrJson<{ result: { tab: TabInfo; root_pane?: PaneInfo } }>(args, signal); - const tab = response.result.tab; - const rootPane = - response.result.root_pane ?? - (await getWorkspacePanes(tab.workspace_id, signal)).find((pane) => pane.tab_id === tab.tab_id) ?? - null; + const created = expectResult( + await herdr.call( + "tab.create", + { + workspace_id: workspaceId, + cwd: absolutePath(params.cwd, requestCwd), + label: params.label, + focus: params.focus === true, + }, + { signal }, + ), + "tab_created", + ); + const { tab, root_pane: rootPane } = created; if (params.pane && rootPane) { recordAlias(params.pane, rootPane.pane_id, tab.workspace_id); } @@ -762,41 +691,46 @@ export default function (pi: ExtensionAPI) { case "tab_focus": { const tabId = params.tab; if (!tabId) throw new Error("'tab' is required for tab_focus"); - const response = await execHerdrJson<{ result: { tab: TabInfo } }>(["tab", "focus", tabId], signal); + const tab = expectResult( + await herdr.call("tab.focus", { tab_id: tabId }, { signal }), + "tab_info", + ).tab; return { - content: [{ type: "text", text: `Focused tab '${response.result.tab.label}'` }], - details: withSnapshot({ action: "tab_focus", tab: response.result.tab }), + content: [{ type: "text", text: `Focused tab '${tab.label}'` }], + details: withSnapshot({ action: "tab_focus", tab }), }; } case "focus": { if (params.tab) { - const response = await execHerdrJson<{ result: { tab: TabInfo } }>(["tab", "focus", params.tab], signal); + const tab = expectResult( + await herdr.call("tab.focus", { tab_id: params.tab }, { signal }), + "tab_info", + ).tab; return { - content: [{ type: "text", text: `Focused tab '${response.result.tab.label}'` }], - details: withSnapshot({ action: "focus", target: "tab", tab: response.result.tab }), + content: [{ type: "text", text: `Focused tab '${tab.label}'` }], + details: withSnapshot({ action: "focus", target: "tab", tab }), }; } if (params.workspace) { - const response = await execHerdrJson<{ result: { workspace: WorkspaceInfo } }>([ - "workspace", - "focus", - params.workspace, - ], signal); + const workspace = expectResult( + await herdr.call("workspace.focus", { workspace_id: params.workspace }, { signal }), + "workspace_info", + ).workspace; return { - content: [{ type: "text", text: `Focused workspace '${response.result.workspace.label}'` }], - details: withSnapshot({ action: "focus", target: "workspace", workspace: response.result.workspace }), + content: [{ type: "text", text: `Focused workspace '${workspace.label}'` }], + details: withSnapshot({ action: "focus", target: "workspace", workspace }), }; } if (params.pane) { const resolved = await requirePaneRef(params.pane, currentWorkspaceId, signal); - const response = await execHerdrJson<{ result: { tab: TabInfo } }>(["tab", "focus", resolved.pane.tab_id], signal); + const pane = expectResult( + await herdr.call("pane.focus", { pane_id: resolved.pane.pane_id }, { signal }), + "pane_info", + ).pane; return { - content: [{ - type: "text", - text: `Focused tab '${response.result.tab.label}' for pane '${resolved.pane.pane_id}'. Herdr does not expose direct pane focus yet.`, - }], - details: withSnapshot({ action: "focus", target: "pane", paneId: resolved.pane.pane_id, tab: response.result.tab }), + content: [{ type: "text", text: `Focused pane '${pane.pane_id}'` }], + details: withSnapshot({ action: "focus", target: "pane", paneId: pane.pane_id }), }; } throw new Error("'workspace', 'tab', or 'pane' is required for focus"); @@ -804,16 +738,33 @@ export default function (pi: ExtensionAPI) { case "pane_split": { rejectUnexpectedParams("pane_split", params, ["workspace", "tab"]); - const paneRef = params.pane ?? currentPaneId; + const paneRef = params.pane; + if (!paneRef) { + throw new Error( + "'pane' is required for pane_split. Create a dedicated work tab first with tab_create and assign its root pane an alias.", + ); + } const direction = params.direction ?? "right"; const sourcePane = await requirePaneRef(paneRef, currentWorkspaceId, signal); - const args = ["pane", "split", sourcePane.pane.pane_id, "--direction", direction]; - if (params.cwd) args.push("--cwd", params.cwd); - if (params.focus !== true) args.push("--no-focus"); - - const response = await execHerdrJson<{ result: { pane: PaneInfo } }>(args, signal); - const splitPane = response.result.pane; + if (sourcePane.pane.tab_id === currentPane.tab_id) { + throw new Error( + "Refusing to split a pane in Pi's tab. Create a dedicated work tab with tab_create, then split its root pane alias.", + ); + } + const splitPane = expectResult( + await herdr.call( + "pane.split", + { + target_pane_id: sourcePane.pane.pane_id, + direction, + cwd: absolutePath(params.cwd, requestCwd), + focus: params.focus === true, + }, + { signal }, + ), + "pane_info", + ).pane; if (params.newPane) { recordAlias(params.newPane, splitPane.pane_id, splitPane.workspace_id); } @@ -848,7 +799,14 @@ export default function (pi: ExtensionAPI) { if (!command) throw new Error("'command' is required for run"); const targetPane = await requirePaneRef(paneRef, currentWorkspaceId, signal); - await execHerdr(["pane", "run", targetPane.pane.pane_id, command], signal); + expectResult( + await herdr.call( + "pane.send_input", + { pane_id: targetPane.pane.pane_id, text: command, keys: ["Enter"] }, + { signal }, + ), + "ok", + ); await sleep(800, signal); const initialOutput = await readPane( @@ -935,32 +893,34 @@ export default function (pi: ExtensionAPI) { const updateTimer = onUpdate ? setInterval(publishWatchUpdate, 1000) : null; try { - const args = ["wait", "output", resolved.pane.pane_id, "--match", match]; - if (params.source) args.push("--source", params.source); - if (params.lines != null) args.push("--lines", String(params.lines)); - if (params.timeout != null) args.push("--timeout", String(params.timeout)); - if (params.regex) args.push("--regex"); - if (params.raw) args.push("--raw"); - - const response = await execHerdrJson<{ - result: { - type: string; - pane_id: string; - revision: number; - matched_line: string; - read: PaneReadResult; - }; - }>(args, signal); - const matched = response.result; - const text = matched.read?.text ? formatReadOutput(matched.read.text) : matched.matched_line; + const matched = expectResult( + await herdr.call( + "pane.wait_for_output", + { + pane_id: resolved.pane.pane_id, + source: protocolReadSource(params.source), + lines: params.lines, + match: { type: params.regex ? "regex" : "substring", value: match }, + timeout_ms: params.timeout, + strip_ansi: params.raw !== true, + }, + { + signal, + timeoutMs: params.timeout != null ? params.timeout + 5_000 : undefined, + }, + ), + "output_matched", + ); + const matchedLine = matched.matched_line ?? match; + const text = matched.read.text ? formatReadOutput(matched.read.text) : matchedLine; return { - content: [{ type: "text", text: `Matched: ${matched.matched_line}\n\n${text}` }], + content: [{ type: "text", text: `Matched: ${matchedLine}\n\n${text}` }], details: withSnapshot({ action: "watch", pane: paneLabel, paneId: resolved.pane.pane_id, - matchedLine: matched.matched_line, + matchedLine, elapsed: Math.floor((Date.now() - startTime) / 1000), }), }; @@ -988,42 +948,45 @@ export default function (pi: ExtensionAPI) { }); } - const deadline = params.timeout != null ? Date.now() + params.timeout : null; - let snapshot: Array<{ - pane: string; - paneId: string; - status: AgentStatus; - agent?: string; - }> = []; + const controllers = resolvedPanes.map(() => new AbortController()); + const abortWaits = () => controllers.forEach((controller) => controller.abort()); + signal?.addEventListener("abort", abortWaits, { once: true }); + try { + const waits = resolvedPanes.map((resolved, index) => + herdr + .call( + "agent.wait", + { + target: resolved.pane.pane_id, + until: statuses, + timeout_ms: params.timeout, + }, + { + signal: controllers[index]?.signal, + timeoutMs: params.timeout != null ? params.timeout + 5_000 : undefined, + }, + ) + .then((result) => expectResult(result, "agent_info")), + ); + if (mode === "all") await Promise.all(waits); + else await Promise.any(waits); + } finally { + signal?.removeEventListener("abort", abortWaits); + abortWaits(); + } - while (true) { - throwIfAborted(signal, "wait_agent"); - snapshot = []; - for (const resolved of resolvedPanes) { - throwIfAborted(signal, "wait_agent"); + const snapshot = await Promise.all( + resolvedPanes.map(async (resolved) => { const pane = await getPaneInfo(resolved.pane.pane_id, signal); if (!pane) throw new Error(`Pane '${resolved.aliasOrRef}' no longer exists.`); - snapshot.push({ + return { pane: resolved.aliasOrRef, paneId: pane.pane_id, status: pane.agent_status, agent: pane.agent, - }); - } - - const satisfied = - mode === "all" - ? snapshot.every((item) => statuses.includes(item.status)) - : snapshot.some((item) => statuses.includes(item.status)); - if (satisfied) break; - if (deadline != null && Date.now() >= deadline) { - throw new Error( - `Timed out waiting for panes [${snapshot.map((item) => item.pane).join(", ")}] to reach ${mode} of statuses '${formatStatusList(statuses)}'. Last statuses: ${snapshot.map((item) => `${item.pane}=${item.status}`).join(", ")}`, - ); - } - await sleepWithSignal(250, signal); - } - + }; + }), + ); const summary = snapshot.map((item) => `${item.pane}=${item.status}`).join(", "); return { content: [{ @@ -1053,11 +1016,21 @@ export default function (pi: ExtensionAPI) { const resolved = await requirePaneRef(paneRef, currentWorkspaceId, signal); if (params.text) { - await execHerdr(["pane", "send-text", resolved.pane.pane_id, params.text], signal); + expectResult( + await herdr.call( + "pane.send_text", + { pane_id: resolved.pane.pane_id, text: params.text }, + { signal }, + ), + "ok", + ); } if (params.keys) { const keys = params.keys.split(/\s+/).filter(Boolean); - await execHerdr(["pane", "send-keys", resolved.pane.pane_id, ...keys], signal); + expectResult( + await herdr.call("pane.send_keys", { pane_id: resolved.pane.pane_id, keys }, { signal }), + "ok", + ); } const desc = [params.text && `"${params.text}"`, params.keys].filter(Boolean).join(" + "); @@ -1083,7 +1056,10 @@ export default function (pi: ExtensionAPI) { throw new Error("Refusing to close the pane pi is running in."); } - await execHerdr(["pane", "close", resolved.pane.pane_id], signal); + expectResult( + await herdr.call("pane.close", { pane_id: resolved.pane.pane_id }, { signal }), + "ok", + ); if (resolved.alias) forgetAlias(resolved.alias); return { diff --git a/config/pi/agent/extensions/pi-herdr/package-lock.json b/config/pi/agent/extensions/pi-herdr/package-lock.json new file mode 100644 index 0000000..4ec9fd3 --- /dev/null +++ b/config/pi/agent/extensions/pi-herdr/package-lock.json @@ -0,0 +1,3531 @@ +{ + "name": "pi-herdr", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "pi-herdr", + "version": "0.1.0", + "devDependencies": { + "@earendil-works/pi-ai": "0.81.1", + "@earendil-works/pi-coding-agent": "0.81.1", + "@earendil-works/pi-tui": "0.81.1", + "@types/node": "24.12.0", + "json-schema-to-typescript": "15.0.4", + "typebox": "1.1.38", + "typescript": "5.9.3" + }, + "peerDependencies": { + "@earendil-works/pi-ai": "*", + "@earendil-works/pi-coding-agent": "*", + "@earendil-works/pi-tui": "*", + "typebox": "*" + } + }, + "node_modules/@anthropic-ai/sdk": { + "version": "0.91.1", + "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.91.1.tgz", + "integrity": "sha512-LAmu761tSN9r66ixvmciswUj/ZC+1Q4iAfpedTfSVLeswRwnY3n2Nb6Tsk+cLPP28aLOPWeMgIuTuCcMC6W/iw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-schema-to-ts": "^3.1.1" + }, + "bin": { + "anthropic-ai-sdk": "bin/cli" + }, + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0" + }, + "peerDependenciesMeta": { + "zod": { + "optional": true + } + } + }, + "node_modules/@apidevtools/json-schema-ref-parser": { + "version": "11.9.3", + "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-11.9.3.tgz", + "integrity": "sha512-60vepv88RwcJtSHrD6MjIL6Ta3SOYbgfnkHb+ppAVK+o9mXprRtulx7VlRl3lN3bbvysAfCS7WMVfhUYemB0IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jsdevtools/ono": "^7.1.3", + "@types/json-schema": "^7.0.15", + "js-yaml": "^4.1.0" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/philsturgeon" + } + }, + "node_modules/@aws-crypto/sha256-browser": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz", + "integrity": "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-js": "^5.2.0", + "@aws-crypto/supports-web-crypto": "^5.2.0", + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-locate-window": "^3.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-crypto/sha256-js": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz", + "integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-crypto/supports-web-crypto": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz", + "integrity": "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-crypto/util": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-5.2.0.tgz", + "integrity": "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.222.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime": { + "version": "3.1048.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-bedrock-runtime/-/client-bedrock-runtime-3.1048.0.tgz", + "integrity": "sha512-u+NT61JZEkRFtpL0CAw1N1dwxnaLgwVXQl/zjJxTGgLyS/jTIdg2SdoEoCTHxgDyCnqa1HEi9QOoE9/pYRNpOQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "^3.974.11", + "@aws-sdk/credential-provider-node": "^3.972.42", + "@aws-sdk/eventstream-handler-node": "^3.972.16", + "@aws-sdk/middleware-eventstream": "^3.972.12", + "@aws-sdk/middleware-websocket": "^3.972.19", + "@aws-sdk/token-providers": "3.1048.0", + "@aws-sdk/types": "^3.973.8", + "@smithy/core": "^3.24.2", + "@smithy/fetch-http-handler": "^5.4.2", + "@smithy/node-http-handler": "^4.7.2", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/core": { + "version": "3.977.1", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.977.1.tgz", + "integrity": "sha512-KVtQRtc00ES/y+Sc3vYXeP6pCIcNlBJCZOwvqSy8ZpVGmbM5+IG+AfhuTKQ2oXmIVqZJewaGMMpzPkywC6xg0w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.974.2", + "@aws-sdk/xml-builder": "^3.972.37", + "@aws/lambda-invoke-store": "^0.3.0", + "@smithy/core": "^3.29.8", + "@smithy/signature-v4": "^5.6.9", + "@smithy/types": "^4.16.1", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-env": { + "version": "3.972.61", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.61.tgz", + "integrity": "sha512-qihs2ekMb89Nxd2JenCgVFhjbkb3EIo7HEBCBzyZACKVJdrLUZBLOmAE3xr0Sayml8n/jZSzwO/IufIiIzO7PQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.0", + "@aws-sdk/types": "^3.974.2", + "@smithy/core": "^3.29.8", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http": { + "version": "3.972.63", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.63.tgz", + "integrity": "sha512-yfozsS8wkWZEi/n6IsrodcFKBWZ0iNAezhJbTReMNc0z1Px17qdeAeuL1/wziCAmCZyXiW7QzP75ggJkBQv8jQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.0", + "@aws-sdk/types": "^3.974.2", + "@smithy/core": "^3.29.8", + "@smithy/fetch-http-handler": "^5.6.10", + "@smithy/node-http-handler": "^4.9.10", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/node-http-handler": { + "version": "4.9.11", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.9.11.tgz", + "integrity": "sha512-slbzbz8taEOzoXv/9y34YNBoE+ZHmddLykCgjDAjvMAsu2nM5s2Gzwa5OGF721tD8s+CKeFUBds5lSj9lcbuDg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.30.0", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.973.6", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.973.6.tgz", + "integrity": "sha512-jGLTW1bj148GL/6/IMlfY2fMYS9FtHOG+NahkFD4y0qkzYudNUahelxryY68/HGMslYuHClk1XaS/3b3eJzEkg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.0", + "@aws-sdk/credential-provider-env": "^3.972.61", + "@aws-sdk/credential-provider-http": "^3.972.63", + "@aws-sdk/credential-provider-login": "^3.972.68", + "@aws-sdk/credential-provider-process": "^3.972.61", + "@aws-sdk/credential-provider-sso": "^3.973.5", + "@aws-sdk/credential-provider-web-identity": "^3.972.67", + "@aws-sdk/nested-clients": "^3.997.35", + "@aws-sdk/types": "^3.974.2", + "@smithy/core": "^3.29.8", + "@smithy/credential-provider-imds": "^4.4.13", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-login": { + "version": "3.972.68", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.68.tgz", + "integrity": "sha512-w6tNci6g7RqFpLhj1f5xseBvaNojb4Pkgp5Jp5apl9hrJtaf2AA+rX9+qlhlWUK6kcyAFYPA7emO+55zj+S98Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.0", + "@aws-sdk/nested-clients": "^3.997.35", + "@aws-sdk/types": "^3.974.2", + "@smithy/core": "^3.29.8", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-node": { + "version": "3.972.72", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.72.tgz", + "integrity": "sha512-blQ7F5QGzylnzeh5549zQLoCAiMHkXFLjFovEMaVy4b2X8JhUu+u9NXro1hyK95YHdVFNmBHKs2hIHtZchxKlQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/credential-provider-env": "^3.972.61", + "@aws-sdk/credential-provider-http": "^3.972.63", + "@aws-sdk/credential-provider-ini": "^3.973.6", + "@aws-sdk/credential-provider-process": "^3.972.61", + "@aws-sdk/credential-provider-sso": "^3.973.5", + "@aws-sdk/credential-provider-web-identity": "^3.972.67", + "@aws-sdk/types": "^3.974.2", + "@smithy/core": "^3.29.8", + "@smithy/credential-provider-imds": "^4.4.13", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-process": { + "version": "3.972.61", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.61.tgz", + "integrity": "sha512-xzRuj+fUVO4nkafKQJVKAF97kGpeQbfjuwmRrtGZNf42/1dkmcz6o7dswBy7alY0htQn5sCL1GWQYEykviWZkA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.0", + "@aws-sdk/types": "^3.974.2", + "@smithy/core": "^3.29.8", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.973.5", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.973.5.tgz", + "integrity": "sha512-fZRjjWhLFelsDoOYjqShQTrIGYC3Pf9Mx9Czf+1ikfQDgktxjze33dVo1q1/ZQ+T0qbtejVoHNHrfD5aJVpv/w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.0", + "@aws-sdk/nested-clients": "^3.997.35", + "@aws-sdk/token-providers": "3.1095.0", + "@aws-sdk/types": "^3.974.2", + "@smithy/core": "^3.29.8", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-sso/node_modules/@aws-sdk/token-providers": { + "version": "3.1095.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.1095.0.tgz", + "integrity": "sha512-65SudS6y4nzaYHybtqcpm3sHe5jLhdMn68HRKS1nUx690BtQeaAQOoujQ+dpOjBATIVGVgKKjEP8tR+U06QJQA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.0", + "@aws-sdk/nested-clients": "^3.997.35", + "@aws-sdk/types": "^3.974.2", + "@smithy/core": "^3.29.8", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.972.67", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.67.tgz", + "integrity": "sha512-FTNZ05gkPBA6CKbU3N4zPgybV+stdazwMOya75CmGdcJL7p8Fw/BdHP8WVxJd0mvzyPK2cg/C3gli58Ir4HgCw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.0", + "@aws-sdk/nested-clients": "^3.997.35", + "@aws-sdk/types": "^3.974.2", + "@smithy/core": "^3.29.8", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/eventstream-handler-node": { + "version": "3.972.30", + "resolved": "https://registry.npmjs.org/@aws-sdk/eventstream-handler-node/-/eventstream-handler-node-3.972.30.tgz", + "integrity": "sha512-hJboPgIpq5+ADc++/B9TBqn65CXV21cZLGB8V5RBQbxkZ/rQ6qMfcxTnW/SvQlasX4jhaSG8B1wsVjhQyDrsnQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.974.2", + "@smithy/core": "^3.29.8", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/middleware-eventstream": { + "version": "3.972.25", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-eventstream/-/middleware-eventstream-3.972.25.tgz", + "integrity": "sha512-9SFbPzJDHHR5k6Q6KvXVas/veUm/TzNcNTFM2UhdXHZHpyIvI2lS+s4cxljw1BihGpVhsAkQDo/2nW7dHxpf4Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.974.2", + "@smithy/core": "^3.29.8", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/middleware-websocket": { + "version": "3.972.43", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-websocket/-/middleware-websocket-3.972.43.tgz", + "integrity": "sha512-n29++15Vma64Kd0enp9Bo8a6LTm8TvUoMbJEwqXtIksv0oEs+SUCRMm3gozDfPD1Ly0k/sSBughxarlLlRF6Xw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.0", + "@aws-sdk/types": "^3.974.2", + "@smithy/core": "^3.29.8", + "@smithy/fetch-http-handler": "^5.6.10", + "@smithy/signature-v4": "^5.6.9", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients": { + "version": "3.997.35", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.997.35.tgz", + "integrity": "sha512-2MJfseVG/aXvIyOIBlYA/Oaf6qFDdsu4D8RKsEUdOQpVuLaor0BdxIBBtJLBNQQEe6Ku3YMvLljwb1MwVUpzRw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.0", + "@aws-sdk/signature-v4-multi-region": "^3.996.42", + "@aws-sdk/types": "^3.974.2", + "@smithy/core": "^3.29.8", + "@smithy/fetch-http-handler": "^5.6.10", + "@smithy/node-http-handler": "^4.9.10", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/node-http-handler": { + "version": "4.9.11", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.9.11.tgz", + "integrity": "sha512-slbzbz8taEOzoXv/9y34YNBoE+ZHmddLykCgjDAjvMAsu2nM5s2Gzwa5OGF721tD8s+CKeFUBds5lSj9lcbuDg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.30.0", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/signature-v4-multi-region": { + "version": "3.996.42", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.996.42.tgz", + "integrity": "sha512-DBV4naZP6HYBlAvPpoQzOP12Wvfou/5rN8yJPXjBTBylU5qwCbh/tXr2MddHoIjgoRkEl/eS+IljiUqvmwey1Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.974.2", + "@smithy/signature-v4": "^5.6.9", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/token-providers": { + "version": "3.1048.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.1048.0.tgz", + "integrity": "sha512-k0y/GcuesuSfWyUM0WamrGyeZmltRYaPbHO82UDA6mZ/doB+FOHKutikPAtSXMn/hDz970cF+iRuuiYO9VEbAA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.11", + "@aws-sdk/nested-clients": "^3.997.9", + "@aws-sdk/types": "^3.973.8", + "@smithy/core": "^3.24.2", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/types": { + "version": "3.974.2", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.974.2.tgz", + "integrity": "sha512-3W6IUtSxFbH6X7Wb7DzGCV5QiFQsd0g8bOfntpmDxQlzBoKWUMBu/JPQR0DwkE+Hpnxd6db1tXbOwdeHddG6cA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/util-locate-window": { + "version": "3.965.8", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.965.8.tgz", + "integrity": "sha512-uUbMs1cBZPafD0ohUj6EwNf0fPZ534NvBxHox4hjX+0Rxq5paSYUem7+hi833pYrzrcnBATKIYpR02MDXT5M9g==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/xml-builder": { + "version": "3.972.37", + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.37.tgz", + "integrity": "sha512-zKq4HQum8JwDyEuyfuI4bbiAcU0KxP6qy+9PR/IsR92IyE/DaBAikzAS50tjxip4bqIIANpCcG+Yyj6CVhXupg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws/lambda-invoke-store": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@aws/lambda-invoke-store/-/lambda-invoke-store-0.3.0.tgz", + "integrity": "sha512-sl4Bm6yiMNYrZKkqqDFWN0UfnWhlS8ivKxrYl+6t0gCLrqr8y3B2IqZZbFRkfaVVp7C/baApyh71P+LeE1A2sQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", + "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@earendil-works/pi-ai": { + "version": "0.81.1", + "resolved": "https://registry.npmjs.org/@earendil-works/pi-ai/-/pi-ai-0.81.1.tgz", + "integrity": "sha512-hzHE7Z8l5mgJk+ke67Lge0rwS2+wbKJrFKl9o5M1R1rh33+cCT7D1AHz1OAtX5wFs90E1/BTGhyJRTUHaMxGvQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@anthropic-ai/sdk": "0.91.1", + "@aws-sdk/client-bedrock-runtime": "3.1048.0", + "@google/genai": "1.52.0", + "@mistralai/mistralai": "2.2.6", + "@opentelemetry/api": "1.9.0", + "@smithy/node-http-handler": "4.7.3", + "http-proxy-agent": "7.0.2", + "https-proxy-agent": "7.0.6", + "openai": "6.26.0", + "partial-json": "0.1.7", + "typebox": "1.1.38" + }, + "bin": { + "pi-ai": "dist/cli.js" + }, + "engines": { + "node": ">=22.19.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent": { + "version": "0.81.1", + "resolved": "https://registry.npmjs.org/@earendil-works/pi-coding-agent/-/pi-coding-agent-0.81.1.tgz", + "integrity": "sha512-r6ovAsZOgAqbC/aU6s+/dPnv/sGZBuWyZNvi3pXjpbuX5wvp3XvGkQI7/VLvX2o9XpmpFaPUxKNym1WfkN/P8A==", + "dev": true, + "hasShrinkwrap": true, + "license": "MIT", + "dependencies": { + "@earendil-works/pi-agent-core": "^0.81.1", + "@earendil-works/pi-ai": "^0.81.1", + "@earendil-works/pi-tui": "^0.81.1", + "@silvia-odwyer/photon-node": "0.3.4", + "chalk": "5.6.2", + "cross-spawn": "7.0.6", + "diff": "8.0.4", + "glob": "13.0.6", + "highlight.js": "10.7.3", + "hosted-git-info": "9.0.3", + "ignore": "7.0.5", + "jiti": "2.7.0", + "minimatch": "10.2.5", + "proper-lockfile": "4.1.2", + "semver": "7.8.0", + "typebox": "1.1.38", + "undici": "8.5.0", + "yaml": "2.9.0" + }, + "bin": { + "pi": "dist/cli.js" + }, + "engines": { + "node": ">=22.19.0" + }, + "optionalDependencies": { + "@mariozechner/clipboard": "0.3.9" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@anthropic-ai/sdk": { + "version": "0.91.1", + "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.91.1.tgz", + "integrity": "sha512-LAmu761tSN9r66ixvmciswUj/ZC+1Q4iAfpedTfSVLeswRwnY3n2Nb6Tsk+cLPP28aLOPWeMgIuTuCcMC6W/iw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-schema-to-ts": "^3.1.1" + }, + "bin": { + "anthropic-ai-sdk": "bin/cli" + }, + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0" + }, + "peerDependenciesMeta": { + "zod": { + "optional": true + } + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@aws-crypto/crc32": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-5.2.0.tgz", + "integrity": "sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@aws-crypto/sha256-browser": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz", + "integrity": "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-js": "^5.2.0", + "@aws-crypto/supports-web-crypto": "^5.2.0", + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-locate-window": "^3.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@aws-crypto/sha256-js": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz", + "integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@aws-crypto/supports-web-crypto": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz", + "integrity": "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@aws-crypto/util": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-5.2.0.tgz", + "integrity": "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.222.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@aws-sdk/client-bedrock-runtime": { + "version": "3.1048.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-bedrock-runtime/-/client-bedrock-runtime-3.1048.0.tgz", + "integrity": "sha512-u+NT61JZEkRFtpL0CAw1N1dwxnaLgwVXQl/zjJxTGgLyS/jTIdg2SdoEoCTHxgDyCnqa1HEi9QOoE9/pYRNpOQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "^3.974.11", + "@aws-sdk/credential-provider-node": "^3.972.42", + "@aws-sdk/eventstream-handler-node": "^3.972.16", + "@aws-sdk/middleware-eventstream": "^3.972.12", + "@aws-sdk/middleware-websocket": "^3.972.19", + "@aws-sdk/token-providers": "3.1048.0", + "@aws-sdk/types": "^3.973.8", + "@smithy/core": "^3.24.2", + "@smithy/fetch-http-handler": "^5.4.2", + "@smithy/node-http-handler": "^4.7.2", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@aws-sdk/core": { + "version": "3.974.11", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.974.11.tgz", + "integrity": "sha512-QpnINq5FZH6EOaDEkmHdT7eUunbvD27pDNQypaWjFyYz7Zl1q3UCMQErBZxpmfGfI7MvI2TlK8KTkgNpv8b1ug==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.973.8", + "@aws-sdk/xml-builder": "^3.972.24", + "@aws/lambda-invoke-store": "^0.2.2", + "@smithy/core": "^3.24.2", + "@smithy/signature-v4": "^5.4.2", + "@smithy/types": "^4.14.1", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@aws-sdk/credential-provider-env": { + "version": "3.972.37", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.37.tgz", + "integrity": "sha512-/jpPvEh6f7ntmIzf7dNxoNX6Q8vt8UpesCjbW6mFfk4V1NW6bIy9qxcQ6WbA8As5yQhsZOe+xeNd4xHX8kdY2Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.11", + "@aws-sdk/types": "^3.973.8", + "@smithy/core": "^3.24.2", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@aws-sdk/credential-provider-http": { + "version": "3.972.39", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.39.tgz", + "integrity": "sha512-pIgTpisWyWg7X1bUbzSjuUYosYTD0Ghz2M0hkSTmb3a6i3qV3uU+NYJPI/E2XSC0HcsZh5rsLPzeXrkb2DS0Cg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.11", + "@aws-sdk/types": "^3.973.8", + "@smithy/core": "^3.24.2", + "@smithy/fetch-http-handler": "^5.4.2", + "@smithy/node-http-handler": "^4.7.2", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.972.41", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.972.41.tgz", + "integrity": "sha512-u2tyjaxJJzW8UtW4SM1ZcPMDwO6y+kV+llvou+Adts0FAKyzes5jG4izQN+KX3yE8ZROpS5y1LJ//xL2iSf76w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.11", + "@aws-sdk/credential-provider-env": "^3.972.37", + "@aws-sdk/credential-provider-http": "^3.972.39", + "@aws-sdk/credential-provider-login": "^3.972.41", + "@aws-sdk/credential-provider-process": "^3.972.37", + "@aws-sdk/credential-provider-sso": "^3.972.41", + "@aws-sdk/credential-provider-web-identity": "^3.972.41", + "@aws-sdk/nested-clients": "^3.997.9", + "@aws-sdk/types": "^3.973.8", + "@smithy/core": "^3.24.2", + "@smithy/credential-provider-imds": "^4.3.2", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@aws-sdk/credential-provider-login": { + "version": "3.972.41", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.41.tgz", + "integrity": "sha512-0LBitxXiAiaE5nlFPfpNIww/8FRY/I7WIndWsc9GmNFOM7cE1wNpVNQEGEk9Outg5l8xl+3vybxFyUy4l9q/LQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.11", + "@aws-sdk/nested-clients": "^3.997.9", + "@aws-sdk/types": "^3.973.8", + "@smithy/core": "^3.24.2", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@aws-sdk/credential-provider-node": { + "version": "3.972.42", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.42.tgz", + "integrity": "sha512-D4oon2zbqqsWOJUM99Gm3/ZyJ0IJvTXVN3PyloGb3kQEyI36fjCZheZj422lAgTWWd6TSHgiImLt3RIaLdv3dQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/credential-provider-env": "^3.972.37", + "@aws-sdk/credential-provider-http": "^3.972.39", + "@aws-sdk/credential-provider-ini": "^3.972.41", + "@aws-sdk/credential-provider-process": "^3.972.37", + "@aws-sdk/credential-provider-sso": "^3.972.41", + "@aws-sdk/credential-provider-web-identity": "^3.972.41", + "@aws-sdk/types": "^3.973.8", + "@smithy/core": "^3.24.2", + "@smithy/credential-provider-imds": "^4.3.2", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@aws-sdk/credential-provider-process": { + "version": "3.972.37", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.37.tgz", + "integrity": "sha512-7nVaHBUaWIddASYfVaA9O4D5ZVjewU3sCol9WqZPGfW0nR+0WqE0xHZnD/U2L33PlOB8KNXGKZ6wOES/QijKzg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.11", + "@aws-sdk/types": "^3.973.8", + "@smithy/core": "^3.24.2", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.972.41", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.972.41.tgz", + "integrity": "sha512-IOWAWEHe5LkjSKkkUUX9ciV6Y1scHTsnfEkdt5yyC4Slrc7AGbkLPrpntjqh18ksJAMOaVhoBsO8p2WyTcY2wQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.11", + "@aws-sdk/nested-clients": "^3.997.9", + "@aws-sdk/token-providers": "3.1048.0", + "@aws-sdk/types": "^3.973.8", + "@smithy/core": "^3.24.2", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.972.41", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.41.tgz", + "integrity": "sha512-mbACk9Yypa8nm4iGZLs0PofOXEcTDOUw6wDnsPXNDNSd2WNXs1tSo+6nc/fh0jLYdfVZThhBL98PHW4aXFsG5A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.11", + "@aws-sdk/nested-clients": "^3.997.9", + "@aws-sdk/types": "^3.973.8", + "@smithy/core": "^3.24.2", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@aws-sdk/eventstream-handler-node": { + "version": "3.972.16", + "resolved": "https://registry.npmjs.org/@aws-sdk/eventstream-handler-node/-/eventstream-handler-node-3.972.16.tgz", + "integrity": "sha512-yedpPgKftqjU5SlPFHfqWpOw6xSCRieWRG1euWOlXn4WJxt2VX92VprCa2PpSOXjVCAeK6dTjW9eJRXVig9yGA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.973.8", + "@smithy/core": "^3.24.2", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@aws-sdk/middleware-eventstream": { + "version": "3.972.12", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-eventstream/-/middleware-eventstream-3.972.12.tgz", + "integrity": "sha512-tHTHHCHNrq6XklQvlzHBDJG4Iuhh7NVPRdtmvP+nHFA+5sxPlIDzlAHHgfoYHGvT3NXP1yVP/L5c3opUn6T3Qg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.973.8", + "@smithy/core": "^3.24.2", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@aws-sdk/middleware-websocket": { + "version": "3.972.19", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-websocket/-/middleware-websocket-3.972.19.tgz", + "integrity": "sha512-mkEhOGYozqKQkbFaVrjwr0faiwwZza1v5/jSY6Tucm3bD+uKTazIUH/4Yo6aMnQD2ua2W9cMP6s8mvwTcjtqHw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.11", + "@aws-sdk/types": "^3.973.8", + "@smithy/core": "^3.24.2", + "@smithy/fetch-http-handler": "^5.4.2", + "@smithy/signature-v4": "^5.4.2", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@aws-sdk/nested-clients": { + "version": "3.997.9", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.997.9.tgz", + "integrity": "sha512-jPR3rnmRI4hWYyzfmTGBr7NblMp8QYYeflHXba1H6+7CGrWVqWKQzaXFQ4qbExqPRsXN3T3L3JxFhr6aouXUGQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "^3.974.11", + "@aws-sdk/signature-v4-multi-region": "^3.996.27", + "@aws-sdk/types": "^3.973.8", + "@smithy/core": "^3.24.2", + "@smithy/fetch-http-handler": "^5.4.2", + "@smithy/node-http-handler": "^4.7.2", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@aws-sdk/signature-v4-multi-region": { + "version": "3.996.27", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.996.27.tgz", + "integrity": "sha512-0Phbz4t6HI3D3skxvG2uI+VWU034/nSIw1T8d+FPzzQG9EQTrw94o9mOKO2Gv3n3Oc8P7JD7RAUxkoneLWv5Eg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.973.8", + "@smithy/core": "^3.24.2", + "@smithy/signature-v4": "^5.4.2", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@aws-sdk/token-providers": { + "version": "3.1048.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.1048.0.tgz", + "integrity": "sha512-k0y/GcuesuSfWyUM0WamrGyeZmltRYaPbHO82UDA6mZ/doB+FOHKutikPAtSXMn/hDz970cF+iRuuiYO9VEbAA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.11", + "@aws-sdk/nested-clients": "^3.997.9", + "@aws-sdk/types": "^3.973.8", + "@smithy/core": "^3.24.2", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@aws-sdk/types": { + "version": "3.973.8", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.973.8.tgz", + "integrity": "sha512-gjlAdtHMbtR9X5iIhVUvbVcy55KnznpC6bkDUWW9z915bi0ckdUr5cjf16Kp6xq0bP5HBD2xzgbL9F9Quv5vUw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@aws-sdk/util-locate-window": { + "version": "3.965.5", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.965.5.tgz", + "integrity": "sha512-WhlJNNINQB+9qtLtZJcpQdgZw3SCDCpXdUJP7cToGwHbCWCnRckGlc6Bx/OhWwIYFNAn+FIydY8SZ0QmVu3xTQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@aws-sdk/xml-builder": { + "version": "3.972.24", + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.24.tgz", + "integrity": "sha512-V8z5YcDPfsvzrBlj0xR1vhRtocblhYbqdreCJB/voGd4Sr5zjNAeWxexbnqVtskTJe0vFb5KMqbSL++ePl+zRw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@nodable/entities": "2.1.0", + "@smithy/types": "^4.14.1", + "fast-xml-parser": "5.7.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@aws/lambda-invoke-store": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@aws/lambda-invoke-store/-/lambda-invoke-store-0.2.4.tgz", + "integrity": "sha512-iY8yvjE0y651BixKNPgmv1WrQc+GZ142sb0z4gYnChDDY2YqI4P/jsSopBWrKfAt7LOJAkOXt7rC/hms+WclQQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@babel/runtime": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz", + "integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@earendil-works/pi-agent-core": { + "version": "0.81.1", + "resolved": "https://registry.npmjs.org/@earendil-works/pi-agent-core/-/pi-agent-core-0.81.1.tgz", + "dev": true, + "license": "MIT", + "dependencies": { + "@earendil-works/pi-ai": "^0.81.1", + "ignore": "7.0.5", + "typebox": "1.1.38", + "yaml": "2.9.0" + }, + "engines": { + "node": ">=22.19.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@earendil-works/pi-ai": { + "version": "0.81.1", + "resolved": "https://registry.npmjs.org/@earendil-works/pi-ai/-/pi-ai-0.81.1.tgz", + "dev": true, + "license": "MIT", + "dependencies": { + "@anthropic-ai/sdk": "0.91.1", + "@aws-sdk/client-bedrock-runtime": "3.1048.0", + "@google/genai": "1.52.0", + "@mistralai/mistralai": "2.2.6", + "@opentelemetry/api": "1.9.0", + "@smithy/node-http-handler": "4.7.3", + "http-proxy-agent": "7.0.2", + "https-proxy-agent": "7.0.6", + "openai": "6.26.0", + "partial-json": "0.1.7", + "typebox": "1.1.38" + }, + "bin": { + "pi-ai": "dist/cli.js" + }, + "engines": { + "node": ">=22.19.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@earendil-works/pi-tui": { + "version": "0.81.1", + "resolved": "https://registry.npmjs.org/@earendil-works/pi-tui/-/pi-tui-0.81.1.tgz", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "1.6.0", + "marked": "18.0.5" + }, + "engines": { + "node": ">=22.19.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@google/genai": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/@google/genai/-/genai-1.52.0.tgz", + "integrity": "sha512-gwSvbpiN/17O9TbsqSsE/OzZcpv5Fo4RQjdngGgogtuB9RsyJ8ZHhX5KjHj1bp5N9snN2eK8LDGXSaWW2hof8Q==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "google-auth-library": "^10.3.0", + "p-retry": "^4.6.2", + "protobufjs": "^7.5.4", + "ws": "^8.18.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@modelcontextprotocol/sdk": "^1.25.2" + }, + "peerDependenciesMeta": { + "@modelcontextprotocol/sdk": { + "optional": true + } + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@mariozechner/clipboard": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard/-/clipboard-0.3.9.tgz", + "integrity": "sha512-ABnA53mdfkGZwOFUdZNv2S0CWGO/EIuPj8Vv9xmBFmSYg/qFc7ihO6q5FcQjvoE67kZpWkEc4AhD6B/os04yuA==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@mariozechner/clipboard-darwin-arm64": "0.3.9", + "@mariozechner/clipboard-darwin-universal": "0.3.9", + "@mariozechner/clipboard-darwin-x64": "0.3.9", + "@mariozechner/clipboard-linux-arm64-gnu": "0.3.9", + "@mariozechner/clipboard-linux-arm64-musl": "0.3.9", + "@mariozechner/clipboard-linux-riscv64-gnu": "0.3.9", + "@mariozechner/clipboard-linux-x64-gnu": "0.3.9", + "@mariozechner/clipboard-linux-x64-musl": "0.3.9", + "@mariozechner/clipboard-win32-arm64-msvc": "0.3.9", + "@mariozechner/clipboard-win32-x64-msvc": "0.3.9" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@mariozechner/clipboard-darwin-arm64": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-darwin-arm64/-/clipboard-darwin-arm64-0.3.9.tgz", + "integrity": "sha512-BfgV7vCEWZwJwZJw03r6bP5+tf0iI/ANuQYCxi9RNn7FrWB3yzGuMKCrNLRl6V761vXRdL8+OqZ0wd4TqlsNOQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@mariozechner/clipboard-darwin-universal": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-darwin-universal/-/clipboard-darwin-universal-0.3.9.tgz", + "integrity": "sha512-BGGR4iA9Z2shAjI65eI5xtyb3LYNlDW9X3gxKxDbqtbnREohsrqznov6zpKoIrsRWpzlYVEdKphS7ksJ0/ndSQ==", + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@mariozechner/clipboard-darwin-x64": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-darwin-x64/-/clipboard-darwin-x64-0.3.9.tgz", + "integrity": "sha512-4kURmCbS6nt8uYhtmWpUcJWyPHfmAr5dTpXD1nO3pIfa+TSQ9DbrGOYCKH+aEFW47XhQ4Vp8ZTszie+wfFvDKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@mariozechner/clipboard-linux-arm64-gnu": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-linux-arm64-gnu/-/clipboard-linux-arm64-gnu-0.3.9.tgz", + "integrity": "sha512-g59OkUGP2DDfCOIKypHeYgv2M55u/cKvXa5dSxFbEJ34XvIQMdcVmpKCkGUro3ZgefXiGVdwguvTMQGpHWzIXw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@mariozechner/clipboard-linux-arm64-musl": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-linux-arm64-musl/-/clipboard-linux-arm64-musl-0.3.9.tgz", + "integrity": "sha512-AGuJdgKsmJdm4Pych7kv3sqe591ERRaAHW3xjLooiFzn8J+PxUyof++7YZrB5Y5tpnTO+K18Og3taj2NpluCRQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@mariozechner/clipboard-linux-riscv64-gnu": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-linux-riscv64-gnu/-/clipboard-linux-riscv64-gnu-0.3.9.tgz", + "integrity": "sha512-DXBEAiuMpk7dhS1a9NzNxVAFi1vaKoPu7rQNgY8LIDLGrK3lnIp3nT10DUum+PKVJoJppIP+NAA8IZe4DMNDPw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@mariozechner/clipboard-linux-x64-gnu": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-linux-x64-gnu/-/clipboard-linux-x64-gnu-0.3.9.tgz", + "integrity": "sha512-WORrMLd6EpElEME7JRKfSaY34nW1P5LbdgK5YNCS1ncG2LqmITsSMEJ8nh2mpvxb3TxqbOOKgY7k9eMJYlW9Mw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@mariozechner/clipboard-linux-x64-musl": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-linux-x64-musl/-/clipboard-linux-x64-musl-0.3.9.tgz", + "integrity": "sha512-/DHn+1DrfL6oRaPPWXaOKvonFFrni666fxd+zFqiQEfvBH0tsHVWjq9iqBk0oDp0qaPA72lIMy5BptxISBEhZQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@mariozechner/clipboard-win32-arm64-msvc": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-win32-arm64-msvc/-/clipboard-win32-arm64-msvc-0.3.9.tgz", + "integrity": "sha512-O5FHD3ErkMwMhNzAfu3ggy0ug4z7btZuoQgwwxlzPrwV2bxlD6WDpqBY4NCgICAgZdDKdp+loUEKVAVt8aYnhQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@mariozechner/clipboard-win32-x64-msvc": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-win32-x64-msvc/-/clipboard-win32-x64-msvc-0.3.9.tgz", + "integrity": "sha512-ihQC3EufqEY81vhXBgVBtK4prL+wc62zJsSvxrgz7K1hsdt6OObz6v9p3Rn1OG3GJksTTKMJF0u/guMISHPhSA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@mistralai/mistralai": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/@mistralai/mistralai/-/mistralai-2.2.6.tgz", + "integrity": "sha512-W8pX7zHxjJvMIpw8JMxeJEleapXX0Q9NPszdNzqkM3MIEoIGPObdodujj+WHteXEvGfaP/AMwlNyRfEzSY6dQQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.40.0", + "ws": "^8.18.0", + "zod": "^3.25.0 || ^4.0.0", + "zod-to-json-schema": "^3.25.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.9.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + } + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@nodable/entities": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@nodable/entities/-/entities-2.1.0.tgz", + "integrity": "sha512-nyT7T3nbMyBI/lvr6L5TyWbFJAI9FTgVRakNoBqCD+PmID8DzFrrNdLLtHMwMszOtqZa8PAOV24ZqDnQrhQINA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/nodable" + } + ], + "license": "MIT" + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@opentelemetry/api": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", + "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@opentelemetry/semantic-conventions": { + "version": "1.41.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.41.1.tgz", + "integrity": "sha512-/UhIkaZgPutTFmQ7RnIJGgDXZmtEJ7Dvi86xNTFWcnRxVRNk/aotsqDJYeEvDP+FSMB2SdW+pQzNMcWP0rwuNA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@protobufjs/codegen": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.5.tgz", + "integrity": "sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@protobufjs/eventemitter": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.1.tgz", + "integrity": "sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@protobufjs/fetch": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.1.tgz", + "integrity": "sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@protobufjs/utf8": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.1.tgz", + "integrity": "sha512-oOAWABowe8EAbMyWKM0tYDKi8Yaox52D+HWZhAIJqQXbqe0xI/GV7FhLWqlEKreMkfDjshR5FKgi3mnle0h6Eg==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@silvia-odwyer/photon-node": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@silvia-odwyer/photon-node/-/photon-node-0.3.4.tgz", + "integrity": "sha512-bnly4BKB3KDTFxrUIcgCLbaeVVS8lrAkri1pEzskpmxu9MdfGQTy8b8EgcD83ywD3RPMsIulY8xJH5Awa+t9fA==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@smithy/core": { + "version": "3.24.3", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.24.3.tgz", + "integrity": "sha512-Ep/7tPamGY8mgESE3LyLKtxJyy6U52WWAqr/3wial47Sj4u3PiIF73AOGI27UyLy9duTkhZbgzodOfLV4TduZg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/crc32": "5.2.0", + "@smithy/types": "^4.14.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@smithy/credential-provider-imds": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.3.3.tgz", + "integrity": "sha512-I2Bti0DKFo2IJyN28ijCsx51BAumEYR4/1yZ1FXyBygy9MqbnMqCev4JPth/MbpRfBSRAX35hITSnAdJRo1u5w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.24.3", + "@smithy/types": "^4.14.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@smithy/fetch-http-handler": { + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.4.3.tgz", + "integrity": "sha512-F+DRf8IJazRJgYog2A/yJK7eYVc0rqTlRzO+5ZxjJd4WkZoKz0IJRncf7G6t1pdVT3kryJcwuTFhN1c5m6N47A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.24.3", + "@smithy/types": "^4.14.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@smithy/is-array-buffer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", + "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@smithy/node-http-handler": { + "version": "4.7.3", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.7.3.tgz", + "integrity": "sha512-/jPhevcTFPMVl6KNjbaI47iOg1zxC7IsnX4PQDGVZKMFceOXtB8IEYaB7a9VvkP/3oC60WzTeKocvSI7vLT0vA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.24.3", + "@smithy/types": "^4.14.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@smithy/signature-v4": { + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.4.3.tgz", + "integrity": "sha512-53+75QuPl6DL+ct6vVEB51FDO5oulXr20TPV46VvJZg76lIlXNWfxi8j+G2V/t0I2qxCBOa3vX/8bmjrpFVo9g==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.24.3", + "@smithy/types": "^4.14.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@smithy/types": { + "version": "4.14.2", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.14.2.tgz", + "integrity": "sha512-P+otAxbV4CqBybp7EkcJCrig63yE2E7PuNVOmilVMRcx/O+QDzGULTrKsq4DV13gSfak9ObPrWaHl/9bL5YcWw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@smithy/util-buffer-from": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", + "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@smithy/util-utf8": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", + "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/@types/node": { + "version": "22.19.19", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.19.tgz", + "integrity": "sha512-dyh/xO2Fh5bYrfWaaqGrRQQGkNdmYw6AmaAUvYeUMNTWQtvb796ikLdmTchRmOlOiIJ1TDXfWgVx1QkUlQ6Hew==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/bignumber.js": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz", + "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/bowser": { + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.14.1.tgz", + "integrity": "sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/brace-expansion": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.7.tgz", + "integrity": "sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/diff": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.4.tgz", + "integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/fast-xml-builder": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.2.0.tgz", + "integrity": "sha512-00aAWieqff+ZJhsXA4g1g7M8k+7AYoMUUHF+/zFb5U6Uv/P0Vl4QZo84/IcufzYalLuEj9928bXN9PbbFzMF0Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "path-expression-matcher": "^1.5.0", + "xml-naming": "^0.1.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/fast-xml-parser": { + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.7.3.tgz", + "integrity": "sha512-C0AaNuC+mscy6vrAQKAc/rMq+zAPHodfHGZu4sGVehvAQt/JLG1O5zEcYcXSY5zSqr4YVgxsB+pHXTq0i7eDlg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "@nodable/entities": "^2.1.0", + "fast-xml-builder": "^1.1.7", + "path-expression-matcher": "^1.5.0", + "strnum": "^2.2.3" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/gaxios": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-7.1.4.tgz", + "integrity": "sha512-bTIgTsM2bWn3XklZISBTQX7ZSddGW+IO3bMdGaemHZ3tbqExMENHLx6kKZ/KlejgrMtj8q7wBItt51yegqalrA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "extend": "^3.0.2", + "https-proxy-agent": "^7.0.1", + "node-fetch": "^3.3.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/gcp-metadata": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-8.1.2.tgz", + "integrity": "sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "gaxios": "^7.0.0", + "google-logging-utils": "^1.0.0", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/get-east-asian-width": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz", + "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/glob": { + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/google-auth-library": { + "version": "10.6.2", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-10.6.2.tgz", + "integrity": "sha512-e27Z6EThmVNNvtYASwQxose/G57rkRuaRbQyxM2bvYLLX/GqWZ5chWq2EBoUchJbCc57eC9ArzO5wMsEmWftCw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "gaxios": "^7.1.4", + "gcp-metadata": "8.1.2", + "google-logging-utils": "1.1.3", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/google-logging-utils": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-1.1.3.tgz", + "integrity": "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": "*" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/hosted-git-info": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-9.0.3.tgz", + "integrity": "sha512-Hc+ghLoSt6QaYZUv0WBiIvmMDZuZZ7oaDvdH8MbfOO4lOsxdXLEvuC6ePoGs9H1X9oCLyq6+NVN0MKqD+ydxyg==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^11.1.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/jiti": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", + "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "bignumber.js": "^9.0.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/json-schema-to-ts": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/json-schema-to-ts/-/json-schema-to-ts-3.1.1.tgz", + "integrity": "sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "ts-algebra": "^2.0.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/jwa": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/jws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", + "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jwa": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/long": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", + "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/lru-cache": { + "version": "11.4.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.4.0.tgz", + "integrity": "sha512-W+R+kFL4HgVxONq2bhXPi3bGpzGe/yEhVOp233qw9wCRtgncJ15P3bC+e4zZMu4Cq7d+WAJjXGW0uUkifhcatA==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/marked": { + "version": "18.0.5", + "resolved": "https://registry.npmjs.org/marked/-/marked-18.0.5.tgz", + "integrity": "sha512-S6GcvALHg6K4ohtu4E7x0a1AqhAjp6cV8KhLSyN9qVapnzJkusVBxZRcIU9AeYsbe6P1hKDusSbEOzGyyuce6w==", + "dev": true, + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "deprecated": "Use your platform's native DOMException instead", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/openai": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/openai/-/openai-6.26.0.tgz", + "integrity": "sha512-zd23dbWTjiJ6sSAX6s0HrCZi41JwTA1bQVs0wLQPZ2/5o2gxOJA5wh7yOAUgwYybfhDXyhwlpeQf7Mlgx8EOCA==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "openai": "bin/cli" + }, + "peerDependencies": { + "ws": "^8.18.0", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "ws": { + "optional": true + }, + "zod": { + "optional": true + } + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/p-retry/node_modules/@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/partial-json": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/partial-json/-/partial-json-0.1.7.tgz", + "integrity": "sha512-Njv/59hHaokb/hRUjce3Hdv12wd60MtM9Z5Olmn+nehe0QDAsRtRbJPvJ0Z91TusF0SuZRIvnM+S4l6EIP8leA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/path-expression-matcher": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.5.0.tgz", + "integrity": "sha512-cbrerZV+6rvdQrrD+iGMcZFEiiSrbv9Tfdkvnusy6y0x0GKBXREFg/Y65GhIfm0tnLntThhzCnfKwp1WRjeCyQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/proper-lockfile": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz", + "integrity": "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "retry": "^0.12.0", + "signal-exit": "^3.0.2" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/proper-lockfile/node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/protobufjs": { + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.6.4.tgz", + "integrity": "sha512-RJJPTTpvFfHcWLkIa2JFWK4XvtSzS0yEWDmunqHXli1h3JlkbcQZXDZdcWxv+JK3Xsl5/UFDPZ0iGm7DAengYw==", + "dev": true, + "hasInstallScript": true, + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.5", + "@protobufjs/eventemitter": "^1.1.1", + "@protobufjs/fetch": "^1.1.1", + "@protobufjs/float": "^1.0.2", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.1", + "@types/node": ">=13.7.0", + "long": "^5.3.2" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/semver": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz", + "integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/strnum": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.3.0.tgz", + "integrity": "sha512-ums3KNd42PGyx5xaoVTO1mjU1bH3NpY4vsrVlnv9PNGqQj8wd7rJ6nEypLrJ7z5vxK5RP0yMLo6J/Gsm62DI5Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT" + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/ts-algebra": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ts-algebra/-/ts-algebra-2.0.0.tgz", + "integrity": "sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/typebox": { + "version": "1.1.38", + "resolved": "https://registry.npmjs.org/typebox/-/typebox-1.1.38.tgz", + "integrity": "sha512-pZ0aQPmMmXoUvSbeuWf/Hzsc+avNw/Zd6VeE8CFgkVGWyuHPJvqeJJDeJqLve+K70LvjYIoleGcoJHPT17cWoA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/undici": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-8.5.0.tgz", + "integrity": "sha512-xamtWoB1EshgjpmlXd7GGm2VfdDtw1+rD8uhry8pSNW3If6S8E0m2T2+orSKeZXEn/aPJMviCpDBA65WJt8zhg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22.19.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/ws": { + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", + "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/xml-naming": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/xml-naming/-/xml-naming-0.1.0.tgz", + "integrity": "sha512-k8KO9hrMyNk6tUWqUfkTEZbezRRpONVOzUTnc97VnCvyj6Tf9lyUR9EDAIeiVLv56jsMcoXEwjW8Kv5yPY52lw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/yaml": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", + "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/@earendil-works/pi-coding-agent/node_modules/zod-to-json-schema": { + "version": "3.25.2", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.2.tgz", + "integrity": "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==", + "dev": true, + "license": "ISC", + "peerDependencies": { + "zod": "^3.25.28 || ^4" + } + }, + "node_modules/@earendil-works/pi-tui": { + "version": "0.81.1", + "resolved": "https://registry.npmjs.org/@earendil-works/pi-tui/-/pi-tui-0.81.1.tgz", + "integrity": "sha512-OMEe+Zt8oQYi/rCq3upxsTlIScWL0FPhXwQus34TbQb3EmTx88S7Uzx32JxvQiEeWOw8eDCdJf2PBUBE9r6wIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "1.6.0", + "marked": "18.0.5" + }, + "engines": { + "node": ">=22.19.0" + } + }, + "node_modules/@google/genai": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/@google/genai/-/genai-1.52.0.tgz", + "integrity": "sha512-gwSvbpiN/17O9TbsqSsE/OzZcpv5Fo4RQjdngGgogtuB9RsyJ8ZHhX5KjHj1bp5N9snN2eK8LDGXSaWW2hof8Q==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "google-auth-library": "^10.3.0", + "p-retry": "^4.6.2", + "protobufjs": "^7.5.4", + "ws": "^8.18.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@modelcontextprotocol/sdk": "^1.25.2" + }, + "peerDependenciesMeta": { + "@modelcontextprotocol/sdk": { + "optional": true + } + } + }, + "node_modules/@jsdevtools/ono": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", + "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@mistralai/mistralai": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/@mistralai/mistralai/-/mistralai-2.2.6.tgz", + "integrity": "sha512-W8pX7zHxjJvMIpw8JMxeJEleapXX0Q9NPszdNzqkM3MIEoIGPObdodujj+WHteXEvGfaP/AMwlNyRfEzSY6dQQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.40.0", + "ws": "^8.18.0", + "zod": "^3.25.0 || ^4.0.0", + "zod-to-json-schema": "^3.25.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.9.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + } + } + }, + "node_modules/@opentelemetry/api": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", + "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/semantic-conventions": { + "version": "1.43.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.43.0.tgz", + "integrity": "sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.5.tgz", + "integrity": "sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.1.tgz", + "integrity": "sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.1.tgz", + "integrity": "sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.2.tgz", + "integrity": "sha512-b1UQwcEZ4yCnMCD8DAL1VlbvBJE9/IX4FTIp7BG1xYpf29SLazLSrqUkj4w7Y5y7cCVP6E5tcqqcI0xemPkHug==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@smithy/core": { + "version": "3.30.0", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.30.0.tgz", + "integrity": "sha512-dl2yRglDxfzH9uJ4fSo4zTaAHa0zH7+V7BZMRWy8hEYIKT1BiqMUK/CN6T3ADQ3kbA5N1tmUulroJ2UtONS7Kw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/credential-provider-imds": { + "version": "4.4.14", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.4.14.tgz", + "integrity": "sha512-QgbuahIb2qxQeZQvNK0sw3aF3JH5zwH8j2lLp5DUasVXexGGMWULAR+7z0omPXFolCP/m5wN9M5lm9EGdSviTQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.30.0", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/fetch-http-handler": { + "version": "5.6.11", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.6.11.tgz", + "integrity": "sha512-o0Zkj1nKqJAoq+a+BrkhU39tRftMNjLwpc/z06Frfl43wpbHrJMaSAVZE4vTqlxtVkNaGaT0bIDxOp7tkFTuQQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.30.0", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/is-array-buffer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", + "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/node-http-handler": { + "version": "4.7.3", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.7.3.tgz", + "integrity": "sha512-/jPhevcTFPMVl6KNjbaI47iOg1zxC7IsnX4PQDGVZKMFceOXtB8IEYaB7a9VvkP/3oC60WzTeKocvSI7vLT0vA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.24.3", + "@smithy/types": "^4.14.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/signature-v4": { + "version": "5.6.10", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.6.10.tgz", + "integrity": "sha512-EXhWePm3SXJAX38npIy4TXL2Aex/OVgCClTjelN2QHw/U+8CQUH8C7AaxsVzQcYieYPseywn48s89DmvuGjiAg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.30.0", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/types": { + "version": "4.16.1", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.16.1.tgz", + "integrity": "sha512-0JFs3V2y2M9tKW5na/qxe69Zv+uxLMO7QBbhxF/FHu/Gp2NFZAAL9tWl9PU02xxo07pb3G9FTyjNc6D5uZrJIg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-buffer-from": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", + "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-utf8": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", + "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/lodash": { + "version": "4.17.24", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.24.tgz", + "integrity": "sha512-gIW7lQLZbue7lRSWEFql49QJJWThrTFFeIMJdp3eH4tKoxm1OvEPg02rm4wCCSHS0cL3/Fizimb35b7k8atwsQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "24.12.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.12.0.tgz", + "integrity": "sha512-GYDxsZi3ChgmckRT9HPU0WEhKLP08ev/Yfcq2AstjrDASOYCSXeyjDsHg4v5t4jOj7cyDX3vmprafKlWIG9MXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } + }, + "node_modules/@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "dev": true, + "license": "MIT" + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/bignumber.js": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz", + "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/bowser": { + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.14.1.tgz", + "integrity": "sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==", + "dev": true, + "license": "MIT" + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true, + "license": "MIT" + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/gaxios": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-7.3.0.tgz", + "integrity": "sha512-RB5vLV+vvQeoFPCX4QMK6/hjVkbIamPp1QSUD0CiZcnj12qbpiL+pLbYtgD+oZkWl0tl9z+o2Utp+MpM3QRhBA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "extend": "^3.0.2", + "https-proxy-agent": "^7.0.1", + "node-fetch": "^3.3.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/gcp-metadata": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-8.1.2.tgz", + "integrity": "sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "gaxios": "^7.0.0", + "google-logging-utils": "^1.0.0", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz", + "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/google-auth-library": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-10.9.1.tgz", + "integrity": "sha512-i1ydyHrqcIxXkWh/uBmVkzCvIuq5yiK2ATndIe5XxKholrG/MTYP9xGYka4sQhrbIAgGjL2B6NOE7rFaiF3fXw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "gaxios": "^7.1.4", + "gcp-metadata": "8.1.2", + "google-logging-utils": "1.1.3", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/google-logging-utils": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-1.1.3.tgz", + "integrity": "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/js-yaml": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz", + "integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "bignumber.js": "^9.0.0" + } + }, + "node_modules/json-schema-to-ts": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/json-schema-to-ts/-/json-schema-to-ts-3.1.1.tgz", + "integrity": "sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "ts-algebra": "^2.0.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/json-schema-to-typescript": { + "version": "15.0.4", + "resolved": "https://registry.npmjs.org/json-schema-to-typescript/-/json-schema-to-typescript-15.0.4.tgz", + "integrity": "sha512-Su9oK8DR4xCmDsLlyvadkXzX6+GGXJpbhwoLtOGArAG61dvbW4YQmSEno2y66ahpIdmLMg6YUf/QHLgiwvkrHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@apidevtools/json-schema-ref-parser": "^11.5.5", + "@types/json-schema": "^7.0.15", + "@types/lodash": "^4.17.7", + "is-glob": "^4.0.3", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "minimist": "^1.2.8", + "prettier": "^3.2.5", + "tinyglobby": "^0.2.9" + }, + "bin": { + "json2ts": "dist/src/cli.js" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/jwa": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", + "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jwa": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/long": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", + "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/marked": { + "version": "18.0.5", + "resolved": "https://registry.npmjs.org/marked/-/marked-18.0.5.tgz", + "integrity": "sha512-S6GcvALHg6K4ohtu4E7x0a1AqhAjp6cV8KhLSyN9qVapnzJkusVBxZRcIU9AeYsbe6P1hKDusSbEOzGyyuce6w==", + "dev": true, + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "deprecated": "Use your platform's native DOMException instead", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "node_modules/openai": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/openai/-/openai-6.26.0.tgz", + "integrity": "sha512-zd23dbWTjiJ6sSAX6s0HrCZi41JwTA1bQVs0wLQPZ2/5o2gxOJA5wh7yOAUgwYybfhDXyhwlpeQf7Mlgx8EOCA==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "openai": "bin/cli" + }, + "peerDependencies": { + "ws": "^8.18.0", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "ws": { + "optional": true + }, + "zod": { + "optional": true + } + } + }, + "node_modules/p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/partial-json": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/partial-json/-/partial-json-0.1.7.tgz", + "integrity": "sha512-Njv/59hHaokb/hRUjce3Hdv12wd60MtM9Z5Olmn+nehe0QDAsRtRbJPvJ0Z91TusF0SuZRIvnM+S4l6EIP8leA==", + "dev": true, + "license": "MIT" + }, + "node_modules/picomatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/prettier": { + "version": "3.9.6", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.9.6.tgz", + "integrity": "sha512-OpN0zzVdiaiAhxpuuj5efpIS4sY9j7bY6uR5mnj5yPzGkdkjNKSJeUThPb60Jw29QuAZgA4o+/iB49kFiaBX6g==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/protobufjs": { + "version": "7.6.5", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.6.5.tgz", + "integrity": "sha512-/FPD0nUc9jH6rfFjji9IBqOz4pcSE3CsT1m7Ep6Mdb0LxSUMj8hgl6GomOvZzpNpAqqGaXA0P3VSrZLFzIhQrw==", + "dev": true, + "hasInstallScript": true, + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.5", + "@protobufjs/eventemitter": "^1.1.1", + "@protobufjs/fetch": "^1.1.1", + "@protobufjs/float": "^1.0.2", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.1", + "@types/node": ">=13.7.0", + "long": "^5.3.2" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/ts-algebra": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ts-algebra/-/ts-algebra-2.0.0.tgz", + "integrity": "sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==", + "dev": true, + "license": "MIT" + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, + "node_modules/typebox": { + "version": "1.1.38", + "resolved": "https://registry.npmjs.org/typebox/-/typebox-1.1.38.tgz", + "integrity": "sha512-pZ0aQPmMmXoUvSbeuWf/Hzsc+avNw/Zd6VeE8CFgkVGWyuHPJvqeJJDeJqLve+K70LvjYIoleGcoJHPT17cWoA==", + "dev": true, + "license": "MIT" + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "dev": true, + "license": "MIT" + }, + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/ws": { + "version": "8.21.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.1.tgz", + "integrity": "sha512-+0NTnW77fFN/DjQi6k/Sq/Yvk4Sgajw7urW8V+asjXnRgDs9gyGkdb7EzgfhA4goXsRIZKE28fzIXBHEzhuiWw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/zod": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", + "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-to-json-schema": { + "version": "3.25.2", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.2.tgz", + "integrity": "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==", + "dev": true, + "license": "ISC", + "peerDependencies": { + "zod": "^3.25.28 || ^4" + } + } + } +} diff --git a/config/pi/agent/extensions/pi-herdr/package.json b/config/pi/agent/extensions/pi-herdr/package.json new file mode 100644 index 0000000..76d4c22 --- /dev/null +++ b/config/pi/agent/extensions/pi-herdr/package.json @@ -0,0 +1,32 @@ +{ + "name": "pi-herdr", + "version": "0.1.0", + "private": true, + "type": "module", + "description": "Type-safe Herdr orchestration tool for Pi", + "pi": { + "extensions": [ + "./index.ts" + ] + }, + "scripts": { + "generate": "node generate-protocol-types.mjs", + "check-generated": "node generate-protocol-types.mjs --check", + "typecheck": "tsc --noEmit" + }, + "peerDependencies": { + "@earendil-works/pi-ai": "*", + "@earendil-works/pi-coding-agent": "*", + "@earendil-works/pi-tui": "*", + "typebox": "*" + }, + "devDependencies": { + "@earendil-works/pi-ai": "0.81.1", + "@earendil-works/pi-coding-agent": "0.81.1", + "@earendil-works/pi-tui": "0.81.1", + "@types/node": "24.12.0", + "json-schema-to-typescript": "15.0.4", + "typebox": "1.1.38", + "typescript": "5.9.3" + } +} diff --git a/config/pi/agent/extensions/pi-herdr/tsconfig.json b/config/pi/agent/extensions/pi-herdr/tsconfig.json new file mode 100644 index 0000000..241af78 --- /dev/null +++ b/config/pi/agent/extensions/pi-herdr/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "strict": true, + "noEmit": true, + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "skipLibCheck": true, + "types": [ + "node" + ] + }, + "include": [ + "*.ts", + "generated/*.ts" + ] +} diff --git a/flake.lock b/flake.lock index 97ca06a..5905c20 100644 --- a/flake.lock +++ b/flake.lock @@ -51,11 +51,11 @@ "rust-overlay": "rust-overlay" }, "locked": { - "lastModified": 1784942815, - "narHash": "sha256-sSzijwp8RjM048EaWgRH1dP6oLLPz7jd3rNKaMbzVdk=", + "lastModified": 1785002641, + "narHash": "sha256-l8j+XrSr6//V7TJLUUTlukvZ6KlNUCIPx69qz+9nkH8=", "owner": "ogulcancelik", "repo": "herdr", - "rev": "d4e0dd3d903c50d2edb8c3cec71952a83989b310", + "rev": "f67803f4caf6714a6b89d796d04d4ca998ca9a3f", "type": "github" }, "original": {