@schilderlabs/pitown-core 0.2.1 → 0.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent-runner.d.mts +1 -0
- package/dist/agent-runner.mjs +122 -0
- package/dist/agent-runner.mjs.map +1 -0
- package/dist/index.d.mts +76 -23
- package/dist/index.mjs +327 -277
- package/dist/index.mjs.map +1 -1
- package/dist/tasks-BfQm-7-O.mjs +195 -0
- package/dist/tasks-BfQm-7-O.mjs.map +1 -0
- package/package.json +14 -19
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["writeJson","sanitize","createPiInvocationArgs","writeJson","writeJson"],"sources":["../src/events.ts","../src/agents.ts","../src/lease.ts","../src/metrics.ts","../src/pi.ts","../src/shell.ts","../src/repo.ts","../src/controller.ts","../src/interrupts.ts","../src/tasks.ts","../src/loop.ts","../src/orchestration.ts"],"sourcesContent":["import { mkdirSync, readFileSync, writeFileSync } from \"node:fs\"\nimport { dirname } from \"node:path\"\n\nexport function appendJsonl(filePath: string, value: unknown) {\n\tmkdirSync(dirname(filePath), { recursive: true })\n\twriteFileSync(filePath, `${JSON.stringify(value)}\\n`, { encoding: \"utf-8\", flag: \"a\" })\n}\n\nexport function readJsonl<T>(filePath: string): T[] {\n\ttry {\n\t\tconst raw = readFileSync(filePath, \"utf-8\")\n\t\treturn raw\n\t\t\t.split(/\\r?\\n/)\n\t\t\t.map((line) => line.trim())\n\t\t\t.filter(Boolean)\n\t\t\t.map((line) => JSON.parse(line) as T)\n\t} catch {\n\t\treturn []\n\t}\n}\n","import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from \"node:fs\"\nimport { dirname, join } from \"node:path\"\nimport { appendJsonl, readJsonl } from \"./events.js\"\nimport type {\n\tAgentMailbox,\n\tAgentMessageRecord,\n\tAgentSessionRecord,\n\tAgentStateSnapshot,\n\tAgentStatus,\n} from \"./types.js\"\n\nfunction writeJson(path: string, value: unknown) {\n\tmkdirSync(dirname(path), { recursive: true })\n\twriteFileSync(path, `${JSON.stringify(value, null, 2)}\\n`, \"utf-8\")\n}\n\nfunction ensureMailbox(path: string) {\n\tmkdirSync(dirname(path), { recursive: true })\n\tif (!existsSync(path)) writeFileSync(path, \"\", \"utf-8\")\n}\n\nexport function getAgentsDir(artifactsDir: string): string {\n\treturn join(artifactsDir, \"agents\")\n}\n\nexport function getAgentDir(artifactsDir: string, agentId: string): string {\n\treturn join(getAgentsDir(artifactsDir), agentId)\n}\n\nexport function getAgentStatePath(artifactsDir: string, agentId: string): string {\n\treturn join(getAgentDir(artifactsDir, agentId), \"state.json\")\n}\n\nexport function getAgentSessionPath(artifactsDir: string, agentId: string): string {\n\treturn join(getAgentDir(artifactsDir, agentId), \"session.json\")\n}\n\nexport function getAgentMailboxPath(artifactsDir: string, agentId: string, box: AgentMailbox): string {\n\treturn join(getAgentDir(artifactsDir, agentId), `${box}.jsonl`)\n}\n\nexport function getAgentSessionsDir(artifactsDir: string, agentId: string): string {\n\treturn join(getAgentDir(artifactsDir, agentId), \"sessions\")\n}\n\nexport function getSessionIdFromPath(sessionPath: string | null | undefined): string | null {\n\tif (!sessionPath) return null\n\tconst match = /_([0-9a-f-]+)\\.jsonl$/i.exec(sessionPath)\n\treturn match?.[1] ?? null\n}\n\nexport function createAgentSessionRecord(\n\tinput?: Partial<Pick<AgentSessionRecord, \"sessionDir\" | \"sessionId\" | \"sessionPath\" | \"lastAttachedAt\">>,\n): AgentSessionRecord {\n\treturn {\n\t\truntime: \"pi\",\n\t\tpersisted: true,\n\t\tsessionDir: input?.sessionDir ?? null,\n\t\tsessionId: input?.sessionId ?? null,\n\t\tsessionPath: input?.sessionPath ?? null,\n\t\tlastAttachedAt: input?.lastAttachedAt ?? null,\n\t}\n}\n\nexport function createAgentState(input: {\n\tagentId: string\n\trole: string\n\tstatus: AgentStatus\n\ttaskId?: string | null\n\ttask?: string | null\n\tbranch?: string | null\n\tlastMessage?: string | null\n\twaitingOn?: string | null\n\tblocked?: boolean\n\trunId?: string | null\n\tsession?: AgentSessionRecord\n}): AgentStateSnapshot {\n\treturn {\n\t\tagentId: input.agentId,\n\t\trole: input.role,\n\t\tstatus: input.status,\n\t\ttaskId: input.taskId ?? null,\n\t\ttask: input.task ?? null,\n\t\tbranch: input.branch ?? null,\n\t\tupdatedAt: new Date().toISOString(),\n\t\tlastMessage: input.lastMessage ?? null,\n\t\twaitingOn: input.waitingOn ?? null,\n\t\tblocked: input.blocked ?? false,\n\t\trunId: input.runId ?? null,\n\t\tsession: input.session ?? createAgentSessionRecord(),\n\t}\n}\n\nexport function writeAgentState(artifactsDir: string, state: AgentStateSnapshot) {\n\tmkdirSync(getAgentDir(artifactsDir, state.agentId), { recursive: true })\n\tensureMailbox(getAgentMailboxPath(artifactsDir, state.agentId, \"inbox\"))\n\tensureMailbox(getAgentMailboxPath(artifactsDir, state.agentId, \"outbox\"))\n\twriteJson(getAgentStatePath(artifactsDir, state.agentId), state)\n\twriteJson(getAgentSessionPath(artifactsDir, state.agentId), state.session)\n}\n\nexport function readAgentState(artifactsDir: string, agentId: string): AgentStateSnapshot | null {\n\tconst statePath = getAgentStatePath(artifactsDir, agentId)\n\ttry {\n\t\treturn JSON.parse(readFileSync(statePath, \"utf-8\")) as AgentStateSnapshot\n\t} catch {\n\t\treturn null\n\t}\n}\n\nexport function listAgentStates(artifactsDir: string): AgentStateSnapshot[] {\n\tconst agentsDir = getAgentsDir(artifactsDir)\n\tlet entries: string[]\n\ttry {\n\t\tentries = readdirSync(agentsDir)\n\t} catch {\n\t\treturn []\n\t}\n\n\treturn entries\n\t\t.map((entry) => readAgentState(artifactsDir, entry))\n\t\t.filter((state): state is AgentStateSnapshot => state !== null)\n\t\t.sort((left, right) => left.agentId.localeCompare(right.agentId))\n}\n\nexport function appendAgentMessage(input: {\n\tartifactsDir: string\n\tagentId: string\n\tbox: AgentMailbox\n\tfrom: string\n\tbody: string\n}): AgentMessageRecord {\n\tconst record: AgentMessageRecord = {\n\t\tbox: input.box,\n\t\tfrom: input.from,\n\t\tbody: input.body,\n\t\tcreatedAt: new Date().toISOString(),\n\t}\n\tappendJsonl(getAgentMailboxPath(input.artifactsDir, input.agentId, input.box), record)\n\treturn record\n}\n\nexport function readAgentMessages(artifactsDir: string, agentId: string, box: AgentMailbox): AgentMessageRecord[] {\n\treturn readJsonl<AgentMessageRecord>(getAgentMailboxPath(artifactsDir, agentId, box))\n}\n\nexport function getLatestAgentSession(artifactsDir: string, agentId: string): AgentSessionRecord {\n\tconst sessionDir = getAgentSessionsDir(artifactsDir, agentId)\n\tlet entries: string[]\n\ttry {\n\t\tentries = readdirSync(sessionDir)\n\t} catch {\n\t\treturn createAgentSessionRecord({ sessionDir })\n\t}\n\n\tconst latestSessionPath =\n\t\tentries\n\t\t\t.filter((entry) => entry.endsWith(\".jsonl\"))\n\t\t\t.sort()\n\t\t\t.at(-1) ?? null\n\n\tif (latestSessionPath === null) return createAgentSessionRecord({ sessionDir })\n\n\tconst sessionPath = join(sessionDir, latestSessionPath)\n\treturn createAgentSessionRecord({\n\t\tsessionDir,\n\t\tsessionPath,\n\t\tsessionId: getSessionIdFromPath(sessionPath),\n\t})\n}\n","import { mkdirSync, readFileSync, rmSync, writeFileSync } from \"node:fs\"\nimport { homedir, hostname } from \"node:os\"\nimport { join } from \"node:path\"\n\ninterface LeaseData {\n\trunId: string\n\trepoId: string\n\tbranch: string\n\tpid: number\n\thostname: string\n\tstartedAt: string\n}\n\nfunction sanitize(value: string): string {\n\treturn value.replace(/[^a-zA-Z0-9._-]+/g, \"_\")\n}\n\nfunction processAlive(pid: number): boolean {\n\tif (!Number.isFinite(pid) || pid <= 0) return false\n\ttry {\n\t\tprocess.kill(pid, 0)\n\t\treturn true\n\t} catch {\n\t\treturn false\n\t}\n}\n\nexport function acquireRepoLease(runId: string, repoId: string, branch: string): { path: string; release: () => void } {\n\tconst locksDir = join(homedir(), \".pi-town\", \"locks\")\n\tmkdirSync(locksDir, { recursive: true })\n\n\tconst leasePath = join(locksDir, `pi-town-${sanitize(repoId)}-${sanitize(branch)}.json`)\n\tconst nextData: LeaseData = {\n\t\trunId,\n\t\trepoId,\n\t\tbranch,\n\t\tpid: process.pid,\n\t\thostname: hostname(),\n\t\tstartedAt: new Date().toISOString(),\n\t}\n\n\ttry {\n\t\tconst current = JSON.parse(readFileSync(leasePath, \"utf-8\")) as LeaseData\n\t\tif (processAlive(current.pid)) {\n\t\t\tthrow new Error(`Pi Town lease already held by pid ${current.pid} on ${current.hostname} for run ${current.runId}.`)\n\t\t}\n\t\trmSync(leasePath, { force: true })\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code !== \"ENOENT\") {\n\t\t\tif (error instanceof Error && error.message.startsWith(\"Pi Town lease already held\")) throw error\n\t\t}\n\t}\n\n\twriteFileSync(leasePath, `${JSON.stringify(nextData, null, 2)}\\n`, \"utf-8\")\n\n\treturn {\n\t\tpath: leasePath,\n\t\trelease: () => {\n\t\t\ttry {\n\t\t\t\tconst current = JSON.parse(readFileSync(leasePath, \"utf-8\")) as LeaseData\n\t\t\t\tif (current.runId === runId) rmSync(leasePath, { force: true })\n\t\t\t} catch {\n\t\t\t\t// ignore cleanup failures\n\t\t\t}\n\t\t},\n\t}\n}\n","import type { FeedbackCycle, InterruptRecord, MetricsSnapshot, TaskAttempt } from \"./types.js\"\n\nfunction round(value: number): number {\n\treturn Math.round(value * 1000) / 1000\n}\n\nfunction diffHours(start: string, end: string): number {\n\treturn (Date.parse(end) - Date.parse(start)) / 3_600_000\n}\n\nfunction average(values: number[]): number | null {\n\tif (values.length === 0) return null\n\treturn values.reduce((sum, value) => sum + value, 0) / values.length\n}\n\nexport function computeInterruptRate(interrupts: InterruptRecord[], taskAttempts: TaskAttempt[]): number {\n\tif (taskAttempts.length === 0) return 0\n\treturn round(interrupts.length / taskAttempts.length)\n}\n\nexport function computeAutonomousCompletionRate(taskAttempts: TaskAttempt[]): number {\n\tconst completed = taskAttempts.filter((task) => task.status === \"completed\")\n\tif (completed.length === 0) return 0\n\tconst autonomous = completed.filter((task) => !task.interrupted)\n\treturn round(autonomous.length / completed.length)\n}\n\nexport function computeContextCoverageScore(interrupts: InterruptRecord[]): number {\n\tconst observed = new Set(interrupts.map((interrupt) => interrupt.category))\n\tif (observed.size === 0) return 0\n\n\tconst covered = new Set(\n\t\tinterrupts.filter((interrupt) => interrupt.fixType).map((interrupt) => interrupt.category),\n\t)\n\n\treturn round(covered.size / observed.size)\n}\n\nexport function computeMeanTimeToCorrect(interrupts: InterruptRecord[]): number | null {\n\tconst resolved = interrupts.filter((interrupt) => interrupt.resolvedAt)\n\tconst hours = resolved.map((interrupt) => diffHours(interrupt.createdAt, interrupt.resolvedAt!))\n\tconst value = average(hours)\n\treturn value === null ? null : round(value)\n}\n\nexport function computeFeedbackToDemoCycleTime(feedbackCycles: FeedbackCycle[]): number | null {\n\tconst hours = feedbackCycles.map((cycle) => diffHours(cycle.feedbackAt, cycle.demoReadyAt))\n\tconst value = average(hours)\n\treturn value === null ? null : round(value)\n}\n\nexport function computeMetrics(input: {\n\ttaskAttempts: TaskAttempt[]\n\tinterrupts: InterruptRecord[]\n\tfeedbackCycles?: FeedbackCycle[]\n}): MetricsSnapshot {\n\tconst observedCategories = new Set(input.interrupts.map((interrupt) => interrupt.category))\n\tconst coveredCategories = new Set(\n\t\tinput.interrupts.filter((interrupt) => interrupt.fixType).map((interrupt) => interrupt.category),\n\t)\n\tconst completedTasks = input.taskAttempts.filter((task) => task.status === \"completed\").length\n\n\treturn {\n\t\tinterruptRate: computeInterruptRate(input.interrupts, input.taskAttempts),\n\t\tautonomousCompletionRate: computeAutonomousCompletionRate(input.taskAttempts),\n\t\tcontextCoverageScore: computeContextCoverageScore(input.interrupts),\n\t\tmeanTimeToCorrectHours: computeMeanTimeToCorrect(input.interrupts),\n\t\tfeedbackToDemoCycleTimeHours: computeFeedbackToDemoCycleTime(input.feedbackCycles ?? []),\n\t\ttotals: {\n\t\t\ttaskAttempts: input.taskAttempts.length,\n\t\t\tcompletedTasks,\n\t\t\tinterrupts: input.interrupts.length,\n\t\t\tobservedInterruptCategories: observedCategories.size,\n\t\t\tcoveredInterruptCategories: coveredCategories.size,\n\t\t},\n\t}\n}\n","export function detectPiAuthFailure(stderr: string, stdout: string): boolean {\n\tconst output = `${stdout}\\n${stderr}`.toLowerCase()\n\treturn (\n\t\toutput.includes(\"no models available\") ||\n\t\toutput.includes(\"not authenticated\") ||\n\t\toutput.includes(\"authentication\") ||\n\t\toutput.includes(\"/login\") ||\n\t\toutput.includes(\"api key\")\n\t)\n}\n\nexport function createPiAuthHelpMessage(): string {\n\treturn 'Pi appears to be installed but not authenticated or configured. Verify Pi works first: pi -p \"hello\". Either set an API key or run `pi` and use `/login`.'\n}\n","import { spawnSync } from \"node:child_process\"\n\nexport interface CommandResult {\n\tstdout: string\n\tstderr: string\n\texitCode: number\n}\n\nexport function runCommandSync(\n\tcommand: string,\n\targs: string[],\n\toptions?: { cwd?: string; env?: NodeJS.ProcessEnv },\n): CommandResult {\n\tconst result = spawnSync(command, args, {\n\t\tcwd: options?.cwd,\n\t\tenv: options?.env,\n\t\tencoding: \"utf-8\",\n\t})\n\tconst errorText = result.error instanceof Error ? `${result.error.message}\n` : \"\"\n\n\treturn {\n\t\tstdout: result.stdout ?? \"\",\n\t\tstderr: `${errorText}${result.stderr ?? \"\"}`,\n\t\texitCode: result.status ?? 1,\n\t}\n}\n\nexport function assertCommandAvailable(command: string) {\n\tconst result = spawnSync(command, [\"--help\"], {\n\t\tencoding: \"utf-8\",\n\t\tstdio: \"ignore\",\n\t})\n\n\tif (result.error instanceof Error) {\n\t\tthrow new Error(result.error.message)\n\t}\n}\n\nexport function runCommandInteractive(\n\tcommand: string,\n\targs: string[],\n\toptions?: { cwd?: string; env?: NodeJS.ProcessEnv },\n): number {\n\tconst result = spawnSync(command, args, {\n\t\tcwd: options?.cwd,\n\t\tenv: options?.env,\n\t\tstdio: \"inherit\",\n\t})\n\n\tif (result.error instanceof Error) {\n\t\tthrow new Error(result.error.message)\n\t}\n\n\treturn result.status ?? 1\n}\n\nexport function assertSuccess(result: CommandResult, context: string) {\n\tif (result.exitCode === 0) return\n\tconst details = [result.stdout.trim(), result.stderr.trim()].filter(Boolean).join(\"\\n\")\n\tthrow new Error(`${context} failed${details ? `\\n${details}` : \"\"}`)\n}\n","import { createHash } from \"node:crypto\"\nimport { existsSync } from \"node:fs\"\nimport { basename, resolve } from \"node:path\"\nimport { assertSuccess, runCommandSync } from \"./shell.js\"\n\nfunction gitResult(cwd: string, args: string[]) {\n\treturn runCommandSync(\"git\", args, { cwd })\n}\n\nfunction sanitize(value: string): string {\n\treturn value.replace(/[^a-zA-Z0-9._-]+/g, \"-\").replace(/^-+|-+$/g, \"\") || \"repo\"\n}\n\nexport function isGitRepo(cwd: string): boolean {\n\tconst result = gitResult(cwd, [\"rev-parse\", \"--is-inside-work-tree\"])\n\treturn result.exitCode === 0 && result.stdout.trim() === \"true\"\n}\n\nexport function getRepoRoot(cwd: string): string {\n\tif (!isGitRepo(cwd)) return resolve(cwd)\n\tconst result = gitResult(cwd, [\"rev-parse\", \"--show-toplevel\"])\n\tassertSuccess(result, \"git rev-parse --show-toplevel\")\n\treturn resolve(result.stdout.trim())\n}\n\nexport function getCurrentBranch(cwd: string): string | null {\n\tif (!isGitRepo(cwd)) return null\n\tconst result = gitResult(cwd, [\"rev-parse\", \"--abbrev-ref\", \"HEAD\"])\n\tif (result.exitCode !== 0) return null\n\tconst branch = result.stdout.trim()\n\treturn branch || null\n}\n\nexport function getRepoIdentity(cwd: string): string {\n\tif (!isGitRepo(cwd)) return resolve(cwd)\n\n\tconst remote = gitResult(cwd, [\"config\", \"--get\", \"remote.origin.url\"])\n\tconst remoteValue = remote.stdout.trim()\n\tif (remote.exitCode === 0 && remoteValue) return remoteValue\n\n\tconst root = gitResult(cwd, [\"rev-parse\", \"--show-toplevel\"])\n\tassertSuccess(root, \"git rev-parse --show-toplevel\")\n\tconst commonDir = gitResult(cwd, [\"rev-parse\", \"--git-common-dir\"])\n\tassertSuccess(commonDir, \"git rev-parse --git-common-dir\")\n\n\tconst rootPath = resolve(root.stdout.trim())\n\tconst commonDirPath = commonDir.stdout.trim()\n\treturn `${basename(rootPath)}:${rootPath}:${existsSync(commonDirPath) ? resolve(commonDirPath) : commonDirPath}`\n}\n\nexport function createRepoSlug(repoId: string, repoRoot: string): string {\n\tconst name = sanitize(basename(repoRoot))\n\tconst digest = createHash(\"sha1\").update(repoId).digest(\"hex\").slice(0, 8)\n\treturn `${name}-${digest}`\n}\n","import { mkdirSync, writeFileSync } from \"node:fs\"\nimport { join } from \"node:path\"\nimport {\n\tcreateAgentSessionRecord,\n\tcreateAgentState,\n\tgetAgentSessionsDir,\n\tgetLatestAgentSession,\n\treadAgentState,\n\twriteAgentState,\n} from \"./agents.js\"\nimport { appendJsonl } from \"./events.js\"\nimport { acquireRepoLease } from \"./lease.js\"\nimport { computeMetrics } from \"./metrics.js\"\nimport { createPiAuthHelpMessage, detectPiAuthFailure } from \"./pi.js\"\nimport { createRepoSlug, getCurrentBranch, getRepoIdentity, getRepoRoot } from \"./repo.js\"\nimport { assertCommandAvailable, runCommandSync } from \"./shell.js\"\nimport type { ControllerRunResult, PiInvocationRecord, RunManifest, RunOptions, RunSummary } from \"./types.js\"\n\nfunction createRunId(): string {\n\treturn `run-${new Date().toISOString().replace(/[:.]/g, \"-\")}`\n}\n\nfunction createPiInvocationArgs(input: {\n\tsessionDir?: string | null\n\tsessionPath?: string | null\n\tprompt: string\n\tappendedSystemPrompt?: string | null\n\textensionPath?: string | null\n}) {\n\tconst args: string[] = []\n\n\tif (input.extensionPath) args.push(\"--extension\", input.extensionPath)\n\tif (input.appendedSystemPrompt) args.push(\"--append-system-prompt\", input.appendedSystemPrompt)\n\tif (input.sessionPath) args.push(\"--session\", input.sessionPath)\n\telse if (input.sessionDir) args.push(\"--session-dir\", input.sessionDir)\n\telse throw new Error(\"Pi invocation requires a session path or session directory\")\n\targs.push(\"-p\", input.prompt)\n\n\treturn args\n}\n\nfunction writeJson(path: string, value: unknown) {\n\twriteFileSync(path, `${JSON.stringify(value, null, 2)}\\n`, \"utf-8\")\n}\n\nfunction writeText(path: string, value: string) {\n\twriteFileSync(path, value, \"utf-8\")\n}\n\nfunction createPiPrompt(input: {\n\trepoRoot: string\n\tplanPath: string | null\n\tgoal: string | null\n\trecommendedPlanDir: string | null\n}): string {\n\tconst goal = input.goal ?? \"continue from current scaffold state\"\n\n\tif (input.planPath) {\n\t\treturn [\n\t\t\t\"You are the Pi Town leader agent for this repository.\",\n\t\t\t\"Coordinate the next bounded unit of work, keep updates concise, and leave a durable artifact trail.\",\n\t\t\t\"\",\n\t\t\t\"Read the private plans in:\",\n\t\t\t`- ${input.planPath}`,\n\t\t\t\"\",\n\t\t\t\"and the current code in:\",\n\t\t\t`- ${input.repoRoot}`,\n\t\t\t\"\",\n\t\t\t`Goal: ${goal}`,\n\t\t\t\"Continue from the current scaffold state.\",\n\t\t\t\"Keep any persisted run artifacts high-signal and avoid copying private plan contents into them.\",\n\t\t].join(\"\\n\")\n\t}\n\n\treturn [\n\t\t\"You are the Pi Town leader agent for this repository.\",\n\t\t\"Coordinate the next bounded unit of work, keep updates concise, and leave a durable artifact trail.\",\n\t\t\"\",\n\t\t`Work in the repository at: ${input.repoRoot}`,\n\t\t`Goal: ${goal}`,\n\t\t\"No private plan path is configured for this run.\",\n\t\tinput.recommendedPlanDir\n\t\t\t? `If you need private plans, use a user-owned location such as: ${input.recommendedPlanDir}`\n\t\t\t: \"If you need private plans, keep them in a user-owned location outside the repo.\",\n\t\t\"Continue from the current scaffold state.\",\n\t].join(\"\\n\")\n}\n\nfunction assertPiRuntimeAvailable(piCommand: string) {\n\ttry {\n\t\tassertCommandAvailable(piCommand)\n\t} catch (error) {\n\t\tif (piCommand === \"pi\") {\n\t\t\tthrow new Error(\n\t\t\t\t[\n\t\t\t\t\t\"Pi Town requires the `pi` CLI to run `pitown run`.\",\n\t\t\t\t\t\"Install Pi: npm install -g @mariozechner/pi-coding-agent\",\n\t\t\t\t\t\"Then authenticate Pi and verify it works: pi -p \\\"hello\\\"\",\n\t\t\t\t\t`Details: ${(error as Error).message}`,\n\t\t\t\t].join(\"\\n\"),\n\t\t\t)\n\t\t}\n\n\t\tthrow new Error(\n\t\t\t[\n\t\t\t\t`Pi Town could not execute the configured Pi command: ${piCommand}`,\n\t\t\t\t\"Make sure the command exists on PATH or points to an executable file.\",\n\t\t\t\t`Details: ${(error as Error).message}`,\n\t\t\t].join(\"\\n\"),\n\t\t)\n\t}\n}\n\nfunction createManifest(input: {\n\trunId: string\n\trepoId: string\n\trepoSlug: string\n\trepoRoot: string\n\tbranch: string\n\tgoal: string | null\n\tplanPath: string | null\n\trecommendedPlanDir: string | null\n\tmode: \"single-pi\"\n\tleasePath: string\n}): RunManifest {\n\treturn {\n\t\trunId: input.runId,\n\t\trepoId: input.repoId,\n\t\trepoSlug: input.repoSlug,\n\t\trepoRoot: input.repoRoot,\n\t\tbranch: input.branch,\n\t\tgoal: input.goal,\n\t\tplanPath: input.planPath,\n\t\trecommendedPlanDir: input.recommendedPlanDir,\n\t\tmode: input.mode,\n\t\tstartedAt: new Date().toISOString(),\n\t\tendedAt: null,\n\t\tstopReason: null,\n\t\tleasePath: input.leasePath,\n\t\tpiExitCode: null,\n\t\tcompletedTaskCount: 0,\n\t\tblockedTaskCount: 0,\n\t\tskippedTaskCount: 0,\n\t\ttotalCostUsd: 0,\n\t}\n}\n\nfunction createSummary(input: {\n\trunId: string\n\tmode: \"single-pi\"\n\texitCode: number\n\tstdout: string\n\tstderr: string\n\trecommendedPlanDir: string | null\n}): RunSummary {\n\tconst success = input.exitCode === 0\n\tconst recommendation =\n\t\tinput.recommendedPlanDir === null\n\t\t\t? \"\"\n\t\t\t: ` No plan path was configured. Recommended private plans location: ${input.recommendedPlanDir}.`\n\tconst authHelp =\n\t\tsuccess || !detectPiAuthFailure(input.stderr, input.stdout) ? \"\" : ` ${createPiAuthHelpMessage()}`\n\n\treturn {\n\t\trunId: input.runId,\n\t\tmode: input.mode,\n\t\tcreatedAt: new Date().toISOString(),\n\t\tsuccess,\n\t\tmessage: success\n\t\t\t? `Pi invocation completed.${recommendation}`\n\t\t\t: `Pi invocation failed.${authHelp}${recommendation}`,\n\t\tpiExitCode: input.exitCode,\n\t\trecommendedPlanDir: input.recommendedPlanDir,\n\t}\n}\n\nexport function runController(options: RunOptions): ControllerRunResult {\n\tconst cwd = options.cwd ?? process.cwd()\n\tconst artifactsDir = options.artifactsDir\n\tconst repoRoot = getRepoRoot(cwd)\n\tconst repoId = getRepoIdentity(repoRoot)\n\tconst repoSlug = createRepoSlug(repoId, repoRoot)\n\tconst branch = options.branch ?? getCurrentBranch(repoRoot) ?? \"workspace\"\n\tconst goal = options.goal ?? null\n\tconst planPath = options.planPath ?? null\n\tconst recommendedPlanDir = planPath ? null : (options.recommendedPlanDir ?? null)\n\tconst mode = options.mode ?? \"single-pi\"\n\tconst piCommand = options.piCommand ?? \"pi\"\n\tconst runId = createRunId()\n\tconst runDir = join(artifactsDir, \"runs\", runId)\n\tconst latestDir = join(artifactsDir, \"latest\")\n\tconst stdoutPath = join(runDir, \"stdout.txt\")\n\tconst stderrPath = join(runDir, \"stderr.txt\")\n\tconst prompt = createPiPrompt({ repoRoot, planPath, goal, recommendedPlanDir })\n\tconst existingLeaderState = readAgentState(artifactsDir, \"leader\")\n\tconst existingLeaderSession =\n\t\texistingLeaderState?.session.sessionPath || existingLeaderState?.session.sessionDir\n\t\t\t? existingLeaderState.session\n\t\t\t: getLatestAgentSession(artifactsDir, \"leader\")\n\tconst leaderSessionDir = existingLeaderSession.sessionDir ?? getAgentSessionsDir(artifactsDir, \"leader\")\n\tconst leaderState = createAgentState({\n\t\tagentId: \"leader\",\n\t\trole: \"leader\",\n\t\tstatus: \"starting\",\n\t\ttask: goal,\n\t\tbranch,\n\t\tlastMessage: goal ? `Starting leader run for goal: ${goal}` : \"Starting leader run\",\n\t\trunId,\n\t\tsession: createAgentSessionRecord({\n\t\t\tsessionDir: leaderSessionDir,\n\t\t\tsessionId: existingLeaderSession.sessionId,\n\t\t\tsessionPath: existingLeaderSession.sessionPath,\n\t\t}),\n\t})\n\n\tassertPiRuntimeAvailable(piCommand)\n\n\tmkdirSync(runDir, { recursive: true })\n\tmkdirSync(latestDir, { recursive: true })\n\n\twriteText(join(runDir, \"questions.jsonl\"), \"\")\n\twriteText(join(runDir, \"interventions.jsonl\"), \"\")\n\twriteJson(join(runDir, \"agent-state.json\"), {\n\t\tstatus: \"starting\",\n\t\tupdatedAt: new Date().toISOString(),\n\t})\n\twriteAgentState(artifactsDir, leaderState)\n\n\tconst lease = acquireRepoLease(runId, repoId, branch)\n\n\ttry {\n\t\tconst manifest = createManifest({\n\t\t\trunId,\n\t\t\trepoId,\n\t\t\trepoSlug,\n\t\t\trepoRoot,\n\t\t\tbranch,\n\t\t\tgoal,\n\t\t\tplanPath,\n\t\t\trecommendedPlanDir,\n\t\t\tmode,\n\t\t\tleasePath: lease.path,\n\t\t})\n\n\t\tappendJsonl(join(runDir, \"events.jsonl\"), {\n\t\t\ttype: \"run_started\",\n\t\t\trunId,\n\t\t\trepoId,\n\t\t\trepoSlug,\n\t\t\tbranch,\n\t\t\tcreatedAt: manifest.startedAt,\n\t\t})\n\n\t\tconst piStartedAt = new Date().toISOString()\n\t\tappendJsonl(join(runDir, \"events.jsonl\"), {\n\t\t\ttype: \"pi_invocation_started\",\n\t\t\trunId,\n\t\t\tcommand: piCommand,\n\t\t\tcreatedAt: piStartedAt,\n\t\t})\n\n\t\twriteAgentState(\n\t\t\tartifactsDir,\n\t\t\tcreateAgentState({\n\t\t\t\t...leaderState,\n\t\t\t\tstatus: \"running\",\n\t\t\t\tlastMessage: goal ? `Leader working on: ${goal}` : \"Leader working\",\n\t\t\t}),\n\t\t)\n\n\t\tconst piArgs = createPiInvocationArgs({\n\t\t\tsessionDir: leaderState.session.sessionPath === null ? leaderSessionDir : null,\n\t\t\tsessionPath: leaderState.session.sessionPath,\n\t\t\tprompt,\n\t\t\tappendedSystemPrompt: options.appendedSystemPrompt,\n\t\t\textensionPath: options.extensionPath,\n\t\t})\n\t\tconst piResult = runCommandSync(piCommand, piArgs, {\n\t\t\tcwd: repoRoot,\n\t\t\tenv: process.env,\n\t\t})\n\t\tconst piEndedAt = new Date().toISOString()\n\t\tconst latestLeaderSession = getLatestAgentSession(artifactsDir, \"leader\")\n\n\t\twriteText(stdoutPath, piResult.stdout)\n\t\twriteText(stderrPath, piResult.stderr)\n\n\t\tconst piInvocation: PiInvocationRecord = {\n\t\t\tcommand: piCommand,\n\t\t\tcwd: repoRoot,\n\t\t\trepoRoot,\n\t\t\tplanPath,\n\t\t\tgoal,\n\t\t\tsessionDir: latestLeaderSession.sessionDir,\n\t\t\tsessionId: latestLeaderSession.sessionId,\n\t\t\tsessionPath: latestLeaderSession.sessionPath,\n\t\t\tstartedAt: piStartedAt,\n\t\t\tendedAt: piEndedAt,\n\t\t\texitCode: piResult.exitCode,\n\t\t\tstdoutPath,\n\t\t\tstderrPath,\n\t\t\tpromptSummary: planPath\n\t\t\t\t? \"Read private plan path and continue from current scaffold state.\"\n\t\t\t\t: \"Continue from current scaffold state without a configured private plan path.\",\n\t\t}\n\t\twriteJson(join(runDir, \"pi-invocation.json\"), piInvocation)\n\n\t\tappendJsonl(join(runDir, \"events.jsonl\"), {\n\t\t\ttype: \"pi_invocation_finished\",\n\t\t\trunId,\n\t\t\tcommand: piCommand,\n\t\t\texitCode: piInvocation.exitCode,\n\t\t\tcreatedAt: piEndedAt,\n\t\t})\n\n\t\tconst metrics = computeMetrics({\n\t\t\ttaskAttempts: [],\n\t\t\tinterrupts: [],\n\t\t})\n\t\tconst summary = createSummary({\n\t\t\trunId,\n\t\t\tmode,\n\t\t\texitCode: piInvocation.exitCode,\n\t\t\tstdout: piResult.stdout,\n\t\t\tstderr: piResult.stderr,\n\t\t\trecommendedPlanDir,\n\t\t})\n\t\tconst finalManifest: RunManifest = {\n\t\t\t...manifest,\n\t\t\tendedAt: piEndedAt,\n\t\t\tstopReason:\n\t\t\t\tpiInvocation.exitCode === 0\n\t\t\t\t\t? \"pi invocation completed\"\n\t\t\t\t\t: `pi invocation exited with code ${piInvocation.exitCode}`,\n\t\t\tpiExitCode: piInvocation.exitCode,\n\t\t}\n\n\t\twriteJson(join(runDir, \"manifest.json\"), finalManifest)\n\t\twriteJson(join(runDir, \"metrics.json\"), metrics)\n\t\twriteJson(join(runDir, \"run-summary.json\"), summary)\n\t\twriteJson(join(runDir, \"agent-state.json\"), {\n\t\t\tstatus: summary.success ? \"completed\" : \"failed\",\n\t\t\tupdatedAt: piEndedAt,\n\t\t\texitCode: piInvocation.exitCode,\n\t\t})\n\t\twriteJson(join(latestDir, \"manifest.json\"), finalManifest)\n\t\twriteJson(join(latestDir, \"metrics.json\"), metrics)\n\t\twriteJson(join(latestDir, \"run-summary.json\"), summary)\n\t\twriteAgentState(\n\t\t\tartifactsDir,\n\t\t\tcreateAgentState({\n\t\t\t\t...leaderState,\n\t\t\t\t\tstatus: piInvocation.exitCode === 0 ? \"idle\" : \"blocked\",\n\t\t\t\t\tlastMessage:\n\t\t\t\t\t\tpiInvocation.exitCode === 0\n\t\t\t\t\t\t\t? \"Leader run completed and is ready for the next instruction\"\n\t\t\t\t\t\t\t: `Leader run stopped with exit code ${piInvocation.exitCode}`,\n\t\t\t\t\tblocked: piInvocation.exitCode !== 0,\n\t\t\t\t\twaitingOn: piInvocation.exitCode === 0 ? null : \"human-or-follow-up-run\",\n\t\t\t\t\tsession: createAgentSessionRecord({\n\t\t\t\t\t\tsessionDir: latestLeaderSession.sessionDir,\n\t\t\t\t\t\tsessionId: latestLeaderSession.sessionId,\n\t\t\t\t\t\tsessionPath: latestLeaderSession.sessionPath,\n\t\t\t\t\t}),\n\t\t\t\t}),\n\t\t\t)\n\n\t\tappendJsonl(join(runDir, \"events.jsonl\"), {\n\t\t\ttype: \"run_finished\",\n\t\t\trunId,\n\t\t\tcreatedAt: finalManifest.endedAt,\n\t\t\tstopReason: finalManifest.stopReason,\n\t\t\tmetrics,\n\t\t})\n\n\t\treturn {\n\t\t\trunId,\n\t\t\trunDir,\n\t\t\tlatestDir,\n\t\t\tmanifest: finalManifest,\n\t\t\tmetrics,\n\t\t\tsummary,\n\t\t\tpiInvocation,\n\t\t}\n\t} finally {\n\t\tlease.release()\n\t}\n}\n","import { randomUUID } from \"node:crypto\"\nimport type { InterruptCategory, InterruptRecord } from \"./types.js\"\n\nexport interface CreateInterruptInput {\n\trunId: string\n\ttaskId?: string\n\tcategory: InterruptCategory\n\tsubtype?: string\n\tsummary: string\n\trequiresHuman?: boolean\n\tcreatedAt?: string\n}\n\nexport function createInterruptRecord(input: CreateInterruptInput): InterruptRecord {\n\treturn {\n\t\tid: randomUUID(),\n\t\trunId: input.runId,\n\t\tcategory: input.category,\n\t\tsummary: input.summary,\n\t\trequiresHuman: input.requiresHuman ?? true,\n\t\tcreatedAt: input.createdAt ?? new Date().toISOString(),\n\t\t...(input.taskId ? { taskId: input.taskId } : {}),\n\t\t...(input.subtype ? { subtype: input.subtype } : {}),\n\t}\n}\n\nexport function resolveInterrupt(\n\tinterrupt: InterruptRecord,\n\toptions: Pick<InterruptRecord, \"resolvedAt\" | \"fixType\">,\n): InterruptRecord {\n\treturn {\n\t\t...interrupt,\n\t\t...(options.resolvedAt ? { resolvedAt: options.resolvedAt } : {}),\n\t\t...(options.fixType ? { fixType: options.fixType } : {}),\n\t}\n}\n","import { mkdirSync, readFileSync, readdirSync, writeFileSync } from \"node:fs\"\nimport { dirname, join } from \"node:path\"\nimport type { TaskRecord, TaskStatus } from \"./types.js\"\n\nfunction writeJson(path: string, value: unknown) {\n\tmkdirSync(dirname(path), { recursive: true })\n\twriteFileSync(path, `${JSON.stringify(value, null, 2)}\\n`, \"utf-8\")\n}\n\nexport function getTasksDir(artifactsDir: string): string {\n\treturn join(artifactsDir, \"tasks\")\n}\n\nexport function getTaskPath(artifactsDir: string, taskId: string): string {\n\treturn join(getTasksDir(artifactsDir), `${taskId}.json`)\n}\n\nexport function createTaskRecord(input: {\n\ttaskId: string\n\ttitle: string\n\tstatus: TaskStatus\n\trole: string\n\tassignedAgentId: string\n\tcreatedBy: string\n}): TaskRecord {\n\tconst now = new Date().toISOString()\n\treturn {\n\t\ttaskId: input.taskId,\n\t\ttitle: input.title,\n\t\tstatus: input.status,\n\t\trole: input.role,\n\t\tassignedAgentId: input.assignedAgentId,\n\t\tcreatedBy: input.createdBy,\n\t\tcreatedAt: now,\n\t\tupdatedAt: now,\n\t}\n}\n\nexport function writeTaskRecord(artifactsDir: string, task: TaskRecord) {\n\twriteJson(getTaskPath(artifactsDir, task.taskId), task)\n}\n\nexport function updateTaskRecordStatus(artifactsDir: string, taskId: string, status: TaskStatus): TaskRecord | null {\n\tconst task = readTaskRecord(artifactsDir, taskId)\n\tif (task === null) return null\n\n\tconst updatedTask: TaskRecord = {\n\t\t...task,\n\t\tstatus,\n\t\tupdatedAt: new Date().toISOString(),\n\t}\n\twriteTaskRecord(artifactsDir, updatedTask)\n\treturn updatedTask\n}\n\nexport function readTaskRecord(artifactsDir: string, taskId: string): TaskRecord | null {\n\tconst path = getTaskPath(artifactsDir, taskId)\n\ttry {\n\t\treturn JSON.parse(readFileSync(path, \"utf-8\")) as TaskRecord\n\t} catch {\n\t\treturn null\n\t}\n}\n\nexport function listTaskRecords(artifactsDir: string): TaskRecord[] {\n\tconst tasksDir = getTasksDir(artifactsDir)\n\tlet entries: string[]\n\ttry {\n\t\tentries = readdirSync(tasksDir)\n\t} catch {\n\t\treturn []\n\t}\n\n\treturn entries\n\t\t.filter((entry) => entry.endsWith(\".json\"))\n\t\t.map((entry) => readTaskRecord(artifactsDir, entry.replace(/\\.json$/, \"\")))\n\t\t.filter((task): task is TaskRecord => task !== null)\n\t\t.sort((left, right) => left.taskId.localeCompare(right.taskId))\n}\n","import { mkdirSync, writeFileSync } from \"node:fs\"\nimport { join } from \"node:path\"\nimport { listAgentStates } from \"./agents.js\"\nimport { runController } from \"./controller.js\"\nimport { appendJsonl } from \"./events.js\"\nimport { computeMetrics } from \"./metrics.js\"\nimport { listTaskRecords } from \"./tasks.js\"\nimport type {\n\tBoardSnapshot,\n\tControllerRunResult,\n\tLoopIterationResult,\n\tLoopOptions,\n\tLoopRunResult,\n\tLoopStopReason,\n\tMetricsSnapshot,\n} from \"./types.js\"\n\nconst DEFAULT_MAX_ITERATIONS = 10\nconst DEFAULT_MAX_WALL_TIME_MS = 3_600_000\n\nfunction createLoopId(): string {\n\treturn `loop-${new Date().toISOString().replace(/[:.]/g, \"-\")}`\n}\n\nfunction writeJson(path: string, value: unknown) {\n\twriteFileSync(path, `${JSON.stringify(value, null, 2)}\\n`, \"utf-8\")\n}\n\nexport function snapshotBoard(artifactsDir: string): BoardSnapshot {\n\tconst tasks = listTaskRecords(artifactsDir)\n\tconst agents = listAgentStates(artifactsDir)\n\n\tconst taskEntries = tasks.map((task) => ({ taskId: task.taskId, status: task.status }))\n\tconst agentEntries = agents.map((agent) => ({\n\t\tagentId: agent.agentId,\n\t\tstatus: agent.status,\n\t\tblocked: agent.blocked,\n\t}))\n\n\tconst allTasksCompleted = tasks.length > 0 && tasks.every((task) => task.status === \"completed\")\n\tconst allRemainingTasksBlocked =\n\t\ttasks.length > 0 && tasks.every((task) => task.status === \"completed\" || task.status === \"blocked\")\n\n\tconst leader = agents.find((agent) => agent.agentId === \"leader\")\n\tconst leaderBlocked = leader?.blocked === true\n\n\tconst hasQueuedOrRunningWork =\n\t\tagents.some((agent) => agent.status === \"queued\" || agent.status === \"running\" || agent.status === \"starting\") ||\n\t\ttasks.some((task) => task.status === \"queued\" || task.status === \"running\")\n\n\treturn {\n\t\ttasks: taskEntries,\n\t\tagents: agentEntries,\n\t\tallTasksCompleted,\n\t\tallRemainingTasksBlocked,\n\t\tleaderBlocked,\n\t\thasQueuedOrRunningWork,\n\t}\n}\n\nexport function evaluateStopCondition(input: {\n\titeration: number\n\tmaxIterations: number\n\telapsedMs: number\n\tmaxWallTimeMs: number\n\tpiExitCode: number\n\tstopOnPiFailure: boolean\n\tboard: BoardSnapshot\n\tmetrics: MetricsSnapshot\n\tinterruptRateThreshold: number | null\n}): { stopReason: LoopStopReason | null; continueReason: string | null } {\n\tif (input.iteration >= input.maxIterations) {\n\t\treturn { stopReason: \"max-iterations-reached\", continueReason: null }\n\t}\n\n\tif (input.elapsedMs >= input.maxWallTimeMs) {\n\t\treturn { stopReason: \"max-wall-time-reached\", continueReason: null }\n\t}\n\n\tif (input.stopOnPiFailure && input.piExitCode !== 0) {\n\t\treturn { stopReason: \"pi-exit-nonzero\", continueReason: null }\n\t}\n\n\tif (input.board.allTasksCompleted) {\n\t\treturn { stopReason: \"all-tasks-completed\", continueReason: null }\n\t}\n\n\tif (input.board.leaderBlocked) {\n\t\treturn { stopReason: \"leader-blocked\", continueReason: null }\n\t}\n\n\tif (input.board.allRemainingTasksBlocked) {\n\t\treturn { stopReason: \"all-remaining-tasks-blocked\", continueReason: null }\n\t}\n\n\tif (\n\t\tinput.interruptRateThreshold !== null &&\n\t\tinput.metrics.interruptRate > input.interruptRateThreshold\n\t) {\n\t\treturn { stopReason: \"high-interrupt-rate\", continueReason: null }\n\t}\n\n\tconst reasons: string[] = []\n\tif (input.board.hasQueuedOrRunningWork) reasons.push(\"queued or running work remains\")\n\tif (input.board.tasks.length === 0) reasons.push(\"no tasks tracked yet\")\n\tif (reasons.length === 0) reasons.push(\"leader idle, no stop condition met\")\n\n\treturn { stopReason: null, continueReason: reasons.join(\"; \") }\n}\n\nfunction aggregateMetrics(iterations: LoopIterationResult[]): MetricsSnapshot {\n\tif (iterations.length === 0) {\n\t\treturn computeMetrics({ taskAttempts: [], interrupts: [] })\n\t}\n\n\tlet totalTaskAttempts = 0\n\tlet totalCompletedTasks = 0\n\tlet totalInterrupts = 0\n\tlet totalObservedInterruptCategories = 0\n\tlet totalCoveredInterruptCategories = 0\n\tlet interruptRateSum = 0\n\tlet autonomousCompletionRateSum = 0\n\tlet contextCoverageScoreSum = 0\n\tlet mttcValues: number[] = []\n\tlet ftdValues: number[] = []\n\n\tfor (const iter of iterations) {\n\t\tconst m = iter.metrics\n\t\ttotalTaskAttempts += m.totals.taskAttempts\n\t\ttotalCompletedTasks += m.totals.completedTasks\n\t\ttotalInterrupts += m.totals.interrupts\n\t\ttotalObservedInterruptCategories += m.totals.observedInterruptCategories\n\t\ttotalCoveredInterruptCategories += m.totals.coveredInterruptCategories\n\t\tinterruptRateSum += m.interruptRate\n\t\tautonomousCompletionRateSum += m.autonomousCompletionRate\n\t\tcontextCoverageScoreSum += m.contextCoverageScore\n\t\tif (m.meanTimeToCorrectHours !== null) mttcValues.push(m.meanTimeToCorrectHours)\n\t\tif (m.feedbackToDemoCycleTimeHours !== null) ftdValues.push(m.feedbackToDemoCycleTimeHours)\n\t}\n\n\tconst count = iterations.length\n\tconst round = (v: number) => Math.round(v * 1000) / 1000\n\tconst avg = (values: number[]) => (values.length === 0 ? null : round(values.reduce((s, v) => s + v, 0) / values.length))\n\n\treturn {\n\t\tinterruptRate: round(interruptRateSum / count),\n\t\tautonomousCompletionRate: round(autonomousCompletionRateSum / count),\n\t\tcontextCoverageScore: round(contextCoverageScoreSum / count),\n\t\tmeanTimeToCorrectHours: avg(mttcValues),\n\t\tfeedbackToDemoCycleTimeHours: avg(ftdValues),\n\t\ttotals: {\n\t\t\ttaskAttempts: totalTaskAttempts,\n\t\t\tcompletedTasks: totalCompletedTasks,\n\t\t\tinterrupts: totalInterrupts,\n\t\t\tobservedInterruptCategories: totalObservedInterruptCategories,\n\t\t\tcoveredInterruptCategories: totalCoveredInterruptCategories,\n\t\t},\n\t}\n}\n\nexport function runLoop(options: LoopOptions): LoopRunResult {\n\tconst maxIterations = options.maxIterations ?? DEFAULT_MAX_ITERATIONS\n\tconst maxWallTimeMs = options.maxWallTimeMs ?? DEFAULT_MAX_WALL_TIME_MS\n\tconst stopOnPiFailure = options.stopOnPiFailure ?? true\n\tconst interruptRateThreshold = options.interruptRateThreshold ?? null\n\tconst loopId = createLoopId()\n\tconst artifactsDir = options.runOptions.artifactsDir\n\tconst loopDir = join(artifactsDir, \"loops\", loopId)\n\n\tmkdirSync(loopDir, { recursive: true })\n\n\tconst loopStartedAt = Date.now()\n\tconst iterations: LoopIterationResult[] = []\n\tlet finalStopReason: LoopStopReason = \"max-iterations-reached\"\n\n\tappendJsonl(join(loopDir, \"events.jsonl\"), {\n\t\ttype: \"loop_started\",\n\t\tloopId,\n\t\tmaxIterations,\n\t\tmaxWallTimeMs,\n\t\tstopOnPiFailure,\n\t\tcreatedAt: new Date().toISOString(),\n\t})\n\n\tfor (let iteration = 1; iteration <= maxIterations; iteration++) {\n\t\tconst iterationStart = Date.now()\n\n\t\tlet controllerResult: ControllerRunResult\n\t\ttry {\n\t\t\tcontrollerResult = runController(options.runOptions)\n\t\t} catch (error) {\n\t\t\t// If controller fails to run (e.g. lease issue), record and stop\n\t\t\tappendJsonl(join(loopDir, \"events.jsonl\"), {\n\t\t\t\ttype: \"loop_iteration_error\",\n\t\t\t\tloopId,\n\t\t\t\titeration,\n\t\t\t\terror: (error as Error).message,\n\t\t\t\tcreatedAt: new Date().toISOString(),\n\t\t\t})\n\t\t\tfinalStopReason = \"pi-exit-nonzero\"\n\t\t\tbreak\n\t\t}\n\n\t\tconst iterationElapsedMs = Date.now() - iterationStart\n\t\tconst totalElapsedMs = Date.now() - loopStartedAt\n\t\tconst board = snapshotBoard(artifactsDir)\n\t\tconst metrics = controllerResult.metrics\n\n\t\tconst { stopReason, continueReason } = evaluateStopCondition({\n\t\t\titeration,\n\t\t\tmaxIterations,\n\t\t\telapsedMs: totalElapsedMs,\n\t\t\tmaxWallTimeMs,\n\t\t\tpiExitCode: controllerResult.piInvocation.exitCode,\n\t\t\tstopOnPiFailure,\n\t\t\tboard,\n\t\t\tmetrics,\n\t\t\tinterruptRateThreshold,\n\t\t})\n\n\t\tconst iterationResult: LoopIterationResult = {\n\t\t\titeration,\n\t\t\tcontrollerResult,\n\t\t\tboardSnapshot: board,\n\t\t\tmetrics,\n\t\t\telapsedMs: iterationElapsedMs,\n\t\t\tcontinueReason,\n\t\t\tstopReason,\n\t\t}\n\n\t\titerations.push(iterationResult)\n\n\t\twriteJson(join(loopDir, `iteration-${iteration}.json`), {\n\t\t\titeration,\n\t\t\trunId: controllerResult.runId,\n\t\t\tboardSnapshot: board,\n\t\t\tmetrics,\n\t\t\telapsedMs: iterationElapsedMs,\n\t\t\tcontinueReason,\n\t\t\tstopReason,\n\t\t})\n\n\t\tappendJsonl(join(loopDir, \"events.jsonl\"), {\n\t\t\ttype: \"loop_iteration_completed\",\n\t\t\tloopId,\n\t\t\titeration,\n\t\t\trunId: controllerResult.runId,\n\t\t\tpiExitCode: controllerResult.piInvocation.exitCode,\n\t\t\tstopReason,\n\t\t\tcontinueReason,\n\t\t\tcreatedAt: new Date().toISOString(),\n\t\t})\n\n\t\tif (options.onIterationComplete) {\n\t\t\toptions.onIterationComplete(iterationResult)\n\t\t}\n\n\t\tif (stopReason !== null) {\n\t\t\tfinalStopReason = stopReason\n\t\t\tbreak\n\t\t}\n\t}\n\n\tconst totalElapsedMs = Date.now() - loopStartedAt\n\tconst finalBoard = iterations.length > 0 ? iterations[iterations.length - 1].boardSnapshot : snapshotBoard(artifactsDir)\n\tconst aggregate = aggregateMetrics(iterations)\n\n\tconst loopResult: LoopRunResult = {\n\t\tloopId,\n\t\titerations,\n\t\tstopReason: finalStopReason,\n\t\ttotalIterations: iterations.length,\n\t\ttotalElapsedMs,\n\t\tfinalBoardSnapshot: finalBoard,\n\t\taggregateMetrics: aggregate,\n\t}\n\n\twriteJson(join(loopDir, \"loop-summary.json\"), {\n\t\tloopId,\n\t\tstopReason: finalStopReason,\n\t\ttotalIterations: iterations.length,\n\t\ttotalElapsedMs,\n\t\tfinalBoardSnapshot: finalBoard,\n\t\taggregateMetrics: aggregate,\n\t})\n\n\tappendJsonl(join(loopDir, \"events.jsonl\"), {\n\t\ttype: \"loop_finished\",\n\t\tloopId,\n\t\tstopReason: finalStopReason,\n\t\ttotalIterations: iterations.length,\n\t\ttotalElapsedMs,\n\t\tcreatedAt: new Date().toISOString(),\n\t})\n\n\treturn loopResult\n}\n","import { writeFileSync } from \"node:fs\"\nimport {\n\tappendAgentMessage,\n\tcreateAgentSessionRecord,\n\tcreateAgentState,\n\tgetAgentDir,\n\tgetAgentSessionsDir,\n\tgetLatestAgentSession,\n\treadAgentState,\n\twriteAgentState,\n} from \"./agents.js\"\nimport { createTaskRecord, updateTaskRecordStatus, writeTaskRecord } from \"./tasks.js\"\nimport { assertCommandAvailable, runCommandSync } from \"./shell.js\"\nimport type { AgentSessionRecord, AgentStateSnapshot, TaskRecord } from \"./types.js\"\n\nexport interface SpawnAgentRunOptions {\n\trepoRoot: string\n\tartifactsDir: string\n\trole: string\n\tagentId: string\n\ttask: string | null\n\tappendedSystemPrompt?: string | null\n\textensionPath?: string | null\n\ttaskId?: string | null\n}\n\nexport interface SpawnAgentRunResult {\n\tpiResult: { stdout: string; stderr: string; exitCode: number }\n\tlatestSession: AgentSessionRecord\n\tcompletionMessage: string\n}\n\nexport interface DelegateTaskOptions {\n\trepoRoot: string\n\tartifactsDir: string\n\tfromAgentId: string\n\trole: string\n\tagentId?: string | null\n\tappendedSystemPrompt?: string | null\n\textensionPath?: string | null\n\ttask: string\n}\n\nexport interface DelegateTaskResult {\n\ttask: TaskRecord\n\tagentId: string\n\tpiResult: { stdout: string; stderr: string; exitCode: number }\n\tlatestSession: AgentSessionRecord\n}\n\nexport interface ResolvedAgentSession {\n\tstate: AgentStateSnapshot\n\tsession: AgentSessionRecord\n}\n\nexport interface RunAgentTurnOptions {\n\trepoRoot: string\n\tartifactsDir: string\n\tagentId: string\n\tmessage: string\n\tfrom?: string\n\truntimeArgs?: string[] | null\n}\n\nexport interface RunAgentTurnResult {\n\tpiResult: { stdout: string; stderr: string; exitCode: number }\n\tlatestSession: AgentSessionRecord\n\tcompletionMessage: string\n}\n\nfunction createPiInvocationArgs(input: {\n\tsessionDir?: string | null\n\tsessionPath?: string | null\n\tprompt?: string | null\n\tappendedSystemPrompt?: string | null\n\textensionPath?: string | null\n}): string[] {\n\tconst args: string[] = []\n\n\tif (input.extensionPath) args.push(\"--extension\", input.extensionPath)\n\tif (input.appendedSystemPrompt) args.push(\"--append-system-prompt\", input.appendedSystemPrompt)\n\tif (input.sessionPath) args.push(\"--session\", input.sessionPath)\n\telse if (input.sessionDir) args.push(\"--session-dir\", input.sessionDir)\n\telse throw new Error(\"Pi invocation requires a session path or session directory\")\n\tif (input.prompt) args.push(\"-p\", input.prompt)\n\n\treturn args\n}\n\nexport function createRolePrompt(input: { role: string; task: string | null; repoRoot: string }): string {\n\tconst task = input.task ?? \"pick the next bounded task from the current repo context\"\n\n\tswitch (input.role) {\n\t\tcase \"leader\":\n\t\t\treturn [\n\t\t\t\t\"You are the Pi Town leader.\",\n\t\t\t\t\"You coordinate work for this repository and act as the primary human-facing agent.\",\n\t\t\t\t\"\",\n\t\t\t\t`Repository: ${input.repoRoot}`,\n\t\t\t\t`Task: ${task}`,\n\t\t\t\t\"Keep updates concise, choose bounded next steps, and leave a durable artifact trail.\",\n\t\t\t].join(\"\\n\")\n\t\tcase \"reviewer\":\n\t\t\treturn [\n\t\t\t\t\"You are the Pi Town reviewer.\",\n\t\t\t\t\"You review work for correctness, safety, and completeness.\",\n\t\t\t\t\"\",\n\t\t\t\t`Repository: ${input.repoRoot}`,\n\t\t\t\t`Task: ${task}`,\n\t\t\t\t\"Focus on validation confidence, regressions, and whether the output is ready for a human handoff.\",\n\t\t\t].join(\"\\n\")\n\t\tcase \"docs-keeper\":\n\t\t\treturn [\n\t\t\t\t\"You are the Pi Town docs keeper.\",\n\t\t\t\t\"You summarize outcomes, blockers, and continuity in compact factual language.\",\n\t\t\t\t\"\",\n\t\t\t\t`Repository: ${input.repoRoot}`,\n\t\t\t\t`Task: ${task}`,\n\t\t\t\t\"Keep the output concise and useful for the next run or human review.\",\n\t\t\t].join(\"\\n\")\n\t\tdefault:\n\t\t\treturn [\n\t\t\t\t\"You are the Pi Town worker.\",\n\t\t\t\t\"You implement one bounded task at a time.\",\n\t\t\t\t\"\",\n\t\t\t\t`Repository: ${input.repoRoot}`,\n\t\t\t\t`Task: ${task}`,\n\t\t\t\t\"Keep scope tight, prefer explicit validations, and summarize what changed and what still needs follow-up.\",\n\t\t\t].join(\"\\n\")\n\t}\n}\n\nexport function resolveAgentSession(agentId: string, artifactsDir: string): ResolvedAgentSession {\n\tconst state = readAgentState(artifactsDir, agentId)\n\tif (state === null) throw new Error(`Unknown agent: ${agentId}`)\n\n\tconst latestSession = getLatestAgentSession(artifactsDir, agentId)\n\tconst sessionPath = state.session.sessionPath ?? latestSession.sessionPath\n\tconst sessionId = state.session.sessionId ?? latestSession.sessionId\n\tconst sessionDir = state.session.sessionDir ?? latestSession.sessionDir ?? getAgentSessionsDir(artifactsDir, agentId)\n\n\tif (sessionPath === null) {\n\t\tthrow new Error(`Agent ${agentId} does not have a persisted Pi session yet.`)\n\t}\n\n\treturn {\n\t\tstate,\n\t\tsession: createAgentSessionRecord({\n\t\t\tsessionDir,\n\t\t\tsessionId,\n\t\t\tsessionPath,\n\t\t\tlastAttachedAt: new Date().toISOString(),\n\t\t}),\n\t}\n}\n\nexport function queueAgentMessage(input: { artifactsDir: string; agentId: string; from: string; body: string }) {\n\tconst state = readAgentState(input.artifactsDir, input.agentId)\n\tif (state === null) throw new Error(`Unknown agent: ${input.agentId}`)\n\n\tappendAgentMessage({\n\t\tartifactsDir: input.artifactsDir,\n\t\tagentId: input.agentId,\n\t\tbox: \"inbox\",\n\t\tfrom: input.from,\n\t\tbody: input.body,\n\t})\n\n\twriteAgentState(\n\t\tinput.artifactsDir,\n\t\tcreateAgentState({\n\t\t\t...state,\n\t\t\tstatus: state.status === \"idle\" ? \"queued\" : state.status,\n\t\t\tlastMessage: input.body,\n\t\t\twaitingOn: null,\n\t\t\tblocked: false,\n\t\t\tsession: createAgentSessionRecord({\n\t\t\t\tsessionDir: state.session.sessionDir ?? getAgentSessionsDir(input.artifactsDir, input.agentId),\n\t\t\t\tsessionId: state.session.sessionId,\n\t\t\t\tsessionPath: state.session.sessionPath,\n\t\t\t\tlastAttachedAt: state.session.lastAttachedAt,\n\t\t\t}),\n\t\t}),\n\t)\n}\n\nexport function updateAgentStatus(input: {\n\tartifactsDir: string\n\tagentId: string\n\tstatus: \"queued\" | \"running\" | \"idle\" | \"blocked\" | \"completed\" | \"failed\"\n\tlastMessage?: string | null\n\twaitingOn?: string | null\n\tblocked?: boolean\n}) {\n\tconst state = readAgentState(input.artifactsDir, input.agentId)\n\tif (state === null) throw new Error(`Unknown agent: ${input.agentId}`)\n\n\tif (state.taskId) {\n\t\tconst taskStatus =\n\t\t\tinput.status === \"completed\"\n\t\t\t\t? \"completed\"\n\t\t\t\t: input.status === \"blocked\" || input.status === \"failed\"\n\t\t\t\t\t? \"blocked\"\n\t\t\t\t\t: input.status === \"running\" || input.status === \"queued\"\n\t\t\t\t\t\t? \"running\"\n\t\t\t\t\t\t: null\n\t\tif (taskStatus) updateTaskRecordStatus(input.artifactsDir, state.taskId, taskStatus)\n\t}\n\n\twriteAgentState(\n\t\tinput.artifactsDir,\n\t\tcreateAgentState({\n\t\t\t...state,\n\t\t\tstatus: input.status,\n\t\t\tlastMessage: input.lastMessage ?? state.lastMessage,\n\t\t\twaitingOn: input.waitingOn ?? state.waitingOn,\n\t\t\tblocked: input.blocked ?? state.blocked,\n\t\t\tsession: state.session,\n\t\t}),\n\t)\n}\n\nexport function spawnAgentRun(options: SpawnAgentRunOptions): SpawnAgentRunResult {\n\tconst sessionDir = getAgentSessionsDir(options.artifactsDir, options.agentId)\n\n\tif (readAgentState(options.artifactsDir, options.agentId) !== null) {\n\t\tthrow new Error(`Agent already exists: ${options.agentId}`)\n\t}\n\n\tassertCommandAvailable(\"pi\")\n\n\tconst state = createAgentState({\n\t\tagentId: options.agentId,\n\t\trole: options.role,\n\t\tstatus: \"queued\",\n\t\ttaskId: options.taskId ?? null,\n\t\ttask: options.task,\n\t\tlastMessage: options.task ? `Spawned with task: ${options.task}` : `Spawned ${options.role} agent`,\n\t\tsession: createAgentSessionRecord({\n\t\t\tsessionDir,\n\t\t}),\n\t})\n\twriteAgentState(options.artifactsDir, state)\n\tif (options.task) {\n\t\tappendAgentMessage({\n\t\t\tartifactsDir: options.artifactsDir,\n\t\t\tagentId: options.agentId,\n\t\t\tbox: \"inbox\",\n\t\t\tfrom: \"system\",\n\t\t\tbody: options.task,\n\t\t})\n\t}\n\n\twriteAgentState(\n\t\toptions.artifactsDir,\n\t\tcreateAgentState({\n\t\t\t...state,\n\t\t\tstatus: \"running\",\n\t\t\tlastMessage: options.task ? `Running ${options.role} task: ${options.task}` : `Running ${options.role} agent`,\n\t\t}),\n\t)\n\n\tconst prompt = createRolePrompt({ role: options.role, task: options.task, repoRoot: options.repoRoot })\n\tconst piArgs = createPiInvocationArgs({\n\t\tsessionDir,\n\t\tprompt,\n\t\tappendedSystemPrompt: options.appendedSystemPrompt,\n\t\textensionPath: options.extensionPath,\n\t})\n\tconst piResult = runCommandSync(\"pi\", piArgs, {\n\t\tcwd: options.repoRoot,\n\t\tenv: process.env,\n\t})\n\tconst latestSession = getLatestAgentSession(options.artifactsDir, options.agentId)\n\tconst agentArtifactsDir = getAgentDir(options.artifactsDir, options.agentId)\n\twriteFileSync(`${agentArtifactsDir}/latest-stdout.txt`, piResult.stdout, \"utf-8\")\n\twriteFileSync(`${agentArtifactsDir}/latest-stderr.txt`, piResult.stderr, \"utf-8\")\n\twriteFileSync(\n\t\t`${agentArtifactsDir}/latest-invocation.json`,\n\t\t`${JSON.stringify(\n\t\t\t{\n\t\t\t\tcommand: \"pi\",\n\t\t\t\targs: piArgs,\n\t\t\t\texitCode: piResult.exitCode,\n\t\t\t\tsessionDir,\n\t\t\t\tsessionPath: latestSession.sessionPath,\n\t\t\t\tsessionId: latestSession.sessionId,\n\t\t\t},\n\t\t\tnull,\n\t\t\t2,\n\t\t)}\\n`,\n\t\t\"utf-8\",\n\t)\n\n\tconst completionMessage =\n\t\tpiResult.stdout.trim() ||\n\t\t(piResult.exitCode === 0 ? `${options.role} run completed` : `${options.role} run exited with code ${piResult.exitCode}`)\n\tappendAgentMessage({\n\t\tartifactsDir: options.artifactsDir,\n\t\tagentId: options.agentId,\n\t\tbox: \"outbox\",\n\t\tfrom: options.agentId,\n\t\tbody: completionMessage,\n\t})\n\twriteAgentState(\n\t\toptions.artifactsDir,\n\t\tcreateAgentState({\n\t\t\t...state,\n\t\t\tstatus: piResult.exitCode === 0 ? \"idle\" : \"blocked\",\n\t\t\tlastMessage: completionMessage,\n\t\t\tblocked: piResult.exitCode !== 0,\n\t\t\twaitingOn: piResult.exitCode === 0 ? null : \"human-or-follow-up-run\",\n\t\t\tsession: createAgentSessionRecord({\n\t\t\t\tsessionDir: latestSession.sessionDir,\n\t\t\t\tsessionId: latestSession.sessionId,\n\t\t\t\tsessionPath: latestSession.sessionPath,\n\t\t\t}),\n\t\t}),\n\t)\n\n\treturn { piResult, latestSession, completionMessage }\n}\n\nexport function runAgentTurn(options: RunAgentTurnOptions): RunAgentTurnResult {\n\tassertCommandAvailable(\"pi\")\n\n\tconst resolved = resolveAgentSession(options.agentId, options.artifactsDir)\n\tconst messageSource = options.from ?? \"human\"\n\twriteAgentState(\n\t\toptions.artifactsDir,\n\t\tcreateAgentState({\n\t\t\t...resolved.state,\n\t\t\tstatus: \"running\",\n\t\t\tlastMessage: `Responding to ${messageSource}: ${options.message}`,\n\t\t\twaitingOn: null,\n\t\t\tblocked: false,\n\t\t\tsession: resolved.session,\n\t\t}),\n\t)\n\n\tconst piArgs =\n\t\toptions.runtimeArgs && options.runtimeArgs.length > 0\n\t\t\t? options.runtimeArgs\n\t\t\t: createPiInvocationArgs({\n\t\t\t\t\tsessionPath: resolved.session.sessionPath,\n\t\t\t\t\tprompt: options.message,\n\t\t\t\t})\n\tconst piResult = runCommandSync(\"pi\", piArgs, {\n\t\tcwd: options.repoRoot,\n\t\tenv: process.env,\n\t})\n\tconst latestSession = getLatestAgentSession(options.artifactsDir, options.agentId)\n\tconst agentArtifactsDir = getAgentDir(options.artifactsDir, options.agentId)\n\twriteFileSync(`${agentArtifactsDir}/latest-stdout.txt`, piResult.stdout, \"utf-8\")\n\twriteFileSync(`${agentArtifactsDir}/latest-stderr.txt`, piResult.stderr, \"utf-8\")\n\twriteFileSync(\n\t\t`${agentArtifactsDir}/latest-invocation.json`,\n\t\t`${JSON.stringify(\n\t\t\t{\n\t\t\t\tcommand: \"pi\",\n\t\t\t\targs: piArgs,\n\t\t\t\texitCode: piResult.exitCode,\n\t\t\t\tsessionDir: latestSession.sessionDir,\n\t\t\t\tsessionPath: latestSession.sessionPath,\n\t\t\t\tsessionId: latestSession.sessionId,\n\t\t\t},\n\t\t\tnull,\n\t\t\t2,\n\t\t)}\\n`,\n\t\t\"utf-8\",\n\t)\n\n\tconst completionMessage =\n\t\tpiResult.stdout.trim() ||\n\t\t(piResult.exitCode === 0\n\t\t\t? `${resolved.state.role} turn completed`\n\t\t\t: `${resolved.state.role} turn exited with code ${piResult.exitCode}`)\n\tappendAgentMessage({\n\t\tartifactsDir: options.artifactsDir,\n\t\tagentId: options.agentId,\n\t\tbox: \"outbox\",\n\t\tfrom: options.agentId,\n\t\tbody: completionMessage,\n\t})\n\n\twriteAgentState(\n\t\toptions.artifactsDir,\n\t\tcreateAgentState({\n\t\t\t...resolved.state,\n\t\t\tstatus: piResult.exitCode === 0 ? \"idle\" : \"blocked\",\n\t\t\tlastMessage: completionMessage,\n\t\t\twaitingOn: piResult.exitCode === 0 ? null : \"human-or-follow-up-run\",\n\t\t\tblocked: piResult.exitCode !== 0,\n\t\t\tsession: createAgentSessionRecord({\n\t\t\t\tsessionDir: latestSession.sessionDir,\n\t\t\t\tsessionId: latestSession.sessionId,\n\t\t\t\tsessionPath: latestSession.sessionPath,\n\t\t\t}),\n\t\t}),\n\t)\n\n\treturn { piResult, latestSession, completionMessage }\n}\n\nexport function delegateTask(options: DelegateTaskOptions): DelegateTaskResult {\n\tconst fromState = readAgentState(options.artifactsDir, options.fromAgentId)\n\tif (fromState === null) throw new Error(`Unknown delegating agent: ${options.fromAgentId}`)\n\n\tconst agentId = options.agentId ?? `${options.role}-${Date.now()}`\n\tconst task = createTaskRecord({\n\t\ttaskId: `task-${Date.now()}`,\n\t\ttitle: options.task,\n\t\tstatus: \"queued\",\n\t\trole: options.role,\n\t\tassignedAgentId: agentId,\n\t\tcreatedBy: options.fromAgentId,\n\t})\n\twriteTaskRecord(options.artifactsDir, task)\n\n\tappendAgentMessage({\n\t\tartifactsDir: options.artifactsDir,\n\t\tagentId: options.fromAgentId,\n\t\tbox: \"outbox\",\n\t\tfrom: options.fromAgentId,\n\t\tbody: `Delegated ${task.taskId} to ${agentId}: ${options.task}`,\n\t})\n\n\tconst { piResult, latestSession } = spawnAgentRun({\n\t\trepoRoot: options.repoRoot,\n\t\tartifactsDir: options.artifactsDir,\n\t\trole: options.role,\n\t\tagentId,\n\t\tappendedSystemPrompt: options.appendedSystemPrompt,\n\t\textensionPath: options.extensionPath,\n\t\ttask: options.task,\n\t\ttaskId: task.taskId,\n\t})\n\n\tappendAgentMessage({\n\t\tartifactsDir: options.artifactsDir,\n\t\tagentId,\n\t\tbox: \"inbox\",\n\t\tfrom: options.fromAgentId,\n\t\tbody: `Delegated by ${options.fromAgentId} as ${task.taskId}: ${options.task}`,\n\t})\n\n\twriteTaskRecord(options.artifactsDir, {\n\t\t...task,\n\t\tstatus: piResult.exitCode === 0 ? \"completed\" : \"blocked\",\n\t\tupdatedAt: new Date().toISOString(),\n\t})\n\n\treturn {\n\t\ttask: {\n\t\t\t...task,\n\t\t\tstatus: piResult.exitCode === 0 ? \"completed\" : \"blocked\",\n\t\t\tupdatedAt: new Date().toISOString(),\n\t\t},\n\t\tagentId,\n\t\tpiResult,\n\t\tlatestSession,\n\t}\n}\n"],"mappings":";;;;;;;AAGA,SAAgB,YAAY,UAAkB,OAAgB;AAC7D,WAAU,QAAQ,SAAS,EAAE,EAAE,WAAW,MAAM,CAAC;AACjD,eAAc,UAAU,GAAG,KAAK,UAAU,MAAM,CAAC,KAAK;EAAE,UAAU;EAAS,MAAM;EAAK,CAAC;;AAGxF,SAAgB,UAAa,UAAuB;AACnD,KAAI;AAEH,SADY,aAAa,UAAU,QAAQ,CAEzC,MAAM,QAAQ,CACd,KAAK,SAAS,KAAK,MAAM,CAAC,CAC1B,OAAO,QAAQ,CACf,KAAK,SAAS,KAAK,MAAM,KAAK,CAAM;SAC/B;AACP,SAAO,EAAE;;;;;;ACNX,SAASA,YAAU,MAAc,OAAgB;AAChD,WAAU,QAAQ,KAAK,EAAE,EAAE,WAAW,MAAM,CAAC;AAC7C,eAAc,MAAM,GAAG,KAAK,UAAU,OAAO,MAAM,EAAE,CAAC,KAAK,QAAQ;;AAGpE,SAAS,cAAc,MAAc;AACpC,WAAU,QAAQ,KAAK,EAAE,EAAE,WAAW,MAAM,CAAC;AAC7C,KAAI,CAAC,WAAW,KAAK,CAAE,eAAc,MAAM,IAAI,QAAQ;;AAGxD,SAAgB,aAAa,cAA8B;AAC1D,QAAO,KAAK,cAAc,SAAS;;AAGpC,SAAgB,YAAY,cAAsB,SAAyB;AAC1E,QAAO,KAAK,aAAa,aAAa,EAAE,QAAQ;;AAGjD,SAAgB,kBAAkB,cAAsB,SAAyB;AAChF,QAAO,KAAK,YAAY,cAAc,QAAQ,EAAE,aAAa;;AAG9D,SAAgB,oBAAoB,cAAsB,SAAyB;AAClF,QAAO,KAAK,YAAY,cAAc,QAAQ,EAAE,eAAe;;AAGhE,SAAgB,oBAAoB,cAAsB,SAAiB,KAA2B;AACrG,QAAO,KAAK,YAAY,cAAc,QAAQ,EAAE,GAAG,IAAI,QAAQ;;AAGhE,SAAgB,oBAAoB,cAAsB,SAAyB;AAClF,QAAO,KAAK,YAAY,cAAc,QAAQ,EAAE,WAAW;;AAG5D,SAAgB,qBAAqB,aAAuD;AAC3F,KAAI,CAAC,YAAa,QAAO;AAEzB,QADc,yBAAyB,KAAK,YAAY,GACzC,MAAM;;AAGtB,SAAgB,yBACf,OACqB;AACrB,QAAO;EACN,SAAS;EACT,WAAW;EACX,YAAY,OAAO,cAAc;EACjC,WAAW,OAAO,aAAa;EAC/B,aAAa,OAAO,eAAe;EACnC,gBAAgB,OAAO,kBAAkB;EACzC;;AAGF,SAAgB,iBAAiB,OAYV;AACtB,QAAO;EACN,SAAS,MAAM;EACf,MAAM,MAAM;EACZ,QAAQ,MAAM;EACd,QAAQ,MAAM,UAAU;EACxB,MAAM,MAAM,QAAQ;EACpB,QAAQ,MAAM,UAAU;EACxB,4BAAW,IAAI,MAAM,EAAC,aAAa;EACnC,aAAa,MAAM,eAAe;EAClC,WAAW,MAAM,aAAa;EAC9B,SAAS,MAAM,WAAW;EAC1B,OAAO,MAAM,SAAS;EACtB,SAAS,MAAM,WAAW,0BAA0B;EACpD;;AAGF,SAAgB,gBAAgB,cAAsB,OAA2B;AAChF,WAAU,YAAY,cAAc,MAAM,QAAQ,EAAE,EAAE,WAAW,MAAM,CAAC;AACxE,eAAc,oBAAoB,cAAc,MAAM,SAAS,QAAQ,CAAC;AACxE,eAAc,oBAAoB,cAAc,MAAM,SAAS,SAAS,CAAC;AACzE,aAAU,kBAAkB,cAAc,MAAM,QAAQ,EAAE,MAAM;AAChE,aAAU,oBAAoB,cAAc,MAAM,QAAQ,EAAE,MAAM,QAAQ;;AAG3E,SAAgB,eAAe,cAAsB,SAA4C;CAChG,MAAM,YAAY,kBAAkB,cAAc,QAAQ;AAC1D,KAAI;AACH,SAAO,KAAK,MAAM,aAAa,WAAW,QAAQ,CAAC;SAC5C;AACP,SAAO;;;AAIT,SAAgB,gBAAgB,cAA4C;CAC3E,MAAM,YAAY,aAAa,aAAa;CAC5C,IAAI;AACJ,KAAI;AACH,YAAU,YAAY,UAAU;SACzB;AACP,SAAO,EAAE;;AAGV,QAAO,QACL,KAAK,UAAU,eAAe,cAAc,MAAM,CAAC,CACnD,QAAQ,UAAuC,UAAU,KAAK,CAC9D,MAAM,MAAM,UAAU,KAAK,QAAQ,cAAc,MAAM,QAAQ,CAAC;;AAGnE,SAAgB,mBAAmB,OAMZ;CACtB,MAAM,SAA6B;EAClC,KAAK,MAAM;EACX,MAAM,MAAM;EACZ,MAAM,MAAM;EACZ,4BAAW,IAAI,MAAM,EAAC,aAAa;EACnC;AACD,aAAY,oBAAoB,MAAM,cAAc,MAAM,SAAS,MAAM,IAAI,EAAE,OAAO;AACtF,QAAO;;AAGR,SAAgB,kBAAkB,cAAsB,SAAiB,KAAyC;AACjH,QAAO,UAA8B,oBAAoB,cAAc,SAAS,IAAI,CAAC;;AAGtF,SAAgB,sBAAsB,cAAsB,SAAqC;CAChG,MAAM,aAAa,oBAAoB,cAAc,QAAQ;CAC7D,IAAI;AACJ,KAAI;AACH,YAAU,YAAY,WAAW;SAC1B;AACP,SAAO,yBAAyB,EAAE,YAAY,CAAC;;CAGhD,MAAM,oBACL,QACE,QAAQ,UAAU,MAAM,SAAS,SAAS,CAAC,CAC3C,MAAM,CACN,GAAG,GAAG,IAAI;AAEb,KAAI,sBAAsB,KAAM,QAAO,yBAAyB,EAAE,YAAY,CAAC;CAE/E,MAAM,cAAc,KAAK,YAAY,kBAAkB;AACvD,QAAO,yBAAyB;EAC/B;EACA;EACA,WAAW,qBAAqB,YAAY;EAC5C,CAAC;;;;;AC3JH,SAASC,WAAS,OAAuB;AACxC,QAAO,MAAM,QAAQ,qBAAqB,IAAI;;AAG/C,SAAS,aAAa,KAAsB;AAC3C,KAAI,CAAC,OAAO,SAAS,IAAI,IAAI,OAAO,EAAG,QAAO;AAC9C,KAAI;AACH,UAAQ,KAAK,KAAK,EAAE;AACpB,SAAO;SACA;AACP,SAAO;;;AAIT,SAAgB,iBAAiB,OAAe,QAAgB,QAAuD;CACtH,MAAM,WAAW,KAAK,SAAS,EAAE,YAAY,QAAQ;AACrD,WAAU,UAAU,EAAE,WAAW,MAAM,CAAC;CAExC,MAAM,YAAY,KAAK,UAAU,WAAWA,WAAS,OAAO,CAAC,GAAGA,WAAS,OAAO,CAAC,OAAO;CACxF,MAAM,WAAsB;EAC3B;EACA;EACA;EACA,KAAK,QAAQ;EACb,UAAU,UAAU;EACpB,4BAAW,IAAI,MAAM,EAAC,aAAa;EACnC;AAED,KAAI;EACH,MAAM,UAAU,KAAK,MAAM,aAAa,WAAW,QAAQ,CAAC;AAC5D,MAAI,aAAa,QAAQ,IAAI,CAC5B,OAAM,IAAI,MAAM,qCAAqC,QAAQ,IAAI,MAAM,QAAQ,SAAS,WAAW,QAAQ,MAAM,GAAG;AAErH,SAAO,WAAW,EAAE,OAAO,MAAM,CAAC;UAC1B,OAAO;AACf,MAAK,MAAgC,SAAS,UAC7C;OAAI,iBAAiB,SAAS,MAAM,QAAQ,WAAW,6BAA6B,CAAE,OAAM;;;AAI9F,eAAc,WAAW,GAAG,KAAK,UAAU,UAAU,MAAM,EAAE,CAAC,KAAK,QAAQ;AAE3E,QAAO;EACN,MAAM;EACN,eAAe;AACd,OAAI;AAEH,QADgB,KAAK,MAAM,aAAa,WAAW,QAAQ,CAAC,CAChD,UAAU,MAAO,QAAO,WAAW,EAAE,OAAO,MAAM,CAAC;WACxD;;EAIT;;;;;AC/DF,SAAS,MAAM,OAAuB;AACrC,QAAO,KAAK,MAAM,QAAQ,IAAK,GAAG;;AAGnC,SAAS,UAAU,OAAe,KAAqB;AACtD,SAAQ,KAAK,MAAM,IAAI,GAAG,KAAK,MAAM,MAAM,IAAI;;AAGhD,SAAS,QAAQ,QAAiC;AACjD,KAAI,OAAO,WAAW,EAAG,QAAO;AAChC,QAAO,OAAO,QAAQ,KAAK,UAAU,MAAM,OAAO,EAAE,GAAG,OAAO;;AAG/D,SAAgB,qBAAqB,YAA+B,cAAqC;AACxG,KAAI,aAAa,WAAW,EAAG,QAAO;AACtC,QAAO,MAAM,WAAW,SAAS,aAAa,OAAO;;AAGtD,SAAgB,gCAAgC,cAAqC;CACpF,MAAM,YAAY,aAAa,QAAQ,SAAS,KAAK,WAAW,YAAY;AAC5E,KAAI,UAAU,WAAW,EAAG,QAAO;AAEnC,QAAO,MADY,UAAU,QAAQ,SAAS,CAAC,KAAK,YAAY,CACxC,SAAS,UAAU,OAAO;;AAGnD,SAAgB,4BAA4B,YAAuC;CAClF,MAAM,WAAW,IAAI,IAAI,WAAW,KAAK,cAAc,UAAU,SAAS,CAAC;AAC3E,KAAI,SAAS,SAAS,EAAG,QAAO;AAMhC,QAAO,MAJS,IAAI,IACnB,WAAW,QAAQ,cAAc,UAAU,QAAQ,CAAC,KAAK,cAAc,UAAU,SAAS,CAC1F,CAEoB,OAAO,SAAS,KAAK;;AAG3C,SAAgB,yBAAyB,YAA8C;CAGtF,MAAM,QAAQ,QAFG,WAAW,QAAQ,cAAc,UAAU,WAAW,CAChD,KAAK,cAAc,UAAU,UAAU,WAAW,UAAU,WAAY,CAAC,CACpE;AAC5B,QAAO,UAAU,OAAO,OAAO,MAAM,MAAM;;AAG5C,SAAgB,+BAA+B,gBAAgD;CAE9F,MAAM,QAAQ,QADA,eAAe,KAAK,UAAU,UAAU,MAAM,YAAY,MAAM,YAAY,CAAC,CAC/D;AAC5B,QAAO,UAAU,OAAO,OAAO,MAAM,MAAM;;AAG5C,SAAgB,eAAe,OAIX;CACnB,MAAM,qBAAqB,IAAI,IAAI,MAAM,WAAW,KAAK,cAAc,UAAU,SAAS,CAAC;CAC3F,MAAM,oBAAoB,IAAI,IAC7B,MAAM,WAAW,QAAQ,cAAc,UAAU,QAAQ,CAAC,KAAK,cAAc,UAAU,SAAS,CAChG;CACD,MAAM,iBAAiB,MAAM,aAAa,QAAQ,SAAS,KAAK,WAAW,YAAY,CAAC;AAExF,QAAO;EACN,eAAe,qBAAqB,MAAM,YAAY,MAAM,aAAa;EACzE,0BAA0B,gCAAgC,MAAM,aAAa;EAC7E,sBAAsB,4BAA4B,MAAM,WAAW;EACnE,wBAAwB,yBAAyB,MAAM,WAAW;EAClE,8BAA8B,+BAA+B,MAAM,kBAAkB,EAAE,CAAC;EACxF,QAAQ;GACP,cAAc,MAAM,aAAa;GACjC;GACA,YAAY,MAAM,WAAW;GAC7B,6BAA6B,mBAAmB;GAChD,4BAA4B,kBAAkB;GAC9C;EACD;;;;;AC3EF,SAAgB,oBAAoB,QAAgB,QAAyB;CAC5E,MAAM,SAAS,GAAG,OAAO,IAAI,SAAS,aAAa;AACnD,QACC,OAAO,SAAS,sBAAsB,IACtC,OAAO,SAAS,oBAAoB,IACpC,OAAO,SAAS,iBAAiB,IACjC,OAAO,SAAS,SAAS,IACzB,OAAO,SAAS,UAAU;;AAI5B,SAAgB,0BAAkC;AACjD,QAAO;;;;;ACJR,SAAgB,eACf,SACA,MACA,SACgB;CAChB,MAAM,SAAS,UAAU,SAAS,MAAM;EACvC,KAAK,SAAS;EACd,KAAK,SAAS;EACd,UAAU;EACV,CAAC;CACF,MAAM,YAAY,OAAO,iBAAiB,QAAQ,GAAG,OAAO,MAAM,QAAQ;IACvE;AAEH,QAAO;EACN,QAAQ,OAAO,UAAU;EACzB,QAAQ,GAAG,YAAY,OAAO,UAAU;EACxC,UAAU,OAAO,UAAU;EAC3B;;AAGF,SAAgB,uBAAuB,SAAiB;CACvD,MAAM,SAAS,UAAU,SAAS,CAAC,SAAS,EAAE;EAC7C,UAAU;EACV,OAAO;EACP,CAAC;AAEF,KAAI,OAAO,iBAAiB,MAC3B,OAAM,IAAI,MAAM,OAAO,MAAM,QAAQ;;AAIvC,SAAgB,sBACf,SACA,MACA,SACS;CACT,MAAM,SAAS,UAAU,SAAS,MAAM;EACvC,KAAK,SAAS;EACd,KAAK,SAAS;EACd,OAAO;EACP,CAAC;AAEF,KAAI,OAAO,iBAAiB,MAC3B,OAAM,IAAI,MAAM,OAAO,MAAM,QAAQ;AAGtC,QAAO,OAAO,UAAU;;AAGzB,SAAgB,cAAc,QAAuB,SAAiB;AACrE,KAAI,OAAO,aAAa,EAAG;CAC3B,MAAM,UAAU,CAAC,OAAO,OAAO,MAAM,EAAE,OAAO,OAAO,MAAM,CAAC,CAAC,OAAO,QAAQ,CAAC,KAAK,KAAK;AACvF,OAAM,IAAI,MAAM,GAAG,QAAQ,SAAS,UAAU,KAAK,YAAY,KAAK;;;;;ACvDrE,SAAS,UAAU,KAAa,MAAgB;AAC/C,QAAO,eAAe,OAAO,MAAM,EAAE,KAAK,CAAC;;AAG5C,SAAS,SAAS,OAAuB;AACxC,QAAO,MAAM,QAAQ,qBAAqB,IAAI,CAAC,QAAQ,YAAY,GAAG,IAAI;;AAG3E,SAAgB,UAAU,KAAsB;CAC/C,MAAM,SAAS,UAAU,KAAK,CAAC,aAAa,wBAAwB,CAAC;AACrE,QAAO,OAAO,aAAa,KAAK,OAAO,OAAO,MAAM,KAAK;;AAG1D,SAAgB,YAAY,KAAqB;AAChD,KAAI,CAAC,UAAU,IAAI,CAAE,QAAO,QAAQ,IAAI;CACxC,MAAM,SAAS,UAAU,KAAK,CAAC,aAAa,kBAAkB,CAAC;AAC/D,eAAc,QAAQ,gCAAgC;AACtD,QAAO,QAAQ,OAAO,OAAO,MAAM,CAAC;;AAGrC,SAAgB,iBAAiB,KAA4B;AAC5D,KAAI,CAAC,UAAU,IAAI,CAAE,QAAO;CAC5B,MAAM,SAAS,UAAU,KAAK;EAAC;EAAa;EAAgB;EAAO,CAAC;AACpE,KAAI,OAAO,aAAa,EAAG,QAAO;AAElC,QADe,OAAO,OAAO,MAAM,IAClB;;AAGlB,SAAgB,gBAAgB,KAAqB;AACpD,KAAI,CAAC,UAAU,IAAI,CAAE,QAAO,QAAQ,IAAI;CAExC,MAAM,SAAS,UAAU,KAAK;EAAC;EAAU;EAAS;EAAoB,CAAC;CACvE,MAAM,cAAc,OAAO,OAAO,MAAM;AACxC,KAAI,OAAO,aAAa,KAAK,YAAa,QAAO;CAEjD,MAAM,OAAO,UAAU,KAAK,CAAC,aAAa,kBAAkB,CAAC;AAC7D,eAAc,MAAM,gCAAgC;CACpD,MAAM,YAAY,UAAU,KAAK,CAAC,aAAa,mBAAmB,CAAC;AACnE,eAAc,WAAW,iCAAiC;CAE1D,MAAM,WAAW,QAAQ,KAAK,OAAO,MAAM,CAAC;CAC5C,MAAM,gBAAgB,UAAU,OAAO,MAAM;AAC7C,QAAO,GAAG,SAAS,SAAS,CAAC,GAAG,SAAS,GAAG,WAAW,cAAc,GAAG,QAAQ,cAAc,GAAG;;AAGlG,SAAgB,eAAe,QAAgB,UAA0B;AAGxE,QAAO,GAFM,SAAS,SAAS,SAAS,CAAC,CAE1B,GADA,WAAW,OAAO,CAAC,OAAO,OAAO,CAAC,OAAO,MAAM,CAAC,MAAM,GAAG,EAAE;;;;;AClC3E,SAAS,cAAsB;AAC9B,QAAO,wBAAO,IAAI,MAAM,EAAC,aAAa,CAAC,QAAQ,SAAS,IAAI;;AAG7D,SAASC,yBAAuB,OAM7B;CACF,MAAM,OAAiB,EAAE;AAEzB,KAAI,MAAM,cAAe,MAAK,KAAK,eAAe,MAAM,cAAc;AACtE,KAAI,MAAM,qBAAsB,MAAK,KAAK,0BAA0B,MAAM,qBAAqB;AAC/F,KAAI,MAAM,YAAa,MAAK,KAAK,aAAa,MAAM,YAAY;UACvD,MAAM,WAAY,MAAK,KAAK,iBAAiB,MAAM,WAAW;KAClE,OAAM,IAAI,MAAM,6DAA6D;AAClF,MAAK,KAAK,MAAM,MAAM,OAAO;AAE7B,QAAO;;AAGR,SAASC,YAAU,MAAc,OAAgB;AAChD,eAAc,MAAM,GAAG,KAAK,UAAU,OAAO,MAAM,EAAE,CAAC,KAAK,QAAQ;;AAGpE,SAAS,UAAU,MAAc,OAAe;AAC/C,eAAc,MAAM,OAAO,QAAQ;;AAGpC,SAAS,eAAe,OAKb;CACV,MAAM,OAAO,MAAM,QAAQ;AAE3B,KAAI,MAAM,SACT,QAAO;EACN;EACA;EACA;EACA;EACA,KAAK,MAAM;EACX;EACA;EACA,KAAK,MAAM;EACX;EACA,SAAS;EACT;EACA;EACA,CAAC,KAAK,KAAK;AAGb,QAAO;EACN;EACA;EACA;EACA,8BAA8B,MAAM;EACpC,SAAS;EACT;EACA,MAAM,qBACH,iEAAiE,MAAM,uBACvE;EACH;EACA,CAAC,KAAK,KAAK;;AAGb,SAAS,yBAAyB,WAAmB;AACpD,KAAI;AACH,yBAAuB,UAAU;UACzB,OAAO;AACf,MAAI,cAAc,KACjB,OAAM,IAAI,MACT;GACC;GACA;GACA;GACA,YAAa,MAAgB;GAC7B,CAAC,KAAK,KAAK,CACZ;AAGF,QAAM,IAAI,MACT;GACC,wDAAwD;GACxD;GACA,YAAa,MAAgB;GAC7B,CAAC,KAAK,KAAK,CACZ;;;AAIH,SAAS,eAAe,OAWR;AACf,QAAO;EACN,OAAO,MAAM;EACb,QAAQ,MAAM;EACd,UAAU,MAAM;EAChB,UAAU,MAAM;EAChB,QAAQ,MAAM;EACd,MAAM,MAAM;EACZ,UAAU,MAAM;EAChB,oBAAoB,MAAM;EAC1B,MAAM,MAAM;EACZ,4BAAW,IAAI,MAAM,EAAC,aAAa;EACnC,SAAS;EACT,YAAY;EACZ,WAAW,MAAM;EACjB,YAAY;EACZ,oBAAoB;EACpB,kBAAkB;EAClB,kBAAkB;EAClB,cAAc;EACd;;AAGF,SAAS,cAAc,OAOR;CACd,MAAM,UAAU,MAAM,aAAa;CACnC,MAAM,iBACL,MAAM,uBAAuB,OAC1B,KACA,qEAAqE,MAAM,mBAAmB;CAClG,MAAM,WACL,WAAW,CAAC,oBAAoB,MAAM,QAAQ,MAAM,OAAO,GAAG,KAAK,IAAI,yBAAyB;AAEjG,QAAO;EACN,OAAO,MAAM;EACb,MAAM,MAAM;EACZ,4BAAW,IAAI,MAAM,EAAC,aAAa;EACnC;EACA,SAAS,UACN,2BAA2B,mBAC3B,wBAAwB,WAAW;EACtC,YAAY,MAAM;EAClB,oBAAoB,MAAM;EAC1B;;AAGF,SAAgB,cAAc,SAA0C;CACvE,MAAM,MAAM,QAAQ,OAAO,QAAQ,KAAK;CACxC,MAAM,eAAe,QAAQ;CAC7B,MAAM,WAAW,YAAY,IAAI;CACjC,MAAM,SAAS,gBAAgB,SAAS;CACxC,MAAM,WAAW,eAAe,QAAQ,SAAS;CACjD,MAAM,SAAS,QAAQ,UAAU,iBAAiB,SAAS,IAAI;CAC/D,MAAM,OAAO,QAAQ,QAAQ;CAC7B,MAAM,WAAW,QAAQ,YAAY;CACrC,MAAM,qBAAqB,WAAW,OAAQ,QAAQ,sBAAsB;CAC5E,MAAM,OAAO,QAAQ,QAAQ;CAC7B,MAAM,YAAY,QAAQ,aAAa;CACvC,MAAM,QAAQ,aAAa;CAC3B,MAAM,SAAS,KAAK,cAAc,QAAQ,MAAM;CAChD,MAAM,YAAY,KAAK,cAAc,SAAS;CAC9C,MAAM,aAAa,KAAK,QAAQ,aAAa;CAC7C,MAAM,aAAa,KAAK,QAAQ,aAAa;CAC7C,MAAM,SAAS,eAAe;EAAE;EAAU;EAAU;EAAM;EAAoB,CAAC;CAC/E,MAAM,sBAAsB,eAAe,cAAc,SAAS;CAClE,MAAM,wBACL,qBAAqB,QAAQ,eAAe,qBAAqB,QAAQ,aACtE,oBAAoB,UACpB,sBAAsB,cAAc,SAAS;CACjD,MAAM,mBAAmB,sBAAsB,cAAc,oBAAoB,cAAc,SAAS;CACxG,MAAM,cAAc,iBAAiB;EACpC,SAAS;EACT,MAAM;EACN,QAAQ;EACR,MAAM;EACN;EACA,aAAa,OAAO,iCAAiC,SAAS;EAC9D;EACA,SAAS,yBAAyB;GACjC,YAAY;GACZ,WAAW,sBAAsB;GACjC,aAAa,sBAAsB;GACnC,CAAC;EACF,CAAC;AAEF,0BAAyB,UAAU;AAEnC,WAAU,QAAQ,EAAE,WAAW,MAAM,CAAC;AACtC,WAAU,WAAW,EAAE,WAAW,MAAM,CAAC;AAEzC,WAAU,KAAK,QAAQ,kBAAkB,EAAE,GAAG;AAC9C,WAAU,KAAK,QAAQ,sBAAsB,EAAE,GAAG;AAClD,aAAU,KAAK,QAAQ,mBAAmB,EAAE;EAC3C,QAAQ;EACR,4BAAW,IAAI,MAAM,EAAC,aAAa;EACnC,CAAC;AACF,iBAAgB,cAAc,YAAY;CAE1C,MAAM,QAAQ,iBAAiB,OAAO,QAAQ,OAAO;AAErD,KAAI;EACH,MAAM,WAAW,eAAe;GAC/B;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA,WAAW,MAAM;GACjB,CAAC;AAEF,cAAY,KAAK,QAAQ,eAAe,EAAE;GACzC,MAAM;GACN;GACA;GACA;GACA;GACA,WAAW,SAAS;GACpB,CAAC;EAEF,MAAM,+BAAc,IAAI,MAAM,EAAC,aAAa;AAC5C,cAAY,KAAK,QAAQ,eAAe,EAAE;GACzC,MAAM;GACN;GACA,SAAS;GACT,WAAW;GACX,CAAC;AAEF,kBACC,cACA,iBAAiB;GAChB,GAAG;GACH,QAAQ;GACR,aAAa,OAAO,sBAAsB,SAAS;GACnD,CAAC,CACF;EASD,MAAM,WAAW,eAAe,WAPjBD,yBAAuB;GACrC,YAAY,YAAY,QAAQ,gBAAgB,OAAO,mBAAmB;GAC1E,aAAa,YAAY,QAAQ;GACjC;GACA,sBAAsB,QAAQ;GAC9B,eAAe,QAAQ;GACvB,CAAC,EACiD;GAClD,KAAK;GACL,KAAK,QAAQ;GACb,CAAC;EACF,MAAM,6BAAY,IAAI,MAAM,EAAC,aAAa;EAC1C,MAAM,sBAAsB,sBAAsB,cAAc,SAAS;AAEzE,YAAU,YAAY,SAAS,OAAO;AACtC,YAAU,YAAY,SAAS,OAAO;EAEtC,MAAM,eAAmC;GACxC,SAAS;GACT,KAAK;GACL;GACA;GACA;GACA,YAAY,oBAAoB;GAChC,WAAW,oBAAoB;GAC/B,aAAa,oBAAoB;GACjC,WAAW;GACX,SAAS;GACT,UAAU,SAAS;GACnB;GACA;GACA,eAAe,WACZ,qEACA;GACH;AACD,cAAU,KAAK,QAAQ,qBAAqB,EAAE,aAAa;AAE3D,cAAY,KAAK,QAAQ,eAAe,EAAE;GACzC,MAAM;GACN;GACA,SAAS;GACT,UAAU,aAAa;GACvB,WAAW;GACX,CAAC;EAEF,MAAM,UAAU,eAAe;GAC9B,cAAc,EAAE;GAChB,YAAY,EAAE;GACd,CAAC;EACF,MAAM,UAAU,cAAc;GAC7B;GACA;GACA,UAAU,aAAa;GACvB,QAAQ,SAAS;GACjB,QAAQ,SAAS;GACjB;GACA,CAAC;EACF,MAAM,gBAA6B;GAClC,GAAG;GACH,SAAS;GACT,YACC,aAAa,aAAa,IACvB,4BACA,kCAAkC,aAAa;GACnD,YAAY,aAAa;GACzB;AAED,cAAU,KAAK,QAAQ,gBAAgB,EAAE,cAAc;AACvD,cAAU,KAAK,QAAQ,eAAe,EAAE,QAAQ;AAChD,cAAU,KAAK,QAAQ,mBAAmB,EAAE,QAAQ;AACpD,cAAU,KAAK,QAAQ,mBAAmB,EAAE;GAC3C,QAAQ,QAAQ,UAAU,cAAc;GACxC,WAAW;GACX,UAAU,aAAa;GACvB,CAAC;AACF,cAAU,KAAK,WAAW,gBAAgB,EAAE,cAAc;AAC1D,cAAU,KAAK,WAAW,eAAe,EAAE,QAAQ;AACnD,cAAU,KAAK,WAAW,mBAAmB,EAAE,QAAQ;AACvD,kBACC,cACA,iBAAiB;GAChB,GAAG;GACF,QAAQ,aAAa,aAAa,IAAI,SAAS;GAC/C,aACC,aAAa,aAAa,IACvB,+DACA,qCAAqC,aAAa;GACtD,SAAS,aAAa,aAAa;GACnC,WAAW,aAAa,aAAa,IAAI,OAAO;GAChD,SAAS,yBAAyB;IACjC,YAAY,oBAAoB;IAChC,WAAW,oBAAoB;IAC/B,aAAa,oBAAoB;IACjC,CAAC;GACF,CAAC,CACF;AAEF,cAAY,KAAK,QAAQ,eAAe,EAAE;GACzC,MAAM;GACN;GACA,WAAW,cAAc;GACzB,YAAY,cAAc;GAC1B;GACA,CAAC;AAEF,SAAO;GACN;GACA;GACA;GACA,UAAU;GACV;GACA;GACA;GACA;WACQ;AACT,QAAM,SAAS;;;;;;ACpXjB,SAAgB,sBAAsB,OAA8C;AACnF,QAAO;EACN,IAAI,YAAY;EAChB,OAAO,MAAM;EACb,UAAU,MAAM;EAChB,SAAS,MAAM;EACf,eAAe,MAAM,iBAAiB;EACtC,WAAW,MAAM,8BAAa,IAAI,MAAM,EAAC,aAAa;EACtD,GAAI,MAAM,SAAS,EAAE,QAAQ,MAAM,QAAQ,GAAG,EAAE;EAChD,GAAI,MAAM,UAAU,EAAE,SAAS,MAAM,SAAS,GAAG,EAAE;EACnD;;AAGF,SAAgB,iBACf,WACA,SACkB;AAClB,QAAO;EACN,GAAG;EACH,GAAI,QAAQ,aAAa,EAAE,YAAY,QAAQ,YAAY,GAAG,EAAE;EAChE,GAAI,QAAQ,UAAU,EAAE,SAAS,QAAQ,SAAS,GAAG,EAAE;EACvD;;;;;AC9BF,SAASE,YAAU,MAAc,OAAgB;AAChD,WAAU,QAAQ,KAAK,EAAE,EAAE,WAAW,MAAM,CAAC;AAC7C,eAAc,MAAM,GAAG,KAAK,UAAU,OAAO,MAAM,EAAE,CAAC,KAAK,QAAQ;;AAGpE,SAAgB,YAAY,cAA8B;AACzD,QAAO,KAAK,cAAc,QAAQ;;AAGnC,SAAgB,YAAY,cAAsB,QAAwB;AACzE,QAAO,KAAK,YAAY,aAAa,EAAE,GAAG,OAAO,OAAO;;AAGzD,SAAgB,iBAAiB,OAOlB;CACd,MAAM,uBAAM,IAAI,MAAM,EAAC,aAAa;AACpC,QAAO;EACN,QAAQ,MAAM;EACd,OAAO,MAAM;EACb,QAAQ,MAAM;EACd,MAAM,MAAM;EACZ,iBAAiB,MAAM;EACvB,WAAW,MAAM;EACjB,WAAW;EACX,WAAW;EACX;;AAGF,SAAgB,gBAAgB,cAAsB,MAAkB;AACvE,aAAU,YAAY,cAAc,KAAK,OAAO,EAAE,KAAK;;AAGxD,SAAgB,uBAAuB,cAAsB,QAAgB,QAAuC;CACnH,MAAM,OAAO,eAAe,cAAc,OAAO;AACjD,KAAI,SAAS,KAAM,QAAO;CAE1B,MAAM,cAA0B;EAC/B,GAAG;EACH;EACA,4BAAW,IAAI,MAAM,EAAC,aAAa;EACnC;AACD,iBAAgB,cAAc,YAAY;AAC1C,QAAO;;AAGR,SAAgB,eAAe,cAAsB,QAAmC;CACvF,MAAM,OAAO,YAAY,cAAc,OAAO;AAC9C,KAAI;AACH,SAAO,KAAK,MAAM,aAAa,MAAM,QAAQ,CAAC;SACvC;AACP,SAAO;;;AAIT,SAAgB,gBAAgB,cAAoC;CACnE,MAAM,WAAW,YAAY,aAAa;CAC1C,IAAI;AACJ,KAAI;AACH,YAAU,YAAY,SAAS;SACxB;AACP,SAAO,EAAE;;AAGV,QAAO,QACL,QAAQ,UAAU,MAAM,SAAS,QAAQ,CAAC,CAC1C,KAAK,UAAU,eAAe,cAAc,MAAM,QAAQ,WAAW,GAAG,CAAC,CAAC,CAC1E,QAAQ,SAA6B,SAAS,KAAK,CACnD,MAAM,MAAM,UAAU,KAAK,OAAO,cAAc,MAAM,OAAO,CAAC;;;;;AC5DjE,MAAM,yBAAyB;AAC/B,MAAM,2BAA2B;AAEjC,SAAS,eAAuB;AAC/B,QAAO,yBAAQ,IAAI,MAAM,EAAC,aAAa,CAAC,QAAQ,SAAS,IAAI;;AAG9D,SAAS,UAAU,MAAc,OAAgB;AAChD,eAAc,MAAM,GAAG,KAAK,UAAU,OAAO,MAAM,EAAE,CAAC,KAAK,QAAQ;;AAGpE,SAAgB,cAAc,cAAqC;CAClE,MAAM,QAAQ,gBAAgB,aAAa;CAC3C,MAAM,SAAS,gBAAgB,aAAa;AAoB5C,QAAO;EACN,OAnBmB,MAAM,KAAK,UAAU;GAAE,QAAQ,KAAK;GAAQ,QAAQ,KAAK;GAAQ,EAAE;EAoBtF,QAnBoB,OAAO,KAAK,WAAW;GAC3C,SAAS,MAAM;GACf,QAAQ,MAAM;GACd,SAAS,MAAM;GACf,EAAE;EAgBF,mBAdyB,MAAM,SAAS,KAAK,MAAM,OAAO,SAAS,KAAK,WAAW,YAAY;EAe/F,0BAbA,MAAM,SAAS,KAAK,MAAM,OAAO,SAAS,KAAK,WAAW,eAAe,KAAK,WAAW,UAAU;EAcnG,eAZc,OAAO,MAAM,UAAU,MAAM,YAAY,SAAS,EACnC,YAAY;EAYzC,wBATA,OAAO,MAAM,UAAU,MAAM,WAAW,YAAY,MAAM,WAAW,aAAa,MAAM,WAAW,WAAW,IAC9G,MAAM,MAAM,SAAS,KAAK,WAAW,YAAY,KAAK,WAAW,UAAU;EAS3E;;AAGF,SAAgB,sBAAsB,OAUmC;AACxE,KAAI,MAAM,aAAa,MAAM,cAC5B,QAAO;EAAE,YAAY;EAA0B,gBAAgB;EAAM;AAGtE,KAAI,MAAM,aAAa,MAAM,cAC5B,QAAO;EAAE,YAAY;EAAyB,gBAAgB;EAAM;AAGrE,KAAI,MAAM,mBAAmB,MAAM,eAAe,EACjD,QAAO;EAAE,YAAY;EAAmB,gBAAgB;EAAM;AAG/D,KAAI,MAAM,MAAM,kBACf,QAAO;EAAE,YAAY;EAAuB,gBAAgB;EAAM;AAGnE,KAAI,MAAM,MAAM,cACf,QAAO;EAAE,YAAY;EAAkB,gBAAgB;EAAM;AAG9D,KAAI,MAAM,MAAM,yBACf,QAAO;EAAE,YAAY;EAA+B,gBAAgB;EAAM;AAG3E,KACC,MAAM,2BAA2B,QACjC,MAAM,QAAQ,gBAAgB,MAAM,uBAEpC,QAAO;EAAE,YAAY;EAAuB,gBAAgB;EAAM;CAGnE,MAAM,UAAoB,EAAE;AAC5B,KAAI,MAAM,MAAM,uBAAwB,SAAQ,KAAK,iCAAiC;AACtF,KAAI,MAAM,MAAM,MAAM,WAAW,EAAG,SAAQ,KAAK,uBAAuB;AACxE,KAAI,QAAQ,WAAW,EAAG,SAAQ,KAAK,qCAAqC;AAE5E,QAAO;EAAE,YAAY;EAAM,gBAAgB,QAAQ,KAAK,KAAK;EAAE;;AAGhE,SAAS,iBAAiB,YAAoD;AAC7E,KAAI,WAAW,WAAW,EACzB,QAAO,eAAe;EAAE,cAAc,EAAE;EAAE,YAAY,EAAE;EAAE,CAAC;CAG5D,IAAI,oBAAoB;CACxB,IAAI,sBAAsB;CAC1B,IAAI,kBAAkB;CACtB,IAAI,mCAAmC;CACvC,IAAI,kCAAkC;CACtC,IAAI,mBAAmB;CACvB,IAAI,8BAA8B;CAClC,IAAI,0BAA0B;CAC9B,IAAI,aAAuB,EAAE;CAC7B,IAAI,YAAsB,EAAE;AAE5B,MAAK,MAAM,QAAQ,YAAY;EAC9B,MAAM,IAAI,KAAK;AACf,uBAAqB,EAAE,OAAO;AAC9B,yBAAuB,EAAE,OAAO;AAChC,qBAAmB,EAAE,OAAO;AAC5B,sCAAoC,EAAE,OAAO;AAC7C,qCAAmC,EAAE,OAAO;AAC5C,sBAAoB,EAAE;AACtB,iCAA+B,EAAE;AACjC,6BAA2B,EAAE;AAC7B,MAAI,EAAE,2BAA2B,KAAM,YAAW,KAAK,EAAE,uBAAuB;AAChF,MAAI,EAAE,iCAAiC,KAAM,WAAU,KAAK,EAAE,6BAA6B;;CAG5F,MAAM,QAAQ,WAAW;CACzB,MAAM,SAAS,MAAc,KAAK,MAAM,IAAI,IAAK,GAAG;CACpD,MAAM,OAAO,WAAsB,OAAO,WAAW,IAAI,OAAO,MAAM,OAAO,QAAQ,GAAG,MAAM,IAAI,GAAG,EAAE,GAAG,OAAO,OAAO;AAExH,QAAO;EACN,eAAe,MAAM,mBAAmB,MAAM;EAC9C,0BAA0B,MAAM,8BAA8B,MAAM;EACpE,sBAAsB,MAAM,0BAA0B,MAAM;EAC5D,wBAAwB,IAAI,WAAW;EACvC,8BAA8B,IAAI,UAAU;EAC5C,QAAQ;GACP,cAAc;GACd,gBAAgB;GAChB,YAAY;GACZ,6BAA6B;GAC7B,4BAA4B;GAC5B;EACD;;AAGF,SAAgB,QAAQ,SAAqC;CAC5D,MAAM,gBAAgB,QAAQ,iBAAiB;CAC/C,MAAM,gBAAgB,QAAQ,iBAAiB;CAC/C,MAAM,kBAAkB,QAAQ,mBAAmB;CACnD,MAAM,yBAAyB,QAAQ,0BAA0B;CACjE,MAAM,SAAS,cAAc;CAC7B,MAAM,eAAe,QAAQ,WAAW;CACxC,MAAM,UAAU,KAAK,cAAc,SAAS,OAAO;AAEnD,WAAU,SAAS,EAAE,WAAW,MAAM,CAAC;CAEvC,MAAM,gBAAgB,KAAK,KAAK;CAChC,MAAM,aAAoC,EAAE;CAC5C,IAAI,kBAAkC;AAEtC,aAAY,KAAK,SAAS,eAAe,EAAE;EAC1C,MAAM;EACN;EACA;EACA;EACA;EACA,4BAAW,IAAI,MAAM,EAAC,aAAa;EACnC,CAAC;AAEF,MAAK,IAAI,YAAY,GAAG,aAAa,eAAe,aAAa;EAChE,MAAM,iBAAiB,KAAK,KAAK;EAEjC,IAAI;AACJ,MAAI;AACH,sBAAmB,cAAc,QAAQ,WAAW;WAC5C,OAAO;AAEf,eAAY,KAAK,SAAS,eAAe,EAAE;IAC1C,MAAM;IACN;IACA;IACA,OAAQ,MAAgB;IACxB,4BAAW,IAAI,MAAM,EAAC,aAAa;IACnC,CAAC;AACF,qBAAkB;AAClB;;EAGD,MAAM,qBAAqB,KAAK,KAAK,GAAG;EACxC,MAAM,iBAAiB,KAAK,KAAK,GAAG;EACpC,MAAM,QAAQ,cAAc,aAAa;EACzC,MAAM,UAAU,iBAAiB;EAEjC,MAAM,EAAE,YAAY,mBAAmB,sBAAsB;GAC5D;GACA;GACA,WAAW;GACX;GACA,YAAY,iBAAiB,aAAa;GAC1C;GACA;GACA;GACA;GACA,CAAC;EAEF,MAAM,kBAAuC;GAC5C;GACA;GACA,eAAe;GACf;GACA,WAAW;GACX;GACA;GACA;AAED,aAAW,KAAK,gBAAgB;AAEhC,YAAU,KAAK,SAAS,aAAa,UAAU,OAAO,EAAE;GACvD;GACA,OAAO,iBAAiB;GACxB,eAAe;GACf;GACA,WAAW;GACX;GACA;GACA,CAAC;AAEF,cAAY,KAAK,SAAS,eAAe,EAAE;GAC1C,MAAM;GACN;GACA;GACA,OAAO,iBAAiB;GACxB,YAAY,iBAAiB,aAAa;GAC1C;GACA;GACA,4BAAW,IAAI,MAAM,EAAC,aAAa;GACnC,CAAC;AAEF,MAAI,QAAQ,oBACX,SAAQ,oBAAoB,gBAAgB;AAG7C,MAAI,eAAe,MAAM;AACxB,qBAAkB;AAClB;;;CAIF,MAAM,iBAAiB,KAAK,KAAK,GAAG;CACpC,MAAM,aAAa,WAAW,SAAS,IAAI,WAAW,WAAW,SAAS,GAAG,gBAAgB,cAAc,aAAa;CACxH,MAAM,YAAY,iBAAiB,WAAW;CAE9C,MAAM,aAA4B;EACjC;EACA;EACA,YAAY;EACZ,iBAAiB,WAAW;EAC5B;EACA,oBAAoB;EACpB,kBAAkB;EAClB;AAED,WAAU,KAAK,SAAS,oBAAoB,EAAE;EAC7C;EACA,YAAY;EACZ,iBAAiB,WAAW;EAC5B;EACA,oBAAoB;EACpB,kBAAkB;EAClB,CAAC;AAEF,aAAY,KAAK,SAAS,eAAe,EAAE;EAC1C,MAAM;EACN;EACA,YAAY;EACZ,iBAAiB,WAAW;EAC5B;EACA,4BAAW,IAAI,MAAM,EAAC,aAAa;EACnC,CAAC;AAEF,QAAO;;;;;ACjOR,SAAS,uBAAuB,OAMnB;CACZ,MAAM,OAAiB,EAAE;AAEzB,KAAI,MAAM,cAAe,MAAK,KAAK,eAAe,MAAM,cAAc;AACtE,KAAI,MAAM,qBAAsB,MAAK,KAAK,0BAA0B,MAAM,qBAAqB;AAC/F,KAAI,MAAM,YAAa,MAAK,KAAK,aAAa,MAAM,YAAY;UACvD,MAAM,WAAY,MAAK,KAAK,iBAAiB,MAAM,WAAW;KAClE,OAAM,IAAI,MAAM,6DAA6D;AAClF,KAAI,MAAM,OAAQ,MAAK,KAAK,MAAM,MAAM,OAAO;AAE/C,QAAO;;AAGR,SAAgB,iBAAiB,OAAwE;CACxG,MAAM,OAAO,MAAM,QAAQ;AAE3B,SAAQ,MAAM,MAAd;EACC,KAAK,SACJ,QAAO;GACN;GACA;GACA;GACA,eAAe,MAAM;GACrB,SAAS;GACT;GACA,CAAC,KAAK,KAAK;EACb,KAAK,WACJ,QAAO;GACN;GACA;GACA;GACA,eAAe,MAAM;GACrB,SAAS;GACT;GACA,CAAC,KAAK,KAAK;EACb,KAAK,cACJ,QAAO;GACN;GACA;GACA;GACA,eAAe,MAAM;GACrB,SAAS;GACT;GACA,CAAC,KAAK,KAAK;EACb,QACC,QAAO;GACN;GACA;GACA;GACA,eAAe,MAAM;GACrB,SAAS;GACT;GACA,CAAC,KAAK,KAAK;;;AAIf,SAAgB,oBAAoB,SAAiB,cAA4C;CAChG,MAAM,QAAQ,eAAe,cAAc,QAAQ;AACnD,KAAI,UAAU,KAAM,OAAM,IAAI,MAAM,kBAAkB,UAAU;CAEhE,MAAM,gBAAgB,sBAAsB,cAAc,QAAQ;CAClE,MAAM,cAAc,MAAM,QAAQ,eAAe,cAAc;CAC/D,MAAM,YAAY,MAAM,QAAQ,aAAa,cAAc;CAC3D,MAAM,aAAa,MAAM,QAAQ,cAAc,cAAc,cAAc,oBAAoB,cAAc,QAAQ;AAErH,KAAI,gBAAgB,KACnB,OAAM,IAAI,MAAM,SAAS,QAAQ,4CAA4C;AAG9E,QAAO;EACN;EACA,SAAS,yBAAyB;GACjC;GACA;GACA;GACA,iCAAgB,IAAI,MAAM,EAAC,aAAa;GACxC,CAAC;EACF;;AAGF,SAAgB,kBAAkB,OAA8E;CAC/G,MAAM,QAAQ,eAAe,MAAM,cAAc,MAAM,QAAQ;AAC/D,KAAI,UAAU,KAAM,OAAM,IAAI,MAAM,kBAAkB,MAAM,UAAU;AAEtE,oBAAmB;EAClB,cAAc,MAAM;EACpB,SAAS,MAAM;EACf,KAAK;EACL,MAAM,MAAM;EACZ,MAAM,MAAM;EACZ,CAAC;AAEF,iBACC,MAAM,cACN,iBAAiB;EAChB,GAAG;EACH,QAAQ,MAAM,WAAW,SAAS,WAAW,MAAM;EACnD,aAAa,MAAM;EACnB,WAAW;EACX,SAAS;EACT,SAAS,yBAAyB;GACjC,YAAY,MAAM,QAAQ,cAAc,oBAAoB,MAAM,cAAc,MAAM,QAAQ;GAC9F,WAAW,MAAM,QAAQ;GACzB,aAAa,MAAM,QAAQ;GAC3B,gBAAgB,MAAM,QAAQ;GAC9B,CAAC;EACF,CAAC,CACF;;AAGF,SAAgB,kBAAkB,OAO/B;CACF,MAAM,QAAQ,eAAe,MAAM,cAAc,MAAM,QAAQ;AAC/D,KAAI,UAAU,KAAM,OAAM,IAAI,MAAM,kBAAkB,MAAM,UAAU;AAEtE,KAAI,MAAM,QAAQ;EACjB,MAAM,aACL,MAAM,WAAW,cACd,cACA,MAAM,WAAW,aAAa,MAAM,WAAW,WAC9C,YACA,MAAM,WAAW,aAAa,MAAM,WAAW,WAC9C,YACA;AACN,MAAI,WAAY,wBAAuB,MAAM,cAAc,MAAM,QAAQ,WAAW;;AAGrF,iBACC,MAAM,cACN,iBAAiB;EAChB,GAAG;EACH,QAAQ,MAAM;EACd,aAAa,MAAM,eAAe,MAAM;EACxC,WAAW,MAAM,aAAa,MAAM;EACpC,SAAS,MAAM,WAAW,MAAM;EAChC,SAAS,MAAM;EACf,CAAC,CACF;;AAGF,SAAgB,cAAc,SAAoD;CACjF,MAAM,aAAa,oBAAoB,QAAQ,cAAc,QAAQ,QAAQ;AAE7E,KAAI,eAAe,QAAQ,cAAc,QAAQ,QAAQ,KAAK,KAC7D,OAAM,IAAI,MAAM,yBAAyB,QAAQ,UAAU;AAG5D,wBAAuB,KAAK;CAE5B,MAAM,QAAQ,iBAAiB;EAC9B,SAAS,QAAQ;EACjB,MAAM,QAAQ;EACd,QAAQ;EACR,QAAQ,QAAQ,UAAU;EAC1B,MAAM,QAAQ;EACd,aAAa,QAAQ,OAAO,sBAAsB,QAAQ,SAAS,WAAW,QAAQ,KAAK;EAC3F,SAAS,yBAAyB,EACjC,YACA,CAAC;EACF,CAAC;AACF,iBAAgB,QAAQ,cAAc,MAAM;AAC5C,KAAI,QAAQ,KACX,oBAAmB;EAClB,cAAc,QAAQ;EACtB,SAAS,QAAQ;EACjB,KAAK;EACL,MAAM;EACN,MAAM,QAAQ;EACd,CAAC;AAGH,iBACC,QAAQ,cACR,iBAAiB;EAChB,GAAG;EACH,QAAQ;EACR,aAAa,QAAQ,OAAO,WAAW,QAAQ,KAAK,SAAS,QAAQ,SAAS,WAAW,QAAQ,KAAK;EACtG,CAAC,CACF;CAGD,MAAM,SAAS,uBAAuB;EACrC;EACA,QAHc,iBAAiB;GAAE,MAAM,QAAQ;GAAM,MAAM,QAAQ;GAAM,UAAU,QAAQ;GAAU,CAAC;EAItG,sBAAsB,QAAQ;EAC9B,eAAe,QAAQ;EACvB,CAAC;CACF,MAAM,WAAW,eAAe,MAAM,QAAQ;EAC7C,KAAK,QAAQ;EACb,KAAK,QAAQ;EACb,CAAC;CACF,MAAM,gBAAgB,sBAAsB,QAAQ,cAAc,QAAQ,QAAQ;CAClF,MAAM,oBAAoB,YAAY,QAAQ,cAAc,QAAQ,QAAQ;AAC5E,eAAc,GAAG,kBAAkB,qBAAqB,SAAS,QAAQ,QAAQ;AACjF,eAAc,GAAG,kBAAkB,qBAAqB,SAAS,QAAQ,QAAQ;AACjF,eACC,GAAG,kBAAkB,0BACrB,GAAG,KAAK,UACP;EACC,SAAS;EACT,MAAM;EACN,UAAU,SAAS;EACnB;EACA,aAAa,cAAc;EAC3B,WAAW,cAAc;EACzB,EACD,MACA,EACA,CAAC,KACF,QACA;CAED,MAAM,oBACL,SAAS,OAAO,MAAM,KACrB,SAAS,aAAa,IAAI,GAAG,QAAQ,KAAK,kBAAkB,GAAG,QAAQ,KAAK,wBAAwB,SAAS;AAC/G,oBAAmB;EAClB,cAAc,QAAQ;EACtB,SAAS,QAAQ;EACjB,KAAK;EACL,MAAM,QAAQ;EACd,MAAM;EACN,CAAC;AACF,iBACC,QAAQ,cACR,iBAAiB;EAChB,GAAG;EACH,QAAQ,SAAS,aAAa,IAAI,SAAS;EAC3C,aAAa;EACb,SAAS,SAAS,aAAa;EAC/B,WAAW,SAAS,aAAa,IAAI,OAAO;EAC5C,SAAS,yBAAyB;GACjC,YAAY,cAAc;GAC1B,WAAW,cAAc;GACzB,aAAa,cAAc;GAC3B,CAAC;EACF,CAAC,CACF;AAED,QAAO;EAAE;EAAU;EAAe;EAAmB;;AAGtD,SAAgB,aAAa,SAAkD;AAC9E,wBAAuB,KAAK;CAE5B,MAAM,WAAW,oBAAoB,QAAQ,SAAS,QAAQ,aAAa;CAC3E,MAAM,gBAAgB,QAAQ,QAAQ;AACtC,iBACC,QAAQ,cACR,iBAAiB;EAChB,GAAG,SAAS;EACZ,QAAQ;EACR,aAAa,iBAAiB,cAAc,IAAI,QAAQ;EACxD,WAAW;EACX,SAAS;EACT,SAAS,SAAS;EAClB,CAAC,CACF;CAED,MAAM,SACL,QAAQ,eAAe,QAAQ,YAAY,SAAS,IACjD,QAAQ,cACR,uBAAuB;EACvB,aAAa,SAAS,QAAQ;EAC9B,QAAQ,QAAQ;EAChB,CAAC;CACL,MAAM,WAAW,eAAe,MAAM,QAAQ;EAC7C,KAAK,QAAQ;EACb,KAAK,QAAQ;EACb,CAAC;CACF,MAAM,gBAAgB,sBAAsB,QAAQ,cAAc,QAAQ,QAAQ;CAClF,MAAM,oBAAoB,YAAY,QAAQ,cAAc,QAAQ,QAAQ;AAC5E,eAAc,GAAG,kBAAkB,qBAAqB,SAAS,QAAQ,QAAQ;AACjF,eAAc,GAAG,kBAAkB,qBAAqB,SAAS,QAAQ,QAAQ;AACjF,eACC,GAAG,kBAAkB,0BACrB,GAAG,KAAK,UACP;EACC,SAAS;EACT,MAAM;EACN,UAAU,SAAS;EACnB,YAAY,cAAc;EAC1B,aAAa,cAAc;EAC3B,WAAW,cAAc;EACzB,EACD,MACA,EACA,CAAC,KACF,QACA;CAED,MAAM,oBACL,SAAS,OAAO,MAAM,KACrB,SAAS,aAAa,IACpB,GAAG,SAAS,MAAM,KAAK,mBACvB,GAAG,SAAS,MAAM,KAAK,yBAAyB,SAAS;AAC7D,oBAAmB;EAClB,cAAc,QAAQ;EACtB,SAAS,QAAQ;EACjB,KAAK;EACL,MAAM,QAAQ;EACd,MAAM;EACN,CAAC;AAEF,iBACC,QAAQ,cACR,iBAAiB;EAChB,GAAG,SAAS;EACZ,QAAQ,SAAS,aAAa,IAAI,SAAS;EAC3C,aAAa;EACb,WAAW,SAAS,aAAa,IAAI,OAAO;EAC5C,SAAS,SAAS,aAAa;EAC/B,SAAS,yBAAyB;GACjC,YAAY,cAAc;GAC1B,WAAW,cAAc;GACzB,aAAa,cAAc;GAC3B,CAAC;EACF,CAAC,CACF;AAED,QAAO;EAAE;EAAU;EAAe;EAAmB;;AAGtD,SAAgB,aAAa,SAAkD;AAE9E,KADkB,eAAe,QAAQ,cAAc,QAAQ,YAAY,KACzD,KAAM,OAAM,IAAI,MAAM,6BAA6B,QAAQ,cAAc;CAE3F,MAAM,UAAU,QAAQ,WAAW,GAAG,QAAQ,KAAK,GAAG,KAAK,KAAK;CAChE,MAAM,OAAO,iBAAiB;EAC7B,QAAQ,QAAQ,KAAK,KAAK;EAC1B,OAAO,QAAQ;EACf,QAAQ;EACR,MAAM,QAAQ;EACd,iBAAiB;EACjB,WAAW,QAAQ;EACnB,CAAC;AACF,iBAAgB,QAAQ,cAAc,KAAK;AAE3C,oBAAmB;EAClB,cAAc,QAAQ;EACtB,SAAS,QAAQ;EACjB,KAAK;EACL,MAAM,QAAQ;EACd,MAAM,aAAa,KAAK,OAAO,MAAM,QAAQ,IAAI,QAAQ;EACzD,CAAC;CAEF,MAAM,EAAE,UAAU,kBAAkB,cAAc;EACjD,UAAU,QAAQ;EAClB,cAAc,QAAQ;EACtB,MAAM,QAAQ;EACd;EACA,sBAAsB,QAAQ;EAC9B,eAAe,QAAQ;EACvB,MAAM,QAAQ;EACd,QAAQ,KAAK;EACb,CAAC;AAEF,oBAAmB;EAClB,cAAc,QAAQ;EACtB;EACA,KAAK;EACL,MAAM,QAAQ;EACd,MAAM,gBAAgB,QAAQ,YAAY,MAAM,KAAK,OAAO,IAAI,QAAQ;EACxE,CAAC;AAEF,iBAAgB,QAAQ,cAAc;EACrC,GAAG;EACH,QAAQ,SAAS,aAAa,IAAI,cAAc;EAChD,4BAAW,IAAI,MAAM,EAAC,aAAa;EACnC,CAAC;AAEF,QAAO;EACN,MAAM;GACL,GAAG;GACH,QAAQ,SAAS,aAAa,IAAI,cAAc;GAChD,4BAAW,IAAI,MAAM,EAAC,aAAa;GACnC;EACD;EACA;EACA;EACA"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["sanitize","processAlive","createPiInvocationArgs","writeJson","sleepMs"],"sources":["../src/lease.ts","../src/metrics.ts","../src/pi.ts","../src/shell.ts","../src/repo.ts","../src/controller.ts","../src/interrupts.ts","../src/loop.ts","../src/orchestration.ts","../src/stop.ts"],"sourcesContent":["import { mkdirSync, readFileSync, rmSync, writeFileSync } from \"node:fs\"\nimport { homedir, hostname } from \"node:os\"\nimport { join } from \"node:path\"\n\ninterface LeaseData {\n\trunId: string\n\trepoId: string\n\tbranch: string\n\tpid: number\n\thostname: string\n\tstartedAt: string\n}\n\nfunction sanitize(value: string): string {\n\treturn value.replace(/[^a-zA-Z0-9._-]+/g, \"_\")\n}\n\nfunction processAlive(pid: number): boolean {\n\tif (!Number.isFinite(pid) || pid <= 0) return false\n\ttry {\n\t\tprocess.kill(pid, 0)\n\t\treturn true\n\t} catch {\n\t\treturn false\n\t}\n}\n\nexport function acquireRepoLease(runId: string, repoId: string, branch: string): { path: string; release: () => void } {\n\tconst locksDir = join(homedir(), \".pi-town\", \"locks\")\n\tmkdirSync(locksDir, { recursive: true })\n\n\tconst leasePath = join(locksDir, `pi-town-${sanitize(repoId)}-${sanitize(branch)}.json`)\n\tconst nextData: LeaseData = {\n\t\trunId,\n\t\trepoId,\n\t\tbranch,\n\t\tpid: process.pid,\n\t\thostname: hostname(),\n\t\tstartedAt: new Date().toISOString(),\n\t}\n\n\ttry {\n\t\tconst current = JSON.parse(readFileSync(leasePath, \"utf-8\")) as LeaseData\n\t\tif (processAlive(current.pid)) {\n\t\t\tthrow new Error(`Pi Town lease already held by pid ${current.pid} on ${current.hostname} for run ${current.runId}.`)\n\t\t}\n\t\trmSync(leasePath, { force: true })\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code !== \"ENOENT\") {\n\t\t\tif (error instanceof Error && error.message.startsWith(\"Pi Town lease already held\")) throw error\n\t\t}\n\t}\n\n\twriteFileSync(leasePath, `${JSON.stringify(nextData, null, 2)}\\n`, \"utf-8\")\n\n\treturn {\n\t\tpath: leasePath,\n\t\trelease: () => {\n\t\t\ttry {\n\t\t\t\tconst current = JSON.parse(readFileSync(leasePath, \"utf-8\")) as LeaseData\n\t\t\t\tif (current.runId === runId) rmSync(leasePath, { force: true })\n\t\t\t} catch {\n\t\t\t\t// ignore cleanup failures\n\t\t\t}\n\t\t},\n\t}\n}\n","import type { FeedbackCycle, InterruptRecord, MetricsSnapshot, TaskAttempt } from \"./types.js\"\n\nfunction round(value: number): number {\n\treturn Math.round(value * 1000) / 1000\n}\n\nfunction diffHours(start: string, end: string): number {\n\treturn (Date.parse(end) - Date.parse(start)) / 3_600_000\n}\n\nfunction average(values: number[]): number | null {\n\tif (values.length === 0) return null\n\treturn values.reduce((sum, value) => sum + value, 0) / values.length\n}\n\nexport function computeInterruptRate(interrupts: InterruptRecord[], taskAttempts: TaskAttempt[]): number {\n\tif (taskAttempts.length === 0) return 0\n\treturn round(interrupts.length / taskAttempts.length)\n}\n\nexport function computeAutonomousCompletionRate(taskAttempts: TaskAttempt[]): number {\n\tconst completed = taskAttempts.filter((task) => task.status === \"completed\")\n\tif (completed.length === 0) return 0\n\tconst autonomous = completed.filter((task) => !task.interrupted)\n\treturn round(autonomous.length / completed.length)\n}\n\nexport function computeContextCoverageScore(interrupts: InterruptRecord[]): number {\n\tconst observed = new Set(interrupts.map((interrupt) => interrupt.category))\n\tif (observed.size === 0) return 0\n\n\tconst covered = new Set(\n\t\tinterrupts.filter((interrupt) => interrupt.fixType).map((interrupt) => interrupt.category),\n\t)\n\n\treturn round(covered.size / observed.size)\n}\n\nexport function computeMeanTimeToCorrect(interrupts: InterruptRecord[]): number | null {\n\tconst resolved = interrupts.filter((interrupt) => interrupt.resolvedAt)\n\tconst hours = resolved.map((interrupt) => diffHours(interrupt.createdAt, interrupt.resolvedAt!))\n\tconst value = average(hours)\n\treturn value === null ? null : round(value)\n}\n\nexport function computeFeedbackToDemoCycleTime(feedbackCycles: FeedbackCycle[]): number | null {\n\tconst hours = feedbackCycles.map((cycle) => diffHours(cycle.feedbackAt, cycle.demoReadyAt))\n\tconst value = average(hours)\n\treturn value === null ? null : round(value)\n}\n\nexport function computeMetrics(input: {\n\ttaskAttempts: TaskAttempt[]\n\tinterrupts: InterruptRecord[]\n\tfeedbackCycles?: FeedbackCycle[]\n}): MetricsSnapshot {\n\tconst observedCategories = new Set(input.interrupts.map((interrupt) => interrupt.category))\n\tconst coveredCategories = new Set(\n\t\tinput.interrupts.filter((interrupt) => interrupt.fixType).map((interrupt) => interrupt.category),\n\t)\n\tconst completedTasks = input.taskAttempts.filter((task) => task.status === \"completed\").length\n\n\treturn {\n\t\tinterruptRate: computeInterruptRate(input.interrupts, input.taskAttempts),\n\t\tautonomousCompletionRate: computeAutonomousCompletionRate(input.taskAttempts),\n\t\tcontextCoverageScore: computeContextCoverageScore(input.interrupts),\n\t\tmeanTimeToCorrectHours: computeMeanTimeToCorrect(input.interrupts),\n\t\tfeedbackToDemoCycleTimeHours: computeFeedbackToDemoCycleTime(input.feedbackCycles ?? []),\n\t\ttotals: {\n\t\t\ttaskAttempts: input.taskAttempts.length,\n\t\t\tcompletedTasks,\n\t\t\tinterrupts: input.interrupts.length,\n\t\t\tobservedInterruptCategories: observedCategories.size,\n\t\t\tcoveredInterruptCategories: coveredCategories.size,\n\t\t},\n\t}\n}\n","export function detectPiAuthFailure(stderr: string, stdout: string): boolean {\n\tconst output = `${stdout}\\n${stderr}`.toLowerCase()\n\treturn (\n\t\toutput.includes(\"no models available\") ||\n\t\toutput.includes(\"not authenticated\") ||\n\t\toutput.includes(\"authentication\") ||\n\t\toutput.includes(\"/login\") ||\n\t\toutput.includes(\"api key\")\n\t)\n}\n\nexport function createPiAuthHelpMessage(): string {\n\treturn 'Pi appears to be installed but not authenticated or configured. Verify Pi works first: pi -p \"hello\". Either set an API key or run `pi` and use `/login`.'\n}\n","import { spawnSync } from \"node:child_process\"\n\nexport interface CommandResult {\n\tstdout: string\n\tstderr: string\n\texitCode: number\n}\n\nexport function runCommandSync(\n\tcommand: string,\n\targs: string[],\n\toptions?: { cwd?: string; env?: NodeJS.ProcessEnv },\n): CommandResult {\n\tconst result = spawnSync(command, args, {\n\t\tcwd: options?.cwd,\n\t\tenv: options?.env,\n\t\tencoding: \"utf-8\",\n\t})\n\tconst errorText = result.error instanceof Error ? `${result.error.message}\n` : \"\"\n\n\treturn {\n\t\tstdout: result.stdout ?? \"\",\n\t\tstderr: `${errorText}${result.stderr ?? \"\"}`,\n\t\texitCode: result.status ?? 1,\n\t}\n}\n\nexport function assertCommandAvailable(command: string) {\n\tconst result = spawnSync(command, [\"--help\"], {\n\t\tencoding: \"utf-8\",\n\t\tstdio: \"ignore\",\n\t})\n\n\tif (result.error instanceof Error) {\n\t\tthrow new Error(result.error.message)\n\t}\n}\n\nexport function runCommandInteractive(\n\tcommand: string,\n\targs: string[],\n\toptions?: { cwd?: string; env?: NodeJS.ProcessEnv },\n): number {\n\tconst result = spawnSync(command, args, {\n\t\tcwd: options?.cwd,\n\t\tenv: options?.env,\n\t\tstdio: \"inherit\",\n\t})\n\n\tif (result.error instanceof Error) {\n\t\tthrow new Error(result.error.message)\n\t}\n\n\treturn result.status ?? 1\n}\n\nexport function assertSuccess(result: CommandResult, context: string) {\n\tif (result.exitCode === 0) return\n\tconst details = [result.stdout.trim(), result.stderr.trim()].filter(Boolean).join(\"\\n\")\n\tthrow new Error(`${context} failed${details ? `\\n${details}` : \"\"}`)\n}\n","import { createHash } from \"node:crypto\"\nimport { existsSync } from \"node:fs\"\nimport { basename, resolve } from \"node:path\"\nimport { assertSuccess, runCommandSync } from \"./shell.js\"\n\nfunction gitResult(cwd: string, args: string[]) {\n\treturn runCommandSync(\"git\", args, { cwd })\n}\n\nfunction sanitize(value: string): string {\n\treturn value.replace(/[^a-zA-Z0-9._-]+/g, \"-\").replace(/^-+|-+$/g, \"\") || \"repo\"\n}\n\nexport function isGitRepo(cwd: string): boolean {\n\tconst result = gitResult(cwd, [\"rev-parse\", \"--is-inside-work-tree\"])\n\treturn result.exitCode === 0 && result.stdout.trim() === \"true\"\n}\n\nexport function getRepoRoot(cwd: string): string {\n\tif (!isGitRepo(cwd)) return resolve(cwd)\n\tconst result = gitResult(cwd, [\"rev-parse\", \"--show-toplevel\"])\n\tassertSuccess(result, \"git rev-parse --show-toplevel\")\n\treturn resolve(result.stdout.trim())\n}\n\nexport function getCurrentBranch(cwd: string): string | null {\n\tif (!isGitRepo(cwd)) return null\n\tconst result = gitResult(cwd, [\"rev-parse\", \"--abbrev-ref\", \"HEAD\"])\n\tif (result.exitCode !== 0) return null\n\tconst branch = result.stdout.trim()\n\treturn branch || null\n}\n\nexport function getRepoIdentity(cwd: string): string {\n\tif (!isGitRepo(cwd)) return resolve(cwd)\n\n\tconst remote = gitResult(cwd, [\"config\", \"--get\", \"remote.origin.url\"])\n\tconst remoteValue = remote.stdout.trim()\n\tif (remote.exitCode === 0 && remoteValue) return remoteValue\n\n\tconst root = gitResult(cwd, [\"rev-parse\", \"--show-toplevel\"])\n\tassertSuccess(root, \"git rev-parse --show-toplevel\")\n\tconst commonDir = gitResult(cwd, [\"rev-parse\", \"--git-common-dir\"])\n\tassertSuccess(commonDir, \"git rev-parse --git-common-dir\")\n\n\tconst rootPath = resolve(root.stdout.trim())\n\tconst commonDirPath = commonDir.stdout.trim()\n\treturn `${basename(rootPath)}:${rootPath}:${existsSync(commonDirPath) ? resolve(commonDirPath) : commonDirPath}`\n}\n\nexport function createRepoSlug(repoId: string, repoRoot: string): string {\n\tconst name = sanitize(basename(repoRoot))\n\tconst digest = createHash(\"sha1\").update(repoId).digest(\"hex\").slice(0, 8)\n\treturn `${name}-${digest}`\n}\n","import { mkdirSync, writeFileSync } from \"node:fs\"\nimport { join } from \"node:path\"\nimport {\n\tcreateAgentSessionRecord,\n\tcreateAgentState,\n\tgetAgentSessionsDir,\n\tgetLatestAgentSession,\n\treadAgentState,\n\twriteAgentState,\n} from \"./agents.js\"\nimport { appendJsonl } from \"./events.js\"\nimport { acquireRepoLease } from \"./lease.js\"\nimport { computeMetrics } from \"./metrics.js\"\nimport { createPiAuthHelpMessage, detectPiAuthFailure } from \"./pi.js\"\nimport { createRepoSlug, getCurrentBranch, getRepoIdentity, getRepoRoot } from \"./repo.js\"\nimport { assertCommandAvailable, runCommandSync } from \"./shell.js\"\nimport type { ControllerRunResult, PiInvocationRecord, RunManifest, RunOptions, RunSummary } from \"./types.js\"\n\nfunction createRunId(): string {\n\treturn `run-${new Date().toISOString().replace(/[:.]/g, \"-\")}`\n}\n\nfunction createPiInvocationArgs(input: {\n\tsessionDir?: string | null\n\tsessionPath?: string | null\n\tprompt: string\n\tappendedSystemPrompt?: string | null | undefined\n\textensionPath?: string | null | undefined\n}) {\n\tconst args: string[] = []\n\n\tif (input.extensionPath) args.push(\"--extension\", input.extensionPath)\n\tif (input.appendedSystemPrompt) args.push(\"--append-system-prompt\", input.appendedSystemPrompt)\n\tif (input.sessionPath) args.push(\"--session\", input.sessionPath)\n\telse if (input.sessionDir) args.push(\"--session-dir\", input.sessionDir)\n\telse throw new Error(\"Pi invocation requires a session path or session directory\")\n\targs.push(\"-p\", input.prompt)\n\n\treturn args\n}\n\nfunction writeJson(path: string, value: unknown) {\n\twriteFileSync(path, `${JSON.stringify(value, null, 2)}\\n`, \"utf-8\")\n}\n\nfunction writeText(path: string, value: string) {\n\twriteFileSync(path, value, \"utf-8\")\n}\n\nfunction createPiPrompt(input: {\n\trepoRoot: string\n\tplanPath: string | null\n\tgoal: string | null\n\trecommendedPlanDir: string | null\n}): string {\n\tconst goal = input.goal ?? \"continue from current scaffold state\"\n\n\tif (input.planPath) {\n\t\treturn [\n\t\t\t\"You are the Pi Town mayor agent for this repository.\",\n\t\t\t\"Coordinate the next bounded unit of work, keep updates concise, and leave a durable artifact trail.\",\n\t\t\t\"\",\n\t\t\t\"Read the private plans in:\",\n\t\t\t`- ${input.planPath}`,\n\t\t\t\"\",\n\t\t\t\"and the current code in:\",\n\t\t\t`- ${input.repoRoot}`,\n\t\t\t\"\",\n\t\t\t`Goal: ${goal}`,\n\t\t\t\"Continue from the current scaffold state.\",\n\t\t\t\"Keep any persisted run artifacts high-signal and avoid copying private plan contents into them.\",\n\t\t].join(\"\\n\")\n\t}\n\n\treturn [\n\t\t\"You are the Pi Town mayor agent for this repository.\",\n\t\t\"Coordinate the next bounded unit of work, keep updates concise, and leave a durable artifact trail.\",\n\t\t\"\",\n\t\t`Work in the repository at: ${input.repoRoot}`,\n\t\t`Goal: ${goal}`,\n\t\t\"No private plan path is configured for this run.\",\n\t\tinput.recommendedPlanDir\n\t\t\t? `If you need private plans, use a user-owned location such as: ${input.recommendedPlanDir}`\n\t\t\t: \"If you need private plans, keep them in a user-owned location outside the repo.\",\n\t\t\"Continue from the current scaffold state.\",\n\t].join(\"\\n\")\n}\n\nfunction assertPiRuntimeAvailable(piCommand: string) {\n\ttry {\n\t\tassertCommandAvailable(piCommand)\n\t} catch (error) {\n\t\tif (piCommand === \"pi\") {\n\t\t\tthrow new Error(\n\t\t\t\t[\n\t\t\t\t\t\"Pi Town requires the `pi` CLI to run `pitown run`.\",\n\t\t\t\t\t\"Install Pi: npm install -g @mariozechner/pi-coding-agent\",\n\t\t\t\t\t\"Then authenticate Pi and verify it works: pi -p \\\"hello\\\"\",\n\t\t\t\t\t`Details: ${(error as Error).message}`,\n\t\t\t\t].join(\"\\n\"),\n\t\t\t)\n\t\t}\n\n\t\tthrow new Error(\n\t\t\t[\n\t\t\t\t`Pi Town could not execute the configured Pi command: ${piCommand}`,\n\t\t\t\t\"Make sure the command exists on PATH or points to an executable file.\",\n\t\t\t\t`Details: ${(error as Error).message}`,\n\t\t\t].join(\"\\n\"),\n\t\t)\n\t}\n}\n\nfunction createManifest(input: {\n\trunId: string\n\trepoId: string\n\trepoSlug: string\n\trepoRoot: string\n\tbranch: string\n\tgoal: string | null\n\tplanPath: string | null\n\trecommendedPlanDir: string | null\n\tmode: \"single-pi\"\n\tleasePath: string\n}): RunManifest {\n\treturn {\n\t\trunId: input.runId,\n\t\trepoId: input.repoId,\n\t\trepoSlug: input.repoSlug,\n\t\trepoRoot: input.repoRoot,\n\t\tbranch: input.branch,\n\t\tgoal: input.goal,\n\t\tplanPath: input.planPath,\n\t\trecommendedPlanDir: input.recommendedPlanDir,\n\t\tmode: input.mode,\n\t\tstartedAt: new Date().toISOString(),\n\t\tendedAt: null,\n\t\tstopReason: null,\n\t\tleasePath: input.leasePath,\n\t\tpiExitCode: null,\n\t\tcompletedTaskCount: 0,\n\t\tblockedTaskCount: 0,\n\t\tskippedTaskCount: 0,\n\t\ttotalCostUsd: 0,\n\t}\n}\n\nfunction createSummary(input: {\n\trunId: string\n\tmode: \"single-pi\"\n\texitCode: number\n\tstdout: string\n\tstderr: string\n\trecommendedPlanDir: string | null\n}): RunSummary {\n\tconst success = input.exitCode === 0\n\tconst recommendation =\n\t\tinput.recommendedPlanDir === null\n\t\t\t? \"\"\n\t\t\t: ` No plan path was configured. Recommended private plans location: ${input.recommendedPlanDir}.`\n\tconst authHelp =\n\t\tsuccess || !detectPiAuthFailure(input.stderr, input.stdout) ? \"\" : ` ${createPiAuthHelpMessage()}`\n\n\treturn {\n\t\trunId: input.runId,\n\t\tmode: input.mode,\n\t\tcreatedAt: new Date().toISOString(),\n\t\tsuccess,\n\t\tmessage: success\n\t\t\t? `Pi invocation completed.${recommendation}`\n\t\t\t: `Pi invocation failed.${authHelp}${recommendation}`,\n\t\tpiExitCode: input.exitCode,\n\t\trecommendedPlanDir: input.recommendedPlanDir,\n\t}\n}\n\nexport function runController(options: RunOptions): ControllerRunResult {\n\tconst cwd = options.cwd ?? process.cwd()\n\tconst artifactsDir = options.artifactsDir\n\tconst repoRoot = getRepoRoot(cwd)\n\tconst repoId = getRepoIdentity(repoRoot)\n\tconst repoSlug = createRepoSlug(repoId, repoRoot)\n\tconst branch = options.branch ?? getCurrentBranch(repoRoot) ?? \"workspace\"\n\tconst goal = options.goal ?? null\n\tconst planPath = options.planPath ?? null\n\tconst recommendedPlanDir = planPath ? null : (options.recommendedPlanDir ?? null)\n\tconst mode = options.mode ?? \"single-pi\"\n\tconst piCommand = options.piCommand ?? \"pi\"\n\tconst runId = createRunId()\n\tconst runDir = join(artifactsDir, \"runs\", runId)\n\tconst latestDir = join(artifactsDir, \"latest\")\n\tconst stdoutPath = join(runDir, \"stdout.txt\")\n\tconst stderrPath = join(runDir, \"stderr.txt\")\n\tconst prompt = createPiPrompt({ repoRoot, planPath, goal, recommendedPlanDir })\n\tconst existingMayorState = readAgentState(artifactsDir, \"mayor\")\n\tconst existingMayorSession =\n\t\texistingMayorState?.session.sessionPath || existingMayorState?.session.sessionDir\n\t\t\t? existingMayorState.session\n\t\t\t: getLatestAgentSession(artifactsDir, \"mayor\")\n\tconst mayorSessionDir = existingMayorSession.sessionDir ?? getAgentSessionsDir(artifactsDir, \"mayor\")\n\tconst mayorState = createAgentState({\n\t\tagentId: \"mayor\",\n\t\trole: \"mayor\",\n\t\tstatus: \"starting\",\n\t\ttask: goal,\n\t\tbranch,\n\t\tlastMessage: goal ? `Starting mayor run for goal: ${goal}` : \"Starting mayor run\",\n\t\trunId,\n\t\tsession: createAgentSessionRecord({\n\t\t\tsessionDir: mayorSessionDir,\n\t\t\tsessionId: existingMayorSession.sessionId,\n\t\t\tsessionPath: existingMayorSession.sessionPath,\n\t\t}),\n\t})\n\n\tassertPiRuntimeAvailable(piCommand)\n\n\tmkdirSync(runDir, { recursive: true })\n\tmkdirSync(latestDir, { recursive: true })\n\n\twriteText(join(runDir, \"questions.jsonl\"), \"\")\n\twriteText(join(runDir, \"interventions.jsonl\"), \"\")\n\twriteJson(join(runDir, \"agent-state.json\"), {\n\t\tstatus: \"starting\",\n\t\tupdatedAt: new Date().toISOString(),\n\t})\n\twriteAgentState(artifactsDir, mayorState)\n\n\tconst lease = acquireRepoLease(runId, repoId, branch)\n\n\ttry {\n\t\tconst manifest = createManifest({\n\t\t\trunId,\n\t\t\trepoId,\n\t\t\trepoSlug,\n\t\t\trepoRoot,\n\t\t\tbranch,\n\t\t\tgoal,\n\t\t\tplanPath,\n\t\t\trecommendedPlanDir,\n\t\t\tmode,\n\t\t\tleasePath: lease.path,\n\t\t})\n\n\t\tappendJsonl(join(runDir, \"events.jsonl\"), {\n\t\t\ttype: \"run_started\",\n\t\t\trunId,\n\t\t\trepoId,\n\t\t\trepoSlug,\n\t\t\tbranch,\n\t\t\tcreatedAt: manifest.startedAt,\n\t\t})\n\n\t\tconst piStartedAt = new Date().toISOString()\n\t\tappendJsonl(join(runDir, \"events.jsonl\"), {\n\t\t\ttype: \"pi_invocation_started\",\n\t\t\trunId,\n\t\t\tcommand: piCommand,\n\t\t\tcreatedAt: piStartedAt,\n\t\t})\n\n\t\twriteAgentState(\n\t\t\tartifactsDir,\n\t\t\tcreateAgentState({\n\t\t\t\t...mayorState,\n\t\t\t\tstatus: \"running\",\n\t\t\t\tlastMessage: goal ? `Mayor working on: ${goal}` : \"Mayor working\",\n\t\t\t}),\n\t\t)\n\n\t\tconst piArgs = createPiInvocationArgs({\n\t\t\tsessionDir: mayorState.session.sessionPath === null ? mayorSessionDir : null,\n\t\t\tsessionPath: mayorState.session.sessionPath,\n\t\t\tprompt,\n\t\t\tappendedSystemPrompt: options.appendedSystemPrompt,\n\t\t\textensionPath: options.extensionPath,\n\t\t})\n\t\tconst piResult = runCommandSync(piCommand, piArgs, {\n\t\t\tcwd: repoRoot,\n\t\t\tenv: process.env,\n\t\t})\n\t\tconst piEndedAt = new Date().toISOString()\n\t\tconst latestMayorSession = getLatestAgentSession(artifactsDir, \"mayor\")\n\n\t\twriteText(stdoutPath, piResult.stdout)\n\t\twriteText(stderrPath, piResult.stderr)\n\n\t\tconst piInvocation: PiInvocationRecord = {\n\t\t\tcommand: piCommand,\n\t\t\tcwd: repoRoot,\n\t\t\trepoRoot,\n\t\t\tplanPath,\n\t\t\tgoal,\n\t\t\tsessionDir: latestMayorSession.sessionDir,\n\t\t\tsessionId: latestMayorSession.sessionId,\n\t\t\tsessionPath: latestMayorSession.sessionPath,\n\t\t\tstartedAt: piStartedAt,\n\t\t\tendedAt: piEndedAt,\n\t\t\texitCode: piResult.exitCode,\n\t\t\tstdoutPath,\n\t\t\tstderrPath,\n\t\t\tpromptSummary: planPath\n\t\t\t\t? \"Read private plan path and continue from current scaffold state.\"\n\t\t\t\t: \"Continue from current scaffold state without a configured private plan path.\",\n\t\t}\n\t\twriteJson(join(runDir, \"pi-invocation.json\"), piInvocation)\n\n\t\tappendJsonl(join(runDir, \"events.jsonl\"), {\n\t\t\ttype: \"pi_invocation_finished\",\n\t\t\trunId,\n\t\t\tcommand: piCommand,\n\t\t\texitCode: piInvocation.exitCode,\n\t\t\tcreatedAt: piEndedAt,\n\t\t})\n\n\t\tconst metrics = computeMetrics({\n\t\t\ttaskAttempts: [],\n\t\t\tinterrupts: [],\n\t\t})\n\t\tconst summary = createSummary({\n\t\t\trunId,\n\t\t\tmode,\n\t\t\texitCode: piInvocation.exitCode,\n\t\t\tstdout: piResult.stdout,\n\t\t\tstderr: piResult.stderr,\n\t\t\trecommendedPlanDir,\n\t\t})\n\t\tconst finalManifest: RunManifest = {\n\t\t\t...manifest,\n\t\t\tendedAt: piEndedAt,\n\t\t\tstopReason:\n\t\t\t\tpiInvocation.exitCode === 0\n\t\t\t\t\t? \"pi invocation completed\"\n\t\t\t\t\t: `pi invocation exited with code ${piInvocation.exitCode}`,\n\t\t\tpiExitCode: piInvocation.exitCode,\n\t\t}\n\n\t\twriteJson(join(runDir, \"manifest.json\"), finalManifest)\n\t\twriteJson(join(runDir, \"metrics.json\"), metrics)\n\t\twriteJson(join(runDir, \"run-summary.json\"), summary)\n\t\twriteJson(join(runDir, \"agent-state.json\"), {\n\t\t\tstatus: summary.success ? \"completed\" : \"failed\",\n\t\t\tupdatedAt: piEndedAt,\n\t\t\texitCode: piInvocation.exitCode,\n\t\t})\n\t\twriteJson(join(latestDir, \"manifest.json\"), finalManifest)\n\t\twriteJson(join(latestDir, \"metrics.json\"), metrics)\n\t\twriteJson(join(latestDir, \"run-summary.json\"), summary)\n\t\twriteAgentState(\n\t\t\tartifactsDir,\n\t\t\tcreateAgentState({\n\t\t\t\t...mayorState,\n\t\t\t\t\tstatus: piInvocation.exitCode === 0 ? \"idle\" : \"blocked\",\n\t\t\t\t\tlastMessage:\n\t\t\t\t\t\tpiInvocation.exitCode === 0\n\t\t\t\t\t\t\t? \"Mayor run completed and is ready for the next instruction\"\n\t\t\t\t\t\t\t: `Mayor run stopped with exit code ${piInvocation.exitCode}`,\n\t\t\t\t\tblocked: piInvocation.exitCode !== 0,\n\t\t\t\t\twaitingOn: piInvocation.exitCode === 0 ? null : \"human-or-follow-up-run\",\n\t\t\t\t\tsession: createAgentSessionRecord({\n\t\t\t\t\t\tsessionDir: latestMayorSession.sessionDir,\n\t\t\t\t\t\tsessionId: latestMayorSession.sessionId,\n\t\t\t\t\t\tsessionPath: latestMayorSession.sessionPath,\n\t\t\t\t\t}),\n\t\t\t\t}),\n\t\t\t)\n\n\t\tappendJsonl(join(runDir, \"events.jsonl\"), {\n\t\t\ttype: \"run_finished\",\n\t\t\trunId,\n\t\t\tcreatedAt: finalManifest.endedAt,\n\t\t\tstopReason: finalManifest.stopReason,\n\t\t\tmetrics,\n\t\t})\n\n\t\treturn {\n\t\t\trunId,\n\t\t\trunDir,\n\t\t\tlatestDir,\n\t\t\tmanifest: finalManifest,\n\t\t\tmetrics,\n\t\t\tsummary,\n\t\t\tpiInvocation,\n\t\t}\n\t} finally {\n\t\tlease.release()\n\t}\n}\n","import { randomUUID } from \"node:crypto\"\nimport type { InterruptCategory, InterruptRecord } from \"./types.js\"\n\nexport interface CreateInterruptInput {\n\trunId: string\n\ttaskId?: string\n\tcategory: InterruptCategory\n\tsubtype?: string\n\tsummary: string\n\trequiresHuman?: boolean\n\tcreatedAt?: string\n}\n\nexport function createInterruptRecord(input: CreateInterruptInput): InterruptRecord {\n\treturn {\n\t\tid: randomUUID(),\n\t\trunId: input.runId,\n\t\tcategory: input.category,\n\t\tsummary: input.summary,\n\t\trequiresHuman: input.requiresHuman ?? true,\n\t\tcreatedAt: input.createdAt ?? new Date().toISOString(),\n\t\t...(input.taskId ? { taskId: input.taskId } : {}),\n\t\t...(input.subtype ? { subtype: input.subtype } : {}),\n\t}\n}\n\nexport function resolveInterrupt(\n\tinterrupt: InterruptRecord,\n\toptions: Pick<InterruptRecord, \"resolvedAt\" | \"fixType\">,\n): InterruptRecord {\n\treturn {\n\t\t...interrupt,\n\t\t...(options.resolvedAt ? { resolvedAt: options.resolvedAt } : {}),\n\t\t...(options.fixType ? { fixType: options.fixType } : {}),\n\t}\n}\n","import { mkdirSync, writeFileSync } from \"node:fs\"\nimport { join } from \"node:path\"\nimport { listAgentStates } from \"./agents.js\"\nimport { runController } from \"./controller.js\"\nimport { appendJsonl } from \"./events.js\"\nimport { computeMetrics } from \"./metrics.js\"\nimport { listTaskRecords } from \"./tasks.js\"\nimport type {\n\tBoardSnapshot,\n\tControllerRunResult,\n\tLoopIterationResult,\n\tLoopOptions,\n\tLoopRunResult,\n\tLoopStopReason,\n\tMetricsSnapshot,\n} from \"./types.js\"\n\nconst DEFAULT_MAX_ITERATIONS = 10\nconst DEFAULT_MAX_WALL_TIME_MS = 3_600_000\nconst DEFAULT_BACKGROUND_POLL_MS = 250\n\nfunction createLoopId(): string {\n\treturn `loop-${new Date().toISOString().replace(/[:.]/g, \"-\")}`\n}\n\nfunction writeJson(path: string, value: unknown) {\n\twriteFileSync(path, `${JSON.stringify(value, null, 2)}\\n`, \"utf-8\")\n}\n\nfunction sleepMs(ms: number) {\n\tAtomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms)\n}\n\nfunction hasBackgroundWork(board: BoardSnapshot): boolean {\n\treturn (\n\t\tboard.agents.some(\n\t\t\t(agent) =>\n\t\t\t\tagent.agentId !== \"mayor\" &&\n\t\t\t\t(agent.status === \"queued\" || agent.status === \"running\" || agent.status === \"starting\"),\n\t\t) || board.tasks.some((task) => task.status === \"queued\" || task.status === \"running\")\n\t)\n}\n\nfunction waitForBackgroundWorkToSettle(input: {\n\tartifactsDir: string\n\tmaxWallTimeMs: number\n\tloopStartedAt: number\n\tpollIntervalMs?: number\n}): { timedOut: boolean; board: BoardSnapshot } {\n\tconst pollIntervalMs = input.pollIntervalMs ?? DEFAULT_BACKGROUND_POLL_MS\n\tlet board = snapshotBoard(input.artifactsDir)\n\n\twhile (hasBackgroundWork(board)) {\n\t\tif (Date.now() - input.loopStartedAt >= input.maxWallTimeMs) {\n\t\t\treturn { timedOut: true, board }\n\t\t}\n\n\t\tsleepMs(pollIntervalMs)\n\t\tboard = snapshotBoard(input.artifactsDir)\n\t}\n\n\treturn { timedOut: false, board }\n}\n\nexport function snapshotBoard(artifactsDir: string): BoardSnapshot {\n\tconst tasks = listTaskRecords(artifactsDir)\n\tconst agents = listAgentStates(artifactsDir)\n\n\tconst taskEntries = tasks.map((task) => ({ taskId: task.taskId, status: task.status }))\n\tconst agentEntries = agents.map((agent) => ({\n\t\tagentId: agent.agentId,\n\t\tstatus: agent.status,\n\t\tblocked: agent.blocked,\n\t}))\n\n\tconst allTasksCompleted = tasks.length > 0 && tasks.every((task) => task.status === \"completed\")\n\tconst allRemainingTasksBlocked =\n\t\ttasks.length > 0 && tasks.every((task) => task.status === \"completed\" || task.status === \"blocked\" || task.status === \"aborted\")\n\n\tconst mayor = agents.find((agent) => agent.agentId === \"mayor\")\n\tconst mayorBlocked = mayor?.blocked === true\n\n\tconst hasQueuedOrRunningWork =\n\t\tagents.some((agent) => agent.status === \"queued\" || agent.status === \"running\" || agent.status === \"starting\") ||\n\t\ttasks.some((task) => task.status === \"queued\" || task.status === \"running\")\n\n\treturn {\n\t\ttasks: taskEntries,\n\t\tagents: agentEntries,\n\t\tallTasksCompleted,\n\t\tallRemainingTasksBlocked,\n\t\tmayorBlocked,\n\t\thasQueuedOrRunningWork,\n\t}\n}\n\nexport function evaluateStopCondition(input: {\n\titeration: number\n\tmaxIterations: number\n\telapsedMs: number\n\tmaxWallTimeMs: number\n\tpiExitCode: number\n\tstopOnPiFailure: boolean\n\tstopOnMayorIdleNoWork: boolean\n\tboard: BoardSnapshot\n\tmetrics: MetricsSnapshot\n\tinterruptRateThreshold: number | null\n}): { stopReason: LoopStopReason | null; continueReason: string | null } {\n\tif (input.iteration >= input.maxIterations) {\n\t\treturn { stopReason: \"max-iterations-reached\", continueReason: null }\n\t}\n\n\tif (input.elapsedMs >= input.maxWallTimeMs) {\n\t\treturn { stopReason: \"max-wall-time-reached\", continueReason: null }\n\t}\n\n\tif (input.stopOnPiFailure && input.piExitCode !== 0) {\n\t\treturn { stopReason: \"pi-exit-nonzero\", continueReason: null }\n\t}\n\n\tif (input.board.allTasksCompleted) {\n\t\treturn { stopReason: \"all-tasks-completed\", continueReason: null }\n\t}\n\n\tif (input.board.mayorBlocked) {\n\t\treturn { stopReason: \"mayor-blocked\", continueReason: null }\n\t}\n\n\tconst mayor = input.board.agents.find((agent) => agent.agentId === \"mayor\")\n\tif (input.stopOnMayorIdleNoWork && mayor && !input.board.hasQueuedOrRunningWork && input.board.tasks.length === 0 && mayor.status === \"idle\") {\n\t\treturn { stopReason: \"mayor-idle-no-work\", continueReason: null }\n\t}\n\n\tif (input.board.allRemainingTasksBlocked) {\n\t\treturn { stopReason: \"all-remaining-tasks-blocked\", continueReason: null }\n\t}\n\n\tif (\n\t\tinput.interruptRateThreshold !== null &&\n\t\tinput.metrics.interruptRate > input.interruptRateThreshold\n\t) {\n\t\treturn { stopReason: \"high-interrupt-rate\", continueReason: null }\n\t}\n\n\tconst reasons: string[] = []\n\tif (input.board.hasQueuedOrRunningWork) reasons.push(\"queued or running work remains\")\n\tif (input.board.tasks.length === 0) reasons.push(\"no tasks tracked yet\")\n\tif (reasons.length === 0) reasons.push(\"mayor idle, no stop condition met\")\n\n\treturn { stopReason: null, continueReason: reasons.join(\"; \") }\n}\n\nfunction aggregateMetrics(iterations: LoopIterationResult[]): MetricsSnapshot {\n\tif (iterations.length === 0) {\n\t\treturn computeMetrics({ taskAttempts: [], interrupts: [] })\n\t}\n\n\tlet totalTaskAttempts = 0\n\tlet totalCompletedTasks = 0\n\tlet totalInterrupts = 0\n\tlet totalObservedInterruptCategories = 0\n\tlet totalCoveredInterruptCategories = 0\n\tlet interruptRateSum = 0\n\tlet autonomousCompletionRateSum = 0\n\tlet contextCoverageScoreSum = 0\n\tlet mttcValues: number[] = []\n\tlet ftdValues: number[] = []\n\n\tfor (const iter of iterations) {\n\t\tconst m = iter.metrics\n\t\ttotalTaskAttempts += m.totals.taskAttempts\n\t\ttotalCompletedTasks += m.totals.completedTasks\n\t\ttotalInterrupts += m.totals.interrupts\n\t\ttotalObservedInterruptCategories += m.totals.observedInterruptCategories\n\t\ttotalCoveredInterruptCategories += m.totals.coveredInterruptCategories\n\t\tinterruptRateSum += m.interruptRate\n\t\tautonomousCompletionRateSum += m.autonomousCompletionRate\n\t\tcontextCoverageScoreSum += m.contextCoverageScore\n\t\tif (m.meanTimeToCorrectHours !== null) mttcValues.push(m.meanTimeToCorrectHours)\n\t\tif (m.feedbackToDemoCycleTimeHours !== null) ftdValues.push(m.feedbackToDemoCycleTimeHours)\n\t}\n\n\tconst count = iterations.length\n\tconst round = (v: number) => Math.round(v * 1000) / 1000\n\tconst avg = (values: number[]) => (values.length === 0 ? null : round(values.reduce((s, v) => s + v, 0) / values.length))\n\n\treturn {\n\t\tinterruptRate: round(interruptRateSum / count),\n\t\tautonomousCompletionRate: round(autonomousCompletionRateSum / count),\n\t\tcontextCoverageScore: round(contextCoverageScoreSum / count),\n\t\tmeanTimeToCorrectHours: avg(mttcValues),\n\t\tfeedbackToDemoCycleTimeHours: avg(ftdValues),\n\t\ttotals: {\n\t\t\ttaskAttempts: totalTaskAttempts,\n\t\t\tcompletedTasks: totalCompletedTasks,\n\t\t\tinterrupts: totalInterrupts,\n\t\t\tobservedInterruptCategories: totalObservedInterruptCategories,\n\t\t\tcoveredInterruptCategories: totalCoveredInterruptCategories,\n\t\t},\n\t}\n}\n\nexport function runLoop(options: LoopOptions): LoopRunResult {\n\tconst maxIterations = options.maxIterations ?? DEFAULT_MAX_ITERATIONS\n\tconst maxWallTimeMs = options.maxWallTimeMs ?? DEFAULT_MAX_WALL_TIME_MS\n\tconst stopOnPiFailure = options.stopOnPiFailure ?? true\n\tconst stopOnMayorIdleNoWork = options.stopOnMayorIdleNoWork ?? false\n\tconst interruptRateThreshold = options.interruptRateThreshold ?? null\n\tconst loopId = createLoopId()\n\tconst artifactsDir = options.runOptions.artifactsDir\n\tconst loopDir = join(artifactsDir, \"loops\", loopId)\n\n\tmkdirSync(loopDir, { recursive: true })\n\n\tconst loopStartedAt = Date.now()\n\tconst iterations: LoopIterationResult[] = []\n\tlet finalStopReason: LoopStopReason = \"max-iterations-reached\"\n\tlet needsMayorFollowUp = false\n\n\tappendJsonl(join(loopDir, \"events.jsonl\"), {\n\t\ttype: \"loop_started\",\n\t\tloopId,\n\t\tmaxIterations,\n\t\tmaxWallTimeMs,\n\t\tstopOnPiFailure,\n\t\tcreatedAt: new Date().toISOString(),\n\t})\n\n\tfor (let iteration = 1; iteration <= maxIterations; iteration++) {\n\t\tif (needsMayorFollowUp) {\n\t\t\tconst settled = waitForBackgroundWorkToSettle({\n\t\t\t\tartifactsDir,\n\t\t\t\tmaxWallTimeMs,\n\t\t\t\tloopStartedAt,\n\t\t\t})\n\n\t\t\tappendJsonl(join(loopDir, \"events.jsonl\"), {\n\t\t\t\ttype: \"loop_background_work_settled\",\n\t\t\t\tloopId,\n\t\t\t\titeration,\n\t\t\t\ttimedOut: settled.timedOut,\n\t\t\t\tboardSnapshot: settled.board,\n\t\t\t\tcreatedAt: new Date().toISOString(),\n\t\t\t})\n\n\t\t\tif (settled.timedOut) {\n\t\t\t\tfinalStopReason = \"max-wall-time-reached\"\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tneedsMayorFollowUp = false\n\t\t}\n\n\t\tconst iterationStart = Date.now()\n\n\t\tlet controllerResult: ControllerRunResult\n\t\ttry {\n\t\t\tcontrollerResult = runController(options.runOptions)\n\t\t} catch (error) {\n\t\t\t// If controller fails to run (e.g. lease issue), record and stop\n\t\t\tappendJsonl(join(loopDir, \"events.jsonl\"), {\n\t\t\t\ttype: \"loop_iteration_error\",\n\t\t\t\tloopId,\n\t\t\t\titeration,\n\t\t\t\terror: (error as Error).message,\n\t\t\t\tcreatedAt: new Date().toISOString(),\n\t\t\t})\n\t\t\tfinalStopReason = \"pi-exit-nonzero\"\n\t\t\tbreak\n\t\t}\n\n\t\tconst iterationElapsedMs = Date.now() - iterationStart\n\t\tconst totalElapsedMs = Date.now() - loopStartedAt\n\t\tconst board = snapshotBoard(artifactsDir)\n\t\tconst metrics = controllerResult.metrics\n\n\t\tconst { stopReason, continueReason } = evaluateStopCondition({\n\t\t\titeration,\n\t\t\tmaxIterations,\n\t\t\telapsedMs: totalElapsedMs,\n\t\t\tmaxWallTimeMs,\n\t\t\tpiExitCode: controllerResult.piInvocation.exitCode,\n\t\t\tstopOnPiFailure,\n\t\t\tstopOnMayorIdleNoWork,\n\t\t\tboard,\n\t\t\tmetrics,\n\t\t\tinterruptRateThreshold,\n\t\t})\n\n\t\tconst iterationResult: LoopIterationResult = {\n\t\t\titeration,\n\t\t\tcontrollerResult,\n\t\t\tboardSnapshot: board,\n\t\t\tmetrics,\n\t\t\telapsedMs: iterationElapsedMs,\n\t\t\tcontinueReason,\n\t\t\tstopReason,\n\t\t}\n\n\t\titerations.push(iterationResult)\n\n\t\twriteJson(join(loopDir, `iteration-${iteration}.json`), {\n\t\t\titeration,\n\t\t\trunId: controllerResult.runId,\n\t\t\tboardSnapshot: board,\n\t\t\tmetrics,\n\t\t\telapsedMs: iterationElapsedMs,\n\t\t\tcontinueReason,\n\t\t\tstopReason,\n\t\t})\n\n\t\tappendJsonl(join(loopDir, \"events.jsonl\"), {\n\t\t\ttype: \"loop_iteration_completed\",\n\t\t\tloopId,\n\t\t\titeration,\n\t\t\trunId: controllerResult.runId,\n\t\t\tpiExitCode: controllerResult.piInvocation.exitCode,\n\t\t\tstopReason,\n\t\t\tcontinueReason,\n\t\t\tcreatedAt: new Date().toISOString(),\n\t\t})\n\n\t\tif (options.onIterationComplete) {\n\t\t\toptions.onIterationComplete(iterationResult)\n\t\t}\n\n\t\tif (stopReason !== null) {\n\t\t\tfinalStopReason = stopReason\n\t\t\tbreak\n\t\t}\n\n\t\tneedsMayorFollowUp = hasBackgroundWork(board)\n\t}\n\n\tconst totalElapsedMs = Date.now() - loopStartedAt\n\tconst lastIteration = iterations.at(-1)\n\tconst finalBoard = lastIteration ? lastIteration.boardSnapshot : snapshotBoard(artifactsDir)\n\tconst aggregate = aggregateMetrics(iterations)\n\n\tconst loopResult: LoopRunResult = {\n\t\tloopId,\n\t\titerations,\n\t\tstopReason: finalStopReason,\n\t\ttotalIterations: iterations.length,\n\t\ttotalElapsedMs,\n\t\tfinalBoardSnapshot: finalBoard,\n\t\taggregateMetrics: aggregate,\n\t}\n\n\twriteJson(join(loopDir, \"loop-summary.json\"), {\n\t\tloopId,\n\t\tstopReason: finalStopReason,\n\t\ttotalIterations: iterations.length,\n\t\ttotalElapsedMs,\n\t\tfinalBoardSnapshot: finalBoard,\n\t\taggregateMetrics: aggregate,\n\t})\n\n\tappendJsonl(join(loopDir, \"events.jsonl\"), {\n\t\ttype: \"loop_finished\",\n\t\tloopId,\n\t\tstopReason: finalStopReason,\n\t\ttotalIterations: iterations.length,\n\t\ttotalElapsedMs,\n\t\tcreatedAt: new Date().toISOString(),\n\t})\n\n\treturn loopResult\n}\n","import { spawn } from \"node:child_process\"\nimport { writeFileSync } from \"node:fs\"\nimport { createRequire } from \"node:module\"\nimport { fileURLToPath } from \"node:url\"\nimport {\n\tappendAgentMessage,\n\tcreateAgentSessionRecord,\n\tcreateAgentState,\n\tgetAgentDir,\n\tgetAgentSessionsDir,\n\tgetLatestAgentSession,\n\treadAgentState,\n\twriteAgentState,\n} from \"./agents.js\"\nimport { createTaskRecord, updateTaskRecordStatus, writeTaskRecord } from \"./tasks.js\"\nimport { assertCommandAvailable, runCommandSync } from \"./shell.js\"\nimport type { AgentSessionRecord, AgentStateSnapshot, TaskRecord } from \"./types.js\"\n\nexport interface SpawnAgentRunOptions {\n\trepoRoot: string\n\tartifactsDir: string\n\trole: string\n\tagentId: string\n\ttask: string | null\n\tappendedSystemPrompt?: string | null | undefined\n\textensionPath?: string | null | undefined\n\ttaskId?: string | null | undefined\n}\n\nexport interface SpawnAgentRunResult {\n\tlaunch: {\n\t\tprocessId: number\n\t\tstartedAt: string\n\t}\n\tlatestSession: AgentSessionRecord\n}\n\nexport interface DelegateTaskOptions {\n\trepoRoot: string\n\tartifactsDir: string\n\tfromAgentId: string\n\trole: string\n\tagentId?: string | null | undefined\n\tappendedSystemPrompt?: string | null | undefined\n\textensionPath?: string | null | undefined\n\ttask: string\n}\n\nexport interface DelegateTaskResult {\n\ttask: TaskRecord\n\tagentId: string\n\tlaunch: SpawnAgentRunResult[\"launch\"]\n\tlatestSession: AgentSessionRecord\n}\n\nexport interface ResolvedAgentSession {\n\tstate: AgentStateSnapshot\n\tsession: AgentSessionRecord\n}\n\nexport interface RunAgentTurnOptions {\n\trepoRoot: string\n\tartifactsDir: string\n\tagentId: string\n\tmessage: string\n\tfrom?: string\n\truntimeArgs?: string[] | null\n}\n\nexport interface RunAgentTurnResult {\n\tpiResult: { stdout: string; stderr: string; exitCode: number }\n\tlatestSession: AgentSessionRecord\n\tcompletionMessage: string\n}\n\nfunction createPiInvocationArgs(input: {\n\tsessionDir?: string | null\n\tsessionPath?: string | null\n\tprompt?: string | null\n\tappendedSystemPrompt?: string | null | undefined\n\textensionPath?: string | null | undefined\n}): string[] {\n\tconst args: string[] = []\n\n\tif (input.extensionPath) args.push(\"--extension\", input.extensionPath)\n\tif (input.appendedSystemPrompt) args.push(\"--append-system-prompt\", input.appendedSystemPrompt)\n\tif (input.sessionPath) args.push(\"--session\", input.sessionPath)\n\telse if (input.sessionDir) args.push(\"--session-dir\", input.sessionDir)\n\telse throw new Error(\"Pi invocation requires a session path or session directory\")\n\tif (input.prompt) args.push(\"-p\", input.prompt)\n\n\treturn args\n}\n\nfunction createDetachedRunnerInvocation(encodedPayload: string): { command: string; args: string[] } {\n\tconst modulePath = fileURLToPath(import.meta.url)\n\tif (modulePath.endsWith(\".ts\")) {\n\t\tconst require = createRequire(import.meta.url)\n\t\treturn {\n\t\t\tcommand: process.execPath,\n\t\t\targs: [\"--import\", require.resolve(\"tsx\"), fileURLToPath(new URL(\"./agent-runner.ts\", import.meta.url)), encodedPayload],\n\t\t}\n\t}\n\n\treturn {\n\t\tcommand: process.execPath,\n\t\targs: [fileURLToPath(new URL(\"./agent-runner.mjs\", import.meta.url)), encodedPayload],\n\t}\n}\n\nexport function createRolePrompt(input: { role: string; task: string | null; repoRoot: string }): string {\n\tconst task = input.task ?? \"pick the next bounded task from the current repo context\"\n\n\tswitch (input.role) {\n\t\tcase \"mayor\":\n\t\t\treturn [\n\t\t\t\t\"You are the Pi Town mayor.\",\n\t\t\t\t\"You coordinate work for this repository and act as the primary human-facing agent.\",\n\t\t\t\t\"\",\n\t\t\t\t`Repository: ${input.repoRoot}`,\n\t\t\t\t`Task: ${task}`,\n\t\t\t\t\"Keep updates concise, choose bounded next steps, and leave a durable artifact trail.\",\n\t\t\t].join(\"\\n\")\n\t\tcase \"reviewer\":\n\t\t\treturn [\n\t\t\t\t\"You are the Pi Town reviewer.\",\n\t\t\t\t\"You review work for correctness, safety, and completeness.\",\n\t\t\t\t\"\",\n\t\t\t\t`Repository: ${input.repoRoot}`,\n\t\t\t\t`Task: ${task}`,\n\t\t\t\t\"Focus on validation confidence, regressions, and whether the output is ready for a human handoff.\",\n\t\t\t].join(\"\\n\")\n\t\tcase \"docs-keeper\":\n\t\t\treturn [\n\t\t\t\t\"You are the Pi Town docs keeper.\",\n\t\t\t\t\"You summarize outcomes, blockers, and continuity in compact factual language.\",\n\t\t\t\t\"\",\n\t\t\t\t`Repository: ${input.repoRoot}`,\n\t\t\t\t`Task: ${task}`,\n\t\t\t\t\"Keep the output concise and useful for the next run or human review.\",\n\t\t\t].join(\"\\n\")\n\t\tdefault:\n\t\t\treturn [\n\t\t\t\t\"You are the Pi Town worker.\",\n\t\t\t\t\"You implement one bounded task at a time.\",\n\t\t\t\t\"\",\n\t\t\t\t`Repository: ${input.repoRoot}`,\n\t\t\t\t`Task: ${task}`,\n\t\t\t\t\"Keep scope tight, prefer explicit validations, and summarize what changed and what still needs follow-up.\",\n\t\t\t].join(\"\\n\")\n\t}\n}\n\nexport function resolveAgentSession(agentId: string, artifactsDir: string): ResolvedAgentSession {\n\tconst state = readAgentState(artifactsDir, agentId)\n\tif (state === null) throw new Error(`Unknown agent: ${agentId}`)\n\n\tconst latestSession = getLatestAgentSession(artifactsDir, agentId)\n\tconst sessionPath = state.session.sessionPath ?? latestSession.sessionPath\n\tconst sessionId = state.session.sessionId ?? latestSession.sessionId\n\tconst sessionDir = state.session.sessionDir ?? latestSession.sessionDir ?? getAgentSessionsDir(artifactsDir, agentId)\n\n\tif (sessionPath === null) {\n\t\tthrow new Error(`Agent ${agentId} does not have a persisted Pi session yet.`)\n\t}\n\n\treturn {\n\t\tstate,\n\t\tsession: createAgentSessionRecord({\n\t\t\tsessionDir,\n\t\t\tsessionId,\n\t\t\tsessionPath,\n\t\t\tprocessId: state.session.processId,\n\t\t\tlastAttachedAt: new Date().toISOString(),\n\t\t}),\n\t}\n}\n\nexport function queueAgentMessage(input: { artifactsDir: string; agentId: string; from: string; body: string }) {\n\tconst state = readAgentState(input.artifactsDir, input.agentId)\n\tif (state === null) throw new Error(`Unknown agent: ${input.agentId}`)\n\n\tappendAgentMessage({\n\t\tartifactsDir: input.artifactsDir,\n\t\tagentId: input.agentId,\n\t\tbox: \"inbox\",\n\t\tfrom: input.from,\n\t\tbody: input.body,\n\t})\n\n\twriteAgentState(\n\t\tinput.artifactsDir,\n\t\tcreateAgentState({\n\t\t\t...state,\n\t\t\tstatus: state.status === \"idle\" ? \"queued\" : state.status,\n\t\t\tlastMessage: input.body,\n\t\t\twaitingOn: null,\n\t\t\tblocked: false,\n\t\t\tsession: createAgentSessionRecord({\n\t\t\t\tsessionDir: state.session.sessionDir ?? getAgentSessionsDir(input.artifactsDir, input.agentId),\n\t\t\t\tsessionId: state.session.sessionId,\n\t\t\t\tsessionPath: state.session.sessionPath,\n\t\t\t\tprocessId: state.session.processId,\n\t\t\t\tlastAttachedAt: state.session.lastAttachedAt,\n\t\t\t}),\n\t\t}),\n\t)\n}\n\nexport function updateAgentStatus(input: {\n\tartifactsDir: string\n\tagentId: string\n\tstatus: \"queued\" | \"running\" | \"idle\" | \"blocked\" | \"completed\" | \"failed\" | \"stopped\"\n\tlastMessage?: string | null\n\twaitingOn?: string | null\n\tblocked?: boolean\n}) {\n\tconst state = readAgentState(input.artifactsDir, input.agentId)\n\tif (state === null) throw new Error(`Unknown agent: ${input.agentId}`)\n\n\tif (state.taskId) {\n\t\tconst taskStatus =\n\t\t\tinput.status === \"completed\"\n\t\t\t\t? \"completed\"\n\t\t\t\t: input.status === \"blocked\" || input.status === \"failed\"\n\t\t\t\t\t? \"blocked\"\n\t\t\t\t\t: input.status === \"stopped\"\n\t\t\t\t\t\t? \"aborted\"\n\t\t\t\t\t: input.status === \"running\" || input.status === \"queued\"\n\t\t\t\t\t\t? \"running\"\n\t\t\t\t\t\t: null\n\t\tif (taskStatus) updateTaskRecordStatus(input.artifactsDir, state.taskId, taskStatus)\n\t}\n\n\twriteAgentState(\n\t\tinput.artifactsDir,\n\t\tcreateAgentState({\n\t\t\t...state,\n\t\t\tstatus: input.status,\n\t\t\tlastMessage: input.lastMessage ?? state.lastMessage,\n\t\t\twaitingOn: input.waitingOn ?? state.waitingOn,\n\t\t\tblocked: input.blocked ?? state.blocked,\n\t\t\tsession: state.session,\n\t\t}),\n\t)\n}\n\nexport function spawnAgentRun(options: SpawnAgentRunOptions): SpawnAgentRunResult {\n\tconst sessionDir = getAgentSessionsDir(options.artifactsDir, options.agentId)\n\n\tif (readAgentState(options.artifactsDir, options.agentId) !== null) {\n\t\tthrow new Error(`Agent already exists: ${options.agentId}`)\n\t}\n\n\tassertCommandAvailable(\"pi\")\n\n\tconst state = createAgentState({\n\t\tagentId: options.agentId,\n\t\trole: options.role,\n\t\tstatus: \"queued\",\n\t\ttaskId: options.taskId ?? null,\n\t\ttask: options.task,\n\t\tlastMessage: options.task ? `Spawned with task: ${options.task}` : `Spawned ${options.role} agent`,\n\t\tsession: createAgentSessionRecord({\n\t\t\tsessionDir,\n\t\t}),\n\t})\n\twriteAgentState(options.artifactsDir, state)\n\tif (options.task) {\n\t\tappendAgentMessage({\n\t\t\tartifactsDir: options.artifactsDir,\n\t\t\tagentId: options.agentId,\n\t\t\tbox: \"inbox\",\n\t\t\tfrom: \"system\",\n\t\t\tbody: options.task,\n\t\t})\n\t}\n\n\twriteAgentState(\n\t\toptions.artifactsDir,\n\t\tcreateAgentState({\n\t\t\t...state,\n\t\t\tstatus: \"running\",\n\t\t\tlastMessage: options.task ? `Running ${options.role} task: ${options.task}` : `Running ${options.role} agent`,\n\t\t}),\n\t)\n\n\tconst prompt = createRolePrompt({ role: options.role, task: options.task, repoRoot: options.repoRoot })\n\tconst piArgs = createPiInvocationArgs({\n\t\tsessionDir,\n\t\tprompt,\n\t\tappendedSystemPrompt: options.appendedSystemPrompt,\n\t\textensionPath: options.extensionPath,\n\t})\n\tconst startedAt = new Date().toISOString()\n\tconst encodedPayload = Buffer.from(\n\t\tJSON.stringify({\n\t\t\trepoRoot: options.repoRoot,\n\t\t\tartifactsDir: options.artifactsDir,\n\t\t\tagentId: options.agentId,\n\t\t\trole: options.role,\n\t\t\ttask: options.task,\n\t\t\ttaskId: options.taskId ?? null,\n\t\t\tsessionDir,\n\t\t\tpiArgs,\n\t\t}),\n\t\t\"utf-8\",\n\t).toString(\"base64url\")\n\tconst runner = createDetachedRunnerInvocation(encodedPayload)\n\tconst child = spawn(runner.command, runner.args, {\n\t\tcwd: options.repoRoot,\n\t\tdetached: true,\n\t\tenv: process.env,\n\t\tstdio: \"ignore\",\n\t})\n\tchild.unref()\n\n\tif (!child.pid) {\n\t\tthrow new Error(`Failed to launch detached ${options.role} run for ${options.agentId}`)\n\t}\n\n\twriteFileSync(\n\t\t`${getAgentDir(options.artifactsDir, options.agentId)}/latest-invocation.json`,\n\t\t`${JSON.stringify(\n\t\t\t{\n\t\t\t\tcommand: \"pi\",\n\t\t\t\targs: piArgs,\n\t\t\t\texitCode: null,\n\t\t\t\tsessionDir,\n\t\t\t\tsessionPath: null,\n\t\t\t\tsessionId: null,\n\t\t\t\tprocessId: child.pid,\n\t\t\t\tstartedAt,\n\t\t\t},\n\t\t\tnull,\n\t\t\t2,\n\t\t)}\\n`,\n\t\t\"utf-8\",\n\t)\n\n\treturn {\n\t\tlaunch: {\n\t\t\tprocessId: child.pid,\n\t\t\tstartedAt,\n\t\t},\n\t\tlatestSession: createAgentSessionRecord({\n\t\t\tsessionDir,\n\t\t}),\n\t}\n}\n\nexport function runAgentTurn(options: RunAgentTurnOptions): RunAgentTurnResult {\n\tassertCommandAvailable(\"pi\")\n\n\tconst resolved = resolveAgentSession(options.agentId, options.artifactsDir)\n\tconst messageSource = options.from ?? \"human\"\n\twriteAgentState(\n\t\toptions.artifactsDir,\n\t\tcreateAgentState({\n\t\t\t...resolved.state,\n\t\t\tstatus: \"running\",\n\t\t\tlastMessage: `Responding to ${messageSource}: ${options.message}`,\n\t\t\twaitingOn: null,\n\t\t\tblocked: false,\n\t\t\tsession: resolved.session,\n\t\t}),\n\t)\n\n\tconst piArgs =\n\t\toptions.runtimeArgs && options.runtimeArgs.length > 0\n\t\t\t? options.runtimeArgs\n\t\t\t: createPiInvocationArgs({\n\t\t\t\t\tsessionPath: resolved.session.sessionPath,\n\t\t\t\t\tprompt: options.message,\n\t\t\t\t})\n\tconst piResult = runCommandSync(\"pi\", piArgs, {\n\t\tcwd: options.repoRoot,\n\t\tenv: process.env,\n\t})\n\tconst latestSession = getLatestAgentSession(options.artifactsDir, options.agentId)\n\tconst agentArtifactsDir = getAgentDir(options.artifactsDir, options.agentId)\n\twriteFileSync(`${agentArtifactsDir}/latest-stdout.txt`, piResult.stdout, \"utf-8\")\n\twriteFileSync(`${agentArtifactsDir}/latest-stderr.txt`, piResult.stderr, \"utf-8\")\n\twriteFileSync(\n\t\t`${agentArtifactsDir}/latest-invocation.json`,\n\t\t`${JSON.stringify(\n\t\t\t{\n\t\t\t\tcommand: \"pi\",\n\t\t\t\targs: piArgs,\n\t\t\t\texitCode: piResult.exitCode,\n\t\t\t\tsessionDir: latestSession.sessionDir,\n\t\t\t\tsessionPath: latestSession.sessionPath,\n\t\t\t\tsessionId: latestSession.sessionId,\n\t\t\t},\n\t\t\tnull,\n\t\t\t2,\n\t\t)}\\n`,\n\t\t\"utf-8\",\n\t)\n\n\tconst completionMessage =\n\t\tpiResult.stdout.trim() ||\n\t\t(piResult.exitCode === 0\n\t\t\t? `${resolved.state.role} turn completed`\n\t\t\t: `${resolved.state.role} turn exited with code ${piResult.exitCode}`)\n\tappendAgentMessage({\n\t\tartifactsDir: options.artifactsDir,\n\t\tagentId: options.agentId,\n\t\tbox: \"outbox\",\n\t\tfrom: options.agentId,\n\t\tbody: completionMessage,\n\t})\n\n\twriteAgentState(\n\t\toptions.artifactsDir,\n\t\tcreateAgentState({\n\t\t\t...resolved.state,\n\t\t\tstatus: piResult.exitCode === 0 ? \"idle\" : \"blocked\",\n\t\t\tlastMessage: completionMessage,\n\t\t\twaitingOn: piResult.exitCode === 0 ? null : \"human-or-follow-up-run\",\n\t\t\tblocked: piResult.exitCode !== 0,\n\t\t\tsession: createAgentSessionRecord({\n\t\t\t\tsessionDir: latestSession.sessionDir,\n\t\t\t\tsessionId: latestSession.sessionId,\n\t\t\t\tsessionPath: latestSession.sessionPath,\n\t\t\t\tprocessId: null,\n\t\t\t}),\n\t\t}),\n\t)\n\n\treturn { piResult, latestSession, completionMessage }\n}\n\nexport function delegateTask(options: DelegateTaskOptions): DelegateTaskResult {\n\tconst fromState = readAgentState(options.artifactsDir, options.fromAgentId)\n\tif (fromState === null) throw new Error(`Unknown delegating agent: ${options.fromAgentId}`)\n\n\tconst agentId = options.agentId ?? `${options.role}-${Date.now()}`\n\tconst task = createTaskRecord({\n\t\ttaskId: `task-${Date.now()}`,\n\t\ttitle: options.task,\n\t\tstatus: \"queued\",\n\t\trole: options.role,\n\t\tassignedAgentId: agentId,\n\t\tcreatedBy: options.fromAgentId,\n\t})\n\twriteTaskRecord(options.artifactsDir, task)\n\n\tappendAgentMessage({\n\t\tartifactsDir: options.artifactsDir,\n\t\tagentId: options.fromAgentId,\n\t\tbox: \"outbox\",\n\t\tfrom: options.fromAgentId,\n\t\tbody: `Delegated ${task.taskId} to ${agentId}: ${options.task}`,\n\t})\n\n\tconst { launch, latestSession } = spawnAgentRun({\n\t\trepoRoot: options.repoRoot,\n\t\tartifactsDir: options.artifactsDir,\n\t\trole: options.role,\n\t\tagentId,\n\t\tappendedSystemPrompt: options.appendedSystemPrompt,\n\t\textensionPath: options.extensionPath,\n\t\ttask: options.task,\n\t\ttaskId: task.taskId,\n\t})\n\n\tappendAgentMessage({\n\t\tartifactsDir: options.artifactsDir,\n\t\tagentId,\n\t\tbox: \"inbox\",\n\t\tfrom: options.fromAgentId,\n\t\tbody: `Delegated by ${options.fromAgentId} as ${task.taskId}: ${options.task}`,\n\t})\n\n\twriteTaskRecord(options.artifactsDir, {\n\t\t...task,\n\t\tstatus: \"running\",\n\t\tupdatedAt: new Date().toISOString(),\n\t})\n\n\treturn {\n\t\ttask: {\n\t\t\t...task,\n\t\t\tstatus: \"running\",\n\t\t\tupdatedAt: new Date().toISOString(),\n\t\t},\n\t\tagentId,\n\t\tlaunch,\n\t\tlatestSession,\n\t}\n}\n","import { readdirSync, readFileSync, rmSync } from \"node:fs\"\nimport { homedir } from \"node:os\"\nimport { join } from \"node:path\"\nimport {\n\tappendAgentMessage,\n\tcreateAgentSessionRecord,\n\tcreateAgentState,\n\tlistAgentStates,\n\twriteAgentState,\n} from \"./agents.js\"\nimport { updateTaskRecordStatus } from \"./tasks.js\"\nimport type { AgentStateSnapshot } from \"./types.js\"\n\nconst DEFAULT_GRACE_MS = 750\n\ninterface LeaseData {\n\trunId: string\n\trepoId: string\n\tbranch: string\n\tpid: number\n\thostname: string\n\tstartedAt: string\n}\n\nexport interface StopManagedAgentsOptions {\n\tartifactsDir: string\n\tagentId?: string | null\n\texcludeAgentIds?: string[]\n\tactorId?: string | null\n\treason?: string | null\n\tforce?: boolean\n\tgraceMs?: number\n}\n\nexport interface StopAgentResult {\n\tagentId: string\n\tpreviousStatus: AgentStateSnapshot[\"status\"]\n\tnextStatus: AgentStateSnapshot[\"status\"]\n\tprocessId: number | null\n\tsignal: \"SIGTERM\" | \"SIGKILL\" | null\n\texited: boolean\n}\n\nexport interface StopManagedAgentsResult {\n\tresults: StopAgentResult[]\n\tstoppedAgents: number\n\tsignaledProcesses: number\n}\n\nexport interface RepoLeaseRecord extends LeaseData {\n\tpath: string\n}\n\nexport interface StopRepoLeasesOptions {\n\trepoId?: string | null\n\tforce?: boolean\n\tgraceMs?: number\n}\n\nexport interface StopRepoLeaseResult {\n\tpath: string\n\trunId: string\n\trepoId: string\n\tbranch: string\n\tprocessId: number\n\tsignal: \"SIGTERM\" | \"SIGKILL\" | null\n\texited: boolean\n}\n\nexport interface StopRepoLeasesResult {\n\tresults: StopRepoLeaseResult[]\n\tsignaledProcesses: number\n}\n\nfunction sleepMs(ms: number) {\n\tAtomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms)\n}\n\nfunction getLocksDir(): string {\n\treturn join(homedir(), \".pi-town\", \"locks\")\n}\n\nfunction processAlive(pid: number): boolean {\n\tif (!Number.isFinite(pid) || pid <= 0) return false\n\n\ttry {\n\t\tprocess.kill(pid, 0)\n\t\treturn true\n\t} catch {\n\t\treturn false\n\t}\n}\n\nfunction terminateProcess(pid: number, options: { force?: boolean; graceMs?: number }): {\n\tsignal: \"SIGTERM\" | \"SIGKILL\" | null\n\texited: boolean\n} {\n\tif (!processAlive(pid)) return { signal: null, exited: true }\n\n\ttry {\n\t\tprocess.kill(pid, \"SIGTERM\")\n\t} catch {\n\t\treturn { signal: null, exited: !processAlive(pid) }\n\t}\n\n\tconst graceMs = options.graceMs ?? DEFAULT_GRACE_MS\n\tconst deadline = Date.now() + graceMs\n\twhile (Date.now() < deadline) {\n\t\tif (!processAlive(pid)) return { signal: \"SIGTERM\", exited: true }\n\t\tsleepMs(25)\n\t}\n\n\tif (!options.force) return { signal: \"SIGTERM\", exited: !processAlive(pid) }\n\n\ttry {\n\t\tprocess.kill(pid, \"SIGKILL\")\n\t} catch {\n\t\treturn { signal: \"SIGTERM\", exited: !processAlive(pid) }\n\t}\n\n\treturn { signal: \"SIGKILL\", exited: !processAlive(pid) }\n}\n\nfunction readLease(path: string): RepoLeaseRecord | null {\n\ttry {\n\t\tconst data = JSON.parse(readFileSync(path, \"utf-8\")) as LeaseData\n\t\treturn { ...data, path }\n\t} catch {\n\t\treturn null\n\t}\n}\n\nfunction createStopMessage(options: { actorId?: string | null; reason?: string | null }): string {\n\tif (options.reason) return options.reason\n\tif (options.actorId) return `Stopped by ${options.actorId}`\n\treturn \"Stopped by operator\"\n}\n\nfunction createStopMessageInput(options: StopManagedAgentsOptions): { actorId?: string | null; reason?: string | null } {\n\treturn {\n\t\t...(options.actorId === undefined ? {} : { actorId: options.actorId }),\n\t\t...(options.reason === undefined ? {} : { reason: options.reason }),\n\t}\n}\n\nfunction createTerminateOptions(options: { force?: boolean; graceMs?: number }): { force?: boolean; graceMs?: number } {\n\treturn {\n\t\t...(options.force === undefined ? {} : { force: options.force }),\n\t\t...(options.graceMs === undefined ? {} : { graceMs: options.graceMs }),\n\t}\n}\n\nexport function listRepoLeases(repoId?: string | null): RepoLeaseRecord[] {\n\tlet entries: string[]\n\ttry {\n\t\tentries = readdirSync(getLocksDir())\n\t} catch {\n\t\treturn []\n\t}\n\n\treturn entries\n\t\t.filter((entry) => entry.endsWith(\".json\"))\n\t\t.map((entry) => readLease(join(getLocksDir(), entry)))\n\t\t.filter((record): record is RepoLeaseRecord => record !== null)\n\t\t.filter((record) => repoId === undefined || repoId === null || record.repoId === repoId)\n}\n\nexport function stopRepoLeases(options: StopRepoLeasesOptions): StopRepoLeasesResult {\n\tconst results = listRepoLeases(options.repoId).map((lease) => {\n\t\tconst termination = terminateProcess(lease.pid, options)\n\t\tif (termination.exited) rmSync(lease.path, { force: true })\n\n\t\treturn {\n\t\t\tpath: lease.path,\n\t\t\trunId: lease.runId,\n\t\t\trepoId: lease.repoId,\n\t\t\tbranch: lease.branch,\n\t\t\tprocessId: lease.pid,\n\t\t\tsignal: termination.signal,\n\t\t\texited: termination.exited,\n\t\t}\n\t})\n\n\treturn {\n\t\tresults,\n\t\tsignaledProcesses: results.filter((result) => result.signal !== null).length,\n\t}\n}\n\nexport function stopManagedAgents(options: StopManagedAgentsOptions): StopManagedAgentsResult {\n\tconst reason = createStopMessage(createStopMessageInput(options))\n\tconst excluded = new Set(options.excludeAgentIds ?? [])\n\tconst candidates = listAgentStates(options.artifactsDir).filter((agent) => {\n\t\tif (excluded.has(agent.agentId)) return false\n\t\tif (options.agentId && agent.agentId !== options.agentId) return false\n\t\treturn ![\"completed\", \"failed\", \"stopped\"].includes(agent.status)\n\t})\n\n\tconst results = candidates.map((state) => {\n\t\tconst processId = state.session.processId\n\t\tconst termination =\n\t\t\tprocessId === null\n\t\t\t\t? { signal: null, exited: true }\n\t\t\t\t: terminateProcess(processId, createTerminateOptions(options))\n\n\t\tif (state.taskId) updateTaskRecordStatus(options.artifactsDir, state.taskId, \"aborted\")\n\n\t\tappendAgentMessage({\n\t\t\tartifactsDir: options.artifactsDir,\n\t\t\tagentId: state.agentId,\n\t\t\tbox: \"outbox\",\n\t\t\tfrom: options.actorId ?? \"system\",\n\t\t\tbody: reason,\n\t\t})\n\n\t\twriteAgentState(\n\t\t\toptions.artifactsDir,\n\t\t\tcreateAgentState({\n\t\t\t\t...state,\n\t\t\t\tstatus: \"stopped\",\n\t\t\t\tlastMessage: reason,\n\t\t\t\twaitingOn: \"stopped\",\n\t\t\t\tblocked: true,\n\t\t\t\tsession: createAgentSessionRecord({\n\t\t\t\t\tsessionDir: state.session.sessionDir,\n\t\t\t\t\tsessionId: state.session.sessionId,\n\t\t\t\t\tsessionPath: state.session.sessionPath,\n\t\t\t\t\tprocessId: null,\n\t\t\t\t\tlastAttachedAt: state.session.lastAttachedAt,\n\t\t\t\t}),\n\t\t\t}),\n\t\t)\n\n\t\treturn {\n\t\t\tagentId: state.agentId,\n\t\t\tpreviousStatus: state.status,\n\t\t\tnextStatus: \"stopped\" as const,\n\t\t\tprocessId,\n\t\t\tsignal: termination.signal,\n\t\t\texited: termination.exited,\n\t\t}\n\t})\n\n\treturn {\n\t\tresults,\n\t\tstoppedAgents: results.length,\n\t\tsignaledProcesses: results.filter((result) => result.signal !== null).length,\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
|
|
4
|
+
//#region src/events.ts
|
|
5
|
+
function appendJsonl(filePath, value) {
|
|
6
|
+
mkdirSync(dirname(filePath), { recursive: true });
|
|
7
|
+
writeFileSync(filePath, `${JSON.stringify(value)}\n`, {
|
|
8
|
+
encoding: "utf-8",
|
|
9
|
+
flag: "a"
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
function readJsonl(filePath) {
|
|
13
|
+
try {
|
|
14
|
+
return readFileSync(filePath, "utf-8").split(/\r?\n/).map((line) => line.trim()).filter(Boolean).map((line) => JSON.parse(line));
|
|
15
|
+
} catch {
|
|
16
|
+
return [];
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
//#endregion
|
|
21
|
+
//#region src/agents.ts
|
|
22
|
+
function writeJson$1(path, value) {
|
|
23
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
24
|
+
writeFileSync(path, `${JSON.stringify(value, null, 2)}\n`, "utf-8");
|
|
25
|
+
}
|
|
26
|
+
function ensureMailbox(path) {
|
|
27
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
28
|
+
if (!existsSync(path)) writeFileSync(path, "", "utf-8");
|
|
29
|
+
}
|
|
30
|
+
function getAgentsDir(artifactsDir) {
|
|
31
|
+
return join(artifactsDir, "agents");
|
|
32
|
+
}
|
|
33
|
+
function getAgentDir(artifactsDir, agentId) {
|
|
34
|
+
return join(getAgentsDir(artifactsDir), agentId);
|
|
35
|
+
}
|
|
36
|
+
function getAgentStatePath(artifactsDir, agentId) {
|
|
37
|
+
return join(getAgentDir(artifactsDir, agentId), "state.json");
|
|
38
|
+
}
|
|
39
|
+
function getAgentSessionPath(artifactsDir, agentId) {
|
|
40
|
+
return join(getAgentDir(artifactsDir, agentId), "session.json");
|
|
41
|
+
}
|
|
42
|
+
function getAgentMailboxPath(artifactsDir, agentId, box) {
|
|
43
|
+
return join(getAgentDir(artifactsDir, agentId), `${box}.jsonl`);
|
|
44
|
+
}
|
|
45
|
+
function getAgentSessionsDir(artifactsDir, agentId) {
|
|
46
|
+
return join(getAgentDir(artifactsDir, agentId), "sessions");
|
|
47
|
+
}
|
|
48
|
+
function getSessionIdFromPath(sessionPath) {
|
|
49
|
+
if (!sessionPath) return null;
|
|
50
|
+
return /_([0-9a-f-]+)\.jsonl$/i.exec(sessionPath)?.[1] ?? null;
|
|
51
|
+
}
|
|
52
|
+
function createAgentSessionRecord(input) {
|
|
53
|
+
return {
|
|
54
|
+
runtime: "pi",
|
|
55
|
+
persisted: true,
|
|
56
|
+
sessionDir: input?.sessionDir ?? null,
|
|
57
|
+
sessionId: input?.sessionId ?? null,
|
|
58
|
+
sessionPath: input?.sessionPath ?? null,
|
|
59
|
+
processId: input?.processId ?? null,
|
|
60
|
+
lastAttachedAt: input?.lastAttachedAt ?? null
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
function createAgentState(input) {
|
|
64
|
+
return {
|
|
65
|
+
agentId: input.agentId,
|
|
66
|
+
role: input.role,
|
|
67
|
+
status: input.status,
|
|
68
|
+
taskId: input.taskId ?? null,
|
|
69
|
+
task: input.task ?? null,
|
|
70
|
+
branch: input.branch ?? null,
|
|
71
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
72
|
+
lastMessage: input.lastMessage ?? null,
|
|
73
|
+
waitingOn: input.waitingOn ?? null,
|
|
74
|
+
blocked: input.blocked ?? false,
|
|
75
|
+
runId: input.runId ?? null,
|
|
76
|
+
session: input.session ?? createAgentSessionRecord()
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
function writeAgentState(artifactsDir, state) {
|
|
80
|
+
mkdirSync(getAgentDir(artifactsDir, state.agentId), { recursive: true });
|
|
81
|
+
ensureMailbox(getAgentMailboxPath(artifactsDir, state.agentId, "inbox"));
|
|
82
|
+
ensureMailbox(getAgentMailboxPath(artifactsDir, state.agentId, "outbox"));
|
|
83
|
+
writeJson$1(getAgentStatePath(artifactsDir, state.agentId), state);
|
|
84
|
+
writeJson$1(getAgentSessionPath(artifactsDir, state.agentId), state.session);
|
|
85
|
+
}
|
|
86
|
+
function readAgentState(artifactsDir, agentId) {
|
|
87
|
+
const statePath = getAgentStatePath(artifactsDir, agentId);
|
|
88
|
+
try {
|
|
89
|
+
return JSON.parse(readFileSync(statePath, "utf-8"));
|
|
90
|
+
} catch {
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
function listAgentStates(artifactsDir) {
|
|
95
|
+
const agentsDir = getAgentsDir(artifactsDir);
|
|
96
|
+
let entries;
|
|
97
|
+
try {
|
|
98
|
+
entries = readdirSync(agentsDir);
|
|
99
|
+
} catch {
|
|
100
|
+
return [];
|
|
101
|
+
}
|
|
102
|
+
return entries.map((entry) => readAgentState(artifactsDir, entry)).filter((state) => state !== null).sort((left, right) => left.agentId.localeCompare(right.agentId));
|
|
103
|
+
}
|
|
104
|
+
function appendAgentMessage(input) {
|
|
105
|
+
const record = {
|
|
106
|
+
box: input.box,
|
|
107
|
+
from: input.from,
|
|
108
|
+
body: input.body,
|
|
109
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
110
|
+
};
|
|
111
|
+
appendJsonl(getAgentMailboxPath(input.artifactsDir, input.agentId, input.box), record);
|
|
112
|
+
return record;
|
|
113
|
+
}
|
|
114
|
+
function readAgentMessages(artifactsDir, agentId, box) {
|
|
115
|
+
return readJsonl(getAgentMailboxPath(artifactsDir, agentId, box));
|
|
116
|
+
}
|
|
117
|
+
function getLatestAgentSession(artifactsDir, agentId) {
|
|
118
|
+
const sessionDir = getAgentSessionsDir(artifactsDir, agentId);
|
|
119
|
+
let entries;
|
|
120
|
+
try {
|
|
121
|
+
entries = readdirSync(sessionDir);
|
|
122
|
+
} catch {
|
|
123
|
+
return createAgentSessionRecord({ sessionDir });
|
|
124
|
+
}
|
|
125
|
+
const latestSessionPath = entries.filter((entry) => entry.endsWith(".jsonl")).sort().at(-1) ?? null;
|
|
126
|
+
if (latestSessionPath === null) return createAgentSessionRecord({ sessionDir });
|
|
127
|
+
const sessionPath = join(sessionDir, latestSessionPath);
|
|
128
|
+
return createAgentSessionRecord({
|
|
129
|
+
sessionDir,
|
|
130
|
+
sessionPath,
|
|
131
|
+
sessionId: getSessionIdFromPath(sessionPath)
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
//#endregion
|
|
136
|
+
//#region src/tasks.ts
|
|
137
|
+
function writeJson(path, value) {
|
|
138
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
139
|
+
writeFileSync(path, `${JSON.stringify(value, null, 2)}\n`, "utf-8");
|
|
140
|
+
}
|
|
141
|
+
function getTasksDir(artifactsDir) {
|
|
142
|
+
return join(artifactsDir, "tasks");
|
|
143
|
+
}
|
|
144
|
+
function getTaskPath(artifactsDir, taskId) {
|
|
145
|
+
return join(getTasksDir(artifactsDir), `${taskId}.json`);
|
|
146
|
+
}
|
|
147
|
+
function createTaskRecord(input) {
|
|
148
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
149
|
+
return {
|
|
150
|
+
taskId: input.taskId,
|
|
151
|
+
title: input.title,
|
|
152
|
+
status: input.status,
|
|
153
|
+
role: input.role,
|
|
154
|
+
assignedAgentId: input.assignedAgentId,
|
|
155
|
+
createdBy: input.createdBy,
|
|
156
|
+
createdAt: now,
|
|
157
|
+
updatedAt: now
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
function writeTaskRecord(artifactsDir, task) {
|
|
161
|
+
writeJson(getTaskPath(artifactsDir, task.taskId), task);
|
|
162
|
+
}
|
|
163
|
+
function updateTaskRecordStatus(artifactsDir, taskId, status) {
|
|
164
|
+
const task = readTaskRecord(artifactsDir, taskId);
|
|
165
|
+
if (task === null) return null;
|
|
166
|
+
const updatedTask = {
|
|
167
|
+
...task,
|
|
168
|
+
status,
|
|
169
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
170
|
+
};
|
|
171
|
+
writeTaskRecord(artifactsDir, updatedTask);
|
|
172
|
+
return updatedTask;
|
|
173
|
+
}
|
|
174
|
+
function readTaskRecord(artifactsDir, taskId) {
|
|
175
|
+
const path = getTaskPath(artifactsDir, taskId);
|
|
176
|
+
try {
|
|
177
|
+
return JSON.parse(readFileSync(path, "utf-8"));
|
|
178
|
+
} catch {
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
function listTaskRecords(artifactsDir) {
|
|
183
|
+
const tasksDir = getTasksDir(artifactsDir);
|
|
184
|
+
let entries;
|
|
185
|
+
try {
|
|
186
|
+
entries = readdirSync(tasksDir);
|
|
187
|
+
} catch {
|
|
188
|
+
return [];
|
|
189
|
+
}
|
|
190
|
+
return entries.filter((entry) => entry.endsWith(".json")).map((entry) => readTaskRecord(artifactsDir, entry.replace(/\.json$/, ""))).filter((task) => task !== null).sort((left, right) => left.taskId.localeCompare(right.taskId));
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
//#endregion
|
|
194
|
+
export { appendJsonl as C, writeAgentState as S, getLatestAgentSession as _, readTaskRecord as a, readAgentMessages as b, appendAgentMessage as c, getAgentDir as d, getAgentMailboxPath as f, getAgentsDir as g, getAgentStatePath as h, listTaskRecords as i, createAgentSessionRecord as l, getAgentSessionsDir as m, getTaskPath as n, updateTaskRecordStatus as o, getAgentSessionPath as p, getTasksDir as r, writeTaskRecord as s, createTaskRecord as t, createAgentState as u, getSessionIdFromPath as v, readJsonl as w, readAgentState as x, listAgentStates as y };
|
|
195
|
+
//# sourceMappingURL=tasks-BfQm-7-O.mjs.map
|